aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig7
-rw-r--r--drivers/Makefile7
-rw-r--r--drivers/acorn/README1
-rw-r--r--drivers/acorn/block/Kconfig36
-rw-r--r--drivers/acorn/block/Makefile9
-rw-r--r--drivers/acorn/block/fd1772.c1604
-rw-r--r--drivers/acorn/block/fd1772dma.S100
-rw-r--r--drivers/acorn/block/mfm.S162
-rw-r--r--drivers/acorn/block/mfmhd.c1385
-rw-r--r--drivers/acpi/Kconfig97
-rw-r--r--drivers/acpi/ac.c14
-rw-r--r--drivers/acpi/acpi_memhotplug.c8
-rw-r--r--drivers/acpi/asus_acpi.c14
-rw-r--r--drivers/acpi/battery.c685
-rw-r--r--drivers/acpi/bay.c19
-rw-r--r--drivers/acpi/bus.c12
-rw-r--r--drivers/acpi/button.c14
-rw-r--r--drivers/acpi/container.c10
-rw-r--r--drivers/acpi/dock.c127
-rw-r--r--drivers/acpi/ec.c283
-rw-r--r--drivers/acpi/event.c165
-rw-r--r--drivers/acpi/events/evgpeblk.c4
-rw-r--r--drivers/acpi/events/evrgnini.c3
-rw-r--r--drivers/acpi/fan.c8
-rw-r--r--drivers/acpi/glue.c2
-rw-r--r--drivers/acpi/hardware/hwsleep.c19
-rw-r--r--drivers/acpi/namespace/nsxfeval.c4
-rw-r--r--drivers/acpi/numa.c31
-rw-r--r--drivers/acpi/osl.c44
-rw-r--r--drivers/acpi/pci_link.c11
-rw-r--r--drivers/acpi/pci_root.c9
-rw-r--r--drivers/acpi/power.c8
-rw-r--r--drivers/acpi/processor_core.c48
-rw-r--r--drivers/acpi/processor_idle.c99
-rw-r--r--drivers/acpi/processor_perflib.c6
-rw-r--r--drivers/acpi/processor_throttling.c435
-rw-r--r--drivers/acpi/resources/rsxface.c2
-rw-r--r--drivers/acpi/sbs.c50
-rw-r--r--drivers/acpi/scan.c161
-rw-r--r--drivers/acpi/sleep/Makefile6
-rw-r--r--drivers/acpi/sleep/main.c320
-rw-r--r--drivers/acpi/sleep/poweroff.c98
-rw-r--r--drivers/acpi/sleep/proc.c24
-rw-r--r--drivers/acpi/sleep/sleep.h2
-rw-r--r--drivers/acpi/sleep/wakeup.c2
-rw-r--r--drivers/acpi/system.c165
-rw-r--r--drivers/acpi/tables/tbfadt.c44
-rw-r--r--drivers/acpi/tables/tbutils.c71
-rw-r--r--drivers/acpi/tables/tbxface.c23
-rw-r--r--drivers/acpi/thermal.c234
-rw-r--r--drivers/acpi/utilities/uteval.c21
-rw-r--r--drivers/acpi/utilities/utglobal.c1
-rw-r--r--drivers/acpi/video.c244
-rw-r--r--drivers/amba/bus.c9
-rw-r--r--drivers/ata/Kconfig59
-rw-r--r--drivers/ata/Makefile8
-rw-r--r--drivers/ata/ahci.c688
-rw-r--r--drivers/ata/ata_generic.c18
-rw-r--r--drivers/ata/ata_piix.c263
-rw-r--r--drivers/ata/libata-acpi.c165
-rw-r--r--drivers/ata/libata-core.c1399
-rw-r--r--drivers/ata/libata-eh.c1118
-rw-r--r--drivers/ata/libata-pmp.c1191
-rw-r--r--drivers/ata/libata-scsi.c549
-rw-r--r--drivers/ata/libata-sff.c82
-rw-r--r--drivers/ata/libata.h44
-rw-r--r--drivers/ata/pata_acpi.c395
-rw-r--r--drivers/ata/pata_ali.c30
-rw-r--r--drivers/ata/pata_amd.c45
-rw-r--r--drivers/ata/pata_artop.c39
-rw-r--r--drivers/ata/pata_at32.c441
-rw-r--r--drivers/ata/pata_atiixp.c17
-rw-r--r--drivers/ata/pata_bf54x.c1627
-rw-r--r--drivers/ata/pata_cmd640.c4
-rw-r--r--drivers/ata/pata_cmd64x.c49
-rw-r--r--drivers/ata/pata_cs5520.c51
-rw-r--r--drivers/ata/pata_cs5530.c8
-rw-r--r--drivers/ata/pata_cs5535.c4
-rw-r--r--drivers/ata/pata_cypress.c4
-rw-r--r--drivers/ata/pata_efar.c11
-rw-r--r--drivers/ata/pata_hpt366.c4
-rw-r--r--drivers/ata/pata_hpt37x.c60
-rw-r--r--drivers/ata/pata_hpt3x2n.c19
-rw-r--r--drivers/ata/pata_hpt3x3.c10
-rw-r--r--drivers/ata/pata_icside.c59
-rw-r--r--drivers/ata/pata_isapnp.c12
-rw-r--r--drivers/ata/pata_it8213.c11
-rw-r--r--drivers/ata/pata_it821x.c25
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c27
-rw-r--r--drivers/ata/pata_jmicron.c24
-rw-r--r--drivers/ata/pata_legacy.c27
-rw-r--r--drivers/ata/pata_marvell.c18
-rw-r--r--drivers/ata/pata_mpc52xx.c11
-rw-r--r--drivers/ata/pata_mpiix.c25
-rw-r--r--drivers/ata/pata_netcell.c5
-rw-r--r--drivers/ata/pata_ns87410.c11
-rw-r--r--drivers/ata/pata_ns87415.c467
-rw-r--r--drivers/ata/pata_oldpiix.c11
-rw-r--r--drivers/ata/pata_opti.c11
-rw-r--r--drivers/ata/pata_optidma.c26
-rw-r--r--drivers/ata/pata_pcmcia.c19
-rw-r--r--drivers/ata/pata_pdc2027x.c124
-rw-r--r--drivers/ata/pata_pdc202xx_old.c23
-rw-r--r--drivers/ata/pata_platform.c23
-rw-r--r--drivers/ata/pata_qdi.c15
-rw-r--r--drivers/ata/pata_radisys.c4
-rw-r--r--drivers/ata/pata_rz1000.c13
-rw-r--r--drivers/ata/pata_sc1200.c6
-rw-r--r--drivers/ata/pata_scc.c97
-rw-r--r--drivers/ata/pata_serverworks.c10
-rw-r--r--drivers/ata/pata_sil680.c13
-rw-r--r--drivers/ata/pata_sis.c57
-rw-r--r--drivers/ata/pata_sl82c105.c13
-rw-r--r--drivers/ata/pata_triflex.c11
-rw-r--r--drivers/ata/pata_via.c37
-rw-r--r--drivers/ata/pata_winbond.c13
-rw-r--r--drivers/ata/pdc_adma.c105
-rw-r--r--drivers/ata/sata_inic162x.c52
-rw-r--r--drivers/ata/sata_mv.c330
-rw-r--r--drivers/ata/sata_nv.c93
-rw-r--r--drivers/ata/sata_promise.c56
-rw-r--r--drivers/ata/sata_qstor.c37
-rw-r--r--drivers/ata/sata_sil.c80
-rw-r--r--drivers/ata/sata_sil24.c486
-rw-r--r--drivers/ata/sata_sis.c26
-rw-r--r--drivers/ata/sata_svw.c29
-rw-r--r--drivers/ata/sata_sx4.c27
-rw-r--r--drivers/ata/sata_uli.c34
-rw-r--r--drivers/ata/sata_via.c66
-rw-r--r--drivers/ata/sata_vsc.c31
-rw-r--r--drivers/atm/Kconfig7
-rw-r--r--drivers/atm/eni.c19
-rw-r--r--drivers/atm/firestream.c14
-rw-r--r--drivers/atm/fore200e.c2
-rw-r--r--drivers/atm/idt77252.c8
-rw-r--r--drivers/atm/iphase.c12
-rw-r--r--drivers/atm/lanai.c5
-rw-r--r--drivers/atm/nicstarmac.c2
-rw-r--r--drivers/auxdisplay/Kconfig5
-rw-r--r--drivers/auxdisplay/cfag12864b.c2
-rw-r--r--drivers/base/Kconfig8
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c116
-rw-r--r--drivers/base/class.c60
-rw-r--r--drivers/base/core.c281
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/firmware_class.c15
-rw-r--r--drivers/base/memory.c3
-rw-r--r--drivers/base/platform.c26
-rw-r--r--drivers/base/power/Makefile4
-rw-r--r--drivers/base/power/main.c344
-rw-r--r--drivers/base/power/power.h47
-rw-r--r--drivers/base/power/resume.c149
-rw-r--r--drivers/base/power/runtime.c85
-rw-r--r--drivers/base/power/shutdown.c2
-rw-r--r--drivers/base/power/suspend.c210
-rw-r--r--drivers/base/power/sysfs.c66
-rw-r--r--drivers/base/power/trace.c5
-rw-r--r--drivers/base/sys.c73
-rw-r--r--drivers/block/DAC960.c18
-rw-r--r--drivers/block/DAC960.h7
-rw-r--r--drivers/block/Kconfig19
-rw-r--r--drivers/block/Makefile3
-rw-r--r--drivers/block/amiflop.c2
-rw-r--r--drivers/block/aoe/aoe.h2
-rw-r--r--drivers/block/aoe/aoeblk.c10
-rw-r--r--drivers/block/aoe/aoecmd.c5
-rw-r--r--drivers/block/aoe/aoedev.c4
-rw-r--r--drivers/block/aoe/aoenet.c4
-rw-r--r--drivers/block/ataflop.c2
-rw-r--r--drivers/block/cciss.c33
-rw-r--r--drivers/block/cpqarray.c86
-rw-r--r--drivers/block/floppy.c91
-rw-r--r--drivers/block/lguest_blk.c421
-rw-r--r--drivers/block/loop.c8
-rw-r--r--drivers/block/nbd.c63
-rw-r--r--drivers/block/paride/pcd.c4
-rw-r--r--drivers/block/paride/pd.c2
-rw-r--r--drivers/block/paride/pf.c4
-rw-r--r--drivers/block/pktcdvd.c37
-rw-r--r--drivers/block/ps2esdi.c4
-rw-r--r--drivers/block/ps3disk.c630
-rw-r--r--drivers/block/rd.c6
-rw-r--r--drivers/block/sunvdc.c127
-rw-r--r--drivers/block/swim3.c4
-rw-r--r--drivers/block/sx8.c23
-rw-r--r--drivers/block/ub.c6
-rw-r--r--drivers/block/umem.c244
-rw-r--r--drivers/block/umem.h133
-rw-r--r--drivers/block/viodasd.c80
-rw-r--r--drivers/block/xd.c2
-rw-r--r--drivers/block/xd.h2
-rw-r--r--drivers/block/xen-blkfront.c984
-rw-r--r--drivers/block/xsysace.c307
-rw-r--r--drivers/block/z2ram.c2
-rw-r--r--drivers/bluetooth/hci_usb.c5
-rw-r--r--drivers/cdrom/cdrom.c6
-rw-r--r--drivers/cdrom/viocd.c130
-rw-r--r--drivers/char/Kconfig70
-rw-r--r--drivers/char/Makefile10
-rw-r--r--drivers/char/agp/Kconfig2
-rw-r--r--drivers/char/agp/agp.h3
-rw-r--r--drivers/char/agp/amd-k7-agp.c2
-rw-r--r--drivers/char/agp/ati-agp.c12
-rw-r--r--drivers/char/agp/compat_ioctl.c1
-rw-r--r--drivers/char/agp/efficeon-agp.c2
-rw-r--r--drivers/char/agp/frontend.c1
-rw-r--r--drivers/char/agp/generic.c2
-rw-r--r--drivers/char/agp/hp-agp.c1
-rw-r--r--drivers/char/agp/i460-agp.c4
-rw-r--r--drivers/char/agp/intel-agp.c40
-rw-r--r--drivers/char/agp/nvidia-agp.c3
-rw-r--r--drivers/char/agp/sgi-agp.c1
-rw-r--r--drivers/char/agp/via-agp.c5
-rw-r--r--drivers/char/amiserial.c3
-rw-r--r--drivers/char/decserial.c67
-rw-r--r--drivers/char/drm/drm_bufs.c13
-rw-r--r--drivers/char/drm/i915_dma.c14
-rw-r--r--drivers/char/drm/i915_drv.h7
-rw-r--r--drivers/char/drm/i915_irq.c12
-rw-r--r--drivers/char/drm/via_dmablit.c5
-rw-r--r--drivers/char/dsp56k.c4
-rw-r--r--drivers/char/esp.c6
-rw-r--r--drivers/char/hpet.c90
-rw-r--r--drivers/char/hvc_beat.c4
-rw-r--r--drivers/char/hvc_iseries.c8
-rw-r--r--drivers/char/hvc_lguest.c177
-rw-r--r--drivers/char/hvc_rtas.c2
-rw-r--r--drivers/char/hvc_xen.c159
-rw-r--r--drivers/char/hvcs.c12
-rw-r--r--drivers/char/hw_random/Kconfig2
-rw-r--r--drivers/char/i8k.c4
-rw-r--r--drivers/char/ip2/ip2main.c19
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c6
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c3
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c21
-rw-r--r--drivers/char/istallion.c8
-rw-r--r--drivers/char/keyboard.c4
-rw-r--r--drivers/char/lcd.c1
-rw-r--r--drivers/char/lp.c5
-rw-r--r--drivers/char/mbcs.c27
-rw-r--r--drivers/char/mbcs.h10
-rw-r--r--drivers/char/mmtimer.c1
-rw-r--r--drivers/char/mspec.c66
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c10
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c7
-rw-r--r--drivers/char/pcmcia/synclink_cs.c3
-rw-r--r--drivers/char/ps3flash.c440
-rw-r--r--drivers/char/pty.c9
-rw-r--r--drivers/char/random.c19
-rw-r--r--drivers/char/raw.c5
-rw-r--r--drivers/char/rio/rio_linux.c4
-rw-r--r--drivers/char/rio/riocmd.c4
-rw-r--r--drivers/char/rio/riotable.c3
-rw-r--r--drivers/char/rocket.c3
-rw-r--r--drivers/char/rtc.c32
-rw-r--r--drivers/char/serial167.c6
-rw-r--r--drivers/char/snsc.c3
-rw-r--r--drivers/char/sonypi.c9
-rw-r--r--drivers/char/stallion.c12
-rw-r--r--drivers/char/synclink.c3
-rw-r--r--drivers/char/synclink_gt.c82
-rw-r--r--drivers/char/synclinkmp.c3
-rw-r--r--drivers/char/tipar.c6
-rw-r--r--drivers/char/tpm/tpm.c2
-rw-r--r--drivers/char/tpm/tpm.h2
-rw-r--r--drivers/char/tpm/tpm_atmel.c2
-rw-r--r--drivers/char/tpm/tpm_atmel.h2
-rw-r--r--drivers/char/tpm/tpm_bios.c24
-rw-r--r--drivers/char/tpm/tpm_nsc.c2
-rw-r--r--drivers/char/tpm/tpm_tis.c2
-rw-r--r--drivers/char/tty_io.c62
-rw-r--r--drivers/char/tty_ioctl.c14
-rw-r--r--drivers/char/viotape.c142
-rw-r--r--drivers/char/vme_scc.c8
-rw-r--r--drivers/char/vt_ioctl.c19
-rw-r--r--drivers/char/watchdog/Kconfig133
-rw-r--r--drivers/char/watchdog/Makefile44
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c7
-rw-r--r--drivers/char/watchdog/bfin_wdt.c490
-rw-r--r--drivers/char/watchdog/booke_wdt.c2
-rw-r--r--drivers/char/watchdog/cpu5wdt.c4
-rw-r--r--drivers/char/watchdog/davinci_wdt.c281
-rw-r--r--drivers/char/watchdog/eurotechwdt.c13
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c38
-rw-r--r--drivers/char/watchdog/iop_wdt.c262
-rw-r--r--drivers/char/watchdog/machzwd.c1
-rw-r--r--drivers/char/watchdog/mixcomwd.c5
-rw-r--r--drivers/char/watchdog/mpc5200_wdt.c286
-rw-r--r--drivers/char/watchdog/mpc83xx_wdt.c3
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c3
-rw-r--r--drivers/char/watchdog/mtx-1_wdt.c1
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c218
-rw-r--r--drivers/char/watchdog/omap_wdt.c4
-rw-r--r--drivers/char/watchdog/pcwd_usb.c3
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c6
-rw-r--r--drivers/char/watchdog/sa1100_wdt.c3
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c4
-rw-r--r--drivers/char/watchdog/sc1200wdt.c4
-rw-r--r--drivers/char/watchdog/sc520_wdt.c4
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c24
-rw-r--r--drivers/clocksource/acpi_pm.c2
-rw-r--r--drivers/connector/connector.c16
-rw-r--r--drivers/cpufreq/Kconfig27
-rw-r--r--drivers/cpufreq/cpufreq.c36
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c19
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c22
-rw-r--r--drivers/cpufreq/cpufreq_stats.c18
-rw-r--r--drivers/crypto/Kconfig10
-rw-r--r--drivers/crypto/geode-aes.c1
-rw-r--r--drivers/crypto/padlock-aes.c4
-rw-r--r--drivers/crypto/padlock-sha.c53
-rw-r--r--drivers/dma/ioatdma.c25
-rw-r--r--drivers/dma/ioatdma.h3
-rw-r--r--drivers/dma/iovlock.c27
-rw-r--r--drivers/edac/Kconfig53
-rw-r--r--drivers/edac/Makefile17
-rw-r--r--drivers/edac/amd76x_edac.c75
-rw-r--r--drivers/edac/e752x_edac.c322
-rw-r--r--drivers/edac/e7xxx_edac.c125
-rw-r--r--drivers/edac/edac_core.h (renamed from drivers/edac/edac_mc.h)504
-rw-r--r--drivers/edac/edac_device.c746
-rw-r--r--drivers/edac/edac_device_sysfs.c896
-rw-r--r--drivers/edac/edac_mc.c1696
-rw-r--r--drivers/edac/edac_mc_sysfs.c1042
-rw-r--r--drivers/edac/edac_module.c222
-rw-r--r--drivers/edac/edac_module.h85
-rw-r--r--drivers/edac/edac_pci.c493
-rw-r--r--drivers/edac/edac_pci_sysfs.c763
-rw-r--r--drivers/edac/edac_stub.c46
-rw-r--r--drivers/edac/i3000_edac.c506
-rw-r--r--drivers/edac/i5000_edac.c1505
-rw-r--r--drivers/edac/i82443bxgx_edac.c402
-rw-r--r--drivers/edac/i82860_edac.c56
-rw-r--r--drivers/edac/i82875p_edac.c92
-rw-r--r--drivers/edac/i82975x_edac.c666
-rw-r--r--drivers/edac/pasemi_edac.c299
-rw-r--r--drivers/edac/r82600_edac.c77
-rw-r--r--drivers/eisa/eisa-bus.c9
-rw-r--r--drivers/firewire/Kconfig3
-rw-r--r--drivers/firewire/fw-card.c6
-rw-r--r--drivers/firewire/fw-device.c11
-rw-r--r--drivers/firewire/fw-ohci.c29
-rw-r--r--drivers/firewire/fw-sbp2.c72
-rw-r--r--drivers/firewire/fw-transaction.c13
-rw-r--r--drivers/firewire/fw-transaction.h6
-rw-r--r--drivers/firmware/dmi-id.c62
-rw-r--r--drivers/firmware/dmi_scan.c57
-rw-r--r--drivers/firmware/edd.c4
-rw-r--r--drivers/firmware/efivars.c4
-rw-r--r--drivers/hid/Kconfig5
-rw-r--r--drivers/hid/usbhid/hid-core.c5
-rw-r--r--drivers/hid/usbhid/hid-quirks.c138
-rw-r--r--drivers/hwmon/Kconfig92
-rw-r--r--drivers/hwmon/Makefile4
-rw-r--r--drivers/hwmon/abituguru.c45
-rw-r--r--drivers/hwmon/abituguru3.c1141
-rw-r--r--drivers/hwmon/ams/ams-core.c1
-rw-r--r--drivers/hwmon/applesmc.c16
-rw-r--r--drivers/hwmon/coretemp.c2
-rw-r--r--drivers/hwmon/dme1737.c2080
-rw-r--r--drivers/hwmon/ds1621.c161
-rw-r--r--drivers/hwmon/f71805f.c178
-rw-r--r--drivers/hwmon/fscher.c4
-rw-r--r--drivers/hwmon/hdaps.c4
-rw-r--r--drivers/hwmon/it87.c497
-rw-r--r--drivers/hwmon/lm63.c4
-rw-r--r--drivers/hwmon/lm78.c4
-rw-r--r--drivers/hwmon/lm83.c12
-rw-r--r--drivers/hwmon/lm90.c78
-rw-r--r--drivers/hwmon/lm93.c2655
-rw-r--r--drivers/hwmon/pc87360.c232
-rw-r--r--drivers/hwmon/pc87427.c2
-rw-r--r--drivers/hwmon/sis5595.c510
-rw-r--r--drivers/hwmon/smsc47b397.c7
-rw-r--r--drivers/hwmon/smsc47m1.c16
-rw-r--r--drivers/hwmon/smsc47m192.c37
-rw-r--r--drivers/hwmon/thmc50.c440
-rw-r--r--drivers/hwmon/via686a.c538
-rw-r--r--drivers/hwmon/vt8231.c318
-rw-r--r--drivers/hwmon/w83627ehf.c661
-rw-r--r--drivers/hwmon/w83627hf.c155
-rw-r--r--drivers/hwmon/w83781d.c6
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c52
-rw-r--r--drivers/i2c/busses/Kconfig8
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-gpio.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c4
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c1
-rw-r--r--drivers/i2c/busses/i2c-isa.c192
-rw-r--r--drivers/i2c/busses/i2c-mpc.c11
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c31
-rw-r--r--drivers/i2c/busses/i2c-piix4.c6
-rw-r--r--drivers/i2c/busses/i2c-pxa.c2
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c4
-rw-r--r--drivers/i2c/chips/ds1682.c3
-rw-r--r--drivers/i2c/chips/isp1301_omap.c42
-rw-r--r--drivers/i2c/chips/menelaus.c3
-rw-r--r--drivers/i2c/chips/tps65010.c2
-rw-r--r--drivers/i2c/i2c-core.c10
-rw-r--r--drivers/ide/Kconfig128
-rw-r--r--drivers/ide/arm/icside.c32
-rw-r--r--drivers/ide/arm/ide_arm.c20
-rw-r--r--drivers/ide/cris/ide-cris.c20
-rw-r--r--drivers/ide/ide-acpi.c42
-rw-r--r--drivers/ide/ide-cd.c4
-rw-r--r--drivers/ide/ide-disk.c23
-rw-r--r--drivers/ide/ide-dma.c93
-rw-r--r--drivers/ide/ide-floppy.c70
-rw-r--r--drivers/ide/ide-io.c63
-rw-r--r--drivers/ide/ide-iops.c54
-rw-r--r--drivers/ide/ide-lib.c157
-rw-r--r--drivers/ide/ide-probe.c8
-rw-r--r--drivers/ide/ide-tape.c2
-rw-r--r--drivers/ide/ide-timing.h20
-rw-r--r--drivers/ide/ide.c123
-rw-r--r--drivers/ide/legacy/Makefile2
-rw-r--r--drivers/ide/legacy/ali14xx.c15
-rw-r--r--drivers/ide/legacy/dtc2278.c7
-rw-r--r--drivers/ide/legacy/falconide.c2
-rw-r--r--drivers/ide/legacy/hd.c2
-rw-r--r--drivers/ide/legacy/ht6560b.c21
-rw-r--r--drivers/ide/legacy/ide-cs.c1
-rw-r--r--drivers/ide/legacy/ide_platform.c182
-rw-r--r--drivers/ide/legacy/qd65xx.c79
-rw-r--r--drivers/ide/legacy/umc8672.c9
-rw-r--r--drivers/ide/mips/au1xxx-ide.c19
-rw-r--r--drivers/ide/mips/swarm.c3
-rw-r--r--drivers/ide/pci/aec62xx.c29
-rw-r--r--drivers/ide/pci/alim15x3.c61
-rw-r--r--drivers/ide/pci/amd74xx.c37
-rw-r--r--drivers/ide/pci/atiixp.c43
-rw-r--r--drivers/ide/pci/cmd640.c46
-rw-r--r--drivers/ide/pci/cmd64x.c64
-rw-r--r--drivers/ide/pci/cs5520.c61
-rw-r--r--drivers/ide/pci/cs5530.c36
-rw-r--r--drivers/ide/pci/cs5535.c58
-rw-r--r--drivers/ide/pci/cy82c693.c23
-rw-r--r--drivers/ide/pci/generic.c15
-rw-r--r--drivers/ide/pci/hpt34x.c31
-rw-r--r--drivers/ide/pci/hpt366.c210
-rw-r--r--drivers/ide/pci/it8213.c50
-rw-r--r--drivers/ide/pci/it821x.c32
-rw-r--r--drivers/ide/pci/jmicron.c96
-rw-r--r--drivers/ide/pci/ns87415.c10
-rw-r--r--drivers/ide/pci/opti621.c23
-rw-r--r--drivers/ide/pci/pdc202xx_new.c106
-rw-r--r--drivers/ide/pci/pdc202xx_old.c44
-rw-r--r--drivers/ide/pci/piix.c49
-rw-r--r--drivers/ide/pci/rz1000.c1
-rw-r--r--drivers/ide/pci/sc1200.c73
-rw-r--r--drivers/ide/pci/scc_pata.c138
-rw-r--r--drivers/ide/pci/serverworks.c108
-rw-r--r--drivers/ide/pci/sgiioc4.c89
-rw-r--r--drivers/ide/pci/siimage.c170
-rw-r--r--drivers/ide/pci/sis5513.c54
-rw-r--r--drivers/ide/pci/sl82c105.c47
-rw-r--r--drivers/ide/pci/slc90e66.c25
-rw-r--r--drivers/ide/pci/tc86c001.c16
-rw-r--r--drivers/ide/pci/triflex.c17
-rw-r--r--drivers/ide/pci/trm290.c1
-rw-r--r--drivers/ide/pci/via82cxxx.c58
-rw-r--r--drivers/ide/ppc/mpc8xx.c25
-rw-r--r--drivers/ide/ppc/pmac.c71
-rw-r--r--drivers/ide/setup-pci.c59
-rw-r--r--drivers/ieee1394/Kconfig2
-rw-r--r--drivers/ieee1394/eth1394.c53
-rw-r--r--drivers/ieee1394/ieee1394_core.c2
-rw-r--r--drivers/ieee1394/nodemgr.c17
-rw-r--r--drivers/ieee1394/ohci1394.c4
-rw-r--r--drivers/ieee1394/raw1394.c2
-rw-r--r--drivers/ieee1394/sbp2.c19
-rw-r--r--drivers/infiniband/core/addr.c6
-rw-r--r--drivers/infiniband/core/agent.c24
-rw-r--r--drivers/infiniband/core/agent.h6
-rw-r--r--drivers/infiniband/core/cm.c53
-rw-r--r--drivers/infiniband/core/cma.c70
-rw-r--r--drivers/infiniband/core/device.c6
-rw-r--r--drivers/infiniband/core/fmr_pool.c22
-rw-r--r--drivers/infiniband/core/mad.c26
-rw-r--r--drivers/infiniband/core/mad_rmpp.c8
-rw-r--r--drivers/infiniband/core/multicast.c2
-rw-r--r--drivers/infiniband/core/sa_query.c16
-rw-r--r--drivers/infiniband/core/sysfs.c9
-rw-r--r--drivers/infiniband/core/ucma.c74
-rw-r--r--drivers/infiniband/core/umem.c25
-rw-r--r--drivers/infiniband/core/user_mad.c151
-rw-r--r--drivers/infiniband/core/uverbs.h1
-rw-r--r--drivers/infiniband/core/uverbs_main.c16
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c1
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c1
-rw-r--r--drivers/infiniband/hw/amso1100/c2_qp.c1
-rw-r--r--drivers/infiniband/hw/amso1100/c2_vq.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c5
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c36
-rw-r--r--drivers/infiniband/hw/ehca/ehca_av.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h111
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes_pSeries.h156
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c35
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c11
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c70
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c147
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h7
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c151
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mcast.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c1430
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.h23
-rw-r--r--drivers/infiniband/hw/ehca/ehca_pd.c26
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qes.h22
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c372
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c17
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_tools.h61
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c58
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c162
-rw-r--r--drivers/infiniband/hw/ehca/hcp_phyp.c2
-rw-r--r--drivers/infiniband/hw/ehca/hipz_fns_core.h4
-rw-r--r--drivers/infiniband/hw/ehca/hipz_hw.h24
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.c223
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.h32
-rw-r--r--drivers/infiniband/hw/ipath/Makefile1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c94
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c23
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c106
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c14
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c74
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c187
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c57
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c38
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c129
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h27
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.c365
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.h71
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c53
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c31
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c73
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c308
-rw-r--r--drivers/infiniband/hw/ipath/ipath_stats.c71
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c40
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c98
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c382
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c26
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c331
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h49
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c2
-rw-r--r--drivers/infiniband/hw/mlx4/main.c50
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h16
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c100
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c202
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c9
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c102
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c221
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c36
-rw-r--r--drivers/infiniband/hw/mthca/mthca_wqe.h15
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h30
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c38
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c69
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c89
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c41
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c3
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h5
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c2
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c6
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c48
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c33
-rw-r--r--drivers/input/evdev.c2
-rw-r--r--drivers/input/input.c62
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c8
-rw-r--r--drivers/input/keyboard/gpio_keys.c1
-rw-r--r--drivers/input/misc/Kconfig1
-rw-r--r--drivers/input/misc/atlas_btns.c9
-rw-r--r--drivers/input/misc/pcspkr.c14
-rw-r--r--drivers/input/misc/wistron_btns.c2
-rw-r--r--drivers/input/mouse/appletouch.c113
-rw-r--r--drivers/input/mouse/lifebook.c8
-rw-r--r--drivers/input/mouse/synaptics.c2
-rw-r--r--drivers/input/mouse/touchkit_ps2.h3
-rw-r--r--drivers/input/serio/Kconfig2
-rw-r--r--drivers/input/serio/ambakmi.c6
-rw-r--r--drivers/input/serio/gscps2.c6
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h10
-rw-r--r--drivers/input/serio/i8042.c6
-rw-r--r--drivers/input/serio/pcips2.c6
-rw-r--r--drivers/input/serio/sa1111ps2.c6
-rw-r--r--drivers/input/serio/serio.c11
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c2
-rw-r--r--drivers/isdn/Kconfig12
-rw-r--r--drivers/isdn/act2000/Kconfig2
-rw-r--r--drivers/isdn/divert/divert_procfs.c11
-rw-r--r--drivers/isdn/gigaset/Kconfig10
-rw-r--r--drivers/isdn/hardware/eicon/diva_didd.c5
-rw-r--r--drivers/isdn/hisax/Kconfig1
-rw-r--r--drivers/isdn/hisax/avm_pci.c224
-rw-r--r--drivers/isdn/hisax/bkm_a8.c8
-rw-r--r--drivers/isdn/hisax/config.c4
-rw-r--r--drivers/isdn/hisax/diva.c513
-rw-r--r--drivers/isdn/hisax/elsa.c494
-rw-r--r--drivers/isdn/hisax/hfc_usb.c603
-rw-r--r--drivers/isdn/hisax/hfc_usb.h130
-rw-r--r--drivers/isdn/hisax/sedlbauer.c276
-rw-r--r--drivers/isdn/hisax/telespci.c8
-rw-r--r--drivers/isdn/hisax/w6692.c7
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c274
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c5
-rw-r--r--drivers/isdn/i4l/Kconfig3
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c5
-rw-r--r--drivers/isdn/i4l/isdn_common.c7
-rw-r--r--drivers/isdn/i4l/isdn_net.c270
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c6
-rw-r--r--drivers/isdn/icn/Kconfig2
-rw-r--r--drivers/isdn/pcbit/Kconfig2
-rw-r--r--drivers/isdn/sc/Kconfig2
-rw-r--r--drivers/isdn/sc/card.h2
-rw-r--r--drivers/isdn/sc/command.c2
-rw-r--r--drivers/isdn/sc/timer.c2
-rw-r--r--drivers/kvm/Kconfig8
-rw-r--r--drivers/kvm/kvm.h20
-rw-r--r--drivers/kvm/kvm_main.c124
-rw-r--r--drivers/kvm/mmu.c151
-rw-r--r--drivers/kvm/paging_tmpl.h2
-rw-r--r--drivers/kvm/x86_emulate.c30
-rw-r--r--drivers/leds/Kconfig35
-rw-r--r--drivers/leds/Makefile4
-rw-r--r--drivers/leds/led-class.c49
-rw-r--r--drivers/leds/led-triggers.c27
-rw-r--r--drivers/leds/leds-cobalt-qube.c102
-rw-r--r--drivers/leds/leds-cobalt-raq.c138
-rw-r--r--drivers/leds/leds-cobalt.c43
-rw-r--r--drivers/leds/leds-gpio.c199
-rw-r--r--drivers/leds/leds-locomo.c2
-rw-r--r--drivers/leds/leds.h8
-rw-r--r--drivers/leds/ledtrig-timer.c49
-rw-r--r--drivers/lguest/Kconfig30
-rw-r--r--drivers/lguest/Makefile19
-rw-r--r--drivers/lguest/README47
-rw-r--r--drivers/lguest/core.c776
-rw-r--r--drivers/lguest/hypercalls.c300
-rw-r--r--drivers/lguest/interrupts_and_traps.c446
-rw-r--r--drivers/lguest/io.c626
-rw-r--r--drivers/lguest/lg.h300
-rw-r--r--drivers/lguest/lguest.c1102
-rw-r--r--drivers/lguest/lguest_asm.S93
-rw-r--r--drivers/lguest/lguest_bus.c218
-rw-r--r--drivers/lguest/lguest_user.c382
-rw-r--r--drivers/lguest/page_tables.c680
-rw-r--r--drivers/lguest/segments.c177
-rw-r--r--drivers/lguest/switcher.S350
-rw-r--r--drivers/macintosh/Kconfig5
-rw-r--r--drivers/macintosh/adb-iop.c1
-rw-r--r--drivers/macintosh/adb.c4
-rw-r--r--drivers/macintosh/adbhid.c21
-rw-r--r--drivers/macintosh/ans-lcd.c3
-rw-r--r--drivers/macintosh/ans-lcd.h11
-rw-r--r--drivers/macintosh/mac_hid.c1
-rw-r--r--drivers/macintosh/macio_asic.c3
-rw-r--r--drivers/macintosh/rack-meter.c1
-rw-r--r--drivers/macintosh/smu.c3
-rw-r--r--drivers/macintosh/therm_adt746x.c5
-rw-r--r--drivers/macintosh/therm_pm72.c6
-rw-r--r--drivers/macintosh/therm_windtunnel.c3
-rw-r--r--drivers/macintosh/via-pmu.c36
-rw-r--r--drivers/macintosh/via-pmu68k.c240
-rw-r--r--drivers/macintosh/windfarm_core.c3
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c3
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c2
-rw-r--r--drivers/md/Kconfig2
-rw-r--r--drivers/md/dm-bio-list.h3
-rw-r--r--drivers/md/dm-crypt.c23
-rw-r--r--drivers/md/dm-emc.c15
-rw-r--r--drivers/md/dm-exception-store.c1
-rw-r--r--drivers/md/dm-io.c8
-rw-r--r--drivers/md/dm-mpath-rdac.c2
-rw-r--r--drivers/md/dm-mpath.c4
-rw-r--r--drivers/md/dm-raid1.c7
-rw-r--r--drivers/md/dm-snap.c2
-rw-r--r--drivers/md/dm-table.c8
-rw-r--r--drivers/md/dm-zero.c2
-rw-r--r--drivers/md/dm.c32
-rw-r--r--drivers/md/faulty.c12
-rw-r--r--drivers/md/linear.c18
-rw-r--r--drivers/md/md.c30
-rw-r--r--drivers/md/multipath.c25
-rw-r--r--drivers/md/raid0.c18
-rw-r--r--drivers/md/raid1.c67
-rw-r--r--drivers/md/raid10.c55
-rw-r--r--drivers/md/raid5.c108
-rw-r--r--drivers/media/Kconfig74
-rw-r--r--drivers/media/common/Kconfig2
-rw-r--r--drivers/media/common/ir-functions.c28
-rw-r--r--drivers/media/common/ir-keymaps.c62
-rw-r--r--drivers/media/common/saa7146_core.c42
-rw-r--r--drivers/media/common/saa7146_fops.c5
-rw-r--r--drivers/media/common/saa7146_i2c.c23
-rw-r--r--drivers/media/common/saa7146_vbi.c9
-rw-r--r--drivers/media/common/saa7146_video.c19
-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.c4
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c7
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--drivers/media/dvb/bt8xx/Makefile2
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c1
-rw-r--r--drivers/media/dvb/bt8xx/bt878.h7
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c6
-rw-r--r--drivers/media/dvb/cinergyT2/Makefile2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c28
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c105
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c7
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c125
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h15
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c37
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c56
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig31
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile8
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-fe.c1488
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c157
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-script.h203
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c1141
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.h3496
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c18
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c23
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c676
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c53
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h1
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c21
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c28
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c79
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h32
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h11
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c7
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c84
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c93
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h32
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c127
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h5
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c25
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c8
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c2
-rw-r--r--drivers/media/dvb/frontends/Kconfig33
-rw-r--r--drivers/media/dvb/frontends/Makefile6
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c1
-rw-r--r--drivers/media/dvb/frontends/cx22700.c1
-rw-r--r--drivers/media/dvb/frontends/cx22702.c1
-rw-r--r--drivers/media/dvb/frontends/cx24110.c1
-rw-r--r--drivers/media/dvb/frontends/cx24123.c3
-rw-r--r--drivers/media/dvb/frontends/dib0070.c580
-rw-r--r--drivers/media/dvb/frontends/dib0070.h44
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c1
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c192
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c727
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c908
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h14
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h57
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c357
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h73
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c1
-rw-r--r--drivers/media/dvb/frontends/isl6421.c1
-rw-r--r--drivers/media/dvb/frontends/l64781.c1
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c1
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c1
-rw-r--r--drivers/media/dvb/frontends/mt2060.c1
-rw-r--r--drivers/media/dvb/frontends/mt2131.c314
-rw-r--r--drivers/media/dvb/frontends/mt2131.h54
-rw-r--r--drivers/media/dvb/frontends/mt2131_priv.h49
-rw-r--r--drivers/media/dvb/frontends/mt2266.c287
-rw-r--r--drivers/media/dvb/frontends/mt2266.h37
-rw-r--r--drivers/media/dvb/frontends/mt312.c1
-rw-r--r--drivers/media/dvb/frontends/mt352.c1
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c24
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h3
-rw-r--r--drivers/media/dvb/frontends/or51132.c2
-rw-r--r--drivers/media/dvb/frontends/or51211.c32
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c729
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h73
-rw-r--r--drivers/media/dvb/frontends/sp8870.c1
-rw-r--r--drivers/media/dvb/frontends/sp887x.c1
-rw-r--r--drivers/media/dvb/frontends/stv0297.c4
-rw-r--r--drivers/media/dvb/frontends/stv0299.c3
-rw-r--r--drivers/media/dvb/frontends/tda10021.c4
-rw-r--r--drivers/media/dvb/frontends/tda10023.c12
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c1
-rw-r--r--drivers/media/dvb/frontends/tda10086.c1
-rw-r--r--drivers/media/dvb/frontends/tda8083.c9
-rw-r--r--drivers/media/dvb/frontends/ves1820.c4
-rw-r--r--drivers/media/dvb/frontends/zl10353.c1
-rw-r--r--drivers/media/dvb/pluto2/Makefile2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig2
-rw-r--r--drivers/media/dvb/ttpci/Makefile2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c18
-rw-r--r--drivers/media/dvb/ttpci/av7110.h1
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c20
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c4
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c36
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c5
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c8
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c33
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c1
-rw-r--r--drivers/media/dvb/ttusb-budget/Makefile2
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c1
-rw-r--r--drivers/media/dvb/ttusb-dec/Makefile2
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c1
-rw-r--r--drivers/media/radio/Kconfig28
-rw-r--r--drivers/media/radio/radio-aimslab.c3
-rw-r--r--drivers/media/radio/radio-aztech.c1
-rw-r--r--drivers/media/radio/radio-cadet.c4
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c4
-rw-r--r--drivers/media/radio/radio-gemtek.c619
-rw-r--r--drivers/media/radio/radio-rtrack2.c1
-rw-r--r--drivers/media/radio/radio-sf16fmi.c1
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c1
-rw-r--r--drivers/media/radio/radio-terratec.c3
-rw-r--r--drivers/media/radio/radio-trust.c1
-rw-r--r--drivers/media/radio/radio-typhoon.c1
-rw-r--r--drivers/media/video/Kconfig24
-rw-r--r--drivers/media/video/Makefile30
-rw-r--r--drivers/media/video/adv7170.c8
-rw-r--r--drivers/media/video/adv7175.c8
-rw-r--r--drivers/media/video/arv.c3
-rw-r--r--drivers/media/video/bt819.c9
-rw-r--r--drivers/media/video/bt856.c8
-rw-r--r--drivers/media/video/bt866.c2
-rw-r--r--drivers/media/video/bt8xx/Kconfig2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c720
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c65
-rw-r--r--drivers/media/video/bt8xx/bttv-gpio.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c5
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c35
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c6
-rw-r--r--drivers/media/video/bt8xx/bttv.h4
-rw-r--r--drivers/media/video/bt8xx/bttvp.h8
-rw-r--r--drivers/media/video/btcx-risc.c1
-rw-r--r--drivers/media/video/bw-qcam.c18
-rw-r--r--drivers/media/video/c-qcam.c4
-rw-r--r--drivers/media/video/cafe_ccic.c56
-rw-r--r--drivers/media/video/compat_ioctl32.c5
-rw-r--r--drivers/media/video/cpia.c1
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c13
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c9
-rw-r--r--drivers/media/video/cx2341x.c19
-rw-r--r--drivers/media/video/cx23885/Kconfig20
-rw-r--r--drivers/media/video/cx23885/Makefile9
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c280
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c1530
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c213
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c382
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h431
-rw-r--r--drivers/media/video/cx23885/cx23885.h301
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c75
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c98
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h6
-rw-r--r--drivers/media/video/cx88/Kconfig6
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c315
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c45
-rw-r--r--drivers/media/video/cx88/cx88-cards.c243
-rw-r--r--drivers/media/video/cx88/cx88-core.c222
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c147
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c52
-rw-r--r--drivers/media/video/cx88/cx88-input.c43
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c146
-rw-r--r--drivers/media/video/cx88/cx88-reg.h35
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c22
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c13
-rw-r--r--drivers/media/video/cx88/cx88-video.c171
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c17
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.h7
-rw-r--r--drivers/media/video/cx88/cx88.h47
-rw-r--r--drivers/media/video/dpc7146.c5
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c7
-rw-r--r--drivers/media/video/et61x251/Kconfig2
-rw-r--r--drivers/media/video/et61x251/et61x251.h23
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c232
-rw-r--r--drivers/media/video/et61x251/et61x251_sensor.h8
-rw-r--r--drivers/media/video/et61x251/et61x251_tas5130d1b.c2
-rw-r--r--drivers/media/video/ir-kbd-i2c.c89
-rw-r--r--drivers/media/video/ivtv/Kconfig22
-rw-r--r--drivers/media/video/ivtv/Makefile5
-rw-r--r--drivers/media/video/ivtv/ivtv-audio.c74
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c84
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h67
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c16
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c362
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h687
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c211
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c29
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c29
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.h7
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c37
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c224
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c356
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.h27
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c47
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h8
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c119
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.h13
-rw-r--r--drivers/media/video/ivtv/ivtv-routing.c (renamed from drivers/media/video/ivtv/ivtv-video.c)90
-rw-r--r--drivers/media/video/ivtv/ivtv-routing.h (renamed from drivers/media/video/ivtv/ivtv-audio.h)12
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c159
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.c46
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c292
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.h9
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h7
-rw-r--r--drivers/media/video/ivtv/ivtv-video.h24
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c55
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.h21
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c1190
-rw-r--r--drivers/media/video/msp3400-driver.c28
-rw-r--r--drivers/media/video/mt20xx.c335
-rw-r--r--drivers/media/video/mt20xx.h37
-rw-r--r--drivers/media/video/mxb.c4
-rw-r--r--drivers/media/video/ov511.c81
-rw-r--r--drivers/media/video/ov7670.c10
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_core.c1
-rw-r--r--drivers/media/video/planb.c33
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c310
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h12
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c63
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c218
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c2
-rw-r--r--drivers/media/video/pwc/pwc-if.c194
-rw-r--r--drivers/media/video/pwc/pwc.h5
-rw-r--r--drivers/media/video/saa5249.c8
-rw-r--r--drivers/media/video/saa6588.c1
-rw-r--r--drivers/media/video/saa7110.c4
-rw-r--r--drivers/media/video/saa7111.c8
-rw-r--r--drivers/media/video/saa7114.c10
-rw-r--r--drivers/media/video/saa7127.c10
-rw-r--r--drivers/media/video/saa7134/Kconfig6
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c19
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c106
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c214
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c192
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c26
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c21
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c43
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c30
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c47
-rw-r--r--drivers/media/video/saa7134/saa7134-vbi.c7
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c210
-rw-r--r--drivers/media/video/saa7134/saa7134.h31
-rw-r--r--drivers/media/video/saa7185.c8
-rw-r--r--drivers/media/video/saa7191.c4
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h9
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c286
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7630.c214
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7660.c88
-rw-r--r--drivers/media/video/stradis.c2
-rw-r--r--drivers/media/video/stv680.c58
-rw-r--r--drivers/media/video/tcm825x.c928
-rw-r--r--drivers/media/video/tcm825x.h199
-rw-r--r--drivers/media/video/tda8290.c560
-rw-r--r--drivers/media/video/tda8290.h54
-rw-r--r--drivers/media/video/tda9887.c111
-rw-r--r--drivers/media/video/tea5761.c320
-rw-r--r--drivers/media/video/tea5761.h47
-rw-r--r--drivers/media/video/tea5767.c203
-rw-r--r--drivers/media/video/tea5767.h47
-rw-r--r--drivers/media/video/tuner-core.c307
-rw-r--r--drivers/media/video/tuner-driver.h99
-rw-r--r--drivers/media/video/tuner-i2c.h70
-rw-r--r--drivers/media/video/tuner-simple.c408
-rw-r--r--drivers/media/video/tuner-simple.h46
-rw-r--r--drivers/media/video/tuner-types.c30
-rw-r--r--drivers/media/video/tvaudio.c5
-rw-r--r--drivers/media/video/tveeprom.c9
-rw-r--r--drivers/media/video/tvmixer.c6
-rw-r--r--drivers/media/video/tvp5150.c2
-rw-r--r--drivers/media/video/usbvideo/konicawc.c2
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--drivers/media/video/usbvideo/vicam.c184
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c9
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c44
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c4
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c1681
-rw-r--r--drivers/media/video/usbvision/usbvision.h13
-rw-r--r--drivers/media/video/v4l1-compat.c1
-rw-r--r--drivers/media/video/v4l2-common.c25
-rw-r--r--drivers/media/video/v4l2-int-device.c158
-rw-r--r--drivers/media/video/videobuf-core.c (renamed from drivers/media/video/video-buf.c)785
-rw-r--r--drivers/media/video/videobuf-dma-sg.c726
-rw-r--r--drivers/media/video/videobuf-dvb.c (renamed from drivers/media/video/video-buf-dvb.c)9
-rw-r--r--drivers/media/video/videobuf-vmalloc.c370
-rw-r--r--drivers/media/video/videodev.c39
-rw-r--r--drivers/media/video/vino.c7
-rw-r--r--drivers/media/video/vivi.c351
-rw-r--r--drivers/media/video/vp27smpx.c212
-rw-r--r--drivers/media/video/w9968cf.c3
-rw-r--r--drivers/media/video/wm8739.c2
-rw-r--r--drivers/media/video/wm8775.c2
-rw-r--r--drivers/media/video/zc0301/Kconfig2
-rw-r--r--drivers/media/video/zc0301/zc0301.h21
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c150
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c1
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c1
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h2
-rw-r--r--drivers/media/video/zoran.h5
-rw-r--r--drivers/media/video/zoran_card.c64
-rw-r--r--drivers/media/video/zoran_card.h8
-rw-r--r--drivers/media/video/zoran_device.c69
-rw-r--r--drivers/media/video/zoran_driver.c327
-rw-r--r--drivers/media/video/zoran_procfs.c9
-rw-r--r--drivers/media/video/zr36016.c4
-rw-r--r--drivers/media/video/zr36050.c6
-rw-r--r--drivers/media/video/zr36060.c6
-rw-r--r--drivers/media/video/zr364xx.c18
-rw-r--r--drivers/message/fusion/Kconfig15
-rw-r--r--drivers/message/fusion/Makefile37
-rw-r--r--drivers/message/fusion/mptbase.c864
-rw-r--r--drivers/message/fusion/mptbase.h207
-rw-r--r--drivers/message/fusion/mptctl.c266
-rw-r--r--drivers/message/fusion/mptdebug.h288
-rw-r--r--drivers/message/fusion/mptfc.c111
-rw-r--r--drivers/message/fusion/mptlan.c5
-rw-r--r--drivers/message/fusion/mptsas.c482
-rw-r--r--drivers/message/fusion/mptscsih.c599
-rw-r--r--drivers/message/fusion/mptscsih.h1
-rw-r--r--drivers/message/fusion/mptspi.c60
-rw-r--r--drivers/message/i2o/i2o_block.c9
-rw-r--r--drivers/mfd/mcp-core.c3
-rw-r--r--drivers/mfd/ucb1x00-core.c3
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/asus-laptop.c45
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c107
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c88
-rw-r--r--drivers/misc/ibmasm/command.c6
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c3
-rw-r--r--drivers/misc/ibmasm/module.c3
-rw-r--r--drivers/misc/msi-laptop.c4
-rw-r--r--drivers/misc/sony-laptop.c420
-rw-r--r--drivers/misc/thinkpad_acpi.c690
-rw-r--r--drivers/misc/thinkpad_acpi.h47
-rw-r--r--drivers/misc/tifm_core.c9
-rw-r--r--drivers/mmc/card/Kconfig7
-rw-r--r--drivers/mmc/card/Makefile2
-rw-r--r--drivers/mmc/card/block.c33
-rw-r--r--drivers/mmc/card/queue.c24
-rw-r--r--drivers/mmc/card/sdio_uart.c1158
-rw-r--r--drivers/mmc/core/Makefile4
-rw-r--r--drivers/mmc/core/bus.c85
-rw-r--r--drivers/mmc/core/core.c301
-rw-r--r--drivers/mmc/core/core.h24
-rw-r--r--drivers/mmc/core/host.c19
-rw-r--r--drivers/mmc/core/mmc.c160
-rw-r--r--drivers/mmc/core/mmc_ops.c202
-rw-r--r--drivers/mmc/core/mmc_ops.h5
-rw-r--r--drivers/mmc/core/sd.c162
-rw-r--r--drivers/mmc/core/sd_ops.c157
-rw-r--r--drivers/mmc/core/sd_ops.h3
-rw-r--r--drivers/mmc/core/sdio.c395
-rw-r--r--drivers/mmc/core/sdio_bus.c270
-rw-r--r--drivers/mmc/core/sdio_bus.h22
-rw-r--r--drivers/mmc/core/sdio_cis.c346
-rw-r--r--drivers/mmc/core/sdio_cis.h23
-rw-r--r--drivers/mmc/core/sdio_io.c548
-rw-r--r--drivers/mmc/core/sdio_irq.c267
-rw-r--r--drivers/mmc/core/sdio_ops.c176
-rw-r--r--drivers/mmc/core/sdio_ops.h22
-rw-r--r--drivers/mmc/host/Kconfig30
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/at91_mci.c50
-rw-r--r--drivers/mmc/host/au1xmmc.c60
-rw-r--r--drivers/mmc/host/imxmmc.c34
-rw-r--r--drivers/mmc/host/mmc_spi.c1408
-rw-r--r--drivers/mmc/host/mmci.c23
-rw-r--r--drivers/mmc/host/mmci.h2
-rw-r--r--drivers/mmc/host/omap.c14
-rw-r--r--drivers/mmc/host/pxamci.c73
-rw-r--r--drivers/mmc/host/pxamci.h2
-rw-r--r--drivers/mmc/host/ricoh_mmc.c151
-rw-r--r--drivers/mmc/host/sdhci.c229
-rw-r--r--drivers/mmc/host/sdhci.h6
-rw-r--r--drivers/mmc/host/tifm_sd.c32
-rw-r--r--drivers/mmc/host/wbsd.c68
-rw-r--r--drivers/mmc/host/wbsd.h2
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/devices/docprobe.c3
-rw-r--r--drivers/mtd/maps/Kconfig4
-rw-r--r--drivers/mtd/maps/lubbock-flash.c6
-rw-r--r--drivers/mtd/maps/mainstone-flash.c5
-rw-r--r--drivers/mtd/maps/physmap_of.c349
-rw-r--r--drivers/mtd/mtdchar.c1
-rw-r--r--drivers/mtd/mtdpart.c4
-rw-r--r--drivers/mtd/mtdsuper.c2
-rw-r--r--drivers/mtd/nand/at91_nand.c5
-rw-r--r--drivers/mtd/nand/cafe_nand.c3
-rw-r--r--drivers/mtd/nand/diskonchip.c3
-rw-r--r--drivers/mtd/nand/edb7312.c10
-rw-r--r--drivers/mtd/nand/nand_base.c12
-rw-r--r--drivers/mtd/rfd_ftl.c1
-rw-r--r--drivers/mtd/ubi/build.c25
-rw-r--r--drivers/mtd/ubi/cdev.c49
-rw-r--r--drivers/mtd/ubi/debug.c44
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/eba.c100
-rw-r--r--drivers/mtd/ubi/gluebi.c27
-rw-r--r--drivers/mtd/ubi/io.c65
-rw-r--r--drivers/mtd/ubi/kapi.c19
-rw-r--r--drivers/mtd/ubi/misc.c4
-rw-r--r--drivers/mtd/ubi/scan.c127
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/mtd/ubi/ubi.h3
-rw-r--r--drivers/mtd/ubi/upd.c4
-rw-r--r--drivers/mtd/ubi/vmt.c53
-rw-r--r--drivers/mtd/ubi/vtbl.c85
-rw-r--r--drivers/mtd/ubi/wl.c95
-rw-r--r--drivers/net/3c501.c43
-rw-r--r--drivers/net/3c501.h2
-rw-r--r--drivers/net/3c503.c6
-rw-r--r--drivers/net/3c505.c79
-rw-r--r--drivers/net/3c507.c60
-rw-r--r--drivers/net/3c509.c28
-rw-r--r--drivers/net/3c515.c6
-rw-r--r--drivers/net/3c523.c23
-rw-r--r--drivers/net/3c527.c9
-rw-r--r--drivers/net/3c59x.c85
-rw-r--r--drivers/net/7990.c47
-rw-r--r--drivers/net/7990.h2
-rw-r--r--drivers/net/8139cp.c144
-rw-r--r--drivers/net/8139too.c429
-rw-r--r--drivers/net/82596.c85
-rw-r--r--drivers/net/Kconfig422
-rw-r--r--drivers/net/Makefile17
-rw-r--r--drivers/net/a2065.c58
-rw-r--r--drivers/net/ac3200.c10
-rw-r--r--drivers/net/acenic.c51
-rw-r--r--drivers/net/amd8111e.c52
-rw-r--r--drivers/net/amd8111e.h26
-rw-r--r--drivers/net/apne.c12
-rw-r--r--drivers/net/appletalk/cops.c22
-rw-r--r--drivers/net/appletalk/ipddp.c3
-rw-r--r--drivers/net/appletalk/ipddp.h2
-rw-r--r--drivers/net/appletalk/ltpc.c12
-rw-r--r--drivers/net/arcnet/arcnet.c18
-rw-r--r--drivers/net/arcnet/com90io.c2
-rw-r--r--drivers/net/arcnet/rfc1051.c4
-rw-r--r--drivers/net/arcnet/rfc1201.c6
-rw-r--r--drivers/net/ariadne.c45
-rw-r--r--drivers/net/arm/am79c961a.c10
-rw-r--r--drivers/net/arm/at91_ether.c19
-rw-r--r--drivers/net/arm/ep93xx_eth.c72
-rw-r--r--drivers/net/arm/ether1.c12
-rw-r--r--drivers/net/arm/ether3.c14
-rw-r--r--drivers/net/arm/etherh.c10
-rw-r--r--drivers/net/at1700.c45
-rw-r--r--drivers/net/atarilance.c104
-rw-r--r--drivers/net/atl1/atl1_ethtool.c14
-rw-r--r--drivers/net/atl1/atl1_hw.c2
-rw-r--r--drivers/net/atl1/atl1_hw.h9
-rw-r--r--drivers/net/atl1/atl1_main.c64
-rw-r--r--drivers/net/atp.c58
-rw-r--r--drivers/net/au1000_eth.c23
-rw-r--r--drivers/net/au1000_eth.h1
-rw-r--r--drivers/net/ax88796.c57
-rw-r--r--drivers/net/b44.c814
-rw-r--r--drivers/net/b44.h83
-rw-r--r--drivers/net/bfin_mac.c1081
-rw-r--r--drivers/net/bfin_mac.h95
-rw-r--r--drivers/net/bmac.c68
-rw-r--r--drivers/net/bnx2.c442
-rw-r--r--drivers/net/bnx2.h18
-rw-r--r--drivers/net/bnx2_fw.h45
-rw-r--r--drivers/net/bnx2_fw2.h35
-rw-r--r--drivers/net/bonding/bond_3ad.c46
-rw-r--r--drivers/net/bonding/bond_3ad.h20
-rw-r--r--drivers/net/bonding/bond_alb.c22
-rw-r--r--drivers/net/bonding/bond_alb.h4
-rw-r--r--drivers/net/bonding/bond_main.c163
-rw-r--r--drivers/net/bonding/bond_sysfs.c23
-rw-r--r--drivers/net/bonding/bonding.h6
-rw-r--r--drivers/net/bsd_comp.c9
-rw-r--r--drivers/net/cassini.c63
-rw-r--r--drivers/net/cassini.h2
-rw-r--r--drivers/net/chelsio/Makefile2
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cxgb2.c24
-rw-r--r--drivers/net/chelsio/mac.c368
-rw-r--r--drivers/net/chelsio/sge.c29
-rw-r--r--drivers/net/chelsio/sge.h2
-rw-r--r--drivers/net/chelsio/subr.c2
-rw-r--r--drivers/net/cris/eth_v10.c8
-rw-r--r--drivers/net/cs89x0.c22
-rw-r--r--drivers/net/cxgb3/adapter.h22
-rw-r--r--drivers/net/cxgb3/common.h20
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h52
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h20
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c382
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c97
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h2
-rw-r--r--drivers/net/cxgb3/regs.h10
-rw-r--r--drivers/net/cxgb3/sge.c202
-rw-r--r--drivers/net/cxgb3/sge_defs.h4
-rw-r--r--drivers/net/cxgb3/t3_hw.c107
-rw-r--r--drivers/net/cxgb3/t3cdev.h3
-rw-r--r--drivers/net/cxgb3/version.h2
-rw-r--r--drivers/net/cxgb3/xgmac.c33
-rw-r--r--drivers/net/de600.c22
-rw-r--r--drivers/net/de600.h1
-rw-r--r--drivers/net/de620.c36
-rw-r--r--drivers/net/declance.c66
-rw-r--r--drivers/net/defxx.c18
-rw-r--r--drivers/net/depca.c55
-rw-r--r--drivers/net/dgrs.c1615
-rw-r--r--drivers/net/dgrs.h38
-rw-r--r--drivers/net/dgrs_asstruct.h37
-rw-r--r--drivers/net/dgrs_bcomm.h148
-rw-r--r--drivers/net/dgrs_es4h.h183
-rw-r--r--drivers/net/dgrs_ether.h135
-rw-r--r--drivers/net/dgrs_firmware.c9966
-rw-r--r--drivers/net/dgrs_i82596.h473
-rw-r--r--drivers/net/dgrs_plx9060.h175
-rw-r--r--drivers/net/dl2k.c39
-rw-r--r--drivers/net/dl2k.h1
-rw-r--r--drivers/net/dm9000.c64
-rw-r--r--drivers/net/dummy.c1
-rw-r--r--drivers/net/e100.c91
-rw-r--r--drivers/net/e1000/e1000.h1
-rw-r--r--drivers/net/e1000/e1000_ethtool.c31
-rw-r--r--drivers/net/e1000/e1000_hw.c31
-rw-r--r--drivers/net/e1000/e1000_hw.h6
-rw-r--r--drivers/net/e1000/e1000_main.c80
-rw-r--r--drivers/net/e1000e/82571.c1351
-rw-r--r--drivers/net/e1000e/Makefile37
-rw-r--r--drivers/net/e1000e/defines.h739
-rw-r--r--drivers/net/e1000e/e1000.h514
-rw-r--r--drivers/net/e1000e/es2lan.c1232
-rw-r--r--drivers/net/e1000e/ethtool.c1780
-rw-r--r--drivers/net/e1000e/hw.h864
-rw-r--r--drivers/net/e1000e/ich8lan.c2225
-rw-r--r--drivers/net/e1000e/lib.c2493
-rw-r--r--drivers/net/e1000e/netdev.c4438
-rw-r--r--drivers/net/e1000e/param.c382
-rw-r--r--drivers/net/e1000e/phy.c1773
-rw-r--r--drivers/net/e2100.c2
-rw-r--r--drivers/net/eepro.c56
-rw-r--r--drivers/net/eepro100.c10
-rw-r--r--drivers/net/eexpress.c58
-rw-r--r--drivers/net/ehea/ehea.h17
-rw-r--r--drivers/net/ehea/ehea_ethtool.c31
-rw-r--r--drivers/net/ehea/ehea_main.c608
-rw-r--r--drivers/net/ehea/ehea_phyp.h1
-rw-r--r--drivers/net/ehea/ehea_qmr.c29
-rw-r--r--drivers/net/ehea/ehea_qmr.h4
-rw-r--r--drivers/net/epic100.c48
-rw-r--r--drivers/net/eql.c25
-rw-r--r--drivers/net/es3210.c24
-rw-r--r--drivers/net/eth16i.c51
-rw-r--r--drivers/net/ewrk3.c54
-rw-r--r--drivers/net/fealnx.c12
-rw-r--r--drivers/net/fec.c106
-rw-r--r--drivers/net/fec_8xx/fec_8xx.h2
-rw-r--r--drivers/net/fec_8xx/fec_main.c62
-rw-r--r--drivers/net/fec_8xx/fec_mii.c5
-rw-r--r--drivers/net/forcedeth.c195
-rw-r--r--drivers/net/fs_enet/Kconfig1
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c518
-rw-r--r--drivers/net/fs_enet/fs_enet.h91
-rw-r--r--drivers/net/fs_enet/mac-fcc.c190
-rw-r--r--drivers/net/fs_enet/mac-fec.c81
-rw-r--r--drivers/net/fs_enet/mac-scc.c110
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c458
-rw-r--r--drivers/net/fs_enet/mii-fec.c152
-rw-r--r--drivers/net/gianfar.c107
-rw-r--r--drivers/net/gianfar.h4
-rw-r--r--drivers/net/gianfar_ethtool.c21
-rw-r--r--drivers/net/gianfar_mii.c2
-rw-r--r--drivers/net/gianfar_mii.h2
-rw-r--r--drivers/net/hamachi.c12
-rw-r--r--drivers/net/hamradio/6pack.c15
-rw-r--r--drivers/net/hamradio/baycom_epp.c5
-rw-r--r--drivers/net/hamradio/bpqether.c45
-rw-r--r--drivers/net/hamradio/dmascc.c9
-rw-r--r--drivers/net/hamradio/hdlcdrv.c3
-rw-r--r--drivers/net/hamradio/mkiss.c14
-rw-r--r--drivers/net/hamradio/scc.c9
-rw-r--r--drivers/net/hamradio/yam.c8
-rw-r--r--drivers/net/hp-plus.c8
-rw-r--r--drivers/net/hp.c7
-rw-r--r--drivers/net/hp100.c11
-rw-r--r--drivers/net/hplance.c1
-rw-r--r--drivers/net/hydra.c8
-rw-r--r--drivers/net/ibm_emac/Kconfig70
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c29
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.c8
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.c48
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.h2
-rw-r--r--drivers/net/ibm_newemac/Kconfig63
-rw-r--r--drivers/net/ibm_newemac/Makefile11
-rw-r--r--drivers/net/ibm_newemac/core.c2906
-rw-r--r--drivers/net/ibm_newemac/core.h355
-rw-r--r--drivers/net/ibm_newemac/debug.c238
-rw-r--r--drivers/net/ibm_newemac/debug.h78
-rw-r--r--drivers/net/ibm_newemac/emac.h268
-rw-r--r--drivers/net/ibm_newemac/mal.c711
-rw-r--r--drivers/net/ibm_newemac/mal.h276
-rw-r--r--drivers/net/ibm_newemac/phy.c373
-rw-r--r--drivers/net/ibm_newemac/phy.h80
-rw-r--r--drivers/net/ibm_newemac/rgmii.c323
-rw-r--r--drivers/net/ibm_newemac/rgmii.h76
-rw-r--r--drivers/net/ibm_newemac/tah.c173
-rw-r--r--drivers/net/ibm_newemac/tah.h90
-rw-r--r--drivers/net/ibm_newemac/zmii.c322
-rw-r--r--drivers/net/ibm_newemac/zmii.h73
-rw-r--r--drivers/net/ibmlana.c45
-rw-r--r--drivers/net/ibmlana.h1
-rw-r--r--drivers/net/ibmveth.c502
-rw-r--r--drivers/net/ibmveth.h59
-rw-r--r--drivers/net/ifb.c24
-rw-r--r--drivers/net/ioc3-eth.c141
-rw-r--r--drivers/net/ipg.c2332
-rw-r--r--drivers/net/ipg.h856
-rw-r--r--drivers/net/irda/Kconfig37
-rw-r--r--drivers/net/irda/Makefile3
-rw-r--r--drivers/net/irda/actisys-sir.c2
-rw-r--r--drivers/net/irda/ali-ircc.c4
-rw-r--r--drivers/net/irda/donauboe.c1
-rw-r--r--drivers/net/irda/ep7211-sir.c89
-rw-r--r--drivers/net/irda/irda-usb.c25
-rw-r--r--drivers/net/irda/irport.c5
-rw-r--r--drivers/net/irda/irtty-sir.c3
-rw-r--r--drivers/net/irda/kingsun-sir.c6
-rw-r--r--drivers/net/irda/ks959-sir.c938
-rw-r--r--drivers/net/irda/ksdazzle-sir.c832
-rw-r--r--drivers/net/irda/mcs7780.c5
-rw-r--r--drivers/net/irda/nsc-ircc.c1
-rw-r--r--drivers/net/irda/sir_dev.c4
-rw-r--r--drivers/net/irda/smsc-ircc2.c4
-rw-r--r--drivers/net/irda/stir4200.c3
-rw-r--r--drivers/net/irda/via-ircc.c3
-rw-r--r--drivers/net/irda/vlsi_ir.c2
-rw-r--r--drivers/net/irda/vlsi_ir.h6
-rw-r--r--drivers/net/irda/w83977af_ir.c3
-rw-r--r--drivers/net/isa-skeleton.c7
-rw-r--r--drivers/net/iseries_veth.c29
-rw-r--r--drivers/net/ixgb/ixgb.h1
-rw-r--r--drivers/net/ixgb/ixgb_ee.c16
-rw-r--r--drivers/net/ixgb/ixgb_ee.h28
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c21
-rw-r--r--drivers/net/ixgb/ixgb_hw.h4
-rw-r--r--drivers/net/ixgb/ixgb_main.c30
-rw-r--r--drivers/net/ixgbe/Makefile36
-rw-r--r--drivers/net/ixgbe/ixgbe.h259
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c589
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c1175
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h86
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c948
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c2872
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.c494
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.h50
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h1332
-rw-r--r--drivers/net/ixp2000/enp2611.c1
-rw-r--r--drivers/net/ixp2000/ixpdev.c39
-rw-r--r--drivers/net/ixp2000/ixpdev.h2
-rw-r--r--drivers/net/jazzsonic.c72
-rw-r--r--drivers/net/lance.c10
-rw-r--r--drivers/net/lguest_net.c555
-rw-r--r--drivers/net/lib82596.c82
-rw-r--r--drivers/net/lib8390.c55
-rw-r--r--drivers/net/lne390.c11
-rw-r--r--drivers/net/loopback.c128
-rw-r--r--drivers/net/lp486e.c60
-rw-r--r--drivers/net/mac8390.c2
-rw-r--r--drivers/net/mac89x0.c15
-rw-r--r--drivers/net/macb.c47
-rw-r--r--drivers/net/macb.h1
-rw-r--r--drivers/net/mace.c69
-rw-r--r--drivers/net/macmace.c56
-rw-r--r--drivers/net/macsonic.c22
-rw-r--r--drivers/net/macvlan.c25
-rw-r--r--drivers/net/meth.c36
-rw-r--r--drivers/net/mipsnet.c27
-rw-r--r--drivers/net/mlx4/catas.c106
-rw-r--r--drivers/net/mlx4/cmd.c14
-rw-r--r--drivers/net/mlx4/cq.c2
-rw-r--r--drivers/net/mlx4/eq.c69
-rw-r--r--drivers/net/mlx4/fw.c2
-rw-r--r--drivers/net/mlx4/icm.c134
-rw-r--r--drivers/net/mlx4/icm.h9
-rw-r--r--drivers/net/mlx4/intf.c2
-rw-r--r--drivers/net/mlx4/main.c154
-rw-r--r--drivers/net/mlx4/mcg.c2
-rw-r--r--drivers/net/mlx4/mlx4.h23
-rw-r--r--drivers/net/mlx4/mr.c257
-rw-r--r--drivers/net/mlx4/pd.c2
-rw-r--r--drivers/net/mlx4/qp.c5
-rw-r--r--drivers/net/mlx4/reset.c3
-rw-r--r--drivers/net/mlx4/srq.c4
-rw-r--r--drivers/net/mv643xx_eth.c100
-rw-r--r--drivers/net/mv643xx_eth.h6
-rw-r--r--drivers/net/mvme147.c13
-rw-r--r--drivers/net/myri10ge/myri10ge.c237
-rw-r--r--drivers/net/myri_sbus.c78
-rw-r--r--drivers/net/myri_sbus.h1
-rw-r--r--drivers/net/natsemi.c67
-rw-r--r--drivers/net/ne-h8300.c12
-rw-r--r--drivers/net/ne.c9
-rw-r--r--drivers/net/ne2.c21
-rw-r--r--drivers/net/ne2k-pci.c17
-rw-r--r--drivers/net/ne3210.c12
-rw-r--r--drivers/net/netconsole.c775
-rw-r--r--drivers/net/netx-eth.c19
-rw-r--r--drivers/net/netxen/netxen_nic.h8
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c52
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h6
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c10
-rw-r--r--drivers/net/netxen/netxen_nic_init.c7
-rw-r--r--drivers/net/netxen/netxen_nic_main.c159
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c14
-rw-r--r--drivers/net/ni5010.c59
-rw-r--r--drivers/net/ni52.c2
-rw-r--r--drivers/net/ni65.c1
-rw-r--r--drivers/net/niu.c7939
-rw-r--r--drivers/net/niu.h3222
-rw-r--r--drivers/net/ns83820.c161
-rw-r--r--drivers/net/pasemi_mac.c960
-rw-r--r--drivers/net/pasemi_mac.h82
-rw-r--r--drivers/net/pci-skeleton.c84
-rw-r--r--drivers/net/pcmcia/3c574_cs.c9
-rw-r--r--drivers/net/pcmcia/3c589_cs.c11
-rw-r--r--drivers/net/pcmcia/axnet_cs.c15
-rw-r--r--drivers/net/pcmcia/com20020_cs.c3
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c9
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c3
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c14
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c13
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c32
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c10
-rw-r--r--drivers/net/pcnet32.c231
-rw-r--r--drivers/net/phy/Kconfig23
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/fixed.c310
-rw-r--r--drivers/net/phy/mdio-bitbang.c187
-rw-r--r--drivers/net/phy/phy.c63
-rw-r--r--drivers/net/phy/phy_device.c10
-rw-r--r--drivers/net/phy/vitesse.c46
-rw-r--r--drivers/net/plip.c83
-rw-r--r--drivers/net/ppp_async.c3
-rw-r--r--drivers/net/ppp_deflate.c6
-rw-r--r--drivers/net/ppp_generic.c63
-rw-r--r--drivers/net/ppp_mppe.c17
-rw-r--r--drivers/net/ppp_synctty.c3
-rw-r--r--drivers/net/pppoe.c158
-rw-r--r--drivers/net/pppol2tp.c137
-rw-r--r--drivers/net/pppox.c18
-rw-r--r--drivers/net/ps3_gelic_net.c373
-rw-r--r--drivers/net/ps3_gelic_net.h25
-rw-r--r--[-rwxr-xr-x]drivers/net/qla3xxx.c199
-rw-r--r--[-rwxr-xr-x]drivers/net/qla3xxx.h9
-rw-r--r--drivers/net/r8169.c150
-rw-r--r--drivers/net/rionet.c28
-rw-r--r--drivers/net/rrunner.c40
-rw-r--r--drivers/net/rrunner.h2
-rw-r--r--drivers/net/s2io-regs.h123
-rw-r--r--drivers/net/s2io.c2117
-rw-r--r--drivers/net/s2io.h67
-rw-r--r--drivers/net/saa9730.c102
-rw-r--r--drivers/net/saa9730.h1
-rw-r--r--drivers/net/sb1000.c20
-rw-r--r--drivers/net/sb1250-mac.c1450
-rw-r--r--drivers/net/sc92031.c16
-rw-r--r--drivers/net/seeq8005.c37
-rw-r--r--drivers/net/sgiseeq.c75
-rw-r--r--drivers/net/shaper.c84
-rw-r--r--drivers/net/sis190.c52
-rw-r--r--drivers/net/sis900.c66
-rw-r--r--drivers/net/sk98lin/Makefile87
-rw-r--r--drivers/net/sk98lin/h/lm80.h179
-rw-r--r--drivers/net/sk98lin/h/skaddr.h285
-rw-r--r--drivers/net/sk98lin/h/skcsum.h213
-rw-r--r--drivers/net/sk98lin/h/skdebug.h74
-rw-r--r--drivers/net/sk98lin/h/skdrv1st.h188
-rw-r--r--drivers/net/sk98lin/h/skdrv2nd.h447
-rw-r--r--drivers/net/sk98lin/h/skerror.h55
-rw-r--r--drivers/net/sk98lin/h/skgedrv.h51
-rw-r--r--drivers/net/sk98lin/h/skgehw.h2126
-rw-r--r--drivers/net/sk98lin/h/skgehwt.h48
-rw-r--r--drivers/net/sk98lin/h/skgei2c.h210
-rw-r--r--drivers/net/sk98lin/h/skgeinit.h797
-rw-r--r--drivers/net/sk98lin/h/skgepnm2.h334
-rw-r--r--drivers/net/sk98lin/h/skgepnmi.h962
-rw-r--r--drivers/net/sk98lin/h/skgesirq.h110
-rw-r--r--drivers/net/sk98lin/h/ski2c.h174
-rw-r--r--drivers/net/sk98lin/h/skqueue.h94
-rw-r--r--drivers/net/sk98lin/h/skrlmt.h438
-rw-r--r--drivers/net/sk98lin/h/sktimer.h63
-rw-r--r--drivers/net/sk98lin/h/sktypes.h69
-rw-r--r--drivers/net/sk98lin/h/skversion.h38
-rw-r--r--drivers/net/sk98lin/h/skvpd.h248
-rw-r--r--drivers/net/sk98lin/h/xmac_ii.h1579
-rw-r--r--drivers/net/sk98lin/skaddr.c1788
-rw-r--r--drivers/net/sk98lin/skdim.c742
-rw-r--r--drivers/net/sk98lin/skethtool.c627
-rw-r--r--drivers/net/sk98lin/skge.c5218
-rw-r--r--drivers/net/sk98lin/skgehwt.c171
-rw-r--r--drivers/net/sk98lin/skgeinit.c2005
-rw-r--r--drivers/net/sk98lin/skgemib.c1075
-rw-r--r--drivers/net/sk98lin/skgepnmi.c8210
-rw-r--r--drivers/net/sk98lin/skgesirq.c2229
-rw-r--r--drivers/net/sk98lin/ski2c.c1296
-rw-r--r--drivers/net/sk98lin/sklm80.c141
-rw-r--r--drivers/net/sk98lin/skqueue.c179
-rw-r--r--drivers/net/sk98lin/skrlmt.c3257
-rw-r--r--drivers/net/sk98lin/sktimer.c250
-rw-r--r--drivers/net/sk98lin/skvpd.c1091
-rw-r--r--drivers/net/sk98lin/skxmac2.c4160
-rw-r--r--drivers/net/skfp/drvfbi.c733
-rw-r--r--drivers/net/skfp/h/mbuf.h4
-rw-r--r--drivers/net/skfp/h/skfbi.h788
-rw-r--r--drivers/net/skfp/h/skfbiinc.h26
-rw-r--r--drivers/net/skfp/h/targethw.h33
-rw-r--r--drivers/net/skfp/hwt.c42
-rw-r--r--drivers/net/skfp/pmf.c2
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/skfp/smt.c2
-rw-r--r--drivers/net/skfp/srf.c4
-rw-r--r--drivers/net/skge.c66
-rw-r--r--drivers/net/skge.h3
-rw-r--r--drivers/net/sky2.c868
-rw-r--r--drivers/net/sky2.h129
-rw-r--r--drivers/net/slip.c4
-rw-r--r--drivers/net/smc-mca.c9
-rw-r--r--drivers/net/smc-ultra.c10
-rw-r--r--drivers/net/smc-ultra32.c10
-rw-r--r--drivers/net/smc911x.c80
-rw-r--r--drivers/net/smc911x.h6
-rw-r--r--drivers/net/smc9194.c68
-rw-r--r--drivers/net/smc91x.c79
-rw-r--r--drivers/net/smc91x.h5
-rw-r--r--drivers/net/spider_net.c122
-rw-r--r--drivers/net/spider_net.h3
-rw-r--r--drivers/net/spider_net_ethtool.c28
-rw-r--r--drivers/net/starfire.c166
-rw-r--r--drivers/net/stnic.c1
-rw-r--r--drivers/net/sun3_82586.c1
-rw-r--r--drivers/net/sun3lance.c90
-rw-r--r--drivers/net/sunbmac.c9
-rw-r--r--drivers/net/sundance.c26
-rw-r--r--drivers/net/sungem.c65
-rw-r--r--drivers/net/sungem.h1
-rw-r--r--drivers/net/sunhme.c14
-rw-r--r--drivers/net/sunlance.c146
-rw-r--r--drivers/net/sunqe.c106
-rw-r--r--drivers/net/sunqe.h1
-rw-r--r--drivers/net/sunvnet.c400
-rw-r--r--drivers/net/sunvnet.h15
-rw-r--r--drivers/net/tc35815.c65
-rw-r--r--drivers/net/tehuti.c2506
-rw-r--r--drivers/net/tehuti.h564
-rw-r--r--drivers/net/tehuti_fw.h10712
-rw-r--r--drivers/net/tg3.c785
-rw-r--r--drivers/net/tg3.h138
-rw-r--r--drivers/net/tlan.c1
-rw-r--r--drivers/net/tokenring/3c359.c70
-rw-r--r--drivers/net/tokenring/abyss.c14
-rw-r--r--drivers/net/tokenring/ibmtr.c69
-rw-r--r--drivers/net/tokenring/lanstreamer.c102
-rw-r--r--drivers/net/tokenring/madgemc.c24
-rw-r--r--drivers/net/tokenring/olympic.c184
-rw-r--r--drivers/net/tokenring/proteon.c9
-rw-r--r--drivers/net/tokenring/skisa.c9
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c4
-rw-r--r--drivers/net/tokenring/tms380tr.h18
-rw-r--r--drivers/net/tokenring/tmspci.c15
-rw-r--r--drivers/net/tsi108_eth.c49
-rw-r--r--drivers/net/tulip/de2104x.c24
-rw-r--r--drivers/net/tulip/de4x5.c50
-rw-r--r--drivers/net/tulip/dmfe.c16
-rw-r--r--drivers/net/tulip/interrupt.c54
-rw-r--r--drivers/net/tulip/tulip.h19
-rw-r--r--drivers/net/tulip/tulip_core.c45
-rw-r--r--drivers/net/tulip/uli526x.c130
-rw-r--r--drivers/net/tulip/winbond-840.c34
-rw-r--r--drivers/net/tulip/xircom_cb.c9
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c1
-rw-r--r--drivers/net/tun.c68
-rw-r--r--drivers/net/typhoon.c97
-rw-r--r--drivers/net/typhoon.h190
-rw-r--r--drivers/net/ucc_geth.c430
-rw-r--r--drivers/net/ucc_geth.h9
-rw-r--r--drivers/net/ucc_geth_ethtool.c389
-rw-r--r--drivers/net/ucc_geth_mii.c10
-rw-r--r--drivers/net/usb/asix.c1
-rw-r--r--drivers/net/usb/dm9601.c2
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/pegasus.c17
-rw-r--r--drivers/net/usb/rtl8150.c2
-rw-r--r--drivers/net/usb/usbnet.c39
-rw-r--r--drivers/net/usb/usbnet.h1
-rw-r--r--drivers/net/veth.c482
-rw-r--r--drivers/net/via-rhine.c81
-rw-r--r--drivers/net/via-velocity.c274
-rw-r--r--drivers/net/via-velocity.h207
-rw-r--r--drivers/net/wan/c101.c4
-rw-r--r--drivers/net/wan/cosa.c4
-rw-r--r--drivers/net/wan/cycx_main.c4
-rw-r--r--drivers/net/wan/cycx_x25.c35
-rw-r--r--drivers/net/wan/dlci.c17
-rw-r--r--drivers/net/wan/dscc4.c7
-rw-r--r--drivers/net/wan/farsync.c3
-rw-r--r--drivers/net/wan/hdlc.c20
-rw-r--r--drivers/net/wan/hdlc_cisco.c10
-rw-r--r--drivers/net/wan/hdlc_fr.c3
-rw-r--r--drivers/net/wan/hdlc_ppp.c2
-rw-r--r--drivers/net/wan/hostess_sv11.c5
-rw-r--r--drivers/net/wan/lapbether.c9
-rw-r--r--drivers/net/wan/lmc/lmc_main.c1
-rw-r--r--drivers/net/wan/lmc/lmc_proto.c2
-rw-r--r--drivers/net/wan/n2.c4
-rw-r--r--drivers/net/wan/pc300_drv.c3
-rw-r--r--drivers/net/wan/pc300too.c4
-rw-r--r--drivers/net/wan/pci200syn.c4
-rw-r--r--drivers/net/wan/sbni.c5
-rw-r--r--drivers/net/wan/sdla.c4
-rw-r--r--drivers/net/wan/sealevel.c3
-rw-r--r--drivers/net/wan/syncppp.c25
-rw-r--r--drivers/net/wan/wanxl.c4
-rw-r--r--drivers/net/wan/x25_asy.c4
-rw-r--r--drivers/net/wd.c9
-rw-r--r--drivers/net/wireless/Kconfig136
-rw-r--r--drivers/net/wireless/Makefile13
-rw-r--r--drivers/net/wireless/adm8211.c2053
-rw-r--r--drivers/net/wireless/adm8211.h656
-rw-r--r--drivers/net/wireless/airo.c56
-rw-r--r--drivers/net/wireless/airport.c1
-rw-r--r--drivers/net/wireless/arlan-main.c25
-rw-r--r--drivers/net/wireless/arlan-proc.c14
-rw-r--r--drivers/net/wireless/atmel.c8
-rw-r--r--drivers/net/wireless/b43/Kconfig131
-rw-r--r--drivers/net/wireless/b43/Makefile20
-rw-r--r--drivers/net/wireless/b43/b43.h854
-rw-r--r--drivers/net/wireless/b43/debugfs.c656
-rw-r--r--drivers/net/wireless/b43/debugfs.h89
-rw-r--r--drivers/net/wireless/b43/dma.c1494
-rw-r--r--drivers/net/wireless/b43/dma.h337
-rw-r--r--drivers/net/wireless/b43/leds.c235
-rw-r--r--drivers/net/wireless/b43/leds.h64
-rw-r--r--drivers/net/wireless/b43/lo.c1261
-rw-r--r--drivers/net/wireless/b43/lo.h112
-rw-r--r--drivers/net/wireless/b43/main.c4070
-rw-r--r--drivers/net/wireless/b43/main.h125
-rw-r--r--drivers/net/wireless/b43/pcmcia.c160
-rw-r--r--drivers/net/wireless/b43/pcmcia.h20
-rw-r--r--drivers/net/wireless/b43/phy.c4380
-rw-r--r--drivers/net/wireless/b43/phy.h297
-rw-r--r--drivers/net/wireless/b43/pio.c652
-rw-r--r--drivers/net/wireless/b43/pio.h152
-rw-r--r--drivers/net/wireless/b43/rfkill.c184
-rw-r--r--drivers/net/wireless/b43/rfkill.h58
-rw-r--r--drivers/net/wireless/b43/sysfs.c235
-rw-r--r--drivers/net/wireless/b43/sysfs.h9
-rw-r--r--drivers/net/wireless/b43/tables.c375
-rw-r--r--drivers/net/wireless/b43/tables.h28
-rw-r--r--drivers/net/wireless/b43/xmit.c650
-rw-r--r--drivers/net/wireless/b43/xmit.h250
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig89
-rw-r--r--drivers/net/wireless/b43legacy/Makefile14
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h832
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.c505
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.h89
-rw-r--r--drivers/net/wireless/b43legacy/dma.c1565
-rw-r--r--drivers/net/wireless/b43legacy/dma.h367
-rw-r--r--drivers/net/wireless/b43legacy/ilt.c336
-rw-r--r--drivers/net/wireless/b43legacy/ilt.h34
-rw-r--r--drivers/net/wireless/b43legacy/leds.c298
-rw-r--r--drivers/net/wireless/b43legacy/leds.h56
-rw-r--r--drivers/net/wireless/b43legacy/main.c3856
-rw-r--r--drivers/net/wireless/b43legacy/main.h127
-rw-r--r--drivers/net/wireless/b43legacy/phy.c2255
-rw-r--r--drivers/net/wireless/b43legacy/phy.h219
-rw-r--r--drivers/net/wireless/b43legacy/pio.c668
-rw-r--r--drivers/net/wireless/b43legacy/pio.h172
-rw-r--r--drivers/net/wireless/b43legacy/radio.c2158
-rw-r--r--drivers/net/wireless/b43legacy/radio.h98
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.c238
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.h9
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c642
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h259
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h6
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c33
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c2
-rw-r--r--drivers/net/wireless/hostap/hostap.h5
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c49
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c13
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c198
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h3
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c7
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c32
-rw-r--r--drivers/net/wireless/hostap/hostap_info.c17
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c40
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c101
-rw-r--r--drivers/net/wireless/hostap/hostap_proc.c15
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h5
-rw-r--r--drivers/net/wireless/ipw2100.c63
-rw-r--r--drivers/net/wireless/ipw2200.c282
-rw-r--r--drivers/net/wireless/ipw2200.h4
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig128
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h118
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c982
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.h191
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c2300
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h581
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c2295
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.h266
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c4736
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h341
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-channel.h161
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h1734
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h152
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h336
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h255
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hw.h537
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h470
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-priv.h308
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h229
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h91
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c8746
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c9340
-rw-r--r--drivers/net/wireless/iwlwifi/iwlwifi.h713
-rw-r--r--drivers/net/wireless/libertas/11d.c124
-rw-r--r--drivers/net/wireless/libertas/11d.h4
-rw-r--r--drivers/net/wireless/libertas/Makefile5
-rw-r--r--drivers/net/wireless/libertas/assoc.c147
-rw-r--r--drivers/net/wireless/libertas/assoc.h2
-rw-r--r--drivers/net/wireless/libertas/cmd.c666
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c377
-rw-r--r--drivers/net/wireless/libertas/debugfs.c147
-rw-r--r--drivers/net/wireless/libertas/decl.h19
-rw-r--r--drivers/net/wireless/libertas/defs.h157
-rw-r--r--drivers/net/wireless/libertas/dev.h81
-rw-r--r--drivers/net/wireless/libertas/ethtool.c83
-rw-r--r--drivers/net/wireless/libertas/fw.c349
-rw-r--r--drivers/net/wireless/libertas/host.h431
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h81
-rw-r--r--drivers/net/wireless/libertas/if_bootcmd.c40
-rw-r--r--drivers/net/wireless/libertas/if_cs.c969
-rw-r--r--drivers/net/wireless/libertas/if_usb.c369
-rw-r--r--drivers/net/wireless/libertas/if_usb.h8
-rw-r--r--drivers/net/wireless/libertas/join.c485
-rw-r--r--drivers/net/wireless/libertas/join.h35
-rw-r--r--drivers/net/wireless/libertas/main.c904
-rw-r--r--drivers/net/wireless/libertas/rx.c85
-rw-r--r--drivers/net/wireless/libertas/scan.c806
-rw-r--r--drivers/net/wireless/libertas/scan.h36
-rw-r--r--drivers/net/wireless/libertas/thread.h52
-rw-r--r--drivers/net/wireless/libertas/tx.c41
-rw-r--r--drivers/net/wireless/libertas/types.h67
-rw-r--r--drivers/net/wireless/libertas/wext.c392
-rw-r--r--drivers/net/wireless/libertas/wext.h9
-rw-r--r--drivers/net/wireless/net2280.h452
-rw-r--r--drivers/net/wireless/netwave_cs.c21
-rw-r--r--drivers/net/wireless/orinoco.c7
-rw-r--r--drivers/net/wireless/orinoco_cs.c1
-rw-r--r--drivers/net/wireless/orinoco_nortel.c1
-rw-r--r--drivers/net/wireless/orinoco_pci.c1
-rw-r--r--drivers/net/wireless/orinoco_plx.c1
-rw-r--r--drivers/net/wireless/orinoco_tmd.c3
-rw-r--r--drivers/net/wireless/p54.h81
-rw-r--r--drivers/net/wireless/p54common.c1019
-rw-r--r--drivers/net/wireless/p54common.h329
-rw-r--r--drivers/net/wireless/p54pci.c692
-rw-r--r--drivers/net/wireless/p54pci.h106
-rw-r--r--drivers/net/wireless/p54usb.c907
-rw-r--r--drivers/net/wireless/p54usb.h133
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c63
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c1
-rw-r--r--drivers/net/wireless/prism54/oid_mgt.c4
-rw-r--r--drivers/net/wireless/ray_cs.c86
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig130
-rw-r--r--drivers/net/wireless/rt2x00/Makefile22
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c1664
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h943
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c1971
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h1236
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c1832
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h798
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h838
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c205
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c368
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.h57
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c1202
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c124
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h119
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c438
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c474
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h127
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h292
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c146
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ring.h268
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c592
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h180
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c2557
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h1457
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c2110
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h1024
-rw-r--r--drivers/net/wireless/rtl8187.h6
-rw-r--r--drivers/net/wireless/rtl8187_dev.c144
-rw-r--r--drivers/net/wireless/rtl818x.h1
-rw-r--r--drivers/net/wireless/spectrum_cs.c1
-rw-r--r--drivers/net/wireless/strip.c24
-rw-r--r--drivers/net/wireless/wavelan.c60
-rw-r--r--drivers/net/wireless/wavelan_cs.c61
-rw-r--r--drivers/net/wireless/wl3501_cs.c93
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c75
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h43
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c157
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h65
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c7
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.c82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.h29
-rw-r--r--drivers/net/xen-netfront.c1817
-rw-r--r--drivers/net/yellowfin.c83
-rw-r--r--drivers/net/znet.c63
-rw-r--r--drivers/net/zorro8390.c18
-rw-r--r--drivers/nubus/nubus.c6
-rw-r--r--drivers/of/Kconfig3
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/base.c275
-rw-r--r--drivers/of/device.c131
-rw-r--r--drivers/of/platform.c96
-rw-r--r--drivers/oprofile/buffer_sync.c3
-rw-r--r--drivers/oprofile/event_buffer.h20
-rw-r--r--drivers/oprofile/oprof.c28
-rw-r--r--drivers/parisc/led.c2
-rw-r--r--drivers/parisc/superio.c1
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/parport/parport_cs.c3
-rw-r--r--drivers/parport/parport_pc.c4
-rw-r--r--drivers/parport/parport_serial.c3
-rw-r--r--drivers/pci/hotplug.c28
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c7
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c4
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c76
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_hpc.c57
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c60
-rw-r--r--drivers/pci/hotplug/pciehp_core.c24
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c20
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c203
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c24
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c6
-rw-r--r--drivers/pci/msi.c2
-rw-r--r--drivers/pci/pci-acpi.c32
-rw-r--r--drivers/pci/pci-driver.c8
-rw-r--r--drivers/pci/pci.c36
-rw-r--r--drivers/pci/pci.h20
-rw-r--r--drivers/pci/pcie/Kconfig9
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c12
-rw-r--r--drivers/pci/probe.c73
-rw-r--r--drivers/pci/proc.c7
-rw-r--r--drivers/pci/quirks.c71
-rw-r--r--drivers/pci/setup-bus.c5
-rw-r--r--drivers/pci/setup-irq.c2
-rw-r--r--drivers/pcmcia/cs.c13
-rw-r--r--drivers/pcmcia/ds.c66
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c2
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c2
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c2
-rw-r--r--drivers/pnp/card.c158
-rw-r--r--drivers/pnp/core.c60
-rw-r--r--drivers/pnp/driver.c77
-rw-r--r--drivers/pnp/interface.c212
-rw-r--r--drivers/pnp/isapnp/compat.c39
-rw-r--r--drivers/pnp/isapnp/core.c356
-rw-r--r--drivers/pnp/isapnp/proc.c62
-rw-r--r--drivers/pnp/manager.c157
-rw-r--r--drivers/pnp/pnpacpi/core.c113
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c452
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c339
-rw-r--r--drivers/pnp/pnpbios/core.c303
-rw-r--r--drivers/pnp/pnpbios/proc.c105
-rw-r--r--drivers/pnp/pnpbios/rsparser.c350
-rw-r--r--drivers/pnp/quirks.c163
-rw-r--r--drivers/pnp/resource.c116
-rw-r--r--drivers/pnp/support.c17
-rw-r--r--drivers/pnp/system.c40
-rw-r--r--drivers/power/Kconfig2
-rw-r--r--drivers/power/power_supply.h3
-rw-r--r--drivers/power/power_supply_sysfs.c16
-rw-r--r--drivers/rapidio/rio-scan.c6
-rw-r--r--drivers/rtc/Kconfig91
-rw-r--r--drivers/rtc/Makefile41
-rw-r--r--drivers/rtc/class.c5
-rw-r--r--drivers/rtc/rtc-bfin.c2
-rw-r--r--drivers/rtc/rtc-cmos.c33
-rw-r--r--drivers/rtc/rtc-dev.c2
-rw-r--r--drivers/rtc/rtc-ds1307.c2
-rw-r--r--drivers/rtc/rtc-ds1553.c4
-rw-r--r--drivers/rtc/rtc-ds1742.c4
-rw-r--r--drivers/rtc/rtc-m41t80.c2
-rw-r--r--drivers/rtc/rtc-m48t59.c2
-rw-r--r--drivers/rtc/rtc-max6900.c96
-rw-r--r--drivers/rtc/rtc-max6902.c6
-rw-r--r--drivers/rtc/rtc-rs5c348.c2
-rw-r--r--drivers/rtc/rtc-s3c.c2
-rw-r--r--drivers/rtc/rtc-sh.c1
-rw-r--r--drivers/rtc/rtc-stk17ta8.c422
-rw-r--r--drivers/rtc/rtc-v3020.c9
-rw-r--r--drivers/s390/block/dasd.c4
-rw-r--r--drivers/s390/block/dasd_devmap.c2
-rw-r--r--drivers/s390/block/dasd_diag.c38
-rw-r--r--drivers/s390/block/dasd_eckd.c32
-rw-r--r--drivers/s390/block/dasd_fba.c28
-rw-r--r--drivers/s390/block/dasd_int.h5
-rw-r--r--drivers/s390/block/dcssblk.c6
-rw-r--r--drivers/s390/block/xpram.c8
-rw-r--r--drivers/s390/char/Kconfig12
-rw-r--r--drivers/s390/char/con3215.c3
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/monwriter.c6
-rw-r--r--drivers/s390/char/raw3270.c7
-rw-r--r--drivers/s390/char/sclp.c5
-rw-r--r--drivers/s390/char/sclp_vt220.c62
-rw-r--r--drivers/s390/char/tape.h2
-rw-r--r--drivers/s390/char/tape_34xx.c35
-rw-r--r--drivers/s390/char/tape_3590.c63
-rw-r--r--drivers/s390/char/tape_block.c4
-rw-r--r--drivers/s390/char/tty3270.c9
-rw-r--r--drivers/s390/char/tty3270.h16
-rw-r--r--drivers/s390/char/vmur.c428
-rw-r--r--drivers/s390/char/vmur.h6
-rw-r--r--drivers/s390/char/vmwatchdog.c4
-rw-r--r--drivers/s390/char/zcore.c7
-rw-r--r--drivers/s390/cio/blacklist.c19
-rw-r--r--drivers/s390/cio/ccwgroup.c73
-rw-r--r--drivers/s390/cio/chp.c49
-rw-r--r--drivers/s390/cio/chsc.c26
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/cio.c18
-rw-r--r--drivers/s390/cio/cio_debug.h2
-rw-r--r--drivers/s390/cio/cmf.c252
-rw-r--r--drivers/s390/cio/css.c131
-rw-r--r--drivers/s390/cio/css.h4
-rw-r--r--drivers/s390/cio/device.c160
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c167
-rw-r--r--drivers/s390/cio/device_id.c48
-rw-r--r--drivers/s390/cio/device_ops.c498
-rw-r--r--drivers/s390/cio/qdio.c136
-rw-r--r--drivers/s390/crypto/ap_bus.c19
-rw-r--r--drivers/s390/crypto/zcrypt_mono.c4
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c9
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.h45
-rw-r--r--drivers/s390/net/claw.c10
-rw-r--r--drivers/s390/net/ctcmain.c7
-rw-r--r--drivers/s390/net/lcs.c12
-rw-r--r--drivers/s390/net/lcs.h1
-rw-r--r--drivers/s390/net/netiucv.c5
-rw-r--r--drivers/s390/net/qeth.h7
-rw-r--r--drivers/s390/net/qeth_eddp.c16
-rw-r--r--drivers/s390/net/qeth_main.c227
-rw-r--r--drivers/s390/net/qeth_mpc.h1
-rw-r--r--drivers/s390/net/qeth_sys.c8
-rw-r--r--drivers/s390/scsi/zfcp_aux.c17
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c10
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c10
-rw-r--r--drivers/s390/scsi/zfcp_def.h1
-rw-r--r--drivers/s390/scsi/zfcp_erp.c21
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c7
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c152
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c4
-rw-r--r--drivers/sbus/char/Kconfig1
-rw-r--r--drivers/sbus/char/bbc_envctrl.c15
-rw-r--r--drivers/sbus/char/bbc_i2c.c7
-rw-r--r--drivers/sbus/char/envctrl.c7
-rw-r--r--drivers/sbus/char/jsflash.c2
-rw-r--r--drivers/sbus/char/vfc_dev.c6
-rw-r--r--drivers/sbus/sbus.c14
-rw-r--r--drivers/scsi/3w-9xxx.c70
-rw-r--r--drivers/scsi/3w-9xxx.h5
-rw-r--r--drivers/scsi/Kconfig22
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/NCR53C9x.c10
-rw-r--r--drivers/scsi/NCR_D700.c3
-rw-r--r--drivers/scsi/NCR_Q720.c3
-rw-r--r--drivers/scsi/a4000t.c3
-rw-r--r--drivers/scsi/aacraid/aachba.c206
-rw-r--r--drivers/scsi/aacraid/aacraid.h20
-rw-r--r--drivers/scsi/aacraid/commsup.c16
-rw-r--r--drivers/scsi/aacraid/linit.c13
-rw-r--r--drivers/scsi/aacraid/nark.c3
-rw-r--r--drivers/scsi/aacraid/rkt.c2
-rw-r--r--drivers/scsi/aacraid/rx.c2
-rw-r--r--drivers/scsi/advansys.c28261
-rw-r--r--drivers/scsi/aha152x.c169
-rw-r--r--drivers/scsi/aha152x.h2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c23
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c22
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c11
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c11
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c24
-rw-r--r--drivers/scsi/arm/Kconfig9
-rw-r--r--drivers/scsi/arm/Makefile1
-rw-r--r--drivers/scsi/arm/cumana_1.c207
-rw-r--r--drivers/scsi/arm/ecoscsi.c236
-rw-r--r--drivers/scsi/arm/oak.c74
-rw-r--r--drivers/scsi/bvme6000_scsi.c3
-rw-r--r--drivers/scsi/dpt_i2o.c132
-rw-r--r--drivers/scsi/dpti.h9
-rw-r--r--drivers/scsi/esp_scsi.c3
-rw-r--r--drivers/scsi/gdth.c48
-rw-r--r--drivers/scsi/gdth.h6
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c39
-rw-r--r--drivers/scsi/ide-scsi.c10
-rw-r--r--drivers/scsi/imm.c3
-rw-r--r--drivers/scsi/ipr.c19
-rw-r--r--drivers/scsi/ips.c3
-rw-r--r--drivers/scsi/iscsi_tcp.c4
-rw-r--r--drivers/scsi/lasi700.c3
-rw-r--r--drivers/scsi/libiscsi.c112
-rw-r--r--drivers/scsi/libsas/Kconfig8
-rw-r--r--drivers/scsi/libsas/Makefile1
-rw-r--r--drivers/scsi/libsas/sas_ata.c816
-rw-r--r--drivers/scsi/libsas/sas_discover.c405
-rw-r--r--drivers/scsi/libsas/sas_dump.c2
-rw-r--r--drivers/scsi/libsas/sas_expander.c244
-rw-r--r--drivers/scsi/libsas/sas_init.c3
-rw-r--r--drivers/scsi/libsas/sas_internal.h3
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c74
-rw-r--r--drivers/scsi/lpfc/lpfc.h72
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c423
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h28
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c243
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c595
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c679
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c539
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h14
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c287
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h10
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c20
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c32
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c162
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c413
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c423
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h10
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c164
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.h2
-rw-r--r--drivers/scsi/megaraid.c8
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c14
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c3
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c4
-rw-r--r--drivers/scsi/mvme16x_scsi.c3
-rw-r--r--drivers/scsi/pcmcia/Kconfig7
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c3
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c3
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c3
-rw-r--r--drivers/scsi/ppa.c3
-rw-r--r--drivers/scsi/ps3rom.c533
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c66
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c1135
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h38
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h27
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h36
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c110
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c206
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c10
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c56
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c398
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c35
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
-rw-r--r--drivers/scsi/qlogicpti.c50
-rw-r--r--drivers/scsi/scsi.c2
-rw-r--r--drivers/scsi/scsi_debug.c2
-rw-r--r--drivers/scsi/scsi_devinfo.c3
-rw-r--r--drivers/scsi/scsi_lib.c52
-rw-r--r--drivers/scsi/scsi_netlink.c27
-rw-r--r--drivers/scsi/scsi_sysctl.c1
-rw-r--r--drivers/scsi/scsi_sysfs.c25
-rw-r--r--drivers/scsi/scsi_tgt_lib.c2
-rw-r--r--drivers/scsi/scsi_transport_fc.c2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c84
-rw-r--r--drivers/scsi/scsi_transport_sas.c125
-rw-r--r--drivers/scsi/scsi_transport_spi.c28
-rw-r--r--drivers/scsi/sd.c18
-rw-r--r--drivers/scsi/seagate.c2
-rw-r--r--drivers/scsi/sim710.c6
-rw-r--r--drivers/scsi/sr.c4
-rw-r--r--drivers/scsi/st.c16
-rw-r--r--drivers/scsi/st.h3
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c2
-rw-r--r--drivers/scsi/tmscsim.c3
-rw-r--r--drivers/scsi/wd33c93.c4
-rw-r--r--drivers/scsi/zorro7xx.c3
-rw-r--r--drivers/serial/68328serial.c71
-rw-r--r--drivers/serial/8250.c92
-rw-r--r--drivers/serial/8250_early.c12
-rw-r--r--drivers/serial/8250_hp300.c1
-rw-r--r--drivers/serial/8250_pci.c212
-rw-r--r--drivers/serial/Kconfig79
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/amba-pl011.c3
-rw-r--r--drivers/serial/bfin_5xx.c222
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h48
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c539
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c18
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h16
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c24
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.h16
-rw-r--r--drivers/serial/imx.c2
-rw-r--r--drivers/serial/mpc52xx_uart.c2
-rw-r--r--drivers/serial/mpsc.c711
-rw-r--r--drivers/serial/pmac_zilog.c22
-rw-r--r--drivers/serial/s3c2410.c2
-rw-r--r--drivers/serial/sb1250-duart.c20
-rw-r--r--drivers/serial/serial_core.c16
-rw-r--r--drivers/serial/serial_cs.c1
-rw-r--r--drivers/serial/serial_txx9.c19
-rw-r--r--drivers/serial/sh-sci.c9
-rw-r--r--drivers/serial/sh-sci.h66
-rw-r--r--drivers/serial/suncore.c123
-rw-r--r--drivers/serial/suncore.h2
-rw-r--r--drivers/serial/sunhv.c13
-rw-r--r--drivers/serial/sunsab.c131
-rw-r--r--drivers/serial/sunsu.c28
-rw-r--r--drivers/serial/sunzilog.c38
-rw-r--r--drivers/serial/uartlite.c286
-rw-r--r--drivers/serial/vr41xx_siu.c7
-rw-r--r--drivers/serial/zs.c1287
-rw-r--r--drivers/serial/zs.h284
-rw-r--r--drivers/sh/superhyway/superhyway.c3
-rw-r--r--drivers/sn/ioc3.c3
-rw-r--r--drivers/spi/atmel_spi.c2
-rw-r--r--drivers/spi/spi.c55
-rw-r--r--drivers/spi/spi_bfin5xx.c3
-rw-r--r--drivers/spi/spi_imx.c2
-rw-r--r--drivers/spi/spi_mpc83xx.c63
-rw-r--r--drivers/spi/spi_s3c24xx.c3
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c2
-rw-r--r--drivers/spi/spi_txx9.c2
-rw-r--r--drivers/spi/spidev.c17
-rw-r--r--drivers/spi/xilinx_spi.c2
-rw-r--r--drivers/ssb/Kconfig117
-rw-r--r--drivers/ssb/Makefile18
-rw-r--r--drivers/ssb/b43_pci_bridge.c48
-rw-r--r--drivers/ssb/driver_chipcommon.c445
-rw-r--r--drivers/ssb/driver_extif.c129
-rw-r--r--drivers/ssb/driver_mipscore.c223
-rw-r--r--drivers/ssb/driver_pcicore.c576
-rw-r--r--drivers/ssb/main.c1162
-rw-r--r--drivers/ssb/pci.c740
-rw-r--r--drivers/ssb/pcihost_wrapper.c104
-rw-r--r--drivers/ssb/pcmcia.c271
-rw-r--r--drivers/ssb/scan.c413
-rw-r--r--drivers/ssb/ssb_private.h136
-rw-r--r--drivers/tc/Makefile1
-rw-r--r--drivers/tc/zs.c2203
-rw-r--r--drivers/tc/zs.h404
-rw-r--r--drivers/telephony/ixj_pcmcia.c3
-rw-r--r--drivers/uio/Kconfig29
-rw-r--r--drivers/uio/Makefile2
-rw-r--r--drivers/uio/uio.c701
-rw-r--r--drivers/uio/uio_cif.c156
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile21
-rw-r--r--drivers/usb/atm/cxacru.c47
-rw-r--r--drivers/usb/atm/speedtch.c10
-rw-r--r--drivers/usb/atm/ueagle-atm.c1395
-rw-r--r--drivers/usb/atm/usbatm.c11
-rw-r--r--drivers/usb/class/cdc-acm.c30
-rw-r--r--drivers/usb/class/usblp.c143
-rw-r--r--drivers/usb/core/config.c24
-rw-r--r--drivers/usb/core/devio.c83
-rw-r--r--drivers/usb/core/driver.c137
-rw-r--r--drivers/usb/core/endpoint.c1
-rw-r--r--drivers/usb/core/generic.c26
-rw-r--r--drivers/usb/core/hcd.c805
-rw-r--r--drivers/usb/core/hcd.h46
-rw-r--r--drivers/usb/core/hub.c285
-rw-r--r--drivers/usb/core/message.c157
-rw-r--r--drivers/usb/core/quirks.c44
-rw-r--r--drivers/usb/core/sysfs.c103
-rw-r--r--drivers/usb/core/urb.c194
-rw-r--r--drivers/usb/core/usb.c41
-rw-r--r--drivers/usb/core/usb.h5
-rw-r--r--drivers/usb/gadget/Kconfig83
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/amd5536udc.c3451
-rw-r--r--drivers/usb/gadget/amd5536udc.h626
-rw-r--r--drivers/usb/gadget/at91_udc.c2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2077
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h352
-rw-r--r--drivers/usb/gadget/config.c4
-rw-r--r--drivers/usb/gadget/dummy_hcd.c95
-rw-r--r--drivers/usb/gadget/epautoconf.c4
-rw-r--r--drivers/usb/gadget/ether.c163
-rw-r--r--drivers/usb/gadget/file_storage.c259
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c90
-rw-r--r--drivers/usb/gadget/gadget_chips.h10
-rw-r--r--drivers/usb/gadget/gmidi.c82
-rw-r--r--drivers/usb/gadget/goku_udc.c5
-rw-r--r--drivers/usb/gadget/inode.c48
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h2
-rw-r--r--drivers/usb/gadget/m66592-udc.c259
-rw-r--r--drivers/usb/gadget/m66592-udc.h610
-rw-r--r--drivers/usb/gadget/net2280.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c12
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c36
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2
-rw-r--r--drivers/usb/gadget/serial.c225
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c237
-rw-r--r--drivers/usb/host/Kconfig15
-rw-r--r--drivers/usb/host/ehci-au1xxx.c11
-rw-r--r--drivers/usb/host/ehci-hcd.c89
-rw-r--r--drivers/usb/host/ehci-mem.c3
-rw-r--r--drivers/usb/host/ehci-pci.c5
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c28
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c103
-rw-r--r--drivers/usb/host/ehci-sched.c174
-rw-r--r--drivers/usb/host/ehci.h14
-rw-r--r--drivers/usb/host/isp116x-hcd.c214
-rw-r--r--drivers/usb/host/ohci-dbg.c10
-rw-r--r--drivers/usb/host/ohci-hcd.c237
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-pci.c22
-rw-r--r--drivers/usb/host/ohci-ppc-of.c5
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c5
-rw-r--r--drivers/usb/host/ohci-q.c187
-rw-r--r--drivers/usb/host/ohci-ssb.c247
-rw-r--r--drivers/usb/host/ohci.h39
-rw-r--r--drivers/usb/host/r8a66597-hcd.c284
-rw-r--r--drivers/usb/host/r8a66597.h87
-rw-r--r--drivers/usb/host/sl811-hcd.c74
-rw-r--r--drivers/usb/host/sl811_cs.c3
-rw-r--r--drivers/usb/host/u132-hcd.c390
-rw-r--r--drivers/usb/host/uhci-debug.c4
-rw-r--r--drivers/usb/host/uhci-hcd.c4
-rw-r--r--drivers/usb/host/uhci-hcd.h16
-rw-r--r--drivers/usb/host/uhci-q.c115
-rw-r--r--drivers/usb/image/mdc800.c45
-rw-r--r--drivers/usb/image/microtek.c19
-rw-r--r--drivers/usb/misc/adutux.c60
-rw-r--r--drivers/usb/misc/appledisplay.c13
-rw-r--r--drivers/usb/misc/auerswald.c25
-rw-r--r--drivers/usb/misc/berry_charge.c7
-rw-r--r--drivers/usb/misc/ftdi-elan.c29
-rw-r--r--drivers/usb/misc/iowarrior.c21
-rw-r--r--drivers/usb/misc/ldusb.c20
-rw-r--r--drivers/usb/misc/legousbtower.c28
-rw-r--r--drivers/usb/misc/phidgetkit.c13
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c13
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c201
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h130
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c60
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c354
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.h1315
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_struct.h144
-rw-r--r--drivers/usb/misc/usblcd.c11
-rw-r--r--drivers/usb/misc/usbtest.c4
-rw-r--r--drivers/usb/misc/uss720.c5
-rw-r--r--drivers/usb/mon/mon_bin.c42
-rw-r--r--drivers/usb/mon/mon_main.c25
-rw-r--r--drivers/usb/mon/mon_text.c74
-rw-r--r--drivers/usb/mon/usb_mon.h2
-rw-r--r--drivers/usb/serial/Kconfig10
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/airprime.c1
-rw-r--r--drivers/usb/serial/ark3116.c5
-rw-r--r--drivers/usb/serial/belkin_sa.c4
-rw-r--r--drivers/usb/serial/bus.c18
-rw-r--r--drivers/usb/serial/ch341.c354
-rw-r--r--drivers/usb/serial/cp2101.c72
-rw-r--r--drivers/usb/serial/digi_acceleport.c970
-rw-r--r--drivers/usb/serial/ftdi_sio.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.h11
-rw-r--r--drivers/usb/serial/funsoft.c21
-rw-r--r--drivers/usb/serial/garmin_gps.c93
-rw-r--r--drivers/usb/serial/io_edgeport.c19
-rw-r--r--drivers/usb/serial/io_ti.c10
-rw-r--r--drivers/usb/serial/ipaq.c4
-rw-r--r--drivers/usb/serial/kl5kusb105.c28
-rw-r--r--drivers/usb/serial/kobil_sct.c144
-rw-r--r--drivers/usb/serial/mct_u232.c46
-rw-r--r--drivers/usb/serial/mct_u232.h2
-rw-r--r--drivers/usb/serial/mos7720.c5
-rw-r--r--drivers/usb/serial/mos7840.c19
-rw-r--r--drivers/usb/serial/option.c13
-rw-r--r--drivers/usb/serial/oti6858.c19
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h1
-rw-r--r--drivers/usb/serial/safe_serial.c17
-rw-r--r--drivers/usb/serial/sierra.c120
-rw-r--r--drivers/usb/serial/usb-serial.c74
-rw-r--r--drivers/usb/serial/visor.c66
-rw-r--r--drivers/usb/serial/visor.h3
-rw-r--r--drivers/usb/storage/dpcm.c56
-rw-r--r--drivers/usb/storage/initializers.c14
-rw-r--r--drivers/usb/storage/initializers.h3
-rw-r--r--drivers/usb/storage/onetouch.c13
-rw-r--r--drivers/usb/storage/scsiglue.c13
-rw-r--r--drivers/usb/storage/shuttle_usbat.c3
-rw-r--r--drivers/usb/storage/unusual_devs.h105
-rw-r--r--drivers/usb/storage/usb.c64
-rw-r--r--drivers/usb/storage/usb.h1
-rw-r--r--drivers/usb/usb-skeleton.c1
-rw-r--r--drivers/video/Kconfig41
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/acornfb.c20
-rw-r--r--drivers/video/amba-clcd.c3
-rw-r--r--drivers/video/atmel_lcdfb.c67
-rw-r--r--drivers/video/aty/ati_ids.h12
-rw-r--r--drivers/video/aty/aty128fb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c9
-rw-r--r--drivers/video/aty/radeon_backlight.c4
-rw-r--r--drivers/video/aty/radeon_base.c6
-rw-r--r--drivers/video/au1100fb.c92
-rw-r--r--drivers/video/au1200fb.c3
-rw-r--r--drivers/video/backlight/Kconfig49
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/backlight.c125
-rw-r--r--drivers/video/backlight/corgi_bl.c22
-rw-r--r--drivers/video/backlight/cr_bllcd.c35
-rw-r--r--drivers/video/backlight/lcd.c112
-rw-r--r--drivers/video/backlight/ltv350qv.c330
-rw-r--r--drivers/video/backlight/ltv350qv.h95
-rw-r--r--drivers/video/bw2.c131
-rw-r--r--drivers/video/cg14.c150
-rw-r--r--drivers/video/cg3.c157
-rw-r--r--drivers/video/cg6.c166
-rw-r--r--drivers/video/chipsfb.c3
-rw-r--r--drivers/video/clps711xfb.c3
-rw-r--r--drivers/video/console/Kconfig4
-rw-r--r--drivers/video/console/fbcon.c14
-rw-r--r--drivers/video/console/fonts.c4
-rw-r--r--drivers/video/console/newport_con.c3
-rw-r--r--drivers/video/console/sticore.c14
-rw-r--r--drivers/video/console/vgacon.c6
-rw-r--r--drivers/video/cyber2000fb.c3
-rw-r--r--drivers/video/fbmem.c42
-rw-r--r--drivers/video/ffb.c170
-rw-r--r--drivers/video/geode/Kconfig15
-rw-r--r--drivers/video/geode/Makefile2
-rw-r--r--drivers/video/geode/lxfb.h199
-rw-r--r--drivers/video/geode/lxfb_core.c621
-rw-r--r--drivers/video/geode/lxfb_ops.c536
-rw-r--r--drivers/video/igafb.c4
-rw-r--r--drivers/video/imacfb.c2
-rw-r--r--drivers/video/imsttfb.c2
-rw-r--r--drivers/video/intelfb/intelfbhw.c8
-rw-r--r--drivers/video/leo.c147
-rw-r--r--drivers/video/logo/Kconfig2
-rw-r--r--drivers/video/logo/logo.c7
-rw-r--r--drivers/video/matrox/g450_pll.c23
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h15
-rw-r--r--drivers/video/matrox/matroxfb_base.h1
-rw-r--r--drivers/video/matrox/matroxfb_misc.c1
-rw-r--r--drivers/video/nvidia/nv_backlight.c2
-rw-r--r--drivers/video/output.c29
-rw-r--r--drivers/video/p9100.c138
-rw-r--r--drivers/video/platinumfb.c48
-rw-r--r--drivers/video/ps3fb.c2
-rw-r--r--drivers/video/pvr2fb.c17
-rw-r--r--drivers/video/pxafb.c2
-rw-r--r--drivers/video/riva/fbdev.c4
-rw-r--r--drivers/video/s3c2410fb.c88
-rw-r--r--drivers/video/s3c2410fb.h3
-rw-r--r--drivers/video/savage/savagefb_driver.c3
-rw-r--r--drivers/video/sbuslib.c25
-rw-r--r--drivers/video/stifb.c19
-rw-r--r--drivers/video/tcx.c184
-rw-r--r--drivers/video/tgafb.c2
-rw-r--r--drivers/video/tx3912fb.c326
-rw-r--r--drivers/video/valkyriefb.c3
-rw-r--r--drivers/video/xilinxfb.c366
-rw-r--r--drivers/w1/masters/ds1wm.c2
-rw-r--r--drivers/w1/masters/matrox_w1.c3
-rw-r--r--drivers/w1/slaves/w1_ds2433.c3
-rw-r--r--drivers/w1/w1.c21
-rw-r--r--drivers/w1/w1_int.c13
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/grant-table.c582
-rw-r--r--drivers/xen/xenbus/Makefile7
-rw-r--r--drivers/xen/xenbus/xenbus_client.c569
-rw-r--r--drivers/xen/xenbus/xenbus_comms.c233
-rw-r--r--drivers/xen/xenbus/xenbus_comms.h46
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c935
-rw-r--r--drivers/xen/xenbus/xenbus_probe.h74
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c861
-rw-r--r--drivers/zorro/zorro-sysfs.c2
2432 files changed, 364161 insertions, 95583 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 7916f4b86d23..7bdae47d6b91 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -8,6 +8,8 @@ source "drivers/connector/Kconfig"
source "drivers/mtd/Kconfig"
+source "drivers/of/Kconfig"
+
source "drivers/parport/Kconfig"
source "drivers/pnp/Kconfig"
@@ -56,6 +58,8 @@ source "drivers/power/Kconfig"
source "drivers/hwmon/Kconfig"
+source "drivers/ssb/Kconfig"
+
source "drivers/mfd/Kconfig"
source "drivers/media/Kconfig"
@@ -84,4 +88,7 @@ source "drivers/auxdisplay/Kconfig"
source "drivers/kvm/Kconfig"
+source "drivers/uio/Kconfig"
+
+source "drivers/lguest/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 503d82569449..a168eacdcd9c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,6 +15,8 @@ obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_PNP) += pnp/
obj-$(CONFIG_ARM_AMBA) += amba/
+obj-$(CONFIG_XEN) += xen/
+
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
obj-y += char/
@@ -38,6 +40,7 @@ obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_FUSION) += message/
obj-$(CONFIG_FIREWIRE) += firewire/
obj-$(CONFIG_IEEE1394) += ieee1394/
+obj-$(CONFIG_UIO) += uio/
obj-y += cdrom/
obj-y += auxdisplay/
obj-$(CONFIG_MTD) += mtd/
@@ -63,6 +66,7 @@ obj-y += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
+obj-$(CONFIG_WATCHDOG) += char/watchdog/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
@@ -70,6 +74,7 @@ obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_MCA) += mca/
obj-$(CONFIG_EISA) += eisa/
+obj-$(CONFIG_LGUEST_GUEST) += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_NEW_LEDS) += leds/
@@ -82,3 +87,5 @@ obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
+obj-$(CONFIG_OF) += of/
+obj-$(CONFIG_SSB) += ssb/
diff --git a/drivers/acorn/README b/drivers/acorn/README
deleted file mode 100644
index d399c09ca61c..000000000000
--- a/drivers/acorn/README
+++ /dev/null
@@ -1 +0,0 @@
-Drivers for the ACORN "podule" ARM specific bus.
diff --git a/drivers/acorn/block/Kconfig b/drivers/acorn/block/Kconfig
deleted file mode 100644
index a0ff25ea439f..000000000000
--- a/drivers/acorn/block/Kconfig
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Block device driver configuration
-#
-
-menu "Acorn-specific block devices"
- depends on ARCH_ARC || ARCH_A5K
-
-config BLK_DEV_FD1772
- tristate "Old Archimedes floppy (1772) support"
- depends on ARCH_ARC || ARCH_A5K
- help
- Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
- R140 and R260) series of computers; it supports only 720K floppies
- at the moment. If you don't have one of these machines just answer
- N.
-
-config BLK_DEV_MFM
- tristate "MFM harddisk support"
- depends on ARCH_ARC || ARCH_A5K
- help
- Support the MFM hard drives on the Acorn Archimedes both
- on-board the A4x0 motherboards and via the Acorn MFM podules.
- Drives up to 64MB are supported. If you haven't got one of these
- machines or drives just say N.
-
-config BLK_DEV_MFM_AUTODETECT
- bool "Autodetect hard drive geometry"
- depends on BLK_DEV_MFM
- help
- If you answer Y, the MFM code will attempt to automatically detect
- the cylinders/heads/sectors count on your hard drive. WARNING: This
- sometimes doesn't work and it also does some dodgy stuff which
- potentially might damage your drive.
-
-endmenu
-
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
deleted file mode 100644
index 38a9afe8e03f..000000000000
--- a/drivers/acorn/block/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for the Acorn block device drivers.
-#
-
-fd1772_mod-objs := fd1772.o fd1772dma.o
-mfmhd_mod-objs := mfmhd.o mfm.o
-
-obj-$(CONFIG_BLK_DEV_FD1772) += fd1772_mod.o
-obj-$(CONFIG_BLK_DEV_MFM) += mfmhd_mod.o
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
deleted file mode 100644
index 423ed08fb6f7..000000000000
--- a/drivers/acorn/block/fd1772.c
+++ /dev/null
@@ -1,1604 +0,0 @@
-/*
- * linux/kernel/arch/arm/drivers/block/fd1772.c
- * Based on ataflop.c in the m68k Linux
- * Copyright (C) 1993 Greg Harp
- * Atari Support by Bjoern Brauel, Roman Hodek
- * Archimedes Support by Dave Gilbert (linux@treblig.org)
- *
- * Big cleanup Sep 11..14 1994 Roman Hodek:
- * - Driver now works interrupt driven
- * - Support for two drives; should work, but I cannot test that :-(
- * - Reading is done in whole tracks and buffered to speed up things
- * - Disk change detection and drive deselecting after motor-off
- * similar to TOS
- * - Autodetection of disk format (DD/HD); untested yet, because I
- * don't have an HD drive :-(
- *
- * Fixes Nov 13 1994 Martin Schaller:
- * - Autodetection works now
- * - Support for 5 1/4" disks
- * - Removed drive type (unknown on atari)
- * - Do seeks with 8 Mhz
- *
- * Changes by Andreas Schwab:
- * - After errors in multiple read mode try again reading single sectors
- * (Feb 1995):
- * - Clean up error handling
- * - Set blk_size for proper size checking
- * - Initialize track register when testing presence of floppy
- * - Implement some ioctl's
- *
- * Changes by Torsten Lang:
- * - When probing the floppies we should add the FDC1772CMDADD_H flag since
- * the FDC1772 will otherwise wait forever when no disk is inserted...
- *
- * Things left to do:
- * - Formatting
- * - Maybe a better strategy for disk change detection (does anyone
- * know one?)
- * - There are some strange problems left: The strangest one is
- * that, at least on my TT (4+4MB), the first 2 Bytes of the last
- * page of the TT-Ram (!) change their contents (some bits get
- * set) while a floppy DMA is going on. But there are no accesses
- * to these memory locations from the kernel... (I tested that by
- * making the page read-only). I cannot explain what's going on...
- * - Sometimes the drive-change-detection stops to work. The
- * function is still called, but the WP bit always reads as 0...
- * Maybe a problem with the status reg mode or a timing problem.
- * Note 10/12/94: The change detection now seems to work reliably.
- * There is no proof, but I've seen no hang for a long time...
- *
- * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk)
- * 26/12/95 - Changed all names starting with FDC to FDC1772
- * Removed all references to clock speed of FDC - we're stuck with 8MHz
- * Modified disk_type structure to remove HD formats
- *
- * 7/ 1/96 - Wrote FIQ code, removed most remaining atariisms
- *
- * 13/ 1/96 - Well I think its read a single sector; but there is a problem
- * fd_rwsec_done which is called in FIQ mode starts another transfer
- * off (in fd_rwsec) while still in FIQ mode. Because its still in
- * FIQ mode it can't service the DMA and loses data. So need to
- * heavily restructure.
- * 14/ 1/96 - Found that the definitions of the register numbers of the
- * FDC were multiplied by 2 in the header for the 16bit words
- * of the atari so half the writes were going in the wrong place.
- * Also realised that the FIQ entry didn't make any attempt to
- * preserve registers or return correctly; now in assembler.
- *
- * 11/ 2/96 - Hmm - doesn't work on real machine. Auto detect doesn't
- * and hacking that past seems to wait forever - check motor
- * being turned on.
- *
- * 17/ 2/96 - still having problems - forcing track to -1 when selecting
- * new drives seems to allow it to read first few sectors
- * but then we get solid hangs at apparently random places
- * which change depending what is happening.
- *
- * 9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35
- * A lot of fiddling in DMA stuff. Having problems with it
- * constnatly thinking its timeing out. Ah - its timeout
- * was set to (6*HZ) rather than jiffies+(6*HZ). Now giving
- * duff data!
- *
- * 5/ 4/96 - Made it use the new IOC_ macros rather than *ioc
- * Hmm - giving unexpected FIQ and then timeouts
- * 18/ 8/96 - Ran through indent -kr -i8
- * Some changes to disc change detect; don't know how well it
- * works.
- * 24/ 8/96 - Put all the track buffering code back in from the atari
- * code - I wonder if it will still work... No :-)
- * Still works if I turn off track buffering.
- * 25/ 8/96 - Changed the timer expires that I'd added back to be
- * jiffies + ....; and it all sprang to life! Got 2.8K/sec
- * off a cp -r of a 679K disc (showed 94% cpu usage!)
- * (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt!
- * Also perhaps that compile was with cache off.
- * changed cli in fd_readtrack_check to cliIF
- * changed vmallocs to kmalloc (whats the difference!!)
- * Removed the busy wait loop in do_fd_request and replaced
- * by a routine on tq_immediate; only 11% cpu on a dd off the
- * raw disc - but the speed is the same.
- * 1/ 9/96 - Idea (failed!) - set the 'disable spin-up sequence'
- * when we read the track if we know the motor is on; didn't
- * help - perhaps we have to do it in stepping as well.
- * Nope. Still doesn't help.
- * Hmm - what seems to be happening is that fd_readtrack_check
- * is never getting called. Its job is to terminate the read
- * just after we think we should have got the data; otherwise
- * the fdc takes 1 second to timeout; which is what's happening
- * Now I can see 'readtrack_timer' being set (which should do the
- * call); but it never seems to be called - hmm!
- * OK - I've moved the check to my tq_immediate code -
- * and it WORKS! 13.95K/second at 19% CPU.
- * I wish I knew why that timer didn't work.....
- *
- * 16/11/96 - Fiddled and frigged for 2.0.18
- *
- * DAG 30/01/99 - Started frobbing for 2.2.1
- * DAG 20/06/99 - A little more frobbing:
- * Included include/asm/uaccess.h for get_user/put_user
- *
- * DAG 1/09/00 - Dusted off for 2.4.0-test7
- * MAX_SECTORS was name clashing so it is now FD1772_...
- * Minor parameter, name layouts for 2.4.x differences
- */
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/fcntl.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/fd.h>
-#include <linux/fd1772.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-#include <linux/bitops.h>
-
-#include <asm/arch/oldlatches.h>
-#include <asm/dma.h>
-#include <asm/hardware.h>
-#include <asm/hardware/ioc.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-
-/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
- * little additional rework in this file). But I'm not yet sure if
- * some other code depends on the number of floppies... (It is defined
- * in a public header!)
- */
-#if 0
-#undef FD_MAX_UNITS
-#define FD_MAX_UNITS 2
-#endif
-
-/* Ditto worries for Arc - DAG */
-#define FD_MAX_UNITS 4
-#define TRACKBUFFER 0
-/*#define DEBUG*/
-
-#ifdef DEBUG
-#define DPRINT(a) printk a
-#else
-#define DPRINT(a)
-#endif
-
-static struct request_queue *floppy_queue;
-
-#define MAJOR_NR FLOPPY_MAJOR
-#define FLOPPY_DMA 0
-#define DEVICE_NAME "floppy"
-#define QUEUE (floppy_queue)
-#define CURRENT elv_next_request(floppy_queue)
-
-/* Disk types: DD */
-static struct archy_disk_type {
- const char *name;
- unsigned spt; /* sectors per track */
- unsigned blocks; /* total number of blocks */
- unsigned stretch; /* track doubling ? */
-} disk_type[] = {
-
- { "d360", 9, 720, 0 }, /* 360kB diskette */
- { "D360", 9, 720, 1 }, /* 360kb in 720kb drive */
- { "D720", 9, 1440, 0 }, /* 720kb diskette (DD) */
- /*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors
- - DAG - can't see how type detect can distinguish this
- from 720K until it reads block 4 by which time its too late! */
-};
-
-#define NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type))
-
-/*
- * Maximum disk size (in kilobytes). This default is used whenever the
- * current disk size is unknown.
- */
-#define MAX_DISK_SIZE 720
-
-static struct gendisk *disks[FD_MAX_UNIT];
-
-/* current info on each unit */
-static struct archy_floppy_struct {
- int connected; /* !=0 : drive is connected */
- int autoprobe; /* !=0 : do autoprobe */
-
- struct archy_disk_type *disktype; /* current type of disk */
-
- int track; /* current head position or -1
- * if unknown */
- unsigned int steprate; /* steprate setting */
- unsigned int wpstat; /* current state of WP signal
- * (for disk change detection) */
-} unit[FD_MAX_UNITS];
-
-/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which
- is an assembler routine */
-extern void fdc1772_comendhandler(void); /* Actually doens't have these parameters - see fd1772.S */
-extern volatile int fdc1772_comendstatus;
-extern volatile int fdc1772_fdc_int_done;
-
-#define FDC1772BASE ((0x210000>>2)|0x80000000)
-
-#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2))
-
-/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather
- than the #def below - well simple - the #def won't compile - and I
- don't understand why (__outwc not defined) */
-/* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility
- with the ST version of fd1772.h */
-/*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */
-void FDC1772_WRITE(int reg, unsigned char val)
-{
- if (reg == FDC1772REG_CMD) {
- DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies));
- if (fdc1772_fdc_int_done) {
- DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n"));
- fdc1772_fdc_int_done = 0;
- };
- };
- outb(val, (reg / 2) + FDC1772BASE);
-};
-
-#define FD1772_MAX_SECTORS 22
-
-unsigned char *DMABuffer; /* buffer for writes */
-/*static unsigned long PhysDMABuffer; *//* physical address */
-/* DAG: On Arc we just go straight for the DMA buffer */
-#define PhysDMABuffer DMABuffer
-
-#ifdef TRACKBUFFER
-unsigned char *TrackBuffer; /* buffer for reads */
-#define PhysTrackBuffer TrackBuffer /* physical address */
-static int BufferDrive, BufferSide, BufferTrack;
-static int read_track; /* non-zero if we are reading whole tracks */
-
-#define SECTOR_BUFFER(sec) (TrackBuffer + ((sec)-1)*512)
-#define IS_BUFFERED(drive,side,track) \
- (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
-#endif
-
-/*
- * These are global variables, as that's the easiest way to give
- * information to interrupts. They are the data used for the current
- * request.
- */
-static int SelectedDrive = 0;
-static int ReqCmd, ReqBlock;
-static int ReqSide, ReqTrack, ReqSector, ReqCnt;
-static int HeadSettleFlag = 0;
-static unsigned char *ReqData, *ReqBuffer;
-static int MotorOn = 0, MotorOffTrys;
-
-/* Synchronization of FDC1772 access. */
-static volatile int fdc_busy = 0;
-static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
-
-
-/* long req'd for set_bit --RR */
-static unsigned long changed_floppies = 0xff, fake_change = 0;
-#define CHECK_CHANGE_DELAY HZ/2
-
-/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */
-#define FD_MOTOR_OFF_DELAY (10*HZ)
-#define FD_MOTOR_OFF_MAXTRY (10*20)
-
-#define FLOPPY_TIMEOUT (6*HZ)
-#define RECALIBRATE_ERRORS 4 /* After this many errors the drive
- * will be recalibrated. */
-#define MAX_ERRORS 8 /* After this many errors the driver
- * will give up. */
-
-#define START_MOTOR_OFF_TIMER(delay) \
- do { \
- motor_off_timer.expires = jiffies + (delay); \
- add_timer( &motor_off_timer ); \
- MotorOffTrys = 0; \
- } while(0)
-
-#define START_CHECK_CHANGE_TIMER(delay) \
- do { \
- mod_timer(&fd_timer, jiffies + (delay)); \
- } while(0)
-
-#define START_TIMEOUT() \
- do { \
- mod_timer(&timeout_timer, jiffies+FLOPPY_TIMEOUT); \
- } while(0)
-
-#define STOP_TIMEOUT() \
- do { \
- del_timer( &timeout_timer ); \
- } while(0)
-
-#define ENABLE_IRQ() enable_irq(FIQ_FD1772+64);
-
-#define DISABLE_IRQ() disable_irq(FIQ_FD1772+64);
-
-static void fd1772_checkint(void);
-
-DECLARE_WORK(fd1772_tq, (void *)fd1772_checkint, NULL);
-/*
- * The driver is trying to determine the correct media format
- * while Probing is set. fd_rwsec_done() clears it after a
- * successful access.
- */
-static int Probing = 0;
-
-/* This flag is set when a dummy seek is necessary to make the WP
- * status bit accessible.
- */
-static int NeedSeek = 0;
-
-
-/***************************** Prototypes *****************************/
-
-static void fd_select_side(int side);
-static void fd_select_drive(int drive);
-static void fd_deselect(void);
-static void fd_motor_off_timer(unsigned long dummy);
-static void check_change(unsigned long dummy);
-static void floppy_irqconsequencehandler(void);
-static void fd_error(void);
-static void do_fd_action(int drive);
-static void fd_calibrate(void);
-static void fd_calibrate_done(int status);
-static void fd_seek(void);
-static void fd_seek_done(int status);
-static void fd_rwsec(void);
-#ifdef TRACKBUFFER
-static void fd_readtrack_check( unsigned long dummy );
-#endif
-static void fd_rwsec_done(int status);
-static void fd_times_out(unsigned long dummy);
-static void finish_fdc(void);
-static void finish_fdc_done(int dummy);
-static void floppy_off(unsigned int nr);
-static void setup_req_params(int drive);
-static void redo_fd_request(void);
-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
- cmd, unsigned long param);
-static void fd_probe(int drive);
-static int fd_test_drive_present(int drive);
-static void config_types(void);
-static int floppy_open(struct inode *inode, struct file *filp);
-static int floppy_release(struct inode *inode, struct file *filp);
-static void do_fd_request(request_queue_t *);
-
-/************************* End of Prototypes **************************/
-
-static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0);
-
-#ifdef TRACKBUFFER
-static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0);
-#endif
-
-static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0);
-
-static DEFINE_TIMER(fd_timer, check_change, 0, 0);
-
-/* DAG: Haven't got a clue what this is? */
-int stdma_islocked(void)
-{
- return 0;
-};
-
-/* Select the side to use. */
-
-static void fd_select_side(int side)
-{
- oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL);
-}
-
-
-/* Select a drive, update the FDC1772's track register
- */
-
-static void fd_select_drive(int drive)
-{
-#ifdef DEBUG
- printk("fd_select_drive:%d\n", drive);
-#endif
- /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */
- oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0);
-
- if (drive == SelectedDrive)
- return;
-
- oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));
-
- /* restore track register to saved value */
- FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track);
- udelay(25);
-
- SelectedDrive = drive;
-}
-
-
-/* Deselect both drives. */
-
-static void fd_deselect(void)
-{
- unsigned long flags;
-
- DPRINT(("fd_deselect\n"));
-
- oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);
-
- SelectedDrive = -1;
-}
-
-
-/* This timer function deselects the drives when the FDC1772 switched the
- * motor off. The deselection cannot happen earlier because the FDC1772
- * counts the index signals, which arrive only if one drive is selected.
- */
-
-static void fd_motor_off_timer(unsigned long dummy)
-{
- unsigned long flags;
- unsigned char status;
- int delay;
-
- del_timer(&motor_off_timer);
-
- if (SelectedDrive < 0)
- /* no drive selected, needn't deselect anyone */
- return;
-
- save_flags(flags);
- cli();
-
- if (fdc_busy) /* was stdma_islocked */
- goto retry;
-
- status = FDC1772_READ(FDC1772REG_STATUS);
-
- if (!(status & 0x80)) {
- /*
- * motor already turned off by FDC1772 -> deselect drives
- * In actual fact its this deselection which turns the motor
- * off on the Arc, since the motor control is actually on
- * Latch A
- */
- DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n"));
- fd_deselect();
- MotorOn = 0;
- restore_flags(flags);
- return;
- }
- /* not yet off, try again */
-
-retry:
- restore_flags(flags);
- /* Test again later; if tested too often, it seems there is no disk
- * in the drive and the FDC1772 will leave the motor on forever (or,
- * at least until a disk is inserted). So we'll test only twice
- * per second from then on...
- */
- delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
- (++MotorOffTrys, HZ / 20) : HZ / 2;
- START_MOTOR_OFF_TIMER(delay);
-}
-
-
-/* This function is repeatedly called to detect disk changes (as good
- * as possible) and keep track of the current state of the write protection.
- */
-
-static void check_change(unsigned long dummy)
-{
- static int drive = 0;
-
- unsigned long flags;
- int stat;
-
- if (fdc_busy)
- return; /* Don't start poking about if the fdc is busy */
-
- return; /* let's just forget it for the mo DAG */
-
- if (++drive > 1 || !unit[drive].connected)
- drive = 0;
-
- save_flags(flags);
- cli();
-
- if (!stdma_islocked()) {
- stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT);
-
- /* The idea here is that if the write protect line has changed then
- the disc must have changed */
- if (stat != unit[drive].wpstat) {
- DPRINT(("wpstat[%d] = %d\n", drive, stat));
- unit[drive].wpstat = stat;
- set_bit(drive, &changed_floppies);
- }
- }
- restore_flags(flags);
-
- START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY);
-}
-
-
-/* Handling of the Head Settling Flag: This flag should be set after each
- * seek operation, because we don't use seeks with verify.
- */
-
-static inline void set_head_settle_flag(void)
-{
- HeadSettleFlag = FDC1772CMDADD_E;
-}
-
-static inline int get_head_settle_flag(void)
-{
- int tmp = HeadSettleFlag;
- HeadSettleFlag = 0;
- return (tmp);
-}
-
-
-
-
-/* General Interrupt Handling */
-
-static inline void copy_buffer(void *from, void *to)
-{
- ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
- int cnt;
-
- for (cnt = 512 / 4; cnt; cnt--)
- *p2++ = *p1++;
-}
-
-static void (*FloppyIRQHandler) (int status) = NULL;
-
-static void floppy_irqconsequencehandler(void)
-{
- unsigned char status;
- void (*handler) (int);
-
- fdc1772_fdc_int_done = 0;
-
- handler = FloppyIRQHandler;
- FloppyIRQHandler = NULL;
-
- if (handler) {
- nop();
- status = (unsigned char) fdc1772_comendstatus;
- DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler));
- handler(status);
- } else {
- DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus));
- }
- DPRINT(("FDC1772 irq: end of floppy_irq\n"));
-}
-
-
-/* Error handling: If some error happened, retry some times, then
- * recalibrate, then try again, and fail after MAX_ERRORS.
- */
-
-static void fd_error(void)
-{
- printk("FDC1772: fd_error\n");
- /*panic("fd1772: fd_error"); *//* DAG tmp */
- if (!CURRENT)
- return;
- CURRENT->errors++;
- if (CURRENT->errors >= MAX_ERRORS) {
- printk("fd%d: too many errors.\n", SelectedDrive);
- end_request(CURRENT, 0);
- } else if (CURRENT->errors == RECALIBRATE_ERRORS) {
- printk("fd%d: recalibrating\n", SelectedDrive);
- if (SelectedDrive != -1)
- unit[SelectedDrive].track = -1;
- }
- redo_fd_request();
-}
-
-
-
-#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
-
-
-/* do_fd_action() is the general procedure for a fd request: All
- * required parameter settings (drive select, side select, track
- * position) are checked and set if needed. For each of these
- * parameters and the actual reading or writing exist two functions:
- * one that starts the setting (or skips it if possible) and one
- * callback for the "done" interrupt. Each done func calls the next
- * set function to propagate the request down to fd_rwsec_done().
- */
-
-static void do_fd_action(int drive)
-{
- struct request *req;
- DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));
-
-#ifdef TRACKBUFFER
-repeat:
-
- if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
- req = CURRENT;
- if (ReqCmd == READ) {
- copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
- if (++ReqCnt < req->current_nr_sectors) {
- /* read next sector */
- setup_req_params( drive );
- goto repeat;
- } else {
- /* all sectors finished */
- req->nr_sectors -= req->current_nr_sectors;
- req->sector += req->current_nr_sectors;
- end_request(req, 1);
- redo_fd_request();
- return;
- }
- } else {
- /* cmd == WRITE, pay attention to track buffer
- * consistency! */
- copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
- }
- }
-#endif
-
- if (SelectedDrive != drive) {
- /*unit[drive].track = -1; DAG */
- fd_select_drive(drive);
- };
-
-
- if (unit[drive].track == -1)
- fd_calibrate();
- else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
- fd_seek();
- else
- fd_rwsec();
-}
-
-
-/* Seek to track 0 if the current track is unknown */
-
-static void fd_calibrate(void)
-{
- DPRINT(("fd_calibrate\n"));
- if (unit[SelectedDrive].track >= 0) {
- fd_calibrate_done(0);
- return;
- }
- DPRINT(("fd_calibrate (after track compare)\n"));
- SET_IRQ_HANDLER(fd_calibrate_done);
- /* we can't verify, since the speed may be incorrect */
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);
-
- NeedSeek = 1;
- MotorOn = 1;
- START_TIMEOUT();
- /* wait for IRQ */
-}
-
-
-static void fd_calibrate_done(int status)
-{
- DPRINT(("fd_calibrate_done()\n"));
- STOP_TIMEOUT();
-
- /* set the correct speed now */
- if (status & FDC1772STAT_RECNF) {
- printk("fd%d: restore failed\n", SelectedDrive);
- fd_error();
- } else {
- unit[SelectedDrive].track = 0;
- fd_seek();
- }
-}
-
-
-/* Seek the drive to the requested track. The drive must have been
- * calibrated at some point before this.
- */
-
-static void fd_seek(void)
-{
- unsigned long flags;
- DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,
- unit[SelectedDrive].track));
- if (unit[SelectedDrive].track == ReqTrack <<
- unit[SelectedDrive].disktype->stretch) {
- fd_seek_done(0);
- return;
- }
- FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<
- unit[SelectedDrive].disktype->stretch);
- udelay(25);
- save_flags(flags);
- clf();
- SET_IRQ_HANDLER(fd_seek_done);
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate |
- /* DAG */
- (MotorOn?FDC1772CMDADD_H:0));
-
- restore_flags(flags);
- MotorOn = 1;
- set_head_settle_flag();
- START_TIMEOUT();
- /* wait for IRQ */
-}
-
-
-static void fd_seek_done(int status)
-{
- DPRINT(("fd_seek_done()\n"));
- STOP_TIMEOUT();
-
- /* set the correct speed */
- if (status & FDC1772STAT_RECNF) {
- printk("fd%d: seek error (to track %d)\n",
- SelectedDrive, ReqTrack);
- /* we don't know exactly which track we are on now! */
- unit[SelectedDrive].track = -1;
- fd_error();
- } else {
- unit[SelectedDrive].track = ReqTrack <<
- unit[SelectedDrive].disktype->stretch;
- NeedSeek = 0;
- fd_rwsec();
- }
-}
-
-
-/* This does the actual reading/writing after positioning the head
- * over the correct track.
- */
-
-#ifdef TRACKBUFFER
-static int MultReadInProgress = 0;
-#endif
-
-
-static void fd_rwsec(void)
-{
- unsigned long paddr, flags;
- unsigned int rwflag, old_motoron;
- unsigned int track;
-
- DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r'));
- if (ReqCmd == WRITE) {
- /*cache_push( (unsigned long)ReqData, 512 ); */
- paddr = (unsigned long) ReqData;
- rwflag = 0x100;
- } else {
- paddr = (unsigned long) PhysDMABuffer;
-#ifdef TRACKBUFFER
- if (read_track)
- paddr = (unsigned long)PhysTrackBuffer;
-#endif
- rwflag = 0;
- }
-
- DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag,
- ReqSector, FDC1772_READ(FDC1772REG_TRACK)));
- fd_select_side(ReqSide);
-
- /*DPRINT(("fd_rwsec() before start sector \n")); */
- /* Start sector of this operation */
-#ifdef TRACKBUFFER
- FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 );
-#else
- FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector );
-#endif
-
- /* Cheat for track if stretch != 0 */
- if (unit[SelectedDrive].disktype->stretch) {
- track = FDC1772_READ(FDC1772REG_TRACK);
- FDC1772_WRITE(FDC1772REG_TRACK, track >>
- unit[SelectedDrive].disktype->stretch);
- }
- udelay(25);
-
- DPRINT(("fd_rwsec() before setup DMA \n"));
- /* Setup DMA - Heavily modified by DAG */
- save_flags(flags);
- clf();
- disable_dma(FLOPPY_DMA);
- set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ);
- set_dma_addr(FLOPPY_DMA, (long) paddr); /* DAG - changed from Atari specific */
-#ifdef TRACKBUFFER
- set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512);
-#else
- set_dma_count(FLOPPY_DMA, 512); /* Block/sector size - going to have to change */
-#endif
- SET_IRQ_HANDLER(fd_rwsec_done);
- /* Turn on dma int */
- enable_dma(FLOPPY_DMA);
- /* Now give it something to do */
- FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) :
-#ifdef TRACKBUFFER
- (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) |
- /* Hmm - the idea here is to stop the FDC spinning the disc
- up when we know that we already still have it spinning */
- (MotorOn?FDC1772CMDADD_H:0))
-#else
- FDC1772CMD_RDSEC
-#endif
- ));
-
- restore_flags(flags);
- DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags));
- /*sti(); *//* DAG - Hmm */
- /* Hmm - should do something DAG */
- old_motoron = MotorOn;
- MotorOn = 1;
- NeedSeek = 1;
-
- /* wait for interrupt */
-
-#ifdef TRACKBUFFER
- if (read_track) {
- /*
- * If reading a whole track, wait about one disk rotation and
- * then check if all sectors are read. The FDC will even
- * search for the first non-existant sector and need 1 sec to
- * recognise that it isn't present :-(
- */
- /* 1 rot. + 5 rot.s if motor was off */
- mod_timer(&readtrack_timer, jiffies + HZ/5 + (old_motoron ? 0 : HZ));
- DPRINT(("Setting readtrack_timer to %d @ %d\n",
- readtrack_timer.expires,jiffies));
- MultReadInProgress = 1;
- }
-#endif
-
- /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */
- START_TIMEOUT();
- /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */
-}
-
-
-#ifdef TRACKBUFFER
-
-static void fd_readtrack_check(unsigned long dummy)
-{
- unsigned long flags, addr;
- extern unsigned char *fdc1772_dataaddr;
-
- DPRINT(("fd_readtrack_check @ %d\n",jiffies));
-
- save_flags(flags);
- clf();
-
- del_timer( &readtrack_timer );
-
- if (!MultReadInProgress) {
- /* This prevents a race condition that could arise if the
- * interrupt is triggered while the calling of this timer
- * callback function takes place. The IRQ function then has
- * already cleared 'MultReadInProgress' when control flow
- * gets here.
- */
- restore_flags(flags);
- return;
- }
-
- /* get the current DMA address */
- addr=(unsigned long)fdc1772_dataaddr; /* DAG - ? */
- DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer));
-
- if (addr >= (unsigned int)PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) {
- /* already read enough data, force an FDC interrupt to stop
- * the read operation
- */
- SET_IRQ_HANDLER( NULL );
- restore_flags(flags);
- DPRINT(("fd_readtrack_check(): done\n"));
- FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI );
- udelay(25);
-
- /* No error until now -- the FDC would have interrupted
- * otherwise!
- */
- fd_rwsec_done( 0 );
- } else {
- /* not yet finished, wait another tenth rotation */
- restore_flags(flags);
- DPRINT(("fd_readtrack_check(): not yet finished\n"));
- readtrack_timer.expires = jiffies + HZ/5/10;
- add_timer( &readtrack_timer );
- }
-}
-
-#endif
-
-static void fd_rwsec_done(int status)
-{
- unsigned int track;
-
- DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies));
-
-#ifdef TRACKBUFFER
- if (read_track && !MultReadInProgress)
- return;
-
- MultReadInProgress = 0;
-
- STOP_TIMEOUT();
-
- if (read_track)
- del_timer( &readtrack_timer );
-#endif
-
-
- /* Correct the track if stretch != 0 */
- if (unit[SelectedDrive].disktype->stretch) {
- track = FDC1772_READ(FDC1772REG_TRACK);
- FDC1772_WRITE(FDC1772REG_TRACK, track <<
- unit[SelectedDrive].disktype->stretch);
- }
- if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) {
- printk("fd%d: is write protected\n", SelectedDrive);
- goto err_end;
- }
- if ((status & FDC1772STAT_RECNF)
-#ifdef TRACKBUFFER
- /* RECNF is no error after a multiple read when the FDC
- * searched for a non-existant sector!
- */
- && !(read_track &&
- FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt)
-#endif
- ) {
- if (Probing) {
- if (unit[SelectedDrive].disktype > disk_type) {
- /* try another disk type */
- unit[SelectedDrive].disktype--;
- set_capacity(disks[SelectedDrive],
- unit[SelectedDrive].disktype->blocks);
- } else
- Probing = 0;
- } else {
- /* record not found, but not probing. Maybe stretch wrong ? Restart probing */
- if (unit[SelectedDrive].autoprobe) {
- unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1;
- set_capacity(disks[SelectedDrive],
- unit[SelectedDrive].disktype->blocks);
- Probing = 1;
- }
- }
- if (Probing) {
- setup_req_params(SelectedDrive);
-#ifdef TRACKBUFFER
- BufferDrive = -1;
-#endif
- do_fd_action(SelectedDrive);
- return;
- }
- printk("fd%d: sector %d not found (side %d, track %d)\n",
- SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack);
- goto err_end;
- }
- if (status & FDC1772STAT_CRC) {
- printk("fd%d: CRC error (side %d, track %d, sector %d)\n",
- SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
- goto err_end;
- }
- if (status & FDC1772STAT_LOST) {
- printk("fd%d: lost data (side %d, track %d, sector %d)\n",
- SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
- goto err_end;
- }
- Probing = 0;
-
- if (ReqCmd == READ) {
-#ifdef TRACKBUFFER
- if (!read_track) {
- /*cache_clear (PhysDMABuffer, 512);*/
- copy_buffer (DMABuffer, ReqData);
- } else {
- /*cache_clear (PhysTrackBuffer, FD1772_MAX_SECTORS * 512);*/
- BufferDrive = SelectedDrive;
- BufferSide = ReqSide;
- BufferTrack = ReqTrack;
- copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
- }
-#else
- /*cache_clear( PhysDMABuffer, 512 ); */
- copy_buffer(DMABuffer, ReqData);
-#endif
- }
- if (++ReqCnt < CURRENT->current_nr_sectors) {
- /* read next sector */
- setup_req_params(SelectedDrive);
- do_fd_action(SelectedDrive);
- } else {
- /* all sectors finished */
- CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
- CURRENT->sector += CURRENT->current_nr_sectors;
- end_request(CURRENT, 1);
- redo_fd_request();
- }
- return;
-
-err_end:
-#ifdef TRACKBUFFER
- BufferDrive = -1;
-#endif
-
- fd_error();
-}
-
-
-static void fd_times_out(unsigned long dummy)
-{
- SET_IRQ_HANDLER(NULL);
- /* If the timeout occurred while the readtrack_check timer was
- * active, we need to cancel it, else bad things will happen */
- del_timer( &readtrack_timer );
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
- udelay(25);
-
- printk("floppy timeout\n");
- STOP_TIMEOUT(); /* hmm - should we do this ? */
- fd_error();
-}
-
-
-/* The (noop) seek operation here is needed to make the WP bit in the
- * FDC1772 status register accessible for check_change. If the last disk
- * operation would have been a RDSEC, this bit would always read as 0
- * no matter what :-( To save time, the seek goes to the track we're
- * already on.
- */
-
-static void finish_fdc(void)
-{
- /* DAG - just try without this dummy seek! */
- finish_fdc_done(0);
- return;
-
- if (!NeedSeek) {
- finish_fdc_done(0);
- } else {
- DPRINT(("finish_fdc: dummy seek started\n"));
- FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track);
- SET_IRQ_HANDLER(finish_fdc_done);
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
- MotorOn = 1;
- START_TIMEOUT();
- /* we must wait for the IRQ here, because the ST-DMA is
- * released immediately afterwards and the interrupt may be
- * delivered to the wrong driver.
- */
- }
-}
-
-
-static void finish_fdc_done(int dummy)
-{
- unsigned long flags;
-
- DPRINT(("finish_fdc_done entered\n"));
- STOP_TIMEOUT();
- NeedSeek = 0;
-
- if (timer_pending(&fd_timer) &&
- time_after(jiffies + 5, fd_timer.expires))
- /* If the check for a disk change is done too early after this
- * last seek command, the WP bit still reads wrong :-((
- */
- mod_timer(&fd_timer, jiffies + 5);
- else {
- /* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
- };
- del_timer(&motor_off_timer);
- START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
-
- save_flags(flags);
- cli();
- /* stdma_release(); - not sure if I should do something DAG */
- fdc_busy = 0;
- wake_up(&fdc_wait);
- restore_flags(flags);
-
- DPRINT(("finish_fdc() finished\n"));
-}
-
-
-/* Prevent "aliased" accesses. */
-static int fd_ref[4];
-static int fd_device[4];
-
-/* dummy for blk.h */
-static void floppy_off(unsigned int nr)
-{
-}
-
-
-/* On the old arcs write protect depends on the particular model
- of machine. On the A310, R140, and A440 there is a disc changed
- detect, however on the A4x0/1 range there is not. There
- is nothing to tell you which machine your on.
- At the moment I'm just marking changed always. I've
- left the Atari's 'change on write protect change' code in this
- part (but nothing sets it).
- RiscOS apparently checks the disc serial number etc. to detect changes
- - but if it sees a disc change line go high (?) it flips to using
- it. Well maybe I'll add that in the future (!?)
-*/
-static int check_floppy_change(struct gendisk *disk)
-{
- struct archy_floppy_struct *p = disk->private_data;
- unsigned int drive = p - unit;
-
- if (test_bit(drive, &fake_change)) {
- /* simulated change (e.g. after formatting) */
- return 1;
- }
- if (test_bit(drive, &changed_floppies)) {
- /* surely changed (the WP signal changed at least once) */
- return 1;
- }
- if (p->wpstat) {
- /* WP is on -> could be changed: to be sure, buffers should be
- * invalidated...
- */
- return 1;
- }
- return 1; /* DAG - was 0 */
-}
-
-static int floppy_revalidate(struct gendisk *disk)
-{
- struct archy_floppy_struct *p = disk->private_data;
- unsigned int drive = p - unit;
-
- if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change)
- || unit[drive].disktype == 0) {
-#ifdef TRACKBUFFER
- BufferDrive = -1;
-#endif
- clear_bit(drive, &fake_change);
- clear_bit(drive, &changed_floppies);
- p->disktype = 0;
- }
- return 0;
-}
-
-/* This sets up the global variables describing the current request. */
-
-static void setup_req_params(int drive)
-{
- int block = ReqBlock + ReqCnt;
-
- ReqTrack = block / unit[drive].disktype->spt;
- ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1;
- ReqSide = ReqTrack & 1;
- ReqTrack >>= 1;
- ReqData = ReqBuffer + 512 * ReqCnt;
-
-#ifdef TRACKBUFFER
- read_track = (ReqCmd == READ && CURRENT->errors == 0);
-#endif
-
- DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide,
- ReqTrack, ReqSector, (unsigned long) ReqData));
-}
-
-
-static void redo_fd_request(void)
-{
- int drive, type;
- struct archy_floppy_struct *floppy;
-
- DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n",
- CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "",
- CURRENT ? CURRENT->sector : 0));
-
-repeat:
-
- if (!CURRENT)
- goto the_end;
-
- floppy = CURRENT->rq_disk->private_data;
- drive = floppy - unit;
- type = fd_device[drive];
-
- if (!floppy->connected) {
- /* drive not connected */
- printk("Unknown Device: fd%d\n", drive);
- end_request(CURRENT, 0);
- goto repeat;
- }
- if (type == 0) {
- if (!floppy->disktype) {
- Probing = 1;
- floppy->disktype = disk_type + NUM_DISK_TYPES - 1;
- set_capacity(disks[drive], floppy->disktype->blocks);
- floppy->autoprobe = 1;
- }
- } else {
- /* user supplied disk type */
- --type;
- if (type >= NUM_DISK_TYPES) {
- printk("fd%d: invalid disk format", drive);
- end_request(CURRENT, 0);
- goto repeat;
- }
- floppy->disktype = &disk_type[type];
- set_capacity(disks[drive], floppy->disktype->blocks);
- floppy->autoprobe = 0;
- }
-
- if (CURRENT->sector + 1 > floppy->disktype->blocks) {
- end_request(CURRENT, 0);
- goto repeat;
- }
- /* stop deselect timer */
- del_timer(&motor_off_timer);
-
- ReqCnt = 0;
- ReqCmd = rq_data_dir(CURRENT);
- ReqBlock = CURRENT->sector;
- ReqBuffer = CURRENT->buffer;
- setup_req_params(drive);
- do_fd_action(drive);
-
- return;
-
-the_end:
- finish_fdc();
-}
-
-static void fd1772_checkint(void)
-{
- extern int fdc1772_bytestogo;
-
- /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/
- if (fdc1772_fdc_int_done)
- floppy_irqconsequencehandler();
- if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0);
- if (fdc_busy) {
- schedule_work(&fd1772_tq);
- }
-}
-
-static void do_fd_request(request_queue_t* q)
-{
- unsigned long flags;
-
- DPRINT(("do_fd_request for pid %d\n", current->pid));
- if (fdc_busy) return;
- save_flags(flags);
- cli();
- wait_event(fdc_wait, !fdc_busy);
- fdc_busy = 1;
- ENABLE_IRQ();
- restore_flags(flags);
-
- fdc1772_fdc_int_done = 0;
-
- redo_fd_request();
-
- schedule_work(&fd1772_tq);
-}
-
-
-static int invalidate_drive(struct block_device *bdev)
-{
- struct archy_floppy_struct *p = bdev->bd_disk->private_data;
- /* invalidate the buffer track to force a reread */
-#ifdef TRACKBUFFER
- BufferDrive = -1;
-#endif
-
- set_bit(p - unit, &fake_change);
- return 0;
-}
-
-static int fd_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long param)
-{
- struct block_device *bdev = inode->i_bdev;
-
- switch (cmd) {
- case FDFMTEND:
- case FDFLUSH:
- invalidate_drive(bdev);
- check_disk_change(bdev);
- case FDFMTBEG:
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-/* Initialize the 'unit' variable for drive 'drive' */
-
-static void fd_probe(int drive)
-{
- unit[drive].connected = 0;
- unit[drive].disktype = NULL;
-
- if (!fd_test_drive_present(drive))
- return;
-
- unit[drive].connected = 1;
- unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */
- unit[drive].steprate = FDC1772STEP_6;
- MotorOn = 1; /* from probe restore operation! */
-}
-
-
-/* This function tests the physical presence of a floppy drive (not
- * whether a disk is inserted). This is done by issuing a restore
- * command, waiting max. 2 seconds (that should be enough to move the
- * head across the whole disk) and looking at the state of the "TR00"
- * signal. This should now be raised if there is a drive connected
- * (and there is no hardware failure :-) Otherwise, the drive is
- * declared absent.
- */
-
-static int fd_test_drive_present(int drive)
-{
- unsigned long timeout;
- unsigned char status;
- int ok;
-
- printk("fd_test_drive_present %d\n", drive);
- if (drive > 1)
- return (0);
- return (1); /* Simple hack for the moment - the autodetect doesn't seem to work on arc */
- fd_select_drive(drive);
-
- /* disable interrupt temporarily */
- DISABLE_IRQ();
- FDC1772_WRITE(FDC1772REG_TRACK, 0x00); /* was ff00 why? */
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6);
-
- /*printk("fd_test_drive_present: Going into timeout loop\n"); */
- for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; time_before(jiffies, timeout);) {
- /* What does this piece of atariism do? - query for an interrupt? */
- /* if (!(mfp.par_dt_reg & 0x20))
- break; */
- /* Well this is my nearest guess - quit when we get an FDC interrupt */
- if (ioc_readb(IOC_FIQSTAT) & 2)
- break;
- }
-
- /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */
- status = FDC1772_READ(FDC1772REG_STATUS);
- ok = (status & FDC1772STAT_TR00) != 0;
-
- /*printk("fd_test_drive_present: ok=%d\n",ok); */
- /* force interrupt to abort restore operation (FDC1772 would try
- * about 50 seconds!) */
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
- udelay(500);
- status = FDC1772_READ(FDC1772REG_STATUS);
- udelay(20);
- /*printk("fd_test_drive_present: just before OK code %d\n",ok); */
-
- if (ok) {
- /* dummy seek command to make WP bit accessible */
- FDC1772_WRITE(FDC1772REG_DATA, 0);
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
- printk("fd_test_drive_present: just before wait for int\n");
- /* DAG: Guess means wait for interrupt */
- while (!(ioc_readb(IOC_FIQSTAT) & 2));
- printk("fd_test_drive_present: just after wait for int\n");
- status = FDC1772_READ(FDC1772REG_STATUS);
- }
- printk("fd_test_drive_present: just before ENABLE_IRQ\n");
- ENABLE_IRQ();
- printk("fd_test_drive_present: about to return\n");
- return (ok);
-}
-
-
-/* Look how many and which kind of drives are connected. If there are
- * floppies, additionally start the disk-change and motor-off timers.
- */
-
-static void config_types(void)
-{
- int drive, cnt = 0;
-
- printk("Probing floppy drive(s):\n");
- for (drive = 0; drive < FD_MAX_UNITS; drive++) {
- fd_probe(drive);
- if (unit[drive].connected) {
- printk("fd%d\n", drive);
- ++cnt;
- }
- }
-
- if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) {
- /* If FDC1772 is still busy from probing, give it another FORCI
- * command to abort the operation. If this isn't done, the FDC1772
- * will interrupt later and its IRQ line stays low, because
- * the status register isn't read. And this will block any
- * interrupts on this IRQ line :-(
- */
- FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
- udelay(500);
- FDC1772_READ(FDC1772REG_STATUS);
- udelay(20);
- }
- if (cnt > 0) {
- START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
- if (cnt == 1)
- fd_select_drive(0);
- /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
- }
-}
-
-/*
- * floppy_open check for aliasing (/dev/fd0 can be the same as
- * /dev/PS0 etc), and disallows simultaneous access to the same
- * drive with different device numbers.
- */
-
-static int floppy_open(struct inode *inode, struct file *filp)
-{
- int drive = iminor(inode) & 3;
- int type = iminor(inode) >> 2;
- int old_dev = fd_device[drive];
-
- if (fd_ref[drive] && old_dev != type)
- return -EBUSY;
-
- if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
- return -EBUSY;
-
- if (filp->f_flags & O_EXCL)
- fd_ref[drive] = -1;
- else
- fd_ref[drive]++;
-
- fd_device[drive] = type;
-
- if (filp->f_flags & O_NDELAY)
- return 0;
-
- if (filp->f_mode & 3) {
- check_disk_change(inode->i_bdev);
- if (filp->f_mode & 2) {
- if (unit[drive].wpstat) {
- floppy_release(inode, filp);
- return -EROFS;
- }
- }
- }
- return 0;
-}
-
-
-static int floppy_release(struct inode *inode, struct file *filp)
-{
- int drive = iminor(inode) & 3;
-
- if (fd_ref[drive] < 0)
- fd_ref[drive] = 0;
- else if (!fd_ref[drive]--) {
- printk("floppy_release with fd_ref == 0");
- fd_ref[drive] = 0;
- }
-
- return 0;
-}
-
-static struct block_device_operations floppy_fops =
-{
- .open = floppy_open,
- .release = floppy_release,
- .ioctl = fd_ioctl,
- .media_changed = check_floppy_change,
- .revalidate_disk= floppy_revalidate,
-};
-
-static struct kobject *floppy_find(dev_t dev, int *part, void *data)
-{
- int drive = *part & 3;
- if ((*part >> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS)
- return NULL;
- *part = 0;
- return get_disk(disks[drive]);
-}
-
-int fd1772_init(void)
-{
- static DEFINE_SPINLOCK(lock);
- int i, err = -ENOMEM;
-
- if (!machine_is_archimedes())
- return 0;
-
- for (i = 0; i < FD_MAX_UNITS; i++) {
- disks[i] = alloc_disk(1);
- if (!disks[i])
- goto err_disk;
- }
-
- err = register_blkdev(MAJOR_NR, "fd");
- if (err)
- goto err_disk;
-
- err = -EBUSY;
- if (request_dma(FLOPPY_DMA, "fd1772")) {
- printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA);
- goto err_blkdev;
- };
-
- if (request_dma(FIQ_FD1772, "fd1772 end")) {
- printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772);
- goto err_dma1;
- };
-
- /* initialize variables */
- SelectedDrive = -1;
-#ifdef TRACKBUFFER
- BufferDrive = BufferSide = BufferTrack = -1;
- /* Atari uses 512 - I want to eventually cope with 1K sectors */
- DMABuffer = kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL);
- TrackBuffer = DMABuffer + 512;
-#else
- /* Allocate memory for the DMAbuffer - on the Atari this takes it
- out of some special memory... */
- DMABuffer = kmalloc(2048); /* Copes with pretty large sectors */
-#endif
- err = -ENOMEM;
- if (!DMAbuffer)
- goto err_dma2;
-
- enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */
-
- floppy_queue = blk_init_queue(do_fd_request, &lock);
- if (!floppy_queue)
- goto err_queue;
-
- for (i = 0; i < FD_MAX_UNITS; i++) {
- unit[i].track = -1;
- disks[i]->major = MAJOR_NR;
- disks[i]->first_minor = 0;
- disks[i]->fops = &floppy_fops;
- sprintf(disks[i]->disk_name, "fd%d", i);
- disks[i]->private_data = &unit[i];
- disks[i]->queue = floppy_queue;
- set_capacity(disks[i], MAX_DISK_SIZE * 2);
- }
- blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
- floppy_find, NULL, NULL);
-
- for (i = 0; i < FD_MAX_UNITS; i++)
- add_disk(disks[i]);
-
- config_types();
-
- return 0;
-
- err_queue:
- kfree(DMAbuffer);
- err_dma2:
- free_dma(FIQ_FD1772);
-
- err_dma1:
- free_dma(FLOPPY_DMA);
-
- err_blkdev:
- unregister_blkdev(MAJOR_NR, "fd");
-
- err_disk:
- while (i--)
- put_disk(disks[i]);
- return err;
-}
diff --git a/drivers/acorn/block/fd1772dma.S b/drivers/acorn/block/fd1772dma.S
deleted file mode 100644
index 7964435443ec..000000000000
--- a/drivers/acorn/block/fd1772dma.S
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <asm/hardware.h>
-
-@ Code for DMA with the 1772 fdc
-.text
-
-
- .global fdc1772_dataaddr
-fdc1772_fiqdata:
-@ Number of bytes left to DMA
- .global fdc1772_bytestogo
-fdc1772_bytestogo:
- .word 0
-@ Place to put/get data from in DMA
- .global fdc1772_dataaddr
-fdc1772_dataaddr:
- .word 0
-
- .global fdc1772_fdc_int_done
-fdc1772_fdc_int_done:
- .word 0
- .global fdc1772_comendstatus
-fdc1772_comendstatus:
- .word 0
-
-@ We hang this off DMA channel 1
- .global fdc1772_comendhandler
-fdc1772_comendhandler:
- mov r8,#IOC_BASE
- ldrb r9,[r8,#0x34] @ IOC FIQ status
- tst r9,#2
- subeqs pc,r14,#4 @ should I leave a space here
- orr r9,r8,#0x10000 @ FDC base
- adr r8,fdc1772_fdc_int_done
- ldrb r10,[r9,#0] @ FDC status
- mov r9,#1 @ Got a FIQ flag
- stmia r8,{r9,r10}
- subs pc,r14,#4
-
-
- .global fdc1772_dma_read
-fdc1772_dma_read:
- mov r8,#IOC_BASE
- ldrb r9,[r8,#0x34] @ IOC FIQ status
- tst r9,#1
- beq fdc1772_dma_read_notours
- orr r8,r8,#0x10000 @ FDC base
- ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt)
- ldmia r11,{r8,r9}
- subs r8,r8,#1 @ One less byte to go
- @ If there was somewhere for this data to go then store it and update pointers
- strplb r10,[r9],#1 @ Store the data and increment the pointer
- stmplia r11,{r8,r9} @ Update count/pointers
- @ Handle any other interrupts if there are any
-fdc1772_dma_read_notours:
- @ Cant branch because this code has been copied down to the FIQ vector
- ldr pc,[pc,#-4]
- .word fdc1772_comendhandler
- .global fdc1772_dma_read_end
-fdc1772_dma_read_end:
-
- .global fdc1772_dma_write
-fdc1772_dma_write:
- mov r8,#IOC_BASE
- ldrb r9,[r8,#0x34] @ IOC FIQ status
- tst r9,#1
- beq fdc1772_dma_write_notours
- orr r8,r8,#0x10000 @ FDC base
- ldmia r11,{r9,r10}
- subs r9,r9,#1 @ One less byte to go
- @ If there really is some data then get it, store it and update count
- ldrplb r12,[r10],#1
- strplb r12,[r8,#0xc] @ write it to FDC data reg
- stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt
- @ Handle any other interrupts
-fdc1772_dma_write_notours:
- @ Cant branch because this code has been copied down to the FIQ vector
- ldr pc,[pc,#-4]
- .word fdc1772_comendhandler
-
- .global fdc1772_dma_write_end
-fdc1772_dma_write_end:
-
-
-@ Setup the FIQ R11 to point to the data and store the count, address
-@ for this dma
-@ R0=count
-@ R1=address
- .global fdc1772_setupdma
-fdc1772_setupdma:
- @ The big job is flipping in and out of FIQ mode
- adr r2,fdc1772_fiqdata @ This is what we really came here for
- stmia r2,{r0,r1}
- mov r3, pc
- teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode
- mov r0,r0 @ NOP
- mov r11,r2
- teqp r3,#0 @ Normal mode
- mov r0,r0 @ NOP
- mov pc,r14
-
diff --git a/drivers/acorn/block/mfm.S b/drivers/acorn/block/mfm.S
deleted file mode 100644
index c90cbd41ce21..000000000000
--- a/drivers/acorn/block/mfm.S
+++ /dev/null
@@ -1,162 +0,0 @@
-@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
-@ motherboard and on ST506 expansion podules.
-@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999
-
-#include <asm/assembler.h>
-
-hdc63463_irqdata:
-@ Controller base address
- .global hdc63463_baseaddress
-hdc63463_baseaddress:
- .word 0
-
- .global hdc63463_irqpolladdress
-hdc63463_irqpolladdress:
- .word 0
-
- .global hdc63463_irqpollmask
-hdc63463_irqpollmask:
- .word 0
-
-@ where to read/write data from the kernel data space
- .global hdc63463_dataptr
-hdc63463_dataptr:
- .word 0
-
-@ Number of bytes left to transfer
- .global hdc63463_dataleft
-hdc63463_dataleft:
- .word 0
-
-@ -------------------------------------------------------------------------
-@ hdc63463_writedma: DMA from host to controller
-@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
-@ r3=data ptr, r4=data left, r5,r6=temporary
- .global hdc63463_writedma
-hdc63463_writedma:
- stmfd sp!,{r4-r7}
- adr r5,hdc63463_irqdata
- ldmia r5,{r0,r1,r2,r3,r4}
-
-writedma_again:
-
- @ test number of remaining bytes to transfer
- cmp r4,#0
- beq writedma_end
- bmi writedma_end
-
- @ Check the hdc is interrupting
- ldrb r5,[r1,#0]
- tst r5,r2
- beq writedma_end
-
- @ Transfer a block of upto 256 bytes
- cmp r4,#256
- movlt r7,r4
- movge r7,#256
-
- @ Check the hdc is still busy and command has not ended and no errors
- ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status
- @ think we should continue DMA until it drops busy - perhaps this was
- @ the main problem with corrected errors causing a hang
- @tst r5,#0x3c00 @ Test for things which should be off
- @bne writedma_end
- and r5,r5,#0x8000 @ This is test for things which should be on: Busy
- cmp r5,#0x8000
- bne writedma_end
-
- @ Bytes remaining at end
- sub r4,r4,r7
-
- @ HDC Write register location
- add r0,r0,#32+8
-
-writedma_loop:
- @ OK - pretty sure we should be doing this
-
- ldr r5,[r3],#4 @ Get a word to be written
- @ get bottom half to be sent first
- mov r6,r5,lsl#16 @ Separate the first 2 bytes
- orr r2,r6,r6,lsr #16 @ Duplicate them in the bottom half of the word
- @ now the top half
- mov r6,r5,lsr#16 @ Get 2nd 2 bytes
- orr r6,r6,r6,lsl#16 @ Duplicate
- @str r6,[r0] @ to hdc
- stmia r0,{r2,r6}
- subs r7,r7,#4 @ Dec. number of bytes left
- bne writedma_loop
-
- @ If we were too slow we had better go through again - DAG - took out with new interrupt routine
- @ sub r0,r0,#32+8
- @ adr r2,hdc63463_irqdata
- @ ldr r2,[r2,#8]
- @ b writedma_again
-
-writedma_end:
- adr r5,hdc63463_irqdata+12
- stmia r5,{r3,r4}
- ldmfd sp!,{r4-r7}
- RETINSTR(mov,pc,lr)
-
-@ -------------------------------------------------------------------------
-@ hdc63463_readdma: DMA from controller to host
-@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
-@ r3=data ptr, r4=data left, r5,r6=temporary
- .global hdc63463_readdma
-hdc63463_readdma:
- stmfd sp!,{r4-r7}
- adr r5,hdc63463_irqdata
- ldmia r5,{r0,r1,r2,r3,r4}
-
-readdma_again:
- @ test number of remaining bytes to transfer
- cmp r4,#0
- beq readdma_end
- bmi readdma_end
-
- @ Check the hdc is interrupting
- ldrb r5,[r1,#0]
- tst r5,r2
- beq readdma_end
-
- @ Check the hdc is still busy and command has not ended and no errors
- ldr r5,[r0,#32] @ Status reg - 16 bit - its the top few bits which are status
- @ think we should continue DMA until it drops busy - perhaps this was
- @ the main problem with corrected errors causing a hang
- @tst r5,#0x3c00 @ Test for things which should be off
- @bne readdma_end
- and r5,r5,#0x8000 @ This is test for things which should be on: Busy
- cmp r5,#0x8000
- bne readdma_end
-
- @ Transfer a block of upto 256 bytes
- cmp r4,#256
- movlt r7,r4
- movge r7,#256
-
- @ Bytes remaining at end
- sub r4,r4,r7
-
- @ Set a pointer to the data register in the HDC
- add r0,r0,#8
-readdma_loop:
- @ OK - pretty sure we should be doing this
- ldmia r0,{r5,r6}
- mov r5,r5,lsl#16
- mov r6,r6,lsl#16
- orr r6,r6,r5,lsr #16
- str r6,[r3],#4
- subs r7,r7,#4 @ Decrement bytes to go
- bne readdma_loop
-
- @ Try reading multiple blocks - if this was fast enough then I do not think
- @ this should help - NO taken out DAG - new interrupt handler has
- @ non-consecutive memory blocks
- @ sub r0,r0,#8
- @ b readdma_again
-
-readdma_end:
- adr r5,hdc63463_irqdata+12
- stmia r5,{r3,r4}
- ldmfd sp!,{r4-r7}
- RETINSTR(mov,pc,lr)
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
deleted file mode 100644
index d85520f78e68..000000000000
--- a/drivers/acorn/block/mfmhd.c
+++ /dev/null
@@ -1,1385 +0,0 @@
-/*
- * linux/drivers/acorn/block/mfmhd.c
- *
- * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk)
- *
- * MFM hard drive code [experimental]
- */
-
-/*
- * Change list:
- *
- * 3/2/96:DAG: Started a change list :-)
- * Set the hardsect_size pointers up since we are running 256 byte
- * sectors
- * Added DMA code, put it into the rw_intr
- * Moved RCAL out of generic interrupt code - don't want to do it
- * while DMA'ing - its now in individual handlers.
- * Took interrupt handlers off task queue lists and called
- * directly - not sure of implications.
- *
- * 18/2/96:DAG: Well its reading OK I think, well enough for image file code
- * to find the image file; but now I've discovered that I actually
- * have to put some code in for image files.
- *
- * Added stuff for image files; seems to work, but I've not
- * got a multisegment image file (I don't think!).
- * Put in a hack (yep a real hack) for multiple cylinder reads.
- * Not convinced its working.
- *
- * 5/4/96:DAG: Added asm/hardware.h and use IOC_ macros
- * Rewrote dma code in mfm.S (again!) - now takes a word at a time
- * from main RAM for speed; still doesn't feel speedy!
- *
- * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding
- * things up, I've finally figured out why its so damn slow.
- * Linux is only reading a block at a time, and so you never
- * get more than 1K per disc revoloution ~=60K/second.
- *
- * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to
- * join adjacent blocks together. Everything falls flat on its
- * face.
- * Four hours of debugging later; I hadn't realised that
- * ll_rw_blk would be so generous as to join blocks whose
- * results aren't going into consecutive buffers.
- *
- * OK; severe rehacking of mfm_rw_interrupt; now end_request's
- * as soon as its DMA'd each request. Odd thing is that
- * we are sometimes getting interrupts where we are not transferring
- * any data; why? Is that what happens when you miss? I doubt
- * it; are we too fast? No - its just at command ends. Got 240K/s
- * better than before, but RiscOS hits 480K/s
- *
- * 25/6/96:RMK: Fixed init code to allow the MFM podule to work. Increased the
- * number of errors for my Miniscribe drive (8425).
- *
- * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off
- * - so in request_done just before it clears Busy it sends a
- * check drive 0 - and the LEDs go off!!!!
- *
- * Added test for mainboard controller. - Removes need for separate
- * define.
- *
- * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make
- * IM drivers work.
- * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO
- * error.)
- *
- * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents
- * gone :-( Hand modified afterwards.
- * Took out last remains of the older image map system.
- *
- * 22/9/96:DAG: Changed mfm.S so it will carry on DMA'ing til; BSY is dropped
- * Changed mfm_rw_intr so that it doesn't follow the error
- * code until BSY is dropped. Nope - still broke. Problem
- * may revolve around when it reads the results for the error
- * number?
- *
- *16/11/96:DAG: Modified for 2.0.18; request_irq changed
- *
- *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system.
- * Improved probe for onboard MFM chip - it was hanging on my A5k.
- * Added autodetect CHS code such that we don't rely on the presence
- * of an ADFS boot block. Added ioport resource manager calls so
- * that we don't clash with already-running hardware (eg. RiscPC Ether
- * card slots if someone tries this)!
- *
- * 17/1/97:RMK: Upgraded to 2.1 kernels.
- *
- * 4/3/98:RMK: Changed major number to 21.
- *
- * 27/6/98:RMK: Changed asm/delay.h to linux/delay.h for mdelay().
- */
-
-/*
- * Possible enhancements:
- * Multi-thread the code so that it is possible that while one drive
- * is seeking, the other one can be reading data/seeking as well.
- * This would be a performance boost with dual drive systems.
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/major.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/blkpg.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/dma.h>
-#include <asm/hardware.h>
-#include <asm/ecard.h>
-#include <asm/hardware/ioc.h>
-
-static void (*do_mfm)(void) = NULL;
-static struct request_queue *mfm_queue;
-static DEFINE_SPINLOCK(mfm_lock);
-
-#define MAJOR_NR MFM_ACORN_MAJOR
-#define QUEUE (mfm_queue)
-#define CURRENT elv_next_request(mfm_queue)
-
-/*
- * Configuration section
- *
- * This is the maximum number of drives that we accept
- */
-#define MFM_MAXDRIVES 2
-/*
- * Linux I/O address of onboard MFM controller or 0 to disable this
- */
-#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
-/*
- * Uncomment this to enable debugging in the MFM driver...
- */
-#ifndef DEBUG
-/*#define DEBUG */
-#endif
-/*
- * End of configuration
- */
-
-
-/*
- * This structure contains all information to do with a particular physical
- * device.
- */
-struct mfm_info {
- unsigned char sectors;
- unsigned char heads;
- unsigned short cylinders;
- unsigned short lowcurrent;
- unsigned short precomp;
-#define NO_TRACK -1
-#define NEED_1_RECAL -2
-#define NEED_2_RECAL -3
- int cylinder;
- struct {
- char recal;
- char report;
- char abort;
- } errors;
-} mfm_info[MFM_MAXDRIVES];
-
-#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
-
-/* Stuff from the assembly routines */
-extern unsigned int hdc63463_baseaddress; /* Controller base address */
-extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */
-extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */
-extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */
-extern int hdc63463_dataleft; /* Number of bytes left to transfer */
-
-
-
-
-static int lastspecifieddrive;
-static unsigned Busy;
-
-static unsigned int PartFragRead; /* The number of sectors which have been read
- during a partial read split over two
- cylinders. If 0 it means a partial
- read did not occur. */
-
-static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */
-static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */
-
-static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */
-static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */
-static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know
- where to take over */
-static char *Copy_buffer;
-
-
-static void mfm_seek(void);
-static void mfm_rerequest(void);
-static void mfm_request(void);
-static void mfm_specify (void);
-static void issue_request(unsigned int block, unsigned int nsect,
- struct request *req);
-
-static unsigned int mfm_addr; /* Controller address */
-static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */
-static unsigned int mfm_irqenable; /* Podule IRQ enable location */
-static unsigned char mfm_irq; /* Interrupt number */
-static int mfm_drives = 0; /* drives available */
-static int mfm_status = 0; /* interrupt status */
-static int *errors;
-
-static struct rawcmd {
- unsigned int dev;
- unsigned int cylinder;
- unsigned int head;
- unsigned int sector;
- unsigned int cmdtype;
- unsigned int cmdcode;
- unsigned char cmddata[16];
- unsigned int cmdlen;
-} raw_cmd;
-
-static unsigned char result[16];
-
-static struct cont {
- void (*interrupt) (void); /* interrupt handler */
- void (*error) (void); /* error handler */
- void (*redo) (void); /* redo handler */
- void (*done) (int st); /* done handler */
-} *cont = NULL;
-
-#if 0
-static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
-#endif
-
-int number_mfm_drives = 1;
-
-/* ------------------------------------------------------------------------------------------ */
-/*
- * From the HD63463 data sheet from Hitachi Ltd.
- */
-
-#define MFM_COMMAND (mfm_addr + 0)
-#define MFM_DATAOUT (mfm_addr + 1)
-#define MFM_STATUS (mfm_addr + 8)
-#define MFM_DATAIN (mfm_addr + 9)
-
-#define CMD_ABT 0xF0 /* Abort */
-#define CMD_SPC 0xE8 /* Specify */
-#define CMD_TST 0xE0 /* Test */
-#define CMD_RCLB 0xC8 /* Recalibrate */
-#define CMD_SEK 0xC0 /* Seek */
-#define CMD_WFS 0xAB /* Write Format Skew */
-#define CMD_WFM 0xA3 /* Write Format */
-#define CMD_MTB 0x90 /* Memory to buffer */
-#define CMD_CMPD 0x88 /* Compare data */
-#define CMD_WD 0x87 /* Write data */
-#define CMD_RED 0x70 /* Read erroneous data */
-#define CMD_RIS 0x68 /* Read ID skew */
-#define CMD_FID 0x61 /* Find ID */
-#define CMD_RID 0x60 /* Read ID */
-#define CMD_BTM 0x50 /* Buffer to memory */
-#define CMD_CKD 0x48 /* Check data */
-#define CMD_RD 0x40 /* Read data */
-#define CMD_OPBW 0x38 /* Open buffer write */
-#define CMD_OPBR 0x30 /* Open buffer read */
-#define CMD_CKV 0x28 /* Check drive */
-#define CMD_CKE 0x20 /* Check ECC */
-#define CMD_POD 0x18 /* Polling disable */
-#define CMD_POL 0x10 /* Polling enable */
-#define CMD_RCAL 0x08 /* Recall */
-
-#define STAT_BSY 0x8000 /* Busy */
-#define STAT_CPR 0x4000 /* Command Parameter Rejection */
-#define STAT_CED 0x2000 /* Command end */
-#define STAT_SED 0x1000 /* Seek end */
-#define STAT_DER 0x0800 /* Drive error */
-#define STAT_ABN 0x0400 /* Abnormal end */
-#define STAT_POL 0x0200 /* Polling */
-
-/* ------------------------------------------------------------------------------------------ */
-#ifdef DEBUG
-static void console_printf(const char *fmt,...)
-{
- static char buffer[2048]; /* Arbitary! */
- extern void console_print(const char *);
- unsigned long flags;
- va_list ap;
-
- local_irq_save(flags);
-
- va_start(ap, fmt);
- vsprintf(buffer, fmt, ap);
- console_print(buffer);
- va_end(fmt);
-
- local_irq_restore(flags);
-}; /* console_printf */
-
-#define DBG(x...) console_printf(x)
-#else
-#define DBG(x...)
-#endif
-
-static void print_status(void)
-{
- char *error;
- static char *errors[] = {
- "no error",
- "command aborted",
- "invalid command",
- "parameter error",
- "not initialised",
- "rejected TEST",
- "no useld",
- "write fault",
- "not ready",
- "no scp",
- "in seek",
- "invalid NCA",
- "invalid step rate",
- "seek error",
- "over run",
- "invalid PHA",
- "data field EEC error",
- "data field CRC error",
- "error corrected",
- "data field fatal error",
- "no data am",
- "not hit",
- "ID field CRC error",
- "time over",
- "no ID am",
- "not writable"
- };
- if (result[1] < 0x65)
- error = errors[result[1] >> 2];
- else
- error = "unknown";
- printk("(");
- if (mfm_status & STAT_BSY) printk("BSY ");
- if (mfm_status & STAT_CPR) printk("CPR ");
- if (mfm_status & STAT_CED) printk("CED ");
- if (mfm_status & STAT_SED) printk("SED ");
- if (mfm_status & STAT_DER) printk("DER ");
- if (mfm_status & STAT_ABN) printk("ABN ");
- if (mfm_status & STAT_POL) printk("POL ");
- printk(") SSB = %X (%s)\n", result[1], error);
-
-}
-
-/* ------------------------------------------------------------------------------------- */
-
-static void issue_command(int command, unsigned char *cmdb, int len)
-{
- int status;
-#ifdef DEBUG
- int i;
- console_printf("issue_command: %02X: ", command);
- for (i = 0; i < len; i++)
- console_printf("%02X ", cmdb[i]);
- console_printf("\n");
-#endif
-
- do {
- status = inw(MFM_STATUS);
- } while (status & (STAT_BSY | STAT_POL));
- DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
-
- if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
- outw(CMD_RCAL, MFM_COMMAND);
- while (inw(MFM_STATUS) & STAT_BSY);
- }
- status = inw(MFM_STATUS);
- DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
-
- while (len > 0) {
- outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
- len -= 2;
- cmdb += 2;
- }
- status = inw(MFM_STATUS);
- DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
-
- outw(command, MFM_COMMAND);
- status = inw(MFM_STATUS);
- DBG("issue_command: status immediately after command issue: %02X:\n ", status >> 8);
-}
-
-static void wait_for_completion(void)
-{
- while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
-}
-
-static void wait_for_command_end(void)
-{
- int i;
-
- while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
-
- for (i = 0; i < 16;) {
- int in;
- in = inw(MFM_DATAIN);
- result[i++] = in >> 8;
- result[i++] = in;
- }
- outw (CMD_RCAL, MFM_COMMAND);
-}
-
-/* ------------------------------------------------------------------------------------- */
-
-static void mfm_rw_intr(void)
-{
- int old_status; /* Holds status on entry, we read to see if the command just finished */
-#ifdef DEBUG
- console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
- print_status();
-#endif
-
- /* Now don't handle the error until BSY drops */
- if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
- /* Something has gone wrong - let's try that again */
- outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
- if (cont) {
- DBG("mfm_rw_intr: DER/ABN err\n");
- cont->error();
- cont->redo();
- };
- return;
- };
-
- /* OK so what ever happened it's not an error, now I reckon we are left between
- a choice of command end or some data which is ready to be collected */
- /* I think we have to transfer data while the interrupt line is on and its
- not any other type of interrupt */
- if (rq_data_dir(CURRENT) == WRITE) {
- extern void hdc63463_writedma(void);
- if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
- printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
- if (cont) {
- cont->error();
- cont->redo();
- };
- return;
- };
- hdc63463_writedma();
- } else {
- extern void hdc63463_readdma(void);
- if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
- printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
- if (cont) {
- cont->error();
- cont->redo();
- };
- return;
- };
- DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
- hdc63463_readdma();
- }; /* Read */
-
- if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
- /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
- /* Ah - well looking at the status its just when we get command end; so no problem */
- /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
- hdc63463_dataptr,Copy_buffer+256);
- print_status(); */
- } else {
- Sectors256LeftInCurrent--;
- Copy_buffer += 256;
- Copy_Sector++;
-
- /* We have come to the end of this request */
- if (!Sectors256LeftInCurrent) {
- DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
- CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
-
- CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
- CURRENT->sector += CURRENT->current_nr_sectors;
- SectorsLeftInRequest -= CURRENT->current_nr_sectors;
-
- end_request(CURRENT, 1);
- if (SectorsLeftInRequest) {
- hdc63463_dataptr = (unsigned int) CURRENT->buffer;
- Copy_buffer = CURRENT->buffer;
- Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
- errors = &(CURRENT->errors);
- /* These should match the present calculations of the next logical sector
- on the device
- Copy_Sector=CURRENT->sector*2; */
-
- if (Copy_Sector != CURRENT->sector * 2)
-#ifdef DEBUG
- /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
- Copy_Sector, CURRENT->sector * 2);
-#else
- printk("mfm: Copy_Sector mismatch! Eek!\n");
-#endif
- }; /* CURRENT */
- }; /* Sectors256LeftInCurrent */
- };
-
- old_status = mfm_status;
- mfm_status = inw(MFM_STATUS);
- if (mfm_status & (STAT_DER | STAT_ABN)) {
- /* Something has gone wrong - let's try that again */
- if (cont) {
- DBG("mfm_rw_intr: DER/ABN error\n");
- cont->error();
- cont->redo();
- };
- return;
- };
-
- /* If this code wasn't entered due to command_end but there is
- now a command end we must read the command results out. If it was
- entered like this then mfm_interrupt_handler would have done the
- job. */
- if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
- ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
- int len = 0;
- while (len < 16) {
- int in;
- in = inw(MFM_DATAIN);
- result[len++] = in >> 8;
- result[len++] = in;
- };
- }; /* Result read */
-
- /*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */
-
- /* If end of command move on */
- if (mfm_status & (STAT_CED)) {
- outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
- /* End of command - trigger the next command */
- if (cont) {
- cont->done(1);
- }
- DBG("mfm_rw_intr: returned from cont->done\n");
- } else {
- /* Its going to generate another interrupt */
- do_mfm = mfm_rw_intr;
- };
-}
-
-static void mfm_setup_rw(void)
-{
- DBG("setting up for rw...\n");
-
- do_mfm = mfm_rw_intr;
- issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
-}
-
-static void mfm_recal_intr(void)
-{
-#ifdef DEBUG
- console_printf("recal intr - status = ");
- print_status();
-#endif
- outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
- if (mfm_status & (STAT_DER | STAT_ABN)) {
- printk("recal failed\n");
- MFM_DRV_INFO.cylinder = NEED_2_RECAL;
- if (cont) {
- cont->error();
- cont->redo();
- }
- return;
- }
- /* Thats seek end - we are finished */
- if (mfm_status & STAT_SED) {
- issue_command(CMD_POD, NULL, 0);
- MFM_DRV_INFO.cylinder = 0;
- mfm_seek();
- return;
- }
- /* Command end without seek end (see data sheet p.20) for parallel seek
- - we have to send a POL command to wait for the seek */
- if (mfm_status & STAT_CED) {
- do_mfm = mfm_recal_intr;
- issue_command(CMD_POL, NULL, 0);
- return;
- }
- printk("recal: unknown status\n");
-}
-
-static void mfm_seek_intr(void)
-{
-#ifdef DEBUG
- console_printf("seek intr - status = ");
- print_status();
-#endif
- outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
- if (mfm_status & (STAT_DER | STAT_ABN)) {
- printk("seek failed\n");
- MFM_DRV_INFO.cylinder = NEED_2_RECAL;
- if (cont) {
- cont->error();
- cont->redo();
- }
- return;
- }
- if (mfm_status & STAT_SED) {
- issue_command(CMD_POD, NULL, 0);
- MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
- mfm_seek();
- return;
- }
- if (mfm_status & STAT_CED) {
- do_mfm = mfm_seek_intr;
- issue_command(CMD_POL, NULL, 0);
- return;
- }
- printk("seek: unknown status\n");
-}
-
-/* IDEA2 seems to work better - its what RiscOS sets my
- * disc to - on its SECOND call to specify!
- */
-#define IDEA2
-#ifndef IDEA2
-#define SPEC_SL 0x16
-#define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */
-#else
-#define SPEC_SL 0x00 /* OM2 - SL - step pulse low */
-#define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */
-#endif
-
-static void mfm_setupspecify (int drive, unsigned char *cmdb)
-{
- cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
- cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
- cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */
- cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */
- cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
- cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */
- cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */
- cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */
- cmdb[8] = SPEC_SH;
- cmdb[9] = 0x0a; /* gap length 1 */
- cmdb[10] = 0x0d; /* gap length 2 */
- cmdb[11] = 0x0c; /* gap length 3 */
- cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */
- cmdb[13] = mfm_info[drive].precomp - 1;
- cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */
- cmdb[15] = mfm_info[drive].lowcurrent - 1;
-}
-
-static void mfm_specify (void)
-{
- unsigned char cmdb[16];
-
- DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
- mfm_setupspecify (raw_cmd.dev, cmdb);
-
- issue_command (CMD_SPC, cmdb, 16);
- /* Ensure that we will do another specify if we move to the other drive */
- lastspecifieddrive = raw_cmd.dev;
- wait_for_completion();
-}
-
-static void mfm_seek(void)
-{
- unsigned char cmdb[4];
-
- DBG("seeking...\n");
- if (MFM_DRV_INFO.cylinder < 0) {
- do_mfm = mfm_recal_intr;
- DBG("mfm_seek: about to call specify\n");
- mfm_specify (); /* DAG added this */
-
- cmdb[0] = raw_cmd.dev + 1;
- cmdb[1] = 0;
-
- issue_command(CMD_RCLB, cmdb, 2);
- return;
- }
- if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
- cmdb[0] = raw_cmd.dev + 1;
- cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */
- cmdb[2] = raw_cmd.cylinder >> 8;
- cmdb[3] = raw_cmd.cylinder;
-
- do_mfm = mfm_seek_intr;
- issue_command(CMD_SEK, cmdb, 4);
- } else
- mfm_setup_rw();
-}
-
-static void mfm_initialise(void)
-{
- DBG("init...\n");
- mfm_seek();
-}
-
-static void request_done(int uptodate)
-{
- DBG("mfm:request_done\n");
- if (uptodate) {
- unsigned char block[2] = {0, 0};
-
- /* Apparently worked - let's check bytes left to DMA */
- if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
- printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
- end_request(CURRENT, 0);
- Busy = 0;
- };
- /* Potentially this means that we've done; but we might be doing
- a partial access, (over two cylinders) or we may have a number
- of fragments in an image file. First let's deal with partial accesss
- */
- if (PartFragRead) {
- /* Yep - a partial access */
-
- /* and issue the remainder */
- issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
- return;
- }
-
- /* ah well - perhaps there is another fragment to go */
-
- /* Increment pointers/counts to start of next fragment */
- if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
-
- /* No - its the end of the line */
- /* end_request's should have happened at the end of sector DMAs */
- /* Turns Drive LEDs off - may slow it down? */
- if (!elv_next_request(QUEUE))
- issue_command(CMD_CKV, block, 2);
-
- Busy = 0;
- DBG("request_done: About to mfm_request\n");
- /* Next one please */
- mfm_request(); /* Moved from mfm_rw_intr */
- DBG("request_done: returned from mfm_request\n");
- } else {
- printk("mfm:request_done: update=0\n");
- end_request(CURRENT, 0);
- Busy = 0;
- }
-}
-
-static void error_handler(void)
-{
- printk("error detected... status = ");
- print_status();
- (*errors)++;
- if (*errors > MFM_DRV_INFO.errors.abort)
- cont->done(0);
- if (*errors > MFM_DRV_INFO.errors.recal)
- MFM_DRV_INFO.cylinder = NEED_2_RECAL;
-}
-
-static void rw_interrupt(void)
-{
- printk("rw_interrupt\n");
-}
-
-static struct cont rw_cont =
-{
- rw_interrupt,
- error_handler,
- mfm_rerequest,
- request_done
-};
-
-/*
- * Actually gets round to issuing the request - note everything at this
- * point is in 256 byte sectors not Linux 512 byte blocks
- */
-static void issue_request(unsigned int block, unsigned int nsect,
- struct request *req)
-{
- struct gendisk *disk = req->rq_disk;
- struct mfm_info *p = disk->private_data;
- int track, start_head, start_sector;
- int sectors_to_next_cyl;
- dev = p - mfm_info;
-
- track = block / p->sectors;
- start_sector = block % p->sectors;
- start_head = track % p->heads;
-
- /* First get the number of whole tracks which are free before the next
- track */
- sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors;
- /* Then add in the number of sectors left on this track */
- sectors_to_next_cyl += (p->sectors - start_sector);
-
- DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track);
-
- raw_cmd.dev = dev;
- raw_cmd.sector = start_sector;
- raw_cmd.head = start_head;
- raw_cmd.cylinder = track / p->heads;
- raw_cmd.cmdtype = CURRENT->cmd;
- raw_cmd.cmdcode = rq_data_dir(CURRENT) == WRITE ? CMD_WD : CMD_RD;
- raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */
- raw_cmd.cmddata[1] = raw_cmd.head;
- raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
- raw_cmd.cmddata[3] = raw_cmd.cylinder;
- raw_cmd.cmddata[4] = raw_cmd.head;
- raw_cmd.cmddata[5] = raw_cmd.sector;
-
- /* Was == and worked - how the heck??? */
- if (lastspecifieddrive != raw_cmd.dev)
- mfm_specify ();
-
- if (nsect <= sectors_to_next_cyl) {
- raw_cmd.cmddata[6] = nsect >> 8;
- raw_cmd.cmddata[7] = nsect;
- PartFragRead = 0; /* All in one */
- PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */
- } else {
- raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
- raw_cmd.cmddata[7] = sectors_to_next_cyl;
- PartFragRead = sectors_to_next_cyl; /* only do this many this time */
- PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */
- PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
- }
- raw_cmd.cmdlen = 8;
-
- /* Setup DMA pointers */
- hdc63463_dataptr = (unsigned int) Copy_buffer;
- hdc63463_dataleft = nsect * 256; /* Better way? */
-
- DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
- raw_cmd.dev + 'a', rq_data_dir(CURRENT) == READ ? "read" : "writ",
- raw_cmd.cylinder,
- raw_cmd.head,
- raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
-
- cont = &rw_cont;
- errors = &(CURRENT->errors);
-#if 0
- mfm_tq.routine = (void (*)(void *)) mfm_initialise;
- queue_task(&mfm_tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-#else
- mfm_initialise();
-#endif
-} /* issue_request */
-
-/*
- * Called when an error has just happened - need to trick mfm_request
- * into thinking we weren't busy
- *
- * Turn off ints - mfm_request expects them this way
- */
-static void mfm_rerequest(void)
-{
- DBG("mfm_rerequest\n");
- cli();
- Busy = 0;
- mfm_request();
-}
-
-static struct gendisk *mfm_gendisk[2];
-
-static void mfm_request(void)
-{
- DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
-
- /* If we are still processing then return; we will get called again */
- if (Busy) {
- /* Again seems to be common in 1.3.45 */
- /*DBG*/printk("mfm_request: Exiting due to busy\n");
- return;
- }
- Busy = 1;
-
- while (1) {
- unsigned int block, nsect;
- struct gendisk *disk;
-
- DBG("mfm_request: loop start\n");
- sti();
-
- DBG("mfm_request: before !CURRENT\n");
-
- if (!CURRENT) {
- printk("mfm_request: Exiting due to empty queue (pre)\n");
- do_mfm = NULL;
- Busy = 0;
- return;
- }
-
- DBG("mfm_request: before arg extraction\n");
-
- disk = CURRENT->rq_disk;
- block = CURRENT->sector;
- nsect = CURRENT->nr_sectors;
- if (block >= get_capacity(disk) ||
- block+nsect > get_capacity(disk)) {
- printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n",
- disk->disk_name, block, nsect, get_capacity(disk));
- printk("mfm: continue 1\n");
- end_request(CURRENT, 0);
- Busy = 0;
- continue;
- }
-
- /* DAG: Linux doesn't cope with this - even though it has an array telling
- it the hardware block size - silly */
- block <<= 1; /* Now in 256 byte sectors */
- nsect <<= 1; /* Ditto */
-
- SectorsLeftInRequest = nsect >> 1;
- Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
- Copy_buffer = CURRENT->buffer;
- Copy_Sector = CURRENT->sector << 1;
-
- DBG("mfm_request: block after offset=%d\n", block);
-
- issue_request(block, nsect, CURRENT);
-
- break;
- }
- DBG("mfm_request: Dropping out bottom\n");
-}
-
-static void do_mfm_request(request_queue_t *q)
-{
- DBG("do_mfm_request: about to mfm_request\n");
- mfm_request();
-}
-
-static void mfm_interrupt_handler(int unused, void *dev_id)
-{
- void (*handler) (void) = do_mfm;
-
- do_mfm = NULL;
-
- DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
-
- mfm_status = inw(MFM_STATUS);
-
- /* If CPR (Command Parameter Reject) and not busy it means that the command
- has some return message to give us */
- if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
- int len = 0;
- while (len < 16) {
- int in;
- in = inw(MFM_DATAIN);
- result[len++] = in >> 8;
- result[len++] = in;
- }
- }
- if (handler) {
- handler();
- return;
- }
- outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
- printk ("mfm: unexpected interrupt - status = ");
- print_status ();
- while (1);
-}
-
-
-
-
-
-/*
- * Tell the user about the drive if we decided it exists.
- */
-static void mfm_geometry(int drive)
-{
- struct mfm_info *p = mfm_info + drive;
- struct gendisk *disk = mfm_gendisk[drive];
- disk->private_data = p;
- if (p->cylinders)
- printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",
- disk->disk_name,
- p->cylinders * p->heads * p->sectors / 4096,
- p->cylinders, p->heads, p->sectors,
- p->lowcurrent, p->precomp);
- set_capacity(disk, p->cylinders * p->heads * p->sectors / 2);
-}
-
-#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
-/*
- * Attempt to detect a drive and find its geometry. The drive has already been
- * specified...
- *
- * We first recalibrate the disk, then try to probe sectors, heads and then
- * cylinders. NOTE! the cylinder probe may break drives. The xd disk driver
- * does something along these lines, so I assume that most drives are up to
- * this mistreatment...
- */
-static int mfm_detectdrive (int drive)
-{
- unsigned int mingeo[3], maxgeo[3];
- unsigned int attribute, need_recal = 1;
- unsigned char cmdb[8];
-
- memset (mingeo, 0, sizeof (mingeo));
- maxgeo[0] = mfm_info[drive].sectors;
- maxgeo[1] = mfm_info[drive].heads;
- maxgeo[2] = mfm_info[drive].cylinders;
-
- cmdb[0] = drive + 1;
- cmdb[6] = 0;
- cmdb[7] = 1;
- for (attribute = 0; attribute < 3; attribute++) {
- while (mingeo[attribute] != maxgeo[attribute]) {
- unsigned int variable;
-
- variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
- cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
-
- if (need_recal) {
- int tries = 5;
-
- do {
- issue_command (CMD_RCLB, cmdb, 2);
- wait_for_completion ();
- wait_for_command_end ();
- if (result[1] == 0x20)
- break;
- } while (result[1] && --tries);
- if (result[1]) {
- outw (CMD_RCAL, MFM_COMMAND);
- return 0;
- }
- need_recal = 0;
- }
-
- switch (attribute) {
- case 0:
- cmdb[5] = variable;
- issue_command (CMD_CMPD, cmdb, 8);
- break;
- case 1:
- cmdb[1] = variable;
- cmdb[4] = variable;
- issue_command (CMD_CMPD, cmdb, 8);
- break;
- case 2:
- cmdb[2] = variable >> 8;
- cmdb[3] = variable;
- issue_command (CMD_SEK, cmdb, 4);
- break;
- }
- wait_for_completion ();
- wait_for_command_end ();
-
- switch (result[1]) {
- case 0x00:
- case 0x50:
- mingeo[attribute] = variable + 1;
- break;
-
- case 0x20:
- outw (CMD_RCAL, MFM_COMMAND);
- return 0;
-
- case 0x24:
- need_recal = 1;
- default:
- maxgeo[attribute] = variable;
- break;
- }
- }
- }
- mfm_info[drive].cylinders = mingeo[2];
- mfm_info[drive].lowcurrent = mingeo[2];
- mfm_info[drive].precomp = mingeo[2] / 2;
- mfm_info[drive].heads = mingeo[1];
- mfm_info[drive].sectors = mingeo[0];
- outw (CMD_RCAL, MFM_COMMAND);
- return 1;
-}
-#endif
-
-/*
- * Initialise all drive information for this controller.
- */
-static int mfm_initdrives(void)
-{
- int drive;
-
- if (number_mfm_drives > MFM_MAXDRIVES) {
- number_mfm_drives = MFM_MAXDRIVES;
- printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
- }
-
- for (drive = 0; drive < number_mfm_drives; drive++) {
- mfm_info[drive].lowcurrent = 1;
- mfm_info[drive].precomp = 1;
- mfm_info[drive].cylinder = -1;
- mfm_info[drive].errors.recal = 0;
- mfm_info[drive].errors.report = 0;
- mfm_info[drive].errors.abort = 4;
-
-#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
- mfm_info[drive].cylinders = 1024;
- mfm_info[drive].heads = 8;
- mfm_info[drive].sectors = 64;
- {
- unsigned char cmdb[16];
-
- mfm_setupspecify (drive, cmdb);
- cmdb[1] &= ~0x81;
- issue_command (CMD_SPC, cmdb, 16);
- wait_for_completion ();
- if (!mfm_detectdrive (drive)) {
- mfm_info[drive].cylinders = 0;
- mfm_info[drive].heads = 0;
- mfm_info[drive].sectors = 0;
- }
- cmdb[0] = cmdb[1] = 0;
- issue_command (CMD_CKV, cmdb, 2);
- }
-#else
- mfm_info[drive].cylinders = 1; /* its going to have to figure it out from the partition info */
- mfm_info[drive].heads = 4;
- mfm_info[drive].sectors = 32;
-#endif
- }
- return number_mfm_drives;
-}
-
-
-
-/*
- * The 'front' end of the mfm driver follows...
- */
-
-static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct mfm_info *p = bdev->bd_disk->private_data;
-
- geo->heads = p->heads;
- geo->sectors = p->sectors;
- geo->cylinders = p->cylinders;
- return 0;
-}
-
-/*
- * This is to handle various kernel command line parameters
- * specific to this driver.
- */
-void mfm_setup(char *str, int *ints)
-{
- return;
-}
-
-/*
- * Set the CHS from the ADFS boot block if it is present. This is not ideal
- * since if there are any non-ADFS partitions on the disk, this won't work!
- * Hence, I want to get rid of this...
- */
-void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
- unsigned char heads, unsigned int secsize)
-{
- struct mfm_info *p = bdev->bd_disk->private_data;
- int drive = p - mfm_info;
- unsigned long disksize = bdev->bd_inode->i_size;
-
- if (p->cylinders == 1) {
- p->sectors = secsptrack;
- p->heads = heads;
- p->cylinders = discsize / (secsptrack * heads * secsize);
-
- if ((heads < 1) || (p->cylinders > 1024)) {
- printk("%s: Insane disc shape! Setting to 512/4/32\n",
- bdev->bd_disk->disk_name);
-
- /* These values are fairly arbitary, but are there so that if your
- * lucky you can pick apart your disc to find out what is going on -
- * I reckon these figures won't hurt MOST drives
- */
- p->sectors = 32;
- p->heads = 4;
- p->cylinders = 512;
- }
- if (raw_cmd.dev == drive)
- mfm_specify ();
- mfm_geometry (drive);
- }
-}
-
-static struct block_device_operations mfm_fops =
-{
- .owner = THIS_MODULE,
- .getgeo = mfm_getgeo,
-};
-
-/*
- * See if there is a controller at the address presently at mfm_addr
- *
- * We check to see if the controller is busy - if it is, we abort it first,
- * and check that the chip is no longer busy after at least 180 clock cycles.
- * We then issue a command and check that the BSY or CPR bits are set.
- */
-static int mfm_probecontroller (unsigned int mfm_addr)
-{
- if (inw (MFM_STATUS) & STAT_BSY) {
- outw (CMD_ABT, MFM_COMMAND);
- udelay (50);
- if (inw (MFM_STATUS) & STAT_BSY)
- return 0;
- }
-
- if (inw (MFM_STATUS) & STAT_CED)
- outw (CMD_RCAL, MFM_COMMAND);
-
- outw (CMD_SEK, MFM_COMMAND);
-
- if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
- unsigned int count = 2000;
- while (inw (MFM_STATUS) & STAT_BSY) {
- udelay (500);
- if (!--count)
- return 0;
- }
-
- outw (CMD_RCAL, MFM_COMMAND);
- }
- return 1;
-}
-
-static int mfm_do_init(unsigned char irqmask)
-{
- int i, ret;
-
- printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
-
- ret = -EBUSY;
- if (!request_region (mfm_addr, 10, "mfm"))
- goto out1;
-
- ret = register_blkdev(MAJOR_NR, "mfm");
- if (ret)
- goto out2;
-
- /* Stuff for the assembler routines to get to */
- hdc63463_baseaddress = ioaddr(mfm_addr);
- hdc63463_irqpolladdress = mfm_IRQPollLoc;
- hdc63463_irqpollmask = irqmask;
-
- mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock);
- if (!mfm_queue)
- goto out2a;
-
- Busy = 0;
- lastspecifieddrive = -1;
-
- mfm_drives = mfm_initdrives();
- if (!mfm_drives) {
- ret = -ENODEV;
- goto out3;
- }
-
- for (i = 0; i < mfm_drives; i++) {
- struct gendisk *disk = alloc_disk(64);
- if (!disk)
- goto Enomem;
- disk->major = MAJOR_NR;
- disk->first_minor = i << 6;
- disk->fops = &mfm_fops;
- sprintf(disk->disk_name, "mfm%c", 'a'+i);
- mfm_gendisk[i] = disk;
- }
-
- printk("mfm: detected %d hard drive%s\n", mfm_drives,
- mfm_drives == 1 ? "" : "s");
- ret = request_irq(mfm_irq, mfm_interrupt_handler, IRQF_DISABLED, "MFM harddisk", NULL);
- if (ret) {
- printk("mfm: unable to get IRQ%d\n", mfm_irq);
- goto out4;
- }
-
- if (mfm_irqenable)
- outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */
-
- for (i = 0; i < mfm_drives; i++) {
- mfm_geometry(i);
- mfm_gendisk[i]->queue = mfm_queue;
- add_disk(mfm_gendisk[i]);
- }
- return 0;
-
-out4:
- for (i = 0; i < mfm_drives; i++)
- put_disk(mfm_gendisk[i]);
-out3:
- blk_cleanup_queue(mfm_queue);
-out2a:
- unregister_blkdev(MAJOR_NR, "mfm");
-out2:
- release_region(mfm_addr, 10);
-out1:
- return ret;
-Enomem:
- while (i--)
- put_disk(mfm_gendisk[i]);
- goto out3;
-}
-
-static void mfm_do_exit(void)
-{
- int i;
-
- free_irq(mfm_irq, NULL);
- for (i = 0; i < mfm_drives; i++) {
- del_gendisk(mfm_gendisk[i]);
- put_disk(mfm_gendisk[i]);
- }
- blk_cleanup_queue(mfm_queue);
- unregister_blkdev(MAJOR_NR, "mfm");
- if (mfm_addr)
- release_region(mfm_addr, 10);
-}
-
-static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id)
-{
- if (mfm_addr)
- return -EBUSY;
-
- mfm_addr = ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800;
- mfm_IRQPollLoc = ioaddr(mfm_addr + 0x400);
- mfm_irqenable = mfm_IRQPollLoc;
- mfm_irq = ec->irq;
-
- return mfm_do_init(0x08);
-}
-
-static void __devexit mfm_remove(struct expansion_card *ec)
-{
- outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */
- mfm_do_exit();
-}
-
-static const struct ecard_id mfm_cids[] = {
- { MANU_ACORN, PROD_ACORN_MFM },
- { 0xffff, 0xffff },
-};
-
-static struct ecard_driver mfm_driver = {
- .probe = mfm_probe,
- .remove = __devexit(mfm_remove),
- .id_table = mfm_cids,
- .drv = {
- .name = "mfm",
- },
-};
-
-/*
- * Look for a MFM controller - first check the motherboard, then the podules
- * The podules have an extra interrupt enable that needs to be played with
- *
- * The HDC is accessed at MEDIUM IOC speeds.
- */
-static int __init mfm_init (void)
-{
- unsigned char irqmask;
-
- if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
- mfm_addr = ONBOARD_MFM_ADDRESS;
- mfm_IRQPollLoc = IOC_IRQSTATB;
- mfm_irqenable = 0;
- mfm_irq = IRQ_HARDDISK;
- return mfm_do_init(0x08); /* IL3 pin */
- } else {
- return ecard_register_driver(&mfm_driver);
- }
-}
-
-static void __exit mfm_exit(void)
-{
- if (mfm_addr == ONBOARD_MFM_ADDRESS)
- mfm_do_exit();
- else
- ecard_unregister_driver(&mfm_driver);
-}
-
-module_init(mfm_init)
-module_exit(mfm_exit)
-MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 139f41f033d8..4875f0149eb4 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -2,16 +2,12 @@
# ACPI Configuration
#
-menu "ACPI (Advanced Configuration and Power Interface) Support"
+menuconfig ACPI
+ bool "ACPI Support (Advanced Configuration and Power Interface) Support"
depends on !X86_NUMAQ
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
- depends on PM
-
-config ACPI
- bool "ACPI Support"
- depends on IA64 || X86
depends on PCI
depends on PM
select PNP
@@ -47,52 +43,48 @@ config ACPI
if ACPI
config ACPI_SLEEP
- bool "Sleep States"
- depends on X86 && (!SMP || SUSPEND_SMP)
- depends on PM
- default y
- ---help---
- This option adds support for ACPI suspend states.
-
- With this option, you will be able to put the system "to sleep".
- Sleep states are low power states for the system and devices. All
- of the system operating state is saved to either memory or disk
- (depending on the state), to allow the system to resume operation
- quickly at your request.
-
- Although this option sounds really nifty, barely any of the device
- drivers have been converted to the new driver model and hence few
- have proper power management support.
-
- This option is not recommended for anyone except those doing driver
- power management development.
-
-config ACPI_SLEEP_PROC_FS
bool
- depends on ACPI_SLEEP && PROC_FS
+ depends on PM_SLEEP
default y
-config ACPI_SLEEP_PROC_SLEEP
- bool "/proc/acpi/sleep (deprecated)"
- depends on ACPI_SLEEP_PROC_FS
- default n
- ---help---
- Create /proc/acpi/sleep
- Deprecated by /sys/power/state
-
config ACPI_PROCFS
- bool "Procfs interface (deprecated)"
- depends on ACPI
+ bool "Deprecated /proc/acpi files"
+ depends on PROC_FS
+ ---help---
+ For backwards compatibility, this option allows
+ depricated /proc/acpi/ files to exist, even when
+ they have been replaced by functions in /sys.
+ The deprecated files (and their replacements) include:
+
+ /proc/acpi/sleep (/sys/power/state)
+ /proc/acpi/info (/sys/modules/acpi/parameters/acpica_version)
+ /proc/acpi/dsdt (/sys/firmware/acpi/tables/DSDT)
+ /proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
+ /proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
+ /proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
+
+ This option has no effect on /proc/acpi/ files
+ and functions which do not yet exist in /sys.
+
+ Say N to delete /proc/acpi/ files that have moved to /sys/
+
+config ACPI_PROC_EVENT
+ bool "Deprecated /proc/acpi/event support"
+ depends on PROC_FS
default y
---help---
- The Procfs interface for ACPI is made optional for backward compatibility.
- As the same functions are duplicated in the sysfs interface
- and this proc interface will be removed some time later,
- it's marked as deprecated.
- ( /proc/acpi/debug_layer && debug_level are deprecated by
- /sys/module/acpi/parameters/debug_layer && debug_level.
- /proc/acpi/info is deprecated by
- /sys/module/acpi/parameters/acpica_version )
+ A user-space daemon, acpi, typically read /proc/acpi/event
+ and handled all ACPI sub-system generated events.
+
+ These events are now delivered to user-space via
+ either the input layer, or as netlink events.
+
+ This build option enables the old code for legacy
+ user-space implementation. After some time, this will
+ be moved under CONFIG_ACPI_PROCFS, and then deleted.
+
+ Say Y here to retain the old behaviour. Say N if your
+ user-space is newer than kernel 2.6.23 (September 2007).
config ACPI_AC
tristate "AC Adapter"
@@ -124,7 +116,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86 && BACKLIGHT_CLASS_DEVICE
+ depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -280,6 +272,14 @@ config ACPI_DEBUG
of verbosity. Saying Y enables these statements. This will increase
your kernel size by around 50K.
+config ACPI_DEBUG_FUNC_TRACE
+ bool "Additionally enable ACPI function tracing"
+ default n
+ depends on ACPI_DEBUG
+ help
+ ACPI Debug Statements slow down ACPI processing. Function trace
+ is about half of the penalty and is rarely useful.
+
config ACPI_EC
bool
default y
@@ -330,7 +330,6 @@ config ACPI_CONTAINER
config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug"
- depends on ACPI
depends on MEMORY_HOTPLUG
default n
help
@@ -359,5 +358,3 @@ config ACPI_SBS
to today's ACPI "Control Method" battery.
endif # ACPI
-
-endmenu
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 37c7dc4f9fe5..26d70702b313 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -34,7 +34,6 @@
#define ACPI_AC_COMPONENT 0x00020000
#define ACPI_AC_CLASS "ac_adapter"
-#define ACPI_AC_HID "ACPI0003"
#define ACPI_AC_DEVICE_NAME "AC Adapter"
#define ACPI_AC_FILE_STATE "state"
#define ACPI_AC_NOTIFY_STATUS 0x80
@@ -56,10 +55,16 @@ static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type);
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
+const static struct acpi_device_id ac_device_ids[] = {
+ {"ACPI0003", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, ac_device_ids);
+
static struct acpi_driver acpi_ac_driver = {
.name = "ac",
.class = ACPI_AC_CLASS,
- .ids = ACPI_AC_HID,
+ .ids = ac_device_ids,
.ops = {
.add = acpi_ac_add,
.remove = acpi_ac_remove,
@@ -199,7 +204,10 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_ac_get_state(ac);
- acpi_bus_generate_event(device, event, (u32) ac->state);
+ acpi_bus_generate_proc_event(device, event, (u32) ac->state);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event,
+ (u32) ac->state);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index e65628a03085..5f1127ad5a95 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -53,10 +53,16 @@ static int acpi_memory_device_add(struct acpi_device *device);
static int acpi_memory_device_remove(struct acpi_device *device, int type);
static int acpi_memory_device_start(struct acpi_device *device);
+static const struct acpi_device_id memory_device_ids[] = {
+ {ACPI_MEMORY_DEVICE_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, memory_device_ids);
+
static struct acpi_driver acpi_memory_device_driver = {
.name = "acpi_memhotplug",
.class = ACPI_MEMORY_DEVICE_CLASS,
- .ids = ACPI_MEMORY_DEVICE_HID,
+ .ids = memory_device_ids,
.ops = {
.add = acpi_memory_device_add,
.remove = acpi_memory_device_remove,
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 3cd79caad70c..d915fec9bf63 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -56,7 +56,6 @@
#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver"
#define ACPI_HOTK_CLASS "hotkey"
#define ACPI_HOTK_DEVICE_NAME "Hotkey"
-#define ACPI_HOTK_HID "ATK0100"
/*
* Some events we use, same for all Asus
@@ -426,14 +425,20 @@ static struct acpi_table_header *asus_info;
static struct asus_hotk *hotk;
/*
- * The hotkey driver declaration
+ * The hotkey driver and autoloading declaration
*/
static int asus_hotk_add(struct acpi_device *device);
static int asus_hotk_remove(struct acpi_device *device, int type);
+static const struct acpi_device_id asus_device_ids[] = {
+ {"ATK0100", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+
static struct acpi_driver asus_hotk_driver = {
.name = "asus_acpi",
.class = ACPI_HOTK_CLASS,
- .ids = ACPI_HOTK_HID,
+ .ids = asus_device_ids,
.ops = {
.add = asus_hotk_add,
.remove = asus_hotk_remove,
@@ -1064,7 +1069,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
hotk->brightness = (event & ~((u32) BR_DOWN));
}
- acpi_bus_generate_event(hotk->device, event,
+ acpi_bus_generate_proc_event(hotk->device, event,
hotk->event_count[event % 128]++);
return;
@@ -1187,6 +1192,7 @@ static int asus_hotk_get_info(void)
break;
default:
kfree(model);
+ model = NULL;
break;
}
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index e64c76c8b726..9b2c0f74f869 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -41,23 +41,31 @@
#define ACPI_BATTERY_COMPONENT 0x00040000
#define ACPI_BATTERY_CLASS "battery"
-#define ACPI_BATTERY_HID "PNP0C0A"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
-#define ACPI_BATTERY_FILE_INFO "info"
-#define ACPI_BATTERY_FILE_STATUS "state"
-#define ACPI_BATTERY_FILE_ALARM "alarm"
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
#define ACPI_BATTERY_NOTIFY_INFO 0x81
#define ACPI_BATTERY_UNITS_WATTS "mW"
#define ACPI_BATTERY_UNITS_AMPS "mA"
#define _COMPONENT ACPI_BATTERY_COMPONENT
+
+#define ACPI_BATTERY_UPDATE_TIME 0
+
+#define ACPI_BATTERY_NONE_UPDATE 0
+#define ACPI_BATTERY_EASY_UPDATE 1
+#define ACPI_BATTERY_INIT_UPDATE 2
+
ACPI_MODULE_NAME("battery");
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
+static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
+
+/* 0 - every time, > 0 - by update_time */
+module_param(update_time, uint, 0644);
+
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
@@ -65,10 +73,16 @@ static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
static int acpi_battery_resume(struct acpi_device *device);
+static const struct acpi_device_id battery_device_ids[] = {
+ {"PNP0C0A", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, battery_device_ids);
+
static struct acpi_driver acpi_battery_driver = {
.name = "battery",
.class = ACPI_BATTERY_CLASS,
- .ids = ACPI_BATTERY_HID,
+ .ids = battery_device_ids,
.ops = {
.add = acpi_battery_add,
.resume = acpi_battery_resume,
@@ -76,7 +90,7 @@ static struct acpi_driver acpi_battery_driver = {
},
};
-struct acpi_battery_status {
+struct acpi_battery_state {
acpi_integer state;
acpi_integer present_rate;
acpi_integer remaining_capacity;
@@ -99,33 +113,111 @@ struct acpi_battery_info {
acpi_string oem_info;
};
-struct acpi_battery_flags {
- u8 present:1; /* Bay occupied? */
- u8 power_unit:1; /* 0=watts, 1=apms */
- u8 alarm:1; /* _BTP present? */
- u8 reserved:5;
+enum acpi_battery_files{
+ ACPI_BATTERY_INFO = 0,
+ ACPI_BATTERY_STATE,
+ ACPI_BATTERY_ALARM,
+ ACPI_BATTERY_NUMFILES,
};
-struct acpi_battery_trips {
- unsigned long warning;
- unsigned long low;
+struct acpi_battery_flags {
+ u8 battery_present_prev;
+ u8 alarm_present;
+ u8 init_update;
+ u8 update[ACPI_BATTERY_NUMFILES];
+ u8 power_unit;
};
struct acpi_battery {
- struct acpi_device * device;
+ struct mutex mutex;
+ struct acpi_device *device;
struct acpi_battery_flags flags;
- struct acpi_battery_trips trips;
+ struct acpi_buffer bif_data;
+ struct acpi_buffer bst_data;
unsigned long alarm;
- struct acpi_battery_info *info;
+ unsigned long update_time[ACPI_BATTERY_NUMFILES];
};
+inline int acpi_battery_present(struct acpi_battery *battery)
+{
+ return battery->device->status.battery_present;
+}
+inline char *acpi_battery_power_units(struct acpi_battery *battery)
+{
+ if (battery->flags.power_unit)
+ return ACPI_BATTERY_UNITS_AMPS;
+ else
+ return ACPI_BATTERY_UNITS_WATTS;
+}
+
+inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
+{
+ return battery->device->handle;
+}
+
/* --------------------------------------------------------------------------
Battery Management
-------------------------------------------------------------------------- */
-static int
-acpi_battery_get_info(struct acpi_battery *battery,
- struct acpi_battery_info **bif)
+static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+{
+ if (!battery)
+ return;
+
+ if (result) {
+ battery->flags.init_update = 1;
+ }
+}
+
+static int acpi_battery_extract_package(struct acpi_battery *battery,
+ union acpi_object *package,
+ struct acpi_buffer *format,
+ struct acpi_buffer *data,
+ char *package_name)
+{
+ acpi_status status = AE_OK;
+ struct acpi_buffer data_null = { 0, NULL };
+
+ status = acpi_extract_package(package, format, &data_null);
+ if (status != AE_BUFFER_OVERFLOW) {
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
+ package_name));
+ return -ENODEV;
+ }
+
+ if (data_null.length != data->length) {
+ kfree(data->pointer);
+ data->pointer = kzalloc(data_null.length, GFP_KERNEL);
+ if (!data->pointer) {
+ ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
+ return -ENOMEM;
+ }
+ data->length = data_null.length;
+ }
+
+ status = acpi_extract_package(package, format, data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
+ package_name));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int acpi_battery_get_status(struct acpi_battery *battery)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(battery->device);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
+ return -ENODEV;
+ }
+ return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = 0;
@@ -133,16 +225,20 @@ acpi_battery_get_info(struct acpi_battery *battery,
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
ACPI_BATTERY_FORMAT_BIF
};
- struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
+ struct acpi_buffer *data = NULL;
+ struct acpi_battery_info *bif = NULL;
+ battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
- if (!battery || !bif)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return 0;
- /* Evalute _BIF */
+ /* Evaluate _BIF */
- status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
return -ENODEV;
@@ -150,41 +246,29 @@ acpi_battery_get_info(struct acpi_battery *battery,
package = buffer.pointer;
- /* Extract Package Data */
-
- status = acpi_extract_package(package, &format, &data);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
- result = -ENODEV;
- goto end;
- }
+ data = &battery->bif_data;
- data.pointer = kzalloc(data.length, GFP_KERNEL);
- if (!data.pointer) {
- result = -ENOMEM;
- goto end;
- }
+ /* Extract Package Data */
- status = acpi_extract_package(package, &format, &data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
- kfree(data.pointer);
- result = -ENODEV;
+ result =
+ acpi_battery_extract_package(battery, package, &format, data,
+ "_BIF");
+ if (result)
goto end;
- }
end:
+
kfree(buffer.pointer);
- if (!result)
- (*bif) = data.pointer;
+ if (!result) {
+ bif = data->pointer;
+ battery->flags.power_unit = bif->power_unit;
+ }
return result;
}
-static int
-acpi_battery_get_status(struct acpi_battery *battery,
- struct acpi_battery_status **bst)
+static int acpi_battery_get_state(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = 0;
@@ -192,16 +276,19 @@ acpi_battery_get_status(struct acpi_battery *battery,
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
ACPI_BATTERY_FORMAT_BST
};
- struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
+ struct acpi_buffer *data = NULL;
+ battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
- if (!battery || !bst)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return 0;
- /* Evalute _BST */
+ /* Evaluate _BST */
- status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
return -ENODEV;
@@ -209,55 +296,49 @@ acpi_battery_get_status(struct acpi_battery *battery,
package = buffer.pointer;
- /* Extract Package Data */
+ data = &battery->bst_data;
- status = acpi_extract_package(package, &format, &data);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
- result = -ENODEV;
- goto end;
- }
-
- data.pointer = kzalloc(data.length, GFP_KERNEL);
- if (!data.pointer) {
- result = -ENOMEM;
- goto end;
- }
+ /* Extract Package Data */
- status = acpi_extract_package(package, &format, &data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
- kfree(data.pointer);
- result = -ENODEV;
+ result =
+ acpi_battery_extract_package(battery, package, &format, data,
+ "_BST");
+ if (result)
goto end;
- }
end:
kfree(buffer.pointer);
- if (!result)
- (*bst) = data.pointer;
-
return result;
}
-static int
-acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+ battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
+
+ return 0;
+}
+
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+ unsigned long alarm)
{
acpi_status status = 0;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list arg_list = { 1, &arg0 };
+ battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
- if (!battery)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return -ENODEV;
- if (!battery->flags.alarm)
+ if (!battery->flags.alarm_present)
return -ENODEV;
arg0.integer.value = alarm;
- status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+ &arg_list, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -268,65 +349,114 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
return 0;
}
-static int acpi_battery_check(struct acpi_battery *battery)
+static int acpi_battery_init_alarm(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = AE_OK;
acpi_handle handle = NULL;
- struct acpi_device *device = NULL;
- struct acpi_battery_info *bif = NULL;
-
+ struct acpi_battery_info *bif = battery->bif_data.pointer;
+ unsigned long alarm = battery->alarm;
- if (!battery)
- return -EINVAL;
+ /* See if alarms are supported, and if so, set default */
- device = battery->device;
+ status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
+ if (ACPI_SUCCESS(status)) {
+ battery->flags.alarm_present = 1;
+ if (!alarm && bif) {
+ alarm = bif->design_capacity_warning;
+ }
+ result = acpi_battery_set_alarm(battery, alarm);
+ if (result)
+ goto end;
+ } else {
+ battery->flags.alarm_present = 0;
+ }
- result = acpi_bus_get_status(device);
- if (result)
- return result;
+ end:
- /* Insertion? */
+ return result;
+}
- if (!battery->flags.present && device->status.battery_present) {
+static int acpi_battery_init_update(struct acpi_battery *battery)
+{
+ int result = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
+ result = acpi_battery_get_status(battery);
+ if (result)
+ return result;
- /* Evalute _BIF to get certain static information */
+ battery->flags.battery_present_prev = acpi_battery_present(battery);
- result = acpi_battery_get_info(battery, &bif);
+ if (acpi_battery_present(battery)) {
+ result = acpi_battery_get_info(battery);
+ if (result)
+ return result;
+ result = acpi_battery_get_state(battery);
if (result)
return result;
- battery->flags.power_unit = bif->power_unit;
- battery->trips.warning = bif->design_capacity_warning;
- battery->trips.low = bif->design_capacity_low;
- kfree(bif);
+ acpi_battery_init_alarm(battery);
+ }
+
+ return result;
+}
- /* See if alarms are supported, and if so, set default */
+static int acpi_battery_update(struct acpi_battery *battery,
+ int update, int *update_result_ptr)
+{
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
- status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
- if (ACPI_SUCCESS(status)) {
- battery->flags.alarm = 1;
- acpi_battery_set_alarm(battery, battery->trips.warning);
+ if (!acpi_battery_present(battery)) {
+ update = 1;
+ }
+
+ if (battery->flags.init_update) {
+ result = acpi_battery_init_update(battery);
+ if (result)
+ goto end;
+ update_result = ACPI_BATTERY_INIT_UPDATE;
+ } else if (update) {
+ result = acpi_battery_get_status(battery);
+ if (result)
+ goto end;
+ if ((!battery->flags.battery_present_prev & acpi_battery_present(battery))
+ || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) {
+ result = acpi_battery_init_update(battery);
+ if (result)
+ goto end;
+ update_result = ACPI_BATTERY_INIT_UPDATE;
+ } else {
+ update_result = ACPI_BATTERY_EASY_UPDATE;
}
}
- /* Removal? */
+ end:
- else if (battery->flags.present && !device->status.battery_present) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
- }
+ battery->flags.init_update = (result != 0);
- battery->flags.present = device->status.battery_present;
+ *update_result_ptr = update_result;
return result;
}
-static void acpi_battery_check_present(struct acpi_battery *battery)
+static void acpi_battery_notify_update(struct acpi_battery *battery)
{
- if (!battery->flags.present) {
- acpi_battery_check(battery);
+ acpi_battery_get_status(battery);
+
+ if (battery->flags.init_update) {
+ return;
+ }
+
+ if ((!battery->flags.battery_present_prev &
+ acpi_battery_present(battery)) ||
+ (battery->flags.battery_present_prev &
+ !acpi_battery_present(battery))) {
+ battery->flags.init_update = 1;
+ } else {
+ battery->flags.update[ACPI_BATTERY_INFO] = 1;
+ battery->flags.update[ACPI_BATTERY_STATE] = 1;
+ battery->flags.update[ACPI_BATTERY_ALARM] = 1;
}
}
@@ -335,37 +465,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery)
-------------------------------------------------------------------------- */
static struct proc_dir_entry *acpi_battery_dir;
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+
+static int acpi_battery_print_info(struct seq_file *seq, int result)
{
- int result = 0;
struct acpi_battery *battery = seq->private;
struct acpi_battery_info *bif = NULL;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (battery->flags.present)
+ if (acpi_battery_present(battery))
seq_printf(seq, "present: yes\n");
else {
seq_printf(seq, "present: no\n");
goto end;
}
- /* Battery Info (_BIF) */
-
- result = acpi_battery_get_info(battery, &bif);
- if (result || !bif) {
- seq_printf(seq, "ERROR: Unable to read battery information\n");
+ bif = battery->bif_data.pointer;
+ if (!bif) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
+ result = -ENODEV;
goto end;
}
- units =
- bif->
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+ /* Battery Units */
+
+ units = acpi_battery_power_units(battery);
if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "design capacity: unknown\n");
@@ -396,7 +522,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
else
seq_printf(seq, "design voltage: %d mV\n",
(u32) bif->design_voltage);
-
seq_printf(seq, "design capacity warning: %d %sh\n",
(u32) bif->design_capacity_warning, units);
seq_printf(seq, "design capacity low: %d %sh\n",
@@ -411,50 +536,40 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
seq_printf(seq, "OEM info: %s\n", bif->oem_info);
end:
- kfree(bif);
- return 0;
-}
+ if (result)
+ seq_printf(seq, "ERROR: Unable to read battery info\n");
-static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+ return result;
}
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+static int acpi_battery_print_state(struct seq_file *seq, int result)
{
- int result = 0;
struct acpi_battery *battery = seq->private;
- struct acpi_battery_status *bst = NULL;
+ struct acpi_battery_state *bst = NULL;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (battery->flags.present)
+ if (acpi_battery_present(battery))
seq_printf(seq, "present: yes\n");
else {
seq_printf(seq, "present: no\n");
goto end;
}
- /* Battery Units */
-
- units =
- battery->flags.
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
- /* Battery Status (_BST) */
-
- result = acpi_battery_get_status(battery, &bst);
- if (result || !bst) {
- seq_printf(seq, "ERROR: Unable to read battery status\n");
+ bst = battery->bst_data.pointer;
+ if (!bst) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
+ result = -ENODEV;
goto end;
}
+ /* Battery Units */
+
+ units = acpi_battery_power_units(battery);
+
if (!(bst->state & 0x04))
seq_printf(seq, "capacity state: ok\n");
else
@@ -490,48 +605,43 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
(u32) bst->present_voltage);
end:
- kfree(bst);
- return 0;
-}
+ if (result) {
+ seq_printf(seq, "ERROR: Unable to read battery state\n");
+ }
-static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_state, PDE(inode)->data);
+ return result;
}
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+static int acpi_battery_print_alarm(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (!battery->flags.present) {
+ if (!acpi_battery_present(battery)) {
seq_printf(seq, "present: no\n");
goto end;
}
/* Battery Units */
- units =
- battery->flags.
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
- /* Battery Alarm */
+ units = acpi_battery_power_units(battery);
seq_printf(seq, "alarm: ");
if (!battery->alarm)
seq_printf(seq, "unsupported\n");
else
- seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+ seq_printf(seq, "%lu %sh\n", battery->alarm, units);
end:
- return 0;
+
+ if (result)
+ seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+
+ return result;
}
static ssize_t
@@ -543,27 +653,113 @@ acpi_battery_write_alarm(struct file *file,
char alarm_string[12] = { '\0' };
struct seq_file *m = file->private_data;
struct acpi_battery *battery = m->private;
-
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
- acpi_battery_check_present(battery);
+ mutex_lock(&battery->mutex);
- if (!battery->flags.present)
- return -ENODEV;
+ result = acpi_battery_update(battery, 1, &update_result);
+ if (result) {
+ result = -ENODEV;
+ goto end;
+ }
- if (copy_from_user(alarm_string, buffer, count))
- return -EFAULT;
+ if (!acpi_battery_present(battery)) {
+ result = -ENODEV;
+ goto end;
+ }
+
+ if (copy_from_user(alarm_string, buffer, count)) {
+ result = -EFAULT;
+ goto end;
+ }
alarm_string[count] = '\0';
result = acpi_battery_set_alarm(battery,
simple_strtoul(alarm_string, NULL, 0));
if (result)
- return result;
+ goto end;
+
+ end:
+
+ acpi_battery_check_result(battery, result);
+
+ if (!result)
+ result = count;
+
+ mutex_unlock(&battery->mutex);
+
+ return result;
+}
+
+typedef int(*print_func)(struct seq_file *seq, int result);
+typedef int(*get_func)(struct acpi_battery *battery);
+
+static struct acpi_read_mux {
+ print_func print;
+ get_func get;
+} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
+ {.get = acpi_battery_get_info, .print = acpi_battery_print_info},
+ {.get = acpi_battery_get_state, .print = acpi_battery_print_state},
+ {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
+};
+
+static int acpi_battery_read(int fid, struct seq_file *seq)
+{
+ struct acpi_battery *battery = seq->private;
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
+ int update = 0;
+
+ mutex_lock(&battery->mutex);
+
+ update = (get_seconds() - battery->update_time[fid] >= update_time);
+ update = (update | battery->flags.update[fid]);
+
+ result = acpi_battery_update(battery, update, &update_result);
+ if (result)
+ goto end;
+
+ if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+ result = acpi_read_funcs[fid].get(battery);
+ if (result)
+ goto end;
+ }
+
+ end:
+ result = acpi_read_funcs[fid].print(seq, result);
+ acpi_battery_check_result(battery, result);
+ battery->flags.update[fid] = result;
+ mutex_unlock(&battery->mutex);
+ return result;
+}
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+ return acpi_battery_read(ACPI_BATTERY_INFO, seq);
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+ return acpi_battery_read(ACPI_BATTERY_STATE, seq);
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+ return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
+}
- return count;
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_state, PDE(inode)->data);
}
static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -571,35 +767,51 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
}
-static const struct file_operations acpi_battery_info_ops = {
+static struct battery_file {
+ struct file_operations ops;
+ mode_t mode;
+ char *name;
+} acpi_battery_file[] = {
+ {
+ .name = "info",
+ .mode = S_IRUGO,
+ .ops = {
.open = acpi_battery_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_state_ops = {
+ },
+ },
+ {
+ .name = "state",
+ .mode = S_IRUGO,
+ .ops = {
.open = acpi_battery_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_alarm_ops = {
+ },
+ },
+ {
+ .name = "alarm",
+ .mode = S_IFREG | S_IRUGO | S_IWUSR,
+ .ops = {
.open = acpi_battery_alarm_open_fs,
.read = seq_read,
.write = acpi_battery_write_alarm,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
+ },
+ },
};
static int acpi_battery_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
+ int i;
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -609,38 +821,16 @@ static int acpi_battery_add_fs(struct acpi_device *device)
acpi_device_dir(device)->owner = THIS_MODULE;
}
- /* 'info' [R] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
- if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_info_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
- /* 'status' [R] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
- S_IRUGO, acpi_device_dir(device));
- if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_state_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
- /* 'alarm' [R/W] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
- if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_alarm_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
+ 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));
+ 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;
@@ -648,15 +838,12 @@ static int acpi_battery_add_fs(struct acpi_device *device)
static int acpi_battery_remove_fs(struct acpi_device *device)
{
-
+ int i;
if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
+ for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+ remove_proc_entry(acpi_battery_file[i].name,
acpi_device_dir(device));
- remove_proc_entry(ACPI_BATTERY_FILE_INFO,
- acpi_device_dir(device));
-
+ }
remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
acpi_device_dir(device) = NULL;
}
@@ -673,7 +860,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
struct acpi_battery *battery = data;
struct acpi_device *device = NULL;
-
if (!battery)
return;
@@ -684,8 +870,13 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
case ACPI_BATTERY_NOTIFY_INFO:
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- acpi_battery_check(battery);
- acpi_bus_generate_event(device, event, battery->flags.present);
+ device = battery->device;
+ acpi_battery_notify_update(battery);
+ acpi_bus_generate_proc_event(device, event,
+ acpi_battery_present(battery));
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event,
+ acpi_battery_present(battery));
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -702,7 +893,6 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device)
return -EINVAL;
@@ -710,15 +900,21 @@ static int acpi_battery_add(struct acpi_device *device)
if (!battery)
return -ENOMEM;
+ mutex_init(&battery->mutex);
+
+ mutex_lock(&battery->mutex);
+
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
acpi_driver_data(device) = battery;
- result = acpi_battery_check(battery);
+ result = acpi_battery_get_status(battery);
if (result)
goto end;
+ battery->flags.init_update = 1;
+
result = acpi_battery_add_fs(device);
if (result)
goto end;
@@ -727,6 +923,7 @@ static int acpi_battery_add(struct acpi_device *device)
ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
result = -ENODEV;
goto end;
}
@@ -736,11 +933,14 @@ static int acpi_battery_add(struct acpi_device *device)
device->status.battery_present ? "present" : "absent");
end:
+
if (result) {
acpi_battery_remove_fs(device);
kfree(battery);
}
+ mutex_unlock(&battery->mutex);
+
return result;
}
@@ -749,18 +949,27 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device || !acpi_driver_data(device))
return -EINVAL;
battery = acpi_driver_data(device);
+ mutex_lock(&battery->mutex);
+
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
acpi_battery_remove_fs(device);
+ kfree(battery->bif_data.pointer);
+
+ kfree(battery->bst_data.pointer);
+
+ mutex_unlock(&battery->mutex);
+
+ mutex_destroy(&battery->mutex);
+
kfree(battery);
return 0;
@@ -775,7 +984,10 @@ static int acpi_battery_resume(struct acpi_device *device)
return -EINVAL;
battery = device->driver_data;
- return acpi_battery_check(battery);
+
+ battery->flags.init_update = 1;
+
+ return 0;
}
static int __init acpi_battery_init(void)
@@ -800,7 +1012,6 @@ static int __init acpi_battery_init(void)
static void __exit acpi_battery_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_battery_driver);
acpi_unlock_battery_dir(acpi_battery_dir);
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index fb3f31b5e69f..6daf6088ac88 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id)
new_bay->pdev = pdev;
platform_set_drvdata(pdev, new_bay);
+ /*
+ * we want the bay driver to be able to send uevents
+ */
+ pdev->dev.uevent_suppress = 0;
+
if (acpi_bay_add_fs(new_bay)) {
platform_device_unregister(new_bay->pdev);
goto bay_add_err;
@@ -328,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data)
{
struct bay *bay_dev = (struct bay *)data;
struct device *dev = &bay_dev->pdev->dev;
+ char event_string[12];
+ char *envp[] = { event_string, NULL };
bay_dprintk(handle, "Bay event");
-
- switch(event) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- case ACPI_NOTIFY_EJECT_REQUEST:
- kobject_uevent(&dev->kobj, KOBJ_CHANGE);
- break;
- default:
- printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
- }
+ sprintf(event_string, "BAY_EVENT=%d", event);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
static acpi_status
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index e5084ececb6f..cbfc81579c9a 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->dev.kobj.name));
+ kobject_name(&device->dev.kobj)));
return -ENODEV;
}
/*
@@ -262,10 +262,12 @@ int acpi_bus_set_power(acpi_handle handle, int state)
printk(KERN_WARNING PREFIX
"Transitioning device [%s] to D%d\n",
device->pnp.bus_id, state);
- else
+ else {
+ device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
+ }
return result;
}
@@ -276,6 +278,7 @@ EXPORT_SYMBOL(acpi_bus_set_power);
Event Management
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROC_EVENT
static DEFINE_SPINLOCK(acpi_bus_event_lock);
LIST_HEAD(acpi_bus_event_list);
@@ -283,7 +286,7 @@ DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
extern int event_is_open;
-int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
+int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
{
struct acpi_bus_event *event = NULL;
unsigned long flags = 0;
@@ -314,7 +317,7 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
return 0;
}
-EXPORT_SYMBOL(acpi_bus_generate_event);
+EXPORT_SYMBOL(acpi_bus_generate_proc_event);
int acpi_bus_receive_event(struct acpi_bus_event *event)
{
@@ -360,6 +363,7 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
}
EXPORT_SYMBOL(acpi_bus_receive_event);
+#endif /* CONFIG_ACPI_PROC_EVENT */
/* --------------------------------------------------------------------------
Notification Handling
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index cb4110b50cd0..2e79a3395ecf 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -66,6 +66,16 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Button Driver");
MODULE_LICENSE("GPL");
+static const struct acpi_device_id button_device_ids[] = {
+ {ACPI_BUTTON_HID_LID, 0},
+ {ACPI_BUTTON_HID_SLEEP, 0},
+ {ACPI_BUTTON_HID_SLEEPF, 0},
+ {ACPI_BUTTON_HID_POWER, 0},
+ {ACPI_BUTTON_HID_POWERF, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, button_device_ids);
+
static int acpi_button_add(struct acpi_device *device);
static int acpi_button_remove(struct acpi_device *device, int type);
static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
@@ -74,7 +84,7 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
static struct acpi_driver acpi_button_driver = {
.name = "button",
.class = ACPI_BUTTON_CLASS,
- .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
+ .ids = button_device_ids,
.ops = {
.add = acpi_button_add,
.remove = acpi_button_remove,
@@ -274,7 +284,7 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
}
input_sync(input);
- acpi_bus_generate_event(button->device, event,
+ acpi_bus_generate_proc_event(button->device, event,
++button->pushed);
break;
default:
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0dd3bf7c0ed1..3c25ec7a1871 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -52,10 +52,18 @@ MODULE_LICENSE("GPL");
static int acpi_container_add(struct acpi_device *device);
static int acpi_container_remove(struct acpi_device *device, int type);
+static const struct acpi_device_id container_device_ids[] = {
+ {"ACPI0004", 0},
+ {"PNP0A05", 0},
+ {"PNP0A06", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, container_device_ids);
+
static struct acpi_driver acpi_container_driver = {
.name = "container",
.class = ACPI_CONTAINER_CLASS,
- .ids = "ACPI0004,PNP0A05,PNP0A06",
+ .ids = container_device_ids,
.ops = {
.add = acpi_container_add,
.remove = acpi_container_remove,
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 4546bf873aea..1dabdf4c07b3 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi");
MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
MODULE_LICENSE("GPL");
+static int immediate_undock = 1;
+module_param(immediate_undock, bool, 0644);
+MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
+ "undock immediately when the undock button is pressed, 0 will cause"
+ " the driver to wait for userspace to write the undock sysfs file "
+ " before undocking");
+
static struct atomic_notifier_head dock_notifier_list;
-static struct platform_device dock_device;
+static struct platform_device *dock_device;
static char dock_device_name[] = "dock";
struct dock_station {
@@ -63,6 +70,7 @@ struct dock_dependent_device {
};
#define DOCK_DOCKING 0x00000001
+#define DOCK_UNDOCKING 0x00000002
#define DOCK_EVENT 3
#define UNDOCK_EVENT 2
@@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
static void dock_event(struct dock_station *ds, u32 event, int num)
{
- struct device *dev = &dock_device.dev;
+ struct device *dev = &dock_device->dev;
+ char event_string[13];
+ char *envp[] = { event_string, NULL };
+
+ if (num == UNDOCK_EVENT)
+ sprintf(event_string, "EVENT=undock");
+ else
+ sprintf(event_string, "EVENT=dock");
+
/*
* Indicate that the status of the dock station has
* changed.
*/
- kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
/**
@@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock)
union acpi_object arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
- obj = name_buffer.pointer;
- printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
+ printk(KERN_INFO PREFIX "%s - %s\n",
+ (char *)name_buffer.pointer, dock ? "docking" : "undocking");
/* _DCK method has one argument */
arg_list.count = 1;
@@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock)
arg.integer.value = dock;
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
if (ACPI_FAILURE(status))
- pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
+ printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
+ (char *)name_buffer.pointer);
kfree(buffer.pointer);
kfree(name_buffer.pointer);
}
@@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds)
ds->last_dock_time = jiffies;
}
+static inline void begin_undock(struct dock_station *ds)
+{
+ ds->flags |= DOCK_UNDOCKING;
+}
+
+static inline void complete_undock(struct dock_station *ds)
+{
+ ds->flags &= ~(DOCK_UNDOCKING);
+}
+
/**
* dock_in_progress - see if we are in the middle of handling a dock event
* @ds: the dock station
@@ -550,7 +576,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
printk(KERN_ERR PREFIX "Unable to undock!\n");
return -EBUSY;
}
-
+ complete_undock(ds);
return 0;
}
@@ -594,7 +620,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
* to the driver who wish to hotplug.
*/
case ACPI_NOTIFY_EJECT_REQUEST:
- handle_eject_request(ds, event);
+ begin_undock(ds);
+ if (immediate_undock)
+ handle_eject_request(ds, event);
+ else
+ dock_event(ds, event, UNDOCK_EVENT);
break;
default:
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -653,6 +683,17 @@ static ssize_t show_docked(struct device *dev,
DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
/*
+ * show_flags - read method for flags file in sysfs
+ */
+static ssize_t show_flags(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
+
+}
+DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+
+/*
* write_undock - write method for "undock" file in sysfs
*/
static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
@@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned long lbuf;
- acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
- if(ACPI_FAILURE(status)) {
+ acpi_status status = acpi_evaluate_integer(dock_station->handle,
+ "_UID", NULL, &lbuf);
+ if (ACPI_FAILURE(status))
return 0;
- }
+
return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
}
DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
-
-
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle)
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
/* initialize platform device stuff */
- dock_device.name = dock_device_name;
- ret = platform_device_register(&dock_device);
+ dock_device =
+ platform_device_register_simple(dock_device_name, 0, NULL, 0);
+ if (IS_ERR(dock_device)) {
+ kfree(dock_station);
+ dock_station = NULL;
+ return PTR_ERR(dock_device);
+ }
+
+ /* we want the dock device to send uevents */
+ dock_device->dev.uevent_suppress = 0;
+
+ ret = device_create_file(&dock_device->dev, &dev_attr_docked);
if (ret) {
- printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+ printk("Error %d adding sysfs file\n", ret);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
- ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+ ret = device_create_file(&dock_device->dev, &dev_attr_undock);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
- ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+ ret = device_create_file(&dock_device->dev, &dev_attr_uid);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
- device_remove_file(&dock_device.dev, &dev_attr_docked);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
- ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+ ret = device_create_file(&dock_device->dev, &dev_attr_flags);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ device_remove_file(&dock_device->dev, &dev_attr_uid);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
@@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle)
dd = alloc_dock_dependent_device(handle);
if (!dd) {
kfree(dock_station);
+ dock_station = NULL;
ret = -ENOMEM;
goto dock_add_err_unregister;
}
@@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle)
dock_add_err:
kfree(dd);
dock_add_err_unregister:
- device_remove_file(&dock_device.dev, &dev_attr_docked);
- device_remove_file(&dock_device.dev, &dev_attr_undock);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ device_remove_file(&dock_device->dev, &dev_attr_uid);
+ device_remove_file(&dock_device->dev, &dev_attr_flags);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
@@ -804,12 +868,15 @@ static int dock_remove(void)
printk(KERN_ERR "Error removing notify handler\n");
/* cleanup sysfs */
- device_remove_file(&dock_device.dev, &dev_attr_docked);
- device_remove_file(&dock_device.dev, &dev_attr_undock);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ device_remove_file(&dock_device->dev, &dev_attr_uid);
+ device_remove_file(&dock_device->dev, &dev_attr_flags);
+ platform_device_unregister(dock_device);
/* free dock station memory */
kfree(dock_station);
+ dock_station = NULL;
return 0;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 82f496c07675..3f7935ab0cf5 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,25 +34,25 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
+#include <linux/list.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/actypes.h>
-#define _COMPONENT ACPI_EC_COMPONENT
-ACPI_MODULE_NAME("ec");
-#define ACPI_EC_COMPONENT 0x00100000
#define ACPI_EC_CLASS "embedded_controller"
-#define ACPI_EC_HID "PNP0C09"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
+
#undef PREFIX
#define PREFIX "ACPI: EC: "
+
/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
+
/* EC commands */
enum ec_command {
ACPI_EC_COMMAND_READ = 0x80,
@@ -61,6 +61,7 @@ enum ec_command {
ACPI_EC_BURST_DISABLE = 0x83,
ACPI_EC_COMMAND_QUERY = 0x84,
};
+
/* EC events */
enum ec_event {
ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
@@ -80,10 +81,15 @@ 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 = ACPI_EC_HID,
+ .ids = ec_device_ids,
.ops = {
.add = acpi_ec_add,
.remove = acpi_ec_remove,
@@ -94,6 +100,16 @@ static struct acpi_driver acpi_ec_driver = {
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
+typedef int (*acpi_ec_query_func) (void *data);
+
+struct acpi_ec_query_handler {
+ struct list_head node;
+ acpi_ec_query_func func;
+ acpi_handle handle;
+ void *data;
+ u8 query_bit;
+};
+
static struct acpi_ec {
acpi_handle handle;
unsigned long gpe;
@@ -104,6 +120,7 @@ static struct acpi_ec {
atomic_t query_pending;
atomic_t event_count;
wait_queue_head_t wait;
+ struct list_head list;
} *boot_ec, *first_ec;
/* --------------------------------------------------------------------------
@@ -245,7 +262,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
if (status) {
- printk(KERN_DEBUG PREFIX
+ printk(KERN_ERR PREFIX
"input buffer is not empty, aborting transaction\n");
goto end;
}
@@ -394,21 +411,66 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
+int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
+ acpi_handle handle, acpi_ec_query_func func,
+ void *data)
+{
+ struct acpi_ec_query_handler *handler =
+ kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+ if (!handler)
+ return -ENOMEM;
+
+ handler->query_bit = query_bit;
+ handler->handle = handle;
+ handler->func = func;
+ handler->data = data;
+ mutex_lock(&ec->lock);
+ list_add_tail(&handler->node, &ec->list);
+ mutex_unlock(&ec->lock);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
+
+void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+{
+ struct acpi_ec_query_handler *handler;
+ mutex_lock(&ec->lock);
+ list_for_each_entry(handler, &ec->list, node) {
+ if (query_bit == handler->query_bit) {
+ list_del(&handler->node);
+ kfree(handler);
+ break;
+ }
+ }
+ mutex_unlock(&ec->lock);
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
static void acpi_ec_gpe_query(void *ec_cxt)
{
struct acpi_ec *ec = ec_cxt;
u8 value = 0;
- char object_name[8];
+ struct acpi_ec_query_handler *handler, copy;
if (!ec || acpi_ec_query(ec, &value))
return;
-
- snprintf(object_name, 8, "_Q%2.2X", value);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
-
- acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+ mutex_lock(&ec->lock);
+ list_for_each_entry(handler, &ec->list, node) {
+ if (value == handler->query_bit) {
+ /* have custom handler for this bit */
+ memcpy(&copy, handler, sizeof(copy));
+ mutex_unlock(&ec->lock);
+ if (copy.func) {
+ copy.func(copy.data);
+ } else if (copy.handle) {
+ acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
+ }
+ return;
+ }
+ }
+ mutex_unlock(&ec->lock);
}
static u32 acpi_ec_gpe_handler(void *data)
@@ -427,8 +489,7 @@ static u32 acpi_ec_gpe_handler(void *data)
if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
atomic_set(&ec->query_pending, 1);
status =
- acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
- ec);
+ acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
}
return status == AE_OK ?
@@ -454,57 +515,35 @@ acpi_ec_space_setup(acpi_handle region_handle,
}
static acpi_status
-acpi_ec_space_handler(u32 function,
- acpi_physical_address address,
- u32 bit_width,
- acpi_integer * value,
+acpi_ec_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, acpi_integer *value,
void *handler_context, void *region_context)
{
- int result = 0;
struct acpi_ec *ec = handler_context;
- u64 temp = *value;
- acpi_integer f_v = 0;
- int i = 0;
+ int result = 0, i = 0;
+ u8 temp = 0;
if ((address > 0xFF) || !value || !handler_context)
return AE_BAD_PARAMETER;
- if (bit_width != 8 && acpi_strict) {
+ if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
- }
-
- next_byte:
- switch (function) {
- case ACPI_READ:
- temp = 0;
- result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
- break;
- case ACPI_WRITE:
- result = acpi_ec_write(ec, (u8) address, (u8) temp);
- break;
- default:
- result = -EINVAL;
- goto out;
- break;
- }
- bit_width -= 8;
- if (bit_width) {
- if (function == ACPI_READ)
- f_v |= temp << 8 * i;
- if (function == ACPI_WRITE)
- temp >>= 8;
- i++;
- address++;
- goto next_byte;
- }
+ if (bits != 8 && acpi_strict)
+ return AE_BAD_PARAMETER;
- if (function == ACPI_READ) {
- f_v |= temp << 8 * i;
- *value = f_v;
+ while (bits - i > 0) {
+ if (function == ACPI_READ) {
+ result = acpi_ec_read(ec, address, &temp);
+ (*value) |= ((acpi_integer)temp) << i;
+ } else {
+ temp = 0xff & ((*value) >> i);
+ result = acpi_ec_write(ec, address, temp);
+ }
+ i += 8;
+ ++address;
}
- out:
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
@@ -597,9 +636,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
static acpi_status
ec_parse_io_ports(struct acpi_resource *resource, void *context);
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
-
static struct acpi_ec *make_acpi_ec(void)
{
struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
@@ -610,13 +646,58 @@ static struct acpi_ec *make_acpi_ec(void)
atomic_set(&ec->event_count, 1);
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
+ INIT_LIST_HEAD(&ec->list);
return ec;
}
+static acpi_status
+acpi_ec_register_query_methods(acpi_handle handle, u32 level,
+ void *context, void **return_value)
+{
+ struct acpi_namespace_node *node = handle;
+ struct acpi_ec *ec = context;
+ int value = 0;
+ if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
+ acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
+ }
+ return AE_OK;
+}
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
+{
+ acpi_status status;
+
+ struct acpi_ec *ec = context;
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ ec_parse_io_ports, ec);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ 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;
+
+ printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
+ ec->gpe, ec->command_addr, ec->data_addr);
+
+ return AE_CTRL_TERMINATE;
+}
+
static int acpi_ec_add(struct acpi_device *device)
{
- acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
if (!device)
@@ -629,8 +710,8 @@ static int acpi_ec_add(struct acpi_device *device)
if (!ec)
return -ENOMEM;
- status = ec_parse_device(device->handle, 0, ec, NULL);
- if (status != AE_CTRL_TERMINATE) {
+ if (ec_parse_device(device->handle, 0, ec, NULL) !=
+ AE_CTRL_TERMINATE) {
kfree(ec);
return -EINVAL;
}
@@ -641,6 +722,8 @@ static int acpi_ec_add(struct acpi_device *device)
/* We might have incorrect info for GL at boot time */
mutex_lock(&boot_ec->lock);
boot_ec->global_lock = ec->global_lock;
+ /* Copy handlers from new ec into boot ec */
+ list_splice(&ec->list, &boot_ec->list);
mutex_unlock(&boot_ec->lock);
kfree(ec);
ec = boot_ec;
@@ -651,22 +734,24 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_driver_data(device) = ec;
acpi_ec_add_fs(device);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
- acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->gpe));
-
return 0;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
{
struct acpi_ec *ec;
+ struct acpi_ec_query_handler *handler, *tmp;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
+ mutex_lock(&ec->lock);
+ list_for_each_entry_safe(handler, tmp, &ec->list, node) {
+ list_del(&handler->node);
+ kfree(handler);
+ }
+ mutex_unlock(&ec->lock);
acpi_ec_remove_fs(device);
acpi_driver_data(device) = NULL;
if (ec == first_ec)
@@ -722,15 +807,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
return -ENODEV;
}
- /* EC is fully operational, allow queries */
- atomic_set(&ec->query_pending, 0);
-
return 0;
}
static int acpi_ec_start(struct acpi_device *device)
{
struct acpi_ec *ec;
+ int ret = 0;
if (!device)
return -EINVAL;
@@ -740,14 +823,14 @@ static int acpi_ec_start(struct acpi_device *device)
if (!ec)
return -EINVAL;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
- ec->gpe, ec->command_addr, ec->data_addr));
-
/* Boot EC is already working */
- if (ec == boot_ec)
- return 0;
+ if (ec != boot_ec)
+ ret = ec_install_handlers(ec);
+
+ /* EC is fully operational, allow queries */
+ atomic_set(&ec->query_pending, 0);
- return ec_install_handlers(ec);
+ return ret;
}
static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -779,34 +862,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return 0;
}
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
-{
- acpi_status status;
-
- struct acpi_ec *ec = context;
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- ec_parse_io_ports, ec);
- if (ACPI_FAILURE(status))
- return status;
-
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
- if (ACPI_FAILURE(status))
- return status;
-
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
-
- ec->handle = handle;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
- ec->gpe, ec->command_addr, ec->data_addr));
-
- return AE_CTRL_TERMINATE;
-}
-
int __init acpi_ec_ecdt_probe(void)
{
int ret;
@@ -819,18 +874,22 @@ int __init acpi_ec_ecdt_probe(void)
/*
* Generate a boot ec context
*/
-
status = acpi_get_table(ACPI_SIG_ECDT, 1,
(struct acpi_table_header **)&ecdt_ptr);
- if (ACPI_FAILURE(status))
- goto error;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
-
- boot_ec->command_addr = ecdt_ptr->control.address;
- boot_ec->data_addr = ecdt_ptr->data.address;
- boot_ec->gpe = ecdt_ptr->gpe;
- boot_ec->handle = ACPI_ROOT_OBJECT;
+ if (ACPI_SUCCESS(status)) {
+ printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n");
+ boot_ec->command_addr = ecdt_ptr->control.address;
+ boot_ec->data_addr = ecdt_ptr->data.address;
+ boot_ec->gpe = ecdt_ptr->gpe;
+ boot_ec->handle = ACPI_ROOT_OBJECT;
+ } else {
+ printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
+ status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
+ boot_ec, NULL);
+ /* Check that acpi_get_devices actually find something */
+ if (ACPI_FAILURE(status) || !boot_ec->handle)
+ goto error;
+ }
ret = ec_install_handlers(boot_ec);
if (!ret) {
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 3b23562e6f92..5c95863f8fa9 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -11,10 +11,13 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <acpi/acpi_drivers.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("event");
+#ifdef CONFIG_ACPI_PROC_EVENT
/* Global vars for handling event proc entry */
static DEFINE_SPINLOCK(acpi_system_event_lock);
int event_is_open = 0;
@@ -48,7 +51,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
static int chars_remaining = 0;
static char *ptr;
-
if (!chars_remaining) {
memset(&event, 0, sizeof(struct acpi_bus_event));
@@ -105,24 +107,173 @@ static const struct file_operations acpi_system_event_ops = {
.release = acpi_system_close_event,
.poll = acpi_system_poll_event,
};
+#endif /* CONFIG_ACPI_PROC_EVENT */
+
+#ifdef CONFIG_NET
+static unsigned int acpi_event_seqnum;
+struct acpi_genl_event {
+ acpi_device_class device_class;
+ char bus_id[15];
+ u32 type;
+ u32 data;
+};
+
+/* attributes of acpi_genl_family */
+enum {
+ ACPI_GENL_ATTR_UNSPEC,
+ ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */
+ __ACPI_GENL_ATTR_MAX,
+};
+#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
+
+/* commands supported by the acpi_genl_family */
+enum {
+ ACPI_GENL_CMD_UNSPEC,
+ ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */
+ __ACPI_GENL_CMD_MAX,
+};
+#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
+
+#define ACPI_GENL_FAMILY_NAME "acpi_event"
+#define ACPI_GENL_VERSION 0x01
+#define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group"
+
+static struct genl_family acpi_event_genl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = ACPI_GENL_FAMILY_NAME,
+ .version = ACPI_GENL_VERSION,
+ .maxattr = ACPI_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group acpi_event_mcgrp = {
+ .name = ACPI_GENL_MCAST_GROUP_NAME,
+};
+
+int acpi_bus_generate_netlink_event(const char *device_class,
+ const char *bus_id,
+ u8 type, int data)
+{
+ struct sk_buff *skb;
+ struct nlattr *attr;
+ struct acpi_genl_event *event;
+ void *msg_header;
+ int size;
+ int result;
+
+ /* allocate memory */
+ size = nla_total_size(sizeof(struct acpi_genl_event)) +
+ nla_total_size(0);
+
+ skb = genlmsg_new(size, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ /* add the genetlink message header */
+ msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
+ &acpi_event_genl_family, 0,
+ ACPI_GENL_CMD_EVENT);
+ if (!msg_header) {
+ nlmsg_free(skb);
+ return -ENOMEM;
+ }
+
+ /* fill the data */
+ attr =
+ nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
+ sizeof(struct acpi_genl_event));
+ if (!attr) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ event = nla_data(attr);
+ if (!event) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ memset(event, 0, sizeof(struct acpi_genl_event));
+
+ strcpy(event->device_class, device_class);
+ strcpy(event->bus_id, bus_id);
+ event->type = type;
+ event->data = data;
+
+ /* send multicast genetlink message */
+ result = genlmsg_end(skb, msg_header);
+ if (result < 0) {
+ nlmsg_free(skb);
+ return result;
+ }
+
+ result =
+ genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Failed to send a Genetlink message!\n"));
+ return 0;
+}
+
+EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
+
+static int acpi_event_genetlink_init(void)
+{
+ int result;
+
+ result = genl_register_family(&acpi_event_genl_family);
+ if (result)
+ return result;
+
+ result = genl_register_mc_group(&acpi_event_genl_family,
+ &acpi_event_mcgrp);
+ if (result)
+ genl_unregister_family(&acpi_event_genl_family);
+
+ return result;
+}
+
+#else
+int acpi_bus_generate_netlink_event(const char *device_class,
+ const char *bus_id,
+ u8 type, int data)
+{
+ return 0;
+}
+
+EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
+
+static int acpi_event_genetlink_init(void)
+{
+ return -ENODEV;
+}
+#endif
static int __init acpi_event_init(void)
{
+#ifdef CONFIG_ACPI_PROC_EVENT
struct proc_dir_entry *entry;
+#endif
int error = 0;
-
if (acpi_disabled)
return 0;
+ /* create genetlink for acpi event */
+ error = acpi_event_genetlink_init();
+ if (error)
+ printk(KERN_WARNING PREFIX
+ "Failed to create genetlink family for ACPI event\n");
+
+#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 {
- error = -ENODEV;
- }
- return error;
+ else
+ return -ENODEV;
+#endif
+
+ return 0;
}
-subsys_initcall(acpi_event_init);
+fs_initcall(acpi_event_init);
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 902c287b3a4f..361ebe6c4a6f 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -586,6 +586,10 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
if (gpe_xrupt->previous) {
gpe_xrupt->previous->next = gpe_xrupt->next;
+ } else {
+ /* No previous, update list head */
+
+ acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
}
if (gpe_xrupt->next) {
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 400d90fca966..b1aaa0e84588 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -284,6 +284,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
}
if (!pci_device_node) {
+ ACPI_FREE(pci_id);
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
@@ -377,7 +378,7 @@ static u8 acpi_ev_match_pci_root_bridge(char *id)
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
{
acpi_status status;
- struct acpi_device_id hid;
+ struct acpica_device_id hid;
struct acpi_compatible_id_list *cid;
acpi_native_uint i;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index ec655c539492..c81f6bdb68b8 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -50,10 +50,16 @@ static int acpi_fan_remove(struct acpi_device *device, int type);
static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
static int acpi_fan_resume(struct acpi_device *device);
+static const struct acpi_device_id fan_device_ids[] = {
+ {"PNP0C0B", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, fan_device_ids);
+
static struct acpi_driver acpi_fan_driver = {
.name = "fan",
.class = ACPI_FAN_CLASS,
- .ids = "PNP0C0B",
+ .ids = fan_device_ids,
.ops = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 41427a41f620..4893e256e399 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -16,7 +16,7 @@
#if ACPI_GLUE_DEBUG
#define DBG(x...) printk(PREFIX x)
#else
-#define DBG(x...)
+#define DBG(x...) do { } while(0)
#endif
static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 76c525dc590b..cf69c0040a39 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -576,13 +576,10 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
}
- status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
- }
- /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
-
/*
+ * GPEs must be enabled before _WAK is called as GPEs
+ * might get fired there
+ *
* Restore the GPEs:
* 1) Disable/Clear all GPEs
* 2) Enable all runtime GPEs
@@ -591,13 +588,19 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- acpi_gbl_system_awake_and_running = TRUE;
-
status = acpi_hw_enable_all_runtime_gpes();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
+ status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
+ }
+ /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
+
+ acpi_gbl_system_awake_and_running = TRUE;
+
/* Enable power button */
(void)
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index be4f2899de74..f39fbc6b9237 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -440,7 +440,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
acpi_status status;
struct acpi_namespace_node *node;
u32 flags;
- struct acpi_device_id hid;
+ struct acpica_device_id hid;
struct acpi_compatible_id_list *cid;
acpi_native_uint i;
@@ -540,7 +540,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
******************************************************************************/
acpi_status
-acpi_get_devices(char *HID,
+acpi_get_devices(const char *HID,
acpi_walk_callback user_function,
void *context, void **return_value)
{
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 0c9f15c54e8c..ab04d848b19d 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -36,13 +36,11 @@
ACPI_MODULE_NAME("numa");
static nodemask_t nodes_found_map = NODE_MASK_NONE;
-#define PXM_INVAL -1
-#define NID_INVAL -1
/* maps to convert between proximity domain and logical node ID */
-static int pxm_to_node_map[MAX_PXM_DOMAINS]
+static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
= { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
-static int node_to_pxm_map[MAX_NUMNODES]
+static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
int pxm_to_node(int pxm)
@@ -59,6 +57,12 @@ int node_to_pxm(int node)
return node_to_pxm_map[node];
}
+void __acpi_map_pxm_to_node(int pxm, int node)
+{
+ pxm_to_node_map[pxm] = node;
+ node_to_pxm_map[node] = pxm;
+}
+
int acpi_map_pxm_to_node(int pxm)
{
int node = pxm_to_node_map[pxm];
@@ -67,8 +71,7 @@ int acpi_map_pxm_to_node(int pxm)
if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
return NID_INVAL;
node = first_unset_node(nodes_found_map);
- pxm_to_node_map[pxm] = node;
- node_to_pxm_map[node] = pxm;
+ __acpi_map_pxm_to_node(pxm, node);
node_set(node, nodes_found_map);
}
@@ -83,7 +86,8 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
node_clear(node, nodes_found_map);
}
-void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
+static void __init
+acpi_table_print_srat_entry(struct acpi_subtable_header *header)
{
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -200,7 +204,7 @@ static int __init acpi_parse_srat(struct acpi_table_header *table)
return 0;
}
-int __init
+static int __init
acpi_table_parse_srat(enum acpi_srat_type id,
acpi_table_entry_handler handler, unsigned int max_entries)
{
@@ -211,14 +215,13 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void)
{
- int result;
-
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
- result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
- acpi_parse_processor_affinity,
- NR_CPUS);
- result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+ acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
+ acpi_parse_processor_affinity, NR_CPUS);
+ acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+ acpi_parse_memory_affinity,
+ NR_NODE_MEMBLKS);
}
/* SLIT: System Locality Information Table */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2e7ba615d760..352cf81af581 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,13 +77,7 @@ static struct workqueue_struct *kacpi_notify_wq;
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
static char osi_additional_string[OSI_STRING_LENGTH_MAX];
-#define OSI_LINUX_ENABLED
-#ifdef OSI_LINUX_ENABLED
-int osi_linux = 1; /* enable _OSI(Linux) by default */
-#else
-int osi_linux; /* disable _OSI(Linux) by default */
-#endif
-
+static int osi_linux; /* disable _OSI(Linux) by default */
#ifdef CONFIG_DMI
static struct __initdata dmi_system_id acpi_osl_dmi_table[];
@@ -1098,7 +1092,7 @@ void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
acpi_status
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
{
- *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
+ *cache = kmem_cache_create(name, size, 0, 0, NULL);
if (*cache == NULL)
return AE_ERROR;
else
@@ -1183,17 +1177,10 @@ acpi_os_validate_interface (char *interface)
if (!strcmp("Linux", interface)) {
printk(KERN_WARNING PREFIX
"System BIOS is requesting _OSI(Linux)\n");
-#ifdef OSI_LINUX_ENABLED
- printk(KERN_WARNING PREFIX
- "Please test with \"acpi_osi=!Linux\"\n"
- "Please send dmidecode "
- "to linux-acpi@vger.kernel.org\n");
-#else
printk(KERN_WARNING PREFIX
"If \"acpi_osi=Linux\" works better,\n"
"Please send dmidecode "
"to linux-acpi@vger.kernel.org\n");
-#endif
if(osi_linux)
return AE_OK;
}
@@ -1227,36 +1214,14 @@ acpi_os_validate_address (
}
#ifdef CONFIG_DMI
-#ifdef OSI_LINUX_ENABLED
-static int dmi_osi_not_linux(struct dmi_system_id *d)
+static int dmi_osi_linux(const struct dmi_system_id *d)
{
- printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident);
- enable_osi_linux(0);
- return 0;
-}
-#else
-static int dmi_osi_linux(struct dmi_system_id *d)
-{
- printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident);
+ printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
enable_osi_linux(1);
return 0;
}
-#endif
static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-#ifdef OSI_LINUX_ENABLED
- /*
- * Boxes that need NOT _OSI(Linux)
- */
- {
- .callback = dmi_osi_not_linux,
- .ident = "Toshiba Satellite P100",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"),
- DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"),
- },
- },
-#else
/*
* Boxes that need _OSI(Linux)
*/
@@ -1268,7 +1233,6 @@ static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
},
},
-#endif
{}
};
#endif /* CONFIG_DMI */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index acc594771379..c9f526e55392 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -46,7 +46,6 @@
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
-#define ACPI_PCI_LINK_HID "PNP0C0F"
#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
#define ACPI_PCI_LINK_FILE_INFO "info"
#define ACPI_PCI_LINK_FILE_STATUS "state"
@@ -54,10 +53,16 @@ ACPI_MODULE_NAME("pci_link");
static int acpi_pci_link_add(struct acpi_device *device);
static int acpi_pci_link_remove(struct acpi_device *device, int type);
+static struct acpi_device_id link_device_ids[] = {
+ {"PNP0C0F", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, link_device_ids);
+
static struct acpi_driver acpi_pci_link_driver = {
.name = "pci_link",
.class = ACPI_PCI_LINK_CLASS,
- .ids = ACPI_PCI_LINK_HID,
+ .ids = link_device_ids,
.ops = {
.add = acpi_pci_link_add,
.remove = acpi_pci_link_remove,
@@ -733,7 +738,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
/* query and set link->irq.active */
acpi_pci_link_get_current(link);
- printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
+ printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.active == link->irq.possible[i]) {
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ad4145a37786..f14ff1ffab29 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -38,16 +38,21 @@
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
-#define ACPI_PCI_ROOT_HID "PNP0A03"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
static int acpi_pci_root_add(struct acpi_device *device);
static int acpi_pci_root_remove(struct acpi_device *device, int type);
static int acpi_pci_root_start(struct acpi_device *device);
+static struct acpi_device_id root_device_ids[] = {
+ {"PNP0A03", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, root_device_ids);
+
static struct acpi_driver acpi_pci_root_driver = {
.name = "pci_root",
.class = ACPI_PCI_ROOT_CLASS,
- .ids = ACPI_PCI_ROOT_HID,
+ .ids = root_device_ids,
.ops = {
.add = acpi_pci_root_add,
.remove = acpi_pci_root_remove,
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4ffecd179702..57b9a2998fd0 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -59,10 +59,16 @@ static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
static int acpi_power_open_fs(struct inode *inode, struct file *file);
+static struct acpi_device_id power_device_ids[] = {
+ {ACPI_POWER_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, power_device_ids);
+
static struct acpi_driver acpi_power_driver = {
.name = "power",
.class = ACPI_POWER_CLASS,
- .ids = ACPI_POWER_HID,
+ .ids = power_device_ids,
.ops = {
.add = acpi_power_add,
.remove = acpi_power_remove,
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e1ca86dfdd66..9f11dc296cdd 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -66,6 +66,7 @@
#define ACPI_PROCESSOR_FILE_LIMIT "limit"
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
@@ -84,15 +85,25 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
+extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
+
+
+static const struct acpi_device_id processor_device_ids[] = {
+ {ACPI_PROCESSOR_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, processor_device_ids);
static struct acpi_driver acpi_processor_driver = {
.name = "processor",
.class = ACPI_PROCESSOR_CLASS,
- .ids = ACPI_PROCESSOR_HID,
+ .ids = processor_device_ids,
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
.start = acpi_processor_start,
+ .suspend = acpi_processor_suspend,
+ .resume = acpi_processor_resume,
},
};
@@ -689,13 +700,23 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
switch (event) {
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
acpi_processor_ppc_has_changed(pr);
- acpi_bus_generate_event(device, event,
+ acpi_bus_generate_proc_event(device, event,
pr->performance_platform_limit);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event,
+ pr->performance_platform_limit);
break;
case ACPI_PROCESSOR_NOTIFY_POWER:
acpi_processor_cst_has_changed(pr);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
break;
+ case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+ acpi_processor_tstate_has_changed(pr);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
@@ -705,6 +726,25 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
return;
}
+static int acpi_cpu_soft_notify(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct acpi_processor *pr = processors[cpu];
+
+ if (action == CPU_ONLINE && pr) {
+ acpi_processor_ppc_has_changed(pr);
+ acpi_processor_cst_has_changed(pr);
+ acpi_processor_tstate_has_changed(pr);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_cpu_notifier =
+{
+ .notifier_call = acpi_cpu_soft_notify,
+};
+
static int acpi_processor_add(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
@@ -968,6 +1008,7 @@ void acpi_processor_install_hotplug_notify(void)
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
#endif
+ register_hotcpu_notifier(&acpi_cpu_notifier);
}
static
@@ -980,6 +1021,7 @@ void acpi_processor_uninstall_hotplug_notify(void)
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
#endif
+ unregister_hotcpu_notifier(&acpi_cpu_notifier);
}
/*
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80ffc7829916..1f6fb38de017 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -63,6 +63,7 @@
ACPI_MODULE_NAME("processor_idle");
#define ACPI_PROCESSOR_FILE_POWER "power"
#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
+#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
static void (*pm_idle_save) (void) __read_mostly;
@@ -91,7 +92,7 @@ module_param(bm_history, uint, 0644);
*
* To skip this limit, boot/load with a large max_cstate limit.
*/
-static int set_max_cstate(struct dmi_system_id *id)
+static int set_max_cstate(const struct dmi_system_id *id)
{
if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
return 0;
@@ -275,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
unsigned long reason;
reason = pr->power.timer_broadcast_on_state < INT_MAX ?
CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
clockevents_notify(reason, &pr->id);
-#else
- cpumask_t mask = cpumask_of_cpu(pr->id);
-
- if (pr->power.timer_broadcast_on_state < INT_MAX)
- on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
- else
- on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
}
/* Power(C) State timer broadcast control */
@@ -297,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
struct acpi_processor_cx *cx,
int broadcast)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
int state = cx - pr->power.states;
if (state >= pr->power.timer_broadcast_on_state) {
@@ -308,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
clockevents_notify(reason, &pr->id);
}
-#endif
}
#else
@@ -324,6 +313,23 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
#endif
+/*
+ * Suspend / resume control
+ */
+static int acpi_idle_suspend;
+
+int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
+{
+ acpi_idle_suspend = 1;
+ return 0;
+}
+
+int acpi_processor_resume(struct acpi_device * device)
+{
+ acpi_idle_suspend = 0;
+ return 0;
+}
+
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
@@ -354,7 +360,7 @@ static void acpi_processor_idle(void)
}
cx = pr->power.state;
- if (!cx) {
+ if (!cx || acpi_idle_suspend) {
if (pm_idle_save)
pm_idle_save();
else
@@ -462,6 +468,9 @@ static void acpi_processor_idle(void)
* TBD: Can't get time duration while in C1, as resumes
* go to an ISR rather than here. Need to instrument
* base interrupt handler.
+ *
+ * Note: the TSC better not stop in C1, sched_clock() will
+ * skew otherwise.
*/
sleep_ticks = 0xFFFFFFFF;
break;
@@ -469,28 +478,45 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C2:
/* Get start time (ticks) */
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ /* Tell the scheduler that we are going deep-idle: */
+ sched_clock_idle_sleep_event();
/* Invoke C2 */
acpi_state_timer_broadcast(pr, cx, 1);
acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C2, so notify users */
mark_tsc_unstable("possible TSC halt in C2");
#endif
+ /* Compute time (ticks) that we were actually asleep */
+ sleep_ticks = ticks_elapsed(t1, t2);
+
+ /* Tell the scheduler how much we idled: */
+ sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+
/* Re-enable interrupts */
local_irq_enable();
+ /* Do not account our idle-switching overhead: */
+ sleep_ticks -= cx->latency_ticks + C2_OVERHEAD;
+
current_thread_info()->status |= TS_POLLING;
- /* Compute time (ticks) that we were actually asleep */
- sleep_ticks =
- ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
acpi_state_timer_broadcast(pr, cx, 0);
break;
case ACPI_STATE_C3:
-
- if (pr->flags.bm_check) {
+ /*
+ * disable bus master
+ * bm_check implies we need ARB_DIS
+ * !bm_check implies we need cache flush
+ * bm_control implies whether we can do ARB_DIS
+ *
+ * That leaves a case where bm_check is set and bm_control is
+ * not set. In that case we cannot do much, we enter C3
+ * without doing anything.
+ */
+ if (pr->flags.bm_check && pr->flags.bm_control) {
if (atomic_inc_return(&c3_cpu_count) ==
num_online_cpus()) {
/*
@@ -499,7 +525,7 @@ static void acpi_processor_idle(void)
*/
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
- } else {
+ } else if (!pr->flags.bm_check) {
/* SMP with no shared cache... Invalidate cache */
ACPI_FLUSH_CPU_CACHE();
}
@@ -508,25 +534,32 @@ static void acpi_processor_idle(void)
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C3 */
acpi_state_timer_broadcast(pr, cx, 1);
+ /* Tell the scheduler that we are going deep-idle: */
+ sched_clock_idle_sleep_event();
acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
- if (pr->flags.bm_check) {
+ if (pr->flags.bm_check && pr->flags.bm_control) {
/* Enable bus master arbitration */
atomic_dec(&c3_cpu_count);
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C3, so notify users */
mark_tsc_unstable("TSC halts in C3");
#endif
+ /* Compute time (ticks) that we were actually asleep */
+ sleep_ticks = ticks_elapsed(t1, t2);
+ /* Tell the scheduler how much we idled: */
+ sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+
/* Re-enable interrupts */
local_irq_enable();
+ /* Do not account our idle-switching overhead: */
+ sleep_ticks -= cx->latency_ticks + C3_OVERHEAD;
+
current_thread_info()->status |= TS_POLLING;
- /* Compute time (ticks) that we were actually asleep */
- sleep_ticks =
- ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
acpi_state_timer_broadcast(pr, cx, 0);
break;
@@ -959,11 +992,17 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
}
if (pr->flags.bm_check) {
- /* bus mastering control is necessary */
if (!pr->flags.bm_control) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 support requires bus mastering control\n"));
- return;
+ if (pr->flags.has_cst != 1) {
+ /* bus mastering control is necessary */
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 support requires BM control\n"));
+ return;
+ } else {
+ /* Here we enter C3 without bus mastering */
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 support without BM control\n"));
+ }
}
} else {
/*
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index c4efc0c17f8f..463b0247cbc5 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -539,7 +539,7 @@ end:
}
int acpi_processor_preregister_performance(
- struct acpi_processor_performance **performance)
+ struct acpi_processor_performance *performance)
{
int count, count_target;
int retval = 0;
@@ -567,12 +567,12 @@ int acpi_processor_preregister_performance(
continue;
}
- if (!performance || !performance[i]) {
+ if (!performance || !percpu_ptr(performance, i)) {
retval = -EINVAL;
continue;
}
- pr->performance = performance[i];
+ pr->performance = percpu_ptr(performance, i);
cpu_set(i, pr->performance->shared_cpu_map);
if (acpi_processor_get_psd(pr)) {
retval = -EINVAL;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index b33486009f41..0b8204e7082a 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -44,17 +44,251 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_throttling");
+static int acpi_processor_get_throttling(struct acpi_processor *pr);
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+
+/*
+ * _TPC - Throttling Present Capabilities
+ */
+static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
+{
+ acpi_status status = 0;
+ unsigned long tpc = 0;
+
+ if (!pr)
+ return -EINVAL;
+ status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+ }
+ return -ENODEV;
+ }
+ pr->throttling_platform_limit = (int)tpc;
+ return 0;
+}
+
+int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
+{
+ return acpi_processor_get_platform_limit(pr);
+}
+
+/*
+ * _PTC - Processor Throttling Control (and status) register location
+ */
+static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *ptc = NULL;
+ union acpi_object obj = { 0 };
+
+ status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+ }
+ return -ENODEV;
+ }
+
+ ptc = (union acpi_object *)buffer.pointer;
+ if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
+ || (ptc->package.count != 2)) {
+ printk(KERN_ERR PREFIX "Invalid _PTC data\n");
+ result = -EFAULT;
+ goto end;
+ }
+
+ /*
+ * control_register
+ */
+
+ obj = ptc->package.elements[0];
+
+ if ((obj.type != ACPI_TYPE_BUFFER)
+ || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+ || (obj.buffer.pointer == NULL)) {
+ printk(KERN_ERR PREFIX
+ "Invalid _PTC data (control_register)\n");
+ result = -EFAULT;
+ goto end;
+ }
+ memcpy(&pr->throttling.control_register, obj.buffer.pointer,
+ sizeof(struct acpi_ptc_register));
+
+ /*
+ * status_register
+ */
+
+ obj = ptc->package.elements[1];
+
+ if ((obj.type != ACPI_TYPE_BUFFER)
+ || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+ || (obj.buffer.pointer == NULL)) {
+ printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
+ result = -EFAULT;
+ goto end;
+ }
+
+ memcpy(&pr->throttling.status_register, obj.buffer.pointer,
+ sizeof(struct acpi_ptc_register));
+
+ end:
+ kfree(buffer.pointer);
+
+ return result;
+}
+
+/*
+ * _TSS - Throttling Supported States
+ */
+static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+ struct acpi_buffer state = { 0, NULL };
+ union acpi_object *tss = NULL;
+ int i;
+
+ status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+ }
+ return -ENODEV;
+ }
+
+ tss = buffer.pointer;
+ if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
+ printk(KERN_ERR PREFIX "Invalid _TSS data\n");
+ result = -EFAULT;
+ goto end;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
+ tss->package.count));
+
+ pr->throttling.state_count = tss->package.count;
+ pr->throttling.states_tss =
+ kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count,
+ GFP_KERNEL);
+ if (!pr->throttling.states_tss) {
+ result = -ENOMEM;
+ goto end;
+ }
+
+ for (i = 0; i < pr->throttling.state_count; i++) {
+
+ struct acpi_processor_tx_tss *tx =
+ (struct acpi_processor_tx_tss *)&(pr->throttling.
+ states_tss[i]);
+
+ state.length = sizeof(struct acpi_processor_tx_tss);
+ state.pointer = tx;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+ status = acpi_extract_package(&(tss->package.elements[i]),
+ &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data"));
+ result = -EFAULT;
+ kfree(pr->throttling.states_tss);
+ goto end;
+ }
+
+ if (!tx->freqpercentage) {
+ printk(KERN_ERR PREFIX
+ "Invalid _TSS data: freq is zero\n");
+ result = -EFAULT;
+ kfree(pr->throttling.states_tss);
+ goto end;
+ }
+ }
+
+ end:
+ kfree(buffer.pointer);
+
+ return result;
+}
+
+/*
+ * _TSD - T-State Dependencies
+ */
+static int acpi_processor_get_tsd(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+ struct acpi_buffer state = { 0, NULL };
+ union acpi_object *tsd = NULL;
+ struct acpi_tsd_package *pdomain;
+
+ status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSD"));
+ }
+ return -ENODEV;
+ }
+
+ tsd = buffer.pointer;
+ if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (tsd->package.count != 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ pdomain = &(pr->throttling.domain_info);
+
+ state.length = sizeof(struct acpi_tsd_package);
+ state.pointer = pdomain;
+
+ status = acpi_extract_package(&(tsd->package.elements[0]),
+ &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ end:
+ kfree(buffer.pointer);
+ return result;
+}
+
/* --------------------------------------------------------------------------
Throttling Control
-------------------------------------------------------------------------- */
-static int acpi_processor_get_throttling(struct acpi_processor *pr)
+static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
{
int state = 0;
u32 value = 0;
u32 duty_mask = 0;
u32 duty_value = 0;
-
if (!pr)
return -EINVAL;
@@ -94,13 +328,115 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
return 0;
}
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+static int acpi_read_throttling_status(struct acpi_processor_throttling
+ *throttling)
+{
+ int value = -1;
+ switch (throttling->status_register.space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ acpi_os_read_port((acpi_io_address) throttling->status_register.
+ address, &value,
+ (u32) throttling->status_register.bit_width *
+ 8);
+ break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ printk(KERN_ERR PREFIX
+ "HARDWARE addr space,NOT supported yet\n");
+ break;
+ default:
+ printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+ (u32) (throttling->status_register.space_id));
+ }
+ return value;
+}
+
+static int acpi_write_throttling_state(struct acpi_processor_throttling
+ *throttling, int value)
+{
+ int ret = -1;
+
+ switch (throttling->control_register.space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ acpi_os_write_port((acpi_io_address) throttling->
+ control_register.address, value,
+ (u32) throttling->control_register.
+ bit_width * 8);
+ ret = 0;
+ break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ printk(KERN_ERR PREFIX
+ "HARDWARE addr space,NOT supported yet\n");
+ break;
+ default:
+ printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+ (u32) (throttling->control_register.space_id));
+ }
+ return ret;
+}
+
+static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
+{
+ int i;
+
+ for (i = 0; i < pr->throttling.state_count; i++) {
+ struct acpi_processor_tx_tss *tx =
+ (struct acpi_processor_tx_tss *)&(pr->throttling.
+ states_tss[i]);
+ if (tx->control == value)
+ break;
+ }
+ if (i > pr->throttling.state_count)
+ i = -1;
+ return i;
+}
+
+static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
+{
+ int value = -1;
+ if (state >= 0 && state <= pr->throttling.state_count) {
+ struct acpi_processor_tx_tss *tx =
+ (struct acpi_processor_tx_tss *)&(pr->throttling.
+ states_tss[state]);
+ value = tx->control;
+ }
+ return value;
+}
+
+static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
+{
+ int state = 0;
+ u32 value = 0;
+
+ if (!pr)
+ return -EINVAL;
+
+ if (!pr->flags.throttling)
+ return -ENODEV;
+
+ pr->throttling.state = 0;
+ local_irq_disable();
+ value = acpi_read_throttling_status(&pr->throttling);
+ if (value >= 0) {
+ state = acpi_get_throttling_state(pr, value);
+ pr->throttling.state = state;
+ }
+ local_irq_enable();
+
+ return 0;
+}
+
+static int acpi_processor_get_throttling(struct acpi_processor *pr)
+{
+ return pr->throttling.acpi_processor_get_throttling(pr);
+}
+
+static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
+ int state)
{
u32 value = 0;
u32 duty_mask = 0;
u32 duty_value = 0;
-
if (!pr)
return -EINVAL;
@@ -113,6 +449,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
if (state == pr->throttling.state)
return 0;
+ if (state < pr->throttling_platform_limit)
+ return -EPERM;
/*
* Calculate the duty_value and duty_mask.
*/
@@ -165,13 +503,49 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
return 0;
}
+static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
+ int state)
+{
+ u32 value = 0;
+
+ if (!pr)
+ return -EINVAL;
+
+ if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+ return -EINVAL;
+
+ if (!pr->flags.throttling)
+ return -ENODEV;
+
+ if (state == pr->throttling.state)
+ return 0;
+
+ if (state < pr->throttling_platform_limit)
+ return -EPERM;
+
+ local_irq_disable();
+
+ value = acpi_get_throttling_value(pr, state);
+ if (value >= 0) {
+ acpi_write_throttling_state(&pr->throttling, value);
+ pr->throttling.state = state;
+ }
+ local_irq_enable();
+
+ return 0;
+}
+
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+{
+ return pr->throttling.acpi_processor_set_throttling(pr, state);
+}
+
int acpi_processor_get_throttling_info(struct acpi_processor *pr)
{
int result = 0;
int step = 0;
int i = 0;
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
pr->throttling.address,
@@ -181,7 +555,26 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
if (!pr)
return -EINVAL;
- /* TBD: Support ACPI 2.0 objects */
+ /*
+ * Evaluate _PTC, _TSS and _TPC
+ * They must all be present or none of them can be used.
+ */
+ if (acpi_processor_get_throttling_control(pr) ||
+ acpi_processor_get_throttling_states(pr) ||
+ acpi_processor_get_platform_limit(pr))
+ {
+ pr->throttling.acpi_processor_get_throttling =
+ &acpi_processor_get_throttling_fadt;
+ pr->throttling.acpi_processor_set_throttling =
+ &acpi_processor_set_throttling_fadt;
+ } else {
+ pr->throttling.acpi_processor_get_throttling =
+ &acpi_processor_get_throttling_ptc;
+ pr->throttling.acpi_processor_set_throttling =
+ &acpi_processor_set_throttling_ptc;
+ }
+
+ acpi_processor_get_tsd(pr);
if (!pr->throttling.address) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
@@ -262,7 +655,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
int i = 0;
int result = 0;
-
if (!pr)
goto end;
@@ -280,15 +672,27 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
}
seq_printf(seq, "state count: %d\n"
- "active state: T%d\n",
- pr->throttling.state_count, pr->throttling.state);
+ "active state: T%d\n"
+ "state available: T%d to T%d\n",
+ pr->throttling.state_count, pr->throttling.state,
+ pr->throttling_platform_limit,
+ pr->throttling.state_count - 1);
seq_puts(seq, "states:\n");
- for (i = 0; i < pr->throttling.state_count; i++)
- seq_printf(seq, " %cT%d: %02d%%\n",
- (i == pr->throttling.state ? '*' : ' '), i,
- (pr->throttling.states[i].performance ? pr->
- throttling.states[i].performance / 10 : 0));
+ if (pr->throttling.acpi_processor_get_throttling ==
+ acpi_processor_get_throttling_fadt) {
+ for (i = 0; i < pr->throttling.state_count; i++)
+ seq_printf(seq, " %cT%d: %02d%%\n",
+ (i == pr->throttling.state ? '*' : ' '), i,
+ (pr->throttling.states[i].performance ? pr->
+ throttling.states[i].performance / 10 : 0));
+ } else {
+ for (i = 0; i < pr->throttling.state_count; i++)
+ seq_printf(seq, " %cT%d: %02d%%\n",
+ (i == pr->throttling.state ? '*' : ' '), i,
+ (int)pr->throttling.states_tss[i].
+ freqpercentage);
+ }
end:
return 0;
@@ -301,7 +705,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode,
PDE(inode)->data);
}
-static ssize_t acpi_processor_write_throttling(struct file * file,
+static ssize_t acpi_processor_write_throttling(struct file *file,
const char __user * buffer,
size_t count, loff_t * data)
{
@@ -310,7 +714,6 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
struct acpi_processor *pr = m->private;
char state_string[12] = { '\0' };
-
if (!pr || (count > sizeof(state_string) - 1))
return -EINVAL;
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index f63813a358c5..4c3fd4cdaf73 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -474,8 +474,6 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context)
return (AE_CTRL_TERMINATE);
}
-ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource)
-
/*******************************************************************************
*
* FUNCTION: acpi_walk_resources
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index c1bae106833c..a578986e3214 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -38,7 +38,6 @@
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
-#define ACPI_SBS_HID "ACPI0002"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
#define ACPI_SBS_FILE_INFO "info"
#define ACPI_SBS_FILE_STATE "state"
@@ -124,10 +123,17 @@ static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
static int acpi_sbs_resume(struct acpi_device *device);
+static const struct acpi_device_id sbs_device_ids[] = {
+ {"ACPI0001", 0},
+ {"ACPI0005", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
+
static struct acpi_driver acpi_sbs_driver = {
.name = "sbs",
.class = ACPI_SBS_CLASS,
- .ids = ACPI_SBS_HID,
+ .ids = sbs_device_ids,
.ops = {
.add = acpi_sbs_add,
.remove = acpi_sbs_remove,
@@ -176,10 +182,8 @@ struct acpi_battery {
};
struct acpi_sbs {
- acpi_handle handle;
int base;
struct acpi_device *device;
- struct acpi_ec_smbus *smbus;
struct mutex mutex;
int sbsm_present;
int sbsm_batteries_supported;
@@ -436,11 +440,12 @@ static int acpi_sbs_generate_event(struct acpi_device *device,
strcpy(acpi_device_bid(device), bid);
strcpy(acpi_device_class(device), class);
- result = acpi_bus_generate_event(device, event, state);
+ result = acpi_bus_generate_proc_event(device, event, state);
strcpy(acpi_device_bid(device), bid_saved);
strcpy(acpi_device_class(device), class_saved);
+ acpi_bus_generate_netlink_event(class, bid, event, state);
return result;
}
@@ -511,7 +516,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
"acpi_sbs_read_word() failed"));
goto end;
}
-
+ sbs->sbsm_present = 1;
sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
end:
@@ -1411,7 +1416,7 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
char dir_name[32];
int do_battery_init = 0, do_ac_init = 0;
int old_remaining_capacity = 0;
- int update_ac = 1, update_battery = 1;
+ int update_battery = 1;
int up_tm = update_time;
if (sbs_zombie(sbs)) {
@@ -1431,10 +1436,6 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
sbs->run_cnt++;
- if (!update_ac && !update_battery) {
- goto end;
- }
-
old_ac_present = sbs->ac.ac_present;
result = acpi_ac_get_present(sbs);
@@ -1630,13 +1631,12 @@ static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs = NULL;
int result = 0, remove_result = 0;
- unsigned long sbs_obj;
int id;
acpi_status status = AE_OK;
unsigned long val;
status =
- acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+ acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
return -EIO;
@@ -1653,7 +1653,7 @@ static int acpi_sbs_add(struct acpi_device *device)
sbs_mutex_lock(sbs);
- sbs->base = (val & 0xff00ull) >> 8;
+ sbs->base = 0xff & (val >> 8);
sbs->device = device;
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
@@ -1665,24 +1665,10 @@ static int acpi_sbs_add(struct acpi_device *device)
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
goto end;
}
- status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
- if (status) {
- ACPI_EXCEPTION((AE_INFO, status,
- "acpi_evaluate_integer() failed"));
- result = -EIO;
- goto end;
- }
- if (sbs_obj > 0) {
- result = acpi_sbsm_get_info(sbs);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbsm_get_info() failed"));
- goto end;
- }
- sbs->sbsm_present = 1;
- }
- if (sbs->sbsm_present == 0) {
+ acpi_sbsm_get_info(sbs);
+
+ if (!sbs->sbsm_present) {
result = acpi_battery_add(sbs, 0);
if (result) {
ACPI_EXCEPTION((AE_INFO, AE_ERROR,
@@ -1702,8 +1688,6 @@ static int acpi_sbs_add(struct acpi_device *device)
}
}
- sbs->handle = device->handle;
-
init_timer(&sbs->update_timer);
result = acpi_check_update_proc(sbs);
if (result)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 6b3b8a522476..5b4d462117cf 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -16,7 +16,7 @@ ACPI_MODULE_NAME("scan");
extern struct acpi_device *acpi_root;
#define ACPI_BUS_CLASS "system_bus"
-#define ACPI_BUS_HID "ACPI_BUS"
+#define ACPI_BUS_HID "LNXSYBUS"
#define ACPI_BUS_DEVICE_NAME "System Bus"
static LIST_HEAD(acpi_device_list);
@@ -29,6 +29,63 @@ struct acpi_device_bus_id{
unsigned int instance_no;
struct list_head node;
};
+
+/*
+ * Creates hid/cid(s) string needed for modalias and uevent
+ * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
+ * char *modalias: "acpi:IBM0001:ACPI0001"
+*/
+static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
+ int size)
+{
+ int len;
+
+ if (!acpi_dev->flags.hardware_id)
+ return -ENODEV;
+
+ len = snprintf(modalias, size, "acpi:%s:",
+ acpi_dev->pnp.hardware_id);
+ if (len < 0 || len >= size)
+ return -EINVAL;
+ size -= len;
+
+ if (acpi_dev->flags.compatible_ids) {
+ struct acpi_compatible_id_list *cid_list;
+ int i;
+ int count;
+
+ cid_list = acpi_dev->pnp.cid_list;
+ for (i = 0; i < cid_list->count; i++) {
+ count = snprintf(&modalias[len], size, "%s:",
+ cid_list->id[i].value);
+ if (count < 0 || count >= size) {
+ printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size",
+ acpi_dev->pnp.device_name, i);
+ break;
+ }
+ len += count;
+ size -= count;
+ }
+ }
+
+ modalias[len] = '\0';
+ return len;
+}
+
+static ssize_t
+acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int len;
+
+ /* Device has no HID and no CID or string is >1024 */
+ len = create_modalias(acpi_dev, buf, 1024);
+ if (len <= 0)
+ return 0;
+ buf[len++] = '\n';
+ return len;
+}
+static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
+
static int acpi_eject_operation(acpi_handle handle, int lockable)
{
struct acpi_object_list arg_list;
@@ -154,6 +211,12 @@ static int acpi_device_setup_files(struct acpi_device *dev)
goto end;
}
+ if (dev->flags.hardware_id || dev->flags.compatible_ids){
+ result = device_create_file(&dev->dev, &dev_attr_modalias);
+ if(result)
+ goto end;
+ }
+
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
* hot-removal function from userland.
@@ -178,6 +241,9 @@ static void acpi_device_remove_files(struct acpi_device *dev)
if (ACPI_SUCCESS(status))
device_remove_file(&dev->dev, &dev_attr_eject);
+ if (dev->flags.hardware_id || dev->flags.compatible_ids)
+ device_remove_file(&dev->dev, &dev_attr_modalias);
+
if(dev->flags.hardware_id)
device_remove_file(&dev->dev, &dev_attr_hid);
if(dev->handle)
@@ -186,6 +252,37 @@ static void acpi_device_remove_files(struct acpi_device *dev)
/* --------------------------------------------------------------------------
ACPI Bus operations
-------------------------------------------------------------------------- */
+
+int acpi_match_device_ids(struct acpi_device *device,
+ const struct acpi_device_id *ids)
+{
+ const struct acpi_device_id *id;
+
+ if (device->flags.hardware_id) {
+ for (id = ids; id->id[0]; id++) {
+ if (!strcmp((char*)id->id, device->pnp.hardware_id))
+ return 0;
+ }
+ }
+
+ if (device->flags.compatible_ids) {
+ struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+ int i;
+
+ for (id = ids; id->id[0]; id++) {
+ /* compare multiple _CID entries against driver ids */
+ for (i = 0; i < cid_list->count; i++) {
+ if (!strcmp((char*)id->id,
+ cid_list->id[i].value))
+ return 0;
+ }
+ }
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL(acpi_match_device_ids);
+
static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
@@ -219,37 +316,21 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_driver *acpi_drv = to_acpi_driver(drv);
- return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+ return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
- int i = 0, length = 0, ret = 0;
+ int len;
- if (acpi_dev->flags.hardware_id)
- ret = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "HWID=%s", acpi_dev->pnp.hardware_id);
- if (ret)
+ if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- if (acpi_dev->flags.compatible_ids) {
- int j;
- struct acpi_compatible_id_list *cid_list;
-
- cid_list = acpi_dev->pnp.cid_list;
-
- for (j = 0; j < cid_list->count; j++) {
- ret = add_uevent_var(envp, num_envp, &i, buffer,
- buffer_size, &length, "COMPTID=%s",
- cid_list->id[j].value);
- if (ret)
- return -ENOMEM;
- }
- }
-
- envp[i] = NULL;
+ len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
@@ -543,25 +624,6 @@ void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
return;
}
-int acpi_match_ids(struct acpi_device *device, char *ids)
-{
- if (device->flags.hardware_id)
- if (strstr(ids, device->pnp.hardware_id))
- return 0;
-
- if (device->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
- int i;
-
- /* compare multiple _CID entries against driver ids */
- for (i = 0; i < cid_list->count; i++) {
- if (strstr(ids, cid_list->id[i].value))
- return 0;
- }
- }
- return -ENOENT;
-}
-
static int acpi_bus_get_perf_flags(struct acpi_device *device)
{
device->performance.state = ACPI_STATE_UNKNOWN;
@@ -624,6 +686,13 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
+ struct acpi_device_id button_device_ids[] = {
+ {"PNP0C0D", 0},
+ {"PNP0C0C", 0},
+ {"PNP0C0E", 0},
+ {"", 0},
+ };
+
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
@@ -643,7 +712,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
device->wakeup.flags.valid = 1;
/* Power button, Lid switch always enable wakeup */
- if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
+ if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
end:
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile
index d6c017709c85..f1fb888c2d29 100644
--- a/drivers/acpi/sleep/Makefile
+++ b/drivers/acpi/sleep/Makefile
@@ -1,5 +1,5 @@
-obj-y := poweroff.o wakeup.o
-obj-$(CONFIG_ACPI_SLEEP) += main.o
-obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc.o
+obj-y := wakeup.o
+obj-y += main.o
+obj-$(CONFIG_ACPI_SLEEP) += proc.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index bc7e16ec8393..5055acf2163c 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -15,12 +15,41 @@
#include <linux/dmi.h>
#include <linux/device.h>
#include <linux/suspend.h>
+
+#include <asm/io.h>
+
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "sleep.h"
u8 sleep_states[ACPI_S_STATE_COUNT];
+#ifdef CONFIG_PM_SLEEP
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+#endif
+
+int acpi_sleep_prepare(u32 acpi_state)
+{
+#ifdef CONFIG_ACPI_SLEEP
+ /* do we have a wakeup address for S2 and S3? */
+ if (acpi_state == ACPI_STATE_S3) {
+ if (!acpi_wakeup_address) {
+ return -EFAULT;
+ }
+ acpi_set_firmware_waking_vector((acpi_physical_address)
+ virt_to_phys((void *)
+ acpi_wakeup_address));
+
+ }
+ ACPI_FLUSH_CPU_CACHE();
+ acpi_enable_wakeup_device_prep(acpi_state);
+#endif
+ acpi_gpe_sleep_prepare(acpi_state);
+ acpi_enter_sleep_state_prep(acpi_state);
+ return 0;
+}
+
+#ifdef CONFIG_SUSPEND
static struct pm_ops acpi_pm_ops;
extern void do_suspend_lowlevel(void);
@@ -35,34 +64,49 @@ static u32 acpi_suspend_states[] = {
static int init_8259A_after_S1;
/**
+ * acpi_pm_set_target - Set the target system sleep state to the state
+ * associated with given @pm_state, if supported.
+ */
+
+static int acpi_pm_set_target(suspend_state_t pm_state)
+{
+ u32 acpi_state = acpi_suspend_states[pm_state];
+ int error = 0;
+
+ if (sleep_states[acpi_state]) {
+ acpi_target_sleep_state = acpi_state;
+ } else {
+ printk(KERN_ERR "ACPI does not support this state: %d\n",
+ pm_state);
+ error = -ENOSYS;
+ }
+ return error;
+}
+
+/**
* acpi_pm_prepare - Do preliminary suspend work.
- * @pm_state: suspend state we're entering.
+ * @pm_state: ignored
*
- * Make sure we support the state. If we do, and we need it, set the
- * firmware waking vector and do arch-specific nastiness to get the
- * wakeup code to the waking vector.
+ * If necessary, set the firmware waking vector and do arch-specific
+ * nastiness to get the wakeup code to the waking vector.
*/
-extern int acpi_sleep_prepare(u32 acpi_state);
-extern void acpi_power_off(void);
-
static int acpi_pm_prepare(suspend_state_t pm_state)
{
- u32 acpi_state = acpi_suspend_states[pm_state];
+ int error = acpi_sleep_prepare(acpi_target_sleep_state);
- if (!sleep_states[acpi_state]) {
- printk("acpi_pm_prepare does not support %d \n", pm_state);
- return -EPERM;
- }
- return acpi_sleep_prepare(acpi_state);
+ if (error)
+ acpi_target_sleep_state = ACPI_STATE_S0;
+
+ return error;
}
/**
* acpi_pm_enter - Actually enter a sleep state.
- * @pm_state: State we're entering.
+ * @pm_state: ignored
*
- * Flush caches and go to sleep. For STR or STD, we have to call
- * arch-specific assembly, which in turn call acpi_enter_sleep_state().
+ * Flush caches and go to sleep. For STR we have to call arch-specific
+ * assembly, which in turn call acpi_enter_sleep_state().
* It's unfortunate, but it works. Please fix if you're feeling frisky.
*/
@@ -70,31 +114,31 @@ static int acpi_pm_enter(suspend_state_t pm_state)
{
acpi_status status = AE_OK;
unsigned long flags = 0;
- u32 acpi_state = acpi_suspend_states[pm_state];
+ u32 acpi_state = acpi_target_sleep_state;
ACPI_FLUSH_CPU_CACHE();
/* Do arch specific saving of state. */
- if (pm_state > PM_SUSPEND_STANDBY) {
+ if (acpi_state == ACPI_STATE_S3) {
int error = acpi_save_state_mem();
- if (error)
+
+ if (error) {
+ acpi_target_sleep_state = ACPI_STATE_S0;
return error;
+ }
}
local_irq_save(flags);
acpi_enable_wakeup_device(acpi_state);
- switch (pm_state) {
- case PM_SUSPEND_STANDBY:
+ switch (acpi_state) {
+ case ACPI_STATE_S1:
barrier();
status = acpi_enter_sleep_state(acpi_state);
break;
- case PM_SUSPEND_MEM:
+ case ACPI_STATE_S3:
do_suspend_lowlevel();
break;
-
- default:
- return -EINVAL;
}
/* ACPI 3.0 specs (P62) says that it's the responsabilty
@@ -107,12 +151,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
- /* restore processor state
- * We should only be here if we're coming back from STR or STD.
- * And, in the case of the latter, the memory image should have already
- * been loaded from disk.
- */
- if (pm_state > PM_SUSPEND_STANDBY)
+ /* restore processor state */
+ if (acpi_state == ACPI_STATE_S3)
acpi_restore_state_mem();
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -120,7 +160,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
/**
* acpi_pm_finish - Finish up suspend sequence.
- * @pm_state: State we're coming out of.
+ * @pm_state: ignored
*
* This is called after we wake back up (or if entering the sleep state
* failed).
@@ -128,7 +168,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
static int acpi_pm_finish(suspend_state_t pm_state)
{
- u32 acpi_state = acpi_suspend_states[pm_state];
+ u32 acpi_state = acpi_target_sleep_state;
acpi_leave_sleep_state(acpi_state);
acpi_disable_wakeup_device(acpi_state);
@@ -136,28 +176,17 @@ static int acpi_pm_finish(suspend_state_t pm_state)
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+ acpi_target_sleep_state = ACPI_STATE_S0;
+
+#ifdef CONFIG_X86
if (init_8259A_after_S1) {
printk("Broken toshiba laptop -> kicking interrupts\n");
init_8259A(0);
}
+#endif
return 0;
}
-int acpi_suspend(u32 acpi_state)
-{
- suspend_state_t states[] = {
- [1] = PM_SUSPEND_STANDBY,
- [3] = PM_SUSPEND_MEM,
- [5] = PM_SUSPEND_MAX
- };
-
- if (acpi_state < 6 && states[acpi_state])
- return pm_suspend(states[acpi_state]);
- if (acpi_state == 4)
- return hibernate();
- return -EINVAL;
-}
-
static int acpi_pm_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -176,12 +205,34 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
static struct pm_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid,
+ .set_target = acpi_pm_set_target,
.prepare = acpi_pm_prepare,
.enter = acpi_pm_enter,
.finish = acpi_pm_finish,
};
-#ifdef CONFIG_SOFTWARE_SUSPEND
+/*
+ * Toshiba fails to preserve interrupts over S1, reinitialization
+ * of 8259 is needed after S1 resume.
+ */
+static int __init init_ints_after_s1(const struct dmi_system_id *d)
+{
+ printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
+ init_8259A_after_S1 = 1;
+ return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+ {
+ .callback = init_ints_after_s1,
+ .ident = "Toshiba Satellite 4030cdt",
+ .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
+ },
+ {},
+};
+#endif /* CONFIG_SUSPEND */
+
+#ifdef CONFIG_HIBERNATION
static int acpi_hibernation_prepare(void)
{
return acpi_sleep_prepare(ACPI_STATE_S4);
@@ -210,69 +261,180 @@ static void acpi_hibernation_finish(void)
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+}
- if (init_8259A_after_S1) {
- printk("Broken toshiba laptop -> kicking interrupts\n");
- init_8259A(0);
- }
+static int acpi_hibernation_pre_restore(void)
+{
+ acpi_status status;
+
+ status = acpi_hw_disable_all_gpes();
+
+ return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_restore_cleanup(void)
+{
+ acpi_hw_enable_all_runtime_gpes();
}
static struct hibernation_ops acpi_hibernation_ops = {
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
.finish = acpi_hibernation_finish,
+ .pre_restore = acpi_hibernation_pre_restore,
+ .restore_cleanup = acpi_hibernation_restore_cleanup,
};
-#endif /* CONFIG_SOFTWARE_SUSPEND */
+#endif /* CONFIG_HIBERNATION */
-/*
- * Toshiba fails to preserve interrupts over S1, reinitialization
- * of 8259 is needed after S1 resume.
+int acpi_suspend(u32 acpi_state)
+{
+ suspend_state_t states[] = {
+ [1] = PM_SUSPEND_STANDBY,
+ [3] = PM_SUSPEND_MEM,
+ [5] = PM_SUSPEND_MAX
+ };
+
+ if (acpi_state < 6 && states[acpi_state])
+ return pm_suspend(states[acpi_state]);
+ if (acpi_state == 4)
+ return hibernate();
+ return -EINVAL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * acpi_pm_device_sleep_state - return preferred power state of ACPI device
+ * in the system sleep state given by %acpi_target_sleep_state
+ * @dev: device to examine
+ * @wake: if set, the device should be able to wake up the system
+ * @d_min_p: used to store the upper limit of allowed states range
+ * Return value: preferred power state of the device on success, -ENODEV on
+ * failure (ie. if there's no 'struct acpi_device' for @dev)
+ *
+ * Find the lowest power (highest number) ACPI device power state that
+ * device @dev can be in while the system is in the sleep state represented
+ * by %acpi_target_sleep_state. If @wake is nonzero, the device should be
+ * able to wake up the system from this sleep state. If @d_min_p is set,
+ * the highest power (lowest number) device power state of @dev allowed
+ * in this system sleep state is stored at the location pointed to by it.
+ *
+ * The caller must ensure that @dev is valid before using this function.
+ * The caller is also responsible for figuring out if the device is
+ * supposed to be able to wake up the system and passing this information
+ * via @wake.
*/
-static int __init init_ints_after_s1(struct dmi_system_id *d)
+
+int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
{
- printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
- init_8259A_after_S1 = 1;
- return 0;
+ acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+ struct acpi_device *adev;
+ char acpi_method[] = "_SxD";
+ unsigned long d_min, d_max;
+
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+ printk(KERN_DEBUG "ACPI handle has no context!\n");
+ return -ENODEV;
+ }
+
+ acpi_method[2] = '0' + acpi_target_sleep_state;
+ /*
+ * If the sleep state is S0, we will return D3, but if the device has
+ * _S0W, we will use the value from _S0W
+ */
+ d_min = ACPI_STATE_D0;
+ d_max = ACPI_STATE_D3;
+
+ /*
+ * If present, _SxD methods return the minimum D-state (highest power
+ * state) we can use for the corresponding S-states. Otherwise, the
+ * minimum D-state is D0 (ACPI 3.x).
+ *
+ * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
+ * provided -- that's our fault recovery, we ignore retval.
+ */
+ if (acpi_target_sleep_state > ACPI_STATE_S0)
+ acpi_evaluate_integer(handle, acpi_method, NULL, &d_min);
+
+ /*
+ * If _PRW says we can wake up the system from the target sleep state,
+ * the D-state returned by _SxD is sufficient for that (we assume a
+ * wakeup-aware driver if wake is set). Still, if _SxW exists
+ * (ACPI 3.x), it should return the maximum (lowest power) D-state that
+ * can wake the system. _S0W may be valid, too.
+ */
+ if (acpi_target_sleep_state == ACPI_STATE_S0 ||
+ (wake && adev->wakeup.state.enabled &&
+ adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
+ acpi_method[3] = 'W';
+ acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
+ /* Sanity check */
+ if (d_max < d_min)
+ d_min = d_max;
+ }
+
+ if (d_min_p)
+ *d_min_p = d_min;
+ return d_max;
}
+#endif
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
- {
- .callback = init_ints_after_s1,
- .ident = "Toshiba Satellite 4030cdt",
- .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
- },
- {},
-};
+static void acpi_power_off_prepare(void)
+{
+ /* Prepare to power off the system */
+ acpi_sleep_prepare(ACPI_STATE_S5);
+}
+
+static void acpi_power_off(void)
+{
+ /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
+ printk("%s called\n", __FUNCTION__);
+ local_irq_disable();
+ acpi_enter_sleep_state(ACPI_STATE_S5);
+}
int __init acpi_sleep_init(void)
{
+ acpi_status status;
+ u8 type_a, type_b;
+#ifdef CONFIG_SUSPEND
int i = 0;
dmi_check_system(acpisleep_dmi_table);
+#endif
if (acpi_disabled)
return 0;
- printk(KERN_INFO PREFIX "(supports");
- for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
- acpi_status status;
- u8 type_a, type_b;
+ sleep_states[ACPI_STATE_S0] = 1;
+ printk(KERN_INFO PREFIX "(supports S0");
+
+#ifdef CONFIG_SUSPEND
+ for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
status = acpi_get_sleep_type_data(i, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
sleep_states[i] = 1;
printk(" S%d", i);
}
}
- printk(")\n");
pm_set_ops(&acpi_pm_ops);
+#endif
-#ifdef CONFIG_SOFTWARE_SUSPEND
- if (sleep_states[ACPI_STATE_S4])
+#ifdef CONFIG_HIBERNATION
+ status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+ if (ACPI_SUCCESS(status)) {
hibernation_set_ops(&acpi_hibernation_ops);
-#else
- sleep_states[ACPI_STATE_S4] = 0;
+ sleep_states[ACPI_STATE_S4] = 1;
+ printk(" S4");
+ }
#endif
-
+ status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
+ if (ACPI_SUCCESS(status)) {
+ sleep_states[ACPI_STATE_S5] = 1;
+ printk(" S5");
+ pm_power_off_prepare = acpi_power_off_prepare;
+ pm_power_off = acpi_power_off;
+ }
+ printk(")\n");
return 0;
}
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
deleted file mode 100644
index d9801eff6489..000000000000
--- a/drivers/acpi/sleep/poweroff.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * poweroff.c - ACPI handler for powering off the system.
- *
- * AKA S5, but it is independent of whether or not the kernel supports
- * any other sleep support in the system.
- *
- * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
- *
- * This file is released under the GPLv2.
- */
-
-#include <linux/pm.h>
-#include <linux/init.h>
-#include <acpi/acpi_bus.h>
-#include <linux/sysdev.h>
-#include <asm/io.h>
-#include "sleep.h"
-
-int acpi_sleep_prepare(u32 acpi_state)
-{
-#ifdef CONFIG_ACPI_SLEEP
- /* do we have a wakeup address for S2 and S3? */
- if (acpi_state == ACPI_STATE_S3) {
- if (!acpi_wakeup_address) {
- return -EFAULT;
- }
- acpi_set_firmware_waking_vector((acpi_physical_address)
- virt_to_phys((void *)
- acpi_wakeup_address));
-
- }
- ACPI_FLUSH_CPU_CACHE();
- acpi_enable_wakeup_device_prep(acpi_state);
-#endif
- acpi_gpe_sleep_prepare(acpi_state);
- acpi_enter_sleep_state_prep(acpi_state);
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-void acpi_power_off(void)
-{
- /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
- printk("%s called\n", __FUNCTION__);
- local_irq_disable();
- /* Some SMP machines only can poweroff in boot CPU */
- acpi_enter_sleep_state(ACPI_STATE_S5);
-}
-
-static int acpi_shutdown(struct sys_device *x)
-{
- switch (system_state) {
- case SYSTEM_POWER_OFF:
- /* Prepare to power off the system */
- return acpi_sleep_prepare(ACPI_STATE_S5);
- case SYSTEM_SUSPEND_DISK:
- /* Prepare to suspend the system to disk */
- return acpi_sleep_prepare(ACPI_STATE_S4);
- default:
- return 0;
- }
-}
-
-static struct sysdev_class acpi_sysclass = {
- set_kset_name("acpi"),
- .shutdown = acpi_shutdown
-};
-
-static struct sys_device device_acpi = {
- .id = 0,
- .cls = &acpi_sysclass,
-};
-
-static int acpi_poweroff_init(void)
-{
- if (!acpi_disabled) {
- u8 type_a, type_b;
- acpi_status status;
-
- status =
- acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
- int error;
- error = sysdev_class_register(&acpi_sysclass);
- if (!error)
- error = sysdev_register(&device_acpi);
- if (!error)
- pm_power_off = acpi_power_off;
- return error;
- }
- }
- return 0;
-}
-
-late_initcall(acpi_poweroff_init);
-
-#endif /* CONFIG_PM */
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 61f1822cc350..3839efd5eaea 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -14,8 +14,16 @@
#include "sleep.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
+
+/*
+ * this file provides support for:
+ * /proc/acpi/sleep
+ * /proc/acpi/alarm
+ * /proc/acpi/wakeup
+ */
+
ACPI_MODULE_NAME("sleep")
-#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
{
int i;
@@ -58,7 +66,7 @@ acpi_system_write_sleep(struct file *file,
goto Done;
}
state = simple_strtoul(str, NULL, 0);
-#ifdef CONFIG_SOFTWARE_SUSPEND
+#ifdef CONFIG_HIBERNATION
if (state == 4) {
error = hibernate();
goto Done;
@@ -68,9 +76,9 @@ acpi_system_write_sleep(struct file *file,
Done:
return error ? error : count;
}
-#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#endif /* CONFIG_ACPI_PROCFS */
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86)
/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
#else
#define HAVE_ACPI_LEGACY_ALARM
@@ -463,7 +471,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = {
.release = single_release,
};
-#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_system_sleep_fops = {
.open = acpi_system_sleep_open_fs,
.read = seq_read,
@@ -471,7 +479,7 @@ static const struct file_operations acpi_system_sleep_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
static const struct file_operations acpi_system_alarm_fops = {
@@ -498,14 +506,14 @@ static int __init acpi_sleep_proc_init(void)
if (acpi_disabled)
return 0;
-#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
+#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;
-#endif
+#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
/* 'alarm' [R/W] */
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
index f3e70397a7d6..ff1f8504f497 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep/sleep.h
@@ -6,3 +6,5 @@ extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
extern void acpi_enable_wakeup_device(u8 sleep_state);
extern void acpi_disable_wakeup_device(u8 sleep_state);
extern void acpi_gpe_sleep_prepare(u32 sleep_state);
+
+extern int acpi_sleep_prepare(u32 acpi_state);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index fab8f2694f03..97c27ddb144d 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -17,7 +17,6 @@ ACPI_MODULE_NAME("wakeup_devices")
extern struct list_head acpi_wakeup_device_list;
extern spinlock_t acpi_device_lock;
-#ifdef CONFIG_ACPI_SLEEP
/**
* acpi_enable_wakeup_device_prep - prepare wakeup devices
* @sleep_state: ACPI state
@@ -180,7 +179,6 @@ static int __init acpi_wakeup_device_init(void)
}
late_initcall(acpi_wakeup_device_init);
-#endif
/*
* Disable all wakeup GPEs before entering requested sleep state.
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 83a8d3097904..edee2806e37b 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -39,15 +39,12 @@ ACPI_MODULE_NAME("system");
#define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DEVICE_NAME "System"
-#define ACPI_SYSTEM_FILE_INFO "info"
-#define ACPI_SYSTEM_FILE_EVENT "event"
-#define ACPI_SYSTEM_FILE_DSDT "dsdt"
-#define ACPI_SYSTEM_FILE_FADT "fadt"
/*
* Make ACPICA version work as module param
*/
-static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
+{
int result;
result = sprintf(buffer, "%x", ACPI_CA_VERSION);
@@ -58,9 +55,126 @@ static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
/* --------------------------------------------------------------------------
+ FS Interface (/sys)
+ -------------------------------------------------------------------------- */
+static LIST_HEAD(acpi_table_attr_list);
+static struct kobject tables_kobj;
+
+struct acpi_table_attr {
+ struct bin_attribute attr;
+ char name[8];
+ int instance;
+ struct list_head node;
+};
+
+static ssize_t acpi_table_show(struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ struct acpi_table_attr *table_attr =
+ container_of(bin_attr, struct acpi_table_attr, attr);
+ struct acpi_table_header *table_header = NULL;
+ acpi_status status;
+ ssize_t ret_count = count;
+
+ status =
+ acpi_get_table(table_attr->name, table_attr->instance,
+ &table_header);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if (offset >= table_header->length) {
+ ret_count = 0;
+ goto end;
+ }
+
+ if (offset + ret_count > table_header->length)
+ ret_count = table_header->length - offset;
+
+ memcpy(buf, ((char *)table_header) + offset, ret_count);
+
+ end:
+ return ret_count;
+}
+
+static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
+ struct acpi_table_header *table_header)
+{
+ struct acpi_table_header *header = NULL;
+ struct acpi_table_attr *attr = NULL;
+
+ memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);
+
+ list_for_each_entry(attr, &acpi_table_attr_list, node) {
+ if (!memcmp(table_header->signature, attr->name,
+ ACPI_NAME_SIZE))
+ if (table_attr->instance < attr->instance)
+ table_attr->instance = attr->instance;
+ }
+ table_attr->instance++;
+
+ if (table_attr->instance > 1 || (table_attr->instance == 1 &&
+ !acpi_get_table(table_header->
+ signature, 2,
+ &header)))
+ sprintf(table_attr->name + 4, "%d", table_attr->instance);
+
+ table_attr->attr.size = 0;
+ table_attr->attr.read = acpi_table_show;
+ table_attr->attr.attr.name = table_attr->name;
+ table_attr->attr.attr.mode = 0444;
+ table_attr->attr.attr.owner = THIS_MODULE;
+
+ return;
+}
+
+static int acpi_system_sysfs_init(void)
+{
+ struct acpi_table_attr *table_attr;
+ struct acpi_table_header *table_header = NULL;
+ int table_index = 0;
+ int result;
+
+ tables_kobj.parent = &acpi_subsys.kobj;
+ kobject_set_name(&tables_kobj, "tables");
+ result = kobject_register(&tables_kobj);
+ if (result)
+ return result;
+
+ do {
+ result = acpi_get_table_by_index(table_index, &table_header);
+ if (!result) {
+ table_index++;
+ table_attr = NULL;
+ table_attr =
+ kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
+ if (!table_attr)
+ return -ENOMEM;
+
+ acpi_table_attr_init(table_attr, table_header);
+ result =
+ sysfs_create_bin_file(&tables_kobj,
+ &table_attr->attr);
+ if (result) {
+ kfree(table_attr);
+ return result;
+ } else
+ list_add_tail(&table_attr->node,
+ &acpi_table_attr_list);
+ }
+ } while (!result);
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_INFO "info"
+#define ACPI_SYSTEM_FILE_EVENT "event"
+#define ACPI_SYSTEM_FILE_DSDT "dsdt"
+#define ACPI_SYSTEM_FILE_FADT "fadt"
static int acpi_system_read_info(struct seq_file *seq, void *offset)
{
@@ -80,7 +194,6 @@ static const struct file_operations acpi_system_info_ops = {
.llseek = seq_lseek,
.release = single_release,
};
-#endif
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
@@ -97,13 +210,11 @@ acpi_system_read_dsdt(struct file *file,
struct acpi_table_header *dsdt = NULL;
ssize_t res;
-
status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
return -ENODEV;
- res = simple_read_from_buffer(buffer, count, ppos,
- dsdt, dsdt->length);
+ res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
return res;
}
@@ -123,28 +234,21 @@ acpi_system_read_fadt(struct file *file,
struct acpi_table_header *fadt = NULL;
ssize_t res;
-
status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
return -ENODEV;
- res = simple_read_from_buffer(buffer, count, ppos,
- fadt, fadt->length);
+ res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
return res;
}
-static int __init acpi_system_init(void)
+static int acpi_system_procfs_init(void)
{
struct proc_dir_entry *entry;
int error = 0;
char *name;
-
- if (acpi_disabled)
- return 0;
-
-#ifdef CONFIG_ACPI_PROCFS
/* 'info' [R] */
name = ACPI_SYSTEM_FILE_INFO;
entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -153,7 +257,6 @@ static int __init acpi_system_init(void)
else {
entry->proc_fops = &acpi_system_info_ops;
}
-#endif
/* 'dsdt' [R] */
name = ACPI_SYSTEM_FILE_DSDT;
@@ -177,12 +280,32 @@ static int __init acpi_system_init(void)
Error:
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
-#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
-#endif
error = -EFAULT;
goto Done;
}
+#else
+static int acpi_system_procfs_init(void)
+{
+ return 0;
+}
+#endif
+
+static int __init acpi_system_init(void)
+{
+ int result = 0;
+
+ if (acpi_disabled)
+ return 0;
+
+ result = acpi_system_procfs_init();
+ if (result)
+ return result;
+
+ result = acpi_system_sysfs_init();
+
+ return result;
+}
subsys_initcall(acpi_system_init);
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 1285e91474fb..002bb33003af 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -211,14 +211,17 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
* DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
* Performs validation on some important FADT fields.
*
+ * NOTE: We create a local copy of the FADT regardless of the version.
+ *
******************************************************************************/
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
{
/*
- * Check if the FADT is larger than what we know about (ACPI 2.0 version).
- * Truncate the table, but make some noise.
+ * Check if the FADT is larger than the largest table that we expect
+ * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
+ * a warning.
*/
if (length > sizeof(struct acpi_table_fadt)) {
ACPI_WARNING((AE_INFO,
@@ -227,10 +230,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
sizeof(struct acpi_table_fadt)));
}
- /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+ /* Clear the entire local FADT */
ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+ /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
+
ACPI_MEMCPY(&acpi_gbl_FADT, table,
ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
@@ -251,7 +256,7 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
* RETURN: None
*
* DESCRIPTION: Converts all versions of the FADT to a common internal format.
- * -> Expand all 32-bit addresses to 64-bit.
+ * Expand all 32-bit addresses to 64-bit.
*
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
* and must contain a copy of the actual FADT.
@@ -292,8 +297,23 @@ static void acpi_tb_convert_fadt(void)
}
/*
- * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
- * structures as necessary.
+ * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
+ * should be zero are indeed zero. This will workaround BIOSs that
+ * inadvertently place values in these fields.
+ *
+ * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
+ * offset 45, 55, 95, and the word located at offset 109, 110.
+ */
+ if (acpi_gbl_FADT.header.revision < 3) {
+ acpi_gbl_FADT.preferred_profile = 0;
+ acpi_gbl_FADT.pstate_control = 0;
+ acpi_gbl_FADT.cst_control = 0;
+ acpi_gbl_FADT.boot_flags = 0;
+ }
+
+ /*
+ * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
+ * generic address structures as necessary.
*/
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
target =
@@ -349,18 +369,6 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_FADT.xpm1a_event_block.space_id;
}
-
- /*
- * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
- * are indeed zero. This will workaround BIOSs that inadvertently placed
- * values in these fields.
- */
- if (acpi_gbl_FADT.header.revision < 3) {
- acpi_gbl_FADT.preferred_profile = 0;
- acpi_gbl_FADT.pstate_control = 0;
- acpi_gbl_FADT.cst_control = 0;
- acpi_gbl_FADT.boot_flags = 0;
- }
}
/******************************************************************************
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 1da64b4518c0..8cc9492ffbf2 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -51,6 +51,65 @@ ACPI_MODULE_NAME("tbutils")
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,
acpi_native_uint table_entry_size);
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_check_xsdt
+ *
+ * PARAMETERS: address - Pointer to the XSDT
+ *
+ * RETURN: status
+ * AE_OK - XSDT is okay
+ * AE_NO_MEMORY - can't map XSDT
+ * AE_INVALID_TABLE_LENGTH - invalid table length
+ * AE_NULL_ENTRY - XSDT has NULL entry
+ *
+ * DESCRIPTION: validate XSDT
+******************************************************************************/
+
+static acpi_status
+acpi_tb_check_xsdt(acpi_physical_address address)
+{
+ struct acpi_table_header *table;
+ u32 length;
+ u64 xsdt_entry_address;
+ u8 *table_entry;
+ u32 table_count;
+ int i;
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table)
+ return AE_NO_MEMORY;
+
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+ if (length < sizeof(struct acpi_table_header))
+ return AE_INVALID_TABLE_LENGTH;
+
+ table = acpi_os_map_memory(address, length);
+ if (!table)
+ return AE_NO_MEMORY;
+
+ /* Calculate the number of tables described in XSDT */
+ table_count =
+ (u32) ((table->length -
+ sizeof(struct acpi_table_header)) / sizeof(u64));
+ table_entry =
+ ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+ for (i = 0; i < table_count; i++) {
+ ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
+ if (!xsdt_entry_address) {
+ /* XSDT has NULL entry */
+ break;
+ }
+ table_entry += sizeof(u64);
+ }
+ acpi_os_unmap_memory(table, length);
+
+ if (i < table_count)
+ return AE_NULL_ENTRY;
+ else
+ return AE_OK;
+}
/*******************************************************************************
*
@@ -341,6 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
+ acpi_physical_address rsdt_address;
u32 length;
u8 *table_entry;
acpi_status status;
@@ -369,6 +429,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
*/
address = (acpi_physical_address) rsdp->xsdt_physical_address;
table_entry_size = sizeof(u64);
+ rsdt_address = (acpi_physical_address)
+ rsdp->rsdt_physical_address;
} else {
/* Root table is an RSDT (32-bit physical addresses) */
@@ -382,6 +444,15 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
*/
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+ if (table_entry_size == sizeof(u64)) {
+ if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) {
+ /* XSDT has NULL entry, RSDT is used */
+ address = rsdt_address;
+ table_entry_size = sizeof(u32);
+ ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry,"
+ "using RSDT"));
+ }
+ }
/* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 5b302c4e293f..a9e3331fee5d 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -52,6 +52,8 @@ ACPI_MODULE_NAME("tbxface")
/* Local prototypes */
static acpi_status acpi_tb_load_namespace(void);
+static int no_auto_ssdt;
+
/*******************************************************************************
*
* FUNCTION: acpi_allocate_root_table
@@ -536,6 +538,10 @@ static acpi_status acpi_tb_load_namespace(void)
ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
acpi_tb_print_table_header(0, table);
+
+ if (no_auto_ssdt == 0) {
+ printk(KERN_WARNING "ACPI: DSDT override uses original SSDTs unless \"acpi_no_auto_ssdt\"");
+ }
}
status =
@@ -577,6 +583,11 @@ static acpi_status acpi_tb_load_namespace(void)
continue;
}
+ if (no_auto_ssdt) {
+ printk(KERN_WARNING "ACPI: SSDT ignored due to \"acpi_no_auto_ssdt\"\n");
+ continue;
+ }
+
/* Ignore errors while loading tables, get as many as possible */
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
@@ -622,3 +633,15 @@ acpi_status acpi_load_tables(void)
}
ACPI_EXPORT_SYMBOL(acpi_load_tables)
+
+
+static int __init acpi_no_auto_ssdt_setup(char *s) {
+
+ printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
+
+ no_auto_ssdt = 1;
+
+ return 1;
+}
+
+__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 88a6fc7fd271..ad898e10c1a9 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -33,6 +33,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
@@ -40,6 +41,7 @@
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/seq_file.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -59,7 +61,6 @@
#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
#define ACPI_THERMAL_NOTIFY_HOT 0xF1
#define ACPI_THERMAL_MODE_ACTIVE 0x00
-#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
#define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
@@ -74,9 +75,29 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
MODULE_LICENSE("GPL");
+static int act;
+module_param(act, int, 0644);
+MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
+
+static int crt;
+module_param(crt, int, 0644);
+MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
+
static int tzp;
-module_param(tzp, int, 0);
-MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
+module_param(tzp, int, 0444);
+MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
+
+static int nocrt;
+module_param(nocrt, int, 0);
+MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
+
+static int off;
+module_param(off, int, 0);
+MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
+
+static int psv;
+module_param(psv, int, 0644);
+MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device, int type);
@@ -92,10 +113,16 @@ static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
size_t, loff_t *);
+static const struct acpi_device_id thermal_device_ids[] = {
+ {ACPI_THERMAL_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
+
static struct acpi_driver acpi_thermal_driver = {
.name = "thermal",
.class = ACPI_THERMAL_CLASS,
- .ids = ACPI_THERMAL_HID,
+ .ids = thermal_device_ids,
.ops = {
.add = acpi_thermal_add,
.remove = acpi_thermal_remove,
@@ -317,6 +344,20 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
tz->trips.critical.temperature));
}
+ if (tz->trips.critical.flags.valid == 1) {
+ if (crt == -1) {
+ tz->trips.critical.flags.valid = 0;
+ } else if (crt > 0) {
+ unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+
+ /*
+ * Allow override to lower critical threshold
+ */
+ if (crt_k < tz->trips.critical.temperature)
+ tz->trips.critical.temperature = crt_k;
+ }
+ }
+
/* Critical Sleep (optional) */
status =
@@ -333,9 +374,16 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
/* Passive: Processors (optional) */
- status =
- acpi_evaluate_integer(tz->device->handle, "_PSV", NULL,
- &tz->trips.passive.temperature);
+ if (psv == -1) {
+ status = AE_SUPPORT;
+ } else if (psv > 0) {
+ tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+ status = AE_OK;
+ } else {
+ status = acpi_evaluate_integer(tz->device->handle,
+ "_PSV", NULL, &tz->trips.passive.temperature);
+ }
+
if (ACPI_FAILURE(status)) {
tz->trips.passive.flags.valid = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
@@ -380,11 +428,33 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
- status =
- acpi_evaluate_integer(tz->device->handle, name, NULL,
- &tz->trips.active[i].temperature);
- if (ACPI_FAILURE(status))
+ if (act == -1)
+ break; /* disable all active trip points */
+
+ status = acpi_evaluate_integer(tz->device->handle,
+ name, NULL, &tz->trips.active[i].temperature);
+
+ if (ACPI_FAILURE(status)) {
+ if (i == 0) /* no active trip points */
+ break;
+ if (act <= 0) /* no override requested */
+ break;
+ if (i == 1) { /* 1 trip point */
+ tz->trips.active[0].temperature =
+ CELSIUS_TO_KELVIN(act);
+ } else { /* multiple trips */
+ /*
+ * Don't allow override higher than
+ * the next higher trip point
+ */
+ tz->trips.active[i - 1].temperature =
+ (tz->trips.active[i - 2].temperature <
+ CELSIUS_TO_KELVIN(act) ?
+ tz->trips.active[i - 2].temperature :
+ CELSIUS_TO_KELVIN(act));
+ }
break;
+ }
name[2] = 'L';
status =
@@ -419,29 +489,9 @@ static int acpi_thermal_get_devices(struct acpi_thermal *tz)
return 0;
}
-static int acpi_thermal_call_usermode(char *path)
-{
- char *argv[2] = { NULL, NULL };
- char *envp[3] = { NULL, NULL, NULL };
-
-
- if (!path)
- return -EINVAL;
-
- argv[0] = path;
-
- /* minimal command environment */
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- call_usermodehelper(argv[0], argv, envp, 0);
-
- return 0;
-}
-
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
- if (!tz || !tz->trips.critical.flags.valid)
+ if (!tz || !tz->trips.critical.flags.valid || nocrt)
return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) {
@@ -453,17 +503,21 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
printk(KERN_EMERG
"Critical temperature reached (%ld C), shutting down.\n",
KELVIN_TO_CELSIUS(tz->temperature));
- acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
+ acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
+ acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+ tz->device->dev.bus_id,
+ ACPI_THERMAL_NOTIFY_CRITICAL,
+ tz->trips.critical.flags.enabled);
- acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+ orderly_poweroff(true);
return 0;
}
static int acpi_thermal_hot(struct acpi_thermal *tz)
{
- if (!tz || !tz->trips.hot.flags.valid)
+ if (!tz || !tz->trips.hot.flags.valid || nocrt)
return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) {
@@ -472,8 +526,12 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
} else if (tz->trips.hot.flags.enabled)
tz->trips.hot.flags.enabled = 0;
- acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
+ acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
tz->trips.hot.flags.enabled);
+ acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+ tz->device->dev.bus_id,
+ ACPI_THERMAL_NOTIFY_HOT,
+ tz->trips.hot.flags.enabled);
/* TBD: Call user-mode "sleep(S4)" function */
@@ -838,12 +896,14 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
goto end;
if (tz->trips.critical.flags.valid)
- seq_printf(seq, "critical (S5): %ld C\n",
- KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
+ seq_printf(seq, "critical (S5): %ld C%s",
+ KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
+ nocrt ? " <disabled>\n" : "\n");
if (tz->trips.hot.flags.valid)
- seq_printf(seq, "hot (S4): %ld C\n",
- KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
+ seq_printf(seq, "hot (S4): %ld C%s",
+ KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
+ nocrt ? " <disabled>\n" : "\n");
if (tz->trips.passive.flags.valid) {
seq_printf(seq,
@@ -1033,9 +1093,9 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
entry->owner = THIS_MODULE;
}
- /* 'trip_points' [R/W] */
+ /* 'trip_points' [R] */
entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
- S_IFREG | S_IRUGO | S_IWUSR,
+ S_IRUGO,
acpi_device_dir(device));
if (!entry)
return -ENODEV;
@@ -1115,12 +1175,16 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
case ACPI_THERMAL_NOTIFY_THRESHOLDS:
acpi_thermal_get_trip_points(tz);
acpi_thermal_check(tz);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
break;
case ACPI_THERMAL_NOTIFY_DEVICES:
if (tz->flags.devices)
acpi_thermal_get_devices(tz);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1295,11 +1359,93 @@ static int acpi_thermal_resume(struct acpi_device *device)
return AE_OK;
}
+#ifdef CONFIG_DMI
+static int thermal_act(const struct dmi_system_id *d) {
+
+ if (act == 0) {
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "disabling all active thermal trip points\n", d->ident);
+ act = -1;
+ }
+ return 0;
+}
+static int thermal_nocrt(const struct dmi_system_id *d) {
+
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "disabling all critical thermal trip point actions.\n", d->ident);
+ nocrt = 1;
+ return 0;
+}
+static int thermal_tzp(const struct dmi_system_id *d) {
+
+ if (tzp == 0) {
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "enabling thermal zone polling\n", d->ident);
+ tzp = 300; /* 300 dS = 30 Seconds */
+ }
+ return 0;
+}
+static int thermal_psv(const struct dmi_system_id *d) {
+
+ if (psv == 0) {
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "disabling all passive thermal trip points\n", d->ident);
+ psv = -1;
+ }
+ return 0;
+}
+
+static struct dmi_system_id thermal_dmi_table[] __initdata = {
+ /*
+ * Award BIOS on this AOpen makes thermal control almost worthless.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=8842
+ */
+ {
+ .callback = thermal_act,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = thermal_psv,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = thermal_tzp,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = thermal_nocrt,
+ .ident = "Gigabyte GA-7ZX",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
+ },
+ },
+ {}
+};
+#endif /* CONFIG_DMI */
+
static int __init acpi_thermal_init(void)
{
int result = 0;
+ dmi_check_system(thermal_dmi_table);
+ if (off) {
+ printk(KERN_NOTICE "ACPI: thermal control disabled\n");
+ return -ENODEV;
+ }
acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
if (!acpi_thermal_dir)
return -ENODEV;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 8ec6f8e48138..0042b7e78b26 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -62,16 +62,13 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
static char *acpi_interfaces_supported[] = {
/* Operating System Vendor Strings */
- "Windows 2000",
- "Windows 2001",
- "Windows 2001 SP0",
- "Windows 2001 SP1",
- "Windows 2001 SP2",
- "Windows 2001 SP3",
- "Windows 2001 SP4",
- "Windows 2001.1",
- "Windows 2001.1 SP1", /* Added 03/2006 */
- "Windows 2006", /* Added 03/2006 */
+ "Windows 2000", /* Windows 2000 */
+ "Windows 2001", /* Windows XP */
+ "Windows 2001 SP1", /* Windows XP SP1 */
+ "Windows 2001 SP2", /* Windows XP SP2 */
+ "Windows 2001.1", /* Windows Server 2003 */
+ "Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */
+ "Windows 2006", /* Windows Vista - Added 03/2006 */
/* Feature Group Strings */
@@ -410,7 +407,7 @@ acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length)
acpi_status
acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
- struct acpi_device_id *hid)
+ struct acpica_device_id *hid)
{
union acpi_operand_object *obj_desc;
acpi_status status;
@@ -612,7 +609,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
acpi_status
acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
- struct acpi_device_id *uid)
+ struct acpica_device_id *uid)
{
union acpi_operand_object *obj_desc;
acpi_status status;
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 1621655d6e2b..93ea8290b4f7 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -126,6 +126,7 @@ const char *acpi_format_exception(acpi_status status)
"Unknown exception code: 0x%8.8X", status));
exception = "UNKNOWN_STATUS_CODE";
+ dump_stack();
}
return (ACPI_CAST_PTR(const char, exception));
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 00d25b347255..b8a2095cb5ee 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -31,8 +31,9 @@
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-
+#include <linux/input.h>
#include <linux/backlight.h>
+#include <linux/video_output.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -73,10 +74,16 @@ MODULE_LICENSE("GPL");
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
+static const struct acpi_device_id video_device_ids[] = {
+ {ACPI_VIDEO_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, video_device_ids);
+
static struct acpi_driver acpi_video_bus = {
.name = "video",
.class = ACPI_VIDEO_CLASS,
- .ids = ACPI_VIDEO_HID,
+ .ids = video_device_ids,
.ops = {
.add = acpi_video_bus_add,
.remove = acpi_video_bus_remove,
@@ -131,6 +138,8 @@ struct acpi_video_bus {
struct semaphore sem;
struct list_head video_device_list;
struct proc_dir_entry *dir;
+ struct input_dev *input;
+ char phys[32]; /* for input device */
};
struct acpi_video_device_flags {
@@ -169,6 +178,7 @@ struct acpi_video_device {
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight;
+ struct output_device *output_dev;
};
/* bus */
@@ -272,13 +282,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
+static int acpi_video_device_get_state(struct acpi_video_device *device,
+ unsigned long *state);
+static int acpi_video_output_get(struct output_device *od);
+static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
/*backlight device sysfs support*/
static int acpi_video_get_brightness(struct backlight_device *bd)
{
unsigned long cur_level;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ (struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_get_level_current(vd, &cur_level);
return (int) cur_level;
}
@@ -287,7 +301,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd)
{
int request_level = bd->props.brightness;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ (struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_set_level(vd, request_level);
return 0;
}
@@ -297,6 +311,28 @@ static struct backlight_ops acpi_backlight_ops = {
.update_status = acpi_video_set_brightness,
};
+/*video output device sysfs support*/
+static int acpi_video_output_get(struct output_device *od)
+{
+ unsigned long state;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
+ acpi_video_device_get_state(vd, &state);
+ return (int)state;
+}
+
+static int acpi_video_output_set(struct output_device *od)
+{
+ unsigned long state = od->request_state;
+ struct acpi_video_device *vd=
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
+ return acpi_video_device_set_state(vd, state);
+}
+
+static struct output_properties acpi_output_properties = {
+ .set_state = acpi_video_output_set,
+ .get_status = acpi_video_output_get,
+};
/* --------------------------------------------------------------------------
Video Management
-------------------------------------------------------------------------- */
@@ -381,7 +417,6 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
arg0.integer.value = level;
status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
- printk(KERN_DEBUG "set_level status: %x\n", status);
return status;
}
@@ -531,7 +566,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
static void acpi_video_device_find_cap(struct acpi_video_device *device)
{
- acpi_integer status;
acpi_handle h_dummy1;
int i;
u32 max_level = 0;
@@ -565,50 +599,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
device->cap._DSS = 1;
}
- status = acpi_video_device_lcd_query_levels(device, &obj);
-
- if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
- int count = 0;
- union acpi_object *o;
-
- br = kzalloc(sizeof(*br), GFP_KERNEL);
- if (!br) {
- printk(KERN_ERR "can't allocate memory\n");
- } else {
- br->levels = kmalloc(obj->package.count *
- sizeof *(br->levels), GFP_KERNEL);
- if (!br->levels)
- goto out;
-
- for (i = 0; i < obj->package.count; i++) {
- o = (union acpi_object *)&obj->package.
- elements[i];
- if (o->type != ACPI_TYPE_INTEGER) {
- printk(KERN_ERR PREFIX "Invalid data\n");
- continue;
- }
- br->levels[count] = (u32) o->integer.value;
- if (br->levels[count] > max_level)
- max_level = br->levels[count];
- count++;
- }
- out:
- if (count < 2) {
- kfree(br->levels);
- kfree(br);
+ if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
+
+ if (obj->package.count >= 2) {
+ int count = 0;
+ union acpi_object *o;
+
+ br = kzalloc(sizeof(*br), GFP_KERNEL);
+ if (!br) {
+ printk(KERN_ERR "can't allocate memory\n");
} else {
- br->count = count;
- device->brightness = br;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "found %d brightness levels\n",
- count));
+ br->levels = kmalloc(obj->package.count *
+ sizeof *(br->levels), GFP_KERNEL);
+ if (!br->levels)
+ goto out;
+
+ for (i = 0; i < obj->package.count; i++) {
+ o = (union acpi_object *)&obj->package.
+ elements[i];
+ if (o->type != ACPI_TYPE_INTEGER) {
+ printk(KERN_ERR PREFIX "Invalid data\n");
+ continue;
+ }
+ br->levels[count] = (u32) o->integer.value;
+
+ if (br->levels[count] > max_level)
+ max_level = br->levels[count];
+ count++;
+ }
+ out:
+ if (count < 2) {
+ kfree(br->levels);
+ kfree(br);
+ } else {
+ br->count = count;
+ device->brightness = br;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "found %d brightness levels\n",
+ count));
+ }
}
}
+
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
}
kfree(obj);
- if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+ if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
unsigned long tmp;
static int count = 0;
char *name;
@@ -626,6 +665,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(name);
}
+ if (device->cap._DCS && device->cap._DSS){
+ static int count = 0;
+ char *name;
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ if (!name)
+ return;
+ sprintf(name, "acpi_video%d", count++);
+ device->output_dev = video_output_register(name,
+ NULL, device, &acpi_output_properties);
+ kfree(name);
+ }
return;
}
@@ -1669,6 +1719,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
backlight_device_unregister(device->backlight);
+ video_output_unregister(device->output_dev);
return 0;
}
@@ -1702,7 +1753,7 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
{
- return acpi_video_bus_DOS(video, 1, 0);
+ return acpi_video_bus_DOS(video, 0, 0);
}
static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
@@ -1714,6 +1765,9 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_video_bus *video = data;
struct acpi_device *device = NULL;
+ struct input_dev *input;
+ int keycode;
+
printk("video bus notify\n");
@@ -1721,11 +1775,13 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
return;
device = video->device;
+ input = video->input;
switch (event) {
case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch,
* most likely via hotkey. */
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_SWITCHVIDEOMODE;
break;
case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video
@@ -1733,22 +1789,38 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
acpi_video_device_enumerate(video);
acpi_video_device_rebind(video);
acpi_video_switch_output(video, event);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_SWITCHVIDEOMODE;
break;
case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
+ acpi_video_switch_output(video, event);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_SWITCHVIDEOMODE;
+ break;
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
+ acpi_video_switch_output(video, event);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_VIDEO_NEXT;
+ break;
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
acpi_video_switch_output(video, event);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_VIDEO_PREV;
break;
default:
+ keycode = KEY_UNKNOWN;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
break;
}
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+
return;
}
@@ -1756,38 +1828,65 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_video_device *video_device = data;
struct acpi_device *device = NULL;
+ struct acpi_video_bus *bus;
+ struct input_dev *input;
+ int keycode;
if (!video_device)
return;
device = video_device->dev;
+ bus = video_device->video;
+ input = bus->input;
switch (event) {
- case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */
- case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */
- acpi_bus_generate_event(device, event, 0);
- break;
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
+ acpi_video_switch_brightness(video_device, event);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_BRIGHTNESS_CYCLE;
+ break;
case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
+ acpi_video_switch_brightness(video_device, event);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_BRIGHTNESSUP;
+ break;
case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
+ acpi_video_switch_brightness(video_device, event);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_BRIGHTNESSDOWN;
+ break;
case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
+ acpi_video_switch_brightness(video_device, event);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_BRIGHTNESS_ZERO;
+ break;
case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
acpi_video_switch_brightness(video_device, event);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ keycode = KEY_DISPLAY_OFF;
break;
default:
+ keycode = KEY_UNKNOWN;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
break;
}
+
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+
return;
}
+static int instance;
static int acpi_video_bus_add(struct acpi_device *device)
{
int result = 0;
acpi_status status = 0;
struct acpi_video_bus *video = NULL;
+ struct input_dev *input;
if (!device)
@@ -1797,6 +1896,13 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (!video)
return -ENOMEM;
+ /* a hack to fix the duplicate name "VID" problem on T61 */
+ if (!strcmp(device->pnp.bus_id, "VID")) {
+ if (instance)
+ device->pnp.bus_id[3] = '0' + instance;
+ instance ++;
+ }
+
video->device = device;
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
@@ -1831,6 +1937,39 @@ static int acpi_video_bus_add(struct acpi_device *device)
goto end;
}
+
+ video->input = input = input_allocate_device();
+
+ snprintf(video->phys, sizeof(video->phys),
+ "%s/video/input0", acpi_device_hid(video->device));
+
+ input->name = acpi_device_name(video->device);
+ input->phys = video->phys;
+ input->id.bustype = BUS_HOST;
+ input->id.product = 0x06;
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
+ set_bit(KEY_VIDEO_NEXT, input->keybit);
+ set_bit(KEY_VIDEO_PREV, input->keybit);
+ set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
+ set_bit(KEY_BRIGHTNESSUP, input->keybit);
+ set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
+ set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
+ set_bit(KEY_DISPLAY_OFF, input->keybit);
+ set_bit(KEY_UNKNOWN, input->keybit);
+ result = input_register_device(input);
+ if (result) {
+ acpi_remove_notify_handler(video->device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_video_bus_notify);
+ acpi_video_bus_stop_devices(video);
+ acpi_video_bus_put_devices(video);
+ kfree(video->attached_array);
+ acpi_video_bus_remove_fs(device);
+ goto end;
+ }
+
+
printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n",
ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
video->flags.multihead ? "yes" : "no",
@@ -1864,6 +2003,7 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
acpi_video_bus_put_devices(video);
acpi_video_bus_remove_fs(device);
+ input_unregister_device(video->input);
kfree(video->attached_array);
kfree(video);
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 268e301775fc..6b94fb7be5f2 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
-static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
+static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct amba_device *pcdev = to_amba_device(dev);
- int retval = 0, i = 0, len = 0;
+ int retval = 0;
- retval = add_uevent_var(envp, nr_env, &i,
- buf, bufsz, &len,
- "AMBA_ID=%08x", pcdev->periphid);
- envp[i] = NULL;
+ retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
return retval;
}
#else
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index d8046a113c37..4672066167e3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -173,6 +173,15 @@ config SATA_INIC162X
help
This option enables support for Initio 162x Serial ATA.
+config PATA_ACPI
+ tristate "ACPI firmware driver for PATA"
+ depends on ATA_ACPI
+ help
+ This option enables an ACPI method driver which drives
+ motherboard PATA controller interfaces through the ACPI
+ firmware in the BIOS. This driver can sometimes handle
+ otherwise unsupported hardware.
+
config PATA_ALI
tristate "ALi PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
@@ -192,16 +201,25 @@ config PATA_AMD
If unsure, say N.
config PATA_ARTOP
- tristate "ARTOP 6210/6260 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ARTOP 6210/6260 PATA support"
+ depends on PCI
help
This option enables support for ARTOP PATA controllers.
If unsure, say N.
+config PATA_AT32
+ tristate "Atmel AVR32 PATA support (Experimental)"
+ depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+ help
+ This option enables support for the IDE devices on the
+ Atmel AT32AP platform.
+
+ If unsure, say N.
+
config PATA_ATIIXP
- tristate "ATI PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ATI PATA support"
+ depends on PCI
help
This option enables support for the ATI ATA interfaces
found on the many ATI chipsets.
@@ -219,8 +237,8 @@ config PATA_CMD640_PCI
If unsure, say N.
config PATA_CMD64X
- tristate "CMD64x PATA support (Very Experimental)"
- depends on PCI&& EXPERIMENTAL
+ tristate "CMD64x PATA support"
+ depends on PCI
help
This option enables support for the CMD64x series chips
except for the CMD640.
@@ -282,8 +300,8 @@ config ATA_GENERIC
If unsure, say N.
config PATA_HPT366
- tristate "HPT 366/368 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "HPT 366/368 PATA support"
+ depends on PCI
help
This option enables support for the HPT 366 and 368
PATA controllers via the new ATA layer.
@@ -432,6 +450,15 @@ config PATA_NS87410
If unsure, say N.
+config PATA_NS87415
+ tristate "Nat Semi NS87415 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the National Semiconductor
+ NS87415 PCI-IDE controller.
+
+ If unsure, say N.
+
config PATA_OPTI
tristate "OPTI621/6215 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
@@ -596,4 +623,20 @@ config PATA_SCC
If unsure, say N.
+config PATA_BF54X
+ tristate "Blackfin 54x ATAPI support"
+ depends on BF542 || BF548 || BF549
+ help
+ This option enables support for the built-in ATAPI controller on
+ Blackfin 54x family chips.
+
+ If unsure, say N.
+
+config PATA_BF54X_DMA
+ bool "DMA mode"
+ depends on PATA_BF54X
+ default y
+ help
+ Enable DMA mode for Blackfin ATAPI controller.
+
endif # ATA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 8149c68ac2c7..2a63645003eb 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
+obj-$(CONFIG_PATA_AT32) += pata_at32.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
@@ -39,6 +40,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
+obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
@@ -61,12 +63,16 @@ 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_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
+# Should be last but two libata driver
+obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
-libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \
+ libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 11e4eb9f304e..10bc3f64c453 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "2.3"
+#define DRV_VERSION "3.0"
enum {
@@ -77,11 +77,10 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
- board_ahci_pi = 1,
- board_ahci_vt8251 = 2,
- board_ahci_ign_iferr = 3,
- board_ahci_sb600 = 4,
- board_ahci_mv = 5,
+ board_ahci_vt8251 = 1,
+ board_ahci_ign_iferr = 2,
+ board_ahci_sb600 = 3,
+ board_ahci_mv = 4,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -97,8 +96,10 @@ enum {
/* HOST_CAP bits */
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
@@ -113,11 +114,11 @@ enum {
PORT_TFDATA = 0x20, /* taskfile data */
PORT_SIG = 0x24, /* device TF signature */
PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR = 0x28, /* SATA phy register block */
PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+ PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
@@ -143,7 +144,8 @@ enum {
PORT_IRQ_IF_ERR |
PORT_IRQ_CONNECT |
PORT_IRQ_PHYRDY |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS |
+ PORT_IRQ_BAD_PMP,
PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
PORT_IRQ_TF_ERR |
PORT_IRQ_HBUS_DATA_ERR,
@@ -153,6 +155,7 @@ enum {
/* PORT_CMD bits */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_PMP = (1 << 17), /* PMP attached */
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
@@ -166,19 +169,22 @@ enum {
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+ /* hpriv->flags bits */
+ AHCI_HFLAG_NO_NCQ = (1 << 0),
+ AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
+ AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
+ AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
+ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
+ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
+ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
+
/* ap->flags bits */
- AHCI_FLAG_NO_NCQ = (1 << 24),
- AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
- AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
- AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
- AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
- AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
- AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */
+ AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
+ AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
};
struct ahci_cmd_hdr {
@@ -197,6 +203,7 @@ struct ahci_sg {
};
struct ahci_host_priv {
+ unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */
u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */
@@ -204,6 +211,7 @@ struct ahci_host_priv {
};
struct ahci_port_priv {
+ struct ata_link *active_link;
struct ahci_cmd_hdr *cmd_slot;
dma_addr_t cmd_slot_dma;
void *cmd_tbl;
@@ -214,10 +222,11 @@ struct ahci_port_priv {
unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
+ u32 intr_mask; /* interrupts to enable */
};
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static void ahci_irq_clear(struct ata_port *ap);
@@ -228,6 +237,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -261,20 +272,17 @@ static struct scsi_host_template ahci_sht = {
};
static const struct ata_port_operations ahci_ops = {
- .port_disable = ata_port_disable,
-
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_clear = ahci_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -285,6 +293,9 @@ static const struct ata_port_operations ahci_ops = {
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
@@ -295,20 +306,17 @@ static const struct ata_port_operations ahci_ops = {
};
static const struct ata_port_operations ahci_vt8251_ops = {
- .port_disable = ata_port_disable,
-
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_clear = ahci_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -319,6 +327,9 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.error_handler = ahci_vt8251_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
@@ -328,53 +339,52 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.port_stop = ahci_port_stop,
};
+#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
+
static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */
{
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
- },
- /* board_ahci_pi */
- {
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_vt8251 */
{
- .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
- AHCI_FLAG_NO_NCQ,
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_vt8251_ops,
},
/* board_ahci_ign_iferr */
{
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_sb600 */
{
- .flags = AHCI_FLAG_COMMON |
- AHCI_FLAG_IGN_SERR_INTERNAL |
- AHCI_FLAG_32BIT_ONLY,
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
+ AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_mv */
{
- .sht = &ahci_sht,
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_MV_PATA),
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
- AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
- AHCI_FLAG_MV_PATA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
@@ -393,23 +403,25 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
- { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
+ { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -417,7 +429,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
- { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+ { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -468,6 +485,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
/* SiS */
{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
@@ -518,7 +543,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
/**
* ahci_save_initial_config - Save and fixup initial config values
* @pdev: target PCI device
- * @pi: associated ATA port info
* @hpriv: host private area to store config values
*
* Some registers containing configuration info might be setup by
@@ -532,7 +556,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
* None.
*/
static void ahci_save_initial_config(struct pci_dev *pdev,
- const struct ata_port_info *pi,
struct ahci_host_priv *hpriv)
{
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
@@ -545,21 +568,23 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
- /* some chips lie about 64bit support */
- if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+ /* some chips have errata preventing 64bit use */
+ if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
- /* fixup zero port_map */
- if (!port_map) {
- port_map = (1 << ahci_nr_ports(cap)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
+ if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do NCQ, turning off CAP_NCQ\n");
+ cap &= ~HOST_CAP_NCQ;
+ }
- /* write the fixed up value to the PI register */
- hpriv->saved_port_map = port_map;
+ if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do PMP, turning off CAP_PMP\n");
+ cap &= ~HOST_CAP_PMP;
}
/*
@@ -567,7 +592,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
* is asserted through the standard AHCI port
* presence register, as bit 4 (counting from 0)
*/
- if (pi->flags & AHCI_FLAG_MV_PATA) {
+ if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
dev_printk(KERN_ERR, &pdev->dev,
"MV_AHCI HACK: port_map %x -> %x\n",
hpriv->port_map,
@@ -577,7 +602,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
/* cross check port_map and cap.n_ports */
- if (pi->flags & AHCI_FLAG_HONOR_PI) {
+ if (port_map) {
u32 tmp_port_map = port_map;
int n_ports = ahci_nr_ports(cap);
@@ -588,17 +613,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
}
- /* Whine if inconsistent. No need to update cap.
- * port_map is used to determine number of ports.
+ /* If n_ports and port_map are inconsistent, whine and
+ * clear port_map and let it be generated from n_ports.
*/
- if (n_ports || tmp_port_map)
+ if (n_ports || tmp_port_map) {
dev_printk(KERN_WARNING, &pdev->dev,
"nr_ports (%u) and implemented port map "
- "(0x%x) don't match\n",
+ "(0x%x) don't match, using nr_ports\n",
ahci_nr_ports(cap), port_map);
- } else {
- /* fabricate port_map from cap.nr_ports */
+ port_map = 0;
+ }
+ }
+
+ /* fabricate port_map from cap.nr_ports */
+ if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
}
/* record values to use during operation */
@@ -625,38 +659,45 @@ static void ahci_restore_initial_config(struct ata_host *host)
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return 0xffffffffU;
- }
+ static const int offset[] = {
+ [SCR_STATUS] = PORT_SCR_STAT,
+ [SCR_CONTROL] = PORT_SCR_CTL,
+ [SCR_ERROR] = PORT_SCR_ERR,
+ [SCR_ACTIVE] = PORT_SCR_ACT,
+ [SCR_NOTIFICATION] = PORT_SCR_NTF,
+ };
+ struct ahci_host_priv *hpriv = ap->host->private_data;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (sc_reg < ARRAY_SIZE(offset) &&
+ (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+ return offset[sc_reg];
+ return 0;
}
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ *val = readl(port_mmio + offset);
+ return 0;
}
+ return -EINVAL;
+}
+
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (offset) {
+ writel(val, port_mmio + offset);
+ return 0;
+ }
+ return -EINVAL;
}
static void ahci_start_engine(struct ata_port *ap)
@@ -817,8 +858,14 @@ static int ahci_reset_controller(struct ata_host *host)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 tmp;
- /* global controller reset */
+ /* we must be in AHCI mode, before using anything
+ * AHCI-specific, such as HOST_RESET.
+ */
tmp = readl(mmio + HOST_CTL);
+ if (!(tmp & HOST_AHCI_EN))
+ writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL);
+
+ /* global controller reset */
if ((tmp & HOST_RESET) == 0) {
writel(tmp | HOST_RESET, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
@@ -885,13 +932,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
static void ahci_init_controller(struct ata_host *host)
{
+ struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int i;
void __iomem *port_mmio;
u32 tmp;
- if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+ if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
port_mmio = __ahci_port_base(host, 4);
writel(0, port_mmio + PORT_IRQ_MASK);
@@ -948,85 +996,115 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
+ int busy, rc;
- if (!(hpriv->cap & HOST_CAP_CLO))
- return -EOPNOTSUPP;
+ /* do we need to kick the port? */
+ busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+ if (!busy && !force_restart)
+ return 0;
+
+ /* stop engine */
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ goto out_restart;
+ /* need to do CLO? */
+ if (!busy) {
+ rc = 0;
+ goto out_restart;
+ }
+
+ if (!(hpriv->cap & HOST_CAP_CLO)) {
+ rc = -EOPNOTSUPP;
+ goto out_restart;
+ }
+
+ /* perform CLO */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_CLO;
writel(tmp, port_mmio + PORT_CMD);
+ rc = 0;
tmp = ata_wait_register(port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO)
- return -EIO;
+ rc = -EIO;
- return 0;
+ /* restart engine */
+ out_restart:
+ ahci_start_engine(ap);
+ return rc;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+ struct ata_taskfile *tf, int is_cmd, u16 flags,
+ unsigned long timeout_msec)
{
+ const u32 cmd_fis_len = 5; /* five dwords */
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
- const u32 cmd_fis_len = 5; /* five dwords */
+ u8 *fis = pp->cmd_tbl;
+ u32 tmp;
+
+ /* prep the command */
+ ata_tf_to_fis(tf, pmp, is_cmd, fis);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+ /* issue & wait */
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+
+ if (timeout_msec) {
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+ 1, timeout_msec);
+ if (tmp & 0x1) {
+ ahci_kick_engine(ap, 1);
+ return -EBUSY;
+ }
+ } else
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ return 0;
+}
+
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ int pmp, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
const char *reason = NULL;
+ unsigned long now, msecs;
struct ata_taskfile tf;
- u32 tmp;
- u8 *fis;
int rc;
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
return 0;
}
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(ap);
- if (rc) {
- reason = "failed to stop engine";
- goto fail_restart;
- }
-
- /* check BUSY/DRQ, perform Command List Override if necessary */
- if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
- rc = ahci_clo(ap);
-
- if (rc == -EOPNOTSUPP) {
- reason = "port busy but CLO unavailable";
- goto fail_restart;
- } else if (rc) {
- reason = "port busy but CLO failed";
- goto fail_restart;
- }
- }
-
- /* restart engine */
- ahci_start_engine(ap);
+ rc = ahci_kick_engine(ap, 1);
+ if (rc)
+ ata_link_printk(link, KERN_WARNING,
+ "failed to reset engine (errno=%d)", rc);
- ata_tf_init(ap->device, &tf);
- fis = pp->cmd_tbl;
+ ata_tf_init(link->device, &tf);
/* issue the first D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0,
- cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+ msecs = 0;
+ now = jiffies;
+ if (time_after(now, deadline))
+ msecs = jiffies_to_msecs(deadline - now);
tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
- if (tmp & 0x1) {
+ if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+ AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
rc = -EIO;
reason = "1st FIS failed";
goto fail;
@@ -1036,14 +1114,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
msleep(1);
/* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+ ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
@@ -1066,16 +1138,26 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class);
return 0;
- fail_restart:
- ahci_start_engine(ap);
fail:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = 0;
+
+ if (link->ap->flags & ATA_FLAG_PMP)
+ pmp = SATA_PMP_CTRL_PORT;
+
+ return ahci_do_softreset(link, class, pmp, deadline);
+}
+
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
@@ -1086,37 +1168,40 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
ahci_stop_engine(ap);
/* clear D2H reception area to properly wait for D2H FIS */
- ata_tf_init(ap->device, &tf);
+ ata_tf_init(link->device, &tf);
tf.command = 0x80;
- ata_tf_to_fis(&tf, d2h_fis, 0);
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
- rc = sata_std_hardreset(ap, class, deadline);
+ rc = sata_std_hardreset(link, class, deadline);
ahci_start_engine(ap);
- if (rc == 0 && ata_port_online(ap))
+ if (rc == 0 && ata_link_online(link))
*class = ahci_dev_classify(ap);
- if (*class == ATA_DEV_UNKNOWN)
+ if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
return rc;
}
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
+ u32 serror;
int rc;
DPRINTK("ENTER\n");
ahci_stop_engine(ap);
- rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline);
/* vt8251 needs SError cleared for the port to operate */
- ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+ ahci_scr_read(ap, SCR_ERROR, &serror);
+ ahci_scr_write(ap, SCR_ERROR, serror);
ahci_start_engine(ap);
@@ -1128,12 +1213,13 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
return rc ?: -EAGAIN;
}
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
{
+ struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
u32 new_tmp, tmp;
- ata_std_postreset(ap, class);
+ ata_std_postreset(link, class);
/* Make sure port's ATAPI bit is set appropriately */
new_tmp = tmp = readl(port_mmio + PORT_CMD);
@@ -1147,6 +1233,12 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
}
}
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ return ahci_do_softreset(link, class, link->pmp, deadline);
+}
+
static u8 ahci_check_status(struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.cmd_addr;
@@ -1205,7 +1297,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1218,7 +1310,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
/*
* Fill in command slot information.
*/
- opts = cmd_fis_len | n_elem << 16;
+ opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
if (qc->tf.flags & ATA_TFLAG_WRITE)
opts |= AHCI_CMD_WRITE;
if (is_atapi)
@@ -1229,66 +1321,87 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->eh_info;
- unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
+ struct ata_eh_info *host_ehi = &ap->link.eh_info;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *active_qc;
+ struct ata_eh_info *active_ehi;
u32 serror;
- ata_ehi_clear_desc(ehi);
+ /* determine active link */
+ ata_port_for_each_link(link, ap)
+ if (ata_link_active(link))
+ break;
+ if (!link)
+ link = &ap->link;
+
+ active_qc = ata_qc_from_tag(ap, link->active_tag);
+ active_ehi = &link->eh_info;
+
+ /* record irq stat */
+ ata_ehi_clear_desc(host_ehi);
+ ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
/* AHCI needs SError cleared; otherwise, it might lock up */
- serror = ahci_scr_read(ap, SCR_ERROR);
+ ahci_scr_read(ap, SCR_ERROR, &serror);
ahci_scr_write(ap, SCR_ERROR, serror);
-
- /* analyze @irq_stat */
- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */
- if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
+ if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
irq_stat &= ~PORT_IRQ_IF_ERR;
if (irq_stat & PORT_IRQ_TF_ERR) {
- err_mask |= AC_ERR_DEV;
- if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
- serror &= ~SERR_INTERNAL;
+ /* If qc is active, charge it; otherwise, the active
+ * link. There's no active qc on NCQ errors. It will
+ * be determined by EH by reading log page 10h.
+ */
+ if (active_qc)
+ active_qc->err_mask |= AC_ERR_DEV;
+ else
+ active_ehi->err_mask |= AC_ERR_DEV;
+
+ if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
+ host_ehi->serror &= ~SERR_INTERNAL;
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(active_ehi,
+ "unknown FIS %08x %08x %08x %08x" ,
+ unk[0], unk[1], unk[2], unk[3]);
+ }
+
+ if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(active_ehi, "incorrect PMP");
}
if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
- err_mask |= AC_ERR_HOST_BUS;
- action |= ATA_EH_SOFTRESET;
+ host_ehi->err_mask |= AC_ERR_HOST_BUS;
+ host_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(host_ehi, "host bus error");
}
if (irq_stat & PORT_IRQ_IF_ERR) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", interface fatal error");
+ host_ehi->err_mask |= AC_ERR_ATA_BUS;
+ host_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(host_ehi, "interface fatal error");
}
if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+ ata_ehi_hotplugged(host_ehi);
+ ata_ehi_push_desc(host_ehi, "%s",
+ irq_stat & PORT_IRQ_CONNECT ?
"connection status changed" : "PHY RDY changed");
}
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
- err_mask |= AC_ERR_HSM;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
- unk[0], unk[1], unk[2], unk[3]);
- }
-
/* okay, let's hand over to EH */
- ehi->serror |= serror;
- ehi->action |= action;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc)
- qc->err_mask |= err_mask;
- else
- ehi->err_mask |= err_mask;
if (irq_stat & PORT_IRQ_FREEZE)
ata_port_freeze(ap);
@@ -1299,25 +1412,64 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
u32 status, qc_active;
int rc, known_irq = 0;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
+ /* ignore BAD_PMP while resetting */
+ if (unlikely(resetting))
+ status &= ~PORT_IRQ_BAD_PMP;
+
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
return;
}
- if (ap->sactive)
+ if (status & PORT_IRQ_SDB_FIS) {
+ /* If SNotification is available, leave notification
+ * handling to sata_async_notification(). If not,
+ * emulate it by snooping SDB FIS RX area.
+ *
+ * Snooping FIS RX area is probably cheaper than
+ * poking SNotification but some constrollers which
+ * implement SNotification, ICH9 for example, don't
+ * store AN SDB FIS into receive area.
+ */
+ if (hpriv->cap & HOST_CAP_SNTF)
+ sata_async_notification(ap);
+ else {
+ /* If the 'N' bit in word 0 of the FIS is set,
+ * we just received asynchronous notification.
+ * Tell libata about it.
+ */
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
+ }
+
+ /* pp->active_link is valid iff any command is in flight */
+ if (ap->qc_active && pp->active_link->sactive)
qc_active = readl(port_mmio + PORT_SCR_ACT);
else
qc_active = readl(port_mmio + PORT_CMD_ISSUE);
rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+
+ /* If resetting, spurious or invalid completions are expected,
+ * return unconditionally.
+ */
+ if (resetting)
+ return;
+
if (rc > 0)
return;
if (rc < 0) {
@@ -1332,7 +1484,7 @@ static void ahci_port_intr(struct ata_port *ap)
/* if !NCQ, ignore. No modern ATA device has broken HSM
* implementation for non-NCQ commands.
*/
- if (!ap->sactive)
+ if (!ap->link.sactive)
return;
if (status & PORT_IRQ_D2H_REG_FIS) {
@@ -1385,7 +1537,7 @@ static void ahci_port_intr(struct ata_port *ap)
if (!known_irq)
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
- status, ap->active_tag, ap->sactive);
+ status, ap->link.active_tag, ap->link.sactive);
}
static void ahci_irq_clear(struct ata_port *ap)
@@ -1450,6 +1602,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /* Keep track of the currently active link. It will be used
+ * in completion path to determine whether NCQ phase is in
+ * progress.
+ */
+ pp->active_link = qc->dev->link;
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1472,6 +1631,7 @@ static void ahci_thaw(struct ata_port *ap)
void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
+ struct ahci_port_priv *pp = ap->private_data;
/* clear IRQ */
tmp = readl(port_mmio + PORT_IRQ_STAT);
@@ -1479,7 +1639,7 @@ static void ahci_thaw(struct ata_port *ap)
writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
/* turn IRQ back on */
- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
static void ahci_error_handler(struct ata_port *ap)
@@ -1491,8 +1651,10 @@ static void ahci_error_handler(struct ata_port *ap)
}
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
- ahci_postreset);
+ sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
+ ahci_hardreset, ahci_postreset,
+ sata_pmp_std_prereset, ahci_pmp_softreset,
+ sata_pmp_std_hardreset, sata_pmp_std_postreset);
}
static void ahci_vt8251_error_handler(struct ata_port *ap)
@@ -1512,11 +1674,50 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED) {
- /* make DMA engine forget about the failed command */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
+ /* make DMA engine forget about the failed command */
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ ahci_kick_engine(ap, 1);
+}
+
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd |= PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask |= PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd &= ~PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+ ahci_power_up(ap);
+ ahci_start_port(ap);
+
+ if (ap->nr_pmp_links)
+ ahci_pmp_attach(ap);
+ else
+ ahci_pmp_detach(ap);
+
+ return 0;
}
#ifdef CONFIG_PM
@@ -1536,14 +1737,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
return rc;
}
-static int ahci_port_resume(struct ata_port *ap)
-{
- ahci_power_up(ap);
- ahci_start_port(ap);
-
- return 0;
-}
-
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1635,6 +1828,12 @@ static int ahci_port_start(struct ata_port *ap)
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
+ /*
+ * Save off initial list of interrupts to be enabled.
+ * This could be changed later
+ */
+ pp->intr_mask = DEF_PORT_IRQ;
+
ap->private_data = pp;
/* engage engines, captain */
@@ -1734,12 +1933,13 @@ static void ahci_print_info(struct ata_host *host)
dev_printk(KERN_INFO, &pdev->dev,
"flags: "
- "%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s\n"
+ "%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n"
,
cap & (1 << 31) ? "64bit " : "",
cap & (1 << 30) ? "ncq " : "",
+ cap & (1 << 29) ? "sntf " : "",
cap & (1 << 28) ? "ilck " : "",
cap & (1 << 27) ? "stag " : "",
cap & (1 << 26) ? "pm " : "",
@@ -1783,20 +1983,24 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
- pci_intx(pdev, 1);
-
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
+ pci_intx(pdev, 1);
/* save initial config */
- ahci_save_initial_config(pdev, &pi, hpriv);
+ ahci_save_initial_config(pdev, hpriv);
/* prepare host */
- if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+ if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
if (!host)
return -ENOMEM;
@@ -1807,11 +2011,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_port *ap = host->ports[i];
void __iomem *port_mmio = ahci_port_base(ap);
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+ 0x100 + ap->port_no * 0x80, "port");
+
/* standard SATA port setup */
- if (hpriv->port_map & (1 << i)) {
+ if (hpriv->port_map & (1 << i))
ap->ioaddr.cmd_addr = port_mmio;
- ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
- }
/* disabled/not-implemented port */
else
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 430fcf4f9ef3..90329982bef7 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -26,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_generic"
-#define DRV_VERSION "0.2.12"
+#define DRV_VERSION "0.2.13"
/*
* A generic parallel ATA driver using libata
@@ -34,7 +34,7 @@
/**
* generic_set_mode - mode setting
- * @ap: interface to set up
+ * @link: link to set up
* @unused: returned device on error
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -43,24 +43,24 @@
* and respect them.
*/
-static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
{
+ struct ata_port *ap = link->ap;
int dma_enabled = 0;
- int i;
+ struct ata_device *dev;
/* Bits 5 and 6 indicate if DMA is active on master/slave */
if (ap->ioaddr.bmdma_addr)
dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
- if (dma_enabled & (1 << (5 + i))) {
+ if (dma_enabled & (1 << (5 + dev->devno))) {
ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
@@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = {
static struct ata_port_operations generic_port_ops = {
.set_mode = generic_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -121,9 +120,8 @@ static struct ata_port_operations generic_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int all_generic_ide; /* Set to claim all devices */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index d9fa329fd157..e783e678acf5 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -91,9 +91,10 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
+#include <linux/dmi.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "2.11"
+#define DRV_VERSION "2.12"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
@@ -122,13 +123,13 @@ enum {
ich_pata_33 = 1, /* ICH up to UDMA 33 only */
ich_pata_66 = 2, /* ICH up to 66 Mhz */
ich_pata_100 = 3, /* ICH up to UDMA 100 */
- ich_pata_133 = 4, /* ICH up to UDMA 133 */
ich5_sata = 5,
ich6_sata = 6,
ich6_sata_ahci = 7,
ich6m_sata_ahci = 8,
ich8_sata_ahci = 9,
piix_pata_mwdma = 10, /* PIIX3 MWDMA only */
+ tolapai_sata_ahci = 11,
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -140,6 +141,9 @@ enum {
RV = -3, /* reserved */
PIIX_AHCI_DEVICE = 6,
+
+ /* host->flags bits */
+ PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
};
struct piix_map_db {
@@ -159,6 +163,10 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static int ich_pata_cable_detect(struct ata_port *ap);
+#ifdef CONFIG_PM
+static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int piix_pci_device_resume(struct pci_dev *pdev);
+#endif
static unsigned int in_module_init = 1;
@@ -190,7 +198,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH5 */
- { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* C-ICH (i810E2) */
{ 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ESB (855GME/875P + 6300ESB) UDMA 100 */
@@ -198,7 +206,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH6 (and 6) (i915) UDMA 100 */
{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH7/7-R (i945, i975) UDMA 100*/
- { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH8 Mobile PATA Controller */
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -245,6 +253,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (ICH9M) */
{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (Tolapai) */
+ { 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci },
{ } /* terminate list */
};
@@ -255,8 +265,8 @@ static struct pci_driver piix_pci_driver = {
.probe = piix_init_one,
.remove = ata_pci_remove_one,
#ifdef CONFIG_PM
- .suspend = ata_pci_device_suspend,
- .resume = ata_pci_device_resume,
+ .suspend = piix_pci_device_suspend,
+ .resume = piix_pci_device_resume,
#endif
};
@@ -279,7 +289,6 @@ static struct scsi_host_template piix_sht = {
};
static const struct ata_port_operations piix_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = piix_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -307,13 +316,11 @@ static const struct ata_port_operations piix_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations ich_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = ich_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -341,14 +348,11 @@ static const struct ata_port_operations ich_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations piix_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -371,7 +375,6 @@ static const struct ata_port_operations piix_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -428,7 +431,19 @@ static const struct piix_map_db ich8_map_db = {
/* PM PS SM SS MAP */
{ P0, P2, P1, P3 }, /* 00b (hardwired when in AHCI) */
{ RV, RV, RV, RV },
- { IDE, IDE, NA, NA }, /* 10b (IDE mode) */
+ { P0, P2, IDE, IDE }, /* 10b (IDE mode) */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db tolapai_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b */
+ { RV, RV, RV, RV }, /* 01b */
+ { RV, RV, RV, RV }, /* 10b */
{ RV, RV, RV, RV },
},
};
@@ -439,10 +454,11 @@ static const struct piix_map_db *piix_map_db_table[] = {
[ich6_sata_ahci] = &ich6_map_db,
[ich6m_sata_ahci] = &ich6m_map_db,
[ich8_sata_ahci] = &ich8_map_db,
+ [tolapai_sata_ahci] = &tolapai_map_db,
};
static struct ata_port_info piix_port_info[] = {
- /* piix_pata_33: 0: PIIX4 at 33MHz */
+ [piix_pata_33] = /* PIIX4 at 33MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -452,7 +468,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_pata_ops,
},
- /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/
+ [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -461,7 +477,8 @@ static struct ata_port_info piix_port_info[] = {
.udma_mask = ATA_UDMA2, /* UDMA33 */
.port_ops = &ich_pata_ops,
},
- /* ich_pata_66: 2 ICH controllers up to 66MHz */
+
+ [ich_pata_66] = /* ICH controllers up to 66MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -471,7 +488,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &ich_pata_ops,
},
- /* ich_pata_100: 3 */
+ [ich_pata_100] =
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
@@ -481,17 +498,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &ich_pata_ops,
},
- /* ich_pata_133: 4 ICH with full UDMA6 */
- {
- .sht = &piix_sht,
- .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
- .pio_mask = 0x1f, /* pio 0-4 */
- .mwdma_mask = 0x06, /* Check: maybe 0x07 */
- .udma_mask = ATA_UDMA6, /* UDMA133 */
- .port_ops = &ich_pata_ops,
- },
-
- /* ich5_sata: 5 */
+ [ich5_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS,
@@ -501,7 +508,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6_sata: 6 */
+ [ich6_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
@@ -511,7 +518,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6_sata_ahci: 7 */
+ [ich6_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -522,7 +529,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6m_sata_ahci: 8 */
+ [ich6m_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -533,7 +540,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich8_sata_ahci: 9 */
+ [ich8_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -544,7 +551,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* piix_pata_mwdma: 10: PIIX3 MWDMA only */
+ [piix_pata_mwdma] = /* PIIX3 MWDMA only */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -552,6 +559,17 @@ static struct ata_port_info piix_port_info[] = {
.mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
.port_ops = &piix_pata_ops,
},
+
+ [tolapai_sata_ahci] =
+ {
+ .sht = &piix_sht,
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
};
static struct pci_bits piix_enable_bits[] = {
@@ -580,6 +598,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
+ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
/* end marker */
{ 0, }
@@ -622,19 +641,20 @@ static int ich_pata_cable_detect(struct ata_port *ap)
/**
* piix_pata_prereset - prereset for PATA host controller
- * @ap: Target port
+ * @link: Target link
* @deadline: deadline jiffies for the operation
*
* LOCKING:
* None (inherited from caller).
*/
-static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void piix_pata_error_handler(struct ata_port *ap)
@@ -881,6 +901,137 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev)
do_pata_set_dmamode(ap, adev, 1);
}
+#ifdef CONFIG_PM
+static int piix_broken_suspend(void)
+{
+ static const struct dmi_system_id sysids[] = {
+ {
+ .ident = "TECRA M3",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M3"),
+ },
+ },
+ {
+ .ident = "TECRA M5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"),
+ },
+ },
+ {
+ .ident = "TECRA M7",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M7"),
+ },
+ },
+ {
+ .ident = "Satellite U200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),
+ },
+ },
+ {
+ .ident = "Satellite U205",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"),
+ },
+ },
+ {
+ .ident = "Portege M500",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),
+ },
+ },
+
+ { } /* terminate list */
+ };
+ static const char *oemstrs[] = {
+ "Tecra M3,",
+ };
+ int i;
+
+ if (dmi_check_system(sysids))
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE(oemstrs); i++)
+ if (dmi_find_device(DMI_DEV_TYPE_OEM_STRING, oemstrs[i], NULL))
+ return 1;
+
+ return 0;
+}
+
+static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ /* Some braindamaged ACPI suspend implementations expect the
+ * controller to be awake on entry; otherwise, it burns cpu
+ * cycles and power trying to do something to the sleeping
+ * beauty.
+ */
+ if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) {
+ pci_save_state(pdev);
+
+ /* mark its power state as "unknown", since we don't
+ * know if e.g. the BIOS will change its device state
+ * when we suspend.
+ */
+ if (pdev->current_state == PCI_D0)
+ pdev->current_state = PCI_UNKNOWN;
+
+ /* tell resume that it's waking up from broken suspend */
+ spin_lock_irqsave(&host->lock, flags);
+ host->flags |= PIIX_HOST_BROKEN_SUSPEND;
+ spin_unlock_irqrestore(&host->lock, flags);
+ } else
+ ata_pci_device_do_suspend(pdev, mesg);
+
+ return 0;
+}
+
+static int piix_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
+ int rc;
+
+ if (host->flags & PIIX_HOST_BROKEN_SUSPEND) {
+ spin_lock_irqsave(&host->lock, flags);
+ host->flags &= ~PIIX_HOST_BROKEN_SUSPEND;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ /* PCI device wasn't disabled during suspend. Use
+ * pci_reenable_device() to avoid affecting the enable
+ * count.
+ */
+ rc = pci_reenable_device(pdev);
+ if (rc)
+ dev_printk(KERN_ERR, &pdev->dev, "failed to enable "
+ "device after resume (%d)\n", rc);
+ } else
+ rc = ata_pci_device_do_resume(pdev);
+
+ if (rc == 0)
+ ata_host_resume(host);
+
+ return rc;
+}
+#endif
+
#define AHCI_PCI_BAR 5
#define AHCI_GLOBAL_CTL 0x04
#define AHCI_ENABLE (1 << 31)
@@ -1015,6 +1166,41 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
hpriv->map = map;
}
+static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id sysids[] = {
+ {
+ /* Clevo M570U sets IOCFG bit 18 if the cdrom
+ * isn't used to boot the system which
+ * disables the channel.
+ */
+ .ident = "M570U",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M570U"),
+ },
+ },
+
+ { } /* terminate list */
+ };
+ u32 iocfg;
+
+ if (!dmi_check_system(sysids))
+ return;
+
+ /* The datasheet says that bit 18 is NOOP but certain systems
+ * seem to use it to disable a channel. Clear the bit on the
+ * affected systems.
+ */
+ pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg);
+ if (iocfg & (1 << 18)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "applying IOCFG bit18 quirk\n");
+ iocfg &= ~(1 << 18);
+ pci_write_config_dword(pdev, PIIX_IOCFG, iocfg);
+ }
+}
+
/**
* piix_init_one - Register PIIX ATA PCI device with kernel services
* @pdev: PCI device to register
@@ -1076,6 +1262,9 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
piix_map_db_table[ent->driver_data]);
}
+ /* apply IOCFG bit18 quirk */
+ piix_iocfg_bit18_quirk(pdev);
+
/* On ICH5, some BIOSen disable the interrupt using the
* PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
* On ICH6, this bit has the same effect, but only when
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index c059f78ad944..3f7533589041 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/pci.h>
+#include <scsi/scsi_device.h>
#include "libata.h"
#include <acpi/acpi_bus.h>
@@ -40,11 +41,40 @@ static int is_pci_dev(struct device *dev)
return (dev->bus == &pci_bus_type);
}
-static void ata_acpi_associate_sata_port(struct ata_port *ap)
+/**
+ * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
+ * @ap: target SATA port
+ *
+ * Look up ACPI objects associated with @ap and initialize acpi_handle
+ * fields of @ap, the port and devices accordingly.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+void ata_acpi_associate_sata_port(struct ata_port *ap)
{
- acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+ WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
+
+ if (!ap->nr_pmp_links) {
+ acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+
+ ap->link.device->acpi_handle =
+ acpi_get_child(ap->host->acpi_handle, adr);
+ } else {
+ struct ata_link *link;
+
+ ap->link.device->acpi_handle = NULL;
- ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr);
+ ata_port_for_each_link(link, ap) {
+ acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+
+ link->device->acpi_handle =
+ acpi_get_child(ap->host->acpi_handle, adr);
+ }
+ }
}
static void ata_acpi_associate_ide_port(struct ata_port *ap)
@@ -60,12 +90,53 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
max_devices++;
for (i = 0; i < max_devices; i++) {
- struct ata_device *dev = &ap->device[i];
+ struct ata_device *dev = &ap->link.device[i];
dev->acpi_handle = acpi_get_child(ap->acpi_handle, i);
}
}
+static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj,
+ u32 event)
+{
+ char event_string[12];
+ char *envp[] = { event_string, NULL };
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ if (event == 0 || event == 1) {
+ unsigned long flags;
+ spin_lock_irqsave(ap->lock, flags);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "ACPI event");
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ if (kobj) {
+ sprintf(event_string, "BAY_EVENT=%d", event);
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+ }
+}
+
+static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_device *dev = data;
+ struct kobject *kobj = NULL;
+
+ if (dev->sdev)
+ kobj = &dev->sdev->sdev_gendev.kobj;
+
+ ata_acpi_handle_hotplug (dev->link->ap, kobj, event);
+}
+
+static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_port *ap = data;
+
+ ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event);
+}
+
/**
* ata_acpi_associate - associate ATA host with ACPI objects
* @host: target ATA host
@@ -81,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
*/
void ata_acpi_associate(struct ata_host *host)
{
- int i;
+ int i, j;
if (!is_pci_dev(host->dev) || libata_noacpi)
return;
@@ -97,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_associate_sata_port(ap);
else
ata_acpi_associate_ide_port(ap);
+
+ if (ap->acpi_handle)
+ acpi_install_notify_handler (ap->acpi_handle,
+ ACPI_SYSTEM_NOTIFY,
+ ata_acpi_ap_notify,
+ ap);
+
+ for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
+ struct ata_device *dev = &ap->link.device[j];
+
+ if (dev->acpi_handle)
+ acpi_install_notify_handler (dev->acpi_handle,
+ ACPI_SYSTEM_NOTIFY,
+ ata_acpi_dev_notify,
+ dev);
+ }
}
}
@@ -113,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host)
* RETURNS:
* 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
*/
-static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
{
struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
union acpi_object *out_obj;
@@ -157,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
return rc;
}
+EXPORT_SYMBOL_GPL(ata_acpi_gtm);
+
/**
* ata_acpi_stm - execute _STM
* @ap: target ATA port
@@ -170,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
* RETURNS:
* 0 on success, -ENOENT if _STM doesn't exist, -errno on failure.
*/
-static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
{
acpi_status status;
struct acpi_object_list input;
@@ -182,10 +271,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
/* Buffers for id may need byteswapping ? */
in_params[1].type = ACPI_TYPE_BUFFER;
in_params[1].buffer.length = 512;
- in_params[1].buffer.pointer = (u8 *)ap->device[0].id;
+ in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id;
in_params[2].type = ACPI_TYPE_BUFFER;
in_params[2].buffer.length = 512;
- in_params[2].buffer.pointer = (u8 *)ap->device[1].id;
+ in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id;
input.count = 3;
input.pointer = in_params;
@@ -202,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
return 0;
}
+EXPORT_SYMBOL_GPL(ata_acpi_stm);
+
/**
* ata_dev_get_GTF - get the drive bootup default taskfile settings
* @dev: target ATA device
@@ -226,7 +317,7 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
void **ptr_to_free)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
acpi_status status;
struct acpi_buffer output;
union acpi_object *out_obj;
@@ -296,6 +387,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
}
/**
+ * ata_acpi_cbl_80wire - Check for 80 wire cable
+ * @ap: Port to check
+ *
+ * Return 1 if the ACPI mode data for this port indicates the BIOS selected
+ * an 80wire mode.
+ */
+
+int ata_acpi_cbl_80wire(struct ata_port *ap)
+{
+ struct ata_acpi_gtm gtm;
+ int valid = 0;
+
+ /* No _GTM data, no information */
+ if (ata_acpi_gtm(ap, &gtm) < 0)
+ return 0;
+
+ /* Split timing, DMA enabled */
+ if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55)
+ valid |= 1;
+ if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55)
+ valid |= 2;
+ /* Shared timing, DMA enabled */
+ if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55)
+ valid |= 1;
+ if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55)
+ valid |= 2;
+
+ /* Drive check */
+ if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
+ return 1;
+ if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
+ return 1;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
+
+/**
* taskfile_load_raw - send taskfile registers to host controller
* @dev: target ATA device
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
@@ -320,7 +449,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
static int taskfile_load_raw(struct ata_device *dev,
const struct ata_acpi_gtf *gtf)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf, rtf;
unsigned int err_mask;
@@ -349,7 +478,7 @@ static int taskfile_load_raw(struct ata_device *dev,
tf.lbal, tf.lbam, tf.lbah, tf.device);
rtf = tf;
- err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR,
"ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed "
@@ -424,7 +553,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
*/
static int ata_acpi_push_id(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
int err;
acpi_status status;
struct acpi_object_list input;
@@ -508,7 +637,7 @@ int ata_acpi_on_suspend(struct ata_port *ap)
*/
void ata_acpi_on_resume(struct ata_port *ap)
{
- int i;
+ struct ata_device *dev;
if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) {
BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
@@ -518,8 +647,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
}
/* schedule _GTF */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->flags |= ATA_DFLAG_ACPI_PENDING;
}
/**
@@ -538,8 +667,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
*/
int ata_acpi_on_devcfg(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
int rc;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 88e2dd0983b5..b05384a8c326 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,8 +59,6 @@
#include "libata.h"
-#define DRV_VERSION "2.21" /* must be exactly four chars */
-
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
@@ -70,6 +68,7 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable);
static void ata_dev_xfermask(struct ata_device *dev);
static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
@@ -86,6 +85,10 @@ int atapi_dmadir = 0;
module_param(atapi_dmadir, int, 0444);
MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+int atapi_passthru16 = 1;
+module_param(atapi_passthru16, int, 0444);
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+
int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
@@ -94,13 +97,17 @@ static int ata_ignore_hpa = 0;
module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
+static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA;
+module_param_named(dma, libata_dma_mask, int, 0444);
+MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
+
static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
module_param(ata_probe_timeout, int, 0444);
MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
-int libata_noacpi = 1;
+int libata_noacpi = 0;
module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
@@ -111,8 +118,9 @@ MODULE_VERSION(DRV_VERSION);
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert
- * @fis: Buffer into which data will output
* @pmp: Port multiplier port
+ * @is_cmd: This FIS is for command
+ * @fis: Buffer into which data will output
*
* Converts a standard ATA taskfile to a Serial ATA
* FIS structure (Register - Host to Device).
@@ -120,12 +128,13 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING:
* Inherited from caller.
*/
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
{
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
- bit 7 indicates Command FIS */
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = pmp & 0xf; /* Port multiplier number*/
+ if (is_cmd)
+ fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
+
fis[2] = tf->command;
fis[3] = tf->feature;
@@ -233,7 +242,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
if (dev->flags & ATA_DFLAG_PIO) {
tf->protocol = ATA_PROT_PIO;
index = dev->multi_count ? 0 : 8;
- } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) {
+ } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) {
/* Unable to use DMA due to host limitation */
tf->protocol = ATA_PROT_PIO;
index = dev->multi_count ? 0 : 8;
@@ -602,7 +611,7 @@ static const char *sata_spd_string(unsigned int spd)
void ata_dev_disable(struct ata_device *dev)
{
if (ata_dev_enabled(dev)) {
- if (ata_msg_drv(dev->ap))
+ if (ata_msg_drv(dev->link->ap))
ata_dev_printk(dev, KERN_WARNING, "disabled\n");
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
ATA_DNXFER_QUIET);
@@ -665,37 +674,57 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
* None.
*
* RETURNS:
- * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- * the event of failure.
+ * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
+ * %ATA_DEV_UNKNOWN the event of failure.
*/
-
unsigned int ata_dev_classify(const struct ata_taskfile *tf)
{
/* Apple's open source Darwin code hints that some devices only
* put a proper signature into the LBA mid/high registers,
* So, we only check those. It's sufficient for uniqueness.
+ *
+ * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate
+ * signatures for ATA and ATAPI devices attached on SerialATA,
+ * 0x3c/0xc3 and 0x69/0x96 respectively. However, SerialATA
+ * spec has never mentioned about using different signatures
+ * for ATA/ATAPI devices. Then, Serial ATA II: Port
+ * Multiplier specification began to use 0x69/0x96 to identify
+ * port multpliers and 0x3c/0xc3 to identify SEMB device.
+ * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and
+ * 0x69/0x96 shortly and described them as reserved for
+ * SerialATA.
+ *
+ * We follow the current spec and consider that 0x69/0x96
+ * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
*/
-
- if (((tf->lbam == 0) && (tf->lbah == 0)) ||
- ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+ if ((tf->lbam == 0) && (tf->lbah == 0)) {
DPRINTK("found ATA device by sig\n");
return ATA_DEV_ATA;
}
- if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
- ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+ if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
DPRINTK("found ATAPI device by sig\n");
return ATA_DEV_ATAPI;
}
+ if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {
+ DPRINTK("found PMP device by sig\n");
+ return ATA_DEV_PMP;
+ }
+
+ if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
+ printk("ata: SEMB device ignored\n");
+ return ATA_DEV_SEMB_UNSUP; /* not yet */
+ }
+
DPRINTK("unknown device\n");
return ATA_DEV_UNKNOWN;
}
/**
* ata_dev_try_classify - Parse returned ATA device signature
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
+ * @dev: ATA device to classify (starting at zero)
+ * @present: device seems present
* @r_err: Value of error register on completion
*
* After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
@@ -713,15 +742,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
* RETURNS:
* Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
*/
-
-unsigned int
-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+ u8 *r_err)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
unsigned int class;
u8 err;
- ap->ops->dev_select(ap, device);
+ ap->ops->dev_select(ap, dev->devno);
memset(&tf, 0, sizeof(tf));
@@ -731,12 +760,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
*r_err = err;
/* see if device passed diags: if master then continue and warn later */
- if (err == 0 && device == 0)
+ if (err == 0 && dev->devno == 0)
/* diagnostic fail : do nothing _YET_ */
- ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+ dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
else if (err == 1)
/* do nothing */ ;
- else if ((device == 0) && (err == 0x81))
+ else if ((dev->devno == 0) && (err == 0x81))
/* do nothing */ ;
else
return ATA_DEV_NONE;
@@ -744,10 +773,20 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
/* determine if device is ATA or ATAPI */
class = ata_dev_classify(&tf);
- if (class == ATA_DEV_UNKNOWN)
- return ATA_DEV_NONE;
- if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
- return ATA_DEV_NONE;
+ if (class == ATA_DEV_UNKNOWN) {
+ /* If the device failed diagnostic, it's likely to
+ * have reported incorrect device signature too.
+ * Assume ATA device if the device seems present but
+ * device signature is invalid with diagnostic
+ * failure.
+ */
+ if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))
+ class = ATA_DEV_ATA;
+ else
+ class = ATA_DEV_NONE;
+ } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+ class = ATA_DEV_NONE;
+
return class;
}
@@ -814,6 +853,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
*p = '\0';
}
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
+
static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
{
u64 sectors = 0;
@@ -841,129 +895,110 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf)
}
/**
- * ata_read_native_max_address_ext - LBA48 native max query
- * @dev: Device to query
+ * ata_read_native_max_address - Read native max address
+ * @dev: target device
+ * @max_sectors: out parameter for the result native max address
*
- * Perform an LBA48 size query upon the device in question. Return the
- * actual LBA48 size or zero if the command fails.
- */
-
-static u64 ata_read_native_max_address_ext(struct ata_device *dev)
-{
- unsigned int err;
- struct ata_taskfile tf;
-
- ata_tf_init(dev, &tf);
-
- tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
- tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
-
- return ata_tf_to_lba48(&tf);
-}
-
-/**
- * ata_read_native_max_address - LBA28 native max query
- * @dev: Device to query
+ * Perform an LBA48 or LBA28 native size query upon the device in
+ * question.
*
- * Performa an LBA28 size query upon the device in question. Return the
- * actual LBA28 size or zero if the command fails.
+ * RETURNS:
+ * 0 on success, -EACCES if command is aborted by the drive.
+ * -EIO on other errors.
*/
-
-static u64 ata_read_native_max_address(struct ata_device *dev)
+static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
{
- unsigned int err;
+ unsigned int err_mask;
struct ata_taskfile tf;
+ int lba48 = ata_id_has_lba48(dev->id);
ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_READ_NATIVE_MAX;
+ /* always clear all address registers */
tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+
+ if (lba48) {
+ tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+ tf.flags |= ATA_TFLAG_LBA48;
+ } else
+ tf.command = ATA_CMD_READ_NATIVE_MAX;
+
tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
+ tf.device |= ATA_LBA;
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to read native "
+ "max address (err_mask=0x%x)\n", err_mask);
+ if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+ return -EACCES;
+ return -EIO;
+ }
- return ata_tf_to_lba(&tf);
+ if (lba48)
+ *max_sectors = ata_tf_to_lba48(&tf);
+ else
+ *max_sectors = ata_tf_to_lba(&tf);
+ if (dev->horkage & ATA_HORKAGE_HPA_SIZE)
+ (*max_sectors)--;
+ return 0;
}
/**
- * ata_set_native_max_address_ext - LBA48 native max set
- * @dev: Device to query
+ * ata_set_max_sectors - Set max sectors
+ * @dev: target device
* @new_sectors: new max sectors value to set for the device
*
- * Perform an LBA48 size set max upon the device in question. Return the
- * actual LBA48 size or zero if the command fails.
+ * Set max sectors of @dev to @new_sectors.
+ *
+ * RETURNS:
+ * 0 on success, -EACCES if command is aborted or denied (due to
+ * previous non-volatile SET_MAX) by the drive. -EIO on other
+ * errors.
*/
-
-static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
{
- unsigned int err;
+ unsigned int err_mask;
struct ata_taskfile tf;
+ int lba48 = ata_id_has_lba48(dev->id);
new_sectors--;
ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_SET_MAX_EXT;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
- tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
-
- tf.lbal = (new_sectors >> 0) & 0xff;
- tf.lbam = (new_sectors >> 8) & 0xff;
- tf.lbah = (new_sectors >> 16) & 0xff;
-
- tf.hob_lbal = (new_sectors >> 24) & 0xff;
- tf.hob_lbam = (new_sectors >> 32) & 0xff;
- tf.hob_lbah = (new_sectors >> 40) & 0xff;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
-
- return ata_tf_to_lba48(&tf);
-}
-
-/**
- * ata_set_native_max_address - LBA28 native max set
- * @dev: Device to query
- * @new_sectors: new max sectors value to set for the device
- *
- * Perform an LBA28 size set max upon the device in question. Return the
- * actual LBA28 size or zero if the command fails.
- */
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
-static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
-{
- unsigned int err;
- struct ata_taskfile tf;
+ if (lba48) {
+ tf.command = ATA_CMD_SET_MAX_EXT;
+ tf.flags |= ATA_TFLAG_LBA48;
- new_sectors--;
+ tf.hob_lbal = (new_sectors >> 24) & 0xff;
+ tf.hob_lbam = (new_sectors >> 32) & 0xff;
+ tf.hob_lbah = (new_sectors >> 40) & 0xff;
+ } else {
+ tf.command = ATA_CMD_SET_MAX;
- ata_tf_init(dev, &tf);
+ tf.device |= (new_sectors >> 24) & 0xf;
+ }
- tf.command = ATA_CMD_SET_MAX;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= ATA_LBA;
tf.lbal = (new_sectors >> 0) & 0xff;
tf.lbam = (new_sectors >> 8) & 0xff;
tf.lbah = (new_sectors >> 16) & 0xff;
- tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to set "
+ "max address (err_mask=0x%x)\n", err_mask);
+ if (err_mask == AC_ERR_DEV &&
+ (tf.feature & (ATA_ABORTED | ATA_IDNF)))
+ return -EACCES;
+ return -EIO;
+ }
- return ata_tf_to_lba(&tf);
+ return 0;
}
/**
@@ -973,60 +1008,93 @@ static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
* Read the size of an LBA28 or LBA48 disk with HPA features and resize
* it if required to the full size of the media. The caller must check
* the drive has the HPA feature set enabled.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-
-static u64 ata_hpa_resize(struct ata_device *dev)
+static int ata_hpa_resize(struct ata_device *dev)
{
- u64 sectors = dev->n_sectors;
- u64 hpa_sectors;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+ u64 sectors = ata_id_n_sectors(dev->id);
+ u64 native_sectors;
+ int rc;
- if (ata_id_has_lba48(dev->id))
- hpa_sectors = ata_read_native_max_address_ext(dev);
- else
- hpa_sectors = ata_read_native_max_address(dev);
+ /* do we need to do it? */
+ if (dev->class != ATA_DEV_ATA ||
+ !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||
+ (dev->horkage & ATA_HORKAGE_BROKEN_HPA))
+ return 0;
- if (hpa_sectors > sectors) {
- ata_dev_printk(dev, KERN_INFO,
- "Host Protected Area detected:\n"
- "\tcurrent size: %lld sectors\n"
- "\tnative size: %lld sectors\n",
- (long long)sectors, (long long)hpa_sectors);
-
- if (ata_ignore_hpa) {
- if (ata_id_has_lba48(dev->id))
- hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
- else
- hpa_sectors = ata_set_native_max_address(dev,
- hpa_sectors);
-
- if (hpa_sectors) {
- ata_dev_printk(dev, KERN_INFO, "native size "
- "increased to %lld sectors\n",
- (long long)hpa_sectors);
- return hpa_sectors;
- }
+ /* read native max address */
+ rc = ata_read_native_max_address(dev, &native_sectors);
+ if (rc) {
+ /* If HPA isn't going to be unlocked, skip HPA
+ * resizing from the next try.
+ */
+ if (!ata_ignore_hpa) {
+ ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+ "broken, will skip HPA handling\n");
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+
+ /* we can continue if device aborted the command */
+ if (rc == -EACCES)
+ rc = 0;
}
- } else if (hpa_sectors < sectors)
- ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) "
- "is smaller than sectors (%lld)\n", __FUNCTION__,
- (long long)hpa_sectors, (long long)sectors);
- return sectors;
-}
+ return rc;
+ }
-static u64 ata_id_n_sectors(const u16 *id)
-{
- if (ata_id_has_lba(id)) {
- if (ata_id_has_lba48(id))
- return ata_id_u64(id, 100);
- else
- return ata_id_u32(id, 60);
- } else {
- if (ata_id_current_chs_valid(id))
- return ata_id_u32(id, 57);
- else
- return id[1] * id[3] * id[6];
+ /* nothing to do? */
+ if (native_sectors <= sectors || !ata_ignore_hpa) {
+ if (!print_info || native_sectors == sectors)
+ return 0;
+
+ if (native_sectors > sectors)
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA detected: current %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ else if (native_sectors < sectors)
+ ata_dev_printk(dev, KERN_WARNING,
+ "native sectors (%llu) is smaller than "
+ "sectors (%llu)\n",
+ (unsigned long long)native_sectors,
+ (unsigned long long)sectors);
+ return 0;
}
+
+ /* let's unlock HPA */
+ rc = ata_set_max_sectors(dev, native_sectors);
+ if (rc == -EACCES) {
+ /* if device aborted the command, skip HPA resizing */
+ ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
+ "(%llu -> %llu), skipping HPA handling\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+ return 0;
+ } else if (rc)
+ return rc;
+
+ /* re-read IDENTIFY data */
+ rc = ata_dev_reread_id(dev, 0);
+ if (rc) {
+ ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
+ "data after HPA resizing\n");
+ return rc;
+ }
+
+ if (print_info) {
+ u64 new_sectors = ata_id_n_sectors(dev->id);
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA unlocked: %llu -> %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)new_sectors,
+ (unsigned long long)native_sectors);
+ }
+
+ return 0;
}
/**
@@ -1148,7 +1216,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
ap->ops->dev_select(ap, device);
if (wait) {
- if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+ if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
msleep(150);
ata_wait_idle(ap);
}
@@ -1326,6 +1394,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
* @dma_dir: Data tranfer direction of the command
* @sg: sg list for the data buffer of the command
* @n_elem: Number of sg entries
+ * @timeout: Timeout in msecs (0 for default)
*
* Executes libata internal command with timeout. @tf contains
* command on entry and result on return. Timeout and error
@@ -1342,13 +1411,15 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, struct scatterlist *sg,
- unsigned int n_elem)
+ unsigned int n_elem, unsigned long timeout)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
u8 command = tf->command;
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1384,12 +1455,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
qc->dev = dev;
ata_qc_reinit(qc);
- preempted_tag = ap->active_tag;
- preempted_sactive = ap->sactive;
+ preempted_tag = link->active_tag;
+ preempted_sactive = link->sactive;
preempted_qc_active = ap->qc_active;
- ap->active_tag = ATA_TAG_POISON;
- ap->sactive = 0;
+ preempted_nr_active_links = ap->nr_active_links;
+ link->active_tag = ATA_TAG_POISON;
+ link->sactive = 0;
ap->qc_active = 0;
+ ap->nr_active_links = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1414,7 +1487,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags);
- rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+ if (!timeout)
+ timeout = ata_probe_timeout * 1000 / HZ;
+
+ rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
ata_port_flush_task(ap);
@@ -1465,9 +1541,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
err_mask = qc->err_mask;
ata_qc_free(qc);
- ap->active_tag = preempted_tag;
- ap->sactive = preempted_sactive;
+ link->active_tag = preempted_tag;
+ link->sactive = preempted_sactive;
ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -1498,6 +1575,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
* @dma_dir: Data tranfer direction of the command
* @buf: Data buffer of the command
* @buflen: Length of data buffer
+ * @timeout: Timeout in msecs (0 for default)
*
* Wrapper around ata_exec_internal_sg() which takes simple
* buffer instead of sg list.
@@ -1510,7 +1588,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
*/
unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen)
+ int dma_dir, void *buf, unsigned int buflen,
+ unsigned long timeout)
{
struct scatterlist *psg = NULL, sg;
unsigned int n_elem = 0;
@@ -1522,7 +1601,8 @@ unsigned ata_exec_internal(struct ata_device *dev,
n_elem++;
}
- return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
+ return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem,
+ timeout);
}
/**
@@ -1549,7 +1629,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
tf.flags |= ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
- return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
}
/**
@@ -1564,7 +1644,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
{
/* Controller doesn't support IORDY. Probably a pointless check
as the caller should know this */
- if (adev->ap->flags & ATA_FLAG_NO_IORDY)
+ if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
/* PIO3 and higher it is mandatory */
if (adev->pio_mode > XFER_PIO_2)
@@ -1611,6 +1691,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
* devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
* for pre-ATA4 drives.
*
+ * FIXME: ATA_CMD_ID_ATA is optional for early drives and right
+ * now we abort if we hit that case.
+ *
* LOCKING:
* Kernel thread context (may sleep)
*
@@ -1620,7 +1703,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
unsigned int class = *p_class;
struct ata_taskfile tf;
unsigned int err_mask = 0;
@@ -1661,7 +1744,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
tf.flags |= ATA_TFLAG_POLLING;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- id, sizeof(id[0]) * ATA_ID_WORDS);
+ id, sizeof(id[0]) * ATA_ID_WORDS, 0);
if (err_mask) {
if (err_mask & AC_ERR_NODEV_HINT) {
DPRINTK("ata%u.%d: NODEV after polling detection\n",
@@ -1720,8 +1803,9 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
tf.feature = SETFEATURES_SPINUP;
tf.protocol = ATA_PROT_NODATA;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err_mask) {
+ err_mask = ata_exec_internal(dev, &tf, NULL,
+ DMA_NONE, NULL, 0, 0);
+ if (err_mask && id[2] != 0x738c) {
rc = -EIO;
reason = "SPINUP failed";
goto err_out;
@@ -1738,10 +1822,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
/*
* The exact sequence expected by certain pre-ATA4 drives is:
* SRST RESET
- * IDENTIFY
- * INITIALIZE DEVICE PARAMETERS
+ * IDENTIFY (optional in early ATA)
+ * INITIALIZE DEVICE PARAMETERS (later IDE and ATA)
* anything else..
* Some drives were very specific about that exact sequence.
+ *
+ * Note that ATA4 says lba is mandatory so the second check
+ * shoud never trigger.
*/
if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -1772,13 +1859,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
static inline u8 ata_dev_knobble(struct ata_device *dev)
{
- return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+ struct ata_port *ap = dev->link->ap;
+ return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
static void ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
if (!ata_id_has_ncq(dev->id)) {
@@ -1815,8 +1903,8 @@ static void ata_dev_config_ncq(struct ata_device *dev,
*/
int ata_dev_configure(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
const u16 *id = dev->id;
unsigned int xfer_mask;
@@ -1842,6 +1930,11 @@ int ata_dev_configure(struct ata_device *dev)
if (rc)
return rc;
+ /* massage HPA, do it early as it might change IDENTIFY data */
+ rc = ata_hpa_resize(dev);
+ if (rc)
+ return rc;
+
/* print device capabilities */
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG,
@@ -1909,9 +2002,6 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}
- if (ata_id_hpa_enabled(dev->id))
- dev->n_sectors = ata_hpa_resize(dev);
-
/* config NCQ */
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
@@ -1960,7 +2050,9 @@ int ata_dev_configure(struct ata_device *dev)
/* ATAPI-specific feature tests */
else if (dev->class == ATA_DEV_ATAPI) {
- char *cdb_intr_string = "";
+ const char *cdb_intr_string = "";
+ const char *atapi_an_string = "";
+ u32 sntf;
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -1972,6 +2064,28 @@ int ata_dev_configure(struct ata_device *dev)
}
dev->cdb_len = (unsigned int) rc;
+ /* Enable ATAPI AN if both the host and device have
+ * the support. If PMP is attached, SNTF is required
+ * to enable ATAPI AN to discern between PHY status
+ * changed notifications and ATAPI ANs.
+ */
+ if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+ (!ap->nr_pmp_links ||
+ sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
+ unsigned int err_mask;
+
+ /* issue SET feature command to turn this on */
+ err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE);
+ if (err_mask)
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to enable ATAPI AN "
+ "(err_mask=0x%x)\n", err_mask);
+ else {
+ dev->flags |= ATA_DFLAG_AN;
+ atapi_an_string = ", ATAPI AN";
+ }
+ }
+
if (ata_id_cdb_intr(dev->id)) {
dev->flags |= ATA_DFLAG_CDB_INTR;
cdb_intr_string = ", CDB intr";
@@ -1980,10 +2094,10 @@ int ata_dev_configure(struct ata_device *dev)
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
- "ATAPI: %s, %s, max %s%s\n",
+ "ATAPI: %s, %s, max %s%s%s\n",
modelbuf, fwrevbuf,
ata_mode_string(xfer_mask),
- cdb_intr_string);
+ cdb_intr_string, atapi_an_string);
}
/* determine max_sectors */
@@ -2100,21 +2214,19 @@ int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES];
- int i, rc;
+ int rc;
struct ata_device *dev;
ata_port_probe(ap);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- tries[i] = ATA_PROBE_MAX_TRIES;
+ ata_link_for_each_dev(dev, &ap->link)
+ tries[dev->devno] = ATA_PROBE_MAX_TRIES;
retry:
/* reset and determine device classes */
ap->ops->phy_reset(ap);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, &ap->link) {
if (!(ap->flags & ATA_FLAG_DISABLED) &&
dev->class != ATA_DEV_UNKNOWN)
classes[dev->devno] = dev->class;
@@ -2129,18 +2241,16 @@ int ata_bus_probe(struct ata_port *ap)
/* after the reset the device state is PIO 0 and the controller
state is undefined. Record the mode */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->pio_mode = XFER_PIO_0;
/* read IDENTIFY page and configure devices. We have to do the identify
specific sequence bass-ackwards so that PDIAG- is released by
the slave device */
- for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
- dev = &ap->device[i];
-
- if (tries[i])
- dev->class = classes[i];
+ ata_link_for_each_dev(dev, &ap->link) {
+ if (tries[dev->devno])
+ dev->class = classes[dev->devno];
if (!ata_dev_enabled(dev))
continue;
@@ -2155,33 +2265,42 @@ int ata_bus_probe(struct ata_port *ap)
if (ap->ops->cable_detect)
ap->cbl = ap->ops->cable_detect(ap);
+ /* We may have SATA bridge glue hiding here irrespective of the
+ reported cable types and sensed types */
+ ata_link_for_each_dev(dev, &ap->link) {
+ if (!ata_dev_enabled(dev))
+ continue;
+ /* SATA drives indicate we have a bridge. We don't know which
+ end of the link the bridge is which is a problem */
+ if (ata_id_is_sata(dev->id))
+ ap->cbl = ATA_CBL_SATA;
+ }
+
/* After the identify sequence we can now set up the devices. We do
this in the normal order so that the user doesn't get confused */
- for(i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, &ap->link) {
if (!ata_dev_enabled(dev))
continue;
- ap->eh_context.i.flags |= ATA_EHI_PRINTINFO;
+ ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
- ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
+ ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
if (rc)
goto fail;
}
/* configure transfer mode */
- rc = ata_set_mode(ap, &dev);
+ rc = ata_set_mode(&ap->link, &dev);
if (rc)
goto fail;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
+ ata_link_for_each_dev(dev, &ap->link)
+ if (ata_dev_enabled(dev))
return 0;
/* no device present, disable port */
ata_port_disable(ap);
- ap->ops->port_disable(ap);
return -ENODEV;
fail:
@@ -2201,7 +2320,7 @@ int ata_bus_probe(struct ata_port *ap)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(&ap->link);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2230,28 +2349,28 @@ void ata_port_probe(struct ata_port *ap)
/**
* sata_print_link_status - Print SATA link status
- * @ap: SATA port to printk link status about
+ * @link: SATA link to printk link status about
*
* This function prints link speed and status of a SATA link.
*
* LOCKING:
* None.
*/
-void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_link *link)
{
u32 sstatus, scontrol, tmp;
- if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+ if (sata_scr_read(link, SCR_STATUS, &sstatus))
return;
- sata_scr_read(ap, SCR_CONTROL, &scontrol);
+ sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (ata_port_online(ap)) {
+ if (ata_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
- ata_port_printk(ap, KERN_INFO,
+ ata_link_printk(link, KERN_INFO,
"SATA link up %s (SStatus %X SControl %X)\n",
sata_spd_string(tmp), sstatus, scontrol);
} else {
- ata_port_printk(ap, KERN_INFO,
+ ata_link_printk(link, KERN_INFO,
"SATA link down (SStatus %X SControl %X)\n",
sstatus, scontrol);
}
@@ -2271,32 +2390,33 @@ void sata_print_link_status(struct ata_port *ap)
*/
void __sata_phy_reset(struct ata_port *ap)
{
- u32 sstatus;
+ struct ata_link *link = &ap->link;
unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus;
if (ap->flags & ATA_FLAG_SATA_RESET) {
/* issue phy wake/reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(link, SCR_CONTROL, 0x301);
/* Couldn't find anything in SATA I/II specs, but
* AHCI-1.1 10.4.2 says at least 1 ms. */
mdelay(1);
}
/* phy wake/clear reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(link, SCR_CONTROL, 0x300);
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sata_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* TODO: phy layer with polling, timeouts, etc. */
- if (!ata_port_offline(ap))
+ if (!ata_link_offline(link))
ata_port_probe(ap);
else
ata_port_disable(ap);
@@ -2341,8 +2461,8 @@ void sata_phy_reset(struct ata_port *ap)
struct ata_device *ata_dev_pair(struct ata_device *adev)
{
- struct ata_port *ap = adev->ap;
- struct ata_device *pair = &ap->device[1 - adev->devno];
+ struct ata_link *link = adev->link;
+ struct ata_device *pair = &link->device[1 - adev->devno];
if (!ata_dev_enabled(pair))
return NULL;
return pair;
@@ -2363,16 +2483,16 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
void ata_port_disable(struct ata_port *ap)
{
- ap->device[0].class = ATA_DEV_NONE;
- ap->device[1].class = ATA_DEV_NONE;
+ ap->link.device[0].class = ATA_DEV_NONE;
+ ap->link.device[1].class = ATA_DEV_NONE;
ap->flags |= ATA_FLAG_DISABLED;
}
/**
* sata_down_spd_limit - adjust SATA spd limit downward
- * @ap: Port to adjust SATA spd limit for
+ * @link: Link to adjust SATA spd limit for
*
- * Adjust SATA spd limit of @ap downward. Note that this
+ * Adjust SATA spd limit of @link downward. Note that this
* function only adjusts the limit. The change must be applied
* using sata_set_spd().
*
@@ -2382,45 +2502,59 @@ void ata_port_disable(struct ata_port *ap)
* RETURNS:
* 0 on success, negative errno on failure
*/
-int sata_down_spd_limit(struct ata_port *ap)
+int sata_down_spd_limit(struct ata_link *link)
{
u32 sstatus, spd, mask;
int rc, highbit;
- rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
- if (rc)
- return rc;
+ if (!sata_scr_valid(link))
+ return -EOPNOTSUPP;
+
+ /* If SCR can be read, use it to determine the current SPD.
+ * If not, use cached value in link->sata_spd.
+ */
+ rc = sata_scr_read(link, SCR_STATUS, &sstatus);
+ if (rc == 0)
+ spd = (sstatus >> 4) & 0xf;
+ else
+ spd = link->sata_spd;
- mask = ap->sata_spd_limit;
+ mask = link->sata_spd_limit;
if (mask <= 1)
return -EINVAL;
+
+ /* unconditionally mask off the highest bit */
highbit = fls(mask) - 1;
mask &= ~(1 << highbit);
- spd = (sstatus >> 4) & 0xf;
- if (spd <= 1)
- return -EINVAL;
- spd--;
- mask &= (1 << spd) - 1;
+ /* Mask off all speeds higher than or equal to the current
+ * one. Force 1.5Gbps if current SPD is not available.
+ */
+ if (spd > 1)
+ mask &= (1 << (spd - 1)) - 1;
+ else
+ mask &= 1;
+
+ /* were we already at the bottom? */
if (!mask)
return -EINVAL;
- ap->sata_spd_limit = mask;
+ link->sata_spd_limit = mask;
- ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+ ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
sata_spd_string(fls(mask)));
return 0;
}
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
{
u32 spd, limit;
- if (ap->sata_spd_limit == UINT_MAX)
+ if (link->sata_spd_limit == UINT_MAX)
limit = 0;
else
- limit = fls(ap->sata_spd_limit);
+ limit = fls(link->sata_spd_limit);
spd = (*scontrol >> 4) & 0xf;
*scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
@@ -2430,10 +2564,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
/**
* sata_set_spd_needed - is SATA spd configuration needed
- * @ap: Port in question
+ * @link: Link in question
*
* Test whether the spd limit in SControl matches
- * @ap->sata_spd_limit. This function is used to determine
+ * @link->sata_spd_limit. This function is used to determine
* whether hardreset is necessary to apply SATA spd
* configuration.
*
@@ -2443,21 +2577,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
* RETURNS:
* 1 if SATA spd configuration is needed, 0 otherwise.
*/
-int sata_set_spd_needed(struct ata_port *ap)
+int sata_set_spd_needed(struct ata_link *link)
{
u32 scontrol;
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+ if (sata_scr_read(link, SCR_CONTROL, &scontrol))
return 0;
- return __sata_set_spd_needed(ap, &scontrol);
+ return __sata_set_spd_needed(link, &scontrol);
}
/**
* sata_set_spd - set SATA spd according to spd limit
- * @ap: Port to set SATA spd for
+ * @link: Link to set SATA spd for
*
- * Set SATA spd of @ap according to sata_spd_limit.
+ * Set SATA spd of @link according to sata_spd_limit.
*
* LOCKING:
* Inherited from caller.
@@ -2466,18 +2600,18 @@ int sata_set_spd_needed(struct ata_port *ap)
* 0 if spd doesn't need to be changed, 1 if spd has been
* changed. Negative errno if SCR registers are inaccessible.
*/
-int sata_set_spd(struct ata_port *ap)
+int sata_set_spd(struct ata_link *link)
{
u32 scontrol;
int rc;
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
- if (!__sata_set_spd_needed(ap, &scontrol))
+ if (!__sata_set_spd_needed(link, &scontrol))
return 0;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
return rc;
return 1;
@@ -2732,7 +2866,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
static int ata_dev_set_mode(struct ata_device *dev)
{
- struct ata_eh_context *ehc = &dev->ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
unsigned int err_mask;
int rc;
@@ -2744,7 +2878,11 @@ static int ata_dev_set_mode(struct ata_device *dev)
/* Old CFA may refuse this command, which is just fine */
if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
err_mask &= ~AC_ERR_DEV;
-
+ /* Some very old devices and some bad newer ones fail any kind of
+ SET_XFERMODE request but support PIO0-2 timings and no IORDY */
+ if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
+ dev->pio_mode <= XFER_PIO_2)
+ err_mask &= ~AC_ERR_DEV;
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
"(err_mask=0x%x)\n", err_mask);
@@ -2752,7 +2890,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
}
ehc->i.flags |= ATA_EHI_POST_SETMODE;
- rc = ata_dev_revalidate(dev, 0);
+ rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
if (rc)
return rc;
@@ -2767,7 +2905,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
/**
* ata_do_set_mode - Program timings and issue SET FEATURES - XFER
- * @ap: port on which timings will be programmed
+ * @link: link on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
* Standard implementation of the function used to tune and set
@@ -2782,25 +2920,36 @@ static int ata_dev_set_mode(struct ata_device *dev)
* 0 on success, negative errno otherwise
*/
-int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
+ struct ata_port *ap = link->ap;
struct ata_device *dev;
- int i, rc = 0, used_dma = 0, found = 0;
-
+ int rc = 0, used_dma = 0, found = 0;
/* step 1: calculate xfer_mask */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ ata_link_for_each_dev(dev, link) {
unsigned int pio_mask, dma_mask;
-
- dev = &ap->device[i];
+ unsigned int mode_mask;
if (!ata_dev_enabled(dev))
continue;
+ mode_mask = ATA_DMA_MASK_ATA;
+ if (dev->class == ATA_DEV_ATAPI)
+ mode_mask = ATA_DMA_MASK_ATAPI;
+ else if (ata_id_is_cfa(dev->id))
+ mode_mask = ATA_DMA_MASK_CFA;
+
ata_dev_xfermask(dev);
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+
+ if (libata_dma_mask & mode_mask)
+ dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+ else
+ dma_mask = 0;
+
dev->pio_mode = ata_xfer_mask2mode(pio_mask);
dev->dma_mode = ata_xfer_mask2mode(dma_mask);
@@ -2812,8 +2961,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
goto out;
/* step 2: always set host PIO timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev))
continue;
@@ -2830,9 +2978,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/* step 3: set host DMA timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev) || !dev->dma_mode)
continue;
@@ -2843,9 +2989,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/* step 4: update devices' xfer mode */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
/* don't update suspended devices' xfer mode */
if (!ata_dev_enabled(dev))
continue;
@@ -2869,7 +3013,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
/**
* ata_set_mode - Program timings and issue SET FEATURES - XFER
- * @ap: port on which timings will be programmed
+ * @link: link on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
* Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
@@ -2882,12 +3026,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
+ struct ata_port *ap = link->ap;
+
/* has private set_mode? */
if (ap->ops->set_mode)
- return ap->ops->set_mode(ap, r_failed_dev);
- return ata_do_set_mode(ap, r_failed_dev);
+ return ap->ops->set_mode(link, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
}
/**
@@ -2990,7 +3136,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
if (!(status & ATA_BUSY))
return 0;
- if (!ata_port_online(ap) && status == 0xff)
+ if (!ata_link_online(&ap->link) && status == 0xff)
return -ENODEV;
if (time_after(now, deadline))
return -EBUSY;
@@ -3071,6 +3217,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct ata_device *dev;
+ int i = 0;
DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
@@ -3081,6 +3229,25 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
+ /* If we issued an SRST then an ATA drive (not ATAPI)
+ * may have changed configuration and be in PIO0 timing. If
+ * we did a hard reset (or are coming from power on) this is
+ * true for ATA or ATAPI. Until we've set a suitable controller
+ * mode we should not touch the bus as we may be talking too fast.
+ */
+
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->pio_mode = XFER_PIO_0;
+
+ /* If the controller has a pio mode setup function then use
+ it to set the chipset to rights. Don't touch the DMA setup
+ as that will be dealt with when revalidating */
+ if (ap->ops->set_piomode) {
+ ata_link_for_each_dev(dev, &ap->link)
+ if (devmask & (1 << i++))
+ ap->ops->set_piomode(ap, dev);
+ }
+
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
* ATAPI devices in Hale Landis's ATADRVR, for the period of time
@@ -3125,6 +3292,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
void ata_bus_reset(struct ata_port *ap)
{
+ struct ata_device *device = ap->link.device;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
u8 err;
@@ -3160,19 +3328,19 @@ void ata_bus_reset(struct ata_port *ap)
/*
* determine by signature whether we have ATA or ATAPI devices
*/
- ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+ device[0].class = ata_dev_try_classify(&device[0], dev0, &err);
if ((slave_possible) && (err != 0x81))
- ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+ device[1].class = ata_dev_try_classify(&device[1], dev1, &err);
/* is double-select really necessary? */
- if (ap->device[1].class != ATA_DEV_NONE)
+ if (device[1].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 1);
- if (ap->device[0].class != ATA_DEV_NONE)
+ if (device[0].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 0);
/* if no devices were detected, disable this port */
- if ((ap->device[0].class == ATA_DEV_NONE) &&
- (ap->device[1].class == ATA_DEV_NONE))
+ if ((device[0].class == ATA_DEV_NONE) &&
+ (device[1].class == ATA_DEV_NONE))
goto err_out;
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
@@ -3185,18 +3353,18 @@ void ata_bus_reset(struct ata_port *ap)
err_out:
ata_port_printk(ap, KERN_ERR, "disabling port\n");
- ap->ops->port_disable(ap);
+ ata_port_disable(ap);
DPRINTK("EXIT\n");
}
/**
- * sata_phy_debounce - debounce SATA phy status
- * @ap: ATA port to debounce SATA phy status for
+ * sata_link_debounce - debounce SATA phy status
+ * @link: ATA link to debounce SATA phy status for
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * Make sure SStatus of @ap reaches stable state, determined by
+* Make sure SStatus of @link reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the
* beginning of the stable state. Because DET gets stuck at 1 on
@@ -3212,8 +3380,8 @@ err_out:
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
- unsigned long deadline)
+int sata_link_debounce(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline)
{
unsigned long interval_msec = params[0];
unsigned long duration = msecs_to_jiffies(params[1]);
@@ -3225,7 +3393,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
if (time_before(t, deadline))
deadline = t;
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3234,7 +3402,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
while (1) {
msleep(interval_msec);
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3251,19 +3419,21 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
last = cur;
last_jiffies = jiffies;
- /* check deadline */
+ /* Check deadline. If debouncing failed, return
+ * -EPIPE to tell upper layer to lower link speed.
+ */
if (time_after(jiffies, deadline))
- return -EBUSY;
+ return -EPIPE;
}
}
/**
- * sata_phy_resume - resume SATA phy
- * @ap: ATA port to resume SATA phy for
+ * sata_link_resume - resume SATA link
+ * @link: ATA link to resume SATA
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * Resume SATA phy of @ap and debounce it.
+ * Resume SATA phy @link and debounce it.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3271,18 +3441,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
- unsigned long deadline)
+int sata_link_resume(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline)
{
u32 scontrol;
int rc;
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
scontrol = (scontrol & 0x0f0) | 0x300;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
return rc;
/* Some PHYs react badly if SStatus is pounded immediately
@@ -3290,15 +3460,15 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
*/
msleep(200);
- return sata_phy_debounce(ap, params, deadline);
+ return sata_link_debounce(link, params, deadline);
}
/**
* ata_std_prereset - prepare for reset
- * @ap: ATA port to be reset
+ * @link: ATA link to be reset
* @deadline: deadline jiffies for the operation
*
- * @ap is about to be reset. Initialize it. Failure from
+ * @link is about to be reset. Initialize it. Failure from
* prereset makes libata abort whole reset sequence and give up
* that port, so prereset should be best-effort. It does its
* best to prepare for reset sequence but if things go wrong, it
@@ -3310,37 +3480,44 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
+int ata_std_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
/* handle link resume */
if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
- (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* Some PMPs don't work with only SRST, force hardreset if PMP
+ * is supported.
+ */
+ if (ap->flags & ATA_FLAG_PMP)
ehc->i.action |= ATA_EH_HARDRESET;
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
- /* if SATA, resume phy */
+ /* if SATA, resume link */
if (ap->flags & ATA_FLAG_SATA) {
- rc = sata_phy_resume(ap, timing, deadline);
+ rc = sata_link_resume(link, timing, deadline);
/* whine about phy resume failure but proceed */
if (rc && rc != -EOPNOTSUPP)
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
"link for reset (errno=%d)\n", rc);
}
/* Wait for !BSY if the controller can wait for the first D2H
* Reg FIS and we don't know that no device is attached.
*/
- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+ if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) {
rc = ata_wait_ready(ap, deadline);
if (rc && rc != -ENODEV) {
- ata_port_printk(ap, KERN_WARNING, "device not ready "
+ ata_link_printk(link, KERN_WARNING, "device not ready "
"(errno=%d), forcing hardreset\n", rc);
ehc->i.action |= ATA_EH_HARDRESET;
}
@@ -3351,7 +3528,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
/**
* ata_std_softreset - reset host port via ATA SRST
- * @ap: port to reset
+ * @link: ATA link to reset
* @classes: resulting classes of attached devices
* @deadline: deadline jiffies for the operation
*
@@ -3363,9 +3540,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+int ata_std_softreset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0;
int rc;
@@ -3373,7 +3551,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -3391,15 +3569,17 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
DPRINTK("about to softreset, devmask=%x\n", devmask);
rc = ata_bus_softreset(ap, devmask, deadline);
/* if link is occupied, -ENODEV too is an error */
- if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+ ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
return rc;
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
+ classes[0] = ata_dev_try_classify(&link->device[0],
+ devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
+ classes[1] = ata_dev_try_classify(&link->device[1],
+ devmask & (1 << 1), &err);
out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -3407,12 +3587,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
}
/**
- * sata_port_hardreset - reset port via SATA phy reset
- * @ap: port to reset
+ * sata_link_hardreset - reset link via SATA phy reset
+ * @link: link to reset
* @timing: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * SATA phy-reset host port using DET bits of SControl register.
+ * SATA phy-reset @link using DET bits of SControl register.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3420,7 +3600,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
unsigned long deadline)
{
u32 scontrol;
@@ -3428,30 +3608,30 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
DPRINTK("ENTER\n");
- if (sata_set_spd_needed(ap)) {
+ if (sata_set_spd_needed(link)) {
/* SATA spec says nothing about how to reconfigure
* spd. To be on the safe side, turn off phy during
* reconfiguration. This works for at least ICH7 AHCI
* and Sil3124.
*/
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
goto out;
scontrol = (scontrol & 0x0f0) | 0x304;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
goto out;
- sata_set_spd(ap);
+ sata_set_spd(link);
}
/* issue phy wake/reset */
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
goto out;
scontrol = (scontrol & 0x0f0) | 0x301;
- if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
goto out;
/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -3459,8 +3639,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
*/
msleep(1);
- /* bring phy back */
- rc = sata_phy_resume(ap, timing, deadline);
+ /* bring link back */
+ rc = sata_link_resume(link, timing, deadline);
out:
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
@@ -3468,7 +3648,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
/**
* sata_std_hardreset - reset host port via SATA phy reset
- * @ap: port to reset
+ * @link: link to reset
* @class: resulting class of attached device
* @deadline: deadline jiffies for the operation
*
@@ -3481,24 +3661,25 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+int sata_std_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ struct ata_port *ap = link->ap;
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
int rc;
DPRINTK("ENTER\n");
/* do hardreset */
- rc = sata_port_hardreset(ap, timing, deadline);
+ rc = sata_link_hardreset(link, timing, deadline);
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
return rc;
}
/* TODO: phy layer with polling, timeouts, etc. */
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
*class = ATA_DEV_NONE;
DPRINTK("EXIT, link offline\n");
return 0;
@@ -3507,17 +3688,27 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
/* wait a while before checking status, see SRST for more info */
msleep(150);
+ /* If PMP is supported, we have to do follow-up SRST. Note
+ * that some PMPs don't send D2H Reg FIS after hardreset at
+ * all if the first port is empty. Wait for it just for a
+ * second and request follow-up SRST.
+ */
+ if (ap->flags & ATA_FLAG_PMP) {
+ ata_wait_ready(ap, jiffies + HZ);
+ return -EAGAIN;
+ }
+
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
return rc;
}
ap->ops->dev_select(ap, 0); /* probably unnecessary */
- *class = ata_dev_try_classify(ap, 0, NULL);
+ *class = ata_dev_try_classify(link->device, 1, NULL);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
@@ -3525,7 +3716,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
/**
* ata_std_postreset - standard postreset callback
- * @ap: the target ata_port
+ * @link: the target ata_link
* @classes: classes of attached devices
*
* This function is invoked after a successful reset. Note that
@@ -3535,18 +3726,19 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
* LOCKING:
* Kernel thread context (may sleep)
*/
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
u32 serror;
DPRINTK("ENTER\n");
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* clear SError */
- if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
- sata_scr_write(ap, SCR_ERROR, serror);
+ if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+ sata_scr_write(link, SCR_ERROR, serror);
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -3633,7 +3825,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
{
unsigned int class = dev->class;
- u16 *id = (void *)dev->ap->sector_buf;
+ u16 *id = (void *)dev->link->ap->sector_buf;
int rc;
/* read ID data */
@@ -3652,6 +3844,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
/**
* ata_dev_revalidate - Revalidate ATA device
* @dev: device to revalidate
+ * @new_class: new class code
* @readid_flags: read ID flags
*
* Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3663,7 +3856,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
int rc;
@@ -3671,6 +3865,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
if (!ata_dev_enabled(dev))
return -ENODEV;
+ /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
+ if (ata_class_enabled(new_class) &&
+ new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+ ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
+ dev->class, new_class);
+ rc = -ENODEV;
+ goto fail;
+ }
+
/* re-read ID */
rc = ata_dev_reread_id(dev, readid_flags);
if (rc)
@@ -3682,11 +3885,16 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
goto fail;
/* verify n_sectors hasn't changed */
- if (dev->class == ATA_DEV_ATA && dev->n_sectors != n_sectors) {
+ if (dev->class == ATA_DEV_ATA && n_sectors &&
+ dev->n_sectors != n_sectors) {
ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
"%llu != %llu\n",
(unsigned long long)n_sectors,
(unsigned long long)dev->n_sectors);
+
+ /* restore original n_sectors */
+ dev->n_sectors = n_sectors;
+
rc = -ENODEV;
goto fail;
}
@@ -3739,6 +3947,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */
{ "IOMEGA ZIP 250 ATAPI Floppy",
NULL, ATA_HORKAGE_NODMA },
+ /* Odd clown on sil3726/4726 PMPs */
+ { "Config Disk", NULL, ATA_HORKAGE_NODMA |
+ ATA_HORKAGE_SKIP_PM },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
@@ -3751,13 +3962,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* http://thread.gmane.org/gmane.linux.ide/14907 */
{ "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ },
/* NCQ is broken */
- { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ },
- { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ },
- { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ },
- { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
- ATA_HORKAGE_NONCQ },
- /* NCQ hard hangs device under heavier load, needs hard power cycle */
- { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ },
+ { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ },
+ { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ },
+ { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ },
+
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
@@ -3766,16 +3976,49 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Drives which do spurious command completion */
{ "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, },
{ "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, },
+ { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, },
{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
+ { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, },
{ "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
-
- /* Devices with NCQ limits */
+ { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, },
+ { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, },
+ { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, },
+ { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, },
+
+ /* devices which puke on READ_NATIVE_MAX */
+ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, },
+ { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA },
+ { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
+ { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA },
+
+ /* Devices which report 1 sector over size HPA */
+ { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, },
+ { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, },
/* End Marker */
{ }
};
+int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+{
+ const char *p;
+ int len;
+
+ /*
+ * check for trailing wildcard: *\0
+ */
+ p = strchr(patt, wildchar);
+ if (p && ((*(p + 1)) == 0))
+ len = p - patt;
+ else
+ len = strlen(name);
+
+ return strncmp(patt, name, len);
+}
+
static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -3786,10 +4029,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strcmp(ad->model_num, model_num)) {
+ if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strcmp(ad->model_rev, model_rev))
+ if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
return ad->horkage;
}
ad++;
@@ -3803,7 +4046,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
* DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
* if the LLDD handles only interrupts in the HSM_ST_LAST state.
*/
- if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+ if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) &&
(dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0;
@@ -3823,7 +4066,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
*/
static void ata_dev_xfermask(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
struct ata_host *host = ap->host;
unsigned long xfer_mask;
@@ -3921,7 +4165,43 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
tf.protocol = ATA_PROT_NODATA;
tf.nsect = dev->xfer_mode;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
+/**
+ * ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES
+ * @dev: Device to which command will be sent
+ * @enable: Whether to enable or disable the feature
+ *
+ * Issue SET FEATURES - SATA FEATURES command to device @dev
+ * on port @ap with sector count set to indicate Asynchronous
+ * Notification feature
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ /* set up set-features taskfile */
+ DPRINTK("set features - SATA features\n");
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = enable;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = SATA_AN;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -3959,7 +4239,12 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
tf.nsect = sectors;
tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ /* A clean abort indicates an original or just out of spec drive
+ and we should continue as we issue the setup based on the
+ drive reported working geometry */
+ if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+ err_mask = 0;
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -4168,6 +4453,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
}
/**
+ * ata_std_qc_defer - Check whether a qc needs to be deferred
+ * @qc: ATA command in question
+ *
+ * Non-NCQ commands cannot run with any other command, NCQ or
+ * not. As upper layer only knows the queue depth, we are
+ * responsible for maintaining exclusion. This function checks
+ * whether a new command @qc can be issued.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (!ata_tag_valid(link->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(link->active_tag) && !link->sactive)
+ return 0;
+ }
+
+ return ATA_DEFER_LINK;
+}
+
+/**
* ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared
*
@@ -4443,7 +4758,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
@@ -4572,6 +4887,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
ata_pio_sector(qc);
} else
ata_pio_sector(qc);
+
+ ata_altstatus(qc->ap); /* flush */
}
/**
@@ -4746,6 +5063,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
__atapi_pio_bytes(qc, bytes);
+ ata_altstatus(ap); /* flush */
return;
@@ -4917,7 +5235,6 @@ fsm_start:
*/
ap->hsm_task_state = HSM_ST;
ata_pio_sectors(qc);
- ata_altstatus(ap); /* flush */
} else
/* send CDB */
atapi_send_cdb(ap, qc);
@@ -4998,7 +5315,6 @@ fsm_start:
if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
ata_pio_sectors(qc);
- ata_altstatus(ap);
status = ata_wait_idle(ap);
}
@@ -5018,13 +5334,11 @@ fsm_start:
if (ap->hsm_task_state == HSM_ST_LAST &&
(!(qc->tf.flags & ATA_TFLAG_WRITE))) {
/* all data read */
- ata_altstatus(ap);
status = ata_wait_idle(ap);
goto fsm_start;
}
}
- ata_altstatus(ap); /* flush */
poll_next = 1;
break;
@@ -5149,7 +5463,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
qc = ata_qc_new(ap);
@@ -5192,6 +5506,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -5200,10 +5515,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
- ap->sactive &= ~(1 << qc->tag);
- else
- ap->active_tag = ATA_TAG_POISON;
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ link->sactive &= ~(1 << qc->tag);
+ if (!link->sactive)
+ ap->nr_active_links--;
+ } else {
+ link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+ }
+
+ /* clear exclusive status */
+ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+ ap->excl_link == link))
+ ap->excl_link = NULL;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
@@ -5372,19 +5696,25 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
void ata_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
/* Make sure only one non-NCQ command is outstanding. The
* check is skipped for old EH because it reuses active qc to
* request ATAPI sense.
*/
- WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+ WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
if (qc->tf.protocol == ATA_PROT_NCQ) {
- WARN_ON(ap->sactive & (1 << qc->tag));
- ap->sactive |= 1 << qc->tag;
+ WARN_ON(link->sactive & (1 << qc->tag));
+
+ if (!link->sactive)
+ ap->nr_active_links++;
+ link->sactive |= 1 << qc->tag;
} else {
- WARN_ON(ap->sactive);
- ap->active_tag = qc->tag;
+ WARN_ON(link->sactive);
+
+ ap->nr_active_links++;
+ link->active_tag = qc->tag;
}
qc->flags |= ATA_QCFLAG_ACTIVE;
@@ -5567,7 +5897,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
inline unsigned int ata_host_intr (struct ata_port *ap,
struct ata_queued_cmd *qc)
{
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
u8 status, host_stat = 0;
VPRINTK("ata%u: protocol %d task_state %d\n",
@@ -5641,7 +5971,8 @@ idle_irq:
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
- ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
@@ -5682,7 +6013,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
@@ -5696,9 +6027,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
/**
* sata_scr_valid - test whether SCRs are accessible
- * @ap: ATA port to test SCR accessibility for
+ * @link: ATA link to test SCR accessibility for
*
- * Test whether SCRs are accessible for @ap.
+ * Test whether SCRs are accessible for @link.
*
* LOCKING:
* None.
@@ -5706,64 +6037,74 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
* RETURNS:
* 1 if SCRs are accessible, 0 otherwise.
*/
-int sata_scr_valid(struct ata_port *ap)
+int sata_scr_valid(struct ata_link *link)
{
+ struct ata_port *ap = link->ap;
+
return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
}
/**
* sata_scr_read - read SCR register of the specified port
- * @ap: ATA port to read SCR for
+ * @link: ATA link to read SCR for
* @reg: SCR to read
* @val: Place to store read value
*
- * Read SCR register @reg of @ap into *@val. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
+ * Read SCR register @reg of @link into *@val. This function is
+ * guaranteed to succeed if @link is ap->link, the cable type of
+ * the port is SATA and the port implements ->scr_read.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
{
- if (sata_scr_valid(ap)) {
- *val = ap->ops->scr_read(ap, reg);
- return 0;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+
+ if (sata_scr_valid(link))
+ return ap->ops->scr_read(ap, reg, val);
+ return -EOPNOTSUPP;
}
- return -EOPNOTSUPP;
+
+ return sata_pmp_scr_read(link, reg, val);
}
/**
* sata_scr_write - write SCR register of the specified port
- * @ap: ATA port to write SCR for
+ * @link: ATA link to write SCR for
* @reg: SCR to write
* @val: value to write
*
- * Write @val to SCR register @reg of @ap. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
+ * Write @val to SCR register @reg of @link. This function is
+ * guaranteed to succeed if @link is ap->link, the cable type of
+ * the port is SATA and the port implements ->scr_read.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
{
- if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- return 0;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+
+ if (sata_scr_valid(link))
+ return ap->ops->scr_write(ap, reg, val);
+ return -EOPNOTSUPP;
}
- return -EOPNOTSUPP;
+
+ return sata_pmp_scr_write(link, reg, val);
}
/**
* sata_scr_write_flush - write SCR register of the specified port and flush
- * @ap: ATA port to write SCR for
+ * @link: ATA link to write SCR for
* @reg: SCR to write
* @val: value to write
*
@@ -5771,28 +6112,36 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
* function performs flush after writing to the register.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{
- if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- ap->ops->scr_read(ap, reg);
- return 0;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+ int rc;
+
+ if (sata_scr_valid(link)) {
+ rc = ap->ops->scr_write(ap, reg, val);
+ if (rc == 0)
+ rc = ap->ops->scr_read(ap, reg, &val);
+ return rc;
+ }
+ return -EOPNOTSUPP;
}
- return -EOPNOTSUPP;
+
+ return sata_pmp_scr_write(link, reg, val);
}
/**
- * ata_port_online - test whether the given port is online
- * @ap: ATA port to test
+ * ata_link_online - test whether the given link is online
+ * @link: ATA link to test
*
- * Test whether @ap is online. Note that this function returns 0
- * if online status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
+ * Test whether @link is online. Note that this function returns
+ * 0 if online status of @link cannot be obtained, so
+ * ata_link_online(link) != !ata_link_offline(link).
*
* LOCKING:
* None.
@@ -5800,22 +6149,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
* RETURNS:
* 1 if the port online status is available and online.
*/
-int ata_port_online(struct ata_port *ap)
+int ata_link_online(struct ata_link *link)
{
u32 sstatus;
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+ (sstatus & 0xf) == 0x3)
return 1;
return 0;
}
/**
- * ata_port_offline - test whether the given port is offline
- * @ap: ATA port to test
+ * ata_link_offline - test whether the given link is offline
+ * @link: ATA link to test
*
- * Test whether @ap is offline. Note that this function returns
- * 0 if offline status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
+ * Test whether @link is offline. Note that this function
+ * returns 0 if offline status of @link cannot be obtained, so
+ * ata_link_online(link) != !ata_link_offline(link).
*
* LOCKING:
* None.
@@ -5823,11 +6173,12 @@ int ata_port_online(struct ata_port *ap)
* RETURNS:
* 1 if the port offline status is available and offline.
*/
-int ata_port_offline(struct ata_port *ap)
+int ata_link_offline(struct ata_link *link)
{
u32 sstatus;
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+ (sstatus & 0xf) != 0x3)
return 1;
return 0;
}
@@ -5845,6 +6196,10 @@ int ata_flush_cache(struct ata_device *dev)
else
cmd = ATA_CMD_FLUSH;
+ /* This is wrong. On a failed flush we get back the LBA of the lost
+ sector and we should (assuming it wasn't aborted as unknown) issue
+ a further flush command to continue the writeback until it
+ does not error */
err_mask = ata_do_simple_cmd(dev, cmd);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
@@ -5864,6 +6219,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
/* Previous resume operation might still be in
* progress. Wait for PM_PENDING to clear.
@@ -5883,8 +6239,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
}
ap->pflags |= ATA_PFLAG_PM_PENDING;
- ap->eh_info.action |= action;
- ap->eh_info.flags |= ehi_flags;
+ __ata_port_for_each_link(link, ap) {
+ link->eh_info.action |= action;
+ link->eh_info.flags |= ehi_flags;
+ }
ata_port_schedule_eh(ap);
@@ -5988,11 +6346,13 @@ int ata_port_start(struct ata_port *ap)
*/
void ata_dev_init(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
unsigned long flags;
/* SATA spd limit is bound to the first device */
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
+ link->sata_spd_limit = link->hw_sata_spd_limit;
+ link->sata_spd = 0;
/* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using
@@ -6000,6 +6360,7 @@ void ata_dev_init(struct ata_device *dev)
*/
spin_lock_irqsave(ap->lock, flags);
dev->flags &= ~ATA_DFLAG_INIT_MASK;
+ dev->horkage = 0;
spin_unlock_irqrestore(ap->lock, flags);
memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
@@ -6010,6 +6371,70 @@ void ata_dev_init(struct ata_device *dev)
}
/**
+ * ata_link_init - Initialize an ata_link structure
+ * @ap: ATA port link is attached to
+ * @link: Link structure to initialize
+ * @pmp: Port multiplier port number
+ *
+ * Initialize @link.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+{
+ int i;
+
+ /* clear everything except for devices */
+ memset(link, 0, offsetof(struct ata_link, device[0]));
+
+ link->ap = ap;
+ link->pmp = pmp;
+ link->active_tag = ATA_TAG_POISON;
+ link->hw_sata_spd_limit = UINT_MAX;
+
+ /* can't use iterator, ap isn't initialized yet */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &link->device[i];
+
+ dev->link = link;
+ dev->devno = dev - link->device;
+ ata_dev_init(dev);
+ }
+}
+
+/**
+ * sata_link_init_spd - Initialize link->sata_spd_limit
+ * @link: Link to configure sata_spd_limit for
+ *
+ * Initialize @link->[hw_]sata_spd_limit to the currently
+ * configured value.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_link_init_spd(struct ata_link *link)
+{
+ u32 scontrol, spd;
+ int rc;
+
+ rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+ if (rc)
+ return rc;
+
+ spd = (scontrol >> 4) & 0xf;
+ if (spd)
+ link->hw_sata_spd_limit &= (1 << spd) - 1;
+
+ link->sata_spd_limit = link->hw_sata_spd_limit;
+
+ return 0;
+}
+
+/**
* ata_port_alloc - allocate and initialize basic ATA port resources
* @host: ATA host this allocated port belongs to
*
@@ -6024,7 +6449,6 @@ void ata_dev_init(struct ata_device *dev)
struct ata_port *ata_port_alloc(struct ata_host *host)
{
struct ata_port *ap;
- unsigned int i;
DPRINTK("ENTER\n");
@@ -6039,9 +6463,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->ctl = ATA_DEVCTL_OBS;
ap->host = host;
ap->dev = host->dev;
-
- ap->hw_sata_spd_limit = UINT_MAX;
- ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
#if defined(ATA_VERBOSE_DEBUG)
@@ -6058,15 +6479,13 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
+ init_timer_deferrable(&ap->fastdrain_timer);
+ ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+ ap->fastdrain_timer.data = (unsigned long)ap;
ap->cbl = ATA_CBL_NONE;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- dev->ap = ap;
- dev->devno = i;
- ata_dev_init(dev);
- }
+ ata_link_init(ap, &ap->link, 0);
#ifdef ATA_IRQ_TRAP
ap->stats.unhandled_irq = 1;
@@ -6102,6 +6521,7 @@ static void ata_host_release(struct device *gendev, void *res)
if (ap->scsi_host)
scsi_host_put(ap->scsi_host);
+ kfree(ap->pmp_link);
kfree(ap);
host->ports[i] = NULL;
}
@@ -6212,6 +6632,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
ap->mwdma_mask = pi->mwdma_mask;
ap->udma_mask = pi->udma_mask;
ap->flags |= pi->flags;
+ ap->link.flags |= pi->link_flags;
ap->ops = pi->port_ops;
if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
@@ -6347,8 +6768,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* set cable, sata_spd_limit and report */
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- int irq_line;
- u32 scontrol;
unsigned long xfer_mask;
/* set SATA cable type if still unset */
@@ -6356,32 +6775,20 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
ap->cbl = ATA_CBL_SATA;
/* init sata_spd_limit to the current value */
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
- int spd = (scontrol >> 4) & 0xf;
- if (spd)
- ap->hw_sata_spd_limit &= (1 << spd) - 1;
- }
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
- /* report the secondary IRQ for second channel legacy */
- irq_line = host->irq;
- if (i == 1 && host->irq2)
- irq_line = host->irq2;
+ sata_link_init_spd(&ap->link);
+ /* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
ap->udma_mask);
- /* print per-port info to dmesg */
- if (!ata_port_is_dummy(ap))
- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
- "ctl 0x%p bmdma 0x%p irq %d\n",
+ if (!ata_port_is_dummy(ap)) {
+ ata_port_printk(ap, KERN_INFO,
+ "%cATA max %s %s\n",
(ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
ata_mode_string(xfer_mask),
- ap->ioaddr.cmd_addr,
- ap->ioaddr.ctl_addr,
- ap->ioaddr.bmdma_addr,
- irq_line);
- else
+ ap->link.eh_info.desc);
+ ata_ehi_clear_desc(&ap->link.eh_info);
+ } else
ata_port_printk(ap, KERN_INFO, "DUMMY\n");
}
@@ -6393,7 +6800,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* probe */
if (ap->ops->error_handler) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags;
ata_port_probe(ap);
@@ -6401,7 +6808,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
- ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->probe_mask =
+ (1 << ata_link_max_devices(&ap->link)) - 1;
ehi->action |= ATA_EH_SOFTRESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
@@ -6434,7 +6842,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- ata_scsi_scan_host(ap);
+ ata_scsi_scan_host(ap, 1);
}
return 0;
@@ -6463,7 +6871,7 @@ int ata_host_activate(struct ata_host *host, int irq,
irq_handler_t irq_handler, unsigned long irq_flags,
struct scsi_host_template *sht)
{
- int rc;
+ int i, rc;
rc = ata_host_start(host);
if (rc)
@@ -6474,8 +6882,8 @@ int ata_host_activate(struct ata_host *host, int irq,
if (rc)
return rc;
- /* Used to print device info at probe */
- host->irq = irq;
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_desc(host->ports[i], "irq %d", irq);
rc = ata_host_register(host, sht);
/* if failed, just free the IRQ and leave ports alone */
@@ -6499,7 +6907,8 @@ int ata_host_activate(struct ata_host *host, int irq,
void ata_port_detach(struct ata_port *ap)
{
unsigned long flags;
- int i;
+ struct ata_link *link;
+ struct ata_device *dev;
if (!ap->ops->error_handler)
goto skip_eh;
@@ -6516,8 +6925,10 @@ void ata_port_detach(struct ata_port *ap)
*/
spin_lock_irqsave(ap->lock, flags);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link)
+ ata_dev_disable(dev);
+ }
spin_unlock_irqrestore(ap->lock, flags);
@@ -6596,7 +7007,7 @@ void ata_std_ports(struct ata_ioports *ioaddr)
*/
void ata_pci_remove_one(struct pci_dev *pdev)
{
- struct device *dev = pci_dev_to_dev(pdev);
+ struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
@@ -6804,7 +7215,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
}
const struct ata_port_operations ata_dummy_port_ops = {
- .port_disable = ata_port_disable,
.check_status = ata_dummy_check_status,
.check_altstatus = ata_dummy_check_status,
.dev_select = ata_noop_dev_select,
@@ -6866,6 +7276,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
EXPORT_SYMBOL_GPL(ata_do_set_mode);
EXPORT_SYMBOL_GPL(ata_data_xfer);
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
@@ -6882,14 +7293,14 @@ EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(ata_dev_disable);
EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+EXPORT_SYMBOL_GPL(sata_link_resume);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_port_hardreset);
+EXPORT_SYMBOL_GPL(sata_link_hardreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
EXPORT_SYMBOL_GPL(ata_dev_classify);
@@ -6910,8 +7321,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_link_online);
+EXPORT_SYMBOL_GPL(ata_link_offline);
#ifdef CONFIG_PM
EXPORT_SYMBOL_GPL(ata_host_suspend);
EXPORT_SYMBOL_GPL(ata_host_resume);
@@ -6942,19 +7353,31 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
+EXPORT_SYMBOL_GPL(sata_pmp_std_prereset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_postreset);
+EXPORT_SYMBOL_GPL(sata_pmp_do_eh);
+
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
+EXPORT_SYMBOL_GPL(ata_port_desc);
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
+#endif /* CONFIG_PCI */
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_link_abort);
EXPORT_SYMBOL_GPL(ata_port_abort);
EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(sata_async_notification);
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_do_eh);
EXPORT_SYMBOL_GPL(ata_irq_on);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
-EXPORT_SYMBOL_GPL(ata_irq_ack);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
EXPORT_SYMBOL_GPL(ata_dev_try_classify);
EXPORT_SYMBOL_GPL(ata_cable_40wire);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9aa62a0754f6..2eaa39fc65d0 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
*/
#include <linux/kernel.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
@@ -56,6 +57,7 @@ enum {
*/
enum {
ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
+ ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
};
/* The following table determines how we sequence resets. Each entry
@@ -73,7 +75,6 @@ static const unsigned long ata_eh_reset_timeouts[] = {
};
static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -85,6 +86,138 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
{ }
#endif /* CONFIG_PM */
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+ va_list args)
+{
+ ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+ ATA_EH_DESC_LEN - ehi->desc_len,
+ fmt, args);
+}
+
+/**
+ * __ata_ehi_push_desc - push error description without adding separator
+ * @ehi: target EHI
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to @ehi->desc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(ehi, fmt, args);
+ va_end(args);
+}
+
+/**
+ * ata_ehi_push_desc - push error description with separator
+ * @ehi: target EHI
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to @ehi->desc.
+ * If @ehi->desc is not empty, ", " is added in-between.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+ va_list args;
+
+ if (ehi->desc_len)
+ __ata_ehi_push_desc(ehi, ", ");
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(ehi, fmt, args);
+ va_end(args);
+}
+
+/**
+ * ata_ehi_clear_desc - clean error description
+ * @ehi: target EHI
+ *
+ * Clear @ehi->desc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+ ehi->desc[0] = '\0';
+ ehi->desc_len = 0;
+}
+
+/**
+ * ata_port_desc - append port description
+ * @ap: target ATA port
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to port
+ * description. If port description is not empty, " " is added
+ * in-between. This function is to be used while initializing
+ * ata_host. The description is printed on host registration.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+{
+ va_list args;
+
+ WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING));
+
+ if (ap->link.eh_info.desc_len)
+ __ata_ehi_push_desc(&ap->link.eh_info, " ");
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
+ va_end(args);
+}
+
+#ifdef CONFIG_PCI
+
+/**
+ * ata_port_pbar_desc - append PCI BAR description
+ * @ap: target ATA port
+ * @bar: target PCI BAR
+ * @offset: offset into PCI BAR
+ * @name: name of the area
+ *
+ * If @offset is negative, this function formats a string which
+ * contains the name, address, size and type of the BAR and
+ * appends it to the port description. If @offset is zero or
+ * positive, only name and offsetted address is appended.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+ const char *name)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ char *type = "";
+ unsigned long long start, len;
+
+ if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+ type = "m";
+ else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+ type = "i";
+
+ start = (unsigned long long)pci_resource_start(pdev, bar);
+ len = (unsigned long long)pci_resource_len(pdev, bar);
+
+ if (offset < 0)
+ ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
+ else
+ ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+}
+
+#endif /* CONFIG_PCI */
+
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
{
@@ -129,28 +262,29 @@ static int ata_ering_map(struct ata_ering *ering,
static unsigned int ata_eh_dev_action(struct ata_device *dev)
{
- struct ata_eh_context *ehc = &dev->ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
return ehc->i.action | ehc->i.dev_action[dev->devno];
}
-static void ata_eh_clear_action(struct ata_device *dev,
+static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
struct ata_eh_info *ehi, unsigned int action)
{
- int i;
+ struct ata_device *tdev;
if (!dev) {
ehi->action &= ~action;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] &= ~action;
+ ata_link_for_each_dev(tdev, link)
+ ehi->dev_action[tdev->devno] &= ~action;
} else {
/* doesn't make sense for port-wide EH actions */
WARN_ON(!(action & ATA_EH_PERDEV_MASK));
/* break ehi->action into ehi->dev_action */
if (ehi->action & action) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] |= ehi->action & action;
+ ata_link_for_each_dev(tdev, link)
+ ehi->dev_action[tdev->devno] |=
+ ehi->action & action;
ehi->action &= ~action;
}
@@ -195,7 +329,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
ret = EH_HANDLED;
spin_lock_irqsave(ap->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc) {
WARN_ON(qc->scsicmd != cmd);
qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
@@ -224,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+ int i;
unsigned long flags;
DPRINTK("ENTER\n");
@@ -290,24 +424,35 @@ void ata_scsi_error(struct Scsi_Host *host)
__ata_port_freeze(ap);
spin_unlock_irqrestore(ap->lock, flags);
+
+ /* initialize eh_tries */
+ ap->eh_tries = ATA_EH_MAX_TRIES;
} else
spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ struct ata_link *link;
+
+ /* kill fast drain timer */
+ del_timer_sync(&ap->fastdrain_timer);
+
/* process port resume request */
ata_eh_handle_port_resume(ap);
/* fetch & clear EH info */
spin_lock_irqsave(ap->lock, flags);
- memset(&ap->eh_context, 0, sizeof(ap->eh_context));
- ap->eh_context.i = ap->eh_info;
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+ __ata_port_for_each_link(link, ap) {
+ memset(&link->eh_context, 0, sizeof(link->eh_context));
+ link->eh_context.i = link->eh_info;
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
+ }
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ ap->excl_link = NULL; /* don't maintain exclusion over EH */
spin_unlock_irqrestore(ap->lock, flags);
@@ -327,20 +472,18 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_lock_irqsave(ap->lock, flags);
if (ap->pflags & ATA_PFLAG_EH_PENDING) {
- if (--repeat_cnt) {
- ata_port_printk(ap, KERN_INFO,
- "EH pending after completion, "
- "repeating EH (cnt=%d)\n", repeat_cnt);
+ if (--ap->eh_tries) {
spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
- "tries, giving up\n", ATA_EH_MAX_REPEAT);
+ "tries, giving up\n", ATA_EH_MAX_TRIES);
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
}
/* this run is complete, make sure EH info is clear */
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+ __ata_port_for_each_link(link, ap)
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
/* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
@@ -351,7 +494,7 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_unlock_irqrestore(ap->lock, flags);
} else {
- WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+ WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
ap->ops->eng_timeout(ap);
}
@@ -506,11 +649,99 @@ void ata_eng_timeout(struct ata_port *ap)
{
DPRINTK("ENTER\n");
- ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+ ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
DPRINTK("EXIT\n");
}
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+ unsigned int tag;
+ int nr = 0;
+
+ /* count only non-internal commands */
+ for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+ if (ata_qc_from_tag(ap, tag))
+ nr++;
+
+ return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+ struct ata_port *ap = (void *)arg;
+ unsigned long flags;
+ int cnt;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ cnt = ata_eh_nr_in_flight(ap);
+
+ /* are we done? */
+ if (!cnt)
+ goto out_unlock;
+
+ if (cnt == ap->fastdrain_cnt) {
+ unsigned int tag;
+
+ /* No progress during the last interval, tag all
+ * in-flight qcs as timed out and freeze the port.
+ */
+ for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+ if (qc)
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ }
+
+ ata_port_freeze(ap);
+ } else {
+ /* some qcs have finished, give it another chance */
+ ap->fastdrain_cnt = cnt;
+ ap->fastdrain_timer.expires =
+ jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ add_timer(&ap->fastdrain_timer);
+ }
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ * @ap: target ATA port
+ * @fastdrain: activate fast drain
+ *
+ * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ * is non-zero and EH wasn't pending before. Fast drain ensures
+ * that EH kicks in in timely manner.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+ int cnt;
+
+ /* already scheduled? */
+ if (ap->pflags & ATA_PFLAG_EH_PENDING)
+ return;
+
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+ if (!fastdrain)
+ return;
+
+ /* do we have in-flight qcs? */
+ cnt = ata_eh_nr_in_flight(ap);
+ if (!cnt)
+ return;
+
+ /* activate fast drain */
+ ap->fastdrain_cnt = cnt;
+ ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ add_timer(&ap->fastdrain_timer);
+}
+
/**
* ata_qc_schedule_eh - schedule qc for error handling
* @qc: command to schedule error handling for
@@ -528,7 +759,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_eh_set_pending(ap, 1);
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,34 +786,25 @@ void ata_port_schedule_eh(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_INITIALIZING)
return;
- ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_eh_set_pending(ap, 1);
scsi_schedule_eh(ap->scsi_host);
DPRINTK("port EH scheduled\n");
}
-/**
- * ata_port_abort - abort all qc's on the port
- * @ap: ATA port to abort qc's for
- *
- * Abort all active qc's of @ap and schedule EH.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
+static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
{
int tag, nr_aborted = 0;
WARN_ON(!ap->ops->error_handler);
+ /* we're gonna abort all commands, no need for fast drain */
+ ata_eh_set_pending(ap, 0);
+
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
- if (qc) {
+ if (qc && (!link || qc->dev->link == link)) {
qc->flags |= ATA_QCFLAG_FAILED;
ata_qc_complete(qc);
nr_aborted++;
@@ -596,6 +818,40 @@ int ata_port_abort(struct ata_port *ap)
}
/**
+ * ata_link_abort - abort all qc's on the link
+ * @link: ATA link to abort qc's for
+ *
+ * Abort all active qc's active on @link and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_link_abort(struct ata_link *link)
+{
+ return ata_do_link_abort(link->ap, link);
+}
+
+/**
+ * ata_port_abort - abort all qc's on the port
+ * @ap: ATA port to abort qc's for
+ *
+ * Abort all active qc's of @ap and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+ return ata_do_link_abort(ap, NULL);
+}
+
+/**
* __ata_port_freeze - freeze port
* @ap: ATA port to freeze
*
@@ -650,6 +906,79 @@ int ata_port_freeze(struct ata_port *ap)
}
/**
+ * sata_async_notification - SATA async notification handler
+ * @ap: ATA port where async notification is received
+ *
+ * Handler to be called when async notification via SDB FIS is
+ * received. This function schedules EH if necessary.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+ u32 sntf;
+ int rc;
+
+ if (!(ap->flags & ATA_FLAG_AN))
+ return 0;
+
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ if (!ap->nr_pmp_links || rc) {
+ /* PMP is not attached or SNTF is not available */
+ if (!ap->nr_pmp_links) {
+ /* PMP is not attached. Check whether ATAPI
+ * AN is configured. If so, notify media
+ * change.
+ */
+ struct ata_device *dev = ap->link.device;
+
+ if ((dev->class == ATA_DEV_ATAPI) &&
+ (dev->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(dev);
+ return 0;
+ } else {
+ /* PMP is attached but SNTF is not available.
+ * ATAPI async media change notification is
+ * not used. The PMP must be reporting PHY
+ * status change, schedule EH.
+ */
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+ } else {
+ /* PMP is attached and SNTF is available */
+ struct ata_link *link;
+
+ /* check and notify ATAPI AN */
+ ata_port_for_each_link(link, ap) {
+ if (!(sntf & (1 << link->pmp)))
+ continue;
+
+ if ((link->device->class == ATA_DEV_ATAPI) &&
+ (link->device->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(link->device);
+ }
+
+ /* If PMP is reporting that PHY status of some
+ * downstream ports has changed, schedule EH.
+ */
+ if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+
+ return 0;
+ }
+}
+
+/**
* ata_eh_freeze_port - EH helper to freeze port
* @ap: ATA port to freeze
*
@@ -760,9 +1089,10 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
unsigned long flags;
ata_dev_disable(dev);
@@ -777,31 +1107,32 @@ static void ata_eh_detach_dev(struct ata_device *dev)
}
/* clear per-dev EH actions */
- ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
- ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
spin_unlock_irqrestore(ap->lock, flags);
}
/**
* ata_eh_about_to_do - about to perform eh_action
- * @ap: target ATA port
+ * @link: target ATA link
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action about to be performed
*
* Called just before performing EH actions to clear related bits
- * in @ap->eh_info such that eh actions are not unnecessarily
+ * in @link->eh_info such that eh actions are not unnecessarily
* repeated.
*
* LOCKING:
* None.
*/
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
+ struct ata_port *ap = link->ap;
+ struct ata_eh_info *ehi = &link->eh_info;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned long flags;
- struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_eh_context *ehc = &ap->eh_context;
spin_lock_irqsave(ap->lock, flags);
@@ -818,7 +1149,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
- ata_eh_clear_action(dev, ehi, action);
+ ata_eh_clear_action(link, dev, ehi, action);
if (!(ehc->i.flags & ATA_EHI_QUIET))
ap->pflags |= ATA_PFLAG_RECOVERED;
@@ -828,26 +1159,28 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
/**
* ata_eh_done - EH action complete
- * @ap: target ATA port
+* @ap: target ATA port
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action just completed
*
* Called right after performing EH actions to clear related bits
- * in @ap->eh_context.
+ * in @link->eh_context.
*
* LOCKING:
* None.
*/
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
+ struct ata_eh_context *ehc = &link->eh_context;
+
/* if reset is complete, clear all reset actions & reset modifier */
if (action & ATA_EH_RESET_MASK) {
action |= ATA_EH_RESET_MASK;
- ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
- ata_eh_clear_action(dev, &ap->eh_context.i, action);
+ ata_eh_clear_action(link, dev, &ehc->i, action);
}
/**
@@ -917,7 +1250,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
tf.protocol = ATA_PROT_PIO;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- buf, sectors * ATA_SECT_SIZE);
+ buf, sectors * ATA_SECT_SIZE, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -941,7 +1274,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
static int ata_eh_read_log_10h(struct ata_device *dev,
int *tag, struct ata_taskfile *tf)
{
- u8 *buf = dev->ap->sector_buf;
+ u8 *buf = dev->link->ap->sector_buf;
unsigned int err_mask;
u8 csum;
int i;
@@ -995,7 +1328,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
{
struct ata_device *dev = qc->dev;
unsigned char *sense_buf = qc->scsicmd->sense_buffer;
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
u8 cdb[ATAPI_CDB_LEN];
@@ -1031,12 +1364,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
}
return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
- sense_buf, SCSI_SENSE_BUFFERSIZE);
+ sense_buf, SCSI_SENSE_BUFFERSIZE, 0);
}
/**
* ata_eh_analyze_serror - analyze SError for a failed port
- * @ap: ATA port to analyze SError for
+ * @link: ATA link to analyze SError for
*
* Analyze SError if available and further determine cause of
* failure.
@@ -1044,11 +1377,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_analyze_serror(struct ata_port *ap)
+static void ata_eh_analyze_serror(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &link->eh_context;
u32 serror = ehc->i.serror;
unsigned int err_mask = 0, action = 0;
+ u32 hotplug_mask;
if (serror & SERR_PERSISTENT) {
err_mask |= AC_ERR_ATA_BUS;
@@ -1067,7 +1401,20 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
err_mask |= AC_ERR_SYSTEM;
action |= ATA_EH_HARDRESET;
}
- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+ /* Determine whether a hotplug event has occurred. Both
+ * SError.N/X are considered hotplug events for enabled or
+ * host links. For disabled PMP links, only N bit is
+ * considered as X bit is left at 1 for link plugging.
+ */
+ hotplug_mask = 0;
+
+ if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+ hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+ else
+ hotplug_mask = SERR_PHYRDY_CHG;
+
+ if (serror & hotplug_mask)
ata_ehi_hotplugged(&ehc->i);
ehc->i.err_mask |= err_mask;
@@ -1076,7 +1423,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
/**
* ata_eh_analyze_ncq_error - analyze NCQ error
- * @ap: ATA port to analyze NCQ error for
+ * @link: ATA link to analyze NCQ error for
*
* Read log page 10h, determine the offending qc and acquire
* error status TF. For NCQ device errors, all LLDDs have to do
@@ -1086,10 +1433,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+static void ata_eh_analyze_ncq_error(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_device *dev = ap->device;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev = link->device;
struct ata_queued_cmd *qc;
struct ata_taskfile tf;
int tag, rc;
@@ -1099,7 +1447,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
return;
/* is it NCQ device error? */
- if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+ if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
return;
/* has LLDD analyzed already? */
@@ -1116,13 +1464,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* okay, this error is ours */
rc = ata_eh_read_log_10h(dev, &tag, &tf);
if (rc) {
- ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+ ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
"(errno=%d)\n", rc);
return;
}
- if (!(ap->sactive & (1 << tag))) {
- ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+ if (!(link->sactive & (1 << tag))) {
+ ata_link_printk(link, KERN_ERR, "log page 10h reported "
"inactive tag %d\n", tag);
return;
}
@@ -1130,7 +1478,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* we've got the perpetrator, condemn it */
qc = __ata_qc_from_tag(ap, tag);
memcpy(&qc->result_tf, &tf, sizeof(tf));
- qc->err_mask |= AC_ERR_DEV;
+ qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
ehc->i.err_mask &= ~AC_ERR_DEV;
}
@@ -1337,7 +1685,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
/* speed down? */
if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
/* speed down SATA link speed if possible */
- if (sata_down_spd_limit(dev->ap) == 0) {
+ if (sata_down_spd_limit(dev->link) == 0) {
action |= ATA_EH_HARDRESET;
goto done;
}
@@ -1368,7 +1716,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
* SATA. Consider it only for PATA.
*/
if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
- (dev->ap->cbl != ATA_CBL_SATA) &&
+ (dev->link->ap->cbl != ATA_CBL_SATA) &&
(dev->xfer_shift != ATA_SHIFT_PIO)) {
if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
dev->spdn_cnt = 0;
@@ -1385,19 +1733,20 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
}
/**
- * ata_eh_autopsy - analyze error and determine recovery action
- * @ap: ATA port to perform autopsy on
+ * ata_eh_link_autopsy - analyze error and determine recovery action
+ * @link: host link to perform autopsy on
*
- * Analyze why @ap failed and determine which recovery action is
- * needed. This function also sets more detailed AC_ERR_* values
- * and fills sense data for ATAPI CHECK SENSE.
+ * Analyze why @link failed and determine which recovery actions
+ * are needed. This function also sets more detailed AC_ERR_*
+ * values and fills sense data for ATAPI CHECK SENSE.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_autopsy(struct ata_port *ap)
+static void ata_eh_link_autopsy(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned int all_err_mask = 0;
int tag, is_io = 0;
u32 serror;
@@ -1409,15 +1758,19 @@ static void ata_eh_autopsy(struct ata_port *ap)
return;
/* obtain and analyze SError */
- rc = sata_scr_read(ap, SCR_ERROR, &serror);
+ rc = sata_scr_read(link, SCR_ERROR, &serror);
if (rc == 0) {
ehc->i.serror |= serror;
- ata_eh_analyze_serror(ap);
- } else if (rc != -EOPNOTSUPP)
+ ata_eh_analyze_serror(link);
+ } else if (rc != -EOPNOTSUPP) {
+ /* SError read failed, force hardreset and probing */
+ ata_ehi_schedule_probe(&ehc->i);
ehc->i.action |= ATA_EH_HARDRESET;
+ ehc->i.err_mask |= AC_ERR_OTHER;
+ }
/* analyze NCQ failure */
- ata_eh_analyze_ncq_error(ap);
+ ata_eh_analyze_ncq_error(link);
/* any real error trumps AC_ERR_OTHER */
if (ehc->i.err_mask & ~AC_ERR_OTHER)
@@ -1428,7 +1781,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
continue;
/* inherit upper level err_mask */
@@ -1482,20 +1835,43 @@ static void ata_eh_autopsy(struct ata_port *ap)
}
/**
- * ata_eh_report - report error handling to user
- * @ap: ATA port EH is going on
+ * ata_eh_autopsy - analyze error and determine recovery action
+ * @ap: host port to perform autopsy on
+ *
+ * Analyze all links of @ap and determine why they failed and
+ * which recovery actions are needed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_eh_autopsy(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ __ata_port_for_each_link(link, ap)
+ ata_eh_link_autopsy(link);
+}
+
+/**
+ * ata_eh_link_report - report error handling to user
+ * @link: ATA link EH is going on
*
* Report EH to user.
*
* LOCKING:
* None.
*/
-static void ata_eh_report(struct ata_port *ap)
+static void ata_eh_link_report(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
const char *frozen, *desc;
+ char tries_buf[6];
int tag, nr_failed = 0;
+ if (ehc->i.flags & ATA_EHI_QUIET)
+ return;
+
desc = NULL;
if (ehc->i.desc[0] != '\0')
desc = ehc->i.desc;
@@ -1503,7 +1879,7 @@ static void ata_eh_report(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
continue;
if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
continue;
@@ -1518,22 +1894,48 @@ static void ata_eh_report(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
+ memset(tries_buf, 0, sizeof(tries_buf));
+ if (ap->eh_tries < ATA_EH_MAX_TRIES)
+ snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+ ap->eh_tries);
+
if (ehc->i.dev) {
ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
- ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
} else {
- ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
+ ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
- ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+ ata_link_printk(link, KERN_ERR, "%s\n", desc);
}
+ if (ehc->i.serror)
+ ata_port_printk(ap, KERN_ERR,
+ "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
+ ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "",
+ ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "",
+ ehc->i.serror & SERR_DATA ? "UnrecovData " : "",
+ ehc->i.serror & SERR_PERSISTENT ? "Persist " : "",
+ ehc->i.serror & SERR_PROTOCOL ? "Proto " : "",
+ ehc->i.serror & SERR_INTERNAL ? "HostInt " : "",
+ ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "",
+ ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "",
+ ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "",
+ ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "",
+ ehc->i.serror & SERR_DISPARITY ? "Dispar " : "",
+ ehc->i.serror & SERR_CRC ? "BadCRC " : "",
+ ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "",
+ ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "",
+ ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
+ ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
+ ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" );
+
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
static const char *dma_str[] = {
[DMA_BIDIRECTIONAL] = "bidi",
@@ -1544,14 +1946,15 @@ static void ata_eh_report(struct ata_port *ap)
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
- if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ qc->dev->link != link || !qc->err_mask)
continue;
ata_dev_printk(qc->dev, KERN_ERR,
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d cdb 0x%x data %u %s\n "
"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
- "Emask 0x%x (%s)\n",
+ "Emask 0x%x (%s)%s\n",
cmd->command, cmd->feature, cmd->nsect,
cmd->lbal, cmd->lbam, cmd->lbah,
cmd->hob_feature, cmd->hob_nsect,
@@ -1562,19 +1965,62 @@ static void ata_eh_report(struct ata_port *ap)
res->lbal, res->lbam, res->lbah,
res->hob_feature, res->hob_nsect,
res->hob_lbal, res->hob_lbam, res->hob_lbah,
- res->device, qc->err_mask, ata_err_string(qc->err_mask));
+ res->device, qc->err_mask, ata_err_string(qc->err_mask),
+ qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+
+ if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
+ ATA_ERR) ) {
+ if (res->command & ATA_BUSY)
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "status: { Busy }\n" );
+ else
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "status: { %s%s%s%s}\n",
+ res->command & ATA_DRDY ? "DRDY " : "",
+ res->command & ATA_DF ? "DF " : "",
+ res->command & ATA_DRQ ? "DRQ " : "",
+ res->command & ATA_ERR ? "ERR " : "" );
+ }
+
+ if (cmd->command != ATA_CMD_PACKET &&
+ (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
+ ATA_ABORTED)))
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "error: { %s%s%s%s}\n",
+ res->feature & ATA_ICRC ? "ICRC " : "",
+ res->feature & ATA_UNC ? "UNC " : "",
+ res->feature & ATA_IDNF ? "IDNF " : "",
+ res->feature & ATA_ABORTED ? "ABRT " : "" );
}
}
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+/**
+ * ata_eh_report - report error handling to user
+ * @ap: ATA port to report EH about
+ *
+ * Report EH to user.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_report(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ __ata_port_for_each_link(link, ap)
+ ata_eh_link_report(link);
+}
+
+static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline)
{
- int i, rc;
+ struct ata_device *dev;
+ int rc;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_UNKNOWN;
- rc = reset(ap, classes, deadline);
+ rc = reset(link, classes, deadline);
if (rc)
return rc;
@@ -1582,73 +2028,89 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
* is complete and convert all ATA_DEV_UNKNOWN to
* ATA_DEV_NONE.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] != ATA_DEV_UNKNOWN)
+ ata_link_for_each_dev(dev, link)
+ if (classes[dev->devno] != ATA_DEV_UNKNOWN)
break;
- if (i < ATA_MAX_DEVICES)
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
+ if (dev) {
+ ata_link_for_each_dev(dev, link) {
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
+ }
return 0;
}
-static int ata_eh_followup_srst_needed(int rc, int classify,
+static int ata_eh_followup_srst_needed(struct ata_link *link,
+ int rc, int classify,
const unsigned int *classes)
{
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ return 0;
if (rc == -EAGAIN)
return 1;
if (rc != 0)
return 0;
- if (classify && classes[0] == ATA_DEV_UNKNOWN)
+ if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
+ return 1;
+ if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
+ classes[0] == ATA_DEV_UNKNOWN)
return 1;
return 0;
}
-static int ata_eh_reset(struct ata_port *ap, int classify,
- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned int *classes = ehc->classes;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
int try = 0;
+ struct ata_device *dev;
unsigned long deadline;
unsigned int action;
ata_reset_fn_t reset;
- int i, rc;
+ unsigned long flags;
+ int rc;
/* about to reset */
- ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags |= ATA_PFLAG_RESETTING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
action = ehc->i.action;
ehc->i.action &= ~ATA_EH_RESET_MASK;
- if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+ if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) &&
+ !sata_set_spd_needed(link) &&
!(action & ATA_EH_HARDRESET))))
ehc->i.action |= ATA_EH_SOFTRESET;
else
ehc->i.action |= ATA_EH_HARDRESET;
if (prereset) {
- rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
+ rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
if (rc) {
if (rc == -ENOENT) {
- ata_port_printk(ap, KERN_DEBUG,
+ ata_link_printk(link, KERN_DEBUG,
"port disabled. ignoring.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
rc = 0;
} else
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
- return rc;
+ goto out;
}
}
@@ -1659,9 +2121,10 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
reset = softreset;
else {
/* prereset told us not to reset, bang classes and return */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
- return 0;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
+ rc = 0;
+ goto out;
}
/* did prereset() screw up? if so, fix up to avoid oopsing */
@@ -1677,7 +2140,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* shut up during boot probing */
if (verbose)
- ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+ ata_link_printk(link, KERN_INFO, "%s resetting link\n",
reset == softreset ? "soft" : "hard");
/* mark that this EH session started with reset */
@@ -1686,78 +2149,112 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
else
ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(ap, reset, classes, deadline);
+ rc = ata_do_reset(link, reset, classes, deadline);
if (reset == hardreset &&
- ata_eh_followup_srst_needed(rc, classify, classes)) {
+ ata_eh_followup_srst_needed(link, rc, classify, classes)) {
/* okay, let's do follow-up softreset */
reset = softreset;
if (!reset) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
- rc = ata_do_reset(ap, reset, classes, deadline);
+ ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
+ rc = ata_do_reset(link, reset, classes, deadline);
- if (rc == 0 && classify &&
- classes[0] == ATA_DEV_UNKNOWN) {
- ata_port_printk(ap, KERN_ERR,
+ if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN &&
+ !(link->flags & ATA_LFLAG_ASSUME_CLASS)) {
+ ata_link_printk(link, KERN_ERR,
"classification failed\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
}
- if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+ /* if we skipped follow-up srst, clear rc */
+ if (rc == -EAGAIN)
+ rc = 0;
+
+ if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
unsigned long now = jiffies;
if (time_before(now, deadline)) {
unsigned long delta = deadline - jiffies;
- ata_port_printk(ap, KERN_WARNING, "reset failed "
+ ata_link_printk(link, KERN_WARNING, "reset failed "
"(errno=%d), retrying in %u secs\n",
rc, (jiffies_to_msecs(delta) + 999) / 1000);
- schedule_timeout_uninterruptible(delta);
+ while (delta)
+ delta = schedule_timeout_uninterruptible(delta);
}
- if (reset == hardreset &&
+ if (rc == -EPIPE ||
try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(link);
if (hardreset)
reset = hardreset;
goto retry;
}
if (rc == 0) {
- /* After the reset, the device state is PIO 0 and the
- * controller state is undefined. Record the mode.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
+ u32 sstatus;
+
+ ata_link_for_each_dev(dev, link) {
+ /* After the reset, the device state is PIO 0
+ * and the controller state is undefined.
+ * Record the mode.
+ */
+ dev->pio_mode = XFER_PIO_0;
+
+ if (ata_link_offline(link))
+ continue;
+
+ /* apply class override and convert UNKNOWN to NONE */
+ if (link->flags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (link->flags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+ else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
+
+ /* record current link speed */
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
+ link->sata_spd = (sstatus >> 4) & 0xf;
if (postreset)
- postreset(ap, classes);
+ postreset(link, classes);
/* reset successful, schedule revalidation */
- ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
+ out:
+ /* clear hotplug flag */
+ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~ATA_PFLAG_RESETTING;
+ spin_unlock_irqrestore(ap->lock, flags);
return rc;
}
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+static int ata_eh_revalidate_and_attach(struct ata_link *link,
struct ata_device **r_failed_dev)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev;
unsigned int new_mask = 0;
unsigned long flags;
- int i, rc = 0;
+ int rc = 0;
DPRINTK("ENTER\n");
@@ -1765,27 +2262,28 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
* be done backwards such that PDIAG- is released by the slave
* device before the master device is identified.
*/
- for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
- unsigned int action, readid_flags = 0;
-
- dev = &ap->device[i];
- action = ata_eh_dev_action(dev);
+ ata_link_for_each_dev_reverse(dev, link) {
+ unsigned int action = ata_eh_dev_action(dev);
+ unsigned int readid_flags = 0;
if (ehc->i.flags & ATA_EHI_DID_RESET)
readid_flags |= ATA_READID_POSTRESET;
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
- if (ata_port_offline(ap)) {
+ WARN_ON(dev->class == ATA_DEV_PMP);
+
+ if (ata_link_offline(link)) {
rc = -EIO;
goto err;
}
- ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
- rc = ata_dev_revalidate(dev, readid_flags);
+ ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
+ rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
+ readid_flags);
if (rc)
goto err;
- ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+ ata_eh_done(link, dev, ATA_EH_REVALIDATE);
/* Configuration may have changed, reconfigure
* transfer mode.
@@ -1799,11 +2297,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
ata_class_enabled(ehc->classes[dev->devno])) {
dev->class = ehc->classes[dev->devno];
- rc = ata_dev_read_id(dev, &dev->class, readid_flags,
- dev->id);
+ if (dev->class == ATA_DEV_PMP)
+ rc = sata_pmp_attach(dev);
+ else
+ rc = ata_dev_read_id(dev, &dev->class,
+ readid_flags, dev->id);
switch (rc) {
case 0:
- new_mask |= 1 << i;
+ new_mask |= 1 << dev->devno;
break;
case -ENOENT:
/* IDENTIFY was issued to non-existent
@@ -1821,16 +2322,16 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
/* PDIAG- should have been released, ask cable type if post-reset */
- if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+ if (ata_is_host_link(link) && ap->ops->cable_detect &&
+ (ehc->i.flags & ATA_EHI_DID_RESET))
ap->cbl = ap->ops->cable_detect(ap);
/* Configure new devices forward such that user doesn't see
* device detection messages backwards.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (!(new_mask & (1 << i)))
+ ata_link_for_each_dev(dev, link) {
+ if (!(new_mask & (1 << dev->devno)) ||
+ dev->class == ATA_DEV_PMP)
continue;
ehc->i.flags |= ATA_EHI_PRINTINFO;
@@ -1855,40 +2356,44 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
-static int ata_port_nr_enabled(struct ata_port *ap)
+static int ata_link_nr_enabled(struct ata_link *link)
{
- int i, cnt = 0;
+ struct ata_device *dev;
+ int cnt = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
+ ata_link_for_each_dev(dev, link)
+ if (ata_dev_enabled(dev))
cnt++;
return cnt;
}
-static int ata_port_nr_vacant(struct ata_port *ap)
+static int ata_link_nr_vacant(struct ata_link *link)
{
- int i, cnt = 0;
+ struct ata_device *dev;
+ int cnt = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ap->device[i].class == ATA_DEV_UNKNOWN)
+ ata_link_for_each_dev(dev, link)
+ if (dev->class == ATA_DEV_UNKNOWN)
cnt++;
return cnt;
}
-static int ata_eh_skip_recovery(struct ata_port *ap)
+static int ata_eh_skip_recovery(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
- int i;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev;
+
+ /* skip disabled links */
+ if (link->flags & ATA_LFLAG_DISABLED)
+ return 1;
/* thaw frozen port, resume link and recover failed devices */
- if ((ap->pflags & ATA_PFLAG_FROZEN) ||
- (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+ if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
+ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
if (dev->class == ATA_DEV_UNKNOWN &&
ehc->classes[dev->devno] != ATA_DEV_NONE)
return 0;
@@ -1897,10 +2402,9 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
return 1;
}
-static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
+static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
ehc->tries[dev->devno]--;
@@ -1916,7 +2420,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(dev->link);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -1926,7 +2430,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ata_dev_disable(dev);
/* detach if offline */
- if (ata_port_offline(ap))
+ if (ata_link_offline(dev->link))
ata_eh_detach_dev(dev);
/* probe if requested */
@@ -1939,12 +2443,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ehc->did_probe_mask |= (1 << dev->devno);
ehc->i.action |= ATA_EH_SOFTRESET;
}
+
+ return 1;
} else {
/* soft didn't work? be haaaaard */
if (ehc->i.flags & ATA_EHI_DID_RESET)
ehc->i.action |= ATA_EH_HARDRESET;
else
ehc->i.action |= ATA_EH_SOFTRESET;
+
+ return 0;
}
}
@@ -1955,12 +2463,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* @softreset: softreset method (can be NULL)
* @hardreset: hardreset method (can be NULL)
* @postreset: postreset method (can be NULL)
+ * @r_failed_link: out parameter for failed link
*
* This is the alpha and omega, eum and yang, heart and soul of
* libata exception handling. On entry, actions required to
- * recover the port and hotplug requests are recorded in
- * eh_context. This function executes all the operations with
- * appropriate retrials and fallbacks to resurrect failed
+ * recover each link and hotplug requests are recorded in the
+ * link's eh_context. This function executes all the operations
+ * with appropriate retrials and fallbacks to resurrect failed
* devices, detach goners and greet newcomers.
*
* LOCKING:
@@ -1969,104 +2478,171 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_link *link;
struct ata_device *dev;
- int i, rc;
+ int nr_failed_devs, nr_disabled_devs;
+ int reset, rc;
+ unsigned long flags;
DPRINTK("ENTER\n");
/* prep for recovery */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-
- /* collect port action mask recorded in dev actions */
- ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
- ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
-
- /* process hotplug request */
- if (dev->flags & ATA_DFLAG_DETACH)
- ata_eh_detach_dev(dev);
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ /* re-enable link? */
+ if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+ ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags &= ~ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+ }
- if (!ata_dev_enabled(dev) &&
- ((ehc->i.probe_mask & (1 << dev->devno)) &&
- !(ehc->did_probe_mask & (1 << dev->devno)))) {
- ata_eh_detach_dev(dev);
- ata_dev_init(dev);
- ehc->did_probe_mask |= (1 << dev->devno);
- ehc->i.action |= ATA_EH_SOFTRESET;
+ ata_link_for_each_dev(dev, link) {
+ if (link->flags & ATA_LFLAG_NO_RETRY)
+ ehc->tries[dev->devno] = 1;
+ else
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+ /* collect port action mask recorded in dev actions */
+ ehc->i.action |= ehc->i.dev_action[dev->devno] &
+ ~ATA_EH_PERDEV_MASK;
+ ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK;
+
+ /* process hotplug request */
+ if (dev->flags & ATA_DFLAG_DETACH)
+ ata_eh_detach_dev(dev);
+
+ if (!ata_dev_enabled(dev) &&
+ ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno)))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
}
}
retry:
rc = 0;
+ nr_failed_devs = 0;
+ nr_disabled_devs = 0;
+ reset = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
- /* skip EH if possible. */
- if (ata_eh_skip_recovery(ap))
- ehc->i.action = 0;
+ /* prep for EH */
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehc->classes[i] = ATA_DEV_UNKNOWN;
+ /* skip EH if possible. */
+ if (ata_eh_skip_recovery(link))
+ ehc->i.action = 0;
- /* reset */
- if (ehc->i.action & ATA_EH_RESET_MASK) {
- ata_eh_freeze_port(ap);
+ /* do we need to reset? */
+ if (ehc->i.action & ATA_EH_RESET_MASK)
+ reset = 1;
- rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
- softreset, hardreset, postreset);
- if (rc) {
- ata_port_printk(ap, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
+ ata_link_for_each_dev(dev, link)
+ ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+ }
+
+ /* reset */
+ if (reset) {
+ /* if PMP is attached, this function only deals with
+ * downstream links, port should stay thawed.
+ */
+ if (!ap->nr_pmp_links)
+ ata_eh_freeze_port(ap);
+
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ if (!(ehc->i.action & ATA_EH_RESET_MASK))
+ continue;
+
+ rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+ prereset, softreset, hardreset,
+ postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
+ }
}
- ata_eh_thaw_port(ap);
+ if (!ap->nr_pmp_links)
+ ata_eh_thaw_port(ap);
}
- /* revalidate existing devices and attach new ones */
- rc = ata_eh_revalidate_and_attach(ap, &dev);
- if (rc)
- goto dev_fail;
+ /* the rest */
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- /* configure transfer mode if necessary */
- if (ehc->i.flags & ATA_EHI_SETMODE) {
- rc = ata_set_mode(ap, &dev);
+ /* revalidate existing devices and attach new ones */
+ rc = ata_eh_revalidate_and_attach(link, &dev);
if (rc)
goto dev_fail;
- ehc->i.flags &= ~ATA_EHI_SETMODE;
- }
- goto out;
+ /* if PMP got attached, return, pmp EH will take care of it */
+ if (link->device->class == ATA_DEV_PMP) {
+ ehc->i.action = 0;
+ return 0;
+ }
+
+ /* configure transfer mode if necessary */
+ if (ehc->i.flags & ATA_EHI_SETMODE) {
+ rc = ata_set_mode(link, &dev);
+ if (rc)
+ goto dev_fail;
+ ehc->i.flags &= ~ATA_EHI_SETMODE;
+ }
- dev_fail:
- ata_eh_handle_dev_fail(dev, rc);
+ /* this link is okay now */
+ ehc->i.flags = 0;
+ continue;
- if (ata_port_nr_enabled(ap)) {
- ata_port_printk(ap, KERN_WARNING, "failed to recover some "
- "devices, retrying in 5 secs\n");
- ssleep(5);
- } else {
- /* no device left, repeat fast */
- msleep(500);
+ dev_fail:
+ nr_failed_devs++;
+ if (ata_eh_handle_dev_fail(dev, rc))
+ nr_disabled_devs++;
+
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
+ /* PMP reset requires working host port.
+ * Can't retry if it's frozen.
+ */
+ if (ap->nr_pmp_links)
+ goto out;
+ break;
+ }
}
- goto retry;
+ if (nr_failed_devs) {
+ if (nr_failed_devs != nr_disabled_devs) {
+ ata_port_printk(ap, KERN_WARNING, "failed to recover "
+ "some devices, retrying in 5 secs\n");
+ ssleep(5);
+ } else {
+ /* no device left to recover, repeat fast */
+ msleep(500);
+ }
- out:
- if (rc) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
+ goto retry;
}
+ out:
+ if (rc && r_failed_link)
+ *r_failed_link = link;
+
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -2081,7 +2657,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
* LOCKING:
* None.
*/
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
{
int tag;
@@ -2111,6 +2687,10 @@ static void ata_eh_finish(struct ata_port *ap)
}
}
}
+
+ /* make sure nr_active_links is zero after EH */
+ WARN_ON(ap->nr_active_links);
+ ap->nr_active_links = 0;
}
/**
@@ -2130,9 +2710,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
+ struct ata_device *dev;
+ int rc;
+
ata_eh_autopsy(ap);
ata_eh_report(ap);
- ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+
+ rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+ NULL);
+ if (rc) {
+ ata_link_for_each_dev(dev, &ap->link)
+ ata_dev_disable(dev);
+ }
+
ata_eh_finish(ap);
}
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
new file mode 100644
index 000000000000..c0c4dbcde091
--- /dev/null
+++ b/drivers/ata/libata-pmp.c
@@ -0,0 +1,1191 @@
+/*
+ * libata-pmp.c - libata port multiplier support
+ *
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include "libata.h"
+
+/**
+ * sata_pmp_read - read PMP register
+ * @link: link to read PMP register for
+ * @reg: register to read
+ * @r_val: resulting value
+ *
+ * Read PMP register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *pmp_dev = ap->link.device;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(pmp_dev, &tf);
+ tf.command = ATA_CMD_PMP_READ;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.feature = reg;
+ tf.device = link->pmp;
+
+ err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+ SATA_PMP_SCR_TIMEOUT);
+ if (err_mask)
+ return err_mask;
+
+ *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
+ return 0;
+}
+
+/**
+ * sata_pmp_write - write PMP register
+ * @link: link to write PMP register for
+ * @reg: register to write
+ * @r_val: value to write
+ *
+ * Write PMP register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *pmp_dev = ap->link.device;
+ struct ata_taskfile tf;
+
+ ata_tf_init(pmp_dev, &tf);
+ tf.command = ATA_CMD_PMP_WRITE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.feature = reg;
+ tf.device = link->pmp;
+ tf.nsect = val & 0xff;
+ tf.lbal = (val >> 8) & 0xff;
+ tf.lbam = (val >> 16) & 0xff;
+ tf.lbah = (val >> 24) & 0xff;
+
+ return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+ SATA_PMP_SCR_TIMEOUT);
+}
+
+/**
+ * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
+ * @qc: ATA command in question
+ *
+ * A host which has command switching PMP support cannot issue
+ * commands to multiple links simultaneously.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+
+ if (ap->excl_link == NULL || ap->excl_link == link) {
+ if (ap->nr_active_links == 0 || ata_link_active(link)) {
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ return ata_std_qc_defer(qc);
+ }
+
+ ap->excl_link = link;
+ }
+
+ return ATA_DEFER_PORT;
+}
+
+/**
+ * sata_pmp_scr_read - read PSCR
+ * @link: ATA link to read PSCR for
+ * @reg: PSCR to read
+ * @r_val: resulting value
+ *
+ * Read PSCR @reg into @r_val for @link, to be called from
+ * ata_scr_read().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
+{
+ unsigned int err_mask;
+
+ if (reg > SATA_PMP_PSCR_CONTROL)
+ return -EINVAL;
+
+ err_mask = sata_pmp_read(link, reg, r_val);
+ if (err_mask) {
+ ata_link_printk(link, KERN_WARNING, "failed to read SCR %d "
+ "(Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * sata_pmp_scr_write - write PSCR
+ * @link: ATA link to write PSCR for
+ * @reg: PSCR to write
+ * @val: value to be written
+ *
+ * Write @val to PSCR @reg for @link, to be called from
+ * ata_scr_write() and ata_scr_write_flush().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
+{
+ unsigned int err_mask;
+
+ if (reg > SATA_PMP_PSCR_CONTROL)
+ return -EINVAL;
+
+ err_mask = sata_pmp_write(link, reg, val);
+ if (err_mask) {
+ ata_link_printk(link, KERN_WARNING, "failed to write SCR %d "
+ "(Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * sata_pmp_std_prereset - prepare PMP link for reset
+ * @link: link to be reset
+ * @deadline: deadline jiffies for the operation
+ *
+ * @link is about to be reset. Initialize it.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_eh_context *ehc = &link->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ /* force HRST? */
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* handle link resume */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ /* resume link */
+ rc = sata_link_resume(link, timing, deadline);
+ if (rc) {
+ /* phy resume failed */
+ ata_link_printk(link, KERN_WARNING, "failed to resume link "
+ "for reset (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* clear SError bits including .X which blocks the port when set */
+ rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "failed to clear SError (errno=%d)\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * sata_pmp_std_hardreset - standard hardreset method for PMP link
+ * @link: link to be reset
+ * @class: resulting class of attached device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Hardreset PMP port @link. Note that this function doesn't
+ * wait for BSY clearance. There simply isn't a generic way to
+ * wait the event. Instead, this function return -EAGAIN thus
+ * telling libata-EH to followup with softreset.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ u32 tmp;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* do hardreset */
+ rc = sata_link_hardreset(link, timing, deadline);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "COMRESET failed (errno=%d)\n", rc);
+ goto out;
+ }
+
+ /* clear SError bits including .X which blocks the port when set */
+ rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "failed to clear SError "
+ "during hardreset (errno=%d)\n", rc);
+ goto out;
+ }
+
+ /* if device is present, follow up with srst to wait for !BSY */
+ if (ata_link_online(link))
+ rc = -EAGAIN;
+ out:
+ /* if SCR isn't accessible, we need to reset the PMP */
+ if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp))
+ rc = -ERESTART;
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * ata_std_postreset - standard postreset method for PMP link
+ * @link: the target ata_link
+ * @classes: classes of attached devices
+ *
+ * This function is invoked after a successful reset. Note that
+ * the device might have been reset more than once using
+ * different reset methods before postreset is invoked.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class)
+{
+ u32 serror;
+
+ DPRINTK("ENTER\n");
+
+ /* clear SError */
+ if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+ sata_scr_write(link, SCR_ERROR, serror);
+
+ /* print link status */
+ sata_print_link_status(link);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * sata_pmp_read_gscr - read GSCR block of SATA PMP
+ * @dev: PMP device
+ * @gscr: buffer to read GSCR block into
+ *
+ * Read selected PMP GSCRs from the PMP at @dev. This will serve
+ * as configuration and identification info for the PMP.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
+{
+ static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
+ int reg = gscr_to_read[i];
+ unsigned int err_mask;
+
+ err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to read PMP "
+ "GSCR[%d] (Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static const char *sata_pmp_spec_rev_str(const u32 *gscr)
+{
+ u32 rev = gscr[SATA_PMP_GSCR_REV];
+
+ if (rev & (1 << 2))
+ return "1.1";
+ if (rev & (1 << 1))
+ return "1.0";
+ return "<unknown>";
+}
+
+static int sata_pmp_configure(struct ata_device *dev, int print_info)
+{
+ struct ata_port *ap = dev->link->ap;
+ u32 *gscr = dev->gscr;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int nr_ports, rc;
+
+ nr_ports = sata_pmp_gscr_ports(gscr);
+
+ if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
+ rc = -EINVAL;
+ reason = "invalid nr_ports";
+ goto fail;
+ }
+
+ if ((ap->flags & ATA_FLAG_AN) &&
+ (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
+ dev->flags |= ATA_DFLAG_AN;
+
+ /* monitor SERR_PHYRDY_CHG on fan-out ports */
+ err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
+ SERR_PHYRDY_CHG);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to write GSCR_ERROR_EN";
+ goto fail;
+ }
+
+ /* turn off notification till fan-out ports are reset and configured */
+ if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+ gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to write GSCR_FEAT_EN";
+ goto fail;
+ }
+ }
+
+ if (print_info) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
+ "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+ sata_pmp_spec_rev_str(gscr),
+ sata_pmp_gscr_vendor(gscr),
+ sata_pmp_gscr_devid(gscr),
+ sata_pmp_gscr_rev(gscr),
+ nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+ gscr[SATA_PMP_GSCR_FEAT]);
+
+ if (!(dev->flags & ATA_DFLAG_AN))
+ ata_dev_printk(dev, KERN_INFO,
+ "Asynchronous notification not supported, "
+ "hotplug won't\n work on fan-out "
+ "ports. Use warm-plug instead.\n");
+ }
+
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
+ reason, err_mask);
+ return rc;
+}
+
+static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+{
+ struct ata_link *pmp_link = ap->pmp_link;
+ int i;
+
+ if (!pmp_link) {
+ pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
+ GFP_NOIO);
+ if (!pmp_link)
+ return -ENOMEM;
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_link_init(ap, &pmp_link[i], i);
+
+ ap->pmp_link = pmp_link;
+ }
+
+ for (i = 0; i < nr_ports; i++) {
+ struct ata_link *link = &pmp_link[i];
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ link->flags = 0;
+ ehc->i.probe_mask |= 1;
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ ehc->i.flags |= ATA_EHI_RESUME_LINK;
+ }
+
+ return 0;
+}
+
+static void sata_pmp_quirks(struct ata_port *ap)
+{
+ u32 *gscr = ap->link.device->gscr;
+ u16 vendor = sata_pmp_gscr_vendor(gscr);
+ u16 devid = sata_pmp_gscr_devid(gscr);
+ struct ata_link *link;
+
+ if (vendor == 0x1095 && devid == 0x3726) {
+ /* sil3726 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 5)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* port 5 is for SEMB device and it doesn't like SRST */
+ if (link->pmp == 5)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_SEMB;
+ }
+ } else if (vendor == 0x1095 && devid == 0x4723) {
+ /* sil4723 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 2)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* the config device at port 2 locks up on SRST */
+ if (link->pmp == 2)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+ }
+ } else if (vendor == 0x1095 && devid == 0x4726) {
+ /* sil4726 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 5)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* The config device, which can be either at
+ * port 0 or 5, locks up on SRST.
+ */
+ if (link->pmp == 0 || link->pmp == 5)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+
+ /* Port 6 is for SEMB device which doesn't
+ * like SRST either.
+ */
+ if (link->pmp == 6)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_SEMB;
+ }
+ } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
+ devid == 0x5734 || devid == 0x5744)) {
+ /* sil5723/5744 quirks */
+
+ /* sil5723/5744 has either two or three downstream
+ * ports depending on operation mode. The last port
+ * is empty if any actual IO device is available or
+ * occupied by a pseudo configuration device
+ * otherwise. Don't try hard to recover it.
+ */
+ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+ } else if (vendor == 0x11ab && devid == 0x4140) {
+ /* Marvell 88SM4140 quirks. Fan-out ports require PHY
+ * reset to work; other than that, it behaves very
+ * nicely.
+ */
+ ata_port_for_each_link(link, ap)
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+ }
+}
+
+/**
+ * sata_pmp_attach - attach a SATA PMP device
+ * @dev: SATA PMP device to attach
+ *
+ * Configure and attach SATA PMP device @dev. This function is
+ * also responsible for allocating and initializing PMP links.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_attach(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ unsigned long flags;
+ struct ata_link *tlink;
+ int rc;
+
+ /* is it hanging off the right place? */
+ if (!(ap->flags & ATA_FLAG_PMP)) {
+ ata_dev_printk(dev, KERN_ERR,
+ "host does not support Port Multiplier\n");
+ return -EINVAL;
+ }
+
+ if (!ata_is_host_link(link)) {
+ ata_dev_printk(dev, KERN_ERR,
+ "Port Multipliers cannot be nested\n");
+ return -EINVAL;
+ }
+
+ if (dev->devno) {
+ ata_dev_printk(dev, KERN_ERR,
+ "Port Multiplier must be the first device\n");
+ return -EINVAL;
+ }
+
+ WARN_ON(link->pmp != 0);
+ link->pmp = SATA_PMP_CTRL_PORT;
+
+ /* read GSCR block */
+ rc = sata_pmp_read_gscr(dev, dev->gscr);
+ if (rc)
+ goto fail;
+
+ /* config PMP */
+ rc = sata_pmp_configure(dev, 1);
+ if (rc)
+ goto fail;
+
+ rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
+ if (rc) {
+ ata_dev_printk(dev, KERN_INFO,
+ "failed to initialize PMP links\n");
+ goto fail;
+ }
+
+ /* attach it */
+ spin_lock_irqsave(ap->lock, flags);
+ WARN_ON(ap->nr_pmp_links);
+ ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ sata_pmp_quirks(ap);
+
+ if (ap->ops->pmp_attach)
+ ap->ops->pmp_attach(ap);
+
+ ata_port_for_each_link(tlink, ap)
+ sata_link_init_spd(tlink);
+
+ ata_acpi_associate_sata_port(ap);
+
+ return 0;
+
+ fail:
+ link->pmp = 0;
+ return rc;
+}
+
+/**
+ * sata_pmp_detach - detach a SATA PMP device
+ * @dev: SATA PMP device to detach
+ *
+ * Detach SATA PMP device @dev. This function is also
+ * responsible for deconfiguring PMP links.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void sata_pmp_detach(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct ata_link *tlink;
+ unsigned long flags;
+
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+
+ WARN_ON(!ata_is_host_link(link) || dev->devno ||
+ link->pmp != SATA_PMP_CTRL_PORT);
+
+ if (ap->ops->pmp_detach)
+ ap->ops->pmp_detach(ap);
+
+ ata_port_for_each_link(tlink, ap)
+ ata_eh_detach_dev(tlink->device);
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->nr_pmp_links = 0;
+ link->pmp = 0;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_acpi_associate_sata_port(ap);
+}
+
+/**
+ * sata_pmp_same_pmp - does new GSCR matches the configured PMP?
+ * @dev: PMP device to compare against
+ * @new_gscr: GSCR block of the new device
+ *
+ * Compare @new_gscr against @dev and determine whether @dev is
+ * the PMP described by @new_gscr.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if @dev matches @new_gscr, 0 otherwise.
+ */
+static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
+{
+ const u32 *old_gscr = dev->gscr;
+ u16 old_vendor, new_vendor, old_devid, new_devid;
+ int old_nr_ports, new_nr_ports;
+
+ old_vendor = sata_pmp_gscr_vendor(old_gscr);
+ new_vendor = sata_pmp_gscr_vendor(new_gscr);
+ old_devid = sata_pmp_gscr_devid(old_gscr);
+ new_devid = sata_pmp_gscr_devid(new_gscr);
+ old_nr_ports = sata_pmp_gscr_ports(old_gscr);
+ new_nr_ports = sata_pmp_gscr_ports(new_gscr);
+
+ if (old_vendor != new_vendor) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "vendor mismatch '0x%x' != '0x%x'\n",
+ old_vendor, new_vendor);
+ return 0;
+ }
+
+ if (old_devid != new_devid) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "device ID mismatch '0x%x' != '0x%x'\n",
+ old_devid, new_devid);
+ return 0;
+ }
+
+ if (old_nr_ports != new_nr_ports) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "nr_ports mismatch '0x%x' != '0x%x'\n",
+ old_nr_ports, new_nr_ports);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * sata_pmp_revalidate - revalidate SATA PMP
+ * @dev: PMP device to revalidate
+ * @new_class: new class code
+ *
+ * Re-read GSCR block and make sure @dev is still attached to the
+ * port and properly configured.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ u32 *gscr = (void *)ap->sector_buf;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
+
+ if (!ata_dev_enabled(dev)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* wrong class? */
+ if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* read GSCR */
+ rc = sata_pmp_read_gscr(dev, gscr);
+ if (rc)
+ goto fail;
+
+ /* is the pmp still there? */
+ if (!sata_pmp_same_pmp(dev, gscr)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
+
+ rc = sata_pmp_configure(dev, 0);
+ if (rc)
+ goto fail;
+
+ ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
+
+ DPRINTK("EXIT, rc=0\n");
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR,
+ "PMP revalidation failed (errno=%d)\n", rc);
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * sata_pmp_revalidate_quick - revalidate SATA PMP quickly
+ * @dev: PMP device to revalidate
+ *
+ * Make sure the attached PMP is accessible.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate_quick(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ u32 prod_id;
+
+ err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID "
+ "(Emask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+
+ if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
+ ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+ /* something weird is going on, request full PMP recovery */
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * sata_pmp_eh_recover_pmp - recover PMP
+ * @ap: ATA port PMP is attached to
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ *
+ * Recover PMP attached to @ap. Recovery procedure is somewhat
+ * similar to that of ata_eh_recover() except that reset should
+ * always be performed in hard->soft sequence and recovery
+ * failure results in PMP detachment.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+ struct ata_link *link = &ap->link;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev = link->device;
+ int tries = ATA_EH_PMP_TRIES;
+ int detach = 0, rc = 0;
+ int reval_failed = 0;
+
+ DPRINTK("ENTER\n");
+
+ if (dev->flags & ATA_DFLAG_DETACH) {
+ detach = 1;
+ goto fail;
+ }
+
+ retry:
+ ehc->classes[0] = ATA_DEV_UNKNOWN;
+
+ if (ehc->i.action & ATA_EH_RESET_MASK) {
+ struct ata_link *tlink;
+
+ ata_eh_freeze_port(ap);
+
+ /* reset */
+ ehc->i.action = ATA_EH_HARDRESET;
+ rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
+ postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "failed to reset PMP, giving up\n");
+ goto fail;
+ }
+
+ ata_eh_thaw_port(ap);
+
+ /* PMP is reset, SErrors cannot be trusted, scan all */
+ ata_port_for_each_link(tlink, ap)
+ ata_ehi_schedule_probe(&tlink->eh_context.i);
+ }
+
+ /* If revalidation is requested, revalidate and reconfigure;
+ * otherwise, do quick revalidation.
+ */
+ if (ehc->i.action & ATA_EH_REVALIDATE)
+ rc = sata_pmp_revalidate(dev, ehc->classes[0]);
+ else
+ rc = sata_pmp_revalidate_quick(dev);
+
+ if (rc) {
+ tries--;
+
+ if (rc == -ENODEV) {
+ ehc->i.probe_mask |= 1;
+ detach = 1;
+ /* give it just two more chances */
+ tries = min(tries, 2);
+ }
+
+ if (tries) {
+ int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
+
+ /* consecutive revalidation failures? speed down */
+ if (reval_failed)
+ sata_down_spd_limit(link);
+ else
+ reval_failed = 1;
+
+ ata_dev_printk(dev, KERN_WARNING,
+ "retrying hardreset%s\n",
+ sleep ? " in 5 secs" : "");
+ if (sleep)
+ ssleep(5);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ goto retry;
+ } else {
+ ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
+ "after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
+ goto fail;
+ }
+ }
+
+ /* okay, PMP resurrected */
+ ehc->i.flags = 0;
+
+ DPRINTK("EXIT, rc=0\n");
+ return 0;
+
+ fail:
+ sata_pmp_detach(dev);
+ if (detach)
+ ata_eh_detach_dev(dev);
+ else
+ ata_dev_disable(dev);
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
+{
+ struct ata_link *link;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ata_port_for_each_link(link, ap) {
+ if (!(link->flags & ATA_LFLAG_DISABLED))
+ continue;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Some PMPs require hardreset sequence to get
+ * SError.N working.
+ */
+ if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) &&
+ (link->eh_context.i.flags & ATA_EHI_RESUME_LINK))
+ sata_link_hardreset(link, sata_deb_timing_normal,
+ jiffies + ATA_TMOUT_INTERNAL_QUICK);
+
+ /* unconditionally clear SError.N */
+ rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "failed to clear "
+ "SError.N (errno=%d)\n", rc);
+ return rc;
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return 0;
+}
+
+static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
+{
+ struct ata_port *ap = link->ap;
+ unsigned long flags;
+
+ if (link_tries[link->pmp] && --link_tries[link->pmp])
+ return 1;
+
+ /* disable this link */
+ if (!(link->flags & ATA_LFLAG_DISABLED)) {
+ ata_link_printk(link, KERN_WARNING,
+ "failed to recover link after %d tries, disabling\n",
+ ATA_EH_PMP_LINK_TRIES);
+
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags |= ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ ata_dev_disable(link->device);
+ link->eh_context.i.action = 0;
+
+ return 0;
+}
+
+/**
+ * sata_pmp_eh_recover - recover PMP-enabled port
+ * @ap: ATA port to recover
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ * @pmp_prereset: PMP prereset method (can be NULL)
+ * @pmp_softreset: PMP softreset method (can be NULL)
+ * @pmp_hardreset: PMP hardreset method (can be NULL)
+ * @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ * Drive EH recovery operation for PMP enabled port @ap. This
+ * function recovers host and PMP ports with proper retrials and
+ * fallbacks. Actual recovery operations are performed using
+ * ata_eh_recover() and sata_pmp_eh_recover_pmp().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+ int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
+ struct ata_link *pmp_link = &ap->link;
+ struct ata_device *pmp_dev = pmp_link->device;
+ struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned int err_mask;
+ u32 gscr_error, sntf;
+ int cnt, rc;
+
+ pmp_tries = ATA_EH_PMP_TRIES;
+ ata_port_for_each_link(link, ap)
+ link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ retry:
+ /* PMP attached? */
+ if (!ap->nr_pmp_links) {
+ rc = ata_eh_recover(ap, prereset, softreset, hardreset,
+ postreset, NULL);
+ if (rc) {
+ ata_link_for_each_dev(dev, &ap->link)
+ ata_dev_disable(dev);
+ return rc;
+ }
+
+ if (pmp_dev->class != ATA_DEV_PMP)
+ return 0;
+
+ /* new PMP online */
+ ata_port_for_each_link(link, ap)
+ link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ /* fall through */
+ }
+
+ /* recover pmp */
+ rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset,
+ postreset);
+ if (rc)
+ goto pmp_fail;
+
+ /* handle disabled links */
+ rc = sata_pmp_eh_handle_disabled_links(ap);
+ if (rc)
+ goto pmp_fail;
+
+ /* recover links */
+ rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset,
+ pmp_postreset, &link);
+ if (rc)
+ goto link_fail;
+
+ /* Connection status might have changed while resetting other
+ * links, check SATA_PMP_GSCR_ERROR before returning.
+ */
+
+ /* clear SNotification */
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ /* enable notification */
+ if (pmp_dev->flags & ATA_DFLAG_AN) {
+ pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
+ pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
+ "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
+ rc = -EIO;
+ goto pmp_fail;
+ }
+ }
+
+ /* check GSCR_ERROR */
+ err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
+ if (err_mask) {
+ ata_dev_printk(pmp_dev, KERN_ERR, "failed to read "
+ "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask);
+ rc = -EIO;
+ goto pmp_fail;
+ }
+
+ cnt = 0;
+ ata_port_for_each_link(link, ap) {
+ if (!(gscr_error & (1 << link->pmp)))
+ continue;
+
+ if (sata_pmp_handle_link_fail(link, link_tries)) {
+ ata_ehi_hotplugged(&link->eh_context.i);
+ cnt++;
+ } else {
+ ata_link_printk(link, KERN_WARNING,
+ "PHY status changed but maxed out on retries, "
+ "giving up\n");
+ ata_link_printk(link, KERN_WARNING,
+ "Manully issue scan to resume this link\n");
+ }
+ }
+
+ if (cnt) {
+ ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
+ "ports, repeating recovery\n");
+ goto retry;
+ }
+
+ return 0;
+
+ link_fail:
+ if (sata_pmp_handle_link_fail(link, link_tries)) {
+ pmp_ehc->i.action |= ATA_EH_HARDRESET;
+ goto retry;
+ }
+
+ /* fall through */
+ pmp_fail:
+ /* Control always ends up here after detaching PMP. Shut up
+ * and return if we're unloading.
+ */
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
+ return rc;
+
+ if (!ap->nr_pmp_links)
+ goto retry;
+
+ if (--pmp_tries) {
+ ata_port_printk(ap, KERN_WARNING,
+ "failed to recover PMP, retrying in 5 secs\n");
+ pmp_ehc->i.action |= ATA_EH_HARDRESET;
+ ssleep(5);
+ goto retry;
+ }
+
+ ata_port_printk(ap, KERN_ERR,
+ "failed to recover PMP after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
+ sata_pmp_detach(pmp_dev);
+ ata_dev_disable(pmp_dev);
+
+ return rc;
+}
+
+/**
+ * sata_pmp_do_eh - do standard error handling for PMP-enabled host
+ * @ap: host port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ * @pmp_prereset: PMP prereset method (can be NULL)
+ * @pmp_softreset: PMP softreset method (can be NULL)
+ * @pmp_hardreset: PMP hardreset method (can be NULL)
+ * @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ * Perform standard error handling sequence for PMP-enabled host
+ * @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void sata_pmp_do_eh(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
+ sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset,
+ pmp_prereset, pmp_softreset, pmp_hardreset,
+ pmp_postreset);
+ ata_eh_finish(ap);
+}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfde22da07ac..ea53e6a570b4 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
#define ALL_SUB_MPAGES 0xff
-static const u8 def_rw_recovery_mpage[] = {
+static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
RW_RECOVERY_MPAGE,
RW_RECOVERY_MPAGE_LEN - 2,
- (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
- (1 << 6), /* ARRE (auto read reallocation) */
+ (1 << 7), /* AWRE */
0, /* read retry count */
0, 0, 0, 0,
0, /* write retry count */
@@ -450,13 +449,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
qc->scsicmd = cmd;
qc->scsidone = done;
- if (cmd->use_sg) {
- qc->__sg = (struct scatterlist *) cmd->request_buffer;
- qc->n_elem = cmd->use_sg;
- } else if (cmd->request_bufflen) {
- qc->__sg = &qc->sgent;
- qc->n_elem = 1;
- }
+ qc->__sg = scsi_sglist(cmd);
+ qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
done(cmd);
@@ -755,6 +749,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+
+ /* Schedule policy is determined by ->qc_defer() callback and
+ * it needs to see every deferred qc. Set dev_blocked to 1 to
+ * prevent SCSI midlayer from automatically deferring
+ * requests.
+ */
+ sdev->max_device_blocked = 1;
}
static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -768,7 +769,7 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
* Decrement max hw segments accordingly.
*/
if (dev->class == ATA_DEV_ATAPI) {
- request_queue_t *q = sdev->request_queue;
+ struct request_queue *q = sdev->request_queue;
blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
}
@@ -943,6 +944,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
goto invalid_fld; /* LOEJ bit set not supported */
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
+
+ if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
+ /* the device lacks PM support, finish without doing anything */
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
+ }
+
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
@@ -1368,14 +1376,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
case ATA_CMD_SET_FEATURES:
if ((qc->tf.feature == SETFEATURES_WC_ON) ||
(qc->tf.feature == SETFEATURES_WC_OFF)) {
- ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ap->link.eh_info.action |= ATA_EH_REVALIDATE;
ata_port_schedule_eh(ap);
}
break;
case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
case ATA_CMD_SET_MULTI: /* multi_count changed */
- ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ap->link.eh_info.action |= ATA_EH_REVALIDATE;
ata_port_schedule_eh(ap);
break;
}
@@ -1422,37 +1430,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_port *ap = dev->ap;
- int is_ncq = is_io && ata_ncq_enabled(dev);
-
- if (is_ncq) {
- if (!ata_tag_valid(ap->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
@@ -1483,14 +1460,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
- int is_io = xlat_func == ata_scsi_rw_xlat;
+ int rc;
VPRINTK("ENTER\n");
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1498,17 +1473,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
/* data is present; dma-map it */
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
- if (unlikely(cmd->request_bufflen < 1)) {
+ if (unlikely(scsi_bufflen(cmd) < 1)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: zero len r/w req\n");
goto err_did;
}
- if (cmd->use_sg)
- ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
- else
- ata_sg_init_one(qc, cmd->request_buffer,
- cmd->request_bufflen);
+ ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
qc->dma_dir = cmd->sc_data_direction;
}
@@ -1518,6 +1489,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
if (xlat_func(qc))
goto early_finish;
+ if (ap->ops->qc_defer) {
+ if ((rc = ap->ops->qc_defer(qc)))
+ goto defer;
+ }
+
/* select device, send command to hardware */
ata_qc_issue(qc);
@@ -1539,8 +1515,12 @@ err_mem:
return 0;
defer:
+ ata_qc_free(qc);
DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (rc == ATA_DEFER_LINK)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ else
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/**
@@ -1562,15 +1542,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
u8 *buf;
unsigned int buflen;
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ struct scatterlist *sg = scsi_sglist(cmd);
- sg = (struct scatterlist *) cmd->request_buffer;
+ if (sg) {
buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
buflen = sg->length;
} else {
- buf = cmd->request_buffer;
- buflen = cmd->request_bufflen;
+ buf = NULL;
+ buflen = 0;
}
*buf_out = buf;
@@ -1590,12 +1569,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
{
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
+ if (sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
}
/**
@@ -1817,6 +1793,62 @@ 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)
+ */
+
+unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ 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);
+
+ 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);
+
+ /* we don't store the ATA device signature, so we fake it */
+
+ tf.command = ATA_DRDY; /* really, this is Status reg */
+ 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) */
+
+ pbuf[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));
+ return 0;
+}
+
+/**
* 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.
@@ -2273,8 +2305,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
qc->tf.feature |= ATAPI_PKT_DMA;
} else {
qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
+ qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
+ qc->tf.lbah = 0;
}
qc->nbytes = SCSI_SENSE_BUFFERSIZE;
@@ -2383,6 +2415,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
@@ -2396,20 +2429,26 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
}
qc->tf.command = ATA_CMD_PACKET;
- qc->nbytes = scmd->request_bufflen;
+ qc->nbytes = scsi_bufflen(scmd);
/* check whether ATAPI DMA is safe */
if (!using_pio && ata_check_atapi_dma(qc))
using_pio = 1;
+ /* Some controller variants snoop this value for Packet transfers
+ to do state machine and FIFO management. Thus we want to set it
+ properly, and for DMA where it is effectively meaningless */
+ nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+
+ qc->tf.lbam = (nbytes & 0xFF);
+ qc->tf.lbah = (nbytes >> 8);
+
if (using_pio || nodata) {
/* no data, or PIO data xfer */
if (nodata)
qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
else
qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
} else {
/* DMA data xfer */
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
@@ -2420,24 +2459,42 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.feature |= ATAPI_DMADIR;
}
+
+ /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE
+ as ATAPI tape drives don't get this right otherwise */
return 0;
}
-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+static struct ata_device * ata_find_dev(struct ata_port *ap, int devno)
{
- if (likely(id < ATA_MAX_DEVICES))
- return &ap->device[id];
+ if (ap->nr_pmp_links == 0) {
+ if (likely(devno < ata_link_max_devices(&ap->link)))
+ return &ap->link.device[devno];
+ } else {
+ if (likely(devno < ap->nr_pmp_links))
+ return &ap->pmp_link[devno].device[0];
+ }
+
return NULL;
}
static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev)
{
+ int devno;
+
/* skip commands not addressed to targets we simulate */
- if (unlikely(scsidev->channel || scsidev->lun))
- return NULL;
+ if (ap->nr_pmp_links == 0) {
+ if (unlikely(scsidev->channel || scsidev->lun))
+ return NULL;
+ devno = scsidev->id;
+ } else {
+ if (unlikely(scsidev->id || scsidev->lun))
+ return NULL;
+ devno = scsidev->channel;
+ }
- return ata_find_dev(ap, scsidev->id);
+ return ata_find_dev(ap, devno);
}
/**
@@ -2458,7 +2515,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev)
if (unlikely(!ata_dev_enabled(dev)))
return 0;
- if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+ if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
if (unlikely(dev->class == ATA_DEV_ATAPI)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: ATAPI is %s, device ignored.\n",
@@ -2631,7 +2688,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
case ATA_CMD_WRITE_LONG_ONCE:
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
goto invalid_fld;
- qc->sect_size = scmd->request_bufflen;
+ qc->sect_size = scsi_bufflen(scmd);
}
/*
@@ -2661,7 +2718,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nbytes = scmd->request_bufflen;
+ qc->nbytes = scsi_bufflen(scmd);
/* request result TF */
qc->flags |= ATA_QCFLAG_RESULT_TF;
@@ -2746,28 +2803,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
void (*done)(struct scsi_cmnd *),
struct ata_device *dev)
{
+ u8 scsi_op = scmd->cmnd[0];
+ ata_xlat_func_t xlat_func;
int rc = 0;
- if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
- DPRINTK("bad CDB len=%u, max=%u\n",
- scmd->cmd_len, dev->cdb_len);
- scmd->result = DID_ERROR << 16;
- done(scmd);
- return 0;
- }
-
if (dev->class == ATA_DEV_ATA) {
- ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
- scmd->cmnd[0]);
+ if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len))
+ goto bad_cdb_len;
- if (xlat_func)
- rc = ata_scsi_translate(dev, scmd, done, xlat_func);
- else
- ata_scsi_simulate(dev, scmd, done);
- } else
- rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
+ xlat_func = ata_get_xlat_func(dev, scsi_op);
+ } else {
+ if (unlikely(!scmd->cmd_len))
+ goto bad_cdb_len;
+
+ xlat_func = NULL;
+ if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
+ /* relay SCSI command to ATAPI device */
+ if (unlikely(scmd->cmd_len > dev->cdb_len))
+ goto bad_cdb_len;
+
+ xlat_func = atapi_xlat;
+ } else {
+ /* ATA_16 passthru, treat as an ATA command */
+ if (unlikely(scmd->cmd_len > 16))
+ goto bad_cdb_len;
+
+ xlat_func = ata_get_xlat_func(dev, scsi_op);
+ }
+ }
+
+ if (xlat_func)
+ rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+ else
+ ata_scsi_simulate(dev, scmd, done);
return rc;
+
+ bad_cdb_len:
+ DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
+ scmd->cmd_len, scsi_op, dev->cdb_len);
+ scmd->result = DID_ERROR << 16;
+ done(scmd);
+ return 0;
}
/**
@@ -2835,6 +2912,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
+ u8 tmp8;
args.dev = dev;
args.id = dev->id;
@@ -2842,15 +2920,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
args.done = done;
switch(scsicmd[0]) {
- /* no-op's, complete with success */
- case SYNCHRONIZE_CACHE:
- case REZERO_UNIT:
- case SEEK_6:
- case SEEK_10:
- case TEST_UNIT_READY:
- case FORMAT_UNIT: /* FIXME: correct? */
- case SEND_DIAGNOSTIC: /* FIXME: correct? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ /* TODO: worth improving? */
+ case FORMAT_UNIT:
+ ata_scsi_invalid_field(cmd, done);
break;
case INQUIRY:
@@ -2858,14 +2930,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_scsi_invalid_field(cmd, done);
else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
- else if (scsicmd[2] == 0x00)
+ else switch (scsicmd[2]) {
+ case 0x00:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
- else if (scsicmd[2] == 0x80)
+ break;
+ case 0x80:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
- else if (scsicmd[2] == 0x83)
+ break;
+ case 0x83:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
- else
+ break;
+ case 0x89:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+ break;
+ default:
ata_scsi_invalid_field(cmd, done);
+ break;
+ }
break;
case MODE_SENSE:
@@ -2893,8 +2974,33 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
break;
- /* mandatory commands we haven't implemented yet */
case REQUEST_SENSE:
+ ata_scsi_set_sense(cmd, 0, 0, 0);
+ cmd->result = (DRIVER_SENSE << 24);
+ done(cmd);
+ break;
+
+ /* if we reach this, then writeback caching is disabled,
+ * turning this into a no-op.
+ */
+ case SYNCHRONIZE_CACHE:
+ /* fall through */
+
+ /* no-op's, complete with success */
+ case REZERO_UNIT:
+ case SEEK_6:
+ case SEEK_10:
+ case TEST_UNIT_READY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ break;
+
+ case SEND_DIAGNOSTIC:
+ tmp8 = scsicmd[1] & ~(1 << 3);
+ if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
/* all other commands */
default:
@@ -2928,6 +3034,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ /* Schedule policy is determined by ->qc_defer()
+ * callback and it needs to see every deferred qc.
+ * Set host_blocked to 1 to prevent SCSI midlayer from
+ * automatically deferring requests.
+ */
+ shost->max_host_blocked = 1;
+
rc = scsi_add_host(ap->scsi_host, ap->host->dev);
if (rc)
goto err_add;
@@ -2947,26 +3060,79 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
return rc;
}
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
- unsigned int i;
+ int tries = 5;
+ struct ata_device *last_failed_dev = NULL;
+ struct ata_link *link;
+ struct ata_device *dev;
if (ap->flags & ATA_FLAG_DISABLED)
return;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- struct scsi_device *sdev;
+ repeat:
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct scsi_device *sdev;
+ int channel = 0, id = 0;
- if (!ata_dev_enabled(dev) || dev->sdev)
- continue;
+ if (!ata_dev_enabled(dev) || dev->sdev)
+ continue;
- sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
- if (!IS_ERR(sdev)) {
- dev->sdev = sdev;
- scsi_device_put(sdev);
+ if (ata_is_host_link(link))
+ id = dev->devno;
+ else
+ channel = link->pmp;
+
+ sdev = __scsi_add_device(ap->scsi_host, channel, id, 0,
+ NULL);
+ if (!IS_ERR(sdev)) {
+ dev->sdev = sdev;
+ scsi_device_put(sdev);
+ }
+ }
+ }
+
+ /* If we scanned while EH was in progress or allocation
+ * failure occurred, scan would have failed silently. Check
+ * whether all devices are attached.
+ */
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ if (ata_dev_enabled(dev) && !dev->sdev)
+ goto exit_loop;
+ }
+ }
+ exit_loop:
+ if (!link)
+ return;
+
+ /* we're missing some SCSI devices */
+ if (sync) {
+ /* If caller requested synchrnous scan && we've made
+ * any progress, sleep briefly and repeat.
+ */
+ if (dev != last_failed_dev) {
+ msleep(100);
+ last_failed_dev = dev;
+ goto repeat;
+ }
+
+ /* We might be failing to detect boot device, give it
+ * a few more chances.
+ */
+ if (--tries) {
+ msleep(100);
+ goto repeat;
}
+
+ ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+ "failed without making any progress,\n"
+ " switching to async\n");
}
+
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ round_jiffies_relative(HZ));
}
/**
@@ -3005,7 +3171,7 @@ int ata_scsi_offline_dev(struct ata_device *dev)
*/
static void ata_scsi_remove_dev(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct scsi_device *sdev;
unsigned long flags;
@@ -3052,6 +3218,43 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
}
}
+static void ata_scsi_handle_link_detach(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *dev;
+
+ ata_link_for_each_dev(dev, link) {
+ unsigned long flags;
+
+ if (!(dev->flags & ATA_DFLAG_DETACHED))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_DETACHED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_scsi_remove_dev(dev);
+ }
+}
+
+/**
+ * ata_scsi_media_change_notify - send media change event
+ * @atadev: Pointer to the disk device with media change event
+ *
+ * Tell the block layer to send a media change notification
+ * event.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_scsi_media_change_notify(struct ata_device *dev)
+{
+#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED
+ if (dev->sdev)
+ scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
+#endif
+}
+
/**
* ata_scsi_hotplug - SCSI part of hotplug
* @work: Pointer to ATA port to perform SCSI hotplug on
@@ -3077,36 +3280,17 @@ void ata_scsi_hotplug(struct work_struct *work)
DPRINTK("ENTER\n");
- /* unplug detached devices */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- unsigned long flags;
-
- if (!(dev->flags & ATA_DFLAG_DETACHED))
- continue;
-
- spin_lock_irqsave(ap->lock, flags);
- dev->flags &= ~ATA_DFLAG_DETACHED;
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_scsi_remove_dev(dev);
- }
+ /* Unplug detached devices. We cannot use link iterator here
+ * because PMP links have to be scanned even if PMP is
+ * currently not attached. Iterate manually.
+ */
+ ata_scsi_handle_link_detach(&ap->link);
+ if (ap->pmp_link)
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_scsi_handle_link_detach(&ap->pmp_link[i]);
/* scan for new ones */
- ata_scsi_scan_host(ap);
-
- /* If we scanned while EH was in progress, scan would have
- * failed silently. Requeue if there are enabled but
- * unattached devices.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
- round_jiffies_relative(HZ));
- break;
- }
- }
+ ata_scsi_scan_host(ap, 0);
DPRINTK("EXIT\n");
}
@@ -3132,27 +3316,42 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
{
struct ata_port *ap = ata_shost_to_port(shost);
unsigned long flags;
- int rc = 0;
+ int devno, rc = 0;
if (!ap->ops->error_handler)
return -EOPNOTSUPP;
- if ((channel != SCAN_WILD_CARD && channel != 0) ||
- (lun != SCAN_WILD_CARD && lun != 0))
+ if (lun != SCAN_WILD_CARD && lun)
return -EINVAL;
+ if (ap->nr_pmp_links == 0) {
+ if (channel != SCAN_WILD_CARD && channel)
+ return -EINVAL;
+ devno = id;
+ } else {
+ if (id != SCAN_WILD_CARD && id)
+ return -EINVAL;
+ devno = channel;
+ }
+
spin_lock_irqsave(ap->lock, flags);
- if (id == SCAN_WILD_CARD) {
- ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
+ if (devno == SCAN_WILD_CARD) {
+ struct ata_link *link;
+
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_info *ehi = &link->eh_info;
+ ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ }
} else {
- struct ata_device *dev = ata_find_dev(ap, id);
+ struct ata_device *dev = ata_find_dev(ap, devno);
if (dev) {
- ap->eh_info.probe_mask |= 1 << dev->devno;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
- ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+ struct ata_eh_info *ehi = &dev->link->eh_info;
+ ehi->probe_mask |= 1 << dev->devno;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}
@@ -3183,24 +3382,26 @@ void ata_scsi_dev_rescan(struct work_struct *work)
{
struct ata_port *ap =
container_of(work, struct ata_port, scsi_rescan_task);
+ struct ata_link *link;
+ struct ata_device *dev;
unsigned long flags;
- unsigned int i;
spin_lock_irqsave(ap->lock, flags);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- struct scsi_device *sdev = dev->sdev;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct scsi_device *sdev = dev->sdev;
- if (!ata_dev_enabled(dev) || !sdev)
- continue;
- if (scsi_device_get(sdev))
- continue;
+ if (!ata_dev_enabled(dev) || !sdev)
+ continue;
+ if (scsi_device_get(sdev))
+ continue;
- spin_unlock_irqrestore(ap->lock, flags);
- scsi_rescan_device(&(sdev->sdev_gendev));
- scsi_device_put(sdev);
- spin_lock_irqsave(ap->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
+ scsi_rescan_device(&(sdev->sdev_gendev));
+ scsi_device_put(sdev);
+ spin_lock_irqsave(ap->lock, flags);
+ }
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -3328,7 +3529,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
{
ata_scsi_sdev_config(sdev);
- ata_scsi_dev_config(sdev, ap->device);
+ ata_scsi_dev_config(sdev, ap->link.device);
return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
@@ -3351,8 +3552,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
ata_scsi_dump_cdb(ap, cmd);
- if (likely(ata_scsi_dev_enabled(ap->device)))
- rc = __ata_scsi_queuecmd(cmd, done, ap->device);
+ if (likely(ata_scsi_dev_enabled(ap->link.device)))
+ rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
else {
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index ca7d2245d684..026439e05afe 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,5 +1,5 @@
/*
- * libata-bmdma.c - helper library for PCI IDE BMDMA
+ * libata-sff.c - helper library for PCI IDE BMDMA
*
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
* Please ALWAYS copy linux-ide@vger.kernel.org
@@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap)
return tmp;
}
-u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; }
-
-/**
- * ata_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Wait up to 10 ms for legacy IDE device to become idle (BUSY
- * or BUSY+DRQ clear). Obtain dma status and port status from
- * device. Clear the interrupt. Return port status.
- *
- * LOCKING:
- */
-
-u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat = 0, post_stat = 0, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- if (ap->ioaddr.bmdma_addr) {
- /* get controller status; clear intr, err bits */
- host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
- ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
- post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- }
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
- return status;
-}
-
-u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
-
/**
* ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
@@ -211,6 +171,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = ioread8(ioaddr->lbal_addr);
tf->hob_lbam = ioread8(ioaddr->lbam_addr);
tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
}
}
@@ -295,7 +257,7 @@ void ata_bmdma_start (struct ata_queued_cmd *qc)
dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- /* Strictly, one may wish to issue a readb() here, to
+ /* Strictly, one may wish to issue an ioread8() here, to
* flush the mmio write. However, control also passes
* to the hardware at this point, and it will interrupt
* us when we are to resume control. So, in effect,
@@ -305,6 +267,9 @@ void ata_bmdma_start (struct ata_queued_cmd *qc)
* is expected, so I think it is best to not add a readb()
* without first all the MMIO ATA cards/mobos.
* Or maybe I'm just being paranoid.
+ *
+ * FIXME: The posting of this write means I/O starts are
+ * unneccessarily delayed for MMIO
*/
}
@@ -440,7 +405,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
unsigned long flags;
int thaw = 0;
- qc = __ata_qc_from_tag(ap, ap->active_tag);
+ qc = __ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
qc = NULL;
@@ -495,7 +460,7 @@ void ata_bmdma_error_handler(struct ata_port *ap)
ata_reset_fn_t hardreset;
hardreset = NULL;
- if (sata_scr_valid(ap))
+ if (sata_scr_valid(&ap->link))
hardreset = sata_std_hardreset;
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
@@ -571,6 +536,10 @@ int ata_pci_init_bmdma(struct ata_host *host)
struct pci_dev *pdev = to_pci_dev(gdev);
int i, rc;
+ /* No BAR4 allocation: No DMA */
+ if (pci_resource_start(pdev, 4) == 0)
+ return 0;
+
/* TODO: If we get no DMA mask we should fall back to PIO */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -598,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host)
if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
(ioread8(bmdma + 2) & 0x80))
host->flags |= ATA_HOST_SIMPLEX;
+
+ ata_port_desc(ap, "bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
}
return 0;
@@ -665,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host)
((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, base),
+ (unsigned long long)pci_resource_start(pdev, base + 1));
+
mask |= 1 << i;
}
@@ -835,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
- host->irq = pdev->irq;
+
+ ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+ ata_port_desc(host->ports[1], "irq %d", pdev->irq);
} else {
if (!ata_port_is_dummy(host->ports[0])) {
- host->irq = ATA_PRIMARY_IRQ(pdev);
- rc = devm_request_irq(dev, host->irq,
+ rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
+
+ ata_port_desc(host->ports[0], "irq %d",
+ ATA_PRIMARY_IRQ(pdev));
}
if (!ata_port_is_dummy(host->ports[1])) {
- host->irq2 = ATA_SECONDARY_IRQ(pdev);
- rc = devm_request_irq(dev, host->irq2,
+ rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
+
+ ata_port_desc(host->ports[1], "irq %d",
+ ATA_SECONDARY_IRQ(pdev));
}
}
@@ -900,7 +882,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer
/* Filter out DMA modes if the device has been configured by
the BIOS as PIO only */
- if (adev->ap->ioaddr.bmdma_addr == 0)
+ if (adev->link->ap->ioaddr.bmdma_addr == 0)
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
return xfer_mask;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ba17fc5f2e99..90df58a3edc9 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -29,6 +29,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
+#define DRV_VERSION "3.00" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_device *dev;
@@ -56,6 +57,7 @@ extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
extern int atapi_dmadir;
+extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
@@ -67,21 +69,23 @@ extern void ata_dev_disable(struct ata_device *dev);
extern void ata_port_flush_task(struct ata_port *ap);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen);
+ int dma_dir, void *buf, unsigned int buflen,
+ unsigned long timeout);
extern unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, struct scatterlist *sg,
- unsigned int n_elem);
+ unsigned int n_elem, unsigned long timeout);
extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id);
extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
-extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags);
extern int ata_dev_configure(struct ata_device *dev);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
+extern int sata_down_spd_limit(struct ata_link *link);
+extern int sata_set_spd_needed(struct ata_link *link);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -92,17 +96,21 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device,
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd(struct ata_link *link);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct ata_port *ata_port_alloc(struct ata_host *host);
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
+extern void ata_acpi_associate_sata_port(struct ata_port *ap);
extern void ata_acpi_associate(struct ata_host *host);
extern int ata_acpi_on_suspend(struct ata_port *ap);
extern void ata_acpi_on_resume(struct ata_port *ap);
extern int ata_acpi_on_devcfg(struct ata_device *adev);
#else
+static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
static inline void ata_acpi_associate(struct ata_host *host) { }
static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
static inline void ata_acpi_on_resume(struct ata_port *ap) { }
@@ -112,8 +120,9 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
/* libata-scsi.c */
extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+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);
@@ -147,11 +156,32 @@ 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);
+/* libata-pmp.c */
+extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_attach(struct ata_device *dev);
+
/* libata-eh.c */
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
new file mode 100644
index 000000000000..5d3920f6fd69
--- /dev/null
+++ b/drivers/ata/pata_acpi.c
@@ -0,0 +1,395 @@
+/*
+ * ACPI PATA driver
+ *
+ * (c) 2007 Red Hat <alan@redhat.com>
+ */
+
+#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 <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_acpi"
+#define DRV_VERSION "0.2.3"
+
+struct pata_acpi {
+ struct ata_acpi_gtm gtm;
+ void *last;
+ unsigned long mask[2];
+};
+
+/**
+ * pacpi_pre_reset - check for 40/80 pin
+ * @ap: Port
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the PATA port setup we need.
+ */
+
+static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pata_acpi *acpi = ap->private_data;
+ if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+ return -ENODEV;
+
+ return ata_std_prereset(link, deadline);
+}
+
+/**
+ * pacpi_cable_detect - cable type detection
+ * @ap: port to detect
+ *
+ * Perform device specific cable detection
+ */
+
+static int pacpi_cable_detect(struct ata_port *ap)
+{
+ struct pata_acpi *acpi = ap->private_data;
+
+ if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * pacpi_error_handler - Setup and error handler
+ * @ap: Port to handle
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pacpi_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+/* Welcome to ACPI, bring a bucket */
+static const unsigned int pio_cycle[7] = {
+ 600, 383, 240, 180, 120, 100, 80
+};
+static const unsigned int mwdma_cycle[5] = {
+ 480, 150, 120, 100, 80
+};
+static const unsigned int udma_cycle[7] = {
+ 120, 80, 60, 45, 30, 20, 15
+};
+
+/**
+ * pacpi_discover_modes - filter non ACPI modes
+ * @adev: ATA device
+ * @mask: proposed modes
+ *
+ * Try the modes available and see which ones the ACPI method will
+ * set up sensibly. From this we get a mask of ACPI modes we can use
+ */
+
+static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+ int i;
+ u32 t;
+ unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
+
+ struct ata_acpi_gtm probe;
+
+ probe = acpi->gtm;
+
+ /* We always use the 0 slot for crap hardware */
+ if (!(probe.flags & 0x10))
+ unit = 0;
+
+ ata_acpi_gtm(ap, &probe);
+
+ /* Start by scanning for PIO modes */
+ for (i = 0; i < 7; i++) {
+ t = probe.drive[unit].pio;
+ if (t <= pio_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
+ break;
+ }
+ }
+
+ /* See if we have MWDMA or UDMA data. We don't bother with MWDMA
+ if UDMA is availabe as this means the BIOS set UDMA and our
+ error changedown if it works is UDMA to PIO anyway */
+ if (probe.flags & (1 << (2 * unit))) {
+ /* MWDMA */
+ for (i = 0; i < 5; i++) {
+ t = probe.drive[unit].dma;
+ if (t <= mwdma_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
+ break;
+ }
+ }
+ } else {
+ /* UDMA */
+ for (i = 0; i < 7; i++) {
+ t = probe.drive[unit].dma;
+ if (t <= udma_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
+ break;
+ }
+ }
+ }
+ if (mask & (0xF8 << ATA_SHIFT_UDMA))
+ ap->cbl = ATA_CBL_PATA80;
+ return mask;
+}
+
+/**
+ * pacpi_mode_filter - mode filter for ACPI
+ * @adev: device
+ * @mask: mask of valid modes
+ *
+ * Filter the valid mode list according to our own specific rules, in
+ * this case the list of discovered valid modes obtained by ACPI probing
+ */
+
+static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ struct pata_acpi *acpi = adev->link->ap->private_data;
+ return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]);
+}
+
+/**
+ * pacpi_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ */
+
+static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if(!(acpi->gtm.flags & 0x10))
+ unit = 0;
+
+ /* Now stuff the nS values into the structure */
+ acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+ ata_acpi_stm(ap, &acpi->gtm);
+ /* See what mode we actually got */
+ ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ * pacpi_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ */
+
+static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if(!(acpi->gtm.flags & 0x10))
+ unit = 0;
+
+ /* Now stuff the nS values into the structure */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+ acpi->gtm.flags |= (1 << (2 * unit));
+ } else {
+ acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+ acpi->gtm.flags &= ~(1 << (2 * unit));
+ }
+ ata_acpi_stm(ap, &acpi->gtm);
+ /* See what mode we actually got */
+ ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ * pacpi_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary.
+ */
+
+static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if (acpi->gtm.flags & 0x10)
+ return ata_qc_issue_prot(qc);
+
+ if (adev != acpi->last) {
+ pacpi_set_piomode(ap, adev);
+ if (adev->dma_mode)
+ pacpi_set_dmamode(ap, adev);
+ acpi->last = adev;
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * pacpi_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * Use the port_start hook to maintain private control structures
+ */
+
+static int pacpi_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pata_acpi *acpi;
+
+ int ret;
+
+ if (ap->acpi_handle == NULL)
+ return -ENODEV;
+
+ acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
+ if (ap->private_data == NULL)
+ return -ENOMEM;
+ acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]);
+ acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]);
+ ret = ata_sff_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct scsi_host_template pacpi_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations pacpi_ops = {
+ .set_piomode = pacpi_set_piomode,
+ .set_dmamode = pacpi_set_dmamode,
+ .mode_filter = pacpi_mode_filter,
+
+ /* Task file is PCI ATA format, use helpers */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pacpi_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pacpi_cable_detect,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = pacpi_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ /* Timeout handling */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = pacpi_port_start,
+};
+
+
+/**
+ * pacpi_init_one - Register ACPI ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in pacpi_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info info = {
+ .sht = &pacpi_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+
+ .port_ops = &pacpi_ops,
+ };
+ const struct ata_port_info *ppi[] = { &info, NULL };
+ return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id pacpi_pci_tbl[] = {
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+ { } /* terminate list */
+};
+
+static struct pci_driver pacpi_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pacpi_pci_tbl,
+ .probe = pacpi_init_one,
+ .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+};
+
+static int __init pacpi_init(void)
+{
+ return pci_register_driver(&pacpi_pci_driver);
+}
+
+static void __exit pacpi_exit(void)
+{
+ pci_unregister_driver(&pacpi_pci_driver);
+}
+
+module_init(pacpi_init);
+module_exit(pacpi_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 010436795d20..364534e7aff4 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,18 +34,25 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.4"
+#define DRV_VERSION "0.7.5"
/*
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "HP Pavilion N5430",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+ DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
+ },
+ },
+ {
+ .ident = "Toshiba Satelite S1800-814",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
},
},
{ }
@@ -298,7 +305,6 @@ static struct scsi_host_template ali_sht = {
*/
static struct ata_port_operations ali_early_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -320,9 +326,8 @@ static struct ata_port_operations ali_early_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -330,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = {
* detect
*/
static struct ata_port_operations ali_20_port_ops = {
- .port_disable = ata_port_disable,
-
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ali_20_filter,
@@ -362,16 +365,14 @@ static struct ata_port_operations ali_20_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
* Port operations for DMA capable ALi with cable detect
*/
static struct ata_port_operations ali_c2_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -401,16 +402,14 @@ static struct ata_port_operations ali_c2_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
* Port operations for DMA capable ALi with cable detect and LBA48
*/
static struct ata_port_operations ali_c5_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -439,9 +438,8 @@ static struct ata_port_operations ali_c5_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index b09facad63e1..c5779ad4abca 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.3.8"
+#define DRV_VERSION "0.3.9"
/**
* timing_setup - shared timing computation and load
@@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
}
/**
- * amd_probe_init - perform reset handling
- * @ap: ATA port
+ * amd_pre_reset - perform reset handling
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Reset sequence checking enable bits to see which ports are
* active.
*/
-static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits amd_enable_bits[] = {
{ 0x40, 1, 0x02, 0x02 },
{ 0x40, 1, 0x01, 0x01 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void amd_error_handler(struct ata_port *ap)
@@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* nv_probe_init - cable detection
- * @ap: ATA port
+ * @lin: ATA link
*
* Perform cable detection. The BIOS stores this in PCI config
* space for us.
*/
-static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int nv_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits nv_enable_bits[] = {
{ 0x50, 1, 0x02, 0x02 },
{ 0x50, 1, 0x01, 0x01 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -268,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap)
pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
cbl = ATA_CBL_PATA80;
+ /* And a triple check across suspend/resume with ACPI around */
+ if (ata_acpi_cbl_80wire(ap))
+ cbl = ATA_CBL_PATA80;
return cbl;
}
@@ -327,7 +332,6 @@ static struct scsi_host_template amd_sht = {
};
static struct ata_port_operations amd33_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd33_set_piomode,
.set_dmamode = amd33_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -356,13 +360,11 @@ static struct ata_port_operations amd33_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd66_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd66_set_piomode,
.set_dmamode = amd66_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -391,13 +393,11 @@ static struct ata_port_operations amd66_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd100_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd100_set_piomode,
.set_dmamode = amd100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -426,13 +426,11 @@ static struct ata_port_operations amd100_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd133_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd133_set_piomode,
.set_dmamode = amd133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -461,13 +459,11 @@ static struct ata_port_operations amd133_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations nv100_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = nv100_set_piomode,
.set_dmamode = nv100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -496,13 +492,11 @@ static struct ata_port_operations nv100_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations nv133_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = nv133_set_piomode,
.set_dmamode = nv133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -531,9 +525,8 @@ static struct ata_port_operations nv133_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index ce589d96ca42..d4218310327b 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -2,6 +2,7 @@
* pata_artop.c - ARTOP ATA controller driver
*
* (C) 2006 Red Hat <alan@redhat.com>
+ * (C) 2007 Bartlomiej Zolnierkiewicz
*
* Based in part on drivers/ide/pci/aec62xx.c
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
@@ -28,7 +29,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_artop"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.4.4"
/*
* The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
@@ -39,8 +40,9 @@
static int clock = 0;
-static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
@@ -50,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -70,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap)
/**
* artop6260_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* The ARTOP hardware reports the cable detect bits in register 0x49.
* Nothing complicated needed here.
*/
-static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
{ 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Odd numbered device ids are the units with enable bits (the -R cards) */
if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -329,7 +332,6 @@ static struct scsi_host_template artop_sht = {
};
static const struct ata_port_operations artop6210_ops = {
- .port_disable = ata_port_disable,
.set_piomode = artop6210_set_piomode,
.set_dmamode = artop6210_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -358,13 +360,11 @@ static const struct ata_port_operations artop6210_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations artop6260_ops = {
- .port_disable = ata_port_disable,
.set_piomode = artop6260_set_piomode,
.set_dmamode = artop6260_set_dmamode,
@@ -391,9 +391,8 @@ static const struct ata_port_operations artop6260_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
@@ -430,7 +429,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA4,
.port_ops = &artop6260_ops,
};
- static const struct ata_port_info info_626x_fast = {
+ static const struct ata_port_info info_628x = {
.sht = &artop_sht,
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f, /* pio0-4 */
@@ -438,6 +437,14 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA5,
.port_ops = &artop6260_ops,
};
+ static const struct ata_port_info info_628x_fast = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &artop6260_ops,
+ };
const struct ata_port_info *ppi[] = { NULL, NULL };
if (!printed_version++)
@@ -455,13 +462,13 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
}
else if (id->driver_data == 1) /* 6260 */
ppi[0] = &info_626x;
- else if (id->driver_data == 2) { /* 6260 or 6260 + fast */
+ else if (id->driver_data == 2) { /* 6280 or 6280 + fast */
unsigned long io = pci_resource_start(pdev, 4);
u8 reg;
- ppi[0] = &info_626x;
+ ppi[0] = &info_628x;
if (inb(io) & 0x10)
- ppi[0] = &info_626x_fast;
+ ppi[0] = &info_628x_fast;
/* Mac systems come up with some registers not set as we
will need them */
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
new file mode 100644
index 000000000000..bb250a48e27c
--- /dev/null
+++ b/drivers/ata/pata_at32.c
@@ -0,0 +1,441 @@
+/*
+ * AVR32 SMC/CFC PATA Driver
+ *
+ * Copyright (C) 2007 Atmel Norway
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/smc.h>
+
+#define DRV_NAME "pata_at32"
+#define DRV_VERSION "0.0.2"
+
+/*
+ * CompactFlash controller memory layout relative to the base address:
+ *
+ * Attribute memory: 0000 0000 -> 003f ffff
+ * Common memory: 0040 0000 -> 007f ffff
+ * I/O memory: 0080 0000 -> 00bf ffff
+ * True IDE Mode: 00c0 0000 -> 00df ffff
+ * Alt IDE Mode: 00e0 0000 -> 00ff ffff
+ *
+ * Only True IDE and Alt True IDE mode are needed for this driver.
+ *
+ * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc)
+ * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat)
+ */
+#define CF_IDE_OFFSET 0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_RES_SIZE 2048
+
+/*
+ * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA
+ * adaptor with a logic analyzer or similar.
+ */
+#undef DEBUG_BUS
+
+/*
+ * ATA PIO modes
+ *
+ * Name | Mb/s | Min cycle time | Mask
+ * --------+-------+----------------+--------
+ * Mode 0 | 3.3 | 600 ns | 0x01
+ * Mode 1 | 5.2 | 383 ns | 0x03
+ * Mode 2 | 8.3 | 240 ns | 0x07
+ * Mode 3 | 11.1 | 180 ns | 0x0f
+ * Mode 4 | 16.7 | 120 ns | 0x1f
+ */
+#define PIO_MASK (0x1f)
+
+/*
+ * Struct containing private information about device.
+ */
+struct at32_ide_info {
+ unsigned int irq;
+ struct resource res_ide;
+ struct resource res_alt;
+ void __iomem *ide_addr;
+ void __iomem *alt_addr;
+ unsigned int cs;
+ struct smc_config smc;
+};
+
+/*
+ * Setup SMC for the given ATA timing.
+ */
+static int pata_at32_setup_timing(struct device *dev,
+ struct at32_ide_info *info,
+ const struct ata_timing *timing)
+{
+ /* These two values are found through testing */
+ const int min_recover = 25;
+ const int ncs_hold = 15;
+
+ struct smc_config *smc = &info->smc;
+
+ int active;
+ int recover;
+
+ /* Total cycle time */
+ smc->read_cycle = timing->cyc8b;
+
+ /* DIOR <= CFIOR timings */
+ smc->nrd_setup = timing->setup;
+ smc->nrd_pulse = timing->act8b;
+
+ /* Compute recover, extend total cycle if needed */
+ active = smc->nrd_setup + smc->nrd_pulse;
+ recover = smc->read_cycle - active;
+
+ if (recover < min_recover) {
+ smc->read_cycle = active + min_recover;
+ recover = min_recover;
+ }
+
+ /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
+ smc->ncs_read_setup = 0;
+ smc->ncs_read_pulse = active + ncs_hold;
+
+ /* Write timings same as read timings */
+ smc->write_cycle = smc->read_cycle;
+ smc->nwe_setup = smc->nrd_setup;
+ smc->nwe_pulse = smc->nrd_pulse;
+ smc->ncs_write_setup = smc->ncs_read_setup;
+ smc->ncs_write_pulse = smc->ncs_read_pulse;
+
+ /* Do some debugging output */
+ dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n",
+ smc->read_cycle, smc->nrd_setup, smc->nrd_pulse,
+ recover, smc->ncs_read_setup, smc->ncs_read_pulse,
+ smc->read_cycle - smc->ncs_read_pulse);
+
+ /* Finally, configure the SMC */
+ return smc_set_configuration(info->cs, smc);
+}
+
+/*
+ * Procedures for libATA.
+ */
+static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing timing;
+ struct at32_ide_info *info = ap->host->private_data;
+
+ int ret;
+
+ /* Compute ATA timing */
+ ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret);
+ return;
+ }
+
+ /* Setup SMC to ATA timing */
+ ret = pata_at32_setup_timing(ap->dev, info, &timing);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret);
+ return;
+ }
+}
+
+static void pata_at32_irq_clear(struct ata_port *ap)
+{
+ /* No DMA controller yet */
+}
+
+static struct scsi_host_template at32_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations at32_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pata_at32_set_piomode,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_data_xfer,
+
+ .irq_clear = pata_at32_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = ata_sff_port_start,
+};
+
+static int __init pata_at32_init_one(struct device *dev,
+ struct at32_ide_info *info)
+{
+ struct ata_host *host;
+ struct ata_port *ap;
+
+ host = ata_host_alloc(dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+
+ /* Setup ATA bindings */
+ ap->ops = &at32_port_ops;
+ ap->pio_mask = PIO_MASK;
+ ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS
+ | ATA_FLAG_PIO_POLLING;
+
+ /*
+ * Since all 8-bit taskfile transfers has to go on the lower
+ * byte of the data bus and there is a bug in the SMC that
+ * makes it impossible to alter the bus width during runtime,
+ * we need to hardwire the address signals as follows:
+ *
+ * A_IDE(2:0) <= A_EBI(3:1)
+ *
+ * This makes all addresses on the EBI even, thus all data
+ * will be on the lower byte of the data bus. All addresses
+ * used by libATA need to be altered according to this.
+ */
+ ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1);
+ ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1);
+
+ ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1);
+ ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1);
+ ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1);
+ ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1);
+ ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1);
+ ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1);
+ ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1);
+ ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1);
+ ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1);
+ ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1);
+
+ /* Set info as private data of ATA host */
+ host->private_data = info;
+
+ /* Register ATA device and return */
+ return ata_host_activate(host, info->irq, ata_interrupt,
+ IRQF_SHARED | IRQF_TRIGGER_RISING,
+ &at32_sht);
+}
+
+/*
+ * This function may come in handy for people analyzing their own
+ * EBI -> PATA adaptors.
+ */
+#ifdef DEBUG_BUS
+
+static void __init pata_at32_debug_bus(struct device *dev,
+ struct at32_ide_info *info)
+{
+ const int d1 = 0xff;
+ const int d2 = 0x00;
+
+ int i;
+
+ /* Write 8-bit values (registers) */
+ iowrite8(d1, info->alt_addr + (0x06 << 1));
+ iowrite8(d2, info->alt_addr + (0x06 << 1));
+
+ for (i = 0; i < 8; i++) {
+ iowrite8(d1, info->ide_addr + (i << 1));
+ iowrite8(d2, info->ide_addr + (i << 1));
+ }
+
+ /* Write 16 bit values (data) */
+ iowrite16(d1, info->ide_addr);
+ iowrite16(d1 << 8, info->ide_addr);
+
+ iowrite16(d1, info->ide_addr);
+ iowrite16(d1 << 8, info->ide_addr);
+}
+
+#endif
+
+static int __init pata_at32_probe(struct platform_device *pdev)
+{
+ const struct ata_timing initial_timing =
+ {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+
+ struct device *dev = &pdev->dev;
+ struct at32_ide_info *info;
+ struct ide_platform_data *board = pdev->dev.platform_data;
+ struct resource *res;
+
+ int irq;
+ int ret;
+
+ if (!board)
+ return -ENXIO;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ /* Retrive IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* Setup struct containing private infomation */
+ info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct at32_ide_info));
+
+ info->irq = irq;
+ info->cs = board->cs;
+
+ /* Request memory resources */
+ info->res_ide.start = res->start + CF_IDE_OFFSET;
+ info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1;
+ info->res_ide.name = "ide";
+ info->res_ide.flags = IORESOURCE_MEM;
+
+ ret = request_resource(res, &info->res_ide);
+ if (ret)
+ goto err_req_res_ide;
+
+ info->res_alt.start = res->start + CF_ALT_IDE_OFFSET;
+ info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1;
+ info->res_alt.name = "alt";
+ info->res_alt.flags = IORESOURCE_MEM;
+
+ ret = request_resource(res, &info->res_alt);
+ if (ret)
+ goto err_req_res_alt;
+
+ /* Setup non-timing elements of SMC */
+ info->smc.bus_width = 2; /* 16 bit data bus */
+ info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */
+ info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */
+ info->smc.nwait_mode = 3; /* NWAIT is in READY mode */
+ info->smc.byte_write = 0; /* Byte select access type */
+ info->smc.tdf_mode = 0; /* TDF optimization disabled */
+ info->smc.tdf_cycles = 0; /* No TDF wait cycles */
+
+ /* Setup ATA timing */
+ ret = pata_at32_setup_timing(dev, info, &initial_timing);
+ if (ret)
+ goto err_setup_timing;
+
+ /* Setup ATA addresses */
+ ret = -ENOMEM;
+ info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16);
+ info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16);
+ if (!info->ide_addr || !info->alt_addr)
+ goto err_ioremap;
+
+#ifdef DEBUG_BUS
+ pata_at32_debug_bus(dev, info);
+#endif
+
+ /* Register ATA device */
+ ret = pata_at32_init_one(dev, info);
+ if (ret)
+ goto err_ata_device;
+
+ return 0;
+
+ err_ata_device:
+ err_ioremap:
+ err_setup_timing:
+ release_resource(&info->res_alt);
+ err_req_res_alt:
+ release_resource(&info->res_ide);
+ err_req_res_ide:
+ kfree(info);
+
+ return ret;
+}
+
+static int __exit pata_at32_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct at32_ide_info *info;
+
+ if (!host)
+ return 0;
+
+ info = host->private_data;
+ ata_host_detach(host);
+
+ if (!info)
+ return 0;
+
+ release_resource(&info->res_ide);
+ release_resource(&info->res_alt);
+
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver pata_at32_driver = {
+ .remove = __exit_p(pata_at32_remove),
+ .driver = {
+ .name = "at32_ide",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pata_at32_init(void)
+{
+ return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
+}
+
+static void __exit pata_at32_exit(void)
+{
+ platform_driver_unregister(&pata_at32_driver);
+}
+
+module_init(pata_at32_init);
+module_exit(pata_at32_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
+MODULE_AUTHOR("Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com>");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 80509be49e7a..9623f5295530 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.4.6"
enum {
ATIIXP_IDE_PIO_TIMING = 0x40,
@@ -33,8 +33,9 @@ enum {
ATIIXP_IDE_UDMA_MODE = 0x56
};
-static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
static const struct pci_bits atiixp_enable_bits[] = {
{ 0x48, 1, 0x01, 0x00 },
{ 0x48, 1, 0x08, 0x00 }
@@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void atiixp_error_handler(struct ata_port *ap)
@@ -172,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* When DMA begins we need to ensure that the UDMA control
* register for the channel is correctly set.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
@@ -198,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
*
* DMA has completed. Clear the UDMA flag as the next operations will
* be PIO ones not UDMA data transfer.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
@@ -232,7 +239,6 @@ static struct scsi_host_template atiixp_sht = {
};
static struct ata_port_operations atiixp_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = atiixp_set_piomode,
.set_dmamode = atiixp_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -261,9 +267,8 @@ static struct ata_port_operations atiixp_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
new file mode 100644
index 000000000000..747549e4563a
--- /dev/null
+++ b/drivers/ata/pata_bf54x.c
@@ -0,0 +1,1627 @@
+/*
+ * File: drivers/ata/pata_bf54x.c
+ * Author: Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:
+ * Description: PATA Driver for blackfin 54x
+ *
+ * Modified:
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#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/platform_device.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME "pata-bf54x"
+#define DRV_VERSION "0.9"
+
+#define ATA_REG_CTRL 0x0E
+#define ATA_REG_ALTSTATUS ATA_REG_CTRL
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL 0x00
+#define ATAPI_OFFSET_STATUS 0x04
+#define ATAPI_OFFSET_DEV_ADDR 0x08
+#define ATAPI_OFFSET_DEV_TXBUF 0x0c
+#define ATAPI_OFFSET_DEV_RXBUF 0x10
+#define ATAPI_OFFSET_INT_MASK 0x14
+#define ATAPI_OFFSET_INT_STATUS 0x18
+#define ATAPI_OFFSET_XFER_LEN 0x1c
+#define ATAPI_OFFSET_LINE_STATUS 0x20
+#define ATAPI_OFFSET_SM_STATE 0x24
+#define ATAPI_OFFSET_TERMINATE 0x28
+#define ATAPI_OFFSET_PIO_TFRCNT 0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT 0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38
+#define ATAPI_OFFSET_REG_TIM_0 0x40
+#define ATAPI_OFFSET_PIO_TIM_0 0x44
+#define ATAPI_OFFSET_PIO_TIM_1 0x48
+#define ATAPI_OFFSET_MULTI_TIM_0 0x50
+#define ATAPI_OFFSET_MULTI_TIM_1 0x54
+#define ATAPI_OFFSET_MULTI_TIM_2 0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0 0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1 0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2 0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+ bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+ bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 3 4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s - SCLK = 133 MHz
+ * UDMA4 - 66 MB/s - SCLK >= 80 MHz
+ * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz
+ * UDMA2 - 33 MB/s - SCLK >= 40 MHz
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle */
+static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 };
+
+/**
+ * PIO timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW */
+static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 };
+/* DIOR/DIOW to end cycle */
+static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 };
+/* DIOW data hold */
+static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/* mode: 0 1 2 */
+/* Cycle Time */
+static const u32 mdma_t0min[] = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[] = { 215, 80, 70 };
+/* DMACK to read data released */
+static const u32 mdma_thmin[] = { 20, 15, 10 };
+/* DIOR/DIOW to DMACK hold */
+static const u32 mdma_tjmin[] = { 20, 5, 5 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkrmin[] = { 50, 50, 25 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkwmin[] = { 215, 50, 25 };
+/* CS[1:0] valid to DIOR/DIOW */
+static const u32 mdma_tmmin[] = { 50, 30, 25 };
+/* DMACK to read data released */
+static const u32 mdma_tzmax[] = { 20, 25, 25 };
+
+/**
+ * Ultra DMA timing table
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 };
+static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 };
+static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 };
+static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+/**
+ *
+ * Function: num_clocks_min
+ *
+ * Description:
+ * calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+ unsigned long fsclk)
+{
+ unsigned long tmp ;
+ unsigned short result;
+
+ tmp = tmin * (fsclk/1000/1000) / 1000;
+ result = (unsigned short)tmp;
+ if ((tmp*1000*1000) < (tmin*(fsclk/1000))) {
+ result++;
+ }
+
+ return result;
+}
+
+/**
+ * bfin_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int mode = adev->pio_mode - XFER_PIO_0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int fsclk = get_sclk();
+ unsigned short teoc_reg, t2_reg, teoc_pio;
+ unsigned short t4_reg, t2_pio, t1_reg;
+ unsigned short n0, n6, t6min = 5;
+
+ /* the most restrictive timing value is t6 and tc, the DIOW - data hold
+ * If one SCLK pulse is longer than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ n6 = num_clocks_min(t6min, fsclk);
+ if (mode >= 0 && mode <= 4 && n6 >= 1) {
+ pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+ /* calculate the timing values for register transfers. */
+ while (mode > 0 && pio_fsclk[mode] > fsclk)
+ mode--;
+
+ /* DIOR/DIOW to end cycle time */
+ t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(reg_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_reg + teoc_reg < n0)
+ t2_reg = n0 - teoc_reg;
+
+ /* calculate the timing values for pio transfers. */
+
+ /* DIOR/DIOW to end cycle time */
+ t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(pio_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_pio + teoc_pio < n0)
+ t2_pio = n0 - teoc_pio;
+
+ /* Address valid to DIOR/DIORW */
+ t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+ /* DIOW data hold */
+ t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+ ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+ ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+ ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+ if (mode > 2) {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) | IORDY_EN);
+ } else {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+ }
+
+ /* Disable host ATAPI PIO interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+ SSYNC();
+ }
+}
+
+/**
+ * bfin_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @udma: udma mode, 0 - 6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int mode;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned long fsclk = get_sclk();
+ unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah;
+ unsigned short tm, td, tkr, tkw, teoc, th;
+ unsigned short n0, nf, tfmin = 5;
+ unsigned short nmin, tcyc;
+
+ mode = adev->dma_mode - XFER_UDMA_0;
+ if (mode >= 0 && mode <= 5) {
+ pr_debug("set udmamode: mode=%d\n", mode);
+ /* the most restrictive timing value is t6 and tc,
+ * the DIOW - data hold. If one SCLK pulse is longer
+ * than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ while (mode > 0 && udma_fsclk[mode] > fsclk)
+ mode--;
+
+ nmin = num_clocks_min(udma_tmin[mode], fsclk);
+ if (nmin >= 1) {
+ /* calculate the timing values for Ultra DMA. */
+ tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk);
+ tcyc = num_clocks_min(udma_tcycmin[mode], fsclk);
+ tcyc_tdvs = 2;
+
+ /* increase tcyc - tdvs (tcyc_tdvs) until we meed
+ * the minimum cycle length
+ */
+ if (tdvs + tcyc_tdvs < tcyc)
+ tcyc_tdvs = tcyc - tdvs;
+
+ /* Mow assign the values required for the timing
+ * registers
+ */
+ if (tcyc_tdvs < 2)
+ tcyc_tdvs = 2;
+
+ if (tdvs < 2)
+ tdvs = 2;
+
+ tack = num_clocks_min(udma_tackmin, fsclk);
+ tss = num_clocks_min(udma_tssmin, fsclk);
+ tmli = num_clocks_min(udma_tmlimin, fsclk);
+ tzah = num_clocks_min(udma_tzahmin, fsclk);
+ trp = num_clocks_min(udma_trpmin[mode], fsclk);
+ tenv = num_clocks_min(udma_tenvmin, fsclk);
+ if (tenv <= udma_tenvmax[mode]) {
+ ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack));
+ ATAPI_SET_ULTRA_TIM_1(base,
+ (tcyc_tdvs<<8 | tdvs));
+ ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
+ ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
+
+ /* Enable host ATAPI Untra DMA interrupts */
+ ATAPI_SET_INT_MASK(base,
+ ATAPI_GET_INT_MASK(base)
+ | UDMAIN_DONE_MASK
+ | UDMAOUT_DONE_MASK
+ | UDMAIN_TERM_MASK
+ | UDMAOUT_TERM_MASK);
+ }
+ }
+ }
+
+ mode = adev->dma_mode - XFER_MW_DMA_0;
+ if (mode >= 0 && mode <= 2) {
+ pr_debug("set mdmamode: mode=%d\n", mode);
+ /* the most restrictive timing value is tf, the DMACK to
+ * read data released. If one SCLK pulse is longer than
+ * this maximum value then the MDMA mode
+ * cannot be supported at this frequency.
+ */
+ while (mode > 0 && mdma_fsclk[mode] > fsclk)
+ mode--;
+
+ nf = num_clocks_min(tfmin, fsclk);
+ if (nf >= 1) {
+ /* calculate the timing values for Multi-word DMA. */
+
+ /* DIOR/DIOW asserted pulse width */
+ td = num_clocks_min(mdma_tdmin[mode], fsclk);
+
+ /* DIOR negated pulse width */
+ tkw = num_clocks_min(mdma_tkwmin[mode], fsclk);
+
+ /* Cycle Time */
+ n0 = num_clocks_min(mdma_t0min[mode], fsclk);
+
+ /* increase tk until we meed the minimum cycle length */
+ if (tkw + td < n0)
+ tkw = n0 - td;
+
+ /* DIOR negated pulse width - read */
+ tkr = num_clocks_min(mdma_tkrmin[mode], fsclk);
+ /* CS{1:0] valid to DIOR/DIOW */
+ tm = num_clocks_min(mdma_tmmin[mode], fsclk);
+ /* DIOR/DIOW to DMACK hold */
+ teoc = num_clocks_min(mdma_tjmin[mode], fsclk);
+ /* DIOW Data hold */
+ th = num_clocks_min(mdma_thmin[mode], fsclk);
+
+ ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
+ ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
+ ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
+
+ /* Enable host ATAPI Multi DMA interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ | MULTI_DONE_MASK | MULTI_TERM_MASK);
+ SSYNC();
+ }
+ }
+ return;
+}
+
+/**
+ *
+ * Function: wait_complete
+ *
+ * Description: Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+ unsigned short status;
+ unsigned int i = 0;
+
+#define PATA_BF54X_WAIT_TIMEOUT 10000
+
+ for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) {
+ status = ATAPI_GET_INT_STATUS(base) & mask;
+ if (status)
+ break;
+ }
+
+ ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ * Function: write_atapi_register
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+ unsigned long ata_reg, unsigned short value)
+{
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, value);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ * Function: read_atapi_register
+ *
+ *Description: Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+ unsigned long ata_reg)
+{
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ * Function: write_atapi_register_data
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT
+ * interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+ }
+}
+
+/**
+ *
+ * Function: read_atapi_register_data
+ *
+ * Description: Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ buf[i] = ATAPI_GET_DEV_RXBUF(base);
+ }
+}
+
+/**
+ * bfin_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_tf_load().
+ */
+
+static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ write_atapi_register(base, ATA_REG_CTRL, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ write_atapi_register(base, ATA_REG_FEATURE,
+ tf->hob_feature);
+ write_atapi_register(base, ATA_REG_NSECT,
+ tf->hob_nsect);
+ write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
+ write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
+ write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
+ pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+ "0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ write_atapi_register(base, ATA_REG_FEATURE, tf->feature);
+ write_atapi_register(base, ATA_REG_NSECT, tf->nsect);
+ write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
+ write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
+ write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
+ pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ write_atapi_register(base, ATA_REG_DEVICE, tf->device);
+ pr_debug("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * bfin_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ * bfin_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Note: Original code is ata_tf_read().
+ */
+
+static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ tf->command = bfin_check_status(ap);
+ tf->feature = read_atapi_register(base, ATA_REG_ERR);
+ tf->nsect = read_atapi_register(base, ATA_REG_NSECT);
+ tf->lbal = read_atapi_register(base, ATA_REG_LBAL);
+ tf->lbam = read_atapi_register(base, ATA_REG_LBAM);
+ tf->lbah = read_atapi_register(base, ATA_REG_LBAH);
+ tf->device = read_atapi_register(base, ATA_REG_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB);
+ tf->hob_feature = read_atapi_register(base, ATA_REG_ERR);
+ tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT);
+ tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL);
+ tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM);
+ tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH);
+ }
+}
+
+/**
+ * bfin_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_exec_command().
+ */
+
+static void bfin_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ write_atapi_register(base, ATA_REG_CMD, tf->command);
+ ata_pause(ap);
+}
+
+/**
+ * bfin_check_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ * bfin_std_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * Note: Original code is ata_std_dev_select().
+ */
+
+static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ write_atapi_register(base, ATA_REG_DEVICE, tmp);
+ ata_pause(ap);
+}
+
+/**
+ * bfin_bmdma_setup - Set up IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_setup().
+ */
+
+static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ unsigned short config = WDSIZE_16;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma setup\n");
+ /* Program the ATA_CTRL register with dir */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* fill the ATAPI DMA controller */
+ set_dma_config(CH_ATAPI_TX, config);
+ set_dma_x_modify(CH_ATAPI_TX, 2);
+ ata_for_each_sg(sg, qc) {
+ set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
+ set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
+ }
+ } else {
+ config |= WNR;
+ /* fill the ATAPI DMA controller */
+ set_dma_config(CH_ATAPI_RX, config);
+ set_dma_x_modify(CH_ATAPI_RX, 2);
+ ata_for_each_sg(sg, qc) {
+ set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
+ set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
+ }
+ }
+}
+
+/**
+ * bfin_bmdma_start - Start an IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma start\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* start ATAPI DMA controller*/
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /*
+ * On blackfin arch, uncacheable memory is not
+ * allocated with flag GFP_DMA. DMA buffer from
+ * common kenel code should be flushed if WB
+ * data cache is enabled. Otherwise, this loop
+ * is an empty loop and optimized out.
+ */
+ ata_for_each_sg(sg, qc) {
+ flush_dcache_range(sg_dma_address(sg),
+ sg_dma_address(sg) + sg_dma_len(sg));
+ }
+ enable_dma(CH_ATAPI_TX);
+ pr_debug("enable udma write\n");
+
+ /* Send ATA DMA write command */
+ bfin_exec_command(ap, &qc->tf);
+
+ /* set ATA DMA write direction */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+ | XFER_DIR));
+ } else {
+ enable_dma(CH_ATAPI_RX);
+ pr_debug("enable udma read\n");
+
+ /* Send ATA DMA read command */
+ bfin_exec_command(ap, &qc->tf);
+
+ /* set ATA DMA read direction */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+ & ~XFER_DIR));
+ }
+
+ /* Reset all transfer count */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
+
+ /* Set transfer length to buffer len */
+ ata_for_each_sg(sg, qc) {
+ ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
+ }
+
+ /* Enable ATA DMA operation*/
+ if (ap->udma_mask)
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+ | ULTRA_START);
+ else
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+ | MULTI_START);
+}
+
+/**
+ * bfin_bmdma_stop - Stop IDE DMA transfer
+ * @qc: Command we are ending DMA for
+ */
+
+static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma stop\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* stop ATAPI DMA controller*/
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ disable_dma(CH_ATAPI_TX);
+ else {
+ disable_dma(CH_ATAPI_RX);
+ if (ap->hsm_task_state & HSM_ST_LAST) {
+ /*
+ * On blackfin arch, uncacheable memory is not
+ * allocated with flag GFP_DMA. DMA buffer from
+ * common kenel code should be invalidated if
+ * data cache is enabled. Otherwise, this loop
+ * is an empty loop and optimized out.
+ */
+ ata_for_each_sg(sg, qc) {
+ invalidate_dcache_range(
+ sg_dma_address(sg),
+ sg_dma_address(sg)
+ + sg_dma_len(sg));
+ }
+ }
+ }
+}
+
+/**
+ * bfin_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 nsect, lbal;
+
+ bfin_std_dev_select(ap, device);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+ write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * bfin_bus_post_reset - PATA device post reset
+ *
+ * Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ unsigned long timeout;
+
+ /* if device 0 was found in ata_devchk, wait for its
+ * BSY bit to clear
+ */
+ if (dev0)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* if device 1 was found in ata_devchk, wait for
+ * register access, then wait for BSY to clear
+ */
+ timeout = jiffies + ATA_TMOUT_BOOT;
+ while (dev1) {
+ u8 nsect, lbal;
+
+ bfin_std_dev_select(ap, 1);
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev1 = 0;
+ break;
+ }
+ msleep(50); /* give drive a breather */
+ }
+ if (dev1)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* is all this really necessary? */
+ bfin_std_dev_select(ap, 0);
+ if (dev1)
+ bfin_std_dev_select(ap, 1);
+ if (dev0)
+ bfin_std_dev_select(ap, 0);
+}
+
+/**
+ * bfin_bus_softreset - PATA device software reset
+ *
+ * Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+ unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* software reset. causes dev0 to be selected */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready
+ */
+ msleep(150);
+
+ /* Before we perform post reset processing we want to see if
+ * the bus shows 0xFF because the odd clown forgets the D7
+ * pulldown resistor.
+ */
+ if (bfin_check_status(ap) == 0xFF)
+ return 0;
+
+ bfin_bus_post_reset(ap, devmask);
+
+ return 0;
+}
+
+/**
+ * bfin_std_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Note: Original code is ata_std_softreset().
+ */
+
+static int bfin_std_softreset(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline)
+{
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0, err_mask;
+ u8 err;
+
+ if (ata_port_offline(ap)) {
+ classes[0] = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* determine if device 0/1 are present */
+ if (bfin_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && bfin_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ bfin_std_dev_select(ap, 0);
+
+ /* issue bus reset */
+ err_mask = bfin_bus_softreset(ap, devmask);
+ if (err_mask) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_dev_try_classify(ap, 0, &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+ return 0;
+}
+
+/**
+ * bfin_bmdma_status - Read IDE DMA status
+ * @ap: Port associated with this ATA transaction.
+ */
+
+static unsigned char bfin_bmdma_status(struct ata_port *ap)
+{
+ unsigned char host_stat = 0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned short int_status = ATAPI_GET_INT_STATUS(base);
+
+ if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+ host_stat = ATA_DMA_ACTIVE;
+ }
+ if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+ host_stat = ATA_DMA_INTR;
+ }
+ if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
+ host_stat = ATA_DMA_ERR;
+ }
+
+ return host_stat;
+}
+
+/**
+ * bfin_data_xfer - Transfer data by PIO
+ * @adev: device for this I/O
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Note: Original code is ata_data_xfer().
+ */
+
+static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ unsigned int words = buflen >> 1;
+ unsigned short *buf16 = (u16 *) buf;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* Transfer multiple of 2 bytes */
+ if (write_data) {
+ write_atapi_data(base, words, buf16);
+ } else {
+ read_atapi_data(base, words, buf16);
+ }
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned short align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (write_data) {
+ memcpy(align_buf, trailing_buf, 1);
+ write_atapi_data(base, 1, align_buf);
+ } else {
+ read_atapi_data(base, 1, align_buf);
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+/**
+ * bfin_irq_clear - Clear ATAPI interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ pr_debug("in atapi irq clear\n");
+ ATAPI_SET_INT_STATUS(base, 0x1FF);
+}
+
+/**
+ * bfin_irq_on - Enable interrupts on a port.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_on().
+ */
+
+static unsigned char bfin_irq_on(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+ pr_debug("in atapi irq on\n");
+ ap->ctl &= ~ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+ tmp = ata_wait_idle(ap);
+
+ bfin_irq_clear(ap);
+
+ return tmp;
+}
+
+/**
+ * bfin_irq_ack - Acknowledge a device interrupt.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_ack().
+ */
+
+static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+ unsigned char status;
+
+ pr_debug("in atapi irq ack\n");
+ status = ata_busy_wait(ap, bits, 1000);
+ if (status & bits)
+ if (ata_msg_err(ap))
+ dev_err(ap->dev, "abnormal status 0x%X\n", status);
+
+ /* get controller status; clear intr, err bits */
+ ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+ | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+ | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+
+ return bfin_bmdma_status(ap);
+}
+
+/**
+ * bfin_bmdma_freeze - Freeze DMA controller port
+ * @ap: port to freeze
+ *
+ * Note: Original code is ata_bmdma_freeze().
+ */
+
+static void bfin_bmdma_freeze(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ pr_debug("in atapi dma freeze\n");
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+ /* Under certain circumstances, some controllers raise IRQ on
+ * ATA_NIEN manipulation. Also, many controllers fail to mask
+ * previously pending IRQ on ATA_NIEN assertion. Clear it.
+ */
+ ata_chk_status(ap);
+
+ bfin_irq_clear(ap);
+}
+
+/**
+ * bfin_bmdma_thaw - Thaw DMA controller port
+ * @ap: port to thaw
+ *
+ * Note: Original code is ata_bmdma_thaw().
+ */
+
+void bfin_bmdma_thaw(struct ata_port *ap)
+{
+ bfin_check_status(ap);
+ bfin_irq_clear(ap);
+ bfin_irq_on(ap);
+}
+
+/**
+ * bfin_std_postreset - standard postreset callback
+ * @ap: the target ata_port
+ * @classes: classes of attached devices
+ *
+ * Note: Original code is ata_std_postreset().
+ */
+
+static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* re-enable interrupts */
+ bfin_irq_on(ap);
+
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ bfin_std_dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ bfin_std_dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ return;
+ }
+
+ /* set up device control */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+}
+
+/**
+ * bfin_error_handler - Stock error handler for DMA controller
+ * @ap: port to handle error for
+ */
+
+static void bfin_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL,
+ bfin_std_postreset);
+}
+
+static void bfin_port_stop(struct ata_port *ap)
+{
+ pr_debug("in atapi port stop\n");
+ if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+ free_dma(CH_ATAPI_RX);
+ free_dma(CH_ATAPI_TX);
+ }
+}
+
+static int bfin_port_start(struct ata_port *ap)
+{
+ pr_debug("in atapi port start\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return 0;
+
+ if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
+ if (request_dma(CH_ATAPI_TX,
+ "BFIN ATAPI TX DMA") >= 0)
+ return 0;
+
+ free_dma(CH_ATAPI_RX);
+ }
+
+ ap->udma_mask = 0;
+ ap->mwdma_mask = 0;
+ dev_err(ap->dev, "Unable to request ATAPI DMA!"
+ " Continue in PIO mode.\n");
+
+ return 0;
+}
+
+static struct scsi_host_template bfin_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = SG_NONE,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+#endif
+};
+
+static const struct ata_port_operations bfin_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = bfin_set_piomode,
+ .set_dmamode = bfin_set_dmamode,
+
+ .tf_load = bfin_tf_load,
+ .tf_read = bfin_tf_read,
+ .exec_command = bfin_exec_command,
+ .check_status = bfin_check_status,
+ .check_altstatus = bfin_check_altstatus,
+ .dev_select = bfin_std_dev_select,
+
+ .bmdma_setup = bfin_bmdma_setup,
+ .bmdma_start = bfin_bmdma_start,
+ .bmdma_stop = bfin_bmdma_stop,
+ .bmdma_status = bfin_bmdma_status,
+ .data_xfer = bfin_data_xfer,
+
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .freeze = bfin_bmdma_freeze,
+ .thaw = bfin_bmdma_thaw,
+ .error_handler = bfin_error_handler,
+ .post_internal_cmd = bfin_bmdma_stop,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = bfin_irq_clear,
+ .irq_on = bfin_irq_on,
+ .irq_ack = bfin_irq_ack,
+
+ .port_start = bfin_port_start,
+ .port_stop = bfin_port_stop,
+};
+
+static struct ata_port_info bfin_port_info[] = {
+ {
+ .sht = &bfin_sht,
+ .flags = ATA_FLAG_SLAVE_POSS
+ | ATA_FLAG_MMIO
+ | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0,
+#ifdef CONFIG_PATA_BF54X_DMA
+ .udma_mask = ATA_UDMA5,
+#else
+ .udma_mask = 0,
+#endif
+ .port_ops = &bfin_pata_ops,
+ },
+};
+
+/**
+ * bfin_reset_controller - initialize BF54x ATAPI controller.
+ */
+
+static int bfin_reset_controller(struct ata_host *host)
+{
+ void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr;
+ int count;
+ unsigned short status;
+
+ /* Disable all ATAPI interrupts */
+ ATAPI_SET_INT_MASK(base, 0);
+ SSYNC();
+
+ /* Assert the RESET signal 25us*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+ udelay(30);
+
+ /* Negate the RESET signal for 2ms*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+ msleep(2);
+
+ /* Wait on Busy flag to clear */
+ count = 10000000;
+ do {
+ status = read_atapi_register(base, ATA_REG_STATUS);
+ } while (count-- && (status & ATA_BUSY));
+
+ /* Enable only ATAPI Device interrupt */
+ ATAPI_SET_INT_MASK(base, 1);
+ SSYNC();
+
+ return (!count);
+}
+
+/**
+ * atapi_io_port - define atapi peripheral port pins.
+ */
+static unsigned short atapi_io_port[] = {
+ P_ATAPI_RESET,
+ P_ATAPI_DIOR,
+ P_ATAPI_DIOW,
+ P_ATAPI_CS0,
+ P_ATAPI_CS1,
+ P_ATAPI_DMACK,
+ P_ATAPI_DMARQ,
+ P_ATAPI_INTRQ,
+ P_ATAPI_IORDY,
+ 0
+};
+
+/**
+ * bfin_atapi_probe - attach a bfin atapi interface
+ * @pdev: platform device
+ *
+ * Register a bfin atapi interface.
+ *
+ *
+ * Platform devices are expected to contain 2 resources per port:
+ *
+ * - I/O Base (IORESOURCE_IO)
+ * - IRQ (IORESOURCE_IRQ)
+ *
+ */
+static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+{
+ int board_idx = 0;
+ struct resource *res;
+ struct ata_host *host;
+ const struct ata_port_info *ppi[] =
+ { &bfin_port_info[board_idx], NULL };
+
+ /*
+ * Simple resource validation ..
+ */
+ if (unlikely(pdev->num_resources != 2)) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Get the register base first
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ return -EINVAL;
+
+ /*
+ * Now that that's out of the way, wire up the port..
+ */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
+ if (!host)
+ return -ENOMEM;
+
+ host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
+
+ if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
+ dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+ return -EFAULT;
+ }
+
+ if (bfin_reset_controller(host)) {
+ peripheral_free_list(atapi_io_port);
+ dev_err(&pdev->dev, "Fail to reset ATAPI device\n");
+ return -EFAULT;
+ }
+
+ if (ata_host_activate(host, platform_get_irq(pdev, 0),
+ 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;
+ }
+
+ return 0;
+}
+
+/**
+ * bfin_atapi_remove - unplug a bfin atapi interface
+ * @pdev: platform device
+ *
+ * A bfin atapi device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_detach(host);
+
+ peripheral_free_list(atapi_io_port);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+int bfin_atapi_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+static struct platform_driver bfin_atapi_driver = {
+ .probe = bfin_atapi_probe,
+ .remove = __devexit_p(bfin_atapi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .suspend = bfin_atapi_suspend,
+ .resume = bfin_atapi_resume,
+#endif
+ },
+};
+
+static int __init bfin_atapi_init(void)
+{
+ pr_info("register bfin atapi driver\n");
+ return platform_driver_register(&bfin_atapi_driver);
+}
+
+static void __exit bfin_atapi_exit(void)
+{
+ platform_driver_unregister(&bfin_atapi_driver);
+}
+
+module_init(bfin_atapi_init);
+module_exit(bfin_atapi_exit);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 0feb5ae8c486..43d198f90968 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -153,7 +153,7 @@ static int cmd640_port_start(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct cmd640_reg *timing;
- int ret = ata_port_start(ap);
+ int ret = ata_sff_port_start(ap);
if (ret < 0)
return ret;
@@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = {
};
static struct ata_port_operations cmd640_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd640_set_piomode,
.mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
@@ -213,7 +212,6 @@ static struct ata_port_operations cmd640_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = cmd640_port_start,
};
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index dc443e7dc37c..9e412c26b2a3 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -31,7 +31,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.3"
+#define DRV_VERSION "0.2.5"
/*
* CMD64x specific registers definition.
@@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap)
}
/**
- * cmd64x_set_piomode - set initial PIO mode data
+ * cmd64x_set_piomode - set PIO and MWDMA timing
* @ap: ATA interface
* @adev: ATA device
+ * @mode: mode
*
- * Called to do the PIO mode setup.
+ * Called to do the PIO and MWDMA mode setup.
*/
-static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct ata_timing t;
@@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
int arttim = arttim_port[ap->port_no][adev->devno];
int drwtim = drwtim_port[ap->port_no][adev->devno];
-
- if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ /* ata_timing_compute is smart and will produce timings for MWDMA
+ that don't violate the drives PIO capabilities. */
+ if (ata_timing_compute(adev, mode, &t, T, 0) < 0) {
printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
return;
}
@@ -168,6 +170,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
/**
+ * cmd64x_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Used when configuring the devices ot set the PIO timings. All the
+ * actual work is done by the PIO/MWDMA setting helper
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ cmd64x_set_timing(ap, adev, adev->pio_mode);
+}
+
+/**
* cmd64x_set_dmamode - set initial DMA mode data
* @ap: ATA interface
* @adev: ATA device
@@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
static const u8 udma_data[] = {
0x30, 0x20, 0x10, 0x20, 0x10, 0x00
};
- static const u8 mwdma_data[] = {
- 0x30, 0x20, 0x10
- };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 regU, regD;
@@ -208,8 +221,10 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
regU |= 1 << adev->devno; /* UDMA on */
if (adev->dma_mode > 2) /* 15nS timing */
regU |= 4 << adev->devno;
- } else
- regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+ } else {
+ regU &= ~ (1 << adev->devno); /* UDMA off */
+ cmd64x_set_timing(ap, adev, adev->dma_mode);
+ }
regD |= 0x20 << adev->devno;
@@ -269,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = {
};
static struct ata_port_operations cmd64x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -298,13 +312,11 @@ static struct ata_port_operations cmd64x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static struct ata_port_operations cmd646r1_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -333,13 +345,11 @@ static struct ata_port_operations cmd646r1_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static struct ata_port_operations cmd648_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -368,7 +378,6 @@ static struct ata_port_operations cmd648_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -397,7 +406,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA1,
+ .udma_mask = ATA_UDMA2,
.port_ops = &cmd64x_port_ops
},
{ /* CMD 646 rev 1 */
@@ -412,7 +421,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA2,
+ .udma_mask = ATA_UDMA4,
.port_ops = &cmd648_port_ops
},
{ /* CMD 649 */
@@ -420,7 +429,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA3,
+ .udma_mask = ATA_UDMA5,
.port_ops = &cmd648_port_ops
}
};
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 6bf037d82b5a..33f7f0843f4f 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cs5520"
-#define DRV_VERSION "0.6.5"
+#define DRV_VERSION "0.6.6"
struct pio_clocks
{
@@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = {
};
static struct ata_port_operations cs5520_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5520_set_piomode,
.set_dmamode = cs5520_set_dmamode,
@@ -184,13 +183,14 @@ static struct ata_port_operations cs5520_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
+ static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
struct ata_port_info pi = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
@@ -244,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
}
/* Map IO ports and initialize host accordingly */
- iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
- iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
- iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
- iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+ iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1);
+ iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1);
iomap[4] = pcim_iomap(pdev, 2, 0);
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
@@ -260,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ioaddr->bmdma_addr = iomap[4];
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[0],
+ "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]);
+ ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma");
+
ioaddr = &host->ports[1]->ioaddr;
ioaddr->cmd_addr = iomap[2];
ioaddr->ctl_addr = iomap[3];
@@ -267,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ioaddr->bmdma_addr = iomap[4] + 8;
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[1],
+ "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]);
+ ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma");
+
/* activate the host */
pci_set_master(pdev);
rc = ata_host_start(host);
@@ -275,7 +283,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
for (i = 0; i < 2; i++) {
static const int irq[] = { 14, 15 };
- struct ata_port *ap = host->ports[0];
+ struct ata_port *ap = host->ports[i];
if (ata_port_is_dummy(ap))
continue;
@@ -285,33 +293,12 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
if (rc)
return rc;
- if (i == 0)
- host->irq = irq[0];
- else
- host->irq2 = irq[1];
+ ata_port_desc(ap, "irq %d", irq[i]);
}
return ata_host_register(host, &cs5520_sht);
}
-/**
- * cs5520_remove_one - device unload
- * @pdev: PCI device being removed
- *
- * Handle an unplug/unload event for a PCI device. Unload the
- * PCI driver but do not use the default handler as we manage
- * resources ourself and *MUST NOT* disable the device as it has
- * other functions.
- */
-
-static void __devexit cs5520_remove_one(struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
-
- ata_host_detach(host);
-}
-
#ifdef CONFIG_PM
/**
* cs5520_reinit_one - device resume
@@ -368,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = {
.name = DRV_NAME,
.id_table = pata_cs5520,
.probe = cs5520_init_one,
- .remove = cs5520_remove_one,
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
.suspend = cs5520_pci_device_suspend,
.resume = cs5520_reinit_one,
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 68f150a1e2f4..57e827e4109e 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -35,7 +35,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_cs5530"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.4"
static void __iomem *cs5530_port_base(struct ata_port *ap)
{
@@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = {
};
static struct ata_port_operations cs5530_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5530_set_piomode,
.set_dmamode = cs5530_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -209,12 +208,11 @@ static struct ata_port_operations cs5530_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
-static struct dmi_system_id palmax_dmi_table[] = {
+static const struct dmi_system_id palmax_dmi_table[] = {
{
.ident = "Palmax PD1100",
.matches = {
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 360b6f32e17e..3578593a882b 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = {
};
static struct ata_port_operations cs5535_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5535_set_piomode,
.set_dmamode = cs5535_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -206,9 +205,8 @@ static struct ata_port_operations cs5535_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 6cbc8778bf4f..fc5f9c4e5d87 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = {
};
static struct ata_port_operations cy82c693_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cy82c693_set_piomode,
.set_dmamode = cy82c693_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -158,9 +157,8 @@ static struct ata_port_operations cy82c693_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index c8ba59c56114..043dcd35106c 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -26,25 +26,26 @@
/**
* efar_pre_reset - Enable bits
- * @ap: Port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Perform cable detection for the EFAR ATA interface. This is
* different to the PIIX arrangement
*/
-static int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int efar_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits efar_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
{ 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -250,7 +251,6 @@ static struct scsi_host_template efar_sht = {
};
static const struct ata_port_operations efar_ops = {
- .port_disable = ata_port_disable,
.set_piomode = efar_set_piomode,
.set_dmamode = efar_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -278,9 +278,8 @@ static const struct ata_port_operations efar_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 6f7d34ad19ef..0713872cf65c 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = {
*/
static struct ata_port_operations hpt366_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt366_set_piomode,
.set_dmamode = hpt366_set_dmamode,
.mode_filter = hpt366_filter,
@@ -342,9 +341,8 @@ static struct ata_port_operations hpt366_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index b0af65aadde3..e61cb1fd57b2 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -8,12 +8,10 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
- * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
*
* TODO
- * PLL mode
- * Look into engine reset on timeout errors. Should not be
- * required.
+ * Look into engine reset on timeout errors. Should not be required.
*/
#include <linux/kernel.h>
@@ -26,7 +24,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.6.6"
+#define DRV_VERSION "0.6.9"
struct hpt_clock {
u8 xfer_speed;
@@ -306,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
/**
* hpt37x_pre_reset - reset the hpt37x bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 370/372 and 374 func 0
*/
-static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
{
u8 scr2, ata66;
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
@@ -339,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -354,7 +353,7 @@ static void hpt37x_error_handler(struct ata_port *ap)
ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
}
-static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
@@ -362,6 +361,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
};
u16 mcr3, mcr6;
u8 ata66;
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
@@ -389,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -644,7 +644,6 @@ static struct scsi_host_template hpt37x_sht = {
*/
static struct ata_port_operations hpt370_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.mode_filter = hpt370_filter,
@@ -673,9 +672,8 @@ static struct ata_port_operations hpt370_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -683,7 +681,6 @@ static struct ata_port_operations hpt370_port_ops = {
*/
static struct ata_port_operations hpt370a_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.mode_filter = hpt370a_filter,
@@ -712,9 +709,8 @@ static struct ata_port_operations hpt370a_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -723,7 +719,6 @@ static struct ata_port_operations hpt370a_port_ops = {
*/
static struct ata_port_operations hpt372_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -752,9 +747,8 @@ static struct ata_port_operations hpt372_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -763,7 +757,6 @@ static struct ata_port_operations hpt372_port_ops = {
*/
static struct ata_port_operations hpt374_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -792,9 +785,8 @@ static struct ata_port_operations hpt374_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -1092,9 +1084,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
int dpll, adjust;
/* Compute DPLL */
- dpll = 2;
- if (port->udma_mask & 0xE0)
- dpll = 3;
+ dpll = (port->udma_mask & 0xC0) ? 3 : 2;
f_low = (MHz[clock_slot] * 48) / MHz[dpll];
f_high = f_low + 2;
@@ -1103,20 +1093,20 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* Select the DPLL clock. */
pci_write_config_byte(dev, 0x5b, 0x21);
- pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
for(adjust = 0; adjust < 8; adjust++) {
if (hpt37x_calibrate_dpll(dev))
break;
/* See if it'll settle at a fractionally different clock */
- if ((adjust & 3) == 3) {
- f_low --;
- f_high ++;
- }
- pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+ if (adjust & 1)
+ f_low -= adjust >> 1;
+ else
+ f_high += adjust >> 1;
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
}
if (adjust == 8) {
- printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
+ printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
return -ENODEV;
}
if (dpll == 3)
@@ -1124,7 +1114,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
else
private_data = (void *)hpt37x_timings_50;
- printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[dpll]);
+ printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using %dMHz DPLL.\n",
+ MHz[clock_slot], MHz[dpll]);
} else {
private_data = (void *)chip_table->clocks[clock_slot];
/*
@@ -1137,7 +1128,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
port = &info_hpt370_33;
if (clock_slot < 2 && port == &info_hpt370a)
port = &info_hpt370a_33;
- printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
+ printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n",
+ chip_table->name, MHz[clock_slot]);
}
/* Now kick off ATA set up */
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index aa29cde09f8b..9f1c084f846f 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,7 +8,7 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
- * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
*
*
* TODO
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.3"
+#define DRV_VERSION "0.3.4"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap)
/**
* hpt3x2n_pre_reset - reset the hpt3x2n bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 3x2n series controllers.
* Reset the hardware and state machine,
*/
-static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Reset the state machine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -360,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = {
*/
static struct ata_port_operations hpt3x2n_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt3x2n_set_piomode,
.set_dmamode = hpt3x2n_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -390,9 +390,8 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -579,10 +578,12 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
}
if (adjust == 8) {
- printk(KERN_WARNING "hpt3x2n: DPLL did not stabilize.\n");
+ printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n");
return -ENODEV;
}
+ printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n",
+ pci_mhz);
/* Set our private data up. We only need a few flags so we use
it directly */
port.private_data = NULL;
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index be0f05efac6d..cb8bdb6887de 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = {
};
static struct ata_port_operations hpt3x3_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt3x3_set_piomode,
#if defined(CONFIG_PATA_HPT3X3_DMA)
.set_dmamode = hpt3x3_set_dmamode,
@@ -153,9 +152,8 @@ static struct ata_port_operations hpt3x3_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -239,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
base = host->iomap[4]; /* Bus mastering base */
for (i = 0; i < host->n_ports; i++) {
- struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->cmd_addr = base + offset_cmd[i];
ioaddr->altstatus_addr =
@@ -247,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ioaddr->scr_addr = NULL;
ata_std_ports(ioaddr);
ioaddr->bmdma_addr = base + 8 * i;
+
+ ata_port_pbar_desc(ap, 4, -1, "ioport");
+ ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
}
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 321d98b0bed2..be30923566c5 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -70,6 +70,8 @@ struct pata_icside_info {
unsigned int mwdma_mask;
unsigned int nr_ports;
const struct portinfo *port[2];
+ unsigned long raw_base;
+ unsigned long raw_ioc_base;
};
#define ICS_TYPE_A3IN 0
@@ -330,17 +332,12 @@ static void ata_dummy_noret(struct ata_port *port)
{
}
-/*
- * We need to shut down unused ports to prevent spurious interrupts.
- * FIXME: the libata core doesn't call this function for PATA interfaces.
- */
-static void pata_icside_port_disable(struct ata_port *ap)
+static void pata_icside_postreset(struct ata_port *ap, unsigned int *classes)
{
struct pata_icside_state *state = ap->host->private_data;
- ata_port_printk(ap, KERN_ERR, "disabling icside port\n");
-
- ata_port_disable(ap);
+ if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)
+ return ata_std_postreset(ap, classes);
state->port[ap->port_no].disabled = 1;
@@ -356,26 +353,13 @@ static void pata_icside_port_disable(struct ata_port *ap)
}
}
-static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+static void pata_icside_error_handler(struct ata_port *ap)
{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
- __FUNCTION__, status);
-
- return status;
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
+ pata_icside_postreset);
}
static struct ata_port_operations pata_icside_port_ops = {
- .port_disable = pata_icside_port_disable,
-
.set_dmamode = pata_icside_set_dmamode,
.tf_load = ata_tf_load,
@@ -397,12 +381,11 @@ static struct ata_port_operations pata_icside_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
+ .error_handler = pata_icside_error_handler,
.post_internal_cmd = pata_icside_bmdma_stop,
.irq_clear = ata_dummy_noret,
.irq_on = ata_irq_on,
- .irq_ack = pata_icside_irq_ack,
.port_start = pata_icside_port_start,
@@ -411,9 +394,10 @@ static struct ata_port_operations pata_icside_port_ops = {
};
static void __devinit
-pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
+pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
const struct portinfo *info)
{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
void __iomem *cmd = base + info->dataoffset;
ioaddr->cmd_addr = cmd;
@@ -430,6 +414,13 @@ pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
ioaddr->ctl_addr = base + info->ctrloffset;
ioaddr->altstatus_addr = ioaddr->ctl_addr;
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+ info->raw_base + info->dataoffset,
+ info->raw_base + info->ctrloffset);
+
+ if (info->raw_ioc_base)
+ ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
}
static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
@@ -450,6 +441,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
info->nr_ports = 1;
info->port[0] = &pata_icside_portinfo_v5;
+ info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC);
+
return 0;
}
@@ -484,19 +477,15 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
state->port[0].port_sel = sel;
state->port[1].port_sel = sel | 1;
- /*
- * FIXME: work around libata's aversion to calling port_disable.
- * This permanently disables interrupts on port 0 - bad luck if
- * you have a drive on that port.
- */
- state->port[0].disabled = 1;
-
info->base = easi_base;
info->irqops = &pata_icside_ops_arcin_v6;
info->nr_ports = 2;
info->port[0] = &pata_icside_portinfo_v6_1;
info->port[1] = &pata_icside_portinfo_v6_2;
+ info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
+ info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+
return icside_dma_init(info);
}
@@ -533,7 +522,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ops = &pata_icside_port_ops;
- pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
+ pata_icside_setup_ioaddr(ap, info->base, info->port[i]);
}
return ata_host_activate(host, ec->irq, ata_interrupt, 0,
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 5525518204e6..88ab0e1d353f 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -17,7 +17,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_isapnp"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.2.2"
static struct scsi_host_template isapnp_sht = {
.module = THIS_MODULE,
@@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = {
};
static struct ata_port_operations isapnp_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -58,9 +57,8 @@ static struct ata_port_operations isapnp_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -112,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pnp_port_start(idev, 0),
+ (unsigned long long)pnp_port_start(idev, 1));
+
/* activate */
return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
&isapnp_sht);
@@ -139,6 +141,8 @@ static struct pnp_device_id isapnp_devices[] = {
{.id = ""}
};
+MODULE_DEVICE_TABLE(pnp, isapnp_devices);
+
static struct pnp_driver isapnp_driver = {
.name = DRV_NAME,
.id_table = isapnp_devices,
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index b8af55e89156..1eda821e5e39 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -23,23 +23,24 @@
/**
* it8213_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* Filter out ports by the enable bits before doing the normal reset
* and probe.
*/
-static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int it8213_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits it8213_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -260,7 +261,6 @@ static struct scsi_host_template it8213_sht = {
};
static const struct ata_port_operations it8213_ops = {
- .port_disable = ata_port_disable,
.set_piomode = it8213_set_piomode,
.set_dmamode = it8213_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -288,9 +288,8 @@ static const struct ata_port_operations it8213_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 430673be1df7..988ef736b936 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@
#define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.7"
+#define DRV_VERSION "0.3.8"
struct it821x_dev
{
@@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap,
{
struct it821x_dev *itdev = ap->private_data;
if (itdev && device != itdev->last_device) {
- struct ata_device *adev = &ap->device[device];
+ struct ata_device *adev = &ap->link.device[device];
it821x_program(ap, adev, itdev->pio[adev->devno]);
itdev->last_device = device;
}
@@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
/**
* it821x_smart_set_mode - mode setting
- * @ap: interface to set up
+ * @link: interface to set up
* @unused: device that failed (error only)
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -459,12 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
* and respect them.
*/
-static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
@@ -533,6 +532,10 @@ static int it821x_check_atapi_dma(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct it821x_dev *itdev = ap->private_data;
+ /* Only use dma for transfers to/from the media. */
+ if (qc->nbytes < 2048)
+ return -EOPNOTSUPP;
+
/* No ATAPI DMA in smart mode */
if (itdev->smart)
return -EOPNOTSUPP;
@@ -560,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap)
struct it821x_dev *itdev;
u8 conf;
- int ret = ata_port_start(ap);
+ int ret = ata_sff_port_start(ap);
if (ret < 0)
return ret;
@@ -587,7 +590,7 @@ static int it821x_port_start(struct ata_port *ap)
itdev->want[1][1] = ATA_ANY;
itdev->last_device = -1;
- if (pdev->revision == 0x11) {
+ if (pdev->revision == 0x10) {
itdev->timing10 = 1;
/* Need to disable ATAPI DMA for this case */
if (!itdev->smart)
@@ -617,7 +620,6 @@ static struct scsi_host_template it821x_sht = {
static struct ata_port_operations it821x_smart_port_ops = {
.set_mode = it821x_smart_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.mode_filter = ata_pci_default_filter,
@@ -647,13 +649,11 @@ static struct ata_port_operations it821x_smart_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
};
static struct ata_port_operations it821x_passthru_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = it821x_passthru_set_piomode,
.set_dmamode = it821x_passthru_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -684,7 +684,6 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_handler = ata_interrupt,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
};
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 4ca7fd6118d5..fcd532afbf2e 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -26,12 +26,11 @@
#define DRV_NAME "pata_ixp4xx_cf"
#define DRV_VERSION "0.2"
-static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
+static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
dev->pio_mode = XFER_PIO_0;
@@ -49,7 +48,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
void __iomem *mmio = ap->ioaddr.data_addr;
struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
@@ -108,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = {
.set_mode = ixp4xx_set_mode,
.mode_filter = ata_pci_default_filter,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -128,14 +126,17 @@ static struct ata_port_operations ixp4xx_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.port_start = ata_port_start,
};
static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
- struct ixp4xx_pata_data *data)
+ struct ixp4xx_pata_data *data,
+ unsigned long raw_cs0, unsigned long raw_cs1)
{
+ unsigned long raw_cmd = raw_cs0;
+ unsigned long raw_ctl = raw_cs1 + 0x06;
+
ioaddr->cmd_addr = data->cs0;
ioaddr->altstatus_addr = data->cs1 + 0x06;
ioaddr->ctl_addr = data->cs1 + 0x06;
@@ -161,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
*(unsigned long *)&ioaddr->device_addr ^= 0x03;
*(unsigned long *)&ioaddr->status_addr ^= 0x03;
*(unsigned long *)&ioaddr->command_addr ^= 0x03;
+
+ raw_cmd ^= 0x03;
+ raw_ctl ^= 0x03;
#endif
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
}
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
@@ -189,6 +195,9 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
+ if (!data->cs0 || !data->cs1)
+ return -ENOMEM;
+
irq = platform_get_irq(pdev, 0);
if (irq)
set_irq_type(irq, IRQT_RISING);
@@ -203,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
ap->pio_mask = 0x1f; /* PIO4 */
ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
- ixp4xx_setup_port(&ap->ioaddr, data);
+ ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 4d67f238eee2..225a7223a726 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -29,7 +29,7 @@ typedef enum {
/**
* jmicron_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
@@ -39,9 +39,9 @@ typedef enum {
* and setup here. We assume that has been done by init_one and the
* BIOS.
*/
-
-static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 control;
u32 control5;
@@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
ap->cbl = ATA_CBL_SATA;
break;
}
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = {
};
static const struct ata_port_operations jmicron_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -168,7 +166,6 @@ static const struct ata_port_operations jmicron_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
@@ -207,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
}
static const struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 },
-
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index edffc25d2d3f..7bed8d806381 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
/**
* legacy_set_mode - mode setting
- * @ap: IDE interface
+ * @link: IDE link
* @unused: Device that failed when error is returned
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -107,12 +107,11 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
* expand on this as per hdparm in the base kernel.
*/
-static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->pio_mode = XFER_PIO_0;
@@ -151,7 +150,6 @@ static struct scsi_host_template legacy_sht = {
*/
static struct ata_port_operations simple_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -172,7 +170,6 @@ static struct ata_port_operations simple_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -180,7 +177,6 @@ static struct ata_port_operations simple_port_ops = {
static struct ata_port_operations legacy_port_ops = {
.set_mode = legacy_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -201,7 +197,6 @@ static struct ata_port_operations legacy_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -256,7 +251,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
unsigned long flags;
@@ -296,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
static struct ata_port_operations pdc20230_port_ops = {
.set_piomode = pdc20230_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -317,7 +311,6 @@ static struct ata_port_operations pdc20230_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -352,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
static struct ata_port_operations ht6560a_port_ops = {
.set_piomode = ht6560a_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -373,7 +365,6 @@ static struct ata_port_operations ht6560a_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -419,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
static struct ata_port_operations ht6560b_port_ops = {
.set_piomode = ht6560b_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -440,7 +430,6 @@ static struct ata_port_operations ht6560b_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -541,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
static struct ata_port_operations opti82c611a_port_ops = {
.set_piomode = opti82c611a_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -562,7 +550,6 @@ static struct ata_port_operations opti82c611a_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -675,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
static struct ata_port_operations opti82c46x_port_ops = {
.set_piomode = opti82c46x_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -696,7 +682,6 @@ static struct ata_port_operations opti82c46x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -814,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
ata_std_ports(&ap->ioaddr);
ap->private_data = ld;
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+
ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
if (ret)
goto fail;
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 87594c04d3a3..9afc8a32b226 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -24,14 +24,15 @@
/**
* marvell_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
*/
-static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 devices;
void __iomem *barp;
@@ -44,17 +45,17 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
return -ENOMEM;
printk("BAR5:");
for(i = 0; i <= 0x0F; i++)
- printk("%02X:%02X ", i, readb(barp + i));
+ printk("%02X:%02X ", i, ioread8(barp + i));
printk("\n");
- devices = readl(barp + 0x0C);
+ devices = ioread32(barp + 0x0C);
pci_iounmap(pdev, barp);
if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
(!(devices & 0x10))) /* PATA enable ? */
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static int marvell_cable_detect(struct ata_port *ap)
@@ -110,8 +111,6 @@ static struct scsi_host_template marvell_sht = {
};
static const struct ata_port_operations marvell_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -138,10 +137,9 @@ static const struct ata_port_operations marvell_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
@@ -192,6 +190,8 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
static const struct pci_device_id marvell_pci_tbl[] = {
{ PCI_DEVICE(0x11AB, 0x6101), },
+ { PCI_DEVICE(0x11AB, 0x6121), },
+ { PCI_DEVICE(0x11AB, 0x6123), },
{ PCI_DEVICE(0x11AB, 0x6145), },
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 182e83c9047b..412140f02853 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -24,7 +24,7 @@
#define DRV_NAME "mpc52xx_ata"
-#define DRV_VERSION "0.1.0ac2"
+#define DRV_VERSION "0.1.2"
/* Private structures used by the driver */
@@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = {
};
static struct ata_port_operations mpc52xx_ata_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = mpc52xx_ata_set_piomode,
.dev_select = mpc52xx_ata_dev_select,
.tf_load = ata_tf_load,
@@ -299,12 +298,12 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
+ unsigned long raw_ata_regs)
{
struct ata_host *host;
struct ata_port *ap;
@@ -338,6 +337,8 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
aio->status_addr = &priv->ata_regs->tf_command;
aio->command_addr = &priv->ata_regs->tf_command;
+ ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
+
/* activate host */
return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
&mpc52xx_ata_sht);
@@ -434,7 +435,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
}
/* Register ourselves to libata */
- rv = mpc52xx_ata_init_one(&op->dev, priv);
+ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
if (rv) {
printk(KERN_ERR DRV_NAME ": "
"Error while registering to ATA layer\n");
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4ea42838297e..d5483087a3fa 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -46,15 +46,16 @@ enum {
SECONDARY = (1 << 14)
};
-static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -168,7 +169,6 @@ static struct scsi_host_template mpiix_sht = {
};
static struct ata_port_operations mpiix_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = mpiix_set_piomode,
.tf_load = ata_tf_load,
@@ -189,9 +189,8 @@ static struct ata_port_operations mpiix_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -202,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
- int irq;
+ int cmd, ctl, irq;
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -210,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
host = ata_host_alloc(&dev->dev, 1);
if (!host)
return -ENOMEM;
+ ap = host->ports[0];
/* MPIIX has many functions which can be turned on or off according
to other devices present. Make sure IDE is enabled before we try
@@ -221,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* See if it's primary or secondary channel... */
if (!(idetim & SECONDARY)) {
+ cmd = 0x1F0;
+ ctl = 0x3F6;
irq = 14;
- cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
- ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
} else {
+ cmd = 0x170;
+ ctl = 0x376;
irq = 15;
- cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
- ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
}
+ cmd_addr = devm_ioport_map(&dev->dev, cmd, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, ctl, 1);
if (!cmd_addr || !ctl_addr)
return -ENOMEM;
+ ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl);
+
/* We do our own plumbing to avoid leaking special cases for whacko
ancient hardware into the core code. There are two issues to
worry about. #1 The chip is a bridge so if in legacy mode and
without BARs set fools the setup. #2 If you pci_disable_device
the MPIIX your box goes castors up */
- ap = host->ports[0];
ap->ops = &mpiix_port_ops;
ap->pio_mask = 0x1F;
ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 40eb574828bf..25c922abd554 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = {
};
static const struct ata_port_operations netcell_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -68,10 +66,9 @@ static const struct ata_port_operations netcell_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 2f5d714ebfc4..6e8e55745b7b 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -32,14 +32,15 @@
/**
* ns87410_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Check enabled ports
*/
-static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits ns87410_enable_bits[] = {
{ 0x43, 1, 0x08, 0x08 },
@@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -161,7 +162,6 @@ static struct scsi_host_template ns87410_sht = {
};
static struct ata_port_operations ns87410_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ns87410_set_piomode,
.tf_load = ata_tf_load,
@@ -184,9 +184,8 @@ static struct ata_port_operations ns87410_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
new file mode 100644
index 000000000000..bb97ef583f9b
--- /dev/null
+++ b/drivers/ata/pata_ns87415.c
@@ -0,0 +1,467 @@
+/*
+ * pata_ns87415.c - NS87415 (non PARISC) PATA
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * This is a fairly generic MWDMA controller. It has some limitations
+ * as it requires timing reloads on PIO/DMA transitions but it is otherwise
+ * fairly well designed.
+ *
+ * This driver assumes the firmware has left the chip in a valid ST506
+ * compliant state, either legacy IRQ 14/15 or native INTA shared. You
+ * may need to add platform code if your system fails to do this.
+ *
+ * The same cell appears in the 87560 controller used by some PARISC
+ * systems. This has its own special mountain of errata.
+ *
+ * TODO:
+ * Test PARISC SuperIO
+ * Get someone to test on SPARC
+ * Implement lazy pio/dma switching for better performance
+ * 8bit shared timing.
+ * See if we need to kill the FIFO for ATAPI
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_ns87415"
+#define DRV_VERSION "0.0.1"
+
+/**
+ * ns87415_set_mode - Initialize host controller mode timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device whose timings we are configuring
+ * @mode: Mode to set
+ *
+ * Program the mode registers for this controller, channel and
+ * device. Because the chip is quite an old design we have to do this
+ * for PIO/DMA switches.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ int unit = 2 * ap->port_no + adev->devno;
+ int timing = 0x44 + 2 * unit;
+ unsigned long T = 1000000000 / 33333; /* PCI clocks */
+ struct ata_timing t;
+ u16 clocking;
+ u8 iordy;
+ u8 status;
+
+ /* Timing register format is 17 - low nybble read timing with
+ the high nybble being 16 - x for recovery time in PCI clocks */
+
+ ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
+
+ clocking = 17 - FIT(t.active, 2, 17);
+ clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ /* Use the same timing for read and write bytes */
+ clocking |= (clocking << 8);
+ pci_write_config_word(dev, timing, clocking);
+
+ /* Set the IORDY enable versus DMA enable on or off properly */
+ pci_read_config_byte(dev, 0x42, &iordy);
+ iordy &= ~(1 << (4 + unit));
+ if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev))
+ iordy |= (1 << (4 + unit));
+
+ /* Paranoia: We shouldn't ever get here with busy write buffers
+ but if so wait */
+
+ pci_read_config_byte(dev, 0x43, &status);
+ while (status & 0x03) {
+ udelay(1);
+ pci_read_config_byte(dev, 0x43, &status);
+ }
+ /* Flip the IORDY/DMA bits now we are sure the write buffers are
+ clear */
+ pci_write_config_byte(dev, 0x42, iordy);
+
+ /* TODO: Set byte 54 command timing to the best 8bit
+ mode shared by all four devices */
+}
+
+/**
+ * ns87415_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ ns87415_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * ns87415_bmdma_setup - Set up DMA
+ * @qc: Command block
+ *
+ * Set up for bus masterng DMA. We have to do this ourselves
+ * rather than use the helper due to a chip erratum
+ */
+
+static void ns87415_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ /* Due to an erratum we need to write these bits to the wrong
+ place - which does save us an I/O bizarrely */
+ dmactl |= ATA_DMA_INTR | ATA_DMA_ERR;
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * ns87415_bmdma_start - Begin DMA transfer
+ * @qc: Command block
+ *
+ * Switch the timings for the chip and set up for a DMA transfer
+ * before the DMA burst begins.
+ *
+ * FIXME: We should do lazy switching on bmdma_start versus
+ * ata_pio_data_xfer for better performance.
+ */
+
+static void ns87415_bmdma_start(struct ata_queued_cmd *qc)
+{
+ ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * ns87415_bmdma_stop - End DMA transfer
+ * @qc: Command block
+ *
+ * End DMA mode and switch the controller back into PIO mode
+ */
+
+static void ns87415_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+ ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+/**
+ * ns87415_bmdma_irq_clear - Clear interrupt
+ * @ap: Channel to clear
+ *
+ * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the
+ * error bits) are reset by writing to register 00 or 08.
+ */
+
+static void ns87415_bmdma_irq_clear(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
+ return;
+ iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR),
+ mmio + ATA_DMA_CMD);
+}
+
+/**
+ * ns87415_check_atapi_dma - ATAPI DMA filter
+ * @qc: Command block
+ *
+ * Disable ATAPI DMA (for now). We may be able to do DMA if we
+ * kill the prefetching. This isn't clear.
+ */
+
+static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return -EOPNOTSUPP;
+}
+
+#if defined(CONFIG_SUPERIO)
+
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ *
+ * Workarounds taken from drivers/ide/pci/ns87415.c
+ */
+
+#include <asm/superio.h>
+
+/**
+ * ns87560_read_buggy - workaround buggy Super I/O chip
+ * @port: Port to read
+ *
+ * Work around chipset problems in the 87560 SuperIO chip
+ */
+
+static u8 ns87560_read_buggy(void __iomem *port)
+{
+ u8 tmp;
+ int retries = SUPERIO_IDE_MAX_RETRIES;
+ do {
+ tmp = ioread8(port);
+ if (tmp != 0)
+ return tmp;
+ udelay(50);
+ } while(retries-- > 0);
+ return tmp;
+}
+
+/**
+ * ns87560_check_status
+ * @ap: channel to check
+ *
+ * Return the status of the channel working around the
+ * 87560 flaws.
+ */
+
+static u8 ns87560_check_status(struct ata_port *ap)
+{
+ return ns87560_read_buggy(ap->ioaddr.status_addr);
+}
+
+/**
+ * ns87560_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf. Work around the 87560 bugs.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ns87560_check_status(ap);
+ tf->feature = ioread8(ioaddr->error_addr);
+ tf->nsect = ioread8(ioaddr->nsect_addr);
+ tf->lbal = ioread8(ioaddr->lbal_addr);
+ tf->lbam = ioread8(ioaddr->lbam_addr);
+ tf->lbah = ioread8(ioaddr->lbah_addr);
+ tf->device = ns87560_read_buggy(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread8(ioaddr->error_addr);
+ tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/**
+ * ns87560_bmdma_status
+ * @ap: channel to check
+ *
+ * Return the DMA status of the channel working around the
+ * 87560 flaws.
+ */
+
+static u8 ns87560_bmdma_status(struct ata_port *ap)
+{
+ return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
+
+static const struct ata_port_operations ns87560_pata_ops = {
+ .set_piomode = ns87415_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ns87560_tf_read,
+ .check_status = ns87560_check_status,
+ .check_atapi_dma = ns87415_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = ns87415_bmdma_setup,
+ .bmdma_start = ns87415_bmdma_start,
+ .bmdma_stop = ns87415_bmdma_stop,
+ .bmdma_status = ns87560_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ns87415_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+#endif /* 87560 SuperIO Support */
+
+
+static const struct ata_port_operations ns87415_pata_ops = {
+ .set_piomode = ns87415_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .check_atapi_dma = ns87415_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = ns87415_bmdma_setup,
+ .bmdma_start = ns87415_bmdma_start,
+ .bmdma_stop = ns87415_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ns87415_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static struct scsi_host_template ns87415_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+
+/**
+ * ns87415_init_one - Register 87415 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in ns87415_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static const struct ata_port_info info = {
+ .sht = &ns87415_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .port_ops = &ns87415_pata_ops,
+ };
+ const struct ata_port_info *ppi[] = { &info, NULL };
+#if defined(CONFIG_SUPERIO)
+ static const struct ata_port_info info87560 = {
+ .sht = &ns87415_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .port_ops = &ns87560_pata_ops,
+ };
+
+ if (PCI_SLOT(pdev->devfn) == 0x0E)
+ ppi[0] = &info87560;
+#endif
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+ /* Select 512 byte sectors */
+ pci_write_config_byte(pdev, 0x55, 0xEE);
+ /* Select PIO0 8bit clocking */
+ pci_write_config_byte(pdev, 0x54, 0xB7);
+ return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id ns87415_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver ns87415_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ns87415_pci_tbl,
+ .probe = ns87415_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init ns87415_init(void)
+{
+ return pci_register_driver(&ns87415_pci_driver);
+}
+
+static void __exit ns87415_exit(void)
+{
+ pci_unregister_driver(&ns87415_pci_driver);
+}
+
+module_init(ns87415_init);
+module_exit(ns87415_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 091a70a0ef1c..3cd5eb2b6c91 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -29,14 +29,15 @@
/**
* oldpiix_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits oldpiix_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
@@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -237,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = {
};
static const struct ata_port_operations oldpiix_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = oldpiix_set_piomode,
.set_dmamode = oldpiix_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -265,9 +265,8 @@ static const struct ata_port_operations oldpiix_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 458bf67f766f..8f79447b6151 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -46,14 +46,15 @@ enum {
/**
* opti_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int opti_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits opti_enable_bits[] = {
{ 0x45, 1, 0x80, 0x00 },
@@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -182,7 +183,6 @@ static struct scsi_host_template opti_sht = {
};
static struct ata_port_operations opti_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = opti_set_piomode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -209,9 +209,8 @@ static struct ata_port_operations opti_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index f89bdfde16d0..6b07b5b48532 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -47,14 +47,15 @@ static int pci_clock; /* 0 = 33 1 = 25 */
/**
* optidma_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int optidma_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits optidma_enable_bits = {
0x40, 1, 0x08, 0x00
@@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -323,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev)
/**
* optidma_set_mode - mode setup
- * @ap: port to set up
+ * @link: link to set up
*
* Use the standard setup to tune the chipset and then finalise the
* configuration by writing the nibble of extra bits of data into
* the chip.
*/
-static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
+ struct ata_port *ap = link->ap;
u8 r;
int nybble = 4 * ap->port_no;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int rc = ata_do_set_mode(ap, r_failed);
+ int rc = ata_do_set_mode(link, r_failed);
if (rc == 0) {
pci_read_config_byte(pdev, 0x43, &r);
r &= (0x0F << nybble);
- r |= (optidma_make_bits43(&ap->device[0]) +
- (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+ r |= (optidma_make_bits43(&link->device[0]) +
+ (optidma_make_bits43(&link->device[0]) << 2)) << nybble;
pci_write_config_byte(pdev, 0x43, r);
}
return rc;
@@ -366,7 +368,6 @@ static struct scsi_host_template optidma_sht = {
};
static struct ata_port_operations optidma_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = optidma_set_pio_mode,
.set_dmamode = optidma_set_dma_mode,
@@ -396,13 +397,11 @@ static struct ata_port_operations optidma_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations optiplus_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = optiplus_set_pio_mode,
.set_dmamode = optiplus_set_dma_mode,
@@ -432,9 +431,8 @@ static struct ata_port_operations optiplus_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index a56257c98fe5..782ff4ada9d1 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.3.2"
/*
* Private data structure to glue stuff together
@@ -56,7 +56,7 @@ struct ata_pcmcia_info {
/**
* pcmcia_set_mode - PCMCIA specific mode setup
- * @ap: Port
+ * @link: link
* @r_failed_dev: Return pointer for failed device
*
* Perform the tuning and setup of the devices and timings, which
@@ -65,13 +65,13 @@ struct ata_pcmcia_info {
* decode, which alas is embarrassingly common in the PC world
*/
-static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
- struct ata_device *master = &ap->device[0];
- struct ata_device *slave = &ap->device[1];
+ struct ata_device *master = &link->device[0];
+ struct ata_device *slave = &link->device[1];
if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
- return ata_do_set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV,
ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
@@ -84,7 +84,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev
ata_dev_disable(slave);
}
}
- return ata_do_set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
}
static struct scsi_host_template pcmcia_sht = {
@@ -107,7 +107,6 @@ static struct scsi_host_template pcmcia_sht = {
static struct ata_port_operations pcmcia_port_ops = {
.set_mode = pcmcia_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -127,7 +126,6 @@ static struct ata_port_operations pcmcia_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_sff_port_start,
};
@@ -304,6 +302,8 @@ next_entry:
ap->ioaddr.ctl_addr = ctl_addr;
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+
/* activate */
ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
IRQF_SHARED, &pcmcia_sht);
@@ -382,6 +382,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 69a5aa4949f5..3d3f1558cdee 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc2027x"
-#define DRV_VERSION "0.9"
+#define DRV_VERSION "1.0"
#undef PDC_DEBUG
#ifdef PDC_DEBUG
@@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
static int pdc2027x_cable_detect(struct ata_port *ap);
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed);
/*
* ATA Timing Tables based on 133MHz controller clock.
@@ -147,7 +147,6 @@ static struct scsi_host_template pdc2027x_sht = {
};
static struct ata_port_operations pdc2027x_pata100_ops = {
- .port_disable = ata_port_disable,
.mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
@@ -173,13 +172,11 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations pdc2027x_pata133_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc2027x_set_piomode,
.set_dmamode = pdc2027x_set_dmamode,
.set_mode = pdc2027x_set_mode,
@@ -208,9 +205,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_info pdc2027x_port_info[] = {
@@ -277,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap)
u32 cgcr;
/* check cable detect results */
- cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+ cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL));
if (cgcr & (1 << 26))
goto cbl40;
@@ -295,12 +291,12 @@ cbl40:
*/
static inline int pdc2027x_port_enabled(struct ata_port *ap)
{
- return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+ return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
}
/**
* pdc2027x_prereset - prereset for PATA host controller
- * @ap: Target port
+ * @link: Target link
* @deadline: deadline jiffies for the operation
*
* Probeinit including cable detection.
@@ -309,12 +305,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
* None (inherited from caller).
*/
-static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
+static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline)
{
/* Check whether port enabled */
- if (!pdc2027x_port_enabled(ap))
+ if (!pdc2027x_port_enabled(link->ap))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -387,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Set the PIO timing registers using value table for 133MHz */
PDPRINTK("Set pio regs... \n");
- ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0xffff0000;
ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
(pdc2027x_pio_timing_tbl[pio].value1 << 8);
- writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0x00ffffff;
ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
- writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
PDPRINTK("Set pio regs done\n");
@@ -430,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* If tHOLD is '1', the hardware will add half clock for data hold time.
* This code segment seems to be no effect. tHOLD will be overwritten below.
*/
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
- writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
}
PDPRINTK("Set udma regs... \n");
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0xff000000;
ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
(pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
(pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
- writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
PDPRINTK("Set udma regs done\n");
@@ -453,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
unsigned int mdma_mode = dma_mode & 0x07;
PDPRINTK("Set mdma regs... \n");
- ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0x0000ffff;
ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
(pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
- writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
PDPRINTK("Set mdma regs done\n");
PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
@@ -470,24 +466,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* pdc2027x_set_mode - Set the timing registers back to correct values.
- * @ap: Port to configure
+ * @link: link to configure
* @r_failed: Returned device for failure
*
* The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
* automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
* This function overwrites the possibly incorrect values set by the hardware to be correct.
*/
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
- int i;
-
- i = ata_do_set_mode(ap, r_failed);
- if (i < 0)
- return i;
+ struct ata_port *ap = link->ap;
+ struct ata_device *dev;
+ int rc;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ rc = ata_do_set_mode(link, r_failed);
+ if (rc < 0)
+ return rc;
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
pdc2027x_set_piomode(ap, dev);
@@ -496,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
* Enable prefetch if the device support PIO only.
*/
if (dev->xfer_shift == ATA_SHIFT_PIO) {
- u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+ u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
ctcr1 |= (1 << 25);
- writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
PDPRINTK("Turn on prefetch\n");
} else {
@@ -563,14 +559,12 @@ static long pdc_read_counter(struct ata_host *host)
u32 bccrl, bccrh, bccrlv, bccrhv;
retry:
- bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
- bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
- rmb();
+ bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+ bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
/* Read the counter values again for verification */
- bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
- bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
- rmb();
+ bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+ bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
counter = (bccrh << 15) | bccrl;
@@ -619,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
/* Show the current clock value of PLL control register
* (maybe already configured by the firmware)
*/
- pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+ pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -659,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
- writew(pll_ctl, mmio_base + PDC_PLL_CTL);
- readw(mmio_base + PDC_PLL_CTL); /* flush */
+ iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL);
+ ioread16(mmio_base + PDC_PLL_CTL); /* flush */
/* Wait the PLL circuit to be stable */
mdelay(30);
@@ -670,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
* Show the current clock value of PLL control register
* (maybe configured by the firmware)
*/
- pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+ pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -692,16 +686,16 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
struct timeval start_time, end_time;
long pll_clock, usec_elapsed;
+ /* Start the test mode */
+ scr = ioread32(mmio_base + PDC_SYS_CTL);
+ PDPRINTK("scr[%X]\n", scr);
+ iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+ ioread32(mmio_base + PDC_SYS_CTL); /* flush */
+
/* Read current counter value */
start_count = pdc_read_counter(host);
do_gettimeofday(&start_time);
- /* Start the test mode */
- scr = readl(mmio_base + PDC_SYS_CTL);
- PDPRINTK("scr[%X]\n", scr);
- writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
- readl(mmio_base + PDC_SYS_CTL); /* flush */
-
/* Let the counter run for 100 ms. */
mdelay(100);
@@ -710,16 +704,16 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
do_gettimeofday(&end_time);
/* Stop the test mode */
- scr = readl(mmio_base + PDC_SYS_CTL);
+ scr = ioread32(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
- readl(mmio_base + PDC_SYS_CTL); /* flush */
+ iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+ ioread32(mmio_base + PDC_SYS_CTL); /* flush */
/* calculate the input clock in Hz */
usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
(end_time.tv_usec - start_time.tv_usec);
- pll_clock = (start_count - end_count) / 100 *
+ pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
(100000000 / usec_elapsed);
PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);
@@ -745,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
*/
pll_clock = pdc_detect_pll_input_clock(host);
- if (pll_clock < 0) /* counter overflow? Try again. */
- pll_clock = pdc_detect_pll_input_clock(host);
-
dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
/* Adjust PLL control register */
@@ -791,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
+ static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
+ static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] =
{ &pdc2027x_port_info[board_idx], NULL };
struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -826,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
mmio_base = host->iomap[PDC_MMIO_BAR];
- pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
- host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
- pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
- host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]);
+ ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i];
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd");
+ }
//pci_enable_intx(pdev);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 92447bed5e77..65d951618c60 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -9,7 +9,7 @@
* First cut with LBA48/ATAPI
*
* TODO:
- * Channel interlock/reset on both required
+ * Channel interlock/reset on both required ?
*/
#include <linux/kernel.h>
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
static int pdc2026x_cable_detect(struct ata_port *ap)
{
@@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{ 0x20, 0x01 }
};
static u8 mdma_timing[3][2] = {
- { 0x60, 0x03 },
- { 0x60, 0x04 },
{ 0xe0, 0x0f },
+ { 0x60, 0x04 },
+ { 0x60, 0x03 },
};
u8 r_bp, r_cp;
@@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* In UDMA3 or higher we have to clock switch for the duration of the
* DMA transfer sequence.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
@@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
*
* After a DMA completes we need to put the clock back to 33MHz for
* PIO timings.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
@@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
iowrite32(0, atapi_reg);
iowrite8(ioread8(clock) & ~sel66, clock);
}
- /* Check we keep host level locking here */
/* Flip back to 33Mhz for PIO */
if (adev->dma_mode >= XFER_UDMA_2)
iowrite8(ioread8(clock) & ~sel66, clock);
@@ -247,7 +252,6 @@ static struct scsi_host_template pdc202xx_sht = {
};
static struct ata_port_operations pdc2024x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -275,13 +279,11 @@ static struct ata_port_operations pdc2024x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations pdc2026x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -310,9 +312,8 @@ static struct ata_port_operations pdc2026x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 79f841bca593..fc72a965643d 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -22,7 +22,7 @@
#include <linux/pata_platform.h>
#define DRV_NAME "pata_platform"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
static int pio_mask = 1;
@@ -30,13 +30,11 @@ static int pio_mask = 1;
* Provide our own set_mode() as we don't want to change anything that has
* already been configured..
*/
-static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ struct ata_device *dev;
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
@@ -71,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = {
static struct ata_port_operations pata_platform_port_ops = {
.set_mode = pata_platform_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -91,7 +88,6 @@ static struct ata_port_operations pata_platform_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_dummy_ret0,
};
@@ -209,12 +205,17 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
- pp_info = (struct pata_platform_info *)(pdev->dev.platform_data);
+ pp_info = pdev->dev.platform_data;
pata_platform_setup_port(&ap->ioaddr, pp_info);
+ ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport",
+ (unsigned long long)io_res->start,
+ (unsigned long long)ctl_res->start);
+
/* activate */
- return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
- pp_info->irq_flags, &pata_platform_sht);
+ return ata_host_activate(host, platform_get_irq(pdev, 0),
+ ata_interrupt, pp_info ? pp_info->irq_flags
+ : 0, &pata_platform_sht);
}
/**
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 1998c19e8743..7d4c696c4cb6 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) {
@@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = {
};
static struct ata_port_operations qdi6500_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = qdi6500_set_piomode,
.tf_load = ata_tf_load,
@@ -192,13 +191,11 @@ static struct ata_port_operations qdi6500_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations qdi6580_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = qdi6580_set_piomode,
.tf_load = ata_tf_load,
@@ -220,9 +217,8 @@ static struct ata_port_operations qdi6580_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -238,6 +234,7 @@ static struct ata_port_operations qdi6580_port_ops = {
static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
{
+ unsigned long ctl = io + 0x206;
struct platform_device *pdev;
struct ata_host *host;
struct ata_port *ap;
@@ -254,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ret = -ENOMEM;
io_addr = devm_ioport_map(&pdev->dev, io, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1);
if (!io_addr || !ctl_addr)
goto fail;
@@ -279,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ap->ioaddr.ctl_addr = ctl_addr;
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl);
+
/*
* Hook in a private data structure per channel
*/
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 7d1aabed422d..d5b76497f4a2 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = {
};
static const struct ata_port_operations radisys_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = radisys_set_piomode,
.set_dmamode = radisys_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -231,9 +230,8 @@ static const struct ata_port_operations radisys_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 7632fcb070ca..ba8a31c55edb 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -26,7 +26,7 @@
/**
* rz1000_set_mode - mode setting function
- * @ap: ATA interface
+ * @link: ATA link
* @unused: returned device on set_mode failure
*
* Use a non standard set_mode function. We don't want to be tuned. We
@@ -34,12 +34,11 @@
* whacked out.
*/
-static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
@@ -74,7 +73,6 @@ static struct scsi_host_template rz1000_sht = {
static struct ata_port_operations rz1000_port_ops = {
.set_mode = rz1000_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -100,9 +98,8 @@ static struct ata_port_operations rz1000_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int rz1000_fifo_disable(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index b8b2d11e4180..21ebc485ca4b 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -40,7 +40,7 @@
#include <linux/libata.h>
#define DRV_NAME "sc1200"
-#define DRV_VERSION "0.2.5"
+#define DRV_VERSION "0.2.6"
#define SC1200_REV_A 0x00
#define SC1200_REV_B1 0x01
@@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = {
};
static struct ata_port_operations sc1200_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sc1200_set_piomode,
.set_dmamode = sc1200_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -227,9 +226,8 @@ static struct ata_port_operations sc1200_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index c55667e0eb65..55576138faea 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -43,7 +43,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_scc"
-#define DRV_VERSION "0.2"
+#define DRV_VERSION "0.3"
#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
@@ -238,12 +238,6 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
else
offset = 0; /* 100MHz */
- /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
- if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
- printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
- speed = XFER_UDMA_4;
- }
-
if (speed >= XFER_UDMA_0)
idx = speed - XFER_UDMA_0;
else
@@ -264,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
}
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+ if (adev->class == ATA_DEV_ATAPI &&
+ (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+ printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+ mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(adev, mask);
+}
+
/**
* scc_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
@@ -358,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = in_be32(ioaddr->lbal_addr);
tf->hob_lbam = in_be32(ioaddr->lbam_addr);
tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+ out_be32(ioaddr->ctl_addr, tf->ctl);
+ ap->last_ctl = tf->ctl;
}
}
@@ -596,16 +603,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
* Note: Original code is ata_std_softreset().
*/
-static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
- unsigned long deadline)
+static int scc_std_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0, err_mask;
u8 err;
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -629,9 +637,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
+ classes[0] = ata_dev_try_classify(&ap->link.device[0],
+ devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
+ classes[1] = ata_dev_try_classify(&ap->link.device[1],
+ devmask & (1 << 1), &err);
out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -694,7 +704,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
/* TBD: SW reset */
- scc_std_softreset(ap, &classes, deadline);
+ scc_std_softreset(&ap->link, &classes, deadline);
continue;
}
@@ -733,7 +743,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
void __iomem *mmio = ap->ioaddr.bmdma_addr;
u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
u32 int_status = in_be32(mmio + SCC_DMA_INTST);
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
static int retry = 0;
/* return if IOS_SS is cleared */
@@ -741,7 +751,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
return host_stat;
/* errata A252,A308 workaround: Step4 */
- if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
+ if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
@@ -752,11 +762,11 @@ static u8 scc_bmdma_status (struct ata_port *ap)
if ((qc->tf.protocol == ATA_PROT_DMA &&
qc->dev->xfer_mode > XFER_UDMA_4)) {
if (!(int_status & INTSTS_ACTEINT)) {
- printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
- ap->print_id, retry);
+ printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+ ap->print_id);
host_stat |= ATA_DMA_ERR;
if (retry++)
- ap->udma_mask >>= 1;
+ ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
} else
retry = 0;
}
@@ -778,7 +788,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
unsigned int words = buflen >> 1;
unsigned int i;
u16 *buf16 = (u16 *) buf;
@@ -832,38 +842,6 @@ static u8 scc_irq_on (struct ata_port *ap)
}
/**
- * scc_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Note: Original code is ata_irq_ack().
- */
-
-static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat, post_stat, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- /* get controller status; clear intr, err bits */
- host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
- out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS,
- host_stat | ATA_DMA_INTR | ATA_DMA_ERR);
-
- post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
-
- return status;
-}
-
-/**
* scc_bmdma_freeze - Freeze BMDMA controller port
* @ap: port to freeze
*
@@ -894,10 +872,10 @@ static void scc_bmdma_freeze (struct ata_port *ap)
* @deadline: deadline jiffies for the operation
*/
-static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int scc_pata_prereset(struct ata_link *link, unsigned long deadline)
{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap, deadline);
+ link->ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(link, deadline);
}
/**
@@ -908,8 +886,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
* Note: Original code is ata_std_postreset().
*/
-static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
+static void scc_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
+
DPRINTK("ENTER\n");
/* is double-select really necessary? */
@@ -1013,10 +993,9 @@ static struct scsi_host_template scc_sht = {
};
static const struct ata_port_operations scc_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode,
- .mode_filter = ata_pci_default_filter,
+ .mode_filter = scc_mode_filter,
.tf_load = scc_tf_load,
.tf_read = scc_tf_read,
@@ -1040,7 +1019,6 @@ static const struct ata_port_operations scc_pata_ops = {
.irq_clear = scc_bmdma_irq_clear,
.irq_on = scc_irq_on,
- .irq_ack = scc_irq_ack,
.port_start = scc_port_start,
.port_stop = scc_port_stop,
@@ -1186,6 +1164,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
host->iomap = pcim_iomap_table(pdev);
+ ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
+ ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
+
rc = scc_host_init(host);
if (rc)
return rc;
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 89691541fe59..df68806df4be 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_serverworks"
-#define DRV_VERSION "0.4.1"
+#define DRV_VERSION "0.4.2"
#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
@@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = {
};
static struct ata_port_operations serverworks_osb4_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = serverworks_set_piomode,
.set_dmamode = serverworks_set_dmamode,
.mode_filter = serverworks_osb4_filter,
@@ -348,13 +347,11 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations serverworks_csb_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = serverworks_set_piomode,
.set_dmamode = serverworks_set_dmamode,
.mode_filter = serverworks_csb_filter,
@@ -384,9 +381,8 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int serverworks_fixup_osb4(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index b0cd52d6e3fb..2eb75cd74a96 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.6"
+#define DRV_VERSION "0.4.7"
#define SIL680_MMIO_BAR 5
@@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) {
/**
* sil680_bus_reset - reset the SIL680 bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the SIL680 housekeeping when doing an ATA bus reset
*/
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+static int sil680_bus_reset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 0);
u8 reset;
@@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
pci_write_config_byte(pdev, addr, reset | 0x03);
udelay(25);
pci_write_config_byte(pdev, addr, reset);
- return ata_std_softreset(ap, classes, deadline);
+ return ata_std_softreset(link, classes, deadline);
}
static void sil680_error_handler(struct ata_port *ap)
@@ -237,7 +238,6 @@ static struct scsi_host_template sil680_sht = {
};
static struct ata_port_operations sil680_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sil680_set_piomode,
.set_dmamode = sil680_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -266,9 +266,8 @@ static struct ata_port_operations sil680_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 9a829a7cbc60..3b5be77e861c 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -2,6 +2,7 @@
* pata_sis.c - SiS ATA driver
*
* (C) 2005 Red Hat <alan@redhat.com>
+ * (C) 2007 Bartlomiej Zolnierkiewicz
*
* Based upon linux/drivers/ide/pci/sis5513.c
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
@@ -35,7 +36,7 @@
#include "sis.h"
#define DRV_NAME "pata_sis"
-#define DRV_VERSION "0.5.1"
+#define DRV_VERSION "0.5.2"
struct sis_chipset {
u16 device; /* PCI host ID */
@@ -53,6 +54,7 @@ struct sis_laptop {
static const struct sis_laptop sis_laptop[] = {
/* devid, subvendor, subdev */
{ 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
+ { 0x5513, 0x1734, 0x105F }, /* FSC Amilo A1630 */
/* end marker */
{ 0, }
};
@@ -82,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev)
static int sis_old_port_base(struct ata_device *adev)
{
- return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno);
+ return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno);
}
/**
@@ -131,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap)
/**
* sis_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sis_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits sis_enable_bits[] = {
{ 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
{ 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
@@ -152,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
/* Clear the FIFO settings. We can't enable the FIFO until
we know we are poking at a disk */
pci_write_config_byte(pdev, 0x4B, 0);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -237,7 +240,7 @@ static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
}
/**
- * sis_100_set_pioode - Initialize host controller PATA PIO timings
+ * sis_100_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
* @adev: Device we are configuring for.
*
@@ -262,7 +265,7 @@ static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
}
/**
- * sis_133_set_pioode - Initialize host controller PATA PIO timings
+ * sis_133_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
* @adev: Device we are configuring for.
*
@@ -334,7 +337,7 @@ static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
int drive_pci = sis_old_port_base(adev);
u16 timing;
- const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
+ const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
const u16 udma_bits[] = { 0xE000, 0xC000, 0xA000 };
pci_read_config_word(pdev, drive_pci, &timing);
@@ -342,15 +345,15 @@ static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
if (adev->dma_mode < XFER_UDMA_0) {
/* bits 3-0 hold recovery timing bits 8-10 active timing and
the higer bits are dependant on the device */
- timing &= ~ 0x870F;
+ timing &= ~0x870F;
timing |= mwdma_bits[speed];
- pci_write_config_word(pdev, drive_pci, timing);
} else {
/* Bit 15 is UDMA on/off, bit 13-14 are cycle time */
speed = adev->dma_mode - XFER_UDMA_0;
timing &= ~0x6000;
timing |= udma_bits[speed];
}
+ pci_write_config_word(pdev, drive_pci, timing);
}
/**
@@ -373,8 +376,9 @@ static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
int drive_pci = sis_old_port_base(adev);
u16 timing;
- const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
- const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000};
+ /* MWDMA 0-2 and UDMA 0-5 */
+ const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
+ const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000, 0x8000 };
pci_read_config_word(pdev, drive_pci, &timing);
@@ -432,8 +436,7 @@ static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev)
* @adev: Device to program
*
* Set UDMA/MWDMA mode for device, in host controller PCI config space.
- * Handles early SiS 961 bridges. Supports MWDMA as well unlike
- * the old ide/pci driver.
+ * Handles early SiS 961 bridges.
*
* LOCKING:
* None (inherited from caller).
@@ -467,8 +470,6 @@ static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *a
* @adev: Device to program
*
* Set UDMA/MWDMA mode for device, in host controller PCI config space.
- * Handles early SiS 961 bridges. Supports MWDMA as well unlike
- * the old ide/pci driver.
*
* LOCKING:
* None (inherited from caller).
@@ -530,7 +531,6 @@ static struct scsi_host_template sis_sht = {
};
static const struct ata_port_operations sis_133_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -558,13 +558,11 @@ static const struct ata_port_operations sis_133_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_133_for_sata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -592,13 +590,11 @@ static const struct ata_port_operations sis_133_for_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_133_early_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_100_set_piomode,
.set_dmamode = sis_133_early_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -626,13 +622,11 @@ static const struct ata_port_operations sis_133_early_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_100_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_100_set_piomode,
.set_dmamode = sis_100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -660,13 +654,11 @@ static const struct ata_port_operations sis_100_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_66_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_old_set_piomode,
.set_dmamode = sis_66_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -694,13 +686,11 @@ static const struct ata_port_operations sis_66_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_old_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_old_set_piomode,
.set_dmamode = sis_old_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -728,9 +718,8 @@ static const struct ata_port_operations sis_old_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_info sis_info = {
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 8c2813aa6cdb..1388cef52c07 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -26,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sl82c105"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.3.2"
enum {
/*
@@ -43,23 +43,24 @@ enum {
/**
* sl82c105_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits sl82c105_enable_bits[] = {
{ 0x40, 1, 0x01, 0x01 },
{ 0x40, 1, 0x10, 0x10 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -224,7 +225,6 @@ static struct scsi_host_template sl82c105_sht = {
};
static struct ata_port_operations sl82c105_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sl82c105_set_piomode,
.mode_filter = ata_pci_default_filter,
@@ -253,9 +253,8 @@ static struct ata_port_operations sl82c105_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index af21f443db6e..403eafcffe12 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -47,25 +47,26 @@
/**
* triflex_prereset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
+static int triflex_prereset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits triflex_enable_bits[] = {
{ 0x80, 1, 0x01, 0x01 },
{ 0x80, 1, 0x02, 0x02 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -197,7 +198,6 @@ static struct scsi_host_template triflex_sht = {
};
static struct ata_port_operations triflex_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = triflex_set_piomode,
.mode_filter = ata_pci_default_filter,
@@ -226,9 +226,8 @@ static struct ata_port_operations triflex_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index f645fe22cd1e..5d41b6612d7f 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -63,7 +63,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_via"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.3.2"
/*
* The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -97,6 +97,7 @@ static const struct via_isa_bridge {
u8 rev_max;
u16 flags;
} via_isa_bridges[] = {
+ { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
@@ -128,7 +129,7 @@ static const struct via_isa_bridge {
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "Acer Ferrari 3400",
.matches = {
@@ -144,6 +145,9 @@ static int via_cable_override(struct pci_dev *pdev)
/* Systems by DMI */
if (dmi_check_system(cable_dmi_table))
return 1;
+ /* Arima W730-K8/Targa Visionary 811/... */
+ if (pdev->subsystem_vendor == 0x161F && pdev->subsystem_device == 0x2032)
+ return 1;
return 0;
}
@@ -180,11 +184,15 @@ static int via_cable_detect(struct ata_port *ap) {
two drives */
if (ata66 & (0x10100000 >> (16 * ap->port_no)))
return ATA_CBL_PATA80;
+ /* Check with ACPI so we can spot BIOS reported SATA bridges */
+ if (ata_acpi_cbl_80wire(ap))
+ return ATA_CBL_PATA80;
return ATA_CBL_PATA40;
}
-static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int via_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
const struct via_isa_bridge *config = ap->host->private_data;
if (!(config->flags & VIA_NO_ENABLES)) {
@@ -197,7 +205,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
return -ENOENT;
}
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -240,7 +248,6 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
int ut;
int offset = 3 - (2*ap->port_no) - adev->devno;
-
/* Calculate the timing values we require */
ata_timing_compute(adev, mode, &t, T, UT);
@@ -287,9 +294,17 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
break;
}
+
/* Set UDMA unless device is not UDMA capable */
- if (udma_type)
- pci_write_config_byte(pdev, 0x50 + offset, ut);
+ if (udma_type) {
+ u8 cable80_status;
+
+ /* Get 80-wire cable detection bit */
+ pci_read_config_byte(pdev, 0x50 + offset, &cable80_status);
+ cable80_status &= 0x10;
+
+ pci_write_config_byte(pdev, 0x50 + offset, ut | cable80_status);
+ }
}
static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -333,7 +348,6 @@ static struct scsi_host_template via_sht = {
};
static struct ata_port_operations via_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -363,13 +377,11 @@ static struct ata_port_operations via_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations via_port_ops_noirq = {
- .port_disable = ata_port_disable,
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -399,9 +411,8 @@ static struct ata_port_operations via_port_ops_noirq = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 83abfeca4057..549cbbe9fd07 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) {
@@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = {
};
static struct ata_port_operations winbond_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = winbond_set_piomode,
.tf_load = ata_tf_load,
@@ -160,9 +159,8 @@ static struct ata_port_operations winbond_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -199,6 +197,7 @@ static __init int winbond_init_one(unsigned long port)
for (i = 0; i < 2 ; i ++) {
unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ unsigned long ctl_port = cmd_port + 0x206;
struct ata_host *host;
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
@@ -214,14 +213,16 @@ static __init int winbond_init_one(unsigned long port)
host = ata_host_alloc(&pdev->dev, 1);
if (!host)
goto err_unregister;
+ ap = host->ports[0];
rc = -ENOMEM;
cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1);
if (!cmd_addr || !ctl_addr)
goto err_unregister;
- ap = host->ports[0];
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port);
+
ap->ops = &winbond_port_ops;
ap->pio_mask = 0x1F;
ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index bec1de594de8..8d1b03d5bcb1 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -44,7 +44,7 @@
#include <linux/libata.h>
#define DRV_NAME "pdc_adma"
-#define DRV_VERSION "0.06"
+#define DRV_VERSION "1.0"
/* macro to calculate base address for ATA regs */
#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
@@ -92,6 +92,8 @@ enum {
/* CPB bits */
cDONE = (1 << 0),
+ cATERR = (1 << 3),
+
cVLD = (1 << 0),
cDAT = (1 << 2),
cIEN = (1 << 3),
@@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev,
static int adma_port_start(struct ata_port *ap);
static void adma_host_stop(struct ata_host *host);
static void adma_port_stop(struct ata_port *ap);
-static void adma_phy_reset(struct ata_port *ap);
static void adma_qc_prep(struct ata_queued_cmd *qc);
static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
static void adma_bmdma_stop(struct ata_queued_cmd *qc);
static u8 adma_bmdma_status(struct ata_port *ap);
static void adma_irq_clear(struct ata_port *ap);
-static void adma_eng_timeout(struct ata_port *ap);
+static void adma_freeze(struct ata_port *ap);
+static void adma_thaw(struct ata_port *ap);
+static void adma_error_handler(struct ata_port *ap);
static struct scsi_host_template adma_ata_sht = {
.module = THIS_MODULE,
@@ -159,21 +162,20 @@ static struct scsi_host_template adma_ata_sht = {
};
static const struct ata_port_operations adma_ata_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
.check_status = ata_check_status,
.dev_select = ata_std_dev_select,
- .phy_reset = adma_phy_reset,
.check_atapi_dma = adma_check_atapi_dma,
.data_xfer = ata_data_xfer,
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
- .eng_timeout = adma_eng_timeout,
+ .freeze = adma_freeze,
+ .thaw = adma_thaw,
+ .error_handler = adma_error_handler,
.irq_clear = adma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = adma_port_start,
.port_stop = adma_port_stop,
.host_stop = adma_host_stop,
@@ -184,7 +186,7 @@ static const struct ata_port_operations adma_ata_ops = {
static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ .flags = ATA_FLAG_SLAVE_POSS |
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
@@ -273,24 +275,42 @@ static inline void adma_enter_reg_mode(struct ata_port *ap)
readb(chan + ADMA_STATUS); /* flush */
}
-static void adma_phy_reset(struct ata_port *ap)
+static void adma_freeze(struct ata_port *ap)
{
- struct adma_port_priv *pp = ap->private_data;
+ void __iomem *chan = ADMA_PORT_REGS(ap);
+
+ /* mask/clear ATA interrupts */
+ writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
+ ata_check_status(ap);
- pp->state = adma_state_idle;
+ /* reset ADMA to idle state */
+ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+ udelay(2);
+ writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL);
+ udelay(2);
+}
+
+static void adma_thaw(struct ata_port *ap)
+{
adma_reinit_engine(ap);
- ata_port_probe(ap);
- ata_bus_reset(ap);
}
-static void adma_eng_timeout(struct ata_port *ap)
+static int adma_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct adma_port_priv *pp = ap->private_data;
if (pp->state != adma_state_idle) /* healthy paranoia */
pp->state = adma_state_mmio;
adma_reinit_engine(ap);
- ata_eng_timeout(ap);
+
+ return ata_std_prereset(link, deadline);
+}
+
+static void adma_error_handler(struct ata_port *ap)
+{
+ ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
static int adma_fill_sg(struct ata_queued_cmd *qc)
@@ -464,14 +484,33 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
pp = ap->private_data;
if (!pp || pp->state != adma_state_pkt)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
- if ((status & (aPERR | aPSD | aUIRQ)))
+ if (status & aPERR)
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ else if ((status & (aPSD | aUIRQ)))
qc->err_mask |= AC_ERR_OTHER;
+
+ if (pp->pkt[0] & cATERR)
+ qc->err_mask |= AC_ERR_DEV;
else if (pp->pkt[0] != cDONE)
qc->err_mask |= AC_ERR_OTHER;
- ata_qc_complete(qc);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi,
+ "ADMA-status 0x%02X", status);
+ ata_ehi_push_desc(ehi,
+ "pkt[0] 0x%02X", pp->pkt[0]);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
}
}
return handled;
@@ -489,7 +528,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
struct adma_port_priv *pp = ap->private_data;
if (!pp || pp->state != adma_state_mmio)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
@@ -502,7 +541,20 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
/* complete taskfile transaction */
pp->state = adma_state_idle;
qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi =
+ &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi,
+ "status 0x%02X", status);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
handled = 1;
}
}
@@ -652,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev,
if (rc)
return rc;
- for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_ata_setup_port(&host->ports[port_no]->ioaddr,
- ADMA_ATA_REGS(mmio_base, port_no));
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no) {
+ struct ata_port *ap = host->ports[port_no];
+ void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no);
+ unsigned int offset = port_base - mmio_base;
+
+ adma_ata_setup_port(&ap->ioaddr, port_base);
+
+ ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port");
+ }
/* initialize adapter */
adma_host_init(host, board_idx);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 3de183461c3c..08595f34b3e8 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -28,7 +28,7 @@
#include <scsi/scsi_device.h>
#define DRV_NAME "sata_inic162x"
-#define DRV_VERSION "0.2"
+#define DRV_VERSION "0.3"
enum {
MMIO_BAR = 5,
@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base)
writew(ctl, idma_ctl);
}
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr;
- u32 val;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
- return 0xffffffffU;
+ return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4;
- val = readl(scr_addr + scr_map[sc_reg] * 4);
+ *val = readl(scr_addr + scr_map[sc_reg] * 4);
/* this controller has stuck DIAG.N, ignore it */
if (sc_reg == SCR_ERROR)
- val &= ~SERR_PHYRDY_CHG;
- return val;
+ *val &= ~SERR_PHYRDY_CHG;
+ return 0;
}
-static void inic_scr_write(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;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
- return;
+ return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
+ return 0;
}
/*
@@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap)
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
u8 irq_stat;
/* fetch and clear irq */
@@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap)
writeb(irq_stat, port_base + PORT_IRQ_STAT);
if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc =
+ ata_qc_from_tag(ap, ap->link.active_tag);
if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
ata_chk_status(ap); /* clear ATA interrupt */
@@ -416,12 +417,13 @@ static void inic_thaw(struct ata_port *ap)
* SRST and SControl hardreset don't give valid signature on this
* controller. Only controller specific hardreset mechanism works.
*/
-static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+static int inic_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
u16 val;
int rc;
@@ -434,15 +436,15 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
msleep(1);
writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
- rc = sata_phy_resume(ap, timing, deadline);
+ rc = sata_link_resume(link, timing, deadline);
if (rc) {
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
"link after reset (errno=%d)\n", rc);
return rc;
}
*class = ATA_DEV_NONE;
- if (ata_port_online(ap)) {
+ if (ata_link_online(link)) {
struct ata_taskfile tf;
/* wait a while before checking status */
@@ -451,7 +453,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_port_printk(ap, KERN_WARNING, "device not ready "
+ ata_link_printk(link, KERN_WARNING, "device not ready "
"after hardreset (errno=%d)\n", rc);
return rc;
}
@@ -550,7 +552,6 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -567,7 +568,6 @@ static struct ata_port_operations inic_port_ops = {
.irq_clear = inic_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.qc_prep = ata_qc_prep,
.qc_issue = inic_qc_issue,
@@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = iomap = pcim_iomap_table(pdev);
for (i = 0; i < NR_PORTS; i++) {
- struct ata_ioports *port = &host->ports[i]->ioaddr;
- void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+ 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 = port_base + PORT_SCR;
+ port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
ata_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);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index fb8a749423ca..4df8311968e9 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -35,8 +35,6 @@
6) Add port multiplier support (intermediate)
- 7) Test and verify 3.0 Gbps support
-
8) Develop a low-power-consumption strategy, and implement it.
9) [Experiment, low priority] See if ATAPI can be supported using
@@ -71,10 +69,11 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "0.81"
+#define DRV_VERSION "1.01"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -227,26 +226,26 @@ enum {
EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
EDMA_ERR_IRQ_MASK_OFS = 0xc,
- EDMA_ERR_D_PAR = (1 << 0),
- EDMA_ERR_PRD_PAR = (1 << 1),
- EDMA_ERR_DEV = (1 << 2),
- EDMA_ERR_DEV_DCON = (1 << 3),
- EDMA_ERR_DEV_CON = (1 << 4),
- EDMA_ERR_SERR = (1 << 5),
+ EDMA_ERR_D_PAR = (1 << 0), /* UDMA data parity err */
+ EDMA_ERR_PRD_PAR = (1 << 1), /* UDMA PRD parity err */
+ EDMA_ERR_DEV = (1 << 2), /* device error */
+ EDMA_ERR_DEV_DCON = (1 << 3), /* device disconnect */
+ EDMA_ERR_DEV_CON = (1 << 4), /* device connected */
+ EDMA_ERR_SERR = (1 << 5), /* SError bits [WBDST] raised */
EDMA_ERR_SELF_DIS = (1 << 7), /* Gen II/IIE self-disable */
EDMA_ERR_SELF_DIS_5 = (1 << 8), /* Gen I self-disable */
- EDMA_ERR_BIST_ASYNC = (1 << 8),
+ EDMA_ERR_BIST_ASYNC = (1 << 8), /* BIST FIS or Async Notify */
EDMA_ERR_TRANS_IRQ_7 = (1 << 8), /* Gen IIE transprt layer irq */
- EDMA_ERR_CRBQ_PAR = (1 << 9),
- EDMA_ERR_CRPB_PAR = (1 << 10),
- EDMA_ERR_INTRL_PAR = (1 << 11),
- EDMA_ERR_IORDY = (1 << 12),
- EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
+ EDMA_ERR_CRQB_PAR = (1 << 9), /* CRQB parity error */
+ EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */
+ EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */
+ EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */
+ EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */
EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
- EDMA_ERR_LNK_DATA_RX = (0xf << 17),
- EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
- EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
- EDMA_ERR_TRANS_PROTO = (1 << 31),
+ EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */
+ EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */
+ EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */
+ EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */
EDMA_ERR_OVERRUN_5 = (1 << 5),
EDMA_ERR_UNDERRUN_5 = (1 << 6),
EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
@@ -255,7 +254,7 @@ enum {
EDMA_ERR_DEV_CON |
EDMA_ERR_SERR |
EDMA_ERR_SELF_DIS |
- EDMA_ERR_CRBQ_PAR |
+ EDMA_ERR_CRQB_PAR |
EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR |
EDMA_ERR_IORDY |
@@ -270,7 +269,7 @@ enum {
EDMA_ERR_OVERRUN_5 |
EDMA_ERR_UNDERRUN_5 |
EDMA_ERR_SELF_DIS_5 |
- EDMA_ERR_CRBQ_PAR |
+ EDMA_ERR_CRQB_PAR |
EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR |
EDMA_ERR_IORDY,
@@ -286,10 +285,10 @@ enum {
EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
EDMA_RSP_Q_PTR_SHIFT = 3,
- EDMA_CMD_OFS = 0x28,
- EDMA_EN = (1 << 0),
- EDMA_DS = (1 << 1),
- ATA_RST = (1 << 2),
+ 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_IORDY_TMOUT = 0x34,
EDMA_ARB_CFG = 0x38,
@@ -301,14 +300,13 @@ enum {
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
MV_HP_ERRATA_XX42A0 = (1 << 5),
- MV_HP_GEN_I = (1 << 6),
- MV_HP_GEN_II = (1 << 7),
- MV_HP_GEN_IIE = (1 << 8),
+ MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
+ MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
+ MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
/* Port private flags (pp_flags) */
- MV_PP_FLAG_EDMA_EN = (1 << 0),
- MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
- MV_PP_FLAG_HAD_A_RESET = (1 << 2),
+ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
+ MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -316,10 +314,17 @@ enum {
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
enum {
- MV_DMA_BOUNDARY = 0xffffffffU,
+ /* DMA boundary 0xffff is required by the s/g splitting
+ * we need on /length/ in mv_fill-sg().
+ */
+ MV_DMA_BOUNDARY = 0xffffU,
+ /* mask of register bits containing lower 32 bits
+ * of EDMA request queue DMA address
+ */
EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
+ /* ditto, for response queue */
EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
};
@@ -403,10 +408,10 @@ struct mv_host_priv {
};
static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+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 void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -416,6 +421,7 @@ static void mv_error_handler(struct ata_port *ap);
static void mv_post_int_cmd(struct ata_queued_cmd *qc);
static void mv_eh_freeze(struct ata_port *ap);
static void mv_eh_thaw(struct ata_port *ap);
+static int mv_slave_config(struct scsi_device *sdev);
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -447,13 +453,13 @@ static struct scsi_host_template mv5_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = MV_MAX_SG_CT,
+ .sg_tablesize = MV_MAX_SG_CT / 2,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = 1,
.proc_name = DRV_NAME,
.dma_boundary = MV_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
+ .slave_configure = mv_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -465,20 +471,18 @@ static struct scsi_host_template mv6_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = MV_MAX_SG_CT,
+ .sg_tablesize = MV_MAX_SG_CT / 2,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = 1,
.proc_name = DRV_NAME,
.dma_boundary = MV_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
+ .slave_configure = mv_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
static const struct ata_port_operations mv5_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -493,7 +497,6 @@ static const struct ata_port_operations mv5_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -508,8 +511,6 @@ static const struct ata_port_operations mv5_ops = {
};
static const struct ata_port_operations mv6_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -524,7 +525,6 @@ static const struct ata_port_operations mv6_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -539,8 +539,6 @@ static const struct ata_port_operations mv6_ops = {
};
static const struct ata_port_operations mv_iie_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -555,7 +553,6 @@ static const struct ata_port_operations mv_iie_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -620,6 +617,9 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
+ /* RocketRAID 1740/174x have different identifiers */
+ { PCI_VDEVICE(TTI, 0x1740), chip_508x },
+ { PCI_VDEVICE(TTI, 0x1742), chip_508x },
{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
@@ -756,6 +756,17 @@ static void mv_irq_clear(struct ata_port *ap)
{
}
+static int mv_slave_config(struct scsi_device *sdev)
+{
+ int rc = ata_scsi_slave_config(sdev);
+ if (rc)
+ return rc;
+
+ blk_queue_max_phys_segments(sdev->request_queue, MV_MAX_SG_CT / 2);
+
+ return 0; /* scsi layer doesn't check return value, sigh */
+}
+
static void mv_set_edma_ptrs(void __iomem *port_mmio,
struct mv_host_priv *hpriv,
struct mv_port_priv *pp)
@@ -823,7 +834,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
}
/**
- * mv_stop_dma - Disable eDMA engine
+ * __mv_stop_dma - Disable eDMA engine
* @ap: ATA channel to manipulate
*
* Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +843,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
* LOCKING:
* Inherited from caller.
*/
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
@@ -865,6 +876,18 @@ static int mv_stop_dma(struct ata_port *ap)
return err;
}
+static int mv_stop_dma(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ rc = __mv_stop_dma(ap);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ return rc;
+}
+
#ifdef ATA_DEBUG
static void mv_dump_mem(void __iomem *start, unsigned bytes)
{
@@ -961,22 +984,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs)
- return readl(mv_ap_base(ap) + ofs);
- else
- return (u32) ofs;
+ if (ofs != 0xffffffffU) {
+ *val = readl(mv_ap_base(ap) + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs)
+ if (ofs != 0xffffffffU) {
writelfl(val, mv_ap_base(ap) + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1056,7 @@ static int mv_port_start(struct ata_port *ap)
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
dma_addr_t mem_dma;
+ unsigned long flags;
int rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1095,14 @@ static int mv_port_start(struct ata_port *ap)
pp->sg_tbl = mem;
pp->sg_tbl_dma = mem_dma;
+ spin_lock_irqsave(&ap->host->lock, flags);
+
mv_edma_cfg(ap, hpriv, port_mmio);
mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
/* Don't turn on EDMA here...do it before DMA commands only. Else
* we'll be unable to send non-data, PIO, etc due to restricted access
* to shadow regs.
@@ -1090,11 +1122,7 @@ static int mv_port_start(struct ata_port *ap)
*/
static void mv_port_stop(struct ata_port *ap)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ap->host->lock, flags);
mv_stop_dma(ap);
- spin_unlock_irqrestore(&ap->host->lock, flags);
}
/**
@@ -1106,10 +1134,9 @@ static void mv_port_stop(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
+static void mv_fill_sg(struct ata_queued_cmd *qc)
{
struct mv_port_priv *pp = qc->ap->private_data;
- unsigned int n_sg = 0;
struct scatterlist *sg;
struct mv_sg *mv_sg;
@@ -1118,18 +1145,27 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
dma_addr_t addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
- mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
- mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
- mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
+ while (sg_len) {
+ u32 offset = addr & 0xffff;
+ u32 len = sg_len;
- if (ata_sg_is_last(sg, qc))
- mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+ if ((offset + sg_len > 0x10000))
+ len = 0x10000 - offset;
- mv_sg++;
- n_sg++;
- }
+ mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
+ mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ mv_sg->flags_size = cpu_to_le32(len & 0xffff);
+
+ sg_len -= len;
+ addr += len;
- return n_sg;
+ if (!sg_len && ata_sg_is_last(sg, qc))
+ mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+
+ mv_sg++;
+ }
+
+ }
}
static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
@@ -1325,7 +1361,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
* port. Turn off EDMA so there won't be problems accessing
* shadow block, etc registers.
*/
- mv_stop_dma(ap);
+ __mv_stop_dma(ap);
return ata_qc_issue_prot(qc);
}
@@ -1370,7 +1406,7 @@ 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 edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
unsigned int action = 0, err_mask = 0;
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
@@ -1378,8 +1414,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
/* just a guess: do we need to do this? should we
* expand this, and do it in all cases?
*/
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ 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);
@@ -1393,16 +1429,16 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (edma_err_cause & EDMA_ERR_DEV)
err_mask |= AC_ERR_DEV;
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
- EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+ EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR)) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_HARDRESET;
- ata_ehi_push_desc(ehi, ", parity error");
+ ata_ehi_push_desc(ehi, "parity error");
}
if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
- ", dev disconnect" : ", dev connect");
+ "dev disconnect" : "dev connect");
}
if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1447,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
struct mv_port_priv *pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
- ata_ehi_push_desc(ehi, ", EDMA self-disable");
+ ata_ehi_push_desc(ehi, "EDMA self-disable");
}
} else {
eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,12 +1455,12 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (edma_err_cause & EDMA_ERR_SELF_DIS) {
struct mv_port_priv *pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
- ata_ehi_push_desc(ehi, ", EDMA self-disable");
+ ata_ehi_push_desc(ehi, "EDMA self-disable");
}
if (edma_err_cause & EDMA_ERR_SERR) {
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
err_mask = AC_ERR_ATA_BUS;
action |= ATA_EH_HARDRESET;
}
@@ -1463,7 +1499,7 @@ static void mv_intr_pio(struct ata_port *ap)
return;
/* get active ATA command */
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (unlikely(!qc)) /* no active tag */
return;
if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */
@@ -1489,33 +1525,30 @@ static void mv_intr_edma(struct ata_port *ap)
while (1) {
u16 status;
+ unsigned int tag;
/* get s/w response queue last-read pointer, and compare */
out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
if (in_index == out_index)
break;
-
/* 50xx: get active ATA command */
- if (IS_GEN_I(hpriv))
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (IS_GEN_I(hpriv))
+ tag = ap->link.active_tag;
- /* 60xx: get active ATA command via tag, to enable support
- * for queueing. this works transparently for queued and
- * non-queued modes.
+ /* Gen II/IIE: get active ATA command via tag, to enable
+ * support for queueing. this works transparently for
+ * queued and non-queued modes.
*/
- else {
- unsigned int tag;
+ else if (IS_GEN_II(hpriv))
+ tag = (le16_to_cpu(pp->crpb[out_index].id)
+ >> CRPB_IOID_SHIFT_6) & 0x3f;
- if (IS_GEN_II(hpriv))
- tag = (le16_to_cpu(pp->crpb[out_index].id)
- >> CRPB_IOID_SHIFT_6) & 0x3f;
- else
- tag = (le16_to_cpu(pp->crpb[out_index].id)
- >> CRPB_IOID_SHIFT_7) & 0x3f;
+ else /* IS_GEN_IIE */
+ tag = (le16_to_cpu(pp->crpb[out_index].id)
+ >> CRPB_IOID_SHIFT_7) & 0x3f;
- qc = ata_qc_from_tag(ap, tag);
- }
+ qc = ata_qc_from_tag(ap, tag);
/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
* bits (WARNING: might not necessarily be associated
@@ -1535,7 +1568,7 @@ static void mv_intr_edma(struct ata_port *ap)
ata_qc_complete(qc);
}
- /* advance software response queue pointer, to
+ /* advance software response queue pointer, to
* indicate (after the loop completes) to hardware
* that we have consumed a response queue entry.
*/
@@ -1604,7 +1637,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
if (unlikely(have_err_bits)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
continue;
@@ -1645,15 +1678,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
for (i = 0; i < host->n_ports; i++) {
ap = host->ports[i];
- if (!ata_port_offline(ap)) {
- ehi = &ap->eh_info;
+ if (!ata_link_offline(&ap->link)) {
+ ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
if (!printed++)
ata_ehi_push_desc(ehi,
"PCI err cause 0x%08x", err_cause);
err_mask = AC_ERR_HOST_BUS;
ehi->action = ATA_EH_HARDRESET;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc)
qc->err_mask |= err_mask;
else
@@ -1741,26 +1774,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
- if (ofs != 0xffffffffU)
- return readl(addr + ofs);
- else
- return (u32) ofs;
+ if (ofs != 0xffffffffU) {
+ *val = readl(addr + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv5_scr_write(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)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
- if (ofs != 0xffffffffU)
+ if (ofs != 0xffffffffU) {
writelfl(val, addr + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,20 +2175,28 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
- DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+ {
+ u32 sstatus, serror, scontrol;
+
+ mv_scr_read(ap, SCR_STATUS, &sstatus);
+ mv_scr_read(ap, SCR_ERROR, &serror);
+ mv_scr_read(ap, SCR_CONTROL, &scontrol);
+ DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", status, serror, scontrol);
+ }
+#endif
/* Issue COMRESET via SControl */
comreset_retry:
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
msleep(1);
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
msleep(20);
do {
- sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
break;
@@ -2164,11 +2209,19 @@ comreset_retry:
(retry-- > 0))
goto comreset_retry;
- DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+ {
+ u32 sstatus, serror, scontrol;
- if (ata_port_offline(ap)) {
+ mv_scr_read(ap, SCR_STATUS, &sstatus);
+ mv_scr_read(ap, SCR_ERROR, &serror);
+ mv_scr_read(ap, SCR_CONTROL, &scontrol);
+ DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", sstatus, serror, scontrol);
+ }
+#endif
+
+ if (ata_link_offline(&ap->link)) {
*class = ATA_DEV_NONE;
return;
}
@@ -2195,7 +2248,7 @@ comreset_retry:
*/
/* finally, read device signature from TF registers */
- *class = ata_dev_try_classify(ap, 0, NULL);
+ *class = ata_dev_try_classify(ap->link.device, 1, NULL);
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -2204,12 +2257,13 @@ comreset_retry:
VPRINTK("EXIT\n");
}
-static int mv_prereset(struct ata_port *ap, unsigned long deadline)
+static int mv_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct mv_port_priv *pp = ap->private_data;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &link->eh_context;
int rc;
-
+
rc = mv_stop_dma(ap);
if (rc)
ehc->i.action |= ATA_EH_HARDRESET;
@@ -2223,7 +2277,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
- if (ata_port_online(ap))
+ if (ata_link_online(link))
rc = ata_wait_ready(ap, deadline);
else
rc = -ENODEV;
@@ -2231,9 +2285,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
return rc;
}
-static int mv_hardreset(struct ata_port *ap, unsigned int *class,
+static int mv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct mv_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
@@ -2246,16 +2301,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class,
return 0;
}
-static void mv_postreset(struct ata_port *ap, unsigned int *classes)
+static void mv_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
u32 serr;
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* clear SError */
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(link, SCR_ERROR, &serr);
+ sata_scr_write_flush(link, SCR_ERROR, serr);
/* bail out if no device is present */
if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
@@ -2528,8 +2584,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
}
for (port = 0; port < host->n_ports; port++) {
+ struct ata_port *ap = host->ports[port];
void __iomem *port_mmio = mv_port_base(mmio, port);
- mv_port_init(&host->ports[port]->ioaddr, port_mmio);
+ unsigned int offset = port_mmio - mmio;
+
+ mv_port_init(&ap->ioaddr, port_mmio);
+
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
}
for (hc = 0; hc < n_hc; hc++) {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index db81e3efa5ec..40557fe2ffdf 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -49,7 +49,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_nv"
-#define DRV_VERSION "3.4"
+#define DRV_VERSION "3.5"
#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL
@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
@@ -340,7 +340,6 @@ static struct scsi_host_template nv_adma_sht = {
};
static const struct ata_port_operations nv_generic_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -359,14 +358,12 @@ static const struct ata_port_operations nv_generic_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
};
static const struct ata_port_operations nv_nf2_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -385,14 +382,12 @@ static const struct ata_port_operations nv_nf2_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
};
static const struct ata_port_operations nv_ck804_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -411,7 +406,6 @@ static const struct ata_port_operations nv_ck804_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
@@ -419,7 +413,6 @@ static const struct ata_port_operations nv_ck804_ops = {
};
static const struct ata_port_operations nv_adma_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = nv_adma_tf_read,
.check_atapi_dma = nv_adma_check_atapi_dma,
@@ -430,6 +423,7 @@ static const struct ata_port_operations nv_adma_ops = {
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = nv_adma_qc_prep,
.qc_issue = nv_adma_qc_issue,
.freeze = nv_adma_freeze,
@@ -439,7 +433,6 @@ static const struct ata_port_operations nv_adma_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = nv_adma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = nv_adma_port_start,
@@ -455,8 +448,8 @@ static const struct ata_port_info nv_port_info[] = {
/* generic */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -466,8 +459,8 @@ static const struct ata_port_info nv_port_info[] = {
/* nforce2/3 */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -477,8 +470,8 @@ static const struct ata_port_info nv_port_info[] = {
/* ck804 */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -489,8 +482,8 @@ static const struct ata_port_info nv_port_info[] = {
{
.sht = &nv_adma_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME |
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -594,7 +587,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
/* Not a proper libata device, ignore */
return rc;
- if (ap->device[sdev->id].class == ATA_DEV_ATAPI) {
+ if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
/*
* NVIDIA reports that ADMA mode does not support ATAPI commands.
* Therefore ATAPI commands are sent through the legacy interface.
@@ -711,23 +704,24 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
flags & (NV_CPB_RESP_ATA_ERR |
NV_CPB_RESP_CMD_ERR |
NV_CPB_RESP_CPB_ERR)))) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
int freeze = 0;
ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+ __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
if (flags & NV_CPB_RESP_ATA_ERR) {
- ata_ehi_push_desc(ehi, ": ATA error");
+ ata_ehi_push_desc(ehi, "ATA error");
ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CMD_ERR) {
- ata_ehi_push_desc(ehi, ": CMD error");
+ ata_ehi_push_desc(ehi, "CMD error");
ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CPB_ERR) {
- ata_ehi_push_desc(ehi, ": CPB error");
+ ata_ehi_push_desc(ehi, "CPB error");
ehi->err_mask |= AC_ERR_SYSTEM;
freeze = 1;
} else {
/* notifier error, but no error in CPB flags? */
+ ata_ehi_push_desc(ehi, "unknown");
ehi->err_mask |= AC_ERR_OTHER;
freeze = 1;
}
@@ -746,7 +740,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
DPRINTK("Completing qc from tag %d\n",cpb_num);
ata_qc_complete(qc);
} else {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
/* Notifier bits set without a command may indicate the drive
is misbehaving. Raise host state machine violation on this
condition. */
@@ -763,7 +757,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
/* freeze if hotplugged */
if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -816,7 +810,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
>> (NV_INT_PORT_SHIFT * i);
- if(ata_tag_valid(ap->active_tag))
+ if(ata_tag_valid(ap->link.active_tag))
/** NV_INT_DEV indication seems unreliable at times
at least in ADMA mode. Force it on always when a
command is active, to prevent losing interrupts. */
@@ -851,23 +845,24 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
NV_ADMA_STAT_HOTUNPLUG |
NV_ADMA_STAT_TIMEOUT |
NV_ADMA_STAT_SERROR))) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+ __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
if (status & NV_ADMA_STAT_TIMEOUT) {
ehi->err_mask |= AC_ERR_SYSTEM;
- ata_ehi_push_desc(ehi, ": timeout");
+ ata_ehi_push_desc(ehi, "timeout");
} else if (status & NV_ADMA_STAT_HOTPLUG) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ": hotplug");
+ ata_ehi_push_desc(ehi, "hotplug");
} else if (status & NV_ADMA_STAT_HOTUNPLUG) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ": hot unplug");
+ ata_ehi_push_desc(ehi, "hot unplug");
} else if (status & NV_ADMA_STAT_SERROR) {
/* let libata analyze SError and figure out the cause */
- ata_ehi_push_desc(ehi, ": SError");
- }
+ ata_ehi_push_desc(ehi, "SError");
+ } else
+ ata_ehi_push_desc(ehi, "unknown");
ata_port_freeze(ap);
continue;
}
@@ -877,10 +872,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
u32 check_commands;
int pos, error = 0;
- if(ata_tag_valid(ap->active_tag))
- check_commands = 1 << ap->active_tag;
+ if(ata_tag_valid(ap->link.active_tag))
+ check_commands = 1 << ap->link.active_tag;
else
- check_commands = ap->sactive;
+ check_commands = ap->link.sactive;
/** Check CPBs for completed commands */
while ((pos = ffs(check_commands)) && !error) {
@@ -1331,7 +1326,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
else
@@ -1391,20 +1386,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret;
}
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
- return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
static void nv_nf2_freeze(struct ata_port *ap)
@@ -1455,7 +1452,7 @@ static void nv_ck804_thaw(struct ata_port *ap)
writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
}
-static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
unsigned int dummy;
@@ -1464,7 +1461,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class,
* some controllers. Don't classify on hardreset. For more
* info, see http://bugme.osdl.org/show_bug.cgi?id=3352
*/
- return sata_std_hardreset(ap, &dummy, deadline);
+ return sata_std_hardreset(link, &dummy, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -1481,7 +1478,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
int i;
u16 tmp;
- if(ata_tag_valid(ap->active_tag) || ap->sactive) {
+ if(ata_tag_valid(ap->link.active_tag) || ap->link.sactive) {
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
@@ -1497,8 +1494,8 @@ static void nv_adma_error_handler(struct ata_port *ap)
for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
struct nv_adma_cpb *cpb = &pp->cpb[i];
- if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) ||
- ap->sactive & (1 << i) )
+ if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
+ ap->link.sactive & (1 << i) )
ata_port_printk(ap, KERN_ERR,
"CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
i, cpb->ctl_flags, cpb->resp_flags);
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d2fcb9a6bec2..903213153b5d 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,7 +45,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "2.09"
+#define DRV_VERSION "2.10"
enum {
PDC_MAX_PORTS = 4,
@@ -128,8 +128,8 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
@@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = {
};
static const struct ata_port_operations pdc_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -185,7 +184,6 @@ static const struct ata_port_operations pdc_sata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
@@ -194,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = {
/* First-generation chips need a more restrictive ->check_atapi_dma op */
static const struct ata_port_operations pdc_old_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -212,7 +209,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
@@ -220,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
};
static const struct ata_port_operations pdc_pata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -238,7 +233,6 @@ static const struct ata_port_operations pdc_pata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = pdc_common_port_start,
};
@@ -328,8 +322,8 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
{ PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
{ PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
- { PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
- { PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3515), board_40518 },
+ { PCI_VDEVICE(PROMISE, 0x3519), board_40518 },
{ PCI_VDEVICE(PROMISE, 0x3d17), board_40518 },
{ PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
@@ -427,19 +421,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA;
}
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -474,7 +469,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
buf32[2] = 0; /* no next-packet */
/* select drive */
- if (sata_scr_valid(ap)) {
+ if (sata_scr_valid(&ap->link)) {
dev_sel = PDC_DEVICE_SATA;
} else {
dev_sel = ATA_DEVICE_OBS;
@@ -625,7 +620,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
u32 port_status, u32 err_mask)
{
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned int ac_err_mask = 0;
ata_ehi_clear_desc(ehi);
@@ -642,8 +637,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
| PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
ac_err_mask |= AC_ERR_HOST_BUS;
- if (sata_scr_valid(ap))
- ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+ if (sata_scr_valid(&ap->link)) {
+ u32 serror;
+
+ pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+ ehi->serror |= serror;
+ }
qc->err_mask |= ac_err_mask;
@@ -768,7 +767,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
tmp = hotplug_status & (0x11 << ata_no);
if (tmp && ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
@@ -783,7 +782,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc_host_intr(ap, qc);
}
@@ -1004,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
- pdc_ata_setup_port(host->ports[i],
- base + 0x200 + ata_no * 0x80,
- base + 0x400 + ata_no * 0x100);
+ unsigned int port_offset = 0x200 + ata_no * 0x80;
+ unsigned int scr_offset = 0x400 + ata_no * 0x100;
+
+ pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9ab554da89bf..c4c4cd29eebb 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -39,7 +39,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
-#define DRV_VERSION "0.08"
+#define DRV_VERSION "0.09"
enum {
QS_MMIO_BAR = 4,
@@ -111,8 +111,8 @@ struct qs_port_priv {
qs_state_t state;
};
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
@@ -145,7 +145,6 @@ static struct scsi_host_template qs_ata_sht = {
};
static const struct ata_port_operations qs_ata_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -159,7 +158,6 @@ static const struct ata_port_operations qs_ata_ops = {
.eng_timeout = qs_eng_timeout,
.irq_clear = qs_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
.port_start = qs_port_start,
@@ -255,18 +253,20 @@ static void qs_eng_timeout(struct ata_port *ap)
ata_eng_timeout(ap);
}
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return ~0U;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ return 0;
}
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+ return 0;
}
static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +337,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
buf[28] = dflags;
/* frame information structure (FIS) */
- ata_tf_to_fis(&qc->tf, &buf[32], 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
}
static inline void qs_packet_start(struct ata_queued_cmd *qc)
@@ -402,7 +402,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
switch (sHST) {
case 0: /* successful CPB */
@@ -435,7 +435,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_mmio)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
@@ -635,9 +635,14 @@ static int qs_ata_init_one(struct pci_dev *pdev,
return rc;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
- void __iomem *chan =
- host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
- qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
+ struct ata_port *ap = host->ports[port_no];
+ unsigned int offset = port_no * 0x4000;
+ void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset;
+
+ qs_ata_setup_port(&ap->ioaddr, chan);
+
+ ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 2a86dc4598d0..ea3a0ab7e027 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "2.2"
+#define DRV_VERSION "2.3"
enum {
SIL_MMIO_BAR = 5,
@@ -59,7 +59,8 @@ enum {
SIL_FLAG_MOD15WRITE = (1 << 30),
SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+ ATA_FLAG_MMIO,
+ SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME,
/*
* Controller IDs
@@ -115,9 +116,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -185,7 +186,6 @@ static struct scsi_host_template sil_sht = {
};
static const struct ata_port_operations sil_ops = {
- .port_disable = ata_port_disable,
.dev_config = sil_dev_config,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -206,7 +206,6 @@ static const struct ata_port_operations sil_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
.port_start = ata_port_start,
@@ -216,6 +215,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -225,6 +225,7 @@ static const struct ata_port_info sil_port_info[] = {
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
SIL_FLAG_NO_SATA_IRQ,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -233,6 +234,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3512 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -241,6 +243,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3114 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -290,35 +293,33 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
/**
* sil_set_mode - wrap set_mode functions
- * @ap: port to set up
+ * @link: link to set up
* @r_failed: returned device when we fail
*
* Wrap the libata method for device setup as after the setup we need
* to inspect the results and do some configuration work
*/
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
- struct ata_host *host = ap->host;
- struct ata_device *dev;
- void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+ struct ata_port *ap = link->ap;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
- u32 tmp, dev_mode[2];
- unsigned int i;
+ struct ata_device *dev;
+ u32 tmp, dev_mode[2] = { };
int rc;
- rc = ata_do_set_mode(ap, r_failed);
+ rc = ata_do_set_mode(link, r_failed);
if (rc)
return rc;
- for (i = 0; i < 2; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev))
- dev_mode[i] = 0; /* PIO0/1/2 */
+ dev_mode[dev->devno] = 0; /* PIO0/1/2 */
else if (dev->flags & ATA_DFLAG_PIO)
- dev_mode[i] = 1; /* PIO3/4 */
+ dev_mode[dev->devno] = 1; /* PIO3/4 */
else
- dev_mode[i] = 3; /* UDMA */
+ dev_mode[dev->devno] = 3; /* UDMA */
/* value 2 indicates MDMA */
}
@@ -350,25 +351,32 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
return NULL;
}
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
void __iomem *mmio = sil_scr_addr(ap, sc_reg);
- if (mmio)
- return readl(mmio);
- return 0xffffffffU;
+
+ if (mmio) {
+ *val = readl(mmio);
+ return 0;
+ }
+ return -EINVAL;
}
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
void __iomem *mmio = sil_scr_addr(ap, sc_reg);
- if (mmio)
+
+ if (mmio) {
writel(val, mmio);
+ return 0;
+ }
+ return -EINVAL;
}
static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
{
- struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 status;
if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
@@ -378,7 +386,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately.
*/
- serror = sil_scr_read(ap, SCR_ERROR);
+ sil_scr_read(ap, SCR_ERROR, &serror);
sil_scr_write(ap, SCR_ERROR, serror);
/* Trigger hotplug and accumulate SError only if the
@@ -387,8 +395,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* repeat probing needlessly.
*/
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
- ata_ehi_hotplugged(&ap->eh_info);
- ap->eh_info.serror |= serror;
+ ata_ehi_hotplugged(&ap->link.eh_info);
+ ap->link.eh_info.serror |= serror;
}
goto freeze;
@@ -555,8 +563,8 @@ static void sil_thaw(struct ata_port *ap)
*/
static void sil_dev_config(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
+ struct ata_port *ap = dev->link->ap;
+ int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -679,7 +687,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
mmio_base = host->iomap[SIL_MMIO_BAR];
for (i = 0; i < host->n_ports; i++) {
- struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
ioaddr->altstatus_addr =
@@ -687,6 +696,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
ioaddr->scr_addr = mmio_base + sil_port[i].scr;
ata_std_ports(ioaddr);
+
+ ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");
}
/* initialize and activate */
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ac43a30ebe29..b0619278454a 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -30,7 +30,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "0.9"
+#define DRV_VERSION "1.1"
/*
* Port request block (PRB) 32 bytes
@@ -168,7 +168,7 @@ enum {
DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT = 16,
@@ -237,8 +237,9 @@ enum {
/* host flags */
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+ ATA_FLAG_AN | ATA_FLAG_PMP,
+ SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
IRQ_STAT_4PORTS = 0xf,
@@ -322,16 +323,20 @@ struct sil24_port_priv {
union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
dma_addr_t cmd_block_dma; /* DMA base addr for them */
struct ata_taskfile tf; /* Cached taskfile registers */
+ int do_port_rst;
};
static void sil24_dev_config(struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static int sil24_qc_defer(struct ata_queued_cmd *qc);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
+static void sil24_pmp_attach(struct ata_port *ap);
+static void sil24_pmp_detach(struct ata_port *ap);
static void sil24_freeze(struct ata_port *ap);
static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
@@ -340,6 +345,7 @@ static int sil24_port_start(struct ata_port *ap);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev);
+static int sil24_port_resume(struct ata_port *ap);
#endif
static const struct pci_device_id sil24_pci_tbl[] = {
@@ -384,8 +390,6 @@ static struct scsi_host_template sil24_sht = {
};
static const struct ata_port_operations sil24_ops = {
- .port_disable = ata_port_disable,
-
.dev_config = sil24_dev_config,
.check_status = sil24_check_status,
@@ -394,22 +398,28 @@ static const struct ata_port_operations sil24_ops = {
.tf_read = sil24_tf_read,
+ .qc_defer = sil24_qc_defer,
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
.irq_clear = sil24_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = sil24_scr_read,
.scr_write = sil24_scr_write,
+ .pmp_attach = sil24_pmp_attach,
+ .pmp_detach = sil24_pmp_detach,
+
.freeze = sil24_freeze,
.thaw = sil24_thaw,
.error_handler = sil24_error_handler,
.post_internal_cmd = sil24_post_internal_cmd,
.port_start = sil24_port_start,
+
+#ifdef CONFIG_PM
+ .port_resume = sil24_port_resume,
+#endif
};
/*
@@ -424,6 +434,7 @@ static const struct ata_port_info sil24_port_info[] = {
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -432,6 +443,7 @@ static const struct ata_port_info sil24_port_info[] = {
/* sil_3132 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -440,6 +452,7 @@ static const struct ata_port_info sil24_port_info[] = {
/* sil_3131/sil_3531 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -456,7 +469,7 @@ static int sil24_tag(int tag)
static void sil24_dev_config(struct ata_device *dev)
{
- void __iomem *port = dev->ap->ioaddr.cmd_addr;
+ void __iomem *port = dev->link->ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -464,15 +477,15 @@ static void sil24_dev_config(struct ata_device *dev)
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
}
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
{
- struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = ap->ioaddr.cmd_addr;
- struct sil24_prb __iomem *prb = port;
+ struct sil24_prb __iomem *prb;
u8 fis[6 * 4];
- memcpy_fromio(fis, prb->fis, 6 * 4);
- ata_tf_from_fis(fis, &pp->tf);
+ prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+ memcpy_fromio(fis, prb->fis, sizeof(fis));
+ ata_tf_from_fis(fis, tf);
}
static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +501,30 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3,
};
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
- return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ return 0;
}
- return 0xffffffffU;
+ return -EINVAL;
}
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+ return 0;
}
+ return -EINVAL;
}
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -515,35 +533,140 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
*tf = pp->tf;
}
+static void sil24_config_port(struct ata_port *ap)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+
+ /* configure IRQ WoC */
+ if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* clear port multiplier enable and resume bits */
+ writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+}
+
+static void sil24_config_pmp(struct ata_port *ap, int attached)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+
+ if (attached)
+ writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);
+}
+
+static void sil24_clear_pmp(struct ata_port *ap)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+ int i;
+
+ writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+ void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;
+
+ writel(0, pmp_base + PORT_PMP_STATUS);
+ writel(0, pmp_base + PORT_PMP_QACTIVE);
+ }
+}
+
static int sil24_init_port(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
u32 tmp;
+ /* clear PMP error status */
+ if (ap->nr_pmp_links)
+ sil24_clear_pmp(ap);
+
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_INIT, PORT_CS_INIT, 10, 100);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_RDY, 0, 10, 100);
- if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+ if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+ pp->do_port_rst = 1;
+ ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
return -EIO;
+ }
+
return 0;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+ const struct ata_taskfile *tf,
+ int is_cmd, u32 ctrl,
+ unsigned long timeout_msec)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
- u32 mask, irq_stat;
+ u32 irq_enabled, irq_mask, irq_stat;
+ int rc;
+
+ prb->ctrl = cpu_to_le16(ctrl);
+ ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+ /* temporarily plug completion and error interrupts */
+ irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+ writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+ writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+ irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+ 10, timeout_msec);
+
+ writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+ irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+ if (irq_stat & PORT_IRQ_COMPLETE)
+ rc = 0;
+ else {
+ /* force port into known state */
+ sil24_init_port(ap);
+
+ if (irq_stat & PORT_IRQ_ERROR)
+ rc = -EIO;
+ else
+ rc = -EBUSY;
+ }
+
+ /* restore IRQ enabled */
+ writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+ return rc;
+}
+
+static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
+ int pmp, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned long timeout_msec = 0;
+ struct ata_taskfile tf;
const char *reason;
+ int rc;
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
goto out;
@@ -556,29 +679,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
}
/* do SRST */
- prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
- prb->fis[1] = 0; /* no PMP yet */
-
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
- mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
- 100, jiffies_to_msecs(deadline - jiffies));
-
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
- irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
- if (!(irq_stat & PORT_IRQ_COMPLETE)) {
- if (irq_stat & PORT_IRQ_ERROR)
- reason = "SRST command error";
- else
- reason = "timeout";
+ if (time_after(deadline, jiffies))
+ timeout_msec = jiffies_to_msecs(deadline - jiffies);
+
+ ata_tf_init(link->device, &tf); /* doesn't really matter */
+ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+ timeout_msec);
+ if (rc == -EBUSY) {
+ reason = "timeout";
+ goto err;
+ } else if (rc) {
+ reason = "SRST command error";
goto err;
}
- sil24_update_tf(ap);
- *class = ata_dev_classify(&pp->tf);
+ sil24_read_tf(ap, 0, &tf);
+ *class = ata_dev_classify(&tf);
if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
@@ -588,23 +704,54 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
return 0;
err:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
return -EIO;
}
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
+}
+
+static int sil24_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
+ int did_port_rst = 0;
const char *reason;
int tout_msec, rc;
u32 tmp;
+ retry:
+ /* Sometimes, DEV_RST is not enough to recover the controller.
+ * This happens often after PM DMA CS errata.
+ */
+ if (pp->do_port_rst) {
+ ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+ "state, performing PORT_RST\n");
+
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+ msleep(10);
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+ 10, 5000);
+
+ /* restore port configuration */
+ sil24_config_port(ap);
+ sil24_config_pmp(ap, ap->nr_pmp_links);
+
+ pp->do_port_rst = 0;
+ did_port_rst = 1;
+ }
+
/* sil24 does the right thing(tm) without any protection */
- sata_set_spd(ap);
+ sata_set_spd(link);
tout_msec = 100;
- if (ata_port_online(ap))
+ if (ata_link_online(link))
tout_msec = 5000;
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
@@ -614,14 +761,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
+ rc = sata_link_debounce(link, sata_deb_timing_long, deadline);
if (rc) {
reason = "PHY debouncing failed";
goto err;
}
if (tmp & PORT_CS_DEV_RST) {
- if (ata_port_offline(ap))
+ if (ata_link_offline(link))
return 0;
reason = "link not ready";
goto err;
@@ -636,7 +783,12 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
return -EAGAIN;
err:
- ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+ if (!did_port_rst) {
+ pp->do_port_rst = 1;
+ goto retry;
+ }
+
+ ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
return -EIO;
}
@@ -656,6 +808,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
}
}
+static int sil24_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ u8 prot = qc->tf.protocol;
+ int is_atapi = (prot == ATA_PROT_ATAPI ||
+ prot == ATA_PROT_ATAPI_NODATA ||
+ prot == ATA_PROT_ATAPI_DMA);
+
+ /* ATAPI commands completing with CHECK_SENSE cause various
+ * weird problems if other commands are active. PMP DMA CS
+ * errata doesn't cover all and HSM violation occurs even with
+ * only one other device active. Always run an ATAPI command
+ * by itself.
+ */
+ if (unlikely(ap->excl_link)) {
+ if (link == ap->excl_link) {
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ } else
+ return ATA_DEFER_PORT;
+ } else if (unlikely(is_atapi)) {
+ ap->excl_link = link;
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ }
+
+ return ata_std_qc_defer(qc);
+}
+
static void sil24_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -699,7 +883,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, prb->fis, 0);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
@@ -728,6 +912,39 @@ static void sil24_irq_clear(struct ata_port *ap)
/* unused */
}
+static void sil24_pmp_attach(struct ata_port *ap)
+{
+ sil24_config_pmp(ap, 1);
+ sil24_init_port(ap);
+}
+
+static void sil24_pmp_detach(struct ata_port *ap)
+{
+ sil24_init_port(ap);
+ sil24_config_pmp(ap, 0);
+}
+
+static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ return sil24_do_softreset(link, class, link->pmp, deadline);
+}
+
+static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int rc;
+
+ rc = sil24_init_port(link->ap);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "hardreset failed (port not ready)\n");
+ return rc;
+ }
+
+ return sata_pmp_std_hardreset(link, class, deadline);
+}
+
static void sil24_freeze(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
@@ -754,8 +971,11 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
- struct ata_eh_info *ehi = &ap->eh_info;
- int freeze = 0;
+ struct sil24_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc = NULL;
+ struct ata_link *link;
+ struct ata_eh_info *ehi;
+ int abort = 0, freeze = 0;
u32 irq_stat;
/* on error, we need to clear IRQ explicitly */
@@ -763,22 +983,29 @@ static void sil24_error_intr(struct ata_port *ap)
writel(irq_stat, port + PORT_IRQ_STAT);
/* first, analyze and record host port events */
+ link = &ap->link;
+ ehi = &link->eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+ ata_ehi_push_desc(ehi, "SDB notify");
+ sata_async_notification(ap);
+ }
+
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s",
- irq_stat & PORT_IRQ_PHYRDY_CHG ?
- "PHY RDY changed" : "device exchanged");
+ ata_ehi_push_desc(ehi, "%s",
+ irq_stat & PORT_IRQ_PHYRDY_CHG ?
+ "PHY RDY changed" : "device exchanged");
freeze = 1;
}
if (irq_stat & PORT_IRQ_UNK_FIS) {
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi , ", unknown FIS");
+ ata_ehi_push_desc(ehi, "unknown FIS");
freeze = 1;
}
@@ -786,8 +1013,44 @@ static void sil24_error_intr(struct ata_port *ap)
if (irq_stat & PORT_IRQ_ERROR) {
struct sil24_cerr_info *ci = NULL;
unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- u32 cerr;
+ u32 context, cerr;
+ int pmp;
+
+ abort = 1;
+
+ /* DMA Context Switch Failure in Port Multiplier Mode
+ * errata. If we have active commands to 3 or more
+ * devices, any error condition on active devices can
+ * corrupt DMA context switching.
+ */
+ if (ap->nr_active_links >= 3) {
+ ehi->err_mask |= AC_ERR_OTHER;
+ ehi->action |= ATA_EH_HARDRESET;
+ ata_ehi_push_desc(ehi, "PMP DMA CS errata");
+ pp->do_port_rst = 1;
+ freeze = 1;
+ }
+
+ /* find out the offending link and qc */
+ if (ap->nr_pmp_links) {
+ context = readl(port + PORT_CONTEXT);
+ pmp = (context >> 5) & 0xf;
+
+ if (pmp < ap->nr_pmp_links) {
+ link = &ap->pmp_link[pmp];
+ ehi = &link->eh_info;
+ qc = ata_qc_from_tag(ap, link->active_tag);
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x",
+ irq_stat);
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_HARDRESET;
+ freeze = 1;
+ }
+ } else
+ qc = ata_qc_from_tag(ap, link->active_tag);
/* analyze CMD_ERR */
cerr = readl(port + PORT_CMD_ERR);
@@ -797,36 +1060,46 @@ static void sil24_error_intr(struct ata_port *ap)
if (ci && ci->desc) {
err_mask |= ci->err_mask;
action |= ci->action;
- ata_ehi_push_desc(ehi, ", %s", ci->desc);
+ ata_ehi_push_desc(ehi, "%s", ci->desc);
} else {
err_mask |= AC_ERR_OTHER;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown command error %d",
+ ata_ehi_push_desc(ehi, "unknown command error %d",
cerr);
}
/* record error info */
- qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
- sil24_update_tf(ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask;
} else
ehi->err_mask |= err_mask;
ehi->action |= action;
+
+ /* if PMP, resume */
+ if (ap->nr_pmp_links)
+ writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
}
/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ else if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void sil24_finish_qc(struct ata_queued_cmd *qc)
{
+ struct ata_port *ap = qc->ap;
+ struct sil24_port_priv *pp = ap->private_data;
+
if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(qc->ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
}
static inline void sil24_host_intr(struct ata_port *ap)
@@ -835,6 +1108,16 @@ static inline void sil24_host_intr(struct ata_port *ap)
u32 slot_stat, qc_active;
int rc;
+ /* If PCIX_IRQ_WOC, there's an inherent race window between
+ * clearing IRQ pending status and reading PORT_SLOT_STAT
+ * which may cause spurious interrupts afterwards. This is
+ * unavoidable and much better than losing interrupts which
+ * happens if IRQ pending is cleared after reading
+ * PORT_SLOT_STAT.
+ */
+ if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
+
slot_stat = readl(port + PORT_SLOT_STAT);
if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
@@ -842,25 +1125,23 @@ static inline void sil24_host_intr(struct ata_port *ap)
return;
}
- if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
-
qc_active = slot_stat & ~HOST_SSTAT_ATTN;
rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
if (rc > 0)
return;
if (rc < 0) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
ata_port_freeze(ap);
return;
}
- if (ata_ratelimit())
+ /* spurious interrupts are expected if PCIX_IRQ_WOC */
+ if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
"(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
- slot_stat, ap->active_tag, ap->sactive);
+ slot_stat, ap->link.active_tag, ap->link.sactive);
}
static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
@@ -902,16 +1183,18 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
static void sil24_error_handler(struct ata_port *ap)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct sil24_port_priv *pp = ap->private_data;
- if (sil24_init_port(ap)) {
+ if (sil24_init_port(ap))
ata_eh_freeze_port(ap);
- ehc->i.action |= ATA_EH_HARDRESET;
- }
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
- ata_std_postreset);
+ sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+ ata_std_postreset, sata_pmp_std_prereset,
+ sil24_pmp_softreset, sil24_pmp_hardreset,
+ sata_pmp_std_postreset);
+
+ pp->do_port_rst = 0;
}
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -919,8 +1202,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
- sil24_init_port(ap);
+ if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+ ata_eh_freeze_port(ap);
}
static int sil24_port_start(struct ata_port *ap)
@@ -958,7 +1241,6 @@ static int sil24_port_start(struct ata_port *ap)
static void sil24_init_controller(struct ata_host *host)
{
void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
- void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
u32 tmp;
int i;
@@ -970,7 +1252,8 @@ static void sil24_init_controller(struct ata_host *host)
/* init ports */
for (i = 0; i < host->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port = ap->ioaddr.cmd_addr;
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
@@ -987,26 +1270,8 @@ static void sil24_init_controller(struct ata_host *host)
"failed to clear port RST\n");
}
- /* Configure IRQ WoC */
- if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
- port + PORT_CTRL_CLR);
+ /* configure port */
+ sil24_config_port(ap);
}
/* Turn on interrupts */
@@ -1057,12 +1322,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = iomap;
for (i = 0; i < host->n_ports; i++) {
- void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
+ struct ata_port *ap = host->ports[i];
+ size_t offset = ap->port_no * PORT_REGS_SIZE;
+ void __iomem *port = iomap[SIL24_PORT_BAR] + offset;
host->ports[i]->ioaddr.cmd_addr = port;
host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
- ata_std_ports(&host->ports[i]->ioaddr);
+ ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host");
+ ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port");
}
/* configure and activate the device */
@@ -1118,6 +1386,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+
+static int sil24_port_resume(struct ata_port *ap)
+{
+ sil24_config_pmp(ap, ap->nr_pmp_links);
+ return 0;
+}
#endif
static int __init sil24_init(void)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 33716b00c6b7..8d98a9fb0a42 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -43,7 +43,7 @@
#include "sis.h"
#define DRV_NAME "sata_sis"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "1.0"
enum {
sis_180 = 0,
@@ -64,8 +64,8 @@ enum {
};
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
@@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = {
};
static const struct ata_port_operations sis_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -123,7 +122,6 @@ static const struct ata_port_operations sis_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
.port_start = ata_port_start,
@@ -207,36 +205,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val
pci_write_config_dword(pdev, cfg_addr+0x10, val);
}
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 val, val2 = 0;
u8 pmr;
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(ap, sc_reg);
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+ *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+
+ *val &= 0xfffffffb;
- return (val | val2) & 0xfffffffb;
+ return 0;
}
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -248,6 +247,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
}
+ return 0;
}
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 63fe99afd59f..12d613c48c19 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -53,7 +53,7 @@
#endif /* CONFIG_PPC_OF */
#define DRV_NAME "sata_svw"
-#define DRV_VERSION "2.2"
+#define DRV_VERSION "2.3"
enum {
/* ap->flags bits */
@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
return 0;
}
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
@@ -328,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = {
static const struct ata_port_operations k2_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = k2_sata_tf_load,
.tf_read = k2_sata_tf_read,
.check_status = k2_stat_check_status,
@@ -348,7 +348,6 @@ static const struct ata_port_operations k2_sata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = k2_sata_scr_read,
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
@@ -444,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* different controllers have different number of ports - currently 4 or 8 */
/* All ports are on the same function. Multi-function device is no
* longer available. This should not be seen in any system. */
- for (i = 0; i < host->n_ports; i++)
- k2_sata_setup_port(&host->ports[i]->ioaddr,
- mmio_base + i * K2_SATA_PORT_OFFSET);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int offset = i * K2_SATA_PORT_OFFSET;
+
+ k2_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+ ata_port_pbar_desc(ap, 5, -1, "mmio");
+ ata_port_pbar_desc(ap, 5, offset, "port");
+ }
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 5193bd8647ba..9f9f7b30654a 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -92,7 +92,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_sx4"
-#define DRV_VERSION "0.11"
+#define DRV_VERSION "0.12"
enum {
@@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = {
};
static const struct ata_port_operations pdc_20621_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -267,7 +266,6 @@ static const struct ata_port_operations pdc_20621_ops = {
.eng_timeout = pdc_eng_timeout,
.irq_clear = pdc20621_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
};
@@ -854,7 +852,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc20621_host_intr(ap, qc, (i > 4),
mmio_base);
@@ -881,7 +879,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
@@ -1383,9 +1381,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
const struct ata_port_info *ppi[] =
{ &pdc_port_info[ent->driver_data], NULL };
struct ata_host *host;
- void __iomem *base;
struct pdc_host_priv *hpriv;
- int rc;
+ int i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1411,11 +1408,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
return rc;
host->iomap = pcim_iomap_table(pdev);
- base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
- pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
- pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
- pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
- pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
+ for (i = 0; i < 4; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+ unsigned int offset = 0x200 + i * 0x80;
+
+ pdc_sata_setup_port(&ap->ioaddr, base + offset);
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
+ }
/* configure and activate */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index b52f83ab056a..d394da085ae4 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -36,7 +36,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_uli"
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "1.3"
enum {
uli_5289 = 0,
@@ -57,8 +57,8 @@ struct uli_priv {
};
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = {
};
static const struct ata_port_operations uli_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -117,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
@@ -164,20 +161,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
pci_write_config_dword(pdev, cfg_addr, val);
}
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
- return uli_scr_cfg_read(ap, sc_reg);
+ *val = uli_scr_cfg_read(ap, sc_reg);
+ return 0;
}
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
- return;
+ return -EINVAL;
uli_scr_cfg_write(ap, sc_reg, val);
+ return 0;
}
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -240,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[2],
+ "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 0) + 8,
+ ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4,
+ (unsigned long long)pci_resource_start(pdev, 4) + 16);
+
ioaddr = &host->ports[3]->ioaddr;
ioaddr->cmd_addr = iomap[2] + 8;
ioaddr->altstatus_addr =
@@ -248,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr->bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
ata_std_ports(ioaddr);
+
+ ata_port_desc(host->ports[2],
+ "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 2) + 9,
+ ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4,
+ (unsigned long long)pci_resource_start(pdev, 4) + 24);
+
break;
case uli_5289:
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index c4124475f754..1dc9b4f2b2dc 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_via"
-#define DRV_VERSION "2.2"
+#define DRV_VERSION "2.3"
enum board_ids_enum {
vt6420,
@@ -57,7 +57,6 @@ enum {
SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */
- SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
PATA_PIO_TIMING = 0xAB, /* PATA timing register */
@@ -68,12 +67,11 @@ enum {
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
- SATA_2DEV = (1 << 5), /* SATA is master/slave */
};
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -122,8 +120,6 @@ static struct scsi_host_template svia_sht = {
};
static const struct ata_port_operations vt6420_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -146,14 +142,11 @@ static const struct ata_port_operations vt6420_sata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_pata_ops = {
- .port_disable = ata_port_disable,
-
.set_piomode = vt6421_set_pio_mode,
.set_dmamode = vt6421_set_dma_mode,
@@ -180,14 +173,11 @@ static const struct ata_port_operations vt6421_pata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -211,7 +201,6 @@ static const struct ata_port_operations vt6421_sata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
@@ -249,18 +238,20 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return -EINVAL;
+ *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
}
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
}
static void svia_noop_freeze(struct ata_port *ap)
@@ -274,7 +265,7 @@ static void svia_noop_freeze(struct ata_port *ap)
/**
* vt6420_prereset - prereset for vt6420
- * @ap: target ATA port
+ * @link: target ATA link
* @deadline: deadline jiffies for the operation
*
* SCR registers on vt6420 are pieces of shit and may hang the
@@ -292,9 +283,10 @@ static void svia_noop_freeze(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
+static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
unsigned long timeout = jiffies + (HZ * 5);
u32 sstatus, scontrol;
int online;
@@ -305,18 +297,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
/* Resume phy. This is the old SATA resume sequence */
svia_scr_write(ap, SCR_CONTROL, 0x300);
- svia_scr_read(ap, SCR_CONTROL); /* flush */
+ svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
+ if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */
- sstatus = svia_scr_read(ap, SCR_STATUS);
- scontrol = svia_scr_read(ap, SCR_CONTROL);
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
+ svia_scr_read(ap, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3;
@@ -325,7 +318,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */
- svia_scr_read(ap, SCR_STATUS);
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
if (!online) {
/* tell EH to bail */
@@ -368,7 +361,7 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
- pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
+ pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->dma_mode - XFER_UDMA_0]);
}
static const unsigned int svia_bar_sizes[] = {
@@ -404,6 +397,9 @@ static void vt6421_init_addrs(struct ata_port *ap)
ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
ata_std_ports(ioaddr);
+
+ ata_port_pbar_desc(ap, ap->port_no, -1, "port");
+ ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma");
}
static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
@@ -510,7 +506,6 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_host *host;
int board_id = (int) ent->driver_data;
const int *bar_sizes;
- u8 tmp8;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -519,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if (board_id == vt6420) {
- pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
- if (tmp8 & SATA_2DEV) {
- dev_printk(KERN_ERR, &pdev->dev,
- "SATA master/slave not supported (0x%x)\n",
- (int) tmp8);
- return -EIO;
- }
-
+ if (board_id == vt6420)
bar_sizes = &svia_bar_sizes[0];
- } else {
+ else
bar_sizes = &vt6421_bar_sizes[0];
- }
for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
if ((pci_resource_start(pdev, i) == 0) ||
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1b5d81faa102..0d9be1684873 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -47,7 +47,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_vsc"
-#define DRV_VERSION "2.2"
+#define DRV_VERSION "2.3"
enum {
VSC_MMIO_BAR = 0,
@@ -98,20 +98,21 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
@@ -239,7 +240,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
return;
}
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled = ata_host_intr(ap, qc);
@@ -316,7 +317,6 @@ static struct scsi_host_template vsc_sata_sht = {
static const struct ata_port_operations vsc_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = vsc_sata_tf_load,
.tf_read = vsc_sata_tf_read,
.exec_command = ata_exec_command,
@@ -335,7 +335,6 @@ static const struct ata_port_operations vsc_sata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = vsc_sata_scr_read,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
@@ -407,9 +406,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
mmio_base = host->iomap[VSC_MMIO_BAR];
- for (i = 0; i < host->n_ports; i++)
- vsc_sata_setup_port(&host->ports[i]->ioaddr,
- mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET;
+
+ vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+ ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port");
+ }
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index bb4ae6281491..b554edac1ced 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -6,6 +6,11 @@ menuconfig ATM_DRIVERS
bool "ATM drivers"
depends on NETDEVICES && ATM
default y
+ ---help---
+ Say Y here to get to see options for Asynchronous Transfer Mode
+ device drivers. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if ATM_DRIVERS && NETDEVICES && ATM
@@ -172,7 +177,7 @@ config ATM_ZATM_DEBUG
config ATM_NICSTAR
tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
- depends on PCI && !64BIT
+ depends on PCI && !64BIT && VIRT_TO_BUS
help
The NICStAR chipset family is used in a large number of ATM NICs for
25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 77637e780d41..41b2204ebc6e 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1738,7 +1738,8 @@ static int __devinit eni_do_init(struct atm_dev *dev)
printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
"magic - expected 0x%x, got 0x%x\n",dev->number,
ENI155_MAGIC,(unsigned) readl(&eprom->magic));
- return -EINVAL;
+ error = -EINVAL;
+ goto unmap;
}
}
eni_dev->phy = base+PHY_BASE;
@@ -1765,17 +1766,27 @@ static int __devinit eni_do_init(struct atm_dev *dev)
printk(")\n");
printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
- return -EINVAL;
+ error = -EINVAL;
+ goto unmap;
}
error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
- if (error) return error;
+ if (error)
+ goto unmap;
for (i = 0; i < ESI_LEN; i++)
printk("%s%02X",i ? "-" : "",dev->esi[i]);
printk(")\n");
printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
- return suni_init(dev);
+
+ error = suni_init(dev);
+ if (error)
+ goto unmap;
+out:
+ return error;
+unmap:
+ iounmap(base);
+ goto out;
}
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 38b688f9f6a9..737cea49f872 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1710,7 +1710,7 @@ static int __devinit fs_init (struct fs_dev *dev)
/* This bit is documented as "RESERVED" */
if (isr & ISR_INIT_ERR) {
printk (KERN_ERR "Error initializing the FS... \n");
- return 1;
+ goto unmap;
}
if (isr & ISR_INIT) {
fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
@@ -1723,7 +1723,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (!to) {
printk (KERN_ERR "timeout initializing the FS... \n");
- return 1;
+ goto unmap;
}
/* XXX fix for fs155 */
@@ -1803,7 +1803,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (!dev->atm_vccs) {
printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
/* XXX Clean up..... */
- return 1;
+ goto unmap;
}
dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
@@ -1813,7 +1813,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (!dev->tx_inuse) {
printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
/* XXX Clean up..... */
- return 1;
+ goto unmap;
}
/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
/* -- RAS2 : FS50 only: Default is OK. */
@@ -1840,7 +1840,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
/* XXX undo all previous stuff... */
- return 1;
+ goto unmap;
}
fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
@@ -1890,6 +1890,9 @@ static int __devinit fs_init (struct fs_dev *dev)
func_exit ();
return 0;
+unmap:
+ iounmap(dev->base);
+ return 1;
}
static int __devinit firestream_init_one (struct pci_dev *pci_dev,
@@ -2012,6 +2015,7 @@ static void __devexit firestream_remove_one (struct pci_dev *pdev)
for (i=0;i < FS_NR_RX_QUEUES;i++)
free_queue (dev, &dev->rx_rq[i]);
+ iounmap(dev->base);
fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
nxtdev = dev->next;
kfree (dev);
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 405ee5e09221..8b12925fe7a4 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -2435,7 +2435,7 @@ fore200e_init_cmd_queue(struct fore200e* fore200e)
}
-static void __init
+static void __devinit
fore200e_param_bs_queue(struct fore200e* fore200e,
enum buffer_scheme scheme, enum buffer_magn magn,
int queue_length, int pool_size, int supply_blksize)
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 8f995ce8d73b..eee54c0cde68 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -65,7 +65,7 @@ static char const rcsid[] =
static unsigned int vpibits = 1;
-#define CONFIG_ATM_IDT77252_SEND_IDLE 1
+#define ATM_IDT77252_SEND_IDLE 1
/*
@@ -3404,7 +3404,7 @@ init_card(struct atm_dev *dev)
conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */
SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */
SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */
-#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifndef ATM_IDT77252_SEND_IDLE
SAR_CFG_NO_IDLE | /* Do not send idle cells */
#endif
0;
@@ -3541,7 +3541,7 @@ init_card(struct atm_dev *dev)
printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
card->name, linkrate, card->link_pcr);
-#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifdef ATM_IDT77252_SEND_IDLE
card->utopia_pcr = card->link_pcr;
#else
card->utopia_pcr = (160000000 / 8 / 54);
@@ -3576,7 +3576,7 @@ init_card(struct atm_dev *dev)
* XXX: <hack>
*/
sprintf(tname, "eth%d", card->index);
- tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */
+ tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */
if (tmp) {
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index a3b605a0ca17..ef52452640e0 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -1601,14 +1601,14 @@ static int rx_init(struct atm_dev *dev)
skb_queue_head_init(&iadev->rx_dma_q);
iadev->rx_free_desc_qhead = NULL;
- iadev->rx_open = kmalloc(4*iadev->num_vc,GFP_KERNEL);
- if (!iadev->rx_open)
- {
+
+ iadev->rx_open = kzalloc(4 * iadev->num_vc, GFP_KERNEL);
+ if (!iadev->rx_open) {
printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n",
dev->number);
goto err_free_dle;
}
- memset(iadev->rx_open, 0, 4*iadev->num_vc);
+
iadev->rxing = 1;
iadev->rx_pkt_cnt = 0;
/* Mode Register */
@@ -3171,12 +3171,12 @@ static int __devinit ia_init_one(struct pci_dev *pdev,
unsigned long flags;
int ret;
- iadev = kmalloc(sizeof(*iadev), GFP_KERNEL);
+ iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
if (!iadev) {
ret = -ENOMEM;
goto err_out;
}
- memset(iadev, 0, sizeof(*iadev));
+
iadev->pci = pdev;
IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 0e2c1ae650e7..144a49f15220 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -65,7 +65,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
/* -------------------- TUNABLE PARAMATERS: */
@@ -552,8 +551,8 @@ static inline void sram_write(const struct lanai_dev *lanai,
writel(val, sram_addr(lanai, offset));
}
-static int __init sram_test_word(
- const struct lanai_dev *lanai, int offset, u32 pattern)
+static int __devinit sram_test_word(const struct lanai_dev *lanai,
+ int offset, u32 pattern)
{
u32 readback;
sram_write(lanai, pattern, offset);
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 480947f4e01e..842e26c45557 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -134,7 +134,7 @@ nicstar_read_eprom_status( virt_addr_t base )
/* Send read instruction */
val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
- for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++)
+ for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
{
NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
(val | rdsrtab[i]) );
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index de2fcce10ba5..043353bd0600 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -8,6 +8,11 @@
menuconfig AUXDISPLAY
depends on PARPORT
bool "Auxiliary Display support"
+ ---help---
+ Say Y here to get to see options for auxiliary display drivers.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if AUXDISPLAY && PARPORT
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c
index cb44cb4f6a47..80bb06105387 100644
--- a/drivers/auxdisplay/cfag12864b.c
+++ b/drivers/auxdisplay/cfag12864b.c
@@ -355,7 +355,7 @@ static int __init cfag12864b_init(void)
cfag12864b_cache = kmalloc(sizeof(unsigned char) *
CFAG12864B_SIZE, GFP_KERNEL);
- if (cfag12864b_buffer == NULL) {
+ if (cfag12864b_cache == NULL) {
printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
"can't alloc cache buffer (%i bytes)\n",
CFAG12864B_SIZE);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5d6312e33490..d7da109c24fd 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -1,5 +1,13 @@
menu "Generic Driver Options"
+config UEVENT_HELPER_PATH
+ string "path to uevent helper"
+ depends on HOTPLUG
+ default "/sbin/hotplug"
+ help
+ Path to uevent helper program forked by the kernel for
+ every uevent.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 47eb02d9f1af..10b2fb6c9ce6 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -18,8 +18,6 @@ extern int attribute_container_init(void);
extern int bus_add_device(struct device * dev);
extern void bus_attach_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
-extern struct bus_type *get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
extern int bus_add_driver(struct device_driver *);
extern void bus_remove_driver(struct device_driver *);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 61c67526a656..9a19b071c573 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -30,6 +30,17 @@
static int __must_check bus_rescan_devices_helper(struct device *dev,
void *data);
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+ return bus ? container_of(kset_get(&bus->subsys),
+ struct bus_type, subsys) : NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+ kset_put(&bus->subsys);
+}
+
static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
@@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj)
*/
}
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
@@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = {
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
- if (get_bus(bus)) {
+ if (bus_get(bus)) {
error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
- put_bus(bus);
+ bus_put(bus);
} else
error = -EINVAL;
return error;
@@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
- if (get_bus(bus)) {
+ if (bus_get(bus)) {
sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
- put_bus(bus);
+ bus_put(bus);
}
}
@@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data)
static ssize_t driver_unbind(struct device_driver *drv,
const char *buf, size_t count)
{
- struct bus_type *bus = get_bus(drv->bus);
+ struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
@@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv,
err = count;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
static ssize_t driver_bind(struct device_driver *drv,
const char *buf, size_t count)
{
- struct bus_type *bus = get_bus(drv->bus);
+ struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
@@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv,
err = -ENODEV;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
*/
int bus_add_device(struct device * dev)
{
- struct bus_type * bus = get_bus(dev->bus);
+ struct bus_type * bus = bus_get(dev->bus);
int error = 0;
if (bus) {
@@ -459,7 +470,7 @@ out_subsys:
out_id:
device_remove_attrs(bus, dev);
out_put:
- put_bus(dev->bus);
+ bus_put(dev->bus);
return error;
}
@@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev)
}
pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
device_release_driver(dev);
- put_bus(dev->bus);
+ bus_put(dev->bus);
}
}
@@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv)
driver_remove_file(drv, &driver_attr_unbind);
}
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+ show_drivers_autoprobe, store_drivers_autoprobe);
+
static int add_probe_files(struct bus_type *bus)
{
int retval;
- bus->drivers_probe_attr.attr.name = "drivers_probe";
- bus->drivers_probe_attr.attr.mode = S_IWUSR;
- bus->drivers_probe_attr.store = store_drivers_probe;
- retval = bus_create_file(bus, &bus->drivers_probe_attr);
+ retval = bus_create_file(bus, &bus_attr_drivers_probe);
if (retval)
goto out;
- bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
- bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
- bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
- bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
- retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+ retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
if (retval)
- bus_remove_file(bus, &bus->drivers_probe_attr);
+ bus_remove_file(bus, &bus_attr_drivers_probe);
out:
return retval;
}
static void remove_probe_files(struct bus_type *bus)
{
- bus_remove_file(bus, &bus->drivers_autoprobe_attr);
- bus_remove_file(bus, &bus->drivers_probe_attr);
+ bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+ bus_remove_file(bus, &bus_attr_drivers_probe);
}
#else
static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; }
static inline void remove_probe_files(struct bus_type *bus) {}
#endif
+static ssize_t driver_uevent_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0)
+ kobject_uevent(&drv->kobj, action);
+ return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
@@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {}
*/
int bus_add_driver(struct device_driver *drv)
{
- struct bus_type * bus = get_bus(drv->bus);
+ struct bus_type * bus = bus_get(drv->bus);
int error = 0;
if (!bus)
@@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv)
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
+ error = driver_create_file(drv, &driver_attr_uevent);
+ if (error) {
+ printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+ __FUNCTION__, drv->name);
+ }
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
@@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv)
out_unregister:
kobject_unregister(&drv->kobj);
out_put_bus:
- put_bus(bus);
+ bus_put(bus);
return error;
}
@@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv)
remove_bind_files(drv);
driver_remove_attrs(drv->bus, drv);
+ driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->knode_bus);
pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
driver_detach(drv);
module_remove_driver(drv);
kobject_unregister(&drv->kobj);
- put_bus(drv->bus);
+ bus_put(drv->bus);
}
@@ -729,18 +754,6 @@ int device_reprobe(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_reprobe);
-struct bus_type *get_bus(struct bus_type *bus)
-{
- return bus ? container_of(subsys_get(&bus->subsys),
- struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
- subsys_put(&bus->subsys);
-}
-
-
/**
* find_bus - locate bus by name.
* @name: name of bus.
@@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n)
put_device(dev);
}
+static ssize_t bus_uevent_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0)
+ kobject_uevent(&bus->subsys.kobj, action);
+ return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
/**
* bus_register - register a bus with the system.
* @bus: bus.
@@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus)
if (retval)
goto out;
- subsys_set_kset(bus, bus_subsys);
+ bus->subsys.kobj.kset = &bus_subsys;
+
retval = subsystem_register(&bus->subsys);
if (retval)
goto out;
+ retval = bus_create_file(bus, &bus_attr_uevent);
+ if (retval)
+ goto bus_uevent_fail;
+
kobject_set_name(&bus->devices.kobj, "devices");
bus->devices.kobj.parent = &bus->subsys.kobj;
retval = kset_register(&bus->devices);
@@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus)
kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.kobj.parent = &bus->subsys.kobj;
- bus->drivers.ktype = &ktype_driver;
+ bus->drivers.ktype = &driver_ktype;
retval = kset_register(&bus->drivers);
if (retval)
goto bus_drivers_fail;
@@ -866,6 +895,8 @@ bus_probe_files_fail:
bus_drivers_fail:
kset_unregister(&bus->devices);
bus_devices_fail:
+ bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
subsystem_unregister(&bus->subsys);
out:
return retval;
@@ -876,7 +907,7 @@ out:
* @bus: bus.
*
* Unregister the child subsystems and the bus itself.
- * Finally, we call put_bus() to release the refcount
+ * Finally, we call bus_put() to release the refcount
*/
void bus_unregister(struct bus_type * bus)
{
@@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus)
remove_probe_files(bus);
kset_unregister(&bus->drivers);
kset_unregister(&bus->devices);
+ bus_remove_file(bus, &bus_attr_uevent);
subsystem_unregister(&bus->subsys);
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4d2222618b78..a863bb091e11 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = {
.store = class_attr_store,
};
-static struct kobj_type ktype_class = {
+static struct kobj_type class_ktype = {
.sysfs_ops = &class_sysfs_ops,
.release = class_release,
};
/* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &ktype_class, NULL);
+static decl_subsys(class, &class_ktype, NULL);
int class_create_file(struct class * cls, const struct class_attribute * attr)
@@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
static struct class *class_get(struct class *cls)
{
if (cls)
- return container_of(subsys_get(&cls->subsys), struct class, subsys);
+ return container_of(kset_get(&cls->subsys), struct class, subsys);
return NULL;
}
static void class_put(struct class * cls)
{
if (cls)
- subsys_put(&cls->subsys);
+ kset_put(&cls->subsys);
}
@@ -149,7 +149,7 @@ int class_register(struct class * cls)
if (error)
return error;
- subsys_set_kset(cls, class_subsys);
+ cls->subsys.kobj.kset = &class_subsys;
error = subsystem_register(&cls->subsys);
if (!error) {
@@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev)
/* needed to allow these devices to have parent class devices */
static int class_device_create_uevent(struct class_device *class_dev,
- char **envp, int num_envp,
- char *buffer, int buffer_size)
+ struct kobj_uevent_env *env)
{
pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
return 0;
@@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj)
}
}
-static struct kobj_type ktype_class_device = {
+static struct kobj_type class_device_ktype = {
.sysfs_ops = &class_dev_sysfs_ops,
.release = class_dev_release,
};
@@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
- if (ktype == &ktype_class_device) {
+ if (ktype == &class_device_ktype) {
struct class_device *class_dev = to_class_dev(kobj);
if (class_dev->class)
return 1;
@@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd)
{ }
#endif
-static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+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 i = 0;
- int length = 0;
int retval = 0;
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
if (MAJOR(class_dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(class_dev->devt));
+ add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(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(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
if (dev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
if (class_dev->uevent) {
/* have the class device specific function add its stuff */
- retval = class_dev->uevent(class_dev, envp, num_envp,
- buffer, buffer_size);
+ 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, envp, num_envp,
- buffer, buffer_size);
+ retval = class_dev->class->uevent(class_dev, env);
if (retval)
pr_debug("class->uevent() returned %d\n", retval);
}
@@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = {
.uevent = class_uevent,
};
-static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
+static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
static int class_device_add_attrs(struct class_device * cd)
@@ -883,7 +861,7 @@ int __init classes_init(void)
/* ick, this is ugly, the things we go through to keep from showing up
* in sysfs... */
- subsystem_init(&class_obj_subsys);
+ kset_init(&class_obj_subsys);
if (!class_obj_subsys.kobj.parent)
class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
return 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 0455aa78fa13..c1343414d285 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj)
}
}
-static struct kobj_type ktype_device = {
+static struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
};
@@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
- if (ktype == &ktype_device) {
+ if (ktype == &device_ktype) {
struct device *dev = to_dev(kobj);
if (dev->uevent_suppress)
return 0;
@@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
return NULL;
}
-static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int dev_uevent(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env)
{
struct device *dev = to_dev(kobj);
- int i = 0;
- int length = 0;
int retval = 0;
/* add the major/minor if present */
if (MAJOR(dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(dev->devt));
+ add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
+ add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
}
if (dev->type && dev->type->name)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVTYPE=%s", dev->type->name);
+ add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "DRIVER=%s", dev->driver->name);
#ifdef CONFIG_SYSFS_DEPRECATED
if (dev->class) {
@@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
path = kobject_get_path(&parent->kobj, GFP_KERNEL);
if (path) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", parent->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
if (parent->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", parent->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s",
+ parent->driver->name);
}
} else if (dev->bus) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}
#endif
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
+ /* have the bus specific function add its stuff */
if (dev->bus && dev->bus->uevent) {
- /* have the bus specific function add its stuff */
- retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->bus->uevent(dev, env);
if (retval)
pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
}
+ /* have the class specific function add its stuff */
if (dev->class && dev->class->dev_uevent) {
- /* have the class specific function add its stuff */
- retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->class->dev_uevent(dev, env);
if (retval)
pr_debug("%s: class uevent() returned %d\n",
__FUNCTION__, retval);
}
+ /* have the device type specific fuction add its stuff */
if (dev->type && dev->type->uevent) {
- /* have the device type specific fuction add its stuff */
- retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->type->uevent(dev, env);
if (retval)
pr_debug("%s: dev_type uevent() returned %d\n",
__FUNCTION__, retval);
@@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
{
struct kobject *top_kobj;
struct kset *kset;
- char *envp[32];
- char *data = NULL;
- char *pos;
+ struct kobj_uevent_env *env = NULL;
int i;
size_t count = 0;
int retval;
/* search the kset, the device belongs to */
top_kobj = &dev->kobj;
- if (!top_kobj->kset && top_kobj->parent) {
- do {
- top_kobj = top_kobj->parent;
- } while (!top_kobj->kset && top_kobj->parent);
- }
+ while (!top_kobj->kset && top_kobj->parent)
+ top_kobj = top_kobj->parent;
if (!top_kobj->kset)
goto out;
+
kset = top_kobj->kset;
if (!kset->uevent_ops || !kset->uevent_ops->uevent)
goto out;
@@ -278,35 +248,37 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
if (!kset->uevent_ops->filter(kset, &dev->kobj))
goto out;
- data = (char *)get_zeroed_page(GFP_KERNEL);
- if (!data)
+ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+ if (!env)
return -ENOMEM;
/* let the kset specific function add its keys */
- pos = data;
- retval = kset->uevent_ops->uevent(kset, &dev->kobj,
- envp, ARRAY_SIZE(envp),
- pos, PAGE_SIZE);
+ retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
if (retval)
goto out;
/* copy keys to file */
- for (i = 0; envp[i]; i++) {
- pos = &buf[count];
- count += sprintf(pos, "%s\n", envp[i]);
- }
+ for (i = 0; i < env->envp_idx; i++)
+ count += sprintf(&buf[count], "%s\n", env->envp[i]);
out:
- free_page((unsigned long)data);
+ kfree(env);
return count;
}
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- if (memcmp(buf, "add", 3) != 0)
- dev_err(dev, "uevent: unsupported action-string; this will "
- "be ignored in a future kernel version");
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0) {
+ kobject_uevent(&dev->kobj, action);
+ goto out;
+ }
+
+ dev_err(dev, "uevent: unsupported action-string; this will "
+ "be ignored in a future kernel version\n");
kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
return count;
}
@@ -433,7 +405,7 @@ static struct device_attribute devt_attr =
* devices_subsys - structure to be registered with kobject core.
*/
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+decl_subsys(devices, &device_ktype, &device_uevent_ops);
/**
@@ -570,9 +542,13 @@ void device_initialize(struct device *dev)
static struct kobject * get_device_parent(struct device *dev,
struct device *parent)
{
- /* Set the parent to the class, not the parent device */
- /* this keeps sysfs from having a symlink to make old udevs happy */
- if (dev->class)
+ /*
+ * Set the parent to the class, not the parent device
+ * for topmost devices in class hierarchy.
+ * This keeps sysfs from having a symlink to make old
+ * udevs happy
+ */
+ if (dev->class && (!parent || parent->class != dev->class))
return &dev->class->subsys.kobj;
else if (parent)
return &parent->kobj;
@@ -643,6 +619,98 @@ static int setup_parent(struct device *dev, struct device *parent)
return 0;
}
+static int device_add_class_symlinks(struct device *dev)
+{
+ int error;
+
+ if (!dev->class)
+ return 0;
+ error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
+ "subsystem");
+ if (error)
+ goto out;
+ /*
+ * If this is not a "fake" compatible device, then create the
+ * symlink from the class to the device.
+ */
+ if (dev->kobj.parent != &dev->class->subsys.kobj) {
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+ dev->bus_id);
+ if (error)
+ goto out_subsys;
+ }
+ if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+ {
+ struct device *parent = dev->parent;
+ char *class_name;
+
+ /*
+ * In old sysfs stacked class devices had 'device'
+ * link pointing to real device instead of parent
+ */
+ while (parent->class && !parent->bus && parent->parent)
+ parent = parent->parent;
+
+ error = sysfs_create_link(&dev->kobj,
+ &parent->kobj,
+ "device");
+ if (error)
+ goto out_busid;
+
+ class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ error = sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, class_name);
+ kfree(class_name);
+ if (error)
+ goto out_device;
+ }
+#else
+ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ if (error)
+ goto out_busid;
+#endif
+ }
+ return 0;
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+out_device:
+ if (dev->parent)
+ sysfs_remove_link(&dev->kobj, "device");
+#endif
+out_busid:
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+out_subsys:
+ sysfs_remove_link(&dev->kobj, "subsystem");
+out:
+ return error;
+}
+
+static void device_remove_class_symlinks(struct device *dev)
+{
+ if (!dev->class)
+ return;
+ if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+ char *class_name;
+
+ class_name = make_class_name(dev->class->name, &dev->kobj);
+ if (class_name) {
+ sysfs_remove_link(&dev->parent->kobj, class_name);
+ kfree(class_name);
+ }
+#endif
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+ sysfs_remove_link(&dev->kobj, "subsystem");
+}
+
/**
* device_add - add device to device hierarchy.
* @dev: device.
@@ -657,7 +725,6 @@ static int setup_parent(struct device *dev, struct device *parent)
int device_add(struct device *dev)
{
struct device *parent = NULL;
- char *class_name = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
@@ -697,27 +764,9 @@ int device_add(struct device *dev)
goto ueventattrError;
}
- if (dev->class) {
- sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
- "subsystem");
- /* If this is not a "fake" compatible device, then create the
- * symlink from the class to the device. */
- if (dev->kobj.parent != &dev->class->subsys.kobj)
- sysfs_create_link(&dev->class->subsys.kobj,
- &dev->kobj, dev->bus_id);
- if (parent) {
- sysfs_create_link(&dev->kobj, &dev->parent->kobj,
- "device");
-#ifdef CONFIG_SYSFS_DEPRECATED
- class_name = make_class_name(dev->class->name,
- &dev->kobj);
- if (class_name)
- sysfs_create_link(&dev->parent->kobj,
- &dev->kobj, class_name);
-#endif
- }
- }
-
+ error = device_add_class_symlinks(dev);
+ if (error)
+ goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
@@ -744,7 +793,6 @@ int device_add(struct device *dev)
up(&dev->class->sem);
}
Done:
- kfree(class_name);
put_device(dev);
return error;
BusError:
@@ -755,6 +803,8 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
+ device_remove_class_symlinks(dev);
+ SymlinkError:
if (MAJOR(dev->devt))
device_remove_file(dev, &devt_attr);
@@ -1139,7 +1189,7 @@ int device_rename(struct device *dev, char *new_name)
{
char *old_class_name = NULL;
char *new_class_name = NULL;
- char *old_symlink_name = NULL;
+ char *old_device_name = NULL;
int error;
dev = get_device(dev);
@@ -1153,42 +1203,49 @@ int device_rename(struct device *dev, char *new_name)
old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif
- if (dev->class) {
- old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
- if (!old_symlink_name) {
- error = -ENOMEM;
- goto out_free_old_class;
- }
- strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+ old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+ if (!old_device_name) {
+ error = -ENOMEM;
+ goto out;
}
-
+ strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
error = kobject_rename(&dev->kobj, new_name);
+ if (error) {
+ strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+ goto out;
+ }
#ifdef CONFIG_SYSFS_DEPRECATED
if (old_class_name) {
new_class_name = make_class_name(dev->class->name, &dev->kobj);
if (new_class_name) {
- sysfs_create_link(&dev->parent->kobj, &dev->kobj,
- new_class_name);
+ error = sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, new_class_name);
+ if (error)
+ goto out;
sysfs_remove_link(&dev->parent->kobj, old_class_name);
}
}
#endif
if (dev->class) {
- sysfs_remove_link(&dev->class->subsys.kobj,
- old_symlink_name);
- sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
- dev->bus_id);
+ sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+ dev->bus_id);
+ if (error) {
+ /* Uh... how to unravel this if restoring can fail? */
+ dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
+ __FUNCTION__, error);
+ }
}
+out:
put_device(dev);
kfree(new_class_name);
- kfree(old_symlink_name);
- out_free_old_class:
kfree(old_class_name);
+ kfree(old_device_name);
return error;
}
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index fe7ef3394144..40545071e3c9 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -53,7 +53,7 @@ static ssize_t store_online(struct sys_device *dev, const char *buf,
ret = count;
return ret;
}
-static SYSDEV_ATTR(online, 0600, show_online, store_online);
+static SYSDEV_ATTR(online, 0644, show_online, store_online);
static void __devinit register_cpu_control(struct cpu *cpu)
{
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 53f0ee6f3016..0295855a3eef 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
static void fw_dev_release(struct device *dev);
-static int firmware_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
- int i = 0, len = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "FIRMWARE=%s", fw_priv->fw_id))
+ if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "TIMEOUT=%i", loading_timeout))
+ if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
@@ -232,6 +227,7 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
/**
* firmware_data_write - write method for firmware
* @kobj: kobject for the device
+ * @bin_attr: bin_attr structure
* @buffer: buffer being written
* @offset: buffer offset for write in total data store area
* @count: buffer size
@@ -296,8 +292,7 @@ firmware_class_timeout(u_long data)
static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
{
- /* XXX warning we should watch out for name collisions */
- strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
+ snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
}
static int fw_register_device(struct device **dev_p, const char *fw_name,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 74b96795d2f5..cb99daeae936 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
return MEMORY_CLASS_NAME;
}
-static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env)
{
int retval = 0;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 869ff8c00146..fb5609241482 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev)
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
- *
- * This device will be marked as not supporting hotpluggable drivers; no
- * device add/remove uevents will be generated. In the unusual case that
- * the device isn't being dynamically allocated as a legacy "probe the
- * hardware" driver, infrastructure code should reverse this marking.
*/
-struct platform_device *platform_device_alloc(const char *name, unsigned int id)
+struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;
@@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id)
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
-
- /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
- * legacy probe-the-hardware drivers, which don't properly split
- * out device enumeration logic from drivers.
- */
- pa->pdev.dev.uevent_suppress = 1;
}
return pa ? &pa->pdev : NULL;
@@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev)
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
- snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
+ snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
+ pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
@@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
* the Linux driver model. In particular, when such drivers are built
* as modules, they can't be "hotplugged".
*/
-struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+struct platform_device *platform_device_register_simple(char *name, int id,
struct resource *res, unsigned int num)
{
struct platform_device *pdev;
@@ -530,7 +520,7 @@ static ssize_t
modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
- int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+ int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
@@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = {
__ATTR_NULL,
};
-static int platform_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
- envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+ add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
return 0;
}
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 91f230939c1e..a803733c839e 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,10 +1,10 @@
obj-y := shutdown.o
-obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o
obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG
endif
-ifeq ($(CONFIG_PM_DEBUG),y)
+ifeq ($(CONFIG_PM_VERBOSE),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index eb9f38d0aa58..0ab4ab21f564 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -20,19 +20,24 @@
*/
#include <linux/device.h>
+#include <linux/kallsyms.h>
#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/resume-trace.h>
+#include "../base.h"
#include "power.h"
LIST_HEAD(dpm_active);
-LIST_HEAD(dpm_off);
-LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_off);
+static LIST_HEAD(dpm_off_irq);
-DEFINE_MUTEX(dpm_mtx);
-DEFINE_MUTEX(dpm_list_mtx);
+static DEFINE_MUTEX(dpm_mtx);
+static DEFINE_MUTEX(dpm_list_mtx);
int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
int device_pm_add(struct device *dev)
{
int error;
@@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev)
}
+/*------------------------- Resume routines -------------------------*/
+
+/**
+ * resume_device - Restore state for one device.
+ * @dev: Device.
+ *
+ */
+
+static int resume_device(struct device * dev)
+{
+ int error = 0;
+
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+
+ down(&dev->sem);
+
+ if (dev->bus && dev->bus->resume) {
+ dev_dbg(dev,"resuming\n");
+ error = dev->bus->resume(dev);
+ }
+
+ if (!error && dev->type && dev->type->resume) {
+ dev_dbg(dev,"resuming\n");
+ error = dev->type->resume(dev);
+ }
+
+ if (!error && dev->class && dev->class->resume) {
+ dev_dbg(dev,"class resume\n");
+ error = dev->class->resume(dev);
+ }
+
+ up(&dev->sem);
+
+ TRACE_RESUME(error);
+ return error;
+}
+
+
+static int resume_device_early(struct device * dev)
+{
+ int error = 0;
+
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+ if (dev->bus && dev->bus->resume_early) {
+ dev_dbg(dev,"EARLY resume\n");
+ error = dev->bus->resume_early(dev);
+ }
+ TRACE_RESUME(error);
+ return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
+static void dpm_resume(void)
+{
+ mutex_lock(&dpm_list_mtx);
+ while(!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.next;
+ struct device * dev = to_device(entry);
+
+ get_device(dev);
+ list_move_tail(entry, &dpm_active);
+
+ mutex_unlock(&dpm_list_mtx);
+ resume_device(dev);
+ mutex_lock(&dpm_list_mtx);
+ put_device(dev);
+ }
+ mutex_unlock(&dpm_list_mtx);
+}
+
+
+/**
+ * device_resume - Restore state of each device in system.
+ *
+ * Walk the dpm_off list, remove each entry, resume the device,
+ * then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+ might_sleep();
+ mutex_lock(&dpm_mtx);
+ dpm_resume();
+ mutex_unlock(&dpm_mtx);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ * dpm_power_up - Power on some devices.
+ *
+ * Walk the dpm_off_irq list and power each device up. This
+ * is used for devices that required they be powered down with
+ * interrupts disabled. As devices are powered on, they are moved
+ * to the dpm_active list.
+ *
+ * Interrupts must be disabled when calling this.
+ */
+
+static void dpm_power_up(void)
+{
+ while(!list_empty(&dpm_off_irq)) {
+ struct list_head * entry = dpm_off_irq.next;
+ struct device * dev = to_device(entry);
+
+ list_move_tail(entry, &dpm_off);
+ resume_device_early(dev);
+ }
+}
+
+
+/**
+ * device_power_up - Turn on all devices that need special attention.
+ *
+ * Power on system devices then devices that required we shut them down
+ * with interrupts disabled.
+ * Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+ sysdev_resume();
+ dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
+/*------------------------- Suspend routines -------------------------*/
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+static inline char *suspend_verb(u32 event)
+{
+ switch (event) {
+ case PM_EVENT_SUSPEND: return "suspend";
+ case PM_EVENT_FREEZE: return "freeze";
+ case PM_EVENT_PRETHAW: return "prethaw";
+ default: return "(unknown suspend event)";
+ }
+}
+
+
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+ dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+ ", may wakeup" : "");
+}
+
+/**
+ * suspend_device - Save state of one device.
+ * @dev: Device.
+ * @state: Power state device is entering.
+ */
+
+static int suspend_device(struct device * dev, pm_message_t state)
+{
+ int error = 0;
+
+ down(&dev->sem);
+ if (dev->power.power_state.event) {
+ dev_dbg(dev, "PM: suspend %d-->%d\n",
+ dev->power.power_state.event, state.event);
+ }
+
+ if (dev->class && dev->class->suspend) {
+ suspend_device_dbg(dev, state, "class ");
+ error = dev->class->suspend(dev, state);
+ suspend_report_result(dev->class->suspend, error);
+ }
+
+ if (!error && dev->type && dev->type->suspend) {
+ suspend_device_dbg(dev, state, "type ");
+ error = dev->type->suspend(dev, state);
+ suspend_report_result(dev->type->suspend, error);
+ }
+
+ if (!error && dev->bus && dev->bus->suspend) {
+ suspend_device_dbg(dev, state, "");
+ error = dev->bus->suspend(dev, state);
+ suspend_report_result(dev->bus->suspend, error);
+ }
+ up(&dev->sem);
+ return error;
+}
+
+
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't acquire a mutex or semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+ int error = 0;
+
+ if (dev->bus && dev->bus->suspend_late) {
+ suspend_device_dbg(dev, state, "LATE ");
+ error = dev->bus->suspend_late(dev, state);
+ suspend_report_result(dev->bus->suspend_late, error);
+ }
+ return error;
+}
+
+/**
+ * device_suspend - Save state and stop all devices in system.
+ * @state: Power state to put each device in.
+ *
+ * Walk the dpm_active list, call ->suspend() for each device, and move
+ * it to the dpm_off list.
+ *
+ * (For historical reasons, if it returns -EAGAIN, that used to mean
+ * that the device would be called again with interrupts disabled.
+ * These days, we use the "suspend_late()" callback for that, so we
+ * print a warning and consider it an error).
+ *
+ * If we get a different error, try and back out.
+ *
+ * If we hit a failure with any of the devices, call device_resume()
+ * above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+ int error = 0;
+
+ might_sleep();
+ mutex_lock(&dpm_mtx);
+ mutex_lock(&dpm_list_mtx);
+ while (!list_empty(&dpm_active) && error == 0) {
+ struct list_head * entry = dpm_active.prev;
+ struct device * dev = to_device(entry);
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+
+ error = suspend_device(dev, state);
+
+ mutex_lock(&dpm_list_mtx);
+
+ /* Check if the device got removed */
+ if (!list_empty(&dev->power.entry)) {
+ /* Move it to the dpm_off list */
+ if (!error)
+ list_move(&dev->power.entry, &dpm_off);
+ }
+ if (error)
+ printk(KERN_ERR "Could not suspend device %s: "
+ "error %d%s\n",
+ kobject_name(&dev->kobj), error,
+ error == -EAGAIN ? " (please convert to suspend_late)" : "");
+ put_device(dev);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ if (error)
+ dpm_resume();
+
+ mutex_unlock(&dpm_mtx);
+ return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+/**
+ * device_power_down - Shut down special devices.
+ * @state: Power state to enter.
+ *
+ * Walk the dpm_off_irq list, calling ->power_down() for each device that
+ * couldn't power down the device with interrupts enabled. When we're
+ * done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+ int error = 0;
+ struct device * dev;
+
+ while (!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.prev;
+
+ dev = to_device(entry);
+ error = suspend_device_late(dev, state);
+ if (error)
+ goto Error;
+ list_move(&dev->power.entry, &dpm_off_irq);
+ }
+
+ error = sysdev_suspend(state);
+ Done:
+ return error;
+ Error:
+ printk(KERN_ERR "Could not power down device %s: "
+ "error %d\n", kobject_name(&dev->kobj), error);
+ dpm_power_up();
+ goto Done;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
+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);
+ printk("%d\n", ret);
+ }
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 2760f25b3ac5..5c4efd493fa5 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -5,38 +5,17 @@
extern void device_shutdown(void);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* main.c
*/
-/*
- * Used to synchronize global power management operations.
- */
-extern struct mutex dpm_mtx;
-
-/*
- * Used to serialize changes to the dpm_* lists.
- */
-extern struct mutex dpm_list_mtx;
-
-/*
- * The PM lists.
- */
-extern struct list_head dpm_active;
-extern struct list_head dpm_off;
-extern struct list_head dpm_off_irq;
-
-
-static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
-{
- return container_of(entry, struct dev_pm_info, entry);
-}
+extern struct list_head dpm_active; /* The active device list */
static inline struct device * to_device(struct list_head * entry)
{
- return container_of(to_pm_info(entry), struct device, power);
+ return container_of(entry, struct device, power.entry);
}
extern int device_pm_add(struct device *);
@@ -49,25 +28,7 @@ extern void device_pm_remove(struct device *);
extern int dpm_sysfs_add(struct device *);
extern void dpm_sysfs_remove(struct device *);
-/*
- * resume.c
- */
-
-extern void dpm_resume(void);
-extern void dpm_power_up(void);
-extern int resume_device(struct device *);
-
-/*
- * suspend.c
- */
-extern int suspend_device(struct device *, pm_message_t);
-
-
-/*
- * runtime.c
- */
-
-#else /* CONFIG_PM */
+#else /* CONFIG_PM_SLEEP */
static inline int device_pm_add(struct device * dev)
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
deleted file mode 100644
index 00fd84ae6e66..000000000000
--- a/drivers/base/power/resume.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * resume.c - Functions for waking devices up.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/resume-trace.h>
-#include "../base.h"
-#include "power.h"
-
-
-/**
- * resume_device - Restore state for one device.
- * @dev: Device.
- *
- */
-
-int resume_device(struct device * dev)
-{
- int error = 0;
-
- TRACE_DEVICE(dev);
- TRACE_RESUME(0);
-
- down(&dev->sem);
-
- if (dev->bus && dev->bus->resume) {
- dev_dbg(dev,"resuming\n");
- error = dev->bus->resume(dev);
- }
-
- if (!error && dev->type && dev->type->resume) {
- dev_dbg(dev,"resuming\n");
- error = dev->type->resume(dev);
- }
-
- if (!error && dev->class && dev->class->resume) {
- dev_dbg(dev,"class resume\n");
- error = dev->class->resume(dev);
- }
-
- up(&dev->sem);
-
- TRACE_RESUME(error);
- return error;
-}
-
-
-static int resume_device_early(struct device * dev)
-{
- int error = 0;
-
- TRACE_DEVICE(dev);
- TRACE_RESUME(0);
- if (dev->bus && dev->bus->resume_early) {
- dev_dbg(dev,"EARLY resume\n");
- error = dev->bus->resume_early(dev);
- }
- TRACE_RESUME(error);
- return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
- */
-void dpm_resume(void)
-{
- mutex_lock(&dpm_list_mtx);
- while(!list_empty(&dpm_off)) {
- struct list_head * entry = dpm_off.next;
- struct device * dev = to_device(entry);
-
- get_device(dev);
- list_move_tail(entry, &dpm_active);
-
- mutex_unlock(&dpm_list_mtx);
- resume_device(dev);
- mutex_lock(&dpm_list_mtx);
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
-}
-
-
-/**
- * device_resume - Restore state of each device in system.
- *
- * Walk the dpm_off list, remove each entry, resume the device,
- * then add it to the dpm_active list.
- */
-
-void device_resume(void)
-{
- might_sleep();
- mutex_lock(&dpm_mtx);
- dpm_resume();
- mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
-
-
-/**
- * dpm_power_up - Power on some devices.
- *
- * Walk the dpm_off_irq list and power each device up. This
- * is used for devices that required they be powered down with
- * interrupts disabled. As devices are powered on, they are moved
- * to the dpm_active list.
- *
- * Interrupts must be disabled when calling this.
- */
-
-void dpm_power_up(void)
-{
- while(!list_empty(&dpm_off_irq)) {
- struct list_head * entry = dpm_off_irq.next;
- struct device * dev = to_device(entry);
-
- list_move_tail(entry, &dpm_off);
- resume_device_early(dev);
- }
-}
-
-
-/**
- * device_power_up - Turn on all devices that need special attention.
- *
- * Power on system devices then devices that required we shut them down
- * with interrupts disabled.
- * Called with interrupts disabled.
- */
-
-void device_power_up(void)
-{
- sysdev_resume();
- dpm_power_up();
-}
-
-EXPORT_SYMBOL_GPL(device_power_up);
-
-
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
deleted file mode 100644
index df6174d85866..000000000000
--- a/drivers/base/power/runtime.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * drivers/base/power/runtime.c - Handling dynamic device power management.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- *
- */
-
-#include <linux/device.h>
-#include "power.h"
-
-
-static void runtime_resume(struct device * dev)
-{
- dev_dbg(dev, "resuming\n");
- if (!dev->power.power_state.event)
- return;
- if (!resume_device(dev))
- dev->power.power_state = PMSG_ON;
-}
-
-
-/**
- * dpm_runtime_resume - Power one device back on.
- * @dev: Device.
- *
- * Bring one device back to the on state by first powering it
- * on, then restoring state. We only operate on devices that aren't
- * already on.
- * FIXME: We need to handle devices that are in an unknown state.
- */
-
-void dpm_runtime_resume(struct device * dev)
-{
- mutex_lock(&dpm_mtx);
- runtime_resume(dev);
- mutex_unlock(&dpm_mtx);
-}
-EXPORT_SYMBOL(dpm_runtime_resume);
-
-
-/**
- * dpm_runtime_suspend - Put one device in low-power state.
- * @dev: Device.
- * @state: State to enter.
- */
-
-int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
- int error = 0;
-
- mutex_lock(&dpm_mtx);
- if (dev->power.power_state.event == state.event)
- goto Done;
-
- if (dev->power.power_state.event)
- runtime_resume(dev);
-
- if (!(error = suspend_device(dev, state)))
- dev->power.power_state = state;
- Done:
- mutex_unlock(&dpm_mtx);
- return error;
-}
-EXPORT_SYMBOL(dpm_runtime_suspend);
-
-
-#if 0
-/**
- * dpm_set_power_state - Update power_state field.
- * @dev: Device.
- * @state: Power state device is in.
- *
- * This is an update mechanism for drivers to notify the core
- * what power state a device is in. Device probing code may not
- * always be able to tell, but we need accurate information to
- * work reliably.
- */
-void dpm_set_power_state(struct device * dev, pm_message_t state)
-{
- mutex_lock(&dpm_mtx);
- dev->power.power_state = state;
- mutex_unlock(&dpm_mtx);
-}
-#endif /* 0 */
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index a47ee1b70d20..56e8eaaac012 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -44,7 +44,5 @@ void device_shutdown(void)
dev->driver->shutdown(dev);
}
}
-
- sysdev_shutdown();
}
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
deleted file mode 100644
index 26df9b231737..000000000000
--- a/drivers/base/power/suspend.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * suspend.c - Functions for putting devices to sleep.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/kallsyms.h>
-#include <linux/pm.h>
-#include "../base.h"
-#include "power.h"
-
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
-static inline char *suspend_verb(u32 event)
-{
- switch (event) {
- case PM_EVENT_SUSPEND: return "suspend";
- case PM_EVENT_FREEZE: return "freeze";
- case PM_EVENT_PRETHAW: return "prethaw";
- default: return "(unknown suspend event)";
- }
-}
-
-
-static void
-suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
-{
- dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
- ", may wakeup" : "");
-}
-
-/**
- * suspend_device - Save state of one device.
- * @dev: Device.
- * @state: Power state device is entering.
- */
-
-int suspend_device(struct device * dev, pm_message_t state)
-{
- int error = 0;
-
- down(&dev->sem);
- if (dev->power.power_state.event) {
- dev_dbg(dev, "PM: suspend %d-->%d\n",
- dev->power.power_state.event, state.event);
- }
-
- if (dev->class && dev->class->suspend) {
- suspend_device_dbg(dev, state, "class ");
- error = dev->class->suspend(dev, state);
- suspend_report_result(dev->class->suspend, error);
- }
-
- if (!error && dev->type && dev->type->suspend) {
- suspend_device_dbg(dev, state, "type ");
- error = dev->type->suspend(dev, state);
- suspend_report_result(dev->type->suspend, error);
- }
-
- if (!error && dev->bus && dev->bus->suspend) {
- suspend_device_dbg(dev, state, "");
- error = dev->bus->suspend(dev, state);
- suspend_report_result(dev->bus->suspend, error);
- }
- up(&dev->sem);
- return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
- int error = 0;
-
- if (dev->bus && dev->bus->suspend_late) {
- suspend_device_dbg(dev, state, "LATE ");
- error = dev->bus->suspend_late(dev, state);
- suspend_report_result(dev->bus->suspend_late, error);
- }
- return error;
-}
-
-/**
- * device_suspend - Save state and stop all devices in system.
- * @state: Power state to put each device in.
- *
- * Walk the dpm_active list, call ->suspend() for each device, and move
- * it to the dpm_off list.
- *
- * (For historical reasons, if it returns -EAGAIN, that used to mean
- * that the device would be called again with interrupts disabled.
- * These days, we use the "suspend_late()" callback for that, so we
- * print a warning and consider it an error).
- *
- * If we get a different error, try and back out.
- *
- * If we hit a failure with any of the devices, call device_resume()
- * above to bring the suspended devices back to life.
- *
- */
-
-int device_suspend(pm_message_t state)
-{
- int error = 0;
-
- might_sleep();
- mutex_lock(&dpm_mtx);
- mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_active) && error == 0) {
- struct list_head * entry = dpm_active.prev;
- struct device * dev = to_device(entry);
-
- get_device(dev);
- mutex_unlock(&dpm_list_mtx);
-
- error = suspend_device(dev, state);
-
- mutex_lock(&dpm_list_mtx);
-
- /* Check if the device got removed */
- if (!list_empty(&dev->power.entry)) {
- /* Move it to the dpm_off list */
- if (!error)
- list_move(&dev->power.entry, &dpm_off);
- }
- if (error)
- printk(KERN_ERR "Could not suspend device %s: "
- "error %d%s\n",
- kobject_name(&dev->kobj), error,
- error == -EAGAIN ? " (please convert to suspend_late)" : "");
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
- if (error)
- dpm_resume();
-
- mutex_unlock(&dpm_mtx);
- return error;
-}
-
-EXPORT_SYMBOL_GPL(device_suspend);
-
-/**
- * device_power_down - Shut down special devices.
- * @state: Power state to enter.
- *
- * Walk the dpm_off_irq list, calling ->power_down() for each device that
- * couldn't power down the device with interrupts enabled. When we're
- * done, power down system devices.
- */
-
-int device_power_down(pm_message_t state)
-{
- int error = 0;
- struct device * dev;
-
- while (!list_empty(&dpm_off)) {
- struct list_head * entry = dpm_off.prev;
-
- dev = to_device(entry);
- error = suspend_device_late(dev, state);
- if (error)
- goto Error;
- list_move(&dev->power.entry, &dpm_off_irq);
- }
-
- error = sysdev_suspend(state);
- Done:
- return error;
- Error:
- printk(KERN_ERR "Could not power down device %s: "
- "error %d\n", kobject_name(&dev->kobj), error);
- dpm_power_up();
- goto Done;
-}
-
-EXPORT_SYMBOL_GPL(device_power_down);
-
-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);
- printk("%d\n", ret);
- }
-}
-EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 2d47517dbe32..f2ed179cd695 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -7,69 +7,6 @@
#include "power.h"
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
-
-/**
- * state - Control current power state of device
- *
- * show() returns the current power state of the device. '0' indicates
- * the device is on. Other values (2) indicate the device is in some low
- * power state.
- *
- * store() sets the current power state, which is an integer valued
- * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early()
- * methods fail this operation; those methods couldn't be called.
- * Otherwise,
- *
- * - If the recorded dev->power.power_state.event matches the
- * target value, nothing is done.
- * - If the recorded event code is nonzero, the device is reactivated
- * by calling bus.resume() and/or class.resume().
- * - If the target value is nonzero, the device is suspended by
- * calling class.suspend() and/or bus.suspend() with event code
- * PM_EVENT_SUSPEND.
- *
- * This mechanism is DEPRECATED and should only be used for testing.
- */
-
-static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
-{
- if (dev->power.power_state.event)
- return sprintf(buf, "2\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
-{
- pm_message_t state;
- int error = -EINVAL;
-
- /* disallow incomplete suspend sequences */
- if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
- return error;
-
- state.event = PM_EVENT_SUSPEND;
- /* Older apps expected to write "3" here - confused with PCI D3 */
- if ((n == 1) && !strcmp(buf, "3"))
- error = dpm_runtime_suspend(dev, state);
-
- if ((n == 1) && !strcmp(buf, "2"))
- error = dpm_runtime_suspend(dev, state);
-
- if ((n == 1) && !strcmp(buf, "0")) {
- dpm_runtime_resume(dev);
- error = 0;
- }
-
- return error ? error : n;
-}
-
-static DEVICE_ATTR(state, 0644, state_show, state_store);
-
-
-#endif /* CONFIG_PM_SYSFS_DEPRECATED */
-
/*
* wakeup - Report/change current wakeup option for device
*
@@ -143,9 +80,6 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
static struct attribute * power_attrs[] = {
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
- &dev_attr_state.attr,
-#endif
&dev_attr_wakeup.attr,
NULL,
};
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index a9ab30fefffc..2b0c601e422e 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -142,6 +142,7 @@ void set_trace_device(struct device *dev)
{
dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
}
+EXPORT_SYMBOL(set_trace_device);
/*
* We could just take the "tracedata" index into the .tracedata
@@ -162,6 +163,7 @@ void generate_resume_trace(void *tracedata, unsigned int user)
file_hash_value = hash_string(lineno, file, FILEHASH);
set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
}
+EXPORT_SYMBOL(generate_resume_trace);
extern char __tracedata_start, __tracedata_end;
static int show_file_hash(unsigned int value)
@@ -170,7 +172,8 @@ static int show_file_hash(unsigned int value)
char *tracedata;
match = 0;
- for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+ for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+ tracedata += 2 + sizeof(unsigned long)) {
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
unsigned int hash = hash_string(lineno, file, FILEHASH);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 18febe26caa1..ac7ff6d0c6e5 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls)
kobject_name(&cls->kset.kobj));
INIT_LIST_HEAD(&cls->drivers);
cls->kset.kobj.parent = &system_subsys.kobj;
- kset_set_kset_s(cls, system_subsys);
+ cls->kset.kobj.kset = &system_subsys;
return kset_register(&cls->kset);
}
@@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls)
EXPORT_SYMBOL_GPL(sysdev_class_register);
EXPORT_SYMBOL_GPL(sysdev_class_unregister);
-
-static LIST_HEAD(sysdev_drivers);
static DEFINE_MUTEX(sysdev_drivers_lock);
/**
* sysdev_driver_register - Register auxillary driver
- * @cls: Device class driver belongs to.
+ * @cls: Device class driver belongs to.
* @drv: Driver.
*
- * If @cls is valid, then @drv is inserted into @cls->drivers to be
+ * @drv is inserted into @cls->drivers to be
* called on each operation on devices of that class. The refcount
* of @cls is incremented.
- * Otherwise, @drv is inserted into sysdev_drivers, and called for
- * each device.
*/
-int sysdev_driver_register(struct sysdev_class * cls,
- struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
{
+ int err = 0;
+
mutex_lock(&sysdev_drivers_lock);
if (cls && kset_get(&cls->kset)) {
list_add_tail(&drv->entry, &cls->drivers);
@@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls,
list_for_each_entry(dev, &cls->kset.list, kobj.entry)
drv->add(dev);
}
- } else
- list_add_tail(&drv->entry, &sysdev_drivers);
+ } else {
+ err = -EINVAL;
+ printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+ WARN_ON(1);
+ }
mutex_unlock(&sysdev_drivers_lock);
- return 0;
+ return err;
}
@@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev)
* code that should have called us.
*/
- /* Notify global drivers */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->add)
- drv->add(sysdev);
- }
-
/* Notify class auxillary drivers */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->add)
@@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev)
struct sysdev_driver * drv;
mutex_lock(&sysdev_drivers_lock);
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->remove)
- drv->remove(sysdev);
- }
-
list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
if (drv->remove)
drv->remove(sysdev);
@@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev)
*
* Loop over each class of system devices, and the devices in each
* of those classes. For each device, we call the shutdown method for
- * each driver registered for the device - the globals, the auxillaries,
+ * each driver registered for the device - the auxillaries,
* and the class driver.
*
* Note: The list is iterated in reverse order, so that we shut down
@@ -320,13 +309,7 @@ void sysdev_shutdown(void)
struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->shutdown)
- drv->shutdown(sysdev);
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
@@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev)
if (drv->resume)
drv->resume(dev);
}
-
- /* Call global drivers. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->resume)
- drv->resume(dev);
- }
}
/**
@@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state)
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->suspend) {
- ret = drv->suspend(sysdev, state);
- if (ret)
- goto gbl_driver;
- }
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->suspend) {
ret = drv->suspend(sysdev, state);
@@ -436,18 +404,7 @@ aux_driver:
if (err_drv->resume)
err_drv->resume(sysdev);
}
- drv = NULL;
-gbl_driver:
- if (drv)
- printk(KERN_ERR "sysdev driver suspend failed for %s\n",
- kobject_name(&sysdev->kobj));
- list_for_each_entry(err_drv, &sysdev_drivers, entry) {
- if (err_drv == drv)
- break;
- if (err_drv->resume)
- err_drv->resume(sysdev);
- }
/* resume other sysdevs in current class */
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
if (err_dev == sysdev)
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 92bf868ca056..84d6aa500e26 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -17,8 +17,8 @@
*/
-#define DAC960_DriverVersion "2.5.48"
-#define DAC960_DriverDate "14 May 2006"
+#define DAC960_DriverVersion "2.5.49"
+#define DAC960_DriverDate "21 Aug 2007"
#include <linux/module.h>
@@ -31,6 +31,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/blkpg.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mm.h>
@@ -1165,9 +1166,9 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
int i;
- if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V1_PciDmaMask))
+ if (pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK))
return DAC960_Failure(Controller, "DMA mask out of range");
- Controller->BounceBufferLimit = DAC690_V1_PciDmaMask;
+ Controller->BounceBufferLimit = DMA_32BIT_MASK;
if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) {
CommandMailboxesSize = 0;
@@ -1368,9 +1369,12 @@ static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
dma_addr_t CommandMailboxDMA;
DAC960_V2_CommandStatus_T CommandStatus;
- if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V2_PciDmaMask))
- return DAC960_Failure(Controller, "DMA mask out of range");
- Controller->BounceBufferLimit = DAC690_V2_PciDmaMask;
+ if (!pci_set_dma_mask(Controller->PCIDevice, DMA_64BIT_MASK))
+ Controller->BounceBufferLimit = DMA_64BIT_MASK;
+ else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK))
+ Controller->BounceBufferLimit = DMA_32BIT_MASK;
+ else
+ return DAC960_Failure(Controller, "DMA mask out of range");
/* This is a temporary dma mapping, used only in the scope of this function */
CommandMailbox = pci_alloc_consistent(PCI_Device,
diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
index f5e2436c39aa..85fa9bb63759 100644
--- a/drivers/block/DAC960.h
+++ b/drivers/block/DAC960.h
@@ -61,13 +61,6 @@
#define DAC960_V2_MaxPhysicalDevices 272
/*
- Define the pci dma mask supported by DAC960 V1 and V2 Firmware Controlers
- */
-
-#define DAC690_V1_PciDmaMask 0xffffffff
-#define DAC690_V2_PciDmaMask 0xffffffffffffffffULL
-
-/*
Define a 32/64 bit I/O Address data type.
*/
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 8f65b88cf711..ca4d7f0d09b7 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -6,6 +6,12 @@ menuconfig BLK_DEV
bool "Block devices"
depends on BLOCK
default y
+ ---help---
+ Say Y here to get to see options for various different block device
+ drivers. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled;
+ only do this if you know what you are doing.
if BLK_DEV
@@ -62,6 +68,7 @@ config AMIGA_Z2RAM
config BLK_DEV_XD
tristate "XT hard disk support"
depends on ISA && ISA_DMA_API
+ select CHECK_SIGNATURE
help
Very old 8 bit hard disk controllers used in the IBM XT computer
will be supported if you say Y here.
@@ -354,8 +361,7 @@ config BLK_DEV_RAM_SIZE
default "4096"
help
The default value is 4096 kilobytes. Only change this if you know
- what are you doing. If you are using IBM S/390, then set this to
- 8192.
+ what are you doing.
config BLK_DEV_RAM_BLOCKSIZE
int "Default RAM disk block size (bytes)"
@@ -427,4 +433,13 @@ config XILINX_SYSACE
help
Include support for the Xilinx SystemACE CompactFlash interface
+config XEN_BLKDEV_FRONTEND
+ tristate "Xen virtual block device support"
+ depends on XEN
+ default y
+ help
+ This driver implements the front-end of the Xen virtual
+ block device driver. It communicates with a back-end driver
+ in another domain which drives the actual block device.
+
endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 9ee08ab4ffa8..014e72121b5a 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_MAC_FLOPPY) += swim3.o
obj-$(CONFIG_BLK_DEV_FD) += floppy.o
obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
+obj-$(CONFIG_PS3_DISK) += ps3disk.o
obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
obj-$(CONFIG_BLK_DEV_RAM) += rd.o
@@ -29,3 +30,5 @@ obj-$(CONFIG_VIODASD) += viodasd.o
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
obj-$(CONFIG_BLK_DEV_UB) += ub.o
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
+obj-$(CONFIG_LGUEST_BLOCK) += lguest_blk.o
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 6ce8b897e262..c9751b2b57e6 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1422,7 +1422,7 @@ static void redo_fd_request(void)
goto repeat;
}
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
{
redo_fd_request();
}
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 1d8466817943..ba07f762c4cb 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -138,7 +138,7 @@ struct aoedev {
u16 maxbcnt;
struct work_struct work;/* disk create work struct */
struct gendisk *gd;
- request_queue_t blkq;
+ struct request_queue blkq;
struct hd_geometry geo;
sector_t ssize;
struct timer_list timer;
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 478489c568a4..b1d00ef6659c 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -125,7 +125,7 @@ aoeblk_release(struct inode *inode, struct file *filp)
}
static int
-aoeblk_make_request(request_queue_t *q, struct bio *bio)
+aoeblk_make_request(struct request_queue *q, struct bio *bio)
{
struct aoedev *d;
struct buf *buf;
@@ -138,7 +138,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
buf = mempool_alloc(d->bufpool, GFP_NOIO);
if (buf == NULL) {
printk(KERN_INFO "aoe: buf allocation failure\n");
- bio_endio(bio, bio->bi_size, -ENOMEM);
+ bio_endio(bio, -ENOMEM);
return 0;
}
memset(buf, 0, sizeof(*buf));
@@ -159,7 +159,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
d->aoemajor, d->aoeminor);
spin_unlock_irqrestore(&d->lock, flags);
mempool_free(buf, d->bufpool);
- bio_endio(bio, bio->bi_size, -ENXIO);
+ bio_endio(bio, -ENXIO);
return 0;
}
@@ -257,9 +257,9 @@ aoeblk_exit(void)
int __init
aoeblk_init(void)
{
- buf_pool_cache = kmem_cache_create("aoe_bufs",
+ buf_pool_cache = kmem_cache_create("aoe_bufs",
sizeof(struct buf),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (buf_pool_cache == NULL)
return -ENOMEM;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 01fbdd38e3be..99672017ca56 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -9,6 +9,7 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/genhd.h>
+#include <net/net_namespace.h>
#include <asm/unaligned.h>
#include "aoe.h"
@@ -194,7 +195,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
sl = sl_tail = NULL;
read_lock(&dev_base_lock);
- for_each_netdev(ifp) {
+ for_each_netdev(&init_net, ifp) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
goto cont;
@@ -652,7 +653,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
disk_stat_add(disk, sectors[rw], n_sect);
disk_stat_add(disk, io_ticks, duration);
n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
- bio_endio(buf->bio, buf->bio->bi_size, n);
+ bio_endio(buf->bio, n);
mempool_free(buf, d->bufpool);
}
}
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 05a97197c918..51f50710e5fc 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -119,7 +119,7 @@ aoedev_downdev(struct aoedev *d)
bio = buf->bio;
if (--buf->nframesout == 0) {
mempool_free(buf, d->bufpool);
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
}
skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
}
@@ -130,7 +130,7 @@ aoedev_downdev(struct aoedev *d)
list_del(d->bufq.next);
bio = buf->bio;
mempool_free(buf, d->bufpool);
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
}
if (d->gd)
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index f9ddfda4d9cb..4dc0fb7da94b 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -8,6 +8,7 @@
#include <linux/blkdev.h>
#include <linux/netdevice.h>
#include <linux/moduleparam.h>
+#include <net/net_namespace.h>
#include <asm/unaligned.h>
#include "aoe.h"
@@ -114,6 +115,9 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
struct aoe_hdr *h;
u32 n;
+ if (ifp->nd_net != &init_net)
+ goto exit;
+
skb = skb_share_check(skb, GFP_ATOMIC);
if (skb == NULL)
return 0;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 14d6b9492750..94268c75d04f 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1466,7 +1466,7 @@ repeat:
}
-void do_fd_request(request_queue_t * q)
+void do_fd_request(struct request_queue * q)
{
unsigned long flags;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index a2d6612b80d2..28d145756f6c 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -139,7 +139,7 @@ static struct board_type products[] = {
static ctlr_info_t *hba[MAX_CTLR];
-static void do_cciss_request(request_queue_t *q);
+static void do_cciss_request(struct request_queue *q);
static irqreturn_t do_cciss_intr(int irq, void *dev_id);
static int cciss_open(struct inode *inode, struct file *filep);
static int cciss_release(struct inode *inode, struct file *filep);
@@ -1194,7 +1194,7 @@ static inline void complete_buffers(struct bio *bio, int status)
int nr_sectors = bio_sectors(bio);
bio->bi_next = NULL;
- bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
+ bio_endio(bio, status ? 0 : -EIO);
bio = xbh;
}
}
@@ -1584,7 +1584,7 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
*/
if (h->gendisk[0] != disk) {
if (disk) {
- request_queue_t *q = disk->queue;
+ struct request_queue *q = disk->queue;
if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
if (q) {
@@ -1977,12 +1977,13 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
{
ReadCapdata_struct *buf;
int return_code;
- buf = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
- if (buf == NULL) {
+
+ buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (!buf) {
printk(KERN_WARNING "cciss: out of memory\n");
return;
}
- memset(buf, 0, sizeof(ReadCapdata_struct));
+
if (withirq)
return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
ctlr, buf, sizeof(ReadCapdata_struct),
@@ -2003,7 +2004,6 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
printk(KERN_INFO " blocks= %llu block_size= %d\n",
(unsigned long long)*total_size+1, *block_size);
kfree(buf);
- return;
}
static void
@@ -2011,12 +2011,13 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
{
ReadCapdata_struct_16 *buf;
int return_code;
- buf = kmalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
- if (buf == NULL) {
+
+ buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
+ if (!buf) {
printk(KERN_WARNING "cciss: out of memory\n");
return;
}
- memset(buf, 0, sizeof(ReadCapdata_struct_16));
+
if (withirq) {
return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
ctlr, buf, sizeof(ReadCapdata_struct_16),
@@ -2038,7 +2039,6 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
printk(KERN_INFO " blocks= %llu block_size= %d\n",
(unsigned long long)*total_size+1, *block_size);
kfree(buf);
- return;
}
static int cciss_revalidate(struct gendisk *disk)
@@ -2511,7 +2511,7 @@ after_error_processing:
/*
* Get a request and submit it to the controller.
*/
-static void do_cciss_request(request_queue_t *q)
+static void do_cciss_request(struct request_queue *q)
{
ctlr_info_t *h = q->queuedata;
CommandList_struct *c;
@@ -3227,12 +3227,15 @@ static int alloc_cciss_hba(void)
for (i = 0; i < MAX_CTLR; i++) {
if (!hba[i]) {
ctlr_info_t *p;
+
p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
if (!p)
goto Enomem;
p->gendisk[0] = alloc_disk(1 << NWD_SHIFT);
- if (!p->gendisk[0])
+ if (!p->gendisk[0]) {
+ kfree(p);
goto Enomem;
+ }
hba[i] = p;
return i;
}
@@ -3380,7 +3383,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
do {
drive_info_struct *drv = &(hba[i]->drv[j]);
struct gendisk *disk = hba[i]->gendisk[j];
- request_queue_t *q;
+ struct request_queue *q;
/* Check if the disk was allocated already */
if (!disk){
@@ -3523,7 +3526,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
for (j = 0; j < CISS_MAX_LUN; j++) {
struct gendisk *disk = hba[i]->gendisk[j];
if (disk) {
- request_queue_t *q = disk->queue;
+ struct request_queue *q = disk->queue;
if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index b94cd1c32131..3853c9a38d6a 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -161,7 +161,7 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo);
static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io);
-static void do_ida_request(request_queue_t *q);
+static void do_ida_request(struct request_queue *q);
static void start_io(ctlr_info_t *h);
static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
@@ -391,7 +391,7 @@ static void __devexit cpqarray_remove_one_eisa (int i)
/* pdev is NULL for eisa */
static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
{
- request_queue_t *q;
+ struct request_queue *q;
int j;
/*
@@ -420,18 +420,17 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
goto Enomem2;
}
- hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
+ hba[i]->cmd_pool = pci_alloc_consistent(
hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
&(hba[i]->cmd_pool_dhandle));
- hba[i]->cmd_pool_bits = kmalloc(
- ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long),
+ hba[i]->cmd_pool_bits = kcalloc(
+ (NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG, sizeof(unsigned long),
GFP_KERNEL);
if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
goto Enomem1;
memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
- memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
printk(KERN_INFO "cpqarray: Finding drives on %s",
hba[i]->devname);
@@ -886,7 +885,7 @@ static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
* are in here (either via the dummy do_ida_request functions or by being
* called from the interrupt handler
*/
-static void do_ida_request(request_queue_t *q)
+static void do_ida_request(struct request_queue *q)
{
ctlr_info_t *h = q->queuedata;
cmdlist_t *c;
@@ -988,7 +987,7 @@ static inline void complete_buffers(struct bio *bio, int ok)
xbh = bio->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO);
+ bio_endio(bio, ok ? 0 : -EIO);
bio = xbh;
}
@@ -1660,45 +1659,30 @@ static void getgeometry(int ctlr)
info_p->log_drv_map = 0;
- id_ldrive = kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
- if(id_ldrive == NULL)
- {
+ id_ldrive = kzalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+ if (!id_ldrive) {
printk( KERN_ERR "cpqarray: out of memory.\n");
- return;
+ goto err_0;
}
- id_ctlr_buf = kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
- if(id_ctlr_buf == NULL)
- {
- kfree(id_ldrive);
+ id_ctlr_buf = kzalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+ if (!id_ctlr_buf) {
printk( KERN_ERR "cpqarray: out of memory.\n");
- return;
+ goto err_1;
}
- id_lstatus_buf = kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
- if(id_lstatus_buf == NULL)
- {
- kfree(id_ctlr_buf);
- kfree(id_ldrive);
+ id_lstatus_buf = kzalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+ if (!id_lstatus_buf) {
printk( KERN_ERR "cpqarray: out of memory.\n");
- return;
+ goto err_2;
}
- sense_config_buf = kmalloc(sizeof(config_t), GFP_KERNEL);
- if(sense_config_buf == NULL)
- {
- kfree(id_lstatus_buf);
- kfree(id_ctlr_buf);
- kfree(id_ldrive);
+ sense_config_buf = kzalloc(sizeof(config_t), GFP_KERNEL);
+ if (!sense_config_buf) {
printk( KERN_ERR "cpqarray: out of memory.\n");
- return;
+ goto err_3;
}
- memset(id_ldrive, 0, sizeof(id_log_drv_t));
- memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
- memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
- memset(sense_config_buf, 0, sizeof(config_t));
-
info_p->phys_drives = 0;
info_p->log_drv_map = 0;
info_p->drv_assign_map = 0;
@@ -1712,13 +1696,8 @@ static void getgeometry(int ctlr)
* so the idastubopen will fail on all logical drives
* on the controller.
*/
- /* Free all the buffers and return */
printk(KERN_ERR "cpqarray: error sending ID controller\n");
- kfree(sense_config_buf);
- kfree(id_lstatus_buf);
- kfree(id_ctlr_buf);
- kfree(id_ldrive);
- return;
+ goto err_4;
}
info_p->log_drives = id_ctlr_buf->nr_drvs;
@@ -1764,12 +1743,7 @@ static void getgeometry(int ctlr)
" failed to report status of logical drive %d\n"
"Access to this controller has been disabled\n",
ctlr, log_unit);
- /* Free all the buffers and return */
- kfree(sense_config_buf);
- kfree(id_lstatus_buf);
- kfree(id_ctlr_buf);
- kfree(id_ldrive);
- return;
+ goto err_4;
}
/*
Make sure the logical drive is configured
@@ -1798,14 +1772,8 @@ static void getgeometry(int ctlr)
sizeof(config_t), 0, 0, log_unit);
if (ret_code == IO_ERROR) {
info_p->log_drv_map = 0;
- /* Free all the buffers and return */
printk(KERN_ERR "cpqarray: error sending sense config\n");
- kfree(sense_config_buf);
- kfree(id_lstatus_buf);
- kfree(id_ctlr_buf);
- kfree(id_ldrive);
- return;
-
+ goto err_4;
}
info_p->phys_drives =
@@ -1820,12 +1788,18 @@ static void getgeometry(int ctlr)
log_index = log_index + 1;
} /* end of if logical drive configured */
} /* end of for log_unit */
+
+ /* Free all the buffers and return */
+err_4:
kfree(sense_config_buf);
- kfree(id_ldrive);
+err_3:
kfree(id_lstatus_buf);
+err_2:
kfree(id_ctlr_buf);
+err_1:
+ kfree(id_ldrive);
+err_0:
return;
-
}
static void __exit cpqarray_exit(void)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index fe088045dd08..80483aac4cc9 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -251,7 +251,7 @@ static int irqdma_allocated;
static struct request *current_req;
static struct request_queue *floppy_queue;
-static void do_fd_request(request_queue_t * q);
+static void do_fd_request(struct request_queue * q);
#ifndef fd_get_dma_residue
#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -2437,22 +2437,19 @@ static void rw_interrupt(void)
/* Compute maximal contiguous buffer size. */
static int buffer_chain_size(void)
{
- struct bio *bio;
struct bio_vec *bv;
- int size, i;
+ int size;
+ struct req_iterator iter;
char *base;
base = bio_data(current_req->bio);
size = 0;
- rq_for_each_bio(bio, current_req) {
- bio_for_each_segment(bv, bio, i) {
- if (page_address(bv->bv_page) + bv->bv_offset !=
- base + size)
- break;
+ rq_for_each_segment(bv, current_req, iter) {
+ if (page_address(bv->bv_page) + bv->bv_offset != base + size)
+ break;
- size += bv->bv_len;
- }
+ size += bv->bv_len;
}
return size >> 9;
@@ -2479,9 +2476,9 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
{
int remaining; /* number of transferred 512-byte sectors */
struct bio_vec *bv;
- struct bio *bio;
char *buffer, *dma_buffer;
- int size, i;
+ int size;
+ struct req_iterator iter;
max_sector = transfer_size(ssize,
min(max_sector, max_sector_2),
@@ -2514,43 +2511,41 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
size = current_req->current_nr_sectors << 9;
- rq_for_each_bio(bio, current_req) {
- bio_for_each_segment(bv, bio, i) {
- if (!remaining)
- break;
+ rq_for_each_segment(bv, current_req, iter) {
+ if (!remaining)
+ break;
- size = bv->bv_len;
- SUPBOUND(size, remaining);
+ size = bv->bv_len;
+ SUPBOUND(size, remaining);
- buffer = page_address(bv->bv_page) + bv->bv_offset;
+ buffer = page_address(bv->bv_page) + bv->bv_offset;
#ifdef FLOPPY_SANITY_CHECK
- if (dma_buffer + size >
- floppy_track_buffer + (max_buffer_sectors << 10) ||
- dma_buffer < floppy_track_buffer) {
- DPRINT("buffer overrun in copy buffer %d\n",
- (int)((floppy_track_buffer -
- dma_buffer) >> 9));
- printk("fsector_t=%d buffer_min=%d\n",
- fsector_t, buffer_min);
- printk("current_count_sectors=%ld\n",
- current_count_sectors);
- if (CT(COMMAND) == FD_READ)
- printk("read\n");
- if (CT(COMMAND) == FD_WRITE)
- printk("write\n");
- break;
- }
- if (((unsigned long)buffer) % 512)
- DPRINT("%p buffer not aligned\n", buffer);
-#endif
+ if (dma_buffer + size >
+ floppy_track_buffer + (max_buffer_sectors << 10) ||
+ dma_buffer < floppy_track_buffer) {
+ DPRINT("buffer overrun in copy buffer %d\n",
+ (int)((floppy_track_buffer -
+ dma_buffer) >> 9));
+ printk("fsector_t=%d buffer_min=%d\n",
+ fsector_t, buffer_min);
+ printk("current_count_sectors=%ld\n",
+ current_count_sectors);
if (CT(COMMAND) == FD_READ)
- memcpy(buffer, dma_buffer, size);
- else
- memcpy(dma_buffer, buffer, size);
-
- remaining -= size;
- dma_buffer += size;
+ printk("read\n");
+ if (CT(COMMAND) == FD_WRITE)
+ printk("write\n");
+ break;
}
+ if (((unsigned long)buffer) % 512)
+ DPRINT("%p buffer not aligned\n", buffer);
+#endif
+ if (CT(COMMAND) == FD_READ)
+ memcpy(buffer, dma_buffer, size);
+ else
+ memcpy(dma_buffer, buffer, size);
+
+ remaining -= size;
+ dma_buffer += size;
}
#ifdef FLOPPY_SANITY_CHECK
if (remaining) {
@@ -2981,7 +2976,7 @@ static void process_fd_request(void)
schedule_bh(redo_fd_request);
}
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
{
if (max_buffer_sectors == 0) {
printk("VFS: do_fd_request called on non-open device\n");
@@ -3815,14 +3810,10 @@ static int check_floppy_change(struct gendisk *disk)
* a disk in the drive, and whether that disk is writable.
*/
-static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done,
+static void floppy_rb0_complete(struct bio *bio,
int err)
{
- if (bio->bi_size)
- return 1;
-
complete((struct completion *)bio->bi_private);
- return 0;
}
static int __floppy_read_block_0(struct block_device *bdev)
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c
new file mode 100644
index 000000000000..fa8e42341b87
--- /dev/null
+++ b/drivers/block/lguest_blk.c
@@ -0,0 +1,421 @@
+/*D:400
+ * The Guest block driver
+ *
+ * This is a simple block driver, which appears as /dev/lgba, lgbb, lgbc etc.
+ * The mechanism is simple: we place the information about the request in the
+ * device page, then use SEND_DMA (containing the data for a write, or an empty
+ * "ping" DMA for a read).
+ :*/
+/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+//#define DEBUG
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/lguest_bus.h>
+
+static char next_block_index = 'a';
+
+/*D:420 Here is the structure which holds all the information we need about
+ * each Guest block device.
+ *
+ * I'm sure at this stage, you're wondering "hey, where was the adventure I was
+ * promised?" and thinking "Rusty sucks, I shall say nasty things about him on
+ * my blog". I think Real adventures have boring bits, too, and you're in the
+ * middle of one. But it gets better. Just not quite yet. */
+struct blockdev
+{
+ /* The block queue infrastructure wants a spinlock: it is held while it
+ * calls our block request function. We grab it in our interrupt
+ * handler so the responses don't mess with new requests. */
+ spinlock_t lock;
+
+ /* The disk structure registered with kernel. */
+ struct gendisk *disk;
+
+ /* The major device number for this disk, and the interrupt. We only
+ * really keep them here for completeness; we'd need them if we
+ * supported device unplugging. */
+ int major;
+ int irq;
+
+ /* The physical address of this device's memory page */
+ unsigned long phys_addr;
+ /* The mapped memory page for convenient acces. */
+ struct lguest_block_page *lb_page;
+
+ /* We only have a single request outstanding at a time: this is it. */
+ struct lguest_dma dma;
+ struct request *req;
+};
+
+/*D:495 We originally used end_request() throughout the driver, but it turns
+ * out that end_request() is deprecated, and doesn't actually end the request
+ * (which seems like a good reason to deprecate it!). It simply ends the first
+ * bio. So if we had 3 bios in a "struct request" we would do all 3,
+ * end_request(), do 2, end_request(), do 1 and end_request(): twice as much
+ * work as we needed to do.
+ *
+ * This reinforced to me that I do not understand the block layer.
+ *
+ * Nonetheless, Jens Axboe gave me this nice helper to end all chunks of a
+ * request. This improved disk speed by 130%. */
+static void end_entire_request(struct request *req, int uptodate)
+{
+ if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+ BUG();
+ add_disk_randomness(req->rq_disk);
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, uptodate);
+}
+
+/* I'm told there are only two stories in the world worth telling: love and
+ * hate. So there used to be a love scene here like this:
+ *
+ * Launcher: We could make beautiful I/O together, you and I.
+ * Guest: My, that's a big disk!
+ *
+ * Unfortunately, it was just too raunchy for our otherwise-gentle tale. */
+
+/*D:490 This is the interrupt handler, called when a block read or write has
+ * been completed for us. */
+static irqreturn_t lgb_irq(int irq, void *_bd)
+{
+ /* We handed our "struct blockdev" as the argument to request_irq(), so
+ * it is passed through to us here. This tells us which device we're
+ * dealing with in case we have more than one. */
+ struct blockdev *bd = _bd;
+ unsigned long flags;
+
+ /* We weren't doing anything? Strange, but could happen if we shared
+ * interrupts (we don't!). */
+ if (!bd->req) {
+ pr_debug("No work!\n");
+ return IRQ_NONE;
+ }
+
+ /* Not done yet? That's equally strange. */
+ if (!bd->lb_page->result) {
+ pr_debug("No result!\n");
+ return IRQ_NONE;
+ }
+
+ /* We have to grab the lock before ending the request. */
+ spin_lock_irqsave(&bd->lock, flags);
+ /* "result" is 1 for success, 2 for failure: end_entire_request() wants
+ * to know whether this succeeded or not. */
+ end_entire_request(bd->req, bd->lb_page->result == 1);
+ /* Clear out request, it's done. */
+ bd->req = NULL;
+ /* Reset incoming DMA for next time. */
+ bd->dma.used_len = 0;
+ /* Ready for more reads or writes */
+ blk_start_queue(bd->disk->queue);
+ spin_unlock_irqrestore(&bd->lock, flags);
+
+ /* The interrupt was for us, we dealt with it. */
+ return IRQ_HANDLED;
+}
+
+/*D:480 The block layer's "struct request" contains a number of "struct bio"s,
+ * each of which contains "struct bio_vec"s, each of which contains a page, an
+ * offset and a length.
+ *
+ * Fortunately there are iterators to help us walk through the "struct
+ * request". Even more fortunately, there were plenty of places to steal the
+ * code from. We pack the "struct request" into our "struct lguest_dma" and
+ * return the total length. */
+static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
+{
+ unsigned int i = 0, len = 0;
+ struct req_iterator iter;
+ struct bio_vec *bvec;
+
+ rq_for_each_segment(bvec, req, iter) {
+ /* We told the block layer not to give us too many. */
+ BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
+ /* If we had a zero-length segment, it would look like
+ * the end of the data referred to by the "struct
+ * lguest_dma", so make sure that doesn't happen. */
+ BUG_ON(!bvec->bv_len);
+ /* Convert page & offset to a physical address */
+ dma->addr[i] = page_to_phys(bvec->bv_page)
+ + bvec->bv_offset;
+ dma->len[i] = bvec->bv_len;
+ len += bvec->bv_len;
+ i++;
+ }
+ /* If the array isn't full, we mark the end with a 0 length */
+ if (i < LGUEST_MAX_DMA_SECTIONS)
+ dma->len[i] = 0;
+ return len;
+}
+
+/* This creates an empty DMA, useful for prodding the Host without sending data
+ * (ie. when we want to do a read) */
+static void empty_dma(struct lguest_dma *dma)
+{
+ dma->len[0] = 0;
+}
+
+/*D:470 Setting up a request is fairly easy: */
+static void setup_req(struct blockdev *bd,
+ int type, struct request *req, struct lguest_dma *dma)
+{
+ /* The type is 1 (write) or 0 (read). */
+ bd->lb_page->type = type;
+ /* The sector on disk where the read or write starts. */
+ bd->lb_page->sector = req->sector;
+ /* The result is initialized to 0 (unfinished). */
+ bd->lb_page->result = 0;
+ /* The current request (so we can end it in the interrupt handler). */
+ bd->req = req;
+ /* The number of bytes: returned as a side-effect of req_to_dma(),
+ * which packs the block layer's "struct request" into our "struct
+ * lguest_dma" */
+ bd->lb_page->bytes = req_to_dma(req, dma);
+}
+
+/*D:450 Write is pretty straightforward: we pack the request into a "struct
+ * lguest_dma", then use SEND_DMA to send the request. */
+static void do_write(struct blockdev *bd, struct request *req)
+{
+ struct lguest_dma send;
+
+ pr_debug("lgb: WRITE sector %li\n", (long)req->sector);
+ setup_req(bd, 1, req, &send);
+
+ lguest_send_dma(bd->phys_addr, &send);
+}
+
+/* Read is similar to write, except we pack the request into our receive
+ * "struct lguest_dma" and send through an empty DMA just to tell the Host that
+ * there's a request pending. */
+static void do_read(struct blockdev *bd, struct request *req)
+{
+ struct lguest_dma ping;
+
+ pr_debug("lgb: READ sector %li\n", (long)req->sector);
+ setup_req(bd, 0, req, &bd->dma);
+
+ empty_dma(&ping);
+ lguest_send_dma(bd->phys_addr, &ping);
+}
+
+/*D:440 This where requests come in: we get handed the request queue and are
+ * expected to pull a "struct request" off it until we've finished them or
+ * we're waiting for a reply: */
+static void do_lgb_request(struct request_queue *q)
+{
+ struct blockdev *bd;
+ struct request *req;
+
+again:
+ /* This sometimes returns NULL even on the very first time around. I
+ * wonder if it's something to do with letting elves handle the request
+ * queue... */
+ req = elv_next_request(q);
+ if (!req)
+ return;
+
+ /* We attached the struct blockdev to the disk: get it back */
+ bd = req->rq_disk->private_data;
+ /* Sometimes we get repeated requests after blk_stop_queue(), but we
+ * can only handle one at a time. */
+ if (bd->req)
+ return;
+
+ /* We only do reads and writes: no tricky business! */
+ if (!blk_fs_request(req)) {
+ pr_debug("Got non-command 0x%08x\n", req->cmd_type);
+ req->errors++;
+ end_entire_request(req, 0);
+ goto again;
+ }
+
+ if (rq_data_dir(req) == WRITE)
+ do_write(bd, req);
+ else
+ do_read(bd, req);
+
+ /* We've put out the request, so stop any more coming in until we get
+ * an interrupt, which takes us to lgb_irq() to re-enable the queue. */
+ blk_stop_queue(q);
+}
+
+/*D:430 This is the "struct block_device_operations" we attach to the disk at
+ * the end of lguestblk_probe(). It doesn't seem to want much. */
+static struct block_device_operations lguestblk_fops = {
+ .owner = THIS_MODULE,
+};
+
+/*D:425 Setting up a disk device seems to involve a lot of code. I'm not sure
+ * quite why. I do know that the IDE code sent two or three of the maintainers
+ * insane, perhaps this is the fringe of the same disease?
+ *
+ * As in the console code, the probe function gets handed the generic
+ * lguest_device from lguest_bus.c: */
+static int lguestblk_probe(struct lguest_device *lgdev)
+{
+ struct blockdev *bd;
+ int err;
+ int irqflags = IRQF_SHARED;
+
+ /* First we allocate our own "struct blockdev" and initialize the easy
+ * fields. */
+ bd = kmalloc(sizeof(*bd), GFP_KERNEL);
+ if (!bd)
+ return -ENOMEM;
+
+ spin_lock_init(&bd->lock);
+ bd->irq = lgdev_irq(lgdev);
+ bd->req = NULL;
+ bd->dma.used_len = 0;
+ bd->dma.len[0] = 0;
+ /* The descriptor in the lguest_devices array provided by the Host
+ * gives the Guest the physical page number of the device's page. */
+ bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
+
+ /* We use lguest_map() to get a pointer to the device page */
+ bd->lb_page = lguest_map(bd->phys_addr, 1);
+ if (!bd->lb_page) {
+ err = -ENOMEM;
+ goto out_free_bd;
+ }
+
+ /* We need a major device number: 0 means "assign one dynamically". */
+ bd->major = register_blkdev(0, "lguestblk");
+ if (bd->major < 0) {
+ err = bd->major;
+ goto out_unmap;
+ }
+
+ /* This allocates a "struct gendisk" where we pack all the information
+ * about the disk which the rest of Linux sees. The argument is the
+ * number of minor devices desired: we need one minor for the main
+ * disk, and one for each partition. Of course, we can't possibly know
+ * how many partitions are on the disk (add_disk does that).
+ */
+ bd->disk = alloc_disk(16);
+ if (!bd->disk) {
+ err = -ENOMEM;
+ goto out_unregister_blkdev;
+ }
+
+ /* Every disk needs a queue for requests to come in: we set up the
+ * queue with a callback function (the core of our driver) and the lock
+ * to use. */
+ bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
+ if (!bd->disk->queue) {
+ err = -ENOMEM;
+ goto out_put_disk;
+ }
+
+ /* We can only handle a certain number of pointers in our SEND_DMA
+ * call, so we set that with blk_queue_max_hw_segments(). This is not
+ * to be confused with blk_queue_max_phys_segments() of course! I
+ * know, who could possibly confuse the two?
+ *
+ * Well, it's simple to tell them apart: this one seems to work and the
+ * other one didn't. */
+ blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
+
+ /* Due to technical limitations of our Host (and simple coding) we
+ * can't have a single buffer which crosses a page boundary. Tell it
+ * here. This means that our maximum request size is 16
+ * (LGUEST_MAX_DMA_SECTIONS) pages. */
+ blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
+
+ /* We name our disk: this becomes the device name when udev does its
+ * magic thing and creates the device node, such as /dev/lgba.
+ * next_block_index is a global which starts at 'a'. Unfortunately
+ * this simple increment logic means that the 27th disk will be called
+ * "/dev/lgb{". In that case, I recommend having at least 29 disks, so
+ * your /dev directory will be balanced. */
+ sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
+
+ /* We look to the device descriptor again to see if this device's
+ * interrupts are expected to be random. If they are, we tell the irq
+ * subsystem. At the moment this bit is always set. */
+ if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+ irqflags |= IRQF_SAMPLE_RANDOM;
+
+ /* Now we have the name and irqflags, we can request the interrupt; we
+ * give it the "struct blockdev" we have set up to pass to lgb_irq()
+ * when there is an interrupt. */
+ err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
+ if (err)
+ goto out_cleanup_queue;
+
+ /* We bind our one-entry DMA pool to the key for this block device so
+ * the Host can reply to our requests. The key is equal to the
+ * physical address of the device's page, which is conveniently
+ * unique. */
+ err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
+ if (err)
+ goto out_free_irq;
+
+ /* We finish our disk initialization and add the disk to the system. */
+ bd->disk->major = bd->major;
+ bd->disk->first_minor = 0;
+ bd->disk->private_data = bd;
+ bd->disk->fops = &lguestblk_fops;
+ /* This is initialized to the disk size by the Launcher. */
+ set_capacity(bd->disk, bd->lb_page->num_sectors);
+ add_disk(bd->disk);
+
+ printk(KERN_INFO "%s: device %i at major %d\n",
+ bd->disk->disk_name, lgdev->index, bd->major);
+
+ /* We don't need to keep the "struct blockdev" around, but if we ever
+ * implemented device removal, we'd need this. */
+ lgdev->private = bd;
+ return 0;
+
+out_free_irq:
+ free_irq(bd->irq, bd);
+out_cleanup_queue:
+ blk_cleanup_queue(bd->disk->queue);
+out_put_disk:
+ put_disk(bd->disk);
+out_unregister_blkdev:
+ unregister_blkdev(bd->major, "lguestblk");
+out_unmap:
+ lguest_unmap(bd->lb_page);
+out_free_bd:
+ kfree(bd);
+ return err;
+}
+
+/*D:410 The boilerplate code for registering the lguest block driver is just
+ * like the console: */
+static struct lguest_driver lguestblk_drv = {
+ .name = "lguestblk",
+ .owner = THIS_MODULE,
+ .device_type = LGUEST_DEVICE_T_BLOCK,
+ .probe = lguestblk_probe,
+};
+
+static __init int lguestblk_init(void)
+{
+ return register_lguest_driver(&lguestblk_drv);
+}
+module_init(lguestblk_init);
+
+MODULE_DESCRIPTION("Lguest block driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index e425daa1eac3..b9233a06934c 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -529,7 +529,7 @@ static struct bio *loop_get_bio(struct loop_device *lo)
return bio;
}
-static int loop_make_request(request_queue_t *q, struct bio *old_bio)
+static int loop_make_request(struct request_queue *q, struct bio *old_bio)
{
struct loop_device *lo = q->queuedata;
int rw = bio_rw(old_bio);
@@ -551,14 +551,14 @@ static int loop_make_request(request_queue_t *q, struct bio *old_bio)
out:
spin_unlock_irq(&lo->lo_lock);
- bio_io_error(old_bio, old_bio->bi_size);
+ bio_io_error(old_bio);
return 0;
}
/*
* kick off io on the underlying address space
*/
-static void loop_unplug(request_queue_t *q)
+static void loop_unplug(struct request_queue *q)
{
struct loop_device *lo = q->queuedata;
@@ -580,7 +580,7 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
bio_put(bio);
} else {
int ret = do_bio_filebacked(lo, bio);
- bio_endio(bio, bio->bi_size, ret);
+ bio_endio(bio, ret);
}
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c12951024090..be5ec3a9b1fc 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -100,7 +100,7 @@ static const char *nbdcmd_to_ascii(int cmd)
static void nbd_end_request(struct request *req)
{
int uptodate = (req->errors == 0) ? 1 : 0;
- request_queue_t *q = req->q;
+ struct request_queue *q = req->q;
unsigned long flags;
dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
@@ -180,7 +180,7 @@ static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec,
static int nbd_send_req(struct nbd_device *lo, struct request *req)
{
- int result, i, flags;
+ int result, flags;
struct nbd_request request;
unsigned long size = req->nr_sectors << 9;
struct socket *sock = lo->sock;
@@ -205,27 +205,23 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
}
if (nbd_cmd(req) == NBD_CMD_WRITE) {
- struct bio *bio;
+ struct req_iterator iter;
+ struct bio_vec *bvec;
/*
* we are really probing at internals to determine
* whether to set MSG_MORE or not...
*/
- rq_for_each_bio(bio, req) {
- struct bio_vec *bvec;
- bio_for_each_segment(bvec, bio, i) {
- flags = 0;
- if ((i < (bio->bi_vcnt - 1)) || bio->bi_next)
- flags = MSG_MORE;
- dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
- lo->disk->disk_name, req,
- bvec->bv_len);
- result = sock_send_bvec(sock, bvec, flags);
- if (result <= 0) {
- printk(KERN_ERR "%s: Send data failed (result %d)\n",
- lo->disk->disk_name,
- result);
- goto error_out;
- }
+ rq_for_each_segment(bvec, req, iter) {
+ flags = 0;
+ if (!rq_iter_last(req, iter))
+ flags = MSG_MORE;
+ dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
+ lo->disk->disk_name, req, bvec->bv_len);
+ result = sock_send_bvec(sock, bvec, flags);
+ if (result <= 0) {
+ printk(KERN_ERR "%s: Send data failed (result %d)\n",
+ lo->disk->disk_name, result);
+ goto error_out;
}
}
}
@@ -321,22 +317,19 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
dprintk(DBG_RX, "%s: request %p: got reply\n",
lo->disk->disk_name, req);
if (nbd_cmd(req) == NBD_CMD_READ) {
- int i;
- struct bio *bio;
- rq_for_each_bio(bio, req) {
- struct bio_vec *bvec;
- bio_for_each_segment(bvec, bio, i) {
- result = sock_recv_bvec(sock, bvec);
- if (result <= 0) {
- printk(KERN_ERR "%s: Receive data failed (result %d)\n",
- lo->disk->disk_name,
- result);
- req->errors++;
- return req;
- }
- dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
- lo->disk->disk_name, req, bvec->bv_len);
+ struct req_iterator iter;
+ struct bio_vec *bvec;
+
+ rq_for_each_segment(bvec, req, iter) {
+ result = sock_recv_bvec(sock, bvec);
+ if (result <= 0) {
+ printk(KERN_ERR "%s: Receive data failed (result %d)\n",
+ lo->disk->disk_name, result);
+ req->errors++;
+ return req;
}
+ dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
+ lo->disk->disk_name, req, bvec->bv_len);
}
}
return req;
@@ -410,7 +403,7 @@ static void nbd_clear_que(struct nbd_device *lo)
* { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
*/
-static void do_nbd_request(request_queue_t * q)
+static void do_nbd_request(struct request_queue * q)
{
struct request *req;
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 1eeb8f2cde71..b8a994a2b013 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -183,7 +183,7 @@ static int pcd_packet(struct cdrom_device_info *cdi,
static int pcd_detect(void);
static void pcd_probe_capabilities(void);
static void do_pcd_read_drq(void);
-static void do_pcd_request(request_queue_t * q);
+static void do_pcd_request(struct request_queue * q);
static void do_pcd_read(void);
struct pcd_unit {
@@ -713,7 +713,7 @@ static int pcd_detect(void)
/* I/O request processing */
static struct request_queue *pcd_queue;
-static void do_pcd_request(request_queue_t * q)
+static void do_pcd_request(struct request_queue * q)
{
if (pcd_busy)
return;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 31e01488eb51..df819f8a95a6 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -698,7 +698,7 @@ static enum action pd_identify(struct pd_unit *disk)
/* end of io request engine */
-static void do_pd_request(request_queue_t * q)
+static void do_pd_request(struct request_queue * q)
{
if (pd_req)
return;
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 5826508f6731..ceffa6034e20 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -202,7 +202,7 @@ module_param_array(drive3, int, NULL, 0);
#define ATAPI_WRITE_10 0x2a
static int pf_open(struct inode *inode, struct file *file);
-static void do_pf_request(request_queue_t * q);
+static void do_pf_request(struct request_queue * q);
static int pf_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -760,7 +760,7 @@ static void pf_end_request(int uptodate)
}
}
-static void do_pf_request(request_queue_t * q)
+static void do_pf_request(struct request_queue * q)
{
if (pf_busy)
return;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 31be33e4f119..540bf3676985 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -752,7 +752,7 @@ static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio
*/
static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
{
- request_queue_t *q = bdev_get_queue(pd->bdev);
+ struct request_queue *q = bdev_get_queue(pd->bdev);
struct request *rq;
int ret = 0;
@@ -979,7 +979,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
* Special care is needed if the underlying block device has a small
* max_phys_segments value.
*/
-static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q)
+static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
{
if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) {
/*
@@ -1058,15 +1058,12 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec)
}
}
-static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_read(struct bio *bio, int err)
{
struct packet_data *pkt = bio->bi_private;
struct pktcdvd_device *pd = pkt->pd;
BUG_ON(!pd);
- if (bio->bi_size)
- return 1;
-
VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio,
(unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err);
@@ -1077,19 +1074,14 @@ static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
wake_up(&pd->wqueue);
}
pkt_bio_finished(pd);
-
- return 0;
}
-static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_packet_write(struct bio *bio, int err)
{
struct packet_data *pkt = bio->bi_private;
struct pktcdvd_device *pd = pkt->pd;
BUG_ON(!pd);
- if (bio->bi_size)
- return 1;
-
VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err);
pd->stats.pkt_ended++;
@@ -1098,7 +1090,6 @@ static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int
atomic_dec(&pkt->io_wait);
atomic_inc(&pkt->run_sm);
wake_up(&pd->wqueue);
- return 0;
}
/*
@@ -1470,7 +1461,7 @@ static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
while (bio) {
next = bio->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
+ bio_endio(bio, uptodate ? 0 : -EIO);
bio = next;
}
pkt->orig_bios = pkt->orig_bios_tail = NULL;
@@ -2314,7 +2305,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
{
int ret;
long lba;
- request_queue_t *q;
+ struct request_queue *q;
/*
* We need to re-open the cdrom device without O_NONBLOCK to be able
@@ -2462,22 +2453,18 @@ static int pkt_close(struct inode *inode, struct file *file)
}
-static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_read_cloned(struct bio *bio, int err)
{
struct packet_stacked_data *psd = bio->bi_private;
struct pktcdvd_device *pd = psd->pd;
- if (bio->bi_size)
- return 1;
-
bio_put(bio);
- bio_endio(psd->bio, psd->bio->bi_size, err);
+ bio_endio(psd->bio, err);
mempool_free(psd, psd_pool);
pkt_bio_finished(pd);
- return 0;
}
-static int pkt_make_request(request_queue_t *q, struct bio *bio)
+static int pkt_make_request(struct request_queue *q, struct bio *bio)
{
struct pktcdvd_device *pd;
char b[BDEVNAME_SIZE];
@@ -2620,13 +2607,13 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
}
return 0;
end_io:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
-static int pkt_merge_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *bvec)
+static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec)
{
struct pktcdvd_device *pd = q->queuedata;
sector_t zone = ZONE(bio->bi_sector, pd);
@@ -2647,7 +2634,7 @@ static int pkt_merge_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *b
static void pkt_init_queue(struct pktcdvd_device *pd)
{
- request_queue_t *q = pd->disk->queue;
+ struct request_queue *q = pd->disk->queue;
blk_queue_make_request(q, pkt_make_request);
blk_queue_hardsect_size(q, CD_FRAMESIZE);
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 688a4fb0dc99..3c796e236253 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -64,7 +64,7 @@ static void reset_ctrl(void);
static int ps2esdi_geninit(void);
-static void do_ps2esdi_request(request_queue_t * q);
+static void do_ps2esdi_request(struct request_queue * q);
static void ps2esdi_readwrite(int cmd, struct request *req);
@@ -473,7 +473,7 @@ static void __init ps2esdi_get_device_cfg(void)
}
/* strategy routine that handles most of the IO requests */
-static void do_ps2esdi_request(request_queue_t * q)
+static void do_ps2esdi_request(struct request_queue * q)
{
struct request *req;
/* since, this routine is called with interrupts cleared - they
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
new file mode 100644
index 000000000000..06d0552cf49c
--- /dev/null
+++ b/drivers/block/ps3disk.c
@@ -0,0 +1,630 @@
+/*
+ * PS3 Disk Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+#include <asm/firmware.h>
+
+
+#define DEVICE_NAME "ps3disk"
+
+#define BOUNCE_SIZE (64*1024)
+
+#define PS3DISK_MAX_DISKS 16
+#define PS3DISK_MINORS 16
+
+
+#define PS3DISK_NAME "ps3d%c"
+
+
+struct ps3disk_private {
+ spinlock_t lock; /* Request queue spinlock */
+ struct request_queue *queue;
+ struct gendisk *gendisk;
+ unsigned int blocking_factor;
+ struct request *req;
+ u64 raw_capacity;
+ unsigned char model[ATA_ID_PROD_LEN+1];
+};
+
+
+#define LV1_STORAGE_SEND_ATA_COMMAND (2)
+#define LV1_STORAGE_ATA_HDDOUT (0x23)
+
+struct lv1_ata_cmnd_block {
+ u16 features;
+ u16 sector_count;
+ u16 LBA_low;
+ u16 LBA_mid;
+ u16 LBA_high;
+ u8 device;
+ u8 command;
+ u32 is_ext;
+ u32 proto;
+ u32 in_out;
+ u32 size;
+ u64 buffer;
+ u32 arglen;
+};
+
+enum lv1_ata_proto {
+ NON_DATA_PROTO = 0,
+ PIO_DATA_IN_PROTO = 1,
+ PIO_DATA_OUT_PROTO = 2,
+ DMA_PROTO = 3
+};
+
+enum lv1_ata_in_out {
+ DIR_WRITE = 0, /* memory -> device */
+ DIR_READ = 1 /* device -> memory */
+};
+
+static int ps3disk_major;
+
+
+static struct block_device_operations ps3disk_fops = {
+ .owner = THIS_MODULE,
+};
+
+
+static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
+ struct request *req, int gather)
+{
+ unsigned int offset = 0;
+ struct req_iterator iter;
+ struct bio_vec *bvec;
+ unsigned int i = 0;
+ size_t size;
+ void *buf;
+
+ rq_for_each_segment(bvec, req, iter) {
+ unsigned long flags;
+ 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);
+
+ size = bvec->bv_len;
+ buf = bvec_kmap_irq(bvec, &flags);
+ if (gather)
+ memcpy(dev->bounce_buf+offset, buf, size);
+ else
+ memcpy(buf, dev->bounce_buf+offset, size);
+ offset += size;
+ flush_kernel_dcache_page(bvec->bv_page);
+ bvec_kunmap_irq(bvec, &flags);
+ i++;
+ }
+}
+
+static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
+ struct request *req)
+{
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+ int write = rq_data_dir(req), res;
+ const char *op = write ? "write" : "read";
+ u64 start_sector, sectors;
+ unsigned int region_id = dev->regions[dev->region_idx].id;
+
+#ifdef DEBUG
+ unsigned int n = 0;
+ struct bio_vec *bv;
+ struct req_iterator iter;
+
+ rq_for_each_segment(bv, req, iter)
+ n++;
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n",
+ __func__, __LINE__, op, n, req->nr_sectors,
+ req->hard_nr_sectors);
+#endif
+
+ start_sector = req->sector * priv->blocking_factor;
+ sectors = req->nr_sectors * priv->blocking_factor;
+ dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+ __func__, __LINE__, op, sectors, start_sector);
+
+ if (write) {
+ ps3disk_scatter_gather(dev, req, 1);
+
+ res = lv1_storage_write(dev->sbd.dev_id, region_id,
+ start_sector, sectors, 0,
+ dev->bounce_lpar, &dev->tag);
+ } else {
+ res = lv1_storage_read(dev->sbd.dev_id, region_id,
+ start_sector, sectors, 0,
+ dev->bounce_lpar, &dev->tag);
+ }
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
+ __LINE__, op, res);
+ end_request(req, 0);
+ return 0;
+ }
+
+ priv->req = req;
+ return 1;
+}
+
+static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
+ struct request *req)
+{
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+ u64 res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
+
+ res = lv1_storage_send_device_command(dev->sbd.dev_id,
+ LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
+ 0, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+ __func__, __LINE__, res);
+ end_request(req, 0);
+ return 0;
+ }
+
+ priv->req = req;
+ return 1;
+}
+
+static void ps3disk_do_request(struct ps3_storage_device *dev,
+ struct request_queue *q)
+{
+ struct request *req;
+
+ dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+ while ((req = elv_next_request(q))) {
+ if (blk_fs_request(req)) {
+ if (ps3disk_submit_request_sg(dev, req))
+ break;
+ } else if (req->cmd_type == REQ_TYPE_FLUSH) {
+ if (ps3disk_submit_flush_request(dev, req))
+ break;
+ } else {
+ blk_dump_rq_flags(req, DEVICE_NAME " bad request");
+ end_request(req, 0);
+ continue;
+ }
+ }
+}
+
+static void ps3disk_request(struct request_queue *q)
+{
+ struct ps3_storage_device *dev = q->queuedata;
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+ if (priv->req) {
+ dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
+ return;
+ }
+
+ ps3disk_do_request(dev, q);
+}
+
+static irqreturn_t ps3disk_interrupt(int irq, void *data)
+{
+ struct ps3_storage_device *dev = data;
+ struct ps3disk_private *priv;
+ struct request *req;
+ int res, read, uptodate;
+ u64 tag, status;
+ unsigned long num_sectors;
+ const char *op;
+
+ res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+ if (tag != dev->tag)
+ dev_err(&dev->sbd.core,
+ "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ __func__, __LINE__, tag, dev->tag);
+
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ __func__, __LINE__, res, status);
+ return IRQ_HANDLED;
+ }
+
+ priv = dev->sbd.core.driver_data;
+ req = priv->req;
+ if (!req) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u non-block layer request completed\n", __func__,
+ __LINE__);
+ dev->lv1_status = status;
+ complete(&dev->done);
+ return IRQ_HANDLED;
+ }
+
+ if (req->cmd_type == REQ_TYPE_FLUSH) {
+ read = 0;
+ num_sectors = req->hard_cur_sectors;
+ op = "flush";
+ } else {
+ read = !rq_data_dir(req);
+ num_sectors = req->nr_sectors;
+ op = read ? "read" : "write";
+ }
+ if (status) {
+ dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ __LINE__, op, status);
+ uptodate = 0;
+ } else {
+ dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
+ __LINE__, op);
+ uptodate = 1;
+ if (read)
+ ps3disk_scatter_gather(dev, req, 0);
+ }
+
+ spin_lock(&priv->lock);
+ if (!end_that_request_first(req, uptodate, num_sectors)) {
+ add_disk_randomness(req->rq_disk);
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, uptodate);
+ }
+ priv->req = NULL;
+ ps3disk_do_request(dev, priv->queue);
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int ps3disk_sync_cache(struct ps3_storage_device *dev)
+{
+ u64 res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
+
+ res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+ __func__, __LINE__, res);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+/* ATA helpers copied from drivers/ata/libata-core.c */
+
+static void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+ unsigned int i;
+
+ for (i = 0; i < buf_words; i++)
+ buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
+ unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
+ unsigned int len)
+{
+ unsigned char *p;
+
+ WARN_ON(!(len & 1));
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen(s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
+
+static int ps3disk_identify(struct ps3_storage_device *dev)
+{
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+ struct lv1_ata_cmnd_block ata_cmnd;
+ u16 *id = dev->bounce_buf;
+ u64 res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__);
+
+ memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
+ ata_cmnd.command = ATA_CMD_ID_ATA;
+ ata_cmnd.sector_count = 1;
+ ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
+ ata_cmnd.buffer = dev->bounce_lpar;
+ ata_cmnd.proto = PIO_DATA_IN_PROTO;
+ ata_cmnd.in_out = DIR_READ;
+
+ res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
+ ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
+ sizeof(ata_cmnd), ata_cmnd.buffer,
+ ata_cmnd.arglen);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n",
+ __func__, __LINE__, res);
+ return -EIO;
+ }
+
+ swap_buf_le16(id, ATA_ID_WORDS);
+
+ /* All we're interested in are raw capacity and model name */
+ priv->raw_capacity = ata_id_n_sectors(id);
+ ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
+ return 0;
+}
+
+static void ps3disk_prepare_flush(struct request_queue *q, struct request *req)
+{
+ struct ps3_storage_device *dev = q->queuedata;
+
+ dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+ memset(req->cmd, 0, sizeof(req->cmd));
+ req->cmd_type = REQ_TYPE_FLUSH;
+}
+
+static int ps3disk_issue_flush(struct request_queue *q, struct gendisk *gendisk,
+ sector_t *sector)
+{
+ struct ps3_storage_device *dev = q->queuedata;
+ struct request *req;
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+ req = blk_get_request(q, WRITE, __GFP_WAIT);
+ ps3disk_prepare_flush(q, req);
+ res = blk_execute_rq(q, gendisk, req, 0);
+ if (res)
+ dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n",
+ __func__, __LINE__, res);
+ blk_put_request(req);
+ return res;
+}
+
+
+static unsigned long ps3disk_mask;
+
+static DEFINE_MUTEX(ps3disk_mask_mutex);
+
+static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct ps3disk_private *priv;
+ int error;
+ unsigned int devidx;
+ struct request_queue *queue;
+ struct gendisk *gendisk;
+
+ if (dev->blk_size < 512) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: cannot handle block size %lu\n", __func__,
+ __LINE__, dev->blk_size);
+ return -EINVAL;
+ }
+
+ BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
+ mutex_lock(&ps3disk_mask_mutex);
+ devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
+ if (devidx >= PS3DISK_MAX_DISKS) {
+ dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__,
+ __LINE__);
+ mutex_unlock(&ps3disk_mask_mutex);
+ return -ENOSPC;
+ }
+ __set_bit(devidx, &ps3disk_mask);
+ mutex_unlock(&ps3disk_mask_mutex);
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dev->sbd.core.driver_data = priv;
+ spin_lock_init(&priv->lock);
+
+ dev->bounce_size = BOUNCE_SIZE;
+ dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+ if (!dev->bounce_buf) {
+ error = -ENOMEM;
+ goto fail_free_priv;
+ }
+
+ error = ps3stor_setup(dev, ps3disk_interrupt);
+ if (error)
+ goto fail_free_bounce;
+
+ ps3disk_identify(dev);
+
+ queue = blk_init_queue(ps3disk_request, &priv->lock);
+ if (!queue) {
+ dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
+ __func__, __LINE__);
+ error = -ENOMEM;
+ goto fail_teardown;
+ }
+
+ priv->queue = queue;
+ queue->queuedata = dev;
+
+ blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
+
+ blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+ blk_queue_segment_boundary(queue, -1UL);
+ blk_queue_dma_alignment(queue, dev->blk_size-1);
+ blk_queue_hardsect_size(queue, dev->blk_size);
+
+ blk_queue_issue_flush_fn(queue, ps3disk_issue_flush);
+ blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
+ ps3disk_prepare_flush);
+
+ blk_queue_max_phys_segments(queue, -1);
+ blk_queue_max_hw_segments(queue, -1);
+ blk_queue_max_segment_size(queue, dev->bounce_size);
+
+ gendisk = alloc_disk(PS3DISK_MINORS);
+ if (!gendisk) {
+ dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
+ __LINE__);
+ error = -ENOMEM;
+ goto fail_cleanup_queue;
+ }
+
+ priv->gendisk = gendisk;
+ gendisk->major = ps3disk_major;
+ gendisk->first_minor = devidx * PS3DISK_MINORS;
+ gendisk->fops = &ps3disk_fops;
+ gendisk->queue = queue;
+ gendisk->private_data = dev;
+ gendisk->driverfs_dev = &dev->sbd.core;
+ snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
+ devidx+'a');
+ priv->blocking_factor = dev->blk_size >> 9;
+ set_capacity(gendisk,
+ dev->regions[dev->region_idx].size*priv->blocking_factor);
+
+ dev_info(&dev->sbd.core,
+ "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n",
+ gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
+ get_capacity(gendisk) >> 11);
+
+ add_disk(gendisk);
+ return 0;
+
+fail_cleanup_queue:
+ blk_cleanup_queue(queue);
+fail_teardown:
+ ps3stor_teardown(dev);
+fail_free_bounce:
+ kfree(dev->bounce_buf);
+fail_free_priv:
+ kfree(priv);
+ dev->sbd.core.driver_data = NULL;
+fail:
+ mutex_lock(&ps3disk_mask_mutex);
+ __clear_bit(devidx, &ps3disk_mask);
+ mutex_unlock(&ps3disk_mask_mutex);
+ return error;
+}
+
+static int ps3disk_remove(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+ mutex_lock(&ps3disk_mask_mutex);
+ __clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+ &ps3disk_mask);
+ mutex_unlock(&ps3disk_mask_mutex);
+ del_gendisk(priv->gendisk);
+ blk_cleanup_queue(priv->queue);
+ put_disk(priv->gendisk);
+ dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
+ ps3disk_sync_cache(dev);
+ ps3stor_teardown(dev);
+ kfree(dev->bounce_buf);
+ kfree(priv);
+ dev->sbd.core.driver_data = NULL;
+ return 0;
+}
+
+static struct ps3_system_bus_driver ps3disk = {
+ .match_id = PS3_MATCH_ID_STOR_DISK,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3disk_probe,
+ .remove = ps3disk_remove,
+ .shutdown = ps3disk_remove,
+};
+
+
+static int __init ps3disk_init(void)
+{
+ int error;
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENODEV;
+
+ error = register_blkdev(0, DEVICE_NAME);
+ if (error <= 0) {
+ printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
+ __LINE__, error);
+ return error;
+ }
+ ps3disk_major = error;
+
+ pr_info("%s:%u: registered block device major %d\n", __func__,
+ __LINE__, ps3disk_major);
+
+ error = ps3_system_bus_driver_register(&ps3disk);
+ if (error)
+ unregister_blkdev(ps3disk_major, DEVICE_NAME);
+
+ return error;
+}
+
+static void __exit ps3disk_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3disk);
+ unregister_blkdev(ps3disk_major, DEVICE_NAME);
+}
+
+module_init(ps3disk_init);
+module_exit(ps3disk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Disk Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index a1512da32410..701ea77f62e9 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -264,7 +264,7 @@ static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector,
* 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Added devfs support
*
*/
-static int rd_make_request(request_queue_t *q, struct bio *bio)
+static int rd_make_request(struct request_queue *q, struct bio *bio)
{
struct block_device *bdev = bio->bi_bdev;
struct address_space * mapping = bdev->bd_inode->i_mapping;
@@ -287,10 +287,10 @@ static int rd_make_request(request_queue_t *q, struct bio *bio)
if (ret)
goto fail;
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
return 0;
fail:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 0f5e3caf85d7..317a790c153b 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -45,8 +45,6 @@ struct vdc_req_entry {
struct vdc_port {
struct vio_driver_state vio;
- struct vdc *vp;
-
struct gendisk *disk;
struct vdc_completion *cmp;
@@ -66,14 +64,11 @@ struct vdc_port {
u64 operations;
u32 vdisk_size;
u8 vdisk_type;
- u8 dev_no;
char disk_name[32];
struct vio_disk_geom geom;
struct vio_disk_vtoc label;
-
- struct list_head list;
};
static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
@@ -81,15 +76,6 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
return container_of(vio, struct vdc_port, vio);
}
-struct vdc {
- /* Protects prot_list. */
- spinlock_t lock;
-
- struct vio_dev *dev;
-
- struct list_head port_list;
-};
-
/* Ordered from largest major to lowest */
static struct vio_version vdc_versions[] = {
{ .major = 1, .minor = 0 },
@@ -431,7 +417,7 @@ static int __send_request(struct request *req)
desc->req_id = port->req_id;
desc->operation = op;
if (port->vdisk_type == VD_DISK_TYPE_DISK) {
- desc->slice = 2;
+ desc->slice = 0xff;
} else {
desc->slice = 0;
}
@@ -458,7 +444,7 @@ out:
return err;
}
-static void do_vdc_request(request_queue_t *q)
+static void do_vdc_request(struct request_queue *q)
{
while (1) {
struct request *req = elv_next_request(q);
@@ -716,7 +702,7 @@ static int probe_disk(struct vdc_port *port)
blk_queue_max_phys_segments(q, port->ring_cookies);
blk_queue_max_sectors(q, port->max_xfer_size);
g->major = vdc_major;
- g->first_minor = port->dev_no << PARTITION_SHIFT;
+ g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
strcpy(g->disk_name, port->disk_name);
g->fops = &vdc_fops;
@@ -747,32 +733,29 @@ static struct vio_driver_ops vdc_vio_ops = {
.handshake_complete = vdc_handshake_complete,
};
+static void print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
static int __devinit vdc_port_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
struct mdesc_handle *hp;
struct vdc_port *port;
- unsigned long flags;
- struct vdc *vp;
- const u64 *port_id;
int err;
- vp = dev_get_drvdata(vdev->dev.parent);
- if (!vp) {
- printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
- return -ENODEV;
- }
+ print_version();
hp = mdesc_grab();
- port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
err = -ENODEV;
- if (!port_id) {
- printk(KERN_ERR PFX "Port lacks id property.\n");
- goto err_out_release_mdesc;
- }
- if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
- printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+ if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+ printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+ vdev->dev_no);
goto err_out_release_mdesc;
}
@@ -783,17 +766,14 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
goto err_out_release_mdesc;
}
- port->vp = vp;
- port->dev_no = *port_id;
-
- if (port->dev_no >= 26)
+ if (vdev->dev_no >= 26)
snprintf(port->disk_name, sizeof(port->disk_name),
VDCBLK_NAME "%c%c",
- 'a' + (port->dev_no / 26) - 1,
- 'a' + (port->dev_no % 26));
+ 'a' + ((int)vdev->dev_no / 26) - 1,
+ 'a' + ((int)vdev->dev_no % 26));
else
snprintf(port->disk_name, sizeof(port->disk_name),
- VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+ VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
vdc_versions, ARRAY_SIZE(vdc_versions),
@@ -818,12 +798,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
if (err)
goto err_out_free_tx_ring;
- INIT_LIST_HEAD(&port->list);
-
- spin_lock_irqsave(&vp->lock, flags);
- list_add(&port->list, &vp->port_list);
- spin_unlock_irqrestore(&vp->lock, flags);
-
dev_set_drvdata(&vdev->dev, port);
mdesc_release(hp);
@@ -867,7 +841,7 @@ static struct vio_device_id vdc_port_match[] = {
},
{},
};
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
static struct vio_driver vdc_port_driver = {
.id_table = vdc_port_match,
@@ -879,58 +853,6 @@ static struct vio_driver vdc_port_driver = {
}
};
-static int __devinit vdc_probe(struct vio_dev *vdev,
- const struct vio_device_id *id)
-{
- static int vdc_version_printed;
- struct vdc *vp;
-
- if (vdc_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-
- vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
- if (!vp)
- return -ENOMEM;
-
- spin_lock_init(&vp->lock);
- vp->dev = vdev;
- INIT_LIST_HEAD(&vp->port_list);
-
- dev_set_drvdata(&vdev->dev, vp);
-
- return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
- struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
- if (vp) {
- kfree(vp);
- dev_set_drvdata(&vdev->dev, NULL);
- }
- return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
- {
- .type = "block",
- },
- {},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
- .id_table = vdc_match,
- .probe = vdc_probe,
- .remove = vdc_remove,
- .driver = {
- .name = "vdc",
- .owner = THIS_MODULE,
- }
-};
-
static int __init vdc_init(void)
{
int err;
@@ -940,19 +862,13 @@ static int __init vdc_init(void)
goto out_err;
vdc_major = err;
- err = vio_register_driver(&vdc_driver);
- if (err)
- goto out_unregister_blkdev;
err = vio_register_driver(&vdc_port_driver);
if (err)
- goto out_unregister_vdc;
+ goto out_unregister_blkdev;
return 0;
-out_unregister_vdc:
- vio_unregister_driver(&vdc_driver);
-
out_unregister_blkdev:
unregister_blkdev(vdc_major, VDCBLK_NAME);
vdc_major = 0;
@@ -964,7 +880,6 @@ out_err:
static void __exit vdc_exit(void)
{
vio_unregister_driver(&vdc_port_driver);
- vio_unregister_driver(&vdc_driver);
unregister_blkdev(vdc_major, VDCBLK_NAME);
}
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 1a65979f1f0f..b4e462f154ea 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -225,7 +225,7 @@ static unsigned short write_postamble[] = {
static void swim3_select(struct floppy_state *fs, int sel);
static void swim3_action(struct floppy_state *fs, int action);
static int swim3_readbit(struct floppy_state *fs, int bit);
-static void do_fd_request(request_queue_t * q);
+static void do_fd_request(struct request_queue * q);
static void start_request(struct floppy_state *fs);
static void set_timeout(struct floppy_state *fs, int nticks,
void (*proc)(unsigned long));
@@ -290,7 +290,7 @@ static int swim3_readbit(struct floppy_state *fs, int bit)
return (stat & DATA) == 0;
}
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
{
int i;
for(i=0;i<floppy_count;i++)
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 54509eb3391b..402209fec59a 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -278,7 +278,7 @@ struct carm_host {
unsigned int state;
u32 fw_ver;
- request_queue_t *oob_q;
+ struct request_queue *oob_q;
unsigned int n_oob;
unsigned int hw_sg_used;
@@ -287,7 +287,7 @@ struct carm_host {
unsigned int wait_q_prod;
unsigned int wait_q_cons;
- request_queue_t *wait_q[CARM_MAX_WAIT_Q];
+ struct request_queue *wait_q[CARM_MAX_WAIT_Q];
unsigned int n_msgs;
u64 msg_alloc;
@@ -756,7 +756,7 @@ static inline void carm_end_request_queued(struct carm_host *host,
assert(rc == 0);
}
-static inline void carm_push_q (struct carm_host *host, request_queue_t *q)
+static inline void carm_push_q (struct carm_host *host, struct request_queue *q)
{
unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q;
@@ -768,7 +768,7 @@ static inline void carm_push_q (struct carm_host *host, request_queue_t *q)
BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */
}
-static inline request_queue_t *carm_pop_q(struct carm_host *host)
+static inline struct request_queue *carm_pop_q(struct carm_host *host)
{
unsigned int idx;
@@ -783,7 +783,7 @@ static inline request_queue_t *carm_pop_q(struct carm_host *host)
static inline void carm_round_robin(struct carm_host *host)
{
- request_queue_t *q = carm_pop_q(host);
+ struct request_queue *q = carm_pop_q(host);
if (q) {
blk_start_queue(q);
VPRINTK("STARTED QUEUE %p\n", q);
@@ -802,7 +802,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
}
}
-static void carm_oob_rq_fn(request_queue_t *q)
+static void carm_oob_rq_fn(struct request_queue *q)
{
struct carm_host *host = q->queuedata;
struct carm_request *crq;
@@ -833,7 +833,7 @@ static void carm_oob_rq_fn(request_queue_t *q)
}
}
-static void carm_rq_fn(request_queue_t *q)
+static void carm_rq_fn(struct request_queue *q)
{
struct carm_port *port = q->queuedata;
struct carm_host *host = port->host;
@@ -1494,7 +1494,7 @@ static int carm_init_disks(struct carm_host *host)
for (i = 0; i < CARM_MAX_PORTS; i++) {
struct gendisk *disk;
- request_queue_t *q;
+ struct request_queue *q;
struct carm_port *port;
port = &host->port[i];
@@ -1538,7 +1538,7 @@ static void carm_free_disks(struct carm_host *host)
for (i = 0; i < CARM_MAX_PORTS; i++) {
struct gendisk *disk = host->port[i].disk;
if (disk) {
- request_queue_t *q = disk->queue;
+ struct request_queue *q = disk->queue;
if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
@@ -1571,7 +1571,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct carm_host *host;
unsigned int pci_dac;
int rc;
- request_queue_t *q;
+ struct request_queue *q;
unsigned int i;
if (!printed_version++)
@@ -1608,7 +1608,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
#endif
- host = kmalloc(sizeof(*host), GFP_KERNEL);
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
if (!host) {
printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
pci_name(pdev));
@@ -1616,7 +1616,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_regions;
}
- memset(host, 0, sizeof(*host));
host->pdev = pdev;
host->flags = pci_dac ? FL_DAC : 0;
spin_lock_init(&host->lock);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 8b13d7d2cb63..c57dd2b3a0c8 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -503,7 +503,7 @@ static void ub_cleanup(struct ub_dev *sc)
{
struct list_head *p;
struct ub_lun *lun;
- request_queue_t *q;
+ struct request_queue *q;
while (!list_empty(&sc->luns)) {
p = sc->luns.next;
@@ -619,7 +619,7 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
* The request function is our main entry point
*/
-static void ub_request_fn(request_queue_t *q)
+static void ub_request_fn(struct request_queue *q)
{
struct ub_lun *lun = q->queuedata;
struct request *rq;
@@ -2273,7 +2273,7 @@ err_core:
static int ub_probe_lun(struct ub_dev *sc, int lnum)
{
struct ub_lun *lun;
- request_queue_t *q;
+ struct request_queue *q;
struct gendisk *disk;
int rc;
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index dec74bd23496..99806f9ee4ce 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -52,7 +52,7 @@
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
-#include <linux/umem.h>
+#include "umem.h"
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -67,9 +67,10 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.3"
-#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown"
-#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver"
+#define DRIVER_NAME "umem"
+#define DRIVER_VERSION "v2.3"
+#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown"
+#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver"
static int debug;
/* #define HW_TRACE(x) writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */
@@ -97,15 +98,9 @@ static int major_nr;
#include <linux/blkpg.h>
struct cardinfo {
- int card_number;
struct pci_dev *dev;
- int irq;
-
- unsigned long csr_base;
unsigned char __iomem *csr_remap;
- unsigned long csr_len;
- unsigned int win_size; /* PCI window size */
unsigned int mm_size; /* size in kbytes */
unsigned int init_size; /* initial segment, in sectors,
@@ -113,14 +108,17 @@ struct cardinfo {
* have been written
*/
struct bio *bio, *currentbio, **biotail;
+ int current_idx;
+ sector_t current_sector;
- request_queue_t *queue;
+ struct request_queue *queue;
struct mm_page {
dma_addr_t page_dma;
struct mm_dma_desc *desc;
int cnt, headcnt;
struct bio *bio, **biotail;
+ int idx;
} mm_pages[2];
#define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc))
@@ -233,7 +231,7 @@ static void dump_regs(struct cardinfo *card)
*/
static void dump_dmastat(struct cardinfo *card, unsigned int dmastat)
{
- printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number);
+ dev_printk(KERN_DEBUG, &card->dev->dev, "DMAstat - ");
if (dmastat & DMASCR_ANY_ERR)
printk("ANY_ERR ");
if (dmastat & DMASCR_MBE_ERR)
@@ -295,7 +293,7 @@ static void mm_start_io(struct cardinfo *card)
desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN);
desc->sem_control_bits = desc->control_bits;
-
+
if (debug & DEBUG_LED_ON_TRANSFER)
set_led(card, LED_REMOVE, LED_ON);
@@ -329,7 +327,7 @@ static int add_bio(struct cardinfo *card);
static void activate(struct cardinfo *card)
{
- /* if No page is Active, and Ready is
+ /* if No page is Active, and Ready is
* not empty, then switch Ready page
* to active and start IO.
* Then add any bh's that are available to Ready
@@ -357,7 +355,7 @@ static inline void reset_page(struct mm_page *page)
page->biotail = & page->bio;
}
-static void mm_unplug_device(request_queue_t *q)
+static void mm_unplug_device(struct request_queue *q)
{
struct cardinfo *card = q->queuedata;
unsigned long flags;
@@ -368,7 +366,7 @@ static void mm_unplug_device(request_queue_t *q)
spin_unlock_irqrestore(&card->lock, flags);
}
-/*
+/*
* If there is room on Ready page, take
* one bh off list and add it.
* return 1 if there was room, else 0.
@@ -380,12 +378,16 @@ static int add_bio(struct cardinfo *card)
dma_addr_t dma_handle;
int offset;
struct bio *bio;
+ struct bio_vec *vec;
+ int idx;
int rw;
int len;
bio = card->currentbio;
if (!bio && card->bio) {
card->currentbio = card->bio;
+ card->current_idx = card->bio->bi_idx;
+ card->current_sector = card->bio->bi_sector;
card->bio = card->bio->bi_next;
if (card->bio == NULL)
card->biotail = &card->bio;
@@ -394,15 +396,17 @@ static int add_bio(struct cardinfo *card)
}
if (!bio)
return 0;
+ idx = card->current_idx;
rw = bio_rw(bio);
if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE)
return 0;
- len = bio_iovec(bio)->bv_len;
- dma_handle = pci_map_page(card->dev,
- bio_page(bio),
- bio_offset(bio),
+ vec = bio_iovec_idx(bio, idx);
+ len = vec->bv_len;
+ dma_handle = pci_map_page(card->dev,
+ vec->bv_page,
+ vec->bv_offset,
len,
(rw==READ) ?
PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
@@ -410,6 +414,8 @@ static int add_bio(struct cardinfo *card)
p = &card->mm_pages[card->Ready];
desc = &p->desc[p->cnt];
p->cnt++;
+ if (p->bio == NULL)
+ p->idx = idx;
if ((p->biotail) != &bio->bi_next) {
*(p->biotail) = bio;
p->biotail = &(bio->bi_next);
@@ -419,7 +425,7 @@ static int add_bio(struct cardinfo *card)
desc->data_dma_handle = dma_handle;
desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle);
- desc->local_addr= cpu_to_le64(bio->bi_sector << 9);
+ desc->local_addr = cpu_to_le64(card->current_sector << 9);
desc->transfer_size = cpu_to_le32(len);
offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc));
desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset));
@@ -435,10 +441,10 @@ static int add_bio(struct cardinfo *card)
desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ);
desc->sem_control_bits = desc->control_bits;
- bio->bi_sector += (len>>9);
- bio->bi_size -= len;
- bio->bi_idx++;
- if (bio->bi_idx >= bio->bi_vcnt)
+ card->current_sector += (len >> 9);
+ idx++;
+ card->current_idx = idx;
+ if (idx >= bio->bi_vcnt)
card->currentbio = NULL;
return 1;
@@ -461,7 +467,7 @@ static void process_page(unsigned long data)
if (card->Active < 0)
goto out_unlock;
page = &card->mm_pages[card->Active];
-
+
while (page->headcnt < page->cnt) {
struct bio *bio = page->bio;
struct mm_dma_desc *desc = &page->desc[page->headcnt];
@@ -471,32 +477,34 @@ static void process_page(unsigned long data)
if (!(control & DMASCR_DMA_COMPLETE)) {
control = dma_status;
- last=1;
+ last=1;
}
page->headcnt++;
- idx = bio->bi_phys_segments;
- bio->bi_phys_segments++;
- if (bio->bi_phys_segments >= bio->bi_vcnt)
+ idx = page->idx;
+ page->idx++;
+ if (page->idx >= bio->bi_vcnt) {
page->bio = bio->bi_next;
+ page->idx = page->bio->bi_idx;
+ }
- pci_unmap_page(card->dev, desc->data_dma_handle,
+ pci_unmap_page(card->dev, desc->data_dma_handle,
bio_iovec_idx(bio,idx)->bv_len,
(control& DMASCR_TRANSFER_READ) ?
PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
if (control & DMASCR_HARD_ERROR) {
/* error */
clear_bit(BIO_UPTODATE, &bio->bi_flags);
- printk(KERN_WARNING "MM%d: I/O error on sector %d/%d\n",
- card->card_number,
- le32_to_cpu(desc->local_addr)>>9,
- le32_to_cpu(desc->transfer_size));
+ dev_printk(KERN_WARNING, &card->dev->dev,
+ "I/O error on sector %d/%d\n",
+ le32_to_cpu(desc->local_addr)>>9,
+ le32_to_cpu(desc->transfer_size));
dump_dmastat(card, control);
} else if (test_bit(BIO_RW, &bio->bi_rw) &&
le32_to_cpu(desc->local_addr)>>9 == card->init_size) {
card->init_size += le32_to_cpu(desc->transfer_size)>>9;
if (card->init_size>>1 >= card->mm_size) {
- printk(KERN_INFO "MM%d: memory now initialised\n",
- card->card_number);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "memory now initialised\n");
set_userbit(card, MEMORY_INITIALIZED, 1);
}
}
@@ -532,7 +540,7 @@ static void process_page(unsigned long data)
return_bio = bio->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
}
}
@@ -541,13 +549,12 @@ static void process_page(unsigned long data)
-- mm_make_request
-----------------------------------------------------------------------------------
*/
-static int mm_make_request(request_queue_t *q, struct bio *bio)
+static int mm_make_request(struct request_queue *q, struct bio *bio)
{
struct cardinfo *card = q->queuedata;
pr_debug("mm_make_request %llu %u\n",
(unsigned long long)bio->bi_sector, bio->bi_size);
- bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/
spin_lock_irq(&card->lock);
*card->biotail = bio;
bio->bi_next = NULL;
@@ -585,7 +592,7 @@ HW_TRACE(0x30);
else
writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16,
card->csr_remap+ DMA_STATUS_CTRL + 2);
-
+
/* log errors and clear interrupt status */
if (dma_status & DMASCR_ANY_ERR) {
unsigned int data_log1, data_log2;
@@ -606,46 +613,51 @@ HW_TRACE(0x30);
dump_dmastat(card, dma_status);
if (stat & 0x01)
- printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n",
- card->card_number, count);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Memory access error detected (err count %d)\n",
+ count);
if (stat & 0x02)
- printk(KERN_ERR "MM%d*: Multi-bit EDC error\n",
- card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Multi-bit EDC error\n");
- printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",
- card->card_number, addr_log2, addr_log1, data_log2, data_log1);
- printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n",
- card->card_number, check, syndrome);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",
+ addr_log2, addr_log1, data_log2, data_log1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Fault Check 0x%02x, Fault Syndrome 0x%02x\n",
+ check, syndrome);
writeb(0, card->csr_remap + ERROR_COUNT);
}
if (dma_status & DMASCR_PARITY_ERR_REP) {
- printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "PARITY ERROR REPORTED\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_PARITY_ERR_DET) {
- printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "PARITY ERROR DETECTED\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_SYSTEM_ERR_SIG) {
- printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "SYSTEM ERROR\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_TARGET_ABT) {
- printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "TARGET ABORT\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_MASTER_ABT) {
- printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "MASTER ABORT\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
@@ -656,7 +668,7 @@ HW_TRACE(0x30);
HW_TRACE(0x36);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
}
/*
-----------------------------------------------------------------------------------
@@ -696,20 +708,20 @@ static int check_battery(struct cardinfo *card, int battery, int status)
card->battery[battery].last_change = jiffies;
if (card->battery[battery].good) {
- printk(KERN_ERR "MM%d: Battery %d now good\n",
- card->card_number, battery + 1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Battery %d now good\n", battery + 1);
card->battery[battery].warned = 0;
} else
- printk(KERN_ERR "MM%d: Battery %d now FAILED\n",
- card->card_number, battery + 1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Battery %d now FAILED\n", battery + 1);
return 1;
} else if (!card->battery[battery].good &&
!card->battery[battery].warned &&
time_after_eq(jiffies, card->battery[battery].last_change +
(HZ * 60 * 60 * 5))) {
- printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n",
- card->card_number, battery + 1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Battery %d still FAILED after 5 hours\n", battery + 1);
card->battery[battery].warned = 1;
return 1;
@@ -733,8 +745,8 @@ static void check_batteries(struct cardinfo *card)
status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY);
if (debug & DEBUG_BATTERY_POLLING)
- printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n",
- card->card_number,
+ dev_printk(KERN_DEBUG, &card->dev->dev,
+ "checking battery status, 1 = %s, 2 = %s\n",
(status & BATTERY_1_FAILURE) ? "FAILURE" : "OK",
(status & BATTERY_2_FAILURE) ? "FAILURE" : "OK");
@@ -749,7 +761,7 @@ static void check_all_batteries(unsigned long ptr)
{
int i;
- for (i = 0; i < num_cards; i++)
+ for (i = 0; i < num_cards; i++)
if (!(cards[i].flags & UM_FLAG_NO_BATT)) {
struct cardinfo *card = &cards[i];
spin_lock_bh(&card->lock);
@@ -853,45 +865,56 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
unsigned char mem_present;
unsigned char batt_status;
unsigned int saved_bar, data;
+ unsigned long csr_base;
+ unsigned long csr_len;
int magic_number;
+ static int printed_version;
- if (pci_enable_device(dev) < 0)
- return -ENODEV;
+ if (!printed_version++)
+ printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
+
+ ret = pci_enable_device(dev);
+ if (ret)
+ return ret;
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8);
pci_set_master(dev);
card->dev = dev;
- card->card_number = num_cards;
- card->csr_base = pci_resource_start(dev, 0);
- card->csr_len = pci_resource_len(dev, 0);
+ csr_base = pci_resource_start(dev, 0);
+ csr_len = pci_resource_len(dev, 0);
+ if (!csr_base || !csr_len)
+ return -ENODEV;
- printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n",
- card->card_number, dev->bus->number, dev->devfn);
+ dev_printk(KERN_INFO, &dev->dev,
+ "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n");
if (pci_set_dma_mask(dev, DMA_64BIT_MASK) &&
pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
+ dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n");
return -ENOMEM;
}
- if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) {
- printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number);
- ret = -ENOMEM;
+ ret = pci_request_regions(dev, DRIVER_NAME);
+ if (ret) {
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Unable to request memory region\n");
goto failed_req_csr;
}
- card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len);
+ card->csr_remap = ioremap_nocache(csr_base, csr_len);
if (!card->csr_remap) {
- printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Unable to remap memory region\n");
ret = -ENOMEM;
goto failed_remap_csr;
}
- printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number,
- card->csr_base, card->csr_remap, card->csr_len);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "CSR 0x%08lx -> 0x%p (0x%lx)\n",
+ csr_base, card->csr_remap, csr_len);
switch(card->dev->device) {
case 0x5415:
@@ -915,7 +938,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
}
if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) {
- printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "Magic number invalid\n");
ret = -ENOMEM;
goto failed_magic;
}
@@ -928,7 +951,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
&card->mm_pages[1].page_dma);
if (card->mm_pages[0].desc == NULL ||
card->mm_pages[1].desc == NULL) {
- printk(KERN_ERR "MM%d: alloc failed\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n");
goto failed_alloc;
}
reset_page(&card->mm_pages[0]);
@@ -949,7 +972,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
tasklet_init(&card->tasklet, process_page, (unsigned long)card);
card->check_batteries = 0;
-
+
mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY);
switch (mem_present) {
case MEM_128_MB:
@@ -982,12 +1005,13 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->battery[1].good = !(batt_status & BATTERY_2_FAILURE);
card->battery[0].last_change = card->battery[1].last_change = jiffies;
- if (card->flags & UM_FLAG_NO_BATT)
- printk(KERN_INFO "MM%d: Size %d KB\n",
- card->card_number, card->mm_size);
+ if (card->flags & UM_FLAG_NO_BATT)
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "Size %d KB\n", card->mm_size);
else {
- printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
- card->card_number, card->mm_size,
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
+ card->mm_size,
(batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"),
card->battery[0].good ? "OK" : "FAILURE",
(batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"),
@@ -1005,19 +1029,16 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
data = ~data;
data += 1;
- card->win_size = data;
-
-
- if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) {
- printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number);
+ if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, DRIVER_NAME, card)) {
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Unable to allocate IRQ\n");
ret = -ENODEV;
goto failed_req_irq;
}
- card->irq = dev->irq;
- printk(KERN_INFO "MM%d: Window size %d bytes, IRQ %d\n", card->card_number,
- card->win_size, card->irq);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "Window size %d bytes, IRQ %d\n", data, dev->irq);
spin_lock_init(&card->lock);
@@ -1037,10 +1058,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
num_cards++;
if (!get_userbit(card, MEMORY_INITIALIZED)) {
- printk(KERN_INFO "MM%d: memory NOT initialized. Consider over-writing whole device.\n", card->card_number);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "memory NOT initialized. Consider over-writing whole device.\n");
card->init_size = 0;
} else {
- printk(KERN_INFO "MM%d: memory already initialized\n", card->card_number);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "memory already initialized\n");
card->init_size = card->mm_size;
}
@@ -1062,7 +1085,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
failed_magic:
iounmap(card->csr_remap);
failed_remap_csr:
- release_mem_region(card->csr_base, card->csr_len);
+ pci_release_regions(dev);
failed_req_csr:
return ret;
@@ -1077,9 +1100,8 @@ static void mm_pci_remove(struct pci_dev *dev)
struct cardinfo *card = pci_get_drvdata(dev);
tasklet_kill(&card->tasklet);
+ free_irq(dev->irq, card);
iounmap(card->csr_remap);
- release_mem_region(card->csr_base, card->csr_len);
- free_irq(card->irq, card);
if (card->mm_pages[0].desc)
pci_free_consistent(card->dev, PAGE_SIZE*2,
@@ -1090,6 +1112,9 @@ static void mm_pci_remove(struct pci_dev *dev)
card->mm_pages[1].desc,
card->mm_pages[1].page_dma);
blk_cleanup_queue(card->queue);
+
+ pci_release_regions(dev);
+ pci_disable_device(dev);
}
static const struct pci_device_id mm_pci_ids[] = {
@@ -1109,11 +1134,12 @@ static const struct pci_device_id mm_pci_ids[] = {
MODULE_DEVICE_TABLE(pci, mm_pci_ids);
static struct pci_driver mm_pci_driver = {
- .name = "umem",
- .id_table = mm_pci_ids,
- .probe = mm_pci_probe,
- .remove = mm_pci_remove,
+ .name = DRIVER_NAME,
+ .id_table = mm_pci_ids,
+ .probe = mm_pci_probe,
+ .remove = mm_pci_remove,
};
+
/*
-----------------------------------------------------------------------------------
-- mm_init
@@ -1125,13 +1151,11 @@ static int __init mm_init(void)
int retval, i;
int err;
- printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
-
retval = pci_register_driver(&mm_pci_driver);
if (retval)
return -ENOMEM;
- err = major_nr = register_blkdev(0, "umem");
+ err = major_nr = register_blkdev(0, DRIVER_NAME);
if (err < 0) {
pci_unregister_driver(&mm_pci_driver);
return -EIO;
@@ -1157,13 +1181,13 @@ static int __init mm_init(void)
}
init_battery_timer();
- printk("MM: desc_per_page = %ld\n", DESC_PER_PAGE);
+ printk(KERN_INFO "MM: desc_per_page = %ld\n", DESC_PER_PAGE);
/* printk("mm_init: Done. 10-19-01 9:00\n"); */
return 0;
out:
pci_unregister_driver(&mm_pci_driver);
- unregister_blkdev(major_nr, "umem");
+ unregister_blkdev(major_nr, DRIVER_NAME);
while (i--)
put_disk(mm_gendisk[i]);
return -ENOMEM;
@@ -1186,7 +1210,7 @@ static void __exit mm_cleanup(void)
pci_unregister_driver(&mm_pci_driver);
- unregister_blkdev(major_nr, "umem");
+ unregister_blkdev(major_nr, DRIVER_NAME);
}
module_init(mm_init);
diff --git a/drivers/block/umem.h b/drivers/block/umem.h
new file mode 100644
index 000000000000..375c68974c9a
--- /dev/null
+++ b/drivers/block/umem.h
@@ -0,0 +1,133 @@
+
+/*
+ * This file contains defines for the
+ * Micro Memory MM5415
+ * family PCI Memory Module with Battery Backup.
+ *
+ * Copyright Micro Memory INC 2001. All rights reserved.
+ * Release under the terms of the GNU GENERAL PUBLIC LICENSE version 2.
+ * See the file COPYING.
+ */
+
+#ifndef _DRIVERS_BLOCK_MM_H
+#define _DRIVERS_BLOCK_MM_H
+
+
+#define IRQ_TIMEOUT (1 * HZ)
+
+/* CSR register definition */
+#define MEMCTRLSTATUS_MAGIC 0x00
+#define MM_MAGIC_VALUE (unsigned char)0x59
+
+#define MEMCTRLSTATUS_BATTERY 0x04
+#define BATTERY_1_DISABLED 0x01
+#define BATTERY_1_FAILURE 0x02
+#define BATTERY_2_DISABLED 0x04
+#define BATTERY_2_FAILURE 0x08
+
+#define MEMCTRLSTATUS_MEMORY 0x07
+#define MEM_128_MB 0xfe
+#define MEM_256_MB 0xfc
+#define MEM_512_MB 0xf8
+#define MEM_1_GB 0xf0
+#define MEM_2_GB 0xe0
+
+#define MEMCTRLCMD_LEDCTRL 0x08
+#define LED_REMOVE 2
+#define LED_FAULT 4
+#define LED_POWER 6
+#define LED_FLIP 255
+#define LED_OFF 0x00
+#define LED_ON 0x01
+#define LED_FLASH_3_5 0x02
+#define LED_FLASH_7_0 0x03
+#define LED_POWER_ON 0x00
+#define LED_POWER_OFF 0x01
+#define USER_BIT1 0x01
+#define USER_BIT2 0x02
+
+#define MEMORY_INITIALIZED USER_BIT1
+
+#define MEMCTRLCMD_ERRCTRL 0x0C
+#define EDC_NONE_DEFAULT 0x00
+#define EDC_NONE 0x01
+#define EDC_STORE_READ 0x02
+#define EDC_STORE_CORRECT 0x03
+
+#define MEMCTRLCMD_ERRCNT 0x0D
+#define MEMCTRLCMD_ERRSTATUS 0x0E
+
+#define ERROR_DATA_LOG 0x20
+#define ERROR_ADDR_LOG 0x28
+#define ERROR_COUNT 0x3D
+#define ERROR_SYNDROME 0x3E
+#define ERROR_CHECK 0x3F
+
+#define DMA_PCI_ADDR 0x40
+#define DMA_LOCAL_ADDR 0x48
+#define DMA_TRANSFER_SIZE 0x50
+#define DMA_DESCRIPTOR_ADDR 0x58
+#define DMA_SEMAPHORE_ADDR 0x60
+#define DMA_STATUS_CTRL 0x68
+#define DMASCR_GO 0x00001
+#define DMASCR_TRANSFER_READ 0x00002
+#define DMASCR_CHAIN_EN 0x00004
+#define DMASCR_SEM_EN 0x00010
+#define DMASCR_DMA_COMP_EN 0x00020
+#define DMASCR_CHAIN_COMP_EN 0x00040
+#define DMASCR_ERR_INT_EN 0x00080
+#define DMASCR_PARITY_INT_EN 0x00100
+#define DMASCR_ANY_ERR 0x00800
+#define DMASCR_MBE_ERR 0x01000
+#define DMASCR_PARITY_ERR_REP 0x02000
+#define DMASCR_PARITY_ERR_DET 0x04000
+#define DMASCR_SYSTEM_ERR_SIG 0x08000
+#define DMASCR_TARGET_ABT 0x10000
+#define DMASCR_MASTER_ABT 0x20000
+#define DMASCR_DMA_COMPLETE 0x40000
+#define DMASCR_CHAIN_COMPLETE 0x80000
+
+/*
+3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE
+READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA
+TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE
+TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS
+(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6,
+AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING
+DMA READ OPERATIONS.
+*/
+#define DMASCR_READ 0x60000000
+#define DMASCR_READLINE 0xE0000000
+#define DMASCR_READMULTI 0xC0000000
+
+
+#define DMASCR_ERROR_MASK (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR | DMASCR_ANY_ERR)
+#define DMASCR_HARD_ERROR (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR)
+
+#define WINDOWMAP_WINNUM 0x7B
+
+#define DMA_READ_FROM_HOST 0
+#define DMA_WRITE_TO_HOST 1
+
+struct mm_dma_desc {
+ __le64 pci_addr;
+ __le64 local_addr;
+ __le32 transfer_size;
+ u32 zero1;
+ __le64 next_desc_addr;
+ __le64 sem_addr;
+ __le32 control_bits;
+ u32 zero2;
+
+ dma_addr_t data_dma_handle;
+
+ /* Copy of the bits */
+ __le64 sem_control_bits;
+} __attribute__((aligned(8)));
+
+/* bits for card->flags */
+#define UM_FLAG_DMA_IN_REGS 1
+#define UM_FLAG_NO_BYTE_STATUS 2
+#define UM_FLAG_NO_BATTREG 4
+#define UM_FLAG_NO_BATT 8
+#endif
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index dae39911a11d..e824b672e05a 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -41,7 +41,6 @@
#include <linux/dma-mapping.h>
#include <linux/completion.h>
#include <linux/device.h>
-#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/vio.h>
@@ -75,53 +74,9 @@ enum {
static DEFINE_SPINLOCK(viodasd_spinlock);
#define VIOMAXREQ 16
-#define VIOMAXBLOCKDMA 12
#define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0])
-struct open_data {
- u64 disk_size;
- u16 max_disk;
- u16 cylinders;
- u16 tracks;
- u16 sectors;
- u16 bytes_per_sector;
-};
-
-struct rw_data {
- u64 offset;
- struct {
- u32 token;
- u32 reserved;
- u64 len;
- } dma_info[VIOMAXBLOCKDMA];
-};
-
-struct vioblocklpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 sub_result;
- u16 disk;
- u16 flags;
- union {
- struct open_data open_data;
- struct rw_data rw_data;
- u64 changed;
- } u;
-};
-
-#define vioblockflags_ro 0x0001
-
-enum vioblocksubtype {
- vioblockopen = 0x0001,
- vioblockclose = 0x0002,
- vioblockread = 0x0003,
- vioblockwrite = 0x0004,
- vioblockflush = 0x0005,
- vioblockcheck = 0x0007
-};
-
struct viodasd_waitevent {
struct completion com;
int rc;
@@ -400,7 +355,7 @@ error_ret:
/*
* This is the external request processing routine
*/
-static void do_viodasd_request(request_queue_t *q)
+static void do_viodasd_request(struct request_queue *q)
{
struct request *req;
@@ -430,7 +385,7 @@ static void do_viodasd_request(request_queue_t *q)
* Probe a single disk and fill in the viodasd_device structure
* for it.
*/
-static void probe_disk(struct viodasd_device *d)
+static int probe_disk(struct viodasd_device *d)
{
HvLpEvent_Rc hvrc;
struct viodasd_waitevent we;
@@ -454,14 +409,14 @@ retry:
0, 0, 0);
if (hvrc != 0) {
printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc);
- return;
+ return 0;
}
wait_for_completion(&we.com);
if (we.rc != 0) {
if (flags != 0)
- return;
+ return 0;
/* try again with read only flag set */
flags = vioblockflags_ro;
goto retry;
@@ -491,15 +446,32 @@ retry:
if (hvrc != 0) {
printk(VIOD_KERN_WARNING
"bad rc sending event to OS/400 %d\n", (int)hvrc);
- return;
+ return 0;
+ }
+
+ if (d->dev == NULL) {
+ /* this is when we reprobe for new disks */
+ if (vio_create_viodasd(dev_no) == NULL) {
+ printk(VIOD_KERN_WARNING
+ "cannot allocate virtual device for disk %d\n",
+ dev_no);
+ return 0;
+ }
+ /*
+ * The vio_create_viodasd will have recursed into this
+ * routine with d->dev set to the new vio device and
+ * will finish the setup of the disk below.
+ */
+ return 1;
}
+
/* create the request queue for the disk */
spin_lock_init(&d->q_lock);
q = blk_init_queue(do_viodasd_request, &d->q_lock);
if (q == NULL) {
printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n",
dev_no);
- return;
+ return 0;
}
g = alloc_disk(1 << PARTITION_SHIFT);
if (g == NULL) {
@@ -507,7 +479,7 @@ retry:
"cannot allocate disk structure for disk %d\n",
dev_no);
blk_cleanup_queue(q);
- return;
+ return 0;
}
d->disk = g;
@@ -539,6 +511,7 @@ retry:
/* register us in the global list */
add_disk(g);
+ return 1;
}
/* returns the total number of scatterlist elements converted */
@@ -719,8 +692,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
d->dev = &vdev->dev;
- probe_disk(d);
- if (d->disk == NULL)
+ if (!probe_disk(d))
return -ENODEV;
return 0;
}
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 0d97b7eb818a..624d30f7da3f 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -298,7 +298,7 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address)
}
/* do_xd_request: handle an incoming request */
-static void do_xd_request (request_queue_t * q)
+static void do_xd_request (struct request_queue * q)
{
struct request *req;
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index 82e090fea957..cffd44a20383 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -104,7 +104,7 @@ static int xd_manual_geo_init (char *command);
static u_char xd_detect (u_char *controller, unsigned int *address);
static u_char xd_initdrives (void (*init_drive)(u_char drive));
-static void do_xd_request (request_queue_t * q);
+static void do_xd_request (struct request_queue * q);
static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
static void xd_recalibrate (u_char drive);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
new file mode 100644
index 000000000000..2bdebcb3ff16
--- /dev/null
+++ b/drivers/block/xen-blkfront.c
@@ -0,0 +1,984 @@
+/*
+ * blkfront.c
+ *
+ * XenLinux virtual block device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/blkif.h>
+
+#include <asm/xen/hypervisor.h>
+
+enum blkif_state {
+ BLKIF_STATE_DISCONNECTED,
+ BLKIF_STATE_CONNECTED,
+ BLKIF_STATE_SUSPENDED,
+};
+
+struct blk_shadow {
+ struct blkif_request req;
+ unsigned long request;
+ unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+static struct block_device_operations xlvbd_block_fops;
+
+#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'. They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct blkfront_info
+{
+ struct xenbus_device *xbdev;
+ dev_t dev;
+ struct gendisk *gd;
+ int vdevice;
+ blkif_vdev_t handle;
+ enum blkif_state connected;
+ int ring_ref;
+ struct blkif_front_ring ring;
+ unsigned int evtchn, irq;
+ struct request_queue *rq;
+ struct work_struct work;
+ struct gnttab_free_callback callback;
+ struct blk_shadow shadow[BLK_RING_SIZE];
+ unsigned long shadow_free;
+ int feature_barrier;
+
+ /**
+ * The number of people holding this device open. We won't allow a
+ * hot-unplug unless this is 0.
+ */
+ int users;
+};
+
+static DEFINE_SPINLOCK(blkif_io_lock);
+
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+ (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
+#define GRANT_INVALID_REF 0
+
+#define PARTS_PER_DISK 16
+
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
+#define DEV_NAME "xvd" /* name in /dev */
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+static LIST_HEAD(vbds_list);
+
+static int get_id_from_freelist(struct blkfront_info *info)
+{
+ unsigned long free = info->shadow_free;
+ BUG_ON(free > BLK_RING_SIZE);
+ info->shadow_free = info->shadow[free].req.id;
+ info->shadow[free].req.id = 0x0fffffee; /* debug */
+ return free;
+}
+
+static void add_id_to_freelist(struct blkfront_info *info,
+ unsigned long id)
+{
+ info->shadow[id].req.id = info->shadow_free;
+ info->shadow[id].request = 0;
+ info->shadow_free = id;
+}
+
+static void blkif_restart_queue_callback(void *arg)
+{
+ struct blkfront_info *info = (struct blkfront_info *)arg;
+ schedule_work(&info->work);
+}
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+ struct blkfront_info *info = req->rq_disk->private_data;
+ unsigned long buffer_mfn;
+ struct blkif_request *ring_req;
+ struct req_iterator iter;
+ struct bio_vec *bvec;
+ unsigned long id;
+ unsigned int fsect, lsect;
+ int ref;
+ grant_ref_t gref_head;
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+ return 1;
+
+ if (gnttab_alloc_grant_references(
+ BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
+ gnttab_request_free_callback(
+ &info->callback,
+ blkif_restart_queue_callback,
+ info,
+ BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ return 1;
+ }
+
+ /* Fill out a communications ring structure. */
+ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+ id = get_id_from_freelist(info);
+ info->shadow[id].request = (unsigned long)req;
+
+ ring_req->id = id;
+ ring_req->sector_number = (blkif_sector_t)req->sector;
+ ring_req->handle = info->handle;
+
+ ring_req->operation = rq_data_dir(req) ?
+ BLKIF_OP_WRITE : BLKIF_OP_READ;
+ if (blk_barrier_rq(req))
+ ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
+ ring_req->nr_segments = 0;
+ rq_for_each_segment(bvec, req, iter) {
+ BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+ fsect = bvec->bv_offset >> 9;
+ lsect = fsect + (bvec->bv_len >> 9) - 1;
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+
+ gnttab_grant_foreign_access_ref(
+ ref,
+ info->xbdev->otherend_id,
+ buffer_mfn,
+ rq_data_dir(req) );
+
+ info->shadow[id].frame[ring_req->nr_segments] =
+ mfn_to_pfn(buffer_mfn);
+
+ ring_req->seg[ring_req->nr_segments] =
+ (struct blkif_request_segment) {
+ .gref = ref,
+ .first_sect = fsect,
+ .last_sect = lsect };
+
+ ring_req->nr_segments++;
+ }
+
+ info->ring.req_prod_pvt++;
+
+ /* Keep a private copy so we can reissue requests when recovering. */
+ info->shadow[id].req = *ring_req;
+
+ gnttab_free_grant_references(gref_head);
+
+ return 0;
+}
+
+
+static inline void flush_requests(struct blkfront_info *info)
+{
+ int notify;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+ if (notify)
+ notify_remote_via_irq(info->irq);
+}
+
+/*
+ * do_blkif_request
+ * read a block; request is in a request queue
+ */
+static void do_blkif_request(struct request_queue *rq)
+{
+ struct blkfront_info *info = NULL;
+ struct request *req;
+ int queued;
+
+ pr_debug("Entered do_blkif_request\n");
+
+ queued = 0;
+
+ while ((req = elv_next_request(rq)) != NULL) {
+ info = req->rq_disk->private_data;
+ if (!blk_fs_request(req)) {
+ end_request(req, 0);
+ continue;
+ }
+
+ if (RING_FULL(&info->ring))
+ goto wait;
+
+ pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+ "(%u/%li) buffer:%p [%s]\n",
+ req, req->cmd, (unsigned long)req->sector,
+ req->current_nr_sectors,
+ req->nr_sectors, req->buffer,
+ rq_data_dir(req) ? "write" : "read");
+
+
+ blkdev_dequeue_request(req);
+ if (blkif_queue_request(req)) {
+ blk_requeue_request(rq, req);
+wait:
+ /* Avoid pointless unplugs. */
+ blk_stop_queue(rq);
+ break;
+ }
+
+ queued++;
+ }
+
+ if (queued != 0)
+ flush_requests(info);
+}
+
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+ struct request_queue *rq;
+
+ rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if (rq == NULL)
+ return -1;
+
+ elevator_init(rq, "noop");
+
+ /* Hard sector size and max sectors impersonate the equiv. hardware. */
+ blk_queue_hardsect_size(rq, sector_size);
+ blk_queue_max_sectors(rq, 512);
+
+ /* Each segment in a request is up to an aligned page in size. */
+ blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+ /* Ensure a merged request will fit in a single I/O ring slot. */
+ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ /* Make sure buffer addresses are sector-aligned. */
+ blk_queue_dma_alignment(rq, 511);
+
+ gd->queue = rq;
+
+ return 0;
+}
+
+
+static int xlvbd_barrier(struct blkfront_info *info)
+{
+ int err;
+
+ err = blk_queue_ordered(info->rq,
+ info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE,
+ NULL);
+
+ if (err)
+ return err;
+
+ printk(KERN_INFO "blkfront: %s: barriers %s\n",
+ info->gd->disk_name,
+ info->feature_barrier ? "enabled" : "disabled");
+ return 0;
+}
+
+
+static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
+ int vdevice, u16 vdisk_info, u16 sector_size,
+ struct blkfront_info *info)
+{
+ struct gendisk *gd;
+ int nr_minors = 1;
+ int err = -ENODEV;
+
+ BUG_ON(info->gd != NULL);
+ BUG_ON(info->rq != NULL);
+
+ if ((minor % PARTS_PER_DISK) == 0)
+ nr_minors = PARTS_PER_DISK;
+
+ gd = alloc_disk(nr_minors);
+ if (gd == NULL)
+ goto out;
+
+ if (nr_minors > 1)
+ sprintf(gd->disk_name, "%s%c", DEV_NAME,
+ 'a' + minor / PARTS_PER_DISK);
+ else
+ sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+ 'a' + minor / PARTS_PER_DISK,
+ minor % PARTS_PER_DISK);
+
+ gd->major = XENVBD_MAJOR;
+ gd->first_minor = minor;
+ gd->fops = &xlvbd_block_fops;
+ gd->private_data = info;
+ gd->driverfs_dev = &(info->xbdev->dev);
+ set_capacity(gd, capacity);
+
+ if (xlvbd_init_blk_queue(gd, sector_size)) {
+ del_gendisk(gd);
+ goto out;
+ }
+
+ info->rq = gd->queue;
+ info->gd = gd;
+
+ if (info->feature_barrier)
+ xlvbd_barrier(info);
+
+ if (vdisk_info & VDISK_READONLY)
+ set_disk_ro(gd, 1);
+
+ if (vdisk_info & VDISK_REMOVABLE)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ if (vdisk_info & VDISK_CDROM)
+ gd->flags |= GENHD_FL_CD;
+
+ return 0;
+
+ out:
+ return err;
+}
+
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+ if (!RING_FULL(&info->ring)) {
+ /* Re-enable calldowns. */
+ blk_start_queue(info->rq);
+ /* Kick things off immediately. */
+ do_blkif_request(info->rq);
+ }
+}
+
+static void blkif_restart_queue(struct work_struct *work)
+{
+ struct blkfront_info *info = container_of(work, struct blkfront_info, work);
+
+ spin_lock_irq(&blkif_io_lock);
+ if (info->connected == BLKIF_STATE_CONNECTED)
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
+}
+
+static void blkif_free(struct blkfront_info *info, int suspend)
+{
+ /* Prevent new requests being issued until we fix things up. */
+ spin_lock_irq(&blkif_io_lock);
+ info->connected = suspend ?
+ BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
+ /* No more blkif_request(). */
+ if (info->rq)
+ blk_stop_queue(info->rq);
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irq(&blkif_io_lock);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ /* Free resources associated with old device channel. */
+ if (info->ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->ring_ref, 0,
+ (unsigned long)info->ring.sring);
+ info->ring_ref = GRANT_INVALID_REF;
+ info->ring.sring = NULL;
+ }
+ if (info->irq)
+ unbind_from_irqhandler(info->irq, info);
+ info->evtchn = info->irq = 0;
+
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+ int i;
+ for (i = 0; i < s->req.nr_segments; i++)
+ gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+{
+ struct request *req;
+ struct blkif_response *bret;
+ RING_IDX i, rp;
+ unsigned long flags;
+ struct blkfront_info *info = (struct blkfront_info *)dev_id;
+ int uptodate;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ again:
+ rp = info->ring.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for (i = info->ring.rsp_cons; i != rp; i++) {
+ unsigned long id;
+ int ret;
+
+ bret = RING_GET_RESPONSE(&info->ring, i);
+ id = bret->id;
+ req = (struct request *)info->shadow[id].request;
+
+ blkif_completion(&info->shadow[id]);
+
+ add_id_to_freelist(info, id);
+
+ uptodate = (bret->status == BLKIF_RSP_OKAY);
+ switch (bret->operation) {
+ case BLKIF_OP_WRITE_BARRIER:
+ if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+ printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+ info->gd->disk_name);
+ uptodate = -EOPNOTSUPP;
+ info->feature_barrier = 0;
+ xlvbd_barrier(info);
+ }
+ /* fall through */
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ if (unlikely(bret->status != BLKIF_RSP_OKAY))
+ dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+ "request: %x\n", bret->status);
+
+ ret = end_that_request_first(req, uptodate,
+ req->hard_nr_sectors);
+ BUG_ON(ret);
+ end_that_request_last(req, uptodate);
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ info->ring.rsp_cons = i;
+
+ if (i != info->ring.req_prod_pvt) {
+ int more_to_do;
+ RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+ if (more_to_do)
+ goto again;
+ } else
+ info->ring.sring->rsp_event = i + 1;
+
+ kick_pending_request_queues(info);
+
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+
+static int setup_blkring(struct xenbus_device *dev,
+ struct blkfront_info *info)
+{
+ struct blkif_sring *sring;
+ int err;
+
+ info->ring_ref = GRANT_INVALID_REF;
+
+ sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+ if (!sring) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+ return -ENOMEM;
+ }
+ SHARED_RING_INIT(sring);
+ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+ if (err < 0) {
+ free_page((unsigned long)sring);
+ info->ring.sring = NULL;
+ goto fail;
+ }
+ info->ring_ref = err;
+
+ err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (err)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->evtchn,
+ blkif_interrupt,
+ IRQF_SAMPLE_RANDOM, "blkif", info);
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err,
+ "bind_evtchn_to_irqhandler failed");
+ goto fail;
+ }
+ info->irq = err;
+
+ return 0;
+fail:
+ blkif_free(info, 0);
+ return err;
+}
+
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+ struct blkfront_info *info)
+{
+ const char *message = NULL;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_blkring(dev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_blkring;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename,
+ "ring-ref", "%u", info->ring_ref);
+ if (err) {
+ message = "writing ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_blkring;
+ }
+
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ return 0;
+
+ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ if (message)
+ xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+ blkif_free(info, 0);
+ out:
+ return err;
+}
+
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffer for communication with the backend, and
+ * inform the backend of the appropriate details for those. Switch to
+ * Initialised state.
+ */
+static int blkfront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err, vdevice, i;
+ struct blkfront_info *info;
+
+ /* FIXME: Use dynamic device id if this is not set. */
+ err = xenbus_scanf(XBT_NIL, dev->nodename,
+ "virtual-device", "%i", &vdevice);
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading virtual-device");
+ return err;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+ return -ENOMEM;
+ }
+
+ info->xbdev = dev;
+ info->vdevice = vdevice;
+ info->connected = BLKIF_STATE_DISCONNECTED;
+ INIT_WORK(&info->work, blkif_restart_queue);
+
+ for (i = 0; i < BLK_RING_SIZE; i++)
+ info->shadow[i].req.id = i+1;
+ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Front end dir is a number, which is used as the id. */
+ info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
+ dev->dev.driver_data = info;
+
+ err = talk_to_backend(dev, info);
+ if (err) {
+ kfree(info);
+ dev->dev.driver_data = NULL;
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int blkif_recover(struct blkfront_info *info)
+{
+ int i;
+ struct blkif_request *req;
+ struct blk_shadow *copy;
+ int j;
+
+ /* Stage 1: Make a safe copy of the shadow state. */
+ copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, info->shadow, sizeof(info->shadow));
+
+ /* Stage 2: Set up free list. */
+ memset(&info->shadow, 0, sizeof(info->shadow));
+ for (i = 0; i < BLK_RING_SIZE; i++)
+ info->shadow[i].req.id = i+1;
+ info->shadow_free = info->ring.req_prod_pvt;
+ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Stage 3: Find pending requests and requeue them. */
+ for (i = 0; i < BLK_RING_SIZE; i++) {
+ /* Not in use? */
+ if (copy[i].request == 0)
+ continue;
+
+ /* Grab a request slot and copy shadow state into it. */
+ req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+ *req = copy[i].req;
+
+ /* We get a new request id, and must reset the shadow state. */
+ req->id = get_id_from_freelist(info);
+ memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
+
+ /* Rewrite any grant references invalidated by susp/resume. */
+ for (j = 0; j < req->nr_segments; j++)
+ gnttab_grant_foreign_access_ref(
+ req->seg[j].gref,
+ info->xbdev->otherend_id,
+ pfn_to_mfn(info->shadow[req->id].frame[j]),
+ rq_data_dir(
+ (struct request *)
+ info->shadow[req->id].request));
+ info->shadow[req->id].req = *req;
+
+ info->ring.req_prod_pvt++;
+ }
+
+ kfree(copy);
+
+ xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+ spin_lock_irq(&blkif_io_lock);
+
+ /* Now safe for us to use the shared ring */
+ info->connected = BLKIF_STATE_CONNECTED;
+
+ /* Send off requeued requests */
+ flush_requests(info);
+
+ /* Kick any other new requests queued since we resumed */
+ kick_pending_request_queues(info);
+
+ spin_unlock_irq(&blkif_io_lock);
+
+ return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our blkif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int blkfront_resume(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ int err;
+
+ dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
+
+ blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+
+ err = talk_to_backend(dev, info);
+ if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+ err = blkif_recover(info);
+
+ return err;
+}
+
+
+/*
+ * Invoked when the backend is finally 'ready' (and has told produced
+ * the details about the physical device - #sectors, size, etc).
+ */
+static void blkfront_connect(struct blkfront_info *info)
+{
+ unsigned long long sectors;
+ unsigned long sector_size;
+ unsigned int binfo;
+ int err;
+
+ if ((info->connected == BLKIF_STATE_CONNECTED) ||
+ (info->connected == BLKIF_STATE_SUSPENDED) )
+ return;
+
+ dev_dbg(&info->xbdev->dev, "%s:%s.\n",
+ __func__, info->xbdev->otherend);
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "sectors", "%llu", &sectors,
+ "info", "%u", &binfo,
+ "sector-size", "%lu", &sector_size,
+ NULL);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err,
+ "reading backend fields at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-barrier", "%lu", &info->feature_barrier,
+ NULL);
+ if (err)
+ info->feature_barrier = 0;
+
+ err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
+ sectors, info->vdevice,
+ binfo, sector_size, info);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+ /* Kick pending requests. */
+ spin_lock_irq(&blkif_io_lock);
+ info->connected = BLKIF_STATE_CONNECTED;
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
+
+ add_disk(info->gd);
+}
+
+/**
+ * Handle the change of state of the backend to Closing. We must delete our
+ * device-layer structures now, to ensure that writes are flushed through to
+ * the backend. Once is this done, we can switch to Closed in
+ * acknowledgement.
+ */
+static void blkfront_closing(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ unsigned long flags;
+
+ dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
+
+ if (info->rq == NULL)
+ goto out;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ del_gendisk(info->gd);
+
+ /* No more blkif_request(). */
+ blk_stop_queue(info->rq);
+
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ blk_cleanup_queue(info->rq);
+ info->rq = NULL;
+
+ out:
+ xenbus_frontend_closed(dev);
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ struct block_device *bd;
+
+ dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateConnected:
+ blkfront_connect(info);
+ break;
+
+ case XenbusStateClosing:
+ bd = bdget(info->dev);
+ if (bd == NULL)
+ xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
+
+ mutex_lock(&bd->bd_mutex);
+ if (info->users > 0)
+ xenbus_dev_error(dev, -EBUSY,
+ "Device in use; refusing to close");
+ else
+ blkfront_closing(dev);
+ mutex_unlock(&bd->bd_mutex);
+ bdput(bd);
+ break;
+ }
+}
+
+static int blkfront_remove(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+
+ blkif_free(info, 0);
+
+ kfree(info);
+
+ return 0;
+}
+
+static int blkif_open(struct inode *inode, struct file *filep)
+{
+ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ info->users++;
+ return 0;
+}
+
+static int blkif_release(struct inode *inode, struct file *filep)
+{
+ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ info->users--;
+ if (info->users == 0) {
+ /* Check whether we have been instructed to close. We will
+ have ignored this request initially, as the device was
+ still mounted. */
+ struct xenbus_device *dev = info->xbdev;
+ enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
+
+ if (state == XenbusStateClosing)
+ blkfront_closing(dev);
+ }
+ return 0;
+}
+
+static struct block_device_operations xlvbd_block_fops =
+{
+ .owner = THIS_MODULE,
+ .open = blkif_open,
+ .release = blkif_release,
+};
+
+
+static struct xenbus_device_id blkfront_ids[] = {
+ { "vbd" },
+ { "" }
+};
+
+static struct xenbus_driver blkfront = {
+ .name = "vbd",
+ .owner = THIS_MODULE,
+ .ids = blkfront_ids,
+ .probe = blkfront_probe,
+ .remove = blkfront_remove,
+ .resume = blkfront_resume,
+ .otherend_changed = backend_changed,
+};
+
+static int __init xlblk_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
+ printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
+ XENVBD_MAJOR, DEV_NAME);
+ return -ENODEV;
+ }
+
+ return xenbus_register_frontend(&blkfront);
+}
+module_init(xlblk_init);
+
+
+static void xlblk_exit(void)
+{
+ return xenbus_unregister_driver(&blkfront);
+}
+module_exit(xlblk_exit);
+
+MODULE_DESCRIPTION("Xen virtual block device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 732ec63b6e9c..9e7652dcde6c 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -91,6 +91,10 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/platform_device.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("Xilinx SystemACE device driver");
@@ -158,6 +162,9 @@ MODULE_LICENSE("GPL");
#define ACE_FIFO_SIZE (32)
#define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE)
+#define ACE_BUS_WIDTH_8 0
+#define ACE_BUS_WIDTH_16 1
+
struct ace_reg_ops;
struct ace_device {
@@ -188,7 +195,7 @@ struct ace_device {
/* Details of hardware device */
unsigned long physaddr;
- void *baseaddr;
+ void __iomem *baseaddr;
int irq;
int bus_width; /* 0 := 8 bit; 1 := 16 bit */
struct ace_reg_ops *reg_ops;
@@ -220,20 +227,20 @@ struct ace_reg_ops {
/* 8 Bit bus width */
static u16 ace_in_8(struct ace_device *ace, int reg)
{
- void *r = ace->baseaddr + reg;
+ void __iomem *r = ace->baseaddr + reg;
return in_8(r) | (in_8(r + 1) << 8);
}
static void ace_out_8(struct ace_device *ace, int reg, u16 val)
{
- void *r = ace->baseaddr + reg;
+ void __iomem *r = ace->baseaddr + reg;
out_8(r, val);
out_8(r + 1, val >> 8);
}
static void ace_datain_8(struct ace_device *ace)
{
- void *r = ace->baseaddr + 0x40;
+ void __iomem *r = ace->baseaddr + 0x40;
u8 *dst = ace->data_ptr;
int i = ACE_FIFO_SIZE;
while (i--)
@@ -243,7 +250,7 @@ static void ace_datain_8(struct ace_device *ace)
static void ace_dataout_8(struct ace_device *ace)
{
- void *r = ace->baseaddr + 0x40;
+ void __iomem *r = ace->baseaddr + 0x40;
u8 *src = ace->data_ptr;
int i = ACE_FIFO_SIZE;
while (i--)
@@ -458,7 +465,7 @@ static inline void ace_fsm_yieldirq(struct ace_device *ace)
}
/* Get the next read/write request; ending requests that we don't handle */
-struct request *ace_get_next_request(request_queue_t * q)
+struct request *ace_get_next_request(struct request_queue * q)
{
struct request *req;
@@ -825,7 +832,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
/* ---------------------------------------------------------------------
* Block ops
*/
-static void ace_request(request_queue_t * q)
+static void ace_request(struct request_queue * q)
{
struct request *req;
struct ace_device *ace;
@@ -902,26 +909,17 @@ static int ace_release(struct inode *inode, struct file *filp)
return 0;
}
-static int ace_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
- struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
- struct hd_geometry __user *geo = (struct hd_geometry __user *)arg;
- struct hd_geometry g;
- dev_dbg(ace->dev, "ace_ioctl()\n");
-
- switch (cmd) {
- case HDIO_GETGEO:
- g.heads = ace->cf_id.heads;
- g.sectors = ace->cf_id.sectors;
- g.cylinders = ace->cf_id.cyls;
- g.start = 0;
- return copy_to_user(geo, &g, sizeof(g)) ? -EFAULT : 0;
+ struct ace_device *ace = bdev->bd_disk->private_data;
- default:
- return -ENOTTY;
- }
- return -ENOTTY;
+ dev_dbg(ace->dev, "ace_getgeo()\n");
+
+ geo->heads = ace->cf_id.heads;
+ geo->sectors = ace->cf_id.sectors;
+ geo->cylinders = ace->cf_id.cyls;
+
+ return 0;
}
static struct block_device_operations ace_fops = {
@@ -930,7 +928,7 @@ static struct block_device_operations ace_fops = {
.release = ace_release,
.media_changed = ace_media_changed,
.revalidate_disk = ace_revalidate_disk,
- .ioctl = ace_ioctl,
+ .getgeo = ace_getgeo,
};
/* --------------------------------------------------------------------
@@ -940,9 +938,11 @@ static int __devinit ace_setup(struct ace_device *ace)
{
u16 version;
u16 val;
-
int rc;
+ dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace);
+ dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq);
+
spin_lock_init(&ace->lock);
init_completion(&ace->id_completion);
@@ -953,15 +953,6 @@ static int __devinit ace_setup(struct ace_device *ace)
if (!ace->baseaddr)
goto err_ioremap;
- if (ace->irq != NO_IRQ) {
- rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
- if (rc) {
- /* Failure - fall back to polled mode */
- dev_err(ace->dev, "request_irq failed\n");
- ace->irq = NO_IRQ;
- }
- }
-
/*
* Initialize the state machine tasklet and stall timer
*/
@@ -991,7 +982,7 @@ static int __devinit ace_setup(struct ace_device *ace)
snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
/* set bus width */
- if (ace->bus_width == 1) {
+ if (ace->bus_width == ACE_BUS_WIDTH_16) {
/* 0x0101 should work regardless of endianess */
ace_out_le16(ace, ACE_BUSMODE, 0x0101);
@@ -1014,6 +1005,16 @@ static int __devinit ace_setup(struct ace_device *ace)
ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |
ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
+ /* Now we can hook up the irq handler */
+ if (ace->irq != NO_IRQ) {
+ rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
+ if (rc) {
+ /* Failure - fall back to polled mode */
+ dev_err(ace->dev, "request_irq failed\n");
+ ace->irq = NO_IRQ;
+ }
+ }
+
/* Enable interrupts */
val = ace_in(ace, ACE_CTRL);
val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
@@ -1033,16 +1034,14 @@ static int __devinit ace_setup(struct ace_device *ace)
return 0;
- err_read:
+err_read:
put_disk(ace->gd);
- err_alloc_disk:
+err_alloc_disk:
blk_cleanup_queue(ace->queue);
- err_blk_initq:
+err_blk_initq:
iounmap(ace->baseaddr);
- if (ace->irq != NO_IRQ)
- free_irq(ace->irq, ace);
- err_ioremap:
- printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n",
+err_ioremap:
+ dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n",
ace->physaddr);
return -ENOMEM;
}
@@ -1065,98 +1064,222 @@ static void __devexit ace_teardown(struct ace_device *ace)
iounmap(ace->baseaddr);
}
-/* ---------------------------------------------------------------------
- * Platform Bus Support
- */
-
-static int __devinit ace_probe(struct device *device)
+static int __devinit
+ace_alloc(struct device *dev, int id, unsigned long physaddr,
+ int irq, int bus_width)
{
- struct platform_device *dev = to_platform_device(device);
struct ace_device *ace;
- int i;
+ int rc;
+ dev_dbg(dev, "ace_alloc(%p)\n", dev);
- dev_dbg(device, "ace_probe(%p)\n", device);
+ if (!physaddr) {
+ rc = -ENODEV;
+ goto err_noreg;
+ }
- /*
- * Allocate the ace device structure
- */
+ /* Allocate and initialize the ace device structure */
ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);
- if (!ace)
+ if (!ace) {
+ rc = -ENOMEM;
goto err_alloc;
-
- ace->dev = device;
- ace->id = dev->id;
- ace->irq = NO_IRQ;
-
- for (i = 0; i < dev->num_resources; i++) {
- if (dev->resource[i].flags & IORESOURCE_MEM)
- ace->physaddr = dev->resource[i].start;
- if (dev->resource[i].flags & IORESOURCE_IRQ)
- ace->irq = dev->resource[i].start;
}
- /* FIXME: Should get bus_width from the platform_device struct */
- ace->bus_width = 1;
+ ace->dev = dev;
+ ace->id = id;
+ ace->physaddr = physaddr;
+ ace->irq = irq;
+ ace->bus_width = bus_width;
- dev_set_drvdata(&dev->dev, ace);
-
- /* Call the bus-independant setup code */
- if (ace_setup(ace) != 0)
+ /* Call the setup code */
+ rc = ace_setup(ace);
+ if (rc)
goto err_setup;
+ dev_set_drvdata(dev, ace);
return 0;
- err_setup:
- dev_set_drvdata(&dev->dev, NULL);
+err_setup:
+ dev_set_drvdata(dev, NULL);
kfree(ace);
- err_alloc:
- printk(KERN_ERR "xsysace: could not initialize device\n");
- return -ENOMEM;
+err_alloc:
+err_noreg:
+ dev_err(dev, "could not initialize device, err=%i\n", rc);
+ return rc;
}
-/*
- * Platform bus remove() method
- */
-static int __devexit ace_remove(struct device *device)
+static void __devexit ace_free(struct device *dev)
{
- struct ace_device *ace = dev_get_drvdata(device);
-
- dev_dbg(device, "ace_remove(%p)\n", device);
+ struct ace_device *ace = dev_get_drvdata(dev);
+ dev_dbg(dev, "ace_free(%p)\n", dev);
if (ace) {
ace_teardown(ace);
+ dev_set_drvdata(dev, NULL);
kfree(ace);
}
+}
+
+/* ---------------------------------------------------------------------
+ * Platform Bus Support
+ */
+static int __devinit ace_probe(struct platform_device *dev)
+{
+ unsigned long physaddr = 0;
+ int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
+ int id = dev->id;
+ int irq = NO_IRQ;
+ int i;
+
+ dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);
+
+ for (i = 0; i < dev->num_resources; i++) {
+ if (dev->resource[i].flags & IORESOURCE_MEM)
+ physaddr = dev->resource[i].start;
+ if (dev->resource[i].flags & IORESOURCE_IRQ)
+ irq = dev->resource[i].start;
+ }
+
+ /* Call the bus-independant setup code */
+ return ace_alloc(&dev->dev, id, physaddr, irq, bus_width);
+}
+
+/*
+ * Platform bus remove() method
+ */
+static int __devexit ace_remove(struct platform_device *dev)
+{
+ ace_free(&dev->dev);
return 0;
}
-static struct device_driver ace_driver = {
- .name = "xsysace",
- .bus = &platform_bus_type,
+static struct platform_driver ace_platform_driver = {
.probe = ace_probe,
.remove = __devexit_p(ace_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "xsysace",
+ },
};
/* ---------------------------------------------------------------------
+ * OF_Platform Bus Support
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+ace_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ unsigned long physaddr;
+ const u32 *id;
+ int irq, bus_width, rc;
+
+ dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match);
+
+ /* device id */
+ id = of_get_property(op->node, "port-number", NULL);
+
+ /* physaddr */
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+ physaddr = res.start;
+
+ /* irq */
+ irq = irq_of_parse_and_map(op->node, 0);
+
+ /* bus width */
+ bus_width = ACE_BUS_WIDTH_16;
+ if (of_find_property(op->node, "8-bit", NULL))
+ bus_width = ACE_BUS_WIDTH_8;
+
+ /* Call the bus-independant setup code */
+ return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+}
+
+static int __devexit ace_of_remove(struct of_device *op)
+{
+ ace_free(&op->dev);
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit ace_of_match[] = {
+ { .compatible = "xilinx,xsysace", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ace_of_match);
+
+static struct of_platform_driver ace_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "xsysace",
+ .match_table = ace_of_match,
+ .probe = ace_of_probe,
+ .remove = __devexit_p(ace_of_remove),
+ .driver = {
+ .name = "xsysace",
+ },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ace_of_register(void)
+{
+ pr_debug("xsysace: registering OF binding\n");
+ return of_register_platform_driver(&ace_of_driver);
+}
+
+static inline void __exit ace_of_unregister(void)
+{
+ of_unregister_platform_driver(&ace_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init ace_of_register(void) { return 0; }
+static inline void __exit ace_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
* Module init/exit routines
*/
static int __init ace_init(void)
{
+ int rc;
+
ace_major = register_blkdev(ace_major, "xsysace");
if (ace_major <= 0) {
- printk(KERN_WARNING "xsysace: register_blkdev() failed\n");
- return ace_major;
+ rc = -ENOMEM;
+ goto err_blk;
}
- pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major);
- return driver_register(&ace_driver);
+ rc = ace_of_register();
+ if (rc)
+ goto err_of;
+
+ pr_debug("xsysace: registering platform binding\n");
+ rc = platform_driver_register(&ace_platform_driver);
+ if (rc)
+ goto err_plat;
+
+ pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major);
+ return 0;
+
+err_plat:
+ ace_of_unregister();
+err_of:
+ unregister_blkdev(ace_major, "xsysace");
+err_blk:
+ printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc);
+ return rc;
}
static void __exit ace_exit(void)
{
pr_debug("Unregistering Xilinx SystemACE driver\n");
- driver_unregister(&ace_driver);
+ platform_driver_unregister(&ace_platform_driver);
+ ace_of_unregister();
unregister_blkdev(ace_major, "xsysace");
}
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index e40fa98842e5..2d5853cbd4b0 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -67,7 +67,7 @@ static DEFINE_SPINLOCK(z2ram_lock);
static struct block_device_operations z2_fops;
static struct gendisk *z2ram_gendisk;
-static void do_z2_request(request_queue_t *q)
+static void do_z2_request(struct request_queue *q)
{
struct request *req;
while ((req = elv_next_request(q)) != NULL) {
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 59b054810ed0..98a9cdeaffb6 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -691,15 +691,18 @@ static void hci_usb_rx_complete(struct urb *urb)
urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i].actual_length);
- if (!urb->iso_frame_desc[i].status)
+ if (!urb->iso_frame_desc[i].status) {
+ husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length;
hci_recv_fragment(husb->hdev, _urb->type,
urb->transfer_buffer + urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i].actual_length);
+ }
}
#else
;
#endif
} else {
+ husb->hdev->stat.byte_rx += count;
err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count);
if (err < 0) {
BT_ERR("%s corrupted packet: type %d count %d",
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 499019bf8f40..79245714f0a7 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1032,6 +1032,10 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
check_disk_change(ip->i_bdev);
return 0;
err_release:
+ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
+ cdi->ops->lock_door(cdi, 0);
+ cdinfo(CD_OPEN, "door unlocked.\n");
+ }
cdi->ops->release(cdi);
err:
cdi->use_count--;
@@ -2094,7 +2098,7 @@ out:
static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
int lba, int nframes)
{
- request_queue_t *q = cdi->disk->queue;
+ struct request_queue *q = cdi->disk->queue;
struct request *rq;
struct bio *bio;
unsigned int len;
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 44cd7b2ddf09..880b5dce3a62 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -56,30 +56,6 @@
#define VIOCD_KERN_WARNING KERN_WARNING "viocd: "
#define VIOCD_KERN_INFO KERN_INFO "viocd: "
-struct viocdlpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 sub_result;
- u16 disk;
- u16 flags;
- u32 token;
- u64 offset; /* On open, max number of disks */
- u64 len; /* On open, size of the disk */
- u32 block_size; /* Only set on open */
- u32 media_size; /* Only set on open */
-};
-
-enum viocdsubtype {
- viocdopen = 0x0001,
- viocdclose = 0x0002,
- viocdread = 0x0003,
- viocdwrite = 0x0004,
- viocdlockdoor = 0x0005,
- viocdgetinfo = 0x0006,
- viocdcheck = 0x0007
-};
-
/*
* Should probably make this a module parameter....sigh
*/
@@ -131,22 +107,13 @@ static struct capability_entry capability_table[] __initdata = {
/* These are our internal structures for keeping track of devices */
static int viocd_numdev;
-struct cdrom_info {
- char rsrcname[10];
- char type[4];
- char model[3];
-};
-/*
- * This needs to be allocated since it is passed to the
- * Hypervisor and we may be a module.
- */
-static struct cdrom_info *viocd_unitinfo;
-static dma_addr_t unitinfo_dmaaddr;
-
struct disk_info {
struct gendisk *viocd_disk;
struct cdrom_device_info viocd_info;
struct device *dev;
+ const char *rsrcname;
+ const char *type;
+ const char *model;
};
static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
@@ -164,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v)
for (i = 0; i < viocd_numdev; i++) {
seq_printf(m, "viocd device %d is iSeries resource %10.10s"
"type %4.4s, model %3.3s\n",
- i, viocd_unitinfo[i].rsrcname,
- viocd_unitinfo[i].type,
- viocd_unitinfo[i].model);
+ i, viocd_diskinfo[i].rsrcname,
+ viocd_diskinfo[i].type,
+ viocd_diskinfo[i].model);
}
return 0;
}
@@ -216,61 +183,6 @@ struct block_device_operations viocd_fops = {
.media_changed = viocd_blk_media_changed,
};
-/* Get info on CD devices from OS/400 */
-static void __init get_viocd_info(void)
-{
- HvLpEvent_Rc hvrc;
- int i;
- struct viocd_waitevent we;
-
- viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- &unitinfo_dmaaddr, GFP_ATOMIC);
- if (viocd_unitinfo == NULL) {
- printk(VIOCD_KERN_WARNING "error allocating unitinfo\n");
- return;
- }
-
- memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD);
-
- init_completion(&we.com);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_cdio | viocdgetinfo,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n",
- (int)hvrc);
- goto error_ret;
- }
-
- wait_for_completion(&we.com);
-
- if (we.rc) {
- const struct vio_error_entry *err =
- vio_lookup_rc(viocd_err_table, we.sub_result);
- printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n",
- we.rc, we.sub_result, err->msg);
- goto error_ret;
- }
-
- for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++)
- viocd_numdev++;
-
-error_ret:
- if (viocd_numdev == 0) {
- dma_free_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- viocd_unitinfo, unitinfo_dmaaddr);
- viocd_unitinfo = NULL;
- }
-}
-
static int viocd_open(struct cdrom_device_info *cdi, int purpose)
{
struct disk_info *diskinfo = cdi->handle;
@@ -398,7 +310,7 @@ static void viocd_end_request(struct request *req, int uptodate)
static int rwreq;
-static void do_viocd_request(request_queue_t *q)
+static void do_viocd_request(struct request_queue *q)
{
struct request *req;
@@ -581,7 +493,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event)
bevent->block_size / 512);
}
/* FALLTHROUGH !! */
- case viocdgetinfo:
case viocdlockdoor:
pwe = (struct viocd_waitevent *)event->xCorrelationToken;
return_complete:
@@ -665,22 +576,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
int deviceno;
struct disk_info *d;
struct cdrom_device_info *c;
- struct cdrom_info *ci;
struct request_queue *q;
+ struct device_node *node = vdev->dev.archdata.of_node;
deviceno = vdev->unit_address;
- if (deviceno >= viocd_numdev)
+ if (deviceno > VIOCD_MAX_CD)
return -ENODEV;
+ if (!node)
+ return -ENODEV;
+
+ if (deviceno >= viocd_numdev)
+ viocd_numdev = deviceno + 1;
d = &viocd_diskinfo[deviceno];
+ d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
+ d->type = of_get_property(node, "linux,vio_type", NULL);
+ d->model = of_get_property(node, "linux,vio_model", NULL);
+
c = &d->viocd_info;
- ci = &viocd_unitinfo[deviceno];
c->ops = &viocd_dops;
c->speed = 4;
c->capacity = 1;
c->handle = d;
- c->mask = ~find_capability(ci->type);
+ c->mask = ~find_capability(d->type);
sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
if (register_cdrom(c) != 0) {
@@ -690,7 +609,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
}
printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
"type %4.4s, model %3.3s\n",
- c->name, ci->rsrcname, ci->type, ci->model);
+ c->name, d->rsrcname, d->type, d->model);
q = blk_init_queue(do_viocd_request, &viocd_reqlock);
if (q == NULL) {
printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",
@@ -799,8 +718,6 @@ static int __init viocd_init(void)
/* Initialize our request handler */
vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
- get_viocd_info();
-
spin_lock_init(&viocd_reqlock);
ret = vio_register_driver(&viocd_driver);
@@ -816,9 +733,6 @@ static int __init viocd_init(void)
return 0;
out_free_info:
- dma_free_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- viocd_unitinfo, unitinfo_dmaaddr);
vio_clearHandler(viomajorsubtype_cdio);
viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
out_unregister:
@@ -830,10 +744,6 @@ static void __exit viocd_exit(void)
{
remove_proc_entry("iSeries/viocd", NULL);
vio_unregister_driver(&viocd_driver);
- if (viocd_unitinfo != NULL)
- dma_free_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- viocd_unitinfo, unitinfo_dmaaddr);
viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
vio_clearHandler(viomajorsubtype_cdio);
unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d8d7125529c4..b391776e5bf3 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -130,6 +130,7 @@ config ROCKETPORT
config CYCLADES
tristate "Cyclades async mux support"
depends on SERIAL_NONSTANDARD && (PCI || ISA)
+ select FW_LOADER
---help---
This driver supports Cyclades Z and Y multiserial boards.
You would need something like this to connect more than two modems to
@@ -185,7 +186,7 @@ config ESPSERIAL
config MOXA_INTELLIO
tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
help
Say Y here if you have a Moxa Intellio multiport serial card.
@@ -241,7 +242,7 @@ config SYNCLINK
config SYNCLINKMP
tristate "SyncLink Multiport support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && PCI
help
Enable support for the SyncLink Multiport (2 or 4 ports)
serial adapter, running asynchronous and HDLC communications up
@@ -372,39 +373,6 @@ config ISTALLION
To compile this driver as a module, choose M here: the
module will be called istallion.
-config SERIAL_DEC
- bool "DECstation serial support"
- depends on MACH_DECSTATION
- default y
- help
- This selects whether you want to be asked about drivers for
- DECstation serial ports.
-
- Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about DECstation serial ports.
-
-config SERIAL_DEC_CONSOLE
- bool "Support for console on a DECstation serial port"
- depends on SERIAL_DEC
- default y
- help
- If you say Y here, it will be possible to use a serial port as the
- system console (the system console is the device which receives all
- kernel messages and warnings and which allows logins in single user
- mode). Note that the firmware uses ttyS0 as the serial console on
- the Maxine and ttyS2 on the others.
-
- If unsure, say Y.
-
-config ZS
- bool "Z85C30 Serial Support"
- depends on SERIAL_DEC
- default y
- help
- Documentation on the Zilog 85C350 serial communications controller
- is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>
-
config A2232
tristate "Commodore A2232 serial support (EXPERIMENTAL)"
depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
@@ -637,6 +605,14 @@ config HVC_BEAT
help
Toshiba's Cell Reference Set Beat Console device driver
+config HVC_XEN
+ bool "Xen Hypervisor Console support"
+ depends on XEN
+ select HVC_DRIVER
+ default y
+ help
+ Xen virtual console device driver
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
@@ -751,7 +727,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -775,6 +751,28 @@ config RTC
To compile this driver as a module, choose M here: the
module will be called rtc.
+config JS_RTC
+ tristate "Enhanced Real Time Clock Support"
+ depends on SPARC32 && PCI
+ ---help---
+ If you say Y here and create a character special file /dev/rtc with
+ major number 10 and minor number 135 using mknod ("man mknod"), you
+ will get access to the real time clock (or hardware clock) built
+ into your computer.
+
+ Every PC has such a clock built in. It can be used to generate
+ signals from as low as 1Hz up to 8192Hz, and can also be used
+ as a 24 hour alarm. It reports status information via the file
+ /proc/driver/rtc and its behaviour is set by various ioctls on
+ /dev/rtc.
+
+ If you think you have a use for such a device (such as periodic data
+ sampling), then say Y here, and read <file:Documentation/rtc.txt>
+ for details.
+
+ To compile this driver as a module, choose M here: the
+ module will be called js-rtc.
+
config SGI_DS1286
tristate "SGI DS1286 RTC support"
depends on SGI_IP22
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f2996a95eb07..c78ff26647ee 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -42,12 +42,14 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
+obj-$(CONFIG_LGUEST_GUEST) += hvc_lguest.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
+obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
@@ -95,7 +97,6 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
-obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_MWAVE) += mwave/
obj-$(CONFIG_AGP) += agp/
obj-$(CONFIG_DRM) += drm/
@@ -105,6 +106,11 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
+obj-$(CONFIG_PS3_FLASH) += ps3flash.o
+
+obj-$(CONFIG_JS_RTC) += js-rtc.o
+js-rtc-y = rtc.o
+
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c
@@ -123,7 +129,7 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c
ifdef GENERATE_KEYMAP
-$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
loadkeys --mktable $< > $@.tmp
sed -e 's/^static *//' $@.tmp > $@
rm $@.tmp
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index a9f9c48c2424..713533d8a86e 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -50,7 +50,7 @@ config AGP_ATI
config AGP_AMD
tristate "AMD Irongate, 761, and 762 chipset support"
- depends on AGP && X86_32
+ depends on AGP && (X86_32 || ALPHA)
help
This option gives you AGP support for the GLX component of
X on AMD Irongate, 761, and 762 chipsets.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 35ab1a9f8e8b..8955e7ff759a 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -176,7 +176,7 @@ struct agp_bridge_data {
#define I830_GMCH_MEM_MASK 0x1
#define I830_GMCH_MEM_64M 0x1
#define I830_GMCH_MEM_128M 0
-#define I830_GMCH_GMS_MASK 0xF0
+#define I830_GMCH_GMS_MASK 0x70
#define I830_GMCH_GMS_DISABLED 0x00
#define I830_GMCH_GMS_LOCAL 0x10
#define I830_GMCH_GMS_STOLEN_512 0x20
@@ -190,6 +190,7 @@ struct agp_bridge_data {
#define INTEL_I830_ERRSTS 0x92
/* Intel 855GM/852GM registers */
+#define I855_GMCH_GMS_MASK 0xF0
#define I855_GMCH_GMS_STOLEN_0M 0x0
#define I855_GMCH_GMS_STOLEN_1M (0x1 << 4)
#define I855_GMCH_GMS_STOLEN_4M (0x2 << 4)
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index df0ddf14b85c..f60bca70d1fb 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -223,6 +223,8 @@ static int amd_irongate_configure(void)
pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp);
temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
+ if (!amd_irongate_private.registers)
+ return -ENOMEM;
/* Write out the address of the gatt table */
writel(agp_bridge->gatt_bus_addr, amd_irongate_private.registers+AMD_ATTBASE);
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 780e59e588ad..2d46b713c8f2 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -123,21 +123,16 @@ static int ati_create_gatt_pages(int nr_tables)
for (i = 0; i < nr_tables; i++) {
entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL);
+ tables[i] = entry;
if (entry == NULL) {
- while (i > 0) {
- kfree(tables[i-1]);
- i--;
- }
- kfree(tables);
retval = -ENOMEM;
break;
}
- tables[i] = entry;
retval = ati_create_page_map(entry);
if (retval != 0)
break;
}
- ati_generic_private.num_tables = nr_tables;
+ ati_generic_private.num_tables = i;
ati_generic_private.gatt_pages = tables;
if (retval != 0)
@@ -218,6 +213,9 @@ static int ati_configure(void)
temp = (temp & 0xfffff000);
ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
+ if (!ati_generic_private.registers)
+ return -ENOMEM;
+
if (is_r200())
pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
else
diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c
index fcb4b1bf0d4e..ecd4248861b9 100644
--- a/drivers/char/agp/compat_ioctl.c
+++ b/drivers/char/agp/compat_ioctl.c
@@ -28,6 +28,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/fs.h>
#include <linux/agpgart.h>
#include <asm/uaccess.h>
#include "agp.h"
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index df8da7262853..d78cd09186aa 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -375,6 +375,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
if (!r->start && r->end) {
if (pci_assign_resource(pdev, 0)) {
printk(KERN_ERR PFX "could not assign resource 0\n");
+ agp_put_bridge(bridge);
return -ENODEV;
}
}
@@ -386,6 +387,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
*/
if (pci_enable_device(pdev)) {
printk(KERN_ERR PFX "Unable to Enable PCI device\n");
+ agp_put_bridge(bridge);
return -ENODEV;
}
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index c7ed617aa7ff..7791e98de51c 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -37,6 +37,7 @@
#include <linux/agpgart.h>
#include <linux/slab.h>
#include <linux/mm.h>
+#include <linux/fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index d535c406b319..3db4f4076ed4 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1170,7 +1170,6 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
map_page_into_agp(page);
get_page(page);
- SetPageLocked(page);
atomic_inc(&agp_bridge->current_memory_agp);
return page_address(page);
}
@@ -1187,7 +1186,6 @@ void agp_generic_destroy_page(void *addr)
page = virt_to_page(addr);
unmap_page_from_agp(page);
put_page(page);
- unlock_page(page);
free_page((unsigned long)addr);
atomic_dec(&agp_bridge->current_memory_agp);
}
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index bcdb149c8179..313a133a1172 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -221,6 +221,7 @@ hp_zx1_lba_init (u64 hpa)
if (cap != PCI_CAP_ID_AGP) {
printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n",
cap, hp->lba_cap_offset);
+ iounmap(hp->lba_regs);
return -ENODEV;
}
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 53354bf83af7..75d2aca6353d 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -249,6 +249,10 @@ static int i460_create_gatt_table (struct agp_bridge_data *bridge)
num_entries = A_SIZE_8(temp)->num_entries;
i460.gatt = ioremap(INTEL_I460_ATTBASE, PAGE_SIZE << page_order);
+ if (!i460.gatt) {
+ printk(KERN_ERR PFX "ioremap failed\n");
+ return -ENOMEM;
+ }
/* These are no good, the should be removed from the agp_bridge strucure... */
agp_bridge->gatt_table_real = NULL;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index a1240603912c..141ca176c397 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -20,7 +20,9 @@
#define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2
#define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00
#define PCI_DEVICE_ID_INTEL_82965GM_IG 0x2A02
+#define PCI_DEVICE_ID_INTEL_82965GME_HB 0x2A10
#define PCI_DEVICE_ID_INTEL_82965GME_IG 0x2A12
+#define PCI_DEVICE_ID_INTEL_82945GME_HB 0x27AC
#define PCI_DEVICE_ID_INTEL_82945GME_IG 0x27AE
#define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0
#define PCI_DEVICE_ID_INTEL_G33_IG 0x29C2
@@ -33,7 +35,8 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB)
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
@@ -213,7 +216,6 @@ static void *i8xx_alloc_pages(void)
}
global_flush_tlb();
get_page(page);
- SetPageLocked(page);
atomic_inc(&agp_bridge->current_memory_agp);
return page_address(page);
}
@@ -229,7 +231,6 @@ static void i8xx_destroy_pages(void *addr)
change_page_attr(page, 4, PAGE_KERNEL);
global_flush_tlb();
put_page(page);
- unlock_page(page);
__free_pages(page, 2);
atomic_dec(&agp_bridge->current_memory_agp);
}
@@ -505,7 +506,7 @@ static void intel_i830_init_gtt_entries(void)
break;
}
} else {
- switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
case I855_GMCH_GMS_STOLEN_1M:
gtt_entries = MB(1) - KB(size);
break;
@@ -527,6 +528,7 @@ static void intel_i830_init_gtt_entries(void)
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
IS_I965 || IS_G33)
gtt_entries = MB(48) - KB(size);
else
@@ -538,6 +540,7 @@ static void intel_i830_init_gtt_entries(void)
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
IS_I965 || IS_G33)
gtt_entries = MB(64) - KB(size);
else
@@ -911,6 +914,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
struct aper_size_info_fixed *size;
int num_entries;
u32 temp, temp2;
+ int gtt_map_size = 256 * 1024;
size = agp_bridge->current_size;
page_order = size->page_order;
@@ -920,15 +924,19 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2);
- intel_private.gtt = ioremap(temp2, 256 * 1024);
+ if (IS_G33)
+ gtt_map_size = 1024 * 1024; /* 1M on G33 */
+ intel_private.gtt = ioremap(temp2, gtt_map_size);
if (!intel_private.gtt)
return -ENOMEM;
temp &= 0xfff80000;
intel_private.registers = ioremap(temp,128 * 4096);
- if (!intel_private.registers)
+ if (!intel_private.registers) {
+ iounmap(intel_private.gtt);
return -ENOMEM;
+ }
temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
global_cache_flush(); /* FIXME: ? */
@@ -982,13 +990,15 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
temp &= 0xfff00000;
intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024);
- if (!intel_private.gtt)
- return -ENOMEM;
+ if (!intel_private.gtt)
+ return -ENOMEM;
intel_private.registers = ioremap(temp,128 * 4096);
- if (!intel_private.registers)
- return -ENOMEM;
+ if (!intel_private.registers) {
+ iounmap(intel_private.gtt);
+ return -ENOMEM;
+ }
temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
global_cache_flush(); /* FIXME: ? */
@@ -1848,9 +1858,9 @@ static const struct intel_driver_description {
NULL, &intel_915_driver },
{ PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G",
NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 1, "945GM",
+ { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM",
NULL, &intel_915_driver },
- { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
+ { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
NULL, &intel_915_driver },
{ PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
NULL, &intel_i965_driver },
@@ -1860,9 +1870,9 @@ static const struct intel_driver_description {
NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G",
NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 1, "965GM",
+ { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM",
NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
+ { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL },
{ PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL },
@@ -2051,11 +2061,13 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
ID(PCI_DEVICE_ID_INTEL_82945G_HB),
ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
+ ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
ID(PCI_DEVICE_ID_INTEL_82965G_1_HB),
ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
ID(PCI_DEVICE_ID_INTEL_82965G_HB),
ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
+ ID(PCI_DEVICE_ID_INTEL_82965GME_HB),
ID(PCI_DEVICE_ID_INTEL_G33_HB),
ID(PCI_DEVICE_ID_INTEL_Q35_HB),
ID(PCI_DEVICE_ID_INTEL_Q33_HB),
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 6cd7373dcdf4..225ed2a53d45 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -157,6 +157,9 @@ static int nvidia_configure(void)
nvidia_private.aperture =
(volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE);
+ if (!nvidia_private.aperture)
+ return -ENOMEM;
+
return 0;
}
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index cda608c42bea..98cf8abb3e57 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -51,7 +51,6 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
return NULL;
get_page(page);
- SetPageLocked(page);
atomic_inc(&agp_bridge->current_memory_agp);
return page_address(page);
}
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 9aaf401a8975..0ecc54d327bc 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -399,6 +399,11 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata =
.device_id = PCI_DEVICE_ID_VIA_P4M890,
.chipset_name = "P4M890",
},
+ /* P4M900 */
+ {
+ .device_id = PCI_DEVICE_ID_VIA_VT3364,
+ .chipset_name = "P4M900",
+ },
{ }, /* dummy final entry, always present */
};
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 7b02bf1289a2..3d468f502d2d 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1721,12 +1721,11 @@ static int get_async_struct(int line, struct async_struct **ret_info)
*ret_info = sstate->info;
return 0;
}
- info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+ info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
if (!info) {
sstate->count--;
return -ENOMEM;
}
- memset(info, 0, sizeof(struct async_struct));
#ifdef DECLARE_WAITQUEUE
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
deleted file mode 100644
index 8ea2bea2b183..000000000000
--- a/drivers/char/decserial.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * sercons.c
- * choose the right serial device at boot time
- *
- * triemer 6-SEP-1998
- * sercons.c is designed to allow the three different kinds
- * of serial devices under the decstation world to co-exist
- * in the same kernel. The idea here is to abstract
- * the pieces of the drivers that are common to this file
- * so that they do not clash at compile time and runtime.
- *
- * HK 16-SEP-1998 v0.002
- * removed the PROM console as this is not a real serial
- * device. Added support for PROM console in drivers/char/tty_io.c
- * instead. Although it may work to enable more than one
- * console device I strongly recommend to use only one.
- */
-
-#include <linux/init.h>
-#include <asm/dec/machtype.h>
-
-#ifdef CONFIG_ZS
-extern int zs_init(void);
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-#ifdef CONFIG_ZS
-extern void zs_serial_console_init(void);
-#endif
-
-#endif
-
-/* rs_init - starts up the serial interface -
- handle normal case of starting up the serial interface */
-
-#ifdef CONFIG_SERIAL
-
-int __init rs_init(void)
-{
-#ifdef CONFIG_ZS
- if (IOASIC)
- return zs_init();
-#endif
- return -ENXIO;
-}
-
-__initcall(rs_init);
-
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/* serial_console_init handles the special case of starting
- * up the console on the serial port
- */
-static int __init decserial_console_init(void)
-{
-#ifdef CONFIG_ZS
- if (IOASIC)
- zs_serial_console_init();
-#endif
- return 0;
-}
-console_initcall(decserial_console_init);
-
-#endif
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 923174c54a1c..c115b39b8517 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -177,8 +177,14 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
MTRR_TYPE_WRCOMB, 1);
}
}
- if (map->type == _DRM_REGISTERS)
+ if (map->type == _DRM_REGISTERS) {
map->handle = ioremap(map->offset, map->size);
+ if (!map->handle) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -ENOMEM;
+ }
+ }
+
break;
case _DRM_SHM:
list = drm_find_matching_map(dev, map);
@@ -479,11 +485,6 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
return -EINVAL;
}
- if (!map) {
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
- }
-
/* Register and framebuffer maps are permanent */
if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 3359cc2b9736..8e7d713a5a15 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -184,6 +184,8 @@ static int i915_initialize(struct drm_device * dev,
* private backbuffer/depthbuffer usage.
*/
dev_priv->use_mi_batchbuffer_start = 0;
+ if (IS_I965G(dev)) /* 965 doesn't support older method */
+ dev_priv->use_mi_batchbuffer_start = 1;
/* Allow hardware batchbuffers unless told otherwise.
*/
@@ -517,8 +519,13 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
if (dev_priv->use_mi_batchbuffer_start) {
BEGIN_LP_RING(2);
- OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
- OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+ if (IS_I965G(dev)) {
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
+ OUT_RING(batch->start);
+ } else {
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+ OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+ }
ADVANCE_LP_RING();
} else {
BEGIN_LP_RING(4);
@@ -735,7 +742,8 @@ static int i915_setparam(DRM_IOCTL_ARGS)
switch (param.param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
- dev_priv->use_mi_batchbuffer_start = param.value;
+ if (!IS_I965G(dev))
+ dev_priv->use_mi_batchbuffer_start = param.value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
dev_priv->tex_lru_log_granularity = param.value;
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index fd918565f4e5..28b98733beb8 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -210,6 +210,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define I915REG_INT_MASK_R 0x020a8
#define I915REG_INT_ENABLE_R 0x020a0
+#define I915REG_PIPEASTAT 0x70024
+#define I915REG_PIPEBSTAT 0x71024
+
+#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define I915_VBLANK_CLEAR (1UL<<1)
+
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
#define SR01 1
@@ -282,6 +288,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
#define MI_BATCH_NON_SECURE (1)
+#define MI_BATCH_NON_SECURE_I965 (1<<8)
#define MI_WAIT_FOR_EVENT ((0x3<<23))
#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index 4b4b2ce89863..bb8e9e9c8201 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -214,6 +214,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 temp;
+ u32 pipea_stats, pipeb_stats;
+
+ pipea_stats = I915_READ(I915REG_PIPEASTAT);
+ pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
temp = I915_READ16(I915REG_INT_IDENTITY_R);
@@ -225,6 +229,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ (void) I915_READ16(I915REG_INT_IDENTITY_R);
+ DRM_READMEMORYBARRIER();
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
@@ -252,6 +258,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
+ I915_WRITE(I915REG_PIPEASTAT,
+ pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
+ I915_VBLANK_CLEAR);
+ I915_WRITE(I915REG_PIPEBSTAT,
+ pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
+ I915_VBLANK_CLEAR);
}
return IRQ_HANDLED;
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index fdb8609dd76f..3dd1ed3d1bf5 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -273,10 +273,9 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) /
vsg->descriptors_per_page;
- if (NULL == (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL)))
+ if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
return DRM_ERR(ENOMEM);
- memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages);
vsg->state = dr_via_desc_pages_alloc;
for (i=0; i<vsg->num_desc_pages; ++i) {
if (NULL == (vsg->desc_pages[i] =
@@ -561,7 +560,7 @@ via_init_dmablit(struct drm_device *dev)
blitq->head = 0;
blitq->cur = 0;
blitq->serviced = 0;
- blitq->num_free = VIA_NUM_BLIT_SLOTS;
+ blitq->num_free = VIA_NUM_BLIT_SLOTS - 1;
blitq->num_outstanding = 0;
blitq->is_active = 0;
blitq->aborting = 0;
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 9b8278e1f4f8..acbfe1c49b4d 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void)
err = PTR_ERR(dsp56k_class);
goto out_chrdev;
}
- class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+ device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
printk(banner);
goto out;
@@ -527,7 +527,7 @@ module_init(dsp56k_init_driver);
static void __exit dsp56k_cleanup_driver(void)
{
- class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+ device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
class_destroy(dsp56k_class);
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
}
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 74cd5118af57..2e7ae42a5503 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -2459,7 +2459,7 @@ static int __init espserial_init(void)
return 1;
}
- info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+ info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
if (!info)
{
@@ -2469,7 +2469,6 @@ static int __init espserial_init(void)
return 1;
}
- memset((void *)info, 0, sizeof(struct esp_struct));
spin_lock_init(&info->lock);
/* rx_trigger, tx_trigger are needed by autoconfig */
info->config.rx_trigger = rx_trigger;
@@ -2527,7 +2526,7 @@ static int __init espserial_init(void)
if (!dma)
info->stat_flags |= ESP_STAT_NEVER_DMA;
- info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+ info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
if (!info)
{
printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
@@ -2536,7 +2535,6 @@ static int __init espserial_init(void)
return 0;
}
- memset((void *)info, 0, sizeof(struct esp_struct));
/* rx_trigger, tx_trigger are needed by autoconfig */
info->config.rx_trigger = rx_trigger;
info->config.tx_trigger = tx_trigger;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0be700f4e8fd..4c16778e3f84 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -29,6 +29,7 @@
#include <linux/bcd.h>
#include <linux/seq_file.h>
#include <linux/bitops.h>
+#include <linux/clocksource.h>
#include <asm/current.h>
#include <asm/uaccess.h>
@@ -51,8 +52,37 @@
#define HPET_RANGE_SIZE 1024 /* from HPET spec */
+#if BITS_PER_LONG == 64
+#define write_counter(V, MC) writeq(V, MC)
+#define read_counter(MC) readq(MC)
+#else
+#define write_counter(V, MC) writel(V, MC)
+#define read_counter(MC) readl(MC)
+#endif
+
static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+/* This clocksource driver currently only works on ia64 */
+#ifdef CONFIG_IA64
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+ return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+ .name = "hpet",
+ .rating = 250,
+ .read = read_hpet,
+ .mask = CLOCKSOURCE_MASK(64),
+ .mult = 0, /*to be caluclated*/
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+#endif
+
/* A lock for concurrent access by app and isr hpet activity. */
static DEFINE_SPINLOCK(hpet_lock);
/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +109,7 @@ struct hpets {
struct hpets *hp_next;
struct hpet __iomem *hp_hpet;
unsigned long hp_hpet_phys;
- struct time_interpolator *hp_interpolator;
+ struct clocksource *hp_clocksource;
unsigned long long hp_tick_freq;
unsigned long hp_delta;
unsigned int hp_ntimer;
@@ -94,13 +124,6 @@ static struct hpets *hpets;
#define HPET_PERIODIC 0x0004
#define HPET_SHARED_IRQ 0x0008
-#if BITS_PER_LONG == 64
-#define write_counter(V, MC) writeq(V, MC)
-#define read_counter(MC) readq(MC)
-#else
-#define write_counter(V, MC) writel(V, MC)
-#define read_counter(MC) readl(MC)
-#endif
#ifndef readq
static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +760,6 @@ static ctl_table dev_root[] = {
static struct ctl_table_header *sysctl_header;
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef CONFIG_TIME_INTERPOLATION
- struct time_interpolator *ti;
-
- ti = kzalloc(sizeof(*ti), GFP_KERNEL);
- if (!ti)
- return;
-
- ti->source = TIME_SOURCE_MMIO64;
- ti->shift = 10;
- ti->addr = &hpetp->hp_hpet->hpet_mc;
- ti->frequency = hpetp->hp_tick_freq;
- ti->drift = HPET_DRIFT;
- ti->mask = -1;
-
- hpetp->hp_interpolator = ti;
- register_time_interpolator(ti);
-#endif
-}
-
/*
* Adjustment for when arming the timer with
* initial conditions. That is, main counter
@@ -909,7 +911,19 @@ int hpet_alloc(struct hpet_data *hdp)
}
hpetp->hp_delta = hpet_calibrate(hpetp);
- hpet_register_interpolator(hpetp);
+
+/* This clocksource driver currently only works on ia64 */
+#ifdef CONFIG_IA64
+ if (!hpet_clocksource) {
+ hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+ CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+ clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+ clocksource_hpet.shift);
+ clocksource_register(&clocksource_hpet);
+ hpetp->hp_clocksource = &clocksource_hpet;
+ hpet_clocksource = &clocksource_hpet;
+ }
+#endif
return 0;
}
@@ -932,14 +946,14 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
__FUNCTION__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
- return -EBUSY;
+ return AE_ALREADY_EXISTS;
}
} else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
struct acpi_resource_fixed_memory32 *fixmem32;
fixmem32 = &res->data.fixed_memory32;
if (!fixmem32)
- return -EINVAL;
+ return AE_NO_MEMORY;
hdp->hd_phys_address = fixmem32->address;
hdp->hd_address = ioremap(fixmem32->address,
@@ -949,7 +963,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
__FUNCTION__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
- return -EBUSY;
+ return AE_ALREADY_EXISTS;
}
} else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
struct acpi_resource_extended_irq *irqp;
@@ -995,13 +1009,19 @@ static int hpet_acpi_add(struct acpi_device *device)
static int hpet_acpi_remove(struct acpi_device *device, int type)
{
- /* XXX need to unregister interpolator, dealloc mem, etc */
+ /* XXX need to unregister clocksource, dealloc mem, etc */
return -EINVAL;
}
+static const struct acpi_device_id hpet_device_ids[] = {
+ {"PNP0103", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, hpet_device_ids);
+
static struct acpi_driver hpet_acpi_driver = {
.name = "hpet",
- .ids = "PNP0103",
+ .ids = hpet_device_ids,
.ops = {
.add = hpet_acpi_add,
.remove = hpet_acpi_remove,
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
index 6f019f19be71..e74bb949c289 100644
--- a/drivers/char/hvc_beat.c
+++ b/drivers/char/hvc_beat.c
@@ -97,7 +97,7 @@ static int hvc_beat_config(char *p)
return 0;
}
-static int hvc_beat_console_init(void)
+static int __init hvc_beat_console_init(void)
{
if (hvc_beat_useit && machine_is_compatible("Beat")) {
hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
@@ -106,7 +106,7 @@ static int hvc_beat_console_init(void)
}
/* temp */
-static int hvc_beat_init(void)
+static int __init hvc_beat_init(void)
{
struct hvc_struct *hp;
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b37f1d5a5be6..a08f8f981c11 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -472,7 +472,7 @@ static void hvc_handle_event(struct HvLpEvent *event)
}
}
-static int send_open(HvLpIndex remoteLp, void *sem)
+static int __init send_open(HvLpIndex remoteLp, void *sem)
{
return HvCallEvent_signalLpEventFast(remoteLp,
HvLpEvent_Type_VirtualIo,
@@ -484,7 +484,7 @@ static int send_open(HvLpIndex remoteLp, void *sem)
0, 0, 0, 0);
}
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
{
atomic_t wait_flag;
int rc;
@@ -552,14 +552,14 @@ static int hvc_vio_init(void)
}
module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
{
vio_unregister_driver(&hvc_vio_driver);
}
module_exit(hvc_vio_exit);
/* the device tree order defines our numbering */
-static int hvc_find_vtys(void)
+static int __init hvc_find_vtys(void)
{
struct device_node *vty;
int num_found = 0;
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c
new file mode 100644
index 000000000000..3d6bd0baa56d
--- /dev/null
+++ b/drivers/char/hvc_lguest.c
@@ -0,0 +1,177 @@
+/*D:300
+ * The Guest console driver
+ *
+ * This is a trivial console driver: we use lguest's DMA mechanism to send
+ * bytes out, and register a DMA buffer to receive bytes in. It is assumed to
+ * be present and available from the very beginning of boot.
+ *
+ * Writing console drivers is one of the few remaining Dark Arts in Linux.
+ * Fortunately for us, the path of virtual consoles has been well-trodden by
+ * the PowerPC folks, who wrote "hvc_console.c" to generically support any
+ * virtual console. We use that infrastructure which only requires us to write
+ * the basic put_chars and get_chars functions and call the right register
+ * functions.
+ :*/
+
+/*M:002 The console can be flooded: while the Guest is processing input the
+ * Host can send more. Buffering in the Host could alleviate this, but it is a
+ * difficult problem in general. :*/
+/* Copyright (C) 2006 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/lguest_bus.h>
+#include <asm/paravirt.h>
+#include "hvc_console.h"
+
+/*D:340 This is our single console input buffer, with associated "struct
+ * lguest_dma" referring to it. Note the 0-terminated length array, and the
+ * use of physical address for the buffer itself. */
+static char inbuf[256];
+static struct lguest_dma cons_input = { .used_len = 0,
+ .addr[0] = __pa(inbuf),
+ .len[0] = sizeof(inbuf),
+ .len[1] = 0 };
+
+/*D:310 The put_chars() callback is pretty straightforward.
+ *
+ * First we put the pointer and length in a "struct lguest_dma": we only have
+ * one pointer, so we set the second length to 0. Then we use SEND_DMA to send
+ * the data to (Host) buffers attached to the console key. Usually a device's
+ * key is a physical address within the device's memory, but because the
+ * console device doesn't have any associated physical memory, we use the
+ * LGUEST_CONSOLE_DMA_KEY constant (aka 0). */
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+ struct lguest_dma dma;
+
+ /* FIXME: DMA buffers in a "struct lguest_dma" are not allowed
+ * to go over page boundaries. This never seems to happen,
+ * but if it did we'd need to fix this code. */
+ dma.len[0] = count;
+ dma.len[1] = 0;
+ dma.addr[0] = __pa(buf);
+
+ lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
+ /* We're expected to return the amount of data we wrote: all of it. */
+ return count;
+}
+
+/*D:350 get_chars() is the callback from the hvc_console infrastructure when
+ * an interrupt is received.
+ *
+ * Firstly we see if our buffer has been filled: if not, we return. The rest
+ * of the code deals with the fact that the hvc_console() infrastructure only
+ * asks us for 16 bytes at a time. We keep a "cons_offset" variable for
+ * partially-read buffers. */
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+ static int cons_offset;
+
+ /* Nothing left to see here... */
+ if (!cons_input.used_len)
+ return 0;
+
+ /* You want more than we have to give? Well, try wanting less! */
+ if (cons_input.used_len - cons_offset < count)
+ count = cons_input.used_len - cons_offset;
+
+ /* Copy across to their buffer and increment offset. */
+ memcpy(buf, inbuf + cons_offset, count);
+ cons_offset += count;
+
+ /* Finished? Zero offset, and reset cons_input so Host will use it
+ * again. */
+ if (cons_offset == cons_input.used_len) {
+ cons_offset = 0;
+ cons_input.used_len = 0;
+ }
+ return count;
+}
+/*:*/
+
+static struct hv_ops lguest_cons = {
+ .get_chars = get_chars,
+ .put_chars = put_chars,
+};
+
+/*D:320 Console drivers are initialized very early so boot messages can go
+ * out. At this stage, the console is output-only. Our driver checks we're a
+ * Guest, and if so hands hvc_instantiate() the console number (0), priority
+ * (0), and the struct hv_ops containing the put_chars() function. */
+static int __init cons_init(void)
+{
+ if (strcmp(paravirt_ops.name, "lguest") != 0)
+ return 0;
+
+ return hvc_instantiate(0, 0, &lguest_cons);
+}
+console_initcall(cons_init);
+
+/*D:370 To set up and manage our virtual console, we call hvc_alloc() and
+ * stash the result in the private pointer of the "struct lguest_device".
+ * Since we never remove the console device we never need this pointer again,
+ * but using ->private is considered good form, and you never know who's going
+ * to copy your driver.
+ *
+ * Once the console is set up, we bind our input buffer ready for input. */
+static int lguestcons_probe(struct lguest_device *lgdev)
+{
+ int err;
+
+ /* The first argument of hvc_alloc() is the virtual console number, so
+ * we use zero. The second argument is the interrupt number.
+ *
+ * The third argument is a "struct hv_ops" containing the put_chars()
+ * and get_chars() pointers. The final argument is the output buffer
+ * size: we use 256 and expect the Host to have room for us to send
+ * that much. */
+ lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
+ if (IS_ERR(lgdev->private))
+ return PTR_ERR(lgdev->private);
+
+ /* We bind a single DMA buffer at key LGUEST_CONSOLE_DMA_KEY.
+ * "cons_input" is that statically-initialized global DMA buffer we saw
+ * above, and we also give the interrupt we want. */
+ err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
+ lgdev_irq(lgdev));
+ if (err)
+ printk("lguest console: failed to bind buffer.\n");
+ return err;
+}
+/* Note the use of lgdev_irq() for the interrupt number. We tell hvc_alloc()
+ * to expect input when this interrupt is triggered, and then tell
+ * lguest_bind_dma() that is the interrupt to send us when input comes in. */
+
+/*D:360 From now on the console driver follows standard Guest driver form:
+ * register_lguest_driver() registers the device type and probe function, and
+ * the probe function sets up the device.
+ *
+ * The standard "struct lguest_driver": */
+static struct lguest_driver lguestcons_drv = {
+ .name = "lguestcons",
+ .owner = THIS_MODULE,
+ .device_type = LGUEST_DEVICE_T_CONSOLE,
+ .probe = lguestcons_probe,
+};
+
+/* The standard init function */
+static int __init hvc_lguest_init(void)
+{
+ return register_lguest_driver(&lguestcons_drv);
+}
+module_init(hvc_lguest_init);
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 4b97eaf18602..bb09413d5a21 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -115,7 +115,7 @@ static void __exit hvc_rtas_exit(void)
module_exit(hvc_rtas_exit);
/* This will happen prior to module init. There is no tty at this time? */
-static int hvc_rtas_console_init(void)
+static int __init hvc_rtas_console_init(void)
{
rtascons_put_char_token = rtas_token("put-term-char");
if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644
index 000000000000..dd68f8541c2d
--- /dev/null
+++ b/drivers/char/hvc_xen.c
@@ -0,0 +1,159 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE 0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+ return mfn_to_virt(xen_start_info->console.domU.mfn);
+}
+
+static inline void notify_daemon(void)
+{
+ /* Use evtchn: this is called early, before irq is set up. */
+ notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+ struct xencons_interface *intf = xencons_interface();
+ XENCONS_RING_IDX cons, prod;
+ int sent = 0;
+
+ cons = intf->out_cons;
+ prod = intf->out_prod;
+ mb(); /* update queue values before going on */
+ BUG_ON((prod - cons) > sizeof(intf->out));
+
+ while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+ intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+ wmb(); /* write ring before updating pointer */
+ intf->out_prod = prod;
+
+ notify_daemon();
+ return sent;
+}
+
+static int read_console(uint32_t vtermno, char *buf, int len)
+{
+ struct xencons_interface *intf = xencons_interface();
+ XENCONS_RING_IDX cons, prod;
+ int recv = 0;
+
+ cons = intf->in_cons;
+ prod = intf->in_prod;
+ mb(); /* get pointers before reading ring */
+ BUG_ON((prod - cons) > sizeof(intf->in));
+
+ while (cons != prod && recv < len)
+ buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+ mb(); /* read ring before consuming */
+ intf->in_cons = cons;
+
+ notify_daemon();
+ return recv;
+}
+
+static struct hv_ops hvc_ops = {
+ .get_chars = read_console,
+ .put_chars = write_console,
+};
+
+static int __init xen_init(void)
+{
+ struct hvc_struct *hp;
+
+ if (!is_running_on_xen())
+ return 0;
+
+ xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+ if (xencons_irq < 0)
+ xencons_irq = 0 /* NO_IRQ */;
+ hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+
+ hvc = hp;
+ return 0;
+}
+
+static void __exit xen_fini(void)
+{
+ if (hvc)
+ hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+ if (!is_running_on_xen())
+ return 0;
+
+ hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+ return 0;
+}
+
+module_init(xen_init);
+module_exit(xen_fini);
+console_initcall(xen_cons_init);
+
+static void xenboot_write_console(struct console *console, const char *string,
+ unsigned len)
+{
+ unsigned int linelen, off = 0;
+ const char *pos;
+
+ while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+ linelen = pos-string+off;
+ if (off + linelen > len)
+ break;
+ write_console(0, string+off, linelen);
+ write_console(0, "\r\n", 2);
+ off += linelen + 1;
+ }
+ if (off < len)
+ write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+ .name = "xenboot",
+ .write = xenboot_write_console,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+};
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 207f7343ba60..69d8866de783 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -210,9 +210,9 @@ static struct ktermios hvcs_tty_termios = {
static int hvcs_parm_num_devs = -1;
module_param(hvcs_parm_num_devs, int, 0);
-char hvcs_driver_name[] = "hvcs";
-char hvcs_device_node[] = "hvcs";
-char hvcs_driver_string[]
+static const char hvcs_driver_name[] = "hvcs";
+static const char hvcs_device_node[] = "hvcs";
+static const char hvcs_driver_string[]
= "IBM hvcs (Hypervisor Virtual Console Server) Driver";
/* Status of partner info rescan triggered via sysfs. */
@@ -784,12 +784,10 @@ static int __devinit hvcs_probe(
return -EFAULT;
}
- hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL);
+ hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
if (!hvcsd)
return -ENODEV;
- /* hvcsd->tty is zeroed out with the memset */
- memset(hvcsd, 0x00, sizeof(*hvcsd));
spin_lock_init(&hvcsd->lock);
/* Automatically incs the refcount the first time */
@@ -1094,7 +1092,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
* NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
* calling this function or you will get deadlock.
*/
-struct hvcs_struct *hvcs_get_by_index(int index)
+static struct hvcs_struct *hvcs_get_by_index(int index)
{
struct hvcs_struct *hvcsd = NULL;
unsigned long flags;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7cda04b33534..2d7cd486e025 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -41,7 +41,7 @@ config HW_RANDOM_AMD
config HW_RANDOM_GEODE
tristate "AMD Geode HW Random Number Generator support"
- depends on HW_RANDOM && X86 && PCI
+ depends on HW_RANDOM && X86_32 && PCI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 0289705967de..cd406416effd 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -98,9 +98,9 @@ struct smm_regs {
unsigned int edi __attribute__ ((packed));
};
-static inline char *i8k_get_dmi_data(int field)
+static inline const char *i8k_get_dmi_data(int field)
{
- char *dmi_data = dmi_get_system_info(field);
+ const char *dmi_data = dmi_get_system_info(field);
return dmi_data && *dmi_data ? dmi_data : "?";
}
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 83c7258d3580..bd94d5f9e62b 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -411,8 +411,8 @@ cleanup_module(void)
iiResetDelay( i2BoardPtrTable[i] );
/* free io addresses and Tibet */
release_region( ip2config.addr[i], 8 );
- class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
- class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
}
/* Disable and remove interrupt handler. */
if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
@@ -425,9 +425,7 @@ cleanup_module(void)
printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
}
put_tty_driver(ip2_tty_driver);
- if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
- printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
- }
+ unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
remove_proc_entry("ip2mem", &proc_root);
// free memory
@@ -502,7 +500,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
{
int i, j, box;
int err = 0;
- int status = 0;
static int loaded;
i2eBordStrPtr pB = NULL;
int rc = -1;
@@ -590,6 +587,8 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
case PCI:
#ifdef CONFIG_PCI
{
+ int status;
+
pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
if (pci_dev_i != NULL) {
@@ -719,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
}
if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
- class_device_create(ip2_class, NULL,
+ device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i),
- NULL, "ipl%d", i);
- class_device_create(ip2_class, NULL,
+ "ipl%d", i);
+ device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
- NULL, "stat%d", i);
+ "stat%d", i);
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index c2aa44ee6eb6..0246a2b8ce48 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device)
entry->dev = dev;
mutex_lock(&reg_list_mutex);
- class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+ device_create(ipmi_class, device, dev, "ipmi%d", if_num);
list_add(&entry->link, &reg_list);
mutex_unlock(&reg_list_mutex);
}
@@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num)
break;
}
}
- class_device_destroy(ipmi_class, dev);
+ device_destroy(ipmi_class, dev);
mutex_unlock(&reg_list_mutex);
}
@@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void)
mutex_lock(&reg_list_mutex);
list_for_each_entry_safe(entry, entry2, &reg_list, link) {
list_del(&entry->link);
- class_device_destroy(ipmi_class, entry->dev);
+ device_destroy(ipmi_class, entry->dev);
kfree(entry);
}
mutex_unlock(&reg_list_mutex);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index b5df7e61aeb2..6a01dd9e43f8 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2639,10 +2639,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
return -ENODEV;
}
- intf = kmalloc(sizeof(*intf), GFP_KERNEL);
+ intf = kzalloc(sizeof(*intf), GFP_KERNEL);
if (!intf)
return -ENOMEM;
- memset(intf, 0, sizeof(*intf));
intf->ipmi_version_major = ipmi_version_major(device_id);
intf->ipmi_version_minor = ipmi_version_minor(device_id);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 4edfdda0cf99..a2894d425153 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1965,10 +1965,10 @@ struct dmi_ipmi_data
u8 slave_addr;
};
-static int __devinit decode_dmi(struct dmi_header *dm,
+static int __devinit decode_dmi(const struct dmi_header *dm,
struct dmi_ipmi_data *dmi)
{
- u8 *data = (u8 *)dm;
+ const u8 *data = (const u8 *)dm;
unsigned long base_addr;
u8 reg_spacing;
u8 len = dm->length;
@@ -2050,6 +2050,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
info->si_type = SI_BT;
break;
default:
+ kfree(info);
return;
}
@@ -2090,13 +2091,14 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
static void __devinit dmi_find_bmc(void)
{
- struct dmi_device *dev = NULL;
+ const struct dmi_device *dev = NULL;
struct dmi_ipmi_data data;
int rv;
while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
memset(&data, 0, sizeof(data));
- rv = decode_dmi((struct dmi_header *) dev->device_data, &data);
+ rv = decode_dmi((const struct dmi_header *) dev->device_data,
+ &data);
if (!rv)
try_init_dmi(&data);
}
@@ -2214,7 +2216,8 @@ static int ipmi_pci_resume(struct pci_dev *pdev)
static struct pci_device_id ipmi_pci_devices[] = {
{ PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
- { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }
+ { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
@@ -2250,19 +2253,19 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
return ret;
}
- regsize = get_property(np, "reg-size", &proplen);
+ regsize = of_get_property(np, "reg-size", &proplen);
if (regsize && proplen != 4) {
dev_warn(&dev->dev, PFX "invalid regsize from OF\n");
return -EINVAL;
}
- regspacing = get_property(np, "reg-spacing", &proplen);
+ regspacing = of_get_property(np, "reg-spacing", &proplen);
if (regspacing && proplen != 4) {
dev_warn(&dev->dev, PFX "invalid regspacing from OF\n");
return -EINVAL;
}
- regshift = get_property(np, "reg-shift", &proplen);
+ regshift = of_get_property(np, "reg-shift", &proplen);
if (regshift && proplen != 4) {
dev_warn(&dev->dev, PFX "invalid regshift from OF\n");
return -EINVAL;
@@ -2291,7 +2294,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
info->irq = irq_of_parse_and_map(dev->node, 0);
info->dev = &dev->dev;
- dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n",
+ dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %x\n",
info->io.addr_data, info->io.regsize, info->io.regspacing,
info->irq);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 3c66f402f9d7..1f27be1ec3d4 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void)
istallion_class = class_create(THIS_MODULE, "staliomem");
for (i = 0; i < 4; i++)
- class_device_create(istallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i),
- NULL, "staliomem%d", i);
+ device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ "staliomem%d", i);
return 0;
err_deinit:
@@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void)
unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
for (j = 0; j < 4; j++)
- class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
- j));
+ device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
class_destroy(istallion_class);
pci_unregister_driver(&stli_pcidriver);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 2ce0af1bd588..d95f316afb5a 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1022,10 +1022,6 @@ static const unsigned short x86_keycodes[256] =
308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-extern int mac_hid_mouse_emulate_buttons(int, int, int);
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
#ifdef CONFIG_SPARC
static int sparc_l1_a_state = 0;
extern void sun_do_break(void);
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
index 1f0962616ee5..4fe9206f84de 100644
--- a/drivers/char/lcd.c
+++ b/drivers/char/lcd.c
@@ -25,7 +25,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <linux/delay.h>
#include "lcd.h"
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 62051f8b0910..c59e2a0996cc 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
- class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
- "lp%d", nr);
+ device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -971,7 +970,7 @@ static void lp_cleanup_module (void)
if (lp_table[offset].dev == NULL)
continue;
parport_unregister_device(lp_table[offset].dev);
- class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
+ device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
}
class_destroy(lp_class);
}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 57f9115a456c..7ee5d9444926 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -39,14 +39,14 @@
#else
#define DBG(fmt...)
#endif
-int mbcs_major;
+static int mbcs_major;
-LIST_HEAD(soft_list);
+static LIST_HEAD(soft_list);
/*
* file operations
*/
-const struct file_operations mbcs_ops = {
+static const struct file_operations mbcs_ops = {
.open = mbcs_open,
.llseek = mbcs_sram_llseek,
.read = mbcs_sram_read,
@@ -377,7 +377,7 @@ dmaread_exit:
return rv;
}
-int mbcs_open(struct inode *ip, struct file *fp)
+static int mbcs_open(struct inode *ip, struct file *fp)
{
struct mbcs_soft *soft;
int minor;
@@ -394,7 +394,7 @@ int mbcs_open(struct inode *ip, struct file *fp)
return -ENODEV;
}
-ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
+static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
{
struct cx_dev *cx_dev = fp->private_data;
struct mbcs_soft *soft = cx_dev->soft;
@@ -418,7 +418,7 @@ ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t *
return rv;
}
-ssize_t
+static ssize_t
mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
{
struct cx_dev *cx_dev = fp->private_data;
@@ -443,7 +443,7 @@ mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * o
return rv;
}
-loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
+static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
{
loff_t newpos;
@@ -491,7 +491,7 @@ static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft)
soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
}
-int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
{
struct cx_dev *cx_dev = fp->private_data;
struct mbcs_soft *soft = cx_dev->soft;
@@ -793,7 +793,7 @@ static int mbcs_remove(struct cx_dev *dev)
return 0;
}
-const struct cx_device_id __devinitdata mbcs_id_table[] = {
+static const struct cx_device_id __devinitdata mbcs_id_table[] = {
{
.part_num = MBCS_PART_NUM,
.mfg_num = MBCS_MFG_NUM,
@@ -807,7 +807,7 @@ const struct cx_device_id __devinitdata mbcs_id_table[] = {
MODULE_DEVICE_TABLE(cx, mbcs_id_table);
-struct cx_drv mbcs_driver = {
+static struct cx_drv mbcs_driver = {
.name = DEVICE_NAME,
.id_table = mbcs_id_table,
.probe = mbcs_probe,
@@ -816,12 +816,7 @@ struct cx_drv mbcs_driver = {
static void __exit mbcs_exit(void)
{
- int rv;
-
- rv = unregister_chrdev(mbcs_major, DEVICE_NAME);
- if (rv < 0)
- DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv);
-
+ unregister_chrdev(mbcs_major, DEVICE_NAME);
cx_driver_unregister(&mbcs_driver);
}
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h
index e7fd47e43257..c9905a3c3353 100644
--- a/drivers/char/mbcs.h
+++ b/drivers/char/mbcs.h
@@ -542,12 +542,12 @@ struct mbcs_soft {
struct semaphore algolock;
};
-extern int mbcs_open(struct inode *ip, struct file *fp);
-extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
+static int mbcs_open(struct inode *ip, struct file *fp);
+static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
loff_t * off);
-extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
+static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
loff_t * off);
-extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
-extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
#endif // __MBCS_H__
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 6e55cfb9c65a..e60a74c66e3d 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
+#include <linux/fs.h>
#include <linux/mmtimer.h>
#include <linux/miscdevice.h>
#include <linux/posix-timers.h>
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index c716ef0dd370..04ac155d3a07 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -38,6 +38,7 @@
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
+#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -66,7 +67,7 @@
/*
* Page types allocated by the device.
*/
-enum {
+enum mspec_page_type {
MSPEC_FETCHOP = 1,
MSPEC_CACHED,
MSPEC_UNCACHED
@@ -82,15 +83,25 @@ static int is_sn2;
* One of these structures is allocated when an mspec region is mmaped. The
* structure is pointed to by the vma->vm_private_data field in the vma struct.
* This structure is used to record the addresses of the mspec pages.
+ * This structure is shared by all vma's that are split off from the
+ * original vma when split_vma()'s are done.
+ *
+ * The refcnt is incremented atomically because mm->mmap_sem does not
+ * protect in fork case where multiple tasks share the vma_data.
*/
struct vma_data {
atomic_t refcnt; /* Number of vmas sharing the data. */
- spinlock_t lock; /* Serialize access to the vma. */
+ spinlock_t lock; /* Serialize access to this structure. */
int count; /* Number of pages allocated. */
- int type; /* Type of pages allocated. */
+ enum mspec_page_type type; /* Type of pages allocated. */
+ int flags; /* See VMD_xxx below. */
+ unsigned long vm_start; /* Original (unsplit) base. */
+ unsigned long vm_end; /* Original (unsplit) end. */
unsigned long maddr[0]; /* Array of MSPEC addresses. */
};
+#define VMD_VMALLOCED 0x1 /* vmalloc'd rather than kmalloc'd */
+
/* used on shub2 to clear FOP cache in the HUB */
static unsigned long scratch_page[MAX_NUMNODES];
#define SH2_AMO_CACHE_ENTRIES 4
@@ -128,8 +139,8 @@ mspec_zero_block(unsigned long addr, int len)
* mspec_open
*
* Called when a device mapping is created by a means other than mmap
- * (via fork, etc.). Increments the reference count on the underlying
- * mspec data so it is not freed prematurely.
+ * (via fork, munmap, etc.). Increments the reference count on the
+ * underlying mspec data so it is not freed prematurely.
*/
static void
mspec_open(struct vm_area_struct *vma)
@@ -144,43 +155,43 @@ mspec_open(struct vm_area_struct *vma)
* mspec_close
*
* Called when unmapping a device mapping. Frees all mspec pages
- * belonging to the vma.
+ * belonging to all the vma's sharing this vma_data structure.
*/
static void
mspec_close(struct vm_area_struct *vma)
{
struct vma_data *vdata;
- int i, pages, result, vdata_size;
+ int index, last_index;
+ unsigned long my_page;
vdata = vma->vm_private_data;
+
if (!atomic_dec_and_test(&vdata->refcnt))
return;
- pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
- for (i = 0; i < pages; i++) {
- if (vdata->maddr[i] == 0)
+ last_index = (vdata->vm_end - vdata->vm_start) >> PAGE_SHIFT;
+ for (index = 0; index < last_index; index++) {
+ if (vdata->maddr[index] == 0)
continue;
/*
* Clear the page before sticking it back
* into the pool.
*/
- result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE);
- if (!result)
- uncached_free_page(vdata->maddr[i]);
+ my_page = vdata->maddr[index];
+ vdata->maddr[index] = 0;
+ if (!mspec_zero_block(my_page, PAGE_SIZE))
+ uncached_free_page(my_page);
else
printk(KERN_WARNING "mspec_close(): "
- "failed to zero page %i\n",
- result);
+ "failed to zero page %ld\n", my_page);
}
- if (vdata_size <= PAGE_SIZE)
- kfree(vdata);
- else
+ if (vdata->flags & VMD_VMALLOCED)
vfree(vdata);
+ else
+ kfree(vdata);
}
-
/*
* mspec_nopfn
*
@@ -194,7 +205,8 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
int index;
struct vma_data *vdata = vma->vm_private_data;
- index = (address - vma->vm_start) >> PAGE_SHIFT;
+ BUG_ON(address < vdata->vm_start || address >= vdata->vm_end);
+ index = (address - vdata->vm_start) >> PAGE_SHIFT;
maddr = (volatile unsigned long) vdata->maddr[index];
if (maddr == 0) {
maddr = uncached_alloc_page(numa_node_id());
@@ -236,10 +248,11 @@ static struct vm_operations_struct mspec_vm_ops = {
* underlying pages.
*/
static int
-mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
+mspec_mmap(struct file *file, struct vm_area_struct *vma,
+ enum mspec_page_type type)
{
struct vma_data *vdata;
- int pages, vdata_size;
+ int pages, vdata_size, flags = 0;
if (vma->vm_pgoff != 0)
return -EINVAL;
@@ -254,12 +267,17 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
if (vdata_size <= PAGE_SIZE)
vdata = kmalloc(vdata_size, GFP_KERNEL);
- else
+ else {
vdata = vmalloc(vdata_size);
+ flags = VMD_VMALLOCED;
+ }
if (!vdata)
return -ENOMEM;
memset(vdata, 0, vdata_size);
+ vdata->vm_start = vma->vm_start;
+ vdata->vm_end = vma->vm_end;
+ vdata->flags = flags;
vdata->type = type;
spin_lock_init(&vdata->lock);
vdata->refcnt = ATOMIC_INIT(1);
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index fee58e03dbe2..cc5d77797def 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1629,7 +1629,7 @@ static int cmm_open(struct inode *inode, struct file *filp)
{
struct cm4000_dev *dev;
struct pcmcia_device *link;
- int rc, minor = iminor(inode);
+ int minor = iminor(inode);
if (minor >= CM4000_MAX_DEV)
return -ENODEV;
@@ -1668,7 +1668,6 @@ static int cmm_open(struct inode *inode, struct file *filp)
start_monitor(dev);
link->open = 1; /* only one open per device */
- rc = 0;
DEBUGP(2, dev, "<- cmm_open\n");
return nonseekable_open(inode, filp);
@@ -1824,7 +1823,7 @@ static int cm4000_resume(struct pcmcia_device *link)
static void cm4000_release(struct pcmcia_device *link)
{
- cmm_cm4000_release(link->priv); /* delay release until device closed */
+ cmm_cm4000_release(link); /* delay release until device closed */
pcmcia_disable_device(link);
}
@@ -1864,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link)
return ret;
}
- class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
- "cmm%d", i);
+ device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
return 0;
}
@@ -1889,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
dev_table[devno] = NULL;
kfree(dev);
- class_device_destroy(cmm_class, MKDEV(major, devno));
+ device_destroy(cmm_class, MKDEV(major, devno));
return;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index af88181a17f4..a0b9c8728d56 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -599,7 +599,7 @@ cs_release:
static void reader_release(struct pcmcia_device *link)
{
- cm4040_reader_release(link->priv);
+ cm4040_reader_release(link);
pcmcia_disable_device(link);
}
@@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link)
return ret;
}
- class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
- "cmx%d", i);
+ device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
return 0;
}
@@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link)
dev_table[devno] = NULL;
kfree(dev);
- class_device_destroy(cmx_class, MKDEV(major, devno));
+ device_destroy(cmx_class, MKDEV(major, devno));
return;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 13808f6083a0..2b889317461e 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -540,13 +540,12 @@ static int mgslpc_probe(struct pcmcia_device *link)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgslpc_attach\n");
- info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+ info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
if (!info) {
printk("Error can't allocate device instance data\n");
return -ENOMEM;
}
- memset(info, 0, sizeof(MGSLPC_INFO));
info->magic = MGSLPC_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
new file mode 100644
index 000000000000..79b6f461be75
--- /dev/null
+++ b/drivers/char/ps3flash.c
@@ -0,0 +1,440 @@
+/*
+ * PS3 FLASH ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME "ps3flash"
+
+#define FLASH_BLOCK_SIZE (256*1024)
+
+
+struct ps3flash_private {
+ struct mutex mutex; /* Bounce buffer mutex */
+};
+
+static struct ps3_storage_device *ps3flash_dev;
+
+static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+ u64 lpar, u64 start_sector,
+ u64 sectors, int write)
+{
+ u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+ write);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ __LINE__, write ? "write" : "read", res);
+ return -EIO;
+ }
+ return sectors;
+}
+
+static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
+ u64 start_sector, u64 sectors,
+ unsigned int sector_offset)
+{
+ u64 max_sectors, lpar;
+
+ max_sectors = dev->bounce_size / dev->blk_size;
+ if (sectors > max_sectors) {
+ dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
+ __func__, __LINE__, max_sectors);
+ sectors = max_sectors;
+ }
+
+ lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
+ return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
+ 0);
+}
+
+static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
+ u64 start_sector)
+{
+ u64 sectors = dev->bounce_size / dev->blk_size;
+ return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
+ sectors, 1);
+}
+
+static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
+{
+ struct ps3_storage_device *dev = ps3flash_dev;
+ loff_t res;
+
+ mutex_lock(&file->f_mapping->host->i_mutex);
+ switch (origin) {
+ case 1:
+ offset += file->f_pos;
+ break;
+ case 2:
+ offset += dev->regions[dev->region_idx].size*dev->blk_size;
+ break;
+ }
+ if (offset < 0) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ file->f_pos = offset;
+ res = file->f_pos;
+
+out:
+ mutex_unlock(&file->f_mapping->host->i_mutex);
+ return res;
+}
+
+static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct ps3_storage_device *dev = ps3flash_dev;
+ struct ps3flash_private *priv = dev->sbd.core.driver_data;
+ u64 size, start_sector, end_sector, offset;
+ ssize_t sectors_read;
+ size_t remaining, n;
+
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
+ __func__, __LINE__, count, *pos, buf);
+
+ size = dev->regions[dev->region_idx].size*dev->blk_size;
+ if (*pos >= size || !count)
+ return 0;
+
+ if (*pos + count > size) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u Truncating count from %zu to %llu\n", __func__,
+ __LINE__, count, size - *pos);
+ count = size - *pos;
+ }
+
+ start_sector = *pos / dev->blk_size;
+ offset = *pos % dev->blk_size;
+ end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+
+ remaining = count;
+ do {
+ mutex_lock(&priv->mutex);
+
+ sectors_read = ps3flash_read_sectors(dev, start_sector,
+ end_sector-start_sector,
+ 0);
+ if (sectors_read < 0) {
+ mutex_unlock(&priv->mutex);
+ goto fail;
+ }
+
+ n = min(remaining, sectors_read*dev->blk_size-offset);
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
+ __func__, __LINE__, n, dev->bounce_buf+offset, buf);
+ if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
+ mutex_unlock(&priv->mutex);
+ sectors_read = -EFAULT;
+ goto fail;
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ *pos += n;
+ buf += n;
+ remaining -= n;
+ start_sector += sectors_read;
+ offset = 0;
+ } while (remaining > 0);
+
+ return count;
+
+fail:
+ return sectors_read;
+}
+
+static ssize_t ps3flash_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct ps3_storage_device *dev = ps3flash_dev;
+ struct ps3flash_private *priv = dev->sbd.core.driver_data;
+ u64 size, chunk_sectors, start_write_sector, end_write_sector,
+ end_read_sector, start_read_sector, head, tail, offset;
+ ssize_t res;
+ size_t remaining, n;
+ unsigned int sec_off;
+
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
+ __func__, __LINE__, count, *pos, buf);
+
+ size = dev->regions[dev->region_idx].size*dev->blk_size;
+ if (*pos >= size || !count)
+ return 0;
+
+ if (*pos + count > size) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u Truncating count from %zu to %llu\n", __func__,
+ __LINE__, count, size - *pos);
+ count = size - *pos;
+ }
+
+ chunk_sectors = dev->bounce_size / dev->blk_size;
+
+ start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+ offset = *pos % dev->bounce_size;
+ end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
+ chunk_sectors;
+
+ end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
+ start_read_sector = (*pos + count) / dev->blk_size;
+
+ /*
+ * As we have to write in 256 KiB chunks, while we can read in blk_size
+ * (usually 512 bytes) chunks, we perform the following steps:
+ * 1. Read from start_write_sector to end_read_sector ("head")
+ * 2. Read from start_read_sector to end_write_sector ("tail")
+ * 3. Copy data to buffer
+ * 4. Write from start_write_sector to end_write_sector
+ * All of this is complicated by using only one 256 KiB bounce buffer.
+ */
+
+ head = end_read_sector - start_write_sector;
+ tail = end_write_sector - start_read_sector;
+
+ remaining = count;
+ do {
+ mutex_lock(&priv->mutex);
+
+ if (end_read_sector >= start_read_sector) {
+ /* Merge head and tail */
+ dev_dbg(&dev->sbd.core,
+ "Merged head and tail: %lu sectors at %lu\n",
+ chunk_sectors, start_write_sector);
+ res = ps3flash_read_sectors(dev, start_write_sector,
+ chunk_sectors, 0);
+ if (res < 0)
+ goto fail;
+ } else {
+ if (head) {
+ /* Read head */
+ dev_dbg(&dev->sbd.core,
+ "head: %lu sectors at %lu\n", head,
+ start_write_sector);
+ res = ps3flash_read_sectors(dev,
+ start_write_sector,
+ head, 0);
+ if (res < 0)
+ goto fail;
+ }
+ if (start_read_sector <
+ start_write_sector+chunk_sectors) {
+ /* Read tail */
+ dev_dbg(&dev->sbd.core,
+ "tail: %lu sectors at %lu\n", tail,
+ start_read_sector);
+ sec_off = start_read_sector-start_write_sector;
+ res = ps3flash_read_sectors(dev,
+ start_read_sector,
+ tail, sec_off);
+ if (res < 0)
+ goto fail;
+ }
+ }
+
+ n = min(remaining, dev->bounce_size-offset);
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
+ __func__, __LINE__, n, buf, dev->bounce_buf+offset);
+ if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
+ res = -EFAULT;
+ goto fail;
+ }
+
+ res = ps3flash_write_chunk(dev, start_write_sector);
+ if (res < 0)
+ goto fail;
+
+ mutex_unlock(&priv->mutex);
+
+ *pos += n;
+ buf += n;
+ remaining -= n;
+ start_write_sector += chunk_sectors;
+ head = 0;
+ offset = 0;
+ } while (remaining > 0);
+
+ return count;
+
+fail:
+ mutex_unlock(&priv->mutex);
+ return res;
+}
+
+
+static irqreturn_t ps3flash_interrupt(int irq, void *data)
+{
+ struct ps3_storage_device *dev = data;
+ int res;
+ u64 tag, status;
+
+ res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+ if (tag != dev->tag)
+ dev_err(&dev->sbd.core,
+ "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ __func__, __LINE__, tag, dev->tag);
+
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ __func__, __LINE__, res, status);
+ } else {
+ dev->lv1_status = status;
+ complete(&dev->done);
+ }
+ return IRQ_HANDLED;
+}
+
+
+static const struct file_operations ps3flash_fops = {
+ .owner = THIS_MODULE,
+ .llseek = ps3flash_llseek,
+ .read = ps3flash_read,
+ .write = ps3flash_write,
+};
+
+static struct miscdevice ps3flash_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DEVICE_NAME,
+ .fops = &ps3flash_fops,
+};
+
+static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct ps3flash_private *priv;
+ int error;
+ unsigned long tmp;
+
+ tmp = dev->regions[dev->region_idx].start*dev->blk_size;
+ if (tmp % FLASH_BLOCK_SIZE) {
+ dev_err(&dev->sbd.core,
+ "%s:%u region start %lu is not aligned\n", __func__,
+ __LINE__, tmp);
+ return -EINVAL;
+ }
+ tmp = dev->regions[dev->region_idx].size*dev->blk_size;
+ if (tmp % FLASH_BLOCK_SIZE) {
+ dev_err(&dev->sbd.core,
+ "%s:%u region size %lu is not aligned\n", __func__,
+ __LINE__, tmp);
+ return -EINVAL;
+ }
+
+ /* use static buffer, kmalloc cannot allocate 256 KiB */
+ if (!ps3flash_bounce_buffer.address)
+ return -ENODEV;
+
+ if (ps3flash_dev) {
+ dev_err(&dev->sbd.core,
+ "Only one FLASH device is supported\n");
+ return -EBUSY;
+ }
+
+ ps3flash_dev = dev;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dev->sbd.core.driver_data = priv;
+ mutex_init(&priv->mutex);
+
+ dev->bounce_size = ps3flash_bounce_buffer.size;
+ dev->bounce_buf = ps3flash_bounce_buffer.address;
+
+ error = ps3stor_setup(dev, ps3flash_interrupt);
+ if (error)
+ goto fail_free_priv;
+
+ ps3flash_misc.parent = &dev->sbd.core;
+ error = misc_register(&ps3flash_misc);
+ if (error) {
+ dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
+ __func__, __LINE__, error);
+ goto fail_teardown;
+ }
+
+ dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
+ __func__, __LINE__, ps3flash_misc.minor);
+ return 0;
+
+fail_teardown:
+ ps3stor_teardown(dev);
+fail_free_priv:
+ kfree(priv);
+ dev->sbd.core.driver_data = NULL;
+fail:
+ ps3flash_dev = NULL;
+ return error;
+}
+
+static int ps3flash_remove(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+
+ misc_deregister(&ps3flash_misc);
+ ps3stor_teardown(dev);
+ kfree(dev->sbd.core.driver_data);
+ dev->sbd.core.driver_data = NULL;
+ ps3flash_dev = NULL;
+ return 0;
+}
+
+
+static struct ps3_system_bus_driver ps3flash = {
+ .match_id = PS3_MATCH_ID_STOR_FLASH,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3flash_probe,
+ .remove = ps3flash_remove,
+ .shutdown = ps3flash_remove,
+};
+
+
+static int __init ps3flash_init(void)
+{
+ return ps3_system_bus_driver_register(&ps3flash);
+}
+
+static void __exit ps3flash_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3flash);
+}
+
+module_init(ps3flash_init);
+module_exit(ps3flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index de14aea34e11..73de77105fea 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
static void __init legacy_pty_init(void)
{
+ if (legacy_count <= 0)
+ return;
- pty_driver = alloc_tty_driver(NR_PTYS);
+ pty_driver = alloc_tty_driver(legacy_count);
if (!pty_driver)
panic("Couldn't allocate pty driver");
- pty_slave_driver = alloc_tty_driver(NR_PTYS);
+ pty_slave_driver = alloc_tty_driver(legacy_count);
if (!pty_slave_driver)
panic("Couldn't allocate pty slave driver");
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 7f5271272f91..af274e5a25ee 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -693,9 +693,14 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
if (r->pull && r->entropy_count < nbytes * 8 &&
r->entropy_count < r->poolinfo->POOLBITS) {
- int bytes = max_t(int, random_read_wakeup_thresh / 8,
- min_t(int, nbytes, sizeof(tmp)));
+ /* If we're limited, always leave two wakeup worth's BITS */
int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
+ int bytes = nbytes;
+
+ /* pull at least as many as BYTES as wakeup BITS */
+ bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
+ /* but never more than the buffer size */
+ bytes = min_t(int, bytes, sizeof(tmp));
DEBUG_ENT("going to reseed %s with %d bits "
"(%d of %d requested)\n",
@@ -1545,11 +1550,13 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
* As close as possible to RFC 793, which
* suggests using a 250 kHz clock.
* Further reading shows this assumes 2 Mb/s networks.
- * For 10 Gb/s Ethernet, a 1 GHz clock is appropriate.
- * That's funny, Linux has one built in! Use it!
- * (Networks are faster now - should this be increased?)
+ * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
+ * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
+ * we also need to limit the resolution so that the u32 seq
+ * overlaps less than one time per MSL (2 minutes).
+ * Choosing a clock of 64 ns period is OK. (period of 274 s)
*/
- seq += ktime_get_real().tv64;
+ seq += ktime_get_real().tv64 >> 6;
#if 0
printk("init_seq(%lx, %lx, %d, %d) = %d\n",
saddr, daddr, sport, dport, seq);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 1f0d7c60c944..bbfa0e241cba 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = {
.owner = THIS_MODULE,
};
-static struct cdev raw_cdev = {
- .kobj = {.name = "raw", },
- .owner = THIS_MODULE,
-};
+static struct cdev raw_cdev;
static int __init raw_init(void)
{
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 294e9cb0c449..0ce96670f979 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -803,9 +803,7 @@ static void *ckmalloc(int size)
{
void *p;
- p = kmalloc(size, GFP_KERNEL);
- if (p)
- memset(p, 0, size);
+ p = kzalloc(size, GFP_KERNEL);
return p;
}
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 8cc60b693460..7321d002c34f 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -556,9 +556,7 @@ struct CmdBlk *RIOGetCmdBlk(void)
{
struct CmdBlk *CmdBlkP;
- CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
- if (CmdBlkP)
- memset(CmdBlkP, 0, sizeof(struct CmdBlk));
+ CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
return CmdBlkP;
}
diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c
index 7e988357326e..991119c9f473 100644
--- a/drivers/char/rio/riotable.c
+++ b/drivers/char/rio/riotable.c
@@ -863,8 +863,7 @@ int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP)
if (PortP->TxRingBuffer)
memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
else if (p->RIOBufferSize) {
- PortP->TxRingBuffer = kmalloc(p->RIOBufferSize, GFP_KERNEL);
- memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
+ PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL);
}
PortP->TxBufferOut = 0;
PortP->TxBufferIn = 0;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 0270080ff0c0..56cbba7b6ec0 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -635,12 +635,11 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
ctlp = sCtlNumToCtlPtr(board);
/* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
- info = kmalloc(sizeof (struct r_port), GFP_KERNEL);
+ info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
if (!info) {
printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);
return;
}
- memset(info, 0, sizeof (struct r_port));
info->magic = RPORT_MAGIC;
info->line = line;
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 22cf7aa56cc4..ec6b65ec69ea 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -82,16 +82,13 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#if defined(__i386__)
+#ifdef CONFIG_X86
#include <asm/hpet.h>
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
#include <linux/pci.h>
#include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
static unsigned long rtc_port;
static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@ static int __init rtc_init(void)
unsigned int year, ctrl;
char *guess = NULL;
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-#endif
#else
void *r;
#ifdef RTC_IRQ
@@ -944,7 +937,7 @@ static int __init rtc_init(void)
#endif
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@ static int __init rtc_init(void)
}
}
}
-#ifdef __sparc_v9__
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
- rtc_port = isa_dev->resource.start;
- rtc_irq = isa_dev->irq;
- goto found;
- }
- }
- }
-#endif
rtc_has_irq = 0;
printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
@@ -1020,7 +1002,7 @@ no_irq:
#endif
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
if (misc_register(&rtc_dev)) {
#ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void)
remove_proc_entry ("driver/rtc", NULL);
misc_deregister(&rtc_dev);
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
@@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
#endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
}
module_init(rtc_init);
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index c585b4738f86..f1497cecffd8 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2573,16 +2573,10 @@ static struct tty_driver *serial167_console_device(struct console *c,
return cy_serial_driver;
}
-static int __init serial167_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
static struct console sercons = {
.name = "ttyS",
.write = serial167_console_write,
.device = serial167_console_device,
- .setup = serial167_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 52753e723eaa..b9c1dba6bd01 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -441,8 +441,7 @@ scdrv_init(void)
continue;
}
- class_device_create(snsc_class, NULL, dev, NULL,
- "%s", devname);
+ device_create(snsc_class, NULL, dev, "%s", devname);
ia64_sn_irtr_intr_enable(scd->scd_nasid,
0 /*ignored */ ,
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 73037a4d3c50..859858561ab6 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -875,7 +875,7 @@ found:
#ifdef CONFIG_ACPI
if (sonypi_acpi_device)
- acpi_bus_generate_event(sonypi_acpi_device, 1, event);
+ acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
#endif
kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
@@ -1147,10 +1147,15 @@ static int sonypi_acpi_remove(struct acpi_device *device, int type)
return 0;
}
+const static struct acpi_device_id sonypi_device_ids[] = {
+ {"SNY6001", 0},
+ {"", 0},
+};
+
static struct acpi_driver sonypi_acpi_driver = {
.name = "sonypi",
.class = "hkey",
- .ids = "SNY6001",
+ .ids = sonypi_device_ids,
.ops = {
.add = sonypi_acpi_add,
.remove = sonypi_acpi_remove,
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 93d0bb8b4c0f..45758d5b56ef 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void)
if (IS_ERR(stallion_class))
printk("STALLION: failed to create class\n");
for (i = 0; i < 4; i++)
- class_device_create(stallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i), NULL,
- "staliomem%d", i);
+ device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ "staliomem%d", i);
return 0;
err_unrtty:
@@ -4795,7 +4794,6 @@ static void __exit stallion_module_exit(void)
{
struct stlbrd *brdp;
unsigned int i, j;
- int retval;
pr_debug("cleanup_module()\n");
@@ -4817,10 +4815,8 @@ static void __exit stallion_module_exit(void)
}
for (i = 0; i < 4; i++)
- class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -retval);
+ device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
class_destroy(stallion_class);
pci_unregister_driver(&stl_pcidriver);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index f53e51ddb9d7..fdc256b380b8 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -4324,13 +4324,12 @@ static struct mgsl_struct* mgsl_allocate_device(void)
{
struct mgsl_struct *info;
- info = kmalloc(sizeof(struct mgsl_struct),
+ info = kzalloc(sizeof(struct mgsl_struct),
GFP_KERNEL);
if (!info) {
printk("Error can't allocate device instance data\n");
} else {
- memset(info, 0, sizeof(struct mgsl_struct));
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, mgsl_bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 428b514201f4..2f97d2f8f916 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1,5 +1,5 @@
/*
- * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $
+ * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $
*
* Device driver for Microgate SyncLink GT serial adapters.
*
@@ -93,7 +93,7 @@
* module identification
*/
static char *driver_name = "SyncLink GT";
-static char *driver_version = "$Revision: 4.36 $";
+static char *driver_version = "$Revision: 4.50 $";
static char *tty_driver_name = "synclink_gt";
static char *tty_dev_prefix = "ttySLG";
MODULE_LICENSE("GPL");
@@ -477,6 +477,7 @@ static void tx_set_idle(struct slgt_info *info);
static unsigned int free_tbuf_count(struct slgt_info *info);
static void reset_tbufs(struct slgt_info *info);
static void tdma_reset(struct slgt_info *info);
+static void tdma_start(struct slgt_info *info);
static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
static void get_signals(struct slgt_info *info);
@@ -904,6 +905,8 @@ start:
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active)
tx_start(info);
+ else
+ tdma_start(info);
spin_unlock_irqrestore(&info->lock,flags);
}
@@ -1562,6 +1565,9 @@ static int hdlcdev_open(struct net_device *dev)
int rc;
unsigned long flags;
+ if (!try_module_get(THIS_MODULE))
+ return -EBUSY;
+
DBGINFO(("%s hdlcdev_open\n", dev->name));
/* generic HDLC layer open processing */
@@ -1631,6 +1637,7 @@ static int hdlcdev_close(struct net_device *dev)
info->netcount=0;
spin_unlock_irqrestore(&info->netlock, flags);
+ module_put(THIS_MODULE);
return 0;
}
@@ -3414,13 +3421,12 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
{
struct slgt_info *info;
- info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL);
if (!info) {
DBGERR(("%s device alloc failed adapter=%d port=%d\n",
driver_name, adapter_num, port_num));
} else {
- memset(info, 0, sizeof(struct slgt_info));
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
@@ -3872,44 +3878,58 @@ static void tx_start(struct slgt_info *info)
slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
/* clear tx idle and underrun status bits */
wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
-
- if (!(rd_reg32(info, TDCSR) & BIT0)) {
- /* tx DMA stopped, restart tx DMA */
- tdma_reset(info);
- /* set 1st descriptor address */
- wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
- switch(info->params.mode) {
- case MGSL_MODE_RAW:
- case MGSL_MODE_MONOSYNC:
- case MGSL_MODE_BISYNC:
- wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
- break;
- default:
- wr_reg32(info, TDCSR, BIT0); /* DMA enable */
- }
- }
-
if (info->params.mode == MGSL_MODE_HDLC)
mod_timer(&info->tx_timer, jiffies +
msecs_to_jiffies(5000));
} else {
- tdma_reset(info);
- /* set 1st descriptor address */
- wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-
slgt_irq_off(info, IRQ_TXDATA);
slgt_irq_on(info, IRQ_TXIDLE);
/* clear tx idle status bit */
wr_reg16(info, SSR, IRQ_TXIDLE);
-
- /* enable tx DMA */
- wr_reg32(info, TDCSR, BIT0);
}
-
+ tdma_start(info);
info->tx_active = 1;
}
}
+/*
+ * start transmit DMA if inactive and there are unsent buffers
+ */
+static void tdma_start(struct slgt_info *info)
+{
+ unsigned int i;
+
+ if (rd_reg32(info, TDCSR) & BIT0)
+ return;
+
+ /* transmit DMA inactive, check for unsent buffers */
+ i = info->tbuf_start;
+ while (!desc_count(info->tbufs[i])) {
+ if (++i == info->tbuf_count)
+ i = 0;
+ if (i == info->tbuf_current)
+ return;
+ }
+ info->tbuf_start = i;
+
+ /* there are unsent buffers, start transmit DMA */
+
+ /* reset needed if previous error condition */
+ tdma_reset(info);
+
+ /* set 1st descriptor address */
+ wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+ switch(info->params.mode) {
+ case MGSL_MODE_RAW:
+ case MGSL_MODE_MONOSYNC:
+ case MGSL_MODE_BISYNC:
+ wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
+ break;
+ default:
+ wr_reg32(info, TDCSR, BIT0); /* DMA enable */
+ }
+}
+
static void tx_stop(struct slgt_info *info)
{
unsigned short val;
@@ -4643,8 +4663,8 @@ static unsigned int free_tbuf_count(struct slgt_info *info)
i=0;
} while (i != info->tbuf_current);
- /* last buffer with zero count may be in use, assume it is */
- if (count)
+ /* if tx DMA active, last zero count buffer is in use */
+ if (count && (rd_reg32(info, TDCSR) & BIT0))
--count;
return count;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index a65407b32079..c63013b2fc36 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -3786,14 +3786,13 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
{
SLMP_INFO *info;
- info = kmalloc(sizeof(SLMP_INFO),
+ info = kzalloc(sizeof(SLMP_INFO),
GFP_KERNEL);
if (!info) {
printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
__FILE__,__LINE__, adapter_num, port_num);
} else {
- memset(info, 0, sizeof(SLMP_INFO));
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 35b40b996534..cef55c40654f 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port)
goto out;
}
- class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
- TIPAR_MINOR + nr), port->dev, "par%d", nr);
+ device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR,
+ TIPAR_MINOR + nr), "par%d", nr);
/* Display informations */
pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -534,7 +534,7 @@ tipar_cleanup_module(void)
if (table[i].dev == NULL)
continue;
parport_unregister_device(table[i].dev);
- class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
+ device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
}
class_destroy(tipar_class);
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 9bb542913b86..39564b76d4a3 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -7,7 +7,7 @@
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index b2e2b002a1bb..d15ccddc92eb 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -7,7 +7,7 @@
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 1ab0896070be..d0e7926eb486 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -7,7 +7,7 @@
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index 9363bcf0a402..6c831f9466b7 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -4,7 +4,7 @@
* Authors:
* Kylene Hall <kjhall@us.ibm.com>
*
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 4eba32b23b29..60a2d2630e36 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -7,6 +7,8 @@
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
* Access to the eventlog extended by the TCG BIOS of PC platform
*
* This program is free software; you can redistribute it and/or
@@ -427,7 +429,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
return -ENOMEM;
if ((err = read_log(log)))
- return err;
+ goto out_free;
/* now register seq file */
err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +437,15 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
seq = file->private_data;
seq->private = log;
} else {
- kfree(log->bios_event_log);
- kfree(log);
+ goto out_free;
}
+
+out:
return err;
+out_free:
+ kfree(log->bios_event_log);
+ kfree(log);
+ goto out;
}
const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +467,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
return -ENOMEM;
if ((err = read_log(log)))
- return err;
+ goto out_free;
/* now register seq file */
err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +475,15 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
seq = file->private_data;
seq->private = log;
} else {
- kfree(log->bios_event_log);
- kfree(log);
+ goto out_free;
}
+
+out:
return err;
+out_free:
+ kfree(log->bios_event_log);
+ kfree(log);
+ goto out;
}
const struct file_operations tpm_binary_bios_measurements_ops = {
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 608f73071bef..6313326bc41f 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -7,7 +7,7 @@
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 483f3f60013c..23fa18a6654c 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -5,6 +5,8 @@
* Leendert van Doorn <leendert@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index de37ebc3a4cf..9c867cf6de64 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -369,25 +369,54 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
}
/**
- * tty_buffer_flush - flush full tty buffers
+ * __tty_buffer_flush - flush full tty buffers
* @tty: tty to flush
*
- * flush all the buffers containing receive data
+ * flush all the buffers containing receive data. Caller must
+ * hold the buffer lock and must have ensured no parallel flush to
+ * ldisc is running.
*
- * Locking: none
+ * Locking: Caller must hold tty->buf.lock
*/
-static void tty_buffer_flush(struct tty_struct *tty)
+static void __tty_buffer_flush(struct tty_struct *tty)
{
struct tty_buffer *thead;
- unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
while((thead = tty->buf.head) != NULL) {
tty->buf.head = thead->next;
tty_buffer_free(tty, thead);
}
tty->buf.tail = NULL;
+}
+
+/**
+ * tty_buffer_flush - flush full tty buffers
+ * @tty: tty to flush
+ *
+ * flush all the buffers containing receive data. If the buffer is
+ * being processed by flush_to_ldisc then we defer the processing
+ * to that function
+ *
+ * Locking: none
+ */
+
+static void tty_buffer_flush(struct tty_struct *tty)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+
+ /* If the data is being pushed to the tty layer then we can't
+ process it here. Instead set a flag and the flush_to_ldisc
+ path will process the flush request before it exits */
+ if (test_bit(TTY_FLUSHING, &tty->flags)) {
+ set_bit(TTY_FLUSHPENDING, &tty->flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ wait_event(tty->read_wait,
+ test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+ return;
+ } else
+ __tty_buffer_flush(tty);
spin_unlock_irqrestore(&tty->buf.lock, flags);
}
@@ -2034,8 +2063,7 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*tp_loc) {
- tp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
- GFP_KERNEL);
+ tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!tp)
goto free_mem_out;
*tp = driver->init_termios;
@@ -2065,8 +2093,7 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*o_tp_loc) {
- o_tp = (struct ktermios *)
- kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+ o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!o_tp)
goto free_mem_out;
*o_tp = driver->other->init_termios;
@@ -3594,6 +3621,7 @@ static void flush_to_ldisc(struct work_struct *work)
return;
spin_lock_irqsave(&tty->buf.lock, flags);
+ set_bit(TTY_FLUSHING, &tty->flags); /* So we know a flush is running */
head = tty->buf.head;
if (head != NULL) {
tty->buf.head = NULL;
@@ -3607,6 +3635,11 @@ static void flush_to_ldisc(struct work_struct *work)
tty_buffer_free(tty, tbuf);
continue;
}
+ /* Ldisc or user is trying to flush the buffers
+ we are feeding to the ldisc, stop feeding the
+ line discipline as we want to empty the queue */
+ if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+ break;
if (!tty->receive_room) {
schedule_delayed_work(&tty->buf.work, 1);
break;
@@ -3620,8 +3653,17 @@ static void flush_to_ldisc(struct work_struct *work)
disc->receive_buf(tty, char_buf, flag_buf, count);
spin_lock_irqsave(&tty->buf.lock, flags);
}
+ /* Restore the queue head */
tty->buf.head = head;
}
+ /* We may have a deferred request to flush the input buffer,
+ if so pull the chain under the lock and empty the queue */
+ if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+ __tty_buffer_flush(tty);
+ clear_bit(TTY_FLUSHPENDING, &tty->flags);
+ wake_up(&tty->read_wait);
+ }
+ clear_bit(TTY_FLUSHING, &tty->flags);
spin_unlock_irqrestore(&tty->buf.lock, flags);
tty_ldisc_deref(disc);
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 3423e9ee6481..3ee73cf64bd2 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -795,6 +795,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
if (L_ICANON(tty))
retval = inq_canon(tty);
return put_user(retval, (unsigned int __user *) arg);
+#ifndef TCGETS2
case TIOCGLCKTRMIOS:
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
return -EFAULT;
@@ -806,6 +807,19 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
return -EFAULT;
return 0;
+#else
+ case TIOCGLCKTRMIOS:
+ if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
+ return -EFAULT;
+ return 0;
+
+ case TIOCSLCKTRMIOS:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
+ return -EFAULT;
+ return 0;
+#endif
case TIOCPKT:
{
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index db57277117bb..db7a731e2362 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -92,47 +92,6 @@ struct viot_devinfo_struct {
#define VIOTAPOP_SETPART 14
#define VIOTAPOP_UNLOAD 15
-struct viotapelpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 sub_type_result;
- u16 tape;
- u16 flags;
- u32 token;
- u64 len;
- union {
- struct {
- u32 tape_op;
- u32 count;
- } op;
- struct {
- u32 type;
- u32 resid;
- u32 dsreg;
- u32 gstat;
- u32 erreg;
- u32 file_no;
- u32 block_no;
- } get_status;
- struct {
- u32 block_no;
- } get_pos;
- } u;
-};
-
-enum viotapesubtype {
- viotapeopen = 0x0001,
- viotapeclose = 0x0002,
- viotaperead = 0x0003,
- viotapewrite = 0x0004,
- viotapegetinfo = 0x0005,
- viotapeop = 0x0006,
- viotapegetpos = 0x0007,
- viotapesetpos = 0x0008,
- viotapegetstatus = 0x0009
-};
-
enum viotaperc {
viotape_InvalidRange = 0x0601,
viotape_InvalidToken = 0x0602,
@@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = {
#define VIOT_WRITING 2
/* Our info on the tapes */
-struct tape_descr {
- char rsrcname[10];
- char type[4];
- char model[3];
-};
-
-static struct tape_descr *viotape_unitinfo;
-static dma_addr_t viotape_unitinfo_token;
+static struct {
+ const char *rsrcname;
+ const char *type;
+ const char *model;
+} viotape_unitinfo[VIOTAPE_MAX_TAPE];
static struct mtget viomtget[VIOTAPE_MAX_TAPE];
@@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
return -err->errno;
}
-/* Get info on all tapes from OS/400 */
-static int get_viotape_info(void)
-{
- HvLpEvent_Rc hvrc;
- int i;
- size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE;
- struct op_struct *op = get_op_struct();
-
- if (op == NULL)
- return -ENOMEM;
-
- viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len,
- &viotape_unitinfo_token, GFP_ATOMIC);
- if (viotape_unitinfo == NULL) {
- free_op_struct(op);
- return -ENOMEM;
- }
-
- memset(viotape_unitinfo, 0, len);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapegetinfo,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64) (unsigned long) op, VIOVERSION << 16,
- viotape_unitinfo_token, len, 0, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
- (int)hvrc);
- free_op_struct(op);
- return -EIO;
- }
-
- wait_for_completion(&op->com);
-
- free_op_struct(op);
-
- for (i = 0;
- ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
- i++)
- viotape_numdev++;
- return 0;
-}
-
-
/* Write */
static ssize_t viotap_write(struct file *file, const char *buf,
size_t count, loff_t * ppos)
@@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event)
tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
op = (struct op_struct *)event->xCorrelationToken;
switch (tapeminor) {
- case viotapegetinfo:
case viotapeopen:
case viotapeclose:
op->rc = tevent->sub_type_result;
@@ -942,19 +850,31 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
{
int i = vdev->unit_address;
int j;
+ struct device_node *node = vdev->dev.archdata.of_node;
- if (i >= viotape_numdev)
+ if (i > VIOTAPE_MAX_TAPE)
return -ENODEV;
+ if (!node)
+ return -ENODEV;
+
+ if (i >= viotape_numdev)
+ viotape_numdev = i + 1;
tape_device[i] = &vdev->dev;
+ viotape_unitinfo[i].rsrcname = of_get_property(node,
+ "linux,vio_rsrcname", NULL);
+ viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
+ NULL);
+ viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
+ NULL);
state[i].cur_part = 0;
for (j = 0; j < MAX_PARTITIONS; ++j)
state[i].part_stat_rwi[j] = VIOT_IDLE;
- class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
+ device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
"iseries!vt%d", i);
- class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
- NULL, "iseries!nvt%d", i);
+ device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+ "iseries!nvt%d", i);
printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
"resource %10.10s type %4.4s, model %3.3s\n",
i, viotape_unitinfo[i].rsrcname,
@@ -966,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev)
{
int i = vdev->unit_address;
- class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
- class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
+ device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+ device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
return 0;
}
@@ -1044,11 +964,6 @@ int __init viotap_init(void)
goto unreg_chrdev;
}
- if ((ret = get_viotape_info()) < 0) {
- printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");
- goto unreg_class;
- }
-
ret = vio_register_driver(&viotape_driver);
if (ret)
goto unreg_class;
@@ -1098,19 +1013,10 @@ static int chg_state(int index, unsigned char new_state, struct file *file)
/* Cleanup */
static void __exit viotap_exit(void)
{
- int ret;
-
remove_proc_entry("iSeries/viotape", NULL);
vio_unregister_driver(&viotape_driver);
class_destroy(tape_class);
- ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
- if (ret < 0)
- printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",
- ret);
- if (viotape_unitinfo)
- dma_free_coherent(iSeries_vio_dev,
- sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
- viotape_unitinfo, viotape_unitinfo_token);
+ unregister_chrdev(VIOTAPE_MAJOR, "viotape");
viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
vio_clearHandler(viomajorsubtype_tape);
clear_op_struct_pool();
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index bef6d886d4fb..e122a0e87bb0 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1013,18 +1013,10 @@ static struct tty_driver *scc_console_device(struct console *c, int *index)
return scc_driver;
}
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
-
static struct console sercons = {
.name = "ttyS",
.write = scc_console_write,
.device = scc_console_device,
- .setup = scc_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c6f6f4209739..7a61a2a9aafe 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -770,6 +770,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
/*
* Switching-from response
*/
+ acquire_console_sem();
if (vc->vt_newvt >= 0) {
if (arg == 0)
/*
@@ -784,7 +785,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* complete the switch.
*/
int newvt;
- acquire_console_sem();
newvt = vc->vt_newvt;
vc->vt_newvt = -1;
i = vc_allocate(newvt);
@@ -798,7 +798,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
* other console switches..
*/
complete_change_console(vc_cons[newvt].d);
- release_console_sem();
}
}
@@ -810,9 +809,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
/*
* If it's just an ACK, ignore it
*/
- if (arg != VT_ACKACQ)
+ if (arg != VT_ACKACQ) {
+ release_console_sem();
return -EINVAL;
+ }
}
+ release_console_sem();
return 0;
@@ -1030,7 +1032,7 @@ static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);
/*
* Sleeps until a vt is activated, or the task is interrupted. Returns
- * 0 if activation, -EINTR if interrupted.
+ * 0 if activation, -EINTR if interrupted by a signal handler.
*/
int vt_waitactive(int vt)
{
@@ -1055,7 +1057,7 @@ int vt_waitactive(int vt)
break;
}
release_console_sem();
- retval = -EINTR;
+ retval = -ERESTARTNOHAND;
if (signal_pending(current))
break;
schedule();
@@ -1208,15 +1210,18 @@ void change_console(struct vc_data *new_vc)
/*
* Send the signal as privileged - kill_pid() will
* tell us if the process has gone or something else
- * is awry
+ * is awry.
+ *
+ * We need to set vt_newvt *before* sending the signal or we
+ * have a race.
*/
+ vc->vt_newvt = new_vc->vc_num;
if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
/*
* It worked. Mark the vt to switch to and
* return. The process needs to send us a
* VT_RELDISP ioctl to complete the switch.
*/
- vc->vt_newvt = new_vc->vc_num;
return;
}
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 2f48ba329961..37bddc1802de 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -55,6 +55,8 @@ config SOFT_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called softdog.
+# ALPHA Architecture
+
# ARM Architecture
config AT91RM9200_WATCHDOG
@@ -187,15 +189,64 @@ config PNX4008_WATCHDOG
Say N if you are unsure.
+config IOP_WATCHDOG
+ tristate "IOP Watchdog"
+ depends on PLAT_IOP
+ select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Intel IOP3XX & IOP13XX I/O Processors. This driver can
+ be built as a module by choosing M. The module will
+ be called iop_wdt.
+
+ Note: The IOP13XX watchdog does an Internal Bus Reset which will
+ affect both cores and the peripherals of the IOP. The ATU-X
+ and/or ATUe configuration registers will remain intact, but if
+ operating as an Root Complex and/or Central Resource, the PCI-X
+ and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER.
+
+config DAVINCI_WATCHDOG
+ tristate "DaVinci watchdog"
+ depends on ARCH_DAVINCI
+ help
+ Say Y here if to include support for the watchdog timer
+ in the DaVinci DM644x/DM646x processors.
+ To compile this driver as a module, choose M here: the
+ module will be called davinci_wdt.
+
+ NOTE: once enabled, this timer cannot be disabled.
+ Say N if you are unsure.
+
+# ARM26 Architecture
+
# AVR32 Architecture
config AT32AP700X_WDT
tristate "AT32AP700x watchdog"
- depends on WATCHDOG && CPU_AT32AP7000
+ depends on CPU_AT32AP7000
help
Watchdog timer embedded into AT32AP700x devices. This will reboot
your system when the timeout is reached.
+# BLACKFIN Architecture
+
+config BFIN_WDT
+ tristate "Blackfin On-Chip Watchdog Timer"
+ depends on BLACKFIN
+ ---help---
+ If you say yes here you will get support for the Blackfin On-Chip
+ Watchdog Timer. If you have one of these processors and wish to
+ have watchdog support enabled, say Y, otherwise say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_wdt.
+
+# CRIS Architecture
+
+# FRV Architecture
+
+# H8300 Architecture
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -524,37 +575,11 @@ config SBC_EPX_C3_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called sbc_epx_c3.
-# PowerPC Architecture
-
-config 8xx_WDT
- tristate "MPC8xx Watchdog Timer"
- depends on 8xx
-
-config 83xx_WDT
- tristate "MPC83xx Watchdog Timer"
- depends on PPC_83xx
-
-config MV64X60_WDT
- tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
- depends on MV64X60
-
-config BOOKE_WDT
- bool "PowerPC Book-E Watchdog Timer"
- depends on BOOKE || 4xx
- ---help---
- Please see Documentation/watchdog/watchdog-api.txt for
- more information.
-
-# PPC64 Architecture
+# M32R Architecture
-config WATCHDOG_RTAS
- tristate "RTAS watchdog"
- depends on PPC_RTAS
- help
- This driver adds watchdog support for the RTAS watchdog.
+# M68K Architecture
- To compile this driver as a module, choose M here. The module
- will be called wdrtas.
+# M68KNOMMU Architecture
# MIPS Architecture
@@ -584,6 +609,44 @@ config WDT_RM9K_GPI
To compile this driver as a module, choose M here: the
module will be called rm9k_wdt.
+# PARISC Architecture
+
+# POWERPC Architecture
+
+config MPC5200_WDT
+ tristate "MPC5200 Watchdog Timer"
+ depends on PPC_MPC52xx
+
+config 8xx_WDT
+ tristate "MPC8xx Watchdog Timer"
+ depends on 8xx
+
+config 83xx_WDT
+ tristate "MPC83xx Watchdog Timer"
+ depends on PPC_83xx
+
+config MV64X60_WDT
+ tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
+ depends on MV64X60
+
+config BOOKE_WDT
+ bool "PowerPC Book-E Watchdog Timer"
+ depends on BOOKE || 4xx
+ ---help---
+ Please see Documentation/watchdog/watchdog-api.txt for
+ more information.
+
+# PPC64 Architecture
+
+config WATCHDOG_RTAS
+ tristate "RTAS watchdog"
+ depends on PPC_RTAS
+ help
+ This driver adds watchdog support for the RTAS watchdog.
+
+ To compile this driver as a module, choose M here. The module
+ will be called wdrtas.
+
# S390 Architecture
config ZVM_WATCHDOG
@@ -598,11 +661,11 @@ config ZVM_WATCHDOG
To compile this driver as a module, choose M here. The module
will be called vmwatchdog.
-# SUPERH Architecture
+# SUPERH (sh + sh64) Architecture
config SH_WDT
tristate "SuperH Watchdog"
- depends on SUPERH
+ depends on SUPERH && (CPU_SH3 || CPU_SH4)
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
@@ -625,6 +688,8 @@ config SH_WDT_MMAP
If you say Y here, user applications will be able to mmap the
WDT/CPG registers.
+# SPARC Architecture
+
# SPARC64 Architecture
config WATCHDOG_CP1XXX
@@ -649,6 +714,10 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
+# V850 Architecture
+
+# XTENSA Architecture
+
#
# ISA-based Watchdog Cards
#
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 3907ec04a4e5..389f8b14ccc4 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -22,6 +22,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
# USB-based Watchdog Cards
obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+# ALPHA Architecture
+
# ARM Architecture
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
@@ -35,10 +37,23 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
+obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+
+# ARM26 Architecture
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+# BLACKFIN Architecture
+obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o
+
+# CRIS Architecture
+
+# FRV Architecture
+
+# H8300 Architecture
+
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
@@ -65,8 +80,22 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
-# PowerPC Architecture
+# M32R Architecture
+
+# M68K Architecture
+
+# M68KNOMMU Architecture
+
+# MIPS Architecture
+obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
+obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
+
+# PARISC Architecture
+
+# POWERPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
@@ -74,17 +103,18 @@ obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
-# MIPS Architecture
-obj-$(CONFIG_INDYDOG) += indydog.o
-obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
-obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
-
# S390 Architecture
-# SUPERH Architecture
+# SUPERH (sh + sh64) Architecture
obj-$(CONFIG_SH_WDT) += shwdt.o
+# SPARC Architecture
+
# SPARC64 Architecture
+# V850 Architecture
+
+# XTENSA Architecture
+
# Architecture Independant
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index e3f6a7d0c83d..c404fc69e7e6 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -312,6 +312,7 @@ static int ali_notify_sys(struct notifier_block *this, unsigned long code, void
*/
static struct pci_device_id ali_pci_tbl[] = {
+ { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, },
};
@@ -329,9 +330,11 @@ static int __init ali_find_watchdog(void)
struct pci_dev *pdev;
u32 wdog;
- /* Check for a 1535 series bridge */
+ /* Check for a 1533/1535 series bridge */
pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
- if(pdev == NULL)
+ if (pdev == NULL)
+ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1533, NULL);
+ if (pdev == NULL)
return -ENODEV;
pci_dev_put(pdev);
diff --git a/drivers/char/watchdog/bfin_wdt.c b/drivers/char/watchdog/bfin_wdt.c
new file mode 100644
index 000000000000..309d27913fc1
--- /dev/null
+++ b/drivers/char/watchdog/bfin_wdt.c
@@ -0,0 +1,490 @@
+/*
+ * Blackfin On-Chip Watchdog Driver
+ * Supports BF53[123]/BF53[467]/BF54[2489]/BF561
+ *
+ * Originally based on softdog.c
+ * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2007 Michele d'Amico
+ * Copyright 1996 Alan Cox <alan@redhat.com>
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
+#define stampit() stamp("here i am")
+
+#define WATCHDOG_NAME "bfin-wdt"
+#define PFX WATCHDOG_NAME ": "
+
+/* The BF561 has two watchdogs (one per core), but since Linux
+ * only runs on core A, we'll just work with that one.
+ */
+#ifdef BF561_FAMILY
+# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL()
+# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT()
+# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT()
+# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x)
+# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x)
+# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
+#endif
+
+/* Bit in SWRST that indicates boot caused by watchdog */
+#define SWRST_RESET_WDOG 0x4000
+
+/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
+#define WDOG_EXPIRED 0x8000
+
+/* Masks for WDEV field in WDOG_CTL register */
+#define ICTL_RESET 0x0
+#define ICTL_NMI 0x2
+#define ICTL_GPI 0x4
+#define ICTL_NONE 0x6
+#define ICTL_MASK 0x6
+
+/* Masks for WDEN field in WDOG_CTL register */
+#define WDEN_MASK 0x0FF0
+#define WDEN_ENABLE 0x0000
+#define WDEN_DISABLE 0x0AD0
+
+/* some defaults */
+#define WATCHDOG_TIMEOUT 20
+
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+static struct watchdog_info bfin_wdt_info;
+static unsigned long open_check;
+static char expect_close;
+static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
+ *
+ * The Userspace watchdog got a KeepAlive: schedule the next timeout.
+ */
+static int bfin_wdt_keepalive(void)
+{
+ stampit();
+ bfin_write_WDOG_STAT(0);
+ return 0;
+}
+
+/**
+ * bfin_wdt_stop - Stop the Watchdog
+ *
+ * Stops the on-chip watchdog.
+ */
+static int bfin_wdt_stop(void)
+{
+ stampit();
+ bfin_write_WDOG_CTL(WDEN_DISABLE);
+ return 0;
+}
+
+/**
+ * bfin_wdt_start - Start the Watchdog
+ *
+ * Starts the on-chip watchdog. Automatically loads WDOG_CNT
+ * into WDOG_STAT for us.
+ */
+static int bfin_wdt_start(void)
+{
+ stampit();
+ bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
+ return 0;
+}
+
+/**
+ * bfin_wdt_running - Check Watchdog status
+ *
+ * See if the watchdog is running.
+ */
+static int bfin_wdt_running(void)
+{
+ stampit();
+ return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
+}
+
+/**
+ * bfin_wdt_set_timeout - Set the Userspace Watchdog timeout
+ * @t: new timeout value (in seconds)
+ *
+ * Translate the specified timeout in seconds into System Clock
+ * terms which is what the on-chip Watchdog requires.
+ */
+static int bfin_wdt_set_timeout(unsigned long t)
+{
+ u32 cnt;
+ unsigned long flags;
+
+ stampit();
+
+ cnt = t * get_sclk();
+ if (cnt < get_sclk()) {
+ printk(KERN_WARNING PFX "timeout value is too large\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+ {
+ int run = bfin_wdt_running();
+ bfin_wdt_stop();
+ bfin_write_WDOG_CNT(cnt);
+ if (run) bfin_wdt_start();
+ }
+ spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+
+ timeout = t;
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_open - Open the Device
+ * @inode: inode of device
+ * @file: file handle of device
+ *
+ * Watchdog device is opened and started.
+ */
+static int bfin_wdt_open(struct inode *inode, struct file *file)
+{
+ stampit();
+
+ if (test_and_set_bit(0, &open_check))
+ return -EBUSY;
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ bfin_wdt_keepalive();
+ bfin_wdt_start();
+
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * bfin_wdt_close - Close the Device
+ * @inode: inode of device
+ * @file: file handle of device
+ *
+ * Watchdog device is closed and stopped.
+ */
+static int bfin_wdt_release(struct inode *inode, struct file *file)
+{
+ stampit();
+
+ if (expect_close == 42) {
+ bfin_wdt_stop();
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ bfin_wdt_keepalive();
+ }
+
+ expect_close = 0;
+ clear_bit(0, &open_check);
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_write - Write to Device
+ * @file: file handle of device
+ * @buf: buffer to write
+ * @count: length of buffer
+ * @ppos: offset
+ *
+ * Pings the watchdog on write.
+ */
+static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ stampit();
+
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ bfin_wdt_keepalive();
+ }
+
+ return len;
+}
+
+/**
+ * bfin_wdt_ioctl - Query Device
+ * @inode: inode of device
+ * @file: file handle of device
+ * @cmd: watchdog command
+ * @arg: argument
+ *
+ * Query basic information from the device or ping it, as outlined by the
+ * watchdog API.
+ */
+static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+
+ stampit();
+
+ switch (cmd) {
+ default:
+ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
+ return -EFAULT;
+ else
+ return 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
+
+ case WDIOC_KEEPALIVE:
+ bfin_wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETTIMEOUT: {
+ int new_timeout;
+
+ if (get_user(new_timeout, p))
+ return -EFAULT;
+
+ if (bfin_wdt_set_timeout(new_timeout))
+ return -EINVAL;
+ }
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+
+ case WDIOC_SETOPTIONS: {
+ unsigned long flags;
+ int options, ret = -EINVAL;
+
+ if (get_user(options, p))
+ return -EFAULT;
+
+ spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+
+ if (options & WDIOS_DISABLECARD) {
+ bfin_wdt_stop();
+ ret = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ bfin_wdt_start();
+ ret = 0;
+ }
+
+ spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+
+ return ret;
+ }
+ }
+}
+
+/**
+ * bfin_wdt_notify_sys - Notifier Handler
+ * @this: notifier block
+ * @code: notifier event
+ * @unused: unused
+ *
+ * Handles specific events, such as turning off the watchdog during a
+ * shutdown event.
+ */
+static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ stampit();
+
+ if (code == SYS_DOWN || code == SYS_HALT)
+ bfin_wdt_stop();
+
+ return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_PM
+static int state_before_suspend;
+
+/**
+ * bfin_wdt_suspend - suspend the watchdog
+ * @pdev: device being suspended
+ * @state: requested suspend state
+ *
+ * Remember if the watchdog was running and stop it.
+ * TODO: is this even right? Doesn't seem to be any
+ * standard in the watchdog world ...
+ */
+static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ stampit();
+
+ state_before_suspend = bfin_wdt_running();
+ bfin_wdt_stop();
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_resume - resume the watchdog
+ * @pdev: device being resumed
+ *
+ * If the watchdog was running, turn it back on.
+ */
+static int bfin_wdt_resume(struct platform_device *pdev)
+{
+ stampit();
+
+ if (state_before_suspend) {
+ bfin_wdt_set_timeout(timeout);
+ bfin_wdt_start();
+ }
+
+ return 0;
+}
+#else
+# define bfin_wdt_suspend NULL
+# define bfin_wdt_resume NULL
+#endif
+
+static struct platform_device bfin_wdt_device = {
+ .name = WATCHDOG_NAME,
+ .id = -1,
+};
+
+static struct platform_driver bfin_wdt_driver = {
+ .driver = {
+ .name = WATCHDOG_NAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = bfin_wdt_suspend,
+ .resume = bfin_wdt_resume,
+};
+
+static struct file_operations bfin_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = bfin_wdt_write,
+ .ioctl = bfin_wdt_ioctl,
+ .open = bfin_wdt_open,
+ .release = bfin_wdt_release,
+};
+
+static struct miscdevice bfin_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &bfin_wdt_fops,
+};
+
+static struct watchdog_info bfin_wdt_info = {
+ .identity = "Blackfin Watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+static struct notifier_block bfin_wdt_notifier = {
+ .notifier_call = bfin_wdt_notify_sys,
+};
+
+/**
+ * bfin_wdt_init - Initialize module
+ *
+ * Registers the device and notifier handler. Actual device
+ * initialization is handled by bfin_wdt_open().
+ */
+static int __init bfin_wdt_init(void)
+{
+ int ret;
+
+ stampit();
+
+ /* Check that the timeout value is within range */
+ if (bfin_wdt_set_timeout(timeout))
+ return -EINVAL;
+
+ /* Since this is an on-chip device and needs no board-specific
+ * resources, we'll handle all the platform device stuff here.
+ */
+ ret = platform_device_register(&bfin_wdt_device);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_probe(&bfin_wdt_driver, NULL);
+ if (ret)
+ return ret;
+
+ ret = register_reboot_notifier(&bfin_wdt_notifier);
+ if (ret) {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+ return ret;
+ }
+
+ ret = misc_register(&bfin_wdt_miscdev);
+ if (ret) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ unregister_reboot_notifier(&bfin_wdt_notifier);
+ return ret;
+ }
+
+ printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_exit - Deinitialize module
+ *
+ * Unregisters the device and notifier handler. Actual device
+ * deinitialization is handled by bfin_wdt_close().
+ */
+static void __exit bfin_wdt_exit(void)
+{
+ misc_deregister(&bfin_wdt_miscdev);
+ unregister_reboot_notifier(&bfin_wdt_notifier);
+}
+
+module_init(bfin_wdt_init);
+module_exit(bfin_wdt_exit);
+
+MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>");
+MODULE_DESCRIPTION("Blackfin Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 0f5c77ddd39d..d362f5bf658a 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -144,7 +144,7 @@ static int booke_wdt_open (struct inode *inode, struct file *file)
booke_wdt_period);
}
- return 0;
+ return nonseekable_open(inode, file);
}
static const struct file_operations booke_wdt_fops = {
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index d0d45a8b09f0..5941ca601a3a 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -162,6 +162,10 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
+ case WDIOC_GETBOOTSTATUS:
+ if ( copy_to_user(argp, &value, sizeof(int)) )
+ return -EFAULT;
+ break;
case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &ident, sizeof(ident)) )
return -EFAULT;
diff --git a/drivers/char/watchdog/davinci_wdt.c b/drivers/char/watchdog/davinci_wdt.c
new file mode 100644
index 000000000000..19db5302ba6e
--- /dev/null
+++ b/drivers/char/watchdog/davinci_wdt.c
@@ -0,0 +1,281 @@
+/*
+ * drivers/char/watchdog/davinci_wdt.c
+ *
+ * Watchdog driver for DaVinci DM644x/DM646x processors
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define MODULE_NAME "DAVINCI-WDT: "
+
+#define DEFAULT_HEARTBEAT 60
+#define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/
+
+/* Timer register set definition */
+#define PID12 (0x0)
+#define EMUMGT (0x4)
+#define TIM12 (0x10)
+#define TIM34 (0x14)
+#define PRD12 (0x18)
+#define PRD34 (0x1C)
+#define TCR (0x20)
+#define TGCR (0x24)
+#define WDTCR (0x28)
+
+/* TCR bit definitions */
+#define ENAMODE12_DISABLED (0 << 6)
+#define ENAMODE12_ONESHOT (1 << 6)
+#define ENAMODE12_PERIODIC (2 << 6)
+
+/* TGCR bit definitions */
+#define TIM12RS_UNRESET (1 << 0)
+#define TIM34RS_UNRESET (1 << 1)
+#define TIMMODE_64BIT_WDOG (2 << 2)
+
+/* WDTCR bit definitions */
+#define WDEN (1 << 14)
+#define WDFLAG (1 << 15)
+#define WDKEY_SEQ0 (0xa5c6 << 16)
+#define WDKEY_SEQ1 (0xda7e << 16)
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+
+static spinlock_t io_lock;
+static unsigned long wdt_status;
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_REGION_INITED 2
+#define WDT_DEVICE_INITED 3
+
+static struct resource *wdt_mem;
+static void __iomem *wdt_base;
+
+static void wdt_service(void)
+{
+ spin_lock(&io_lock);
+
+ /* put watchdog in service state */
+ davinci_writel(WDKEY_SEQ0, wdt_base + WDTCR);
+ /* put watchdog in active state */
+ davinci_writel(WDKEY_SEQ1, wdt_base + WDTCR);
+
+ spin_unlock(&io_lock);
+}
+
+static void wdt_enable(void)
+{
+ u32 tgcr;
+ u32 timer_margin;
+
+ spin_lock(&io_lock);
+
+ /* disable, internal clock source */
+ davinci_writel(0, wdt_base + TCR);
+ /* reset timer, set mode to 64-bit watchdog, and unreset */
+ davinci_writel(0, wdt_base + TGCR);
+ tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
+ davinci_writel(tgcr, wdt_base + TGCR);
+ /* clear counter regs */
+ davinci_writel(0, wdt_base + TIM12);
+ davinci_writel(0, wdt_base + TIM34);
+ /* set timeout period */
+ timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) & 0xffffffff);
+ davinci_writel(timer_margin, wdt_base + PRD12);
+ timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) >> 32);
+ davinci_writel(timer_margin, wdt_base + PRD34);
+ /* enable run continuously */
+ davinci_writel(ENAMODE12_PERIODIC, wdt_base + TCR);
+ /* Once the WDT is in pre-active state write to
+ * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
+ * write protected (except for the WDKEY field)
+ */
+ /* put watchdog in pre-active state */
+ davinci_writel(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
+ /* put watchdog in active state */
+ davinci_writel(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
+
+ spin_unlock(&io_lock);
+}
+
+static int davinci_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ wdt_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+davinci_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (len)
+ wdt_service();
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING,
+ .identity = "DaVinci Watchdog",
+};
+
+static int
+davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_service();
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int davinci_wdt_release(struct inode *inode, struct file *file)
+{
+ wdt_service();
+ clear_bit(WDT_IN_USE, &wdt_status);
+
+ return 0;
+}
+
+static const struct file_operations davinci_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = davinci_wdt_write,
+ .ioctl = davinci_wdt_ioctl,
+ .open = davinci_wdt_open,
+ .release = davinci_wdt_release,
+};
+
+static struct miscdevice davinci_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &davinci_wdt_fops,
+};
+
+static int davinci_wdt_probe(struct platform_device *pdev)
+{
+ int ret = 0, size;
+ struct resource *res;
+
+ spin_lock_init(&io_lock);
+
+ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+ heartbeat = DEFAULT_HEARTBEAT;
+
+ printk(KERN_INFO MODULE_NAME
+ "DaVinci Watchdog Timer: heartbeat %d sec\n", heartbeat);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ printk(KERN_INFO MODULE_NAME
+ "failed to get memory region resource\n");
+ return -ENOENT;
+ }
+
+ size = res->end - res->start + 1;
+ wdt_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (wdt_mem == NULL) {
+ printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
+ return -ENOENT;
+ }
+ wdt_base = (void __iomem *)(res->start);
+
+ ret = misc_register(&davinci_wdt_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ } else {
+ set_bit(WDT_DEVICE_INITED, &wdt_status);
+ }
+
+ return ret;
+}
+
+static int davinci_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&davinci_wdt_miscdev);
+ if (wdt_mem) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ wdt_mem = NULL;
+ }
+ return 0;
+}
+
+static struct platform_driver platform_wdt_driver = {
+ .driver = {
+ .name = "watchdog",
+ },
+ .probe = davinci_wdt_probe,
+ .remove = davinci_wdt_remove,
+};
+
+static int __init davinci_wdt_init(void)
+{
+ return platform_driver_register(&platform_wdt_driver);
+}
+
+static void __exit davinci_wdt_exit(void)
+{
+ return platform_driver_unregister(&platform_wdt_driver);
+}
+
+module_init(davinci_wdt_init);
+module_exit(davinci_wdt_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("DaVinci Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat period in seconds from 1 to "
+ __MODULE_STRING(MAX_HEARTBEAT) ", default "
+ __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index b070324e27a6..b14e9d1f164d 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -1,5 +1,5 @@
/*
- * Eurotech CPU-1220/1410 on board WDT driver
+ * Eurotech CPU-1220/1410/1420 on board WDT driver
*
* (c) Copyright 2001 Ascensit <support@ascensit.com>
* (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
@@ -25,6 +25,9 @@
/* Changelog:
*
+ * 2001 - Rodolfo Giometti
+ * Initial release
+ *
* 2002/04/25 - Rob Radez
* clean up #includes
* clean up locking
@@ -33,13 +36,15 @@
* add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
* add expect_close support
*
- * 2001 - Rodolfo Giometti
- * Initial release
- *
* 2002.05.30 - Joel Becker <joel.becker@oracle.com>
* Added Matt Domsch's nowayout module option.
*/
+/*
+ * The eurotech CPU-1220/1410/1420's watchdog is a part
+ * of the on-board SUPER I/O device SMSC FDC 37B782.
+ */
+
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
index eac4f9b9f007..cd5a565bc3a0 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -39,7 +39,12 @@
* 82801HR (ICH8R) : document number 313056-002, 313057-004,
* 82801HH (ICH8DH) : document number 313056-002, 313057-004,
* 82801HO (ICH8DO) : document number 313056-002, 313057-004,
- * 6300ESB (6300ESB) : document number 300641-003
+ * 82801IB (ICH9) : document number 316972-001, 316973-001,
+ * 82801IR (ICH9R) : document number 316972-001, 316973-001,
+ * 82801IH (ICH9DH) : document number 316972-001, 316973-001,
+ * 6300ESB (6300ESB) : document number 300641-003, 300884-010,
+ * 631xESB (631xESB) : document number 313082-001, 313075-005,
+ * 632xESB (632xESB) : document number 313082-001, 313075-005
*/
/*
@@ -48,8 +53,8 @@
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
-#define DRV_VERSION "1.01"
-#define DRV_RELDATE "21-Jan-2007"
+#define DRV_VERSION "1.02"
+#define DRV_RELDATE "26-Jul-2007"
#define PFX DRV_NAME ": "
/* Includes */
@@ -92,6 +97,10 @@ enum iTCO_chipsets {
TCO_ICH8, /* ICH8 & ICH8R */
TCO_ICH8DH, /* ICH8DH */
TCO_ICH8DO, /* ICH8DO */
+ TCO_ICH9, /* ICH9 */
+ TCO_ICH9R, /* ICH9R */
+ TCO_ICH9DH, /* ICH9DH */
+ TCO_631XESB, /* 631xESB/632xESB */
};
static struct {
@@ -118,6 +127,10 @@ static struct {
{"ICH8 or ICH8R", 2},
{"ICH8DH", 2},
{"ICH8DO", 2},
+ {"ICH9", 2},
+ {"ICH9R", 2},
+ {"ICH9DH", 2},
+ {"631xESB/632xESB", 2},
{NULL,0}
};
@@ -148,6 +161,25 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
+ { PCI_VENDOR_ID_INTEL, 0x2918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9 },
+ { PCI_VENDOR_ID_INTEL, 0x2916, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/char/watchdog/iop_wdt.c
new file mode 100644
index 000000000000..bbbd91af754d
--- /dev/null
+++ b/drivers/char/watchdog/iop_wdt.c
@@ -0,0 +1,262 @@
+/*
+ * drivers/char/watchdog/iop_wdt.c
+ *
+ * WDT driver for Intel I/O Processors
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Curt E Bruns <curt.e.bruns@intel.com>
+ * Peter Milne <peter.milne@d-tacq.com>
+ * Dan Williams <dan.j.williams@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <asm/hardware.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_ENABLED 2
+
+static unsigned long iop_watchdog_timeout(void)
+{
+ return (0xffffffffUL / get_iop_tick_rate());
+}
+
+/**
+ * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
+ * or iop3xx by whether it has a disable command
+ */
+static int wdt_supports_disable(void)
+{
+ int can_disable;
+
+ if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
+ can_disable = 1;
+ else
+ can_disable = 0;
+
+ return can_disable;
+}
+
+static void wdt_enable(void)
+{
+ /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
+ * Takes approx. 10.7s to timeout
+ */
+ write_wdtcr(IOP_WDTCR_EN_ARM);
+ write_wdtcr(IOP_WDTCR_EN);
+}
+
+/* returns 0 if the timer was successfully disabled */
+static int wdt_disable(void)
+{
+ /* Stop Counting */
+ if (wdt_supports_disable()) {
+ write_wdtcr(IOP_WDTCR_DIS_ARM);
+ write_wdtcr(IOP_WDTCR_DIS);
+ clear_bit(WDT_ENABLED, &wdt_status);
+ printk(KERN_INFO "WATCHDOG: Disabled\n");
+ return 0;
+ } else
+ return 1;
+}
+
+static int iop_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ wdt_enable();
+
+ set_bit(WDT_ENABLED, &wdt_status);
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+iop_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_enable();
+ }
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "iop watchdog",
+};
+
+static int
+iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int options;
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user
+ ((struct watchdog_info *)arg, &ident, sizeof ident))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(boot_status, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(iop_watchdog_timeout(), (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(options, (int *)arg))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ if (!nowayout) {
+ if (wdt_disable() == 0) {
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ ret = 0;
+ } else
+ ret = -ENXIO;
+ } else
+ ret = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ wdt_enable();
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int iop_wdt_release(struct inode *inode, struct file *file)
+{
+ int state = 1;
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ if (test_bit(WDT_ENABLED, &wdt_status))
+ state = wdt_disable();
+
+ /* if the timer is not disbaled reload and notify that we are still
+ * going down
+ */
+ if (state != 0) {
+ wdt_enable();
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+ "reset in %lu seconds\n", iop_watchdog_timeout());
+ }
+
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+static const struct file_operations iop_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = iop_wdt_write,
+ .ioctl = iop_wdt_ioctl,
+ .open = iop_wdt_open,
+ .release = iop_wdt_release,
+};
+
+static struct miscdevice iop_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &iop_wdt_fops,
+};
+
+static int __init iop_wdt_init(void)
+{
+ int ret;
+
+ ret = misc_register(&iop_wdt_miscdev);
+ if (ret == 0)
+ printk("iop watchdog timer: timeout %lu sec\n",
+ iop_watchdog_timeout());
+
+ /* check if the reset was caused by the watchdog timer */
+ boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
+
+ /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
+ * NOTE: An IB Reset will Reset both cores in the IOP342
+ */
+ write_wdtsr(IOP13XX_WDTCR_IB_RESET);
+
+ return ret;
+}
+
+static void __exit iop_wdt_exit(void)
+{
+ misc_deregister(&iop_wdt_miscdev);
+}
+
+module_init(iop_wdt_init);
+module_exit(iop_wdt_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
+MODULE_DESCRIPTION("iop watchdog timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index a0d27160c80e..6d35bb112a5f 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -321,6 +321,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index db2ccb864412..1adf1d56027d 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -215,6 +215,11 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
}
break;
+ case WDIOC_GETBOOTSTATUS:
+ if (copy_to_user(p, &status, sizeof(int))) {
+ return -EFAULT;
+ }
+ break;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) {
return -EFAULT;
diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/char/watchdog/mpc5200_wdt.c
new file mode 100644
index 000000000000..564143d40610
--- /dev/null
+++ b/drivers/char/watchdog/mpc5200_wdt.c
@@ -0,0 +1,286 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <asm/of_platform.h>
+#include <asm/uaccess.h>
+#include <asm/mpc52xx.h>
+
+
+#define GPT_MODE_WDT (1<<15)
+#define GPT_MODE_CE (1<<12)
+#define GPT_MODE_MS_TIMER (0x4)
+
+
+struct mpc5200_wdt {
+ unsigned count; /* timer ticks before watchdog kicks in */
+ long ipb_freq;
+ struct miscdevice miscdev;
+ struct resource mem;
+ struct mpc52xx_gpt __iomem *regs;
+ spinlock_t io_lock;
+};
+
+/* is_active stores wether or not the /dev/watchdog device is opened */
+static unsigned long is_active;
+
+/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from
+ * file operations, which sucks. But there can be max 1 watchdog anyway, so...
+ */
+static struct mpc5200_wdt *wdt_global;
+
+
+/* helper to calculate timeout in timer counts */
+static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout)
+{
+ /* use biggest prescaler of 64k */
+ wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout;
+
+ if (wdt->count > 0xffff)
+ wdt->count = 0xffff;
+}
+/* return timeout in seconds (calculated from timer count) */
+static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt)
+{
+ return wdt->count * 0x10000 / wdt->ipb_freq;
+}
+
+
+/* watchdog operations */
+static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
+{
+ spin_lock(&wdt->io_lock);
+ /* disable */
+ out_be32(&wdt->regs->mode, 0);
+ /* set timeout, with maximum prescaler */
+ out_be32(&wdt->regs->count, 0x0 | wdt->count);
+ /* enable watchdog */
+ out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER);
+ spin_unlock(&wdt->io_lock);
+
+ return 0;
+}
+static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
+{
+ spin_lock(&wdt->io_lock);
+ /* writing A5 to OCPW resets the watchdog */
+ out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode)));
+ spin_unlock(&wdt->io_lock);
+ return 0;
+}
+static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
+{
+ spin_lock(&wdt->io_lock);
+ /* disable */
+ out_be32(&wdt->regs->mode, 0);
+ spin_unlock(&wdt->io_lock);
+ return 0;
+}
+
+
+/* file operations */
+static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ struct mpc5200_wdt *wdt = file->private_data;
+ mpc5200_wdt_ping(wdt);
+ return 0;
+}
+static struct watchdog_info mpc5200_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "mpc5200 watchdog on GPT0",
+};
+static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mpc5200_wdt *wdt = file->private_data;
+ int __user *data = (int __user *)arg;
+ int timeout;
+ int ret = 0;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user(data, &mpc5200_wdt_info,
+ sizeof(mpc5200_wdt_info));
+ if (ret)
+ ret = -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, data);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ mpc5200_wdt_ping(wdt);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(timeout, data);
+ if (ret)
+ break;
+ mpc5200_wdt_set_timeout(wdt, timeout);
+ mpc5200_wdt_start(wdt);
+ /* fall through and return the timeout */
+
+ case WDIOC_GETTIMEOUT:
+ timeout = mpc5200_wdt_get_timeout(wdt);
+ ret = put_user(timeout, data);
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+ return ret;
+}
+static int mpc5200_wdt_open(struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &is_active))
+ return -EBUSY;
+
+ /* Set and activate the watchdog */
+ mpc5200_wdt_set_timeout(wdt_global, 30);
+ mpc5200_wdt_start(wdt_global);
+ file->private_data = wdt_global;
+ return nonseekable_open(inode, file);
+}
+static int mpc5200_wdt_release(struct inode *inode, struct file *file)
+{
+#if WATCHDOG_NOWAYOUT == 0
+ struct mpc5200_wdt *wdt = file->private_data;
+ mpc5200_wdt_stop(wdt);
+ wdt->count = 0; /* == disabled */
+#endif
+ clear_bit(0, &is_active);
+ return 0;
+}
+
+static struct file_operations mpc5200_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = mpc5200_wdt_write,
+ .ioctl = mpc5200_wdt_ioctl,
+ .open = mpc5200_wdt_open,
+ .release = mpc5200_wdt_release,
+};
+
+/* module operations */
+static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct mpc5200_wdt *wdt;
+ int err;
+ const void *has_wdt;
+ int size;
+
+ has_wdt = of_get_property(op->node, "has-wdt", NULL);
+ if (!has_wdt)
+ return -ENODEV;
+
+ wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node);
+
+ err = of_address_to_resource(op->node, 0, &wdt->mem);
+ if (err)
+ goto out_free;
+ size = wdt->mem.end - wdt->mem.start + 1;
+ if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) {
+ err = -ENODEV;
+ goto out_free;
+ }
+ wdt->regs = ioremap(wdt->mem.start, size);
+ if (!wdt->regs) {
+ err = -ENODEV;
+ goto out_release;
+ }
+
+ dev_set_drvdata(&op->dev, wdt);
+ spin_lock_init(&wdt->io_lock);
+
+ wdt->miscdev = (struct miscdevice) {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mpc5200_wdt_fops,
+ .parent = &op->dev,
+ };
+ wdt_global = wdt;
+ err = misc_register(&wdt->miscdev);
+ if (!err)
+ return 0;
+
+ iounmap(wdt->regs);
+ out_release:
+ release_mem_region(wdt->mem.start, size);
+ out_free:
+ kfree(wdt);
+ return err;
+}
+
+static int mpc5200_wdt_remove(struct of_device *op)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+
+ mpc5200_wdt_stop(wdt);
+ misc_deregister(&wdt->miscdev);
+ iounmap(wdt->regs);
+ release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1);
+ kfree(wdt);
+
+ return 0;
+}
+static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+ mpc5200_wdt_stop(wdt);
+ return 0;
+}
+static int mpc5200_wdt_resume(struct of_device *op)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+ if (wdt->count)
+ mpc5200_wdt_start(wdt);
+ return 0;
+}
+static int mpc5200_wdt_shutdown(struct of_device *op)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+ mpc5200_wdt_stop(wdt);
+ return 0;
+}
+
+static struct of_device_id mpc5200_wdt_match[] = {
+ { .compatible = "mpc5200-gpt", },
+ {},
+};
+static struct of_platform_driver mpc5200_wdt_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5200-gpt-wdt",
+ .match_table = mpc5200_wdt_match,
+ .probe = mpc5200_wdt_probe,
+ .remove = mpc5200_wdt_remove,
+ .suspend = mpc5200_wdt_suspend,
+ .resume = mpc5200_wdt_resume,
+ .shutdown = mpc5200_wdt_shutdown,
+};
+
+
+static int __init mpc5200_wdt_init(void)
+{
+ return of_register_platform_driver(&mpc5200_wdt_driver);
+}
+
+static void __exit mpc5200_wdt_exit(void)
+{
+ of_unregister_platform_driver(&mpc5200_wdt_driver);
+}
+
+module_init(mpc5200_wdt_init);
+module_exit(mpc5200_wdt_exit);
+
+MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
index 18ca752e2f90..a0bf95fb9763 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -119,6 +119,9 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
case WDIOC_KEEPALIVE:
mpc83xx_wdt_keepalive();
return 0;
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 8aaed10dd499..85b5734403a5 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -57,7 +57,7 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
m8xx_wdt_reset();
mpc8xx_wdt_handler_disable();
- return 0;
+ return nonseekable_open(inode, file);
}
static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index e88947f8fe53..0d2b27735419 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -328,12 +328,11 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
goto err_out;
}
- wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+ wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
if (!wdt) {
ret = -ENOMEM;
goto err_out;
}
- memset(wdt, 0, sizeof(struct mpcore_wdt));
wdt->dev = &dev->dev;
wdt->irq = platform_get_irq(dev, 0);
diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c
index 419ab445c944..dcfd401a7ad7 100644
--- a/drivers/char/watchdog/mtx-1_wdt.c
+++ b/drivers/char/watchdog/mtx-1_wdt.c
@@ -143,6 +143,7 @@ static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int c
mtx1_wdt_reset();
break;
case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index b887cdb01334..0365c317f7e1 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -23,61 +23,101 @@
#include <linux/watchdog.h>
#include <linux/platform_device.h>
-#include <asm/mv64x60.h>
+#include <linux/mv643xx.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-/* MV64x60 WDC (config) register access definitions */
-#define MV64x60_WDC_CTL1_MASK (3 << 24)
-#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)
-#define MV64x60_WDC_CTL2_MASK (3 << 26)
-#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)
+#define MV64x60_WDT_WDC_OFFSET 0
+
+/*
+ * The watchdog configuration register contains a pair of 2-bit fields,
+ * 1. a reload field, bits 27-26, which triggers a reload of
+ * the countdown register, and
+ * 2. an enable field, bits 25-24, which toggles between
+ * enabling and disabling the watchdog timer.
+ * Bit 31 is a read-only field which indicates whether the
+ * watchdog timer is currently enabled.
+ *
+ * The low 24 bits contain the timer reload value.
+ */
+#define MV64x60_WDC_ENABLE_SHIFT 24
+#define MV64x60_WDC_SERVICE_SHIFT 26
+#define MV64x60_WDC_ENABLED_SHIFT 31
+
+#define MV64x60_WDC_ENABLED_TRUE 1
+#define MV64x60_WDC_ENABLED_FALSE 0
/* Flags bits */
#define MV64x60_WDOG_FLAG_OPENED 0
-#define MV64x60_WDOG_FLAG_ENABLED 1
static unsigned long wdt_flags;
static int wdt_status;
-static void __iomem *mv64x60_regs;
+static void __iomem *mv64x60_wdt_regs;
static int mv64x60_wdt_timeout;
+static int mv64x60_wdt_count;
+static unsigned int bus_clk;
+static char expect_close;
+static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static void mv64x60_wdt_reg_write(u32 val)
+static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
{
- /* Allow write only to CTL1 / CTL2 fields, retaining values in
- * other fields.
- */
- u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
- data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
- data |= val;
- writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+ u32 data;
+ u32 enabled;
+ int ret = 0;
+
+ spin_lock(&mv64x60_wdt_spinlock);
+ data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+ enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1;
+
+ /* only toggle the requested field if enabled state matches predicate */
+ if ((enabled ^ enabled_predicate) == 0) {
+ /* We write a 1, then a 2 -- to the appropriate field */
+ data = (1 << field_shift) | mv64x60_wdt_count;
+ writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+
+ data = (2 << field_shift) | mv64x60_wdt_count;
+ writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+ ret = 1;
+ }
+ spin_unlock(&mv64x60_wdt_spinlock);
+
+ return ret;
}
static void mv64x60_wdt_service(void)
{
- /* Write 01 followed by 10 to CTL2 */
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+ mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
+ MV64x60_WDC_SERVICE_SHIFT);
+}
+
+static void mv64x60_wdt_handler_enable(void)
+{
+ if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
+ MV64x60_WDC_ENABLE_SHIFT)) {
+ mv64x60_wdt_service();
+ printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+ }
}
static void mv64x60_wdt_handler_disable(void)
{
- if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
- /* Write 01 followed by 10 to CTL1 */
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+ if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
+ MV64x60_WDC_ENABLE_SHIFT))
printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
- }
}
-static void mv64x60_wdt_handler_enable(void)
+static void mv64x60_wdt_set_timeout(unsigned int timeout)
{
- if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
- /* Write 01 followed by 10 to CTL1 */
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
- printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
- }
+ /* maximum bus cycle count is 0xFFFFFFFF */
+ if (timeout > 0xFFFFFFFF / bus_clk)
+ timeout = 0xFFFFFFFF / bus_clk;
+
+ mv64x60_wdt_count = timeout * bus_clk >> 8;
+ mv64x60_wdt_timeout = timeout;
}
static int mv64x60_wdt_open(struct inode *inode, struct file *file)
@@ -85,21 +125,24 @@ static int mv64x60_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
return -EBUSY;
- mv64x60_wdt_service();
- mv64x60_wdt_handler_enable();
+ if (nowayout)
+ __module_get(THIS_MODULE);
- nonseekable_open(inode, file);
+ mv64x60_wdt_handler_enable();
- return 0;
+ return nonseekable_open(inode, file);
}
static int mv64x60_wdt_release(struct inode *inode, struct file *file)
{
- mv64x60_wdt_service();
-
-#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
- mv64x60_wdt_handler_disable();
-#endif
+ if (expect_close == 42)
+ mv64x60_wdt_handler_disable();
+ else {
+ printk(KERN_CRIT
+ "mv64x60_wdt: unexpected close, not stopping timer!\n");
+ mv64x60_wdt_service();
+ }
+ expect_close = 0;
clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
@@ -109,8 +152,22 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos)
{
- if (len)
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+ if(get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
mv64x60_wdt_service();
+ }
return len;
}
@@ -119,9 +176,12 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int timeout;
+ int options;
void __user *argp = (void __user *)arg;
static struct watchdog_info info = {
- .options = WDIOF_KEEPALIVEPING,
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
.firmware_version = 0,
.identity = "MV64x60 watchdog",
};
@@ -143,7 +203,15 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
return -EOPNOTSUPP;
case WDIOC_SETOPTIONS:
- return -EOPNOTSUPP;
+ if (get_user(options, (int __user *)argp))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD)
+ mv64x60_wdt_handler_disable();
+
+ if (options & WDIOS_ENABLECARD)
+ mv64x60_wdt_handler_enable();
+ break;
case WDIOC_KEEPALIVE:
mv64x60_wdt_service();
@@ -151,11 +219,13 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
break;
case WDIOC_SETTIMEOUT:
- return -EOPNOTSUPP;
+ if (get_user(timeout, (int __user *)argp))
+ return -EFAULT;
+ mv64x60_wdt_set_timeout(timeout);
+ /* Fall through */
case WDIOC_GETTIMEOUT:
- timeout = mv64x60_wdt_timeout * HZ;
- if (put_user(timeout, (int __user *)argp))
+ if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
return -EFAULT;
break;
@@ -184,18 +254,33 @@ static struct miscdevice mv64x60_wdt_miscdev = {
static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
{
struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
- int bus_clk = 133;
+ struct resource *r;
+ int timeout = 10;
- mv64x60_wdt_timeout = 10;
+ bus_clk = 133; /* in MHz */
if (pdata) {
- mv64x60_wdt_timeout = pdata->timeout;
+ timeout = pdata->timeout;
bus_clk = pdata->bus_clk;
}
- mv64x60_regs = mv64x60_get_bridge_vbase();
+ /* Since bus_clk is truncated MHz, actual frequency could be
+ * up to 1MHz higher. Round up, since it's better to time out
+ * too late than too soon.
+ */
+ bus_clk++;
+ bus_clk *= 1000000; /* convert to Hz */
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
- writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
- mv64x60_regs + MV64x60_WDT_WDC);
+ mv64x60_wdt_regs = ioremap(r->start, r->end - r->start + 1);
+ if (mv64x60_wdt_regs == NULL)
+ return -ENOMEM;
+
+ mv64x60_wdt_set_timeout(timeout);
+
+ mv64x60_wdt_handler_disable(); /* in case timer was already running */
return misc_register(&mv64x60_wdt_miscdev);
}
@@ -204,9 +289,10 @@ static int __devexit mv64x60_wdt_remove(struct platform_device *dev)
{
misc_deregister(&mv64x60_wdt_miscdev);
- mv64x60_wdt_service();
mv64x60_wdt_handler_disable();
+ iounmap(mv64x60_wdt_regs);
+
return 0;
}
@@ -219,40 +305,16 @@ static struct platform_driver mv64x60_wdt_driver = {
},
};
-static struct platform_device *mv64x60_wdt_dev;
-
static int __init mv64x60_wdt_init(void)
{
- int ret;
-
printk(KERN_INFO "MV64x60 watchdog driver\n");
- mv64x60_wdt_dev = platform_device_alloc(MV64x60_WDT_NAME, -1);
- if (!mv64x60_wdt_dev) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = platform_device_add(mv64x60_wdt_dev);
- if (ret) {
- platform_device_put(mv64x60_wdt_dev);
- goto out;
- }
-
- ret = platform_driver_register(&mv64x60_wdt_driver);
- if (ret) {
- platform_device_unregister(mv64x60_wdt_dev);
- goto out;
- }
-
- out:
- return ret;
+ return platform_driver_register(&mv64x60_wdt_driver);
}
static void __exit mv64x60_wdt_exit(void)
{
platform_driver_unregister(&mv64x60_wdt_driver);
- platform_device_unregister(mv64x60_wdt_dev);
}
module_init(mv64x60_wdt_init);
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index b36fa8de2131..719b066f73c4 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -142,7 +142,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
omap_wdt_set_timeout();
omap_wdt_enable();
- return 0;
+ return nonseekable_open(inode, file);
}
static int omap_wdt_release(struct inode *inode, struct file *file)
@@ -197,7 +197,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident));
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 1e7a6719d5ba..0f3fd6c9c354 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -626,12 +626,11 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
/* allocate memory for our device and initialize it */
- usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+ usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
if (usb_pcwd == NULL) {
printk(KERN_ERR PFX "Out of memory\n");
goto error;
}
- memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
usb_pcwd_device = usb_pcwd;
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 50430bced2f2..5d1c15f83d23 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -52,10 +52,10 @@
#include <asm/arch/map.h>
-#undef S3C24XX_VA_WATCHDOG
-#define S3C24XX_VA_WATCHDOG (0)
+#undef S3C_VA_WATCHDOG
+#define S3C_VA_WATCHDOG (0)
-#include <asm/arch/regs-watchdog.h>
+#include <asm/plat-s3c/regs-watchdog.h>
#define PFX "s3c2410-wdt: "
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
index 33c1137f17d6..3475f47aaa45 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -45,7 +45,6 @@ static int boot_status;
*/
static int sa1100dog_open(struct inode *inode, struct file *file)
{
- nonseekable_open(inode, file);
if (test_and_set_bit(1,&sa1100wdt_users))
return -EBUSY;
@@ -54,7 +53,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
OSSR = OSSR_M3;
OWER = OWER_WME;
OIER |= OIER_E3;
- return 0;
+ return nonseekable_open(inode, file);
}
/*
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index b6282039198c..e4f3cb6090bc 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -191,8 +191,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
static int fop_open(struct inode * inode, struct file * file)
{
- nonseekable_open(inode, file);
-
/* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
@@ -202,7 +200,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */
wdt_startup();
- return 0;
+ return nonseekable_open(inode, file);
}
static int fop_close(struct inode * inode, struct file * file)
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 2f7ba7a514fe..9670d47190d0 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -150,8 +150,6 @@ static inline int sc1200wdt_status(void)
static int sc1200wdt_open(struct inode *inode, struct file *file)
{
- nonseekable_open(inode, file);
-
/* allow one at a time */
if (down_trylock(&open_sem))
return -EBUSY;
@@ -162,7 +160,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file)
sc1200wdt_start();
printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
- return 0;
+ return nonseekable_open(inode, file);
}
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 2676a43895a7..e8594c64d1e6 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -248,8 +248,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
static int fop_open(struct inode * inode, struct file * file)
{
- nonseekable_open(inode, file);
-
/* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
@@ -258,7 +256,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */
wdt_startup();
- return 0;
+ return nonseekable_open(inode, file);
}
static int fop_close(struct inode * inode, struct file * file)
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index b46e7f47d705..df33b3b5a53c 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -4,7 +4,7 @@
* (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
* added support for W83627THF.
*
- * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ * (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
*
* Based on advantechwdt.c which is based on wdt.c.
* Original copyright messages:
@@ -42,7 +42,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#define WATCHDOG_NAME "w83627hf/thf WDT"
+#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
@@ -78,9 +78,9 @@ w83627hf_select_wd_register(void)
outb_p(0x87, WDT_EFER); /* Enter extended function mode */
outb_p(0x87, WDT_EFER); /* Again according to manual */
- outb(0x20, WDT_EFER); /* check chip version */
+ outb(0x20, WDT_EFER); /* check chip version */
c = inb(WDT_EFDR);
- if (c == 0x82) { /* W83627THF */
+ if (c == 0x82) { /* W83627THF */
outb_p(0x2b, WDT_EFER); /* select GPIO3 */
c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
outb_p(0x2b, WDT_EFER);
@@ -114,11 +114,17 @@ w83627hf_init(void)
printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
}
+
outb_p(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */
+ outb_p(0xF7, WDT_EFER); /* Select CRF7 */
+ t=inb_p(WDT_EFDR); /* read CRF7 */
+ t&=~0xC0; /* disable keyboard & mouse turning off watchdog */
+ outb_p(t, WDT_EFDR); /* Write back to CRF7 */
+
w83627hf_unselect_wd_register();
}
@@ -126,7 +132,7 @@ static void
wdt_ctrl(int timeout)
{
spin_lock(&io_lock);
-
+
w83627hf_select_wd_register();
outb_p(0xF6, WDT_EFER); /* Select CRF6 */
@@ -154,7 +160,7 @@ wdt_disable(void)
static int
wdt_set_heartbeat(int t)
{
- if ((t < 1) || (t > 63))
+ if ((t < 1) || (t > 255))
return -EINVAL;
timeout = t;
@@ -324,11 +330,11 @@ wdt_init(void)
spin_lock_init(&io_lock);
- printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n");
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n",
+ printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
WATCHDOG_TIMEOUT);
}
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index e783dbf0f162..7b46faf22318 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -71,7 +71,7 @@ static struct clocksource clocksource_acpi_pm = {
.rating = 200,
.read = acpi_pm_read,
.mask = (cycle_t)ACPI_PM_MASK,
- .mult = 0, /*to be caluclated*/
+ .mult = 0, /*to be calculated*/
.shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a7b9e9bb3e8d..0e328d387af4 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -235,18 +235,6 @@ out:
}
/*
- * Netlink socket input callback - dequeues the skbs and calls the
- * main netlink receiving function.
- */
-static void cn_input(struct sock *sk, int len)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
- cn_rx_skb(skb);
-}
-
-/*
* Notification routing.
*
* Gets id and checks if there are notification request for it's idx
@@ -442,11 +430,11 @@ static int __devinit cn_init(void)
struct cn_dev *dev = &cdev;
int err;
- dev->input = cn_input;
+ dev->input = cn_rx_skb;
dev->id.idx = cn_idx;
dev->id.val = cn_val;
- dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,
+ dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR,
CN_NETLINK_USERS + 0xf,
dev->input, NULL, THIS_MODULE);
if (!dev->nls)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 993fa7b89253..721f86f4f008 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS
If in doubt, say N.
-# Note that it is not currently possible to set the other governors (such as ondemand)
-# as the default, since if they fail to initialise, cpufreq will be
-# left in an undefined state.
-
choice
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
program shall be able to set the CPU dynamically without having
to enable the userspace governor manually.
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+ bool "ondemand"
+ select CPU_FREQ_GOV_ONDEMAND
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'ondemand' as default. This allows
+ you to get a full dynamic frequency capable system by simply
+ loading your cpufreq low-level hardware driver.
+ Be aware that not all cpufreq drivers support the ondemand
+ governor. If unsure have a look at the help section of the
+ driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+ bool "conservative"
+ select CPU_FREQ_GOV_CONSERVATIVE
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'conservative' as default. This allows
+ you to get a full dynamic frequency capable system by simply
+ loading your cpufreq low-level hardware driver.
+ Be aware that not all cpufreq drivers support the conservative
+ governor. If unsure have a look at the help section of the
+ driver. Fallback governor will be the performance governor.
endchoice
config CPU_FREQ_GOV_PERFORMANCE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2f6a73c01b71..5e626b12b97e 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
+ /* Set governor before ->init, so that driver could check it */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
@@ -828,7 +830,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* prepare interface data */
policy->kobj.parent = &sys_dev->kobj;
policy->kobj.ktype = &ktype_cpufreq;
- strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
+ kobject_set_name(&policy->kobj, "cpufreq");
ret = kobject_register(&policy->kobj);
if (ret) {
@@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
unsigned int ret_freq = 0;
if (policy) {
- if (unlikely(lock_policy_rwsem_read(cpu)))
- return ret_freq;
-
ret_freq = policy->cur;
-
- unlock_policy_rwsem_read(cpu);
cpufreq_cpu_put(policy);
}
@@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
{
int ret;
+ /* Only must be defined when default governor is known to have latency
+ restrictions, like e.g. conservative or ondemand.
+ That this is the case is already ensured in Kconfig
+ */
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+ struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+ struct cpufreq_governor *gov = NULL;
+#endif
+
+ if (policy->governor->max_transition_latency &&
+ policy->cpuinfo.transition_latency >
+ policy->governor->max_transition_latency) {
+ if (!gov)
+ return -EINVAL;
+ else {
+ printk(KERN_WARNING "%s governor failed, too long"
+ " transition latency of HW, fallback"
+ " to %s governor\n",
+ policy->governor->name,
+ gov->name);
+ policy->governor = gov;
+ }
+ }
+
if (!try_module_get(policy->governor->owner))
return -EINVAL;
@@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_update_policy);
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 26f440ccc3fb..4bd33ce8a6f3 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -58,7 +58,7 @@ static unsigned int def_sampling_rate;
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
(!policy->cur))
return -EINVAL;
- if (policy->cpuinfo.transition_latency >
- (TRANSITION_LATENCY_LIMIT * 1000))
- return -EINVAL;
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "conservative",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+ .name = "conservative",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
};
+EXPORT_SYMBOL(cpufreq_gov_conservative);
static int __init cpufreq_gov_dbs_init(void)
{
- return cpufreq_register_governor(&cpufreq_gov_dbs);
+ return cpufreq_register_governor(&cpufreq_gov_conservative);
}
static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
/* Make sure that the scheduled work is indeed not running */
flush_scheduled_work();
- cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ cpufreq_unregister_governor(&cpufreq_gov_conservative);
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e794527e4925..369f44595150 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -47,7 +47,7 @@ static unsigned int def_sampling_rate;
(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if ((!cpu_online(cpu)) || (!policy->cur))
return -EINVAL;
- if (policy->cpuinfo.transition_latency >
- (TRANSITION_LATENCY_LIMIT * 1000)) {
- printk(KERN_WARNING "ondemand governor failed to load "
- "due to too long transition latency\n");
- return -EINVAL;
- }
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
};
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
static int __init cpufreq_gov_dbs_init(void)
{
@@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void)
printk(KERN_ERR "Creation of kondemand failed\n");
return -EFAULT;
}
- return cpufreq_register_governor(&cpufreq_gov_dbs);
+ return cpufreq_register_governor(&cpufreq_gov_ondemand);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ cpufreq_unregister_governor(&cpufreq_gov_ondemand);
destroy_workqueue(kondemand_wq);
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 917b9bab9ccb..8a45d0f93e26 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1;
}
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
return 0;
}
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
{
.notifier_call = cpufreq_stat_cpu_callback,
};
@@ -356,8 +356,7 @@ __init cpufreq_stats_init(void)
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
- CPU_ONLINE, (void *)(long)cpu);
+ cpufreq_update_policy(cpu);
}
return 0;
}
@@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void)
CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
- CPU_DEAD, (void *)(long)cpu);
+ cpufreq_stats_free_table(cpu);
}
}
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
"through sysfs filesystem");
MODULE_LICENSE ("GPL");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 84ebfcc1ffb4..5fd6688a444a 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -2,6 +2,11 @@
menuconfig CRYPTO_HW
bool "Hardware crypto devices"
default y
+ ---help---
+ Say Y here to get to see options for hardware crypto devices and
+ processors. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if CRYPTO_HW
@@ -9,7 +14,6 @@ config CRYPTO_DEV_PADLOCK
tristate "Support for VIA PadLock ACE"
depends on X86_32
select CRYPTO_ALGAPI
- default m
help
Some VIA processors come with an integrated crypto engine
(so called VIA PadLock ACE, Advanced Cryptography Engine)
@@ -23,7 +27,6 @@ config CRYPTO_DEV_PADLOCK_AES
tristate "PadLock driver for AES algorithm"
depends on CRYPTO_DEV_PADLOCK
select CRYPTO_BLKCIPHER
- default m
help
Use VIA PadLock for AES algorithm.
@@ -37,7 +40,6 @@ config CRYPTO_DEV_PADLOCK_SHA
depends on CRYPTO_DEV_PADLOCK
select CRYPTO_SHA1
select CRYPTO_SHA256
- default m
help
Use VIA PadLock for SHA1/SHA256 algorithms.
@@ -53,7 +55,6 @@ config CRYPTO_DEV_GEODE
depends on X86_32 && PCI
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
- default m
help
Say 'Y' here to use the AMD Geode LX processor on-board AES
engine for the CryptoAPI AES algorithm.
@@ -65,7 +66,6 @@ config ZCRYPT
tristate "Support for PCI-attached cryptographic adapters"
depends on S390
select ZCRYPT_MONOLITHIC if ZCRYPT="y"
- default "m"
help
Select this option if you want to use a PCI-attached cryptographic
adapter like:
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 6a86958b577f..f9a34abbf4fa 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -473,6 +473,7 @@ geode_aes_exit(void)
MODULE_AUTHOR("Advanced Micro Devices, Inc.");
MODULE_DESCRIPTION("Geode LX Hardware AES driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("aes");
module_init(geode_aes_init);
module_exit(geode_aes_exit);
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index d4501dc7e650..abbcff0762b1 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2004 Michal Ludvig <michal@logix.cz>
*
- * Key expansion routine taken from crypto/aes.c
+ * Key expansion routine taken from crypto/aes_generic.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -660,4 +660,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Ludvig");
-MODULE_ALIAS("aes-padlock");
+MODULE_ALIAS("aes");
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index a781fd23b607..4e8de162fc12 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -13,6 +13,7 @@
*/
#include <crypto/algapi.h>
+#include <crypto/sha.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -24,12 +25,7 @@
#include "padlock.h"
#define SHA1_DEFAULT_FALLBACK "sha1-generic"
-#define SHA1_DIGEST_SIZE 20
-#define SHA1_HMAC_BLOCK_SIZE 64
-
#define SHA256_DEFAULT_FALLBACK "sha256-generic"
-#define SHA256_DIGEST_SIZE 32
-#define SHA256_HMAC_BLOCK_SIZE 64
struct padlock_sha_ctx {
char *data;
@@ -107,11 +103,11 @@ static void padlock_do_sha1(const char *in, char *out, int count)
char buf[128+16];
char *result = NEAREST_ALIGNED(buf);
- ((uint32_t *)result)[0] = 0x67452301;
- ((uint32_t *)result)[1] = 0xEFCDAB89;
- ((uint32_t *)result)[2] = 0x98BADCFE;
- ((uint32_t *)result)[3] = 0x10325476;
- ((uint32_t *)result)[4] = 0xC3D2E1F0;
+ ((uint32_t *)result)[0] = SHA1_H0;
+ ((uint32_t *)result)[1] = SHA1_H1;
+ ((uint32_t *)result)[2] = SHA1_H2;
+ ((uint32_t *)result)[3] = SHA1_H3;
+ ((uint32_t *)result)[4] = SHA1_H4;
asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
: "+S"(in), "+D"(result)
@@ -128,14 +124,14 @@ static void padlock_do_sha256(const char *in, char *out, int count)
char buf[128+16];
char *result = NEAREST_ALIGNED(buf);
- ((uint32_t *)result)[0] = 0x6A09E667;
- ((uint32_t *)result)[1] = 0xBB67AE85;
- ((uint32_t *)result)[2] = 0x3C6EF372;
- ((uint32_t *)result)[3] = 0xA54FF53A;
- ((uint32_t *)result)[4] = 0x510E527F;
- ((uint32_t *)result)[5] = 0x9B05688C;
- ((uint32_t *)result)[6] = 0x1F83D9AB;
- ((uint32_t *)result)[7] = 0x5BE0CD19;
+ ((uint32_t *)result)[0] = SHA256_H0;
+ ((uint32_t *)result)[1] = SHA256_H1;
+ ((uint32_t *)result)[2] = SHA256_H2;
+ ((uint32_t *)result)[3] = SHA256_H3;
+ ((uint32_t *)result)[4] = SHA256_H4;
+ ((uint32_t *)result)[5] = SHA256_H5;
+ ((uint32_t *)result)[6] = SHA256_H6;
+ ((uint32_t *)result)[7] = SHA256_H7;
asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
: "+S"(in), "+D"(result)
@@ -215,7 +211,7 @@ static struct crypto_alg sha1_alg = {
.cra_priority = PADLOCK_CRA_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_DIGEST |
CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct padlock_sha_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(sha1_alg.cra_list),
@@ -237,7 +233,7 @@ static struct crypto_alg sha256_alg = {
.cra_priority = PADLOCK_CRA_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_DIGEST |
CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA256_HMAC_BLOCK_SIZE,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct padlock_sha_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(sha256_alg.cra_list),
@@ -253,19 +249,6 @@ static struct crypto_alg sha256_alg = {
}
};
-static void __init padlock_sha_check_fallbacks(void)
-{
- if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK))
- printk(KERN_WARNING PFX
- "Couldn't load fallback module for sha1.\n");
-
- if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK))
- printk(KERN_WARNING PFX
- "Couldn't load fallback module for sha256.\n");
-}
-
static int __init padlock_init(void)
{
int rc = -ENODEV;
@@ -280,8 +263,6 @@ static int __init padlock_init(void)
return -ENODEV;
}
- padlock_sha_check_fallbacks();
-
rc = crypto_register_alg(&sha1_alg);
if (rc)
goto out;
@@ -314,5 +295,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Ludvig");
+MODULE_ALIAS("sha1");
+MODULE_ALIAS("sha256");
MODULE_ALIAS("sha1-padlock");
MODULE_ALIAS("sha256-padlock");
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 5fbe56b5cea0..41b18c5a3141 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -191,17 +191,12 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
int i;
LIST_HEAD(tmp_list);
- /*
- * In-use bit automatically set by reading chanctrl
- * If 0, we got it, if 1, someone else did
- */
- chanctrl = readw(ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
- if (chanctrl & IOAT_CHANCTRL_CHANNEL_IN_USE)
- return -EBUSY;
+ /* have we already been set up? */
+ if (!list_empty(&ioat_chan->free_desc))
+ return INITIAL_IOAT_DESC_COUNT;
/* Setup register to interrupt and write completion status on error */
- chanctrl = IOAT_CHANCTRL_CHANNEL_IN_USE |
- IOAT_CHANCTRL_ERR_INT_EN |
+ chanctrl = IOAT_CHANCTRL_ERR_INT_EN |
IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
IOAT_CHANCTRL_ERR_COMPLETION_EN;
writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
@@ -282,11 +277,6 @@ static void ioat_dma_free_chan_resources(struct dma_chan *chan)
in_use_descs - 1);
ioat_chan->last_completion = ioat_chan->completion_addr = 0;
-
- /* Tell hw the chan is free */
- chanctrl = readw(ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
- chanctrl &= ~IOAT_CHANCTRL_CHANNEL_IN_USE;
- writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
}
static struct dma_async_tx_descriptor *
@@ -347,8 +337,7 @@ ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en)
new->async_tx.ack = 0; /* client is in control of this ack */
new->async_tx.cookie = -EBUSY;
- pci_unmap_len_set(new, src_len, orig_len);
- pci_unmap_len_set(new, dst_len, orig_len);
+ pci_unmap_len_set(new, len, orig_len);
spin_unlock_bh(&ioat_chan->desc_lock);
return new ? &new->async_tx : NULL;
@@ -423,11 +412,11 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
*/
pci_unmap_page(chan->device->pdev,
pci_unmap_addr(desc, dst),
- pci_unmap_len(desc, dst_len),
+ pci_unmap_len(desc, len),
PCI_DMA_FROMDEVICE);
pci_unmap_page(chan->device->pdev,
pci_unmap_addr(desc, src),
- pci_unmap_len(desc, src_len),
+ pci_unmap_len(desc, len),
PCI_DMA_TODEVICE);
}
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
index d3726478031a..bf4dad70e0f5 100644
--- a/drivers/dma/ioatdma.h
+++ b/drivers/dma/ioatdma.h
@@ -111,10 +111,9 @@ struct ioat_desc_sw {
struct ioat_dma_descriptor *hw;
struct list_head node;
int tx_cnt;
+ DECLARE_PCI_UNMAP_LEN(len)
DECLARE_PCI_UNMAP_ADDR(src)
- DECLARE_PCI_UNMAP_LEN(src_len)
DECLARE_PCI_UNMAP_ADDR(dst)
- DECLARE_PCI_UNMAP_LEN(dst_len)
struct dma_async_tx_descriptor async_tx;
};
diff --git a/drivers/dma/iovlock.c b/drivers/dma/iovlock.c
index d637555a833b..e763d723e4cf 100644
--- a/drivers/dma/iovlock.c
+++ b/drivers/dma/iovlock.c
@@ -143,29 +143,6 @@ void dma_unpin_iovec_pages(struct dma_pinned_list *pinned_list)
kfree(pinned_list);
}
-static dma_cookie_t dma_memcpy_to_kernel_iovec(struct dma_chan *chan, struct
- iovec *iov, unsigned char *kdata, size_t len)
-{
- dma_cookie_t dma_cookie = 0;
-
- while (len > 0) {
- if (iov->iov_len) {
- int copy = min_t(unsigned int, iov->iov_len, len);
- dma_cookie = dma_async_memcpy_buf_to_buf(
- chan,
- iov->iov_base,
- kdata,
- copy);
- kdata += copy;
- len -= copy;
- iov->iov_len -= copy;
- iov->iov_base += copy;
- }
- iov++;
- }
-
- return dma_cookie;
-}
/*
* We have already pinned down the pages we will be using in the iovecs.
@@ -187,10 +164,6 @@ dma_cookie_t dma_memcpy_to_iovec(struct dma_chan *chan, struct iovec *iov,
if (!chan)
return memcpy_toiovec(iov, kdata, len);
- /* -> kernel copies (e.g. smbfs) */
- if (!pinned_list)
- return dma_memcpy_to_kernel_iovec(chan, iov, kdata, len);
-
iovec_idx = 0;
while (iovec_idx < pinned_list->nr_iovecs) {
struct dma_page_list *page_list;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index debf1d8e8b41..98b6b4fb4257 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -3,18 +3,18 @@
# Copyright (c) 2003 Linux Networx
# Licensed and distributed under the GPL
#
-# $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $
-#
menuconfig EDAC
- tristate "EDAC - error detection and reporting (EXPERIMENTAL)"
+ bool "EDAC - error detection and reporting (EXPERIMENTAL)"
depends on HAS_IOMEM
- depends on X86 && EXPERIMENTAL
+ depends on EXPERIMENTAL
+ depends on X86 || PPC
help
EDAC is designed to report errors in the core system.
These are low-level errors that are reported in the CPU or
- supporting chipset: memory errors, cache errors, PCI errors,
- thermal throttling, etc.. If unsure, select 'Y'.
+ supporting chipset or other subsystems:
+ memory errors, cache errors, PCI errors, thermal throttling, etc..
+ If unsure, select 'Y'.
If this code is reporting problems on your system, please
see the EDAC project web pages for more information at:
@@ -73,6 +73,14 @@ config EDAC_E752X
Support for error detection and correction on the Intel
E7520, E7525, E7320 server chipsets.
+config EDAC_I82443BXGX
+ tristate "Intel 82443BX/GX (440BX/GX)"
+ depends on EDAC_MM_EDAC && PCI && X86_32
+ depends on BROKEN
+ help
+ Support for error detection and correction on the Intel
+ 82443BX/GX memory controllers (440BX/GX chipsets).
+
config EDAC_I82875P
tristate "Intel 82875p (D82875P, E7210)"
depends on EDAC_MM_EDAC && PCI && X86_32
@@ -80,6 +88,20 @@ config EDAC_I82875P
Support for error detection and correction on the Intel
DP82785P and E7210 server chipsets.
+config EDAC_I82975X
+ tristate "Intel 82975x (D82975x)"
+ depends on EDAC_MM_EDAC && PCI && X86
+ help
+ Support for error detection and correction on the Intel
+ DP82975x server chipsets.
+
+config EDAC_I3000
+ tristate "Intel 3000/3010"
+ depends on EDAC_MM_EDAC && PCI && X86_32
+ help
+ Support for error detection and correction on the Intel
+ 3000 and 3010 server chipsets.
+
config EDAC_I82860
tristate "Intel 82860"
depends on EDAC_MM_EDAC && PCI && X86_32
@@ -94,15 +116,20 @@ config EDAC_R82600
Support for error detection and correction on the Radisys
82600 embedded chipset.
-choice
- prompt "Error detecting method"
- default EDAC_POLL
+config EDAC_I5000
+ tristate "Intel Greencreek/Blackford chipset"
+ depends on EDAC_MM_EDAC && X86 && PCI
+ help
+ Support for error detection and correction the Intel
+ Greekcreek/Blackford chipsets.
-config EDAC_POLL
- bool "Poll for errors"
+config EDAC_PASEMI
+ tristate "PA Semi PWRficient"
+ depends on EDAC_MM_EDAC && PCI
+ depends on PPC_PASEMI
help
- Poll the chipset periodically to detect errors.
+ Support for error detection and correction on PA Semi
+ PWRficient.
-endchoice
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 93137fdab4b3..02c09f0ff157 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -5,14 +5,27 @@
# This file may be distributed under the terms of the
# GNU General Public License.
#
-# $Id: Makefile,v 1.4.2.3 2005/07/08 22:05:38 dsp_llnl Exp $
-obj-$(CONFIG_EDAC_MM_EDAC) += edac_mc.o
+obj-$(CONFIG_EDAC) := edac_stub.o
+obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
+
+edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-objs += edac_module.o edac_device_sysfs.o
+
+ifdef CONFIG_PCI
+edac_core-objs += edac_pci.o edac_pci_sysfs.o
+endif
+
obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
+obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
+obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o
+obj-$(CONFIG_EDAC_I82975X) += i82975x_edac.o
+obj-$(CONFIG_EDAC_I3000) += i3000_edac.o
obj-$(CONFIG_EDAC_I82860) += i82860_edac.o
obj-$(CONFIG_EDAC_R82600) += r82600_edac.o
+obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index f79f6b587bfa..f22075410591 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -17,9 +17,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define AMD76X_REVISION " Ver: 2.0.1 " __DATE__
+#define AMD76X_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "amd76x_edac"
#define amd76x_printk(level, fmt, arg...) \
@@ -86,13 +86,13 @@ struct amd76x_dev_info {
static const struct amd76x_dev_info amd76x_devs[] = {
[AMD761] = {
- .ctl_name = "AMD761"
- },
+ .ctl_name = "AMD761"},
[AMD762] = {
- .ctl_name = "AMD762"
- },
+ .ctl_name = "AMD762"},
};
+static struct edac_pci_ctl_info *amd76x_pci;
+
/**
* amd76x_get_error_info - fetch error information
* @mci: Memory controller
@@ -102,21 +102,21 @@ static const struct amd76x_dev_info amd76x_devs[] = {
* on the chip so that further errors will be reported
*/
static void amd76x_get_error_info(struct mem_ctl_info *mci,
- struct amd76x_error_info *info)
+ struct amd76x_error_info *info)
{
struct pci_dev *pdev;
pdev = to_pci_dev(mci->dev);
pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
- &info->ecc_mode_status);
+ &info->ecc_mode_status);
if (info->ecc_mode_status & BIT(8))
pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
- (u32) BIT(8), (u32) BIT(8));
+ (u32) BIT(8), (u32) BIT(8));
if (info->ecc_mode_status & BIT(9))
pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
- (u32) BIT(9), (u32) BIT(9));
+ (u32) BIT(9), (u32) BIT(9));
}
/**
@@ -130,7 +130,8 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci,
* then attempt to handle and clean up after the error
*/
static int amd76x_process_error_info(struct mem_ctl_info *mci,
- struct amd76x_error_info *info, int handle_errors)
+ struct amd76x_error_info *info,
+ int handle_errors)
{
int error_found;
u32 row;
@@ -138,7 +139,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
error_found = 0;
/*
- * Check for an uncorrectable error
+ * Check for an uncorrectable error
*/
if (info->ecc_mode_status & BIT(8)) {
error_found = 1;
@@ -146,12 +147,12 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
if (handle_errors) {
row = (info->ecc_mode_status >> 4) & 0xf;
edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0,
- row, mci->ctl_name);
+ row, mci->ctl_name);
}
}
/*
- * Check for a correctable error
+ * Check for a correctable error
*/
if (info->ecc_mode_status & BIT(9)) {
error_found = 1;
@@ -159,7 +160,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
if (handle_errors) {
row = info->ecc_mode_status & 0xf;
edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0,
- 0, row, 0, mci->ctl_name);
+ 0, row, 0, mci->ctl_name);
}
}
@@ -182,7 +183,7 @@ static void amd76x_check(struct mem_ctl_info *mci)
}
static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- enum edac_type edac_mode)
+ enum edac_type edac_mode)
{
struct csrow_info *csrow;
u32 mba, mba_base, mba_mask, dms;
@@ -193,8 +194,7 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
/* find the DRAM Chip Select Base address and mask */
pci_read_config_dword(pdev,
- AMD76X_MEM_BASE_ADDR + (index * 4),
- &mba);
+ AMD76X_MEM_BASE_ADDR + (index * 4), &mba);
if (!(mba & BIT(0)))
continue;
@@ -238,7 +238,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
debugf0("%s()\n", __func__);
pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
ems_mode = (ems >> 10) & 0x3;
- mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
+ mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0);
if (mci == NULL) {
return -ENOMEM;
@@ -249,24 +249,36 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
mci->mtype_cap = MEM_FLAG_RDDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
mci->edac_cap = ems_mode ?
- (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
+ (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = AMD76X_REVISION;
mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = amd76x_check;
mci->ctl_page_to_phys = NULL;
amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]);
- amd76x_get_error_info(mci, &discard); /* clear counters */
+ amd76x_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
+ /* allocating generic PCI control info */
+ amd76x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!amd76x_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
@@ -278,7 +290,7 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit amd76x_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
@@ -300,6 +312,9 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (amd76x_pci)
+ edac_pci_release_generic_ctl(amd76x_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
@@ -308,16 +323,14 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- AMD762
- },
+ PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ AMD762},
{
- PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- AMD761
- },
+ PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ AMD761},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 8bcc887692ab..6eb434749cd5 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -22,13 +22,16 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
-#define E752X_REVISION " Ver: 2.0.1 " __DATE__
+#define E752X_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "e752x_edac"
static int force_function_unhide;
+static struct edac_pci_ctl_info *e752x_pci;
+
#define e752x_printk(level, fmt, arg...) \
edac_printk(level, "e752x", fmt, ##arg)
@@ -203,25 +206,22 @@ static const struct e752x_dev_info e752x_devs[] = {
[E7520] = {
.err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
- .ctl_name = "E7520"
- },
+ .ctl_name = "E7520"},
[E7525] = {
.err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
- .ctl_name = "E7525"
- },
+ .ctl_name = "E7525"},
[E7320] = {
.err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
- .ctl_name = "E7320"
- },
+ .ctl_name = "E7320"},
};
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
- unsigned long page)
+ unsigned long page)
{
u32 remap;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
@@ -241,13 +241,13 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
}
static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
- u32 sec1_add, u16 sec1_syndrome)
+ u32 sec1_add, u16 sec1_syndrome)
{
u32 page;
int row;
int channel;
int i;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
@@ -261,7 +261,8 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
e752x_printk(KERN_WARNING,
"Test row %d Table %d %d %d %d %d %d %d %d\n", row,
pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
- pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]);
+ pvt->map[4], pvt->map[5], pvt->map[6],
+ pvt->map[7]);
/* test for channel remapping */
for (i = 0; i < 8; i++) {
@@ -275,24 +276,22 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
row = i;
else
e752x_mc_printk(mci, KERN_WARNING,
- "row %d not found in remap table\n", row);
+ "row %d not found in remap table\n",
+ row);
} else
row = edac_mc_find_csrow_by_page(mci, page);
/* 0 = channel A, 1 = channel B */
channel = !(error_one & 1);
- if (!pvt->map_type)
- row = 7 - row;
-
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
sec1_syndrome, row, channel, "e752x CE");
}
static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
- u32 sec1_add, u16 sec1_syndrome, int *error_found,
- int handle_error)
+ u32 sec1_add, u16 sec1_syndrome, int *error_found,
+ int handle_error)
{
*error_found = 1;
@@ -301,11 +300,11 @@ static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
}
static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
- u32 ded_add, u32 scrb_add)
+ u32 ded_add, u32 scrb_add)
{
u32 error_2b, block_page;
int row;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
@@ -316,14 +315,14 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
block_page = error_2b >> (PAGE_SHIFT - 4);
row = pvt->mc_symmetric ?
- /* chip select are bits 14 & 13 */
+ /* chip select are bits 14 & 13 */
((block_page >> 1) & 3) :
edac_mc_find_csrow_by_page(mci, block_page);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ue(mci, block_page,
- offset_in_page(error_2b << 4),
- row, "e752x UE from Read");
+ offset_in_page(error_2b << 4),
+ row, "e752x UE from Read");
}
if (error_one & 0x0404) {
error_2b = scrb_add;
@@ -332,19 +331,20 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
block_page = error_2b >> (PAGE_SHIFT - 4);
row = pvt->mc_symmetric ?
- /* chip select are bits 14 & 13 */
+ /* chip select are bits 14 & 13 */
((block_page >> 1) & 3) :
edac_mc_find_csrow_by_page(mci, block_page);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ue(mci, block_page,
- offset_in_page(error_2b << 4),
- row, "e752x UE from Scruber");
+ offset_in_page(error_2b << 4),
+ row, "e752x UE from Scruber");
}
}
static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
- u32 ded_add, u32 scrb_add, int *error_found, int handle_error)
+ u32 ded_add, u32 scrb_add, int *error_found,
+ int handle_error)
{
*error_found = 1;
@@ -353,7 +353,7 @@ static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
}
static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
*error_found = 1;
@@ -365,24 +365,24 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
}
static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
- u32 retry_add)
+ u32 retry_add)
{
u32 error_1b, page;
int row;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
error_1b = retry_add;
- page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
- row = pvt->mc_symmetric ?
- ((page >> 1) & 3) : /* chip select are bits 14 & 13 */
+ page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
+ row = pvt->mc_symmetric ? ((page >> 1) & 3) : /* chip select are bits 14 & 13 */
edac_mc_find_csrow_by_page(mci, page);
e752x_mc_printk(mci, KERN_WARNING,
- "CE page 0x%lx, row %d : Memory read retry\n",
- (long unsigned int) page, row);
+ "CE page 0x%lx, row %d : Memory read retry\n",
+ (long unsigned int)page, row);
}
static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
- u32 retry_add, int *error_found, int handle_error)
+ u32 retry_add, int *error_found,
+ int handle_error)
{
*error_found = 1;
@@ -391,7 +391,7 @@ static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
}
static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
*error_found = 1;
@@ -420,7 +420,7 @@ static void do_global_error(int fatal, u32 errors)
}
static inline void global_error(int fatal, u32 errors, int *error_found,
- int handle_error)
+ int handle_error)
{
*error_found = 1;
@@ -447,7 +447,7 @@ static void do_hub_error(int fatal, u8 errors)
}
static inline void hub_error(int fatal, u8 errors, int *error_found,
- int handle_error)
+ int handle_error)
{
*error_found = 1;
@@ -505,7 +505,7 @@ static void do_sysbus_error(int fatal, u32 errors)
}
static inline void sysbus_error(int fatal, u32 errors, int *error_found,
- int handle_error)
+ int handle_error)
{
*error_found = 1;
@@ -514,7 +514,7 @@ static inline void sysbus_error(int fatal, u32 errors, int *error_found,
}
static void e752x_check_hub_interface(struct e752x_error_info *info,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
u8 stat8;
@@ -522,33 +522,32 @@ static void e752x_check_hub_interface(struct e752x_error_info *info,
stat8 = info->hi_ferr;
- if(stat8 & 0x7f) { /* Error, so process */
+ if (stat8 & 0x7f) { /* Error, so process */
stat8 &= 0x7f;
- if(stat8 & 0x2b)
+ if (stat8 & 0x2b)
hub_error(1, stat8 & 0x2b, error_found, handle_error);
- if(stat8 & 0x54)
+ if (stat8 & 0x54)
hub_error(0, stat8 & 0x54, error_found, handle_error);
}
-
//pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
stat8 = info->hi_nerr;
- if(stat8 & 0x7f) { /* Error, so process */
+ if (stat8 & 0x7f) { /* Error, so process */
stat8 &= 0x7f;
if (stat8 & 0x2b)
hub_error(1, stat8 & 0x2b, error_found, handle_error);
- if(stat8 & 0x54)
+ if (stat8 & 0x54)
hub_error(0, stat8 & 0x54, error_found, handle_error);
}
}
static void e752x_check_sysbus(struct e752x_error_info *info,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
u32 stat32, error32;
@@ -556,47 +555,47 @@ static void e752x_check_sysbus(struct e752x_error_info *info,
stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
if (stat32 == 0)
- return; /* no errors */
+ return; /* no errors */
error32 = (stat32 >> 16) & 0x3ff;
stat32 = stat32 & 0x3ff;
- if(stat32 & 0x087)
+ if (stat32 & 0x087)
sysbus_error(1, stat32 & 0x087, error_found, handle_error);
- if(stat32 & 0x378)
+ if (stat32 & 0x378)
sysbus_error(0, stat32 & 0x378, error_found, handle_error);
- if(error32 & 0x087)
+ if (error32 & 0x087)
sysbus_error(1, error32 & 0x087, error_found, handle_error);
- if(error32 & 0x378)
+ if (error32 & 0x378)
sysbus_error(0, error32 & 0x378, error_found, handle_error);
}
-static void e752x_check_membuf (struct e752x_error_info *info,
- int *error_found, int handle_error)
+static void e752x_check_membuf(struct e752x_error_info *info,
+ int *error_found, int handle_error)
{
u8 stat8;
stat8 = info->buf_ferr;
- if (stat8 & 0x0f) { /* Error, so process */
+ if (stat8 & 0x0f) { /* Error, so process */
stat8 &= 0x0f;
membuf_error(stat8, error_found, handle_error);
}
stat8 = info->buf_nerr;
- if (stat8 & 0x0f) { /* Error, so process */
+ if (stat8 & 0x0f) { /* Error, so process */
stat8 &= 0x0f;
membuf_error(stat8, error_found, handle_error);
}
}
-static void e752x_check_dram (struct mem_ctl_info *mci,
- struct e752x_error_info *info, int *error_found,
- int handle_error)
+static void e752x_check_dram(struct mem_ctl_info *mci,
+ struct e752x_error_info *info, int *error_found,
+ int handle_error)
{
u16 error_one, error_next;
@@ -604,55 +603,52 @@ static void e752x_check_dram (struct mem_ctl_info *mci,
error_next = info->dram_nerr;
/* decode and report errors */
- if(error_one & 0x0101) /* check first error correctable */
+ if (error_one & 0x0101) /* check first error correctable */
process_ce(mci, error_one, info->dram_sec1_add,
- info->dram_sec1_syndrome, error_found,
- handle_error);
+ info->dram_sec1_syndrome, error_found, handle_error);
- if(error_next & 0x0101) /* check next error correctable */
+ if (error_next & 0x0101) /* check next error correctable */
process_ce(mci, error_next, info->dram_sec2_add,
- info->dram_sec2_syndrome, error_found,
- handle_error);
+ info->dram_sec2_syndrome, error_found, handle_error);
- if(error_one & 0x4040)
+ if (error_one & 0x4040)
process_ue_no_info_wr(mci, error_found, handle_error);
- if(error_next & 0x4040)
+ if (error_next & 0x4040)
process_ue_no_info_wr(mci, error_found, handle_error);
- if(error_one & 0x2020)
+ if (error_one & 0x2020)
process_ded_retry(mci, error_one, info->dram_retr_add,
- error_found, handle_error);
+ error_found, handle_error);
- if(error_next & 0x2020)
+ if (error_next & 0x2020)
process_ded_retry(mci, error_next, info->dram_retr_add,
- error_found, handle_error);
+ error_found, handle_error);
- if(error_one & 0x0808)
- process_threshold_ce(mci, error_one, error_found,
- handle_error);
+ if (error_one & 0x0808)
+ process_threshold_ce(mci, error_one, error_found, handle_error);
- if(error_next & 0x0808)
+ if (error_next & 0x0808)
process_threshold_ce(mci, error_next, error_found,
- handle_error);
+ handle_error);
- if(error_one & 0x0606)
+ if (error_one & 0x0606)
process_ue(mci, error_one, info->dram_ded_add,
- info->dram_scrb_add, error_found, handle_error);
+ info->dram_scrb_add, error_found, handle_error);
- if(error_next & 0x0606)
+ if (error_next & 0x0606)
process_ue(mci, error_next, info->dram_ded_add,
- info->dram_scrb_add, error_found, handle_error);
+ info->dram_scrb_add, error_found, handle_error);
}
-static void e752x_get_error_info (struct mem_ctl_info *mci,
- struct e752x_error_info *info)
+static void e752x_get_error_info(struct mem_ctl_info *mci,
+ struct e752x_error_info *info)
{
struct pci_dev *dev;
struct e752x_pvt *pvt;
memset(info, 0, sizeof(*info));
- pvt = (struct e752x_pvt *) mci->pvt_info;
+ pvt = (struct e752x_pvt *)mci->pvt_info;
dev = pvt->dev_d0f1;
pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
@@ -661,8 +657,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
pci_read_config_word(dev, E752X_SYSBUS_FERR,
&info->sysbus_ferr);
pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
- pci_read_config_word(dev, E752X_DRAM_FERR,
- &info->dram_ferr);
+ pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
&info->dram_sec1_add);
pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
@@ -688,7 +683,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
if (info->dram_ferr)
pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
- info->dram_ferr, info->dram_ferr);
+ info->dram_ferr, info->dram_ferr);
pci_write_config_dword(dev, E752X_FERR_GLOBAL,
info->ferr_global);
@@ -701,8 +696,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
pci_read_config_word(dev, E752X_SYSBUS_NERR,
&info->sysbus_nerr);
pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
- pci_read_config_word(dev, E752X_DRAM_NERR,
- &info->dram_nerr);
+ pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
&info->dram_sec2_add);
pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
@@ -722,15 +716,16 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
if (info->dram_nerr)
pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
- info->dram_nerr, info->dram_nerr);
+ info->dram_nerr, info->dram_nerr);
pci_write_config_dword(dev, E752X_NERR_GLOBAL,
info->nerr_global);
}
}
-static int e752x_process_error_info (struct mem_ctl_info *mci,
- struct e752x_error_info *info, int handle_errors)
+static int e752x_process_error_info(struct mem_ctl_info *mci,
+ struct e752x_error_info *info,
+ int handle_errors)
{
u32 error32, stat32;
int error_found;
@@ -776,26 +771,38 @@ static inline int dual_channel_active(u16 ddrcsr)
return (((ddrcsr >> 12) & 3) == 3);
}
+/* Remap csrow index numbers if map_type is "reverse"
+ */
+static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
+{
+ struct e752x_pvt *pvt = mci->pvt_info;
+
+ if (!pvt->map_type)
+ return (7 - index);
+
+ return (index);
+}
+
static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- u16 ddrcsr)
+ u16 ddrcsr)
{
struct csrow_info *csrow;
unsigned long last_cumul_size;
int index, mem_dev, drc_chan;
- int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
- int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
+ int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
+ int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
u8 value;
u32 dra, drc, cumul_size;
dra = 0;
- for (index=0; index < 4; index++) {
+ for (index = 0; index < 4; index++) {
u8 dra_reg;
- pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg);
+ pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
dra |= dra_reg << (index * 8);
}
pci_read_config_dword(pdev, E752X_DRC, &drc);
drc_chan = dual_channel_active(ddrcsr);
- drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
+ drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
drc_ddim = (drc >> 20) & 0x3;
/* The dram row boundary (DRB) reg values are boundary address for
@@ -806,7 +813,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
/* mem_dev 0=x8, 1=x4 */
mem_dev = (dra >> (index * 4 + 2)) & 0x3;
- csrow = &mci->csrows[index];
+ csrow = &mci->csrows[remap_csrow_index(mci, index)];
mem_dev = (mem_dev == 2);
pci_read_config_byte(pdev, E752X_DRB + index, &value);
@@ -843,10 +850,10 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
}
static void e752x_init_mem_map_table(struct pci_dev *pdev,
- struct e752x_pvt *pvt)
+ struct e752x_pvt *pvt)
{
int index;
- u8 value, last, row, stat8;
+ u8 value, last, row;
last = 0;
row = 0;
@@ -858,7 +865,7 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
/* no dimm in the slot, so flag it as empty */
pvt->map[index] = 0xff;
pvt->map[index + 1] = 0xff;
- } else { /* there is a dimm in the slot */
+ } else { /* there is a dimm in the slot */
pvt->map[index] = row;
row++;
last = value;
@@ -866,31 +873,25 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
* sided
*/
pci_read_config_byte(pdev, E752X_DRB + index + 1,
- &value);
- pvt->map[index + 1] = (value == last) ?
- 0xff : /* the dimm is single sided,
- so flag as empty */
- row; /* this is a double sided dimm
- to save the next row # */
+ &value);
+
+ /* the dimm is single sided, so flag as empty */
+ /* this is a double sided dimm to save the next row #*/
+ pvt->map[index + 1] = (value == last) ? 0xff : row;
row++;
last = value;
}
}
-
- /* set the map type. 1 = normal, 0 = reversed */
- pci_read_config_byte(pdev, E752X_DRM, &stat8);
- pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
}
/* Return 0 on success or 1 on failure. */
static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
- struct e752x_pvt *pvt)
+ struct e752x_pvt *pvt)
{
struct pci_dev *dev;
pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev,
- pvt->bridge_ck);
+ pvt->dev_info->err_dev, pvt->bridge_ck);
if (pvt->bridge_ck == NULL)
pvt->bridge_ck = pci_scan_single_device(pdev->bus,
@@ -898,13 +899,13 @@ static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
if (pvt->bridge_ck == NULL) {
e752x_printk(KERN_ERR, "error reporting device not found:"
- "vendor %x device 0x%x (broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
+ "vendor %x device 0x%x (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
return 1;
}
dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
- NULL);
+ NULL);
if (dev == NULL)
goto fail;
@@ -942,12 +943,22 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
struct mem_ctl_info *mci;
struct e752x_pvt *pvt;
u16 ddrcsr;
- int drc_chan; /* Number of channels 0=1chan,1=2chan */
+ int drc_chan; /* Number of channels 0=1chan,1=2chan */
struct e752x_error_info discard;
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
@@ -956,7 +967,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
if (!force_function_unhide && !(stat8 & (1 << 5))) {
printk(KERN_INFO "Contact your BIOS vendor to see if the "
"E752x error registers can be safely un-hidden\n");
- return -ENOMEM;
+ return -ENODEV;
}
stat8 |= (1 << 5);
pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
@@ -966,7 +977,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
/* Dual channel = 1, Single channel = 0 */
drc_chan = dual_channel_active(ddrcsr);
- mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1);
+ mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
if (mci == NULL) {
return -ENOMEM;
@@ -975,14 +986,14 @@ 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;
+ EDAC_FLAG_S4ECD4ED;
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = E752X_REVISION;
mci->dev = &pdev->dev;
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct e752x_pvt *) mci->pvt_info;
+ pvt = (struct e752x_pvt *)mci->pvt_info;
pvt->dev_info = &e752x_devs[dev_idx];
pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
@@ -993,16 +1004,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): more mci init\n", __func__);
mci->ctl_name = pvt->dev_info->ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = e752x_check;
mci->ctl_page_to_phys = ctl_page_to_phys;
- e752x_init_csrows(mci, pdev, ddrcsr);
- e752x_init_mem_map_table(pdev, pvt);
-
- /* set the map type. 1 = normal, 0 = reversed */
+ /* set the map type. 1 = normal, 0 = reversed
+ * Must be set before e752x_init_csrows in case csrow mapping
+ * is reversed.
+ */
pci_read_config_byte(pdev, E752X_DRM, &stat8);
pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
+ e752x_init_csrows(mci, pdev, ddrcsr);
+ e752x_init_mem_map_table(pdev, pvt);
+
mci->edac_cap |= EDAC_FLAG_NONE;
debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
@@ -1014,19 +1029,29 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
pvt->remaplimit = ((u32) pci_data) << 14;
e752x_printk(KERN_INFO,
- "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
- pvt->remapbase, pvt->remaplimit);
+ "tolm = %x, remapbase = %x, remaplimit = %x\n",
+ pvt->tolm, pvt->remapbase, pvt->remaplimit);
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
e752x_init_error_reporting_regs(pvt);
- e752x_get_error_info(mci, &discard); /* clear other MCH errors */
+ e752x_get_error_info(mci, &discard); /* clear other MCH errors */
+
+ /* allocating generic PCI control info */
+ e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!e752x_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n", __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
@@ -1043,12 +1068,12 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit e752x_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
/* wake up and enable device */
- if(pci_enable_device(pdev) < 0)
+ if (pci_enable_device(pdev) < 0)
return -EIO;
return e752x_probe1(pdev, ent->driver_data);
@@ -1061,10 +1086,13 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (e752x_pci)
+ edac_pci_release_generic_ctl(e752x_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
- pvt = (struct e752x_pvt *) mci->pvt_info;
+ pvt = (struct e752x_pvt *)mci->pvt_info;
pci_dev_put(pvt->dev_d0f0);
pci_dev_put(pvt->dev_d0f1);
pci_dev_put(pvt->bridge_ck);
@@ -1073,20 +1101,17 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7520
- },
+ PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7520},
{
- PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7525
- },
+ PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7525},
{
- PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7320
- },
+ PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7320},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
@@ -1122,5 +1147,6 @@ MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
module_param(force_function_unhide, int, 0444);
MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
-" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
-
+ " 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");
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 310d91b41c96..96ecc4926641 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -27,9 +27,10 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
-#define E7XXX_REVISION " Ver: 2.0.1 " __DATE__
+#define E7XXX_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "e7xxx_edac"
#define e7xxx_printk(level, fmt, arg...) \
@@ -143,23 +144,21 @@ struct e7xxx_error_info {
u32 dram_uelog_add;
};
+static struct edac_pci_ctl_info *e7xxx_pci;
+
static const struct e7xxx_dev_info e7xxx_devs[] = {
[E7500] = {
.err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
- .ctl_name = "E7500"
- },
+ .ctl_name = "E7500"},
[E7501] = {
.err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
- .ctl_name = "E7501"
- },
+ .ctl_name = "E7501"},
[E7505] = {
.err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
- .ctl_name = "E7505"
- },
+ .ctl_name = "E7505"},
[E7205] = {
.err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
- .ctl_name = "E7205"
- },
+ .ctl_name = "E7205"},
};
/* FIXME - is this valid for both SECDED and S4ECD4ED? */
@@ -180,15 +179,15 @@ static inline int e7xxx_find_channel(u16 syndrome)
}
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
- unsigned long page)
+ unsigned long page)
{
u32 remap;
- struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
if ((page < pvt->tolm) ||
- ((page >= 0x100000) && (page < pvt->remapbase)))
+ ((page >= 0x100000) && (page < pvt->remapbase)))
return page;
remap = (page - pvt->tolm) + pvt->remapbase;
@@ -200,8 +199,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
return pvt->tolm - 1;
}
-static void process_ce(struct mem_ctl_info *mci,
- struct e7xxx_error_info *info)
+static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
{
u32 error_1b, page;
u16 syndrome;
@@ -212,7 +210,7 @@ static void process_ce(struct mem_ctl_info *mci,
/* read the error address */
error_1b = info->dram_celog_add;
/* FIXME - should use PAGE_SHIFT */
- page = error_1b >> 6; /* convert the address to 4k page */
+ page = error_1b >> 6; /* convert the address to 4k page */
/* read the syndrome */
syndrome = info->dram_celog_syndrome;
/* FIXME - check for -1 */
@@ -228,8 +226,7 @@ static void process_ce_no_info(struct mem_ctl_info *mci)
edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
}
-static void process_ue(struct mem_ctl_info *mci,
- struct e7xxx_error_info *info)
+static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
{
u32 error_2b, block_page;
int row;
@@ -238,7 +235,7 @@ static void process_ue(struct mem_ctl_info *mci,
/* read the error address */
error_2b = info->dram_uelog_add;
/* FIXME - should use PAGE_SHIFT */
- block_page = error_2b >> 6; /* convert to 4k address */
+ block_page = error_2b >> 6; /* convert to 4k address */
row = edac_mc_find_csrow_by_page(mci, block_page);
edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
}
@@ -249,16 +246,14 @@ static void process_ue_no_info(struct mem_ctl_info *mci)
edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
}
-static void e7xxx_get_error_info (struct mem_ctl_info *mci,
- struct e7xxx_error_info *info)
+static void e7xxx_get_error_info(struct mem_ctl_info *mci,
+ struct e7xxx_error_info *info)
{
struct e7xxx_pvt *pvt;
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
- pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR,
- &info->dram_ferr);
- pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR,
- &info->dram_nerr);
+ pvt = (struct e7xxx_pvt *)mci->pvt_info;
+ pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, &info->dram_ferr);
+ pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, &info->dram_nerr);
if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {
pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,
@@ -279,8 +274,9 @@ static void e7xxx_get_error_info (struct mem_ctl_info *mci,
pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
}
-static int e7xxx_process_error_info (struct mem_ctl_info *mci,
- struct e7xxx_error_info *info, int handle_errors)
+static int e7xxx_process_error_info(struct mem_ctl_info *mci,
+ struct e7xxx_error_info *info,
+ int handle_errors)
{
int error_found;
@@ -341,7 +337,6 @@ static inline int dual_channel_active(u32 drc, int dev_idx)
return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1;
}
-
/* Return DRB granularity (0=32mb, 1=64mb). */
static inline int drb_granularity(u32 drc, int dev_idx)
{
@@ -349,9 +344,8 @@ static inline int drb_granularity(u32 drc, int dev_idx)
return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1;
}
-
static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- int dev_idx, u32 drc)
+ int dev_idx, u32 drc)
{
unsigned long last_cumul_size;
int index;
@@ -419,10 +413,21 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
struct e7xxx_error_info discard;
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);
- mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
+ mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0);
if (mci == NULL)
return -ENOMEM;
@@ -430,17 +435,16 @@ static int e7xxx_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;
+ EDAC_FLAG_S4ECD4ED;
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = E7XXX_REVISION;
mci->dev = &pdev->dev;
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ pvt = (struct e7xxx_pvt *)mci->pvt_info;
pvt->dev_info = &e7xxx_devs[dev_idx];
pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev,
- pvt->bridge_ck);
+ pvt->dev_info->err_dev, pvt->bridge_ck);
if (!pvt->bridge_ck) {
e7xxx_printk(KERN_ERR, "error reporting device not found:"
@@ -451,6 +455,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): more mci init\n", __func__);
mci->ctl_name = pvt->dev_info->ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = e7xxx_check;
mci->ctl_page_to_phys = ctl_page_to_phys;
e7xxx_init_csrows(mci, pdev, dev_idx, drc);
@@ -473,11 +478,22 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail1;
}
+ /* allocating generic PCI control info */
+ e7xxx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!e7xxx_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
@@ -493,7 +509,7 @@ fail0:
/* returns count (>= 0), or negative on error */
static int __devinit e7xxx_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
@@ -509,34 +525,33 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (e7xxx_pci)
+ edac_pci_release_generic_ctl(e7xxx_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ pvt = (struct e7xxx_pvt *)mci->pvt_info;
pci_dev_put(pvt->bridge_ck);
edac_mc_free(mci);
}
static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7205
- },
+ PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7205},
{
- PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7500
- },
+ PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7500},
{
- PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7501
- },
+ PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7501},
{
- PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7505
- },
+ PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7505},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
@@ -563,5 +578,7 @@ module_exit(e7xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
- "Based on.work by Dan Hollis et al");
+ "Based on.work by Dan Hollis et al");
MODULE_DESCRIPTION("MC support for Intel e7xxx 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/edac_mc.h b/drivers/edac/edac_core.h
index 713444cc4105..e80af67664cc 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_core.h
@@ -1,6 +1,7 @@
/*
- * MC kernel module
- * (C) 2003 Linux Networx (http://lnxi.com)
+ * Defines, structures, APIs for edac_core module
+ *
+ * (C) 2007 Linux Networx (http://lnxi.com)
* This file may be distributed under the terms of the
* GNU General Public License.
*
@@ -11,12 +12,13 @@
* NMI handling support added by
* Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
*
- * $Id: edac_mc.h,v 1.4.2.10 2005/10/05 00:43:44 dsp_llnl Exp $
+ * Refactored for multi-source files:
+ * Doug Thompson <norsk5@xmission.com>
*
*/
-#ifndef _EDAC_MC_H_
-#define _EDAC_MC_H_
+#ifndef _EDAC_CORE_H_
+#define _EDAC_CORE_H_
#include <linux/kernel.h>
#include <linux/types.h>
@@ -30,9 +32,14 @@
#include <linux/completion.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
#define EDAC_MC_LABEL_LEN 31
-#define MC_PROC_NAME_MAX_LEN 7
+#define EDAC_DEVICE_NAME_LEN 31
+#define EDAC_ATTRIB_VALUE_LEN 15
+#define MC_PROC_NAME_MAX_LEN 7
#if PAGE_SHIFT < 20
#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
@@ -49,6 +56,14 @@
#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
+/* edac_device printk */
+#define edac_device_printk(ctl, level, fmt, arg...) \
+ printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
+
+/* edac_pci printk */
+#define edac_pci_printk(ctl, level, fmt, arg...) \
+ printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
+
/* prefixes for edac_printk() and edac_mc_printk() */
#define EDAC_MC "MC"
#define EDAC_PCI "PCI"
@@ -69,7 +84,7 @@ extern int edac_debug_level;
#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
-#else /* !CONFIG_EDAC_DEBUG */
+#else /* !CONFIG_EDAC_DEBUG */
#define debugf0( ... )
#define debugf1( ... )
@@ -77,18 +92,14 @@ extern int edac_debug_level;
#define debugf3( ... )
#define debugf4( ... )
-#endif /* !CONFIG_EDAC_DEBUG */
+#endif /* !CONFIG_EDAC_DEBUG */
#define BIT(x) (1 << (x))
#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
PCI_DEVICE_ID_ ## vend ## _ ## dev
-#if defined(CONFIG_X86) && defined(CONFIG_PCI)
-#define dev_name(dev) pci_name(to_pci_dev(dev))
-#else
-#define dev_name(dev) to_platform_device(dev)->name
-#endif
+#define dev_name(dev) (dev)->dev_name
/* memory devices */
enum dev_type {
@@ -124,8 +135,9 @@ enum mem_type {
MEM_DDR, /* Double data rate SDRAM */
MEM_RDDR, /* Registered Double data rate SDRAM */
MEM_RMBS, /* Rambus DRAM */
- MEM_DDR2, /* DDR2 RAM */
- MEM_FB_DDR2, /* fully buffered DDR2 */
+ MEM_DDR2, /* DDR2 RAM */
+ MEM_FB_DDR2, /* fully buffered DDR2 */
+ MEM_RDDR2, /* Registered DDR2 RAM */
};
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
@@ -141,6 +153,7 @@ enum mem_type {
#define MEM_FLAG_RMBS BIT(MEM_RMBS)
#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
+#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
/* chipset Error Detection and Correction capabilities and mode */
enum edac_type {
@@ -181,16 +194,23 @@ enum scrub_type {
};
#define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG)
-#define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC_CORR)
-#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC_CORR)
+#define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC)
+#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC)
#define SCRUB_FLAG_SW_TUN BIT(SCRUB_SW_SCRUB_TUNABLE)
#define SCRUB_FLAG_HW_PROG BIT(SCRUB_HW_PROG)
-#define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC_CORR)
-#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR)
+#define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC)
+#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC)
#define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE)
/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
+/* EDAC internal operation states */
+#define OP_ALLOC 0x100
+#define OP_RUNNING_POLL 0x201
+#define OP_RUNNING_INTERRUPT 0x202
+#define OP_RUNNING_POLL_INTR 0x203
+#define OP_OFFLINE 0x300
+
/*
* There are several things to be aware of that aren't at all obvious:
*
@@ -276,7 +296,7 @@ enum scrub_type {
struct channel_info {
int chan_idx; /* channel index */
u32 ce_count; /* Correctable Errors for this CHANNEL */
- char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
+ char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
struct csrow_info *csrow; /* the parent */
};
@@ -297,15 +317,29 @@ struct csrow_info {
struct mem_ctl_info *mci; /* the parent */
struct kobject kobj; /* sysfs kobject for this csrow */
- struct completion kobj_complete;
- /* FIXME the number of CHANNELs might need to become dynamic */
+ /* channel information for this csrow */
u32 nr_channels;
struct channel_info *channels;
};
+/* mcidev_sysfs_attribute structure
+ * used for driver sysfs attributes and in mem_ctl_info
+ * sysfs top level entries
+ */
+struct mcidev_sysfs_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct mem_ctl_info *,char *);
+ ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
+};
+
+/* MEMORY controller information structure
+ */
struct mem_ctl_info {
- struct list_head link; /* for global list of mem_ctl_info structs */
+ struct list_head link; /* for global list of mem_ctl_info structs */
+
+ struct module *owner; /* Module owner of this control struct */
+
unsigned long mtype_cap; /* memory types supported by mc */
unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */
unsigned long edac_cap; /* configuration capabilities - this is
@@ -322,14 +356,15 @@ struct mem_ctl_info {
/* Translates sdram memory scrub rate given in bytes/sec to the
internal representation and configures whatever else needs
to be configured.
- */
- int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+ */
+ int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
/* Get the current sdram memory scrub rate from the internal
representation and converts it to the closest matching
bandwith in bytes/sec.
- */
- int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+ */
+ int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+
/* pointer to edac checking routine */
void (*edac_check) (struct mem_ctl_info * mci);
@@ -340,7 +375,7 @@ struct mem_ctl_info {
*/
/* FIXME - why not send the phys page to begin with? */
unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
- unsigned long page);
+ unsigned long page);
int mc_idx;
int nr_csrows;
struct csrow_info *csrows;
@@ -353,6 +388,7 @@ struct mem_ctl_info {
const char *mod_name;
const char *mod_ver;
const char *ctl_name;
+ const char *dev_name;
char proc_name[MC_PROC_NAME_MAX_LEN + 1];
void *pvt_info;
u32 ue_noinfo_count; /* Uncorrectable Errors w/o info */
@@ -369,14 +405,327 @@ struct mem_ctl_info {
/* edac sysfs device control */
struct kobject edac_mci_kobj;
- struct completion kobj_complete;
+
+ /* Additional top controller level attributes, but specified
+ * by the low level driver.
+ *
+ * Set by the low level driver to provide attributes at the
+ * controller level, same level as 'ue_count' and 'ce_count' above.
+ * An array of structures, NULL terminated
+ *
+ * If attributes are desired, then set to array of attributes
+ * If no attributes are desired, leave NULL
+ */
+ struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+
+ /* work struct for this MC */
+ struct delayed_work work;
+
+ /* the internal state of this controller instance */
+ int op_state;
+};
+
+/*
+ * The following are the structures to provide for a generic
+ * or abstract 'edac_device'. This set of structures and the
+ * code that implements the APIs for the same, provide for
+ * registering EDAC type devices which are NOT standard memory.
+ *
+ * CPU caches (L1 and L2)
+ * DMA engines
+ * Core CPU swithces
+ * Fabric switch units
+ * PCIe interface controllers
+ * other EDAC/ECC type devices that can be monitored for
+ * errors, etc.
+ *
+ * It allows for a 2 level set of hiearchry. For example:
+ *
+ * cache could be composed of L1, L2 and L3 levels of cache.
+ * Each CPU core would have its own L1 cache, while sharing
+ * L2 and maybe L3 caches.
+ *
+ * View them arranged, via the sysfs presentation:
+ * /sys/devices/system/edac/..
+ *
+ * mc/ <existing memory device directory>
+ * cpu/cpu0/.. <L1 and L2 block directory>
+ * /L1-cache/ce_count
+ * /ue_count
+ * /L2-cache/ce_count
+ * /ue_count
+ * cpu/cpu1/.. <L1 and L2 block directory>
+ * /L1-cache/ce_count
+ * /ue_count
+ * /L2-cache/ce_count
+ * /ue_count
+ * ...
+ *
+ * the L1 and L2 directories would be "edac_device_block's"
+ */
+
+struct edac_device_counter {
+ u32 ue_count;
+ u32 ce_count;
+};
+
+/* forward reference */
+struct edac_device_ctl_info;
+struct edac_device_block;
+
+/* edac_dev_sysfs_attribute structure
+ * used for driver sysfs attributes in mem_ctl_info
+ * for extra controls and attributes:
+ * like high level error Injection controls
+ */
+struct edac_dev_sysfs_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct edac_device_ctl_info *, char *);
+ ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);
+};
+
+/* edac_dev_sysfs_block_attribute structure
+ *
+ * used in leaf 'block' nodes for adding controls/attributes
+ *
+ * each block in each instance of the containing control structure
+ * can have an array of the following. The show and store functions
+ * will be filled in with the show/store function in the
+ * low level driver.
+ *
+ * The 'value' field will be the actual value field used for
+ * counting
+ */
+struct edac_dev_sysfs_block_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *,
+ const char *, size_t);
+ struct edac_device_block *block;
+
+ unsigned int value;
+};
+
+/* device block control structure */
+struct edac_device_block {
+ struct edac_device_instance *instance; /* Up Pointer */
+ char name[EDAC_DEVICE_NAME_LEN + 1];
+
+ struct edac_device_counter counters; /* basic UE and CE counters */
+
+ int nr_attribs; /* how many attributes */
+
+ /* this block's attributes, could be NULL */
+ struct edac_dev_sysfs_block_attribute *block_attributes;
+
+ /* edac sysfs device control */
+ struct kobject kobj;
+};
+
+/* device instance control structure */
+struct edac_device_instance {
+ struct edac_device_ctl_info *ctl; /* Up pointer */
+ char name[EDAC_DEVICE_NAME_LEN + 4];
+
+ struct edac_device_counter counters; /* instance counters */
+
+ u32 nr_blocks; /* how many blocks */
+ struct edac_device_block *blocks; /* block array */
+
+ /* edac sysfs device control */
+ struct kobject kobj;
+};
+
+
+/*
+ * Abstract edac_device control info structure
+ *
+ */
+struct edac_device_ctl_info {
+ /* for global list of edac_device_ctl_info structs */
+ struct list_head link;
+
+ struct module *owner; /* Module owner of this control struct */
+
+ int dev_idx;
+
+ /* Per instance controls for this edac_device */
+ int log_ue; /* boolean for logging UEs */
+ int log_ce; /* boolean for logging CEs */
+ int panic_on_ue; /* boolean for panic'ing on an UE */
+ unsigned poll_msec; /* number of milliseconds to poll interval */
+ unsigned long delay; /* number of jiffies for poll_msec */
+
+ /* Additional top controller level attributes, but specified
+ * by the low level driver.
+ *
+ * Set by the low level driver to provide attributes at the
+ * controller level, same level as 'ue_count' and 'ce_count' above.
+ * An array of structures, NULL terminated
+ *
+ * If attributes are desired, then set to array of attributes
+ * If no attributes are desired, leave NULL
+ */
+ struct edac_dev_sysfs_attribute *sysfs_attributes;
+
+ /* pointer to main 'edac' class in sysfs */
+ struct sysdev_class *edac_class;
+
+ /* the internal state of this controller instance */
+ int op_state;
+ /* work struct for this instance */
+ struct delayed_work work;
+
+ /* pointer to edac polling checking routine:
+ * If NOT NULL: points to polling check routine
+ * If NULL: Then assumes INTERRUPT operation, where
+ * MC driver will receive events
+ */
+ void (*edac_check) (struct edac_device_ctl_info * edac_dev);
+
+ struct device *dev; /* pointer to device structure */
+
+ const char *mod_name; /* module name */
+ const char *ctl_name; /* edac controller name */
+ const char *dev_name; /* pci/platform/etc... name */
+
+ void *pvt_info; /* pointer to 'private driver' info */
+
+ unsigned long start_time; /* edac_device load start time (jiffies) */
+
+ /* these are for safe removal of mc devices from global list while
+ * NMI handlers may be traversing list
+ */
+ struct rcu_head rcu;
+ struct completion removal_complete;
+
+ /* sysfs top name under 'edac' directory
+ * and instance name:
+ * cpu/cpu0/...
+ * cpu/cpu1/...
+ * cpu/cpu2/...
+ * ...
+ */
+ char name[EDAC_DEVICE_NAME_LEN + 1];
+
+ /* Number of instances supported on this control structure
+ * and the array of those instances
+ */
+ u32 nr_instances;
+ struct edac_device_instance *instances;
+
+ /* Event counters for the this whole EDAC Device */
+ struct edac_device_counter counters;
+
+ /* edac sysfs device control for the 'name'
+ * device this structure controls
+ */
+ struct kobject kobj;
};
+/* To get from the instance's wq to the beginning of the ctl structure */
+#define to_edac_mem_ctl_work(w) \
+ container_of(w, struct mem_ctl_info, work)
+
+#define to_edac_device_ctl_work(w) \
+ container_of(w,struct edac_device_ctl_info,work)
+
+/*
+ * The alloc() and free() functions for the 'edac_device' control info
+ * structure. A MC driver will allocate one of these for each edac_device
+ * it is going to control/register with the EDAC CORE.
+ */
+extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+ unsigned sizeof_private,
+ char *edac_device_name, unsigned nr_instances,
+ char *edac_block_name, unsigned nr_blocks,
+ unsigned offset_value,
+ struct edac_dev_sysfs_block_attribute *block_attributes,
+ unsigned nr_attribs,
+ int device_index);
+
+/* The offset value can be:
+ * -1 indicating no offset value
+ * 0 for zero-based block numbers
+ * 1 for 1-based block number
+ * other for other-based block number
+ */
+#define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1)
+
+extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info);
+
#ifdef CONFIG_PCI
+struct edac_pci_counter {
+ atomic_t pe_count;
+ atomic_t npe_count;
+};
+
+/*
+ * Abstract edac_pci control info structure
+ *
+ */
+struct edac_pci_ctl_info {
+ /* for global list of edac_pci_ctl_info structs */
+ struct list_head link;
+
+ int pci_idx;
+
+ struct sysdev_class *edac_class; /* pointer to class */
+
+ /* the internal state of this controller instance */
+ int op_state;
+ /* work struct for this instance */
+ struct delayed_work work;
+
+ /* pointer to edac polling checking routine:
+ * If NOT NULL: points to polling check routine
+ * If NULL: Then assumes INTERRUPT operation, where
+ * MC driver will receive events
+ */
+ void (*edac_check) (struct edac_pci_ctl_info * edac_dev);
+
+ struct device *dev; /* pointer to device structure */
+
+ const char *mod_name; /* module name */
+ const char *ctl_name; /* edac controller name */
+ const char *dev_name; /* pci/platform/etc... name */
+
+ void *pvt_info; /* pointer to 'private driver' info */
+
+ unsigned long start_time; /* edac_pci load start time (jiffies) */
+
+ /* these are for safe removal of devices from global list while
+ * NMI handlers may be traversing list
+ */
+ struct rcu_head rcu;
+ struct completion complete;
+
+ /* sysfs top name under 'edac' directory
+ * and instance name:
+ * cpu/cpu0/...
+ * cpu/cpu1/...
+ * cpu/cpu2/...
+ * ...
+ */
+ char name[EDAC_DEVICE_NAME_LEN + 1];
+
+ /* Event counters for the this whole EDAC Device */
+ struct edac_pci_counter counters;
+
+ /* edac sysfs device control for the 'name'
+ * device this structure controls
+ */
+ struct kobject kobj;
+ struct completion kobj_complete;
+};
+
+#define to_edac_pci_ctl_work(w) \
+ container_of(w, struct edac_pci_ctl_info,work)
+
/* write all or some bits in a byte-register*/
static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
- u8 mask)
+ u8 mask)
{
if (mask != 0xff) {
u8 buf;
@@ -392,7 +741,7 @@ static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
/* write all or some bits in a word-register*/
static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
- u16 value, u16 mask)
+ u16 value, u16 mask)
{
if (mask != 0xffff) {
u16 buf;
@@ -408,7 +757,7 @@ static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
/* write all or some bits in a dword-register*/
static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
- u32 value, u32 mask)
+ u32 value, u32 mask)
{
if (mask != 0xffff) {
u32 buf;
@@ -422,20 +771,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
pci_write_config_dword(pdev, offset, value);
}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_PCI */
-#ifdef CONFIG_EDAC_DEBUG
-void edac_mc_dump_channel(struct channel_info *chan);
-void edac_mc_dump_mci(struct mem_ctl_info *mci);
-void edac_mc_dump_csrow(struct csrow_info *csrow);
-#endif /* CONFIG_EDAC_DEBUG */
-
-extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx);
-extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev);
+extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+ unsigned nr_chans, int edac_index);
+extern int edac_mc_add_mc(struct mem_ctl_info *mci);
+extern void edac_mc_free(struct mem_ctl_info *mci);
+extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
- unsigned long page);
-extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
- u32 size);
+ unsigned long page);
/*
* The no info errors are used when error overflows are reported.
@@ -448,34 +793,59 @@ extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
* statement clutter and extra function arguments.
*/
extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- unsigned long syndrome, int row, int channel,
- const char *msg);
+ unsigned long page_frame_number,
+ unsigned long offset_in_page,
+ unsigned long syndrome, int row, int channel,
+ const char *msg);
extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
- const char *msg);
+ const char *msg);
extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- int row, const char *msg);
+ unsigned long page_frame_number,
+ unsigned long offset_in_page, int row,
+ const char *msg);
extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
- const char *msg);
-extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channel0,
- unsigned int channel1,
- char *msg);
-extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channel,
- char *msg);
+ const char *msg);
+extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow,
+ unsigned int channel0, unsigned int channel1,
+ char *msg);
+extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow,
+ unsigned int channel, char *msg);
/*
- * This kmalloc's and initializes all the structures.
- * Can't be used if all structures don't have the same lifetime.
+ * edac_device APIs
*/
-extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
- unsigned nr_chans);
+extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev);
+extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev);
+extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg);
+extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg);
-/* Free an mc previously allocated by edac_mc_alloc() */
-extern void edac_mc_free(struct mem_ctl_info *mci);
+/*
+ * edac_pci APIs
+ */
+extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+ const char *edac_pci_name);
+
+extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
+
+extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+ unsigned long value);
+
+extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
+extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
+
+extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl(
+ struct device *dev,
+ const char *mod_name);
+
+extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
+extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+
+/*
+ * edac misc APIs
+ */
+extern char *edac_op_state_to_string(int op_state);
-#endif /* _EDAC_MC_H_ */
+#endif /* _EDAC_CORE_H_ */
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
new file mode 100644
index 000000000000..f3690a697cf9
--- /dev/null
+++ b/drivers/edac/edac_device.c
@@ -0,0 +1,746 @@
+
+/*
+ * edac_device.c
+ * (C) 2007 www.douglaskthompson.com
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Doug Thompson <norsk5@xmission.com>
+ *
+ * edac_device API implementation
+ * 19 Jan 2007
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* lock for the list: 'edac_device_list', manipulation of this list
+ * 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);
+
+#ifdef CONFIG_EDAC_DEBUG
+static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
+{
+ debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
+ debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
+ debugf3("\tdev = %p\n", edac_dev->dev);
+ debugf3("\tmod_name:ctl_name = %s:%s\n",
+ edac_dev->mod_name, edac_dev->ctl_name);
+ debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
+}
+#endif /* CONFIG_EDAC_DEBUG */
+
+
+/*
+ * edac_device_alloc_ctl_info()
+ * Allocate a new edac device control info structure
+ *
+ * The control structure is allocated in complete chunk
+ * from the OS. It is in turn sub allocated to the
+ * various objects that compose the struture
+ *
+ * The structure has a 'nr_instance' array within itself.
+ * Each instance represents a major component
+ * Example: L1 cache and L2 cache are 2 instance components
+ *
+ * Within each instance is an array of 'nr_blocks' blockoffsets
+ */
+struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+ unsigned sz_private,
+ char *edac_device_name, unsigned nr_instances,
+ char *edac_block_name, unsigned nr_blocks,
+ unsigned offset_value, /* zero, 1, or other based offset */
+ struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
+ int device_index)
+{
+ struct edac_device_ctl_info *dev_ctl;
+ struct edac_device_instance *dev_inst, *inst;
+ struct edac_device_block *dev_blk, *blk_p, *blk;
+ struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
+ unsigned total_size;
+ unsigned count;
+ unsigned instance, block, attr;
+ void *pvt;
+ int err;
+
+ debugf4("%s() instances=%d blocks=%d\n",
+ __func__, nr_instances, nr_blocks);
+
+ /* Calculate the size of memory we need to allocate AND
+ * determine the offsets of the various item arrays
+ * (instance,block,attrib) from the start of an allocated structure.
+ * We want the alignment of each item (instance,block,attrib)
+ * to be at least as stringent as what the compiler would
+ * provide if we could simply hardcode everything into a single struct.
+ */
+ dev_ctl = (struct edac_device_ctl_info *)NULL;
+
+ /* Calc the 'end' offset past end of ONE ctl_info structure
+ * which will become the start of the 'instance' array
+ */
+ dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
+
+ /* Calc the 'end' offset past the instance array within the ctl_info
+ * which will become the start of the block array
+ */
+ dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
+
+ /* Calc the 'end' offset past the dev_blk array
+ * which will become the start of the attrib array, if any.
+ */
+ count = nr_instances * nr_blocks;
+ dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
+
+ /* Check for case of when an attribute array is specified */
+ if (nr_attrib > 0) {
+ /* calc how many nr_attrib we need */
+ count *= nr_attrib;
+
+ /* Calc the 'end' offset past the attributes array */
+ pvt = edac_align_ptr(&dev_attrib[count], sz_private);
+ } else {
+ /* no attribute array specificed */
+ pvt = edac_align_ptr(dev_attrib, sz_private);
+ }
+
+ /* 'pvt' now points to where the private data area is.
+ * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
+ * is baselined at ZERO
+ */
+ total_size = ((unsigned long)pvt) + sz_private;
+
+ /* Allocate the amount of memory for the set of control structures */
+ dev_ctl = kzalloc(total_size, GFP_KERNEL);
+ if (dev_ctl == NULL)
+ return NULL;
+
+ /* Adjust pointers so they point within the actual memory we
+ * just allocated rather than an imaginary chunk of memory
+ * located at address 0.
+ * 'dev_ctl' points to REAL memory, while the others are
+ * ZERO based and thus need to be adjusted to point within
+ * the allocated memory.
+ */
+ dev_inst = (struct edac_device_instance *)
+ (((char *)dev_ctl) + ((unsigned long)dev_inst));
+ dev_blk = (struct edac_device_block *)
+ (((char *)dev_ctl) + ((unsigned long)dev_blk));
+ dev_attrib = (struct edac_dev_sysfs_block_attribute *)
+ (((char *)dev_ctl) + ((unsigned long)dev_attrib));
+ pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
+
+ /* Begin storing the information into the control info structure */
+ dev_ctl->dev_idx = device_index;
+ dev_ctl->nr_instances = nr_instances;
+ dev_ctl->instances = dev_inst;
+ dev_ctl->pvt_info = pvt;
+
+ /* Name of this edac device */
+ snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
+
+ debugf4("%s() edac_dev=%p next after end=%p\n",
+ __func__, dev_ctl, pvt + sz_private );
+
+ /* Initialize every Instance */
+ for (instance = 0; instance < nr_instances; instance++) {
+ inst = &dev_inst[instance];
+ inst->ctl = dev_ctl;
+ inst->nr_blocks = nr_blocks;
+ blk_p = &dev_blk[instance * nr_blocks];
+ inst->blocks = blk_p;
+
+ /* name of this instance */
+ snprintf(inst->name, sizeof(inst->name),
+ "%s%u", edac_device_name, instance);
+
+ /* Initialize every block in each instance */
+ for (block = 0; block < nr_blocks; block++) {
+ blk = &blk_p[block];
+ blk->instance = inst;
+ snprintf(blk->name, sizeof(blk->name),
+ "%s%d", edac_block_name, block+offset_value);
+
+ debugf4("%s() instance=%d inst_p=%p block=#%d "
+ "block_p=%p name='%s'\n",
+ __func__, instance, inst, block,
+ blk, blk->name);
+
+ /* if there are NO attributes OR no attribute pointer
+ * then continue on to next block iteration
+ */
+ if ((nr_attrib == 0) || (attrib_spec == NULL))
+ continue;
+
+ /* setup the attribute array for this block */
+ blk->nr_attribs = nr_attrib;
+ attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
+ blk->block_attributes = attrib_p;
+
+ debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
+ __func__, blk->block_attributes);
+
+ /* Initialize every user specified attribute in this
+ * block with the data the caller passed in
+ * Each block gets its own copy of pointers,
+ * and its unique 'value'
+ */
+ for (attr = 0; attr < nr_attrib; attr++) {
+ attrib = &attrib_p[attr];
+
+ /* populate the unique per attrib
+ * with the code pointers and info
+ */
+ attrib->attr = attrib_spec[attr].attr;
+ attrib->show = attrib_spec[attr].show;
+ attrib->store = attrib_spec[attr].store;
+
+ attrib->block = blk; /* up link */
+
+ debugf4("%s() alloc-attrib=%p attrib_name='%s' "
+ "attrib-spec=%p spec-name=%s\n",
+ __func__, attrib, attrib->attr.name,
+ &attrib_spec[attr],
+ attrib_spec[attr].attr.name
+ );
+ }
+ }
+ }
+
+ /* Mark this instance as merely ALLOCATED */
+ dev_ctl->op_state = OP_ALLOC;
+
+ /*
+ * Initialize the 'root' kobj for the edac_device controller
+ */
+ err = edac_device_register_sysfs_main_kobj(dev_ctl);
+ if (err) {
+ kfree(dev_ctl);
+ return NULL;
+ }
+
+ /* at this point, the root kobj is valid, and in order to
+ * 'free' the object, then the function:
+ * edac_device_unregister_sysfs_main_kobj() must be called
+ * which will perform kobj unregistration and the actual free
+ * will occur during the kobject callback operation
+ */
+
+ return dev_ctl;
+}
+EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
+
+/*
+ * edac_device_free_ctl_info()
+ * frees the memory allocated by the edac_device_alloc_ctl_info()
+ * function
+ */
+void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
+{
+ edac_device_unregister_sysfs_main_kobj(ctl_info);
+}
+EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
+
+/*
+ * find_edac_device_by_dev
+ * scans the edac_device list for a specific 'struct device *'
+ *
+ * lock to be held prior to call: device_ctls_mutex
+ *
+ * Return:
+ * pointer to control structure managing 'dev'
+ * NULL if not found on list
+ */
+static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
+{
+ struct edac_device_ctl_info *edac_dev;
+ struct list_head *item;
+
+ debugf0("%s()\n", __func__);
+
+ list_for_each(item, &edac_device_list) {
+ edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+ if (edac_dev->dev == dev)
+ return edac_dev;
+ }
+
+ return NULL;
+}
+
+/*
+ * add_edac_dev_to_global_list
+ * Before calling this function, caller must
+ * assign a unique value to edac_dev->dev_idx.
+ *
+ * lock to be held prior to call: device_ctls_mutex
+ *
+ * Return:
+ * 0 on success
+ * 1 on failure.
+ */
+static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
+{
+ struct list_head *item, *insert_before;
+ struct edac_device_ctl_info *rover;
+
+ insert_before = &edac_device_list;
+
+ /* Determine if already on the list */
+ rover = find_edac_device_by_dev(edac_dev->dev);
+ if (unlikely(rover != NULL))
+ goto fail0;
+
+ /* Insert in ascending order by 'dev_idx', so find position */
+ list_for_each(item, &edac_device_list) {
+ rover = list_entry(item, struct edac_device_ctl_info, link);
+
+ if (rover->dev_idx >= edac_dev->dev_idx) {
+ if (unlikely(rover->dev_idx == edac_dev->dev_idx))
+ goto fail1;
+
+ insert_before = item;
+ break;
+ }
+ }
+
+ list_add_tail_rcu(&edac_dev->link, insert_before);
+ return 0;
+
+fail0:
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "%s (%s) %s %s already assigned %d\n",
+ rover->dev->bus_id, dev_name(rover),
+ rover->mod_name, rover->ctl_name, rover->dev_idx);
+ return 1;
+
+fail1:
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "bug in low-level driver: attempt to assign\n"
+ " duplicate dev_idx %d in %s()\n", rover->dev_idx,
+ __func__);
+ return 1;
+}
+
+/*
+ * complete_edac_device_list_del
+ *
+ * callback function when reference count is zero
+ */
+static void complete_edac_device_list_del(struct rcu_head *head)
+{
+ struct edac_device_ctl_info *edac_dev;
+
+ edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
+ INIT_LIST_HEAD(&edac_dev->link);
+ complete(&edac_dev->removal_complete);
+}
+
+/*
+ * del_edac_device_from_global_list
+ *
+ * remove the RCU, setup for a callback call,
+ * then wait for the callback to occur
+ */
+static void del_edac_device_from_global_list(struct edac_device_ctl_info
+ *edac_device)
+{
+ list_del_rcu(&edac_device->link);
+
+ init_completion(&edac_device->removal_complete);
+ call_rcu(&edac_device->rcu, complete_edac_device_list_del);
+ 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
+ *
+ * this workq is embedded within an edac_device_ctl_info
+ * structure, that needs to be polled for possible error events.
+ *
+ * This operation is to acquire the list mutex lock
+ * (thus preventing insertation or deletion)
+ * and then call the device's poll function IFF this device is
+ * running polled and there is a poll function defined.
+ */
+static void edac_device_workq_function(struct work_struct *work_req)
+{
+ struct delayed_work *d_work = (struct delayed_work *)work_req;
+ struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work);
+
+ mutex_lock(&device_ctls_mutex);
+
+ /* Only poll controllers that are running polled and have a check */
+ if ((edac_dev->op_state == OP_RUNNING_POLL) &&
+ (edac_dev->edac_check != NULL)) {
+ edac_dev->edac_check(edac_dev);
+ }
+
+ mutex_unlock(&device_ctls_mutex);
+
+ /* Reschedule the workq for the next time period to start again
+ * if the number of msec is for 1 sec, then adjust to the next
+ * whole one second to save timers fireing all over the period
+ * between integral seconds
+ */
+ if (edac_dev->poll_msec == 1000)
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ round_jiffies(edac_dev->delay));
+ else
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_setup
+ * initialize a workq item for this edac_device instance
+ * passing in the new delay period in msec
+ */
+void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+ unsigned msec)
+{
+ debugf0("%s()\n", __func__);
+
+ /* take the arg 'msec' and set it into the control structure
+ * to used in the time period calculation
+ * then calc the number of jiffies that represents
+ */
+ edac_dev->poll_msec = msec;
+ edac_dev->delay = msecs_to_jiffies(msec);
+
+ INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
+
+ /* optimize here for the 1 second case, which will be normal value, to
+ * fire ON the 1 second time event. This helps reduce all sorts of
+ * timers firing on sub-second basis, while they are happy
+ * to fire together on the 1 second exactly
+ */
+ if (edac_dev->poll_msec == 1000)
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ round_jiffies(edac_dev->delay));
+ else
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_teardown
+ * stop the workq processing on this edac_dev
+ */
+void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+{
+ int status;
+
+ status = cancel_delayed_work(&edac_dev->work);
+ if (status == 0) {
+ /* workq instance might be running, wait for it */
+ flush_workqueue(edac_workqueue);
+ }
+}
+
+/*
+ * edac_device_reset_delay_period
+ *
+ * need to stop any outstanding workq queued up at this time
+ * because we will be resetting the sleep time.
+ * Then restart the workq on the new delay
+ */
+void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
+ unsigned long value)
+{
+ /* cancel the current workq request, without the mutex lock */
+ edac_device_workq_teardown(edac_dev);
+
+ /* acquire the mutex before doing the workq setup */
+ mutex_lock(&device_ctls_mutex);
+
+ /* restart the workq request, with new delay value */
+ edac_device_workq_setup(edac_dev, value);
+
+ mutex_unlock(&device_ctls_mutex);
+}
+
+/**
+ * edac_device_add_device: Insert the 'edac_dev' structure into the
+ * edac_device global list and create sysfs entries associated with
+ * edac_device structure.
+ * @edac_device: pointer to the edac_device structure to be added to the list
+ * 'edac_device' structure.
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
+{
+ debugf0("%s()\n", __func__);
+
+#ifdef CONFIG_EDAC_DEBUG
+ if (edac_debug_level >= 3)
+ edac_device_dump_device(edac_dev);
+#endif
+ mutex_lock(&device_ctls_mutex);
+
+ if (add_edac_dev_to_global_list(edac_dev))
+ goto fail0;
+
+ /* set load time so that error rate can be tracked */
+ edac_dev->start_time = jiffies;
+
+ /* create this instance's sysfs entries */
+ if (edac_device_create_sysfs(edac_dev)) {
+ edac_device_printk(edac_dev, KERN_WARNING,
+ "failed to create sysfs device\n");
+ goto fail1;
+ }
+
+ /* If there IS a check routine, then we are running POLLED */
+ if (edac_dev->edac_check != NULL) {
+ /* This instance is NOW RUNNING */
+ edac_dev->op_state = OP_RUNNING_POLL;
+
+ /*
+ * enable workq processing on this instance,
+ * default = 1000 msec
+ */
+ edac_device_workq_setup(edac_dev, 1000);
+ } else {
+ edac_dev->op_state = OP_RUNNING_INTERRUPT;
+ }
+
+ /* Report action taken */
+ edac_device_printk(edac_dev, KERN_INFO,
+ "Giving out device to module '%s' controller "
+ "'%s': DEV '%s' (%s)\n",
+ edac_dev->mod_name,
+ edac_dev->ctl_name,
+ dev_name(edac_dev),
+ edac_op_state_to_string(edac_dev->op_state));
+
+ mutex_unlock(&device_ctls_mutex);
+ return 0;
+
+fail1:
+ /* Some error, so remove the entry from the lsit */
+ del_edac_device_from_global_list(edac_dev);
+
+fail0:
+ mutex_unlock(&device_ctls_mutex);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(edac_device_add_device);
+
+/**
+ * edac_device_del_device:
+ * Remove sysfs entries for specified edac_device structure and
+ * then remove edac_device structure from global list
+ *
+ * @pdev:
+ * Pointer to 'struct device' representing edac_device
+ * structure to remove.
+ *
+ * Return:
+ * Pointer to removed edac_device structure,
+ * OR NULL if device not found.
+ */
+struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
+{
+ struct edac_device_ctl_info *edac_dev;
+
+ debugf0("%s()\n", __func__);
+
+ mutex_lock(&device_ctls_mutex);
+
+ /* Find the structure on the list, if not there, then leave */
+ edac_dev = find_edac_device_by_dev(dev);
+ if (edac_dev == NULL) {
+ mutex_unlock(&device_ctls_mutex);
+ return NULL;
+ }
+
+ /* mark this instance as OFFLINE */
+ edac_dev->op_state = OP_OFFLINE;
+
+ /* clear workq processing on this instance */
+ edac_device_workq_teardown(edac_dev);
+
+ /* deregister from global list */
+ del_edac_device_from_global_list(edac_dev);
+
+ mutex_unlock(&device_ctls_mutex);
+
+ /* Tear down the sysfs entries for this instance */
+ edac_device_remove_sysfs(edac_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));
+
+ return edac_dev;
+}
+EXPORT_SYMBOL_GPL(edac_device_del_device);
+
+static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
+{
+ return edac_dev->log_ce;
+}
+
+static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
+{
+ return edac_dev->log_ue;
+}
+
+static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info
+ *edac_dev)
+{
+ return edac_dev->panic_on_ue;
+}
+
+/*
+ * edac_device_handle_ce
+ * perform a common output and handling of an 'edac_dev' CE event
+ */
+void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg)
+{
+ struct edac_device_instance *instance;
+ struct edac_device_block *block = NULL;
+
+ if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: 'instance' out of range "
+ "(%d >= %d)\n", inst_nr,
+ edac_dev->nr_instances);
+ return;
+ }
+
+ instance = edac_dev->instances + inst_nr;
+
+ if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: instance %d 'block' "
+ "out of range (%d >= %d)\n",
+ inst_nr, block_nr,
+ instance->nr_blocks);
+ return;
+ }
+
+ if (instance->nr_blocks > 0) {
+ block = instance->blocks + block_nr;
+ block->counters.ce_count++;
+ }
+
+ /* Propogate the count up the 'totals' tree */
+ instance->counters.ce_count++;
+ edac_dev->counters.ce_count++;
+
+ if (edac_device_get_log_ce(edac_dev))
+ edac_device_printk(edac_dev, KERN_WARNING,
+ "CE: %s instance: %s block: %s '%s'\n",
+ edac_dev->ctl_name, instance->name,
+ block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ce);
+
+/*
+ * edac_device_handle_ue
+ * perform a common output and handling of an 'edac_dev' UE event
+ */
+void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg)
+{
+ struct edac_device_instance *instance;
+ struct edac_device_block *block = NULL;
+
+ if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: 'instance' out of range "
+ "(%d >= %d)\n", inst_nr,
+ edac_dev->nr_instances);
+ return;
+ }
+
+ instance = edac_dev->instances + inst_nr;
+
+ if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: instance %d 'block' "
+ "out of range (%d >= %d)\n",
+ inst_nr, block_nr,
+ instance->nr_blocks);
+ return;
+ }
+
+ if (instance->nr_blocks > 0) {
+ block = instance->blocks + block_nr;
+ block->counters.ue_count++;
+ }
+
+ /* Propogate the count up the 'totals' tree */
+ instance->counters.ue_count++;
+ edac_dev->counters.ue_count++;
+
+ if (edac_device_get_log_ue(edac_dev))
+ edac_device_printk(edac_dev, KERN_EMERG,
+ "UE: %s instance: %s block: %s '%s'\n",
+ edac_dev->ctl_name, instance->name,
+ block ? block->name : "N/A", msg);
+
+ if (edac_device_get_panic_on_ue(edac_dev))
+ panic("EDAC %s: UE instance: %s block %s '%s'\n",
+ edac_dev->ctl_name, instance->name,
+ block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ue);
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
new file mode 100644
index 000000000000..70b837f23c43
--- /dev/null
+++ b/drivers/edac/edac_device_sysfs.c
@@ -0,0 +1,896 @@
+/*
+ * file for managing the edac_device class of devices for EDAC
+ *
+ * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_DEVICE_SYMLINK "device"
+
+#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
+
+
+/*
+ * Set of edac_device_ctl_info attribute store/show functions
+ */
+
+/* 'log_ue' */
+static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->log_ue);
+}
+
+static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ /* if parameter is zero, turn off flag, if non-zero turn on flag */
+ ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+ return count;
+}
+
+/* 'log_ce' */
+static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->log_ce);
+}
+
+static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ /* if parameter is zero, turn off flag, if non-zero turn on flag */
+ ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0);
+
+ return count;
+}
+
+/* 'panic_on_ue' */
+static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->panic_on_ue);
+}
+
+static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ /* if parameter is zero, turn off flag, if non-zero turn on flag */
+ ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+ return count;
+}
+
+/* 'poll_msec' show and store functions*/
+static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->poll_msec);
+}
+
+static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ unsigned long value;
+
+ /* get the value and enforce that it is non-zero, must be at least
+ * one millisecond for the delay period, between scans
+ * Then cancel last outstanding delay for the work request
+ * and set a new one.
+ */
+ value = simple_strtoul(data, NULL, 0);
+ edac_device_reset_delay_period(ctl_info, value);
+
+ return count;
+}
+
+/* edac_device_ctl_info specific attribute structure */
+struct ctl_info_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct edac_device_ctl_info *, char *);
+ ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);
+};
+
+#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
+
+/* Function to 'show' fields from the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+ struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+ if (ctl_info_attr->show)
+ return ctl_info_attr->show(edac_dev, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+ struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+ if (ctl_info_attr->store)
+ return ctl_info_attr->store(edac_dev, buffer, count);
+ return -EIO;
+}
+
+/* edac_dev file operations for an 'ctl_info' */
+static struct sysfs_ops device_ctl_info_ops = {
+ .show = edac_dev_ctl_info_show,
+ .store = edac_dev_ctl_info_store
+};
+
+#define CTL_INFO_ATTR(_name,_mode,_show,_store) \
+static struct ctl_info_attribute attr_ctl_info_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* Declare the various ctl_info attributes here and their respective ops */
+CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR,
+ edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);
+CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR,
+ edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);
+CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR,
+ edac_device_ctl_panic_on_ue_show,
+ edac_device_ctl_panic_on_ue_store);
+CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR,
+ edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);
+
+/* Base Attributes of the EDAC_DEVICE ECC object */
+static struct ctl_info_attribute *device_ctrl_attr[] = {
+ &attr_ctl_info_panic_on_ue,
+ &attr_ctl_info_log_ue,
+ &attr_ctl_info_log_ce,
+ &attr_ctl_info_poll_msec,
+ NULL,
+};
+
+/*
+ * edac_device_ctrl_master_release
+ *
+ * called when the reference count for the 'main' kobj
+ * for a edac_device control struct reaches zero
+ *
+ * Reference count model:
+ * One 'main' kobject for each control structure allocated.
+ * That main kobj is initially set to one AND
+ * the reference count for the EDAC 'core' module is
+ * bumped by one, thus added 'keep in memory' dependency.
+ *
+ * Each new internal kobj (in instances and blocks) then
+ * bumps the 'main' kobject.
+ *
+ * When they are released their release functions decrement
+ * the 'main' kobj.
+ *
+ * When the main kobj reaches zero (0) then THIS function
+ * is called which then decrements the EDAC 'core' module.
+ * When the module reference count reaches zero then the
+ * module no longer has dependency on keeping the release
+ * function code in memory and module can be unloaded.
+ *
+ * This will support several control objects as well, each
+ * with its own 'main' kobj.
+ */
+static void edac_device_ctrl_master_release(struct kobject *kobj)
+{
+ struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
+
+ debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx);
+
+ /* decrement the EDAC CORE module ref count */
+ module_put(edac_dev->owner);
+
+ /* free the control struct containing the 'main' kobj
+ * passed in to this routine
+ */
+ kfree(edac_dev);
+}
+
+/* ktype for the main (master) kobject */
+static struct kobj_type ktype_device_ctrl = {
+ .release = edac_device_ctrl_master_release,
+ .sysfs_ops = &device_ctl_info_ops,
+ .default_attrs = (struct attribute **)device_ctrl_attr,
+};
+
+/*
+ * edac_device_register_sysfs_main_kobj
+ *
+ * perform the high level setup for the new edac_device instance
+ *
+ * Return: 0 SUCCESS
+ * !0 FAILURE
+ */
+int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
+{
+ struct sysdev_class *edac_class;
+ int err;
+
+ debugf1("%s()\n", __func__);
+
+ /* get the /sys/devices/system/edac reference */
+ edac_class = edac_get_edac_class();
+ if (edac_class == NULL) {
+ debugf1("%s() no edac_class error\n", __func__);
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Point to the 'edac_class' this instance 'reports' to */
+ edac_dev->edac_class = edac_class;
+
+ /* Init the devices's kobject */
+ memset(&edac_dev->kobj, 0, sizeof(struct kobject));
+ edac_dev->kobj.ktype = &ktype_device_ctrl;
+
+ /* set this new device under the edac_class kobject */
+ edac_dev->kobj.parent = &edac_class->kset.kobj;
+
+ /* generate sysfs "..../edac/<name>" */
+ debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
+ err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
+ if (err)
+ goto err_out;
+
+ /* Record which module 'owns' this control structure
+ * and bump the ref count of the module
+ */
+ edac_dev->owner = THIS_MODULE;
+
+ if (!try_module_get(edac_dev->owner)) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* register */
+ err = kobject_register(&edac_dev->kobj);
+ if (err) {
+ debugf1("%s()Failed to register '.../edac/%s'\n",
+ __func__, edac_dev->name);
+ goto err_kobj_reg;
+ }
+
+ /* At this point, to 'free' the control struct,
+ * edac_device_unregister_sysfs_main_kobj() must be used
+ */
+
+ debugf4("%s() Registered '.../edac/%s' kobject\n",
+ __func__, edac_dev->name);
+
+ return 0;
+
+ /* Error exit stack */
+err_kobj_reg:
+ module_put(edac_dev->owner);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_unregister_sysfs_main_kobj:
+ * the '..../edac/<name>' kobject
+ */
+void edac_device_unregister_sysfs_main_kobj(
+ struct edac_device_ctl_info *edac_dev)
+{
+ debugf0("%s()\n", __func__);
+ debugf4("%s() name of kobject is: %s\n",
+ __func__, kobject_name(&edac_dev->kobj));
+
+ /*
+ * Unregister the edac device's kobject and
+ * allow for reference count to reach 0 at which point
+ * the callback will be called to:
+ * a) module_put() this module
+ * b) 'kfree' the memory
+ */
+ kobject_unregister(&edac_dev->kobj);
+}
+
+/* edac_dev -> instance information */
+
+/*
+ * Set of low-level instance attribute show functions
+ */
+static ssize_t instance_ue_count_show(struct edac_device_instance *instance,
+ char *data)
+{
+ return sprintf(data, "%u\n", instance->counters.ue_count);
+}
+
+static ssize_t instance_ce_count_show(struct edac_device_instance *instance,
+ char *data)
+{
+ return sprintf(data, "%u\n", instance->counters.ce_count);
+}
+
+#define to_instance(k) container_of(k, struct edac_device_instance, kobj)
+#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_device_ctrl_instance_release(struct kobject *kobj)
+{
+ struct edac_device_instance *instance;
+
+ debugf1("%s()\n", __func__);
+
+ /* map from this kobj to the main control struct
+ * and then dec the main kobj count
+ */
+ instance = to_instance(kobj);
+ kobject_put(&instance->ctl->kobj);
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct edac_device_instance *, char *);
+ ssize_t(*store) (struct edac_device_instance *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_device_instance *instance = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->show)
+ return instance_attr->show(instance, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_device_instance *instance = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->store)
+ return instance_attr->store(instance, buffer, count);
+ return -EIO;
+}
+
+/* edac_dev file operations for an 'instance' */
+static struct sysfs_ops device_instance_ops = {
+ .show = edac_dev_instance_show,
+ .store = edac_dev_instance_store
+};
+
+#define INSTANCE_ATTR(_name,_mode,_show,_store) \
+static struct instance_attribute attr_instance_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/*
+ * Define attributes visible for the edac_device instance object
+ * Each contains a pointer to a show and an optional set
+ * function pointer that does the low level output/input
+ */
+INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);
+INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);
+
+/* list of edac_dev 'instance' attributes */
+static struct instance_attribute *device_instance_attr[] = {
+ &attr_instance_ce_count,
+ &attr_instance_ue_count,
+ NULL,
+};
+
+/* The 'ktype' for each edac_dev 'instance' */
+static struct kobj_type ktype_instance_ctrl = {
+ .release = edac_device_ctrl_instance_release,
+ .sysfs_ops = &device_instance_ops,
+ .default_attrs = (struct attribute **)device_instance_attr,
+};
+
+/* edac_dev -> instance -> block information */
+
+#define to_block(k) container_of(k, struct edac_device_block, kobj)
+#define to_block_attr(a) \
+ container_of(a, struct edac_dev_sysfs_block_attribute, attr)
+
+/*
+ * Set of low-level block attribute show functions
+ */
+static ssize_t block_ue_count_show(struct kobject *kobj,
+ struct attribute *attr, char *data)
+{
+ struct edac_device_block *block = to_block(kobj);
+
+ return sprintf(data, "%u\n", block->counters.ue_count);
+}
+
+static ssize_t block_ce_count_show(struct kobject *kobj,
+ struct attribute *attr, char *data)
+{
+ struct edac_device_block *block = to_block(kobj);
+
+ return sprintf(data, "%u\n", block->counters.ce_count);
+}
+
+/* DEVICE block kobject release() function */
+static void edac_device_ctrl_block_release(struct kobject *kobj)
+{
+ struct edac_device_block *block;
+
+ debugf1("%s()\n", __func__);
+
+ /* get the container of the kobj */
+ block = to_block(kobj);
+
+ /* map from 'block kobj' to 'block->instance->controller->main_kobj'
+ * now 'release' the block kobject
+ */
+ kobject_put(&block->instance->ctl->kobj);
+}
+
+
+/* Function to 'show' fields from the edac_dev 'block' structure */
+static ssize_t edac_dev_block_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_dev_sysfs_block_attribute *block_attr =
+ to_block_attr(attr);
+
+ if (block_attr->show)
+ return block_attr->show(kobj, attr, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'block' structure */
+static ssize_t edac_dev_block_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_dev_sysfs_block_attribute *block_attr;
+
+ block_attr = to_block_attr(attr);
+
+ if (block_attr->store)
+ return block_attr->store(kobj, attr, buffer, count);
+ return -EIO;
+}
+
+/* edac_dev file operations for a 'block' */
+static struct sysfs_ops device_block_ops = {
+ .show = edac_dev_block_show,
+ .store = edac_dev_block_store
+};
+
+#define BLOCK_ATTR(_name,_mode,_show,_store) \
+static struct edac_dev_sysfs_block_attribute attr_block_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL);
+BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL);
+
+/* list of edac_dev 'block' attributes */
+static struct edac_dev_sysfs_block_attribute *device_block_attr[] = {
+ &attr_block_ce_count,
+ &attr_block_ue_count,
+ NULL,
+};
+
+/* The 'ktype' for each edac_dev 'block' */
+static struct kobj_type ktype_block_ctrl = {
+ .release = edac_device_ctrl_block_release,
+ .sysfs_ops = &device_block_ops,
+ .default_attrs = (struct attribute **)device_block_attr,
+};
+
+/* block ctor/dtor code */
+
+/*
+ * edac_device_create_block
+ */
+static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+ struct edac_device_instance *instance,
+ struct edac_device_block *block)
+{
+ int i;
+ int err;
+ struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+ struct kobject *main_kobj;
+
+ debugf4("%s() Instance '%s' inst_p=%p block '%s' block_p=%p\n",
+ __func__, instance->name, instance, block->name, block);
+ debugf4("%s() block kobj=%p block kobj->parent=%p\n",
+ __func__, &block->kobj, &block->kobj.parent);
+
+ /* init this block's kobject */
+ memset(&block->kobj, 0, sizeof(struct kobject));
+ block->kobj.parent = &instance->kobj;
+ block->kobj.ktype = &ktype_block_ctrl;
+
+ err = kobject_set_name(&block->kobj, "%s", block->name);
+ if (err)
+ return err;
+
+ /* bump the main kobject's reference count for this controller
+ * and this instance is dependant on the main
+ */
+ main_kobj = kobject_get(&edac_dev->kobj);
+ if (!main_kobj) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Add this block's kobject */
+ err = kobject_register(&block->kobj);
+ if (err) {
+ debugf1("%s() Failed to register instance '%s'\n",
+ __func__, block->name);
+ kobject_put(main_kobj);
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* If there are driver level block attributes, then added them
+ * to the block kobject
+ */
+ sysfs_attrib = block->block_attributes;
+ if (sysfs_attrib && block->nr_attribs) {
+ for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+ debugf4("%s() creating block attrib='%s' "
+ "attrib->%p to kobj=%p\n",
+ __func__,
+ sysfs_attrib->attr.name,
+ sysfs_attrib, &block->kobj);
+
+ /* Create each block_attribute file */
+ err = sysfs_create_file(&block->kobj,
+ &sysfs_attrib->attr);
+ if (err)
+ goto err_on_attrib;
+ }
+ }
+
+ return 0;
+
+ /* Error unwind stack */
+err_on_attrib:
+ kobject_unregister(&block->kobj);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_delete_block(edac_dev,block);
+ */
+static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
+ struct edac_device_block *block)
+{
+ struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+ int i;
+
+ /* if this block has 'attributes' then we need to iterate over the list
+ * and 'remove' the attributes on this block
+ */
+ sysfs_attrib = block->block_attributes;
+ if (sysfs_attrib && block->nr_attribs) {
+ for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+ /* remove each block_attrib file */
+ sysfs_remove_file(&block->kobj,
+ (struct attribute *) sysfs_attrib);
+ }
+ }
+
+ /* unregister this block's kobject, SEE:
+ * edac_device_ctrl_block_release() callback operation
+ */
+ kobject_unregister(&block->kobj);
+}
+
+/* instance ctor/dtor code */
+
+/*
+ * edac_device_create_instance
+ * create just one instance of an edac_device 'instance'
+ */
+static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+ int idx)
+{
+ int i, j;
+ int err;
+ struct edac_device_instance *instance;
+ struct kobject *main_kobj;
+
+ instance = &edac_dev->instances[idx];
+
+ /* Init the instance's kobject */
+ memset(&instance->kobj, 0, sizeof(struct kobject));
+
+ /* set this new device under the edac_device main kobject */
+ instance->kobj.parent = &edac_dev->kobj;
+ instance->kobj.ktype = &ktype_instance_ctrl;
+ instance->ctl = edac_dev;
+
+ err = kobject_set_name(&instance->kobj, "%s", instance->name);
+ if (err)
+ goto err_out;
+
+ /* bump the main kobject's reference count for this controller
+ * and this instance is dependant on the main
+ */
+ main_kobj = kobject_get(&edac_dev->kobj);
+ if (!main_kobj) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Formally register this instance's kobject */
+ err = kobject_register(&instance->kobj);
+ if (err != 0) {
+ debugf2("%s() Failed to register instance '%s'\n",
+ __func__, instance->name);
+ kobject_put(main_kobj);
+ goto err_out;
+ }
+
+ debugf4("%s() now register '%d' blocks for instance %d\n",
+ __func__, instance->nr_blocks, idx);
+
+ /* register all blocks of this instance */
+ for (i = 0; i < instance->nr_blocks; i++) {
+ err = edac_device_create_block(edac_dev, instance,
+ &instance->blocks[i]);
+ if (err) {
+ /* If any fail, remove all previous ones */
+ for (j = 0; j < i; j++)
+ edac_device_delete_block(edac_dev,
+ &instance->blocks[j]);
+ goto err_release_instance_kobj;
+ }
+ }
+
+ debugf4("%s() Registered instance %d '%s' kobject\n",
+ __func__, idx, instance->name);
+
+ return 0;
+
+ /* error unwind stack */
+err_release_instance_kobj:
+ kobject_unregister(&instance->kobj);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_remove_instance
+ * remove an edac_device instance
+ */
+static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
+ int idx)
+{
+ struct edac_device_instance *instance;
+ int i;
+
+ instance = &edac_dev->instances[idx];
+
+ /* unregister all blocks in this instance */
+ for (i = 0; i < instance->nr_blocks; i++)
+ edac_device_delete_block(edac_dev, &instance->blocks[i]);
+
+ /* unregister this instance's kobject, SEE:
+ * edac_device_ctrl_instance_release() for callback operation
+ */
+ kobject_unregister(&instance->kobj);
+}
+
+/*
+ * edac_device_create_instances
+ * create the first level of 'instances' for this device
+ * (ie 'cache' might have 'cache0', 'cache1', 'cache2', etc
+ */
+static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
+{
+ int i, j;
+ int err;
+
+ debugf0("%s()\n", __func__);
+
+ /* iterate over creation of the instances */
+ for (i = 0; i < edac_dev->nr_instances; i++) {
+ err = edac_device_create_instance(edac_dev, i);
+ if (err) {
+ /* unwind previous instances on error */
+ for (j = 0; j < i; j++)
+ edac_device_delete_instance(edac_dev, j);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * edac_device_delete_instances(edac_dev);
+ * unregister all the kobjects of the instances
+ */
+static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
+{
+ int i;
+
+ /* iterate over creation of the instances */
+ for (i = 0; i < edac_dev->nr_instances; i++)
+ edac_device_delete_instance(edac_dev, i);
+}
+
+/* edac_dev sysfs ctor/dtor code */
+
+/*
+ * edac_device_add_main_sysfs_attributes
+ * add some attributes to this instance's main kobject
+ */
+static int edac_device_add_main_sysfs_attributes(
+ struct edac_device_ctl_info *edac_dev)
+{
+ struct edac_dev_sysfs_attribute *sysfs_attrib;
+ int err = 0;
+
+ sysfs_attrib = edac_dev->sysfs_attributes;
+ if (sysfs_attrib) {
+ /* iterate over the array and create an attribute for each
+ * entry in the list
+ */
+ while (sysfs_attrib->attr.name != NULL) {
+ err = sysfs_create_file(&edac_dev->kobj,
+ (struct attribute*) sysfs_attrib);
+ if (err)
+ goto err_out;
+
+ sysfs_attrib++;
+ }
+ }
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_remove_main_sysfs_attributes
+ * remove any attributes to this instance's main kobject
+ */
+static void edac_device_remove_main_sysfs_attributes(
+ struct edac_device_ctl_info *edac_dev)
+{
+ struct edac_dev_sysfs_attribute *sysfs_attrib;
+
+ /* if there are main attributes, defined, remove them. First,
+ * point to the start of the array and iterate over it
+ * removing each attribute listed from this device's instance's kobject
+ */
+ sysfs_attrib = edac_dev->sysfs_attributes;
+ if (sysfs_attrib) {
+ while (sysfs_attrib->attr.name != NULL) {
+ sysfs_remove_file(&edac_dev->kobj,
+ (struct attribute *) sysfs_attrib);
+ sysfs_attrib++;
+ }
+ }
+}
+
+/*
+ * edac_device_create_sysfs() Constructor
+ *
+ * accept a created edac_device control structure
+ * and 'export' it to sysfs. The 'main' kobj should already have been
+ * created. 'instance' and 'block' kobjects should be registered
+ * along with any 'block' attributes from the low driver. In addition,
+ * the main attributes (if any) are connected to the main kobject of
+ * the control structure.
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+ int err;
+ struct kobject *edac_kobj = &edac_dev->kobj;
+
+ debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
+
+ /* go create any main attributes callers wants */
+ err = edac_device_add_main_sysfs_attributes(edac_dev);
+ if (err) {
+ debugf0("%s() failed to add sysfs attribs\n", __func__);
+ goto err_out;
+ }
+
+ /* create a symlink from the edac device
+ * to the platform 'device' being used for this
+ */
+ err = sysfs_create_link(edac_kobj,
+ &edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
+ if (err) {
+ debugf0("%s() sysfs_create_link() returned err= %d\n",
+ __func__, err);
+ goto err_remove_main_attribs;
+ }
+
+ /* Create the first level instance directories
+ * In turn, the nested blocks beneath the instances will
+ * be registered as well
+ */
+ err = edac_device_create_instances(edac_dev);
+ if (err) {
+ debugf0("%s() edac_device_create_instances() "
+ "returned err= %d\n", __func__, err);
+ goto err_remove_link;
+ }
+
+
+ debugf4("%s() create-instances done, idx=%d\n",
+ __func__, edac_dev->dev_idx);
+
+ return 0;
+
+ /* Error unwind stack */
+err_remove_link:
+ /* remove the sym link */
+ sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+err_remove_main_attribs:
+ edac_device_remove_main_sysfs_attributes(edac_dev);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_remove_sysfs() destructor
+ *
+ * given an edac_device struct, tear down the kobject resources
+ */
+void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+ debugf0("%s()\n", __func__);
+
+ /* remove any main attributes for this device */
+ edac_device_remove_main_sysfs_attributes(edac_dev);
+
+ /* remove the device sym link */
+ sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+ /* walk the instance/block kobject tree, deconstructing it */
+ edac_device_delete_instances(edac_dev);
+}
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 804875de5801..063a1bffe38b 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -27,1200 +27,20 @@
#include <linux/list.h>
#include <linux/sysdev.h>
#include <linux/ctype.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
+#include <linux/edac.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/edac.h>
-#include "edac_mc.h"
-
-#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
-
-
-#ifdef CONFIG_EDAC_DEBUG
-/* Values of 0 to 4 will generate output */
-int edac_debug_level = 1;
-EXPORT_SYMBOL_GPL(edac_debug_level);
-#endif
-
-/* EDAC Controls, setable by module parameter, and sysfs */
-static int log_ue = 1;
-static int log_ce = 1;
-static int panic_on_ue;
-static int poll_msec = 1000;
+#include "edac_core.h"
+#include "edac_module.h"
/* lock to memory controller's control array */
-static DECLARE_MUTEX(mem_ctls_mutex);
+static DEFINE_MUTEX(mem_ctls_mutex);
static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
-static struct task_struct *edac_thread;
-
-#ifdef CONFIG_PCI
-static int check_pci_parity = 0; /* default YES check PCI parity */
-static int panic_on_pci_parity; /* default no panic on PCI Parity */
-static atomic_t pci_parity_count = ATOMIC_INIT(0);
-
-static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
-static struct completion edac_pci_kobj_complete;
-#endif /* CONFIG_PCI */
-
-/* START sysfs data and methods */
-
-
-static const char *mem_types[] = {
- [MEM_EMPTY] = "Empty",
- [MEM_RESERVED] = "Reserved",
- [MEM_UNKNOWN] = "Unknown",
- [MEM_FPM] = "FPM",
- [MEM_EDO] = "EDO",
- [MEM_BEDO] = "BEDO",
- [MEM_SDR] = "Unbuffered-SDR",
- [MEM_RDR] = "Registered-SDR",
- [MEM_DDR] = "Unbuffered-DDR",
- [MEM_RDDR] = "Registered-DDR",
- [MEM_RMBS] = "RMBS"
-};
-
-static const char *dev_types[] = {
- [DEV_UNKNOWN] = "Unknown",
- [DEV_X1] = "x1",
- [DEV_X2] = "x2",
- [DEV_X4] = "x4",
- [DEV_X8] = "x8",
- [DEV_X16] = "x16",
- [DEV_X32] = "x32",
- [DEV_X64] = "x64"
-};
-
-static const char *edac_caps[] = {
- [EDAC_UNKNOWN] = "Unknown",
- [EDAC_NONE] = "None",
- [EDAC_RESERVED] = "Reserved",
- [EDAC_PARITY] = "PARITY",
- [EDAC_EC] = "EC",
- [EDAC_SECDED] = "SECDED",
- [EDAC_S2ECD2ED] = "S2ECD2ED",
- [EDAC_S4ECD4ED] = "S4ECD4ED",
- [EDAC_S8ECD8ED] = "S8ECD8ED",
- [EDAC_S16ECD16ED] = "S16ECD16ED"
-};
-
-/* sysfs object: /sys/devices/system/edac */
-static struct sysdev_class edac_class = {
- set_kset_name("edac"),
-};
-
-/* sysfs object:
- * /sys/devices/system/edac/mc
- */
-static struct kobject edac_memctrl_kobj;
-
-/* We use these to wait for the reference counts on edac_memctrl_kobj and
- * edac_pci_kobj to reach 0.
- */
-static struct completion edac_memctrl_kobj_complete;
-
-/*
- * /sys/devices/system/edac/mc;
- * data structures and methods
- */
-static ssize_t memctrl_int_show(void *ptr, char *buffer)
-{
- int *value = (int*) ptr;
- return sprintf(buffer, "%u\n", *value);
-}
-
-static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
-{
- int *value = (int*) ptr;
-
- if (isdigit(*buffer))
- *value = simple_strtoul(buffer, NULL, 0);
-
- return count;
-}
-
-struct memctrl_dev_attribute {
- struct attribute attr;
- void *value;
- ssize_t (*show)(void *,char *);
- ssize_t (*store)(void *, const char *, size_t);
-};
-
-/* Set of show/store abstract level functions for memory control object */
-static ssize_t memctrl_dev_show(struct kobject *kobj,
- struct attribute *attr, char *buffer)
-{
- struct memctrl_dev_attribute *memctrl_dev;
- memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
- if (memctrl_dev->show)
- return memctrl_dev->show(memctrl_dev->value, buffer);
-
- return -EIO;
-}
-
-static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
-{
- struct memctrl_dev_attribute *memctrl_dev;
- memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
- if (memctrl_dev->store)
- return memctrl_dev->store(memctrl_dev->value, buffer, count);
-
- return -EIO;
-}
-
-static struct sysfs_ops memctrlfs_ops = {
- .show = memctrl_dev_show,
- .store = memctrl_dev_store
-};
-
-#define MEMCTRL_ATTR(_name,_mode,_show,_store) \
-struct memctrl_dev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = &_name, \
- .show = _show, \
- .store = _store, \
-};
-
-#define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store) \
-struct memctrl_dev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = _data, \
- .show = _show, \
- .store = _store, \
-};
-
-/* csrow<id> control files */
-MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-
-/* Base Attributes of the memory ECC object */
-static struct memctrl_dev_attribute *memctrl_attr[] = {
- &attr_panic_on_ue,
- &attr_log_ue,
- &attr_log_ce,
- &attr_poll_msec,
- NULL,
-};
-
-/* Main MC kobject release() function */
-static void edac_memctrl_master_release(struct kobject *kobj)
-{
- debugf1("%s()\n", __func__);
- complete(&edac_memctrl_kobj_complete);
-}
-
-static struct kobj_type ktype_memctrl = {
- .release = edac_memctrl_master_release,
- .sysfs_ops = &memctrlfs_ops,
- .default_attrs = (struct attribute **) memctrl_attr,
-};
-
-/* Initialize the main sysfs entries for edac:
- * /sys/devices/system/edac
- *
- * and children
- *
- * Return: 0 SUCCESS
- * !0 FAILURE
- */
-static int edac_sysfs_memctrl_setup(void)
-{
- int err = 0;
-
- debugf1("%s()\n", __func__);
-
- /* create the /sys/devices/system/edac directory */
- err = sysdev_class_register(&edac_class);
-
- if (err) {
- debugf1("%s() error=%d\n", __func__, err);
- return err;
- }
-
- /* Init the MC's kobject */
- memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
- edac_memctrl_kobj.parent = &edac_class.kset.kobj;
- edac_memctrl_kobj.ktype = &ktype_memctrl;
-
- /* generate sysfs "..../edac/mc" */
- err = kobject_set_name(&edac_memctrl_kobj,"mc");
-
- if (err)
- goto fail;
-
- /* FIXME: maybe new sysdev_create_subdir() */
- err = kobject_register(&edac_memctrl_kobj);
-
- if (err) {
- debugf1("Failed to register '.../edac/mc'\n");
- goto fail;
- }
-
- debugf1("Registered '.../edac/mc' kobject\n");
-
- return 0;
-
-fail:
- sysdev_class_unregister(&edac_class);
- return err;
-}
-
-/*
- * MC teardown:
- * the '..../edac/mc' kobject followed by '..../edac' itself
- */
-static void edac_sysfs_memctrl_teardown(void)
-{
- debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
- /* Unregister the MC's kobject and wait for reference count to reach
- * 0.
- */
- init_completion(&edac_memctrl_kobj_complete);
- kobject_unregister(&edac_memctrl_kobj);
- wait_for_completion(&edac_memctrl_kobj_complete);
-
- /* Unregister the 'edac' object */
- sysdev_class_unregister(&edac_class);
-}
-
-#ifdef CONFIG_PCI
-static ssize_t edac_pci_int_show(void *ptr, char *buffer)
-{
- int *value = ptr;
- return sprintf(buffer,"%d\n",*value);
-}
-
-static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
-{
- int *value = ptr;
-
- if (isdigit(*buffer))
- *value = simple_strtoul(buffer,NULL,0);
-
- return count;
-}
-
-struct edac_pci_dev_attribute {
- struct attribute attr;
- void *value;
- ssize_t (*show)(void *,char *);
- ssize_t (*store)(void *, const char *,size_t);
-};
-
-/* Set of show/store abstract level functions for PCI Parity object */
-static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
- char *buffer)
-{
- struct edac_pci_dev_attribute *edac_pci_dev;
- edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
- if (edac_pci_dev->show)
- return edac_pci_dev->show(edac_pci_dev->value, buffer);
- return -EIO;
-}
-
-static ssize_t edac_pci_dev_store(struct kobject *kobj,
- struct attribute *attr, const char *buffer, size_t count)
-{
- struct edac_pci_dev_attribute *edac_pci_dev;
- edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
- if (edac_pci_dev->show)
- return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
- return -EIO;
-}
-
-static struct sysfs_ops edac_pci_sysfs_ops = {
- .show = edac_pci_dev_show,
- .store = edac_pci_dev_store
-};
-
-#define EDAC_PCI_ATTR(_name,_mode,_show,_store) \
-struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = &_name, \
- .show = _show, \
- .store = _store, \
-};
-
-#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \
-struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = _data, \
- .show = _show, \
- .store = _store, \
-};
-
-/* PCI Parity control files */
-EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
- edac_pci_int_store);
-EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
- edac_pci_int_store);
-EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
-
-/* Base Attributes of the memory ECC object */
-static struct edac_pci_dev_attribute *edac_pci_attr[] = {
- &edac_pci_attr_check_pci_parity,
- &edac_pci_attr_panic_on_pci_parity,
- &edac_pci_attr_pci_parity_count,
- NULL,
-};
-
-/* No memory to release */
-static void edac_pci_release(struct kobject *kobj)
-{
- debugf1("%s()\n", __func__);
- complete(&edac_pci_kobj_complete);
-}
-
-static struct kobj_type ktype_edac_pci = {
- .release = edac_pci_release,
- .sysfs_ops = &edac_pci_sysfs_ops,
- .default_attrs = (struct attribute **) edac_pci_attr,
-};
-
-/**
- * edac_sysfs_pci_setup()
- *
- */
-static int edac_sysfs_pci_setup(void)
-{
- int err;
-
- debugf1("%s()\n", __func__);
-
- memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj));
- edac_pci_kobj.parent = &edac_class.kset.kobj;
- edac_pci_kobj.ktype = &ktype_edac_pci;
- err = kobject_set_name(&edac_pci_kobj, "pci");
-
- if (!err) {
- /* Instanstiate the csrow object */
- /* FIXME: maybe new sysdev_create_subdir() */
- err = kobject_register(&edac_pci_kobj);
-
- if (err)
- debugf1("Failed to register '.../edac/pci'\n");
- else
- debugf1("Registered '.../edac/pci' kobject\n");
- }
-
- return err;
-}
-
-static void edac_sysfs_pci_teardown(void)
-{
- debugf0("%s()\n", __func__);
- init_completion(&edac_pci_kobj_complete);
- kobject_unregister(&edac_pci_kobj);
- wait_for_completion(&edac_pci_kobj_complete);
-}
-
-
-static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
-{
- int where;
- u16 status;
-
- where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
- pci_read_config_word(dev, where, &status);
-
- /* If we get back 0xFFFF then we must suspect that the card has been
- * pulled but the Linux PCI layer has not yet finished cleaning up.
- * We don't want to report on such devices
- */
-
- if (status == 0xFFFF) {
- u32 sanity;
-
- pci_read_config_dword(dev, 0, &sanity);
-
- if (sanity == 0xFFFFFFFF)
- return 0;
- }
-
- status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
- PCI_STATUS_PARITY;
-
- if (status)
- /* reset only the bits we are interested in */
- pci_write_config_word(dev, where, status);
-
- return status;
-}
-
-typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
-
-/* Clear any PCI parity errors logged by this device. */
-static void edac_pci_dev_parity_clear(struct pci_dev *dev)
-{
- u8 header_type;
-
- get_pci_parity_status(dev, 0);
-
- /* read the device TYPE, looking for bridges */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
- get_pci_parity_status(dev, 1);
-}
-
-/*
- * PCI Parity polling
- *
- */
-static void edac_pci_dev_parity_test(struct pci_dev *dev)
-{
- u16 status;
- u8 header_type;
-
- /* read the STATUS register on this device
- */
- status = get_pci_parity_status(dev, 0);
-
- debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id );
-
- /* check the status reg for errors */
- if (status) {
- if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Signaled System Error on %s\n",
- pci_name(dev));
-
- if (status & (PCI_STATUS_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Master Data Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
-
- if (status & (PCI_STATUS_DETECTED_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Detected Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
- }
-
- /* read the device TYPE, looking for bridges */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
- debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id );
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
- /* On bridges, need to examine secondary status register */
- status = get_pci_parity_status(dev, 1);
-
- debugf2("PCI SEC_STATUS= 0x%04x %s\n",
- status, dev->dev.bus_id );
-
- /* check the secondary status reg for errors */
- if (status) {
- if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Signaled System Error on %s\n",
- pci_name(dev));
-
- if (status & (PCI_STATUS_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Master Data Parity Error on "
- "%s\n", pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
-
- if (status & (PCI_STATUS_DETECTED_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Detected Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
- }
- }
-}
-
-/*
- * pci_dev parity list iterator
- * Scan the PCI device list for one iteration, looking for SERRORs
- * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
- */
-static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
-{
- struct pci_dev *dev = NULL;
-
- /* request for kernel access to the next PCI device, if any,
- * and while we are looking at it have its reference count
- * bumped until we are done with it
- */
- while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- fn(dev);
- }
-}
-
-static void do_pci_parity_check(void)
-{
- unsigned long flags;
- int before_count;
-
- debugf3("%s()\n", __func__);
-
- if (!check_pci_parity)
- return;
-
- before_count = atomic_read(&pci_parity_count);
-
- /* scan all PCI devices looking for a Parity Error on devices and
- * bridges
- */
- local_irq_save(flags);
- edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
- local_irq_restore(flags);
-
- /* Only if operator has selected panic on PCI Error */
- if (panic_on_pci_parity) {
- /* If the count is different 'after' from 'before' */
- if (before_count != atomic_read(&pci_parity_count))
- panic("EDAC: PCI Parity Error");
- }
-}
-
-static inline void clear_pci_parity_errors(void)
-{
- /* Clear any PCI bus parity errors that devices initially have logged
- * in their registers.
- */
- edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
-}
-
-#else /* CONFIG_PCI */
-
-/* pre-process these away */
-#define do_pci_parity_check()
-#define clear_pci_parity_errors()
-#define edac_sysfs_pci_teardown()
-#define edac_sysfs_pci_setup() (0)
-
-#endif /* CONFIG_PCI */
-
-/* EDAC sysfs CSROW data structures and methods
- */
-
-/* Set of more default csrow<id> attribute show/store functions */
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%u\n", csrow->ue_count);
-}
-
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%u\n", csrow->ce_count);
-}
-
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
-}
-
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%s\n", mem_types[csrow->mtype]);
-}
-
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%s\n", dev_types[csrow->dtype]);
-}
-
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
-}
-
-/* show/store functions for DIMM Label attributes */
-static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
- char *data, int channel)
-{
- return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
- csrow->channels[channel].label);
-}
-
-static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
- const char *data,
- size_t count,
- int channel)
-{
- ssize_t max_size = 0;
-
- max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
- strncpy(csrow->channels[channel].label, data, max_size);
- csrow->channels[channel].label[max_size] = '\0';
-
- return max_size;
-}
-
-/* show function for dynamic chX_ce_count attribute */
-static ssize_t channel_ce_count_show(struct csrow_info *csrow,
- char *data,
- int channel)
-{
- return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
-}
-
-/* csrow specific attribute structure */
-struct csrowdev_attribute {
- struct attribute attr;
- ssize_t (*show)(struct csrow_info *,char *,int);
- ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
- int private;
-};
-
-#define to_csrow(k) container_of(k, struct csrow_info, kobj)
-#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
-
-/* Set of show/store higher level functions for default csrow attributes */
-static ssize_t csrowdev_show(struct kobject *kobj,
- struct attribute *attr,
- char *buffer)
-{
- struct csrow_info *csrow = to_csrow(kobj);
- struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
-
- if (csrowdev_attr->show)
- return csrowdev_attr->show(csrow,
- buffer,
- csrowdev_attr->private);
- return -EIO;
-}
-
-static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
-{
- struct csrow_info *csrow = to_csrow(kobj);
- struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
-
- if (csrowdev_attr->store)
- return csrowdev_attr->store(csrow,
- buffer,
- count,
- csrowdev_attr->private);
- return -EIO;
-}
-
-static struct sysfs_ops csrowfs_ops = {
- .show = csrowdev_show,
- .store = csrowdev_store
-};
-
-#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
-struct csrowdev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
- .private = _private, \
-};
-
-/* default cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
-CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
-CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
-CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
-CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
-CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
-
-/* default attributes of the CSROW<id> object */
-static struct csrowdev_attribute *default_csrow_attr[] = {
- &attr_dev_type,
- &attr_mem_type,
- &attr_edac_mode,
- &attr_size_mb,
- &attr_ue_count,
- &attr_ce_count,
- NULL,
-};
-
-
-/* possible dynamic channel DIMM Label attribute files */
-CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 0 );
-CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 1 );
-CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 2 );
-CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 3 );
-CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 4 );
-CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 5 );
-
-/* Total possible dynamic DIMM Label attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
- &attr_ch0_dimm_label,
- &attr_ch1_dimm_label,
- &attr_ch2_dimm_label,
- &attr_ch3_dimm_label,
- &attr_ch4_dimm_label,
- &attr_ch5_dimm_label
-};
-
-/* possible dynamic channel ce_count attribute files */
-CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 0 );
-CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 1 );
-CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 2 );
-CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 3 );
-CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 4 );
-CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 5 );
-
-/* Total possible dynamic ce_count attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
- &attr_ch0_ce_count,
- &attr_ch1_ce_count,
- &attr_ch2_ce_count,
- &attr_ch3_ce_count,
- &attr_ch4_ce_count,
- &attr_ch5_ce_count
-};
-
-
-#define EDAC_NR_CHANNELS 6
-
-/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
-static int edac_create_channel_files(struct kobject *kobj, int chan)
-{
- int err=-ENODEV;
-
- if (chan >= EDAC_NR_CHANNELS)
- return err;
-
- /* create the DIMM label attribute file */
- err = sysfs_create_file(kobj,
- (struct attribute *) dynamic_csrow_dimm_attr[chan]);
-
- if (!err) {
- /* create the CE Count attribute file */
- err = sysfs_create_file(kobj,
- (struct attribute *) dynamic_csrow_ce_count_attr[chan]);
- } else {
- debugf1("%s() dimm labels and ce_count files created", __func__);
- }
-
- return err;
-}
-
-/* No memory to release for this kobj */
-static void edac_csrow_instance_release(struct kobject *kobj)
-{
- struct csrow_info *cs;
-
- cs = container_of(kobj, struct csrow_info, kobj);
- complete(&cs->kobj_complete);
-}
-
-/* the kobj_type instance for a CSROW */
-static struct kobj_type ktype_csrow = {
- .release = edac_csrow_instance_release,
- .sysfs_ops = &csrowfs_ops,
- .default_attrs = (struct attribute **) default_csrow_attr,
-};
-
-/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(
- struct kobject *edac_mci_kobj,
- struct csrow_info *csrow,
- int index)
-{
- int err = 0;
- int chan;
-
- memset(&csrow->kobj, 0, sizeof(csrow->kobj));
-
- /* generate ..../edac/mc/mc<id>/csrow<index> */
-
- csrow->kobj.parent = edac_mci_kobj;
- csrow->kobj.ktype = &ktype_csrow;
-
- /* name this instance of csrow<id> */
- err = kobject_set_name(&csrow->kobj,"csrow%d",index);
- if (err)
- goto error_exit;
-
- /* Instanstiate the csrow object */
- err = kobject_register(&csrow->kobj);
- if (!err) {
- /* Create the dyanmic attribute files on this csrow,
- * namely, the DIMM labels and the channel ce_count
- */
- for (chan = 0; chan < csrow->nr_channels; chan++) {
- err = edac_create_channel_files(&csrow->kobj,chan);
- if (err)
- break;
- }
- }
-
-error_exit:
- return err;
-}
-
-/* default sysfs methods and data structures for the main MCI kobject */
-
-static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
- const char *data, size_t count)
-{
- int row, chan;
-
- mci->ue_noinfo_count = 0;
- mci->ce_noinfo_count = 0;
- mci->ue_count = 0;
- mci->ce_count = 0;
-
- for (row = 0; row < mci->nr_csrows; row++) {
- struct csrow_info *ri = &mci->csrows[row];
-
- ri->ue_count = 0;
- ri->ce_count = 0;
-
- for (chan = 0; chan < ri->nr_channels; chan++)
- ri->channels[chan].ce_count = 0;
- }
-
- mci->start_time = jiffies;
- return count;
-}
-
-/* memory scrubbing */
-static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
- const char *data, size_t count)
-{
- u32 bandwidth = -1;
-
- if (mci->set_sdram_scrub_rate) {
-
- memctrl_int_store(&bandwidth, data, count);
-
- if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set successfully, applied: %d\n",
- bandwidth);
- } else {
- /* FIXME: error codes maybe? */
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set FAILED, could not apply: %d\n",
- bandwidth);
- }
- } else {
- /* FIXME: produce "not implemented" ERROR for user-side. */
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'set'control is not implemented!\n");
- }
- return count;
-}
-
-static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
-{
- u32 bandwidth = -1;
-
- if (mci->get_sdram_scrub_rate) {
- if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate successfully, fetched: %d\n",
- bandwidth);
- } else {
- /* FIXME: error codes maybe? */
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate fetch FAILED, got: %d\n",
- bandwidth);
- }
- } else {
- /* FIXME: produce "not implemented" ERROR for user-side. */
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'get' control is not implemented!\n");
- }
- return sprintf(data, "%d\n", bandwidth);
-}
-
-/* default attribute files for the MCI object */
-static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ue_count);
-}
-
-static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ce_count);
-}
-
-static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ce_noinfo_count);
-}
-
-static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ue_noinfo_count);
-}
-
-static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
-}
-
-static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%s\n", mci->ctl_name);
-}
-
-static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
-{
- int total_pages, csrow_idx;
-
- for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
- csrow_idx++) {
- struct csrow_info *csrow = &mci->csrows[csrow_idx];
-
- if (!csrow->nr_pages)
- continue;
-
- total_pages += csrow->nr_pages;
- }
-
- return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages));
-}
-
-struct mcidev_attribute {
- struct attribute attr;
- ssize_t (*show)(struct mem_ctl_info *,char *);
- ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
-};
-
-#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
-#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
-
-/* MCI show/store functions for top most object */
-static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
- char *buffer)
-{
- struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
- struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
- if (mcidev_attr->show)
- return mcidev_attr->show(mem_ctl_info, buffer);
-
- return -EIO;
-}
-
-static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
-{
- struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
- struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
- if (mcidev_attr->store)
- return mcidev_attr->store(mem_ctl_info, buffer, count);
-
- return -EIO;
-}
-
-static struct sysfs_ops mci_ops = {
- .show = mcidev_show,
- .store = mcidev_store
-};
-
-#define MCIDEV_ATTR(_name,_mode,_show,_store) \
-struct mcidev_attribute mci_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-};
-
-/* default Control file */
-MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
-
-/* default Attribute files */
-MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
-MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
-MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
-MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
-MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
-MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
-MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
-
-/* memory scrubber attribute file */
-MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store);
-
-static struct mcidev_attribute *mci_attr[] = {
- &mci_attr_reset_counters,
- &mci_attr_mc_name,
- &mci_attr_size_mb,
- &mci_attr_seconds_since_reset,
- &mci_attr_ue_noinfo_count,
- &mci_attr_ce_noinfo_count,
- &mci_attr_ue_count,
- &mci_attr_ce_count,
- &mci_attr_sdram_scrub_rate,
- NULL
-};
-
-/*
- * Release of a MC controlling instance
- */
-static void edac_mci_instance_release(struct kobject *kobj)
-{
- struct mem_ctl_info *mci;
-
- mci = to_mci(kobj);
- debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
- complete(&mci->kobj_complete);
-}
-
-static struct kobj_type ktype_mci = {
- .release = edac_mci_instance_release,
- .sysfs_ops = &mci_ops,
- .default_attrs = (struct attribute **) mci_attr,
-};
-
-
-#define EDAC_DEVICE_SYMLINK "device"
-
-/*
- * Create a new Memory Controller kobject instance,
- * mc<id> under the 'mc' directory
- *
- * Return:
- * 0 Success
- * !0 Failure
- */
-static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
-{
- int i;
- int err;
- struct csrow_info *csrow;
- struct kobject *edac_mci_kobj=&mci->edac_mci_kobj;
-
- debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
- memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj));
-
- /* set the name of the mc<id> object */
- err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
- if (err)
- return err;
-
- /* link to our parent the '..../edac/mc' object */
- edac_mci_kobj->parent = &edac_memctrl_kobj;
- edac_mci_kobj->ktype = &ktype_mci;
-
- /* register the mc<id> kobject */
- err = kobject_register(edac_mci_kobj);
- if (err)
- return err;
-
- /* create a symlink for the device */
- err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
- EDAC_DEVICE_SYMLINK);
- if (err)
- goto fail0;
-
- /* Make directories for each CSROW object
- * under the mc<id> kobject
- */
- for (i = 0; i < mci->nr_csrows; i++) {
- csrow = &mci->csrows[i];
-
- /* Only expose populated CSROWs */
- if (csrow->nr_pages > 0) {
- err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
- if (err)
- goto fail1;
- }
- }
-
- return 0;
-
- /* CSROW error: backout what has already been registered, */
-fail1:
- for ( i--; i >= 0; i--) {
- if (csrow->nr_pages > 0) {
- init_completion(&csrow->kobj_complete);
- kobject_unregister(&mci->csrows[i].kobj);
- wait_for_completion(&csrow->kobj_complete);
- }
- }
-
-fail0:
- init_completion(&mci->kobj_complete);
- kobject_unregister(edac_mci_kobj);
- wait_for_completion(&mci->kobj_complete);
- return err;
-}
-
-/*
- * remove a Memory Controller instance
- */
-static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
-{
- int i;
-
- debugf0("%s()\n", __func__);
-
- /* remove all csrow kobjects */
- for (i = 0; i < mci->nr_csrows; i++) {
- if (mci->csrows[i].nr_pages > 0) {
- init_completion(&mci->csrows[i].kobj_complete);
- kobject_unregister(&mci->csrows[i].kobj);
- wait_for_completion(&mci->csrows[i].kobj_complete);
- }
- }
-
- sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
- init_completion(&mci->kobj_complete);
- kobject_unregister(&mci->edac_mci_kobj);
- wait_for_completion(&mci->kobj_complete);
-}
-
-/* END OF sysfs data and methods */
-
#ifdef CONFIG_EDAC_DEBUG
-void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct channel_info *chan)
{
debugf4("\tchannel = %p\n", chan);
debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -1228,25 +48,21 @@ void edac_mc_dump_channel(struct channel_info *chan)
debugf4("\tchannel->label = '%s'\n", chan->label);
debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
}
-EXPORT_SYMBOL_GPL(edac_mc_dump_channel);
-void edac_mc_dump_csrow(struct csrow_info *csrow)
+static void edac_mc_dump_csrow(struct csrow_info *csrow)
{
debugf4("\tcsrow = %p\n", csrow);
debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
- debugf4("\tcsrow->first_page = 0x%lx\n",
- csrow->first_page);
+ debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages);
- debugf4("\tcsrow->nr_channels = %d\n",
- csrow->nr_channels);
+ debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
debugf4("\tcsrow->channels = %p\n", csrow->channels);
debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
}
-EXPORT_SYMBOL_GPL(edac_mc_dump_csrow);
-void edac_mc_dump_mci(struct mem_ctl_info *mci)
+static void edac_mc_dump_mci(struct mem_ctl_info *mci)
{
debugf3("\tmci = %p\n", mci);
debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
@@ -1256,13 +72,11 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci)
debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
mci->nr_csrows, mci->csrows);
debugf3("\tdev = %p\n", mci->dev);
- debugf3("\tmod_name:ctl_name = %s:%s\n",
- mci->mod_name, mci->ctl_name);
+ debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
}
-EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
-#endif /* CONFIG_EDAC_DEBUG */
+#endif /* CONFIG_EDAC_DEBUG */
/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
* Adjust 'ptr' so that its alignment is at least as stringent as what the
@@ -1271,7 +85,7 @@ EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
* If 'size' is a constant, the compiler will optimize this whole function
* down to either a no-op or the addition of a constant to the value of 'ptr'.
*/
-static inline char * align_ptr(void *ptr, unsigned size)
+void *edac_align_ptr(void *ptr, unsigned size)
{
unsigned align, r;
@@ -1288,14 +102,14 @@ static inline char * align_ptr(void *ptr, unsigned size)
else if (size > sizeof(char))
align = sizeof(short);
else
- return (char *) ptr;
+ return (char *)ptr;
r = size % align;
if (r == 0)
- return (char *) ptr;
+ return (char *)ptr;
- return (char *) (((unsigned long) ptr) + align - r);
+ return (void *)(((unsigned long)ptr) + align - r);
}
/**
@@ -1315,7 +129,7 @@ static inline char * align_ptr(void *ptr, unsigned size)
* struct mem_ctl_info pointer
*/
struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
- unsigned nr_chans)
+ unsigned nr_chans, int edac_index)
{
struct mem_ctl_info *mci;
struct csrow_info *csi, *csrow;
@@ -1323,30 +137,32 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
void *pvt;
unsigned size;
int row, chn;
+ int err;
/* Figure out the offsets of the various items from the start of an mc
* structure. We want the alignment of each item to be at least as
* stringent as what the compiler would provide if we could simply
* hardcode everything into a single struct.
*/
- mci = (struct mem_ctl_info *) 0;
- csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi));
- chi = (struct channel_info *)
- align_ptr(&csi[nr_csrows], sizeof(*chi));
- pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
- size = ((unsigned long) pvt) + sz_pvt;
-
- if ((mci = kmalloc(size, GFP_KERNEL)) == NULL)
+ mci = (struct mem_ctl_info *)0;
+ csi = edac_align_ptr(&mci[1], sizeof(*csi));
+ chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi));
+ pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
+ size = ((unsigned long)pvt) + sz_pvt;
+
+ mci = kzalloc(size, GFP_KERNEL);
+ if (mci == NULL)
return NULL;
/* Adjust pointers so they point within the memory we just allocated
* rather than an imaginary chunk of memory located at address 0.
*/
- csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi));
- chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi));
- pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL;
+ csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
+ chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+ pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
- memset(mci, 0, size); /* clear all fields */
+ /* setup index and various internal pointers */
+ mci->mc_idx = edac_index;
mci->csrows = csi;
mci->pvt_info = pvt;
mci->nr_csrows = nr_csrows;
@@ -1366,20 +182,45 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
}
}
+ mci->op_state = OP_ALLOC;
+
+ /*
+ * Initialize the 'root' kobj for the edac_mc controller
+ */
+ err = edac_mc_register_sysfs_main_kobj(mci);
+ if (err) {
+ kfree(mci);
+ return NULL;
+ }
+
+ /* at this point, the root kobj is valid, and in order to
+ * 'free' the object, then the function:
+ * edac_mc_unregister_sysfs_main_kobj() must be called
+ * which will perform kobj unregistration and the actual free
+ * will occur during the kobject callback operation
+ */
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_alloc);
/**
- * edac_mc_free: Free a previously allocated 'mci' structure
+ * edac_mc_free
+ * 'Free' a previously allocated 'mci' structure
* @mci: pointer to a struct mem_ctl_info structure
*/
void edac_mc_free(struct mem_ctl_info *mci)
{
- kfree(mci);
+ edac_mc_unregister_sysfs_main_kobj(mci);
}
EXPORT_SYMBOL_GPL(edac_mc_free);
+
+/*
+ * find_mci_by_dev
+ *
+ * scan list of controllers looking for the one that manages
+ * the 'dev' device
+ */
static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
{
struct mem_ctl_info *mci;
@@ -1397,18 +238,149 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
return NULL;
}
+/*
+ * handler for EDAC to check if NMI type handler has asserted interrupt
+ */
+static int edac_mc_assert_error_check_and_clear(void)
+{
+ int old_state;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ return 1;
+
+ old_state = edac_err_assert;
+ edac_err_assert = 0;
+
+ return old_state;
+}
+
+/*
+ * edac_mc_workq_function
+ * performs the operation scheduled by a workq request
+ */
+static void edac_mc_workq_function(struct work_struct *work_req)
+{
+ struct delayed_work *d_work = (struct delayed_work *)work_req;
+ struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
+
+ mutex_lock(&mem_ctls_mutex);
+
+ /* if this control struct has movd to offline state, we are done */
+ if (mci->op_state == OP_OFFLINE) {
+ mutex_unlock(&mem_ctls_mutex);
+ return;
+ }
+
+ /* Only poll controllers that are running polled and have a check */
+ if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
+ mci->edac_check(mci);
+
+ mutex_unlock(&mem_ctls_mutex);
+
+ /* Reschedule */
+ queue_delayed_work(edac_workqueue, &mci->work,
+ msecs_to_jiffies(edac_mc_get_poll_msec()));
+}
+
+/*
+ * edac_mc_workq_setup
+ * initialize a workq item for this mci
+ * passing in the new delay period in msec
+ *
+ * locking model:
+ *
+ * called with the mem_ctls_mutex held
+ */
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+{
+ debugf0("%s()\n", __func__);
+
+ /* if this instance is not in the POLL state, then simply return */
+ if (mci->op_state != OP_RUNNING_POLL)
+ return;
+
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+}
+
+/*
+ * edac_mc_workq_teardown
+ * stop the workq processing on this mci
+ *
+ * locking model:
+ *
+ * called WITHOUT lock held
+ */
+static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
+{
+ int status;
+
+ status = cancel_delayed_work(&mci->work);
+ if (status == 0) {
+ debugf0("%s() not canceled, flush the queue\n",
+ __func__);
+
+ /* workq instance might be running, wait for it */
+ flush_workqueue(edac_workqueue);
+ }
+}
+
+/*
+ * edac_mc_reset_delay_period(unsigned long value)
+ *
+ * user space has updated our poll period value, need to
+ * reset our workq delays
+ */
+void edac_mc_reset_delay_period(int value)
+{
+ struct mem_ctl_info *mci;
+ struct list_head *item;
+
+ mutex_lock(&mem_ctls_mutex);
+
+ /* scan the list and turn off all workq timers, doing so under lock
+ */
+ list_for_each(item, &mc_devices) {
+ mci = list_entry(item, struct mem_ctl_info, link);
+
+ if (mci->op_state == OP_RUNNING_POLL)
+ cancel_delayed_work(&mci->work);
+ }
+
+ mutex_unlock(&mem_ctls_mutex);
+
+
+ /* re-walk the list, and reset the poll delay */
+ mutex_lock(&mem_ctls_mutex);
+
+ list_for_each(item, &mc_devices) {
+ mci = list_entry(item, struct mem_ctl_info, link);
+
+ edac_mc_workq_setup(mci, (unsigned long) value);
+ }
+
+ mutex_unlock(&mem_ctls_mutex);
+}
+
+
+
/* Return 0 on success, 1 on failure.
* Before calling this function, caller must
* assign a unique value to mci->mc_idx.
+ *
+ * locking model:
+ *
+ * called with the mem_ctls_mutex lock held
*/
-static int add_mc_to_global_list (struct mem_ctl_info *mci)
+static int add_mc_to_global_list(struct mem_ctl_info *mci)
{
struct list_head *item, *insert_before;
struct mem_ctl_info *p;
insert_before = &mc_devices;
- if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL))
+ p = find_mci_by_dev(mci->dev);
+ if (unlikely(p != NULL))
goto fail0;
list_for_each(item, &mc_devices) {
@@ -1424,18 +396,19 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci)
}
list_add_tail_rcu(&mci->link, insert_before);
+ atomic_inc(&edac_handlers);
return 0;
fail0:
edac_printk(KERN_WARNING, EDAC_MC,
- "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
- dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx);
+ "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
+ dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
return 1;
fail1:
edac_printk(KERN_WARNING, EDAC_MC,
- "bug in low-level driver: attempt to assign\n"
- " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
+ "bug in low-level driver: attempt to assign\n"
+ " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
return 1;
}
@@ -1450,6 +423,7 @@ static void complete_mc_list_del(struct rcu_head *head)
static void del_mc_from_global_list(struct mem_ctl_info *mci)
{
+ atomic_dec(&edac_handlers);
list_del_rcu(&mci->link);
init_completion(&mci->complete);
call_rcu(&mci->rcu, complete_mc_list_del);
@@ -1457,6 +431,34 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
}
/**
+ * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold mem_ctls_mutex.
+ */
+struct mem_ctl_info *edac_mc_find(int idx)
+{
+ struct list_head *item;
+ struct mem_ctl_info *mci;
+
+ list_for_each(item, &mc_devices) {
+ mci = list_entry(item, struct mem_ctl_info, link);
+
+ if (mci->mc_idx >= idx) {
+ if (mci->mc_idx == idx)
+ return mci;
+
+ break;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(edac_mc_find);
+
+/**
* edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
* create sysfs entries associated with mci structure
* @mci: pointer to the mci structure to be added to the list
@@ -1468,10 +470,10 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
*/
/* FIXME - should a warning be printed if no error detection? correction? */
-int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
+int edac_mc_add_mc(struct mem_ctl_info *mci)
{
debugf0("%s()\n", __func__);
- mci->mc_idx = mc_idx;
+
#ifdef CONFIG_EDAC_DEBUG
if (edac_debug_level >= 3)
edac_mc_dump_mci(mci);
@@ -1484,12 +486,12 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
edac_mc_dump_csrow(&mci->csrows[i]);
for (j = 0; j < mci->csrows[i].nr_channels; j++)
- edac_mc_dump_channel(
- &mci->csrows[i].channels[j]);
+ edac_mc_dump_channel(&mci->csrows[i].
+ channels[j]);
}
}
#endif
- down(&mem_ctls_mutex);
+ mutex_lock(&mem_ctls_mutex);
if (add_mc_to_global_list(mci))
goto fail0;
@@ -1503,18 +505,28 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
goto fail1;
}
+ /* If there IS a check routine, then we are running POLLED */
+ if (mci->edac_check != NULL) {
+ /* This instance is NOW RUNNING */
+ mci->op_state = OP_RUNNING_POLL;
+
+ edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+ } else {
+ mci->op_state = OP_RUNNING_INTERRUPT;
+ }
+
/* 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));
+ edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
+ " DEV %s\n", mci->mod_name, mci->ctl_name, dev_name(mci));
- up(&mem_ctls_mutex);
+ mutex_unlock(&mem_ctls_mutex);
return 0;
fail1:
del_mc_from_global_list(mci);
fail0:
- up(&mem_ctls_mutex);
+ mutex_unlock(&mem_ctls_mutex);
return 1;
}
EXPORT_SYMBOL_GPL(edac_mc_add_mc);
@@ -1526,29 +538,41 @@ EXPORT_SYMBOL_GPL(edac_mc_add_mc);
*
* Return pointer to removed mci structure, or NULL if device not found.
*/
-struct mem_ctl_info * edac_mc_del_mc(struct device *dev)
+struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
{
struct mem_ctl_info *mci;
- debugf0("MC: %s()\n", __func__);
- down(&mem_ctls_mutex);
+ debugf0("%s()\n", __func__);
+
+ mutex_lock(&mem_ctls_mutex);
- if ((mci = find_mci_by_dev(dev)) == NULL) {
- up(&mem_ctls_mutex);
+ /* find the requested mci struct in the global list */
+ mci = find_mci_by_dev(dev);
+ if (mci == NULL) {
+ mutex_unlock(&mem_ctls_mutex);
return NULL;
}
- edac_remove_sysfs_mci_device(mci);
+ /* marking MCI offline */
+ mci->op_state = OP_OFFLINE;
+
del_mc_from_global_list(mci);
- up(&mem_ctls_mutex);
+ mutex_unlock(&mem_ctls_mutex);
+
+ /* flush workq processes and remove sysfs */
+ edac_mc_workq_teardown(mci);
+ edac_remove_sysfs_mci_device(mci);
+
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->dev));
+ mci->mod_name, mci->ctl_name, dev_name(mci));
+
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_del_mc);
-void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
+static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
+ u32 size)
{
struct page *pg;
void *virt_addr;
@@ -1557,7 +581,7 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
debugf3("%s()\n", __func__);
/* ECC error page was not in our memory. Ignore it. */
- if(!pfn_valid(page))
+ if (!pfn_valid(page))
return;
/* Find the actual page structure then map it and fix */
@@ -1577,7 +601,6 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
if (PageHighMem(pg))
local_irq_restore(flags);
}
-EXPORT_SYMBOL_GPL(edac_mc_scrub_block);
/* FIXME - should return -1 */
int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
@@ -1611,7 +634,7 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
if (row == -1)
edac_mc_printk(mci, KERN_ERR,
"could not look up page error address %lx\n",
- (unsigned long) page);
+ (unsigned long)page);
return row;
}
@@ -1620,8 +643,9 @@ EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
/* FIXME - setable log (warning/emerg) levels */
/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
void edac_mc_handle_ce(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- unsigned long syndrome, int row, int channel, const char *msg)
+ unsigned long page_frame_number,
+ unsigned long offset_in_page, unsigned long syndrome,
+ int row, int channel, const char *msg)
{
unsigned long remapped_page;
@@ -1647,7 +671,7 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
return;
}
- if (log_ce)
+ if (edac_mc_get_log_ce())
/* FIXME - put in DIMM location */
edac_mc_printk(mci, KERN_WARNING,
"CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
@@ -1671,18 +695,18 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
* page - which can then be scrubbed.
*/
remapped_page = mci->ctl_page_to_phys ?
- mci->ctl_page_to_phys(mci, page_frame_number) :
- page_frame_number;
+ mci->ctl_page_to_phys(mci, page_frame_number) :
+ page_frame_number;
edac_mc_scrub_block(remapped_page, offset_in_page,
- mci->csrows[row].grain);
+ mci->csrows[row].grain);
}
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
{
- if (log_ce)
+ if (edac_mc_get_log_ce())
edac_mc_printk(mci, KERN_WARNING,
"CE - no information available: %s\n", msg);
@@ -1692,8 +716,8 @@ void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
void edac_mc_handle_ue(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- int row, const char *msg)
+ unsigned long page_frame_number,
+ unsigned long offset_in_page, int row, const char *msg)
{
int len = EDAC_MC_LABEL_LEN * 4;
char labels[len + 1];
@@ -1714,26 +738,26 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci,
}
chars = snprintf(pos, len + 1, "%s",
- mci->csrows[row].channels[0].label);
+ mci->csrows[row].channels[0].label);
len -= chars;
pos += chars;
for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
- chan++) {
+ chan++) {
chars = snprintf(pos, len + 1, ":%s",
- mci->csrows[row].channels[chan].label);
+ mci->csrows[row].channels[chan].label);
len -= chars;
pos += chars;
}
- if (log_ue)
+ if (edac_mc_get_log_ue())
edac_mc_printk(mci, KERN_EMERG,
"UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
"labels \"%s\": %s\n", page_frame_number,
- offset_in_page, mci->csrows[row].grain, row, labels,
- msg);
+ offset_in_page, mci->csrows[row].grain, row,
+ labels, msg);
- if (panic_on_ue)
+ if (edac_mc_get_panic_on_ue())
panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
"row %d, labels \"%s\": %s\n", mci->mc_idx,
page_frame_number, offset_in_page,
@@ -1746,10 +770,10 @@ EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
{
- if (panic_on_ue)
+ if (edac_mc_get_panic_on_ue())
panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
- if (log_ue)
+ if (edac_mc_get_log_ue())
edac_mc_printk(mci, KERN_WARNING,
"UE - no information available: %s\n", msg);
mci->ue_noinfo_count++;
@@ -1757,16 +781,14 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
-
/*************************************************************
* On Fully Buffered DIMM modules, this help function is
* called to process UE events
*/
void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channela,
- unsigned int channelb,
- char *msg)
+ unsigned int csrow,
+ unsigned int channela,
+ unsigned int channelb, char *msg)
{
int len = EDAC_MC_LABEL_LEN * 4;
char labels[len + 1];
@@ -1808,20 +830,21 @@ void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
/* Generate the DIMM labels from the specified channels */
chars = snprintf(pos, len + 1, "%s",
mci->csrows[csrow].channels[channela].label);
- len -= chars; pos += chars;
+ len -= chars;
+ pos += chars;
chars = snprintf(pos, len + 1, "-%s",
mci->csrows[csrow].channels[channelb].label);
- if (log_ue)
+ if (edac_mc_get_log_ue())
edac_mc_printk(mci, KERN_EMERG,
"UE row %d, channel-a= %d channel-b= %d "
"labels \"%s\": %s\n", csrow, channela, channelb,
labels, msg);
- if (panic_on_ue)
+ if (edac_mc_get_panic_on_ue())
panic("UE row %d, channel-a= %d channel-b= %d "
- "labels \"%s\": %s\n", csrow, channela,
- channelb, labels, msg);
+ "labels \"%s\": %s\n", csrow, channela,
+ channelb, labels, msg);
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
@@ -1830,9 +853,7 @@ EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
* called to process CE events
*/
void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channel,
- char *msg)
+ unsigned int csrow, unsigned int channel, char *msg)
{
/* Ensure boundary values */
@@ -1853,13 +874,12 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
return;
}
- if (log_ce)
+ if (edac_mc_get_log_ce())
/* FIXME - put in DIMM location */
edac_mc_printk(mci, KERN_WARNING,
"CE row %d, channel %d, label \"%s\": %s\n",
csrow, channel,
- mci->csrows[csrow].channels[channel].label,
- msg);
+ mci->csrows[csrow].channels[channel].label, msg);
mci->ce_count++;
mci->csrows[csrow].ce_count++;
@@ -1867,17 +887,16 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
-
/*
* Iterate over all MC instances and check for ECC, et al, errors
*/
-static inline void check_mc_devices(void)
+void edac_check_mc_devices(void)
{
struct list_head *item;
struct mem_ctl_info *mci;
debugf3("%s()\n", __func__);
- down(&mem_ctls_mutex);
+ mutex_lock(&mem_ctls_mutex);
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
@@ -1886,120 +905,5 @@ static inline void check_mc_devices(void)
mci->edac_check(mci);
}
- up(&mem_ctls_mutex);
-}
-
-/*
- * Check MC status every poll_msec.
- * Check PCI status every poll_msec as well.
- *
- * This where the work gets done for edac.
- *
- * SMP safe, doesn't use NMI, and auto-rate-limits.
- */
-static void do_edac_check(void)
-{
- debugf3("%s()\n", __func__);
- check_mc_devices();
- do_pci_parity_check();
-}
-
-static int edac_kernel_thread(void *arg)
-{
- set_freezable();
- while (!kthread_should_stop()) {
- do_edac_check();
-
- /* goto sleep for the interval */
- schedule_timeout_interruptible((HZ * poll_msec) / 1000);
- try_to_freeze();
- }
-
- return 0;
-}
-
-/*
- * edac_mc_init
- * module initialization entry point
- */
-static int __init edac_mc_init(void)
-{
- edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
-
- /*
- * Harvest and clear any boot/initialization PCI parity errors
- *
- * FIXME: This only clears errors logged by devices present at time of
- * module initialization. We should also do an initial clear
- * of each newly hotplugged device.
- */
- clear_pci_parity_errors();
-
- /* Create the MC sysfs entries */
- if (edac_sysfs_memctrl_setup()) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error initializing sysfs code\n");
- return -ENODEV;
- }
-
- /* Create the PCI parity sysfs entries */
- if (edac_sysfs_pci_setup()) {
- edac_sysfs_memctrl_teardown();
- edac_printk(KERN_ERR, EDAC_MC,
- "EDAC PCI: Error initializing sysfs code\n");
- return -ENODEV;
- }
-
- /* create our kernel thread */
- edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
-
- if (IS_ERR(edac_thread)) {
- /* remove the sysfs entries */
- edac_sysfs_memctrl_teardown();
- edac_sysfs_pci_teardown();
- return PTR_ERR(edac_thread);
- }
-
- return 0;
-}
-
-/*
- * edac_mc_exit()
- * module exit/termination functioni
- */
-static void __exit edac_mc_exit(void)
-{
- debugf0("%s()\n", __func__);
- kthread_stop(edac_thread);
-
- /* tear down the sysfs device */
- edac_sysfs_memctrl_teardown();
- edac_sysfs_pci_teardown();
+ mutex_unlock(&mem_ctls_mutex);
}
-
-module_init(edac_mc_init);
-module_exit(edac_mc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
- "Based on work by Dan Hollis et al");
-MODULE_DESCRIPTION("Core library routines for MC reporting");
-
-module_param(panic_on_ue, int, 0644);
-MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
-#ifdef CONFIG_PCI
-module_param(check_pci_parity, int, 0644);
-MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on");
-module_param(panic_on_pci_parity, int, 0644);
-MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on");
-#endif
-module_param(log_ue, int, 0644);
-MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
-module_param(log_ce, int, 0644);
-MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on");
-module_param(poll_msec, int, 0644);
-MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds");
-#ifdef CONFIG_EDAC_DEBUG
-module_param(edac_debug_level, int, 0644);
-MODULE_PARM_DESC(edac_debug_level, "Debug level");
-#endif
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
new file mode 100644
index 000000000000..3706b2bc0987
--- /dev/null
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -0,0 +1,1042 @@
+/*
+ * edac_mc kernel module
+ * (C) 2005-2007 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+
+/* MC EDAC Controls, setable by module parameter, and sysfs */
+static int edac_mc_log_ue = 1;
+static int edac_mc_log_ce = 1;
+static int edac_mc_panic_on_ue;
+static int edac_mc_poll_msec = 1000;
+
+/* Getter functions for above */
+int edac_mc_get_log_ue(void)
+{
+ return edac_mc_log_ue;
+}
+
+int edac_mc_get_log_ce(void)
+{
+ return edac_mc_log_ce;
+}
+
+int edac_mc_get_panic_on_ue(void)
+{
+ return edac_mc_panic_on_ue;
+}
+
+/* this is temporary */
+int edac_mc_get_poll_msec(void)
+{
+ return edac_mc_poll_msec;
+}
+
+/* Parameter declarations for above */
+module_param(edac_mc_panic_on_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
+module_param(edac_mc_log_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ue,
+ "Log uncorrectable error to console: 0=off 1=on");
+module_param(edac_mc_log_ce, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ce,
+ "Log correctable error to console: 0=off 1=on");
+module_param(edac_mc_poll_msec, int, 0644);
+MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
+
+/*
+ * various constants for Memory Controllers
+ */
+static const char *mem_types[] = {
+ [MEM_EMPTY] = "Empty",
+ [MEM_RESERVED] = "Reserved",
+ [MEM_UNKNOWN] = "Unknown",
+ [MEM_FPM] = "FPM",
+ [MEM_EDO] = "EDO",
+ [MEM_BEDO] = "BEDO",
+ [MEM_SDR] = "Unbuffered-SDR",
+ [MEM_RDR] = "Registered-SDR",
+ [MEM_DDR] = "Unbuffered-DDR",
+ [MEM_RDDR] = "Registered-DDR",
+ [MEM_RMBS] = "RMBS",
+ [MEM_DDR2] = "Unbuffered-DDR2",
+ [MEM_FB_DDR2] = "FullyBuffered-DDR2",
+ [MEM_RDDR2] = "Registered-DDR2"
+};
+
+static const char *dev_types[] = {
+ [DEV_UNKNOWN] = "Unknown",
+ [DEV_X1] = "x1",
+ [DEV_X2] = "x2",
+ [DEV_X4] = "x4",
+ [DEV_X8] = "x8",
+ [DEV_X16] = "x16",
+ [DEV_X32] = "x32",
+ [DEV_X64] = "x64"
+};
+
+static const char *edac_caps[] = {
+ [EDAC_UNKNOWN] = "Unknown",
+ [EDAC_NONE] = "None",
+ [EDAC_RESERVED] = "Reserved",
+ [EDAC_PARITY] = "PARITY",
+ [EDAC_EC] = "EC",
+ [EDAC_SECDED] = "SECDED",
+ [EDAC_S2ECD2ED] = "S2ECD2ED",
+ [EDAC_S4ECD4ED] = "S4ECD4ED",
+ [EDAC_S8ECD8ED] = "S8ECD8ED",
+ [EDAC_S16ECD16ED] = "S16ECD16ED"
+};
+
+
+
+/*
+ * /sys/devices/system/edac/mc;
+ * data structures and methods
+ */
+static ssize_t memctrl_int_show(void *ptr, char *buffer)
+{
+ int *value = (int *)ptr;
+ return sprintf(buffer, "%u\n", *value);
+}
+
+static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
+{
+ int *value = (int *)ptr;
+
+ if (isdigit(*buffer))
+ *value = simple_strtoul(buffer, NULL, 0);
+
+ return count;
+}
+
+/*
+ * mc poll_msec time value
+ */
+static ssize_t poll_msec_int_store(void *ptr, const char *buffer, size_t count)
+{
+ int *value = (int *)ptr;
+
+ if (isdigit(*buffer)) {
+ *value = simple_strtoul(buffer, NULL, 0);
+
+ /* notify edac_mc engine to reset the poll period */
+ edac_mc_reset_delay_period(*value);
+ }
+
+ return count;
+}
+
+
+/* EDAC sysfs CSROW data structures and methods
+ */
+
+/* Set of more default csrow<id> attribute show/store functions */
+static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%u\n", csrow->ue_count);
+}
+
+static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%u\n", csrow->ce_count);
+}
+
+static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
+}
+
+static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%s\n", mem_types[csrow->mtype]);
+}
+
+static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%s\n", dev_types[csrow->dtype]);
+}
+
+static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]);
+}
+
+/* show/store functions for DIMM Label attributes */
+static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
+ char *data, int channel)
+{
+ return snprintf(data, EDAC_MC_LABEL_LEN, "%s",
+ csrow->channels[channel].label);
+}
+
+static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
+ const char *data,
+ size_t count, int channel)
+{
+ ssize_t max_size = 0;
+
+ max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
+ strncpy(csrow->channels[channel].label, data, max_size);
+ csrow->channels[channel].label[max_size] = '\0';
+
+ return max_size;
+}
+
+/* show function for dynamic chX_ce_count attribute */
+static ssize_t channel_ce_count_show(struct csrow_info *csrow,
+ char *data, int channel)
+{
+ return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+}
+
+/* csrow specific attribute structure */
+struct csrowdev_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct csrow_info *, char *, int);
+ ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
+ int private;
+};
+
+#define to_csrow(k) container_of(k, struct csrow_info, kobj)
+#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
+
+/* Set of show/store higher level functions for default csrow attributes */
+static ssize_t csrowdev_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct csrow_info *csrow = to_csrow(kobj);
+ struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+ if (csrowdev_attr->show)
+ return csrowdev_attr->show(csrow,
+ buffer, csrowdev_attr->private);
+ return -EIO;
+}
+
+static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct csrow_info *csrow = to_csrow(kobj);
+ struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+ if (csrowdev_attr->store)
+ return csrowdev_attr->store(csrow,
+ buffer,
+ count, csrowdev_attr->private);
+ return -EIO;
+}
+
+static struct sysfs_ops csrowfs_ops = {
+ .show = csrowdev_show,
+ .store = csrowdev_store
+};
+
+#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
+static struct csrowdev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+ .private = _private, \
+};
+
+/* default cwrow<id>/attribute files */
+CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
+CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
+CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
+CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
+CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
+CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
+
+/* default attributes of the CSROW<id> object */
+static struct csrowdev_attribute *default_csrow_attr[] = {
+ &attr_dev_type,
+ &attr_mem_type,
+ &attr_edac_mode,
+ &attr_size_mb,
+ &attr_ue_count,
+ &attr_ce_count,
+ NULL,
+};
+
+/* possible dynamic channel DIMM Label attribute files */
+CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 0);
+CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 1);
+CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 2);
+CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 3);
+CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 4);
+CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 5);
+
+/* Total possible dynamic DIMM Label attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
+ &attr_ch0_dimm_label,
+ &attr_ch1_dimm_label,
+ &attr_ch2_dimm_label,
+ &attr_ch3_dimm_label,
+ &attr_ch4_dimm_label,
+ &attr_ch5_dimm_label
+};
+
+/* possible dynamic channel ce_count attribute files */
+CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
+CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
+CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
+CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
+CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
+CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
+
+/* Total possible dynamic ce_count attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
+ &attr_ch0_ce_count,
+ &attr_ch1_ce_count,
+ &attr_ch2_ce_count,
+ &attr_ch3_ce_count,
+ &attr_ch4_ce_count,
+ &attr_ch5_ce_count
+};
+
+#define EDAC_NR_CHANNELS 6
+
+/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
+static int edac_create_channel_files(struct kobject *kobj, int chan)
+{
+ int err = -ENODEV;
+
+ if (chan >= EDAC_NR_CHANNELS)
+ return err;
+
+ /* create the DIMM label attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *)
+ dynamic_csrow_dimm_attr[chan]);
+
+ if (!err) {
+ /* create the CE Count attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *)
+ dynamic_csrow_ce_count_attr[chan]);
+ } else {
+ debugf1("%s() dimm labels and ce_count files created",
+ __func__);
+ }
+
+ return err;
+}
+
+/* No memory to release for this kobj */
+static void edac_csrow_instance_release(struct kobject *kobj)
+{
+ struct mem_ctl_info *mci;
+ struct csrow_info *cs;
+
+ debugf1("%s()\n", __func__);
+
+ cs = container_of(kobj, struct csrow_info, kobj);
+ mci = cs->mci;
+
+ kobject_put(&mci->edac_mci_kobj);
+}
+
+/* the kobj_type instance for a CSROW */
+static struct kobj_type ktype_csrow = {
+ .release = edac_csrow_instance_release,
+ .sysfs_ops = &csrowfs_ops,
+ .default_attrs = (struct attribute **)default_csrow_attr,
+};
+
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_object(struct mem_ctl_info *mci,
+ struct csrow_info *csrow, int index)
+{
+ struct kobject *kobj_mci = &mci->edac_mci_kobj;
+ struct kobject *kobj;
+ int chan;
+ int err;
+
+ /* generate ..../edac/mc/mc<id>/csrow<index> */
+ memset(&csrow->kobj, 0, sizeof(csrow->kobj));
+ csrow->mci = mci; /* include container up link */
+ csrow->kobj.parent = kobj_mci;
+ csrow->kobj.ktype = &ktype_csrow;
+
+ /* name this instance of csrow<id> */
+ err = kobject_set_name(&csrow->kobj, "csrow%d", index);
+ if (err)
+ goto err_out;
+
+ /* bump the mci instance's kobject's ref count */
+ kobj = kobject_get(&mci->edac_mci_kobj);
+ if (!kobj) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Instanstiate the csrow object */
+ err = kobject_register(&csrow->kobj);
+ if (err)
+ goto err_release_top_kobj;
+
+ /* At this point, to release a csrow kobj, one must
+ * call the kobject_unregister and allow that tear down
+ * to work the releasing
+ */
+
+ /* Create the dyanmic attribute files on this csrow,
+ * namely, the DIMM labels and the channel ce_count
+ */
+ for (chan = 0; chan < csrow->nr_channels; chan++) {
+ err = edac_create_channel_files(&csrow->kobj, chan);
+ if (err) {
+ /* special case the unregister here */
+ kobject_unregister(&csrow->kobj);
+ goto err_out;
+ }
+ }
+
+ return 0;
+
+ /* error unwind stack */
+err_release_top_kobj:
+ kobject_put(&mci->edac_mci_kobj);
+
+err_out:
+ return err;
+}
+
+/* default sysfs methods and data structures for the main MCI kobject */
+
+static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ int row, chan;
+
+ mci->ue_noinfo_count = 0;
+ mci->ce_noinfo_count = 0;
+ mci->ue_count = 0;
+ mci->ce_count = 0;
+
+ for (row = 0; row < mci->nr_csrows; row++) {
+ struct csrow_info *ri = &mci->csrows[row];
+
+ ri->ue_count = 0;
+ ri->ce_count = 0;
+
+ for (chan = 0; chan < ri->nr_channels; chan++)
+ ri->channels[chan].ce_count = 0;
+ }
+
+ mci->start_time = jiffies;
+ return count;
+}
+
+/* memory scrubbing */
+static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ u32 bandwidth = -1;
+
+ if (mci->set_sdram_scrub_rate) {
+
+ memctrl_int_store(&bandwidth, data, count);
+
+ if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set successfully, applied: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set FAILED, could not apply: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'set'control is not implemented!\n");
+ }
+ return count;
+}
+
+static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+{
+ u32 bandwidth = -1;
+
+ if (mci->get_sdram_scrub_rate) {
+ if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate successfully, fetched: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate fetch FAILED, got: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'get' control is not implemented\n");
+ }
+ return sprintf(data, "%d\n", bandwidth);
+}
+
+/* default attribute files for the MCI object */
+static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ue_count);
+}
+
+static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ce_count);
+}
+
+static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ce_noinfo_count);
+}
+
+static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ue_noinfo_count);
+}
+
+static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
+}
+
+static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%s\n", mci->ctl_name);
+}
+
+static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
+{
+ int total_pages, csrow_idx;
+
+ for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
+ csrow_idx++) {
+ struct csrow_info *csrow = &mci->csrows[csrow_idx];
+
+ if (!csrow->nr_pages)
+ continue;
+
+ total_pages += csrow->nr_pages;
+ }
+
+ return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
+}
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
+#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
+
+/* MCI show/store functions for top most object */
+static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ if (mcidev_attr->show)
+ return mcidev_attr->show(mem_ctl_info, buffer);
+
+ return -EIO;
+}
+
+static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ if (mcidev_attr->store)
+ return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+ return -EIO;
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops mci_ops = {
+ .show = mcidev_show,
+ .store = mcidev_store
+};
+
+#define MCIDEV_ATTR(_name,_mode,_show,_store) \
+static struct mcidev_sysfs_attribute mci_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* default Control file */
+MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+
+/* default Attribute files */
+MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+
+/* memory scrubber attribute file */
+MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
+ mci_sdram_scrub_rate_store);
+
+static struct mcidev_sysfs_attribute *mci_attr[] = {
+ &mci_attr_reset_counters,
+ &mci_attr_mc_name,
+ &mci_attr_size_mb,
+ &mci_attr_seconds_since_reset,
+ &mci_attr_ue_noinfo_count,
+ &mci_attr_ce_noinfo_count,
+ &mci_attr_ue_count,
+ &mci_attr_ce_count,
+ &mci_attr_sdram_scrub_rate,
+ NULL
+};
+
+
+/*
+ * Release of a MC controlling instance
+ *
+ * each MC control instance has the following resources upon entry:
+ * a) a ref count on the top memctl kobj
+ * b) a ref count on this module
+ *
+ * this function must decrement those ref counts and then
+ * issue a free on the instance's memory
+ */
+static void edac_mci_control_release(struct kobject *kobj)
+{
+ struct mem_ctl_info *mci;
+
+ mci = to_mci(kobj);
+
+ debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
+
+ /* decrement the module ref count */
+ module_put(mci->owner);
+
+ /* free the mci instance memory here */
+ kfree(mci);
+}
+
+static struct kobj_type ktype_mci = {
+ .release = edac_mci_control_release,
+ .sysfs_ops = &mci_ops,
+ .default_attrs = (struct attribute **)mci_attr,
+};
+
+/* show/store, tables, etc for the MC kset */
+
+
+struct memctrl_dev_attribute {
+ struct attribute attr;
+ void *value;
+ ssize_t(*show) (void *, char *);
+ ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for memory control object */
+static ssize_t memctrl_dev_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct memctrl_dev_attribute *memctrl_dev;
+ memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+ if (memctrl_dev->show)
+ return memctrl_dev->show(memctrl_dev->value, buffer);
+
+ return -EIO;
+}
+
+static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct memctrl_dev_attribute *memctrl_dev;
+ memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+ if (memctrl_dev->store)
+ return memctrl_dev->store(memctrl_dev->value, buffer, count);
+
+ return -EIO;
+}
+
+static struct sysfs_ops memctrlfs_ops = {
+ .show = memctrl_dev_show,
+ .store = memctrl_dev_store
+};
+
+#define MEMCTRL_ATTR(_name, _mode, _show, _store) \
+static struct memctrl_dev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = &_name, \
+ .show = _show, \
+ .store = _store, \
+};
+
+#define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store) \
+static struct memctrl_dev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = _data, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* csrow<id> control files */
+MEMCTRL_ATTR(edac_mc_panic_on_ue,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ue,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ce,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_poll_msec,
+ S_IRUGO | S_IWUSR, memctrl_int_show, poll_msec_int_store);
+
+/* Base Attributes of the memory ECC object */
+static struct memctrl_dev_attribute *memctrl_attr[] = {
+ &attr_edac_mc_panic_on_ue,
+ &attr_edac_mc_log_ue,
+ &attr_edac_mc_log_ce,
+ &attr_edac_mc_poll_msec,
+ NULL,
+};
+
+
+/* the ktype for the mc_kset internal kobj */
+static struct kobj_type ktype_mc_set_attribs = {
+ .sysfs_ops = &memctrlfs_ops,
+ .default_attrs = (struct attribute **)memctrl_attr,
+};
+
+/* EDAC memory controller sysfs kset:
+ * /sys/devices/system/edac/mc
+ */
+static struct kset mc_kset = {
+ .kobj = {.ktype = &ktype_mc_set_attribs },
+ .ktype = &ktype_mci,
+};
+
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ * setups and registers the main kobject for each mci
+ */
+int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+ struct kobject *kobj_mci;
+ int err;
+
+ debugf1("%s()\n", __func__);
+
+ kobj_mci = &mci->edac_mci_kobj;
+
+ /* Init the mci's kobject */
+ memset(kobj_mci, 0, sizeof(*kobj_mci));
+
+ /* this instance become part of the mc_kset */
+ kobj_mci->kset = &mc_kset;
+
+ /* set the name of the mc<id> object */
+ err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
+ if (err)
+ goto fail_out;
+
+ /* Record which module 'owns' this control structure
+ * and bump the ref count of the module
+ */
+ mci->owner = THIS_MODULE;
+
+ /* bump ref count on this module */
+ if (!try_module_get(mci->owner)) {
+ err = -ENODEV;
+ goto fail_out;
+ }
+
+ /* register the mc<id> kobject to the mc_kset */
+ err = kobject_register(kobj_mci);
+ if (err) {
+ debugf1("%s()Failed to register '.../edac/mc%d'\n",
+ __func__, mci->mc_idx);
+ goto kobj_reg_fail;
+ }
+
+ /* At this point, to 'free' the control struct,
+ * edac_mc_unregister_sysfs_main_kobj() must be used
+ */
+
+ debugf1("%s() Registered '.../edac/mc%d' kobject\n",
+ __func__, mci->mc_idx);
+
+ return 0;
+
+ /* Error exit stack */
+
+kobj_reg_fail:
+ module_put(mci->owner);
+
+fail_out:
+ return err;
+}
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ * tears down and the main mci kobject from the mc_kset
+ */
+void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+ /* delete the kobj from the mc_kset */
+ kobject_unregister(&mci->edac_mci_kobj);
+}
+
+#define EDAC_DEVICE_SYMLINK "device"
+
+/*
+ * edac_create_mci_instance_attributes
+ * create MC driver specific attributes at the topmost level
+ * directory of this mci instance.
+ */
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+ int err;
+ struct mcidev_sysfs_attribute *sysfs_attrib;
+
+ /* point to the start of the array and iterate over it
+ * adding each attribute listed to this mci instance's kobject
+ */
+ sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+ while (sysfs_attrib && sysfs_attrib->attr.name) {
+ err = sysfs_create_file(&mci->edac_mci_kobj,
+ (struct attribute*) sysfs_attrib);
+ if (err) {
+ return err;
+ }
+
+ sysfs_attrib++;
+ }
+
+ return 0;
+}
+
+/*
+ * edac_remove_mci_instance_attributes
+ * remove MC driver specific attributes at the topmost level
+ * directory of this mci instance.
+ */
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+ struct mcidev_sysfs_attribute *sysfs_attrib;
+
+ /* point to the start of the array and iterate over it
+ * adding each attribute listed to this mci instance's kobject
+ */
+ sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+ /* loop if there are attributes and until we hit a NULL entry */
+ while (sysfs_attrib && sysfs_attrib->attr.name) {
+ sysfs_remove_file(&mci->edac_mci_kobj,
+ (struct attribute *) sysfs_attrib);
+ sysfs_attrib++;
+ }
+}
+
+
+/*
+ * Create a new Memory Controller kobject instance,
+ * mc<id> under the 'mc' directory
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+ int i;
+ int err;
+ struct csrow_info *csrow;
+ struct kobject *kobj_mci = &mci->edac_mci_kobj;
+
+ debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+
+ /* create a symlink for the device */
+ err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
+ EDAC_DEVICE_SYMLINK);
+ if (err) {
+ debugf1("%s() failure to create symlink\n", __func__);
+ goto fail0;
+ }
+
+ /* If the low level driver desires some attributes,
+ * then create them now for the driver.
+ */
+ if (mci->mc_driver_sysfs_attributes) {
+ err = edac_create_mci_instance_attributes(mci);
+ if (err) {
+ debugf1("%s() failure to create mci attributes\n",
+ __func__);
+ goto fail0;
+ }
+ }
+
+ /* Make directories for each CSROW object under the mc<id> kobject
+ */
+ for (i = 0; i < mci->nr_csrows; i++) {
+ csrow = &mci->csrows[i];
+
+ /* Only expose populated CSROWs */
+ if (csrow->nr_pages > 0) {
+ err = edac_create_csrow_object(mci, csrow, i);
+ if (err) {
+ debugf1("%s() failure: create csrow %d obj\n",
+ __func__, i);
+ goto fail1;
+ }
+ }
+ }
+
+ return 0;
+
+ /* CSROW error: backout what has already been registered, */
+fail1:
+ for (i--; i >= 0; i--) {
+ if (csrow->nr_pages > 0) {
+ kobject_unregister(&mci->csrows[i].kobj);
+ }
+ }
+
+ /* remove the mci instance's attributes, if any */
+ edac_remove_mci_instance_attributes(mci);
+
+ /* remove the symlink */
+ sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
+
+fail0:
+ return err;
+}
+
+/*
+ * remove a Memory Controller instance
+ */
+void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+ int i;
+
+ debugf0("%s()\n", __func__);
+
+ /* remove all csrow kobjects */
+ for (i = 0; i < mci->nr_csrows; i++) {
+ if (mci->csrows[i].nr_pages > 0) {
+ debugf0("%s() unreg csrow-%d\n", __func__, i);
+ kobject_unregister(&mci->csrows[i].kobj);
+ }
+ }
+
+ debugf0("%s() remove_link\n", __func__);
+
+ /* remove the symlink */
+ sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
+
+ debugf0("%s() remove_mci_instance\n", __func__);
+
+ /* remove this mci instance's attribtes */
+ edac_remove_mci_instance_attributes(mci);
+
+ debugf0("%s() unregister this mci kobj\n", __func__);
+
+ /* unregister this instance's kobject */
+ kobject_unregister(&mci->edac_mci_kobj);
+}
+
+
+
+
+/*
+ * edac_setup_sysfs_mc_kset(void)
+ *
+ * Initialize the mc_kset for the 'mc' entry
+ * This requires creating the top 'mc' directory with a kset
+ * and its controls/attributes.
+ *
+ * To this 'mc' kset, instance 'mci' will be grouped as children.
+ *
+ * Return: 0 SUCCESS
+ * !0 FAILURE error code
+ */
+int edac_sysfs_setup_mc_kset(void)
+{
+ int err = 0;
+ struct sysdev_class *edac_class;
+
+ debugf1("%s()\n", __func__);
+
+ /* get the /sys/devices/system/edac class reference */
+ edac_class = edac_get_edac_class();
+ if (edac_class == NULL) {
+ debugf1("%s() no edac_class error=%d\n", __func__, err);
+ goto fail_out;
+ }
+
+ /* Init the MC's kobject */
+ kobject_set_name(&mc_kset.kobj, "mc");
+ mc_kset.kobj.parent = &edac_class->kset.kobj;
+
+ /* register the mc_kset */
+ err = kset_register(&mc_kset);
+ if (err) {
+ debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
+ goto fail_out;
+ }
+
+ debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
+
+ return 0;
+
+
+ /* error unwind stack */
+fail_out:
+ return err;
+}
+
+/*
+ * edac_sysfs_teardown_mc_kset
+ *
+ * deconstruct the mc_ket for memory controllers
+ */
+void edac_sysfs_teardown_mc_kset(void)
+{
+ kset_unregister(&mc_kset);
+}
+
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
new file mode 100644
index 000000000000..e0c4a4086055
--- /dev/null
+++ b/drivers/edac/edac_module.c
@@ -0,0 +1,222 @@
+/*
+ * edac_module.c
+ *
+ * (C) 2007 www.softwarebitmaker.com
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Author: Doug Thompson <dougthompson@xmission.com>
+ *
+ */
+#include <linux/edac.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_VERSION "Ver: 2.1.0 " __DATE__
+
+#ifdef CONFIG_EDAC_DEBUG
+/* Values of 0 to 4 will generate output */
+int edac_debug_level = 2;
+EXPORT_SYMBOL_GPL(edac_debug_level);
+#endif
+
+/* scope is to module level only */
+struct workqueue_struct *edac_workqueue;
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ * need to export to other files in this modules
+ */
+static struct sysdev_class edac_class = {
+ set_kset_name("edac"),
+};
+static int edac_class_valid;
+
+/*
+ * edac_op_state_to_string()
+ */
+char *edac_op_state_to_string(int opstate)
+{
+ if (opstate == OP_RUNNING_POLL)
+ return "POLLED";
+ else if (opstate == OP_RUNNING_INTERRUPT)
+ return "INTERRUPT";
+ else if (opstate == OP_RUNNING_POLL_INTR)
+ return "POLL-INTR";
+ else if (opstate == OP_ALLOC)
+ return "ALLOC";
+ else if (opstate == OP_OFFLINE)
+ return "OFFLINE";
+
+ return "UNKNOWN";
+}
+
+/*
+ * edac_get_edac_class()
+ *
+ * return pointer to the edac class of 'edac'
+ */
+struct sysdev_class *edac_get_edac_class(void)
+{
+ struct sysdev_class *classptr = NULL;
+
+ if (edac_class_valid)
+ classptr = &edac_class;
+
+ return classptr;
+}
+
+/*
+ * edac_register_sysfs_edac_name()
+ *
+ * register the 'edac' into /sys/devices/system
+ *
+ * return:
+ * 0 success
+ * !0 error
+ */
+static int edac_register_sysfs_edac_name(void)
+{
+ int err;
+
+ /* create the /sys/devices/system/edac directory */
+ err = sysdev_class_register(&edac_class);
+
+ if (err) {
+ debugf1("%s() error=%d\n", __func__, err);
+ return err;
+ }
+
+ edac_class_valid = 1;
+ return 0;
+}
+
+/*
+ * sysdev_class_unregister()
+ *
+ * unregister the 'edac' from /sys/devices/system
+ */
+static void edac_unregister_sysfs_edac_name(void)
+{
+ /* only if currently registered, then unregister it */
+ if (edac_class_valid)
+ sysdev_class_unregister(&edac_class);
+
+ edac_class_valid = 0;
+}
+
+/*
+ * edac_workqueue_setup
+ * initialize the edac work queue for polling operations
+ */
+static int edac_workqueue_setup(void)
+{
+ edac_workqueue = create_singlethread_workqueue("edac-poller");
+ if (edac_workqueue == NULL)
+ return -ENODEV;
+ else
+ return 0;
+}
+
+/*
+ * edac_workqueue_teardown
+ * teardown the edac workqueue
+ */
+static void edac_workqueue_teardown(void)
+{
+ if (edac_workqueue) {
+ flush_workqueue(edac_workqueue);
+ destroy_workqueue(edac_workqueue);
+ edac_workqueue = NULL;
+ }
+}
+
+/*
+ * edac_init
+ * module initialization entry point
+ */
+static int __init edac_init(void)
+{
+ int err = 0;
+
+ edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
+
+ /*
+ * Harvest and clear any boot/initialization PCI parity errors
+ *
+ * FIXME: This only clears errors logged by devices present at time of
+ * module initialization. We should also do an initial clear
+ * of each newly hotplugged device.
+ */
+ edac_pci_clear_parity_errors();
+
+ /*
+ * perform the registration of the /sys/devices/system/edac class object
+ */
+ if (edac_register_sysfs_edac_name()) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error initializing 'edac' kobject\n");
+ err = -ENODEV;
+ goto error;
+ }
+
+ /*
+ * now set up the mc_kset under the edac class object
+ */
+ err = edac_sysfs_setup_mc_kset();
+ if (err)
+ goto sysfs_setup_fail;
+
+ /* Setup/Initialize the workq for this core */
+ err = edac_workqueue_setup();
+ if (err) {
+ edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
+ goto workq_fail;
+ }
+
+ return 0;
+
+ /* Error teardown stack */
+workq_fail:
+ edac_sysfs_teardown_mc_kset();
+
+sysfs_setup_fail:
+ edac_unregister_sysfs_edac_name();
+
+error:
+ return err;
+}
+
+/*
+ * edac_exit()
+ * module exit/termination function
+ */
+static void __exit edac_exit(void)
+{
+ debugf0("%s()\n", __func__);
+
+ /* tear down the various subsystems */
+ edac_workqueue_teardown();
+ edac_sysfs_teardown_mc_kset();
+ edac_unregister_sysfs_edac_name();
+}
+
+/*
+ * Inform the kernel of our entry and exit points
+ */
+module_init(edac_init);
+module_exit(edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
+MODULE_DESCRIPTION("Core library routines for EDAC reporting");
+
+/* refer to *_sysfs.c files for parameters that are exported via sysfs */
+
+#ifdef CONFIG_EDAC_DEBUG
+module_param(edac_debug_level, int, 0644);
+MODULE_PARM_DESC(edac_debug_level, "Debug level");
+#endif
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
new file mode 100644
index 000000000000..cbc419c8ebc1
--- /dev/null
+++ b/drivers/edac/edac_module.h
@@ -0,0 +1,85 @@
+
+/*
+ * edac_module.h
+ *
+ * For defining functions/data for within the EDAC_CORE module only
+ *
+ * written by doug thompson <norsk5@xmission.h>
+ */
+
+#ifndef __EDAC_MODULE_H__
+#define __EDAC_MODULE_H__
+
+#include <linux/sysdev.h>
+
+#include "edac_core.h"
+
+/*
+ * INTERNAL EDAC MODULE:
+ * EDAC memory controller sysfs create/remove functions
+ * and setup/teardown functions
+ *
+ * edac_mc objects
+ */
+extern int edac_sysfs_setup_mc_kset(void);
+extern void edac_sysfs_teardown_mc_kset(void);
+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);
+extern int edac_mc_get_log_ue(void);
+extern int edac_mc_get_log_ce(void);
+extern int edac_mc_get_panic_on_ue(void);
+extern int edac_get_poll_msec(void);
+extern int edac_mc_get_poll_msec(void);
+
+extern int edac_device_register_sysfs_main_kobj(
+ struct edac_device_ctl_info *edac_dev);
+extern void edac_device_unregister_sysfs_main_kobj(
+ struct edac_device_ctl_info *edac_dev);
+extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
+extern struct sysdev_class *edac_get_edac_class(void);
+
+/* edac core workqueue: single CPU mode */
+extern struct workqueue_struct *edac_workqueue;
+extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+ unsigned msec);
+extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_reset_delay_period(struct edac_device_ctl_info
+ *edac_dev, unsigned long value);
+extern void edac_mc_reset_delay_period(int value);
+
+extern void *edac_align_ptr(void *ptr, unsigned size);
+
+/*
+ * EDAC PCI functions
+ */
+#ifdef CONFIG_PCI
+extern void edac_pci_do_parity_check(void);
+extern void edac_pci_clear_parity_errors(void);
+extern int edac_sysfs_pci_setup(void);
+extern void edac_sysfs_pci_teardown(void);
+extern int edac_pci_get_check_errors(void);
+extern int edac_pci_get_poll_msec(void);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg);
+extern void edac_pci_handle_npe(struct edac_pci_ctl_info *pci,
+ const char *msg);
+#else /* CONFIG_PCI */
+/* pre-process these away */
+#define edac_pci_do_parity_check()
+#define edac_pci_clear_parity_errors()
+#define edac_sysfs_pci_setup() (0)
+#define edac_sysfs_pci_teardown()
+#define edac_pci_get_check_errors()
+#define edac_pci_get_poll_msec()
+#define edac_pci_handle_pe()
+#define edac_pci_handle_npe()
+#endif /* CONFIG_PCI */
+
+#endif /* __EDAC_MODULE_H__ */
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
new file mode 100644
index 000000000000..5dee9f50414b
--- /dev/null
+++ b/drivers/edac/edac_pci.c
@@ -0,0 +1,493 @@
+/*
+ * EDAC PCI component
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+static DEFINE_MUTEX(edac_pci_ctls_mutex);
+static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
+
+/*
+ * edac_pci_alloc_ctl_info
+ *
+ * The alloc() function for the 'edac_pci' control info
+ * structure. The chip driver will allocate one of these for each
+ * edac_pci it is going to control/register with the EDAC CORE.
+ */
+struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+ const char *edac_pci_name)
+{
+ struct edac_pci_ctl_info *pci;
+ void *pvt;
+ unsigned int size;
+
+ debugf1("%s()\n", __func__);
+
+ pci = (struct edac_pci_ctl_info *)0;
+ pvt = edac_align_ptr(&pci[1], sz_pvt);
+ size = ((unsigned long)pvt) + sz_pvt;
+
+ /* Alloc the needed control struct memory */
+ pci = kzalloc(size, GFP_KERNEL);
+ if (pci == NULL)
+ return NULL;
+
+ /* Now much private space */
+ pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
+
+ pci->pvt_info = pvt;
+ pci->op_state = OP_ALLOC;
+
+ snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
+
+ return pci;
+}
+EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
+
+/*
+ * edac_pci_free_ctl_info()
+ *
+ * Last action on the pci control structure.
+ *
+ * call the remove sysfs informaton, which will unregister
+ * this control struct's kobj. When that kobj's ref count
+ * goes to zero, its release function will be call and then
+ * kfree() the memory.
+ */
+void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
+{
+ debugf1("%s()\n", __func__);
+
+ edac_pci_remove_sysfs(pci);
+}
+EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
+
+/*
+ * find_edac_pci_by_dev()
+ * scans the edac_pci list for a specific 'struct device *'
+ *
+ * return NULL if not found, or return control struct pointer
+ */
+static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
+{
+ struct edac_pci_ctl_info *pci;
+ struct list_head *item;
+
+ debugf1("%s()\n", __func__);
+
+ list_for_each(item, &edac_pci_list) {
+ pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+ if (pci->dev == dev)
+ return pci;
+ }
+
+ return NULL;
+}
+
+/*
+ * add_edac_pci_to_global_list
+ * Before calling this function, caller must assign a unique value to
+ * edac_dev->pci_idx.
+ * Return:
+ * 0 on success
+ * 1 on failure
+ */
+static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
+{
+ struct list_head *item, *insert_before;
+ struct edac_pci_ctl_info *rover;
+
+ debugf1("%s()\n", __func__);
+
+ insert_before = &edac_pci_list;
+
+ /* Determine if already on the list */
+ rover = find_edac_pci_by_dev(pci->dev);
+ if (unlikely(rover != NULL))
+ goto fail0;
+
+ /* Insert in ascending order by 'pci_idx', so find position */
+ list_for_each(item, &edac_pci_list) {
+ rover = list_entry(item, struct edac_pci_ctl_info, link);
+
+ if (rover->pci_idx >= pci->pci_idx) {
+ if (unlikely(rover->pci_idx == pci->pci_idx))
+ goto fail1;
+
+ insert_before = item;
+ break;
+ }
+ }
+
+ list_add_tail_rcu(&pci->link, insert_before);
+ return 0;
+
+fail0:
+ edac_printk(KERN_WARNING, EDAC_PCI,
+ "%s (%s) %s %s already assigned %d\n",
+ rover->dev->bus_id, dev_name(rover),
+ rover->mod_name, rover->ctl_name, rover->pci_idx);
+ return 1;
+
+fail1:
+ edac_printk(KERN_WARNING, EDAC_PCI,
+ "but in low-level driver: attempt to assign\n"
+ "\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
+ __func__);
+ return 1;
+}
+
+/*
+ * complete_edac_pci_list_del
+ *
+ * RCU completion callback to indicate item is deleted
+ */
+static void complete_edac_pci_list_del(struct rcu_head *head)
+{
+ struct edac_pci_ctl_info *pci;
+
+ pci = container_of(head, struct edac_pci_ctl_info, rcu);
+ INIT_LIST_HEAD(&pci->link);
+ complete(&pci->complete);
+}
+
+/*
+ * del_edac_pci_from_global_list
+ *
+ * remove the PCI control struct from the global list
+ */
+static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
+{
+ list_del_rcu(&pci->link);
+ init_completion(&pci->complete);
+ call_rcu(&pci->rcu, complete_edac_pci_list_del);
+ wait_for_completion(&pci->complete);
+}
+
+/*
+ * edac_pci_find()
+ * Search for an edac_pci_ctl_info structure whose index is 'idx'
+ *
+ * If found, return a pointer to the structure
+ * Else return NULL.
+ *
+ * Caller must hold pci_ctls_mutex.
+ */
+struct edac_pci_ctl_info *edac_pci_find(int idx)
+{
+ struct list_head *item;
+ struct edac_pci_ctl_info *pci;
+
+ /* Iterage over list, looking for exact match of ID */
+ list_for_each(item, &edac_pci_list) {
+ pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+ if (pci->pci_idx >= idx) {
+ if (pci->pci_idx == idx)
+ return pci;
+
+ /* not on list, so terminate early */
+ break;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(edac_pci_find);
+
+/*
+ * edac_pci_workq_function()
+ *
+ * periodic function that performs the operation
+ * scheduled by a workq request, for a given PCI control struct
+ */
+static void edac_pci_workq_function(struct work_struct *work_req)
+{
+ struct delayed_work *d_work = (struct delayed_work *)work_req;
+ struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
+ int msec;
+ unsigned long delay;
+
+ debugf3("%s() checking\n", __func__);
+
+ mutex_lock(&edac_pci_ctls_mutex);
+
+ if (pci->op_state == OP_RUNNING_POLL) {
+ /* we might be in POLL mode, but there may NOT be a poll func
+ */
+ if ((pci->edac_check != NULL) && edac_pci_get_check_errors())
+ pci->edac_check(pci);
+
+ /* if we are on a one second period, then use round */
+ msec = edac_pci_get_poll_msec();
+ if (msec == 1000)
+ delay = round_jiffies(msecs_to_jiffies(msec));
+ else
+ delay = msecs_to_jiffies(msec);
+
+ /* Reschedule only if we are in POLL mode */
+ queue_delayed_work(edac_workqueue, &pci->work, delay);
+ }
+
+ mutex_unlock(&edac_pci_ctls_mutex);
+}
+
+/*
+ * edac_pci_workq_setup()
+ * initialize a workq item for this edac_pci instance
+ * passing in the new delay period in msec
+ *
+ * locking model:
+ * called when 'edac_pci_ctls_mutex' is locked
+ */
+static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
+ unsigned int msec)
+{
+ debugf0("%s()\n", __func__);
+
+ INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
+ queue_delayed_work(edac_workqueue, &pci->work,
+ msecs_to_jiffies(edac_pci_get_poll_msec()));
+}
+
+/*
+ * edac_pci_workq_teardown()
+ * stop the workq processing on this edac_pci instance
+ */
+static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
+{
+ int status;
+
+ debugf0("%s()\n", __func__);
+
+ status = cancel_delayed_work(&pci->work);
+ if (status == 0)
+ flush_workqueue(edac_workqueue);
+}
+
+/*
+ * edac_pci_reset_delay_period
+ *
+ * called with a new period value for the workq period
+ * a) stop current workq timer
+ * b) restart workq timer with new value
+ */
+void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+ unsigned long value)
+{
+ debugf0("%s()\n", __func__);
+
+ edac_pci_workq_teardown(pci);
+
+ /* need to lock for the setup */
+ mutex_lock(&edac_pci_ctls_mutex);
+
+ edac_pci_workq_setup(pci, value);
+
+ mutex_unlock(&edac_pci_ctls_mutex);
+}
+EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
+
+/*
+ * edac_pci_add_device: Insert the 'edac_dev' structure into the
+ * edac_pci global list and create sysfs entries associated with
+ * edac_pci structure.
+ * @pci: pointer to the edac_device structure to be added to the list
+ * @edac_idx: A unique numeric identifier to be assigned to the
+ * 'edac_pci' structure.
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
+{
+ debugf0("%s()\n", __func__);
+
+ pci->pci_idx = edac_idx;
+ pci->start_time = jiffies;
+
+ mutex_lock(&edac_pci_ctls_mutex);
+
+ if (add_edac_pci_to_global_list(pci))
+ goto fail0;
+
+ if (edac_pci_create_sysfs(pci)) {
+ edac_pci_printk(pci, KERN_WARNING,
+ "failed to create sysfs pci\n");
+ goto fail1;
+ }
+
+ if (pci->edac_check != NULL) {
+ pci->op_state = OP_RUNNING_POLL;
+
+ edac_pci_workq_setup(pci, 1000);
+ } else {
+ pci->op_state = OP_RUNNING_INTERRUPT;
+ }
+
+ edac_pci_printk(pci, KERN_INFO,
+ "Giving out device to module '%s' controller '%s':"
+ " DEV '%s' (%s)\n",
+ pci->mod_name,
+ pci->ctl_name,
+ dev_name(pci), edac_op_state_to_string(pci->op_state));
+
+ mutex_unlock(&edac_pci_ctls_mutex);
+ return 0;
+
+ /* error unwind stack */
+fail1:
+ del_edac_pci_from_global_list(pci);
+fail0:
+ mutex_unlock(&edac_pci_ctls_mutex);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(edac_pci_add_device);
+
+/*
+ * edac_pci_del_device()
+ * Remove sysfs entries for specified edac_pci structure and
+ * then remove edac_pci structure from global list
+ *
+ * @dev:
+ * Pointer to 'struct device' representing edac_pci structure
+ * to remove
+ *
+ * Return:
+ * Pointer to removed edac_pci structure,
+ * or NULL if device not found
+ */
+struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
+{
+ struct edac_pci_ctl_info *pci;
+
+ debugf0("%s()\n", __func__);
+
+ mutex_lock(&edac_pci_ctls_mutex);
+
+ /* ensure the control struct is on the global list
+ * if not, then leave
+ */
+ pci = find_edac_pci_by_dev(dev);
+ if (pci == NULL) {
+ mutex_unlock(&edac_pci_ctls_mutex);
+ return NULL;
+ }
+
+ pci->op_state = OP_OFFLINE;
+
+ del_edac_pci_from_global_list(pci);
+
+ mutex_unlock(&edac_pci_ctls_mutex);
+
+ /* stop the workq timer */
+ edac_pci_workq_teardown(pci);
+
+ 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));
+
+ return pci;
+}
+EXPORT_SYMBOL_GPL(edac_pci_del_device);
+
+/*
+ * edac_pci_generic_check
+ *
+ * a Generic parity check API
+ */
+void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
+{
+ debugf4("%s()\n", __func__);
+ edac_pci_do_parity_check();
+}
+
+/* free running instance index counter */
+static int edac_pci_idx;
+#define EDAC_PCI_GENCTL_NAME "EDAC PCI controller"
+
+struct edac_pci_gen_data {
+ int edac_idx;
+};
+
+/*
+ * edac_pci_create_generic_ctl
+ *
+ * A generic constructor for a PCI parity polling device
+ * Some systems have more than one domain of PCI busses.
+ * For systems with one domain, then this API will
+ * provide for a generic poller.
+ *
+ * This routine calls the edac_pci_alloc_ctl_info() for
+ * the generic device, with default values
+ */
+struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
+ const char *mod_name)
+{
+ struct edac_pci_ctl_info *pci;
+ struct edac_pci_gen_data *pdata;
+
+ pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
+ if (!pci)
+ return NULL;
+
+ pdata = pci->pvt_info;
+ pci->dev = dev;
+ dev_set_drvdata(pci->dev, pci);
+ pci->dev_name = pci_name(to_pci_dev(dev));
+
+ pci->mod_name = mod_name;
+ pci->ctl_name = EDAC_PCI_GENCTL_NAME;
+ pci->edac_check = edac_pci_generic_check;
+
+ pdata->edac_idx = edac_pci_idx++;
+
+ if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
+ debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+ edac_pci_free_ctl_info(pci);
+ return NULL;
+ }
+
+ return pci;
+}
+EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
+
+/*
+ * edac_pci_release_generic_ctl
+ *
+ * The release function of a generic EDAC PCI polling device
+ */
+void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
+{
+ debugf0("%s() pci mod=%s\n", __func__, pci->mod_name);
+
+ edac_pci_del_device(pci->dev);
+ edac_pci_free_ctl_info(pci);
+}
+EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
new file mode 100644
index 000000000000..69f5dddabddf
--- /dev/null
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -0,0 +1,763 @@
+/*
+ * (C) 2005, 2006 Linux Networx (http://lnxi.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* Turn off this whole feature if PCI is not configured */
+#ifdef CONFIG_PCI
+
+#define EDAC_PCI_SYMLINK "device"
+
+/* data variables exported via sysfs */
+static int check_pci_errors; /* default NO check PCI parity */
+static int edac_pci_panic_on_pe; /* default NO panic on PCI Parity */
+static int edac_pci_log_pe = 1; /* log PCI parity errors */
+static int edac_pci_log_npe = 1; /* log PCI non-parity error errors */
+static int edac_pci_poll_msec = 1000; /* one second workq period */
+
+static atomic_t pci_parity_count = ATOMIC_INIT(0);
+static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
+
+static struct kobject edac_pci_top_main_kobj;
+static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
+
+/* getter functions for the data variables */
+int edac_pci_get_check_errors(void)
+{
+ return check_pci_errors;
+}
+
+int edac_pci_get_log_pe(void)
+{
+ return edac_pci_log_pe;
+}
+
+int edac_pci_get_log_npe(void)
+{
+ return edac_pci_log_npe;
+}
+
+int edac_pci_get_panic_on_pe(void)
+{
+ return edac_pci_panic_on_pe;
+}
+
+int edac_pci_get_poll_msec(void)
+{
+ return edac_pci_poll_msec;
+}
+
+/**************************** EDAC PCI sysfs instance *******************/
+static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data)
+{
+ return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));
+}
+
+static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,
+ char *data)
+{
+ return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));
+}
+
+#define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_instance_attr(a) container_of(a, struct instance_attribute, attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_pci_instance_release(struct kobject *kobj)
+{
+ struct edac_pci_ctl_info *pci;
+
+ debugf0("%s()\n", __func__);
+
+ /* Form pointer to containing struct, the pci control struct */
+ pci = to_instance(kobj);
+
+ /* decrement reference count on top main kobj */
+ kobject_put(&edac_pci_top_main_kobj);
+
+ kfree(pci); /* Free the control struct */
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct edac_pci_ctl_info *, char *);
+ ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_pci_ctl_info *pci = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->show)
+ return instance_attr->show(pci, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_pci_ctl_info *pci = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->store)
+ return instance_attr->store(pci, buffer, count);
+ return -EIO;
+}
+
+/* fs_ops table */
+static struct sysfs_ops pci_instance_ops = {
+ .show = edac_pci_instance_show,
+ .store = edac_pci_instance_store
+};
+
+#define INSTANCE_ATTR(_name, _mode, _show, _store) \
+static struct instance_attribute attr_instance_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
+INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
+
+/* pci instance attributes */
+static struct instance_attribute *pci_instance_attr[] = {
+ &attr_instance_pe_count,
+ &attr_instance_npe_count,
+ NULL
+};
+
+/* the ktype for a pci instance */
+static struct kobj_type ktype_pci_instance = {
+ .release = edac_pci_instance_release,
+ .sysfs_ops = &pci_instance_ops,
+ .default_attrs = (struct attribute **)pci_instance_attr,
+};
+
+/*
+ * edac_pci_create_instance_kobj
+ *
+ * construct one EDAC PCI instance's kobject for use
+ */
+static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+{
+ struct kobject *main_kobj;
+ int err;
+
+ debugf0("%s()\n", __func__);
+
+ /* Set the parent and the instance's ktype */
+ pci->kobj.parent = &edac_pci_top_main_kobj;
+ pci->kobj.ktype = &ktype_pci_instance;
+
+ err = kobject_set_name(&pci->kobj, "pci%d", idx);
+ if (err)
+ return err;
+
+ /* First bump the ref count on the top main kobj, which will
+ * track the number of PCI instances we have, and thus nest
+ * properly on keeping the module loaded
+ */
+ main_kobj = kobject_get(&edac_pci_top_main_kobj);
+ if (!main_kobj) {
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* And now register this new kobject under the main kobj */
+ err = kobject_register(&pci->kobj);
+ if (err != 0) {
+ debugf2("%s() failed to register instance pci%d\n",
+ __func__, idx);
+ kobject_put(&edac_pci_top_main_kobj);
+ goto error_out;
+ }
+
+ debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+
+ return 0;
+
+ /* Error unwind statck */
+error_out:
+ return err;
+}
+
+/*
+ * edac_pci_unregister_sysfs_instance_kobj
+ *
+ * unregister the kobj for the EDAC PCI instance
+ */
+void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
+{
+ debugf0("%s()\n", __func__);
+
+ /* Unregister the instance kobject and allow its release
+ * function release the main reference count and then
+ * kfree the memory
+ */
+ kobject_unregister(&pci->kobj);
+}
+
+/***************************** EDAC PCI sysfs root **********************/
+#define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
+
+/* simple show/store functions for attributes */
+static ssize_t edac_pci_int_show(void *ptr, char *buffer)
+{
+ int *value = ptr;
+ return sprintf(buffer, "%d\n", *value);
+}
+
+static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
+{
+ int *value = ptr;
+
+ if (isdigit(*buffer))
+ *value = simple_strtoul(buffer, NULL, 0);
+
+ return count;
+}
+
+struct edac_pci_dev_attribute {
+ struct attribute attr;
+ void *value;
+ ssize_t(*show) (void *, char *);
+ ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for PCI Parity object */
+static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct edac_pci_dev_attribute *edac_pci_dev;
+ edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+ if (edac_pci_dev->show)
+ return edac_pci_dev->show(edac_pci_dev->value, buffer);
+ return -EIO;
+}
+
+static ssize_t edac_pci_dev_store(struct kobject *kobj,
+ struct attribute *attr, const char *buffer,
+ size_t count)
+{
+ struct edac_pci_dev_attribute *edac_pci_dev;
+ edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+ if (edac_pci_dev->show)
+ return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
+ return -EIO;
+}
+
+static struct sysfs_ops edac_pci_sysfs_ops = {
+ .show = edac_pci_dev_show,
+ .store = edac_pci_dev_store
+};
+
+#define EDAC_PCI_ATTR(_name,_mode,_show,_store) \
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = &_name, \
+ .show = _show, \
+ .store = _store, \
+};
+
+#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = _data, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* PCI Parity control files */
+EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
+EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);
+
+/* Base Attributes of the memory ECC object */
+static struct edac_pci_dev_attribute *edac_pci_attr[] = {
+ &edac_pci_attr_check_pci_errors,
+ &edac_pci_attr_edac_pci_log_pe,
+ &edac_pci_attr_edac_pci_log_npe,
+ &edac_pci_attr_edac_pci_panic_on_pe,
+ &edac_pci_attr_pci_parity_count,
+ &edac_pci_attr_pci_nonparity_count,
+ NULL,
+};
+
+/*
+ * edac_pci_release_main_kobj
+ *
+ * This release function is called when the reference count to the
+ * passed kobj goes to zero.
+ *
+ * This kobj is the 'main' kobject that EDAC PCI instances
+ * link to, and thus provide for proper nesting counts
+ */
+static void edac_pci_release_main_kobj(struct kobject *kobj)
+{
+
+ debugf0("%s() here to module_put(THIS_MODULE)\n", __func__);
+
+ /* last reference to top EDAC PCI kobject has been removed,
+ * NOW release our ref count on the core module
+ */
+ module_put(THIS_MODULE);
+}
+
+/* ktype struct for the EDAC PCI main kobj */
+static struct kobj_type ktype_edac_pci_main_kobj = {
+ .release = edac_pci_release_main_kobj,
+ .sysfs_ops = &edac_pci_sysfs_ops,
+ .default_attrs = (struct attribute **)edac_pci_attr,
+};
+
+/**
+ * edac_pci_main_kobj_setup()
+ *
+ * setup the sysfs for EDAC PCI attributes
+ * assumes edac_class has already been initialized
+ */
+int edac_pci_main_kobj_setup(void)
+{
+ int err;
+ struct sysdev_class *edac_class;
+
+ debugf0("%s()\n", __func__);
+
+ /* check and count if we have already created the main kobject */
+ if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
+ return 0;
+
+ /* First time, so create the main kobject and its
+ * controls and atributes
+ */
+ edac_class = edac_get_edac_class();
+ if (edac_class == NULL) {
+ debugf1("%s() no edac_class\n", __func__);
+ err = -ENODEV;
+ goto decrement_count_fail;
+ }
+
+ /* Need the kobject hook ups, and name setting */
+ edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
+ edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
+
+ err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
+ if (err)
+ goto decrement_count_fail;
+
+ /* Bump the reference count on this module to ensure the
+ * modules isn't unloaded until we deconstruct the top
+ * level main kobj for EDAC PCI
+ */
+ if (!try_module_get(THIS_MODULE)) {
+ debugf1("%s() try_module_get() failed\n", __func__);
+ err = -ENODEV;
+ goto decrement_count_fail;
+ }
+
+ /* Instanstiate the pci object */
+ /* FIXME: maybe new sysdev_create_subdir() */
+ err = kobject_register(&edac_pci_top_main_kobj);
+ if (err) {
+ debugf1("Failed to register '.../edac/pci'\n");
+ goto kobject_register_fail;
+ }
+
+ /* At this point, to 'release' the top level kobject
+ * for EDAC PCI, then edac_pci_main_kobj_teardown()
+ * must be used, for resources to be cleaned up properly
+ */
+ debugf1("Registered '.../edac/pci' kobject\n");
+
+ return 0;
+
+ /* Error unwind statck */
+kobject_register_fail:
+ module_put(THIS_MODULE);
+
+decrement_count_fail:
+ /* if are on this error exit, nothing to tear down */
+ atomic_dec(&edac_pci_sysfs_refcount);
+
+ return err;
+}
+
+/*
+ * edac_pci_main_kobj_teardown()
+ *
+ * if no longer linked (needed) remove the top level EDAC PCI
+ * kobject with its controls and attributes
+ */
+static void edac_pci_main_kobj_teardown(void)
+{
+ debugf0("%s()\n", __func__);
+
+ /* Decrement the count and only if no more controller instances
+ * are connected perform the unregisteration of the top level
+ * main kobj
+ */
+ if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
+ debugf0("%s() called kobject_unregister on main kobj\n",
+ __func__);
+ kobject_unregister(&edac_pci_top_main_kobj);
+ }
+}
+
+/*
+ *
+ * edac_pci_create_sysfs
+ *
+ * Create the controls/attributes for the specified EDAC PCI device
+ */
+int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
+{
+ int err;
+ struct kobject *edac_kobj = &pci->kobj;
+
+ debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+
+ /* create the top main EDAC PCI kobject, IF needed */
+ err = edac_pci_main_kobj_setup();
+ if (err)
+ return err;
+
+ /* Create this instance's kobject under the MAIN kobject */
+ err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
+ if (err)
+ goto unregister_cleanup;
+
+ err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
+ if (err) {
+ debugf0("%s() sysfs_create_link() returned err= %d\n",
+ __func__, err);
+ goto symlink_fail;
+ }
+
+ return 0;
+
+ /* Error unwind stack */
+symlink_fail:
+ edac_pci_unregister_sysfs_instance_kobj(pci);
+
+unregister_cleanup:
+ edac_pci_main_kobj_teardown();
+
+ return err;
+}
+
+/*
+ * edac_pci_remove_sysfs
+ *
+ * remove the controls and attributes for this EDAC PCI device
+ */
+void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
+{
+ debugf0("%s() index=%d\n", __func__, pci->pci_idx);
+
+ /* Remove the symlink */
+ sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
+
+ /* remove this PCI instance's sysfs entries */
+ edac_pci_unregister_sysfs_instance_kobj(pci);
+
+ /* Call the main unregister function, which will determine
+ * if this 'pci' is the last instance.
+ * If it is, the main kobject will be unregistered as a result
+ */
+ debugf0("%s() calling edac_pci_main_kobj_teardown()\n", __func__);
+ edac_pci_main_kobj_teardown();
+}
+
+/************************ PCI error handling *************************/
+static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
+{
+ int where;
+ u16 status;
+
+ where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
+ pci_read_config_word(dev, where, &status);
+
+ /* If we get back 0xFFFF then we must suspect that the card has been
+ * pulled but the Linux PCI layer has not yet finished cleaning up.
+ * We don't want to report on such devices
+ */
+
+ if (status == 0xFFFF) {
+ u32 sanity;
+
+ pci_read_config_dword(dev, 0, &sanity);
+
+ if (sanity == 0xFFFFFFFF)
+ return 0;
+ }
+
+ status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
+ PCI_STATUS_PARITY;
+
+ if (status)
+ /* reset only the bits we are interested in */
+ pci_write_config_word(dev, where, status);
+
+ return status;
+}
+
+
+/* Clear any PCI parity errors logged by this device. */
+static void edac_pci_dev_parity_clear(struct pci_dev *dev)
+{
+ u8 header_type;
+
+ debugf0("%s()\n", __func__);
+
+ get_pci_parity_status(dev, 0);
+
+ /* read the device TYPE, looking for bridges */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
+ get_pci_parity_status(dev, 1);
+}
+
+/*
+ * PCI Parity polling
+ *
+ * Fucntion to retrieve the current parity status
+ * and decode it
+ *
+ */
+static void edac_pci_dev_parity_test(struct pci_dev *dev)
+{
+ unsigned long flags;
+ u16 status;
+ u8 header_type;
+
+ /* stop any interrupts until we can acquire the status */
+ local_irq_save(flags);
+
+ /* read the STATUS register on this device */
+ status = get_pci_parity_status(dev, 0);
+
+ /* read the device TYPE, looking for bridges */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ local_irq_restore(flags);
+
+ debugf4("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+ /* check the status reg for errors */
+ if (status) {
+ if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Signaled System Error on %s\n",
+ pci_name(dev));
+ atomic_inc(&pci_nonparity_count);
+ }
+
+ if (status & (PCI_STATUS_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Master Data Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+
+ if (status & (PCI_STATUS_DETECTED_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Detected Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+ }
+
+
+ debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);
+
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+ /* On bridges, need to examine secondary status register */
+ status = get_pci_parity_status(dev, 1);
+
+ debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+ /* check the secondary status reg for errors */
+ if (status) {
+ if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Signaled System Error on %s\n",
+ pci_name(dev));
+ atomic_inc(&pci_nonparity_count);
+ }
+
+ if (status & (PCI_STATUS_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Master Data Parity Error on "
+ "%s\n", pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+
+ if (status & (PCI_STATUS_DETECTED_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Detected Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+ }
+ }
+}
+
+/* reduce some complexity in definition of the iterator */
+typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
+
+/*
+ * pci_dev parity list iterator
+ * Scan the PCI device list for one pass, looking for SERRORs
+ * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
+ */
+static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
+{
+ struct pci_dev *dev = NULL;
+
+ /* request for kernel access to the next PCI device, if any,
+ * and while we are looking at it have its reference count
+ * bumped until we are done with it
+ */
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ fn(dev);
+ }
+}
+
+/*
+ * edac_pci_do_parity_check
+ *
+ * performs the actual PCI parity check operation
+ */
+void edac_pci_do_parity_check(void)
+{
+ int before_count;
+
+ debugf3("%s()\n", __func__);
+
+ /* if policy has PCI check off, leave now */
+ if (!check_pci_errors)
+ return;
+
+ before_count = atomic_read(&pci_parity_count);
+
+ /* scan all PCI devices looking for a Parity Error on devices and
+ * bridges.
+ * The iterator calls pci_get_device() which might sleep, thus
+ * we cannot disable interrupts in this scan.
+ */
+ edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
+
+ /* Only if operator has selected panic on PCI Error */
+ if (edac_pci_get_panic_on_pe()) {
+ /* If the count is different 'after' from 'before' */
+ if (before_count != atomic_read(&pci_parity_count))
+ panic("EDAC: PCI Parity Error");
+ }
+}
+
+/*
+ * edac_pci_clear_parity_errors
+ *
+ * function to perform an iteration over the PCI devices
+ * and clearn their current status
+ */
+void edac_pci_clear_parity_errors(void)
+{
+ /* Clear any PCI bus parity errors that devices initially have logged
+ * in their registers.
+ */
+ edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
+}
+
+/*
+ * edac_pci_handle_pe
+ *
+ * Called to handle a PARITY ERROR event
+ */
+void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+ /* global PE counter incremented by edac_pci_do_parity_check() */
+ atomic_inc(&pci->counters.pe_count);
+
+ if (edac_pci_get_log_pe())
+ edac_pci_printk(pci, KERN_WARNING,
+ "Parity Error ctl: %s %d: %s\n",
+ pci->ctl_name, pci->pci_idx, msg);
+
+ /*
+ * poke all PCI devices and see which one is the troublemaker
+ * panic() is called if set
+ */
+ edac_pci_do_parity_check();
+}
+EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
+
+
+/*
+ * edac_pci_handle_npe
+ *
+ * Called to handle a NON-PARITY ERROR event
+ */
+void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+ /* global NPE counter incremented by edac_pci_do_parity_check() */
+ atomic_inc(&pci->counters.npe_count);
+
+ if (edac_pci_get_log_npe())
+ edac_pci_printk(pci, KERN_WARNING,
+ "Non-Parity Error ctl: %s %d: %s\n",
+ pci->ctl_name, pci->pci_idx, msg);
+
+ /*
+ * poke all PCI devices and see which one is the troublemaker
+ * panic() is called if set
+ */
+ edac_pci_do_parity_check();
+}
+EXPORT_SYMBOL_GPL(edac_pci_handle_npe);
+
+/*
+ * Define the PCI parameter to the module
+ */
+module_param(check_pci_errors, int, 0644);
+MODULE_PARM_DESC(check_pci_errors,
+ "Check for PCI bus parity errors: 0=off 1=on");
+module_param(edac_pci_panic_on_pe, int, 0644);
+MODULE_PARM_DESC(edac_pci_panic_on_pe,
+ "Panic on PCI Bus Parity error: 0=off 1=on");
+
+#endif /* CONFIG_PCI */
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
new file mode 100644
index 000000000000..20b428aa155e
--- /dev/null
+++ b/drivers/edac/edac_stub.c
@@ -0,0 +1,46 @@
+/*
+ * common EDAC components that must be in kernel
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/edac.h>
+#include <asm/atomic.h>
+#include <asm/edac.h>
+
+int edac_op_state = EDAC_OPSTATE_INVAL;
+EXPORT_SYMBOL_GPL(edac_op_state);
+
+atomic_t edac_handlers = ATOMIC_INIT(0);
+EXPORT_SYMBOL_GPL(edac_handlers);
+
+int edac_err_assert = 0;
+EXPORT_SYMBOL_GPL(edac_err_assert);
+
+/*
+ * called to determine if there is an EDAC driver interested in
+ * knowing an event (such as NMI) occurred
+ */
+int edac_handler_set(void)
+{
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ return 0;
+
+ return atomic_read(&edac_handlers);
+}
+EXPORT_SYMBOL_GPL(edac_handler_set);
+
+/*
+ * handler for NMI type of interrupts to assert error
+ */
+void edac_atomic_assert_error(void)
+{
+ edac_err_assert++;
+}
+EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
new file mode 100644
index 000000000000..e895f9f887ab
--- /dev/null
+++ b/drivers/edac/i3000_edac.c
@@ -0,0 +1,506 @@
+/*
+ * Intel 3000/3010 Memory Controller kernel module
+ * Copyright (C) 2007 Akamai Technologies, Inc.
+ * Shamelessly copied from:
+ * Intel D82875P Memory Controller kernel module
+ * (C) 2003 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define I3000_REVISION "1.1"
+
+#define EDAC_MOD_STR "i3000_edac"
+
+#define I3000_RANKS 8
+#define I3000_RANKS_PER_CHANNEL 4
+#define I3000_CHANNELS 2
+
+/* Intel 3000 register addresses - device 0 function 0 - DRAM Controller */
+
+#define I3000_MCHBAR 0x44 /* MCH Memory Mapped Register BAR */
+#define I3000_MCHBAR_MASK 0xffffc000
+#define I3000_MMR_WINDOW_SIZE 16384
+
+#define I3000_EDEAP 0x70 /* Extended DRAM Error Address Pointer (8b)
+ *
+ * 7:1 reserved
+ * 0 bit 32 of address
+ */
+#define I3000_DEAP 0x58 /* DRAM Error Address Pointer (32b)
+ *
+ * 31:7 address
+ * 6:1 reserved
+ * 0 Error channel 0/1
+ */
+#define I3000_DEAP_GRAIN (1 << 7)
+#define I3000_DEAP_PFN(edeap, deap) ((((edeap) & 1) << (32 - PAGE_SHIFT)) | \
+ ((deap) >> PAGE_SHIFT))
+#define I3000_DEAP_OFFSET(deap) ((deap) & ~(I3000_DEAP_GRAIN-1) & ~PAGE_MASK)
+#define I3000_DEAP_CHANNEL(deap) ((deap) & 1)
+
+#define I3000_DERRSYN 0x5c /* DRAM Error Syndrome (8b)
+ *
+ * 7:0 DRAM ECC Syndrome
+ */
+
+#define I3000_ERRSTS 0xc8 /* Error Status Register (16b)
+ *
+ * 15:12 reserved
+ * 11 MCH Thermal Sensor Event for SMI/SCI/SERR
+ * 10 reserved
+ * 9 LOCK to non-DRAM Memory Flag (LCKF)
+ * 8 Received Refresh Timeout Flag (RRTOF)
+ * 7:2 reserved
+ * 1 Multiple-bit DRAM ECC Error Flag (DMERR)
+ * 0 Single-bit DRAM ECC Error Flag (DSERR)
+ */
+#define I3000_ERRSTS_BITS 0x0b03 /* bits which indicate errors */
+#define I3000_ERRSTS_UE 0x0002
+#define I3000_ERRSTS_CE 0x0001
+
+#define I3000_ERRCMD 0xca /* Error Command (16b)
+ *
+ * 15:12 reserved
+ * 11 SERR on MCH Thermal Sensor Event (TSESERR)
+ * 10 reserved
+ * 9 SERR on LOCK to non-DRAM Memory (LCKERR)
+ * 8 SERR on DRAM Refresh Timeout (DRTOERR)
+ * 7:2 reserved
+ * 1 SERR Multiple-Bit DRAM ECC Error (DMERR)
+ * 0 SERR on Single-Bit ECC Error (DSERR)
+ */
+
+/* Intel MMIO register space - device 0 function 0 - MMR space */
+
+#define I3000_DRB_SHIFT 25 /* 32MiB grain */
+
+#define I3000_C0DRB 0x100 /* Channel 0 DRAM Rank Boundary (8b x 4)
+ *
+ * 7:0 Channel 0 DRAM Rank Boundary Address
+ */
+#define I3000_C1DRB 0x180 /* Channel 1 DRAM Rank Boundary (8b x 4)
+ *
+ * 7:0 Channel 1 DRAM Rank Boundary Address
+ */
+
+#define I3000_C0DRA 0x108 /* Channel 0 DRAM Rank Attribute (8b x 2)
+ *
+ * 7 reserved
+ * 6:4 DRAM odd Rank Attribute
+ * 3 reserved
+ * 2:0 DRAM even Rank Attribute
+ *
+ * Each attribute defines the page
+ * size of the corresponding rank:
+ * 000: unpopulated
+ * 001: reserved
+ * 010: 4 KB
+ * 011: 8 KB
+ * 100: 16 KB
+ * Others: reserved
+ */
+#define I3000_C1DRA 0x188 /* Channel 1 DRAM Rank Attribute (8b x 2) */
+#define ODD_RANK_ATTRIB(dra) (((dra) & 0x70) >> 4)
+#define EVEN_RANK_ATTRIB(dra) ((dra) & 0x07)
+
+#define I3000_C0DRC0 0x120 /* DRAM Controller Mode 0 (32b)
+ *
+ * 31:30 reserved
+ * 29 Initialization Complete (IC)
+ * 28:11 reserved
+ * 10:8 Refresh Mode Select (RMS)
+ * 7 reserved
+ * 6:4 Mode Select (SMS)
+ * 3:2 reserved
+ * 1:0 DRAM Type (DT)
+ */
+
+#define I3000_C0DRC1 0x124 /* DRAM Controller Mode 1 (32b)
+ *
+ * 31 Enhanced Addressing Enable (ENHADE)
+ * 30:0 reserved
+ */
+
+enum i3000p_chips {
+ I3000 = 0,
+};
+
+struct i3000_dev_info {
+ const char *ctl_name;
+};
+
+struct i3000_error_info {
+ u16 errsts;
+ u8 derrsyn;
+ u8 edeap;
+ u32 deap;
+ u16 errsts2;
+};
+
+static const struct i3000_dev_info i3000_devs[] = {
+ [I3000] = {
+ .ctl_name = "i3000"},
+};
+
+static struct pci_dev *mci_pdev;
+static int i3000_registered = 1;
+static struct edac_pci_ctl_info *i3000_pci;
+
+static void i3000_get_error_info(struct mem_ctl_info *mci,
+ struct i3000_error_info *info)
+{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+
+ /*
+ * This is a mess because there is no atomic way to read all the
+ * registers at once and the registers can transition from CE being
+ * overwritten by UE.
+ */
+ pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts);
+ if (!(info->errsts & I3000_ERRSTS_BITS))
+ return;
+ pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+ pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+ pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+ pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts2);
+
+ /*
+ * If the error is the same for both reads then the first set
+ * of reads is valid. If there is a change then there is a CE
+ * with no info and the second set of reads is valid and
+ * should be UE info.
+ */
+ if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+ pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+ pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+ pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+ }
+
+ /* Clear any error bits.
+ * (Yes, we really clear bits by writing 1 to them.)
+ */
+ pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+ I3000_ERRSTS_BITS);
+}
+
+static int i3000_process_error_info(struct mem_ctl_info *mci,
+ struct i3000_error_info *info,
+ int handle_errors)
+{
+ int row, multi_chan;
+ int pfn, offset, channel;
+
+ multi_chan = mci->csrows[0].nr_channels - 1;
+
+ if (!(info->errsts & I3000_ERRSTS_BITS))
+ return 0;
+
+ if (!handle_errors)
+ return 1;
+
+ if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+ edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+ info->errsts = info->errsts2;
+ }
+
+ pfn = I3000_DEAP_PFN(info->edeap, info->deap);
+ offset = I3000_DEAP_OFFSET(info->deap);
+ channel = I3000_DEAP_CHANNEL(info->deap);
+
+ row = edac_mc_find_csrow_by_page(mci, pfn);
+
+ if (info->errsts & I3000_ERRSTS_UE)
+ edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE");
+ else
+ edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row,
+ multi_chan ? channel : 0, "i3000 CE");
+
+ return 1;
+}
+
+static void i3000_check(struct mem_ctl_info *mci)
+{
+ struct i3000_error_info info;
+
+ debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+ i3000_get_error_info(mci, &info);
+ i3000_process_error_info(mci, &info, 1);
+}
+
+static int i3000_is_interleaved(const unsigned char *c0dra,
+ const unsigned char *c1dra,
+ const unsigned char *c0drb,
+ const unsigned char *c1drb)
+{
+ int i;
+
+ /* If the channels aren't populated identically then
+ * we're not interleaved.
+ */
+ for (i = 0; i < I3000_RANKS_PER_CHANNEL / 2; i++)
+ if (ODD_RANK_ATTRIB(c0dra[i]) != ODD_RANK_ATTRIB(c1dra[i]) ||
+ EVEN_RANK_ATTRIB(c0dra[i]) !=
+ EVEN_RANK_ATTRIB(c1dra[i]))
+ return 0;
+
+ /* If the rank boundaries for the two channels are different
+ * then we're not interleaved.
+ */
+ for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++)
+ if (c0drb[i] != c1drb[i])
+ return 0;
+
+ return 1;
+}
+
+static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ int rc;
+ int i;
+ struct mem_ctl_info *mci = NULL;
+ unsigned long last_cumul_size;
+ int interleaved, nr_channels;
+ unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS];
+ unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2];
+ unsigned char *c0drb = drb, *c1drb = &drb[I3000_RANKS_PER_CHANNEL];
+ unsigned long mchbar;
+ void __iomem *window;
+
+ debugf0("MC: %s()\n", __func__);
+
+ pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar);
+ mchbar &= I3000_MCHBAR_MASK;
+ window = ioremap_nocache(mchbar, I3000_MMR_WINDOW_SIZE);
+ if (!window) {
+ printk(KERN_ERR "i3000: cannot map mmio space at 0x%lx\n",
+ mchbar);
+ return -ENODEV;
+ }
+
+ 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 */
+ c1dra[1] = readb(window + I3000_C1DRA + 1); /* ranks 2,3 */
+
+ for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++) {
+ c0drb[i] = readb(window + I3000_C0DRB + i);
+ c1drb[i] = readb(window + I3000_C1DRB + i);
+ }
+
+ iounmap(window);
+
+ /* Figure out how many channels we have.
+ *
+ * If we have what the datasheet calls "asymmetric channels"
+ * (essentially the same as what was called "virtual single
+ * channel mode" in the i82875) then it's a single channel as
+ * far as EDAC is concerned.
+ */
+ interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb);
+ nr_channels = interleaved ? 2 : 1;
+ mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0);
+ if (!mci)
+ return -ENOMEM;
+
+ debugf3("MC: %s(): init mci\n", __func__);
+
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR2;
+
+ mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_SECDED;
+
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I3000_REVISION;
+ mci->ctl_name = i3000_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
+ mci->edac_check = i3000_check;
+ mci->ctl_page_to_phys = NULL;
+
+ /*
+ * The dram rank boundary (DRB) reg values are boundary addresses
+ * for each DRAM rank with a granularity of 32MB. DRB regs are
+ * cumulative; the last one will contain the total memory
+ * contained in all ranks.
+ *
+ * If we're in interleaved mode then we're only walking through
+ * the ranks of controller 0, so we double all the values we see.
+ */
+ for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
+ u8 value;
+ u32 cumul_size;
+ struct csrow_info *csrow = &mci->csrows[i];
+
+ value = drb[i];
+ cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
+ if (interleaved)
+ cumul_size <<= 1;
+ debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
+ __func__, i, cumul_size);
+ if (cumul_size == last_cumul_size) {
+ csrow->mtype = MEM_EMPTY;
+ continue;
+ }
+
+ csrow->first_page = last_cumul_size;
+ csrow->last_page = cumul_size - 1;
+ csrow->nr_pages = cumul_size - last_cumul_size;
+ last_cumul_size = cumul_size;
+ csrow->grain = I3000_DEAP_GRAIN;
+ csrow->mtype = MEM_DDR2;
+ csrow->dtype = DEV_UNKNOWN;
+ csrow->edac_mode = EDAC_UNKNOWN;
+ }
+
+ /* Clear any error bits.
+ * (Yes, we really clear bits by writing 1 to them.)
+ */
+ pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+ I3000_ERRSTS_BITS);
+
+ rc = -ENODEV;
+ if (edac_mc_add_mc(mci)) {
+ debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail;
+ }
+
+ /* allocating generic PCI control info */
+ i3000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i3000_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ /* get this far and it's successful */
+ debugf3("MC: %s(): success\n", __func__);
+ return 0;
+
+ fail:
+ if (mci)
+ edac_mc_free(mci);
+
+ return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i3000_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ debugf0("MC: %s()\n", __func__);
+
+ if (pci_enable_device(pdev) < 0)
+ return -EIO;
+
+ rc = i3000_probe1(pdev, ent->driver_data);
+ if (mci_pdev == NULL)
+ mci_pdev = pci_dev_get(pdev);
+
+ return rc;
+}
+
+static void __devexit i3000_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+
+ debugf0("%s()\n", __func__);
+
+ if (i3000_pci)
+ edac_pci_release_generic_ctl(i3000_pci);
+
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+ return;
+
+ edac_mc_free(mci);
+}
+
+static const struct pci_device_id i3000_pci_tbl[] __devinitdata = {
+ {
+ PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I3000},
+ {
+ 0,
+ } /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i3000_pci_tbl);
+
+static struct pci_driver i3000_driver = {
+ .name = EDAC_MOD_STR,
+ .probe = i3000_init_one,
+ .remove = __devexit_p(i3000_remove_one),
+ .id_table = i3000_pci_tbl,
+};
+
+static int __init i3000_init(void)
+{
+ int pci_rc;
+
+ debugf3("MC: %s()\n", __func__);
+ pci_rc = pci_register_driver(&i3000_driver);
+ if (pci_rc < 0)
+ goto fail0;
+
+ if (mci_pdev == NULL) {
+ i3000_registered = 0;
+ mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_3000_HB, NULL);
+ if (!mci_pdev) {
+ debugf0("i3000 pci_get_device fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+
+ pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl);
+ if (pci_rc < 0) {
+ debugf0("i3000 init fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+ }
+
+ return 0;
+
+fail1:
+ pci_unregister_driver(&i3000_driver);
+
+fail0:
+ if (mci_pdev)
+ pci_dev_put(mci_pdev);
+
+ return pci_rc;
+}
+
+static void __exit i3000_exit(void)
+{
+ debugf3("MC: %s()\n", __func__);
+
+ pci_unregister_driver(&i3000_driver);
+ if (!i3000_registered) {
+ i3000_remove_one(mci_pdev);
+ pci_dev_put(mci_pdev);
+ }
+}
+
+module_init(i3000_init);
+module_exit(i3000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akamai Technologies Arthur Ulfeldt/Jason Uhlenkott");
+MODULE_DESCRIPTION("MC support for Intel 3000 memory hub controllers");
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
new file mode 100644
index 000000000000..96f7e63e3996
--- /dev/null
+++ b/drivers/edac/i5000_edac.c
@@ -0,0 +1,1505 @@
+/*
+ * Intel 5000(P/V/X) class Memory Controllers kernel module
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Douglas Thompson Linux Networx (http://lnxi.com)
+ * norsk5@xmission.com
+ *
+ * This module is based on the following document:
+ *
+ * Intel 5000X Chipset Memory Controller Hub (MCH) - Datasheet
+ * http://developer.intel.com/design/chipsets/datashts/313070.htm
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/edac.h>
+#include <asm/mmzone.h>
+
+#include "edac_core.h"
+
+/*
+ * Alter this version for the I5000 module when modifications are made
+ */
+#define I5000_REVISION " Ver: 2.0.12 " __DATE__
+#define EDAC_MOD_STR "i5000_edac"
+
+#define i5000_printk(level, fmt, arg...) \
+ edac_printk(level, "i5000", fmt, ##arg)
+
+#define i5000_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i5000", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_FBD_0
+#define PCI_DEVICE_ID_INTEL_FBD_0 0x25F5
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_FBD_1
+#define PCI_DEVICE_ID_INTEL_FBD_1 0x25F6
+#endif
+
+/* Device 16,
+ * Function 0: System Address
+ * Function 1: Memory Branch Map, Control, Errors Register
+ * Function 2: FSB Error Registers
+ *
+ * All 3 functions of Device 16 (0,1,2) share the SAME DID
+ */
+#define PCI_DEVICE_ID_INTEL_I5000_DEV16 0x25F0
+
+/* OFFSETS for Function 0 */
+
+/* OFFSETS for Function 1 */
+#define AMBASE 0x48
+#define MAXCH 0x56
+#define MAXDIMMPERCH 0x57
+#define TOLM 0x6C
+#define REDMEMB 0x7C
+#define RED_ECC_LOCATOR(x) ((x) & 0x3FFFF)
+#define REC_ECC_LOCATOR_EVEN(x) ((x) & 0x001FF)
+#define REC_ECC_LOCATOR_ODD(x) ((x) & 0x3FE00)
+#define MIR0 0x80
+#define MIR1 0x84
+#define MIR2 0x88
+#define AMIR0 0x8C
+#define AMIR1 0x90
+#define AMIR2 0x94
+
+#define FERR_FAT_FBD 0x98
+#define NERR_FAT_FBD 0x9C
+#define EXTRACT_FBDCHAN_INDX(x) (((x)>>28) & 0x3)
+#define FERR_FAT_FBDCHAN 0x30000000
+#define FERR_FAT_M3ERR 0x00000004
+#define FERR_FAT_M2ERR 0x00000002
+#define FERR_FAT_M1ERR 0x00000001
+#define FERR_FAT_MASK (FERR_FAT_M1ERR | \
+ FERR_FAT_M2ERR | \
+ FERR_FAT_M3ERR)
+
+#define FERR_NF_FBD 0xA0
+
+/* Thermal and SPD or BFD errors */
+#define FERR_NF_M28ERR 0x01000000
+#define FERR_NF_M27ERR 0x00800000
+#define FERR_NF_M26ERR 0x00400000
+#define FERR_NF_M25ERR 0x00200000
+#define FERR_NF_M24ERR 0x00100000
+#define FERR_NF_M23ERR 0x00080000
+#define FERR_NF_M22ERR 0x00040000
+#define FERR_NF_M21ERR 0x00020000
+
+/* Correctable errors */
+#define FERR_NF_M20ERR 0x00010000
+#define FERR_NF_M19ERR 0x00008000
+#define FERR_NF_M18ERR 0x00004000
+#define FERR_NF_M17ERR 0x00002000
+
+/* Non-Retry or redundant Retry errors */
+#define FERR_NF_M16ERR 0x00001000
+#define FERR_NF_M15ERR 0x00000800
+#define FERR_NF_M14ERR 0x00000400
+#define FERR_NF_M13ERR 0x00000200
+
+/* Uncorrectable errors */
+#define FERR_NF_M12ERR 0x00000100
+#define FERR_NF_M11ERR 0x00000080
+#define FERR_NF_M10ERR 0x00000040
+#define FERR_NF_M9ERR 0x00000020
+#define FERR_NF_M8ERR 0x00000010
+#define FERR_NF_M7ERR 0x00000008
+#define FERR_NF_M6ERR 0x00000004
+#define FERR_NF_M5ERR 0x00000002
+#define FERR_NF_M4ERR 0x00000001
+
+#define FERR_NF_UNCORRECTABLE (FERR_NF_M12ERR | \
+ FERR_NF_M11ERR | \
+ FERR_NF_M10ERR | \
+ FERR_NF_M8ERR | \
+ FERR_NF_M7ERR | \
+ FERR_NF_M6ERR | \
+ FERR_NF_M5ERR | \
+ FERR_NF_M4ERR)
+#define FERR_NF_CORRECTABLE (FERR_NF_M20ERR | \
+ FERR_NF_M19ERR | \
+ FERR_NF_M18ERR | \
+ FERR_NF_M17ERR)
+#define FERR_NF_DIMM_SPARE (FERR_NF_M27ERR | \
+ FERR_NF_M28ERR)
+#define FERR_NF_THERMAL (FERR_NF_M26ERR | \
+ FERR_NF_M25ERR | \
+ FERR_NF_M24ERR | \
+ FERR_NF_M23ERR)
+#define FERR_NF_SPD_PROTOCOL (FERR_NF_M22ERR)
+#define FERR_NF_NORTH_CRC (FERR_NF_M21ERR)
+#define FERR_NF_NON_RETRY (FERR_NF_M13ERR | \
+ FERR_NF_M14ERR | \
+ FERR_NF_M15ERR)
+
+#define NERR_NF_FBD 0xA4
+#define FERR_NF_MASK (FERR_NF_UNCORRECTABLE | \
+ FERR_NF_CORRECTABLE | \
+ FERR_NF_DIMM_SPARE | \
+ FERR_NF_THERMAL | \
+ FERR_NF_SPD_PROTOCOL | \
+ FERR_NF_NORTH_CRC | \
+ FERR_NF_NON_RETRY)
+
+#define EMASK_FBD 0xA8
+#define EMASK_FBD_M28ERR 0x08000000
+#define EMASK_FBD_M27ERR 0x04000000
+#define EMASK_FBD_M26ERR 0x02000000
+#define EMASK_FBD_M25ERR 0x01000000
+#define EMASK_FBD_M24ERR 0x00800000
+#define EMASK_FBD_M23ERR 0x00400000
+#define EMASK_FBD_M22ERR 0x00200000
+#define EMASK_FBD_M21ERR 0x00100000
+#define EMASK_FBD_M20ERR 0x00080000
+#define EMASK_FBD_M19ERR 0x00040000
+#define EMASK_FBD_M18ERR 0x00020000
+#define EMASK_FBD_M17ERR 0x00010000
+
+#define EMASK_FBD_M15ERR 0x00004000
+#define EMASK_FBD_M14ERR 0x00002000
+#define EMASK_FBD_M13ERR 0x00001000
+#define EMASK_FBD_M12ERR 0x00000800
+#define EMASK_FBD_M11ERR 0x00000400
+#define EMASK_FBD_M10ERR 0x00000200
+#define EMASK_FBD_M9ERR 0x00000100
+#define EMASK_FBD_M8ERR 0x00000080
+#define EMASK_FBD_M7ERR 0x00000040
+#define EMASK_FBD_M6ERR 0x00000020
+#define EMASK_FBD_M5ERR 0x00000010
+#define EMASK_FBD_M4ERR 0x00000008
+#define EMASK_FBD_M3ERR 0x00000004
+#define EMASK_FBD_M2ERR 0x00000002
+#define EMASK_FBD_M1ERR 0x00000001
+
+#define ENABLE_EMASK_FBD_FATAL_ERRORS (EMASK_FBD_M1ERR | \
+ EMASK_FBD_M2ERR | \
+ EMASK_FBD_M3ERR)
+
+#define ENABLE_EMASK_FBD_UNCORRECTABLE (EMASK_FBD_M4ERR | \
+ EMASK_FBD_M5ERR | \
+ EMASK_FBD_M6ERR | \
+ EMASK_FBD_M7ERR | \
+ EMASK_FBD_M8ERR | \
+ EMASK_FBD_M9ERR | \
+ EMASK_FBD_M10ERR | \
+ EMASK_FBD_M11ERR | \
+ EMASK_FBD_M12ERR)
+#define ENABLE_EMASK_FBD_CORRECTABLE (EMASK_FBD_M17ERR | \
+ EMASK_FBD_M18ERR | \
+ EMASK_FBD_M19ERR | \
+ EMASK_FBD_M20ERR)
+#define ENABLE_EMASK_FBD_DIMM_SPARE (EMASK_FBD_M27ERR | \
+ EMASK_FBD_M28ERR)
+#define ENABLE_EMASK_FBD_THERMALS (EMASK_FBD_M26ERR | \
+ EMASK_FBD_M25ERR | \
+ EMASK_FBD_M24ERR | \
+ EMASK_FBD_M23ERR)
+#define ENABLE_EMASK_FBD_SPD_PROTOCOL (EMASK_FBD_M22ERR)
+#define ENABLE_EMASK_FBD_NORTH_CRC (EMASK_FBD_M21ERR)
+#define ENABLE_EMASK_FBD_NON_RETRY (EMASK_FBD_M15ERR | \
+ EMASK_FBD_M14ERR | \
+ EMASK_FBD_M13ERR)
+
+#define ENABLE_EMASK_ALL (ENABLE_EMASK_FBD_NON_RETRY | \
+ ENABLE_EMASK_FBD_NORTH_CRC | \
+ ENABLE_EMASK_FBD_SPD_PROTOCOL | \
+ ENABLE_EMASK_FBD_THERMALS | \
+ ENABLE_EMASK_FBD_DIMM_SPARE | \
+ ENABLE_EMASK_FBD_FATAL_ERRORS | \
+ ENABLE_EMASK_FBD_CORRECTABLE | \
+ ENABLE_EMASK_FBD_UNCORRECTABLE)
+
+#define ERR0_FBD 0xAC
+#define ERR1_FBD 0xB0
+#define ERR2_FBD 0xB4
+#define MCERR_FBD 0xB8
+#define NRECMEMA 0xBE
+#define NREC_BANK(x) (((x)>>12) & 0x7)
+#define NREC_RDWR(x) (((x)>>11) & 1)
+#define NREC_RANK(x) (((x)>>8) & 0x7)
+#define NRECMEMB 0xC0
+#define NREC_CAS(x) (((x)>>16) & 0xFFFFFF)
+#define NREC_RAS(x) ((x) & 0x7FFF)
+#define NRECFGLOG 0xC4
+#define NREEECFBDA 0xC8
+#define NREEECFBDB 0xCC
+#define NREEECFBDC 0xD0
+#define NREEECFBDD 0xD4
+#define NREEECFBDE 0xD8
+#define REDMEMA 0xDC
+#define RECMEMA 0xE2
+#define REC_BANK(x) (((x)>>12) & 0x7)
+#define REC_RDWR(x) (((x)>>11) & 1)
+#define REC_RANK(x) (((x)>>8) & 0x7)
+#define RECMEMB 0xE4
+#define REC_CAS(x) (((x)>>16) & 0xFFFFFF)
+#define REC_RAS(x) ((x) & 0x7FFF)
+#define RECFGLOG 0xE8
+#define RECFBDA 0xEC
+#define RECFBDB 0xF0
+#define RECFBDC 0xF4
+#define RECFBDD 0xF8
+#define RECFBDE 0xFC
+
+/* OFFSETS for Function 2 */
+
+/*
+ * Device 21,
+ * Function 0: Memory Map Branch 0
+ *
+ * Device 22,
+ * Function 0: Memory Map Branch 1
+ */
+#define PCI_DEVICE_ID_I5000_BRANCH_0 0x25F5
+#define PCI_DEVICE_ID_I5000_BRANCH_1 0x25F6
+
+#define AMB_PRESENT_0 0x64
+#define AMB_PRESENT_1 0x66
+#define MTR0 0x80
+#define MTR1 0x84
+#define MTR2 0x88
+#define MTR3 0x8C
+
+#define NUM_MTRS 4
+#define CHANNELS_PER_BRANCH (2)
+
+/* Defines to extract the vaious fields from the
+ * MTRx - Memory Technology Registers
+ */
+#define MTR_DIMMS_PRESENT(mtr) ((mtr) & (0x1 << 8))
+#define MTR_DRAM_WIDTH(mtr) ((((mtr) >> 6) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS(mtr) ((((mtr) >> 5) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS_ADDR_BITS(mtr) ((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2)
+#define MTR_DIMM_RANK(mtr) (((mtr) >> 4) & 0x1)
+#define MTR_DIMM_RANK_ADDR_BITS(mtr) (MTR_DIMM_RANK(mtr) ? 2 : 1)
+#define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3)
+#define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13)
+#define MTR_DIMM_COLS(mtr) ((mtr) & 0x3)
+#define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10)
+
+#ifdef CONFIG_EDAC_DEBUG
+static char *numrow_toString[] = {
+ "8,192 - 13 rows",
+ "16,384 - 14 rows",
+ "32,768 - 15 rows",
+ "reserved"
+};
+
+static char *numcol_toString[] = {
+ "1,024 - 10 columns",
+ "2,048 - 11 columns",
+ "4,096 - 12 columns",
+ "reserved"
+};
+#endif
+
+/* Enumeration of supported devices */
+enum i5000_chips {
+ I5000P = 0,
+ I5000V = 1, /* future */
+ I5000X = 2 /* future */
+};
+
+/* Device name and register DID (Device ID) */
+struct i5000_dev_info {
+ const char *ctl_name; /* name for this device */
+ u16 fsb_mapping_errors; /* DID for the branchmap,control */
+};
+
+/* Table of devices attributes supported by this driver */
+static const struct i5000_dev_info i5000_devs[] = {
+ [I5000P] = {
+ .ctl_name = "I5000",
+ .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I5000_DEV16,
+ },
+};
+
+struct i5000_dimm_info {
+ int megabytes; /* size, 0 means not present */
+ int dual_rank;
+};
+
+#define MAX_CHANNELS 6 /* max possible channels */
+#define MAX_CSROWS (8*2) /* max possible csrows per channel */
+
+/* driver private data structure */
+struct i5000_pvt {
+ struct pci_dev *system_address; /* 16.0 */
+ struct pci_dev *branchmap_werrors; /* 16.1 */
+ struct pci_dev *fsb_error_regs; /* 16.2 */
+ struct pci_dev *branch_0; /* 21.0 */
+ struct pci_dev *branch_1; /* 22.0 */
+
+ u16 tolm; /* top of low memory */
+ u64 ambase; /* AMB BAR */
+
+ u16 mir0, mir1, mir2;
+
+ u16 b0_mtr[NUM_MTRS]; /* Memory Technlogy Reg */
+ u16 b0_ambpresent0; /* Branch 0, Channel 0 */
+ u16 b0_ambpresent1; /* Brnach 0, Channel 1 */
+
+ u16 b1_mtr[NUM_MTRS]; /* Memory Technlogy Reg */
+ u16 b1_ambpresent0; /* Branch 1, Channel 8 */
+ u16 b1_ambpresent1; /* Branch 1, Channel 1 */
+
+ /* DIMM infomation matrix, allocating architecture maximums */
+ struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
+
+ /* Actual values for this controller */
+ int maxch; /* Max channels */
+ int maxdimmperch; /* Max DIMMs per channel */
+};
+
+/* I5000 MCH error information retrieved from Hardware */
+struct i5000_error_info {
+
+ /* These registers are always read from the MC */
+ u32 ferr_fat_fbd; /* First Errors Fatal */
+ u32 nerr_fat_fbd; /* Next Errors Fatal */
+ u32 ferr_nf_fbd; /* First Errors Non-Fatal */
+ u32 nerr_nf_fbd; /* Next Errors Non-Fatal */
+
+ /* These registers are input ONLY if there was a Recoverable Error */
+ u32 redmemb; /* Recoverable Mem Data Error log B */
+ u16 recmema; /* Recoverable Mem Error log A */
+ u32 recmemb; /* Recoverable Mem Error log B */
+
+ /* These registers are input ONLY if there was a
+ * Non-Recoverable Error */
+ u16 nrecmema; /* Non-Recoverable Mem log A */
+ u16 nrecmemb; /* Non-Recoverable Mem log B */
+
+};
+
+static struct edac_pci_ctl_info *i5000_pci;
+
+/*
+ * i5000_get_error_info Retrieve the hardware error information from
+ * the hardware and cache it in the 'info'
+ * structure
+ */
+static void i5000_get_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info)
+{
+ struct i5000_pvt *pvt;
+ u32 value;
+
+ pvt = mci->pvt_info;
+
+ /* read in the 1st FATAL error register */
+ pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value);
+
+ /* Mask only the bits that the doc says are valid
+ */
+ value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK);
+
+ /* If there is an error, then read in the */
+ /* NEXT FATAL error register and the Memory Error Log Register A */
+ if (value & FERR_FAT_MASK) {
+ info->ferr_fat_fbd = value;
+
+ /* harvest the various error data we need */
+ pci_read_config_dword(pvt->branchmap_werrors,
+ NERR_FAT_FBD, &info->nerr_fat_fbd);
+ pci_read_config_word(pvt->branchmap_werrors,
+ NRECMEMA, &info->nrecmema);
+ pci_read_config_word(pvt->branchmap_werrors,
+ NRECMEMB, &info->nrecmemb);
+
+ /* Clear the error bits, by writing them back */
+ pci_write_config_dword(pvt->branchmap_werrors,
+ FERR_FAT_FBD, value);
+ } else {
+ info->ferr_fat_fbd = 0;
+ info->nerr_fat_fbd = 0;
+ info->nrecmema = 0;
+ info->nrecmemb = 0;
+ }
+
+ /* read in the 1st NON-FATAL error register */
+ pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value);
+
+ /* If there is an error, then read in the 1st NON-FATAL error
+ * register as well */
+ if (value & FERR_NF_MASK) {
+ info->ferr_nf_fbd = value;
+
+ /* harvest the various error data we need */
+ pci_read_config_dword(pvt->branchmap_werrors,
+ NERR_NF_FBD, &info->nerr_nf_fbd);
+ pci_read_config_word(pvt->branchmap_werrors,
+ RECMEMA, &info->recmema);
+ pci_read_config_dword(pvt->branchmap_werrors,
+ RECMEMB, &info->recmemb);
+ pci_read_config_dword(pvt->branchmap_werrors,
+ REDMEMB, &info->redmemb);
+
+ /* Clear the error bits, by writing them back */
+ pci_write_config_dword(pvt->branchmap_werrors,
+ FERR_NF_FBD, value);
+ } else {
+ info->ferr_nf_fbd = 0;
+ info->nerr_nf_fbd = 0;
+ info->recmema = 0;
+ info->recmemb = 0;
+ info->redmemb = 0;
+ }
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ * struct i5000_error_info *info,
+ * int handle_errors);
+ *
+ * handle the Intel FATAL errors, if any
+ */
+static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info,
+ int handle_errors)
+{
+ char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+ u32 allErrors;
+ int branch;
+ int channel;
+ int bank;
+ int rank;
+ int rdwr;
+ int ras, cas;
+
+ /* mask off the Error bits that are possible */
+ allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK);
+ if (!allErrors)
+ return; /* if no error, return now */
+
+ /* ONLY ONE of the possible error bits will be set, as per the docs */
+ i5000_mc_printk(mci, KERN_ERR,
+ "FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",
+ allErrors);
+
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
+ channel = branch;
+
+ /* Use the NON-Recoverable macros to extract data */
+ bank = NREC_BANK(info->nrecmema);
+ rank = NREC_RANK(info->nrecmema);
+ rdwr = NREC_RDWR(info->nrecmema);
+ ras = NREC_RAS(info->nrecmemb);
+ cas = NREC_CAS(info->nrecmemb);
+
+ debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d "
+ "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+ rank, channel, channel + 1, branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas);
+
+ /* Only 1 bit will be on */
+ if (allErrors & FERR_FAT_M1ERR) {
+ i5000_mc_printk(mci, KERN_ERR,
+ "Alert on non-redundant retry or fast "
+ "reset timeout\n");
+
+ } else if (allErrors & FERR_FAT_M2ERR) {
+ i5000_mc_printk(mci, KERN_ERR,
+ "Northbound CRC error on non-redundant "
+ "retry\n");
+
+ } else if (allErrors & FERR_FAT_M3ERR) {
+ i5000_mc_printk(mci, KERN_ERR,
+ ">Tmid Thermal event with intelligent "
+ "throttling disabled\n");
+ }
+
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
+ "FATAL Err=0x%x)",
+ branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+ allErrors);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ * struct i5000_error_info *info,
+ * int handle_errors);
+ *
+ * handle the Intel NON-FATAL errors, if any
+ */
+static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info,
+ int handle_errors)
+{
+ char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+ u32 allErrors;
+ u32 ue_errors;
+ u32 ce_errors;
+ u32 misc_errors;
+ int branch;
+ int channel;
+ int bank;
+ int rank;
+ int rdwr;
+ int ras, cas;
+
+ /* mask off the Error bits that are possible */
+ allErrors = (info->ferr_nf_fbd & FERR_NF_MASK);
+ if (!allErrors)
+ return; /* if no error, return now */
+
+ /* ONLY ONE of the possible error bits will be set, as per the docs */
+ i5000_mc_printk(mci, KERN_WARNING,
+ "NON-FATAL ERRORS Found!!! 1st NON-FATAL Err "
+ "Reg= 0x%x\n", allErrors);
+
+ ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
+ if (ue_errors) {
+ debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
+
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+ channel = branch;
+ bank = NREC_BANK(info->nrecmema);
+ rank = NREC_RANK(info->nrecmema);
+ rdwr = NREC_RDWR(info->nrecmema);
+ ras = NREC_RAS(info->nrecmemb);
+ cas = NREC_CAS(info->nrecmemb);
+
+ debugf0
+ ("\t\tCSROW= %d Channels= %d,%d (Branch= %d "
+ "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+ rank, channel, channel + 1, branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas);
+
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+ "CAS=%d, UE Err=0x%x)",
+ branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+ ue_errors);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+ }
+
+ /* Check correctable errors */
+ ce_errors = allErrors & FERR_NF_CORRECTABLE;
+ if (ce_errors) {
+ debugf0("\tCorrected bits= 0x%x\n", ce_errors);
+
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+
+ channel = 0;
+ if (REC_ECC_LOCATOR_ODD(info->redmemb))
+ channel = 1;
+
+ /* Convert channel to be based from zero, instead of
+ * from branch base of 0 */
+ channel += branch;
+
+ bank = REC_BANK(info->recmema);
+ rank = REC_RANK(info->recmema);
+ rdwr = REC_RDWR(info->recmema);
+ ras = REC_RAS(info->recmemb);
+ cas = REC_CAS(info->recmemb);
+
+ debugf0("\t\tCSROW= %d Channel= %d (Branch %d "
+ "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+ rank, channel, branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas);
+
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+ "CAS=%d, CE Err=0x%x)", branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas, ce_errors);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ce(mci, rank, channel, msg);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_THERMAL;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_NON_RETRY;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING, "\tNON-Retry Errors, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_NORTH_CRC;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING,
+ "\tNORTHBOUND CRC Error, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_SPD_PROTOCOL;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING,
+ "\tSPD Protocol Error, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_DIMM_SPARE;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING, "\tDIMM-Spare Error, bits= 0x%x\n",
+ misc_errors);
+ }
+}
+
+/*
+ * i5000_process_error_info Process the error info that is
+ * in the 'info' structure, previously retrieved from hardware
+ */
+static void i5000_process_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info,
+ int handle_errors)
+{
+ /* First handle any fatal errors that occurred */
+ i5000_process_fatal_error_info(mci, info, handle_errors);
+
+ /* now handle any non-fatal errors that occurred */
+ i5000_process_nonfatal_error_info(mci, info, handle_errors);
+}
+
+/*
+ * i5000_clear_error Retrieve any error from the hardware
+ * but do NOT process that error.
+ * Used for 'clearing' out of previous errors
+ * Called by the Core module.
+ */
+static void i5000_clear_error(struct mem_ctl_info *mci)
+{
+ struct i5000_error_info info;
+
+ i5000_get_error_info(mci, &info);
+}
+
+/*
+ * i5000_check_error Retrieve and process errors reported by the
+ * hardware. Called by the Core module.
+ */
+static void i5000_check_error(struct mem_ctl_info *mci)
+{
+ struct i5000_error_info info;
+ debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+ i5000_get_error_info(mci, &info);
+ i5000_process_error_info(mci, &info, 1);
+}
+
+/*
+ * i5000_get_devices Find and perform 'get' operation on the MCH's
+ * device/functions we want to reference for this driver
+ *
+ * Need to 'get' device 16 func 1 and func 2
+ */
+static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx)
+{
+ //const struct i5000_dev_info *i5000_dev = &i5000_devs[dev_idx];
+ struct i5000_pvt *pvt;
+ struct pci_dev *pdev;
+
+ pvt = mci->pvt_info;
+
+ /* Attempt to 'get' the MCH register we want */
+ pdev = NULL;
+ while (1) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+ /* End of list, leave */
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "'system address,Process Bus' "
+ "device not found:"
+ "vendor 0x%x device 0x%x FUNC 1 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+ return 1;
+ }
+
+ /* Scan for device 16 func 1 */
+ if (PCI_FUNC(pdev->devfn) == 1)
+ break;
+ }
+
+ pvt->branchmap_werrors = pdev;
+
+ /* Attempt to 'get' the MCH register we want */
+ pdev = NULL;
+ while (1) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "MC: 'branchmap,control,errors' "
+ "device not found:"
+ "vendor 0x%x device 0x%x Func 2 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ return 1;
+ }
+
+ /* Scan for device 16 func 1 */
+ if (PCI_FUNC(pdev->devfn) == 2)
+ break;
+ }
+
+ pvt->fsb_error_regs = pdev;
+
+ debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->system_address),
+ pvt->system_address->vendor, pvt->system_address->device);
+ debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->branchmap_werrors),
+ pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
+ debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->fsb_error_regs),
+ pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+
+ pdev = NULL;
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_I5000_BRANCH_0, pdev);
+
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "MC: 'BRANCH 0' device not found:"
+ "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_I5000_BRANCH_0);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ pci_dev_put(pvt->fsb_error_regs);
+ return 1;
+ }
+
+ pvt->branch_0 = pdev;
+
+ /* If this device claims to have more than 2 channels then
+ * fetch Branch 1's information
+ */
+ if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+ pdev = NULL;
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_I5000_BRANCH_1, pdev);
+
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "MC: 'BRANCH 1' device not found:"
+ "vendor 0x%x device 0x%x Func 0 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_I5000_BRANCH_1);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ pci_dev_put(pvt->fsb_error_regs);
+ pci_dev_put(pvt->branch_0);
+ return 1;
+ }
+
+ pvt->branch_1 = pdev;
+ }
+
+ return 0;
+}
+
+/*
+ * i5000_put_devices 'put' all the devices that we have
+ * reserved via 'get'
+ */
+static void i5000_put_devices(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+
+ pvt = mci->pvt_info;
+
+ pci_dev_put(pvt->branchmap_werrors); /* FUNC 1 */
+ pci_dev_put(pvt->fsb_error_regs); /* FUNC 2 */
+ pci_dev_put(pvt->branch_0); /* DEV 21 */
+
+ /* Only if more than 2 channels do we release the second branch */
+ if (pvt->maxch >= CHANNELS_PER_BRANCH)
+ pci_dev_put(pvt->branch_1); /* DEV 22 */
+}
+
+/*
+ * determine_amb_resent
+ *
+ * the information is contained in NUM_MTRS different registers
+ * determineing which of the NUM_MTRS requires knowing
+ * which channel is in question
+ *
+ * 2 branches, each with 2 channels
+ * b0_ambpresent0 for channel '0'
+ * b0_ambpresent1 for channel '1'
+ * b1_ambpresent0 for channel '2'
+ * b1_ambpresent1 for channel '3'
+ */
+static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
+{
+ int amb_present;
+
+ if (channel < CHANNELS_PER_BRANCH) {
+ if (channel & 0x1)
+ amb_present = pvt->b0_ambpresent1;
+ else
+ amb_present = pvt->b0_ambpresent0;
+ } else {
+ if (channel & 0x1)
+ amb_present = pvt->b1_ambpresent1;
+ else
+ amb_present = pvt->b1_ambpresent0;
+ }
+
+ return amb_present;
+}
+
+/*
+ * determine_mtr(pvt, csrow, channel)
+ *
+ * return the proper MTR register as determine by the csrow and channel desired
+ */
+static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel)
+{
+ int mtr;
+
+ if (channel < CHANNELS_PER_BRANCH)
+ mtr = pvt->b0_mtr[csrow >> 1];
+ else
+ mtr = pvt->b1_mtr[csrow >> 1];
+
+ return mtr;
+}
+
+/*
+ */
+static void decode_mtr(int slot_row, u16 mtr)
+{
+ int ans;
+
+ ans = MTR_DIMMS_PRESENT(mtr);
+
+ debugf2("\tMTR%d=0x%x: DIMMs are %s\n", slot_row, mtr,
+ ans ? "Present" : "NOT Present");
+ if (!ans)
+ return;
+
+ debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+ debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+ debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
+ debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
+ debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+}
+
+static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
+ struct i5000_dimm_info *dinfo)
+{
+ int mtr;
+ int amb_present_reg;
+ int addrBits;
+
+ mtr = determine_mtr(pvt, csrow, channel);
+ if (MTR_DIMMS_PRESENT(mtr)) {
+ amb_present_reg = determine_amb_present_reg(pvt, channel);
+
+ /* Determine if there is a DIMM present in this DIMM slot */
+ if (amb_present_reg & (1 << (csrow >> 1))) {
+ dinfo->dual_rank = MTR_DIMM_RANK(mtr);
+
+ if (!((dinfo->dual_rank == 0) &&
+ ((csrow & 0x1) == 0x1))) {
+ /* Start with the number of bits for a Bank
+ * on the DRAM */
+ addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
+ /* Add thenumber of ROW bits */
+ addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+ /* add the number of COLUMN bits */
+ addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+
+ addrBits += 6; /* add 64 bits per DIMM */
+ addrBits -= 20; /* divide by 2^^20 */
+ addrBits -= 3; /* 8 bits per bytes */
+
+ dinfo->megabytes = 1 << addrBits;
+ }
+ }
+ }
+}
+
+/*
+ * calculate_dimm_size
+ *
+ * also will output a DIMM matrix map, if debug is enabled, for viewing
+ * how the DIMMs are populated
+ */
+static void calculate_dimm_size(struct i5000_pvt *pvt)
+{
+ struct i5000_dimm_info *dinfo;
+ int csrow, max_csrows;
+ char *p, *mem_buffer;
+ int space, n;
+ int channel;
+
+ /* ================= Generate some debug output ================= */
+ space = PAGE_SIZE;
+ mem_buffer = p = kmalloc(space, GFP_KERNEL);
+ if (p == NULL) {
+ i5000_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n",
+ __FILE__, __func__);
+ return;
+ }
+
+ n = snprintf(p, space, "\n");
+ p += n;
+ space -= n;
+
+ /* Scan all the actual CSROWS (which is # of DIMMS * 2)
+ * and calculate the information for each DIMM
+ * Start with the highest csrow first, to display it first
+ * and work toward the 0th csrow
+ */
+ max_csrows = pvt->maxdimmperch * 2;
+ for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
+
+ /* on an odd csrow, first output a 'boundary' marker,
+ * then reset the message buffer */
+ if (csrow & 0x1) {
+ n = snprintf(p, space, "---------------------------"
+ "--------------------------------");
+ p += n;
+ space -= n;
+ debugf2("%s\n", mem_buffer);
+ p = mem_buffer;
+ space = PAGE_SIZE;
+ }
+ n = snprintf(p, space, "csrow %2d ", csrow);
+ p += n;
+ space -= n;
+
+ for (channel = 0; channel < pvt->maxch; channel++) {
+ dinfo = &pvt->dimm_info[csrow][channel];
+ handle_channel(pvt, csrow, channel, dinfo);
+ n = snprintf(p, space, "%4d MB | ", dinfo->megabytes);
+ p += n;
+ space -= n;
+ }
+ n = snprintf(p, space, "\n");
+ p += n;
+ space -= n;
+ }
+
+ /* Output the last bottom 'boundary' marker */
+ n = snprintf(p, space, "---------------------------"
+ "--------------------------------\n");
+ p += n;
+ space -= n;
+
+ /* now output the 'channel' labels */
+ n = snprintf(p, space, " ");
+ p += n;
+ space -= n;
+ for (channel = 0; channel < pvt->maxch; channel++) {
+ n = snprintf(p, space, "channel %d | ", channel);
+ p += n;
+ space -= n;
+ }
+ n = snprintf(p, space, "\n");
+ p += n;
+ space -= n;
+
+ /* output the last message and free buffer */
+ debugf2("%s\n", mem_buffer);
+ kfree(mem_buffer);
+}
+
+/*
+ * i5000_get_mc_regs read in the necessary registers and
+ * cache locally
+ *
+ * Fills in the private data members
+ */
+static void i5000_get_mc_regs(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+ u32 actual_tolm;
+ u16 limit;
+ int slot_row;
+ int maxch;
+ int maxdimmperch;
+ int way0, way1;
+
+ pvt = mci->pvt_info;
+
+ pci_read_config_dword(pvt->system_address, AMBASE,
+ (u32 *) & pvt->ambase);
+ pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
+ ((u32 *) & pvt->ambase) + sizeof(u32));
+
+ maxdimmperch = pvt->maxdimmperch;
+ maxch = pvt->maxch;
+
+ debugf2("AMBASE= 0x%lx MAXCH= %d MAX-DIMM-Per-CH= %d\n",
+ (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+
+ /* Get the Branch Map regs */
+ pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
+ pvt->tolm >>= 12;
+ debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
+ pvt->tolm);
+
+ actual_tolm = pvt->tolm << 28;
+ debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm);
+
+ pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
+ pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
+ pci_read_config_word(pvt->branchmap_werrors, MIR2, &pvt->mir2);
+
+ /* Get the MIR[0-2] regs */
+ limit = (pvt->mir0 >> 4) & 0x0FFF;
+ way0 = pvt->mir0 & 0x1;
+ way1 = pvt->mir0 & 0x2;
+ debugf2("MIR0: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
+ limit = (pvt->mir1 >> 4) & 0x0FFF;
+ way0 = pvt->mir1 & 0x1;
+ way1 = pvt->mir1 & 0x2;
+ debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
+ limit = (pvt->mir2 >> 4) & 0x0FFF;
+ way0 = pvt->mir2 & 0x1;
+ way1 = pvt->mir2 & 0x2;
+ debugf2("MIR2: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
+
+ /* Get the MTR[0-3] regs */
+ for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+ int where = MTR0 + (slot_row * sizeof(u32));
+
+ pci_read_config_word(pvt->branch_0, where,
+ &pvt->b0_mtr[slot_row]);
+
+ debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
+ pvt->b0_mtr[slot_row]);
+
+ if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+ pci_read_config_word(pvt->branch_1, where,
+ &pvt->b1_mtr[slot_row]);
+ debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row,
+ where, pvt->b0_mtr[slot_row]);
+ } else {
+ pvt->b1_mtr[slot_row] = 0;
+ }
+ }
+
+ /* Read and dump branch 0's MTRs */
+ debugf2("\nMemory Technology Registers:\n");
+ debugf2(" Branch 0:\n");
+ for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+ decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
+ }
+ pci_read_config_word(pvt->branch_0, AMB_PRESENT_0,
+ &pvt->b0_ambpresent0);
+ debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+ pci_read_config_word(pvt->branch_0, AMB_PRESENT_1,
+ &pvt->b0_ambpresent1);
+ debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+
+ /* Only if we have 2 branchs (4 channels) */
+ if (pvt->maxch < CHANNELS_PER_BRANCH) {
+ pvt->b1_ambpresent0 = 0;
+ pvt->b1_ambpresent1 = 0;
+ } else {
+ /* Read and dump branch 1's MTRs */
+ debugf2(" Branch 1:\n");
+ for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+ decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
+ }
+ pci_read_config_word(pvt->branch_1, AMB_PRESENT_0,
+ &pvt->b1_ambpresent0);
+ debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
+ pvt->b1_ambpresent0);
+ pci_read_config_word(pvt->branch_1, AMB_PRESENT_1,
+ &pvt->b1_ambpresent1);
+ debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
+ pvt->b1_ambpresent1);
+ }
+
+ /* Go and determine the size of each DIMM and place in an
+ * orderly matrix */
+ calculate_dimm_size(pvt);
+}
+
+/*
+ * i5000_init_csrows Initialize the 'csrows' table within
+ * the mci control structure with the
+ * addressing of memory.
+ *
+ * return:
+ * 0 success
+ * 1 no actual memory found on this MC
+ */
+static int i5000_init_csrows(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+ struct csrow_info *p_csrow;
+ int empty, channel_count;
+ int max_csrows;
+ int mtr;
+ int csrow_megs;
+ int channel;
+ int csrow;
+
+ pvt = mci->pvt_info;
+
+ channel_count = pvt->maxch;
+ max_csrows = pvt->maxdimmperch * 2;
+
+ empty = 1; /* Assume NO memory */
+
+ for (csrow = 0; csrow < max_csrows; csrow++) {
+ p_csrow = &mci->csrows[csrow];
+
+ p_csrow->csrow_idx = csrow;
+
+ /* use branch 0 for the basis */
+ mtr = pvt->b0_mtr[csrow >> 1];
+
+ /* if no DIMMS on this row, continue */
+ if (!MTR_DIMMS_PRESENT(mtr))
+ continue;
+
+ /* FAKE OUT VALUES, FIXME */
+ p_csrow->first_page = 0 + csrow * 20;
+ p_csrow->last_page = 9 + csrow * 20;
+ p_csrow->page_mask = 0xFFF;
+
+ p_csrow->grain = 8;
+
+ csrow_megs = 0;
+ for (channel = 0; channel < pvt->maxch; channel++) {
+ csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
+ }
+
+ p_csrow->nr_pages = csrow_megs << 8;
+
+ /* Assume DDR2 for now */
+ p_csrow->mtype = MEM_FB_DDR2;
+
+ /* ask what device type on this row */
+ if (MTR_DRAM_WIDTH(mtr))
+ p_csrow->dtype = DEV_X8;
+ else
+ p_csrow->dtype = DEV_X4;
+
+ p_csrow->edac_mode = EDAC_S8ECD8ED;
+
+ empty = 0;
+ }
+
+ return empty;
+}
+
+/*
+ * i5000_enable_error_reporting
+ * Turn on the memory reporting features of the hardware
+ */
+static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+ u32 fbd_error_mask;
+
+ pvt = mci->pvt_info;
+
+ /* Read the FBD Error Mask Register */
+ pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+ &fbd_error_mask);
+
+ /* Enable with a '0' */
+ fbd_error_mask &= ~(ENABLE_EMASK_ALL);
+
+ pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+ fbd_error_mask);
+}
+
+/*
+ * i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels)
+ *
+ * ask the device how many channels are present and how many CSROWS
+ * as well
+ */
+static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
+ int *num_dimms_per_channel,
+ int *num_channels)
+{
+ u8 value;
+
+ /* Need to retrieve just how many channels and dimms per channel are
+ * supported on this memory controller
+ */
+ pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
+ *num_dimms_per_channel = (int)value *2;
+
+ pci_read_config_byte(pdev, MAXCH, &value);
+ *num_channels = (int)value;
+}
+
+/*
+ * i5000_probe1 Probe for ONE instance of device to see if it is
+ * present.
+ * return:
+ * 0 for FOUND a device
+ * < 0 for error code
+ */
+static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ struct mem_ctl_info *mci;
+ struct i5000_pvt *pvt;
+ int num_channels;
+ int num_dimms_per_channel;
+ int num_csrows;
+
+ debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+ __func__,
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+ /* We only are looking for func 0 of the set */
+ 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
+ *
+ * The Chipset will report what it can handle which will be greater
+ * or equal to what the motherboard manufacturer will implement.
+ *
+ * As we don't have a motherboard identification routine to determine
+ * actual number of slots/dimms per channel, we thus utilize the
+ * resource as specified by the chipset. Thus, we might have
+ * have more DIMMs per channel than actually on the mobo, but this
+ * allows the driver to support upto the chipset max, without
+ * some fancy mobo determination.
+ */
+ i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
+ &num_channels);
+ num_csrows = num_dimms_per_channel * 2;
+
+ debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n",
+ __func__, num_channels, num_dimms_per_channel, num_csrows);
+
+ /* allocate a new MC control structure */
+ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+ mci->dev = &pdev->dev; /* record ptr to the generic device */
+
+ pvt = mci->pvt_info;
+ pvt->system_address = pdev; /* Record this device in our private */
+ pvt->maxch = num_channels;
+ pvt->maxdimmperch = num_dimms_per_channel;
+
+ /* 'get' the pci devices we want to reserve for our use */
+ if (i5000_get_devices(mci, dev_idx))
+ goto fail0;
+
+ /* Time to get serious */
+ i5000_get_mc_regs(mci); /* retrieve the hardware registers */
+
+ mci->mc_idx = 0;
+ mci->mtype_cap = MEM_FLAG_FB_DDR2;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE;
+ mci->edac_cap = EDAC_FLAG_NONE;
+ mci->mod_name = "i5000_edac.c";
+ mci->mod_ver = I5000_REVISION;
+ mci->ctl_name = i5000_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
+ mci->ctl_page_to_phys = NULL;
+
+ /* Set the function pointer to an actual operation function */
+ mci->edac_check = i5000_check_error;
+
+ /* initialize the MC control structure 'csrows' table
+ * with the mapping and control information */
+ if (i5000_init_csrows(mci)) {
+ debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
+ " because i5000_init_csrows() returned nonzero "
+ "value\n");
+ mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
+ } else {
+ debugf1("MC: Enable error reporting now\n");
+ i5000_enable_error_reporting(mci);
+ }
+
+ /* add this new MC control structure to EDAC's list of MCs */
+ if (edac_mc_add_mc(mci)) {
+ debugf0("MC: " __FILE__
+ ": %s(): failed edac_mc_add_mc()\n", __func__);
+ /* FIXME: perhaps some code should go here that disables error
+ * reporting if we just enabled it
+ */
+ goto fail1;
+ }
+
+ i5000_clear_error(mci);
+
+ /* allocating generic PCI control info */
+ i5000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i5000_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ return 0;
+
+ /* Error exit unwinding stack */
+fail1:
+
+ i5000_put_devices(mci);
+
+fail0:
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+/*
+ * i5000_init_one constructor for one instance of device
+ *
+ * returns:
+ * negative on error
+ * count (>= 0)
+ */
+static int __devinit i5000_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int rc;
+
+ debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* wake up device */
+ rc = pci_enable_device(pdev);
+ if (rc == -EIO)
+ return rc;
+
+ /* now probe and enable the device */
+ return i5000_probe1(pdev, id->driver_data);
+}
+
+/*
+ * i5000_remove_one destructor for one instance of device
+ *
+ */
+static void __devexit i5000_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+
+ if (i5000_pci)
+ edac_pci_release_generic_ctl(i5000_pci);
+
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+ return;
+
+ /* retrieve references to resources, and free those resources */
+ i5000_put_devices(mci);
+
+ edac_mc_free(mci);
+}
+
+/*
+ * pci_device_id table for which devices we are looking for
+ *
+ * The "E500P" device is the first device supported.
+ */
+static const struct pci_device_id i5000_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
+ .driver_data = I5000P},
+
+ {0,} /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i5000_pci_tbl);
+
+/*
+ * i5000_driver pci_driver structure for this module
+ *
+ */
+static struct pci_driver i5000_driver = {
+ .name = __stringify(KBUILD_BASENAME),
+ .probe = i5000_init_one,
+ .remove = __devexit_p(i5000_remove_one),
+ .id_table = i5000_pci_tbl,
+};
+
+/*
+ * i5000_init Module entry function
+ * Try to initialize this module for its devices
+ */
+static int __init i5000_init(void)
+{
+ int pci_rc;
+
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+ pci_rc = pci_register_driver(&i5000_driver);
+
+ return (pci_rc < 0) ? pci_rc : 0;
+}
+
+/*
+ * i5000_exit() Module exit function
+ * Unregister the driver
+ */
+static void __exit i5000_exit(void)
+{
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ pci_unregister_driver(&i5000_driver);
+}
+
+module_init(i5000_init);
+module_exit(i5000_exit);
+
+MODULE_LICENSE("GPL");
+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
new file mode 100644
index 000000000000..83bfe37c4bbb
--- /dev/null
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -0,0 +1,402 @@
+/*
+ * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
+ * module (C) 2006 Tim Small
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License.
+ *
+ * Written by Tim Small <tim@buttersideup.com>, based on work by Linux
+ * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
+ * others.
+ *
+ * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
+ *
+ * Written with reference to 82443BX Host Bridge Datasheet:
+ * http://www.intel.com/design/chipsets/440/documentation.htm
+ * references to this document given in [].
+ *
+ * This module doesn't support the 440LX, but it may be possible to
+ * make it do so (the 440LX's register definitions are different, but
+ * not completely so - I haven't studied them in enough detail to know
+ * how easy this would be).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82443_REVISION "0.1"
+
+#define EDAC_MOD_STR "i82443bxgx_edac"
+
+/* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
+ * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
+ * rows" "The 82443BX supports multiple-bit error detection and
+ * single-bit error correction when ECC mode is enabled and
+ * single/multi-bit error detection when correction is disabled.
+ * During writes to the DRAM, the 82443BX generates ECC for the data
+ * on a QWord basis. Partial QWord writes require a read-modify-write
+ * cycle when ECC is enabled."
+*/
+
+/* "Additionally, the 82443BX ensures that the data is corrected in
+ * main memory so that accumulation of errors is prevented. Another
+ * error within the same QWord would result in a double-bit error
+ * which is unrecoverable. This is known as hardware scrubbing since
+ * it requires no software intervention to correct the data in memory."
+ */
+
+/* [Also see page 100 (section 4.3), "DRAM Interface"]
+ * [Also see page 112 (section 4.6.1.4), ECC]
+ */
+
+#define I82443BXGX_NR_CSROWS 8
+#define I82443BXGX_NR_CHANS 1
+#define I82443BXGX_NR_DIMMS 4
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI
+ * config space offset */
+#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if
+ * row is non-ECC */
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */
+
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */
+#define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */
+#define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */
+
+#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI
+ * config space offset, Error Address
+ * Pointer Register */
+#define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */
+#define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */
+#define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC) */
+
+#define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI
+ * config space offset. */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */
+
+#define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI
+ * config space offset. */
+#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */
+#define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */
+#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */
+#define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */
+
+#define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI
+ * config space offset. */
+#define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */
+#define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */
+#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1 /* 01 = SDRAM */
+#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */
+
+#define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI
+ * config space offset. */
+
+/* FIXME - don't poll when ECC disabled? */
+
+struct i82443bxgx_edacmc_error_info {
+ u32 eap;
+};
+
+static struct edac_pci_ctl_info *i82443bxgx_pci;
+
+static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
+ struct i82443bxgx_edacmc_error_info
+ *info)
+{
+ struct pci_dev *pdev;
+ pdev = to_pci_dev(mci->dev);
+ pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
+ if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
+ /* Clear error to allow next error to be reported [p.61] */
+ pci_write_bits32(pdev, I82443BXGX_EAP,
+ I82443BXGX_EAP_OFFSET_SBE,
+ I82443BXGX_EAP_OFFSET_SBE);
+
+ if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
+ /* Clear error to allow next error to be reported [p.61] */
+ pci_write_bits32(pdev, I82443BXGX_EAP,
+ I82443BXGX_EAP_OFFSET_MBE,
+ I82443BXGX_EAP_OFFSET_MBE);
+}
+
+static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
+ struct
+ i82443bxgx_edacmc_error_info
+ *info, int handle_errors)
+{
+ int error_found = 0;
+ u32 eapaddr, page, pageoffset;
+
+ /* bits 30:12 hold the 4kb block in which the error occurred
+ * [p.61] */
+ eapaddr = (info->eap & 0xfffff000);
+ page = eapaddr >> PAGE_SHIFT;
+ pageoffset = eapaddr - (page << PAGE_SHIFT);
+
+ if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
+ error_found = 1;
+ if (handle_errors)
+ edac_mc_handle_ce(mci, page, pageoffset,
+ /* 440BX/GX don't make syndrome information
+ * available */
+ 0, edac_mc_find_csrow_by_page(mci, page), 0,
+ mci->ctl_name);
+ }
+
+ if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
+ error_found = 1;
+ if (handle_errors)
+ edac_mc_handle_ue(mci, page, pageoffset,
+ edac_mc_find_csrow_by_page(mci, page),
+ mci->ctl_name);
+ }
+
+ return error_found;
+}
+
+static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
+{
+ struct i82443bxgx_edacmc_error_info info;
+
+ debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+ i82443bxgx_edacmc_get_error_info(mci, &info);
+ i82443bxgx_edacmc_process_error_info(mci, &info, 1);
+}
+
+static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev,
+ enum edac_type edac_mode,
+ enum mem_type mtype)
+{
+ struct csrow_info *csrow;
+ int index;
+ u8 drbar, dramc;
+ u32 row_base, row_high_limit, row_high_limit_last;
+
+ pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+ row_high_limit_last = 0;
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+ pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
+ debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
+ mci->mc_idx, __func__, index, drbar);
+ row_high_limit = ((u32) drbar << 23);
+ /* find the DRAM Chip Select Base address and mask */
+ debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
+ "Boundry Address=%#0x, Last = %#0x \n",
+ mci->mc_idx, __func__, index, row_high_limit,
+ row_high_limit_last);
+
+ /* 440GX goes to 2GB, represented with a DRB of 0. */
+ if (row_high_limit_last && !row_high_limit)
+ row_high_limit = 1UL << 31;
+
+ /* This row is empty [p.49] */
+ if (row_high_limit == row_high_limit_last)
+ continue;
+ row_base = row_high_limit_last;
+ csrow->first_page = row_base >> PAGE_SHIFT;
+ csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
+ csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
+ /* EAP reports in 4kilobyte granularity [61] */
+ csrow->grain = 1 << 12;
+ csrow->mtype = mtype;
+ /* I don't think 440BX can tell you device type? FIXME? */
+ csrow->dtype = DEV_UNKNOWN;
+ /* Mode is global to all rows on 440BX */
+ csrow->edac_mode = edac_mode;
+ row_high_limit_last = row_high_limit;
+ }
+}
+
+static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ struct mem_ctl_info *mci;
+ u8 dramc;
+ u32 nbxcfg, ecc_mode;
+ enum mem_type mtype;
+ enum edac_type edac_mode;
+
+ debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* Something is really hosed if PCI config space reads from
+ * the MC aren't working.
+ */
+ if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
+ return -EIO;
+
+ mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+ pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+ switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
+ case I82443BXGX_DRAMC_DRAM_IS_EDO:
+ mtype = MEM_EDO;
+ break;
+ case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
+ mtype = MEM_SDR;
+ break;
+ case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
+ mtype = MEM_RDR;
+ break;
+ default:
+ debugf0("Unknown/reserved DRAM type value "
+ "in DRAMC register!\n");
+ mtype = -MEM_UNKNOWN;
+ }
+
+ if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
+ mci->edac_cap = mci->edac_ctl_cap;
+ else
+ mci->edac_cap = EDAC_FLAG_NONE;
+
+ mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+ pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
+ ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
+ (BIT(0) | BIT(1)));
+
+ mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
+ ? SCRUB_HW_SRC : SCRUB_NONE;
+
+ switch (ecc_mode) {
+ case I82443BXGX_NBXCFG_INTEGRITY_NONE:
+ edac_mode = EDAC_NONE;
+ break;
+ case I82443BXGX_NBXCFG_INTEGRITY_EC:
+ edac_mode = EDAC_EC;
+ break;
+ case I82443BXGX_NBXCFG_INTEGRITY_ECC:
+ case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
+ edac_mode = EDAC_SECDED;
+ break;
+ default:
+ debugf0("%s(): Unknown/reserved ECC state "
+ "in NBXCFG register!\n", __func__);
+ edac_mode = EDAC_UNKNOWN;
+ break;
+ }
+
+ i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
+
+ /* Many BIOSes don't clear error flags on boot, so do this
+ * here, or we get "phantom" errors occuring at module-load
+ * time. */
+ pci_write_bits32(pdev, I82443BXGX_EAP,
+ (I82443BXGX_EAP_OFFSET_SBE |
+ I82443BXGX_EAP_OFFSET_MBE),
+ (I82443BXGX_EAP_OFFSET_SBE |
+ I82443BXGX_EAP_OFFSET_MBE));
+
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I82443_REVISION;
+ mci->ctl_name = "I82443BXGX";
+ mci->dev_name = pci_name(pdev);
+ mci->edac_check = i82443bxgx_edacmc_check;
+ mci->ctl_page_to_phys = NULL;
+
+ if (edac_mc_add_mc(mci)) {
+ debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail;
+ }
+
+ /* allocating generic PCI control info */
+ i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82443bxgx_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+ return 0;
+
+fail:
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* don't need to call pci_device_enable() */
+ return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+}
+
+static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+
+ if (i82443bxgx_pci)
+ edac_pci_release_generic_ctl(i82443bxgx_pci);
+
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+ return;
+
+ edac_mc_free(mci);
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
+
+static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
+ {0,} /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
+
+static struct pci_driver i82443bxgx_edacmc_driver = {
+ .name = EDAC_MOD_STR,
+ .probe = i82443bxgx_edacmc_init_one,
+ .remove = __devexit_p(i82443bxgx_edacmc_remove_one),
+ .id_table = i82443bxgx_pci_tbl,
+};
+
+static int __init i82443bxgx_edacmc_init(void)
+{
+ return pci_register_driver(&i82443bxgx_edacmc_driver);
+}
+
+static void __exit i82443bxgx_edacmc_exit(void)
+{
+ pci_unregister_driver(&i82443bxgx_edacmc_driver);
+}
+
+module_init(i82443bxgx_edacmc_init);
+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");
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index e4bb298e613f..f5ecd2c4d813 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -14,9 +14,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define I82860_REVISION " Ver: 2.0.1 " __DATE__
+#define I82860_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "i82860_edac"
#define i82860_printk(level, fmt, arg...) \
@@ -54,16 +54,16 @@ struct i82860_error_info {
static const struct i82860_dev_info i82860_devs[] = {
[I82860] = {
- .ctl_name = "i82860"
- },
+ .ctl_name = "i82860"},
};
-static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code
* has already registered driver
*/
+static struct edac_pci_ctl_info *i82860_pci;
static void i82860_get_error_info(struct mem_ctl_info *mci,
- struct i82860_error_info *info)
+ struct i82860_error_info *info)
{
struct pci_dev *pdev;
@@ -91,13 +91,13 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
if ((info->errsts ^ info->errsts2) & 0x0003) {
pci_read_config_dword(pdev, I82860_EAP, &info->eap);
- pci_read_config_word(pdev, I82860_DERRCTL_STS,
- &info->derrsyn);
+ pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
}
}
static int i82860_process_error_info(struct mem_ctl_info *mci,
- struct i82860_error_info *info, int handle_errors)
+ struct i82860_error_info *info,
+ int handle_errors)
{
int row;
@@ -136,7 +136,7 @@ static void i82860_check(struct mem_ctl_info *mci)
static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
{
unsigned long last_cumul_size;
- u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
+ u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
u16 value;
u32 cumul_size;
struct csrow_info *csrow;
@@ -155,7 +155,7 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
csrow = &mci->csrows[index];
pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
cumul_size = (value & I82860_GBA_MASK) <<
- (I82860_GBA_SHIFT - PAGE_SHIFT);
+ (I82860_GBA_SHIFT - PAGE_SHIFT);
debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
cumul_size);
@@ -186,7 +186,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
the channel and the GRA registers map to physical devices so we are
going to make 1 channel for group.
*/
- mci = edac_mc_alloc(0, 16, 1);
+ mci = edac_mc_alloc(0, 16, 1, 0);
if (!mci)
return -ENOMEM;
@@ -200,19 +200,31 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = I82860_REVISION;
mci->ctl_name = i82860_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = i82860_check;
mci->ctl_page_to_phys = NULL;
i82860_init_csrows(mci, pdev);
- i82860_get_error_info(mci, &discard); /* clear counters */
+ i82860_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
+ /* allocating generic PCI control info */
+ i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82860_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
@@ -225,7 +237,7 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit i82860_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
@@ -249,6 +261,9 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (i82860_pci)
+ edac_pci_release_generic_ctl(i82860_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
@@ -257,12 +272,11 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- I82860
- },
+ PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I82860},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
@@ -329,5 +343,5 @@ module_exit(i82860_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
- "Ben Woodard <woodard@redhat.com>");
+ "Ben Woodard <woodard@redhat.com>");
MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 2800b3e614a9..031abadc439a 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -18,9 +18,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define I82875P_REVISION " Ver: 2.0.1 " __DATE__
+#define I82875P_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "i82875p_edac"
#define i82875p_printk(level, fmt, arg...) \
@@ -174,18 +174,19 @@ struct i82875p_error_info {
static const struct i82875p_dev_info i82875p_devs[] = {
[I82875P] = {
- .ctl_name = "i82875p"
- },
+ .ctl_name = "i82875p"},
};
-static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code has
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
* already registered driver
*/
static int i82875p_registered = 1;
+static struct edac_pci_ctl_info *i82875p_pci;
+
static void i82875p_get_error_info(struct mem_ctl_info *mci,
- struct i82875p_error_info *info)
+ struct i82875p_error_info *info)
{
struct pci_dev *pdev;
@@ -197,38 +198,39 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
* overwritten by UE.
*/
pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
+
+ if (!(info->errsts & 0x0081))
+ return;
+
pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
pci_read_config_byte(pdev, I82875P_DES, &info->des);
pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
- pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
-
/*
* If the error is the same then we can for both reads then
* the first set of reads is valid. If there is a change then
* there is a CE no info and the second set of reads is valid
* and should be UE info.
*/
- if (!(info->errsts2 & 0x0081))
- return;
-
if ((info->errsts ^ info->errsts2) & 0x0081) {
pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
pci_read_config_byte(pdev, I82875P_DES, &info->des);
- pci_read_config_byte(pdev, I82875P_DERRSYN,
- &info->derrsyn);
+ pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
}
+
+ pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
}
static int i82875p_process_error_info(struct mem_ctl_info *mci,
- struct i82875p_error_info *info, int handle_errors)
+ struct i82875p_error_info *info,
+ int handle_errors)
{
int row, multi_chan;
multi_chan = mci->csrows[0].nr_channels - 1;
- if (!(info->errsts2 & 0x0081))
+ if (!(info->errsts & 0x0081))
return 0;
if (!handle_errors)
@@ -263,10 +265,12 @@ static void i82875p_check(struct mem_ctl_info *mci)
/* Return 0 on success or 1 on failure. */
static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
- struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
+ struct pci_dev **ovrfl_pdev,
+ void __iomem **ovrfl_window)
{
struct pci_dev *dev;
void __iomem *window;
+ int err;
*ovrfl_pdev = NULL;
*ovrfl_window = NULL;
@@ -284,14 +288,19 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
if (dev == NULL)
return 1;
- pci_bus_add_device(dev);
+ err = pci_bus_add_device(dev);
+ if (err) {
+ i82875p_printk(KERN_ERR,
+ "%s(): pci_bus_add_device() Failed\n",
+ __func__);
+ }
}
*ovrfl_pdev = dev;
if (pci_enable_device(dev)) {
i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
- "device\n", __func__);
+ "device\n", __func__);
return 1;
}
@@ -307,7 +316,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
if (window == NULL) {
i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
- __func__);
+ __func__);
goto fail1;
}
@@ -325,21 +334,20 @@ fail0:
return 1;
}
-
/* Return 1 if dual channel mode is active. Else return 0. */
static inline int dual_channel_active(u32 drc)
{
return (drc >> 21) & 0x1;
}
-
static void i82875p_init_csrows(struct mem_ctl_info *mci,
- struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc)
+ struct pci_dev *pdev,
+ void __iomem * ovrfl_window, u32 drc)
{
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
- u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
+ u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
u32 cumul_size;
int index;
@@ -392,7 +400,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
drc = readl(ovrfl_window + I82875P_DRC);
nr_chans = dual_channel_active(drc) + 1;
mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
- nr_chans);
+ nr_chans, 0);
if (!mci) {
rc = -ENOMEM;
@@ -407,23 +415,35 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = I82875P_REVISION;
mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = i82875p_check;
mci->ctl_page_to_phys = NULL;
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct i82875p_pvt *) mci->pvt_info;
+ pvt = (struct i82875p_pvt *)mci->pvt_info;
pvt->ovrfl_pdev = ovrfl_pdev;
pvt->ovrfl_window = ovrfl_window;
i82875p_init_csrows(mci, pdev, ovrfl_window, drc);
- i82875p_get_error_info(mci, &discard); /* clear counters */
+ i82875p_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail1;
}
+ /* allocating generic PCI control info */
+ i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82875p_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
@@ -442,7 +462,7 @@ fail0:
/* returns count (>= 0), or negative on error */
static int __devinit i82875p_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
@@ -467,10 +487,13 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (i82875p_pci)
+ edac_pci_release_generic_ctl(i82875p_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
- pvt = (struct i82875p_pvt *) mci->pvt_info;
+ pvt = (struct i82875p_pvt *)mci->pvt_info;
if (pvt->ovrfl_window)
iounmap(pvt->ovrfl_window);
@@ -488,12 +511,11 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- I82875P
- },
+ PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I82875P},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
@@ -517,7 +539,7 @@ static int __init i82875p_init(void)
if (mci_pdev == NULL) {
mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82875_0, NULL);
+ PCI_DEVICE_ID_INTEL_82875_0, NULL);
if (!mci_pdev) {
debugf0("875p pci_get_device fail\n");
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
new file mode 100644
index 000000000000..0ee888456932
--- /dev/null
+++ b/drivers/edac/i82975x_edac.c
@@ -0,0 +1,666 @@
+/*
+ * Intel 82975X Memory Controller kernel module
+ * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com)
+ * (C) 2007 jetzbroadband (http://jetzbroadband.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Arvind R.
+ * Copied from i82875p_edac.c source:
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82975X_REVISION " Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR "i82975x_edac"
+
+#define i82975x_printk(level, fmt, arg...) \
+ edac_printk(level, "i82975x", fmt, ##arg)
+
+#define i82975x_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_82975_0
+#define PCI_DEVICE_ID_INTEL_82975_0 0x277c
+#endif /* PCI_DEVICE_ID_INTEL_82975_0 */
+
+#define I82975X_NR_CSROWS(nr_chans) (8/(nr_chans))
+
+/* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */
+#define I82975X_EAP 0x58 /* Dram Error Address Pointer (32b)
+ *
+ * 31:7 128 byte cache-line address
+ * 6:1 reserved
+ * 0 0: CH0; 1: CH1
+ */
+
+#define I82975X_DERRSYN 0x5c /* Dram Error SYNdrome (8b)
+ *
+ * 7:0 DRAM ECC Syndrome
+ */
+
+#define I82975X_DES 0x5d /* Dram ERRor DeSTination (8b)
+ * 0h: Processor Memory Reads
+ * 1h:7h reserved
+ * More - See Page 65 of Intel DocSheet.
+ */
+
+#define I82975X_ERRSTS 0xc8 /* Error Status Register (16b)
+ *
+ * 15:12 reserved
+ * 11 Thermal Sensor Event
+ * 10 reserved
+ * 9 non-DRAM lock error (ndlock)
+ * 8 Refresh Timeout
+ * 7:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+/* Error Reporting is supported by 3 mechanisms:
+ 1. DMI SERR generation ( ERRCMD )
+ 2. SMI DMI generation ( SMICMD )
+ 3. SCI DMI generation ( SCICMD )
+NOTE: Only ONE of the three must be enabled
+*/
+#define I82975X_ERRCMD 0xca /* Error Command (16b)
+ *
+ * 15:12 reserved
+ * 11 Thermal Sensor Event
+ * 10 reserved
+ * 9 non-DRAM lock error (ndlock)
+ * 8 Refresh Timeout
+ * 7:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+#define I82975X_SMICMD 0xcc /* Error Command (16b)
+ *
+ * 15:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+#define I82975X_SCICMD 0xce /* Error Command (16b)
+ *
+ * 15:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+#define I82975X_XEAP 0xfc /* Extended Dram Error Address Pointer (8b)
+ *
+ * 7:1 reserved
+ * 0 Bit32 of the Dram Error Address
+ */
+
+#define I82975X_MCHBAR 0x44 /*
+ *
+ * 31:14 Base Addr of 16K memory-mapped
+ * configuration space
+ * 13:1 reserverd
+ * 0 mem-mapped config space enable
+ */
+
+/* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) */
+/* Intel 82975x memory mapped register space */
+
+#define I82975X_DRB_SHIFT 25 /* fixed 32MiB grain */
+
+#define I82975X_DRB 0x100 /* DRAM Row Boundary (8b x 8)
+ *
+ * 7 set to 1 in highest DRB of
+ * channel if 4GB in ch.
+ * 6:2 upper boundary of rank in
+ * 32MB grains
+ * 1:0 set to 0
+ */
+#define I82975X_DRB_CH0R0 0x100
+#define I82975X_DRB_CH0R1 0x101
+#define I82975X_DRB_CH0R2 0x102
+#define I82975X_DRB_CH0R3 0x103
+#define I82975X_DRB_CH1R0 0x180
+#define I82975X_DRB_CH1R1 0x181
+#define I82975X_DRB_CH1R2 0x182
+#define I82975X_DRB_CH1R3 0x183
+
+
+#define I82975X_DRA 0x108 /* DRAM Row Attribute (4b x 8)
+ * defines the PAGE SIZE to be used
+ * for the rank
+ * 7 reserved
+ * 6:4 row attr of odd rank, i.e. 1
+ * 3 reserved
+ * 2:0 row attr of even rank, i.e. 0
+ *
+ * 000 = unpopulated
+ * 001 = reserved
+ * 010 = 4KiB
+ * 011 = 8KiB
+ * 100 = 16KiB
+ * others = reserved
+ */
+#define I82975X_DRA_CH0R01 0x108
+#define I82975X_DRA_CH0R23 0x109
+#define I82975X_DRA_CH1R01 0x188
+#define I82975X_DRA_CH1R23 0x189
+
+
+#define I82975X_BNKARC 0x10e /* Type of device in each rank - Bank Arch (16b)
+ *
+ * 15:8 reserved
+ * 7:6 Rank 3 architecture
+ * 5:4 Rank 2 architecture
+ * 3:2 Rank 1 architecture
+ * 1:0 Rank 0 architecture
+ *
+ * 00 => x16 devices; i.e 4 banks
+ * 01 => x8 devices; i.e 8 banks
+ */
+#define I82975X_C0BNKARC 0x10e
+#define I82975X_C1BNKARC 0x18e
+
+
+
+#define I82975X_DRC 0x120 /* DRAM Controller Mode0 (32b)
+ *
+ * 31:30 reserved
+ * 29 init complete
+ * 28:11 reserved, according to Intel
+ * 22:21 number of channels
+ * 00=1 01=2 in 82875
+ * seems to be ECC mode
+ * bits in 82975 in Asus
+ * P5W
+ * 19:18 Data Integ Mode
+ * 00=none 01=ECC in 82875
+ * 10:8 refresh mode
+ * 7 reserved
+ * 6:4 mode select
+ * 3:2 reserved
+ * 1:0 DRAM type 10=Second Revision
+ * DDR2 SDRAM
+ * 00, 01, 11 reserved
+ */
+#define I82975X_DRC_CH0M0 0x120
+#define I82975X_DRC_CH1M0 0x1A0
+
+
+#define I82975X_DRC_M1 0x124 /* DRAM Controller Mode1 (32b)
+ * 31 0=Standard Address Map
+ * 1=Enhanced Address Map
+ * 30:0 reserved
+ */
+
+#define I82975X_DRC_CH0M1 0x124
+#define I82975X_DRC_CH1M1 0x1A4
+
+enum i82975x_chips {
+ I82975X = 0,
+};
+
+struct i82975x_pvt {
+ void __iomem *mch_window;
+};
+
+struct i82975x_dev_info {
+ const char *ctl_name;
+};
+
+struct i82975x_error_info {
+ u16 errsts;
+ u32 eap;
+ u8 des;
+ u8 derrsyn;
+ u16 errsts2;
+ u8 chan; /* the channel is bit 0 of EAP */
+ u8 xeap; /* extended eap bit */
+};
+
+static const struct i82975x_dev_info i82975x_devs[] = {
+ [I82975X] = {
+ .ctl_name = "i82975x"
+ },
+};
+
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
+ * already registered driver
+ */
+
+static int i82975x_registered = 1;
+
+static void i82975x_get_error_info(struct mem_ctl_info *mci,
+ struct i82975x_error_info *info)
+{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+
+ /*
+ * This is a mess because there is no atomic way to read all the
+ * registers at once and the registers can transition from CE being
+ * overwritten by UE.
+ */
+ pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts);
+ pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+ pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+ pci_read_config_byte(pdev, I82975X_DES, &info->des);
+ pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn);
+ pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2);
+
+ pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003);
+
+ /*
+ * If the error is the same then we can for both reads then
+ * the first set of reads is valid. If there is a change then
+ * there is a CE no info and the second set of reads is valid
+ * and should be UE info.
+ */
+ if (!(info->errsts2 & 0x0003))
+ return;
+
+ if ((info->errsts ^ info->errsts2) & 0x0003) {
+ pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+ pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+ pci_read_config_byte(pdev, I82975X_DES, &info->des);
+ pci_read_config_byte(pdev, I82975X_DERRSYN,
+ &info->derrsyn);
+ }
+}
+
+static int i82975x_process_error_info(struct mem_ctl_info *mci,
+ struct i82975x_error_info *info, int handle_errors)
+{
+ int row, multi_chan, chan;
+
+ multi_chan = mci->csrows[0].nr_channels - 1;
+
+ if (!(info->errsts2 & 0x0003))
+ return 0;
+
+ if (!handle_errors)
+ return 1;
+
+ if ((info->errsts ^ info->errsts2) & 0x0003) {
+ edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+ info->errsts = info->errsts2;
+ }
+
+ chan = info->eap & 1;
+ info->eap >>= 1;
+ if (info->xeap )
+ info->eap |= 0x80000000;
+ info->eap >>= PAGE_SHIFT;
+ row = edac_mc_find_csrow_by_page(mci, info->eap);
+
+ if (info->errsts & 0x0002)
+ edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE");
+ else
+ edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
+ multi_chan ? chan : 0,
+ "i82975x CE");
+
+ return 1;
+}
+
+static void i82975x_check(struct mem_ctl_info *mci)
+{
+ struct i82975x_error_info info;
+
+ debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+ i82975x_get_error_info(mci, &info);
+ i82975x_process_error_info(mci, &info, 1);
+}
+
+/* Return 1 if dual channel mode is active. Else return 0. */
+static int dual_channel_active(void __iomem *mch_window)
+{
+ /*
+ * We treat interleaved-symmetric configuration as dual-channel - EAP's
+ * bit-0 giving the channel of the error location.
+ *
+ * All other configurations are treated as single channel - the EAP's
+ * bit-0 will resolve ok in symmetric area of mixed
+ * (symmetric/asymmetric) configurations
+ */
+ u8 drb[4][2];
+ int row;
+ int dualch;
+
+ for (dualch = 1, row = 0; dualch && (row < 4); row++) {
+ drb[row][0] = readb(mch_window + I82975X_DRB + row);
+ drb[row][1] = readb(mch_window + I82975X_DRB + row + 0x80);
+ dualch = dualch && (drb[row][0] == drb[row][1]);
+ }
+ return dualch;
+}
+
+static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
+{
+ /*
+ * ASUS P5W DH either does not program this register or programs
+ * it wrong!
+ * ECC is possible on i92975x ONLY with DEV_X8 which should mean 'val'
+ * for each rank should be 01b - the LSB of the word should be 0x55;
+ * but it reads 0!
+ */
+ return DEV_X8;
+}
+
+static void i82975x_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev, void __iomem *mch_window)
+{
+ struct csrow_info *csrow;
+ unsigned long last_cumul_size;
+ u8 value;
+ u32 cumul_size;
+ int index;
+
+ last_cumul_size = 0;
+
+ /*
+ * 82875 comment:
+ * The dram row boundary (DRB) reg values are boundary address
+ * for each DRAM row with a granularity of 32 or 64MB (single/dual
+ * channel operation). DRB regs are cumulative; therefore DRB7 will
+ * contain the total memory contained in all eight rows.
+ *
+ * FIXME:
+ * EDAC currently works for Dual-channel Interleaved configuration.
+ * Other configurations, which the chip supports, need fixing/testing.
+ *
+ */
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+
+ value = readb(mch_window + I82975X_DRB + index +
+ ((index >= 4) ? 0x80 : 0));
+ cumul_size = value;
+ cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT);
+ debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+ cumul_size);
+ if (cumul_size == last_cumul_size)
+ continue; /* not populated */
+
+ csrow->first_page = last_cumul_size;
+ csrow->last_page = cumul_size - 1;
+ csrow->nr_pages = cumul_size - last_cumul_size;
+ last_cumul_size = cumul_size;
+ csrow->grain = 1 << 7; /* I82975X_EAP has 128B resolution */
+ csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */
+ csrow->dtype = i82975x_dram_type(mch_window, index);
+ csrow->edac_mode = EDAC_SECDED; /* only supported */
+ }
+}
+
+/* #define i82975x_DEBUG_IOMEM */
+
+#ifdef i82975x_DEBUG_IOMEM
+static void i82975x_print_dram_timings(void __iomem *mch_window)
+{
+ /*
+ * The register meanings are from Intel specs;
+ * (shows 13-5-5-5 for 800-DDR2)
+ * Asus P5W Bios reports 15-5-4-4
+ * What's your religion?
+ */
+ static const int caslats[4] = { 5, 4, 3, 6 };
+ u32 dtreg[2];
+
+ dtreg[0] = readl(mch_window + 0x114);
+ dtreg[1] = readl(mch_window + 0x194);
+ i82975x_printk(KERN_INFO, "DRAM Timings : Ch0 Ch1\n"
+ " RAS Active Min = %d %d\n"
+ " CAS latency = %d %d\n"
+ " RAS to CAS = %d %d\n"
+ " RAS precharge = %d %d\n",
+ (dtreg[0] >> 19 ) & 0x0f,
+ (dtreg[1] >> 19) & 0x0f,
+ caslats[(dtreg[0] >> 8) & 0x03],
+ caslats[(dtreg[1] >> 8) & 0x03],
+ ((dtreg[0] >> 4) & 0x07) + 2,
+ ((dtreg[1] >> 4) & 0x07) + 2,
+ (dtreg[0] & 0x07) + 2,
+ (dtreg[1] & 0x07) + 2
+ );
+
+}
+#endif
+
+static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ int rc = -ENODEV;
+ struct mem_ctl_info *mci;
+ struct i82975x_pvt *pvt;
+ void __iomem *mch_window;
+ u32 mchbar;
+ u32 drc[2];
+ struct i82975x_error_info discard;
+ int chans;
+#ifdef i82975x_DEBUG_IOMEM
+ u8 c0drb[4];
+ u8 c1drb[4];
+#endif
+
+ debugf0("%s()\n", __func__);
+
+ pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar);
+ if (!(mchbar & 1)) {
+ debugf3("%s(): failed, MCHBAR disabled!\n", __func__);
+ goto fail0;
+ }
+ mchbar &= 0xffffc000; /* bits 31:14 used for 16K window */
+ mch_window = ioremap_nocache(mchbar, 0x1000);
+
+#ifdef i82975x_DEBUG_IOMEM
+ i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n",
+ mchbar, mch_window);
+
+ c0drb[0] = readb(mch_window + I82975X_DRB_CH0R0);
+ c0drb[1] = readb(mch_window + I82975X_DRB_CH0R1);
+ c0drb[2] = readb(mch_window + I82975X_DRB_CH0R2);
+ c0drb[3] = readb(mch_window + I82975X_DRB_CH0R3);
+ c1drb[0] = readb(mch_window + I82975X_DRB_CH1R0);
+ c1drb[1] = readb(mch_window + I82975X_DRB_CH1R1);
+ c1drb[2] = readb(mch_window + I82975X_DRB_CH1R2);
+ c1drb[3] = readb(mch_window + I82975X_DRB_CH1R3);
+ i82975x_printk(KERN_INFO, "DRBCH0R0 = 0x%02x\n", c0drb[0]);
+ i82975x_printk(KERN_INFO, "DRBCH0R1 = 0x%02x\n", c0drb[1]);
+ i82975x_printk(KERN_INFO, "DRBCH0R2 = 0x%02x\n", c0drb[2]);
+ i82975x_printk(KERN_INFO, "DRBCH0R3 = 0x%02x\n", c0drb[3]);
+ i82975x_printk(KERN_INFO, "DRBCH1R0 = 0x%02x\n", c1drb[0]);
+ i82975x_printk(KERN_INFO, "DRBCH1R1 = 0x%02x\n", c1drb[1]);
+ i82975x_printk(KERN_INFO, "DRBCH1R2 = 0x%02x\n", c1drb[2]);
+ i82975x_printk(KERN_INFO, "DRBCH1R3 = 0x%02x\n", c1drb[3]);
+#endif
+
+ drc[0] = readl(mch_window + I82975X_DRC_CH0M0);
+ drc[1] = readl(mch_window + I82975X_DRC_CH1M0);
+#ifdef i82975x_DEBUG_IOMEM
+ i82975x_printk(KERN_INFO, "DRC_CH0 = %0x, %s\n", drc[0],
+ ((drc[0] >> 21) & 3) == 1 ?
+ "ECC enabled" : "ECC disabled");
+ i82975x_printk(KERN_INFO, "DRC_CH1 = %0x, %s\n", drc[1],
+ ((drc[1] >> 21) & 3) == 1 ?
+ "ECC enabled" : "ECC disabled");
+
+ i82975x_printk(KERN_INFO, "C0 BNKARC = %0x\n",
+ readw(mch_window + I82975X_C0BNKARC));
+ i82975x_printk(KERN_INFO, "C1 BNKARC = %0x\n",
+ readw(mch_window + I82975X_C1BNKARC));
+ i82975x_print_dram_timings(mch_window);
+ goto fail1;
+#endif
+ if (!(((drc[0] >> 21) & 3) == 1 || ((drc[1] >> 21) & 3) == 1)) {
+ i82975x_printk(KERN_INFO, "ECC disabled on both channels.\n");
+ goto fail1;
+ }
+
+ chans = dual_channel_active(mch_window) + 1;
+
+ /* assuming only one controller, index thus is 0 */
+ mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans),
+ chans, 0);
+ if (!mci) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ debugf3("%s(): init mci\n", __func__);
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I82975X_REVISION;
+ mci->ctl_name = i82975x_devs[dev_idx].ctl_name;
+ mci->edac_check = i82975x_check;
+ mci->ctl_page_to_phys = NULL;
+ debugf3("%s(): init pvt\n", __func__);
+ pvt = (struct i82975x_pvt *) mci->pvt_info;
+ pvt->mch_window = mch_window;
+ i82975x_init_csrows(mci, pdev, mch_window);
+ i82975x_get_error_info(mci, &discard); /* clear counters */
+
+ /* finalize this instance of memory controller with edac core */
+ if (edac_mc_add_mc(mci)) {
+ debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail2;
+ }
+
+ /* get this far and it's successful */
+ debugf3("%s(): success\n", __func__);
+ return 0;
+
+fail2:
+ edac_mc_free(mci);
+
+fail1:
+ iounmap(mch_window);
+fail0:
+ return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82975x_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ debugf0("%s()\n", __func__);
+
+ if (pci_enable_device(pdev) < 0)
+ return -EIO;
+
+ rc = i82975x_probe1(pdev, ent->driver_data);
+
+ if (mci_pdev == NULL)
+ mci_pdev = pci_dev_get(pdev);
+
+ return rc;
+}
+
+static void __devexit i82975x_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+ struct i82975x_pvt *pvt;
+
+ debugf0("%s()\n", __func__);
+
+ mci = edac_mc_del_mc(&pdev->dev);
+ if (mci == NULL)
+ return;
+
+ pvt = mci->pvt_info;
+ if (pvt->mch_window)
+ iounmap( pvt->mch_window );
+
+ edac_mc_free(mci);
+}
+
+static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = {
+ {
+ PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I82975X
+ },
+ {
+ 0,
+ } /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl);
+
+static struct pci_driver i82975x_driver = {
+ .name = EDAC_MOD_STR,
+ .probe = i82975x_init_one,
+ .remove = __devexit_p(i82975x_remove_one),
+ .id_table = i82975x_pci_tbl,
+};
+
+static int __init i82975x_init(void)
+{
+ int pci_rc;
+
+ debugf3("%s()\n", __func__);
+
+ pci_rc = pci_register_driver(&i82975x_driver);
+ if (pci_rc < 0)
+ goto fail0;
+
+ if (mci_pdev == NULL) {
+ mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82975_0, NULL);
+
+ if (!mci_pdev) {
+ debugf0("i82975x pci_get_device fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+
+ pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl);
+
+ if (pci_rc < 0) {
+ debugf0("i82975x init fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+ }
+
+ return 0;
+
+fail1:
+ pci_unregister_driver(&i82975x_driver);
+
+fail0:
+ if (mci_pdev != NULL)
+ pci_dev_put(mci_pdev);
+
+ return pci_rc;
+}
+
+static void __exit i82975x_exit(void)
+{
+ debugf3("%s()\n", __func__);
+
+ pci_unregister_driver(&i82975x_driver);
+
+ if (!i82975x_registered) {
+ i82975x_remove_one(mci_pdev);
+ pci_dev_put(mci_pdev);
+ }
+}
+
+module_init(i82975x_init);
+module_exit(i82975x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
+MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
new file mode 100644
index 000000000000..e66cdd42a392
--- /dev/null
+++ b/drivers/edac/pasemi_edac.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip memory controllers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define MODULE_NAME "pasemi_edac"
+
+#define MCCFG_MCEN 0x300
+#define MCCFG_MCEN_MMC_EN 0x00000001
+#define MCCFG_ERRCOR 0x388
+#define MCCFG_ERRCOR_RNK_FAIL_DET_EN 0x00000100
+#define MCCFG_ERRCOR_ECC_GEN_EN 0x00000010
+#define MCCFG_ERRCOR_ECC_CRR_EN 0x00000001
+#define MCCFG_SCRUB 0x384
+#define MCCFG_SCRUB_RGLR_SCRB_EN 0x00000001
+#define MCDEBUG_ERRCTL1 0x728
+#define MCDEBUG_ERRCTL1_RFL_LOG_EN 0x00080000
+#define MCDEBUG_ERRCTL1_MBE_LOG_EN 0x00040000
+#define MCDEBUG_ERRCTL1_SBE_LOG_EN 0x00020000
+#define MCDEBUG_ERRSTA 0x730
+#define MCDEBUG_ERRSTA_RFL_STATUS 0x00000004
+#define MCDEBUG_ERRSTA_MBE_STATUS 0x00000002
+#define MCDEBUG_ERRSTA_SBE_STATUS 0x00000001
+#define MCDEBUG_ERRCNT1 0x734
+#define MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO 0x00000080
+#define MCDEBUG_ERRLOG1A 0x738
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_M 0x30000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_NONE 0x00000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_SBE 0x10000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_MBE 0x20000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_RFL 0x30000000
+#define MCDEBUG_ERRLOG1A_MERR_BA_M 0x00700000
+#define MCDEBUG_ERRLOG1A_MERR_BA_S 20
+#define MCDEBUG_ERRLOG1A_MERR_CS_M 0x00070000
+#define MCDEBUG_ERRLOG1A_MERR_CS_S 16
+#define MCDEBUG_ERRLOG1A_SYNDROME_M 0x0000ffff
+#define MCDRAM_RANKCFG 0x114
+#define MCDRAM_RANKCFG_EN 0x00000001
+#define MCDRAM_RANKCFG_TYPE_SIZE_M 0x000001c0
+#define MCDRAM_RANKCFG_TYPE_SIZE_S 6
+
+#define PASEMI_EDAC_NR_CSROWS 8
+#define PASEMI_EDAC_NR_CHANS 1
+#define PASEMI_EDAC_ERROR_GRAIN 64
+
+static int last_page_in_mmc;
+static int system_mmc_id;
+
+
+static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
+{
+ struct pci_dev *pdev = to_pci_dev(mci->dev);
+ u32 tmp;
+
+ pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
+ &tmp);
+
+ tmp &= (MCDEBUG_ERRSTA_RFL_STATUS | MCDEBUG_ERRSTA_MBE_STATUS
+ | MCDEBUG_ERRSTA_SBE_STATUS);
+
+ if (tmp) {
+ if (tmp & MCDEBUG_ERRSTA_SBE_STATUS)
+ pci_write_config_dword(pdev, MCDEBUG_ERRCNT1,
+ MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO);
+ pci_write_config_dword(pdev, MCDEBUG_ERRSTA, tmp);
+ }
+
+ return tmp;
+}
+
+static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
+{
+ struct pci_dev *pdev = to_pci_dev(mci->dev);
+ u32 errlog1a;
+ u32 cs;
+
+ if (!errsta)
+ return;
+
+ pci_read_config_dword(pdev, MCDEBUG_ERRLOG1A, &errlog1a);
+
+ cs = (errlog1a & MCDEBUG_ERRLOG1A_MERR_CS_M) >>
+ MCDEBUG_ERRLOG1A_MERR_CS_S;
+
+ /* uncorrectable/multi-bit errors */
+ if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
+ MCDEBUG_ERRSTA_RFL_STATUS)) {
+ edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0,
+ cs, mci->ctl_name);
+ }
+
+ /* correctable/single-bit errors */
+ if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) {
+ edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0,
+ 0, cs, 0, mci->ctl_name);
+ }
+}
+
+static void pasemi_edac_check(struct mem_ctl_info *mci)
+{
+ u32 errsta;
+
+ errsta = pasemi_edac_get_error_info(mci);
+ if (errsta)
+ pasemi_edac_process_error_info(mci, errsta);
+}
+
+static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev,
+ enum edac_type edac_mode)
+{
+ struct csrow_info *csrow;
+ u32 rankcfg;
+ int index;
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+
+ pci_read_config_dword(pdev,
+ MCDRAM_RANKCFG + (index * 12),
+ &rankcfg);
+
+ if (!(rankcfg & MCDRAM_RANKCFG_EN))
+ continue;
+
+ switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >>
+ MCDRAM_RANKCFG_TYPE_SIZE_S) {
+ case 0:
+ csrow->nr_pages = 128 << (20 - PAGE_SHIFT);
+ break;
+ case 1:
+ csrow->nr_pages = 256 << (20 - PAGE_SHIFT);
+ break;
+ case 2:
+ case 3:
+ csrow->nr_pages = 512 << (20 - PAGE_SHIFT);
+ break;
+ case 4:
+ csrow->nr_pages = 1024 << (20 - PAGE_SHIFT);
+ break;
+ case 5:
+ csrow->nr_pages = 2048 << (20 - PAGE_SHIFT);
+ break;
+ default:
+ edac_mc_printk(mci, KERN_ERR,
+ "Unrecognized Rank Config. rankcfg=%u\n",
+ rankcfg);
+ return -EINVAL;
+ }
+
+ csrow->first_page = last_page_in_mmc;
+ csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+ last_page_in_mmc += csrow->nr_pages;
+ csrow->page_mask = 0;
+ csrow->grain = PASEMI_EDAC_ERROR_GRAIN;
+ csrow->mtype = MEM_DDR;
+ csrow->dtype = DEV_UNKNOWN;
+ csrow->edac_mode = edac_mode;
+ }
+ return 0;
+}
+
+static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mem_ctl_info *mci = NULL;
+ u32 errctl1, errcor, scrub, mcen;
+
+ pci_read_config_dword(pdev, MCCFG_MCEN, &mcen);
+ if (!(mcen & MCCFG_MCEN_MMC_EN))
+ return -ENODEV;
+
+ /*
+ * We should think about enabling other error detection later on
+ */
+
+ pci_read_config_dword(pdev, MCDEBUG_ERRCTL1, &errctl1);
+ errctl1 |= MCDEBUG_ERRCTL1_SBE_LOG_EN |
+ MCDEBUG_ERRCTL1_MBE_LOG_EN |
+ MCDEBUG_ERRCTL1_RFL_LOG_EN;
+ pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1);
+
+ mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS,
+ system_mmc_id++);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ pci_read_config_dword(pdev, MCCFG_ERRCOR, &errcor);
+ errcor |= MCCFG_ERRCOR_RNK_FAIL_DET_EN |
+ MCCFG_ERRCOR_ECC_GEN_EN |
+ MCCFG_ERRCOR_ECC_CRR_EN;
+
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+ mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
+ ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ?
+ (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_EC) :
+ EDAC_FLAG_NONE;
+ mci->mod_name = MODULE_NAME;
+ mci->dev_name = pci_name(pdev);
+ mci->ctl_name = "pasemi,1682m-mc";
+ mci->edac_check = pasemi_edac_check;
+ mci->ctl_page_to_phys = NULL;
+ pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub);
+ mci->scrub_cap = SCRUB_FLAG_HW_PROG | SCRUB_FLAG_HW_SRC;
+ mci->scrub_mode =
+ ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ? SCRUB_FLAG_HW_SRC : 0) |
+ ((scrub & MCCFG_SCRUB_RGLR_SCRB_EN) ? SCRUB_FLAG_HW_PROG : 0);
+
+ if (pasemi_edac_init_csrows(mci, pdev,
+ (mci->edac_cap & EDAC_FLAG_SECDED) ?
+ EDAC_SECDED :
+ ((mci->edac_cap & EDAC_FLAG_EC) ?
+ EDAC_EC : EDAC_NONE)))
+ goto fail;
+
+ /*
+ * Clear status
+ */
+ pasemi_edac_get_error_info(mci);
+
+ if (edac_mc_add_mc(mci))
+ goto fail;
+
+ /* get this far and it's successful */
+ return 0;
+
+fail:
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
+
+ if (!mci)
+ return;
+
+ edac_mc_free(mci);
+}
+
+
+static const struct pci_device_id pasemi_edac_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
+
+static struct pci_driver pasemi_edac_driver = {
+ .name = MODULE_NAME,
+ .probe = pasemi_edac_probe,
+ .remove = __devexit_p(pasemi_edac_remove),
+ .id_table = pasemi_edac_pci_tbl,
+};
+
+static int __init pasemi_edac_init(void)
+{
+ return pci_register_driver(&pasemi_edac_driver);
+}
+
+static void __exit pasemi_edac_exit(void)
+{
+ pci_unregister_driver(&pasemi_edac_driver);
+}
+
+module_init(pasemi_edac_init);
+module_exit(pasemi_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller");
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index a49cf0a39398..e25f712f2dc3 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -11,7 +11,7 @@
*
* Written with reference to 82600 High Integration Dual PCI System
* Controller Data Book:
- * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
+ * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
* references to this document given in []
*/
@@ -20,9 +20,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define R82600_REVISION " Ver: 2.0.1 " __DATE__
+#define R82600_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "r82600_edac"
#define r82600_printk(level, fmt, arg...) \
@@ -131,10 +131,12 @@ struct r82600_error_info {
u32 eapr;
};
-static unsigned int disable_hardware_scrub = 0;
+static unsigned int disable_hardware_scrub;
-static void r82600_get_error_info (struct mem_ctl_info *mci,
- struct r82600_error_info *info)
+static struct edac_pci_ctl_info *r82600_pci;
+
+static void r82600_get_error_info(struct mem_ctl_info *mci,
+ struct r82600_error_info *info)
{
struct pci_dev *pdev;
@@ -144,18 +146,19 @@ static void r82600_get_error_info (struct mem_ctl_info *mci,
if (info->eapr & BIT(0))
/* Clear error to allow next error to be reported [p.62] */
pci_write_bits32(pdev, R82600_EAP,
- ((u32) BIT(0) & (u32) BIT(1)),
- ((u32) BIT(0) & (u32) BIT(1)));
+ ((u32) BIT(0) & (u32) BIT(1)),
+ ((u32) BIT(0) & (u32) BIT(1)));
if (info->eapr & BIT(1))
/* Clear error to allow next error to be reported [p.62] */
pci_write_bits32(pdev, R82600_EAP,
- ((u32) BIT(0) & (u32) BIT(1)),
- ((u32) BIT(0) & (u32) BIT(1)));
+ ((u32) BIT(0) & (u32) BIT(1)),
+ ((u32) BIT(0) & (u32) BIT(1)));
}
-static int r82600_process_error_info (struct mem_ctl_info *mci,
- struct r82600_error_info *info, int handle_errors)
+static int r82600_process_error_info(struct mem_ctl_info *mci,
+ struct r82600_error_info *info,
+ int handle_errors)
{
int error_found;
u32 eapaddr, page;
@@ -172,25 +175,24 @@ static int r82600_process_error_info (struct mem_ctl_info *mci,
* granularity (upper 19 bits only) */
page = eapaddr >> PAGE_SHIFT;
- if (info->eapr & BIT(0)) { /* CE? */
+ if (info->eapr & BIT(0)) { /* CE? */
error_found = 1;
if (handle_errors)
- edac_mc_handle_ce(mci, page, 0, /* not avail */
+ edac_mc_handle_ce(mci, page, 0, /* not avail */
syndrome,
edac_mc_find_csrow_by_page(mci, page),
- 0, /* channel */
- mci->ctl_name);
+ 0, mci->ctl_name);
}
- if (info->eapr & BIT(1)) { /* UE? */
+ if (info->eapr & BIT(1)) { /* UE? */
error_found = 1;
if (handle_errors)
/* 82600 doesn't give enough info */
edac_mc_handle_ue(mci, page, 0,
- edac_mc_find_csrow_by_page(mci, page),
- mci->ctl_name);
+ edac_mc_find_csrow_by_page(mci, page),
+ mci->ctl_name);
}
return error_found;
@@ -211,11 +213,11 @@ static inline int ecc_enabled(u8 dramcr)
}
static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- u8 dramcr)
+ u8 dramcr)
{
struct csrow_info *csrow;
int index;
- u8 drbar; /* SDRAM Row Boundry Address Register */
+ u8 drbar; /* SDRAM Row Boundry Address Register */
u32 row_high_limit, row_high_limit_last;
u32 reg_sdram, ecc_on, row_base;
@@ -276,7 +278,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
sdram_refresh_rate);
debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
- mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);
+ mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0);
if (mci == NULL)
return -ENOMEM;
@@ -305,15 +307,16 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = R82600_REVISION;
mci->ctl_name = "R82600";
+ mci->dev_name = pci_name(pdev);
mci->edac_check = r82600_check;
mci->ctl_page_to_phys = NULL;
r82600_init_csrows(mci, pdev, dramcr);
- r82600_get_error_info(mci, &discard); /* clear counters */
+ r82600_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
@@ -326,6 +329,17 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
}
+ /* allocating generic PCI control info */
+ r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!r82600_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
debugf3("%s(): success\n", __func__);
return 0;
@@ -336,7 +350,7 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit r82600_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
@@ -350,6 +364,9 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (r82600_pci)
+ edac_pci_release_generic_ctl(r82600_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
@@ -358,11 +375,11 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
{
- PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
- },
+ PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
+ },
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
@@ -389,7 +406,7 @@ module_exit(r82600_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
- "on behalf of EADS Astrium");
+ "on behalf of EADS Astrium");
MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
module_param(disable_hardware_scrub, bool, 0644);
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index d944647c82c2..4d4a47393909 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv)
return 0;
}
-static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct eisa_device *edev = to_eisa_device(dev);
- int i = 0;
- int length = 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
- envp[i] = NULL;
+ add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
return 0;
}
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index d011a76f8e7a..fe9e768cfbc4 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -11,7 +11,8 @@ config FIREWIRE
This is the "Juju" FireWire stack, a new alternative implementation
designed for robustness and simplicity. You can build either this
stack, or the classic stack (the ieee1394 driver, ohci1394 etc.)
- or both.
+ or both. Please read http://wiki.linux1394.org/JujuMigration before
+ you enable the new stack.
To compile this driver as a module, say M here: the module will be
called firewire-core. It functionally replaces ieee1394, raw1394,
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 0aeab3218bb6..3e9719948a8e 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -510,9 +510,11 @@ fw_core_remove_card(struct fw_card *card)
/* Set up the dummy driver. */
card->driver = &dummy_driver;
- fw_flush_transactions(card);
-
fw_destroy_nodes(card);
+ flush_scheduled_work();
+
+ fw_flush_transactions(card);
+ del_timer_sync(&card->flush_timer);
fw_card_put(card);
}
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 2b6586341635..56681b3b297b 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
}
static int
-fw_unit_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct fw_unit *unit = fw_unit(dev);
char modalias[64];
- int length = 0;
- int i = 0;
get_modalias(unit, modalias, sizeof(modalias));
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=%s", modalias))
+ if (add_uevent_var(env, "MODALIAS=%s", modalias))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 41476abc0693..e14c1ca7813e 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -224,6 +224,7 @@ ohci_update_phy_reg(struct fw_card *card, int addr,
u32 val, old;
reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+ flush_writes(ohci);
msleep(2);
val = reg_read(ohci, OHCI1394_PhyControl);
if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
@@ -586,7 +587,7 @@ static void context_stop(struct context *ctx)
break;
fw_notify("context_stop: still active (0x%08x)\n", reg);
- msleep(1);
+ mdelay(1);
}
}
@@ -906,6 +907,8 @@ static void bus_reset_tasklet(unsigned long data)
int self_id_count, i, j, reg;
int generation, new_generation;
unsigned long flags;
+ void *free_rom = NULL;
+ dma_addr_t free_rom_bus = 0;
reg = reg_read(ohci, OHCI1394_NodeID);
if (!(reg & OHCI1394_NodeID_idValid)) {
@@ -969,8 +972,8 @@ static void bus_reset_tasklet(unsigned long data)
*/
if (ohci->next_config_rom != NULL) {
- dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
- ohci->config_rom, ohci->config_rom_bus);
+ free_rom = ohci->config_rom;
+ free_rom_bus = ohci->config_rom_bus;
ohci->config_rom = ohci->next_config_rom;
ohci->config_rom_bus = ohci->next_config_rom_bus;
ohci->next_config_rom = NULL;
@@ -989,6 +992,10 @@ static void bus_reset_tasklet(unsigned long data)
spin_unlock_irqrestore(&ohci->lock, flags);
+ if (free_rom)
+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ free_rom, free_rom_bus);
+
fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
self_id_count, ohci->self_id_buffer);
}
@@ -1185,7 +1192,7 @@ ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
{
struct fw_ohci *ohci;
unsigned long flags;
- int retval = 0;
+ int retval = -EBUSY;
__be32 *next_config_rom;
dma_addr_t next_config_rom_bus;
@@ -1239,10 +1246,7 @@ ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
reg_write(ohci, OHCI1394_ConfigROMmap,
ohci->next_config_rom_bus);
- } else {
- dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
- next_config_rom, next_config_rom_bus);
- retval = -EBUSY;
+ retval = 0;
}
spin_unlock_irqrestore(&ohci->lock, flags);
@@ -1256,6 +1260,9 @@ ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
*/
if (retval == 0)
fw_core_initiate_bus_reset(&ohci->card, 1);
+ else
+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ next_config_rom, next_config_rom_bus);
return retval;
}
@@ -1938,10 +1945,8 @@ static int pci_suspend(struct pci_dev *pdev, pm_message_t state)
return err;
}
err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
- if (err) {
- fw_error("pci_set_power_state failed\n");
- return err;
- }
+ if (err)
+ fw_error("pci_set_power_state failed with %d\n", err);
return 0;
}
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 7c53be0387fb..238730f75db1 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -159,6 +159,7 @@ struct sbp2_pointer {
struct sbp2_orb {
struct fw_transaction t;
+ struct kref kref;
dma_addr_t request_bus;
int rcode;
struct sbp2_pointer pointer;
@@ -280,6 +281,14 @@ static const struct {
};
static void
+free_orb(struct kref *kref)
+{
+ struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref);
+
+ kfree(orb);
+}
+
+static void
sbp2_status_write(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source,
int generation, int speed,
@@ -312,8 +321,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(orb, &sd->orb_list, link) {
if (STATUS_GET_ORB_HIGH(status) == 0 &&
- STATUS_GET_ORB_LOW(status) == orb->request_bus &&
- orb->rcode == RCODE_COMPLETE) {
+ STATUS_GET_ORB_LOW(status) == orb->request_bus) {
+ orb->rcode = RCODE_COMPLETE;
list_del(&orb->link);
break;
}
@@ -325,6 +334,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
else
fw_error("status write for unknown orb\n");
+ kref_put(&orb->kref, free_orb);
+
fw_send_response(card, request, RCODE_COMPLETE);
}
@@ -335,13 +346,27 @@ complete_transaction(struct fw_card *card, int rcode,
struct sbp2_orb *orb = data;
unsigned long flags;
- orb->rcode = rcode;
- if (rcode != RCODE_COMPLETE) {
- spin_lock_irqsave(&card->lock, flags);
+ /*
+ * This is a little tricky. We can get the status write for
+ * the orb before we get this callback. The status write
+ * handler above will assume the orb pointer transaction was
+ * successful and set the rcode to RCODE_COMPLETE for the orb.
+ * So this callback only sets the rcode if it hasn't already
+ * been set and only does the cleanup if the transaction
+ * failed and we didn't already get a status write.
+ */
+ spin_lock_irqsave(&card->lock, flags);
+
+ if (orb->rcode == -1)
+ orb->rcode = rcode;
+ if (orb->rcode != RCODE_COMPLETE) {
list_del(&orb->link);
- spin_unlock_irqrestore(&card->lock, flags);
orb->callback(orb, NULL);
}
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ kref_put(&orb->kref, free_orb);
}
static void
@@ -360,6 +385,10 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
list_add_tail(&orb->link, &sd->orb_list);
spin_unlock_irqrestore(&device->card->lock, flags);
+ /* Take a ref for the orb list and for the transaction callback. */
+ kref_get(&orb->kref);
+ kref_get(&orb->kref);
+
fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
node_id, generation, device->max_speed, offset,
&orb->pointer, sizeof(orb->pointer),
@@ -416,6 +445,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
if (orb == NULL)
return -ENOMEM;
+ kref_init(&orb->base.kref);
orb->response_bus =
dma_map_single(device->card->device, &orb->response,
sizeof(orb->response), DMA_FROM_DEVICE);
@@ -490,7 +520,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
if (response)
fw_memcpy_from_be32(response,
orb->response, sizeof(orb->response));
- kfree(orb);
+ kref_put(&orb->base.kref, free_orb);
return retval;
}
@@ -840,7 +870,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
container_of(base_orb, struct sbp2_command_orb, base);
struct fw_unit *unit = orb->unit;
struct fw_device *device = fw_device(unit->device.parent);
- struct scatterlist *sg;
int result;
if (status != NULL) {
@@ -876,11 +905,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
dma_unmap_single(device->card->device, orb->base.request_bus,
sizeof(orb->request), DMA_TO_DEVICE);
- if (orb->cmd->use_sg > 0) {
- sg = (struct scatterlist *)orb->cmd->request_buffer;
- dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+ if (scsi_sg_count(orb->cmd) > 0)
+ dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+ scsi_sg_count(orb->cmd),
orb->cmd->sc_data_direction);
- }
if (orb->page_table_bus != 0)
dma_unmap_single(device->card->device, orb->page_table_bus,
@@ -888,7 +916,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
orb->cmd->result = result;
orb->done(orb->cmd);
- kfree(orb);
}
static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
@@ -901,8 +928,8 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
int sg_len, l, i, j, count;
dma_addr_t sg_addr;
- sg = (struct scatterlist *)orb->cmd->request_buffer;
- count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+ sg = scsi_sglist(orb->cmd);
+ count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
orb->cmd->sc_data_direction);
if (count == 0)
goto fail;
@@ -971,7 +998,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
return 0;
fail_page_table:
- dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+ dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
orb->cmd->sc_data_direction);
fail:
return -ENOMEM;
@@ -986,6 +1013,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
struct fw_unit *unit = sd->unit;
struct fw_device *device = fw_device(unit->device.parent);
struct sbp2_command_orb *orb;
+ unsigned max_payload;
/*
* Bidirectional commands are not yet implemented, and unknown
@@ -1006,6 +1034,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
/* Initialize rcode to something not RCODE_COMPLETE. */
orb->base.rcode = -1;
+ kref_init(&orb->base.kref);
orb->unit = unit;
orb->done = done;
@@ -1019,8 +1048,10 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
* specifies the max payload size as 2 ^ (max_payload + 2), so
* if we set this to max_speed + 7, we get the right value.
*/
+ max_payload = min(device->max_speed + 7,
+ device->card->max_receive - 1);
orb->request.misc =
- COMMAND_ORB_MAX_PAYLOAD(device->max_speed + 7) |
+ COMMAND_ORB_MAX_PAYLOAD(max_payload) |
COMMAND_ORB_SPEED(device->max_speed) |
COMMAND_ORB_NOTIFY;
@@ -1031,7 +1062,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
orb->request.misc |=
COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
- if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+ if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0)
goto fail_mapping;
fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
@@ -1050,10 +1081,11 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
sd->command_block_agent_address + SBP2_ORB_POINTER);
+ kref_put(&orb->base.kref, free_orb);
return 0;
fail_mapping:
- kfree(orb);
+ kref_put(&orb->base.kref, free_orb);
fail_alloc:
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1162,7 +1194,7 @@ static struct device_attribute *sbp2_scsi_sysfs_attrs[] = {
static struct scsi_host_template scsi_driver_template = {
.module = THIS_MODULE,
.name = "SBP-2 IEEE-1394",
- .proc_name = (char *)sbp2_driver_name,
+ .proc_name = sbp2_driver_name,
.queuecommand = sbp2_scsi_queuecommand,
.slave_alloc = sbp2_scsi_slave_alloc,
.slave_configure = sbp2_scsi_slave_configure,
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 80d0121463d0..3e1cb12e43cd 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -605,8 +605,10 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
* check is sufficient to ensure we don't send response to
* broadcast packets or posted writes.
*/
- if (request->ack != ACK_PENDING)
+ if (request->ack != ACK_PENDING) {
+ kfree(request);
return;
+ }
if (rcode == RCODE_COMPLETE)
fw_fill_response(&request->response, request->request_header,
@@ -628,11 +630,6 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
unsigned long flags;
int tcode, destination, source;
- if (p->payload_length > 2048) {
- /* FIXME: send error response. */
- return;
- }
-
if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
return;
@@ -737,7 +734,7 @@ fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
}
EXPORT_SYMBOL(fw_core_handle_response);
-const struct fw_address_region topology_map_region =
+static const struct fw_address_region topology_map_region =
{ .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };
static void
@@ -775,7 +772,7 @@ static struct fw_address_handler topology_map = {
.address_callback = handle_topology_map,
};
-const struct fw_address_region registers_region =
+static const struct fw_address_region registers_region =
{ .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, };
static void
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index 5abed193f4a6..fa7967b57408 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -123,6 +123,10 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
size_t length,
void *callback_data);
+/*
+ * Important note: The callback must guarantee that either fw_send_response()
+ * or kfree() is called on the @request.
+ */
typedef void (*fw_address_callback_t)(struct fw_card *card,
struct fw_request *request,
int tcode, int destination, int source,
@@ -227,7 +231,7 @@ struct fw_card {
unsigned long reset_jiffies;
unsigned long long guid;
- int max_receive;
+ unsigned max_receive;
int link_speed;
int config_rom_generation;
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 59c3b5aa89f4..b6e1eb77d148 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -13,21 +13,31 @@
#include <linux/device.h>
#include <linux/autoconf.h>
-#define DEFINE_DMI_ATTR(_name, _mode, _show) \
-static struct device_attribute sys_dmi_##_name##_attr = \
- __ATTR(_name, _mode, _show, NULL);
-
-#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
-static ssize_t sys_dmi_##_name##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *page) \
-{ \
- ssize_t len; \
- len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
- page[len-1] = '\n'; \
- return len; \
-} \
-DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+struct dmi_device_attribute{
+ struct device_attribute dev_attr;
+ int field;
+};
+#define to_dmi_dev_attr(_dev_attr) \
+ container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
+
+static ssize_t sys_dmi_field_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ int field = to_dmi_dev_attr(attr)->field;
+ ssize_t len;
+ len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
+ page[len-1] = '\n';
+ return len;
+}
+
+#define DMI_ATTR(_name, _mode, _show, _field) \
+ { .dev_attr = __ATTR(_name, _mode, _show, NULL), \
+ .field = _field }
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
+static struct dmi_device_attribute sys_dmi_##_name##_attr = \
+ DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
@@ -121,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev,
return r+1;
}
-DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+static struct device_attribute sys_dmi_modalias_attr =
+ __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
@@ -134,14 +145,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = {
NULL
};
-static int dmi_dev_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- strcpy(buffer, "MODALIAS=");
- get_modalias(buffer+9, buffer_size-9);
- envp[0] = buffer;
- envp[1] = NULL;
-
+ ssize_t len;
+
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+ len = get_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
@@ -157,7 +171,7 @@ static struct device *dmi_dev;
#define ADD_DMI_ATTR(_name, _field) \
if (dmi_get_system_info(_field)) \
- sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+ sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
extern int dmi_available;
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index f7318b3b51f2..0cdadea7a40e 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -8,9 +8,9 @@
#include <linux/slab.h>
#include <asm/dmi.h>
-static char * __init dmi_string(struct dmi_header *dm, u8 s)
+static char * __init dmi_string(const struct dmi_header *dm, u8 s)
{
- u8 *bp = ((u8 *) dm) + dm->length;
+ const u8 *bp = ((u8 *) dm) + dm->length;
char *str = "";
if (s) {
@@ -37,7 +37,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
* pointing to completely the wrong place for example
*/
static int __init dmi_table(u32 base, int len, int num,
- void (*decode)(struct dmi_header *))
+ void (*decode)(const struct dmi_header *))
{
u8 *buf, *data;
int i = 0;
@@ -53,7 +53,8 @@ static int __init dmi_table(u32 base, int len, int num,
* OR we run off the end of the table (also happens)
*/
while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
- struct dmi_header *dm = (struct dmi_header *)data;
+ const struct dmi_header *dm = (const struct dmi_header *)data;
+
/*
* We want to know the total length (formated area and strings)
* before decoding to make sure we won't run off the table in
@@ -71,7 +72,7 @@ static int __init dmi_table(u32 base, int len, int num,
return 0;
}
-static int __init dmi_checksum(u8 *buf)
+static int __init dmi_checksum(const u8 *buf)
{
u8 sum = 0;
int a;
@@ -89,9 +90,10 @@ int dmi_available;
/*
* Save a DMI string
*/
-static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
+static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string)
{
- char *p, *d = (char*) dm;
+ const char *d = (const char*) dm;
+ char *p;
if (dmi_ident[slot])
return;
@@ -103,9 +105,9 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
dmi_ident[slot] = p;
}
-static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index)
{
- u8 *d = (u8*) dm + index;
+ const u8 *d = (u8*) dm + index;
char *s;
int is_ff = 1, is_00 = 1, i;
@@ -132,9 +134,9 @@ static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
dmi_ident[slot] = s;
}
-static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index)
{
- u8 *d = (u8*) dm + index;
+ const u8 *d = (u8*) dm + index;
char *s;
if (dmi_ident[slot])
@@ -148,13 +150,13 @@ static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
dmi_ident[slot] = s;
}
-static void __init dmi_save_devices(struct dmi_header *dm)
+static void __init dmi_save_devices(const struct dmi_header *dm)
{
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
struct dmi_device *dev;
for (i = 0; i < count; i++) {
- char *d = (char *)(dm + 1) + (i * 2);
+ const char *d = (char *)(dm + 1) + (i * 2);
/* Skip disabled device */
if ((*d & 0x80) == 0)
@@ -173,7 +175,7 @@ static void __init dmi_save_devices(struct dmi_header *dm)
}
}
-static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
+static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
{
int i, count = *(u8 *)(dm + 1);
struct dmi_device *dev;
@@ -194,7 +196,7 @@ static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
}
}
-static void __init dmi_save_ipmi_device(struct dmi_header *dm)
+static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
{
struct dmi_device *dev;
void * data;
@@ -225,7 +227,7 @@ static void __init dmi_save_ipmi_device(struct dmi_header *dm)
* and machine entries. For 2.5 we should pull the smbus controller info
* out of here.
*/
-static void __init dmi_decode(struct dmi_header *dm)
+static void __init dmi_decode(const struct dmi_header *dm)
{
switch(dm->type) {
case 0: /* BIOS Information */
@@ -265,9 +267,10 @@ static void __init dmi_decode(struct dmi_header *dm)
}
}
-static int __init dmi_present(char __iomem *p)
+static int __init dmi_present(const char __iomem *p)
{
u8 buf[15];
+
memcpy_fromio(buf, p, 15);
if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
u16 num = (buf[13] << 8) | buf[12];
@@ -348,10 +351,10 @@ void __init dmi_scan_machine(void)
* returns non zero or we hit the end. Callback function is called for
* each successful match. Returns the number of matches.
*/
-int dmi_check_system(struct dmi_system_id *list)
+int dmi_check_system(const struct dmi_system_id *list)
{
int i, count = 0;
- struct dmi_system_id *d = list;
+ const struct dmi_system_id *d = list;
while (d->ident) {
for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
@@ -380,7 +383,7 @@ EXPORT_SYMBOL(dmi_check_system);
* Returns one DMI data value, can be used to perform
* complex DMI data checks.
*/
-char *dmi_get_system_info(int field)
+const char *dmi_get_system_info(int field)
{
return dmi_ident[field];
}
@@ -391,7 +394,7 @@ EXPORT_SYMBOL(dmi_get_system_info);
* dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
* @str: Case sensitive Name
*/
-int dmi_name_in_vendors(char *str)
+int dmi_name_in_vendors(const char *str)
{
static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
@@ -418,13 +421,15 @@ EXPORT_SYMBOL(dmi_name_in_vendors);
* A new search is initiated by passing %NULL as the @from argument.
* If @from is not %NULL, searches continue from next device.
*/
-struct dmi_device * dmi_find_device(int type, const char *name,
- struct dmi_device *from)
+const struct dmi_device * dmi_find_device(int type, const char *name,
+ const struct dmi_device *from)
{
- struct list_head *d, *head = from ? &from->list : &dmi_devices;
+ const struct list_head *head = from ? &from->list : &dmi_devices;
+ struct list_head *d;
for(d = head->next; d != &dmi_devices; d = d->next) {
- struct dmi_device *dev = list_entry(d, struct dmi_device, list);
+ const struct dmi_device *dev =
+ list_entry(d, struct dmi_device, list);
if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
((name == NULL) || (strcmp(dev->name, name) == 0)))
@@ -444,7 +449,7 @@ EXPORT_SYMBOL(dmi_find_device);
int dmi_get_year(int field)
{
int year;
- char *s = dmi_get_system_info(field);
+ const char *s = dmi_get_system_info(field);
if (!s)
return -1;
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 0fb730ee1da8..6942e065e609 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj)
kfree(dev);
}
-static struct kobj_type ktype_edd = {
+static struct kobj_type edd_ktype = {
.release = edd_release,
.sysfs_ops = &edd_attr_ops,
.default_attrs = def_attrs,
};
-static decl_subsys(edd,&ktype_edd,NULL);
+static decl_subsys(edd, &edd_ktype, NULL);
/**
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index bfd2d67df689..858a7b95933b 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = {
NULL,
};
-static struct kobj_type ktype_efivar = {
+static struct kobj_type efivar_ktype = {
.release = efivar_release,
.sysfs_ops = &efivar_attr_ops,
.default_attrs = def_attrs,
@@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = {
NULL, /* maybe more in the future? */
};
-static decl_subsys(vars, &ktype_efivar, NULL);
+static decl_subsys(vars, &efivar_ktype, NULL);
static decl_subsys(efi, NULL, NULL);
/*
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 3b63b0b78122..19667fcc722a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -5,6 +5,11 @@ menuconfig HID_SUPPORT
bool "HID Devices"
depends on INPUT
default y
+ ---help---
+ Say Y here to get to see options for various computer-human interface
+ device drivers. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if HID_SUPPORT
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b2baeaeba9be..0a1f2b52a12f 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -743,7 +743,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
hid->quirks = quirks;
if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
- goto fail;
+ goto fail_no_usbhid;
hid->driver_data = usbhid;
usbhid->hid = hid;
@@ -878,6 +878,8 @@ fail:
usb_free_urb(usbhid->urbout);
usb_free_urb(usbhid->urbctrl);
hid_free_buffers(dev, hid);
+ kfree(usbhid);
+fail_no_usbhid:
hid_free_device(hid);
return NULL;
@@ -913,6 +915,7 @@ static void hid_disconnect(struct usb_interface *intf)
usb_free_urb(usbhid->urbout);
hid_free_buffers(hid_to_usb_dev(hid), hid);
+ kfree(usbhid);
hid_free_device(hid);
}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 775b9f3b8ce3..6b21a214f419 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -61,7 +61,9 @@
#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
-#define USB_DEVICE_ID_APPLE_IR 0x8240
+
+#define USB_VENDOR_ID_ASUS 0x0b05
+#define USB_DEVICE_ID_ASUS_LCM 0x1726
#define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
@@ -198,6 +200,70 @@
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
+#define USB_DEVICE_ID_LOGITECH_HARMONY 0xc110
+#define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111
+#define USB_DEVICE_ID_LOGITECH_HARMONY_3 0xc112
+#define USB_DEVICE_ID_LOGITECH_HARMONY_4 0xc113
+#define USB_DEVICE_ID_LOGITECH_HARMONY_5 0xc114
+#define USB_DEVICE_ID_LOGITECH_HARMONY_6 0xc115
+#define USB_DEVICE_ID_LOGITECH_HARMONY_7 0xc116
+#define USB_DEVICE_ID_LOGITECH_HARMONY_8 0xc117
+#define USB_DEVICE_ID_LOGITECH_HARMONY_9 0xc118
+#define USB_DEVICE_ID_LOGITECH_HARMONY_10 0xc119
+#define USB_DEVICE_ID_LOGITECH_HARMONY_11 0xc11a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_12 0xc11b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_13 0xc11c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_14 0xc11d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_15 0xc11e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_16 0xc11f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_17 0xc120
+#define USB_DEVICE_ID_LOGITECH_HARMONY_18 0xc121
+#define USB_DEVICE_ID_LOGITECH_HARMONY_19 0xc122
+#define USB_DEVICE_ID_LOGITECH_HARMONY_20 0xc123
+#define USB_DEVICE_ID_LOGITECH_HARMONY_21 0xc124
+#define USB_DEVICE_ID_LOGITECH_HARMONY_22 0xc125
+#define USB_DEVICE_ID_LOGITECH_HARMONY_23 0xc126
+#define USB_DEVICE_ID_LOGITECH_HARMONY_24 0xc127
+#define USB_DEVICE_ID_LOGITECH_HARMONY_25 0xc128
+#define USB_DEVICE_ID_LOGITECH_HARMONY_26 0xc129
+#define USB_DEVICE_ID_LOGITECH_HARMONY_27 0xc12a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_28 0xc12b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_29 0xc12c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_30 0xc12d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_31 0xc12e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_32 0xc12f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_33 0xc130
+#define USB_DEVICE_ID_LOGITECH_HARMONY_34 0xc131
+#define USB_DEVICE_ID_LOGITECH_HARMONY_35 0xc132
+#define USB_DEVICE_ID_LOGITECH_HARMONY_36 0xc133
+#define USB_DEVICE_ID_LOGITECH_HARMONY_37 0xc134
+#define USB_DEVICE_ID_LOGITECH_HARMONY_38 0xc135
+#define USB_DEVICE_ID_LOGITECH_HARMONY_39 0xc136
+#define USB_DEVICE_ID_LOGITECH_HARMONY_40 0xc137
+#define USB_DEVICE_ID_LOGITECH_HARMONY_41 0xc138
+#define USB_DEVICE_ID_LOGITECH_HARMONY_42 0xc139
+#define USB_DEVICE_ID_LOGITECH_HARMONY_43 0xc13a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_44 0xc13b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_45 0xc13c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_46 0xc13d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_47 0xc13e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_48 0xc13f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_49 0xc140
+#define USB_DEVICE_ID_LOGITECH_HARMONY_50 0xc141
+#define USB_DEVICE_ID_LOGITECH_HARMONY_51 0xc142
+#define USB_DEVICE_ID_LOGITECH_HARMONY_52 0xc143
+#define USB_DEVICE_ID_LOGITECH_HARMONY_53 0xc144
+#define USB_DEVICE_ID_LOGITECH_HARMONY_54 0xc145
+#define USB_DEVICE_ID_LOGITECH_HARMONY_55 0xc146
+#define USB_DEVICE_ID_LOGITECH_HARMONY_56 0xc147
+#define USB_DEVICE_ID_LOGITECH_HARMONY_57 0xc148
+#define USB_DEVICE_ID_LOGITECH_HARMONY_58 0xc149
+#define USB_DEVICE_ID_LOGITECH_HARMONY_59 0xc14a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_60 0xc14b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_61 0xc14c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_KBD 0xc311
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
@@ -221,6 +287,9 @@
#define USB_DEVICE_ID_NCR_FIRST 0x0300
#define USB_DEVICE_ID_NCR_LAST 0x03ff
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY 0xc359
+
#define USB_VENDOR_ID_NEC 0x073e
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
@@ -315,7 +384,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
@@ -463,6 +532,71 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_2, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_3, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_4, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_5, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_6, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_7, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_8, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_9, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_10, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_11, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_12, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_13, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_14, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_15, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_16, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_17, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_18, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_19, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_21, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_22, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_23, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_24, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_25, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_26, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_27, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_28, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_29, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_31, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_32, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_33, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_34, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_35, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_36, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_37, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_38, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_39, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_40, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_41, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_42, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_43, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_44, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_45, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_46, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_47, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_48, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_49, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_50, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_51, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_52, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_53, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_54, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_55, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_56, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_57, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_58, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_59, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_60, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_61, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_62, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE },
{ 0, 0 }
};
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 99c82b1af8c9..e8f44b580f0a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -29,17 +29,34 @@ config HWMON_VID
default n
config SENSORS_ABITUGURU
- tristate "Abit uGuru"
+ tristate "Abit uGuru (rev 1 & 2)"
depends on EXPERIMENTAL
help
- If you say yes here you get support for the Abit uGuru chips
- sensor part. The voltage and frequency control parts of the Abit
- uGuru are not supported. The Abit uGuru chip can be found on Abit
- uGuru featuring motherboards (most modern Abit motherboards).
+ If you say yes here you get support for the sensor part of the first
+ and second revision of the Abit uGuru chip. The voltage and frequency
+ control parts of the Abit uGuru are not supported. The Abit uGuru
+ chip can be found on Abit uGuru featuring motherboards (most modern
+ Abit motherboards from before end 2005). For more info and a list
+ of which motherboards have which revision see
+ Documentation/hwmon/abituguru
This driver can also be built as a module. If so, the module
will be called abituguru.
+config SENSORS_ABITUGURU3
+ tristate "Abit uGuru (rev 3)"
+ depends on HWMON && EXPERIMENTAL
+ help
+ If you say yes here you get support for the sensor part of the
+ third revision of the Abit uGuru chip. Only reading the sensors
+ and their settings is supported. The third revision of the Abit
+ uGuru chip can be found on recent Abit motherboards (since end
+ 2005). For more info and a list of which motherboards have which
+ revision see Documentation/hwmon/abituguru3
+
+ This driver can also be built as a module. If so, the module
+ will be called abituguru3.
+
config SENSORS_AD7418
tristate "Analog Devices AD7416, AD7417 and AD7418"
depends on I2C && EXPERIMENTAL
@@ -251,12 +268,10 @@ config SENSORS_CORETEMP
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
- depends on I2C
- select I2C_ISA
select HWMON_VID
help
If you say yes here you get support for ITE IT8705F, IT8712F,
- IT8716F and IT8718F sensor chips, and the SiS960 clone.
+ IT8716F, IT8718F and IT8726F sensor chips, and the SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
@@ -366,8 +381,8 @@ config SENSORS_LM90
depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
- LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
- MAX6658 sensor chips.
+ LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657,
+ MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
The Analog Devices ADT7461 sensor chip is also supported, but only
if found in ADM1032 compatibility mode.
@@ -385,6 +400,17 @@ config SENSORS_LM92
This driver can also be built as a module. If so, the module
will be called lm92.
+config SENSORS_LM93
+ tristate "National Semiconductor LM93 and compatibles"
+ depends on HWMON && I2C
+ select HWMON_VID
+ help
+ If you say yes here you get support for National Semiconductor LM93
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm93.
+
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C
@@ -406,8 +432,6 @@ config SENSORS_MAX6650
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
- depends on I2C && EXPERIMENTAL
- select I2C_ISA
select HWMON_VID
help
If you say yes here you get access to the hardware monitoring
@@ -434,8 +458,7 @@ config SENSORS_PC87427
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
- depends on I2C && PCI && EXPERIMENTAL
- select I2C_ISA
+ depends on PCI
help
If you say yes here you get support for the integrated sensors in
SiS5595 South Bridges.
@@ -443,6 +466,18 @@ config SENSORS_SIS5595
This driver can also be built as a module. If so, the module
will be called sis5595.
+config SENSORS_DME1737
+ tristate "SMSC DME1737 and compatibles"
+ depends on I2C && EXPERIMENTAL
+ select HWMON_VID
+ help
+ If you say yes here you get support for the hardware monitoring
+ and fan control features of the SMSC DME1737 (and compatibles
+ like the Asus A8000) Super-I/O chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called dme1737.
+
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
help
@@ -486,10 +521,19 @@ config SENSORS_SMSC47B397
This driver can also be built as a module. If so, the module
will be called smsc47b397.
+config SENSORS_THMC50
+ tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for Texas Instruments THMC50
+ sensor chips and clones: the Analog Devices ADM1022.
+
+ This driver can also be built as a module. If so, the module
+ will be called thmc50.
+
config SENSORS_VIA686A
tristate "VIA686A"
- depends on I2C && PCI
- select I2C_ISA
+ depends on PCI
help
If you say yes here you get support for the integrated sensors in
Via 686A/B South Bridges.
@@ -510,9 +554,8 @@ config SENSORS_VT1211
config SENSORS_VT8231
tristate "VIA VT8231"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI
select HWMON_VID
- select I2C_ISA
help
If you say yes here then you get support for the integrated sensors
in the VIA VT8231 device.
@@ -585,17 +628,16 @@ config SENSORS_W83627HF
will be called w83627hf.
config SENSORS_W83627EHF
- tristate "Winbond W83627EHF"
- depends on I2C && EXPERIMENTAL
- select I2C_ISA
+ tristate "Winbond W83627EHF/DHG"
+ select HWMON_VID
help
- If you say yes here you get preliminary support for the hardware
+ If you say yes here you get support for the hardware
monitoring functionality of the Winbond W83627EHF Super-I/O chip.
- Only fan and temperature inputs are supported at the moment, while
- the chip does much more than that.
This driver also supports the W83627EHG, which is the lead-free
- version of the W83627EHF.
+ version of the W83627EHF, and the W83627DHG, which is a similar
+ chip suited for specific Intel processors that use PECI such as
+ the Core 2 Duo.
This driver can also be built as a module. If so, the module
will be called w83627ehf.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index cfaf338919dd..d04f90031ebf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
+obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
+obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
@@ -45,6 +47,7 @@ obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
+obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
@@ -53,6 +56,7 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index bede4d990ea6..2317f4bb9c92 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -16,9 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
- This driver supports the sensor part of the custom Abit uGuru chip found
- on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
- etc voltage & frequency control is not supported!
+ This driver supports the sensor part of the first and second revision of
+ the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
+ of lack of specs the CPU/RAM voltage & frequency control is not supported!
*/
#include <linux/module.h>
#include <linux/sched.h>
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
#include <asm/io.h>
/* Banks */
@@ -418,7 +419,7 @@ static int __devinit
abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
u8 sensor_addr)
{
- u8 val, buf[3];
+ u8 val, test_flag, buf[3];
int i, ret = -ENODEV; /* error is the most common used retval :| */
/* If overriden by the user return the user selected type */
@@ -436,7 +437,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
return -ENODEV;
/* Test val is sane / usable for sensor type detection. */
- if ((val < 10u) || (val > 240u)) {
+ if ((val < 10u) || (val > 250u)) {
printk(KERN_WARNING ABIT_UGURU_NAME
": bank1-sensor: %d reading (%d) too close to limits, "
"unable to determine sensor type, skipping sensor\n",
@@ -449,10 +450,20 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
/* Volt sensor test, enable volt low alarm, set min value ridicously
- high. If its a volt sensor this should always give us an alarm. */
- buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
- buf[1] = 245;
- buf[2] = 250;
+ high, or vica versa if the reading is very high. If its a volt
+ sensor this should always give us an alarm. */
+ if (val <= 240u) {
+ buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+ buf[1] = 245;
+ buf[2] = 250;
+ test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG;
+ } else {
+ buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE;
+ buf[1] = 5;
+ buf[2] = 10;
+ test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG;
+ }
+
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
buf, 3) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
@@ -469,13 +480,13 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
sensor_addr, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
- if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+ if (buf[0] & test_flag) {
ABIT_UGURU_DEBUG(2, " found volt sensor\n");
ret = ABIT_UGURU_IN_SENSOR;
goto abituguru_detect_bank1_sensor_type_exit;
} else
ABIT_UGURU_DEBUG(2, " alarm raised during volt "
- "sensor test, but volt low flag not set\n");
+ "sensor test, but volt range flag not set\n");
} else
ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor "
"test\n");
@@ -1287,6 +1298,7 @@ abituguru_probe_error:
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return res;
}
@@ -1296,13 +1308,13 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -1436,6 +1448,15 @@ static int __init abituguru_init(void)
int address, err;
struct resource res = { .flags = IORESOURCE_IO };
+#ifdef CONFIG_DMI
+ const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+ /* safety check, refuse to load on non Abit motherboards */
+ if (!force && (!board_vendor ||
+ strcmp(board_vendor, "http://www.abit.com.tw/")))
+ return -ENODEV;
+#endif
+
address = abituguru_detect();
if (address < 0)
return address;
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
new file mode 100644
index 000000000000..cdd8b6dea16d
--- /dev/null
+++ b/drivers/hwmon/abituguru3.c
@@ -0,0 +1,1141 @@
+/*
+ abituguru3.c Copyright (c) 2006 Hans de Goede <j.w.r.degoede@hhs.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ This driver supports the sensor part of revision 3 of the custom Abit uGuru
+ chip found on newer Abit uGuru motherboards. Note: because of lack of specs
+ only reading the sensors and their settings is supported.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+
+/* uGuru3 bank addresses */
+#define ABIT_UGURU3_SETTINGS_BANK 0x01
+#define ABIT_UGURU3_SENSORS_BANK 0x08
+#define ABIT_UGURU3_MISC_BANK 0x09
+#define ABIT_UGURU3_ALARMS_START 0x1E
+#define ABIT_UGURU3_SETTINGS_START 0x24
+#define ABIT_UGURU3_VALUES_START 0x80
+#define ABIT_UGURU3_BOARD_ID 0x0A
+/* uGuru3 sensor bank flags */ /* Alarm if: */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */
+#define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */
+#define ABIT_UGURU3_BEEP_ENABLE 0x08 /* beep if alarm */
+#define ABIT_UGURU3_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */
+/* sensor types */
+#define ABIT_UGURU3_IN_SENSOR 0
+#define ABIT_UGURU3_TEMP_SENSOR 1
+#define ABIT_UGURU3_FAN_SENSOR 2
+
+/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
+ convert them to params. Determined by trial and error. I assume this is
+ cpu-speed independent, since the ISA-bus and not the CPU should be the
+ bottleneck. */
+#define ABIT_UGURU3_WAIT_TIMEOUT 250
+/* Normally the 0xAC at the end of synchronize() is reported after the
+ first read, but sometimes not and we need to poll */
+#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5
+/* utility macros */
+#define ABIT_UGURU3_NAME "abituguru3"
+#define ABIT_UGURU3_DEBUG(format, arg...) \
+ if (verbose) \
+ printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
+
+/* Macros to help calculate the sysfs_names array length */
+#define ABIT_UGURU3_MAX_NO_SENSORS 26
+/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+ in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */
+#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
+/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
+ temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
+ temp??_label\0 */
+#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
+/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
+ fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */
+#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
+/* Worst case scenario 16 in sensors (longest names_length) and the rest
+ temp sensors (second longest names_length). */
+#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
+ (ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
+
+/* All the macros below are named identical to the openguru2 program
+ reverse engineered by Louis Kruger, hence the names might not be 100%
+ logical. I could come up with better names, but I prefer keeping the names
+ identical so that this driver can be compared with his work more easily. */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU3_BASE 0x00E0
+#define ABIT_UGURU3_CMD 0x00
+#define ABIT_UGURU3_DATA 0x04
+#define ABIT_UGURU3_REGION_LENGTH 5
+/* The wait_xxx functions return this on success and the last contents
+ of the DATA register (0-255) on failure. */
+#define ABIT_UGURU3_SUCCESS -1
+/* uGuru status flags */
+#define ABIT_UGURU3_STATUS_READY_FOR_READ 0x01
+#define ABIT_UGURU3_STATUS_BUSY 0x02
+
+
+/* Structures */
+struct abituguru3_sensor_info {
+ const char* name;
+ int port;
+ int type;
+ int multiplier;
+ int divisor;
+ int offset;
+};
+
+struct abituguru3_motherboard_info {
+ u16 id;
+ const char *name;
+ /* + 1 -> end of sensors indicated by a sensor with name == NULL */
+ struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
+};
+
+/* For the Abit uGuru, we need to keep some data in memory.
+ The structure is dynamically allocated, at the same time when a new
+ abituguru3 device is allocated. */
+struct abituguru3_data {
+ struct class_device *class_dev; /* hwmon registered device */
+ struct mutex update_lock; /* protect access to data and uGuru */
+ unsigned short addr; /* uguru base address */
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* For convenience the sysfs attr and their names are generated
+ automatically. We have max 10 entries per sensor (for in sensors) */
+ struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
+ * 10];
+
+ /* Buffer to store the dynamically generated sysfs names */
+ char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
+
+ /* Pointer to the sensors info for the detected motherboard */
+ const struct abituguru3_sensor_info *sensors;
+
+ /* The abituguru3 supports upto 48 sensors, and thus has registers
+ sets for 48 sensors, for convienence reasons / simplicity of the
+ code we always read and store all registers for all 48 sensors */
+
+ /* Alarms for all 48 sensors (1 bit per sensor) */
+ u8 alarms[48/8];
+
+ /* Value of all 48 sensors */
+ u8 value[48];
+
+ /* Settings of all 48 sensors, note in and temp sensors (the first 32
+ sensors) have 3 bytes of settings, while fans only have 2 bytes,
+ for convenience we use 3 bytes for all sensors */
+ u8 settings[48][3];
+};
+
+
+/* Constants */
+static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
+ { 0x000C, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS FAN", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x000D, "Abit AW8", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM1", 26, 1, 1, 1, 0 },
+ { "PWM2", 27, 1, 1, 1, 0 },
+ { "PWM3", 28, 1, 1, 1, 0 },
+ { "PWM4", 29, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
+ { "AUX4 Fan", 38, 2, 60, 1, 0 },
+ { "AUX5 Fan", 39, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x000E, "AL-8", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x000F, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0010, "Abit NI8 SLI GR", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "NB 1.4V", 4, 0, 10, 1, 0 },
+ { "SB 1.5V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "SYS", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "OTES1 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0011, "Abit AT8 32X", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 20, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
+ { "NB 1.8V", 4, 0, 10, 1, 0 },
+ { "NB 1.8V Dual", 5, 0, 10, 1, 0 },
+ { "HTV 1.2", 3, 0, 10, 1, 0 },
+ { "PCIE 1.2V", 12, 0, 10, 1, 0 },
+ { "NB 1.2V", 13, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "NB", 25, 1, 1, 1, 0 },
+ { "System", 26, 1, 1, 1, 0 },
+ { "PWM", 27, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0012, "Abit AN8 32X", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 20, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "HyperTransport", 3, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
+ { "NB", 4, 0, 10, 1, 0 },
+ { "SB", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "SYS", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0013, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM1", 26, 1, 1, 1, 0 },
+ { "PWM2", 27, 1, 1, 1, 0 },
+ { "PWM3", 28, 1, 1, 1, 0 },
+ { "PWM4", 29, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
+ { "AUX4 Fan", 38, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0014, "Abit AB9 Pro", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0015, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 20, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "HyperTransport", 3, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
+ { "NB", 4, 0, 10, 1, 0 },
+ { "SB", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "SYS", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0016, "AW9D-MAX", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM1", 26, 1, 1, 1, 0 },
+ { "PWM2", 27, 1, 1, 1, 0 },
+ { "PWM3", 28, 1, 1, 1, 0 },
+ { "PWM4", 29, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
+ { "OTES1 Fan", 38, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0017, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "HyperTransport", 3, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
+ { "NB 1.8V", 4, 0, 10, 1, 0 },
+ { "NB 1.2V ", 13, 0, 10, 1, 0 },
+ { "SB 1.2V", 5, 0, 10, 1, 0 },
+ { "PCIE 1.2V", 12, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "ATX +3.3V", 10, 0, 20, 1, 0 },
+ { "ATX 5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 26, 1, 1, 1, 0 },
+ { "PWM", 27, 1, 1, 1, 0 },
+ { "CPU FAN", 32, 2, 60, 1, 0 },
+ { "SYS FAN", 34, 2, 60, 1, 0 },
+ { "AUX1 FAN", 35, 2, 60, 1, 0 },
+ { "AUX2 FAN", 36, 2, 60, 1, 0 },
+ { "AUX3 FAN", 37, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0018, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT", 3, 0, 10, 1, 0 },
+ { "MCH 1.25V", 4, 0, 10, 1, 0 },
+ { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM Phase1", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0019, "unknown", {
+ { "CPU Core", 7, 0, 10, 1, 0 },
+ { "DDR2", 13, 0, 20, 1, 0 },
+ { "DDR2 VTT", 14, 0, 10, 1, 0 },
+ { "CPU VTT", 3, 0, 20, 1, 0 },
+ { "NB 1.2V ", 4, 0, 10, 1, 0 },
+ { "SB 1.5V", 6, 0, 10, 1, 0 },
+ { "HyperTransport", 5, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 12, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "ATX +3.3V", 10, 0, 20, 1, 0 },
+ { "ATX 5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM Phase1", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU FAN", 32, 2, 60, 1, 0 },
+ { "SYS FAN", 34, 2, 60, 1, 0 },
+ { "AUX1 FAN", 33, 2, 60, 1, 0 },
+ { "AUX2 FAN", 35, 2, 60, 1, 0 },
+ { "AUX3 FAN", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x001A, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH 1.25V", 4, 0, 10, 1, 0 },
+ { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM ", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
+};
+
+
+/* Insmod parameters */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+/* Default verbose is 1, since this driver is still in the testing phase */
+static int verbose = 1;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
+
+
+/* wait while the uguru is busy (usually after a write) */
+static int abituguru3_wait_while_busy(struct abituguru3_data *data)
+{
+ u8 x;
+ int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+ while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+ ABIT_UGURU3_STATUS_BUSY) {
+ timeout--;
+ if (timeout == 0)
+ return x;
+ /* sleep a bit before our last try, to give the uGuru3 one
+ last chance to respond. */
+ if (timeout == 1)
+ msleep(1);
+ }
+ return ABIT_UGURU3_SUCCESS;
+}
+
+/* wait till uguru is ready to be read */
+static int abituguru3_wait_for_read(struct abituguru3_data *data)
+{
+ u8 x;
+ int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+ while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+ ABIT_UGURU3_STATUS_READY_FOR_READ)) {
+ timeout--;
+ if (timeout == 0)
+ return x;
+ /* sleep a bit before our last try, to give the uGuru3 one
+ last chance to respond. */
+ if (timeout == 1)
+ msleep(1);
+ }
+ return ABIT_UGURU3_SUCCESS;
+}
+
+/* This synchronizes us with the uGuru3's protocol state machine, this
+ must be done before each command. */
+static int abituguru3_synchronize(struct abituguru3_data *data)
+{
+ int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
+
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
+ "wait, status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ outb(0x20, data->addr + ABIT_UGURU3_DATA);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ outb(0x10, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ outb(0x00, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
+ timeout--;
+ if (timeout == 0) {
+ ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
+ "hold 0xAC after synchronize, cmd: 0x%02x\n",
+ x);
+ return -EIO;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
+ result in buf */
+static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
+ u8 count, u8 *buf)
+{
+ int i, x;
+
+ if ((x = abituguru3_synchronize(data)))
+ return x;
+
+ outb(0x1A, data->addr + ABIT_UGURU3_DATA);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
+ (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ outb(bank, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending the bank, status: 0x%02x\n",
+ (unsigned int)bank, (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ outb(offset, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending the offset, status: 0x%02x\n",
+ (unsigned int)bank, (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ outb(count, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending the count, status: 0x%02x\n",
+ (unsigned int)bank, (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ for (i = 0; i < count; i++) {
+ if ((x = abituguru3_wait_for_read(data)) !=
+ ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("timeout reading byte %d from "
+ "0x%02x:0x%02x, status: 0x%02x\n", i,
+ (unsigned int)bank, (unsigned int)offset, x);
+ break;
+ }
+ buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
+ }
+ return i;
+}
+
+/* Sensor settings are stored 1 byte per offset with the bytes
+ placed add consecutive offsets. */
+static int abituguru3_read_increment_offset(struct abituguru3_data *data,
+ u8 bank, u8 offset, u8 count,
+ u8 *buf, int offset_count)
+{
+ int i, x;
+
+ for (i = 0; i < offset_count; i++)
+ if ((x = abituguru3_read(data, bank, offset + i, count,
+ buf + i * count)) != count)
+ return i * count + (i && (x < 0)) ? 0 : x;
+
+ return i * count;
+}
+
+/* Following are the sysfs callback functions. These functions expect:
+ sensor_device_attribute_2->index: index into the data->sensors array
+ sensor_device_attribute_2->nr: register offset, bitmask or NA. */
+static struct abituguru3_data *abituguru3_update_device(struct device *dev);
+
+static ssize_t show_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int value;
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = abituguru3_update_device(dev);
+ const struct abituguru3_sensor_info *sensor;
+
+ if (!data)
+ return -EIO;
+
+ sensor = &data->sensors[attr->index];
+
+ /* are we reading a setting, or is this a normal read? */
+ if (attr->nr)
+ value = data->settings[sensor->port][attr->nr];
+ else
+ value = data->value[sensor->port];
+
+ /* convert the value */
+ value = (value * sensor->multiplier) / sensor->divisor +
+ sensor->offset;
+
+ /* alternatively we could update the sensors settings struct for this,
+ but then its contents would differ from the windows sw ini files */
+ if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
+ value *= 1000;
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int port;
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = abituguru3_update_device(dev);
+
+ if (!data)
+ return -EIO;
+
+ port = data->sensors[attr->index].port;
+
+ /* See if the alarm bit for this sensor is set and if a bitmask is
+ given in attr->nr also check if the alarm matches the type of alarm
+ we're looking for (for volt it can be either low or high). The type
+ is stored in a few readonly bits in the settings of the sensor. */
+ if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
+ (!attr->nr || (data->settings[port][0] & attr->nr)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_mask(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = dev_get_drvdata(dev);
+
+ if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->sensors[attr->index].name);
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
+ SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
+ SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
+ SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
+ SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
+ ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
+ ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
+ ABIT_UGURU3_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
+ ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
+ }, {
+ SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
+ SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
+ SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
+ SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
+ SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
+ ABIT_UGURU3_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
+ ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
+ }, {
+ SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
+ SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
+ SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
+ SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
+ ABIT_UGURU3_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
+ ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
+} };
+
+static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
+ SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int __devinit abituguru3_probe(struct platform_device *pdev)
+{
+ const int no_sysfs_attr[3] = { 10, 8, 7 };
+ int sensor_index[3] = { 0, 1, 1 };
+ struct abituguru3_data *data;
+ int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+ char *sysfs_filename;
+ u8 buf[2];
+ u16 id;
+
+ if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+ mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
+
+ /* Read the motherboard ID */
+ if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK,
+ ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) {
+ goto abituguru3_probe_error;
+ }
+
+ /* Completely read the uGuru to see if one really is there */
+ if (!abituguru3_update_device(&pdev->dev))
+ goto abituguru3_probe_error;
+
+ /* lookup the ID in our motherboard table */
+ id = ((u16)buf[0] << 8) | (u16)buf[1];
+ for (i = 0; abituguru3_motherboards[i].id; i++)
+ if (abituguru3_motherboards[i].id == id)
+ break;
+ if (!abituguru3_motherboards[i].id) {
+ printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard "
+ "ID: %04X. Please report this to the abituguru3 "
+ "maintainer (see MAINTAINERS)\n", (unsigned int)id);
+ goto abituguru3_probe_error;
+ }
+ data->sensors = abituguru3_motherboards[i].sensors;
+ printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
+ "ID: %04X (%s)\n", (unsigned int)id,
+ abituguru3_motherboards[i].name);
+
+ /* Fill the sysfs attr array */
+ sysfs_attr_i = 0;
+ sysfs_filename = data->sysfs_names;
+ sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
+ for (i = 0; data->sensors[i].name; i++) {
+ /* Fail safe check, this should never happen! */
+ if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Fatal error motherboard has more sensors "
+ "then ABIT_UGURU3_MAX_NO_SENSORS. This should "
+ "never happen please report to the abituguru3 "
+ "maintainer (see MAINTAINERS)\n");
+ res = -ENAMETOOLONG;
+ goto abituguru3_probe_error;
+ }
+ type = data->sensors[i].type;
+ for (j = 0; j < no_sysfs_attr[type]; j++) {
+ used = snprintf(sysfs_filename, sysfs_names_free,
+ abituguru3_sysfs_templ[type][j].dev_attr.attr.
+ name, sensor_index[type]) + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru3_sysfs_templ[type][j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+ data->sysfs_attr[sysfs_attr_i].index = i;
+ sysfs_filename += used;
+ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ sensor_index[type]++;
+ }
+ /* Fail safe check, this should never happen! */
+ if (sysfs_names_free < 0) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Fatal error ran out of space for sysfs attr names. "
+ "This should never happen please report to the "
+ "abituguru3 maintainer (see MAINTAINERS)\n");
+ res = -ENAMETOOLONG;
+ goto abituguru3_probe_error;
+ }
+
+ /* Register sysfs hooks */
+ for (i = 0; i < sysfs_attr_i; i++)
+ if (device_create_file(&pdev->dev,
+ &data->sysfs_attr[i].dev_attr))
+ goto abituguru3_probe_error;
+ for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+ if (device_create_file(&pdev->dev,
+ &abituguru3_sysfs_attr[i].dev_attr))
+ goto abituguru3_probe_error;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ res = PTR_ERR(data->class_dev);
+ goto abituguru3_probe_error;
+ }
+
+ return 0; /* success */
+
+abituguru3_probe_error:
+ for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+ device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+ device_remove_file(&pdev->dev,
+ &abituguru3_sysfs_attr[i].dev_attr);
+ kfree(data);
+ return res;
+}
+
+static int __devexit abituguru3_remove(struct platform_device *pdev)
+{
+ int i;
+ struct abituguru3_data *data = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->class_dev);
+ for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+ device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+ device_remove_file(&pdev->dev,
+ &abituguru3_sysfs_attr[i].dev_attr);
+ kfree(data);
+
+ return 0;
+}
+
+static struct abituguru3_data *abituguru3_update_device(struct device *dev)
+{
+ int i;
+ struct abituguru3_data *data = dev_get_drvdata(dev);
+
+ mutex_lock(&data->update_lock);
+ if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+ /* Clear data->valid while updating */
+ data->valid = 0;
+ /* Read alarms */
+ if (abituguru3_read_increment_offset(data,
+ ABIT_UGURU3_SETTINGS_BANK,
+ ABIT_UGURU3_ALARMS_START,
+ 1, data->alarms, 48/8) != (48/8))
+ goto LEAVE_UPDATE;
+ /* Read in and temp sensors (3 byte settings / sensor) */
+ for (i = 0; i < 32; i++) {
+ if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+ ABIT_UGURU3_VALUES_START + i,
+ 1, &data->value[i]) != 1)
+ goto LEAVE_UPDATE;
+ if (abituguru3_read_increment_offset(data,
+ ABIT_UGURU3_SETTINGS_BANK,
+ ABIT_UGURU3_SETTINGS_START + i * 3,
+ 1,
+ data->settings[i], 3) != 3)
+ goto LEAVE_UPDATE;
+ }
+ /* Read temp sensors (2 byte settings / sensor) */
+ for (i = 0; i < 16; i++) {
+ if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+ ABIT_UGURU3_VALUES_START + 32 + i,
+ 1, &data->value[32 + i]) != 1)
+ goto LEAVE_UPDATE;
+ if (abituguru3_read_increment_offset(data,
+ ABIT_UGURU3_SETTINGS_BANK,
+ ABIT_UGURU3_SETTINGS_START + 32 * 3 +
+ i * 2, 1,
+ data->settings[32 + i], 2) != 2)
+ goto LEAVE_UPDATE;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+LEAVE_UPDATE:
+ mutex_unlock(&data->update_lock);
+ if (data->valid)
+ return data;
+ else
+ return NULL;
+}
+
+#ifdef CONFIG_PM
+static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct abituguru3_data *data = platform_get_drvdata(pdev);
+ /* make sure all communications with the uguru3 are done and no new
+ ones are started */
+ mutex_lock(&data->update_lock);
+ return 0;
+}
+
+static int abituguru3_resume(struct platform_device *pdev)
+{
+ struct abituguru3_data *data = platform_get_drvdata(pdev);
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+#else
+#define abituguru3_suspend NULL
+#define abituguru3_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver abituguru3_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = ABIT_UGURU3_NAME,
+ },
+ .probe = abituguru3_probe,
+ .remove = __devexit_p(abituguru3_remove),
+ .suspend = abituguru3_suspend,
+ .resume = abituguru3_resume
+};
+
+static int __init abituguru3_detect(void)
+{
+ /* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
+ 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
+ at CMD instead, why is unknown. So we test for 0x05 too. */
+ u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
+ u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
+ if (((data_val == 0x00) || (data_val == 0x08)) &&
+ ((cmd_val == 0xAC) || (cmd_val == 0x05)))
+ return ABIT_UGURU3_BASE;
+
+ ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
+ "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+ if (force) {
+ printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is "
+ "present because of \"force\" parameter\n");
+ return ABIT_UGURU3_BASE;
+ }
+
+ /* No uGuru3 found */
+ return -ENODEV;
+}
+
+static struct platform_device *abituguru3_pdev;
+
+static int __init abituguru3_init(void)
+{
+ int address, err;
+ struct resource res = { .flags = IORESOURCE_IO };
+
+ address = abituguru3_detect();
+ if (address < 0)
+ return address;
+
+ err = platform_driver_register(&abituguru3_driver);
+ if (err)
+ goto exit;
+
+ abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, address);
+ if (!abituguru3_pdev) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ res.start = address;
+ res.end = address + ABIT_UGURU3_REGION_LENGTH - 1;
+ res.name = ABIT_UGURU3_NAME;
+
+ err = platform_device_add_resources(abituguru3_pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Device resource addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(abituguru3_pdev);
+ if (err) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Device addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(abituguru3_pdev);
+exit_driver_unregister:
+ platform_driver_unregister(&abituguru3_driver);
+exit:
+ return err;
+}
+
+static void __exit abituguru3_exit(void)
+{
+ platform_device_unregister(abituguru3_pdev);
+ platform_driver_unregister(&abituguru3_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru3_init);
+module_exit(abituguru3_exit);
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index 6db973739725..a112a03e8f29 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -23,7 +23,6 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/module.h>
#include <asm/pmac_pfunc.h>
#include <asm/of_platform.h>
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index eb81a6430fe4..571f49e80277 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -79,11 +79,15 @@
/*
* Temperature sensors keys (sp78 - 2 bytes).
- * First set for Macbook(Pro), second for Macmini.
*/
static const char* temperature_sensors_sets[][13] = {
+/* Set 0: Macbook Pro */
{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
"Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
+/* Set 1: Macbook set */
+ { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
+ "Th1H", "Ts0P", NULL },
+/* Set 2: Macmini set */
{ "TC0D", "TC0P", NULL }
};
@@ -1048,7 +1052,7 @@ static const struct attribute_group temperature_attributes_group =
/*
* applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
*/
-static int applesmc_dmi_match(struct dmi_system_id *id)
+static int applesmc_dmi_match(const struct dmi_system_id *id)
{
int i = 0;
struct dmi_match_data* dmi_data = id->driver_data;
@@ -1129,10 +1133,10 @@ static void applesmc_release_accelerometer(void)
static __initdata struct dmi_match_data applesmc_dmi_data[] = {
/* MacBook Pro: accelerometer, backlight and temperature set 0 */
{ .accelerometer = 1, .light = 1, .temperature_set = 0 },
-/* MacBook: accelerometer and temperature set 0 */
- { .accelerometer = 1, .light = 0, .temperature_set = 0 },
-/* MacBook: temperature set 1 */
- { .accelerometer = 0, .light = 0, .temperature_set = 1 }
+/* MacBook: accelerometer and temperature set 1 */
+ { .accelerometer = 1, .light = 0, .temperature_set = 1 },
+/* MacMini: temperature set 2 */
+ { .accelerometer = 0, .light = 0, .temperature_set = 2 },
};
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 6d54c8caed79..7c1795225b06 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -318,7 +318,7 @@ exit:
}
#ifdef CONFIG_HOTPLUG_CPU
-void coretemp_device_remove(unsigned int cpu)
+static void coretemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p, *n;
mutex_lock(&pdev_list_mutex);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
new file mode 100644
index 000000000000..e9cbc727664d
--- /dev/null
+++ b/drivers/hwmon/dme1737.c
@@ -0,0 +1,2080 @@
+/*
+ * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
+ * integrated hardware monitoring features.
+ * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the LM85 driver. The hardware monitoring
+ * capabilities of the DME1737 are very similar to the LM85 with some
+ * additional features. Even though the DME1737 is a Super-I/O chip, the
+ * hardware monitoring registers are only accessible via SMBus.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+/* Module load parameters */
+static int force_start;
+module_param(force_start, bool, 0);
+MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(dme1737);
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows:
+ *
+ * Voltages Temperatures
+ * -------- ------------
+ * in0 +5VTR (+5V stdby) temp1 Remote diode 1
+ * in1 Vccp (proc core) temp2 Internal temp
+ * in2 VCC (internal +3.3V) temp3 Remote diode 2
+ * in3 +5V
+ * in4 +12V
+ * in5 VTR (+3.3V stby)
+ * in6 Vbat
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-6 (ix) */
+#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) \
+ : 0x94 + (ix))
+#define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \
+ : 0x91 + (ix) * 2)
+#define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \
+ : 0x92 + (ix) * 2)
+
+/* Temperatures (temp) numbered 0-2 (ix) */
+#define DME1737_REG_TEMP(ix) (0x25 + (ix))
+#define DME1737_REG_TEMP_MIN(ix) (0x4e + (ix) * 2)
+#define DME1737_REG_TEMP_MAX(ix) (0x4f + (ix) * 2)
+#define DME1737_REG_TEMP_OFFSET(ix) ((ix) == 0 ? 0x1f \
+ : 0x1c + (ix))
+
+/* Voltage and temperature LSBs
+ * The LSBs (4 bits each) are stored in 5 registers with the following layouts:
+ * IN_TEMP_LSB(0) = [in5, in6]
+ * IN_TEMP_LSB(1) = [temp3, temp1]
+ * IN_TEMP_LSB(2) = [in4, temp2]
+ * IN_TEMP_LSB(3) = [in3, in0]
+ * IN_TEMP_LSB(4) = [in2, in1] */
+#define DME1737_REG_IN_TEMP_LSB(ix) (0x84 + (ix))
+static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0};
+static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4};
+static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
+static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
+
+/* Fans numbered 0-5 (ix) */
+#define DME1737_REG_FAN(ix) ((ix) < 4 ? 0x28 + (ix) * 2 \
+ : 0xa1 + (ix) * 2)
+#define DME1737_REG_FAN_MIN(ix) ((ix) < 4 ? 0x54 + (ix) * 2 \
+ : 0xa5 + (ix) * 2)
+#define DME1737_REG_FAN_OPT(ix) ((ix) < 4 ? 0x90 + (ix) \
+ : 0xb2 + (ix))
+#define DME1737_REG_FAN_MAX(ix) (0xb4 + (ix)) /* only for fan[4-5] */
+
+/* PWMs numbered 0-2, 4-5 (ix) */
+#define DME1737_REG_PWM(ix) ((ix) < 3 ? 0x30 + (ix) \
+ : 0xa1 + (ix))
+#define DME1737_REG_PWM_CONFIG(ix) (0x5c + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_MIN(ix) (0x64 + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_FREQ(ix) ((ix) < 3 ? 0x5f + (ix) \
+ : 0xa3 + (ix))
+/* The layout of the ramp rate registers is different from the other pwm
+ * registers. The bits for the 3 PWMs are stored in 2 registers:
+ * PWM_RR(0) = [OFF3, OFF2, OFF1, RES, RR1E, RR1-2, RR1-1, RR1-0]
+ * PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] */
+#define DME1737_REG_PWM_RR(ix) (0x62 + (ix)) /* only for pwm[0-2] */
+
+/* Thermal zones 0-2 */
+#define DME1737_REG_ZONE_LOW(ix) (0x67 + (ix))
+#define DME1737_REG_ZONE_ABS(ix) (0x6a + (ix))
+/* The layout of the hysteresis registers is different from the other zone
+ * registers. The bits for the 3 zones are stored in 2 registers:
+ * ZONE_HYST(0) = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ * ZONE_HYST(1) = [H3-3, H3-2, H3-1, H3-0, RES, RES, RES, RES] */
+#define DME1737_REG_ZONE_HYST(ix) (0x6d + (ix))
+
+/* Alarm registers and bit mapping
+ * The 3 8-bit alarm registers will be concatenated to a single 32-bit
+ * alarm value [0, ALARM3, ALARM2, ALARM1]. */
+#define DME1737_REG_ALARM1 0x41
+#define DME1737_REG_ALARM2 0x42
+#define DME1737_REG_ALARM3 0x83
+static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17};
+static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
+static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
+
+/* Miscellaneous registers */
+#define DME1737_REG_COMPANY 0x3e
+#define DME1737_REG_VERSTEP 0x3f
+#define DME1737_REG_CONFIG 0x40
+#define DME1737_REG_CONFIG2 0x7f
+#define DME1737_REG_VID 0x43
+#define DME1737_REG_TACH_PWM 0x81
+
+/* ---------------------------------------------------------------------
+ * Misc defines
+ * --------------------------------------------------------------------- */
+
+/* Chip identification */
+#define DME1737_COMPANY_SMSC 0x5c
+#define DME1737_VERSTEP 0x88
+#define DME1737_VERSTEP_MASK 0xf8
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct dme1737_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ int valid; /* !=0 if following fields are valid */
+ unsigned long last_update; /* in jiffies */
+ unsigned long last_vbat; /* in jiffies */
+
+ u8 vid;
+ u8 pwm_rr_en;
+ u8 has_pwm;
+ u8 has_fan;
+
+ /* Register values */
+ u16 in[7];
+ u8 in_min[7];
+ u8 in_max[7];
+ s16 temp[3];
+ s8 temp_min[3];
+ s8 temp_max[3];
+ s8 temp_offset[3];
+ u8 config;
+ u8 config2;
+ u8 vrm;
+ u16 fan[6];
+ u16 fan_min[6];
+ u8 fan_max[2];
+ u8 fan_opt[6];
+ u8 pwm[6];
+ u8 pwm_min[3];
+ u8 pwm_config[3];
+ u8 pwm_acz[3];
+ u8 pwm_freq[6];
+ u8 pwm_rr[2];
+ u8 zone_low[3];
+ u8 zone_abs[3];
+ u8 zone_hyst[2];
+ u32 alarms;
+};
+
+/* Nominal voltage values */
+static const int IN_NOMINAL[] = {5000, 2250, 3300, 5000, 12000, 3300, 3300};
+
+/* Voltage input
+ * Voltage inputs have 16 bits resolution, limit values have 8 bits
+ * resolution. */
+static inline int IN_FROM_REG(int reg, int ix, int res)
+{
+ return (reg * IN_NOMINAL[ix] + (3 << (res - 3))) / (3 << (res - 2));
+}
+
+static inline int IN_TO_REG(int val, int ix)
+{
+ return SENSORS_LIMIT((val * 192 + IN_NOMINAL[ix] / 2) /
+ IN_NOMINAL[ix], 0, 255);
+}
+
+/* Temperature input
+ * The register values represent temperatures in 2's complement notation from
+ * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit
+ * values have 8 bits resolution. */
+static inline int TEMP_FROM_REG(int reg, int res)
+{
+ return (reg * 1000) >> (res - 8);
+}
+
+static inline int TEMP_TO_REG(int val)
+{
+ return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
+ -128, 127);
+}
+
+/* Temperature range */
+static const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,
+ 10000, 13333, 16000, 20000, 26666, 32000,
+ 40000, 53333, 80000};
+
+static inline int TEMP_RANGE_FROM_REG(int reg)
+{
+ return TEMP_RANGE[(reg >> 4) & 0x0f];
+}
+
+static int TEMP_RANGE_TO_REG(int val, int reg)
+{
+ int i;
+
+ for (i = 15; i > 0; i--) {
+ if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) {
+ break;
+ }
+ }
+
+ return (reg & 0x0f) | (i << 4);
+}
+
+/* Temperature hysteresis
+ * Register layout:
+ * reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ * reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] */
+static inline int TEMP_HYST_FROM_REG(int reg, int ix)
+{
+ return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
+}
+
+static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
+{
+ int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+
+ return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
+}
+
+/* Fan input RPM */
+static inline int FAN_FROM_REG(int reg, int tpc)
+{
+ return (reg == 0 || reg == 0xffff) ? 0 :
+ (tpc == 0) ? 90000 * 60 / reg : tpc * reg;
+}
+
+static inline int FAN_TO_REG(int val, int tpc)
+{
+ return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc,
+ 0, 0xffff);
+}
+
+/* Fan TPC (tach pulse count)
+ * Converts a register value to a TPC multiplier or returns 0 if the tachometer
+ * is configured in legacy (non-tpc) mode */
+static inline int FAN_TPC_FROM_REG(int reg)
+{
+ return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);
+}
+
+/* Fan type
+ * The type of a fan is expressed in number of pulses-per-revolution that it
+ * emits */
+static inline int FAN_TYPE_FROM_REG(int reg)
+{
+ int edge = (reg >> 1) & 0x03;
+
+ return (edge > 0) ? 1 << (edge - 1) : 0;
+}
+
+static inline int FAN_TYPE_TO_REG(int val, int reg)
+{
+ int edge = (val == 4) ? 3 : val;
+
+ return (reg & 0xf9) | (edge << 1);
+}
+
+/* Fan max RPM */
+static const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,
+ 0x11, 0x0f, 0x0e};
+
+static int FAN_MAX_FROM_REG(int reg)
+{
+ int i;
+
+ for (i = 10; i > 0; i--) {
+ if (reg == FAN_MAX[i]) {
+ break;
+ }
+ }
+
+ return 1000 + i * 500;
+}
+
+static int FAN_MAX_TO_REG(int val)
+{
+ int i;
+
+ for (i = 10; i > 0; i--) {
+ if (val > (1000 + (i - 1) * 500)) {
+ break;
+ }
+ }
+
+ return FAN_MAX[i];
+}
+
+/* PWM enable
+ * Register to enable mapping:
+ * 000: 2 fan on zone 1 auto
+ * 001: 2 fan on zone 2 auto
+ * 010: 2 fan on zone 3 auto
+ * 011: 0 fan full on
+ * 100: -1 fan disabled
+ * 101: 2 fan on hottest of zones 2,3 auto
+ * 110: 2 fan on hottest of zones 1,2,3 auto
+ * 111: 1 fan in manual mode */
+static inline int PWM_EN_FROM_REG(int reg)
+{
+ static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};
+
+ return en[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_EN_TO_REG(int val, int reg)
+{
+ int en = (val == 1) ? 7 : 3;
+
+ return (reg & 0x1f) | ((en & 0x07) << 5);
+}
+
+/* PWM auto channels zone
+ * Register to auto channels zone mapping (ACZ is a bitfield with bit x
+ * corresponding to zone x+1):
+ * 000: 001 fan on zone 1 auto
+ * 001: 010 fan on zone 2 auto
+ * 010: 100 fan on zone 3 auto
+ * 011: 000 fan full on
+ * 100: 000 fan disabled
+ * 101: 110 fan on hottest of zones 2,3 auto
+ * 110: 111 fan on hottest of zones 1,2,3 auto
+ * 111: 000 fan in manual mode */
+static inline int PWM_ACZ_FROM_REG(int reg)
+{
+ static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};
+
+ return acz[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_ACZ_TO_REG(int val, int reg)
+{
+ int acz = (val == 4) ? 2 : val - 1;
+
+ return (reg & 0x1f) | ((acz & 0x07) << 5);
+}
+
+/* PWM frequency */
+static const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,
+ 15000, 20000, 30000, 25000, 0, 0, 0, 0};
+
+static inline int PWM_FREQ_FROM_REG(int reg)
+{
+ return PWM_FREQ[reg & 0x0f];
+}
+
+static int PWM_FREQ_TO_REG(int val, int reg)
+{
+ int i;
+
+ /* the first two cases are special - stupid chip design! */
+ if (val > 27500) {
+ i = 10;
+ } else if (val > 22500) {
+ i = 11;
+ } else {
+ for (i = 9; i > 0; i--) {
+ if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) {
+ break;
+ }
+ }
+ }
+
+ return (reg & 0xf0) | i;
+}
+
+/* PWM ramp rate
+ * Register layout:
+ * reg[0] = [OFF3, OFF2, OFF1, RES, RR1-E, RR1-2, RR1-1, RR1-0]
+ * reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] */
+static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};
+
+static inline int PWM_RR_FROM_REG(int reg, int ix)
+{
+ int rr = (ix == 1) ? reg >> 4 : reg;
+
+ return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;
+}
+
+static int PWM_RR_TO_REG(int val, int ix, int reg)
+{
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) {
+ break;
+ }
+ }
+
+ return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;
+}
+
+/* PWM ramp rate enable */
+static inline int PWM_RR_EN_FROM_REG(int reg, int ix)
+{
+ return PWM_RR_FROM_REG(reg, ix) ? 1 : 0;
+}
+
+static inline int PWM_RR_EN_TO_REG(int val, int ix, int reg)
+{
+ int en = (ix == 1) ? 0x80 : 0x08;
+
+ return val ? reg | en : reg & ~en;
+}
+
+/* PWM min/off
+ * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for
+ * the register layout). */
+static inline int PWM_OFF_FROM_REG(int reg, int ix)
+{
+ return (reg >> (ix + 5)) & 0x01;
+}
+
+static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
+{
+ return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5));
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static u8 dme1737_read(struct i2c_client *client, u8 reg)
+{
+ s32 val = i2c_smbus_read_byte_data(client, reg);
+
+ if (val < 0) {
+ dev_warn(&client->dev, "Read from register 0x%02x failed! "
+ "Please report to the driver maintainer.\n", reg);
+ }
+
+ return val;
+}
+
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ s32 res = i2c_smbus_write_byte_data(client, reg, value);
+
+ if (res < 0) {
+ dev_warn(&client->dev, "Write to register 0x%02x failed! "
+ "Please report to the driver maintainer.\n", reg);
+ }
+
+ return res;
+}
+
+static struct dme1737_data *dme1737_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int ix;
+ u8 lsb[5];
+
+ mutex_lock(&data->update_lock);
+
+ /* Enable a Vbat monitoring cycle every 10 mins */
+ if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
+ dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+ DME1737_REG_CONFIG) | 0x10);
+ data->last_vbat = jiffies;
+ }
+
+ /* Sample register contents every 1 sec */
+ if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
+ data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
+
+ /* In (voltage) registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ /* Voltage inputs are stored as 16 bit values even
+ * though they have only 12 bits resolution. This is
+ * to make it consistent with the temp inputs. */
+ data->in[ix] = dme1737_read(client,
+ DME1737_REG_IN(ix)) << 8;
+ data->in_min[ix] = dme1737_read(client,
+ DME1737_REG_IN_MIN(ix));
+ data->in_max[ix] = dme1737_read(client,
+ DME1737_REG_IN_MAX(ix));
+ }
+
+ /* Temp registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+ /* Temp inputs are stored as 16 bit values even
+ * though they have only 12 bits resolution. This is
+ * to take advantage of implicit conversions between
+ * register values (2's complement) and temp values
+ * (signed decimal). */
+ data->temp[ix] = dme1737_read(client,
+ DME1737_REG_TEMP(ix)) << 8;
+ data->temp_min[ix] = dme1737_read(client,
+ DME1737_REG_TEMP_MIN(ix));
+ data->temp_max[ix] = dme1737_read(client,
+ DME1737_REG_TEMP_MAX(ix));
+ data->temp_offset[ix] = dme1737_read(client,
+ DME1737_REG_TEMP_OFFSET(ix));
+ }
+
+ /* In and temp LSB registers
+ * The LSBs are latched when the MSBs are read, so the order in
+ * which the registers are read (MSB first, then LSB) is
+ * important! */
+ for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
+ lsb[ix] = dme1737_read(client,
+ DME1737_REG_IN_TEMP_LSB(ix));
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
+ DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+ data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] <<
+ DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0;
+ }
+
+ /* Fan registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+ /* Skip reading registers if optional fans are not
+ * present */
+ if (!(data->has_fan & (1 << ix))) {
+ continue;
+ }
+ data->fan[ix] = dme1737_read(client,
+ DME1737_REG_FAN(ix));
+ data->fan[ix] |= dme1737_read(client,
+ DME1737_REG_FAN(ix) + 1) << 8;
+ data->fan_min[ix] = dme1737_read(client,
+ DME1737_REG_FAN_MIN(ix));
+ data->fan_min[ix] |= dme1737_read(client,
+ DME1737_REG_FAN_MIN(ix) + 1) << 8;
+ data->fan_opt[ix] = dme1737_read(client,
+ DME1737_REG_FAN_OPT(ix));
+ /* fan_max exists only for fan[5-6] */
+ if (ix > 3) {
+ data->fan_max[ix - 4] = dme1737_read(client,
+ DME1737_REG_FAN_MAX(ix));
+ }
+ }
+
+ /* PWM registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
+ /* Skip reading registers if optional PWMs are not
+ * present */
+ if (!(data->has_pwm & (1 << ix))) {
+ continue;
+ }
+ data->pwm[ix] = dme1737_read(client,
+ DME1737_REG_PWM(ix));
+ data->pwm_freq[ix] = dme1737_read(client,
+ DME1737_REG_PWM_FREQ(ix));
+ /* pwm_config and pwm_min exist only for pwm[1-3] */
+ if (ix < 3) {
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ data->pwm_min[ix] = dme1737_read(client,
+ DME1737_REG_PWM_MIN(ix));
+ }
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
+ data->pwm_rr[ix] = dme1737_read(client,
+ DME1737_REG_PWM_RR(ix));
+ }
+
+ /* Thermal zone registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
+ data->zone_low[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_LOW(ix));
+ data->zone_abs[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_ABS(ix));
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
+ data->zone_hyst[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_HYST(ix));
+ }
+
+ /* Alarm registers */
+ data->alarms = dme1737_read(client,
+ DME1737_REG_ALARM1);
+ /* Bit 7 tells us if the other alarm registers are non-zero and
+ * therefore also need to be read */
+ if (data->alarms & 0x80) {
+ data->alarms |= dme1737_read(client,
+ DME1737_REG_ALARM2) << 8;
+ data->alarms |= dme1737_read(client,
+ DME1737_REG_ALARM3) << 16;
+ }
+
+ data->last_update = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_IN_INPUT 0
+#define SYS_IN_MIN 1
+#define SYS_IN_MAX 2
+#define SYS_IN_ALARM 3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_IN_INPUT:
+ res = IN_FROM_REG(data->in[ix], ix, 16);
+ break;
+ case SYS_IN_MIN:
+ res = IN_FROM_REG(data->in_min[ix], ix, 8);
+ break;
+ case SYS_IN_MAX:
+ res = IN_FROM_REG(data->in_max[ix], ix, 8);
+ break;
+ case SYS_IN_ALARM:
+ res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_IN_MIN:
+ data->in_min[ix] = IN_TO_REG(val, ix);
+ dme1737_write(client, DME1737_REG_IN_MIN(ix),
+ data->in_min[ix]);
+ break;
+ case SYS_IN_MAX:
+ data->in_max[ix] = IN_TO_REG(val, ix);
+ dme1737_write(client, DME1737_REG_IN_MAX(ix),
+ data->in_max[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_TEMP_INPUT 0
+#define SYS_TEMP_MIN 1
+#define SYS_TEMP_MAX 2
+#define SYS_TEMP_OFFSET 3
+#define SYS_TEMP_ALARM 4
+#define SYS_TEMP_FAULT 5
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_TEMP_INPUT:
+ res = TEMP_FROM_REG(data->temp[ix], 16);
+ break;
+ case SYS_TEMP_MIN:
+ res = TEMP_FROM_REG(data->temp_min[ix], 8);
+ break;
+ case SYS_TEMP_MAX:
+ res = TEMP_FROM_REG(data->temp_max[ix], 8);
+ break;
+ case SYS_TEMP_OFFSET:
+ res = TEMP_FROM_REG(data->temp_offset[ix], 8);
+ break;
+ case SYS_TEMP_ALARM:
+ res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01;
+ break;
+ case SYS_TEMP_FAULT:
+ res = (((u16)data->temp[ix] & 0xff00) == 0x8000);
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_TEMP_MIN:
+ data->temp_min[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+ data->temp_min[ix]);
+ break;
+ case SYS_TEMP_MAX:
+ data->temp_max[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+ data->temp_max[ix]);
+ break;
+ case SYS_TEMP_OFFSET:
+ data->temp_offset[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+ data->temp_offset[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Zone sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_ZONE_AUTO_CHANNELS_TEMP 0
+#define SYS_ZONE_AUTO_POINT1_TEMP_HYST 1
+#define SYS_ZONE_AUTO_POINT1_TEMP 2
+#define SYS_ZONE_AUTO_POINT2_TEMP 3
+#define SYS_ZONE_AUTO_POINT3_TEMP 4
+
+static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_ZONE_AUTO_CHANNELS_TEMP:
+ /* check config2 for non-standard temp-to-zone mapping */
+ if ((ix == 1) && (data->config2 & 0x02)) {
+ res = 4;
+ } else {
+ res = 1 << ix;
+ }
+ break;
+ case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+ res = TEMP_FROM_REG(data->zone_low[ix], 8) -
+ TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix);
+ break;
+ case SYS_ZONE_AUTO_POINT1_TEMP:
+ res = TEMP_FROM_REG(data->zone_low[ix], 8);
+ break;
+ case SYS_ZONE_AUTO_POINT2_TEMP:
+ /* pwm_freq holds the temp range bits in the upper nibble */
+ res = TEMP_FROM_REG(data->zone_low[ix], 8) +
+ TEMP_RANGE_FROM_REG(data->pwm_freq[ix]);
+ break;
+ case SYS_ZONE_AUTO_POINT3_TEMP:
+ res = TEMP_FROM_REG(data->zone_abs[ix], 8);
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+ /* Refresh the cache */
+ data->zone_low[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_LOW(ix));
+ /* Modify the temp hyst value */
+ data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
+ TEMP_FROM_REG(data->zone_low[ix], 8) -
+ val, ix, dme1737_read(client,
+ DME1737_REG_ZONE_HYST(ix == 2)));
+ dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+ data->zone_hyst[ix == 2]);
+ break;
+ case SYS_ZONE_AUTO_POINT1_TEMP:
+ data->zone_low[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+ data->zone_low[ix]);
+ break;
+ case SYS_ZONE_AUTO_POINT2_TEMP:
+ /* Refresh the cache */
+ data->zone_low[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_LOW(ix));
+ /* Modify the temp range value (which is stored in the upper
+ * nibble of the pwm_freq register) */
+ data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
+ TEMP_FROM_REG(data->zone_low[ix], 8),
+ dme1737_read(client,
+ DME1737_REG_PWM_FREQ(ix)));
+ dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+ data->pwm_freq[ix]);
+ break;
+ case SYS_ZONE_AUTO_POINT3_TEMP:
+ data->zone_abs[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+ data->zone_abs[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_FAN_INPUT 0
+#define SYS_FAN_MIN 1
+#define SYS_FAN_MAX 2
+#define SYS_FAN_ALARM 3
+#define SYS_FAN_TYPE 4
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_FAN_INPUT:
+ res = FAN_FROM_REG(data->fan[ix],
+ ix < 4 ? 0 :
+ FAN_TPC_FROM_REG(data->fan_opt[ix]));
+ break;
+ case SYS_FAN_MIN:
+ res = FAN_FROM_REG(data->fan_min[ix],
+ ix < 4 ? 0 :
+ FAN_TPC_FROM_REG(data->fan_opt[ix]));
+ break;
+ case SYS_FAN_MAX:
+ /* only valid for fan[5-6] */
+ res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]);
+ break;
+ case SYS_FAN_ALARM:
+ res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01;
+ break;
+ case SYS_FAN_TYPE:
+ /* only valid for fan[1-4] */
+ res = FAN_TYPE_FROM_REG(data->fan_opt[ix]);
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_FAN_MIN:
+ if (ix < 4) {
+ data->fan_min[ix] = FAN_TO_REG(val, 0);
+ } else {
+ /* Refresh the cache */
+ data->fan_opt[ix] = dme1737_read(client,
+ DME1737_REG_FAN_OPT(ix));
+ /* Modify the fan min value */
+ data->fan_min[ix] = FAN_TO_REG(val,
+ FAN_TPC_FROM_REG(data->fan_opt[ix]));
+ }
+ dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+ data->fan_min[ix] & 0xff);
+ dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+ data->fan_min[ix] >> 8);
+ break;
+ case SYS_FAN_MAX:
+ /* Only valid for fan[5-6] */
+ data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
+ dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+ data->fan_max[ix - 4]);
+ break;
+ case SYS_FAN_TYPE:
+ /* Only valid for fan[1-4] */
+ if (!(val == 1 || val == 2 || val == 4)) {
+ count = -EINVAL;
+ dev_warn(&client->dev, "Fan type value %ld not "
+ "supported. Choose one of 1, 2, or 4.\n",
+ val);
+ goto exit;
+ }
+ data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+ DME1737_REG_FAN_OPT(ix)));
+ dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+ data->fan_opt[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs attributes
+ * ix = [0-4]
+ * --------------------------------------------------------------------- */
+
+#define SYS_PWM 0
+#define SYS_PWM_FREQ 1
+#define SYS_PWM_ENABLE 2
+#define SYS_PWM_RAMP_RATE 3
+#define SYS_PWM_AUTO_CHANNELS_ZONE 4
+#define SYS_PWM_AUTO_PWM_MIN 5
+#define SYS_PWM_AUTO_POINT1_PWM 6
+#define SYS_PWM_AUTO_POINT2_PWM 7
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_PWM:
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) {
+ res = 255;
+ } else {
+ res = data->pwm[ix];
+ }
+ break;
+ case SYS_PWM_FREQ:
+ res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]);
+ break;
+ case SYS_PWM_ENABLE:
+ if (ix > 3) {
+ res = 1; /* pwm[5-6] hard-wired to manual mode */
+ } else {
+ res = PWM_EN_FROM_REG(data->pwm_config[ix]);
+ }
+ break;
+ case SYS_PWM_RAMP_RATE:
+ /* Only valid for pwm[1-3] */
+ res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix);
+ break;
+ case SYS_PWM_AUTO_CHANNELS_ZONE:
+ /* Only valid for pwm[1-3] */
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ res = PWM_ACZ_FROM_REG(data->pwm_config[ix]);
+ } else {
+ res = data->pwm_acz[ix];
+ }
+ break;
+ case SYS_PWM_AUTO_PWM_MIN:
+ /* Only valid for pwm[1-3] */
+ if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) {
+ res = data->pwm_min[ix];
+ } else {
+ res = 0;
+ }
+ break;
+ case SYS_PWM_AUTO_POINT1_PWM:
+ /* Only valid for pwm[1-3] */
+ res = data->pwm_min[ix];
+ break;
+ case SYS_PWM_AUTO_POINT2_PWM:
+ /* Only valid for pwm[1-3] */
+ res = 255; /* hard-wired */
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static struct attribute *dme1737_attr_pwm[];
+static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_PWM:
+ data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+ dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+ break;
+ case SYS_PWM_FREQ:
+ data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+ DME1737_REG_PWM_FREQ(ix)));
+ dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+ data->pwm_freq[ix]);
+ break;
+ case SYS_PWM_ENABLE:
+ /* Only valid for pwm[1-3] */
+ if (val < 0 || val > 2) {
+ count = -EINVAL;
+ dev_warn(&client->dev, "PWM enable %ld not "
+ "supported. Choose one of 0, 1, or 2.\n",
+ val);
+ goto exit;
+ }
+ /* Refresh the cache */
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
+ /* Bail out if no change */
+ goto exit;
+ }
+ /* Do some housekeeping if we are currently in auto mode */
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ /* Save the current zone channel assignment */
+ data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
+ data->pwm_config[ix]);
+ /* Save the current ramp rate state and disable it */
+ data->pwm_rr[ix > 0] = dme1737_read(client,
+ DME1737_REG_PWM_RR(ix > 0));
+ data->pwm_rr_en &= ~(1 << ix);
+ if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
+ data->pwm_rr_en |= (1 << ix);
+ data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
+ data->pwm_rr[ix > 0]);
+ dme1737_write(client,
+ DME1737_REG_PWM_RR(ix > 0),
+ data->pwm_rr[ix > 0]);
+ }
+ }
+ /* Set the new PWM mode */
+ switch (val) {
+ case 0:
+ /* Change permissions of pwm[ix] to read-only */
+ dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ S_IRUGO);
+ /* Turn fan fully on */
+ data->pwm_config[ix] = PWM_EN_TO_REG(0,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ break;
+ case 1:
+ /* Turn on manual mode */
+ data->pwm_config[ix] = PWM_EN_TO_REG(1,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ /* Change permissions of pwm[ix] to read-writeable */
+ dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ S_IRUGO | S_IWUSR);
+ break;
+ case 2:
+ /* Change permissions of pwm[ix] to read-only */
+ dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ S_IRUGO);
+ /* Turn on auto mode using the saved zone channel
+ * assignment */
+ data->pwm_config[ix] = PWM_ACZ_TO_REG(
+ data->pwm_acz[ix],
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ /* Enable PWM ramp rate if previously enabled */
+ if (data->pwm_rr_en & (1 << ix)) {
+ data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
+ dme1737_read(client,
+ DME1737_REG_PWM_RR(ix > 0)));
+ dme1737_write(client,
+ DME1737_REG_PWM_RR(ix > 0),
+ data->pwm_rr[ix > 0]);
+ }
+ break;
+ }
+ break;
+ case SYS_PWM_RAMP_RATE:
+ /* Only valid for pwm[1-3] */
+ /* Refresh the cache */
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ data->pwm_rr[ix > 0] = dme1737_read(client,
+ DME1737_REG_PWM_RR(ix > 0));
+ /* Set the ramp rate value */
+ if (val > 0) {
+ data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix,
+ data->pwm_rr[ix > 0]);
+ }
+ /* Enable/disable the feature only if the associated PWM
+ * output is in automatic mode. */
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
+ data->pwm_rr[ix > 0]);
+ }
+ dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+ data->pwm_rr[ix > 0]);
+ break;
+ case SYS_PWM_AUTO_CHANNELS_ZONE:
+ /* Only valid for pwm[1-3] */
+ if (!(val == 1 || val == 2 || val == 4 ||
+ val == 6 || val == 7)) {
+ count = -EINVAL;
+ dev_warn(&client->dev, "PWM auto channels zone %ld "
+ "not supported. Choose one of 1, 2, 4, 6, "
+ "or 7.\n", val);
+ goto exit;
+ }
+ /* Refresh the cache */
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ /* PWM is already in auto mode so update the temp
+ * channel assignment */
+ data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ } else {
+ /* PWM is not in auto mode so we save the temp
+ * channel assignment for later use */
+ data->pwm_acz[ix] = val;
+ }
+ break;
+ case SYS_PWM_AUTO_PWM_MIN:
+ /* Only valid for pwm[1-3] */
+ /* Refresh the cache */
+ data->pwm_min[ix] = dme1737_read(client,
+ DME1737_REG_PWM_MIN(ix));
+ /* There are only 2 values supported for the auto_pwm_min
+ * value: 0 or auto_point1_pwm. So if the temperature drops
+ * below the auto_point1_temp_hyst value, the fan either turns
+ * off or runs at auto_point1_pwm duty-cycle. */
+ if (val > ((data->pwm_min[ix] + 1) / 2)) {
+ data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
+ dme1737_read(client,
+ DME1737_REG_PWM_RR(0)));
+
+ } else {
+ data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
+ dme1737_read(client,
+ DME1737_REG_PWM_RR(0)));
+
+ }
+ dme1737_write(client, DME1737_REG_PWM_RR(0),
+ data->pwm_rr[0]);
+ break;
+ case SYS_PWM_AUTO_POINT1_PWM:
+ /* Only valid for pwm[1-3] */
+ data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+ dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+ data->pwm_min[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs attributes
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ data->vrm = val;
+ return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+/* ---------------------------------------------------------------------
+ * Sysfs device attribute defines and structs
+ * --------------------------------------------------------------------- */
+
+/* Voltages 0-6 */
+
+#define SENSOR_DEVICE_ATTR_IN(ix) \
+static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
+ show_in, NULL, SYS_IN_INPUT, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SYS_IN_MIN, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SYS_IN_MAX, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
+ show_in, NULL, SYS_IN_ALARM, ix)
+
+SENSOR_DEVICE_ATTR_IN(0);
+SENSOR_DEVICE_ATTR_IN(1);
+SENSOR_DEVICE_ATTR_IN(2);
+SENSOR_DEVICE_ATTR_IN(3);
+SENSOR_DEVICE_ATTR_IN(4);
+SENSOR_DEVICE_ATTR_IN(5);
+SENSOR_DEVICE_ATTR_IN(6);
+
+/* Temperatures 1-3 */
+
+#define SENSOR_DEVICE_ATTR_TEMP(ix) \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
+ show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
+ show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+ show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
+ show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+
+SENSOR_DEVICE_ATTR_TEMP(1);
+SENSOR_DEVICE_ATTR_TEMP(2);
+SENSOR_DEVICE_ATTR_TEMP(3);
+
+/* Zones 1-3 */
+
+#define SENSOR_DEVICE_ATTR_ZONE(ix) \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
+ show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+
+SENSOR_DEVICE_ATTR_ZONE(1);
+SENSOR_DEVICE_ATTR_ZONE(2);
+SENSOR_DEVICE_ATTR_ZONE(3);
+
+/* Fans 1-4 */
+
+#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_1TO4(1);
+SENSOR_DEVICE_ATTR_FAN_1TO4(2);
+SENSOR_DEVICE_ATTR_FAN_1TO4(3);
+SENSOR_DEVICE_ATTR_FAN_1TO4(4);
+
+/* Fans 5-6 */
+
+#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_MAX, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_5TO6(5);
+SENSOR_DEVICE_ATTR_FAN_5TO6(6);
+
+/* PWMs 1-3 */
+
+#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
+ show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_1TO3(1);
+SENSOR_DEVICE_ATTR_PWM_1TO3(2);
+SENSOR_DEVICE_ATTR_PWM_1TO3(3);
+
+/* PWMs 5-6 */
+
+#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+ show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_5TO6(5);
+SENSOR_DEVICE_ATTR_PWM_5TO6(6);
+
+/* Misc */
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+#define SENSOR_DEV_ATTR_IN(ix) \
+&sensor_dev_attr_in##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_alarm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_TEMP_LOCK(ix) \
+&sensor_dev_attr_temp##ix##_offset.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_TEMP(ix) \
+SENSOR_DEV_ATTR_TEMP_LOCK(ix), \
+&sensor_dev_attr_temp##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_fault.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_ZONE_LOCK(ix) \
+&sensor_dev_attr_zone##ix##_auto_point1_temp_hyst.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point1_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point2_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point3_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_ZONE(ix) \
+SENSOR_DEV_ATTR_ZONE_LOCK(ix), \
+&sensor_dev_attr_zone##ix##_auto_channels_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_1TO4(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_type.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_5TO6(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_max.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix) \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_ramp_rate.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_channels_zone.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_pwm_min.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point1_pwm.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_1TO3(ix) \
+SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix), \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point2_pwm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix) \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_5TO6(ix) \
+SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr
+
+/* This struct holds all the attributes that are always present and need to be
+ * created unconditionally. The attributes that need modification of their
+ * permissions are created read-only and write permissions are added or removed
+ * on the fly when required */
+static struct attribute *dme1737_attr[] ={
+ /* Voltages */
+ SENSOR_DEV_ATTR_IN(0),
+ SENSOR_DEV_ATTR_IN(1),
+ SENSOR_DEV_ATTR_IN(2),
+ SENSOR_DEV_ATTR_IN(3),
+ SENSOR_DEV_ATTR_IN(4),
+ SENSOR_DEV_ATTR_IN(5),
+ SENSOR_DEV_ATTR_IN(6),
+ /* Temperatures */
+ SENSOR_DEV_ATTR_TEMP(1),
+ SENSOR_DEV_ATTR_TEMP(2),
+ SENSOR_DEV_ATTR_TEMP(3),
+ /* Zones */
+ SENSOR_DEV_ATTR_ZONE(1),
+ SENSOR_DEV_ATTR_ZONE(2),
+ SENSOR_DEV_ATTR_ZONE(3),
+ /* Misc */
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group dme1737_group = {
+ .attrs = dme1737_attr,
+};
+
+/* The following structs hold the PWM attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_pwm1[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3(1),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm2[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3(2),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm3[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3(3),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm5[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6(5),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm6[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6(6),
+ NULL
+};
+
+static const struct attribute_group dme1737_pwm_group[] = {
+ { .attrs = dme1737_attr_pwm1 },
+ { .attrs = dme1737_attr_pwm2 },
+ { .attrs = dme1737_attr_pwm3 },
+ { .attrs = NULL },
+ { .attrs = dme1737_attr_pwm5 },
+ { .attrs = dme1737_attr_pwm6 },
+};
+
+/* The following structs hold the fan attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_fan1[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(1),
+ NULL
+};
+static struct attribute *dme1737_attr_fan2[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(2),
+ NULL
+};
+static struct attribute *dme1737_attr_fan3[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(3),
+ NULL
+};
+static struct attribute *dme1737_attr_fan4[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(4),
+ NULL
+};
+static struct attribute *dme1737_attr_fan5[] = {
+ SENSOR_DEV_ATTR_FAN_5TO6(5),
+ NULL
+};
+static struct attribute *dme1737_attr_fan6[] = {
+ SENSOR_DEV_ATTR_FAN_5TO6(6),
+ NULL
+};
+
+static const struct attribute_group dme1737_fan_group[] = {
+ { .attrs = dme1737_attr_fan1 },
+ { .attrs = dme1737_attr_fan2 },
+ { .attrs = dme1737_attr_fan3 },
+ { .attrs = dme1737_attr_fan4 },
+ { .attrs = dme1737_attr_fan5 },
+ { .attrs = dme1737_attr_fan6 },
+};
+
+/* The permissions of all of the following attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_lock[] = {
+ /* Temperatures */
+ SENSOR_DEV_ATTR_TEMP_LOCK(1),
+ SENSOR_DEV_ATTR_TEMP_LOCK(2),
+ SENSOR_DEV_ATTR_TEMP_LOCK(3),
+ /* Zones */
+ SENSOR_DEV_ATTR_ZONE_LOCK(1),
+ SENSOR_DEV_ATTR_ZONE_LOCK(2),
+ SENSOR_DEV_ATTR_ZONE_LOCK(3),
+ NULL
+};
+
+static const struct attribute_group dme1737_lock_group = {
+ .attrs = dme1737_attr_lock,
+};
+
+/* The permissions of the following PWM attributes are changed to read-
+ * writeable if the chip is *not* locked and the respective PWM is available.
+ * Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_pwm1_lock[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm2_lock[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm3_lock[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm5_lock[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm6_lock[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+ NULL
+};
+
+static const struct attribute_group dme1737_pwm_lock_group[] = {
+ { .attrs = dme1737_attr_pwm1_lock },
+ { .attrs = dme1737_attr_pwm2_lock },
+ { .attrs = dme1737_attr_pwm3_lock },
+ { .attrs = NULL },
+ { .attrs = dme1737_attr_pwm5_lock },
+ { .attrs = dme1737_attr_pwm6_lock },
+};
+
+/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
+ * chip is not locked. Otherwise they are read-only. */
+static struct attribute *dme1737_attr_pwm[] = {
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+};
+
+/* ---------------------------------------------------------------------
+ * Super-IO functions
+ * --------------------------------------------------------------------- */
+
+static inline int dme1737_sio_inb(int sio_cip, int reg)
+{
+ outb(reg, sio_cip);
+ return inb(sio_cip + 1);
+}
+
+static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
+{
+ outb(reg, sio_cip);
+ outb(val, sio_cip + 1);
+}
+
+static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+{
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int err = 0, reg;
+ u16 addr;
+
+ /* Enter configuration mode */
+ outb(0x55, sio_cip);
+
+ /* Check device ID
+ * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+ reg = dme1737_sio_inb(sio_cip, 0x20);
+ if (!(reg == 0x77 || reg == 0x78)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Select logical device A (runtime registers) */
+ dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+ /* Get the base address of the runtime registers */
+ if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61))) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Read the runtime registers to determine which optional features
+ * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+ * to '10' if the respective feature is enabled. */
+ if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+ data->has_fan |= (1 << 5);
+ }
+ if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+ data->has_pwm |= (1 << 5);
+ }
+ if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+ data->has_fan |= (1 << 4);
+ }
+ if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+ data->has_pwm |= (1 << 4);
+ }
+
+exit:
+ /* Exit configuration mode */
+ outb(0xaa, sio_cip);
+
+ return err;
+}
+
+/* ---------------------------------------------------------------------
+ * Device detection, registration and initialization
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_driver;
+
+static void dme1737_chmod_file(struct i2c_client *client,
+ struct attribute *attr, mode_t mode)
+{
+ if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
+ dev_warn(&client->dev, "Failed to change permissions of %s.\n",
+ attr->name);
+ }
+}
+
+static void dme1737_chmod_group(struct i2c_client *client,
+ const struct attribute_group *group,
+ mode_t mode)
+{
+ struct attribute **attr;
+
+ for (attr = group->attrs; *attr; attr++) {
+ dme1737_chmod_file(client, *attr, mode);
+ }
+}
+
+static int dme1737_init_client(struct i2c_client *client)
+{
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int ix;
+ u8 reg;
+
+ data->config = dme1737_read(client, DME1737_REG_CONFIG);
+ /* Inform if part is not monitoring/started */
+ if (!(data->config & 0x01)) {
+ if (!force_start) {
+ dev_err(&client->dev, "Device is not monitoring. "
+ "Use the force_start load parameter to "
+ "override.\n");
+ return -EFAULT;
+ }
+
+ /* Force monitoring */
+ data->config |= 0x01;
+ dme1737_write(client, DME1737_REG_CONFIG, data->config);
+ }
+ /* Inform if part is not ready */
+ if (!(data->config & 0x04)) {
+ dev_err(&client->dev, "Device is not ready.\n");
+ return -EFAULT;
+ }
+
+ data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+ /* Check if optional fan3 input is enabled */
+ if (data->config2 & 0x04) {
+ data->has_fan |= (1 << 2);
+ }
+
+ /* Fan4 and pwm3 are only available if the client's I2C address
+ * is the default 0x2e. Otherwise the I/Os associated with these
+ * functions are used for addr enable/select. */
+ if (client->addr == 0x2e) {
+ data->has_fan |= (1 << 3);
+ data->has_pwm |= (1 << 2);
+ }
+
+ /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
+ * For this, we need to query the runtime registers through the
+ * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
+ if (dme1737_sio_get_features(0x2e, client) &&
+ dme1737_sio_get_features(0x4e, client)) {
+ dev_warn(&client->dev, "Failed to query Super-IO for optional "
+ "features.\n");
+ }
+
+ /* Fan1, fan2, pwm1, and pwm2 are always present */
+ data->has_fan |= 0x03;
+ data->has_pwm |= 0x03;
+
+ dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+ "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+ (data->has_pwm & (1 << 2)) ? "yes" : "no",
+ (data->has_pwm & (1 << 4)) ? "yes" : "no",
+ (data->has_pwm & (1 << 5)) ? "yes" : "no",
+ (data->has_fan & (1 << 2)) ? "yes" : "no",
+ (data->has_fan & (1 << 3)) ? "yes" : "no",
+ (data->has_fan & (1 << 4)) ? "yes" : "no",
+ (data->has_fan & (1 << 5)) ? "yes" : "no");
+
+ reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+ /* Inform if fan-to-pwm mapping differs from the default */
+ if (reg != 0xa4) {
+ dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+ "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
+ "fan4->pwm%d. Please report to the driver "
+ "maintainer.\n",
+ (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+ ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+ }
+
+ /* Switch pwm[1-3] to manual mode if they are currently disabled and
+ * set the duty-cycles to 0% (which is identical to the PWMs being
+ * disabled). */
+ if (!(data->config & 0x02)) {
+ for (ix = 0; ix < 3; ix++) {
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ if ((data->has_pwm & (1 << ix)) &&
+ (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
+ dev_info(&client->dev, "Switching pwm%d to "
+ "manual mode.\n", ix + 1);
+ data->pwm_config[ix] = PWM_EN_TO_REG(1,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM(ix), 0);
+ dme1737_write(client,
+ DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ }
+ }
+ }
+
+ /* Initialize the default PWM auto channels zone (acz) assignments */
+ data->pwm_acz[0] = 1; /* pwm1 -> zone1 */
+ data->pwm_acz[1] = 2; /* pwm2 -> zone2 */
+ data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
+
+ /* Set VRM */
+ data->vrm = vid_which_vrm();
+
+ return 0;
+}
+
+static int dme1737_detect(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ u8 company, verstep = 0;
+ struct i2c_client *client;
+ struct dme1737_data *data;
+ int ix, err = 0;
+ const char *name;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &dme1737_driver;
+
+ /* A negative kind means that the driver was loaded with no force
+ * parameter (default), so we must identify the chip. */
+ if (kind < 0) {
+ company = dme1737_read(client, DME1737_REG_COMPANY);
+ verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+
+ if (!((company == DME1737_COMPANY_SMSC) &&
+ ((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
+ err = -ENODEV;
+ goto exit_kfree;
+ }
+ }
+
+ kind = dme1737;
+ name = "dme1737";
+
+ /* Fill in the remaining client fields and put it into the global
+ * list */
+ strlcpy(client->name, name, I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client))) {
+ goto exit_kfree;
+ }
+
+ /* Initialize the DME1737 chip */
+ if ((err = dme1737_init_client(client))) {
+ goto exit_detach;
+ }
+
+ /* Create standard sysfs attributes */
+ if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
+ goto exit_detach;
+ }
+
+ /* Create fan sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &dme1737_fan_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
+
+ /* Create PWM sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &dme1737_pwm_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
+
+ /* Inform if the device is locked. Otherwise change the permissions of
+ * selected attributes from read-only to read-writeable. */
+ if (data->config & 0x02) {
+ dev_info(&client->dev, "Device is locked. Some attributes "
+ "will be read-only.\n");
+ } else {
+ /* Change permissions of standard attributes */
+ dme1737_chmod_group(client, &dme1737_lock_group,
+ S_IRUGO | S_IWUSR);
+
+ /* Change permissions of PWM attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ dme1737_chmod_group(client,
+ &dme1737_pwm_lock_group[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
+
+ /* Change permissions of pwm[1-3] if in manual mode */
+ for (ix = 0; ix < 3; ix++) {
+ if ((data->has_pwm & (1 << ix)) &&
+ (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+ dme1737_chmod_file(client,
+ dme1737_attr_pwm[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
+ }
+
+ /* Register device */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
+ "(rev 0x%02x)\n", client->addr, verstep);
+
+ return 0;
+
+exit_remove:
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_fan_group[ix]);
+ }
+ }
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_pwm_group[ix]);
+ }
+ }
+ sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+exit_detach:
+ i2c_detach_client(client);
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON)) {
+ return 0;
+ }
+
+ return i2c_probe(adapter, &addr_data, dme1737_detect);
+}
+
+static int dme1737_detach_client(struct i2c_client *client)
+{
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int ix, err;
+
+ hwmon_device_unregister(data->class_dev);
+
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_fan_group[ix]);
+ }
+ }
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_pwm_group[ix]);
+ }
+ }
+ sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+
+ if ((err = i2c_detach_client(client))) {
+ return err;
+ }
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver dme1737_driver = {
+ .driver = {
+ .name = "dme1737",
+ },
+ .attach_adapter = dme1737_attach_adapter,
+ .detach_client = dme1737_detach_client,
+};
+
+static int __init dme1737_init(void)
+{
+ return i2c_add_driver(&dme1737_driver);
+}
+
+static void __exit dme1737_exit(void)
+{
+ i2c_del_driver(&dme1737_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("DME1737 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(dme1737_init);
+module_exit(dme1737_exit);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index d5ac422d73b2..1212d6b7f316 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -27,6 +27,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
@@ -52,9 +53,11 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
#define DS1621_REG_CONFIG_DONE 0x80
/* The DS1621 registers */
-#define DS1621_REG_TEMP 0xAA /* word, RO */
-#define DS1621_REG_TEMP_MIN 0xA2 /* word, RW */
-#define DS1621_REG_TEMP_MAX 0xA1 /* word, RW */
+static const u8 DS1621_REG_TEMP[3] = {
+ 0xAA, /* input, word, RO */
+ 0xA2, /* min, word, RW */
+ 0xA1, /* max, word, RW */
+};
#define DS1621_REG_CONF 0xAC /* byte, RW */
#define DS1621_COM_START 0xEE /* no data */
#define DS1621_COM_STOP 0x22 /* no data */
@@ -63,10 +66,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
#define DS1621_ALARM_TEMP_HIGH 0x40
#define DS1621_ALARM_TEMP_LOW 0x20
-/* Conversions. Rounding and limit checking is only done on the TO_REG
- variants. Note that you should be a bit careful with which arguments
- these macros are called: arguments may be evaluated more than once.
- Fixing this is just not worth it. */
+/* Conversions */
#define ALARMS_FROM_REG(val) ((val) & \
(DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
@@ -78,7 +78,7 @@ struct ds1621_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u16 temp, temp_min, temp_max; /* Register values, word */
+ u16 temp[3]; /* Register values, word */
u8 conf; /* Register encoding, combined */
};
@@ -101,7 +101,7 @@ static struct i2c_driver ds1621_driver = {
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
+ the SMBus standard. */
static int ds1621_read_value(struct i2c_client *client, u8 reg)
{
if (reg == DS1621_REG_CONF)
@@ -110,9 +110,6 @@ static int ds1621_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.
- DS1621 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == DS1621_REG_CONF)
@@ -139,50 +136,61 @@ static void ds1621_init_client(struct i2c_client *client)
i2c_smbus_write_byte(client, DS1621_COM_START);
}
-#define show(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct ds1621_data *data = ds1621_update_client(dev); \
- return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ds1621_data *data = ds1621_update_client(dev);
+ return sprintf(buf, "%d\n",
+ LM75_TEMP_FROM_REG(data->temp[attr->index]));
}
-show(temp);
-show(temp_min);
-show(temp_max);
-
-#define set_temp(suffix, value, reg) \
-static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct ds1621_data *data = ds1621_update_client(dev); \
- u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \
- \
- mutex_lock(&data->update_lock); \
- data->value = val; \
- ds1621_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
-}
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1621_data *data = ds1621_update_client(dev);
+ u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
-set_temp(min, temp_min, DS1621_REG_TEMP_MIN);
-set_temp(max, temp_max, DS1621_REG_TEMP_MAX);
+ mutex_lock(&data->update_lock);
+ data->temp[attr->index] = val;
+ ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
+ data->temp[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct ds1621_data *data = ds1621_update_client(dev);
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ds1621_data *data = ds1621_update_client(dev);
+ return sprintf(buf, "%d\n", !!(data->conf & attr->index));
+}
+
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+ DS1621_ALARM_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+ DS1621_ALARM_TEMP_HIGH);
static struct attribute *ds1621_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_max.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
NULL
};
@@ -204,9 +212,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
int kind)
{
int conf, temp;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct ds1621_data *data;
- int err = 0;
+ int i, err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA
@@ -221,55 +229,44 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &ds1621_driver;
- new_client->flags = 0;
-
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &ds1621_driver;
/* Now, we do the remaining detection. It is lousy. */
if (kind < 0) {
/* The NVB bit should be low if no EEPROM write has been
requested during the latest 10ms, which is highly
improbable in our case. */
- conf = ds1621_read_value(new_client, DS1621_REG_CONF);
+ conf = ds1621_read_value(client, DS1621_REG_CONF);
if (conf & DS1621_REG_CONFIG_NVB)
goto exit_free;
/* The 7 lowest bits of a temperature should always be 0. */
- temp = ds1621_read_value(new_client, DS1621_REG_TEMP);
- if (temp & 0x007f)
- goto exit_free;
- temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN);
- if (temp & 0x007f)
- goto exit_free;
- temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
- if (temp & 0x007f)
- goto exit_free;
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
+ if (temp & 0x007f)
+ goto exit_free;
+ }
}
- /* Determine the chip type - only one kind supported! */
- if (kind <= 0)
- kind = ds1621;
-
/* Fill in remaining client fields and put it into the global list */
- strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
- data->valid = 0;
+ strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the DS1621 chip */
- ds1621_init_client(new_client);
+ ds1621_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -278,9 +275,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
+ sysfs_remove_group(&client->dev.kobj, &ds1621_group);
exit_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -314,23 +311,21 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
+ int i;
dev_dbg(&client->dev, "Starting ds1621 update\n");
data->conf = ds1621_read_value(client, DS1621_REG_CONF);
- data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
-
- data->temp_min = ds1621_read_value(client,
- DS1621_REG_TEMP_MIN);
- data->temp_max = ds1621_read_value(client,
- DS1621_REG_TEMP_MAX);
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+ data->temp[i] = ds1621_read_value(client,
+ DS1621_REG_TEMP[i]);
/* reset alarms if necessary */
new_conf = data->conf;
- if (data->temp > data->temp_min)
+ if (data->temp[0] > data->temp[1]) /* input > min */
new_conf &= ~DS1621_ALARM_TEMP_LOW;
- if (data->temp < data->temp_max)
+ if (data->temp[0] < data->temp[2]) /* input < max */
new_conf &= ~DS1621_ALARM_TEMP_HIGH;
if (data->conf != new_conf)
ds1621_write_value(client, DS1621_REG_CONF,
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index cdbe309b8fc4..6f60715f34f8 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -127,6 +127,13 @@ superio_exit(int base)
#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr))
#define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr))
#define F71805F_REG_TEMP_MODE 0x01
+/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */
+/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */
+#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \
+ (0xA0 + 0x10 * (pwmnr) + (2 - (apnr)))
+#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \
+ (0xA4 + 0x10 * (pwmnr) + \
+ 2 * (2 - (apnr)))
#define F71805F_REG_START 0x00
/* status nr from 0 to 2 */
@@ -144,6 +151,11 @@ superio_exit(int base)
* Data structures and manipulation thereof
*/
+struct f71805f_auto_point {
+ u8 temp[3];
+ u16 fan[3];
+};
+
struct f71805f_data {
unsigned short addr;
const char *name;
@@ -170,6 +182,7 @@ struct f71805f_data {
u8 temp_hyst[3];
u8 temp_mode;
unsigned long alarms;
+ struct f71805f_auto_point auto_points[3];
};
struct f71805f_sio_data {
@@ -312,7 +325,7 @@ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
static struct f71805f_data *f71805f_update_device(struct device *dev)
{
struct f71805f_data *data = dev_get_drvdata(dev);
- int nr;
+ int nr, apnr;
mutex_lock(&data->update_lock);
@@ -342,6 +355,18 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
F71805F_REG_TEMP_HYST(nr));
}
data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE);
+ for (nr = 0; nr < 3; nr++) {
+ for (apnr = 0; apnr < 3; apnr++) {
+ data->auto_points[nr].temp[apnr] =
+ f71805f_read8(data,
+ F71805F_REG_PWM_AUTO_POINT_TEMP(nr,
+ apnr));
+ data->auto_points[nr].fan[apnr] =
+ f71805f_read16(data,
+ F71805F_REG_PWM_AUTO_POINT_FAN(nr,
+ apnr));
+ }
+ }
data->last_limits = jiffies;
}
@@ -705,6 +730,70 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
return count;
}
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char* buf)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+
+ return sprintf(buf, "%ld\n",
+ temp_from_reg(data->auto_points[pwmnr].temp[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char* buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+ unsigned long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
+ f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr),
+ data->auto_points[pwmnr].temp[apnr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_point_fan(struct device *dev,
+ struct device_attribute *devattr,
+ char* buf)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+
+ return sprintf(buf, "%ld\n",
+ fan_from_reg(data->auto_points[pwmnr].fan[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_fan(struct device *dev,
+ struct device_attribute *devattr,
+ const char* buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
+ f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr),
+ data->auto_points[pwmnr].fan[apnr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -932,6 +1021,63 @@ static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR,
show_pwm_freq, set_pwm_freq, 2);
static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 0, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 2, 2);
+
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
@@ -1014,6 +1160,25 @@ static struct attribute *f71805f_attributes[] = {
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr,
+
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
@@ -1242,12 +1407,12 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
struct resource *res;
int i;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1290,15 +1455,12 @@ static int __init f71805f_device_add(unsigned short address,
goto exit_device_put;
}
- pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
- GFP_KERNEL);
- if (!pdev->dev.platform_data) {
- err = -ENOMEM;
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct f71805f_sio_data));
+ if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
- memcpy(pdev->dev.platform_data, sio_data,
- sizeof(struct f71805f_sio_data));
err = platform_device_add(pdev);
if (err) {
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index 19717752cfca..b34b546c68b8 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -441,6 +441,8 @@ static struct fscher_data *fscher_update_device(struct device *dev)
data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL);
data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE);
+ data->global_control = fscher_read_value(client,
+ FSCHER_REG_CONTROL);
data->last_updated = jiffies;
data->valid = 1;
@@ -599,7 +601,7 @@ static ssize_t set_control(struct i2c_client *client, struct fscher_data *data,
unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01;
mutex_lock(&data->update_lock);
- data->global_control &= ~v;
+ data->global_control = v;
fscher_write_value(client, reg, v);
mutex_unlock(&data->update_lock);
return count;
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index e0cf5e6fe5bc..a7c6d407572b 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -480,14 +480,14 @@ static struct attribute_group hdaps_attribute_group = {
/* Module stuff */
/* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */
-static int __init hdaps_dmi_match(struct dmi_system_id *id)
+static int __init hdaps_dmi_match(const struct dmi_system_id *id)
{
printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
return 1;
}
/* hdaps_dmi_match_invert - found an inverted match. */
-static int __init hdaps_dmi_match_invert(struct dmi_system_id *id)
+static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
{
hdaps_invert = 1;
printk(KERN_INFO "hdaps: inverting axis readings.\n");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 62afc63708a5..d75dba9b810b 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -6,6 +6,7 @@
IT8712F Super I/O chip w/LPC interface
IT8716F Super I/O chip w/LPC interface
IT8718F Super I/O chip w/LPC interface
+ IT8726F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com>
@@ -30,8 +31,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -40,10 +40,12 @@
#include <linux/sysfs.h>
#include <asm/io.h>
+#define DRVNAME "it87"
-static unsigned short isa_address;
enum chips { it87, it8712, it8716, it8718 };
+static struct platform_device *pdev;
+
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
#define VAL 0x2f /* The value to read/write */
@@ -97,6 +99,7 @@ superio_exit(void)
#define IT8705F_DEVID 0x8705
#define IT8716F_DEVID 0x8716
#define IT8718F_DEVID 0x8718
+#define IT8726F_DEVID 0x8726
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
@@ -110,10 +113,6 @@ static int update_vbat;
/* Not all BIOSes properly configure the PWM registers */
static int fix_pwm_polarity;
-/* Values read from Super-I/O config space */
-static u16 chip_type;
-static u8 vid_value;
-
/* Many IT87 constants specified below */
/* Length of ISA address segment */
@@ -214,13 +213,20 @@ static const unsigned int pwm_freq[8] = {
};
+struct it87_sio_data {
+ enum chips type;
+ /* Values read from Super-I/O config space */
+ u8 vid_value;
+};
+
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct it87_data {
- struct i2c_client client;
struct class_device *class_dev;
enum chips type;
+ unsigned short addr;
+ const char *name;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -245,26 +251,25 @@ struct it87_data {
};
-static int it87_detect(struct i2c_adapter *adapter);
-static int it87_detach_client(struct i2c_client *client);
+static int it87_probe(struct platform_device *pdev);
+static int __devexit it87_remove(struct platform_device *pdev);
-static int it87_read_value(struct i2c_client *client, u8 reg);
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int it87_read_value(struct it87_data *data, u8 reg);
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value);
static struct it87_data *it87_update_device(struct device *dev);
-static int it87_check_pwm(struct i2c_client *client);
-static void it87_init_client(struct i2c_client *client, struct it87_data *data);
+static int it87_check_pwm(struct device *dev);
+static void it87_init_device(struct platform_device *pdev);
-static struct i2c_driver it87_isa_driver = {
+static struct platform_driver it87_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "it87-isa",
+ .name = DRVNAME,
},
- .attach_adapter = it87_detect,
- .detach_client = it87_detach_client,
+ .probe = it87_probe,
+ .remove = __devexit_p(it87_remove),
};
-
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -301,13 +306,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
- it87_write_value(client, IT87_REG_VIN_MIN(nr),
+ it87_write_value(data, IT87_REG_VIN_MIN(nr),
data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -318,13 +322,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
- it87_write_value(client, IT87_REG_VIN_MAX(nr),
+ it87_write_value(data, IT87_REG_VIN_MAX(nr),
data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -392,13 +395,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_high[nr] = TEMP_TO_REG(val);
- it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+ it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -408,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_low[nr] = TEMP_TO_REG(val);
- it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
+ it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -451,8 +452,7 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -468,7 +468,7 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
mutex_unlock(&data->update_lock);
return -EINVAL;
}
- it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+ it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
mutex_unlock(&data->update_lock);
return count;
}
@@ -542,13 +542,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
u8 reg;
mutex_lock(&data->update_lock);
- reg = it87_read_value(client, IT87_REG_FAN_DIV);
+ reg = it87_read_value(data, IT87_REG_FAN_DIV);
switch (nr) {
case 0: data->fan_div[nr] = reg & 0x07; break;
case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
@@ -556,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
}
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -566,14 +565,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
int min;
u8 old;
mutex_lock(&data->update_lock);
- old = it87_read_value(client, IT87_REG_FAN_DIV);
+ old = it87_read_value(data, IT87_REG_FAN_DIV);
/* Save fan min limit */
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
@@ -594,11 +592,11 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
val |= (data->fan_div[1] & 0x07) << 3;
if (data->fan_div[2] == 3)
val |= 0x1 << 6;
- it87_write_value(client, IT87_REG_FAN_DIV, val);
+ it87_write_value(data, IT87_REG_FAN_DIV, val);
/* Restore fan min limit */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -609,8 +607,7 @@ static ssize_t set_pwm_enable(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -618,17 +615,17 @@ static ssize_t set_pwm_enable(struct device *dev,
if (val == 0) {
int tmp;
/* make sure the fan is on when in on/off mode */
- tmp = it87_read_value(client, IT87_REG_FAN_CTL);
- it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr));
+ tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+ it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
/* set on/off mode */
data->fan_main_ctrl &= ~(1 << nr);
- it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
} else if (val == 1) {
/* set SmartGuardian mode */
data->fan_main_ctrl |= (1 << nr);
- it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
/* set saved pwm value, clear FAN_CTLX PWM mode bit */
- it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+ it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
} else {
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -643,8 +640,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
if (val < 0 || val > 255)
@@ -653,15 +649,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->manual_pwm_ctl[nr] = val;
if (data->fan_main_ctrl & (1 << nr))
- it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+ it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_pwm_freq(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
int i;
@@ -672,9 +667,9 @@ static ssize_t set_pwm_freq(struct device *dev,
}
mutex_lock(&data->update_lock);
- data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f;
+ data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
data->fan_ctl |= i << 4;
- it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl);
+ it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
mutex_unlock(&data->update_lock);
return count;
@@ -729,15 +724,14 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN16_TO_REG(val);
- it87_write_value(client, IT87_REG_FAN_MIN(nr),
+ it87_write_value(data, IT87_REG_FAN_MIN(nr),
data->fan_min[nr] & 0xff);
- it87_write_value(client, IT87_REG_FANX_MIN(nr),
+ it87_write_value(data, IT87_REG_FANX_MIN(nr),
data->fan_min[nr] >> 8);
mutex_unlock(&data->update_lock);
return count;
@@ -775,8 +769,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t
store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -794,6 +787,14 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *it87_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
@@ -835,6 +836,7 @@ static struct attribute *it87_attributes[] = {
&sensor_dev_attr_temp3_type.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -877,17 +879,36 @@ static const struct attribute_group it87_group_opt = {
};
/* SuperIO detection - will change isa_address if a chip is found */
-static int __init it87_find(unsigned short *address)
+static int __init it87_find(unsigned short *address,
+ struct it87_sio_data *sio_data)
{
int err = -ENODEV;
+ u16 chip_type;
superio_enter();
chip_type = superio_inw(DEVID);
- if (chip_type != IT8712F_DEVID
- && chip_type != IT8716F_DEVID
- && chip_type != IT8718F_DEVID
- && chip_type != IT8705F_DEVID)
- goto exit;
+
+ switch (chip_type) {
+ case IT8705F_DEVID:
+ sio_data->type = it87;
+ break;
+ case IT8712F_DEVID:
+ sio_data->type = it8712;
+ break;
+ case IT8716F_DEVID:
+ case IT8726F_DEVID:
+ sio_data->type = it8716;
+ break;
+ case IT8718F_DEVID:
+ sio_data->type = it8718;
+ break;
+ case 0xffff: /* No device at all */
+ goto exit;
+ default:
+ pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n",
+ chip_type);
+ goto exit;
+ }
superio_select(PME);
if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
@@ -911,7 +932,7 @@ static int __init it87_find(unsigned short *address)
superio_select(GPIO);
if (chip_type == it8718)
- vid_value = superio_inb(IT87_SIO_VID_REG);
+ sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
reg = superio_inb(IT87_SIO_PINX2_REG);
if (reg & (1 << 0))
@@ -925,18 +946,26 @@ exit:
return err;
}
-/* This function is called by i2c_probe */
-static int it87_detect(struct i2c_adapter *adapter)
+static int __devinit it87_probe(struct platform_device *pdev)
{
- struct i2c_client *new_client;
struct it87_data *data;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct it87_sio_data *sio_data = dev->platform_data;
int err = 0;
- const char *name;
int enable_pwm_interface;
-
- /* Reserve the ISA region */
- if (!request_region(isa_address, IT87_EXTENT,
- it87_isa_driver.driver.name)){
+ static const char *names[] = {
+ "it87",
+ "it8712",
+ "it8716",
+ "it8718",
+ };
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, IT87_EXTENT, DRVNAME)) {
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start,
+ (unsigned long)(res->start + IT87_EXTENT - 1));
err = -EBUSY;
goto ERROR0;
}
@@ -946,129 +975,104 @@ static int it87_detect(struct i2c_adapter *adapter)
goto ERROR1;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = isa_address;
- new_client->adapter = adapter;
- new_client->driver = &it87_isa_driver;
+ data->addr = res->start;
+ data->type = sio_data->type;
+ data->name = names[sio_data->type];
/* Now, we do the remaining detection. */
- if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
- || it87_read_value(new_client, IT87_REG_CHIPID) != 0x90) {
+ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
+ || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
err = -ENODEV;
goto ERROR2;
}
- /* Determine the chip type. */
- switch (chip_type) {
- case IT8712F_DEVID:
- data->type = it8712;
- name = "it8712";
- break;
- case IT8716F_DEVID:
- data->type = it8716;
- name = "it8716";
- break;
- case IT8718F_DEVID:
- data->type = it8718;
- name = "it8718";
- break;
- default:
- data->type = it87;
- name = "it87";
- }
+ platform_set_drvdata(pdev, data);
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto ERROR2;
-
/* Check PWM configuration */
- enable_pwm_interface = it87_check_pwm(new_client);
+ enable_pwm_interface = it87_check_pwm(dev);
/* Initialize the IT87 chip */
- it87_init_client(new_client, data);
+ it87_init_device(pdev);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
- goto ERROR3;
+ if ((err = sysfs_create_group(&dev->kobj, &it87_group)))
+ goto ERROR2;
/* Do not create fan files for disabled fans */
if (data->type == it8716 || data->type == it8718) {
/* 16-bit tachometers */
if (data->has_fan & (1 << 0)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan1_input16.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan1_min16.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 1)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan2_input16.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan2_min16.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 2)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan3_input16.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_min16.dev_attr)))
goto ERROR4;
}
} else {
/* 8-bit tachometers with clock divider */
if (data->has_fan & (1 << 0)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan1_input.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan1_min.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan1_div.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 1)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan2_input.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan2_min.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan2_div.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 2)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan3_input.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_min.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_div.dev_attr)))
goto ERROR4;
}
}
if (enable_pwm_interface) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_pwm1_enable.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm2_enable.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm3_enable.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm1.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm2.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm3.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_pwm1_freq))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_pwm2_freq))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_pwm3_freq)))
goto ERROR4;
}
@@ -1077,15 +1081,15 @@ static int it87_detect(struct i2c_adapter *adapter)
|| data->type == it8718) {
data->vrm = vid_which_vrm();
/* VID reading from Super-I/O config space if available */
- data->vid = vid_value;
- if ((err = device_create_file(&new_client->dev,
+ data->vid = sio_data->vid_value;
+ if ((err = device_create_file(dev,
&dev_attr_vrm))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_cpu0_vid)))
goto ERROR4;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto ERROR4;
@@ -1094,31 +1098,27 @@ static int it87_detect(struct i2c_adapter *adapter)
return 0;
ERROR4:
- sysfs_remove_group(&new_client->dev.kobj, &it87_group);
- sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
-ERROR3:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&dev->kobj, &it87_group);
+ sysfs_remove_group(&dev->kobj, &it87_group_opt);
ERROR2:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
ERROR1:
- release_region(isa_address, IT87_EXTENT);
+ release_region(res->start, IT87_EXTENT);
ERROR0:
return err;
}
-static int it87_detach_client(struct i2c_client *client)
+static int __devexit it87_remove(struct platform_device *pdev)
{
- struct it87_data *data = i2c_get_clientdata(client);
- int err;
+ struct it87_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &it87_group);
- sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
+ sysfs_remove_group(&pdev->dev.kobj, &it87_group);
+ sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, IT87_EXTENT);
+ release_region(data->addr, IT87_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -1127,28 +1127,29 @@ static int it87_detach_client(struct i2c_client *client)
/* Must be called with data->update_lock held, except during initialization.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
-static int it87_read_value(struct i2c_client *client, u8 reg)
+static int it87_read_value(struct it87_data *data, u8 reg)
{
- outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- return inb_p(client->addr + IT87_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+ return inb_p(data->addr + IT87_DATA_REG_OFFSET);
}
/* Must be called with data->update_lock held, except during initialization.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
{
- outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+ outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
}
/* Return 1 if and only if the PWM interface is safe to use */
-static int it87_check_pwm(struct i2c_client *client)
+static int __devinit it87_check_pwm(struct device *dev)
{
+ struct it87_data *data = dev_get_drvdata(dev);
/* Some BIOSes fail to correctly configure the IT87 fans. All fans off
* and polarity set to active low is sign that this is the case so we
* disable pwm control to protect the user. */
- int tmp = it87_read_value(client, IT87_REG_FAN_CTL);
+ int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
if ((tmp & 0x87) == 0) {
if (fix_pwm_polarity) {
/* The user asks us to attempt a chip reconfiguration.
@@ -1158,7 +1159,7 @@ static int it87_check_pwm(struct i2c_client *client)
u8 pwm[3];
for (i = 0; i < 3; i++)
- pwm[i] = it87_read_value(client,
+ pwm[i] = it87_read_value(data,
IT87_REG_PWM(i));
/* If any fan is in automatic pwm mode, the polarity
@@ -1166,26 +1167,26 @@ static int it87_check_pwm(struct i2c_client *client)
* better don't change anything (but still disable the
* PWM interface). */
if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
- dev_info(&client->dev, "Reconfiguring PWM to "
+ dev_info(dev, "Reconfiguring PWM to "
"active high polarity\n");
- it87_write_value(client, IT87_REG_FAN_CTL,
+ it87_write_value(data, IT87_REG_FAN_CTL,
tmp | 0x87);
for (i = 0; i < 3; i++)
- it87_write_value(client,
+ it87_write_value(data,
IT87_REG_PWM(i),
0x7f & ~pwm[i]);
return 1;
}
- dev_info(&client->dev, "PWM configuration is "
+ dev_info(dev, "PWM configuration is "
"too broken to be fixed\n");
}
- dev_info(&client->dev, "Detected broken BIOS "
+ dev_info(dev, "Detected broken BIOS "
"defaults, disabling PWM interface\n");
return 0;
} else if (fix_pwm_polarity) {
- dev_info(&client->dev, "PWM configuration looks "
+ dev_info(dev, "PWM configuration looks "
"sane, won't touch\n");
}
@@ -1193,8 +1194,9 @@ static int it87_check_pwm(struct i2c_client *client)
}
/* Called when we have found a new IT87. */
-static void it87_init_client(struct i2c_client *client, struct it87_data *data)
+static void __devinit it87_init_device(struct platform_device *pdev)
{
+ struct it87_data *data = platform_get_drvdata(pdev);
int tmp, i;
/* initialize to sane defaults:
@@ -1214,48 +1216,48 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
* means -1 degree C, which surprisingly doesn't trigger an alarm,
* but is still confusing, so change to 127 degrees C. */
for (i = 0; i < 8; i++) {
- tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
+ tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
if (tmp == 0xff)
- it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
+ it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
}
for (i = 0; i < 3; i++) {
- tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+ tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
if (tmp == 0xff)
- it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
+ it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
}
/* Check if temperature channnels are reset manually or by some reason */
- tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+ tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);
if ((tmp & 0x3f) == 0) {
/* Temp1,Temp3=thermistor; Temp2=thermal diode */
tmp = (tmp & 0xc0) | 0x2a;
- it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp);
+ it87_write_value(data, IT87_REG_TEMP_ENABLE, tmp);
}
data->sensor = tmp;
/* Check if voltage monitors are reset manually or by some reason */
- tmp = it87_read_value(client, IT87_REG_VIN_ENABLE);
+ tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
if ((tmp & 0xff) == 0) {
/* Enable all voltage monitors */
- it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
+ it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
}
/* Check if tachometers are reset manually or by some reason */
- data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
+ data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
if ((data->fan_main_ctrl & 0x70) == 0) {
/* Enable all fan tachometers */
data->fan_main_ctrl |= 0x70;
- it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
}
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
/* Set tachometers to 16-bit mode if needed */
if (data->type == it8716 || data->type == it8718) {
- tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
+ tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
if (~tmp & 0x07 & data->has_fan) {
- dev_dbg(&client->dev,
+ dev_dbg(&pdev->dev,
"Setting fan1-3 to 16-bit mode\n");
- it87_write_value(client, IT87_REG_FAN_16BIT,
+ it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
}
@@ -1265,7 +1267,7 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
for (i = 0; i < 3; i++) {
if (data->fan_main_ctrl & (1 << i)) {
/* pwm mode */
- tmp = it87_read_value(client, IT87_REG_PWM(i));
+ tmp = it87_read_value(data, IT87_REG_PWM(i));
if (tmp & 0x80) {
/* automatic pwm - not yet implemented, but
* leave the settings made by the BIOS alone
@@ -1279,15 +1281,14 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
}
/* Start monitoring */
- it87_write_value(client, IT87_REG_CONFIG,
- (it87_read_value(client, IT87_REG_CONFIG) & 0x36)
+ it87_write_value(data, IT87_REG_CONFIG,
+ (it87_read_value(data, IT87_REG_CONFIG) & 0x36)
| (update_vbat ? 0x41 : 0x01));
}
static struct it87_data *it87_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -1298,20 +1299,20 @@ static struct it87_data *it87_update_device(struct device *dev)
if (update_vbat) {
/* Cleared after each update, so reenable. Value
returned by this read will be previous value */
- it87_write_value(client, IT87_REG_CONFIG,
- it87_read_value(client, IT87_REG_CONFIG) | 0x40);
+ it87_write_value(data, IT87_REG_CONFIG,
+ it87_read_value(data, IT87_REG_CONFIG) | 0x40);
}
for (i = 0; i <= 7; i++) {
data->in[i] =
- it87_read_value(client, IT87_REG_VIN(i));
+ it87_read_value(data, IT87_REG_VIN(i));
data->in_min[i] =
- it87_read_value(client, IT87_REG_VIN_MIN(i));
+ it87_read_value(data, IT87_REG_VIN_MIN(i));
data->in_max[i] =
- it87_read_value(client, IT87_REG_VIN_MAX(i));
+ it87_read_value(data, IT87_REG_VIN_MAX(i));
}
/* in8 (battery) has no limit registers */
data->in[8] =
- it87_read_value(client, IT87_REG_VIN(8));
+ it87_read_value(data, IT87_REG_VIN(8));
for (i = 0; i < 3; i++) {
/* Skip disabled fans */
@@ -1319,46 +1320,47 @@ static struct it87_data *it87_update_device(struct device *dev)
continue;
data->fan_min[i] =
- it87_read_value(client, IT87_REG_FAN_MIN(i));
- data->fan[i] = it87_read_value(client,
+ it87_read_value(data, IT87_REG_FAN_MIN(i));
+ data->fan[i] = it87_read_value(data,
IT87_REG_FAN(i));
/* Add high byte if in 16-bit mode */
if (data->type == it8716 || data->type == it8718) {
- data->fan[i] |= it87_read_value(client,
+ data->fan[i] |= it87_read_value(data,
IT87_REG_FANX(i)) << 8;
- data->fan_min[i] |= it87_read_value(client,
+ data->fan_min[i] |= it87_read_value(data,
IT87_REG_FANX_MIN(i)) << 8;
}
}
for (i = 0; i < 3; i++) {
data->temp[i] =
- it87_read_value(client, IT87_REG_TEMP(i));
+ it87_read_value(data, IT87_REG_TEMP(i));
data->temp_high[i] =
- it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+ it87_read_value(data, IT87_REG_TEMP_HIGH(i));
data->temp_low[i] =
- it87_read_value(client, IT87_REG_TEMP_LOW(i));
+ it87_read_value(data, IT87_REG_TEMP_LOW(i));
}
/* Newer chips don't have clock dividers */
if ((data->has_fan & 0x07) && data->type != it8716
&& data->type != it8718) {
- i = it87_read_value(client, IT87_REG_FAN_DIV);
+ i = it87_read_value(data, IT87_REG_FAN_DIV);
data->fan_div[0] = i & 0x07;
data->fan_div[1] = (i >> 3) & 0x07;
data->fan_div[2] = (i & 0x40) ? 3 : 1;
}
data->alarms =
- it87_read_value(client, IT87_REG_ALARM1) |
- (it87_read_value(client, IT87_REG_ALARM2) << 8) |
- (it87_read_value(client, IT87_REG_ALARM3) << 16);
- data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
- data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL);
-
- data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+ it87_read_value(data, IT87_REG_ALARM1) |
+ (it87_read_value(data, IT87_REG_ALARM2) << 8) |
+ (it87_read_value(data, IT87_REG_ALARM3) << 16);
+ data->fan_main_ctrl = it87_read_value(data,
+ IT87_REG_FAN_MAIN_CTRL);
+ data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
+
+ data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability */
if (data->type == it8712 || data->type == it8716) {
- data->vid = it87_read_value(client, IT87_REG_VID);
+ data->vid = it87_read_value(data, IT87_REG_VID);
/* The older IT8712F revisions had only 5 VID pins,
but we assume it is always safe to read 6 bits. */
data->vid &= 0x3f;
@@ -1372,24 +1374,85 @@ static struct it87_data *it87_update_device(struct device *dev)
return data;
}
+static int __init it87_device_add(unsigned short address,
+ const struct it87_sio_data *sio_data)
+{
+ struct resource res = {
+ .start = address ,
+ .end = address + IT87_EXTENT - 1,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct it87_sio_data));
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __init sm_it87_init(void)
{
- int res;
+ int err;
+ unsigned short isa_address=0;
+ struct it87_sio_data sio_data;
+
+ err = it87_find(&isa_address, &sio_data);
+ if (err)
+ return err;
+ err = platform_driver_register(&it87_driver);
+ if (err)
+ return err;
- if ((res = it87_find(&isa_address)))
- return res;
- return i2c_isa_add_driver(&it87_isa_driver);
+ err = it87_device_add(isa_address, &sio_data);
+ if (err){
+ platform_driver_unregister(&it87_driver);
+ return err;
+ }
+
+ return 0;
}
static void __exit sm_it87_exit(void)
{
- i2c_isa_del_driver(&it87_isa_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&it87_driver);
}
MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
"Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver");
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
module_param(fix_pwm_polarity, bool, 0);
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index d69f3cf07122..2162d69a8c06 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -364,7 +364,7 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
@@ -383,7 +383,7 @@ static struct attribute *lm63_attributes[] = {
&dev_attr_temp2_crit_hyst.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 9fb572f03ba5..6eea3476b90c 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -864,7 +864,7 @@ static int __init lm78_isa_found(unsigned short address)
/* Determine the chip type */
outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET);
val = inb_p(address + LM78_DATA_REG_OFFSET);
- if (val == 0x00 /* LM78 */
+ if (val == 0x00 || val == 0x20 /* LM78 */
|| val == 0x40 /* LM78-J */
|| (val & 0xfe) == 0xc0) /* LM79 */
found = 1;
@@ -882,7 +882,7 @@ static int __init lm78_isa_device_add(unsigned short address)
{
struct resource res = {
.start = address,
- .end = address + LM78_EXTENT,
+ .end = address + LM78_EXTENT - 1,
.name = "lm78",
.flags = IORESOURCE_IO,
};
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index feb87b41e986..654c0f73464d 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -223,14 +223,14 @@ static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
@@ -245,7 +245,7 @@ static struct attribute *lm83_attributes[] = {
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
@@ -266,9 +266,9 @@ static struct attribute *lm83_attributes_opt[] = {
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp4_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
NULL
};
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 6882ce75feee..af541d67245d 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -43,6 +43,13 @@
* variants. The extra address and features of the MAX6659 are not
* supported by this driver.
*
+ * This driver also supports the MAX6680 and MAX6681, two other sensor
+ * chips made by Maxim. These are quite similar to the other Maxim
+ * chips. Complete datasheet can be obtained at:
+ * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
+ * The MAX6680 and MAX6681 only differ in the pinout so they can be
+ * treated identically.
+ *
* This driver also supports the ADT7461 chip from Analog Devices but
* only in its "compatability mode". If an ADT7461 chip is found but
* is configured in non-compatible mode (where its temperature
@@ -84,20 +91,25 @@
/*
* Addresses to scan
* Address is fully defined internally and cannot be changed except for
- * MAX6659.
+ * MAX6659, MAX6680 and MAX6681.
* LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658
* have address 0x4c.
* ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d.
* MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ * 0x4c, 0x4d or 0x4e.
*/
-static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
+ 0x29, 0x2a, 0x2b,
+ 0x4c, 0x4d, 0x4e,
+ I2C_CLIENT_END };
/*
* Insmod parameters
*/
-I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
/*
* The LM90 registers
@@ -359,7 +371,7 @@ static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
@@ -381,7 +393,7 @@ static struct attribute *lm90_attributes[] = {
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
@@ -429,7 +441,7 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
*/
/* The ADM1032 supports PEC but not on write byte transactions, so we need
- to explicitely ask for a transaction without PEC. */
+ to explicitly ask for a transaction without PEC. */
static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter, client->addr,
@@ -525,7 +537,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
&reg_convrate) < 0)
goto exit_free;
- if (man_id == 0x01) { /* National Semiconductor */
+ if ((address == 0x4C || address == 0x4D)
+ && man_id == 0x01) { /* National Semiconductor */
u8 reg_config2;
if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2,
@@ -548,7 +561,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
} else
- if (man_id == 0x41) { /* Analog Devices */
+ if ((address == 0x4C || address == 0x4D)
+ && man_id == 0x41) { /* Analog Devices */
if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
&& (reg_config1 & 0x3F) == 0x00
&& reg_convrate <= 0x0A) {
@@ -562,18 +576,30 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
} else
if (man_id == 0x4D) { /* Maxim */
/*
- * The Maxim variants do NOT have a chip_id register.
- * Reading from that address will return the last read
- * value, which in our case is those of the man_id
- * register. Likewise, the config1 register seems to
- * lack a low nibble, so the value will be those of the
- * previous read, so in our case those of the man_id
- * register.
+ * The MAX6657, MAX6658 and MAX6659 do NOT have a
+ * chip_id register. Reading from that address will
+ * return the last read value, which in our case is
+ * those of the man_id register. Likewise, the config1
+ * register seems to lack a low nibble, so the value
+ * will be those of the previous read, so in our case
+ * those of the man_id register.
*/
if (chip_id == man_id
+ && (address == 0x4C || address == 0x4D)
&& (reg_config1 & 0x1F) == (man_id & 0x0F)
&& reg_convrate <= 0x09) {
kind = max6657;
+ } else
+ /* The chip_id register of the MAX6680 and MAX6681
+ * holds the revision of the chip.
+ * the lowest bit of the config1 register is unused
+ * and should return zero when read, so should the
+ * second to last bit of config1 (software reset)
+ */
+ if (chip_id == 0x01
+ && (reg_config1 & 0x03) == 0x00
+ && reg_convrate <= 0x07) {
+ kind = max6680;
}
}
@@ -599,6 +625,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
name = "lm86";
} else if (kind == max6657) {
name = "max6657";
+ } else if (kind == max6680) {
+ name = "max6680";
} else if (kind == adt7461) {
name = "adt7461";
}
@@ -646,7 +674,8 @@ exit:
static void lm90_init_client(struct i2c_client *client)
{
- u8 config;
+ u8 config, config_orig;
+ struct lm90_data *data = i2c_get_clientdata(client);
/*
* Start the conversions.
@@ -657,9 +686,20 @@ static void lm90_init_client(struct i2c_client *client)
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
- if (config & 0x40)
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
- config & 0xBF); /* run */
+ config_orig = config;
+
+ /*
+ * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+ * 0.125 degree resolution) and range (0x08, extend range
+ * to -64 degree) mode for the remote temperature sensor.
+ */
+ if (data->kind == max6680) {
+ config |= 0x18;
+ }
+
+ config &= 0xBF; /* run */
+ if (config != config_orig) /* Only write if changed */
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}
static int lm90_detach_client(struct i2c_client *client)
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
new file mode 100644
index 000000000000..d84f8bf6f284
--- /dev/null
+++ b/drivers/hwmon/lm93.c
@@ -0,0 +1,2655 @@
+/*
+ lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+
+ Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
+ Copyright (c) 2004 Utilitek Systems, Inc.
+
+ derived in part from lm78.c:
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+
+ derived in part from lm85.c:
+ Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
+ Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
+
+ derived in part from w83l785ts.c:
+ Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
+
+ Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+ Copyright (c) 2005 Aspen Systems, Inc.
+
+ Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
+ Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
+
+ Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+ Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+/* LM93 REGISTER ADDRESSES */
+
+/* miscellaneous */
+#define LM93_REG_MFR_ID 0x3e
+#define LM93_REG_VER 0x3f
+#define LM93_REG_STATUS_CONTROL 0xe2
+#define LM93_REG_CONFIG 0xe3
+#define LM93_REG_SLEEP_CONTROL 0xe4
+
+/* alarm values start here */
+#define LM93_REG_HOST_ERROR_1 0x48
+
+/* voltage inputs: in1-in16 (nr => 0-15) */
+#define LM93_REG_IN(nr) (0x56 + (nr))
+#define LM93_REG_IN_MIN(nr) (0x90 + (nr) * 2)
+#define LM93_REG_IN_MAX(nr) (0x91 + (nr) * 2)
+
+/* temperature inputs: temp1-temp4 (nr => 0-3) */
+#define LM93_REG_TEMP(nr) (0x50 + (nr))
+#define LM93_REG_TEMP_MIN(nr) (0x78 + (nr) * 2)
+#define LM93_REG_TEMP_MAX(nr) (0x79 + (nr) * 2)
+
+/* temp[1-4]_auto_boost (nr => 0-3) */
+#define LM93_REG_BOOST(nr) (0x80 + (nr))
+
+/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */
+#define LM93_REG_PROCHOT_CUR(nr) (0x67 + (nr) * 2)
+#define LM93_REG_PROCHOT_AVG(nr) (0x68 + (nr) * 2)
+#define LM93_REG_PROCHOT_MAX(nr) (0xb0 + (nr))
+
+/* fan tach inputs: fan1-fan4 (nr => 0-3) */
+#define LM93_REG_FAN(nr) (0x6e + (nr) * 2)
+#define LM93_REG_FAN_MIN(nr) (0xb4 + (nr) * 2)
+
+/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */
+#define LM93_REG_PWM_CTL(nr,reg) (0xc8 + (reg) + (nr) * 4)
+#define LM93_PWM_CTL1 0x0
+#define LM93_PWM_CTL2 0x1
+#define LM93_PWM_CTL3 0x2
+#define LM93_PWM_CTL4 0x3
+
+/* GPIO input state */
+#define LM93_REG_GPI 0x6b
+
+/* vid inputs: vid1-vid2 (nr => 0-1) */
+#define LM93_REG_VID(nr) (0x6c + (nr))
+
+/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */
+#define LM93_REG_VCCP_LIMIT_OFF(nr) (0xb2 + (nr))
+
+/* temp[1-4]_auto_boost_hyst */
+#define LM93_REG_BOOST_HYST_12 0xc0
+#define LM93_REG_BOOST_HYST_34 0xc1
+#define LM93_REG_BOOST_HYST(nr) (0xc0 + (nr)/2)
+
+/* temp[1-4]_auto_pwm_[min|hyst] */
+#define LM93_REG_PWM_MIN_HYST_12 0xc3
+#define LM93_REG_PWM_MIN_HYST_34 0xc4
+#define LM93_REG_PWM_MIN_HYST(nr) (0xc3 + (nr)/2)
+
+/* prochot_override & prochot_interval */
+#define LM93_REG_PROCHOT_OVERRIDE 0xc6
+#define LM93_REG_PROCHOT_INTERVAL 0xc7
+
+/* temp[1-4]_auto_base (nr => 0-3) */
+#define LM93_REG_TEMP_BASE(nr) (0xd0 + (nr))
+
+/* temp[1-4]_auto_offsets (step => 0-11) */
+#define LM93_REG_TEMP_OFFSET(step) (0xd4 + (step))
+
+/* #PROCHOT & #VRDHOT PWM ramp control */
+#define LM93_REG_PWM_RAMP_CTL 0xbf
+
+/* miscellaneous */
+#define LM93_REG_SFC1 0xbc
+#define LM93_REG_SFC2 0xbd
+#define LM93_REG_GPI_VID_CTL 0xbe
+#define LM93_REG_SF_TACH_TO_PWM 0xe0
+
+/* error masks */
+#define LM93_REG_GPI_ERR_MASK 0xec
+#define LM93_REG_MISC_ERR_MASK 0xed
+
+/* LM93 REGISTER VALUES */
+#define LM93_MFR_ID 0x73
+#define LM93_MFR_ID_PROTOTYPE 0x72
+
+/* SMBus capabilities */
+#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)
+#define LM93_SMBUS_FUNC_MIN (I2C_FUNC_SMBUS_BYTE_DATA | \
+ I2C_FUNC_SMBUS_WORD_DATA)
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm93);
+
+static int disable_block;
+module_param(disable_block, bool, 0);
+MODULE_PARM_DESC(disable_block,
+ "Set to non-zero to disable SMBus block data transactions.");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization.");
+
+static int vccp_limit_type[2] = {0,0};
+module_param_array(vccp_limit_type, int, NULL, 0);
+MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes.");
+
+static int vid_agtl;
+module_param(vid_agtl, int, 0);
+MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds.");
+
+/* Driver data */
+static struct i2c_driver lm93_driver;
+
+/* LM93 BLOCK READ COMMANDS */
+static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = {
+ { 0xf2, 8 },
+ { 0xf3, 8 },
+ { 0xf4, 6 },
+ { 0xf5, 16 },
+ { 0xf6, 4 },
+ { 0xf7, 8 },
+ { 0xf8, 12 },
+ { 0xf9, 32 },
+ { 0xfa, 8 },
+ { 0xfb, 8 },
+ { 0xfc, 16 },
+ { 0xfd, 9 },
+};
+
+/* ALARMS: SYSCTL format described further below
+ REG: 64 bits in 8 registers, as immediately below */
+struct block1_t {
+ u8 host_status_1;
+ u8 host_status_2;
+ u8 host_status_3;
+ u8 host_status_4;
+ u8 p1_prochot_status;
+ u8 p2_prochot_status;
+ u8 gpi_status;
+ u8 fan_status;
+};
+
+/*
+ * Client-specific data
+ */
+struct lm93_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ unsigned long last_updated; /* In jiffies */
+
+ /* client update function */
+ void (*update)(struct lm93_data *, struct i2c_client *);
+
+ char valid; /* !=0 if following fields are valid */
+
+ /* register values, arranged by block read groups */
+ struct block1_t block1;
+
+ /* temp1 - temp4: unfiltered readings
+ temp1 - temp2: filtered readings */
+ u8 block2[6];
+
+ /* vin1 - vin16: readings */
+ u8 block3[16];
+
+ /* prochot1 - prochot2: readings */
+ struct {
+ u8 cur;
+ u8 avg;
+ } block4[2];
+
+ /* fan counts 1-4 => 14-bits, LE, *left* justified */
+ u16 block5[4];
+
+ /* block6 has a lot of data we don't need */
+ struct {
+ u8 min;
+ u8 max;
+ } temp_lim[4];
+
+ /* vin1 - vin16: low and high limits */
+ struct {
+ u8 min;
+ u8 max;
+ } block7[16];
+
+ /* fan count limits 1-4 => same format as block5 */
+ u16 block8[4];
+
+ /* pwm control registers (2 pwms, 4 regs) */
+ u8 block9[2][4];
+
+ /* auto/pwm base temp and offset temp registers */
+ struct {
+ u8 base[4];
+ u8 offset[12];
+ } block10;
+
+ /* master config register */
+ u8 config;
+
+ /* VID1 & VID2 => register format, 6-bits, right justified */
+ u8 vid[2];
+
+ /* prochot1 - prochot2: limits */
+ u8 prochot_max[2];
+
+ /* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */
+ u8 vccp_limits[2];
+
+ /* GPIO input state (register format, i.e. inverted) */
+ u8 gpi;
+
+ /* #PROCHOT override (register format) */
+ u8 prochot_override;
+
+ /* #PROCHOT intervals (register format) */
+ u8 prochot_interval;
+
+ /* Fan Boost Temperatures (register format) */
+ u8 boost[4];
+
+ /* Fan Boost Hysteresis (register format) */
+ u8 boost_hyst[2];
+
+ /* Temperature Zone Min. PWM & Hysteresis (register format) */
+ u8 auto_pwm_min_hyst[2];
+
+ /* #PROCHOT & #VRDHOT PWM Ramp Control */
+ u8 pwm_ramp_ctl;
+
+ /* miscellaneous setup regs */
+ u8 sfc1;
+ u8 sfc2;
+ u8 sf_tach_to_pwm;
+
+ /* The two PWM CTL2 registers can read something other than what was
+ last written for the OVR_DC field (duty cycle override). So, we
+ save the user-commanded value here. */
+ u8 pwm_override[2];
+};
+
+/* VID: mV
+ REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */
+static int LM93_VID_FROM_REG(u8 reg)
+{
+ return vid_from_reg((reg & 0x3f), 100);
+}
+
+/* min, max, and nominal register values, per channel (u8) */
+static const u8 lm93_vin_reg_min[16] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae,
+};
+static const u8 lm93_vin_reg_max[16] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const u8 lm93_vin_reg_nom[16] = {
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
+};
+*/
+
+/* min, max, and nominal voltage readings, per channel (mV)*/
+static const unsigned long lm93_vin_val_min[16] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3000,
+};
+
+static const unsigned long lm93_vin_val_max[16] = {
+ 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600,
+ 4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const unsigned long lm93_vin_val_nom[16] = {
+ 927, 927, 927, 1200, 1500, 1500, 1200, 1200,
+ 3300, 5000, 2500, 1969, 984, 984, 309, 3300,
+};
+*/
+
+static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
+{
+ const long uV_max = lm93_vin_val_max[nr] * 1000;
+ const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+ const long slope = (uV_max - uV_min) /
+ (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+ const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+ return (slope * reg + intercept + 500) / 1000;
+}
+
+/* IN: mV, limits determined by channel nr
+ REG: scaling determined by channel nr */
+static u8 LM93_IN_TO_REG(int nr, unsigned val)
+{
+ /* range limit */
+ const long mV = SENSORS_LIMIT(val,
+ lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+
+ /* try not to lose too much precision here */
+ const long uV = mV * 1000;
+ const long uV_max = lm93_vin_val_max[nr] * 1000;
+ const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+ /* convert */
+ const long slope = (uV_max - uV_min) /
+ (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+ const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+ u8 result = ((uV - intercept + (slope/2)) / slope);
+ result = SENSORS_LIMIT(result,
+ lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+ return result;
+}
+
+/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
+static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
+{
+ const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+ (((reg >> 0 & 0x0f) + 1) * -25000);
+ const long uV_vid = vid * 1000;
+ return (uV_vid + uV_offset + 5000) / 10000;
+}
+
+#define LM93_IN_MIN_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,0,vid)
+#define LM93_IN_MAX_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,1,vid)
+
+/* vid in mV , upper == 0 indicates low limit, otherwise upper limit
+ upper also determines which nibble of the register is returned
+ (the other nibble will be 0x0) */
+static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
+{
+ long uV_offset = vid * 1000 - val * 10000;
+ if (upper) {
+ uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+ return (u8)((uV_offset / 12500 - 1) << 4);
+ } else {
+ uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+ return (u8)((uV_offset / -25000 - 1) << 0);
+ }
+}
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+ REG: 1C/bit, two's complement */
+static int LM93_TEMP_FROM_REG(u8 reg)
+{
+ return (s8)reg * 1000;
+}
+
+#define LM93_TEMP_MIN (-128000)
+#define LM93_TEMP_MAX ( 127000)
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+ REG: 1C/bit, two's complement */
+static u8 LM93_TEMP_TO_REG(int temp)
+{
+ int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+ ntemp += (ntemp<0 ? -500 : 500);
+ return (u8)(ntemp / 1000);
+}
+
+/* Determine 4-bit temperature offset resolution */
+static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
+{
+ /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */
+ return sfc2 & (nr < 2 ? 0x10 : 0x20);
+}
+
+/* This function is common to all 4-bit temperature offsets
+ reg is 4 bits right justified
+ mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
+{
+ return (reg & 0x0f) * (mode ? 5 : 10);
+}
+
+#define LM93_TEMP_OFFSET_MIN ( 0)
+#define LM93_TEMP_OFFSET_MAX0 (150)
+#define LM93_TEMP_OFFSET_MAX1 ( 75)
+
+/* This function is common to all 4-bit temperature offsets
+ returns 4 bits right justified
+ mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
+{
+ int factor = mode ? 5 : 10;
+
+ off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+ mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
+ return (u8)((off + factor/2) / factor);
+}
+
+/* 0 <= nr <= 3 */
+static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode)
+{
+ /* temp1-temp2 (nr=0,1) use lower nibble */
+ if (nr < 2)
+ return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode);
+
+ /* temp3-temp4 (nr=2,3) use upper nibble */
+ else
+ return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode);
+}
+
+/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
+ REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
+ 0 <= nr <= 3 */
+static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode)
+{
+ u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode);
+
+ /* temp1-temp2 (nr=0,1) use lower nibble */
+ if (nr < 2)
+ return (old & 0xf0) | (new & 0x0f);
+
+ /* temp3-temp4 (nr=2,3) use upper nibble */
+ else
+ return (new << 4 & 0xf0) | (old & 0x0f);
+}
+
+static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr,
+ int mode)
+{
+ u8 reg;
+
+ switch (nr) {
+ case 0:
+ reg = data->boost_hyst[0] & 0x0f;
+ break;
+ case 1:
+ reg = data->boost_hyst[0] >> 4 & 0x0f;
+ break;
+ case 2:
+ reg = data->boost_hyst[1] & 0x0f;
+ break;
+ case 3:
+ default:
+ reg = data->boost_hyst[1] >> 4 & 0x0f;
+ break;
+ }
+
+ return LM93_TEMP_FROM_REG(data->boost[nr]) -
+ LM93_TEMP_OFFSET_FROM_REG(reg, mode);
+}
+
+static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst,
+ int nr, int mode)
+{
+ u8 reg = LM93_TEMP_OFFSET_TO_REG(
+ (LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode);
+
+ switch (nr) {
+ case 0:
+ reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f);
+ break;
+ case 1:
+ reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f);
+ break;
+ case 2:
+ reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f);
+ break;
+ case 3:
+ default:
+ reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f);
+ break;
+ }
+
+ return reg;
+}
+
+/* PWM: 0-255 per sensors documentation
+ REG: 0-13 as mapped below... right justified */
+typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t;
+static int lm93_pwm_map[2][16] = {
+ {
+ 0x00, /* 0.00% */ 0x40, /* 25.00% */
+ 0x50, /* 31.25% */ 0x60, /* 37.50% */
+ 0x70, /* 43.75% */ 0x80, /* 50.00% */
+ 0x90, /* 56.25% */ 0xa0, /* 62.50% */
+ 0xb0, /* 68.75% */ 0xc0, /* 75.00% */
+ 0xd0, /* 81.25% */ 0xe0, /* 87.50% */
+ 0xf0, /* 93.75% */ 0xff, /* 100.00% */
+ 0xff, 0xff, /* 14, 15 are reserved and should never occur */
+ },
+ {
+ 0x00, /* 0.00% */ 0x40, /* 25.00% */
+ 0x49, /* 28.57% */ 0x52, /* 32.14% */
+ 0x5b, /* 35.71% */ 0x64, /* 39.29% */
+ 0x6d, /* 42.86% */ 0x76, /* 46.43% */
+ 0x80, /* 50.00% */ 0x89, /* 53.57% */
+ 0x92, /* 57.14% */ 0xb6, /* 71.43% */
+ 0xdb, /* 85.71% */ 0xff, /* 100.00% */
+ 0xff, 0xff, /* 14, 15 are reserved and should never occur */
+ },
+};
+
+static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq)
+{
+ return lm93_pwm_map[freq][reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq)
+{
+ int i;
+ for (i = 0; i < 13; i++)
+ if (pwm <= lm93_pwm_map[freq][i])
+ break;
+
+ /* can fall through with i==13 */
+ return (u8)i;
+}
+
+static int LM93_FAN_FROM_REG(u16 regs)
+{
+ const u16 count = le16_to_cpu(regs) >> 2;
+ return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count;
+}
+
+/*
+ * RPM: (82.5 to 1350000)
+ * REG: 14-bits, LE, *left* justified
+ */
+static u16 LM93_FAN_TO_REG(long rpm)
+{
+ u16 count, regs;
+
+ if (rpm == 0) {
+ count = 0x3fff;
+ } else {
+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+ count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+ }
+
+ regs = count << 2;
+ return cpu_to_le16(regs);
+}
+
+/* PWM FREQ: HZ
+ REG: 0-7 as mapped below */
+static int lm93_pwm_freq_map[8] = {
+ 22500, 96, 84, 72, 60, 48, 36, 12
+};
+
+static int LM93_PWM_FREQ_FROM_REG(u8 reg)
+{
+ return lm93_pwm_freq_map[reg & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_FREQ_TO_REG(int freq)
+{
+ int i;
+ for (i = 7; i > 0; i--)
+ if (freq <= lm93_pwm_freq_map[i])
+ break;
+
+ /* can fall through with i==0 */
+ return (u8)i;
+}
+
+/* TIME: 1/100 seconds
+ * REG: 0-7 as mapped below */
+static int lm93_spinup_time_map[8] = {
+ 0, 10, 25, 40, 70, 100, 200, 400,
+};
+
+static int LM93_SPINUP_TIME_FROM_REG(u8 reg)
+{
+ return lm93_spinup_time_map[reg >> 5 & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_SPINUP_TIME_TO_REG(int time)
+{
+ int i;
+ for (i = 0; i < 7; i++)
+ if (time <= lm93_spinup_time_map[i])
+ break;
+
+ /* can fall through with i==8 */
+ return (u8)i;
+}
+
+#define LM93_RAMP_MIN 0
+#define LM93_RAMP_MAX 75
+
+static int LM93_RAMP_FROM_REG(u8 reg)
+{
+ return (reg & 0x0f) * 5;
+}
+
+/* RAMP: 1/100 seconds
+ REG: 50mS/bit 4-bits right justified */
+static u8 LM93_RAMP_TO_REG(int ramp)
+{
+ ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+ return (u8)((ramp + 2) / 5);
+}
+
+/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
+ * REG: (same) */
+static u8 LM93_PROCHOT_TO_REG(long prochot)
+{
+ prochot = SENSORS_LIMIT(prochot, 0, 255);
+ return (u8)prochot;
+}
+
+/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
+ * REG: 0-9 as mapped below */
+static int lm93_interval_map[10] = {
+ 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200,
+};
+
+static int LM93_INTERVAL_FROM_REG(u8 reg)
+{
+ return lm93_interval_map[reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_INTERVAL_TO_REG(long interval)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ if (interval <= lm93_interval_map[i])
+ break;
+
+ /* can fall through with i==9 */
+ return (u8)i;
+}
+
+/* GPIO: 0-255, GPIO0 is LSB
+ * REG: inverted */
+static unsigned LM93_GPI_FROM_REG(u8 reg)
+{
+ return ~reg & 0xff;
+}
+
+/* alarm bitmask definitions
+ The LM93 has nearly 64 bits of error status... I've pared that down to
+ what I think is a useful subset in order to fit it into 32 bits.
+
+ Especially note that the #VRD_HOT alarms are missing because we provide
+ that information as values in another sysfs file.
+
+ If libsensors is extended to support 64 bit values, this could be revisited.
+*/
+#define LM93_ALARM_IN1 0x00000001
+#define LM93_ALARM_IN2 0x00000002
+#define LM93_ALARM_IN3 0x00000004
+#define LM93_ALARM_IN4 0x00000008
+#define LM93_ALARM_IN5 0x00000010
+#define LM93_ALARM_IN6 0x00000020
+#define LM93_ALARM_IN7 0x00000040
+#define LM93_ALARM_IN8 0x00000080
+#define LM93_ALARM_IN9 0x00000100
+#define LM93_ALARM_IN10 0x00000200
+#define LM93_ALARM_IN11 0x00000400
+#define LM93_ALARM_IN12 0x00000800
+#define LM93_ALARM_IN13 0x00001000
+#define LM93_ALARM_IN14 0x00002000
+#define LM93_ALARM_IN15 0x00004000
+#define LM93_ALARM_IN16 0x00008000
+#define LM93_ALARM_FAN1 0x00010000
+#define LM93_ALARM_FAN2 0x00020000
+#define LM93_ALARM_FAN3 0x00040000
+#define LM93_ALARM_FAN4 0x00080000
+#define LM93_ALARM_PH1_ERR 0x00100000
+#define LM93_ALARM_PH2_ERR 0x00200000
+#define LM93_ALARM_SCSI1_ERR 0x00400000
+#define LM93_ALARM_SCSI2_ERR 0x00800000
+#define LM93_ALARM_DVDDP1_ERR 0x01000000
+#define LM93_ALARM_DVDDP2_ERR 0x02000000
+#define LM93_ALARM_D1_ERR 0x04000000
+#define LM93_ALARM_D2_ERR 0x08000000
+#define LM93_ALARM_TEMP1 0x10000000
+#define LM93_ALARM_TEMP2 0x20000000
+#define LM93_ALARM_TEMP3 0x40000000
+
+static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1)
+{
+ unsigned result;
+ result = b1.host_status_2 & 0x3f;
+
+ if (vccp_limit_type[0])
+ result |= (b1.host_status_4 & 0x10) << 2;
+ else
+ result |= b1.host_status_2 & 0x40;
+
+ if (vccp_limit_type[1])
+ result |= (b1.host_status_4 & 0x20) << 2;
+ else
+ result |= b1.host_status_2 & 0x80;
+
+ result |= b1.host_status_3 << 8;
+ result |= (b1.fan_status & 0x0f) << 16;
+ result |= (b1.p1_prochot_status & 0x80) << 13;
+ result |= (b1.p2_prochot_status & 0x80) << 14;
+ result |= (b1.host_status_4 & 0xfc) << 20;
+ result |= (b1.host_status_1 & 0x07) << 28;
+ return result;
+}
+
+#define MAX_RETRIES 5
+
+static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
+{
+ int value, i;
+
+ /* retry in case of read errors */
+ for (i=1; i<=MAX_RETRIES; i++) {
+ if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) {
+ return value;
+ } else {
+ dev_warn(&client->dev,"lm93: read byte data failed, "
+ "address 0x%02x.\n", reg);
+ mdelay(i + 3);
+ }
+
+ }
+
+ /* <TODO> what to return in case of error? */
+ dev_err(&client->dev,"lm93: All read byte retries failed!!\n");
+ return 0;
+}
+
+static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
+{
+ int result;
+
+ /* <TODO> how to handle write errors? */
+ result = i2c_smbus_write_byte_data(client, reg, value);
+
+ if (result < 0)
+ dev_warn(&client->dev,"lm93: write byte data failed, "
+ "0x%02x at address 0x%02x.\n", value, reg);
+
+ return result;
+}
+
+static u16 lm93_read_word(struct i2c_client *client, u8 reg)
+{
+ int value, i;
+
+ /* retry in case of read errors */
+ for (i=1; i<=MAX_RETRIES; i++) {
+ if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) {
+ return value;
+ } else {
+ dev_warn(&client->dev,"lm93: read word data failed, "
+ "address 0x%02x.\n", reg);
+ mdelay(i + 3);
+ }
+
+ }
+
+ /* <TODO> what to return in case of error? */
+ dev_err(&client->dev,"lm93: All read word retries failed!!\n");
+ return 0;
+}
+
+static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
+{
+ int result;
+
+ /* <TODO> how to handle write errors? */
+ result = i2c_smbus_write_word_data(client, reg, value);
+
+ if (result < 0)
+ dev_warn(&client->dev,"lm93: write word data failed, "
+ "0x%04x at address 0x%02x.\n", value, reg);
+
+ return result;
+}
+
+static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX];
+
+/*
+ read block data into values, retry if not expected length
+ fbn => index to lm93_block_read_cmds table
+ (Fixed Block Number - section 14.5.2 of LM93 datasheet)
+*/
+static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
+{
+ int i, result=0;
+
+ for (i = 1; i <= MAX_RETRIES; i++) {
+ result = i2c_smbus_read_block_data(client,
+ lm93_block_read_cmds[fbn].cmd, lm93_block_buffer);
+
+ if (result == lm93_block_read_cmds[fbn].len) {
+ break;
+ } else {
+ dev_warn(&client->dev,"lm93: block read data failed, "
+ "command 0x%02x.\n",
+ lm93_block_read_cmds[fbn].cmd);
+ mdelay(i + 3);
+ }
+ }
+
+ if (result == lm93_block_read_cmds[fbn].len) {
+ memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len);
+ } else {
+ /* <TODO> what to do in case of error? */
+ }
+}
+
+static struct lm93_data *lm93_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ const unsigned long interval = HZ + (HZ / 2);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + interval) ||
+ !data->valid) {
+
+ data->update(data, client);
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/* update routine for data that has no corresponding SMBus block command */
+static void lm93_update_client_common(struct lm93_data *data,
+ struct i2c_client *client)
+{
+ int i;
+ u8 *ptr;
+
+ /* temp1 - temp4: limits */
+ for (i = 0; i < 4; i++) {
+ data->temp_lim[i].min =
+ lm93_read_byte(client, LM93_REG_TEMP_MIN(i));
+ data->temp_lim[i].max =
+ lm93_read_byte(client, LM93_REG_TEMP_MAX(i));
+ }
+
+ /* config register */
+ data->config = lm93_read_byte(client, LM93_REG_CONFIG);
+
+ /* vid1 - vid2: values */
+ for (i = 0; i < 2; i++)
+ data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i));
+
+ /* prochot1 - prochot2: limits */
+ for (i = 0; i < 2; i++)
+ data->prochot_max[i] = lm93_read_byte(client,
+ LM93_REG_PROCHOT_MAX(i));
+
+ /* vccp1 - vccp2: VID relative limits */
+ for (i = 0; i < 2; i++)
+ data->vccp_limits[i] = lm93_read_byte(client,
+ LM93_REG_VCCP_LIMIT_OFF(i));
+
+ /* GPIO input state */
+ data->gpi = lm93_read_byte(client, LM93_REG_GPI);
+
+ /* #PROCHOT override state */
+ data->prochot_override = lm93_read_byte(client,
+ LM93_REG_PROCHOT_OVERRIDE);
+
+ /* #PROCHOT intervals */
+ data->prochot_interval = lm93_read_byte(client,
+ LM93_REG_PROCHOT_INTERVAL);
+
+ /* Fan Boost Termperature registers */
+ for (i = 0; i < 4; i++)
+ data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i));
+
+ /* Fan Boost Temperature Hyst. registers */
+ data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12);
+ data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34);
+
+ /* Temperature Zone Min. PWM & Hysteresis registers */
+ data->auto_pwm_min_hyst[0] =
+ lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12);
+ data->auto_pwm_min_hyst[1] =
+ lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34);
+
+ /* #PROCHOT & #VRDHOT PWM Ramp Control register */
+ data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+
+ /* misc setup registers */
+ data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1);
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sf_tach_to_pwm = lm93_read_byte(client,
+ LM93_REG_SF_TACH_TO_PWM);
+
+ /* write back alarm values to clear */
+ for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++)
+ lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i));
+}
+
+/* update routine which uses SMBus block data commands */
+static void lm93_update_client_full(struct lm93_data *data,
+ struct i2c_client *client)
+{
+ dev_dbg(&client->dev,"starting device update (block data enabled)\n");
+
+ /* in1 - in16: values & limits */
+ lm93_read_block(client, 3, (u8 *)(data->block3));
+ lm93_read_block(client, 7, (u8 *)(data->block7));
+
+ /* temp1 - temp4: values */
+ lm93_read_block(client, 2, (u8 *)(data->block2));
+
+ /* prochot1 - prochot2: values */
+ lm93_read_block(client, 4, (u8 *)(data->block4));
+
+ /* fan1 - fan4: values & limits */
+ lm93_read_block(client, 5, (u8 *)(data->block5));
+ lm93_read_block(client, 8, (u8 *)(data->block8));
+
+ /* pmw control registers */
+ lm93_read_block(client, 9, (u8 *)(data->block9));
+
+ /* alarm values */
+ lm93_read_block(client, 1, (u8 *)(&data->block1));
+
+ /* auto/pwm registers */
+ lm93_read_block(client, 10, (u8 *)(&data->block10));
+
+ lm93_update_client_common(data, client);
+}
+
+/* update routine which uses SMBus byte/word data commands only */
+static void lm93_update_client_min(struct lm93_data *data,
+ struct i2c_client *client)
+{
+ int i,j;
+ u8 *ptr;
+
+ dev_dbg(&client->dev,"starting device update (block data disabled)\n");
+
+ /* in1 - in16: values & limits */
+ for (i = 0; i < 16; i++) {
+ data->block3[i] =
+ lm93_read_byte(client, LM93_REG_IN(i));
+ data->block7[i].min =
+ lm93_read_byte(client, LM93_REG_IN_MIN(i));
+ data->block7[i].max =
+ lm93_read_byte(client, LM93_REG_IN_MAX(i));
+ }
+
+ /* temp1 - temp4: values */
+ for (i = 0; i < 4; i++) {
+ data->block2[i] =
+ lm93_read_byte(client, LM93_REG_TEMP(i));
+ }
+
+ /* prochot1 - prochot2: values */
+ for (i = 0; i < 2; i++) {
+ data->block4[i].cur =
+ lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i));
+ data->block4[i].avg =
+ lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i));
+ }
+
+ /* fan1 - fan4: values & limits */
+ for (i = 0; i < 4; i++) {
+ data->block5[i] =
+ lm93_read_word(client, LM93_REG_FAN(i));
+ data->block8[i] =
+ lm93_read_word(client, LM93_REG_FAN_MIN(i));
+ }
+
+ /* pwm control registers */
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 4; j++) {
+ data->block9[i][j] =
+ lm93_read_byte(client, LM93_REG_PWM_CTL(i,j));
+ }
+ }
+
+ /* alarm values */
+ for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) {
+ *(ptr + i) =
+ lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i);
+ }
+
+ /* auto/pwm (base temp) registers */
+ for (i = 0; i < 4; i++) {
+ data->block10.base[i] =
+ lm93_read_byte(client, LM93_REG_TEMP_BASE(i));
+ }
+
+ /* auto/pwm (offset temp) registers */
+ for (i = 0; i < 12; i++) {
+ data->block10.offset[i] =
+ lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i));
+ }
+
+ lm93_update_client_common(data, client);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf, "%d\n", LM93_IN_FROM_REG(nr, data->block3[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_in, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_in, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_in, NULL, 12);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_in, NULL, 13);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_in, NULL, 14);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in, NULL, 15);
+
+static ssize_t show_in_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int vccp = nr - 6;
+ long rc, vid;
+
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid);
+ }
+ else {
+ rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); \
+ }
+ return sprintf(buf, "%ld\n", rc); \
+}
+
+static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ int vccp = nr - 6;
+ long vid;
+
+ mutex_lock(&data->update_lock);
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) |
+ LM93_IN_REL_TO_REG(val, 0, vid);
+ lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+ data->vccp_limits[vccp]);
+ }
+ else {
+ data->block7[nr].min = LM93_IN_TO_REG(nr,val);
+ lm93_write_byte(client, LM93_REG_IN_MIN(nr),
+ data->block7[nr].min);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 12);
+static SENSOR_DEVICE_ATTR(in14_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 13);
+static SENSOR_DEVICE_ATTR(in15_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 14);
+static SENSOR_DEVICE_ATTR(in16_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 15);
+
+static ssize_t show_in_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int vccp = nr - 6;
+ long rc, vid;
+
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp],vid);
+ }
+ else {
+ rc = LM93_IN_FROM_REG(nr,data->block7[nr].max); \
+ }
+ return sprintf(buf,"%ld\n",rc); \
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ int vccp = nr - 6;
+ long vid;
+
+ mutex_lock(&data->update_lock);
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) |
+ LM93_IN_REL_TO_REG(val, 1, vid);
+ lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+ data->vccp_limits[vccp]);
+ }
+ else {
+ data->block7[nr].max = LM93_IN_TO_REG(nr,val);
+ lm93_write_byte(client, LM93_REG_IN_MAX(nr),
+ data->block7[nr].max);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 12);
+static SENSOR_DEVICE_ATTR(in14_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 13);
+static SENSOR_DEVICE_ATTR(in15_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 14);
+static SENSOR_DEVICE_ATTR(in16_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 15);
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block2[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].min));
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), data->temp_lim[nr].min);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+ show_temp_min, store_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
+ show_temp_min, store_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
+ show_temp_min, store_temp_min, 2);
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].max));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), data->temp_lim[nr].max);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ show_temp_max, store_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
+ show_temp_max, store_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
+ show_temp_max, store_temp_max, 2);
+
+static ssize_t show_temp_auto_base(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block10.base[nr]));
+}
+
+static ssize_t store_temp_auto_base(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->block10.base[nr] = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), data->block10.base[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_base, S_IWUSR | S_IRUGO,
+ show_temp_auto_base, store_temp_auto_base, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_base, S_IWUSR | S_IRUGO,
+ show_temp_auto_base, store_temp_auto_base, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_base, S_IWUSR | S_IRUGO,
+ show_temp_auto_base, store_temp_auto_base, 2);
+
+static ssize_t show_temp_auto_boost(struct device *dev,
+ struct device_attribute *attr,char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->boost[nr]));
+}
+
+static ssize_t store_temp_auto_boost(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->boost[nr] = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_BOOST(nr), data->boost[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost, store_temp_auto_boost, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost, store_temp_auto_boost, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost, store_temp_auto_boost, 2);
+
+static ssize_t show_temp_auto_boost_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+ return sprintf(buf,"%d\n",
+ LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode));
+}
+
+static ssize_t store_temp_auto_boost_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ /* force 0.5C/bit mode */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+ data->boost_hyst[nr/2] = LM93_AUTO_BOOST_HYST_TO_REG(data, val, nr, 1);
+ lm93_write_byte(client, LM93_REG_BOOST_HYST(nr),
+ data->boost_hyst[nr/2]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost_hyst,
+ store_temp_auto_boost_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost_hyst,
+ store_temp_auto_boost_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost_hyst,
+ store_temp_auto_boost_hyst, 2);
+
+static ssize_t show_temp_auto_offset(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+ int nr = s_attr->index;
+ int ofs = s_attr->nr;
+ struct lm93_data *data = lm93_update_device(dev);
+ int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+ return sprintf(buf,"%d\n",
+ LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs],
+ nr,mode));
+}
+
+static ssize_t store_temp_auto_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+ int nr = s_attr->index;
+ int ofs = s_attr->nr;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ /* force 0.5C/bit mode */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+ data->block10.offset[ofs] = LM93_TEMP_AUTO_OFFSET_TO_REG(
+ data->block10.offset[ofs], val, nr, 1);
+ lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ofs),
+ data->block10.offset[ofs]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset1, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset2, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset3, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset4, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset5, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset6, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset7, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 6, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset8, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 7, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset9, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 8, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset10, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 9, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset11, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 10, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset12, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 11, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset1, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset2, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset3, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset4, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 3, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset5, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset6, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 5, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset7, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 6, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset8, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 7, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset9, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 8, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset10, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 9, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset11, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 10, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset12, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 11, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset1, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset2, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset3, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset4, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 3, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset5, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 4, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset6, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 5, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset7, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 6, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset8, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 7, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset9, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 8, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset10, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 9, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset11, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 10, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset12, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 11, 2);
+
+static ssize_t show_temp_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ u8 reg, ctl4;
+ struct lm93_data *data = lm93_update_device(dev);
+ reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f;
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ return sprintf(buf,"%d\n",LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_temp_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 reg, ctl4;
+
+ mutex_lock(&data->update_lock);
+ reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr));
+ ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+ reg = (reg & 0x0f) |
+ LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ :
+ LM93_PWM_MAP_HI_FREQ) << 4;
+ data->auto_pwm_min_hyst[nr/2] = reg;
+ lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_pwm_min, S_IWUSR | S_IRUGO,
+ show_temp_auto_pwm_min,
+ store_temp_auto_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_pwm_min, S_IWUSR | S_IRUGO,
+ show_temp_auto_pwm_min,
+ store_temp_auto_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_pwm_min, S_IWUSR | S_IRUGO,
+ show_temp_auto_pwm_min,
+ store_temp_auto_pwm_min, 2);
+
+static ssize_t show_temp_auto_offset_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+ return sprintf(buf,"%d\n",LM93_TEMP_OFFSET_FROM_REG(
+ data->auto_pwm_min_hyst[nr/2], mode));
+}
+
+static ssize_t store_temp_auto_offset_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+ /* force 0.5C/bit mode */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+ reg = data->auto_pwm_min_hyst[nr/2];
+ reg = (reg & 0xf0) | (LM93_TEMP_OFFSET_TO_REG(val, 1) & 0x0f);
+ data->auto_pwm_min_hyst[nr/2] = reg;
+ lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_offset_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset_hyst,
+ store_temp_auto_offset_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_offset_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset_hyst,
+ store_temp_auto_offset_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_offset_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset_hyst,
+ store_temp_auto_offset_hyst, 2);
+
+static ssize_t show_fan_input(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
+ int nr = s_attr->index;
+ struct lm93_data *data = lm93_update_device(dev);
+
+ return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block5[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+
+ return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block8[nr]));
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->block8[nr] = LM93_FAN_TO_REG(val);
+ lm93_write_word(client,LM93_REG_FAN_MIN(nr),data->block8[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 3);
+
+/* some tedious bit-twiddling here to deal with the register format:
+
+ data->sf_tach_to_pwm: (tach to pwm mapping bits)
+
+ bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+ T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
+
+ data->sfc2: (enable bits)
+
+ bit | 3 | 2 | 1 | 0
+ T4 T3 T2 T1
+*/
+
+static ssize_t show_fan_smart_tach(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ long rc = 0;
+ int mapping;
+
+ /* extract the relevant mapping */
+ mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03;
+
+ /* if there's a mapping and it's enabled */
+ if (mapping && ((data->sfc2 >> nr) & 0x01))
+ rc = mapping;
+ return sprintf(buf,"%ld\n",rc);
+}
+
+/* helper function - must grab data->update_lock before calling
+ fan is 0-3, indicating fan1-fan4 */
+static void lm93_write_fan_smart_tach(struct i2c_client *client,
+ struct lm93_data *data, int fan, long value)
+{
+ /* insert the new mapping and write it out */
+ data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+ data->sf_tach_to_pwm &= ~(0x3 << fan * 2);
+ data->sf_tach_to_pwm |= value << fan * 2;
+ lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm);
+
+ /* insert the enable bit and write it out */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ if (value)
+ data->sfc2 |= 1 << fan;
+ else
+ data->sfc2 &= ~(1 << fan);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_fan_smart_tach(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ /* sanity test, ignore the write otherwise */
+ if (0 <= val && val <= 2) {
+ /* can't enable if pwm freq is 22.5KHz */
+ if (val) {
+ u8 ctl4 = lm93_read_byte(client,
+ LM93_REG_PWM_CTL(val-1,LM93_PWM_CTL4));
+ if ((ctl4 & 0x07) == 0)
+ val = 0;
+ }
+ lm93_write_fan_smart_tach(client, data, nr, val);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 0);
+static SENSOR_DEVICE_ATTR(fan2_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 1);
+static SENSOR_DEVICE_ATTR(fan3_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 2);
+static SENSOR_DEVICE_ATTR(fan4_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 3);
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl2, ctl4;
+ long rc;
+
+ ctl2 = data->block9[nr][LM93_PWM_CTL2];
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ if (ctl2 & 0x01) /* show user commanded value if enabled */
+ rc = data->pwm_override[nr];
+ else /* show present h/w value if manual pwm disabled */
+ rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ);
+ return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl2, ctl4;
+
+ mutex_lock(&data->update_lock);
+ ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+ ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+ ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val,(ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4;
+ /* save user commanded value */
+ data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4,
+ (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ :
+ LM93_PWM_MAP_HI_FREQ);
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl2;
+ long rc;
+
+ ctl2 = data->block9[nr][LM93_PWM_CTL2];
+ if (ctl2 & 0x01) /* manual override enabled ? */
+ rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1;
+ else
+ rc = 2;
+ return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl2;
+
+ mutex_lock(&data->update_lock);
+ ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+
+ switch (val) {
+ case 0:
+ ctl2 |= 0xF1; /* enable manual override, set PWM to max */
+ break;
+ case 1: ctl2 |= 0x01; /* enable manual override */
+ break;
+ case 2: ctl2 &= ~0x01; /* disable manual override */
+ break;
+ default:
+ mutex_unlock(&data->update_lock);
+ return -EINVAL;
+ }
+
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ show_pwm_enable, store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+ show_pwm_enable, store_pwm_enable, 1);
+
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl4;
+
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ return sprintf(buf,"%d\n",LM93_PWM_FREQ_FROM_REG(ctl4));
+}
+
+/* helper function - must grab data->update_lock before calling
+ pwm is 0-1, indicating pwm1-pwm2
+ this disables smart tach for all tach channels bound to the given pwm */
+static void lm93_disable_fan_smart_tach(struct i2c_client *client,
+ struct lm93_data *data, int pwm)
+{
+ int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+ int mask;
+
+ /* collapse the mapping into a mask of enable bits */
+ mapping = (mapping >> pwm) & 0x55;
+ mask = mapping & 0x01;
+ mask |= (mapping & 0x04) >> 1;
+ mask |= (mapping & 0x10) >> 2;
+ mask |= (mapping & 0x40) >> 3;
+
+ /* disable smart tach according to the mask */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 &= ~mask;
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl4;
+
+ mutex_lock(&data->update_lock);
+ ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+ ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val);
+ data->block9[nr][LM93_PWM_CTL4] = ctl4;
+ /* ctl4 == 0 -> 22.5KHz -> disable smart tach */
+ if (!ctl4)
+ lm93_disable_fan_smart_tach(client, data, nr);
+ lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO,
+ show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IWUSR | S_IRUGO,
+ show_pwm_freq, store_pwm_freq, 1);
+
+static ssize_t show_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->block9[nr][LM93_PWM_CTL1]);
+}
+
+static ssize_t store_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+ lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1),
+ data->block9[nr][LM93_PWM_CTL1]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels, S_IWUSR | S_IRUGO,
+ show_pwm_auto_channels, store_pwm_auto_channels, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels, S_IWUSR | S_IRUGO,
+ show_pwm_auto_channels, store_pwm_auto_channels, 1);
+
+static ssize_t show_pwm_auto_spinup_min(struct device *dev,
+ struct device_attribute *attr,char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl3, ctl4;
+
+ ctl3 = data->block9[nr][LM93_PWM_CTL3];
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ return sprintf(buf,"%d\n",
+ LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_pwm_auto_spinup_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl3, ctl4;
+
+ mutex_lock(&data->update_lock);
+ ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+ ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+ ctl3 = (ctl3 & 0xf0) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ :
+ LM93_PWM_MAP_HI_FREQ);
+ data->block9[nr][LM93_PWM_CTL3] = ctl3;
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_min, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_min,
+ store_pwm_auto_spinup_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_min, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_min,
+ store_pwm_auto_spinup_min, 1);
+
+static ssize_t show_pwm_auto_spinup_time(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_SPINUP_TIME_FROM_REG(
+ data->block9[nr][LM93_PWM_CTL3]));
+}
+
+static ssize_t store_pwm_auto_spinup_time(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl3;
+
+ mutex_lock(&data->update_lock);
+ ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+ ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0);
+ data->block9[nr][LM93_PWM_CTL3] = ctl3;
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_time, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_time,
+ store_pwm_auto_spinup_time, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_time, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_time,
+ store_pwm_auto_spinup_time, 1);
+
+static ssize_t show_pwm_auto_prochot_ramp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f));
+}
+
+static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ramp;
+
+ mutex_lock(&data->update_lock);
+ ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+ ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG(val) << 4 & 0xf0);
+ lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(pwm_auto_prochot_ramp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_prochot_ramp,
+ store_pwm_auto_prochot_ramp);
+
+static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f));
+}
+
+static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ramp;
+
+ mutex_lock(&data->update_lock);
+ ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+ ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG(val) & 0x0f);
+ lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+
+static DEVICE_ATTR(pwm_auto_vrdhot_ramp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_vrdhot_ramp,
+ store_pwm_auto_vrdhot_ramp);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+
+static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->block4[nr].cur);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1, S_IRUGO, show_prochot, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2, S_IRUGO, show_prochot, NULL, 1);
+
+static ssize_t show_prochot_avg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->block4[nr].avg);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_avg, S_IRUGO, show_prochot_avg, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2_avg, S_IRUGO, show_prochot_avg, NULL, 1);
+
+static ssize_t show_prochot_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->prochot_max[nr]);
+}
+
+static ssize_t store_prochot_max(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr),
+ data->prochot_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_max, S_IWUSR | S_IRUGO,
+ show_prochot_max, store_prochot_max, 0);
+static SENSOR_DEVICE_ATTR(prochot2_max, S_IWUSR | S_IRUGO,
+ show_prochot_max, store_prochot_max, 1);
+
+static const u8 prochot_override_mask[] = { 0x80, 0x40 };
+
+static ssize_t show_prochot_override(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ (data->prochot_override & prochot_override_mask[nr]) ? 1 : 0);
+}
+
+static ssize_t store_prochot_override(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->prochot_override |= prochot_override_mask[nr];
+ else
+ data->prochot_override &= (~prochot_override_mask[nr]);
+ lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+ data->prochot_override);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_override, S_IWUSR | S_IRUGO,
+ show_prochot_override, store_prochot_override, 0);
+static SENSOR_DEVICE_ATTR(prochot2_override, S_IWUSR | S_IRUGO,
+ show_prochot_override, store_prochot_override, 1);
+
+static ssize_t show_prochot_interval(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 tmp;
+ if (nr==1)
+ tmp = (data->prochot_interval & 0xf0) >> 4;
+ else
+ tmp = data->prochot_interval & 0x0f;
+ return sprintf(buf,"%d\n",LM93_INTERVAL_FROM_REG(tmp));
+}
+
+static ssize_t store_prochot_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 tmp;
+
+ mutex_lock(&data->update_lock);
+ tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL);
+ if (nr==1)
+ tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4);
+ else
+ tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val);
+ data->prochot_interval = tmp;
+ lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, tmp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_interval, S_IWUSR | S_IRUGO,
+ show_prochot_interval, store_prochot_interval, 0);
+static SENSOR_DEVICE_ATTR(prochot2_interval, S_IWUSR | S_IRUGO,
+ show_prochot_interval, store_prochot_interval, 1);
+
+static ssize_t show_prochot_override_duty_cycle(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->prochot_override & 0x0f);
+}
+
+static ssize_t store_prochot_override_duty_cycle(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->prochot_override = (data->prochot_override & 0xf0) |
+ SENSORS_LIMIT(val, 0, 15);
+ lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+ data->prochot_override);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(prochot_override_duty_cycle, S_IRUGO | S_IWUSR,
+ show_prochot_override_duty_cycle,
+ store_prochot_override_duty_cycle);
+
+static ssize_t show_prochot_short(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",(data->config & 0x10) ? 1 : 0);
+}
+
+static ssize_t store_prochot_short(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->config |= 0x10;
+ else
+ data->config &= ~0x10;
+ lm93_write_byte(client, LM93_REG_CONFIG, data->config);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(prochot_short, S_IRUGO | S_IWUSR,
+ show_prochot_short, store_prochot_short);
+
+static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0);
+static SENSOR_DEVICE_ATTR(vrdhot2, S_IRUGO, show_vrdhot, NULL, 1);
+
+static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_GPI_FROM_REG(data->gpi));
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_ALARMS_FROM_REG(data->block1));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm93_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_in13_input.dev_attr.attr,
+ &sensor_dev_attr_in14_input.dev_attr.attr,
+ &sensor_dev_attr_in15_input.dev_attr.attr,
+ &sensor_dev_attr_in16_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in11_min.dev_attr.attr,
+ &sensor_dev_attr_in12_min.dev_attr.attr,
+ &sensor_dev_attr_in13_min.dev_attr.attr,
+ &sensor_dev_attr_in14_min.dev_attr.attr,
+ &sensor_dev_attr_in15_min.dev_attr.attr,
+ &sensor_dev_attr_in16_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in10_max.dev_attr.attr,
+ &sensor_dev_attr_in11_max.dev_attr.attr,
+ &sensor_dev_attr_in12_max.dev_attr.attr,
+ &sensor_dev_attr_in13_max.dev_attr.attr,
+ &sensor_dev_attr_in14_max.dev_attr.attr,
+ &sensor_dev_attr_in15_max.dev_attr.attr,
+ &sensor_dev_attr_in16_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_base.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_base.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_base.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_boost.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_boost.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_boost.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_boost_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_boost_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_boost_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset1.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset2.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset3.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset4.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset5.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset6.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset7.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset8.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset9.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset10.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset11.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset12.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset1.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset2.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset3.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset4.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset5.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset6.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset7.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset8.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset9.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset10.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset11.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset12.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset1.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset2.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset3.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset4.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset5.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset6.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset7.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset8.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset9.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset10.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset11.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset12.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_fan2_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_fan3_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_fan4_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_spinup_min.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_spinup_min.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_spinup_time.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
+ &dev_attr_pwm_auto_prochot_ramp.attr,
+ &dev_attr_pwm_auto_vrdhot_ramp.attr,
+ &sensor_dev_attr_vid1.dev_attr.attr,
+ &sensor_dev_attr_vid2.dev_attr.attr,
+ &sensor_dev_attr_prochot1.dev_attr.attr,
+ &sensor_dev_attr_prochot2.dev_attr.attr,
+ &sensor_dev_attr_prochot1_avg.dev_attr.attr,
+ &sensor_dev_attr_prochot2_avg.dev_attr.attr,
+ &sensor_dev_attr_prochot1_max.dev_attr.attr,
+ &sensor_dev_attr_prochot2_max.dev_attr.attr,
+ &sensor_dev_attr_prochot1_override.dev_attr.attr,
+ &sensor_dev_attr_prochot2_override.dev_attr.attr,
+ &sensor_dev_attr_prochot1_interval.dev_attr.attr,
+ &sensor_dev_attr_prochot2_interval.dev_attr.attr,
+ &dev_attr_prochot_override_duty_cycle.attr,
+ &dev_attr_prochot_short.attr,
+ &sensor_dev_attr_vrdhot1.dev_attr.attr,
+ &sensor_dev_attr_vrdhot2.dev_attr.attr,
+ &dev_attr_gpio.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static struct attribute_group lm93_attr_grp = {
+ .attrs = lm93_attrs,
+};
+
+static void lm93_init_client(struct i2c_client *client)
+{
+ int i;
+ u8 reg;
+
+ /* configure VID pin input thresholds */
+ reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL);
+ lm93_write_byte(client, LM93_REG_GPI_VID_CTL,
+ reg | (vid_agtl ? 0x03 : 0x00));
+
+ if (init) {
+ /* enable #ALERT pin */
+ reg = lm93_read_byte(client, LM93_REG_CONFIG);
+ lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08);
+
+ /* enable ASF mode for BMC status registers */
+ reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL);
+ lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02);
+
+ /* set sleep state to S0 */
+ lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0);
+
+ /* unmask #VRDHOT and dynamic VCCP (if nec) error events */
+ reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK);
+ reg &= ~0x03;
+ reg &= ~(vccp_limit_type[0] ? 0x10 : 0);
+ reg &= ~(vccp_limit_type[1] ? 0x20 : 0);
+ lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg);
+ }
+
+ /* start monitoring */
+ reg = lm93_read_byte(client, LM93_REG_CONFIG);
+ lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01);
+
+ /* spin until ready */
+ for (i=0; i<20; i++) {
+ msleep(10);
+ if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80)
+ return;
+ }
+
+ dev_warn(&client->dev,"timed out waiting for sensor "
+ "chip to signal ready!\n");
+}
+
+static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct lm93_data *data;
+ struct i2c_client *client;
+
+ int err = -ENODEV, func;
+ void (*update)(struct lm93_data *, struct i2c_client *);
+
+ /* choose update routine based on bus capabilities */
+ func = i2c_get_functionality(adapter);
+ if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
+ (!disable_block) ) {
+ dev_dbg(&adapter->dev,"using SMBus block data transactions\n");
+ update = lm93_update_client_full;
+ } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
+ dev_dbg(&adapter->dev,"disabled SMBus block data "
+ "transactions\n");
+ update = lm93_update_client_min;
+ } else {
+ dev_dbg(&adapter->dev,"detect failed, "
+ "smbus byte and/or word data not supported!\n");
+ goto err_out;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access lm78_{read,write}_value. */
+
+ if ( !(data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL))) {
+ dev_dbg(&adapter->dev,"out of memory!\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &lm93_driver;
+
+ /* detection */
+ if (kind < 0) {
+ int mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
+
+ if (mfr != 0x01) {
+ dev_dbg(&adapter->dev,"detect failed, "
+ "bad manufacturer id 0x%02x!\n", mfr);
+ goto err_free;
+ }
+ }
+
+ if (kind <= 0) {
+ int ver = lm93_read_byte(client, LM93_REG_VER);
+
+ if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) {
+ kind = lm93;
+ } else {
+ dev_dbg(&adapter->dev,"detect failed, "
+ "bad version id 0x%02x!\n", ver);
+ if (kind == 0)
+ dev_dbg(&adapter->dev,
+ "(ignored 'force' parameter)\n");
+ goto err_free;
+ }
+ }
+
+ /* fill in remaining client fields */
+ strlcpy(client->name, "lm93", I2C_NAME_SIZE);
+ dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
+ client->name, i2c_adapter_id(client->adapter),
+ client->addr);
+
+ /* housekeeping */
+ data->valid = 0;
+ data->update = update;
+ mutex_init(&data->update_lock);
+
+ /* tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto err_free;
+
+ /* initialize the chip */
+ lm93_init_client(client);
+
+ err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
+ if (err)
+ goto err_detach;
+
+ /* Register hwmon driver class */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if ( !IS_ERR(data->class_dev))
+ return 0;
+
+ err = PTR_ERR(data->class_dev);
+ dev_err(&client->dev, "error registering hwmon device.\n");
+ sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+err_detach:
+ i2c_detach_client(client);
+err_free:
+ kfree(data);
+err_out:
+ return err;
+}
+
+/* This function is called when:
+ * lm93_driver is inserted (when this module is loaded), for each
+ available adapter
+ * when a new adapter is inserted (and lm93_driver is still present) */
+static int lm93_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, lm93_detect);
+}
+
+static int lm93_detach_client(struct i2c_client *client)
+{
+ struct lm93_data *data = i2c_get_clientdata(client);
+ int err = 0;
+
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+
+ err = i2c_detach_client(client);
+ if (!err)
+ kfree(data);
+ return err;
+}
+
+static struct i2c_driver lm93_driver = {
+ .driver = {
+ .name = "lm93",
+ },
+ .attach_adapter = lm93_attach_adapter,
+ .detach_client = lm93_detach_client,
+};
+
+static int __init lm93_init(void)
+{
+ return i2c_add_driver(&lm93_driver);
+}
+
+static void __exit lm93_exit(void)
+{
+ i2c_del_driver(&lm93_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
+ "Hans J. Koch <hjk@linutronix.de");
+MODULE_DESCRIPTION("LM93 driver");
+MODULE_LICENSE("GPL");
+
+module_init(lm93_init);
+module_exit(lm93_exit);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index c8a21be09d87..f57c75d59a5b 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1,7 +1,7 @@
/*
* pc87360.c - Part of lm_sensors, Linux kernel modules
* for hardware monitoring
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
*
* Copied from smsc47m1.c:
* Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@@ -37,8 +37,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -47,12 +46,10 @@
#include <asm/io.h>
static u8 devid;
-static unsigned short address;
+static struct platform_device *pdev;
static unsigned short extra_isa[3];
static u8 confreg[4];
-enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-
static int init = 1;
module_param(init, int, 0);
MODULE_PARM_DESC(init,
@@ -178,11 +175,11 @@ static inline u8 PWM_TO_REG(int val, int inv)
((val) + 500) / 1000)
/*
- * Client data (each client gets its own)
+ * Device data
*/
struct pc87360_data {
- struct i2c_client client;
+ const char *name;
struct class_device *class_dev;
struct mutex lock;
struct mutex update_lock;
@@ -222,27 +219,28 @@ struct pc87360_data {
* Functions declaration
*/
-static int pc87360_detect(struct i2c_adapter *adapter);
-static int pc87360_detach_client(struct i2c_client *client);
+static int pc87360_probe(struct platform_device *pdev);
+static int __devexit pc87360_remove(struct platform_device *pdev);
static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
u8 reg);
static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
u8 reg, u8 value);
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
+static void pc87360_init_device(struct platform_device *pdev,
+ int use_thermistors);
static struct pc87360_data *pc87360_update_device(struct device *dev);
/*
- * Driver data (common to all clients)
+ * Driver data
*/
-static struct i2c_driver pc87360_driver = {
+static struct platform_driver pc87360_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pc87360",
},
- .attach_adapter = pc87360_detect,
- .detach_client = pc87360_detach_client,
+ .probe = pc87360_probe,
+ .remove = __devexit_p(pc87360_remove),
};
/*
@@ -281,8 +279,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long fan_min = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -347,8 +344,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, con
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -410,8 +406,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -425,8 +420,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -511,8 +505,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@@ -584,8 +577,7 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -599,8 +591,7 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -614,8 +605,7 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -715,8 +705,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -730,8 +719,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -745,8 +733,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -818,6 +805,14 @@ static const struct attribute_group pc8736x_temp_group = {
.attrs = pc8736x_temp_attr_array,
};
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct pc87360_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
/*
* Device detection, registration and update
*/
@@ -912,28 +907,18 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
return 0;
}
-static int pc87360_detect(struct i2c_adapter *adapter)
+static int __devinit pc87360_probe(struct platform_device *pdev)
{
int i;
- struct i2c_client *client;
struct pc87360_data *data;
int err = 0;
const char *name = "pc87360";
int use_thermistors = 0;
- struct device *dev;
+ struct device *dev = &pdev->dev;
if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
return -ENOMEM;
- client = &data->client;
- dev = &client->dev;
- i2c_set_clientdata(client, data);
- client->addr = address;
- mutex_init(&data->lock);
- client->adapter = adapter;
- client->driver = &pc87360_driver;
- client->flags = 0;
-
data->fannr = 2;
data->innr = 0;
data->tempnr = 0;
@@ -960,15 +945,17 @@ static int pc87360_detect(struct i2c_adapter *adapter)
break;
}
- strlcpy(client->name, name, sizeof(client->name));
+ data->name = name;
data->valid = 0;
+ mutex_init(&data->lock);
mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
for (i = 0; i < 3; i++) {
if (((data->address[i] = extra_isa[i]))
&& !request_region(extra_isa[i], PC87360_EXTENT,
pc87360_driver.driver.name)) {
- dev_err(&client->dev, "Region 0x%x-0x%x already "
+ dev_err(dev, "Region 0x%x-0x%x already "
"in use!\n", extra_isa[i],
extra_isa[i]+PC87360_EXTENT-1);
for (i--; i >= 0; i--)
@@ -982,9 +969,6 @@ static int pc87360_detect(struct i2c_adapter *adapter)
if (data->fannr)
data->fan_conf = confreg[0] | (confreg[1] << 8);
- if ((err = i2c_attach_client(client)))
- goto ERROR2;
-
/* Use the correct reference voltage
Unless both the VLM and the TMS logical devices agree to
use an external Vref, the internal one is used. */
@@ -996,7 +980,7 @@ static int pc87360_detect(struct i2c_adapter *adapter)
PC87365_REG_TEMP_CONFIG);
}
data->in_vref = (i&0x02) ? 3025 : 2966;
- dev_dbg(&client->dev, "Using %s reference voltage\n",
+ dev_dbg(dev, "Using %s reference voltage\n",
(i&0x02) ? "external" : "internal");
data->vid_conf = confreg[3];
@@ -1015,18 +999,18 @@ static int pc87360_detect(struct i2c_adapter *adapter)
if (devid == 0xe9 && data->address[1]) /* PC87366 */
use_thermistors = confreg[2] & 0x40;
- pc87360_init_client(client, use_thermistors);
+ pc87360_init_device(pdev, use_thermistors);
}
/* Register all-or-nothing sysfs groups */
if (data->innr &&
- (err = sysfs_create_group(&client->dev.kobj,
+ (err = sysfs_create_group(&dev->kobj,
&pc8736x_vin_group)))
goto ERROR3;
if (data->innr == 14 &&
- (err = sysfs_create_group(&client->dev.kobj,
+ (err = sysfs_create_group(&dev->kobj,
&pc8736x_therm_group)))
goto ERROR3;
@@ -1067,7 +1051,10 @@ static int pc87360_detect(struct i2c_adapter *adapter)
goto ERROR3;
}
- data->class_dev = hwmon_device_register(&client->dev);
+ if ((err = device_create_file(dev, &dev_attr_name)))
+ goto ERROR3;
+
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto ERROR3;
@@ -1075,14 +1062,12 @@ static int pc87360_detect(struct i2c_adapter *adapter)
return 0;
ERROR3:
+ device_remove_file(dev, &dev_attr_name);
/* can still remove groups whose members were added individually */
- sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
- i2c_detach_client(client);
-ERROR2:
+ sysfs_remove_group(&dev->kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&dev->kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
for (i = 0; i < 3; i++) {
if (data->address[i]) {
release_region(data->address[i], PC87360_EXTENT);
@@ -1093,20 +1078,18 @@ ERROR1:
return err;
}
-static int pc87360_detach_client(struct i2c_client *client)
+static int __devexit pc87360_remove(struct platform_device *pdev)
{
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = platform_get_drvdata(pdev);
int i;
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
- if ((i = i2c_detach_client(client)))
- return i;
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group);
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@@ -1144,9 +1127,10 @@ static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
mutex_unlock(&(data->lock));
}
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
+static void pc87360_init_device(struct platform_device *pdev,
+ int use_thermistors)
{
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = platform_get_drvdata(pdev);
int i, nr;
const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
const u8 init_temp[3] = { 2, 2, 1 };
@@ -1155,7 +1139,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
if (init >= 2 && data->innr) {
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE);
- dev_info(&client->dev, "VLM conversion set to "
+ dev_info(&pdev->dev, "VLM conversion set to "
"1s period, 160us delay\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE,
@@ -1169,7 +1153,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
if (!(reg & 0x01)) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling in%d\n", i);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_IN_STATUS,
@@ -1193,7 +1177,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS);
if (!(reg & 0x01)) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i+1);
pc87360_write_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS,
@@ -1210,7 +1194,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP,
(i-11)/2, PC87365_REG_TEMP_STATUS);
if (reg & 0x01) {
- dev_dbg(&client->dev, "Skipping "
+ dev_dbg(&pdev->dev, "Skipping "
"temp%d, pin already in use "
"by temp%d\n", i-7, (i-11)/2);
continue;
@@ -1220,7 +1204,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
if (!(reg & 0x01)) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i-7);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_TEMP_STATUS,
@@ -1234,7 +1218,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG);
if (reg & 0x01) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling monitoring (VLM)\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG,
@@ -1246,7 +1230,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG);
if (reg & 0x01) {
- dev_dbg(&client->dev, "Forcibly enabling "
+ dev_dbg(&pdev->dev, "Forcibly enabling "
"monitoring (TMS)\n");
pc87360_write_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG,
@@ -1268,9 +1252,9 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
}
}
-static void pc87360_autodiv(struct i2c_client *client, int nr)
+static void pc87360_autodiv(struct device *dev, int nr)
{
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
u8 old_min = data->fan_min[nr];
/* Increase clock divider if needed and possible */
@@ -1280,7 +1264,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
data->fan_status[nr] += 0x20;
data->fan_min[nr] >>= 1;
data->fan[nr] >>= 1;
- dev_dbg(&client->dev, "Increasing "
+ dev_dbg(dev, "Increasing "
"clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);
}
@@ -1292,7 +1276,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
data->fan_status[nr] -= 0x20;
data->fan_min[nr] <<= 1;
data->fan[nr] <<= 1;
- dev_dbg(&client->dev, "Decreasing "
+ dev_dbg(dev, "Decreasing "
"clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]),
nr+1);
@@ -1309,14 +1293,13 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
static struct pc87360_data *pc87360_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
u8 i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
- dev_dbg(&client->dev, "Data update\n");
+ dev_dbg(dev, "Data update\n");
/* Fans */
for (i = 0; i < data->fannr; i++) {
@@ -1330,7 +1313,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
LD_FAN, NO_BANK,
PC87360_REG_FAN_MIN(i));
/* Change clock divider if needed */
- pc87360_autodiv(client, i);
+ pc87360_autodiv(dev, i);
/* Clear bits and write new divider */
pc87360_write_value(data, LD_FAN, NO_BANK,
PC87360_REG_FAN_STATUS(i),
@@ -1418,9 +1401,53 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
return data;
}
+static int __init pc87360_device_add(unsigned short address)
+{
+ struct resource res = {
+ .name = "pc87360",
+ .flags = IORESOURCE_IO,
+ };
+ int err, i;
+
+ pdev = platform_device_alloc("pc87360", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "pc87360: Device allocation failed\n");
+ goto exit;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!extra_isa[i])
+ continue;
+ res.start = extra_isa[i];
+ res.end = extra_isa[i] + PC87360_EXTENT - 1;
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "pc87360: Device resource[%d] "
+ "addition failed (%d)\n", i, err);
+ goto exit_device_put;
+ }
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "pc87360: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __init pc87360_init(void)
{
- int i;
+ int err, i;
+ unsigned short address = 0;
if (pc87360_find(0x2e, &devid, extra_isa)
&& pc87360_find(0x4e, &devid, extra_isa)) {
@@ -1443,12 +1470,27 @@ static int __init pc87360_init(void)
return -ENODEV;
}
- return i2c_isa_add_driver(&pc87360_driver);
+ err = platform_driver_register(&pc87360_driver);
+ if (err)
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ err = pc87360_device_add(address);
+ if (err)
+ goto exit_driver;
+
+ return 0;
+
+ exit_driver:
+ platform_driver_unregister(&pc87360_driver);
+ exit:
+ return err;
}
static void __exit pc87360_exit(void)
{
- i2c_isa_del_driver(&pc87360_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&pc87360_driver);
}
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 29354fa26f81..2915bc4ad0d5 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -484,7 +484,6 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
struct resource *res;
int i;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
for (i = 0; i < 8; i++) {
@@ -492,6 +491,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
continue;
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
}
+ platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 3f400263fc0f..92956eb3f3c1 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -54,9 +54,9 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
@@ -72,17 +72,13 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Device address
- Note that we can't determine the ISA address until we have initialized
- our module */
-static unsigned short address;
+static struct platform_device *pdev;
/* Many SIS5595 constants specified below */
/* Length of ISA address segment */
#define SIS5595_EXTENT 8
/* PCI Config Registers */
-#define SIS5595_REVISION_REG 0x08
#define SIS5595_BASE_REG 0x68
#define SIS5595_PIN_REG 0x7A
#define SIS5595_ENABLE_REG 0x7B
@@ -165,7 +161,8 @@ static inline u8 DIV_TO_REG(int val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct sis5595_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
struct class_device *class_dev;
struct mutex lock;
@@ -189,102 +186,88 @@ struct sis5595_data {
static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
-static int sis5595_detect(struct i2c_adapter *adapter);
-static int sis5595_detach_client(struct i2c_client *client);
+static int sis5595_probe(struct platform_device *pdev);
+static int __devexit sis5595_remove(struct platform_device *pdev);
-static int sis5595_read_value(struct i2c_client *client, u8 reg);
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int sis5595_read_value(struct sis5595_data *data, u8 reg);
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
static struct sis5595_data *sis5595_update_device(struct device *dev);
-static void sis5595_init_client(struct i2c_client *client);
+static void sis5595_init_device(struct sis5595_data *data);
-static struct i2c_driver sis5595_driver = {
+static struct platform_driver sis5595_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "sis5595",
},
- .attach_adapter = sis5595_detect,
- .detach_client = sis5595_detach_client,
+ .probe = sis5595_probe,
+ .remove = __devexit_p(sis5595_remove),
};
/* 4 Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
+ sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
+ sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_in_offset(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
- show_in##offset, NULL); \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
show_in_offset(0);
show_in_offset(1);
@@ -307,13 +290,12 @@ static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over = TEMP_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
+ sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
mutex_unlock(&data->update_lock);
return count;
}
@@ -326,13 +308,12 @@ static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst = TEMP_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
+ sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
mutex_unlock(&data->update_lock);
return count;
}
@@ -344,37 +325,47 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
show_temp_hyst, set_temp_hyst);
/* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+ sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
@@ -382,11 +373,12 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long min;
unsigned long val = simple_strtoul(buf, NULL, 10);
int reg;
@@ -394,7 +386,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
mutex_lock(&data->update_lock);
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
- reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
+ reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
switch (val) {
case 1: data->fan_div[nr] = 0; break;
@@ -402,7 +394,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
- dev_err(&client->dev, "fan_div value %ld not "
+ dev_err(dev, "fan_div value %ld not "
"supported. Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -416,55 +408,25 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
break;
}
- sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
+ sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
data->fan_min[nr] =
FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+ sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1);
show_fan_offset(1);
show_fan_offset(2);
-static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
-{
- return set_fan_div(dev, buf, count, 0) ;
-}
-
-static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
-{
- return set_fan_div(dev, buf, count, 1) ;
-}
-static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
- show_fan_1_div, set_fan_1_div);
-static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
- show_fan_2_div, set_fan_2_div);
-
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -473,28 +435,37 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *sis5595_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -503,9 +474,9 @@ static const struct attribute_group sis5595_group = {
};
static struct attribute *sis5595_attributes_opt[] = {
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
@@ -518,68 +489,35 @@ static const struct attribute_group sis5595_group_opt = {
};
/* This is called when the module is loaded */
-static int sis5595_detect(struct i2c_adapter *adapter)
+static int __devinit sis5595_probe(struct platform_device *pdev)
{
int err = 0;
int i;
- struct i2c_client *new_client;
struct sis5595_data *data;
+ struct resource *res;
char val;
- u16 a;
- if (force_addr)
- address = force_addr & ~(SIS5595_EXTENT - 1);
/* Reserve the ISA region */
- if (!request_region(address, SIS5595_EXTENT,
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, SIS5595_EXTENT,
sis5595_driver.driver.name)) {
err = -EBUSY;
goto exit;
}
- if (force_addr) {
- dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
- goto exit_release;
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
- goto exit_release;
- if ((a & ~(SIS5595_EXTENT - 1)) != address)
- /* doesn't work for some chips? */
- goto exit_release;
- }
-
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
- goto exit_release;
- }
- if ((val & 0x80) == 0) {
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
- val | 0x80))
- goto exit_release;
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
- goto exit_release;
- if ((val & 0x80) == 0)
- /* doesn't work for some chips! */
- goto exit_release;
- }
if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit_release;
}
- new_client = &data->client;
- new_client->addr = address;
mutex_init(&data->lock);
- i2c_set_clientdata(new_client, data);
- new_client->adapter = adapter;
- new_client->driver = &sis5595_driver;
- new_client->flags = 0;
+ mutex_init(&data->update_lock);
+ data->addr = res->start;
+ data->name = "sis5595";
+ platform_set_drvdata(pdev, data);
/* Check revision and pin registers to determine whether 4 or 5 voltages */
- pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
+ pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
/* 4 voltages, 1 temp */
data->maxins = 3;
if (data->revision >= REV2MIN) {
@@ -589,47 +527,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
data->maxins = 4;
}
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
-
- data->valid = 0;
- mutex_init(&data->update_lock);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the SIS5595 chip */
- sis5595_init_client(new_client);
+ sis5595_init_device(data);
/* A few vars need to be filled upon startup */
for (i = 0; i < 2; i++) {
- data->fan_min[i] = sis5595_read_value(new_client,
+ data->fan_min[i] = sis5595_read_value(data,
SIS5595_REG_FAN_MIN(i));
}
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
- goto exit_detach;
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
+ goto exit_free;
if (data->maxins == 4) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in4_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_max)))
+ if ((err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_in4_input.dev_attr))
+ || (err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_in4_min.dev_attr))
+ || (err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_in4_max.dev_attr)))
goto exit_remove_files;
} else {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(&pdev->dev,
&dev_attr_temp1_input))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(&pdev->dev,
&dev_attr_temp1_max))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(&pdev->dev,
&dev_attr_temp1_max_hyst)))
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -638,32 +566,26 @@ static int sis5595_detect(struct i2c_adapter *adapter)
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
- sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
-exit_detach:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
exit_free:
kfree(data);
exit_release:
- release_region(address, SIS5595_EXTENT);
+ release_region(res->start, SIS5595_EXTENT);
exit:
return err;
}
-static int sis5595_detach_client(struct i2c_client *client)
+static int __devexit sis5595_remove(struct platform_device *pdev)
{
- struct sis5595_data *data = i2c_get_clientdata(client);
- int err;
+ struct sis5595_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &sis5595_group);
- sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, SIS5595_EXTENT);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
+ release_region(data->addr, SIS5595_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -671,41 +593,37 @@ static int sis5595_detach_client(struct i2c_client *client)
/* ISA access must be locked explicitly. */
-static int sis5595_read_value(struct i2c_client *client, u8 reg)
+static int sis5595_read_value(struct sis5595_data *data, u8 reg)
{
int res;
- struct sis5595_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
- outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
- res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+ res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
mutex_unlock(&data->lock);
return res;
}
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
{
- struct sis5595_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
- outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
- outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+ outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
mutex_unlock(&data->lock);
- return 0;
}
/* Called when we have found a new SIS5595. */
-static void sis5595_init_client(struct i2c_client *client)
+static void __devinit sis5595_init_device(struct sis5595_data *data)
{
- u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
+ u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
if (!(config & 0x01))
- sis5595_write_value(client, SIS5595_REG_CONFIG,
+ sis5595_write_value(data, SIS5595_REG_CONFIG,
(config & 0xf7) | 0x01);
}
static struct sis5595_data *sis5595_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -715,35 +633,35 @@ static struct sis5595_data *sis5595_update_device(struct device *dev)
for (i = 0; i <= data->maxins; i++) {
data->in[i] =
- sis5595_read_value(client, SIS5595_REG_IN(i));
+ sis5595_read_value(data, SIS5595_REG_IN(i));
data->in_min[i] =
- sis5595_read_value(client,
+ sis5595_read_value(data,
SIS5595_REG_IN_MIN(i));
data->in_max[i] =
- sis5595_read_value(client,
+ sis5595_read_value(data,
SIS5595_REG_IN_MAX(i));
}
for (i = 0; i < 2; i++) {
data->fan[i] =
- sis5595_read_value(client, SIS5595_REG_FAN(i));
+ sis5595_read_value(data, SIS5595_REG_FAN(i));
data->fan_min[i] =
- sis5595_read_value(client,
+ sis5595_read_value(data,
SIS5595_REG_FAN_MIN(i));
}
if (data->maxins == 3) {
data->temp =
- sis5595_read_value(client, SIS5595_REG_TEMP);
+ sis5595_read_value(data, SIS5595_REG_TEMP);
data->temp_over =
- sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
+ sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
data->temp_hyst =
- sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
+ sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
}
- i = sis5595_read_value(client, SIS5595_REG_FANDIV);
+ i = sis5595_read_value(data, SIS5595_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms =
- sis5595_read_value(client, SIS5595_REG_ALARM1) |
- (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
+ sis5595_read_value(data, SIS5595_REG_ALARM1) |
+ (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
}
@@ -774,10 +692,50 @@ static int blacklist[] __devinitdata = {
PCI_DEVICE_ID_SI_5598,
0 };
+static int __devinit sis5595_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + SIS5595_EXTENT - 1,
+ .name = "sis5595",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("sis5595", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "sis5595: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "sis5595: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "sis5595: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __devinit sis5595_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- u16 val;
+ u16 address;
+ u8 enable;
int *i;
for (i = blacklist; *i != 0; i++) {
@@ -790,27 +748,68 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
}
}
+ force_addr &= ~(SIS5595_EXTENT - 1);
+ if (force_addr) {
+ dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
+ pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
+ }
+
if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(dev, SIS5595_BASE_REG, &val))
+ pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
+ dev_err(&dev->dev, "Failed to read ISA address\n");
return -ENODEV;
+ }
- address = val & ~(SIS5595_EXTENT - 1);
- if (address == 0 && force_addr == 0) {
+ address &= ~(SIS5595_EXTENT - 1);
+ if (!address) {
dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
+ if (force_addr && address != force_addr) {
+ /* doesn't work for some chips? */
+ dev_err(&dev->dev, "Failed to force ISA address\n");
+ return -ENODEV;
+ }
- s_bridge = pci_dev_get(dev);
- if (i2c_isa_add_driver(&sis5595_driver)) {
- pci_dev_put(s_bridge);
- s_bridge = NULL;
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
+ dev_err(&dev->dev, "Failed to read enable register\n");
+ return -ENODEV;
+ }
+ if (!(enable & 0x80)) {
+ if ((PCIBIOS_SUCCESSFUL !=
+ pci_write_config_byte(dev, SIS5595_ENABLE_REG,
+ enable | 0x80))
+ || (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
+ || (!(enable & 0x80))) {
+ /* doesn't work for some chips! */
+ dev_err(&dev->dev, "Failed to enable HWM device\n");
+ return -ENODEV;
+ }
}
+ if (platform_driver_register(&sis5595_driver)) {
+ dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
+ goto exit;
+ }
+
+ s_bridge = pci_dev_get(dev);
+ /* Sets global pdev as a side effect */
+ if (sis5595_device_add(address))
+ goto exit_unregister;
+
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
return -ENODEV;
+
+exit_unregister:
+ pci_dev_put(dev);
+ platform_driver_unregister(&sis5595_driver);
+exit:
+ return -ENODEV;
}
static struct pci_driver sis5595_pci_driver = {
@@ -828,7 +827,8 @@ static void __exit sm_sis5595_exit(void)
{
pci_unregister_driver(&sis5595_pci_driver);
if (s_bridge != NULL) {
- i2c_isa_del_driver(&sis5595_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&sis5595_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 943abbd95ab5..45266b30ce1d 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -174,6 +174,8 @@ static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
REG: count of 90kHz pulses / revolution */
static int fan_from_reg(u16 reg)
{
+ if (reg == 0 || reg == 0xffff)
+ return 0;
return 90000 * 60 / reg;
}
@@ -333,7 +335,7 @@ static int __init smsc47b397_find(unsigned short *addr)
superio_enter();
id = superio_inb(SUPERIO_REG_DEVID);
- if ((id != 0x6f) && (id != 0x81)) {
+ if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
superio_exit();
return -ENODEV;
}
@@ -346,7 +348,8 @@ 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" : "LPC47B397-NC", *addr, rev);
+ id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
+ "LPC47B397-NC", *addr, rev);
superio_exit();
return 0;
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 1e21c8cc948f..d3181967f167 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -134,7 +134,7 @@ struct smsc47m1_sio_data {
static int smsc47m1_probe(struct platform_device *pdev);
-static int smsc47m1_remove(struct platform_device *pdev);
+static int __devexit smsc47m1_remove(struct platform_device *pdev);
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
int init);
@@ -585,6 +585,8 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_alarms)))
goto error_remove_files;
+ if ((err = device_create_file(dev, &dev_attr_name)))
+ goto error_remove_files;
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
@@ -597,6 +599,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
error_remove_files:
sysfs_remove_group(&dev->kobj, &smsc47m1_group);
error_free:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
error_release:
release_region(res->start, SMSC_EXTENT);
@@ -608,12 +611,12 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
struct smsc47m1_data *data = platform_get_drvdata(pdev);
struct resource *res;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(res->start, SMSC_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -693,15 +696,12 @@ static int __init smsc47m1_device_add(unsigned short address,
goto exit_device_put;
}
- pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
- GFP_KERNEL);
- if (!pdev->dev.platform_data) {
- err = -ENOMEM;
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct smsc47m1_sio_data));
+ if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
- memcpy(pdev->dev.platform_data, sio_data,
- sizeof(struct smsc47m1_sio_data));
err = platform_device_add(pdev);
if (err) {
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index a012f396f354..d3a3ba04cb0f 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -31,6 +31,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/sysfs.h>
+#include <linux/mutex.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -97,7 +98,7 @@ static inline int TEMP_FROM_REG(s8 val)
struct smsc47m192_data {
struct i2c_client client;
struct class_device *class_dev;
- struct semaphore update_lock;
+ struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -164,11 +165,11 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val, nr);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
data->in_min[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -181,11 +182,11 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val, nr);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
data->in_max[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -243,11 +244,11 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_min[nr] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
data->temp_min[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -260,11 +261,11 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_max[nr] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
data->temp_max[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -287,7 +288,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
long val = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_offset[nr] = TEMP_TO_REG(val);
if (nr>1)
i2c_smbus_write_byte_data(client,
@@ -303,7 +304,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
} else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
i2c_smbus_write_byte_data(client,
SMSC47M192_REG_TEMP_OFFSET(nr), 0);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -360,8 +361,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
@@ -411,13 +412,13 @@ static struct attribute *smsc47m192_attributes[] = {
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -531,7 +532,7 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
/* Fill in the remaining client fields and put into the global list */
strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
data->vrm = vid_which_vrm();
- init_MUTEX(&data->update_lock);
+ mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(client)))
@@ -594,7 +595,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
struct smsc47m192_data *data = i2c_get_clientdata(client);
int i, config;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
@@ -645,7 +646,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
data->valid = 1;
}
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return data;
}
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
new file mode 100644
index 000000000000..9395b52d9b99
--- /dev/null
+++ b/drivers/hwmon/thmc50.c
@@ -0,0 +1,440 @@
+/*
+ thmc50.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+ Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
+ Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and
+ Philip Edelbrock <phil@netroedge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+MODULE_LICENSE("GPL");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(thmc50, adm1022);
+I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
+ "to enable 3rd temperature (ADM1022 only)");
+
+/* Many THMC50 constants specified below */
+
+/* The THMC50 registers */
+#define THMC50_REG_CONF 0x40
+#define THMC50_REG_COMPANY_ID 0x3E
+#define THMC50_REG_DIE_CODE 0x3F
+#define THMC50_REG_ANALOG_OUT 0x19
+
+const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
+const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
+const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
+
+#define THMC50_REG_CONF_nFANOFF 0x20
+
+/* Each client has this additional data */
+struct thmc50_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ enum chips type;
+ unsigned long last_updated; /* In jiffies */
+ char has_temp3; /* !=0 if it is ADM1022 in temp3 mode */
+ char valid; /* !=0 if following fields are valid */
+
+ /* Register values */
+ s8 temp_input[3];
+ s8 temp_max[3];
+ s8 temp_min[3];
+ u8 analog_out;
+};
+
+static int thmc50_attach_adapter(struct i2c_adapter *adapter);
+static int thmc50_detach_client(struct i2c_client *client);
+static void thmc50_init_client(struct i2c_client *client);
+static struct thmc50_data *thmc50_update_device(struct device *dev);
+
+static struct i2c_driver thmc50_driver = {
+ .driver = {
+ .name = "thmc50",
+ },
+ .attach_adapter = thmc50_attach_adapter,
+ .detach_client = thmc50_detach_client,
+};
+
+static ssize_t show_analog_out(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct thmc50_data *data = thmc50_update_device(dev);
+ return sprintf(buf, "%d\n", data->analog_out);
+}
+
+static ssize_t set_analog_out(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct thmc50_data *data = i2c_get_clientdata(client);
+ int tmp = simple_strtoul(buf, NULL, 10);
+ int config;
+
+ mutex_lock(&data->update_lock);
+ data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
+ i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
+ data->analog_out);
+
+ config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+ if (data->analog_out == 0)
+ config &= ~THMC50_REG_CONF_nFANOFF;
+ else
+ config |= THMC50_REG_CONF_nFANOFF;
+ i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* There is only one PWM mode = DC */
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0\n");
+}
+
+/* Temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct thmc50_data *data = thmc50_update_device(dev);
+ return sprintf(buf, "%d\n", data->temp_input[nr] * 1000);
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct thmc50_data *data = thmc50_update_device(dev);
+ return sprintf(buf, "%d\n", data->temp_min[nr] * 1000);
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct thmc50_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+ i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
+ data->temp_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct thmc50_data *data = thmc50_update_device(dev);
+ return sprintf(buf, "%d\n", data->temp_max[nr] * 1000);
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct thmc50_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+ i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
+ data->temp_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define temp_reg(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
+ NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+ show_temp_min, set_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, offset - 1);
+
+temp_reg(1);
+temp_reg(2);
+temp_reg(3);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
+ set_analog_out, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
+
+static struct attribute *thmc50_attributes[] = {
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group thmc50_group = {
+ .attrs = thmc50_attributes,
+};
+
+/* for ADM1022 3rd temperature mode */
+static struct attribute *adm1022_attributes[] = {
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adm1022_group = {
+ .attrs = adm1022_attributes,
+};
+
+static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ unsigned company;
+ unsigned revision;
+ unsigned config;
+ struct i2c_client *client;
+ struct thmc50_data *data;
+ struct device *dev;
+ int err = 0;
+ const char *type_name = "";
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_debug("thmc50: detect failed, "
+ "smbus byte data not supported!\n");
+ goto exit;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access thmc50 registers. */
+ if (!(data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL))) {
+ pr_debug("thmc50: detect failed, kzalloc failed!\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &thmc50_driver;
+ dev = &client->dev;
+
+ pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
+ client->addr, i2c_adapter_id(client->adapter));
+
+ /* Now, we do the remaining detection. */
+ company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
+ revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
+ config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+
+ if (kind == 0)
+ kind = thmc50;
+ else if (kind < 0) {
+ err = -ENODEV;
+ if (revision >= 0xc0 && ((config & 0x10) == 0)) {
+ if (company == 0x49) {
+ kind = thmc50;
+ err = 0;
+ } else if (company == 0x41) {
+ kind = adm1022;
+ err = 0;
+ }
+ }
+ }
+ if (err == -ENODEV) {
+ pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
+ goto exit_free;
+ }
+ pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
+ type_name, (revision >> 4) - 0xc, revision & 0xf);
+ data->type = kind;
+
+ if (kind == thmc50)
+ type_name = "thmc50";
+ else if (kind == adm1022) {
+ int id = i2c_adapter_id(client->adapter);
+ int i;
+
+ type_name = "adm1022";
+ data->has_temp3 = (config >> 7) & 1; /* config MSB */
+ for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
+ if (adm1022_temp3[i] == id &&
+ adm1022_temp3[i + 1] == address) {
+ /* enable 2nd remote temp */
+ data->has_temp3 = 1;
+ break;
+ }
+ }
+
+ /* Fill in the remaining client fields & put it into the global list */
+ strlcpy(client->name, type_name, I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ thmc50_init_client(client);
+
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
+ goto exit_detach;
+
+ /* Register ADM1022 sysfs hooks */
+ if (data->type == adm1022)
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &adm1022_group)))
+ goto exit_remove_sysfs_thmc50;
+
+ /* Register a new directory entry with module sensors */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_sysfs;
+ }
+
+ return 0;
+
+exit_remove_sysfs:
+ if (data->type == adm1022)
+ sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+exit_remove_sysfs_thmc50:
+ sysfs_remove_group(&client->dev.kobj, &thmc50_group);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int thmc50_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, thmc50_detect);
+}
+
+static int thmc50_detach_client(struct i2c_client *client)
+{
+ struct thmc50_data *data = i2c_get_clientdata(client);
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &thmc50_group);
+ if (data->type == adm1022)
+ sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
+
+ return 0;
+}
+
+static void thmc50_init_client(struct i2c_client *client)
+{
+ struct thmc50_data *data = i2c_get_clientdata(client);
+ int config;
+
+ data->analog_out = i2c_smbus_read_byte_data(client,
+ THMC50_REG_ANALOG_OUT);
+ /* set up to at least 1 */
+ if (data->analog_out == 0) {
+ data->analog_out = 1;
+ i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
+ data->analog_out);
+ }
+ config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+ config |= 0x1; /* start the chip if it is in standby mode */
+ if (data->has_temp3)
+ config |= 0x80; /* enable 2nd remote temp */
+ i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
+}
+
+static struct thmc50_data *thmc50_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct thmc50_data *data = i2c_get_clientdata(client);
+ int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + timeout)
+ || !data->valid) {
+
+ int temps = data->has_temp3 ? 3 : 2;
+ int i;
+ for (i = 0; i < temps; i++) {
+ data->temp_input[i] = i2c_smbus_read_byte_data(client,
+ THMC50_REG_TEMP[i]);
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ THMC50_REG_TEMP_MAX[i]);
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ THMC50_REG_TEMP_MIN[i]);
+ }
+ data->analog_out =
+ i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static int __init sm_thmc50_init(void)
+{
+ return i2c_add_driver(&thmc50_driver);
+}
+
+static void __exit sm_thmc50_exit(void)
+{
+ i2c_del_driver(&thmc50_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
+MODULE_DESCRIPTION("THMC50 driver");
+
+module_init(sm_thmc50_init);
+module_exit(sm_thmc50_exit);
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 9a440c8cc520..696c8a2e5374 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -34,9 +34,9 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
@@ -51,10 +51,7 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Device address
- Note that we can't determine the ISA address until we have initialized
- our module */
-static unsigned short address;
+static struct platform_device *pdev;
/*
The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -295,7 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct via686a_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
struct class_device *class_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -315,98 +313,85 @@ struct via686a_data {
static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
-static int via686a_detect(struct i2c_adapter *adapter);
-static int via686a_detach_client(struct i2c_client *client);
+static int via686a_probe(struct platform_device *pdev);
+static int __devexit via686a_remove(struct platform_device *pdev);
-static inline int via686a_read_value(struct i2c_client *client, u8 reg)
+static inline int via686a_read_value(struct via686a_data *data, u8 reg)
{
- return (inb_p(client->addr + reg));
+ return inb_p(data->addr + reg);
}
-static inline void via686a_write_value(struct i2c_client *client, u8 reg,
+static inline void via686a_write_value(struct via686a_data *data, u8 reg,
u8 value)
{
- outb_p(value, client->addr + reg);
+ outb_p(value, data->addr + reg);
}
static struct via686a_data *via686a_update_device(struct device *dev);
-static void via686a_init_client(struct i2c_client *client);
+static void via686a_init_device(struct via686a_data *data);
/* following are the sysfs callback functions */
/* 7 voltage sensors */
-static ssize_t show_in(struct device *dev, char *buf, int nr) {
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val, nr);
- via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
+ via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val, nr);
- via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
+ via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_in_offset(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
show_in_offset(0);
show_in_offset(1);
@@ -415,150 +400,128 @@ show_in_offset(3);
show_in_offset(4);
/* 3 temperatures */
-static ssize_t show_temp(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
}
-static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
}
-static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
}
-static ssize_t set_temp_over(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over[nr] = TEMP_TO_REG(val);
- via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
+ via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
data->temp_over[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_temp_hyst(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst[nr] = TEMP_TO_REG(val);
- via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
+ via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
data->temp_hyst[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_temp_offset(offset) \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset - 1); \
-} \
-static ssize_t \
-show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_over(dev, buf, offset - 1); \
-} \
-static ssize_t \
-show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_hyst(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_over(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_hyst(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_over, set_temp_##offset##_over); \
-static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_hyst, set_temp_##offset##_hyst);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_over, set_temp_over, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp_hyst, set_temp_hyst, offset - 1);
show_temp_offset(1);
show_temp_offset(2);
show_temp_offset(3);
/* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n",
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+ via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
int old;
mutex_lock(&data->update_lock);
- old = via686a_read_value(client, VIA686A_REG_FANDIV);
+ old = via686a_read_value(data, VIA686A_REG_FANDIV);
data->fan_div[nr] = DIV_TO_REG(val);
old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
- via686a_write_value(client, VIA686A_REG_FANDIV, old);
+ via686a_write_value(data, VIA686A_REG_FANDIV, old);
mutex_unlock(&data->update_lock);
return count;
}
#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_div(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_div, set_fan_##offset##_div);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1);
show_fan_offset(1);
show_fan_offset(2);
@@ -570,41 +533,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct via686a_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *via686a_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_max.attr,
-
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp3_max.attr,
- &dev_attr_temp1_max_hyst.attr,
- &dev_attr_temp2_max_hyst.attr,
- &dev_attr_temp3_max_hyst.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_div.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -612,58 +584,29 @@ static const struct attribute_group via686a_group = {
.attrs = via686a_attributes,
};
-/* The driver. I choose to use type i2c_driver, as at is identical to both
- smbus_driver and isa_driver, and clients could be of either kind */
-static struct i2c_driver via686a_driver = {
+static struct platform_driver via686a_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "via686a",
},
- .attach_adapter = via686a_detect,
- .detach_client = via686a_detach_client,
+ .probe = via686a_probe,
+ .remove = __devexit_p(via686a_remove),
};
/* This is called when the module is loaded */
-static int via686a_detect(struct i2c_adapter *adapter)
+static int __devinit via686a_probe(struct platform_device *pdev)
{
- struct i2c_client *new_client;
struct via686a_data *data;
- int err = 0;
- const char client_name[] = "via686a";
- u16 val;
-
- /* 8231 requires multiple of 256, we enforce that on 686 as well */
- if (force_addr) {
- address = force_addr & 0xFF00;
- dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
- address);
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
- return -ENODEV;
- }
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
- return -ENODEV;
- if (!(val & 0x0001)) {
- if (force_addr) {
- dev_info(&adapter->dev, "enabling sensors\n");
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
- val | 0x0001))
- return -ENODEV;
- } else {
- dev_warn(&adapter->dev, "sensors disabled - enable "
- "with force_addr=0x%x\n", address);
- return -ENODEV;
- }
- }
+ struct resource *res;
+ int err;
/* Reserve the ISA region */
- if (!request_region(address, VIA686A_EXTENT,
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, VIA686A_EXTENT,
via686a_driver.driver.name)) {
- dev_err(&adapter->dev, "region 0x%x already in use!\n",
- address);
+ dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+ (unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
@@ -672,30 +615,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
goto exit_release;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &via686a_driver;
- new_client->flags = 0;
-
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
-
- data->valid = 0;
+ platform_set_drvdata(pdev, data);
+ data->addr = res->start;
+ data->name = "via686a";
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
/* Initialize the VIA686A chip */
- via686a_init_client(new_client);
+ via686a_init_device(data);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
- goto exit_detach;
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
+ goto exit_free;
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -704,51 +636,46 @@ static int via686a_detect(struct i2c_adapter *adapter)
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
-exit_detach:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
exit_free:
kfree(data);
exit_release:
- release_region(address, VIA686A_EXTENT);
+ release_region(res->start, VIA686A_EXTENT);
return err;
}
-static int via686a_detach_client(struct i2c_client *client)
+static int __devexit via686a_remove(struct platform_device *pdev)
{
- struct via686a_data *data = i2c_get_clientdata(client);
- int err;
+ struct via686a_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &via686a_group);
+ sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, VIA686A_EXTENT);
+ release_region(data->addr, VIA686A_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
-static void via686a_init_client(struct i2c_client *client)
+static void __devinit via686a_init_device(struct via686a_data *data)
{
u8 reg;
/* Start monitoring */
- reg = via686a_read_value(client, VIA686A_REG_CONFIG);
- via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
+ reg = via686a_read_value(data, VIA686A_REG_CONFIG);
+ via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
/* Configure temp interrupt mode for continuous-interrupt operation */
- via686a_write_value(client, VIA686A_REG_TEMP_MODE,
- via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
- !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
+ reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
+ via686a_write_value(data, VIA686A_REG_TEMP_MODE,
+ (reg & ~VIA686A_TEMP_MODE_MASK)
+ | VIA686A_TEMP_MODE_CONTINUOUS);
}
static struct via686a_data *via686a_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+ struct via686a_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -757,27 +684,27 @@ static struct via686a_data *via686a_update_device(struct device *dev)
|| !data->valid) {
for (i = 0; i <= 4; i++) {
data->in[i] =
- via686a_read_value(client, VIA686A_REG_IN(i));
- data->in_min[i] = via686a_read_value(client,
+ via686a_read_value(data, VIA686A_REG_IN(i));
+ data->in_min[i] = via686a_read_value(data,
VIA686A_REG_IN_MIN
(i));
data->in_max[i] =
- via686a_read_value(client, VIA686A_REG_IN_MAX(i));
+ via686a_read_value(data, VIA686A_REG_IN_MAX(i));
}
for (i = 1; i <= 2; i++) {
data->fan[i - 1] =
- via686a_read_value(client, VIA686A_REG_FAN(i));
- data->fan_min[i - 1] = via686a_read_value(client,
+ via686a_read_value(data, VIA686A_REG_FAN(i));
+ data->fan_min[i - 1] = via686a_read_value(data,
VIA686A_REG_FAN_MIN(i));
}
for (i = 0; i <= 2; i++) {
- data->temp[i] = via686a_read_value(client,
+ data->temp[i] = via686a_read_value(data,
VIA686A_REG_TEMP[i]) << 2;
data->temp_over[i] =
- via686a_read_value(client,
+ via686a_read_value(data,
VIA686A_REG_TEMP_OVER[i]);
data->temp_hyst[i] =
- via686a_read_value(client,
+ via686a_read_value(data,
VIA686A_REG_TEMP_HYST[i]);
}
/* add in lower 2 bits
@@ -785,23 +712,23 @@ static struct via686a_data *via686a_update_device(struct device *dev)
temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
*/
- data->temp[0] |= (via686a_read_value(client,
+ data->temp[0] |= (via686a_read_value(data,
VIA686A_REG_TEMP_LOW1)
& 0xc0) >> 6;
data->temp[1] |=
- (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+ (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0x30) >> 4;
data->temp[2] |=
- (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+ (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0xc0) >> 6;
- i = via686a_read_value(client, VIA686A_REG_FANDIV);
+ i = via686a_read_value(data, VIA686A_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms =
- via686a_read_value(client,
+ via686a_read_value(data,
VIA686A_REG_ALARM1) |
- (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
+ (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
}
@@ -818,32 +745,102 @@ static struct pci_device_id via686a_pci_ids[] = {
MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
+static int __devinit via686a_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + VIA686A_EXTENT - 1,
+ .name = "via686a",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("via686a", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "via686a: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "via686a: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "via686a: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __devinit via686a_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- u16 val;
+ u16 address, val;
+ if (force_addr) {
+ address = force_addr & ~(VIA686A_EXTENT - 1);
+ dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
+ return -ENODEV;
+ }
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
return -ENODEV;
address = val & ~(VIA686A_EXTENT - 1);
- if (address == 0 && force_addr == 0) {
+ if (address == 0) {
dev_err(&dev->dev, "base address not set - upgrade BIOS "
"or use force_addr=0xaddr\n");
return -ENODEV;
}
- s_bridge = pci_dev_get(dev);
- if (i2c_isa_add_driver(&via686a_driver)) {
- pci_dev_put(s_bridge);
- s_bridge = NULL;
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
+ return -ENODEV;
+ if (!(val & 0x0001)) {
+ if (!force_addr) {
+ dev_warn(&dev->dev, "Sensors disabled, enable "
+ "with force_addr=0x%x\n", address);
+ return -ENODEV;
+ }
+
+ dev_warn(&dev->dev, "Enabling sensors\n");
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VIA686A_ENABLE_REG,
+ val | 0x0001))
+ return -ENODEV;
}
+ if (platform_driver_register(&via686a_driver))
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ if (via686a_device_add(address))
+ goto exit_unregister;
+
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
+ s_bridge = pci_dev_get(dev);
+ return -ENODEV;
+
+exit_unregister:
+ platform_driver_unregister(&via686a_driver);
+exit:
return -ENODEV;
}
@@ -862,7 +859,8 @@ static void __exit sm_via686a_exit(void)
{
pci_unregister_driver(&via686a_pci_driver);
if (s_bridge != NULL) {
- i2c_isa_del_driver(&via686a_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&via686a_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index a6a4aa0eee16..3e63eaf19041 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -29,8 +29,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -42,10 +41,7 @@ static int force_addr;
module_param(force_addr, int, 0);
MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");
-/* Device address
- Note that we can't determine the ISA address until we have initialized
- our module */
-static unsigned short isa_address;
+static struct platform_device *pdev;
#define VT8231_EXTENT 0x80
#define VT8231_BASE_REG 0x70
@@ -148,7 +144,9 @@ static inline u8 FAN_TO_REG(long rpm, int div)
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
struct vt8231_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
+
struct mutex update_lock;
struct class_device *class_dev;
char valid; /* !=0 if following fields are valid */
@@ -168,20 +166,20 @@ struct vt8231_data {
};
static struct pci_dev *s_bridge;
-static int vt8231_detect(struct i2c_adapter *adapter);
-static int vt8231_detach_client(struct i2c_client *client);
+static int vt8231_probe(struct platform_device *pdev);
+static int __devexit vt8231_remove(struct platform_device *pdev);
static struct vt8231_data *vt8231_update_device(struct device *dev);
-static void vt8231_init_client(struct i2c_client *client);
+static void vt8231_init_device(struct vt8231_data *data);
-static inline int vt8231_read_value(struct i2c_client *client, u8 reg)
+static inline int vt8231_read_value(struct vt8231_data *data, u8 reg)
{
- return inb_p(client->addr + reg);
+ return inb_p(data->addr + reg);
}
-static inline void vt8231_write_value(struct i2c_client *client, u8 reg,
+static inline void vt8231_write_value(struct vt8231_data *data, u8 reg,
u8 value)
{
- outb_p(value, client->addr + reg);
+ outb_p(value, data->addr + reg);
}
/* following are the sysfs callback functions */
@@ -220,13 +218,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
- vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]);
+ vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -236,13 +233,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
- vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]);
+ vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -278,14 +274,13 @@ static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr,
static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
0, 255);
- vt8231_write_value(client, regvoltmin[5], data->in_min[5]);
+ vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -293,14 +288,13 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
0, 255);
- vt8231_write_value(client, regvoltmax[5], data->in_max[5]);
+ vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -348,26 +342,24 @@ static ssize_t show_temp0_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
- vt8231_write_value(client, regtempmax[0], data->temp_max[0]);
+ vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
- vt8231_write_value(client, regtempmin[0], data->temp_min[0]);
+ vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -404,13 +396,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
- vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]);
+ vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -419,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
- vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]);
+ vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -486,13 +476,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+ vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -500,12 +489,11 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
unsigned long val = simple_strtoul(buf, NULL, 10);
int nr = sensor_attr->index;
- int old = vt8231_read_value(client, VT8231_REG_FANDIV);
+ int old = vt8231_read_value(data, VT8231_REG_FANDIV);
long min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
@@ -516,7 +504,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
- dev_err(&client->dev, "fan_div value %ld not supported."
+ dev_err(dev, "fan_div value %ld not supported."
"Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -524,10 +512,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
/* Correct the fan minimum speed */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+ vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
- vt8231_write_value(client, VT8231_REG_FANDIV, old);
+ vt8231_write_value(data, VT8231_REG_FANDIV, old);
mutex_unlock(&data->update_lock);
return count;
}
@@ -551,9 +539,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
struct vt8231_data *data = vt8231_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
-
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct vt8231_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *vt8231_attributes_temps[6][4] = {
{
&dev_attr_temp1_input.attr,
@@ -648,6 +643,7 @@ static struct attribute *vt8231_attributes[] = {
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -655,13 +651,13 @@ static const struct attribute_group vt8231_group = {
.attrs = vt8231_attributes,
};
-static struct i2c_driver vt8231_driver = {
+static struct platform_driver vt8231_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "vt8231",
},
- .attach_adapter = vt8231_detect,
- .detach_client = vt8231_detach_client,
+ .probe = vt8231_probe,
+ .remove = __devexit_p(vt8231_remove),
};
static struct pci_device_id vt8231_pci_ids[] = {
@@ -680,40 +676,18 @@ static struct pci_driver vt8231_pci_driver = {
.probe = vt8231_pci_probe,
};
-int vt8231_detect(struct i2c_adapter *adapter)
+int vt8231_probe(struct platform_device *pdev)
{
- struct i2c_client *client;
+ struct resource *res;
struct vt8231_data *data;
int err = 0, i;
- u16 val;
-
- /* 8231 requires multiple of 256 */
- if (force_addr) {
- isa_address = force_addr & 0xFF00;
- dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
- isa_address);
- if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge,
- VT8231_BASE_REG, isa_address))
- return -ENODEV;
- }
-
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(s_bridge, VT8231_ENABLE_REG, &val))
- return -ENODEV;
-
- if (!(val & 0x0001)) {
- dev_warn(&adapter->dev, "enabling sensors\n");
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, VT8231_ENABLE_REG,
- val | 0x0001))
- return -ENODEV;
- }
/* Reserve the ISA region */
- if (!request_region(isa_address, VT8231_EXTENT,
- vt8231_pci_driver.name)) {
- dev_err(&adapter->dev, "region 0x%x already in use!\n",
- isa_address);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, VT8231_EXTENT,
+ vt8231_driver.driver.name)) {
+ dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+ (unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
@@ -722,33 +696,23 @@ int vt8231_detect(struct i2c_adapter *adapter)
goto exit_release;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = isa_address;
- client->adapter = adapter;
- client->driver = &vt8231_driver;
-
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
+ platform_set_drvdata(pdev, data);
+ data->addr = res->start;
+ data->name = "vt8231";
mutex_init(&data->update_lock);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
- vt8231_init_client(client);
+ vt8231_init_device(data);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
- goto exit_detach;
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group)))
+ goto exit_free;
/* Must update device information to find out the config field */
- data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
+ data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
if (ISTEMP(i, data->uch_config)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
&vt8231_group_temps[i])))
goto exit_remove_files;
}
@@ -756,13 +720,13 @@ int vt8231_detect(struct i2c_adapter *adapter)
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
if (ISVOLT(i, data->uch_config)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
&vt8231_group_volts[i])))
goto exit_remove_files;
}
}
- data->class_dev = hwmon_device_register(&client->dev);
+ data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -771,56 +735,52 @@ int vt8231_detect(struct i2c_adapter *adapter)
exit_remove_files:
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
+
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
- sysfs_remove_group(&client->dev.kobj, &vt8231_group);
-exit_detach:
- i2c_detach_client(client);
exit_free:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
+
exit_release:
- release_region(isa_address, VT8231_EXTENT);
+ release_region(res->start, VT8231_EXTENT);
return err;
}
-static int vt8231_detach_client(struct i2c_client *client)
+static int __devexit vt8231_remove(struct platform_device *pdev)
{
- struct vt8231_data *data = i2c_get_clientdata(client);
- int err, i;
+ struct vt8231_data *data = platform_get_drvdata(pdev);
+ int i;
hwmon_device_unregister(data->class_dev);
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
- sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
- if ((err = i2c_detach_client(client))) {
- return err;
- }
-
- release_region(client->addr, VT8231_EXTENT);
+ release_region(data->addr, VT8231_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
-
return 0;
}
-static void vt8231_init_client(struct i2c_client *client)
+static void vt8231_init_device(struct vt8231_data *data)
{
- vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0);
- vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0);
+ vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0);
+ vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0);
}
static struct vt8231_data *vt8231_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int i;
u16 low;
@@ -830,41 +790,41 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
|| !data->valid) {
for (i = 0; i < 6; i++) {
if (ISVOLT(i, data->uch_config)) {
- data->in[i] = vt8231_read_value(client,
+ data->in[i] = vt8231_read_value(data,
regvolt[i]);
- data->in_min[i] = vt8231_read_value(client,
+ data->in_min[i] = vt8231_read_value(data,
regvoltmin[i]);
- data->in_max[i] = vt8231_read_value(client,
+ data->in_max[i] = vt8231_read_value(data,
regvoltmax[i]);
}
}
for (i = 0; i < 2; i++) {
- data->fan[i] = vt8231_read_value(client,
+ data->fan[i] = vt8231_read_value(data,
VT8231_REG_FAN(i));
- data->fan_min[i] = vt8231_read_value(client,
+ data->fan_min[i] = vt8231_read_value(data,
VT8231_REG_FAN_MIN(i));
}
- low = vt8231_read_value(client, VT8231_REG_TEMP_LOW01);
+ low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01);
low = (low >> 6) | ((low & 0x30) >> 2)
- | (vt8231_read_value(client, VT8231_REG_TEMP_LOW25) << 4);
+ | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4);
for (i = 0; i < 6; i++) {
if (ISTEMP(i, data->uch_config)) {
- data->temp[i] = (vt8231_read_value(client,
+ data->temp[i] = (vt8231_read_value(data,
regtemp[i]) << 2)
| ((low >> (2 * i)) & 0x03);
- data->temp_max[i] = vt8231_read_value(client,
+ data->temp_max[i] = vt8231_read_value(data,
regtempmax[i]);
- data->temp_min[i] = vt8231_read_value(client,
+ data->temp_min[i] = vt8231_read_value(data,
regtempmin[i]);
}
}
- i = vt8231_read_value(client, VT8231_REG_FANDIV);
+ i = vt8231_read_value(data, VT8231_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
- data->alarms = vt8231_read_value(client, VT8231_REG_ALARM1) |
- (vt8231_read_value(client, VT8231_REG_ALARM2) << 8);
+ data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) |
+ (vt8231_read_value(data, VT8231_REG_ALARM2) << 8);
/* Set alarm flags correctly */
if (!data->fan[0] && data->fan_min[0]) {
@@ -888,33 +848,102 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
return data;
}
+static int __devinit vt8231_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + VT8231_EXTENT - 1,
+ .name = "vt8231",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("vt8231", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "vt8231: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "vt8231: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "vt8231: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __devinit vt8231_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- u16 val;
+ u16 address, val;
+ if (force_addr) {
+ address = force_addr & 0xff00;
+ dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
+ address);
+
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
+ return -ENODEV;
+ }
if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG,
&val))
return -ENODEV;
- isa_address = val & ~(VT8231_EXTENT - 1);
- if (isa_address == 0 && force_addr == 0) {
+ address = val & ~(VT8231_EXTENT - 1);
+ if (address == 0) {
dev_err(&dev->dev, "base address not set -\
upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
- s_bridge = pci_dev_get(dev);
+ if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG,
+ &val))
+ return -ENODEV;
- if (i2c_isa_add_driver(&vt8231_driver)) {
- pci_dev_put(s_bridge);
- s_bridge = NULL;
+ if (!(val & 0x0001)) {
+ dev_warn(&dev->dev, "enabling sensors\n");
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VT8231_ENABLE_REG,
+ val | 0x0001))
+ return -ENODEV;
}
+ if (platform_driver_register(&vt8231_driver))
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ if (vt8231_device_add(address))
+ goto exit_unregister;
+
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
+
+ /* We do, however, mark ourselves as using the PCI device to stop it
+ getting unloaded. */
+ s_bridge = pci_dev_get(dev);
+ return -ENODEV;
+
+exit_unregister:
+ platform_driver_unregister(&vt8231_driver);
+exit:
return -ENODEV;
}
@@ -927,7 +956,8 @@ static void __exit sm_vt8231_exit(void)
{
pci_unregister_driver(&vt8231_pci_driver);
if (s_bridge != NULL) {
- i2c_isa_del_driver(&vt8231_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&vt8231_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 30a76404f0af..d9a9ec7dd84a 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -41,41 +41,39 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include "lm75.h"
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
+enum kinds { w83627ehf, w83627dhg };
-/*
- * Super-I/O constants and functions
- */
+/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
+static const char * w83627ehf_device_names[] = {
+ "w83627ehf",
+ "w83627dhg",
+};
+
+#define DRVNAME "w83627ehf"
/*
- * The three following globals are initialized in w83627ehf_find(), before
- * the i2c-isa device is created. Otherwise, they could be stored in
- * w83627ehf_data. This is ugly, but necessary, and when the driver is next
- * updated to become a platform driver, the globals will disappear.
+ * Super-I/O constants and functions
*/
-static int REG; /* The register to read/write */
-static int VAL; /* The value to read/write */
-/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This
- * value is also used in w83627ehf_detect() to export a device name in sysfs
- * (e.g. w83627ehf or w83627dhg) */
-static int w83627ehf_num_in;
#define W83627EHF_LD_HWM 0x0b
#define SIO_REG_LDSEL 0x07 /* Logical device select */
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+#define SIO_REG_VID_CTRL 0xF0 /* VID control */
+#define SIO_REG_VID_DATA 0xF1 /* VID data */
#define SIO_W83627EHF_ID 0x8850
#define SIO_W83627EHG_ID 0x8860
@@ -83,38 +81,38 @@ static int w83627ehf_num_in;
#define SIO_ID_MASK 0xFFF0
static inline void
-superio_outb(int reg, int val)
+superio_outb(int ioreg, int reg, int val)
{
- outb(reg, REG);
- outb(val, VAL);
+ outb(reg, ioreg);
+ outb(val, ioreg + 1);
}
static inline int
-superio_inb(int reg)
+superio_inb(int ioreg, int reg)
{
- outb(reg, REG);
- return inb(VAL);
+ outb(reg, ioreg);
+ return inb(ioreg + 1);
}
static inline void
-superio_select(int ld)
+superio_select(int ioreg, int ld)
{
- outb(SIO_REG_LDSEL, REG);
- outb(ld, VAL);
+ outb(SIO_REG_LDSEL, ioreg);
+ outb(ld, ioreg + 1);
}
static inline void
-superio_enter(void)
+superio_enter(int ioreg)
{
- outb(0x87, REG);
- outb(0x87, REG);
+ outb(0x87, ioreg);
+ outb(0x87, ioreg);
}
static inline void
-superio_exit(void)
+superio_exit(int ioreg)
{
- outb(0x02, REG);
- outb(0x02, VAL);
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
}
/*
@@ -124,8 +122,8 @@ superio_exit(void)
#define IOREGION_ALIGNMENT ~7
#define IOREGION_OFFSET 5
#define IOREGION_LENGTH 2
-#define ADDR_REG_OFFSET 5
-#define DATA_REG_OFFSET 6
+#define ADDR_REG_OFFSET 0
+#define DATA_REG_OFFSET 1
#define W83627EHF_REG_BANK 0x4E
#define W83627EHF_REG_CONFIG 0x40
@@ -255,7 +253,9 @@ static inline u8 in_to_reg(u32 val, u8 nr)
*/
struct w83627ehf_data {
- struct i2c_client client;
+ int addr; /* IO base of hw monitor block */
+ const char *name;
+
struct class_device *class_dev;
struct mutex lock;
@@ -264,6 +264,7 @@ struct w83627ehf_data {
unsigned long last_updated; /* In jiffies */
/* Register values */
+ u8 in_num; /* number of in inputs we have */
u8 in[10]; /* Register value */
u8 in_max[10]; /* Register value */
u8 in_min[10]; /* Register value */
@@ -271,6 +272,7 @@ struct w83627ehf_data {
u8 fan_min[5];
u8 fan_div[5];
u8 has_fan; /* some fan inputs can be disabled */
+ u8 temp_type[3];
s8 temp1;
s8 temp1_max;
s8 temp1_max_hyst;
@@ -288,6 +290,14 @@ struct w83627ehf_data {
u8 fan_min_output[4]; /* minimum fan speed */
u8 fan_stop_time[4];
+
+ u8 vid;
+ u8 vrm;
+};
+
+struct w83627ehf_sio_data {
+ int sioreg;
+ enum kinds kind;
};
static inline int is_word_sized(u16 reg)
@@ -299,160 +309,161 @@ static inline int is_word_sized(u16 reg)
|| (reg & 0x00ff) == 0x55));
}
-/* We assume that the default bank is 0, thus the following two functions do
- nothing for registers which live in bank 0. For others, they respectively
- set the bank register to the correct value (before the register is
- accessed), and back to 0 (afterwards). */
-static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
+/* Registers 0x50-0x5f are banked */
+static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
{
- if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
- outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
+ if ((reg & 0x00f0) == 0x50) {
+ outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+ outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
}
}
-static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
+/* Not strictly necessary, but play it safe for now */
+static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
{
if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
- outb_p(0, client->addr + DATA_REG_OFFSET);
+ outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+ outb_p(0, data->addr + DATA_REG_OFFSET);
}
}
-static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
+static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
int res, word_sized = is_word_sized(reg);
mutex_lock(&data->lock);
- w83627ehf_set_bank(client, reg);
- outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
- res = inb_p(client->addr + DATA_REG_OFFSET);
+ w83627ehf_set_bank(data, reg);
+ outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+ res = inb_p(data->addr + DATA_REG_OFFSET);
if (word_sized) {
outb_p((reg & 0xff) + 1,
- client->addr + ADDR_REG_OFFSET);
- res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
+ data->addr + ADDR_REG_OFFSET);
+ res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
}
- w83627ehf_reset_bank(client, reg);
+ w83627ehf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return res;
}
-static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
int word_sized = is_word_sized(reg);
mutex_lock(&data->lock);
- w83627ehf_set_bank(client, reg);
- outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
+ w83627ehf_set_bank(data, reg);
+ outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
if (word_sized) {
- outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
+ outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
outb_p((reg & 0xff) + 1,
- client->addr + ADDR_REG_OFFSET);
+ data->addr + ADDR_REG_OFFSET);
}
- outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
- w83627ehf_reset_bank(client, reg);
+ outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+ w83627ehf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return 0;
}
/* This function assumes that the caller holds data->update_lock */
-static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
+static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
u8 reg;
switch (nr) {
case 0:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
| ((data->fan_div[0] & 0x03) << 4);
/* fan5 input control bit is write only, compute the value */
reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
+ w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
| ((data->fan_div[0] & 0x04) << 3);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
break;
case 1:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
| ((data->fan_div[1] & 0x03) << 6);
/* fan5 input control bit is write only, compute the value */
reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
+ w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
| ((data->fan_div[1] & 0x04) << 4);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
break;
case 2:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
| ((data->fan_div[2] & 0x03) << 6);
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
+ w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
| ((data->fan_div[2] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
break;
case 3:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
| (data->fan_div[3] & 0x03);
- w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
+ w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
| ((data->fan_div[3] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
break;
case 4:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
| ((data->fan_div[4] & 0x03) << 2)
| ((data->fan_div[4] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
break;
}
}
+static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
+{
+ int i;
+
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+ data->fan_div[0] = (i >> 4) & 0x03;
+ data->fan_div[1] = (i >> 6) & 0x03;
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
+ data->fan_div[2] = (i >> 6) & 0x03;
+ i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+ data->fan_div[0] |= (i >> 3) & 0x04;
+ data->fan_div[1] |= (i >> 4) & 0x04;
+ data->fan_div[2] |= (i >> 5) & 0x04;
+ if (data->has_fan & ((1 << 3) | (1 << 4))) {
+ i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ data->fan_div[3] = i & 0x03;
+ data->fan_div[4] = ((i >> 2) & 0x03)
+ | ((i >> 5) & 0x04);
+ }
+ if (data->has_fan & (1 << 3)) {
+ i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
+ data->fan_div[3] |= (i >> 5) & 0x04;
+ }
+}
+
static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
int i;
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ)
+ if (time_after(jiffies, data->last_updated + HZ + HZ/2)
|| !data->valid) {
/* Fan clock dividers */
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
- data->fan_div[0] = (i >> 4) & 0x03;
- data->fan_div[1] = (i >> 6) & 0x03;
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
- data->fan_div[2] = (i >> 6) & 0x03;
- i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
- data->fan_div[0] |= (i >> 3) & 0x04;
- data->fan_div[1] |= (i >> 4) & 0x04;
- data->fan_div[2] |= (i >> 5) & 0x04;
- if (data->has_fan & ((1 << 3) | (1 << 4))) {
- i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
- data->fan_div[3] = i & 0x03;
- data->fan_div[4] = ((i >> 2) & 0x03)
- | ((i >> 5) & 0x04);
- }
- if (data->has_fan & (1 << 3)) {
- i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
- data->fan_div[3] |= (i >> 5) & 0x04;
- }
+ w83627ehf_update_fan_div(data);
/* Measured voltages and limits */
- for (i = 0; i < w83627ehf_num_in; i++) {
- data->in[i] = w83627ehf_read_value(client,
+ for (i = 0; i < data->in_num; i++) {
+ data->in[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN(i));
- data->in_min[i] = w83627ehf_read_value(client,
+ data->in_min[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN_MIN(i));
- data->in_max[i] = w83627ehf_read_value(client,
+ data->in_max[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN_MAX(i));
}
@@ -461,9 +472,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
if (!(data->has_fan & (1 << i)))
continue;
- data->fan[i] = w83627ehf_read_value(client,
+ data->fan[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN[i]);
- data->fan_min[i] = w83627ehf_read_value(client,
+ data->fan_min[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN_MIN[i]);
/* If we failed to measure the fan speed and clock
@@ -471,16 +482,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
time */
if (data->fan[i] == 0xff
&& data->fan_div[i] < 0x07) {
- dev_dbg(&client->dev, "Increasing fan%d "
+ dev_dbg(dev, "Increasing fan%d "
"clock divider from %u to %u\n",
i + 1, div_from_reg(data->fan_div[i]),
div_from_reg(data->fan_div[i] + 1));
data->fan_div[i]++;
- w83627ehf_write_fan_div(client, i);
+ w83627ehf_write_fan_div(data, i);
/* Preserve min limit if possible */
if (data->fan_min[i] >= 2
&& data->fan_min[i] != 255)
- w83627ehf_write_value(client,
+ w83627ehf_write_value(data,
W83627EHF_REG_FAN_MIN[i],
(data->fan_min[i] /= 2));
}
@@ -489,9 +500,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
for (i = 0; i < 4; i++) {
/* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
if (i != 1) {
- pwmcfg = w83627ehf_read_value(client,
+ pwmcfg = w83627ehf_read_value(data,
W83627EHF_REG_PWM_ENABLE[i]);
- tolerance = w83627ehf_read_value(client,
+ tolerance = w83627ehf_read_value(data,
W83627EHF_REG_TOLERANCE[i]);
}
data->pwm_mode[i] =
@@ -500,14 +511,14 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
data->pwm_enable[i] =
((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
& 3) + 1;
- data->pwm[i] = w83627ehf_read_value(client,
+ data->pwm[i] = w83627ehf_read_value(data,
W83627EHF_REG_PWM[i]);
- data->fan_min_output[i] = w83627ehf_read_value(client,
+ data->fan_min_output[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN_MIN_OUTPUT[i]);
- data->fan_stop_time[i] = w83627ehf_read_value(client,
+ data->fan_stop_time[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN_STOP_TIME[i]);
data->target_temp[i] =
- w83627ehf_read_value(client,
+ w83627ehf_read_value(data,
W83627EHF_REG_TARGET[i]) &
(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
@@ -515,26 +526,26 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
}
/* Measured temperatures and limits */
- data->temp1 = w83627ehf_read_value(client,
+ data->temp1 = w83627ehf_read_value(data,
W83627EHF_REG_TEMP1);
- data->temp1_max = w83627ehf_read_value(client,
+ data->temp1_max = w83627ehf_read_value(data,
W83627EHF_REG_TEMP1_OVER);
- data->temp1_max_hyst = w83627ehf_read_value(client,
+ data->temp1_max_hyst = w83627ehf_read_value(data,
W83627EHF_REG_TEMP1_HYST);
for (i = 0; i < 2; i++) {
- data->temp[i] = w83627ehf_read_value(client,
+ data->temp[i] = w83627ehf_read_value(data,
W83627EHF_REG_TEMP[i]);
- data->temp_max[i] = w83627ehf_read_value(client,
+ data->temp_max[i] = w83627ehf_read_value(data,
W83627EHF_REG_TEMP_OVER[i]);
- data->temp_max_hyst[i] = w83627ehf_read_value(client,
+ data->temp_max_hyst[i] = w83627ehf_read_value(data,
W83627EHF_REG_TEMP_HYST[i]);
}
- data->alarms = w83627ehf_read_value(client,
+ data->alarms = w83627ehf_read_value(data,
W83627EHF_REG_ALARM1) |
- (w83627ehf_read_value(client,
+ (w83627ehf_read_value(data,
W83627EHF_REG_ALARM2) << 8) |
- (w83627ehf_read_value(client,
+ (w83627ehf_read_value(data,
W83627EHF_REG_ALARM3) << 16);
data->last_updated = jiffies;
@@ -567,15 +578,14 @@ static ssize_t \
store_in_##reg (struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->in_##reg[nr] = in_to_reg(val, nr); \
- w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
+ w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
data->in_##reg[nr]); \
mutex_unlock(&data->update_lock); \
return count; \
@@ -673,8 +683,7 @@ static ssize_t
store_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
unsigned int val = simple_strtoul(buf, NULL, 10);
@@ -716,18 +725,25 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
/* Write both the fan clock divider (if it changed) and the new
fan min (unconditionally) */
if (new_div != data->fan_div[nr]) {
- if (new_div > data->fan_div[nr])
- data->fan[nr] >>= (data->fan_div[nr] - new_div);
- else
- data->fan[nr] <<= (new_div - data->fan_div[nr]);
+ /* Preserve the fan speed reading */
+ if (data->fan[nr] != 0xff) {
+ if (new_div > data->fan_div[nr])
+ data->fan[nr] >>= new_div - data->fan_div[nr];
+ else if (data->fan[nr] & 0x80)
+ data->fan[nr] = 0xff;
+ else
+ data->fan[nr] <<= data->fan_div[nr] - new_div;
+ }
dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
nr + 1, div_from_reg(data->fan_div[nr]),
div_from_reg(new_div));
data->fan_div[nr] = new_div;
- w83627ehf_write_fan_div(client, nr);
+ w83627ehf_write_fan_div(data, nr);
+ /* Give the chip time to sample a new speed value */
+ data->last_updated = jiffies;
}
- w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
+ w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
data->fan_min[nr]);
mutex_unlock(&data->update_lock);
@@ -788,13 +804,12 @@ static ssize_t \
store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
- w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
+ w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
data->temp1_##reg); \
mutex_unlock(&data->update_lock); \
return count; \
@@ -822,15 +837,14 @@ static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->reg[nr] = LM75_TEMP_TO_REG(val); \
- w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
+ w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
data->reg[nr]); \
mutex_unlock(&data->update_lock); \
return count; \
@@ -838,6 +852,15 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
store_temp_reg(OVER, temp_max);
store_temp_reg(HYST, temp_max_hyst);
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
static struct sensor_device_attribute sda_temp[] = {
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
@@ -857,6 +880,9 @@ static struct sensor_device_attribute sda_temp[] = {
SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+ SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+ SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+ SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
};
#define show_pwm_reg(reg) \
@@ -877,8 +903,7 @@ static ssize_t
store_pwm_mode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u32 val = simple_strtoul(buf, NULL, 10);
@@ -887,12 +912,12 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
if (val > 1)
return -EINVAL;
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
data->pwm_mode[nr] = val;
reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
if (!val)
reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
- w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
@@ -901,15 +926,14 @@ static ssize_t
store_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
mutex_lock(&data->update_lock);
data->pwm[nr] = val;
- w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
+ w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
mutex_unlock(&data->update_lock);
return count;
}
@@ -918,8 +942,7 @@ static ssize_t
store_pwm_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u32 val = simple_strtoul(buf, NULL, 10);
@@ -928,11 +951,11 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
if (!val || (val > 2)) /* only modes 1 and 2 are supported */
return -EINVAL;
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
data->pwm_enable[nr] = val;
reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
- w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
@@ -955,15 +978,14 @@ static ssize_t
store_target_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
mutex_lock(&data->update_lock);
data->target_temp[nr] = val;
- w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
+ w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
mutex_unlock(&data->update_lock);
return count;
}
@@ -972,8 +994,7 @@ static ssize_t
store_tolerance(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u16 reg;
@@ -981,13 +1002,13 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
data->tolerance[nr] = val;
if (nr == 1)
reg = (reg & 0x0f) | (val << 4);
else
reg = (reg & 0xf0) | val;
- w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
+ w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1058,14 +1079,13 @@ static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{\
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
- w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
mutex_unlock(&data->update_lock); \
return count; \
}
@@ -1087,21 +1107,28 @@ static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
data->pwm_mode[nr]); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
- w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
mutex_unlock(&data->update_lock); \
return count; \
} \
fan_time_functions(fan_stop_time, FAN_STOP_TIME)
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
@@ -1125,8 +1152,16 @@ static struct sensor_device_attribute sda_sf3_arrays[] = {
store_fan_min_output, 2),
};
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
/*
- * Driver and client management
+ * Driver and device management
*/
static void w83627ehf_device_remove_files(struct device *dev)
@@ -1134,12 +1169,13 @@ static void w83627ehf_device_remove_files(struct device *dev)
/* some entries in the following arrays may not have been used in
* device_create_file(), but device_remove_file() will ignore them */
int i;
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
- for (i = 0; i < w83627ehf_num_in; i++) {
+ for (i = 0; i < data->in_num; i++) {
device_remove_file(dev, &sda_in_input[i].dev_attr);
device_remove_file(dev, &sda_in_alarm[i].dev_attr);
device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1160,43 +1196,64 @@ static void w83627ehf_device_remove_files(struct device *dev)
}
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
device_remove_file(dev, &sda_temp[i].dev_attr);
-}
-static struct i2c_driver w83627ehf_driver;
+ device_remove_file(dev, &dev_attr_name);
+ if (data->vid != 0x3f)
+ device_remove_file(dev, &dev_attr_cpu0_vid);
+}
-static void w83627ehf_init_client(struct i2c_client *client)
+/* Get the monitoring functions started */
+static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
{
int i;
- u8 tmp;
+ u8 tmp, diode;
/* Start monitoring is needed */
- tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
+ tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
if (!(tmp & 0x01))
- w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
+ w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
tmp | 0x01);
/* Enable temp2 and temp3 if needed */
for (i = 0; i < 2; i++) {
- tmp = w83627ehf_read_value(client,
+ tmp = w83627ehf_read_value(data,
W83627EHF_REG_TEMP_CONFIG[i]);
if (tmp & 0x01)
- w83627ehf_write_value(client,
+ w83627ehf_write_value(data,
W83627EHF_REG_TEMP_CONFIG[i],
tmp & 0xfe);
}
+
+ /* Enable VBAT monitoring if needed */
+ tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+ if (!(tmp & 0x01))
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
+
+ /* Get thermal sensor types */
+ diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ for (i = 0; i < 3; i++) {
+ if ((tmp & (0x02 << i)))
+ data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
+ else
+ data->temp_type[i] = 4; /* thermistor */
+ }
}
-static int w83627ehf_detect(struct i2c_adapter *adapter)
+static int __devinit w83627ehf_probe(struct platform_device *pdev)
{
- struct i2c_client *client;
+ struct device *dev = &pdev->dev;
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
struct w83627ehf_data *data;
- struct device *dev;
- u8 fan4pin, fan5pin;
+ struct resource *res;
+ u8 fan4pin, fan5pin, en_vrm10;
int i, err = 0;
- if (!request_region(address + IOREGION_OFFSET, IOREGION_LENGTH,
- w83627ehf_driver.driver.name)) {
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
err = -EBUSY;
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start,
+ (unsigned long)res->start + IOREGION_LENGTH - 1);
goto exit;
}
@@ -1205,41 +1262,47 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
goto exit_release;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
+ data->addr = res->start;
mutex_init(&data->lock);
- client->adapter = adapter;
- client->driver = &w83627ehf_driver;
- client->flags = 0;
- dev = &client->dev;
-
- if (w83627ehf_num_in == 9)
- strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE);
- else /* just say ehf. 627EHG is 627EHF in lead-free packaging. */
- strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
-
- data->valid = 0;
mutex_init(&data->update_lock);
+ data->name = w83627ehf_device_names[sio_data->kind];
+ platform_set_drvdata(pdev, data);
- /* Tell the i2c layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
+ data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
/* Initialize the chip */
- w83627ehf_init_client(client);
-
- /* A few vars need to be filled upon startup */
- for (i = 0; i < 5; i++)
- data->fan_min[i] = w83627ehf_read_value(client,
- W83627EHF_REG_FAN_MIN[i]);
+ w83627ehf_init_device(data);
+
+ data->vrm = vid_which_vrm();
+ superio_enter(sio_data->sioreg);
+ /* Set VID input sensibility if needed. In theory the BIOS should
+ have set it, but in practice it's not always the case. */
+ en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10);
+ if ((en_vrm10 & 0x08) && data->vrm != 100) {
+ dev_warn(dev, "Setting VID input voltage to TTL\n");
+ superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+ en_vrm10 & ~0x08);
+ } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
+ dev_warn(dev, "Setting VID input voltage to VRM10\n");
+ superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+ en_vrm10 | 0x08);
+ }
+ /* Read VID value */
+ superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+ if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80)
+ data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;
+ else {
+ dev_info(dev, "VID pins in output mode, CPU VID not "
+ "available\n");
+ data->vid = 0x3f;
+ }
/* fan4 and fan5 share some pins with the GPIO and serial flash */
- superio_enter();
- fan5pin = superio_inb(0x24) & 0x2;
- fan4pin = superio_inb(0x29) & 0x6;
- superio_exit();
+ fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
+ fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
+ superio_exit(sio_data->sioreg);
/* It looks like fan4 and fan5 pins can be alternatively used
as fan on/off switches, but fan5 control is write only :/
@@ -1248,12 +1311,15 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
is not the default. */
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
if ((i & (1 << 2)) && (!fan4pin))
data->has_fan |= (1 << 3);
if (!(i & (1 << 1)) && (!fan5pin))
data->has_fan |= (1 << 4);
+ /* Read fan clock dividers immediately */
+ w83627ehf_update_fan_div(data);
+
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
if ((err = device_create_file(dev,
@@ -1268,7 +1334,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
goto exit_remove;
}
- for (i = 0; i < w83627ehf_num_in; i++)
+ for (i = 0; i < data->in_num; i++)
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|| (err = device_create_file(dev,
&sda_in_alarm[i].dev_attr))
@@ -1308,6 +1374,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
goto exit_remove;
+ err = device_create_file(dev, &dev_attr_name);
+ if (err)
+ goto exit_remove;
+
+ if (data->vid != 0x3f) {
+ err = device_create_file(dev, &dev_attr_cpu0_vid);
+ if (err)
+ goto exit_remove;
+ }
+
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
@@ -1318,95 +1394,172 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
exit_remove:
w83627ehf_device_remove_files(dev);
- i2c_detach_client(client);
-exit_free:
kfree(data);
+ platform_set_drvdata(pdev, NULL);
exit_release:
- release_region(address + IOREGION_OFFSET, IOREGION_LENGTH);
+ release_region(res->start, IOREGION_LENGTH);
exit:
return err;
}
-static int w83627ehf_detach_client(struct i2c_client *client)
+static int __devexit w83627ehf_remove(struct platform_device *pdev)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- int err;
+ struct w83627ehf_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- w83627ehf_device_remove_files(&client->dev);
-
- if ((err = i2c_detach_client(client)))
- return err;
- release_region(client->addr + IOREGION_OFFSET, IOREGION_LENGTH);
+ w83627ehf_device_remove_files(&pdev->dev);
+ release_region(data->addr, IOREGION_LENGTH);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
-static struct i2c_driver w83627ehf_driver = {
+static struct platform_driver w83627ehf_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "w83627ehf",
+ .name = DRVNAME,
},
- .attach_adapter = w83627ehf_detect,
- .detach_client = w83627ehf_detach_client,
+ .probe = w83627ehf_probe,
+ .remove = __devexit_p(w83627ehf_remove),
};
-static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
+/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
+ struct w83627ehf_sio_data *sio_data)
{
+ static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
+ static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
+ static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+
u16 val;
+ const char *sio_name;
- REG = sioaddr;
- VAL = sioaddr + 1;
- superio_enter();
+ superio_enter(sioaddr);
- val = (superio_inb(SIO_REG_DEVID) << 8)
- | superio_inb(SIO_REG_DEVID + 1);
+ val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+ | superio_inb(sioaddr, SIO_REG_DEVID + 1);
switch (val & SIO_ID_MASK) {
- case SIO_W83627DHG_ID:
- w83627ehf_num_in = 9;
- break;
case SIO_W83627EHF_ID:
+ sio_data->kind = w83627ehf;
+ sio_name = sio_name_W83627EHF;
+ break;
case SIO_W83627EHG_ID:
- w83627ehf_num_in = 10;
+ sio_data->kind = w83627ehf;
+ sio_name = sio_name_W83627EHG;
+ break;
+ case SIO_W83627DHG_ID:
+ sio_data->kind = w83627dhg;
+ sio_name = sio_name_W83627DHG;
break;
default:
- printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n",
- val);
- superio_exit();
+ if (val != 0xffff)
+ pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
+ val);
+ superio_exit(sioaddr);
return -ENODEV;
}
- superio_select(W83627EHF_LD_HWM);
- val = (superio_inb(SIO_REG_ADDR) << 8)
- | superio_inb(SIO_REG_ADDR + 1);
+ /* We have a known chip, find the HWM I/O address */
+ superio_select(sioaddr, W83627EHF_LD_HWM);
+ val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+ | superio_inb(sioaddr, SIO_REG_ADDR + 1);
*addr = val & IOREGION_ALIGNMENT;
if (*addr == 0) {
- superio_exit();
+ printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
+ "device with a base I/O port 0.\n");
+ superio_exit(sioaddr);
return -ENODEV;
}
/* Activate logical device if needed */
- val = superio_inb(SIO_REG_ENABLE);
- if (!(val & 0x01))
- superio_outb(SIO_REG_ENABLE, val | 0x01);
+ val = superio_inb(sioaddr, SIO_REG_ENABLE);
+ if (!(val & 0x01)) {
+ printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
+ "Sensor is probably unusable.\n");
+ superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+ }
+
+ superio_exit(sioaddr);
+ pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
+ sio_data->sioreg = sioaddr;
- superio_exit();
return 0;
}
+/* when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the w83627ehf driver. But since we platform_device_alloc(), we
+ * must keep track of the device */
+static struct platform_device *pdev;
+
static int __init sensors_w83627ehf_init(void)
{
- if (w83627ehf_find(0x2e, &address)
- && w83627ehf_find(0x4e, &address))
+ int err;
+ unsigned short address;
+ struct resource res;
+ struct w83627ehf_sio_data sio_data;
+
+ /* initialize sio_data->kind and sio_data->sioreg.
+ *
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+ * w83627ehf hardware monitor, and call probe() */
+ if (w83627ehf_find(0x2e, &address, &sio_data) &&
+ w83627ehf_find(0x4e, &address, &sio_data))
return -ENODEV;
- return i2c_isa_add_driver(&w83627ehf_driver);
+ err = platform_driver_register(&w83627ehf_driver);
+ if (err)
+ goto exit;
+
+ if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit_unregister;
+ }
+
+ err = platform_device_add_data(pdev, &sio_data,
+ sizeof(struct w83627ehf_sio_data));
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+
+ memset(&res, 0, sizeof(res));
+ res.name = DRVNAME;
+ res.start = address + IOREGION_OFFSET;
+ res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+ res.flags = IORESOURCE_IO;
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ /* platform_device_add calls probe() */
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit_unregister:
+ platform_driver_unregister(&w83627ehf_driver);
+exit:
+ return err;
}
static void __exit sensors_w83627ehf_exit(void)
{
- i2c_isa_del_driver(&w83627ehf_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&w83627ehf_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 12cb40a975de..7a4a15f4bf8b 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -220,6 +220,18 @@ static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
+#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
+
+#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
+
+static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
+ W83637HF_REG_PWM_FREQ2,
+ W83637HF_REG_PWM_FREQ3 };
+
+#define W83627HF_BASE_PWM_FREQ 46870
+
#define W83781D_REG_I2C_ADDR 0x48
#define W83781D_REG_I2C_SUBADDR 0x4A
@@ -267,6 +279,49 @@ static int TEMP_FROM_REG(u8 reg)
#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
+{
+ unsigned long freq;
+ freq = W83627HF_BASE_PWM_FREQ >> reg;
+ return freq;
+}
+static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
+{
+ u8 i;
+ /* Only 5 dividers (1 2 4 8 16)
+ Search for the nearest available frequency */
+ for (i = 0; i < 4; i++) {
+ if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
+ (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
+ break;
+ }
+ return i;
+}
+
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+ /* Clock bit 8 -> 180 kHz or 24 MHz */
+ unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
+
+ reg &= 0x7f;
+ /* This should not happen but anyway... */
+ if (reg == 0)
+ reg++;
+ return (clock / (reg << 8));
+}
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+ /* Minimum divider value is 0x01 and maximum is 0x7F */
+ if (val >= 93750) /* The highest we can do */
+ return 0x01;
+ if (val >= 720) /* Use 24 MHz clock */
+ return (24000000UL / (val << 8));
+ if (val < 6) /* The lowest we can do */
+ return 0xFF;
+ else /* Use 180 kHz clock */
+ return (0x80 | (180000UL / (val << 8)));
+}
+
#define BEEP_MASK_FROM_REG(val) (val)
#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
@@ -316,6 +371,7 @@ struct w83627hf_data {
u32 beep_mask; /* Register encoding, combined */
u8 beep_enable; /* Boolean */
u8 pwm[3]; /* Register value */
+ u8 pwm_freq[3]; /* Register value */
u16 sens[3]; /* 782D/783S only.
1 = pentium diode; 2 = 3904 diode;
3000-5000 = thermistor beta.
@@ -331,7 +387,7 @@ struct w83627hf_sio_data {
static int w83627hf_probe(struct platform_device *pdev);
-static int w83627hf_remove(struct platform_device *pdev);
+static int __devexit w83627hf_remove(struct platform_device *pdev);
static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
@@ -852,6 +908,64 @@ sysfs_pwm(2);
sysfs_pwm(3);
static ssize_t
+show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+{
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ if (data->type == w83627hf)
+ return sprintf(buf, "%ld\n",
+ pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+ else
+ return sprintf(buf, "%ld\n",
+ pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+}
+
+static ssize_t
+store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ static const u8 mask[]={0xF8, 0x8F};
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+
+ if (data->type == w83627hf) {
+ data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+ w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
+ (data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+ (w83627hf_read_value(data,
+ W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+ } else {
+ data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
+ w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
+ data->pwm_freq[nr - 1]);
+ }
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define sysfs_pwm_freq(offset) \
+static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return show_pwm_freq_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_pwm_freq_##offset(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ return store_pwm_freq_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
+ show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
+
+sysfs_pwm_freq(1);
+sysfs_pwm_freq(2);
+sysfs_pwm_freq(3);
+
+static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
struct w83627hf_data *data = w83627hf_update_device(dev);
@@ -1077,6 +1191,9 @@ static struct attribute *w83627hf_attributes_opt[] = {
&dev_attr_pwm3.attr,
+ &dev_attr_pwm1_freq.attr,
+ &dev_attr_pwm2_freq.attr,
+ &dev_attr_pwm3_freq.attr,
NULL
};
@@ -1139,7 +1256,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
|| (err = device_create_file(dev, &dev_attr_in5_max))
|| (err = device_create_file(dev, &dev_attr_in6_input))
|| (err = device_create_file(dev, &dev_attr_in6_min))
- || (err = device_create_file(dev, &dev_attr_in6_max)))
+ || (err = device_create_file(dev, &dev_attr_in6_max))
+ || (err = device_create_file(dev, &dev_attr_pwm1_freq))
+ || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
goto ERROR4;
if (data->type != w83697hf)
@@ -1169,6 +1288,12 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_pwm3)))
goto ERROR4;
+ if (data->type == w83637hf || data->type == w83687thf)
+ if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
+ || (err = device_create_file(dev, &dev_attr_pwm2_freq))
+ || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+ goto ERROR4;
+
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
@@ -1181,6 +1306,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
sysfs_remove_group(&dev->kobj, &w83627hf_group);
sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
ERROR3:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
ERROR1:
release_region(res->start, WINB_REGION_SIZE);
@@ -1193,11 +1319,11 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
struct w83627hf_data *data = platform_get_drvdata(pdev);
struct resource *res;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1472,6 +1598,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
(data->type == w83627hf || data->type == w83697hf))
break;
}
+ if (data->type == w83627hf) {
+ u8 tmp = w83627hf_read_value(data,
+ W83627HF_REG_PWM_FREQ);
+ data->pwm_freq[0] = tmp & 0x07;
+ data->pwm_freq[1] = (tmp >> 4) & 0x07;
+ } else if (data->type != w83627thf) {
+ for (i = 1; i <= 3; i++) {
+ data->pwm_freq[i - 1] =
+ w83627hf_read_value(data,
+ W83637HF_REG_PWM_FREQ[i - 1]);
+ if (i == 2 && (data->type == w83697hf))
+ break;
+ }
+ }
data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
data->temp_max =
@@ -1548,15 +1688,12 @@ static int __init w83627hf_device_add(unsigned short address,
goto exit_device_put;
}
- pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
- GFP_KERNEL);
- if (!pdev->dev.platform_data) {
- err = -ENOMEM;
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct w83627hf_sio_data));
+ if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
- memcpy(pdev->dev.platform_data, sio_data,
- sizeof(struct w83627hf_sio_data));
err = platform_device_add(pdev);
if (err) {
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index f85b48fea1c4..dcc941a5aaff 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -740,9 +740,9 @@ store_sensor(struct device *dev, struct device_attribute *da,
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
show_sensor, store_sensor, 0);
static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
- show_sensor, store_sensor, 0);
+ show_sensor, store_sensor, 1);
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
- show_sensor, store_sensor, 0);
+ show_sensor, store_sensor, 2);
/* I2C devices get this name attribute automatically, but for ISA devices
we must create it by ourselves. */
@@ -1746,7 +1746,7 @@ w83781d_isa_device_add(unsigned short address)
{
struct resource res = {
.start = address,
- .end = address + W83781D_EXTENT,
+ .end = address + W83781D_EXTENT - 1,
.name = "w83781d",
.flags = IORESOURCE_IO,
};
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 8a5f5825bb72..7f0a0a62cf60 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -357,13 +357,29 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
return wrcount;
}
+static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: sda is high */
+ if (is_ack) /* send ack */
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timeout */
+ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
+ return -ETIMEDOUT;
+ }
+ scllo(adap);
+ return 0;
+}
+
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int inval;
int rdcount=0; /* counts bytes read */
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
unsigned char *temp = msg->buf;
int count = msg->len;
+ const unsigned flags = msg->flags;
while (count > 0) {
inval = i2c_inb(i2c_adap);
@@ -377,28 +393,12 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
temp++;
count--;
- if (msg->flags & I2C_M_NO_RD_ACK) {
- bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n",
- inval);
- continue;
- }
-
- /* assert: sda is high */
- if (count) /* send ack */
- setsda(adap, 0);
- udelay((adap->udelay + 1) / 2);
- bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval,
- count ? "A" : "NA");
- if (sclhi(adap)<0) { /* timeout */
- dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n");
- return -ETIMEDOUT;
- };
- scllo(adap);
-
/* Some SMBus transactions require that we receive the
transaction length as the first read byte. */
- if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) {
+ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+ if (!(flags & I2C_M_NO_RD_ACK))
+ acknak(i2c_adap, 0);
dev_err(&i2c_adap->dev, "readbytes: invalid "
"block length (%d)\n", inval);
return -EREMOTEIO;
@@ -409,6 +409,18 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
count += inval;
msg->len += inval;
}
+
+ bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+ inval,
+ (flags & I2C_M_NO_RD_ACK)
+ ? "(no ack/nak)"
+ : (count ? "A" : "NA"));
+
+ if (!(flags & I2C_M_NO_RD_ACK)) {
+ inval = acknak(i2c_adap, count);
+ if (inval < 0)
+ return inval;
+ }
}
return rdcount;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 1c77e14480dc..9f3a4cd0b07f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -92,9 +92,9 @@ config I2C_AU1550
config I2C_BLACKFIN_TWI
tristate "Blackfin TWI I2C support"
- depends on BF534 || BF536 || BF537
+ depends on BF534 || BF536 || BF537 || BF54x
help
- This is the TWI I2C device driver for Blackfin 534/536/537.
+ This is the TWI I2C device driver for Blackfin 534/536/537/54x.
This driver can also be built as a module. If so, the module
will be called i2c-bfin-twi.
@@ -208,6 +208,7 @@ config I2C_PIIX4
ATI IXP400
ATI SB600
ATI SB700
+ ATI SB800
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -237,9 +238,6 @@ config I2C_IOP3XX
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
-config I2C_ISA
- tristate
-
config I2C_IXP4XX
tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
depends on ARCH_IXP4XX
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a6db4e38bda8..5b752e4e1918 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_I2C_I801) += i2c-i801.o
obj-$(CONFIG_I2C_I810) += i2c-i810.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
-obj-$(CONFIG_I2C_ISA) += i2c-isa.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 025f19423faf..44e1cd21bb01 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -147,7 +147,7 @@ static int __init i2c_gpio_probe(struct platform_device *pdev)
* The reason to do so is to avoid sysfs names that only make
* sense when there are multiple adapters.
*/
- adap->nr = pdev->id >= 0 ? pdev->id : 0;
+ adap->nr = (pdev->id != -1) ? pdev->id : 0;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
goto err_add_bus;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 8f5c686123b8..289816db52ae 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -272,11 +272,11 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
/* Make sure the SMBus host is ready to start transmitting */
temp = inb_p(SMBHSTSTS);
if (i == 1) {
- /* Erronenous conditions before transaction:
+ /* Erroneous conditions before transaction:
* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
errmask = 0x9f;
} else {
- /* Erronenous conditions during transaction:
+ /* Erroneous conditions during transaction:
* Failed, Bus_Err, Dev_Err, Intr */
errmask = 0x1e;
}
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 440342bc62e1..ace644e21b14 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -490,6 +490,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
new_adapter->id = I2C_HW_IOP3XX;
new_adapter->owner = THIS_MODULE;
+ new_adapter->class = I2C_CLASS_HWMON;
new_adapter->dev.parent = &pdev->dev;
new_adapter->nr = pdev->id;
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
deleted file mode 100644
index b0e1370075de..000000000000
--- a/drivers/i2c/busses/i2c-isa.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
- Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
-
- Based on the i2c-isa pseudo-adapter from the lm_sensors project
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* This implements an i2c-core-like thing for ISA hardware monitoring
- chips. Such chips are linked to the i2c subsystem for historical
- reasons (because the early ISA hardware monitoring chips such as the
- LM78 had both an I2C and an ISA interface). They used to be
- registered with the main i2c-core, but as a first step in the
- direction of a clean separation between I2C and ISA chip drivers,
- we now have this separate core for ISA ones. It is significantly
- more simple than the real one, of course, because we don't have to
- handle multiple busses: there is only one (fake) ISA adapter.
- It is worth noting that we still rely on i2c-core for some things
- at the moment - but hopefully this won't last. */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
-#include <linux/platform_device.h>
-#include <linux/completion.h>
-
-/* Exported by i2c-core for i2c-isa only */
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct class i2c_adapter_class;
-
-static u32 isa_func(struct i2c_adapter *adapter);
-
-/* This is the actual algorithm we define */
-static const struct i2c_algorithm isa_algorithm = {
- .functionality = isa_func,
-};
-
-/* There can only be one... */
-static struct i2c_adapter isa_adapter = {
- .owner = THIS_MODULE,
- .id = I2C_HW_ISA,
- .class = I2C_CLASS_HWMON,
- .algo = &isa_algorithm,
- .name = "ISA main adapter",
-};
-
-/* We can't do a thing... */
-static u32 isa_func(struct i2c_adapter *adapter)
-{
- return 0;
-}
-
-
-/* We implement an interface which resembles i2c_{add,del}_driver,
- but for i2c-isa drivers. We don't have to remember and handle lists
- of drivers and adapters so this is much more simple, of course. */
-
-int i2c_isa_add_driver(struct i2c_driver *driver)
-{
- int res;
-
- /* Add the driver to the list of i2c drivers in the driver core */
- driver->driver.bus = &i2c_bus_type;
- res = driver_register(&driver->driver);
- if (res)
- return res;
- dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
-
- /* Now look for clients */
- res = driver->attach_adapter(&isa_adapter);
- if (res) {
- dev_dbg(&isa_adapter.dev,
- "Driver %s failed to attach adapter, unregistering\n",
- driver->driver.name);
- driver_unregister(&driver->driver);
- }
- return res;
-}
-
-int i2c_isa_del_driver(struct i2c_driver *driver)
-{
- struct list_head *item, *_n;
- struct i2c_client *client;
- int res;
-
- /* Detach all clients belonging to this one driver */
- list_for_each_safe(item, _n, &isa_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
- if (client->driver != driver)
- continue;
- dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
- client->name, client->addr);
- if ((res = driver->detach_client(client))) {
- dev_err(&isa_adapter.dev, "Failed, driver "
- "%s not unregistered!\n",
- driver->driver.name);
- return res;
- }
- }
-
- /* Get the driver off the core list */
- driver_unregister(&driver->driver);
- dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->driver.name);
-
- return 0;
-}
-
-
-static int __init i2c_isa_init(void)
-{
- int err;
-
- mutex_init(&isa_adapter.clist_lock);
- INIT_LIST_HEAD(&isa_adapter.clients);
-
- isa_adapter.nr = ANY_I2C_ISA_BUS;
- isa_adapter.dev.parent = &platform_bus;
- sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
- isa_adapter.dev.release = &i2c_adapter_dev_release;
- isa_adapter.dev.class = &i2c_adapter_class;
- err = device_register(&isa_adapter.dev);
- if (err) {
- printk(KERN_ERR "i2c-isa: Failed to register device\n");
- goto exit;
- }
-
- dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
-
- return 0;
-
-exit:
- return err;
-}
-
-static void __exit i2c_isa_exit(void)
-{
-#ifdef DEBUG
- struct list_head *item, *_n;
- struct i2c_client *client = NULL;
-#endif
-
- /* There should be no more active client */
-#ifdef DEBUG
- dev_dbg(&isa_adapter.dev, "Looking for clients\n");
- list_for_each_safe(item, _n, &isa_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
- dev_err(&isa_adapter.dev, "Driver %s still has an active "
- "ISA client at 0x%x\n", client->driver->driver.name,
- client->addr);
- }
- if (client != NULL)
- return;
-#endif
-
- /* Clean up the sysfs representation */
- dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
- init_completion(&isa_adapter.dev_released);
- device_unregister(&isa_adapter.dev);
-
- /* Wait for sysfs to drop all references */
- dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
- wait_for_completion(&isa_adapter.dev_released);
-
- dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
-}
-
-EXPORT_SYMBOL(i2c_isa_add_driver);
-EXPORT_SYMBOL(i2c_isa_del_driver);
-
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("ISA bus access through i2c");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_isa_init);
-module_exit(i2c_isa_exit);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 851c3ed513d0..d8de4ac88b7d 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -105,6 +105,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
schedule();
if (time_after(jiffies, orig_jiffies + timeout)) {
pr_debug("I2C: timeout\n");
+ writeccr(i2c, 0);
result = -EIO;
break;
}
@@ -116,10 +117,12 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
result = wait_event_interruptible_timeout(i2c->queue,
(i2c->interrupt & CSR_MIF), timeout * HZ);
- if (unlikely(result < 0))
+ if (unlikely(result < 0)) {
pr_debug("I2C: wait interrupted\n");
- else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+ writeccr(i2c, 0);
+ } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
pr_debug("I2C: wait timeout\n");
+ writeccr(i2c, 0);
result = -ETIMEDOUT;
}
@@ -172,7 +175,6 @@ static void mpc_i2c_start(struct mpc_i2c *i2c)
static void mpc_i2c_stop(struct mpc_i2c *i2c)
{
writeccr(i2c, CCR_MEN);
- writeccr(i2c, 0);
}
static int mpc_write(struct mpc_i2c *i2c, int target,
@@ -261,6 +263,7 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
if (signal_pending(current)) {
pr_debug("I2C: Interrupted\n");
+ writeccr(i2c, 0);
return -EINTR;
}
if (time_after(jiffies, orig_jiffies + HZ)) {
@@ -362,7 +365,7 @@ static int fsl_i2c_probe(struct platform_device *pdev)
fail_add:
if (i2c->irq != 0)
- free_irq(i2c->irq, NULL);
+ free_irq(i2c->irq, i2c);
fail_irq:
iounmap(i2c->base);
fail_map:
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 251154ae5d97..bb7bf68a7fb6 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -107,6 +107,21 @@ struct mv64xxx_i2c_data {
*
*****************************************************************************
*/
+
+/* Reset hardware and initialize FSM */
+static void
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
+ writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
+ drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+ writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+ drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
static void
mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
{
@@ -203,7 +218,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
drv_data->state, status, drv_data->msg->addr,
drv_data->msg->flags);
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
- drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ mv64xxx_i2c_hw_init(drv_data);
drv_data->rc = -EIO;
}
}
@@ -367,6 +382,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
"mv64xxx: I2C bus locked, block: %d, "
"time_left: %d\n", drv_data->block,
(int)time_left);
+ mv64xxx_i2c_hw_init(drv_data);
}
} else
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -443,19 +459,6 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
*
*****************************************************************************
*/
-static void __devinit
-mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
-{
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
- writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
- drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
- writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
- drv_data->state = MV64XXX_I2C_STATE_IDLE;
-}
-
static int __devinit
mv64xxx_i2c_map_regs(struct platform_device *pd,
struct mv64xxx_i2c_data *drv_data)
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index debc76cd2161..167e4137ee21 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -23,7 +23,7 @@
Supports:
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000
- ATI IXP200, IXP300, IXP400, SB600, SB700
+ ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
@@ -397,9 +397,7 @@ static struct pci_device_id piix4_ids[] = {
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
.driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS),
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
.driver_data = 0 },
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 9d6b790d4321..bb5466b27b59 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -926,7 +926,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
* The reason to do so is to avoid sysfs names that only make
* sense when there are multiple adapters.
*/
- i2c->adap.nr = dev->id >= 0 ? dev->id : 0;
+ i2c->adap.nr = dev->id != -1 ? dev->id : 0;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index e4540fcf6476..c44ada5f4292 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -39,8 +39,8 @@
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-iic.h>
-#include <asm/arch/iic.h>
+#include <asm/plat-s3c/regs-iic.h>
+#include <asm/plat-s3c/iic.h>
/* i2c controller state */
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
index 5879f0f25495..9e94542c18a2 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/i2c/chips/ds1682.c
@@ -75,7 +75,8 @@ static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
/* Special case: the 32 bit regs are time values with 1/4s
* resolution, scale them up to milliseconds */
if (sattr->nr == 4)
- return sprintf(buf, "%llu\n", ((u64) le32_to_cpu(val)) * 250);
+ return sprintf(buf, "%llu\n",
+ ((unsigned long long)le32_to_cpu(val)) * 250);
/* Format the output string and return # of bytes */
return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 9fafadb92510..fe04e46991aa 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -18,8 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#undef DEBUG
-#undef VERBOSE
#include <linux/kernel.h>
#include <linux/module.h>
@@ -44,7 +42,7 @@
#define DRIVER_VERSION "24 August 2004"
-#define DRIVER_NAME (isp1301_driver.name)
+#define DRIVER_NAME (isp1301_driver.driver.name)
MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
MODULE_LICENSE("GPL");
@@ -55,6 +53,7 @@ struct isp1301 {
void (*i2c_release)(struct device *dev);
int irq;
+ int irq_type;
u32 last_otg_ctrl;
unsigned working:1;
@@ -63,7 +62,7 @@ struct isp1301 {
/* use keventd context to change the state for us */
struct work_struct work;
-
+
unsigned long todo;
# define WORK_UPDATE_ISP 0 /* update ISP from OTG */
# define WORK_UPDATE_OTG 1 /* update OTG from ISP */
@@ -94,7 +93,7 @@ struct isp1301 {
/* board-specific PM hooks */
-#include <asm/arch/gpio.h>
+#include <asm/gpio.h>
#include <asm/arch/mux.h>
#include <asm/mach-types.h>
@@ -291,7 +290,7 @@ static void power_up(struct isp1301 *isp)
{
// isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG);
-
+
/* do this only when cpu is driving transceiver,
* so host won't see a low speed device...
*/
@@ -799,7 +798,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
/* role is host */
} else {
if (!(otg_ctrl & OTG_ID)) {
- otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+ otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ;
}
@@ -1100,9 +1099,9 @@ static u8 isp1301_clear_latch(struct isp1301 *isp)
}
static void
-isp1301_work(void *data)
+isp1301_work(struct work_struct *work)
{
- struct isp1301 *isp = data;
+ struct isp1301 *isp = container_of(work, struct isp1301, work);
int stop;
/* implicit lock: we're the only task using this device */
@@ -1244,7 +1243,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
* - DEVICE mode, for when there's a B/Mini-B (device) connector
*
* As a rule, you won't have an isp1301 chip unless it's there to
- * support the OTG mode. Other modes help testing USB controllers
+ * support the OTG mode. Other modes help testing USB controllers
* in isolation from (full) OTG support, or maybe so later board
* revisions can help to support those feature.
*/
@@ -1260,9 +1259,9 @@ static int isp1301_otg_enable(struct isp1301 *isp)
* a few more interrupts than are strictly needed.
*/
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+ INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+ INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
@@ -1306,9 +1305,9 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
dev_info(&isp->client.dev, "A-Host sessions ok\n");
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_ID_GND);
+ INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_ID_GND);
+ INTR_ID_GND);
/* If this has a Mini-AB connector, this mode is highly
* nonstandard ... but can be handy for testing, especially with
@@ -1368,9 +1367,9 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_SESS_VLD);
+ INTR_SESS_VLD);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_VBUS_VLD);
+ INTR_VBUS_VLD);
dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
dump_regs(isp, __FUNCTION__);
@@ -1494,7 +1493,7 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
if (!isp)
return 0;
- INIT_WORK(&isp->work, isp1301_work, isp);
+ INIT_WORK(&isp->work, isp1301_work);
init_timer(&isp->timer);
isp->timer.function = isp1301_timer;
isp->timer.data = (unsigned long) isp;
@@ -1572,13 +1571,14 @@ fail1:
/* IRQ wired at M14 */
omap_cfg_reg(M14_1510_GPIO2);
isp->irq = OMAP_GPIO_IRQ(2);
- omap_request_gpio(2);
- omap_set_gpio_direction(2, 1);
- omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE);
+ if (gpio_request(2, "isp1301") == 0)
+ gpio_direction_input(2);
+ isp->irq_type = IRQF_TRIGGER_FALLING;
}
+ isp->irq_type |= IRQF_SAMPLE_RANDOM;
status = request_irq(isp->irq, isp1301_irq,
- IRQF_SAMPLE_RANDOM, DRIVER_NAME, isp);
+ isp->irq_type, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
isp->irq, status);
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
index 48a7e2f0bdd3..d9c92c5e0077 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/i2c/chips/menelaus.c
@@ -1,4 +1,3 @@
-#define DEBUG
/*
* Copyright (C) 2004 Texas Instruments, Inc.
*
@@ -933,7 +932,7 @@ static int menelaus_set_time(struct device *dev, struct rtc_time *t)
return status;
status = menelaus_write_reg(MENELAUS_RTC_WKDAY, BIN2BCD(t->tm_wday));
if (status < 0) {
- dev_err(&the_menelaus->client->dev, "rtc write reg %02x",
+ dev_err(&the_menelaus->client->dev, "rtc write reg %02x "
"err %d\n", MENELAUS_RTC_WKDAY, status);
return status;
}
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 3c3f2ebf3fc9..503ffec2ce07 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -352,7 +352,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
/* REVISIT: this might need its own workqueue
* plus tweaks including deadlock avoidance ...
* also needs to get error handling and probably
- * an #ifdef CONFIG_SOFTWARE_SUSPEND
+ * an #ifdef CONFIG_HIBERNATION
*/
hibernate();
#endif
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6971a62397db..910a62de190d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
#ifdef CONFIG_HOTPLUG
/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
-static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct i2c_client *client = to_i2c_client(dev);
- int i = 0, length = 0;
/* by definition, legacy drivers can't hotplug */
if (dev->driver || !client->driver_name)
return 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=%s", client->driver_name))
+ if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
return -ENOMEM;
- envp[i] = NULL;
dev_dbg(dev, "uevent\n");
return 0;
}
@@ -288,7 +284,6 @@ void i2c_adapter_dev_release(struct device *dev)
struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
}
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */
static ssize_t
show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -307,7 +302,6 @@ struct class i2c_adapter_class = {
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
};
-EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index b1a9b81c211f..aa0e0c9f74c5 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -304,9 +304,17 @@ comment "IDE chipset support/bugfixes"
config IDE_GENERIC
tristate "generic/default IDE chipset support"
- default y
+ default H8300
help
- If unsure, say Y.
+ If unsure, say N.
+
+config BLK_DEV_PLATFORM
+ tristate "Platform driver for IDE interfaces"
+ help
+ This is the platform IDE driver, used mostly for Memory Mapped
+ IDE devices, like Compact Flashes running in True IDE mode.
+
+ If unsure, say N.
config BLK_DEV_CMD640
bool "CMD640 chipset bugfix/support"
@@ -345,22 +353,22 @@ config BLK_DEV_CMD640_ENHANCED
config BLK_DEV_IDEPNP
bool "PNP EIDE support"
depends on PNP
+ select IDE_GENERIC
help
If you have a PnP (Plug and Play) compatible EIDE card and
would like the kernel to automatically detect and activate
it, say Y here.
+if PCI
+
+comment "PCI IDE chipsets support"
+
config BLK_DEV_IDEPCI
- bool "PCI IDE chipset support" if PCI
- default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC
- help
- Say Y here for PCI systems which use IDE drive(s).
- This option helps the IDE driver to automatically detect and
- configure all PCI-based IDE interfaces in your system.
+ bool
config IDEPCI_SHARE_IRQ
bool "Sharing PCI IDE interrupts support"
- depends on PCI && BLK_DEV_IDEPCI
+ depends on BLK_DEV_IDEPCI
help
Some ATA/IDE chipsets have hardware support which allows for
sharing a single IRQ with other cards. To enable support for
@@ -370,11 +378,11 @@ config IDEPCI_SHARE_IRQ
If unsure, say N.
config IDEPCI_PCIBUS_ORDER
- def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+ def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
config BLK_DEV_OFFBOARD
bool "Boot off-board chipsets first support"
- depends on PCI && BLK_DEV_IDEPCI
+ depends on BLK_DEV_IDEPCI
help
Normally, IDE controllers built into the motherboard (on-board
controllers) are assigned to ide0 and ide1 while those on add-in PCI
@@ -397,21 +405,23 @@ config BLK_DEV_OFFBOARD
config BLK_DEV_GENERIC
tristate "Generic PCI IDE Chipset Support"
- depends on BLK_DEV_IDEPCI
+ select BLK_DEV_IDEPCI
help
This option provides generic support for various PCI IDE Chipsets
which otherwise might not be supported.
config BLK_DEV_OPTI621
tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
- depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL
+ depends on EXPERIMENTAL
+ select BLK_DEV_IDEPCI
help
This is a driver for the OPTi 82C621 EIDE controller.
Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
config BLK_DEV_RZ1000
tristate "RZ1000 chipset bugfix/support"
- depends on PCI && BLK_DEV_IDEPCI && X86
+ depends on X86
+ select BLK_DEV_IDEPCI
help
The PC-Technologies RZ1000 IDE chip is used on many common 486 and
Pentium motherboards, usually along with the "Neptune" chipset.
@@ -422,35 +432,21 @@ config BLK_DEV_RZ1000
things will operate 100% reliably.
config BLK_DEV_IDEDMA_PCI
- bool "Generic PCI bus-master DMA support"
- depends on PCI && BLK_DEV_IDEPCI
- ---help---
- If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
- is capable of bus-master DMA operation (most Pentium PCI systems),
- you will want to say Y here to reduce CPU overhead. You can then use
- the "hdparm" utility to enable DMA for drives for which it was not
- enabled automatically. By default, DMA is not enabled automatically
- for these drives, but you can change that by saying Y to the
- following question "Use DMA by default when available". You can get
- the latest version of the hdparm utility from
- <ftp://ibiblio.org/pub/Linux/system/hardware/>.
-
- Read the comments at the beginning of <file:drivers/ide/ide-dma.c>
- and the file <file:Documentation/ide.txt> for more information.
-
- It is safe to say Y to this question.
-
-if BLK_DEV_IDEDMA_PCI
+ bool
+ select BLK_DEV_IDEPCI
config BLK_DEV_IDEDMA_FORCED
bool "Force enable legacy 2.0.X HOSTS to use DMA"
+ depends on BLK_DEV_IDEDMA_PCI
help
This is an old piece of lost code from Linux 2.0 Kernels.
Generally say N here.
+# TODO: remove it
config IDEDMA_ONLYDISK
bool "Enable DMA only for disks "
+ depends on BLK_DEV_IDEDMA_PCI
help
This is used if you know your ATAPI Devices are going to fail DMA
Transfers.
@@ -459,6 +455,7 @@ config IDEDMA_ONLYDISK
config BLK_DEV_AEC62XX
tristate "AEC62XX chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
IDE controllers. This allows the kernel to change PIO, DMA and UDMA
@@ -466,6 +463,7 @@ config BLK_DEV_AEC62XX
config BLK_DEV_ALI15X3
tristate "ALI M15x3 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
onboard chipsets. It also tests for Simplex mode and enables
@@ -494,6 +492,7 @@ config WDC_ALI15X3
config BLK_DEV_AMD74XX
tristate "AMD and nVidia IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for AMD-7xx and AMD-8111 chips
and also for the nVidia nForce chip. This allows the kernel to
@@ -503,6 +502,7 @@ config BLK_DEV_AMD74XX
config BLK_DEV_ATIIXP
tristate "ATI IXP chipset IDE support"
depends on X86
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for ATI IXP chipset.
This allows the kernel to change PIO, DMA and UDMA speeds
@@ -512,18 +512,21 @@ config BLK_DEV_ATIIXP
config BLK_DEV_CMD64X
tristate "CMD64{3|6|8|9} chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
Say Y here if you have an IDE controller which uses any of these
chipsets: CMD643, CMD646, or CMD648.
config BLK_DEV_TRIFLEX
tristate "Compaq Triflex IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
Say Y here if you have a Compaq Triflex IDE controller, such
as those commonly found on Compaq Pentium-Pro systems
config BLK_DEV_CY82C693
tristate "CY82C693 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds detection and support for the CY82C693 chipset
used on Digital's PC-Alpha 164SX boards.
@@ -534,6 +537,7 @@ config BLK_DEV_CY82C693
config BLK_DEV_CS5520
tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
depends on EXPERIMENTAL
+ select BLK_DEV_IDEDMA_PCI
help
Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
5510/5520 chipset. This will automatically be detected and
@@ -543,6 +547,7 @@ config BLK_DEV_CS5520
config BLK_DEV_CS5530
tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
will automatically be detected and configured if found.
@@ -552,6 +557,7 @@ config BLK_DEV_CS5530
config BLK_DEV_CS5535
tristate "AMD CS5535 chipset support"
depends on X86 && !X86_64
+ select BLK_DEV_IDEDMA_PCI
help
Include support for UDMA on the NSC/AMD CS5535 companion chipset.
This will automatically be detected and configured if found.
@@ -560,6 +566,7 @@ config BLK_DEV_CS5535
config BLK_DEV_HPT34X
tristate "HPT34X chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds up to 4 more EIDE devices sharing a single
interrupt. The HPT343 chipset in its current form is a non-bootable
@@ -580,7 +587,8 @@ config HPT34X_AUTODMA
config BLK_DEV_HPT366
tristate "HPT36X/37X chipset support"
- ---help---
+ select BLK_DEV_IDEDMA_PCI
+ help
HPT366 is an Ultra DMA chipset for ATA-66.
HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
HPT370 is an Ultra DMA chipset for ATA-100.
@@ -604,18 +612,21 @@ config BLK_DEV_HPT366
config BLK_DEV_JMICRON
tristate "JMicron JMB36x support"
+ select BLK_DEV_IDEDMA_PCI
help
Basic support for the JMicron ATA controllers. For full support
use the libata drivers.
config BLK_DEV_SC1200
tristate "National SCx200 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for the built in IDE on the National
SCx200 series of embedded x86 "Geode" systems
config BLK_DEV_PIIX
tristate "Intel PIIXn 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
@@ -624,17 +635,20 @@ config BLK_DEV_PIIX
config BLK_DEV_IT8213
tristate "IT8213 IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for the ITE 8213 IDE controller.
config BLK_DEV_IT821X
tristate "IT821X IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for the ITE 8211 IDE controller and the
IT 8212 IDE RAID controller in both RAID and pass-through mode.
config BLK_DEV_NS87415
tristate "NS87415 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds detection and support for the NS87415 chip
(used mainly on SPARC64 and PA-RISC machines).
@@ -643,6 +657,7 @@ config BLK_DEV_NS87415
config BLK_DEV_PDC202XX_OLD
tristate "PROMISE PDC202{46|62|65|67} support"
+ select BLK_DEV_IDEDMA_PCI
help
Promise Ultra33 or PDC20246
Promise Ultra66 or PDC20262
@@ -684,9 +699,11 @@ config PDC202XX_BURST
config BLK_DEV_PDC202XX_NEW
tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
+ select BLK_DEV_IDEDMA_PCI
config BLK_DEV_SVWKS
tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
chipsets.
@@ -695,6 +712,7 @@ config BLK_DEV_SGIIOC4
tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
select IDEPCI_SHARE_IRQ
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
chipset, which has one channel and can support two devices.
@@ -702,6 +720,7 @@ config BLK_DEV_SGIIOC4
config BLK_DEV_SIIMAGE
tristate "Silicon Image chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds PIO/(U)DMA support for the SI CMD680 and SII
3112 (Serial ATA) chips.
@@ -709,7 +728,8 @@ config BLK_DEV_SIIMAGE
config BLK_DEV_SIS5513
tristate "SiS5513 chipset support"
depends on X86
- ---help---
+ select BLK_DEV_IDEDMA_PCI
+ help
This driver ensures (U)DMA support for SIS5513 chipset family based
mainboards.
@@ -728,6 +748,7 @@ config BLK_DEV_SIS5513
config BLK_DEV_SL82C105
tristate "Winbond SL82c105 support"
depends on (PPC || ARM)
+ select BLK_DEV_IDEDMA_PCI
help
If you have a Winbond SL82c105 IDE controller, say Y here to enable
special configuration for this chip. This is common on various CHRP
@@ -735,6 +756,7 @@ config BLK_DEV_SL82C105
config BLK_DEV_SLC90E66
tristate "SLC90E66 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver ensures (U)DMA support for Victory66 SouthBridges for
SMsC with Intel NorthBridges. This is an Ultra66 based chipset.
@@ -750,6 +772,7 @@ config BLK_DEV_SLC90E66
config BLK_DEV_TRM290
tristate "Tekram TRM290 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for bus master DMA transfers
using the Tekram TRM290 PCI IDE chip. Volunteers are
@@ -758,6 +781,7 @@ config BLK_DEV_TRM290
config BLK_DEV_VIA82CXXX
tristate "VIA82CXXX chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for VIA BusMastering IDE chips.
This allows the kernel to change PIO, DMA and UDMA speeds and to
@@ -765,12 +789,14 @@ config BLK_DEV_VIA82CXXX
config BLK_DEV_TC86C001
tristate "Toshiba TC86C001 support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for Toshiba TC86C001 GOKU-S chip.
config BLK_DEV_CELLEB
tristate "Toshiba's Cell Reference Set IDE support"
depends on PPC_CELLEB
+ select BLK_DEV_IDEDMA_PCI
help
This driver provides support for the built-in IDE controller on
Toshiba Cell Reference Board.
@@ -780,7 +806,7 @@ endif
config BLK_DEV_IDE_PMAC
bool "Builtin PowerMac IDE support"
- depends on PPC_PMAC && IDE=y
+ depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
help
This driver provides support for the built-in IDE controller on
most of the recent Apple Power Macintoshes and PowerBooks.
@@ -833,7 +859,8 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
depends on BLK_DEV_IDE_AU1XXX
config IDE_ARM
- def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+ def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+ select IDE_GENERIC
config BLK_DEV_IDE_ICSIDE
tristate "ICS IDE interface support"
@@ -867,6 +894,7 @@ config BLK_DEV_IDE_BAST
config BLK_DEV_GAYLE
bool "Amiga Gayle IDE interface support"
depends on AMIGA
+ select IDE_GENERIC
help
This is the IDE driver for the Amiga Gayle IDE interface. It supports
both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
@@ -898,6 +926,7 @@ config BLK_DEV_IDEDOUBLER
config BLK_DEV_BUDDHA
bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
depends on ZORRO && EXPERIMENTAL
+ select IDE_GENERIC
help
This is the IDE driver for the IDE interfaces on the Buddha,
Catweasel and X-Surf expansion boards. It supports up to two interfaces
@@ -910,6 +939,7 @@ config BLK_DEV_BUDDHA
config BLK_DEV_FALCON_IDE
bool "Falcon IDE interface support"
depends on ATARI
+ select IDE_GENERIC
help
This is the IDE driver for the builtin IDE interface on the Atari
Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
@@ -919,6 +949,7 @@ config BLK_DEV_FALCON_IDE
config BLK_DEV_MAC_IDE
bool "Macintosh Quadra/Powerbook IDE interface support"
depends on MAC
+ select IDE_GENERIC
help
This is the IDE driver for the builtin IDE interface on some m68k
Macintosh models. It supports both the `Quadra style' (used in
@@ -932,6 +963,7 @@ config BLK_DEV_MAC_IDE
config BLK_DEV_Q40IDE
bool "Q40/Q60 IDE interface support"
depends on Q40
+ select IDE_GENERIC
help
Enable the on-board IDE controller in the Q40/Q60. This should
normally be on; disable it only if you are running a custom hard
@@ -939,7 +971,8 @@ config BLK_DEV_Q40IDE
config BLK_DEV_MPC8xx_IDE
bool "MPC8xx IDE support"
- depends on 8xx && IDE=y && BLK_DEV_IDE=y
+ depends on 8xx && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
+ select IDE_GENERIC
help
This option provides support for IDE on Motorola MPC8xx Systems.
Please see 'Type of MPC8xx IDE interface' for details.
@@ -977,24 +1010,9 @@ config IDE_EXT_DIRECT
endchoice
# no isa -> no vlb
-config IDE_CHIPSETS
- bool "Other IDE chipset support"
- depends on ISA
- ---help---
- Say Y here if you want to include enhanced support for various IDE
- interface chipsets used on motherboards and add-on cards. You can
- then pick your particular IDE chip from among the following options.
- This enhanced support may be necessary for Linux to be able to
- access the 3rd/4th drives in some systems. It may also enable
- setting of higher speed I/O rates to improve system performance with
- these chipsets. Most of these also require special kernel boot
- parameters to actually turn on the support at runtime; you can find
- a list of these in the file <file:Documentation/ide.txt>.
-
- People with SCSI-only systems can say N here.
-
-if IDE_CHIPSETS
+if ISA
+comment "Other IDE chipsets support"
comment "Note: most of these also require special kernel boot parameters"
config BLK_DEV_4DRIVES
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index c89b5f4b2d04..7912a471f10d 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -248,15 +248,9 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
* MW1 80 50 50 150 C
* MW2 70 25 25 120 C
*/
-static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
+static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
{
- int on = 0, cycle_time = 0, use_dma_info = 0;
-
- /*
- * Limit the transfer speed to MW_DMA_2.
- */
- if (xfer_mode > XFER_MW_DMA_2)
- xfer_mode = XFER_MW_DMA_2;
+ int cycle_time, use_dma_info = 0;
switch (xfer_mode) {
case XFER_MW_DMA_2:
@@ -278,6 +272,8 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
case XFER_SW_DMA_0:
cycle_time = 480;
break;
+ default:
+ return 1;
}
/*
@@ -289,17 +285,10 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
drive->drive_data = cycle_time;
- if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
- on = 1;
- else
- drive->drive_data = 480;
-
printk("%s: %s selected (peak %dMB/s)\n", drive->name,
ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
- drive->current_speed = xfer_mode;
-
- return on;
+ return ide_config_drive_speed(drive, xfer_mode);
}
static void icside_dma_host_off(ide_drive_t *drive)
@@ -326,8 +315,7 @@ static int icside_dma_check(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
- int xfer_mode = XFER_PIO_2;
- int on;
+ int xfer_mode = 0;
if (!(id->capability & 1) || !hwif->autodma)
goto out;
@@ -356,9 +344,10 @@ static int icside_dma_check(ide_drive_t *drive)
}
out:
- on = icside_set_speed(drive, xfer_mode);
+ if (xfer_mode == 0)
+ return -1;
- return on ? 0 : -1;
+ return icside_set_speed(drive, xfer_mode) ? -1 : 0;
}
static int icside_dma_end(ide_drive_t *drive)
@@ -693,13 +682,12 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto out;
- state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct icside_state), GFP_KERNEL);
if (!state) {
ret = -ENOMEM;
goto release;
}
- memset(state, 0, sizeof(state));
state->type = ICS_TYPE_NOTYPE;
state->dev = &ec->dev;
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index a3d6744e870a..bce2bec81413 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -1,5 +1,5 @@
/*
- * ARM/ARM26 default IDE host driver
+ * ARM default IDE host driver
*
* Copyright (C) 2004 Bartlomiej Zolnierkiewicz
* Based on code by: Russell King, Ian Molton and Alexander Schulz.
@@ -14,12 +14,6 @@
#include <asm/mach-types.h>
#include <asm/irq.h>
-#ifdef CONFIG_ARM26
-# define IDE_ARM_HOST (machine_is_a5k())
-#else
-# define IDE_ARM_HOST (1)
-#endif
-
#ifdef CONFIG_ARCH_CLPS7500
# include <asm/arch/hardware.h>
#
@@ -32,12 +26,10 @@
void __init ide_arm_init(void)
{
- if (IDE_ARM_HOST) {
- hw_regs_t hw;
+ hw_regs_t hw;
- memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
- hw.irq = IDE_ARM_IRQ;
- ide_register_hw(&hw, 1, NULL);
- }
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
+ hw.irq = IDE_ARM_IRQ;
+ ide_register_hw(&hw, 1, NULL);
}
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 886091bc7db0..4bb42b30bfc0 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -414,12 +414,6 @@ cris_ide_reset(unsigned val)
#ifdef CONFIG_ETRAX_IDE_G27_RESET
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val);
#endif
-#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
- REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, val);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
- REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, val);
-#endif
#ifdef CONFIG_ETRAX_IDE_PB7_RESET
port_pb_dir_shadow = port_pb_dir_shadow |
IO_STATE(R_PORT_PB_DIR, dir7, output);
@@ -686,7 +680,7 @@ static void cris_dma_off(ide_drive_t *drive)
{
}
-static void tune_cris_ide(ide_drive_t *drive, u8 pio)
+static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int setup, strobe, hold;
@@ -722,17 +716,14 @@ static void tune_cris_ide(ide_drive_t *drive, u8 pio)
}
cris_ide_set_speed(TYPE_PIO, setup, strobe, hold);
+
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int speed_cris_ide(ide_drive_t *drive, u8 speed)
+static int speed_cris_ide(ide_drive_t *drive, const u8 speed)
{
int cyc = 0, dvs = 0, strobe = 0, hold = 0;
- if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
- tune_cris_ide(drive, speed - XFER_PIO_0);
- return ide_config_drive_speed(drive, speed);
- }
-
switch(speed)
{
case XFER_UDMA_0:
@@ -799,7 +790,7 @@ init_e100_ide (void)
ide_register_hw(&hw, 1, &hwif);
hwif->mmio = 1;
hwif->chipset = ide_etrax100;
- hwif->tuneproc = &tune_cris_ide;
+ hwif->set_pio_mode = &cris_set_pio_mode;
hwif->speedproc = &speed_cris_ide;
hwif->ata_input_data = &cris_ide_input_data;
hwif->ata_output_data = &cris_ide_output_data;
@@ -820,6 +811,7 @@ init_e100_ide (void)
hwif->dma_host_on = &cris_dma_on;
hwif->dma_off_quietly = &cris_dma_off;
hwif->cbl = ATA_CBL_PATA40;
+ hwif->pio_mask = ATA_PIO4,
hwif->ultra_mask = cris_ultra_mask;
hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
hwif->autodma = 1;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 17aea65d7dd2..6bff81a58bf3 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -612,6 +612,46 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
/**
+ * ide_acpi_set_state - set the channel power state
+ * @hwif: target IDE interface
+ * @on: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ide_acpi_set_state(ide_hwif_t *hwif, int on)
+{
+ int unit;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+ /* channel first and then drives for power on and verse versa for power off */
+ if (on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (!drive->acpidata->obj_handle)
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+
+ if (drive->acpidata->obj_handle && drive->present) {
+ acpi_bus_set_power(drive->acpidata->obj_handle,
+ on? ACPI_STATE_D0: ACPI_STATE_D3);
+ }
+ }
+ if (!on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_set_state);
+
+/**
* ide_acpi_init - initialize the ACPI link for an IDE interface
* @hwif: target IDE interface (channel)
*
@@ -679,6 +719,8 @@ void ide_acpi_init(ide_hwif_t *hwif)
return;
}
+ /* ACPI _PS0 before _STM */
+ ide_acpi_set_state(hwif, 1);
/*
* ACPI requires us to call _STM on startup
*/
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 1486eb212ccc..ca843522f91d 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -3071,7 +3071,7 @@ static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
/*
* standard prep_rq_fn that builds 10 byte cmds
*/
-static int ide_cdrom_prep_fs(request_queue_t *q, struct request *rq)
+static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
{
int hard_sect = queue_hardsect_size(q);
long block = (long)rq->hard_sector / (hard_sect >> 9);
@@ -3137,7 +3137,7 @@ static int ide_cdrom_prep_pc(struct request *rq)
return BLKPREP_OK;
}
-static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq)
+static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
{
if (blk_fs_request(rq))
return ide_cdrom_prep_fs(q, rq);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index b1304a7f3e0a..4754769eda97 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -481,6 +481,16 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id)
&& id->lba_capacity_2;
}
+/*
+ * Some disks report total number of sectors instead of
+ * maximum sector address. We list them here.
+ */
+static const struct drive_list_entry hpa_list[] = {
+ { "ST340823A", NULL },
+ { "ST320413A", NULL },
+ { NULL, NULL }
+};
+
static void idedisk_check_hpa(ide_drive_t *drive)
{
unsigned long long capacity, set_max;
@@ -492,6 +502,15 @@ static void idedisk_check_hpa(ide_drive_t *drive)
else
set_max = idedisk_read_native_max_address(drive);
+ if (ide_in_drive_list(drive->id, hpa_list)) {
+ /*
+ * Since we are inclusive wrt to firmware revisions do this
+ * extra check and apply the workaround only when needed.
+ */
+ if (set_max == capacity + 1)
+ set_max--;
+ }
+
if (set_max <= capacity)
return;
@@ -679,7 +698,7 @@ static ide_proc_entry_t idedisk_proc[] = {
};
#endif /* CONFIG_IDE_PROC_FS */
-static void idedisk_prepare_flush(request_queue_t *q, struct request *rq)
+static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
{
ide_drive_t *drive = q->queuedata;
@@ -697,7 +716,7 @@ static void idedisk_prepare_flush(request_queue_t *q, struct request *rq)
rq->buffer = rq->cmd;
}
-static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int idedisk_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
ide_drive_t *drive = q->queuedata;
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 5fe1d72ab451..6000c08f51ba 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -135,25 +135,6 @@ static const struct drive_list_entry drive_blacklist [] = {
};
/**
- * ide_in_drive_list - look for drive in black/white list
- * @id: drive identifier
- * @drive_table: list to inspect
- *
- * Look for a drive in the blacklist and the whitelist tables
- * Returns 1 if the drive is found in the table.
- */
-
-int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
-{
- for ( ; drive_table->id_model ; drive_table++)
- if ((!strcmp(drive_table->id_model, id->model)) &&
- (!drive_table->id_firmware ||
- strstr(id->fw_rev, drive_table->id_firmware)))
- return 1;
- return 0;
-}
-
-/**
* ide_dma_intr - IDE DMA interrupt handler
* @drive: the drive the interrupt is for
*
@@ -349,9 +330,17 @@ EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
static int config_drive_for_dma (ide_drive_t *drive)
{
+ ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
- if ((id->capability & 1) && drive->hwif->autodma) {
+ /* consult the list of known "bad" drives */
+ if (__ide_dma_bad_drive(drive))
+ return -1;
+
+ if (drive->media != ide_disk && hwif->atapi_dma == 0)
+ return -1;
+
+ if ((id->capability & 1) && drive->autodma) {
/*
* Enable DMA on any drive that has
* UltraDMA (mode 0/1/2/3/4/5/6) enabled
@@ -514,20 +503,6 @@ int __ide_dma_on (ide_drive_t *drive)
EXPORT_SYMBOL(__ide_dma_on);
/**
- * __ide_dma_check - check DMA setup
- * @drive: drive to check
- *
- * Don't use - due for extermination
- */
-
-int __ide_dma_check (ide_drive_t *drive)
-{
- return config_drive_for_dma(drive);
-}
-
-EXPORT_SYMBOL(__ide_dma_check);
-
-/**
* ide_dma_setup - begin a DMA phase
* @drive: target device
*
@@ -678,7 +653,7 @@ static const u8 xfer_mode_bases[] = {
XFER_SW_DMA_0,
};
-static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = drive->hwif;
@@ -689,17 +664,28 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
if ((id->field_valid & 4) == 0)
break;
- mask = id->dma_ultra & hwif->ultra_mask;
-
if (hwif->udma_filter)
- mask &= hwif->udma_filter(drive);
+ mask = hwif->udma_filter(drive);
+ else
+ mask = hwif->ultra_mask;
+ mask &= id->dma_ultra;
- if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
- mask &= 0x07;
+ /*
+ * avoid false cable warning from eighty_ninty_three()
+ */
+ if (req_mode > XFER_UDMA_2) {
+ if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+ mask &= 0x07;
+ }
break;
case XFER_MW_DMA_0:
- if (id->field_valid & 2)
- mask = id->dma_mword & hwif->mwdma_mask;
+ if ((id->field_valid & 2) == 0)
+ break;
+ if (hwif->mdma_filter)
+ mask = hwif->mdma_filter(drive);
+ else
+ mask = hwif->mwdma_mask;
+ mask &= id->dma_mword;
break;
case XFER_SW_DMA_0:
if (id->field_valid & 2) {
@@ -728,15 +714,18 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
}
/**
- * ide_max_dma_mode - compute DMA speed
+ * ide_find_dma_mode - compute DMA speed
* @drive: IDE device
+ * @req_mode: requested mode
+ *
+ * Checks the drive/host capabilities and finds the speed to use for
+ * the DMA transfer. The speed is then limited by the requested mode.
*
- * Checks the drive capabilities and returns the speed to use
- * for the DMA transfer. Returns 0 if the drive is incapable
- * of DMA transfers.
+ * Returns 0 if the drive/host combination is incapable of DMA transfers
+ * or if the requested mode is not a DMA mode.
*/
-u8 ide_max_dma_mode(ide_drive_t *drive)
+u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
{
ide_hwif_t *hwif = drive->hwif;
unsigned int mask;
@@ -747,7 +736,9 @@ u8 ide_max_dma_mode(ide_drive_t *drive)
return 0;
for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
- mask = ide_get_mode_mask(drive, xfer_mode_bases[i]);
+ if (req_mode < xfer_mode_bases[i])
+ continue;
+ mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
x = fls(mask) - 1;
if (x >= 0) {
mode = xfer_mode_bases[i] + x;
@@ -757,10 +748,10 @@ u8 ide_max_dma_mode(ide_drive_t *drive)
printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
- return mode;
+ return min(mode, req_mode);
}
-EXPORT_SYMBOL_GPL(ide_max_dma_mode);
+EXPORT_SYMBOL_GPL(ide_find_dma_mode);
int ide_tune_dma(ide_drive_t *drive)
{
@@ -1021,7 +1012,7 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
if (!hwif->dma_host_on)
hwif->dma_host_on = &ide_dma_host_on;
if (!hwif->ide_dma_check)
- hwif->ide_dma_check = &__ide_dma_check;
+ hwif->ide_dma_check = &config_drive_for_dma;
if (!hwif->dma_setup)
hwif->dma_setup = &ide_dma_setup;
if (!hwif->dma_exec_cmd)
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index a21f585b1caa..04a357808f2e 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -99,6 +99,8 @@
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <scsi/scsi_ioctl.h>
+
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -604,26 +606,24 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns
{
struct request *rq = pc->rq;
struct bio_vec *bvec;
- struct bio *bio;
+ struct req_iterator iter;
unsigned long flags;
char *data;
- int count, i, done = 0;
+ int count, done = 0;
- rq_for_each_bio(bio, rq) {
- bio_for_each_segment(bvec, bio, i) {
- if (!bcount)
- break;
+ rq_for_each_segment(bvec, rq, iter) {
+ if (!bcount)
+ break;
- count = min(bvec->bv_len, bcount);
+ count = min(bvec->bv_len, bcount);
- data = bvec_kmap_irq(bvec, &flags);
- drive->hwif->atapi_input_bytes(drive, data, count);
- bvec_kunmap_irq(data, &flags);
+ data = bvec_kmap_irq(bvec, &flags);
+ drive->hwif->atapi_input_bytes(drive, data, count);
+ bvec_kunmap_irq(data, &flags);
- bcount -= count;
- pc->b_count += count;
- done += count;
- }
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
}
idefloppy_do_end_request(drive, 1, done >> 9);
@@ -637,27 +637,25 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns
static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
{
struct request *rq = pc->rq;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bvec;
unsigned long flags;
- int count, i, done = 0;
+ int count, done = 0;
char *data;
- rq_for_each_bio(bio, rq) {
- bio_for_each_segment(bvec, bio, i) {
- if (!bcount)
- break;
+ rq_for_each_segment(bvec, rq, iter) {
+ if (!bcount)
+ break;
- count = min(bvec->bv_len, bcount);
+ count = min(bvec->bv_len, bcount);
- data = bvec_kmap_irq(bvec, &flags);
- drive->hwif->atapi_output_bytes(drive, data, count);
- bvec_kunmap_irq(data, &flags);
+ data = bvec_kmap_irq(bvec, &flags);
+ drive->hwif->atapi_output_bytes(drive, data, count);
+ bvec_kunmap_irq(data, &flags);
- bcount -= count;
- pc->b_count += count;
- done += count;
- }
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
}
idefloppy_do_end_request(drive, 1, done >> 9);
@@ -2099,7 +2097,21 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
return idefloppy_get_format_progress(drive, argp);
}
- return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+ /*
+ * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+ * and CDROM_SEND_PACKET (legacy) ioctls
+ */
+ if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+ err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
+ bdev->bd_disk, cmd, argp);
+ else
+ err = -ENOTTY;
+
+ if (err == -ENOTTY)
+ err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+ return err;
}
static int idefloppy_media_changed(struct gendisk *disk)
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index c5b5011da56e..9560a8f4a86c 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,7 +55,7 @@
#include <asm/bitops.h>
static int __ide_end_request(ide_drive_t *drive, struct request *rq,
- int uptodate, int nr_sectors)
+ int uptodate, unsigned int nr_bytes)
{
int ret = 1;
@@ -64,7 +64,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
* complete the whole request right now
*/
if (blk_noretry_request(rq) && end_io_error(uptodate))
- nr_sectors = rq->hard_nr_sectors;
+ nr_bytes = rq->hard_nr_sectors << 9;
if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
rq->errors = -EIO;
@@ -78,7 +78,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
HWGROUP(drive)->hwif->ide_dma_on(drive);
}
- if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
add_disk_randomness(rq->rq_disk);
if (!list_empty(&rq->queuelist))
blkdev_dequeue_request(rq);
@@ -103,6 +103,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
{
+ unsigned int nr_bytes = nr_sectors << 9;
struct request *rq;
unsigned long flags;
int ret = 1;
@@ -114,10 +115,14 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
spin_lock_irqsave(&ide_lock, flags);
rq = HWGROUP(drive)->rq;
- if (!nr_sectors)
- nr_sectors = rq->hard_cur_sectors;
+ if (!nr_bytes) {
+ if (blk_pc_request(rq))
+ nr_bytes = rq->data_len;
+ else
+ nr_bytes = rq->hard_cur_sectors << 9;
+ }
- ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+ ret = __ide_end_request(drive, rq, uptodate, nr_bytes);
spin_unlock_irqrestore(&ide_lock, flags);
return ret;
@@ -196,8 +201,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
return do_rw_taskfile(drive, args);
case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */
- if (drive->hwif->tuneproc != NULL)
- drive->hwif->tuneproc(drive, 255);
+ ide_set_max_pio(drive);
/*
* skip idedisk_pm_idle for ATAPI devices
*/
@@ -219,11 +223,12 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
* we could be smarter and check for current xfer_speed
* in struct drive etc...
*/
- if ((drive->id->capability & 1) == 0)
- break;
if (drive->hwif->ide_dma_check == NULL)
break;
drive->hwif->dma_off_quietly(drive);
+ /*
+ * TODO: respect ->using_dma setting
+ */
ide_set_dma(drive);
break;
}
@@ -782,6 +787,30 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
return ide_started;
}
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
+{
+ switch (req_pio) {
+ case 202:
+ case 201:
+ case 200:
+ case 102:
+ case 101:
+ case 100:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+ case 9:
+ case 8:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+ case 7:
+ case 6:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+ default:
+ return 0;
+ }
+}
+
/**
* do_special - issue some special commands
* @drive: drive the command is for
@@ -799,9 +828,17 @@ static ide_startstop_t do_special (ide_drive_t *drive)
printk("%s: do_special: 0x%02x\n", drive->name, s->all);
#endif
if (s->b.set_tune) {
+ ide_hwif_t *hwif = drive->hwif;
+ u8 req_pio = drive->tune_req;
+
s->b.set_tune = 0;
- if (HWIF(drive)->tuneproc != NULL)
- HWIF(drive)->tuneproc(drive, drive->tune_req);
+
+ if (set_pio_mode_abuse(drive->hwif, req_pio)) {
+ if (hwif->set_pio_mode)
+ hwif->set_pio_mode(drive, req_pio);
+ } else
+ ide_set_pio(drive, req_pio);
+
return ide_stopped;
} else {
if (drive->media == ide_disk)
@@ -1321,7 +1358,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
/*
* Passes the stuff to ide_do_request
*/
-void do_ide_request(request_queue_t *q)
+void do_ide_request(struct request_queue *q)
{
ide_drive_t *drive = q->queuedata;
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 92578b6832e9..cf0678b61161 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -565,6 +565,36 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
EXPORT_SYMBOL(ide_wait_stat);
+/**
+ * ide_in_drive_list - look for drive in black/white list
+ * @id: drive identifier
+ * @drive_table: list to inspect
+ *
+ * Look for a drive in the blacklist and the whitelist tables
+ * Returns 1 if the drive is found in the table.
+ */
+
+int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
+{
+ for ( ; drive_table->id_model; drive_table++)
+ if ((!strcmp(drive_table->id_model, id->model)) &&
+ (!drive_table->id_firmware ||
+ strstr(id->fw_rev, drive_table->id_firmware)))
+ return 1;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_in_drive_list);
+
+/*
+ * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid.
+ * We list them here and depend on the device side cable detection for them.
+ */
+static const struct drive_list_entry ivb_list[] = {
+ { "QUANTUM FIREBALLlct10 05" , "A03.0900" },
+ { NULL , NULL }
+};
+
/*
* All hosts that use the 80c ribbon must use!
* The name is derived from upper byte of word 93 and the 80c ribbon.
@@ -573,25 +603,29 @@ u8 eighty_ninty_three (ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
+ int ivb = ide_in_drive_list(id, ivb_list);
if (hwif->cbl == ATA_CBL_PATA40_SHORT)
return 1;
- if (hwif->cbl != ATA_CBL_PATA80)
+ if (ivb)
+ printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
+ drive->name);
+
+ if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
goto no_80w;
- /* Check for SATA but only if we are ATA5 or higher */
- if (id->hw_config == 0 && (id->major_rev_num & 0x7FE0))
+ if (ide_dev_is_sata(id))
return 1;
/*
* FIXME:
* - change master/slave IDENTIFY order
- * - force bit13 (80c cable present) check
+ * - force bit13 (80c cable present) check also for !ivb devices
* (unless the slave device is pre-ATA3)
*/
#ifndef CONFIG_IDEDMA_IVB
- if (id->hw_config & 0x4000)
+ if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
#else
if (id->hw_config & 0x6000)
#endif
@@ -746,12 +780,6 @@ int ide_driveid_update (ide_drive_t *drive)
/*
* Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere. Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again. :) -ml
- *
- * It is gone..........
*
* const char *msg == consider adding for verbose errors.
*/
@@ -795,7 +823,7 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
hwif->OUTB(speed, IDE_NSECTOR_REG);
hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
- hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+ hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
udelay(1);
@@ -822,7 +850,7 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
*/
for (i = 0; i < 10; i++) {
udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+ if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
error = 0;
break;
}
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 074bb32a4a40..d97390c0543b 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -76,41 +76,26 @@ EXPORT_SYMBOL(ide_xfer_verbose);
* Given the available transfer modes this function returns
* the best available speed at or below the speed requested.
*
- * FIXME: filter also PIO/SWDMA/MWDMA modes
+ * TODO: check device PIO capabilities
*/
-u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
+static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
{
-#ifdef CONFIG_BLK_DEV_IDEDMA
ide_hwif_t *hwif = drive->hwif;
- u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2;
+ u8 mode = ide_find_dma_mode(drive, speed);
- if (hwif->udma_filter)
- mask = hwif->udma_filter(drive);
-
- /*
- * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false
- * cable warning from eighty_ninty_three(), moving ide_rate_filter()
- * calls from ->speedproc to core code will make this hack go away
- */
- if (speed > XFER_UDMA_2) {
- if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
- mask &= 0x07;
+ if (mode == 0) {
+ if (hwif->pio_mask)
+ mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
+ else
+ mode = XFER_PIO_4;
}
- if (mask)
- mode = fls(mask) - 1 + XFER_UDMA_0;
-
// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
return min(speed, mode);
-#else /* !CONFIG_BLK_DEV_IDEDMA */
- return min(speed, (u8)XFER_PIO_4);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-EXPORT_SYMBOL(ide_rate_filter);
-
int ide_use_fast_pio(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -249,12 +234,34 @@ static int ide_scan_pio_blacklist (char *model)
return -1;
}
+unsigned int ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
+{
+ struct hd_driveid *id = drive->id;
+ int cycle_time = 0;
+
+ if (id->field_valid & 2) {
+ if (id->capability & 8)
+ cycle_time = id->eide_pio_iordy;
+ else
+ cycle_time = id->eide_pio;
+ }
+
+ /* conservative "downgrade" for all pre-ATA2 drives */
+ if (pio < 3) {
+ if (cycle_time && cycle_time < ide_pio_timings[pio].cycle_time)
+ cycle_time = 0; /* use standard timing */
+ }
+
+ return cycle_time ? cycle_time : ide_pio_timings[pio].cycle_time;
+}
+
+EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
+
/**
* ide_get_best_pio_mode - get PIO mode from drive
* @drive: drive to consider
* @mode_wanted: preferred mode
* @max_mode: highest allowed mode
- * @d: PIO data
*
* This routine returns the recommended PIO settings for a given drive,
* based on the drive->id information and the ide_pio_blacklist[].
@@ -263,22 +270,18 @@ static int ide_scan_pio_blacklist (char *model)
* This is used by most chipset support modules when "auto-tuning".
*/
-u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
{
int pio_mode;
- int cycle_time = 0;
- int use_iordy = 0;
struct hd_driveid* id = drive->id;
int overridden = 0;
- if (mode_wanted != 255) {
- pio_mode = mode_wanted;
- use_iordy = (pio_mode > 2);
- } else if (!drive->id) {
- pio_mode = 0;
- } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
- overridden = 1;
- use_iordy = (pio_mode > 2);
+ if (mode_wanted != 255)
+ return min_t(u8, mode_wanted, max_mode);
+
+ if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
+ (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+ printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
} else {
pio_mode = id->tPIO;
if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
@@ -286,9 +289,7 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
overridden = 1;
}
if (id->field_valid & 2) { /* drive implements ATA2? */
- if (id->capability & 8) { /* drive supports use_iordy? */
- use_iordy = 1;
- cycle_time = id->eide_pio_iordy;
+ if (id->capability & 8) { /* IORDY supported? */
if (id->eide_pio_modes & 7) {
overridden = 0;
if (id->eide_pio_modes & 4)
@@ -298,36 +299,61 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
else
pio_mode = 3;
}
- } else {
- cycle_time = id->eide_pio;
}
}
+ if (overridden)
+ printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
+ drive->name);
+
/*
* Conservative "downgrade" for all pre-ATA2 drives
*/
- if (pio_mode && pio_mode < 4) {
+ if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 &&
+ pio_mode && pio_mode < 4) {
pio_mode--;
- overridden = 1;
- if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
- cycle_time = 0; /* use standard timing */
+ printk(KERN_INFO "%s: applying conservative "
+ "PIO \"downgrade\"\n", drive->name);
}
}
- if (pio_mode > max_mode) {
+
+ if (pio_mode > max_mode)
pio_mode = max_mode;
- cycle_time = 0;
- }
- if (d) {
- d->pio_mode = pio_mode;
- d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
- d->use_iordy = use_iordy;
- d->overridden = overridden;
- }
+
return pio_mode;
}
EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+/* req_pio == "255" for auto-tune */
+void ide_set_pio(ide_drive_t *drive, u8 req_pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 host_pio, pio;
+
+ if (hwif->set_pio_mode == NULL)
+ return;
+
+ BUG_ON(hwif->pio_mask == 0x00);
+
+ host_pio = fls(hwif->pio_mask) - 1;
+
+ pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
+
+ /*
+ * TODO:
+ * - report device max PIO mode
+ * - check req_pio != 255 against device max PIO mode
+ */
+ printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
+ drive->name, host_pio, req_pio,
+ req_pio == 255 ? "(auto-tune)" : "", pio);
+
+ hwif->set_pio_mode(drive, pio);
+}
+
+EXPORT_SYMBOL_GPL(ide_set_pio);
+
/**
* ide_toggle_bounce - handle bounce buffering
* @drive: drive to update
@@ -365,13 +391,26 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
{
-#ifndef CONFIG_BLK_DEV_IDEDMA
- rate = min(rate, (u8) XFER_PIO_4);
-#endif
- if(HWIF(drive)->speedproc)
- return HWIF(drive)->speedproc(drive, rate);
- else
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (hwif->speedproc == NULL)
return -1;
+
+ rate = ide_rate_filter(drive, rate);
+
+ if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) {
+ if (hwif->set_pio_mode)
+ hwif->set_pio_mode(drive, rate - XFER_PIO_0);
+
+ /*
+ * FIXME: this is incorrect to return zero here but
+ * since all users of ide_set_xfer_rate() ignore
+ * the return value it is not a problem currently
+ */
+ return 0;
+ }
+
+ return hwif->speedproc(drive, rate);
}
static void ide_dump_opcode(ide_drive_t *drive)
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 5a4c5ea12f89..b4c9f63a3854 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -827,10 +827,8 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present) {
- if (hwif->tuneproc != NULL &&
- drive->autotune == IDE_TUNE_AUTO)
- /* auto-tune PIO mode */
- hwif->tuneproc(drive, 255);
+ if (drive->autotune == IDE_TUNE_AUTO)
+ ide_set_max_pio(drive);
if (drive->autotune != IDE_TUNE_DEFAULT &&
drive->autotune != IDE_TUNE_AUTO)
@@ -945,7 +943,7 @@ static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
*/
static int ide_init_queue(ide_drive_t *drive)
{
- request_queue_t *q;
+ struct request_queue *q;
ide_hwif_t *hwif = HWIF(drive);
int max_sectors = 256;
int max_sg_entries = PRD_ENTRIES;
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index e82bfa5e0ab8..1fa57947bca0 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -640,7 +640,7 @@ typedef enum {
} idetape_chrdev_direction_t;
struct idetape_bh {
- unsigned short b_size;
+ u32 b_size;
atomic_t b_count;
struct idetape_bh *b_reqnext;
char *b_data;
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
index e6cb8593b5ba..daffbb9797e1 100644
--- a/drivers/ide/ide-timing.h
+++ b/drivers/ide/ide-timing.h
@@ -106,23 +106,6 @@ static struct ide_timing ide_timing[] = {
#define XFER_EPIO 0x01
#define XFER_PIO 0x00
-static short ide_find_best_pio_mode(ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- short best = 0;
-
- if (id->field_valid & 2) { /* EIDE PIO modes */
-
- if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
- (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
- (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
- }
-
- return (drive->id->tPIO == 2) ? XFER_PIO_2 :
- (drive->id->tPIO == 1) ? XFER_PIO_1 :
- (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
-}
-
static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
{
q->setup = EZ(t->setup * 1000, T);
@@ -212,7 +195,8 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
*/
if ((speed & XFER_MODE) != XFER_PIO) {
- ide_timing_compute(drive, ide_find_best_pio_mode(drive), &p, T, UT);
+ u8 pio = ide_get_best_pio_mode(drive, 255, 5);
+ ide_timing_compute(drive, XFER_PIO_0 + pio, &p, T, UT);
ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 077fb674a96d..a96a8b1b3539 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -16,10 +16,6 @@
* (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec.
*
- * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
- * Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
- * Tertiary: ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
- * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
* ...
*
* From hd.c:
@@ -47,80 +43,6 @@
* This was a rewrite of just about everything from hd.c, though some original
* code is still sprinkled about. Think of it as a major evolution, with
* inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- *
- * Version 1.0 ALPHA initial code, primary i/f working okay
- * Version 1.3 BETA dual i/f on shared irq tested & working!
- * Version 1.4 BETA added auto probing for irq(s)
- * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms,
- * ...
- * Version 5.50 allow values as small as 20 for idebus=
- * Version 5.51 force non io_32bit in drive_cmd_intr()
- * change delay_10ms() to delay_50ms() to fix problems
- * Version 5.52 fix incorrect invalidation of removable devices
- * add "hdx=slow" command line option
- * Version 5.60 start to modularize the driver; the disk and ATAPI
- * drivers can be compiled as loadable modules.
- * move IDE probe code to ide-probe.c
- * move IDE disk code to ide-disk.c
- * add support for generic IDE device subdrivers
- * add m68k code from Geert Uytterhoeven
- * probe all interfaces by default
- * add ioctl to (re)probe an interface
- * Version 6.00 use per device request queues
- * attempt to optimize shared hwgroup performance
- * add ioctl to manually adjust bandwidth algorithms
- * add kerneld support for the probe module
- * fix bug in ide_error()
- * fix bug in the first ide_get_lock() call for Atari
- * don't flush leftover data for ATAPI devices
- * Version 6.01 clear hwgroup->active while the hwgroup sleeps
- * support HDIO_GETGEO for floppies
- * Version 6.02 fix ide_ack_intr() call
- * check partition table on floppies
- * Version 6.03 handle bad status bit sequencing in ide_wait_stat()
- * Version 6.10 deleted old entries from this list of updates
- * replaced triton.c with ide-dma.c generic PCI DMA
- * added support for BIOS-enabled UltraDMA
- * rename all "promise" things to "pdc4030"
- * fix EZ-DRIVE handling on small disks
- * Version 6.11 fix probe error in ide_scan_devices()
- * fix ancient "jiffies" polling bugs
- * mask all hwgroup interrupts on each irq entry
- * Version 6.12 integrate ioctl and proc interfaces
- * fix parsing of "idex=" command line parameter
- * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com
- * Version 6.14 fixed IRQ sharing among PCI devices
- * Version 6.15 added SMP awareness to IDE drivers
- * Version 6.16 fixed various bugs; even more SMP friendly
- * Version 6.17 fix for newest EZ-Drive problem
- * Version 6.18 default unpartitioned-disk translation now "BIOS LBA"
- * Version 6.19 Re-design for a UNIFORM driver for all platforms,
- * model based on suggestions from Russell King and
- * Geert Uytterhoeven
- * Promise DC4030VL now supported.
- * add support for ide6/ide7
- * delay_50ms() changed to ide_delay_50ms() and exported.
- * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection.
- * Added hdx=flash to allow for second flash disk
- * detection w/o the hang loop.
- * Added support for ide8/ide9
- * Added idex=ata66 for the quirky chipsets that are
- * ATA-66 compliant, but have yet to determine a method
- * of verification of the 80c cable presence.
- * Specifically Promise's PDC20262 chipset.
- * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old
- * hat that clarified original low level driver design.
- * Version 6.30 Added SMP support; fixed multmode issues. -ml
- * Version 6.31 Debug Share INTR's and request queue streaming
- * Native ATA-100 support
- * Prep for Cascades Project
- * Version 7.00alpha First named revision of ide rearrange
- *
- * Some additional driver compile-time options are in ./include/linux/ide.h
- *
- * To do, in likely order of completion:
- * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
*/
#define REVISION "Revision: 7.00alpha2"
@@ -455,6 +377,10 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->straight8 = tmp_hwif->straight8;
hwif->bus_state = tmp_hwif->bus_state;
+ hwif->host_flags = tmp_hwif->host_flags;
+
+ hwif->pio_mask = tmp_hwif->pio_mask;
+
hwif->atapi_dma = tmp_hwif->atapi_dma;
hwif->ultra_mask = tmp_hwif->ultra_mask;
hwif->mwdma_mask = tmp_hwif->mwdma_mask;
@@ -470,8 +396,9 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->cds = tmp_hwif->cds;
#endif
- hwif->tuneproc = tmp_hwif->tuneproc;
+ hwif->set_pio_mode = tmp_hwif->set_pio_mode;
hwif->speedproc = tmp_hwif->speedproc;
+ hwif->mdma_filter = tmp_hwif->mdma_filter;
hwif->udma_filter = tmp_hwif->udma_filter;
hwif->selectproc = tmp_hwif->selectproc;
hwif->reset_poll = tmp_hwif->reset_poll;
@@ -940,8 +867,9 @@ int set_pio_mode(ide_drive_t *drive, int arg)
if (arg < 0 || arg > 255)
return -EINVAL;
- if (!HWIF(drive)->tuneproc)
+ if (drive->hwif->set_pio_mode == NULL)
return -ENOSYS;
+
if (drive->special.b.set_tune)
return -EBUSY;
ide_init_drive_cmd(&rq);
@@ -988,6 +916,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ int ret;
/* Call ACPI _GTM only once */
if (!(drive->dn % 2))
@@ -1004,7 +933,14 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
mesg.event = PM_EVENT_FREEZE;
rqpm.pm_state = mesg.event;
- return ide_do_drive_cmd(drive, &rq, ide_wait);
+ ret = ide_do_drive_cmd(drive, &rq, ide_wait);
+ /* only call ACPI _PS3 after both drivers are suspended */
+ if (!ret && (((drive->dn % 2) && hwif->drives[0].present
+ && hwif->drives[1].present)
+ || !hwif->drives[0].present
+ || !hwif->drives[1].present))
+ ide_acpi_set_state(hwif, 0);
+ return ret;
}
static int generic_ide_resume(struct device *dev)
@@ -1017,8 +953,10 @@ static int generic_ide_resume(struct device *dev)
int err;
/* Call ACPI _STM only once */
- if (!(drive->dn % 2))
+ if (!(drive->dn % 2)) {
+ ide_acpi_set_state(hwif, 1);
ide_acpi_push_timing(hwif);
+ }
ide_acpi_exec_tfs(drive);
@@ -1171,10 +1109,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
return 0;
}
- case CDROMEJECT:
- case CDROMCLOSETRAY:
- return scsi_cmd_ioctl(file, bdev->bd_disk->queue, bdev->bd_disk, cmd, p);
-
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -1729,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = {
__ATTR_NULL
};
-static int ide_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
{
ide_drive_t *drive = to_ide_device(dev);
- int i = 0;
- int length = 0;
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MEDIA=%s", media_string(drive));
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "DRIVENAME=%s", drive->name);
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=ide:m-%s", media_string(drive));
- envp[i] = NULL;
+
+ add_uevent_var(env, "MEDIA=%s", media_string(drive));
+ add_uevent_var(env, "DRIVENAME=%s", drive->name);
+ add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
return 0;
}
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
index c7971061767e..409822349f10 100644
--- a/drivers/ide/legacy/Makefile
+++ b/drivers/ide/legacy/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
+obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o
+
# Last of all
obj-$(CONFIG_BLK_DEV_HD) += hd.o
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index df17ed68c0bc..2f0ef9b44033 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -68,8 +68,6 @@ static RegInitializer initData[] __initdata = {
{0x35, 0x03}, {0x00, 0x00}
};
-#define ALI_MAX_PIO 4
-
/* timing parameter registers for each drive */
static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
{0x03, 0x26, 0x04, 0x27}, /* drive 0 */
@@ -109,19 +107,16 @@ static void outReg (u8 data, u8 reg)
* This function computes timing parameters
* and sets controller registers accordingly.
*/
-static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int driveNum;
int time1, time2;
u8 param1, param2, param3, param4;
unsigned long flags;
- ide_pio_data_t d;
int bus_speed = system_bus_clock();
- pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
-
/* calculate timing, according to PIO mode */
- time1 = d.cycle_time;
+ time1 = ide_pio_cycle_time(drive, pio);
time2 = ide_pio_timings[pio].active_time;
param3 = param1 = (time2 * bus_speed + 999) / 1000;
param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
@@ -212,11 +207,13 @@ static int __init ali14xx_probe(void)
mate = &ide_hwifs[1];
hwif->chipset = ide_ali14xx;
- hwif->tuneproc = &ali14xx_tune_drive;
+ hwif->pio_mask = ATA_PIO4;
+ hwif->set_pio_mode = &ali14xx_set_pio_mode;
hwif->mate = mate;
mate->chipset = ide_ali14xx;
- mate->tuneproc = &ali14xx_tune_drive;
+ mate->pio_mask = ATA_PIO4;
+ mate->set_pio_mode = &ali14xx_set_pio_mode;
mate->mate = hwif;
mate->channel = 1;
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 36a3f0ac6162..f16521254867 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -67,12 +67,10 @@ static void sub22 (char b, char c)
}
}
-static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned long flags;
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
if (pio >= 3) {
spin_lock_irqsave(&ide_lock, flags);
/*
@@ -123,7 +121,8 @@ static int __init dtc2278_probe(void)
hwif->serialized = 1;
hwif->chipset = ide_dtc2278;
- hwif->tuneproc = &tune_dtc2278;
+ hwif->pio_mask = ATA_PIO4;
+ hwif->set_pio_mode = &dtc2278_set_pio_mode;
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
hwif->mate = mate;
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index e1e9d9d6893f..f0829b83e970 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -8,6 +8,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
@@ -54,6 +55,7 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
*/
int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
/*
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 8f2db8dd35f7..8e05d88e81ba 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -652,7 +652,7 @@ repeat:
}
}
-static void do_hd_request (request_queue_t * q)
+static void do_hd_request (struct request_queue * q)
{
disable_irq(HD_IRQ);
hd_request();
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index c8f353b1296f..2e5a9cc5c0f7 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -199,23 +199,24 @@ static int __init try_to_init_ht6560b(void)
return 1;
}
-static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
{
int active_time, recovery_time;
int active_cycles, recovery_cycles;
- ide_pio_data_t d;
int bus_speed = system_bus_clock();
if (pio) {
- pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-
+ unsigned int cycle_time;
+
+ cycle_time = ide_pio_cycle_time(drive, pio);
+
/*
* Just like opti621.c we try to calculate the
* actual cycle time for recovery and activity
* according system bus speed.
*/
active_time = ide_pio_timings[pio].active_time;
- recovery_time = d.cycle_time
+ recovery_time = cycle_time
- active_time
- ide_pio_timings[pio].setup_time;
/*
@@ -275,7 +276,7 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state)
#endif
}
-static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned long flags;
u8 timing;
@@ -331,13 +332,17 @@ int __init ht6560b_init(void)
hwif->chipset = ide_ht6560b;
hwif->selectproc = &ht6560b_selectproc;
- hwif->tuneproc = &tune_ht6560b;
+ hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
+ hwif->pio_mask = ATA_PIO5;
+ hwif->set_pio_mode = &ht6560b_set_pio_mode;
hwif->serialized = 1; /* is this needed? */
hwif->mate = mate;
mate->chipset = ide_ht6560b;
mate->selectproc = &ht6560b_selectproc;
- mate->tuneproc = &tune_ht6560b;
+ mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
+ mate->pio_mask = ATA_PIO5;
+ mate->set_pio_mode = &ht6560b_set_pio_mode;
mate->serialized = 1; /* is this needed? */
mate->mate = hwif;
mate->channel = 1;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 2f3977f195b7..4cdb519f9832 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -386,6 +386,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
new file mode 100644
index 000000000000..ccfb9893a467
--- /dev/null
+++ b/drivers/ide/legacy/ide_platform.c
@@ -0,0 +1,182 @@
+/*
+ * Platform IDE driver
+ *
+ * Copyright (C) 2007 MontaVista Software
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/pata_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+static struct {
+ void __iomem *plat_ide_mapbase;
+ void __iomem *plat_ide_alt_mapbase;
+ ide_hwif_t *hwif;
+ int index;
+} hwif_prop;
+
+static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
+ void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
+ int mmio)
+{
+ unsigned long port = (unsigned long)base;
+ ide_hwif_t *hwif;
+ int index, i;
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = ide_hwifs + index;
+ if (hwif->io_ports[IDE_DATA_OFFSET] == port)
+ goto found;
+ }
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = ide_hwifs + index;
+ if (hwif->io_ports[IDE_DATA_OFFSET] == 0)
+ goto found;
+ }
+
+ return NULL;
+
+found:
+
+ hwif->hw.io_ports[IDE_DATA_OFFSET] = port;
+
+ port += (1 << pdata->ioport_shift);
+ for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
+ i++, port += (1 << pdata->ioport_shift))
+ hwif->hw.io_ports[i] = port;
+
+ hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+ hwif->hw.irq = hwif->irq = irq;
+
+ hwif->hw.dma = NO_DMA;
+ hwif->hw.chipset = ide_generic;
+
+ if (mmio) {
+ hwif->mmio = 1;
+ default_hwif_mmiops(hwif);
+ }
+
+ hwif_prop.hwif = hwif;
+ hwif_prop.index = index;
+
+ return hwif;
+}
+
+static int __devinit plat_ide_probe(struct platform_device *pdev)
+{
+ struct resource *res_base, *res_alt, *res_irq;
+ ide_hwif_t *hwif;
+ struct pata_platform_info *pdata;
+ int ret = 0;
+ int mmio = 0;
+
+ pdata = pdev->dev.platform_data;
+
+ /* get a pointer to the register memory */
+ res_base = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1);
+
+ if (!res_base || !res_alt) {
+ res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_base || !res_alt) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ mmio = 1;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (mmio) {
+ hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev,
+ res_base->start, res_base->end - res_base->start + 1);
+ hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev,
+ res_alt->start, res_alt->end - res_alt->start + 1);
+ } else {
+ hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev,
+ res_base->start, res_base->end - res_base->start + 1);
+ hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev,
+ res_alt->start, res_alt->end - res_alt->start + 1);
+ }
+
+ hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
+ hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
+
+ if (!hwif) {
+ ret = -ENODEV;
+ goto out;
+ }
+ hwif->gendev.parent = &pdev->dev;
+ hwif->noprobe = 0;
+
+ probe_hwif_init(hwif);
+
+ platform_set_drvdata(pdev, hwif);
+ ide_proc_register_port(hwif);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int __devexit plat_ide_remove(struct platform_device *pdev)
+{
+ ide_hwif_t *hwif = pdev->dev.driver_data;
+
+ if (hwif != hwif_prop.hwif) {
+ dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error",
+ pdev->name);
+ } else {
+ ide_unregister(hwif_prop.index);
+ hwif_prop.index = 0;
+ hwif_prop.hwif = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver platform_ide_driver = {
+ .driver = {
+ .name = "pata_platform",
+ },
+ .probe = plat_ide_probe,
+ .remove = __devexit_p(plat_ide_remove),
+};
+
+static int __init platform_ide_init(void)
+{
+ return platform_driver_register(&platform_ide_driver);
+}
+
+static void __exit platform_ide_exit(void)
+{
+ platform_driver_unregister(&platform_ide_driver);
+}
+
+MODULE_DESCRIPTION("Platform IDE driver");
+MODULE_LICENSE("GPL");
+
+module_init(platform_ide_init);
+module_exit(platform_ide_exit);
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 7783745dd167..0c81d2d0b941 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -224,15 +224,14 @@ static void qd_set_timing (ide_drive_t *drive, u8 timing)
printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
}
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
+ /*
+ * FIXME: use "pio" value
+ */
if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
&& drive->id->tPIO && (drive->id->field_valid & 0x02)
&& drive->id->eide_pio >= 240) {
@@ -246,44 +245,39 @@ static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
}
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- ide_pio_data_t d;
int base = HWIF(drive)->select_data;
+ unsigned int cycle_time;
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
- pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+ cycle_time = ide_pio_cycle_time(drive, pio);
switch (pio) {
case 0: break;
case 3:
- if (d.cycle_time >= 110) {
+ if (cycle_time >= 110) {
active_time = 86;
- recovery_time = d.cycle_time - 102;
+ recovery_time = cycle_time - 102;
} else
printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
break;
case 4:
- if (d.cycle_time >= 69) {
+ if (cycle_time >= 69) {
active_time = 70;
- recovery_time = d.cycle_time - 61;
+ recovery_time = cycle_time - 61;
} else
printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
break;
default:
- if (d.cycle_time >= 180) {
+ if (cycle_time >= 180) {
active_time = 110;
- recovery_time = d.cycle_time - 120;
+ recovery_time = cycle_time - 120;
} else {
active_time = ide_pio_timings[pio].active_time;
- recovery_time = d.cycle_time
- -active_time;
+ recovery_time = cycle_time - active_time;
}
}
printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
@@ -335,8 +329,7 @@ static int __init qd_testreg(int port)
*/
static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
- unsigned int data0, unsigned int data1,
- void (*tuneproc) (ide_drive_t *, u8 pio))
+ unsigned int data0, unsigned int data1)
{
hwif->chipset = ide_qd65xx;
hwif->channel = hwif->index;
@@ -346,8 +339,7 @@ static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
hwif->drives[1].drive_data = data1;
hwif->drives[0].io_32bit =
hwif->drives[1].io_32bit = 1;
- hwif->tuneproc = tuneproc;
- probe_hwif_init(hwif);
+ hwif->pio_mask = ATA_PIO4;
}
/*
@@ -360,7 +352,7 @@ static void __exit qd_unsetup(ide_hwif_t *hwif)
{
u8 config = hwif->config_data;
int base = hwif->select_data;
- void *tuneproc = (void *) hwif->tuneproc;
+ void *set_pio_mode = (void *)hwif->set_pio_mode;
if (hwif->chipset != ide_qd65xx)
return;
@@ -368,12 +360,12 @@ static void __exit qd_unsetup(ide_hwif_t *hwif)
printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
hwif->selectproc = NULL;
- hwif->tuneproc = NULL;
+ hwif->set_pio_mode = NULL;
- if (tuneproc == (void *) qd6500_tune_drive) {
+ if (set_pio_mode == (void *)qd6500_set_pio_mode) {
// will do it for both
qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
- } else if (tuneproc == (void *) qd6580_tune_drive) {
+ } else if (set_pio_mode == (void *)qd6580_set_pio_mode) {
if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
@@ -423,8 +415,11 @@ static int __init qd_probe(int base)
return 1;
}
- qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
- &qd6500_tune_drive);
+ qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA);
+
+ hwif->set_pio_mode = &qd6500_set_pio_mode;
+
+ probe_hwif_init(hwif);
ide_proc_register_port(hwif);
@@ -454,8 +449,12 @@ static int __init qd_probe(int base)
printk(KERN_INFO "%s: qd6580: single IDE board\n",
hwif->name);
qd_setup(hwif, base, config | (control << 8),
- QD6580_DEF_DATA, QD6580_DEF_DATA2,
- &qd6580_tune_drive);
+ QD6580_DEF_DATA, QD6580_DEF_DATA2);
+
+ hwif->set_pio_mode = &qd6580_set_pio_mode;
+
+ probe_hwif_init(hwif);
+
qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
ide_proc_register_port(hwif);
@@ -471,11 +470,19 @@ static int __init qd_probe(int base)
hwif->name, mate->name);
qd_setup(hwif, base, config | (control << 8),
- QD6580_DEF_DATA, QD6580_DEF_DATA,
- &qd6580_tune_drive);
+ QD6580_DEF_DATA, QD6580_DEF_DATA);
+
+ hwif->set_pio_mode = &qd6580_set_pio_mode;
+
+ probe_hwif_init(hwif);
+
qd_setup(mate, base, config | (control << 8),
- QD6580_DEF_DATA2, QD6580_DEF_DATA2,
- &qd6580_tune_drive);
+ QD6580_DEF_DATA2, QD6580_DEF_DATA2);
+
+ mate->set_pio_mode = &qd6580_set_pio_mode;
+
+ probe_hwif_init(mate);
+
qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
ide_proc_register_port(hwif);
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index ddc403a0bd82..1151c92dd531 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -105,12 +105,11 @@ static void umc_set_speeds (u8 speeds[])
speeds[0], speeds[1], speeds[2], speeds[3]);
}
-static void tune_umc (ide_drive_t *drive, u8 pio)
+static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
drive->name, pio, pio_to_umc[pio]);
spin_lock_irqsave(&ide_lock, flags);
@@ -149,11 +148,13 @@ static int __init umc8672_probe(void)
mate = &ide_hwifs[1];
hwif->chipset = ide_umc8672;
- hwif->tuneproc = &tune_umc;
+ hwif->pio_mask = ATA_PIO4;
+ hwif->set_pio_mode = &umc_set_pio_mode;
hwif->mate = mate;
mate->chipset = ide_umc8672;
- mate->tuneproc = &tune_umc;
+ mate->pio_mask = ATA_PIO4;
+ mate->set_pio_mode = &umc_set_pio_mode;
mate->mate = hwif;
mate->channel = 1;
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 2e7013a2a7f6..85819ae20602 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -99,18 +99,12 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
#endif
-static void auide_tune_drive(ide_drive_t *drive, byte pio)
+static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int mem_sttime;
int mem_stcfg;
u8 speed;
- /* get the best pio mode for the drive */
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
- printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",
- drive->name, pio);
-
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
@@ -175,7 +169,7 @@ static void auide_tune_drive(ide_drive_t *drive, byte pio)
ide_config_drive_speed(drive, speed);
}
-static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
+static int auide_tune_chipset(ide_drive_t *drive, const u8 speed)
{
int mem_sttime;
int mem_stcfg;
@@ -183,11 +177,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
- if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
- auide_tune_drive(drive, speed - XFER_PIO_0);
- return 0;
- }
-
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
case XFER_MW_DMA_2:
@@ -692,6 +681,8 @@ static int au_ide_probe(struct device *dev)
hwif->swdma_mask = 0x0;
#endif
+ hwif->pio_mask = ATA_PIO4;
+
hwif->noprobe = 0;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
@@ -710,7 +701,7 @@ static int au_ide_probe(struct device *dev)
hwif->OUTSW = auide_outsw;
#endif
- hwif->tuneproc = &auide_tune_drive;
+ hwif->set_pio_mode = &au1xxx_set_pio_mode;
hwif->speedproc = &auide_tune_chipset;
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 6e935d7c63fd..c2e29571b007 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -165,12 +165,11 @@ static int __devinit swarm_ide_init_module(void)
goto out;
}
- if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) {
+ if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) {
err = -ENOMEM;
goto out_unregister_driver;
}
- memset (pldev, 0, sizeof (*pldev));
pldev->name = swarm_ide_string;
pldev->id = 0;
pldev->dev.release = swarm_ide_platform_release;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index e5d09367627e..0d5f62c5dfae 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -87,12 +87,11 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
return chipset_table->ultra_settings;
}
-static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u16 d_conf = 0;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 ultra = 0, ultra_conf = 0;
u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
unsigned long flags;
@@ -115,11 +114,10 @@ static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
return(ide_config_drive_speed(drive, speed));
}
-static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 unit = (drive->select.b.unit & 0x01);
u8 tmp1 = 0, tmp2 = 0;
u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
@@ -140,9 +138,8 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
return(ide_config_drive_speed(drive, speed));
}
-static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
(void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
}
@@ -152,7 +149,7 @@ static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- aec62xx_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -174,12 +171,6 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
{
int bus_speed = system_bus_clock();
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
-
if (bus_speed <= 33)
pci_set_drvdata(dev, (void *) aec6xxx_33_base);
else
@@ -209,7 +200,7 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
u8 reg54 = 0, mask = hwif->channel ? 0xf0 : 0x0f;
unsigned long flags;
- hwif->tuneproc = &aec62xx_tune_drive;
+ hwif->set_pio_mode = &aec_set_pio_mode;
if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
if(hwif->mate)
@@ -271,48 +262,48 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
.init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x07, /* udma0-2 */
},{ /* 1 */
.name = "AEC6260",
.init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 2 */
.name = "AEC6260R",
.init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = NEVER_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 3 */
.name = "AEC6280",
.init_setup = init_setup_aec6x80,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 4 */
.name = "AEC6280R",
.init_setup = init_setup_aec6x80,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
}
};
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index ba0fb92b0417..d04b966b4347 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/alim15x3.c Version 0.25 Jun 9 2007
+ * linux/drivers/ide/pci/alim15x3.c Version 0.26 Jul 14 2007
*
* Copyright (C) 1998-2000 Michel Aubry, Maintainer
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -283,19 +283,15 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
/**
- * ali15x3_tune_pio - set up chipset for PIO mode
- * @drive: drive to tune
- * @pio: desired mode
+ * ali_tune_pio - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
- * Select the best PIO mode for the drive in question.
- * Then program the controller for this mode.
- *
- * Returns the PIO mode programmed.
+ * Program the controller for the given PIO mode.
*/
-
-static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
+
+static void ali_tune_pio(ide_drive_t *drive, const u8 pio)
{
- ide_pio_data_t d;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
int s_time, a_time, c_time;
@@ -307,7 +303,6 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
u8 cd_dma_fifo = 0;
int unit = drive->select.b.unit & 1;
- pio = ide_get_best_pio_mode(drive, pio, 5, &d);
s_time = ide_pio_timings[pio].setup_time;
a_time = ide_pio_timings[pio].active_time;
if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
@@ -360,22 +355,20 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
* { 25, 70, 25 }, PIO Mode 4 with IORDY ns
* { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
*/
-
- return pio;
}
/**
- * ali15x3_tune_drive - set up drive for PIO mode
+ * ali_set_pio_mode - set up drive for PIO mode
* @drive: drive to tune
* @pio: desired mode
*
- * Program the controller with the best PIO timing for the given drive.
+ * Program the controller with the desired PIO timing for the given drive.
* Then set up the drive itself.
*/
-static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ali15x3_tune_pio(drive, pio);
+ ali_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
@@ -410,22 +403,24 @@ static u8 ali_udma_filter(ide_drive_t *drive)
/**
* ali15x3_tune_chipset - set up chipset/drive for new speed
* @drive: drive to configure for
- * @xferspeed: desired speed
+ * @speed: desired speed
*
* Configure the hardware for the desired IDE transfer mode.
* We also do the needed drive configuration through helpers
*/
-
-static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 speed1 = speed;
u8 unit = (drive->select.b.unit & 0x01);
u8 tmpbyte = 0x00;
int m5229_udma = (hwif->channel) ? 0x57 : 0x56;
+ if (speed < XFER_PIO_0)
+ return 1;
+
if (speed == XFER_UDMA_6)
speed1 = 0x47;
@@ -438,8 +433,9 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
tmpbyte &= ultra_enable;
pci_write_config_byte(dev, m5229_udma, tmpbyte);
- if (speed < XFER_SW_DMA_0)
- (void) ali15x3_tune_pio(drive, speed - XFER_PIO_0);
+ /*
+ * FIXME: Oh, my... DMA timings are never set.
+ */
} else {
pci_read_config_byte(dev, m5229_udma, &tmpbyte);
tmpbyte &= (0x0f << ((1-unit) << 2));
@@ -472,7 +468,7 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
if (ide_tune_dma(drive))
return 0;
- ali15x3_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -589,12 +585,19 @@ out:
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "HP Pavilion N5430",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+ DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
+ },
+ },
+ {
+ .ident = "Toshiba Satellite S1800-814",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
},
},
{ }
@@ -695,7 +698,7 @@ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
{
hwif->autodma = 0;
- hwif->tuneproc = &ali15x3_tune_drive;
+ hwif->set_pio_mode = &ali_set_pio_mode;
hwif->speedproc = &ali15x3_tune_chipset;
hwif->udma_filter = &ali_udma_filter;
@@ -817,9 +820,9 @@ static ide_pci_device_t ali15x3_chipset __devinitdata = {
.init_chipset = init_chipset_ali15x3,
.init_hwif = init_hwif_ali15x3,
.init_dma = init_dma_ali15x3,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
};
/**
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 8d30b99a54d8..513205e52ad2 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -1,5 +1,5 @@
/*
- * Version 2.20
+ * Version 2.22
*
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
* IDE driver for Linux.
@@ -234,7 +234,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
* by upper layers.
*/
-static int amd_set_drive(ide_drive_t *drive, u8 speed)
+static int amd_set_drive(ide_drive_t *drive, const u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
struct ide_timing t, p;
@@ -266,32 +266,21 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
}
/*
- * amd74xx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
+ * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
*/
-static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- if (pio == 255) {
- amd_set_drive(drive, ide_find_best_pio_mode(drive));
- return;
- }
-
- amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
+ amd_set_drive(drive, XFER_PIO_0 + pio);
}
static int amd74xx_ide_dma_check(ide_drive_t *drive)
{
- u8 speed = ide_max_dma_mode(drive);
-
- if (speed == 0)
- speed = ide_find_best_pio_mode(drive);
-
- amd_set_drive(drive, speed);
-
- if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ if (ide_tune_dma(drive))
return 0;
+ ide_set_max_pio(drive);
+
return -1;
}
@@ -409,7 +398,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
hwif->autodma = 0;
- hwif->tuneproc = &amd74xx_tune_drive;
+ hwif->set_pio_mode = &amd_set_pio_mode;
hwif->speedproc = &amd_set_drive;
for (i = 0; i < 2; i++) {
@@ -448,10 +437,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
- .channels = 2, \
.autodma = AUTODMA, \
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
+ | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ .pio_mask = ATA_PIO5, \
}
#define DECLARE_NV_DEV(name_str) \
@@ -459,10 +450,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
- .channels = 2, \
.autodma = AUTODMA, \
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
+ | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ .pio_mask = ATA_PIO5, \
}
static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 2761510309b3..178876a3afca 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -1,9 +1,8 @@
/*
- * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004
+ * linux/drivers/ide/pci/atiixp.c Version 0.02 Jun 16 2007
*
* Copyright (C) 2003 ATI Inc. <hyu@ati.com>
- * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
- *
+ * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
*/
#include <linux/types.h>
@@ -123,14 +122,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
}
/**
- * atiixp_tune_drive - tune a drive attached to a ATIIXP
+ * atiixp_tune_pio - tune a drive attached to a ATIIXP
* @drive: drive to tune
* @pio: desired PIO mode
*
* Set the interface PIO mode.
*/
-static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -154,26 +153,30 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&atiixp_lock, flags);
}
+static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ atiixp_tune_pio(drive, pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
/**
* atiixp_tune_chipset - tune a ATIIXP interface
* @drive: IDE drive to tune
- * @xferspeed: speed to configure
+ * @speed: speed to configure
*
* Set a ATIIXP interface channel to the desired speeds. This involves
* requires the right timing data into the ATIIXP configuration space
* then setting the drive parameters appropriately
*/
-static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
+static int atiixp_speedproc(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
u32 tmp32;
u16 tmp16;
- u8 speed, pio;
-
- speed = ide_rate_filter(drive, xferspeed);
+ u8 pio;
spin_lock_irqsave(&atiixp_lock, flags);
@@ -201,7 +204,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
else
pio = speed - XFER_PIO_0;
- atiixp_tuneproc(drive, pio);
+ atiixp_tune_pio(drive, pio);
return ide_config_drive_speed(drive, speed);
}
@@ -216,18 +219,13 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
static int atiixp_dma_check(ide_drive_t *drive)
{
- u8 tspeed, speed;
-
drive->init_speed = 0;
if (ide_tune_dma(drive))
return 0;
- if (ide_use_fast_pio(drive)) {
- tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
- speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
- atiixp_speedproc(drive, speed);
- }
+ if (ide_use_fast_pio(drive))
+ ide_set_max_pio(drive);
return -1;
}
@@ -250,7 +248,7 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
hwif->irq = ch ? 15 : 14;
hwif->autodma = 0;
- hwif->tuneproc = &atiixp_tuneproc;
+ hwif->set_pio_mode = &atiixp_set_pio_mode;
hwif->speedproc = &atiixp_speedproc;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -285,17 +283,18 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.name = "ATIIXP",
.init_hwif = init_hwif_atiixp,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 1 */
.name = "SB600_PATA",
.init_hwif = init_hwif_atiixp,
- .channels = 1,
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
},
};
@@ -318,7 +317,7 @@ static struct pci_device_id atiixp_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index dc43f009acab..f369645e4d16 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -628,50 +628,42 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
program_drive_counts (index);
}
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
+ unsigned int index = 0, cycle_time;
u8 b;
- ide_pio_data_t d;
- unsigned int index = 0;
while (drive != cmd_drives[index]) {
if (++index > 3) {
- printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+ printk(KERN_ERR "%s: bad news in %s\n",
+ drive->name, __FUNCTION__);
return;
}
}
- switch (mode_wanted) {
+ switch (pio) {
case 6: /* set fast-devsel off */
case 7: /* set fast-devsel on */
- mode_wanted &= 1;
b = get_cmd640_reg(CNTRL) & ~0x27;
- if (mode_wanted)
+ if (pio & 1)
b |= 0x27;
put_cmd640_reg(CNTRL, b);
- printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+ printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, (pio & 1) ? "en" : "dis");
return;
case 8: /* set prefetch off */
case 9: /* set prefetch on */
- mode_wanted &= 1;
- set_prefetch_mode(index, mode_wanted);
- printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+ set_prefetch_mode(index, pio & 1);
+ printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis");
return;
}
- (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
- cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ cmd640_set_mode(index, pio, cycle_time);
+
+ printk("%s: selected cmd640 PIO mode%d (%dns)",
+ drive->name, pio, cycle_time);
- printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
- drive->name,
- d.pio_mode,
- d.cycle_time,
- d.overridden ? " (overriding vendor mode)" : "");
display_clocks(index);
- return;
}
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -769,7 +761,10 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
cmd_hwif0->chipset = ide_cmd640;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- cmd_hwif0->tuneproc = &cmd640_tune_drive;
+ cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
+ IDE_HFLAG_ABUSE_FAST_DEVSEL;
+ cmd_hwif0->pio_mask = ATA_PIO5;
+ cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
/*
@@ -824,7 +819,10 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif1->mate = cmd_hwif0;
cmd_hwif1->channel = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- cmd_hwif1->tuneproc = &cmd640_tune_drive;
+ cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
+ IDE_HFLAG_ABUSE_FAST_DEVSEL;
+ cmd_hwif1->pio_mask = ATA_PIO5;
+ cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
}
printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 1e89dd6e5bbf..0b568c60f926 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -214,27 +214,25 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
}
/*
- * This routine selects drive's best PIO mode and writes into the chipset
- * registers setup/active/recovery timings.
+ * This routine writes into the chipset registers
+ * PIO setup/active/recovery timings.
*/
-static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
+static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- ide_pio_data_t pio;
- u8 pio_mode, setup_count, arttim = 0;
+ unsigned int cycle_time;
+ u8 setup_count, arttim = 0;
+
static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
- pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
- cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
- drive->name, mode_wanted, pio_mode, pio.cycle_time,
- pio.overridden ? " (overriding vendor mode)" : "");
+ cycle_time = ide_pio_cycle_time(drive, pio);
- program_cycle_times(drive, pio.cycle_time,
- ide_pio_timings[pio_mode].active_time);
+ program_cycle_times(drive, cycle_time,
+ ide_pio_timings[pio].active_time);
- setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
+ setup_count = quantize_timing(ide_pio_timings[pio].setup_time,
1000 / system_bus_clock());
/*
@@ -265,16 +263,14 @@ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
arttim |= setup_values[setup_count];
(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
-
- return pio_mode;
}
/*
* Attempts to set drive's PIO mode.
- * Special cases are 8: prefetch off, 9: prefetch on (both never worked),
- * and 255: auto-select best mode (used at boot time).
+ * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
*/
-static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
+
+static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
/*
* Filter out the prefetch control values
@@ -283,19 +279,17 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
if (pio == 8 || pio == 9)
return;
- pio = cmd64x_tune_pio(drive, pio);
+ cmd64x_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
+static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 unit = drive->dn & 0x01;
u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
- speed = ide_rate_filter(drive, speed);
-
if (speed >= XFER_SW_DMA_0) {
(void) pci_read_config_byte(dev, pciU, &regU);
regU &= ~(unit ? 0xCA : 0x35);
@@ -329,14 +323,6 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
case XFER_MW_DMA_0:
program_cycle_times(drive, 480, 215);
break;
- case XFER_PIO_5:
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
- break;
default:
return 1;
}
@@ -353,7 +339,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- cmd64x_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -474,11 +460,11 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
switch (rev) {
case 0x07:
case 0x05:
- printk("%s: UltraDMA capable", name);
+ printk("%s: UltraDMA capable\n", name);
break;
case 0x03:
default:
- printk("%s: MultiWord DMA force limited", name);
+ printk("%s: MultiWord DMA force limited\n", name);
break;
case 0x01:
printk("%s: MultiWord DMA limited, "
@@ -537,7 +523,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- hwif->tuneproc = &cmd64x_tune_drive;
+ hwif->set_pio_mode = &cmd64x_set_pio_mode;
hwif->speedproc = &cmd64x_tune_chipset;
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
@@ -618,40 +604,44 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
.init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x00, /* no udma */
},{ /* 1 */
.name = "CMD646",
.init_setup = init_setup_cmd646,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x07, /* udma0-2 */
},{ /* 2 */
.name = "CMD648",
.init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 3 */
.name = "CMD649",
.init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x3f, /* udma0-5 */
}
};
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 3b88a3a56116..1217d2a747fb 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -66,32 +66,13 @@ static struct pio_clocks cs5520_pio_clocks[]={
{1, 2, 1}
};
-static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *pdev = hwif->pci_dev;
- u8 speed = min((u8)XFER_PIO_4, xferspeed);
- int pio = speed;
- u8 reg;
int controller = drive->dn > 1 ? 1 : 0;
- int error;
-
- switch(speed)
- {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- pio -= XFER_PIO_0;
- break;
- default:
- pio = 0;
- printk(KERN_ERR "cs55x0: bad ide timing.\n");
- }
-
- printk("PIO clocking = %d\n", pio);
-
+ u8 reg;
+
/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
/* 8bit CAT/CRT - 8bit command timing for channel */
@@ -115,25 +96,28 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
reg = inb(hwif->dma_base + 0x02 + 8*controller);
reg |= 1<<((drive->dn&1)+5);
outb(reg, hwif->dma_base + 0x02 + 8*controller);
-
- error = ide_config_drive_speed(drive, speed);
- /* ATAPI is harder so leave it for now */
- if(!error && drive->media == ide_disk)
- error = hwif->ide_dma_on(drive);
- return error;
-}
-
-static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
+static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
- cs5520_tune_chipset(drive, (XFER_PIO_0 + pio));
+ printk(KERN_ERR "cs55x0: bad ide timing.\n");
+
+ cs5520_set_pio_mode(drive, 0);
+
+ /*
+ * FIXME: this is incorrect to return zero here but
+ * since all users of ide_set_xfer_rate() ignore
+ * the return value it is not a problem currently
+ */
+ return 0;
}
static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
{
/* Tune the drive for PIO modes up to PIO 4 */
- cs5520_tune_drive(drive, 4);
+ ide_set_max_pio(drive);
/* Then tell the core to use DMA operations */
return 0;
@@ -165,7 +149,7 @@ static int cs5520_dma_on(ide_drive_t *drive)
static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
{
- hwif->tuneproc = &cs5520_tune_drive;
+ hwif->set_pio_mode = &cs5520_set_pio_mode;
hwif->speedproc = &cs5520_tune_chipset;
hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
hwif->ide_dma_on = &cs5520_dma_on;
@@ -179,7 +163,8 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
hwif->drives[1].autotune = 1;
return;
}
-
+
+ /* ATAPI is harder so leave it for now */
hwif->atapi_dma = 0;
hwif->ultra_mask = 0;
hwif->swdma_mask = 0;
@@ -194,10 +179,10 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
.name = name_str, \
.init_setup_dma = cs5520_init_setup_dma, \
.init_hwif = init_hwif_cs5520, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
- .flags = IDEPCI_FLAG_ISA_PORTS, \
+ .host_flags = IDE_HFLAG_ISA_PORTS, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index b5c00d15a704..741507b4cd93 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/cs5530.c Version 0.73 Mar 10 2007
+ * linux/drivers/ide/pci/cs5530.c Version 0.74 Jul 28 2007
*
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
@@ -71,19 +71,18 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
}
/**
- * cs5530_tuneproc - select/set PIO modes
+ * cs5530_set_pio_mode - set PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
- * cs5530_tuneproc() handles selection/setting of PIO modes
- * for both the chipset and drive.
+ * Handles setting of PIO mode for both the chipset and drive.
*
- * The ide_init_cs5530() routine guarantees that all drives
+ * The init_hwif_cs5530() routine guarantees that all drives
* will have valid default PIO timings set up before we get here.
*/
-static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */
+static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
cs5530_tunepio(drive, pio);
}
@@ -143,13 +142,11 @@ static int cs5530_config_dma(ide_drive_t *drive)
return 1;
}
-static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
+static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode)
{
unsigned long basereg;
unsigned int reg, timings = 0;
- mode = ide_rate_filter(drive, mode);
-
/*
* Tell the drive to switch to the new mode; abort on failure.
*/
@@ -166,13 +163,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
case XFER_MW_DMA_0: timings = 0x00077771; break;
case XFER_MW_DMA_1: timings = 0x00012121; break;
case XFER_MW_DMA_2: timings = 0x00002020; break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- cs5530_tunepio(drive, mode - XFER_PIO_0);
- return 0;
default:
BUG();
break;
@@ -207,6 +197,9 @@ static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const ch
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
unsigned long flags;
+ if (pci_resource_start(dev, 4) == 0)
+ return -EFAULT;
+
dev = NULL;
while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
switch (dev->device) {
@@ -305,7 +298,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
- hwif->tuneproc = &cs5530_tuneproc;
+ hwif->set_pio_mode = &cs5530_set_pio_mode;
hwif->speedproc = &cs5530_tune_chipset;
basereg = CS5530_BASEREG(hwif);
@@ -325,6 +318,9 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
/* needs autotuning later */
}
+ if (hwif->dma_base == 0)
+ return;
+
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x07;
hwif->mwdma_mask = 0x07;
@@ -341,9 +337,9 @@ static ide_pci_device_t cs5530_chipset __devinitdata = {
.name = "CS5530",
.init_chipset = init_chipset_cs5530,
.init_hwif = init_hwif_cs5530,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 10f61f38243c..383b7eccbcbb 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -2,6 +2,7 @@
* linux/drivers/ide/pci/cs5535.c
*
* Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
*
* History:
* 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
@@ -74,7 +75,7 @@ static unsigned int cs5535_udma_timings[5] =
*
* cs5535_set_speed() configures the chipset to a new speed.
*/
-static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
+static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
{
u32 reg = 0, dummy;
@@ -83,14 +84,17 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
/* Set the PIO timings */
if ((speed & XFER_MODE) == XFER_PIO) {
- u8 pioa;
- u8 piob;
- u8 cmd;
+ ide_drive_t *pair = &drive->hwif->drives[drive->dn ^ 1];
+ u8 cmd, pioa;
- pioa = speed - XFER_PIO_0;
- piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]),
- 255, 4, NULL);
- cmd = pioa < piob ? pioa : piob;
+ cmd = pioa = speed - XFER_PIO_0;
+
+ if (pair->present) {
+ u8 piob = ide_get_best_pio_mode(pair, 255, 4);
+
+ if (piob < cmd)
+ cmd = piob;
+ }
/* Write the speed of the current drive */
reg = (cs5535_pio_cmd_timings[cmd] << 16) |
@@ -116,7 +120,7 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
reg &= 0x80000000UL; /* Preserve the PIO format bit */
- if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7)
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4)
reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
@@ -137,46 +141,35 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
*/
static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
{
- speed = ide_rate_filter(drive, speed);
ide_config_drive_speed(drive, speed);
cs5535_set_speed(drive, speed);
return 0;
}
-/****
- * cs5535_tuneproc - PIO setup
- * @drive: drive to set up
- * @pio: mode to use (255 for 'best possible')
+/**
+ * cs5535_set_pio_mode - PIO setup
+ * @drive: drive
+ * @pio: PIO mode number
*
* A callback from the upper layers for PIO-only tuning.
*/
-static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
+
+static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- u8 modes[] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3,
- XFER_PIO_4 };
-
- /* cs5535 max pio is pio 4, best_pio will check the blacklist.
- i think we don't need to rate_filter the incoming xferspeed
- since we know we're only going to choose pio */
- xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL);
- ide_config_drive_speed(drive, modes[xferspeed]);
- cs5535_set_speed(drive, xferspeed);
+ ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+ cs5535_set_speed(drive, XFER_PIO_0 + pio);
}
static int cs5535_dma_check(ide_drive_t *drive)
{
- u8 speed;
-
drive->init_speed = 0;
if (ide_tune_dma(drive))
return 0;
- if (ide_use_fast_pio(drive)) {
- speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
- cs5535_set_drive(drive, speed);
- }
+ if (ide_use_fast_pio(drive))
+ ide_set_max_pio(drive);
return -1;
}
@@ -205,7 +198,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
hwif->autodma = 0;
- hwif->tuneproc = &cs5535_tuneproc;
+ hwif->set_pio_mode = &cs5535_set_pio_mode;
hwif->speedproc = &cs5535_set_drive;
hwif->ide_dma_check = &cs5535_dma_check;
@@ -228,9 +221,10 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
static ide_pci_device_t cs5535_chipset __devinitdata = {
.name = "CS5535",
.init_hwif = init_hwif_cs5535,
- .channels = 1,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
};
static int __devinit cs5535_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 103b9db97853..dc278025d318 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -97,9 +97,6 @@
#define CY82_INDEX_CHANNEL1 0x31
#define CY82_INDEX_TIMEOUT 0x32
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO 4
-
/* the min and max PCI bus speed in MHz - from datasheet */
#define CY82C963_MIN_BUS_SPEED 25
#define CY82C963_MAX_BUS_SPEED 33
@@ -148,9 +145,6 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
* so you can play with the idebus=xx parameter
*/
- if (pio > CY82C693_MAX_PIO)
- pio = CY82C693_MAX_PIO;
-
/* let's calc the address setup time clocks */
p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
@@ -269,10 +263,7 @@ static int cy82c693_ide_dma_on (ide_drive_t *drive)
return __ide_dma_on(drive);
}
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -329,13 +320,6 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
#endif /* CY82C693_DEBUG_LOGS */
- /* first let's calc the pio modes */
- pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
-
-#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
/* let's calc the values for this PIO mode */
compute_clocks(pio, &pclk);
@@ -447,7 +431,7 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->chipset = ide_cy82c693;
- hwif->tuneproc = &cy82c693_tune_drive;
+ hwif->set_pio_mode = &cy82c693_set_pio_mode;
if (!hwif->dma_base) {
hwif->drives[0].autotune = 1;
@@ -483,9 +467,10 @@ static ide_pci_device_t cy82c693_chipset __devinitdata = {
.init_chipset = init_chipset_cy82c693,
.init_iops = init_iops_cy82c693,
.init_hwif = init_hwif_cy82c693,
- .channels = 1,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
};
static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 0d51a11e81da..48caa468b762 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -95,92 +95,77 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = {
{ /* 0 */
.name = "Unknown",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 1 */
.name = "NS87410",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
.bootable = ON_BOARD,
},{ /* 2 */
.name = "SAMURAI",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 3 */
.name = "HT6565",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 4 */
.name = "UM8673F",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
},{ /* 5 */
.name = "UM8886A",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
},{ /* 6 */
.name = "UM8886BF",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
},{ /* 7 */
.name = "HINT_IDE",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 8 */
.name = "VIA_IDE",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 9 */
.name = "OPTI621V",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 10 */
.name = "VIA8237SATA",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
},{ /* 11 */
.name = "Piccolo0102",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 12 */
.name = "Piccolo0103",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 13 */
.name = "Piccolo0105",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 14 */
.name = "Revolution",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
}
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 2c24c3de8846..a1bb10188fe5 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -43,10 +43,9 @@
#define HPT343_DEBUG_DRIVE_INFO 0
-static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
u8 hi_speed, lo_speed;
@@ -78,9 +77,8 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
return(ide_config_drive_speed(drive, speed));
}
-static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
}
@@ -89,14 +87,10 @@ static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
drive->init_speed = 0;
if (ide_tune_dma(drive))
-#ifndef CONFIG_HPT34X_AUTODMA
return -1;
-#else
- return 0;
-#endif
if (ide_use_fast_pio(drive))
- hpt34x_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -120,17 +114,10 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
- if (cmd & PCI_COMMAND_MEMORY) {
- if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
+ if (cmd & PCI_COMMAND_MEMORY)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
- } else {
+ else
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
- }
/*
* Since 20-23 can be assigned and are R/W, we correct them.
@@ -157,7 +144,7 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
hwif->autodma = 0;
- hwif->tuneproc = &hpt34x_tune_drive;
+ hwif->set_pio_mode = &hpt34x_set_pio_mode;
hwif->speedproc = &hpt34x_tune_chipset;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -167,9 +154,11 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
+#ifdef CONFIG_HPT34X_AUTODMA
hwif->ultra_mask = 0x07;
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
+#endif
hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
if (!noautodma)
@@ -182,10 +171,10 @@ static ide_pci_device_t hpt34x_chipset __devinitdata = {
.name = "HPT34X",
.init_chipset = init_chipset_hpt34x,
.init_hwif = init_hwif_hpt34x,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = NEVER_BOARD,
- .extra = 16
+ .extra = 16,
+ .pio_mask = ATA_PIO5,
};
static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index e9b07a97c340..0e7d3b60d43c 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/hpt366.c Version 1.10 Jun 29, 2007
+ * linux/drivers/ide/pci/hpt366.c Version 1.13 Sep 29, 2007
*
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
@@ -68,7 +68,8 @@
* HPT37x chip family; save space by introducing the separate transfer mode
* table in which the mode lookup is done
* - use f_CNT value saved by the HighPoint BIOS as reading it directly gives
- * the wrong PCI frequency since DPLL has already been calibrated by BIOS
+ * the wrong PCI frequency since DPLL has already been calibrated by BIOS;
+ * read it only from the function 0 of HPT374 chips
* - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
* and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
* - pass to init_chipset() handlers a copy of the IDE PCI device structure as
@@ -113,6 +114,7 @@
* unify HPT36x/37x timing setup code and the speedproc handlers by joining
* the register setting lists into the table indexed by the clock selected
* - set the correct hwif->ultra_mask for each individual chip
+ * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
* Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
*/
@@ -517,47 +519,67 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
}
/*
- * Note for the future; the SATA hpt37x we must set
- * either PIO or UDMA modes 0,4,5
+ * The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
*/
static u8 hpt3xx_udma_filter(ide_drive_t *drive)
{
- struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
- u8 mask;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
+ u8 mask = hwif->ultra_mask;
switch (info->chip_type) {
- case HPT370A:
- if (!HPT370_ALLOW_ATA100_5 ||
- check_in_drive_list(drive, bad_ata100_5))
- return 0x1f;
- else
- return 0x3f;
- case HPT370:
- if (!HPT370_ALLOW_ATA100_5 ||
- check_in_drive_list(drive, bad_ata100_5))
- mask = 0x1f;
- else
- mask = 0x3f;
- break;
case HPT36x:
if (!HPT366_ALLOW_ATA66_4 ||
check_in_drive_list(drive, bad_ata66_4))
- mask = 0x0f;
- else
- mask = 0x1f;
+ mask = ATA_UDMA3;
if (!HPT366_ALLOW_ATA66_3 ||
check_in_drive_list(drive, bad_ata66_3))
- mask = 0x07;
+ mask = ATA_UDMA2;
+ break;
+ case HPT370:
+ if (!HPT370_ALLOW_ATA100_5 ||
+ check_in_drive_list(drive, bad_ata100_5))
+ mask = ATA_UDMA4;
break;
+ case HPT370A:
+ if (!HPT370_ALLOW_ATA100_5 ||
+ check_in_drive_list(drive, bad_ata100_5))
+ return ATA_UDMA4;
+ case HPT372 :
+ case HPT372A:
+ case HPT372N:
+ case HPT374 :
+ if (ide_dev_is_sata(drive->id))
+ mask &= ~0x0e;
+ /* Fall thru */
default:
- return 0x7f;
+ return mask;
}
return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
}
+static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
+
+ switch (info->chip_type) {
+ case HPT372 :
+ case HPT372A:
+ case HPT372N:
+ case HPT374 :
+ if (ide_dev_is_sata(drive->id))
+ return 0x00;
+ /* Fall thru */
+ default:
+ return 0x07;
+ }
+}
+
static u32 get_speed_setting(u8 speed, struct hpt_info *info)
{
int i;
@@ -578,20 +600,15 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
return (*info->settings)[i];
}
-static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
struct hpt_info *info = pci_get_drvdata(dev);
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 itr_addr = drive->dn ? 0x44 : 0x40;
u32 old_itr = 0;
u32 itr_mask, new_itr;
- /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
- if (drive->media != ide_disk)
- speed = min_t(u8, speed, XFER_PIO_4);
-
itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
(speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
@@ -610,20 +627,15 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
return ide_config_drive_speed(drive, speed);
}
-static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
struct hpt_info *info = pci_get_drvdata(dev);
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 itr_addr = 0x40 + (drive->dn * 4);
u32 old_itr = 0;
u32 itr_mask, new_itr;
- /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
- if (drive->media != ide_disk)
- speed = min_t(u8, speed, XFER_PIO_4);
-
itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
(speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
@@ -650,9 +662,8 @@ static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
return hpt36x_tune_chipset(drive, speed);
}
-static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
(void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
}
@@ -714,7 +725,7 @@ static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- hpt3xx_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -981,6 +992,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
unsigned long io_base = pci_resource_start(dev, 4);
u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
+ u8 chip_type;
enum ata_clock clock;
if (info == NULL) {
@@ -992,15 +1004,8 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
* Copy everything from a static "template" structure
* to just allocated per-chip hpt_info structure.
*/
- *info = *(struct hpt_info *)pci_get_drvdata(dev);
-
- /*
- * FIXME: Not portable. Also, why do we enable the ROM in the first place?
- * We don't seem to be using it.
- */
- if (dev->resource[PCI_ROM_RESOURCE].start)
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ memcpy(info, pci_get_drvdata(dev), sizeof(struct hpt_info));
+ chip_type = info->chip_type;
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
@@ -1010,7 +1015,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
/*
* First, try to estimate the PCI clock frequency...
*/
- if (info->chip_type >= HPT370) {
+ if (chip_type >= HPT370) {
u8 scr1 = 0;
u16 f_cnt = 0;
u32 temp = 0;
@@ -1024,7 +1029,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
* HighPoint does this for HPT372A.
* NOTE: This register is only writeable via I/O space.
*/
- if (info->chip_type == HPT372A)
+ if (chip_type == HPT372A)
outb(0x0e, io_base + 0x9c);
/*
@@ -1042,13 +1047,28 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
* First try reading the register in which the HighPoint BIOS
* saves f_CNT value before reprogramming the DPLL from its
* default setting (which differs for the various chips).
- * NOTE: This register is only accessible via I/O space.
*
- * In case the signature check fails, we'll have to resort to
- * reading the f_CNT register itself in hopes that nobody has
- * touched the DPLL yet...
+ * NOTE: This register is only accessible via I/O space;
+ * HPT374 BIOS only saves it for the function 0, so we have to
+ * always read it from there -- no need to check the result of
+ * pci_get_slot() for the function 0 as the whole device has
+ * been already "pinned" (via function 1) in init_setup_hpt374()
+ */
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+ struct pci_dev *dev1 = pci_get_slot(dev->bus,
+ dev->devfn - 1);
+ unsigned long io_base = pci_resource_start(dev1, 4);
+
+ temp = inl(io_base + 0x90);
+ pci_dev_put(dev1);
+ } else
+ temp = inl(io_base + 0x90);
+
+ /*
+ * In case the signature check fails, we'll have to
+ * resort to reading the f_CNT register itself in hopes
+ * that nobody has touched the DPLL yet...
*/
- temp = inl(io_base + 0x90);
if ((temp & 0xFFFFF000) != 0xABCDE000) {
int i;
@@ -1128,7 +1148,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
* We also don't like using the DPLL because this causes glitches
* on PRST-/SRST- when the state engine gets reset...
*/
- if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+ if (chip_type >= HPT374 || info->settings[clock] == NULL) {
u16 f_low, delta = pci_clk < 50 ? 2 : 4;
int adjust;
@@ -1198,7 +1218,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
/* Point to this chip's own instance of the hpt_info structure. */
pci_set_drvdata(dev, info);
- if (info->chip_type >= HPT370) {
+ if (chip_type >= HPT370) {
u8 mcr1, mcr4;
/*
@@ -1217,7 +1237,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
* the MISC. register to stretch the UltraDMA Tss timing.
* NOTE: This register is only writeable via I/O space.
*/
- if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+ if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
@@ -1226,25 +1246,25 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = pci_get_drvdata(dev);
- int serialize = HPT_SERIALIZE_IO;
- u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
- u8 chip_type = info->chip_type;
- u8 new_mcr, old_mcr = 0;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ int serialize = HPT_SERIALIZE_IO;
+ u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
+ u8 chip_type = info->chip_type;
+ u8 new_mcr, old_mcr = 0;
/* Cache the channel's MISC. control registers' offset */
- hwif->select_data = hwif->channel ? 0x54 : 0x50;
+ hwif->select_data = hwif->channel ? 0x54 : 0x50;
- hwif->tuneproc = &hpt3xx_tune_drive;
- hwif->speedproc = &hpt3xx_tune_chipset;
- hwif->quirkproc = &hpt3xx_quirkproc;
- hwif->intrproc = &hpt3xx_intrproc;
- hwif->maskproc = &hpt3xx_maskproc;
- hwif->busproc = &hpt3xx_busproc;
+ hwif->set_pio_mode = &hpt3xx_set_pio_mode;
+ hwif->speedproc = &hpt3xx_tune_chipset;
+ hwif->quirkproc = &hpt3xx_quirkproc;
+ hwif->intrproc = &hpt3xx_intrproc;
+ hwif->maskproc = &hpt3xx_maskproc;
+ hwif->busproc = &hpt3xx_busproc;
- if (chip_type <= HPT370A)
- hwif->udma_filter = &hpt3xx_udma_filter;
+ hwif->udma_filter = &hpt3xx_udma_filter;
+ hwif->mdma_filter = &hpt3xx_mdma_filter;
/*
* HPT3xxN chips have some complications:
@@ -1491,22 +1511,22 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
* to both functions -- really stupid design decision... :-(
* Bit 4 is for the primary channel, bit 5 for the secondary.
*/
- d->channels = 1;
+ d->host_flags |= IDE_HFLAG_SINGLE;
d->enablebits[0].mask = d->enablebits[0].val = 0x10;
- d->udma_mask = HPT366_ALLOW_ATA66_3 ?
- (HPT366_ALLOW_ATA66_4 ? 0x1f : 0x0f) : 0x07;
+ d->udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ?
+ ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2;
break;
case 3:
case 4:
- d->udma_mask = HPT370_ALLOW_ATA100_5 ? 0x3f : 0x1f;
+ d->udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4;
break;
default:
rev = 6;
/* fall thru */
case 5:
case 6:
- d->udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f;
+ d->udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5;
break;
}
@@ -1554,71 +1574,71 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 1 */
.name = "HPT372A",
.init_setup = init_setup_hpt372a,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 2 */
.name = "HPT302",
.init_setup = init_setup_hpt302,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT302_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+ .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 3 */
.name = "HPT371",
.init_setup = init_setup_hpt371,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT371_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+ .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 4 */
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2, /* 4 */
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = 0x3f,
+ .udma_mask = ATA_UDMA5,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 5 */
.name = "HPT372N",
.init_setup = init_setup_hpt372n,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2, /* 4 */
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
}
};
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index ff48c23e571e..76e91ff9420b 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -21,7 +21,7 @@
* it8213_dma_2_pio - return the PIO mode matching DMA
* @xfer_rate: transfer speed
*
- * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * Returns the nearest equivalent PIO timing for the DMA
* mode requested by the controller.
*/
@@ -35,34 +35,28 @@ static u8 it8213_dma_2_pio (u8 xfer_rate) {
case XFER_UDMA_1:
case XFER_UDMA_0:
case XFER_MW_DMA_2:
- case XFER_PIO_4:
return 4;
case XFER_MW_DMA_1:
- case XFER_PIO_3:
return 3;
case XFER_SW_DMA_2:
- case XFER_PIO_2:
return 2;
case XFER_MW_DMA_0:
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
- case XFER_PIO_1:
- case XFER_PIO_0:
- case XFER_PIO_SLOW:
default:
return 0;
}
}
/*
- * it8213_tuneproc - tune a drive
+ * it8213_tune_pio - tune a drive
* @drive: drive to tune
* @pio: desired PIO mode
*
* Set the interface PIO mode.
*/
-static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -82,8 +76,6 @@ static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
spin_lock_irqsave(&tune_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
@@ -113,23 +105,25 @@ static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&tune_lock, flags);
}
+static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ it8213_tune_pio(drive, pio);
+ ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
/**
* it8213_tune_chipset - set controller timings
* @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * @speed: speed we want to achieve
*
- * Tune the ITE chipset for the desired mode. If we can't achieve
- * the desired mode then tune for a lower one, but ultimately
- * make the thing work.
+ * Tune the ITE chipset for the desired mode.
*/
-static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
{
-
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 maslave = 0x40;
- u8 speed = ide_rate_filter(drive, xferspeed);
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
int v_flag = 0x01 << drive->dn;
@@ -157,12 +151,6 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_1:
case XFER_SW_DMA_2:
break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- break;
default:
return -1;
}
@@ -193,7 +181,9 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
if (reg55 & w_flag)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+
+ it8213_tune_pio(drive, it8213_dma_2_pio(speed));
+
return ide_config_drive_speed(drive, speed);
}
@@ -209,13 +199,10 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static int it8213_config_drive_for_dma (ide_drive_t *drive)
{
- u8 pio;
-
if (ide_tune_dma(drive))
return 0;
- pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
- it8213_tune_chipset(drive, XFER_PIO_0 + pio);
+ ide_set_max_pio(drive);
return -1;
}
@@ -234,7 +221,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
u8 reg42h = 0;
hwif->speedproc = &it8213_tune_chipset;
- hwif->tuneproc = &it8213_tuneproc;
+ hwif->set_pio_mode = &it8213_set_pio_mode;
hwif->autodma = 0;
@@ -272,10 +259,11 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
{ \
.name = name_str, \
.init_hwif = init_hwif_it8213, \
- .channels = 1, \
.autodma = AUTODMA, \
.enablebits = {{0x41,0x80,0x80}}, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_SINGLE, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t it8213_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 8197b653ba1e..758a98230cc5 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -255,7 +255,7 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
* on the cable.
*/
if (pair) {
- u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
/* trim PIO to the slowest of the master/slave */
if (pair_pio < set_pio)
set_pio = pair_pio;
@@ -274,9 +274,8 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
}
-static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
+static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
(void)it821x_tunepio(drive, pio);
}
@@ -405,32 +404,19 @@ static int it821x_dma_end(ide_drive_t *drive)
return ret;
}
-
/**
* it821x_tune_chipset - set controller timings
* @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * @speed: speed we want to achieve
*
- * Tune the ITE chipset for the desired mode. If we can't achieve
- * the desired mode then tune for a lower one, but ultimately
- * make the thing work.
+ * Tune the ITE chipset for the desired mode.
*/
-static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- u8 speed = ide_rate_filter(drive, xferspeed);
-
- switch (speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- return it821x_tunepio(drive, speed - XFER_PIO_0);
- }
if (itdev->smart == 0) {
switch (speed) {
@@ -477,7 +463,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive)
if (ide_tune_dma(drive))
return 0;
- it821x_tuneproc(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -644,7 +630,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
}
hwif->speedproc = &it821x_tune_chipset;
- hwif->tuneproc = &it821x_tuneproc;
+ hwif->set_pio_mode = &it821x_set_pio_mode;
/* MWDMA/PIO clock switching for pass through mode */
if(!idev->smart) {
@@ -718,10 +704,10 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
.name = name_str, \
.init_chipset = init_chipset_it821x, \
.init_hwif = init_hwif_it821x, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
- .fixup = it821x_fixups \
+ .fixup = it821x_fixups, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t it821x_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index a6008f63e71e..d379fbaf6743 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -83,39 +83,22 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
return ATA_CBL_PATA80;
}
-static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
+static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- return;
-}
-
-/**
- * config_jmicron_chipset_for_pio - set drive timings
- * @drive: drive to tune
- * @speed we want
- *
- */
-
-static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
- u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
+ ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
* jmicron_tune_chipset - set controller timings
* @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * @speed: speed we want to achieve
*
* As the JMicron snoops for timings all we actually need to do is
- * make sure we don't set an invalid mode. We do need to honour
- * the cable detect here.
+ * set the transfer mode on the device.
*/
-static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
+static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed)
{
- u8 speed = ide_rate_filter(drive, xferspeed);
-
return ide_config_drive_speed(drive, speed);
}
@@ -132,7 +115,7 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive)
if (ide_tune_dma(drive))
return 0;
- config_jmicron_chipset_for_pio(drive, 1);
+ ide_set_max_pio(drive);
return -1;
}
@@ -147,7 +130,7 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive)
static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
{
hwif->speedproc = &jmicron_tune_chipset;
- hwif->tuneproc = &jmicron_tuneproc;
+ hwif->set_pio_mode = &jmicron_set_pio_mode;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -173,22 +156,13 @@ fallback:
return;
}
-#define DECLARE_JMB_DEV(name_str) \
- { \
- .name = name_str, \
- .init_hwif = init_hwif_jmicron, \
- .channels = 2, \
- .autodma = AUTODMA, \
- .bootable = ON_BOARD, \
- .enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
- }
-
-static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
- /* 0 */ DECLARE_JMB_DEV("JMB361"),
- /* 1 */ DECLARE_JMB_DEV("JMB363"),
- /* 2 */ DECLARE_JMB_DEV("JMB365"),
- /* 3 */ DECLARE_JMB_DEV("JMB366"),
- /* 4 */ DECLARE_JMB_DEV("JMB368"),
+static ide_pci_device_t jmicron_chipset __devinitdata = {
+ .name = "JMB",
+ .init_hwif = init_hwif_jmicron,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
+ .pio_mask = ATA_PIO5,
};
/**
@@ -202,35 +176,29 @@ static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]);
+ ide_setup_pci_device(dev, &jmicron_chipset);
return 0;
}
-/* If libata is configured, jmicron PCI quirk will configure it such
- * that the SATA ports are in AHCI function while the PATA ports are
- * in a separate IDE function. In such cases, match device class and
- * attach only to IDE. If libata isn't configured, keep the old
- * behavior for backward compatibility.
+/* All JMB PATA controllers have and will continue to have the same
+ * interface. Matching vendor and device class is enough for all
+ * current and future controllers if the controller is programmed
+ * properly.
+ *
+ * If libata is configured, jmicron PCI quirk programs the controller
+ * into the correct mode. If libata isn't configured, match known
+ * device IDs too to maintain backward compatibility.
*/
-#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
-#define JMB_CLASS PCI_CLASS_STORAGE_IDE << 8
-#define JMB_CLASS_MASK 0xffff00
-#else
-#define JMB_CLASS 0
-#define JMB_CLASS_MASK 0
-#endif
-
static struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 0},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 1},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 2},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 3},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 4},
+#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
+#endif
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ 0, },
};
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index b310c4f51077..465c935fdf25 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -187,14 +187,6 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive)
return 1;
}
-static int ns87415_ide_dma_check (ide_drive_t *drive)
-{
- if (drive->media != ide_disk)
- return -1;
-
- return __ide_dma_check(drive);
-}
-
static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -266,7 +258,6 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
outb(0x60, hwif->dma_status);
hwif->dma_setup = &ns87415_ide_dma_setup;
- hwif->ide_dma_check = &ns87415_ide_dma_check;
hwif->ide_dma_end = &ns87415_ide_dma_end;
if (!noautodma)
@@ -281,7 +272,6 @@ static ide_pci_device_t ns87415_chipset __devinitdata = {
.init_iops = init_iops_ns87415,
#endif
.init_hwif = init_hwif_ns87415,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
};
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index aede7eee9246..9fa06393469a 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -47,7 +47,7 @@
* The main problem with OPTi is that some timings for master
* and slave must be the same. For example, if you have master
* PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
+ * master for PIO 0. Second problem is that opti621_set_pio_mode
* got only one drive to set, but have to set both drives.
* This is solved in compute_pios. If you don't set
* the second drive, compute_pios use ide_get_best_pio_mode
@@ -103,7 +103,7 @@
#include <asm/io.h>
-#define OPTI621_MAX_PIO 3
+//#define OPTI621_MAX_PIO 3
/* In fact, I do not have any PIO 4 drive
* (address: 25 ns, data: 70 ns, recovery: 35 ns),
* but OPTi 82C621 is programmable and it can do (minimal values):
@@ -136,8 +136,8 @@ static int reg_base;
#define PIO_NOT_EXIST 254
#define PIO_DONT_KNOW 255
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-static void compute_pios(ide_drive_t *drive, u8 pio)
+/* there are stored pio numbers from other calls of opti621_set_pio_mode */
+static void compute_pios(ide_drive_t *drive, const u8 pio)
/* Store values into drive->drive_data
* second_contr - 0 for primary controller, 1 for secondary
* slave_drive - 0 -> pio is for master, 1 -> pio is for slave
@@ -147,12 +147,13 @@ static void compute_pios(ide_drive_t *drive, u8 pio)
int d;
ide_hwif_t *hwif = HWIF(drive);
- drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+ drive->drive_data = pio;
+
for (d = 0; d < 2; ++d) {
drive = &hwif->drives[d];
if (drive->present) {
if (drive->drive_data == PIO_DONT_KNOW)
- drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+ drive->drive_data = ide_get_best_pio_mode(drive, 255, 3);
#ifdef OPTI621_DEBUG
printk("%s: Selected PIO mode %d\n",
drive->name, drive->drive_data);
@@ -240,8 +241,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks)
}
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
/* primary and secondary drives share some registers,
* so we have to program both drives
@@ -331,7 +331,8 @@ static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
hwif->autodma = 0;
hwif->drives[0].drive_data = PIO_DONT_KNOW;
hwif->drives[1].drive_data = PIO_DONT_KNOW;
- hwif->tuneproc = &opti621_tune_drive;
+
+ hwif->set_pio_mode = &opti621_set_pio_mode;
if (!(hwif->dma_base))
return;
@@ -350,17 +351,17 @@ static ide_pci_device_t opti621_chipsets[] __devinitdata = {
{ /* 0 */
.name = "OPTI621",
.init_hwif = init_hwif_opti621,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO3,
},{ /* 1 */
.name = "OPTI621X",
.init_hwif = init_hwif_opti621,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO3,
}
};
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index ee5020df005d..5fb1eedc8194 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -9,7 +9,7 @@
* Split from:
* linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2005-2006 MontaVista Software, Inc.
+ * Copyright (C) 2005-2007 MontaVista Software, Inc.
* Portions Copyright (C) 1999 Promise Technology, Inc.
* Author: Frank Tiernan (frankt@promise.com)
* Released under terms of General Public License
@@ -146,14 +146,12 @@ static struct udma_timing {
{ 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
};
-static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
+static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
int err;
- speed = ide_rate_filter(drive, speed);
-
/*
* Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
* automatically set the timing registers based on 100 MHz PLL output.
@@ -217,9 +215,8 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
return err;
}
-static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
+static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
(void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
}
@@ -239,7 +236,7 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- pdcnew_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -341,7 +338,7 @@ static long __devinit detect_pll_input_clock(unsigned long dma_base)
*/
usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
(end_time.tv_usec - start_time.tv_usec);
- pll_input = ((start_count - end_count) & 0x3ffffff) / 10 *
+ pll_input = ((start_count - end_count) & 0x3fffffff) / 10 *
(10000000 / usec_elapsed);
DBG("start[%ld] end[%ld]\n", start_count, end_count);
@@ -378,12 +375,8 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
int f, r;
u8 pll_ctl0, pll_ctl1;
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
+ if (dma_base == 0)
+ return -EFAULT;
#ifdef CONFIG_PPC_PMAC
apple_kiwi_init(dev);
@@ -496,20 +489,24 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
{
hwif->autodma = 0;
- hwif->tuneproc = &pdcnew_tune_drive;
+ hwif->set_pio_mode = &pdcnew_set_pio_mode;
+
hwif->quirkproc = &pdcnew_quirkproc;
hwif->speedproc = &pdcnew_tune_chipset;
hwif->resetproc = &pdcnew_reset;
+ hwif->err_stops_fifo = 1;
+
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
+ return;
+
hwif->atapi_dma = 1;
hwif->ultra_mask = hwif->cds->udma_mask;
hwif->mwdma_mask = 0x07;
- hwif->err_stops_fifo = 1;
-
hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
@@ -525,43 +522,52 @@ static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d)
return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_pdc20270(struct pci_dev *dev,
- ide_pci_device_t *d)
+static int __devinit init_setup_pdc20270(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
- int ret;
+ struct pci_dev *bridge = dev->bus->self;
+
+ if (bridge != NULL &&
+ bridge->vendor == PCI_VENDOR_ID_DEC &&
+ bridge->device == PCI_DEVICE_ID_DEC_21150) {
+ struct pci_dev *dev2;
- if ((dev->bus->self &&
- dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
- (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
if (PCI_SLOT(dev->devfn) & 2)
return -ENODEV;
- d->extra = 0;
- while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- (PCI_SLOT(findev->devfn) & 2)) {
- if (findev->irq != dev->irq) {
- findev->irq = dev->irq;
- }
- ret = ide_setup_pci_devices(dev, findev, d);
- pci_dev_put(findev);
- return ret;
+
+ dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 2,
+ PCI_FUNC(dev->devfn)));
+ if (dev2 != NULL &&
+ dev2->vendor == dev->vendor &&
+ dev2->device == dev->device) {
+ int ret;
+
+ if (dev2->irq != dev->irq) {
+ dev2->irq = dev->irq;
+
+ printk(KERN_WARNING "%s: PCI config space "
+ "interrupt fixed.\n", d->name);
}
+
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
}
return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_pdc20276(struct pci_dev *dev,
- ide_pci_device_t *d)
+static int __devinit init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d)
{
- if ((dev->bus->self) &&
- (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
- ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
- (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
- printk(KERN_INFO "ide: Skipping Promise PDC20276 "
- "attached to I2O RAID controller.\n");
+ struct pci_dev *bridge = dev->bus->self;
+
+ if (bridge != NULL &&
+ bridge->vendor == PCI_VENDOR_ID_INTEL &&
+ (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
+ bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
+
+ printk(KERN_INFO "%s: attached to I2O RAID controller, "
+ "skipping.\n", d->name);
return -ENODEV;
}
return ide_setup_pci_device(dev, d);
@@ -573,63 +579,63 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 1 */
.name = "PDC20269",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 2 */
.name = "PDC20270",
.init_setup = init_setup_pdc20270,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 3 */
.name = "PDC20271",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 4 */
.name = "PDC20275",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 5 */
.name = "PDC20276",
.init_setup = init_setup_pdc20276,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 6 */
.name = "PDC20277",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
}
};
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 41ac4a94959f..b578307fad51 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/pdc202xx_old.c Version 0.50 Mar 3, 2007
+ * linux/drivers/ide/pci/pdc202xx_old.c Version 0.51 Jul 27, 2007
*
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006-2007 MontaVista Software, Inc.
@@ -63,12 +63,11 @@ static const char *pdc_quirk_drives[] = {
static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
-static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 drive_pci = 0x60 + (drive->dn << 2);
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 AP = 0, BP = 0, CP = 0;
u8 TA = 0, TB = 0, TC = 0;
@@ -143,9 +142,8 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
return ide_config_drive_speed(drive, speed);
}
-static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
}
@@ -191,7 +189,7 @@ static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- pdc202xx_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -307,23 +305,16 @@ static void pdc202xx_reset (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
ide_hwif_t *mate = hwif->mate;
-
+
pdc202xx_reset_host(hwif);
pdc202xx_reset_host(mate);
- pdc202xx_tune_drive(drive, 255);
+
+ ide_set_max_pio(drive);
}
static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
const char *name)
{
- /* This doesn't appear needed */
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
-
return dev->irq;
}
@@ -337,7 +328,9 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->rqsize = 256;
hwif->autodma = 0;
- hwif->tuneproc = &pdc202xx_tune_drive;
+
+ hwif->set_pio_mode = &pdc202xx_set_pio_mode;
+
hwif->quirkproc = &pdc202xx_quirkproc;
if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
@@ -345,15 +338,18 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->speedproc = &pdc202xx_tune_chipset;
+ hwif->err_stops_fifo = 1;
+
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
+ return;
+
hwif->ultra_mask = hwif->cds->udma_mask;
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
hwif->atapi_dma = 1;
- hwif->err_stops_fifo = 1;
-
hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
hwif->dma_timeout = &pdc202xx_dma_timeout;
@@ -449,10 +445,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 16,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x07, /* udma0-2 */
},{ /* 1 */
.name = "PDC20262",
@@ -460,10 +456,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 2 */
.name = "PDC20263",
@@ -471,10 +467,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 3 */
.name = "PDC20265",
@@ -482,10 +478,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 4 */
.name = "PDC20267",
@@ -493,10 +489,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
}
};
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 1372c35be035..fd8214a7ab98 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/piix.c Version 0.50 Jun 10, 2007
+ * linux/drivers/ide/pci/piix.c Version 0.52 Jul 14, 2007
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -17,11 +17,11 @@
* 41
* 43
*
- * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4);
- *
+ * | PIO 0 | c0 | 80 | 0 |
+ * | PIO 2 | SW2 | d0 | 90 | 4 |
+ * | PIO 3 | MW1 | e1 | a1 | 9 |
+ * | PIO 4 | MW2 | e3 | a3 | b |
+ *
* sitre = word40 & 0x4000; primary
* sitre = word42 & 0x4000; secondary
*
@@ -109,7 +109,7 @@ static int no_piix_dma;
* piix_dma_2_pio - return the PIO mode matching DMA
* @xfer_rate: transfer speed
*
- * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * Returns the nearest equivalent PIO timing for the DMA
* mode requested by the controller.
*/
@@ -123,20 +123,14 @@ static u8 piix_dma_2_pio (u8 xfer_rate) {
case XFER_UDMA_1:
case XFER_UDMA_0:
case XFER_MW_DMA_2:
- case XFER_PIO_4:
return 4;
case XFER_MW_DMA_1:
- case XFER_PIO_3:
return 3;
case XFER_SW_DMA_2:
- case XFER_PIO_2:
return 2;
case XFER_MW_DMA_0:
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
- case XFER_PIO_1:
- case XFER_PIO_0:
- case XFER_PIO_SLOW:
default:
return 0;
}
@@ -210,16 +204,16 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio)
}
/**
- * piix_tune_drive - tune a drive attached to PIIX
+ * piix_set_pio_mode - set PIO mode
* @drive: drive to tune
* @pio: desired PIO mode
*
* Set the drive's PIO mode (might be useful if drive is not registered
* in CMOS for any reason).
*/
-static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+
+static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
piix_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
@@ -227,19 +221,18 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
/**
* piix_tune_chipset - tune a PIIX interface
* @drive: IDE drive to tune
- * @xferspeed: speed to configure
+ * @speed: speed to configure
*
* Set a PIIX interface channel to the desired speeds. This involves
* requires the right timing data into the PIIX configuration space
* then setting the drive parameters appropriately
*/
-
-static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 maslave = hwif->channel ? 0x42 : 0x40;
- u8 speed = ide_rate_filter(drive, xferspeed);
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
int v_flag = 0x01 << drive->dn;
@@ -266,10 +259,6 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_0: break;
default: return -1;
}
@@ -300,6 +289,7 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
}
piix_tune_pio(drive, piix_dma_2_pio(speed));
+
return ide_config_drive_speed(drive, speed);
}
@@ -319,7 +309,7 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- piix_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -456,7 +446,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
}
hwif->autodma = 0;
- hwif->tuneproc = &piix_tune_drive;
+
+ hwif->set_pio_mode = &piix_set_pio_mode;
hwif->speedproc = &piix_tune_chipset;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -495,10 +486,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_piix, \
.init_hwif = init_hwif_piix, \
- .channels = 2, \
.autodma = AUTODMA, \
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
.bootable = ON_BOARD, \
+ .pio_mask = ATA_PIO4, \
.udma_mask = udma, \
}
@@ -514,11 +505,11 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
*/
.name = "MPIIX",
.init_hwif = init_hwif_piix,
- .channels = 2,
.autodma = NODMA,
.enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
.bootable = ON_BOARD,
- .flags = IDEPCI_FLAG_ISA_PORTS
+ .host_flags = IDE_HFLAG_ISA_PORTS,
+ .pio_mask = ATA_PIO4,
},
/* 3 */ DECLARE_PIIX_DEV("PIIX3", 0x00), /* no udma */
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index f8c954690142..10e1ae7a4a02 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -52,7 +52,6 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
static ide_pci_device_t rz1000_chipset __devinitdata = {
.name = "RZ100x",
.init_hwif = init_hwif_rz1000,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
};
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 523363c93794..79ecab689489 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/sc1200.c Version 0.94 Mar 10 2007
+ * linux/drivers/ide/pci/sc1200.c Version 0.95 Jun 16 2007
*
* Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
@@ -138,7 +138,7 @@ out:
return mask;
}
-static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
+static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
{
ide_hwif_t *hwif = HWIF(drive);
int unit = drive->select.b.unit;
@@ -146,25 +146,11 @@ static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
unsigned short pci_clock;
unsigned int basereg = hwif->channel ? 0x50 : 0x40;
- mode = ide_rate_filter(drive, mode);
-
/*
* Tell the drive to switch to the new mode; abort on failure.
*/
- if (sc1200_set_xfer_mode(drive, mode)) {
- printk("SC1200: set xfer mode failure\n");
+ if (sc1200_set_xfer_mode(drive, mode))
return 1; /* failure */
- }
-
- switch (mode) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- sc1200_tunepio(drive, mode - XFER_PIO_0);
- return 0;
- }
pci_clock = sc1200_get_pci_clock();
@@ -274,19 +260,20 @@ static int sc1200_ide_dma_end (ide_drive_t *drive)
}
/*
- * sc1200_tuneproc() handles selection/setting of PIO modes
+ * sc1200_set_pio_mode() handles setting of PIO modes
* for both the chipset and drive.
*
* All existing BIOSs for this chipset guarantee that all drives
* will have valid default PIO timings set up before we get here.
*/
-static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */
+
+static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
int mode = -1;
/*
- * bad abuse of ->tuneproc interface
+ * bad abuse of ->set_pio_mode interface
*/
switch (pio) {
case 200: mode = XFER_UDMA_0; break;
@@ -304,9 +291,6 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "au
return;
}
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
- printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
-
if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
sc1200_tunepio(drive, pio);
}
@@ -390,7 +374,7 @@ static int sc1200_resume (struct pci_dev *dev)
// loop over all interfaces that are part of this pci device:
//
while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
- unsigned int basereg, r, d, format;
+ unsigned int basereg, r;
sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data;
//
@@ -402,41 +386,6 @@ static int sc1200_resume (struct pci_dev *dev)
pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
}
}
- //
- // Re-program drive PIO modes
- //
- pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
- format = (format >> 31) & 1;
- if (format)
- format += sc1200_get_pci_clock();
- for (d = 0; d < 2; ++d) {
- ide_drive_t *drive = &(hwif->drives[d]);
- if (drive->present) {
- unsigned int pio, timings;
- pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
- for (pio = 0; pio <= 4; ++pio) {
- if (sc1200_pio_timings[format][pio] == timings)
- break;
- }
- if (pio > 4)
- pio = 255; /* autotune */
- (void)sc1200_tuneproc(drive, pio);
- }
- }
- //
- // Re-program drive DMA modes
- //
- for (d = 0; d < MAX_DRIVES; ++d) {
- ide_drive_t *drive = &(hwif->drives[d]);
- if (drive->present && !__ide_dma_bad_drive(drive)) {
- int enable_dma = drive->using_dma;
- hwif->dma_off_quietly(drive);
- if (sc1200_config_dma(drive))
- enable_dma = 0;
- if (enable_dma)
- hwif->dma_host_on(drive);
- }
- }
}
return 0;
}
@@ -457,7 +406,8 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
hwif->ide_dma_end = &sc1200_ide_dma_end;
if (!noautodma)
hwif->autodma = 1;
- hwif->tuneproc = &sc1200_tuneproc;
+
+ hwif->set_pio_mode = &sc1200_set_pio_mode;
hwif->speedproc = &sc1200_tune_chipset;
}
hwif->atapi_dma = 1;
@@ -471,9 +421,10 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
static ide_pci_device_t sc1200_chipset __devinitdata = {
.name = "SC1200",
.init_hwif = init_hwif_sc1200,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_DMA_MODES,
+ .pio_mask = ATA_PIO4,
};
static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index 7b87488e3daa..66a526e0ece4 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -165,9 +165,9 @@ scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port)
ide_hwif_t *hwif = HWIF(drive);
out_be32((void*)port, addr);
- __asm__ __volatile__("eieio":::"memory");
+ eieio();
in_be32((void*)(hwif->dma_base + 0x01c));
- __asm__ __volatile__("eieio":::"memory");
+ eieio();
}
static void
@@ -190,7 +190,7 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
}
/**
- * scc_tuneproc - tune a drive PIO mode
+ * scc_tune_pio - tune a drive PIO mode
* @drive: drive to tune
* @mode_wanted: the target operating mode
*
@@ -198,7 +198,7 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
* controller.
*/
-static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
+static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -207,56 +207,38 @@ static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
unsigned long piosht_port = ctl_base + 0x000;
unsigned long pioct_port = ctl_base + 0x004;
unsigned long reg;
- unsigned char speed = XFER_PIO_0;
int offset;
- mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL);
- switch (mode_wanted) {
- case 4:
- speed = XFER_PIO_4;
- break;
- case 3:
- speed = XFER_PIO_3;
- break;
- case 2:
- speed = XFER_PIO_2;
- break;
- case 1:
- speed = XFER_PIO_1;
- break;
- case 0:
- default:
- speed = XFER_PIO_0;
- break;
- }
-
reg = in_be32((void __iomem *)cckctrl_port);
if (reg & CCKCTRL_ATACLKOEN) {
offset = 1; /* 133MHz */
} else {
offset = 0; /* 100MHz */
}
- reg = JCHSTtbl[offset][mode_wanted] << 16 | JCHHTtbl[offset][mode_wanted];
+ reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
out_be32((void __iomem *)piosht_port, reg);
- reg = JCHCTtbl[offset][mode_wanted];
+ reg = JCHCTtbl[offset][pio];
out_be32((void __iomem *)pioct_port, reg);
+}
- ide_config_drive_speed(drive, speed);
+static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ scc_tune_pio(drive, pio);
+ ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
* scc_tune_chipset - tune a drive DMA mode
* @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * @speed: speed we want to achieve
*
* Load the timing settings for this device mode into the
* controller.
*/
-static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
+static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
- u8 speed = ide_rate_filter(drive, xferspeed);
struct scc_ports *ports = ide_get_hwifdata(hwif);
unsigned long ctl_base = ports->ctl;
unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -280,25 +262,13 @@ static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
switch (speed) {
case XFER_UDMA_6:
- idx = 6;
- break;
case XFER_UDMA_5:
- idx = 5;
- break;
case XFER_UDMA_4:
- idx = 4;
- break;
case XFER_UDMA_3:
- idx = 3;
- break;
case XFER_UDMA_2:
- idx = 2;
- break;
case XFER_UDMA_1:
- idx = 1;
- break;
case XFER_UDMA_0:
- idx = 0;
+ idx = speed - XFER_UDMA_0;
break;
default:
return 1;
@@ -329,7 +299,7 @@ static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
* required.
* If the drive isn't suitable for DMA or we hit other problems
* then we will drop down to PIO and set up PIO appropriately.
- * (return 1)
+ * (return -1)
*/
static int scc_config_drive_for_dma(ide_drive_t *drive)
@@ -338,7 +308,7 @@ static int scc_config_drive_for_dma(ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- scc_tuneproc(drive, 4);
+ ide_set_max_pio(drive);
return -1;
}
@@ -401,6 +371,33 @@ static int scc_ide_dma_end(ide_drive_t * drive)
ide_hwif_t *hwif = HWIF(drive);
unsigned long intsts_port = hwif->dma_base + 0x014;
u32 reg;
+ int dma_stat, data_loss = 0;
+ static int retry = 0;
+
+ /* errata A308 workaround: Step5 (check data loss) */
+ /* We don't check non ide_disk because it is limited to UDMA4 */
+ if (!(in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+ drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
+ reg = in_be32((void __iomem *)intsts_port);
+ if (!(reg & INTSTS_ACTEINT)) {
+ printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
+ drive->name);
+ data_loss = 1;
+ if (retry++) {
+ struct request *rq = HWGROUP(drive)->rq;
+ int unit;
+ /* ERROR_RESET and drive->crc_count are needed
+ * to reduce DMA transfer mode in retry process.
+ */
+ if (rq)
+ rq->errors |= ERROR_RESET;
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ drive->crc_count++;
+ }
+ }
+ }
+ }
while (1) {
reg = in_be32((void __iomem *)intsts_port);
@@ -469,27 +466,25 @@ static int scc_ide_dma_end(ide_drive_t * drive)
break;
}
- return __ide_dma_end(drive);
+ dma_stat = __ide_dma_end(drive);
+ if (data_loss)
+ dma_stat |= 2; /* emulate DMA error (to retry command) */
+ return dma_stat;
}
/* returns 1 if dma irq issued, 0 otherwise */
static int scc_dma_test_irq(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ ide_hwif_t *hwif = HWIF(drive);
+ u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
- /* return 1 if INTR asserted */
- if ((dma_stat & 4) == 4)
+ /* SCC errata A252,A308 workaround: Step4 */
+ if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+ (int_stat & INTSTS_INTRQ))
return 1;
- /* Workaround for PTERADD: emulate DMA_INTR when
- * - IDE_STATUS[ERR] = 1
- * - INT_STATUS[INTRQ] = 1
- * - DMA_STATUS[IORACTA] = 1
- */
- if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
- in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
- dma_stat & 1)
+ /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
+ if (int_stat & INTSTS_IOIRQS)
return 1;
if (!drive->waiting_for_dma)
@@ -498,6 +493,21 @@ static int scc_dma_test_irq(ide_drive_t *drive)
return 0;
}
+static u8 scc_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 mask = hwif->ultra_mask;
+
+ /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
+ if ((drive->media != ide_disk) && (mask & 0xE0)) {
+ printk(KERN_INFO "%s: limit %s to UDMA4\n",
+ SCC_PATA_NAME, drive->name);
+ mask = 0x1F;
+ }
+
+ return mask;
+}
+
/**
* setup_mmio_scc - map CTRL/BMID region
* @dev: PCI device we are configuring
@@ -511,8 +521,8 @@ static int setup_mmio_scc (struct pci_dev *dev, const char *name)
unsigned long dma_base = pci_resource_start(dev, 1);
unsigned long ctl_size = pci_resource_len(dev, 0);
unsigned long dma_size = pci_resource_len(dev, 1);
- void *ctl_addr;
- void *dma_addr;
+ void __iomem *ctl_addr;
+ void __iomem *dma_addr;
int i;
for (i = 0; i < MAX_HWIFS; i++) {
@@ -699,9 +709,10 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
hwif->dma_setup = scc_dma_setup;
hwif->ide_dma_end = scc_ide_dma_end;
hwif->speedproc = scc_tune_chipset;
- hwif->tuneproc = scc_tuneproc;
+ hwif->set_pio_mode = scc_set_pio_mode;
hwif->ide_dma_check = scc_config_drive_for_dma;
hwif->ide_dma_test_irq = scc_dma_test_irq;
+ hwif->udma_filter = scc_udma_filter;
hwif->drives[0].autotune = IDE_TUNE_AUTO;
hwif->drives[1].autotune = IDE_TUNE_AUTO;
@@ -731,9 +742,10 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
.init_setup = init_setup_scc, \
.init_iops = init_iops_scc, \
.init_hwif = init_hwif_scc, \
- .channels = 1, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_SINGLE, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t scc_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index ed04e0c8dd4c..0351cf210427 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/serverworks.c Version 0.20 Jun 3 2007
+ * linux/drivers/ide/pci/serverworks.c Version 0.22 Jun 27 2007
*
* Copyright (C) 1998-2000 Michel Aubry
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -123,23 +123,39 @@ static u8 svwks_csb_check (struct pci_dev *dev)
}
return 0;
}
-static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+{
+ static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+
+ struct pci_dev *dev = drive->hwif->pci_dev;
+
+ pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
+
+ if (svwks_csb_check(dev)) {
+ u16 csb_pio = 0;
+
+ pci_read_config_word(dev, 0x4a, &csb_pio);
+
+ csb_pio &= ~(0x0f << (4 * drive->dn));
+ csb_pio |= (pio << (4 * drive->dn));
+
+ pci_write_config_word(dev, 0x4a, csb_pio);
+ }
+}
+
+static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed)
{
static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
- static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
- static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
- u8 pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
u8 unit = (drive->select.b.unit & 0x01);
- u8 csb5 = svwks_csb_check(dev);
- u8 ultra_enable = 0, ultra_timing = 0;
- u8 dma_timing = 0, pio_timing = 0;
- u16 csb5_pio = 0;
+
+ u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0;
/* If we are about to put a disk into UDMA mode we screwed up.
Our code assumes we never _ever_ do this on an OSB4 */
@@ -149,31 +165,15 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
BUG();
pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
- pci_read_config_word(dev, 0x4A, &csb5_pio);
pci_read_config_byte(dev, 0x54, &ultra_enable);
ultra_timing &= ~(0x0F << (4*unit));
ultra_enable &= ~(0x01 << drive->dn);
- csb5_pio &= ~(0x0F << (4*drive->dn));
switch(speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- pio_timing |= pio_modes[speed - XFER_PIO_0];
- csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn));
- break;
-
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
- /*
- * TODO: always setup PIO mode so this won't be needed
- */
- pio_timing |= pio_modes[pio];
- csb5_pio |= (pio << (4*drive->dn));
dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
break;
@@ -183,11 +183,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
- /*
- * TODO: always setup PIO mode so this won't be needed
- */
- pio_timing |= pio_modes[pio];
- csb5_pio |= (pio << (4*drive->dn));
dma_timing |= dma_modes[2];
ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
ultra_enable |= (0x01 << drive->dn);
@@ -195,10 +190,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
break;
}
- pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
- if (csb5)
- pci_write_config_word(dev, 0x4A, csb5_pio);
-
pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable);
@@ -206,10 +197,10 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
return (ide_config_drive_speed(drive, speed));
}
-static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
- (void)svwks_tune_chipset(drive, XFER_PIO_0 + pio);
+ svwks_tune_pio(drive, pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -220,7 +211,7 @@ static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- svwks_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -389,12 +380,10 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
{
- u8 dma_stat = 0;
-
if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14;
- hwif->tuneproc = &svwks_tune_drive;
+ hwif->set_pio_mode = &svwks_set_pio_mode;
hwif->speedproc = &svwks_tune_chipset;
hwif->udma_filter = &svwks_udma_filter;
@@ -407,11 +396,11 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
hwif->autodma = 0;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
return;
- }
hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
@@ -421,11 +410,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
if (!noautodma)
hwif->autodma = 1;
- dma_stat = inb(hwif->dma_status);
- hwif->drives[0].autodma = (dma_stat & 0x20);
- hwif->drives[1].autodma = (dma_stat & 0x40);
- hwif->drives[0].autotune = (!(dma_stat & 0x20));
- hwif->drives[1].autotune = (!(dma_stat & 0x40));
+ hwif->drives[0].autodma = hwif->drives[1].autodma = 1;
}
static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
@@ -441,9 +426,12 @@ static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
d->bootable = ON_BOARD;
}
- d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
- (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ d->host_flags |= IDE_HFLAG_SINGLE;
+ else
+ d->host_flags &= ~IDE_HFLAG_SINGLE;
return ide_setup_pci_device(dev, d);
}
@@ -454,41 +442,43 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 1 */
.name = "SvrWks CSB5",
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 2 */
.name = "SvrWks CSB6",
.init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 3 */
.name = "SvrWks CSB6",
.init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 1, /* 2 */
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
},{ /* 4 */
.name = "SvrWks HT1000",
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 1, /* 2 */
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
}
};
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index d396b2929ed8..c292e1de1d56 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -34,6 +34,8 @@
#include <linux/ide.h>
+#define DRV_NAME "SGIIOC4"
+
/* IOC4 Specific Definitions */
#define IOC4_CMD_OFFSET 0x100
#define IOC4_CTRL_OFFSET 0x120
@@ -289,15 +291,26 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
drive->hwif->dma_host_off(drive);
}
+static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed)
+{
+ if (speed != XFER_MW_DMA_2)
+ return 1;
+
+ return ide_config_drive_speed(drive, speed);
+}
+
static int sgiioc4_ide_dma_check(ide_drive_t *drive)
{
- /* FIXME: check for available DMA modes */
- if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
- printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, "
- "using PIO instead\n", drive->name);
- return -1;
- } else
+ if (ide_tune_dma(drive))
return 0;
+
+ /*
+ * ->set_pio_mode is not implemented currently
+ * so this is just for the completness
+ */
+ ide_set_max_pio(drive);
+
+ return -1;
}
/* returns 1 if dma irq issued, 0 otherwise */
@@ -353,7 +366,7 @@ sgiioc4_INB(unsigned long port)
}
/* Creates a dma map for the scatter-gather list entries */
-static void __devinit
+static int __devinit
ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
{
void __iomem *virt_dma_base;
@@ -369,7 +382,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
"ALREADY in use\n",
__FUNCTION__, hwif->name, (void *) dma_base,
(void *) dma_base + num_ports - 1);
- goto dma_alloc_failure;
+ return -1;
}
virt_dma_base = ioremap(dma_base, num_ports);
@@ -395,7 +408,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
if (pad) {
ide_set_hwifdata(hwif, pad);
- return;
+ return 0;
}
pci_free_consistent(hwif->pci_dev,
@@ -413,10 +426,7 @@ dma_pci_alloc_failure:
dma_remap_failure:
release_mem_region(dma_base, num_ports);
-dma_alloc_failure:
- /* Disable DMA because we couldnot allocate any DMA maps */
- hwif->autodma = 0;
- hwif->atapi_dma = 0;
+ return -1;
}
/* Initializes the IOC4 DMA Engine */
@@ -581,13 +591,11 @@ static void __devinit
ide_init_sgiioc4(ide_hwif_t * hwif)
{
hwif->mmio = 1;
- hwif->autodma = 1;
hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
- hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */
- hwif->swdma_mask = 0x2;
- hwif->tuneproc = NULL; /* Sets timing for PIO mode */
- hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */
+ hwif->mwdma_mask = 0x04;
+ hwif->pio_mask = 0x00;
+ hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
+ hwif->speedproc = &sgiioc4_speedproc;
hwif->selectproc = NULL;/* Use the default routine to select drive */
hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
@@ -614,7 +622,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
}
static int __devinit
-sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
+sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
{
unsigned long cmd_base, dma_base, irqport;
unsigned long bar0, cmd_phys_base, ctl;
@@ -631,7 +639,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
break;
}
if (h == MAX_HWIFS) {
- printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", d->name);
+ printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n",
+ DRV_NAME);
return -ENOMEM;
}
@@ -640,7 +649,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
virt_base = ioremap(bar0, pci_resource_len(dev, 0));
if (virt_base == NULL) {
printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
- d->name, bar0);
+ DRV_NAME, bar0);
return -ENOMEM;
}
cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET;
@@ -671,7 +680,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
hwif->chipset = ide_pci;
hwif->pci_dev = dev;
hwif->channel = 0; /* Single Channel chip */
- hwif->cds = (struct ide_pci_device_s *) d;
hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
/* The IOC4 uses MMIO rather than Port IO. */
@@ -682,11 +690,14 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
ide_init_sgiioc4(hwif);
- if (dma_base)
- ide_dma_sgiioc4(hwif, dma_base);
- else
+ hwif->autodma = 0;
+
+ if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) {
+ hwif->autodma = 1;
+ hwif->drives[1].autodma = hwif->drives[0].autodma = 1;
+ } else
printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
- hwif->name, d->name);
+ hwif->name, DRV_NAME);
if (probe_hwif_init(hwif))
return -EIO;
@@ -698,7 +709,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
}
static unsigned int __devinit
-pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
+pci_init_sgiioc4(struct pci_dev *dev)
{
unsigned int class_rev;
int ret;
@@ -706,30 +717,20 @@ pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
- d->name, pci_name(dev), class_rev);
+ DRV_NAME, pci_name(dev), class_rev);
if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
- "firmware is obsolete - please upgrade to revision"
- "46 or higher\n", d->name, pci_name(dev));
+ "firmware is obsolete - please upgrade to "
+ "revision46 or higher\n",
+ DRV_NAME, pci_name(dev));
ret = -EAGAIN;
goto out;
}
- ret = sgiioc4_ide_setup_pci_device(dev, d);
+ ret = sgiioc4_ide_setup_pci_device(dev);
out:
return ret;
}
-static ide_pci_device_t sgiioc4_chipset __devinitdata = {
- /* Channel 0 */
- .name = "SGIIOC4",
- .init_hwif = ide_init_sgiioc4,
- .init_dma = ide_dma_sgiioc4,
- .channels = 1,
- .autodma = AUTODMA,
- /* SGI IOC4 doesn't have enablebits. */
- .bootable = ON_BOARD,
-};
-
int
ioc4_ide_attach_one(struct ioc4_driver_data *idd)
{
@@ -739,7 +740,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd)
if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
return 0;
- return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset);
+ return pci_init_sgiioc4(idd->idd_pdev);
}
static struct ioc4_submodule ioc4_ide_submodule = {
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 1c3e35487893..5d1e5e52a044 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,9 +1,10 @@
/*
- * linux/drivers/ide/pci/siimage.c Version 1.12 Mar 10 2007
+ * linux/drivers/ide/pci/siimage.c Version 1.16 Jul 13 2007
*
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat <alan@redhat.com>
* Copyright (C) 2007 MontaVista Software, Inc.
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
*
* May be copied or modified under the terms of the GNU General Public License
*
@@ -31,6 +32,10 @@
* unplugging/replugging the virtual CD interface when the DRAC is reset.
* This often causes drivers/ide/siimage to panic but is ok with the rather
* smarter code in libata.
+ *
+ * TODO:
+ * - IORDY fixes
+ * - VDMA support
*/
#include <linux/types.h>
@@ -160,140 +165,90 @@ out:
}
/**
- * siimage_taskfile_timing - turn timing data to a mode
- * @hwif: interface to query
- *
- * Read the timing data for the interface and return the
- * mode that is being used.
- */
-
-static byte siimage_taskfile_timing (ide_hwif_t *hwif)
-{
- u16 timing = 0x328a;
- unsigned long addr = siimage_selreg(hwif, 2);
-
- if (hwif->mmio)
- timing = hwif->INW(addr);
- else
- pci_read_config_word(hwif->pci_dev, addr, &timing);
-
- switch (timing) {
- case 0x10c1: return 4;
- case 0x10c3: return 3;
- case 0x1104:
- case 0x1281: return 2;
- case 0x2283: return 1;
- case 0x328a:
- default: return 0;
- }
-}
-
-/**
- * simmage_tuneproc - tune a drive
+ * sil_tune_pio - tune a drive
* @drive: drive to tune
- * @mode_wanted: the target operating mode
+ * @pio: the desired PIO mode
*
* Load the timing settings for this device mode into the
* controller. If we are in PIO mode 3 or 4 turn on IORDY
* monitoring (bit 9). The TF timing is bits 31:16
*/
-
-static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+
+static void sil_tune_pio(ide_drive_t *drive, u8 pio)
{
+ const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+ const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
ide_hwif_t *hwif = HWIF(drive);
+ ide_drive_t *pair = &hwif->drives[drive->dn ^ 1];
u32 speedt = 0;
u16 speedp = 0;
unsigned long addr = siimage_seldev(drive, 0x04);
unsigned long tfaddr = siimage_selreg(hwif, 0x02);
-
- /* cheat for now and use the docs */
- switch (mode_wanted) {
- case 4:
- speedp = 0x10c1;
- speedt = 0x10c1;
- break;
- case 3:
- speedp = 0x10c3;
- speedt = 0x10c3;
- break;
- case 2:
- speedp = 0x1104;
- speedt = 0x1281;
- break;
- case 1:
- speedp = 0x2283;
- speedt = 0x2283;
- break;
- case 0:
- default:
- speedp = 0x328a;
- speedt = 0x328a;
- break;
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u8 tf_pio = pio;
+ u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84)
+ : (hwif->mmio ? 0xB4 : 0x80);
+ u8 mode = 0;
+ u8 unit = drive->select.b.unit;
+
+ /* trim *taskfile* PIO to the slowest of the master/slave */
+ if (pair->present) {
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+
+ if (pair_pio < tf_pio)
+ tf_pio = pair_pio;
}
+ /* cheat for now and use the docs */
+ speedp = data_speed[pio];
+ speedt = tf_speed[tf_pio];
+
if (hwif->mmio) {
hwif->OUTW(speedp, addr);
hwif->OUTW(speedt, tfaddr);
/* Now set up IORDY */
- if(mode_wanted == 3 || mode_wanted == 4)
+ if (pio > 2)
hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
else
hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
+
+ mode = hwif->INB(base + addr_mask);
+ mode &= ~(unit ? 0x30 : 0x03);
+ mode |= (unit ? 0x10 : 0x01);
+ hwif->OUTB(mode, base + addr_mask);
} else {
pci_write_config_word(hwif->pci_dev, addr, speedp);
pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
speedp &= ~0x200;
/* Set IORDY for mode 3 or 4 */
- if(mode_wanted == 3 || mode_wanted == 4)
+ if (pio > 2)
speedp |= 0x200;
pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
+
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+ mode &= ~(unit ? 0x30 : 0x03);
+ mode |= (unit ? 0x10 : 0x01);
+ pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
}
}
-/**
- * config_siimage_chipset_for_pio - set drive timings
- * @drive: drive to tune
- * @speed we want
- *
- * Compute the best pio mode we can for a given device. Also honour
- * the timings for the driver when dealing with mixed devices. Some
- * of this is ugly but its all wrapped up here
- *
- * The SI680 can also do VDMA - we need to start using that
- *
- * FIXME: we use the BIOS channel timings to avoid driving the task
- * files too fast at the disk. We need to compute the master/slave
- * drive PIO mode properly so that we can up the speed on a hotplug
- * system.
- */
-
-static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- u8 channel_timings = siimage_taskfile_timing(HWIF(drive));
- u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
- /* WARNING PIO timing mess is going to happen b/w devices, argh */
- if ((channel_timings != set_pio) && (set_pio > channel_timings))
- set_pio = channel_timings;
-
- siimage_tuneproc(drive, set_pio);
- speed = XFER_PIO_0 + set_pio;
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
+ sil_tune_pio(drive, pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
* siimage_tune_chipset - set controller timings
* @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * @speed: speed we want to achieve
*
- * Tune the SII chipset for the desired mode. If we can't achieve
- * the desired mode then tune for a lower one, but ultimately
- * make the thing work.
+ * Tune the SII chipset for the desired mode.
*/
-
-static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+
+static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
{
u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
@@ -302,7 +257,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
ide_hwif_t *hwif = HWIF(drive);
u16 ultra = 0, multi = 0;
u8 mode = 0, unit = drive->select.b.unit;
- u8 speed = ide_rate_filter(drive, xferspeed);
unsigned long base = (unsigned long)hwif->hwif_data;
u8 scsc = 0, addr_mask = ((hwif->channel) ?
((hwif->mmio) ? 0xF4 : 0x84) :
@@ -330,20 +284,11 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
scsc = is_sata(hwif) ? 1 : scsc;
switch(speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- siimage_tuneproc(drive, (speed - XFER_PIO_0));
- mode |= ((unit) ? 0x10 : 0x01);
- break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
multi = dma[speed - XFER_MW_DMA_0];
mode |= ((unit) ? 0x20 : 0x02);
- config_siimage_chipset_for_pio(drive, 0);
break;
case XFER_UDMA_6:
case XFER_UDMA_5:
@@ -356,7 +301,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
(ultra5[speed - XFER_UDMA_0]));
mode |= ((unit) ? 0x30 : 0x03);
- config_siimage_chipset_for_pio(drive, 0);
break;
default:
return 1;
@@ -390,7 +334,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- config_siimage_chipset_for_pio(drive, 1);
+ ide_set_max_pio(drive);
return -1;
}
@@ -961,7 +905,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
hwif->resetproc = &siimage_reset;
hwif->speedproc = &siimage_tune_chipset;
- hwif->tuneproc = &siimage_tuneproc;
+ hwif->set_pio_mode = &sil_set_pio_mode;
hwif->reset_poll = &siimage_reset_poll;
hwif->pre_reset = &siimage_pre_reset;
hwif->udma_filter = &sil_udma_filter;
@@ -976,11 +920,11 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
first = 0;
}
}
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ if (hwif->dma_base == 0)
return;
- }
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
@@ -1016,9 +960,9 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
.init_iops = init_iops_siimage, \
.init_hwif = init_hwif_siimage, \
.fixup = siimage_fixup, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t siimage_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 756a9b6eb462..3e18899de631 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/sis5513.c Version 0.25 Jun 10, 2007
+ * linux/drivers/ide/pci/sis5513.c Version 0.27 Jul 14, 2007
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
@@ -519,27 +519,18 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
}
}
-static int sis5513_tune_drive(ide_drive_t *drive, u8 pio)
+static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
config_art_rwp_pio(drive, pio);
- return ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static void sis5513_tuneproc(ide_drive_t *drive, u8 pio)
-{
- (void)sis5513_tune_drive(drive, pio);
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
-
- u8 drive_pci, reg, speed;
u32 regdw;
-
- speed = ide_rate_filter(drive, xferspeed);
+ u8 drive_pci, reg;
/* See config_art_rwp_pio for drive pci config registers */
drive_pci = 0x40;
@@ -582,9 +573,6 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
} else {
- /* if ATA133 disable, we should not set speed above UDMA5 */
- if (speed > XFER_UDMA_5)
- speed = XFER_UDMA_5;
regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
}
@@ -608,12 +596,6 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- return sis5513_tune_drive(drive, speed - XFER_PIO_0);
default:
BUG();
break;
@@ -627,7 +609,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive)
/*
* TODO: always set PIO mode and remove this
*/
- sis5513_tuneproc(drive, 255);
+ ide_set_max_pio(drive);
drive->init_speed = 0;
@@ -635,11 +617,25 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- sis5513_tuneproc(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
+static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ int drive_pci;
+ u32 reg54 = 0, regdw = 0;
+
+ pci_read_config_dword(dev, 0x54, &reg54);
+ drive_pci = ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4;
+ pci_read_config_dword(dev, drive_pci, &regdw);
+
+ /* if ATA133 disable, we should not set speed above UDMA5 */
+ return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
+}
+
/* Chip detection and general config */
static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name)
{
@@ -801,6 +797,7 @@ struct sis_laptop {
static const struct sis_laptop sis_laptop[] = {
/* devid, subvendor, subdev */
{ 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
+ { 0x5513, 0x1734, 0x105f }, /* FSC Amilo A1630 */
/* end marker */
{ 0, }
};
@@ -843,9 +840,12 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14;
- hwif->tuneproc = &sis5513_tuneproc;
+ hwif->set_pio_mode = &sis_set_pio_mode;
hwif->speedproc = &sis5513_tune_chipset;
+ if (chipset_family >= ATA_133)
+ hwif->udma_filter = sis5513_ata133_udma_filter;
+
if (!(hwif->dma_base)) {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -878,10 +878,10 @@ static ide_pci_device_t sis5513_chipset __devinitdata = {
.name = "SIS5513",
.init_chipset = init_chipset_sis5513,
.init_hwif = init_hwif_sis5513,
- .channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index a7323d278c49..f492318ba797 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -52,12 +52,13 @@
* Convert a PIO mode and cycle time to the required on/off times
* for the interface. This has protection against runaway timings.
*/
-static unsigned int get_pio_timings(ide_pio_data_t *p)
+static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
{
unsigned int cmd_on, cmd_off;
+ u8 iordy = 0;
- cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
- cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+ cmd_on = (ide_pio_timings[pio].active_time + 29) / 30;
+ cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
if (cmd_on == 0)
cmd_on = 1;
@@ -65,24 +66,22 @@ static unsigned int get_pio_timings(ide_pio_data_t *p)
if (cmd_off == 0)
cmd_off = 1;
- return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+ if (pio > 2 || ide_dev_has_iordy(drive->id))
+ iordy = 0x40;
+
+ return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
}
/*
* Configure the chipset for PIO mode.
*/
-static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
+static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
int reg = 0x44 + drive->dn * 4;
- ide_pio_data_t p;
u16 drv_ctrl;
- DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
-
- pio = ide_get_best_pio_mode(drive, pio, 5, &p);
-
- drv_ctrl = get_pio_timings(&p);
+ drv_ctrl = get_pio_timings(drive, pio);
/*
* Store the PIO timings so that we can restore them
@@ -101,15 +100,14 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
}
printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
- ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl);
-
- return pio;
+ ide_xfer_verbose(pio + XFER_PIO_0),
+ ide_pio_cycle_time(drive, pio), drv_ctrl);
}
/*
* Configure the drive and chipset for a new transfer speed.
*/
-static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
+static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed)
{
static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
u16 drv_ctrl;
@@ -117,8 +115,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
drive->name, ide_xfer_verbose(speed)));
- speed = ide_rate_filter(drive, speed);
-
switch (speed) {
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
@@ -143,14 +139,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
pci_write_config_word(dev, reg, drv_ctrl);
}
break;
- case XFER_PIO_5:
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- (void) sl82c105_tune_pio(drive, speed - XFER_PIO_0);
- break;
default:
return -1;
}
@@ -323,11 +311,10 @@ static void sl82c105_resetproc(ide_drive_t *drive)
* We only deal with PIO mode here - DMA mode 'using_dma' is not
* initialised at the point that this function is called.
*/
-static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio)
+static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio));
+ sl82c105_tune_pio(drive, pio);
- pio = sl82c105_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
@@ -395,7 +382,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
- hwif->tuneproc = &sl82c105_tune_drive;
+ hwif->set_pio_mode = &sl82c105_set_pio_mode;
hwif->speedproc = &sl82c105_tune_chipset;
hwif->selectproc = &sl82c105_selectproc;
hwif->resetproc = &sl82c105_resetproc;
@@ -449,10 +436,10 @@ static ide_pci_device_t sl82c105_chipset __devinitdata = {
.name = "W82C105",
.init_chipset = init_chipset_sl82c105,
.init_hwif = init_hwif_sl82c105,
- .channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
};
static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 575dbbd8b482..ae8e91324577 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/slc90e66.c Version 0.14 February 8, 2007
+ * linux/drivers/ide/pci/slc90e66.c Version 0.16 Jul 14, 2007
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
@@ -29,20 +29,14 @@ static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
case XFER_UDMA_1:
case XFER_UDMA_0:
case XFER_MW_DMA_2:
- case XFER_PIO_4:
return 4;
case XFER_MW_DMA_1:
- case XFER_PIO_3:
return 3;
case XFER_SW_DMA_2:
- case XFER_PIO_2:
return 2;
case XFER_MW_DMA_0:
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
- case XFER_PIO_1:
- case XFER_PIO_0:
- case XFER_PIO_SLOW:
default:
return 0;
}
@@ -101,19 +95,17 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&ide_lock, flags);
}
-static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
slc90e66_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 maslave = hwif->channel ? 0x42 : 0x40;
- u8 speed = ide_rate_filter(drive, xferspeed);
int sitre = 0, a_speed = 7 << (drive->dn * 4);
int u_speed = 0, u_flag = 1 << drive->dn;
u16 reg4042, reg44, reg48, reg4a;
@@ -133,10 +125,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_0: break;
default: return -1;
}
@@ -157,6 +145,7 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
}
slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed));
+
return ide_config_drive_speed(drive, speed);
}
@@ -168,7 +157,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- slc90e66_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -184,7 +173,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
hwif->speedproc = &slc90e66_tune_chipset;
- hwif->tuneproc = &slc90e66_tune_drive;
+ hwif->set_pio_mode = &slc90e66_set_pio_mode;
pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
@@ -214,10 +203,10 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
static ide_pci_device_t slc90e66_chipset __devinitdata = {
.name = "SLC90E66",
.init_hwif = init_hwif_slc90e66,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 8de1f8e22494..e23b9cfb6eb4 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -13,14 +13,12 @@
#include <linux/pci.h>
#include <linux/ide.h>
-static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
u16 mode, scr = hwif->INW(scr_port);
- speed = ide_rate_filter(drive, speed);
-
switch (speed) {
case XFER_UDMA_4: mode = 0x00c0; break;
case XFER_UDMA_3: mode = 0x00b0; break;
@@ -45,9 +43,8 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
return ide_config_drive_speed(drive, speed);
}
-static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
(void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
}
@@ -173,7 +170,7 @@ static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- tc86c001_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
@@ -195,7 +192,7 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
/* Store the system control register base for convenience... */
hwif->config_data = sc_base;
- hwif->tuneproc = &tc86c001_tune_drive;
+ hwif->set_pio_mode = &tc86c001_set_pio_mode;
hwif->speedproc = &tc86c001_tune_chipset;
hwif->busproc = &tc86c001_busproc;
@@ -248,9 +245,10 @@ static ide_pci_device_t tc86c001_chipset __devinitdata = {
.name = "TC86C001",
.init_chipset = init_chipset_tc86c001,
.init_hwif = init_hwif_tc86c001,
- .channels = 1,
.autodma = AUTODMA,
- .bootable = OFF_BOARD
+ .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
};
static int __devinit tc86c001_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 35e8c612638f..c3ff066eea5a 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -40,7 +40,7 @@
#include <linux/ide.h>
#include <linux/init.h>
-static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -48,7 +48,6 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
u16 timing = 0;
u32 triflex_timings = 0;
u8 unit = (drive->select.b.unit & 0x01);
- u8 speed = ide_rate_filter(drive, xferspeed);
pci_read_config_dword(dev, channel_offset, &triflex_timings);
@@ -94,10 +93,9 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
return (ide_config_drive_speed(drive, speed));
}
-static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
+static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
- (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
+ (void)triflex_tune_chipset(drive, XFER_PIO_0 + pio);
}
static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
@@ -105,16 +103,19 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
if (ide_tune_dma(drive))
return 0;
- triflex_tune_drive(drive, 255);
+ ide_set_max_pio(drive);
return -1;
}
static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
{
- hwif->tuneproc = &triflex_tune_drive;
+ hwif->set_pio_mode = &triflex_set_pio_mode;
hwif->speedproc = &triflex_tune_chipset;
+ if (hwif->dma_base == 0)
+ return;
+
hwif->atapi_dma = 1;
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
@@ -129,10 +130,10 @@ static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
static ide_pci_device_t triflex_device __devinitdata = {
.name = "TRIFLEX",
.init_hwif = init_hwif_triflex,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit triflex_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index cbb1b11119a5..dc4f4e298e00 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -327,7 +327,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
static ide_pci_device_t trm290_chipset __devinitdata = {
.name = "TRM290",
.init_hwif = init_hwif_trm290,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
};
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 27e92fb9f95e..378feb491ec4 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -1,6 +1,6 @@
/*
*
- * Version 3.45
+ * Version 3.48
*
* VIA IDE driver for Linux. Supported southbridges:
*
@@ -74,6 +74,7 @@ static struct via_isa_bridge {
u8 udma_mask;
u8 flags;
} via_isa_bridges[] = {
+ { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
@@ -157,7 +158,7 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
* by upper layers.
*/
-static int via_set_drive(ide_drive_t *drive, u8 speed)
+static int via_set_drive(ide_drive_t *drive, const u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
@@ -194,21 +195,16 @@ static int via_set_drive(ide_drive_t *drive, u8 speed)
}
/**
- * via82cxxx_tune_drive - PIO setup
- * @drive: drive to set up
- * @pio: mode to use (255 for 'best possible')
+ * via_set_pio_mode - PIO setup
+ * @drive: drive
+ * @pio: PIO mode number
*
* A callback from the upper layers for PIO-only tuning.
*/
-static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+static void via_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- if (pio == 255) {
- via_set_drive(drive, ide_find_best_pio_mode(drive));
- return;
- }
-
- via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
+ via_set_drive(drive, XFER_PIO_0 + pio);
}
/**
@@ -221,16 +217,11 @@ static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
static int via82cxxx_ide_dma_check (ide_drive_t *drive)
{
- u8 speed = ide_max_dma_mode(drive);
-
- if (speed == 0)
- speed = ide_find_best_pio_mode(drive);
-
- via_set_drive(drive, speed);
-
- if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ if (ide_tune_dma(drive))
return 0;
+ ide_set_max_pio(drive);
+
return -1;
}
@@ -418,7 +409,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "Acer Ferrari 3400",
.matches = {
@@ -429,19 +420,26 @@ static struct dmi_system_id cable_dmi_table[] = {
{ }
};
-static int via_cable_override(void)
+static int via_cable_override(struct pci_dev *pdev)
{
/* Systems by DMI */
if (dmi_check_system(cable_dmi_table))
return 1;
+
+ /* Arima W730-K8/Targa Visionary 811/... */
+ if (pdev->subsystem_vendor == 0x161F &&
+ pdev->subsystem_device == 0x2032)
+ return 1;
+
return 0;
}
static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
{
- struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
+ struct pci_dev *pdev = hwif->pci_dev;
+ struct via82cxxx_dev *vdev = pci_get_drvdata(pdev);
- if (via_cable_override())
+ if (via_cable_override(pdev))
return ATA_CBL_PATA40_SHORT;
if ((vdev->via_80w >> hwif->channel) & 1)
@@ -457,7 +455,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
hwif->autodma = 0;
- hwif->tuneproc = &via82cxxx_tune_drive;
+ hwif->set_pio_mode = &via_set_pio_mode;
hwif->speedproc = &via_set_drive;
@@ -498,18 +496,22 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
.name = "VP_IDE",
.init_chipset = init_chipset_via82cxxx,
.init_hwif = init_hwif_via82cxxx,
- .channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
- .bootable = ON_BOARD
+ .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
+ | IDE_HFLAG_PIO_NO_DOWNGRADE,
+ .pio_mask = ATA_PIO5,
},{ /* 1 */
.name = "VP_IDE",
.init_chipset = init_chipset_via82cxxx,
.init_hwif = init_hwif_via82cxxx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
+ | IDE_HFLAG_PIO_NO_DOWNGRADE,
+ .pio_mask = ATA_PIO5,
}
};
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 82de2d781f2e..df2e92034f5d 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -32,7 +32,6 @@
#include <asm/mpc8xx.h>
#include <asm/mmu.h>
#include <asm/processor.h>
-#include <asm/residual.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/ide.h>
@@ -46,7 +45,7 @@ static void print_funcid (int func);
static int check_ide_device (unsigned long base);
static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio);
typedef struct ide_ioport_desc {
unsigned long base_off; /* Offset to PCMCIA memory */
@@ -315,8 +314,8 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
#endif /* CONFIG_IDE_8xx_PCCARD */
}
- /* register routine to tune PIO mode */
- ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+ ide_hwifs[data_port].pio_mask = ATA_PIO4;
+ ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
/* Enable Harddisk Interrupt,
@@ -401,8 +400,8 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
*irq = ioport_dsc[data_port].irq;
}
- /* register routine to tune PIO mode */
- ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+ ide_hwifs[data_port].pio_mask = ATA_PIO4;
+ ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
/* Enable Harddisk Interrupt,
@@ -426,25 +425,13 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */
#endif
-
/* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- ide_pio_data_t d;
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
volatile pcmconf8xx_t *pcmp;
ulong timing, mask, reg;
-#endif
-
- pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-#if 1
- printk("%s[%d] %s: best PIO mode: %d\n",
- __FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index e46f47206542..f759a5397865 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -6,6 +6,7 @@
* for doing DMA.
*
* Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -311,7 +312,8 @@ static struct kauai_timing kauai_pio_timings[] =
{ 240 , 0x0800038b },
{ 239 , 0x0800030c },
{ 180 , 0x05000249 },
- { 120 , 0x04000148 }
+ { 120 , 0x04000148 },
+ { 0 , 0 },
};
static struct kauai_timing kauai_mdma_timings[] =
@@ -351,7 +353,8 @@ static struct kauai_timing shasta_pio_timings[] =
{ 240 , 0x040003cd },
{ 239 , 0x040003cd },
{ 180 , 0x0400028b },
- { 120 , 0x0400010a }
+ { 120 , 0x0400010a },
+ { 0 , 0 },
};
static struct kauai_timing shasta_mdma_timings[] =
@@ -411,8 +414,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
static void pmac_ide_selectproc(ide_drive_t *drive);
static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
@@ -604,6 +605,9 @@ out:
drive->id->dma_1word |= 0x0101; break;
default: break;
}
+ if (!drive->init_speed)
+ drive->init_speed = command;
+ drive->current_speed = command;
}
enable_irq(hwif->irq);
return result;
@@ -613,26 +617,26 @@ out:
* Old tuning functions (called on hdparm -p), sets up drive PIO timings
*/
static void
-pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- ide_pio_data_t d;
u32 *timings;
unsigned accessTicks, recTicks;
unsigned accessTime, recTime;
pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
-
+ unsigned int cycle_time;
+
if (pmif == NULL)
return;
/* which drive is it ? */
timings = &pmif->timings[drive->select.b.unit & 0x01];
- pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+ cycle_time = ide_pio_cycle_time(drive, pio);
switch (pmif->kind) {
case controller_sh_ata6: {
/* 133Mhz cell */
- u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+ u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
if (tr == 0)
return;
*timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
@@ -641,7 +645,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
case controller_un_ata6:
case controller_k2_ata6: {
/* 100Mhz cell */
- u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time);
+ u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
if (tr == 0)
return;
*timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
@@ -649,7 +653,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
}
case controller_kl_ata4:
/* 66Mhz cell */
- recTime = d.cycle_time - ide_pio_timings[pio].active_time
+ recTime = cycle_time - ide_pio_timings[pio].active_time
- ide_pio_timings[pio].setup_time;
recTime = max(recTime, 150U);
accessTime = ide_pio_timings[pio].active_time;
@@ -665,7 +669,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
default: {
/* 33Mhz cell */
int ebit = 0;
- recTime = d.cycle_time - ide_pio_timings[pio].active_time
+ recTime = cycle_time - ide_pio_timings[pio].active_time
- ide_pio_timings[pio].setup_time;
recTime = max(recTime, 150U);
accessTime = ide_pio_timings[pio].active_time;
@@ -694,8 +698,10 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
drive->name, pio, *timings);
#endif
- if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
- pmac_ide_do_update_timings(drive);
+ if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio))
+ return;
+
+ pmac_ide_do_update_timings(drive);
}
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
@@ -911,13 +917,12 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
/*
* Speedproc. This function is called by the core to set any of the standard
- * timing (PIO, MDMA or UDMA) to both the drive and the controller.
+ * DMA timing (MDMA or UDMA) to both the drive and the controller.
* You may notice we don't use this function on normal "dma check" operation,
* our dedicated function is more precise as it uses the drive provided
* cycle time value. We should probably fix this one to deal with that too...
*/
-static int
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
+static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed)
{
int unit = (drive->select.b.unit & 0x01);
int ret = 0;
@@ -933,17 +938,9 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
case XFER_UDMA_6:
- if (pmif->kind != controller_sh_ata6)
- return 1;
case XFER_UDMA_5:
- if (pmif->kind != controller_un_ata6 &&
- pmif->kind != controller_k2_ata6 &&
- pmif->kind != controller_sh_ata6)
- return 1;
case XFER_UDMA_4:
case XFER_UDMA_3:
- if (drive->hwif->cbl != ATA_CBL_PATA80)
- return 1;
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
@@ -967,13 +964,6 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
case XFER_SW_DMA_0:
return 1;
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- pmac_ide_tuneproc(drive, speed & 0x07);
- break;
default:
ret = 1;
}
@@ -985,7 +975,6 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
return ret;
pmac_ide_do_update_timings(drive);
- drive->current_speed = speed;
return 0;
}
@@ -1247,7 +1236,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
- hwif->tuneproc = pmac_ide_tuneproc;
+ hwif->pio_mask = ATA_PIO4;
+ hwif->set_pio_mode = pmac_ide_set_pio_mode;
if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6
|| pmif->kind == controller_sh_ata6)
@@ -1542,6 +1532,7 @@ static struct pci_device_id pmac_ide_pci_match[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {},
};
static struct pci_driver pmac_ide_pci_driver = {
@@ -1735,11 +1726,6 @@ pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
/* Apply timings to controller */
*timings = timing_local[0];
*timings2 = timing_local[1];
-
- /* Set speed info in drive */
- drive->current_speed = mode;
- if (!drive->init_speed)
- drive->init_speed = mode;
return 1;
}
@@ -1791,11 +1777,6 @@ pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
*timings = timing_local[0];
*timings2 = timing_local[1];
- /* Set speed info in drive */
- drive->current_speed = mode;
- if (!drive->init_speed)
- drive->init_speed = mode;
-
return 1;
}
@@ -1808,9 +1789,7 @@ pmac_ide_dma_check(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
- pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
int enable = 1;
- int map;
drive->using_dma = 0;
if (drive->media == ide_floppy)
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index c88d33225cf9..1129f8c30840 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -5,12 +5,6 @@
*
* Copyright (c) 1995-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
- *
- * Recent Changes
- * Split the set up function into multiple functions
- * Use pci_set_master
- * Fix misreporting of I/O v MMIO problems
- * Initial fixups for simplex devices
*/
/*
@@ -407,7 +401,7 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d,
unsigned long ctl = 0, base = 0;
ide_hwif_t *hwif;
- if ((d->flags & IDEPCI_FLAG_ISA_PORTS) == 0) {
+ if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
/* Possibly we should fail if these checks report true */
ide_pci_check_iomem(dev, d, 2*port);
ide_pci_check_iomem(dev, d, 2*port+1);
@@ -571,7 +565,7 @@ out:
void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, ata_index_t *index)
{
- int port;
+ int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
int at_least_one_hwif_enabled = 0;
ide_hwif_t *hwif, *mate = NULL;
u8 tmp;
@@ -582,16 +576,13 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
* Set up the IDE ports
*/
- for (port = 0; port <= 1; ++port) {
+ for (port = 0; port < channels; ++port) {
ide_pci_enablebit_t *e = &(d->enablebits[port]);
if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
(tmp & e->mask) != e->val))
continue; /* port not enabled */
- if (d->channels <= port)
- break;
-
if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
continue;
@@ -616,6 +607,9 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
else
ide_hwif_setup_dma(dev, d, hwif);
bypass_legacy_dma:
+ hwif->host_flags = d->host_flags;
+ hwif->pio_mask = d->pio_mask;
+
if (d->init_hwif)
/* Call chipset-specific routine
* for each enabled hwif
@@ -822,19 +816,15 @@ static int __init ide_scan_pcidev(struct pci_dev *dev)
struct list_head *l;
struct pci_driver *d;
- list_for_each(l, &ide_pci_drivers)
- {
+ list_for_each(l, &ide_pci_drivers) {
d = list_entry(l, struct pci_driver, node);
- if(d->id_table)
- {
- const struct pci_device_id *id = pci_match_id(d->id_table, dev);
- if(id != NULL)
- {
- if(d->probe(dev, id) >= 0)
- {
- dev->driver = d;
- return 1;
- }
+ if (d->id_table) {
+ const struct pci_device_id *id = pci_match_id(d->id_table,
+ dev);
+ if (id != NULL && d->probe(dev, id) >= 0) {
+ dev->driver = d;
+ pci_dev_get(dev);
+ return 1;
}
}
}
@@ -857,15 +847,13 @@ void __init ide_scan_pcibus (int scan_direction)
struct list_head *l, *n;
pre_init = 0;
- if (!scan_direction) {
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ if (!scan_direction)
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
ide_scan_pcidev(dev);
- }
- } else {
- while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ else
+ while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev))
+ != NULL)
ide_scan_pcidev(dev);
- }
- }
/*
* Hand the drivers over to the PCI layer now we
@@ -875,12 +863,9 @@ void __init ide_scan_pcibus (int scan_direction)
list_for_each_safe(l, n, &ide_pci_drivers) {
list_del(l);
d = list_entry(l, struct pci_driver, node);
- if (__pci_register_driver(d, d->driver.owner,
- d->driver.mod_name)) {
- printk(KERN_ERR "%s: failed to register driver "
- "for %s\n", __FUNCTION__,
- d->driver.mod_name);
- }
+ if (__pci_register_driver(d, d->driver.owner, d->driver.mod_name))
+ printk(KERN_ERR "%s: failed to register driver for %s\n",
+ __FUNCTION__, d->driver.mod_name);
}
}
#endif
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 8012b3b0ce75..545663ef820b 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -97,7 +97,7 @@ config IEEE1394_SBP2
config IEEE1394_SBP2_PHYS_DMA
bool "Enable replacement for physical DMA in SBP2"
- depends on IEEE1394 && IEEE1394_SBP2 && EXPERIMENTAL && (X86_32 || PPC_32)
+ depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
help
This builds sbp2 for use with non-OHCI host adapters which do not
support physical DMA or for when ohci1394 is run with phys_dma=0.
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 93362eed94ed..dc9dce22f6a8 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -159,14 +159,16 @@ MODULE_PARM_DESC(max_partial_datagrams,
static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len);
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len);
static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+static int ether1394_header_parse(const struct sk_buff *skb,
+ unsigned char *haddr);
+static int ether1394_header_cache(const struct neighbour *neigh,
+ struct hh_cache *hh);
static void ether1394_header_cache_update(struct hh_cache *hh,
- struct net_device *dev,
- unsigned char *haddr);
+ const struct net_device *dev,
+ const unsigned char *haddr);
static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
static void ether1394_iso(struct hpsb_iso *iso);
@@ -506,6 +508,14 @@ static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
spin_unlock_irqrestore(&priv->lock, flags);
}
+static const struct header_ops ether1394_header_ops = {
+ .create = ether1394_header,
+ .rebuild = ether1394_rebuild_header,
+ .cache = ether1394_header_cache,
+ .cache_update = ether1394_header_cache_update,
+ .parse = ether1394_header_parse,
+};
+
static void ether1394_init_dev(struct net_device *dev)
{
dev->open = ether1394_open;
@@ -515,11 +525,7 @@ static void ether1394_init_dev(struct net_device *dev)
dev->tx_timeout = ether1394_tx_timeout;
dev->change_mtu = ether1394_change_mtu;
- dev->hard_header = ether1394_header;
- dev->rebuild_header = ether1394_rebuild_header;
- dev->hard_header_cache = ether1394_header_cache;
- dev->header_cache_update= ether1394_header_cache_update;
- dev->hard_header_parse = ether1394_header_parse;
+ dev->header_ops = &ether1394_header_ops;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
@@ -598,7 +604,6 @@ static void ether1394_add_host(struct hpsb_host *host)
goto out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &host->device);
priv = netdev_priv(dev);
@@ -711,8 +716,8 @@ static void ether1394_host_reset(struct hpsb_host *host)
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp). */
static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct eth1394hdr *eth =
(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
@@ -752,15 +757,15 @@ static int ether1394_rebuild_header(struct sk_buff *skb)
return 0;
}
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int ether1394_header_parse(const struct sk_buff *skb,
+ unsigned char *haddr)
{
- struct net_device *dev = skb->dev;
-
- memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
+ memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
return ETH1394_ALEN;
}
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int ether1394_header_cache(const struct neighbour *neigh,
+ struct hh_cache *hh)
{
unsigned short type = hh->hh_type;
struct net_device *dev = neigh->dev;
@@ -779,8 +784,8 @@ static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
/* Called by Address Resolution module to notify changes in address. */
static void ether1394_header_cache_update(struct hh_cache *hh,
- struct net_device *dev,
- unsigned char * haddr)
+ const struct net_device *dev,
+ const unsigned char * haddr)
{
memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
}
@@ -900,8 +905,8 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
}
/* Now add the ethernet header. */
- if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
- skb->len) >= 0)
+ if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
+ skb->len) >= 0)
ret = ether1394_type_trans(skb, dev);
return ret;
@@ -1729,7 +1734,7 @@ static int __init ether1394_init_module(void)
packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct packet_task),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!packet_task_cache)
return -ENOMEM;
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index ee45259573c8..98fd985a32ff 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1273,7 +1273,7 @@ static void __exit ieee1394_cleanup(void)
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
}
-fs_initcall(ieee1394_init); /* same as ohci1394 */
+module_init(ieee1394_init);
module_exit(ieee1394_cleanup);
/* Exported symbols */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 2ffd53461db6..1939fee616ec 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -153,8 +153,7 @@ struct host_info {
};
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
static void nodemgr_resume_ne(struct node_entry *ne);
static void nodemgr_remove_ne(struct node_entry *ne);
static struct node_entry *find_entry_by_guid(u64 guid);
@@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
#ifdef CONFIG_HOTPLUG
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct unit_directory *ud;
- int i = 0;
- int length = 0;
int retval = 0;
/* ieee1394:venNmoNspNverN */
char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
@@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
#define PUT_ENVP(fmt,val) \
do { \
- retval = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &length, \
- fmt, val); \
+ retval = add_uevent_var(env, fmt, val); \
if (retval) \
return retval; \
} while (0)
@@ -1201,15 +1195,12 @@ do { \
#undef PUT_ENVP
- envp[i] = NULL;
-
return 0;
}
#else
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 5667c8102efc..372c5c16eb31 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3537,7 +3537,5 @@ static int __init ohci1394_init(void)
return pci_register_driver(&ohci1394_pci_driver);
}
-/* Register before most other device drivers.
- * Useful for remote debugging via physical DMA, e.g. using firescope. */
-fs_initcall(ohci1394_init);
+module_init(ohci1394_init);
module_exit(ohci1394_cleanup);
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 336e5ff4cfcf..cadf0479cce5 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -2677,7 +2677,7 @@ static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
struct raw1394_iso_packets32 __user *arg)
{
compat_uptr_t infos32;
- void *infos;
+ void __user *infos;
long err = -EFAULT;
struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index e882cb951b47..a81ba8fca0db 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -513,9 +513,9 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
return 0;
}
-static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu)
+static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
+ struct hpsb_host *host)
{
- struct hpsb_host *host = lu->hi->host;
struct list_head *lh, *next;
struct sbp2_command_info *cmd;
unsigned long flags;
@@ -773,11 +773,6 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
SBP2_ERR("failed to register lower 4GB address range");
goto failed_alloc;
}
-#else
- if (dma_set_mask(hi->host->device.parent, DMA_32BIT_MASK)) {
- SBP2_ERR("failed to set 4GB DMA mask");
- goto failed_alloc;
- }
#endif
}
@@ -927,15 +922,16 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
if (!lu)
return;
-
hi = lu->hi;
+ if (!hi)
+ goto no_hi;
if (lu->shost) {
scsi_remove_host(lu->shost);
scsi_host_put(lu->shost);
}
flush_scheduled_work();
- sbp2util_remove_command_orb_pool(lu);
+ sbp2util_remove_command_orb_pool(lu, hi->host);
list_del(&lu->lu_list);
@@ -976,9 +972,8 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
lu->ud->device.driver_data = NULL;
- if (hi)
- module_put(hi->host->driver->owner);
-
+ module_put(hi->host->driver->owner);
+no_hi:
kfree(lu);
}
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index a91001c59b69..5381c80de10a 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -161,8 +161,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in)
if (ip_route_output_key(&rt, &fl))
return;
- arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev,
- rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL);
+ neigh_event_send(rt->u.dst.neighbour, NULL);
ip_rt_put(rt);
}
@@ -295,10 +294,9 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
struct addr_req *req;
int ret = 0;
- req = kmalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
- memset(req, 0, sizeof *req);
if (src_addr)
memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index db2633e4aae6..ae7c2880e624 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -78,15 +78,14 @@ ib_get_agent_port(struct ib_device *device, int port_num)
return entry;
}
-int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
- struct ib_wc *wc, struct ib_device *device,
- int port_num, int qpn)
+void agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
+ struct ib_wc *wc, struct ib_device *device,
+ int port_num, int qpn)
{
struct ib_agent_port_private *port_priv;
struct ib_mad_agent *agent;
struct ib_mad_send_buf *send_buf;
struct ib_ah *ah;
- int ret;
struct ib_mad_send_wr_private *mad_send_wr;
if (device->node_type == RDMA_NODE_IB_SWITCH)
@@ -96,23 +95,21 @@ int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
if (!port_priv) {
printk(KERN_ERR SPFX "Unable to find port agent\n");
- return -ENODEV;
+ return;
}
agent = port_priv->agent[qpn];
ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
if (IS_ERR(ah)) {
- ret = PTR_ERR(ah);
- printk(KERN_ERR SPFX "ib_create_ah_from_wc error:%d\n", ret);
- return ret;
+ printk(KERN_ERR SPFX "ib_create_ah_from_wc error\n");
+ return;
}
send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0,
IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
GFP_KERNEL);
if (IS_ERR(send_buf)) {
- ret = PTR_ERR(send_buf);
- printk(KERN_ERR SPFX "ib_create_send_mad error:%d\n", ret);
+ printk(KERN_ERR SPFX "ib_create_send_mad error\n");
goto err1;
}
@@ -126,16 +123,15 @@ int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
mad_send_wr->send_wr.wr.ud.port_num = port_num;
}
- if ((ret = ib_post_send_mad(send_buf, NULL))) {
- printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret);
+ if (ib_post_send_mad(send_buf, NULL)) {
+ printk(KERN_ERR SPFX "ib_post_send_mad error\n");
goto err2;
}
- return 0;
+ return;
err2:
ib_free_send_mad(send_buf);
err1:
ib_destroy_ah(ah);
- return ret;
}
static void agent_send_handler(struct ib_mad_agent *mad_agent,
diff --git a/drivers/infiniband/core/agent.h b/drivers/infiniband/core/agent.h
index 86d72fab37b0..fb9ed1489f95 100644
--- a/drivers/infiniband/core/agent.h
+++ b/drivers/infiniband/core/agent.h
@@ -46,8 +46,8 @@ extern int ib_agent_port_open(struct ib_device *device, int port_num);
extern int ib_agent_port_close(struct ib_device *device, int port_num);
-extern int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
- struct ib_wc *wc, struct ib_device *device,
- int port_num, int qpn);
+extern void agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
+ struct ib_wc *wc, struct ib_device *device,
+ int port_num, int qpn);
#endif /* __AGENT_H_ */
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 9820c67ba47d..2e39236d189f 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -2219,6 +2219,9 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
{
struct cm_id_private *cm_id_priv;
struct ib_mad_send_buf *msg;
+ enum ib_cm_state cm_state;
+ enum ib_cm_lap_state lap_state;
+ enum cm_msg_response msg_response;
void *data;
unsigned long flags;
int ret;
@@ -2235,48 +2238,40 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
spin_lock_irqsave(&cm_id_priv->lock, flags);
switch(cm_id_priv->id.state) {
case IB_CM_REQ_RCVD:
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- goto error1;
-
- cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- CM_MSG_RESPONSE_REQ, service_timeout,
- private_data, private_data_len);
- ret = ib_post_send_mad(msg, NULL);
- if (ret)
- goto error2;
- cm_id->state = IB_CM_MRA_REQ_SENT;
+ cm_state = IB_CM_MRA_REQ_SENT;
+ lap_state = cm_id->lap_state;
+ msg_response = CM_MSG_RESPONSE_REQ;
break;
case IB_CM_REP_RCVD:
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- goto error1;
-
- cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- CM_MSG_RESPONSE_REP, service_timeout,
- private_data, private_data_len);
- ret = ib_post_send_mad(msg, NULL);
- if (ret)
- goto error2;
- cm_id->state = IB_CM_MRA_REP_SENT;
+ cm_state = IB_CM_MRA_REP_SENT;
+ lap_state = cm_id->lap_state;
+ msg_response = CM_MSG_RESPONSE_REP;
break;
case IB_CM_ESTABLISHED:
+ cm_state = cm_id->state;
+ lap_state = IB_CM_MRA_LAP_SENT;
+ msg_response = CM_MSG_RESPONSE_OTHER;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error1;
+ }
+
+ if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) {
ret = cm_alloc_msg(cm_id_priv, &msg);
if (ret)
goto error1;
cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- CM_MSG_RESPONSE_OTHER, service_timeout,
+ msg_response, service_timeout,
private_data, private_data_len);
ret = ib_post_send_mad(msg, NULL);
if (ret)
goto error2;
- cm_id->lap_state = IB_CM_MRA_LAP_SENT;
- break;
- default:
- ret = -EINVAL;
- goto error1;
}
+
+ cm_id->state = cm_state;
+ cm_id->lap_state = lap_state;
cm_id_priv->service_timeout = service_timeout;
cm_set_private_data(cm_id_priv, data, private_data_len);
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -3374,7 +3369,7 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
}
EXPORT_SYMBOL(ib_cm_init_qp_attr);
-void cm_get_ack_delay(struct cm_device *cm_dev)
+static void cm_get_ack_delay(struct cm_device *cm_dev)
{
struct ib_device_attr attr;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 23af7a032a03..93644f82592c 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -52,6 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL");
#define CMA_CM_RESPONSE_TIMEOUT 20
#define CMA_MAX_CM_RETRIES 15
+#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
static void cma_add_one(struct ib_device *device);
static void cma_remove_one(struct ib_device *device);
@@ -138,6 +139,7 @@ struct rdma_id_private {
u32 qkey;
u32 qp_num;
u8 srq;
+ u8 tos;
};
struct cma_multicast {
@@ -573,7 +575,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
break;
case RDMA_TRANSPORT_IWARP:
if (!id_priv->cm_id.iw) {
- qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+ qp_attr->qp_access_flags = 0;
*qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
} else
ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
@@ -1089,6 +1091,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
event.param.ud.private_data_len =
IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
} else {
+ ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
conn_id = cma_new_conn_id(&listen_id->id, ib_event);
cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
ib_event->private_data, offset);
@@ -1474,6 +1477,15 @@ err:
}
EXPORT_SYMBOL(rdma_listen);
+void rdma_set_service_type(struct rdma_cm_id *id, int tos)
+{
+ struct rdma_id_private *id_priv;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ id_priv->tos = (u8) tos;
+}
+EXPORT_SYMBOL(rdma_set_service_type);
+
static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
void *context)
{
@@ -1498,23 +1510,37 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
struct cma_work *work)
{
- struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr;
+ struct rdma_addr *addr = &id_priv->id.route.addr;
struct ib_sa_path_rec path_rec;
+ ib_sa_comp_mask comp_mask;
+ struct sockaddr_in6 *sin6;
memset(&path_rec, 0, sizeof path_rec);
- ib_addr_get_sgid(addr, &path_rec.sgid);
- ib_addr_get_dgid(addr, &path_rec.dgid);
- path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
+ ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
+ ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
+ path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
path_rec.numb_path = 1;
path_rec.reversible = 1;
+ path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr);
+
+ comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
+ IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
+ IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
+
+ if (addr->src_addr.sa_family == AF_INET) {
+ path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
+ comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
+ } else {
+ sin6 = (struct sockaddr_in6 *) &addr->src_addr;
+ path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
+ comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+ }
id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
- id_priv->id.port_num, &path_rec,
- IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
- IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
- IB_SA_PATH_REC_REVERSIBLE,
- timeout_ms, GFP_KERNEL,
- cma_query_handler, work, &id_priv->query);
+ id_priv->id.port_num, &path_rec,
+ comp_mask, timeout_ms,
+ GFP_KERNEL, cma_query_handler,
+ work, &id_priv->query);
return (id_priv->query_id < 0) ? id_priv->query_id : 0;
}
@@ -1866,13 +1892,14 @@ err1:
static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
{
struct rdma_bind_list *bind_list;
- int port, ret;
+ int port, ret, low, high;
bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list)
return -ENOMEM;
retry:
+ /* FIXME: add proper port randomization per like inet_csk_get_port */
do {
ret = idr_get_new_above(ps, bind_list, next_port, &port);
} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
@@ -1880,18 +1907,19 @@ retry:
if (ret)
goto err1;
- if (port > sysctl_local_port_range[1]) {
- if (next_port != sysctl_local_port_range[0]) {
+ inet_get_local_port_range(&low, &high);
+ if (port > high) {
+ if (next_port != low) {
idr_remove(ps, port);
- next_port = sysctl_local_port_range[0];
+ next_port = low;
goto retry;
}
ret = -EADDRNOTAVAIL;
goto err2;
}
- if (port == sysctl_local_port_range[1])
- next_port = sysctl_local_port_range[0];
+ if (port == high)
+ next_port = low;
else
next_port = port + 1;
@@ -2769,12 +2797,12 @@ static void cma_remove_one(struct ib_device *device)
static int cma_init(void)
{
- int ret;
+ int ret, low, high;
get_random_bytes(&next_port, sizeof next_port);
- next_port = ((unsigned int) next_port %
- (sysctl_local_port_range[1] - sysctl_local_port_range[0])) +
- sysctl_local_port_range[0];
+ inet_get_local_port_range(&low, &high);
+ next_port = ((unsigned int) next_port % (high - low)) + low;
+
cma_wq = create_singlethread_workqueue("rdma_cm");
if (!cma_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 3ada17c0f239..5ac5ffee05cb 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -120,12 +120,12 @@ static struct ib_device *__ib_device_get_by_name(const char *name)
static int alloc_name(char *name)
{
- long *inuse;
+ unsigned long *inuse;
char buf[IB_DEVICE_NAME_MAX];
struct ib_device *device;
int i;
- inuse = (long *) get_zeroed_page(GFP_KERNEL);
+ inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL);
if (!inuse)
return -ENOMEM;
@@ -702,7 +702,7 @@ int ib_find_pkey(struct ib_device *device,
if (ret)
return ret;
- if (pkey == tmp_pkey) {
+ if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) {
*index = i;
return 0;
}
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index a06bcc65a871..d7f64525469b 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -152,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
#ifdef DEBUG
if (fmr->ref_count !=0) {
- printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d",
+ printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d\n",
fmr, fmr->ref_count);
}
#endif
@@ -170,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
ret = ib_unmap_fmr(&fmr_list);
if (ret)
- printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret);
+ printk(KERN_WARNING PFX "ib_unmap_fmr returned %d\n", ret);
spin_lock_irq(&pool->pool_lock);
list_splice(&unmap_list, &pool->free_list);
@@ -235,13 +235,13 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
attr = kmalloc(sizeof *attr, GFP_KERNEL);
if (!attr) {
- printk(KERN_WARNING PFX "couldn't allocate device attr struct");
+ printk(KERN_WARNING PFX "couldn't allocate device attr struct\n");
return ERR_PTR(-ENOMEM);
}
ret = ib_query_device(device, attr);
if (ret) {
- printk(KERN_WARNING PFX "couldn't query device: %d", ret);
+ printk(KERN_WARNING PFX "couldn't query device: %d\n", ret);
kfree(attr);
return ERR_PTR(ret);
}
@@ -255,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
pool = kmalloc(sizeof *pool, GFP_KERNEL);
if (!pool) {
- printk(KERN_WARNING PFX "couldn't allocate pool struct");
+ printk(KERN_WARNING PFX "couldn't allocate pool struct\n");
return ERR_PTR(-ENOMEM);
}
@@ -272,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
GFP_KERNEL);
if (!pool->cache_bucket) {
- printk(KERN_WARNING PFX "Failed to allocate cache in pool");
+ printk(KERN_WARNING PFX "Failed to allocate cache in pool\n");
ret = -ENOMEM;
goto out_free_pool;
}
@@ -296,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
"ib_fmr(%s)",
device->name);
if (IS_ERR(pool->thread)) {
- printk(KERN_WARNING PFX "couldn't start cleanup thread");
+ printk(KERN_WARNING PFX "couldn't start cleanup thread\n");
ret = PTR_ERR(pool->thread);
goto out_free_pool;
}
@@ -314,7 +314,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
GFP_KERNEL);
if (!fmr) {
printk(KERN_WARNING PFX "failed to allocate fmr "
- "struct for FMR %d", i);
+ "struct for FMR %d\n", i);
goto out_fail;
}
@@ -326,7 +326,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
if (IS_ERR(fmr->fmr)) {
printk(KERN_WARNING PFX "fmr_create failed "
- "for FMR %d", i);
+ "for FMR %d\n", i);
kfree(fmr);
goto out_fail;
}
@@ -381,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
}
if (i < pool->pool_size)
- printk(KERN_WARNING PFX "pool still has %d regions registered",
+ printk(KERN_WARNING PFX "pool still has %d regions registered\n",
pool->pool_size - i);
kfree(pool->cache_bucket);
@@ -518,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
#ifdef DEBUG
if (fmr->ref_count < 0)
- printk(KERN_WARNING PFX "FMR %p has ref count %d < 0",
+ printk(KERN_WARNING PFX "FMR %p has ref count %d < 0\n",
fmr, fmr->ref_count);
#endif
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 6b8faca02f8a..6f4287716ab1 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1842,16 +1842,11 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
{
struct ib_mad_qp_info *qp_info;
struct ib_mad_private_header *mad_priv_hdr;
- struct ib_mad_private *recv, *response;
+ struct ib_mad_private *recv, *response = NULL;
struct ib_mad_list_head *mad_list;
struct ib_mad_agent_private *mad_agent;
int port_num;
- response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
- if (!response)
- printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory "
- "for response buffer\n");
-
mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id;
qp_info = mad_list->mad_queue->qp_info;
dequeue_mad(mad_list);
@@ -1879,6 +1874,13 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num))
goto out;
+ response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
+ if (!response) {
+ printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory "
+ "for response buffer\n");
+ goto out;
+ }
+
if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH)
port_num = wc->port_num;
else
@@ -1914,12 +1916,11 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
response->header.recv_wc.recv_buf.mad = &response->mad.mad;
response->header.recv_wc.recv_buf.grh = &response->grh;
- if (!agent_send_response(&response->mad.mad,
- &response->grh, wc,
- port_priv->device,
- smi_get_fwd_port(&recv->mad.smp),
- qp_info->qp->qp_num))
- response = NULL;
+ agent_send_response(&response->mad.mad,
+ &response->grh, wc,
+ port_priv->device,
+ smi_get_fwd_port(&recv->mad.smp),
+ qp_info->qp->qp_num);
goto out;
}
@@ -2998,7 +2999,6 @@ static int __init ib_mad_init_module(void)
sizeof(struct ib_mad_private),
0,
SLAB_HWCACHE_ALIGN,
- NULL,
NULL);
if (!ib_mad_cache) {
printk(KERN_ERR PFX "Couldn't create ib_mad cache\n");
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index 3663fd7022be..d43bc62005b3 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -163,8 +163,10 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,
hdr_len, 0, GFP_KERNEL);
if (IS_ERR(msg))
ib_destroy_ah(ah);
- else
+ else {
msg->ah = ah;
+ msg->context[0] = ah;
+ }
return msg;
}
@@ -197,9 +199,7 @@ static void ack_ds_ack(struct ib_mad_agent_private *agent,
void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)
{
- struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad;
-
- if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_ACK)
+ if (mad_send_wc->send_buf->context[0] == mad_send_wc->send_buf->ah)
ib_destroy_ah(mad_send_wc->send_buf->ah);
ib_free_send_mad(mad_send_wc->send_buf);
}
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 15b4c4d3606d..1bc1fe605282 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -196,7 +196,7 @@ static void queue_join(struct mcast_member *member)
unsigned long flags;
spin_lock_irqsave(&group->lock, flags);
- list_add(&member->list, &group->pending_list);
+ list_add_tail(&member->list, &group->pending_list);
if (group->state == MCAST_IDLE) {
group->state = MCAST_BUSY;
atomic_inc(&group->refcount);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 20ab6b3e484d..cf474ec27070 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -123,14 +123,10 @@ static u32 tid;
.field_name = "sa_path_rec:" #field
static const struct ib_field path_rec_table[] = {
- { RESERVED,
+ { PATH_REC_FIELD(service_id),
.offset_words = 0,
.offset_bits = 0,
- .size_bits = 32 },
- { RESERVED,
- .offset_words = 1,
- .offset_bits = 0,
- .size_bits = 32 },
+ .size_bits = 64 },
{ PATH_REC_FIELD(dgid),
.offset_words = 2,
.offset_bits = 0,
@@ -179,7 +175,7 @@ static const struct ib_field path_rec_table[] = {
.offset_words = 12,
.offset_bits = 16,
.size_bits = 16 },
- { RESERVED,
+ { PATH_REC_FIELD(qos_class),
.offset_words = 13,
.offset_bits = 0,
.size_bits = 12 },
@@ -385,9 +381,7 @@ static void update_sm_ah(struct work_struct *work)
new_ah->pkey_index = 0;
if (ib_find_pkey(port->agent->device, port->port_num,
- IB_DEFAULT_PKEY_FULL, &new_ah->pkey_index) &&
- ib_find_pkey(port->agent->device, port->port_num,
- IB_DEFAULT_PKEY_PARTIAL, &new_ah->pkey_index))
+ IB_DEFAULT_PKEY_FULL, &new_ah->pkey_index))
printk(KERN_ERR "Couldn't find index for default PKey\n");
memset(&ah_attr, 0, sizeof ah_attr);
@@ -533,7 +527,7 @@ static int alloc_mad(struct ib_sa_query *query, gfp_t gfp_mask)
query->sm_ah->pkey_index,
0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA,
gfp_mask);
- if (!query->mad_buf) {
+ if (IS_ERR(query->mad_buf)) {
kref_put(&query->sm_ah->ref, free_sm_ah);
return -ENOMEM;
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 70b77ae67422..3d4050681325 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev)
kfree(dev);
}
-static int ib_device_uevent(struct class_device *cdev, char **envp,
- int num_envp, char *buf, int size)
+static int ib_device_uevent(struct class_device *cdev,
+ struct kobj_uevent_env *env)
{
struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
- int i = 0, len = 0;
- if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
- "NAME=%s", dev->name))
+ if (add_uevent_var(env, "NAME=%s", dev->name))
return -ENOMEM;
/*
* It would be nice to pass the node GUID with the event...
*/
- envp[i] = NULL;
return 0;
}
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 53b4c94a7eb5..90d675ad9ec8 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -792,6 +792,78 @@ out:
return ret;
}
+static int ucma_set_option_id(struct ucma_context *ctx, int optname,
+ void *optval, size_t optlen)
+{
+ int ret = 0;
+
+ switch (optname) {
+ case RDMA_OPTION_ID_TOS:
+ if (optlen != sizeof(u8)) {
+ ret = -EINVAL;
+ break;
+ }
+ rdma_set_service_type(ctx->cm_id, *((u8 *) optval));
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static int ucma_set_option_level(struct ucma_context *ctx, int level,
+ int optname, void *optval, size_t optlen)
+{
+ int ret;
+
+ switch (level) {
+ case RDMA_OPTION_ID:
+ ret = ucma_set_option_id(ctx, optname, optval, optlen);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_set_option cmd;
+ struct ucma_context *ctx;
+ void *optval;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ optval = kmalloc(cmd.optlen, GFP_KERNEL);
+ if (!optval) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval,
+ cmd.optlen)) {
+ ret = -EFAULT;
+ goto out2;
+ }
+
+ ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval,
+ cmd.optlen);
+out2:
+ kfree(optval);
+out1:
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
int in_len, int out_len)
{
@@ -936,7 +1008,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
[RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
[RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event,
[RDMA_USER_CM_CMD_GET_OPTION] = NULL,
- [RDMA_USER_CM_CMD_SET_OPTION] = NULL,
+ [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option,
[RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
[RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
[RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 26d0470eef6e..2f54e29dc7a6 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -37,9 +37,15 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/sched.h>
+#include <linux/hugetlb.h>
#include "uverbs.h"
+#define IB_UMEM_MAX_PAGE_CHUNK \
+ ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \
+ ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \
+ (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
+
static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
{
struct ib_umem_chunk *chunk, *tmp;
@@ -70,6 +76,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
{
struct ib_umem *umem;
struct page **page_list;
+ struct vm_area_struct **vma_list;
struct ib_umem_chunk *chunk;
unsigned long locked;
unsigned long lock_limit;
@@ -99,6 +106,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
*/
umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ);
+ /* We assume the memory is from hugetlb until proved otherwise */
+ umem->hugetlb = 1;
+
INIT_LIST_HEAD(&umem->chunk_list);
page_list = (struct page **) __get_free_page(GFP_KERNEL);
@@ -107,6 +117,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
return ERR_PTR(-ENOMEM);
}
+ /*
+ * if we can't alloc the vma_list, it's not so bad;
+ * just assume the memory is not hugetlb memory
+ */
+ vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL);
+ if (!vma_list)
+ umem->hugetlb = 0;
+
npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT;
down_write(&current->mm->mmap_sem);
@@ -126,7 +144,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
ret = get_user_pages(current, current->mm, cur_base,
min_t(int, npages,
PAGE_SIZE / sizeof (struct page *)),
- 1, !umem->writable, page_list, NULL);
+ 1, !umem->writable, page_list, vma_list);
if (ret < 0)
goto out;
@@ -147,6 +165,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
for (i = 0; i < chunk->nents; ++i) {
+ if (vma_list &&
+ !is_vm_hugetlb_page(vma_list[i + off]))
+ umem->hugetlb = 0;
chunk->page_list[i].page = page_list[i + off];
chunk->page_list[i].offset = 0;
chunk->page_list[i].length = PAGE_SIZE;
@@ -181,6 +202,8 @@ out:
current->mm->locked_vm = locked;
up_write(&current->mm->mmap_sem);
+ if (vma_list)
+ free_page((unsigned long) vma_list);
free_page((unsigned long) page_list);
return ret < 0 ? ERR_PTR(ret) : umem;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index d97ded25c4ff..b53eac4611de 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -44,6 +44,7 @@
#include <linux/poll.h>
#include <linux/rwsem.h>
#include <linux/kref.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -118,6 +119,8 @@ struct ib_umad_file {
wait_queue_head_t recv_wait;
struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
int agents_dead;
+ u8 use_pkey_index;
+ u8 already_used;
};
struct ib_umad_packet {
@@ -147,6 +150,12 @@ static void ib_umad_release_dev(struct kref *ref)
kfree(dev);
}
+static int hdr_size(struct ib_umad_file *file)
+{
+ return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
+ sizeof (struct ib_user_mad_hdr_old);
+}
+
/* caller must hold port->mutex at least for reading */
static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
{
@@ -221,13 +230,13 @@ static void recv_handler(struct ib_mad_agent *agent,
packet->length = mad_recv_wc->mad_len;
packet->recv_wc = mad_recv_wc;
- packet->mad.hdr.status = 0;
- packet->mad.hdr.length = sizeof (struct ib_user_mad) +
- mad_recv_wc->mad_len;
- packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
- packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
- packet->mad.hdr.sl = mad_recv_wc->wc->sl;
- packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
+ packet->mad.hdr.status = 0;
+ packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len;
+ packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
+ packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
+ packet->mad.hdr.sl = mad_recv_wc->wc->sl;
+ packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
+ packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index;
packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
if (packet->mad.hdr.grh_present) {
struct ib_ah_attr ah_attr;
@@ -253,8 +262,8 @@ err1:
ib_free_recv_mad(mad_recv_wc);
}
-static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
- size_t count)
+static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
+ struct ib_umad_packet *packet, size_t count)
{
struct ib_mad_recv_buf *recv_buf;
int left, seg_payload, offset, max_seg_payload;
@@ -262,15 +271,15 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
/* We need enough room to copy the first (or only) MAD segment. */
recv_buf = &packet->recv_wc->recv_buf;
if ((packet->length <= sizeof (*recv_buf->mad) &&
- count < sizeof (packet->mad) + packet->length) ||
+ count < hdr_size(file) + packet->length) ||
(packet->length > sizeof (*recv_buf->mad) &&
- count < sizeof (packet->mad) + sizeof (*recv_buf->mad)))
+ count < hdr_size(file) + sizeof (*recv_buf->mad)))
return -EINVAL;
- if (copy_to_user(buf, &packet->mad, sizeof (packet->mad)))
+ if (copy_to_user(buf, &packet->mad, hdr_size(file)))
return -EFAULT;
- buf += sizeof (packet->mad);
+ buf += hdr_size(file);
seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
if (copy_to_user(buf, recv_buf->mad, seg_payload))
return -EFAULT;
@@ -280,7 +289,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
* Multipacket RMPP MAD message. Copy remainder of message.
* Note that last segment may have a shorter payload.
*/
- if (count < sizeof (packet->mad) + packet->length) {
+ if (count < hdr_size(file) + packet->length) {
/*
* The buffer is too small, return the first RMPP segment,
* which includes the RMPP message length.
@@ -300,18 +309,23 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
return -EFAULT;
}
}
- return sizeof (packet->mad) + packet->length;
+ return hdr_size(file) + packet->length;
}
-static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet,
- size_t count)
+static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
+ struct ib_umad_packet *packet, size_t count)
{
- ssize_t size = sizeof (packet->mad) + packet->length;
+ ssize_t size = hdr_size(file) + packet->length;
if (count < size)
return -EINVAL;
- if (copy_to_user(buf, &packet->mad, size))
+ if (copy_to_user(buf, &packet->mad, hdr_size(file)))
+ return -EFAULT;
+
+ buf += hdr_size(file);
+
+ if (copy_to_user(buf, packet->mad.data, packet->length))
return -EFAULT;
return size;
@@ -324,7 +338,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
struct ib_umad_packet *packet;
ssize_t ret;
- if (count < sizeof (struct ib_user_mad))
+ if (count < hdr_size(file))
return -EINVAL;
spin_lock_irq(&file->recv_lock);
@@ -348,9 +362,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
spin_unlock_irq(&file->recv_lock);
if (packet->recv_wc)
- ret = copy_recv_mad(buf, packet, count);
+ ret = copy_recv_mad(file, buf, packet, count);
else
- ret = copy_send_mad(buf, packet, count);
+ ret = copy_send_mad(file, buf, packet, count);
if (ret < 0) {
/* Requeue packet */
@@ -442,15 +456,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
__be64 *tid;
int ret, data_len, hdr_len, copy_offset, rmpp_active;
- if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
+ if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
return -EINVAL;
packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
if (!packet)
return -ENOMEM;
- if (copy_from_user(&packet->mad, buf,
- sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) {
+ if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
ret = -EFAULT;
goto err;
}
@@ -461,6 +474,13 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err;
}
+ buf += hdr_size(file);
+
+ if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
down_read(&file->port->mutex);
agent = __get_agent(file, packet->mad.hdr.id);
@@ -500,11 +520,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
IB_MGMT_RMPP_FLAG_ACTIVE;
}
- data_len = count - sizeof (struct ib_user_mad) - hdr_len;
+ data_len = count - hdr_size(file) - hdr_len;
packet->msg = ib_create_send_mad(agent,
be32_to_cpu(packet->mad.hdr.qpn),
- 0, rmpp_active, hdr_len,
- data_len, GFP_KERNEL);
+ packet->mad.hdr.pkey_index, rmpp_active,
+ hdr_len, data_len, GFP_KERNEL);
if (IS_ERR(packet->msg)) {
ret = PTR_ERR(packet->msg);
goto err_ah;
@@ -517,7 +537,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
/* Copy MAD header. Any RMPP header is already in place. */
memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
- buf += sizeof (struct ib_user_mad);
if (!rmpp_active) {
if (copy_from_user(packet->msg->mad + copy_offset,
@@ -589,7 +608,8 @@ static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wa
return mask;
}
-static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
+static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
+ int compat_method_mask)
{
struct ib_user_mad_reg_req ureq;
struct ib_mad_reg_req req;
@@ -604,7 +624,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
goto out;
}
- if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) {
+ if (copy_from_user(&ureq, arg, sizeof ureq)) {
ret = -EFAULT;
goto out;
}
@@ -625,8 +645,18 @@ found:
if (ureq.mgmt_class) {
req.mgmt_class = ureq.mgmt_class;
req.mgmt_class_version = ureq.mgmt_class_version;
- memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask);
- memcpy(req.oui, ureq.oui, sizeof req.oui);
+ memcpy(req.oui, ureq.oui, sizeof req.oui);
+
+ if (compat_method_mask) {
+ u32 *umm = (u32 *) ureq.method_mask;
+ int i;
+
+ for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i)
+ req.method_mask[i] =
+ umm[i * 2] | ((u64) umm[i * 2 + 1] << 32);
+ } else
+ memcpy(req.method_mask, ureq.method_mask,
+ sizeof req.method_mask);
}
agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
@@ -646,6 +676,16 @@ found:
goto out;
}
+ if (!file->already_used) {
+ file->already_used = 1;
+ if (!file->use_pkey_index) {
+ printk(KERN_WARNING "user_mad: process %s did not enable "
+ "P_Key index support.\n", current->comm);
+ printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt "
+ "has info on the new ABI.\n");
+ }
+ }
+
file->agent[agent_id] = agent;
ret = 0;
@@ -654,13 +694,13 @@ out:
return ret;
}
-static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg)
+static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
{
struct ib_mad_agent *agent = NULL;
u32 id;
int ret = 0;
- if (get_user(id, (u32 __user *) arg))
+ if (get_user(id, arg))
return -EFAULT;
down_write(&file->port->mutex);
@@ -682,18 +722,51 @@ out:
return ret;
}
+static long ib_umad_enable_pkey(struct ib_umad_file *file)
+{
+ int ret = 0;
+
+ down_write(&file->port->mutex);
+ if (file->already_used)
+ ret = -EINVAL;
+ else
+ file->use_pkey_index = 1;
+ up_write(&file->port->mutex);
+
+ return ret;
+}
+
static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case IB_USER_MAD_REGISTER_AGENT:
- return ib_umad_reg_agent(filp->private_data, arg);
+ return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
+ case IB_USER_MAD_UNREGISTER_AGENT:
+ return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
+ case IB_USER_MAD_ENABLE_PKEY:
+ return ib_umad_enable_pkey(filp->private_data);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case IB_USER_MAD_REGISTER_AGENT:
+ return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1);
case IB_USER_MAD_UNREGISTER_AGENT:
- return ib_umad_unreg_agent(filp->private_data, arg);
+ return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg));
+ case IB_USER_MAD_ENABLE_PKEY:
+ return ib_umad_enable_pkey(filp->private_data);
default:
return -ENOIOCTLCMD;
}
}
+#endif
static int ib_umad_open(struct inode *inode, struct file *filp)
{
@@ -782,7 +855,9 @@ static const struct file_operations umad_fops = {
.write = ib_umad_write,
.poll = ib_umad_poll,
.unlocked_ioctl = ib_umad_ioctl,
- .compat_ioctl = ib_umad_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ib_umad_compat_ioctl,
+#endif
.open = ib_umad_open,
.release = ib_umad_close
};
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index c33546f9e961..c75eb6c9bd49 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -148,7 +148,6 @@ void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd);
-void ib_uverbs_release_event_file(struct kref *ref);
struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 14d7ccd89195..7c2ac3905582 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -125,6 +125,14 @@ static void ib_uverbs_release_dev(struct kref *ref)
complete(&dev->comp);
}
+static void ib_uverbs_release_event_file(struct kref *ref)
+{
+ struct ib_uverbs_event_file *file =
+ container_of(ref, struct ib_uverbs_event_file, ref);
+
+ kfree(file);
+}
+
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
struct ib_uverbs_event_file *ev_file,
struct ib_ucq_object *uobj)
@@ -331,14 +339,6 @@ static unsigned int ib_uverbs_event_poll(struct file *filp,
return pollflags;
}
-void ib_uverbs_release_event_file(struct kref *ref)
-{
- struct ib_uverbs_event_file *file =
- container_of(ref, struct ib_uverbs_event_file, ref);
-
- kfree(file);
-}
-
static int ib_uverbs_event_fasync(int fd, struct file *filp, int on)
{
struct ib_uverbs_event_file *file = filp->private_data;
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 0aecea67f3e6..f283a9f0c23b 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -886,7 +886,6 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev,
return NULL;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
netdev->open = c2_up;
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 997cf1530762..7a6cece6ea9d 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -715,7 +715,6 @@ static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
static void setup(struct net_device *netdev)
{
- SET_MODULE_OWNER(netdev);
netdev->open = c2_pseudo_up;
netdev->stop = c2_pseudo_down;
netdev->hard_start_xmit = c2_pseudo_xmit_frame;
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
index 420c1380f5c3..01d07862ea86 100644
--- a/drivers/infiniband/hw/amso1100/c2_qp.c
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -506,6 +506,7 @@ int c2_alloc_qp(struct c2_dev *c2dev,
qp->send_sgl_depth = qp_attrs->cap.max_send_sge;
qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;
qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;
+ init_waitqueue_head(&qp->wait);
/* Initialize the SQ MQ */
q_size = be32_to_cpu(reply->sq_depth);
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c
index 36620a22413c..cfdacb1ec279 100644
--- a/drivers/infiniband/hw/amso1100/c2_vq.c
+++ b/drivers/infiniband/hw/amso1100/c2_vq.c
@@ -85,7 +85,7 @@ int vq_init(struct c2_dev *c2dev)
(char) ('0' + c2dev->devnum));
c2dev->host_msg_cache =
kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (c2dev->host_msg_cache == NULL) {
return -ENOMEM;
}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 1518b41482ae..eec6a30840ca 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -37,6 +37,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <net/net_namespace.h>
#include "cxio_resource.h"
#include "cxio_hal.h"
@@ -894,7 +895,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev_p)
if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) {
return -EBUSY;
}
- netdev_p = dev_get_by_name(rdev_p->dev_name);
+ netdev_p = dev_get_by_name(&init_net, rdev_p->dev_name);
if (!netdev_p) {
return -EINVAL;
}
@@ -916,7 +917,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev_p)
PDBG("%s opening rnic dev %s\n", __FUNCTION__, rdev_p->dev_name);
memset(&rdev_p->ctrl_qp, 0, sizeof(rdev_p->ctrl_qp));
if (!rdev_p->t3cdev_p)
- rdev_p->t3cdev_p = T3CDEV(netdev_p);
+ rdev_p->t3cdev_p = dev2t3cdev(netdev_p);
rdev_p->t3cdev_p->ulp = (void *) rdev_p;
err = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_GET_PARAMS,
&(rdev_p->rnic_info));
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 3b41dc0c39dd..20ba372dd182 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -63,37 +63,37 @@ static char *states[] = {
};
static int ep_timeout_secs = 10;
-module_param(ep_timeout_secs, int, 0444);
+module_param(ep_timeout_secs, int, 0644);
MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
"in seconds (default=10)");
static int mpa_rev = 1;
-module_param(mpa_rev, int, 0444);
+module_param(mpa_rev, int, 0644);
MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, "
"1 is spec compliant. (default=1)");
static int markers_enabled = 0;
-module_param(markers_enabled, int, 0444);
+module_param(markers_enabled, int, 0644);
MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)");
static int crc_enabled = 1;
-module_param(crc_enabled, int, 0444);
+module_param(crc_enabled, int, 0644);
MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)");
static int rcv_win = 256 * 1024;
-module_param(rcv_win, int, 0444);
+module_param(rcv_win, int, 0644);
MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)");
static int snd_win = 32 * 1024;
-module_param(snd_win, int, 0444);
+module_param(snd_win, int, 0644);
MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
static unsigned int nocong = 0;
-module_param(nocong, uint, 0444);
+module_param(nocong, uint, 0644);
MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)");
static unsigned int cong_flavor = 1;
-module_param(cong_flavor, uint, 0444);
+module_param(cong_flavor, uint, 0644);
MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)");
static void process_work(struct work_struct *work);
@@ -139,7 +139,7 @@ static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb)
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, hwtid));
skb->priority = CPL_PRIORITY_SETUP;
- tdev->send(tdev, skb);
+ cxgb3_ofld_send(tdev, skb);
return;
}
@@ -161,7 +161,7 @@ int iwch_quiesce_tid(struct iwch_ep *ep)
req->val = cpu_to_be64(1 << S_TCB_RX_QUIESCE);
skb->priority = CPL_PRIORITY_DATA;
- ep->com.tdev->send(ep->com.tdev, skb);
+ cxgb3_ofld_send(ep->com.tdev, skb);
return 0;
}
@@ -183,7 +183,7 @@ int iwch_resume_tid(struct iwch_ep *ep)
req->val = 0;
skb->priority = CPL_PRIORITY_DATA;
- ep->com.tdev->send(ep->com.tdev, skb);
+ cxgb3_ofld_send(ep->com.tdev, skb);
return 0;
}
@@ -229,9 +229,8 @@ static void *alloc_ep(int size, gfp_t gfp)
{
struct iwch_ep_common *epc;
- epc = kmalloc(size, gfp);
+ epc = kzalloc(size, gfp);
if (epc) {
- memset(epc, 0, size);
kref_init(&epc->kref);
spin_lock_init(&epc->lock);
init_waitqueue_head(&epc->waitq);
@@ -785,7 +784,7 @@ static int update_rx_credits(struct iwch_ep *ep, u32 credits)
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid));
req->credit_dack = htonl(V_RX_CREDITS(credits) | V_RX_FORCE_ACK(1));
skb->priority = CPL_PRIORITY_ACK;
- ep->com.tdev->send(ep->com.tdev, skb);
+ cxgb3_ofld_send(ep->com.tdev, skb);
return credits;
}
@@ -1153,7 +1152,7 @@ static int listen_start(struct iwch_listen_ep *ep)
req->opt1 = htonl(V_CONN_POLICY(CPL_CONN_POLICY_ASK));
skb->priority = 1;
- ep->com.tdev->send(ep->com.tdev, skb);
+ cxgb3_ofld_send(ep->com.tdev, skb);
return 0;
}
@@ -1187,7 +1186,7 @@ static int listen_stop(struct iwch_listen_ep *ep)
req->cpu_idx = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
skb->priority = 1;
- ep->com.tdev->send(ep->com.tdev, skb);
+ cxgb3_ofld_send(ep->com.tdev, skb);
return 0;
}
@@ -1265,7 +1264,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
rpl->opt0l_status = htonl(CPL_PASS_OPEN_REJECT);
rpl->opt2 = 0;
rpl->rsvd = rpl->opt2;
- tdev->send(tdev, skb);
+ cxgb3_ofld_send(tdev, skb);
}
}
@@ -1558,7 +1557,7 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
rpl->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid));
rpl->cmd = CPL_ABORT_NO_RST;
- ep->com.tdev->send(ep->com.tdev, rpl_skb);
+ cxgb3_ofld_send(ep->com.tdev, rpl_skb);
if (state != ABORTING) {
state_set(&ep->com, DEAD);
release_ep_resources(ep);
@@ -1914,6 +1913,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)
fail3:
cxgb3_free_stid(ep->com.tdev, ep->stid);
fail2:
+ cm_id->rem_ref(cm_id);
put_ep(&ep->com);
fail1:
out:
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
index 3cd6bf3402d1..97d108634c58 100644
--- a/drivers/infiniband/hw/ehca/ehca_av.c
+++ b/drivers/infiniband/hw/ehca/ehca_av.c
@@ -79,7 +79,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
av->av.ipd = (ah_mult > 0) ?
((ehca_mult - 1) / ah_mult) : 0;
} else
- av->av.ipd = ehca_static_rate;
+ av->av.ipd = ehca_static_rate;
av->av.lnh = ah_attr->ah_flags;
av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
@@ -259,7 +259,7 @@ int ehca_init_av_cache(void)
av_cache = kmem_cache_create("ehca_cache_av",
sizeof(struct ehca_av), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!av_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index daf823ea1ace..0f7a55d35ea7 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -43,7 +43,6 @@
#ifndef __EHCA_CLASSES_H__
#define __EHCA_CLASSES_H__
-
struct ehca_module;
struct ehca_qp;
struct ehca_cq;
@@ -54,6 +53,7 @@ struct ehca_pd;
struct ehca_av;
#include <linux/wait.h>
+#include <linux/mutex.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
@@ -100,6 +100,11 @@ struct ehca_sport {
struct ehca_sma_attr saved_attr;
};
+#define HCA_CAP_MR_PGSIZE_4K 0x80000000
+#define HCA_CAP_MR_PGSIZE_64K 0x40000000
+#define HCA_CAP_MR_PGSIZE_1M 0x20000000
+#define HCA_CAP_MR_PGSIZE_16M 0x10000000
+
struct ehca_shca {
struct ib_device ib_device;
struct ibmebus_dev *ibmebus_dev;
@@ -115,6 +120,8 @@ struct ehca_shca {
struct h_galpas galpas;
struct mutex modify_mutex;
u64 hca_cap;
+ /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
+ u32 hca_cap_mr_pgsize;
int max_mtu;
};
@@ -122,6 +129,10 @@ struct ehca_pd {
struct ib_pd ib_pd;
struct ipz_pd fw_pd;
u32 ownpid;
+ /* small queue mgmt */
+ struct mutex lock;
+ struct list_head free[2];
+ struct list_head full[2];
};
enum ehca_ext_qp_type {
@@ -204,11 +215,12 @@ struct ehca_mr {
spinlock_t mrlock;
enum ehca_mr_flag flags;
- u32 num_pages; /* number of MR pages */
- u32 num_4k; /* number of 4k "page" portions to form MR */
+ u32 num_kpages; /* number of kernel pages */
+ u32 num_hwpages; /* number of hw pages to form MR */
+ u64 hwpage_size; /* hw page size used for this MR */
int acl; /* ACL (stored here for usage in reregister) */
u64 *start; /* virtual start address (stored here for */
- /* usage in reregister) */
+ /* usage in reregister) */
u64 size; /* size (stored here for usage in reregister) */
u32 fmr_page_size; /* page size for FMR */
u32 fmr_max_pages; /* max pages for FMR */
@@ -217,9 +229,6 @@ struct ehca_mr {
/* fw specific data */
struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */
struct h_galpas galpas;
- /* data for userspace bridge */
- u32 nr_of_pages;
- void *pagearray;
};
struct ehca_mw {
@@ -241,26 +250,30 @@ enum ehca_mr_pgi_type {
struct ehca_mr_pginfo {
enum ehca_mr_pgi_type type;
- u64 num_pages;
- u64 page_cnt;
- u64 num_4k; /* number of 4k "page" portions */
- u64 page_4k_cnt; /* counter for 4k "page" portions */
- u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */
-
- /* type EHCA_MR_PGI_PHYS section */
- int num_phys_buf;
- struct ib_phys_buf *phys_buf_array;
- u64 next_buf;
-
- /* type EHCA_MR_PGI_USER section */
- struct ib_umem *region;
- struct ib_umem_chunk *next_chunk;
- u64 next_nmap;
-
- /* type EHCA_MR_PGI_FMR section */
- u64 *page_list;
- u64 next_listelem;
- /* next_4k also used within EHCA_MR_PGI_FMR */
+ u64 num_kpages;
+ u64 kpage_cnt;
+ u64 hwpage_size; /* hw page size used for this MR */
+ u64 num_hwpages; /* number of hw pages */
+ u64 hwpage_cnt; /* counter for hw pages */
+ u64 next_hwpage; /* next hw page in buffer/chunk/listelem */
+
+ union {
+ struct { /* type EHCA_MR_PGI_PHYS section */
+ int num_phys_buf;
+ struct ib_phys_buf *phys_buf_array;
+ u64 next_buf;
+ } phy;
+ struct { /* type EHCA_MR_PGI_USER section */
+ struct ib_umem *region;
+ struct ib_umem_chunk *next_chunk;
+ u64 next_nmap;
+ } usr;
+ struct { /* type EHCA_MR_PGI_FMR section */
+ u64 fmr_pgsize;
+ u64 *page_list;
+ u64 next_listelem;
+ } fmr;
+ } u;
};
/* output parameters for MR/FMR hipz calls */
@@ -298,6 +311,8 @@ int ehca_init_av_cache(void);
void ehca_cleanup_av_cache(void);
int ehca_init_mrmw_cache(void);
void ehca_cleanup_mrmw_cache(void);
+int ehca_init_small_qp_cache(void);
+void ehca_cleanup_small_qp_cache(void);
extern rwlock_t ehca_qp_idr_lock;
extern rwlock_t ehca_cq_idr_lock;
@@ -308,6 +323,7 @@ extern int ehca_static_rate;
extern int ehca_port_act_time;
extern int ehca_use_hp_mr;
extern int ehca_scaling_code;
+extern int ehca_mr_largepage;
struct ipzu_queue_resp {
u32 qe_size; /* queue entry size */
@@ -315,13 +331,15 @@ struct ipzu_queue_resp {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state;
- u32 dummy; /* padding for 8 byte alignment */
+ u32 offset; /* save offset within a page for small_qp */
};
struct ehca_create_cq_resp {
u32 cq_number;
u32 token;
struct ipzu_queue_resp ipz_queue;
+ u32 fw_handle_ofs;
+ u32 dummy;
};
struct ehca_create_qp_resp {
@@ -332,7 +350,8 @@ struct ehca_create_qp_resp {
u32 qkey;
/* qp_num assigned by ehca: sqp0/1 may have got different numbers */
u32 real_qp_num;
- u32 dummy; /* padding for 8 byte alignment */
+ u32 fw_handle_ofs;
+ u32 dummy;
struct ipzu_queue_resp ipz_squeue;
struct ipzu_queue_resp ipz_rqueue;
};
@@ -357,15 +376,29 @@ enum ehca_ll_comp_flags {
LLQP_COMP_MASK = 0x60,
};
+struct ehca_alloc_queue_parms {
+ /* input parameters */
+ int max_wr;
+ int max_sge;
+ int page_size;
+ int is_small;
+
+ /* output parameters */
+ u16 act_nr_wqes;
+ u8 act_nr_sges;
+ u32 queue_size; /* bytes for small queues, pages otherwise */
+};
+
struct ehca_alloc_qp_parms {
-/* input parameters */
+ struct ehca_alloc_queue_parms squeue;
+ struct ehca_alloc_queue_parms rqueue;
+
+ /* input parameters */
enum ehca_service_type servicetype;
+ int qp_storage;
int sigtype;
enum ehca_ext_qp_type ext_type;
enum ehca_ll_comp_flags ll_comp_flags;
-
- int max_send_wr, max_recv_wr;
- int max_send_sge, max_recv_sge;
int ud_av_l_key_ctl;
u32 token;
@@ -375,22 +408,14 @@ struct ehca_alloc_qp_parms {
u32 srq_qpn, srq_token, srq_limit;
-/* output parameters */
+ /* output parameters */
u32 real_qp_num;
struct ipz_qp_handle qp_handle;
struct h_galpas galpas;
-
- u16 act_nr_send_wqes;
- u16 act_nr_recv_wqes;
- u8 act_nr_recv_sges;
- u8 act_nr_send_sges;
-
- u32 nr_rq_pages;
- u32 nr_sq_pages;
};
int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
-struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
index fb3df5c271e7..1798e6466bd0 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
@@ -154,83 +154,83 @@ struct hcp_modify_qp_control_block {
u32 reserved_70_127[58]; /* 70 */
};
-#define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0)
-#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2)
-#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3)
-#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4)
-#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5)
-#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6)
-#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7)
-#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8)
-#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9)
-#define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11)
-#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12)
-#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13)
-#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14)
-#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15)
-#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16)
-#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17)
-#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18)
-#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19)
-#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20)
-#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21)
-#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22)
-#define MQPCB_DLID EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23)
-#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24)
-#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25)
-#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26)
-#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27)
-#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28)
-#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30)
-#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31)
-#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31)
-#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32)
-#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33)
-#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34)
-#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31)
-#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35)
-#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36)
-#define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37)
-#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38)
-#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39)
-#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40)
-#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41)
-#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42)
-#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44)
-#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45)
-#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46)
-#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47)
-#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31)
-#define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31)
-#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48)
-#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_CURR_SRQ_LIMIT EHCA_BMASK_IBM(49,49)
-#define MQPCB_CURR_SRQ_LIMIT EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50)
-#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51)
+#define MQPCB_MASK_QKEY EHCA_BMASK_IBM( 0, 0)
+#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM( 2, 2)
+#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM( 3, 3)
+#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM( 4, 4)
+#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM( 5, 5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM( 6, 6)
+#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM( 7, 7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM( 8, 8)
+#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM( 9, 9)
+#define MQPCB_QP_STATE EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11, 11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12, 12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13, 13)
+#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14, 14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15, 15)
+#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16, 16)
+#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17, 17)
+#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18, 18)
+#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19, 19)
+#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20, 20)
+#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21, 21)
+#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22, 22)
+#define MQPCB_DLID EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23, 23)
+#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24, 24)
+#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25, 25)
+#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26, 26)
+#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27, 27)
+#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28, 28)
+#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30, 30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31, 31)
+#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28, 31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32, 32)
+#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33, 33)
+#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34, 34)
+#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35, 35)
+#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36, 36)
+#define MQPCB_DLID_AL EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37, 37)
+#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38, 38)
+#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39, 39)
+#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40, 40)
+#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41, 41)
+#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42, 42)
+#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44, 44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45, 45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46, 46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47, 47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31, 31)
+#define MQPCB_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48, 48)
+#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_CURR_SRQ_LIMIT EHCA_BMASK_IBM(49, 49)
+#define MQPCB_CURR_SRQ_LIMIT EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50, 50)
+#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51, 51)
#endif /* __EHCA_CLASSES_PSERIES_H__ */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 01d4a148bd71..79c25f51c21e 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -97,7 +97,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
return ret;
}
-struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
{
struct ehca_qp *ret = NULL;
unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
@@ -166,7 +166,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
write_lock_irqsave(&ehca_cq_idr_lock, flags);
ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
-
} while (ret == -EAGAIN);
if (ret) {
@@ -176,6 +175,12 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
goto create_cq_exit1;
}
+ if (my_cq->token > 0x1FFFFFF) {
+ cq = ERR_PTR(-ENOMEM);
+ ehca_err(device, "Invalid number of cq. device=%p", device);
+ goto create_cq_exit2;
+ }
+
/*
* CQs maximum depth is 4GB-64, but we need additional 20 as buffer
* for receiving errors CQEs.
@@ -185,15 +190,15 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (h_ret != H_SUCCESS) {
ehca_err(device, "hipz_h_alloc_resource_cq() failed "
- "h_ret=%lx device=%p", h_ret, device);
+ "h_ret=%li device=%p", h_ret, device);
cq = ERR_PTR(ehca2ib_return_code(h_ret));
goto create_cq_exit2;
}
- ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
- EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
+ ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
if (!ipz_rc) {
- ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
+ ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%i device=%p",
ipz_rc, device);
cq = ERR_PTR(-EINVAL);
goto create_cq_exit3;
@@ -221,7 +226,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (h_ret < H_SUCCESS) {
ehca_err(device, "hipz_h_register_rpage_cq() failed "
- "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i "
+ "ehca_cq=%p cq_num=%x h_ret=%li counter=%i "
"act_pages=%i", my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
cq = ERR_PTR(-EINVAL);
@@ -233,7 +238,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if ((h_ret != H_SUCCESS) || vpage) {
ehca_err(device, "Registration of pages not "
"complete ehca_cq=%p cq_num=%x "
- "h_ret=%lx", my_cq, my_cq->cq_number,
+ "h_ret=%li", my_cq, my_cq->cq_number,
h_ret);
cq = ERR_PTR(-EAGAIN);
goto create_cq_exit4;
@@ -241,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
} else {
if (h_ret != H_PAGE_REGISTERED) {
ehca_err(device, "Registration of page failed "
- "ehca_cq=%p cq_num=%x h_ret=%lx"
+ "ehca_cq=%p cq_num=%x h_ret=%li"
"counter=%i act_pages=%i",
my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
@@ -276,6 +281,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
resp.ipz_queue.queue_length = ipz_queue->queue_length;
resp.ipz_queue.pagesize = ipz_queue->pagesize;
resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
+ resp.fw_handle_ofs = (u32)
+ (my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1));
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
ehca_err(device, "Copy to udata failed.");
goto create_cq_exit4;
@@ -285,13 +292,13 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
return cq;
create_cq_exit4:
- ipz_queue_dtor(&my_cq->ipz_queue);
+ ipz_queue_dtor(NULL, &my_cq->ipz_queue);
create_cq_exit3:
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
if (h_ret != H_SUCCESS)
ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
- "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret);
+ "cq_num=%x h_ret=%li", my_cq, my_cq->cq_number, h_ret);
create_cq_exit2:
write_lock_irqsave(&ehca_cq_idr_lock, flags);
@@ -355,11 +362,11 @@ int ehca_destroy_cq(struct ib_cq *cq)
cq_num);
}
if (h_ret != H_SUCCESS) {
- ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx "
+ ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%li "
"ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
return ehca2ib_return_code(h_ret);
}
- ipz_queue_dtor(&my_cq->ipz_queue);
+ ipz_queue_dtor(NULL, &my_cq->ipz_queue);
kmem_cache_free(cq_cache, my_cq);
return 0;
@@ -387,7 +394,7 @@ int ehca_init_cq_cache(void)
cq_cache = kmem_cache_create("ehca_cache_cq",
sizeof(struct ehca_cq), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!cq_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 4961eb88827c..1d41faa7a337 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -86,8 +86,8 @@ int ehca_create_eq(struct ehca_shca *shca,
return -EINVAL;
}
- ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
- EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
+ ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0);
if (!ret) {
ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
goto create_eq_exit1;
@@ -96,7 +96,8 @@ int ehca_create_eq(struct ehca_shca *shca,
for (i = 0; i < nr_pages; i++) {
u64 rpage;
- if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+ if (!vpage) {
ret = H_RESOURCE;
goto create_eq_exit2;
}
@@ -144,7 +145,7 @@ int ehca_create_eq(struct ehca_shca *shca,
return 0;
create_eq_exit2:
- ipz_queue_dtor(&eq->ipz_queue);
+ ipz_queue_dtor(NULL, &eq->ipz_queue);
create_eq_exit1:
hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
@@ -180,7 +181,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
ehca_err(&shca->ib_device, "Can't free EQ resources.");
return -EINVAL;
}
- ipz_queue_dtor(&eq->ipz_queue);
+ ipz_queue_dtor(NULL, &eq->ipz_queue);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index bbd3c6a5822f..4aa3ffa6a19f 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -82,33 +82,37 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
props->vendor_id = rblock->vendor_id >> 8;
props->vendor_part_id = rblock->vendor_part_id >> 16;
props->hw_ver = rblock->hw_ver;
- props->max_qp = min_t(int, rblock->max_qp, INT_MAX);
- props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX);
- props->max_sge = min_t(int, rblock->max_sge, INT_MAX);
- props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX);
- props->max_cq = min_t(int, rblock->max_cq, INT_MAX);
- props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX);
- props->max_mr = min_t(int, rblock->max_mr, INT_MAX);
- props->max_mw = min_t(int, rblock->max_mw, INT_MAX);
- props->max_pd = min_t(int, rblock->max_pd, INT_MAX);
- props->max_ah = min_t(int, rblock->max_ah, INT_MAX);
- props->max_fmr = min_t(int, rblock->max_mr, INT_MAX);
- props->max_srq = 0;
- props->max_srq_wr = 0;
- props->max_srq_sge = 0;
+ props->max_qp = min_t(unsigned, rblock->max_qp, INT_MAX);
+ props->max_qp_wr = min_t(unsigned, rblock->max_wqes_wq, INT_MAX);
+ props->max_sge = min_t(unsigned, rblock->max_sge, INT_MAX);
+ props->max_sge_rd = min_t(unsigned, rblock->max_sge_rd, INT_MAX);
+ props->max_cq = min_t(unsigned, rblock->max_cq, INT_MAX);
+ props->max_cqe = min_t(unsigned, rblock->max_cqe, INT_MAX);
+ props->max_mr = min_t(unsigned, rblock->max_mr, INT_MAX);
+ props->max_mw = min_t(unsigned, rblock->max_mw, INT_MAX);
+ props->max_pd = min_t(unsigned, rblock->max_pd, INT_MAX);
+ props->max_ah = min_t(unsigned, rblock->max_ah, INT_MAX);
+ props->max_fmr = min_t(unsigned, rblock->max_mr, INT_MAX);
+
+ if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
+ props->max_srq = props->max_qp;
+ props->max_srq_wr = props->max_qp_wr;
+ props->max_srq_sge = 3;
+ }
+
props->max_pkeys = 16;
props->local_ca_ack_delay
= rblock->local_ca_ack_delay;
props->max_raw_ipv6_qp
- = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
+ = min_t(unsigned, rblock->max_raw_ipv6_qp, INT_MAX);
props->max_raw_ethy_qp
- = min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
+ = min_t(unsigned, rblock->max_raw_ethy_qp, INT_MAX);
props->max_mcast_grp
- = min_t(int, rblock->max_mcast_grp, INT_MAX);
+ = min_t(unsigned, rblock->max_mcast_grp, INT_MAX);
props->max_mcast_qp_attach
- = min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
+ = min_t(unsigned, rblock->max_mcast_qp_attach, INT_MAX);
props->max_total_mcast_qp_attach
- = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+ = min_t(unsigned, rblock->max_total_mcast_qp_attach, INT_MAX);
/* translate device capabilities */
props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID |
@@ -127,6 +131,7 @@ int ehca_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
int ret = 0;
+ u64 h_ret;
struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
ib_device);
struct hipz_query_port *rblock;
@@ -137,7 +142,8 @@ int ehca_query_port(struct ib_device *ibdev,
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_port1;
@@ -197,6 +203,7 @@ int ehca_query_sma_attr(struct ehca_shca *shca,
u8 port, struct ehca_sma_attr *attr)
{
int ret = 0;
+ u64 h_ret;
struct hipz_query_port *rblock;
rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
@@ -205,7 +212,8 @@ int ehca_query_sma_attr(struct ehca_shca *shca,
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_sma_attr1;
@@ -230,9 +238,11 @@ query_sma_attr1:
int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
{
int ret = 0;
- struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+ u64 h_ret;
+ struct ehca_shca *shca;
struct hipz_query_port *rblock;
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
if (index > 16) {
ehca_err(&shca->ib_device, "Invalid index: %x.", index);
return -EINVAL;
@@ -244,7 +254,8 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_pkey1;
@@ -262,6 +273,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
int index, union ib_gid *gid)
{
int ret = 0;
+ u64 h_ret;
struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
ib_device);
struct hipz_query_port *rblock;
@@ -277,7 +289,8 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_gid1;
@@ -302,11 +315,12 @@ int ehca_modify_port(struct ib_device *ibdev,
struct ib_port_modify *props)
{
int ret = 0;
- struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+ struct ehca_shca *shca;
struct hipz_query_port *rblock;
u32 cap;
u64 hret;
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
if ((props->set_port_cap_mask | props->clr_port_cap_mask)
& ~allowed_port_caps) {
ehca_err(&shca->ib_device, "Non-changeable bits set in masks "
@@ -325,7 +339,8 @@ int ehca_modify_port(struct ib_device *ibdev,
goto modify_port1;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (hret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto modify_port2;
@@ -337,7 +352,8 @@ int ehca_modify_port(struct ib_device *ibdev,
hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
cap, props->init_type, port_modify_mask);
if (hret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "Modify port failed hret=%lx", hret);
+ ehca_err(&shca->ib_device, "Modify port failed h_ret=%li",
+ hret);
ret = -EINVAL;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 96eba3830754..3f617b27b954 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -49,29 +49,26 @@
#include "hipz_fns.h"
#include "ipz_pt_fn.h"
-#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
-#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31)
-#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7)
-#define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31)
-#define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31)
-#define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63)
-#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63)
-
-#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
-#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
-#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
-#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
-#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16,16)
-
-#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
+#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1)
+#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM( 2, 7)
+#define EQE_CQ_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_TOKEN EHCA_BMASK_IBM(32, 63)
+#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32, 63)
+
+#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1)
+#define NEQE_EVENT_CODE EHCA_BMASK_IBM( 2, 7)
+#define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
+#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16)
+
+#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7)
static void queue_comp_task(struct ehca_cq *__cq);
-static struct ehca_comp_pool* pool;
-#ifdef CONFIG_HOTPLUG_CPU
-static struct notifier_block comp_pool_callback_nb;
-#endif
+static struct ehca_comp_pool *pool;
static inline void comp_event_callback(struct ehca_cq *cq)
{
@@ -85,8 +82,8 @@ static inline void comp_event_callback(struct ehca_cq *cq)
return;
}
-static void print_error_data(struct ehca_shca * shca, void* data,
- u64* rblock, int length)
+static void print_error_data(struct ehca_shca *shca, void *data,
+ u64 *rblock, int length)
{
u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
u64 resource = rblock[1];
@@ -94,7 +91,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
switch (type) {
case 0x1: /* Queue Pair */
{
- struct ehca_qp *qp = (struct ehca_qp*)data;
+ struct ehca_qp *qp = (struct ehca_qp *)data;
/* only print error data if AER is set */
if (rblock[6] == 0)
@@ -107,7 +104,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
}
case 0x4: /* Completion Queue */
{
- struct ehca_cq *cq = (struct ehca_cq*)data;
+ struct ehca_cq *cq = (struct ehca_cq *)data;
ehca_err(&shca->ib_device,
"CQ 0x%x (resource=%lx) has errors.",
@@ -116,7 +113,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
}
default:
ehca_err(&shca->ib_device,
- "Unknown errror type: %lx on %s.",
+ "Unknown error type: %lx on %s.",
type, shca->ib_device.name);
break;
}
@@ -175,11 +172,32 @@ error_data1:
}
-static void qp_event_callback(struct ehca_shca *shca,
- u64 eqe,
+static void dispatch_qp_event(struct ehca_shca *shca, struct ehca_qp *qp,
enum ib_event_type event_type)
{
struct ib_event event;
+
+ event.device = &shca->ib_device;
+ event.event = event_type;
+
+ if (qp->ext_type == EQPT_SRQ) {
+ if (!qp->ib_srq.event_handler)
+ return;
+
+ event.element.srq = &qp->ib_srq;
+ qp->ib_srq.event_handler(&event, qp->ib_srq.srq_context);
+ } else {
+ if (!qp->ib_qp.event_handler)
+ return;
+
+ event.element.qp = &qp->ib_qp;
+ qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+ }
+}
+
+static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
+ enum ib_event_type event_type, int fatal)
+{
struct ehca_qp *qp;
u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
@@ -187,20 +205,22 @@ static void qp_event_callback(struct ehca_shca *shca,
qp = idr_find(&ehca_qp_idr, token);
read_unlock(&ehca_qp_idr_lock);
-
if (!qp)
return;
- ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
+ if (fatal)
+ ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
- if (!qp->ib_qp.event_handler)
- return;
+ dispatch_qp_event(shca, qp, fatal && qp->ext_type == EQPT_SRQ ?
+ IB_EVENT_SRQ_ERR : event_type);
- event.device = &shca->ib_device;
- event.event = event_type;
- event.element.qp = &qp->ib_qp;
-
- qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+ /*
+ * eHCA only processes one WQE at a time for SRQ base QPs,
+ * so the last WQE has been processed as soon as the QP enters
+ * error state.
+ */
+ if (fatal && qp->ext_type == EQPT_SRQBASE)
+ dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
return;
}
@@ -234,17 +254,17 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
switch (identifier) {
case 0x02: /* path migrated */
- qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG);
+ qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG, 0);
break;
case 0x03: /* communication established */
- qp_event_callback(shca, eqe, IB_EVENT_COMM_EST);
+ qp_event_callback(shca, eqe, IB_EVENT_COMM_EST, 0);
break;
case 0x04: /* send queue drained */
- qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED);
+ qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED, 0);
break;
case 0x05: /* QP error */
case 0x06: /* QP error */
- qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL);
+ qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL, 1);
break;
case 0x07: /* CQ error */
case 0x08: /* CQ error */
@@ -271,13 +291,18 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
case 0x11: /* unaffiliated access error */
ehca_err(&shca->ib_device, "Unaffiliated access error.");
break;
- case 0x12: /* path migrating error */
- ehca_err(&shca->ib_device, "Path migration error.");
+ case 0x12: /* path migrating */
+ ehca_err(&shca->ib_device, "Path migrating.");
break;
case 0x13: /* interface trace stopped */
ehca_err(&shca->ib_device, "Interface trace stopped.");
break;
case 0x14: /* first error capture info available */
+ ehca_info(&shca->ib_device, "First error capture available");
+ break;
+ case 0x15: /* SRQ limit reached */
+ qp_event_callback(shca, eqe, IB_EVENT_SRQ_LIMIT_REACHED, 0);
+ break;
default:
ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
identifier, shca->ib_device.name);
@@ -572,7 +597,7 @@ void ehca_tasklet_eq(unsigned long data)
ehca_process_eq((struct ehca_shca*)data, 1);
}
-static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
+static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
{
int cpu;
unsigned long flags;
@@ -636,7 +661,7 @@ static void queue_comp_task(struct ehca_cq *__cq)
__queue_comp_task(__cq, cct);
}
-static void run_comp_task(struct ehca_cpu_comp_task* cct)
+static void run_comp_task(struct ehca_cpu_comp_task *cct)
{
struct ehca_cq *cq;
unsigned long flags;
@@ -666,12 +691,12 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct)
static int comp_task(void *__cct)
{
- struct ehca_cpu_comp_task* cct = __cct;
+ struct ehca_cpu_comp_task *cct = __cct;
int cql_empty;
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_INTERRUPTIBLE);
- while(!kthread_should_stop()) {
+ while (!kthread_should_stop()) {
add_wait_queue(&cct->wait_queue, &wait);
spin_lock_irq(&cct->task_lock);
@@ -732,9 +757,7 @@ static void destroy_comp_task(struct ehca_comp_pool *pool,
kthread_stop(task);
}
-#ifdef CONFIG_HOTPLUG_CPU
-static void take_over_work(struct ehca_comp_pool *pool,
- int cpu)
+static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
{
struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
LIST_HEAD(list);
@@ -745,7 +768,7 @@ static void take_over_work(struct ehca_comp_pool *pool,
list_splice_init(&cct->cq_list, &list);
- while(!list_empty(&list)) {
+ while (!list_empty(&list)) {
cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
list_del(&cq->entry);
@@ -757,9 +780,9 @@ static void take_over_work(struct ehca_comp_pool *pool,
}
-static int comp_pool_callback(struct notifier_block *nfb,
- unsigned long action,
- void *hcpu)
+static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
struct ehca_cpu_comp_task *cct;
@@ -768,7 +791,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
- if(!create_comp_task(pool, cpu)) {
+ if (!create_comp_task(pool, cpu)) {
ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
return NOTIFY_BAD;
}
@@ -805,7 +828,11 @@ static int comp_pool_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-#endif
+
+static struct notifier_block comp_pool_callback_nb __cpuinitdata = {
+ .notifier_call = comp_pool_callback,
+ .priority = 0,
+};
int ehca_create_comp_pool(void)
{
@@ -836,11 +863,7 @@ int ehca_create_comp_pool(void)
}
}
-#ifdef CONFIG_HOTPLUG_CPU
- comp_pool_callback_nb.notifier_call = comp_pool_callback;
- comp_pool_callback_nb.priority =0;
- register_cpu_notifier(&comp_pool_callback_nb);
-#endif
+ register_hotcpu_notifier(&comp_pool_callback_nb);
printk(KERN_INFO "eHCA scaling code enabled\n");
@@ -854,9 +877,7 @@ void ehca_destroy_comp_pool(void)
if (!ehca_scaling_code)
return;
-#ifdef CONFIG_HOTPLUG_CPU
- unregister_cpu_notifier(&comp_pool_callback_nb);
-#endif
+ unregister_hotcpu_notifier(&comp_pool_callback_nb);
for (i = 0; i < NR_CPUS; i++) {
if (cpu_online(i))
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 77aeca6a2c2f..dce503bb7d6b 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -81,8 +81,9 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
int num_phys_buf,
int mr_access_flags, u64 *iova_start);
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
- int mr_access_flags, struct ib_udata *udata);
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt, int mr_access_flags,
+ struct ib_udata *udata);
int ehca_rereg_phys_mr(struct ib_mr *mr,
int mr_rereg_mask,
@@ -192,7 +193,7 @@ void ehca_poll_eqs(unsigned long data);
void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr);
#else
-#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags))
+#define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags))
#define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 28ba2dd24216..403467f66fe6 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -49,10 +49,12 @@
#include "ehca_tools.h"
#include "hcp_if.h"
+#define HCAD_VERSION "0024"
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0023");
+MODULE_VERSION(HCAD_VERSION);
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -63,16 +65,18 @@ int ehca_port_act_time = 30;
int ehca_poll_all_eqs = 1;
int ehca_static_rate = -1;
int ehca_scaling_code = 0;
-
-module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
-module_param_named(debug_level, ehca_debug_level, int, 0);
-module_param_named(hw_level, ehca_hw_level, int, 0);
-module_param_named(nr_ports, ehca_nr_ports, int, 0);
-module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
-module_param_named(port_act_time, ehca_port_act_time, int, 0);
-module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
-module_param_named(static_rate, ehca_static_rate, int, 0);
-module_param_named(scaling_code, ehca_scaling_code, int, 0);
+int ehca_mr_largepage = 0;
+
+module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO);
+module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);
+module_param_named(hw_level, ehca_hw_level, int, S_IRUGO);
+module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO);
+module_param_named(use_hp_mr, ehca_use_hp_mr, int, S_IRUGO);
+module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO);
+module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO);
+module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);
+module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO);
+module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO);
MODULE_PARM_DESC(open_aqp1,
"AQP1 on startup (0: no (default), 1: yes)");
@@ -95,6 +99,9 @@ MODULE_PARM_DESC(static_rate,
"set permanent static rate (default: disabled)");
MODULE_PARM_DESC(scaling_code,
"set scaling code (0: disabled/default, 1: enabled)");
+MODULE_PARM_DESC(mr_largepage,
+ "use large page for MR (0: use PAGE_SIZE (default), "
+ "1: use large page depending on MR size");
DEFINE_RWLOCK(ehca_qp_idr_lock);
DEFINE_RWLOCK(ehca_cq_idr_lock);
@@ -107,7 +114,7 @@ static DEFINE_SPINLOCK(shca_list_lock);
static struct timer_list poll_eqs_timer;
#ifdef CONFIG_PPC_64K_PAGES
-static struct kmem_cache *ctblk_cache = NULL;
+static struct kmem_cache *ctblk_cache;
void *ehca_alloc_fw_ctrlblock(gfp_t flags)
{
@@ -125,6 +132,23 @@ void ehca_free_fw_ctrlblock(void *ptr)
}
#endif
+int ehca2ib_return_code(u64 ehca_rc)
+{
+ switch (ehca_rc) {
+ case H_SUCCESS:
+ return 0;
+ case H_RESOURCE: /* Resource in use */
+ case H_BUSY:
+ return -EBUSY;
+ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+ case H_CONSTRAINED: /* resource constraint */
+ case H_NO_MEM:
+ return -ENOMEM;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ehca_create_slab_caches(void)
{
int ret;
@@ -159,19 +183,28 @@ static int ehca_create_slab_caches(void)
goto create_slab_caches5;
}
+ ret = ehca_init_small_qp_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create small queue SLAB cache.");
+ goto create_slab_caches6;
+ }
+
#ifdef CONFIG_PPC_64K_PAGES
ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
EHCA_PAGESIZE, H_CB_ALIGNMENT,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!ctblk_cache) {
ehca_gen_err("Cannot create ctblk SLAB cache.");
- ehca_cleanup_mrmw_cache();
- goto create_slab_caches5;
+ ehca_cleanup_small_qp_cache();
+ goto create_slab_caches6;
}
#endif
return 0;
+create_slab_caches6:
+ ehca_cleanup_mrmw_cache();
+
create_slab_caches5:
ehca_cleanup_av_cache();
@@ -189,6 +222,7 @@ create_slab_caches2:
static void ehca_destroy_slab_caches(void)
{
+ ehca_cleanup_small_qp_cache();
ehca_cleanup_mrmw_cache();
ehca_cleanup_av_cache();
ehca_cleanup_qp_cache();
@@ -200,8 +234,8 @@ static void ehca_destroy_slab_caches(void)
#endif
}
-#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
-#define EHCA_REVID EHCA_BMASK_IBM(40,63)
+#define EHCA_HCAAVER EHCA_BMASK_IBM(32, 39)
+#define EHCA_REVID EHCA_BMASK_IBM(40, 63)
static struct cap_descr {
u64 mask;
@@ -241,7 +275,7 @@ int ehca_sense_attributes(struct ehca_shca *shca)
h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
if (h_ret != H_SUCCESS) {
- ehca_gen_err("Cannot query device properties. h_ret=%lx",
+ ehca_gen_err("Cannot query device properties. h_ret=%li",
h_ret);
ret = -EPERM;
goto sense_attributes1;
@@ -263,22 +297,27 @@ int ehca_sense_attributes(struct ehca_shca *shca)
ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
- if ((hcaaver == 1) && (revid == 0))
- shca->hw_level = 0x11;
- else if ((hcaaver == 1) && (revid == 1))
- shca->hw_level = 0x12;
- else if ((hcaaver == 1) && (revid == 2))
- shca->hw_level = 0x13;
- else if ((hcaaver == 2) && (revid == 0))
- shca->hw_level = 0x21;
- else if ((hcaaver == 2) && (revid == 0x10))
- shca->hw_level = 0x22;
- else {
+ if (hcaaver == 1) {
+ if (revid <= 3)
+ shca->hw_level = 0x10 | (revid + 1);
+ else
+ shca->hw_level = 0x14;
+ } else if (hcaaver == 2) {
+ if (revid == 0)
+ shca->hw_level = 0x21;
+ else if (revid == 0x10)
+ shca->hw_level = 0x22;
+ else if (revid == 0x20 || revid == 0x21)
+ shca->hw_level = 0x23;
+ }
+
+ if (!shca->hw_level) {
ehca_gen_warn("unknown hardware version"
" - assuming default level");
shca->hw_level = 0x22;
}
- }
+ } else
+ shca->hw_level = ehca_hw_level;
ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
shca->sport[0].rate = IB_RATE_30_GBPS;
@@ -290,10 +329,12 @@ int ehca_sense_attributes(struct ehca_shca *shca)
if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
ehca_gen_dbg(" %s", hca_cap_descr[i].descr);
- port = (struct hipz_query_port *) rblock;
+ shca->hca_cap_mr_pgsize = rblock->memory_page_size_supported;
+
+ port = (struct hipz_query_port *)rblock;
h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
if (h_ret != H_SUCCESS) {
- ehca_gen_err("Cannot query port properties. h_ret=%lx",
+ ehca_gen_err("Cannot query port properties. h_ret=%li",
h_ret);
ret = -EPERM;
goto sense_attributes1;
@@ -341,7 +382,7 @@ int ehca_init_device(struct ehca_shca *shca)
strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
shca->ib_device.owner = THIS_MODULE;
- shca->ib_device.uverbs_abi_ver = 7;
+ shca->ib_device.uverbs_abi_ver = 8;
shca->ib_device.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -439,7 +480,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
return -EPERM;
}
- ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
+ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0);
if (IS_ERR(ibcq)) {
ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
return PTR_ERR(ibcq);
@@ -487,13 +528,13 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
ret = ib_destroy_qp(sport->ibqp_aqp1);
if (ret) {
- ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret);
+ ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
return ret;
}
ret = ib_destroy_cq(sport->ibcq_aqp1);
if (ret)
- ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret);
+ ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret);
return ret;
}
@@ -585,6 +626,14 @@ static ssize_t ehca_show_adapter_handle(struct device *dev,
}
static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
+static ssize_t ehca_show_mr_largepage(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", ehca_mr_largepage);
+}
+static DEVICE_ATTR(mr_largepage, S_IRUGO, ehca_show_mr_largepage, NULL);
+
static struct attribute *ehca_dev_attrs[] = {
&dev_attr_adapter_handle.attr,
&dev_attr_num_ports.attr,
@@ -601,6 +650,7 @@ static struct attribute *ehca_dev_attrs[] = {
&dev_attr_cur_mw.attr,
&dev_attr_max_pd.attr,
&dev_attr_max_ah.attr,
+ &dev_attr_mr_largepage.attr,
NULL
};
@@ -666,7 +716,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
}
/* create internal protection domain */
- ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+ ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);
if (IS_ERR(ibpd)) {
ehca_err(&shca->ib_device, "Cannot create internal PD.");
ret = PTR_ERR(ibpd);
@@ -680,7 +730,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
if (ret) {
- ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x",
+ ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i",
ret);
goto probe5;
}
@@ -688,7 +738,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
ret = ib_register_device(&shca->ib_device);
if (ret) {
ehca_err(&shca->ib_device,
- "ib_register_device() failed ret=%x", ret);
+ "ib_register_device() failed ret=%i", ret);
goto probe6;
}
@@ -729,7 +779,7 @@ probe8:
ret = ehca_destroy_aqp1(&shca->sport[0]);
if (ret)
ehca_err(&shca->ib_device,
- "Cannot destroy AQP1 for port 1. ret=%x", ret);
+ "Cannot destroy AQP1 for port 1. ret=%i", ret);
probe7:
ib_unregister_device(&shca->ib_device);
@@ -778,7 +828,7 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev)
if (ret)
ehca_err(&shca->ib_device,
"Cannot destroy AQP1 for port %x "
- "ret=%x", ret, i);
+ "ret=%i", ret, i);
}
}
@@ -787,20 +837,20 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev)
ret = ehca_dereg_internal_maxmr(shca);
if (ret)
ehca_err(&shca->ib_device,
- "Cannot destroy internal MR. ret=%x", ret);
+ "Cannot destroy internal MR. ret=%i", ret);
ret = ehca_dealloc_pd(&shca->pd->ib_pd);
if (ret)
ehca_err(&shca->ib_device,
- "Cannot destroy internal PD. ret=%x", ret);
+ "Cannot destroy internal PD. ret=%i", ret);
ret = ehca_destroy_eq(shca, &shca->eq);
if (ret)
- ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret);
+ ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret);
ret = ehca_destroy_eq(shca, &shca->neq);
if (ret)
- ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret);
+ ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret);
ib_dealloc_device(&shca->ib_device);
@@ -861,20 +911,23 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0023)\n");
+ "(Version " HCAD_VERSION ")\n");
- if ((ret = ehca_create_comp_pool())) {
+ ret = ehca_create_comp_pool();
+ if (ret) {
ehca_gen_err("Cannot create comp pool.");
return ret;
}
- if ((ret = ehca_create_slab_caches())) {
+ ret = ehca_create_slab_caches();
+ if (ret) {
ehca_gen_err("Cannot create SLAB caches");
ret = -ENOMEM;
goto module_init1;
}
- if ((ret = ibmebus_register_driver(&ehca_driver))) {
+ ret = ibmebus_register_driver(&ehca_driver);
+ if (ret) {
ehca_gen_err("Cannot register eHCA device driver");
ret = -EINVAL;
goto module_init2;
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
index 32a870660bfe..e3ef0264ccc6 100644
--- a/drivers/infiniband/hw/ehca/ehca_mcast.c
+++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
@@ -88,7 +88,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (h_ret != H_SUCCESS)
ehca_err(ibqp->device,
"ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
- "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+ "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
@@ -125,7 +125,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (h_ret != H_SUCCESS)
ehca_err(ibqp->device,
"ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
- "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+ "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index add79bd44e39..da88738265ed 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -5,6 +5,7 @@
*
* Authors: Dietmar Decker <ddecker@de.ibm.com>
* Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
*
* Copyright (c) 2005 IBM Corporation
*
@@ -39,26 +40,66 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <rdma/ib_umem.h>
-
#include <asm/current.h>
+#include <rdma/ib_umem.h>
+
#include "ehca_iverbs.h"
#include "ehca_mrmw.h"
#include "hcp_if.h"
#include "hipz_hw.h"
+#define NUM_CHUNKS(length, chunk_size) \
+ (((length) + (chunk_size - 1)) / (chunk_size))
+
+/* max number of rpages (per hcall register_rpages) */
+#define MAX_RPAGES 512
+
static struct kmem_cache *mr_cache;
static struct kmem_cache *mw_cache;
+enum ehca_mr_pgsize {
+ EHCA_MR_PGSIZE4K = 0x1000L,
+ EHCA_MR_PGSIZE64K = 0x10000L,
+ EHCA_MR_PGSIZE1M = 0x100000L,
+ EHCA_MR_PGSIZE16M = 0x1000000L
+};
+
+#define EHCA_MR_PGSHIFT4K 12
+#define EHCA_MR_PGSHIFT64K 16
+#define EHCA_MR_PGSHIFT1M 20
+#define EHCA_MR_PGSHIFT16M 24
+
+static u32 ehca_encode_hwpage_size(u32 pgsize)
+{
+ u32 idx = 0;
+ pgsize >>= 12;
+ /*
+ * map mr page size into hw code:
+ * 0, 1, 2, 3 for 4K, 64K, 1M, 64M
+ */
+ while (!(pgsize & 1)) {
+ idx++;
+ pgsize >>= 4;
+ }
+ return idx;
+}
+
+static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca)
+{
+ if (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)
+ return EHCA_MR_PGSIZE16M;
+ return EHCA_MR_PGSIZE4K;
+}
+
static struct ehca_mr *ehca_mr_new(void)
{
struct ehca_mr *me;
me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
- if (me) {
+ if (me)
spin_lock_init(&me->mrlock);
- } else
+ else
ehca_gen_err("alloc failed");
return me;
@@ -74,9 +115,9 @@ static struct ehca_mw *ehca_mw_new(void)
struct ehca_mw *me;
me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
- if (me) {
+ if (me)
spin_lock_init(&me->mwlock);
- } else
+ else
ehca_gen_err("alloc failed");
return me;
@@ -106,11 +147,12 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
goto get_dma_mr_exit0;
}
- ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
+ ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
mr_access_flags, e_pd,
&e_maxmr->ib.ib_mr.lkey,
&e_maxmr->ib.ib_mr.rkey);
if (ret) {
+ ehca_mr_delete(e_maxmr);
ib_mr = ERR_PTR(ret);
goto get_dma_mr_exit0;
}
@@ -123,7 +165,7 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
get_dma_mr_exit0:
if (IS_ERR(ib_mr))
- ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ",
+ ehca_err(&shca->ib_device, "h_ret=%li pd=%p mr_access_flags=%x",
PTR_ERR(ib_mr), pd, mr_access_flags);
return ib_mr;
} /* end ehca_get_dma_mr() */
@@ -144,9 +186,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
u64 size;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
- u32 num_pages_mr;
- u32 num_pages_4k; /* 4k portion "pages" */
if ((num_phys_buf <= 0) || !phys_buf_array) {
ehca_err(pd->device, "bad input values: num_phys_buf=%x "
@@ -190,12 +229,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
goto reg_phys_mr_exit0;
}
- /* determine number of MR pages */
- num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
- PAGE_SIZE - 1) / PAGE_SIZE);
- num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
/* register MR on HCA */
if (ehca_mr_is_maxmr(size, iova_start)) {
e_mr->flags |= EHCA_MR_FLAG_MAXMR;
@@ -207,13 +240,26 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
goto reg_phys_mr_exit1;
}
} else {
- pginfo.type = EHCA_MR_PGI_PHYS;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.num_phys_buf = num_phys_buf;
- pginfo.phys_buf_array = phys_buf_array;
- pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
- EHCA_PAGESIZE);
+ struct ehca_mr_pginfo pginfo;
+ u32 num_kpages;
+ u32 num_hwpages;
+ u64 hw_pgsize;
+
+ num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size,
+ PAGE_SIZE);
+ /* for kernel space we try most possible pgsize */
+ hw_pgsize = ehca_get_max_hwpage_size(shca);
+ num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size,
+ hw_pgsize);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_kpages = num_kpages;
+ pginfo.hwpage_size = hw_pgsize;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.u.phy.num_phys_buf = num_phys_buf;
+ pginfo.u.phy.phys_buf_array = phys_buf_array;
+ pginfo.next_hwpage =
+ ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -231,7 +277,7 @@ reg_phys_mr_exit1:
ehca_mr_delete(e_mr);
reg_phys_mr_exit0:
if (IS_ERR(ib_mr))
- ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p "
+ ehca_err(pd->device, "h_ret=%li pd=%p phys_buf_array=%p "
"num_phys_buf=%x mr_access_flags=%x iova_start=%p",
PTR_ERR(ib_mr), pd, phys_buf_array,
num_phys_buf, mr_access_flags, iova_start);
@@ -240,18 +286,20 @@ reg_phys_mr_exit0:
/*----------------------------------------------------------------------*/
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
- int mr_access_flags, struct ib_udata *udata)
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt, int mr_access_flags,
+ struct ib_udata *udata)
{
struct ib_mr *ib_mr;
struct ehca_mr *e_mr;
struct ehca_shca *shca =
container_of(pd->device, struct ehca_shca, ib_device);
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
int ret;
- u32 num_pages_mr;
- u32 num_pages_4k; /* 4k portion "pages" */
+ u32 num_kpages;
+ u32 num_hwpages;
+ u64 hwpage_size;
if (!pd) {
ehca_gen_err("bad pd=%p", pd);
@@ -289,7 +337,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
mr_access_flags);
if (IS_ERR(e_mr->umem)) {
- ib_mr = (void *) e_mr->umem;
+ ib_mr = (void *)e_mr->umem;
goto reg_user_mr_exit1;
}
@@ -301,23 +349,51 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
}
/* determine number of MR pages */
- num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
- PAGE_SIZE);
- num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
- EHCA_PAGESIZE);
+ num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
+ /* select proper hw_pgsize */
+ if (ehca_mr_largepage &&
+ (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) {
+ int page_shift = PAGE_SHIFT;
+ if (e_mr->umem->hugetlb) {
+ /* determine page_shift, clamp between 4K and 16M */
+ page_shift = (fls64(length - 1) + 3) & ~3;
+ page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K),
+ EHCA_MR_PGSHIFT16M);
+ }
+ hwpage_size = 1UL << page_shift;
+ } else
+ hwpage_size = EHCA_MR_PGSIZE4K; /* ehca1 only supports 4k */
+ ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size);
+reg_user_mr_fallback:
+ num_hwpages = NUM_CHUNKS((virt % hwpage_size) + length, hwpage_size);
/* register MR on HCA */
- pginfo.type = EHCA_MR_PGI_USER;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.region = e_mr->umem;
- pginfo.next_4k = e_mr->umem->offset / EHCA_PAGESIZE;
- pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
- (&e_mr->umem->chunk_list),
- list);
-
- ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
- &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_USER;
+ pginfo.hwpage_size = hwpage_size;
+ pginfo.num_kpages = num_kpages;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.u.usr.region = e_mr->umem;
+ pginfo.next_hwpage = e_mr->umem->offset / hwpage_size;
+ pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk,
+ (&e_mr->umem->chunk_list),
+ list);
+
+ ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
+ e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
+ ehca_warn(pd->device, "failed to register mr "
+ "with hwpage_size=%lx", hwpage_size);
+ ehca_info(pd->device, "try to register mr with "
+ "kpage_size=%lx", PAGE_SIZE);
+ /*
+ * this means kpages are not contiguous for a hw page
+ * try kernel page size as fallback solution
+ */
+ hwpage_size = PAGE_SIZE;
+ goto reg_user_mr_fallback;
+ }
if (ret) {
ib_mr = ERR_PTR(ret);
goto reg_user_mr_exit2;
@@ -332,8 +408,7 @@ reg_user_mr_exit1:
ehca_mr_delete(e_mr);
reg_user_mr_exit0:
if (IS_ERR(ib_mr))
- ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x"
- " udata=%p",
+ ehca_err(pd->device, "rc=%li pd=%p mr_access_flags=%x udata=%p",
PTR_ERR(ib_mr), pd, mr_access_flags, udata);
return ib_mr;
} /* end ehca_reg_user_mr() */
@@ -360,9 +435,9 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
struct ehca_pd *new_pd;
u32 tmp_lkey, tmp_rkey;
unsigned long sl_flags;
- u32 num_pages_mr = 0;
- u32 num_pages_4k = 0; /* 4k portion "pages" */
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 num_kpages = 0;
+ u32 num_hwpages = 0;
+ struct ehca_mr_pginfo pginfo;
u32 cur_pid = current->tgid;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
@@ -414,7 +489,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
goto rereg_phys_mr_exit0;
}
if (!phys_buf_array || num_phys_buf <= 0) {
- ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
+ ehca_err(mr->device, "bad input values mr_rereg_mask=%x"
" phys_buf_array=%p num_phys_buf=%x",
mr_rereg_mask, phys_buf_array, num_phys_buf);
ret = -EINVAL;
@@ -438,12 +513,14 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
/* set requested values dependent on rereg request */
spin_lock_irqsave(&e_mr->mrlock, sl_flags);
- new_start = e_mr->start; /* new == old address */
- new_size = e_mr->size; /* new == old length */
- new_acl = e_mr->acl; /* new == old access control */
- new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+ new_start = e_mr->start;
+ new_size = e_mr->size;
+ new_acl = e_mr->acl;
+ new_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
if (mr_rereg_mask & IB_MR_REREG_TRANS) {
+ u64 hw_pgsize = ehca_get_max_hwpage_size(shca);
+
new_start = iova_start; /* change address */
/* check physical buffer list and calculate size */
ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array,
@@ -458,17 +535,19 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
ret = -EINVAL;
goto rereg_phys_mr_exit1;
}
- num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
- PAGE_SIZE - 1) / PAGE_SIZE);
- num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
- pginfo.type = EHCA_MR_PGI_PHYS;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.num_phys_buf = num_phys_buf;
- pginfo.phys_buf_array = phys_buf_array;
- pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
- EHCA_PAGESIZE);
+ num_kpages = NUM_CHUNKS(((u64)new_start % PAGE_SIZE) +
+ new_size, PAGE_SIZE);
+ num_hwpages = NUM_CHUNKS(((u64)new_start % hw_pgsize) +
+ new_size, hw_pgsize);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_kpages = num_kpages;
+ pginfo.hwpage_size = hw_pgsize;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.u.phy.num_phys_buf = num_phys_buf;
+ pginfo.u.phy.phys_buf_array = phys_buf_array;
+ pginfo.next_hwpage =
+ ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
}
if (mr_rereg_mask & IB_MR_REREG_ACCESS)
new_acl = mr_access_flags;
@@ -490,7 +569,7 @@ rereg_phys_mr_exit1:
spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
rereg_phys_mr_exit0:
if (ret)
- ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p "
+ ehca_err(mr->device, "ret=%i mr=%p mr_rereg_mask=%x pd=%p "
"phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x "
"iova_start=%p",
ret, mr, mr_rereg_mask, pd, phys_buf_array,
@@ -510,7 +589,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
u32 cur_pid = current->tgid;
unsigned long sl_flags;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
(my_pd->ownpid != cur_pid)) {
@@ -532,25 +611,25 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p "
+ ehca_err(mr->device, "hipz_mr_query failed, h_ret=%li mr=%p "
"hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
- ret = ehca_mrmw_map_hrc_query_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto query_mr_exit1;
}
- mr_attr->pd = mr->pd;
+ mr_attr->pd = mr->pd;
mr_attr->device_virt_addr = hipzout.vaddr;
- mr_attr->size = hipzout.len;
- mr_attr->lkey = hipzout.lkey;
- mr_attr->rkey = hipzout.rkey;
+ mr_attr->size = hipzout.len;
+ mr_attr->lkey = hipzout.lkey;
+ mr_attr->rkey = hipzout.rkey;
ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
query_mr_exit1:
spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
query_mr_exit0:
if (ret)
- ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p",
+ ehca_err(mr->device, "ret=%i mr=%p mr_attr=%p",
ret, mr, mr_attr);
return ret;
} /* end ehca_query_mr() */
@@ -592,11 +671,11 @@ int ehca_dereg_mr(struct ib_mr *mr)
/* TODO: BUSY: MR still has bound window(s) */
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
- ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p "
+ ehca_err(mr->device, "hipz_free_mr failed, h_ret=%li shca=%p "
"e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto dereg_mr_exit0;
}
@@ -608,7 +687,7 @@ int ehca_dereg_mr(struct ib_mr *mr)
dereg_mr_exit0:
if (ret)
- ehca_err(mr->device, "ret=%x mr=%p", ret, mr);
+ ehca_err(mr->device, "ret=%i mr=%p", ret, mr);
return ret;
} /* end ehca_dereg_mr() */
@@ -622,7 +701,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
struct ehca_shca *shca =
container_of(pd->device, struct ehca_shca, ib_device);
- struct ehca_mw_hipzout_parms hipzout = {{0},0};
+ struct ehca_mw_hipzout_parms hipzout;
e_mw = ehca_mw_new();
if (!e_mw) {
@@ -633,10 +712,10 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
e_pd->fw_pd, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
+ ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%li "
"shca=%p hca_hndl=%lx mw=%p",
h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
- ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
+ ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
goto alloc_mw_exit1;
}
/* successful MW allocation */
@@ -648,7 +727,7 @@ alloc_mw_exit1:
ehca_mw_delete(e_mw);
alloc_mw_exit0:
if (IS_ERR(ib_mw))
- ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd);
+ ehca_err(pd->device, "h_ret=%li pd=%p", PTR_ERR(ib_mw), pd);
return ib_mw;
} /* end ehca_alloc_mw() */
@@ -675,11 +754,11 @@ int ehca_dealloc_mw(struct ib_mw *mw)
h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
if (h_ret != H_SUCCESS) {
- ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p "
+ ehca_err(mw->device, "hipz_free_mw failed, h_ret=%li shca=%p "
"mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
e_mw->ipz_mw_handle.handle);
- return ehca_mrmw_map_hrc_free_mw(h_ret);
+ return ehca2ib_return_code(h_ret);
}
/* successful deallocation */
ehca_mw_delete(e_mw);
@@ -699,7 +778,8 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
struct ehca_mr *e_fmr;
int ret;
u32 tmp_lkey, tmp_rkey;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
+ u64 hw_pgsize;
/* check other parameters */
if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
@@ -729,8 +809,8 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
ib_fmr = ERR_PTR(-EINVAL);
goto alloc_fmr_exit0;
}
- if (((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) &&
- ((1 << fmr_attr->page_shift) != PAGE_SIZE)) {
+ hw_pgsize = ehca_get_max_hwpage_size(shca);
+ if ((1 << fmr_attr->page_shift) != hw_pgsize) {
ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
fmr_attr->page_shift);
ib_fmr = ERR_PTR(-EINVAL);
@@ -745,6 +825,11 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
e_fmr->flags |= EHCA_MR_FLAG_FMR;
/* register MR on HCA */
+ memset(&pginfo, 0, sizeof(pginfo));
+ /*
+ * pginfo.num_hwpages==0, ie register_rpages() will not be called
+ * but deferred to map_phys_fmr()
+ */
ret = ehca_reg_mr(shca, e_fmr, NULL,
fmr_attr->max_pages * (1 << fmr_attr->page_shift),
mr_access_flags, e_pd, &pginfo,
@@ -755,6 +840,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
}
/* successful */
+ e_fmr->hwpage_size = hw_pgsize;
e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
e_fmr->fmr_max_pages = fmr_attr->max_pages;
e_fmr->fmr_max_maps = fmr_attr->max_maps;
@@ -764,10 +850,6 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
alloc_fmr_exit1:
ehca_mr_delete(e_fmr);
alloc_fmr_exit0:
- if (IS_ERR(ib_fmr))
- ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x "
- "fmr_attr=%p", PTR_ERR(ib_fmr), pd,
- mr_access_flags, fmr_attr);
return ib_fmr;
} /* end ehca_alloc_fmr() */
@@ -783,7 +865,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
container_of(fmr->device, struct ehca_shca, ib_device);
struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
u32 tmp_lkey, tmp_rkey;
if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
@@ -809,14 +891,18 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
}
- pginfo.type = EHCA_MR_PGI_FMR;
- pginfo.num_pages = list_len;
- pginfo.num_4k = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
- pginfo.page_list = page_list;
- pginfo.next_4k = ((iova & (e_fmr->fmr_page_size-1)) /
- EHCA_PAGESIZE);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_FMR;
+ pginfo.num_kpages = list_len;
+ pginfo.hwpage_size = e_fmr->hwpage_size;
+ pginfo.num_hwpages =
+ list_len * e_fmr->fmr_page_size / pginfo.hwpage_size;
+ pginfo.u.fmr.page_list = page_list;
+ pginfo.next_hwpage =
+ (iova & (e_fmr->fmr_page_size-1)) / pginfo.hwpage_size;
+ pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size;
- ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
+ ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
list_len * e_fmr->fmr_page_size,
e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
if (ret)
@@ -830,9 +916,8 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
map_phys_fmr_exit0:
if (ret)
- ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
- "iova=%lx",
- ret, fmr, page_list, list_len, iova);
+ ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x "
+ "iova=%lx", ret, fmr, page_list, list_len, iova);
return ret;
} /* end ehca_map_phys_fmr() */
@@ -894,7 +979,7 @@ int ehca_unmap_fmr(struct list_head *fmr_list)
unmap_fmr_exit0:
if (ret)
- ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
+ ehca_gen_err("ret=%i fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
ret, fmr_list, num_fmr, unmap_fmr_cnt);
return ret;
} /* end ehca_unmap_fmr() */
@@ -918,11 +1003,11 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
if (h_ret != H_SUCCESS) {
- ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p "
+ ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%li e_fmr=%p "
"hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle, fmr->lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto free_fmr_exit0;
}
/* successful deregistration */
@@ -931,7 +1016,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
free_fmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr);
+ ehca_err(&shca->ib_device, "ret=%i fmr=%p", ret, fmr);
return ret;
} /* end ehca_dealloc_fmr() */
@@ -950,20 +1035,20 @@ int ehca_reg_mr(struct ehca_shca *shca,
int ret;
u64 h_ret;
u32 hipz_acl;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
if (ehca_use_hp_mr == 1)
- hipz_acl |= 0x00000001;
+ hipz_acl |= 0x00000001;
h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
(u64)iova_start, size, hipz_acl,
e_pd->fw_pd, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
+ ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%li "
"hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
- ret = ehca_mrmw_map_hrc_alloc(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto ehca_reg_mr_exit0;
}
@@ -974,11 +1059,12 @@ int ehca_reg_mr(struct ehca_shca *shca,
goto ehca_reg_mr_exit1;
/* successful registration */
- e_mr->num_pages = pginfo->num_pages;
- e_mr->num_4k = pginfo->num_4k;
- e_mr->start = iova_start;
- e_mr->size = size;
- e_mr->acl = acl;
+ e_mr->num_kpages = pginfo->num_kpages;
+ e_mr->num_hwpages = pginfo->num_hwpages;
+ e_mr->hwpage_size = pginfo->hwpage_size;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
return 0;
@@ -986,22 +1072,22 @@ int ehca_reg_mr(struct ehca_shca *shca,
ehca_reg_mr_exit1:
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
+ ehca_err(&shca->ib_device, "h_ret=%li shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
- "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
+ "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%i",
h_ret, shca, e_mr, iova_start, size, acl, e_pd,
- hipzout.lkey, pginfo, pginfo->num_pages,
- pginfo->num_4k, ret);
+ hipzout.lkey, pginfo, pginfo->num_kpages,
+ pginfo->num_hwpages, ret);
ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
"not recoverable");
}
ehca_reg_mr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
- "num_pages=%lx num_4k=%lx",
+ "num_kpages=%lx num_hwpages=%lx",
ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
- pginfo->num_pages, pginfo->num_4k);
+ pginfo->num_kpages, pginfo->num_hwpages);
return ret;
} /* end ehca_reg_mr() */
@@ -1018,6 +1104,9 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
u32 i;
u64 *kpage;
+ if (!pginfo->num_hwpages) /* in case of fmr */
+ return 0;
+
kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!kpage) {
ehca_err(&shca->ib_device, "kpage alloc failed");
@@ -1025,25 +1114,25 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
goto ehca_reg_mr_rpages_exit0;
}
- /* max 512 pages per shot */
- for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+ /* max MAX_RPAGES ehca mr pages per register call */
+ for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) {
- if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
- rnum = pginfo->num_4k % 512; /* last shot */
+ if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
+ rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */
if (rnum == 0)
- rnum = 512; /* last shot is full */
+ rnum = MAX_RPAGES; /* last shot is full */
} else
- rnum = 512;
+ rnum = MAX_RPAGES;
+
+ ret = ehca_set_pagebuf(pginfo, rnum, kpage);
+ if (ret) {
+ ehca_err(&shca->ib_device, "ehca_set_pagebuf "
+ "bad rc, ret=%i rnum=%x kpage=%p",
+ ret, rnum, kpage);
+ goto ehca_reg_mr_rpages_exit1;
+ }
if (rnum > 1) {
- ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
- if (ret) {
- ehca_err(&shca->ib_device, "ehca_set_pagebuf "
- "bad rc, ret=%x rnum=%x kpage=%p",
- ret, rnum, kpage);
- ret = -EFAULT;
- goto ehca_reg_mr_rpages_exit1;
- }
rpage = virt_to_abs(kpage);
if (!rpage) {
ehca_err(&shca->ib_device, "kpage=%p i=%x",
@@ -1051,45 +1140,39 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
ret = -EFAULT;
goto ehca_reg_mr_rpages_exit1;
}
- } else { /* rnum==1 */
- ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
- if (ret) {
- ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
- "bad rc, ret=%x i=%x", ret, i);
- ret = -EFAULT;
- goto ehca_reg_mr_rpages_exit1;
- }
- }
+ } else
+ rpage = *kpage;
- h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
- 0, /* pagesize 4k */
- 0, rpage, rnum);
+ h_ret = hipz_h_register_rpage_mr(
+ shca->ipz_hca_handle, e_mr,
+ ehca_encode_hwpage_size(pginfo->hwpage_size),
+ 0, rpage, rnum);
- if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+ if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
/*
* check for 'registration complete'==H_SUCCESS
* and for 'page registered'==H_PAGE_REGISTERED
*/
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "last "
- "hipz_reg_rpage_mr failed, h_ret=%lx "
+ "hipz_reg_rpage_mr failed, h_ret=%li "
"e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx"
" lkey=%x", h_ret, e_mr, i,
shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
e_mr->ib.ib_mr.lkey);
- ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
+ ret = ehca2ib_return_code(h_ret);
break;
} else
ret = 0;
} else if (h_ret != H_PAGE_REGISTERED) {
ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
- "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx "
+ "h_ret=%li e_mr=%p i=%x lkey=%x hca_hndl=%lx "
"mr_hndl=%lx", h_ret, e_mr, i,
e_mr->ib.ib_mr.lkey,
shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle);
- ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
+ ret = ehca2ib_return_code(h_ret);
break;
} else
ret = 0;
@@ -1100,9 +1183,9 @@ ehca_reg_mr_rpages_exit1:
ehca_free_fw_ctrlblock(kpage);
ehca_reg_mr_rpages_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
- "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
- pginfo->num_pages, pginfo->num_4k);
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p "
+ "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
+ pginfo, pginfo->num_kpages, pginfo->num_hwpages);
return ret;
} /* end ehca_reg_mr_rpages() */
@@ -1124,10 +1207,10 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
u64 *kpage;
u64 rpage;
struct ehca_mr_pginfo pginfo_save;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!kpage) {
@@ -1137,12 +1220,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
}
pginfo_save = *pginfo;
- ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+ ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
if (ret) {
ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
- "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
- e_mr, pginfo, pginfo->type, pginfo->num_pages,
- pginfo->num_4k,kpage);
+ "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx "
+ "kpage=%p", e_mr, pginfo, pginfo->type,
+ pginfo->num_kpages, pginfo->num_hwpages, kpage);
goto ehca_rereg_mr_rereg1_exit1;
}
rpage = virt_to_abs(kpage);
@@ -1161,10 +1244,10 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
* (MW bound or MR is shared)
*/
ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
- "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
+ "(Rereg1), h_ret=%li e_mr=%p", h_ret, e_mr);
*pginfo = pginfo_save;
ret = -EAGAIN;
- } else if ((u64*)hipzout.vaddr != iova_start) {
+ } else if ((u64 *)hipzout.vaddr != iova_start) {
ehca_err(&shca->ib_device, "PHYP changed iova_start in "
"rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
"mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
@@ -1176,11 +1259,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
* successful reregistration
* note: start and start_out are identical for eServer HCAs
*/
- e_mr->num_pages = pginfo->num_pages;
- e_mr->num_4k = pginfo->num_4k;
- e_mr->start = iova_start;
- e_mr->size = size;
- e_mr->acl = acl;
+ e_mr->num_kpages = pginfo->num_kpages;
+ e_mr->num_hwpages = pginfo->num_hwpages;
+ e_mr->hwpage_size = pginfo->hwpage_size;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
}
@@ -1189,10 +1273,10 @@ ehca_rereg_mr_rereg1_exit1:
ehca_free_fw_ctrlblock(kpage);
ehca_rereg_mr_rereg1_exit0:
if ( ret && (ret != -EAGAIN) )
- ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
- "pginfo=%p num_pages=%lx num_4k=%lx",
- ret, *lkey, *rkey, pginfo, pginfo->num_pages,
- pginfo->num_4k);
+ ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x "
+ "pginfo=%p num_kpages=%lx num_hwpages=%lx",
+ ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
+ pginfo->num_hwpages);
return ret;
} /* end ehca_rereg_mr_rereg1() */
@@ -1214,10 +1298,12 @@ int ehca_rereg_mr(struct ehca_shca *shca,
int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
/* first determine reregistration hCall(s) */
- if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
- (pginfo->num_4k > e_mr->num_4k)) {
- ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
- "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+ if ((pginfo->num_hwpages > MAX_RPAGES) ||
+ (e_mr->num_hwpages > MAX_RPAGES) ||
+ (pginfo->num_hwpages > e_mr->num_hwpages)) {
+ ehca_dbg(&shca->ib_device, "Rereg3 case, "
+ "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x",
+ pginfo->num_hwpages, e_mr->num_hwpages);
rereg_1_hcall = 0;
rereg_3_hcall = 1;
}
@@ -1248,12 +1334,12 @@ int ehca_rereg_mr(struct ehca_shca *shca,
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx "
+ "h_ret=%li e_mr=%p hca_hndl=%lx mr_hndl=%lx "
"mr->lkey=%x",
h_ret, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
e_mr->ib.ib_mr.lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto ehca_rereg_mr_exit0;
}
/* clean ehca_mr_t, without changing struct ib_mr and lock */
@@ -1262,13 +1348,14 @@ int ehca_rereg_mr(struct ehca_shca *shca,
/* set some MR values */
e_mr->flags = save_mr.flags;
+ e_mr->hwpage_size = save_mr.hwpage_size;
e_mr->fmr_page_size = save_mr.fmr_page_size;
e_mr->fmr_max_pages = save_mr.fmr_max_pages;
e_mr->fmr_max_maps = save_mr.fmr_max_maps;
e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
- e_pd, pginfo, lkey, rkey);
+ e_pd, pginfo, lkey, rkey);
if (ret) {
u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
memcpy(&e_mr->flags, &(save_mr.flags),
@@ -1279,11 +1366,11 @@ int ehca_rereg_mr(struct ehca_shca *shca,
ehca_rereg_mr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
- "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+ "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
"rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
- acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
+ acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
rereg_1_hcall, rereg_3_hcall);
return ret;
} /* end ehca_rereg_mr() */
@@ -1295,97 +1382,84 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
{
int ret = 0;
u64 h_ret;
- int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
- int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
struct ehca_pd *e_pd =
container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
struct ehca_mr save_fmr;
u32 tmp_lkey, tmp_rkey;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
-
- /* first check if reregistration hCall can be used for unmap */
- if (e_fmr->fmr_max_pages > 512) {
- rereg_1_hcall = 0;
- rereg_3_hcall = 1;
- }
+ struct ehca_mr_pginfo pginfo;
+ struct ehca_mr_hipzout_parms hipzout;
+ struct ehca_mr save_mr;
- if (rereg_1_hcall) {
+ if (e_fmr->fmr_max_pages <= MAX_RPAGES) {
/*
* note: after using rereg hcall with len=0,
* rereg hcall must be used again for registering pages
*/
h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
0, 0, e_pd->fw_pd, 0, &hipzout);
- if (h_ret != H_SUCCESS) {
- /*
- * should not happen, because length checked above,
- * FMRs are not shared and no MW bound to FMRs
- */
- ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
- "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
- "mr_hndl=%lx lkey=%x lkey_out=%x",
- h_ret, e_fmr, shca->ipz_hca_handle.handle,
- e_fmr->ipz_mr_handle.handle,
- e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
- rereg_3_hcall = 1;
- } else {
+ if (h_ret == H_SUCCESS) {
/* successful reregistration */
e_fmr->start = NULL;
e_fmr->size = 0;
tmp_lkey = hipzout.lkey;
tmp_rkey = hipzout.rkey;
+ return 0;
}
+ /*
+ * should not happen, because length checked above,
+ * FMRs are not shared and no MW bound to FMRs
+ */
+ ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
+ "(Rereg1), h_ret=%li e_fmr=%p hca_hndl=%lx "
+ "mr_hndl=%lx lkey=%x lkey_out=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
+ /* try free and rereg */
}
- if (rereg_3_hcall) {
- struct ehca_mr save_mr;
-
- /* first free old FMR */
- h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
- if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
- "lkey=%x",
- h_ret, e_fmr, shca->ipz_hca_handle.handle,
- e_fmr->ipz_mr_handle.handle,
- e_fmr->ib.ib_fmr.lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
- goto ehca_unmap_one_fmr_exit0;
- }
- /* clean ehca_mr_t, without changing lock */
- save_fmr = *e_fmr;
- ehca_mr_deletenew(e_fmr);
-
- /* set some MR values */
- e_fmr->flags = save_fmr.flags;
- e_fmr->fmr_page_size = save_fmr.fmr_page_size;
- e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
- e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
- e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
- e_fmr->acl = save_fmr.acl;
-
- pginfo.type = EHCA_MR_PGI_FMR;
- pginfo.num_pages = 0;
- pginfo.num_4k = 0;
- ret = ehca_reg_mr(shca, e_fmr, NULL,
- (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
- e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
- &tmp_rkey);
- if (ret) {
- u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
- memcpy(&e_fmr->flags, &(save_mr.flags),
- sizeof(struct ehca_mr) - offset);
- goto ehca_unmap_one_fmr_exit0;
- }
+ /* first free old FMR */
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+ "h_ret=%li e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+ "lkey=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey);
+ ret = ehca2ib_return_code(h_ret);
+ goto ehca_unmap_one_fmr_exit0;
+ }
+ /* clean ehca_mr_t, without changing lock */
+ save_fmr = *e_fmr;
+ ehca_mr_deletenew(e_fmr);
+
+ /* set some MR values */
+ e_fmr->flags = save_fmr.flags;
+ e_fmr->hwpage_size = save_fmr.hwpage_size;
+ e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+ e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+ e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+ e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+ e_fmr->acl = save_fmr.acl;
+
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_FMR;
+ ret = ehca_reg_mr(shca, e_fmr, NULL,
+ (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
+ e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+ &tmp_rkey);
+ if (ret) {
+ u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+ memcpy(&e_fmr->flags, &(save_mr.flags),
+ sizeof(struct ehca_mr) - offset);
}
ehca_unmap_one_fmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
- "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
- ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
- rereg_1_hcall, rereg_3_hcall);
+ ehca_err(&shca->ib_device, "ret=%i tmp_lkey=%x tmp_rkey=%x "
+ "fmr_max_pages=%x",
+ ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
return ret;
} /* end ehca_unmap_one_fmr() */
@@ -1403,31 +1477,32 @@ int ehca_reg_smr(struct ehca_shca *shca,
int ret = 0;
u64 h_ret;
u32 hipz_acl;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
&hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
"shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
"e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
e_origmr->ib.ib_mr.lkey);
- ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto ehca_reg_smr_exit0;
}
/* successful registration */
- e_newmr->num_pages = e_origmr->num_pages;
- e_newmr->num_4k = e_origmr->num_4k;
- e_newmr->start = iova_start;
- e_newmr->size = e_origmr->size;
- e_newmr->acl = acl;
+ e_newmr->num_kpages = e_origmr->num_kpages;
+ e_newmr->num_hwpages = e_origmr->num_hwpages;
+ e_newmr->hwpage_size = e_origmr->hwpage_size;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
e_newmr->ipz_mr_handle = hipzout.handle;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
@@ -1435,7 +1510,7 @@ int ehca_reg_smr(struct ehca_shca *shca,
ehca_reg_smr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_origmr=%p "
"e_newmr=%p iova_start=%p acl=%x e_pd=%p",
ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd);
return ret;
@@ -1453,10 +1528,11 @@ int ehca_reg_internal_maxmr(
struct ehca_mr *e_mr;
u64 *iova_start;
u64 size_maxmr;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
struct ib_phys_buf ib_pbuf;
- u32 num_pages_mr;
- u32 num_pages_4k; /* 4k portion "pages" */
+ u32 num_kpages;
+ u32 num_hwpages;
+ u64 hw_pgsize;
e_mr = ehca_mr_new();
if (!e_mr) {
@@ -1468,28 +1544,31 @@ int ehca_reg_internal_maxmr(
/* register internal max-MR on HCA */
size_maxmr = (u64)high_memory - PAGE_OFFSET;
- iova_start = (u64*)KERNELBASE;
+ iova_start = (u64 *)KERNELBASE;
ib_pbuf.addr = 0;
ib_pbuf.size = size_maxmr;
- num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
- PAGE_SIZE - 1) / PAGE_SIZE);
- num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
- pginfo.type = EHCA_MR_PGI_PHYS;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.num_phys_buf = 1;
- pginfo.phys_buf_array = &ib_pbuf;
+ num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
+ PAGE_SIZE);
+ hw_pgsize = ehca_get_max_hwpage_size(shca);
+ num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size_maxmr,
+ hw_pgsize);
+
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_kpages = num_kpages;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.hwpage_size = hw_pgsize;
+ pginfo.u.phy.num_phys_buf = 1;
+ pginfo.u.phy.phys_buf_array = &ib_pbuf;
ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
&pginfo, &e_mr->ib.ib_mr.lkey,
&e_mr->ib.ib_mr.rkey);
if (ret) {
ehca_err(&shca->ib_device, "reg of internal max MR failed, "
- "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
- "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
- num_pages_mr, num_pages_4k);
+ "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x "
+ "num_hwpages=%x", e_mr, iova_start, size_maxmr,
+ num_kpages, num_hwpages);
goto ehca_reg_internal_maxmr_exit1;
}
@@ -1506,7 +1585,7 @@ ehca_reg_internal_maxmr_exit1:
ehca_mr_delete(e_mr);
ehca_reg_internal_maxmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p",
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_pd=%p e_maxmr=%p",
ret, shca, e_pd, e_maxmr);
return ret;
} /* end ehca_reg_internal_maxmr() */
@@ -1524,28 +1603,29 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
u64 h_ret;
struct ehca_mr *e_origmr = shca->maxmr;
u32 hipz_acl;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
&hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
"e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, e_origmr, shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
e_origmr->ib.ib_mr.lkey);
- return ehca_mrmw_map_hrc_reg_smr(h_ret);
+ return ehca2ib_return_code(h_ret);
}
/* successful registration */
- e_newmr->num_pages = e_origmr->num_pages;
- e_newmr->num_4k = e_origmr->num_4k;
- e_newmr->start = iova_start;
- e_newmr->size = e_origmr->size;
- e_newmr->acl = acl;
+ e_newmr->num_kpages = e_origmr->num_kpages;
+ e_newmr->num_hwpages = e_origmr->num_hwpages;
+ e_newmr->hwpage_size = e_origmr->hwpage_size;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
e_newmr->ipz_mr_handle = hipzout.handle;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
@@ -1573,7 +1653,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
if (ret) {
ehca_err(&shca->ib_device, "dereg internal max-MR failed, "
- "ret=%x e_maxmr=%p shca=%p lkey=%x",
+ "ret=%i e_maxmr=%p shca=%p lkey=%x",
ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
shca->maxmr = e_maxmr;
goto ehca_dereg_internal_maxmr_exit0;
@@ -1583,7 +1663,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
ehca_dereg_internal_maxmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p",
+ ehca_err(&shca->ib_device, "ret=%i shca=%p shca->maxmr=%p",
ret, shca, shca->maxmr);
return ret;
} /* end ehca_dereg_internal_maxmr() */
@@ -1677,299 +1757,352 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
/*----------------------------------------------------------------------*/
-/* setup page buffer from page info */
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
- u32 number,
- u64 *kpage)
+/* PAGE_SIZE >= pginfo->hwpage_size */
+static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
{
int ret = 0;
struct ib_umem_chunk *prev_chunk;
struct ib_umem_chunk *chunk;
- struct ib_phys_buf *pbuf;
- u64 *fmrlist;
- u64 num4k, pgaddr, offs4k;
+ u64 pgaddr;
u32 i = 0;
u32 j = 0;
-
- if (pginfo->type == EHCA_MR_PGI_PHYS) {
- /* loop over desired phys_buf_array entries */
- while (i < number) {
- pbuf = pginfo->phys_buf_array + pginfo->next_buf;
- num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
- offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
- while (pginfo->next_4k < offs4k + num4k) {
- /* sanity check */
- if ((pginfo->page_cnt >= pginfo->num_pages) ||
- (pginfo->page_4k_cnt >= pginfo->num_4k)) {
- ehca_gen_err("page_cnt >= num_pages, "
- "page_cnt=%lx "
- "num_pages=%lx "
- "page_4k_cnt=%lx "
- "num_4k=%lx i=%x",
- pginfo->page_cnt,
- pginfo->num_pages,
- pginfo->page_4k_cnt,
- pginfo->num_4k, i);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
- }
- *kpage = phys_to_abs(
- (pbuf->addr & EHCA_PAGEMASK)
- + (pginfo->next_4k * EHCA_PAGESIZE));
- if ( !(*kpage) && pbuf->addr ) {
- ehca_gen_err("pbuf->addr=%lx "
- "pbuf->size=%lx "
- "next_4k=%lx", pbuf->addr,
- pbuf->size,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
- }
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k %
- (PAGE_SIZE / EHCA_PAGESIZE) == 0)
- (pginfo->page_cnt)++;
- kpage++;
- i++;
- if (i >= number) break;
+ int hwpages_per_kpage = PAGE_SIZE / pginfo->hwpage_size;
+
+ /* loop over desired chunk entries */
+ chunk = pginfo->u.usr.next_chunk;
+ prev_chunk = pginfo->u.usr.next_chunk;
+ list_for_each_entry_continue(
+ chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+ for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+ pgaddr = page_to_pfn(chunk->page_list[i].page)
+ << PAGE_SHIFT ;
+ *kpage = phys_to_abs(pgaddr +
+ (pginfo->next_hwpage *
+ pginfo->hwpage_size));
+ if ( !(*kpage) ) {
+ ehca_gen_err("pgaddr=%lx "
+ "chunk->page_list[i]=%lx "
+ "i=%x next_hwpage=%lx",
+ pgaddr, (u64)sg_dma_address(
+ &chunk->page_list[i]),
+ i, pginfo->next_hwpage);
+ return -EFAULT;
}
- if (pginfo->next_4k >= offs4k + num4k) {
- (pginfo->next_buf)++;
- pginfo->next_4k = 0;
+ (pginfo->hwpage_cnt)++;
+ (pginfo->next_hwpage)++;
+ kpage++;
+ if (pginfo->next_hwpage % hwpages_per_kpage == 0) {
+ (pginfo->kpage_cnt)++;
+ (pginfo->u.usr.next_nmap)++;
+ pginfo->next_hwpage = 0;
+ i++;
}
+ j++;
+ if (j >= number) break;
+ }
+ if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+ (j >= number)) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ break;
+ } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ } else if (j >= number)
+ break;
+ else
+ prev_chunk = chunk;
+ }
+ pginfo->u.usr.next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->u.usr.region->chunk_list)),
+ list);
+ return ret;
+}
+
+/*
+ * check given pages for contiguous layout
+ * last page addr is returned in prev_pgaddr for further check
+ */
+static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
+ int start_idx, int end_idx,
+ u64 *prev_pgaddr)
+{
+ int t;
+ for (t = start_idx; t <= end_idx; t++) {
+ u64 pgaddr = page_to_pfn(page_list[t].page) << PAGE_SHIFT;
+ ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
+ *(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
+ if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
+ ehca_gen_err("uncontiguous page found pgaddr=%lx "
+ "prev_pgaddr=%lx page_list_i=%x",
+ pgaddr, *prev_pgaddr, t);
+ return -EINVAL;
}
- } else if (pginfo->type == EHCA_MR_PGI_USER) {
- /* loop over desired chunk entries */
- chunk = pginfo->next_chunk;
- prev_chunk = pginfo->next_chunk;
- list_for_each_entry_continue(chunk,
- (&(pginfo->region->chunk_list)),
- list) {
- for (i = pginfo->next_nmap; i < chunk->nmap; ) {
+ *prev_pgaddr = pgaddr;
+ }
+ return 0;
+}
+
+/* PAGE_SIZE < pginfo->hwpage_size */
+static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret = 0;
+ struct ib_umem_chunk *prev_chunk;
+ struct ib_umem_chunk *chunk;
+ u64 pgaddr, prev_pgaddr;
+ u32 i = 0;
+ u32 j = 0;
+ int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE;
+ int nr_kpages = kpages_per_hwpage;
+
+ /* loop over desired chunk entries */
+ chunk = pginfo->u.usr.next_chunk;
+ prev_chunk = pginfo->u.usr.next_chunk;
+ list_for_each_entry_continue(
+ chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+ for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+ if (nr_kpages == kpages_per_hwpage) {
pgaddr = ( page_to_pfn(chunk->page_list[i].page)
<< PAGE_SHIFT );
- *kpage = phys_to_abs(pgaddr +
- (pginfo->next_4k *
- EHCA_PAGESIZE));
+ *kpage = phys_to_abs(pgaddr);
if ( !(*kpage) ) {
- ehca_gen_err("pgaddr=%lx "
- "chunk->page_list[i]=%lx "
- "i=%x next_4k=%lx mr=%p",
- pgaddr,
- (u64)sg_dma_address(
- &chunk->
- page_list[i]),
- i, pginfo->next_4k, e_mr);
+ ehca_gen_err("pgaddr=%lx i=%x",
+ pgaddr, i);
ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
+ return ret;
}
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- kpage++;
- if (pginfo->next_4k %
- (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_nmap)++;
- pginfo->next_4k = 0;
- i++;
+ /*
+ * The first page in a hwpage must be aligned;
+ * the first MR page is exempt from this rule.
+ */
+ if (pgaddr & (pginfo->hwpage_size - 1)) {
+ if (pginfo->hwpage_cnt) {
+ ehca_gen_err(
+ "invalid alignment "
+ "pgaddr=%lx i=%x "
+ "mr_pgsize=%lx",
+ pgaddr, i,
+ pginfo->hwpage_size);
+ ret = -EFAULT;
+ return ret;
+ }
+ /* first MR page */
+ pginfo->kpage_cnt =
+ (pgaddr &
+ (pginfo->hwpage_size - 1)) >>
+ PAGE_SHIFT;
+ nr_kpages -= pginfo->kpage_cnt;
+ *kpage = phys_to_abs(
+ pgaddr &
+ ~(pginfo->hwpage_size - 1));
}
- j++;
- if (j >= number) break;
+ ehca_gen_dbg("kpage=%lx chunk_page=%lx "
+ "value=%016lx", *kpage, pgaddr,
+ *(u64 *)abs_to_virt(
+ phys_to_abs(pgaddr)));
+ prev_pgaddr = pgaddr;
+ i++;
+ pginfo->kpage_cnt++;
+ pginfo->u.usr.next_nmap++;
+ nr_kpages--;
+ if (!nr_kpages)
+ goto next_kpage;
+ continue;
}
- if ((pginfo->next_nmap >= chunk->nmap) &&
- (j >= number)) {
- pginfo->next_nmap = 0;
- prev_chunk = chunk;
- break;
- } else if (pginfo->next_nmap >= chunk->nmap) {
- pginfo->next_nmap = 0;
- prev_chunk = chunk;
- } else if (j >= number)
+ if (i + nr_kpages > chunk->nmap) {
+ ret = ehca_check_kpages_per_ate(
+ chunk->page_list, i,
+ chunk->nmap - 1, &prev_pgaddr);
+ if (ret) return ret;
+ pginfo->kpage_cnt += chunk->nmap - i;
+ pginfo->u.usr.next_nmap += chunk->nmap - i;
+ nr_kpages -= chunk->nmap - i;
break;
- else
- prev_chunk = chunk;
- }
- pginfo->next_chunk =
- list_prepare_entry(prev_chunk,
- (&(pginfo->region->chunk_list)),
- list);
- } else if (pginfo->type == EHCA_MR_PGI_FMR) {
- /* loop over desired page_list entries */
- fmrlist = pginfo->page_list + pginfo->next_listelem;
- for (i = 0; i < number; i++) {
- *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
- pginfo->next_4k * EHCA_PAGESIZE);
- if ( !(*kpage) ) {
- ehca_gen_err("*fmrlist=%lx fmrlist=%p "
- "next_listelem=%lx next_4k=%lx",
- *fmrlist, fmrlist,
- pginfo->next_listelem,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
}
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
+
+ ret = ehca_check_kpages_per_ate(chunk->page_list, i,
+ i + nr_kpages - 1,
+ &prev_pgaddr);
+ if (ret) return ret;
+ i += nr_kpages;
+ pginfo->kpage_cnt += nr_kpages;
+ pginfo->u.usr.next_nmap += nr_kpages;
+next_kpage:
+ nr_kpages = kpages_per_hwpage;
+ (pginfo->hwpage_cnt)++;
kpage++;
- if (pginfo->next_4k %
- (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_listelem)++;
- fmrlist++;
- pginfo->next_4k = 0;
- }
+ j++;
+ if (j >= number) break;
}
- } else {
- ehca_gen_err("bad pginfo->type=%x", pginfo->type);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
+ if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+ (j >= number)) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ break;
+ } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ } else if (j >= number)
+ break;
+ else
+ prev_chunk = chunk;
}
-
-ehca_set_pagebuf_exit0:
- if (ret)
- ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
- "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
- "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
- "next_listelem=%lx region=%p next_chunk=%p "
- "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
- pginfo->num_pages, pginfo->num_4k,
- pginfo->next_buf, pginfo->next_4k, number, kpage,
- pginfo->page_cnt, pginfo->page_4k_cnt, i,
- pginfo->next_listelem, pginfo->region,
- pginfo->next_chunk, pginfo->next_nmap);
+ pginfo->u.usr.next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->u.usr.region->chunk_list)),
+ list);
return ret;
-} /* end ehca_set_pagebuf() */
-
-/*----------------------------------------------------------------------*/
+}
-/* setup 1 page from page info page buffer */
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
- u64 *rpage)
+int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
{
int ret = 0;
- struct ib_phys_buf *tmp_pbuf;
- u64 *fmrlist;
- struct ib_umem_chunk *chunk;
- struct ib_umem_chunk *prev_chunk;
- u64 pgaddr, num4k, offs4k;
-
- if (pginfo->type == EHCA_MR_PGI_PHYS) {
- /* sanity check */
- if ((pginfo->page_cnt >= pginfo->num_pages) ||
- (pginfo->page_4k_cnt >= pginfo->num_4k)) {
- ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
- "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
- pginfo->page_cnt, pginfo->num_pages,
- pginfo->page_4k_cnt, pginfo->num_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
- }
- tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
- num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
- offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
- *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
- (pginfo->next_4k * EHCA_PAGESIZE));
- if ( !(*rpage) && tmp_pbuf->addr ) {
- ehca_gen_err("tmp_pbuf->addr=%lx"
- " tmp_pbuf->size=%lx next_4k=%lx",
- tmp_pbuf->addr, tmp_pbuf->size,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
- }
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
- (pginfo->page_cnt)++;
- if (pginfo->next_4k >= offs4k + num4k) {
- (pginfo->next_buf)++;
- pginfo->next_4k = 0;
- }
- } else if (pginfo->type == EHCA_MR_PGI_USER) {
- chunk = pginfo->next_chunk;
- prev_chunk = pginfo->next_chunk;
- list_for_each_entry_continue(chunk,
- (&(pginfo->region->chunk_list)),
- list) {
- pgaddr = ( page_to_pfn(chunk->page_list[
- pginfo->next_nmap].page)
- << PAGE_SHIFT);
- *rpage = phys_to_abs(pgaddr +
- (pginfo->next_4k * EHCA_PAGESIZE));
- if ( !(*rpage) ) {
- ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
- " next_nmap=%lx next_4k=%lx mr=%p",
- pgaddr, (u64)sg_dma_address(
- &chunk->page_list[
- pginfo->
- next_nmap]),
- pginfo->next_nmap, pginfo->next_4k,
- e_mr);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
- }
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k %
- (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_nmap)++;
- pginfo->next_4k = 0;
+ struct ib_phys_buf *pbuf;
+ u64 num_hw, offs_hw;
+ u32 i = 0;
+
+ /* loop over desired phys_buf_array entries */
+ while (i < number) {
+ pbuf = pginfo->u.phy.phys_buf_array + pginfo->u.phy.next_buf;
+ num_hw = NUM_CHUNKS((pbuf->addr % pginfo->hwpage_size) +
+ pbuf->size, pginfo->hwpage_size);
+ offs_hw = (pbuf->addr & ~(pginfo->hwpage_size - 1)) /
+ pginfo->hwpage_size;
+ while (pginfo->next_hwpage < offs_hw + num_hw) {
+ /* sanity check */
+ if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
+ (pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
+ ehca_gen_err("kpage_cnt >= num_kpages, "
+ "kpage_cnt=%lx num_kpages=%lx "
+ "hwpage_cnt=%lx "
+ "num_hwpages=%lx i=%x",
+ pginfo->kpage_cnt,
+ pginfo->num_kpages,
+ pginfo->hwpage_cnt,
+ pginfo->num_hwpages, i);
+ return -EFAULT;
}
- if (pginfo->next_nmap >= chunk->nmap) {
- pginfo->next_nmap = 0;
- prev_chunk = chunk;
+ *kpage = phys_to_abs(
+ (pbuf->addr & ~(pginfo->hwpage_size - 1)) +
+ (pginfo->next_hwpage * pginfo->hwpage_size));
+ if ( !(*kpage) && pbuf->addr ) {
+ ehca_gen_err("pbuf->addr=%lx pbuf->size=%lx "
+ "next_hwpage=%lx", pbuf->addr,
+ pbuf->size, pginfo->next_hwpage);
+ return -EFAULT;
}
- break;
+ (pginfo->hwpage_cnt)++;
+ (pginfo->next_hwpage)++;
+ if (PAGE_SIZE >= pginfo->hwpage_size) {
+ if (pginfo->next_hwpage %
+ (PAGE_SIZE / pginfo->hwpage_size) == 0)
+ (pginfo->kpage_cnt)++;
+ } else
+ pginfo->kpage_cnt += pginfo->hwpage_size /
+ PAGE_SIZE;
+ kpage++;
+ i++;
+ if (i >= number) break;
}
- pginfo->next_chunk =
- list_prepare_entry(prev_chunk,
- (&(pginfo->region->chunk_list)),
- list);
- } else if (pginfo->type == EHCA_MR_PGI_FMR) {
- fmrlist = pginfo->page_list + pginfo->next_listelem;
- *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
- pginfo->next_4k * EHCA_PAGESIZE);
- if ( !(*rpage) ) {
+ if (pginfo->next_hwpage >= offs_hw + num_hw) {
+ (pginfo->u.phy.next_buf)++;
+ pginfo->next_hwpage = 0;
+ }
+ }
+ return ret;
+}
+
+int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret = 0;
+ u64 *fmrlist;
+ u32 i;
+
+ /* loop over desired page_list entries */
+ fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem;
+ for (i = 0; i < number; i++) {
+ *kpage = phys_to_abs((*fmrlist & ~(pginfo->hwpage_size - 1)) +
+ pginfo->next_hwpage * pginfo->hwpage_size);
+ if ( !(*kpage) ) {
ehca_gen_err("*fmrlist=%lx fmrlist=%p "
- "next_listelem=%lx next_4k=%lx",
- *fmrlist, fmrlist, pginfo->next_listelem,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
+ "next_listelem=%lx next_hwpage=%lx",
+ *fmrlist, fmrlist,
+ pginfo->u.fmr.next_listelem,
+ pginfo->next_hwpage);
+ return -EFAULT;
}
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k %
- (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_listelem)++;
- pginfo->next_4k = 0;
+ (pginfo->hwpage_cnt)++;
+ if (pginfo->u.fmr.fmr_pgsize >= pginfo->hwpage_size) {
+ if (pginfo->next_hwpage %
+ (pginfo->u.fmr.fmr_pgsize /
+ pginfo->hwpage_size) == 0) {
+ (pginfo->kpage_cnt)++;
+ (pginfo->u.fmr.next_listelem)++;
+ fmrlist++;
+ pginfo->next_hwpage = 0;
+ } else
+ (pginfo->next_hwpage)++;
+ } else {
+ unsigned int cnt_per_hwpage = pginfo->hwpage_size /
+ pginfo->u.fmr.fmr_pgsize;
+ unsigned int j;
+ u64 prev = *kpage;
+ /* check if adrs are contiguous */
+ for (j = 1; j < cnt_per_hwpage; j++) {
+ u64 p = phys_to_abs(fmrlist[j] &
+ ~(pginfo->hwpage_size - 1));
+ if (prev + pginfo->u.fmr.fmr_pgsize != p) {
+ ehca_gen_err("uncontiguous fmr pages "
+ "found prev=%lx p=%lx "
+ "idx=%x", prev, p, i + j);
+ return -EINVAL;
+ }
+ prev = p;
+ }
+ pginfo->kpage_cnt += cnt_per_hwpage;
+ pginfo->u.fmr.next_listelem += cnt_per_hwpage;
+ fmrlist += cnt_per_hwpage;
}
- } else {
+ kpage++;
+ }
+ return ret;
+}
+
+/* setup page buffer from page info */
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret;
+
+ switch (pginfo->type) {
+ case EHCA_MR_PGI_PHYS:
+ ret = ehca_set_pagebuf_phys(pginfo, number, kpage);
+ break;
+ case EHCA_MR_PGI_USER:
+ ret = PAGE_SIZE >= pginfo->hwpage_size ?
+ ehca_set_pagebuf_user1(pginfo, number, kpage) :
+ ehca_set_pagebuf_user2(pginfo, number, kpage);
+ break;
+ case EHCA_MR_PGI_FMR:
+ ret = ehca_set_pagebuf_fmr(pginfo, number, kpage);
+ break;
+ default:
ehca_gen_err("bad pginfo->type=%x", pginfo->type);
ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
+ break;
}
-
-ehca_set_pagebuf_1_exit0:
- if (ret)
- ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
- "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
- "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
- "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
- pginfo, pginfo->type, pginfo->num_pages,
- pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
- rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
- pginfo->next_listelem, pginfo->region,
- pginfo->next_chunk, pginfo->next_nmap);
return ret;
-} /* end ehca_set_pagebuf_1() */
+} /* end ehca_set_pagebuf() */
/*----------------------------------------------------------------------*/
@@ -1982,7 +2115,7 @@ int ehca_mr_is_maxmr(u64 size,
{
/* a MR is treated as max-MR only if it fits following: */
if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
- (iova_start == (void*)KERNELBASE)) {
+ (iova_start == (void *)KERNELBASE)) {
ehca_gen_dbg("this is a max-MR");
return 1;
} else
@@ -2011,9 +2144,9 @@ void ehca_mrmw_map_acl(int ib_acl,
/*----------------------------------------------------------------------*/
/* sets page size in hipz access control for MR/MW. */
-void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/
+void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl) /*INOUT*/
{
- return; /* HCA supports only 4k */
+ *hipz_acl |= (ehca_encode_hwpage_size(pgsize) << 24);
} /* end ehca_mrmw_set_pgsize_hipz_acl() */
/*----------------------------------------------------------------------*/
@@ -2042,196 +2175,23 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
/*----------------------------------------------------------------------*/
/*
- * map HIPZ rc to IB retcodes for MR/MW allocations
- * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
- */
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* successful completion */
- return 0;
- case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
- case H_CONSTRAINED: /* resource constraint */
- case H_NO_MEM:
- return -ENOMEM;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_alloc() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering last page
- */
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* registration complete */
- return 0;
- case H_PAGE_REGISTERED: /* page registered */
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
-/* case H_QT_PARM: invalid queue type */
- case H_PARAMETER: /*
- * invalid logical address,
- * or count zero or greater 512
- */
- case H_TABLE_FULL: /* page table full */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_rrpg_last() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering one page, but not last page
- */
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_PAGE_REGISTERED: /* page registered */
- return 0;
- case H_SUCCESS: /* registration complete */
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
-/* case H_QT_PARM: invalid queue type */
- case H_PARAMETER: /*
- * invalid logical address,
- * or count zero or greater 512
- */
- case H_TABLE_FULL: /* page table full */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
-
-/*----------------------------------------------------------------------*/
-
-/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* successful completion */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_query_mr() */
-
-/*----------------------------------------------------------------------*/
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MR resource
- * Used for hipz_h_free_resource_mr
- */
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* resource freed */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- case H_R_STATE: /* invalid resource state */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_RESOURCE: /* Resource in use */
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_free_mr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MW resource
- * Used for hipz_h_free_resource_mw
- */
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* resource freed */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- case H_R_STATE: /* invalid resource state */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_RESOURCE: /* Resource in use */
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_free_mw() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for SMR registrations
- * Used for hipz_h_register_smr.
- */
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* successful completion */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- case H_MEM_PARM: /* invalid MR virtual address */
- case H_MEM_ACCESS_PARM: /* invalid access controls */
- case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_reg_smr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
* MR destructor and constructor
* used in Reregister MR verb, sets all fields in ehca_mr_t to 0,
* except struct ib_mr and spinlock
*/
void ehca_mr_deletenew(struct ehca_mr *mr)
{
- mr->flags = 0;
- mr->num_pages = 0;
- mr->num_4k = 0;
- mr->acl = 0;
- mr->start = NULL;
+ mr->flags = 0;
+ mr->num_kpages = 0;
+ mr->num_hwpages = 0;
+ mr->acl = 0;
+ mr->start = NULL;
mr->fmr_page_size = 0;
mr->fmr_max_pages = 0;
- mr->fmr_max_maps = 0;
- mr->fmr_map_cnt = 0;
+ mr->fmr_max_maps = 0;
+ mr->fmr_map_cnt = 0;
memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
memset(&mr->galpas, 0, sizeof(mr->galpas));
- mr->nr_of_pages = 0;
- mr->pagearray = NULL;
} /* end ehca_mr_deletenew() */
int ehca_init_mrmw_cache(void)
@@ -2239,13 +2199,13 @@ int ehca_init_mrmw_cache(void)
mr_cache = kmem_cache_create("ehca_cache_mr",
sizeof(struct ehca_mr), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!mr_cache)
return -ENOMEM;
mw_cache = kmem_cache_create("ehca_cache_mw",
sizeof(struct ehca_mw), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!mw_cache) {
kmem_cache_destroy(mr_cache);
mr_cache = NULL;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h
index d936e40a5748..bc8f4e31c123 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.h
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h
@@ -101,40 +101,21 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
u64 *page_list,
int list_len);
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
u32 number,
u64 *kpage);
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
- u64 *rpage);
-
int ehca_mr_is_maxmr(u64 size,
u64 *iova_start);
void ehca_mrmw_map_acl(int ib_acl,
u32 *hipz_acl);
-void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
+void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl);
void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
int *ib_acl);
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
-
void ehca_mr_deletenew(struct ehca_mr *mr);
#endif /*_EHCA_MRMW_H_*/
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
index 79d0591a8043..43bcf085fcf2 100644
--- a/drivers/infiniband/hw/ehca/ehca_pd.c
+++ b/drivers/infiniband/hw/ehca/ehca_pd.c
@@ -49,6 +49,7 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
struct ib_ucontext *context, struct ib_udata *udata)
{
struct ehca_pd *pd;
+ int i;
pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
if (!pd) {
@@ -58,6 +59,11 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
}
pd->ownpid = current->tgid;
+ for (i = 0; i < 2; i++) {
+ INIT_LIST_HEAD(&pd->free[i]);
+ INIT_LIST_HEAD(&pd->full[i]);
+ }
+ mutex_init(&pd->lock);
/*
* Kernel PD: when device = -1, 0
@@ -81,6 +87,8 @@ int ehca_dealloc_pd(struct ib_pd *pd)
{
u32 cur_pid = current->tgid;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
+ int i, leftovers = 0;
+ struct ipz_small_queue_page *page, *tmp;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
my_pd->ownpid != cur_pid) {
@@ -89,8 +97,20 @@ int ehca_dealloc_pd(struct ib_pd *pd)
return -EINVAL;
}
- kmem_cache_free(pd_cache,
- container_of(pd, struct ehca_pd, ib_pd));
+ for (i = 0; i < 2; i++) {
+ list_splice(&my_pd->full[i], &my_pd->free[i]);
+ list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) {
+ leftovers = 1;
+ free_page(page->page);
+ kmem_cache_free(small_qp_cache, page);
+ }
+ }
+
+ if (leftovers)
+ ehca_warn(pd->device,
+ "Some small queue pages were not freed");
+
+ kmem_cache_free(pd_cache, my_pd);
return 0;
}
@@ -100,7 +120,7 @@ int ehca_init_pd_cache(void)
pd_cache = kmem_cache_create("ehca_cache_pd",
sizeof(struct ehca_pd), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!pd_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h
index 8707d297ce4c..818803057ebf 100644
--- a/drivers/infiniband/hw/ehca/ehca_qes.h
+++ b/drivers/infiniband/hw/ehca/ehca_qes.h
@@ -53,13 +53,13 @@ struct ehca_vsgentry {
u32 length;
};
-#define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7)
-#define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3)
-#define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12)
-#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31)
-#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47)
-#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55)
-#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63)
+#define GRH_FLAG_MASK EHCA_BMASK_IBM( 7, 7)
+#define GRH_IPVERSION_MASK EHCA_BMASK_IBM( 0, 3)
+#define GRH_TCLASS_MASK EHCA_BMASK_IBM( 4, 12)
+#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13, 31)
+#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32, 47)
+#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48, 55)
+#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56, 63)
/*
* Unreliable Datagram Address Vector Format
@@ -206,10 +206,10 @@ struct ehca_wqe {
};
-#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
-#define WC_IMM_DATA EHCA_BMASK_IBM(1,1)
-#define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2)
-#define WC_SE_BIT EHCA_BMASK_IBM(3,3)
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0)
+#define WC_IMM_DATA EHCA_BMASK_IBM(1, 1)
+#define WC_GRH_PRESENT EHCA_BMASK_IBM(2, 2)
+#define WC_SE_BIT EHCA_BMASK_IBM(3, 3)
#define WC_STATUS_ERROR_BIT 0x80000000
#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
#define WC_STATUS_PURGE_BIT 0x10
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 74671250303f..e2bd62be11e7 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -273,38 +273,44 @@ static inline void queue2resp(struct ipzu_queue_resp *resp,
resp->queue_length = queue->queue_length;
resp->pagesize = queue->pagesize;
resp->toggle_state = queue->toggle_state;
-}
-
-static inline int ll_qp_msg_size(int nr_sge)
-{
- return 128 << nr_sge;
+ resp->offset = queue->offset;
}
/*
* init_qp_queue initializes/constructs r/squeue and registers queue pages.
*/
static inline int init_qp_queue(struct ehca_shca *shca,
+ struct ehca_pd *pd,
struct ehca_qp *my_qp,
struct ipz_queue *queue,
int q_type,
u64 expected_hret,
- int nr_q_pages,
- int wqe_size,
- int nr_sges)
+ struct ehca_alloc_queue_parms *parms,
+ int wqe_size)
{
- int ret, cnt, ipz_rc;
+ int ret, cnt, ipz_rc, nr_q_pages;
void *vpage;
u64 rpage, h_ret;
struct ib_device *ib_dev = &shca->ib_device;
struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
- if (!nr_q_pages)
+ if (!parms->queue_size)
return 0;
- ipz_rc = ipz_queue_ctor(queue, nr_q_pages, EHCA_PAGESIZE,
- wqe_size, nr_sges);
+ if (parms->is_small) {
+ nr_q_pages = 1;
+ ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+ 128 << parms->page_size,
+ wqe_size, parms->act_nr_sges, 1);
+ } else {
+ nr_q_pages = parms->queue_size;
+ ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+ EHCA_PAGESIZE, wqe_size,
+ parms->act_nr_sges, 0);
+ }
+
if (!ipz_rc) {
- ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x",
+ ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i",
ipz_rc);
return -EBUSY;
}
@@ -323,12 +329,12 @@ static inline int init_qp_queue(struct ehca_shca *shca,
h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
my_qp->ipz_qp_handle,
NULL, 0, q_type,
- rpage, 1,
+ rpage, parms->is_small ? 0 : 1,
my_qp->galpas.kernel);
if (cnt == (nr_q_pages - 1)) { /* last page! */
if (h_ret != expected_hret) {
ehca_err(ib_dev, "hipz_qp_register_rpage() "
- "h_ret= %lx ", h_ret);
+ "h_ret=%li", h_ret);
ret = ehca2ib_return_code(h_ret);
goto init_qp_queue1;
}
@@ -342,7 +348,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
} else {
if (h_ret != H_PAGE_REGISTERED) {
ehca_err(ib_dev, "hipz_qp_register_rpage() "
- "h_ret= %lx ", h_ret);
+ "h_ret=%li", h_ret);
ret = ehca2ib_return_code(h_ret);
goto init_qp_queue1;
}
@@ -354,19 +360,55 @@ static inline int init_qp_queue(struct ehca_shca *shca,
return 0;
init_qp_queue1:
- ipz_queue_dtor(queue);
+ ipz_queue_dtor(pd, queue);
return ret;
}
+static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp)
+{
+ if (is_llqp)
+ return 128 << act_nr_sge;
+ else
+ return offsetof(struct ehca_wqe,
+ u.nud.sg_list[act_nr_sge]);
+}
+
+static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
+ int req_nr_sge, int is_llqp)
+{
+ u32 wqe_size, q_size;
+ int act_nr_sge = req_nr_sge;
+
+ if (!is_llqp)
+ /* round up #SGEs so WQE size is a power of 2 */
+ for (act_nr_sge = 4; act_nr_sge <= 252;
+ act_nr_sge = 4 + 2 * act_nr_sge)
+ if (act_nr_sge >= req_nr_sge)
+ break;
+
+ wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);
+ q_size = wqe_size * (queue->max_wr + 1);
+
+ if (q_size <= 512)
+ queue->page_size = 2;
+ else if (q_size <= 1024)
+ queue->page_size = 3;
+ else
+ queue->page_size = 0;
+
+ queue->is_small = (queue->page_size != 0);
+}
+
/*
* Create an ib_qp struct that is either a QP or an SRQ, depending on
* the value of the is_srq parameter. If init_attr and srq_init_attr share
* fields, the field out of init_attr is used.
*/
-struct ehca_qp *internal_create_qp(struct ib_pd *pd,
- struct ib_qp_init_attr *init_attr,
- struct ib_srq_init_attr *srq_init_attr,
- struct ib_udata *udata, int is_srq)
+static struct ehca_qp *internal_create_qp(
+ struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_srq_init_attr *srq_init_attr,
+ struct ib_udata *udata, int is_srq)
{
struct ehca_qp *my_qp;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
@@ -471,7 +513,7 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
} else if (init_attr->cap.max_send_wr > 255) {
ehca_err(pd->device,
"Invalid Number of "
- "ax_send_wr=%x for UD QP_TYPE=%x",
+ "max_send_wr=%x for UD QP_TYPE=%x",
init_attr->cap.max_send_wr, qp_type);
return ERR_PTR(-EINVAL);
}
@@ -482,6 +524,18 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
return ERR_PTR(-EINVAL);
break;
}
+ } else {
+ int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI
+ || qp_type == IB_QPT_GSI) ? 250 : 252;
+
+ if (init_attr->cap.max_send_sge > max_sge
+ || init_attr->cap.max_recv_sge > max_sge) {
+ ehca_err(pd->device, "Invalid number of SGEs requested "
+ "send_sge=%x recv_sge=%x max_sge=%x",
+ init_attr->cap.max_send_sge,
+ init_attr->cap.max_recv_sge, max_sge);
+ return ERR_PTR(-EINVAL);
+ }
}
if (pd->uobject && udata)
@@ -515,7 +569,6 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
write_lock_irqsave(&ehca_qp_idr_lock, flags);
ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-
} while (ret == -EAGAIN);
if (ret) {
@@ -524,11 +577,17 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
goto create_qp_exit0;
}
+ if (my_qp->token > 0x1FFFFFF) {
+ ret = -EINVAL;
+ ehca_err(pd->device, "Invalid number of qp");
+ goto create_qp_exit1;
+ }
+
parms.servicetype = ibqptype2servicetype(qp_type);
if (parms.servicetype < 0) {
ret = -EINVAL;
ehca_err(pd->device, "Invalid qp_type=%x", qp_type);
- goto create_qp_exit0;
+ goto create_qp_exit1;
}
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
@@ -552,14 +611,25 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
if (my_qp->recv_cq)
parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle;
- parms.max_send_wr = init_attr->cap.max_send_wr;
- parms.max_recv_wr = init_attr->cap.max_recv_wr;
- parms.max_send_sge = max_send_sge;
- parms.max_recv_sge = max_recv_sge;
+ parms.squeue.max_wr = init_attr->cap.max_send_wr;
+ parms.rqueue.max_wr = init_attr->cap.max_recv_wr;
+ parms.squeue.max_sge = max_send_sge;
+ parms.rqueue.max_sge = max_recv_sge;
+
+ if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
+ if (HAS_SQ(my_qp))
+ ehca_determine_small_queue(
+ &parms.squeue, max_send_sge, is_llqp);
+ if (HAS_RQ(my_qp))
+ ehca_determine_small_queue(
+ &parms.rqueue, max_recv_sge, is_llqp);
+ parms.qp_storage =
+ (parms.squeue.is_small || parms.rqueue.is_small);
+ }
h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx",
+ ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li",
h_ret);
ret = ehca2ib_return_code(h_ret);
goto create_qp_exit1;
@@ -569,50 +639,33 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
my_qp->ipz_qp_handle = parms.qp_handle;
my_qp->galpas = parms.galpas;
+ swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp);
+ rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp);
+
switch (qp_type) {
case IB_QPT_RC:
- if (!is_llqp) {
- swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
- (parms.act_nr_send_sges)]);
- rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
- (parms.act_nr_recv_sges)]);
- } else { /* for LLQP we need to use msg size, not wqe size */
- swqe_size = ll_qp_msg_size(max_send_sge);
- rwqe_size = ll_qp_msg_size(max_recv_sge);
- parms.act_nr_send_sges = 1;
- parms.act_nr_recv_sges = 1;
+ if (is_llqp) {
+ parms.squeue.act_nr_sges = 1;
+ parms.rqueue.act_nr_sges = 1;
}
break;
- case IB_QPT_UC:
- swqe_size = offsetof(struct ehca_wqe,
- u.nud.sg_list[parms.act_nr_send_sges]);
- rwqe_size = offsetof(struct ehca_wqe,
- u.nud.sg_list[parms.act_nr_recv_sges]);
- break;
-
case IB_QPT_UD:
case IB_QPT_GSI:
case IB_QPT_SMI:
+ /* UD circumvention */
if (is_llqp) {
- swqe_size = ll_qp_msg_size(parms.act_nr_send_sges);
- rwqe_size = ll_qp_msg_size(parms.act_nr_recv_sges);
- parms.act_nr_send_sges = 1;
- parms.act_nr_recv_sges = 1;
+ parms.squeue.act_nr_sges = 1;
+ parms.rqueue.act_nr_sges = 1;
} else {
- /* UD circumvention */
- parms.act_nr_send_sges -= 2;
- parms.act_nr_recv_sges -= 2;
- swqe_size = offsetof(struct ehca_wqe,
- u.ud_av.sg_list[parms.act_nr_send_sges]);
- rwqe_size = offsetof(struct ehca_wqe,
- u.ud_av.sg_list[parms.act_nr_recv_sges]);
+ parms.squeue.act_nr_sges -= 2;
+ parms.rqueue.act_nr_sges -= 2;
}
if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
- parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
- parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
- parms.act_nr_send_sges = init_attr->cap.max_send_sge;
- parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
+ parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr;
+ parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr;
+ parms.squeue.act_nr_sges = init_attr->cap.max_send_sge;
+ parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge;
ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1;
}
@@ -625,25 +678,23 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
/* initialize r/squeue and register queue pages */
if (HAS_SQ(my_qp)) {
ret = init_qp_queue(
- shca, my_qp, &my_qp->ipz_squeue, 0,
+ shca, my_pd, my_qp, &my_qp->ipz_squeue, 0,
HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS,
- parms.nr_sq_pages, swqe_size,
- parms.act_nr_send_sges);
+ &parms.squeue, swqe_size);
if (ret) {
ehca_err(pd->device, "Couldn't initialize squeue "
- "and pages ret=%x", ret);
+ "and pages ret=%i", ret);
goto create_qp_exit2;
}
}
if (HAS_RQ(my_qp)) {
ret = init_qp_queue(
- shca, my_qp, &my_qp->ipz_rqueue, 1,
- H_SUCCESS, parms.nr_rq_pages, rwqe_size,
- parms.act_nr_recv_sges);
+ shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1,
+ H_SUCCESS, &parms.rqueue, rwqe_size);
if (ret) {
ehca_err(pd->device, "Couldn't initialize rqueue "
- "and pages ret=%x", ret);
+ "and pages ret=%i", ret);
goto create_qp_exit3;
}
}
@@ -670,18 +721,16 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
}
init_attr->cap.max_inline_data = 0; /* not supported yet */
- init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
- init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
- init_attr->cap.max_send_sge = parms.act_nr_send_sges;
- init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+ init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges;
+ init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes;
+ init_attr->cap.max_send_sge = parms.squeue.act_nr_sges;
+ init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
my_qp->init_attr = *init_attr;
/* NOTE: define_apq0() not supported yet */
if (qp_type == IB_QPT_GSI) {
h_ret = ehca_define_sqp(shca, my_qp, init_attr);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx",
- h_ret);
ret = ehca2ib_return_code(h_ret);
goto create_qp_exit4;
}
@@ -690,8 +739,8 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
if (my_qp->send_cq) {
ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
if (ret) {
- ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
- ret);
+ ehca_err(pd->device,
+ "Couldn't assign qp to send_cq ret=%i", ret);
goto create_qp_exit4;
}
}
@@ -707,10 +756,13 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
resp.ext_type = my_qp->ext_type;
resp.qkey = my_qp->qkey;
resp.real_qp_num = my_qp->real_qp_num;
+
if (HAS_SQ(my_qp))
queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
if (HAS_RQ(my_qp))
queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue);
+ resp.fw_handle_ofs = (u32)
+ (my_qp->galpas.user.fw_handle & (PAGE_SIZE - 1));
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
@@ -723,11 +775,11 @@ struct ehca_qp *internal_create_qp(struct ib_pd *pd,
create_qp_exit4:
if (HAS_RQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
create_qp_exit3:
if (HAS_SQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_squeue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
create_qp_exit2:
hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
@@ -749,11 +801,11 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
struct ehca_qp *ret;
ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0);
- return IS_ERR(ret) ? (struct ib_qp *) ret : &ret->ib_qp;
+ return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp;
}
-int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
- struct ib_uobject *uobject);
+static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+ struct ib_uobject *uobject);
struct ib_srq *ehca_create_srq(struct ib_pd *pd,
struct ib_srq_init_attr *srq_init_attr,
@@ -780,7 +832,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1);
if (IS_ERR(my_qp))
- return (struct ib_srq *) my_qp;
+ return (struct ib_srq *)my_qp;
/* copy back return values */
srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
@@ -805,7 +857,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to INIT"
- "ehca_qp=%p qp_num=%x hret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -819,7 +871,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not enable SRQ"
- "ehca_qp=%p qp_num=%x hret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -833,11 +885,13 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to RTR"
- "ehca_qp=%p qp_num=%x hret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
+ ehca_free_fw_ctrlblock(mqpcb);
+
return &my_qp->ib_srq;
create_srq2:
@@ -871,11 +925,11 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
&bad_send_wqe_p, NULL, 2);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
- " ehca_qp=%p qp_num=%x h_ret=%lx",
+ " ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
- bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+ bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63)));
ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
qp_num, bad_send_wqe_p);
/* convert wqe pointer to vadr */
@@ -890,7 +944,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
}
/* loop sets wqe's purge bit */
- wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+ wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
*bad_wqe_cnt = 0;
while (wqe->optype != 0xff && wqe->wqef != 0xff) {
if (ehca_debug_level)
@@ -898,7 +952,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
wqe->nr_of_data_seg = 0; /* suppress data access */
wqe->wqef = WQEF_PURGE; /* WQE to be purged */
q_ofs = ipz_queue_advance_offset(squeue, q_ofs);
- wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+ wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
*bad_wqe_cnt = (*bad_wqe_cnt)+1;
}
/*
@@ -949,7 +1003,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
mqpcb, my_qp->galpas.kernel);
if (h_ret != H_SUCCESS) {
ehca_err(ibqp->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, ibqp->qp_num, h_ret);
ret = ehca2ib_return_code(h_ret);
goto modify_qp_exit1;
@@ -985,7 +1039,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ibqp, &smiqp_attr, smiqp_attr_mask, 1);
if (smirc) {
ehca_err(ibqp->device, "SMI RESET -> INIT failed. "
- "ehca_modify_qp() rc=%x", smirc);
+ "ehca_modify_qp() rc=%i", smirc);
ret = H_PARAMETER;
goto modify_qp_exit1;
}
@@ -1003,7 +1057,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
goto modify_qp_exit1;
}
- ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
+ ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x "
"new qp_state=%x attribute_mask=%x",
my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
@@ -1019,7 +1073,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
goto modify_qp_exit1;
}
- if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+ mqpcb->qp_state = ib2ehca_qp_state(qp_new_state);
+ if (mqpcb->qp_state)
update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
else {
ret = -EINVAL;
@@ -1077,7 +1132,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
spin_lock_irqsave(&my_qp->spinlock_s, flags);
squeue_locked = 1;
/* mark next free wqe */
- wqe = (struct ehca_wqe*)
+ wqe = (struct ehca_wqe *)
ipz_qeit_get(&my_qp->ipz_squeue);
wqe->optype = wqe->wqef = 0xff;
ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
@@ -1086,7 +1141,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
if (ret) {
ehca_err(ibqp->device, "prepare_sqe_rts() failed "
- "ehca_qp=%p qp_num=%x ret=%x",
+ "ehca_qp=%p qp_num=%x ret=%i",
my_qp, ibqp->qp_num, ret);
goto modify_qp_exit2;
}
@@ -1112,6 +1167,13 @@ static int internal_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_PKEY_INDEX) {
+ if (attr->pkey_index >= 16) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid pkey_index=%x. "
+ "ehca_qp=%p qp_num=%x max_pkey_index=f",
+ attr->pkey_index, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
mqpcb->prim_p_key_idx = attr->pkey_index;
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
}
@@ -1220,50 +1282,78 @@ static int internal_modify_qp(struct ib_qp *ibqp,
int ehca_mult = ib_rate_to_mult(
shca->sport[my_qp->init_attr.port_num].rate);
+ if (attr->alt_port_num < 1
+ || attr->alt_port_num > shca->num_ports) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid alt_port=%x. "
+ "ehca_qp=%p qp_num=%x num_ports=%x",
+ attr->alt_port_num, my_qp, ibqp->qp_num,
+ shca->num_ports);
+ goto modify_qp_exit2;
+ }
+ mqpcb->alt_phys_port = attr->alt_port_num;
+
+ if (attr->alt_pkey_index >= 16) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid alt_pkey_index=%x. "
+ "ehca_qp=%p qp_num=%x max_pkey_index=f",
+ attr->pkey_index, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
+ mqpcb->alt_p_key_idx = attr->alt_pkey_index;
+
+ mqpcb->timeout_al = attr->alt_timeout;
mqpcb->dlid_al = attr->alt_ah_attr.dlid;
- update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1);
mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1);
mqpcb->service_level_al = attr->alt_ah_attr.sl;
- update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1);
- if (ah_mult < ehca_mult)
- mqpcb->max_static_rate = (ah_mult > 0) ?
- ((ehca_mult - 1) / ah_mult) : 0;
+ if (ah_mult > 0 && ah_mult < ehca_mult)
+ mqpcb->max_static_rate_al = (ehca_mult - 1) / ah_mult;
else
mqpcb->max_static_rate_al = 0;
- update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1);
+ /* OpenIB doesn't support alternate retry counts - copy them */
+ mqpcb->retry_count_al = mqpcb->retry_count;
+ mqpcb->rnr_retry_count_al = mqpcb->rnr_retry_count;
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_ALT_PHYS_PORT, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_ALT_P_KEY_IDX, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT_AL, 1);
+
+ /*
+ * Always supply the GRH flag, even if it's zero, to give the
+ * hypervisor a clear "yes" or "no" instead of a "perhaps"
+ */
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
/*
* only if GRH is TRUE we might consider SOURCE_GID_IDX
* and DEST_GID otherwise phype will return H_ATTR_PARM!!!
*/
if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
- mqpcb->send_grh_flag_al = 1 << 31;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
- mqpcb->source_gid_idx_al =
- attr->alt_ah_attr.grh.sgid_index;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1);
+ mqpcb->send_grh_flag_al = 1;
for (cnt = 0; cnt < 16; cnt++)
mqpcb->dest_gid_al.byte[cnt] =
attr->alt_ah_attr.grh.dgid.raw[cnt];
-
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1);
+ mqpcb->source_gid_idx_al =
+ attr->alt_ah_attr.grh.sgid_index;
mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1);
mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1);
mqpcb->traffic_class_al =
attr->alt_ah_attr.grh.traffic_class;
+
update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1) |
EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
}
}
@@ -1285,7 +1375,14 @@ static int internal_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_PATH_MIG_STATE) {
- mqpcb->path_migration_state = attr->path_mig_state;
+ if (attr->path_mig_state != IB_MIG_REARM
+ && attr->path_mig_state != IB_MIG_MIGRATED) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid mig_state=%x",
+ attr->path_mig_state);
+ goto modify_qp_exit2;
+ }
+ mqpcb->path_migration_state = attr->path_mig_state + 1;
update_mask |=
EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
}
@@ -1311,8 +1408,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
- "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
+ ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%li "
+ "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1344,7 +1441,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ret = ehca2ib_return_code(h_ret);
ehca_err(ibqp->device, "ENABLE in context of "
"RESET_2_INIT failed! Maybe you didn't get "
- "a LID h_ret=%lx ehca_qp=%p qp_num=%x",
+ "a LID h_ret=%li ehca_qp=%p qp_num=%x",
h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1411,7 +1508,7 @@ int ehca_query_qp(struct ib_qp *qp,
}
if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
- ehca_err(qp->device,"Invalid attribute mask "
+ ehca_err(qp->device, "Invalid attribute mask "
"ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
my_qp, qp->qp_num, qp_attr_mask);
return -EINVAL;
@@ -1419,7 +1516,7 @@ int ehca_query_qp(struct ib_qp *qp,
qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!qpcb) {
- ehca_err(qp->device,"Out of memory for qpcb "
+ ehca_err(qp->device, "Out of memory for qpcb "
"ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
return -ENOMEM;
}
@@ -1431,8 +1528,8 @@ int ehca_query_qp(struct ib_qp *qp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(qp->device,"hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%lx",
+ ehca_err(qp->device, "hipz_h_query_qp() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, qp->qp_num, h_ret);
goto query_qp_exit1;
}
@@ -1442,7 +1539,7 @@ int ehca_query_qp(struct ib_qp *qp,
if (qp_attr->cur_qp_state == -EINVAL) {
ret = -EINVAL;
- ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
+ ehca_err(qp->device, "Got invalid ehca_qp_state=%x "
"ehca_qp=%p qp_num=%x",
qpcb->qp_state, my_qp, qp->qp_num);
goto query_qp_exit1;
@@ -1453,7 +1550,7 @@ int ehca_query_qp(struct ib_qp *qp,
qp_attr->qkey = qpcb->qkey;
qp_attr->path_mtu = qpcb->path_mtu;
- qp_attr->path_mig_state = qpcb->path_migration_state;
+ qp_attr->path_mig_state = qpcb->path_migration_state - 1;
qp_attr->rq_psn = qpcb->receive_psn;
qp_attr->sq_psn = qpcb->send_psn;
qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
@@ -1607,7 +1704,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(ibsrq->device, "hipz_h_modify_qp() failed rc=%lx "
+ ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%li "
"ehca_qp=%p qp_num=%x",
h_ret, my_qp, my_qp->real_qp_num);
}
@@ -1650,12 +1747,13 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
ehca_err(srq->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, h_ret);
goto query_srq_exit1;
}
srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
+ srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe;
srq_attr->srq_limit = EHCA_BMASK_GET(
MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
@@ -1668,8 +1766,8 @@ query_srq_exit1:
return ret;
}
-int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
- struct ib_uobject *uobject)
+static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+ struct ib_uobject *uobject)
{
struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
@@ -1700,7 +1798,7 @@ int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num);
if (ret) {
ehca_err(dev, "Couldn't unassign qp from "
- "send_cq ret=%x qp_num=%x cq_num=%x", ret,
+ "send_cq ret=%i qp_num=%x cq_num=%x", ret,
qp_num, my_qp->send_cq->cq_number);
return ret;
}
@@ -1712,7 +1810,7 @@ int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
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 rc=%lx "
+ ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "
"ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
return ehca2ib_return_code(h_ret);
}
@@ -1733,9 +1831,9 @@ int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
}
if (HAS_RQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
if (HAS_SQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_squeue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
kmem_cache_free(qp_cache, my_qp);
return 0;
}
@@ -1759,7 +1857,7 @@ int ehca_init_qp_cache(void)
qp_cache = kmem_cache_create("ehca_cache_qp",
sizeof(struct ehca_qp), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!qp_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 61da65e6e5e0..ea91360835d3 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -79,7 +79,8 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
}
if (ehca_debug_level) {
- ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+ ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
+ ipz_rqueue);
ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
}
@@ -99,7 +100,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
struct ib_sge *sge = send_wr->sg_list;
ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
- "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+ "send_flags=%x opcode=%x", idx, send_wr->wr_id,
send_wr->num_sge, send_wr->send_flags,
send_wr->opcode);
if (mad_hdr) {
@@ -116,7 +117,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
mad_hdr->attr_mod);
}
for (j = 0; j < send_wr->num_sge; j++) {
- u8 *data = (u8 *) abs_to_virt(sge->addr);
+ u8 *data = (u8 *)abs_to_virt(sge->addr);
ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
"lkey=%x",
idx, j, data, sge->length, sge->lkey);
@@ -525,7 +526,7 @@ poll_cq_one_read_cqe:
if (!cqe) {
ret = -EAGAIN;
ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p "
- "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret);
+ "cq_num=%x ret=%i", my_cq, my_cq->cq_number, ret);
goto poll_cq_one_exit0;
}
@@ -534,9 +535,11 @@ poll_cq_one_read_cqe:
cqe_count++;
if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
- struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+ struct ehca_qp *qp;
int purgeflag;
unsigned long flags;
+
+ qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number);
if (!qp) {
ehca_err(cq->device, "cq_num=%x qp_num=%x "
"could not find qp -> ignore cqe",
@@ -551,8 +554,8 @@ poll_cq_one_read_cqe:
spin_unlock_irqrestore(&qp->spinlock_s, flags);
if (purgeflag) {
- ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
- "src_qp=%x",
+ ehca_dbg(cq->device,
+ "Got CQE with purged bit qp_num=%x src_qp=%x",
cqe->local_qp_number, cqe->remote_qp_number);
if (ehca_debug_level)
ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index 9f16e9c79394..f0792e5fbd02 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -82,7 +82,7 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
if (ret != H_SUCCESS) {
ehca_err(&shca->ib_device,
- "Can't define AQP1 for port %x. rc=%lx",
+ "Can't define AQP1 for port %x. h_ret=%li",
port, ret);
return ret;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
index 03b185f873da..4a8346a2bc9e 100644
--- a/drivers/infiniband/hw/ehca/ehca_tools.h
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -73,40 +73,37 @@ extern int ehca_debug_level;
if (unlikely(ehca_debug_level)) \
dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \
"PU%04x EHCA_DBG:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, \
+ raw_smp_processor_id(), __FUNCTION__, \
## arg); \
} while (0)
#define ehca_info(ib_dev, format, arg...) \
dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
#define ehca_warn(ib_dev, format, arg...) \
dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
#define ehca_err(ib_dev, format, arg...) \
dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
/* use this one only if no ib_dev available */
#define ehca_gen_dbg(format, arg...) \
do { \
if (unlikely(ehca_debug_level)) \
- printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
- get_paca()->paca_index, __FUNCTION__, ## arg); \
+ printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
+ raw_smp_processor_id(), __FUNCTION__, ## arg); \
} while (0)
#define ehca_gen_warn(format, arg...) \
- do { \
- if (unlikely(ehca_debug_level)) \
- printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
- get_paca()->paca_index, __FUNCTION__, ## arg); \
- } while (0)
+ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
#define ehca_gen_err(format, arg...) \
printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
/**
* ehca_dmp - printk a memory block, whose length is n*8 bytes.
@@ -114,12 +111,12 @@ extern int ehca_debug_level;
* <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
*/
#define ehca_dmp(adr, len, format, args...) \
- do { \
- unsigned int x; \
+ do { \
+ unsigned int x; \
unsigned int l = (unsigned int)(len); \
- unsigned char *deb = (unsigned char*)(adr); \
+ unsigned char *deb = (unsigned char *)(adr); \
for (x = 0; x < l; x += 16) { \
- printk("EHCA_DMP:%s " format \
+ printk(KERN_INFO "EHCA_DMP:%s " format \
" adr=%p ofs=%04x %016lx %016lx\n", \
__FUNCTION__, ##args, deb, x, \
*((u64 *)&deb[0]), *((u64 *)&deb[8])); \
@@ -128,16 +125,16 @@ extern int ehca_debug_level;
} while (0)
/* define a bitmask, little endian version */
-#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+#define EHCA_BMASK(pos, length) (((pos) << 16) + (length))
/* define a bitmask, the ibm way... */
-#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+#define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
/* internal function, don't use */
-#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
/* internal function, don't use */
-#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+#define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff))
/**
* EHCA_BMASK_SET - return value shifted and masked by mask
@@ -145,30 +142,16 @@ extern int ehca_debug_level;
* variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
* in variable
*/
-#define EHCA_BMASK_SET(mask,value) \
- ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+#define EHCA_BMASK_SET(mask, value) \
+ ((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask))
/**
* EHCA_BMASK_GET - extract a parameter from value by mask
*/
-#define EHCA_BMASK_GET(mask,value) \
- (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
-
+#define EHCA_BMASK_GET(mask, value) \
+ (EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask)))
/* Converts ehca to ib return code */
-static inline int ehca2ib_return_code(u64 ehca_rc)
-{
- switch (ehca_rc) {
- case H_SUCCESS:
- return 0;
- case H_BUSY:
- return -EBUSY;
- case H_NO_MEM:
- return -ENOMEM;
- default:
- return -EINVAL;
- }
-}
-
+int ehca2ib_return_code(u64 ehca_rc);
#endif /* EHCA_TOOLS_H */
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 3031b3bb56f9..5234d6c15c49 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -70,7 +70,7 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
static void ehca_mm_open(struct vm_area_struct *vma)
{
- u32 *count = (u32*)vma->vm_private_data;
+ u32 *count = (u32 *)vma->vm_private_data;
if (!count) {
ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
vma->vm_start, vma->vm_end);
@@ -86,7 +86,7 @@ static void ehca_mm_open(struct vm_area_struct *vma)
static void ehca_mm_close(struct vm_area_struct *vma)
{
- u32 *count = (u32*)vma->vm_private_data;
+ u32 *count = (u32 *)vma->vm_private_data;
if (!count) {
ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
vma->vm_start, vma->vm_end);
@@ -109,7 +109,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
u64 vsize, physical;
vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
+ if (vsize < EHCA_PAGESIZE) {
ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
return -EINVAL;
}
@@ -118,10 +118,10 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
/* VM_IO | VM_RESERVED are set by remap_pfn_range() */
- ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
- vsize, vma->vm_page_prot);
+ ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
+ vma->vm_page_prot);
if (unlikely(ret)) {
- ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+ ehca_gen_err("remap_pfn_range() failed ret=%i", ret);
return -ENOMEM;
}
@@ -146,10 +146,10 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
page = virt_to_page(virt_addr);
ret = vm_insert_page(vma, start, page);
if (unlikely(ret)) {
- ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+ ehca_gen_err("vm_insert_page() failed rc=%i", ret);
return ret;
}
- start += PAGE_SIZE;
+ start += PAGE_SIZE;
}
vma->vm_private_data = mm_count;
(*mm_count)++;
@@ -164,23 +164,23 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
int ret;
switch (rsrc_type) {
- case 1: /* galpa fw handle */
+ case 0: /* galpa fw handle */
ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "ehca_mmap_fw() failed rc=%x cq_num=%x",
+ "ehca_mmap_fw() failed rc=%i cq_num=%x",
ret, cq->cq_number);
return ret;
}
break;
- case 2: /* cq queue_addr */
+ case 1: /* cq queue_addr */
ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "ehca_mmap_queue() failed rc=%x cq_num=%x",
+ "ehca_mmap_queue() failed rc=%i cq_num=%x",
ret, cq->cq_number);
return ret;
}
@@ -201,36 +201,38 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
int ret;
switch (rsrc_type) {
- case 1: /* galpa fw handle */
+ case 0: /* galpa fw handle */
ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "remap_pfn_range() failed ret=%x qp_num=%x",
+ "remap_pfn_range() failed ret=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return -ENOMEM;
}
break;
- case 2: /* qp rqueue_addr */
+ case 1: /* qp rqueue_addr */
ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
qp->ib_qp.qp_num);
- ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+ ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
+ &qp->mm_count_rqueue);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+ "ehca_mmap_queue(rq) failed rc=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return ret;
}
break;
- case 3: /* qp squeue_addr */
+ case 2: /* qp squeue_addr */
ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
qp->ib_qp.qp_num);
- ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+ ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
+ &qp->mm_count_squeue);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+ "ehca_mmap_queue(sq) failed rc=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return ret;
}
@@ -247,10 +249,10 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
- u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
- u32 idr_handle = fileoffset >> 32;
- u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
- u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u64 fileoffset = vma->vm_pgoff;
+ u32 idr_handle = fileoffset & 0x1FFFFFF;
+ u32 q_type = (fileoffset >> 27) & 0x1; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */
u32 cur_pid = current->tgid;
u32 ret;
struct ehca_cq *cq;
@@ -259,7 +261,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
struct ib_uobject *uobject;
switch (q_type) {
- case 1: /* CQ */
+ case 0: /* CQ */
read_lock(&ehca_cq_idr_lock);
cq = idr_find(&ehca_cq_idr, idr_handle);
read_unlock(&ehca_cq_idr_lock);
@@ -281,13 +283,13 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
ret = ehca_mmap_cq(vma, cq, rsrc_type);
if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "ehca_mmap_cq() failed rc=%x cq_num=%x",
+ "ehca_mmap_cq() failed rc=%i cq_num=%x",
ret, cq->cq_number);
return ret;
}
break;
- case 2: /* QP */
+ case 1: /* QP */
read_lock(&ehca_qp_idr_lock);
qp = idr_find(&ehca_qp_idr, idr_handle);
read_unlock(&ehca_qp_idr_lock);
@@ -311,7 +313,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
ret = ehca_mmap_qp(vma, qp, rsrc_type);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "ehca_mmap_qp() failed rc=%x qp_num=%x",
+ "ehca_mmap_qp() failed rc=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return ret;
}
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 4776a8b0feec..c16a21374bb5 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -52,10 +52,13 @@
#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11)
#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12)
#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_STORAGE EHCA_BMASK_IBM(16, 17)
#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18)
#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21)
#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23)
#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31)
+#define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35)
+#define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39)
#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63)
#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15)
@@ -81,6 +84,10 @@
#define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48)
#define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49)
+#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx"
+#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx"
+#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx"
+
static DEFINE_SPINLOCK(hcall_lock);
static u32 get_longbusy_msecs(int longbusy_rc)
@@ -113,16 +120,28 @@ static long ehca_plpar_hcall_norets(unsigned long opcode,
unsigned long arg7)
{
long ret;
- int i, sleep_msecs;
+ int i, sleep_msecs, do_lock;
+ unsigned long flags;
- ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
- "arg5=%lx arg6=%lx arg7=%lx",
+ ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT,
opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ /* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */
+ if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) {
+ arg7 = 0; /* better not upset firmware */
+ do_lock = 1;
+ }
+
for (i = 0; i < 5; i++) {
+ if (do_lock)
+ spin_lock_irqsave(&hcall_lock, flags);
+
ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
arg5, arg6, arg7);
+ if (do_lock)
+ spin_unlock_irqrestore(&hcall_lock, flags);
+
if (H_IS_LONG_BUSY(ret)) {
sleep_msecs = get_longbusy_msecs(ret);
msleep_interruptible(sleep_msecs);
@@ -130,16 +149,13 @@ static long ehca_plpar_hcall_norets(unsigned long opcode,
}
if (ret < H_SUCCESS)
- ehca_gen_err("opcode=%lx ret=%lx"
- " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
- " arg5=%lx arg6=%lx arg7=%lx ",
- opcode, ret,
- arg1, arg2, arg3, arg4, arg5,
- arg6, arg7);
-
- ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret);
- return ret;
+ ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT,
+ opcode, ret, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ else
+ ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret);
+ return ret;
}
return H_BUSY;
@@ -158,25 +174,24 @@ static long ehca_plpar_hcall9(unsigned long opcode,
unsigned long arg9)
{
long ret;
- int i, sleep_msecs, lock_is_set = 0;
+ int i, sleep_msecs, do_lock;
unsigned long flags = 0;
- ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
- "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
- opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9);
+ ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode,
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+
+ /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */
+ do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5));
for (i = 0; i < 5; i++) {
- if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) {
+ if (do_lock)
spin_lock_irqsave(&hcall_lock, flags);
- lock_is_set = 1;
- }
ret = plpar_hcall9(opcode, outs,
arg1, arg2, arg3, arg4, arg5,
arg6, arg7, arg8, arg9);
- if (lock_is_set)
+ if (do_lock)
spin_unlock_irqrestore(&hcall_lock, flags);
if (H_IS_LONG_BUSY(ret)) {
@@ -185,26 +200,19 @@ static long ehca_plpar_hcall9(unsigned long opcode,
continue;
}
- if (ret < H_SUCCESS)
- ehca_gen_err("opcode=%lx ret=%lx"
- " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
- " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
- " arg9=%lx"
- " out1=%lx out2=%lx out3=%lx out4=%lx"
- " out5=%lx out6=%lx out7=%lx out8=%lx"
- " out9=%lx",
- opcode, ret,
- arg1, arg2, arg3, arg4, arg5,
- arg6, arg7, arg8, arg9,
- outs[0], outs[1], outs[2], outs[3],
+ if (ret < H_SUCCESS) {
+ ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT,
+ opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9);
+ ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
+ ret, outs[0], outs[1], outs[2], outs[3],
+ outs[4], outs[5], outs[6], outs[7],
+ outs[8]);
+ } else
+ ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
+ ret, outs[0], outs[1], outs[2], outs[3],
outs[4], outs[5], outs[6], outs[7],
outs[8]);
-
- ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
- "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx "
- "out9=%lx",
- opcode, ret, outs[0], outs[1], outs[2], outs[3],
- outs[4], outs[5], outs[6], outs[7], outs[8]);
return ret;
}
@@ -244,7 +252,7 @@ u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
*eq_ist = (u32)outs[5];
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resource - ret=%lx ", ret);
+ ehca_gen_err("Not enough resource - ret=%li ", ret);
return ret;
}
@@ -282,7 +290,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%lx", ret);
+ ehca_gen_err("Not enough resources. ret=%li", ret);
return ret;
}
@@ -299,6 +307,11 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
| EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
| EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
| EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE,
+ parms->squeue.page_size)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE,
+ parms->rqueue.page_size)
| EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
!!(parms->ll_comp_flags & LLQP_RECV_COMP))
| EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
@@ -309,13 +322,13 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
max_r10_reg =
EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
- parms->max_send_wr + 1)
+ parms->squeue.max_wr + 1)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
- parms->max_recv_wr + 1)
+ parms->rqueue.max_wr + 1)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
- parms->max_send_sge)
+ parms->squeue.max_sge)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
- parms->max_recv_sge);
+ parms->rqueue.max_sge);
r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token);
@@ -335,24 +348,24 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
parms->qp_handle.handle = outs[0];
parms->real_qp_num = (u32)outs[1];
- parms->act_nr_send_wqes =
+ parms->squeue.act_nr_wqes =
(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
- parms->act_nr_recv_wqes =
+ parms->rqueue.act_nr_wqes =
(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
- parms->act_nr_send_sges =
+ parms->squeue.act_nr_sges =
(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
- parms->act_nr_recv_sges =
+ parms->rqueue.act_nr_sges =
(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
- parms->nr_sq_pages =
+ parms->squeue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
- parms->nr_rq_pages =
+ parms->rqueue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
if (ret == H_SUCCESS)
hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%lx", ret);
+ ehca_gen_err("Not enough resources. ret=%li", ret);
return ret;
}
@@ -427,7 +440,8 @@ u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
{
return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
adapter_handle.handle, /* r4 */
- queue_type | pagesize << 8, /* r5 */
+ (u64)queue_type | ((u64)pagesize) << 8,
+ /* r5 */
resource_handle, /* r6 */
logical_address_of_page, /* r7 */
count, /* r8 */
@@ -496,13 +510,13 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
const u64 count,
const struct h_galpa galpa)
{
- if (count != 1) {
+ if (count > 1) {
ehca_gen_err("Page counter=%lx", count);
return H_PARAMETER;
}
- return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
- qp_handle.handle,logical_address_of_page,
+ return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+ qp_handle.handle, logical_address_of_page,
count);
}
@@ -522,9 +536,9 @@ u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
qp_handle.handle, /* r6 */
0, 0, 0, 0, 0, 0);
if (log_addr_next_sq_wqe2processed)
- *log_addr_next_sq_wqe2processed = (void*)outs[0];
+ *log_addr_next_sq_wqe2processed = (void *)outs[0];
if (log_addr_next_rq_wqe2processed)
- *log_addr_next_rq_wqe2processed = (void*)outs[1];
+ *log_addr_next_rq_wqe2processed = (void *)outs[1];
return ret;
}
@@ -546,7 +560,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Insufficient resources ret=%lx", ret);
+ ehca_gen_err("Insufficient resources ret=%li", ret);
return ret;
}
@@ -582,7 +596,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
qp->ipz_qp_handle.handle, /* r6 */
0, 0, 0, 0, 0, 0);
if (ret == H_HARDWARE)
- ehca_gen_err("HCA not operational. ret=%lx", ret);
+ ehca_gen_err("HCA not operational. ret=%li", ret);
ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle.handle, /* r4 */
@@ -590,7 +604,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("Resource still in use. ret=%lx", ret);
+ ehca_gen_err("Resource still in use. ret=%li", ret);
return ret;
}
@@ -625,7 +639,7 @@ u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
*bma_qp_nr = (u32)outs[1];
if (ret == H_ALIAS_EXIST)
- ehca_gen_err("AQP1 already exists. ret=%lx", ret);
+ ehca_gen_err("AQP1 already exists. ret=%li", ret);
return ret;
}
@@ -647,7 +661,7 @@ u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
0, 0);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%lx", ret);
+ ehca_gen_err("Not enough resources. ret=%li", ret);
return ret;
}
@@ -686,7 +700,7 @@ u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret);
+ ehca_gen_err("H_FREE_RESOURCE failed ret=%li ", ret);
return ret;
}
@@ -708,7 +722,7 @@ u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("Resource in use. ret=%lx ", ret);
+ ehca_gen_err("Resource in use. ret=%li ", ret);
return ret;
}
@@ -724,6 +738,9 @@ u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
u64 ret;
u64 outs[PLPAR_HCALL9_BUFSIZE];
+ ehca_gen_dbg("kernel PAGE_SIZE=%x access_ctrl=%016x "
+ "vaddr=%lx length=%lx",
+ (u32)PAGE_SIZE, access_ctrl, vaddr, length);
ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
adapter_handle.handle, /* r4 */
5, /* r5 */
@@ -748,6 +765,19 @@ u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
{
u64 ret;
+ if (unlikely(ehca_debug_level >= 2)) {
+ if (count > 1) {
+ u64 *kpage;
+ int i;
+ kpage = (u64 *)abs_to_virt(logical_address_of_page);
+ for (i = 0; i < count; i++)
+ ehca_gen_dbg("kpage[%d]=%p",
+ i, (void *)kpage[i]);
+ } else
+ ehca_gen_dbg("kpage=%p",
+ (void *)logical_address_of_page);
+ }
+
if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
ehca_gen_err("logical_address_of_page not on a 4k boundary "
"adapter_handle=%lx mr=%p mr_handle=%lx "
@@ -791,7 +821,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle.handle, /* r4 */
mr->ipz_mr_handle.handle, /* r5 */
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 5);
}
u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c
index 0b1a4772c78a..214821095cb1 100644
--- a/drivers/infiniband/hw/ehca/hcp_phyp.c
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.c
@@ -50,7 +50,7 @@ int hcall_map_page(u64 physaddr, u64 *mapaddr)
int hcall_unmap_page(u64 mapaddr)
{
- iounmap((volatile void __iomem*)mapaddr);
+ iounmap((volatile void __iomem *) mapaddr);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h
index 20898a153446..868735fd3187 100644
--- a/drivers/infiniband/hw/ehca/hipz_fns_core.h
+++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h
@@ -53,10 +53,10 @@
#define hipz_galpa_load_cq(gal, offset) \
hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
-#define hipz_galpa_store_qp(gal,offset, value) \
+#define hipz_galpa_store_qp(gal, offset, value) \
hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
#define hipz_galpa_load_qp(gal, offset) \
- hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+ hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
{
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h
index dad6dea5636b..d9739e554515 100644
--- a/drivers/infiniband/hw/ehca/hipz_hw.h
+++ b/drivers/infiniband/hw/ehca/hipz_hw.h
@@ -161,11 +161,11 @@ struct hipz_qptemm {
/* 0x1000 */
};
-#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3,3)
+#define QPX_SQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3)
-#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x)
/* MRMWPT Entry Memory Map */
struct hipz_mrmwmm {
@@ -187,7 +187,7 @@ struct hipz_mrmwmm {
};
-#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x)
struct hipz_qpedmm {
/* 0x00 */
@@ -238,7 +238,7 @@ struct hipz_qpedmm {
u64 qpedx_rrva3;
};
-#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x)
/* CQ Table Entry Memory Map */
struct hipz_cqtemm {
@@ -263,12 +263,12 @@ struct hipz_cqtemm {
/* 0x1000 */
};
-#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63)
-#define CQX_FECADDER EHCA_BMASK_IBM(32,63)
-#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
-#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32, 63)
+#define CQX_FECADDER EHCA_BMASK_IBM(32, 63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0)
-#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x)
/* EQ Table Entry Memory Map */
struct hipz_eqtemm {
@@ -293,7 +293,7 @@ struct hipz_eqtemm {
};
-#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x)
/* access control defines for MR/MW */
#define HIPZ_ACCESSCTRL_L_WRITE 0x00800000
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
index bf7a40088f61..661f8db62706 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -40,6 +40,11 @@
#include "ehca_tools.h"
#include "ipz_pt_fn.h"
+#include "ehca_classes.h"
+
+#define PAGES_PER_KPAGE (PAGE_SIZE >> EHCA_PAGESHIFT)
+
+struct kmem_cache *small_qp_cache;
void *ipz_qpageit_get_inc(struct ipz_queue *queue)
{
@@ -49,7 +54,7 @@ void *ipz_qpageit_get_inc(struct ipz_queue *queue)
queue->current_q_offset -= queue->pagesize;
ret = NULL;
}
- if (((u64)ret) % EHCA_PAGESIZE) {
+ if (((u64)ret) % queue->pagesize) {
ehca_gen_err("ERROR!! not at PAGE-Boundary");
return NULL;
}
@@ -83,80 +88,196 @@ int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset)
return -EINVAL;
}
-int ipz_queue_ctor(struct ipz_queue *queue,
- const u32 nr_of_pages,
- const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
+#if PAGE_SHIFT < EHCA_PAGESHIFT
+#error Kernel pages must be at least as large than eHCA pages (4K) !
+#endif
+
+/*
+ * allocate pages for queue:
+ * outer loop allocates whole kernel pages (page aligned) and
+ * inner loop divides a kernel page into smaller hca queue pages
+ */
+static int alloc_queue_pages(struct ipz_queue *queue, const u32 nr_of_pages)
{
- int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
- int f;
+ int k, f = 0;
+ u8 *kpage;
- if (pagesize > PAGE_SIZE) {
- ehca_gen_err("FATAL ERROR: pagesize=%x is greater "
- "than kernel page size", pagesize);
- return 0;
- }
- if (!pages_per_kpage) {
- ehca_gen_err("FATAL ERROR: invalid kernel page size. "
- "pages_per_kpage=%x", pages_per_kpage);
- return 0;
- }
- queue->queue_length = nr_of_pages * pagesize;
- queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
- if (!queue->queue_pages) {
- ehca_gen_err("ERROR!! didn't get the memory");
- return 0;
- }
- memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
- /*
- * allocate pages for queue:
- * outer loop allocates whole kernel pages (page aligned) and
- * inner loop divides a kernel page into smaller hca queue pages
- */
- f = 0;
while (f < nr_of_pages) {
- u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
- int k;
+ kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
if (!kpage)
- goto ipz_queue_ctor_exit0; /*NOMEM*/
- for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) {
- (queue->queue_pages)[f] = (struct ipz_page *)kpage;
+ goto out;
+
+ for (k = 0; k < PAGES_PER_KPAGE && f < nr_of_pages; k++) {
+ queue->queue_pages[f] = (struct ipz_page *)kpage;
kpage += EHCA_PAGESIZE;
f++;
}
}
+ return 1;
- queue->current_q_offset = 0;
+out:
+ for (f = 0; f < nr_of_pages && queue->queue_pages[f];
+ f += PAGES_PER_KPAGE)
+ free_page((unsigned long)(queue->queue_pages)[f]);
+ return 0;
+}
+
+static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+ int order = ilog2(queue->pagesize) - 9;
+ struct ipz_small_queue_page *page;
+ unsigned long bit;
+
+ mutex_lock(&pd->lock);
+
+ if (!list_empty(&pd->free[order]))
+ page = list_entry(pd->free[order].next,
+ struct ipz_small_queue_page, list);
+ else {
+ page = kmem_cache_zalloc(small_qp_cache, GFP_KERNEL);
+ if (!page)
+ goto out;
+
+ page->page = get_zeroed_page(GFP_KERNEL);
+ if (!page->page) {
+ kmem_cache_free(small_qp_cache, page);
+ goto out;
+ }
+
+ list_add(&page->list, &pd->free[order]);
+ }
+
+ bit = find_first_zero_bit(page->bitmap, IPZ_SPAGE_PER_KPAGE >> order);
+ __set_bit(bit, page->bitmap);
+ page->fill++;
+
+ if (page->fill == IPZ_SPAGE_PER_KPAGE >> order)
+ list_move(&page->list, &pd->full[order]);
+
+ mutex_unlock(&pd->lock);
+
+ queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9)));
+ queue->small_page = page;
+ queue->offset = bit << (order + 9);
+ return 1;
+
+out:
+ ehca_err(pd->ib_pd.device, "failed to allocate small queue page");
+ return 0;
+}
+
+static void free_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+ int order = ilog2(queue->pagesize) - 9;
+ struct ipz_small_queue_page *page = queue->small_page;
+ unsigned long bit;
+ int free_page = 0;
+
+ bit = ((unsigned long)queue->queue_pages[0] & ~PAGE_MASK)
+ >> (order + 9);
+
+ mutex_lock(&pd->lock);
+
+ __clear_bit(bit, page->bitmap);
+ page->fill--;
+
+ if (page->fill == 0) {
+ list_del(&page->list);
+ free_page = 1;
+ }
+
+ if (page->fill == (IPZ_SPAGE_PER_KPAGE >> order) - 1)
+ /* the page was full until we freed the chunk */
+ list_move_tail(&page->list, &pd->free[order]);
+
+ mutex_unlock(&pd->lock);
+
+ if (free_page) {
+ free_page(page->page);
+ kmem_cache_free(small_qp_cache, page);
+ }
+}
+
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+ const u32 nr_of_pages, const u32 pagesize,
+ const u32 qe_size, const u32 nr_of_sg,
+ int is_small)
+{
+ if (pagesize > PAGE_SIZE) {
+ ehca_gen_err("FATAL ERROR: pagesize=%x "
+ "is greater than kernel page size", pagesize);
+ return 0;
+ }
+
+ /* init queue fields */
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->pagesize = pagesize;
queue->qe_size = qe_size;
queue->act_nr_of_sg = nr_of_sg;
- queue->pagesize = pagesize;
+ queue->current_q_offset = 0;
queue->toggle_state = 1;
- return 1;
+ queue->small_page = NULL;
- ipz_queue_ctor_exit0:
- ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
- queue, f, nr_of_pages);
- for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
- if (!(queue->queue_pages)[f])
- break;
- free_page((unsigned long)(queue->queue_pages)[f]);
+ /* allocate queue page pointers */
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ ehca_gen_err("Couldn't allocate queue page list");
+ return 0;
}
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+
+ /* allocate actual queue pages */
+ if (is_small) {
+ if (!alloc_small_queue_page(queue, pd))
+ goto ipz_queue_ctor_exit0;
+ } else
+ if (!alloc_queue_pages(queue, nr_of_pages))
+ goto ipz_queue_ctor_exit0;
+
+ return 1;
+
+ipz_queue_ctor_exit0:
+ ehca_gen_err("Couldn't alloc pages queue=%p "
+ "nr_of_pages=%x", queue, nr_of_pages);
+ vfree(queue->queue_pages);
+
return 0;
}
-int ipz_queue_dtor(struct ipz_queue *queue)
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue)
{
- int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
- int g;
- int nr_pages;
+ int i, nr_pages;
if (!queue || !queue->queue_pages) {
ehca_gen_dbg("queue or queue_pages is NULL");
return 0;
}
- nr_pages = queue->queue_length / queue->pagesize;
- for (g = 0; g < nr_pages; g += pages_per_kpage)
- free_page((unsigned long)(queue->queue_pages)[g]);
+
+ if (queue->small_page)
+ free_small_queue_page(queue, pd);
+ else {
+ nr_pages = queue->queue_length / queue->pagesize;
+ for (i = 0; i < nr_pages; i += PAGES_PER_KPAGE)
+ free_page((unsigned long)queue->queue_pages[i]);
+ }
+
vfree(queue->queue_pages);
return 1;
}
+
+int ehca_init_small_qp_cache(void)
+{
+ small_qp_cache = kmem_cache_create("ehca_cache_small_qp",
+ sizeof(struct ipz_small_queue_page),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!small_qp_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ehca_cleanup_small_qp_cache(void)
+{
+ kmem_cache_destroy(small_qp_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index 007f0882fd40..a801274ea337 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -51,11 +51,27 @@
#include "ehca_tools.h"
#include "ehca_qes.h"
+struct ehca_pd;
+struct ipz_small_queue_page;
+
+extern struct kmem_cache *small_qp_cache;
+
/* struct generic ehca page */
struct ipz_page {
u8 entries[EHCA_PAGESIZE];
};
+#define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512)
+
+struct ipz_small_queue_page {
+ unsigned long page;
+ unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG];
+ int fill;
+ void *mapped_addr;
+ u32 mmap_count;
+ struct list_head list;
+};
+
/* struct generic queue in linux kernel virtual memory (kv) */
struct ipz_queue {
u64 current_q_offset; /* current queue entry */
@@ -66,7 +82,8 @@ struct ipz_queue {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state; /* toggle flag - per page */
- u32 dummy3; /* 64 bit alignment */
+ u32 offset; /* save offset within page for small_qp */
+ struct ipz_small_queue_page *small_page;
};
/*
@@ -188,9 +205,10 @@ struct ipz_qpt {
* see ipz_qpt_ctor()
* returns true if ok, false if out of memory
*/
-int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
- const u32 pagesize, const u32 qe_size,
- const u32 nr_of_sg);
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+ const u32 nr_of_pages, const u32 pagesize,
+ const u32 qe_size, const u32 nr_of_sg,
+ int is_small);
/*
* destructor for a ipz_queue_t
@@ -198,7 +216,7 @@ int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
* see ipz_queue_ctor()
* returns true if ok, false if queue was NULL-ptr of free failed
*/
-int ipz_queue_dtor(struct ipz_queue *queue);
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue);
/*
* constructor for a ipz_qpt_t,
@@ -240,7 +258,7 @@ void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
{
void *ret = ipz_qeit_get(queue);
- u32 qe = *(u8 *) ret;
+ u32 qe = *(u8 *)ret;
if ((qe >> 7) != (queue->toggle_state & 1))
return NULL;
ipz_qeit_eq_get_inc(queue); /* this is a good one */
@@ -250,7 +268,7 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
{
void *ret = ipz_qeit_get(queue);
- u32 qe = *(u8 *) ret;
+ u32 qe = *(u8 *)ret;
if ((qe >> 7) != (queue->toggle_state & 1))
return NULL;
return ret;
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index ec2e603ea241..fe6738826865 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -14,7 +14,6 @@ ib_ipath-y := \
ipath_init_chip.o \
ipath_intr.o \
ipath_keys.o \
- ipath_layer.o \
ipath_mad.o \
ipath_mmap.o \
ipath_mr.o \
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index b4b786d0dfca..851df8a75e79 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -100,8 +100,7 @@ struct infinipath_stats {
__u64 sps_hwerrs;
/* number of times IB link changed state unexpectedly */
__u64 sps_iblink;
- /* kernel receive interrupts that didn't read intstat */
- __u64 sps_fastrcvint;
+ __u64 sps_unused; /* was fastrcvint, no longer implemented */
/* number of kernel (port0) packets received */
__u64 sps_port0pkts;
/* number of "ethernet" packets sent by driver */
@@ -190,6 +189,8 @@ typedef enum _ipath_ureg {
#define IPATH_RUNTIME_RCVHDR_COPY 0x8
#define IPATH_RUNTIME_MASTER 0x10
/* 0x20 and 0x40 are no longer used, but are reserved for ABI compatibility */
+#define IPATH_RUNTIME_FORCE_PIOAVAIL 0x400
+#define IPATH_RUNTIME_PIO_REGSWAPPED 0x800
/*
* This structure is returned by ipath_userinit() immediately after
@@ -351,7 +352,7 @@ struct ipath_base_info {
* may not be implemented; the user code must deal with this if it
* cares, or it must abort after initialization reports the difference.
*/
-#define IPATH_USER_SWMINOR 5
+#define IPATH_USER_SWMINOR 6
#define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index a6f04d27ec57..645ed71fd797 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -76,22 +76,25 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
}
return;
}
- wc->queue[head].wr_id = entry->wr_id;
- wc->queue[head].status = entry->status;
- wc->queue[head].opcode = entry->opcode;
- wc->queue[head].vendor_err = entry->vendor_err;
- wc->queue[head].byte_len = entry->byte_len;
- wc->queue[head].imm_data = (__u32 __force)entry->imm_data;
- wc->queue[head].qp_num = entry->qp->qp_num;
- wc->queue[head].src_qp = entry->src_qp;
- wc->queue[head].wc_flags = entry->wc_flags;
- wc->queue[head].pkey_index = entry->pkey_index;
- wc->queue[head].slid = entry->slid;
- wc->queue[head].sl = entry->sl;
- wc->queue[head].dlid_path_bits = entry->dlid_path_bits;
- wc->queue[head].port_num = entry->port_num;
- /* Make sure queue entry is written before the head index. */
- smp_wmb();
+ if (cq->ip) {
+ wc->uqueue[head].wr_id = entry->wr_id;
+ wc->uqueue[head].status = entry->status;
+ wc->uqueue[head].opcode = entry->opcode;
+ wc->uqueue[head].vendor_err = entry->vendor_err;
+ wc->uqueue[head].byte_len = entry->byte_len;
+ wc->uqueue[head].imm_data = (__u32 __force)entry->imm_data;
+ wc->uqueue[head].qp_num = entry->qp->qp_num;
+ wc->uqueue[head].src_qp = entry->src_qp;
+ wc->uqueue[head].wc_flags = entry->wc_flags;
+ wc->uqueue[head].pkey_index = entry->pkey_index;
+ wc->uqueue[head].slid = entry->slid;
+ wc->uqueue[head].sl = entry->sl;
+ wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
+ wc->uqueue[head].port_num = entry->port_num;
+ /* Make sure entry is written before the head index. */
+ smp_wmb();
+ } else
+ wc->kqueue[head] = *entry;
wc->head = next;
if (cq->notify == IB_CQ_NEXT_COMP ||
@@ -130,6 +133,12 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
int npolled;
u32 tail;
+ /* The kernel can only poll a kernel completion queue */
+ if (cq->ip) {
+ npolled = -EINVAL;
+ goto bail;
+ }
+
spin_lock_irqsave(&cq->lock, flags);
wc = cq->queue;
@@ -137,31 +146,10 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
if (tail > (u32) cq->ibcq.cqe)
tail = (u32) cq->ibcq.cqe;
for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
- struct ipath_qp *qp;
-
if (tail == wc->head)
break;
- /* Make sure entry is read after head index is read. */
- smp_rmb();
- qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table,
- wc->queue[tail].qp_num);
- entry->qp = &qp->ibqp;
- if (atomic_dec_and_test(&qp->refcount))
- wake_up(&qp->wait);
-
- entry->wr_id = wc->queue[tail].wr_id;
- entry->status = wc->queue[tail].status;
- entry->opcode = wc->queue[tail].opcode;
- entry->vendor_err = wc->queue[tail].vendor_err;
- entry->byte_len = wc->queue[tail].byte_len;
- entry->imm_data = wc->queue[tail].imm_data;
- entry->src_qp = wc->queue[tail].src_qp;
- entry->wc_flags = wc->queue[tail].wc_flags;
- entry->pkey_index = wc->queue[tail].pkey_index;
- entry->slid = wc->queue[tail].slid;
- entry->sl = wc->queue[tail].sl;
- entry->dlid_path_bits = wc->queue[tail].dlid_path_bits;
- entry->port_num = wc->queue[tail].port_num;
+ /* The kernel doesn't need a RMB since it has the lock. */
+ *entry = wc->kqueue[tail];
if (tail >= cq->ibcq.cqe)
tail = 0;
else
@@ -171,6 +159,7 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
spin_unlock_irqrestore(&cq->lock, flags);
+bail:
return npolled;
}
@@ -215,6 +204,7 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
struct ipath_cq *cq;
struct ipath_cq_wc *wc;
struct ib_cq *ret;
+ u32 sz;
if (entries < 1 || entries > ib_ipath_max_cqes) {
ret = ERR_PTR(-EINVAL);
@@ -235,7 +225,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
* We need to use vmalloc() in order to support mmap and large
* numbers of entries.
*/
- wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries);
+ sz = sizeof(*wc);
+ if (udata && udata->outlen >= sizeof(__u64))
+ sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
+ else
+ sz += sizeof(struct ib_wc) * (entries + 1);
+ wc = vmalloc_user(sz);
if (!wc) {
ret = ERR_PTR(-ENOMEM);
goto bail_cq;
@@ -247,9 +242,8 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
*/
if (udata && udata->outlen >= sizeof(__u64)) {
int err;
- u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
- cq->ip = ipath_create_mmap_info(dev, s, context, wc);
+ cq->ip = ipath_create_mmap_info(dev, sz, context, wc);
if (!cq->ip) {
ret = ERR_PTR(-ENOMEM);
goto bail_wc;
@@ -380,6 +374,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
struct ipath_cq_wc *wc;
u32 head, tail, n;
int ret;
+ u32 sz;
if (cqe < 1 || cqe > ib_ipath_max_cqes) {
ret = -EINVAL;
@@ -389,7 +384,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
/*
* Need to use vmalloc() if we want to support large #s of entries.
*/
- wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe);
+ sz = sizeof(*wc);
+ if (udata && udata->outlen >= sizeof(__u64))
+ sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
+ else
+ sz += sizeof(struct ib_wc) * (cqe + 1);
+ wc = vmalloc_user(sz);
if (!wc) {
ret = -ENOMEM;
goto bail;
@@ -430,7 +430,10 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
goto bail;
}
for (n = 0; tail != head; n++) {
- wc->queue[n] = old_wc->queue[tail];
+ if (cq->ip)
+ wc->uqueue[n] = old_wc->uqueue[tail];
+ else
+ wc->kqueue[n] = old_wc->kqueue[tail];
if (tail == (u32) cq->ibcq.cqe)
tail = 0;
else
@@ -447,9 +450,8 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
if (cq->ip) {
struct ipath_ibdev *dev = to_idev(ibcq->device);
struct ipath_mmap_info *ip = cq->ip;
- u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
- ipath_update_mmap_info(dev, ip, s, wc);
+ ipath_update_mmap_info(dev, ip, sz, wc);
spin_lock_irq(&dev->pending_lock);
if (list_empty(&ip->pending_mmaps))
list_add(&ip->pending_mmaps, &dev->pending_mmaps);
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index a698f1949d10..4137c7770f1b 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -44,6 +44,7 @@
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
+#include <linux/fs.h>
#include <asm/uaccess.h>
#include "ipath_kernel.h"
@@ -445,19 +446,21 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
dd->ipath_unit, plen - 1, pbufn);
if (dp.pbc_wd == 0)
- /* Legacy operation, use computed pbc_wd */
dp.pbc_wd = plen;
-
- /* we have to flush after the PBC for correctness on some cpus
- * or WC buffer can be written out of order */
writeq(dp.pbc_wd, piobuf);
- ipath_flush_wc();
- /* copy all by the trigger word, then flush, so it's written
+ /*
+ * Copy all by the trigger word, then flush, so it's written
* to chip before trigger word, then write trigger word, then
- * flush again, so packet is sent. */
- __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
- ipath_flush_wc();
- __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ * flush again, so packet is sent.
+ */
+ if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
+ ipath_flush_wc();
+ __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
+ ipath_flush_wc();
+ __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ } else
+ __iowrite32_copy(piobuf + 2, tmpbuf, clen);
+
ipath_flush_wc();
ret = sizeof(dp);
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 9361f5ab8bd6..1f152ded1e3c 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -34,6 +34,7 @@
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/pci.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
@@ -280,6 +281,89 @@ void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd)
{
}
+/*
+ * Perform a PIO buffer bandwidth write test, to verify proper system
+ * configuration. Even when all the setup calls work, occasionally
+ * BIOS or other issues can prevent write combining from working, or
+ * can cause other bandwidth problems to the chip.
+ *
+ * This test simply writes the same buffer over and over again, and
+ * measures close to the peak bandwidth to the chip (not testing
+ * data bandwidth to the wire). On chips that use an address-based
+ * trigger to send packets to the wire, this is easy. On chips that
+ * use a count to trigger, we want to make sure that the packet doesn't
+ * go out on the wire, or trigger flow control checks.
+ */
+static void ipath_verify_pioperf(struct ipath_devdata *dd)
+{
+ u32 pbnum, cnt, lcnt;
+ u32 __iomem *piobuf;
+ u32 *addr;
+ u64 msecs, emsecs;
+
+ piobuf = ipath_getpiobuf(dd, &pbnum);
+ if (!piobuf) {
+ dev_info(&dd->pcidev->dev,
+ "No PIObufs for checking perf, skipping\n");
+ return;
+ }
+
+ /*
+ * Enough to give us a reasonable test, less than piobuf size, and
+ * likely multiple of store buffer length.
+ */
+ cnt = 1024;
+
+ addr = vmalloc(cnt);
+ if (!addr) {
+ dev_info(&dd->pcidev->dev,
+ "Couldn't get memory for checking PIO perf,"
+ " skipping\n");
+ goto done;
+ }
+
+ preempt_disable(); /* we want reasonably accurate elapsed time */
+ msecs = 1 + jiffies_to_msecs(jiffies);
+ for (lcnt = 0; lcnt < 10000U; lcnt++) {
+ /* wait until we cross msec boundary */
+ if (jiffies_to_msecs(jiffies) >= msecs)
+ break;
+ udelay(1);
+ }
+
+ writeq(0, piobuf); /* length 0, no dwords actually sent */
+ ipath_flush_wc();
+
+ /*
+ * this is only roughly accurate, since even with preempt we
+ * still take interrupts that could take a while. Running for
+ * >= 5 msec seems to get us "close enough" to accurate values
+ */
+ msecs = jiffies_to_msecs(jiffies);
+ for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) {
+ __iowrite32_copy(piobuf + 64, addr, cnt >> 2);
+ emsecs = jiffies_to_msecs(jiffies) - msecs;
+ }
+
+ /* 1 GiB/sec, slightly over IB SDR line rate */
+ if (lcnt < (emsecs * 1024U))
+ ipath_dev_err(dd,
+ "Performance problem: bandwidth to PIO buffers is "
+ "only %u MiB/sec\n",
+ lcnt / (u32) emsecs);
+ else
+ ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n",
+ lcnt / (u32) emsecs);
+
+ preempt_enable();
+
+ vfree(addr);
+
+done:
+ /* disarm piobuf, so it's available again */
+ ipath_disarm_piobufs(dd, pbnum, 1);
+}
+
static int __devinit ipath_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -298,8 +382,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit);
- read_bars(dd, pdev, &bar0, &bar1);
-
ret = pci_enable_device(pdev);
if (ret) {
/* This can happen iff:
@@ -445,9 +527,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
goto bail_regions;
}
- dd->ipath_deviceid = ent->device; /* save for later use */
- dd->ipath_vendorid = ent->vendor;
-
dd->ipath_pcirev = pdev->revision;
#if defined(__powerpc__)
@@ -515,6 +594,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ret = 0;
}
+ ipath_verify_pioperf(dd);
+
ipath_device_create_group(&pdev->dev, dd);
ipathfs_add_device(dd);
ipath_user_add(dd);
@@ -740,7 +821,7 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
* pioavail updates to memory to stop.
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- sendorig & ~IPATH_S_PIOBUFAVAILUPD);
+ sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
@@ -1614,7 +1695,7 @@ int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
* it's safer to always do it.
* PIOAvail bits are updated by the chip as if normal send had happened.
*/
-void ipath_cancel_sends(struct ipath_devdata *dd)
+void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
{
ipath_dbg("Cancelling all in-progress send buffers\n");
dd->ipath_lastcancel = jiffies+HZ/2; /* skip armlaunch errs a bit */
@@ -1627,6 +1708,9 @@ void ipath_cancel_sends(struct ipath_devdata *dd)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_disarm_piobufs(dd, 0,
(unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k));
+ if (restore_sendctrl) /* else done by caller later */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ dd->ipath_sendctrl);
/* and again, be sure all have hit the chip */
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
@@ -1655,7 +1739,7 @@ static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
/* flush all queued sends when going to DOWN or INIT, to be sure that
* they don't block MAD packets */
if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT)
- ipath_cancel_sends(dd);
+ ipath_cancel_sends(dd, 1);
ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
dd->ipath_ibcctrl | which);
@@ -1889,7 +1973,7 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
/* Below is "non-zero" to force override, but both actual LEDs are off */
#define LED_OVER_BOTH_OFF (8)
-void ipath_run_led_override(unsigned long opaque)
+static void ipath_run_led_override(unsigned long opaque)
{
struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
int timeoff;
@@ -2000,7 +2084,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
INFINIPATH_IBCC_LINKINITCMD_SHIFT);
- ipath_cancel_sends(dd);
+ ipath_cancel_sends(dd, 0);
+
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
/* disable IBC */
dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index 6b9147964a4f..bcfa3ccb555f 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -426,8 +426,8 @@ bail:
* @buffer: data to write
* @len: number of bytes to write
*/
-int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
- const void *buffer, int len)
+static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
+ const void *buffer, int len)
{
u8 single_byte;
int sub_len;
@@ -596,7 +596,11 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
goto bail;
}
- len = offsetof(struct ipath_flash, if_future);
+ /*
+ * read full flash, not just currently used part, since it may have
+ * been written with a newer definition
+ * */
+ len = sizeof(struct ipath_flash);
buf = vmalloc(len);
if (!buf) {
ipath_dev_err(dd, "Couldn't allocate memory to read %u "
@@ -737,8 +741,10 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
/*
* The quick-check above determined that there is something worthy
* of logging, so get current contents and do a more detailed idea.
+ * read full flash, not just currently used part, since it may have
+ * been written with a newer definition
*/
- len = offsetof(struct ipath_flash, if_future);
+ len = sizeof(struct ipath_flash);
buf = vmalloc(len);
ret = 1;
if (!buf) {
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 33ab0d6b80ff..5de3243a47c3 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -538,6 +538,9 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
continue;
cnt++;
if (dd->ipath_pageshadow[porttid + tid]) {
+ struct page *p;
+ 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);
dd->ipath_f_put_tid(dd, &tidbase[tid],
@@ -546,9 +549,7 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
pci_unmap_page(dd->pcidev,
dd->ipath_physshadow[porttid + tid],
PAGE_SIZE, PCI_DMA_FROMDEVICE);
- ipath_release_user_pages(
- &dd->ipath_pageshadow[porttid + tid], 1);
- dd->ipath_pageshadow[porttid + tid] = NULL;
+ ipath_release_user_pages(&p, 1);
ipath_stats.sps_pageunlocks++;
} else
ipath_dbg("Unused tid %u, ignoring\n", tid);
@@ -1341,6 +1342,19 @@ bail:
return ret;
}
+static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd)
+{
+ unsigned pollflag = 0;
+
+ if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) &&
+ pd->port_hdrqfull != pd->port_hdrqfull_poll) {
+ pollflag |= POLLIN | POLLRDNORM;
+ pd->port_hdrqfull_poll = pd->port_hdrqfull;
+ }
+
+ return pollflag;
+}
+
static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
struct file *fp,
struct poll_table_struct *pt)
@@ -1350,22 +1364,20 @@ static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
dd = pd->port_dd;
- if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
- pollflag |= POLLERR;
- clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
- }
+ /* variable access in ipath_poll_hdrqfull() needs this */
+ rmb();
+ pollflag = ipath_poll_hdrqfull(pd);
- if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) {
+ if (pd->port_urgent != pd->port_urgent_poll) {
pollflag |= POLLIN | POLLRDNORM;
- clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag);
+ pd->port_urgent_poll = pd->port_urgent;
}
if (!pollflag) {
+ /* this saves a spin_lock/unlock in interrupt handler... */
set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
- if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
- set_bit(IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag);
-
+ /* flush waiting flag so don't miss an event... */
+ wmb();
poll_wait(fp, &pd->port_wait, pt);
}
@@ -1376,31 +1388,27 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
struct file *fp,
struct poll_table_struct *pt)
{
- u32 head, tail;
+ u32 head;
+ u32 tail;
unsigned pollflag = 0;
struct ipath_devdata *dd;
dd = pd->port_dd;
+ /* variable access in ipath_poll_hdrqfull() needs this */
+ rmb();
+ pollflag = ipath_poll_hdrqfull(pd);
+
head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
- if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
- pollflag |= POLLERR;
- clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
- }
-
- if (tail != head ||
- test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) {
+ if (head != tail)
pollflag |= POLLIN | POLLRDNORM;
- clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag);
- }
-
- if (!pollflag) {
+ else {
+ /* this saves a spin_lock/unlock in interrupt handler */
set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
- if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
- set_bit(IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag);
+ /* flush waiting flag so we don't miss an event */
+ wmb();
set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
&dd->ipath_rcvctrl);
@@ -1917,6 +1925,12 @@ static int ipath_do_user_init(struct file *fp,
ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
pd->port_port, head32);
pd->port_tidcursor = 0; /* start at beginning after open */
+
+ /* initialize poll variables... */
+ pd->port_urgent = 0;
+ pd->port_urgent_poll = 0;
+ pd->port_hdrqfull_poll = pd->port_hdrqfull;
+
/*
* now enable the port; the tail registers will be written to memory
* by the chip as soon as it sees the write to
@@ -2039,9 +2053,11 @@ static int ipath_close(struct inode *in, struct file *fp)
if (dd->ipath_kregbase) {
int i;
- /* atomically clear receive enable port. */
+ /* atomically clear receive enable port and intr avail. */
clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
&dd->ipath_rcvctrl);
+ clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+ &dd->ipath_rcvctrl);
ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
/* and read back from chip to be sure that nothing
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 2e689b974e1f..262c25db05cd 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -130,175 +130,6 @@ static const struct file_operations atomic_counters_ops = {
.read = atomic_counters_read,
};
-static ssize_t atomic_node_info_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- u32 nodeinfo[10];
- struct ipath_devdata *dd;
- u64 guid;
-
- dd = file->f_path.dentry->d_inode->i_private;
-
- guid = be64_to_cpu(dd->ipath_guid);
-
- nodeinfo[0] = /* BaseVersion is SMA */
- /* ClassVersion is SMA */
- (1 << 8) /* NodeType */
- | (1 << 0); /* NumPorts */
- nodeinfo[1] = (u32) (guid >> 32);
- nodeinfo[2] = (u32) (guid & 0xffffffff);
- /* PortGUID == SystemImageGUID for us */
- nodeinfo[3] = nodeinfo[1];
- /* PortGUID == SystemImageGUID for us */
- nodeinfo[4] = nodeinfo[2];
- /* PortGUID == NodeGUID for us */
- nodeinfo[5] = nodeinfo[3];
- /* PortGUID == NodeGUID for us */
- nodeinfo[6] = nodeinfo[4];
- nodeinfo[7] = (4 << 16) /* we support 4 pkeys */
- | (dd->ipath_deviceid << 0);
- /* our chip version as 16 bits major, 16 bits minor */
- nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16);
- nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0);
-
- return simple_read_from_buffer(buf, count, ppos, nodeinfo,
- sizeof nodeinfo);
-}
-
-static const struct file_operations atomic_node_info_ops = {
- .read = atomic_node_info_read,
-};
-
-static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- u32 portinfo[13];
- u32 tmp, tmp2;
- struct ipath_devdata *dd;
-
- dd = file->f_path.dentry->d_inode->i_private;
-
- /* so we only initialize non-zero fields. */
- memset(portinfo, 0, sizeof portinfo);
-
- /*
- * Notimpl yet M_Key (64)
- * Notimpl yet GID (64)
- */
-
- portinfo[4] = (dd->ipath_lid << 16);
-
- /*
- * Notimpl yet SMLID.
- * CapabilityMask is 0, we don't support any of these
- * DiagCode is 0; we don't store any diag info for now Notimpl yet
- * M_KeyLeasePeriod (we don't support M_Key)
- */
-
- /* LocalPortNum is whichever port number they ask for */
- portinfo[7] = (dd->ipath_unit << 24)
- /* LinkWidthEnabled */
- | (2 << 16)
- /* LinkWidthSupported (really 2, but not IB valid) */
- | (3 << 8)
- /* LinkWidthActive */
- | (2 << 0);
- tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
- tmp2 = 5;
- if (tmp == IPATH_IBSTATE_INIT)
- tmp = 2;
- else if (tmp == IPATH_IBSTATE_ARM)
- tmp = 3;
- else if (tmp == IPATH_IBSTATE_ACTIVE)
- tmp = 4;
- else {
- tmp = 0; /* down */
- tmp2 = tmp & 0xf;
- }
-
- portinfo[8] = (1 << 28) /* LinkSpeedSupported */
- | (tmp << 24) /* PortState */
- | (tmp2 << 20) /* PortPhysicalState */
- | (2 << 16)
-
- /* LinkDownDefaultState */
- /* M_KeyProtectBits == 0 */
- /* NotImpl yet LMC == 0 (we can support all values) */
- | (1 << 4) /* LinkSpeedActive */
- | (1 << 0); /* LinkSpeedEnabled */
- switch (dd->ipath_ibmtu) {
- case 4096:
- tmp = 5;
- break;
- case 2048:
- tmp = 4;
- break;
- case 1024:
- tmp = 3;
- break;
- case 512:
- tmp = 2;
- break;
- case 256:
- tmp = 1;
- break;
- default: /* oops, something is wrong */
- ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, "
- "treat as 2048\n", dd->ipath_ibmtu);
- tmp = 4;
- break;
- }
- portinfo[9] = (tmp << 28)
- /* NeighborMTU */
- /* Notimpl MasterSMSL */
- | (1 << 20)
-
- /* VLCap */
- /* Notimpl InitType (actually, an SMA decision) */
- /* VLHighLimit is 0 (only one VL) */
- ; /* VLArbitrationHighCap is 0 (only one VL) */
- /*
- * Note: the chips support a maximum MTU of 4096, but the driver
- * hasn't implemented this feature yet, so set the maximum
- * to 2048.
- */
- portinfo[10] = /* VLArbitrationLowCap is 0 (only one VL) */
- /* InitTypeReply is SMA decision */
- (4 << 16) /* MTUCap 2048 */
- | (7 << 13) /* VLStallCount */
- | (0x1f << 8) /* HOQLife */
- | (1 << 4)
-
- /* OperationalVLs 0 */
- /* PartitionEnforcementInbound */
- /* PartitionEnforcementOutbound not enforced */
- /* FilterRawinbound not enforced */
- ; /* FilterRawOutbound not enforced */
- /* M_KeyViolations are not counted by hardware, SMA can count */
- tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
- /* P_KeyViolations are counted by hardware. */
- portinfo[11] = ((tmp & 0xffff) << 0);
- portinfo[12] =
- /* Q_KeyViolations are not counted by hardware */
- (1 << 8)
-
- /* GUIDCap */
- /* SubnetTimeOut handled by SMA */
- /* RespTimeValue handled by SMA */
- ;
- /* LocalPhyErrors are programmed to max */
- portinfo[12] |= (0xf << 20)
- | (0xf << 16) /* OverRunErrors are programmed to max */
- ;
-
- return simple_read_from_buffer(buf, count, ppos, portinfo,
- sizeof portinfo);
-}
-
-static const struct file_operations atomic_port_info_ops = {
- .read = atomic_port_info_read,
-};
-
static ssize_t flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -427,22 +258,6 @@ static int create_device_files(struct super_block *sb,
goto bail;
}
- ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp,
- &atomic_node_info_ops, dd);
- if (ret) {
- printk(KERN_ERR "create_file(%s/node_info) "
- "failed: %d\n", unit, ret);
- goto bail;
- }
-
- ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp,
- &atomic_port_info_ops, dd);
- if (ret) {
- printk(KERN_ERR "create_file(%s/port_info) "
- "failed: %d\n", unit, ret);
- goto bail;
- }
-
ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,
&flash_ops, dd);
if (ret) {
@@ -508,8 +323,6 @@ static int remove_device_files(struct super_block *sb,
}
remove_file(dir, "flash");
- remove_file(dir, "port_info");
- remove_file(dir, "node_info");
remove_file(dir, "atomic_counters");
d_delete(dir);
ret = simple_rmdir(root->d_inode, dir);
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 650745d83fac..ddbebe4bdb27 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -631,56 +631,35 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
{
char *n = NULL;
u8 boardrev = dd->ipath_boardrev;
- int ret;
+ int ret = 0;
switch (boardrev) {
- case 4: /* Ponderosa is one of the bringup boards */
- n = "Ponderosa";
- break;
case 5:
/*
* original production board; two production levels, with
* different serial number ranges. See ipath_ht_early_init() for
* case where we enable IPATH_GPIO_INTR for later serial # range.
+ * Original 112* serial number is no longer supported.
*/
n = "InfiniPath_QHT7040";
break;
- case 6:
- n = "OEM_Board_3";
- break;
case 7:
/* small form factor production board */
n = "InfiniPath_QHT7140";
break;
- case 8:
- n = "LS/X-1";
- break;
- case 9: /* Comstock bringup test board */
- n = "Comstock";
- break;
- case 10:
- n = "OEM_Board_2";
- break;
- case 11:
- n = "InfiniPath_HT-470"; /* obsoleted */
- break;
- case 12:
- n = "OEM_Board_4";
- break;
default: /* don't know, just print the number */
ipath_dev_err(dd, "Don't yet know about board "
"with ID %u\n", boardrev);
snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
boardrev);
+ ret = 1;
break;
}
if (n)
snprintf(name, namelen, "%s", n);
- if (dd->ipath_boardrev != 6 && dd->ipath_boardrev != 7 &&
- dd->ipath_boardrev != 11) {
+ if (ret) {
ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name);
- ret = 1;
goto bail;
}
if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 ||
@@ -1554,10 +1533,25 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
* can use GPIO interrupts. They have serial #'s starting
* with 128, rather than 112.
*/
- dd->ipath_flags |= IPATH_GPIO_INTR;
- } else
- ipath_dev_err(dd, "Unsupported InfiniPath serial "
- "number %.16s!\n", dd->ipath_serial);
+ if (dd->ipath_serial[0] == '1' &&
+ dd->ipath_serial[1] == '2' &&
+ dd->ipath_serial[2] == '8')
+ dd->ipath_flags |= IPATH_GPIO_INTR;
+ else {
+ ipath_dev_err(dd, "Unsupported InfiniPath board "
+ "(serial number %.16s)!\n",
+ dd->ipath_serial);
+ return 1;
+ }
+ }
+
+ if (dd->ipath_minrev >= 4) {
+ /* Rev4+ reports extra errors via internal GPIO pins */
+ dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
+ dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
+ dd->ipath_gpio_mask);
+ }
return 0;
}
@@ -1592,7 +1586,10 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
struct ipath_base_info *kinfo = kbase;
kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |
- IPATH_RUNTIME_RCVHDR_COPY;
+ IPATH_RUNTIME_PIO_REGSWAPPED;
+
+ if (pd->port_dd->ipath_minrev < 4)
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY;
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 9868ccda5f26..0103d6f4847b 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -321,6 +321,8 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
<< INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
static int ipath_pe_txe_recover(struct ipath_devdata *);
+static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
+ u32, unsigned long);
/**
* ipath_pe_handle_hwerrors - display hardware errors.
@@ -555,8 +557,11 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n",
dd->ipath_majrev, dd->ipath_minrev);
ret = 1;
- } else
+ } else {
ret = 0;
+ if (dd->ipath_minrev >= 2)
+ dd->ipath_f_put_tid = ipath_pe_put_tid_2;
+ }
return ret;
}
@@ -1138,11 +1143,14 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
pa |= 2 << 29;
}
- /* workaround chip bug 9437 by writing each TID twice
- * and holding a spinlock around the writes, so they don't
- * intermix with other TID (eager or expected) writes
- * Unfortunately, this call can be done from interrupt level
- * for the port 0 eager TIDs, so we have to use irqsave
+ /*
+ * Workaround chip bug 9437 by writing the scratch register
+ * before and after the TID, and with an io write barrier.
+ * We use a spinlock around the writes, so they can't intermix
+ * with other TID (eager or expected) writes (the chip bug
+ * is triggered by back to back TID writes). Unfortunately, this
+ * call can be done from interrupt level for the port 0 eager TIDs,
+ * so we have to use irqsave locks.
*/
spin_lock_irqsave(&dd->ipath_tid_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);
@@ -1220,7 +1228,7 @@ static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
for (i = 0; i < dd->ipath_rcvtidcnt; i++)
- ipath_pe_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+ dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
tidinv);
tidbase = (u64 __iomem *)
@@ -1229,7 +1237,7 @@ static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
port * dd->ipath_rcvegrcnt * sizeof(*tidbase));
for (i = 0; i < dd->ipath_rcvegrcnt; i++)
- ipath_pe_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+ dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
tidinv);
}
@@ -1268,6 +1276,8 @@ static void ipath_pe_tidtemplate(struct ipath_devdata *dd)
static int ipath_pe_early_init(struct ipath_devdata *dd)
{
dd->ipath_flags |= IPATH_4BYTE_TID;
+ if (ipath_unordered_wc())
+ dd->ipath_flags |= IPATH_PIO_FLUSH_WC;
/*
* For openfabrics, we need to be able to handle an IB header of
@@ -1338,7 +1348,8 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
dd = pd->port_dd;
done:
- kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE |
+ IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED;
return 0;
}
@@ -1395,10 +1406,11 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
dd->ipath_f_clear_tids = ipath_pe_clear_tids;
- if (dd->ipath_minrev >= 2)
- dd->ipath_f_put_tid = ipath_pe_put_tid_2;
- else
- dd->ipath_f_put_tid = ipath_pe_put_tid;
+ /*
+ * this may get changed after we read the chip revision,
+ * but we start with the safe version for all revs
+ */
+ dd->ipath_f_put_tid = ipath_pe_put_tid;
dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
dd->ipath_f_setextled = ipath_setup_pe_setextled;
dd->ipath_f_get_base_info = ipath_pe_get_base_info;
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 49951d583804..9dd0bacf8461 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -782,7 +782,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
* Follows early_init because some chips have to initialize
* PIO buffers in early_init to avoid false parity errors.
*/
- ipath_cancel_sends(dd);
+ ipath_cancel_sends(dd, 0);
/* early_init sets rcvhdrentsize and rcvhdrsize, so this must be
* done after early_init */
@@ -851,13 +851,14 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
dd->ipath_hwerrmask);
- dd->ipath_maskederrs = dd->ipath_ignorederrs;
/* clear all */
ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL);
/* enable errors that are masked, at least this first time. */
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
~dd->ipath_maskederrs);
- /* clear any interrups up to this point (ints still not enabled) */
+ dd->ipath_errormask = ipath_read_kreg64(dd,
+ dd->ipath_kregs->kr_errormask);
+ /* clear any interrupts up to this point (ints still not enabled) */
ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);
/*
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 47aa43428fbf..6a5dd5cd773d 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -70,7 +70,7 @@ static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
* 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)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
{
u32 piobcnt;
unsigned long sbuf[4];
@@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate)
return ret;
}
+void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
+{
+ struct ib_event event;
+
+ event.device = &dd->verbs_dev->ibdev;
+ event.element.port_num = 1;
+ event.event = ev;
+ ib_dispatch_event(&event);
+}
+
static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
ipath_err_t errs, int noprint)
{
@@ -303,7 +313,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
* Flush all queued sends when link went to DOWN or INIT,
* to be sure that they don't block SMA and other MAD packets
*/
- ipath_cancel_sends(dd);
+ ipath_cancel_sends(dd, 1);
}
else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
lstate == IPATH_IBSTATE_ACTIVE) {
@@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */
ipath_stats.sps_iblink++;
if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
dd->ipath_flags |= IPATH_LINKDOWN;
dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
| IPATH_LINKACTIVE |
@@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
*dd->ipath_statusp |=
IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
dd->ipath_f_setextled(dd, lstate, ltstate);
+ signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
/*
* set INIT and DOWN. Down is checked by most of the other
* code, but INIT is useful to know in a few places.
@@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
| IPATH_STATUS_IB_READY);
dd->ipath_f_setextled(dd, lstate, ltstate);
} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) {
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
dd->ipath_flags |= IPATH_LINKARMED;
dd->ipath_flags &=
~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT |
@@ -517,10 +534,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint);
- /*
- * don't report errors that are masked (includes those always
- * ignored)
- */
+ /* don't report errors that are masked */
errs &= ~dd->ipath_maskederrs;
/* do these first, they are most important */
@@ -566,19 +580,19 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* ones on this particular interrupt, which also isn't great
*/
dd->ipath_maskederrs |= dd->ipath_lasterror | errs;
+ dd->ipath_errormask &= ~dd->ipath_maskederrs;
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
- ~dd->ipath_maskederrs);
+ dd->ipath_errormask);
s_iserr = ipath_decode_err(msg, sizeof msg,
- (dd->ipath_maskederrs & ~dd->
- ipath_ignorederrs));
+ dd->ipath_maskederrs);
- if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
+ if (dd->ipath_maskederrs &
~(INFINIPATH_E_RRCVEGRFULL |
INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
ipath_dev_err(dd, "Temporarily disabling "
"error(s) %llx reporting; too frequent (%s)\n",
- (unsigned long long) (dd->ipath_maskederrs &
- ~dd->ipath_ignorederrs), msg);
+ (unsigned long long)dd->ipath_maskederrs,
+ msg);
else {
/*
* rcvegrfull and rcvhdrqfull are "normal",
@@ -691,17 +705,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
chkerrpkts = 1;
dd->ipath_lastrcvhdrqtails[i] = tl;
pd->port_hdrqfull++;
- if (test_bit(IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag)) {
- clear_bit(
- IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag);
- set_bit(
- IPATH_PORT_WAITING_OVERFLOW,
- &pd->int_flag);
- wake_up_interruptible(
- &pd->port_wait);
- }
+ /* flush hdrqfull so that poll() sees it */
+ wmb();
+ wake_up_interruptible(&pd->port_wait);
}
}
}
@@ -793,19 +799,22 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
/* 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);
+ ipath_cancel_sends(dd, 0);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control);
/* ensure pio avail updates continue */
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- dd->ipath_sendctrl & ~IPATH_S_PIOBUFAVAILUPD);
+ dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
@@ -817,7 +826,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
for (i = 0; i < dd->ipath_pioavregs; i++) {
/* deal with 6110 chip bug */
im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
- val = ipath_read_kreg64(dd, 0x1000+(im*sizeof(u64)));
+ val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
= le64_to_cpu(val);
}
@@ -832,7 +841,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
E_SPKT_ERRS_IGNORE);
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
- ~dd->ipath_maskederrs);
+ dd->ipath_errormask);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, -1LL);
ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
}
@@ -959,6 +969,8 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
int i;
int rcvdint = 0;
+ /* test_bit below needs this... */
+ rmb();
portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
dd->ipath_i_rcvavail_mask)
| ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
@@ -966,22 +978,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
for (i = 1; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
if (portr & (1 << i) && pd && pd->port_cnt) {
- if (test_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag)) {
- clear_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag);
- set_bit(IPATH_PORT_WAITING_RCV,
- &pd->int_flag);
+ if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
+ &pd->port_flag)) {
clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
&dd->ipath_rcvctrl);
wake_up_interruptible(&pd->port_wait);
rcvdint = 1;
- } else if (test_bit(IPATH_PORT_WAITING_URG,
- &pd->port_flag)) {
- clear_bit(IPATH_PORT_WAITING_URG,
- &pd->port_flag);
- set_bit(IPATH_PORT_WAITING_URG,
- &pd->int_flag);
+ } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG,
+ &pd->port_flag)) {
+ pd->port_urgent++;
wake_up_interruptible(&pd->port_wait);
}
}
@@ -1002,7 +1007,6 @@ irqreturn_t ipath_intr(int irq, void *data)
u32 istat, chk0rcv = 0;
ipath_err_t estat = 0;
irqreturn_t ret;
- u32 oldhead, curtail;
static unsigned unexpected = 0;
static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) |
(1U<<INFINIPATH_I_RCVURG_SHIFT);
@@ -1035,36 +1039,6 @@ irqreturn_t ipath_intr(int irq, void *data)
goto bail;
}
- /*
- * We try to avoid reading the interrupt status register, since
- * that's a PIO read, and stalls the processor for up to about
- * ~0.25 usec. The idea is that if we processed a port0 packet,
- * we blindly clear the port 0 receive interrupt bits, and nothing
- * else, then return. If other interrupts are pending, the chip
- * will re-interrupt us as soon as we write the intclear register.
- * We then won't process any more kernel packets (if not the 2nd
- * time, then the 3rd or 4th) and we'll then handle the other
- * interrupts. We clear the interrupts first so that we don't
- * lose intr for later packets that arrive while we are processing.
- */
- oldhead = dd->ipath_port0head;
- curtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
- if (oldhead != curtail) {
- if (dd->ipath_flags & IPATH_GPIO_INTR) {
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
- (u64) (1 << IPATH_GPIO_PORT0_BIT));
- istat = port0rbits | INFINIPATH_I_GPIO;
- }
- else
- istat = port0rbits;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
- ipath_kreceive(dd);
- if (oldhead != dd->ipath_port0head) {
- ipath_stats.sps_fastrcvint++;
- goto done;
- }
- }
-
istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
if (unlikely(!istat)) {
@@ -1115,8 +1089,8 @@ irqreturn_t ipath_intr(int irq, void *data)
* GPIO_2 indicates (on some HT4xx boards) that a packet
* has arrived for Port 0. Checking for this
* is controlled by flag IPATH_GPIO_INTR.
- * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
- * that we need to count. Checking for this
+ * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate
+ * errors that we need to count. Checking for this
* is controlled by flag IPATH_GPIO_ERRINTRS.
*/
u32 gpiostatus;
@@ -1167,10 +1141,8 @@ irqreturn_t ipath_intr(int irq, void *data)
/*
* Some unexpected bits remain. If they could have
* caused the interrupt, complain and clear.
- * MEA: this is almost certainly non-ideal.
- * we should look into auto-disable of unexpected
- * GPIO interrupts, possibly on a "three strikes"
- * basis.
+ * To avoid repetition of this condition, also clear
+ * the mask. It is almost certainly due to error.
*/
const u32 mask = (u32) dd->ipath_gpio_mask;
@@ -1178,6 +1150,10 @@ irqreturn_t ipath_intr(int irq, void *data)
ipath_dbg("Unexpected GPIO IRQ bits %x\n",
gpiostatus & mask);
to_clear |= (gpiostatus & mask);
+ dd->ipath_gpio_mask &= ~(gpiostatus & mask);
+ ipath_write_kreg(dd,
+ dd->ipath_kregs->kr_gpio_mask,
+ dd->ipath_gpio_mask);
}
}
if (to_clear) {
@@ -1225,7 +1201,6 @@ irqreturn_t ipath_intr(int irq, void *data)
handle_layer_pioavail(dd);
}
-done:
ret = IRQ_HANDLED;
bail:
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 3105005fc9d2..8786dd7922e4 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -42,6 +42,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
+#include <rdma/ib_verbs.h>
#include "ipath_common.h"
#include "ipath_debug.h"
@@ -139,6 +140,12 @@ struct ipath_portdata {
u32 port_pionowait;
/* total number of rcvhdrqfull errors */
u32 port_hdrqfull;
+ /* saved total number of rcvhdrqfull errors for poll edge trigger */
+ u32 port_hdrqfull_poll;
+ /* total number of polled urgent packets */
+ u32 port_urgent;
+ /* 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;
/* same size as task_struct .comm[] */
@@ -261,18 +268,10 @@ struct ipath_devdata {
* limiting of hwerror reporting
*/
ipath_err_t ipath_lasthwerror;
- /*
- * errors masked because they occur too fast, also includes errors
- * that are always ignored (ipath_ignorederrs)
- */
+ /* errors masked because they occur too fast */
ipath_err_t ipath_maskederrs;
/* time in jiffies at which to re-enable maskederrs */
unsigned long ipath_unmasktime;
- /*
- * errors always ignored (masked), at least for a given
- * chip/device, because they are wrong or not useful
- */
- ipath_err_t ipath_ignorederrs;
/* count of egrfull errors, combined for all ports */
u64 ipath_last_tidfull;
/* for ipath_qcheck() */
@@ -436,6 +435,7 @@ struct ipath_devdata {
u64 ipath_lastibcstat;
/* hwerrmask shadow */
ipath_err_t ipath_hwerrmask;
+ ipath_err_t ipath_errormask; /* errormask shadow */
/* interrupt config reg shadow */
u64 ipath_intconfig;
/* kr_sendpiobufbase value */
@@ -683,7 +683,7 @@ int ipath_unordered_wc(void);
void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
unsigned cnt);
-void ipath_cancel_sends(struct ipath_devdata *);
+void ipath_cancel_sends(struct ipath_devdata *, int);
int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *);
void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
@@ -731,6 +731,8 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
#define IPATH_LINKACTIVE 0x200
/* link current state is unknown */
#define IPATH_LINKUNK 0x400
+ /* Write combining flush needed for PIO */
+#define IPATH_PIO_FLUSH_WC 0x1000
/* no IB cable, or no device on IB cable */
#define IPATH_NOCABLE 0x4000
/* Supports port zero per packet receive interrupts via
@@ -762,8 +764,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
#define IPATH_PORT_MASTER_UNINIT 4
/* waiting for an urgent packet to arrive */
#define IPATH_PORT_WAITING_URG 5
- /* waiting for a header overflow */
-#define IPATH_PORT_WAITING_OVERFLOW 6
/* free up any allocated data at closes */
void ipath_free_data(struct ipath_portdata *dd);
@@ -776,7 +776,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 signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);
/*
* Set LED override, only the two LSBs have "public" meaning, but
@@ -820,7 +820,6 @@ static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
int ipath_get_user_pages(unsigned long, size_t, struct page **);
-int ipath_get_user_pages_nocopy(unsigned long, struct page **);
void ipath_release_user_pages(struct page **, size_t);
void ipath_release_user_pages_on_close(struct page **, size_t);
int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int);
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
deleted file mode 100644
index 82616b779e24..000000000000
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * These are the routines used by layered drivers, currently just the
- * layered ethernet driver and verbs layer.
- */
-
-#include <linux/io.h>
-#include <asm/byteorder.h>
-
-#include "ipath_kernel.h"
-#include "ipath_layer.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-/* Acquire before ipath_devs_lock. */
-static DEFINE_MUTEX(ipath_layer_mutex);
-
-u16 ipath_layer_rcv_opcode;
-
-static int (*layer_intr)(void *, u32);
-static int (*layer_rcv)(void *, void *, struct sk_buff *);
-static int (*layer_rcv_lid)(void *, void *);
-
-static void *(*layer_add_one)(int, struct ipath_devdata *);
-static void (*layer_remove_one)(void *);
-
-int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
-{
- int ret = -ENODEV;
-
- if (dd->ipath_layer.l_arg && layer_intr)
- ret = layer_intr(dd->ipath_layer.l_arg, arg);
-
- return ret;
-}
-
-int ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
-{
- int ret;
-
- mutex_lock(&ipath_layer_mutex);
-
- ret = __ipath_layer_intr(dd, arg);
-
- mutex_unlock(&ipath_layer_mutex);
-
- return ret;
-}
-
-int __ipath_layer_rcv(struct ipath_devdata *dd, void *hdr,
- struct sk_buff *skb)
-{
- int ret = -ENODEV;
-
- if (dd->ipath_layer.l_arg && layer_rcv)
- ret = layer_rcv(dd->ipath_layer.l_arg, hdr, skb);
-
- return ret;
-}
-
-int __ipath_layer_rcv_lid(struct ipath_devdata *dd, void *hdr)
-{
- int ret = -ENODEV;
-
- if (dd->ipath_layer.l_arg && layer_rcv_lid)
- ret = layer_rcv_lid(dd->ipath_layer.l_arg, hdr);
-
- return ret;
-}
-
-void ipath_layer_lid_changed(struct ipath_devdata *dd)
-{
- mutex_lock(&ipath_layer_mutex);
-
- if (dd->ipath_layer.l_arg && layer_intr)
- layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID);
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-void ipath_layer_add(struct ipath_devdata *dd)
-{
- mutex_lock(&ipath_layer_mutex);
-
- if (layer_add_one)
- dd->ipath_layer.l_arg =
- layer_add_one(dd->ipath_unit, dd);
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-void ipath_layer_remove(struct ipath_devdata *dd)
-{
- mutex_lock(&ipath_layer_mutex);
-
- if (dd->ipath_layer.l_arg && layer_remove_one) {
- layer_remove_one(dd->ipath_layer.l_arg);
- dd->ipath_layer.l_arg = NULL;
- }
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
- void (*l_remove)(void *),
- int (*l_intr)(void *, u32),
- int (*l_rcv)(void *, void *, struct sk_buff *),
- u16 l_rcv_opcode,
- int (*l_rcv_lid)(void *, void *))
-{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- mutex_lock(&ipath_layer_mutex);
-
- layer_add_one = l_add;
- layer_remove_one = l_remove;
- layer_intr = l_intr;
- layer_rcv = l_rcv;
- layer_rcv_lid = l_rcv_lid;
- ipath_layer_rcv_opcode = l_rcv_opcode;
-
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- if (!(dd->ipath_flags & IPATH_INITTED))
- continue;
-
- if (dd->ipath_layer.l_arg)
- continue;
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd);
- spin_lock_irqsave(&ipath_devs_lock, flags);
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- mutex_unlock(&ipath_layer_mutex);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_register);
-
-void ipath_layer_unregister(void)
-{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- mutex_lock(&ipath_layer_mutex);
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- if (dd->ipath_layer.l_arg && layer_remove_one) {
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- layer_remove_one(dd->ipath_layer.l_arg);
- spin_lock_irqsave(&ipath_devs_lock, flags);
- dd->ipath_layer.l_arg = NULL;
- }
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
- layer_add_one = NULL;
- layer_remove_one = NULL;
- layer_intr = NULL;
- layer_rcv = NULL;
- layer_rcv_lid = NULL;
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_unregister);
-
-int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
-{
- int ret;
- u32 intval = 0;
-
- mutex_lock(&ipath_layer_mutex);
-
- if (!dd->ipath_layer.l_arg) {
- ret = -EINVAL;
- goto bail;
- }
-
- ret = ipath_setrcvhdrsize(dd, IPATH_HEADER_QUEUE_WORDS);
-
- if (ret < 0)
- goto bail;
-
- *pktmax = dd->ipath_ibmaxlen;
-
- if (*dd->ipath_statusp & IPATH_STATUS_IB_READY)
- intval |= IPATH_LAYER_INT_IF_UP;
- if (dd->ipath_lid)
- intval |= IPATH_LAYER_INT_LID;
- if (dd->ipath_mlid)
- intval |= IPATH_LAYER_INT_BCAST;
- /*
- * do this on open, in case low level is already up and
- * just layered driver was reloaded, etc.
- */
- if (intval)
- layer_intr(dd->ipath_layer.l_arg, intval);
-
- ret = 0;
-bail:
- mutex_unlock(&ipath_layer_mutex);
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_open);
-
-u16 ipath_layer_get_lid(struct ipath_devdata *dd)
-{
- return dd->ipath_lid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_lid);
-
-/**
- * ipath_layer_get_mac - get the MAC address
- * @dd: the infinipath device
- * @mac: the MAC is put here
- *
- * This is the EUID-64 OUI octets (top 3), then
- * skip the next 2 (which should both be zero or 0xff).
- * The returned MAC is in network order
- * mac points to at least 6 bytes of buffer
- * We assume that by the time the LID is set, that the GUID is as valid
- * as it's ever going to be, rather than adding yet another status bit.
- */
-
-int ipath_layer_get_mac(struct ipath_devdata *dd, u8 * mac)
-{
- u8 *guid;
-
- guid = (u8 *) &dd->ipath_guid;
-
- mac[0] = guid[0];
- mac[1] = guid[1];
- mac[2] = guid[2];
- mac[3] = guid[5];
- mac[4] = guid[6];
- mac[5] = guid[7];
- if ((guid[3] || guid[4]) && !(guid[3] == 0xff && guid[4] == 0xff))
- ipath_dbg("Warning, guid bytes 3 and 4 not 0 or 0xffff: "
- "%x %x\n", guid[3], guid[4]);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_mac);
-
-u16 ipath_layer_get_bcast(struct ipath_devdata *dd)
-{
- return dd->ipath_mlid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_bcast);
-
-int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr)
-{
- int ret = 0;
- u32 __iomem *piobuf;
- u32 plen, *uhdr;
- size_t count;
- __be16 vlsllnh;
-
- if (!(dd->ipath_flags & IPATH_RCVHDRSZ_SET)) {
- ipath_dbg("send while not open\n");
- ret = -EINVAL;
- } else
- if ((dd->ipath_flags & (IPATH_LINKUNK | IPATH_LINKDOWN)) ||
- dd->ipath_lid == 0) {
- /*
- * lid check is for when sma hasn't yet configured
- */
- ret = -ENETDOWN;
- ipath_cdbg(VERBOSE, "send while not ready, "
- "mylid=%u, flags=0x%x\n",
- dd->ipath_lid, dd->ipath_flags);
- }
-
- vlsllnh = *((__be16 *) hdr);
- if (vlsllnh != htons(IPATH_LRH_BTH)) {
- ipath_dbg("Warning: lrh[0] wrong (%x, not %x); "
- "not sending\n", be16_to_cpu(vlsllnh),
- IPATH_LRH_BTH);
- ret = -EINVAL;
- }
- if (ret)
- goto done;
-
- /* Get a PIO buffer to use. */
- piobuf = ipath_getpiobuf(dd, NULL);
- if (piobuf == NULL) {
- ret = -EBUSY;
- goto done;
- }
-
- plen = (sizeof(*hdr) >> 2); /* actual length */
- ipath_cdbg(EPKT, "0x%x+1w pio %p\n", plen, piobuf);
-
- writeq(plen+1, piobuf); /* len (+1 for pad) to pbc, no flags */
- ipath_flush_wc();
- piobuf += 2;
- uhdr = (u32 *)hdr;
- count = plen-1; /* amount we can copy before trigger word */
- __iowrite32_copy(piobuf, uhdr, count);
- ipath_flush_wc();
- __raw_writel(uhdr[count], piobuf + count);
- ipath_flush_wc(); /* ensure it's sent, now */
-
- ipath_stats.sps_ether_spkts++; /* ether packet sent */
-
-done:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_send_hdr);
-
-int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd)
-{
- set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
-
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- dd->ipath_sendctrl);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int);
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h
deleted file mode 100644
index 415709c4d85b..000000000000
--- a/drivers/infiniband/hw/ipath/ipath_layer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _IPATH_LAYER_H
-#define _IPATH_LAYER_H
-
-/*
- * This header file is for symbols shared between the infinipath driver
- * and drivers layered upon it (such as ipath).
- */
-
-struct sk_buff;
-struct ipath_devdata;
-struct ether_header;
-
-int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
- void (*l_remove)(void *),
- int (*l_intr)(void *, u32),
- int (*l_rcv)(void *, void *,
- struct sk_buff *),
- u16 rcv_opcode,
- int (*l_rcv_lid)(void *, void *));
-void ipath_layer_unregister(void);
-int ipath_layer_open(struct ipath_devdata *, u32 * pktmax);
-u16 ipath_layer_get_lid(struct ipath_devdata *dd);
-int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *);
-u16 ipath_layer_get_bcast(struct ipath_devdata *dd);
-int ipath_layer_send_hdr(struct ipath_devdata *dd,
- struct ether_header *hdr);
-int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd);
-
-/* ipath_ether interrupt values */
-#define IPATH_LAYER_INT_IF_UP 0x2
-#define IPATH_LAYER_INT_IF_DOWN 0x4
-#define IPATH_LAYER_INT_LID 0x8
-#define IPATH_LAYER_INT_SEND_CONTINUE 0x10
-#define IPATH_LAYER_INT_BCAST 0x40
-
-extern unsigned ipath_debug; /* debugging bit mask */
-
-#endif /* _IPATH_LAYER_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index d61c03044545..3d1432d1e3f4 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -245,7 +245,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
/* Only return the mkey if the protection field allows it. */
if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey ||
- (dev->mkeyprot_resv_lmc >> 6) == 0)
+ dev->mkeyprot == 0)
pip->mkey = dev->mkey;
pip->gid_prefix = dev->gid_prefix;
lid = dev->dd->ipath_lid;
@@ -264,7 +264,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
pip->portphysstate_linkdown =
(ipath_cvt_physportstate[ibcstat & 0xf] << 4) |
(get_linkdowndefaultstate(dev->dd) ? 1 : 2);
- pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc;
+ pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dev->dd->ipath_lmc;
pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */
switch (dev->dd->ipath_ibmtu) {
case 4096:
@@ -401,7 +401,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
struct ib_port_info *pip = (struct ib_port_info *)smp->data;
struct ib_event event;
struct ipath_ibdev *dev;
- u32 flags;
+ struct ipath_devdata *dd;
char clientrereg = 0;
u16 lid, smlid;
u8 lwe;
@@ -415,6 +415,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
goto err;
dev = to_idev(ibdev);
+ dd = dev->dd;
event.device = ibdev;
event.element.port_num = port;
@@ -423,11 +424,12 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
lid = be16_to_cpu(pip->lid);
- if (lid != dev->dd->ipath_lid) {
+ if (dd->ipath_lid != lid ||
+ dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) {
/* Must be a valid unicast LID address. */
if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
goto err;
- ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7);
+ ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7);
event.event = IB_EVENT_LID_CHANGE;
ib_dispatch_event(&event);
}
@@ -461,18 +463,18 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
case 0: /* NOP */
break;
case 1: /* SLEEP */
- if (set_linkdowndefaultstate(dev->dd, 1))
+ if (set_linkdowndefaultstate(dd, 1))
goto err;
break;
case 2: /* POLL */
- if (set_linkdowndefaultstate(dev->dd, 0))
+ if (set_linkdowndefaultstate(dd, 0))
goto err;
break;
default:
goto err;
}
- dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc;
+ dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
dev->vl_high_limit = pip->vl_high_limit;
switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) {
@@ -495,7 +497,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
/* XXX We have already partially updated our state! */
goto err;
}
- ipath_set_mtu(dev->dd, mtu);
+ ipath_set_mtu(dd, mtu);
dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
@@ -511,16 +513,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
* later.
*/
if (pip->pkey_violations == 0)
- dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd);
+ dev->z_pkey_violations = ipath_get_cr_errpkey(dd);
if (pip->qkey_violations == 0)
dev->qkey_violations = 0;
ore = pip->localphyerrors_overrunerrors;
- if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF))
+ if (set_phyerrthreshold(dd, (ore >> 4) & 0xF))
goto err;
- if (set_overrunthreshold(dev->dd, (ore & 0xF)))
+ if (set_overrunthreshold(dd, (ore & 0xF)))
goto err;
dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
@@ -538,7 +540,6 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
* is down or is being set to down.
*/
state = pip->linkspeed_portstate & 0xF;
- flags = dev->dd->ipath_flags;
lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
goto err;
@@ -554,7 +555,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
/* FALLTHROUGH */
case IB_PORT_DOWN:
if (lstate == 0)
- if (get_linkdowndefaultstate(dev->dd))
+ if (get_linkdowndefaultstate(dd))
lstate = IPATH_IB_LINKDOWN_SLEEP;
else
lstate = IPATH_IB_LINKDOWN;
@@ -566,27 +567,13 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
lstate = IPATH_IB_LINKDOWN_DISABLE;
else
goto err;
- ipath_set_linkstate(dev->dd, lstate);
- if (flags & IPATH_LINKACTIVE) {
- event.event = IB_EVENT_PORT_ERR;
- ib_dispatch_event(&event);
- }
+ ipath_set_linkstate(dd, lstate);
break;
case IB_PORT_ARMED:
- if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
- break;
- ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM);
- if (flags & IPATH_LINKACTIVE) {
- event.event = IB_EVENT_PORT_ERR;
- ib_dispatch_event(&event);
- }
+ ipath_set_linkstate(dd, IPATH_IB_LINKARM);
break;
case IB_PORT_ACTIVE:
- if (!(flags & IPATH_LINKARMED))
- break;
- ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
- event.event = IB_EVENT_PORT_ACTIVE;
- ib_dispatch_event(&event);
+ ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
break;
default:
/* XXX We have already partially updated our state! */
@@ -1350,7 +1337,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) {
/* Clear timeout and mkey protection field. */
dev->mkey_lease_timeout = 0;
- dev->mkeyprot_resv_lmc &= 0x3F;
+ dev->mkeyprot = 0;
}
/*
@@ -1361,7 +1348,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
dev->mkey != smp->mkey &&
(smp->method == IB_MGMT_METHOD_SET ||
(smp->method == IB_MGMT_METHOD_GET &&
- (dev->mkeyprot_resv_lmc >> 7) != 0))) {
+ dev->mkeyprot >= 2))) {
if (dev->mkey_violations != 0xFFFF)
++dev->mkey_violations;
if (dev->mkey_lease_timeout ||
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 1324b35ff1f8..6a41fdbc8e57 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -338,6 +338,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->s_busy = 0;
qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
qp->s_hdrwords = 0;
+ qp->s_wqe = NULL;
qp->s_psn = 0;
qp->r_psn = 0;
qp->r_msn = 0;
@@ -376,13 +377,15 @@ static void ipath_reset_qp(struct ipath_qp *qp)
* @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.
*/
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
+ int ret = 0;
ipath_dbg("QP%d/%d in error state\n",
qp->ibqp.qp_num, qp->remote_qpn);
@@ -453,7 +456,10 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
wq->tail = tail;
spin_unlock(&qp->r_rq.lock);
- }
+ } else if (qp->ibqp.event_handler)
+ ret = 1;
+
+ return ret;
}
/**
@@ -472,6 +478,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
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);
@@ -531,7 +538,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
break;
case IB_QPS_ERR:
- ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+ lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
break;
default:
@@ -590,6 +597,14 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->state = new_state;
spin_unlock_irqrestore(&qp->s_lock, flags);
+ if (lastwqe) {
+ struct ib_event ev;
+
+ ev.device = qp->ibqp.device;
+ ev.element.qp = &qp->ibqp;
+ ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+ }
ret = 0;
goto bail;
@@ -751,6 +766,9 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
switch (init_attr->qp_type) {
case IB_QPT_UC:
case IB_QPT_RC:
+ case IB_QPT_UD:
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
sz = sizeof(struct ipath_sge) *
init_attr->cap.max_send_sge +
sizeof(struct ipath_swqe);
@@ -759,10 +777,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
ret = ERR_PTR(-ENOMEM);
goto bail;
}
- /* FALLTHROUGH */
- case IB_QPT_UD:
- case IB_QPT_SMI:
- case IB_QPT_GSI:
sz = sizeof(*qp);
if (init_attr->srq) {
struct ipath_srq *srq = to_isrq(init_attr->srq);
@@ -805,8 +819,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);
- tasklet_init(&qp->s_task, ipath_do_ruc_send,
- (unsigned long)qp);
+ tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp);
INIT_LIST_HEAD(&qp->piowait);
INIT_LIST_HEAD(&qp->timerwait);
qp->state = IB_QPS_RESET;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 46744ea2babd..5c29b2bfea17 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -81,9 +81,8 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
* Note that we are in the responder's side of the QP context.
* Note the QP s_lock must be held.
*/
-static int ipath_make_rc_ack(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr, u32 pmtu)
{
struct ipath_ack_entry *e;
u32 hwords;
@@ -192,8 +191,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
}
qp->s_hdrwords = hwords;
qp->s_cur_size = len;
- *bth0p = bth0 | (1 << 22); /* Set M bit */
- *bth2p = bth2;
+ ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2);
return 1;
bail:
@@ -203,32 +201,39 @@ bail:
/**
* ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
* @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
*
* Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
*/
-int ipath_make_rc_req(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_rc_req(struct ipath_qp *qp)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ struct ipath_other_headers *ohdr;
struct ipath_sge_state *ss;
struct ipath_swqe *wqe;
u32 hwords;
u32 len;
u32 bth0;
u32 bth2;
+ u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
char newreq;
+ unsigned long flags;
+ int ret = 0;
+
+ ohdr = &qp->s_hdr.u.oth;
+ if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+ ohdr = &qp->s_hdr.u.l.oth;
+
+ /*
+ * The lock is needed to synchronize between the sending tasklet,
+ * the receive interrupt handler, and timeout resends.
+ */
+ spin_lock_irqsave(&qp->s_lock, flags);
/* Sending responses has higher priority over sending requests. */
if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
(qp->s_flags & IPATH_S_ACK_PENDING) ||
qp->s_ack_state != OP(ACKNOWLEDGE)) &&
- ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
+ ipath_make_rc_ack(dev, qp, ohdr, pmtu))
goto done;
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
@@ -560,13 +565,12 @@ int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_hdrwords = hwords;
qp->s_cur_sge = ss;
qp->s_cur_size = len;
- *bth0p = bth0 | (qp->s_state << 24);
- *bth2p = bth2;
+ ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
done:
- return 1;
-
+ ret = 1;
bail:
- return 0;
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ return ret;
}
/**
@@ -627,7 +631,7 @@ static void send_rc_ack(struct ipath_qp *qp)
/*
* If we can send the ACK, clear the ACK state.
*/
- if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
+ if (ipath_verbs_send(qp, &hdr, hwords, NULL, 0) == 0) {
dev->n_unicast_xmit++;
goto done;
}
@@ -757,7 +761,9 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
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;
@@ -1041,7 +1047,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int 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;
@@ -1454,6 +1462,19 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
goto send_ack;
}
/*
+ * Try to send a simple ACK to work around a Mellanox bug
+ * which doesn't accept a RDMA read response or atomic
+ * response as an ACK for earlier SENDs or RDMA writes.
+ */
+ if (qp->r_head_ack_queue == qp->s_tail_ack_queue &&
+ !(qp->s_flags & IPATH_S_ACK_PENDING) &&
+ qp->s_ack_state == OP(ACKNOWLEDGE)) {
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ qp->r_nak_state = 0;
+ qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
+ goto send_ack;
+ }
+ /*
* Resend the RDMA read or atomic op which
* ACKs this duplicate request.
*/
@@ -1476,11 +1497,21 @@ send_ack:
static 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;
- ipath_error_qp(qp, err);
+ lastwqe = ipath_error_qp(qp, err);
spin_unlock_irqrestore(&qp->s_lock, flags);
+
+ if (lastwqe) {
+ struct ib_event ev;
+
+ ev.device = qp->ibqp.device;
+ ev.element.qp = &qp->ibqp;
+ ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+ }
}
static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 85256747d8a1..4b6b7ee8e5c1 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -31,6 +31,8 @@
* SOFTWARE.
*/
+#include <linux/spinlock.h>
+
#include "ipath_verbs.h"
#include "ipath_kernel.h"
@@ -106,27 +108,30 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
spin_unlock_irqrestore(&dev->pending_lock, flags);
}
-static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
+/**
+ * ipath_init_sge - Validate a RWQE and fill in the SGE state
+ * @qp: the QP
+ *
+ * Return 1 if OK.
+ */
+int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+ u32 *lengthp, struct ipath_sge_state *ss)
{
- int user = to_ipd(qp->ibqp.pd)->user;
int i, j, ret;
struct ib_wc wc;
- qp->r_len = 0;
+ *lengthp = 0;
for (i = j = 0; i < wqe->num_sge; i++) {
if (wqe->sg_list[i].length == 0)
continue;
/* Check LKEY */
- if ((user && wqe->sg_list[i].lkey == 0) ||
- !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
- IB_ACCESS_LOCAL_WRITE))
+ if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
+ &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
goto bad_lkey;
- qp->r_len += wqe->sg_list[i].length;
+ *lengthp += wqe->sg_list[i].length;
j++;
}
- qp->r_sge.sge = qp->r_sg_list[0];
- qp->r_sge.sg_list = qp->r_sg_list + 1;
- qp->r_sge.num_sge = j;
+ ss->num_sge = j;
ret = 1;
goto bail;
@@ -172,6 +177,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
u32 tail;
int ret;
+ qp->r_sge.sg_list = qp->r_sg_list;
+
if (qp->ibqp.srq) {
srq = to_isrq(qp->ibqp.srq);
handler = srq->ibsrq.event_handler;
@@ -199,7 +206,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
wqe = get_rwqe_ptr(rq, tail);
if (++tail >= rq->size)
tail = 0;
- } while (!wr_id_only && !init_sge(qp, wqe));
+ } while (!wr_id_only && !ipath_init_sge(qp, wqe, &qp->r_len,
+ &qp->r_sge));
qp->r_wr_id = wqe->wr_id;
wq->tail = tail;
@@ -239,9 +247,9 @@ bail:
/**
* ipath_ruc_loopback - handle UC and RC lookback requests
- * @sqp: the loopback QP
+ * @sqp: the sending QP
*
- * This is called from ipath_do_uc_send() or ipath_do_rc_send() to
+ * This is called from ipath_do_send() to
* forward a WQE addressed to the same HCA.
* Note that although we are single threaded due to the tasklet, we still
* have to protect against post_send(). We don't have to worry about
@@ -450,40 +458,18 @@ again:
wc.byte_len = wqe->length;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
- /* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
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:
sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
-
- if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
- (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- 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.qp = &sqp->ibqp;
- wc.src_qp = 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(sqp->ibqp.send_cq), &wc, 0);
- }
-
- /* Update s_last now that we are finished with the SWQE */
- spin_lock_irqsave(&sqp->s_lock, flags);
- if (++sqp->s_last >= sqp->s_size)
- sqp->s_last = 0;
- spin_unlock_irqrestore(&sqp->s_lock, flags);
+ ipath_send_complete(sqp, wqe, IB_WC_SUCCESS);
goto again;
done:
@@ -491,13 +477,11 @@ done:
wake_up(&qp->wait);
}
-static int want_buffer(struct ipath_devdata *dd)
+static void want_buffer(struct ipath_devdata *dd)
{
set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
-
- return 0;
}
/**
@@ -507,14 +491,11 @@ static int want_buffer(struct ipath_devdata *dd)
*
* Called when we run out of PIO buffers.
*/
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
+static void ipath_no_bufs_available(struct ipath_qp *qp,
+ struct ipath_ibdev *dev)
{
unsigned long flags;
- spin_lock_irqsave(&dev->pending_lock, flags);
- if (list_empty(&qp->piowait))
- list_add_tail(&qp->piowait, &dev->piowait);
- spin_unlock_irqrestore(&dev->pending_lock, flags);
/*
* Note that as soon as want_buffer() is called and
* possibly before it returns, ipath_ib_piobufavail()
@@ -524,101 +505,14 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
* We leave the busy flag set so that another post send doesn't
* try to put the same QP on the piowait list again.
*/
+ 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++;
}
/**
- * ipath_post_ruc_send - post RC and UC sends
- * @qp: the QP to post on
- * @wr: the work request to send
- */
-int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
-{
- struct ipath_swqe *wqe;
- unsigned long flags;
- u32 next;
- int i, j;
- int acc;
- int ret;
-
- /*
- * Don't allow RDMA reads or atomic operations on UC or
- * undefined operations.
- * Make sure buffer is large enough to hold the result for atomics.
- */
- if (qp->ibqp.qp_type == IB_QPT_UC) {
- if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) {
- ret = -EINVAL;
- goto bail;
- }
- } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) {
- ret = -EINVAL;
- goto bail;
- } else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
- (wr->num_sge == 0 ||
- wr->sg_list[0].length < sizeof(u64) ||
- wr->sg_list[0].addr & (sizeof(u64) - 1))) {
- ret = -EINVAL;
- goto bail;
- } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
- ret = -EINVAL;
- goto bail;
- }
- /* IB spec says that num_sge == 0 is OK. */
- if (wr->num_sge > qp->s_max_sge) {
- ret = -ENOMEM;
- goto bail;
- }
- spin_lock_irqsave(&qp->s_lock, flags);
- next = qp->s_head + 1;
- if (next >= qp->s_size)
- next = 0;
- if (next == qp->s_last) {
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ret = -EINVAL;
- goto bail;
- }
-
- wqe = get_swqe_ptr(qp, qp->s_head);
- wqe->wr = *wr;
- wqe->ssn = qp->s_ssn++;
- wqe->sg_list[0].mr = NULL;
- wqe->sg_list[0].vaddr = NULL;
- wqe->sg_list[0].length = 0;
- wqe->sg_list[0].sge_length = 0;
- wqe->length = 0;
- acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0;
- for (i = 0, j = 0; i < wr->num_sge; i++) {
- if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ret = -EINVAL;
- goto bail;
- }
- if (wr->sg_list[i].length == 0)
- continue;
- if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
- acc)) {
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ret = -EINVAL;
- goto bail;
- }
- wqe->length += wr->sg_list[i].length;
- j++;
- }
- wqe->wr.num_sge = j;
- qp->s_head = next;
- spin_unlock_irqrestore(&qp->s_lock, flags);
-
- ipath_do_ruc_send((unsigned long) qp);
-
- ret = 0;
-
-bail:
- return ret;
-}
-
-/**
* ipath_make_grh - construct a GRH header
* @dev: a pointer to the ipath device
* @hdr: a pointer to the GRH header being constructed
@@ -648,39 +542,66 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
return sizeof(struct ib_grh) / sizeof(u32);
}
+void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 bth0, u32 bth2)
+{
+ u16 lrh0;
+ u32 nwords;
+ u32 extra_bytes;
+
+ /* Construct the header. */
+ extra_bytes = -qp->s_cur_size & 3;
+ nwords = (qp->s_cur_size + extra_bytes) >> 2;
+ lrh0 = IPATH_LRH_BTH;
+ if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
+ qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
+ &qp->remote_ah_attr.grh,
+ qp->s_hdrwords, nwords);
+ lrh0 = IPATH_LRH_GRH;
+ }
+ lrh0 |= qp->remote_ah_attr.sl << 4;
+ qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
+ qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
+ qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+ bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ bth0 |= extra_bytes << 20;
+ ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
+ ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+ ohdr->bth[2] = cpu_to_be32(bth2);
+}
+
/**
- * ipath_do_ruc_send - perform a send on an RC or UC QP
+ * ipath_do_send - perform a send on a QP
* @data: contains a pointer to the QP
*
* Process entries in the send work queue until credit or queue is
* exhausted. Only allow one CPU to send a packet per QP (tasklet).
- * Otherwise, after we drop the QP s_lock, two threads could send
- * packets out of order.
+ * Otherwise, two threads could send packets out of order.
*/
-void ipath_do_ruc_send(unsigned long data)
+void ipath_do_send(unsigned long data)
{
struct ipath_qp *qp = (struct ipath_qp *)data;
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
- unsigned long flags;
- u16 lrh0;
- u32 nwords;
- u32 extra_bytes;
- u32 bth0;
- u32 bth2;
- u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
- struct ipath_other_headers *ohdr;
+ int (*make_req)(struct ipath_qp *qp);
if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
goto bail;
- if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
+ 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;
}
- ohdr = &qp->s_hdr.u.oth;
- if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
- ohdr = &qp->s_hdr.u.l.oth;
+ if (qp->ibqp.qp_type == IB_QPT_RC)
+ make_req = ipath_make_rc_req;
+ else if (qp->ibqp.qp_type == IB_QPT_UC)
+ make_req = ipath_make_uc_req;
+ else
+ make_req = ipath_make_ud_req;
again:
/* Check for a constructed packet to be sent. */
@@ -689,9 +610,8 @@ again:
* If no PIO bufs are available, return. An interrupt will
* call ipath_ib_piobufavail() when one is available.
*/
- if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
- (u32 *) &qp->s_hdr, qp->s_cur_size,
- qp->s_cur_sge)) {
+ 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;
}
@@ -700,54 +620,42 @@ again:
qp->s_hdrwords = 0;
}
- /*
- * The lock is needed to synchronize between setting
- * qp->s_ack_state, resend timer, and post_send().
- */
- spin_lock_irqsave(&qp->s_lock, flags);
-
- if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
- ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
- ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
- /*
- * Clear the busy bit before unlocking to avoid races with
- * adding new work queue items and then failing to process
- * them.
- */
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
- spin_unlock_irqrestore(&qp->s_lock, flags);
- goto bail;
- }
+ if (make_req(qp))
+ goto again;
+clear:
+ clear_bit(IPATH_S_BUSY, &qp->s_busy);
+bail:;
+}
- spin_unlock_irqrestore(&qp->s_lock, flags);
+void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
+ enum ib_wc_status status)
+{
+ u32 last = qp->s_last;
- /* Construct the header. */
- extra_bytes = (4 - qp->s_cur_size) & 3;
- nwords = (qp->s_cur_size + extra_bytes) >> 2;
- lrh0 = IPATH_LRH_BTH;
- if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
- qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
- &qp->remote_ah_attr.grh,
- qp->s_hdrwords, nwords);
- lrh0 = IPATH_LRH_GRH;
- }
- lrh0 |= qp->remote_ah_attr.sl << 4;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
- SIZE_OF_CRC);
- qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
- bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
- bth0 |= extra_bytes << 20;
- ohdr->bth[0] = cpu_to_be32(bth0);
- ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
- ohdr->bth[2] = cpu_to_be32(bth2);
+ if (++last == qp->s_size)
+ last = 0;
+ qp->s_last = last;
- /* Check for more work to do. */
- goto again;
+ /* See ch. 11.2.4.1 and 10.7.3.1 */
+ if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
+ (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+ status != IB_WC_SUCCESS) {
+ struct ib_wc wc;
-clear:
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
-bail:
- return;
+ 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);
+ }
}
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index 73ed17d03188..f0271415cd5b 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -55,7 +55,6 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
u64 val64;
unsigned long t0, t1;
u64 ret;
- unsigned long flags;
t0 = jiffies;
/* If fast increment counters are only 32 bits, snapshot them,
@@ -92,18 +91,12 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
if (creg == dd->ipath_cregs->cr_wordsendcnt) {
if (val != dd->ipath_lastsword) {
dd->ipath_sword += val - dd->ipath_lastsword;
- spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
- dd->ipath_traffic_wds += val - dd->ipath_lastsword;
- spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
dd->ipath_lastsword = val;
}
val64 = dd->ipath_sword;
} else if (creg == dd->ipath_cregs->cr_wordrcvcnt) {
if (val != dd->ipath_lastrword) {
dd->ipath_rword += val - dd->ipath_lastrword;
- spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
- dd->ipath_traffic_wds += val - dd->ipath_lastrword;
- spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
dd->ipath_lastrword = val;
}
val64 = dd->ipath_rword;
@@ -196,6 +189,45 @@ static void ipath_qcheck(struct ipath_devdata *dd)
}
}
+static void ipath_chk_errormask(struct ipath_devdata *dd)
+{
+ static u32 fixed;
+ u32 ctrl;
+ unsigned long errormask;
+ unsigned long hwerrs;
+
+ if (!dd->ipath_errormask || !(dd->ipath_flags & IPATH_INITTED))
+ return;
+
+ errormask = ipath_read_kreg64(dd, dd->ipath_kregs->kr_errormask);
+
+ if (errormask == dd->ipath_errormask)
+ return;
+ fixed++;
+
+ hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
+ ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
+
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+ dd->ipath_errormask);
+
+ if ((hwerrs & dd->ipath_hwerrmask) ||
+ (ctrl & INFINIPATH_C_FREEZEMODE)) {
+ /* force re-interrupt of pending events, just in case */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, 0ULL);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, 0ULL);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
+ dev_info(&dd->pcidev->dev,
+ "errormask fixed(%u) %lx -> %lx, ctrl %x hwerr %lx\n",
+ fixed, errormask, (unsigned long)dd->ipath_errormask,
+ ctrl, hwerrs);
+ } else
+ ipath_dbg("errormask fixed(%u) %lx -> %lx, no freeze\n",
+ fixed, errormask,
+ (unsigned long)dd->ipath_errormask);
+}
+
+
/**
* ipath_get_faststats - get word counters from chip before they overflow
* @opaque - contains a pointer to the infinipath device ipath_devdata
@@ -208,6 +240,7 @@ void ipath_get_faststats(unsigned long opaque)
u32 val;
static unsigned cnt;
unsigned long flags;
+ u64 traffic_wds;
/*
* don't access the chip while running diags, or memory diags can
@@ -223,12 +256,13 @@ void ipath_get_faststats(unsigned long opaque)
* exceeding a threshold, so we need to check the word-counts
* even if they are 64-bit.
*/
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+ traffic_wds = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
- if (dd->ipath_traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
+ traffic_wds -= dd->ipath_traffic_wds;
+ dd->ipath_traffic_wds += traffic_wds;
+ if (traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
atomic_add(5, &dd->ipath_active_time); /* S/B #define */
- dd->ipath_traffic_wds = 0;
spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
if (dd->ipath_flags & IPATH_32BITCOUNTERS) {
@@ -251,14 +285,13 @@ void ipath_get_faststats(unsigned long opaque)
dd->ipath_lasterror = 0;
if (dd->ipath_lasthwerror)
dd->ipath_lasthwerror = 0;
- if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs)
+ if (dd->ipath_maskederrs
&& time_after(jiffies, dd->ipath_unmasktime)) {
char ebuf[256];
int iserr;
iserr = ipath_decode_err(ebuf, sizeof ebuf,
- (dd->ipath_maskederrs & ~dd->
- ipath_ignorederrs));
- if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
+ dd->ipath_maskederrs);
+ if (dd->ipath_maskederrs &
~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
INFINIPATH_E_PKTERRS ))
ipath_dev_err(dd, "Re-enabling masked errors "
@@ -278,9 +311,12 @@ void ipath_get_faststats(unsigned long opaque)
ipath_cdbg(ERRPKT, "Re-enabling packet"
" problem interrupt (%s)\n", ebuf);
}
- dd->ipath_maskederrs = dd->ipath_ignorederrs;
+
+ /* re-enable masked errors */
+ dd->ipath_errormask |= dd->ipath_maskederrs;
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
- ~dd->ipath_maskederrs);
+ dd->ipath_errormask);
+ dd->ipath_maskederrs = 0;
}
/* limit qfull messages to ~one per minute per port */
@@ -294,6 +330,7 @@ void ipath_get_faststats(unsigned long opaque)
}
}
+ ipath_chk_errormask(dd);
done:
mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 16238cd3a036..e1ad7cfc21fd 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -163,6 +163,42 @@ static ssize_t show_boardversion(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion);
}
+static ssize_t show_lmc(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc);
+}
+
+static ssize_t store_lmc(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+ u16 lmc = 0;
+ int ret;
+
+ ret = ipath_parse_ushort(buf, &lmc);
+ if (ret < 0)
+ goto invalid;
+
+ if (lmc > 7) {
+ ret = -EINVAL;
+ goto invalid;
+ }
+
+ ipath_set_lid(dd, dd->ipath_lid, lmc);
+
+ goto bail;
+invalid:
+ ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc);
+bail:
+ return ret;
+}
+
static ssize_t show_lid(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -190,7 +226,7 @@ static ssize_t store_lid(struct device *dev,
goto invalid;
}
- ipath_set_lid(dd, lid, 0);
+ ipath_set_lid(dd, lid, dd->ipath_lmc);
goto bail;
invalid:
@@ -648,6 +684,7 @@ static struct attribute_group driver_attr_group = {
};
static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
+static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state);
static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
@@ -667,6 +704,7 @@ static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
static struct attribute *dev_attributes[] = {
&dev_attr_guid.attr,
+ &dev_attr_lmc.attr,
&dev_attr_lid.attr,
&dev_attr_link_state.attr,
&dev_attr_mlid.attr,
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 8380fbc50d2c..2dd8de20d221 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -37,72 +37,40 @@
/* cut down ridiculously long IB macro names */
#define OP(x) IB_OPCODE_UC_##x
-static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
- struct ib_wc *wc)
-{
- if (++qp->s_last == qp->s_size)
- qp->s_last = 0;
- if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
- (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- 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->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;
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0);
- }
-}
-
/**
* ipath_make_uc_req - construct a request packet (SEND, RDMA write)
* @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
*
* Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
*/
-int ipath_make_uc_req(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_uc_req(struct ipath_qp *qp)
{
+ struct ipath_other_headers *ohdr;
struct ipath_swqe *wqe;
u32 hwords;
u32 bth0;
u32 len;
- struct ib_wc wc;
+ u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+ int ret = 0;
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))
goto done;
+ ohdr = &qp->s_hdr.u.oth;
+ if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+ ohdr = &qp->s_hdr.u.l.oth;
+
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
bth0 = 1 << 22; /* Set M bit */
/* Get the next send request. */
- wqe = get_swqe_ptr(qp, qp->s_last);
+ wqe = get_swqe_ptr(qp, qp->s_cur);
+ qp->s_wqe = NULL;
switch (qp->s_state) {
default:
- /*
- * Signal the completion of the last send
- * (if there is one).
- */
- if (qp->s_last != qp->s_tail) {
- complete_last_send(qp, wqe, &wc);
- wqe = get_swqe_ptr(qp, qp->s_last);
- }
-
/* Check if send work queue is empty. */
- if (qp->s_tail == qp->s_head)
+ if (qp->s_cur == qp->s_head)
goto done;
/*
* Start a new request.
@@ -131,6 +99,9 @@ int ipath_make_uc_req(struct ipath_qp *qp,
}
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
case IB_WR_RDMA_WRITE:
@@ -157,13 +128,14 @@ int ipath_make_uc_req(struct ipath_qp *qp,
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
}
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
default:
goto done;
}
- if (++qp->s_tail >= qp->s_size)
- qp->s_tail = 0;
break;
case OP(SEND_FIRST):
@@ -185,6 +157,9 @@ int ipath_make_uc_req(struct ipath_qp *qp,
}
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
case OP(RDMA_WRITE_FIRST):
@@ -207,18 +182,22 @@ int ipath_make_uc_req(struct ipath_qp *qp,
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
}
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
}
qp->s_len -= len;
qp->s_hdrwords = hwords;
qp->s_cur_sge = &qp->s_sge;
qp->s_cur_size = len;
- *bth0p = bth0 | (qp->s_state << 24);
- *bth2p = qp->s_next_psn++ & IPATH_PSN_MASK;
- return 1;
+ ipath_make_ruc_header(to_idev(qp->ibqp.device),
+ qp, ohdr, bth0 | (qp->s_state << 24),
+ qp->s_next_psn++ & IPATH_PSN_MASK);
+ ret = 1;
done:
- return 0;
+ return ret;
}
/**
@@ -485,6 +464,16 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
rdma_last_imm:
+ if (header_in_data) {
+ wc.imm_data = *(__be32 *) data;
+ data += sizeof(__be32);
+ } else {
+ /* Immediate data comes after BTH */
+ wc.imm_data = ohdr->u.imm_data;
+ }
+ hdrsize += 4;
+ wc.wc_flags = IB_WC_WITH_IMM;
+
/* Get the number of bytes the message was padded by. */
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
/* Check for invalid length. */
@@ -505,16 +494,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
dev->n_pkt_drops++;
goto done;
}
- if (header_in_data) {
- wc.imm_data = *(__be32 *) data;
- data += sizeof(__be32);
- } else {
- /* Immediate data comes after BTH */
- wc.imm_data = ohdr->u.imm_data;
- }
- hdrsize += 4;
- wc.wc_flags = IB_WC_WITH_IMM;
- wc.byte_len = 0;
+ wc.byte_len = qp->r_len;
goto last_imm;
case OP(RDMA_WRITE_LAST):
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index f9a3338a5fb7..16a2a938b520 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -36,68 +36,17 @@
#include "ipath_verbs.h"
#include "ipath_kernel.h"
-static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
- u32 *lengthp, struct ipath_sge_state *ss)
-{
- int user = to_ipd(qp->ibqp.pd)->user;
- int i, j, ret;
- struct ib_wc wc;
-
- *lengthp = 0;
- for (i = j = 0; i < wqe->num_sge; i++) {
- if (wqe->sg_list[i].length == 0)
- continue;
- /* Check LKEY */
- if ((user && wqe->sg_list[i].lkey == 0) ||
- !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
- &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
- goto bad_lkey;
- *lengthp += wqe->sg_list[i].length;
- j++;
- }
- ss->num_sge = j;
- ret = 1;
- goto bail;
-
-bad_lkey:
- 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;
-bail:
- return ret;
-}
-
/**
* ipath_ud_loopback - handle send on loopback QPs
- * @sqp: the QP
- * @ss: the SGE state
- * @length: the length of the data to send
- * @wr: the work request
- * @wc: the work completion entry
+ * @sqp: the sending QP
+ * @swqe: the send work request
*
- * This is called from ipath_post_ud_send() to forward a WQE addressed
+ * This is called from ipath_make_ud_req() to forward a WQE addressed
* to the same HCA.
* Note that the receive interrupt handler may be calling ipath_ud_rcv()
* while this is being called.
*/
-static void ipath_ud_loopback(struct ipath_qp *sqp,
- struct ipath_sge_state *ss,
- u32 length, struct ib_send_wr *wr,
- struct ib_wc *wc)
+static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
{
struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
struct ipath_qp *qp;
@@ -110,12 +59,18 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
struct ipath_rwq *wq;
struct ipath_rwqe *wqe;
void (*handler)(struct ib_event *, void *);
+ struct ib_wc wc;
u32 tail;
u32 rlen;
+ u32 length;
- qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);
- if (!qp)
- return;
+ qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn);
+ if (!qp) {
+ dev->n_pkt_drops++;
+ goto send_comp;
+ }
+
+ rsge.sg_list = NULL;
/*
* Check that the qkey matches (except for QP0, see 9.6.1.4.1).
@@ -123,39 +78,34 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
* qkey from the QP context instead of the WR (see 10.2.5).
*/
if (unlikely(qp->ibqp.qp_num &&
- ((int) wr->wr.ud.remote_qkey < 0
- ? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) {
+ ((int) swqe->wr.wr.ud.remote_qkey < 0 ?
+ sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) {
/* XXX OK to lose a count once in a while. */
dev->qkey_violations++;
dev->n_pkt_drops++;
- goto done;
+ goto drop;
}
/*
* A GRH is expected to preceed the data even if not
* present on the wire.
*/
- wc->byte_len = length + sizeof(struct ib_grh);
+ length = swqe->length;
+ wc.byte_len = length + sizeof(struct ib_grh);
- if (wr->opcode == IB_WR_SEND_WITH_IMM) {
- wc->wc_flags = IB_WC_WITH_IMM;
- wc->imm_data = wr->imm_data;
+ if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+ wc.wc_flags = IB_WC_WITH_IMM;
+ wc.imm_data = swqe->wr.imm_data;
} else {
- wc->wc_flags = 0;
- wc->imm_data = 0;
+ wc.wc_flags = 0;
+ wc.imm_data = 0;
}
- if (wr->num_sge > 1) {
- rsge.sg_list = kmalloc((wr->num_sge - 1) *
- sizeof(struct ipath_sge),
- GFP_ATOMIC);
- } else
- rsge.sg_list = NULL;
-
/*
- * Get the next work request entry to find where to put the data.
- * Note that it is safe to drop the lock after changing rq->tail
- * since ipath_post_receive() won't fill the empty slot.
+ * This would be a lot simpler if we could call ipath_get_rwqe()
+ * but that uses state that the receive interrupt handler uses
+ * so we would need to lock out receive interrupts while doing
+ * local loopback.
*/
if (qp->ibqp.srq) {
srq = to_isrq(qp->ibqp.srq);
@@ -167,32 +117,53 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
rq = &qp->r_rq;
}
+ if (rq->max_sge > 1) {
+ /*
+ * XXX We could use GFP_KERNEL if ipath_do_send()
+ * was always called from the tasklet instead of
+ * from ipath_post_send().
+ */
+ rsge.sg_list = kmalloc((rq->max_sge - 1) *
+ sizeof(struct ipath_sge),
+ GFP_ATOMIC);
+ if (!rsge.sg_list) {
+ dev->n_pkt_drops++;
+ goto drop;
+ }
+ }
+
+ /*
+ * Get the next work request entry to find where to put the data.
+ * Note that it is safe to drop the lock after changing rq->tail
+ * since ipath_post_receive() won't fill the empty slot.
+ */
spin_lock_irqsave(&rq->lock, flags);
wq = rq->wq;
tail = wq->tail;
- while (1) {
- if (unlikely(tail == wq->head)) {
- spin_unlock_irqrestore(&rq->lock, flags);
- dev->n_pkt_drops++;
- goto bail_sge;
- }
- /* Make sure entry is read after head index is read. */
- smp_rmb();
- wqe = get_rwqe_ptr(rq, tail);
- if (++tail >= rq->size)
- tail = 0;
- if (init_sge(qp, wqe, &rlen, &rsge))
- break;
- wq->tail = tail;
+ /* Validate tail before using it since it is user writable. */
+ if (tail >= rq->size)
+ tail = 0;
+ if (unlikely(tail == wq->head)) {
+ spin_unlock_irqrestore(&rq->lock, flags);
+ dev->n_pkt_drops++;
+ goto drop;
+ }
+ wqe = get_rwqe_ptr(rq, tail);
+ if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) {
+ spin_unlock_irqrestore(&rq->lock, flags);
+ dev->n_pkt_drops++;
+ goto drop;
}
/* Silently drop packets which are too big. */
- if (wc->byte_len > rlen) {
+ if (wc.byte_len > rlen) {
spin_unlock_irqrestore(&rq->lock, flags);
dev->n_pkt_drops++;
- goto bail_sge;
+ goto drop;
}
+ if (++tail >= rq->size)
+ tail = 0;
wq->tail = tail;
- wc->wr_id = wqe->wr_id;
+ wc.wr_id = wqe->wr_id;
if (handler) {
u32 n;
@@ -221,13 +192,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
} else
spin_unlock_irqrestore(&rq->lock, flags);
- ah_attr = &to_iah(wr->wr.ud.ah)->attr;
+ ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
if (ah_attr->ah_flags & IB_AH_GRH) {
ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
- wc->wc_flags |= IB_WC_GRH;
+ wc.wc_flags |= IB_WC_GRH;
} else
ipath_skip_sge(&rsge, sizeof(struct ib_grh));
- sge = &ss->sge;
+ sge = swqe->sg_list;
while (length) {
u32 len = sge->length;
@@ -241,8 +212,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
sge->length -= len;
sge->sge_length -= len;
if (sge->sge_length == 0) {
- if (--ss->num_sge)
- *sge = *ss->sg_list++;
+ if (--swqe->wr.num_sge)
+ sge++;
} else if (sge->length == 0 && sge->mr != NULL) {
if (++sge->n >= IPATH_SEGSZ) {
if (++sge->m >= sge->mr->mapsz)
@@ -256,123 +227,60 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
}
length -= len;
}
- 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;
+ 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. */
- wc->pkey_index = 0;
- wc->slid = dev->dd->ipath_lid |
+ wc.pkey_index = 0;
+ wc.slid = dev->dd->ipath_lid |
(ah_attr->src_path_bits &
- ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));
- wc->sl = ah_attr->sl;
- wc->dlid_path_bits =
- ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ ((1 << dev->dd->ipath_lmc) - 1));
+ wc.sl = ah_attr->sl;
+ wc.dlid_path_bits =
+ ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1);
+ wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
- ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
- wr->send_flags & IB_SEND_SOLICITED);
-
-bail_sge:
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+ swqe->wr.send_flags & IB_SEND_SOLICITED);
+drop:
kfree(rsge.sg_list);
-done:
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
+send_comp:
+ ipath_send_complete(sqp, swqe, IB_WC_SUCCESS);
}
/**
- * ipath_post_ud_send - post a UD send on QP
+ * ipath_make_ud_req - construct a UD request packet
* @qp: the QP
- * @wr: the work request
*
- * Note that we actually send the data as it is posted instead of putting
- * the request into a ring buffer. If we wanted to use a ring buffer,
- * we would need to save a reference to the destination address in the SWQE.
+ * Return 1 if constructed; otherwise, return 0.
*/
-int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+int ipath_make_ud_req(struct ipath_qp *qp)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_other_headers *ohdr;
struct ib_ah_attr *ah_attr;
- struct ipath_sge_state ss;
- struct ipath_sge *sg_list;
- struct ib_wc wc;
- u32 hwords;
+ struct ipath_swqe *wqe;
u32 nwords;
- u32 len;
u32 extra_bytes;
u32 bth0;
u16 lrh0;
u16 lid;
- int i;
- int ret;
+ int ret = 0;
- if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
- ret = 0;
+ if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)))
goto bail;
- }
- if (wr->wr.ud.ah->pd != qp->ibqp.pd) {
- ret = -EPERM;
+ if (qp->s_cur == qp->s_head)
goto bail;
- }
- /* IB spec says that num_sge == 0 is OK. */
- if (wr->num_sge > qp->s_max_sge) {
- ret = -EINVAL;
- goto bail;
- }
-
- if (wr->num_sge > 1) {
- sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list),
- GFP_ATOMIC);
- if (!sg_list) {
- ret = -ENOMEM;
- goto bail;
- }
- } else
- sg_list = NULL;
-
- /* Check the buffer to send. */
- ss.sg_list = sg_list;
- ss.sge.mr = NULL;
- ss.sge.vaddr = NULL;
- ss.sge.length = 0;
- ss.sge.sge_length = 0;
- ss.num_sge = 0;
- len = 0;
- for (i = 0; i < wr->num_sge; i++) {
- /* Check LKEY */
- if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
- ret = -EINVAL;
- goto bail;
- }
-
- if (wr->sg_list[i].length == 0)
- continue;
- if (!ipath_lkey_ok(qp, ss.num_sge ?
- sg_list + ss.num_sge - 1 : &ss.sge,
- &wr->sg_list[i], 0)) {
- ret = -EINVAL;
- goto bail;
- }
- len += wr->sg_list[i].length;
- ss.num_sge++;
- }
- /* Check for invalid packet size. */
- if (len > dev->dd->ipath_ibmtu) {
- ret = -EINVAL;
- goto bail;
- }
- extra_bytes = (4 - len) & 3;
- nwords = (len + extra_bytes) >> 2;
+ wqe = get_swqe_ptr(qp, qp->s_cur);
/* Construct the header. */
- ah_attr = &to_iah(wr->wr.ud.ah)->attr;
- if (ah_attr->dlid == 0) {
- ret = -EINVAL;
- goto bail;
- }
+ ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
dev->n_multicast_xmit++;
@@ -381,74 +289,63 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
} else {
dev->n_unicast_xmit++;
lid = ah_attr->dlid &
- ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ ~((1 << dev->dd->ipath_lmc) - 1);
if (unlikely(lid == dev->dd->ipath_lid)) {
- /*
- * Pass in an uninitialized ib_wc to save stack
- * space.
- */
- ipath_ud_loopback(qp, &ss, len, wr, &wc);
+ ipath_ud_loopback(qp, wqe);
goto done;
}
}
+
+ extra_bytes = -wqe->length & 3;
+ nwords = (wqe->length + extra_bytes) >> 2;
+
+ /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
+ qp->s_hdrwords = 7;
+ if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
+ qp->s_hdrwords++;
+ qp->s_cur_size = wqe->length;
+ qp->s_cur_sge = &qp->s_sge;
+ qp->s_wqe = wqe;
+ qp->s_sge.sge = wqe->sg_list[0];
+ qp->s_sge.sg_list = wqe->sg_list + 1;
+ qp->s_sge.num_sge = wqe->wr.num_sge;
+
if (ah_attr->ah_flags & IB_AH_GRH) {
/* Header size in 32-bit words. */
- hwords = 17;
+ qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
+ &ah_attr->grh,
+ qp->s_hdrwords, nwords);
lrh0 = IPATH_LRH_GRH;
ohdr = &qp->s_hdr.u.l.oth;
- qp->s_hdr.u.l.grh.version_tclass_flow =
- cpu_to_be32((6 << 28) |
- (ah_attr->grh.traffic_class << 20) |
- ah_attr->grh.flow_label);
- qp->s_hdr.u.l.grh.paylen =
- cpu_to_be16(((wr->opcode ==
- IB_WR_SEND_WITH_IMM ? 6 : 5) +
- nwords + SIZE_OF_CRC) << 2);
- /* next_hdr is defined by C8-7 in ch. 8.4.1 */
- qp->s_hdr.u.l.grh.next_hdr = 0x1B;
- qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit;
- /* The SGID is 32-bit aligned. */
- qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
- dev->gid_prefix;
- qp->s_hdr.u.l.grh.sgid.global.interface_id =
- dev->dd->ipath_guid;
- qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid;
/*
* Don't worry about sending to locally attached multicast
* QPs. It is unspecified by the spec. what happens.
*/
} else {
/* Header size in 32-bit words. */
- hwords = 7;
lrh0 = IPATH_LRH_BTH;
ohdr = &qp->s_hdr.u.oth;
}
- if (wr->opcode == IB_WR_SEND_WITH_IMM) {
- ohdr->u.ud.imm_data = wr->imm_data;
- wc.imm_data = wr->imm_data;
- hwords += 1;
+ if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+ ohdr->u.ud.imm_data = wqe->wr.imm_data;
bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
- } else if (wr->opcode == IB_WR_SEND) {
- wc.imm_data = 0;
+ } else
bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
- } else {
- ret = -EINVAL;
- goto bail;
- }
lrh0 |= ah_attr->sl << 4;
if (qp->ibqp.qp_type == IB_QPT_SMI)
lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */
qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
- qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
+ qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
+ SIZE_OF_CRC);
lid = dev->dd->ipath_lid;
if (lid) {
lid |= ah_attr->src_path_bits &
- ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ ((1 << dev->dd->ipath_lmc) - 1);
qp->s_hdr.lrh[3] = cpu_to_be16(lid);
} else
qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
- if (wr->send_flags & IB_SEND_SOLICITED)
+ if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
bth0 |= extra_bytes << 20;
bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
@@ -460,38 +357,20 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
ah_attr->dlid != IPATH_PERMISSIVE_LID ?
__constant_cpu_to_be32(IPATH_MULTICAST_QPN) :
- cpu_to_be32(wr->wr.ud.remote_qpn);
- /* XXX Could lose a PSN count but not worth locking */
+ cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
/*
* Qkeys with the high order bit set mean use the
* qkey from the QP context instead of the WR (see 10.2.5).
*/
- ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ?
- qp->qkey : wr->wr.ud.remote_qkey);
+ ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
+ qp->qkey : wqe->wr.wr.ud.remote_qkey);
ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
- if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr,
- len, &ss))
- dev->n_no_piobuf++;
done:
- /* Queue the completion status entry. */
- if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
- (wr->send_flags & IB_SEND_SIGNALED)) {
- wc.wr_id = wr->wr_id;
- wc.status = IB_WC_SUCCESS;
- wc.vendor_err = 0;
- wc.opcode = IB_WC_SEND;
- wc.byte_len = len;
- wc.qp = &qp->ibqp;
- wc.src_qp = 0;
- wc.wc_flags = 0;
- /* XXX initialize other fields? */
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
- }
- kfree(sg_list);
-
- ret = 0;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
+ ret = 1;
bail:
return ret;
@@ -672,7 +551,8 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* Save the LMC lower bits if the destination LID is a unicast LID.
*/
wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 :
- dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ dlid & ((1 << dev->dd->ipath_lmc) - 1);
+ wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
(ohdr->bth[0] &
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 27034d38b3dd..0190edc8044e 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -171,32 +171,6 @@ int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
return ret;
}
-/**
- * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared
- * @start_page: the page to lock
- * @p: the output page structure
- *
- * This is similar to ipath_get_user_pages, but it's always one page, and we
- * mark the page as locked for I/O, and shared. This is used for the user
- * process page that contains the destination address for the rcvhdrq tail
- * update, so we need to have the vma. If we don't do this, the page can be
- * taken away from us on fork, even if the child never touches it, and then
- * the user process never sees the tail register updates.
- */
-int ipath_get_user_pages_nocopy(unsigned long page, struct page **p)
-{
- struct vm_area_struct *vma;
- int ret;
-
- down_write(&current->mm->mmap_sem);
-
- ret = __get_user_pages(page, 1, p, &vma);
-
- up_write(&current->mm->mmap_sem);
-
- return ret;
-}
-
void ipath_release_user_pages(struct page **p, size_t num_pages)
{
down_write(&current->mm->mmap_sem);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 65f7181e9cf8..74f77e7c2c1b 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -230,6 +230,121 @@ 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);
+}
+
+/**
+ * ipath_post_one_send - post one RC, UC, or UD send work request
+ * @qp: the QP to post on
+ * @wr: the work request to send
+ */
+static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+{
+ struct ipath_swqe *wqe;
+ u32 next;
+ int i;
+ int j;
+ int acc;
+ int ret;
+ unsigned long flags;
+
+ 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;
+ }
+
+ /* IB spec says that num_sge == 0 is OK. */
+ if (wr->num_sge > qp->s_max_sge)
+ goto bail_inval;
+
+ /*
+ * Don't allow RDMA reads or atomic operations on UC or
+ * undefined operations.
+ * Make sure buffer is large enough to hold the result for atomics.
+ */
+ if (qp->ibqp.qp_type == IB_QPT_UC) {
+ if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
+ goto bail_inval;
+ } else if (qp->ibqp.qp_type == IB_QPT_UD) {
+ /* Check UD opcode */
+ if (wr->opcode != IB_WR_SEND &&
+ wr->opcode != IB_WR_SEND_WITH_IMM)
+ goto bail_inval;
+ /* Check UD destination address PD */
+ if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+ goto bail_inval;
+ } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
+ goto bail_inval;
+ else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
+ (wr->num_sge == 0 ||
+ wr->sg_list[0].length < sizeof(u64) ||
+ wr->sg_list[0].addr & (sizeof(u64) - 1)))
+ goto bail_inval;
+ else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic)
+ goto bail_inval;
+
+ next = qp->s_head + 1;
+ if (next >= qp->s_size)
+ next = 0;
+ if (next == qp->s_last)
+ goto bail_inval;
+
+ 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 ?
+ IB_ACCESS_LOCAL_WRITE : 0;
+ for (i = 0, j = 0; i < wr->num_sge; i++) {
+ u32 length = wr->sg_list[i].length;
+ int ok;
+
+ if (length == 0)
+ continue;
+ ok = ipath_lkey_ok(qp, &wqe->sg_list[j],
+ &wr->sg_list[i], acc);
+ if (!ok)
+ goto bail_inval;
+ wqe->length += length;
+ j++;
+ }
+ wqe->wr.num_sge = j;
+ }
+ if (qp->ibqp.qp_type == IB_QPT_UC ||
+ qp->ibqp.qp_type == IB_QPT_RC) {
+ if (wqe->length > 0x80000000U)
+ goto bail_inval;
+ } else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
+ goto bail_inval;
+ qp->s_head = next;
+
+ ret = 0;
+ goto bail;
+
+bail_inval:
+ ret = -EINVAL;
+bail:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ return ret;
+}
+
/**
* ipath_post_send - post a send on a QP
* @ibqp: the QP to post the send on
@@ -244,35 +359,17 @@ static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ipath_qp *qp = to_iqp(ibqp);
int err = 0;
- /* Check that state is OK to post send. */
- if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) {
- *bad_wr = wr;
- err = -EINVAL;
- goto bail;
- }
-
for (; wr; wr = wr->next) {
- switch (qp->ibqp.qp_type) {
- case IB_QPT_UC:
- case IB_QPT_RC:
- err = ipath_post_ruc_send(qp, wr);
- break;
-
- case IB_QPT_SMI:
- case IB_QPT_GSI:
- case IB_QPT_UD:
- err = ipath_post_ud_send(qp, wr);
- break;
-
- default:
- err = -EINVAL;
- }
+ err = ipath_post_one_send(qp, wr);
if (err) {
*bad_wr = wr;
- break;
+ goto bail;
}
}
+ /* Try to do the send work in the caller's context. */
+ ipath_do_send((unsigned long) qp);
+
bail:
return err;
}
@@ -416,7 +513,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data,
/* Check for a valid destination LID (see ch. 7.11.1). */
lid = be16_to_cpu(hdr->lrh[1]);
if (lid < IPATH_MULTICAST_LID_BASE) {
- lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ lid &= ~((1 << dev->dd->ipath_lmc) - 1);
if (unlikely(lid != dev->dd->ipath_lid)) {
dev->rcv_errors++;
goto bail;
@@ -488,7 +585,7 @@ bail:;
* This is called from ipath_do_rcv_timer() at interrupt level to check for
* QPs which need retransmits and to collect performance numbers.
*/
-void ipath_ib_timer(struct ipath_ibdev *dev)
+static void ipath_ib_timer(struct ipath_ibdev *dev)
{
struct ipath_qp *resend = NULL;
struct list_head *last;
@@ -631,7 +728,7 @@ static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
#endif
static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
- u32 length)
+ u32 length, unsigned flush_wc)
{
u32 extra = 0;
u32 data = 0;
@@ -641,11 +738,11 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
u32 len = ss->sge.length;
u32 off;
- BUG_ON(len == 0);
if (len > length)
len = length;
if (len > ss->sge.sge_length)
len = ss->sge.sge_length;
+ BUG_ON(len == 0);
/* If the source address is not aligned, try to align it. */
off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
if (off) {
@@ -757,36 +854,25 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
}
/* Update address before sending packet. */
update_sge(ss, length);
- /* must flush early everything before trigger word */
- ipath_flush_wc();
- __raw_writel(last, piobuf);
- /* be sure trigger word is written */
- ipath_flush_wc();
+ if (flush_wc) {
+ /* must flush early everything before trigger word */
+ ipath_flush_wc();
+ __raw_writel(last, piobuf);
+ /* be sure trigger word is written */
+ ipath_flush_wc();
+ } else
+ __raw_writel(last, piobuf);
}
-/**
- * ipath_verbs_send - send a packet
- * @dd: the infinipath device
- * @hdrwords: the number of words in the header
- * @hdr: the packet header
- * @len: the length of the packet in bytes
- * @ss: the SGE to send
- */
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
- u32 *hdr, u32 len, struct ipath_sge_state *ss)
+static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords,
+ struct ipath_sge_state *ss, u32 len,
+ u32 plen, u32 dwords)
{
+ struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
u32 __iomem *piobuf;
- u32 plen;
+ unsigned flush_wc;
int ret;
- /* +1 is for the qword padding of pbc */
- plen = hdrwords + ((len + 3) >> 2) + 1;
- if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
- ret = -EINVAL;
- goto bail;
- }
-
- /* Get a PIO buffer to use. */
piobuf = ipath_getpiobuf(dd, NULL);
if (unlikely(piobuf == NULL)) {
ret = -EBUSY;
@@ -799,51 +885,90 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
* or WC buffer can be written out of order.
*/
writeq(plen, piobuf);
- ipath_flush_wc();
piobuf += 2;
+
+ flush_wc = dd->ipath_flags & IPATH_PIO_FLUSH_WC;
if (len == 0) {
/*
* If there is just the header portion, must flush before
* writing last word of header for correctness, and after
* the last header word (trigger word).
*/
- __iowrite32_copy(piobuf, hdr, hdrwords - 1);
- ipath_flush_wc();
- __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
- ipath_flush_wc();
- ret = 0;
- goto bail;
+ if (flush_wc) {
+ ipath_flush_wc();
+ __iowrite32_copy(piobuf, hdr, hdrwords - 1);
+ ipath_flush_wc();
+ __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
+ ipath_flush_wc();
+ } else
+ __iowrite32_copy(piobuf, hdr, hdrwords);
+ goto done;
}
+ if (flush_wc)
+ ipath_flush_wc();
__iowrite32_copy(piobuf, hdr, hdrwords);
piobuf += hdrwords;
/* The common case is aligned and contained in one segment. */
if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
!((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
- u32 w;
u32 *addr = (u32 *) ss->sge.vaddr;
/* Update address before sending packet. */
update_sge(ss, len);
- /* Need to round up for the last dword in the packet. */
- w = (len + 3) >> 2;
- __iowrite32_copy(piobuf, addr, w - 1);
- /* must flush early everything before trigger word */
- ipath_flush_wc();
- __raw_writel(addr[w - 1], piobuf + w - 1);
- /* be sure trigger word is written */
- ipath_flush_wc();
- ret = 0;
- goto bail;
+ if (flush_wc) {
+ __iowrite32_copy(piobuf, addr, dwords - 1);
+ /* must flush early everything before trigger word */
+ ipath_flush_wc();
+ __raw_writel(addr[dwords - 1], piobuf + dwords - 1);
+ /* be sure trigger word is written */
+ ipath_flush_wc();
+ } else
+ __iowrite32_copy(piobuf, addr, dwords);
+ goto done;
}
- copy_io(piobuf, ss, len);
+ copy_io(piobuf, ss, len, flush_wc);
+done:
+ if (qp->s_wqe)
+ ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
ret = 0;
-
bail:
return ret;
}
+/**
+ * ipath_verbs_send - send a packet
+ * @qp: the QP to send on
+ * @hdr: the packet header
+ * @hdrwords: the number of words in the header
+ * @ss: the SGE to send
+ * @len: the length of the packet in bytes
+ */
+int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+ u32 hdrwords, struct ipath_sge_state *ss, u32 len)
+{
+ struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
+ u32 plen;
+ int ret;
+ u32 dwords = (len + 3) >> 2;
+
+ /* +1 is for the qword padding of pbc */
+ plen = hdrwords + dwords + 1;
+
+ /* Drop non-VL15 packets if we are not in the active state */
+ if (!(dd->ipath_flags & IPATH_LINKACTIVE) &&
+ qp->ibqp.qp_type != IB_QPT_SMI) {
+ if (qp->s_wqe)
+ ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
+ ret = 0;
+ } else
+ ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords,
+ ss, len, plen, dwords);
+
+ return ret;
+}
+
int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
u64 *rwords, u64 *spkts, u64 *rpkts,
u64 *xmit_wait)
@@ -852,7 +977,6 @@ int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
if (!(dd->ipath_flags & IPATH_INITTED)) {
/* no hardware, freeze, etc. */
- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
ret = -EINVAL;
goto bail;
}
@@ -878,48 +1002,44 @@ bail:
int ipath_get_counters(struct ipath_devdata *dd,
struct ipath_verbs_counters *cntrs)
{
+ struct ipath_cregs const *crp = dd->ipath_cregs;
int ret;
if (!(dd->ipath_flags & IPATH_INITTED)) {
/* no hardware, freeze, etc. */
- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
ret = -EINVAL;
goto bail;
}
cntrs->symbol_error_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+ ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt);
cntrs->link_error_recovery_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+ ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt);
/*
* The link downed counter counts when the other side downs the
* connection. We add in the number of times we downed the link
* due to local link integrity errors to compensate.
*/
cntrs->link_downed_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
+ ipath_snap_cntr(dd, crp->cr_iblinkdowncnt);
cntrs->port_rcv_errors =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
+ ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) +
+ ipath_snap_cntr(dd, crp->cr_rcvovflcnt) +
+ ipath_snap_cntr(dd, crp->cr_portovflcnt) +
+ ipath_snap_cntr(dd, crp->cr_err_rlencnt) +
+ ipath_snap_cntr(dd, crp->cr_invalidrlencnt) +
+ ipath_snap_cntr(dd, crp->cr_errlinkcnt) +
+ ipath_snap_cntr(dd, crp->cr_erricrccnt) +
+ ipath_snap_cntr(dd, crp->cr_errvcrccnt) +
+ ipath_snap_cntr(dd, crp->cr_errlpcrccnt) +
+ ipath_snap_cntr(dd, crp->cr_badformatcnt) +
dd->ipath_rxfc_unsupvl_errs;
cntrs->port_rcv_remphys_errors =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
- cntrs->port_xmit_discards =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
- cntrs->port_xmit_data =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- cntrs->port_rcv_data =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
- cntrs->port_xmit_packets =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
- cntrs->port_rcv_packets =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+ ipath_snap_cntr(dd, crp->cr_rcvebpcnt);
+ cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt);
+ cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt);
+ cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt);
+ cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt);
+ cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt);
cntrs->local_link_integrity_errors =
(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
dd->ipath_lli_errs : dd->ipath_lli_errors;
@@ -1033,25 +1153,26 @@ static int ipath_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
struct ipath_ibdev *dev = to_idev(ibdev);
+ struct ipath_devdata *dd = dev->dd;
enum ib_mtu mtu;
- u16 lid = dev->dd->ipath_lid;
+ u16 lid = dd->ipath_lid;
u64 ibcstat;
memset(props, 0, sizeof(*props));
props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE);
- props->lmc = dev->mkeyprot_resv_lmc & 7;
+ props->lmc = dd->ipath_lmc;
props->sm_lid = dev->sm_lid;
props->sm_sl = dev->sm_sl;
- ibcstat = dev->dd->ipath_lastibcstat;
+ ibcstat = dd->ipath_lastibcstat;
props->state = ((ibcstat >> 4) & 0x3) + 1;
/* See phys_state_show() */
props->phys_state = ipath_cvt_physportstate[
- dev->dd->ipath_lastibcstat & 0xf];
+ dd->ipath_lastibcstat & 0xf];
props->port_cap_flags = dev->port_cap_flags;
props->gid_tbl_len = 1;
props->max_msg_sz = 0x80000000;
- props->pkey_tbl_len = ipath_get_npkeys(dev->dd);
- props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) -
+ props->pkey_tbl_len = ipath_get_npkeys(dd);
+ props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) -
dev->z_pkey_violations;
props->qkey_viol_cntr = dev->qkey_violations;
props->active_width = IB_WIDTH_4X;
@@ -1061,12 +1182,12 @@ static int ipath_query_port(struct ib_device *ibdev,
props->init_type_reply = 0;
/*
- * Note: the chips support a maximum MTU of 4096, but the driver
+ * Note: the chip supports a maximum MTU of 4096, but the driver
* hasn't implemented this feature yet, so set the maximum value
* to 2048.
*/
props->max_mtu = IB_MTU_2048;
- switch (dev->dd->ipath_ibmtu) {
+ switch (dd->ipath_ibmtu) {
case 4096:
mtu = IB_MTU_4096;
break;
@@ -1415,9 +1536,7 @@ static int disable_timer(struct ipath_devdata *dd)
{
/* Disable GPIO bit 2 interrupt */
if (dd->ipath_flags & IPATH_GPIO_INTR) {
- u64 val;
/* Disable GPIO bit 2 interrupt */
- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
dd->ipath_gpio_mask);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index f3d1f2cee6f8..6ccb54f104a3 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -42,7 +42,7 @@
#include <rdma/ib_pack.h>
#include <rdma/ib_user_verbs.h>
-#include "ipath_layer.h"
+#include "ipath_kernel.h"
#define IPATH_MAX_RDMA_ATOMIC 4
@@ -61,6 +61,7 @@
*/
#define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1)
+/* AETH NAK opcode values */
#define IB_RNR_NAK 0x20
#define IB_NAK_PSN_ERROR 0x60
#define IB_NAK_INVALID_REQUEST 0x61
@@ -68,6 +69,7 @@
#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63
#define IB_NAK_INVALID_RD_REQUEST 0x64
+/* Flags for checking QP state (see ib_ipath_state_ops[]) */
#define IPATH_POST_SEND_OK 0x01
#define IPATH_POST_RECV_OK 0x02
#define IPATH_PROCESS_RECV_OK 0x04
@@ -189,7 +191,11 @@ struct ipath_mmap_info {
struct ipath_cq_wc {
u32 head; /* index of next entry to fill */
u32 tail; /* index of next ib_poll_cq() entry */
- struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */
+ union {
+ /* these are actually size ibcq.cqe + 1 */
+ struct ib_uverbs_wc uqueue[0];
+ struct ib_wc kqueue[0];
+ };
};
/*
@@ -241,7 +247,7 @@ struct ipath_mregion {
*/
struct ipath_sge {
struct ipath_mregion *mr;
- void *vaddr; /* current pointer into the segment */
+ void *vaddr; /* kernel virtual address of segment */
u32 sge_length; /* length of the SGE */
u32 length; /* remaining length of the segment */
u16 m; /* current index: mr->map[m] */
@@ -409,6 +415,7 @@ struct ipath_qp {
u32 s_ssn; /* SSN of tail entry */
u32 s_lsn; /* limit sequence number (credit) */
struct ipath_swqe *s_wq; /* send work queue */
+ struct ipath_swqe *s_wqe;
struct ipath_rq r_rq; /* receive work queue */
struct ipath_sge r_sg_list[0]; /* verified SGEs */
};
@@ -494,7 +501,7 @@ struct ipath_ibdev {
int ib_unit; /* This is the device number */
u16 sm_lid; /* in host order */
u8 sm_sl;
- u8 mkeyprot_resv_lmc;
+ u8 mkeyprot;
/* non-zero when timer is set */
unsigned long mkey_lease_timeout;
@@ -669,7 +676,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
int ipath_destroy_qp(struct ib_qp *ibqp);
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
@@ -685,8 +692,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc);
void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
- u32 *hdr, u32 len, struct ipath_sge_state *ss);
+int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+ u32 hdrwords, struct ipath_sge_state *ss, u32 len);
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
@@ -694,8 +701,6 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
-int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr);
-
void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
@@ -735,6 +740,8 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
int ipath_destroy_srq(struct ib_srq *ibsrq);
+void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
+
int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
@@ -782,22 +789,30 @@ void ipath_update_mmap_info(struct ipath_ibdev *dev,
int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
-
void ipath_insert_rnr_queue(struct ipath_qp *qp);
+int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+ u32 *lengthp, struct ipath_sge_state *ss);
+
int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
struct ib_global_route *grh, u32 hwords, u32 nwords);
-void ipath_do_ruc_send(unsigned long data);
+void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 bth0, u32 bth2);
+
+void ipath_do_send(unsigned long data);
+
+void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
+ enum ib_wc_status status);
-int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p);
+int ipath_make_rc_req(struct ipath_qp *qp);
-int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p);
+int ipath_make_uc_req(struct ipath_qp *qp);
+
+int ipath_make_ud_req(struct ipath_qp *qp);
int ipath_register_ib_device(struct ipath_devdata *);
@@ -807,8 +822,6 @@ void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
int ipath_ib_piobufavail(struct ipath_ibdev *);
-void ipath_ib_timer(struct ipath_ibdev *);
-
unsigned ipath_get_npkeys(struct ipath_devdata *);
u32 ipath_get_cr_errpkey(struct ipath_devdata *);
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 660b27aecae5..8bf44daf45ec 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -389,7 +389,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
wc->opcode = IB_WC_SEND;
break;
case MLX4_OPCODE_RDMA_READ:
- wc->opcode = IB_WC_SEND;
+ wc->opcode = IB_WC_RDMA_READ;
wc->byte_len = be32_to_cpu(cqe->byte_cnt);
break;
case MLX4_OPCODE_ATOMIC_CS:
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 333091787c5f..0ed02b7834da 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -109,7 +109,7 @@ int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey,
in_modifier, op_modifier,
MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
- if (!err);
+ if (!err)
memcpy(response_mad, outmailbox->buf, 256);
mlx4_free_cmd_mailbox(dev->dev, inmailbox);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index dde8fe9af47e..d8287d9db41e 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -476,9 +476,48 @@ out:
return err;
}
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "MT%d\n", dev->dev->pdev->device);
+}
+
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32),
+ (int) (dev->dev->caps.fw_ver >> 16) & 0xffff,
+ (int) dev->dev->caps.fw_ver & 0xffff);
+}
+
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "%x\n", dev->dev->rev_id);
+}
+
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id);
+}
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *mlx4_class_attributes[] = {
+ &class_device_attr_hw_rev,
+ &class_device_attr_fw_ver,
+ &class_device_attr_hca_type,
+ &class_device_attr_board_id
+};
+
static void *mlx4_ib_add(struct mlx4_dev *dev)
{
struct mlx4_ib_dev *ibdev;
+ int i;
ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
if (!ibdev) {
@@ -568,6 +607,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach;
ibdev->ib_dev.process_mad = mlx4_ib_process_mad;
+ ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc;
+ ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr;
+ ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr;
+ ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc;
+
if (init_node_data(ibdev))
goto err_map;
@@ -580,6 +624,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (mlx4_ib_mad_init(ibdev))
goto err_reg;
+ for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) {
+ if (class_device_create_file(&ibdev->ib_dev.class_dev,
+ mlx4_class_attributes[i]))
+ goto err_reg;
+ }
+
return ibdev;
err_reg:
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 705ff2fa237e..28697653a370 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -93,6 +93,11 @@ struct mlx4_ib_mr {
struct ib_umem *umem;
};
+struct mlx4_ib_fmr {
+ struct ib_fmr ibfmr;
+ struct mlx4_fmr mfmr;
+};
+
struct mlx4_ib_wq {
u64 *wrid;
spinlock_t lock;
@@ -199,6 +204,10 @@ static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr)
return container_of(ibmr, struct mlx4_ib_mr, ibmr);
}
+static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
+{
+ return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr);
+}
static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp)
{
return container_of(ibqp, struct mlx4_ib_qp, ibqp);
@@ -284,6 +293,13 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
int mlx4_ib_mad_init(struct mlx4_ib_dev *dev);
void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev);
+struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr);
+int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages,
+ u64 iova);
+int mlx4_ib_unmap_fmr(struct list_head *fmr_list);
+int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr);
+
static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
{
return !!(ah->av.g_slid & 0x80);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 85ae906f1d12..7dc91a3e712d 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -96,11 +96,10 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
pages[i++] = sg_dma_address(&chunk->page_list[j]) +
umem->page_size * k;
/*
- * Be friendly to WRITE_MTT firmware
- * command, and pass it chunks of
- * appropriate size.
+ * Be friendly to mlx4_write_mtt() and
+ * pass it chunks of appropriate size.
*/
- if (i == PAGE_SIZE / sizeof (u64) - 2) {
+ if (i == PAGE_SIZE / sizeof (u64)) {
err = mlx4_write_mtt(dev->dev, mtt, n,
i, pages);
if (err)
@@ -182,3 +181,96 @@ int mlx4_ib_dereg_mr(struct ib_mr *ibmr)
return 0;
}
+
+struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc,
+ struct ib_fmr_attr *fmr_attr)
+{
+ struct mlx4_ib_dev *dev = to_mdev(pd->device);
+ struct mlx4_ib_fmr *fmr;
+ int err = -ENOMEM;
+
+ fmr = kmalloc(sizeof *fmr, GFP_KERNEL);
+ if (!fmr)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc),
+ fmr_attr->max_pages, fmr_attr->max_maps,
+ fmr_attr->page_shift, &fmr->mfmr);
+ if (err)
+ goto err_free;
+
+ err = mlx4_mr_enable(to_mdev(pd->device)->dev, &fmr->mfmr.mr);
+ if (err)
+ goto err_mr;
+
+ fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key;
+
+ return &fmr->ibfmr;
+
+err_mr:
+ mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr);
+
+err_free:
+ kfree(fmr);
+
+ return ERR_PTR(err);
+}
+
+int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+ int npages, u64 iova)
+{
+ struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+ struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device);
+
+ return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova,
+ &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey);
+}
+
+int mlx4_ib_unmap_fmr(struct list_head *fmr_list)
+{
+ struct ib_fmr *ibfmr;
+ int err;
+ struct mlx4_dev *mdev = NULL;
+
+ list_for_each_entry(ibfmr, fmr_list, list) {
+ if (mdev && to_mdev(ibfmr->device)->dev != mdev)
+ return -EINVAL;
+ mdev = to_mdev(ibfmr->device)->dev;
+ }
+
+ if (!mdev)
+ return 0;
+
+ list_for_each_entry(ibfmr, fmr_list, list) {
+ struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+
+ mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey);
+ }
+
+ /*
+ * Make sure all MPT status updates are visible before issuing
+ * SYNC_TPT firmware command.
+ */
+ wmb();
+
+ err = mlx4_SYNC_TPT(mdev);
+ if (err)
+ printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when "
+ "unmapping FMRs\n", err);
+
+ return 0;
+}
+
+int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr)
+{
+ struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+ struct mlx4_ib_dev *dev = to_mdev(ibfmr->device);
+ int err;
+
+ err = mlx4_fmr_free(dev->dev, &ifmr->mfmr);
+
+ if (!err)
+ kfree(ifmr);
+
+ return err;
+}
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 40042184ad58..31a480e5b0d0 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -415,9 +415,11 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
return 0;
err_wrid:
- if (pd->uobject && !init_attr->srq)
- mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
- else {
+ if (pd->uobject) {
+ if (!init_attr->srq)
+ mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context),
+ &qp->db);
+ } else {
kfree(qp->sq.wrid);
kfree(qp->rq.wrid);
}
@@ -742,7 +744,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
printk(KERN_ERR "path MTU (%u) is invalid\n",
attr->path_mtu);
- return -EINVAL;
+ goto out;
}
context->mtu_msgmax = (attr->path_mtu << 5) | 31;
}
@@ -781,10 +783,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_AV) {
if (mlx4_set_path(dev, &attr->ah_attr, &context->pri_path,
- attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) {
- err = -EINVAL;
+ attr_mask & IB_QP_PORT ? attr->port_num : qp->port))
goto out;
- }
optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
MLX4_QP_OPTPAR_SCHED_QUEUE);
@@ -798,15 +798,15 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_ALT_PATH) {
if (attr->alt_port_num == 0 ||
attr->alt_port_num > dev->dev->caps.num_ports)
- return -EINVAL;
+ goto out;
if (attr->alt_pkey_index >=
dev->dev->caps.pkey_table_len[attr->alt_port_num])
- return -EINVAL;
+ goto out;
if (mlx4_set_path(dev, &attr->alt_ah_attr, &context->alt_path,
attr->alt_port_num))
- return -EINVAL;
+ goto out;
context->alt_path.pkey_index = attr->alt_pkey_index;
context->alt_path.ackto = attr->alt_timeout << 3;
@@ -1183,12 +1183,86 @@ static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq
return cur + nreq >= wq->max_post;
}
+static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
+ u64 remote_addr, u32 rkey)
+{
+ rseg->raddr = cpu_to_be64(remote_addr);
+ rseg->rkey = cpu_to_be32(rkey);
+ rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add);
+ } else {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare = 0;
+ }
+
+}
+
+static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
+ struct ib_send_wr *wr)
+{
+ memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
+ dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+ dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
+static void set_mlx_icrc_seg(void *dseg)
+{
+ u32 *t = dseg;
+ struct mlx4_wqe_inline_seg *iseg = dseg;
+
+ t[1] = 0;
+
+ /*
+ * Need a barrier here before writing the byte_count field to
+ * make sure that all the data is visible before the
+ * byte_count field is set. Otherwise, if the segment begins
+ * a new cacheline, the HCA prefetcher could grab the 64-byte
+ * chunk and get a valid (!= * 0xffffffff) byte count but
+ * stale data, and end up sending the wrong data.
+ */
+ wmb();
+
+ iseg->byte_count = cpu_to_be32((1 << 31) | 4);
+}
+
+static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+
+ /*
+ * Need a barrier here before writing the byte_count field to
+ * make sure that all the data is visible before the
+ * byte_count field is set. Otherwise, if the segment begins
+ * a new cacheline, the HCA prefetcher could grab the 64-byte
+ * chunk and get a valid (!= * 0xffffffff) byte count but
+ * stale data, and end up sending the wrong data.
+ */
+ wmb();
+
+ dseg->byte_count = cpu_to_be32(sg->length);
+}
+
+static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+ dseg->byte_count = cpu_to_be32(sg->length);
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+}
+
int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
struct mlx4_ib_qp *qp = to_mqp(ibqp);
void *wqe;
struct mlx4_wqe_ctrl_seg *ctrl;
+ struct mlx4_wqe_data_seg *dseg;
unsigned long flags;
int nreq;
int err = 0;
@@ -1238,26 +1312,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.atomic.remote_addr);
- ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.atomic.rkey);
- ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
wqe += sizeof (struct mlx4_wqe_raddr_seg);
- if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
- ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.swap);
- ((struct mlx4_wqe_atomic_seg *) wqe)->compare =
- cpu_to_be64(wr->wr.atomic.compare_add);
- } else {
- ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.compare_add);
- ((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0;
- }
-
+ set_atomic_seg(wqe, wr);
wqe += sizeof (struct mlx4_wqe_atomic_seg);
+
size += (sizeof (struct mlx4_wqe_raddr_seg) +
sizeof (struct mlx4_wqe_atomic_seg)) / 16;
@@ -1266,15 +1327,10 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_RDMA_READ:
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
wqe += sizeof (struct mlx4_wqe_raddr_seg);
size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
-
break;
default:
@@ -1284,13 +1340,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case IB_QPT_UD:
- memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av,
- &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
- ((struct mlx4_wqe_datagram_seg *) wqe)->dqpn =
- cpu_to_be32(wr->wr.ud.remote_qpn);
- ((struct mlx4_wqe_datagram_seg *) wqe)->qkey =
- cpu_to_be32(wr->wr.ud.remote_qkey);
-
+ set_datagram_seg(wqe, wr);
wqe += sizeof (struct mlx4_wqe_datagram_seg);
size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
break;
@@ -1312,27 +1362,27 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
}
- for (i = 0; i < wr->num_sge; ++i) {
- ((struct mlx4_wqe_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mlx4_wqe_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mlx4_wqe_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ /*
+ * Write data segments in reverse order, so as to
+ * overwrite cacheline stamp last within each
+ * cacheline. This avoids issues with WQE
+ * prefetching.
+ */
- wqe += sizeof (struct mlx4_wqe_data_seg);
- size += sizeof (struct mlx4_wqe_data_seg) / 16;
- }
+ dseg = wqe;
+ dseg += wr->num_sge - 1;
+ size += wr->num_sge * (sizeof (struct mlx4_wqe_data_seg) / 16);
/* Add one more inline data segment for ICRC for MLX sends */
- if (qp->ibqp.qp_type == IB_QPT_SMI || qp->ibqp.qp_type == IB_QPT_GSI) {
- ((struct mlx4_wqe_inline_seg *) wqe)->byte_count =
- cpu_to_be32((1 << 31) | 4);
- ((u32 *) wqe)[1] = 0;
- wqe += sizeof (struct mlx4_wqe_data_seg);
+ if (unlikely(qp->ibqp.qp_type == IB_QPT_SMI ||
+ qp->ibqp.qp_type == IB_QPT_GSI)) {
+ set_mlx_icrc_seg(dseg + 1);
size += sizeof (struct mlx4_wqe_data_seg) / 16;
}
+ for (i = wr->num_sge - 1; i >= 0; --i, --dseg)
+ set_data_seg(dseg, wr->sg_list + i);
+
ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size;
@@ -1421,11 +1471,8 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
scat = get_recv_wqe(qp, ind);
- for (i = 0; i < wr->num_sge; ++i) {
- scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
- scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey);
- scat[i].addr = cpu_to_be64(wr->sg_list[i].addr);
- }
+ for (i = 0; i < wr->num_sge; ++i)
+ __set_data_seg(scat + i, wr->sg_list + i);
if (i < qp->rq.max_gs) {
scat[i].byte_count = 0;
@@ -1498,7 +1545,7 @@ static int to_ib_qp_access_flags(int mlx4_flags)
static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
struct mlx4_qp_path *path)
{
- memset(ib_ah_attr, 0, sizeof *path);
+ memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1;
if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
@@ -1515,7 +1562,7 @@ static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
ib_ah_attr->grh.traffic_class =
(be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
ib_ah_attr->grh.flow_label =
- be32_to_cpu(path->tclass_flowlabel) & 0xffffff;
+ be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
memcpy(ib_ah_attr->grh.dgid.raw,
path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
}
@@ -1560,7 +1607,10 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
}
qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f;
- qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
+ if (qp_attr->qp_state == IB_QPS_INIT)
+ qp_attr->port_num = qp->port;
+ else
+ qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING;
@@ -1578,17 +1628,25 @@ int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
done:
qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt;
+ qp_attr->cap.max_recv_sge = qp->rq.max_gs;
+
if (!ibqp->uobject) {
- qp_attr->cap.max_send_wr = qp->sq.wqe_cnt;
- qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt;
- qp_attr->cap.max_send_sge = qp->sq.max_gs;
- qp_attr->cap.max_recv_sge = qp->rq.max_gs;
- qp_attr->cap.max_inline_data = (1 << qp->sq.wqe_shift) -
- send_wqe_overhead(qp->ibqp.qp_type) -
- sizeof (struct mlx4_wqe_inline_seg);
- qp_init_attr->cap = qp_attr->cap;
+ qp_attr->cap.max_send_wr = qp->sq.wqe_cnt;
+ qp_attr->cap.max_send_sge = qp->sq.max_gs;
+ } else {
+ qp_attr->cap.max_send_wr = 0;
+ qp_attr->cap.max_send_sge = 0;
}
+ /*
+ * We don't support inline sends for kernel QPs (yet), and we
+ * don't know what userspace's value should be.
+ */
+ qp_attr->cap.max_inline_data = 0;
+
+ qp_init_attr->cap = qp_attr->cap;
+
return 0;
}
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 408748fb5285..e7e9a3d0dac3 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -251,7 +251,7 @@ int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
if (ret)
return ret;
- srq_attr->srq_limit = be16_to_cpu(limit_watermark);
+ srq_attr->srq_limit = limit_watermark;
srq_attr->max_wr = srq->msrq.max - 1;
srq_attr->max_sge = srq->msrq.max_gs;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index f40558d76475..6966f943f440 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -290,6 +290,12 @@ static int mthca_cmd_post(struct mthca_dev *dev,
err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
op_modifier, op, token, event);
+ /*
+ * Make sure that our HCR writes don't get mixed in with
+ * writes from another CPU starting a FW command.
+ */
+ mmiowb();
+
mutex_unlock(&dev->cmd.hcr_mutex);
return err;
}
@@ -357,8 +363,6 @@ void mthca_cmd_event(struct mthca_dev *dev,
context->status = status;
context->out_param = out_param;
- context->token += dev->cmd.token_mask + 1;
-
complete(&context->done);
}
@@ -380,6 +384,7 @@ static int mthca_cmd_wait(struct mthca_dev *dev,
spin_lock(&dev->cmd.context_lock);
BUG_ON(dev->cmd.free_head < 0);
context = &dev->cmd.context[dev->cmd.free_head];
+ context->token += dev->cmd.token_mask + 1;
dev->cmd.free_head = context->next;
spin_unlock(&dev->cmd.context_lock);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 9bae3cc60603..15aa32eb78b6 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -83,7 +83,7 @@ enum {
MTHCA_QP_CONTEXT_SIZE = 0x200,
MTHCA_RDB_ENTRY_SIZE = 0x20,
MTHCA_AV_SIZE = 0x20,
- MTHCA_MGM_ENTRY_SIZE = 0x40,
+ MTHCA_MGM_ENTRY_SIZE = 0x100,
/* Arbel FW gives us these, but we need them for Tavor */
MTHCA_MPT_ENTRY_SIZE = 0x40,
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index aa563e61de65..60de6f93869e 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -61,13 +61,13 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
#ifdef CONFIG_PCI_MSI
-static int msi_x = 0;
+static int msi_x = 1;
module_param(msi_x, int, 0444);
MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
static int msi = 0;
module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
+MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
#else /* CONFIG_PCI_MSI */
@@ -137,40 +137,23 @@ static const char mthca_version[] __devinitdata =
static int mthca_tune_pci(struct mthca_dev *mdev)
{
- int cap;
- u16 val;
-
if (!tune_pci)
return 0;
/* First try to max out Read Byte Count */
- cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX);
- if (cap) {
- if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) {
- mthca_err(mdev, "Couldn't read PCI-X command register, "
- "aborting.\n");
- return -ENODEV;
- }
- val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2);
- if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) {
- mthca_err(mdev, "Couldn't write PCI-X command register, "
- "aborting.\n");
+ if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) {
+ if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) {
+ mthca_err(mdev, "Couldn't set PCI-X max read count, "
+ "aborting.\n");
return -ENODEV;
}
} else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE))
mthca_info(mdev, "No PCI-X capability, not setting RBC.\n");
- cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP);
- if (cap) {
- if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) {
- mthca_err(mdev, "Couldn't read PCI Express device control "
- "register, aborting.\n");
- return -ENODEV;
- }
- val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);
- if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) {
- mthca_err(mdev, "Couldn't write PCI Express device control "
- "register, aborting.\n");
+ if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) {
+ if (pcie_set_readrq(mdev->pdev, 4096)) {
+ mthca_err(mdev, "Couldn't write PCI Express read request, "
+ "aborting.\n");
return -ENODEV;
}
} else if (mdev->mthca_flags & MTHCA_FLAG_PCIE)
@@ -833,14 +816,19 @@ static int mthca_setup_hca(struct mthca_dev *dev)
err = mthca_NOP(dev, &status);
if (err || status) {
- mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n",
- dev->mthca_flags & MTHCA_FLAG_MSI_X ?
- dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
- dev->pdev->irq);
- if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))
- mthca_err(dev, "Try again with MSI/MSI-X disabled.\n");
- else
+ if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
+ mthca_warn(dev, "NOP command failed to generate interrupt "
+ "(IRQ %d).\n",
+ dev->mthca_flags & MTHCA_FLAG_MSI_X ?
+ dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
+ dev->pdev->irq);
+ mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
+ } else {
+ mthca_err(dev, "NOP command failed to generate interrupt "
+ "(IRQ %d), aborting.\n",
+ dev->pdev->irq);
mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+ }
goto err_cmd_poll;
}
@@ -1115,12 +1103,6 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
goto err_free_dev;
}
- if (msi_x && !mthca_enable_msi_x(mdev))
- mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
- if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
- !pci_enable_msi(pdev))
- mdev->mthca_flags |= MTHCA_FLAG_MSI;
-
if (mthca_cmd_init(mdev)) {
mthca_err(mdev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
@@ -1135,7 +1117,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
goto err_cmd;
if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
- mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n",
+ mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n",
(int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
(int) (mdev->fw_ver & 0xffff),
(int) (mthca_hca_table[hca_type].latest_fw >> 32),
@@ -1144,7 +1126,35 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
}
+ if (msi_x && !mthca_enable_msi_x(mdev))
+ mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
+ else if (msi) {
+ static int warned;
+
+ if (!warned) {
+ printk(KERN_WARNING PFX "WARNING: MSI support will be "
+ "removed from the ib_mthca driver in January 2008.\n");
+ printk(KERN_WARNING " If you are using MSI and cannot "
+ "switch to MSI-X, please tell "
+ "<general@lists.openfabrics.org>.\n");
+ ++warned;
+ }
+
+ if (!pci_enable_msi(pdev))
+ mdev->mthca_flags |= MTHCA_FLAG_MSI;
+ }
+
err = mthca_setup_hca(mdev);
+ if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ pci_disable_msix(pdev);
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+ pci_disable_msi(pdev);
+ mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
+
+ err = mthca_setup_hca(mdev);
+ }
+
if (err)
goto err_close;
@@ -1180,17 +1190,17 @@ err_cleanup:
mthca_cleanup_uar_table(mdev);
err_close:
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ pci_disable_msix(pdev);
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+ pci_disable_msi(pdev);
+
mthca_close_hca(mdev);
err_cmd:
mthca_cmd_cleanup(mdev);
err_free_dev:
- if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
- pci_disable_msix(pdev);
- if (mdev->mthca_flags & MTHCA_FLAG_MSI)
- pci_disable_msi(pdev);
-
ib_dealloc_device(&mdev->ib_dev);
err_free_res:
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 11f1d99db40b..df01b2026a64 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1578,6 +1578,45 @@ static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq,
return cur + nreq >= wq->max;
}
+static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg,
+ u64 remote_addr, u32 rkey)
+{
+ rseg->raddr = cpu_to_be64(remote_addr);
+ rseg->rkey = cpu_to_be32(rkey);
+ rseg->reserved = 0;
+}
+
+static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg,
+ struct ib_send_wr *wr)
+{
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add);
+ } else {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare = 0;
+ }
+
+}
+
+static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg,
+ struct ib_send_wr *wr)
+{
+ useg->lkey = cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
+ useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
+ useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+ useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg,
+ struct ib_send_wr *wr)
+{
+ memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
+ useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+ useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
@@ -1590,8 +1629,15 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int nreq;
int i;
int size;
- int size0 = 0;
- u32 f0 = 0;
+ /*
+ * f0 and size0 are only used if nreq != 0, and they will
+ * always be initialized the first time through the main loop
+ * before nreq is incremented. So nreq cannot become non-zero
+ * without initializing f0 and size0, and they are in fact
+ * never used uninitialized.
+ */
+ int uninitialized_var(size0);
+ u32 uninitialized_var(f0);
int ind;
u8 op0 = 0;
@@ -1636,25 +1682,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.atomic.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.atomic.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
wqe += sizeof (struct mthca_raddr_seg);
- if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.swap);
- ((struct mthca_atomic_seg *) wqe)->compare =
- cpu_to_be64(wr->wr.atomic.compare_add);
- } else {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.compare_add);
- ((struct mthca_atomic_seg *) wqe)->compare = 0;
- }
-
+ set_atomic_seg(wqe, wr);
wqe += sizeof (struct mthca_atomic_seg);
size += (sizeof (struct mthca_raddr_seg) +
sizeof (struct mthca_atomic_seg)) / 16;
@@ -1663,12 +1695,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
case IB_WR_RDMA_READ:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -1683,12 +1712,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -1700,16 +1726,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case UD:
- ((struct mthca_tavor_ud_seg *) wqe)->lkey =
- cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
- ((struct mthca_tavor_ud_seg *) wqe)->av_addr =
- cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
- ((struct mthca_tavor_ud_seg *) wqe)->dqpn =
- cpu_to_be32(wr->wr.ud.remote_qpn);
- ((struct mthca_tavor_ud_seg *) wqe)->qkey =
- cpu_to_be32(wr->wr.ud.remote_qkey);
-
- wqe += sizeof (struct mthca_tavor_ud_seg);
+ set_tavor_ud_seg(wqe, wr);
+ wqe += sizeof (struct mthca_tavor_ud_seg);
size += sizeof (struct mthca_tavor_ud_seg) / 16;
break;
@@ -1734,13 +1752,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
- wqe += sizeof (struct mthca_data_seg);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
+ wqe += sizeof (struct mthca_data_seg);
size += sizeof (struct mthca_data_seg) / 16;
}
@@ -1768,11 +1781,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
mthca_opcode[wr->opcode]);
wmb();
((struct mthca_next_seg *) prev_wqe)->ee_nds =
- cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+ cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size |
((wr->send_flags & IB_SEND_FENCE) ?
MTHCA_NEXT_FENCE : 0));
- if (!size0) {
+ if (!nreq) {
size0 = size;
op0 = mthca_opcode[wr->opcode];
f0 = wr->send_flags & IB_SEND_FENCE ?
@@ -1822,7 +1835,14 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
int nreq;
int i;
int size;
- int size0 = 0;
+ /*
+ * size0 is only used if nreq != 0, and it will always be
+ * initialized the first time through the main loop before
+ * nreq is incremented. So nreq cannot become non-zero
+ * without initializing size0, and it is in fact never used
+ * uninitialized.
+ */
+ int uninitialized_var(size0);
int ind;
void *wqe;
void *prev_wqe;
@@ -1863,13 +1883,8 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
- wqe += sizeof (struct mthca_data_seg);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
+ wqe += sizeof (struct mthca_data_seg);
size += sizeof (struct mthca_data_seg) / 16;
}
@@ -1881,7 +1896,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
((struct mthca_next_seg *) prev_wqe)->ee_nds =
cpu_to_be32(MTHCA_NEXT_DBD | size);
- if (!size0)
+ if (!nreq)
size0 = size;
++ind;
@@ -1903,7 +1918,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
qp->rq.next_ind = ind;
qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
- size0 = 0;
}
}
@@ -1945,8 +1959,15 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int nreq;
int i;
int size;
- int size0 = 0;
- u32 f0 = 0;
+ /*
+ * f0 and size0 are only used if nreq != 0, and they will
+ * always be initialized the first time through the main loop
+ * before nreq is incremented. So nreq cannot become non-zero
+ * without initializing f0 and size0, and they are in fact
+ * never used uninitialized.
+ */
+ int uninitialized_var(size0);
+ u32 uninitialized_var(f0);
int ind;
u8 op0 = 0;
@@ -1966,7 +1987,6 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
- size0 = 0;
/*
* Make sure that descriptors are written before
@@ -2017,26 +2037,12 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.atomic.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.atomic.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
wqe += sizeof (struct mthca_raddr_seg);
- if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.swap);
- ((struct mthca_atomic_seg *) wqe)->compare =
- cpu_to_be64(wr->wr.atomic.compare_add);
- } else {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.compare_add);
- ((struct mthca_atomic_seg *) wqe)->compare = 0;
- }
-
- wqe += sizeof (struct mthca_atomic_seg);
+ set_atomic_seg(wqe, wr);
+ wqe += sizeof (struct mthca_atomic_seg);
size += (sizeof (struct mthca_raddr_seg) +
sizeof (struct mthca_atomic_seg)) / 16;
break;
@@ -2044,12 +2050,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_RDMA_READ:
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -2064,12 +2067,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -2081,14 +2081,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case UD:
- memcpy(((struct mthca_arbel_ud_seg *) wqe)->av,
- to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
- ((struct mthca_arbel_ud_seg *) wqe)->dqpn =
- cpu_to_be32(wr->wr.ud.remote_qpn);
- ((struct mthca_arbel_ud_seg *) wqe)->qkey =
- cpu_to_be32(wr->wr.ud.remote_qkey);
-
- wqe += sizeof (struct mthca_arbel_ud_seg);
+ set_arbel_ud_seg(wqe, wr);
+ wqe += sizeof (struct mthca_arbel_ud_seg);
size += sizeof (struct mthca_arbel_ud_seg) / 16;
break;
@@ -2113,13 +2107,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
- wqe += sizeof (struct mthca_data_seg);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
+ wqe += sizeof (struct mthca_data_seg);
size += sizeof (struct mthca_data_seg) / 16;
}
@@ -2151,7 +2140,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
((wr->send_flags & IB_SEND_FENCE) ?
MTHCA_NEXT_FENCE : 0));
- if (!size0) {
+ if (!nreq) {
size0 = size;
op0 = mthca_opcode[wr->opcode];
f0 = wr->send_flags & IB_SEND_FENCE ?
@@ -2241,20 +2230,12 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mthca_data_seg);
}
- if (i < qp->rq.max_gs) {
- ((struct mthca_data_seg *) wqe)->byte_count = 0;
- ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
- ((struct mthca_data_seg *) wqe)->addr = 0;
- }
+ if (i < qp->rq.max_gs)
+ mthca_set_data_seg_inval(wqe);
qp->wrid[ind] = wr->wr_id;
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index b8f05a526673..3f58c11a62b7 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -509,7 +509,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
for (nreq = 0; wr; wr = wr->next) {
ind = srq->first_free;
- if (ind < 0) {
+ if (unlikely(ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -519,7 +519,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
wqe = get_wqe(srq, ind);
next_ind = *wqe_to_link(wqe);
- if (next_ind < 0) {
+ if (unlikely(next_ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -543,20 +543,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mthca_data_seg);
}
- if (i < srq->max_gs) {
- ((struct mthca_data_seg *) wqe)->byte_count = 0;
- ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
- ((struct mthca_data_seg *) wqe)->addr = 0;
- }
+ if (i < srq->max_gs)
+ mthca_set_data_seg_inval(wqe);
((struct mthca_next_seg *) prev_wqe)->nda_op =
cpu_to_be32((ind << srq->wqe_shift) | 1);
@@ -631,7 +623,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
for (nreq = 0; wr; ++nreq, wr = wr->next) {
ind = srq->first_free;
- if (ind < 0) {
+ if (unlikely(ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -641,7 +633,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
wqe = get_wqe(srq, ind);
next_ind = *wqe_to_link(wqe);
- if (next_ind < 0) {
+ if (unlikely(next_ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -662,20 +654,12 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mthca_data_seg);
}
- if (i < srq->max_gs) {
- ((struct mthca_data_seg *) wqe)->byte_count = 0;
- ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
- ((struct mthca_data_seg *) wqe)->addr = 0;
- }
+ if (i < srq->max_gs)
+ mthca_set_data_seg_inval(wqe);
srq->wrid[ind] = wr->wr_id;
srq->first_free = next_ind;
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h
index e7d2c1e86199..f6a66fe78e48 100644
--- a/drivers/infiniband/hw/mthca/mthca_wqe.h
+++ b/drivers/infiniband/hw/mthca/mthca_wqe.h
@@ -113,4 +113,19 @@ struct mthca_mlx_seg {
__be16 vcrc;
};
+static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg,
+ struct ib_sge *sg)
+{
+ dseg->byte_count = cpu_to_be32(sg->length);
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+}
+
+static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg)
+{
+ dseg->byte_count = 0;
+ dseg->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+ dseg->addr = 0;
+}
+
#endif /* MTHCA_WQE_H */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 285c143115cc..6545fa798b12 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -86,6 +86,7 @@ enum {
IPOIB_MCAST_STARTED = 8,
IPOIB_FLAG_NETIF_STOPPED = 9,
IPOIB_FLAG_ADMIN_CM = 10,
+ IPOIB_FLAG_UMCAST = 11,
IPOIB_MAX_BACKOFF_SECONDS = 16,
@@ -113,7 +114,27 @@ struct ipoib_pseudoheader {
u8 hwaddr[INFINIBAND_ALEN];
};
-struct ipoib_mcast;
+/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
+struct ipoib_mcast {
+ struct ib_sa_mcmember_rec mcmember;
+ struct ib_sa_multicast *mc;
+ struct ipoib_ah *ah;
+
+ struct rb_node rb_node;
+ struct list_head list;
+
+ unsigned long created;
+ unsigned long backoff;
+
+ unsigned long flags;
+ unsigned char logcount;
+
+ struct list_head neigh_list;
+
+ struct sk_buff_head pkt_queue;
+
+ struct net_device *dev;
+};
struct ipoib_rx_buf {
struct sk_buff *skb;
@@ -228,6 +249,8 @@ struct ipoib_dev_priv {
struct net_device *dev;
+ struct napi_struct napi;
+
unsigned long flags;
struct mutex mcast_mutex;
@@ -278,8 +301,6 @@ struct ipoib_dev_priv {
struct ib_event_handler event_handler;
- struct net_device_stats stats;
-
struct net_device *parent;
struct list_head child_intfs;
struct list_head list;
@@ -351,7 +372,7 @@ extern struct workqueue_struct *ipoib_workqueue;
/* functions */
-int ipoib_poll(struct net_device *dev, int *budget);
+int ipoib_poll(struct napi_struct *napi, int budget);
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
@@ -364,6 +385,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah)
int ipoib_open(struct net_device *dev);
int ipoib_add_pkey_attr(struct net_device *dev);
+int ipoib_add_umcast_attr(struct net_device *dev);
void ipoib_send(struct net_device *dev, struct sk_buff *skb,
struct ipoib_ah *address, u32 qpn);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 08b4676a3820..0a0dcb8fdfd1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -430,7 +430,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
ipoib_dbg(priv, "cm recv error "
"(status=%d, wrid=%d vend_err %x)\n",
wc->status, wr_id, wc->vendor_err);
- ++priv->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
goto repost;
}
@@ -457,7 +457,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
* this packet and reuse the old buffer.
*/
ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id);
- ++priv->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
goto repost;
}
@@ -474,8 +474,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb_pull(skb, IPOIB_ENCAP_LEN);
dev->last_rx = jiffies;
- ++priv->stats.rx_packets;
- priv->stats.rx_bytes += skb->len;
+ ++dev->stats.rx_packets;
+ dev->stats.rx_bytes += skb->len;
skb->dev = dev;
/* XXX get correct PACKET_ type here */
@@ -512,8 +512,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
if (unlikely(skb->len > tx->mtu)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
skb->len, tx->mtu);
- ++priv->stats.tx_dropped;
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_dropped;
+ ++dev->stats.tx_errors;
ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN);
return;
}
@@ -532,7 +532,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
tx_req->skb = skb;
addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
dev_kfree_skb_any(skb);
return;
}
@@ -542,7 +542,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
addr, skb->len))) {
ipoib_warn(priv, "post_send failed\n");
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
} else {
@@ -580,8 +580,8 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE);
/* FIXME: is this right? Shouldn't we only increment on success? */
- ++priv->stats.tx_packets;
- priv->stats.tx_bytes += tx_req->skb->len;
+ ++dev->stats.tx_packets;
+ dev->stats.tx_bytes += tx_req->skb->len;
dev_kfree_skb_any(tx_req->skb);
@@ -810,14 +810,16 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- struct ib_qp_init_attr attr = {};
- attr.recv_cq = priv->cq;
- attr.srq = priv->cm.srq;
- attr.cap.max_send_wr = ipoib_sendq_size;
- attr.cap.max_send_sge = 1;
- attr.sq_sig_type = IB_SIGNAL_ALL_WR;
- attr.qp_type = IB_QPT_RC;
- attr.send_cq = cq;
+ struct ib_qp_init_attr attr = {
+ .send_cq = cq,
+ .recv_cq = priv->cq,
+ .srq = priv->cm.srq,
+ .cap.max_send_wr = ipoib_sendq_size,
+ .cap.max_send_sge = 1,
+ .sq_sig_type = IB_SIGNAL_ALL_WR,
+ .qp_type = IB_QPT_RC,
+ };
+
return ib_create_qp(priv->pd, &attr);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 10944888cffd..1a77e79f6b43 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -208,7 +208,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
* this packet and reuse the old buffer.
*/
if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
- ++priv->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
goto repost;
}
@@ -225,8 +225,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb_pull(skb, IPOIB_ENCAP_LEN);
dev->last_rx = jiffies;
- ++priv->stats.rx_packets;
- priv->stats.rx_bytes += skb->len;
+ ++dev->stats.rx_packets;
+ dev->stats.rx_bytes += skb->len;
skb->dev = dev;
/* XXX get correct PACKET_ type here */
@@ -260,8 +260,8 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
ib_dma_unmap_single(priv->ca, tx_req->mapping,
tx_req->skb->len, DMA_TO_DEVICE);
- ++priv->stats.tx_packets;
- priv->stats.tx_bytes += tx_req->skb->len;
+ ++dev->stats.tx_packets;
+ dev->stats.tx_bytes += tx_req->skb->len;
dev_kfree_skb_any(tx_req->skb);
@@ -281,63 +281,58 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
wc->status, wr_id, wc->vendor_err);
}
-int ipoib_poll(struct net_device *dev, int *budget)
+int ipoib_poll(struct napi_struct *napi, int budget)
{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
- int max = min(*budget, dev->quota);
+ struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi);
+ struct net_device *dev = priv->dev;
int done;
int t;
- int empty;
int n, i;
done = 0;
- empty = 0;
- while (max) {
+poll_more:
+ while (done < budget) {
+ int max = (budget - done);
+
t = min(IPOIB_NUM_WC, max);
n = ib_poll_cq(priv->cq, t, priv->ibwc);
- for (i = 0; i < n; ++i) {
+ for (i = 0; i < n; i++) {
struct ib_wc *wc = priv->ibwc + i;
if (wc->wr_id & IPOIB_CM_OP_SRQ) {
++done;
- --max;
ipoib_cm_handle_rx_wc(dev, wc);
} else if (wc->wr_id & IPOIB_OP_RECV) {
++done;
- --max;
ipoib_ib_handle_rx_wc(dev, wc);
} else
ipoib_ib_handle_tx_wc(dev, wc);
}
- if (n != t) {
- empty = 1;
+ if (n != t)
break;
- }
}
- dev->quota -= done;
- *budget -= done;
-
- if (empty) {
- netif_rx_complete(dev);
+ if (done < budget) {
+ netif_rx_complete(dev, napi);
if (unlikely(ib_req_notify_cq(priv->cq,
IB_CQ_NEXT_COMP |
IB_CQ_REPORT_MISSED_EVENTS)) &&
- netif_rx_reschedule(dev, 0))
- return 1;
-
- return 0;
+ netif_rx_reschedule(dev, napi))
+ goto poll_more;
}
- return 1;
+ return done;
}
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
{
- netif_rx_schedule(dev_ptr);
+ struct net_device *dev = dev_ptr;
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+
+ netif_rx_schedule(dev, &priv->napi);
}
static inline int post_send(struct ipoib_dev_priv *priv,
@@ -367,8 +362,8 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN);
- ++priv->stats.tx_dropped;
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_dropped;
+ ++dev->stats.tx_errors;
ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);
return;
}
@@ -388,7 +383,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
DMA_TO_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
dev_kfree_skb_any(skb);
return;
}
@@ -397,7 +392,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
address->ah, qpn, addr, skb->len))) {
ipoib_warn(priv, "post_send failed\n");
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
} else {
@@ -558,6 +553,14 @@ void ipoib_drain_cq(struct net_device *dev)
do {
n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
for (i = 0; i < n; ++i) {
+ /*
+ * Convert any successful completions to flush
+ * errors to avoid passing packets up the
+ * stack after bringing the device down.
+ */
+ if (priv->ibwc[i].status == IB_WC_SUCCESS)
+ priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR;
+
if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
@@ -577,7 +580,6 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
int i;
clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
- netif_poll_disable(dev);
ipoib_cm_dev_stop(dev);
@@ -660,7 +662,6 @@ timeout:
msleep(1);
}
- netif_poll_enable(dev);
ib_req_notify_cq(priv->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 894b1dcdf3eb..e072f3c32ce6 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -98,16 +98,20 @@ int ipoib_open(struct net_device *dev)
ipoib_dbg(priv, "bringing up interface\n");
+ napi_enable(&priv->napi);
set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
if (ipoib_pkey_dev_delay_open(dev))
return 0;
- if (ipoib_ib_dev_open(dev))
+ if (ipoib_ib_dev_open(dev)) {
+ napi_disable(&priv->napi);
return -EINVAL;
+ }
if (ipoib_ib_dev_up(dev)) {
ipoib_ib_dev_stop(dev, 1);
+ napi_disable(&priv->napi);
return -EINVAL;
}
@@ -140,6 +144,7 @@ static int ipoib_stop(struct net_device *dev)
ipoib_dbg(priv, "stopping interface\n");
clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
+ napi_disable(&priv->napi);
netif_stop_queue(dev);
@@ -468,9 +473,10 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
INIT_LIST_HEAD(&path->neigh_list);
memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
- path->pathrec.sgid = priv->local_gid;
- path->pathrec.pkey = cpu_to_be16(priv->pkey);
- path->pathrec.numb_path = 1;
+ path->pathrec.sgid = priv->local_gid;
+ path->pathrec.pkey = cpu_to_be16(priv->pkey);
+ path->pathrec.numb_path = 1;
+ path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
return path;
}
@@ -491,6 +497,7 @@ static int path_rec_start(struct net_device *dev,
IB_SA_PATH_REC_DGID |
IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_NUMB_PATH |
+ IB_SA_PATH_REC_TRAFFIC_CLASS |
IB_SA_PATH_REC_PKEY,
1000, GFP_ATOMIC,
path_rec_completion,
@@ -512,7 +519,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
neigh = ipoib_neigh_alloc(skb->dst->neighbour);
if (!neigh) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
return;
}
@@ -577,7 +584,7 @@ err_list:
err_path:
ipoib_neigh_free(dev, neigh);
err_drop:
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
spin_unlock(&priv->lock);
@@ -626,7 +633,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
} else
__path_add(dev, path);
} else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
@@ -645,7 +652,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
skb_push(skb, sizeof *phdr);
__skb_queue_tail(&path->queue, skb);
} else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
@@ -713,7 +720,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
__skb_queue_tail(&neigh->queue, skb);
spin_unlock(&priv->lock);
} else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
} else {
@@ -739,7 +746,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
IPOIB_QPN(phdr->hwaddr),
IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
dev_kfree_skb_any(skb);
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
goto out;
}
@@ -753,13 +760,6 @@ out:
return NETDEV_TX_OK;
}
-static struct net_device_stats *ipoib_get_stats(struct net_device *dev)
-{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
-
- return &priv->stats;
-}
-
static void ipoib_timeout(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -775,7 +775,7 @@ static void ipoib_timeout(struct net_device *dev)
static int ipoib_hard_header(struct sk_buff *skb,
struct net_device *dev,
unsigned short type,
- void *daddr, void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned len)
{
struct ipoib_header *header;
@@ -856,11 +856,10 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
*to_ipoib_neigh(neigh->neighbour) = NULL;
while ((skb = __skb_dequeue(&neigh->queue))) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
if (ipoib_cm_get(neigh))
@@ -935,6 +934,10 @@ void ipoib_dev_cleanup(struct net_device *dev)
priv->tx_ring = NULL;
}
+static const struct header_ops ipoib_header_ops = {
+ .create = ipoib_hard_header,
+};
+
static void ipoib_setup(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -943,13 +946,12 @@ static void ipoib_setup(struct net_device *dev)
dev->stop = ipoib_stop;
dev->change_mtu = ipoib_change_mtu;
dev->hard_start_xmit = ipoib_start_xmit;
- dev->get_stats = ipoib_get_stats;
dev->tx_timeout = ipoib_timeout;
- dev->hard_header = ipoib_hard_header;
+ dev->header_ops = &ipoib_header_ops;
dev->set_multicast_list = ipoib_set_mcast_list;
dev->neigh_setup = ipoib_neigh_setup_dev;
- dev->poll = ipoib_poll;
- dev->weight = 100;
+
+ netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
dev->watchdog_timeo = HZ;
@@ -973,8 +975,6 @@ static void ipoib_setup(struct net_device *dev)
netif_carrier_off(dev);
- SET_MODULE_OWNER(dev);
-
priv->dev = dev;
spin_lock_init(&priv->lock);
@@ -1017,6 +1017,37 @@ static ssize_t show_pkey(struct device *dev,
}
static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static ssize_t show_umcast(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+
+ return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags));
+}
+
+static ssize_t set_umcast(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+ unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
+
+ if (umcast_val > 0) {
+ set_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+ ipoib_warn(priv, "ignoring multicast groups joined directly "
+ "by userspace\n");
+ } else
+ clear_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+
+ return count;
+}
+static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast);
+
+int ipoib_add_umcast_attr(struct net_device *dev)
+{
+ return device_create_file(&dev->dev, &dev_attr_umcast);
+}
+
static ssize_t create_child(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1083,7 +1114,7 @@ static struct net_device *ipoib_add_port(const char *format,
if (result) {
printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n",
hca->name, port, result);
- goto alloc_mem_failed;
+ goto device_init_failed;
}
/*
@@ -1099,7 +1130,7 @@ static struct net_device *ipoib_add_port(const char *format,
if (result) {
printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n",
hca->name, port, result);
- goto alloc_mem_failed;
+ goto device_init_failed;
} else
memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid));
@@ -1134,6 +1165,8 @@ static struct net_device *ipoib_add_port(const char *format,
goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
+ if (ipoib_add_umcast_attr(priv->dev))
+ goto sysfs_failed;
if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
goto sysfs_failed;
if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index aae367057a56..827820ec66d1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -57,28 +57,6 @@ MODULE_PARM_DESC(mcast_debug_level,
static DEFINE_MUTEX(mcast_mutex);
-/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
-struct ipoib_mcast {
- struct ib_sa_mcmember_rec mcmember;
- struct ib_sa_multicast *mc;
- struct ipoib_ah *ah;
-
- struct rb_node rb_node;
- struct list_head list;
-
- unsigned long created;
- unsigned long backoff;
-
- unsigned long flags;
- unsigned char logcount;
-
- struct list_head neigh_list;
-
- struct sk_buff_head pkt_queue;
-
- struct net_device *dev;
-};
-
struct ipoib_mcast_iter {
struct net_device *dev;
union ib_gid mgid;
@@ -125,7 +103,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
}
spin_lock_irqsave(&priv->tx_lock, flags);
- priv->stats.tx_dropped += tx_dropped;
+ dev->stats.tx_dropped += tx_dropped;
spin_unlock_irqrestore(&priv->tx_lock, flags);
kfree(mcast);
@@ -320,7 +298,7 @@ ipoib_mcast_sendonly_join_complete(int status,
/* Flush out any queued packets */
spin_lock_irq(&priv->tx_lock);
while (!skb_queue_empty(&mcast->pkt_queue)) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
}
spin_unlock_irq(&priv->tx_lock);
@@ -675,7 +653,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
if (!test_bit(IPOIB_MCAST_STARTED, &priv->flags) ||
!priv->broadcast ||
!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
goto unlock;
}
@@ -690,7 +668,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
if (!mcast) {
ipoib_warn(priv, "unable to allocate memory for "
"multicast structure\n");
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
goto out;
}
@@ -705,7 +683,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
skb_queue_tail(&mcast->pkt_queue, skb);
else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
@@ -783,6 +761,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)
struct ipoib_mcast *mcast, *tmcast;
LIST_HEAD(remove_list);
unsigned long flags;
+ struct ib_sa_mcmember_rec rec;
ipoib_dbg_mcast(priv, "restarting multicast task\n");
@@ -816,6 +795,14 @@ void ipoib_mcast_restart_task(struct work_struct *work)
if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
struct ipoib_mcast *nmcast;
+ /* ignore group which is directly joined by userspace */
+ if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) &&
+ !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) {
+ ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid "
+ IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
+ continue;
+ }
+
/* Not found or send-only group, let's add a new entry */
ipoib_dbg_mcast(priv, "adding multicast entry for mgid "
IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 982eb88e27ec..3c6e45db0ab5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -185,7 +185,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
goto out_free_cq;
init_attr.send_cq = priv->cq;
- init_attr.recv_cq = priv->cq,
+ init_attr.recv_cq = priv->cq;
priv->qp = ib_create_qp(priv->pd, &init_attr);
if (IS_ERR(priv->qp)) {
@@ -211,6 +211,7 @@ out_free_cq:
out_free_mr:
ib_dereg_mr(priv->mr);
+ ipoib_cm_dev_cleanup(dev);
out_free_pd:
ib_dealloc_pd(priv->pd);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 6762988439d1..293f5b892e3f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -119,6 +119,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
+ if (ipoib_add_umcast_attr(priv->dev))
+ goto sysfs_failed;
if (device_create_file(&priv->dev->dev, &dev_attr_parent))
goto sysfs_failed;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index effdee299b0c..bad8dacafd10 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -548,6 +548,7 @@ iscsi_iser_ep_disconnect(__u64 ep_handle)
}
static struct scsi_host_template iscsi_iser_sht = {
+ .module = THIS_MODULE,
.name = "iSCSI Initiator over iSER, v." DRV_VER,
.queuecommand = iscsi_queuecommand,
.can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
@@ -637,7 +638,7 @@ static int __init iser_init(void)
ig.desc_cache = kmem_cache_create("iser_descriptors",
sizeof (struct iser_desc),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (ig.desc_cache == NULL)
return -ENOMEM;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index e2353701e8bb..1ee867b1b341 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -310,8 +310,6 @@ int iser_conn_init(struct iser_conn **ib_conn);
void iser_conn_terminate(struct iser_conn *ib_conn);
-void iser_conn_release(struct iser_conn *ib_conn);
-
void iser_rcv_completion(struct iser_desc *desc,
unsigned long dto_xfer_len);
@@ -329,9 +327,6 @@ void iser_reg_single(struct iser_device *device,
struct iser_regd_buf *regd_buf,
enum dma_data_direction direction);
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
- enum iser_data_dir cmd_dir);
-
void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
enum iser_data_dir cmd_dir);
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 9ea5b9aaba7c..a6f2303ed14a 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -34,8 +34,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/kfifo.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index fc9f1fd0ae54..e05690e3592f 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -36,8 +36,6 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/highmem.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include "iscsi_iser.h"
@@ -103,8 +101,8 @@ void iser_reg_single(struct iser_device *device,
/**
* iser_start_rdma_unaligned_sg
*/
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
- enum iser_data_dir cmd_dir)
+static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ enum iser_data_dir cmd_dir)
{
int dma_nents;
struct ib_device *dev;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 2044de1164ac..654a4dce0236 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -32,7 +32,6 @@
*
* $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
*/
-#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -311,6 +310,29 @@ static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
}
/**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+static void iser_conn_release(struct iser_conn *ib_conn)
+{
+ struct iser_device *device = ib_conn->device;
+
+ BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+ mutex_lock(&ig.connlist_mutex);
+ list_del(&ib_conn->conn_list);
+ mutex_unlock(&ig.connlist_mutex);
+
+ iser_free_ib_conn_res(ib_conn);
+ ib_conn->device = NULL;
+ /* on EVENT_ADDR_ERROR there's no device yet for this conn */
+ if (device != NULL)
+ iser_device_try_release(device);
+ if (ib_conn->iser_conn)
+ ib_conn->iser_conn->ib_conn = NULL;
+ kfree(ib_conn);
+}
+
+/**
* triggers start of the disconnect procedures and wait for them to be done
*/
void iser_conn_terminate(struct iser_conn *ib_conn)
@@ -550,30 +572,6 @@ connect_failure:
}
/**
- * Frees all conn objects and deallocs conn descriptor
- */
-void iser_conn_release(struct iser_conn *ib_conn)
-{
- struct iser_device *device = ib_conn->device;
-
- BUG_ON(ib_conn->state != ISER_CONN_DOWN);
-
- mutex_lock(&ig.connlist_mutex);
- list_del(&ib_conn->conn_list);
- mutex_unlock(&ig.connlist_mutex);
-
- iser_free_ib_conn_res(ib_conn);
- ib_conn->device = NULL;
- /* on EVENT_ADDR_ERROR there's no device yet for this conn */
- if (device != NULL)
- iser_device_try_release(device);
- if (ib_conn->iser_conn)
- ib_conn->iser_conn->ib_conn = NULL;
- kfree(ib_conn);
-}
-
-
-/**
* iser_reg_page_vec - Register physical memory
*
* returns: 0 on success, errno code on failure
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index f01ca182f226..9ccc63886d92 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -75,16 +75,12 @@ module_param(topspin_workarounds, int, 0444);
MODULE_PARM_DESC(topspin_workarounds,
"Enable workarounds for Topspin/Cisco SRP target bugs if != 0");
-static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
-
static int mellanox_workarounds = 1;
module_param(mellanox_workarounds, int, 0444);
MODULE_PARM_DESC(mellanox_workarounds,
"Enable workarounds for Mellanox SRP target bugs if != 0");
-static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
-
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr);
@@ -108,6 +104,24 @@ static const char *srp_target_info(struct Scsi_Host *host)
return host_to_target(host)->target_name;
}
+static int srp_target_is_topspin(struct srp_target_port *target)
+{
+ static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
+ static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d };
+
+ return topspin_workarounds &&
+ (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) ||
+ !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui));
+}
+
+static int srp_target_is_mellanox(struct srp_target_port *target)
+{
+ static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
+
+ return mellanox_workarounds &&
+ !memcmp(&target->ioc_guid, mellanox_oui, sizeof mellanox_oui);
+}
+
static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
gfp_t gfp_mask,
enum dma_data_direction direction)
@@ -271,6 +285,7 @@ static int srp_lookup_path(struct srp_target_port *target)
target->srp_host->dev->dev,
target->srp_host->port,
&target->path,
+ IB_SA_PATH_REC_SERVICE_ID |
IB_SA_PATH_REC_DGID |
IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_NUMB_PATH |
@@ -360,7 +375,7 @@ static int srp_send_req(struct srp_target_port *target)
* zero out the first 8 bytes of our initiator port ID and set
* the second 8 bytes to the local node GUID.
*/
- if (topspin_workarounds && !memcmp(&target->ioc_guid, topspin_oui, 3)) {
+ if (srp_target_is_topspin(target)) {
printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
"activated for target GUID %016llx\n",
(unsigned long long) be64_to_cpu(target->ioc_guid));
@@ -585,8 +600,8 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
if (!dev->fmr_pool)
return -ENODEV;
- if ((ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) &&
- mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
+ if (srp_target_is_mellanox(target) &&
+ (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask))
return -EINVAL;
len = page_cnt = 0;
@@ -1087,8 +1102,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
break;
case IB_CM_REJ_PORT_REDIRECT:
- if (topspin_workarounds &&
- !memcmp(&target->ioc_guid, topspin_oui, 3)) {
+ if (srp_target_is_topspin(target)) {
/*
* Topspin/Cisco SRP gateways incorrectly send
* reject reason code 25 when they mean 24
@@ -1679,6 +1693,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
goto out;
}
target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16));
+ target->path.service_id = target->service_id;
kfree(p);
break;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index d404aa8680ea..27026f7d3c03 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -312,7 +312,7 @@ struct input_event_compat {
#elif defined(CONFIG_S390)
# define COMPAT_TEST test_thread_flag(TIF_31BIT)
#elif defined(CONFIG_MIPS)
-# define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR)
+# define COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
#else
# define COMPAT_TEST test_thread_flag(TIF_32BIT)
#endif
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c59544f7e232..3070c7aa1237 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1067,87 +1067,66 @@ static void input_dev_release(struct device *device)
* Input uevent interface - loading event handlers based on
* device bitfields.
*/
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
const char *name, unsigned long *bitmap, int max)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "%s=", name))
return -ENOMEM;
- *cur_len += input_print_bitmap(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- bitmap, max, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_bitmap(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ bitmap, max, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
struct input_dev *dev)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
- "MODALIAS=");
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- *cur_len += input_print_modalias(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- dev, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ dev, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \
do { \
- int err = input_add_uevent_bm_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- name, bm, max); \
+ int err = input_add_uevent_bm_var(env, name, bm, max); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \
do { \
- int err = input_add_uevent_modalias_var(envp, \
- num_envp, &i, \
- buffer, buffer_size, &len, \
- dev); \
+ int err = input_add_uevent_modalias_var(env, dev); \
if (err) \
return err; \
} while (0)
-static int input_dev_uevent(struct device *device, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct input_dev *dev = to_input_dev(device);
- int i = 0;
- int len = 0;
INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor,
@@ -1179,7 +1158,6 @@ static int input_dev_uevent(struct device *device, char **envp,
INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
- envp[i] = NULL;
return 0;
}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 3154ccd74000..45c4939ced75 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -246,13 +246,12 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
int iforce_get_id_packet(struct iforce *iforce, char *packet)
{
- int status;
-
switch (iforce->bus) {
- case IFORCE_USB:
-
+ case IFORCE_USB: {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
+ int status;
+
iforce->cr.bRequest = packet[0];
iforce->ctrl->dev = iforce->usbdev;
@@ -273,6 +272,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
#else
dbg("iforce_get_id_packet: iforce->bus = USB!");
#endif
+ }
break;
case IFORCE_232:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 3d6820b4465b..e2a3293bc67e 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -22,7 +22,6 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
-#include <linux/irq.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 9b26574f1466..d602b8fa7d46 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -68,6 +68,7 @@ config INPUT_WISTRON_BTNS
select INPUT_POLLDEV
select NEW_LEDS
select LEDS_CLASS
+ select CHECK_SIGNATURE
help
Say Y here for support of Winstron laptop button interface, used on
laptops of various brands, including Acer and Fujitsu-Siemens. If
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 0acc3a123604..e43e92fd9e23 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -31,7 +31,6 @@
#define ACPI_ATLAS_NAME "Atlas ACPI"
#define ACPI_ATLAS_CLASS "Atlas"
-#define ACPI_ATLAS_BUTTON_HID "ASIM0000"
static struct input_dev *input_dev;
@@ -130,10 +129,16 @@ static int atlas_acpi_button_remove(struct acpi_device *device, int type)
return status;
}
+static const struct acpi_device_id atlas_device_ids[] = {
+ {"ASIM0000", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
+
static struct acpi_driver atlas_acpi_driver = {
.name = ACPI_ATLAS_NAME,
.class = ACPI_ATLAS_CLASS,
- .ids = ACPI_ATLAS_BUTTON_HID,
+ .ids = atlas_device_ids,
.ops = {
.add = atlas_acpi_button_add,
.remove = atlas_acpi_button_remove,
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 31989dcd922c..c19f77fbaf2a 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -17,14 +17,20 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/platform_device.h>
-#include <asm/8253pit.h>
#include <asm/io.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
-static DEFINE_SPINLOCK(i8253_beep_lock);
+#ifdef CONFIG_X86
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+#include <asm/8253pit.h>
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -43,7 +49,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
if (value > 20 && value < 32767)
count = PIT_TICK_RATE / value;
- spin_lock_irqsave(&i8253_beep_lock, flags);
+ spin_lock_irqsave(&i8253_lock, flags);
if (count) {
/* enable counter 2 */
@@ -58,7 +64,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
outb(inb_p(0x61) & 0xFC, 0x61);
}
- spin_unlock_irqrestore(&i8253_beep_lock, flags);
+ spin_unlock_irqrestore(&i8253_lock, flags);
return 0;
}
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 60121f10f8d9..b438d998625c 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -247,7 +247,7 @@ static int have_wifi;
static int have_bluetooth;
static int have_leds;
-static int __init dmi_matched(struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
{
const struct key_entry *key;
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e3215267db11..a1804bfdbb8c 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -155,6 +155,8 @@ struct atp {
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
int overflowwarn; /* overflow warning printed? */
int datalen; /* size of an USB urb transfer */
+ int idlecount; /* number of empty packets */
+ struct work_struct work;
};
#define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@ static inline int atp_is_geyser_3(struct atp *dev)
(productId == GEYSER4_JIS_PRODUCT_ID);
}
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+ char data[8];
+ int size;
+
+ size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ATP_GEYSER3_MODE_READ_REQUEST_ID,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ATP_GEYSER3_MODE_REQUEST_VALUE,
+ ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+ if (size != 8) {
+ err("Could not do mode read request from device"
+ " (Geyser 3 mode)");
+ return -EIO;
+ }
+
+ /* Apply the mode switch */
+ data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+ size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ATP_GEYSER3_MODE_REQUEST_VALUE,
+ ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+ if (size != 8) {
+ err("Could not do mode write request to device"
+ " (Geyser 3 mode)");
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+ struct atp *dev = container_of(work, struct atp, work);
+ struct usb_device *udev = dev->udev;
+
+ dev->idlecount = 0;
+ atp_geyser3_init(udev);
+}
+
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
int *z, int *fingers)
{
@@ -277,6 +328,7 @@ static void atp_complete(struct urb* urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
+ int key;
struct atp *dev = urb->context;
switch (urb->status) {
@@ -417,6 +469,7 @@ static void atp_complete(struct urb* urb)
ATP_XFACT, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
ATP_YFACT, &y_z, &y_f);
+ key = dev->data[dev->datalen - 1] & 1;
if (x && y) {
if (dev->x_old != -1) {
@@ -439,8 +492,8 @@ static void atp_complete(struct urb* urb)
}
dev->x_old = x;
dev->y_old = y;
- }
- else if (!x && !y) {
+
+ } else if (!x && !y) {
dev->x_old = dev->y_old = -1;
input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +502,21 @@ static void atp_complete(struct urb* urb)
/* reset the accumulator on release */
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
- }
- input_report_key(dev->input, BTN_LEFT,
- !!dev->data[dev->datalen - 1]);
+ /* Geyser 3 will continue to send packets continually after
+ the first touch unless reinitialised. Do so if it's been
+ idle for a while in order to avoid waking the kernel up
+ several hundred times a second */
+ if (!key && atp_is_geyser_3(dev)) {
+ dev->idlecount++;
+ if (dev->idlecount == 10) {
+ dev->valid = 0;
+ schedule_work(&dev->work);
+ }
+ }
+ }
+ input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
exit:
@@ -480,6 +543,7 @@ static void atp_close(struct input_dev *input)
struct atp *dev = input_get_drvdata(input);
usb_kill_urb(dev->urb);
+ cancel_work_sync(&dev->work);
dev->open = 0;
}
@@ -528,40 +592,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
dev->datalen = 81;
if (atp_is_geyser_3(dev)) {
- /*
- * By default Geyser 3 device sends standard USB HID mouse
- * packets (Report ID 2). This code changes device mode, so it
- * sends raw sensor reports (Report ID 5).
- */
- char data[8];
- int size;
-
- size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_READ_REQUEST_ID,
- USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
- if (size != 8) {
- err("Could not do mode read request from device"
- " (Geyser 3 mode)");
+ /* switch to raw sensor mode */
+ if (atp_geyser3_init(udev))
goto err_free_devs;
- }
-
- /* Apply the mode switch */
- data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
- size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
- if (size != 8) {
- err("Could not do mode write request to device"
- " (Geyser 3 mode)");
- goto err_free_devs;
- }
printk("appletouch Geyser 3 inited.\n");
}
@@ -636,6 +670,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
/* save our data pointer in this interface device */
usb_set_intfdata(iface, dev);
+ INIT_WORK(&dev->work, atp_reinit);
+
return 0;
err_free_buffer:
@@ -669,14 +705,17 @@ static void atp_disconnect(struct usb_interface *iface)
static int atp_suspend(struct usb_interface *iface, pm_message_t message)
{
struct atp *dev = usb_get_intfdata(iface);
+
usb_kill_urb(dev->urb);
dev->valid = 0;
+
return 0;
}
static int atp_resume(struct usb_interface *iface)
{
struct atp *dev = usb_get_intfdata(iface);
+
if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
return -EIO;
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 9561dee120c6..d7de4c53b3d8 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -27,7 +27,7 @@ struct lifebook_data {
static const char *desired_serio_phys;
-static int lifebook_set_serio_phys(struct dmi_system_id *d)
+static int lifebook_set_serio_phys(const struct dmi_system_id *d)
{
desired_serio_phys = d->driver_data;
return 0;
@@ -35,13 +35,13 @@ static int lifebook_set_serio_phys(struct dmi_system_id *d)
static unsigned char lifebook_use_6byte_proto;
-static int lifebook_set_6byte_proto(struct dmi_system_id *d)
+static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
{
lifebook_use_6byte_proto = 1;
return 0;
}
-static struct dmi_system_id lifebook_dmi_table[] = {
+static const struct dmi_system_id lifebook_dmi_table[] = {
{
.ident = "FLORA-ie 55mi",
.matches = {
@@ -117,7 +117,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{
struct lifebook_data *priv = psmouse->private;
struct input_dev *dev1 = psmouse->dev;
- struct input_dev *dev2 = priv->dev2;
+ struct input_dev *dev2 = priv ? priv->dev2 : NULL;
unsigned char *packet = psmouse->packet;
int relative_packet = packet[0] & 0x08;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 666ad3a53fdb..d349c4a5e3e8 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -602,7 +602,7 @@ static int synaptics_reconnect(struct psmouse *psmouse)
#if defined(__i386__)
#include <linux/dmi.h>
-static struct dmi_system_id toshiba_dmi_table[] = {
+static const struct dmi_system_id toshiba_dmi_table[] = {
{
.ident = "Toshiba Satellite",
.matches = {
diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h
index 61e9dfd8419f..8a0dd3574aef 100644
--- a/drivers/input/mouse/touchkit_ps2.h
+++ b/drivers/input/mouse/touchkit_ps2.h
@@ -15,7 +15,8 @@
#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
#else
-inline int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+static inline int touchkit_ps2_detect(struct psmouse *psmouse,
+ int set_properties)
{
return -ENOSYS;
}
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index adef447f23ea..5ce632ca6815 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -21,7 +21,7 @@ if SERIO
config SERIO_I8042
tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
default y
- depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K
+ depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BFIN
---help---
i8042 is the chip over which the standard AT keyboard and PS/2
mouse are connected to the computer. If you use these devices,
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 5a7b49c35539..b10ffae7c39b 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -117,15 +117,13 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
if (ret)
return ret;
- kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
- io = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
+ io = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!kmi || !io) {
ret = -ENOMEM;
goto out;
}
- memset(kmi, 0, sizeof(struct amba_kmi_port));
- memset(io, 0, sizeof(struct serio));
io->id.type = SERIO_8042;
io->write = amba_kmi_write;
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 74f14e097789..3e99df6be084 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -340,8 +340,8 @@ static int __init gscps2_probe(struct parisc_device *dev)
if (dev->id.sversion == 0x96)
hpa += GSC_DINO_OFFSET;
- ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL);
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2port = kzalloc(sizeof(struct gscps2port), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!ps2port || !serio) {
ret = -ENOMEM;
goto fail_nomem;
@@ -349,8 +349,6 @@ static int __init gscps2_probe(struct parisc_device *dev)
dev_set_drvdata(&dev->dev, ps2port);
- memset(ps2port, 0, sizeof(struct gscps2port));
- memset(serio, 0, sizeof(struct serio));
ps2port->port = serio;
ps2port->padev = dev;
ps2port->addr = ioremap_nocache(hpa, GSC_STATUS + 4);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 702a526cf45b..f8fe42148093 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -211,6 +211,16 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ /*
+ * Like DV4017EA does not raise AUXERR for errors on MUX ports.
+ */
+ .ident = "HP Pavilion DV4270ca",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
+ },
+ },
+ {
.ident = "Toshiba P10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 42aa4ec72661..11dafc0ee994 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -516,6 +516,7 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
{
unsigned long flags;
unsigned char str, data;
+ int ret = 0;
spin_lock_irqsave(&i8042_lock, flags);
str = i8042_read_status();
@@ -524,10 +525,11 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
if (i8042_irq_being_tested &&
data == 0xa5 && (str & I8042_STR_AUXDATA))
complete(&i8042_aux_irq_delivered);
+ ret = 1;
}
spin_unlock_irqrestore(&i8042_lock, flags);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(ret);
}
/*
@@ -1042,7 +1044,7 @@ static void __devinit i8042_register_ports(void)
}
}
-static void __devinit i8042_unregister_ports(void)
+static void __devexit i8042_unregister_ports(void)
{
int i;
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index ea5e3c6ddb62..1b404f9e3bff 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -140,15 +140,13 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i
if (ret)
goto disable;
- ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL);
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM;
goto release;
}
- memset(ps2if, 0, sizeof(struct pcips2_data));
- memset(serio, 0, sizeof(struct serio));
serio->id.type = SERIO_8042;
serio->write = pcips2_write;
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index d31ece8f68e9..2ad88780a170 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -234,15 +234,13 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
struct serio *serio;
int ret;
- ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM;
goto free;
}
- memset(ps2if, 0, sizeof(struct ps2if));
- memset(serio, 0, sizeof(struct serio));
serio->id.type = SERIO_8042;
serio->write = ps2_write;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 372ca4931194..b3bc15acd3f5 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
#define SERIO_ADD_UEVENT_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct serio *serio;
- int i = 0;
- int len = 0;
if (!dev)
return -ENODEV;
@@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
- envp[i] = NULL;
return 0;
}
@@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
#else
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 9b3a26cd1a8d..9fb3d5c30999 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -856,7 +856,7 @@ static int usbtouch_probe(struct usb_interface *intf,
le16_to_cpu(udev->descriptor.idProduct));
usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
- strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
+ strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
input_dev->name = usbtouch->name;
input_dev->phys = usbtouch->phys;
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index cf906c8cee4d..66f946aa30b3 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -21,9 +21,7 @@ menuconfig ISDN
if ISDN
-menu "Old ISDN4Linux"
-
-config ISDN_I4L
+menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)"
---help---
This driver allows you to use an ISDN adapter for networking
@@ -45,12 +43,8 @@ if ISDN_I4L
source "drivers/isdn/i4l/Kconfig"
endif
-endmenu
-
-comment "CAPI subsystem"
-
-config ISDN_CAPI
- tristate "CAPI2.0 support"
+menuconfig ISDN_CAPI
+ tristate "CAPI 2.0 subsystem"
help
This provides the CAPI (Common ISDN Application Programming
Interface, a standard making it easy for programs to access ISDN
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
index 78e6ad8d57c5..3fc1a5434ef7 100644
--- a/drivers/isdn/act2000/Kconfig
+++ b/drivers/isdn/act2000/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_ACT2000
tristate "IBM Active 2000 support"
- depends on ISDN_I4L && ISA
+ depends on ISA
help
Say Y here if you have an IBM Active 2000 ISDN card. In order to use
this card, additional firmware is necessary, which has to be loaded
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index be77ee625bb7..4fd4c46892e3 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -17,6 +17,7 @@
#include <linux/fs.h>
#endif
#include <linux/isdnif.h>
+#include <net/net_namespace.h>
#include "isdn_divert.h"
@@ -70,6 +71,8 @@ put_info_buffer(char *cp)
wake_up_interruptible(&(rd_queue));
} /* put_info_buffer */
+#ifdef CONFIG_PROC_FS
+
/**********************************/
/* deflection device read routine */
/**********************************/
@@ -253,8 +256,6 @@ isdn_divert_ioctl(struct inode *inode, struct file *file,
return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
} /* isdn_divert_ioctl */
-
-#ifdef CONFIG_PROC_FS
static const struct file_operations isdn_fops =
{
.owner = THIS_MODULE,
@@ -284,12 +285,12 @@ divert_dev_init(void)
init_waitqueue_head(&rd_queue);
#ifdef CONFIG_PROC_FS
- isdn_proc_entry = proc_mkdir("net/isdn", NULL);
+ 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);
if (!isdn_divert_entry) {
- remove_proc_entry("net/isdn", NULL);
+ remove_proc_entry("isdn", init_net.proc_net);
return (-1);
}
isdn_divert_entry->proc_fops = &isdn_fops;
@@ -309,7 +310,7 @@ divert_dev_deinit(void)
#ifdef CONFIG_PROC_FS
remove_proc_entry("divert", isdn_proc_entry);
- remove_proc_entry("net/isdn", NULL);
+ remove_proc_entry("isdn", init_net.proc_net);
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index bcbb6502a773..0017e50c6948 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -1,9 +1,5 @@
-menu "Siemens Gigaset"
- depends on ISDN_I4L
-
-config ISDN_DRV_GIGASET
+menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support (isdn)"
- depends on ISDN_I4L
select CRC_CCITT
select BITREVERSE
help
@@ -55,6 +51,4 @@ config GIGASET_UNDOCREQ
features like configuration mode of M105, say yes. If you
care about your device, say no.
-endif
-
-endmenu
+endif # ISDN_DRV_GIGASET != n
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
index d755d904e62c..993b14cf1778 100644
--- a/drivers/isdn/hardware/eicon/diva_didd.c
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
+#include <net/net_namespace.h>
#include "platform.h"
#include "di_defs.h"
@@ -86,7 +87,7 @@ proc_read(char *page, char **start, off_t off, int count, int *eof,
static int DIVA_INIT_FUNCTION create_proc(void)
{
- proc_net_eicon = proc_mkdir("net/eicon", NULL);
+ proc_net_eicon = proc_mkdir("eicon", init_net.proc_net);
if (proc_net_eicon) {
if ((proc_didd =
@@ -102,7 +103,7 @@ static int DIVA_INIT_FUNCTION create_proc(void)
static void remove_proc(void)
{
remove_proc_entry(DRIVERLNAME, proc_net_eicon);
- remove_proc_entry("net/eicon", NULL);
+ remove_proc_entry("eicon", init_net.proc_net);
}
static int DIVA_INIT_FUNCTION divadidd_init(void)
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 12d91fb9f8cb..a3b945ac3256 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -1,6 +1,5 @@
menu "Passive cards"
- depends on ISDN_I4L
config ISDN_DRV_HISAX
tristate "HiSax SiemensChipSet driver support"
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index b04a178e5021..f8b79783c8b3 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -20,7 +20,6 @@
#include <linux/isapnp.h>
#include <linux/interrupt.h>
-extern const char *CardType[];
static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
#define AVM_FRITZ_PCI 1
@@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
{
u_int val, ver;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, avm_pci_rev);
- printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_FRITZPCI)
- return (0);
- if (card->para[1]) {
- /* old manual method */
- cs->hw.avm.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_avm_d = NULL;
- if ((pnp_avm_c = pnp_find_card(
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
- if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
- int err;
-
- pnp_disable_dev(pnp_avm_d);
- err = pnp_activate_dev(pnp_avm_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- cs->hw.avm.cfg_reg =
- pnp_port_start(pnp_avm_d, 0);
- cs->irq = pnp_irq(pnp_avm_d, 0);
- if (!cs->irq) {
- printk(KERN_ERR "FritzPnP:No IRQ\n");
- return(0);
- }
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPnP:No IO address\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
- }
- } else {
- printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
- }
-#endif
-#ifdef CONFIG_PCI
- if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_A1, dev_avm))) {
- if (pci_enable_device(dev_avm))
- return(0);
- cs->irq = dev_avm->irq;
- if (!cs->irq) {
- printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PCI;
- } else {
- printk(KERN_WARNING "FritzPCI: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-#else
- printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
-ready:
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
+ "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 31);
return (0);
@@ -860,3 +774,137 @@ ready:
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+ return(1); /* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+ struct pnp_dev *pnp_avm_d = NULL;
+
+ if (!isapnp_present())
+ return(1); /* no-op: success */
+
+ if ((pnp_avm_c = pnp_find_card(
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+ if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+ int err;
+
+ pnp_disable_dev(pnp_avm_d);
+ err = pnp_activate_dev(pnp_avm_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ cs->hw.avm.cfg_reg =
+ pnp_port_start(pnp_avm_d, 0);
+ cs->irq = pnp_irq(pnp_avm_d, 0);
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPnP:No IRQ\n");
+ return(0);
+ }
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPnP:No IO address\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PNP;
+
+ return (2); /* goto 'ready' label */
+ }
+ }
+
+ return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+ return(1); /* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+ if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+ if (pci_enable_device(dev_avm))
+ return(0);
+
+ cs->irq = dev_avm->irq;
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+
+ cs->subtyp = AVM_FRITZ_PCI;
+ } else {
+ printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ return(0);
+ }
+
+ cs->irq_flags |= IRQF_SHARED;
+
+ return (1);
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ int rc;
+
+ strcpy(tmp, avm_pci_rev);
+ printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+ if (cs->typ != ISDN_CTYPE_FRITZPCI)
+ return (0);
+
+ if (card->para[1]) {
+ /* old manual method */
+ cs->hw.avm.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = AVM_FRITZ_PNP;
+ goto ready;
+ }
+
+ rc = avm_pnp_setup(cs);
+ if (rc < 1)
+ return (0);
+ if (rc == 2)
+ goto ready;
+
+ rc = avm_pci_setup(cs);
+ if (rc < 1)
+ return (0);
+
+ready:
+ return avm_setup_rest(cs);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 6339bb443f62..99ef3b43fcd7 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -20,8 +20,6 @@
#include <linux/pci.h>
#include "bkm_ax.h"
-#ifdef CONFIG_PCI
-
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
@@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0;
static u_char pci_device_fn __devinitdata = 0;
static u_char pci_irq __devinitdata = 0;
-#endif /* CONFIG_PCI */
-
int __devinit
setup_sct_quadro(struct IsdnCard *card)
{
-#ifdef CONFIG_PCI
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int found = 0;
@@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card)
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
-#else
- printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
}
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 5f7907e57090..97097ef3491e 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1146,14 +1146,12 @@ static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
}
if (ret) {
closecard(cardnr);
- ret = 0;
goto outf_cs;
}
init_tei(cs, cs->protocol);
ret = CallcNewChan(cs);
if (ret) {
closecard(cardnr);
- ret = 0;
goto outf_cs;
}
/* ISAR needs firmware download first */
@@ -1165,7 +1163,7 @@ static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
outf_cs:
kfree(cs);
card->cs = NULL;
- return ret;
+ return 0;
}
static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 6eebeb441bfd..826745078746 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -25,8 +25,6 @@
#include <linux/pci.h>
#include <linux/isapnp.h>
-extern const char *CardType[];
-
static const char *Diva_revision = "$Revision: 1.33.2.6 $";
#define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
{
- int bytecnt = 8;
+ int bytecnt;
u_char val;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
- strcpy(tmp, Diva_revision);
- printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
- return(0);
- cs->hw.diva.status = 0;
- if (card->para[1]) {
- cs->hw.diva.ctrl_reg = 0;
- cs->hw.diva.cfg_reg = card->para[1];
- val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
- cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- if ((val == 1) || (val==2)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
- }
- cs->irq = card->para[0];
- } else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.diva.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl =
- card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac =
- card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_HSCX_ADR;
- }
- goto ready;
- } else {
- printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
- }
- }
-#endif
-#ifdef CONFIG_PCI
- cs->subtyp = 0;
- if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
- if (pci_enable_device(dev_diva))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
- if (pci_enable_device(dev_diva_u))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva_u->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
- if (pci_enable_device(dev_diva201))
- return(0);
- cs->subtyp = DIVA_IPAC_PCI;
- cs->irq = dev_diva201->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
- } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
- if (pci_enable_device(dev_diva202))
- return(0);
- cs->subtyp = DIVA_IPACX_PCI;
- cs->irq = dev_diva202->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
- } else {
- printk(KERN_WARNING "Diva: No PCI card found\n");
- return(0);
- }
-
- if (!cs->irq) {
- printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
-
- if (!cs->hw.diva.cfg_reg) {
- printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-#else
- printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI) ) {
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = 0;
- cs->hw.diva.hscx = 0;
- cs->hw.diva.isac_adr = 0;
- cs->hw.diva.hscx_adr = 0;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- bytecnt = 0;
- } else {
- cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
- cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
- cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
- cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
- bytecnt = 32;
- }
- }
-#ifdef __ISAPNP__
-ready:
-#endif
+ if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+ bytecnt = 8;
+ else
+ bytecnt = 32;
printk(KERN_INFO
"Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@ ready:
if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %lx-%lx already in use\n",
- CardType[card->typ],
+ "diva",
cs->hw.diva.cfg_reg,
cs->hw.diva.cfg_reg + bytecnt);
iounmap_diva(cs);
@@ -1206,3 +994,290 @@ ready:
}
return (1);
}
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ if (!card->para[1])
+ return (-1); /* card not found; continue search */
+
+ cs->hw.diva.ctrl_reg = 0;
+ cs->hw.diva.cfg_reg = card->para[1];
+ val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+ cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+ printk(KERN_INFO "Diva: IPAC version %x\n", val);
+ if ((val == 1) || (val==2)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+ }
+ cs->irq = card->para[0];
+
+ return (1); /* card found */
+}
+
+#else /* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ struct pnp_dev *pnp_d;
+
+ if (!isapnp_present())
+ return (-1); /* card not found; continue search */
+
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.diva.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl =
+ card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_HSCX_ADR;
+ }
+ return (1); /* card found */
+ } else {
+ printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c=NULL;
+ }
+
+ return (-1); /* card not found; continue search */
+}
+
+#else /* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* ISAPNP */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+
+ cs->subtyp = 0;
+ if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+ if (pci_enable_device(dev_diva))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+ } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+ if (pci_enable_device(dev_diva_u))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva_u->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+ if (pci_enable_device(dev_diva201))
+ return(0);
+ cs->subtyp = DIVA_IPAC_PCI;
+ cs->irq = dev_diva201->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+ } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+ if (pci_enable_device(dev_diva202))
+ return(0);
+ cs->subtyp = DIVA_IPACX_PCI;
+ cs->irq = dev_diva202->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+ } else {
+ return (-1); /* card not found; continue search */
+ }
+
+ if (!cs->irq) {
+ printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+
+ if (!cs->hw.diva.cfg_reg) {
+ printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+
+ if ((cs->subtyp == DIVA_IPAC_PCI) ||
+ (cs->subtyp == DIVA_IPACX_PCI) ) {
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = 0;
+ cs->hw.diva.hscx = 0;
+ cs->hw.diva.isac_adr = 0;
+ cs->hw.diva.hscx_adr = 0;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+ cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+ cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+ cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+ }
+
+ return (1); /* card found */
+}
+
+#else /* if !CONFIG_PCI */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+ int rc, have_card = 0;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Diva_revision);
+ printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+ return(0);
+ cs->hw.diva.status = 0;
+
+ rc = setup_diva_isa(card);
+ if (!rc)
+ return rc;
+ if (rc > 0) {
+ have_card = 1;
+ goto ready;
+ }
+
+ rc = setup_diva_isapnp(card);
+ if (!rc)
+ return rc;
+ if (rc > 0) {
+ have_card = 1;
+ goto ready;
+ }
+
+ rc = setup_diva_pci(card);
+ if (!rc)
+ return rc;
+ if (rc > 0)
+ have_card = 1;
+
+ready:
+ if (!have_card) {
+ printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+ return(0);
+ }
+
+ return setup_diva_common(card->cs);
+}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index fab3e4ea0595..0c1351b23840 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -30,8 +30,6 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
-extern const char *CardType[];
-
static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
static const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs)
return (CARD_portlist[i]);
}
-static struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ cs->hw.elsa.base = card->para[0];
+ printk(KERN_INFO "Elsa: Microlink IO probing\n");
+ if (cs->hw.elsa.base) {
+ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+ cs->typ))) {
+ printk(KERN_WARNING
+ "Elsa: no Elsa Microlink at %#lx\n",
+ cs->hw.elsa.base);
+ return (0);
+ }
+ } else
+ cs->hw.elsa.base = probe_elsa(cs);
+
+ if (!cs->hw.elsa.base) {
+ printk(KERN_WARNING
+ "No Elsa Microlink found\n");
+ return (0);
+ }
+
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ val = bytein(cs->hw.elsa.cfg);
+ if (cs->subtyp == ELSA_PC) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+ } else if (cs->subtyp == ELSA_PCC8) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+ } else {
+ const u_char CARD_IrqTab[8] =
+ {15, 10, 15, 3, 11, 5, 11, 9};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+ }
+ val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+ if (val < 3)
+ val |= 8;
+ val += 'A' - 3;
+ if (val == 'B' || val == 'C')
+ val ^= 1;
+ if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+ val = 'C';
+ printk(KERN_INFO
+ "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ val, cs->irq);
+ val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+ if (val) {
+ printk(KERN_WARNING
+ "Elsa: Microlink S0 bus power bad\n");
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ }
+
+ return (1);
+}
#ifdef __ISAPNP__
static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+#endif /* __ISAPNP__ */
-int __devinit
-setup_elsa(struct IsdnCard *card)
+static int __devinit
+setup_elsa_isapnp(struct IsdnCard *card)
{
- int bytecnt;
- u_char val;
struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, Elsa_revision);
- printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
- cs->hw.elsa.ctrl_reg = 0;
- cs->hw.elsa.status = 0;
- cs->hw.elsa.MFlag = 0;
- cs->subtyp = 0;
- if (cs->typ == ISDN_CTYPE_ELSA) {
- cs->hw.elsa.base = card->para[0];
- printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (cs->hw.elsa.base) {
- if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
- cs->typ))) {
- printk(KERN_WARNING
- "Elsa: no Elsa Microlink at %#lx\n",
- cs->hw.elsa.base);
- return (0);
- }
- } else
- cs->hw.elsa.base = probe_elsa(cs);
- if (cs->hw.elsa.base) {
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- val = bytein(cs->hw.elsa.cfg);
- if (cs->subtyp == ELSA_PC) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
- } else if (cs->subtyp == ELSA_PCC8) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
- } else {
- const u_char CARD_IrqTab[8] =
- {15, 10, 15, 3, 11, 5, 11, 9};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
- }
- val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
- if (val < 3)
- val |= 8;
- val += 'A' - 3;
- if (val == 'B' || val == 'C')
- val ^= 1;
- if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
- val = 'C';
- printk(KERN_INFO
- "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- val, cs->irq);
- val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
- if (val) {
- printk(KERN_WARNING
- "Elsa: Microlink S0 bus power bad\n");
- cs->hw.elsa.status |= ELSA_BAD_PWR;
- }
- } else {
- printk(KERN_WARNING
- "No Elsa Microlink found\n");
- return (0);
- }
- } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
+ if (!card->para[1] && isapnp_present()) {
+ struct pnp_dev *pnp_d;
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- if (ipid->function == ISAPNP_FUNCTION(0x133))
- cs->subtyp = ELSA_QS1000;
- else
- cs->subtyp = ELSA_QS3000;
- break;
- } else {
- printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
return(0);
}
+ if (ipid->function == ISAPNP_FUNCTION(0x133))
+ cs->subtyp = ELSA_QS1000;
+ else
+ cs->subtyp = ELSA_QS3000;
+ break;
+ } else {
+ printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+ return(0);
}
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
- return(0);
}
+ ipid++;
+ pnp_c=NULL;
+ }
+ if (!ipid->card_vendor) {
+ printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+ return(0);
}
-#endif
- if (card->para[1] && card->para[0]) {
- cs->hw.elsa.base = card->para[1];
- cs->irq = card->para[0];
- if (!cs->subtyp)
- cs->subtyp = ELSA_QS1000;
- } else {
- printk(KERN_ERR "Elsa PnP: no parameter\n");
- }
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+ }
+#endif /* __ISAPNP__ */
+
+ if (card->para[1] && card->para[0]) {
cs->hw.elsa.base = card->para[1];
cs->irq = card->para[0];
- val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
- if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
- cs->subtyp = ELSA_PCMCIA_IPAC;
- cs->hw.elsa.ale = cs->hw.elsa.base + 0;
- cs->hw.elsa.isac = cs->hw.elsa.base + 2;
- cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = ELSA_PCMCIA;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- }
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->hw.elsa.ctrl = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+ if (!cs->subtyp)
+ cs->subtyp = ELSA_QS1000;
+ } else {
+ printk(KERN_ERR "Elsa PnP: no parameter\n");
+ }
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+
+ return (1);
+}
+
+static void __devinit
+setup_elsa_pcmcia(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+ if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+ cs->subtyp = ELSA_PCMCIA_IPAC;
+ cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+ cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = ELSA_PCMCIA;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ }
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->hw.elsa.ctrl = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+}
+
#ifdef CONFIG_PCI
- cs->subtyp = 0;
- if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
- if (pci_enable_device(dev_qs1000))
- return(0);
- cs->subtyp = ELSA_QS1000PCI;
- cs->irq = dev_qs1000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
- if (pci_enable_device(dev_qs3000))
- return(0);
- cs->subtyp = ELSA_QS3000PCI;
- cs->irq = dev_qs3000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
- } else {
- printk(KERN_WARNING "Elsa: No PCI card found\n");
+static struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+
+ cs->subtyp = 0;
+ if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+ if (pci_enable_device(dev_qs1000))
return(0);
- }
- if (!cs->irq) {
- printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ cs->subtyp = ELSA_QS1000PCI;
+ cs->irq = dev_qs1000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+ } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+ if (pci_enable_device(dev_qs3000))
return(0);
- }
+ cs->subtyp = ELSA_QS3000PCI;
+ cs->irq = dev_qs3000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+ } else {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
+ return(0);
+ }
+ if (!cs->irq) {
+ printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+ printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+ printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+ printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+ printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+ }
+ cs->hw.elsa.ale = cs->hw.elsa.base;
+ cs->hw.elsa.isac = cs->hw.elsa.base +1;
+ cs->hw.elsa.hscx = cs->hw.elsa.base +1;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->hw.elsa.cfg,
+ cs->irq);
+
+ return (1);
+}
- if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
- printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
- return(0);
- }
- if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
- printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
- printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
- printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
- }
- cs->hw.elsa.ale = cs->hw.elsa.base;
- cs->hw.elsa.isac = cs->hw.elsa.base +1;
- cs->hw.elsa.hscx = cs->hw.elsa.base +1;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->hw.elsa.cfg,
- cs->irq);
#else
- printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
- return (0);
+
+static void __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+ return (1);
+}
#endif /* CONFIG_PCI */
- } else
- return (0);
+
+static int __devinit
+setup_elsa_common(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+ int bytecnt;
switch (cs->subtyp) {
case ELSA_PC:
@@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card)
here, it would fail. */
if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
printk(KERN_WARNING
- "HiSax: %s config port %#lx-%#lx already in use\n",
- CardType[card->typ],
+ "HiSax: ELSA config port %#lx-%#lx already in use\n",
cs->hw.elsa.base,
cs->hw.elsa.base + bytecnt);
return (0);
@@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card)
if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
printk(KERN_WARNING
- "HiSax: %s pci port %x-%x already in use\n",
- CardType[card->typ],
+ "HiSax: ELSA pci port %x-%x already in use\n",
cs->hw.elsa.cfg,
cs->hw.elsa.cfg + 0x80);
release_region(cs->hw.elsa.base, bytecnt);
@@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card)
}
return (1);
}
+
+int __devinit
+setup_elsa(struct IsdnCard *card)
+{
+ int rc;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Elsa_revision);
+ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ cs->hw.elsa.MFlag = 0;
+ cs->subtyp = 0;
+
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ rc = setup_elsa_isa(card);
+ if (!rc)
+ return (0);
+
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+ rc = setup_elsa_isapnp(card);
+ if (!rc)
+ return (0);
+
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
+ setup_elsa_pcmcia(card);
+
+ else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+ rc = setup_elsa_pci(card);
+ if (!rc)
+ return (0);
+
+ } else
+ return (0);
+
+ return setup_elsa_common(card);
+}
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index b1a26e02df02..60843b3f3b6f 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1,12 +1,12 @@
/*
* hfc_usb.c
*
- * $Id: hfc_usb.c,v 2.3.2.13 2006/02/17 17:17:22 mbachem Exp $
+ * $Id: hfc_usb.c,v 2.3.2.20 2007/08/20 14:07:54 mbachem Exp $
*
* modular HiSax ISDN driver for Colognechip HFC-S USB chip
*
- * Authors : Peter Sprenger (sprenger@moving-bytes.de)
- * Martin Bachem (info@colognechip.com)
+ * Authors : Peter Sprenger (sprenger@moving-bytes.de)
+ * Martin Bachem (m.bachem@gmx.de, info@colognechip.com)
*
* based on the first hfc_usb driver of
* Werner Cornelius (werner@isdn-development.de)
@@ -37,24 +37,25 @@
#include <linux/kernel_stat.h>
#include <linux/usb.h>
#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/moduleparam.h>
#include "hisax.h"
#include "hisax_if.h"
#include "hfc_usb.h"
static const char *hfcusb_revision =
- "$Revision: 2.3.2.13 $ $Date: 2006/02/17 17:17:22 $ ";
+ "$Revision: 2.3.2.20 $ $Date: 2007/08/20 14:07:54 $ ";
/* Hisax debug support
-* use "modprobe debug=x" where x is bitfield of USB_DBG & ISDN_DBG
+* debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
*/
-#ifdef CONFIG_HISAX_DEBUG
-#include <linux/moduleparam.h>
#define __debug_variable hfc_debug
#include "hisax_debug.h"
static u_int debug;
module_param(debug, uint, 0);
static int hfc_debug;
-#endif
+
/* private vendor specific data */
typedef struct {
@@ -63,9 +64,7 @@ typedef struct {
char *vend_name; // device name
} hfcsusb_vdata;
-/****************************************/
-/* data defining the devices to be used */
-/****************************************/
+/* VID/PID device list */
static struct usb_device_id hfcusb_idtab[] = {
{
USB_DEVICE(0x0959, 0x2bd0),
@@ -90,49 +89,47 @@ static struct usb_device_id hfcusb_idtab[] = {
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {4, 0, 2, 1},
"Stollmann USB TA"}),
- },
+ },
{
USB_DEVICE(0x0742, 0x2009),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {4, 0, 2, 1},
"Aceex USB ISDN TA"}),
- },
+ },
{
USB_DEVICE(0x0742, 0x200A),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {4, 0, 2, 1},
"OEM USB ISDN TA"}),
- },
+ },
{
USB_DEVICE(0x08e3, 0x0301),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {2, 0, 1, 4},
"Olitec USB RNIS"}),
- },
+ },
{
USB_DEVICE(0x07fa, 0x0846),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Bewan Modem RNIS USB"}),
- },
+ },
{
USB_DEVICE(0x07fa, 0x0847),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Djinn Numeris USB"}),
- },
+ },
{
USB_DEVICE(0x07b0, 0x0006),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Twister ISDN TA"}),
- },
+ },
{ }
};
-/***************************************************************/
/* structure defining input+output fifos (interrupt/bulk mode) */
-/***************************************************************/
struct usb_fifo; /* forward definition */
typedef struct iso_urb_struct {
struct urb *purb;
@@ -140,8 +137,8 @@ typedef struct iso_urb_struct {
struct usb_fifo *owner_fifo; /* pointer to owner fifo */
} iso_urb_struct;
-
struct hfcusb_data; /* forward definition */
+
typedef struct usb_fifo {
int fifonum; /* fifo index attached to this structure */
int active; /* fifo is currently active */
@@ -160,15 +157,12 @@ typedef struct usb_fifo {
struct hisax_if *hif; /* hisax interface */
int delete_flg; /* only delete skbuff once */
int last_urblen; /* remember length of last packet */
-
} usb_fifo;
-/*********************************************/
/* structure holding all data for one device */
-/*********************************************/
typedef struct hfcusb_data {
/* HiSax Interface for loadable Layer1 drivers */
- struct hisax_d_if d_if; /* see hisax_if.h */
+ struct hisax_d_if d_if; /* see hisax_if.h */
struct hisax_b_if b_if[2]; /* see hisax_if.h */
int protocol;
@@ -176,12 +170,13 @@ typedef struct hfcusb_data {
int if_used; /* used interface number */
int alt_used; /* used alternate config */
int ctrl_paksize; /* control pipe packet size */
- int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */
+ int ctrl_in_pipe, /* handles for control pipe */
+ ctrl_out_pipe;
int cfg_used; /* configuration index used */
int vend_idx; /* vendor found */
int b_mode[2]; /* B-channel mode */
int l1_activated; /* layer 1 activated */
- int disc_flag; /* 'true' if device was disonnected to avoid some USB actions */
+ int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */
int packet_size, iso_packet_size;
/* control pipe background handling */
@@ -208,7 +203,6 @@ typedef struct hfcusb_data {
static void collect_rx_frame(usb_fifo * fifo, __u8 * data, int len,
int finish);
-
static inline const char *
symbolic(struct hfcusb_symbolic_list list[], const int num)
{
@@ -219,10 +213,6 @@ symbolic(struct hfcusb_symbolic_list list[], const int num)
return "<unknown ERROR>";
}
-
-/******************************************************/
-/* start next background transfer for control channel */
-/******************************************************/
static void
ctrl_start_transfer(hfcusb_data * hfc)
{
@@ -240,10 +230,6 @@ ctrl_start_transfer(hfcusb_data * hfc)
}
} /* ctrl_start_transfer */
-/************************************/
-/* queue a control transfer request */
-/* return 0 on success. */
-/************************************/
static int
queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val, int action)
{
@@ -260,19 +246,8 @@ queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val, int action)
if (++hfc->ctrl_cnt == 1)
ctrl_start_transfer(hfc);
return (0);
-} /* queue_control_request */
-
-static int
-control_action_handler(hfcusb_data * hfc, int reg, int val, int action)
-{
- if (!action)
- return (1); /* no action defined */
- return (0);
}
-/***************************************************************/
-/* control completion routine handling background control cmds */
-/***************************************************************/
static void
ctrl_complete(struct urb *urb)
{
@@ -282,9 +257,6 @@ ctrl_complete(struct urb *urb)
urb->dev = hfc->dev;
if (hfc->ctrl_cnt) {
buf = &hfc->ctrl_buff[hfc->ctrl_out_idx];
- control_action_handler(hfc, buf->hfc_reg, buf->reg_val,
- buf->action);
-
hfc->ctrl_cnt--; /* decrement actual count */
if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
hfc->ctrl_out_idx = 0; /* pointer wrap */
@@ -293,9 +265,7 @@ ctrl_complete(struct urb *urb)
}
} /* ctrl_complete */
-/***************************************************/
/* write led data to auxport & invert if necessary */
-/***************************************************/
static void
write_led(hfcusb_data * hfc, __u8 led_state)
{
@@ -305,9 +275,6 @@ write_led(hfcusb_data * hfc, __u8 led_state)
}
}
-/**************************/
-/* handle LED bits */
-/**************************/
static void
set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
{
@@ -324,9 +291,7 @@ set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
}
}
-/**************************/
-/* handle LED requests */
-/**************************/
+/* handle LED requests */
static void
handle_led(hfcusb_data * hfc, int event)
{
@@ -339,85 +304,73 @@ handle_led(hfcusb_data * hfc, int event)
switch (event) {
case LED_POWER_ON:
- set_led_bit(hfc, driver_info->led_bits[0],
- 0);
- set_led_bit(hfc, driver_info->led_bits[1],
- 1);
- set_led_bit(hfc, driver_info->led_bits[2],
- 1);
- set_led_bit(hfc, driver_info->led_bits[3],
- 1);
+ set_led_bit(hfc, driver_info->led_bits[0], 0);
+ set_led_bit(hfc, driver_info->led_bits[1], 1);
+ set_led_bit(hfc, driver_info->led_bits[2], 1);
+ set_led_bit(hfc, driver_info->led_bits[3], 1);
break;
- case LED_POWER_OFF: /* no Power off handling */
+ case LED_POWER_OFF:
+ set_led_bit(hfc, driver_info->led_bits[0], 1);
+ set_led_bit(hfc, driver_info->led_bits[1], 1);
+ set_led_bit(hfc, driver_info->led_bits[2], 1);
+ set_led_bit(hfc, driver_info->led_bits[3], 1);
break;
case LED_S0_ON:
- set_led_bit(hfc, driver_info->led_bits[1],
- 0);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
break;
case LED_S0_OFF:
- set_led_bit(hfc, driver_info->led_bits[1],
- 1);
+ set_led_bit(hfc, driver_info->led_bits[1], 1);
break;
case LED_B1_ON:
- set_led_bit(hfc, driver_info->led_bits[2],
- 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
break;
case LED_B1_OFF:
- set_led_bit(hfc, driver_info->led_bits[2],
- 1);
+ set_led_bit(hfc, driver_info->led_bits[2], 1);
break;
case LED_B2_ON:
- set_led_bit(hfc, driver_info->led_bits[3],
- 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
case LED_B2_OFF:
- set_led_bit(hfc, driver_info->led_bits[3],
- 1);
+ set_led_bit(hfc, driver_info->led_bits[3], 1);
break;
}
write_led(hfc, hfc->led_state);
}
-/********************************/
-/* called when timer t3 expires */
-/********************************/
+/* ISDN l1 timer T3 expires */
static void
l1_timer_expire_t3(hfcusb_data * hfc)
{
hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
NULL);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+
+ DBG(HFCUSB_DBG_STATES,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
-#endif
- hfc->l1_activated = false;
+
+ hfc->l1_activated = 0;
handle_led(hfc, LED_S0_OFF);
/* deactivate : */
queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
queue_control_request(hfc, HFCUSB_STATES, 3, 1);
}
-/********************************/
-/* called when timer t4 expires */
-/********************************/
+/* ISDN l1 timer T4 expires */
static void
l1_timer_expire_t4(hfcusb_data * hfc)
{
hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
NULL);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+
+ DBG(HFCUSB_DBG_STATES,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
-#endif
- hfc->l1_activated = false;
+
+ hfc->l1_activated = 0;
handle_led(hfc, LED_S0_OFF);
}
-/*****************************/
-/* handle S0 state changes */
-/*****************************/
+/* S0 state changed */
static void
-state_handler(hfcusb_data * hfc, __u8 state)
+s0_state_handler(hfcusb_data * hfc, __u8 state)
{
__u8 old_state;
@@ -425,38 +378,29 @@ state_handler(hfcusb_data * hfc, __u8 state)
if (state == old_state || state < 1 || state > 8)
return;
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG, "HFC-S USB: new S0 state:%d old_state:%d", state,
- old_state);
-#endif
+ DBG(HFCUSB_DBG_STATES, "HFC-S USB: S0 statechange(%d -> %d)",
+ old_state, state);
+
if (state < 4 || state == 7 || state == 8) {
if (timer_pending(&hfc->t3_timer))
del_timer(&hfc->t3_timer);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG, "HFC-S USB: T3 deactivated");
-#endif
+ DBG(HFCUSB_DBG_STATES, "HFC-S USB: T3 deactivated");
}
if (state >= 7) {
if (timer_pending(&hfc->t4_timer))
del_timer(&hfc->t4_timer);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG, "HFC-S USB: T4 deactivated");
-#endif
+ DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 deactivated");
}
if (state == 7 && !hfc->l1_activated) {
hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
PH_ACTIVATE | INDICATION, NULL);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
-#endif
- hfc->l1_activated = true;
+ DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
+ hfc->l1_activated = 1;
handle_led(hfc, LED_S0_ON);
} else if (state <= 3 /* && activated */ ) {
if (old_state == 7 || old_state == 8) {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG, "HFC-S USB: T4 activated");
-#endif
+ DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 activated");
if (!timer_pending(&hfc->t4_timer)) {
hfc->t4_timer.expires =
jiffies + (HFC_TIMER_T4 * HZ) / 1000;
@@ -466,18 +410,15 @@ state_handler(hfcusb_data * hfc, __u8 state)
hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
PH_DEACTIVATE | INDICATION,
NULL);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+ DBG(HFCUSB_DBG_STATES,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent");
-#endif
- hfc->l1_activated = false;
+ hfc->l1_activated = 0;
handle_led(hfc, LED_S0_OFF);
}
}
hfc->l1_state = state;
}
-/* prepare iso urb */
static void
fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
void *buf, int num_packets, int packet_size, int interval,
@@ -503,15 +444,16 @@ fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
}
/* allocs urbs and start isoc transfer with two pending urbs to avoid
- gaps in the transfer chain */
+ * gaps in the transfer chain
+ */
static int
start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,
usb_complete_t complete, int packet_size)
{
int i, k, errcode;
- printk(KERN_INFO "HFC-S USB: starting ISO-chain for Fifo %i\n",
- fifo->fifonum);
+ DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting ISO-URBs for fifo:%d\n",
+ fifo->fifonum);
/* allocate Memory for Iso out Urbs */
for (i = 0; i < 2; i++) {
@@ -556,10 +498,9 @@ start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,
errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
fifo->active = (errcode >= 0) ? 1 : 0;
- if (errcode < 0) {
- printk(KERN_INFO "HFC-S USB: %s URB nr:%d\n",
- symbolic(urb_errlist, errcode), i);
- };
+ if (errcode < 0)
+ printk(KERN_INFO "HFC-S USB: usb_submit_urb URB nr:%d, error(%i): '%s'\n",
+ i, errcode, symbolic(urb_errlist, errcode));
}
return (fifo->active);
}
@@ -572,16 +513,15 @@ stop_isoc_chain(usb_fifo * fifo)
for (i = 0; i < 2; i++) {
if (fifo->iso[i].purb) {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
+ DBG(HFCUSB_DBG_INIT,
"HFC-S USB: Stopping iso chain for fifo %i.%i",
fifo->fifonum, i);
-#endif
usb_kill_urb(fifo->iso[i].purb);
usb_free_urb(fifo->iso[i].purb);
fifo->iso[i].purb = NULL;
}
}
+
usb_kill_urb(fifo->urb);
usb_free_urb(fifo->urb);
fifo->urb = NULL;
@@ -594,9 +534,6 @@ static int iso_packets[8] =
ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
};
-/*****************************************************/
-/* transmit completion routine for all ISO tx fifos */
-/*****************************************************/
static void
tx_iso_complete(struct urb *urb)
{
@@ -607,20 +544,38 @@ tx_iso_complete(struct urb *urb)
errcode;
int frame_complete, transp_mode, fifon, status;
__u8 threshbit;
- __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
fifon = fifo->fifonum;
status = urb->status;
tx_offset = 0;
+ /* ISO transfer only partially completed,
+ look at individual frame status for details */
+ if (status == -EXDEV) {
+ DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV"
+ ", urb->status %d, fifonum %d\n",
+ status, fifon);
+
+ for (k = 0; k < iso_packets[fifon]; ++k) {
+ errcode = urb->iso_frame_desc[k].status;
+ if (errcode)
+ DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete "
+ "packet %i, status: %i\n",
+ k, errcode);
+ }
+
+ // clear status, so go on with ISO transfers
+ status = 0;
+ }
+
if (fifo->active && !status) {
transp_mode = 0;
if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
- transp_mode = true;
+ transp_mode = 1;
/* is FifoFull-threshold set for our channel? */
- threshbit = threshtable[fifon] & hfc->threshold_mask;
+ threshbit = (hfc->threshold_mask & (1 << fifon));
num_isoc_packets = iso_packets[fifon];
/* predict dataflow to avoid fifo overflow */
@@ -635,8 +590,9 @@ tx_iso_complete(struct urb *urb)
tx_iso_complete, urb->context);
memset(context_iso_urb->buffer, 0,
sizeof(context_iso_urb->buffer));
- frame_complete = false;
- /* Generate next Iso Packets */
+ frame_complete = 0;
+
+ /* Generate next ISO Packets */
for (k = 0; k < num_isoc_packets; ++k) {
if (fifo->skbuff) {
len = fifo->skbuff->len;
@@ -661,7 +617,7 @@ tx_iso_complete(struct urb *urb)
/* add 2 byte flags and 16bit CRC at end of ISDN frame */
fifo->bit_line += 32;
}
- frame_complete = true;
+ frame_complete = 1;
}
memcpy(context_iso_urb->buffer +
@@ -688,7 +644,7 @@ tx_iso_complete(struct urb *urb)
}
if (frame_complete) {
- fifo->delete_flg = true;
+ fifo->delete_flg = 1;
fifo->hif->l1l2(fifo->hif,
PH_DATA | CONFIRM,
(void *) (unsigned long) fifo->skbuff->
@@ -696,30 +652,26 @@ tx_iso_complete(struct urb *urb)
if (fifo->skbuff && fifo->delete_flg) {
dev_kfree_skb_any(fifo->skbuff);
fifo->skbuff = NULL;
- fifo->delete_flg = false;
+ fifo->delete_flg = 0;
}
- frame_complete = false;
+ frame_complete = 0;
}
}
errcode = usb_submit_urb(urb, GFP_ATOMIC);
if (errcode < 0) {
printk(KERN_INFO
- "HFC-S USB: error submitting ISO URB: %d \n",
+ "HFC-S USB: error submitting ISO URB: %d\n",
errcode);
}
} else {
if (status && !hfc->disc_flag) {
printk(KERN_INFO
- "HFC-S USB: tx_iso_complete : urb->status %s (%i), fifonum=%d\n",
- symbolic(urb_errlist, status), status,
- fifon);
+ "HFC-S USB: tx_iso_complete: error(%i): '%s', fifonum=%d\n",
+ status, symbolic(urb_errlist, status), fifon);
}
}
-} /* tx_iso_complete */
+}
-/*****************************************************/
-/* receive completion routine for all ISO tx fifos */
-/*****************************************************/
static void
rx_iso_complete(struct urb *urb)
{
@@ -731,21 +683,25 @@ rx_iso_complete(struct urb *urb)
unsigned int iso_status;
__u8 *buf;
static __u8 eof[8];
-#ifdef CONFIG_HISAX_DEBUG
- __u8 i;
-#endif
fifon = fifo->fifonum;
status = urb->status;
if (urb->status == -EOVERFLOW) {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",
- fifon);
-#endif
+ DBG(HFCUSB_DBG_VERBOSE_USB,
+ "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon);
+ status = 0;
+ }
+
+ /* ISO transfer only partially completed,
+ look at individual frame status for details */
+ if (status == -EXDEV) {
+ DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV "
+ "urb->status %d, fifonum %d\n",
+ status, fifon);
status = 0;
}
+
if (fifo->active && !status) {
num_isoc_packets = iso_packets[fifon];
maxlen = fifo->usb_packet_maxlen;
@@ -754,40 +710,38 @@ rx_iso_complete(struct urb *urb)
offset = urb->iso_frame_desc[k].offset;
buf = context_iso_urb->buffer + offset;
iso_status = urb->iso_frame_desc[k].status;
-#ifdef CONFIG_HISAX_DEBUG
+
if (iso_status && !hfc->disc_flag)
- DBG(USB_DBG,
- "HFC-S USB: ISO packet failure - status:%x",
- iso_status);
+ DBG(HFCUSB_DBG_VERBOSE_USB,
+ "HFC-S USB: rx_iso_complete "
+ "ISO packet %i, status: %i\n",
+ k, iso_status);
- if ((fifon == 5) && (debug > 1)) {
- printk(KERN_INFO
+ if (fifon == HFCUSB_D_RX) {
+ DBG(HFCUSB_DBG_VERBOSE_USB,
"HFC-S USB: ISO-D-RX lst_urblen:%2d "
- "act_urblen:%2d max-urblen:%2d "
- "EOF:0x%0x DATA: ",
+ "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
fifo->last_urblen, len, maxlen,
eof[5]);
- for (i = 0; i < len; i++)
- printk("%.2x ", buf[i]);
- printk("\n");
+
+ DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
}
-#endif
+
if (fifo->last_urblen != maxlen) {
/* the threshold mask is in the 2nd status byte */
hfc->threshold_mask = buf[1];
/* care for L1 state only for D-Channel
to avoid overlapped iso completions */
- if (fifon == 5) {
+ if (fifon == HFCUSB_D_RX) {
/* the S0 state is in the upper half
of the 1st status byte */
- state_handler(hfc, buf[0] >> 4);
+ s0_state_handler(hfc, buf[0] >> 4);
}
eof[fifon] = buf[0] & 1;
if (len > 2)
collect_rx_frame(fifo, buf + 2,
len - 2,
- (len <
- maxlen) ?
+ (len < maxlen) ?
eof[fifon] : 0);
} else {
collect_rx_frame(fifo, buf, len,
@@ -804,41 +758,37 @@ rx_iso_complete(struct urb *urb)
rx_iso_complete, urb->context);
errcode = usb_submit_urb(urb, GFP_ATOMIC);
if (errcode < 0) {
- printk(KERN_INFO
- "HFC-S USB: error submitting ISO URB: %d \n",
+ printk(KERN_ERR
+ "HFC-S USB: error submitting ISO URB: %d\n",
errcode);
}
} else {
if (status && !hfc->disc_flag) {
- printk(KERN_INFO
+ printk(KERN_ERR
"HFC-S USB: rx_iso_complete : "
"urb->status %d, fifonum %d\n",
status, fifon);
}
}
-} /* rx_iso_complete */
+}
-/*****************************************************/
-/* collect data from interrupt or isochron in */
-/*****************************************************/
+/* collect rx data from INT- and ISO-URBs */
static void
collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
{
hfcusb_data *hfc = fifo->hfc;
int transp_mode, fifon;
-#ifdef CONFIG_HISAX_DEBUG
- int i;
-#endif
+
fifon = fifo->fifonum;
transp_mode = 0;
if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
- transp_mode = true;
+ transp_mode = 1;
if (!fifo->skbuff) {
fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
if (!fifo->skbuff) {
- printk(KERN_INFO
- "HFC-S USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",
+ printk(KERN_ERR
+ "HFC-S USB: cannot allocate buffer for fifo(%d)\n",
fifon);
return;
}
@@ -847,17 +797,11 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
if (fifo->skbuff->len + len < fifo->max_size) {
memcpy(skb_put(fifo->skbuff, len), data, len);
} else {
-#ifdef CONFIG_HISAX_DEBUG
- printk(KERN_INFO "HFC-S USB: ");
- for (i = 0; i < 15; i++)
- printk("%.2x ",
- fifo->skbuff->data[fifo->skbuff->
- len - 15 + i]);
- printk("\n");
-#endif
- printk(KERN_INFO
- "HCF-USB: got frame exceeded fifo->max_size:%d on fifo:%d\n",
+ DBG(HFCUSB_DBG_FIFO_ERR,
+ "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)",
fifo->max_size, fifon);
+ DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
+ skb_trim(fifo->skbuff, 0);
}
}
if (transp_mode && fifo->skbuff->len >= 128) {
@@ -870,6 +814,13 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
if (finish) {
if ((!fifo->skbuff->data[fifo->skbuff->len - 1])
&& (fifo->skbuff->len > 3)) {
+
+ if (fifon == HFCUSB_D_RX) {
+ DBG(HFCUSB_DBG_DCHANNEL,
+ "HFC-S USB: D-RX len(%d)", fifo->skbuff->len);
+ DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff);
+ }
+
/* remove CRC & status */
skb_trim(fifo->skbuff, fifo->skbuff->len - 3);
if (fifon == HFCUSB_PCM_RX) {
@@ -882,39 +833,17 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
fifo->skbuff);
fifo->skbuff = NULL; /* buffer was freed from upper layer */
} else {
- if (fifo->skbuff->len > 3) {
- printk(KERN_INFO
- "HFC-S USB: got frame %d bytes but CRC ERROR on fifo:%d!!!\n",
- fifo->skbuff->len, fifon);
-#ifdef CONFIG_HISAX_DEBUG
- if (debug > 1) {
- printk(KERN_INFO "HFC-S USB: ");
- for (i = 0; i < 15; i++)
- printk("%.2x ",
- fifo->skbuff->
- data[fifo->skbuff->
- len - 15 + i]);
- printk("\n");
- }
-#endif
- }
-#ifdef CONFIG_HISAX_DEBUG
- else {
- printk(KERN_INFO
- "HFC-S USB: frame to small (%d bytes)!!!\n",
- fifo->skbuff->len);
- }
-#endif
+ DBG(HFCUSB_DBG_FIFO_ERR,
+ "HFC-S USB: ERROR frame len(%d) fifo(%d)",
+ fifo->skbuff->len, fifon);
+ DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
skb_trim(fifo->skbuff, 0);
}
}
}
-/***********************************************/
-/* receive completion routine for all rx fifos */
-/***********************************************/
static void
-rx_complete(struct urb *urb)
+rx_int_complete(struct urb *urb)
{
int len;
int status;
@@ -922,18 +851,14 @@ rx_complete(struct urb *urb)
usb_fifo *fifo = (usb_fifo *) urb->context;
hfcusb_data *hfc = fifo->hfc;
static __u8 eof[8];
-#ifdef CONFIG_HISAX_DEBUG
- __u8 i;
-#endif
urb->dev = hfc->dev; /* security init */
fifon = fifo->fifonum;
if ((!fifo->active) || (urb->status)) {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG, "HFC-S USB: RX-Fifo %i is going down (%i)",
+ DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)",
fifon, urb->status);
-#endif
+
fifo->urb->interval = 0; /* cancel automatic rescheduling */
if (fifo->skbuff) {
dev_kfree_skb_any(fifo->skbuff);
@@ -945,22 +870,20 @@ rx_complete(struct urb *urb)
buf = fifo->buffer;
maxlen = fifo->usb_packet_maxlen;
-#ifdef CONFIG_HISAX_DEBUG
- if ((fifon == 5) && (debug > 1)) {
- printk(KERN_INFO
- "HFC-S USB: INT-D-RX lst_urblen:%2d act_urblen:%2d max-urblen:%2d EOF:0x%0x DATA: ",
- fifo->last_urblen, len, maxlen, eof[5]);
- for (i = 0; i < len; i++)
- printk("%.2x ", buf[i]);
- printk("\n");
+ if (fifon == HFCUSB_D_RX) {
+ DBG(HFCUSB_DBG_VERBOSE_USB,
+ "HFC-S USB: INT-D-RX lst_urblen:%2d "
+ "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
+ fifo->last_urblen, len, maxlen,
+ eof[5]);
+ DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
}
-#endif
if (fifo->last_urblen != fifo->usb_packet_maxlen) {
/* the threshold mask is in the 2nd status byte */
hfc->threshold_mask = buf[1];
/* the S0 state is in the upper half of the 1st status byte */
- state_handler(hfc, buf[0] >> 4);
+ s0_state_handler(hfc, buf[0] >> 4);
eof[fifon] = buf[0] & 1;
/* if we have more than the 2 status bytes -> collect data */
if (len > 2)
@@ -975,20 +898,19 @@ rx_complete(struct urb *urb)
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
printk(KERN_INFO
- "HFC-S USB: error resubmitting URN at rx_complete...\n");
+ "HFC-S USB: %s error resubmitting URB fifo(%d)\n",
+ __FUNCTION__, fifon);
}
-} /* rx_complete */
+}
-/***************************************************/
-/* start the interrupt transfer for the given fifo */
-/***************************************************/
+/* start initial INT-URB for certain fifo */
static void
start_int_fifo(usb_fifo * fifo)
{
int errcode;
- printk(KERN_INFO "HFC-S USB: starting intr IN fifo:%d\n",
- fifo->fifonum);
+ DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n",
+ fifo->fifonum);
if (!fifo->urb) {
fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -997,33 +919,28 @@ start_int_fifo(usb_fifo * fifo)
}
usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe,
fifo->buffer, fifo->usb_packet_maxlen,
- rx_complete, fifo, fifo->intervall);
+ rx_int_complete, fifo, fifo->intervall);
fifo->active = 1; /* must be marked active */
errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
if (errcode) {
- printk(KERN_INFO
+ printk(KERN_ERR
"HFC-S USB: submit URB error(start_int_info): status:%i\n",
errcode);
fifo->active = 0;
fifo->skbuff = NULL;
}
-} /* start_int_fifo */
+}
-/*****************************/
-/* set the B-channel mode */
-/*****************************/
static void
-set_hfcmode(hfcusb_data * hfc, int channel, int mode)
+setup_bchannel(hfcusb_data * hfc, int channel, int mode)
{
__u8 val, idx_table[2] = { 0, 2 };
if (hfc->disc_flag) {
return;
}
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG, "HFC-S USB: setting channel %d to mode %d", channel,
- mode);
-#endif
+ DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d",
+ channel, mode);
hfc->b_mode[channel] = mode;
/* setup CON_HDLC */
@@ -1080,20 +997,17 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
switch (pr) {
case PH_ACTIVATE | REQUEST:
if (fifo->fifonum == HFCUSB_D_TX) {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+ DBG(HFCUSB_DBG_STATES,
"HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST");
-#endif
+
if (hfc->l1_state != 3
&& hfc->l1_state != 7) {
hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
PH_DEACTIVATE |
INDICATION,
NULL);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+ DBG(HFCUSB_DBG_STATES,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)");
-#endif
} else {
if (hfc->l1_state == 7) { /* l1 already active */
hfc->d_if.ifc.l1l2(&hfc->
@@ -1103,10 +1017,8 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
|
INDICATION,
NULL);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+ DBG(HFCUSB_DBG_STATES,
"HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)");
-#endif
} else {
/* force sending sending INFO1 */
queue_control_request(hfc,
@@ -1132,11 +1044,9 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
}
}
} else {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
- "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST");
-#endif
- set_hfcmode(hfc,
+ DBG(HFCUSB_DBG_STATES,
+ "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST");
+ setup_bchannel(hfc,
(fifo->fifonum ==
HFCUSB_B1_TX) ? 0 : 1,
(long) arg);
@@ -1147,18 +1057,12 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
break;
case PH_DEACTIVATE | REQUEST:
if (fifo->fifonum == HFCUSB_D_TX) {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+ DBG(HFCUSB_DBG_STATES,
"HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST");
-#endif
- printk(KERN_INFO
- "HFC-S USB: ISDN TE device should not deativate...\n");
} else {
-#ifdef CONFIG_HISAX_DEBUG
- DBG(ISDN_DBG,
+ DBG(HFCUSB_DBG_STATES,
"HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST");
-#endif
- set_hfcmode(hfc,
+ setup_bchannel(hfc,
(fifo->fifonum ==
HFCUSB_B1_TX) ? 0 : 1,
(int) L1_MODE_NULL);
@@ -1171,25 +1075,20 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
if (fifo->skbuff && fifo->delete_flg) {
dev_kfree_skb_any(fifo->skbuff);
fifo->skbuff = NULL;
- fifo->delete_flg = false;
+ fifo->delete_flg = 0;
}
fifo->skbuff = arg; /* we have a new buffer */
break;
default:
- printk(KERN_INFO
- "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n",
- pr);
+ DBG(HFCUSB_DBG_STATES,
+ "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x", pr);
break;
}
}
-/***************************************************************************/
-/* usb_init is called once when a new matching device is detected to setup */
-/* main parameters. It registers the driver at the main hisax module. */
-/* on success 0 is returned. */
-/***************************************************************************/
+/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */
static int
-usb_init(hfcusb_data * hfc)
+hfc_usb_init(hfcusb_data * hfc)
{
usb_fifo *fifo;
int i, err;
@@ -1214,11 +1113,11 @@ usb_init(hfcusb_data * hfc)
/* aux = output, reset off */
write_usb(hfc, HFCUSB_CIRM, 0x10);
- /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
+ /* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */
write_usb(hfc, HFCUSB_USB_SIZE,
(hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
- /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
+ /* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */
write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
/* enable PCM/GCI master mode */
@@ -1257,8 +1156,8 @@ usb_init(hfcusb_data * hfc)
hfc->b_mode[0] = L1_MODE_NULL;
hfc->b_mode[1] = L1_MODE_NULL;
- hfc->l1_activated = false;
- hfc->disc_flag = false;
+ hfc->l1_activated = 0;
+ hfc->disc_flag = 0;
hfc->led_state = 0;
hfc->led_new_data = 0;
hfc->old_led_state = 0;
@@ -1349,11 +1248,9 @@ usb_init(hfcusb_data * hfc)
handle_led(hfc, LED_POWER_ON);
return (0);
-} /* usb_init */
+}
-/*************************************************/
-/* function called to probe a new plugged device */
-/*************************************************/
+/* initial callback for each plugged USB device */
static int
hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
@@ -1378,11 +1275,6 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
}
}
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ifnum,
- iface->desc.bAlternateSetting, intf->minor);
-#endif
printk(KERN_INFO
"HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",
ifnum, iface->desc.bAlternateSetting, intf->minor);
@@ -1403,15 +1295,11 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* check for config EOL element */
while (validconf[cfg_used][0]) {
- cfg_found = true;
+ cfg_found = 1;
vcf = validconf[cfg_used];
/* first endpoint descriptor */
ep = iface->endpoint;
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-S USB: (if=%d alt=%d cfg_used=%d)\n",
- ifnum, probe_alt_setting, cfg_used);
-#endif
+
memcpy(cmptbl, vcf, 16 * sizeof(int));
/* check for all endpoints in this alternate setting */
@@ -1425,7 +1313,7 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
idx++;
attr = ep->desc.bmAttributes;
if (cmptbl[idx] == EP_NUL) {
- cfg_found = false;
+ cfg_found = 0;
}
if (attr == USB_ENDPOINT_XFER_INT
&& cmptbl[idx] == EP_INT)
@@ -1438,16 +1326,9 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
cmptbl[idx] = EP_NUL;
/* check if all INT endpoints match minimum interval */
- if (attr == USB_ENDPOINT_XFER_INT
- && ep->desc.bInterval <
- vcf[17]) {
-#ifdef CONFIG_HISAX_DEBUG
- if (cfg_found)
- DBG(USB_DBG,
- "HFC-S USB: Interrupt Endpoint interval < %d found - skipping config",
- vcf[17]);
-#endif
- cfg_found = false;
+ if ((attr == USB_ENDPOINT_XFER_INT)
+ && (ep->desc.bInterval < vcf[17])) {
+ cfg_found = 0;
}
ep++;
}
@@ -1455,7 +1336,7 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* all entries must be EP_NOP or EP_NUL for a valid config */
if (cmptbl[i] != EP_NOP
&& cmptbl[i] != EP_NUL)
- cfg_found = false;
+ cfg_found = 0;
}
if (cfg_found) {
if (cfg_used < small_match) {
@@ -1464,23 +1345,16 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
probe_alt_setting;
iface_used = iface;
}
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-USB: small_match=%x %x\n",
- small_match, alt_used);
-#endif
}
cfg_used++;
}
alt_idx++;
- } /* (alt_idx < intf->num_altsetting) */
+ } /* (alt_idx < intf->num_altsetting) */
/* found a valid USB Ta Endpint config */
if (small_match != 0xffff) {
iface = iface_used;
- if (!
- (context =
- kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
+ if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
return (-ENOMEM); /* got no mem */
ep = iface->endpoint;
@@ -1613,20 +1487,15 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
driver_info;
printk(KERN_INFO "HFC-S USB: detected \"%s\"\n",
driver_info->vend_name);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n",
+
+ DBG(HFCUSB_DBG_INIT,
+ "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)",
conf_str[small_match], context->if_used,
- context->alt_used);
- printk(KERN_INFO
- "HFC-S USB: E-channel (\"ECHO:\") logging ");
- if (validconf[small_match][18])
- printk(" possible\n");
- else
- printk("NOT possible\n");
-#endif
+ context->alt_used,
+ validconf[small_match][18]);
+
/* init the chip and register the driver */
- if (usb_init(context)) {
+ if (hfc_usb_init(context)) {
usb_kill_urb(context->ctrl_urb);
usb_free_urb(context->ctrl_urb);
context->ctrl_urb = NULL;
@@ -1643,17 +1512,19 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
return (-EIO);
}
-/****************************************************/
-/* function called when an active device is removed */
-/****************************************************/
+/* callback for unplugged USB device */
static void
hfc_usb_disconnect(struct usb_interface
*intf)
{
hfcusb_data *context = usb_get_intfdata(intf);
int i;
+
+ handle_led(context, LED_POWER_OFF);
+ schedule_timeout((10 * HZ) / 1000);
+
printk(KERN_INFO "HFC-S USB: device disconnect\n");
- context->disc_flag = true;
+ context->disc_flag = 1;
usb_set_intfdata(intf, NULL);
if (!context)
return;
@@ -1661,25 +1532,22 @@ hfc_usb_disconnect(struct usb_interface
del_timer(&context->t3_timer);
if (timer_pending(&context->t4_timer))
del_timer(&context->t4_timer);
+
/* tell all fifos to terminate */
for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
if (context->fifos[i].usb_transfer_mode == USB_ISOC) {
if (context->fifos[i].active > 0) {
stop_isoc_chain(&context->fifos[i]);
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-S USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i",
- i);
-#endif
+ DBG(HFCUSB_DBG_INIT,
+ "HFC-S USB: %s stopping ISOC chain Fifo(%i)",
+ __FUNCTION__, i);
}
} else {
if (context->fifos[i].active > 0) {
context->fifos[i].active = 0;
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG,
- "HFC-S USB: hfc_usb_disconnect: unlinking URB for Fifo no %i",
- i);
-#endif
+ DBG(HFCUSB_DBG_INIT,
+ "HFC-S USB: %s unlinking URB for Fifo(%i)",
+ __FUNCTION__, i);
}
usb_kill_urb(context->fifos[i].urb);
usb_free_urb(context->fifos[i].urb);
@@ -1692,34 +1560,29 @@ hfc_usb_disconnect(struct usb_interface
context->ctrl_urb = NULL;
hisax_unregister(&context->d_if);
kfree(context); /* free our structure again */
-} /* hfc_usb_disconnect */
+}
-/************************************/
-/* our driver information structure */
-/************************************/
static struct usb_driver hfc_drv = {
.name = "hfc_usb",
.id_table = hfcusb_idtab,
.probe = hfc_usb_probe,
.disconnect = hfc_usb_disconnect,
};
+
static void __exit
-hfc_usb_exit(void)
+hfc_usb_mod_exit(void)
{
-#ifdef CONFIG_HISAX_DEBUG
- DBG(USB_DBG, "HFC-S USB: calling \"hfc_usb_exit\" ...");
-#endif
- usb_deregister(&hfc_drv); /* release our driver */
+ usb_deregister(&hfc_drv); /* release our driver */
printk(KERN_INFO "HFC-S USB: module removed\n");
}
static int __init
-hfc_usb_init(void)
+hfc_usb_mod_init(void)
{
+ char revstr[30], datestr[30], dummy[30];
#ifndef CONFIG_HISAX_DEBUG
- unsigned int debug = -1;
+ hfc_debug = debug;
#endif
- char revstr[30], datestr[30], dummy[30];
sscanf(hfcusb_revision,
"%s %s $ %s %s %s $ ", dummy, revstr,
dummy, datestr, dummy);
@@ -1734,8 +1597,8 @@ hfc_usb_init(void)
return (0);
}
-module_init(hfc_usb_init);
-module_exit(hfc_usb_exit);
+module_init(hfc_usb_mod_init);
+module_exit(hfc_usb_mod_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
index 471f2354dfde..e79f56568d30 100644
--- a/drivers/isdn/hisax/hfc_usb.h
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -1,8 +1,8 @@
/*
-* hfc_usb.h
-*
-* $Id: hfc_usb.h,v 4.2 2005/04/07 15:27:17 martinb1 Exp $
-*/
+ * hfc_usb.h
+ *
+ * $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $
+ */
#ifndef __HFC_USB_H__
#define __HFC_USB_H__
@@ -10,25 +10,20 @@
#define DRIVER_AUTHOR "Peter Sprenger (sprenger@moving-byters.de)"
#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver"
-#define VERBOSE_USB_DEBUG
+#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
+#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
+#define HFC_TIMER_T4 500 /* time for state change interval */
-/***********/
-/* defines */
-/***********/
-#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
-#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
-#define HFC_TIMER_T4 500 /* time for state change interval */
+#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
+#define HFCUSB_L1_DRX 1 /* D-frame received */
+#define HFCUSB_L1_ERX 2 /* E-frame received */
+#define HFCUSB_L1_DTX 4 /* D-frames completed */
-#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
-#define HFCUSB_L1_DRX 1 /* D-frame received */
-#define HFCUSB_L1_ERX 2 /* E-frame received */
-#define HFCUSB_L1_DTX 4 /* D-frames completed */
+#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
-#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
-
-#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
-#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
+#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
+#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
#define HFCUSB_CIRM 0x00 /* cirm register index */
@@ -52,9 +47,8 @@
#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
-/******************/
+
/* fifo registers */
-/******************/
#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
@@ -66,9 +60,9 @@
#define HFCUSB_PCM_RX 7
/*
-* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
-* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
-*/
+ * used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
+ * supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
+ */
#define USB_INT 0
#define USB_BULK 1
#define USB_ISOC 2
@@ -77,49 +71,36 @@
#define ISOC_PACKETS_B 8
#define ISO_BUFFER_SIZE 128
-// ISO send definitions
+/* Fifo flow Control for TX ISO */
#define SINK_MAX 68
#define SINK_MIN 48
#define SINK_DMIN 12
#define SINK_DMAX 18
#define BITLINE_INF (-64*8)
-
-/**********/
-/* macros */
-/**********/
+/* HFC-S USB register access by Control-URSs */
#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT)
#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
-
-
-/*******************/
-/* Debugging Flags */
-/*******************/
-#define USB_DBG 1
-#define ISDN_DBG 2
-
-
-/* *********************/
-/* USB related defines */
-/***********************/
#define HFC_CTRL_BUFSIZE 32
-
-
-/*************************************************/
/* entry and size of output/input control buffer */
-/*************************************************/
typedef struct {
__u8 hfc_reg; /* register number */
__u8 reg_val; /* value to be written (or read) */
int action; /* data for action handler */
} ctrl_buft;
+/* Debugging Flags */
+#define HFCUSB_DBG_INIT 0x0001
+#define HFCUSB_DBG_STATES 0x0002
+#define HFCUSB_DBG_DCHANNEL 0x0080
+#define HFCUSB_DBG_FIFO_ERR 0x4000
+#define HFCUSB_DBG_VERBOSE_USB 0x8000
-/********************/
-/* URB error codes: */
-/********************/
-/* Used to represent a list of values and their respective symbolic names */
+/*
+ * URB error codes:
+ * Used to represent a list of values and their respective symbolic names
+ */
struct hfcusb_symbolic_list {
const int num;
const char *name;
@@ -134,20 +115,20 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
{-ENXIO, "URB already queued"},
{-EFBIG, "Too much ISO frames requested"},
{-ENOSR, "Buffer error (overrun)"},
- {-EPIPE, "Specified endpoint is stalled"},
+ {-EPIPE, "Specified endpoint is stalled (device not responding)"},
{-EOVERFLOW, "Babble (bad cable?)"},
{-EPROTO, "Bit-stuff error (bad cable?)"},
- {-EILSEQ, "CRC or missing token"},
- {-ETIME, "Device did not respond"},
+ {-EILSEQ, "CRC/Timeout"},
+ {-ETIMEDOUT, "NAK (device does not respond)"},
{-ESHUTDOWN, "Device unplugged"},
{-1, NULL}
};
-/*****************************************************/
-/* device dependant information to support different */
-/* ISDN Ta's using the HFC-S USB chip */
-/*****************************************************/
+/*
+ * device dependant information to support different
+ * ISDN Ta's using the HFC-S USB chip
+ */
/* USB descriptor need to contain one of the following EndPoint combination: */
#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT
@@ -155,16 +136,19 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT
#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT
-#define EP_NUL 1 // Endpoint at this position not allowed
-#define EP_NOP 2 // all type of endpoints allowed at this position
-#define EP_ISO 3 // Isochron endpoint mandatory at this position
-#define EP_BLK 4 // Bulk endpoint mandatory at this position
-#define EP_INT 5 // Interrupt endpoint mandatory at this position
+#define EP_NUL 1 // Endpoint at this position not allowed
+#define EP_NOP 2 // all type of endpoints allowed at this position
+#define EP_ISO 3 // Isochron endpoint mandatory at this position
+#define EP_BLK 4 // Bulk endpoint mandatory at this position
+#define EP_INT 5 // Interrupt endpoint mandatory at this position
-/* this array represents all endpoints possible in the HCF-USB the last
-* 3 entries are the configuration number, the minimum interval for
-* Interrupt endpoints & boolean if E-channel logging possible
-*/
+/*
+ * List of all supported endpoint configuration sets, used to find the
+ * best matching endpoint configuration within a devices' USB descriptor.
+ * We need at least 3 RX endpoints, and 3 TX endpoints, either
+ * INT-in and ISO-out, or ISO-in and ISO-out)
+ * with 4 RX endpoints even E-Channel logging is possible
+ */
static int validconf[][19] = {
// INT in, ISO out config
{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
@@ -193,7 +177,6 @@ static char *conf_str[] = {
};
#endif
-
typedef struct {
int vendor; // vendor id
int prod_id; // product id
@@ -202,9 +185,9 @@ typedef struct {
signed short led_bits[8]; // array of 8 possible LED bitmask settings
} vendor_data;
-#define LED_OFF 0 // no LED support
-#define LED_SCHEME1 1 // LED standard scheme
-#define LED_SCHEME2 2 // not used yet...
+#define LED_OFF 0 // no LED support
+#define LED_SCHEME1 1 // LED standard scheme
+#define LED_SCHEME2 2 // not used yet...
#define LED_POWER_ON 1
#define LED_POWER_OFF 2
@@ -217,11 +200,8 @@ typedef struct {
#define LED_B2_OFF 9
#define LED_B2_DATA 10
-#define LED_NORMAL 0 // LEDs are normal
-#define LED_INVERTED 1 // LEDs are inverted
-
-/* time in ms to perform a Flashing LED when B-Channel has traffic */
-#define LED_TIME 250
+#define LED_NORMAL 0 // LEDs are normal
+#define LED_INVERTED 1 // LEDs are inverted
-#endif // __HFC_USB_H__
+#endif // __HFC_USB_H__
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index ad06f3cc60fb..03dfc32166a0 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
#ifdef __ISAPNP__
static struct isapnp_device_id sedl_ids[] __devinitdata = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+ struct IsdnCardState *cs = card->cs;
+ struct pnp_dev *pnp_d;
+
+ if (!isapnp_present())
+ return -1;
+
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+ cs->subtyp = SEDL_SPEED_FAX;
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ *bytecnt = 16;
+ } else {
+ cs->subtyp = SEDL_SPEED_CARD_WIN;
+ cs->hw.sedl.chip = SEDL_CHIP_TEST;
+ }
+
+ return (1);
+ } else {
+ printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c = NULL;
+ }
+
+ printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+ return -1;
+}
+#else
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+ return -1;
+}
+#endif /* __ISAPNP__ */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u16 sub_vendor_id, sub_id;
+
+ if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+ if (pci_enable_device(dev_sedl))
+ return(0);
+ cs->irq = dev_sedl->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+ } else {
+ printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+ cs->hw.sedl.bus = SEDL_BUS_PCI;
+ sub_vendor_id = dev_sedl->subsystem_vendor;
+ sub_id = dev_sedl->subsystem_device;
+ printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+ sub_vendor_id, sub_id);
+ printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+ cs->hw.sedl.cfg_reg);
+ if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+ printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+ return(0);
+ }
+ if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PCI;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = HST_SAPHIR3;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = SEDL_SPEED_PCI;
+ } else {
+ printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+ sub_vendor_id);
+ return(0);
+ }
+
+ cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+ byteout(cs->hw.sedl.cfg_reg, 0xff);
+ byteout(cs->hw.sedl.cfg_reg, 0x00);
+ byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+ mdelay(2);
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+ mdelay(10);
+
+ return (1);
+}
+
+#else
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+ return (1);
+}
+
+#endif /* CONFIG_PCI */
int __devinit
setup_sedlbauer(struct IsdnCard *card)
{
- int bytecnt, ver, val;
+ int bytecnt = 8, ver, val, rc;
struct IsdnCardState *cs = card->cs;
char tmp[64];
- u16 sub_vendor_id, sub_id;
strcpy(tmp, Sedlbauer_revision);
printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card)
bytecnt = 16;
}
} else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.sedl.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0x2)) {
- cs->subtyp = SEDL_SPEED_FAX;
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- bytecnt = 16;
- } else {
- cs->subtyp = SEDL_SPEED_CARD_WIN;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- }
- goto ready;
- } else {
- printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
- }
- }
-#endif
-/* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
- if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
- if (pci_enable_device(dev_sedl))
- return(0);
- cs->irq = dev_sedl->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
- } else {
- printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.sedl.bus = SEDL_BUS_PCI;
- sub_vendor_id = dev_sedl->subsystem_vendor;
- sub_id = dev_sedl->subsystem_device;
- printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
- sub_vendor_id, sub_id);
- printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
- cs->hw.sedl.cfg_reg);
- if (sub_id != PCI_SUB_ID_SEDLBAUER) {
- printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
- return(0);
- }
- if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PCI;
- } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = HST_SAPHIR3;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = SEDL_SPEED_PCI;
- } else {
- printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
- sub_vendor_id);
- return(0);
- }
+ rc = setup_sedlbauer_isapnp(card, &bytecnt);
+ if (!rc)
+ return (0);
+ if (rc > 0)
+ goto ready;
+
+ /* Probe for Sedlbauer speed pci */
+ rc = setup_sedlbauer_pci(card);
+ if (!rc)
+ return (0);
+
bytecnt = 256;
- cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
- byteout(cs->hw.sedl.cfg_reg, 0xff);
- byteout(cs->hw.sedl.cfg_reg, 0x00);
- byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
- mdelay(2);
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- mdelay(10);
-#else
- printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
}
-#ifdef __ISAPNP__
ready:
-#endif
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index d09f6d033f15..4393003ae162 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card)
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
+
strcpy(tmp, telespci_revision);
printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELESPCI)
return (0);
-#ifdef CONFIG_PCI
+
if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
if (pci_enable_device(dev_tel))
return(0);
@@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card)
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
}
-#else
- printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
- printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
/* Initialize Zoran PCI controller */
writel(0x00000000, cs->hw.teles0.membase + 0x28);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 3aeceaf9769e..39129b94f8be 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card)
printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_W6692)
return (0);
-#ifdef CONFIG_PCI
+
while (id_list[id_idx].vendor_id) {
dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
id_list[id_idx].device_id,
@@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card)
cs->hw.w6692.iobase + 255);
return (0);
}
-#else
- printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "HiSax: W6692 unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
printk(KERN_INFO
"HiSax: %s config irq:%d I/O:%x\n",
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 9e01748a176e..b7cc5c2f08c6 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -20,10 +20,15 @@
#include "hysdn_defs.h"
static struct pci_device_id hysdn_pci_tbl[] = {
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
+
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -34,128 +39,7 @@ MODULE_LICENSE("GPL");
static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
static int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
-
-/**********************************************/
-/* table assigning PCI-sub ids to board types */
-/* the last entry contains all 0 */
-/**********************************************/
-static struct {
- unsigned short subid; /* PCI sub id */
- unsigned char cardtyp; /* card type assigned */
-} pci_subid_map[] = {
-
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
- },
- {
- 0, 0
- } /* terminating entry */
-};
-
-
-/*********************************************************************/
-/* search_cards searches for available cards in the pci config data. */
-/* If a card is found, the card structure is allocated and the cards */
-/* ressources are reserved. cardmax is incremented. */
-/*********************************************************************/
-static void
-search_cards(void)
-{
- struct pci_dev *akt_pcidev = NULL;
- hysdn_card *card, *card_last;
- int i;
-
- card_root = NULL;
- card_last = NULL;
- while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- akt_pcidev)) != NULL) {
- if (pci_enable_device(akt_pcidev))
- continue;
-
- if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
- printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
- return;
- }
- card->myid = cardmax; /* set own id */
- card->bus = akt_pcidev->bus->number;
- card->devfn = akt_pcidev->devfn; /* slot + function */
- card->subsysid = akt_pcidev->subsystem_device;
- card->irq = akt_pcidev->irq;
- card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
- card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
- card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
- card->brdtype = BD_NONE; /* unknown */
- card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
- card->faxchans = 0; /* default no fax channels */
- card->bchans = 2; /* and 2 b-channels */
- for (i = 0; pci_subid_map[i].subid; i++)
- if (pci_subid_map[i].subid == card->subsysid) {
- card->brdtype = pci_subid_map[i].cardtyp;
- break;
- }
- if (card->brdtype != BD_NONE) {
- if (ergo_inithardware(card)) {
- printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
- kfree(card);
- continue;
- }
- } else {
- printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
- kfree(card); /* release mem */
- continue;
- }
- cardmax++;
- card->next = NULL; /*end of chain */
- if (card_last)
- card_last->next = card; /* pointer to next card */
- else
- card_root = card;
- card_last = card; /* new chain end */
- } /* device found */
-} /* search_cards */
-
-/************************************************************************************/
-/* free_resources frees the acquired PCI resources and returns the allocated memory */
-/************************************************************************************/
-static void
-free_resources(void)
-{
- hysdn_card *card;
-
- while (card_root) {
- card = card_root;
- if (card->releasehardware)
- card->releasehardware(card); /* free all hardware resources */
- card_root = card_root->next; /* remove card from chain */
- kfree(card); /* return mem */
-
- } /* while card_root */
-} /* free_resources */
-
-/**************************************************************************/
-/* stop_cards disables (hardware resets) all cards and disables interrupt */
-/**************************************************************************/
-static void
-stop_cards(void)
-{
- hysdn_card *card;
-
- card = card_root; /* first in chain */
- while (card) {
- if (card->stopcard)
- card->stopcard(card);
- card = card->next; /* remove card from chain */
- } /* while card */
-} /* stop_cards */
+static hysdn_card *card_last = NULL; /* pointer to first card */
/****************************************************************************/
@@ -191,31 +75,138 @@ hysdn_getrev(const char *revision)
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
+
+static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+ const struct pci_device_id *ent)
+{
+ hysdn_card *card;
+ int rc;
+
+ rc = pci_enable_device(akt_pcidev);
+ if (rc)
+ return rc;
+
+ if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+ card->subsysid = akt_pcidev->subsystem_device;
+ card->irq = akt_pcidev->irq;
+ card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+ card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+ card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+ card->bchans = 2; /* and 2 b-channels */
+ card->brdtype = ent->driver_data;
+
+ if (ergo_inithardware(card)) {
+ printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+ rc = -EBUSY;
+ goto err_out_card;
+ }
+
+ cardmax++;
+ card->next = NULL; /*end of chain */
+ if (card_last)
+ card_last->next = card; /* pointer to next card */
+ else
+ card_root = card;
+ card_last = card; /* new chain end */
+
+ pci_set_drvdata(akt_pcidev, card);
+ return 0;
+
+err_out_card:
+ kfree(card);
+err_out:
+ pci_disable_device(akt_pcidev);
+ return rc;
+}
+
+static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+{
+ hysdn_card *card = pci_get_drvdata(akt_pcidev);
+
+ pci_set_drvdata(akt_pcidev, NULL);
+
+ if (card->stopcard)
+ card->stopcard(card);
+
+#ifdef CONFIG_HYSDN_CAPI
+ hycapi_capi_release(card);
+#endif
+
+ if (card->releasehardware)
+ card->releasehardware(card); /* free all hardware resources */
+
+ if (card == card_root) {
+ card_root = card_root->next;
+ if (!card_root)
+ card_last = NULL;
+ } else {
+ hysdn_card *tmp = card_root;
+ while (tmp) {
+ if (tmp->next == card)
+ tmp->next = card->next;
+ card_last = tmp;
+ tmp = tmp->next;
+ }
+ }
+
+ kfree(card);
+ pci_disable_device(akt_pcidev);
+}
+
+static struct pci_driver hysdn_pci_driver = {
+ .name = "hysdn",
+ .id_table = hysdn_pci_tbl,
+ .probe = hysdn_pci_init_one,
+ .remove = __devexit_p(hysdn_pci_remove_one),
+};
+
+static int hysdn_have_procfs;
+
static int __init
hysdn_init(void)
{
char tmp[50];
+ int rc;
strcpy(tmp, hysdn_init_revision);
printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
strcpy(tmp, hysdn_net_revision);
printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
- search_cards();
+
+ rc = pci_register_driver(&hysdn_pci_driver);
+ if (rc)
+ return rc;
+
printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
- if (hysdn_procconf_init()) {
- free_resources(); /* proc file_sys not created */
- return (-1);
- }
+ if (!hysdn_procconf_init())
+ hysdn_have_procfs = 1;
+
#ifdef CONFIG_HYSDN_CAPI
if(cardmax > 0) {
if(hycapi_init()) {
printk(KERN_ERR "HYCAPI: init failed\n");
- return(-1);
+
+ if (hysdn_have_procfs)
+ hysdn_procconf_release();
+
+ pci_unregister_driver(&hysdn_pci_driver);
+ return -ESPIPE;
}
}
#endif /* CONFIG_HYSDN_CAPI */
- return (0); /* no error */
+
+ return 0; /* no error */
} /* init_module */
@@ -230,20 +221,15 @@ hysdn_init(void)
static void __exit
hysdn_exit(void)
{
+ if (hysdn_have_procfs)
+ hysdn_procconf_release();
+
+ pci_unregister_driver(&hysdn_pci_driver);
+
#ifdef CONFIG_HYSDN_CAPI
- hysdn_card *card;
-#endif /* CONFIG_HYSDN_CAPI */
- stop_cards();
-#ifdef CONFIG_HYSDN_CAPI
- card = card_root; /* first in chain */
- while (card) {
- hycapi_capi_release(card);
- card = card->next; /* remove card from chain */
- } /* while card */
hycapi_cleanup();
#endif /* CONFIG_HYSDN_CAPI */
- hysdn_procconf_release();
- free_resources();
+
printk(KERN_NOTICE "HYSDN: module unloaded\n");
} /* cleanup_module */
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index dc477e0aab0e..27d890b48f88 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -16,6 +16,7 @@
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
+#include <net/net_namespace.h>
#include "hysdn_defs.h"
@@ -392,7 +393,7 @@ hysdn_procconf_init(void)
hysdn_card *card;
unsigned char conf_name[20];
- hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, proc_net);
+ hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, init_net.proc_net);
if (!hysdn_proc_entry) {
printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
return (-1);
@@ -437,5 +438,5 @@ hysdn_procconf_release(void)
card = card->next; /* point to next card */
}
- remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+ remove_proc_entry(PROC_SUBDIR_NAME, init_net.proc_net);
}
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index e91c187992dd..36778b270c30 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -99,7 +99,6 @@ config ISDN_DRV_LOOP
config ISDN_DIVERSION
tristate "Support isdn diversion services"
- depends on ISDN_I4L
help
This option allows you to use some supplementary diversion
services in conjunction with the HiSax driver on an EURO/DSS1
@@ -119,13 +118,11 @@ config ISDN_DIVERSION
endmenu
comment "ISDN4Linux hardware drivers"
- depends on ISDN_I4L
source "drivers/isdn/hisax/Kconfig"
menu "Active cards"
- depends on ISDN_I4L!=n
source "drivers/isdn/icn/Kconfig"
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
index 90a23795db7e..02d9918705dd 100644
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -341,7 +341,7 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data)
* Allocate space for the dictionary. This may be more than one page in
* length.
*/
- db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict));
+ db->dict = vmalloc(hsize * sizeof(struct bsd_dict));
if (!db->dict) {
bsd_free (db);
return NULL;
@@ -354,8 +354,7 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data)
if (!decomp)
db->lens = NULL;
else {
- db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
- sizeof (db->lens[0]));
+ db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0]));
if (!db->lens) {
bsd_free (db);
return (NULL);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index c97330b19877..4910bca52640 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1135,7 +1135,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
if (count > dev->drv[drvidx]->stavail)
count = dev->drv[drvidx]->stavail;
len = dev->drv[drvidx]->interface->readstat(buf, count,
- drvidx, isdn_minor2chan(minor));
+ drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
if (len < 0) {
retval = len;
goto out;
@@ -1207,7 +1207,8 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off
*/
if (dev->drv[drvidx]->interface->writecmd)
retval = dev->drv[drvidx]->interface->
- writecmd(buf, count, drvidx, isdn_minor2chan(minor));
+ writecmd(buf, count, drvidx,
+ isdn_minor2chan(minor - ISDN_MINOR_CTRL));
else
retval = count;
goto out;
@@ -2291,7 +2292,7 @@ static int __init isdn_init(void)
int i;
char tmprev[50];
- if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
+ if (!(dev = vmalloc(sizeof(isdn_dev)))) {
printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
return -EIO;
}
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index aa83277aba74..7c9cb7e19f2e 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -77,7 +77,7 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n)
if (lp->master)
dev = lp->master;
else
- dev = &n->dev;
+ dev = n->dev;
return netif_running(dev);
}
@@ -90,7 +90,7 @@ static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
if (lp->master)
netif_wake_queue(lp->master);
else
- netif_wake_queue(&lp->netdev->dev);
+ netif_wake_queue(lp->netdev->dev);
}
/*
@@ -102,7 +102,7 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
if (lp->master)
netif_stop_queue(lp->master);
else
- netif_stop_queue(&lp->netdev->dev);
+ netif_stop_queue(lp->netdev->dev);
}
/*
@@ -287,7 +287,7 @@ isdn_net_unbind_channel(isdn_net_local * lp)
BEWARE! This chunk of code cannot be called from hardware
interrupt handler. I hope it is true. --ANK
*/
- qdisc_reset(lp->netdev->dev.qdisc);
+ qdisc_reset(lp->netdev->dev->qdisc);
}
lp->dialstate = 0;
dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
@@ -345,27 +345,27 @@ isdn_net_autohup(void)
l->chargetime += l->chargeint;
if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
if (l->outgoing || l->hupflags & ISDN_INHUP)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
} else if (l->outgoing) {
if (l->hupflags & ISDN_CHARGEHUP) {
if (l->hupflags & ISDN_WAITCHARGE) {
printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
l->name, l->hupflags);
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
printk(KERN_DEBUG
"isdn_net: %s: chtime = %lu, chint = %d\n",
l->name, l->chargetime, l->chargeint);
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
}
} else
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
} else if (l->hupflags & ISDN_INHUP)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
}
if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
break;
}
}
@@ -579,7 +579,7 @@ isdn_net_dial(void)
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
lp->name);
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
break;
}
anymore = 1;
@@ -616,8 +616,8 @@ isdn_net_dial(void)
s = "dial suppressed: isdn system stopped";
else
s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(&p->dev, NULL, s);
- isdn_net_hangup(&p->dev);
+ isdn_net_unreachable(p->dev, NULL, s);
+ isdn_net_hangup(p->dev);
break;
}
cmd.driver = lp->isdn_device;
@@ -633,7 +633,7 @@ isdn_net_dial(void)
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
lp->name);
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
break;
}
if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
@@ -644,8 +644,8 @@ isdn_net_dial(void)
if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, NULL, "dial: timed out");
- isdn_net_hangup(&p->dev);
+ isdn_net_unreachable(p->dev, NULL, "dial: timed out");
+ isdn_net_hangup(p->dev);
break;
}
@@ -674,9 +674,9 @@ isdn_net_dial(void)
if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times");
+ isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times");
}
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
break;
}
}
@@ -758,7 +758,7 @@ isdn_net_dial(void)
cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
isdn_command(&cmd);
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
else {
anymore = 1;
lp->dialstate++;
@@ -781,7 +781,7 @@ isdn_net_dial(void)
printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
#endif
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
else
anymore = 1;
break;
@@ -1618,7 +1618,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
__be32 addr = 0; /* local ipv4 address */
__be32 mask = 0; /* local netmask */
- if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+ if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
@@ -1866,61 +1866,21 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
isdn_net_local *lp = p->local;
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
- isdn_net_receive(&p->dev, skb);
+ isdn_net_receive(p->dev, skb);
return 1;
}
}
return 0;
}
-static int
-my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
-{
- struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
- /*
- * Set the protocol type. For a packet of type ETH_P_802_3 we
- * put the length here instead. It is up to the 802.2 layer to
- * carry protocol information.
- */
-
- if (type != ETH_P_802_3)
- eth->h_proto = htons(type);
- else
- eth->h_proto = htons(len);
-
- /*
- * Set the source hardware address.
- */
- if (saddr)
- memcpy(eth->h_source, saddr, dev->addr_len);
- else
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-
- /*
- * Anyway, the loopback-device should never use this function...
- */
-
- if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
- memset(eth->h_dest, 0, dev->addr_len);
- return ETH_HLEN /*(dev->hard_header_len)*/;
- }
- if (daddr) {
- memcpy(eth->h_dest, daddr, dev->addr_len);
- return ETH_HLEN /*dev->hard_header_len*/;
- }
- return -ETH_HLEN /*dev->hard_header_len*/;
-}
-
/*
* build an header
* depends on encaps that is being used.
*/
-static int
-isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned plen)
+static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type,
+ const void *daddr, const void *saddr, unsigned plen)
{
isdn_net_local *lp = dev->priv;
unsigned char *p;
@@ -1928,7 +1888,7 @@ isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
- len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+ len = eth_header(skb, dev, type, daddr, saddr, plen);
break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP:
@@ -2005,6 +1965,32 @@ isdn_net_rebuild_header(struct sk_buff *skb)
return ret;
}
+static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
+{
+ const struct net_device *dev = neigh->dev;
+ isdn_net_local *lp = dev->priv;
+
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+ return eth_header_cache(neigh, hh);
+ return -1;
+}
+
+static void isdn_header_cache_update(struct hh_cache *hh,
+ const struct net_device *dev,
+ const unsigned char *haddr)
+{
+ isdn_net_local *lp = dev->priv;
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+ return eth_header_cache_update(hh, dev, haddr);
+}
+
+static const struct header_ops isdn_header_ops = {
+ .create = isdn_net_header,
+ .rebuild = isdn_net_rebuild_header,
+ .cache = isdn_header_cache,
+ .cache_update = isdn_header_cache_update,
+};
+
/*
* Interface-setup. (just after registering a new interface)
*/
@@ -2012,18 +1998,12 @@ static int
isdn_net_init(struct net_device *ndev)
{
ushort max_hlhdr_len = 0;
- isdn_net_local *lp = (isdn_net_local *) ndev->priv;
- int drvidx, i;
+ int drvidx;
ether_setup(ndev);
- lp->org_hhc = ndev->hard_header_cache;
- lp->org_hcu = ndev->header_cache_update;
+ ndev->header_ops = NULL;
/* Setup the generic properties */
-
- ndev->hard_header = NULL;
- ndev->hard_header_cache = NULL;
- ndev->header_cache_update = NULL;
ndev->mtu = 1500;
ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
ndev->type = ARPHRD_ETHER;
@@ -2032,9 +2012,6 @@ isdn_net_init(struct net_device *ndev)
/* for clients with MPPP maybe higher values better */
ndev->tx_queue_len = 30;
- for (i = 0; i < ETH_ALEN; i++)
- ndev->broadcast[i] = 0xff;
-
/* The ISDN-specific entries in the device structure. */
ndev->open = &isdn_net_open;
ndev->hard_start_xmit = &isdn_net_start_xmit;
@@ -2052,7 +2029,6 @@ isdn_net_init(struct net_device *ndev)
ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
ndev->stop = &isdn_net_close;
ndev->get_stats = &isdn_net_get_stats;
- ndev->rebuild_header = &isdn_net_rebuild_header;
ndev->do_ioctl = NULL;
return 0;
}
@@ -2531,6 +2507,42 @@ isdn_net_force_dial(char *name)
}
/*
+ * Helper for alloc_netdev()
+ */
+static void _isdn_setup(struct net_device *dev)
+{
+ isdn_net_local *lp = dev->priv;
+
+ dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ lp->p_encap = ISDN_NET_ENCAP_RAWIP;
+ lp->magic = ISDN_NET_MAGIC;
+ lp->last = lp;
+ lp->next = lp;
+ lp->isdn_device = -1;
+ lp->isdn_channel = -1;
+ lp->pre_device = -1;
+ lp->pre_channel = -1;
+ lp->exclusive = -1;
+ lp->ppp_slot = -1;
+ lp->pppbind = -1;
+ skb_queue_head_init(&lp->super_tx_queue);
+ lp->l2_proto = ISDN_PROTO_L2_X75I;
+ lp->l3_proto = ISDN_PROTO_L3_TRANS;
+ lp->triggercps = 6000;
+ lp->slavedelay = 10 * HZ;
+ lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
+ lp->onhtime = 10; /* Default hangup-time for saving costs */
+ lp->dialmax = 1;
+ /* Hangup before Callback, manual dial */
+ lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
+ lp->cbdelay = 25; /* Wait 5 secs before Callback */
+ lp->dialtimeout = -1; /* Infinite Dial-Timeout */
+ lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
+ lp->dialstarted = 0; /* Jiffies of last dial-start */
+ lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
+}
+
+/*
* Allocate a new network-interface and initialize its data structures.
*/
char *
@@ -2543,23 +2555,21 @@ isdn_net_new(char *name, struct net_device *master)
printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
return NULL;
}
+ if (name == NULL)
+ name = " ";
if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return NULL;
}
- if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+ netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, _isdn_setup);
+ if (!netdev->dev) {
+ printk(KERN_WARNING "isdn_net: Could not allocate network device\n");
kfree(netdev);
return NULL;
}
- if (name == NULL)
- strcpy(netdev->local->name, " ");
- else
- strcpy(netdev->local->name, name);
- strcpy(netdev->dev.name, netdev->local->name);
- netdev->dev.priv = netdev->local;
- netdev->dev.init = isdn_net_init;
- netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
+ netdev->local = netdev->dev->priv;
+ strcpy(netdev->local->name, netdev->dev->name);
+ netdev->dev->init = isdn_net_init;
if (master) {
/* Device shall be a slave */
struct net_device *p = (((isdn_net_local *) master->priv)->slave);
@@ -2571,60 +2581,33 @@ isdn_net_new(char *name, struct net_device *master)
q = p;
p = (((isdn_net_local *) p->priv)->slave);
}
- ((isdn_net_local *) q->priv)->slave = &(netdev->dev);
+ ((isdn_net_local *) q->priv)->slave = netdev->dev;
} else {
/* Device shall be a master */
/*
* Watchdog timer (currently) for master only.
*/
- netdev->dev.tx_timeout = isdn_net_tx_timeout;
- netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
- if (register_netdev(&netdev->dev) != 0) {
+ netdev->dev->tx_timeout = isdn_net_tx_timeout;
+ netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
+ if (register_netdev(netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
- kfree(netdev->local);
+ free_netdev(netdev->dev);
kfree(netdev);
return NULL;
}
}
- netdev->local->magic = ISDN_NET_MAGIC;
-
netdev->queue = netdev->local;
spin_lock_init(&netdev->queue_lock);
- netdev->local->last = netdev->local;
netdev->local->netdev = netdev;
- netdev->local->next = netdev->local;
INIT_WORK(&netdev->local->tqueue, isdn_net_softint);
spin_lock_init(&netdev->local->xmit_lock);
- netdev->local->isdn_device = -1;
- netdev->local->isdn_channel = -1;
- netdev->local->pre_device = -1;
- netdev->local->pre_channel = -1;
- netdev->local->exclusive = -1;
- netdev->local->ppp_slot = -1;
- netdev->local->pppbind = -1;
- skb_queue_head_init(&netdev->local->super_tx_queue);
- netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
- netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
- netdev->local->triggercps = 6000;
- netdev->local->slavedelay = 10 * HZ;
- netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- netdev->local->onhtime = 10; /* Default hangup-time for saving costs
- of those who forget configuring this */
- netdev->local->dialmax = 1;
- netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
- netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
- netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */
- netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
- netdev->local->dialstarted = 0; /* Jiffies of last dial-start */
- netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
-
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
- return netdev->dev.name;
+ return netdev->dev->name;
}
char *
@@ -2649,7 +2632,7 @@ isdn_net_newslave(char *parm)
/* Master must not be started yet */
if (isdn_net_device_started(n))
return NULL;
- return (isdn_net_new(newname, &(n->dev)));
+ return (isdn_net_new(newname, n->dev));
}
return NULL;
}
@@ -2718,9 +2701,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
lp->name);
return -EINVAL;
#else
- p->dev.type = ARPHRD_PPP; /* change ARP type */
- p->dev.addr_len = 0;
- p->dev.do_ioctl = isdn_ppp_dev_ioctl;
+ p->dev->type = ARPHRD_PPP; /* change ARP type */
+ p->dev->addr_len = 0;
+ p->dev->do_ioctl = isdn_ppp_dev_ioctl;
#endif
break;
case ISDN_NET_ENCAP_X25IFACE:
@@ -2729,12 +2712,12 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
p->local->name);
return -EINVAL;
#else
- p->dev.type = ARPHRD_X25; /* change ARP type */
- p->dev.addr_len = 0;
+ p->dev->type = ARPHRD_X25; /* change ARP type */
+ p->dev->addr_len = 0;
#endif
break;
case ISDN_NET_ENCAP_CISCOHDLCK:
- p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
+ p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl;
break;
default:
if( cfg->p_encap >= 0 &&
@@ -2861,21 +2844,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
}
if (cfg->p_encap != lp->p_encap) {
if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev.hard_header = NULL;
- p->dev.hard_header_cache = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
+ p->dev->header_ops = NULL;
+ p->dev->flags = IFF_NOARP|IFF_POINTOPOINT;
} else {
- p->dev.hard_header = isdn_net_header;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
- p->dev.hard_header_cache = lp->org_hhc;
- p->dev.header_cache_update = lp->org_hcu;
- p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
- } else {
- p->dev.hard_header_cache = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
- }
+ p->dev->header_ops = &isdn_header_ops;
+ if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
+ p->dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+ else
+ p->dev->flags = IFF_NOARP|IFF_POINTOPOINT;
}
}
lp->p_encap = cfg->p_encap;
@@ -3095,7 +3071,7 @@ isdn_net_force_hangup(char *name)
isdn_net_hangup(q);
q = (((isdn_net_local *) q->priv)->slave);
}
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
return 0;
}
return -ENODEV;
@@ -3123,13 +3099,11 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
if (p->local->master) {
/* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
+ if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev)
((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
} else {
/* Unregister only if it's a master-device */
- p->dev.hard_header_cache = p->local->org_hhc;
- p->dev.header_cache_update = p->local->org_hcu;
- unregister_netdev(&p->dev);
+ unregister_netdev(p->dev);
}
/* Unlink device from chain */
spin_lock_irqsave(&dev->lock, flags);
@@ -3157,7 +3131,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
/* If no more net-devices remain, disable auto-hangup timer */
if (dev->netdev == NULL)
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- kfree(p->local);
+ free_netdev(p->dev);
kfree(p);
return 0;
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 387392cb3d68..0e5e59f84344 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -360,7 +360,7 @@ isdn_ppp_release(int min, struct file *file)
* isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
* removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
*/
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
}
for (i = 0; i < NUM_RCV_BUFFS; i++) {
kfree(is->rq[i].buf);
@@ -531,7 +531,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
if (lp) {
/* OK .. we are ready to send buffers */
is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
- netif_wake_queue(&lp->netdev->dev);
+ netif_wake_queue(lp->netdev->dev);
break;
}
}
@@ -1023,7 +1023,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
static void
isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
- struct net_device *dev = &net_dev->dev;
+ struct net_device *dev = net_dev->dev;
struct ippp_struct *is, *mis;
isdn_net_local *mlp = NULL;
int slot;
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
index fcb99f5f0b26..89d15eed765e 100644
--- a/drivers/isdn/icn/Kconfig
+++ b/drivers/isdn/icn/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_ICN
tristate "ICN 2B and 4B support"
- depends on ISDN_I4L && ISA
+ depends on ISA
help
This enables support for two kinds of ISDN-cards made by a German
company called ICN. 2B is the standard version for a single ISDN
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
index 0933881ab0c2..ffba6eca1244 100644
--- a/drivers/isdn/pcbit/Kconfig
+++ b/drivers/isdn/pcbit/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_PCBIT
tristate "PCBIT-D support"
- depends on ISDN_I4L && ISA && (BROKEN || X86)
+ depends on ISA && (BROKEN || X86)
help
This enables support for the PCBIT ISDN-card. This card is
manufactured in Portugal by Octal. For running this card,
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
index 5346e33d816c..e6510ca7bf43 100644
--- a/drivers/isdn/sc/Kconfig
+++ b/drivers/isdn/sc/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_SC
tristate "Spellcaster support"
- depends on ISDN_I4L && ISA
+ depends on ISA
help
This enables support for the Spellcaster BRI ISDN boards. This
driver currently builds only in a modularized version.
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
index 4fbfa825c3a2..5992f63c383e 100644
--- a/drivers/isdn/sc/card.h
+++ b/drivers/isdn/sc/card.h
@@ -125,7 +125,7 @@ int sendmessage(int card, unsigned int procid, unsigned int type,
int receivemessage(int card, RspMessage *rspmsg);
int sc_ioctl(int card, scs_ioctl *data);
int setup_buffers(int card, int c);
-void check_reset(unsigned long data);
+void sc_check_reset(unsigned long data);
void check_phystat(unsigned long data);
#endif /* CARD_H */
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
index b7bb7cbcf503..0e4969c2ef95 100644
--- a/drivers/isdn/sc/command.c
+++ b/drivers/isdn/sc/command.c
@@ -344,7 +344,7 @@ int reset(int card)
spin_lock_irqsave(&sc_adapter[card]->lock, flags);
init_timer(&sc_adapter[card]->reset_timer);
- sc_adapter[card]->reset_timer.function = check_reset;
+ sc_adapter[card]->reset_timer.function = sc_check_reset;
sc_adapter[card]->reset_timer.data = card;
sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
add_timer(&sc_adapter[card]->reset_timer);
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index cc1b8861be2a..91fbe0dc28ec 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -43,7 +43,7 @@ static void setup_ports(int card)
* Then, check to see if the signate has been set. Next, set the
* signature to a known value and issue a startproc if needed.
*/
-void check_reset(unsigned long data)
+void sc_check_reset(unsigned long data)
{
unsigned long flags;
unsigned long sig;
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 33fa28a8c199..0a419a0de603 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -5,13 +5,19 @@ menuconfig VIRTUALIZATION
bool "Virtualization"
depends on X86
default y
+ ---help---
+ Say Y here to get to see options for using your Linux host to run other
+ operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
depends on X86 && EXPERIMENTAL
- depends on X86_CMPXCHG64 || 64BIT
+ select ANON_INODES
---help---
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index a7c5e6bee034..336be86c6f5a 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -121,7 +121,7 @@ struct kvm_pte_chain {
* bits 4:7 - page table level for this shadow (1-4)
* bits 8:9 - page table quadrant for 2-level guests
* bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- * bits 17:18 - "access" - the user and writable bits of a huge page pde
+ * bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
*/
union kvm_mmu_page_role {
unsigned word;
@@ -131,7 +131,7 @@ union kvm_mmu_page_role {
unsigned quadrant : 2;
unsigned pad_for_nice_hex_output : 6;
unsigned metaphysical : 1;
- unsigned hugepage_access : 2;
+ unsigned hugepage_access : 3;
};
};
@@ -535,8 +535,8 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
int kvm_mmu_setup(struct kvm_vcpu *vcpu);
int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -569,6 +569,8 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
@@ -617,7 +619,7 @@ unsigned long segment_base(u16 selector);
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
const u8 *old, const u8 *new, int bytes);
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
-void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
int kvm_mmu_load(struct kvm_vcpu *vcpu);
void kvm_mmu_unload(struct kvm_vcpu *vcpu);
@@ -626,11 +628,15 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code)
{
- if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
- kvm_mmu_free_some_pages(vcpu);
return vcpu->mmu.page_fault(vcpu, gva, error_code);
}
+static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+{
+ if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+ __kvm_mmu_free_some_pages(vcpu);
+}
+
static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
{
if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1b206f197c6b..cd0557954e50 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -238,23 +238,6 @@ static void vcpu_load(struct kvm_vcpu *vcpu)
kvm_arch_ops->vcpu_load(vcpu);
}
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
- struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
-
- mutex_lock(&vcpu->mutex);
- if (!vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return NULL;
- }
- kvm_arch_ops->vcpu_load(vcpu);
- return vcpu;
-}
-
static void vcpu_put(struct kvm_vcpu *vcpu)
{
kvm_arch_ops->vcpu_put(vcpu);
@@ -314,9 +297,6 @@ static struct kvm *kvm_create_vm(void)
kvm_io_bus_init(&kvm->pio_bus);
spin_lock_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages);
- spin_lock(&kvm_lock);
- list_add(&kvm->vm_list, &vm_list);
- spin_unlock(&kvm_lock);
kvm_io_bus_init(&kvm->mmio_bus);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
@@ -326,6 +306,9 @@ static struct kvm *kvm_create_vm(void)
vcpu->kvm = kvm;
vcpu->mmu.root_hpa = INVALID_PAGE;
}
+ spin_lock(&kvm_lock);
+ list_add(&kvm->vm_list, &vm_list);
+ spin_unlock(&kvm_lock);
return kvm;
}
@@ -663,13 +646,6 @@ void fx_init(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(fx_init);
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
- spin_lock(&vcpu->kvm->lock);
- kvm_mmu_slot_remove_write_access(vcpu, slot);
- spin_unlock(&vcpu->kvm->lock);
-}
-
/*
* Allocate some memory and give it an address in the guest physical address
* space.
@@ -792,19 +768,10 @@ raced:
*memslot = new;
++kvm->memory_config_version;
- spin_unlock(&kvm->lock);
-
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu;
+ kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+ kvm_flush_remote_tlbs(kvm);
- vcpu = vcpu_load_slot(kvm, i);
- if (!vcpu)
- continue;
- if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
- do_remove_write_access(vcpu, mem->slot);
- kvm_mmu_reset_context(vcpu);
- vcpu_put(vcpu);
- }
+ spin_unlock(&kvm->lock);
kvm_free_physmem_slot(&old, &new);
return 0;
@@ -826,7 +793,6 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_memory_slot *memslot;
int r, i;
int n;
- int cleared;
unsigned long any = 0;
spin_lock(&kvm->lock);
@@ -855,23 +821,11 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
goto out;
- if (any) {
- cleared = 0;
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu;
-
- vcpu = vcpu_load_slot(kvm, i);
- if (!vcpu)
- continue;
- if (!cleared) {
- do_remove_write_access(vcpu, log->slot);
- memset(memslot->dirty_bitmap, 0, n);
- cleared = 1;
- }
- kvm_arch_ops->tlb_flush(vcpu);
- vcpu_put(vcpu);
- }
- }
+ spin_lock(&kvm->lock);
+ kvm_mmu_slot_remove_write_access(kvm, log->slot);
+ kvm_flush_remote_tlbs(kvm);
+ memset(memslot->dirty_bitmap, 0, n);
+ spin_unlock(&kvm->lock);
r = 0;
@@ -920,13 +874,9 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
break;
kvm->naliases = n;
- spin_unlock(&kvm->lock);
+ kvm_mmu_zap_all(kvm);
- vcpu_load(&kvm->vcpus[0]);
- spin_lock(&kvm->lock);
- kvm_mmu_zap_all(&kvm->vcpus[0]);
spin_unlock(&kvm->lock);
- vcpu_put(&kvm->vcpus[0]);
return 0;
@@ -1120,18 +1070,16 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
return 0;
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0);
- if (memcmp(virt + offset_in_page(gpa), val, bytes)) {
- kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
- memcpy(virt + offset_in_page(gpa), val, bytes);
- }
+ kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+ memcpy(virt + offset_in_page(gpa), val, bytes);
kunmap_atomic(virt, KM_USER0);
return 1;
}
-static int emulator_write_emulated(unsigned long addr,
- const void *val,
- unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+static int emulator_write_emulated_onepage(unsigned long addr,
+ const void *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
{
struct kvm_vcpu *vcpu = ctxt->vcpu;
struct kvm_io_device *mmio_dev;
@@ -1163,6 +1111,26 @@ static int emulator_write_emulated(unsigned long addr,
return X86EMUL_CONTINUE;
}
+static int emulator_write_emulated(unsigned long addr,
+ const void *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ /* Crossing a page boundary? */
+ if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
+ int rc, now;
+
+ now = -addr & ~PAGE_MASK;
+ rc = emulator_write_emulated_onepage(addr, val, now, ctxt);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ addr += now;
+ val += now;
+ bytes -= now;
+ }
+ return emulator_write_emulated_onepage(addr, val, bytes, ctxt);
+}
+
static int emulator_cmpxchg_emulated(unsigned long addr,
const void *old,
const void *new,
@@ -1567,7 +1535,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
}
@@ -1645,7 +1613,7 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
return kvm_arch_ops->set_msr(vcpu, msr_index, data);
}
@@ -2183,7 +2151,7 @@ static __init void kvm_init_msr_list(void)
*/
static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
{
- return set_msr(vcpu, index, *data);
+ return kvm_set_msr(vcpu, index, *data);
}
/*
@@ -2464,9 +2432,9 @@ static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
break;
}
}
- if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) {
+ if (entry && (entry->edx & (1 << 20)) && !(efer & EFER_NX)) {
entry->edx &= ~(1 << 20);
- printk(KERN_INFO ": guest NX capability removed\n");
+ printk(KERN_INFO "kvm: guest NX capability removed\n");
}
}
@@ -2667,7 +2635,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
break;
}
case KVM_GET_MSRS:
- r = msr_io(vcpu, argp, get_msr, 1);
+ r = msr_io(vcpu, argp, kvm_get_msr, 1);
break;
case KVM_SET_MSRS:
r = msr_io(vcpu, argp, do_set_msr, 0);
@@ -3006,6 +2974,10 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
switch (val) {
case CPU_DYING:
case CPU_DYING_FROZEN:
+ printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
+ cpu);
+ hardware_disable(NULL);
+ break;
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index b297a6b111ac..23965aa5ee78 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -154,7 +154,6 @@ struct kvm_rmap_desc {
static struct kmem_cache *pte_chain_cache;
static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_cache;
static struct kmem_cache *mmu_page_header_cache;
static int is_write_protection(struct kvm_vcpu *vcpu)
@@ -225,6 +224,29 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
kfree(mc->objects[--mc->nobjs]);
}
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+ int min, gfp_t gfp_flags)
+{
+ struct page *page;
+
+ if (cache->nobjs >= min)
+ return 0;
+ while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+ page = alloc_page(gfp_flags);
+ if (!page)
+ return -ENOMEM;
+ set_page_private(page, 0);
+ cache->objects[cache->nobjs++] = page_address(page);
+ }
+ return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+ while (mc->nobjs)
+ free_page((unsigned long)mc->objects[--mc->nobjs]);
+}
+
static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
{
int r;
@@ -237,8 +259,7 @@ static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
rmap_desc_cache, 1, gfp_flags);
if (r)
goto out;
- r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
- mmu_page_cache, 4, gfp_flags);
+ r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
@@ -252,12 +273,14 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
int r;
r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
+ kvm_mmu_free_some_pages(vcpu);
if (r < 0) {
spin_unlock(&vcpu->kvm->lock);
kvm_arch_ops->vcpu_put(vcpu);
r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
kvm_arch_ops->vcpu_load(vcpu);
spin_lock(&vcpu->kvm->lock);
+ kvm_mmu_free_some_pages(vcpu);
}
return r;
}
@@ -266,7 +289,7 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
- mmu_free_memory_cache(&vcpu->mmu_page_cache);
+ mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
}
@@ -281,24 +304,15 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
return p;
}
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
- if (mc->nobjs < KVM_NR_MEM_OBJS)
- mc->objects[mc->nobjs++] = obj;
- else
- kfree(obj);
-}
-
static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
{
return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
sizeof(struct kvm_pte_chain));
}
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
- struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
{
- mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+ kfree(pc);
}
static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -307,10 +321,9 @@ static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
sizeof(struct kvm_rmap_desc));
}
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
- struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
{
- mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+ kfree(rd);
}
/*
@@ -355,8 +368,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
}
}
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
- struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
struct kvm_rmap_desc *desc,
int i,
struct kvm_rmap_desc *prev_desc)
@@ -376,10 +388,10 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
prev_desc->more = desc->more;
else
set_page_private(page,(unsigned long)desc->more | 1);
- mmu_free_rmap_desc(vcpu, desc);
+ mmu_free_rmap_desc(desc);
}
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
{
struct page *page;
struct kvm_rmap_desc *desc;
@@ -407,7 +419,7 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
while (desc) {
for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
if (desc->shadow_ptes[i] == spte) {
- rmap_desc_remove_entry(vcpu, page,
+ rmap_desc_remove_entry(page,
desc, i,
prev_desc);
return;
@@ -442,7 +454,7 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
BUG_ON(!(*spte & PT_PRESENT_MASK));
BUG_ON(!(*spte & PT_WRITABLE_MASK));
rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
- rmap_remove(vcpu, spte);
+ rmap_remove(spte);
set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
kvm_flush_remote_tlbs(vcpu->kvm);
}
@@ -464,14 +476,14 @@ static int is_empty_shadow_page(u64 *spt)
}
#endif
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_free_page(struct kvm *kvm,
struct kvm_mmu_page *page_head)
{
ASSERT(is_empty_shadow_page(page_head->spt));
list_del(&page_head->link);
- mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
- mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
- ++vcpu->kvm->n_free_mmu_pages;
+ __free_page(virt_to_page(page_head->spt));
+ kfree(page_head);
+ ++kvm->n_free_mmu_pages;
}
static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -537,8 +549,7 @@ static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
pte_chain->parent_ptes[0] = parent_pte;
}
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
u64 *parent_pte)
{
struct kvm_pte_chain *pte_chain;
@@ -565,7 +576,7 @@ static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
pte_chain->parent_ptes[i] = NULL;
if (i == 0) {
hlist_del(&pte_chain->link);
- mmu_free_pte_chain(vcpu, pte_chain);
+ mmu_free_pte_chain(pte_chain);
if (hlist_empty(&page->parent_ptes)) {
page->multimapped = 0;
page->parent_pte = NULL;
@@ -643,7 +654,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
return page;
}
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
struct kvm_mmu_page *page)
{
unsigned i;
@@ -655,10 +666,10 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
if (page->role.level == PT_PAGE_TABLE_LEVEL) {
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
if (pt[i] & PT_PRESENT_MASK)
- rmap_remove(vcpu, &pt[i]);
+ rmap_remove(&pt[i]);
pt[i] = 0;
}
- kvm_flush_remote_tlbs(vcpu->kvm);
+ kvm_flush_remote_tlbs(kvm);
return;
}
@@ -669,19 +680,18 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
if (!(ent & PT_PRESENT_MASK))
continue;
ent &= PT64_BASE_ADDR_MASK;
- mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+ mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
}
- kvm_flush_remote_tlbs(vcpu->kvm);
+ kvm_flush_remote_tlbs(kvm);
}
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
u64 *parent_pte)
{
- mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+ mmu_page_remove_parent_pte(page, parent_pte);
}
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
struct kvm_mmu_page *page)
{
u64 *parent_pte;
@@ -697,15 +707,15 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
parent_pte = chain->parent_ptes[0];
}
BUG_ON(!parent_pte);
- kvm_mmu_put_page(vcpu, page, parent_pte);
+ kvm_mmu_put_page(page, parent_pte);
set_shadow_pte(parent_pte, 0);
}
- kvm_mmu_page_unlink_children(vcpu, page);
+ kvm_mmu_page_unlink_children(kvm, page);
if (!page->root_count) {
hlist_del(&page->hash_link);
- kvm_mmu_free_page(vcpu, page);
+ kvm_mmu_free_page(kvm, page);
} else
- list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+ list_move(&page->link, &kvm->active_mmu_pages);
}
static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -724,7 +734,7 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
if (page->gfn == gfn && !page->role.metaphysical) {
pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
r = 1;
}
return r;
@@ -737,7 +747,7 @@ static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
pgprintk("%s: zap %lx %x\n",
__FUNCTION__, gfn, page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
}
@@ -1089,10 +1099,10 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
pte = *spte;
if (is_present_pte(pte)) {
if (page->role.level == PT_PAGE_TABLE_LEVEL)
- rmap_remove(vcpu, spte);
+ rmap_remove(spte);
else {
child = page_header(pte & PT64_BASE_ADDR_MASK);
- mmu_page_remove_parent_pte(vcpu, child, spte);
+ mmu_page_remove_parent_pte(child, spte);
}
}
*spte = 0;
@@ -1161,7 +1171,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
*/
pgprintk("misaligned: gpa %llx bytes %d role %x\n",
gpa, bytes, page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
continue;
}
page_offset = offset;
@@ -1200,17 +1210,16 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT);
}
-void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) {
struct kvm_mmu_page *page;
page = container_of(vcpu->kvm->active_mmu_pages.prev,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
}
-EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
static void free_mmu_pages(struct kvm_vcpu *vcpu)
{
@@ -1219,7 +1228,7 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu)
while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
page = container_of(vcpu->kvm->active_mmu_pages.next,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
free_page((unsigned long)vcpu->mmu.pae_root);
}
@@ -1277,9 +1286,8 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
mmu_free_memory_caches(vcpu);
}
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
{
- struct kvm *kvm = vcpu->kvm;
struct kvm_mmu_page *page;
list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1293,27 +1301,20 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
/* avoid RMW */
if (pt[i] & PT_WRITABLE_MASK) {
- rmap_remove(vcpu, &pt[i]);
+ rmap_remove(&pt[i]);
pt[i] &= ~PT_WRITABLE_MASK;
}
}
}
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
{
- destroy_kvm_mmu(vcpu);
-
- while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
- struct kvm_mmu_page *page;
+ struct kvm_mmu_page *page, *node;
- page = container_of(vcpu->kvm->active_mmu_pages.next,
- struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
- }
+ list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+ kvm_mmu_zap_page(kvm, page);
- mmu_free_memory_caches(vcpu);
- kvm_flush_remote_tlbs(vcpu->kvm);
- init_kvm_mmu(vcpu);
+ kvm_flush_remote_tlbs(kvm);
}
void kvm_mmu_module_exit(void)
@@ -1322,8 +1323,6 @@ void kvm_mmu_module_exit(void)
kmem_cache_destroy(pte_chain_cache);
if (rmap_desc_cache)
kmem_cache_destroy(rmap_desc_cache);
- if (mmu_page_cache)
- kmem_cache_destroy(mmu_page_cache);
if (mmu_page_header_cache)
kmem_cache_destroy(mmu_page_header_cache);
}
@@ -1332,24 +1331,18 @@ int kvm_mmu_module_init(void)
{
pte_chain_cache = kmem_cache_create("kvm_pte_chain",
sizeof(struct kvm_pte_chain),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!pte_chain_cache)
goto nomem;
rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
sizeof(struct kvm_rmap_desc),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!rmap_desc_cache)
goto nomem;
- mmu_page_cache = kmem_cache_create("kvm_mmu_page",
- PAGE_SIZE,
- PAGE_SIZE, 0, NULL, NULL);
- if (!mmu_page_cache)
- goto nomem;
-
mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
sizeof(struct kvm_mmu_page),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!mmu_page_header_cache)
goto nomem;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index a7c5cb0319ea..4b5391c717f8 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -366,6 +366,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
metaphysical = 1;
hugepage_access = *guest_ent;
hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+ if (*guest_ent & PT64_NX_MASK)
+ hugepage_access |= (1 << 2);
hugepage_access >>= PT_WRITABLE_SHIFT;
table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
>> PAGE_SHIFT;
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index f60012d62610..4b8a0cc9665e 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -163,7 +163,7 @@ static u16 twobyte_table[256] = {
ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 - 0x3F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -486,6 +486,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
unsigned long modrm_ea;
int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
int no_wb = 0;
+ u64 msr_data;
/* Shadow copy of register state. Committed on successful emulation. */
unsigned long _regs[NR_VCPU_REGS];
@@ -1177,6 +1178,8 @@ pop_instruction:
twobyte_insn:
switch (b) {
case 0x01: /* lgdt, lidt, lmsw */
+ /* Disable writeback. */
+ no_wb = 1;
switch (modrm_reg) {
u16 size;
unsigned long address;
@@ -1214,11 +1217,13 @@ twobyte_insn:
}
break;
case 0x21: /* mov from dr to reg */
+ no_wb = 1;
if (modrm_mod != 3)
goto cannot_emulate;
rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]);
break;
case 0x23: /* mov from reg to dr */
+ no_wb = 1;
if (modrm_mod != 3)
goto cannot_emulate;
rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]);
@@ -1344,6 +1349,29 @@ twobyte_special_insn:
goto cannot_emulate;
realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
break;
+ case 0x30:
+ /* wrmsr */
+ msr_data = (u32)_regs[VCPU_REGS_RAX]
+ | ((u64)_regs[VCPU_REGS_RDX] << 32);
+ rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+ if (rc) {
+ kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ _eip = ctxt->vcpu->rip;
+ }
+ rc = X86EMUL_CONTINUE;
+ break;
+ case 0x32:
+ /* rdmsr */
+ rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+ if (rc) {
+ kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ _eip = ctxt->vcpu->rip;
+ } else {
+ _regs[VCPU_REGS_RAX] = (u32)msr_data;
+ _regs[VCPU_REGS_RDX] = msr_data >> 32;
+ }
+ rc = X86EMUL_CONTINUE;
+ break;
case 0xc7: /* Grp9 (cmpxchg8b) */
{
u64 old, new;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 87d2046f866c..3cb23210b912 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1,9 +1,6 @@
-
-menu "LED devices"
- depends on HAS_IOMEM
-
-config NEW_LEDS
+menuconfig NEW_LEDS
bool "LED Support"
+ depends on HAS_IOMEM
help
Say Y to enable Linux LED support. This allows control of supported
LEDs from both userspace and optionally, by kernel events (triggers).
@@ -11,9 +8,10 @@ config NEW_LEDS
This is not related to standard keyboard LEDs which are controlled
via the input system.
+if NEW_LEDS
+
config LEDS_CLASS
tristate "LED Class Support"
- depends on NEW_LEDS
help
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
@@ -89,17 +87,31 @@ config LEDS_H1940
help
This option enables support for the LEDs on the h1940.
-config LEDS_COBALT
- tristate "LED Support for Cobalt Server front LED"
+config LEDS_COBALT_QUBE
+ tristate "LED Support for the Cobalt Qube series front LED"
+ depends on LEDS_CLASS && MIPS_COBALT
+ help
+ This option enables support for the front LED on Cobalt Qube series
+
+config LEDS_COBALT_RAQ
+ bool "LED Support for the Cobalt Raq series"
depends on LEDS_CLASS && MIPS_COBALT
+ select LEDS_TRIGGERS
+ help
+ This option enables support for the Cobalt Raq series LEDs.
+
+config LEDS_GPIO
+ tristate "LED Support for GPIO connected LEDs"
+ depends on LEDS_CLASS && GENERIC_GPIO
help
- This option enables support for the front LED on Cobalt Server
+ This option enables support for the LEDs connected to GPIO
+ outputs. To be useful the particular board must have LEDs
+ and they must be connected to the GPIO lines.
comment "LED Triggers"
config LEDS_TRIGGERS
bool "LED Trigger support"
- depends on NEW_LEDS
help
This option enables trigger support for the leds class.
These triggers allow kernel events to drive the LEDs and can
@@ -128,5 +140,4 @@ config LEDS_TRIGGER_HEARTBEAT
load average.
If unsure, say Y.
-endmenu
-
+endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index aa2c18efa5b2..d2ca1abbc3d2 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -15,7 +15,9 @@ obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
-obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
+obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
+obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
+obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3c1711210e38..4211293ce862 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -2,7 +2,7 @@
* LED Class Core
*
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
- * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
+ * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.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
@@ -24,9 +24,10 @@
static struct class *leds_class;
-static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+static ssize_t led_brightness_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
ssize_t ret = 0;
/* no lock needed for this */
@@ -36,10 +37,10 @@ static ssize_t led_brightness_show(struct class_device *dev, char *buf)
return ret;
}
-static ssize_t led_brightness_store(struct class_device *dev,
- const char *buf, size_t size)
+static ssize_t led_brightness_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
ssize_t ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
@@ -56,10 +57,9 @@ static ssize_t led_brightness_store(struct class_device *dev,
return ret;
}
-static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
- led_brightness_store);
+static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
#ifdef CONFIG_LEDS_TRIGGERS
-static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
#endif
/**
@@ -93,16 +93,15 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
int rc;
- led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
- parent, "%s", led_cdev->name);
- if (unlikely(IS_ERR(led_cdev->class_dev)))
- return PTR_ERR(led_cdev->class_dev);
+ led_cdev->dev = device_create(leds_class, parent, 0, "%s",
+ led_cdev->name);
+ if (unlikely(IS_ERR(led_cdev->dev)))
+ return PTR_ERR(led_cdev->dev);
- class_set_devdata(led_cdev->class_dev, led_cdev);
+ dev_set_drvdata(led_cdev->dev, led_cdev);
/* register the attributes */
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
if (rc)
goto err_out;
@@ -114,8 +113,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
#ifdef CONFIG_LEDS_TRIGGERS
rwlock_init(&led_cdev->trigger_lock);
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_trigger);
+ rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
if (rc)
goto err_out_led_list;
@@ -123,18 +121,17 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
#endif
printk(KERN_INFO "Registered led device: %s\n",
- led_cdev->class_dev->class_id);
+ led_cdev->name);
return 0;
#ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list:
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ device_remove_file(led_cdev->dev, &dev_attr_brightness);
list_del(&led_cdev->node);
#endif
err_out:
- class_device_unregister(led_cdev->class_dev);
+ device_unregister(led_cdev->dev);
return rc;
}
EXPORT_SYMBOL_GPL(led_classdev_register);
@@ -147,18 +144,16 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
*/
void led_classdev_unregister(struct led_classdev *led_cdev)
{
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ device_remove_file(led_cdev->dev, &dev_attr_brightness);
#ifdef CONFIG_LEDS_TRIGGERS
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_trigger);
+ device_remove_file(led_cdev->dev, &dev_attr_trigger);
write_lock(&led_cdev->trigger_lock);
if (led_cdev->trigger)
led_trigger_set(led_cdev, NULL);
write_unlock(&led_cdev->trigger_lock);
#endif
- class_device_unregister(led_cdev->class_dev);
+ device_unregister(led_cdev->dev);
write_lock(&leds_list_lock);
list_del(&led_cdev->node);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 454fb0901f82..575368c2b100 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -1,7 +1,7 @@
/*
* LED Triggers Core
*
- * Copyright 2005-2006 Openedhand Ltd.
+ * Copyright 2005-2007 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
*
@@ -28,10 +28,10 @@
static DEFINE_RWLOCK(triggers_list_lock);
static LIST_HEAD(trigger_list);
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
- size_t count)
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
char trigger_name[TRIG_NAME_MAX];
struct led_trigger *trig;
size_t len;
@@ -67,9 +67,10 @@ ssize_t led_trigger_store(struct class_device *dev, const char *buf,
}
-ssize_t led_trigger_show(struct class_device *dev, char *buf)
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_trigger *trig;
int len = 0;
@@ -183,13 +184,20 @@ int led_trigger_register(struct led_trigger *trigger)
void led_trigger_register_simple(const char *name, struct led_trigger **tp)
{
struct led_trigger *trigger;
+ int err;
trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
if (trigger) {
trigger->name = name;
- led_trigger_register(trigger);
- }
+ err = led_trigger_register(trigger);
+ if (err < 0)
+ printk(KERN_WARNING "LED trigger %s failed to register"
+ " (%d)\n", name, err);
+ } else
+ printk(KERN_WARNING "LED trigger %s failed to register"
+ " (no memory)\n", name);
+
*tp = trigger;
}
@@ -215,7 +223,8 @@ void led_trigger_unregister(struct led_trigger *trigger)
void led_trigger_unregister_simple(struct led_trigger *trigger)
{
- led_trigger_unregister(trigger);
+ if (trigger)
+ led_trigger_unregister(trigger);
kfree(trigger);
}
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
new file mode 100644
index 000000000000..d2b54b53d80a
--- /dev/null
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
+ *
+ * Control the Cobalt Qube/RaQ front LED
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define LED_FRONT_LEFT 0x01
+#define LED_FRONT_RIGHT 0x02
+
+static void __iomem *led_port;
+static u8 led_value;
+
+static void qube_front_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ if (brightness)
+ led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
+ else
+ led_value = ~(LED_FRONT_LEFT | LED_FRONT_RIGHT);
+ writeb(led_value, led_port);
+}
+
+static struct led_classdev qube_front_led = {
+ .name = "qube-front",
+ .brightness = LED_FULL,
+ .brightness_set = qube_front_led_set,
+ .default_trigger = "ide-disk",
+};
+
+static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int retval;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EBUSY;
+
+ led_port = ioremap(res->start, res->end - res->start + 1);
+ if (!led_port)
+ return -ENOMEM;
+
+ led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
+ writeb(led_value, led_port);
+
+ retval = led_classdev_register(&pdev->dev, &qube_front_led);
+ if (retval)
+ goto err_iounmap;
+
+ return 0;
+
+err_iounmap:
+ iounmap(led_port);
+ led_port = NULL;
+
+ return retval;
+}
+
+static int __devexit cobalt_qube_led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&qube_front_led);
+
+ if (led_port) {
+ iounmap(led_port);
+ led_port = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver cobalt_qube_led_driver = {
+ .probe = cobalt_qube_led_probe,
+ .remove = __devexit_p(cobalt_qube_led_remove),
+ .driver = {
+ .name = "cobalt-qube-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cobalt_qube_led_init(void)
+{
+ return platform_driver_register(&cobalt_qube_led_driver);
+}
+
+static void __exit cobalt_qube_led_exit(void)
+{
+ platform_driver_unregister(&cobalt_qube_led_driver);
+}
+
+module_init(cobalt_qube_led_init);
+module_exit(cobalt_qube_led_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Front LED support for Cobalt Server");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
new file mode 100644
index 000000000000..6ebfff341e6c
--- /dev/null
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -0,0 +1,138 @@
+/*
+ * LEDs driver for the Cobalt Raq series.
+ *
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define LED_WEB 0x04
+#define LED_POWER_OFF 0x08
+
+static void __iomem *led_port;
+static u8 led_value;
+static DEFINE_SPINLOCK(led_value_lock);
+
+static void raq_web_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_value_lock, flags);
+
+ if (brightness)
+ led_value |= LED_WEB;
+ else
+ led_value &= ~LED_WEB;
+ writeb(led_value, led_port);
+
+ spin_unlock_irqrestore(&led_value_lock, flags);
+}
+
+static struct led_classdev raq_web_led = {
+ .name = "raq-web",
+ .brightness_set = raq_web_led_set,
+};
+
+static void raq_power_off_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_value_lock, flags);
+
+ if (brightness)
+ led_value |= LED_POWER_OFF;
+ else
+ led_value &= ~LED_POWER_OFF;
+ writeb(led_value, led_port);
+
+ spin_unlock_irqrestore(&led_value_lock, flags);
+}
+
+static struct led_classdev raq_power_off_led = {
+ .name = "raq-power-off",
+ .brightness_set = raq_power_off_led_set,
+ .default_trigger = "power-off",
+};
+
+static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int retval;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EBUSY;
+
+ led_port = ioremap(res->start, res->end - res->start + 1);
+ if (!led_port)
+ return -ENOMEM;
+
+ retval = led_classdev_register(&pdev->dev, &raq_power_off_led);
+ if (retval)
+ goto err_iounmap;
+
+ retval = led_classdev_register(&pdev->dev, &raq_web_led);
+ if (retval)
+ goto err_unregister;
+
+ return 0;
+
+err_unregister:
+ led_classdev_unregister(&raq_power_off_led);
+
+err_iounmap:
+ iounmap(led_port);
+ led_port = NULL;
+
+ return retval;
+}
+
+static int __devexit cobalt_raq_led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&raq_power_off_led);
+ led_classdev_unregister(&raq_web_led);
+
+ if (led_port) {
+ iounmap(led_port);
+ led_port = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver cobalt_raq_led_driver = {
+ .probe = cobalt_raq_led_probe,
+ .remove = __devexit_p(cobalt_raq_led_remove),
+ .driver = {
+ .name = "cobalt-raq-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cobalt_raq_led_init(void)
+{
+ return platform_driver_register(&cobalt_raq_led_driver);
+}
+
+module_init(cobalt_raq_led_init);
diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c
deleted file mode 100644
index d16439ce5da7..000000000000
--- a/drivers/leds/leds-cobalt.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
- *
- * Control the Cobalt Qube/RaQ front LED
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/leds.h>
-#include <asm/mach-cobalt/cobalt.h>
-
-static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
-{
- if (brightness)
- COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT;
- else
- COBALT_LED_PORT = 0;
-}
-
-static struct led_classdev cobalt_led = {
- .name = "cobalt-front-led",
- .brightness_set = cobalt_led_set,
- .default_trigger = "ide-disk",
-};
-
-static int __init cobalt_led_init(void)
-{
- return led_classdev_register(NULL, &cobalt_led);
-}
-
-static void __exit cobalt_led_exit(void)
-{
- led_classdev_unregister(&cobalt_led);
-}
-
-module_init(cobalt_led_init);
-module_exit(cobalt_led_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Front LED support for Cobalt Server");
-MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644
index 000000000000..47d90db280ce
--- /dev/null
+++ b/drivers/leds/leds-gpio.c
@@ -0,0 +1,199 @@
+/*
+ * LEDs driver for GPIOs
+ *
+ * Copyright (C) 2007 8D Technologies inc.
+ * Raphael Assenat <raph@8d.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+
+#include <asm/gpio.h>
+
+struct gpio_led_data {
+ struct led_classdev cdev;
+ unsigned gpio;
+ struct work_struct work;
+ u8 new_level;
+ u8 can_sleep;
+ u8 active_low;
+};
+
+static void gpio_led_work(struct work_struct *work)
+{
+ struct gpio_led_data *led_dat =
+ container_of(work, struct gpio_led_data, work);
+
+ gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+}
+
+static void gpio_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct gpio_led_data *led_dat =
+ container_of(led_cdev, struct gpio_led_data, cdev);
+ int level;
+
+ if (value == LED_OFF)
+ level = 0;
+ else
+ level = 1;
+
+ if (led_dat->active_low)
+ level = !level;
+
+ /* setting GPIOs with I2C/etc requires a preemptible task context */
+ if (led_dat->can_sleep) {
+ if (preempt_count()) {
+ led_dat->new_level = level;
+ schedule_work(&led_dat->work);
+ } else
+ gpio_set_value_cansleep(led_dat->gpio, level);
+ } else
+ gpio_set_value(led_dat->gpio, level);
+}
+
+static int __init gpio_led_probe(struct platform_device *pdev)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led *cur_led;
+ struct gpio_led_data *leds_data, *led_dat;
+ int i, ret = 0;
+
+ if (!pdata)
+ return -EBUSY;
+
+ leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
+ GFP_KERNEL);
+ if (!leds_data)
+ return -ENOMEM;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ cur_led = &pdata->leds[i];
+ led_dat = &leds_data[i];
+
+ led_dat->cdev.name = cur_led->name;
+ led_dat->cdev.default_trigger = cur_led->default_trigger;
+ led_dat->gpio = cur_led->gpio;
+ led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+ led_dat->active_low = cur_led->active_low;
+ led_dat->cdev.brightness_set = gpio_led_set;
+ led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+
+ ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
+ if (ret < 0)
+ goto err;
+
+ gpio_direction_output(led_dat->gpio, led_dat->active_low);
+
+ ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+ if (ret < 0) {
+ gpio_free(led_dat->gpio);
+ goto err;
+ }
+
+ INIT_WORK(&led_dat->work, gpio_led_work);
+ }
+
+ platform_set_drvdata(pdev, leds_data);
+
+ return 0;
+
+err:
+ if (i > 0) {
+ for (i = i - 1; i >= 0; i--) {
+ led_classdev_unregister(&leds_data[i].cdev);
+ gpio_free(leds_data[i].gpio);
+ }
+ }
+
+ flush_scheduled_work();
+ kfree(leds_data);
+
+ return ret;
+}
+
+static int __exit gpio_led_remove(struct platform_device *pdev)
+{
+ int i;
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led_data *leds_data;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ led_classdev_unregister(&leds_data[i].cdev);
+ gpio_free(leds_data[i].gpio);
+ }
+
+ kfree(leds_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led_data *leds_data;
+ int i;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++)
+ led_classdev_suspend(&leds_data[i].cdev);
+
+ return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led_data *leds_data;
+ int i;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++)
+ led_classdev_resume(&leds_data[i].cdev);
+
+ return 0;
+}
+#else
+#define gpio_led_suspend NULL
+#define gpio_led_resume NULL
+#endif
+
+static struct platform_driver gpio_led_driver = {
+ .remove = __exit_p(gpio_led_remove),
+ .suspend = gpio_led_suspend,
+ .resume = gpio_led_resume,
+ .driver = {
+ .name = "leds-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_led_init(void)
+{
+ return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
+}
+
+static void __exit gpio_led_exit(void)
+{
+ platform_driver_unregister(&gpio_led_driver);
+}
+
+module_init(gpio_led_init);
+module_exit(gpio_led_exit);
+
+MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
+MODULE_DESCRIPTION("GPIO LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 6f2d449ba983..bfac499f3258 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -19,7 +19,7 @@
static void locomoled_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value, int offset)
{
- struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
+ struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
unsigned long flags;
local_irq_save(flags);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index a715c4ed93ff..f2f3884fe063 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -13,6 +13,7 @@
#ifndef __LEDS_H_INCLUDED
#define __LEDS_H_INCLUDED
+#include <linux/device.h>
#include <linux/leds.h>
static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -37,8 +38,9 @@ void led_trigger_set(struct led_classdev *led_cdev,
#define led_trigger_set(x, y) do {} while(0)
#endif
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
- size_t count);
-ssize_t led_trigger_show(struct class_device *dev, char *buf);
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
#endif /* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d756bdb01c59..ed9ff02c77ea 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -52,9 +52,10 @@ static void led_timer_function(unsigned long data)
mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
}
-static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_on_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
sprintf(buf, "%lu\n", timer_data->delay_on);
@@ -62,10 +63,10 @@ static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
return strlen(buf) + 1;
}
-static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
- size_t size)
+static ssize_t led_delay_on_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
@@ -84,9 +85,10 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
return ret;
}
-static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_off_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
sprintf(buf, "%lu\n", timer_data->delay_off);
@@ -94,10 +96,10 @@ static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
return strlen(buf) + 1;
}
-static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
- size_t size)
+static ssize_t led_delay_off_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
@@ -116,10 +118,8 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
return ret;
}
-static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
- led_delay_on_store);
-static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
- led_delay_off_store);
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
static void timer_trig_activate(struct led_classdev *led_cdev)
{
@@ -136,18 +136,17 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
timer_data->timer.function = led_timer_function;
timer_data->timer.data = (unsigned long) led_cdev;
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_delay_on);
- if (rc) goto err_out;
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_delay_off);
- if (rc) goto err_out_delayon;
+ rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+ if (rc)
+ goto err_out;
+ rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+ if (rc)
+ goto err_out_delayon;
return;
err_out_delayon:
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_delay_on);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);
err_out:
led_cdev->trigger_data = NULL;
kfree(timer_data);
@@ -158,10 +157,8 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
struct timer_trig_data *timer_data = led_cdev->trigger_data;
if (timer_data) {
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_delay_on);
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_delay_off);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_off);
del_timer_sync(&timer_data->timer);
kfree(timer_data);
}
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
new file mode 100644
index 000000000000..41e2250613a1
--- /dev/null
+++ b/drivers/lguest/Kconfig
@@ -0,0 +1,30 @@
+config LGUEST
+ tristate "Linux hypervisor example code"
+ depends on X86 && PARAVIRT && EXPERIMENTAL && !X86_PAE && FUTEX
+ select LGUEST_GUEST
+ select HVC_DRIVER
+ ---help---
+ This is a very simple module which allows you to run
+ multiple instances of the same Linux kernel, using the
+ "lguest" command found in the Documentation/lguest directory.
+ Note that "lguest" is pronounced to rhyme with "fell quest",
+ not "rustyvisor". See Documentation/lguest/lguest.txt.
+
+ If unsure, say N. If curious, say M. If masochistic, say Y.
+
+config LGUEST_GUEST
+ bool
+ help
+ The guest needs code built-in, even if the host has lguest
+ support as a module. The drivers are tiny, so we build them
+ in too.
+
+config LGUEST_NET
+ tristate
+ default y
+ depends on LGUEST_GUEST && NET
+
+config LGUEST_BLOCK
+ tristate
+ default y
+ depends on LGUEST_GUEST && BLOCK
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
new file mode 100644
index 000000000000..e5047471c334
--- /dev/null
+++ b/drivers/lguest/Makefile
@@ -0,0 +1,19 @@
+# Guest requires the paravirt_ops replacement and the bus driver.
+obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
+
+# Host requires the other files, which can be a module.
+obj-$(CONFIG_LGUEST) += lg.o
+lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
+ segments.o io.o lguest_user.o switcher.o
+
+Preparation Preparation!: PREFIX=P
+Guest: PREFIX=G
+Drivers: PREFIX=D
+Launcher: PREFIX=L
+Host: PREFIX=H
+Switcher: PREFIX=S
+Mastery: PREFIX=M
+Beer:
+ @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}"
+Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery:
+ @sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
diff --git a/drivers/lguest/README b/drivers/lguest/README
new file mode 100644
index 000000000000..b7db39a64c66
--- /dev/null
+++ b/drivers/lguest/README
@@ -0,0 +1,47 @@
+Welcome, friend reader, to lguest.
+
+Lguest is an adventure, with you, the reader, as Hero. I can't think of many
+5000-line projects which offer both such capability and glimpses of future
+potential; it is an exciting time to be delving into the source!
+
+But be warned; this is an arduous journey of several hours or more! And as we
+know, all true Heroes are driven by a Noble Goal. Thus I offer a Beer (or
+equivalent) to anyone I meet who has completed this documentation.
+
+So get comfortable and keep your wits about you (both quick and humorous).
+Along your way to the Noble Goal, you will also gain masterly insight into
+lguest, and hypervisors and x86 virtualization in general.
+
+Our Quest is in seven parts: (best read with C highlighting turned on)
+
+I) Preparation
+ - In which our potential hero is flown quickly over the landscape for a
+ taste of its scope. Suitable for the armchair coders and other such
+ persons of faint constitution.
+
+II) Guest
+ - Where we encounter the first tantalising wisps of code, and come to
+ understand the details of the life of a Guest kernel.
+
+III) Drivers
+ - Whereby the Guest finds its voice and become useful, and our
+ understanding of the Guest is completed.
+
+IV) Launcher
+ - Where we trace back to the creation of the Guest, and thus begin our
+ understanding of the Host.
+
+V) Host
+ - Where we master the Host code, through a long and tortuous journey.
+ Indeed, it is here that our hero is tested in the Bit of Despair.
+
+VI) Switcher
+ - Where our understanding of the intertwined nature of Guests and Hosts
+ is completed.
+
+VII) Mastery
+ - Where our fully fledged hero grapples with the Great Question:
+ "What next?"
+
+make Preparation!
+Rusty Russell.
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
new file mode 100644
index 000000000000..4a315f08a567
--- /dev/null
+++ b/drivers/lguest/core.c
@@ -0,0 +1,776 @@
+/*P:400 This contains run_guest() which actually calls into the Host<->Guest
+ * Switcher and analyzes the return, such as determining if the Guest wants the
+ * Host to do something. This file also contains useful helper routines, and a
+ * couple of non-obvious setup and teardown pieces which were implemented after
+ * days of debugging pain. :*/
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/cpu.h>
+#include <linux/freezer.h>
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/poll.h>
+#include <asm/highmem.h>
+#include <asm/asm-offsets.h>
+#include <asm/i387.h>
+#include "lg.h"
+
+/* Found in switcher.S */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
+extern unsigned long default_idt_entries[];
+
+/* Every guest maps the core switcher code. */
+#define SHARED_SWITCHER_PAGES \
+ DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
+/* Pages for switcher itself, then two pages per cpu */
+#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
+
+/* We map at -4M for ease of mapping into the guest (one PTE page). */
+#define SWITCHER_ADDR 0xFFC00000
+
+static struct vm_struct *switcher_vma;
+static struct page **switcher_page;
+
+static int cpu_had_pge;
+static struct {
+ unsigned long offset;
+ unsigned short segment;
+} lguest_entry;
+
+/* This One Big lock protects all inter-guest data structures. */
+DEFINE_MUTEX(lguest_lock);
+static DEFINE_PER_CPU(struct lguest *, last_guest);
+
+/* FIXME: Make dynamic. */
+#define MAX_LGUEST_GUESTS 16
+struct lguest lguests[MAX_LGUEST_GUESTS];
+
+/* Offset from where switcher.S was compiled to where we've copied it */
+static unsigned long switcher_offset(void)
+{
+ return SWITCHER_ADDR - (unsigned long)start_switcher_text;
+}
+
+/* This cpu's struct lguest_pages. */
+static struct lguest_pages *lguest_pages(unsigned int cpu)
+{
+ return &(((struct lguest_pages *)
+ (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
+}
+
+/*H:010 We need to set up the Switcher at a high virtual address. Remember the
+ * Switcher is a few hundred bytes of assembler code which actually changes the
+ * CPU to run the Guest, and then changes back to the Host when a trap or
+ * interrupt happens.
+ *
+ * The Switcher code must be at the same virtual address in the Guest as the
+ * Host since it will be running as the switchover occurs.
+ *
+ * Trying to map memory at a particular address is an unusual thing to do, so
+ * it's not a simple one-liner. We also set up the per-cpu parts of the
+ * Switcher here.
+ */
+static __init int map_switcher(void)
+{
+ int i, err;
+ struct page **pagep;
+
+ /*
+ * Map the Switcher in to high memory.
+ *
+ * It turns out that if we choose the address 0xFFC00000 (4MB under the
+ * top virtual address), it makes setting up the page tables really
+ * easy.
+ */
+
+ /* We allocate an array of "struct page"s. map_vm_area() wants the
+ * pages in this form, rather than just an array of pointers. */
+ switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
+ GFP_KERNEL);
+ if (!switcher_page) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* Now we actually allocate the pages. The Guest will see these pages,
+ * so we make sure they're zeroed. */
+ for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ if (!addr) {
+ err = -ENOMEM;
+ goto free_some_pages;
+ }
+ switcher_page[i] = virt_to_page(addr);
+ }
+
+ /* Now we reserve the "virtual memory area" we want: 0xFFC00000
+ * (SWITCHER_ADDR). We might not get it in theory, but in practice
+ * it's worked so far. */
+ switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
+ VM_ALLOC, SWITCHER_ADDR, VMALLOC_END);
+ if (!switcher_vma) {
+ err = -ENOMEM;
+ printk("lguest: could not map switcher pages high\n");
+ goto free_pages;
+ }
+
+ /* This code actually sets up the pages we've allocated to appear at
+ * SWITCHER_ADDR. map_vm_area() takes the vma we allocated above, the
+ * kind of pages we're mapping (kernel pages), and a pointer to our
+ * array of struct pages. It increments that pointer, but we don't
+ * care. */
+ pagep = switcher_page;
+ err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
+ if (err) {
+ printk("lguest: map_vm_area failed: %i\n", err);
+ goto free_vma;
+ }
+
+ /* Now the switcher is mapped at the right address, we can't fail!
+ * Copy in the compiled-in Switcher code (from switcher.S). */
+ memcpy(switcher_vma->addr, start_switcher_text,
+ end_switcher_text - start_switcher_text);
+
+ /* Most of the switcher.S doesn't care that it's been moved; on Intel,
+ * jumps are relative, and it doesn't access any references to external
+ * code or data.
+ *
+ * The only exception is the interrupt handlers in switcher.S: their
+ * addresses are placed in a table (default_idt_entries), so we need to
+ * update the table with the new addresses. switcher_offset() is a
+ * convenience function which returns the distance between the builtin
+ * switcher code and the high-mapped copy we just made. */
+ for (i = 0; i < IDT_ENTRIES; i++)
+ default_idt_entries[i] += switcher_offset();
+
+ /*
+ * Set up the Switcher's per-cpu areas.
+ *
+ * Each CPU gets two pages of its own within the high-mapped region
+ * (aka. "struct lguest_pages"). Much of this can be initialized now,
+ * but some depends on what Guest we are running (which is set up in
+ * copy_in_guest_info()).
+ */
+ for_each_possible_cpu(i) {
+ /* lguest_pages() returns this CPU's two pages. */
+ struct lguest_pages *pages = lguest_pages(i);
+ /* This is a convenience pointer to make the code fit one
+ * statement to a line. */
+ struct lguest_ro_state *state = &pages->state;
+
+ /* The Global Descriptor Table: the Host has a different one
+ * for each CPU. We keep a descriptor for the GDT which says
+ * where it is and how big it is (the size is actually the last
+ * byte, not the size, hence the "-1"). */
+ state->host_gdt_desc.size = GDT_SIZE-1;
+ state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+
+ /* All CPUs on the Host use the same Interrupt Descriptor
+ * Table, so we just use store_idt(), which gets this CPU's IDT
+ * descriptor. */
+ store_idt(&state->host_idt_desc);
+
+ /* The descriptors for the Guest's GDT and IDT can be filled
+ * out now, too. We copy the GDT & IDT into ->guest_gdt and
+ * ->guest_idt before actually running the Guest. */
+ state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+ state->guest_idt_desc.address = (long)&state->guest_idt;
+ state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+ state->guest_gdt_desc.address = (long)&state->guest_gdt;
+
+ /* We know where we want the stack to be when the Guest enters
+ * the switcher: in pages->regs. The stack grows upwards, so
+ * we start it at the end of that structure. */
+ state->guest_tss.esp0 = (long)(&pages->regs + 1);
+ /* And this is the GDT entry to use for the stack: we keep a
+ * couple of special LGUEST entries. */
+ state->guest_tss.ss0 = LGUEST_DS;
+
+ /* x86 can have a finegrained bitmap which indicates what I/O
+ * ports the process can use. We set it to the end of our
+ * structure, meaning "none". */
+ state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+
+ /* Some GDT entries are the same across all Guests, so we can
+ * set them up now. */
+ setup_default_gdt_entries(state);
+ /* Most IDT entries are the same for all Guests, too.*/
+ setup_default_idt_entries(state, default_idt_entries);
+
+ /* The Host needs to be able to use the LGUEST segments on this
+ * CPU, too, so put them in the Host GDT. */
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+ }
+
+ /* In the Switcher, we want the %cs segment register to use the
+ * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
+ * it will be undisturbed when we switch. To change %cs and jump we
+ * need this structure to feed to Intel's "lcall" instruction. */
+ lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+ lguest_entry.segment = LGUEST_CS;
+
+ printk(KERN_INFO "lguest: mapped switcher at %p\n",
+ switcher_vma->addr);
+ /* And we succeeded... */
+ return 0;
+
+free_vma:
+ vunmap(switcher_vma->addr);
+free_pages:
+ i = TOTAL_SWITCHER_PAGES;
+free_some_pages:
+ for (--i; i >= 0; i--)
+ __free_pages(switcher_page[i], 0);
+ kfree(switcher_page);
+out:
+ return err;
+}
+/*:*/
+
+/* Cleaning up the mapping when the module is unloaded is almost...
+ * too easy. */
+static void unmap_switcher(void)
+{
+ unsigned int i;
+
+ /* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */
+ vunmap(switcher_vma->addr);
+ /* Now we just need to free the pages we copied the switcher into */
+ for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
+ __free_pages(switcher_page[i], 0);
+}
+
+/*H:130 Our Guest is usually so well behaved; it never tries to do things it
+ * isn't allowed to. Unfortunately, "struct paravirt_ops" isn't quite
+ * complete, because it doesn't contain replacements for the Intel I/O
+ * instructions. As a result, the Guest sometimes fumbles across one during
+ * the boot process as it probes for various things which are usually attached
+ * to a PC.
+ *
+ * When the Guest uses one of these instructions, we get trap #13 (General
+ * Protection Fault) and come here. We see if it's one of those troublesome
+ * instructions and skip over it. We return true if we did. */
+static int emulate_insn(struct lguest *lg)
+{
+ u8 insn;
+ unsigned int insnlen = 0, in = 0, shift = 0;
+ /* The eip contains the *virtual* address of the Guest's instruction:
+ * guest_pa just subtracts the Guest's page_offset. */
+ unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+
+ /* The guest_pa() function only works for Guest kernel addresses, but
+ * that's all we're trying to do anyway. */
+ if (lg->regs->eip < lg->page_offset)
+ return 0;
+
+ /* Decoding x86 instructions is icky. */
+ lgread(lg, &insn, physaddr, 1);
+
+ /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
+ of the eax register. */
+ if (insn == 0x66) {
+ shift = 16;
+ /* The instruction is 1 byte so far, read the next byte. */
+ insnlen = 1;
+ lgread(lg, &insn, physaddr + insnlen, 1);
+ }
+
+ /* We can ignore the lower bit for the moment and decode the 4 opcodes
+ * we need to emulate. */
+ switch (insn & 0xFE) {
+ case 0xE4: /* in <next byte>,%al */
+ insnlen += 2;
+ in = 1;
+ break;
+ case 0xEC: /* in (%dx),%al */
+ insnlen += 1;
+ in = 1;
+ break;
+ case 0xE6: /* out %al,<next byte> */
+ insnlen += 2;
+ break;
+ case 0xEE: /* out %al,(%dx) */
+ insnlen += 1;
+ break;
+ default:
+ /* OK, we don't know what this is, can't emulate. */
+ return 0;
+ }
+
+ /* If it was an "IN" instruction, they expect the result to be read
+ * into %eax, so we change %eax. We always return all-ones, which
+ * traditionally means "there's nothing there". */
+ if (in) {
+ /* Lower bit tells is whether it's a 16 or 32 bit access */
+ if (insn & 0x1)
+ lg->regs->eax = 0xFFFFFFFF;
+ else
+ lg->regs->eax |= (0xFFFF << shift);
+ }
+ /* Finally, we've "done" the instruction, so move past it. */
+ lg->regs->eip += insnlen;
+ /* Success! */
+ return 1;
+}
+/*:*/
+
+/*L:305
+ * Dealing With Guest Memory.
+ *
+ * When the Guest gives us (what it thinks is) a physical address, we can use
+ * the normal copy_from_user() & copy_to_user() on that address: remember,
+ * Guest physical == Launcher virtual.
+ *
+ * But we can't trust the Guest: it might be trying to access the Launcher
+ * code. We have to check that the range is below the pfn_limit the Launcher
+ * gave us. We have to make sure that addr + len doesn't give us a false
+ * positive by overflowing, too. */
+int lguest_address_ok(const struct lguest *lg,
+ unsigned long addr, unsigned long len)
+{
+ return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
+}
+
+/* This is a convenient routine to get a 32-bit value from the Guest (a very
+ * common operation). Here we can see how useful the kill_lguest() routine we
+ * met in the Launcher can be: we return a random value (0) instead of needing
+ * to return an error. */
+u32 lgread_u32(struct lguest *lg, unsigned long addr)
+{
+ u32 val = 0;
+
+ /* Don't let them access lguest binary. */
+ if (!lguest_address_ok(lg, addr, sizeof(val))
+ || get_user(val, (u32 __user *)addr) != 0)
+ kill_guest(lg, "bad read address %#lx", addr);
+ return val;
+}
+
+/* Same thing for writing a value. */
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
+{
+ if (!lguest_address_ok(lg, addr, sizeof(val))
+ || put_user(val, (u32 __user *)addr) != 0)
+ kill_guest(lg, "bad write address %#lx", addr);
+}
+
+/* This routine is more generic, and copies a range of Guest bytes into a
+ * buffer. If the copy_from_user() fails, we fill the buffer with zeroes, so
+ * the caller doesn't end up using uninitialized kernel memory. */
+void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+ /* copy_from_user should do this, but as we rely on it... */
+ memset(b, 0, bytes);
+ kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
+ }
+}
+
+/* Similarly, our generic routine to copy into a range of Guest bytes. */
+void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+ unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || copy_to_user((void __user *)addr, b, bytes) != 0)
+ kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
+}
+/* (end of memory access helper routines) :*/
+
+static void set_ts(void)
+{
+ u32 cr0;
+
+ cr0 = read_cr0();
+ if (!(cr0 & 8))
+ write_cr0(cr0|8);
+}
+
+/*S:010
+ * We are getting close to the Switcher.
+ *
+ * Remember that each CPU has two pages which are visible to the Guest when it
+ * runs on that CPU. This has to contain the state for that Guest: we copy the
+ * state in just before we run the Guest.
+ *
+ * Each Guest has "changed" flags which indicate what has changed in the Guest
+ * since it last ran. We saw this set in interrupts_and_traps.c and
+ * segments.c.
+ */
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+{
+ /* Copying all this data can be quite expensive. We usually run the
+ * same Guest we ran last time (and that Guest hasn't run anywhere else
+ * meanwhile). If that's not the case, we pretend everything in the
+ * Guest has changed. */
+ if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
+ __get_cpu_var(last_guest) = lg;
+ lg->last_pages = pages;
+ lg->changed = CHANGED_ALL;
+ }
+
+ /* These copies are pretty cheap, so we do them unconditionally: */
+ /* Save the current Host top-level page directory. */
+ pages->state.host_cr3 = __pa(current->mm->pgd);
+ /* Set up the Guest's page tables to see this CPU's pages (and no
+ * other CPU's pages). */
+ map_switcher_in_guest(lg, pages);
+ /* Set up the two "TSS" members which tell the CPU what stack to use
+ * for traps which do directly into the Guest (ie. traps at privilege
+ * level 1). */
+ pages->state.guest_tss.esp1 = lg->esp1;
+ pages->state.guest_tss.ss1 = lg->ss1;
+
+ /* Copy direct-to-Guest trap entries. */
+ if (lg->changed & CHANGED_IDT)
+ copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+
+ /* Copy all GDT entries which the Guest can change. */
+ if (lg->changed & CHANGED_GDT)
+ copy_gdt(lg, pages->state.guest_gdt);
+ /* If only the TLS entries have changed, copy them. */
+ else if (lg->changed & CHANGED_GDT_TLS)
+ copy_gdt_tls(lg, pages->state.guest_gdt);
+
+ /* Mark the Guest as unchanged for next time. */
+ lg->changed = 0;
+}
+
+/* Finally: the code to actually call into the Switcher to run the Guest. */
+static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+{
+ /* This is a dummy value we need for GCC's sake. */
+ unsigned int clobber;
+
+ /* Copy the guest-specific information into this CPU's "struct
+ * lguest_pages". */
+ copy_in_guest_info(lg, pages);
+
+ /* Set the trap number to 256 (impossible value). If we fault while
+ * switching to the Guest (bad segment registers or bug), this will
+ * cause us to abort the Guest. */
+ lg->regs->trapnum = 256;
+
+ /* Now: we push the "eflags" register on the stack, then do an "lcall".
+ * This is how we change from using the kernel code segment to using
+ * the dedicated lguest code segment, as well as jumping into the
+ * Switcher.
+ *
+ * The lcall also pushes the old code segment (KERNEL_CS) onto the
+ * stack, then the address of this call. This stack layout happens to
+ * exactly match the stack of an interrupt... */
+ asm volatile("pushf; lcall *lguest_entry"
+ /* This is how we tell GCC that %eax ("a") and %ebx ("b")
+ * are changed by this routine. The "=" means output. */
+ : "=a"(clobber), "=b"(clobber)
+ /* %eax contains the pages pointer. ("0" refers to the
+ * 0-th argument above, ie "a"). %ebx contains the
+ * physical address of the Guest's top-level page
+ * directory. */
+ : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+ /* We tell gcc that all these registers could change,
+ * which means we don't have to save and restore them in
+ * the Switcher. */
+ : "memory", "%edx", "%ecx", "%edi", "%esi");
+}
+/*:*/
+
+/*H:030 Let's jump straight to the the main loop which runs the Guest.
+ * Remember, this is called by the Launcher reading /dev/lguest, and we keep
+ * going around and around until something interesting happens. */
+int run_guest(struct lguest *lg, unsigned long __user *user)
+{
+ /* We stop running once the Guest is dead. */
+ while (!lg->dead) {
+ /* We need to initialize this, otherwise gcc complains. It's
+ * not (yet) clever enough to see that it's initialized when we
+ * need it. */
+ unsigned int cr2 = 0; /* Damn gcc */
+
+ /* First we run any hypercalls the Guest wants done: either in
+ * the hypercall ring in "struct lguest_data", or directly by
+ * using int 31 (LGUEST_TRAP_ENTRY). */
+ do_hypercalls(lg);
+ /* It's possible the Guest did a SEND_DMA hypercall to the
+ * Launcher, in which case we return from the read() now. */
+ if (lg->dma_is_pending) {
+ if (put_user(lg->pending_dma, user) ||
+ put_user(lg->pending_key, user+1))
+ return -EFAULT;
+ return sizeof(unsigned long)*2;
+ }
+
+ /* Check for signals */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ /* If Waker set break_out, return to Launcher. */
+ if (lg->break_out)
+ return -EAGAIN;
+
+ /* Check if there are any interrupts which can be delivered
+ * now: if so, this sets up the hander to be executed when we
+ * next run the Guest. */
+ maybe_do_interrupt(lg);
+
+ /* All long-lived kernel loops need to check with this horrible
+ * thing called the freezer. If the Host is trying to suspend,
+ * it stops us. */
+ try_to_freeze();
+
+ /* Just make absolutely sure the Guest is still alive. One of
+ * those hypercalls could have been fatal, for example. */
+ if (lg->dead)
+ break;
+
+ /* If the Guest asked to be stopped, we sleep. The Guest's
+ * clock timer or LHCALL_BREAK from the Waker will wake us. */
+ if (lg->halted) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ continue;
+ }
+
+ /* OK, now we're ready to jump into the Guest. First we put up
+ * the "Do Not Disturb" sign: */
+ local_irq_disable();
+
+ /* Remember the awfully-named TS bit? If the Guest has asked
+ * to set it we set it now, so we can trap and pass that trap
+ * to the Guest if it uses the FPU. */
+ if (lg->ts)
+ set_ts();
+
+ /* SYSENTER is an optimized way of doing system calls. We
+ * can't allow it because it always jumps to privilege level 0.
+ * A normal Guest won't try it because we don't advertise it in
+ * CPUID, but a malicious Guest (or malicious Guest userspace
+ * program) could, so we tell the CPU to disable it before
+ * running the Guest. */
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+
+ /* Now we actually run the Guest. It will pop back out when
+ * something interesting happens, and we can examine its
+ * registers to see what it was doing. */
+ run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+
+ /* The "regs" pointer contains two extra entries which are not
+ * really registers: a trap number which says what interrupt or
+ * trap made the switcher code come back, and an error code
+ * which some traps set. */
+
+ /* If the Guest page faulted, then the cr2 register will tell
+ * us the bad virtual address. We have to grab this now,
+ * because once we re-enable interrupts an interrupt could
+ * fault and thus overwrite cr2, or we could even move off to a
+ * different CPU. */
+ if (lg->regs->trapnum == 14)
+ cr2 = read_cr2();
+ /* Similarly, if we took a trap because the Guest used the FPU,
+ * we have to restore the FPU it expects to see. */
+ else if (lg->regs->trapnum == 7)
+ math_state_restore();
+
+ /* Restore SYSENTER if it's supposed to be on. */
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+
+ /* Now we're ready to be interrupted or moved to other CPUs */
+ local_irq_enable();
+
+ /* OK, so what happened? */
+ switch (lg->regs->trapnum) {
+ case 13: /* We've intercepted a GPF. */
+ /* Check if this was one of those annoying IN or OUT
+ * instructions which we need to emulate. If so, we
+ * just go back into the Guest after we've done it. */
+ if (lg->regs->errcode == 0) {
+ if (emulate_insn(lg))
+ continue;
+ }
+ break;
+ case 14: /* We've intercepted a page fault. */
+ /* The Guest accessed a virtual address that wasn't
+ * mapped. This happens a lot: we don't actually set
+ * up most of the page tables for the Guest at all when
+ * we start: as it runs it asks for more and more, and
+ * we set them up as required. In this case, we don't
+ * even tell the Guest that the fault happened.
+ *
+ * The errcode tells whether this was a read or a
+ * write, and whether kernel or userspace code. */
+ if (demand_page(lg, cr2, lg->regs->errcode))
+ continue;
+
+ /* OK, it's really not there (or not OK): the Guest
+ * needs to know. We write out the cr2 value so it
+ * knows where the fault occurred.
+ *
+ * Note that if the Guest were really messed up, this
+ * could happen before it's done the INITIALIZE
+ * hypercall, so lg->lguest_data will be NULL, so
+ * &lg->lguest_data->cr2 will be address 8. Writing
+ * into that address won't hurt the Host at all,
+ * though. */
+ if (put_user(cr2, &lg->lguest_data->cr2))
+ kill_guest(lg, "Writing cr2");
+ break;
+ case 7: /* We've intercepted a Device Not Available fault. */
+ /* If the Guest doesn't want to know, we already
+ * restored the Floating Point Unit, so we just
+ * continue without telling it. */
+ if (!lg->ts)
+ continue;
+ break;
+ case 32 ... 255:
+ /* These values mean a real interrupt occurred, in
+ * which case the Host handler has already been run.
+ * We just do a friendly check if another process
+ * should now be run, then fall through to loop
+ * around: */
+ cond_resched();
+ case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
+ continue;
+ }
+
+ /* If we get here, it's a trap the Guest wants to know
+ * about. */
+ if (deliver_trap(lg, lg->regs->trapnum))
+ continue;
+
+ /* If the Guest doesn't have a handler (either it hasn't
+ * registered any yet, or it's one of the faults we don't let
+ * it handle), it dies with a cryptic error message. */
+ kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+ lg->regs->trapnum, lg->regs->eip,
+ lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
+ }
+ /* The Guest is dead => "No such file or directory" */
+ return -ENOENT;
+}
+
+/* Now we can look at each of the routines this calls, in increasing order of
+ * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
+ * deliver_trap() and demand_page(). After all those, we'll be ready to
+ * examine the Switcher, and our philosophical understanding of the Host/Guest
+ * duality will be complete. :*/
+
+int find_free_guest(void)
+{
+ unsigned int i;
+ for (i = 0; i < MAX_LGUEST_GUESTS; i++)
+ if (!lguests[i].tsk)
+ return i;
+ return -1;
+}
+
+static void adjust_pge(void *on)
+{
+ if (on)
+ write_cr4(read_cr4() | X86_CR4_PGE);
+ else
+ write_cr4(read_cr4() & ~X86_CR4_PGE);
+}
+
+/*H:000
+ * Welcome to the Host!
+ *
+ * By this point your brain has been tickled by the Guest code and numbed by
+ * the Launcher code; prepare for it to be stretched by the Host code. This is
+ * the heart. Let's begin at the initialization routine for the Host's lg
+ * module.
+ */
+static int __init init(void)
+{
+ int err;
+
+ /* Lguest can't run under Xen, VMI or itself. It does Tricky Stuff. */
+ if (paravirt_enabled()) {
+ printk("lguest is afraid of %s\n", paravirt_ops.name);
+ return -EPERM;
+ }
+
+ /* First we put the Switcher up in very high virtual memory. */
+ err = map_switcher();
+ if (err)
+ return err;
+
+ /* Now we set up the pagetable implementation for the Guests. */
+ err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
+ if (err) {
+ unmap_switcher();
+ return err;
+ }
+
+ /* The I/O subsystem needs some things initialized. */
+ lguest_io_init();
+
+ /* /dev/lguest needs to be registered. */
+ err = lguest_device_init();
+ if (err) {
+ free_pagetables();
+ unmap_switcher();
+ return err;
+ }
+
+ /* Finally, we need to turn off "Page Global Enable". PGE is an
+ * optimization where page table entries are specially marked to show
+ * they never change. The Host kernel marks all the kernel pages this
+ * way because it's always present, even when userspace is running.
+ *
+ * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
+ * switch to the Guest kernel. If you don't disable this on all CPUs,
+ * you'll get really weird bugs that you'll chase for two days.
+ *
+ * I used to turn PGE off every time we switched to the Guest and back
+ * on when we return, but that slowed the Switcher down noticibly. */
+
+ /* We don't need the complexity of CPUs coming and going while we're
+ * doing this. */
+ lock_cpu_hotplug();
+ if (cpu_has_pge) { /* We have a broader idea of "global". */
+ /* Remember that this was originally set (for cleanup). */
+ cpu_had_pge = 1;
+ /* adjust_pge is a helper function which sets or unsets the PGE
+ * bit on its CPU, depending on the argument (0 == unset). */
+ on_each_cpu(adjust_pge, (void *)0, 0, 1);
+ /* Turn off the feature in the global feature set. */
+ clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ }
+ unlock_cpu_hotplug();
+
+ /* All good! */
+ return 0;
+}
+
+/* Cleaning up is just the same code, backwards. With a little French. */
+static void __exit fini(void)
+{
+ lguest_device_remove();
+ free_pagetables();
+ unmap_switcher();
+
+ /* If we had PGE before we started, turn it back on now. */
+ lock_cpu_hotplug();
+ if (cpu_had_pge) {
+ set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ /* adjust_pge's argument "1" means set PGE. */
+ on_each_cpu(adjust_pge, (void *)1, 0, 1);
+ }
+ unlock_cpu_hotplug();
+}
+
+/* The Host side of lguest can be a module. This is a nice way for people to
+ * play with it. */
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
new file mode 100644
index 000000000000..db6caace3b9c
--- /dev/null
+++ b/drivers/lguest/hypercalls.c
@@ -0,0 +1,300 @@
+/*P:500 Just as userspace programs request kernel operations through a system
+ * call, the Guest requests Host operations through a "hypercall". You might
+ * notice this nomenclature doesn't really follow any logic, but the name has
+ * been around for long enough that we're stuck with it. As you'd expect, this
+ * code is basically a one big switch statement. :*/
+
+/* Copyright (C) 2006 Rusty Russell IBM Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <irq_vectors.h>
+#include "lg.h"
+
+/*H:120 This is the core hypercall routine: where the Guest gets what it
+ * wants. Or gets killed. Or, in the case of LHCALL_CRASH, both.
+ *
+ * Remember from the Guest: %eax == which call to make, and the arguments are
+ * packed into %edx, %ebx and %ecx if needed. */
+static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
+{
+ switch (regs->eax) {
+ case LHCALL_FLUSH_ASYNC:
+ /* This call does nothing, except by breaking out of the Guest
+ * it makes us process all the asynchronous hypercalls. */
+ break;
+ case LHCALL_LGUEST_INIT:
+ /* You can't get here unless you're already initialized. Don't
+ * do that. */
+ kill_guest(lg, "already have lguest_data");
+ break;
+ case LHCALL_CRASH: {
+ /* Crash is such a trivial hypercall that we do it in four
+ * lines right here. */
+ char msg[128];
+ /* If the lgread fails, it will call kill_guest() itself; the
+ * kill_guest() with the message will be ignored. */
+ lgread(lg, msg, regs->edx, sizeof(msg));
+ msg[sizeof(msg)-1] = '\0';
+ kill_guest(lg, "CRASH: %s", msg);
+ break;
+ }
+ case LHCALL_FLUSH_TLB:
+ /* FLUSH_TLB comes in two flavors, depending on the
+ * argument: */
+ if (regs->edx)
+ guest_pagetable_clear_all(lg);
+ else
+ guest_pagetable_flush_user(lg);
+ break;
+ case LHCALL_BIND_DMA:
+ /* BIND_DMA really wants four arguments, but it's the only call
+ * which does. So the Guest packs the number of buffers and
+ * the interrupt number into the final argument, and we decode
+ * it here. This can legitimately fail, since we currently
+ * place a limit on the number of DMA pools a Guest can have.
+ * So we return true or false from this call. */
+ regs->eax = bind_dma(lg, regs->edx, regs->ebx,
+ regs->ecx >> 8, regs->ecx & 0xFF);
+ break;
+
+ /* All these calls simply pass the arguments through to the right
+ * routines. */
+ case LHCALL_SEND_DMA:
+ send_dma(lg, regs->edx, regs->ebx);
+ break;
+ case LHCALL_LOAD_GDT:
+ load_guest_gdt(lg, regs->edx, regs->ebx);
+ break;
+ case LHCALL_LOAD_IDT_ENTRY:
+ load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx);
+ break;
+ case LHCALL_NEW_PGTABLE:
+ guest_new_pagetable(lg, regs->edx);
+ break;
+ case LHCALL_SET_STACK:
+ guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx);
+ break;
+ case LHCALL_SET_PTE:
+ guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx));
+ break;
+ case LHCALL_SET_PMD:
+ guest_set_pmd(lg, regs->edx, regs->ebx);
+ break;
+ case LHCALL_LOAD_TLS:
+ guest_load_tls(lg, regs->edx);
+ break;
+ case LHCALL_SET_CLOCKEVENT:
+ guest_set_clockevent(lg, regs->edx);
+ break;
+
+ case LHCALL_TS:
+ /* This sets the TS flag, as we saw used in run_guest(). */
+ lg->ts = regs->edx;
+ break;
+ case LHCALL_HALT:
+ /* Similarly, this sets the halted flag for run_guest(). */
+ lg->halted = 1;
+ break;
+ default:
+ kill_guest(lg, "Bad hypercall %li\n", regs->eax);
+ }
+}
+
+/* Asynchronous hypercalls are easy: we just look in the array in the Guest's
+ * "struct lguest_data" and see if there are any new ones marked "ready".
+ *
+ * We are careful to do these in order: obviously we respect the order the
+ * Guest put them in the ring, but we also promise the Guest that they will
+ * happen before any normal hypercall (which is why we check this before
+ * checking for a normal hcall). */
+static void do_async_hcalls(struct lguest *lg)
+{
+ unsigned int i;
+ u8 st[LHCALL_RING_SIZE];
+
+ /* For simplicity, we copy the entire call status array in at once. */
+ if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
+ return;
+
+
+ /* We process "struct lguest_data"s hcalls[] ring once. */
+ for (i = 0; i < ARRAY_SIZE(st); i++) {
+ struct lguest_regs regs;
+ /* We remember where we were up to from last time. This makes
+ * sure that the hypercalls are done in the order the Guest
+ * places them in the ring. */
+ unsigned int n = lg->next_hcall;
+
+ /* 0xFF means there's no call here (yet). */
+ if (st[n] == 0xFF)
+ break;
+
+ /* OK, we have hypercall. Increment the "next_hcall" cursor,
+ * and wrap back to 0 if we reach the end. */
+ if (++lg->next_hcall == LHCALL_RING_SIZE)
+ lg->next_hcall = 0;
+
+ /* We copy the hypercall arguments into a fake register
+ * structure. This makes life simple for do_hcall(). */
+ if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
+ || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
+ || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
+ || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) {
+ kill_guest(lg, "Fetching async hypercalls");
+ break;
+ }
+
+ /* Do the hypercall, same as a normal one. */
+ do_hcall(lg, &regs);
+
+ /* Mark the hypercall done. */
+ if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
+ kill_guest(lg, "Writing result for async hypercall");
+ break;
+ }
+
+ /* Stop doing hypercalls if we've just done a DMA to the
+ * Launcher: it needs to service this first. */
+ if (lg->dma_is_pending)
+ break;
+ }
+}
+
+/* Last of all, we look at what happens first of all. The very first time the
+ * Guest makes a hypercall, we end up here to set things up: */
+static void initialize(struct lguest *lg)
+{
+ u32 tsc_speed;
+
+ /* You can't do anything until you're initialized. The Guest knows the
+ * rules, so we're unforgiving here. */
+ if (lg->regs->eax != LHCALL_LGUEST_INIT) {
+ kill_guest(lg, "hypercall %li before LGUEST_INIT",
+ lg->regs->eax);
+ return;
+ }
+
+ /* We insist that the Time Stamp Counter exist and doesn't change with
+ * cpu frequency. Some devious chip manufacturers decided that TSC
+ * changes could be handled in software. I decided that time going
+ * backwards might be good for benchmarks, but it's bad for users.
+ *
+ * We also insist that the TSC be stable: the kernel detects unreliable
+ * TSCs for its own purposes, and we use that here. */
+ if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
+ tsc_speed = tsc_khz;
+ else
+ tsc_speed = 0;
+
+ /* The pointer to the Guest's "struct lguest_data" is the only
+ * argument. */
+ lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
+ /* If we check the address they gave is OK now, we can simply
+ * copy_to_user/from_user from now on rather than using lgread/lgwrite.
+ * I put this in to show that I'm not immune to writing stupid
+ * optimizations. */
+ if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
+ kill_guest(lg, "bad guest page %p", lg->lguest_data);
+ return;
+ }
+ /* The Guest tells us where we're not to deliver interrupts by putting
+ * the range of addresses into "struct lguest_data". */
+ if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
+ || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
+ /* We tell the Guest that it can't use the top 4MB of virtual
+ * addresses used by the Switcher. */
+ || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
+ || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
+ /* We also give the Guest a unique id, as used in lguest_net.c. */
+ || put_user(lg->guestid, &lg->lguest_data->guestid))
+ kill_guest(lg, "bad guest page %p", lg->lguest_data);
+
+ /* We write the current time into the Guest's data page once now. */
+ write_timestamp(lg);
+
+ /* This is the one case where the above accesses might have been the
+ * first write to a Guest page. This may have caused a copy-on-write
+ * fault, but the Guest might be referring to the old (read-only)
+ * page. */
+ guest_pagetable_clear_all(lg);
+}
+/* Now we've examined the hypercall code; our Guest can make requests. There
+ * is one other way we can do things for the Guest, as we see in
+ * emulate_insn(). */
+
+/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
+ * Normally we don't need to do this: the Guest will run again and update the
+ * trap number before we come back around the run_guest() loop to
+ * do_hypercalls().
+ *
+ * However, if we are signalled or the Guest sends DMA to the Launcher, that
+ * loop will exit without running the Guest. When it comes back it would try
+ * to re-run the hypercall. */
+static void clear_hcall(struct lguest *lg)
+{
+ lg->regs->trapnum = 255;
+}
+
+/*H:100
+ * Hypercalls
+ *
+ * Remember from the Guest, hypercalls come in two flavors: normal and
+ * asynchronous. This file handles both of types.
+ */
+void do_hypercalls(struct lguest *lg)
+{
+ /* Not initialized yet? */
+ if (unlikely(!lg->lguest_data)) {
+ /* Did the Guest make a hypercall? We might have come back for
+ * some other reason (an interrupt, a different trap). */
+ if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+ /* Set up the "struct lguest_data" */
+ initialize(lg);
+ /* The hypercall is done. */
+ clear_hcall(lg);
+ }
+ return;
+ }
+
+ /* The Guest has initialized.
+ *
+ * Look in the hypercall ring for the async hypercalls: */
+ do_async_hcalls(lg);
+
+ /* If we stopped reading the hypercall ring because the Guest did a
+ * SEND_DMA to the Launcher, we want to return now. Otherwise if the
+ * Guest asked us to do a hypercall, we do it. */
+ if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+ do_hcall(lg, lg->regs);
+ /* The hypercall is done. */
+ clear_hcall(lg);
+ }
+}
+
+/* This routine supplies the Guest with time: it's used for wallclock time at
+ * initial boot and as a rough time source if the TSC isn't available. */
+void write_timestamp(struct lguest *lg)
+{
+ struct timespec now;
+ ktime_get_real_ts(&now);
+ if (put_user(now, &lg->lguest_data->time))
+ kill_guest(lg, "Writing timestamp");
+}
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
new file mode 100644
index 000000000000..39731232d827
--- /dev/null
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -0,0 +1,446 @@
+/*P:800 Interrupts (traps) are complicated enough to earn their own file.
+ * There are three classes of interrupts:
+ *
+ * 1) Real hardware interrupts which occur while we're running the Guest,
+ * 2) Interrupts for virtual devices attached to the Guest, and
+ * 3) Traps and faults from the Guest.
+ *
+ * Real hardware interrupts must be delivered to the Host, not the Guest.
+ * Virtual interrupts must be delivered to the Guest, but we make them look
+ * just like real hardware would deliver them. Traps from the Guest can be set
+ * up to go directly back into the Guest, but sometimes the Host wants to see
+ * them first, so we also have a way of "reflecting" them into the Guest as if
+ * they had been delivered to it directly. :*/
+#include <linux/uaccess.h>
+#include "lg.h"
+
+/* The address of the interrupt handler is split into two bits: */
+static unsigned long idt_address(u32 lo, u32 hi)
+{
+ return (lo & 0x0000FFFF) | (hi & 0xFFFF0000);
+}
+
+/* The "type" of the interrupt handler is a 4 bit field: we only support a
+ * couple of types. */
+static int idt_type(u32 lo, u32 hi)
+{
+ return (hi >> 8) & 0xF;
+}
+
+/* An IDT entry can't be used unless the "present" bit is set. */
+static int idt_present(u32 lo, u32 hi)
+{
+ return (hi & 0x8000);
+}
+
+/* We need a helper to "push" a value onto the Guest's stack, since that's a
+ * big part of what delivering an interrupt does. */
+static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
+{
+ /* Stack grows upwards: move stack then write value. */
+ *gstack -= 4;
+ lgwrite_u32(lg, *gstack, val);
+}
+
+/*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
+ * trap. The mechanics of delivering traps and interrupts to the Guest are the
+ * same, except some traps have an "error code" which gets pushed onto the
+ * stack as well: the caller tells us if this is one.
+ *
+ * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
+ * interrupt or trap. It's split into two parts for traditional reasons: gcc
+ * on i386 used to be frightened by 64 bit numbers.
+ *
+ * We set up the stack just like the CPU does for a real interrupt, so it's
+ * identical for the Guest (and the standard "iret" instruction will undo
+ * it). */
+static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
+{
+ unsigned long gstack;
+ u32 eflags, ss, irq_enable;
+
+ /* There are two cases for interrupts: one where the Guest is already
+ * in the kernel, and a more complex one where the Guest is in
+ * userspace. We check the privilege level to find out. */
+ if ((lg->regs->ss&0x3) != GUEST_PL) {
+ /* The Guest told us their kernel stack with the SET_STACK
+ * hypercall: both the virtual address and the segment */
+ gstack = guest_pa(lg, lg->esp1);
+ ss = lg->ss1;
+ /* We push the old stack segment and pointer onto the new
+ * stack: when the Guest does an "iret" back from the interrupt
+ * handler the CPU will notice they're dropping privilege
+ * levels and expect these here. */
+ push_guest_stack(lg, &gstack, lg->regs->ss);
+ push_guest_stack(lg, &gstack, lg->regs->esp);
+ } else {
+ /* We're staying on the same Guest (kernel) stack. */
+ gstack = guest_pa(lg, lg->regs->esp);
+ ss = lg->regs->ss;
+ }
+
+ /* Remember that we never let the Guest actually disable interrupts, so
+ * the "Interrupt Flag" bit is always set. We copy that bit from the
+ * Guest's "irq_enabled" field into the eflags word: the Guest copies
+ * it back in "lguest_iret". */
+ eflags = lg->regs->eflags;
+ if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+ && !(irq_enable & X86_EFLAGS_IF))
+ eflags &= ~X86_EFLAGS_IF;
+
+ /* An interrupt is expected to push three things on the stack: the old
+ * "eflags" word, the old code segment, and the old instruction
+ * pointer. */
+ push_guest_stack(lg, &gstack, eflags);
+ push_guest_stack(lg, &gstack, lg->regs->cs);
+ push_guest_stack(lg, &gstack, lg->regs->eip);
+
+ /* For the six traps which supply an error code, we push that, too. */
+ if (has_err)
+ push_guest_stack(lg, &gstack, lg->regs->errcode);
+
+ /* Now we've pushed all the old state, we change the stack, the code
+ * segment and the address to execute. */
+ lg->regs->ss = ss;
+ lg->regs->esp = gstack + lg->page_offset;
+ lg->regs->cs = (__KERNEL_CS|GUEST_PL);
+ lg->regs->eip = idt_address(lo, hi);
+
+ /* There are two kinds of interrupt handlers: 0xE is an "interrupt
+ * gate" which expects interrupts to be disabled on entry. */
+ if (idt_type(lo, hi) == 0xE)
+ if (put_user(0, &lg->lguest_data->irq_enabled))
+ kill_guest(lg, "Disabling interrupts");
+}
+
+/*H:200
+ * Virtual Interrupts.
+ *
+ * maybe_do_interrupt() gets called before every entry to the Guest, to see if
+ * we should divert the Guest to running an interrupt handler. */
+void maybe_do_interrupt(struct lguest *lg)
+{
+ unsigned int irq;
+ DECLARE_BITMAP(blk, LGUEST_IRQS);
+ struct desc_struct *idt;
+
+ /* If the Guest hasn't even initialized yet, we can do nothing. */
+ if (!lg->lguest_data)
+ return;
+
+ /* Take our "irqs_pending" array and remove any interrupts the Guest
+ * wants blocked: the result ends up in "blk". */
+ if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
+ sizeof(blk)))
+ return;
+
+ bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
+
+ /* Find the first interrupt. */
+ irq = find_first_bit(blk, LGUEST_IRQS);
+ /* None? Nothing to do */
+ if (irq >= LGUEST_IRQS)
+ return;
+
+ /* They may be in the middle of an iret, where they asked us never to
+ * deliver interrupts. */
+ if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end)
+ return;
+
+ /* If they're halted, interrupts restart them. */
+ if (lg->halted) {
+ /* Re-enable interrupts. */
+ if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
+ kill_guest(lg, "Re-enabling interrupts");
+ lg->halted = 0;
+ } else {
+ /* Otherwise we check if they have interrupts disabled. */
+ u32 irq_enabled;
+ if (get_user(irq_enabled, &lg->lguest_data->irq_enabled))
+ irq_enabled = 0;
+ if (!irq_enabled)
+ return;
+ }
+
+ /* Look at the IDT entry the Guest gave us for this interrupt. The
+ * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
+ * over them. */
+ idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+ /* If they don't have a handler (yet?), we just ignore it */
+ if (idt_present(idt->a, idt->b)) {
+ /* OK, mark it no longer pending and deliver it. */
+ clear_bit(irq, lg->irqs_pending);
+ /* set_guest_interrupt() takes the interrupt descriptor and a
+ * flag to say whether this interrupt pushes an error code onto
+ * the stack as well: virtual interrupts never do. */
+ set_guest_interrupt(lg, idt->a, idt->b, 0);
+ }
+
+ /* Every time we deliver an interrupt, we update the timestamp in the
+ * Guest's lguest_data struct. It would be better for the Guest if we
+ * did this more often, but it can actually be quite slow: doing it
+ * here is a compromise which means at least it gets updated every
+ * timer interrupt. */
+ write_timestamp(lg);
+}
+
+/*H:220 Now we've got the routines to deliver interrupts, delivering traps
+ * like page fault is easy. The only trick is that Intel decided that some
+ * traps should have error codes: */
+static int has_err(unsigned int trap)
+{
+ return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
+}
+
+/* deliver_trap() returns true if it could deliver the trap. */
+int deliver_trap(struct lguest *lg, unsigned int num)
+{
+ /* Trap numbers are always 8 bit, but we set an impossible trap number
+ * for traps inside the Switcher, so check that here. */
+ if (num >= ARRAY_SIZE(lg->idt))
+ return 0;
+
+ /* Early on the Guest hasn't set the IDT entries (or maybe it put a
+ * bogus one in): if we fail here, the Guest will be killed. */
+ if (!idt_present(lg->idt[num].a, lg->idt[num].b))
+ return 0;
+ set_guest_interrupt(lg, lg->idt[num].a, lg->idt[num].b, has_err(num));
+ return 1;
+}
+
+/*H:250 Here's the hard part: returning to the Host every time a trap happens
+ * and then calling deliver_trap() and re-entering the Guest is slow.
+ * Particularly because Guest userspace system calls are traps (trap 128).
+ *
+ * So we'd like to set up the IDT to tell the CPU to deliver traps directly
+ * into the Guest. This is possible, but the complexities cause the size of
+ * this file to double! However, 150 lines of code is worth writing for taking
+ * system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all
+ * the other hypervisors would tease it.
+ *
+ * This routine determines if a trap can be delivered directly. */
+static int direct_trap(const struct lguest *lg,
+ const struct desc_struct *trap,
+ unsigned int num)
+{
+ /* Hardware interrupts don't go to the Guest at all (except system
+ * call). */
+ if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
+ return 0;
+
+ /* The Host needs to see page faults (for shadow paging and to save the
+ * fault address), general protection faults (in/out emulation) and
+ * device not available (TS handling), and of course, the hypercall
+ * trap. */
+ if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
+ return 0;
+
+ /* Only trap gates (type 15) can go direct to the Guest. Interrupt
+ * gates (type 14) disable interrupts as they are entered, which we
+ * never let the Guest do. Not present entries (type 0x0) also can't
+ * go direct, of course 8) */
+ return idt_type(trap->a, trap->b) == 0xF;
+}
+/*:*/
+
+/*M:005 The Guest has the ability to turn its interrupt gates into trap gates,
+ * if it is careful. The Host will let trap gates can go directly to the
+ * Guest, but the Guest needs the interrupts atomically disabled for an
+ * interrupt gate. It can do this by pointing the trap gate at instructions
+ * within noirq_start and noirq_end, where it can safely disable interrupts. */
+
+/*M:006 The Guests do not use the sysenter (fast system call) instruction,
+ * because it's hardcoded to enter privilege level 0 and so can't go direct.
+ * It's about twice as fast as the older "int 0x80" system call, so it might
+ * still be worthwhile to handle it in the Switcher and lcall down to the
+ * Guest. The sysenter semantics are hairy tho: search for that keyword in
+ * entry.S :*/
+
+/*H:260 When we make traps go directly into the Guest, we need to make sure
+ * the kernel stack is valid (ie. mapped in the page tables). Otherwise, the
+ * CPU trying to deliver the trap will fault while trying to push the interrupt
+ * words on the stack: this is called a double fault, and it forces us to kill
+ * the Guest.
+ *
+ * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */
+void pin_stack_pages(struct lguest *lg)
+{
+ unsigned int i;
+
+ /* Depending on the CONFIG_4KSTACKS option, the Guest can have one or
+ * two pages of stack space. */
+ for (i = 0; i < lg->stack_pages; i++)
+ /* The stack grows *upwards*, so the address we're given is the
+ * start of the page after the kernel stack. Subtract one to
+ * get back onto the first stack page, and keep subtracting to
+ * get to the rest of the stack pages. */
+ pin_page(lg, lg->esp1 - 1 - i * PAGE_SIZE);
+}
+
+/* Direct traps also mean that we need to know whenever the Guest wants to use
+ * a different kernel stack, so we can change the IDT entries to use that
+ * stack. The IDT entries expect a virtual address, so unlike most addresses
+ * the Guest gives us, the "esp" (stack pointer) value here is virtual, not
+ * physical.
+ *
+ * In Linux each process has its own kernel stack, so this happens a lot: we
+ * change stacks on each context switch. */
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
+{
+ /* You are not allowd have a stack segment with privilege level 0: bad
+ * Guest! */
+ if ((seg & 0x3) != GUEST_PL)
+ kill_guest(lg, "bad stack segment %i", seg);
+ /* We only expect one or two stack pages. */
+ if (pages > 2)
+ kill_guest(lg, "bad stack pages %u", pages);
+ /* Save where the stack is, and how many pages */
+ lg->ss1 = seg;
+ lg->esp1 = esp;
+ lg->stack_pages = pages;
+ /* Make sure the new stack pages are mapped */
+ pin_stack_pages(lg);
+}
+
+/* All this reference to mapping stacks leads us neatly into the other complex
+ * part of the Host: page table handling. */
+
+/*H:235 This is the routine which actually checks the Guest's IDT entry and
+ * transfers it into our entry in "struct lguest": */
+static void set_trap(struct lguest *lg, struct desc_struct *trap,
+ unsigned int num, u32 lo, u32 hi)
+{
+ u8 type = idt_type(lo, hi);
+
+ /* We zero-out a not-present entry */
+ if (!idt_present(lo, hi)) {
+ trap->a = trap->b = 0;
+ return;
+ }
+
+ /* We only support interrupt and trap gates. */
+ if (type != 0xE && type != 0xF)
+ kill_guest(lg, "bad IDT type %i", type);
+
+ /* We only copy the handler address, present bit, privilege level and
+ * type. The privilege level controls where the trap can be triggered
+ * manually with an "int" instruction. This is usually GUEST_PL,
+ * except for system calls which userspace can use. */
+ trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF);
+ trap->b = (hi&0xFFFFEF00);
+}
+
+/*H:230 While we're here, dealing with delivering traps and interrupts to the
+ * Guest, we might as well complete the picture: how the Guest tells us where
+ * it wants them to go. This would be simple, except making traps fast
+ * requires some tricks.
+ *
+ * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the
+ * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */
+void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
+{
+ /* Guest never handles: NMI, doublefault, spurious interrupt or
+ * hypercall. We ignore when it tries to set them. */
+ if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY)
+ return;
+
+ /* Mark the IDT as changed: next time the Guest runs we'll know we have
+ * to copy this again. */
+ lg->changed |= CHANGED_IDT;
+
+ /* The IDT which we keep in "struct lguest" only contains 32 entries
+ * for the traps and LGUEST_IRQS (32) entries for interrupts. We
+ * ignore attempts to set handlers for higher interrupt numbers, except
+ * for the system call "interrupt" at 128: we have a special IDT entry
+ * for that. */
+ if (num < ARRAY_SIZE(lg->idt))
+ set_trap(lg, &lg->idt[num], num, lo, hi);
+ else if (num == SYSCALL_VECTOR)
+ set_trap(lg, &lg->syscall_idt, num, lo, hi);
+}
+
+/* The default entry for each interrupt points into the Switcher routines which
+ * simply return to the Host. The run_guest() loop will then call
+ * deliver_trap() to bounce it back into the Guest. */
+static void default_idt_entry(struct desc_struct *idt,
+ int trap,
+ const unsigned long handler)
+{
+ /* A present interrupt gate. */
+ u32 flags = 0x8e00;
+
+ /* Set the privilege level on the entry for the hypercall: this allows
+ * the Guest to use the "int" instruction to trigger it. */
+ if (trap == LGUEST_TRAP_ENTRY)
+ flags |= (GUEST_PL << 13);
+
+ /* Now pack it into the IDT entry in its weird format. */
+ idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
+ idt->b = (handler&0xFFFF0000) | flags;
+}
+
+/* When the Guest first starts, we put default entries into the IDT. */
+void setup_default_idt_entries(struct lguest_ro_state *state,
+ const unsigned long *def)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++)
+ default_idt_entry(&state->guest_idt[i], i, def[i]);
+}
+
+/*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
+ * we copy them into the IDT which we've set up for Guests on this CPU, just
+ * before we run the Guest. This routine does that copy. */
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+ const unsigned long *def)
+{
+ unsigned int i;
+
+ /* We can simply copy the direct traps, otherwise we use the default
+ * ones in the Switcher: they will return to the Host. */
+ for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
+ if (direct_trap(lg, &lg->idt[i], i))
+ idt[i] = lg->idt[i];
+ else
+ default_idt_entry(&idt[i], i, def[i]);
+ }
+
+ /* Don't forget the system call trap! The IDT entries for other
+ * interupts never change, so no need to copy them. */
+ i = SYSCALL_VECTOR;
+ if (direct_trap(lg, &lg->syscall_idt, i))
+ idt[i] = lg->syscall_idt;
+ else
+ default_idt_entry(&idt[i], i, def[i]);
+}
+
+void guest_set_clockevent(struct lguest *lg, unsigned long delta)
+{
+ ktime_t expires;
+
+ if (unlikely(delta == 0)) {
+ /* Clock event device is shutting down. */
+ hrtimer_cancel(&lg->hrt);
+ return;
+ }
+
+ expires = ktime_add_ns(ktime_get_real(), delta);
+ hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
+}
+
+static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
+{
+ struct lguest *lg = container_of(timer, struct lguest, hrt);
+
+ set_bit(0, lg->irqs_pending);
+ if (lg->halted)
+ wake_up_process(lg->tsk);
+ return HRTIMER_NORESTART;
+}
+
+void init_clockdev(struct lguest *lg)
+{
+ hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ lg->hrt.function = clockdev_fn;
+}
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
new file mode 100644
index 000000000000..ea68613b43f6
--- /dev/null
+++ b/drivers/lguest/io.c
@@ -0,0 +1,626 @@
+/*P:300 The I/O mechanism in lguest is simple yet flexible, allowing the Guest
+ * to talk to the Launcher or directly to another Guest. It uses familiar
+ * concepts of DMA and interrupts, plus some neat code stolen from
+ * futexes... :*/
+
+/* Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/types.h>
+#include <linux/futex.h>
+#include <linux/jhash.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+#include "lg.h"
+
+/*L:300
+ * I/O
+ *
+ * Getting data in and out of the Guest is quite an art. There are numerous
+ * ways to do it, and they all suck differently. We try to keep things fairly
+ * close to "real" hardware so our Guest's drivers don't look like an alien
+ * visitation in the middle of the Linux code, and yet make sure that Guests
+ * can talk directly to other Guests, not just the Launcher.
+ *
+ * To do this, the Guest gives us a key when it binds or sends DMA buffers.
+ * The key corresponds to a "physical" address inside the Guest (ie. a virtual
+ * address inside the Launcher process). We don't, however, use this key
+ * directly.
+ *
+ * We want Guests which share memory to be able to DMA to each other: two
+ * Launchers can mmap memory the same file, then the Guests can communicate.
+ * Fortunately, the futex code provides us with a way to get a "union
+ * futex_key" corresponding to the memory lying at a virtual address: if the
+ * two processes share memory, the "union futex_key" for that memory will match
+ * even if the memory is mapped at different addresses in each. So we always
+ * convert the keys to "union futex_key"s to compare them.
+ *
+ * Before we dive into this though, we need to look at another set of helper
+ * routines used throughout the Host kernel code to access Guest memory.
+ :*/
+static struct list_head dma_hash[61];
+
+/* An unfortunate side effect of the Linux double-linked list implementation is
+ * that there's no good way to statically initialize an array of linked
+ * lists. */
+void lguest_io_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dma_hash); i++)
+ INIT_LIST_HEAD(&dma_hash[i]);
+}
+
+/* FIXME: allow multi-page lengths. */
+static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma)
+{
+ unsigned int i;
+
+ for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+ if (!dma->len[i])
+ return 1;
+ if (!lguest_address_ok(lg, dma->addr[i], dma->len[i]))
+ goto kill;
+ if (dma->len[i] > PAGE_SIZE)
+ goto kill;
+ /* We could do over a page, but is it worth it? */
+ if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE)
+ goto kill;
+ }
+ return 1;
+
+kill:
+ kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]);
+ return 0;
+}
+
+/*L:330 This is our hash function, using the wonderful Jenkins hash.
+ *
+ * The futex key is a union with three parts: an unsigned long word, a pointer,
+ * and an int "offset". We could use jhash_2words() which takes three u32s.
+ * (Ok, the hash functions are great: the naming sucks though).
+ *
+ * It's nice to be portable to 64-bit platforms, so we use the more generic
+ * jhash2(), which takes an array of u32, the number of u32s, and an initial
+ * u32 to roll in. This is uglier, but breaks down to almost the same code on
+ * 32-bit platforms like this one.
+ *
+ * We want a position in the array, so we modulo ARRAY_SIZE(dma_hash) (ie. 61).
+ */
+static unsigned int hash(const union futex_key *key)
+{
+ return jhash2((u32*)&key->both.word,
+ (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+ key->both.offset)
+ % ARRAY_SIZE(dma_hash);
+}
+
+/* This is a convenience routine to compare two keys. It's a much bemoaned C
+ * weakness that it doesn't allow '==' on structures or unions, so we have to
+ * open-code it like this. */
+static inline int key_eq(const union futex_key *a, const union futex_key *b)
+{
+ return (a->both.word == b->both.word
+ && a->both.ptr == b->both.ptr
+ && a->both.offset == b->both.offset);
+}
+
+/*L:360 OK, when we need to actually free up a Guest's DMA array we do several
+ * things, so we have a convenient function to do it.
+ *
+ * The caller must hold a read lock on dmainfo owner's current->mm->mmap_sem
+ * for the drop_futex_key_refs(). */
+static void unlink_dma(struct lguest_dma_info *dmainfo)
+{
+ /* You locked this too, right? */
+ BUG_ON(!mutex_is_locked(&lguest_lock));
+ /* This is how we know that the entry is free. */
+ dmainfo->interrupt = 0;
+ /* Remove it from the hash table. */
+ list_del(&dmainfo->list);
+ /* Drop the references we were holding (to the inode or mm). */
+ drop_futex_key_refs(&dmainfo->key);
+}
+
+/*L:350 This is the routine which we call when the Guest asks to unregister a
+ * DMA array attached to a given key. Returns true if the array was found. */
+static int unbind_dma(struct lguest *lg,
+ const union futex_key *key,
+ unsigned long dmas)
+{
+ int i, ret = 0;
+
+ /* We don't bother with the hash table, just look through all this
+ * Guest's DMA arrays. */
+ for (i = 0; i < LGUEST_MAX_DMA; i++) {
+ /* In theory it could have more than one array on the same key,
+ * or one array on multiple keys, so we check both */
+ if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
+ unlink_dma(&lg->dma[i]);
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*L:340 BIND_DMA: this is the hypercall which sets up an array of "struct
+ * lguest_dma" for receiving I/O.
+ *
+ * The Guest wants to bind an array of "struct lguest_dma"s to a particular key
+ * to receive input. This only happens when the Guest is setting up a new
+ * device, so it doesn't have to be very fast.
+ *
+ * It returns 1 on a successful registration (it can fail if we hit the limit
+ * of registrations for this Guest).
+ */
+int bind_dma(struct lguest *lg,
+ unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
+{
+ unsigned int i;
+ int ret = 0;
+ union futex_key key;
+ /* Futex code needs the mmap_sem. */
+ struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+ /* Invalid interrupt? (We could kill the guest here). */
+ if (interrupt >= LGUEST_IRQS)
+ return 0;
+
+ /* We need to grab the Big Lguest Lock, because other Guests may be
+ * trying to look through this Guest's DMAs to send something while
+ * we're doing this. */
+ mutex_lock(&lguest_lock);
+ down_read(fshared);
+ if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+ kill_guest(lg, "bad dma key %#lx", ukey);
+ goto unlock;
+ }
+
+ /* We want to keep this key valid once we drop mmap_sem, so we have to
+ * hold a reference. */
+ get_futex_key_refs(&key);
+
+ /* If the Guest specified an interrupt of 0, that means they want to
+ * unregister this array of "struct lguest_dma"s. */
+ if (interrupt == 0)
+ ret = unbind_dma(lg, &key, dmas);
+ else {
+ /* Look through this Guest's dma array for an unused entry. */
+ for (i = 0; i < LGUEST_MAX_DMA; i++) {
+ /* If the interrupt is non-zero, the entry is already
+ * used. */
+ if (lg->dma[i].interrupt)
+ continue;
+
+ /* OK, a free one! Fill on our details. */
+ lg->dma[i].dmas = dmas;
+ lg->dma[i].num_dmas = numdmas;
+ lg->dma[i].next_dma = 0;
+ lg->dma[i].key = key;
+ lg->dma[i].guestid = lg->guestid;
+ lg->dma[i].interrupt = interrupt;
+
+ /* Now we add it to the hash table: the position
+ * depends on the futex key that we got. */
+ list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
+ /* Success! */
+ ret = 1;
+ goto unlock;
+ }
+ }
+ /* If we didn't find a slot to put the key in, drop the reference
+ * again. */
+ drop_futex_key_refs(&key);
+unlock:
+ /* Unlock and out. */
+ up_read(fshared);
+ mutex_unlock(&lguest_lock);
+ return ret;
+}
+
+/*L:385 Note that our routines to access a different Guest's memory are called
+ * lgread_other() and lgwrite_other(): these names emphasize that they are only
+ * used when the Guest is *not* the current Guest.
+ *
+ * The interface for copying from another process's memory is called
+ * access_process_vm(), with a final argument of 0 for a read, and 1 for a
+ * write.
+ *
+ * We need lgread_other() to read the destination Guest's "struct lguest_dma"
+ * array. */
+static int lgread_other(struct lguest *lg,
+ void *buf, u32 addr, unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
+ memset(buf, 0, bytes);
+ kill_guest(lg, "bad address in registered DMA struct");
+ return 0;
+ }
+ return 1;
+}
+
+/* "lgwrite()" to another Guest: used to update the destination "used_len" once
+ * we've transferred data into the buffer. */
+static int lgwrite_other(struct lguest *lg, u32 addr,
+ const void *buf, unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
+ != bytes)) {
+ kill_guest(lg, "bad address writing to registered DMA");
+ return 0;
+ }
+ return 1;
+}
+
+/*L:400 This is the generic engine which copies from a source "struct
+ * lguest_dma" from this Guest into another Guest's "struct lguest_dma". The
+ * destination Guest's pages have already been mapped, as contained in the
+ * pages array.
+ *
+ * If you're wondering if there's a nice "copy from one process to another"
+ * routine, so was I. But Linux isn't really set up to copy between two
+ * unrelated processes, so we have to write it ourselves.
+ */
+static u32 copy_data(struct lguest *srclg,
+ const struct lguest_dma *src,
+ const struct lguest_dma *dst,
+ struct page *pages[])
+{
+ unsigned int totlen, si, di, srcoff, dstoff;
+ void *maddr = NULL;
+
+ /* We return the total length transferred. */
+ totlen = 0;
+
+ /* We keep indexes into the source and destination "struct lguest_dma",
+ * and an offset within each region. */
+ si = di = 0;
+ srcoff = dstoff = 0;
+
+ /* We loop until the source or destination is exhausted. */
+ while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
+ && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
+ /* We can only transfer the rest of the src buffer, or as much
+ * as will fit into the destination buffer. */
+ u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
+
+ /* For systems using "highmem" we need to use kmap() to access
+ * the page we want. We often use the same page over and over,
+ * so rather than kmap() it on every loop, we set the maddr
+ * pointer to NULL when we need to move to the next
+ * destination page. */
+ if (!maddr)
+ maddr = kmap(pages[di]);
+
+ /* Copy directly from (this Guest's) source address to the
+ * destination Guest's kmap()ed buffer. Note that maddr points
+ * to the start of the page: we need to add the offset of the
+ * destination address and offset within the buffer. */
+
+ /* FIXME: This is not completely portable. I looked at
+ * copy_to_user_page(), and some arch's seem to need special
+ * flushes. x86 is fine. */
+ if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
+ (void __user *)src->addr[si], len) != 0) {
+ /* If a copy failed, it's the source's fault. */
+ kill_guest(srclg, "bad address in sending DMA");
+ totlen = 0;
+ break;
+ }
+
+ /* Increment the total and src & dst offsets */
+ totlen += len;
+ srcoff += len;
+ dstoff += len;
+
+ /* Presumably we reached the end of the src or dest buffers: */
+ if (srcoff == src->len[si]) {
+ /* Move to the next buffer at offset 0 */
+ si++;
+ srcoff = 0;
+ }
+ if (dstoff == dst->len[di]) {
+ /* We need to unmap that destination page and reset
+ * maddr ready for the next one. */
+ kunmap(pages[di]);
+ maddr = NULL;
+ di++;
+ dstoff = 0;
+ }
+ }
+
+ /* If we still had a page mapped at the end, unmap now. */
+ if (maddr)
+ kunmap(pages[di]);
+
+ return totlen;
+}
+
+/*L:390 This is how we transfer a "struct lguest_dma" from the source Guest
+ * (the current Guest which called SEND_DMA) to another Guest. */
+static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
+ struct lguest *dstlg, const struct lguest_dma *dst)
+{
+ int i;
+ u32 ret;
+ struct page *pages[LGUEST_MAX_DMA_SECTIONS];
+
+ /* We check that both source and destination "struct lguest_dma"s are
+ * within the bounds of the source and destination Guests */
+ if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
+ return 0;
+
+ /* We need to map the pages which correspond to each parts of
+ * destination buffer. */
+ for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+ if (dst->len[i] == 0)
+ break;
+ /* get_user_pages() is a complicated function, especially since
+ * we only want a single page. But it works, and returns the
+ * number of pages. Note that we're holding the destination's
+ * mmap_sem, as get_user_pages() requires. */
+ if (get_user_pages(dstlg->tsk, dstlg->mm,
+ dst->addr[i], 1, 1, 1, pages+i, NULL)
+ != 1) {
+ /* This means the destination gave us a bogus buffer */
+ kill_guest(dstlg, "Error mapping DMA pages");
+ ret = 0;
+ goto drop_pages;
+ }
+ }
+
+ /* Now copy the data until we run out of src or dst. */
+ ret = copy_data(srclg, src, dst, pages);
+
+drop_pages:
+ while (--i >= 0)
+ put_page(pages[i]);
+ return ret;
+}
+
+/*L:380 Transferring data from one Guest to another is not as simple as I'd
+ * like. We've found the "struct lguest_dma_info" bound to the same address as
+ * the send, we need to copy into it.
+ *
+ * This function returns true if the destination array was empty. */
+static int dma_transfer(struct lguest *srclg,
+ unsigned long udma,
+ struct lguest_dma_info *dst)
+{
+ struct lguest_dma dst_dma, src_dma;
+ struct lguest *dstlg;
+ u32 i, dma = 0;
+
+ /* From the "struct lguest_dma_info" we found in the hash, grab the
+ * Guest. */
+ dstlg = &lguests[dst->guestid];
+ /* Read in the source "struct lguest_dma" handed to SEND_DMA. */
+ lgread(srclg, &src_dma, udma, sizeof(src_dma));
+
+ /* We need the destination's mmap_sem, and we already hold the source's
+ * mmap_sem for the futex key lookup. Normally this would suggest that
+ * we could deadlock if the destination Guest was trying to send to
+ * this source Guest at the same time, which is another reason that all
+ * I/O is done under the big lguest_lock. */
+ down_read(&dstlg->mm->mmap_sem);
+
+ /* Look through the destination DMA array for an available buffer. */
+ for (i = 0; i < dst->num_dmas; i++) {
+ /* We keep a "next_dma" pointer which often helps us avoid
+ * looking at lots of previously-filled entries. */
+ dma = (dst->next_dma + i) % dst->num_dmas;
+ if (!lgread_other(dstlg, &dst_dma,
+ dst->dmas + dma * sizeof(struct lguest_dma),
+ sizeof(dst_dma))) {
+ goto fail;
+ }
+ if (!dst_dma.used_len)
+ break;
+ }
+
+ /* If we found a buffer, we do the actual data copy. */
+ if (i != dst->num_dmas) {
+ unsigned long used_lenp;
+ unsigned int ret;
+
+ ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
+ /* Put used length in the source "struct lguest_dma"'s used_len
+ * field. It's a little tricky to figure out where that is,
+ * though. */
+ lgwrite_u32(srclg,
+ udma+offsetof(struct lguest_dma, used_len), ret);
+ /* Tranferring 0 bytes is OK if the source buffer was empty. */
+ if (ret == 0 && src_dma.len[0] != 0)
+ goto fail;
+
+ /* The destination Guest might be running on a different CPU:
+ * we have to make sure that it will see the "used_len" field
+ * change to non-zero *after* it sees the data we copied into
+ * the buffer. Hence a write memory barrier. */
+ wmb();
+ /* Figuring out where the destination's used_len field for this
+ * "struct lguest_dma" in the array is also a little ugly. */
+ used_lenp = dst->dmas
+ + dma * sizeof(struct lguest_dma)
+ + offsetof(struct lguest_dma, used_len);
+ lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
+ /* Move the cursor for next time. */
+ dst->next_dma++;
+ }
+ up_read(&dstlg->mm->mmap_sem);
+
+ /* We trigger the destination interrupt, even if the destination was
+ * empty and we didn't transfer anything: this gives them a chance to
+ * wake up and refill. */
+ set_bit(dst->interrupt, dstlg->irqs_pending);
+ /* Wake up the destination process. */
+ wake_up_process(dstlg->tsk);
+ /* If we passed the last "struct lguest_dma", the receive had no
+ * buffers left. */
+ return i == dst->num_dmas;
+
+fail:
+ up_read(&dstlg->mm->mmap_sem);
+ return 0;
+}
+
+/*L:370 This is the counter-side to the BIND_DMA hypercall; the SEND_DMA
+ * hypercall. We find out who's listening, and send to them. */
+void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
+{
+ union futex_key key;
+ int empty = 0;
+ struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+again:
+ mutex_lock(&lguest_lock);
+ down_read(fshared);
+ /* Get the futex key for the key the Guest gave us */
+ if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+ kill_guest(lg, "bad sending DMA key");
+ goto unlock;
+ }
+ /* Since the key must be a multiple of 4, the futex key uses the lower
+ * bit of the "offset" field (which would always be 0) to indicate a
+ * mapping which is shared with other processes (ie. Guests). */
+ if (key.shared.offset & 1) {
+ struct lguest_dma_info *i;
+ /* Look through the hash for other Guests. */
+ list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+ /* Don't send to ourselves. */
+ if (i->guestid == lg->guestid)
+ continue;
+ if (!key_eq(&key, &i->key))
+ continue;
+
+ /* If dma_transfer() tells us the destination has no
+ * available buffers, we increment "empty". */
+ empty += dma_transfer(lg, udma, i);
+ break;
+ }
+ /* If the destination is empty, we release our locks and
+ * give the destination Guest a brief chance to restock. */
+ if (empty == 1) {
+ /* Give any recipients one chance to restock. */
+ up_read(&current->mm->mmap_sem);
+ mutex_unlock(&lguest_lock);
+ /* Next time, we won't try again. */
+ empty++;
+ goto again;
+ }
+ } else {
+ /* Private mapping: Guest is sending to its Launcher. We set
+ * the "dma_is_pending" flag so that the main loop will exit
+ * and the Launcher's read() from /dev/lguest will return. */
+ lg->dma_is_pending = 1;
+ lg->pending_dma = udma;
+ lg->pending_key = ukey;
+ }
+unlock:
+ up_read(fshared);
+ mutex_unlock(&lguest_lock);
+}
+/*:*/
+
+void release_all_dma(struct lguest *lg)
+{
+ unsigned int i;
+
+ BUG_ON(!mutex_is_locked(&lguest_lock));
+
+ down_read(&lg->mm->mmap_sem);
+ for (i = 0; i < LGUEST_MAX_DMA; i++) {
+ if (lg->dma[i].interrupt)
+ unlink_dma(&lg->dma[i]);
+ }
+ up_read(&lg->mm->mmap_sem);
+}
+
+/*M:007 We only return a single DMA buffer to the Launcher, but it would be
+ * more efficient to return a pointer to the entire array of DMA buffers, which
+ * it can cache and choose one whenever it wants.
+ *
+ * Currently the Launcher uses a write to /dev/lguest, and the return value is
+ * the address of the DMA structure with the interrupt number placed in
+ * dma->used_len. If we wanted to return the entire array, we need to return
+ * the address, array size and interrupt number: this seems to require an
+ * ioctl(). :*/
+
+/*L:320 This routine looks for a DMA buffer registered by the Guest on the
+ * given key (using the BIND_DMA hypercall). */
+unsigned long get_dma_buffer(struct lguest *lg,
+ unsigned long ukey, unsigned long *interrupt)
+{
+ unsigned long ret = 0;
+ union futex_key key;
+ struct lguest_dma_info *i;
+ struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+ /* Take the Big Lguest Lock to stop other Guests sending this Guest DMA
+ * at the same time. */
+ mutex_lock(&lguest_lock);
+ /* To match between Guests sharing the same underlying memory we steal
+ * code from the futex infrastructure. This requires that we hold the
+ * "mmap_sem" for our process (the Launcher), and pass it to the futex
+ * code. */
+ down_read(fshared);
+
+ /* This can fail if it's not a valid address, or if the address is not
+ * divisible by 4 (the futex code needs that, we don't really). */
+ if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+ kill_guest(lg, "bad registered DMA buffer");
+ goto unlock;
+ }
+ /* Search the hash table for matching entries (the Launcher can only
+ * send to its own Guest for the moment, so the entry must be for this
+ * Guest) */
+ list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+ if (key_eq(&key, &i->key) && i->guestid == lg->guestid) {
+ unsigned int j;
+ /* Look through the registered DMA array for an
+ * available buffer. */
+ for (j = 0; j < i->num_dmas; j++) {
+ struct lguest_dma dma;
+
+ ret = i->dmas + j * sizeof(struct lguest_dma);
+ lgread(lg, &dma, ret, sizeof(dma));
+ if (dma.used_len == 0)
+ break;
+ }
+ /* Store the interrupt the Guest wants when the buffer
+ * is used. */
+ *interrupt = i->interrupt;
+ break;
+ }
+ }
+unlock:
+ up_read(fshared);
+ mutex_unlock(&lguest_lock);
+ return ret;
+}
+/*:*/
+
+/*L:410 This really has completed the Launcher. Not only have we now finished
+ * the longest chapter in our journey, but this also means we are over halfway
+ * through!
+ *
+ * Enough prevaricating around the bush: it is time for us to dive into the
+ * core of the Host, in "make Host".
+ */
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
new file mode 100644
index 000000000000..64f0abed317c
--- /dev/null
+++ b/drivers/lguest/lg.h
@@ -0,0 +1,300 @@
+#ifndef _LGUEST_H
+#define _LGUEST_H
+
+#include <asm/desc.h>
+
+#define GDT_ENTRY_LGUEST_CS 10
+#define GDT_ENTRY_LGUEST_DS 11
+#define LGUEST_CS (GDT_ENTRY_LGUEST_CS * 8)
+#define LGUEST_DS (GDT_ENTRY_LGUEST_DS * 8)
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/stringify.h>
+#include <linux/binfmts.h>
+#include <linux/futex.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <asm/semaphore.h>
+#include "irq_vectors.h"
+
+#define GUEST_PL 1
+
+struct lguest_regs
+{
+ /* Manually saved part. */
+ unsigned long ebx, ecx, edx;
+ unsigned long esi, edi, ebp;
+ unsigned long gs;
+ unsigned long eax;
+ unsigned long fs, ds, es;
+ unsigned long trapnum, errcode;
+ /* Trap pushed part */
+ unsigned long eip;
+ unsigned long cs;
+ unsigned long eflags;
+ unsigned long esp;
+ unsigned long ss;
+};
+
+void free_pagetables(void);
+int init_pagetables(struct page **switcher_page, unsigned int pages);
+
+/* Full 4G segment descriptors, suitable for CS and DS. */
+#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
+#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
+
+struct lguest_dma_info
+{
+ struct list_head list;
+ union futex_key key;
+ unsigned long dmas;
+ u16 next_dma;
+ u16 num_dmas;
+ u16 guestid;
+ u8 interrupt; /* 0 when not registered */
+};
+
+/*H:310 The page-table code owes a great debt of gratitude to Andi Kleen. He
+ * reviewed the original code which used "u32" for all page table entries, and
+ * insisted that it would be far clearer with explicit typing. I thought it
+ * was overkill, but he was right: it is much clearer than it was before.
+ *
+ * We have separate types for the Guest's ptes & pgds and the shadow ptes &
+ * pgds. There's already a Linux type for these (pte_t and pgd_t) but they
+ * change depending on kernel config options (PAE). */
+
+/* Each entry is identical: lower 12 bits of flags and upper 20 bits for the
+ * "page frame number" (0 == first physical page, etc). They are different
+ * types so the compiler will warn us if we mix them improperly. */
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} spgd_t;
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} spte_t;
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} gpgd_t;
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} gpte_t;
+
+/* We have two convenient macros to convert a "raw" value as handed to us by
+ * the Guest into the correct Guest PGD or PTE type. */
+#define mkgpte(_val) ((gpte_t){.raw.val = _val})
+#define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
+/*:*/
+
+struct pgdir
+{
+ unsigned long cr3;
+ spgd_t *pgdir;
+};
+
+/* This is a guest-specific page (mapped ro) into the guest. */
+struct lguest_ro_state
+{
+ /* Host information we need to restore when we switch back. */
+ u32 host_cr3;
+ struct Xgt_desc_struct host_idt_desc;
+ struct Xgt_desc_struct host_gdt_desc;
+ u32 host_sp;
+
+ /* Fields which are used when guest is running. */
+ struct Xgt_desc_struct guest_idt_desc;
+ struct Xgt_desc_struct guest_gdt_desc;
+ struct i386_hw_tss guest_tss;
+ struct desc_struct guest_idt[IDT_ENTRIES];
+ struct desc_struct guest_gdt[GDT_ENTRIES];
+};
+
+/* We have two pages shared with guests, per cpu. */
+struct lguest_pages
+{
+ /* This is the stack page mapped rw in guest */
+ char spare[PAGE_SIZE - sizeof(struct lguest_regs)];
+ struct lguest_regs regs;
+
+ /* This is the host state & guest descriptor page, ro in guest */
+ struct lguest_ro_state state;
+} __attribute__((aligned(PAGE_SIZE)));
+
+#define CHANGED_IDT 1
+#define CHANGED_GDT 2
+#define CHANGED_GDT_TLS 4 /* Actually a subset of CHANGED_GDT */
+#define CHANGED_ALL 3
+
+/* The private info the thread maintains about the guest. */
+struct lguest
+{
+ /* At end of a page shared mapped over lguest_pages in guest. */
+ unsigned long regs_page;
+ struct lguest_regs *regs;
+ struct lguest_data __user *lguest_data;
+ struct task_struct *tsk;
+ struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */
+ u16 guestid;
+ u32 pfn_limit;
+ u32 page_offset;
+ u32 cr2;
+ int halted;
+ int ts;
+ u32 next_hcall;
+ u32 esp1;
+ u8 ss1;
+
+ /* Do we need to stop what we're doing and return to userspace? */
+ int break_out;
+ wait_queue_head_t break_wq;
+
+ /* Bitmap of what has changed: see CHANGED_* above. */
+ int changed;
+ struct lguest_pages *last_pages;
+
+ /* We keep a small number of these. */
+ u32 pgdidx;
+ struct pgdir pgdirs[4];
+
+ /* Cached wakeup: we hold a reference to this task. */
+ struct task_struct *wake;
+
+ unsigned long noirq_start, noirq_end;
+ int dma_is_pending;
+ unsigned long pending_dma; /* struct lguest_dma */
+ unsigned long pending_key; /* address they're sending to */
+
+ unsigned int stack_pages;
+ u32 tsc_khz;
+
+ struct lguest_dma_info dma[LGUEST_MAX_DMA];
+
+ /* Dead? */
+ const char *dead;
+
+ /* The GDT entries copied into lguest_ro_state when running. */
+ struct desc_struct gdt[GDT_ENTRIES];
+
+ /* The IDT entries: some copied into lguest_ro_state when running. */
+ struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
+ struct desc_struct syscall_idt;
+
+ /* Virtual clock device */
+ struct hrtimer hrt;
+
+ /* Pending virtual interrupts */
+ DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
+};
+
+extern struct lguest lguests[];
+extern struct mutex lguest_lock;
+
+/* core.c: */
+u32 lgread_u32(struct lguest *lg, unsigned long addr);
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
+void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
+void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
+int find_free_guest(void);
+int lguest_address_ok(const struct lguest *lg,
+ unsigned long addr, unsigned long len);
+int run_guest(struct lguest *lg, unsigned long __user *user);
+
+
+/* interrupts_and_traps.c: */
+void maybe_do_interrupt(struct lguest *lg);
+int deliver_trap(struct lguest *lg, unsigned int num);
+void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
+void pin_stack_pages(struct lguest *lg);
+void setup_default_idt_entries(struct lguest_ro_state *state,
+ const unsigned long *def);
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+ const unsigned long *def);
+void guest_set_clockevent(struct lguest *lg, unsigned long delta);
+void init_clockdev(struct lguest *lg);
+
+/* segments.c: */
+void setup_default_gdt_entries(struct lguest_ro_state *state);
+void setup_guest_gdt(struct lguest *lg);
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num);
+void guest_load_tls(struct lguest *lg, unsigned long tls_array);
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt);
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
+
+/* page_tables.c: */
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
+void free_guest_pagetable(struct lguest *lg);
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i);
+void guest_pagetable_clear_all(struct lguest *lg);
+void guest_pagetable_flush_user(struct lguest *lg);
+void guest_set_pte(struct lguest *lg, unsigned long cr3,
+ unsigned long vaddr, gpte_t val);
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
+int demand_page(struct lguest *info, unsigned long cr2, int errcode);
+void pin_page(struct lguest *lg, unsigned long vaddr);
+
+/* lguest_user.c: */
+int lguest_device_init(void);
+void lguest_device_remove(void);
+
+/* io.c: */
+void lguest_io_init(void);
+int bind_dma(struct lguest *lg,
+ unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
+void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
+void release_all_dma(struct lguest *lg);
+unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
+ unsigned long *interrupt);
+
+/* hypercalls.c: */
+void do_hypercalls(struct lguest *lg);
+void write_timestamp(struct lguest *lg);
+
+/*L:035
+ * Let's step aside for the moment, to study one important routine that's used
+ * widely in the Host code.
+ *
+ * There are many cases where the Guest does something invalid, like pass crap
+ * to a hypercall. Since only the Guest kernel can make hypercalls, it's quite
+ * acceptable to simply terminate the Guest and give the Launcher a nicely
+ * formatted reason. It's also simpler for the Guest itself, which doesn't
+ * need to check most hypercalls for "success"; if you're still running, it
+ * succeeded.
+ *
+ * Once this is called, the Guest will never run again, so most Host code can
+ * call this then continue as if nothing had happened. This means many
+ * functions don't have to explicitly return an error code, which keeps the
+ * code simple.
+ *
+ * It also means that this can be called more than once: only the first one is
+ * remembered. The only trick is that we still need to kill the Guest even if
+ * we can't allocate memory to store the reason. Linux has a neat way of
+ * packing error codes into invalid pointers, so we use that here.
+ *
+ * Like any macro which uses an "if", it is safely wrapped in a run-once "do {
+ * } while(0)".
+ */
+#define kill_guest(lg, fmt...) \
+do { \
+ if (!(lg)->dead) { \
+ (lg)->dead = kasprintf(GFP_ATOMIC, fmt); \
+ if (!(lg)->dead) \
+ (lg)->dead = ERR_PTR(-ENOMEM); \
+ } \
+} while(0)
+/* (End of aside) :*/
+
+static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+{
+ return vaddr - lg->page_offset;
+}
+#endif /* __ASSEMBLY__ */
+#endif /* _LGUEST_H */
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
new file mode 100644
index 000000000000..ee1c6d05c3d3
--- /dev/null
+++ b/drivers/lguest/lguest.c
@@ -0,0 +1,1102 @@
+/*P:010
+ * A hypervisor allows multiple Operating Systems to run on a single machine.
+ * To quote David Wheeler: "Any problem in computer science can be solved with
+ * another layer of indirection."
+ *
+ * We keep things simple in two ways. First, we start with a normal Linux
+ * kernel and insert a module (lg.ko) which allows us to run other Linux
+ * kernels the same way we'd run processes. We call the first kernel the Host,
+ * and the others the Guests. The program which sets up and configures Guests
+ * (such as the example in Documentation/lguest/lguest.c) is called the
+ * Launcher.
+ *
+ * Secondly, we only run specially modified Guests, not normal kernels. When
+ * you set CONFIG_LGUEST to 'y' or 'm', this automatically sets
+ * CONFIG_LGUEST_GUEST=y, which compiles this file into the kernel so it knows
+ * how to be a Guest. This means that you can use the same kernel you boot
+ * normally (ie. as a Host) as a Guest.
+ *
+ * These Guests know that they cannot do privileged operations, such as disable
+ * interrupts, and that they have to ask the Host to do such things explicitly.
+ * This file consists of all the replacements for such low-level native
+ * hardware operations: these special Guest versions call the Host.
+ *
+ * So how does the kernel know it's a Guest? The Guest starts at a special
+ * entry point marked with a magic string, which sets up a few things then
+ * calls here. We replace the native functions in "struct paravirt_ops"
+ * with our Guest versions, then boot like normal. :*/
+
+/*
+ * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/lguest_bus.h>
+#include <asm/paravirt.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/mce.h>
+#include <asm/io.h>
+
+/*G:010 Welcome to the Guest!
+ *
+ * The Guest in our tale is a simple creature: identical to the Host but
+ * behaving in simplified but equivalent ways. In particular, the Guest is the
+ * same kernel as the Host (or at least, built from the same source code). :*/
+
+/* Declarations for definitions in lguest_guest.S */
+extern char lguest_noirq_start[], lguest_noirq_end[];
+extern const char lgstart_cli[], lgend_cli[];
+extern const char lgstart_sti[], lgend_sti[];
+extern const char lgstart_popf[], lgend_popf[];
+extern const char lgstart_pushf[], lgend_pushf[];
+extern const char lgstart_iret[], lgend_iret[];
+extern void lguest_iret(void);
+
+struct lguest_data lguest_data = {
+ .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
+ .noirq_start = (u32)lguest_noirq_start,
+ .noirq_end = (u32)lguest_noirq_end,
+ .blocked_interrupts = { 1 }, /* Block timer interrupts */
+};
+struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
+
+/*G:035 Notice the lazy_hcall() above, rather than hcall(). This is our first
+ * real optimization trick!
+ *
+ * When lazy_mode is set, it means we're allowed to defer all hypercalls and do
+ * them as a batch when lazy_mode is eventually turned off. Because hypercalls
+ * are reasonably expensive, batching them up makes sense. For example, a
+ * large mmap might update dozens of page table entries: that code calls
+ * lguest_lazy_mode(PARAVIRT_LAZY_MMU), does the dozen updates, then calls
+ * lguest_lazy_mode(PARAVIRT_LAZY_NONE).
+ *
+ * So, when we're in lazy mode, we call async_hypercall() to store the call for
+ * future processing. When lazy mode is turned off we issue a hypercall to
+ * flush the stored calls.
+ *
+ * There's also a hack where "mode" is set to "PARAVIRT_LAZY_FLUSH" which
+ * indicates we're to flush any outstanding calls immediately. This is used
+ * when an interrupt handler does a kmap_atomic(): the page table changes must
+ * happen immediately even if we're in the middle of a batch. Usually we're
+ * not, though, so there's nothing to do. */
+static enum paravirt_lazy_mode lazy_mode; /* Note: not SMP-safe! */
+static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
+{
+ if (mode == PARAVIRT_LAZY_FLUSH) {
+ if (unlikely(lazy_mode != PARAVIRT_LAZY_NONE))
+ hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+ } else {
+ lazy_mode = mode;
+ if (mode == PARAVIRT_LAZY_NONE)
+ hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+ }
+}
+
+static void lazy_hcall(unsigned long call,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3)
+{
+ if (lazy_mode == PARAVIRT_LAZY_NONE)
+ hcall(call, arg1, arg2, arg3);
+ else
+ async_hcall(call, arg1, arg2, arg3);
+}
+
+/* async_hcall() is pretty simple: I'm quite proud of it really. We have a
+ * ring buffer of stored hypercalls which the Host will run though next time we
+ * do a normal hypercall. Each entry in the ring has 4 slots for the hypercall
+ * arguments, and a "hcall_status" word which is 0 if the call is ready to go,
+ * and 255 once the Host has finished with it.
+ *
+ * If we come around to a slot which hasn't been finished, then the table is
+ * full and we just make the hypercall directly. This has the nice side
+ * effect of causing the Host to run all the stored calls in the ring buffer
+ * which empties it for next time! */
+void async_hcall(unsigned long call,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+ /* Note: This code assumes we're uniprocessor. */
+ static unsigned int next_call;
+ unsigned long flags;
+
+ /* Disable interrupts if not already disabled: we don't want an
+ * interrupt handler making a hypercall while we're already doing
+ * one! */
+ local_irq_save(flags);
+ if (lguest_data.hcall_status[next_call] != 0xFF) {
+ /* Table full, so do normal hcall which will flush table. */
+ hcall(call, arg1, arg2, arg3);
+ } else {
+ lguest_data.hcalls[next_call].eax = call;
+ lguest_data.hcalls[next_call].edx = arg1;
+ lguest_data.hcalls[next_call].ebx = arg2;
+ lguest_data.hcalls[next_call].ecx = arg3;
+ /* Arguments must all be written before we mark it to go */
+ wmb();
+ lguest_data.hcall_status[next_call] = 0;
+ if (++next_call == LHCALL_RING_SIZE)
+ next_call = 0;
+ }
+ local_irq_restore(flags);
+}
+/*:*/
+
+/* Wrappers for the SEND_DMA and BIND_DMA hypercalls. This is mainly because
+ * Jeff Garzik complained that __pa() should never appear in drivers, and this
+ * helps remove most of them. But also, it wraps some ugliness. */
+void lguest_send_dma(unsigned long key, struct lguest_dma *dma)
+{
+ /* The hcall might not write this if something goes wrong */
+ dma->used_len = 0;
+ hcall(LHCALL_SEND_DMA, key, __pa(dma), 0);
+}
+
+int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
+ unsigned int num, u8 irq)
+{
+ /* This is the only hypercall which actually wants 5 arguments, and we
+ * only support 4. Fortunately the interrupt number is always less
+ * than 256, so we can pack it with the number of dmas in the final
+ * argument. */
+ if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq))
+ return -ENOMEM;
+ return 0;
+}
+
+/* Unbinding is the same hypercall as binding, but with 0 num & irq. */
+void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas)
+{
+ hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0);
+}
+
+/* For guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse. */
+void *lguest_map(unsigned long phys_addr, unsigned long pages)
+{
+ return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+}
+
+void lguest_unmap(void *addr)
+{
+ iounmap((__force void __iomem *)addr);
+}
+
+/*G:033
+ * Here are our first native-instruction replacements: four functions for
+ * interrupt control.
+ *
+ * The simplest way of implementing these would be to have "turn interrupts
+ * off" and "turn interrupts on" hypercalls. Unfortunately, this is too slow:
+ * these are by far the most commonly called functions of those we override.
+ *
+ * So instead we keep an "irq_enabled" field inside our "struct lguest_data",
+ * which the Guest can update with a single instruction. The Host knows to
+ * check there when it wants to deliver an interrupt.
+ */
+
+/* save_flags() is expected to return the processor state (ie. "eflags"). The
+ * eflags word contains all kind of stuff, but in practice Linux only cares
+ * about the interrupt flag. Our "save_flags()" just returns that. */
+static unsigned long save_fl(void)
+{
+ return lguest_data.irq_enabled;
+}
+
+/* "restore_flags" just sets the flags back to the value given. */
+static void restore_fl(unsigned long flags)
+{
+ lguest_data.irq_enabled = flags;
+}
+
+/* Interrupts go off... */
+static void irq_disable(void)
+{
+ lguest_data.irq_enabled = 0;
+}
+
+/* Interrupts go on... */
+static void irq_enable(void)
+{
+ lguest_data.irq_enabled = X86_EFLAGS_IF;
+}
+/*:*/
+/*M:003 Note that we don't check for outstanding interrupts when we re-enable
+ * them (or when we unmask an interrupt). This seems to work for the moment,
+ * since interrupts are rare and we'll just get the interrupt on the next timer
+ * tick, but when we turn on CONFIG_NO_HZ, we should revisit this. One way
+ * would be to put the "irq_enabled" field in a page by itself, and have the
+ * Host write-protect it when an interrupt comes in when irqs are disabled.
+ * There will then be a page fault as soon as interrupts are re-enabled. :*/
+
+/*G:034
+ * The Interrupt Descriptor Table (IDT).
+ *
+ * The IDT tells the processor what to do when an interrupt comes in. Each
+ * entry in the table is a 64-bit descriptor: this holds the privilege level,
+ * address of the handler, and... well, who cares? The Guest just asks the
+ * Host to make the change anyway, because the Host controls the real IDT.
+ */
+static void lguest_write_idt_entry(struct desc_struct *dt,
+ int entrynum, u32 low, u32 high)
+{
+ /* Keep the local copy up to date. */
+ write_dt_entry(dt, entrynum, low, high);
+ /* Tell Host about this new entry. */
+ hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high);
+}
+
+/* Changing to a different IDT is very rare: we keep the IDT up-to-date every
+ * time it is written, so we can simply loop through all entries and tell the
+ * Host about them. */
+static void lguest_load_idt(const struct Xgt_desc_struct *desc)
+{
+ unsigned int i;
+ struct desc_struct *idt = (void *)desc->address;
+
+ for (i = 0; i < (desc->size+1)/8; i++)
+ hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+}
+
+/*
+ * The Global Descriptor Table.
+ *
+ * The Intel architecture defines another table, called the Global Descriptor
+ * Table (GDT). You tell the CPU where it is (and its size) using the "lgdt"
+ * instruction, and then several other instructions refer to entries in the
+ * table. There are three entries which the Switcher needs, so the Host simply
+ * controls the entire thing and the Guest asks it to make changes using the
+ * LOAD_GDT hypercall.
+ *
+ * This is the opposite of the IDT code where we have a LOAD_IDT_ENTRY
+ * hypercall and use that repeatedly to load a new IDT. I don't think it
+ * really matters, but wouldn't it be nice if they were the same?
+ */
+static void lguest_load_gdt(const struct Xgt_desc_struct *desc)
+{
+ BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
+ hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
+}
+
+/* For a single GDT entry which changes, we do the lazy thing: alter our GDT,
+ * then tell the Host to reload the entire thing. This operation is so rare
+ * that this naive implementation is reasonable. */
+static void lguest_write_gdt_entry(struct desc_struct *dt,
+ int entrynum, u32 low, u32 high)
+{
+ write_dt_entry(dt, entrynum, low, high);
+ hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
+}
+
+/* OK, I lied. There are three "thread local storage" GDT entries which change
+ * on every context switch (these three entries are how glibc implements
+ * __thread variables). So we have a hypercall specifically for this case. */
+static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+ /* There's one problem which normal hardware doesn't have: the Host
+ * can't handle us removing entries we're currently using. So we clear
+ * the GS register here: if it's needed it'll be reloaded anyway. */
+ loadsegment(gs, 0);
+ lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
+}
+
+/*G:038 That's enough excitement for now, back to ploughing through each of
+ * the paravirt_ops (we're about 1/3 of the way through).
+ *
+ * This is the Local Descriptor Table, another weird Intel thingy. Linux only
+ * uses this for some strange applications like Wine. We don't do anything
+ * here, so they'll get an informative and friendly Segmentation Fault. */
+static void lguest_set_ldt(const void *addr, unsigned entries)
+{
+}
+
+/* This loads a GDT entry into the "Task Register": that entry points to a
+ * structure called the Task State Segment. Some comments scattered though the
+ * kernel code indicate that this used for task switching in ages past, along
+ * with blood sacrifice and astrology.
+ *
+ * Now there's nothing interesting in here that we don't get told elsewhere.
+ * But the native version uses the "ltr" instruction, which makes the Host
+ * complain to the Guest about a Segmentation Fault and it'll oops. So we
+ * override the native version with a do-nothing version. */
+static void lguest_load_tr_desc(void)
+{
+}
+
+/* The "cpuid" instruction is a way of querying both the CPU identity
+ * (manufacturer, model, etc) and its features. It was introduced before the
+ * Pentium in 1993 and keeps getting extended by both Intel and AMD. As you
+ * might imagine, after a decade and a half this treatment, it is now a giant
+ * ball of hair. Its entry in the current Intel manual runs to 28 pages.
+ *
+ * This instruction even it has its own Wikipedia entry. The Wikipedia entry
+ * has been translated into 4 languages. I am not making this up!
+ *
+ * We could get funky here and identify ourselves as "GenuineLguest", but
+ * instead we just use the real "cpuid" instruction. Then I pretty much turned
+ * off feature bits until the Guest booted. (Don't say that: you'll damage
+ * lguest sales!) Shut up, inner voice! (Hey, just pointing out that this is
+ * hardly future proof.) Noone's listening! They don't like you anyway,
+ * parenthetic weirdo!
+ *
+ * Replacing the cpuid so we can turn features off is great for the kernel, but
+ * anyone (including userspace) can just use the raw "cpuid" instruction and
+ * the Host won't even notice since it isn't privileged. So we try not to get
+ * too worked up about it. */
+static void lguest_cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ int function = *eax;
+
+ native_cpuid(eax, ebx, ecx, edx);
+ switch (function) {
+ case 1: /* Basic feature request. */
+ /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
+ *ecx &= 0x00002201;
+ /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, FPU. */
+ *edx &= 0x07808101;
+ /* The Host can do a nice optimization if it knows that the
+ * kernel mappings (addresses above 0xC0000000 or whatever
+ * PAGE_OFFSET is set to) haven't changed. But Linux calls
+ * flush_tlb_user() for both user and kernel mappings unless
+ * the Page Global Enable (PGE) feature bit is set. */
+ *edx |= 0x00002000;
+ break;
+ case 0x80000000:
+ /* Futureproof this a little: if they ask how much extended
+ * processor information there is, limit it to known fields. */
+ if (*eax > 0x80000008)
+ *eax = 0x80000008;
+ break;
+ }
+}
+
+/* Intel has four control registers, imaginatively named cr0, cr2, cr3 and cr4.
+ * I assume there's a cr1, but it hasn't bothered us yet, so we'll not bother
+ * it. The Host needs to know when the Guest wants to change them, so we have
+ * a whole series of functions like read_cr0() and write_cr0().
+ *
+ * We start with CR0. CR0 allows you to turn on and off all kinds of basic
+ * features, but Linux only really cares about one: the horrifically-named Task
+ * Switched (TS) bit at bit 3 (ie. 8)
+ *
+ * What does the TS bit do? Well, it causes the CPU to trap (interrupt 7) if
+ * the floating point unit is used. Which allows us to restore FPU state
+ * lazily after a task switch, and Linux uses that gratefully, but wouldn't a
+ * name like "FPUTRAP bit" be a little less cryptic?
+ *
+ * We store cr0 (and cr3) locally, because the Host never changes it. The
+ * Guest sometimes wants to read it and we'd prefer not to bother the Host
+ * unnecessarily. */
+static unsigned long current_cr0, current_cr3;
+static void lguest_write_cr0(unsigned long val)
+{
+ /* 8 == TS bit. */
+ lazy_hcall(LHCALL_TS, val & 8, 0, 0);
+ current_cr0 = val;
+}
+
+static unsigned long lguest_read_cr0(void)
+{
+ return current_cr0;
+}
+
+/* Intel provided a special instruction to clear the TS bit for people too cool
+ * to use write_cr0() to do it. This "clts" instruction is faster, because all
+ * the vowels have been optimized out. */
+static void lguest_clts(void)
+{
+ lazy_hcall(LHCALL_TS, 0, 0, 0);
+ current_cr0 &= ~8U;
+}
+
+/* CR2 is the virtual address of the last page fault, which the Guest only ever
+ * reads. The Host kindly writes this into our "struct lguest_data", so we
+ * just read it out of there. */
+static unsigned long lguest_read_cr2(void)
+{
+ return lguest_data.cr2;
+}
+
+/* CR3 is the current toplevel pagetable page: the principle is the same as
+ * cr0. Keep a local copy, and tell the Host when it changes. */
+static void lguest_write_cr3(unsigned long cr3)
+{
+ lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
+ current_cr3 = cr3;
+}
+
+static unsigned long lguest_read_cr3(void)
+{
+ return current_cr3;
+}
+
+/* CR4 is used to enable and disable PGE, but we don't care. */
+static unsigned long lguest_read_cr4(void)
+{
+ return 0;
+}
+
+static void lguest_write_cr4(unsigned long val)
+{
+}
+
+/*
+ * Page Table Handling.
+ *
+ * Now would be a good time to take a rest and grab a coffee or similarly
+ * relaxing stimulant. The easy parts are behind us, and the trek gradually
+ * winds uphill from here.
+ *
+ * Quick refresher: memory is divided into "pages" of 4096 bytes each. The CPU
+ * maps virtual addresses to physical addresses using "page tables". We could
+ * use one huge index of 1 million entries: each address is 4 bytes, so that's
+ * 1024 pages just to hold the page tables. But since most virtual addresses
+ * are unused, we use a two level index which saves space. The CR3 register
+ * contains the physical address of the top level "page directory" page, which
+ * contains physical addresses of up to 1024 second-level pages. Each of these
+ * second level pages contains up to 1024 physical addresses of actual pages,
+ * or Page Table Entries (PTEs).
+ *
+ * Here's a diagram, where arrows indicate physical addresses:
+ *
+ * CR3 ---> +---------+
+ * | --------->+---------+
+ * | | | PADDR1 |
+ * Top-level | | PADDR2 |
+ * (PMD) page | | |
+ * | | Lower-level |
+ * | | (PTE) page |
+ * | | | |
+ * .... ....
+ *
+ * So to convert a virtual address to a physical address, we look up the top
+ * level, which points us to the second level, which gives us the physical
+ * address of that page. If the top level entry was not present, or the second
+ * level entry was not present, then the virtual address is invalid (we
+ * say "the page was not mapped").
+ *
+ * Put another way, a 32-bit virtual address is divided up like so:
+ *
+ * 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ * |<---- 10 bits ---->|<---- 10 bits ---->|<------ 12 bits ------>|
+ * Index into top Index into second Offset within page
+ * page directory page pagetable page
+ *
+ * The kernel spends a lot of time changing both the top-level page directory
+ * and lower-level pagetable pages. The Guest doesn't know physical addresses,
+ * so while it maintains these page tables exactly like normal, it also needs
+ * to keep the Host informed whenever it makes a change: the Host will create
+ * the real page tables based on the Guests'.
+ */
+
+/* The Guest calls this to set a second-level entry (pte), ie. to map a page
+ * into a process' address space. We set the entry then tell the Host the
+ * toplevel and address this corresponds to. The Guest uses one pagetable per
+ * process, so we need to tell the Host which one we're changing (mm->pgd). */
+static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+ lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
+}
+
+/* The Guest calls this to set a top-level entry. Again, we set the entry then
+ * tell the Host which top-level page we changed, and the index of the entry we
+ * changed. */
+static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ *pmdp = pmdval;
+ lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
+ (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+}
+
+/* There are a couple of legacy places where the kernel sets a PTE, but we
+ * don't know the top level any more. This is useless for us, since we don't
+ * know which pagetable is changing or what address, so we just tell the Host
+ * to forget all of them. Fortunately, this is very rare.
+ *
+ * ... except in early boot when the kernel sets up the initial pagetables,
+ * which makes booting astonishingly slow. So we don't even tell the Host
+ * anything changed until we've done the first page table switch.
+ */
+static void lguest_set_pte(pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+ /* Don't bother with hypercall before initial setup. */
+ if (current_cr3)
+ lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+/* Unfortunately for Lguest, the paravirt_ops for page tables were based on
+ * native page table operations. On native hardware you can set a new page
+ * table entry whenever you want, but if you want to remove one you have to do
+ * a TLB flush (a TLB is a little cache of page table entries kept by the CPU).
+ *
+ * So the lguest_set_pte_at() and lguest_set_pmd() functions above are only
+ * called when a valid entry is written, not when it's removed (ie. marked not
+ * present). Instead, this is where we come when the Guest wants to remove a
+ * page table entry: we tell the Host to set that entry to 0 (ie. the present
+ * bit is zero). */
+static void lguest_flush_tlb_single(unsigned long addr)
+{
+ /* Simply set it to zero: if it was not, it will fault back in. */
+ lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0);
+}
+
+/* This is what happens after the Guest has removed a large number of entries.
+ * This tells the Host that any of the page table entries for userspace might
+ * have changed, ie. virtual addresses below PAGE_OFFSET. */
+static void lguest_flush_tlb_user(void)
+{
+ lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
+}
+
+/* This is called when the kernel page tables have changed. That's not very
+ * common (unless the Guest is using highmem, which makes the Guest extremely
+ * slow), so it's worth separating this from the user flushing above. */
+static void lguest_flush_tlb_kernel(void)
+{
+ lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+/*
+ * The Unadvanced Programmable Interrupt Controller.
+ *
+ * This is an attempt to implement the simplest possible interrupt controller.
+ * I spent some time looking though routines like set_irq_chip_and_handler,
+ * set_irq_chip_and_handler_name, set_irq_chip_data and set_phasers_to_stun and
+ * I *think* this is as simple as it gets.
+ *
+ * We can tell the Host what interrupts we want blocked ready for using the
+ * lguest_data.interrupts bitmap, so disabling (aka "masking") them is as
+ * simple as setting a bit. We don't actually "ack" interrupts as such, we
+ * just mask and unmask them. I wonder if we should be cleverer?
+ */
+static void disable_lguest_irq(unsigned int irq)
+{
+ set_bit(irq, lguest_data.blocked_interrupts);
+}
+
+static void enable_lguest_irq(unsigned int irq)
+{
+ clear_bit(irq, lguest_data.blocked_interrupts);
+}
+
+/* This structure describes the lguest IRQ controller. */
+static struct irq_chip lguest_irq_controller = {
+ .name = "lguest",
+ .mask = disable_lguest_irq,
+ .mask_ack = disable_lguest_irq,
+ .unmask = enable_lguest_irq,
+};
+
+/* This sets up the Interrupt Descriptor Table (IDT) entry for each hardware
+ * interrupt (except 128, which is used for system calls), and then tells the
+ * Linux infrastructure that each interrupt is controlled by our level-based
+ * lguest interrupt controller. */
+static void __init lguest_init_IRQ(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < LGUEST_IRQS; i++) {
+ int vector = FIRST_EXTERNAL_VECTOR + i;
+ if (vector != SYSCALL_VECTOR) {
+ set_intr_gate(vector, interrupt[i]);
+ set_irq_chip_and_handler(i, &lguest_irq_controller,
+ handle_level_irq);
+ }
+ }
+ /* This call is required to set up for 4k stacks, where we have
+ * separate stacks for hard and soft interrupts. */
+ irq_ctx_init(smp_processor_id());
+}
+
+/*
+ * Time.
+ *
+ * It would be far better for everyone if the Guest had its own clock, but
+ * until then the Host gives us the time on every interrupt.
+ */
+static unsigned long lguest_get_wallclock(void)
+{
+ return lguest_data.time.tv_sec;
+}
+
+static cycle_t lguest_clock_read(void)
+{
+ unsigned long sec, nsec;
+
+ /* If the Host tells the TSC speed, we can trust that. */
+ if (lguest_data.tsc_khz)
+ return native_read_tsc();
+
+ /* If we can't use the TSC, we read the time value written by the Host.
+ * Since it's in two parts (seconds and nanoseconds), we risk reading
+ * it just as it's changing from 99 & 0.999999999 to 100 and 0, and
+ * getting 99 and 0. As Linux tends to come apart under the stress of
+ * time travel, we must be careful: */
+ do {
+ /* First we read the seconds part. */
+ sec = lguest_data.time.tv_sec;
+ /* This read memory barrier tells the compiler and the CPU that
+ * this can't be reordered: we have to complete the above
+ * before going on. */
+ rmb();
+ /* Now we read the nanoseconds part. */
+ nsec = lguest_data.time.tv_nsec;
+ /* Make sure we've done that. */
+ rmb();
+ /* Now if the seconds part has changed, try again. */
+ } while (unlikely(lguest_data.time.tv_sec != sec));
+
+ /* Our non-TSC clock is in real nanoseconds. */
+ return sec*1000000000ULL + nsec;
+}
+
+/* This is what we tell the kernel is our clocksource. */
+static struct clocksource lguest_clock = {
+ .name = "lguest",
+ .rating = 400,
+ .read = lguest_clock_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .mult = 1 << 22,
+ .shift = 22,
+};
+
+/* The "scheduler clock" is just our real clock, adjusted to start at zero */
+static unsigned long long lguest_sched_clock(void)
+{
+ return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
+/* We also need a "struct clock_event_device": Linux asks us to set it to go
+ * off some time in the future. Actually, James Morris figured all this out, I
+ * just applied the patch. */
+static int lguest_clockevent_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ if (delta < LG_CLOCK_MIN_DELTA) {
+ if (printk_ratelimit())
+ printk(KERN_DEBUG "%s: small delta %lu ns\n",
+ __FUNCTION__, delta);
+ return -ETIME;
+ }
+ hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+ return 0;
+}
+
+static void lguest_clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /* A 0 argument shuts the clock down. */
+ hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* This is what we expect. */
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ BUG();
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+/* This describes our primitive timer chip. */
+static struct clock_event_device lguest_clockevent = {
+ .name = "lguest",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = lguest_clockevent_set_next_event,
+ .set_mode = lguest_clockevent_set_mode,
+ .rating = INT_MAX,
+ .mult = 1,
+ .shift = 0,
+ .min_delta_ns = LG_CLOCK_MIN_DELTA,
+ .max_delta_ns = LG_CLOCK_MAX_DELTA,
+};
+
+/* This is the Guest timer interrupt handler (hardware interrupt 0). We just
+ * call the clockevent infrastructure and it does whatever needs doing. */
+static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned long flags;
+
+ /* Don't interrupt us while this is running. */
+ local_irq_save(flags);
+ lguest_clockevent.event_handler(&lguest_clockevent);
+ local_irq_restore(flags);
+}
+
+/* At some point in the boot process, we get asked to set up our timing
+ * infrastructure. The kernel doesn't expect timer interrupts before this, but
+ * we cleverly initialized the "blocked_interrupts" field of "struct
+ * lguest_data" so that timer interrupts were blocked until now. */
+static void lguest_time_init(void)
+{
+ /* Set up the timer interrupt (0) to go to our simple timer routine */
+ set_irq_handler(0, lguest_time_irq);
+
+ /* Our clock structure look like arch/i386/kernel/tsc.c if we can use
+ * the TSC, otherwise it's a dumb nanosecond-resolution clock. Either
+ * way, the "rating" is initialized so high that it's always chosen
+ * over any other clocksource. */
+ if (lguest_data.tsc_khz) {
+ lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz,
+ lguest_clock.shift);
+ lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+ }
+ clock_base = lguest_clock_read();
+ clocksource_register(&lguest_clock);
+
+ /* Now we've set up our clock, we can use it as the scheduler clock */
+ paravirt_ops.sched_clock = lguest_sched_clock;
+
+ /* We can't set cpumask in the initializer: damn C limitations! Set it
+ * here and register our timer device. */
+ lguest_clockevent.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&lguest_clockevent);
+
+ /* Finally, we unblock the timer interrupt. */
+ enable_lguest_irq(0);
+}
+
+/*
+ * Miscellaneous bits and pieces.
+ *
+ * Here is an oddball collection of functions which the Guest needs for things
+ * to work. They're pretty simple.
+ */
+
+/* The Guest needs to tell the host what stack it expects traps to use. For
+ * native hardware, this is part of the Task State Segment mentioned above in
+ * lguest_load_tr_desc(), but to help hypervisors there's this special call.
+ *
+ * We tell the Host the segment we want to use (__KERNEL_DS is the kernel data
+ * segment), the privilege level (we're privilege level 1, the Host is 0 and
+ * will not tolerate us trying to use that), the stack pointer, and the number
+ * of pages in the stack. */
+static void lguest_load_esp0(struct tss_struct *tss,
+ struct thread_struct *thread)
+{
+ lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->esp0,
+ THREAD_SIZE/PAGE_SIZE);
+}
+
+/* Let's just say, I wouldn't do debugging under a Guest. */
+static void lguest_set_debugreg(int regno, unsigned long value)
+{
+ /* FIXME: Implement */
+}
+
+/* There are times when the kernel wants to make sure that no memory writes are
+ * caught in the cache (that they've all reached real hardware devices). This
+ * doesn't matter for the Guest which has virtual hardware.
+ *
+ * On the Pentium 4 and above, cpuid() indicates that the Cache Line Flush
+ * (clflush) instruction is available and the kernel uses that. Otherwise, it
+ * uses the older "Write Back and Invalidate Cache" (wbinvd) instruction.
+ * Unlike clflush, wbinvd can only be run at privilege level 0. So we can
+ * ignore clflush, but replace wbinvd.
+ */
+static void lguest_wbinvd(void)
+{
+}
+
+/* If the Guest expects to have an Advanced Programmable Interrupt Controller,
+ * we play dumb by ignoring writes and returning 0 for reads. So it's no
+ * longer Programmable nor Controlling anything, and I don't think 8 lines of
+ * code qualifies for Advanced. It will also never interrupt anything. It
+ * does, however, allow us to get through the Linux boot code. */
+#ifdef CONFIG_X86_LOCAL_APIC
+static void lguest_apic_write(unsigned long reg, unsigned long v)
+{
+}
+
+static unsigned long lguest_apic_read(unsigned long reg)
+{
+ return 0;
+}
+#endif
+
+/* STOP! Until an interrupt comes in. */
+static void lguest_safe_halt(void)
+{
+ hcall(LHCALL_HALT, 0, 0, 0);
+}
+
+/* Perhaps CRASH isn't the best name for this hypercall, but we use it to get a
+ * message out when we're crashing as well as elegant termination like powering
+ * off.
+ *
+ * Note that the Host always prefers that the Guest speak in physical addresses
+ * rather than virtual addresses, so we use __pa() here. */
+static void lguest_power_off(void)
+{
+ hcall(LHCALL_CRASH, __pa("Power down"), 0, 0);
+}
+
+/*
+ * Panicing.
+ *
+ * Don't. But if you did, this is what happens.
+ */
+static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
+{
+ hcall(LHCALL_CRASH, __pa(p), 0, 0);
+ /* The hcall won't return, but to keep gcc happy, we're "done". */
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block paniced = {
+ .notifier_call = lguest_panic
+};
+
+/* Setting up memory is fairly easy. */
+static __init char *lguest_memory_setup(void)
+{
+ /* We do this here and not earlier because lockcheck barfs if we do it
+ * before start_kernel() */
+ atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+
+ /* The Linux bootloader header contains an "e820" memory map: the
+ * Launcher populated the first entry with our memory limit. */
+ add_memory_region(E820_MAP->addr, E820_MAP->size, E820_MAP->type);
+
+ /* This string is for the boot messages. */
+ return "LGUEST";
+}
+
+/*G:050
+ * Patching (Powerfully Placating Performance Pedants)
+ *
+ * We have already seen that "struct paravirt_ops" lets us replace simple
+ * native instructions with calls to the appropriate back end all throughout
+ * the kernel. This allows the same kernel to run as a Guest and as a native
+ * kernel, but it's slow because of all the indirect branches.
+ *
+ * Remember that David Wheeler quote about "Any problem in computer science can
+ * be solved with another layer of indirection"? The rest of that quote is
+ * "... But that usually will create another problem." This is the first of
+ * those problems.
+ *
+ * Our current solution is to allow the paravirt back end to optionally patch
+ * over the indirect calls to replace them with something more efficient. We
+ * patch the four most commonly called functions: disable interrupts, enable
+ * interrupts, restore interrupts and save interrupts. We usually have 10
+ * bytes to patch into: the Guest versions of these operations are small enough
+ * that we can fit comfortably.
+ *
+ * First we need assembly templates of each of the patchable Guest operations,
+ * and these are in lguest_asm.S. */
+
+/*G:060 We construct a table from the assembler templates: */
+static const struct lguest_insns
+{
+ const char *start, *end;
+} lguest_insns[] = {
+ [PARAVIRT_PATCH(irq_disable)] = { lgstart_cli, lgend_cli },
+ [PARAVIRT_PATCH(irq_enable)] = { lgstart_sti, lgend_sti },
+ [PARAVIRT_PATCH(restore_fl)] = { lgstart_popf, lgend_popf },
+ [PARAVIRT_PATCH(save_fl)] = { lgstart_pushf, lgend_pushf },
+};
+
+/* Now our patch routine is fairly simple (based on the native one in
+ * paravirt.c). If we have a replacement, we copy it in and return how much of
+ * the available space we used. */
+static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
+ unsigned long addr, unsigned len)
+{
+ unsigned int insn_len;
+
+ /* Don't do anything special if we don't have a replacement */
+ if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start)
+ return paravirt_patch_default(type, clobber, ibuf, addr, len);
+
+ insn_len = lguest_insns[type].end - lguest_insns[type].start;
+
+ /* Similarly if we can't fit replacement (shouldn't happen, but let's
+ * be thorough). */
+ if (len < insn_len)
+ return paravirt_patch_default(type, clobber, ibuf, addr, len);
+
+ /* Copy in our instructions. */
+ memcpy(ibuf, lguest_insns[type].start, insn_len);
+ return insn_len;
+}
+
+/*G:030 Once we get to lguest_init(), we know we're a Guest. The paravirt_ops
+ * structure in the kernel provides a single point for (almost) every routine
+ * we have to override to avoid privileged instructions. */
+__init void lguest_init(void *boot)
+{
+ /* Copy boot parameters first: the Launcher put the physical location
+ * in %esi, and head.S converted that to a virtual address and handed
+ * it to us. We use "__memcpy" because "memcpy" sometimes tries to do
+ * tricky things to go faster, and we're not ready for that. */
+ __memcpy(&boot_params, boot, PARAM_SIZE);
+ /* The boot parameters also tell us where the command-line is: save
+ * that, too. */
+ __memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr),
+ COMMAND_LINE_SIZE);
+
+ /* We're under lguest, paravirt is enabled, and we're running at
+ * privilege level 1, not 0 as normal. */
+ paravirt_ops.name = "lguest";
+ paravirt_ops.paravirt_enabled = 1;
+ paravirt_ops.kernel_rpl = 1;
+
+ /* We set up all the lguest overrides for sensitive operations. These
+ * are detailed with the operations themselves. */
+ paravirt_ops.save_fl = save_fl;
+ paravirt_ops.restore_fl = restore_fl;
+ paravirt_ops.irq_disable = irq_disable;
+ paravirt_ops.irq_enable = irq_enable;
+ paravirt_ops.load_gdt = lguest_load_gdt;
+ paravirt_ops.memory_setup = lguest_memory_setup;
+ paravirt_ops.cpuid = lguest_cpuid;
+ paravirt_ops.write_cr3 = lguest_write_cr3;
+ paravirt_ops.flush_tlb_user = lguest_flush_tlb_user;
+ paravirt_ops.flush_tlb_single = lguest_flush_tlb_single;
+ paravirt_ops.flush_tlb_kernel = lguest_flush_tlb_kernel;
+ paravirt_ops.set_pte = lguest_set_pte;
+ paravirt_ops.set_pte_at = lguest_set_pte_at;
+ paravirt_ops.set_pmd = lguest_set_pmd;
+#ifdef CONFIG_X86_LOCAL_APIC
+ paravirt_ops.apic_write = lguest_apic_write;
+ paravirt_ops.apic_write_atomic = lguest_apic_write;
+ paravirt_ops.apic_read = lguest_apic_read;
+#endif
+ paravirt_ops.load_idt = lguest_load_idt;
+ paravirt_ops.iret = lguest_iret;
+ paravirt_ops.load_esp0 = lguest_load_esp0;
+ paravirt_ops.load_tr_desc = lguest_load_tr_desc;
+ paravirt_ops.set_ldt = lguest_set_ldt;
+ paravirt_ops.load_tls = lguest_load_tls;
+ paravirt_ops.set_debugreg = lguest_set_debugreg;
+ paravirt_ops.clts = lguest_clts;
+ paravirt_ops.read_cr0 = lguest_read_cr0;
+ paravirt_ops.write_cr0 = lguest_write_cr0;
+ paravirt_ops.init_IRQ = lguest_init_IRQ;
+ paravirt_ops.read_cr2 = lguest_read_cr2;
+ paravirt_ops.read_cr3 = lguest_read_cr3;
+ paravirt_ops.read_cr4 = lguest_read_cr4;
+ paravirt_ops.write_cr4 = lguest_write_cr4;
+ paravirt_ops.write_gdt_entry = lguest_write_gdt_entry;
+ paravirt_ops.write_idt_entry = lguest_write_idt_entry;
+ paravirt_ops.patch = lguest_patch;
+ paravirt_ops.safe_halt = lguest_safe_halt;
+ paravirt_ops.get_wallclock = lguest_get_wallclock;
+ paravirt_ops.time_init = lguest_time_init;
+ paravirt_ops.set_lazy_mode = lguest_lazy_mode;
+ paravirt_ops.wbinvd = lguest_wbinvd;
+ /* Now is a good time to look at the implementations of these functions
+ * before returning to the rest of lguest_init(). */
+
+ /*G:070 Now we've seen all the paravirt_ops, we return to
+ * lguest_init() where the rest of the fairly chaotic boot setup
+ * occurs.
+ *
+ * The Host expects our first hypercall to tell it where our "struct
+ * lguest_data" is, so we do that first. */
+ hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
+
+ /* The native boot code sets up initial page tables immediately after
+ * the kernel itself, and sets init_pg_tables_end so they're not
+ * clobbered. The Launcher places our initial pagetables somewhere at
+ * the top of our physical memory, so we don't need extra space: set
+ * init_pg_tables_end to the end of the kernel. */
+ init_pg_tables_end = __pa(pg0);
+
+ /* Load the %fs segment register (the per-cpu segment register) with
+ * the normal data segment to get through booting. */
+ asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
+
+ /* Clear the part of the kernel data which is expected to be zero.
+ * Normally it will be anyway, but if we're loading from a bzImage with
+ * CONFIG_RELOCATALE=y, the relocations will be sitting here. */
+ memset(__bss_start, 0, __bss_stop - __bss_start);
+
+ /* The Host uses the top of the Guest's virtual address space for the
+ * Host<->Guest Switcher, and it tells us how much it needs in
+ * lguest_data.reserve_mem, set up on the LGUEST_INIT hypercall. */
+ reserve_top_address(lguest_data.reserve_mem);
+
+ /* If we don't initialize the lock dependency checker now, it crashes
+ * paravirt_disable_iospace. */
+ lockdep_init();
+
+ /* The IDE code spends about 3 seconds probing for disks: if we reserve
+ * all the I/O ports up front it can't get them and so doesn't probe.
+ * Other device drivers are similar (but less severe). This cuts the
+ * kernel boot time on my machine from 4.1 seconds to 0.45 seconds. */
+ paravirt_disable_iospace();
+
+ /* This is messy CPU setup stuff which the native boot code does before
+ * start_kernel, so we have to do, too: */
+ cpu_detect(&new_cpu_data);
+ /* head.S usually sets up the first capability word, so do it here. */
+ new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+ /* Math is always hard! */
+ new_cpu_data.hard_math = 1;
+
+#ifdef CONFIG_X86_MCE
+ mce_disabled = 1;
+#endif
+#ifdef CONFIG_ACPI
+ acpi_disabled = 1;
+ acpi_ht = 0;
+#endif
+
+ /* We set the perferred console to "hvc". This is the "hypervisor
+ * virtual console" driver written by the PowerPC people, which we also
+ * adapted for lguest's use. */
+ add_preferred_console("hvc", 0, NULL);
+
+ /* Last of all, we set the power management poweroff hook to point to
+ * the Guest routine to power off. */
+ pm_power_off = lguest_power_off;
+
+ /* Now we're set up, call start_kernel() in init/main.c and we proceed
+ * to boot as normal. It never returns. */
+ start_kernel();
+}
+/*
+ * This marks the end of stage II of our journey, The Guest.
+ *
+ * It is now time for us to explore the nooks and crannies of the three Guest
+ * devices and complete our understanding of the Guest in "make Drivers".
+ */
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
new file mode 100644
index 000000000000..1ddcd5cd20f6
--- /dev/null
+++ b/drivers/lguest/lguest_asm.S
@@ -0,0 +1,93 @@
+#include <linux/linkage.h>
+#include <linux/lguest.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/processor-flags.h>
+
+/*G:020 This is where we begin: we have a magic signature which the launcher
+ * looks for. The plan is that the Linux boot protocol will be extended with a
+ * "platform type" field which will guide us here from the normal entry point,
+ * but for the moment this suffices. The normal boot code uses %esi for the
+ * boot header, so we do too. We convert it to a virtual address by adding
+ * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax).
+ *
+ * The .section line puts this code in .init.text so it will be discarded after
+ * boot. */
+.section .init.text, "ax", @progbits
+.ascii "GenuineLguest"
+ /* Set up initial stack. */
+ movl $(init_thread_union+THREAD_SIZE),%esp
+ movl %esi, %eax
+ addl $__PAGE_OFFSET, %eax
+ jmp lguest_init
+
+/*G:055 We create a macro which puts the assembler code between lgstart_ and
+ * lgend_ markers. These templates are put in the .text section: they can't be
+ * discarded after boot as we may need to patch modules, too. */
+.text
+#define LGUEST_PATCH(name, insns...) \
+ lgstart_##name: insns; lgend_##name:; \
+ .globl lgstart_##name; .globl lgend_##name
+
+LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
+/*:*/
+
+/* These demark the EIP range where host should never deliver interrupts. */
+.global lguest_noirq_start
+.global lguest_noirq_end
+
+/*M:004 When the Host reflects a trap or injects an interrupt into the Guest,
+ * it sets the eflags interrupt bit on the stack based on
+ * lguest_data.irq_enabled, so the Guest iret logic does the right thing when
+ * restoring it. However, when the Host sets the Guest up for direct traps,
+ * such as system calls, the processor is the one to push eflags onto the
+ * stack, and the interrupt bit will be 1 (in reality, interrupts are always
+ * enabled in the Guest).
+ *
+ * This turns out to be harmless: the only trap which should happen under Linux
+ * with interrupts disabled is Page Fault (due to our lazy mapping of vmalloc
+ * regions), which has to be reflected through the Host anyway. If another
+ * trap *does* go off when interrupts are disabled, the Guest will panic, and
+ * we'll never get to this iret! :*/
+
+/*G:045 There is one final paravirt_op that the Guest implements, and glancing
+ * at it you can see why I left it to last. It's *cool*! It's in *assembler*!
+ *
+ * The "iret" instruction is used to return from an interrupt or trap. The
+ * stack looks like this:
+ * old address
+ * old code segment & privilege level
+ * old processor flags ("eflags")
+ *
+ * The "iret" instruction pops those values off the stack and restores them all
+ * at once. The only problem is that eflags includes the Interrupt Flag which
+ * the Guest can't change: the CPU will simply ignore it when we do an "iret".
+ * So we have to copy eflags from the stack to lguest_data.irq_enabled before
+ * we do the "iret".
+ *
+ * There are two problems with this: firstly, we need to use a register to do
+ * the copy and secondly, the whole thing needs to be atomic. The first
+ * problem is easy to solve: push %eax on the stack so we can use it, and then
+ * restore it at the end just before the real "iret".
+ *
+ * The second is harder: copying eflags to lguest_data.irq_enabled will turn
+ * interrupts on before we're finished, so we could be interrupted before we
+ * return to userspace or wherever. Our solution to this is to surround the
+ * code with lguest_noirq_start: and lguest_noirq_end: labels. We tell the
+ * Host that it is *never* to interrupt us there, even if interrupts seem to be
+ * enabled. */
+ENTRY(lguest_iret)
+ pushl %eax
+ movl 12(%esp), %eax
+lguest_noirq_start:
+ /* Note the %ss: segment prefix here. Normal data accesses use the
+ * "ds" segment, but that will have already been restored for whatever
+ * we're returning to (such as userspace): we can't trust it. The %ss:
+ * prefix makes sure we use the stack segment, which is still valid. */
+ movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
+ popl %eax
+ iret
+lguest_noirq_end:
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c
new file mode 100644
index 000000000000..9e7752cc8002
--- /dev/null
+++ b/drivers/lguest/lguest_bus.c
@@ -0,0 +1,218 @@
+/*P:050 Lguest guests use a very simple bus for devices. It's a simple array
+ * of device descriptors contained just above the top of normal memory. The
+ * lguest bus is 80% tedious boilerplate code. :*/
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lguest_bus.h>
+#include <asm/io.h>
+#include <asm/paravirt.h>
+
+static ssize_t type_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%hu", lguest_devices[dev->index].type);
+}
+static ssize_t features_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%hx", lguest_devices[dev->index].features);
+}
+static ssize_t pfn_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%u", lguest_devices[dev->index].pfn);
+}
+static ssize_t status_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%hx", lguest_devices[dev->index].status);
+}
+static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1)
+ return -EINVAL;
+ return count;
+}
+static struct device_attribute lguest_dev_attrs[] = {
+ __ATTR_RO(type),
+ __ATTR_RO(features),
+ __ATTR_RO(pfn),
+ __ATTR(status, 0644, status_show, status_store),
+ __ATTR_NULL
+};
+
+/*D:130 The generic bus infrastructure requires a function which says whether a
+ * device matches a driver. For us, it is simple: "struct lguest_driver"
+ * contains a "device_type" field which indicates what type of device it can
+ * handle, so we just cast the args and compare: */
+static int lguest_dev_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv);
+
+ return (drv->device_type == lguest_devices[dev->index].type);
+}
+/*:*/
+
+struct lguest_bus {
+ struct bus_type bus;
+ struct device dev;
+};
+
+static struct lguest_bus lguest_bus = {
+ .bus = {
+ .name = "lguest",
+ .match = lguest_dev_match,
+ .dev_attrs = lguest_dev_attrs,
+ },
+ .dev = {
+ .parent = NULL,
+ .bus_id = "lguest",
+ }
+};
+
+/*D:140 This is the callback which occurs once the bus infrastructure matches
+ * up a device and driver, ie. in response to add_lguest_device() calling
+ * device_register(), or register_lguest_driver() calling driver_register().
+ *
+ * At the moment it's always the latter: the devices are added first, since
+ * scan_devices() is called from a "core_initcall", and the drivers themselves
+ * called later as a normal "initcall". But it would work the other way too.
+ *
+ * So now we have the happy couple, we add the status bit to indicate that we
+ * found a driver. If the driver truly loves the device, it will return
+ * happiness from its probe function (ok, perhaps this wasn't my greatest
+ * analogy), and we set the final "driver ok" bit so the Host sees it's all
+ * green. */
+static int lguest_dev_probe(struct device *_dev)
+{
+ int ret;
+ struct lguest_device*dev = container_of(_dev,struct lguest_device,dev);
+ struct lguest_driver*drv = container_of(dev->dev.driver,
+ struct lguest_driver, drv);
+
+ lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER;
+ ret = drv->probe(dev);
+ if (ret == 0)
+ lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK;
+ return ret;
+}
+
+/* The last part of the bus infrastructure is the function lguest drivers use
+ * to register themselves. Firstly, we do nothing if there's no lguest bus
+ * (ie. this is not a Guest), otherwise we fill in the embedded generic "struct
+ * driver" fields and call the generic driver_register(). */
+int register_lguest_driver(struct lguest_driver *drv)
+{
+ if (!lguest_devices)
+ return 0;
+
+ drv->drv.bus = &lguest_bus.bus;
+ drv->drv.name = drv->name;
+ drv->drv.owner = drv->owner;
+ drv->drv.probe = lguest_dev_probe;
+
+ return driver_register(&drv->drv);
+}
+
+/* At the moment we build all the drivers into the kernel because they're so
+ * simple: 8144 bytes for all three of them as I type this. And as the console
+ * really needs to be built in, it's actually only 3527 bytes for the network
+ * and block drivers.
+ *
+ * If they get complex it will make sense for them to be modularized, so we
+ * need to explicitly export the symbol.
+ *
+ * I don't think non-GPL modules make sense, so it's a GPL-only export.
+ */
+EXPORT_SYMBOL_GPL(register_lguest_driver);
+
+/*D:120 This is the core of the lguest bus: actually adding a new device.
+ * It's a separate function because it's neater that way, and because an
+ * earlier version of the code supported hotplug and unplug. They were removed
+ * early on because they were never used.
+ *
+ * As Andrew Tridgell says, "Untested code is buggy code".
+ *
+ * It's worth reading this carefully: we start with an index into the array of
+ * "struct lguest_device_desc"s indicating the device which is new: */
+static void add_lguest_device(unsigned int index)
+{
+ struct lguest_device *new;
+
+ /* Each "struct lguest_device_desc" has a "status" field, which the
+ * Guest updates as the device is probed. In the worst case, the Host
+ * can look at these bits to tell what part of device setup failed,
+ * even if the console isn't available. */
+ lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE;
+ new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL);
+ if (!new) {
+ printk(KERN_EMERG "Cannot allocate lguest device %u\n", index);
+ lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+ return;
+ }
+
+ /* The "struct lguest_device" setup is pretty straight-forward example
+ * code. */
+ new->index = index;
+ new->private = NULL;
+ memset(&new->dev, 0, sizeof(new->dev));
+ new->dev.parent = &lguest_bus.dev;
+ new->dev.bus = &lguest_bus.bus;
+ sprintf(new->dev.bus_id, "%u", index);
+
+ /* device_register() causes the bus infrastructure to look for a
+ * matching driver. */
+ if (device_register(&new->dev) != 0) {
+ printk(KERN_EMERG "Cannot register lguest device %u\n", index);
+ lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+ kfree(new);
+ }
+}
+
+/*D:110 scan_devices() simply iterates through the device array. The type 0
+ * is reserved to mean "no device", and anything else means we have found a
+ * device: add it. */
+static void scan_devices(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < LGUEST_MAX_DEVICES; i++)
+ if (lguest_devices[i].type)
+ add_lguest_device(i);
+}
+
+/*D:100 Fairly early in boot, lguest_bus_init() is called to set up the lguest
+ * bus. We check that we are a Guest by checking paravirt_ops.name: there are
+ * other ways of checking, but this seems most obvious to me.
+ *
+ * So we can access the array of "struct lguest_device_desc"s easily, we map
+ * that memory and store the pointer in the global "lguest_devices". Then we
+ * register the bus with the core. Doing two registrations seems clunky to me,
+ * but it seems to be the correct sysfs incantation.
+ *
+ * Finally we call scan_devices() which adds all the devices found in the
+ * "struct lguest_device_desc" array. */
+static int __init lguest_bus_init(void)
+{
+ if (strcmp(paravirt_ops.name, "lguest") != 0)
+ return 0;
+
+ /* Devices are in a single page above top of "normal" mem */
+ lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
+
+ if (bus_register(&lguest_bus.bus) != 0
+ || device_register(&lguest_bus.dev) != 0)
+ panic("lguest bus registration failed");
+
+ scan_devices();
+ return 0;
+}
+/* Do this after core stuff, before devices. */
+postcore_initcall(lguest_bus_init);
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
new file mode 100644
index 000000000000..80d1b58c7698
--- /dev/null
+++ b/drivers/lguest/lguest_user.c
@@ -0,0 +1,382 @@
+/*P:200 This contains all the /dev/lguest code, whereby the userspace launcher
+ * controls and communicates with the Guest. For example, the first write will
+ * tell us the memory size, pagetable, entry point and kernel address offset.
+ * A read will run the Guest until a signal is pending (-EINTR), or the Guest
+ * does a DMA out to the Launcher. Writes are also used to get a DMA buffer
+ * registered by the Guest and to send the Guest an interrupt. :*/
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include "lg.h"
+
+/*L:030 setup_regs() doesn't really belong in this file, but it gives us an
+ * early glimpse deeper into the Host so it's worth having here.
+ *
+ * Most of the Guest's registers are left alone: we used get_zeroed_page() to
+ * allocate the structure, so they will be 0. */
+static void setup_regs(struct lguest_regs *regs, unsigned long start)
+{
+ /* There are four "segment" registers which the Guest needs to boot:
+ * The "code segment" register (cs) refers to the kernel code segment
+ * __KERNEL_CS, and the "data", "extra" and "stack" segment registers
+ * refer to the kernel data segment __KERNEL_DS.
+ *
+ * The privilege level is packed into the lower bits. The Guest runs
+ * at privilege level 1 (GUEST_PL).*/
+ regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
+ regs->cs = __KERNEL_CS|GUEST_PL;
+
+ /* The "eflags" register contains miscellaneous flags. Bit 1 (0x002)
+ * is supposed to always be "1". Bit 9 (0x200) controls whether
+ * interrupts are enabled. We always leave interrupts enabled while
+ * running the Guest. */
+ regs->eflags = 0x202;
+
+ /* The "Extended Instruction Pointer" register says where the Guest is
+ * running. */
+ regs->eip = start;
+
+ /* %esi points to our boot information, at physical address 0, so don't
+ * touch it. */
+}
+
+/*L:310 To send DMA into the Guest, the Launcher needs to be able to ask for a
+ * DMA buffer. This is done by writing LHREQ_GETDMA and the key to
+ * /dev/lguest. */
+static long user_get_dma(struct lguest *lg, const u32 __user *input)
+{
+ unsigned long key, udma, irq;
+
+ /* Fetch the key they wrote to us. */
+ if (get_user(key, input) != 0)
+ return -EFAULT;
+ /* Look for a free Guest DMA buffer bound to that key. */
+ udma = get_dma_buffer(lg, key, &irq);
+ if (!udma)
+ return -ENOENT;
+
+ /* We need to tell the Launcher what interrupt the Guest expects after
+ * the buffer is filled. We stash it in udma->used_len. */
+ lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
+
+ /* The (guest-physical) address of the DMA buffer is returned from
+ * the write(). */
+ return udma;
+}
+
+/*L:315 To force the Guest to stop running and return to the Launcher, the
+ * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
+ * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
+static int break_guest_out(struct lguest *lg, const u32 __user *input)
+{
+ unsigned long on;
+
+ /* Fetch whether they're turning break on or off.. */
+ if (get_user(on, input) != 0)
+ return -EFAULT;
+
+ if (on) {
+ lg->break_out = 1;
+ /* Pop it out (may be running on different CPU) */
+ wake_up_process(lg->tsk);
+ /* Wait for them to reset it */
+ return wait_event_interruptible(lg->break_wq, !lg->break_out);
+ } else {
+ lg->break_out = 0;
+ wake_up(&lg->break_wq);
+ return 0;
+ }
+}
+
+/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
+ * number to /dev/lguest. */
+static int user_send_irq(struct lguest *lg, const u32 __user *input)
+{
+ u32 irq;
+
+ if (get_user(irq, input) != 0)
+ return -EFAULT;
+ if (irq >= LGUEST_IRQS)
+ return -EINVAL;
+ /* Next time the Guest runs, the core code will see if it can deliver
+ * this interrupt. */
+ set_bit(irq, lg->irqs_pending);
+ return 0;
+}
+
+/*L:040 Once our Guest is initialized, the Launcher makes it run by reading
+ * from /dev/lguest. */
+static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
+{
+ struct lguest *lg = file->private_data;
+
+ /* You must write LHREQ_INITIALIZE first! */
+ if (!lg)
+ return -EINVAL;
+
+ /* If you're not the task which owns the guest, go away. */
+ if (current != lg->tsk)
+ return -EPERM;
+
+ /* If the guest is already dead, we indicate why */
+ if (lg->dead) {
+ size_t len;
+
+ /* lg->dead either contains an error code, or a string. */
+ if (IS_ERR(lg->dead))
+ return PTR_ERR(lg->dead);
+
+ /* We can only return as much as the buffer they read with. */
+ len = min(size, strlen(lg->dead)+1);
+ if (copy_to_user(user, lg->dead, len) != 0)
+ return -EFAULT;
+ return len;
+ }
+
+ /* If we returned from read() last time because the Guest sent DMA,
+ * clear the flag. */
+ if (lg->dma_is_pending)
+ lg->dma_is_pending = 0;
+
+ /* Run the Guest until something interesting happens. */
+ return run_guest(lg, (unsigned long __user *)user);
+}
+
+/*L:020 The initialization write supplies 4 32-bit values (in addition to the
+ * 32-bit LHREQ_INITIALIZE value). These are:
+ *
+ * pfnlimit: The highest (Guest-physical) page number the Guest should be
+ * allowed to access. The Launcher has to live in Guest memory, so it sets
+ * this to ensure the Guest can't reach it.
+ *
+ * pgdir: The (Guest-physical) address of the top of the initial Guest
+ * pagetables (which are set up by the Launcher).
+ *
+ * start: The first instruction to execute ("eip" in x86-speak).
+ *
+ * page_offset: The PAGE_OFFSET constant in the Guest kernel. We should
+ * probably wean the code off this, but it's a very useful constant! Any
+ * address above this is within the Guest kernel, and any kernel address can
+ * quickly converted from physical to virtual by adding PAGE_OFFSET. It's
+ * 0xC0000000 (3G) by default, but it's configurable at kernel build time.
+ */
+static int initialize(struct file *file, const u32 __user *input)
+{
+ /* "struct lguest" contains everything we (the Host) know about a
+ * Guest. */
+ struct lguest *lg;
+ int err, i;
+ u32 args[4];
+
+ /* We grab the Big Lguest lock, which protects the global array
+ * "lguests" and multiple simultaneous initializations. */
+ mutex_lock(&lguest_lock);
+ /* You can't initialize twice! Close the device and start again... */
+ if (file->private_data) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ if (copy_from_user(args, input, sizeof(args)) != 0) {
+ err = -EFAULT;
+ goto unlock;
+ }
+
+ /* Find an unused guest. */
+ i = find_free_guest();
+ if (i < 0) {
+ err = -ENOSPC;
+ goto unlock;
+ }
+ /* OK, we have an index into the "lguest" array: "lg" is a convenient
+ * pointer. */
+ lg = &lguests[i];
+
+ /* Populate the easy fields of our "struct lguest" */
+ lg->guestid = i;
+ lg->pfn_limit = args[0];
+ lg->page_offset = args[3];
+
+ /* We need a complete page for the Guest registers: they are accessible
+ * to the Guest and we can only grant it access to whole pages. */
+ lg->regs_page = get_zeroed_page(GFP_KERNEL);
+ if (!lg->regs_page) {
+ err = -ENOMEM;
+ goto release_guest;
+ }
+ /* We actually put the registers at the bottom of the page. */
+ lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs);
+
+ /* Initialize the Guest's shadow page tables, using the toplevel
+ * address the Launcher gave us. This allocates memory, so can
+ * fail. */
+ err = init_guest_pagetable(lg, args[1]);
+ if (err)
+ goto free_regs;
+
+ /* Now we initialize the Guest's registers, handing it the start
+ * address. */
+ setup_regs(lg->regs, args[2]);
+
+ /* There are a couple of GDT entries the Guest expects when first
+ * booting. */
+ setup_guest_gdt(lg);
+
+ /* The timer for lguest's clock needs initialization. */
+ init_clockdev(lg);
+
+ /* We keep a pointer to the Launcher task (ie. current task) for when
+ * other Guests want to wake this one (inter-Guest I/O). */
+ lg->tsk = current;
+ /* We need to keep a pointer to the Launcher's memory map, because if
+ * the Launcher dies we need to clean it up. If we don't keep a
+ * reference, it is destroyed before close() is called. */
+ lg->mm = get_task_mm(lg->tsk);
+
+ /* Initialize the queue for the waker to wait on */
+ init_waitqueue_head(&lg->break_wq);
+
+ /* We remember which CPU's pages this Guest used last, for optimization
+ * when the same Guest runs on the same CPU twice. */
+ lg->last_pages = NULL;
+
+ /* We keep our "struct lguest" in the file's private_data. */
+ file->private_data = lg;
+
+ mutex_unlock(&lguest_lock);
+
+ /* And because this is a write() call, we return the length used. */
+ return sizeof(args);
+
+free_regs:
+ free_page(lg->regs_page);
+release_guest:
+ memset(lg, 0, sizeof(*lg));
+unlock:
+ mutex_unlock(&lguest_lock);
+ return err;
+}
+
+/*L:010 The first operation the Launcher does must be a write. All writes
+ * start with a 32 bit number: for the first write this must be
+ * LHREQ_INITIALIZE to set up the Guest. After that the Launcher can use
+ * writes of other values to get DMA buffers and send interrupts. */
+static ssize_t write(struct file *file, const char __user *input,
+ size_t size, loff_t *off)
+{
+ /* Once the guest is initialized, we hold the "struct lguest" in the
+ * file private data. */
+ struct lguest *lg = file->private_data;
+ u32 req;
+
+ if (get_user(req, input) != 0)
+ return -EFAULT;
+ input += sizeof(req);
+
+ /* If you haven't initialized, you must do that first. */
+ if (req != LHREQ_INITIALIZE && !lg)
+ return -EINVAL;
+
+ /* Once the Guest is dead, all you can do is read() why it died. */
+ if (lg && lg->dead)
+ return -ENOENT;
+
+ /* If you're not the task which owns the Guest, you can only break */
+ if (lg && current != lg->tsk && req != LHREQ_BREAK)
+ return -EPERM;
+
+ switch (req) {
+ case LHREQ_INITIALIZE:
+ return initialize(file, (const u32 __user *)input);
+ case LHREQ_GETDMA:
+ return user_get_dma(lg, (const u32 __user *)input);
+ case LHREQ_IRQ:
+ return user_send_irq(lg, (const u32 __user *)input);
+ case LHREQ_BREAK:
+ return break_guest_out(lg, (const u32 __user *)input);
+ default:
+ return -EINVAL;
+ }
+}
+
+/*L:060 The final piece of interface code is the close() routine. It reverses
+ * everything done in initialize(). This is usually called because the
+ * Launcher exited.
+ *
+ * Note that the close routine returns 0 or a negative error number: it can't
+ * really fail, but it can whine. I blame Sun for this wart, and K&R C for
+ * letting them do it. :*/
+static int close(struct inode *inode, struct file *file)
+{
+ struct lguest *lg = file->private_data;
+
+ /* If we never successfully initialized, there's nothing to clean up */
+ if (!lg)
+ return 0;
+
+ /* We need the big lock, to protect from inter-guest I/O and other
+ * Launchers initializing guests. */
+ mutex_lock(&lguest_lock);
+ /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+ hrtimer_cancel(&lg->hrt);
+ /* Free any DMA buffers the Guest had bound. */
+ release_all_dma(lg);
+ /* Free up the shadow page tables for the Guest. */
+ free_guest_pagetable(lg);
+ /* Now all the memory cleanups are done, it's safe to release the
+ * Launcher's memory management structure. */
+ mmput(lg->mm);
+ /* If lg->dead doesn't contain an error code it will be NULL or a
+ * kmalloc()ed string, either of which is ok to hand to kfree(). */
+ if (!IS_ERR(lg->dead))
+ kfree(lg->dead);
+ /* We can free up the register page we allocated. */
+ free_page(lg->regs_page);
+ /* We clear the entire structure, which also marks it as free for the
+ * next user. */
+ memset(lg, 0, sizeof(*lg));
+ /* Release lock and exit. */
+ mutex_unlock(&lguest_lock);
+
+ return 0;
+}
+
+/*L:000
+ * Welcome to our journey through the Launcher!
+ *
+ * The Launcher is the Host userspace program which sets up, runs and services
+ * the Guest. In fact, many comments in the Drivers which refer to "the Host"
+ * doing things are inaccurate: the Launcher does all the device handling for
+ * the Guest. The Guest can't tell what's done by the the Launcher and what by
+ * the Host.
+ *
+ * Just to confuse you: to the Host kernel, the Launcher *is* the Guest and we
+ * shall see more of that later.
+ *
+ * We begin our understanding with the Host kernel interface which the Launcher
+ * uses: reading and writing a character device called /dev/lguest. All the
+ * work happens in the read(), write() and close() routines: */
+static struct file_operations lguest_fops = {
+ .owner = THIS_MODULE,
+ .release = close,
+ .write = write,
+ .read = read,
+};
+
+/* This is a textbook example of a "misc" character device. Populate a "struct
+ * miscdevice" and register it with misc_register(). */
+static struct miscdevice lguest_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lguest",
+ .fops = &lguest_fops,
+};
+
+int __init lguest_device_init(void)
+{
+ return misc_register(&lguest_dev);
+}
+
+void __exit lguest_device_remove(void)
+{
+ misc_deregister(&lguest_dev);
+}
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
new file mode 100644
index 000000000000..b7a924ace684
--- /dev/null
+++ b/drivers/lguest/page_tables.c
@@ -0,0 +1,680 @@
+/*P:700 The pagetable code, on the other hand, still shows the scars of
+ * previous encounters. It's functional, and as neat as it can be in the
+ * circumstances, but be wary, for these things are subtle and break easily.
+ * The Guest provides a virtual to physical mapping, but we can neither trust
+ * it nor use it: we verify and convert it here to point the hardware to the
+ * actual Guest pages when running the Guest. :*/
+
+/* Copyright (C) Rusty Russell IBM Corporation 2006.
+ * GPL v2 and any later version */
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/percpu.h>
+#include <asm/tlbflush.h>
+#include "lg.h"
+
+/*M:008 We hold reference to pages, which prevents them from being swapped.
+ * It'd be nice to have a callback in the "struct mm_struct" when Linux wants
+ * to swap out. If we had this, and a shrinker callback to trim PTE pages, we
+ * could probably consider launching Guests as non-root. :*/
+
+/*H:300
+ * The Page Table Code
+ *
+ * We use two-level page tables for the Guest. If you're not entirely
+ * comfortable with virtual addresses, physical addresses and page tables then
+ * I recommend you review lguest.c's "Page Table Handling" (with diagrams!).
+ *
+ * The Guest keeps page tables, but we maintain the actual ones here: these are
+ * called "shadow" page tables. Which is a very Guest-centric name: these are
+ * the real page tables the CPU uses, although we keep them up to date to
+ * reflect the Guest's. (See what I mean about weird naming? Since when do
+ * shadows reflect anything?)
+ *
+ * Anyway, this is the most complicated part of the Host code. There are seven
+ * parts to this:
+ * (i) Setting up a page table entry for the Guest when it faults,
+ * (ii) Setting up the page table entry for the Guest stack,
+ * (iii) Setting up a page table entry when the Guest tells us it has changed,
+ * (iv) Switching page tables,
+ * (v) Flushing (thowing away) page tables,
+ * (vi) Mapping the Switcher when the Guest is about to run,
+ * (vii) Setting up the page tables initially.
+ :*/
+
+/* Pages a 4k long, and each page table entry is 4 bytes long, giving us 1024
+ * (or 2^10) entries per page. */
+#define PTES_PER_PAGE_SHIFT 10
+#define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT)
+
+/* 1024 entries in a page table page maps 1024 pages: 4MB. The Switcher is
+ * conveniently placed at the top 4MB, so it uses a separate, complete PTE
+ * page. */
+#define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1)
+
+/* We actually need a separate PTE page for each CPU. Remember that after the
+ * Switcher code itself comes two pages for each CPU, and we don't want this
+ * CPU's guest to see the pages of any other CPU. */
+static DEFINE_PER_CPU(spte_t *, switcher_pte_pages);
+#define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
+
+/*H:320 With our shadow and Guest types established, we need to deal with
+ * them: the page table code is curly enough to need helper functions to keep
+ * it clear and clean.
+ *
+ * The first helper takes a virtual address, and says which entry in the top
+ * level page table deals with that address. Since each top level entry deals
+ * with 4M, this effectively divides by 4M. */
+static unsigned vaddr_to_pgd_index(unsigned long vaddr)
+{
+ return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+}
+
+/* There are two functions which return pointers to the shadow (aka "real")
+ * page tables.
+ *
+ * spgd_addr() takes the virtual address and returns a pointer to the top-level
+ * page directory entry for that address. Since we keep track of several page
+ * tables, the "i" argument tells us which one we're interested in (it's
+ * usually the current one). */
+static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+{
+ unsigned int index = vaddr_to_pgd_index(vaddr);
+
+ /* We kill any Guest trying to touch the Switcher addresses. */
+ if (index >= SWITCHER_PGD_INDEX) {
+ kill_guest(lg, "attempt to access switcher pages");
+ index = 0;
+ }
+ /* Return a pointer index'th pgd entry for the i'th page table. */
+ return &lg->pgdirs[i].pgdir[index];
+}
+
+/* This routine then takes the PGD entry given above, which contains the
+ * address of the PTE page. It then returns a pointer to the PTE entry for the
+ * given address. */
+static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr)
+{
+ spte_t *page = __va(spgd.pfn << PAGE_SHIFT);
+ /* You should never call this if the PGD entry wasn't valid */
+ BUG_ON(!(spgd.flags & _PAGE_PRESENT));
+ return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE];
+}
+
+/* These two functions just like the above two, except they access the Guest
+ * page tables. Hence they return a Guest address. */
+static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
+{
+ unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+ return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t);
+}
+
+static unsigned long gpte_addr(struct lguest *lg,
+ gpgd_t gpgd, unsigned long vaddr)
+{
+ unsigned long gpage = gpgd.pfn << PAGE_SHIFT;
+ BUG_ON(!(gpgd.flags & _PAGE_PRESENT));
+ return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t);
+}
+
+/*H:350 This routine takes a page number given by the Guest and converts it to
+ * an actual, physical page number. It can fail for several reasons: the
+ * virtual address might not be mapped by the Launcher, the write flag is set
+ * and the page is read-only, or the write flag was set and the page was
+ * shared so had to be copied, but we ran out of memory.
+ *
+ * This holds a reference to the page, so release_pte() is careful to
+ * put that back. */
+static unsigned long get_pfn(unsigned long virtpfn, int write)
+{
+ struct page *page;
+ /* This value indicates failure. */
+ unsigned long ret = -1UL;
+
+ /* get_user_pages() is a complex interface: it gets the "struct
+ * vm_area_struct" and "struct page" assocated with a range of pages.
+ * It also needs the task's mmap_sem held, and is not very quick.
+ * It returns the number of pages it got. */
+ down_read(&current->mm->mmap_sem);
+ if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT,
+ 1, write, 1, &page, NULL) == 1)
+ ret = page_to_pfn(page);
+ up_read(&current->mm->mmap_sem);
+ return ret;
+}
+
+/*H:340 Converting a Guest page table entry to a shadow (ie. real) page table
+ * entry can be a little tricky. The flags are (almost) the same, but the
+ * Guest PTE contains a virtual page number: the CPU needs the real page
+ * number. */
+static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write)
+{
+ spte_t spte;
+ unsigned long pfn;
+
+ /* The Guest sets the global flag, because it thinks that it is using
+ * PGE. We only told it to use PGE so it would tell us whether it was
+ * flushing a kernel mapping or a userspace mapping. We don't actually
+ * use the global bit, so throw it away. */
+ spte.flags = (gpte.flags & ~_PAGE_GLOBAL);
+
+ /* We need a temporary "unsigned long" variable to hold the answer from
+ * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't
+ * fit in spte.pfn. get_pfn() finds the real physical number of the
+ * page, given the virtual number. */
+ pfn = get_pfn(gpte.pfn, write);
+ if (pfn == -1UL) {
+ kill_guest(lg, "failed to get page %u", gpte.pfn);
+ /* When we destroy the Guest, we'll go through the shadow page
+ * tables and release_pte() them. Make sure we don't think
+ * this one is valid! */
+ spte.flags = 0;
+ }
+ /* Now we assign the page number, and our shadow PTE is complete. */
+ spte.pfn = pfn;
+ return spte;
+}
+
+/*H:460 And to complete the chain, release_pte() looks like this: */
+static void release_pte(spte_t pte)
+{
+ /* Remember that get_user_pages() took a reference to the page, in
+ * get_pfn()? We have to put it back now. */
+ if (pte.flags & _PAGE_PRESENT)
+ put_page(pfn_to_page(pte.pfn));
+}
+/*:*/
+
+static void check_gpte(struct lguest *lg, gpte_t gpte)
+{
+ if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit)
+ kill_guest(lg, "bad page table entry");
+}
+
+static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
+{
+ if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit)
+ kill_guest(lg, "bad page directory entry");
+}
+
+/*H:330
+ * (i) Setting up a page table entry for the Guest when it faults
+ *
+ * We saw this call in run_guest(): when we see a page fault in the Guest, we
+ * come here. That's because we only set up the shadow page tables lazily as
+ * they're needed, so we get page faults all the time and quietly fix them up
+ * and return to the Guest without it knowing.
+ *
+ * If we fixed up the fault (ie. we mapped the address), this routine returns
+ * true. */
+int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
+{
+ gpgd_t gpgd;
+ spgd_t *spgd;
+ unsigned long gpte_ptr;
+ gpte_t gpte;
+ spte_t *spte;
+
+ /* First step: get the top-level Guest page table entry. */
+ gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr)));
+ /* Toplevel not present? We can't map it in. */
+ if (!(gpgd.flags & _PAGE_PRESENT))
+ return 0;
+
+ /* Now look at the matching shadow entry. */
+ spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+ if (!(spgd->flags & _PAGE_PRESENT)) {
+ /* No shadow entry: allocate a new shadow PTE page. */
+ unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
+ /* This is not really the Guest's fault, but killing it is
+ * simple for this corner case. */
+ if (!ptepage) {
+ kill_guest(lg, "out of memory allocating pte page");
+ return 0;
+ }
+ /* We check that the Guest pgd is OK. */
+ check_gpgd(lg, gpgd);
+ /* And we copy the flags to the shadow PGD entry. The page
+ * number in the shadow PGD is the page we just allocated. */
+ spgd->raw.val = (__pa(ptepage) | gpgd.flags);
+ }
+
+ /* OK, now we look at the lower level in the Guest page table: keep its
+ * address, because we might update it later. */
+ gpte_ptr = gpte_addr(lg, gpgd, vaddr);
+ gpte = mkgpte(lgread_u32(lg, gpte_ptr));
+
+ /* If this page isn't in the Guest page tables, we can't page it in. */
+ if (!(gpte.flags & _PAGE_PRESENT))
+ return 0;
+
+ /* Check they're not trying to write to a page the Guest wants
+ * read-only (bit 2 of errcode == write). */
+ if ((errcode & 2) && !(gpte.flags & _PAGE_RW))
+ return 0;
+
+ /* User access to a kernel page? (bit 3 == user access) */
+ if ((errcode & 4) && !(gpte.flags & _PAGE_USER))
+ return 0;
+
+ /* Check that the Guest PTE flags are OK, and the page number is below
+ * the pfn_limit (ie. not mapping the Launcher binary). */
+ check_gpte(lg, gpte);
+ /* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */
+ gpte.flags |= _PAGE_ACCESSED;
+ if (errcode & 2)
+ gpte.flags |= _PAGE_DIRTY;
+
+ /* Get the pointer to the shadow PTE entry we're going to set. */
+ spte = spte_addr(lg, *spgd, vaddr);
+ /* If there was a valid shadow PTE entry here before, we release it.
+ * This can happen with a write to a previously read-only entry. */
+ release_pte(*spte);
+
+ /* If this is a write, we insist that the Guest page is writable (the
+ * final arg to gpte_to_spte()). */
+ if (gpte.flags & _PAGE_DIRTY)
+ *spte = gpte_to_spte(lg, gpte, 1);
+ else {
+ /* If this is a read, don't set the "writable" bit in the page
+ * table entry, even if the Guest says it's writable. That way
+ * we come back here when a write does actually ocur, so we can
+ * update the Guest's _PAGE_DIRTY flag. */
+ gpte_t ro_gpte = gpte;
+ ro_gpte.flags &= ~_PAGE_RW;
+ *spte = gpte_to_spte(lg, ro_gpte, 0);
+ }
+
+ /* Finally, we write the Guest PTE entry back: we've set the
+ * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
+ lgwrite_u32(lg, gpte_ptr, gpte.raw.val);
+
+ /* We succeeded in mapping the page! */
+ return 1;
+}
+
+/*H:360 (ii) Setting up the page table entry for the Guest stack.
+ *
+ * Remember pin_stack_pages() which makes sure the stack is mapped? It could
+ * simply call demand_page(), but as we've seen that logic is quite long, and
+ * usually the stack pages are already mapped anyway, so it's not required.
+ *
+ * This is a quick version which answers the question: is this virtual address
+ * mapped by the shadow page tables, and is it writable? */
+static int page_writable(struct lguest *lg, unsigned long vaddr)
+{
+ spgd_t *spgd;
+ unsigned long flags;
+
+ /* Look at the top level entry: is it present? */
+ spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+ if (!(spgd->flags & _PAGE_PRESENT))
+ return 0;
+
+ /* Check the flags on the pte entry itself: it must be present and
+ * writable. */
+ flags = spte_addr(lg, *spgd, vaddr)->flags;
+ return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
+}
+
+/* So, when pin_stack_pages() asks us to pin a page, we check if it's already
+ * in the page tables, and if not, we call demand_page() with error code 2
+ * (meaning "write"). */
+void pin_page(struct lguest *lg, unsigned long vaddr)
+{
+ if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2))
+ kill_guest(lg, "bad stack page %#lx", vaddr);
+}
+
+/*H:450 If we chase down the release_pgd() code, it looks like this: */
+static void release_pgd(struct lguest *lg, spgd_t *spgd)
+{
+ /* If the entry's not present, there's nothing to release. */
+ if (spgd->flags & _PAGE_PRESENT) {
+ unsigned int i;
+ /* Converting the pfn to find the actual PTE page is easy: turn
+ * the page number into a physical address, then convert to a
+ * virtual address (easy for kernel pages like this one). */
+ spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT);
+ /* For each entry in the page, we might need to release it. */
+ for (i = 0; i < PTES_PER_PAGE; i++)
+ release_pte(ptepage[i]);
+ /* Now we can free the page of PTEs */
+ free_page((long)ptepage);
+ /* And zero out the PGD entry we we never release it twice. */
+ spgd->raw.val = 0;
+ }
+}
+
+/*H:440 (v) Flushing (thowing away) page tables,
+ *
+ * We saw flush_user_mappings() called when we re-used a top-level pgdir page.
+ * It simply releases every PTE page from 0 up to the kernel address. */
+static void flush_user_mappings(struct lguest *lg, int idx)
+{
+ unsigned int i;
+ /* Release every pgd entry up to the kernel's address. */
+ for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++)
+ release_pgd(lg, lg->pgdirs[idx].pgdir + i);
+}
+
+/* The Guest also has a hypercall to do this manually: it's used when a large
+ * number of mappings have been changed. */
+void guest_pagetable_flush_user(struct lguest *lg)
+{
+ /* Drop the userspace part of the current page table. */
+ flush_user_mappings(lg, lg->pgdidx);
+}
+/*:*/
+
+/* We keep several page tables. This is a simple routine to find the page
+ * table (if any) corresponding to this top-level address the Guest has given
+ * us. */
+static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ if (lg->pgdirs[i].cr3 == pgtable)
+ break;
+ return i;
+}
+
+/*H:435 And this is us, creating the new page directory. If we really do
+ * allocate a new one (and so the kernel parts are not there), we set
+ * blank_pgdir. */
+static unsigned int new_pgdir(struct lguest *lg,
+ unsigned long cr3,
+ int *blank_pgdir)
+{
+ unsigned int next;
+
+ /* We pick one entry at random to throw out. Choosing the Least
+ * Recently Used might be better, but this is easy. */
+ next = random32() % ARRAY_SIZE(lg->pgdirs);
+ /* If it's never been allocated at all before, try now. */
+ if (!lg->pgdirs[next].pgdir) {
+ lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL);
+ /* If the allocation fails, just keep using the one we have */
+ if (!lg->pgdirs[next].pgdir)
+ next = lg->pgdidx;
+ else
+ /* This is a blank page, so there are no kernel
+ * mappings: caller must map the stack! */
+ *blank_pgdir = 1;
+ }
+ /* Record which Guest toplevel this shadows. */
+ lg->pgdirs[next].cr3 = cr3;
+ /* Release all the non-kernel mappings. */
+ flush_user_mappings(lg, next);
+
+ return next;
+}
+
+/*H:430 (iv) Switching page tables
+ *
+ * This is what happens when the Guest changes page tables (ie. changes the
+ * top-level pgdir). This happens on almost every context switch. */
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+ int newpgdir, repin = 0;
+
+ /* Look to see if we have this one already. */
+ newpgdir = find_pgdir(lg, pgtable);
+ /* If not, we allocate or mug an existing one: if it's a fresh one,
+ * repin gets set to 1. */
+ if (newpgdir == ARRAY_SIZE(lg->pgdirs))
+ newpgdir = new_pgdir(lg, pgtable, &repin);
+ /* Change the current pgd index to the new one. */
+ lg->pgdidx = newpgdir;
+ /* If it was completely blank, we map in the Guest kernel stack */
+ if (repin)
+ pin_stack_pages(lg);
+}
+
+/*H:470 Finally, a routine which throws away everything: all PGD entries in all
+ * the shadow page tables. This is used when we destroy the Guest. */
+static void release_all_pagetables(struct lguest *lg)
+{
+ unsigned int i, j;
+
+ /* Every shadow pagetable this Guest has */
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ if (lg->pgdirs[i].pgdir)
+ /* Every PGD entry except the Switcher at the top */
+ for (j = 0; j < SWITCHER_PGD_INDEX; j++)
+ release_pgd(lg, lg->pgdirs[i].pgdir + j);
+}
+
+/* We also throw away everything when a Guest tells us it's changed a kernel
+ * mapping. Since kernel mappings are in every page table, it's easiest to
+ * throw them all away. This is amazingly slow, but thankfully rare. */
+void guest_pagetable_clear_all(struct lguest *lg)
+{
+ release_all_pagetables(lg);
+ /* We need the Guest kernel stack mapped again. */
+ pin_stack_pages(lg);
+}
+
+/*H:420 This is the routine which actually sets the page table entry for then
+ * "idx"'th shadow page table.
+ *
+ * Normally, we can just throw out the old entry and replace it with 0: if they
+ * use it demand_page() will put the new entry in. We need to do this anyway:
+ * The Guest expects _PAGE_ACCESSED to be set on its PTE the first time a page
+ * is read from, and _PAGE_DIRTY when it's written to.
+ *
+ * But Avi Kivity pointed out that most Operating Systems (Linux included) set
+ * these bits on PTEs immediately anyway. This is done to save the CPU from
+ * having to update them, but it helps us the same way: if they set
+ * _PAGE_ACCESSED then we can put a read-only PTE entry in immediately, and if
+ * they set _PAGE_DIRTY then we can put a writable PTE entry in immediately.
+ */
+static void do_set_pte(struct lguest *lg, int idx,
+ unsigned long vaddr, gpte_t gpte)
+{
+ /* Look up the matching shadow page directot entry. */
+ spgd_t *spgd = spgd_addr(lg, idx, vaddr);
+
+ /* If the top level isn't present, there's no entry to update. */
+ if (spgd->flags & _PAGE_PRESENT) {
+ /* Otherwise, we start by releasing the existing entry. */
+ spte_t *spte = spte_addr(lg, *spgd, vaddr);
+ release_pte(*spte);
+
+ /* If they're setting this entry as dirty or accessed, we might
+ * as well put that entry they've given us in now. This shaves
+ * 10% off a copy-on-write micro-benchmark. */
+ if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+ check_gpte(lg, gpte);
+ *spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY);
+ } else
+ /* Otherwise we can demand_page() it in later. */
+ spte->raw.val = 0;
+ }
+}
+
+/*H:410 Updating a PTE entry is a little trickier.
+ *
+ * We keep track of several different page tables (the Guest uses one for each
+ * process, so it makes sense to cache at least a few). Each of these have
+ * identical kernel parts: ie. every mapping above PAGE_OFFSET is the same for
+ * all processes. So when the page table above that address changes, we update
+ * all the page tables, not just the current one. This is rare.
+ *
+ * The benefit is that when we have to track a new page table, we can copy keep
+ * all the kernel mappings. This speeds up context switch immensely. */
+void guest_set_pte(struct lguest *lg,
+ unsigned long cr3, unsigned long vaddr, gpte_t gpte)
+{
+ /* Kernel mappings must be changed on all top levels. Slow, but
+ * doesn't happen often. */
+ if (vaddr >= lg->page_offset) {
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ if (lg->pgdirs[i].pgdir)
+ do_set_pte(lg, i, vaddr, gpte);
+ } else {
+ /* Is this page table one we have a shadow for? */
+ int pgdir = find_pgdir(lg, cr3);
+ if (pgdir != ARRAY_SIZE(lg->pgdirs))
+ /* If so, do the update. */
+ do_set_pte(lg, pgdir, vaddr, gpte);
+ }
+}
+
+/*H:400
+ * (iii) Setting up a page table entry when the Guest tells us it has changed.
+ *
+ * Just like we did in interrupts_and_traps.c, it makes sense for us to deal
+ * with the other side of page tables while we're here: what happens when the
+ * Guest asks for a page table to be updated?
+ *
+ * We already saw that demand_page() will fill in the shadow page tables when
+ * needed, so we can simply remove shadow page table entries whenever the Guest
+ * tells us they've changed. When the Guest tries to use the new entry it will
+ * fault and demand_page() will fix it up.
+ *
+ * So with that in mind here's our code to to update a (top-level) PGD entry:
+ */
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
+{
+ int pgdir;
+
+ /* The kernel seems to try to initialize this early on: we ignore its
+ * attempts to map over the Switcher. */
+ if (idx >= SWITCHER_PGD_INDEX)
+ return;
+
+ /* If they're talking about a page table we have a shadow for... */
+ pgdir = find_pgdir(lg, cr3);
+ if (pgdir < ARRAY_SIZE(lg->pgdirs))
+ /* ... throw it away. */
+ release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
+}
+
+/*H:500 (vii) Setting up the page tables initially.
+ *
+ * When a Guest is first created, the Launcher tells us where the toplevel of
+ * its first page table is. We set some things up here: */
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+ /* In flush_user_mappings() we loop from 0 to
+ * "vaddr_to_pgd_index(lg->page_offset)". This assumes it won't hit
+ * the Switcher mappings, so check that now. */
+ if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
+ return -EINVAL;
+ /* We start on the first shadow page table, and give it a blank PGD
+ * page. */
+ lg->pgdidx = 0;
+ lg->pgdirs[lg->pgdidx].cr3 = pgtable;
+ lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
+ if (!lg->pgdirs[lg->pgdidx].pgdir)
+ return -ENOMEM;
+ return 0;
+}
+
+/* When a Guest dies, our cleanup is fairly simple. */
+void free_guest_pagetable(struct lguest *lg)
+{
+ unsigned int i;
+
+ /* Throw away all page table pages. */
+ release_all_pagetables(lg);
+ /* Now free the top levels: free_page() can handle 0 just fine. */
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ free_page((long)lg->pgdirs[i].pgdir);
+}
+
+/*H:480 (vi) Mapping the Switcher when the Guest is about to run.
+ *
+ * The Switcher and the two pages for this CPU need to be available to the
+ * Guest (and not the pages for other CPUs). We have the appropriate PTE pages
+ * for each CPU already set up, we just need to hook them in. */
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
+{
+ spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+ spgd_t switcher_pgd;
+ spte_t regs_pte;
+
+ /* Make the last PGD entry for this Guest point to the Switcher's PTE
+ * page for this CPU (with appropriate flags). */
+ switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT;
+ switcher_pgd.flags = _PAGE_KERNEL;
+ lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
+
+ /* We also change the Switcher PTE page. When we're running the Guest,
+ * we want the Guest's "regs" page to appear where the first Switcher
+ * page for this CPU is. This is an optimization: when the Switcher
+ * saves the Guest registers, it saves them into the first page of this
+ * CPU's "struct lguest_pages": if we make sure the Guest's register
+ * page is already mapped there, we don't have to copy them out
+ * again. */
+ regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT;
+ regs_pte.flags = _PAGE_KERNEL;
+ switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE]
+ = regs_pte;
+}
+/*:*/
+
+static void free_switcher_pte_pages(void)
+{
+ unsigned int i;
+
+ for_each_possible_cpu(i)
+ free_page((long)switcher_pte_page(i));
+}
+
+/*H:520 Setting up the Switcher PTE page for given CPU is fairly easy, given
+ * the CPU number and the "struct page"s for the Switcher code itself.
+ *
+ * Currently the Switcher is less than a page long, so "pages" is always 1. */
+static __init void populate_switcher_pte_page(unsigned int cpu,
+ struct page *switcher_page[],
+ unsigned int pages)
+{
+ unsigned int i;
+ spte_t *pte = switcher_pte_page(cpu);
+
+ /* The first entries are easy: they map the Switcher code. */
+ for (i = 0; i < pages; i++) {
+ pte[i].pfn = page_to_pfn(switcher_page[i]);
+ pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+ }
+
+ /* The only other thing we map is this CPU's pair of pages. */
+ i = pages + cpu*2;
+
+ /* First page (Guest registers) is writable from the Guest */
+ pte[i].pfn = page_to_pfn(switcher_page[i]);
+ pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW;
+ /* The second page contains the "struct lguest_ro_state", and is
+ * read-only. */
+ pte[i+1].pfn = page_to_pfn(switcher_page[i+1]);
+ pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+}
+
+/*H:510 At boot or module load time, init_pagetables() allocates and populates
+ * the Switcher PTE page for each CPU. */
+__init int init_pagetables(struct page **switcher_page, unsigned int pages)
+{
+ unsigned int i;
+
+ for_each_possible_cpu(i) {
+ switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL);
+ if (!switcher_pte_page(i)) {
+ free_switcher_pte_pages();
+ return -ENOMEM;
+ }
+ populate_switcher_pte_page(i, switcher_page, pages);
+ }
+ return 0;
+}
+/*:*/
+
+/* Cleaning up simply involves freeing the PTE page for each CPU. */
+void free_pagetables(void)
+{
+ free_switcher_pte_pages();
+}
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
new file mode 100644
index 000000000000..9b81119f46e9
--- /dev/null
+++ b/drivers/lguest/segments.c
@@ -0,0 +1,177 @@
+/*P:600 The x86 architecture has segments, which involve a table of descriptors
+ * which can be used to do funky things with virtual address interpretation.
+ * We originally used to use segments so the Guest couldn't alter the
+ * Guest<->Host Switcher, and then we had to trim Guest segments, and restore
+ * for userspace per-thread segments, but trim again for on userspace->kernel
+ * transitions... This nightmarish creation was contained within this file,
+ * where we knew not to tread without heavy armament and a change of underwear.
+ *
+ * In these modern times, the segment handling code consists of simple sanity
+ * checks, and the worst you'll experience reading this code is butterfly-rash
+ * from frolicking through its parklike serenity. :*/
+#include "lg.h"
+
+/*H:600
+ * We've almost completed the Host; there's just one file to go!
+ *
+ * Segments & The Global Descriptor Table
+ *
+ * (That title sounds like a bad Nerdcore group. Not to suggest that there are
+ * any good Nerdcore groups, but in high school a friend of mine had a band
+ * called Joe Fish and the Chips, so there are definitely worse band names).
+ *
+ * To refresh: the GDT is a table of 8-byte values describing segments. Once
+ * set up, these segments can be loaded into one of the 6 "segment registers".
+ *
+ * GDT entries are passed around as "struct desc_struct"s, which like IDT
+ * entries are split into two 32-bit members, "a" and "b". One day, someone
+ * will clean that up, and be declared a Hero. (No pressure, I'm just saying).
+ *
+ * Anyway, the GDT entry contains a base (the start address of the segment), a
+ * limit (the size of the segment - 1), and some flags. Sounds simple, and it
+ * would be, except those zany Intel engineers decided that it was too boring
+ * to put the base at one end, the limit at the other, and the flags in
+ * between. They decided to shotgun the bits at random throughout the 8 bytes,
+ * like so:
+ *
+ * 0 16 40 48 52 56 63
+ * [ limit part 1 ][ base part 1 ][ flags ][li][fl][base ]
+ * mit ags part 2
+ * part 2
+ *
+ * As a result, this file contains a certain amount of magic numeracy. Let's
+ * begin.
+ */
+
+/* There are several entries we don't let the Guest set. The TSS entry is the
+ * "Task State Segment" which controls all kinds of delicate things. The
+ * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the
+ * the Guest can't be trusted to deal with double faults. */
+static int ignored_gdt(unsigned int num)
+{
+ return (num == GDT_ENTRY_TSS
+ || num == GDT_ENTRY_LGUEST_CS
+ || num == GDT_ENTRY_LGUEST_DS
+ || num == GDT_ENTRY_DOUBLEFAULT_TSS);
+}
+
+/*H:610 Once the GDT has been changed, we fix the new entries up a little. We
+ * don't care if they're invalid: the worst that can happen is a General
+ * Protection Fault in the Switcher when it restores a Guest segment register
+ * which tries to use that entry. Then we kill the Guest for causing such a
+ * mess: the message will be "unhandled trap 256". */
+static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
+{
+ unsigned int i;
+
+ for (i = start; i < end; i++) {
+ /* We never copy these ones to real GDT, so we don't care what
+ * they say */
+ if (ignored_gdt(i))
+ continue;
+
+ /* Segment descriptors contain a privilege level: the Guest is
+ * sometimes careless and leaves this as 0, even though it's
+ * running at privilege level 1. If so, we fix it here. */
+ if ((lg->gdt[i].b & 0x00006000) == 0)
+ lg->gdt[i].b |= (GUEST_PL << 13);
+
+ /* Each descriptor has an "accessed" bit. If we don't set it
+ * now, the CPU will try to set it when the Guest first loads
+ * that entry into a segment register. But the GDT isn't
+ * writable by the Guest, so bad things can happen. */
+ lg->gdt[i].b |= 0x00000100;
+ }
+}
+
+/* This routine is called at boot or modprobe time for each CPU to set up the
+ * "constant" GDT entries for Guests running on that CPU. */
+void setup_default_gdt_entries(struct lguest_ro_state *state)
+{
+ struct desc_struct *gdt = state->guest_gdt;
+ unsigned long tss = (unsigned long)&state->guest_tss;
+
+ /* The hypervisor segments are full 0-4G segments, privilege level 0 */
+ gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+ gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+
+ /* The TSS segment refers to the TSS entry for this CPU, so we cannot
+ * copy it from the Guest. Forgive the magic flags */
+ gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
+ gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
+ | ((tss >> 16) & 0x000000FF);
+}
+
+/* This routine is called before the Guest is run for the first time. */
+void setup_guest_gdt(struct lguest *lg)
+{
+ /* Start with full 0-4G segments... */
+ lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+ lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+ /* ...except the Guest is allowed to use them, so set the privilege
+ * level appropriately in the flags. */
+ lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+ lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+}
+
+/* Like the IDT, we never simply use the GDT the Guest gives us. We set up the
+ * GDTs for each CPU, then we copy across the entries each time we want to run
+ * a different Guest on that CPU. */
+
+/* A partial GDT load, for the three "thead-local storage" entries. Otherwise
+ * it's just like load_guest_gdt(). So much, in fact, it would probably be
+ * neater to have a single hypercall to cover both. */
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
+{
+ unsigned int i;
+
+ for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
+ gdt[i] = lg->gdt[i];
+}
+
+/* This is the full version */
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
+{
+ unsigned int i;
+
+ /* The default entries from setup_default_gdt_entries() are not
+ * replaced. See ignored_gdt() above. */
+ for (i = 0; i < GDT_ENTRIES; i++)
+ if (!ignored_gdt(i))
+ gdt[i] = lg->gdt[i];
+}
+
+/* This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). */
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
+{
+ /* We assume the Guest has the same number of GDT entries as the
+ * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
+ if (num > ARRAY_SIZE(lg->gdt))
+ kill_guest(lg, "too many gdt entries %i", num);
+
+ /* We read the whole thing in, then fix it up. */
+ lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
+ fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
+ /* Mark that the GDT changed so the core knows it has to copy it again,
+ * even if the Guest is run on the same CPU. */
+ lg->changed |= CHANGED_GDT;
+}
+
+void guest_load_tls(struct lguest *lg, unsigned long gtls)
+{
+ struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
+
+ lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+ fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+ lg->changed |= CHANGED_GDT_TLS;
+}
+
+/*
+ * With this, we have finished the Host.
+ *
+ * Five of the seven parts of our task are complete. You have made it through
+ * the Bit of Despair (I think that's somewhere in the page table code,
+ * myself).
+ *
+ * Next, we examine "make Switcher". It's short, but intense.
+ */
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/switcher.S
new file mode 100644
index 000000000000..7c9c230cc845
--- /dev/null
+++ b/drivers/lguest/switcher.S
@@ -0,0 +1,350 @@
+/*P:900 This is the Switcher: code which sits at 0xFFC00000 to do the low-level
+ * Guest<->Host switch. It is as simple as it can be made, but it's naturally
+ * very specific to x86.
+ *
+ * You have now completed Preparation. If this has whet your appetite; if you
+ * are feeling invigorated and refreshed then the next, more challenging stage
+ * can be found in "make Guest". :*/
+
+/*S:100
+ * Welcome to the Switcher itself!
+ *
+ * This file contains the low-level code which changes the CPU to run the Guest
+ * code, and returns to the Host when something happens. Understand this, and
+ * you understand the heart of our journey.
+ *
+ * Because this is in assembler rather than C, our tale switches from prose to
+ * verse. First I tried limericks:
+ *
+ * There once was an eax reg,
+ * To which our pointer was fed,
+ * It needed an add,
+ * Which asm-offsets.h had
+ * But this limerick is hurting my head.
+ *
+ * Next I tried haikus, but fitting the required reference to the seasons in
+ * every stanza was quickly becoming tiresome:
+ *
+ * The %eax reg
+ * Holds "struct lguest_pages" now:
+ * Cherry blossoms fall.
+ *
+ * Then I started with Heroic Verse, but the rhyming requirement leeched away
+ * the content density and led to some uniquely awful oblique rhymes:
+ *
+ * These constants are coming from struct offsets
+ * For use within the asm switcher text.
+ *
+ * Finally, I settled for something between heroic hexameter, and normal prose
+ * with inappropriate linebreaks. Anyway, it aint no Shakespeare.
+ */
+
+// Not all kernel headers work from assembler
+// But these ones are needed: the ENTRY() define
+// And constants extracted from struct offsets
+// To avoid magic numbers and breakage:
+// Should they change the compiler can't save us
+// Down here in the depths of assembler code.
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include "lg.h"
+
+// We mark the start of the code to copy
+// It's placed in .text tho it's never run here
+// You'll see the trick macro at the end
+// Which interleaves data and text to effect.
+.text
+ENTRY(start_switcher_text)
+
+// When we reach switch_to_guest we have just left
+// The safe and comforting shores of C code
+// %eax has the "struct lguest_pages" to use
+// Where we save state and still see it from the Guest
+// And %ebx holds the Guest shadow pagetable:
+// Once set we have truly left Host behind.
+ENTRY(switch_to_guest)
+ // We told gcc all its regs could fade,
+ // Clobbered by our journey into the Guest
+ // We could have saved them, if we tried
+ // But time is our master and cycles count.
+
+ // Segment registers must be saved for the Host
+ // We push them on the Host stack for later
+ pushl %es
+ pushl %ds
+ pushl %gs
+ pushl %fs
+ // But the compiler is fickle, and heeds
+ // No warning of %ebp clobbers
+ // When frame pointers are used. That register
+ // Must be saved and restored or chaos strikes.
+ pushl %ebp
+ // The Host's stack is done, now save it away
+ // In our "struct lguest_pages" at offset
+ // Distilled into asm-offsets.h
+ movl %esp, LGUEST_PAGES_host_sp(%eax)
+
+ // All saved and there's now five steps before us:
+ // Stack, GDT, IDT, TSS
+ // And last of all the page tables are flipped.
+
+ // Yet beware that our stack pointer must be
+ // Always valid lest an NMI hits
+ // %edx does the duty here as we juggle
+ // %eax is lguest_pages: our stack lies within.
+ movl %eax, %edx
+ addl $LGUEST_PAGES_regs, %edx
+ movl %edx, %esp
+
+ // The Guest's GDT we so carefully
+ // Placed in the "struct lguest_pages" before
+ lgdt LGUEST_PAGES_guest_gdt_desc(%eax)
+
+ // The Guest's IDT we did partially
+ // Move to the "struct lguest_pages" as well.
+ lidt LGUEST_PAGES_guest_idt_desc(%eax)
+
+ // The TSS entry which controls traps
+ // Must be loaded up with "ltr" now:
+ // For after we switch over our page tables
+ // It (as the rest) will be writable no more.
+ // (The GDT entry TSS needs
+ // Changes type when we load it: damn Intel!)
+ movl $(GDT_ENTRY_TSS*8), %edx
+ ltr %dx
+
+ // Look back now, before we take this last step!
+ // The Host's TSS entry was also marked used;
+ // Let's clear it again, ere we return.
+ // The GDT descriptor of the Host
+ // Points to the table after two "size" bytes
+ movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
+ // Clear the type field of "used" (byte 5, bit 2)
+ andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
+
+ // Once our page table's switched, the Guest is live!
+ // The Host fades as we run this final step.
+ // Our "struct lguest_pages" is now read-only.
+ movl %ebx, %cr3
+
+ // The page table change did one tricky thing:
+ // The Guest's register page has been mapped
+ // Writable onto our %esp (stack) --
+ // We can simply pop off all Guest regs.
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %gs
+ popl %eax
+ popl %fs
+ popl %ds
+ popl %es
+
+ // Near the base of the stack lurk two strange fields
+ // Which we fill as we exit the Guest
+ // These are the trap number and its error
+ // We can simply step past them on our way.
+ addl $8, %esp
+
+ // The last five stack slots hold return address
+ // And everything needed to change privilege
+ // Into the Guest privilege level of 1,
+ // And the stack where the Guest had last left it.
+ // Interrupts are turned back on: we are Guest.
+ iret
+
+// There are two paths where we switch to the Host
+// So we put the routine in a macro.
+// We are on our way home, back to the Host
+// Interrupted out of the Guest, we come here.
+#define SWITCH_TO_HOST \
+ /* We save the Guest state: all registers first \
+ * Laid out just as "struct lguest_regs" defines */ \
+ pushl %es; \
+ pushl %ds; \
+ pushl %fs; \
+ pushl %eax; \
+ pushl %gs; \
+ pushl %ebp; \
+ pushl %edi; \
+ pushl %esi; \
+ pushl %edx; \
+ pushl %ecx; \
+ pushl %ebx; \
+ /* Our stack and our code are using segments \
+ * Set in the TSS and IDT \
+ * Yet if we were to touch data we'd use \
+ * Whatever data segment the Guest had. \
+ * Load the lguest ds segment for now. */ \
+ movl $(LGUEST_DS), %eax; \
+ movl %eax, %ds; \
+ /* So where are we? Which CPU, which struct? \
+ * The stack is our clue: our TSS starts \
+ * It at the end of "struct lguest_pages". \
+ * Or we may have stumbled while restoring \
+ * Our Guest segment regs while in switch_to_guest, \
+ * The fault pushed atop that part-unwound stack. \
+ * If we round the stack down to the page start \
+ * We're at the start of "struct lguest_pages". */ \
+ movl %esp, %eax; \
+ andl $(~(1 << PAGE_SHIFT - 1)), %eax; \
+ /* Save our trap number: the switch will obscure it \
+ * (The Guest regs are not mapped here in the Host) \
+ * %ebx holds it safe for deliver_to_host */ \
+ movl LGUEST_PAGES_regs_trapnum(%eax), %ebx; \
+ /* The Host GDT, IDT and stack! \
+ * All these lie safely hidden from the Guest: \
+ * We must return to the Host page tables \
+ * (Hence that was saved in struct lguest_pages) */ \
+ movl LGUEST_PAGES_host_cr3(%eax), %edx; \
+ movl %edx, %cr3; \
+ /* As before, when we looked back at the Host \
+ * As we left and marked TSS unused \
+ * So must we now for the Guest left behind. */ \
+ andb $0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \
+ /* Switch to Host's GDT, IDT. */ \
+ lgdt LGUEST_PAGES_host_gdt_desc(%eax); \
+ lidt LGUEST_PAGES_host_idt_desc(%eax); \
+ /* Restore the Host's stack where it's saved regs lie */ \
+ movl LGUEST_PAGES_host_sp(%eax), %esp; \
+ /* Last the TSS: our Host is complete */ \
+ movl $(GDT_ENTRY_TSS*8), %edx; \
+ ltr %dx; \
+ /* Restore now the regs saved right at the first. */ \
+ popl %ebp; \
+ popl %fs; \
+ popl %gs; \
+ popl %ds; \
+ popl %es
+
+// Here's where we come when the Guest has just trapped:
+// (Which trap we'll see has been pushed on the stack).
+// We need only switch back, and the Host will decode
+// Why we came home, and what needs to be done.
+return_to_host:
+ SWITCH_TO_HOST
+ iret
+
+// An interrupt, with some cause external
+// Has ajerked us rudely from the Guest's code
+// Again we must return home to the Host
+deliver_to_host:
+ SWITCH_TO_HOST
+ // But now we must go home via that place
+ // Where that interrupt was supposed to go
+ // Had we not been ensconced, running the Guest.
+ // Here we see the cleverness of our stack:
+ // The Host stack is formed like an interrupt
+ // With EIP, CS and EFLAGS layered.
+ // Interrupt handlers end with "iret"
+ // And that will take us home at long long last.
+
+ // But first we must find the handler to call!
+ // The IDT descriptor for the Host
+ // Has two bytes for size, and four for address:
+ // %edx will hold it for us for now.
+ movl (LGUEST_PAGES_host_idt_desc+2)(%eax), %edx
+ // We now know the table address we need,
+ // And saved the trap's number inside %ebx.
+ // Yet the pointer to the handler is smeared
+ // Across the bits of the table entry.
+ // What oracle can tell us how to extract
+ // From such a convoluted encoding?
+ // I consulted gcc, and it gave
+ // These instructions, which I gladly credit:
+ leal (%edx,%ebx,8), %eax
+ movzwl (%eax),%edx
+ movl 4(%eax), %eax
+ xorw %ax, %ax
+ orl %eax, %edx
+ // Now the address of the handler's in %edx
+ // We call it now: its "iret" takes us home.
+ jmp *%edx
+
+// Every interrupt can come to us here
+// But we must truly tell each apart.
+// They number two hundred and fifty six
+// And each must land in a different spot,
+// Push its number on stack, and join the stream.
+
+// And worse, a mere six of the traps stand apart
+// And push on their stack an addition:
+// An error number, thirty two bits long
+// So we punish the other two fifty
+// And make them push a zero so they match.
+
+// Yet two fifty six entries is long
+// And all will look most the same as the last
+// So we create a macro which can make
+// As many entries as we need to fill.
+
+// Note the change to .data then .text:
+// We plant the address of each entry
+// Into a (data) table for the Host
+// To know where each Guest interrupt should go.
+.macro IRQ_STUB N TARGET
+ .data; .long 1f; .text; 1:
+ // Trap eight, ten through fourteen and seventeen
+ // Supply an error number. Else zero.
+ .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17)
+ pushl $0
+ .endif
+ pushl $\N
+ jmp \TARGET
+ ALIGN
+.endm
+
+// This macro creates numerous entries
+// Using GAS macros which out-power C's.
+.macro IRQ_STUBS FIRST LAST TARGET
+ irq=\FIRST
+ .rept \LAST-\FIRST+1
+ IRQ_STUB irq \TARGET
+ irq=irq+1
+ .endr
+.endm
+
+// Here's the marker for our pointer table
+// Laid in the data section just before
+// Each macro places the address of code
+// Forming an array: each one points to text
+// Which handles interrupt in its turn.
+.data
+.global default_idt_entries
+default_idt_entries:
+.text
+ // The first two traps go straight back to the Host
+ IRQ_STUBS 0 1 return_to_host
+ // We'll say nothing, yet, about NMI
+ IRQ_STUB 2 handle_nmi
+ // Other traps also return to the Host
+ IRQ_STUBS 3 31 return_to_host
+ // All interrupts go via their handlers
+ IRQ_STUBS 32 127 deliver_to_host
+ // 'Cept system calls coming from userspace
+ // Are to go to the Guest, never the Host.
+ IRQ_STUB 128 return_to_host
+ IRQ_STUBS 129 255 deliver_to_host
+
+// The NMI, what a fabulous beast
+// Which swoops in and stops us no matter that
+// We're suspended between heaven and hell,
+// (Or more likely between the Host and Guest)
+// When in it comes! We are dazed and confused
+// So we do the simplest thing which one can.
+// Though we've pushed the trap number and zero
+// We discard them, return, and hope we live.
+handle_nmi:
+ addl $8, %esp
+ iret
+
+// We are done; all that's left is Mastery
+// And "make Mastery" is a journey long
+// Designed to make your fingers itch to code.
+
+// Here ends the text, the file and poem.
+ENTRY(end_switcher_text)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 20da011d40d0..77f50b63a970 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -3,6 +3,11 @@ menuconfig MACINTOSH_DRIVERS
bool "Macintosh device drivers"
depends on PPC || MAC || X86
default y if (PPC_PMAC || MAC)
+ ---help---
+ Say Y here to get to see options for devices used with Macintosh
+ computers. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if MACINTOSH_DRIVERS
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index 17ef5d3c01b4..444696625171 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -19,7 +19,6 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <asm/bootinfo.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_iop.h>
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index bc77c5e2ca9f..5c742a526082 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -89,7 +89,7 @@ static int sleepy_trackpad;
static int autopoll_devs;
int __adb_probe_sync;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier adb_sleep_notifier = {
adb_notify_sleep,
@@ -313,7 +313,7 @@ int __init adb_init(void)
printk(KERN_WARNING "Warning: no ADB interface detected\n");
adb_controller = NULL;
} else {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
pmu_register_sleep_notifier(&adb_sleep_notifier);
#endif /* CONFIG_PM */
#ifdef CONFIG_PPC
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 9ff2189d2e2a..8cce016b3d09 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -75,7 +75,7 @@ static struct notifier_block adbhid_adb_notifier = {
#define ADB_KEY_POWER_OLD 0x7e
#define ADB_KEY_POWER 0x7f
-u8 adb_to_linux_keycodes[128] = {
+u16 adb_to_linux_keycodes[128] = {
/* 0x00 */ KEY_A, /* 30 */
/* 0x01 */ KEY_S, /* 31 */
/* 0x02 */ KEY_D, /* 32 */
@@ -139,7 +139,7 @@ u8 adb_to_linux_keycodes[128] = {
/* 0x3c */ KEY_RIGHT, /* 106 */
/* 0x3d */ KEY_DOWN, /* 108 */
/* 0x3e */ KEY_UP, /* 103 */
- /* 0x3f */ 0,
+ /* 0x3f */ KEY_FN, /* 0x1d0 */
/* 0x40 */ 0,
/* 0x41 */ KEY_KPDOT, /* 83 */
/* 0x42 */ 0,
@@ -213,7 +213,7 @@ struct adbhid {
int original_handler_id;
int current_handler_id;
int mouse_kind;
- unsigned char *keycode;
+ u16 *keycode;
char name[64];
char phys[32];
int flags;
@@ -334,7 +334,7 @@ adbhid_input_keycode(int id, int scancode, int repeat)
keycode = ADB_KEY_POWER;
}
break;
- case ADB_KEY_POWER:
+ case ADB_KEY_POWER:
/* Fn + Command will produce a bogus "power" keycode */
if (ahid->flags & FLAG_FN_KEY_PRESSED) {
keycode = ADB_KEY_CMD;
@@ -359,8 +359,7 @@ adbhid_input_keycode(int id, int scancode, int repeat)
}
} else
ahid->flags |= FLAG_FN_KEY_PRESSED;
- /* Swallow the key press */
- return;
+ break;
case ADB_KEY_DEL:
/* Emulate Fn+delete = forward delete */
if (ahid->flags & FLAG_FN_KEY_PRESSED) {
@@ -374,9 +373,9 @@ adbhid_input_keycode(int id, int scancode, int repeat)
#endif /* CONFIG_PPC_PMAC */
}
- if (adbhid[id]->keycode[keycode]) {
- input_report_key(adbhid[id]->input,
- adbhid[id]->keycode[keycode], !up_flag);
+ key = adbhid[id]->keycode[keycode];
+ if (key) {
+ input_report_key(adbhid[id]->input, key, !up_flag);
input_sync(adbhid[id]->input);
} else
printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
@@ -795,8 +794,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
input_dev->event = adbhid_kbd_event;
- input_dev->keycodemax = 127;
- input_dev->keycodesize = 1;
+ input_dev->keycodemax = KEY_FN;
+ input_dev->keycodesize = sizeof(hid->keycode[0]);
break;
case ADB_MOUSE:
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index e54c4d9f6365..73c50bc02095 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -14,9 +14,10 @@
#include <asm/uaccess.h>
#include <asm/sections.h>
#include <asm/prom.h>
-#include <asm/ans-lcd.h>
#include <asm/io.h>
+#include "ans-lcd.h"
+
#define ANSLCD_ADDR 0xf301c000
#define ANSLCD_CTRL_IX 0x00
#define ANSLCD_DATA_IX 0x10
diff --git a/drivers/macintosh/ans-lcd.h b/drivers/macintosh/ans-lcd.h
new file mode 100644
index 000000000000..d795b9fd2db6
--- /dev/null
+++ b/drivers/macintosh/ans-lcd.h
@@ -0,0 +1,11 @@
+#ifndef _PPC_ANS_LCD_H
+#define _PPC_ANS_LCD_H
+
+#define ANSLCD_MINOR 156
+
+#define ANSLCD_CLEAR 0x01
+#define ANSLCD_SENDCTRL 0x02
+#define ANSLCD_SETSHORTDELAY 0x03
+#define ANSLCD_SETLONGDELAY 0x04
+
+#endif
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 76c1e8e4a487..33dee3a773ed 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -13,6 +13,7 @@
#include <linux/sysctl.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/kbd_kern.h>
static struct input_dev *emumousebtn;
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index c96b7fe882a4..ec9e5f32f0ae 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -365,10 +365,9 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
if (np == NULL)
return NULL;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->bus = &chip->lbus;
dev->media_bay = in_bay;
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 4177ff004753..2c21d4f25cc8 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -30,7 +30,6 @@
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
-#include <asm/dbdma.h>
#include <asm/macio.h>
#include <asm/keylargo.h>
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index f8e1a135bf9d..d409f6759482 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -1053,10 +1053,9 @@ static int smu_open(struct inode *inode, struct file *file)
struct smu_private *pp;
unsigned long flags;
- pp = kmalloc(sizeof(struct smu_private), GFP_KERNEL);
+ pp = kzalloc(sizeof(struct smu_private), GFP_KERNEL);
if (pp == 0)
return -ENOMEM;
- memset(pp, 0, sizeof(struct smu_private));
spin_lock_init(&pp->lock);
pp->mode = smu_file_commands;
init_waitqueue_head(&pp->wait);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index f25685b9b7cf..276945d51513 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -379,13 +379,10 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
if (thermostat)
return 0;
- th = (struct thermostat *)
- kmalloc(sizeof(struct thermostat), GFP_KERNEL);
-
+ th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
if (!th)
return -ENOMEM;
- memset(th, 0, sizeof(*th));
th->clt.addr = addr;
th->clt.adapter = adapter;
th->clt.driver = &thermostat_driver;
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index dbb22403979f..e43554e754a4 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -318,10 +318,9 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
if (adap == NULL)
return NULL;
- clt = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (clt == NULL)
return NULL;
- memset(clt, 0, sizeof(struct i2c_client));
clt->addr = (id >> 1) & 0x7f;
clt->adapter = adap;
@@ -1770,7 +1769,8 @@ static int call_critical_overtemp(void)
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
- return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+ return call_usermodehelper(critical_overtemp_path,
+ argv, envp, UMH_WAIT_EXEC);
}
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 3d0354e96a97..5452da1bb1a5 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -431,9 +431,8 @@ do_probe( struct i2c_adapter *adapter, int addr, int kind )
| I2C_FUNC_SMBUS_WRITE_BYTE) )
return 0;
- if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) )
+ if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) )
return -ENOMEM;
- memset( cl, 0, sizeof(struct i2c_client) );
cl->addr = addr;
cl->adapter = adapter;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 157080b3b468..f7c509b7a8ea 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -152,10 +152,10 @@ static spinlock_t pmu_lock;
static u8 pmu_intr_mask;
static int pmu_version;
static int drop_interrupts;
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
-#endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+#if (defined(CONFIG_PM_SLEEP)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
static int sleep_in_progress;
#endif
static unsigned long async_req_locks;
@@ -410,7 +410,7 @@ static int __init via_pmu_start(void)
irq = irq_of_parse_and_map(vias, 0);
if (irq == NO_IRQ) {
- printk(KERN_ERR "via-pmu: can't map interruptn");
+ printk(KERN_ERR "via-pmu: can't map interrupt\n");
return -ENODEV;
}
if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) {
@@ -875,7 +875,7 @@ proc_read_options(char *page, char **start, off_t off,
{
char *p = page;
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
@@ -916,7 +916,7 @@ proc_write_options(struct file *file, const char __user *buffer,
*(val++) = 0;
while(*val == ' ')
val++;
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
if (!strcmp(label, "lid_wakeup"))
@@ -1738,7 +1738,7 @@ pmu_present(void)
return via != 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static LIST_HEAD(sleep_notifiers);
@@ -1769,9 +1769,9 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
return 0;
}
EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
/* Sleep is broadcast last-to-first */
static void broadcast_sleep(int when)
@@ -2390,7 +2390,7 @@ powerbook_sleep_3400(void)
return 0;
}
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
/*
* Support for /dev/pmu device
@@ -2573,7 +2573,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
int error = -EINVAL;
switch (cmd) {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -2601,7 +2601,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return put_user(0, argp);
else
return put_user(1, argp);
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
/* Compatibility ioctl's for backlight */
@@ -2757,7 +2757,7 @@ pmu_polled_request(struct adb_request *req)
* to do suspend-to-disk.
*/
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
int pmu_sys_suspended;
@@ -2792,7 +2792,7 @@ static int pmu_sys_resume(struct sys_device *sysdev)
return 0;
}
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
static struct sysdev_class pmu_sysclass = {
set_kset_name("pmu"),
@@ -2803,10 +2803,10 @@ static struct sys_device device_pmu = {
};
static struct sysdev_driver driver_pmu = {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
.suspend = &pmu_sys_suspend,
.resume = &pmu_sys_resume,
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
};
static int __init init_pmu_sysfs(void)
@@ -2841,10 +2841,10 @@ EXPORT_SYMBOL(pmu_wait_complete);
EXPORT_SYMBOL(pmu_suspend);
EXPORT_SYMBOL(pmu_resume);
EXPORT_SYMBOL(pmu_unlock);
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
EXPORT_SYMBOL(pmu_enable_irled);
EXPORT_SYMBOL(pmu_battery_count);
EXPORT_SYMBOL(pmu_batteries);
EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index dfdf11c1eec4..e2f84da09e7c 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -818,243 +818,3 @@ pmu_present(void)
{
return (pmu_kind != PMU_UNKNOWN);
}
-
-#if 0 /* needs some work for 68K */
-
-/*
- * This struct is used to store config register values for
- * PCI devices which may get powered off when we sleep.
- */
-static struct pci_save {
- u16 command;
- u16 cache_lat;
- u16 intr;
-} *pbook_pci_saves;
-static int n_pbook_pci_saves;
-
-static inline void
-pbook_pci_save(void)
-{
- int npci;
- struct pci_dev *pd = NULL;
- struct pci_save *ps;
-
- npci = 0;
- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
- ++npci;
- n_pbook_pci_saves = npci;
- if (npci == 0)
- return;
- ps = kmalloc(npci * sizeof(*ps), GFP_KERNEL);
- pbook_pci_saves = ps;
- if (ps == NULL)
- return;
-
- pd = NULL;
- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
- pci_read_config_word(pd, PCI_COMMAND, &ps->command);
- pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
- pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
- ++ps;
- --npci;
- }
-}
-
-static inline void
-pbook_pci_restore(void)
-{
- u16 cmd;
- struct pci_save *ps = pbook_pci_saves;
- struct pci_dev *pd = NULL;
- int j;
-
- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
- if (ps->command == 0)
- continue;
- pci_read_config_word(pd, PCI_COMMAND, &cmd);
- if ((ps->command & ~cmd) == 0)
- continue;
- switch (pd->hdr_type) {
- case PCI_HEADER_TYPE_NORMAL:
- for (j = 0; j < 6; ++j)
- pci_write_config_dword(pd,
- PCI_BASE_ADDRESS_0 + j*4,
- pd->resource[j].start);
- pci_write_config_dword(pd, PCI_ROM_ADDRESS,
- pd->resource[PCI_ROM_RESOURCE].start);
- pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
- ps->cache_lat);
- pci_write_config_word(pd, PCI_INTERRUPT_LINE,
- ps->intr);
- pci_write_config_word(pd, PCI_COMMAND, ps->command);
- break;
- /* other header types not restored at present */
- }
- }
-}
-
-/*
- * Put the powerbook to sleep.
- */
-#define IRQ_ENABLE ((unsigned int *)0xf3000024)
-#define MEM_CTRL ((unsigned int *)0xf8000070)
-
-int powerbook_sleep(void)
-{
- int ret, i, x;
- static int save_backlight;
- static unsigned int save_irqen;
- unsigned long msr;
- unsigned int hid0;
- unsigned long p, wait;
- struct adb_request sleep_req;
-
- /* Notify device drivers */
- ret = blocking_notifier_call_chain(&sleep_notifier_list,
- PBOOK_SLEEP, NULL);
- if (ret & NOTIFY_STOP_MASK)
- return -EBUSY;
-
- /* Sync the disks. */
- /* XXX It would be nice to have some way to ensure that
- * nobody is dirtying any new buffers while we wait. */
- sys_sync();
-
- /* Turn off the display backlight */
- save_backlight = backlight_enabled;
- if (save_backlight)
- pmu_enable_backlight(0);
-
- /* Give the disks a little time to actually finish writing */
- for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
- mb();
-
- /* Disable all interrupts except pmu */
- save_irqen = in_le32(IRQ_ENABLE);
- for (i = 0; i < 32; ++i)
- if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
- disable_irq(i);
- asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
- /* Save the state of PCI config space for some slots */
- pbook_pci_save();
-
- /* Set the memory controller to keep the memory refreshed
- while we're asleep */
- for (i = 0x403f; i >= 0x4000; --i) {
- out_be32(MEM_CTRL, i);
- do {
- x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
- } while (x == 0);
- if (x >= 0x100)
- break;
- }
-
- /* Ask the PMU to put us to sleep */
- pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
- while (!sleep_req.complete)
- mb();
- /* displacement-flush the L2 cache - necessary? */
- for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
- i = *(volatile int *)p;
- asleep = 1;
-
- /* Put the CPU into sleep mode */
- asm volatile("mfspr %0,1008" : "=r" (hid0) :);
- hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
- asm volatile("mtspr 1008,%0" : : "r" (hid0));
- local_save_flags(msr);
- msr |= MSR_POW | MSR_EE;
- local_irq_restore(msr);
- udelay(10);
-
- /* OK, we're awake again, start restoring things */
- out_be32(MEM_CTRL, 0x3f);
- pbook_pci_restore();
-
- /* wait for the PMU interrupt sequence to complete */
- while (asleep)
- mb();
-
- /* reenable interrupts */
- for (i = 0; i < 32; ++i)
- if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
- enable_irq(i);
-
- /* Notify drivers */
- blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
-
- /* reenable ADB autopoll */
- pmu_adb_autopoll(adb_dev_map);
-
- /* Turn on the screen backlight, if it was on before */
- if (save_backlight)
- pmu_enable_backlight(1);
-
- /* Wait for the hard disk to spin up */
-
- return 0;
-}
-
-/*
- * Support for /dev/pmu device
- */
-static int pmu_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static ssize_t pmu_read(struct file *file, char *buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t pmu_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static int pmu_ioctl(struct inode * inode, struct file *filp,
- u_int cmd, u_long arg)
-{
- int error;
- __u32 value;
-
- switch (cmd) {
- case PMU_IOC_SLEEP:
- return -ENOSYS;
- case PMU_IOC_GET_BACKLIGHT:
- return put_user(backlight_level, (__u32 *)arg);
- case PMU_IOC_SET_BACKLIGHT:
- error = get_user(value, (__u32 *)arg);
- if (!error)
- pmu_set_brightness(value);
- return error;
- case PMU_IOC_GET_MODEL:
- return put_user(pmu_kind, (__u32 *)arg);
- }
- return -EINVAL;
-}
-
-static const struct file_operations pmu_device_fops = {
- .read = pmu_read,
- .write = pmu_write,
- .ioctl = pmu_ioctl,
- .open = pmu_open,
-};
-
-static struct miscdevice pmu_device = {
- PMU_MINOR, "pmu", &pmu_device_fops
-};
-
-void pmu_device_init(void)
-{
- if (!via)
- return;
- if (misc_register(&pmu_device) < 0)
- printk(KERN_ERR "via-pmu68k: cannot register misc device.\n");
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e18d265d5d33..516d943227e2 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -80,7 +80,8 @@ int wf_critical_overtemp(void)
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
- return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+ return call_usermodehelper(critical_overtemp_path,
+ argv, envp, UMH_WAIT_EXEC);
}
EXPORT_SYMBOL_GPL(wf_critical_overtemp);
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index a0fabf3c2008..7e10c3ab4d50 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -117,10 +117,9 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
DBG("wf_lm75: creating %s device at address 0x%02x\n",
ds1775 ? "ds1775" : "lm75", addr);
- lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+ lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
if (lm == NULL)
return NULL;
- memset(lm, 0, sizeof(struct wf_lm75_sensor));
/* Usual rant about sensor names not beeing very consistent in
* the device-tree, oh well ...
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 351982bcec1b..f449d775cdf4 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -380,10 +380,12 @@ static int __init sat_sensors_init(void)
return i2c_add_driver(&wf_sat_driver);
}
+#if 0 /* uncomment when module_exit() below is uncommented */
static void __exit sat_sensors_exit(void)
{
i2c_del_driver(&wf_sat_driver);
}
+#endif
module_init(sat_sensors_init);
/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 531d4d17d011..34a8c60a254a 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -263,7 +263,7 @@ config DM_MULTIPATH_EMC
config DM_MULTIPATH_RDAC
tristate "LSI/Engenio RDAC multipath support (EXPERIMENTAL)"
- depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
+ depends on DM_MULTIPATH && BLK_DEV_DM && SCSI && EXPERIMENTAL
---help---
Multipath support for LSI/Engenio RDAC.
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index 16ee3b018b3a..3f7b827649e3 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -9,6 +9,8 @@
#include <linux/bio.h>
+#ifdef CONFIG_BLOCK
+
struct bio_list {
struct bio *head;
struct bio *tail;
@@ -106,4 +108,5 @@ static inline struct bio *bio_list_get(struct bio_list *bl)
return bio;
}
+#endif /* CONFIG_BLOCK */
#endif
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index ba952a032598..8216a6f75be5 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -489,7 +489,7 @@ static void dec_pending(struct dm_crypt_io *io, int error)
if (!atomic_dec_and_test(&io->pending))
return;
- bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
+ bio_endio(io->base_bio, io->error);
mempool_free(io, cc->io_pool);
}
@@ -509,25 +509,19 @@ static void kcryptd_queue_io(struct dm_crypt_io *io)
queue_work(_kcryptd_workqueue, &io->work);
}
-static int crypt_endio(struct bio *clone, unsigned int done, int error)
+static void crypt_endio(struct bio *clone, int error)
{
struct dm_crypt_io *io = clone->bi_private;
struct crypt_config *cc = io->target->private;
unsigned read_io = bio_data_dir(clone) == READ;
/*
- * free the processed pages, even if
- * it's only a partially completed write
+ * free the processed pages
*/
- if (!read_io)
- crypt_free_buffer_pages(cc, clone, done);
-
- /* keep going - not finished yet */
- if (unlikely(clone->bi_size))
- return 1;
-
- if (!read_io)
+ if (!read_io) {
+ crypt_free_buffer_pages(cc, clone, clone->bi_size);
goto out;
+ }
if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) {
error = -EIO;
@@ -537,12 +531,11 @@ static int crypt_endio(struct bio *clone, unsigned int done, int error)
bio_put(clone);
io->post_process = 1;
kcryptd_queue_io(io);
- return 0;
+ return;
out:
bio_put(clone);
dec_pending(io, error);
- return error;
}
static void clone_init(struct dm_crypt_io *io, struct bio *clone)
@@ -920,6 +913,8 @@ static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = (struct crypt_config *) ti->private;
+ flush_workqueue(_kcryptd_workqueue);
+
bioset_free(cc->bs);
mempool_destroy(cc->page_pool);
mempool_destroy(cc->io_pool);
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 265c467854da..a2191a4fcf77 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -38,13 +38,10 @@ static inline void free_bio(struct bio *bio)
bio_put(bio);
}
-static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
+static void emc_endio(struct bio *bio, int error)
{
struct dm_path *path = bio->bi_private;
- if (bio->bi_size)
- return 1;
-
/* We also need to look at the sense keys here whether or not to
* switch to the next PG etc.
*
@@ -109,15 +106,7 @@ static struct request *get_failover_req(struct emc_handler *h,
return NULL;
}
- rq->bio = rq->biotail = bio;
- blk_rq_bio_prep(q, rq, bio);
-
- rq->rq_disk = bdev->bd_contains->bd_disk;
-
- /* bio backed don't set data */
- rq->buffer = rq->data = NULL;
- /* rq data_len used for pc cmd's request_bufflen */
- rq->data_len = bio->bi_size;
+ blk_rq_append_bio(q, rq, bio);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 3d65917a1bbb..8fe81e1807e0 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -623,6 +623,7 @@ int dm_create_persistent(struct exception_store *store)
ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
if (!ps->metadata_wq) {
+ kfree(ps);
DMERR("couldn't start header metadata update thread");
return -ENOMEM;
}
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index f3a772486437..b8e342fe7586 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -124,15 +124,11 @@ static void dec_count(struct io *io, unsigned int region, int error)
}
}
-static int endio(struct bio *bio, unsigned int done, int error)
+static void endio(struct bio *bio, int error)
{
struct io *io;
unsigned region;
- /* keep going until we've finished */
- if (bio->bi_size)
- return 1;
-
if (error && bio_data_dir(bio) == READ)
zero_fill_bio(bio);
@@ -146,8 +142,6 @@ static int endio(struct bio *bio, unsigned int done, int error)
bio_put(bio);
dec_count(io, region, error);
-
- return 0;
}
/*-----------------------------------------------------------------
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c
index 8b776b8cb7f7..16b161345775 100644
--- a/drivers/md/dm-mpath-rdac.c
+++ b/drivers/md/dm-mpath-rdac.c
@@ -292,7 +292,7 @@ static struct request *get_rdac_req(struct rdac_handler *h,
rq->end_io_data = h;
rq->timeout = h->timeout;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
- rq->cmd_flags = REQ_FAILFAST | REQ_NOMERGE;
+ rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
return rq;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index d6ca9d0a6fd1..31056abca89d 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -390,11 +390,11 @@ static void dispatch_queued_ios(struct multipath *m)
r = map_io(m, bio, mpio, 1);
if (r < 0)
- bio_endio(bio, bio->bi_size, r);
+ bio_endio(bio, r);
else if (r == DM_MAPIO_REMAPPED)
generic_make_request(bio);
else if (r == DM_MAPIO_REQUEUE)
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
bio = next;
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 1a876f9965e0..d09ff15490a5 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -820,7 +820,7 @@ static void write_callback(unsigned long error, void *context)
break;
}
}
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
}
static void do_write(struct mirror_set *ms, struct bio *bio)
@@ -900,7 +900,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
*/
if (unlikely(ms->log_failure))
while ((bio = bio_list_pop(&sync)))
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
else while ((bio = bio_list_pop(&sync)))
do_write(ms, bio);
@@ -951,13 +951,12 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);
- ms = kmalloc(len, GFP_KERNEL);
+ ms = kzalloc(len, GFP_KERNEL);
if (!ms) {
ti->error = "Cannot allocate mirror context";
return NULL;
}
- memset(ms, 0, len);
spin_lock_init(&ms->lock);
ms->ti = ti;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 83ddbfe6b8a4..98a633f3d6b0 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -636,7 +636,7 @@ static void error_bios(struct bio *bio)
while (bio) {
n = bio->bi_next;
bio->bi_next = NULL;
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
bio = n;
}
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 2fc199b0016b..2bcde5798b5a 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -526,7 +526,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
{
- request_queue_t *q = bdev_get_queue(bdev);
+ struct request_queue *q = bdev_get_queue(bdev);
struct io_restrictions *rs = &ti->limits;
/*
@@ -979,7 +979,7 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
devices = dm_table_get_devices(t);
for (d = devices->next; d != devices; d = d->next) {
struct dm_dev *dd = list_entry(d, struct dm_dev, list);
- request_queue_t *q = bdev_get_queue(dd->bdev);
+ struct request_queue *q = bdev_get_queue(dd->bdev);
r |= bdi_congested(&q->backing_dev_info, bdi_bits);
}
@@ -992,7 +992,7 @@ void dm_table_unplug_all(struct dm_table *t)
for (d = devices->next; d != devices; d = d->next) {
struct dm_dev *dd = list_entry(d, struct dm_dev, list);
- request_queue_t *q = bdev_get_queue(dd->bdev);
+ struct request_queue *q = bdev_get_queue(dd->bdev);
if (q->unplug_fn)
q->unplug_fn(q);
@@ -1011,7 +1011,7 @@ int dm_table_flush_all(struct dm_table *t)
for (d = devices->next; d != devices; d = d->next) {
struct dm_dev *dd = list_entry(d, struct dm_dev, list);
- request_queue_t *q = bdev_get_queue(dd->bdev);
+ struct request_queue *q = bdev_get_queue(dd->bdev);
int err;
if (!q->issue_flush_fn)
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index f314d7dc9c26..bdec206c404b 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -43,7 +43,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio,
break;
}
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
/* accepted bio, don't make new request */
return DM_MAPIO_SUBMITTED;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 846614e676c6..167765c47747 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -80,7 +80,7 @@ struct mapped_device {
unsigned long flags;
- request_queue_t *queue;
+ struct request_queue *queue;
struct gendisk *disk;
char name[16];
@@ -484,23 +484,20 @@ static void dec_pending(struct dm_io *io, int error)
blk_add_trace_bio(io->md->queue, io->bio,
BLK_TA_COMPLETE);
- bio_endio(io->bio, io->bio->bi_size, io->error);
+ bio_endio(io->bio, io->error);
}
free_io(io->md, io);
}
}
-static int clone_endio(struct bio *bio, unsigned int done, int error)
+static void clone_endio(struct bio *bio, int error)
{
int r = 0;
struct dm_target_io *tio = bio->bi_private;
struct mapped_device *md = tio->io->md;
dm_endio_fn endio = tio->ti->type->end_io;
- if (bio->bi_size)
- return 1;
-
if (!bio_flagged(bio, BIO_UPTODATE) && !error)
error = -EIO;
@@ -514,7 +511,7 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
error = r;
else if (r == DM_ENDIO_INCOMPLETE)
/* The target will handle the io */
- return 1;
+ return;
else if (r) {
DMWARN("unimplemented target endio return value: %d", r);
BUG();
@@ -530,7 +527,6 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
bio_put(bio);
free_tio(md, tio);
- return r;
}
static sector_t max_io_len(struct mapped_device *md,
@@ -580,8 +576,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
/* the bio has been remapped so dispatch it */
blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
- tio->io->bio->bi_bdev->bd_dev, sector,
- clone->bi_sector);
+ tio->io->bio->bi_bdev->bd_dev,
+ clone->bi_sector, sector);
generic_make_request(clone);
} else if (r < 0 || r == DM_MAPIO_REQUEUE) {
@@ -761,7 +757,7 @@ static void __split_bio(struct mapped_device *md, struct bio *bio)
ci.map = dm_get_table(md);
if (!ci.map) {
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return;
}
@@ -792,7 +788,7 @@ static void __split_bio(struct mapped_device *md, struct bio *bio)
* The request function that just remaps the bio built up by
* dm_merge_bvec.
*/
-static int dm_request(request_queue_t *q, struct bio *bio)
+static int dm_request(struct request_queue *q, struct bio *bio)
{
int r;
int rw = bio_data_dir(bio);
@@ -803,7 +799,7 @@ static int dm_request(request_queue_t *q, struct bio *bio)
* guarantee it is (or can be) handled by the targets correctly.
*/
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -820,13 +816,13 @@ static int dm_request(request_queue_t *q, struct bio *bio)
up_read(&md->io_lock);
if (bio_rw(bio) == READA) {
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
r = queue_io(md, bio);
if (r < 0) {
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
} else if (r == 0)
@@ -844,7 +840,7 @@ static int dm_request(request_queue_t *q, struct bio *bio)
return 0;
}
-static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
+static int dm_flush_all(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
struct mapped_device *md = q->queuedata;
@@ -859,7 +855,7 @@ static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
return ret;
}
-static void dm_unplug_all(request_queue_t *q)
+static void dm_unplug_all(struct request_queue *q)
{
struct mapped_device *md = q->queuedata;
struct dm_table *map = dm_get_table(md);
@@ -1110,7 +1106,7 @@ static void __set_size(struct mapped_device *md, sector_t size)
static int __bind(struct mapped_device *md, struct dm_table *t)
{
- request_queue_t *q = md->queue;
+ struct request_queue *q = md->queue;
sector_t size;
size = dm_table_get_size(t);
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index 4ebd0f2a75ec..cf2ddce34118 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -65,18 +65,16 @@
#include <linux/raid/md.h>
-static int faulty_fail(struct bio *bio, unsigned int bytes_done, int error)
+static void faulty_fail(struct bio *bio, int error)
{
struct bio *b = bio->bi_private;
b->bi_size = bio->bi_size;
b->bi_sector = bio->bi_sector;
- if (bio->bi_size == 0)
- bio_put(bio);
+ bio_put(bio);
- clear_bit(BIO_UPTODATE, &b->bi_flags);
- return (b->bi_end_io)(b, bytes_done, -EIO);
+ bio_io_error(b);
}
typedef struct faulty_conf {
@@ -167,7 +165,7 @@ static void add_sector(conf_t *conf, sector_t start, int mode)
conf->nfaults = n+1;
}
-static int make_request(request_queue_t *q, struct bio *bio)
+static int make_request(struct request_queue *q, struct bio *bio)
{
mddev_t *mddev = q->queuedata;
conf_t *conf = (conf_t*)mddev->private;
@@ -179,7 +177,7 @@ static int make_request(request_queue_t *q, struct bio *bio)
/* special case - don't decrement, don't generic_make_request,
* just fail immediately
*/
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
return 0;
}
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 192741083196..550148770bb2 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -55,7 +55,7 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector)
*
* Return amount of bytes we can take at this offset
*/
-static int linear_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+static int linear_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
{
mddev_t *mddev = q->queuedata;
dev_info_t *dev0;
@@ -79,20 +79,20 @@ static int linear_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio
return maxsectors << 9;
}
-static void linear_unplug(request_queue_t *q)
+static void linear_unplug(struct request_queue *q)
{
mddev_t *mddev = q->queuedata;
linear_conf_t *conf = mddev_to_conf(mddev);
int i;
for (i=0; i < mddev->raid_disks; i++) {
- request_queue_t *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev);
+ struct request_queue *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev);
if (r_queue->unplug_fn)
r_queue->unplug_fn(r_queue);
}
}
-static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int linear_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
mddev_t *mddev = q->queuedata;
@@ -101,7 +101,7 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
for (i=0; i < mddev->raid_disks && ret == 0; i++) {
struct block_device *bdev = conf->disks[i].rdev->bdev;
- request_queue_t *r_queue = bdev_get_queue(bdev);
+ struct request_queue *r_queue = bdev_get_queue(bdev);
if (!r_queue->issue_flush_fn)
ret = -EOPNOTSUPP;
@@ -118,7 +118,7 @@ static int linear_congested(void *data, int bits)
int i, ret = 0;
for (i = 0; i < mddev->raid_disks && !ret ; i++) {
- request_queue_t *q = bdev_get_queue(conf->disks[i].rdev->bdev);
+ struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
ret |= bdi_congested(&q->backing_dev_info, bits);
}
return ret;
@@ -330,7 +330,7 @@ static int linear_stop (mddev_t *mddev)
return 0;
}
-static int linear_make_request (request_queue_t *q, struct bio *bio)
+static int linear_make_request (struct request_queue *q, struct bio *bio)
{
const int rw = bio_data_dir(bio);
mddev_t *mddev = q->queuedata;
@@ -338,7 +338,7 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
sector_t block;
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -358,7 +358,7 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
bdevname(tmp_dev->rdev->bdev, b),
(unsigned long long)tmp_dev->size,
(unsigned long long)tmp_dev->offset);
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
if (unlikely(bio->bi_sector + (bio->bi_size >> 9) >
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 65ddc887dfd7..acf1b81b47cb 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -211,9 +211,9 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
)
-static int md_fail_request (request_queue_t *q, struct bio *bio)
+static int md_fail_request (struct request_queue *q, struct bio *bio)
{
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
@@ -384,12 +384,10 @@ static void free_disk_sb(mdk_rdev_t * rdev)
}
-static int super_written(struct bio *bio, unsigned int bytes_done, int error)
+static void super_written(struct bio *bio, int error)
{
mdk_rdev_t *rdev = bio->bi_private;
mddev_t *mddev = rdev->mddev;
- if (bio->bi_size)
- return 1;
if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
printk("md: super_written gets error=%d, uptodate=%d\n",
@@ -401,16 +399,13 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error)
if (atomic_dec_and_test(&mddev->pending_writes))
wake_up(&mddev->sb_wait);
bio_put(bio);
- return 0;
}
-static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error)
+static void super_written_barrier(struct bio *bio, int error)
{
struct bio *bio2 = bio->bi_private;
mdk_rdev_t *rdev = bio2->bi_private;
mddev_t *mddev = rdev->mddev;
- if (bio->bi_size)
- return 1;
if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
error == -EOPNOTSUPP) {
@@ -424,11 +419,11 @@ static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int e
spin_unlock_irqrestore(&mddev->write_lock, flags);
wake_up(&mddev->sb_wait);
bio_put(bio);
- return 0;
+ } else {
+ bio_put(bio2);
+ bio->bi_private = rdev;
+ super_written(bio, error);
}
- bio_put(bio2);
- bio->bi_private = rdev;
- return super_written(bio, bytes_done, error);
}
void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
@@ -489,13 +484,9 @@ void md_super_wait(mddev_t *mddev)
finish_wait(&mddev->sb_wait, &wq);
}
-static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
+static void bi_complete(struct bio *bio, int error)
{
- if (bio->bi_size)
- return 1;
-
complete((struct completion*)bio->bi_private);
- return 0;
}
int sync_page_io(struct block_device *bdev, sector_t sector, int size,
@@ -3085,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
mddev->gendisk = disk;
mutex_unlock(&disks_mutex);
mddev->kobj.parent = &disk->kobj;
- mddev->kobj.k_name = NULL;
- snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+ kobject_set_name(&mddev->kobj, "%s", "md");
mddev->kobj.ktype = &md_ktype;
if (kobject_register(&mddev->kobj))
printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 14da37fee37b..f2a63f394ad9 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -82,21 +82,17 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err)
struct bio *bio = mp_bh->master_bio;
multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
- bio_endio(bio, bio->bi_size, err);
+ bio_endio(bio, err);
mempool_free(mp_bh, conf->pool);
}
-static int multipath_end_request(struct bio *bio, unsigned int bytes_done,
- int error)
+static void multipath_end_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private);
multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev;
- if (bio->bi_size)
- return 1;
-
if (uptodate)
multipath_end_bh_io(mp_bh, 0);
else if (!bio_rw_ahead(bio)) {
@@ -112,7 +108,6 @@ static int multipath_end_request(struct bio *bio, unsigned int bytes_done,
} else
multipath_end_bh_io(mp_bh, error);
rdev_dec_pending(rdev, conf->mddev);
- return 0;
}
static void unplug_slaves(mddev_t *mddev)
@@ -125,7 +120,7 @@ static void unplug_slaves(mddev_t *mddev)
mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)
&& atomic_read(&rdev->nr_pending)) {
- request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+ struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
@@ -140,13 +135,13 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_unlock();
}
-static void multipath_unplug(request_queue_t *q)
+static void multipath_unplug(struct request_queue *q)
{
unplug_slaves(q->queuedata);
}
-static int multipath_make_request (request_queue_t *q, struct bio * bio)
+static int multipath_make_request (struct request_queue *q, struct bio * bio)
{
mddev_t *mddev = q->queuedata;
multipath_conf_t *conf = mddev_to_conf(mddev);
@@ -155,7 +150,7 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
const int rw = bio_data_dir(bio);
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -169,7 +164,7 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
mp_bh->path = multipath_map(conf);
if (mp_bh->path < 0) {
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
mempool_free(mp_bh, conf->pool);
return 0;
}
@@ -199,7 +194,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev)
seq_printf (seq, "]");
}
-static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int multipath_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
mddev_t *mddev = q->queuedata;
@@ -211,7 +206,7 @@ static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
- request_queue_t *r_queue = bdev_get_queue(bdev);
+ struct request_queue *r_queue = bdev_get_queue(bdev);
if (!r_queue->issue_flush_fn)
ret = -EOPNOTSUPP;
@@ -238,7 +233,7 @@ static int multipath_congested(void *data, int bits)
for (i = 0; i < mddev->raid_disks ; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
- request_queue_t *q = bdev_get_queue(rdev->bdev);
+ struct request_queue *q = bdev_get_queue(rdev->bdev);
ret |= bdi_congested(&q->backing_dev_info, bits);
/* Just like multipath_map, we just check the
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 2c404f73a377..ef0da2d84959 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -25,7 +25,7 @@
#define MD_DRIVER
#define MD_PERSONALITY
-static void raid0_unplug(request_queue_t *q)
+static void raid0_unplug(struct request_queue *q)
{
mddev_t *mddev = q->queuedata;
raid0_conf_t *conf = mddev_to_conf(mddev);
@@ -33,14 +33,14 @@ static void raid0_unplug(request_queue_t *q)
int i;
for (i=0; i<mddev->raid_disks; i++) {
- request_queue_t *r_queue = bdev_get_queue(devlist[i]->bdev);
+ struct request_queue *r_queue = bdev_get_queue(devlist[i]->bdev);
if (r_queue->unplug_fn)
r_queue->unplug_fn(r_queue);
}
}
-static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid0_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
mddev_t *mddev = q->queuedata;
@@ -50,7 +50,7 @@ static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
for (i=0; i<mddev->raid_disks && ret == 0; i++) {
struct block_device *bdev = devlist[i]->bdev;
- request_queue_t *r_queue = bdev_get_queue(bdev);
+ struct request_queue *r_queue = bdev_get_queue(bdev);
if (!r_queue->issue_flush_fn)
ret = -EOPNOTSUPP;
@@ -68,7 +68,7 @@ static int raid0_congested(void *data, int bits)
int i, ret = 0;
for (i = 0; i < mddev->raid_disks && !ret ; i++) {
- request_queue_t *q = bdev_get_queue(devlist[i]->bdev);
+ struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
ret |= bdi_congested(&q->backing_dev_info, bits);
}
@@ -268,7 +268,7 @@ static int create_strip_zones (mddev_t *mddev)
*
* Return amount of bytes we can accept at this offset
*/
-static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+static int raid0_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
{
mddev_t *mddev = q->queuedata;
sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
@@ -408,7 +408,7 @@ static int raid0_stop (mddev_t *mddev)
return 0;
}
-static int raid0_make_request (request_queue_t *q, struct bio *bio)
+static int raid0_make_request (struct request_queue *q, struct bio *bio)
{
mddev_t *mddev = q->queuedata;
unsigned int sect_in_chunk, chunksize_bits, chunk_size, chunk_sects;
@@ -420,7 +420,7 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio)
const int rw = bio_data_dir(bio);
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -490,7 +490,7 @@ bad_map:
" or bigger than %dk %llu %d\n", chunk_size,
(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 00c78b77b13d..6d03bea6fa58 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -238,7 +238,7 @@ static void raid_end_bio_io(r1bio_t *r1_bio)
(unsigned long long) bio->bi_sector +
(bio->bi_size >> 9) - 1);
- bio_endio(bio, bio->bi_size,
+ bio_endio(bio,
test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
}
free_r1bio(r1_bio);
@@ -255,16 +255,13 @@ static inline void update_head_pos(int disk, r1bio_t *r1_bio)
r1_bio->sector + (r1_bio->sectors);
}
-static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid1_end_read_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
int mirror;
conf_t *conf = mddev_to_conf(r1_bio->mddev);
- if (bio->bi_size)
- return 1;
-
mirror = r1_bio->read_disk;
/*
* this branch is our 'one mirror IO has finished' event handler:
@@ -301,10 +298,9 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
}
rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
- return 0;
}
-static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid1_end_write_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -312,8 +308,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
conf_t *conf = mddev_to_conf(r1_bio->mddev);
struct bio *to_put = NULL;
- if (bio->bi_size)
- return 1;
for (mirror = 0; mirror < conf->raid_disks; mirror++)
if (r1_bio->bios[mirror] == bio)
@@ -366,7 +360,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
(unsigned long long) mbio->bi_sector,
(unsigned long long) mbio->bi_sector +
(mbio->bi_size >> 9) - 1);
- bio_endio(mbio, mbio->bi_size, 0);
+ bio_endio(mbio, 0);
}
}
}
@@ -400,8 +394,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
if (to_put)
bio_put(to_put);
-
- return 0;
}
@@ -552,7 +544,7 @@ static void unplug_slaves(mddev_t *mddev)
for (i=0; i<mddev->raid_disks; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
- request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+ struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
@@ -567,7 +559,7 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_unlock();
}
-static void raid1_unplug(request_queue_t *q)
+static void raid1_unplug(struct request_queue *q)
{
mddev_t *mddev = q->queuedata;
@@ -575,7 +567,7 @@ static void raid1_unplug(request_queue_t *q)
md_wakeup_thread(mddev->thread);
}
-static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid1_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
mddev_t *mddev = q->queuedata;
@@ -587,7 +579,7 @@ static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
- request_queue_t *r_queue = bdev_get_queue(bdev);
+ struct request_queue *r_queue = bdev_get_queue(bdev);
if (!r_queue->issue_flush_fn)
ret = -EOPNOTSUPP;
@@ -615,7 +607,7 @@ static int raid1_congested(void *data, int bits)
for (i = 0; i < mddev->raid_disks; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
- request_queue_t *q = bdev_get_queue(rdev->bdev);
+ struct request_queue *q = bdev_get_queue(rdev->bdev);
/* Note the '|| 1' - when read_balance prefers
* non-congested targets, it can be removed
@@ -765,7 +757,7 @@ do_sync_io:
return NULL;
}
-static int make_request(request_queue_t *q, struct bio * bio)
+static int make_request(struct request_queue *q, struct bio * bio)
{
mddev_t *mddev = q->queuedata;
conf_t *conf = mddev_to_conf(mddev);
@@ -796,7 +788,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
if (rw == WRITE)
md_write_end(mddev);
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -1137,14 +1129,11 @@ abort:
}
-static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_read(struct bio *bio, int error)
{
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
int i;
- if (bio->bi_size)
- return 1;
-
for (i=r1_bio->mddev->raid_disks; i--; )
if (r1_bio->bios[i] == bio)
break;
@@ -1160,10 +1149,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
if (atomic_dec_and_test(&r1_bio->remaining))
reschedule_retry(r1_bio);
- return 0;
}
-static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_write(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -1172,9 +1160,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
int i;
int mirror=0;
- if (bio->bi_size)
- return 1;
-
for (i = 0; i < conf->raid_disks; i++)
if (r1_bio->bios[i] == bio) {
mirror = i;
@@ -1200,7 +1185,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
md_done_sync(mddev, r1_bio->sectors, uptodate);
put_buf(r1_bio);
}
- return 0;
}
static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
@@ -1972,7 +1956,8 @@ static int run(mddev_t *mddev)
!test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
mddev->degraded++;
- conf->fullsync = 1;
+ if (disk->rdev)
+ conf->fullsync = 1;
}
}
if (mddev->degraded == conf->raid_disks) {
@@ -2153,11 +2138,25 @@ static int raid1_reshape(mddev_t *mddev)
oldpool = conf->r1bio_pool;
conf->r1bio_pool = newpool;
- for (d=d2=0; d < conf->raid_disks; d++)
- if (conf->mirrors[d].rdev) {
- conf->mirrors[d].rdev->raid_disk = d2;
- newmirrors[d2++].rdev = conf->mirrors[d].rdev;
+ for (d = d2 = 0; d < conf->raid_disks; d++) {
+ mdk_rdev_t *rdev = conf->mirrors[d].rdev;
+ if (rdev && rdev->raid_disk != d2) {
+ char nm[20];
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_remove_link(&mddev->kobj, nm);
+ rdev->raid_disk = d2;
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_remove_link(&mddev->kobj, nm);
+ if (sysfs_create_link(&mddev->kobj,
+ &rdev->kobj, nm))
+ printk(KERN_WARNING
+ "md/raid1: cannot register "
+ "%s for %s\n",
+ nm, mdname(mddev));
}
+ if (rdev)
+ newmirrors[d2++].rdev = rdev;
+ }
kfree(conf->mirrors);
conf->mirrors = newmirrors;
kfree(conf->poolinfo);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a95ada1cfac4..25a96c42bdb0 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -227,7 +227,7 @@ static void raid_end_bio_io(r10bio_t *r10_bio)
{
struct bio *bio = r10_bio->master_bio;
- bio_endio(bio, bio->bi_size,
+ bio_endio(bio,
test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO);
free_r10bio(r10_bio);
}
@@ -243,15 +243,13 @@ static inline void update_head_pos(int slot, r10bio_t *r10_bio)
r10_bio->devs[slot].addr + (r10_bio->sectors);
}
-static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid10_end_read_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
int slot, dev;
conf_t *conf = mddev_to_conf(r10_bio->mddev);
- if (bio->bi_size)
- return 1;
slot = r10_bio->read_slot;
dev = r10_bio->devs[slot].devnum;
@@ -284,19 +282,15 @@ static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int
}
rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
- return 0;
}
-static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid10_end_write_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
int slot, dev;
conf_t *conf = mddev_to_conf(r10_bio->mddev);
- if (bio->bi_size)
- return 1;
-
for (slot = 0; slot < conf->copies; slot++)
if (r10_bio->devs[slot].bio == bio)
break;
@@ -339,7 +333,6 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in
}
rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
- return 0;
}
@@ -453,7 +446,7 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
* If near_copies == raid_disk, there are no striping issues,
* but in that case, the function isn't called at all.
*/
-static int raid10_mergeable_bvec(request_queue_t *q, struct bio *bio,
+static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio,
struct bio_vec *bio_vec)
{
mddev_t *mddev = q->queuedata;
@@ -595,7 +588,7 @@ static void unplug_slaves(mddev_t *mddev)
for (i=0; i<mddev->raid_disks; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
- request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+ struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
@@ -610,7 +603,7 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_unlock();
}
-static void raid10_unplug(request_queue_t *q)
+static void raid10_unplug(struct request_queue *q)
{
mddev_t *mddev = q->queuedata;
@@ -618,7 +611,7 @@ static void raid10_unplug(request_queue_t *q)
md_wakeup_thread(mddev->thread);
}
-static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid10_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
mddev_t *mddev = q->queuedata;
@@ -630,7 +623,7 @@ static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
- request_queue_t *r_queue = bdev_get_queue(bdev);
+ struct request_queue *r_queue = bdev_get_queue(bdev);
if (!r_queue->issue_flush_fn)
ret = -EOPNOTSUPP;
@@ -658,7 +651,7 @@ static int raid10_congested(void *data, int bits)
for (i = 0; i < mddev->raid_disks && ret == 0; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
- request_queue_t *q = bdev_get_queue(rdev->bdev);
+ struct request_queue *q = bdev_get_queue(rdev->bdev);
ret |= bdi_congested(&q->backing_dev_info, bits);
}
@@ -772,7 +765,7 @@ static void unfreeze_array(conf_t *conf)
spin_unlock_irq(&conf->resync_lock);
}
-static int make_request(request_queue_t *q, struct bio * bio)
+static int make_request(struct request_queue *q, struct bio * bio)
{
mddev_t *mddev = q->queuedata;
conf_t *conf = mddev_to_conf(mddev);
@@ -787,7 +780,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
unsigned long flags;
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -819,7 +812,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
" or bigger than %dk %llu %d\n", chunk_sects/2,
(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
@@ -917,6 +910,13 @@ static int make_request(request_queue_t *q, struct bio * bio)
bio_list_add(&bl, mbio);
}
+ if (unlikely(!atomic_read(&r10_bio->remaining))) {
+ /* the array is dead */
+ md_write_end(mddev);
+ raid_end_bio_io(r10_bio);
+ return 0;
+ }
+
bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0);
spin_lock_irqsave(&conf->device_lock, flags);
bio_list_merge(&conf->pending_bio_list, &bl);
@@ -1148,15 +1148,12 @@ abort:
}
-static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_read(struct bio *bio, int error)
{
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
conf_t *conf = mddev_to_conf(r10_bio->mddev);
int i,d;
- if (bio->bi_size)
- return 1;
-
for (i=0; i<conf->copies; i++)
if (r10_bio->devs[i].bio == bio)
break;
@@ -1185,10 +1182,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
reschedule_retry(r10_bio);
}
rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
- return 0;
}
-static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_write(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
@@ -1196,9 +1192,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
conf_t *conf = mddev_to_conf(mddev);
int i,d;
- if (bio->bi_size)
- return 1;
-
for (i = 0; i < conf->copies; i++)
if (r10_bio->devs[i].bio == bio)
break;
@@ -1221,7 +1214,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
}
}
rdev_dec_pending(conf->mirrors[d].rdev, mddev);
- return 0;
}
/*
@@ -1367,7 +1359,7 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
if (test_bit(R10BIO_Uptodate, &r10_bio->state))
generic_make_request(wbio);
else
- bio_endio(wbio, wbio->bi_size, -EIO);
+ bio_endio(wbio, -EIO);
}
@@ -1557,7 +1549,6 @@ static void raid10d(mddev_t *mddev)
bio = r10_bio->devs[r10_bio->read_slot].bio;
r10_bio->devs[r10_bio->read_slot].bio =
mddev->ro ? IO_BLOCKED : NULL;
- bio_put(bio);
mirror = read_balance(conf, r10_bio);
if (mirror == -1) {
printk(KERN_ALERT "raid10: %s: unrecoverable I/O"
@@ -1565,8 +1556,10 @@ static void raid10d(mddev_t *mddev)
bdevname(bio->bi_bdev,b),
(unsigned long long)r10_bio->sector);
raid_end_bio_io(r10_bio);
+ bio_put(bio);
} else {
const int do_sync = bio_sync(r10_bio->master_bio);
+ bio_put(bio);
rdev = conf->mirrors[mirror].rdev;
if (printk_ratelimit())
printk(KERN_ERR "raid10: %s: redirecting sector %llu to"
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0b66afef2d82..caaca9e178bc 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -108,12 +108,11 @@ static void return_io(struct bio *return_bi)
{
struct bio *bi = return_bi;
while (bi) {
- int bytes = bi->bi_size;
return_bi = bi->bi_next;
bi->bi_next = NULL;
bi->bi_size = 0;
- bi->bi_end_io(bi, bytes,
+ bi->bi_end_io(bi,
test_bit(BIO_UPTODATE, &bi->bi_flags)
? 0 : -EIO);
bi = return_bi;
@@ -289,7 +288,7 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, in
}
static void unplug_slaves(mddev_t *mddev);
-static void raid5_unplug_device(request_queue_t *q);
+static void raid5_unplug_device(struct request_queue *q);
static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks,
int pd_idx, int noblock)
@@ -382,10 +381,10 @@ static unsigned long get_stripe_work(struct stripe_head *sh)
return pending;
}
-static int
-raid5_end_read_request(struct bio *bi, unsigned int bytes_done, int error);
-static int
-raid5_end_write_request (struct bio *bi, unsigned int bytes_done, int error);
+static void
+raid5_end_read_request(struct bio *bi, int error);
+static void
+raid5_end_write_request(struct bio *bi, int error);
static void ops_run_io(struct stripe_head *sh)
{
@@ -493,12 +492,12 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
if (frombio)
tx = async_memcpy(page, bio_page, page_offset,
b_offset, clen,
- ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
+ ASYNC_TX_DEP_ACK,
tx, NULL, NULL);
else
tx = async_memcpy(bio_page, page, b_offset,
page_offset, clen,
- ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
+ ASYNC_TX_DEP_ACK,
tx, NULL, NULL);
}
if (clen < len) /* hit end of page */
@@ -514,7 +513,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
struct stripe_head *sh = stripe_head_ref;
struct bio *return_bi = NULL;
raid5_conf_t *conf = sh->raid_conf;
- int i, more_to_read = 0;
+ int i;
pr_debug("%s: stripe %llu\n", __FUNCTION__,
(unsigned long long)sh->sector);
@@ -522,16 +521,14 @@ static void ops_complete_biofill(void *stripe_head_ref)
/* clear completed biofills */
for (i = sh->disks; i--; ) {
struct r5dev *dev = &sh->dev[i];
- /* check if this stripe has new incoming reads */
- if (dev->toread)
- more_to_read++;
/* acknowledge completion of a biofill operation */
- /* and check if we need to reply to a read request
- */
- if (test_bit(R5_Wantfill, &dev->flags) && !dev->toread) {
+ /* and check if we need to reply to a read request,
+ * new R5_Wantfill requests are held off until
+ * !test_bit(STRIPE_OP_BIOFILL, &sh->ops.pending)
+ */
+ if (test_and_clear_bit(R5_Wantfill, &dev->flags)) {
struct bio *rbi, *rbi2;
- clear_bit(R5_Wantfill, &dev->flags);
/* The access to dev->read is outside of the
* spin_lock_irq(&conf->device_lock), but is protected
@@ -558,8 +555,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
return_io(return_bi);
- if (more_to_read)
- set_bit(STRIPE_HANDLE, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
}
@@ -951,7 +947,7 @@ static int grow_stripes(raid5_conf_t *conf, int num)
conf->active_name = 0;
sc = kmem_cache_create(conf->cache_name[conf->active_name],
sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!sc)
return 1;
conf->slab_cache = sc;
@@ -1003,7 +999,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
/* Step 1 */
sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!sc)
return -ENOMEM;
@@ -1113,8 +1109,7 @@ static void shrink_stripes(raid5_conf_t *conf)
conf->slab_cache = NULL;
}
-static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
- int error)
+static void raid5_end_read_request(struct bio * bi, int error)
{
struct stripe_head *sh = bi->bi_private;
raid5_conf_t *conf = sh->raid_conf;
@@ -1123,8 +1118,6 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
char b[BDEVNAME_SIZE];
mdk_rdev_t *rdev;
- if (bi->bi_size)
- return 1;
for (i=0 ; i<disks; i++)
if (bi == &sh->dev[i].req)
@@ -1135,7 +1128,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
uptodate);
if (i == disks) {
BUG();
- return 0;
+ return;
}
if (uptodate) {
@@ -1188,20 +1181,15 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
- return 0;
}
-static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
- int error)
+static void raid5_end_write_request (struct bio *bi, int error)
{
struct stripe_head *sh = bi->bi_private;
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks, i;
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
- if (bi->bi_size)
- return 1;
-
for (i=0 ; i<disks; i++)
if (bi == &sh->dev[i].req)
break;
@@ -1211,7 +1199,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
uptodate);
if (i == disks) {
BUG();
- return 0;
+ return;
}
if (!uptodate)
@@ -1222,7 +1210,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
- return 0;
}
@@ -2541,7 +2528,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
struct dma_async_tx_descriptor *tx = NULL;
clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
for (i = 0; i < sh->disks; i++)
- if (i != sh->pd_idx && (r6s && i != r6s->qd_idx)) {
+ if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) {
int dd_idx, pd_idx, j;
struct stripe_head *sh2;
@@ -2574,7 +2561,8 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
for (j = 0; j < conf->raid_disks; j++)
if (j != sh2->pd_idx &&
- (r6s && j != r6s->qd_idx) &&
+ (!r6s || j != raid6_next_disk(sh2->pd_idx,
+ sh2->disks)) &&
!test_bit(R5_Expanded, &sh2->dev[j].flags))
break;
if (j == conf->raid_disks) {
@@ -2583,12 +2571,12 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
}
release_stripe(sh2);
- /* done submitting copies, wait for them to complete */
- if (i + 1 >= sh->disks) {
- async_tx_ack(tx);
- dma_wait_for_async_tx(tx);
- }
}
+ /* done submitting copies, wait for them to complete */
+ if (tx) {
+ async_tx_ack(tx);
+ dma_wait_for_async_tx(tx);
+ }
}
/*
@@ -2855,7 +2843,7 @@ static void handle_stripe5(struct stripe_head *sh)
sh->disks = conf->raid_disks;
sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
conf->raid_disks);
- s.locked += handle_write_operations5(sh, 0, 1);
+ s.locked += handle_write_operations5(sh, 1, 1);
} else if (s.expanded &&
!test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
clear_bit(STRIPE_EXPAND_READY, &sh->state);
@@ -3182,7 +3170,7 @@ static void unplug_slaves(mddev_t *mddev)
for (i=0; i<mddev->raid_disks; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
- request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+ struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
@@ -3197,7 +3185,7 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_unlock();
}
-static void raid5_unplug_device(request_queue_t *q)
+static void raid5_unplug_device(struct request_queue *q)
{
mddev_t *mddev = q->queuedata;
raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3216,7 +3204,7 @@ static void raid5_unplug_device(request_queue_t *q)
unplug_slaves(mddev);
}
-static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid5_issue_flush(struct request_queue *q, struct gendisk *disk,
sector_t *error_sector)
{
mddev_t *mddev = q->queuedata;
@@ -3228,7 +3216,7 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
- request_queue_t *r_queue = bdev_get_queue(bdev);
+ struct request_queue *r_queue = bdev_get_queue(bdev);
if (!r_queue->issue_flush_fn)
ret = -EOPNOTSUPP;
@@ -3267,7 +3255,7 @@ static int raid5_congested(void *data, int bits)
/* We want read requests to align with chunks where possible,
* but write requests don't need to.
*/
-static int raid5_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
{
mddev_t *mddev = q->queuedata;
sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
@@ -3342,7 +3330,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
* first).
* If the read failed..
*/
-static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
+static void raid5_align_endio(struct bio *bi, int error)
{
struct bio* raid_bi = bi->bi_private;
mddev_t *mddev;
@@ -3350,8 +3338,6 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
mdk_rdev_t *rdev;
- if (bi->bi_size)
- return 1;
bio_put(bi);
mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata;
@@ -3362,22 +3348,21 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
rdev_dec_pending(rdev, conf->mddev);
if (!error && uptodate) {
- bio_endio(raid_bi, bytes, 0);
+ bio_endio(raid_bi, 0);
if (atomic_dec_and_test(&conf->active_aligned_reads))
wake_up(&conf->wait_for_stripe);
- return 0;
+ return;
}
pr_debug("raid5_align_endio : io error...handing IO for a retry\n");
add_bio_to_retry(raid_bi, conf);
- return 0;
}
static int bio_fits_rdev(struct bio *bi)
{
- request_queue_t *q = bdev_get_queue(bi->bi_bdev);
+ struct request_queue *q = bdev_get_queue(bi->bi_bdev);
if ((bi->bi_size>>9) > q->max_sectors)
return 0;
@@ -3396,7 +3381,7 @@ static int bio_fits_rdev(struct bio *bi)
}
-static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
+static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
{
mddev_t *mddev = q->queuedata;
raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3466,7 +3451,7 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
}
-static int make_request(request_queue_t *q, struct bio * bi)
+static int make_request(struct request_queue *q, struct bio * bi)
{
mddev_t *mddev = q->queuedata;
raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3478,7 +3463,7 @@ static int make_request(request_queue_t *q, struct bio * bi)
int remaining;
if (unlikely(bio_barrier(bi))) {
- bio_endio(bi, bi->bi_size, -EOPNOTSUPP);
+ bio_endio(bi, -EOPNOTSUPP);
return 0;
}
@@ -3594,12 +3579,11 @@ static int make_request(request_queue_t *q, struct bio * bi)
remaining = --bi->bi_phys_segments;
spin_unlock_irq(&conf->device_lock);
if (remaining == 0) {
- int bytes = bi->bi_size;
if ( rw == WRITE )
md_write_end(mddev);
- bi->bi_size = 0;
- bi->bi_end_io(bi, bytes,
+
+ bi->bi_end_io(bi,
test_bit(BIO_UPTODATE, &bi->bi_flags)
? 0 : -EIO);
}
@@ -3877,10 +3861,8 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
remaining = --raid_bio->bi_phys_segments;
spin_unlock_irq(&conf->device_lock);
if (remaining == 0) {
- int bytes = raid_bio->bi_size;
- raid_bio->bi_size = 0;
- raid_bio->bi_end_io(raid_bio, bytes,
+ raid_bio->bi_end_io(raid_bio,
test_bit(BIO_UPTODATE, &raid_bio->bi_flags)
? 0 : -EIO);
}
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 624b21cef5b3..dd9bd4310c84 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -69,19 +69,89 @@ source "drivers/media/common/Kconfig"
config VIDEO_TUNER
tristate
depends on I2C
+ 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
+
+menuconfig VIDEO_TUNER_CUSTOMIZE
+ bool "Customize analog tuner modules to build"
+ depends on VIDEO_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 devices which cannot be tuned due to lack of
+ driver support
+
+ If unsure say N.
+
+if VIDEO_TUNER_CUSTOMIZE
+
+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+8275(a) tuner combo"
+ depends on I2C
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+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.
+
+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.
+
+config TUNER_SIMPLE
+ tristate "Simple tuner support"
+ depends on I2C
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for various simple tuners.
+
+endif # VIDEO_TUNER_CUSTOMIZE
-config VIDEO_BUF
+config VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DMA_SG
depends on PCI
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_VMALLOC
+ select VIDEOBUF_GEN
tristate
-config VIDEO_BUF_DVB
+config VIDEOBUF_DVB
tristate
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
config VIDEO_BTCX
tristate
+config VIDEO_IR_I2C
+ tristate
+
config VIDEO_IR
tristate
+ select VIDEO_IR_I2C if I2C
config VIDEO_TVEEPROM
tristate
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 5c63c8e24ee7..c5092ef1082f 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -5,5 +5,5 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
depends on VIDEO_DEV
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_SAA7146
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index fcb194135627..e7c3ab951a44 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/jiffies.h>
#include <media/ir-common.h>
@@ -107,21 +106,20 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
}
/* -------------------------------------------------------------------------- */
-
+/* extract mask bits out of data and pack them into the result */
u32 ir_extract_bits(u32 data, u32 mask)
{
- int mbit, vbit;
- u32 value;
+ u32 vbit = 1, value = 0;
+
+ do {
+ if (mask&1) {
+ if (data&1)
+ value |= vbit;
+ vbit<<=1;
+ }
+ data>>=1;
+ } while (mask>>=1);
- value = 0;
- vbit = 0;
- for (mbit = 0; mbit < 32; mbit++) {
- if (!(mask & ((u32)1 << mbit)))
- continue;
- if (data & ((u32)1 << mbit))
- value |= (1 << vbit);
- vbit++;
- }
return value;
}
@@ -346,8 +344,8 @@ void ir_rc5_timer_end(unsigned long data)
}
/* Set/reset key-up timer */
- timeout = current_jiffies + (500 + ir->rc5_key_timeout
- * HZ) / 1000;
+ timeout = current_jiffies +
+ msecs_to_jiffies(ir->rc5_key_timeout);
mod_timer(&ir->timer_keyup, timeout);
/* Save code for repeat test */
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index cbd1184b5219..aefcf28da1ca 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/input.h>
#include <media/ir-common.h>
@@ -1783,3 +1782,64 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
+
+/* DViCO FUSION HDTV MCE remote */
+IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
+
+ [ 0x0b ] = KEY_1,
+ [ 0x17 ] = KEY_2,
+ [ 0x1b ] = KEY_3,
+ [ 0x07 ] = KEY_4,
+ [ 0x50 ] = KEY_5,
+ [ 0x54 ] = KEY_6,
+ [ 0x48 ] = KEY_7,
+ [ 0x4c ] = KEY_8,
+ [ 0x58 ] = KEY_9,
+ [ 0x03 ] = KEY_0,
+
+ [ 0x5e ] = KEY_OK,
+ [ 0x51 ] = KEY_UP,
+ [ 0x53 ] = KEY_DOWN,
+ [ 0x5b ] = KEY_LEFT,
+ [ 0x5f ] = KEY_RIGHT,
+
+ [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */
+ [ 0x0e ] = KEY_MP3,
+ [ 0x1a ] = KEY_DVD,
+ [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */
+ [ 0x16 ] = KEY_SETUP,
+ [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */
+ [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */
+
+ [ 0x49 ] = KEY_BACK,
+ [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */
+ [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */
+ [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */
+
+ [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */
+ [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */
+ [ 0x42 ] = KEY_ENTER, /* Labeled START with a green
+ * MS windows logo on remote */
+
+ [ 0x15 ] = KEY_VOLUMEUP,
+ [ 0x05 ] = KEY_VOLUMEDOWN,
+ [ 0x11 ] = KEY_CHANNELUP,
+ [ 0x09 ] = KEY_CHANNELDOWN,
+
+ [ 0x52 ] = KEY_CAMERA,
+ [ 0x5a ] = KEY_TUNER,
+ [ 0x19 ] = KEY_OPEN,
+
+ [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */
+ [ 0x1f ] = KEY_ZOOM,
+
+ [ 0x43 ] = KEY_REWIND,
+ [ 0x47 ] = KEY_PLAYPAUSE,
+ [ 0x4f ] = KEY_FASTFORWARD,
+ [ 0x57 ] = KEY_MUTE,
+ [ 0x0d ] = KEY_STOP,
+ [ 0x01 ] = KEY_RECORD,
+ [ 0x4e ] = KEY_POWER,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index ef3e54cd9407..365a22118a09 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -27,7 +27,7 @@ static int saa7146_num;
unsigned int saa7146_debug;
-module_param(saa7146_debug, int, 0644);
+module_param(saa7146_debug, uint, 0644);
MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
#if 0
@@ -100,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
* general helper functions
****************************************************************************/
-/* this is videobuf_vmalloc_to_sg() from video-buf.c
+/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
may be triggered on highmem machines */
static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
@@ -130,10 +130,10 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
/********************************************************************************/
/* common page table functions */
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
{
int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
- char *mem = vmalloc_32(length);
+ void *mem = vmalloc_32(length);
int slen = 0;
if (NULL == mem)
@@ -168,7 +168,7 @@ err_null:
return NULL;
}
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
{
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
saa7146_pgtable_free(pci, pt);
@@ -248,10 +248,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
static irqreturn_t interrupt_hw(int irq, void *dev_id)
{
struct saa7146_dev *dev = dev_id;
- u32 isr = 0;
+ u32 isr;
+ u32 ack_isr;
/* read out the interrupt status register */
- isr = saa7146_read(dev, ISR);
+ ack_isr = isr = saa7146_read(dev, ISR);
/* is this our interrupt? */
if ( 0 == isr ) {
@@ -259,8 +260,6 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
return IRQ_NONE;
}
- saa7146_write(dev, ISR, isr);
-
if( 0 != (dev->ext)) {
if( 0 != (dev->ext->irq_mask & isr )) {
if( 0 != dev->ext->irq_func ) {
@@ -283,21 +282,16 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
isr &= ~MASK_28;
}
if (0 != (isr & (MASK_16|MASK_17))) {
- u32 status = saa7146_read(dev, I2C_STATUS);
- if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
- SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
- /* only wake up if we expect something */
- if( 0 != dev->i2c_op ) {
- u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2;
- u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f;
- DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr));
- dev->i2c_op = 0;
- wake_up(&dev->i2c_wq);
- } else {
- DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
- }
+ SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+ /* only wake up if we expect something */
+ if (0 != dev->i2c_op) {
+ dev->i2c_op = 0;
+ wake_up(&dev->i2c_wq);
} else {
- DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
+ u32 psr = saa7146_read(dev, PSR);
+ u32 ssr = saa7146_read(dev, SSR);
+ printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+ dev->name, isr, psr, ssr);
}
isr &= ~(MASK_16|MASK_17);
}
@@ -306,6 +300,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
ERR(("disabling interrupt source(s)!\n"));
SAA7146_IER_DISABLE(dev,isr);
}
+ saa7146_write(dev, ISR, ack_isr);
return IRQ_HANDLED;
}
@@ -548,7 +543,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
EXPORT_SYMBOL_GPL(saa7146_setgpio);
-EXPORT_SYMBOL_GPL(saa7146_i2c_transfer);
EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
EXPORT_SYMBOL_GPL(saa7146_debug);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index b4770aecc01d..67d1b1b1b254 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
struct saa7146_buf *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
DEB_EE(("dev:%p, buf:%p\n",dev,buf));
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
buf->vb.state = STATE_NEEDS_INIT;
}
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 8c85efc26527..7e7689afae62 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -202,7 +202,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
/* a signal arrived */
return -ERESTARTSYS;
- printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n");
+ printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
+ dev->name, __FUNCTION__);
return -EIO;
}
status = saa7146_read(dev, I2C_STATUS);
@@ -219,7 +220,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
break;
}
if (time_after(jiffies,timeout)) {
- printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n");
+ printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
+ dev->name, __FUNCTION__);
return -EIO;
}
}
@@ -235,7 +237,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
/* this is normal when probing the bus
* (no answer from nonexisistant device...)
*/
- DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n"));
+ printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
+ dev->name, __FUNCTION__);
return -EIO;
}
if (++trial < 50 && short_delay)
@@ -246,8 +249,16 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
}
/* give a detailed status report */
- if ( 0 != (status & SAA7146_I2C_ERR)) {
-
+ if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
+ SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
+ SAA7146_I2C_AL | SAA7146_I2C_ERR |
+ SAA7146_I2C_BUSY)) ) {
+
+ if ( 0 == (status & SAA7146_I2C_ERR) ||
+ 0 == (status & SAA7146_I2C_BUSY) ) {
+ /* it may take some time until ERR goes high - ignore */
+ DEB_I2C(("unexpected i2c status %04x\n", status));
+ }
if( 0 != (status & SAA7146_I2C_SPERR) ) {
DEB_I2C(("error due to invalid start/stop condition.\n"));
}
@@ -277,7 +288,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
return 0;
}
-int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
+static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
{
int i = 0, count = 0;
u32* buffer = dev->d_i2c.cpu_addr;
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 063608462ebe..6103484e4442 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf
/* we don't wait here for the first field anymore. this is different from the video
capture and might cause that the first buffer is only half filled (with only
one field). but since this is some sort of streaming data, this is not that negative.
- but by doing this, we can use the whole engine from video-buf.c... */
+ but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
/*
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
@@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
saa7146_dma_free(dev,q,buf);
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
err = videobuf_iolock(q,&buf->vb, NULL);
if (err)
goto oops;
- err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
+ err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
+ dma->sglist, dma->sglen);
if (0 != err)
return err;
}
@@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
fh->vbi_fmt.start[1] = 312;
fh->vbi_fmt.count[1] = 16;
- videobuf_queue_init(&fh->vbi_q, &vbi_qops,
+ videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e3d04a4cef4d..f245a3b2ef47 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
struct pci_dev *pci = dev->pci;
- struct scatterlist *list = buf->vb.dma.sglist;
- int length = buf->vb.dma.sglen;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ struct scatterlist *list = dma->sglist;
+ int length = dma->sglen;
struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
@@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
/* if we have a user buffer, the first page may not be
aligned to a page boundary. */
- pt1->offset = buf->vb.dma.sglist->offset;
+ pt1->offset = list->offset;
pt2->offset = pt1->offset+o1;
pt3->offset = pt1->offset+o2;
@@ -889,9 +890,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
DEB_EE(("VIDIOC_QUERYCAP\n"));
- strcpy(cap->driver, "saa7146 v4l2");
- strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+ strcpy((char *)cap->driver, "saa7146 v4l2");
+ strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+ sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = SAA7146_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
@@ -968,7 +969,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
}
memset(f,0,sizeof(*f));
f->index = index;
- strlcpy(f->description,formats[index].name,sizeof(f->description));
+ strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
f->pixelformat = formats[index].pixelformat;
break;
}
@@ -1211,6 +1212,8 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
mutex_unlock(&q->lock);
return err;
}
+
+ gbuffers = err;
memset(mbuf,0,sizeof(*mbuf));
mbuf->frames = gbuffers;
mbuf->size = gbuffers * gbufsize;
@@ -1411,7 +1414,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
- videobuf_queue_init(&fh->video_q, &video_qops,
+ videobuf_queue_pci_init(&fh->video_q, &video_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index a0dcd59da76e..3197aeb61d1f 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,7 +1,7 @@
config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
depends on DVB_CORE && I2C
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index bff00b58bf65..e97ff60a1eff 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
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/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index b02c2fd65baa..0378fd646591 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -500,13 +500,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
/* try the air atsc 3nd generation (lgdt3303) */
if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC3;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
} else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 02a0ea6e1c17..6bf858a436c9 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -135,6 +135,13 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
int i, ret = 0;
+ /* Some drivers use 1 byte or 0 byte reads as probes, which this
+ * driver doesn't support. These probes will always fail, so this
+ * hack makes them always succeed. If one knew how, it would of
+ * course be better to actually do the read. */
+ if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
+ return 1;
+
if (mutex_lock_interruptible(&fc->i2c_mutex))
return -ERESTARTSYS;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index cfd6fb729a61..ea666174e988 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,7 +7,7 @@ config DVB_BT8XX
select DVB_CX24110 if !DVB_FE_CUSTOMISE
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 9d197efb481d..84cf70504d17 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index df72b4b8ee10..eca602d9b3de 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <asm/io.h>
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index f685bc129609..d593bc145628 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -149,11 +149,10 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
void bt878_stop(struct bt878 *bt);
#if defined(__powerpc__) /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
+static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
{
- __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val),
- "r"(addr));
- __asm__ __volatile__("eieio":::"memory");
+ st_le32(addr, val);
+ eieio();
}
#define bmtwrite(dat,adr) io_st_le32((adr),(dat))
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index e908e3cf1e50..b7a17e69ca4d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1652,7 +1652,7 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
static int dst_tune_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status)
{
struct dst_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 4f1c09bee538..dedd30a8356b 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -21,7 +21,6 @@
#include <linux/bitops.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -611,7 +610,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) {
dvb_attach(dvb_pll_attach, card->fe, 0x61,
- card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
+ card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
dprintk ("dvb_bt8xx: lgdt330x detected\n");
}
break;
@@ -692,6 +691,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_PC_HDTV:
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+ if (card->fe != NULL)
+ dvb_attach(dvb_pll_attach, card->fe, 0x61,
+ card->i2c_adapter, DVB_PLL_FCV1236D);
break;
}
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
index c51aece20f9f..d762d8cb0cf1 100644
--- a/drivers/media/dvb/cinergyT2/Makefile
+++ b/drivers/media/dvb/cinergyT2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index b40af48a2edb..5a12b5679556 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -548,19 +548,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
- unsigned int mask = 0;
+ unsigned int mask = 0;
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
- if (cinergyt2->pending_fe_events != 0)
+ if (cinergyt2->pending_fe_events != 0)
mask |= (POLLIN | POLLRDNORM | POLLPRI);
mutex_unlock(&cinergyt2->sem);
- return mask;
+ return mask;
}
@@ -829,7 +829,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
input_dev->id.version = 1;
- input_dev->cdev.dev = &cinergyt2->udev->dev;
+ input_dev->dev.parent = &cinergyt2->udev->dev;
err = input_register_device(input_dev);
if (err) {
@@ -905,12 +905,11 @@ static int cinergyt2_probe (struct usb_interface *intf,
struct cinergyt2 *cinergyt2;
int err;
- if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
+ if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
dprintk(1, "out of memory?!?\n");
return -ENOMEM;
}
- memset (cinergyt2, 0, sizeof (struct cinergyt2));
usb_set_intfdata (intf, (void *) cinergyt2);
mutex_init(&cinergyt2->sem);
@@ -1000,18 +999,17 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
return -ERESTARTSYS;
- if (1) {
- cinergyt2_suspend_rc(cinergyt2);
- cancel_rearming_delayed_work(&cinergyt2->query_work);
+ cinergyt2_suspend_rc(cinergyt2);
+ cancel_rearming_delayed_work(&cinergyt2->query_work);
- mutex_lock(&cinergyt2->sem);
- if (cinergyt2->streaming)
- cinergyt2_stop_stream_xfer(cinergyt2);
- cinergyt2_sleep(cinergyt2, 1);
- mutex_unlock(&cinergyt2->sem);
- }
+ mutex_lock(&cinergyt2->sem);
+ if (cinergyt2->streaming)
+ cinergyt2_stop_stream_xfer(cinergyt2);
+ cinergyt2_sleep(cinergyt2, 1);
+ mutex_unlock(&cinergyt2->sem);
mutex_unlock(&cinergyt2->wq_sem);
+
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 275df65fde99..f94bc31e3b33 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -24,7 +24,6 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
@@ -97,7 +96,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
if (avail > todo)
avail = todo;
- ret = dvb_ringbuffer_read(src, buf, avail, 1);
+ ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
if (ret < 0)
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 2a03bf53cb29..084a508a03da 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -32,11 +32,11 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
+#include <linux/kthread.h>
#include "dvb_ca_en50221.h"
#include "dvb_ringbuffer.h"
@@ -140,13 +140,7 @@ struct dvb_ca_private {
wait_queue_head_t wait_queue;
/* PID of the monitoring thread */
- pid_t thread_pid;
-
- /* Wait queue used when shutting thread down */
- wait_queue_head_t thread_queue;
-
- /* Flag indicating when thread should exit */
- unsigned int exit:1;
+ struct task_struct *thread;
/* Flag indicating if the CA device is open */
unsigned int open:1;
@@ -175,7 +169,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e
* @param nlen Number of bytes in needle.
* @return Pointer into haystack needle was found at, or NULL if not found.
*/
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
{
int i;
@@ -482,7 +476,7 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
}
/* check it contains the correct DVB string */
- dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+ dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
if (dvb_str == NULL)
return -EINVAL;
if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +507,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
ca->slot_info[slot].config_option = tuple[0] & 0x3f;
/* OK, check it contains the correct strings */
- if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
- (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+ if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+ (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
break;
got_cftableentry = 1;
@@ -902,28 +896,10 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
ca->wakeup = 1;
mb();
- wake_up_interruptible(&ca->thread_queue);
+ wake_up_process(ca->thread);
}
/**
- * Used by the CA thread to determine if an early wakeup is necessary
- *
- * @param ca CA instance.
- */
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca)
-{
- if (ca->wakeup) {
- ca->wakeup = 0;
- return 1;
- }
- if (ca->exit)
- return 1;
-
- return 0;
-}
-
-
-/**
* Update the delay used by the thread.
*
* @param ca CA instance.
@@ -982,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
static int dvb_ca_en50221_thread(void *data)
{
struct dvb_ca_private *ca = data;
- char name[15];
int slot;
int flags;
int status;
@@ -991,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data)
dprintk("%s\n", __FUNCTION__);
- /* setup kernel thread */
- snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
-
- lock_kernel();
- daemonize(name);
- sigfillset(&current->blocked);
- unlock_kernel();
-
/* choose the correct initial delay */
dvb_ca_en50221_thread_update_delay(ca);
/* main loop */
- while (!ca->exit) {
+ while (!kthread_should_stop()) {
/* sleep for a bit */
- if (!ca->wakeup) {
- flags = wait_event_interruptible_timeout(ca->thread_queue,
- dvb_ca_en50221_thread_should_wakeup(ca),
- ca->delay);
- if ((flags == -ERESTARTSYS) || ca->exit) {
- /* got signal or quitting */
- break;
- }
+ while (!ca->wakeup) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(ca->delay);
+ if (kthread_should_stop())
+ return 0;
}
ca->wakeup = 0;
@@ -1181,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data)
}
}
- /* completed */
- ca->thread_pid = 0;
- mb();
- wake_up_interruptible(&ca->thread_queue);
return 0;
}
@@ -1300,7 +1260,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
struct dvb_ca_private *ca = dvbdev->priv;
u8 slot, connection_id;
int status;
- char fragbuf[HOST_LINK_BUF_SIZE];
+ u8 fragbuf[HOST_LINK_BUF_SIZE];
int fragpos = 0;
int fraglen;
unsigned long timeout;
@@ -1486,7 +1446,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
}
if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
- buf + pktlen, fraglen, 1)) < 0) {
+ (u8 *)buf + pktlen, fraglen, 1)) < 0) {
goto exit;
}
pktlen += fraglen;
@@ -1536,8 +1496,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
return -EIO;
err = dvb_generic_open(inode, file);
- if (err < 0)
+ if (err < 0) {
+ module_put(ca->pub->owner);
return err;
+ }
for (i = 0; i < ca->slot_count; i++) {
@@ -1570,7 +1532,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_ca_private *ca = dvbdev->priv;
- int err = 0;
+ int err;
dprintk("%s\n", __FUNCTION__);
@@ -1582,7 +1544,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
module_put(ca->pub->owner);
- return 0;
+ return err;
}
@@ -1682,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
goto error;
}
init_waitqueue_head(&ca->wait_queue);
- ca->thread_pid = 0;
- init_waitqueue_head(&ca->thread_queue);
- ca->exit = 0;
ca->open = 0;
ca->wakeup = 0;
ca->next_read_slot = 0;
@@ -1710,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
mb();
/* create a kthread for monitoring this CA device */
-
- ret = kernel_thread(dvb_ca_en50221_thread, ca, 0);
-
- if (ret < 0) {
- printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+ ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+ ca->dvbdev->adapter->num, ca->dvbdev->id);
+ if (IS_ERR(ca->thread)) {
+ ret = PTR_ERR(ca->thread);
+ printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+ ret);
goto error;
}
- ca->thread_pid = ret;
return 0;
error:
@@ -1748,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
dprintk("%s\n", __FUNCTION__);
/* shutdown the thread if there was one */
- if (ca->thread_pid) {
- if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
- printk("dvb_ca_release adapter %d: thread PID %d already died\n",
- ca->dvbdev->adapter->num, ca->thread_pid);
- } else {
- ca->exit = 1;
- mb();
- dvb_ca_en50221_thread_wakeup(ca);
- wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
- }
- }
+ kthread_stop(ca->thread);
for (i = 0; i < ca->slot_count; i++) {
dvb_ca_en50221_slot_shutdown(ca, i);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d8d1c3df863..7959020f9317 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
{
struct dvb_demux_feed *feed;
- struct list_head *pos, *head = &demux->feed_list;
u16 pid = ts_pid(buf);
int dvr_done = 0;
- list_for_each(pos, head) {
- feed = list_entry(pos, struct dvb_demux_feed, list_head);
-
+ list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
@@ -1068,7 +1065,7 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
- dvb_dmx_swfilter(dvbdemux, buf, count);
+ dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
mutex_unlock(&dvbdemux->mutex);
if (signal_pending(current))
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index b6c7f6610ec5..b203640ef1c5 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
@@ -43,7 +42,7 @@
#include "dvbdev.h"
static int dvb_frontend_debug;
-static int dvb_shutdown_timeout = 5;
+static int dvb_shutdown_timeout;
static int dvb_force_auto_inversion;
static int dvb_override_tune_delay;
static int dvb_powerdown_on_sleep = 1;
@@ -138,7 +137,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
dprintk ("%s\n", __FUNCTION__);
- if (down_interruptible (&events->sem))
+ if (mutex_lock_interruptible (&events->mtx))
return;
wp = (events->eventw + 1) % MAX_EVENT;
@@ -159,7 +158,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
events->eventw = wp;
- up (&events->sem);
+ mutex_unlock(&events->mtx);
e->status = status;
@@ -197,7 +196,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
return ret;
}
- if (down_interruptible (&events->sem))
+ if (mutex_lock_interruptible (&events->mtx))
return -ERESTARTSYS;
memcpy (event, &events->events[events->eventr],
@@ -205,7 +204,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
events->eventr = (events->eventr + 1) % MAX_EVENT;
- up (&events->sem);
+ mutex_unlock(&events->mtx);
return 0;
}
@@ -574,10 +573,9 @@ restart:
dvb_frontend_swzigzag(fe);
}
- if (dvb_shutdown_timeout) {
- if (dvb_powerdown_on_sleep)
- if (fe->ops.set_voltage)
- fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+ if (dvb_powerdown_on_sleep) {
+ if (fe->ops.set_voltage)
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
if (fe->ops.tuner_ops.sleep) {
fe->ops.tuner_ops.sleep(fe);
if (fe->ops.i2c_gate_ctrl)
@@ -697,6 +695,65 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return 0;
}
+static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+ u32 *freq_min, u32 *freq_max)
+{
+ *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+ if (fe->ops.info.frequency_max == 0)
+ *freq_max = fe->ops.tuner_ops.info.frequency_max;
+ else if (fe->ops.tuner_ops.info.frequency_max == 0)
+ *freq_max = fe->ops.info.frequency_max;
+ else
+ *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+ if (*freq_min == 0 || *freq_max == 0)
+ printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
+ fe->dvb->num);
+}
+
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *parms)
+{
+ u32 freq_min;
+ u32 freq_max;
+
+ /* range check: frequency */
+ dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+ if ((freq_min && parms->frequency < freq_min) ||
+ (freq_max && parms->frequency > freq_max)) {
+ printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
+ fe->dvb->num, parms->frequency, freq_min, freq_max);
+ return -EINVAL;
+ }
+
+ /* range check: symbol rate */
+ if (fe->ops.info.type == FE_QPSK) {
+ if ((fe->ops.info.symbol_rate_min &&
+ parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+ (fe->ops.info.symbol_rate_max &&
+ parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+ printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+ fe->dvb->num, parms->u.qpsk.symbol_rate,
+ fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+ return -EINVAL;
+ }
+
+ } else if (fe->ops.info.type == FE_QAM) {
+ if ((fe->ops.info.symbol_rate_min &&
+ parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
+ (fe->ops.info.symbol_rate_max &&
+ parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
+ printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+ fe->dvb->num, parms->u.qam.symbol_rate,
+ fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
@@ -707,7 +764,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
dprintk ("%s\n", __FUNCTION__);
- if (!fe || fepriv->exit)
+ if (fepriv->exit)
return -ENODEV;
if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -722,6 +779,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
+ dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
@@ -883,6 +941,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_SET_FRONTEND: {
struct dvb_frontend_tune_settings fetunesettings;
+ if (dvb_frontend_check_parameters(fe, parg) < 0) {
+ err = -EINVAL;
+ break;
+ }
+
memcpy (&fepriv->parameters, parg,
sizeof (struct dvb_frontend_parameters));
@@ -992,18 +1055,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
dprintk ("%s\n", __FUNCTION__);
- if ((ret = dvb_generic_open (inode, file)) < 0)
- return ret;
-
- if (fe->ops.ts_bus_ctrl) {
- if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) {
- dvb_generic_release (inode, file);
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+ if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
return ret;
- }
}
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if ((ret = dvb_generic_open (inode, file)) < 0)
+ goto err1;
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
/* normal tune mode when opened R/W */
fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
fepriv->tone = -1;
@@ -1011,13 +1071,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
ret = dvb_frontend_start (fe);
if (ret)
- dvb_generic_release (inode, file);
+ goto err2;
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
}
return ret;
+
+err2:
+ dvb_generic_release(inode, file);
+err1:
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl(fe, 0);
+ return ret;
}
static int dvb_frontend_release(struct inode *inode, struct file *file)
@@ -1032,16 +1099,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fepriv->release_jiffies = jiffies;
- if (fe->ops.ts_bus_ctrl)
- fe->ops.ts_bus_ctrl (fe, 0);
-
ret = dvb_generic_release (inode, file);
- if (dvbdev->users==-1 && fepriv->exit==1) {
- fops_put(file->f_op);
- file->f_op = NULL;
- wake_up(&dvbdev->wait_queue);
+ if (dvbdev->users == -1) {
+ if (fepriv->exit == 1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ wake_up(&dvbdev->wait_queue);
+ }
+ if (fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl(fe, 0);
}
+
return ret;
}
@@ -1080,7 +1149,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
init_MUTEX (&fepriv->sem);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
- init_MUTEX (&fepriv->events.sem);
+ mutex_init(&fepriv->events.mtx);
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index f233d78bc364..a5262e852c82 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
#include <linux/dvb/frontend.h>
@@ -61,6 +62,13 @@ struct dvb_tuner_info {
u32 bandwidth_step;
};
+struct analog_parameters {
+ unsigned int frequency;
+ unsigned int mode;
+ unsigned int audmode;
+ u64 std;
+};
+
struct dvb_tuner_ops {
struct dvb_tuner_info info;
@@ -71,6 +79,7 @@ struct dvb_tuner_ops {
/** This is for simple PLLs - set all parameters in one go. */
int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+ int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
@@ -79,7 +88,9 @@ struct dvb_tuner_ops {
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
#define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
int (*get_status)(struct dvb_frontend *fe, u32 *status);
+ int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
/** These are provided seperately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter seperately. */
@@ -103,7 +114,7 @@ struct dvb_frontend_ops {
int (*tune)(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status);
/* get frontend tuning algorithm from the module */
int (*get_frontend_algo)(struct dvb_frontend *fe);
@@ -142,7 +153,7 @@ struct dvb_fe_events {
int eventr;
int overflow;
wait_queue_head_t wait_queue;
- struct semaphore sem;
+ struct mutex mtx;
};
struct dvb_frontend {
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4ebf33a5ffa2..a33eb5988c42 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -347,7 +347,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
{
struct dvb_net_priv *priv = dev->priv;
unsigned long skipped = 0L;
- u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+ const u8 *ts, *ts_end, *from_where = NULL;
+ u8 ts_remain = 0, how_much = 0, new_ts = 1;
struct ethhdr *ethh = NULL;
#ifdef ULE_DEBUG
@@ -356,15 +357,10 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
static unsigned char *ule_where = ule_hist, ule_dump = 0;
#endif
- if (dev == NULL) {
- printk( KERN_ERR "NO netdev struct!\n" );
- return;
- }
-
/* For all TS cells in current buffer.
* Appearently, we are called for every single TS cell.
*/
- for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+ for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
if (new_ts) {
/* We are about to process a new TS cell. */
@@ -799,7 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
}
-static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
+static void dvb_net_sec(struct net_device *dev,
+ const u8 *pkt, int pkt_len)
{
u8 *eth;
struct sk_buff *skb;
@@ -901,7 +898,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
* we rely on the DVB API definition where exactly one complete
* section is delivered in buffer1
*/
- dvb_net_sec (dev, (u8*) buffer1, buffer1_len);
+ dvb_net_sec (dev, buffer1, buffer1_len);
return 0;
}
@@ -1223,10 +1220,17 @@ static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
return &((struct dvb_net_priv*) dev->priv)->stats;
}
+static const struct header_ops dvb_header_ops = {
+ .create = eth_header,
+ .parse = eth_header_parse,
+ .rebuild = eth_rebuild_header,
+};
+
static void dvb_net_setup(struct net_device *dev)
{
ether_setup(dev);
+ dev->header_ops = &dvb_header_ops;
dev->open = dvb_net_open;
dev->stop = dvb_net_stop;
dev->hard_start_xmit = dvb_net_tx;
@@ -1235,7 +1239,7 @@ static void dvb_net_setup(struct net_device *dev)
dev->set_mac_address = dvb_net_set_mac;
dev->mtu = 4096;
dev->mc_count = 0;
- dev->hard_header_cache = NULL;
+
dev->flags |= IFF_NOARP;
}
@@ -1444,18 +1448,9 @@ static int dvb_net_close(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
- if (!dvbdev)
- return -ENODEV;
-
- if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- dvbdev->readers++;
- } else {
- dvbdev->writers++;
- }
-
- dvbdev->users++;
+ dvb_generic_release(inode, file);
- if(dvbdev->users == 1 && dvbnet->exit==1) {
+ if(dvbdev->users == 1 && dvbnet->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
wake_up(&dvbdev->wait_queue);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a9fa3337dd81..18738faecbbc 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -25,7 +25,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -59,18 +58,13 @@ static struct class *dvb_class;
static struct dvb_device* dvbdev_find_device (int minor)
{
- struct list_head *entry;
+ struct dvb_adapter *adap;
- list_for_each (entry, &dvb_adapter_list) {
- struct list_head *entry0;
- struct dvb_adapter *adap;
- adap = list_entry (entry, struct dvb_adapter, list_head);
- list_for_each (entry0, &adap->device_list) {
- struct dvb_device *dev;
- dev = list_entry (entry0, struct dvb_device, list_head);
+ list_for_each_entry(adap, &dvb_adapter_list, list_head) {
+ struct dvb_device *dev;
+ list_for_each_entry(dev, &adap->device_list, list_head)
if (nums2minor(adap->num, dev->type, dev->id) == minor)
return dev;
- }
}
return NULL;
@@ -109,10 +103,7 @@ static struct file_operations dvb_device_fops =
.open = dvb_device_open,
};
-static struct cdev dvb_device_cdev = {
- .kobj = {.name = "dvb", },
- .owner = THIS_MODULE,
-};
+static struct cdev dvb_device_cdev;
int dvb_generic_open(struct inode *inode, struct file *file)
{
@@ -180,13 +171,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
u32 id = 0;
while (id < DVB_MAX_IDS) {
- struct list_head *entry;
- list_for_each (entry, &adap->device_list) {
- struct dvb_device *dev;
- dev = list_entry (entry, struct dvb_device, list_head);
+ struct dvb_device *dev;
+ list_for_each_entry(dev, &adap->device_list, list_head)
if (dev->type == type && dev->id == id)
goto skip;
- }
return id;
skip:
id++;
@@ -200,7 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
{
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
- struct class_device *clsdev;
+ struct device *clsdev;
int id;
mutex_lock(&dvbdev_register_lock);
@@ -208,7 +196,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
- printk ("%s: could get find free device id...\n", __FUNCTION__);
+ printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
return -ENFILE;
}
@@ -242,17 +230,16 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
- clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR,
- nums2minor(adap->num, type, id)),
- adap->device, "dvb%d.%s%d", adap->num,
- dnames[type], id);
+ clsdev = device_create(dvb_class, adap->device,
+ MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+ "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
__FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev));
return PTR_ERR(clsdev);
}
- dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+ dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
nums2minor(adap->num, type, id));
@@ -266,8 +253,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
if (!dvbdev)
return;
- class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
- dvbdev->type, dvbdev->id)));
+ device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
+ dvbdev->type, dvbdev->id)));
list_del (&dvbdev->list_head);
kfree (dvbdev->fops);
@@ -281,13 +268,10 @@ static int dvbdev_get_free_adapter_num (void)
int num = 0;
while (num < DVB_MAX_ADAPTERS) {
- struct list_head *entry;
- list_for_each (entry, &dvb_adapter_list) {
- struct dvb_adapter *adap;
- adap = list_entry (entry, struct dvb_adapter, list_head);
+ struct dvb_adapter *adap;
+ list_for_each_entry(adap, &dvb_adapter_list, list_head)
if (adap->num == num)
goto skip;
- }
return num;
skip:
num++;
@@ -311,7 +295,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list);
- printk ("DVB: registering new adapter (%s).\n", name);
+ printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
adap->num = num;
adap->name = name;
@@ -407,13 +391,13 @@ static int __init init_dvbdev(void)
dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable register character device\n");
goto error;
}
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 54488737a08f..d73934dd4c57 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -2,7 +2,6 @@ config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C
select FW_LOADER
- select DVB_PLL
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -27,13 +26,14 @@ config DVB_USB_A800
depends on DVB_USB
select DVB_DIB3000MC
select DVB_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.
config DVB_USB_DIBUSB_MB
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MB
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -74,6 +74,8 @@ config DVB_USB_DIB0700
select DVB_DIB7000M
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_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
USB bridge is also present in devices having the DiB7700 DVB-T-USB
@@ -89,7 +91,7 @@ config DVB_USB_DIB0700
config DVB_USB_UMT_010
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -98,7 +100,7 @@ config DVB_USB_UMT_010
config DVB_USB_CXUSB
tristate "Conexant USB2.0 hybrid reference design support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_CX22702 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -142,7 +144,7 @@ config DVB_USB_AU6610
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
help
@@ -188,6 +190,7 @@ config DVB_USB_NOVA_T_USB2
depends on DVB_USB
select DVB_DIB3000MC
select DVB_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.
@@ -216,5 +219,23 @@ config DVB_USB_OPERA1
tristate "Opera1 DVB-S USB2.0 receiver"
depends on DVB_USB
select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+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
+ help
+ Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+ and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+ tristate "Afatech AF9005 default remote control support"
+ depends on DVB_USB_AF9005
+ help
+ Say Y here to support the default remote control decoding for the
+ Afatech AF9005 based receiver.
+
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 976f840cc904..73ac0a93fdeb 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -55,4 +55,10 @@ dvb-usb-opera-objs = opera1.o
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-af9005-objs = af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs = af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
new file mode 100644
index 000000000000..b1a9c4cdec93
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-fe.c
@@ -0,0 +1,1488 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+ struct dvb_usb_device *d;
+ fe_status_t stat;
+
+ /* retraining parameters */
+ u32 original_fcw;
+ u16 original_rf_top;
+ u16 original_if_top;
+ u16 original_if_min;
+ u16 original_aci0_if_top;
+ u16 original_aci1_if_top;
+ u16 original_aci0_if_min;
+ u8 original_if_unplug_th;
+ u8 original_rf_unplug_th;
+ u8 original_dtop_if_unplug_th;
+ u8 original_dtop_rf_unplug_th;
+
+ /* statistics */
+ u32 pre_vit_error_count;
+ u32 pre_vit_bit_count;
+ u32 ber;
+ u32 post_vit_error_count;
+ u32 post_vit_bit_count;
+ u32 unc;
+ u16 abort_count;
+
+ int opened;
+ int strong;
+ unsigned long next_status_check;
+ struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+ u16 reglo, u8 pos, u8 len, u16 value)
+{
+ int ret;
+ u8 temp;
+
+ if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+ return ret;
+ temp = (u8) ((value & 0x0300) >> 8);
+ return af9005_write_register_bits(d, reghi, pos, len,
+ (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+ u16 reglo, u8 pos, u8 len, u16 * value)
+{
+ int ret;
+ u8 temp0, temp1;
+
+ if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+ return ret;
+ if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+ return ret;
+ switch (pos) {
+ case 0:
+ *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+ break;
+ case 2:
+ *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+ break;
+ case 4:
+ *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+ break;
+ case 6:
+ *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+ break;
+ default:
+ err("invalid pos in read word agc");
+ return -EINVAL;
+ }
+ return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp;
+
+ *available = false;
+
+ ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+ fec_vtb_rsd_mon_en_pos,
+ fec_vtb_rsd_mon_en_len, &temp);
+ if (ret)
+ return ret;
+ if (temp & 1) {
+ ret =
+ af9005_read_register_bits(state->d,
+ xd_p_reg_ofsm_read_rbc_en,
+ reg_ofsm_read_rbc_en_pos,
+ reg_ofsm_read_rbc_en_len, &temp);
+ if (ret)
+ return ret;
+ if ((temp & 1) == 0)
+ *available = true;
+
+ }
+ return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+ u32 * post_err_count,
+ u32 * post_cw_count,
+ u16 * abort_count)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u32 err_count;
+ u32 cw_count;
+ u8 temp, temp0, temp1, temp2;
+ u16 loc_abort_count;
+
+ *post_err_count = 0;
+ *post_cw_count = 0;
+
+ /* check if error bit count is ready */
+ ret =
+ af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+ fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (!temp) {
+ deb_info("rsd counter not ready\n");
+ return 100;
+ }
+ /* get abort count */
+ ret =
+ af9005_read_ofdm_register(state->d,
+ xd_r_fec_rsd_abort_packet_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d,
+ xd_r_fec_rsd_abort_packet_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+ /* get error count */
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+ &temp2);
+ if (ret)
+ return ret;
+ err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+ *post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+ /* get RSD packet number */
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ cw_count = ((u32) temp1 << 8) + temp0;
+ if (cw_count == 0) {
+ err("wrong RSD packet count");
+ return -EIO;
+ }
+ deb_info("POST abort count %d err count %d rsd packets %d\n",
+ loc_abort_count, err_count, cw_count);
+ *post_cw_count = cw_count - (u32) loc_abort_count;
+ *abort_count = loc_abort_count;
+ return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+ u32 * post_err_count, u32 * post_cw_count,
+ u16 * abort_count)
+{
+ u32 loc_cw_count = 0, loc_err_count;
+ u16 loc_abort_count;
+ int ret;
+
+ ret =
+ af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+ &loc_abort_count);
+ if (ret)
+ return ret;
+ *post_err_count = loc_err_count;
+ *post_cw_count = loc_cw_count * 204 * 8;
+ *abort_count = loc_abort_count;
+
+ return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+ u32 * pre_err_count,
+ u32 * pre_bit_count)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp, temp0, temp1, temp2;
+ u32 super_frame_count, x, bits;
+ int ret;
+
+ ret =
+ af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+ fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (!temp) {
+ deb_info("viterbi counter not ready\n");
+ return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */
+ }
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+ &temp2);
+ if (ret)
+ return ret;
+ *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ super_frame_count = ((u32) temp1 << 8) + temp0;
+ if (super_frame_count == 0) {
+ deb_info("super frame count 0\n");
+ return 102;
+ }
+
+ /* read fft mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+ reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (temp == 0) {
+ /* 2K */
+ x = 1512;
+ } else if (temp == 1) {
+ /* 8k */
+ x = 6048;
+ } else {
+ err("Invalid fft mode");
+ return -EINVAL;
+ }
+
+ /* read constellation mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+ reg_tpsd_const_pos, reg_tpsd_const_len,
+ &temp);
+ if (ret)
+ return ret;
+ switch (temp) {
+ case 0: /* QPSK */
+ bits = 2;
+ break;
+ case 1: /* QAM_16 */
+ bits = 4;
+ break;
+ case 2: /* QAM_64 */
+ bits = 6;
+ break;
+ default:
+ err("invalid constellation mode");
+ return -EINVAL;
+ }
+ *pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+ deb_info("PRE err count %d frame count %d bit count %d\n",
+ *pre_err_count, super_frame_count, *pre_bit_count);
+ return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+
+ /* set super frame count to 1 */
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+ 1 & 0xff);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+ 1 >> 8);
+ if (ret)
+ return ret;
+ /* reset pre viterbi error count */
+ ret =
+ af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+ fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+ 1);
+
+ return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+
+ /* set packet unit */
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+ 10000 & 0xff);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+ 10000 >> 8);
+ if (ret)
+ return ret;
+ /* reset post viterbi error count */
+ ret =
+ af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+ fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+ 1);
+
+ return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret, fecavailable;
+ u64 numerator, denominator;
+
+ deb_info("GET STATISTIC\n");
+ ret = af9005_is_fecmon_available(fe, &fecavailable);
+ if (ret)
+ return ret;
+ if (!fecavailable) {
+ deb_info("fecmon not available\n");
+ return 0;
+ }
+
+ ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+ &state->pre_vit_bit_count);
+ if (ret == 0) {
+ af9005_reset_pre_viterbi(fe);
+ if (state->pre_vit_bit_count > 0) {
+ /* according to v 0.0.4 of the dvb api ber should be a multiple
+ of 10E-9 so we have to multiply the error count by
+ 10E9=1000000000 */
+ numerator =
+ (u64) state->pre_vit_error_count * (u64) 1000000000;
+ denominator = (u64) state->pre_vit_bit_count;
+ state->ber = do_div(numerator, denominator);
+ } else {
+ state->ber = 0xffffffff;
+ }
+ }
+
+ ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+ &state->post_vit_bit_count,
+ &state->abort_count);
+ if (ret == 0) {
+ ret = af9005_reset_post_viterbi(fe);
+ state->unc += state->abort_count;
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (time_after(jiffies, state->next_status_check)) {
+ deb_info("REFRESH STATE\n");
+
+ /* statistics */
+ if (af9005_get_statistic(fe))
+ err("get_statistic_failed");
+ state->next_status_check = jiffies + 250 * HZ / 1000;
+ }
+ return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp;
+ int ret;
+
+ if (fe->ops.tuner_ops.release == NULL)
+ return -ENODEV;
+
+ *stat = 0;
+ ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+ agc_lock_pos, agc_lock_len, &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_SIGNAL;
+
+ ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+ fd_tpsd_lock_pos, fd_tpsd_lock_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_CARRIER;
+
+ ret = af9005_read_register_bits(state->d,
+ xd_r_mp2if_sync_byte_locked,
+ mp2if_sync_byte_locked_pos,
+ mp2if_sync_byte_locked_pos, &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+ if (state->opened)
+ af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+ ret =
+ af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+ reg_strong_sginal_detected_pos,
+ reg_strong_sginal_detected_len, &temp);
+ if (ret)
+ return ret;
+ if (temp != state->strong) {
+ deb_info("adjust for strong signal %d\n", temp);
+ state->strong = temp;
+ }
+ return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (fe->ops.tuner_ops.release == NULL)
+ return -ENODEV;
+ af9005_fe_refresh_state(fe);
+ *ber = state->ber;
+ return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (fe->ops.tuner_ops.release == NULL)
+ return -ENODEV;
+ af9005_fe_refresh_state(fe);
+ *unc = state->unc;
+ return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+ u16 * strength)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 if_gain, rf_gain;
+
+ if (fe->ops.tuner_ops.release == NULL)
+ return -ENODEV;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+ &rf_gain);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+ &if_gain);
+ if (ret)
+ return ret;
+ /* this value has no real meaning, but i don't have the tables that relate
+ the rf and if gain with the dbm, so I just scale the value */
+ *strength = (512 - rf_gain - if_gain) << 7;
+ return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+ /* the snr can be derived from the ber and the constellation
+ but I don't think this kind of complex calculations belong
+ in the driver. I may be wrong.... */
+ return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+ u8 temp0, temp1, temp2, temp3, buf[4];
+ int ret;
+ u32 NS_coeff1_2048Nu;
+ u32 NS_coeff1_8191Nu;
+ u32 NS_coeff1_8192Nu;
+ u32 NS_coeff1_8193Nu;
+ u32 NS_coeff2_2k;
+ u32 NS_coeff2_8k;
+
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ NS_coeff1_2048Nu = 0x2ADB6DC;
+ NS_coeff1_8191Nu = 0xAB7313;
+ NS_coeff1_8192Nu = 0xAB6DB7;
+ NS_coeff1_8193Nu = 0xAB685C;
+ NS_coeff2_2k = 0x156DB6E;
+ NS_coeff2_8k = 0x55B6DC;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ NS_coeff1_2048Nu = 0x3200001;
+ NS_coeff1_8191Nu = 0xC80640;
+ NS_coeff1_8192Nu = 0xC80000;
+ NS_coeff1_8193Nu = 0xC7F9C0;
+ NS_coeff2_2k = 0x1900000;
+ NS_coeff2_8k = 0x640000;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ NS_coeff1_2048Nu = 0x3924926;
+ NS_coeff1_8191Nu = 0xE4996E;
+ NS_coeff1_8192Nu = 0xE49249;
+ NS_coeff1_8193Nu = 0xE48B25;
+ NS_coeff2_2k = 0x1C92493;
+ NS_coeff2_8k = 0x724925;
+ break;
+ default:
+ err("Invalid bandwith %d.", bw);
+ return -EINVAL;
+ }
+
+ /*
+ * write NS_coeff1_2048Nu
+ */
+
+ temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+ temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+ temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ /* cfoe_NS_2k_coeff1_25_24 */
+ ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_23_16 */
+ ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_15_8 */
+ ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_7_0 */
+ ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff2_2k
+ */
+
+ temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+ temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+ temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+ temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8191Nu
+ */
+
+ temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+ temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8192Nu
+ */
+
+ temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+ temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8193Nu
+ */
+
+ temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+ temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff2_8k
+ */
+
+ temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+ temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+ temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+ temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+ return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+ u8 temp;
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ temp = 0;
+ break;
+ case BANDWIDTH_7_MHZ:
+ temp = 1;
+ break;
+ case BANDWIDTH_8_MHZ:
+ temp = 2;
+ break;
+ default:
+ err("Invalid bandwith %d.", bw);
+ return -EINVAL;
+ }
+ return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+ reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp = on;
+ int ret;
+ deb_info("power %s tuner\n", on ? "on" : "off");
+ ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+ return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+ 0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+ 0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ int ret, i, scriptlen;
+ u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+ u8 buf[2];
+ u16 if1;
+
+ deb_info("in af9005_fe_init\n");
+
+ /* reset */
+ deb_info("reset\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+ 4, 1, 0x01)))
+ return ret;
+ if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+ return ret;
+ /* clear ofdm reset */
+ deb_info("clear ofdm reset\n");
+ for (i = 0; i < 150; i++) {
+ if ((ret =
+ af9005_read_ofdm_register(state->d,
+ xd_I2C_reg_ofdm_rst, &temp)))
+ return ret;
+ if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+ break;
+ msleep(10);
+ }
+ if (i == 150)
+ return -ETIMEDOUT;
+
+ /*FIXME in the dump
+ write B200 A9
+ write xd_g_reg_ofsm_clk 7
+ read eepr c6 (2)
+ read eepr c7 (2)
+ misc ctrl 3 -> 1
+ read eepr ca (6)
+ write xd_g_reg_ofsm_clk 0
+ write B200 a1
+ */
+ ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+ if (ret)
+ return ret;
+ temp = 0x01;
+ ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+ if (ret)
+ return ret;
+
+ temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+ reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+ return ret;
+ ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+ reg_ofdm_rst_pos, reg_ofdm_rst_len, 0);
+
+ if (ret)
+ return ret;
+ /* don't know what register aefc is, but this is what the windows driver does */
+ ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+ if (ret)
+ return ret;
+
+ /* set stand alone chip */
+ deb_info("set stand alone chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+ reg_dca_stand_alone_pos,
+ reg_dca_stand_alone_len, 1)))
+ return ret;
+
+ /* set dca upper & lower chip */
+ deb_info("set dca upper & lower chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+ reg_dca_upper_chip_pos,
+ reg_dca_upper_chip_len, 0)))
+ return ret;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+ reg_dca_lower_chip_pos,
+ reg_dca_lower_chip_len, 0)))
+ return ret;
+
+ /* set 2wire master clock to 0x14 (for 60KHz) */
+ deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+ if ((ret =
+ af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+ return ret;
+
+ /* clear dca enable chip */
+ deb_info("clear dca enable chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+ reg_dca_en_pos, reg_dca_en_len, 0)))
+ return ret;
+ /* FIXME these are register bits, but I don't know which ones */
+ ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+ if (ret)
+ return ret;
+
+ /* init other parameters: program cfoe and select bandwith */
+ deb_info("program cfoe\n");
+ if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+ return ret;
+ /* set read-update bit for constellation */
+ deb_info("set read-update bit for constellation\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+ reg_feq_read_update_pos,
+ reg_feq_read_update_len, 1)))
+ return ret;
+
+ /* sample code has a set MPEG TS code here
+ but sniffing reveals that it doesn't do it */
+
+ /* set read-update bit to 1 for DCA constellation */
+ deb_info("set read-update bit 1 for DCA constellation\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+ reg_dca_read_update_pos,
+ reg_dca_read_update_len, 1)))
+ return ret;
+
+ /* enable fec monitor */
+ deb_info("enable fec monitor\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+ fec_vtb_rsd_mon_en_pos,
+ fec_vtb_rsd_mon_en_len, 1)))
+ return ret;
+
+ /* FIXME should be register bits, I don't know which ones */
+ ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+ /* set api_retrain_never_freeze */
+ deb_info("set api_retrain_never_freeze\n");
+ if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+ return ret;
+
+ /* load init script */
+ deb_info("load init script\n");
+ scriptlen = sizeof(script) / sizeof(RegDesc);
+ for (i = 0; i < scriptlen; i++) {
+ if ((ret =
+ af9005_write_register_bits(state->d, script[i].reg,
+ script[i].pos,
+ script[i].len, script[i].val)))
+ return ret;
+ /* save 3 bytes of original fcw */
+ if (script[i].reg == 0xae18)
+ temp2 = script[i].val;
+ if (script[i].reg == 0xae19)
+ temp1 = script[i].val;
+ if (script[i].reg == 0xae1a)
+ temp0 = script[i].val;
+
+ /* save original unplug threshold */
+ if (script[i].reg == xd_p_reg_unplug_th)
+ state->original_if_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+ state->original_rf_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+ state->original_dtop_if_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+ state->original_dtop_rf_unplug_th = script[i].val;
+
+ }
+ state->original_fcw =
+ ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+ /* save original TOPs */
+ deb_info("save original TOPs\n");
+
+ /* RF TOP */
+ ret =
+ af9005_read_word_agc(state->d,
+ xd_p_reg_aagc_rf_top_numerator_9_8,
+ xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+ &state->original_rf_top);
+ if (ret)
+ return ret;
+
+ /* IF TOP */
+ ret =
+ af9005_read_word_agc(state->d,
+ xd_p_reg_aagc_if_top_numerator_9_8,
+ xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+ &state->original_if_top);
+ if (ret)
+ return ret;
+
+ /* ACI 0 IF TOP */
+ ret =
+ af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+ &state->original_aci0_if_top);
+ if (ret)
+ return ret;
+
+ /* ACI 1 IF TOP */
+ ret =
+ af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+ &state->original_aci1_if_top);
+ if (ret)
+ return ret;
+
+ /* attach tuner and init */
+ if (fe->ops.tuner_ops.release == NULL) {
+ /* read tuner and board id from eeprom */
+ ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+ if (ret) {
+ err("Impossible to read EEPROM\n");
+ return ret;
+ }
+ deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+ switch (buf[0]) {
+ case 2: /* MT2060 */
+ /* read if1 from eeprom */
+ ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+ if (ret) {
+ err("Impossible to read EEPROM\n");
+ return ret;
+ }
+ if1 = (u16) (buf[0] << 8) + buf[1];
+ if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+ &af9005_mt2060_config, if1) == NULL) {
+ deb_info("MT2060 attach failed\n");
+ return -ENODEV;
+ }
+ break;
+ case 3: /* QT1010 */
+ case 9: /* QT1010B */
+ if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+ &af9005_qt1010_config) ==NULL) {
+ deb_info("QT1010 attach failed\n");
+ return -ENODEV;
+ }
+ break;
+ default:
+ err("Unsupported tuner type %d", buf[0]);
+ return -ENODEV;
+ }
+ ret = fe->ops.tuner_ops.init(fe);
+ if (ret)
+ return ret;
+ }
+
+ deb_info("profit!\n");
+ return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+ return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+
+ if (acquire) {
+ state->opened++;
+ } else {
+
+ state->opened--;
+ if (!state->opened)
+ af9005_led_control(state->d, 0);
+ }
+ return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp, temp0, temp1, temp2;
+
+ deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+ fep->u.ofdm.bandwidth);
+ if (fe->ops.tuner_ops.release == NULL) {
+ err("Tuner not attached");
+ return -ENODEV;
+ }
+
+ deb_info("turn off led\n");
+ /* not in the log */
+ ret = af9005_led_control(state->d, 0);
+ if (ret)
+ return ret;
+ /* not sure about the bits */
+ ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+ if (ret)
+ return ret;
+
+ /* set FCW to default value */
+ deb_info("set FCW to default value\n");
+ temp0 = (u8) (state->original_fcw & 0x000000ff);
+ temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+ temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+ ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+ if (ret)
+ return ret;
+
+ /* restore original TOPs */
+ deb_info("restore original TOPs\n");
+ ret =
+ af9005_write_word_agc(state->d,
+ xd_p_reg_aagc_rf_top_numerator_9_8,
+ xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+ state->original_rf_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d,
+ xd_p_reg_aagc_if_top_numerator_9_8,
+ xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+ state->original_if_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+ state->original_aci0_if_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+ state->original_aci1_if_top);
+ if (ret)
+ return ret;
+
+ /* select bandwith */
+ deb_info("select bandwidth");
+ ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+ if (ret)
+ return ret;
+ ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+ if (ret)
+ return ret;
+
+ /* clear easy mode flag */
+ deb_info("clear easy mode flag\n");
+ ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+ if (ret)
+ return ret;
+
+ /* set unplug threshold to original value */
+ deb_info("set unplug threshold to original value\n");
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+ state->original_if_unplug_th);
+ if (ret)
+ return ret;
+ /* set tuner */
+ deb_info("set tuner\n");
+ ret = fe->ops.tuner_ops.set_params(fe, fep);
+ if (ret)
+ return ret;
+
+ /* trigger ofsm */
+ deb_info("trigger ofsm\n");
+ temp = 0;
+ ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+ if (ret)
+ return ret;
+
+ /* clear retrain and freeze flag */
+ deb_info("clear retrain and freeze flag\n");
+ ret =
+ af9005_write_register_bits(state->d,
+ xd_p_reg_api_retrain_request,
+ reg_api_retrain_request_pos, 2, 0);
+ if (ret)
+ return ret;
+
+ /* reset pre viterbi and post viterbi registers and statistics */
+ af9005_reset_pre_viterbi(fe);
+ af9005_reset_post_viterbi(fe);
+ state->pre_vit_error_count = 0;
+ state->pre_vit_bit_count = 0;
+ state->ber = 0;
+ state->post_vit_error_count = 0;
+ /* state->unc = 0; commented out since it should be ever increasing */
+ state->abort_count = 0;
+
+ state->next_status_check = jiffies;
+ state->strong = -1;
+
+ return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp;
+
+ /* mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+ reg_tpsd_const_pos, reg_tpsd_const_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("===== fe_get_frontend ==============\n");
+ deb_info("CONSTELLATION ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.constellation = QPSK;
+ deb_info("QPSK\n");
+ break;
+ case 1:
+ fep->u.ofdm.constellation = QAM_16;
+ deb_info("QAM_16\n");
+ break;
+ case 2:
+ fep->u.ofdm.constellation = QAM_64;
+ deb_info("QAM_64\n");
+ break;
+ }
+
+ /* tps hierarchy and alpha value */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+ reg_tpsd_hier_pos, reg_tpsd_hier_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("HIERARCHY ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ deb_info("NONE\n");
+ break;
+ case 1:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+ deb_info("1\n");
+ break;
+ case 2:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+ deb_info("2\n");
+ break;
+ case 3:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+ deb_info("4\n");
+ break;
+ }
+
+ /* high/low priority */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+ reg_dec_pri_pos, reg_dec_pri_len, &temp);
+ if (ret)
+ return ret;
+ /* if temp is set = high priority */
+ deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+ /* high coderate */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+ reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("CODERATE HP ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.code_rate_HP = FEC_1_2;
+ deb_info("FEC_1_2\n");
+ break;
+ case 1:
+ fep->u.ofdm.code_rate_HP = FEC_2_3;
+ deb_info("FEC_2_3\n");
+ break;
+ case 2:
+ fep->u.ofdm.code_rate_HP = FEC_3_4;
+ deb_info("FEC_3_4\n");
+ break;
+ case 3:
+ fep->u.ofdm.code_rate_HP = FEC_5_6;
+ deb_info("FEC_5_6\n");
+ break;
+ case 4:
+ fep->u.ofdm.code_rate_HP = FEC_7_8;
+ deb_info("FEC_7_8\n");
+ break;
+ }
+
+ /* low coderate */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+ reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("CODERATE LP ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.code_rate_LP = FEC_1_2;
+ deb_info("FEC_1_2\n");
+ break;
+ case 1:
+ fep->u.ofdm.code_rate_LP = FEC_2_3;
+ deb_info("FEC_2_3\n");
+ break;
+ case 2:
+ fep->u.ofdm.code_rate_LP = FEC_3_4;
+ deb_info("FEC_3_4\n");
+ break;
+ case 3:
+ fep->u.ofdm.code_rate_LP = FEC_5_6;
+ deb_info("FEC_5_6\n");
+ break;
+ case 4:
+ fep->u.ofdm.code_rate_LP = FEC_7_8;
+ deb_info("FEC_7_8\n");
+ break;
+ }
+
+ /* guard interval */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+ reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+ if (ret)
+ return ret;
+ deb_info("GUARD INTERVAL ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ deb_info("1_32\n");
+ break;
+ case 1:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ deb_info("1_16\n");
+ break;
+ case 2:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ deb_info("1_8\n");
+ break;
+ case 3:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ deb_info("1_4\n");
+ break;
+ }
+
+ /* fft */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+ reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("TRANSMISSION MODE ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ deb_info("2K\n");
+ break;
+ case 1:
+ fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ deb_info("8K\n");
+ break;
+ }
+
+ /* bandwidth */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+ reg_bw_len, &temp);
+ deb_info("BANDWIDTH ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ deb_info("6\n");
+ break;
+ case 1:
+ fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ deb_info("7\n");
+ break;
+ case 2:
+ fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ deb_info("8\n");
+ break;
+ }
+ return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state =
+ (struct af9005_fe_state *)fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+ struct af9005_fe_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ deb_info("attaching frontend af9005\n");
+
+ state->d = d;
+ state->opened = 0;
+
+ memcpy(&state->frontend.ops, &af9005_fe_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+ error:
+ return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+ .info = {
+ .name = "AF9005 USB DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = af9005_fe_release,
+
+ .init = af9005_fe_init,
+ .sleep = af9005_fe_sleep,
+ .ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+ .set_frontend = af9005_fe_set_frontend,
+ .get_frontend = af9005_fe_get_frontend,
+
+ .read_status = af9005_fe_read_status,
+ .read_ber = af9005_fe_read_ber,
+ .read_signal_strength = af9005_fe_read_signal_strength,
+ .read_snr = af9005_fe_read_snr,
+ .read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
new file mode 100644
index 000000000000..ff00c0e8f4a1
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "enable (1) or disable (0) debug messages."
+ DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct dvb_usb_rc_key af9005_rc_keys[] = {
+
+ {0x01, 0xb7, KEY_POWER},
+ {0x01, 0xa7, KEY_VOLUMEUP},
+ {0x01, 0x87, KEY_CHANNELUP},
+ {0x01, 0x7f, KEY_MUTE},
+ {0x01, 0xbf, KEY_VOLUMEDOWN},
+ {0x01, 0x3f, KEY_CHANNELDOWN},
+ {0x01, 0xdf, KEY_1},
+ {0x01, 0x5f, KEY_2},
+ {0x01, 0x9f, KEY_3},
+ {0x01, 0x1f, KEY_4},
+ {0x01, 0xef, KEY_5},
+ {0x01, 0x6f, KEY_6},
+ {0x01, 0xaf, KEY_7},
+ {0x01, 0x27, KEY_8},
+ {0x01, 0x07, KEY_9},
+ {0x01, 0xcf, KEY_ZOOM},
+ {0x01, 0x4f, KEY_0},
+ {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
+
+ {0x00, 0xbd, KEY_POWER},
+ {0x00, 0x7d, KEY_VOLUMEUP},
+ {0x00, 0xfd, KEY_CHANNELUP},
+ {0x00, 0x9d, KEY_MUTE},
+ {0x00, 0x5d, KEY_VOLUMEDOWN},
+ {0x00, 0xdd, KEY_CHANNELDOWN},
+ {0x00, 0xad, KEY_1},
+ {0x00, 0x6d, KEY_2},
+ {0x00, 0xed, KEY_3},
+ {0x00, 0x8d, KEY_4},
+ {0x00, 0x4d, KEY_5},
+ {0x00, 0xcd, KEY_6},
+ {0x00, 0xb5, KEY_7},
+ {0x00, 0x75, KEY_8},
+ {0x00, 0xf5, KEY_9},
+ {0x00, 0x95, KEY_ZOOM},
+ {0x00, 0x55, KEY_0},
+ {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */
+};
+
+int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+
+static int repeatable_keys[] = {
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+ KEY_CHANNELUP,
+ KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+ int *state)
+{
+ u16 mark, space;
+ u32 result;
+ u8 cust, dat, invdat;
+ int i;
+
+ if (len >= 6) {
+ mark = (u16) (data[0] << 8) + data[1];
+ space = (u16) (data[2] << 8) + data[3];
+ if (space * 3 < mark) {
+ for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+ if (d->last_event == repeatable_keys[i]) {
+ *state = REMOTE_KEY_REPEAT;
+ *event = d->last_event;
+ deb_decode("repeat key, event %x\n",
+ *event);
+ return 0;
+ }
+ }
+ deb_decode("repeated key ignored (non repeatable)\n");
+ return 0;
+ } else if (len >= 33 * 4) { /*32 bits + start code */
+ result = 0;
+ for (i = 4; i < 4 + 32 * 4; i += 4) {
+ result <<= 1;
+ mark = (u16) (data[i] << 8) + data[i + 1];
+ mark >>= 1;
+ space = (u16) (data[i + 2] << 8) + data[i + 3];
+ space >>= 1;
+ if (mark * 2 > space)
+ result += 1;
+ }
+ deb_decode("key pressed, raw value %x\n", result);
+ if ((result & 0xff000000) != 0xfe000000) {
+ deb_decode
+ ("doesn't start with 0xfe, ignored\n");
+ return 0;
+ }
+ cust = (result >> 16) & 0xff;
+ dat = (result >> 8) & 0xff;
+ invdat = (~result) & 0xff;
+ if (dat != invdat) {
+ deb_decode("code != inverted code\n");
+ return 0;
+ }
+ for (i = 0; i < af9005_rc_keys_size; i++) {
+ if (af9005_rc_keys[i].custom == cust
+ && af9005_rc_keys[i].data == dat) {
+ *event = af9005_rc_keys[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ deb_decode
+ ("key pressed, event %x\n", *event);
+ return 0;
+ }
+ }
+ deb_decode("not found in table\n");
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(af9005_rc_keys);
+EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+ ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
new file mode 100644
index 000000000000..6eeaae51b1ca
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-script.h
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+ u16 reg;
+ u8 pos;
+ u8 len;
+ u8 val;
+} RegDesc;
+
+RegDesc script[] = {
+ {0xa180, 0x0, 0x8, 0xa},
+ {0xa181, 0x0, 0x8, 0xd7},
+ {0xa182, 0x0, 0x8, 0xa3},
+ {0xa0a0, 0x0, 0x8, 0x0},
+ {0xa0a1, 0x0, 0x5, 0x0},
+ {0xa0a1, 0x5, 0x1, 0x1},
+ {0xa0c0, 0x0, 0x4, 0x1},
+ {0xa20e, 0x4, 0x4, 0xa},
+ {0xa20f, 0x0, 0x8, 0x40},
+ {0xa210, 0x0, 0x8, 0x8},
+ {0xa32a, 0x0, 0x4, 0xa},
+ {0xa32c, 0x0, 0x8, 0x20},
+ {0xa32b, 0x0, 0x8, 0x15},
+ {0xa1a0, 0x1, 0x1, 0x1},
+ {0xa000, 0x0, 0x1, 0x1},
+ {0xa000, 0x1, 0x1, 0x0},
+ {0xa001, 0x1, 0x1, 0x1},
+ {0xa001, 0x0, 0x1, 0x0},
+ {0xa001, 0x5, 0x1, 0x0},
+ {0xa00e, 0x0, 0x5, 0x10},
+ {0xa00f, 0x0, 0x3, 0x4},
+ {0xa00f, 0x3, 0x3, 0x5},
+ {0xa010, 0x0, 0x3, 0x4},
+ {0xa010, 0x3, 0x3, 0x5},
+ {0xa016, 0x4, 0x4, 0x3},
+ {0xa01f, 0x0, 0x6, 0xa},
+ {0xa020, 0x0, 0x6, 0xa},
+ {0xa2bc, 0x0, 0x1, 0x1},
+ {0xa2bc, 0x5, 0x1, 0x1},
+ {0xa015, 0x0, 0x8, 0x50},
+ {0xa016, 0x0, 0x1, 0x0},
+ {0xa02a, 0x0, 0x8, 0x50},
+ {0xa029, 0x0, 0x8, 0x4b},
+ {0xa614, 0x0, 0x8, 0x46},
+ {0xa002, 0x0, 0x5, 0x19},
+ {0xa003, 0x0, 0x5, 0x1a},
+ {0xa004, 0x0, 0x5, 0x19},
+ {0xa005, 0x0, 0x5, 0x1a},
+ {0xa008, 0x0, 0x8, 0x69},
+ {0xa009, 0x0, 0x2, 0x2},
+ {0xae1b, 0x0, 0x8, 0x69},
+ {0xae1c, 0x0, 0x8, 0x2},
+ {0xae1d, 0x0, 0x8, 0x2a},
+ {0xa022, 0x0, 0x8, 0xaa},
+ {0xa006, 0x0, 0x8, 0xc8},
+ {0xa007, 0x0, 0x2, 0x0},
+ {0xa00c, 0x0, 0x8, 0xba},
+ {0xa00d, 0x0, 0x2, 0x2},
+ {0xa608, 0x0, 0x8, 0xba},
+ {0xa60e, 0x0, 0x2, 0x2},
+ {0xa609, 0x0, 0x8, 0x80},
+ {0xa60e, 0x2, 0x2, 0x3},
+ {0xa00a, 0x0, 0x8, 0xb6},
+ {0xa00b, 0x0, 0x2, 0x0},
+ {0xa011, 0x0, 0x8, 0xb9},
+ {0xa012, 0x0, 0x2, 0x0},
+ {0xa013, 0x0, 0x8, 0xbd},
+ {0xa014, 0x0, 0x2, 0x2},
+ {0xa366, 0x0, 0x1, 0x1},
+ {0xa2bc, 0x3, 0x1, 0x0},
+ {0xa2bd, 0x0, 0x8, 0xa},
+ {0xa2be, 0x0, 0x8, 0x14},
+ {0xa2bf, 0x0, 0x8, 0x8},
+ {0xa60a, 0x0, 0x8, 0xbd},
+ {0xa60e, 0x4, 0x2, 0x2},
+ {0xa60b, 0x0, 0x8, 0x86},
+ {0xa60e, 0x6, 0x2, 0x3},
+ {0xa001, 0x2, 0x2, 0x1},
+ {0xa1c7, 0x0, 0x8, 0xf5},
+ {0xa03d, 0x0, 0x8, 0xb1},
+ {0xa616, 0x0, 0x8, 0xff},
+ {0xa617, 0x0, 0x8, 0xad},
+ {0xa618, 0x0, 0x8, 0xad},
+ {0xa61e, 0x3, 0x1, 0x1},
+ {0xae1a, 0x0, 0x8, 0x0},
+ {0xae19, 0x0, 0x8, 0xc8},
+ {0xae18, 0x0, 0x8, 0x61},
+ {0xa140, 0x0, 0x8, 0x0},
+ {0xa141, 0x0, 0x8, 0xc8},
+ {0xa142, 0x0, 0x7, 0x61},
+ {0xa023, 0x0, 0x8, 0xff},
+ {0xa021, 0x0, 0x8, 0xad},
+ {0xa026, 0x0, 0x1, 0x0},
+ {0xa024, 0x0, 0x8, 0xff},
+ {0xa025, 0x0, 0x8, 0xff},
+ {0xa1c8, 0x0, 0x8, 0xf},
+ {0xa2bc, 0x1, 0x1, 0x0},
+ {0xa60c, 0x0, 0x4, 0x5},
+ {0xa60c, 0x4, 0x4, 0x6},
+ {0xa60d, 0x0, 0x8, 0xa},
+ {0xa371, 0x0, 0x1, 0x1},
+ {0xa366, 0x1, 0x3, 0x7},
+ {0xa338, 0x0, 0x8, 0x10},
+ {0xa339, 0x0, 0x6, 0x7},
+ {0xa33a, 0x0, 0x6, 0x1f},
+ {0xa33b, 0x0, 0x8, 0xf6},
+ {0xa33c, 0x3, 0x5, 0x4},
+ {0xa33d, 0x4, 0x4, 0x0},
+ {0xa33d, 0x1, 0x1, 0x1},
+ {0xa33d, 0x2, 0x1, 0x1},
+ {0xa33d, 0x3, 0x1, 0x1},
+ {0xa16d, 0x0, 0x4, 0xf},
+ {0xa161, 0x0, 0x5, 0x5},
+ {0xa162, 0x0, 0x4, 0x5},
+ {0xa165, 0x0, 0x8, 0xff},
+ {0xa166, 0x0, 0x8, 0x9c},
+ {0xa2c3, 0x0, 0x4, 0x5},
+ {0xa61a, 0x0, 0x6, 0xf},
+ {0xb200, 0x0, 0x8, 0xa1},
+ {0xb201, 0x0, 0x8, 0x7},
+ {0xa093, 0x0, 0x1, 0x0},
+ {0xa093, 0x1, 0x5, 0xf},
+ {0xa094, 0x0, 0x8, 0xff},
+ {0xa095, 0x0, 0x8, 0xf},
+ {0xa080, 0x2, 0x5, 0x3},
+ {0xa081, 0x0, 0x4, 0x0},
+ {0xa081, 0x4, 0x4, 0x9},
+ {0xa082, 0x0, 0x5, 0x1f},
+ {0xa08d, 0x0, 0x8, 0x1},
+ {0xa083, 0x0, 0x8, 0x32},
+ {0xa084, 0x0, 0x1, 0x0},
+ {0xa08e, 0x0, 0x8, 0x3},
+ {0xa085, 0x0, 0x8, 0x32},
+ {0xa086, 0x0, 0x3, 0x0},
+ {0xa087, 0x0, 0x8, 0x6e},
+ {0xa088, 0x0, 0x5, 0x15},
+ {0xa089, 0x0, 0x8, 0x0},
+ {0xa08a, 0x0, 0x5, 0x19},
+ {0xa08b, 0x0, 0x8, 0x92},
+ {0xa08c, 0x0, 0x5, 0x1c},
+ {0xa120, 0x0, 0x8, 0x0},
+ {0xa121, 0x0, 0x5, 0x10},
+ {0xa122, 0x0, 0x8, 0x0},
+ {0xa123, 0x0, 0x7, 0x40},
+ {0xa123, 0x7, 0x1, 0x0},
+ {0xa124, 0x0, 0x8, 0x13},
+ {0xa125, 0x0, 0x7, 0x10},
+ {0xa1c0, 0x0, 0x8, 0x0},
+ {0xa1c1, 0x0, 0x5, 0x4},
+ {0xa1c2, 0x0, 0x8, 0x0},
+ {0xa1c3, 0x0, 0x5, 0x10},
+ {0xa1c3, 0x5, 0x3, 0x0},
+ {0xa1c4, 0x0, 0x6, 0x0},
+ {0xa1c5, 0x0, 0x7, 0x10},
+ {0xa100, 0x0, 0x8, 0x0},
+ {0xa101, 0x0, 0x5, 0x10},
+ {0xa102, 0x0, 0x8, 0x0},
+ {0xa103, 0x0, 0x7, 0x40},
+ {0xa103, 0x7, 0x1, 0x0},
+ {0xa104, 0x0, 0x8, 0x18},
+ {0xa105, 0x0, 0x7, 0xa},
+ {0xa106, 0x0, 0x8, 0x20},
+ {0xa107, 0x0, 0x8, 0x40},
+ {0xa108, 0x0, 0x4, 0x0},
+ {0xa38c, 0x0, 0x8, 0xfc},
+ {0xa38d, 0x0, 0x8, 0x0},
+ {0xa38e, 0x0, 0x8, 0x7e},
+ {0xa38f, 0x0, 0x8, 0x0},
+ {0xa390, 0x0, 0x8, 0x2f},
+ {0xa60f, 0x5, 0x1, 0x1},
+ {0xa170, 0x0, 0x8, 0xdc},
+ {0xa171, 0x0, 0x2, 0x0},
+ {0xa2ae, 0x0, 0x1, 0x1},
+ {0xa2ae, 0x1, 0x1, 0x1},
+ {0xa392, 0x0, 0x1, 0x1},
+ {0xa391, 0x2, 0x1, 0x0},
+ {0xabc1, 0x0, 0x8, 0xff},
+ {0xabc2, 0x0, 0x8, 0x0},
+ {0xabc8, 0x0, 0x8, 0x8},
+ {0xabca, 0x0, 0x8, 0x10},
+ {0xabcb, 0x0, 0x1, 0x0},
+ {0xabc3, 0x5, 0x3, 0x7},
+ {0xabc0, 0x6, 0x1, 0x0},
+ {0xabc0, 0x4, 0x2, 0x0},
+ {0xa344, 0x4, 0x4, 0x1},
+ {0xabc0, 0x7, 0x1, 0x1},
+ {0xabc0, 0x2, 0x1, 0x1},
+ {0xa345, 0x0, 0x8, 0x66},
+ {0xa346, 0x0, 0x8, 0x66},
+ {0xa347, 0x0, 0x4, 0x0},
+ {0xa343, 0x0, 0x4, 0xa},
+ {0xa347, 0x4, 0x4, 0x2},
+ {0xa348, 0x0, 0x4, 0xc},
+ {0xa348, 0x4, 0x4, 0x7},
+ {0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
new file mode 100644
index 000000000000..7db6eee50e39
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -0,0 +1,1141 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+ DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+int dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+int dvb_usb_af9005_dump_eeprom = 0;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+/* remote control decoder */
+int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
+ int *state);
+void *rc_keys;
+int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+ u8 sequence;
+ int led_state;
+};
+
+int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
+ u8 * rbuf, u16 rlen, int delay_ms)
+{
+ int actlen, ret = -ENOMEM;
+
+ if (wbuf == NULL || wlen == 0)
+ return -EINVAL;
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ deb_xfer(">>> ");
+ debug_dump(wbuf, wlen, deb_xfer);
+
+ ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+ 2), wbuf, wlen,
+ &actlen, 2000);
+
+ if (ret)
+ err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
+ else
+ ret = actlen != wlen ? -1 : 0;
+
+ /* an answer is expected, and no error before */
+ if (!ret && rbuf && rlen) {
+ if (delay_ms)
+ msleep(delay_ms);
+
+ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+ 0x01), rbuf,
+ rlen, &actlen, 2000);
+
+ if (ret)
+ err("recv bulk message failed: %d", ret);
+ else {
+ deb_xfer("<<< ");
+ debug_dump(rbuf, actlen, deb_xfer);
+ }
+ }
+
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
+{
+ return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
+}
+
+int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+ int readwrite, int type, u8 * values, int len)
+{
+ struct af9005_device_state *st = d->priv;
+ u8 obuf[16] = { 0 };
+ u8 ibuf[17] = { 0 };
+ u8 command;
+ int i;
+ int ret;
+
+ if (len < 1) {
+ err("generic read/write, less than 1 byte. Makes no sense.");
+ return -EINVAL;
+ }
+ if (len > 8) {
+ err("generic read/write, more than 8 bytes. Not supported.");
+ return -EINVAL;
+ }
+
+ obuf[0] = 14; /* rest of buffer length low */
+ obuf[1] = 0; /* rest of buffer length high */
+
+ obuf[2] = AF9005_REGISTER_RW; /* register operation */
+ obuf[3] = 12; /* rest of buffer length */
+
+ obuf[4] = st->sequence++; /* sequence number */
+
+ obuf[5] = (u8) (reg >> 8); /* register address */
+ obuf[6] = (u8) (reg & 0xff);
+
+ if (type == AF9005_OFDM_REG) {
+ command = AF9005_CMD_OFDM_REG;
+ } else {
+ command = AF9005_CMD_TUNER;
+ }
+
+ if (len > 1)
+ command |=
+ AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+ command |= readwrite;
+ if (readwrite == AF9005_CMD_WRITE)
+ for (i = 0; i < len; i++)
+ obuf[8 + i] = values[i];
+ else if (type == AF9005_TUNER_REG)
+ /* read command for tuner, the first byte contains the i2c address */
+ obuf[8] = values[0];
+ obuf[7] = command;
+
+ ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+ if (ret)
+ return ret;
+
+ /* sanity check */
+ if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+ err("generic read/write, wrong reply code.");
+ return -EIO;
+ }
+ if (ibuf[3] != 0x0d) {
+ err("generic read/write, wrong length in reply.");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("generic read/write, wrong sequence in reply.");
+ return -EIO;
+ }
+ /*
+ Windows driver doesn't check these fields, in fact sometimes
+ the register in the reply is different that what has been sent
+
+ if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+ err("generic read/write, wrong register in reply.");
+ return -EIO;
+ }
+ if (ibuf[7] != command) {
+ err("generic read/write wrong command in reply.");
+ return -EIO;
+ }
+ */
+ if (ibuf[16] != 0x01) {
+ err("generic read/write wrong status code in reply.");
+ return -EIO;
+ }
+ if (readwrite == AF9005_CMD_READ)
+ for (i = 0; i < len; i++)
+ values[i] = ibuf[8 + i];
+
+ return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+ int ret;
+ deb_reg("read register %x ", reg);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_OFDM_REG,
+ value, 1);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("value %x\n", *value);
+ return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ int ret;
+ deb_reg("read %d registers %x ", len, reg);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_OFDM_REG,
+ values, len);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ debug_dump(values, len, deb_reg);
+ return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+ int ret;
+ u8 temp = value;
+ deb_reg("write register %x value %x ", reg, value);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE, AF9005_OFDM_REG,
+ &temp, 1);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("ok\n");
+ return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ int ret;
+ deb_reg("write %d registers %x values ", len, reg);
+ debug_dump(values, len, deb_reg);
+
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE, AF9005_OFDM_REG,
+ values, len);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("ok\n");
+ return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+ u8 len, u8 * value)
+{
+ u8 temp;
+ int ret;
+ deb_reg("read bits %x %x %x", reg, pos, len);
+ ret = af9005_read_ofdm_register(d, reg, &temp);
+ if (ret) {
+ deb_reg(" failed\n");
+ return ret;
+ }
+ *value = (temp >> pos) & regmask[len - 1];
+ deb_reg(" value %x\n", *value);
+ return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+ u8 len, u8 value)
+{
+ u8 temp, mask;
+ int ret;
+ deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+ if (pos == 0 && len == 8)
+ return af9005_write_ofdm_register(d, reg, value);
+ ret = af9005_read_ofdm_register(d, reg, &temp);
+ if (ret)
+ return ret;
+ mask = regmask[len - 1] << pos;
+ temp = (temp & ~mask) | ((value << pos) & mask);
+ return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+ u16 reg, u8 * values, int len)
+{
+ return af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_TUNER_REG,
+ values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+ u16 reg, u8 * values, int len)
+{
+ return af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE,
+ AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ /* don't let the name of this function mislead you: it's just used
+ as an interface from the firmware to the i2c bus. The actual
+ i2c addresses are contained in the data */
+ int ret, i, done = 0, fail = 0;
+ u8 temp;
+ ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+ if (ret)
+ return ret;
+ if (reg != 0xffff) {
+ /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+ for (i = 0; i < 200; i++) {
+ ret =
+ af9005_read_ofdm_register(d,
+ xd_I2C_i2c_m_status_wdat_done,
+ &temp);
+ if (ret)
+ return ret;
+ done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+ << i2c_m_status_wdat_done_pos);
+ if (done)
+ break;
+ fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+ << i2c_m_status_wdat_fail_pos);
+ if (fail)
+ break;
+ msleep(50);
+ }
+ if (i == 200)
+ return -ETIMEDOUT;
+ if (fail) {
+ /* clear write fail bit */
+ af9005_write_register_bits(d,
+ xd_I2C_i2c_m_status_wdat_fail,
+ i2c_m_status_wdat_fail_pos,
+ i2c_m_status_wdat_fail_len,
+ 1);
+ return -EIO;
+ }
+ /* clear write done bit */
+ ret =
+ af9005_write_register_bits(d,
+ xd_I2C_i2c_m_status_wdat_fail,
+ i2c_m_status_wdat_done_pos,
+ i2c_m_status_wdat_done_len, 1);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+ u8 * values, int len)
+{
+ /* don't let the name of this function mislead you: it's just used
+ as an interface from the firmware to the i2c bus. The actual
+ i2c addresses are contained in the data */
+ int ret, i;
+ u8 temp, buf[2];
+
+ buf[0] = addr; /* tuner i2c address */
+ buf[1] = values[0]; /* tuner register */
+
+ values[0] = addr + 0x01; /* i2c read address */
+
+ if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+ /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+ ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+ if (ret)
+ return ret;
+ }
+
+ /* send read command to ofsm */
+ ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+ if (ret)
+ return ret;
+
+ /* check if read done */
+ for (i = 0; i < 200; i++) {
+ ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+ if (ret)
+ return ret;
+ if (temp & 0x01)
+ break;
+ msleep(50);
+ }
+ if (i == 200)
+ return -ETIMEDOUT;
+
+ /* clear read done bit (by writing 1) */
+ ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+ if (ret)
+ return ret;
+
+ /* get read data (available from 0xa400) */
+ for (i = 0; i < len; i++) {
+ ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+ if (ret)
+ return ret;
+ values[i] = temp;
+ }
+ return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+ u8 * data, int len)
+{
+ int ret, i;
+ u8 buf[3];
+ deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+ reg, len);
+ debug_dump(data, len, deb_i2c);
+
+ for (i = 0; i < len; i++) {
+ buf[0] = i2caddr;
+ buf[1] = reg + (u8) i;
+ buf[2] = data[i];
+ ret =
+ af9005_write_tuner_registers(d,
+ APO_REG_I2C_RW_SILICON_TUNER,
+ buf, 3);
+ if (ret) {
+ deb_i2c("i2c_write failed\n");
+ return ret;
+ }
+ }
+ deb_i2c("i2c_write ok\n");
+ return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+ u8 * data, int len)
+{
+ int ret, i;
+ u8 temp;
+ deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+ for (i = 0; i < len; i++) {
+ temp = reg + i;
+ ret =
+ af9005_read_tuner_registers(d,
+ APO_REG_I2C_RW_SILICON_TUNER,
+ i2caddr, &temp, 1);
+ if (ret) {
+ deb_i2c("i2c_read failed\n");
+ return ret;
+ }
+ data[i] = temp;
+ }
+ deb_i2c("i2c data read: ");
+ debug_dump(data, len, deb_i2c);
+ return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ /* only implements what the mt2060 module does, don't know how
+ to make it really generic */
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret;
+ u8 reg, addr;
+ u8 *value;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ if (num == 2) {
+ /* reads a single register */
+ reg = *msg[0].buf;
+ addr = msg[0].addr;
+ value = msg[1].buf;
+ ret = af9005_i2c_read(d, addr, reg, value, 1);
+ if (ret == 0)
+ ret = 2;
+ } else {
+ /* write one or more registers */
+ reg = msg[0].buf[0];
+ addr = msg[0].addr;
+ value = &msg[0].buf[1];
+ ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+ if (ret == 0)
+ ret = 1;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+ .master_xfer = af9005_i2c_xfer,
+ .functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+ int wlen, u8 * rbuf, int rlen)
+{
+ struct af9005_device_state *st = d->priv;
+
+ int ret, i, packet_len;
+ u8 buf[64];
+ u8 ibuf[64];
+
+ if (wlen < 0) {
+ err("send command, wlen less than 0 bytes. Makes no sense.");
+ return -EINVAL;
+ }
+ if (wlen > 54) {
+ err("send command, wlen more than 54 bytes. Not supported.");
+ return -EINVAL;
+ }
+ if (rlen > 54) {
+ err("send command, rlen more than 54 bytes. Not supported.");
+ return -EINVAL;
+ }
+ packet_len = wlen + 5;
+ buf[0] = (u8) (packet_len & 0xff);
+ buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+ buf[2] = 0x26; /* packet type */
+ buf[3] = wlen + 3;
+ buf[4] = st->sequence++;
+ buf[5] = command;
+ buf[6] = wlen;
+ for (i = 0; i < wlen; i++)
+ buf[7 + i] = wbuf[i];
+ ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+ if (ret)
+ return ret;
+ if (ibuf[2] != 0x27) {
+ err("send command, wrong reply code.");
+ return -EIO;
+ }
+ if (ibuf[4] != buf[4]) {
+ err("send command, wrong sequence in reply.");
+ return -EIO;
+ }
+ if (ibuf[5] != 0x01) {
+ err("send command, wrong status code in reply.");
+ return -EIO;
+ }
+ if (ibuf[6] != rlen) {
+ err("send command, invalid data length in reply.");
+ return -EIO;
+ }
+ for (i = 0; i < rlen; i++)
+ rbuf[i] = ibuf[i + 7];
+ return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+ int len)
+{
+ struct af9005_device_state *st = d->priv;
+ u8 obuf[16], ibuf[14];
+ int ret, i;
+
+ memset(obuf, 0, sizeof(obuf));
+ memset(ibuf, 0, sizeof(ibuf));
+
+ obuf[0] = 14; /* length of rest of packet low */
+ obuf[1] = 0; /* length of rest of packer high */
+
+ obuf[2] = 0x2a; /* read/write eeprom */
+
+ obuf[3] = 12; /* size */
+
+ obuf[4] = st->sequence++;
+
+ obuf[5] = 0; /* read */
+
+ obuf[6] = len;
+ obuf[7] = address;
+ ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+ if (ret)
+ return ret;
+ if (ibuf[2] != 0x2b) {
+ err("Read eeprom, invalid reply code");
+ return -EIO;
+ }
+ if (ibuf[3] != 10) {
+ err("Read eeprom, invalid reply length");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("Read eeprom, wrong sequence in reply ");
+ return -EIO;
+ }
+ if (ibuf[5] != 1) {
+ err("Read eeprom, wrong status in reply ");
+ return -EIO;
+ }
+ for (i = 0; i < len; i++) {
+ values[i] = ibuf[6 + i];
+ }
+ return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+ u8 buf[FW_BULKOUT_SIZE + 2];
+ u16 checksum;
+ int act_len, i, ret;
+ memset(buf, 0, sizeof(buf));
+ buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+ buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+ switch (type) {
+ case FW_CONFIG:
+ buf[2] = 0x11;
+ buf[3] = 0x04;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x03;
+ checksum = buf[4] + buf[5];
+ buf[6] = (u8) ((checksum >> 8) & 0xff);
+ buf[7] = (u8) (checksum & 0xff);
+ break;
+ case FW_CONFIRM:
+ buf[2] = 0x11;
+ buf[3] = 0x04;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x01;
+ checksum = buf[4] + buf[5];
+ buf[6] = (u8) ((checksum >> 8) & 0xff);
+ buf[7] = (u8) (checksum & 0xff);
+ break;
+ case FW_BOOT:
+ buf[2] = 0x10;
+ buf[3] = 0x08;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x97;
+ buf[6] = 0xaa;
+ buf[7] = 0x55;
+ buf[8] = 0xa5;
+ buf[9] = 0x5a;
+ checksum = 0;
+ for (i = 4; i <= 9; i++)
+ checksum += buf[i];
+ buf[10] = (u8) ((checksum >> 8) & 0xff);
+ buf[11] = (u8) (checksum & 0xff);
+ break;
+ default:
+ err("boot packet invalid boot packet type");
+ return -EINVAL;
+ }
+ deb_fw(">>> ");
+ debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x02),
+ buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+ if (ret)
+ err("boot packet bulk message failed: %d (%d/%d)", ret,
+ FW_BULKOUT_SIZE + 2, act_len);
+ else
+ ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+ if (ret)
+ return ret;
+ memset(buf, 0, 9);
+ ret = usb_bulk_msg(udev,
+ usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+ if (ret) {
+ err("boot packet recv bulk message failed: %d", ret);
+ return ret;
+ }
+ deb_fw("<<< ");
+ debug_dump(buf, act_len, deb_fw);
+ checksum = 0;
+ switch (type) {
+ case FW_CONFIG:
+ if (buf[2] != 0x11) {
+ err("boot bad config header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad config size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad config sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x04) {
+ err("boot bad config subtype.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad config checksum.");
+ return -EIO;
+ }
+ *reply = buf[6];
+ break;
+ case FW_CONFIRM:
+ if (buf[2] != 0x11) {
+ err("boot bad confirm header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad confirm size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad confirm sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x02) {
+ err("boot bad confirm subtype.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad confirm checksum.");
+ return -EIO;
+ }
+ *reply = buf[6];
+ break;
+ case FW_BOOT:
+ if (buf[2] != 0x10) {
+ err("boot bad boot header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad boot size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad boot sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x01) {
+ err("boot bad boot pattern 01.");
+ return -EIO;
+ }
+ if (buf[6] != 0x10) {
+ err("boot bad boot pattern 10.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad boot checksum.");
+ return -EIO;
+ }
+ break;
+
+ }
+
+ return 0;
+}
+
+int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+ int i, packets, ret, act_len;
+
+ u8 buf[FW_BULKOUT_SIZE + 2];
+ u8 reply;
+
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ if (reply != 0x01) {
+ err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+ return -EIO;
+ }
+ packets = fw->size / FW_BULKOUT_SIZE;
+ buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+ buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+ for (i = 0; i < packets; i++) {
+ memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+ FW_BULKOUT_SIZE);
+ deb_fw(">>> ");
+ debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x02),
+ buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+ if (ret) {
+ err("firmware download failed at packet %d with code %d", i, ret);
+ return ret;
+ }
+ }
+ ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+ if (ret)
+ return ret;
+ if (reply != (u8) (packets & 0xff)) {
+ err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+ return -EIO;
+ }
+ ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+ if (ret)
+ return ret;
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ if (reply != 0x02) {
+ err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+ return -EIO;
+ }
+
+ return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+ struct af9005_device_state *st = d->priv;
+ int temp, ret;
+
+ if (onoff && dvb_usb_af9005_led)
+ temp = 1;
+ else
+ temp = 0;
+ if (st->led_state != temp) {
+ ret =
+ af9005_write_register_bits(d, xd_p_reg_top_locken1,
+ reg_top_locken1_pos,
+ reg_top_locken1_len, temp);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_register_bits(d, xd_p_reg_top_lock1,
+ reg_top_lock1_pos,
+ reg_top_lock1_len, temp);
+ if (ret)
+ return ret;
+ st->led_state = temp;
+ }
+ return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ u8 buf[8];
+ int i;
+
+ /* without these calls the first commands after downloading
+ the firmware fail. I put these calls here to simulate
+ what it is done in dvb-usb-init.c.
+ */
+ struct usb_device *udev = adap->dev->udev;
+ usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+ if (dvb_usb_af9005_dump_eeprom) {
+ printk("EEPROM DUMP\n");
+ for (i = 0; i < 255; i += 8) {
+ af9005_read_eeprom(adap->dev, i, buf, 8);
+ printk("ADDR %x ", i);
+ debug_dump(buf, 8, printk);
+ }
+ }
+ adap->fe = af9005_fe_attach(adap->dev);
+ return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+ struct af9005_device_state *st = d->priv;
+ int ret, len;
+
+ u8 obuf[5];
+ u8 ibuf[256];
+
+ *state = REMOTE_NO_KEY_PRESSED;
+ if (rc_decode == NULL) {
+ /* it shouldn't never come here */
+ return 0;
+ }
+ /* deb_info("rc_query\n"); */
+ obuf[0] = 3; /* rest of packet length low */
+ obuf[1] = 0; /* rest of packet lentgh high */
+ obuf[2] = 0x40; /* read remote */
+ obuf[3] = 1; /* rest of packet length */
+ obuf[4] = st->sequence++; /* sequence number */
+ ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+ if (ret) {
+ err("rc query failed");
+ return ret;
+ }
+ if (ibuf[2] != 0x41) {
+ err("rc query bad header.");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("rc query bad sequence.");
+ return -EIO;
+ }
+ len = ibuf[5];
+ if (len > 246) {
+ err("rc query invalid length");
+ return -EIO;
+ }
+ if (len > 0) {
+ deb_rc("rc data (%d) ", len);
+ debug_dump((ibuf + 6), len, deb_rc);
+ ret = rc_decode(d, &ibuf[6], len, event, state);
+ if (ret) {
+ err("rc_decode failed");
+ return ret;
+ } else {
+ deb_rc("rc_decode state %x event %x\n", *state, *event);
+ if (*state == REMOTE_KEY_REPEAT)
+ *event = d->last_event;
+ }
+ }
+ return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+ return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+ deb_info("pid filter control onoff %d\n", onoff);
+ if (onoff) {
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_register_bits(adap->dev,
+ XD_MP2IF_DMX_CTRL, 1, 1, 1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+ } else
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+ if (ret)
+ return ret;
+ deb_info("pid filter control ok\n");
+ return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+ u16 pid, int onoff)
+{
+ u8 cmd = index & 0x1f;
+ int ret;
+ deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+ pid, onoff);
+ if (onoff) {
+ /* cannot use it as pid_filter_ctrl since it has to be done
+ before setting the first pid */
+ if (adap->feedcount == 1) {
+ deb_info("first pid set, enable pid table\n");
+ ret = af9005_pid_filter_control(adap, onoff);
+ if (ret)
+ return ret;
+ }
+ ret =
+ af9005_write_ofdm_register(adap->dev,
+ XD_MP2IF_PID_DATA_L,
+ (u8) (pid & 0xff));
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(adap->dev,
+ XD_MP2IF_PID_DATA_H,
+ (u8) (pid >> 8));
+ if (ret)
+ return ret;
+ cmd |= 0x20 | 0x40;
+ } else {
+ if (adap->feedcount == 0) {
+ deb_info("last pid unset, disable pid table\n");
+ ret = af9005_pid_filter_control(adap, onoff);
+ if (ret)
+ return ret;
+ }
+ }
+ ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+ if (ret)
+ return ret;
+ deb_info("set pid ok\n");
+ return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ int ret;
+ u8 reply;
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ deb_info("result of FW_CONFIG in identify state %d\n", reply);
+ if (reply == 0x01)
+ *cold = 1;
+ else if (reply == 0x02)
+ *cold = 0;
+ else
+ return -EIO;
+ deb_info("Identify state cold = %d\n", *cold);
+ return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+}
+
+static struct usb_device_id af9005_usb_table[] = {
+ {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+ {0},
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "af9005.fw",
+ .download_firmware = af9005_download_firmware,
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct af9005_device_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps =
+ DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = af9005_pid_filter,
+ /* .pid_filter_ctrl = af9005_pid_filter_control, */
+ .frontend_attach = af9005_frontend_attach,
+ /* .tuner_attach = af9005_tuner_attach, */
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 4096, /* actual size seen is 3948 */
+ }
+ }
+ },
+ }
+ },
+ .power_ctrl = af9005_power_ctrl,
+ .identify_state = af9005_identify_state,
+
+ .i2c_algo = &af9005_i2c_algo,
+
+ .rc_interval = 200,
+ .rc_key_map = NULL,
+ .rc_key_map_size = 0,
+ .rc_query = af9005_rc_query,
+
+ .num_device_descs = 2,
+ .devices = {
+ {.name = "Afatech DVB-T USB1.1 stick",
+ .cold_ids = {&af9005_usb_table[0], NULL},
+ .warm_ids = {NULL},
+ },
+ {.name = "TerraTec Cinergy T USB XE",
+ .cold_ids = {&af9005_usb_table[1], NULL},
+ .warm_ids = {NULL},
+ },
+ {NULL},
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+ .name = "dvb_usb_af9005",
+ .probe = af9005_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&af9005_usb_driver))) {
+ err("usb_register failed. (%d)", result);
+ return result;
+ }
+ rc_decode = symbol_request(af9005_rc_decode);
+ rc_keys = symbol_request(af9005_rc_keys);
+ rc_keys_size = symbol_request(af9005_rc_keys_size);
+ if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+ err("af9005_rc_decode function not found, disabling remote");
+ af9005_properties.rc_query = NULL;
+ } else {
+ af9005_properties.rc_key_map = rc_keys;
+ af9005_properties.rc_key_map_size = *rc_keys_size;
+ }
+
+ return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+ /* release rc decode symbols */
+ if (rc_decode != NULL)
+ symbol_put(af9005_rc_decode);
+ if (rc_keys != NULL)
+ symbol_put(af9005_rc_keys);
+ if (rc_keys_size != NULL)
+ symbol_put(af9005_rc_keys_size);
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
new file mode 100644
index 000000000000..0bc48a012187
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern int dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+ FW_CONFIG,
+ FW_CONFIRM,
+ FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG 0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW 0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER 0x80
+#define AF9005_CMD_BURST 0x02
+#define AF9005_CMD_AUTOINC 0x04
+#define AF9005_CMD_READ 0x00
+#define AF9005_CMD_WRITE 0x01
+
+/* af9005 registers */
+#define APO_REG_RESET 0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER 0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER 0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */
+#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */
+
+/***********************************************************************
+ * Apollo Registers from VLSI *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc 0xA000
+#define reg_aagc_inverted_agc_pos 0
+#define reg_aagc_inverted_agc_len 1
+#define reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only 0xA000
+#define reg_aagc_sign_only_pos 1
+#define reg_aagc_sign_only_len 1
+#define reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en 0xA000
+#define reg_aagc_slow_adc_en_pos 2
+#define reg_aagc_slow_adc_en_len 1
+#define reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale 0xA000
+#define reg_aagc_slow_adc_scale_pos 3
+#define reg_aagc_slow_adc_scale_len 5
+#define reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock 0xA001
+#define reg_aagc_check_slow_adc_lock_pos 0
+#define reg_aagc_check_slow_adc_lock_len 1
+#define reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control 0xA001
+#define reg_aagc_init_control_pos 1
+#define reg_aagc_init_control_len 1
+#define reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel 0xA001
+#define reg_aagc_total_gain_sel_pos 2
+#define reg_aagc_total_gain_sel_len 2
+#define reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv 0xA001
+#define reg_aagc_out_inv_pos 5
+#define reg_aagc_out_inv_len 1
+#define reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en 0xA001
+#define reg_aagc_int_en_pos 6
+#define reg_aagc_int_en_len 1
+#define reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag 0xA001
+#define reg_aagc_lock_change_flag_pos 7
+#define reg_aagc_lock_change_flag_len 1
+#define reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002
+#define reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003
+#define reg_aagc_rf_loop_bw_scale_track_pos 0
+#define reg_aagc_rf_loop_bw_scale_track_len 5
+#define reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004
+#define reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define reg_aagc_if_loop_bw_scale_acquire_len 5
+#define reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005
+#define reg_aagc_if_loop_bw_scale_track_pos 0
+#define reg_aagc_if_loop_bw_scale_track_len 5
+#define reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006
+#define reg_aagc_max_rf_agc_7_0_pos 0
+#define reg_aagc_max_rf_agc_7_0_len 8
+#define reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007
+#define reg_aagc_max_rf_agc_9_8_pos 0
+#define reg_aagc_max_rf_agc_9_8_len 2
+#define reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008
+#define reg_aagc_min_rf_agc_7_0_pos 0
+#define reg_aagc_min_rf_agc_7_0_len 8
+#define reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009
+#define reg_aagc_min_rf_agc_9_8_pos 0
+#define reg_aagc_min_rf_agc_9_8_len 2
+#define reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A
+#define reg_aagc_max_if_agc_7_0_pos 0
+#define reg_aagc_max_if_agc_7_0_len 8
+#define reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B
+#define reg_aagc_max_if_agc_9_8_pos 0
+#define reg_aagc_max_if_agc_9_8_len 2
+#define reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C
+#define reg_aagc_min_if_agc_7_0_pos 0
+#define reg_aagc_min_if_agc_7_0_len 8
+#define reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D
+#define reg_aagc_min_if_agc_9_8_pos 0
+#define reg_aagc_min_if_agc_9_8_len 2
+#define reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale 0xA00E
+#define reg_aagc_lock_sample_scale_pos 0
+#define reg_aagc_lock_sample_scale_len 5
+#define reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F
+#define reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F
+#define reg_aagc_rf_agc_lock_scale_track_pos 3
+#define reg_aagc_rf_agc_lock_scale_track_len 3
+#define reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010
+#define reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define reg_aagc_if_agc_lock_scale_acquire_len 3
+#define reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010
+#define reg_aagc_if_agc_lock_scale_track_pos 3
+#define reg_aagc_if_agc_lock_scale_track_len 3
+#define reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011
+#define reg_aagc_rf_top_numerator_7_0_pos 0
+#define reg_aagc_rf_top_numerator_7_0_len 8
+#define reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012
+#define reg_aagc_rf_top_numerator_9_8_pos 0
+#define reg_aagc_rf_top_numerator_9_8_len 2
+#define reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013
+#define reg_aagc_if_top_numerator_7_0_pos 0
+#define reg_aagc_if_top_numerator_7_0_len 8
+#define reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014
+#define reg_aagc_if_top_numerator_9_8_pos 0
+#define reg_aagc_if_top_numerator_9_8_len 2
+#define reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015
+#define reg_aagc_adc_out_desired_7_0_pos 0
+#define reg_aagc_adc_out_desired_7_0_len 8
+#define reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8 0xA016
+#define reg_aagc_adc_out_desired_8_pos 0
+#define reg_aagc_adc_out_desired_8_len 1
+#define reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain 0xA016
+#define reg_aagc_fixed_gain_pos 3
+#define reg_aagc_fixed_gain_len 1
+#define reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th 0xA016
+#define reg_aagc_lock_count_th_pos 4
+#define reg_aagc_lock_count_th_len 4
+#define reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017
+#define reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018
+#define reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019
+#define reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A
+#define reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B
+#define reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define reg_aagc_fixed_if_agc_control_7_0_len 8
+#define reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C
+#define reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define reg_aagc_fixed_if_agc_control_15_8_len 8
+#define reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D
+#define reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define reg_aagc_fixed_if_agc_control_23_16_len 8
+#define reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E
+#define reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define reg_aagc_fixed_if_agc_control_30_24_len 7
+#define reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F
+#define reg_aagc_rf_agc_unlock_numerator_pos 0
+#define reg_aagc_rf_agc_unlock_numerator_len 6
+#define reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020
+#define reg_aagc_if_agc_unlock_numerator_pos 0
+#define reg_aagc_if_agc_unlock_numerator_len 6
+#define reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th 0xA021
+#define reg_unplug_th_pos 0
+#define reg_unplug_th_len 8
+#define reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define reg_weak_signal_rfagc_thr_pos 0
+#define reg_weak_signal_rfagc_thr_len 8
+#define reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define reg_unplug_rf_gain_th_pos 0
+#define reg_unplug_rf_gain_th_len 8
+#define reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define reg_unplug_dtop_rf_gain_th_pos 0
+#define reg_unplug_dtop_rf_gain_th_len 8
+#define reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define reg_unplug_dtop_if_gain_th_pos 0
+#define reg_unplug_dtop_if_gain_th_len 8
+#define reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define reg_top_recover_at_unplug_en_pos 0
+#define reg_top_recover_at_unplug_en_len 1
+#define reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6 0xA027
+#define reg_aagc_rf_x6_pos 0
+#define reg_aagc_rf_x6_len 8
+#define reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7 0xA028
+#define reg_aagc_rf_x7_pos 0
+#define reg_aagc_rf_x7_len 8
+#define reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8 0xA029
+#define reg_aagc_rf_x8_pos 0
+#define reg_aagc_rf_x8_len 8
+#define reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9 0xA02A
+#define reg_aagc_rf_x9_pos 0
+#define reg_aagc_rf_x9_len 8
+#define reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10 0xA02B
+#define reg_aagc_rf_x10_pos 0
+#define reg_aagc_rf_x10_len 8
+#define reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11 0xA02C
+#define reg_aagc_rf_x11_pos 0
+#define reg_aagc_rf_x11_len 8
+#define reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12 0xA02D
+#define reg_aagc_rf_x12_pos 0
+#define reg_aagc_rf_x12_len 8
+#define reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13 0xA02E
+#define reg_aagc_rf_x13_pos 0
+#define reg_aagc_rf_x13_len 8
+#define reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0 0xA02F
+#define reg_aagc_if_x0_pos 0
+#define reg_aagc_if_x0_len 8
+#define reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1 0xA030
+#define reg_aagc_if_x1_pos 0
+#define reg_aagc_if_x1_len 8
+#define reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2 0xA031
+#define reg_aagc_if_x2_pos 0
+#define reg_aagc_if_x2_len 8
+#define reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3 0xA032
+#define reg_aagc_if_x3_pos 0
+#define reg_aagc_if_x3_len 8
+#define reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4 0xA033
+#define reg_aagc_if_x4_pos 0
+#define reg_aagc_if_x4_len 8
+#define reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5 0xA034
+#define reg_aagc_if_x5_pos 0
+#define reg_aagc_if_x5_len 8
+#define reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6 0xA035
+#define reg_aagc_if_x6_pos 0
+#define reg_aagc_if_x6_len 8
+#define reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7 0xA036
+#define reg_aagc_if_x7_pos 0
+#define reg_aagc_if_x7_len 8
+#define reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8 0xA037
+#define reg_aagc_if_x8_pos 0
+#define reg_aagc_if_x8_len 8
+#define reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9 0xA038
+#define reg_aagc_if_x9_pos 0
+#define reg_aagc_if_x9_len 8
+#define reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10 0xA039
+#define reg_aagc_if_x10_pos 0
+#define reg_aagc_if_x10_len 8
+#define reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11 0xA03A
+#define reg_aagc_if_x11_pos 0
+#define reg_aagc_if_x11_len 8
+#define reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12 0xA03B
+#define reg_aagc_if_x12_pos 0
+#define reg_aagc_if_x12_len 8
+#define reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13 0xA03C
+#define reg_aagc_if_x13_pos 0
+#define reg_aagc_if_x13_len 8
+#define reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D
+#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E
+#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0 0xA070
+#define reg_aagc_total_gain_7_0_pos 0
+#define reg_aagc_total_gain_7_0_len 8
+#define reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8 0xA071
+#define reg_aagc_total_gain_15_8_pos 0
+#define reg_aagc_total_gain_15_8_len 8
+#define reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074
+#define reg_aagc_in_sat_cnt_7_0_pos 0
+#define reg_aagc_in_sat_cnt_7_0_len 8
+#define reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075
+#define reg_aagc_in_sat_cnt_15_8_pos 0
+#define reg_aagc_in_sat_cnt_15_8_len 8
+#define reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076
+#define reg_aagc_in_sat_cnt_23_16_pos 0
+#define reg_aagc_in_sat_cnt_23_16_len 8
+#define reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077
+#define reg_aagc_in_sat_cnt_31_24_pos 0
+#define reg_aagc_in_sat_cnt_31_24_len 8
+#define reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078
+#define reg_aagc_digital_rf_volt_7_0_pos 0
+#define reg_aagc_digital_rf_volt_7_0_len 8
+#define reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079
+#define reg_aagc_digital_rf_volt_9_8_pos 0
+#define reg_aagc_digital_rf_volt_9_8_len 2
+#define reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A
+#define reg_aagc_digital_if_volt_7_0_pos 0
+#define reg_aagc_digital_if_volt_7_0_len 8
+#define reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B
+#define reg_aagc_digital_if_volt_9_8_pos 0
+#define reg_aagc_digital_if_volt_9_8_len 2
+#define reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain 0xA07C
+#define reg_aagc_rf_gain_pos 0
+#define reg_aagc_rf_gain_len 8
+#define reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain 0xA07D
+#define reg_aagc_if_gain_pos 0
+#define reg_aagc_if_gain_len 8
+#define reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator 0xA080
+#define tinr_imp_indicator_pos 0
+#define tinr_imp_indicator_len 2
+#define tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size 0xA080
+#define reg_tinr_fifo_size_pos 2
+#define reg_tinr_fifo_size_len 5
+#define reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th 0xA081
+#define reg_tinr_saturation_cnt_th_pos 0
+#define reg_tinr_saturation_cnt_th_len 4
+#define reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0 0xA081
+#define reg_tinr_saturation_th_3_0_pos 4
+#define reg_tinr_saturation_th_3_0_len 4
+#define reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4 0xA082
+#define reg_tinr_saturation_th_8_4_pos 0
+#define reg_tinr_saturation_th_8_4_len 5
+#define reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083
+#define reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define reg_tinr_imp_duration_th_2k_7_0_len 8
+#define reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084
+#define reg_tinr_imp_duration_th_2k_8_pos 0
+#define reg_tinr_imp_duration_th_2k_8_len 1
+#define reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085
+#define reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define reg_tinr_imp_duration_th_8k_7_0_len 8
+#define reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086
+#define reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define reg_tinr_imp_duration_th_8k_10_8_len 3
+#define reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087
+#define reg_tinr_freq_ratio_6m_7_0_pos 0
+#define reg_tinr_freq_ratio_6m_7_0_len 8
+#define reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088
+#define reg_tinr_freq_ratio_6m_12_8_pos 0
+#define reg_tinr_freq_ratio_6m_12_8_len 5
+#define reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089
+#define reg_tinr_freq_ratio_7m_7_0_pos 0
+#define reg_tinr_freq_ratio_7m_7_0_len 8
+#define reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A
+#define reg_tinr_freq_ratio_7m_12_8_pos 0
+#define reg_tinr_freq_ratio_7m_12_8_len 5
+#define reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B
+#define reg_tinr_freq_ratio_8m_7_0_pos 0
+#define reg_tinr_freq_ratio_8m_7_0_len 8
+#define reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C
+#define reg_tinr_freq_ratio_8m_12_8_pos 0
+#define reg_tinr_freq_ratio_8m_12_8_len 5
+#define reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D
+#define reg_tinr_imp_duration_th_low_2k_pos 0
+#define reg_tinr_imp_duration_th_low_2k_len 8
+#define reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E
+#define reg_tinr_imp_duration_th_low_8k_pos 0
+#define reg_tinr_imp_duration_th_low_8k_len 8
+#define reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0 0xA090
+#define reg_tinr_counter_7_0_pos 0
+#define reg_tinr_counter_7_0_len 8
+#define reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8 0xA091
+#define reg_tinr_counter_15_8_pos 0
+#define reg_tinr_counter_15_8_len 8
+#define reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en 0xA093
+#define reg_tinr_adative_tinr_en_pos 0
+#define reg_tinr_adative_tinr_en_len 1
+#define reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size 0xA093
+#define reg_tinr_peak_fifo_size_pos 1
+#define reg_tinr_peak_fifo_size_len 5
+#define reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst 0xA093
+#define reg_tinr_counter_rst_pos 6
+#define reg_tinr_counter_rst_len 1
+#define reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0 0xA094
+#define reg_tinr_search_period_7_0_pos 0
+#define reg_tinr_search_period_7_0_len 8
+#define reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8 0xA095
+#define reg_tinr_search_period_15_8_pos 0
+#define reg_tinr_search_period_15_8_len 8
+#define reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0 0xA0A0
+#define reg_ccifs_fcw_7_0_pos 0
+#define reg_ccifs_fcw_7_0_len 8
+#define reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8 0xA0A1
+#define reg_ccifs_fcw_12_8_pos 0
+#define reg_ccifs_fcw_12_8_len 5
+#define reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv 0xA0A1
+#define reg_ccifs_spec_inv_pos 5
+#define reg_ccifs_spec_inv_len 1
+#define reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger 0xA0A2
+#define reg_gp_trigger_pos 0
+#define reg_gp_trigger_len 1
+#define reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel 0xA0A2
+#define reg_trigger_sel_pos 1
+#define reg_trigger_sel_len 2
+#define reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm 0xA0A2
+#define reg_debug_ofdm_pos 3
+#define reg_debug_ofdm_len 2
+#define reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel 0xA0A3
+#define reg_trigger_module_sel_pos 0
+#define reg_trigger_module_sel_len 6
+#define reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel 0xA0A4
+#define reg_trigger_set_sel_pos 0
+#define reg_trigger_set_sel_len 6
+#define reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n 0xA0A4
+#define reg_fw_int_mask_n_pos 6
+#define reg_fw_int_mask_n_len 1
+#define reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group 0xA0A5
+#define reg_debug_group_pos 0
+#define reg_debug_group_len 4
+#define reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel 0xA0A5
+#define reg_odbg_clk_sel_pos 4
+#define reg_odbg_clk_sel_len 2
+#define reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc 0xA0C0
+#define reg_ccif_sc_pos 0
+#define reg_ccif_sc_len 4
+#define reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate 0xA0C1
+#define reg_ccif_saturate_pos 0
+#define reg_ccif_saturate_len 2
+#define reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate 0xA0C1
+#define reg_antif_saturate_pos 2
+#define reg_antif_saturate_len 4
+#define reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate 0xA0C2
+#define reg_acif_saturate_pos 0
+#define reg_acif_saturate_len 8
+#define reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8
+#define reg_tmr_timer0_threshold_7_0_pos 0
+#define reg_tmr_timer0_threshold_7_0_len 8
+#define reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9
+#define reg_tmr_timer0_threshold_15_8_pos 0
+#define reg_tmr_timer0_threshold_15_8_len 8
+#define reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable 0xA0CA
+#define reg_tmr_timer0_enable_pos 0
+#define reg_tmr_timer0_enable_len 1
+#define reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA
+#define reg_tmr_timer0_clk_sel_pos 1
+#define reg_tmr_timer0_clk_sel_len 1
+#define reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int 0xA0CA
+#define reg_tmr_timer0_int_pos 2
+#define reg_tmr_timer0_int_len 1
+#define reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst 0xA0CA
+#define reg_tmr_timer0_rst_pos 3
+#define reg_tmr_timer0_rst_len 1
+#define reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB
+#define reg_tmr_timer0_count_7_0_pos 0
+#define reg_tmr_timer0_count_7_0_len 8
+#define reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC
+#define reg_tmr_timer0_count_15_8_pos 0
+#define reg_tmr_timer0_count_15_8_len 8
+#define reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend 0xA0CD
+#define reg_suspend_pos 0
+#define reg_suspend_len 1
+#define reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy 0xA0CD
+#define reg_suspend_rdy_pos 1
+#define reg_suspend_rdy_len 1
+#define reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume 0xA0CD
+#define reg_resume_pos 2
+#define reg_resume_len 1
+#define reg_resume_lsb 0
+#define xd_p_reg_resume_rdy 0xA0CD
+#define reg_resume_rdy_pos 3
+#define reg_resume_rdy_len 1
+#define reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf 0xA0CE
+#define reg_fmf_pos 0
+#define reg_fmf_len 8
+#define reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0 0xA100
+#define ccid_accumulate_num_2k_7_0_pos 0
+#define ccid_accumulate_num_2k_7_0_len 8
+#define ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8 0xA101
+#define ccid_accumulate_num_2k_12_8_pos 0
+#define ccid_accumulate_num_2k_12_8_len 5
+#define ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0 0xA102
+#define ccid_accumulate_num_8k_7_0_pos 0
+#define ccid_accumulate_num_8k_7_0_len 8
+#define ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8 0xA103
+#define ccid_accumulate_num_8k_14_8_pos 0
+#define ccid_accumulate_num_8k_14_8_len 7
+#define ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0 0xA103
+#define ccid_desired_level_0_pos 7
+#define ccid_desired_level_0_len 1
+#define ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1 0xA104
+#define ccid_desired_level_8_1_pos 0
+#define ccid_desired_level_8_1_len 8
+#define ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay 0xA105
+#define ccid_apply_delay_pos 0
+#define ccid_apply_delay_len 7
+#define ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1 0xA106
+#define ccid_CCID_Threshold1_pos 0
+#define ccid_CCID_Threshold1_len 8
+#define ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2 0xA107
+#define ccid_CCID_Threshold2_pos 0
+#define ccid_CCID_Threshold2_len 8
+#define ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale 0xA108
+#define reg_ccid_gain_scale_pos 0
+#define reg_ccid_gain_scale_len 4
+#define reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set 0xA108
+#define reg_ccid2_passband_gain_set_pos 4
+#define reg_ccid2_passband_gain_set_len 4
+#define reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0 0xA109
+#define ccid_multiplier_7_0_pos 0
+#define ccid_multiplier_7_0_len 8
+#define ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8 0xA10A
+#define ccid_multiplier_15_8_pos 0
+#define ccid_multiplier_15_8_len 8
+#define ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits 0xA10B
+#define ccid_right_shift_bits_pos 0
+#define ccid_right_shift_bits_len 4
+#define ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0 0xA10C
+#define reg_ccid_sx_7_0_pos 0
+#define reg_ccid_sx_7_0_len 8
+#define reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8 0xA10D
+#define reg_ccid_sx_15_8_pos 0
+#define reg_ccid_sx_15_8_len 8
+#define reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16 0xA10E
+#define reg_ccid_sx_21_16_pos 0
+#define reg_ccid_sx_21_16_len 6
+#define reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0 0xA110
+#define reg_ccid_sy_7_0_pos 0
+#define reg_ccid_sy_7_0_len 8
+#define reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8 0xA111
+#define reg_ccid_sy_15_8_pos 0
+#define reg_ccid_sy_15_8_len 8
+#define reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16 0xA112
+#define reg_ccid_sy_23_16_pos 0
+#define reg_ccid_sy_23_16_len 8
+#define reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0 0xA114
+#define reg_ccid2_sz_7_0_pos 0
+#define reg_ccid2_sz_7_0_len 8
+#define reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8 0xA115
+#define reg_ccid2_sz_15_8_pos 0
+#define reg_ccid2_sz_15_8_len 8
+#define reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16 0xA116
+#define reg_ccid2_sz_23_16_pos 0
+#define reg_ccid2_sz_23_16_len 8
+#define reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24 0xA117
+#define reg_ccid2_sz_25_24_pos 0
+#define reg_ccid2_sz_25_24_len 2
+#define reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0 0xA118
+#define reg_ccid2_sy_7_0_pos 0
+#define reg_ccid2_sy_7_0_len 8
+#define reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8 0xA119
+#define reg_ccid2_sy_15_8_pos 0
+#define reg_ccid2_sy_15_8_len 8
+#define reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16 0xA11A
+#define reg_ccid2_sy_23_16_pos 0
+#define reg_ccid2_sy_23_16_len 8
+#define reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24 0xA11B
+#define reg_ccid2_sy_25_24_pos 0
+#define reg_ccid2_sy_25_24_len 2
+#define reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120
+#define dagc1_accumulate_num_2k_7_0_pos 0
+#define dagc1_accumulate_num_2k_7_0_len 8
+#define dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121
+#define dagc1_accumulate_num_2k_12_8_pos 0
+#define dagc1_accumulate_num_2k_12_8_len 5
+#define dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122
+#define dagc1_accumulate_num_8k_7_0_pos 0
+#define dagc1_accumulate_num_8k_7_0_len 8
+#define dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123
+#define dagc1_accumulate_num_8k_14_8_pos 0
+#define dagc1_accumulate_num_8k_14_8_len 7
+#define dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0 0xA123
+#define dagc1_desired_level_0_pos 7
+#define dagc1_desired_level_0_len 1
+#define dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1 0xA124
+#define dagc1_desired_level_8_1_pos 0
+#define dagc1_desired_level_8_1_len 8
+#define dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay 0xA125
+#define dagc1_apply_delay_pos 0
+#define dagc1_apply_delay_len 7
+#define dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl 0xA126
+#define dagc1_bypass_scale_ctl_pos 0
+#define dagc1_bypass_scale_ctl_len 2
+#define dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127
+#define reg_dagc1_in_sat_cnt_7_0_pos 0
+#define reg_dagc1_in_sat_cnt_7_0_len 8
+#define reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128
+#define reg_dagc1_in_sat_cnt_15_8_pos 0
+#define reg_dagc1_in_sat_cnt_15_8_len 8
+#define reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129
+#define reg_dagc1_in_sat_cnt_23_16_pos 0
+#define reg_dagc1_in_sat_cnt_23_16_len 8
+#define reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A
+#define reg_dagc1_in_sat_cnt_31_24_pos 0
+#define reg_dagc1_in_sat_cnt_31_24_len 8
+#define reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B
+#define reg_dagc1_out_sat_cnt_7_0_pos 0
+#define reg_dagc1_out_sat_cnt_7_0_len 8
+#define reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C
+#define reg_dagc1_out_sat_cnt_15_8_pos 0
+#define reg_dagc1_out_sat_cnt_15_8_len 8
+#define reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D
+#define reg_dagc1_out_sat_cnt_23_16_pos 0
+#define reg_dagc1_out_sat_cnt_23_16_len 8
+#define reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E
+#define reg_dagc1_out_sat_cnt_31_24_pos 0
+#define reg_dagc1_out_sat_cnt_31_24_len 8
+#define reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0 0xA136
+#define dagc1_multiplier_7_0_pos 0
+#define dagc1_multiplier_7_0_len 8
+#define dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8 0xA137
+#define dagc1_multiplier_15_8_pos 0
+#define dagc1_multiplier_15_8_len 8
+#define dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits 0xA138
+#define dagc1_right_shift_bits_pos 0
+#define dagc1_right_shift_bits_len 4
+#define dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0 0xA140
+#define reg_bfs_fcw_7_0_pos 0
+#define reg_bfs_fcw_7_0_len 8
+#define reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8 0xA141
+#define reg_bfs_fcw_15_8_pos 0
+#define reg_bfs_fcw_15_8_len 8
+#define reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16 0xA142
+#define reg_bfs_fcw_22_16_pos 0
+#define reg_bfs_fcw_22_16_len 7
+#define reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0 0xA144
+#define reg_antif_sf_7_0_pos 0
+#define reg_antif_sf_7_0_len 8
+#define reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8 0xA145
+#define reg_antif_sf_11_8_pos 0
+#define reg_antif_sf_11_8_len 4
+#define reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0 0xA150
+#define bfs_fcw_q_7_0_pos 0
+#define bfs_fcw_q_7_0_len 8
+#define bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8 0xA151
+#define bfs_fcw_q_15_8_pos 0
+#define bfs_fcw_q_15_8_len 8
+#define bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16 0xA152
+#define bfs_fcw_q_22_16_pos 0
+#define bfs_fcw_q_22_16_len 7
+#define bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu 0xA160
+#define reg_dca_enu_pos 0
+#define reg_dca_enu_len 1
+#define reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl 0xA160
+#define reg_dca_enl_pos 1
+#define reg_dca_enl_len 1
+#define reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip 0xA160
+#define reg_dca_lower_chip_pos 2
+#define reg_dca_lower_chip_len 1
+#define reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip 0xA160
+#define reg_dca_upper_chip_pos 3
+#define reg_dca_upper_chip_len 1
+#define reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch 0xA160
+#define reg_dca_platch_pos 4
+#define reg_dca_platch_len 1
+#define reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th 0xA161
+#define reg_dca_th_pos 0
+#define reg_dca_th_len 5
+#define reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale 0xA162
+#define reg_dca_scale_pos 0
+#define reg_dca_scale_len 4
+#define reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0 0xA163
+#define reg_dca_tone_7_0_pos 0
+#define reg_dca_tone_7_0_len 8
+#define reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8 0xA164
+#define reg_dca_tone_12_8_pos 0
+#define reg_dca_tone_12_8_len 5
+#define reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0 0xA165
+#define reg_dca_time_7_0_pos 0
+#define reg_dca_time_7_0_len 8
+#define reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8 0xA166
+#define reg_dca_time_15_8_pos 0
+#define reg_dca_time_15_8_len 8
+#define reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm 0xA167
+#define dcasm_pos 0
+#define dcasm_len 3
+#define dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0 0xA168
+#define reg_qnt_valuew_7_0_pos 0
+#define reg_qnt_valuew_7_0_len 8
+#define reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8 0xA169
+#define reg_qnt_valuew_10_8_pos 0
+#define reg_qnt_valuew_10_8_len 3
+#define reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0 0xA16A
+#define dca_sbx_gain_diff_7_0_pos 0
+#define dca_sbx_gain_diff_7_0_len 8
+#define dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8 0xA16B
+#define dca_sbx_gain_diff_9_8_pos 0
+#define dca_sbx_gain_diff_9_8_len 2
+#define dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone 0xA16C
+#define reg_dca_stand_alone_pos 0
+#define reg_dca_stand_alone_len 1
+#define reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en 0xA16C
+#define reg_dca_upper_out_en_pos 1
+#define reg_dca_upper_out_en_len 1
+#define reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en 0xA16C
+#define reg_dca_rc_en_pos 2
+#define reg_dca_rc_en_len 1
+#define reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send 0xA16C
+#define reg_dca_retrain_send_pos 3
+#define reg_dca_retrain_send_len 1
+#define reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec 0xA16C
+#define reg_dca_retrain_rec_pos 4
+#define reg_dca_retrain_rec_len 1
+#define reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy 0xA16C
+#define reg_dca_api_tpsrdy_pos 5
+#define reg_dca_api_tpsrdy_len 1
+#define reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap 0xA16D
+#define reg_dca_symbol_gap_pos 0
+#define reg_dca_symbol_gap_len 4
+#define reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E
+#define reg_qnt_nfvaluew_7_0_pos 0
+#define reg_qnt_nfvaluew_7_0_len 8
+#define reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F
+#define reg_qnt_nfvaluew_10_8_pos 0
+#define reg_qnt_nfvaluew_10_8_len 3
+#define reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0 0xA170
+#define reg_qnt_flatness_thr_7_0_pos 0
+#define reg_qnt_flatness_thr_7_0_len 8
+#define reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8 0xA171
+#define reg_qnt_flatness_thr_9_8_pos 0
+#define reg_qnt_flatness_thr_9_8_len 2
+#define reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0 0xA171
+#define reg_dca_tone_idx_5_0_pos 2
+#define reg_dca_tone_idx_5_0_len 6
+#define reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6 0xA172
+#define reg_dca_tone_idx_12_6_pos 0
+#define reg_dca_tone_idx_12_6_len 7
+#define reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld 0xA173
+#define reg_dca_data_vld_pos 0
+#define reg_dca_data_vld_len 1
+#define reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update 0xA173
+#define reg_dca_read_update_pos 1
+#define reg_dca_read_update_len 1
+#define reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0 0xA173
+#define reg_dca_data_re_5_0_pos 2
+#define reg_dca_data_re_5_0_len 6
+#define reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6 0xA174
+#define reg_dca_data_re_10_6_pos 0
+#define reg_dca_data_re_10_6_len 5
+#define reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0 0xA175
+#define reg_dca_data_im_7_0_pos 0
+#define reg_dca_data_im_7_0_len 8
+#define reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8 0xA176
+#define reg_dca_data_im_10_8_pos 0
+#define reg_dca_data_im_10_8_len 3
+#define reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0 0xA178
+#define reg_dca_data_h2_7_0_pos 0
+#define reg_dca_data_h2_7_0_len 8
+#define reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8 0xA179
+#define reg_dca_data_h2_9_8_pos 0
+#define reg_dca_data_h2_9_8_len 2
+#define reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0 0xA180
+#define reg_f_adc_7_0_pos 0
+#define reg_f_adc_7_0_len 8
+#define reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8 0xA181
+#define reg_f_adc_15_8_pos 0
+#define reg_f_adc_15_8_len 8
+#define reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16 0xA182
+#define reg_f_adc_23_16_pos 0
+#define reg_f_adc_23_16_len 8
+#define reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0 0xA190
+#define intp_mu_7_0_pos 0
+#define intp_mu_7_0_len 8
+#define intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8 0xA191
+#define intp_mu_15_8_pos 0
+#define intp_mu_15_8_len 8
+#define intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16 0xA192
+#define intp_mu_19_16_pos 0
+#define intp_mu_19_16_len 4
+#define intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst 0xA1A0
+#define reg_agc_rst_pos 0
+#define reg_agc_rst_len 1
+#define reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en 0xA1A0
+#define rf_agc_en_pos 1
+#define rf_agc_en_len 1
+#define rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis 0xA1A0
+#define rf_agc_dis_pos 2
+#define rf_agc_dis_len 1
+#define rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst 0xA1A0
+#define if_agc_rst_pos 3
+#define if_agc_rst_len 1
+#define if_agc_rst_lsb 0
+#define xd_p_if_agc_en 0xA1A0
+#define if_agc_en_pos 4
+#define if_agc_en_len 1
+#define if_agc_en_lsb 0
+#define xd_p_if_agc_dis 0xA1A0
+#define if_agc_dis_pos 5
+#define if_agc_dis_len 1
+#define if_agc_dis_lsb 0
+#define xd_p_agc_lock 0xA1A0
+#define agc_lock_pos 6
+#define agc_lock_len 1
+#define agc_lock_lsb 0
+#define xd_p_reg_tinr_rst 0xA1A1
+#define reg_tinr_rst_pos 0
+#define reg_tinr_rst_len 1
+#define reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en 0xA1A1
+#define reg_tinr_en_pos 1
+#define reg_tinr_en_len 1
+#define reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en 0xA1A2
+#define reg_ccifs_en_pos 0
+#define reg_ccifs_en_len 1
+#define reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis 0xA1A2
+#define reg_ccifs_dis_pos 1
+#define reg_ccifs_dis_len 1
+#define reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst 0xA1A2
+#define reg_ccifs_rst_pos 2
+#define reg_ccifs_rst_len 1
+#define reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp 0xA1A2
+#define reg_ccifs_byp_pos 3
+#define reg_ccifs_byp_len 1
+#define reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en 0xA1A3
+#define reg_ccif_en_pos 0
+#define reg_ccif_en_len 1
+#define reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis 0xA1A3
+#define reg_ccif_dis_pos 1
+#define reg_ccif_dis_len 1
+#define reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst 0xA1A3
+#define reg_ccif_rst_pos 2
+#define reg_ccif_rst_len 1
+#define reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp 0xA1A3
+#define reg_ccif_byp_pos 3
+#define reg_ccif_byp_len 1
+#define reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst 0xA1A4
+#define dagc1_rst_pos 0
+#define dagc1_rst_len 1
+#define dagc1_rst_lsb 0
+#define xd_p_dagc1_en 0xA1A4
+#define dagc1_en_pos 1
+#define dagc1_en_len 1
+#define dagc1_en_lsb 0
+#define xd_p_dagc1_mode 0xA1A4
+#define dagc1_mode_pos 2
+#define dagc1_mode_len 2
+#define dagc1_mode_lsb 0
+#define xd_p_dagc1_done 0xA1A4
+#define dagc1_done_pos 4
+#define dagc1_done_len 1
+#define dagc1_done_lsb 0
+#define xd_p_ccid_rst 0xA1A5
+#define ccid_rst_pos 0
+#define ccid_rst_len 1
+#define ccid_rst_lsb 0
+#define xd_p_ccid_en 0xA1A5
+#define ccid_en_pos 1
+#define ccid_en_len 1
+#define ccid_en_lsb 0
+#define xd_p_ccid_mode 0xA1A5
+#define ccid_mode_pos 2
+#define ccid_mode_len 2
+#define ccid_mode_lsb 0
+#define xd_p_ccid_done 0xA1A5
+#define ccid_done_pos 4
+#define ccid_done_len 1
+#define ccid_done_lsb 0
+#define xd_r_ccid_deted 0xA1A5
+#define ccid_deted_pos 5
+#define ccid_deted_len 1
+#define ccid_deted_lsb 0
+#define xd_p_ccid2_en 0xA1A5
+#define ccid2_en_pos 6
+#define ccid2_en_len 1
+#define ccid2_en_lsb 0
+#define xd_p_ccid2_done 0xA1A5
+#define ccid2_done_pos 7
+#define ccid2_done_len 1
+#define ccid2_done_lsb 0
+#define xd_p_reg_bfs_en 0xA1A6
+#define reg_bfs_en_pos 0
+#define reg_bfs_en_len 1
+#define reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis 0xA1A6
+#define reg_bfs_dis_pos 1
+#define reg_bfs_dis_len 1
+#define reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst 0xA1A6
+#define reg_bfs_rst_pos 2
+#define reg_bfs_rst_len 1
+#define reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp 0xA1A6
+#define reg_bfs_byp_pos 3
+#define reg_bfs_byp_len 1
+#define reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en 0xA1A7
+#define reg_antif_en_pos 0
+#define reg_antif_en_len 1
+#define reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis 0xA1A7
+#define reg_antif_dis_pos 1
+#define reg_antif_dis_len 1
+#define reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst 0xA1A7
+#define reg_antif_rst_pos 2
+#define reg_antif_rst_len 1
+#define reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp 0xA1A7
+#define reg_antif_byp_pos 3
+#define reg_antif_byp_len 1
+#define reg_antif_byp_lsb 0
+#define xd_p_intp_en 0xA1A8
+#define intp_en_pos 0
+#define intp_en_len 1
+#define intp_en_lsb 0
+#define xd_p_intp_dis 0xA1A8
+#define intp_dis_pos 1
+#define intp_dis_len 1
+#define intp_dis_lsb 0
+#define xd_p_intp_rst 0xA1A8
+#define intp_rst_pos 2
+#define intp_rst_len 1
+#define intp_rst_lsb 0
+#define xd_p_intp_byp 0xA1A8
+#define intp_byp_pos 3
+#define intp_byp_len 1
+#define intp_byp_lsb 0
+#define xd_p_reg_acif_en 0xA1A9
+#define reg_acif_en_pos 0
+#define reg_acif_en_len 1
+#define reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis 0xA1A9
+#define reg_acif_dis_pos 1
+#define reg_acif_dis_len 1
+#define reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst 0xA1A9
+#define reg_acif_rst_pos 2
+#define reg_acif_rst_len 1
+#define reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp 0xA1A9
+#define reg_acif_byp_pos 3
+#define reg_acif_byp_len 1
+#define reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode 0xA1A9
+#define reg_acif_sync_mode_pos 4
+#define reg_acif_sync_mode_len 1
+#define reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst 0xA1AA
+#define dagc2_rst_pos 0
+#define dagc2_rst_len 1
+#define dagc2_rst_lsb 0
+#define xd_p_dagc2_en 0xA1AA
+#define dagc2_en_pos 1
+#define dagc2_en_len 1
+#define dagc2_en_lsb 0
+#define xd_p_dagc2_mode 0xA1AA
+#define dagc2_mode_pos 2
+#define dagc2_mode_len 2
+#define dagc2_mode_lsb 0
+#define xd_p_dagc2_done 0xA1AA
+#define dagc2_done_pos 4
+#define dagc2_done_len 1
+#define dagc2_done_lsb 0
+#define xd_p_reg_dca_en 0xA1AB
+#define reg_dca_en_pos 0
+#define reg_dca_en_len 1
+#define reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0
+#define dagc2_accumulate_num_2k_7_0_pos 0
+#define dagc2_accumulate_num_2k_7_0_len 8
+#define dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1
+#define dagc2_accumulate_num_2k_12_8_pos 0
+#define dagc2_accumulate_num_2k_12_8_len 5
+#define dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2
+#define dagc2_accumulate_num_8k_7_0_pos 0
+#define dagc2_accumulate_num_8k_7_0_len 8
+#define dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3
+#define dagc2_accumulate_num_8k_12_8_pos 0
+#define dagc2_accumulate_num_8k_12_8_len 5
+#define dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0 0xA1C3
+#define dagc2_desired_level_2_0_pos 5
+#define dagc2_desired_level_2_0_len 3
+#define dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3 0xA1C4
+#define dagc2_desired_level_8_3_pos 0
+#define dagc2_desired_level_8_3_len 6
+#define dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay 0xA1C5
+#define dagc2_apply_delay_pos 0
+#define dagc2_apply_delay_len 7
+#define dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl 0xA1C6
+#define dagc2_bypass_scale_ctl_pos 0
+#define dagc2_bypass_scale_ctl_len 3
+#define dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1 0xA1C7
+#define dagc2_programmable_shift1_pos 0
+#define dagc2_programmable_shift1_len 8
+#define dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2 0xA1C8
+#define dagc2_programmable_shift2_pos 0
+#define dagc2_programmable_shift2_len 8
+#define dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9
+#define reg_dagc2_in_sat_cnt_7_0_pos 0
+#define reg_dagc2_in_sat_cnt_7_0_len 8
+#define reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA
+#define reg_dagc2_in_sat_cnt_15_8_pos 0
+#define reg_dagc2_in_sat_cnt_15_8_len 8
+#define reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB
+#define reg_dagc2_in_sat_cnt_23_16_pos 0
+#define reg_dagc2_in_sat_cnt_23_16_len 8
+#define reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC
+#define reg_dagc2_in_sat_cnt_31_24_pos 0
+#define reg_dagc2_in_sat_cnt_31_24_len 8
+#define reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD
+#define reg_dagc2_out_sat_cnt_7_0_pos 0
+#define reg_dagc2_out_sat_cnt_7_0_len 8
+#define reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE
+#define reg_dagc2_out_sat_cnt_15_8_pos 0
+#define reg_dagc2_out_sat_cnt_15_8_len 8
+#define reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF
+#define reg_dagc2_out_sat_cnt_23_16_pos 0
+#define reg_dagc2_out_sat_cnt_23_16_len 8
+#define reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0
+#define reg_dagc2_out_sat_cnt_31_24_pos 0
+#define reg_dagc2_out_sat_cnt_31_24_len 8
+#define reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0 0xA1D6
+#define dagc2_multiplier_7_0_pos 0
+#define dagc2_multiplier_7_0_len 8
+#define dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8 0xA1D7
+#define dagc2_multiplier_15_8_pos 0
+#define dagc2_multiplier_15_8_len 8
+#define dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits 0xA1D8
+#define dagc2_right_shift_bits_pos 0
+#define dagc2_right_shift_bits_len 4
+#define dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0 0xA200
+#define cfoe_NS_coeff1_7_0_pos 0
+#define cfoe_NS_coeff1_7_0_len 8
+#define cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8 0xA201
+#define cfoe_NS_coeff1_15_8_pos 0
+#define cfoe_NS_coeff1_15_8_len 8
+#define cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16 0xA202
+#define cfoe_NS_coeff1_23_16_pos 0
+#define cfoe_NS_coeff1_23_16_len 8
+#define cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24 0xA203
+#define cfoe_NS_coeff1_25_24_pos 0
+#define cfoe_NS_coeff1_25_24_len 2
+#define cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0 0xA203
+#define cfoe_NS_coeff2_5_0_pos 2
+#define cfoe_NS_coeff2_5_0_len 6
+#define cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6 0xA204
+#define cfoe_NS_coeff2_13_6_pos 0
+#define cfoe_NS_coeff2_13_6_len 8
+#define cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14 0xA205
+#define cfoe_NS_coeff2_21_14_pos 0
+#define cfoe_NS_coeff2_21_14_len 8
+#define cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22 0xA206
+#define cfoe_NS_coeff2_24_22_pos 0
+#define cfoe_NS_coeff2_24_22_len 3
+#define cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0 0xA206
+#define cfoe_lf_c1_4_0_pos 3
+#define cfoe_lf_c1_4_0_len 5
+#define cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5 0xA207
+#define cfoe_lf_c1_12_5_pos 0
+#define cfoe_lf_c1_12_5_len 8
+#define cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13 0xA208
+#define cfoe_lf_c1_20_13_pos 0
+#define cfoe_lf_c1_20_13_len 8
+#define cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21 0xA209
+#define cfoe_lf_c1_25_21_pos 0
+#define cfoe_lf_c1_25_21_len 5
+#define cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0 0xA209
+#define cfoe_lf_c2_2_0_pos 5
+#define cfoe_lf_c2_2_0_len 3
+#define cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3 0xA20A
+#define cfoe_lf_c2_10_3_pos 0
+#define cfoe_lf_c2_10_3_len 8
+#define cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11 0xA20B
+#define cfoe_lf_c2_18_11_pos 0
+#define cfoe_lf_c2_18_11_len 8
+#define cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19 0xA20C
+#define cfoe_lf_c2_25_19_pos 0
+#define cfoe_lf_c2_25_19_len 7
+#define cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0 0xA20D
+#define cfoe_ifod_7_0_pos 0
+#define cfoe_ifod_7_0_len 8
+#define cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8 0xA20E
+#define cfoe_ifod_10_8_pos 0
+#define cfoe_ifod_10_8_len 3
+#define cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th 0xA20E
+#define cfoe_Divg_ctr_th_pos 4
+#define cfoe_Divg_ctr_th_len 4
+#define cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th 0xA20F
+#define cfoe_FOT_divg_th_pos 0
+#define cfoe_FOT_divg_th_len 8
+#define cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th 0xA210
+#define cfoe_FOT_cnvg_th_pos 0
+#define cfoe_FOT_cnvg_th_len 8
+#define cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0 0xA211
+#define reg_cfoe_offset_7_0_pos 0
+#define reg_cfoe_offset_7_0_len 8
+#define reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8 0xA212
+#define reg_cfoe_offset_9_8_pos 0
+#define reg_cfoe_offset_9_8_len 2
+#define reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212
+#define reg_cfoe_ifoe_sign_corr_pos 2
+#define reg_cfoe_ifoe_sign_corr_len 1
+#define reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0 0xA218
+#define cfoe_fot_LF_output_7_0_pos 0
+#define cfoe_fot_LF_output_7_0_len 8
+#define cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8 0xA219
+#define cfoe_fot_LF_output_15_8_pos 0
+#define cfoe_fot_LF_output_15_8_len 8
+#define cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0 0xA21A
+#define cfoe_ifo_metric_7_0_pos 0
+#define cfoe_ifo_metric_7_0_len 8
+#define cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8 0xA21B
+#define cfoe_ifo_metric_15_8_pos 0
+#define cfoe_ifo_metric_15_8_len 8
+#define cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16 0xA21C
+#define cfoe_ifo_metric_23_16_pos 0
+#define cfoe_ifo_metric_23_16_len 8
+#define cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu 0xA220
+#define ste_Nu_pos 0
+#define ste_Nu_len 2
+#define ste_Nu_lsb 0
+#define xd_p_ste_GI 0xA220
+#define ste_GI_pos 2
+#define ste_GI_len 3
+#define ste_GI_lsb 0
+#define xd_p_ste_symbol_num 0xA221
+#define ste_symbol_num_pos 0
+#define ste_symbol_num_len 2
+#define ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num 0xA221
+#define ste_sample_num_pos 2
+#define ste_sample_num_len 2
+#define ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en 0xA221
+#define reg_ste_buf_en_pos 7
+#define reg_ste_buf_en_len 1
+#define reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0 0xA222
+#define ste_FFT_offset_7_0_pos 0
+#define ste_FFT_offset_7_0_len 8
+#define ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8 0xA223
+#define ste_FFT_offset_11_8_pos 0
+#define ste_FFT_offset_11_8_len 4
+#define ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod 0xA223
+#define reg_ste_tstmod_pos 5
+#define reg_ste_tstmod_len 1
+#define reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0 0xA224
+#define ste_adv_start_7_0_pos 0
+#define ste_adv_start_7_0_len 8
+#define ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8 0xA225
+#define ste_adv_start_10_8_pos 0
+#define ste_adv_start_10_8_len 3
+#define ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop 0xA226
+#define ste_adv_stop_pos 0
+#define ste_adv_stop_len 8
+#define ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0 0xA228
+#define ste_P_value_7_0_pos 0
+#define ste_P_value_7_0_len 8
+#define ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8 0xA229
+#define ste_P_value_10_8_pos 0
+#define ste_P_value_10_8_len 3
+#define ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0 0xA22A
+#define ste_M_value_7_0_pos 0
+#define ste_M_value_7_0_len 8
+#define ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8 0xA22B
+#define ste_M_value_10_8_pos 0
+#define ste_M_value_10_8_len 3
+#define ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1 0xA22C
+#define ste_H1_pos 0
+#define ste_H1_len 7
+#define ste_H1_lsb 0
+#define xd_r_ste_H2 0xA22D
+#define ste_H2_pos 0
+#define ste_H2_len 7
+#define ste_H2_lsb 0
+#define xd_r_ste_H3 0xA22E
+#define ste_H3_pos 0
+#define ste_H3_len 7
+#define ste_H3_lsb 0
+#define xd_r_ste_H4 0xA22F
+#define ste_H4_pos 0
+#define ste_H4_len 7
+#define ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0 0xA230
+#define ste_Corr_value_I_7_0_pos 0
+#define ste_Corr_value_I_7_0_len 8
+#define ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8 0xA231
+#define ste_Corr_value_I_15_8_pos 0
+#define ste_Corr_value_I_15_8_len 8
+#define ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16 0xA232
+#define ste_Corr_value_I_23_16_pos 0
+#define ste_Corr_value_I_23_16_len 8
+#define ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24 0xA233
+#define ste_Corr_value_I_27_24_pos 0
+#define ste_Corr_value_I_27_24_len 4
+#define ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0 0xA234
+#define ste_Corr_value_Q_7_0_pos 0
+#define ste_Corr_value_Q_7_0_len 8
+#define ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8 0xA235
+#define ste_Corr_value_Q_15_8_pos 0
+#define ste_Corr_value_Q_15_8_len 8
+#define ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16 0xA236
+#define ste_Corr_value_Q_23_16_pos 0
+#define ste_Corr_value_Q_23_16_len 8
+#define ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24 0xA237
+#define ste_Corr_value_Q_27_24_pos 0
+#define ste_Corr_value_Q_27_24_len 4
+#define ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0 0xA238
+#define ste_J_num_7_0_pos 0
+#define ste_J_num_7_0_len 8
+#define ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8 0xA239
+#define ste_J_num_15_8_pos 0
+#define ste_J_num_15_8_len 8
+#define ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16 0xA23A
+#define ste_J_num_23_16_pos 0
+#define ste_J_num_23_16_len 8
+#define ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24 0xA23B
+#define ste_J_num_31_24_pos 0
+#define ste_J_num_31_24_len 8
+#define ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0 0xA23C
+#define ste_J_den_7_0_pos 0
+#define ste_J_den_7_0_len 8
+#define ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8 0xA23D
+#define ste_J_den_15_8_pos 0
+#define ste_J_den_15_8_len 8
+#define ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16 0xA23E
+#define ste_J_den_18_16_pos 0
+#define ste_J_den_18_16_len 3
+#define ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator 0xA23E
+#define ste_Beacon_Indicator_pos 4
+#define ste_Beacon_Indicator_len 1
+#define ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num 0xA250
+#define tpsd_Frame_Num_pos 0
+#define tpsd_Frame_Num_len 2
+#define tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel 0xA250
+#define tpsd_Constel_pos 2
+#define tpsd_Constel_len 2
+#define tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI 0xA250
+#define tpsd_GI_pos 4
+#define tpsd_GI_len 2
+#define tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode 0xA250
+#define tpsd_Mode_pos 6
+#define tpsd_Mode_len 2
+#define tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP 0xA251
+#define tpsd_CR_HP_pos 0
+#define tpsd_CR_HP_len 3
+#define tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP 0xA251
+#define tpsd_CR_LP_pos 3
+#define tpsd_CR_LP_len 3
+#define tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie 0xA252
+#define tpsd_Hie_pos 0
+#define tpsd_Hie_len 3
+#define tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits 0xA252
+#define tpsd_Res_Bits_pos 3
+#define tpsd_Res_Bits_len 5
+#define tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0 0xA253
+#define tpsd_Res_Bits_0_pos 0
+#define tpsd_Res_Bits_0_len 1
+#define tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd 0xA253
+#define tpsd_LengthInd_pos 1
+#define tpsd_LengthInd_len 6
+#define tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0 0xA254
+#define tpsd_Cell_Id_7_0_pos 0
+#define tpsd_Cell_Id_7_0_len 8
+#define tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8 0xA255
+#define tpsd_Cell_Id_15_8_pos 0
+#define tpsd_Cell_Id_15_8_len 8
+#define tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0 0xA260
+#define reg_fft_mask_tone0_7_0_pos 0
+#define reg_fft_mask_tone0_7_0_len 8
+#define reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8 0xA261
+#define reg_fft_mask_tone0_12_8_pos 0
+#define reg_fft_mask_tone0_12_8_len 5
+#define reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0 0xA262
+#define reg_fft_mask_tone1_7_0_pos 0
+#define reg_fft_mask_tone1_7_0_len 8
+#define reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8 0xA263
+#define reg_fft_mask_tone1_12_8_pos 0
+#define reg_fft_mask_tone1_12_8_len 5
+#define reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0 0xA264
+#define reg_fft_mask_tone2_7_0_pos 0
+#define reg_fft_mask_tone2_7_0_len 8
+#define reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8 0xA265
+#define reg_fft_mask_tone2_12_8_pos 0
+#define reg_fft_mask_tone2_12_8_len 5
+#define reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0 0xA266
+#define reg_fft_mask_tone3_7_0_pos 0
+#define reg_fft_mask_tone3_7_0_len 8
+#define reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8 0xA267
+#define reg_fft_mask_tone3_12_8_pos 0
+#define reg_fft_mask_tone3_12_8_len 5
+#define reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0 0xA268
+#define reg_fft_mask_from0_7_0_pos 0
+#define reg_fft_mask_from0_7_0_len 8
+#define reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8 0xA269
+#define reg_fft_mask_from0_12_8_pos 0
+#define reg_fft_mask_from0_12_8_len 5
+#define reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0 0xA26A
+#define reg_fft_mask_to0_7_0_pos 0
+#define reg_fft_mask_to0_7_0_len 8
+#define reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8 0xA26B
+#define reg_fft_mask_to0_12_8_pos 0
+#define reg_fft_mask_to0_12_8_len 5
+#define reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0 0xA26C
+#define reg_fft_mask_from1_7_0_pos 0
+#define reg_fft_mask_from1_7_0_len 8
+#define reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8 0xA26D
+#define reg_fft_mask_from1_12_8_pos 0
+#define reg_fft_mask_from1_12_8_len 5
+#define reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0 0xA26E
+#define reg_fft_mask_to1_7_0_pos 0
+#define reg_fft_mask_to1_7_0_len 8
+#define reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8 0xA26F
+#define reg_fft_mask_to1_12_8_pos 0
+#define reg_fft_mask_to1_12_8_len 5
+#define reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0 0xA280
+#define reg_cge_idx0_7_0_pos 0
+#define reg_cge_idx0_7_0_len 8
+#define reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8 0xA281
+#define reg_cge_idx0_12_8_pos 0
+#define reg_cge_idx0_12_8_len 5
+#define reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0 0xA282
+#define reg_cge_idx1_7_0_pos 0
+#define reg_cge_idx1_7_0_len 8
+#define reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8 0xA283
+#define reg_cge_idx1_12_8_pos 0
+#define reg_cge_idx1_12_8_len 5
+#define reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0 0xA284
+#define reg_cge_idx2_7_0_pos 0
+#define reg_cge_idx2_7_0_len 8
+#define reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8 0xA285
+#define reg_cge_idx2_12_8_pos 0
+#define reg_cge_idx2_12_8_len 5
+#define reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0 0xA286
+#define reg_cge_idx3_7_0_pos 0
+#define reg_cge_idx3_7_0_len 8
+#define reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8 0xA287
+#define reg_cge_idx3_12_8_pos 0
+#define reg_cge_idx3_12_8_len 5
+#define reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0 0xA288
+#define reg_cge_idx4_7_0_pos 0
+#define reg_cge_idx4_7_0_len 8
+#define reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8 0xA289
+#define reg_cge_idx4_12_8_pos 0
+#define reg_cge_idx4_12_8_len 5
+#define reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0 0xA28A
+#define reg_cge_idx5_7_0_pos 0
+#define reg_cge_idx5_7_0_len 8
+#define reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8 0xA28B
+#define reg_cge_idx5_12_8_pos 0
+#define reg_cge_idx5_12_8_len 5
+#define reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0 0xA28C
+#define reg_cge_idx6_7_0_pos 0
+#define reg_cge_idx6_7_0_len 8
+#define reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8 0xA28D
+#define reg_cge_idx6_12_8_pos 0
+#define reg_cge_idx6_12_8_len 5
+#define reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0 0xA28E
+#define reg_cge_idx7_7_0_pos 0
+#define reg_cge_idx7_7_0_len 8
+#define reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8 0xA28F
+#define reg_cge_idx7_12_8_pos 0
+#define reg_cge_idx7_12_8_len 5
+#define reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0 0xA290
+#define reg_cge_idx8_7_0_pos 0
+#define reg_cge_idx8_7_0_len 8
+#define reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8 0xA291
+#define reg_cge_idx8_12_8_pos 0
+#define reg_cge_idx8_12_8_len 5
+#define reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0 0xA292
+#define reg_cge_idx9_7_0_pos 0
+#define reg_cge_idx9_7_0_len 8
+#define reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8 0xA293
+#define reg_cge_idx9_12_8_pos 0
+#define reg_cge_idx9_12_8_len 5
+#define reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0 0xA294
+#define reg_cge_idx10_7_0_pos 0
+#define reg_cge_idx10_7_0_len 8
+#define reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8 0xA295
+#define reg_cge_idx10_12_8_pos 0
+#define reg_cge_idx10_12_8_len 5
+#define reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0 0xA296
+#define reg_cge_idx11_7_0_pos 0
+#define reg_cge_idx11_7_0_len 8
+#define reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8 0xA297
+#define reg_cge_idx11_12_8_pos 0
+#define reg_cge_idx11_12_8_len 5
+#define reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0 0xA298
+#define reg_cge_idx12_7_0_pos 0
+#define reg_cge_idx12_7_0_len 8
+#define reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8 0xA299
+#define reg_cge_idx12_12_8_pos 0
+#define reg_cge_idx12_12_8_len 5
+#define reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0 0xA29A
+#define reg_cge_idx13_7_0_pos 0
+#define reg_cge_idx13_7_0_len 8
+#define reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8 0xA29B
+#define reg_cge_idx13_12_8_pos 0
+#define reg_cge_idx13_12_8_len 5
+#define reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0 0xA29C
+#define reg_cge_idx14_7_0_pos 0
+#define reg_cge_idx14_7_0_len 8
+#define reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8 0xA29D
+#define reg_cge_idx14_12_8_pos 0
+#define reg_cge_idx14_12_8_len 5
+#define reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0 0xA29E
+#define reg_cge_idx15_7_0_pos 0
+#define reg_cge_idx15_7_0_len 8
+#define reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8 0xA29F
+#define reg_cge_idx15_12_8_pos 0
+#define reg_cge_idx15_12_8_len 5
+#define reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc 0xA2A8
+#define reg_fft_crc_pos 0
+#define reg_fft_crc_len 8
+#define reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max 0xA2A9
+#define fd_fft_shift_max_pos 0
+#define fd_fft_shift_max_len 4
+#define fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift 0xA2A9
+#define fd_fft_shift_pos 4
+#define fd_fft_shift_len 4
+#define fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num 0xA2AA
+#define fd_fft_frame_num_pos 0
+#define fd_fft_frame_num_len 2
+#define fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count 0xA2AB
+#define fd_fft_symbol_count_pos 0
+#define fd_fft_symbol_count_len 7
+#define fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0 0xA2AC
+#define reg_fft_idx_max_7_0_pos 0
+#define reg_fft_idx_max_7_0_len 8
+#define reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8 0xA2AD
+#define reg_fft_idx_max_12_8_pos 0
+#define reg_fft_idx_max_12_8_len 5
+#define reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program 0xA2AE
+#define reg_cge_program_pos 0
+#define reg_cge_program_len 1
+#define reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed 0xA2AE
+#define reg_cge_fixed_pos 1
+#define reg_cge_fixed_len 1
+#define reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en 0xA2AE
+#define reg_fft_rotate_en_pos 2
+#define reg_fft_rotate_en_len 1
+#define reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0 0xA2AE
+#define reg_fft_rotate_base_4_0_pos 3
+#define reg_fft_rotate_base_4_0_len 5
+#define reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5 0xA2AF
+#define reg_fft_rotate_base_12_5_pos 0
+#define reg_fft_rotate_base_12_5_len 8
+#define reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd 0xA2B8
+#define reg_gp_trigger_fd_pos 0
+#define reg_gp_trigger_fd_len 1
+#define reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd 0xA2B8
+#define reg_trigger_sel_fd_pos 1
+#define reg_trigger_sel_fd_len 2
+#define reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd 0xA2B9
+#define reg_trigger_module_sel_fd_pos 0
+#define reg_trigger_module_sel_fd_len 6
+#define reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd 0xA2BA
+#define reg_trigger_set_sel_fd_pos 0
+#define reg_trigger_set_sel_fd_len 6
+#define reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0 0xA2BC
+#define reg_fd_noname_7_0_pos 0
+#define reg_fd_noname_7_0_len 8
+#define reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8 0xA2BD
+#define reg_fd_noname_15_8_pos 0
+#define reg_fd_noname_15_8_len 8
+#define reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16 0xA2BE
+#define reg_fd_noname_23_16_pos 0
+#define reg_fd_noname_23_16_len 8
+#define reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24 0xA2BF
+#define reg_fd_noname_31_24_pos 0
+#define reg_fd_noname_31_24_len 8
+#define reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0
+#define fd_fpcc_cp_corr_signn_pos 0
+#define fd_fpcc_cp_corr_signn_len 8
+#define fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1 0xA2C1
+#define reg_feq_s1_pos 0
+#define reg_feq_s1_len 5
+#define reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2
+#define fd_fpcc_cp_corr_tone_th_pos 0
+#define fd_fpcc_cp_corr_tone_th_len 6
+#define fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3
+#define fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define fd_fpcc_cp_corr_symbol_log_th_len 4
+#define fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int 0xA2C4
+#define fd_fpcc_cp_corr_int_pos 0
+#define fd_fpcc_cp_corr_int_len 1
+#define fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0 0xA320
+#define reg_sfoe_ns_7_0_pos 0
+#define reg_sfoe_ns_7_0_len 8
+#define reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8 0xA321
+#define reg_sfoe_ns_14_8_pos 0
+#define reg_sfoe_ns_14_8_len 7
+#define reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0 0xA322
+#define reg_sfoe_c1_7_0_pos 0
+#define reg_sfoe_c1_7_0_len 8
+#define reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8 0xA323
+#define reg_sfoe_c1_15_8_pos 0
+#define reg_sfoe_c1_15_8_len 8
+#define reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16 0xA324
+#define reg_sfoe_c1_17_16_pos 0
+#define reg_sfoe_c1_17_16_len 2
+#define reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0 0xA325
+#define reg_sfoe_c2_7_0_pos 0
+#define reg_sfoe_c2_7_0_len 8
+#define reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8 0xA326
+#define reg_sfoe_c2_15_8_pos 0
+#define reg_sfoe_c2_15_8_len 8
+#define reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16 0xA327
+#define reg_sfoe_c2_17_16_pos 0
+#define reg_sfoe_c2_17_16_len 2
+#define reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2 0xA328
+#define reg_sfoe_out_9_2_pos 0
+#define reg_sfoe_out_9_2_len 8
+#define reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0 0xA329
+#define reg_sfoe_out_1_0_pos 0
+#define reg_sfoe_out_1_0_len 2
+#define reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th 0xA32A
+#define reg_sfoe_lm_counter_th_pos 0
+#define reg_sfoe_lm_counter_th_len 4
+#define reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th 0xA32B
+#define reg_sfoe_convg_th_pos 0
+#define reg_sfoe_convg_th_len 8
+#define reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th 0xA32C
+#define reg_sfoe_divg_th_pos 0
+#define reg_sfoe_divg_th_len 8
+#define reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en 0xA330
+#define fd_tpsd_en_pos 0
+#define fd_tpsd_en_len 1
+#define fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis 0xA330
+#define fd_tpsd_dis_pos 1
+#define fd_tpsd_dis_len 1
+#define fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst 0xA330
+#define fd_tpsd_rst_pos 2
+#define fd_tpsd_rst_len 1
+#define fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock 0xA330
+#define fd_tpsd_lock_pos 3
+#define fd_tpsd_lock_len 1
+#define fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19 0xA330
+#define fd_tpsd_s19_pos 4
+#define fd_tpsd_s19_len 1
+#define fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17 0xA330
+#define fd_tpsd_s17_pos 5
+#define fd_tpsd_s17_len 1
+#define fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en 0xA331
+#define fd_sfr_ste_en_pos 0
+#define fd_sfr_ste_en_len 1
+#define fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis 0xA331
+#define fd_sfr_ste_dis_pos 1
+#define fd_sfr_ste_dis_len 1
+#define fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst 0xA331
+#define fd_sfr_ste_rst_pos 2
+#define fd_sfr_ste_rst_len 1
+#define fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode 0xA331
+#define fd_sfr_ste_mode_pos 3
+#define fd_sfr_ste_mode_len 1
+#define fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done 0xA331
+#define fd_sfr_ste_done_pos 4
+#define fd_sfr_ste_done_len 1
+#define fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en 0xA332
+#define reg_cfoe_ffoe_en_pos 0
+#define reg_cfoe_ffoe_en_len 1
+#define reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis 0xA332
+#define reg_cfoe_ffoe_dis_pos 1
+#define reg_cfoe_ffoe_dis_len 1
+#define reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst 0xA332
+#define reg_cfoe_ffoe_rst_pos 2
+#define reg_cfoe_ffoe_rst_len 1
+#define reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en 0xA332
+#define reg_cfoe_ifoe_en_pos 3
+#define reg_cfoe_ifoe_en_len 1
+#define reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis 0xA332
+#define reg_cfoe_ifoe_dis_pos 4
+#define reg_cfoe_ifoe_dis_len 1
+#define reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst 0xA332
+#define reg_cfoe_ifoe_rst_pos 5
+#define reg_cfoe_ifoe_rst_len 1
+#define reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en 0xA332
+#define reg_cfoe_fot_en_pos 6
+#define reg_cfoe_fot_en_len 1
+#define reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en 0xA332
+#define reg_cfoe_fot_lm_en_pos 7
+#define reg_cfoe_fot_lm_en_len 1
+#define reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst 0xA333
+#define reg_cfoe_fot_rst_pos 0
+#define reg_cfoe_fot_rst_len 1
+#define reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done 0xA333
+#define fd_cfoe_ffoe_done_pos 1
+#define fd_cfoe_ffoe_done_len 1
+#define fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld 0xA333
+#define fd_cfoe_metric_vld_pos 2
+#define fd_cfoe_metric_vld_len 1
+#define fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld 0xA333
+#define reg_cfoe_ifod_vld_pos 3
+#define reg_cfoe_ifod_vld_len 1
+#define reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done 0xA333
+#define fd_cfoe_ifoe_done_pos 4
+#define fd_cfoe_ifoe_done_len 1
+#define fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid 0xA333
+#define fd_cfoe_fot_valid_pos 5
+#define fd_cfoe_fot_valid_len 1
+#define fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int 0xA333
+#define reg_cfoe_divg_int_pos 6
+#define reg_cfoe_divg_int_len 1
+#define reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag 0xA333
+#define reg_cfoe_divg_flag_pos 7
+#define reg_cfoe_divg_flag_len 1
+#define reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en 0xA334
+#define reg_sfoe_en_pos 0
+#define reg_sfoe_en_len 1
+#define reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis 0xA334
+#define reg_sfoe_dis_pos 1
+#define reg_sfoe_dis_len 1
+#define reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst 0xA334
+#define reg_sfoe_rst_pos 2
+#define reg_sfoe_rst_len 1
+#define reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int 0xA334
+#define reg_sfoe_vld_int_pos 3
+#define reg_sfoe_vld_int_len 1
+#define reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en 0xA334
+#define reg_sfoe_lm_en_pos 4
+#define reg_sfoe_lm_en_len 1
+#define reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int 0xA334
+#define reg_sfoe_divg_int_pos 5
+#define reg_sfoe_divg_int_len 1
+#define reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag 0xA334
+#define reg_sfoe_divg_flag_pos 6
+#define reg_sfoe_divg_flag_len 1
+#define reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst 0xA335
+#define reg_fft_rst_pos 0
+#define reg_fft_rst_len 1
+#define reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon 0xA335
+#define reg_fft_fast_beacon_pos 1
+#define reg_fft_fast_beacon_len 1
+#define reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid 0xA335
+#define reg_fft_fast_valid_pos 2
+#define reg_fft_fast_valid_len 1
+#define reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en 0xA335
+#define reg_fft_mask_en_pos 3
+#define reg_fft_mask_en_len 1
+#define reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en 0xA335
+#define reg_fft_crc_en_pos 4
+#define reg_fft_crc_en_len 1
+#define reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en 0xA336
+#define reg_finr_en_pos 0
+#define reg_finr_en_len 1
+#define reg_finr_en_lsb 0
+#define xd_p_fd_fste_en 0xA337
+#define fd_fste_en_pos 1
+#define fd_fste_en_len 1
+#define fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift 0xA338
+#define fd_sqi_tps_level_shift_pos 0
+#define fd_sqi_tps_level_shift_len 8
+#define fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len 0xA339
+#define fd_pilot_ma_len_pos 0
+#define fd_pilot_ma_len_len 6
+#define fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len 0xA33A
+#define fd_tps_ma_len_pos 0
+#define fd_tps_ma_len_len 6
+#define fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3 0xA33B
+#define fd_sqi_s3_pos 0
+#define fd_sqi_s3_len 8
+#define fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0 0xA33C
+#define fd_sqi_dummy_reg_0_pos 0
+#define fd_sqi_dummy_reg_0_len 1
+#define fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel 0xA33C
+#define fd_sqi_debug_sel_pos 1
+#define fd_sqi_debug_sel_len 2
+#define fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2 0xA33C
+#define fd_sqi_s2_pos 3
+#define fd_sqi_s2_len 5
+#define fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1 0xA33D
+#define fd_sqi_dummy_reg_1_pos 0
+#define fd_sqi_dummy_reg_1_len 1
+#define fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore 0xA33D
+#define fd_inr_ignore_pos 1
+#define fd_inr_ignore_len 1
+#define fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore 0xA33D
+#define fd_pilot_ignore_pos 2
+#define fd_pilot_ignore_len 1
+#define fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore 0xA33D
+#define fd_etps_ignore_pos 3
+#define fd_etps_ignore_len 1
+#define fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1 0xA33D
+#define fd_sqi_s1_pos 4
+#define fd_sqi_s1_len 4
+#define fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0 0xA33E
+#define reg_fste_ehw_7_0_pos 0
+#define reg_fste_ehw_7_0_len 8
+#define reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8 0xA33F
+#define reg_fste_ehw_9_8_pos 0
+#define reg_fste_ehw_9_8_len 2
+#define reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld 0xA33F
+#define reg_fste_i_adj_vld_pos 2
+#define reg_fste_i_adj_vld_len 1
+#define reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0 0xA340
+#define reg_fste_phase_ini_7_0_pos 0
+#define reg_fste_phase_ini_7_0_len 8
+#define reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8 0xA341
+#define reg_fste_phase_ini_11_8_pos 0
+#define reg_fste_phase_ini_11_8_len 4
+#define reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0 0xA341
+#define reg_fste_phase_inc_3_0_pos 4
+#define reg_fste_phase_inc_3_0_len 4
+#define reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4 0xA342
+#define reg_fste_phase_inc_11_4_pos 0
+#define reg_fste_phase_inc_11_4_len 8
+#define reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max 0xA343
+#define reg_fste_acum_cost_cnt_max_pos 0
+#define reg_fste_acum_cost_cnt_max_len 4
+#define reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std 0xA343
+#define reg_fste_step_size_std_pos 4
+#define reg_fste_step_size_std_len 4
+#define reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max 0xA344
+#define reg_fste_step_size_max_pos 0
+#define reg_fste_step_size_max_len 4
+#define reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min 0xA344
+#define reg_fste_step_size_min_pos 4
+#define reg_fste_step_size_min_len 4
+#define reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0 0xA345
+#define reg_fste_frac_step_size_7_0_pos 0
+#define reg_fste_frac_step_size_7_0_len 8
+#define reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8 0xA346
+#define reg_fste_frac_step_size_15_8_pos 0
+#define reg_fste_frac_step_size_15_8_len 8
+#define reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16 0xA347
+#define reg_fste_frac_step_size_19_16_pos 0
+#define reg_fste_frac_step_size_19_16_len 4
+#define reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347
+#define reg_fste_rpd_dir_cnt_max_pos 4
+#define reg_fste_rpd_dir_cnt_max_len 4
+#define reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs 0xA348
+#define reg_fste_ehs_pos 0
+#define reg_fste_ehs_len 4
+#define reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348
+#define reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define reg_fste_frac_cost_cnt_max_3_0_len 4
+#define reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349
+#define reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define reg_fste_frac_cost_cnt_max_9_4_len 6
+#define reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0 0xA34A
+#define reg_fste_w0_7_0_pos 0
+#define reg_fste_w0_7_0_len 8
+#define reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8 0xA34B
+#define reg_fste_w0_11_8_pos 0
+#define reg_fste_w0_11_8_len 4
+#define reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0 0xA34B
+#define reg_fste_w1_3_0_pos 4
+#define reg_fste_w1_3_0_len 4
+#define reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4 0xA34C
+#define reg_fste_w1_11_4_pos 0
+#define reg_fste_w1_11_4_len 8
+#define reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0 0xA34D
+#define reg_fste_w2_7_0_pos 0
+#define reg_fste_w2_7_0_len 8
+#define reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8 0xA34E
+#define reg_fste_w2_11_8_pos 0
+#define reg_fste_w2_11_8_len 4
+#define reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0 0xA34E
+#define reg_fste_w3_3_0_pos 4
+#define reg_fste_w3_3_0_len 4
+#define reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4 0xA34F
+#define reg_fste_w3_11_4_pos 0
+#define reg_fste_w3_11_4_len 8
+#define reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0 0xA350
+#define reg_fste_w4_7_0_pos 0
+#define reg_fste_w4_7_0_len 8
+#define reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8 0xA351
+#define reg_fste_w4_11_8_pos 0
+#define reg_fste_w4_11_8_len 4
+#define reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0 0xA351
+#define reg_fste_w5_3_0_pos 4
+#define reg_fste_w5_3_0_len 4
+#define reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4 0xA352
+#define reg_fste_w5_11_4_pos 0
+#define reg_fste_w5_11_4_len 8
+#define reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0 0xA353
+#define reg_fste_w6_7_0_pos 0
+#define reg_fste_w6_7_0_len 8
+#define reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8 0xA354
+#define reg_fste_w6_11_8_pos 0
+#define reg_fste_w6_11_8_len 4
+#define reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0 0xA354
+#define reg_fste_w7_3_0_pos 4
+#define reg_fste_w7_3_0_len 4
+#define reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4 0xA355
+#define reg_fste_w7_11_4_pos 0
+#define reg_fste_w7_11_4_len 8
+#define reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0 0xA356
+#define reg_fste_w8_7_0_pos 0
+#define reg_fste_w8_7_0_len 8
+#define reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8 0xA357
+#define reg_fste_w8_11_8_pos 0
+#define reg_fste_w8_11_8_len 4
+#define reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0 0xA357
+#define reg_fste_w9_3_0_pos 4
+#define reg_fste_w9_3_0_len 4
+#define reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4 0xA358
+#define reg_fste_w9_11_4_pos 0
+#define reg_fste_w9_11_4_len 8
+#define reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0 0xA359
+#define reg_fste_wa_7_0_pos 0
+#define reg_fste_wa_7_0_len 8
+#define reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8 0xA35A
+#define reg_fste_wa_11_8_pos 0
+#define reg_fste_wa_11_8_len 4
+#define reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0 0xA35A
+#define reg_fste_wb_3_0_pos 4
+#define reg_fste_wb_3_0_len 4
+#define reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4 0xA35B
+#define reg_fste_wb_11_4_pos 0
+#define reg_fste_wb_11_4_len 8
+#define reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj 0xA35C
+#define fd_fste_i_adj_pos 0
+#define fd_fste_i_adj_len 5
+#define fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0 0xA35D
+#define fd_fste_f_adj_7_0_pos 0
+#define fd_fste_f_adj_7_0_len 8
+#define fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8 0xA35E
+#define fd_fste_f_adj_15_8_pos 0
+#define fd_fste_f_adj_15_8_len 8
+#define fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16 0xA35F
+#define fd_fste_f_adj_19_16_pos 0
+#define fd_fste_f_adj_19_16_len 4
+#define fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass 0xA366
+#define reg_feq_Leak_Bypass_pos 0
+#define reg_feq_Leak_Bypass_len 1
+#define reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1 0xA366
+#define reg_feq_Leak_Mneg1_pos 1
+#define reg_feq_Leak_Mneg1_len 3
+#define reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366
+#define reg_feq_Leak_B_ShiftQ_pos 4
+#define reg_feq_Leak_B_ShiftQ_len 4
+#define reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0 0xA367
+#define reg_feq_Leak_B_Float0_pos 0
+#define reg_feq_Leak_B_Float0_len 8
+#define reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1 0xA368
+#define reg_feq_Leak_B_Float1_pos 0
+#define reg_feq_Leak_B_Float1_len 8
+#define reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2 0xA369
+#define reg_feq_Leak_B_Float2_pos 0
+#define reg_feq_Leak_B_Float2_len 8
+#define reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3 0xA36A
+#define reg_feq_Leak_B_Float3_pos 0
+#define reg_feq_Leak_B_Float3_len 8
+#define reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4 0xA36B
+#define reg_feq_Leak_B_Float4_pos 0
+#define reg_feq_Leak_B_Float4_len 8
+#define reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5 0xA36C
+#define reg_feq_Leak_B_Float5_pos 0
+#define reg_feq_Leak_B_Float5_len 8
+#define reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6 0xA36D
+#define reg_feq_Leak_B_Float6_pos 0
+#define reg_feq_Leak_B_Float6_len 8
+#define reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7 0xA36E
+#define reg_feq_Leak_B_Float7_pos 0
+#define reg_feq_Leak_B_Float7_len 8
+#define reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0 0xA36F
+#define reg_feq_data_h2_7_0_pos 0
+#define reg_feq_data_h2_7_0_len 8
+#define reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8 0xA370
+#define reg_feq_data_h2_9_8_pos 0
+#define reg_feq_data_h2_9_8_len 2
+#define reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps 0xA371
+#define reg_feq_leak_use_slice_tps_pos 0
+#define reg_feq_leak_use_slice_tps_len 1
+#define reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update 0xA371
+#define reg_feq_read_update_pos 1
+#define reg_feq_read_update_len 1
+#define reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld 0xA371
+#define reg_feq_data_vld_pos 2
+#define reg_feq_data_vld_len 1
+#define reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0 0xA371
+#define reg_feq_tone_idx_4_0_pos 3
+#define reg_feq_tone_idx_4_0_len 5
+#define reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5 0xA372
+#define reg_feq_tone_idx_12_5_pos 0
+#define reg_feq_tone_idx_12_5_len 8
+#define reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0 0xA373
+#define reg_feq_data_re_7_0_pos 0
+#define reg_feq_data_re_7_0_len 8
+#define reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8 0xA374
+#define reg_feq_data_re_10_8_pos 0
+#define reg_feq_data_re_10_8_len 3
+#define reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0 0xA375
+#define reg_feq_data_im_7_0_pos 0
+#define reg_feq_data_im_7_0_len 8
+#define reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8 0xA376
+#define reg_feq_data_im_10_8_pos 0
+#define reg_feq_data_im_10_8_len 3
+#define reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re 0xA377
+#define reg_feq_y_re_pos 0
+#define reg_feq_y_re_len 8
+#define reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im 0xA378
+#define reg_feq_y_im_pos 0
+#define reg_feq_y_im_len 8
+#define reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0 0xA379
+#define reg_feq_h_re_7_0_pos 0
+#define reg_feq_h_re_7_0_len 8
+#define reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8 0xA37A
+#define reg_feq_h_re_8_pos 0
+#define reg_feq_h_re_8_len 1
+#define reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0 0xA37B
+#define reg_feq_h_im_7_0_pos 0
+#define reg_feq_h_im_7_0_len 8
+#define reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8 0xA37C
+#define reg_feq_h_im_8_pos 0
+#define reg_feq_h_im_8_len 1
+#define reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0 0xA380
+#define fec_super_frm_unit_7_0_pos 0
+#define fec_super_frm_unit_7_0_len 8
+#define fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8 0xA381
+#define fec_super_frm_unit_15_8_pos 0
+#define fec_super_frm_unit_15_8_len 8
+#define fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382
+#define fec_vtb_err_bit_cnt_7_0_pos 0
+#define fec_vtb_err_bit_cnt_7_0_len 8
+#define fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383
+#define fec_vtb_err_bit_cnt_15_8_pos 0
+#define fec_vtb_err_bit_cnt_15_8_len 8
+#define fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384
+#define fec_vtb_err_bit_cnt_23_16_pos 0
+#define fec_vtb_err_bit_cnt_23_16_len 8
+#define fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0 0xA385
+#define fec_rsd_packet_unit_7_0_pos 0
+#define fec_rsd_packet_unit_7_0_len 8
+#define fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8 0xA386
+#define fec_rsd_packet_unit_15_8_pos 0
+#define fec_rsd_packet_unit_15_8_len 8
+#define fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387
+#define fec_rsd_bit_err_cnt_7_0_pos 0
+#define fec_rsd_bit_err_cnt_7_0_len 8
+#define fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388
+#define fec_rsd_bit_err_cnt_15_8_pos 0
+#define fec_rsd_bit_err_cnt_15_8_len 8
+#define fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389
+#define fec_rsd_bit_err_cnt_23_16_pos 0
+#define fec_rsd_bit_err_cnt_23_16_len 8
+#define fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A
+#define fec_rsd_abort_packet_cnt_7_0_pos 0
+#define fec_rsd_abort_packet_cnt_7_0_len 8
+#define fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B
+#define fec_rsd_abort_packet_cnt_15_8_pos 0
+#define fec_rsd_abort_packet_cnt_15_8_len 8
+#define fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0 0xA38E
+#define fec_RS_TH_1_7_0_pos 0
+#define fec_RS_TH_1_7_0_len 8
+#define fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8 0xA38F
+#define fec_RS_TH_1_15_8_pos 0
+#define fec_RS_TH_1_15_8_len 8
+#define fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2 0xA390
+#define fec_RS_TH_2_pos 0
+#define fec_RS_TH_2_len 8
+#define fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en 0xA391
+#define fec_mon_en_pos 0
+#define fec_mon_en_len 1
+#define fec_mon_en_lsb 0
+#define xd_p_reg_b8to47 0xA391
+#define reg_b8to47_pos 1
+#define reg_b8to47_len 1
+#define reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep 0xA391
+#define reg_rsd_sync_rep_pos 2
+#define reg_rsd_sync_rep_len 1
+#define reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst 0xA391
+#define fec_rsd_retrain_rst_pos 3
+#define fec_rsd_retrain_rst_len 1
+#define fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy 0xA391
+#define fec_rsd_ber_rdy_pos 4
+#define fec_rsd_ber_rdy_len 1
+#define fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst 0xA391
+#define fec_rsd_ber_rst_pos 5
+#define fec_rsd_ber_rst_len 1
+#define fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy 0xA391
+#define fec_vtb_ber_rdy_pos 6
+#define fec_vtb_ber_rdy_len 1
+#define fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst 0xA391
+#define fec_vtb_ber_rst_pos 7
+#define fec_vtb_ber_rst_len 1
+#define fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en 0xA392
+#define reg_vtb_clk40en_pos 0
+#define reg_vtb_clk40en_len 1
+#define reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en 0xA392
+#define fec_vtb_rsd_mon_en_pos 1
+#define fec_vtb_rsd_mon_en_len 1
+#define fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en 0xA392
+#define reg_fec_data_en_pos 2
+#define reg_fec_data_en_len 1
+#define reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2 0xA392
+#define fec_dummy_reg_2_pos 3
+#define fec_dummy_reg_2_len 3
+#define fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk 0xA392
+#define reg_sync_chk_pos 6
+#define reg_sync_chk_len 1
+#define reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass 0xA392
+#define fec_rsd_bypass_pos 7
+#define fec_rsd_bypass_len 1
+#define fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst 0xA393
+#define fec_sw_rst_pos 0
+#define fec_sw_rst_len 1
+#define fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc 0xA394
+#define fec_vtb_pm_crc_pos 0
+#define fec_vtb_pm_crc_len 8
+#define fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc 0xA395
+#define fec_vtb_tb_7_crc_pos 0
+#define fec_vtb_tb_7_crc_len 8
+#define fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc 0xA396
+#define fec_vtb_tb_6_crc_pos 0
+#define fec_vtb_tb_6_crc_len 8
+#define fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc 0xA397
+#define fec_vtb_tb_5_crc_pos 0
+#define fec_vtb_tb_5_crc_len 8
+#define fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc 0xA398
+#define fec_vtb_tb_4_crc_pos 0
+#define fec_vtb_tb_4_crc_len 8
+#define fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc 0xA399
+#define fec_vtb_tb_3_crc_pos 0
+#define fec_vtb_tb_3_crc_len 8
+#define fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc 0xA39A
+#define fec_vtb_tb_2_crc_pos 0
+#define fec_vtb_tb_2_crc_len 8
+#define fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc 0xA39B
+#define fec_vtb_tb_1_crc_pos 0
+#define fec_vtb_tb_1_crc_len 8
+#define fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc 0xA39C
+#define fec_vtb_tb_0_crc_pos 0
+#define fec_vtb_tb_0_crc_len 8
+#define fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc 0xA39D
+#define fec_rsd_bank0_crc_pos 0
+#define fec_rsd_bank0_crc_len 8
+#define fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc 0xA39E
+#define fec_rsd_bank1_crc_pos 0
+#define fec_rsd_bank1_crc_len 8
+#define fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc 0xA39F
+#define fec_idi_vtb_crc_pos 0
+#define fec_idi_vtb_crc_len 8
+#define fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod 0xA3C0
+#define reg_tpsd_txmod_pos 0
+#define reg_tpsd_txmod_len 2
+#define reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi 0xA3C0
+#define reg_tpsd_gi_pos 2
+#define reg_tpsd_gi_len 2
+#define reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier 0xA3C0
+#define reg_tpsd_hier_pos 4
+#define reg_tpsd_hier_len 3
+#define reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw 0xA3C1
+#define reg_bw_pos 2
+#define reg_bw_len 2
+#define reg_bw_lsb 0
+#define xd_g_reg_dec_pri 0xA3C1
+#define reg_dec_pri_pos 4
+#define reg_dec_pri_len 1
+#define reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const 0xA3C1
+#define reg_tpsd_const_pos 6
+#define reg_tpsd_const_len 2
+#define reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr 0xA3C2
+#define reg_tpsd_hpcr_pos 0
+#define reg_tpsd_hpcr_len 3
+#define reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr 0xA3C2
+#define reg_tpsd_lpcr_pos 3
+#define reg_tpsd_lpcr_len 3
+#define reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk 0xA3D0
+#define reg_ofsm_clk_pos 0
+#define reg_ofsm_clk_len 3
+#define reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg 0xA3D1
+#define reg_fclk_cfg_pos 0
+#define reg_fclk_cfg_len 1
+#define reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi 0xA3D1
+#define reg_fclk_idi_pos 1
+#define reg_fclk_idi_len 1
+#define reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi 0xA3D1
+#define reg_fclk_odi_pos 2
+#define reg_fclk_odi_len 1
+#define reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd 0xA3D1
+#define reg_fclk_rsd_pos 3
+#define reg_fclk_rsd_len 1
+#define reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb 0xA3D1
+#define reg_fclk_vtb_pos 4
+#define reg_fclk_vtb_len 1
+#define reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste 0xA3D1
+#define reg_fclk_cste_pos 5
+#define reg_fclk_cste_len 1
+#define reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if 0xA3D1
+#define reg_fclk_mp2if_pos 6
+#define reg_fclk_mp2if_len 1
+#define reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr 0xA400
+#define i2c_m_slave_addr_pos 0
+#define i2c_m_slave_addr_len 8
+#define i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1 0xA401
+#define i2c_m_data1_pos 0
+#define i2c_m_data1_len 8
+#define i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2 0xA402
+#define i2c_m_data2_pos 0
+#define i2c_m_data2_len 8
+#define i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3 0xA403
+#define i2c_m_data3_pos 0
+#define i2c_m_data3_len 8
+#define i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4 0xA404
+#define i2c_m_data4_pos 0
+#define i2c_m_data4_len 8
+#define i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5 0xA405
+#define i2c_m_data5_pos 0
+#define i2c_m_data5_len 8
+#define i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6 0xA406
+#define i2c_m_data6_pos 0
+#define i2c_m_data6_len 8
+#define i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7 0xA407
+#define i2c_m_data7_pos 0
+#define i2c_m_data7_len 8
+#define i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8 0xA408
+#define i2c_m_data8_pos 0
+#define i2c_m_data8_len 8
+#define i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9 0xA409
+#define i2c_m_data9_pos 0
+#define i2c_m_data9_len 8
+#define i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10 0xA40A
+#define i2c_m_data10_pos 0
+#define i2c_m_data10_len 8
+#define i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11 0xA40B
+#define i2c_m_data11_pos 0
+#define i2c_m_data11_len 8
+#define i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw 0xA40C
+#define i2c_m_cmd_rw_pos 0
+#define i2c_m_cmd_rw_len 1
+#define i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen 0xA40C
+#define i2c_m_cmd_rwlen_pos 3
+#define i2c_m_cmd_rwlen_len 4
+#define i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe 0xA40D
+#define i2c_m_status_cmd_exe_pos 0
+#define i2c_m_status_cmd_exe_len 1
+#define i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done 0xA40D
+#define i2c_m_status_wdat_done_pos 1
+#define i2c_m_status_wdat_done_len 1
+#define i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail 0xA40D
+#define i2c_m_status_wdat_fail_pos 2
+#define i2c_m_status_wdat_fail_len 1
+#define i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period 0xA40E
+#define i2c_m_period_pos 0
+#define i2c_m_period_len 8
+#define i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F
+#define i2c_m_reg_msb_lsb_pos 0
+#define i2c_m_reg_msb_lsb_len 1
+#define i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst 0xA40F
+#define reg_ofdm_rst_pos 1
+#define reg_ofdm_rst_len 1
+#define reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner 0xA40F
+#define reg_sample_period_on_tuner_pos 2
+#define reg_sample_period_on_tuner_len 1
+#define reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c 0xA40F
+#define reg_rst_i2c_pos 3
+#define reg_rst_i2c_len 1
+#define reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en 0xA40F
+#define reg_ofdm_rst_en_pos 4
+#define reg_ofdm_rst_en_len 1
+#define reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on 0xA40F
+#define reg_tuner_sda_sync_on_pos 5
+#define reg_tuner_sda_sync_on_len 1
+#define reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm 0xA500
+#define mp2if_data_access_disable_ofsm_pos 0
+#define mp2if_data_access_disable_ofsm_len 1
+#define mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm 0xA500
+#define reg_mp2_sw_rst_ofsm_pos 1
+#define reg_mp2_sw_rst_ofsm_len 1
+#define reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm 0xA500
+#define reg_mp2if_clk_en_ofsm_pos 2
+#define reg_mp2if_clk_en_ofsm_len 1
+#define reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked 0xA500
+#define mp2if_sync_byte_locked_pos 3
+#define mp2if_sync_byte_locked_len 1
+#define mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188 0xA500
+#define mp2if_ts_not_188_pos 4
+#define mp2if_ts_not_188_len 1
+#define mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty 0xA500
+#define mp2if_psb_empty_pos 5
+#define mp2if_psb_empty_len 1
+#define mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow 0xA500
+#define mp2if_psb_overflow_pos 6
+#define mp2if_psb_overflow_len 1
+#define mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500
+#define mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define mp2if_keep_sf_sync_byte_ofsm_len 1
+#define mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501
+#define mp2if_psb_mp2if_num_pkt_pos 0
+#define mp2if_psb_mp2if_num_pkt_len 6
+#define mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm 0xA501
+#define reg_mpeg_full_speed_ofsm_pos 6
+#define reg_mpeg_full_speed_ofsm_len 1
+#define reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501
+#define mp2if_mpeg_ser_mode_ofsm_pos 7
+#define mp2if_mpeg_ser_mode_ofsm_len 1
+#define mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51 0xA600
+#define reg_sw_mon51_pos 0
+#define reg_sw_mon51_len 8
+#define reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel 0xA601
+#define reg_top_pcsel_pos 0
+#define reg_top_pcsel_len 1
+#define reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232 0xA601
+#define reg_top_rs232_pos 1
+#define reg_top_rs232_len 1
+#define reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout 0xA601
+#define reg_top_pcout_pos 2
+#define reg_top_pcout_len 1
+#define reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug 0xA601
+#define reg_top_debug_pos 3
+#define reg_top_debug_len 1
+#define reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly 0xA601
+#define reg_top_adcdly_pos 4
+#define reg_top_adcdly_len 2
+#define reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw 0xA601
+#define reg_top_pwrdw_pos 6
+#define reg_top_pwrdw_len 1
+#define reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv 0xA601
+#define reg_top_pwrdw_inv_pos 7
+#define reg_top_pwrdw_inv_len 1
+#define reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv 0xA602
+#define reg_top_int_inv_pos 0
+#define reg_top_int_inv_len 1
+#define reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel 0xA602
+#define reg_top_dio_sel_pos 1
+#define reg_top_dio_sel_len 1
+#define reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0 0xA603
+#define reg_top_gpioon0_pos 0
+#define reg_top_gpioon0_len 1
+#define reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1 0xA603
+#define reg_top_gpioon1_pos 1
+#define reg_top_gpioon1_len 1
+#define reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2 0xA603
+#define reg_top_gpioon2_pos 2
+#define reg_top_gpioon2_len 1
+#define reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3 0xA603
+#define reg_top_gpioon3_pos 3
+#define reg_top_gpioon3_len 1
+#define reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1 0xA603
+#define reg_top_lockon1_pos 4
+#define reg_top_lockon1_len 1
+#define reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2 0xA603
+#define reg_top_lockon2_pos 5
+#define reg_top_lockon2_len 1
+#define reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0 0xA604
+#define reg_top_gpioo0_pos 0
+#define reg_top_gpioo0_len 1
+#define reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1 0xA604
+#define reg_top_gpioo1_pos 1
+#define reg_top_gpioo1_len 1
+#define reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2 0xA604
+#define reg_top_gpioo2_pos 2
+#define reg_top_gpioo2_len 1
+#define reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3 0xA604
+#define reg_top_gpioo3_pos 3
+#define reg_top_gpioo3_len 1
+#define reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1 0xA604
+#define reg_top_lock1_pos 4
+#define reg_top_lock1_len 1
+#define reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2 0xA604
+#define reg_top_lock2_pos 5
+#define reg_top_lock2_len 1
+#define reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0 0xA605
+#define reg_top_gpioen0_pos 0
+#define reg_top_gpioen0_len 1
+#define reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1 0xA605
+#define reg_top_gpioen1_pos 1
+#define reg_top_gpioen1_len 1
+#define reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2 0xA605
+#define reg_top_gpioen2_pos 2
+#define reg_top_gpioen2_len 1
+#define reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3 0xA605
+#define reg_top_gpioen3_pos 3
+#define reg_top_gpioen3_len 1
+#define reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1 0xA605
+#define reg_top_locken1_pos 4
+#define reg_top_locken1_len 1
+#define reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2 0xA605
+#define reg_top_locken2_pos 5
+#define reg_top_locken2_len 1
+#define reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0 0xA606
+#define reg_top_gpioi0_pos 0
+#define reg_top_gpioi0_len 1
+#define reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1 0xA606
+#define reg_top_gpioi1_pos 1
+#define reg_top_gpioi1_len 1
+#define reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2 0xA606
+#define reg_top_gpioi2_pos 2
+#define reg_top_gpioi2_len 1
+#define reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3 0xA606
+#define reg_top_gpioi3_pos 3
+#define reg_top_gpioi3_len 1
+#define reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1 0xA606
+#define reg_top_locki1_pos 4
+#define reg_top_locki1_len 1
+#define reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2 0xA606
+#define reg_top_locki2_pos 5
+#define reg_top_locki2_len 1
+#define reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0 0xA608
+#define reg_dummy_7_0_pos 0
+#define reg_dummy_7_0_len 8
+#define reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8 0xA609
+#define reg_dummy_15_8_pos 0
+#define reg_dummy_15_8_len 8
+#define reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16 0xA60A
+#define reg_dummy_23_16_pos 0
+#define reg_dummy_23_16_len 8
+#define reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24 0xA60B
+#define reg_dummy_31_24_pos 0
+#define reg_dummy_31_24_len 8
+#define reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32 0xA60C
+#define reg_dummy_39_32_pos 0
+#define reg_dummy_39_32_len 8
+#define reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40 0xA60D
+#define reg_dummy_47_40_pos 0
+#define reg_dummy_47_40_len 8
+#define reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48 0xA60E
+#define reg_dummy_55_48_pos 0
+#define reg_dummy_55_48_len 8
+#define reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56 0xA60F
+#define reg_dummy_63_56_pos 0
+#define reg_dummy_63_56_len 8
+#define reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64 0xA610
+#define reg_dummy_71_64_pos 0
+#define reg_dummy_71_64_len 8
+#define reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72 0xA611
+#define reg_dummy_79_72_pos 0
+#define reg_dummy_79_72_len 8
+#define reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80 0xA612
+#define reg_dummy_87_80_pos 0
+#define reg_dummy_87_80_len 8
+#define reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88 0xA613
+#define reg_dummy_95_88_pos 0
+#define reg_dummy_95_88_len 8
+#define reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96 0xA614
+#define reg_dummy_103_96_pos 0
+#define reg_dummy_103_96_len 8
+#define reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag 0xA615
+#define reg_unplug_flag_pos 0
+#define reg_unplug_flag_len 1
+#define reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request 0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag 0xA615
+#define reg_back_to_dca_flag_pos 2
+#define reg_back_to_dca_flag_len 1
+#define reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request 0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag 0xA615
+#define reg_Dyn_Top_Try_flag_pos 3
+#define reg_Dyn_Top_Try_flag_len 1
+#define reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag 0xA615
+#define reg_API_retrain_freeze_flag_pos 4
+#define reg_API_retrain_freeze_flag_len 1
+#define reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104 0xA615
+#define reg_dummy_111_104_pos 0
+#define reg_dummy_111_104_len 8
+#define reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112 0xA616
+#define reg_dummy_119_112_pos 0
+#define reg_dummy_119_112_len 8
+#define reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120 0xA617
+#define reg_dummy_127_120_pos 0
+#define reg_dummy_127_120_len 8
+#define reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128 0xA618
+#define reg_dummy_135_128_pos 0
+#define reg_dummy_135_128_len 8
+#define reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136 0xA619
+#define reg_dummy_143_136_pos 0
+#define reg_dummy_143_136_len 8
+#define reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis 0xA619
+#define reg_CCIR_dis_pos 0
+#define reg_CCIR_dis_len 1
+#define reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144 0xA61A
+#define reg_dummy_151_144_pos 0
+#define reg_dummy_151_144_len 8
+#define reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152 0xA61B
+#define reg_dummy_159_152_pos 0
+#define reg_dummy_159_152_len 8
+#define reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160 0xA61C
+#define reg_dummy_167_160_pos 0
+#define reg_dummy_167_160_len 8
+#define reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168 0xA61D
+#define reg_dummy_175_168_pos 0
+#define reg_dummy_175_168_len 8
+#define reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176 0xA61E
+#define reg_dummy_183_176_pos 0
+#define reg_dummy_183_176_len 8
+#define reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en 0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis 0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0 0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8 0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16 0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184 0xA61F
+#define reg_dummy_191_184_pos 0
+#define reg_dummy_191_184_len 8
+#define reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192 0xA620
+#define reg_dummy_199_192_pos 0
+#define reg_dummy_199_192_len 8
+#define reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en 0xABC0
+#define reg_ce_en_pos 0
+#define reg_ce_en_len 1
+#define reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en 0xABC0
+#define reg_ce_fctrl_en_pos 1
+#define reg_ce_fctrl_en_len 1
+#define reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi 0xABC0
+#define reg_ce_fste_tdi_pos 2
+#define reg_ce_fste_tdi_len 1
+#define reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic 0xABC0
+#define reg_ce_dynamic_pos 3
+#define reg_ce_dynamic_len 1
+#define reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf 0xABC0
+#define reg_ce_conf_pos 4
+#define reg_ce_conf_len 2
+#define reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12 0xABC0
+#define reg_ce_dyn12_pos 6
+#define reg_ce_dyn12_len 1
+#define reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en 0xABC0
+#define reg_ce_derot_en_pos 7
+#define reg_ce_derot_en_len 1
+#define reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0 0xABC1
+#define reg_ce_dynamic_th_7_0_pos 0
+#define reg_ce_dynamic_th_7_0_len 8
+#define reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8 0xABC2
+#define reg_ce_dynamic_th_15_8_pos 0
+#define reg_ce_dynamic_th_15_8_len 8
+#define reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1 0xABC3
+#define reg_ce_s1_pos 0
+#define reg_ce_s1_len 5
+#define reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value 0xABC3
+#define reg_ce_var_forced_value_pos 5
+#define reg_ce_var_forced_value_len 3
+#define reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0 0xABC4
+#define reg_ce_data_im_7_0_pos 0
+#define reg_ce_data_im_7_0_len 8
+#define reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8 0xABC5
+#define reg_ce_data_im_8_pos 0
+#define reg_ce_data_im_8_len 1
+#define reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0 0xABC5
+#define reg_ce_data_re_6_0_pos 1
+#define reg_ce_data_re_6_0_len 7
+#define reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7 0xABC6
+#define reg_ce_data_re_8_7_pos 0
+#define reg_ce_data_re_8_7_len 2
+#define reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0 0xABC6
+#define reg_ce_tone_5_0_pos 2
+#define reg_ce_tone_5_0_len 6
+#define reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6 0xABC7
+#define reg_ce_tone_12_6_pos 0
+#define reg_ce_tone_12_6_len 7
+#define reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th 0xABC8
+#define reg_ce_centroid_drift_th_pos 0
+#define reg_ce_centroid_drift_th_len 8
+#define reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max 0xABC9
+#define reg_ce_centroid_count_max_pos 0
+#define reg_ce_centroid_count_max_len 4
+#define reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA
+#define reg_ce_centroid_bias_inc_7_0_pos 0
+#define reg_ce_centroid_bias_inc_7_0_len 8
+#define reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB
+#define reg_ce_centroid_bias_inc_8_pos 0
+#define reg_ce_centroid_bias_inc_8_len 1
+#define reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0 0xABCC
+#define reg_ce_var_th0_7_0_pos 0
+#define reg_ce_var_th0_7_0_len 8
+#define reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8 0xABCD
+#define reg_ce_var_th0_15_8_pos 0
+#define reg_ce_var_th0_15_8_len 8
+#define reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0 0xABCE
+#define reg_ce_var_th1_7_0_pos 0
+#define reg_ce_var_th1_7_0_len 8
+#define reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8 0xABCF
+#define reg_ce_var_th1_15_8_pos 0
+#define reg_ce_var_th1_15_8_len 8
+#define reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0 0xABD0
+#define reg_ce_var_th2_7_0_pos 0
+#define reg_ce_var_th2_7_0_len 8
+#define reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8 0xABD1
+#define reg_ce_var_th2_15_8_pos 0
+#define reg_ce_var_th2_15_8_len 8
+#define reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0 0xABD2
+#define reg_ce_var_th3_7_0_pos 0
+#define reg_ce_var_th3_7_0_len 8
+#define reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8 0xABD3
+#define reg_ce_var_th3_15_8_pos 0
+#define reg_ce_var_th3_15_8_len 8
+#define reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0 0xABD4
+#define reg_ce_var_th4_7_0_pos 0
+#define reg_ce_var_th4_7_0_len 8
+#define reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8 0xABD5
+#define reg_ce_var_th4_15_8_pos 0
+#define reg_ce_var_th4_15_8_len 8
+#define reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0 0xABD6
+#define reg_ce_var_th5_7_0_pos 0
+#define reg_ce_var_th5_7_0_len 8
+#define reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8 0xABD7
+#define reg_ce_var_th5_15_8_pos 0
+#define reg_ce_var_th5_15_8_len 8
+#define reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0 0xABD8
+#define reg_ce_var_th6_7_0_pos 0
+#define reg_ce_var_th6_7_0_len 8
+#define reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8 0xABD9
+#define reg_ce_var_th6_15_8_pos 0
+#define reg_ce_var_th6_15_8_len 8
+#define reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset 0xABDA
+#define reg_ce_fctrl_reset_pos 0
+#define reg_ce_fctrl_reset_len 1
+#define reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en 0xABDA
+#define reg_ce_cent_auto_clr_en_pos 1
+#define reg_ce_cent_auto_clr_en_len 1
+#define reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA
+#define reg_ce_fctrl_auto_reset_en_pos 2
+#define reg_ce_fctrl_auto_reset_en_len 1
+#define reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en 0xABDA
+#define reg_ce_var_forced_en_pos 3
+#define reg_ce_var_forced_en_len 1
+#define reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en 0xABDA
+#define reg_ce_cent_forced_en_pos 4
+#define reg_ce_cent_forced_en_len 1
+#define reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max 0xABDA
+#define reg_ce_var_max_pos 5
+#define reg_ce_var_max_len 3
+#define reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB
+#define reg_ce_cent_forced_value_7_0_pos 0
+#define reg_ce_cent_forced_value_7_0_len 8
+#define reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC
+#define reg_ce_cent_forced_value_11_8_pos 0
+#define reg_ce_cent_forced_value_11_8_len 4
+#define reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd 0xABDD
+#define reg_ce_fctrl_rd_pos 0
+#define reg_ce_fctrl_rd_len 1
+#define reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0 0xABDD
+#define reg_ce_centroid_max_6_0_pos 1
+#define reg_ce_centroid_max_6_0_len 7
+#define reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7 0xABDE
+#define reg_ce_centroid_max_11_7_pos 0
+#define reg_ce_centroid_max_11_7_len 5
+#define reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var 0xABDF
+#define reg_ce_var_pos 0
+#define reg_ce_var_len 3
+#define reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy 0xABDF
+#define reg_ce_fctrl_rdy_pos 3
+#define reg_ce_fctrl_rdy_len 1
+#define reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0 0xABDF
+#define reg_ce_centroid_out_3_0_pos 4
+#define reg_ce_centroid_out_3_0_len 4
+#define reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4 0xABE0
+#define reg_ce_centroid_out_11_4_pos 0
+#define reg_ce_centroid_out_11_4_len 8
+#define reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0 0xABE1
+#define reg_ce_bias_7_0_pos 0
+#define reg_ce_bias_7_0_len 8
+#define reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8 0xABE2
+#define reg_ce_bias_11_8_pos 0
+#define reg_ce_bias_11_8_len 4
+#define reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0 0xABE2
+#define reg_ce_m1_3_0_pos 4
+#define reg_ce_m1_3_0_len 4
+#define reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4 0xABE3
+#define reg_ce_m1_11_4_pos 0
+#define reg_ce_m1_11_4_len 8
+#define reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0 0xABE4
+#define reg_ce_rh0_7_0_pos 0
+#define reg_ce_rh0_7_0_len 8
+#define reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8 0xABE5
+#define reg_ce_rh0_15_8_pos 0
+#define reg_ce_rh0_15_8_len 8
+#define reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16 0xABE6
+#define reg_ce_rh0_23_16_pos 0
+#define reg_ce_rh0_23_16_len 8
+#define reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24 0xABE7
+#define reg_ce_rh0_31_24_pos 0
+#define reg_ce_rh0_31_24_len 8
+#define reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0 0xABE8
+#define reg_ce_rh3_real_7_0_pos 0
+#define reg_ce_rh3_real_7_0_len 8
+#define reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8 0xABE9
+#define reg_ce_rh3_real_15_8_pos 0
+#define reg_ce_rh3_real_15_8_len 8
+#define reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16 0xABEA
+#define reg_ce_rh3_real_23_16_pos 0
+#define reg_ce_rh3_real_23_16_len 8
+#define reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24 0xABEB
+#define reg_ce_rh3_real_31_24_pos 0
+#define reg_ce_rh3_real_31_24_len 8
+#define reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0 0xABEC
+#define reg_ce_rh3_imag_7_0_pos 0
+#define reg_ce_rh3_imag_7_0_len 8
+#define reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8 0xABED
+#define reg_ce_rh3_imag_15_8_pos 0
+#define reg_ce_rh3_imag_15_8_len 8
+#define reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16 0xABEE
+#define reg_ce_rh3_imag_23_16_pos 0
+#define reg_ce_rh3_imag_23_16_len 8
+#define reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24 0xABEF
+#define reg_ce_rh3_imag_31_24_pos 0
+#define reg_ce_rh3_imag_31_24_len 8
+#define reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0 0xABF0
+#define reg_feq_fix_eh2_7_0_pos 0
+#define reg_feq_fix_eh2_7_0_len 8
+#define reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8 0xABF1
+#define reg_feq_fix_eh2_15_8_pos 0
+#define reg_feq_fix_eh2_15_8_len 8
+#define reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16 0xABF2
+#define reg_feq_fix_eh2_23_16_pos 0
+#define reg_feq_fix_eh2_23_16_len 8
+#define reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24 0xABF3
+#define reg_feq_fix_eh2_31_24_pos 0
+#define reg_feq_fix_eh2_31_24_len 8
+#define reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0 0xABF4
+#define reg_ce_m2_central_7_0_pos 0
+#define reg_ce_m2_central_7_0_len 8
+#define reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8 0xABF5
+#define reg_ce_m2_central_15_8_pos 0
+#define reg_ce_m2_central_15_8_len 8
+#define reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift 0xABF6
+#define reg_ce_fftshift_pos 0
+#define reg_ce_fftshift_len 4
+#define reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1 0xABF6
+#define reg_ce_fftshift1_pos 4
+#define reg_ce_fftshift1_len 4
+#define reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2 0xABF7
+#define reg_ce_fftshift2_pos 0
+#define reg_ce_fftshift2_len 4
+#define reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile 0xABF7
+#define reg_ce_top_mobile_pos 4
+#define reg_ce_top_mobile_len 1
+#define reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE 0xB000
+#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+ u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+ u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+ u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+ u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+ u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+ u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+ u32 * event, int *state);
+extern struct dvb_usb_rc_key af9005_rc_keys[];
+extern int af9005_rc_keys_size;
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index bac2ae3b4a1f..04e31cf7d530 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -354,41 +354,35 @@ static struct mt352_config cxusb_mt352_config = {
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
- u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- adap->pll_addr = 0x61;
- memcpy(adap->pll_init, bpll, 4);
- adap->pll_desc = &dvb_pll_fmd1216me;
-
- adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+ DVB_PLL_FMD1216ME);
return 0;
}
static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
- dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
return 0;
}
static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index cda3adea24fb..4a903ea95896 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -30,17 +30,19 @@ extern int dvb_usb_dib0700_debug;
// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
+#define REQUEST_SET_RC 0x11
#define REQUEST_GET_VERSION 0x15
struct dib0700_state {
u8 channel_state;
u16 mt2060_if1[2];
-
+ u8 rc_toggle;
u8 is_dib7000pc;
};
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
+extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
@@ -50,5 +52,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device
extern int dib0700_device_count;
extern struct dvb_usb_device_properties dib0700_devices[];
extern struct usb_device_id dib0700_usb_id_table[];
-
#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index dddf164f269a..3ea294eb96bd 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug;
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
+static int dvb_usb_dib0700_ir_proto = 1;
+module_param(dvb_usb_dib0700_ir_proto, int, 0644);
+MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
+
/* expecting rx buffer: request data[0] data[1] ... data[2] */
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
{
@@ -32,7 +36,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
}
/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
-static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
{
u16 index, value;
int status;
@@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return dib0700_ctrl_wr(adap->dev, b, 4);
}
+static int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+ u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
+ int i = dib0700_ctrl_wr(d, rc_setup, 3);
+ if (i<0) {
+ err("ir protocol setup failed");
+ return -1;
+ }
+ return 0;
+}
+
static int dib0700_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int i;
+ struct dvb_usb_device *dev;
for (i = 0; i < dib0700_device_count; i++)
- if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
+ if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0)
+ {
+ dib0700_rc_setup(dev);
return 0;
+ }
return -ENODEV;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 2208757d9017..e8c4a8694532 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -4,7 +4,7 @@
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
- * Copyright (C) 2005-6 DiBcom, SA
+ * Copyright (C) 2005-7 DiBcom, SA
*/
#include "dib0700.h"
@@ -12,13 +12,19 @@
#include "dib7000m.h"
#include "dib7000p.h"
#include "mt2060.h"
+#include "mt2266.h"
+#include "dib0070.h"
static int force_lna_activation;
module_param(force_lna_activation, int, 0644);
MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
"if applicable for the device (default: 0=automatic/off).");
-/* Hauppauge Nova-T 500
+struct dib0700_adapter_state {
+ int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+};
+
+/* Hauppauge Nova-T 500 (aka Bristol)
* has a LNA on GPIO0 which is enabled by setting 1 */
static struct mt2060_config bristol_mt2060_config[2] = {
{
@@ -96,6 +102,321 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
}
+/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
+
+/* MT226x */
+static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
+ {
+ BAND_UHF, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+ 1130, // inv_gain
+ 21, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 0, // wbd_alpha
+
+ 65535, // agc1_max
+ 33770, // agc1_min
+ 65535, // agc2_max
+ 23592, // agc2_min
+
+ 0, // agc1_pt1
+ 62, // agc1_pt2
+ 255, // agc1_pt3
+ 64, // agc1_slope1
+ 64, // agc1_slope2
+ 132, // agc2_pt1
+ 192, // agc2_pt2
+ 80, // agc2_slope1
+ 80, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 1, // perform_agc_softsplit
+ }, {
+ BAND_VHF | BAND_LBAND, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+ 2372, // inv_gain
+ 21, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 0, // wbd_alpha
+
+ 65535, // agc1_max
+ 0, // agc1_min
+ 65535, // agc2_max
+ 23592, // agc2_min
+
+ 0, // agc1_pt1
+ 128, // agc1_pt2
+ 128, // agc1_pt3
+ 128, // agc1_slope1
+ 0, // agc1_slope2
+ 128, // agc2_pt1
+ 253, // agc2_pt2
+ 81, // agc2_slope1
+ 0, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 1, // perform_agc_softsplit
+ }
+};
+
+static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
+ 60000, 30000, // internal, sampling
+ 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+ 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+ (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+ 0, // ifreq
+ 20452225, // timf
+};
+
+static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
+ { .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 1,
+
+ .agc_config_count = 2,
+ .agc = stk7700d_7000p_mt2266_agc_config,
+ .bw = &stk7700d_mt2266_pll_config,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+ },
+ { .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 1,
+
+ .agc_config_count = 2,
+ .agc = stk7700d_7000p_mt2266_agc_config,
+ .bw = &stk7700d_mt2266_pll_config,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+ }
+};
+
+static struct mt2266_config stk7700d_mt2266_config[2] = {
+ { .i2c_address = 0x60
+ },
+ { .i2c_address = 0x60
+ }
+};
+
+static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if (adap->id == 0) {
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config);
+ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+ &stk7700d_dib7000p_mt2266_config[adap->id]);
+
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct i2c_adapter *tun_i2c;
+ tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
+ &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
+}
+
+#define DEFAULT_RC_INTERVAL 150
+
+static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
+
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[4];
+ int i;
+ struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct dib0700_state *st = d->priv;
+ *event = 0;
+ *state = REMOTE_NO_KEY_PRESSED;
+ i=dib0700_ctrl_rd(d,rc_request,2,key,4);
+ if (i<=0) {
+ err("RC Query Failed");
+ return -1;
+ }
+ if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+ if (key[3-1]!=st->rc_toggle) {
+ for (i=0;i<d->props.rc_key_map_size; i++) {
+ if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+ *event = keymap[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ st->rc_toggle=key[3-1];
+ return 0;
+ }
+ }
+ err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+ }
+ return 0;
+}
+
+static struct dvb_usb_rc_key dib0700_rc_keys[] = {
+ /* Key codes for the tiny Pinnacle remote*/
+ { 0x07, 0x00, KEY_MUTE },
+ { 0x07, 0x01, KEY_MENU }, // Pinnacle logo
+ { 0x07, 0x39, KEY_POWER },
+ { 0x07, 0x03, KEY_VOLUMEUP },
+ { 0x07, 0x09, KEY_VOLUMEDOWN },
+ { 0x07, 0x06, KEY_CHANNELUP },
+ { 0x07, 0x0c, KEY_CHANNELDOWN },
+ { 0x07, 0x0f, KEY_1 },
+ { 0x07, 0x15, KEY_2 },
+ { 0x07, 0x10, KEY_3 },
+ { 0x07, 0x18, KEY_4 },
+ { 0x07, 0x1b, KEY_5 },
+ { 0x07, 0x1e, KEY_6 },
+ { 0x07, 0x11, KEY_7 },
+ { 0x07, 0x21, KEY_8 },
+ { 0x07, 0x12, KEY_9 },
+ { 0x07, 0x27, KEY_0 },
+ { 0x07, 0x24, KEY_SCREEN }, // 'Square' key
+ { 0x07, 0x2a, KEY_TEXT }, // 'T' key
+ { 0x07, 0x2d, KEY_REWIND },
+ { 0x07, 0x30, KEY_PLAY },
+ { 0x07, 0x33, KEY_FASTFORWARD },
+ { 0x07, 0x36, KEY_RECORD },
+ { 0x07, 0x3c, KEY_STOP },
+ { 0x07, 0x3f, KEY_CANCEL }, // '?' key
+ /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+ { 0xeb, 0x01, KEY_POWER },
+ { 0xeb, 0x02, KEY_1 },
+ { 0xeb, 0x03, KEY_2 },
+ { 0xeb, 0x04, KEY_3 },
+ { 0xeb, 0x05, KEY_4 },
+ { 0xeb, 0x06, KEY_5 },
+ { 0xeb, 0x07, KEY_6 },
+ { 0xeb, 0x08, KEY_7 },
+ { 0xeb, 0x09, KEY_8 },
+ { 0xeb, 0x0a, KEY_9 },
+ { 0xeb, 0x0b, KEY_VIDEO },
+ { 0xeb, 0x0c, KEY_0 },
+ { 0xeb, 0x0d, KEY_REFRESH },
+ { 0xeb, 0x0f, KEY_EPG },
+ { 0xeb, 0x10, KEY_UP },
+ { 0xeb, 0x11, KEY_LEFT },
+ { 0xeb, 0x12, KEY_OK },
+ { 0xeb, 0x13, KEY_RIGHT },
+ { 0xeb, 0x14, KEY_DOWN },
+ { 0xeb, 0x16, KEY_INFO },
+ { 0xeb, 0x17, KEY_RED },
+ { 0xeb, 0x18, KEY_GREEN },
+ { 0xeb, 0x19, KEY_YELLOW },
+ { 0xeb, 0x1a, KEY_BLUE },
+ { 0xeb, 0x1b, KEY_CHANNELUP },
+ { 0xeb, 0x1c, KEY_VOLUMEUP },
+ { 0xeb, 0x1d, KEY_MUTE },
+ { 0xeb, 0x1e, KEY_VOLUMEDOWN },
+ { 0xeb, 0x1f, KEY_CHANNELDOWN },
+ { 0xeb, 0x40, KEY_PAUSE },
+ { 0xeb, 0x41, KEY_HOME },
+ { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */
+ { 0xeb, 0x43, KEY_SUBTITLE },
+ { 0xeb, 0x44, KEY_TEXT }, /* Teletext */
+ { 0xeb, 0x45, KEY_DELETE },
+ { 0xeb, 0x46, KEY_TV },
+ { 0xeb, 0x47, KEY_DVD },
+ { 0xeb, 0x48, KEY_STOP },
+ { 0xeb, 0x49, KEY_VIDEO },
+ { 0xeb, 0x4a, KEY_AUDIO }, /* Music */
+ { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */
+ { 0xeb, 0x4c, KEY_PLAY },
+ { 0xeb, 0x4d, KEY_BACK },
+ { 0xeb, 0x4e, KEY_REWIND },
+ { 0xeb, 0x4f, KEY_FASTFORWARD },
+ { 0xeb, 0x54, KEY_PREVIOUS },
+ { 0xeb, 0x58, KEY_RECORD },
+ { 0xeb, 0x5c, KEY_NEXT },
+
+ /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+ { 0x1e, 0x00, KEY_0 },
+ { 0x1e, 0x01, KEY_1 },
+ { 0x1e, 0x02, KEY_2 },
+ { 0x1e, 0x03, KEY_3 },
+ { 0x1e, 0x04, KEY_4 },
+ { 0x1e, 0x05, KEY_5 },
+ { 0x1e, 0x06, KEY_6 },
+ { 0x1e, 0x07, KEY_7 },
+ { 0x1e, 0x08, KEY_8 },
+ { 0x1e, 0x09, KEY_9 },
+ { 0x1e, 0x0a, KEY_KPASTERISK },
+ { 0x1e, 0x0b, KEY_RED },
+ { 0x1e, 0x0c, KEY_RADIO },
+ { 0x1e, 0x0d, KEY_MENU },
+ { 0x1e, 0x0e, KEY_GRAVE }, /* # */
+ { 0x1e, 0x0f, KEY_MUTE },
+ { 0x1e, 0x10, KEY_VOLUMEUP },
+ { 0x1e, 0x11, KEY_VOLUMEDOWN },
+ { 0x1e, 0x12, KEY_CHANNEL },
+ { 0x1e, 0x14, KEY_UP },
+ { 0x1e, 0x15, KEY_DOWN },
+ { 0x1e, 0x16, KEY_LEFT },
+ { 0x1e, 0x17, KEY_RIGHT },
+ { 0x1e, 0x18, KEY_VIDEO },
+ { 0x1e, 0x19, KEY_AUDIO },
+ { 0x1e, 0x1a, KEY_MEDIA },
+ { 0x1e, 0x1b, KEY_EPG },
+ { 0x1e, 0x1c, KEY_TV },
+ { 0x1e, 0x1e, KEY_NEXT },
+ { 0x1e, 0x1f, KEY_BACK },
+ { 0x1e, 0x20, KEY_CHANNELUP },
+ { 0x1e, 0x21, KEY_CHANNELDOWN },
+ { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+ { 0x1e, 0x25, KEY_OK },
+ { 0x1e, 0x29, KEY_BLUE},
+ { 0x1e, 0x2e, KEY_GREEN },
+ { 0x1e, 0x30, KEY_PAUSE },
+ { 0x1e, 0x32, KEY_REWIND },
+ { 0x1e, 0x34, KEY_FASTFORWARD },
+ { 0x1e, 0x35, KEY_PLAY },
+ { 0x1e, 0x36, KEY_STOP },
+ { 0x1e, 0x37, KEY_RECORD },
+ { 0x1e, 0x38, KEY_YELLOW },
+ { 0x1e, 0x3b, KEY_GOTO },
+ { 0x1e, 0x3d, KEY_POWER },
+};
+
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
BAND_UHF | BAND_VHF, // band_caps
@@ -194,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = {
(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
60258167, // ifreq
20452225, // timf
+ 30000000, // xtal
};
static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -213,6 +535,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = {
static struct dib7000p_config stk7700p_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
+ .agc_config_count = 1,
.agc = &stk7700p_7000p_mt2060_agc_config,
.bw = &stk7700p_pll_config,
@@ -267,27 +590,245 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
}
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+ BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+ 600, // inv_gain
+ 10, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 5, // wbd_alpha
+
+ 65535, // agc1_max
+ 0, // agc1_min
+
+ 65535, // agc2_max
+ 0, // agc2_min
+
+ 0, // agc1_pt1
+ 40, // agc1_pt2
+ 183, // agc1_pt3
+ 206, // agc1_slope1
+ 255, // agc1_slope2
+ 72, // agc2_pt1
+ 152, // agc2_pt2
+ 88, // agc2_slope1
+ 90, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 0, // perform_agc_softsplit
+};
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+ return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+ return dib7000p_set_gpio(fe, 9, 0, onoff);
+}
+
+static struct dib0070_config dib7070p_dib0070_config[2] = {
+ {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+ .clock_pad_drive = 4
+ }, {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+
+ }
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ u16 offset;
+ u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ switch (band) {
+ case BAND_VHF: offset = 950; break;
+ case BAND_UHF:
+ default: offset = 550; break;
+ }
+ deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+ dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+ return state->set_param_save(fe, fep);
+}
+
+static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+ if (adap->id == 0) {
+ if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+ return -ENODEV;
+ } else {
+ if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+ return -ENODEV;
+ }
+
+ st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+ adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+ return 0;
+}
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+ 60000, 15000, // internal, sampling
+ 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+ 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+ (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+ (0 << 25) | 0, // ifreq = 0.000000 MHz
+ 20452225, // timf
+ 12000000, // xtal_hz
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+};
+
+/* STK7070P */
+static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* STK7070PD */
+static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+ {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ }, {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ }
+};
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* DVB-USB and USB stuff follows */
struct usb_device_id dib0700_usb_id_table[] = {
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
+/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
{ USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
{ USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
- { } /* Terminating entry */
+/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) },
+/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+ { 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
.caps = DVB_USB_IS_AN_I2C_ADAPTER, \
.usb_ctrl = DEVICE_SPECIFIC, \
- .firmware = "dvb-usb-dib0700-01.fw", \
+ .firmware = "dvb-usb-dib0700-03-pre1.fw", \
.download_firmware = dib0700_download_firmware, \
.no_reconnect = 1, \
.size_of_priv = sizeof(struct dib0700_state), \
@@ -321,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 6,
+ .num_device_descs = 7,
.devices = {
{ "DiBcom STK7700P reference design",
{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -336,7 +877,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Compro Videomate U500",
- { &dib0700_usb_id_table[6], NULL },
+ { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
{ NULL },
},
{ "Uniwill STK7700P based (Hama and others)",
@@ -346,8 +887,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ "Leadtek Winfast DTV Dongle (STK7700P based)",
{ &dib0700_usb_id_table[8], NULL },
{ NULL },
+ },
+ { "AVerMedia AVerTV DVB-T Express",
+ { &dib0700_usb_id_table[20] },
+ { NULL },
}
- }
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -371,8 +921,112 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
{ NULL },
},
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .frontend_attach = stk7700d_frontend_attach,
+ .tuner_attach = stk7700d_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ }, {
+ .frontend_attach = stk7700d_frontend_attach,
+ .tuner_attach = stk7700d_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+ }
+ },
+
+ .num_device_descs = 4,
+ .devices = {
+ { "Pinnacle PCTV 2000e",
+ { &dib0700_usb_id_table[11], NULL },
+ { NULL },
+ },
+ { "Terratec Cinergy DT XS Diversity",
+ { &dib0700_usb_id_table[12], NULL },
+ { NULL },
+ },
+ { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity",
+ { &dib0700_usb_id_table[13], NULL },
+ { NULL },
+ },
+ { "DiBcom STK7700D reference design",
+ { &dib0700_usb_id_table[14], NULL },
+ { NULL },
+ },
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
+
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = stk7070p_frontend_attach,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom STK7070P reference design",
+ { &dib0700_usb_id_table[15], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV DVB-T Flash Stick",
+ { &dib0700_usb_id_table[16], NULL },
+ { NULL },
+ },
}
- }
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .frontend_attach = stk7070pd_frontend_attach0,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }, {
+ .frontend_attach = stk7070pd_frontend_attach1,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom STK7070PD reference design",
+ { &dib0700_usb_id_table[17], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV Dual DVB-T Diversity Stick",
+ { &dib0700_usb_id_table[18], NULL },
+ { NULL },
+ },
+ }
+ },
};
int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 5143e426d283..9a184da01c47 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -295,7 +295,7 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
/* not found - use panasonic pll parameters */
- if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+ if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
return -ENOMEM;
} else {
st->mt2060_present = 1;
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 7a6ae8f482e0..043cadae0859 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -14,6 +14,14 @@
*/
#include "dibusb.h"
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dibusb_state *st = adap->priv;
+
+ return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib3000_config demod_cfg;
@@ -21,21 +29,34 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
demod_cfg.demod_address = 0x8;
- if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+ if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+ &adap->dev->i2c_adap, &st->ops)) == NULL)
return -ENODEV;
- adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
- adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+ adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
return 0;
}
static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_tua6010xs;
+ struct dibusb_state *st = adap->priv;
+
+ st->tuner_addr = 0x61;
+
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+ DVB_PLL_TUA6010XS);
+ return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dibusb_state *st = adap->priv;
+
+ st->tuner_addr = 0x60;
+
+ dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+ DVB_PLL_TDA665X);
return 0;
}
@@ -50,30 +71,28 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
{ .flags = 0, .buf = b, .len = 2 },
{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
};
+ struct dibusb_state *st = adap->priv;
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
- msg[0].addr = msg[1].addr = 0x60;
+ msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+ if (adap->fe->ops.i2c_gate_ctrl)
+ adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
err("tuner i2c write failed.");
ret = -EREMOTEIO;
}
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
+ if (adap->fe->ops.i2c_gate_ctrl)
+ adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
if (b2[0] == 0xfe) {
info("This device has the Thomson Cable onboard. Which is default.");
- dibusb_thomson_tuner_attach(adap);
+ ret = dibusb_thomson_tuner_attach(adap);
} else {
- u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("This device has the Panasonic ENV77H11D5 onboard.");
- adap->pll_addr = 0x60;
- memcpy(adap->pll_init,bpll,4);
- adap->pll_desc = &dvb_pll_tda665x;
+ ret = dibusb_panasonic_tuner_attach(adap);
}
return ret;
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index b60781032742..8e847aa73ba1 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -99,6 +99,7 @@
struct dibusb_state {
struct dib_fe_xfer_ops ops;
int mt2060_present;
+ u8 tuner_addr;
};
struct dibusb_device_state {
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index b5acb11c0bc9..bca1e0905739 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -118,7 +118,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
u8 b[5];
- dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+
+ fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
@@ -130,12 +131,14 @@ static struct nxt6000_config digitv_nxt6000_config = {
static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct digitv_state *st = adap->dev->priv;
+
if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ st->is_nxt6000 = 0;
return 0;
}
if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
- adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ st->is_nxt6000 = 1;
return 0;
}
return -EIO;
@@ -143,8 +146,14 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x60;
- adap->pll_desc = &dvb_pll_tded4;
+ struct digitv_state *st = adap->dev->priv;
+
+ if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+ return -ENODEV;
+
+ if (st->is_nxt6000)
+ adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
return 0;
}
@@ -273,6 +282,8 @@ static struct dvb_usb_device_properties digitv_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-digitv-02.fw",
+ .size_of_priv = sizeof(struct digitv_state),
+
.num_adapters = 1,
.adapter = {
{
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
index 477ee428a70e..8b43e3db8691 100644
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ b/drivers/media/dvb/dvb-usb/digitv.h
@@ -4,6 +4,10 @@
#define DVB_USB_LOG_PREFIX "digitv"
#include "dvb-usb.h"
+struct digitv_state {
+ int is_nxt6000;
+};
+
extern int dvb_usb_digitv_debug;
#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 7dbe14321019..d86cf9bee91c 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -1,5 +1,5 @@
/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
@@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties;
static struct dvb_usb_device_properties wt220u_fc_properties;
static struct dvb_usb_device_properties wt220u_properties;
static struct dvb_usb_device_properties wt220u_zl0353_properties;
+static struct dvb_usb_device_properties wt220u_miglia_properties;
static int dtt200u_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf,
if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
- dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
+ dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0)
return 0;
return -ENODEV;
@@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = {
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) },
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) },
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) },
+ { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
@@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
}
};
+static struct dvb_usb_device_properties wt220u_miglia_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-wt220u-miglia-01.fw",
+
+ .num_adapters = 1,
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView WT-220U PenType Receiver (Miglia)",
+ .cold_ids = { &dtt200u_usb_table[9], NULL },
+ /* This device turns into WT220U_ZL0353_WARM when fw
+ has been uploaded */
+ .warm_ids = { NULL },
+ },
+ { NULL },
+ }
+};
+
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver dtt200u_usb_driver = {
.name = "dvb_usb_dtt200u",
@@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init);
module_exit(dtt200u_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 088b6dee3a7f..23428cd30756 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,82 +46,3 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
d->state &= ~DVB_USB_STATE_I2C;
return 0;
}
-
-int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
- int ret = 0;
-
- /* if pll_desc is not used */
- if (adap->pll_desc == NULL)
- return 0;
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
- deb_pll("pll init: %x\n",adap->pll_addr);
- deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
- adap->pll_init[2], adap->pll_init[3]);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
- err("tuner i2c write failed for pll_init.");
- ret = -EREMOTEIO;
- }
- msleep(1);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
- return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-
-int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
-
- if (buf_len != 5)
- return -EINVAL;
- if (adap->pll_desc == NULL)
- return 0;
-
- deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
-
- b[0] = adap->pll_addr;
- dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
-
- deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
-
- return 5;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-
-int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- int ret = 0;
- u8 b[5];
- struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
-
- dvb_usb_tuner_calc_regs(fe,fep,b,5);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
- err("tuner i2c write failed for pll_set.");
- ret = -EREMOTEIO;
- }
- msleep(1);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
-
- return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 403081689de1..4fa3e895028a 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -11,7 +11,9 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
-#define USB_VID_ALCOR_MICRO 0x058f
+#define USB_VID_AFATECH 0x15a4
+#define USB_VID_ALCOR_MICRO 0x058f
+#define USB_VID_ALINK 0x05e3
#define USB_VID_ANCHOR 0x0547
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
#define USB_VID_AVERMEDIA 0x07ca
@@ -32,9 +34,11 @@
#define USB_VID_LEADTEK 0x0413
#define USB_VID_LITEON 0x04ca
#define USB_VID_MEDION 0x1660
+#define USB_VID_MIGLIA 0x18f3
#define USB_VID_MSI 0x0db0
#define USB_VID_OPERA1 0x695c
#define USB_VID_PINNACLE 0x2304
+#define USB_VID_TERRATEC 0x0ccd
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
@@ -44,6 +48,8 @@
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
#define USB_PID_ADSTECH_USB2_WARM 0xa334
+#define USB_PID_AFATECH_AF9005 0x9020
+#define USB_VID_ALINK_DTU 0xf170
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
@@ -53,6 +59,7 @@
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
@@ -61,6 +68,9 @@
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_DIBCOM_STK7700P 0x1e14
#define USB_PID_DIBCOM_STK7700P_PC 0x1e78
+#define USB_PID_DIBCOM_STK7700D 0x1ef0
+#define USB_PID_DIBCOM_STK7070P 0x1ebc
+#define USB_PID_DIBCOM_STK7070PD 0x1ebe
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_DPOSH_M9206_COLD 0x9206
#define USB_PID_DPOSH_M9206_WARM 0xa090
@@ -69,6 +79,7 @@
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
@@ -109,8 +120,17 @@
#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580
+#define USB_PID_AVERMEDIA_EXPRESS 0xb568
#define USB_PID_AVERMEDIA_VOLAR 0xa807
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
+#define USB_PID_PINNACLE_PCTV2000E 0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229
+#define USB_PID_PCTV_200E 0x020e
+#define USB_PID_PCTV_400E 0x020f
+#define USB_PID_PCTV_450E 0x0222
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
@@ -130,9 +150,6 @@
#define USB_PID_MSI_MEGASKY580_55801 0x5581
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
-#define USB_PID_PCTV_200E 0x020e
-#define USB_PID_PCTV_400E 0x020f
-#define USB_PID_PCTV_450E 0x0222
#define USB_PID_LITEON_DVB_T_COLD 0xf000
#define USB_PID_LITEON_DVB_T_WARM 0xf001
#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
@@ -142,8 +159,11 @@
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
-#define USB_PID_GENPIX_8PSK_COLD 0x0200
-#define USB_PID_GENPIX_8PSK_WARM 0x0201
+#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
+#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201
+#define USB_PID_GENPIX_8PSK_REV_2 0x0202
+#define USB_PID_GENPIX_SKYWALKER_1 0x0203
+#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
#define USB_PID_SIGMATEK_DVB_110 0x6610
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
#define USB_PID_OPERA1_COLD 0x2830
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index ffdde83d1e77..cdd717c3fe45 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0
static int dvb_usb_force_pid_filter_usage;
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
-MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
static int dvb_usb_adapter_init(struct dvb_usb_device *d)
{
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 9200a30dd1b9..7b9f35bfb4f0 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -110,7 +110,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
input_dev->name = "IR-receiver inside an USB DVB receiver";
input_dev->phys = d->rc_phys;
usb_to_input_id(d->udev, &input_dev->id);
- input_dev->cdev.dev = &d->udev->dev;
+ input_dev->dev.parent = &d->udev->dev;
/* set the bits for the keys */
deb_rc("key map size: %d\n", d->props.rc_key_map_size);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 6f824a569e14..d1b3c7b81fff 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -297,12 +297,6 @@ struct dvb_usb_adapter {
int feedcount;
int pid_filtering;
- /* tuner programming information */
- u8 pll_addr;
- u8 pll_init[4];
- struct dvb_pll_desc *pll_desc;
- int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
-
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
@@ -388,11 +382,6 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
/* commonly used remote control parsing */
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
-/* commonly used pll init and set functions */
-extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
-extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
-
/* commonly used firmware download types and function */
struct hexline {
u8 len;
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index e0587e663591..f01d99c1c43c 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -157,6 +157,7 @@ static int gl861_probe(struct usb_interface *intf,
static struct usb_device_id gl861_table [] = {
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+ { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, gl861_table);
@@ -187,12 +188,16 @@ static struct dvb_usb_device_properties gl861_properties = {
}},
.i2c_algo = &gl861_i2c_algo,
- .num_device_descs = 1,
+ .num_device_descs = 2,
.devices = {
{ "MSI Mega Sky 55801 DVB-T USB2.0",
{ &gl861_table[0], NULL },
{ NULL },
},
+ { "A-LINK DTU DVB-T USB2.0",
+ { &gl861_table[1], NULL },
+ { NULL },
+ },
}
};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 6ccbdc9cd772..e37142d9271a 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -1,7 +1,8 @@
/* DVB USB compliant Linux driver for the
- * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
*
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
*
* Thanks to GENPIX for the sample code used to implement this module.
*
@@ -17,27 +18,39 @@
struct gp8psk_fe_state {
struct dvb_frontend fe;
-
struct dvb_usb_device *d;
-
+ u8 lock;
u16 snr;
-
- unsigned long next_snr_check;
+ unsigned long next_status_check;
+ unsigned long status_check_interval;
};
+static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
+{
+ u8 buf[6];
+ if (time_after(jiffies,st->next_status_check)) {
+ gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
+ gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
+ st->snr = (buf[1]) << 8 | buf[0];
+ st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+ }
+ return 0;
+}
+
static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
{
struct gp8psk_fe_state *st = fe->demodulator_priv;
- u8 lock;
+ gp8psk_fe_update_status(st);
- if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
- return -EINVAL;
-
- if (lock)
+ if (st->lock)
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
else
*status = 0;
+ if (*status & FE_HAS_LOCK)
+ st->status_check_interval = 1000;
+ else
+ st->status_check_interval = 100;
return 0;
}
@@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct gp8psk_fe_state *st = fe->demodulator_priv;
- u8 buf[2];
-
- if (time_after(jiffies,st->next_snr_check)) {
- gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
- *snr = (int)(buf[1]) << 8 | buf[0];
- /* snr is reported in dBu*256 */
- /* snr / 38.4 ~= 100% strength */
- /* snr * 17 returns 100% strength as 65535 */
- if (*snr <= 3855)
- *snr = (*snr<<4) + *snr; // snr * 17
- else
- *snr = 65535;
- st->next_snr_check = jiffies + (10*HZ)/1000;
- } else {
- *snr = st->snr;
- }
+ gp8psk_fe_update_status(st);
+ /* snr is reported in dBu*256 */
+ *snr = st->snr;
return 0;
}
static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
- return gp8psk_fe_read_snr(fe, strength);
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ gp8psk_fe_update_status(st);
+ /* snr is reported in dBu*256 */
+ /* snr / 38.4 ~= 100% strength */
+ /* snr * 17 returns 100% strength as 65535 */
+ if (st->snr > 0xf00)
+ *strength = 0xffff;
+ else
+ *strength = (st->snr << 4) + st->snr; /* snr*17 */
+ return 0;
}
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
- tune->min_delay_ms = 800;
+ tune->min_delay_ms = 200;
return 0;
}
@@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
- state->next_snr_check = jiffies;
+ state->lock = 0;
+ state->next_status_check = jiffies;
+ state->status_check_interval = 200;
return 0;
}
@@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt
return 0;
}
+static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+ return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
+}
+
static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
{
struct gp8psk_fe_state* state = fe->demodulator_priv;
@@ -235,10 +252,10 @@ success:
static struct dvb_frontend_ops gp8psk_fe_ops = {
.info = {
- .name = "Genpix 8psk-USB DVB-S",
+ .name = "Genpix 8psk-to-USB2 DVB-S",
.type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
+ .frequency_min = 800000,
+ .frequency_max = 2250000,
.frequency_stepsize = 100,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
@@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.set_tone = gp8psk_fe_set_tone,
.set_voltage = gp8psk_fe_set_voltage,
.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+ .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 518d67fca5e8..92147ee3e14f 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -1,7 +1,8 @@
/* DVB USB compliant Linux driver for the
- * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
*
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
*
* Thanks to GENPIX for the sample code used to implement this module.
*
@@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
}
if (ret < 0 || ret != blen) {
- warn("usb in operation failed.");
+ warn("usb in %d operation failed.", req);
ret = -EIO;
} else
ret = 0;
@@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
goto out_rel_fw;
- info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+ info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
ptr = fw->data;
- buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+ buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
while (ptr[0] != 0xff) {
u16 buflen = ptr[0] + 4;
@@ -129,25 +130,34 @@ out_rel_fw:
static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 status, buf;
+ int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+
if (onoff) {
gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
- if (! (status & 0x01)) /* started */
+ if (! (status & bm8pskStarted)) { /* started */
+ if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+ gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
return -EINVAL;
+ }
- if (! (status & 0x02)) /* BCM4500 firmware loaded */
- if(gp8psk_load_bcm4500fw(d))
- return EINVAL;
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
+ if(gp8psk_load_bcm4500fw(d))
+ return EINVAL;
- if (! (status & 0x04)) /* LNB Power */
+ if (! (status & bmIntersilOn)) /* LNB Power */
if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
&buf, 1))
return EINVAL;
- /* Set DVB mode */
- if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
- return -EINVAL;
- gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ /* Set DVB mode to 1 */
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+ return EINVAL;
+ /* Abort possible TS (if previous tune crashed) */
+ if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
+ return EINVAL;
} else {
/* Turn off LNB power */
if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
@@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
/* Turn off 8psk power */
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
return -EINVAL;
-
+ if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+ gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
}
return 0;
}
+int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+{
+ u8 buf;
+ int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+ /* Turn off 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+ return -EINVAL;
+ /* Turn On 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+ return -EINVAL;
+ /* load BCM4500 firmware */
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (gp8psk_load_bcm4500fw(d))
+ return EINVAL;
+ return 0;
+}
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
@@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties;
static int gp8psk_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+ int ret;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ ret = dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+ if (ret == 0) {
+ info("found Genpix USB device pID = %x (hex)",
+ le16_to_cpu(udev->descriptor.idProduct));
+ }
+ return ret;
}
static struct usb_device_id gp8psk_usb_table [] = {
- { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
- { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .num_device_descs = 1,
+ .num_device_descs = 4,
.devices = {
- { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+ { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
.warm_ids = { &gp8psk_usb_table[1], NULL },
},
+ { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[2], NULL },
+ },
+ { .name = "Genpix SkyWalker-1 DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[3], NULL },
+ },
+ { .name = "Genpix SkyWalker-CW3K DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[4], NULL },
+ },
{ NULL },
}
};
@@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init);
module_exit(gp8psk_usb_module_exit);
MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
-MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_VERSION("1.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
index 3eba7061011c..e83a57506cfa 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -1,7 +1,8 @@
/* DVB USB compliant Linux driver for the
- * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
*
* Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
*
* Thanks to GENPIX for the sample code used to implement this module.
*
@@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug;
#define TH_COMMAND_IN 0xC0
#define TH_COMMAND_OUT 0xC1
-/* command bytes */
-#define GET_8PSK_CONFIG 0x80
+/* gp8psk commands */
+
+#define GET_8PSK_CONFIG 0x80 /* in */
#define SET_8PSK_CONFIG 0x81
+#define I2C_WRITE 0x83
+#define I2C_READ 0x84
#define ARM_TRANSFER 0x85
#define TUNE_8PSK 0x86
-#define GET_SIGNAL_STRENGTH 0x87
+#define GET_SIGNAL_STRENGTH 0x87 /* in */
#define LOAD_BCM4500 0x88
-#define BOOT_8PSK 0x89
-#define START_INTERSIL 0x8A
+#define BOOT_8PSK 0x89 /* in */
+#define START_INTERSIL 0x8A /* in */
#define SET_LNB_VOLTAGE 0x8B
#define SET_22KHZ_TONE 0x8C
#define SEND_DISEQC_COMMAND 0x8D
#define SET_DVB_MODE 0x8E
#define SET_DN_SWITCH 0x8F
-#define GET_SIGNAL_LOCK 0x90
+#define GET_SIGNAL_LOCK 0x90 /* in */
+#define GET_SERIAL_NUMBER 0x93 /* in */
+#define USE_EXTRA_VOLT 0x94
+#define CW3K_INIT 0x9d
+
+/* PSK_configuration bits */
+#define bm8pskStarted 0x01
+#define bm8pskFW_Loaded 0x02
+#define bmIntersilOn 0x04
+#define bmDVBmode 0x08
+#define bm22kHz 0x10
+#define bmSEL18V 0x20
+#define bmDCtuned 0x40
+#define bmArmed 0x80
/* Satellite modulation modes */
#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
@@ -75,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
#endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c546ddeda5d4..a956bc503a4c 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -22,6 +22,8 @@ static int dvb_usb_m920x_debug;
module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
u16 index, void *data, int size)
{
@@ -57,7 +59,8 @@ static inline int m920x_write(struct usb_device *udev, u8 request,
static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
{
- int ret = 0;
+ int ret = 0, i, epi, flags = 0;
+ int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
if (d->props.rc_query) {
@@ -76,9 +79,51 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
deb("Initialising remote control success\n");
}
+ for (i = 0; i < d->props.num_adapters; i++)
+ flags |= d->adapter[i].props.caps;
+
+ /* Some devices(Dposh) might crash if we attempt touch at all. */
+ if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+ for (i = 0; i < d->props.num_adapters; i++) {
+ epi = d->adapter[i].props.stream.endpoint - 0x81;
+
+ if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+ printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+ return -EINVAL;
+ }
+
+ adap_enabled[epi] = 1;
+ }
+
+ for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+ if (adap_enabled[i])
+ continue;
+
+ if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+ return ret;
+
+ if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+ return ret;
+ }
+ }
+
return ret;
}
+static int m920x_init_ep(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt;
+
+ if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+ deb("No alt found!\n");
+ return -ENODEV;
+ }
+
+ return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+}
+
static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct m920x_state *m = d->priv;
@@ -211,8 +256,7 @@ static struct i2c_algorithm m920x_i2c_algo = {
};
/* pid filter */
-static int m920x_set_filter(struct dvb_usb_adapter *adap,
- int type, int idx, int pid)
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
{
int ret = 0;
@@ -221,10 +265,10 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
pid |= 0x8000;
- if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+ if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
return ret;
- if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+ if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
return ret;
return ret;
@@ -233,40 +277,35 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
static int m920x_update_filters(struct dvb_usb_adapter *adap)
{
struct m920x_state *m = adap->dev->priv;
- int enabled = m->filtering_enabled;
+ int enabled = m->filtering_enabled[adap->id];
int i, ret = 0, filter = 0;
+ int ep = adap->props.stream.endpoint;
for (i = 0; i < M9206_MAX_FILTERS; i++)
- if (m->filters[i] == 8192)
+ if (m->filters[adap->id][i] == 8192)
enabled = 0;
/* Disable all filters */
- if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
return ret;
for (i = 0; i < M9206_MAX_FILTERS; i++)
- if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
return ret;
- if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0)
- return ret;
-
/* Set */
if (enabled) {
for (i = 0; i < M9206_MAX_FILTERS; i++) {
- if (m->filters[i] == 0)
+ if (m->filters[adap->id][i] == 0)
continue;
- if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
return ret;
filter++;
}
}
- if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
- return ret;
-
return ret;
}
@@ -274,7 +313,7 @@ static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct m920x_state *m = adap->dev->priv;
- m->filtering_enabled = onoff ? 1 : 0;
+ m->filtering_enabled[adap->id] = onoff ? 1 : 0;
return m920x_update_filters(adap);
}
@@ -283,7 +322,7 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
{
struct m920x_state *m = adap->dev->priv;
- m->filters[index] = onoff ? pid : 0;
+ m->filters[adap->id][index] = onoff ? pid : 0;
return m920x_update_filters(adap);
}
@@ -368,6 +407,7 @@ static int m920x_identify_state(struct usb_device *udev,
/* demod configurations */
static int m920x_mt352_demod_init(struct dvb_frontend *fe)
{
+ int ret;
u8 config[] = { CONFIG, 0x3d };
u8 clock[] = { CLOCK_CTL, 0x30 };
u8 reset[] = { RESET, 0x80 };
@@ -377,17 +417,25 @@ static int m920x_mt352_demod_init(struct dvb_frontend *fe)
u8 unk1[] = { 0x93, 0x1a };
u8 unk2[] = { 0xb5, 0x7a };
- mt352_write(fe, config, ARRAY_SIZE(config));
- mt352_write(fe, clock, ARRAY_SIZE(clock));
- mt352_write(fe, reset, ARRAY_SIZE(reset));
- mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
- mt352_write(fe, agc, ARRAY_SIZE(agc));
- mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
- mt352_write(fe, unk1, ARRAY_SIZE(unk1));
- mt352_write(fe, unk2, ARRAY_SIZE(unk2));
-
deb("Demod init!\n");
+ if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+ return ret;
+
return 0;
}
@@ -558,8 +606,7 @@ static struct dvb_usb_device_properties dposh_properties;
static int m920x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
- struct usb_host_interface *alt;
+ struct dvb_usb_device *d = NULL;
int ret;
struct m920x_inits *rc_init_seq = NULL;
int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -604,23 +651,13 @@ static int m920x_probe(struct usb_interface *intf,
* tvwalkertwin_properties already configured both
* tuners, so there is nothing for us to do here
*/
-
- return -ENODEV;
}
found:
- alt = usb_altnum_to_altsetting(intf, 1);
- if (alt == NULL) {
- deb("No alt found!\n");
- return -ENODEV;
- }
-
- ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- if (ret < 0)
+ if ((ret = m920x_init_ep(intf)) < 0)
return ret;
- if ((ret = m920x_init(d, rc_init_seq)) != 0)
+ if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
return ret;
return ret;
@@ -737,9 +774,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
*
* LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
* TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working)
+ * TDA10046 #1 is located at i2c address 0x0b
* TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working)
+ * TDA8275A #1 is located at i2c address 0x61
*/
static struct dvb_usb_device_properties tvwalkertwin_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -756,7 +793,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.size_of_priv = sizeof(struct m920x_state),
.identify_state = m920x_identify_state,
- .num_adapters = 1,
+ .num_adapters = 2,
.adapter = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index 2c8942d04222..37532890accd 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -18,6 +18,7 @@
#define M9206_FW 0x30
#define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 2
/*
sequences found in logs:
@@ -60,8 +61,8 @@ response to a write, is unknown.
*/
struct m920x_state {
- u16 filters[M9206_MAX_FILTERS];
- int filtering_enabled;
+ u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+ int filtering_enabled[M9206_MAX_ADAPTERS];
int rep_count;
};
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 518d7ad217df..d7c04951ceab 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -263,7 +263,7 @@ static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(
dvb_pll_attach, adap->fe, 0xc0>>1,
- &adap->dev->i2c_adap, &dvb_pll_opera1
+ &adap->dev->i2c_adap, DVB_PLL_OPERA1
);
return 0;
}
@@ -435,9 +435,9 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
{
const struct firmware *fw = NULL;
u8 *b, *p;
- int ret = 0, i;
+ int ret = 0, i,fpgasize=40;
u8 testval;
- info("start downloading fpga firmware");
+ info("start downloading fpga firmware %s",filename);
if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
err("did not find the firmware file. (%s) "
@@ -454,17 +454,20 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
/* clear fpga ? */
opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
OPERA_WRITE_MSG);
- for (i = 0; p[i] != 0 && i < fw->size;) {
+ for (i = 0; i < fw->size;) {
+ if ( (fw->size - i) <fpgasize){
+ fpgasize=fw->size-i;
+ }
b = (u8 *) p + i;
if (opera1_xilinx_rw
- (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
- OPERA_WRITE_MSG) != b[0]
+ (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+ OPERA_WRITE_MSG) != fpgasize
) {
err("error while transferring firmware");
ret = -EINVAL;
break;
}
- i = i + 1 + b[0];
+ i = i + fpgasize;
}
/* restart the CPU */
if (ret || opera1_xilinx_rw
@@ -534,18 +537,16 @@ static struct dvb_usb_device_properties opera1_properties = {
static int opera1_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
struct usb_device *udev = interface_to_usbdev(intf);
if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
udev->descriptor.idVendor == USB_VID_OPERA1 &&
- (d == NULL
- || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
- ) {
+ opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+ ) {
return -EINVAL;
}
- if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+ if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
return -EINVAL;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index f77b48f76582..0dcab3d4e236 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -65,9 +65,7 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
static int umt_tuner_attach (struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_tua6034;
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
return 0;
}
@@ -84,8 +82,8 @@ static int umt_probe(struct usb_interface *intf,
/* do not change the order of the ID table */
static struct usb_device_id umt_table [] = {
-/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, umt_table);
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 69a46b3607a2..5bbd2d5192f0 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
+ for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
if (vp7045_rc_keys[i].data == key) {
*state = REMOTE_KEY_PRESSED;
*event = vp7045_rc_keys[i].event;
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ff448761dcef..59b9ed1f1aec 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -283,6 +283,14 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_S5H1409
+ tristate "Samsung S5H1409 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
comment "Tuners/PLL support"
depends on DVB_CORE
@@ -291,7 +299,7 @@ config DVB_PLL
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
- This module driver a number of tuners based on PLL chips with a
+ 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
@@ -322,6 +330,29 @@ config DVB_TUNER_MT2060
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
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner DiB0070 from DiBcom.
+ This device is only used inside a SiP called togther with a
+ demodulator for now.
+
comment "Miscellaneous devices"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 27f386585d43..4b8ad1f132aa 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel DVB frontend device drivers.
#
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -40,5 +40,9 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TDA827X) += tda827x.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
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index baeb311de893..a913f49c062b 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -33,7 +33,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 13ad1bfae663..11a4968f18cb 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 335219ebce2d..1dc164d5488c 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "cx22702.h"
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 10fc0c8316dd..b03d8283c37d 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 732e94aaa364..d74fdbd63361 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include "dvb_frontend.h"
@@ -917,7 +916,7 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
static int cx24123_tune(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status)
{
int retval = 0;
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
new file mode 100644
index 000000000000..481eaa684157
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -0,0 +1,580 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0070.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
+
+#define DIB0070_P1D 0x00
+#define DIB0070_P1F 0x01
+#define DIB0070_P1G 0x03
+#define DIB0070S_P1A 0x02
+
+struct dib0070_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend *fe;
+ const struct dib0070_config *cfg;
+ u16 wbd_ff_offset;
+ u8 revision;
+};
+
+static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+{
+ u8 b[2];
+ struct i2c_msg msg[2] = {
+ { .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 },
+ };
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "DiB0070 I2C read failed\n");
+ return 0;
+ }
+ return (b[0] << 8) | b[1];
+}
+
+static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+{
+ u8 b[3] = { reg, val >> 8, val & 0xff };
+ struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0070 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
+
+static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ u16 tmp = 0;
+ tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
+
+ switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) {
+ case 8000:
+ tmp |= (0 << 14);
+ break;
+ case 7000:
+ tmp |= (1 << 14);
+ break;
+ case 6000:
+ tmp |= (2 << 14);
+ break;
+ case 5000:
+ default:
+ tmp |= (3 << 14);
+ break;
+ }
+ dib0070_write_reg(st, 0x02, tmp);
+ return 0;
+}
+
+static void dib0070_captrim(struct dib0070_state *st, u16 LO4)
+{
+ int8_t captrim, fcaptrim, step_sign, step;
+ u16 adc, adc_diff = 3000;
+
+
+
+ dib0070_write_reg(st, 0x0f, 0xed10);
+ dib0070_write_reg(st, 0x17, 0x0034);
+
+ dib0070_write_reg(st, 0x18, 0x0032);
+ msleep(2);
+
+ step = captrim = fcaptrim = 64;
+
+ do {
+ step /= 2;
+ dib0070_write_reg(st, 0x14, LO4 | captrim);
+ msleep(1);
+ adc = dib0070_read_reg(st, 0x19);
+
+ dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024);
+
+ if (adc >= 400) {
+ adc -= 400;
+ step_sign = -1;
+ } else {
+ adc = 400 - adc;
+ step_sign = 1;
+ }
+
+ if (adc < adc_diff) {
+ dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff);
+ adc_diff = adc;
+ fcaptrim = captrim;
+
+
+
+ }
+ captrim += (step_sign * step);
+ } while (step >= 1);
+
+ dib0070_write_reg(st, 0x14, LO4 | fcaptrim);
+ dib0070_write_reg(st, 0x18, 0x07ff);
+}
+
+#define LPF 100 // define for the loop filter 100kHz by default 16-07-06
+#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7)
+#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12)
+#define LO4_SET_CTRIM(l, c) l |= (c) << 10
+static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
+
+ u8 band = BAND_OF_FREQUENCY(freq), c;
+
+ /*******************VCO***********************************/
+ u16 lo4 = 0;
+
+ u8 REFDIV, PRESC = 2;
+ u32 FBDiv, Rest, FREF, VCOF_kHz;
+ u16 Num, Den;
+ /*******************FrontEnd******************************/
+ u16 value = 0;
+
+ dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
+
+
+ dib0070_write_reg(st, 0x17, 0x30);
+
+ dib0070_set_bandwidth(fe, ch); /* c is used as HF */
+ switch (st->revision) {
+ case DIB0070S_P1A:
+ switch (band) {
+ case BAND_LBAND:
+ LO4_SET_VCO_HFDIV(lo4, 1, 1);
+ c = 2;
+ break;
+ case BAND_SBAND:
+ LO4_SET_VCO_HFDIV(lo4, 0, 0);
+ LO4_SET_CTRIM(lo4, 1);;
+ c = 1;
+ break;
+ case BAND_UHF:
+ default:
+ if (freq < 570000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 3);
+ PRESC = 6; c = 6;
+ } else if (freq < 680000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 2);
+ c = 4;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 1, 2);
+ c = 4;
+ }
+ break;
+ } break;
+
+ case DIB0070_P1G:
+ case DIB0070_P1F:
+ default:
+ switch (band) {
+ case BAND_FM:
+ LO4_SET_VCO_HFDIV(lo4, 0, 7);
+ c = 24;
+ break;
+ case BAND_LBAND:
+ LO4_SET_VCO_HFDIV(lo4, 1, 0);
+ c = 2;
+ break;
+ case BAND_VHF:
+ if (freq < 180000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 3);
+ c = 16;
+ } else if (freq < 190000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 3);
+ c = 16;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 0, 6);
+ c = 12;
+ }
+ break;
+
+ case BAND_UHF:
+ default:
+ if (freq < 570000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 5);
+ c = 6;
+ } else if (freq < 700000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 1);
+ c = 4;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 1, 1);
+ c = 4;
+ }
+ break;
+ }
+ break;
+ }
+
+ dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf);
+ dprintk( "VCO = %hd", (lo4 >> 11) & 0x3);
+
+
+ VCOF_kHz = (c * freq) * 2;
+ dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq);
+
+ switch (band) {
+ case BAND_VHF:
+ REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
+ break;
+ case BAND_FM:
+ REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
+ break;
+ default:
+ REFDIV = (u8) ( st->cfg->clock_khz / 10000);
+ break;
+ }
+ FREF = st->cfg->clock_khz / REFDIV;
+
+ dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
+
+
+
+ switch (st->revision) {
+ case DIB0070S_P1A:
+ FBDiv = (VCOF_kHz / PRESC / FREF);
+ Rest = (VCOF_kHz / PRESC) - FBDiv * FREF;
+ break;
+
+ case DIB0070_P1G:
+ case DIB0070_P1F:
+ default:
+ FBDiv = (freq / (FREF / 2));
+ Rest = 2 * freq - FBDiv * FREF;
+ break;
+ }
+
+
+ if (Rest < LPF) Rest = 0;
+ else if (Rest < 2 * LPF) Rest = 2 * LPF;
+ else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; }
+ else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
+ Rest = (Rest * 6528) / (FREF / 10);
+ dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
+
+ Num = 0;
+ Den = 1;
+
+ if (Rest > 0) {
+ LO4_SET_SD(lo4, 1);
+ Den = 255;
+ Num = (u16)Rest;
+ }
+ dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1);
+
+
+
+ dib0070_write_reg(st, 0x11, (u16)FBDiv);
+
+
+ dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
+
+
+ dib0070_write_reg(st, 0x13, Num);
+
+
+ value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
+
+ switch (band) {
+ case BAND_UHF: value |= 0x4000 | 0x0800; break;
+ case BAND_LBAND: value |= 0x2000 | 0x0400; break;
+ default: value |= 0x8000 | 0x1000; break;
+ }
+ dib0070_write_reg(st, 0x20, value);
+
+ dib0070_captrim(st, lo4);
+ if (st->revision == DIB0070S_P1A) {
+ if (band == BAND_SBAND)
+ dib0070_write_reg(st, 0x15, 0x16e2);
+ else
+ dib0070_write_reg(st, 0x15, 0x56e5);
+ }
+
+
+
+ switch (band) {
+ case BAND_UHF: value = 0x7c82; break;
+ case BAND_LBAND: value = 0x7c84; break;
+ default: value = 0x7c81; break;
+ }
+ dib0070_write_reg(st, 0x0f, value);
+ dib0070_write_reg(st, 0x06, 0x3fff);
+
+ /* Front End */
+ /* c == TUNE, value = SWITCH */
+ c = 0;
+ value = 0;
+ switch (band) {
+ case BAND_FM:
+ c = 0; value = 1;
+ break;
+
+ case BAND_VHF:
+ if (freq <= 180000) c = 0;
+ else if (freq <= 188200) c = 1;
+ else if (freq <= 196400) c = 2;
+ else c = 3;
+ value = 1;
+ break;
+
+ case BAND_LBAND:
+ if (freq <= 1500000) c = 0;
+ else if (freq <= 1600000) c = 1;
+ else c = 3;
+ break;
+
+ case BAND_SBAND:
+ c = 7;
+ dib0070_write_reg(st, 0x1d,0xFFFF);
+ break;
+
+ case BAND_UHF:
+ default:
+ if (st->cfg->flip_chip) {
+ if (freq <= 550000) c = 0;
+ else if (freq <= 590000) c = 1;
+ else if (freq <= 666000) c = 3;
+ else c = 5;
+ } else {
+ if (freq <= 550000) c = 2;
+ else if (freq <= 650000) c = 3;
+ else if (freq <= 750000) c = 5;
+ else if (freq <= 850000) c = 6;
+ else c = 7;
+ }
+ value = 2;
+ break;
+ }
+
+ /* default: LNA_MATCH=7, BIAS=3 */
+ dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0));
+ dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127));
+ dib0070_write_reg(st, 0x0d, 0x0d80);
+
+
+ dib0070_write_reg(st, 0x18, 0x07ff);
+ dib0070_write_reg(st, 0x17, 0x0033);
+
+ return 0;
+}
+
+static int dib0070_wakeup(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ if (st->cfg->sleep)
+ st->cfg->sleep(fe, 0);
+ return 0;
+}
+
+static int dib0070_sleep(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ if (st->cfg->sleep)
+ st->cfg->sleep(fe, 1);
+ return 0;
+}
+
+static u16 dib0070_p1f_defaults[] =
+
+{
+ 7, 0x02,
+ 0x0008,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0002,
+ 0x0100,
+
+ 3, 0x0d,
+ 0x0d80,
+ 0x0001,
+ 0x0000,
+
+ 4, 0x11,
+ 0x0000,
+ 0x0103,
+ 0x0000,
+ 0x0000,
+
+ 3, 0x16,
+ 0x0004 | 0x0040,
+ 0x0030,
+ 0x07ff,
+
+ 6, 0x1b,
+ 0x4112,
+ 0xff00,
+ 0xc07f,
+ 0x0000,
+ 0x0180,
+ 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+
+ 0,
+};
+
+static void dib0070_wbd_calibration(struct dib0070_state *state)
+{
+ u16 wbd_offs;
+ dib0070_write_reg(state, 0x0f, 0x6d81);
+ dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+ msleep(9);
+ wbd_offs = dib0070_read_reg(state, 0x19);
+ dib0070_write_reg(state, 0x20, 0);
+ state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
+ dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+}
+
+u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ return st->wbd_ff_offset;
+}
+
+EXPORT_SYMBOL(dib0070_wbd_offset);
+static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
+{
+ struct dib0070_state *state = fe->tuner_priv;
+ u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+ dprintk( "CTRL_LO5: 0x%x", lo5);
+ return dib0070_write_reg(state, 0x15, lo5);
+}
+
+#define pgm_read_word(w) (*w)
+static int dib0070_reset(struct dib0070_state *state)
+{
+ u16 l, r, *n;
+
+ HARD_RESET(state);
+
+
+#ifndef FORCE_SBAND_TUNER
+ if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
+ state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
+ else
+#endif
+ state->revision = DIB0070S_P1A;
+
+ /* P1F or not */
+ dprintk( "Revision: %x", state->revision);
+
+ if (state->revision == DIB0070_P1D) {
+ dprintk( "Error: this driver is not to be used meant for P1D or earlier");
+ return -EINVAL;
+ }
+
+ n = (u16 *) dib0070_p1f_defaults;
+ l = pgm_read_word(n++);
+ while (l) {
+ r = pgm_read_word(n++);
+ do {
+ dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
+ r++;
+ } while (--l);
+ l = pgm_read_word(n++);
+ }
+
+ if (state->cfg->force_crystal_mode != 0)
+ r = state->cfg->force_crystal_mode;
+ else if (state->cfg->clock_khz >= 24000)
+ r = 1;
+ else
+ r = 2;
+
+ r |= state->cfg->osc_buffer_state << 3;
+
+ dib0070_write_reg(state, 0x10, r);
+ dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4));
+
+ if (state->cfg->invert_iq) {
+ r = dib0070_read_reg(state, 0x02) & 0xffdf;
+ dib0070_write_reg(state, 0x02, r | (1 << 5));
+ }
+
+
+ if (state->revision == DIB0070S_P1A)
+ dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1);
+ else
+ dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0);
+
+ dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
+ return 0;
+}
+
+
+static int dib0070_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static struct dvb_tuner_ops dib0070_ops = {
+ .info = {
+ .name = "DiBcom DiB0070",
+ .frequency_min = 45000000,
+ .frequency_max = 860000000,
+ .frequency_step = 1000,
+ },
+ .release = dib0070_release,
+
+ .init = dib0070_wakeup,
+ .sleep = dib0070_sleep,
+ .set_params = dib0070_tune_digital,
+// .get_frequency = dib0070_get_frequency,
+// .get_bandwidth = dib0070_get_bandwidth
+};
+
+struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+ struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->cfg = cfg;
+ state->i2c = i2c;
+ state->fe = fe;
+ fe->tuner_priv = state;
+
+ if (dib0070_reset(state) != 0)
+ goto free_mem;
+
+ dib0070_wbd_calibration(state);
+
+ printk(KERN_INFO "DiB0070: successfully identified\n");
+ memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = state;
+ return fe;
+
+free_mem:
+ kfree(state);
+ fe->tuner_priv = NULL;
+ return NULL;
+}
+EXPORT_SYMBOL(dib0070_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
new file mode 100644
index 000000000000..786e37d33889
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib0070.h
@@ -0,0 +1,44 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+#ifndef DIB0070_H
+#define DIB0070_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
+
+struct dib0070_config {
+ u8 i2c_address;
+
+ /* tuner pins controlled externally */
+ int (*reset) (struct dvb_frontend *, int);
+ int (*sleep) (struct dvb_frontend *, int);
+
+ /* offset in kHz */
+ int freq_offset_khz_uhf;
+ int freq_offset_khz_vhf;
+
+ u8 osc_buffer_state; /* 0= normal, 1= tri-state */
+ u32 clock_khz;
+ u8 clock_pad_drive; /* (Drive + 1) * 2mA */
+
+ u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
+
+ u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
+
+ u8 flip_chip;
+};
+
+extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index b6adea5ffeb8..136b9d2164d7 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 054d7e6d9662..edae0be063f5 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,7 +1,7 @@
/*
* Driver for DiBcom DiB3000MC/P-demodulator.
*
- * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This code is partially based on the previous dib3000mc.c .
@@ -13,10 +13,6 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
-//#include <linux/init.h>
-//#include <linux/delay.h>
-//#include <linux/string.h>
-//#include <linux/slab.h>
#include "dvb_frontend.h"
@@ -26,7 +22,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
struct dib3000mc_state {
struct dvb_frontend demod;
@@ -42,6 +42,8 @@ struct dib3000mc_state {
fe_bandwidth_t current_bandwidth;
u16 dev_id;
+
+ u8 sfn_workaround_active :1;
};
static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
@@ -71,7 +73,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
-
static int dib3000mc_identify(struct dib3000mc_state *state)
{
u16 value;
@@ -92,7 +93,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state)
return 0;
}
-static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
{
u32 timf;
@@ -103,7 +104,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
} else
timf = state->timf;
- timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
+ timf *= (bw / 1000);
if (update_offset) {
s16 tim_offs = dib3000mc_read_word(state, 416);
@@ -111,17 +112,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
if (tim_offs & 0x2000)
tim_offs -= 0x4000;
- if (nfft == 0)
+ if (nfft == TRANSMISSION_MODE_2K)
tim_offs *= 4;
timf += tim_offs;
- state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
+ state->timf = timf / (bw / 1000);
}
dprintk("timf: %d\n", timf);
- dib3000mc_write_word(state, 23, timf >> 16);
- dib3000mc_write_word(state, 24, timf & 0xffff);
+ dib3000mc_write_word(state, 23, (u16) (timf >> 16));
+ dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff);
return 0;
}
@@ -209,31 +210,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
return ret;
}
-static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
{
- struct dib3000mc_state *state = demod->demodulator_priv;
u16 bw_cfg[6] = { 0 };
u16 imp_bw_cfg[3] = { 0 };
u16 reg;
/* settings here are for 27.7MHz */
switch (bw) {
- case BANDWIDTH_8_MHZ:
+ case 8000:
bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000:
bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
break;
- case BANDWIDTH_6_MHZ:
+ case 6000:
bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
break;
- case 255 /* BANDWIDTH_5_MHZ */:
+ case 5000:
bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
break;
@@ -257,7 +257,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
// Timing configuration
- dib3000mc_set_timing(state, 0, bw, 0);
+ dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
return 0;
}
@@ -276,7 +276,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode,
for (i = 58; i < 87; i++)
dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
- if (nfft == 1) {
+ if (nfft == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 58, 0x3b);
dib3000mc_write_word(state, 84, 0x00);
dib3000mc_write_word(state, 85, 0x8200);
@@ -376,7 +376,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
// P_search_maxtrial=1
dib3000mc_write_word(state, 5, 1);
- dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib3000mc_set_bandwidth(state, 8000);
// div_lock_mask
dib3000mc_write_word(state, 4, 0x814);
@@ -397,7 +397,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
dib3000mc_write_word(state, 180, 0x2FF0);
// Impulse noise configuration
- dib3000mc_set_impulse_noise(state, 0, 1);
+ dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
// output mode set-up
dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
@@ -423,13 +423,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
{
u16 cfg[4] = { 0 },reg;
switch (qam) {
- case 0:
+ case QPSK:
cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
break;
- case 1:
+ case QAM_16:
cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
break;
- case 2:
+ case QAM_64:
cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
break;
}
@@ -437,11 +437,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
dib3000mc_write_word(state, reg, cfg[reg - 129]);
}
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
{
- u16 tmp;
-
- dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+ u16 value;
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
// if (boost)
// dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -455,7 +455,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
dib3000mc_write_word(state, 26, 0x6680);
dib3000mc_write_word(state, 29, 0x1273);
dib3000mc_write_word(state, 33, 5);
- dib3000mc_set_adp_cfg(state, 1);
+ dib3000mc_set_adp_cfg(state, QAM_16);
dib3000mc_write_word(state, 133, 15564);
dib3000mc_write_word(state, 12 , 0x0);
@@ -470,52 +470,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
dib3000mc_write_word(state, 97,0);
dib3000mc_write_word(state, 98,0);
- dib3000mc_set_impulse_noise(state, 0, chan->nfft);
-
- tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
- dib3000mc_write_word(state, 0, tmp);
+ dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib3000mc_write_word(state, 0, value);
dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
- tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
- if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
- tmp |= chan->vit_code_rate_hp << 1;
- else
- tmp |= chan->vit_code_rate_lp << 1;
- dib3000mc_write_word(state, 181, tmp);
+ value = 0;
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
+ dib3000mc_write_word(state, 181, value);
- // diversity synchro delay
- tmp = dib3000mc_read_word(state, 180) & 0x000f;
- tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
- dib3000mc_write_word(state, 180, tmp);
+ // diversity synchro delay add 50% SFN margin
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case TRANSMISSION_MODE_2K:
+ default: value = 64; break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ value <<= 4;
+ value |= dib3000mc_read_word(state, 180) & 0x000f;
+ dib3000mc_write_word(state, 180, value);
// restart demod
- tmp = dib3000mc_read_word(state, 0);
- dib3000mc_write_word(state, 0, tmp | (1 << 9));
- dib3000mc_write_word(state, 0, tmp);
+ value = dib3000mc_read_word(state, 0);
+ dib3000mc_write_word(state, 0, value | (1 << 9));
+ dib3000mc_write_word(state, 0, value);
msleep(30);
- dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+ dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
}
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
{
struct dib3000mc_state *state = demod->demodulator_priv;
u16 reg;
// u32 val;
- struct dibx000_ofdm_channel fchan;
+ struct dvb_frontend_parameters schan;
- INIT_OFDM_CHANNEL(&fchan);
- fchan = *chan;
+ schan = *chan;
+ /* TODO what is that ? */
/* a channel for autosearch */
- fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
- fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
- fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_2_3;
+ schan.u.ofdm.hierarchy_information = 0;
- dib3000mc_set_channel_cfg(state, &fchan, 11);
+ dib3000mc_set_channel_cfg(state, &schan, 11);
reg = dib3000mc_read_word(state, 0);
dib3000mc_write_word(state, 0, reg | (1 << 8));
@@ -539,7 +585,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib3000mc_state *state = demod->demodulator_priv;
@@ -547,11 +593,17 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
dib3000mc_set_channel_cfg(state, ch, 0);
// activates isi
- dib3000mc_write_word(state, 29, 0x1073);
-
- dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
+ if (state->sfn_workaround_active) {
+ dprintk("SFN workaround is active\n");
+ dib3000mc_write_word(state, 29, 0x1273);
+ dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
+ } else {
+ dib3000mc_write_word(state, 29, 0x1073);
+ dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
+ }
- if (ch->nfft == 1) {
+ dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
+ if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 26, 38528);
dib3000mc_write_word(state, 33, 8);
} else {
@@ -560,7 +612,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
}
if (dib3000mc_read_word(state, 509) & 0x80)
- dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+ dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
return 0;
}
@@ -632,13 +684,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib3000mc_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+ /* maybe the parameter has been changed */
+ state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, fep);
@@ -651,7 +702,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 100, found;
- dib3000mc_autosearch_start(fe, &ch);
+ dib3000mc_autosearch_start(fe, fep);
do {
msleep(1);
found = dib3000mc_autosearch_is_irq(fe);
@@ -662,13 +713,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
return 0; // no channel found
dib3000mc_get_frontend(fe, fep);
- FEP2DIB(fep,&ch);
}
/* make this a config parameter */
dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib3000mc_tune(fe, &ch);
+ return dib3000mc_tune(fe, fep);
}
static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index f64546c6aeb5..fb18441a8c57 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -2,7 +2,7 @@
* Linux-DVB Driver for DiBcom's DiB7000M and
* first generation DiB7000P-demodulator-family.
*
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -19,7 +19,7 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0)
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
struct dib7000m_state {
struct dvb_frontend demod;
@@ -39,8 +39,16 @@ struct dib7000m_state {
fe_bandwidth_t current_bandwidth;
struct dibx000_agc_config *current_agc;
u32 timf;
+ u32 timf_default;
+ u32 internal_clk;
+
+ u8 div_force_off : 1;
+ u8 div_state : 1;
+ u16 div_sync_wait;
u16 revision;
+
+ u8 agc_state;
};
enum dib7000m_power_mode {
@@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
};
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
- dprintk("i2c read error on %d\n",reg);
+ dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
}
@@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
+static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+{
+ u16 l = 0, r, *n;
+ n = buf;
+ l = *n++;
+ while (l) {
+ r = *n++;
+
+ if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
+ r++;
+
+ do {
+ dib7000m_write_word(state, r, *n++);
+ r++;
+ } while (--l);
+ l = *n++;
+ }
+}
+
static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
{
int ret = 0;
@@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
fifo_threshold = 1792;
smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
- dprintk("-I- Setting output mode for demod %p to %d\n",
- &state->demod, mode);
+ dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
switch (mode) {
case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
@@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
outreg = 0;
break;
default:
- dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
break;
}
@@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
ret |= dib7000m_write_word(state, 1795, outreg);
ret |= dib7000m_write_word(state, 1805, sram);
+ if (state->revision == 0x4003) {
+ u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
+ if (mode == OUTMODE_DIVERSITY)
+ clk_cfg1 |= (1 << 1); // P_O_CLK_en
+ dib7000m_write_word(state, 909, clk_cfg1);
+ }
return ret;
}
-static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
{
/* by default everything is going to be powered off */
u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff;
+ u8 offset = 0;
/* now, depending on the requested mode, we power on */
switch (mode) {
@@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p
if (!state->cfg.mobile_mode)
reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
- /* P_sdio_select_clk = 0 on MC */
+ /* P_sdio_select_clk = 0 on MC and after*/
if (state->revision != 0x4000)
reg_906 <<= 1;
- dib7000m_write_word(state, 903, reg_903);
- dib7000m_write_word(state, 904, reg_904);
- dib7000m_write_word(state, 905, reg_905);
- dib7000m_write_word(state, 906, reg_906);
+ if (state->revision == 0x4003)
+ offset = 1;
- return 0;
+ dib7000m_write_word(state, 903 + offset, reg_903);
+ dib7000m_write_word(state, 904 + offset, reg_904);
+ dib7000m_write_word(state, 905 + offset, reg_905);
+ dib7000m_write_word(state, 906 + offset, reg_906);
}
static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
@@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc
break;
}
-// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914);
-
+// dprintk( "913: %x, 914: %x", reg_913, reg_914);
ret |= dib7000m_write_word(state, 913, reg_913);
ret |= dib7000m_write_word(state, 914, reg_914);
return ret;
}
-static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
+static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
{
- struct dib7000m_state *state = demod->demodulator_priv;
u32 timf;
// store the current bandwidth for later use
- state->current_bandwidth = bw_idx;
+ state->current_bandwidth = bw;
if (state->timf == 0) {
- dprintk("-D- Using default timf\n");
- timf = state->cfg.bw->timf;
+ dprintk( "using default timf");
+ timf = state->timf_default;
} else {
- dprintk("-D- Using updated timf\n");
+ dprintk( "using updated timf");
timf = state->timf;
}
- timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80;
+ timf = timf * (bw / 50) / 160;
- dib7000m_write_word(state, 23, (timf >> 16) & 0xffff);
- dib7000m_write_word(state, 24, (timf ) & 0xffff);
+ dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+ dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff));
+
+ return 0;
+}
+
+static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+
+ if (state->div_force_off) {
+ dprintk( "diversity combination deactivated - forced by COFDM parameters");
+ onoff = 0;
+ }
+ state->div_state = (u8)onoff;
+
+ if (onoff) {
+ dib7000m_write_word(state, 263 + state->reg_offs, 6);
+ dib7000m_write_word(state, 264 + state->reg_offs, 6);
+ dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+ } else {
+ dib7000m_write_word(state, 263 + state->reg_offs, 1);
+ dib7000m_write_word(state, 264 + state->reg_offs, 0);
+ dib7000m_write_word(state, 266 + state->reg_offs, 0);
+ }
return 0;
}
@@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
{
/* internal */
-// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
@@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
{
- dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
- dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff);
- dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
- dib7000m_write_word(state, 22, bw->ifreq & 0xffff);
+ dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+ dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff));
+ dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
+ dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff));
dib7000m_write_word(state, 928, bw->sad_cfg);
}
@@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state)
static void dib7000mc_reset_pll(struct dib7000m_state *state)
{
const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+ u16 clk_cfg1;
// clk_cfg0
dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
// clk_cfg1
//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
- dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) |
+ clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
- (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0));
+ (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
+ dib7000m_write_word(state, 908, clk_cfg1);
+ clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
+ dib7000m_write_word(state, 908, clk_cfg1);
// smpl_cfg
dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
@@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state)
static int dib7000m_reset_gpio(struct dib7000m_state *st)
{
/* reset the GPIOs */
- dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",
- st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos);
-
dib7000m_write_word(st, 773, st->cfg.gpio_dir);
dib7000m_write_word(st, 774, st->cfg.gpio_val);
@@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st)
return 0;
}
+static u16 dib7000m_defaults_common[] =
+
+{
+ // auto search configuration
+ 3, 2,
+ 0x0004,
+ 0x1000,
+ 0x0814,
+
+ 12, 6,
+ 0x001b,
+ 0x7740,
+ 0x005b,
+ 0x8d80,
+ 0x01c9,
+ 0xc380,
+ 0x0000,
+ 0x0080,
+ 0x0000,
+ 0x0090,
+ 0x0001,
+ 0xd4c0,
+
+ 1, 26,
+ 0x6680, // P_corm_thres Lock algorithms configuration
+
+ 1, 170,
+ 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+
+ 8, 173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ 1, 182,
+ 8192, // P_fft_nb_to_cut
+
+ 2, 195,
+ 0x0ccd, // P_pha3_thres
+ 0, // P_cti_use_cpe, P_cti_use_prog
+
+ 1, 205,
+ 0x200f, // P_cspu_regul, P_cspu_win_cut
+
+ 5, 214,
+ 0x023d, // P_adp_regul_cnt
+ 0x00a4, // P_adp_noise_cnt
+ 0x00a4, // P_adp_regul_ext
+ 0x7ff0, // P_adp_noise_ext
+ 0x3ccc, // P_adp_fil
+
+ 1, 226,
+ 0, // P_2d_byp_ti_num
+
+ 1, 255,
+ 0x800, // P_equal_thres_wgn
+
+ 1, 263,
+ 0x0001,
+
+ 1, 281,
+ 0x0010, // P_fec_*
+
+ 1, 294,
+ 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+ 0
+};
+
+static u16 dib7000m_defaults[] =
+
+{
+ /* set ADC level to -16 */
+ 11, 76,
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117,
+
+ // Tuner IO bank: max drive (14mA)
+ 1, 912,
+ 0x2c8a,
+
+ 1, 1817,
+ 1,
+
+ 0,
+};
+
static int dib7000m_demod_reset(struct dib7000m_state *state)
{
dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
@@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state)
dib7000mc_reset_pll(state);
if (dib7000m_reset_gpio(state) != 0)
- dprintk("-E- GPIO reset was not successful.\n");
+ dprintk( "GPIO reset was not successful.");
if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
- dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+ dprintk( "OUTPUT_MODE could not be reset.");
/* unforce divstr regardless whether i2c enumeration was done or not */
dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
- dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib7000m_set_bandwidth(state, 8000);
dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
dib7000m_sad_calib(state);
dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+ if (state->cfg.dvbt_mode)
+ dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+ if (state->cfg.mobile_mode)
+ dib7000m_write_word(state, 261 + state->reg_offs, 2);
+ else
+ dib7000m_write_word(state, 224 + state->reg_offs, 1);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ dib7000m_write_word(state, 36, 0x0755);
+ else
+ dib7000m_write_word(state, 36, 0x1f55);
+
+ // P_divclksel=3 P_divbitsel=1
+ if (state->revision == 0x4000)
+ dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+ else
+ dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+ dib7000m_write_tab(state, dib7000m_defaults_common);
+ dib7000m_write_tab(state, dib7000m_defaults);
+
dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
+ state->internal_clk = state->cfg.bw->internal;
+
return 0;
}
@@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state)
(agc - state->current_agc->split.min_thres) /
(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
- dprintk("AGC split_offset: %d\n",split_offset);
+ dprintk( "AGC split_offset: %d",split_offset);
// P_agc_force_split and P_agc_split_offset
return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
@@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state)
static int dib7000m_update_lna(struct dib7000m_state *state)
{
- int i;
u16 dyn_gain;
- // when there is no LNA to program return immediatly
- if (state->cfg.update_lna == NULL)
- return 0;
-
- msleep(60);
- for (i = 0; i < 20; i++) {
- // read dyn_gain here (because it is demod-dependent and not tuner)
+ if (state->cfg.update_lna) {
+ // read dyn_gain here (because it is demod-dependent and not fe)
dyn_gain = dib7000m_read_word(state, 390);
- dprintk("agc global: %d\n", dyn_gain);
-
if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
dib7000m_restart_agc(state);
- msleep(60);
- } else
- break;
+ return 1;
+ }
}
return 0;
}
-static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
{
struct dibx000_agc_config *agc = NULL;
int i;
- if (state->current_band == band)
- return;
+ if (state->current_band == band && state->current_agc != NULL)
+ return 0;
state->current_band = band;
for (i = 0; i < state->cfg.agc_config_count; i++)
@@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
}
if (agc == NULL) {
- dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band);
- return;
+ dprintk( "no valid AGC configuration found for band 0x%02x",band);
+ return -EINVAL;
}
state->current_agc = agc;
@@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp);
- dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+ dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
/* AGC continued */
@@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
if (state->revision > 0x4000) { // settings for the MC
dib7000m_write_word(state, 71, agc->agc1_pt3);
-// dprintk("-D- 929: %x %d %d\n",
+// dprintk( "929: %x %d %d",
// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
} else {
@@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
for (i = 0; i < 9; i++)
dib7000m_write_word(state, 88 + i, b[i]);
}
+ return 0;
}
-static void dib7000m_update_timf_freq(struct dib7000m_state *state)
+static void dib7000m_update_timf(struct dib7000m_state *state)
{
u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
- state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ state->timf = timf * 160 / (state->current_bandwidth / 50);
dib7000m_write_word(state, 23, (u16) (timf >> 16));
dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
- dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+ dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
+}
+
+static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ u16 cfg_72 = dib7000m_read_word(state, 72);
+ int ret = -1;
+ u8 *agc_state = &state->agc_state;
+ u8 agc_split;
+
+ switch (state->agc_state) {
+ case 0:
+ // set power-up level: interf+analog+AGC
+ dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+ dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+ if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+ return -1;
+
+ ret = 7; /* ADC power up */
+ (*agc_state)++;
+ break;
+
+ case 1:
+ /* AGC initialization */
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000m_write_word(state, 75, 32768);
+ if (!state->current_agc->perform_agc_softsplit) {
+ /* we are using the wbd - so slow AGC startup */
+ dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
+ (*agc_state)++;
+ ret = 5;
+ } else {
+ /* default AGC startup */
+ (*agc_state) = 4;
+ /* wait AGC rough lock time */
+ ret = 7;
+ }
+
+ dib7000m_restart_agc(state);
+ break;
+
+ case 2: /* fast split search path after 5sec */
+ dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */
+ dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */
+ (*agc_state)++;
+ ret = 14;
+ break;
+
+ case 3: /* split search ended */
+ agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
+ dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
+
+ dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */
+ dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+ dib7000m_restart_agc(state);
+
+ dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+ (*agc_state)++;
+ ret = 5;
+ break;
+
+ case 4: /* LNA startup */
+ /* wait AGC accurate lock time */
+ ret = 7;
+
+ if (dib7000m_update_lna(state))
+ // wait only AGC rough lock time
+ ret = 5;
+ else
+ (*agc_state)++;
+ break;
+
+ case 5:
+ dib7000m_agc_soft_split(state);
+
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+
+ (*agc_state)++;
+ break;
+
+ default:
+ break;
+ }
+ return ret;
}
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq)
{
u16 value, est[4];
- dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz));
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
/* nfft, guard, qam, alpha */
- dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ case /* 4K MODE */ 255: value |= (2 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib7000m_write_word(state, 0, value);
dib7000m_write_word(state, 5, (seq << 4));
- /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
- value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
- if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
- value |= (ch->vit_code_rate_hp << 1);
- else
- value |= (ch->vit_code_rate_lp << 1);
+ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+ value = 0;
+ if (1 != 0)
+ value |= (1 << 6);
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
dib7000m_write_word(state, 267 + state->reg_offs, value);
/* offset loop parameters */
@@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of
dib7000m_write_word(state, 33, (0 << 4) | 0x5);
/* P_dvsy_sync_wait */
- switch (ch->nfft) {
- case 1: value = 256; break;
- case 2: value = 128; break;
- case 0:
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
- value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
- value <<= 4;
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
- if (ch->intlv_native || state->revision > 0x4000)
- value |= (1 << 2) | (2 << 0);
+ if (1 == 1 || state->revision > 0x4000)
+ state->div_force_off = 0;
else
- value |= 0;
- dib7000m_write_word(state, 266 + state->reg_offs, value);
+ state->div_force_off = 1;
+ dib7000m_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->nqam) {
- case 2:
+ switch (ch->u.ofdm.constellation) {
+ case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
break;
- case 1:
+ case QAM_16:
est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
@@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of
for (value = 0; value < 4; value++)
dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
- // set power-up level: interf+analog+AGC
- dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
- dib7000m_set_adc_state(state, DIBX000_ADC_ON);
-
- msleep(7);
-
- //AGC initialization
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 1);
-
- dib7000m_restart_agc(state);
-
- // wait AGC rough lock time
- msleep(5);
-
- dib7000m_update_lna(state);
- dib7000m_agc_soft_split(state);
-
- // wait AGC accurate lock time
- msleep(7);
-
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 0);
-
// set power-up level: autosearch
dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
}
-static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000m_state *state = demod->demodulator_priv;
- struct dibx000_ofdm_channel auto_ch;
+ struct dvb_frontend_parameters schan;
int ret = 0;
- u32 value;
-
- INIT_OFDM_CHANNEL(&auto_ch);
- auto_ch.RF_kHz = ch->RF_kHz;
- auto_ch.Bw = ch->Bw;
- auto_ch.nqam = 2;
- auto_ch.guard = 0;
- auto_ch.nfft = 1;
- auto_ch.vit_alpha = 1;
- auto_ch.vit_select_hp = 1;
- auto_ch.vit_code_rate_hp = 2;
- auto_ch.vit_code_rate_lp = 3;
- auto_ch.vit_hrch = 0;
- auto_ch.intlv_native = 1;
-
- dib7000m_set_channel(state, &auto_ch, 7);
+ u32 value, factor;
+
+ schan = *ch;
+
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_3_4;
+ schan.u.ofdm.hierarchy_information = 0;
+
+ dib7000m_set_channel(state, &schan, 7);
+
+ factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ if (factor >= 5000)
+ factor = 1;
+ else
+ factor = 6;
// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
- value = 30 * state->cfg.bw->internal;
+ value = 30 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.bw->internal;
+ value = 100 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
- value = 500 * state->cfg.bw->internal;
+ value = 500 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
// start search
value = dib7000m_read_word(state, 0);
- ret |= dib7000m_write_word(state, 0, value | (1 << 9));
+ ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
/* clear n_irq_pending */
if (state->revision == 0x4000)
@@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
u16 irq_pending = dib7000m_read_word(state, reg);
if (irq_pending & 0x1) { // failed
- dprintk("#\n");
+ dprintk( "autosearch failed");
return 1;
}
if (irq_pending & 0x2) { // succeeded
- dprintk("!\n");
+ dprintk( "autosearch succeeded");
return 2;
}
return 0; // still pending
@@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
return dib7000m_autosearch_irq(state, 537);
}
-static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000m_state *state = demod->demodulator_priv;
int ret = 0;
@@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
ret |= dib7000m_write_word(state, 898, 0x0000);
msleep(45);
- ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+ dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
- // never achieved a lock with that bandwidth so far - wait for timfreq to update
+ // never achieved a lock before - wait for timfreq to update
if (state->timf == 0)
msleep(200);
//dump_reg(state);
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
value = (6 << 8) | 0x80;
- switch (ch->nfft) {
- case 0: value |= (7 << 12); break;
- case 1: value |= (9 << 12); break;
- case 2: value |= (8 << 12); break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
+ case /* 4K MODE */ 255: value |= (8 << 12); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
}
ret |= dib7000m_write_word(state, 26, value);
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
value = (0 << 4);
- switch (ch->nfft) {
- case 0: value |= 0x6; break;
- case 1: value |= 0x8; break;
- case 2: value |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= 0x6; break;
+ case /* 4K MODE */ 255: value |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
ret |= dib7000m_write_word(state, 32, value);
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
value = (0 << 4);
- switch (ch->nfft) {
- case 0: value |= 0x6; break;
- case 1: value |= 0x8; break;
- case 2: value |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= 0x6; break;
+ case /* 4K MODE */ 255: value |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
ret |= dib7000m_write_word(state, 33, value);
- // we achieved a lock - it's time to update the osc freq
+ // we achieved a lock - it's time to update the timf freq
if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
- dib7000m_update_timf_freq(state);
+ dib7000m_update_timf(state);
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
return ret;
}
-static int dib7000m_init(struct dvb_frontend *demod)
+static int dib7000m_wakeup(struct dvb_frontend *demod)
{
struct dib7000m_state *state = demod->demodulator_priv;
- int ret = 0;
- u8 o = state->reg_offs;
dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
- dprintk("-E- could not start Slow ADC\n");
-
- if (state->cfg.dvbt_mode)
- dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
-
- if (state->cfg.mobile_mode)
- ret |= dib7000m_write_word(state, 261 + o, 2);
- else
- ret |= dib7000m_write_word(state, 224 + o, 1);
-
- ret |= dib7000m_write_word(state, 173 + o, 0);
- ret |= dib7000m_write_word(state, 174 + o, 0);
- ret |= dib7000m_write_word(state, 175 + o, 0);
- ret |= dib7000m_write_word(state, 176 + o, 0);
- ret |= dib7000m_write_word(state, 177 + o, 0);
- ret |= dib7000m_write_word(state, 178 + o, 0);
- ret |= dib7000m_write_word(state, 179 + o, 0);
- ret |= dib7000m_write_word(state, 180 + o, 0);
-
- // P_corm_thres Lock algorithms configuration
- ret |= dib7000m_write_word(state, 26, 0x6680);
-
- // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
- ret |= dib7000m_write_word(state, 170 + o, 0x0410);
- // P_fft_nb_to_cut
- ret |= dib7000m_write_word(state, 182 + o, 8192);
- // P_pha3_thres
- ret |= dib7000m_write_word(state, 195 + o, 0x0ccd);
- // P_cti_use_cpe, P_cti_use_prog
- ret |= dib7000m_write_word(state, 196 + o, 0);
- // P_cspu_regul, P_cspu_win_cut
- ret |= dib7000m_write_word(state, 205 + o, 0x200f);
- // P_adp_regul_cnt
- ret |= dib7000m_write_word(state, 214 + o, 0x023d);
- // P_adp_noise_cnt
- ret |= dib7000m_write_word(state, 215 + o, 0x00a4);
- // P_adp_regul_ext
- ret |= dib7000m_write_word(state, 216 + o, 0x00a4);
- // P_adp_noise_ext
- ret |= dib7000m_write_word(state, 217 + o, 0x7ff0);
- // P_adp_fil
- ret |= dib7000m_write_word(state, 218 + o, 0x3ccc);
-
- // P_2d_byp_ti_num
- ret |= dib7000m_write_word(state, 226 + o, 0);
-
- // P_fec_*
- ret |= dib7000m_write_word(state, 281 + o, 0x0010);
- // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
- ret |= dib7000m_write_word(state, 294 + o,0x0062);
-
- // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
- if(state->cfg.tuner_is_baseband)
- ret |= dib7000m_write_word(state, 36, 0x0755);
- else
- ret |= dib7000m_write_word(state, 36, 0x1f55);
-
- // auto search configuration
- ret |= dib7000m_write_word(state, 2, 0x0004);
- ret |= dib7000m_write_word(state, 3, 0x1000);
- ret |= dib7000m_write_word(state, 4, 0x0814);
- ret |= dib7000m_write_word(state, 6, 0x001b);
- ret |= dib7000m_write_word(state, 7, 0x7740);
- ret |= dib7000m_write_word(state, 8, 0x005b);
- ret |= dib7000m_write_word(state, 9, 0x8d80);
- ret |= dib7000m_write_word(state, 10, 0x01c9);
- ret |= dib7000m_write_word(state, 11, 0xc380);
- ret |= dib7000m_write_word(state, 12, 0x0000);
- ret |= dib7000m_write_word(state, 13, 0x0080);
- ret |= dib7000m_write_word(state, 14, 0x0000);
- ret |= dib7000m_write_word(state, 15, 0x0090);
- ret |= dib7000m_write_word(state, 16, 0x0001);
- ret |= dib7000m_write_word(state, 17, 0xd4c0);
- ret |= dib7000m_write_word(state, 263 + o,0x0001);
-
- // P_divclksel=3 P_divbitsel=1
- if (state->revision == 0x4000)
- dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
- else
- dib7000m_write_word(state, 909, (3 << 4) | 1);
-
- // Tuner IO bank: max drive (14mA)
- ret |= dib7000m_write_word(state, 912 ,0x2c8a);
+ dprintk( "could not start Slow ADC");
- ret |= dib7000m_write_word(state, 1817, 1);
-
- return ret;
+ return 0;
}
static int dib7000m_sleep(struct dvb_frontend *demod)
{
struct dib7000m_state *st = demod->demodulator_priv;
dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
- return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) |
- dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+ dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
+ return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
}
static int dib7000m_identify(struct dib7000m_state *state)
{
u16 value;
+
if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
- dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value);
+ dprintk( "wrong Vendor ID (0x%x)",value);
return -EREMOTEIO;
}
state->revision = dib7000m_read_word(state, 897);
if (state->revision != 0x4000 &&
state->revision != 0x4001 &&
- state->revision != 0x4002) {
- dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value);
+ state->revision != 0x4002 &&
+ state->revision != 0x4003) {
+ dprintk( "wrong Device ID (0x%x)",value);
return -EREMOTEIO;
}
/* protect this driver to be used with 7000PC */
if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
- dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n");
+ dprintk( "this driver does not work with DiB7000PC");
return -EREMOTEIO;
}
switch (state->revision) {
- case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break;
- case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break;
- case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break;
+ case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
+ case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
+ case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
+ case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
}
return 0;
@@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib7000m_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
+ int time;
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, fep);
+ /* start up the AGC */
+ state->agc_state = 0;
+ do {
+ time = dib7000m_agc_startup(fe, fep);
+ if (time != -1)
+ msleep(time);
+ } while (time != -1);
+
if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
fep->u.ofdm.constellation == QAM_AUTO ||
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000m_autosearch_start(fe, &ch);
+ dib7000m_autosearch_start(fe, fep);
do {
msleep(1);
found = dib7000m_autosearch_is_irq(fe);
} while (found == 0 && i--);
- dprintk("autosearch returns: %d\n",found);
+ dprintk("autosearch returns: %d",found);
if (found == 0 || found == 1)
return 0; // no channel found
dib7000m_get_frontend(fe, fep);
- FEP2DIB(fep, &ch);
}
/* make this a config parameter */
dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib7000m_tune(fe, &ch);
+ return dib7000m_tune(fe, fep);
}
static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
if (dib7000m_identify(&st) != 0) {
st.i2c_addr = default_addr;
if (dib7000m_identify(&st) != 0) {
- dprintk("DiB7000M #%d: not identified\n", k);
+ dprintk("DiB7000M #%d: not identified", k);
return -EIO;
}
}
@@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
/* set new i2c address and force divstart */
dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
- dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
}
for (k = 0; k < no_of_demods; k++) {
@@ -1135,6 +1344,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
demod->demodulator_priv = st;
memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+ st->timf_default = cfg->bw->timf;
+
if (dib7000m_identify(st) != 0)
goto error;
@@ -1172,7 +1383,7 @@ static struct dvb_frontend_ops dib7000m_ops = {
.release = dib7000m_release,
- .init = dib7000m_init,
+ .init = dib7000m_wakeup,
.sleep = dib7000m_sleep,
.set_frontend = dib7000m_set_frontend,
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index aece458cfe12..f45bcfc51cf8 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -1,7 +1,7 @@
/*
* Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
*
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -18,7 +18,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
struct dib7000p_state {
struct dvb_frontend demod;
@@ -36,12 +40,21 @@ struct dib7000p_state {
struct dibx000_agc_config *current_agc;
u32 timf;
+ u8 div_force_off : 1;
+ u8 div_state : 1;
+ u16 div_sync_wait;
+
+ u8 agc_state;
+
u16 gpio_dir;
u16 gpio_val;
+
+ u8 sfn_workaround_active :1;
};
enum dib7000p_power_mode {
DIB7000P_POWER_ALL = 0,
+ DIB7000P_POWER_ANALOG_ADC,
DIB7000P_POWER_INTERFACE_ONLY,
};
@@ -55,7 +68,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
};
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
- dprintk("i2c read error on %d\n",reg);
+ dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
}
@@ -71,6 +84,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
+static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
+{
+ u16 l = 0, r, *n;
+ n = buf;
+ l = *n++;
+ while (l) {
+ r = *n++;
+
+ do {
+ dib7000p_write_word(state, r, *n++);
+ r++;
+ } while (--l);
+ l = *n++;
+ }
+}
+
static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
{
int ret = 0;
@@ -80,7 +109,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
fifo_threshold = 1792;
smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
- dprintk("-I- Setting output mode for demod %p to %d\n",
+ dprintk( "setting output mode for demod %p to %d",
&state->demod, mode);
switch (mode) {
@@ -104,11 +133,14 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
fifo_threshold = 512;
outreg = (1 << 10) | (5 << 6);
break;
+ case OUTMODE_ANALOG_ADC:
+ outreg = (1 << 10) | (3 << 6);
+ break;
case OUTMODE_HIGH_Z: // disable
outreg = 0;
break;
default:
- dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
break;
}
@@ -122,6 +154,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
return ret;
}
+static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+
+ if (state->div_force_off) {
+ dprintk( "diversity combination deactivated - forced by COFDM parameters");
+ onoff = 0;
+ }
+ state->div_state = (u8)onoff;
+
+ if (onoff) {
+ dib7000p_write_word(state, 204, 6);
+ dib7000p_write_word(state, 205, 16);
+ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+ dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+ } else {
+ dib7000p_write_word(state, 204, 1);
+ dib7000p_write_word(state, 205, 0);
+ dib7000p_write_word(state, 207, 0);
+ }
+
+ return 0;
+}
+
static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
{
/* by default everything is powered off */
@@ -134,10 +190,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
case DIB7000P_POWER_ALL:
reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
break;
+
+ case DIB7000P_POWER_ANALOG_ADC:
+ /* dem, cfg, iqc, sad, agc */
+ reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
+ /* nud */
+ reg_776 &= ~((1 << 0));
+ /* Dout */
+ reg_1280 &= ~((1 << 11));
+ /* fall through wanted to enable the interfaces */
+
/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
break;
+
/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
}
@@ -188,34 +255,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad
break;
}
-// dprintk("908: %x, 909: %x\n", reg_908, reg_909);
+// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
dib7000p_write_word(state, 908, reg_908);
dib7000p_write_word(state, 909, reg_909);
}
-static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
+static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
{
- struct dib7000p_state *state = demod->demodulator_priv;
u32 timf;
// store the current bandwidth for later use
- state->current_bandwidth = BW_Idx;
+ state->current_bandwidth = bw;
if (state->timf == 0) {
- dprintk("-D- Using default timf\n");
+ dprintk( "using default timf");
timf = state->cfg.bw->timf;
} else {
- dprintk("-D- Using updated timf\n");
+ dprintk( "using updated timf");
timf = state->timf;
}
- timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80;
-
- dprintk("timf: %d\n",timf);
+ timf = timf * (bw / 50) / 160;
- dib7000p_write_word(state, 23, (timf >> 16) & 0xffff);
- dib7000p_write_word(state, 24, (timf ) & 0xffff);
+ dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+ dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
return 0;
}
@@ -223,7 +287,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
static int dib7000p_sad_calib(struct dib7000p_state *state)
{
/* internal */
-// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
@@ -236,18 +300,37 @@ static int dib7000p_sad_calib(struct dib7000p_state *state)
return 0;
}
+int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ if (value > 4095)
+ value = 4095;
+ state->wbd_ref = value;
+ return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
+}
+
+EXPORT_SYMBOL(dib7000p_set_wbd_ref);
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+ u16 clk_cfg0;
+
+ /* force PLL bypass */
+ clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
+ (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
+ (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+ dib7000p_write_word(state, 900, clk_cfg0);
+
+ /* P_pll_cfg */
dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
- dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) |
- (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0));
+ clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
+ dib7000p_write_word(state, 900, clk_cfg0);
- dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
- dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff);
- dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
- dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff);
+ dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+ dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
+ dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
+ dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
dib7000p_write_word(state, 72, bw->sad_cfg);
}
@@ -255,7 +338,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state)
static int dib7000p_reset_gpio(struct dib7000p_state *st)
{
/* reset the GPIOs */
- dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+ dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
dib7000p_write_word(st, 1029, st->gpio_dir);
dib7000p_write_word(st, 1030, st->gpio_val);
@@ -268,6 +351,120 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st)
return 0;
}
+static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
+{
+ st->gpio_dir = dib7000p_read_word(st, 1029);
+ st->gpio_dir &= ~(1 << num); /* reset the direction bit */
+ st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
+ dib7000p_write_word(st, 1029, st->gpio_dir);
+
+ st->gpio_val = dib7000p_read_word(st, 1030);
+ st->gpio_val &= ~(1 << num); /* reset the direction bit */
+ st->gpio_val |= (val & 0x01) << num; /* set the new value */
+ dib7000p_write_word(st, 1030, st->gpio_val);
+
+ return 0;
+}
+
+int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ return dib7000p_cfg_gpio(state, num, dir, val);
+}
+
+EXPORT_SYMBOL(dib7000p_set_gpio);
+static u16 dib7000p_defaults[] =
+
+{
+ // auto search configuration
+ 3, 2,
+ 0x0004,
+ 0x1000,
+ 0x0814, /* Equal Lock */
+
+ 12, 6,
+ 0x001b,
+ 0x7740,
+ 0x005b,
+ 0x8d80,
+ 0x01c9,
+ 0xc380,
+ 0x0000,
+ 0x0080,
+ 0x0000,
+ 0x0090,
+ 0x0001,
+ 0xd4c0,
+
+ 1, 26,
+ 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+
+ /* set ADC level to -16 */
+ 11, 79,
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117,
+
+ 1, 142,
+ 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+
+ /* disable power smoothing */
+ 8, 145,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ 1, 154,
+ 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+
+ 1, 168,
+ 0x0ccd, // P_pha3_thres, default 0x3000
+
+// 1, 169,
+// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+
+ 1, 183,
+ 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+
+ 5, 187,
+ 0x023d, // P_adp_regul_cnt=573, default: 410
+ 0x00a4, // P_adp_noise_cnt=
+ 0x00a4, // P_adp_regul_ext
+ 0x7ff0, // P_adp_noise_ext
+ 0x3ccc, // P_adp_fil
+
+ 1, 198,
+ 0x800, // P_equal_thres_wgn
+
+ 1, 222,
+ 0x0010, // P_fec_ber_rs_len=2
+
+ 1, 235,
+ 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+ 2, 901,
+ 0x0006, // P_clk_cfg1
+ (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
+
+ 1, 905,
+ 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
+
+ 0,
+};
+
static int dib7000p_demod_reset(struct dib7000p_state *state)
{
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -292,111 +489,307 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
dib7000p_reset_pll(state);
if (dib7000p_reset_gpio(state) != 0)
- dprintk("-E- GPIO reset was not successful.\n");
+ dprintk( "GPIO reset was not successful.");
if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
- dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+ dprintk( "OUTPUT_MODE could not be reset.");
/* unforce divstr regardless whether i2c enumeration was done or not */
dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
+ dib7000p_set_bandwidth(state, 8000);
+
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+ dib7000p_sad_calib(state);
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ dib7000p_write_word(state, 36,0x0755);
+ else
+ dib7000p_write_word(state, 36,0x1f55);
+
+ dib7000p_write_tab(state, dib7000p_defaults);
+
dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+
return 0;
}
+static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+{
+ u16 tmp = 0;
+ tmp = dib7000p_read_word(state, 903);
+ dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
+ tmp = dib7000p_read_word(state, 900);
+ dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+}
+
static void dib7000p_restart_agc(struct dib7000p_state *state)
{
// P_restart_iqc & P_restart_agc
- dib7000p_write_word(state, 770, 0x0c00);
+ dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
dib7000p_write_word(state, 770, 0x0000);
}
-static void dib7000p_update_lna(struct dib7000p_state *state)
+static int dib7000p_update_lna(struct dib7000p_state *state)
{
- int i;
u16 dyn_gain;
// when there is no LNA to program return immediatly
- if (state->cfg.update_lna == NULL)
- return;
-
- for (i = 0; i < 5; i++) {
- // read dyn_gain here (because it is demod-dependent and not tuner)
+ if (state->cfg.update_lna) {
+ // read dyn_gain here (because it is demod-dependent and not fe)
dyn_gain = dib7000p_read_word(state, 394);
-
if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
dib7000p_restart_agc(state);
- msleep(5);
- } else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
+{
+ struct dibx000_agc_config *agc = NULL;
+ int i;
+ if (state->current_band == band && state->current_agc != NULL)
+ return 0;
+ state->current_band = band;
+
+ for (i = 0; i < state->cfg.agc_config_count; i++)
+ if (state->cfg.agc[i].band_caps & band) {
+ agc = &state->cfg.agc[i];
break;
+ }
+
+ if (agc == NULL) {
+ dprintk( "no valid AGC configuration found for band 0x%02x",band);
+ return -EINVAL;
}
+
+ state->current_agc = agc;
+
+ /* AGC */
+ dib7000p_write_word(state, 75 , agc->setup );
+ dib7000p_write_word(state, 76 , agc->inv_gain );
+ dib7000p_write_word(state, 77 , agc->time_stabiliz );
+ dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+ // Demod AGC loop configuration
+ dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+ dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
+
+ /* AGC continued */
+ dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+ state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+ if (state->wbd_ref != 0)
+ dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+ else
+ dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+ dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
+
+ dib7000p_write_word(state, 107, agc->agc1_max);
+ dib7000p_write_word(state, 108, agc->agc1_min);
+ dib7000p_write_word(state, 109, agc->agc2_max);
+ dib7000p_write_word(state, 110, agc->agc2_min);
+ dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+ dib7000p_write_word(state, 112, agc->agc1_pt3);
+ dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+ dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+ dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+ return 0;
}
-static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
- u16 tmp = 0;
- tmp = dib7000p_read_word(state, 903);
- dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
- tmp = dib7000p_read_word(state, 900);
- dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+ struct dib7000p_state *state = demod->demodulator_priv;
+ int ret = -1;
+ u8 *agc_state = &state->agc_state;
+ u8 agc_split;
+
+ switch (state->agc_state) {
+ case 0:
+ // set power-up level: interf+analog+AGC
+ dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+ dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+ dib7000p_pll_clk_cfg(state);
+
+ if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+ return -1;
+
+ ret = 7;
+ (*agc_state)++;
+ break;
+
+ case 1:
+ // AGC initialization
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000p_write_word(state, 78, 32768);
+ if (!state->current_agc->perform_agc_softsplit) {
+ /* we are using the wbd - so slow AGC startup */
+ /* force 0 split on WBD and restart AGC */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
+ (*agc_state)++;
+ ret = 5;
+ } else {
+ /* default AGC startup */
+ (*agc_state) = 4;
+ /* wait AGC rough lock time */
+ ret = 7;
+ }
+
+ dib7000p_restart_agc(state);
+ break;
+
+ case 2: /* fast split search path after 5sec */
+ dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
+ (*agc_state)++;
+ ret = 14;
+ break;
+
+ case 3: /* split search ended */
+ agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
+ dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
+
+ dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+ dib7000p_restart_agc(state);
+
+ dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+ (*agc_state)++;
+ ret = 5;
+ break;
+
+ case 4: /* LNA startup */
+ // wait AGC accurate lock time
+ ret = 7;
+
+ if (dib7000p_update_lna(state))
+ // wait only AGC rough lock time
+ ret = 5;
+ else // nothing was done, go to the next state
+ (*agc_state)++;
+ break;
+
+ case 5:
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+ (*agc_state)++;
+ break;
+ default:
+ break;
+ }
+ return ret;
}
-static void dib7000p_update_timf_freq(struct dib7000p_state *state)
+static void dib7000p_update_timf(struct dib7000p_state *state)
{
u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
- state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ state->timf = timf * 160 / (state->current_bandwidth / 50);
dib7000p_write_word(state, 23, (u16) (timf >> 16));
dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
- dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+ dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
+
}
-static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
{
- u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208;
+ u16 value, est[4];
+
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
/* nfft, guard, qam, alpha */
- dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ case /* 4K MODE */ 255: value |= (2 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib7000p_write_word(state, 0, value);
dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
- /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
- tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
- if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
- tmp |= (ch->vit_code_rate_hp << 1);
- else
- tmp |= (ch->vit_code_rate_lp << 1);
- dib7000p_write_word(state, 208, tmp);
+ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+ value = 0;
+ if (1 != 0)
+ value |= (1 << 6);
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
+ dib7000p_write_word(state, 208, value);
+
+ /* offset loop parameters */
+ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
+ dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
+ dib7000p_write_word(state, 29, 0x1273); // isi
+ dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
/* P_dvsy_sync_wait */
- switch (ch->nfft) {
- case 1: tmp = 256; break;
- case 2: tmp = 128; break;
- case 0:
- default: tmp = 64; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_2K:
+ default: value = 64; break;
}
- tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
- tmp <<= 4;
-
- /* deactive the possibility of diversity reception if extended interleave */
- /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
- if (ch->intlv_native || ch->nfft == 1)
- tmp |= (1 << 2) | (2 << 0);
- dib7000p_write_word(state, 207, tmp);
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
- dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
- dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073
- dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
- dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
+ /* deactive the possibility of diversity reception if extended interleaver */
+ state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
+ dib7000p_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->nqam) {
- case 2:
+ switch (ch->u.ofdm.constellation) {
+ case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
break;
- case 1:
+ case QAM_16:
est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
@@ -409,66 +802,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of
est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
break;
}
- for (tmp = 0; tmp < 4; tmp++)
- dib7000p_write_word(state, 187 + tmp, est[tmp]);
-
- // set power-up level: interf+analog+AGC
- dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
- dib7000p_set_adc_state(state, DIBX000_ADC_ON);
- dib7000p_pll_clk_cfg(state);
- msleep(7);
-
- // AGC initialization
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 1);
-
- dib7000p_restart_agc(state);
-
- // wait AGC rough lock time
- msleep(5);
-
- dib7000p_update_lna(state);
-
- // wait AGC accurate lock time
- msleep(7);
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 0);
+ for (value = 0; value < 4; value++)
+ dib7000p_write_word(state, 187 + value, est[value]);
}
-static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000p_state *state = demod->demodulator_priv;
- struct dibx000_ofdm_channel auto_ch;
- u32 value;
-
- INIT_OFDM_CHANNEL(&auto_ch);
- auto_ch.RF_kHz = ch->RF_kHz;
- auto_ch.Bw = ch->Bw;
- auto_ch.nqam = 2;
- auto_ch.guard = 0;
- auto_ch.nfft = 1;
- auto_ch.vit_alpha = 1;
- auto_ch.vit_select_hp = 1;
- auto_ch.vit_code_rate_hp = 2;
- auto_ch.vit_code_rate_lp = 3;
- auto_ch.vit_hrch = 0;
- auto_ch.intlv_native = 1;
-
- dib7000p_set_channel(state, &auto_ch, 7);
+ struct dvb_frontend_parameters schan;
+ u32 value, factor;
+
+ schan = *ch;
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_3_4;
+ schan.u.ofdm.hierarchy_information = 0;
+
+ dib7000p_set_channel(state, &schan, 7);
+
+ factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ if (factor >= 5000)
+ factor = 1;
+ else
+ factor = 6;
// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
- value = 30 * state->cfg.bw->internal;
+ value = 30 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.bw->internal;
+ value = 100 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
- value = 500 * state->cfg.bw->internal;
+ value = 500 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
value = dib7000p_read_word(state, 0);
- dib7000p_write_word(state, 0, (1 << 9) | value);
+ dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
dib7000p_read_word(state, 1284);
dib7000p_write_word(state, 0, (u16) value);
@@ -489,7 +861,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
+{
+ static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
+ static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
+ 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
+ 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
+ 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
+ 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
+ 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
+ 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
+ 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
+ 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
+ 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
+ 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
+ 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
+ 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
+ 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255};
+
+ u32 xtal = state->cfg.bw->xtal_hz / 1000;
+ int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
+ int k;
+ int coef_re[8],coef_im[8];
+ int bw_khz = bw;
+ u32 pha;
+
+ dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
+
+
+ if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
+ return;
+
+ bw_khz /= 100;
+
+ dib7000p_write_word(state, 142 ,0x0610);
+
+ for (k = 0; k < 8; k++) {
+ pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
+
+ if (pha==0) {
+ coef_re[k] = 256;
+ coef_im[k] = 0;
+ } else if(pha < 256) {
+ coef_re[k] = sine[256-(pha&0xff)];
+ coef_im[k] = sine[pha&0xff];
+ } else if (pha == 256) {
+ coef_re[k] = 0;
+ coef_im[k] = 256;
+ } else if (pha < 512) {
+ coef_re[k] = -sine[pha&0xff];
+ coef_im[k] = sine[256 - (pha&0xff)];
+ } else if (pha == 512) {
+ coef_re[k] = -256;
+ coef_im[k] = 0;
+ } else if (pha < 768) {
+ coef_re[k] = -sine[256-(pha&0xff)];
+ coef_im[k] = -sine[pha&0xff];
+ } else if (pha == 768) {
+ coef_re[k] = 0;
+ coef_im[k] = -256;
+ } else {
+ coef_re[k] = sine[pha&0xff];
+ coef_im[k] = -sine[256 - (pha&0xff)];
+ }
+
+ coef_re[k] *= notch[k];
+ coef_re[k] += (1<<14);
+ if (coef_re[k] >= (1<<24))
+ coef_re[k] = (1<<24) - 1;
+ coef_re[k] /= (1<<15);
+
+ coef_im[k] *= notch[k];
+ coef_im[k] += (1<<14);
+ if (coef_im[k] >= (1<<24))
+ coef_im[k] = (1<<24)-1;
+ coef_im[k] /= (1<<15);
+
+ dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
+
+ dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+ dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
+ dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+ }
+ dib7000p_write_word(state,143 ,0);
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000p_state *state = demod->demodulator_priv;
u16 tmp = 0;
@@ -505,7 +965,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
msleep(45);
/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
- dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+ tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
+ if (state->sfn_workaround_active) {
+ dprintk( "SFN workaround is active");
+ tmp |= (1 << 9);
+ dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
+ } else {
+ dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
+ }
+ dib7000p_write_word(state, 29, tmp);
// never achieved a lock with that bandwidth so far - wait for osc-freq to update
if (state->timf == 0)
@@ -515,28 +983,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
tmp = (6 << 8) | 0x80;
- switch (ch->nfft) {
- case 0: tmp |= (7 << 12); break;
- case 1: tmp |= (9 << 12); break;
- case 2: tmp |= (8 << 12); break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
+ case /* 4K MODE */ 255: tmp |= (8 << 12); break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
}
dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
tmp = (0 << 4);
- switch (ch->nfft) {
- case 0: tmp |= 0x6; break;
- case 1: tmp |= 0x8; break;
- case 2: tmp |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+ case /* 4K MODE */ 255: tmp |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
dib7000p_write_word(state, 32, tmp);
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
tmp = (0 << 4);
- switch (ch->nfft) {
- case 0: tmp |= 0x6; break;
- case 1: tmp |= 0x8; break;
- case 2: tmp |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+ case /* 4K MODE */ 255: tmp |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
dib7000p_write_word(state, 33, tmp);
@@ -552,131 +1023,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
// we achieved a lock - it's time to update the osc freq
if ((tmp >> 6) & 0x1)
- dib7000p_update_timf_freq(state);
+ dib7000p_update_timf(state);
+ if (state->cfg.spur_protect)
+ dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
return 0;
}
-static int dib7000p_init(struct dvb_frontend *demod)
+static int dib7000p_wakeup(struct dvb_frontend *demod)
{
- struct dibx000_agc_config *agc;
struct dib7000p_state *state = demod->demodulator_priv;
- int ret = 0;
-
- // Demodulator default configuration
- agc = state->cfg.agc;
-
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-
- /* AGC */
- ret |= dib7000p_write_word(state, 75 , agc->setup );
- ret |= dib7000p_write_word(state, 76 , agc->inv_gain );
- ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz );
- ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
-
- // Demod AGC loop configuration
- ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
- ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
-
- /* AGC continued */
- dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
- state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
- if (state->wbd_ref != 0)
- ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
- else
- ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
-
- ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
-
- ret |= dib7000p_write_word(state, 107, agc->agc1_max);
- ret |= dib7000p_write_word(state, 108, agc->agc1_min);
- ret |= dib7000p_write_word(state, 109, agc->agc2_max);
- ret |= dib7000p_write_word(state, 110, agc->agc2_min);
- ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
- ret |= dib7000p_write_word(state, 112, agc->agc1_pt3);
- ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
- ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
- ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
- /* disable power smoothing */
- ret |= dib7000p_write_word(state, 145, 0);
- ret |= dib7000p_write_word(state, 146, 0);
- ret |= dib7000p_write_word(state, 147, 0);
- ret |= dib7000p_write_word(state, 148, 0);
- ret |= dib7000p_write_word(state, 149, 0);
- ret |= dib7000p_write_word(state, 150, 0);
- ret |= dib7000p_write_word(state, 151, 0);
- ret |= dib7000p_write_word(state, 152, 0);
-
- // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
- ret |= dib7000p_write_word(state, 26 ,0x6680);
-
- // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
- ret |= dib7000p_write_word(state, 142,0x0410);
- // P_fft_freq_dir=1, P_fft_nb_to_cut=0
- ret |= dib7000p_write_word(state, 154,1 << 13);
- // P_pha3_thres, default 0x3000
- ret |= dib7000p_write_word(state, 168,0x0ccd);
- // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
- //ret |= dib7000p_write_word(state, 169,0x0010);
- // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
- ret |= dib7000p_write_word(state, 183,0x200f);
- // P_adp_regul_cnt=573, default: 410
- ret |= dib7000p_write_word(state, 187,0x023d);
- // P_adp_noise_cnt=
- ret |= dib7000p_write_word(state, 188,0x00a4);
- // P_adp_regul_ext
- ret |= dib7000p_write_word(state, 189,0x00a4);
- // P_adp_noise_ext
- ret |= dib7000p_write_word(state, 190,0x7ff0);
- // P_adp_fil
- ret |= dib7000p_write_word(state, 191,0x3ccc);
-
- ret |= dib7000p_write_word(state, 222,0x0010);
- // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
- ret |= dib7000p_write_word(state, 235,0x0062);
-
- // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
- if(state->cfg.tuner_is_baseband)
- ret |= dib7000p_write_word(state, 36,0x0755);
- else
- ret |= dib7000p_write_word(state, 36,0x1f55);
-
- // auto search configuration
- ret |= dib7000p_write_word(state, 2 ,0x0004);
- ret |= dib7000p_write_word(state, 3 ,0x1000);
-
- /* Equal Lock */
- ret |= dib7000p_write_word(state, 4 ,0x0814);
-
- ret |= dib7000p_write_word(state, 6 ,0x001b);
- ret |= dib7000p_write_word(state, 7 ,0x7740);
- ret |= dib7000p_write_word(state, 8 ,0x005b);
- ret |= dib7000p_write_word(state, 9 ,0x8d80);
- ret |= dib7000p_write_word(state, 10 ,0x01c9);
- ret |= dib7000p_write_word(state, 11 ,0xc380);
- ret |= dib7000p_write_word(state, 12 ,0x0000);
- ret |= dib7000p_write_word(state, 13 ,0x0080);
- ret |= dib7000p_write_word(state, 14 ,0x0000);
- ret |= dib7000p_write_word(state, 15 ,0x0090);
- ret |= dib7000p_write_word(state, 16 ,0x0001);
- ret |= dib7000p_write_word(state, 17 ,0xd4c0);
-
- // P_clk_cfg1
- ret |= dib7000p_write_word(state, 901, 0x0006);
-
- // P_divclksel=3 P_divbitsel=1
- ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
-
- // Tuner IO bank: max drive (14mA) + divout pads max drive
- ret |= dib7000p_write_word(state, 905, 0x2c8e);
-
- ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
- dib7000p_sad_calib(state);
-
- return ret;
+ return 0;
}
static int dib7000p_sleep(struct dvb_frontend *demod)
@@ -688,16 +1049,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod)
static int dib7000p_identify(struct dib7000p_state *st)
{
u16 value;
- dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n",
+ dprintk( "checking demod on I2C address: %d (%x)",
st->i2c_addr, st->i2c_addr);
if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
- dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value);
+ dprintk( "wrong Vendor ID (read=0x%x)",value);
return -EREMOTEIO;
}
if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
- dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value);
+ dprintk( "wrong Device ID (%x)",value);
return -EREMOTEIO;
}
@@ -767,41 +1128,48 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib7000p_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
+ int time;
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+ /* maybe the parameter has been changed */
+ state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, fep);
+ /* start up the AGC */
+ state->agc_state = 0;
+ do {
+ time = dib7000p_agc_startup(fe, fep);
+ if (time != -1)
+ msleep(time);
+ } while (time != -1);
+
if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
fep->u.ofdm.constellation == QAM_AUTO ||
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000p_autosearch_start(fe, &ch);
+ dib7000p_autosearch_start(fe, fep);
do {
msleep(1);
found = dib7000p_autosearch_is_irq(fe);
} while (found == 0 && i--);
- dprintk("autosearch returns: %d\n",found);
+ dprintk("autosearch returns: %d",found);
if (found == 0 || found == 1)
return 0; // no channel found
dib7000p_get_frontend(fe, fep);
- FEP2DIB(fep, &ch);
}
/* make this a config parameter */
dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib7000p_tune(fe, &ch);
+ return dib7000p_tune(fe, fep);
}
static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -879,7 +1247,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
if (i2c_transfer(i2c_adap, msg, 2) == 2)
if (rx[0] == 0x01 && rx[1] == 0xb3) {
- dprintk("-D- DiB7000PC detected\n");
+ dprintk("-D- DiB7000PC detected");
return 1;
}
@@ -887,11 +1255,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
if (i2c_transfer(i2c_adap, msg, 2) == 2)
if (rx[0] == 0x01 && rx[1] == 0xb3) {
- dprintk("-D- DiB7000PC detected\n");
+ dprintk("-D- DiB7000PC detected");
return 1;
}
- dprintk("-D- DiB7000PC not detected\n");
+ dprintk("-D- DiB7000PC not detected");
return 0;
}
EXPORT_SYMBOL(dib7000pc_detection);
@@ -929,7 +1297,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
/* set new i2c address and force divstart */
dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
- dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
}
for (k = 0; k < no_of_demods; k++) {
@@ -1000,7 +1368,7 @@ static struct dvb_frontend_ops dib7000p_ops = {
.release = dib7000p_release,
- .init = dib7000p_init,
+ .init = dib7000p_wakeup,
.sleep = dib7000p_sleep,
.set_frontend = dib7000p_set_frontend,
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 79465cf1aced..eefcac8b5244 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -9,6 +9,7 @@ struct dib7000p_config {
u8 tuner_is_baseband;
int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+ u8 agc_config_count;
struct dibx000_agc_config *agc;
struct dibx000_bandwidth_config *bw;
@@ -27,20 +28,19 @@ struct dib7000p_config {
u8 quartz_direct;
+ u8 spur_protect;
+
int (*agc_control) (struct dvb_frontend *, u8 before);
};
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+
extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-
-/* TODO
-extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
-extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
-extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
-extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
-*/
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
#endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index a1df604366c3..5e17275afd25 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -111,6 +111,8 @@ struct dibx000_bandwidth_config {
u32 ifreq;
u32 timf;
+
+ u32 xtal_hz;
};
enum dibx000_adc_states {
@@ -122,56 +124,17 @@ enum dibx000_adc_states {
DIBX000_VBG_DISABLE,
};
-#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
+#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
(v) == BANDWIDTH_7_MHZ ? 7000 : \
(v) == BANDWIDTH_6_MHZ ? 6000 : 8000 )
/* Chip output mode. */
-#define OUTMODE_HIGH_Z 0
-#define OUTMODE_MPEG2_PAR_GATED_CLK 1
-#define OUTMODE_MPEG2_PAR_CONT_CLK 2
-#define OUTMODE_MPEG2_SERIAL 7
-#define OUTMODE_DIVERSITY 4
-#define OUTMODE_MPEG2_FIFO 5
-
-/* I hope I can get rid of the following kludge in the near future */
-struct dibx000_ofdm_channel {
- u32 RF_kHz;
- u8 Bw;
- s16 nfft;
- s16 guard;
- s16 nqam;
- s16 vit_hrch;
- s16 vit_select_hp;
- s16 vit_alpha;
- s16 vit_code_rate_hp;
- s16 vit_code_rate_lp;
- u8 intlv_native;
-};
-
-#define FEP2DIB(fep,ch) \
- (ch)->RF_kHz = (fep)->frequency / 1000; \
- (ch)->Bw = (fep)->u.ofdm.bandwidth; \
- (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
- (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
- (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
- (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
- (ch)->vit_select_hp = 1; \
- (ch)->vit_alpha = 1; \
- (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
- (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
- (ch)->intlv_native = 1;
-
-#define INIT_OFDM_CHANNEL(ch) do {\
- (ch)->Bw = 0; \
- (ch)->nfft = -1; \
- (ch)->guard = -1; \
- (ch)->nqam = -1; \
- (ch)->vit_hrch = -1; \
- (ch)->vit_select_hp = -1; \
- (ch)->vit_alpha = -1; \
- (ch)->vit_code_rate_hp = -1; \
- (ch)->vit_code_rate_lp = -1; \
-} while (0)
+#define OUTMODE_HIGH_Z 0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK 2
+#define OUTMODE_MPEG2_SERIAL 7
+#define OUTMODE_DIVERSITY 4
+#define OUTMODE_MPEG2_FIFO 5
+#define OUTMODE_ANALOG_ADC 6
#endif
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 5f96ffda91ad..8c8d7342d0b3 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -24,6 +24,59 @@
#include "dvb-pll.h"
+struct dvb_pll_priv {
+ /* pll number */
+ int nr;
+
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#define DVB_PLL_MAX 64
+
+static unsigned int dvb_pll_devcount;
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 };
+module_param_array(input, int, NULL, 0644);
+MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)");
+
+static unsigned int id[DVB_PLL_MAX] =
+ { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
+module_param_array(id, int, NULL, 0644);
+MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
+
+/* ----------------------------------------------------------- */
+
+struct dvb_pll_desc {
+ char *name;
+ u32 min;
+ u32 max;
+ u32 iffreq;
+ void (*set)(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params);
+ u8 *initdata;
+ u8 *sleepdata;
+ int count;
+ struct {
+ u32 limit;
+ u32 stepsize;
+ u8 config;
+ u8 cb;
+ } entries[12];
+};
+
/* ----------------------------------------------------------- */
/* descriptions */
@@ -38,7 +91,13 @@
0x50 = AGC Take over point = 103 dBuV */
static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+/* 0x04 = 166.67 kHz divider
+
+ 0x80 = AGC Time constant 50ms Iagc = 9 uA
+ 0x20 = AGC Take over point = 112 dBuV */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
.name = "Thomson dtt7579",
.min = 177000000,
.max = 858000000,
@@ -52,9 +111,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
{ 999999999, 166667, 0xf4, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
-struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
.name = "Thomson dtt7610",
.min = 44000000,
.max = 958000000,
@@ -66,19 +124,19 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
{ 999999999, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
-static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (BANDWIDTH_7_MHZ == bandwidth)
+ if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
buf[3] |= 0x10;
}
-struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
.name = "Thomson dtt759x",
.min = 177000000,
.max = 896000000,
- .setbw = thomson_dtt759x_bw,
+ .set = thomson_dtt759x_bw,
.iffreq= 36166667,
.sleepdata = (u8[]){ 2, 0x84, 0x03 },
.count = 5,
@@ -90,9 +148,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
{ 999999999, 166667, 0xfc, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
-struct dvb_pll_desc dvb_pll_lg_z201 = {
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
.name = "LG z201",
.min = 174000000,
.max = 862000000,
@@ -107,9 +164,8 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
{ 999999999, 166667, 0xfc, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_lg_z201);
-struct dvb_pll_desc dvb_pll_microtune_4042 = {
+static struct dvb_pll_desc dvb_pll_microtune_4042 = {
.name = "Microtune 4042 FI5",
.min = 57000000,
.max = 858000000,
@@ -121,9 +177,8 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
{ 999999999, 62500, 0x8e, 0x31 },
},
};
-EXPORT_SYMBOL(dvb_pll_microtune_4042);
-struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
.name = "Thomson dtt761x",
.min = 57000000,
@@ -137,9 +192,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
{ 999999999, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
-struct dvb_pll_desc dvb_pll_unknown_1 = {
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
.min = 174000000,
.max = 862000000,
@@ -157,12 +211,11 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
{ 999999999, 166667, 0xfc, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_unknown_1);
/* Infineon TUA6010XS
* used in Thomson Cable Tuner
*/
-struct dvb_pll_desc dvb_pll_tua6010xs = {
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
.name = "Infineon TUA6010XS",
.min = 44250000,
.max = 858000000,
@@ -174,10 +227,9 @@ struct dvb_pll_desc dvb_pll_tua6010xs = {
{ 999999999, 62500, 0x8e, 0x85 },
},
};
-EXPORT_SYMBOL(dvb_pll_tua6010xs);
/* Panasonic env57h1xd5 (some Philips PLL ?) */
-struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
.name = "Panasonic ENV57H1XD5",
.min = 44250000,
.max = 858000000,
@@ -190,23 +242,24 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = {
{ 999999999, 166667, 0xc2, 0xa4 },
},
};
-EXPORT_SYMBOL(dvb_pll_env57h1xd5);
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
-static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_tda665x = {
+static struct dvb_pll_desc dvb_pll_tda665x = {
.name = "Philips TDA6650/TDA6651",
.min = 44250000,
.max = 858000000,
- .setbw = tda665x_bw,
+ .set = tda665x_bw,
.iffreq= 36166667,
+ .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
.count = 12,
.entries = {
{ 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
@@ -223,36 +276,35 @@ struct dvb_pll_desc dvb_pll_tda665x = {
{ 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
}
};
-EXPORT_SYMBOL(dvb_pll_tda665x);
/* Infineon TUA6034
* used in LG TDTP E102P
*/
-static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (BANDWIDTH_7_MHZ != bandwidth)
+ if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_tua6034 = {
+static struct dvb_pll_desc dvb_pll_tua6034 = {
.name = "Infineon TUA6034",
.min = 44250000,
.max = 858000000,
.iffreq= 36166667,
.count = 3,
- .setbw = tua6034_bw,
+ .set = tua6034_bw,
.entries = {
{ 174500000, 62500, 0xce, 0x01 },
{ 230000000, 62500, 0xce, 0x02 },
{ 999999999, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
* used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
.name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
@@ -265,23 +317,26 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
{ 999999999, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
*/
-static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+ params->frequency >= 158870000)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_fmd1216me = {
+static struct dvb_pll_desc dvb_pll_fmd1216me = {
.name = "Philips FMD1216ME",
.min = 50870000,
.max = 858000000,
.iffreq= 36125000,
- .setbw = fmd1216me_bw,
+ .set = fmd1216me_bw,
+ .initdata = tua603x_agc112,
+ .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
.count = 7,
.entries = {
{ 143870000, 166667, 0xbc, 0x41 },
@@ -293,23 +348,23 @@ struct dvb_pll_desc dvb_pll_fmd1216me = {
{ 999999999, 166667, 0xfc, 0x44 },
}
};
-EXPORT_SYMBOL(dvb_pll_fmd1216me);
/* ALPS TDED4
* used in Nebula-Cards and USB boxes
*/
-static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x04;
}
-struct dvb_pll_desc dvb_pll_tded4 = {
+static struct dvb_pll_desc dvb_pll_tded4 = {
.name = "ALPS TDED4",
.min = 47000000,
.max = 863000000,
.iffreq= 36166667,
- .setbw = tded4_bw,
+ .set = tded4_bw,
.count = 4,
.entries = {
{ 153000000, 166667, 0x85, 0x01 },
@@ -318,12 +373,11 @@ struct dvb_pll_desc dvb_pll_tded4 = {
{ 999999999, 166667, 0x85, 0x88 },
}
};
-EXPORT_SYMBOL(dvb_pll_tded4);
/* ALPS TDHU2
* used in AverTVHD MCE A180
*/
-struct dvb_pll_desc dvb_pll_tdhu2 = {
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
.name = "ALPS TDHU2",
.min = 54000000,
.max = 864000000,
@@ -336,16 +390,48 @@ struct dvb_pll_desc dvb_pll_tdhu2 = {
{ 999999999, 62500, 0x85, 0x88 },
}
};
-EXPORT_SYMBOL(dvb_pll_tdhu2);
/* Philips TUV1236D
* used in ATI HDTV Wonder
*/
-struct dvb_pll_desc dvb_pll_tuv1236d = {
+static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ unsigned int new_rf = input[priv->nr];
+
+ if ((new_rf == 0) || (new_rf > 2)) {
+ switch (params->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ new_rf = 1;
+ break;
+ case VSB_8:
+ default:
+ new_rf = 2;
+ }
+ }
+
+ switch (new_rf) {
+ case 1:
+ buf[3] |= 0x08;
+ break;
+ case 2:
+ buf[3] &= ~0x08;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: unhandled rf input selection: %d",
+ __FUNCTION__, new_rf);
+ }
+}
+
+static struct dvb_pll_desc dvb_pll_tuv1236d = {
.name = "Philips TUV1236D",
.min = 54000000,
.max = 864000000,
.iffreq= 44000000,
+ .set = tuv1236d_rf,
.count = 3,
.entries = {
{ 157250000, 62500, 0xc6, 0x41 },
@@ -353,12 +439,11 @@ struct dvb_pll_desc dvb_pll_tuv1236d = {
{ 999999999, 62500, 0xc6, 0x44 },
},
};
-EXPORT_SYMBOL(dvb_pll_tuv1236d);
/* Samsung TBMV30111IN / TBMV30712IN1
* used in Air2PC ATSC - 2nd generation (nxt2002)
*/
-struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
.name = "Samsung TBMV30111IN / TBMV30712IN1",
.min = 54000000,
.max = 860000000,
@@ -373,12 +458,11 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = {
{ 999999999, 166667, 0xfc, 0x02 },
}
};
-EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
/*
* Philips SD1878 Tuner.
*/
-struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
.name = "Philips SD1878",
.min = 950000,
.max = 2150000,
@@ -391,19 +475,19 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
{ 2150000, 500, 0xc4, 0xc0},
},
};
-EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
/*
* Philips TD1316 Tuner.
*/
-static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+static void td1316_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
u8 band;
/* determine band */
- if (freq < 161000000)
+ if (params->frequency < 161000000)
band = 1;
- else if (freq < 444000000)
+ else if (params->frequency < 444000000)
band = 2;
else
band = 4;
@@ -411,16 +495,16 @@ static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
buf[3] |= band;
/* setup PLL filter */
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 1 << 3;
}
-struct dvb_pll_desc dvb_pll_philips_td1316 = {
+static struct dvb_pll_desc dvb_pll_philips_td1316 = {
.name = "Philips TD1316",
.min = 87000000,
.max = 895000000,
.iffreq= 36166667,
- .setbw = td1316_bw,
+ .set = td1316_bw,
.count = 9,
.entries = {
{ 93834000, 166667, 0xca, 0x60},
@@ -434,10 +518,9 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = {
{ 858834000, 166667, 0xca, 0xe0},
},
};
-EXPORT_SYMBOL(dvb_pll_philips_td1316);
/* FE6600 used on DViCO Hybrid */
-struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
.name = "Thomson FE6600",
.min = 44250000,
.max = 858000000,
@@ -450,19 +533,20 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
{ 999999999, 166667, 0xf4, 0x18 },
}
};
-EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
-static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[2] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_opera1 = {
+static struct dvb_pll_desc dvb_pll_opera1 = {
.name = "Opera Tuner",
.min = 900000,
.max = 2250000,
.iffreq= 0,
- .setbw = opera1_bw,
+ .set = opera1_bw,
.count = 8,
.entries = {
{ 1064000, 500, 0xe5, 0xc6 },
@@ -475,57 +559,89 @@ struct dvb_pll_desc dvb_pll_opera1 = {
{ 2250000, 500, 0xe5, 0xc4 },
}
};
-EXPORT_SYMBOL(dvb_pll_opera1);
-struct dvb_pll_priv {
- /* i2c details */
- int pll_i2c_address;
- struct i2c_adapter *i2c;
+/* Philips FCV1236D
+ */
+static struct dvb_pll_desc dvb_pll_fcv1236d = {
+/* Bit_0: RF Input select
+ * Bit_1: 0=digital, 1=analog
+ */
+ .name = "Philips FCV1236D",
+ .min = 53000000,
+ .max = 803000000,
+ .iffreq= 44000000,
+ .count = 3,
+ .entries = {
+ { 159000000, 62500, 0x8e, 0xa0 },
+ { 453000000, 62500, 0x8e, 0x90 },
+ { 999999999, 62500, 0x8e, 0x30 },
+ },
+};
- /* the PLL descriptor */
- struct dvb_pll_desc *pll_desc;
+/* ----------------------------------------------------------- */
- /* cached frequency/bandwidth */
- u32 frequency;
- u32 bandwidth;
+static struct dvb_pll_desc *pll_list[] = {
+ [DVB_PLL_UNDEFINED] = NULL,
+ [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579,
+ [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x,
+ [DVB_PLL_THOMSON_DTT7610] = &dvb_pll_thomson_dtt7610,
+ [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201,
+ [DVB_PLL_MICROTUNE_4042] = &dvb_pll_microtune_4042,
+ [DVB_PLL_THOMSON_DTT761X] = &dvb_pll_thomson_dtt761x,
+ [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1,
+ [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs,
+ [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5,
+ [DVB_PLL_TUA6034] = &dvb_pll_tua6034,
+ [DVB_PLL_LG_TDVS_H06XF] = &dvb_pll_lg_tdvs_h06xf,
+ [DVB_PLL_TDA665X] = &dvb_pll_tda665x,
+ [DVB_PLL_FMD1216ME] = &dvb_pll_fmd1216me,
+ [DVB_PLL_TDED4] = &dvb_pll_tded4,
+ [DVB_PLL_TUV1236D] = &dvb_pll_tuv1236d,
+ [DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
+ [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
+ [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+ [DVB_PLL_PHILIPS_TD1316] = &dvb_pll_philips_td1316,
+ [DVB_PLL_THOMSON_FE6600] = &dvb_pll_thomson_fe6600,
+ [DVB_PLL_OPERA1] = &dvb_pll_opera1,
+ [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d,
};
/* ----------------------------------------------------------- */
/* code */
-static int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
- u32 freq, int bandwidth)
+static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ struct dvb_pll_desc *desc = priv->pll_desc;
u32 div;
int i;
- if (freq != 0 && (freq < desc->min || freq > desc->max))
- return -EINVAL;
+ if (params->frequency != 0 && (params->frequency < desc->min ||
+ params->frequency > desc->max))
+ return -EINVAL;
for (i = 0; i < desc->count; i++) {
- if (freq > desc->entries[i].limit)
+ if (params->frequency > desc->entries[i].limit)
continue;
break;
}
+
if (debug)
- printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
- desc->name, freq, bandwidth, i, desc->count);
+ printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+ params->frequency, i, desc->count);
if (i == desc->count)
return -EINVAL;
- div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
- desc->entries[i].stepsize;
+ div = (params->frequency + desc->iffreq +
+ desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
buf[0] = div >> 8;
buf[1] = div & 0xff;
buf[2] = desc->entries[i].config;
buf[3] = desc->entries[i].cb;
- if (desc->setbw)
- desc->setbw(buf, freq, bandwidth);
+ if (desc->set)
+ desc->set(fe, buf, params);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -534,7 +650,6 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
// calculate the frequency we set it to
return (div * desc->entries[i].stepsize) - desc->iffreq;
}
-EXPORT_SYMBOL(dvb_pll_configure);
static int dvb_pll_release(struct dvb_frontend *fe)
{
@@ -578,18 +693,12 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
{ .addr = priv->pll_i2c_address, .flags = 0,
.buf = buf, .len = sizeof(buf) };
int result;
- u32 bandwidth = 0, frequency = 0;
+ u32 frequency = 0;
if (priv->i2c == NULL)
return -EINVAL;
- // DVBT bandwidth only just now
- if (fe->ops.info.type == FE_OFDM) {
- bandwidth = params->u.ofdm.bandwidth;
- }
-
- if ((result = dvb_pll_configure(priv->pll_desc, buf,
- params->frequency, bandwidth)) < 0)
+ if ((result = dvb_pll_configure(fe, buf, params)) < 0)
return result;
else
frequency = result;
@@ -601,7 +710,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
}
priv->frequency = frequency;
- priv->bandwidth = bandwidth;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
}
@@ -612,18 +721,12 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
{
struct dvb_pll_priv *priv = fe->tuner_priv;
int result;
- u32 bandwidth = 0, frequency = 0;
+ u32 frequency = 0;
if (buf_len < 5)
return -EINVAL;
- // DVBT bandwidth only just now
- if (fe->ops.info.type == FE_OFDM) {
- bandwidth = params->u.ofdm.bandwidth;
- }
-
- if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
- params->frequency, bandwidth)) < 0)
+ if ((result = dvb_pll_configure(fe, buf+1, params)) < 0)
return result;
else
frequency = result;
@@ -631,7 +734,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
buf[0] = priv->pll_i2c_address;
priv->frequency = frequency;
- priv->bandwidth = bandwidth;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 5;
}
@@ -687,13 +790,22 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc)
+ unsigned int pll_desc_id)
{
u8 b1 [] = { 0 };
struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
.buf = b1, .len = 1 };
struct dvb_pll_priv *priv = NULL;
int ret;
+ struct dvb_pll_desc *desc;
+
+ if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
+ (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
+ pll_desc_id = id[dvb_pll_devcount];
+
+ BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+ desc = pll_list[pll_desc_id];
if (i2c != NULL) {
if (fe->ops.i2c_gate_ctrl)
@@ -713,6 +825,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
priv->pll_i2c_address = pll_addr;
priv->i2c = i2c;
priv->pll_desc = desc;
+ priv->nr = dvb_pll_devcount++;
memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
sizeof(struct dvb_tuner_ops));
@@ -720,13 +833,37 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
strncpy(fe->ops.tuner_ops.info.name, desc->name,
sizeof(fe->ops.tuner_ops.info.name));
fe->ops.tuner_ops.info.frequency_min = desc->min;
- fe->ops.tuner_ops.info.frequency_min = desc->max;
+ fe->ops.tuner_ops.info.frequency_max = desc->max;
if (!desc->initdata)
fe->ops.tuner_ops.init = NULL;
if (!desc->sleepdata)
fe->ops.tuner_ops.sleep = NULL;
fe->tuner_priv = priv;
+
+ if ((debug) || (id[priv->nr] == pll_desc_id)) {
+ printk("dvb-pll[%d]", priv->nr);
+ if (i2c != NULL)
+ printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+ printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
+ id[priv->nr] == pll_desc_id ?
+ "insmod option" : "autodetected");
+ }
+ if ((debug) || (input[priv->nr] > 0)) {
+ printk("dvb-pll[%d]", priv->nr);
+ if (i2c != NULL)
+ printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+ printk(": tuner rf input will be ");
+ switch (input[priv->nr]) {
+ case 0:
+ printk("autoselected\n");
+ break;
+ default:
+ printk("set to input %d (insmod option)\n",
+ input[priv->nr]);
+ }
+ }
+
return fe;
}
EXPORT_SYMBOL(dvb_pll_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 5209f46f0893..e93a8104052b 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -8,50 +8,29 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-struct dvb_pll_desc {
- char *name;
- u32 min;
- u32 max;
- u32 iffreq;
- void (*setbw)(u8 *buf, u32 freq, int bandwidth);
- u8 *initdata;
- u8 *sleepdata;
- int count;
- struct {
- u32 limit;
- u32 stepsize;
- u8 config;
- u8 cb;
- } entries[12];
-};
-
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
-extern struct dvb_pll_desc dvb_pll_lg_z201;
-extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
-extern struct dvb_pll_desc dvb_pll_unknown_1;
-
-extern struct dvb_pll_desc dvb_pll_tua6010xs;
-extern struct dvb_pll_desc dvb_pll_env57h1xd5;
-extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
-extern struct dvb_pll_desc dvb_pll_tda665x;
-extern struct dvb_pll_desc dvb_pll_fmd1216me;
-extern struct dvb_pll_desc dvb_pll_tded4;
-
-extern struct dvb_pll_desc dvb_pll_tuv1236d;
-extern struct dvb_pll_desc dvb_pll_tdhu2;
-extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
-extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
-extern struct dvb_pll_desc dvb_pll_philips_td1316;
-
-extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-extern struct dvb_pll_desc dvb_pll_opera1;
-
-extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
- u32 freq, int bandwidth);
+#define DVB_PLL_UNDEFINED 0
+#define DVB_PLL_THOMSON_DTT7579 1
+#define DVB_PLL_THOMSON_DTT759X 2
+#define DVB_PLL_THOMSON_DTT7610 3
+#define DVB_PLL_LG_Z201 4
+#define DVB_PLL_MICROTUNE_4042 5
+#define DVB_PLL_THOMSON_DTT761X 6
+#define DVB_PLL_UNKNOWN_1 7
+#define DVB_PLL_TUA6010XS 8
+#define DVB_PLL_ENV57H1XD5 9
+#define DVB_PLL_TUA6034 10
+#define DVB_PLL_LG_TDVS_H06XF 11
+#define DVB_PLL_TDA665X 12
+#define DVB_PLL_FMD1216ME 13
+#define DVB_PLL_TDED4 14
+#define DVB_PLL_TUV1236D 15
+#define DVB_PLL_TDHU2 16
+#define DVB_PLL_SAMSUNG_TBMV 17
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
+#define DVB_PLL_PHILIPS_TD1316 19
+#define DVB_PLL_THOMSON_FE6600 20
+#define DVB_PLL_OPERA1 21
+#define DVB_PLL_FCV1236D 22
/**
* Attach a dvb-pll to the supplied frontend structure.
@@ -59,19 +38,19 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
* @param fe Frontend to attach to.
* @param pll_addr i2c address of the PLL (if used).
* @param i2c i2c adapter to use (set to NULL if not used).
- * @param desc dvb_pll_desc to use.
+ * @param pll_desc_id dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc);
+ unsigned int pll_desc_id);
#else
static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc)
+ unsigned int pll_desc_id)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
return NULL;
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 6271b1e7f6ab..fed09dfb2b7c 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
index c967148a5945..684c8ec166cb 100644
--- a/drivers/media/dvb/frontends/isl6421.c
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1aeacb1c4af7..443d9045d4c9 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index e25286e2d431..bdc9fa88b86a 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index 2d2f58c26226..76f935d9755a 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c
index 450fad8d9b65..1305b0e63ce5 100644
--- a/drivers/media/dvb/frontends/mt2060.c
+++ b/drivers/media/dvb/frontends/mt2060.c
@@ -22,7 +22,6 @@
/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/dvb/frontend.h>
#include <linux/i2c.h>
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c
new file mode 100644
index 000000000000..4b93931de4e1
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.c
@@ -0,0 +1,314 @@
+/*
+ * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2006 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 <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2131.h"
+#include "mt2131_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
+
+static u8 mt2131_config1[] = {
+ 0x01,
+ 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
+ 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
+ 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
+ 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
+};
+
+static u8 mt2131_config2[] = {
+ 0x10,
+ 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
+};
+
+static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address, .flags = 0,
+ .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+ .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "mt2131 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
+ .buf = buf, .len = 2 };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mt2131 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
+{
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = buf, .len = len };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",
+ (int)len);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mt2131_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mt2131_priv *priv;
+ int ret=0, i;
+ u32 freq;
+ u8 if_band_center;
+ u32 f_lo1, f_lo2;
+ u32 div1, num1, div2, num2;
+ u8 b[8];
+ u8 lockval = 0;
+
+ priv = fe->tuner_priv;
+ if (fe->ops.info.type == FE_OFDM)
+ priv->bandwidth = params->u.ofdm.bandwidth;
+ else
+ priv->bandwidth = 0;
+
+ freq = params->frequency / 1000; // Hz -> kHz
+ dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq);
+
+ f_lo1 = freq + MT2131_IF1 * 1000;
+ f_lo1 = (f_lo1 / 250) * 250;
+ f_lo2 = f_lo1 - freq - MT2131_IF2;
+
+ priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000,
+
+ /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
+ num1 = f_lo1 * 64 / (MT2131_FREF / 128);
+ div1 = num1 / 8192;
+ num1 &= 0x1fff;
+
+ /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
+ num2 = f_lo2 * 64 / (MT2131_FREF / 128);
+ div2 = num2 / 8192;
+ num2 &= 0x1fff;
+
+ if (freq <= 82500) if_band_center = 0x00; else
+ if (freq <= 137500) if_band_center = 0x01; else
+ if (freq <= 192500) if_band_center = 0x02; else
+ if (freq <= 247500) if_band_center = 0x03; else
+ if (freq <= 302500) if_band_center = 0x04; else
+ if (freq <= 357500) if_band_center = 0x05; else
+ if (freq <= 412500) if_band_center = 0x06; else
+ if (freq <= 467500) if_band_center = 0x07; else
+ if (freq <= 522500) if_band_center = 0x08; else
+ if (freq <= 577500) if_band_center = 0x09; else
+ if (freq <= 632500) if_band_center = 0x0A; else
+ if (freq <= 687500) if_band_center = 0x0B; else
+ if (freq <= 742500) if_band_center = 0x0C; else
+ if (freq <= 797500) if_band_center = 0x0D; else
+ if (freq <= 852500) if_band_center = 0x0E; else
+ if (freq <= 907500) if_band_center = 0x0F; else
+ if (freq <= 962500) if_band_center = 0x10; else
+ if (freq <= 1017500) if_band_center = 0x11; else
+ if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
+
+ b[0] = 1;
+ b[1] = (num1 >> 5) & 0xFF;
+ b[2] = (num1 & 0x1F);
+ b[3] = div1;
+ b[4] = (num2 >> 5) & 0xFF;
+ b[5] = num2 & 0x1F;
+ b[6] = div2;
+
+ dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
+ dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center);
+ dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
+ dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n",
+ (int)div1, (int)num1, (int)div2, (int)num2);
+ dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
+ (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
+ (int)b[6]);
+
+ ret = mt2131_writeregs(priv,b,7);
+ if (ret < 0)
+ return ret;
+
+ mt2131_writereg(priv, 0x0b, if_band_center);
+
+ /* Wait for lock */
+ i = 0;
+ do {
+ mt2131_readreg(priv, 0x08, &lockval);
+ if ((lockval & 0x88) == 0x88)
+ break;
+ msleep(4);
+ i++;
+ } while (i < 10);
+
+ return ret;
+}
+
+static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __FUNCTION__);
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __FUNCTION__);
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ u8 lock_status = 0;
+ u8 afc_status = 0;
+
+ *status = 0;
+
+ mt2131_readreg(priv, 0x08, &lock_status);
+ if ((lock_status & 0x88) == 0x88)
+ *status = TUNER_STATUS_LOCKED;
+
+ mt2131_readreg(priv, 0x09, &afc_status);
+ dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
+ __FUNCTION__, lock_status, afc_status);
+
+ return 0;
+}
+
+static int mt2131_init(struct dvb_frontend *fe)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ int ret;
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ if ((ret = mt2131_writeregs(priv, mt2131_config1,
+ sizeof(mt2131_config1))) < 0)
+ return ret;
+
+ mt2131_writereg(priv, 0x0b, 0x09);
+ mt2131_writereg(priv, 0x15, 0x47);
+ mt2131_writereg(priv, 0x07, 0xf2);
+ mt2131_writereg(priv, 0x0b, 0x01);
+
+ if ((ret = mt2131_writeregs(priv, mt2131_config2,
+ sizeof(mt2131_config2))) < 0)
+ return ret;
+
+ return ret;
+}
+
+static int mt2131_release(struct dvb_frontend *fe)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mt2131_tuner_ops = {
+ .info = {
+ .name = "Microtune MT2131",
+ .frequency_min = 48000000,
+ .frequency_max = 860000000,
+ .frequency_step = 50000,
+ },
+
+ .release = mt2131_release,
+ .init = mt2131_init,
+
+ .set_params = mt2131_set_params,
+ .get_frequency = mt2131_get_frequency,
+ .get_bandwidth = mt2131_get_bandwidth,
+ .get_status = mt2131_get_status
+};
+
+struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mt2131_config *cfg, u16 if1)
+{
+ struct mt2131_priv *priv = NULL;
+ u8 id = 0;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->bandwidth = 6000000; /* 6MHz */
+ priv->i2c = i2c;
+
+ if (mt2131_readreg(priv, 0, &id) != 0) {
+ kfree(priv);
+ return NULL;
+ }
+ if ( (id != 0x3E) && (id != 0x3F) ) {
+ printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
+ cfg->i2c_address);
+ kfree(priv);
+ return NULL;
+ }
+
+ printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
+ cfg->i2c_address);
+ memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(mt2131_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h
new file mode 100644
index 000000000000..1e4ffe7dc8c8
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.h
@@ -0,0 +1,54 @@
+/*
+ * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2006 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 __MT2131_H__
+#define __MT2131_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2131_config {
+ u8 i2c_address;
+ 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))
+extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mt2131_config *cfg,
+ u16 if1);
+#else
+static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mt2131_config *cfg,
+ u16 if1)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MT2131 */
+
+#endif /* __MT2131_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h
new file mode 100644
index 000000000000..e930759c2c00
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131_priv.h
@@ -0,0 +1,49 @@
+/*
+ * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2006 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 __MT2131_PRIV_H__
+#define __MT2131_PRIV_H__
+
+/* Regs */
+#define MT2131_PWR 0x07
+#define MT2131_UPC_1 0x0b
+#define MT2131_AGC_RL 0x10
+#define MT2131_MISC_2 0x15
+
+/* frequency values in KHz */
+#define MT2131_IF1 1220
+#define MT2131_IF2 44000
+#define MT2131_FREF 16000
+
+struct mt2131_priv {
+ struct mt2131_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif /* __MT2131_PRIV_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c
new file mode 100644
index 000000000000..03fe8265745f
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2266.c
@@ -0,0 +1,287 @@
+/*
+ * Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ * Copyright (c) 2007 Olivier DANET <odanet@caramail.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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+#include "mt2266.h"
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV 0
+#define REG_TUNE 1
+#define REG_BAND 6
+#define REG_BANDWIDTH 8
+#define REG_LOCK 0x12
+
+#define PART_REV 0x85
+
+struct mt2266_priv {
+ struct mt2266_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "MT2266 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Writes a single register
+static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+ };
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "MT2266 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
+{
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+ };
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Initialisation sequences
+static u8 mt2266_init1[] = {
+ REG_TUNE,
+ 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
+
+static u8 mt2266_init2[] = {
+ 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
+ 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
+
+static u8 mt2266_init_8mhz[] = {
+ REG_BANDWIDTH,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
+
+static u8 mt2266_init_7mhz[] = {
+ REG_BANDWIDTH,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+
+static u8 mt2266_init_6mhz[] = {
+ REG_BANDWIDTH,
+ 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+
+#define FREF 30000 // Quartz oscillator 30 MHz
+
+static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mt2266_priv *priv;
+ int ret=0;
+ u32 freq;
+ u32 tune;
+ u8 lnaband;
+ u8 b[10];
+ int i;
+
+ priv = fe->tuner_priv;
+
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0xff);
+
+ freq = params->frequency / 1000; // Hz -> kHz
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->frequency = freq * 1000;
+ tune=2 * freq * (8192/16) / (FREF/16);
+
+ if (freq <= 495000) lnaband = 0xEE; else
+ if (freq <= 525000) lnaband = 0xDD; else
+ if (freq <= 550000) lnaband = 0xCC; else
+ if (freq <= 580000) lnaband = 0xBB; else
+ if (freq <= 605000) lnaband = 0xAA; else
+ if (freq <= 630000) lnaband = 0x99; else
+ if (freq <= 655000) lnaband = 0x88; else
+ if (freq <= 685000) lnaband = 0x77; else
+ if (freq <= 710000) lnaband = 0x66; else
+ if (freq <= 735000) lnaband = 0x55; else
+ if (freq <= 765000) lnaband = 0x44; else
+ if (freq <= 802000) lnaband = 0x33; else
+ if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
+
+ msleep(100);
+ mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
+ (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
+ mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+ b[0] = REG_TUNE;
+ b[1] = (tune >> 8) & 0x1F;
+ b[2] = tune & 0xFF;
+ b[3] = tune >> 13;
+ mt2266_writeregs(priv,b,4);
+
+ dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
+ dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
+
+ b[0] = 0x05;
+ b[1] = 0x62;
+ b[2] = lnaband;
+ mt2266_writeregs(priv,b,3);
+
+ //Waits for pll lock or timeout
+ i = 0;
+ do {
+ mt2266_readreg(priv,REG_LOCK,b);
+ if ((b[0] & 0x40)==0x40)
+ break;
+ msleep(10);
+ i++;
+ } while (i<10);
+ dprintk("Lock when i=%i",(int)i);
+ return ret;
+}
+
+static void mt2266_calibrate(struct mt2266_priv *priv)
+{
+ mt2266_writereg(priv,0x11,0x03);
+ mt2266_writereg(priv,0x11,0x01);
+
+ mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
+ mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
+
+ mt2266_writereg(priv,0x33,0x5e);
+ mt2266_writereg(priv,0x10,0x10);
+ mt2266_writereg(priv,0x10,0x00);
+
+ mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+ msleep(25);
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0x00);
+ msleep(75);
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0xff);
+}
+
+static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int mt2266_init(struct dvb_frontend *fe)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0xff);
+ return 0;
+}
+
+static int mt2266_sleep(struct dvb_frontend *fe)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0x00);
+ return 0;
+}
+
+static int mt2266_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mt2266_tuner_ops = {
+ .info = {
+ .name = "Microtune MT2266",
+ .frequency_min = 470000000,
+ .frequency_max = 860000000,
+ .frequency_step = 50000,
+ },
+ .release = mt2266_release,
+ .init = mt2266_init,
+ .sleep = mt2266_sleep,
+ .set_params = mt2266_set_params,
+ .get_frequency = mt2266_get_frequency,
+ .get_bandwidth = mt2266_get_bandwidth
+};
+
+struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+ struct mt2266_priv *priv = NULL;
+ u8 id = 0;
+
+ priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ if (mt2266_readreg(priv,0,&id) != 0) {
+ kfree(priv);
+ return NULL;
+ }
+ if (id != PART_REV) {
+ kfree(priv);
+ return NULL;
+ }
+ printk(KERN_INFO "MT2266: successfully identified\n");
+ memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ mt2266_calibrate(priv);
+ return fe;
+}
+EXPORT_SYMBOL(mt2266_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h
new file mode 100644
index 000000000000..f31dd613ad37
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2266.h
@@ -0,0 +1,37 @@
+/*
+ * Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ * Copyright (c) 2007 Olivier DANET <odanet@caramail.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.
+ */
+
+#ifndef MT2266_H
+#define MT2266_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2266_config {
+ u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_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)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TUNER_MT2266
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 1ef821825641..0606b9a5b616 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 87e31ca7e108..5dd9b731f6f2 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index b809f83d9563..fcf964fe1d6b 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -44,12 +44,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "nxt200x.h"
struct nxt200x_state {
@@ -546,11 +544,6 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
nxt200x_writebytes(state, 0x17, buf, 1);
}
- /* get tuning information */
- if (fe->ops.tuner_ops.calc_regs) {
- fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
- }
-
/* set additional params */
switch (p->u.vsb.modulation) {
case QAM_64:
@@ -559,27 +552,24 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
/* This is just a guess since I am unable to test it */
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 1);
-
- /* set input */
- if (state->config->set_pll_input)
- state->config->set_pll_input(buf+1, 1);
break;
case VSB_8:
/* Set non-punctured clock for VSB */
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
-
- /* set input */
- if (state->config->set_pll_input)
- state->config->set_pll_input(buf+1, 0);
break;
default:
return -EINVAL;
break;
}
- /* write frequency information */
- nxt200x_writetuner(state, buf);
+ if (fe->ops.tuner_ops.calc_regs) {
+ /* get tuning information */
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+
+ /* write frequency information */
+ nxt200x_writetuner(state, buf);
+ }
/* reset the agc now that tuning has been completed */
nxt200x_agc_reset(state);
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 28bc5591b319..bb0ef58d7972 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,9 +38,6 @@ struct nxt200x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* used to set pll input */
- int (*set_pll_input)(u8* buf, int input);
-
/* need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 4e0aca7c67aa..b314a1f2deed 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
@@ -45,7 +44,6 @@
#include "dvb_math.h"
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "or51132.h"
static int debug;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 048d7cfe12d3..f02bd9445955 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/string.h>
@@ -223,38 +222,13 @@ static int or51211_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
struct or51211_state* state = fe->demodulator_priv;
- u32 freq = 0;
- u16 tunerfreq = 0;
- u8 buf[4];
/* Change only if we are actually changing the channel */
if (state->current_frequency != param->frequency) {
- freq = 44000 + (param->frequency/1000);
- tunerfreq = freq * 16/1000;
-
- dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
- param->frequency,tunerfreq);
-
- buf[0] = (tunerfreq >> 8) & 0x7F;
- buf[1] = (tunerfreq & 0xFF);
- buf[2] = 0x8E;
-
- if (param->frequency < 157250000) {
- buf[3] = 0xA0;
- dprintk("set_parameters VHF low range\n");
- } else if (param->frequency < 454000000) {
- buf[3] = 0x90;
- dprintk("set_parameters VHF high range\n");
- } else {
- buf[3] = 0x30;
- dprintk("set_parameters UHF range\n");
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
- "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
-
- if (i2c_writebytes(state,0xC2>>1,buf,4))
- printk(KERN_WARNING "or51211:set_parameters error "
- "writing to tuner\n");
/* Set to ATSC mode */
or51211_setmode(fe,0);
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
new file mode 100644
index 000000000000..30e8a705fad4
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -0,0 +1,729 @@
+/*
+ Samsung S5H1409 VSB/QAM demodulator driver
+
+ Copyright (C) 2006 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 <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 "dvb-pll.h"
+#include "s5h1409.h"
+
+struct s5h1409_state {
+
+ struct i2c_adapter* i2c;
+
+ /* configuration settings */
+ const struct s5h1409_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* previous uncorrected block counter */
+ fe_modulation_t current_modulation;
+
+ u32 current_frequency;
+};
+
+static int debug = 0;
+#define dprintk if (debug) printk
+
+/* Register values to initialise the demod, this will set VSB by default */
+static struct init_tab {
+ u8 reg;
+ u16 data;
+} init_tab[] = {
+ { 0x00, 0x0071, },
+ { 0x01, 0x3213, },
+ { 0x09, 0x0025, },
+ { 0x1c, 0x001d, },
+ { 0x1f, 0x002d, },
+ { 0x20, 0x001d, },
+ { 0x22, 0x0022, },
+ { 0x23, 0x0020, },
+ { 0x29, 0x110f, },
+ { 0x2a, 0x10b4, },
+ { 0x2b, 0x10ae, },
+ { 0x2c, 0x0031, },
+ { 0x31, 0x010d, },
+ { 0x32, 0x0100, },
+ { 0x44, 0x0510, },
+ { 0x54, 0x0104, },
+ { 0x58, 0x2222, },
+ { 0x59, 0x1162, },
+ { 0x5a, 0x3211, },
+ { 0x5d, 0x0370, },
+ { 0x5e, 0x0296, },
+ { 0x61, 0x0010, },
+ { 0x63, 0x4a00, },
+ { 0x65, 0x0800, },
+ { 0x71, 0x0003, },
+ { 0x72, 0x0470, },
+ { 0x81, 0x0002, },
+ { 0x82, 0x0600, },
+ { 0x86, 0x0002, },
+ { 0x8a, 0x2c38, },
+ { 0x8b, 0x2a37, },
+ { 0x92, 0x302f, },
+ { 0x93, 0x3332, },
+ { 0x96, 0x000c, },
+ { 0x99, 0x0101, },
+ { 0x9c, 0x2e37, },
+ { 0x9d, 0x2c37, },
+ { 0x9e, 0x2c37, },
+ { 0xab, 0x0100, },
+ { 0xac, 0x1003, },
+ { 0xad, 0x103f, },
+ { 0xe2, 0x0100, },
+ { 0x28, 0x1010, },
+ { 0xb1, 0x000e, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+ u16 val;
+ u16 data;
+} vsb_snr_tab[] = {
+ { 1023, 770, },
+ { 923, 300, },
+ { 918, 295, },
+ { 915, 290, },
+ { 911, 285, },
+ { 906, 280, },
+ { 901, 275, },
+ { 896, 270, },
+ { 891, 265, },
+ { 885, 260, },
+ { 879, 255, },
+ { 873, 250, },
+ { 864, 245, },
+ { 858, 240, },
+ { 850, 235, },
+ { 841, 230, },
+ { 832, 225, },
+ { 823, 220, },
+ { 812, 215, },
+ { 802, 210, },
+ { 788, 205, },
+ { 778, 200, },
+ { 767, 195, },
+ { 753, 190, },
+ { 740, 185, },
+ { 725, 180, },
+ { 707, 175, },
+ { 689, 170, },
+ { 671, 165, },
+ { 656, 160, },
+ { 637, 155, },
+ { 616, 150, },
+ { 542, 145, },
+ { 519, 140, },
+ { 507, 135, },
+ { 497, 130, },
+ { 492, 125, },
+ { 474, 120, },
+ { 300, 111, },
+ { 0, 0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+ u16 val;
+ u16 data;
+} qam64_snr_tab[] = {
+ { 12, 300, },
+ { 15, 290, },
+ { 18, 280, },
+ { 22, 270, },
+ { 23, 268, },
+ { 24, 266, },
+ { 25, 264, },
+ { 27, 262, },
+ { 28, 260, },
+ { 29, 258, },
+ { 30, 256, },
+ { 32, 254, },
+ { 33, 252, },
+ { 34, 250, },
+ { 35, 249, },
+ { 36, 248, },
+ { 37, 247, },
+ { 38, 246, },
+ { 39, 245, },
+ { 40, 244, },
+ { 41, 243, },
+ { 42, 241, },
+ { 43, 240, },
+ { 44, 239, },
+ { 45, 238, },
+ { 46, 237, },
+ { 47, 236, },
+ { 48, 235, },
+ { 49, 234, },
+ { 50, 233, },
+ { 51, 232, },
+ { 52, 231, },
+ { 53, 230, },
+ { 55, 229, },
+ { 56, 228, },
+ { 57, 227, },
+ { 58, 226, },
+ { 59, 225, },
+ { 60, 224, },
+ { 62, 223, },
+ { 63, 222, },
+ { 65, 221, },
+ { 66, 220, },
+ { 68, 219, },
+ { 69, 218, },
+ { 70, 217, },
+ { 72, 216, },
+ { 73, 215, },
+ { 75, 214, },
+ { 76, 213, },
+ { 78, 212, },
+ { 80, 211, },
+ { 81, 210, },
+ { 83, 209, },
+ { 84, 208, },
+ { 85, 207, },
+ { 87, 206, },
+ { 89, 205, },
+ { 91, 204, },
+ { 93, 203, },
+ { 95, 202, },
+ { 96, 201, },
+ { 104, 200, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+ u16 val;
+ u16 data;
+} qam256_snr_tab[] = {
+ { 12, 400, },
+ { 13, 390, },
+ { 15, 380, },
+ { 17, 360, },
+ { 19, 350, },
+ { 22, 348, },
+ { 23, 346, },
+ { 24, 344, },
+ { 25, 342, },
+ { 26, 340, },
+ { 27, 336, },
+ { 28, 334, },
+ { 29, 332, },
+ { 30, 330, },
+ { 31, 328, },
+ { 32, 326, },
+ { 33, 325, },
+ { 34, 322, },
+ { 35, 320, },
+ { 37, 318, },
+ { 39, 316, },
+ { 40, 314, },
+ { 41, 312, },
+ { 42, 310, },
+ { 43, 308, },
+ { 46, 306, },
+ { 47, 304, },
+ { 49, 302, },
+ { 51, 300, },
+ { 53, 298, },
+ { 54, 297, },
+ { 55, 296, },
+ { 56, 295, },
+ { 57, 294, },
+ { 59, 293, },
+ { 60, 292, },
+ { 61, 291, },
+ { 63, 290, },
+ { 64, 289, },
+ { 65, 288, },
+ { 66, 287, },
+ { 68, 286, },
+ { 69, 285, },
+ { 71, 284, },
+ { 72, 283, },
+ { 74, 282, },
+ { 75, 281, },
+ { 76, 280, },
+ { 77, 279, },
+ { 78, 278, },
+ { 81, 277, },
+ { 83, 276, },
+ { 84, 275, },
+ { 86, 274, },
+ { 87, 273, },
+ { 89, 272, },
+ { 90, 271, },
+ { 92, 270, },
+ { 93, 269, },
+ { 95, 268, },
+ { 96, 267, },
+ { 98, 266, },
+ { 100, 265, },
+ { 102, 264, },
+ { 104, 263, },
+ { 105, 262, },
+ { 106, 261, },
+ { 110, 260, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
+{
+ int ret;
+ u8 buf [] = { reg, data >> 8, data & 0xff };
+
+ struct i2c_msg msg = { .addr = state->config->demod_address,
+ .flags = 0, .buf = buf, .len = 3 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+ "ret == %i)\n", __FUNCTION__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0, 0 };
+
+ struct i2c_msg msg [] = {
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 2 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+ return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1409_softreset(struct dvb_frontend* fe)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __FUNCTION__);
+
+ s5h1409_writereg(state, 0xf5, 0);
+ s5h1409_writereg(state, 0xf5, 1);
+ return 0;
+}
+
+static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ int ret = 0;
+
+ dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
+
+ if( (KHz == 44000) || (KHz == 5380) ) {
+ s5h1409_writereg(state, 0x87, 0x01be);
+ s5h1409_writereg(state, 0x88, 0x0436);
+ s5h1409_writereg(state, 0x89, 0x054d);
+ } else {
+ printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __FUNCTION__);
+
+ if(inverted == 1)
+ return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
+ else
+ return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
+}
+
+static int s5h1409_enable_modulation(struct dvb_frontend* fe,
+ fe_modulation_t m)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(0x%08x)\n", __FUNCTION__, m);
+
+ switch(m) {
+ case VSB_8:
+ dprintk("%s() VSB_8\n", __FUNCTION__);
+ s5h1409_writereg(state, 0xf4, 0);
+ break;
+ case QAM_64:
+ dprintk("%s() QAM_64\n", __FUNCTION__);
+ s5h1409_writereg(state, 0xf4, 1);
+ s5h1409_writereg(state, 0x85, 0x100);
+ break;
+ case QAM_256:
+ dprintk("%s() QAM_256\n", __FUNCTION__);
+ s5h1409_writereg(state, 0xf4, 1);
+ s5h1409_writereg(state, 0x85, 0x101);
+ break;
+ default:
+ dprintk("%s() Invalid modulation\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ state->current_modulation = m;
+ s5h1409_softreset(fe);
+
+ return 0;
+}
+
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+ if (enable)
+ return s5h1409_writereg(state, 0xf3, 1);
+ else
+ return s5h1409_writereg(state, 0xf3, 0);
+}
+
+static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+ if (enable)
+ return s5h1409_writereg(state, 0xe3, 0x1100);
+ else
+ return s5h1409_writereg(state, 0xe3, 0);
+}
+
+static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+ return s5h1409_writereg(state, 0xf2, enable);
+}
+
+static int s5h1409_register_reset(struct dvb_frontend* fe)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __FUNCTION__);
+
+ return s5h1409_writereg(state, 0xfa, 0);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1409_set_frontend (struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency);
+
+ s5h1409_softreset(fe);
+
+ state->current_frequency = p->frequency;
+
+ s5h1409_enable_modulation(fe, p->u.vsb.modulation);
+
+ if (fe->ops.tuner_ops.set_params) {
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+static int s5h1409_init (struct dvb_frontend* fe)
+{
+ int i;
+
+ struct s5h1409_state* state = fe->demodulator_priv;
+ dprintk("%s()\n", __FUNCTION__);
+
+ s5h1409_sleep(fe, 0);
+ s5h1409_register_reset(fe);
+
+ for (i=0; i < ARRAY_SIZE(init_tab); i++)
+ s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+ /* The datasheet says that after initialisation, VSB is default */
+ state->current_modulation = VSB_8;
+
+ if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
+ s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+ else
+ s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+
+ s5h1409_set_spectralinversion(fe, state->config->inversion);
+ s5h1409_set_if_freq(fe, state->config->if_freq);
+ s5h1409_set_gpio(fe, state->config->gpio);
+ s5h1409_softreset(fe);
+
+ /* Note: Leaving the I2C gate open here. */
+ s5h1409_i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+
+static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ u16 reg;
+ u32 tuner_status = 0;
+
+ *status = 0;
+
+ /* Get the demodulator status */
+ reg = s5h1409_readreg(state, 0xf1);
+ if(reg & 0x1000)
+ *status |= FE_HAS_VITERBI;
+ if(reg & 0x8000)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+ switch(state->config->status_mode) {
+ case S5H1409_DEMODLOCKING:
+ if (*status & FE_HAS_VITERBI)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ case S5H1409_TUNERLOCKING:
+ /* Get the tuner status */
+ if (fe->ops.tuner_ops.get_status) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (tuner_status)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ }
+
+ dprintk("%s() status 0x%08x\n", __FUNCTION__, *status);
+
+ return 0;
+}
+
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __FUNCTION__);
+
+ for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+ if (v < qam256_snr_tab[i].val) {
+ *snr = qam256_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __FUNCTION__);
+
+ for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+ if (v < qam64_snr_tab[i].val) {
+ *snr = qam64_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __FUNCTION__);
+
+ for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+ if (v > vsb_snr_tab[i].val) {
+ *snr = vsb_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ dprintk("%s() snr=%d\n", __FUNCTION__, *snr);
+ return ret;
+}
+
+static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ u16 reg;
+ dprintk("%s()\n", __FUNCTION__);
+
+ reg = s5h1409_readreg(state, 0xf1) & 0x1ff;
+
+ switch(state->current_modulation) {
+ case QAM_64:
+ return s5h1409_qam64_lookup_snr(fe, snr, reg);
+ case QAM_256:
+ return s5h1409_qam256_lookup_snr(fe, snr, reg);
+ case VSB_8:
+ return s5h1409_vsb_lookup_snr(fe, snr, reg);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int s5h1409_read_signal_strength(struct dvb_frontend* fe,
+ u16* signal_strength)
+{
+ return s5h1409_read_snr(fe, signal_strength);
+}
+
+static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ *ucblocks = s5h1409_readreg(state, 0xb5);
+
+ return 0;
+}
+
+static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ return s5h1409_read_ucblocks(fe, ber);
+}
+
+static int s5h1409_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ p->frequency = state->current_frequency;
+ p->u.vsb.modulation = state->current_modulation;
+
+ return 0;
+}
+
+static int s5h1409_get_tune_settings(struct dvb_frontend* fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void s5h1409_release(struct dvb_frontend* fe)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1409_ops;
+
+struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct s5h1409_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->current_modulation = 0;
+
+ /* check if the demod exists */
+ if (s5h1409_readreg(state, 0x04) != 0x0066)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s5h1409_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* Note: Leaving the I2C gate open here. */
+ s5h1409_writereg(state, 0xf3, 1);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops s5h1409_ops = {
+
+ .info = {
+ .name = "Samsung S5H1409 QAM/8VSB Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .init = s5h1409_init,
+ .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl,
+ .set_frontend = s5h1409_set_frontend,
+ .get_frontend = s5h1409_get_frontend,
+ .get_tune_settings = s5h1409_get_tune_settings,
+ .read_status = s5h1409_read_status,
+ .read_ber = s5h1409_read_ber,
+ .read_signal_strength = s5h1409_read_signal_strength,
+ .read_snr = s5h1409_read_snr,
+ .read_ucblocks = s5h1409_read_ucblocks,
+ .release = s5h1409_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1409_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
new file mode 100644
index 000000000000..20f9af1af445
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -0,0 +1,73 @@
+/*
+ Samsung S5H1409 VSB/QAM demodulator driver
+
+ Copyright (C) 2006 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 __S5H1409_H__
+#define __S5H1409_H__
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1409_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* serial/parallel output */
+#define S5H1409_PARALLEL_OUTPUT 0
+#define S5H1409_SERIAL_OUTPUT 1
+ u8 output_mode;
+
+ /* GPIO Setting */
+#define S5H1409_GPIO_OFF 0
+#define S5H1409_GPIO_ON 1
+ u8 gpio;
+
+ /* IF Freq in KHz */
+ u16 if_freq;
+
+ /* Spectral Inversion */
+#define S5H1409_INVERSION_OFF 0
+#define S5H1409_INVERSION_ON 1
+ u8 inversion;
+
+ /* Return lock status based on tuner lock, or demod lock */
+#define S5H1409_TUNERLOCKING 0
+#define S5H1409_DEMODLOCKING 1
+ u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
+extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_S5H1409 */
+
+#endif /* __S5H1409_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index d98fd5c2e13e..da876f7bfe32 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/delay.h>
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index 5c2f8f4e0ae5..1aa2539f5099 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 9a343972ff50..17e5cb561cd8 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -680,8 +680,8 @@ static struct dvb_frontend_ops stv0297_ops = {
.info = {
.name = "ST STV0297 DVB-C",
.type = FE_QAM,
- .frequency_min = 64000000,
- .frequency_max = 1300000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.frequency_stepsize = 62500,
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 18768d2f6d40..035dd7ba6519 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -45,7 +45,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -249,7 +248,7 @@ static int stv0299_get_symbolrate (struct stv0299_state* state)
dprintk ("%s\n", __FUNCTION__);
stv0299_readregs (state, 0x1f, sfr, 3);
- stv0299_readregs (state, 0x1a, &rtf, 1);
+ stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
srate = (sfr[0] << 8) | sfr[1];
srate *= Mclk;
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index e725f612a6b7..4cd9e82c4669 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -439,8 +439,8 @@ static struct dvb_frontend_ops tda10021_ops = {
.name = "Philips TDA10021 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */
.symbol_rate_max = (XIN/2)/4, /* SACLK/4 */
#if 0
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index da796e784be3..364bc01971a0 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
s16 SFIL=0;
u16 NDEC = 0;
- if (sr > (SYSCLK/(2*4)))
- sr=SYSCLK/(2*4);
-
- if (sr<870000)
- sr=870000;
-
if (sr < (u32)(SYSCLK/98.40)) {
NDEC=3;
SFIL=1;
@@ -478,7 +472,7 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
state->i2c = i2c;
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
- for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+ for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
if (tda10023_inittab[i] == 0x00) {
state->reg0 = tda10023_inittab[i+2];
break;
@@ -506,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = {
.name = "Philips TDA10023 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
.symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */
.caps = 0x400 | //FE_CAN_QAM_4
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 33a84372c9e6..8415a8a5247a 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -31,7 +31,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index 0f2d4b415560..9a8ddc537f8f 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 67415c9db6f7..011b74f798a0 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -443,12 +442,12 @@ static struct dvb_frontend_ops tda8083_ops = {
.info = {
.name = "Philips TDA8083 DVB-S",
.type = FE_QPSK,
- .frequency_min = 950000, /* FIXME: guessed! */
- .frequency_max = 1400000, /* FIXME: guessed! */
+ .frequency_min = 920000, /* TDA8060 */
+ .frequency_max = 2200000, /* TDA8060 */
.frequency_stepsize = 125, /* kHz for QPSK frontends */
/* .frequency_tolerance = ???,*/
- .symbol_rate_min = 1000000, /* FIXME: guessed! */
- .symbol_rate_max = 45000000, /* FIXME: guessed! */
+ .symbol_rate_min = 12000000,
+ .symbol_rate_max = 30000000,
/* .symbol_rate_tolerance = ???,*/
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 9b57576bfeb4..066b73b75698 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = {
.name = "VLSI VES1820 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.caps = FE_CAN_QAM_16 |
FE_CAN_QAM_32 |
FE_CAN_QAM_64 |
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 245f9b7dddfa..a97a7fd2c891 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
index ce6a9aaf937e..7ac128724df8 100644
--- a/drivers/media/dvb/pluto2/Makefile
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7751628e1415..6d53289b3276 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -108,7 +108,7 @@ config DVB_BUDGET_AV
tristate "Budget cards with analog video inputs"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146_VV
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index aa85ecdc6c80..2c1145236ee6 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index ef1108c0bf11..8b8144f77a73 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -40,7 +40,6 @@
#include <linux/smp_lock.h>
#include <linux/kernel.h>
-#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
@@ -137,6 +136,15 @@ static void init_av7110_av(struct av7110 *av7110)
if (ret < 0)
printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+ 1, (u16) av7110->display_ar);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to set aspect ratio\n");
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+ 1, av7110->display_panscan);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to set pan scan\n");
+
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
if (ret < 0)
printk("dvb-ttpci: unable to configure 4:3 wss\n");
@@ -1534,7 +1542,7 @@ static int get_firmware(struct av7110* av7110)
}
/* check if the firmware is available */
- av7110->bin_fw = (unsigned char *) vmalloc(fw->size);
+ av7110->bin_fw = vmalloc(fw->size);
if (NULL == av7110->bin_fw) {
dprintk(1, "out of memory\n");
release_firmware(fw);
@@ -2258,7 +2266,7 @@ static int frontend_init(struct av7110 *av7110)
FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
- FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
@@ -2639,12 +2647,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
av7110->mixer.volume_left = volume;
av7110->mixer.volume_right = volume;
- init_av7110_av(av7110);
-
ret = av7110_register(av7110);
if (ret < 0)
goto err_arm_thread_stop_10;
+ init_av7110_av(av7110);
+
/* special case DVB-C: these cards have an analog tuner
plus need some special handling, so we have separate
saa7146_ext_vv data for these... */
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 115002b0390c..0cb439527498 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -194,6 +194,7 @@ struct av7110 {
int video_blank;
struct video_status videostate;
+ u16 display_panscan;
int display_ar;
int trickmode;
#define TRICK_NONE 0
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 58678c05aa53..d75e7e48addc 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -391,7 +391,7 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
****************************************************************************/
static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
- const char *buf, unsigned long count)
+ const u8 *buf, unsigned long count)
{
unsigned long todo = count;
int free;
@@ -436,7 +436,7 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
-static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
@@ -499,7 +499,7 @@ static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
return count - todo;
}
-static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
@@ -959,7 +959,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
#define MIN_IFRAME 400000
-static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock)
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
{
int i, n;
@@ -1082,19 +1082,18 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_SET_DISPLAY_FORMAT:
{
video_displayformat_t format = (video_displayformat_t) arg;
- u16 val = 0;
switch (format) {
case VIDEO_PAN_SCAN:
- val = VID_PAN_SCAN_PREF;
+ av7110->display_panscan = VID_PAN_SCAN_PREF;
break;
case VIDEO_LETTER_BOX:
- val = VID_VC_AND_PS_PREF;
+ av7110->display_panscan = VID_VC_AND_PS_PREF;
break;
case VIDEO_CENTER_CUT_OUT:
- val = VID_CENTRE_CUT_PREF;
+ av7110->display_panscan = VID_CENTRE_CUT_PREF;
break;
default:
@@ -1104,7 +1103,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
break;
av7110->videostate.display_format = format;
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
- 1, (u16) val);
+ 1, av7110->display_panscan);
break;
}
@@ -1466,8 +1465,9 @@ int av7110_av_register(struct av7110 *av7110)
av7110->videostate.play_state = VIDEO_STOPPED;
av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
av7110->videostate.video_format = VIDEO_FORMAT_4_3;
- av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT;
+ av7110->videostate.display_format = VIDEO_LETTER_BOX;
av7110->display_ar = VIDEO_FORMAT_4_3;
+ av7110->display_panscan = VID_VC_AND_PS_PREF;
init_waitqueue_head(&av7110->video_events.wait_queue);
spin_lock_init(&av7110->video_events.lock);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index e1c1294bb767..c58e3fc509ed 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -151,7 +151,7 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
{
int free;
int non_blocking = file->f_flags & O_NONBLOCK;
- char *page = (char *)__get_free_page(GFP_USER);
+ u8 *page = (u8 *)__get_free_page(GFP_USER);
int res;
if (!page)
@@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
return -EINVAL;
DVB_RINGBUFFER_SKIP(cibuf, 2);
- return dvb_ringbuffer_read(cibuf, buf, len, 1);
+ return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
}
static int dvb_ca_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 70aee4eb5da4..a468aa2e4854 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -158,7 +158,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
dprintk(4, "writing DRAM block %d\n", i);
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
bootblock ^= 0x1400;
iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
@@ -173,10 +173,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
if (rest > 4)
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
else
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
@@ -751,7 +751,7 @@ static int FlushText(struct av7110 *av7110)
return 0;
}
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
{
int i, ret;
unsigned long start;
@@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble
static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
{
- int i;
- int length = last - first + 1;
+ int i;
+ int length = last - first + 1;
- if (length * 4 > DATA_BUFF3_SIZE)
- return -EINVAL;
+ if (length * 4 > DATA_BUFF3_SIZE)
+ return -EINVAL;
- for (i = 0; i < length; i++) {
- u32 color, blend, yuv;
+ for (i = 0; i < length; i++) {
+ u32 color, blend, yuv;
- if (get_user(color, colors + i))
- return -EFAULT;
- blend = (color & 0xF0000000) >> 4;
- yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+ if (get_user(color, colors + i))
+ return -EFAULT;
+ blend = (color & 0xF0000000) >> 4;
+ yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
(color >> 16) & 0xFF) | blend : 0;
- yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
- wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
- }
- return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
+ yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
+ wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
+ }
+ return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
av7110->osdwin,
bpp2pal[av7110->osdbpp[av7110->osdwin]],
first, last);
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 673d9b3f064c..74d940f75da6 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -393,7 +393,7 @@ static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val,
}
/* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count)
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
{
memcpy(av7110->debi_virt, val, count);
av7110_debiwrite(av7110, config, addr, 0, count);
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index a97f166bb523..5d19c402dad1 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -25,7 +25,6 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <asm/bitops.h>
@@ -280,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
if (count < size)
return -EINVAL;
- page = (char *) vmalloc(size);
+ page = vmalloc(size);
if (!page)
return -ENOMEM;
@@ -356,7 +355,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
input_dev->id.vendor = av7110->dev->pci->vendor;
input_dev->id.product = av7110->dev->pci->device;
}
- input_dev->cdev.dev = &av7110->dev->pci->dev;
+ input_dev->dev.parent = &av7110->dev->pci->dev;
/* initial keymap */
memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
input_register_keys(&av7110->ir);
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index fcd9994058d0..76cca003252f 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = {
static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
{
+ struct av7110 *av7110 = dev->ext_priv;
u8 buf[] = { 0x00, reg, data };
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
dprintk(4, "dev: %p\n", dev);
- if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+ if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
return -1;
return 0;
}
static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
{
+ struct av7110 *av7110 = dev->ext_priv;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
dprintk(4, "dev: %p\n", dev);
- if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+ if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
return -1;
return 0;
}
@@ -333,7 +335,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return -EINVAL;
memset(t, 0, sizeof(*t));
- strcpy(t->name, "Television");
+ strcpy((char *)t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 0e817d6f1ce5..3439c9864f67 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -828,29 +828,6 @@ static u8 philips_sd1878_inittab[] = {
0xff, 0xff
};
-static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 buf[4];
- int rc;
- struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
- struct budget *budget = (struct budget *) fe->dvb->priv;
-
- if((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
- params->frequency, 0);
- if(rc < 0) return rc;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
-
- return 0;
-}
-
static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
u32 srate, u32 ratio)
{
@@ -921,6 +898,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
#define SUBID_DVBS_EASYWATCH_1 0x001a
+#define SUBID_DVBS_EASYWATCH_2 0x001b
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_EASYWATCH 0x002a
@@ -982,10 +960,13 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBS_TV_STAR_CI:
case SUBID_DVBS_CYNERGY1200N:
case SUBID_DVBS_EASYWATCH:
+ case SUBID_DVBS_EASYWATCH_2:
fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
&budget_av->budget.i2c_adap);
if (fe) {
- fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ dvb_attach(dvb_pll_attach, fe, 0x60,
+ &budget_av->budget.i2c_adap,
+ DVB_PLL_PHILIPS_SD1878_TDA8261);
}
break;
@@ -1251,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = {
.capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
.flags = 0,
.stds = &standard[0],
- .num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
+ .num_stds = ARRAY_SIZE(standard),
.ioctls = &ioctls[0],
.ioctl = av_ioctl,
};
@@ -1264,6 +1245,7 @@ MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
@@ -1287,6 +1269,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+ MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9d42f88ebb0e..509349211d4f 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -206,7 +206,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
input_dev->id.vendor = saa->pci->vendor;
input_dev->id.product = saa->pci->device;
}
- input_dev->cdev.dev = &saa->pci->dev;
+ input_dev->dev.parent = &saa->pci->dev;
/* Select keymap and address */
switch (budget_ci->budget.dev->pci->subsystem_device) {
@@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
case 0x100f:
case 0x1011:
case 0x1012:
- case 0x1017:
/* The hauppauge keymap is a superset of these remotes */
ir_input_init(input_dev, &budget_ci->ir.state,
IR_TYPE_RC5, ir_codes_hauppauge_new);
@@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.rc5_device = rc5_device;
break;
case 0x1010:
+ case 0x1017:
/* for the Technotrend 1500 bundled remote */
ir_input_init(input_dev, &budget_ci->ir.state,
IR_TYPE_RC5, ir_codes_tt_1500);
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index b611f2b1f8bc..0252081f013c 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -34,7 +34,6 @@
* the project's page is at http://www.linuxtv.org/dvb/
*/
-#include <linux/moduleparam.h>
#include "budget.h"
#include "ttpci-eeprom.h"
diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile
index 6ab97f6b53fc..fbe2b9514c21 100644
--- a/drivers/media/dvb/ttusb-budget/Makefile
+++ b/drivers/media/dvb/ttusb-budget/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index b60cdc93d6db..288e79f2cb0f 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -13,7 +13,6 @@
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/delay.h>
#include <linux/time.h>
diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile
index b41bf1f06a9f..2d70a8269391 100644
--- a/drivers/media/dvb/ttusb-dec/Makefile
+++ b/drivers/media/dvb/ttusb-dec/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 78c98b089975..5e691fd79904 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -22,7 +22,6 @@
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 194b102140ef..11e962f1a97f 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -111,11 +111,16 @@ config RADIO_AZTECH_PORT
jumper sets the card to 0x358.
config RADIO_GEMTEK
- tristate "GemTek Radio Card support"
+ tristate "GemTek Radio card (or compatible) support"
depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have this FM radio card, and then fill in the
- port address below.
+ I/O port address and settings below. The following cards either have
+ GemTek Radio tuner or are rebranded GemTek Radio cards:
+
+ - Sound Vision 16 Gold with FM Radio
+ - Typhoon Radio card (some models)
+ - Hama Radio card
In order to control your radio card, you will need to use programs
that are compatible with the Video For Linux API. Information on
@@ -126,14 +131,25 @@ config RADIO_GEMTEK
module will be called radio-gemtek.
config RADIO_GEMTEK_PORT
- hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)"
+ hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
depends on RADIO_GEMTEK=y
default "34c"
help
Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
0x34c, if you haven't changed the jumper setting on the card. On
Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
- port is 0x28c.
+ port is 0x20c, 0x248 or 0x28c.
+ If automatic I/O port probing is enabled this port will be used only
+ in case of automatic probing failure, ie. as a fallback.
+
+config RADIO_GEMTEK_PROBE
+ bool "Automatic I/O port probing"
+ depends on RADIO_GEMTEK=y
+ default y
+ help
+ Say Y here to enable automatic probing for GemTek Radio card. The
+ following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
+ 0x28c.
config RADIO_GEMTEK_PCI
tristate "GemTek PCI Radio Card support"
@@ -324,8 +340,8 @@ config RADIO_ZOLTRIX_PORT
Enter the I/O port of your Zoltrix radio card.
config USB_DSBR
- tristate "D-Link USB FM radio support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+ tristate "D-Link/GemTek USB FM radio support"
+ depends on USB && VIDEO_V4L2
---help---
Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 5adc27c3ced9..f0a67e93d7fd 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -63,7 +63,7 @@ struct rt_device
static void sleep_delay(long n)
{
/* Sleep nicely for 'n' uS */
- int d=n/(1000000/HZ);
+ int d=n/msecs_to_jiffies(1000);
if(!d)
udelay(n);
else
@@ -392,7 +392,6 @@ static struct video_device rtrack_radio=
.owner = THIS_MODULE,
.name = "RadioTrack radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &rtrack_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 9f1addae6928..9b1f7a99dac0 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -355,7 +355,6 @@ static struct video_device aztech_radio=
.owner = THIS_MODULE,
.name = "Aztech radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &aztech_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8cf2e9df5c8a..34e317ced5a3 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -329,7 +329,7 @@ cadet_handler(unsigned long data)
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
- readtimer.expires=jiffies+(HZ/20);
+ readtimer.expires=jiffies+msecs_to_jiffies(50);
add_timer(&readtimer);
}
@@ -349,7 +349,7 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
- readtimer.expires=jiffies+(HZ/20);
+ readtimer.expires=jiffies+msecs_to_jiffies(50);
add_timer(&readtimer);
}
if(rdsin==rdsout) {
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 5e6f17df204b..99a323131333 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -94,7 +94,6 @@ struct gemtek_pci_card {
u32 iobase;
u32 length;
- u16 model;
u32 current_frequency;
u8 mute;
@@ -377,7 +376,6 @@ static struct video_device vdev_template = {
.owner = THIS_MODULE,
.name = "Gemtek PCI Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &gemtek_pci_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
@@ -414,8 +412,6 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
goto err_pci;
}
- pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
pci_set_drvdata( pci_dev, card );
if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index b04b6a7fff7c..0c963db03614 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -26,143 +26,383 @@
#include <media/v4l2-common.h>
#include <linux/spinlock.h>
-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,3)
+#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
-static struct v4l2_queryctrl radio_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535,
- .default_value = 0xff,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
+/*
+ * Module info.
+ */
+
+MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
+MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
+MODULE_LICENSE("GPL");
+
+/*
+ * Module params.
+ */
#ifndef CONFIG_RADIO_GEMTEK_PORT
#define CONFIG_RADIO_GEMTEK_PORT -1
#endif
+#ifndef CONFIG_RADIO_GEMTEK_PROBE
+#define CONFIG_RADIO_GEMTEK_PROBE 1
+#endif
-static int io = CONFIG_RADIO_GEMTEK_PORT;
-static int radio_nr = -1;
-static spinlock_t lock;
+static int io = CONFIG_RADIO_GEMTEK_PORT;
+static int probe = CONFIG_RADIO_GEMTEK_PROBE;
+static int hardmute;
+static int shutdown = 1;
+static int keepmuted = 1;
+static int initmute = 1;
+static int radio_nr = -1;
-struct gemtek_device
-{
- int port;
- unsigned long curfreq;
+module_param(io, int, 0444);
+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
+ "probing is disabled or fails. The most common I/O ports are: 0x20c "
+ "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
+ " work for the combined sound/radiocard).");
+
+module_param(probe, bool, 0444);
+MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
+ "common I/O ports used by the card are probed.");
+
+module_param(hardmute, bool, 0644);
+MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
+ "reduce static noise.");
+
+module_param(shutdown, bool, 0644);
+MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
+ "module is unloaded.");
+
+module_param(keepmuted, bool, 0644);
+MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
+
+module_param(initmute, bool, 0444);
+MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
+
+module_param(radio_nr, int, 0444);
+
+/*
+ * Functions for controlling the card.
+ */
+#define GEMTEK_LOWFREQ (87*16000)
+#define GEMTEK_HIGHFREQ (108*16000)
+
+/*
+ * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal
+ * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz).
+ */
+#define FSCALE 8
+#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1<<FSCALE)))
+#define REF_FREQ ((unsigned int)(6.39 * 16 * (1<<FSCALE)))
+
+#define GEMTEK_CK 0x01 /* Clock signal */
+#define GEMTEK_DA 0x02 /* Serial data */
+#define GEMTEK_CE 0x04 /* Chip enable */
+#define GEMTEK_NS 0x08 /* No signal */
+#define GEMTEK_MT 0x10 /* Line mute */
+#define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */
+#define GEMTEK_PLL_OFF 0x07 /* PLL off */
+
+#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */
+
+#define SHORT_DELAY 5 /* usec */
+#define LONG_DELAY 75 /* usec */
+
+struct gemtek_device {
+ unsigned long lastfreq;
int muted;
+ u32 bu2614data;
};
+#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */
+#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */
+#define BU2614_VOID_BITS 4 /* unused */
+#define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */
+#define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */
+#define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */
+#define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/
+#define BU2614_VOID2_BITS 1 /* unused */
+#define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */
+#define BU2614_TEST_BITS 1 /* TS, Test data is input */
+
+#define BU2614_FREQ_SHIFT 0
+#define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT)
+#define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT)
+#define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT)
+#define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT)
+#define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT)
+#define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT)
+#define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT)
+#define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT)
+#define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT)
+
+#define MKMASK(field) (((1<<BU2614_##field##_BITS) - 1) << \
+ BU2614_##field##_SHIFT)
+#define BU2614_PORT_MASK MKMASK(PORT)
+#define BU2614_FREQ_MASK MKMASK(FREQ)
+#define BU2614_VOID_MASK MKMASK(VOID)
+#define BU2614_FMES_MASK MKMASK(FMES)
+#define BU2614_STDF_MASK MKMASK(STDF)
+#define BU2614_SWIN_MASK MKMASK(SWIN)
+#define BU2614_SWAL_MASK MKMASK(SWAL)
+#define BU2614_VOID2_MASK MKMASK(VOID2)
+#define BU2614_FMUN_MASK MKMASK(FMUN)
+#define BU2614_TEST_MASK MKMASK(TEST)
-/* local things */
+static struct gemtek_device gemtek_unit;
-/* the correct way to mute the gemtek may be to write the last written
- * frequency || 0x10, but just writing 0x10 once seems to do it as well
+static spinlock_t lock;
+
+/*
+ * Set data which will be sent to BU2614FS.
*/
-static void gemtek_mute(struct gemtek_device *dev)
+#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \
+ ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT))
+
+/*
+ * Transmit settings to BU2614FS over GemTek IC.
+ */
+static void gemtek_bu2614_transmit(struct gemtek_device *dev)
{
- if(dev->muted)
- return;
+ int i, bit, q, mute;
+
spin_lock(&lock);
- outb(0x10, io);
+
+ mute = dev->muted ? GEMTEK_MT : 0x00;
+
+ outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(LONG_DELAY);
+
+ for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
+ bit = (q & 1) ? GEMTEK_DA : 0;
+ outb_p(mute | GEMTEK_CE | bit, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
+ }
+
+ outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(LONG_DELAY);
+
spin_unlock(&lock);
- dev->muted = 1;
}
-static void gemtek_unmute(struct gemtek_device *dev)
+/*
+ * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected).
+ */
+static unsigned long gemtek_convfreq(unsigned long freq)
{
- if(dev->muted == 0)
+ return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+}
+
+/*
+ * Set FM-frequency.
+ */
+static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+{
+
+ if (keepmuted && hardmute && dev->muted)
return;
- spin_lock(&lock);
- outb(0x20, io);
- spin_unlock(&lock);
+
+ if (freq < GEMTEK_LOWFREQ)
+ freq = GEMTEK_LOWFREQ;
+ else if (freq > GEMTEK_HIGHFREQ)
+ freq = GEMTEK_HIGHFREQ;
+
+ dev->lastfreq = freq;
dev->muted = 0;
+
+ gemtek_bu2614_set(dev, BU2614_PORT, 0);
+ gemtek_bu2614_set(dev, BU2614_FMES, 0);
+ gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
+ gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+ gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */
+ gemtek_bu2614_set(dev, BU2614_TEST, 0);
+
+ gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
+ gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
+
+ gemtek_bu2614_transmit(dev);
}
-static void zero(void)
+/*
+ * Set mute flag.
+ */
+static void gemtek_mute(struct gemtek_device *dev)
{
- outb_p(0x04, io);
- udelay(5);
- outb_p(0x05, io);
- udelay(5);
+ int i;
+ dev->muted = 1;
+
+ if (hardmute) {
+ /* Turn off PLL, disable data output */
+ gemtek_bu2614_set(dev, BU2614_PORT, 0);
+ gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */
+ gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
+ gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+ gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */
+ gemtek_bu2614_set(dev, BU2614_TEST, 0);
+ gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
+ gemtek_bu2614_set(dev, BU2614_FREQ, 0);
+ gemtek_bu2614_transmit(dev);
+ } else {
+ spin_lock(&lock);
+
+ /* Read bus contents (CE, CK and DA). */
+ i = inb_p(io);
+ /* Write it back with mute flag set. */
+ outb_p((i >> 5) | GEMTEK_MT, io);
+ udelay(SHORT_DELAY);
+
+ spin_unlock(&lock);
+ }
}
-static void one(void)
+/*
+ * Unset mute flag.
+ */
+static void gemtek_unmute(struct gemtek_device *dev)
{
- outb_p(0x06, io);
- udelay(5);
- outb_p(0x07, io);
- udelay(5);
+ int i;
+ dev->muted = 0;
+
+ if (hardmute) {
+ /* Turn PLL back on. */
+ gemtek_setfreq(dev, dev->lastfreq);
+ } else {
+ spin_lock(&lock);
+
+ i = inb_p(io);
+ outb_p(i >> 5, io);
+ udelay(SHORT_DELAY);
+
+ spin_unlock(&lock);
+ }
}
-static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+/*
+ * Get signal strength (= stereo status).
+ */
+static inline int gemtek_getsigstr(void)
{
- int i;
+ return inb_p(io) & GEMTEK_NS ? 0 : 1;
+}
-/* freq = 78.25*((float)freq/16000.0 + 10.52); */
+/*
+ * Check if requested card acts like GemTek Radio card.
+ */
+static int gemtek_verify(int port)
+{
+ static int verified = -1;
+ int i, q;
- freq /= 16;
- freq += 10520;
- freq *= 7825;
- freq /= 100000;
+ if (verified == port)
+ return 1;
spin_lock(&lock);
- /* 2 start bits */
- outb_p(0x03, io);
- udelay(5);
- outb_p(0x07, io);
- udelay(5);
+ q = inb_p(port); /* Read bus contents before probing. */
+ /* Try to turn on CE, CK and DA respectively and check if card responds
+ properly. */
+ for (i = 0; i < 3; ++i) {
+ outb_p(1 << i, port);
+ udelay(SHORT_DELAY);
- /* 28 frequency bits (lsb first) */
- for (i = 0; i < 14; i++)
- if (freq & (1 << i))
- one();
- else
- zero();
- /* 36 unknown bits */
- for (i = 0; i < 11; i++)
- zero();
- one();
- for (i = 0; i < 4; i++)
- zero();
- one();
- zero();
-
- /* 2 end bits */
- outb_p(0x03, io);
- udelay(5);
- outb_p(0x07, io);
- udelay(5);
+ if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
+ spin_unlock(&lock);
+ return 0;
+ }
+ }
+ outb_p(q >> 5, port); /* Write bus contents back. */
+ udelay(SHORT_DELAY);
spin_unlock(&lock);
+ verified = port;
- return 0;
+ return 1;
}
-static int gemtek_getsigstr(struct gemtek_device *dev)
+/*
+ * Automatic probing for card.
+ */
+static int gemtek_probe(void)
{
- spin_lock(&lock);
- inb(io);
- udelay(5);
- spin_unlock(&lock);
- if (inb(io) & 8) /* bit set = no signal present */
- return 0;
- return 1; /* signal present */
+ int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+ int i;
+
+ if (!probe) {
+ printk(KERN_INFO "Automatic device probing disabled.\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "Automatic device probing enabled.\n");
+
+ for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
+ printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
+
+ if (!request_region(ioports[i], 1, "gemtek-probe")) {
+ printk(KERN_WARNING "I/O port 0x%x busy!\n",
+ ioports[i]);
+ continue;
+ }
+
+ if (gemtek_verify(ioports[i])) {
+ printk(KERN_INFO "Card found from I/O port "
+ "0x%x!\n", ioports[i]);
+
+ release_region(ioports[i], 1);
+
+ io = ioports[i];
+ return io;
+ }
+
+ release_region(ioports[i], 1);
+ }
+
+ printk(KERN_ERR "Automatic probing failed!\n");
+
+ return -1;
}
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
+/*
+ * Video 4 Linux stuff.
+ */
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }, {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
+static struct file_operations gemtek_fops = {
+ .owner = THIS_MODULE,
+ .open = video_exclusive_open,
+ .release = video_exclusive_release,
+ .ioctl = video_ioctl2,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .llseek = no_llseek
+};
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
{
strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
strlcpy(v->card, "GemTek", sizeof(v->card));
@@ -172,28 +412,29 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
{
- struct video_device *dev = video_devdata(file);
- struct gemtek_device *rt = dev->priv;
-
if (v->index > 0)
return -EINVAL;
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
- v->rangelow = (87*16000);
- v->rangehigh = (108*16000);
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff*gemtek_getsigstr(rt);
+ v->rangelow = GEMTEK_LOWFREQ;
+ v->rangehigh = GEMTEK_HIGHFREQ;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->signal = 0xffff * gemtek_getsigstr();
+ if (v->signal) {
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ } else {
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+
return 0;
}
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
{
if (v->index > 0)
return -EINVAL;
@@ -201,38 +442,35 @@ static int vidioc_s_tuner(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ struct v4l2_frequency *f)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
- rt->curfreq = f->frequency;
- /* needs to be called twice in order for getsigstr to work */
- gemtek_setfreq(rt, rt->curfreq);
- gemtek_setfreq(rt, rt->curfreq);
+ gemtek_setfreq(rt, f->frequency);
+
return 0;
}
static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ struct v4l2_frequency *f)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
f->type = V4L2_TUNER_RADIO;
- f->frequency = rt->curfreq;
+ f->frequency = rt->lastfreq;
return 0;
}
static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+ struct v4l2_queryctrl *qc)
{
int i;
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
+ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
return 0;
}
}
@@ -240,7 +478,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
}
static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+ struct v4l2_control *ctrl)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
@@ -260,7 +498,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
}
static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+ struct v4l2_control *ctrl)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
@@ -282,8 +520,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
return -EINVAL;
}
-static int vidioc_g_audio (struct file *file, void *priv,
- struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
if (a->index > 1)
return -EINVAL;
@@ -306,100 +543,102 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
if (a->index != 0)
return -EINVAL;
return 0;
}
-static struct gemtek_device gemtek_unit;
-
-static const struct file_operations gemtek_fops = {
- .owner = THIS_MODULE,
- .open = video_exclusive_open,
- .release = video_exclusive_release,
- .ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
+static struct video_device gemtek_radio = {
+ .owner = THIS_MODULE,
+ .name = "GemTek Radio card",
+ .type = VID_TYPE_TUNER,
+ .hardware = VID_HARDWARE_GEMTEK,
+ .fops = &gemtek_fops,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl
};
-static struct video_device gemtek_radio=
-{
- .owner = THIS_MODULE,
- .name = "GemTek radio",
- .type = VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &gemtek_fops,
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
-};
+/*
+ * Initialization / cleanup related stuff.
+ */
+/*
+ * Initilize card.
+ */
static int __init gemtek_init(void)
{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n");
- return -EINVAL;
- }
+ printk(KERN_INFO RADIO_BANNER "\n");
- if (!request_region(io, 4, "gemtek"))
- {
- printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
- return -EBUSY;
- }
+ spin_lock_init(&lock);
- gemtek_radio.priv=&gemtek_unit;
+ gemtek_probe();
+ if (io) {
+ if (!request_region(io, 1, "gemtek")) {
+ printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
+ return -EBUSY;
+ }
- if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
- release_region(io, 4);
+ if (!gemtek_verify(io))
+ printk(KERN_WARNING "Card at I/O port 0x%x does not "
+ "respond properly, check your "
+ "configuration.\n", io);
+ else
+ printk(KERN_INFO "Using I/O port 0x%x.\n", io);
+ } else if (probe) {
+ printk(KERN_ERR "Automatic probing failed and no "
+ "fixed I/O port defined.\n");
+ return -ENODEV;
+ } else {
+ printk(KERN_ERR "Automatic probing disabled but no fixed "
+ "I/O port defined.");
return -EINVAL;
}
- printk(KERN_INFO "GemTek Radio Card driver.\n");
- spin_lock_init(&lock);
+ gemtek_radio.priv = &gemtek_unit;
- /* this is _maybe_ unnecessary */
- outb(0x01, io);
+ if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
+ radio_nr) == -1) {
+ release_region(io, 1);
+ return -EBUSY;
+ }
- /* mute card - prevents noisy bootups */
- gemtek_unit.muted = 0;
- gemtek_mute(&gemtek_unit);
+ /* Set defaults */
+ gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
+ gemtek_unit.bu2614data = 0;
+
+ if (initmute)
+ gemtek_mute(&gemtek_unit);
return 0;
}
-MODULE_AUTHOR("Jonas Munsin");
-MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
-module_param(radio_nr, int, 0);
-
-static void __exit gemtek_cleanup(void)
+/*
+ * Module cleanup
+ */
+static void __exit gemtek_exit(void)
{
+ if (shutdown) {
+ hardmute = 1; /* Turn off PLL */
+ gemtek_mute(&gemtek_unit);
+ } else {
+ printk(KERN_INFO "Module unloaded but card not muted!\n");
+ }
+
video_unregister_device(&gemtek_radio);
- release_region(io,4);
+ release_region(io, 1);
}
module_init(gemtek_init);
-module_exit(gemtek_cleanup);
-
-/*
- Local variables:
- compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
- End:
-*/
+module_exit(gemtek_exit);
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 9b493b3298cd..82aedfc95d4f 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -297,7 +297,6 @@ static struct video_device rtrack2_radio=
.owner = THIS_MODULE,
.name = "RadioTrack II radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &rtrack2_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index dc33f19c0e2c..395165367f37 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -297,7 +297,6 @@ static struct video_device fmi_radio=
.owner = THIS_MODULE,
.name = "SF16FMx radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &fmi_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index e6c125def5cb..c432c44bd634 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -442,7 +442,6 @@ static struct video_device fmr2_radio=
.owner = THIS_MODULE,
.name = "SF16FMR2 radio",
. type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &fmr2_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index e43acfd7e533..535ffe8c8102 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -173,7 +173,7 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
i--;
p--;
temp = temp/2;
- }
+ }
spin_lock(&lock);
@@ -369,7 +369,6 @@ static struct video_device terratec_radio=
.owner = THIS_MODULE,
.name = "TerraTec ActiveRadio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &terratec_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index c27c629d99df..c11981fed827 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -349,7 +349,6 @@ static struct video_device trust_radio=
.owner = THIS_MODULE,
.name = "Trust FM Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &trust_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 8ff5a23a9f01..1366326474e5 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -349,7 +349,6 @@ static struct video_device typhoon_radio =
.owner = THIS_MODULE,
.name = "Typhoon Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &typhoon_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4d45a40016de..2e571eb9313a 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -148,6 +148,15 @@ config VIDEO_WM8739
To compile this driver as a module, choose M here: the
module will be called wm8739.
+config VIDEO_VP27SMPX
+ tristate "Panasonic VP27s internal MPX"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the internal MPX of the Panasonic VP27s tuner.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vp27smpx.
+
comment "Video decoders"
config VIDEO_BT819
@@ -197,6 +206,13 @@ config VIDEO_OV7670
OV7670 VGA camera. It currently only works with the M88ALP01
controller.
+config VIDEO_TCM825X
+ tristate "TCM825x camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a driver for the Toshiba TCM825x VGA camera sensor.
+ It is used for example in Nokia N800.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L1 && I2C
@@ -348,7 +364,7 @@ endmenu # encoder / decoder chips
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
- select VIDEO_BUF
+ select VIDEOBUF_VMALLOC
default n
---help---
Enables a virtual video driver. This device shows a color bar
@@ -500,7 +516,7 @@ config VIDEO_VINO
config VIDEO_STRADIS
tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && !PPC64
+ depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
help
Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
driver for PCI. There is a product page at
@@ -511,7 +527,7 @@ config VIDEO_ZORAN_ZR36060
config VIDEO_ZORAN
tristate "Zoran ZR36057/36067 Video For Linux"
- depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && !PPC64
+ depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
help
Say Y for support for MJPEG capture cards based on the Zoran
36057/36067 PCI controller chipset. This includes the Iomega
@@ -652,6 +668,8 @@ config VIDEO_HEXIUM_GEMINI
source "drivers/media/video/cx88/Kconfig"
+source "drivers/media/video/cx23885/Kconfig"
+
source "drivers/media/video/ivtv/Kconfig"
config VIDEO_M32R_AR
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9c2de501612f..b5a064163e03 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -4,19 +4,19 @@
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
-tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
- mt20xx.o tda8290.o tea5767.o tda9887.o
+tuner-objs := tuner-core.o tuner-types.o tda9887.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
+ v4l2-int-device.o
ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
endif
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
@@ -59,9 +59,8 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
-obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
@@ -71,6 +70,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -80,8 +80,17 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-obj-$(CONFIG_VIDEO_BUF) += video-buf.o
-obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
+
+obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.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_VIDEOBUF_GEN) += videobuf-core.o
+obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
+obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
@@ -95,6 +104,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
@@ -112,6 +123,9 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 823cd6cc471e..cbab53fc6243 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -38,23 +38,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(x) (x)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 05c7820fe53e..0d0c554bfdf7 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -34,23 +34,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 649f52f9ad27..19e9929ffa0f 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -442,7 +441,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
{
struct video_window *w = arg;
DEBUG(1, "VIDIOCGWIN:\n");
- memset(w, 0, sizeof(w));
+ memset(w, 0, sizeof(*w));
w->width = ar->width;
w->height = ar->height;
return 0;
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 59a43603b5cb..12d1b9248be5 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -38,23 +38,24 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
+
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 853b1a3d6a1d..e1028a76c042 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -38,23 +38,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 2e4cf1efdd21..b767b098d14b 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -257,7 +257,7 @@ static int bt866_write(struct bt866 *encoder,
printk(KERN_WARNING "%s: I/O error #%d "
"(write 0x%02x/0x%02x)\n",
encoder->i2c->name, err, encoder->addr, subaddr);
- schedule_timeout_interruptible(HZ/10);
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
}
if (err == 3) {
printk(KERN_WARNING "%s: giving up\n",
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 58eae887a629..2ca162b390a2 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_BT848
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 6b31e50fb951..dd6a7d68b07f 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -27,12 +27,12 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/firmware.h>
+#include <net/checksum.h>
#include <asm/io.h>
@@ -45,7 +45,7 @@ static void boot_msp34xx(struct bttv *btv, int pin);
static void boot_bt832(struct bttv *btv);
static void hauppauge_eeprom(struct bttv *btv);
static void avermedia_eeprom(struct bttv *btv);
-static void osprey_eeprom(struct bttv *btv);
+static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
static void modtec_eeprom(struct bttv *btv);
static void init_PXC200(struct bttv *btv);
static void init_RTV24(struct bttv *btv);
@@ -178,8 +178,8 @@ static struct CARD {
/* this seems to happen as well ... */
{ 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
- { 0x3000121a, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" },
+ { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" },
{ 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" },
{ 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -313,6 +313,7 @@ static struct CARD {
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
+ { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
{ 0, -1, NULL }
};
@@ -329,7 +330,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -344,7 +345,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 2, 0, 0, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -359,7 +360,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -387,13 +388,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = 4,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -408,7 +409,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 0, 1 },
.gpiomute = 3,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -423,7 +424,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x0c, 0x04, 0x08, 0x04 },
/* 0x04 for some cards ?? */
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = avermedia_tvphone_audio,
@@ -433,13 +434,13 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX-Vision MV-Delta",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -457,7 +458,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -488,7 +489,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 4,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -503,7 +504,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x20001,0x10001, 0, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -519,7 +520,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 13, 14, 11, 7 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -553,7 +554,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 4,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -568,7 +569,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0, 1, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -587,7 +588,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x002000,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
},
[BTTV_BOARD_WINVIEW_601] = {
.name = "Leadtek WinView 601",
@@ -600,7 +601,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
.gpiomute = 0xcfa007,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = winview_audio,
@@ -616,7 +617,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 1, 0, 0, 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -624,13 +625,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
.video_inputs = 4,
.audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x8dff00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.no_msp34xx = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -643,7 +644,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -674,7 +675,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -683,7 +684,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 7,
.muxsel = { 2, 3, -1 },
.digital_mode = DIGITAL_MODE_CAMERA,
@@ -708,7 +709,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -740,7 +741,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -813,13 +814,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Imagenation PXC200",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1, /* was: 4 */
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.gpiomux = { 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = PXC200_muxsel,
@@ -836,7 +837,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x0800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -860,13 +861,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = 4,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -911,7 +912,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.pll = PLL_28,
.has_radio = 1,
- .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = winfast2000_audio,
@@ -928,7 +929,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -945,7 +946,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -962,7 +963,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x29,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -978,7 +979,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x551c00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -995,7 +996,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1030,7 +1031,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 13, 4, 11, 7 },
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -1048,7 +1049,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1063,7 +1064,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
.gpiomute = 0xff3ffc,
.no_msp34xx = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1074,14 +1075,14 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 3,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 1, 1, 0, 2 },
.gpiomute = 3,
.no_msp34xx = 1,
.pll = PLL_NONE,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1089,14 +1090,14 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX-Vision MV-Delta 2",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1112,7 +1113,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xbcb03f,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 21,
+ .tuner_type = TUNER_TEMIC_4039FR5_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1129,7 +1130,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_35,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -1148,7 +1149,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1206,7 +1207,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.pll = PLL_28,
- .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+ .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1234,7 +1235,7 @@ struct tvcard bttv_tvcards[] = {
1= FM stereo Radio from Tuner */
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1277,7 +1278,7 @@ struct tvcard bttv_tvcards[] = {
0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
0x0880: Tuner A2 stereo */
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1313,7 +1314,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1324,7 +1325,7 @@ struct tvcard bttv_tvcards[] = {
.name = "GrandTec 'Grand Video Capture' (Bt848)",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.gpiomask = 0,
.muxsel = { 3, 1 },
@@ -1332,7 +1333,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_35,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1365,7 +1366,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 2, 0, 0, 0 },
.gpiomute = 1,
.pll = PLL_28,
- .tuner_type = 0,
+ .tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1377,7 +1378,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 2,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 11,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 2, 0, 0, 1 },
@@ -1392,7 +1393,7 @@ struct tvcard bttv_tvcards[] = {
.name = "AG Electronics GMV1",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.gpiomask = 0xF,
.muxsel = { 2, 2 },
@@ -1400,7 +1401,7 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1447,7 +1448,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 1,
.muxsel = { 2, 3, 0, 1 },
.gpiomux = { 0, 0, 1, 0 },
@@ -1476,7 +1477,7 @@ struct tvcard bttv_tvcards[] = {
.no_tda9875 = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1517,13 +1518,35 @@ struct tvcard bttv_tvcards[] = {
/* ---- card 0x44 ---------------------------------- */
[BTTV_BOARD_VOODOOTV_FM] = {
- .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+ .name = "3Dfx VoodooTV FM (Euro)",
/* try "insmod msp3400 simple=0" if you have
* sound problems with this card. */
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+ .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff },
+ .gpiomute = 0x947fff,
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+ .muxsel = { 2, 3 ,0 ,1 },
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_VOODOOTV_200] = {
+ .name = "VoodooTV 200 (USA)",
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = UNSET,
.gpiomask = 0x4f8a00,
/* 0x100000: 1=MSP enabled (0=disable again)
* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1543,8 +1566,8 @@ struct tvcard bttv_tvcards[] = {
.name = "Active Imaging AIMMS",
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -1564,7 +1587,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 13,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 25,
+ .tuner_type = TUNER_LG_PAL_I_FM,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -1580,7 +1603,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Lifeview FlyVideo 98EZ (capture only) LR51",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.muxsel = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
.pll = PLL_28,
@@ -1606,7 +1629,7 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.no_tda9875 = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
@@ -1626,13 +1649,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Sensoray 311",
.video_inputs = 5,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 4,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1641,15 +1664,15 @@ struct tvcard bttv_tvcards[] = {
.name = "RemoteVision MX (RV605)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x00,
.gpiomask2 = 0x07ff,
.muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
.no_msp34xx = 1,
.no_tda9875 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = rv605_muxsel,
@@ -1693,15 +1716,15 @@ struct tvcard bttv_tvcards[] = {
.name = "GrandTec Multi Capture Card (Bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1724,7 +1747,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
@@ -1744,10 +1767,10 @@ struct tvcard bttv_tvcards[] = {
/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
.name = "DSP Design TCVIDEO",
.video_inputs = 4,
- .svhs = -1,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1762,7 +1785,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 0, 1, 1 },
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1791,11 +1814,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
.video_inputs = 4, /* id-inputs-clock */
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.muxsel = { 3, 2, 0, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1806,11 +1829,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
.video_inputs = 3,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.muxsel = { 2, 3, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1823,11 +1846,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 3, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1838,11 +1861,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1853,11 +1876,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1868,8 +1891,8 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0 },
.pll = PLL_28,
.tuner_type = UNSET,
@@ -1885,7 +1908,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
@@ -1900,7 +1923,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
@@ -1915,11 +1938,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 500", /* 500 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1930,9 +1953,9 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 540", /* 540 */
.video_inputs = 4,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1945,7 +1968,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 2000", /* 2000 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
@@ -1961,11 +1984,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IDS Eagle",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 0, 1, 2, 3 },
.muxsel_hook = eagle_muxsel,
@@ -1978,8 +2001,8 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 0,
.svhs = 1,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -2020,13 +2043,13 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.gpiomux = { 0, 1, 2, 3},
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2035,7 +2058,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Euresys Picolo",
.video_inputs = 3,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.no_msp34xx = 1,
@@ -2052,8 +2075,8 @@ struct tvcard bttv_tvcards[] = {
.name = "ProVideo PV150", /* 0x4f */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3 },
.gpiomux = { 0 },
@@ -2080,7 +2103,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 2,
+ .tuner_type = TUNER_PHILIPS_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = adtvk503_audio,
@@ -2098,7 +2121,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Notes:
@@ -2121,7 +2144,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -2138,11 +2161,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IVC-200",
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xdf,
.muxsel = { 2 },
.pll = PLL_28,
@@ -2151,9 +2174,9 @@ struct tvcard bttv_tvcards[] = {
.name = "Grand X-Guard / Trust 814PCI",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = 4,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.gpiomask2 = 0xff,
@@ -2169,14 +2192,14 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_NEBULA_DIGITV] = {
.name = "Nebula Electronics DigiTV",
.video_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2189,15 +2212,15 @@ struct tvcard bttv_tvcards[] = {
.name = "ProVideo PV143",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2206,14 +2229,14 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2221,14 +2244,14 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009-X1 Combi (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2238,7 +2261,7 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009 MiniDIN (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2248,7 +2271,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2256,7 +2279,7 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009 Combi (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2266,7 +2289,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2274,11 +2297,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IVC-100",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xdf,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
@@ -2288,11 +2311,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IVC-120G",
.video_inputs = 16,
.audio_inputs = 0, /* card has no audio */
- .tuner = -1, /* card has no tuner */
- .tuner_type = -1,
+ .tuner = UNSET, /* card has no tuner */
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1, /* card has no svhs */
+ .svhs = UNSET, /* card has no svhs */
.needs_tvaudio = 0,
.no_msp34xx = 1,
.no_tda9875 = 1,
@@ -2333,7 +2356,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 3,
.audio_inputs = 0,
.svhs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.muxsel = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
.no_msp34xx = 1,
.no_tda9875 = 1,
@@ -2364,9 +2387,9 @@ struct tvcard bttv_tvcards[] = {
.name = "SIMUS GVC1100",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2395,14 +2418,14 @@ struct tvcard bttv_tvcards[] = {
.name = "LMLBT4",
.video_inputs = 4, /* IN1,IN2,IN3,IN4 */
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.needs_tvaudio = 0,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2452,8 +2475,8 @@ struct tvcard bttv_tvcards[] = {
.name = "Euresys Picolo Tetra",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
.no_msp34xx = 1,
@@ -2464,7 +2487,7 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.needs_tvaudio = 0,
.muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2490,7 +2513,7 @@ struct tvcard bttv_tvcards[] = {
.name = "AVerMedia AVerTV DVB-T 771",
.video_inputs = 2,
.svhs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2509,14 +2532,14 @@ struct tvcard bttv_tvcards[] = {
/* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
.name = "AverMedia AverTV DVB-T 761",
.video_inputs = 2,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2528,8 +2551,8 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX Vision Sigma-SQ",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0,
.muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2537,7 +2560,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2546,15 +2569,15 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX Vision Sigma-SLC",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0,
.muxsel = { 2, 2, 2, 2 },
.muxsel_hook = sigmaSLC_muxsel,
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2566,7 +2589,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xFF,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 2, 0, 0, 0 },
@@ -2584,14 +2607,14 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_DVICO_DVBT_LITE] = {
/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
.name = "DViCO FusionHDTV DVB-T Lite",
- .tuner = -1,
+ .tuner = UNSET,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.no_video = 1,
.has_dvb = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2634,14 +2657,14 @@ struct tvcard bttv_tvcards[] = {
.name = "Tibet Systems 'Progress DVR' CS16",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = tibetCS16_muxsel,
@@ -2661,11 +2684,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Kodicom 4400R (master)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
/* GPIO bits 0-9 used for analog switch:
* 00 - 03: camera selector
* 04 - 06: channel (controller) selector
@@ -2693,11 +2716,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Kodicom 4400R (slave)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0x010000,
.no_gpioirq = 1,
.muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2717,7 +2740,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2820,13 +2843,28 @@ struct tvcard bttv_tvcards[] = {
.has_remote = 1,
},
/* ---- card 0x8c ---------------------------------- */
+ /* Has four Bt878 chips behind a PCI bridge, each chip has:
+ one external BNC composite input (mux 2)
+ three internal composite inputs (unknown muxes)
+ an 18-bit stereo A/D (CS5331A), which has:
+ one external stereo unblanced (RCA) audio connection
+ one (or 3?) internal stereo balanced (XLR) audio connection
+ input is selected via gpio to a 14052B mux
+ (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300)
+ gain is controlled via an X9221A chip on the I2C bus @0x28
+ sample rate is controlled via gpio to an MK1413S
+ (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3)
+ There is neither a tuner nor an svideo input. */
[BTTV_BOARD_OSPREY440] = {
.name = "Osprey 440",
- .video_inputs = 1,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 2 },
+ .video_inputs = 4,
+ .audio_inputs = 2, /* this is meaningless */
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .muxsel = { 2, 3, 0, 1 }, /* 3,0,1 are guesses */
+ .gpiomask = 0x303,
+ .gpiomute = 0x000, /* int + 32kHz */
+ .gpiomux = { 0, 0, 0x000, 0x100},
.pll = PLL_28,
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
@@ -2848,7 +2886,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 2,
+ .tuner_type = TUNER_PHILIPS_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2875,14 +2913,14 @@ struct tvcard bttv_tvcards[] = {
.name = "Hauppauge ImpactVCB (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0f, /* old: 7 */
.muxsel = { 0, 1, 3, 2 }, /* Composite 0-3 */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2914,10 +2952,10 @@ struct tvcard bttv_tvcards[] = {
.name = "SSAI Security Video Interface",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0, 1, 2, 3 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2925,12 +2963,47 @@ struct tvcard bttv_tvcards[] = {
.name = "SSAI Ultrasound Video Interface",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 0, 1, 3 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ /* ---- card 0x94---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+ .name = "DViCO FusionHDTV 2",
+ .tuner = 0,
+ .tuner_type = TUNER_PHILIPS_ATSC, /* FCV1236D */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1 },
+ .gpiomask = 0x00e00007,
+ .gpiomux = { 0x00400005, 0, 0x00000001, 0 },
+ .gpiomute = 0x00c00007,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ /* ---- card 0x95---------------------------------- */
+ [BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
+ .name = "Typhoon TV-Tuner PCI (50684)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3014f,
+ .muxsel = { 2, 3, 1, 1 },
+ .gpiomux = { 0x20001,0x10001, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
},
};
@@ -3040,7 +3113,7 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
static void flyvideo_gpio(struct bttv *btv)
{
int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
- int tuner=-1,ttype;
+ int tuner=UNSET,ttype;
gpio_inout(0xffffff, 0);
udelay(8); /* without this we would see the 0x1800 mask */
@@ -3085,7 +3158,7 @@ static void flyvideo_gpio(struct bttv *btv)
* gpio & 0x001000 output bit for audio routing */
if(is_capture_only)
- tuner=4; /* No tuner present */
+ tuner = TUNER_ABSENT; /* No tuner present */
printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
@@ -3093,7 +3166,7 @@ static void flyvideo_gpio(struct bttv *btv)
btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
is_capture_only?"yes":"no ");
- if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+ if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
btv->tuner_type = tuner;
btv->has_radio = has_radio;
@@ -3219,15 +3292,15 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
btaor((2)<<5, ~(3<<5), BT848_IFORM);
gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
- /* composite */
- /* set chroma ADC to sleep */
- btor(BT848_ADC_C_SLEEP, BT848_ADC);
- /* set to composite video */
- btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
- btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+ /* composite */
+ /* set chroma ADC to sleep */
+ btor(BT848_ADC_C_SLEEP, BT848_ADC);
+ /* set to composite video */
+ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+ btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
- /* switch sync drive off */
- gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+ /* switch sync drive off */
+ gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
}
static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
@@ -3302,6 +3375,7 @@ void __devinit bttv_init_card1(struct bttv *btv)
case BTTV_BOARD_HAUPPAUGE878:
boot_msp34xx(btv,5);
break;
+ case BTTV_BOARD_VOODOOTV_200:
case BTTV_BOARD_VOODOOTV_FM:
boot_msp34xx(btv,20);
break;
@@ -3328,10 +3402,9 @@ void __devinit bttv_init_card1(struct bttv *btv)
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
- int tda9887;
int addr=ADDR_UNSET;
- btv->tuner_type = -1;
+ btv->tuner_type = UNSET;
if (BTTV_BOARD_UNKNOWN == btv->c.type) {
bttv_readee(btv,eeprom_data,0xa0);
@@ -3396,7 +3469,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
}
break;
- case BTTV_BOARD_STB2:
+ case BTTV_BOARD_STB2:
if (btv->cardid == 0x3060121a) {
/* Fix up entry for 3DFX VoodooTV 100,
which is an OEM STB card variant. */
@@ -3412,11 +3485,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
case BTTV_BOARD_OSPREY2xx:
case BTTV_BOARD_OSPREY2x0_SVID:
case BTTV_BOARD_OSPREY2x0:
+ case BTTV_BOARD_OSPREY440:
case BTTV_BOARD_OSPREY500:
case BTTV_BOARD_OSPREY540:
case BTTV_BOARD_OSPREY2000:
bttv_readee(btv,eeprom_data,0xa0);
- osprey_eeprom(btv);
+ osprey_eeprom(btv, eeprom_data);
break;
case BTTV_BOARD_IDS_EAGLE:
init_ids_eagle(btv);
@@ -3479,7 +3553,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
if (UNSET != tuner[btv->c.nr])
btv->tuner_type = tuner[btv->c.nr];
- printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+ if (btv->tuner_type == TUNER_ABSENT ||
+ bttv_tvcards[btv->c.type].tuner == UNSET)
+ printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+ else if(btv->tuner_type == UNSET)
+ printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+ else
+ printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+ btv->tuner_type);
if (btv->tuner_type != UNSET) {
struct tuner_setup tun_setup;
@@ -3521,6 +3603,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (!autoload)
return;
+ if (bttv_tvcards[btv->c.type].tuner == UNSET)
+ return; /* no tuner or related drivers to load */
+
/* try to detect audio/fader chips */
if (!bttv_tvcards[btv->c.type].no_msp34xx &&
bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
@@ -3541,17 +3626,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->c.type].needs_tvaudio)
request_module("tvaudio");
- /* tuner modules */
- tda9887 = 0;
- if (btv->tda9887_conf)
- tda9887 = 1;
- if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
- bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
- tda9887 = 1;
- /* Hybrid DVB card, DOES have a tda9887 */
- if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
- tda9887 = 1;
- if (btv->tuner_type != UNSET)
+ if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
request_module("tuner");
}
@@ -3706,106 +3781,119 @@ static int __devinit pvr_boot(struct bttv *btv)
/* ----------------------------------------------------------------------- */
/* some osprey specific stuff */
-static void __devinit osprey_eeprom(struct bttv *btv)
+static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
{
- int i = 0;
- unsigned char *ee = eeprom_data;
- unsigned long serial = 0;
-
- if (btv->c.type == 0) {
- /* this might be an antique... check for MMAC label in eeprom */
- if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
- unsigned char checksum = 0;
- for (i = 0; i < 21; i++)
- checksum += ee[i];
- if (checksum != ee[21])
- return;
- btv->c.type = BTTV_BOARD_OSPREY1x0_848;
- for (i = 12; i < 21; i++)
- serial *= 10, serial += ee[i] - '0';
- }
- } else {
- unsigned short type;
- int offset = 4*16;
-
- for (; offset < 8*16; offset += 16) {
- unsigned short checksum = 0;
- /* verify the checksum */
- for (i = 0; i < 14; i++)
- checksum += ee[i+offset];
- checksum = ~checksum; /* no idea why */
- if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
- ((checksum & 0x0FF) == ee[offset+15])) {
- break;
- }
- }
-
- if (offset >= 8*16)
- return;
-
- /* found a valid descriptor */
- type = (ee[offset+4]<<8) | (ee[offset+5]);
-
- switch(type) {
- /* 848 based */
- case 0x0004:
- btv->c.type = BTTV_BOARD_OSPREY1x0_848;
- break;
- case 0x0005:
- btv->c.type = BTTV_BOARD_OSPREY101_848;
- break;
-
- /* 878 based */
- case 0x0012:
- case 0x0013:
- btv->c.type = BTTV_BOARD_OSPREY1x0;
- break;
- case 0x0014:
- case 0x0015:
- btv->c.type = BTTV_BOARD_OSPREY1x1;
- break;
- case 0x0016:
- case 0x0017:
- case 0x0020:
- btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
- break;
- case 0x0018:
- case 0x0019:
- case 0x001E:
- case 0x001F:
- btv->c.type = BTTV_BOARD_OSPREY2xx;
- break;
- case 0x001A:
- case 0x001B:
- btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
- break;
- case 0x0040:
- btv->c.type = BTTV_BOARD_OSPREY500;
- break;
- case 0x0050:
- case 0x0056:
- btv->c.type = BTTV_BOARD_OSPREY540;
- /* bttv_osprey_540_init(btv); */
- break;
- case 0x0060:
- case 0x0070:
- case 0x00A0:
- btv->c.type = BTTV_BOARD_OSPREY2x0;
- /* enable output on select control lines */
- gpio_inout(0xffffff,0x000303);
- break;
- default:
- /* unknown...leave generic, but get serial # */
- break;
- }
- serial = (ee[offset+6] << 24)
- | (ee[offset+7] << 16)
- | (ee[offset+8] << 8)
- | (ee[offset+9]);
- }
-
- printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
- btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial);
+ int i;
+ u32 serial = 0;
+ int cardid = -1;
+
+ /* This code will nevery actually get called in this case.... */
+ if (btv->c.type == BTTV_BOARD_UNKNOWN) {
+ /* this might be an antique... check for MMAC label in eeprom */
+ if (!strncmp(ee, "MMAC", 4)) {
+ u8 checksum = 0;
+ for (i = 0; i < 21; i++)
+ checksum += ee[i];
+ if (checksum != ee[21])
+ return;
+ cardid = BTTV_BOARD_OSPREY1x0_848;
+ for (i = 12; i < 21; i++)
+ serial *= 10, serial += ee[i] - '0';
+ }
+ } else {
+ unsigned short type;
+
+ for (i = 4*16; i < 8*16; i += 16) {
+ u16 checksum = ip_compute_csum(ee + i, 16);
+
+ if ((checksum&0xff) + (checksum>>8) == 0xff)
+ break;
+ }
+ if (i >= 8*16)
+ return;
+ ee += i;
+
+ /* found a valid descriptor */
+ type = be16_to_cpup((u16*)(ee+4));
+
+ switch(type) {
+ /* 848 based */
+ case 0x0004:
+ cardid = BTTV_BOARD_OSPREY1x0_848;
+ break;
+ case 0x0005:
+ cardid = BTTV_BOARD_OSPREY101_848;
+ break;
+
+ /* 878 based */
+ case 0x0012:
+ case 0x0013:
+ cardid = BTTV_BOARD_OSPREY1x0;
+ break;
+ case 0x0014:
+ case 0x0015:
+ cardid = BTTV_BOARD_OSPREY1x1;
+ break;
+ case 0x0016:
+ case 0x0017:
+ case 0x0020:
+ cardid = BTTV_BOARD_OSPREY1x1_SVID;
+ break;
+ case 0x0018:
+ case 0x0019:
+ case 0x001E:
+ case 0x001F:
+ cardid = BTTV_BOARD_OSPREY2xx;
+ break;
+ case 0x001A:
+ case 0x001B:
+ cardid = BTTV_BOARD_OSPREY2x0_SVID;
+ break;
+ case 0x0040:
+ cardid = BTTV_BOARD_OSPREY500;
+ break;
+ case 0x0050:
+ case 0x0056:
+ cardid = BTTV_BOARD_OSPREY540;
+ /* bttv_osprey_540_init(btv); */
+ break;
+ case 0x0060:
+ case 0x0070:
+ case 0x00A0:
+ cardid = BTTV_BOARD_OSPREY2x0;
+ /* enable output on select control lines */
+ gpio_inout(0xffffff,0x000303);
+ break;
+ case 0x00D8:
+ cardid = BTTV_BOARD_OSPREY440;
+ break;
+ default:
+ /* unknown...leave generic, but get serial # */
+ printk(KERN_INFO "bttv%d: "
+ "osprey eeprom: unknown card type 0x%04x\n",
+ btv->c.nr, type);
+ break;
+ }
+ serial = be32_to_cpup((u32*)(ee+6));
+ }
+
+ printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
+ btv->c.nr, cardid,
+ cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial);
+
+ if (cardid<0 || btv->c.type == cardid)
+ return;
+
+ /* card type isn't set correctly */
+ if (card[btv->c.nr] < bttv_num_tvcards) {
+ printk(KERN_WARNING "bttv%d: osprey eeprom: "
+ "Not overriding user specified card type\n", btv->c.nr);
+ } else {
+ printk(KERN_INFO "bttv%d: osprey eeprom: "
+ "Changing card type from %d to %d\n", btv->c.nr,
+ btv->c.type, cardid);
+ btv->c.type = cardid;
+ }
}
/* ----------------------------------------------------------------------- */
@@ -3865,11 +3953,15 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
if(norm==VIDEO_MODE_NTSC) {
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
dprintk("bttv_tda9880_setnorm to NTSC\n");
}
else {
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
dprintk("bttv_tda9880_setnorm to PAL\n");
}
/* set GPIO according */
@@ -4163,7 +4255,7 @@ static int tea5757_read(struct bttv *btv)
bus_low(btv,btv->mbox_clk);
udelay(10);
- timeout= jiffies + HZ;
+ timeout= jiffies + msecs_to_jiffies(1000);
/* wait for DATA line to go low; error if it doesn't */
while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index b1fedb0f6431..7a332b3efe51 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -30,7 +30,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -155,13 +154,14 @@ MODULE_LICENSE("GPL");
/* ----------------------------------------------------------------------- */
/* sysfs */
-static ssize_t show_card(struct class_device *cd, char *buf)
+static ssize_t show_card(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vfd = to_video_device(cd);
struct bttv *btv = dev_get_drvdata(vfd->dev);
return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
}
-static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
/* ----------------------------------------------------------------------- */
/* dvb auto-load setup */
@@ -1218,7 +1218,14 @@ audio_mux(struct bttv *btv, int input, int mute)
break;
case TVAUDIO_INPUT_TUNER:
default:
- route.input = MSP_INPUT_DEFAULT;
+ /* This is the only card that uses TUNER2, and afaik,
+ is the only difference between the VOODOOTV_FM
+ and VOODOOTV_200 */
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+ route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+ MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+ else
+ route.input = MSP_INPUT_DEFAULT;
break;
}
route.output = MSP_OUTPUT_DEFAULT;
@@ -1253,7 +1260,7 @@ i2c_vidiocschan(struct bttv *btv)
v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
- if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
bttv_tda9880_setnorm(btv,btv->tvnorm);
}
@@ -1323,6 +1330,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
switch (btv->c.type) {
case BTTV_BOARD_VOODOOTV_FM:
+ case BTTV_BOARD_VOODOOTV_200:
bttv_tda9880_setnorm(btv,norm);
break;
}
@@ -2251,6 +2259,24 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* bt848 has a 12-bit register space */
+ reg->reg &= 0xfff;
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = btread(reg->reg);
+ else
+ btwrite(reg->val, reg->reg);
+ return 0;
+ }
+#endif
default:
return -ENOIOCTLCMD;
@@ -2557,7 +2583,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
- new = videobuf_alloc(sizeof(*new));
+ new = videobuf_pci_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
@@ -3023,7 +3049,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
mutex_lock(&fh->cap.lock);
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
- new = videobuf_alloc(sizeof(*new));
+ new = videobuf_pci_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
@@ -3046,6 +3072,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
V4L2_MEMORY_MMAP);
if (retval < 0)
goto fh_unlock_and_return;
+
+ gbuffers = retval;
memset(mbuf,0,sizeof(*mbuf));
mbuf->frames = gbuffers;
mbuf->size = gbuffers * gbufsize;
@@ -3116,9 +3144,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
retval = -EIO;
/* fall through */
case STATE_DONE:
- videobuf_dma_sync(&fh->cap,&buf->vb.dma);
+ {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ videobuf_dma_sync(&fh->cap,dma);
bttv_dma_free(&fh->cap,btv,buf);
break;
+ }
default:
retval = -EINVAL;
break;
@@ -3312,7 +3343,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
- new = videobuf_alloc(sizeof(*new));
+ new = videobuf_pci_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
retval = bttv_switch_overlay(btv,fh,new);
@@ -3561,6 +3592,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
case VIDIOC_LOG_STATUS:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -3669,7 +3702,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
mutex_unlock(&fh->cap.lock);
return POLLERR;
}
- fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
+ fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf) {
mutex_unlock(&fh->cap.lock);
return POLLERR;
@@ -3736,13 +3769,13 @@ static int bttv_open(struct inode *inode, struct file *file)
fh->ov.setup_ok = 0;
v4l2_prio_open(&btv->prio,&fh->prio);
- videobuf_queue_init(&fh->cap, &bttv_video_qops,
+ videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
btv->c.pci, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
fh);
- videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
+ videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
btv->c.pci, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
@@ -3943,6 +3976,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOC_LOG_STATUS:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -4583,9 +4618,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
btv->c.nr,btv->video_dev->minor & 0x1f);
- if (class_device_create_file(&btv->video_dev->class_dev,
- &class_device_attr_card)<0) {
- printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+ if (device_create_file(&btv->video_dev->class_dev,
+ &dev_attr_card)<0) {
+ printk(KERN_ERR "bttv%d: device_create_file 'card' "
"failed\n", btv->c.nr);
goto err;
}
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index 84154c26f9c5..dce6dae5740e 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -106,11 +106,9 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
int bttv_sub_del_devices(struct bttv_core *core)
{
- struct bttv_sub_device *sub;
- struct list_head *item,*save;
+ struct bttv_sub_device *sub, *save;
- list_for_each_safe(item,save,&core->subs) {
- sub = list_entry(item,struct bttv_sub_device,list);
+ list_for_each_entry_safe(sub, save, &core->subs, list) {
list_del(&sub->list);
device_unregister(&sub->dev);
}
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 0dfa49b66418..844f1762c45a 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 6f74c8042bc3..e7c521b8444a 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -19,7 +19,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -153,7 +152,7 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
- ir->timer.expires = jiffies + HZ;
+ ir->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
@@ -313,7 +312,7 @@ int bttv_input_init(struct bttv *btv)
input_dev->id.vendor = btv->c.pci->vendor;
input_dev->id.product = btv->c.pci->device;
}
- input_dev->cdev.dev = &btv->c.pci->dev;
+ input_dev->dev.parent = &btv->c.pci->dev;
btv->remote = ir;
bttv_ir_start(btv, ir);
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index e7104d9cb4bd..58986f1a5f1a 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -574,10 +574,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
void
bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
btcx_riscmem_free(btv->c.pci,&buf->bottom);
btcx_riscmem_free(btv->c.pci,&buf->top);
buf->vb.state = STATE_NEEDS_INIT;
@@ -699,6 +701,7 @@ int
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
{
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
dprintk(KERN_DEBUG
"bttv%d: buffer field: %s format: %s size: %dx%d\n",
@@ -716,25 +719,25 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
- bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->top,dma->sglist,
/* offset */ 0,bpl,
/* padding */ 0,/* skip_lines */ 0,
buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
- bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->bottom,dma->sglist,
0,bpl,0,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
- bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->top,dma->sglist,
0,bpl,bpl,0,buf->vb.height >> 1);
- bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->bottom,dma->sglist,
bpl,bpl,bpl,0,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
- bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->top,dma->sglist,
0,bpl,0,0,buf->vb.height >> 1);
- bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->bottom,dma->sglist,
bpf,bpl,0,0,buf->vb.height >> 1);
break;
default:
@@ -767,7 +770,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,/* both_fields */ 0,
tvnorm,&buf->crop);
- bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
+ bttv_risc_planar(btv, &buf->top, dma->sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
@@ -776,7 +779,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,
tvnorm,&buf->crop);
- bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
+ bttv_risc_planar(btv, &buf->bottom, dma->sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
@@ -789,14 +792,14 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
- buf->vb.dma.sglist,
+ dma->sglist,
0,buf->vb.width,ypadding,lines,
uoffset,voffset,
buf->fmt->hshift,
buf->fmt->vshift,
cpadding);
bttv_risc_planar(btv,&buf->bottom,
- buf->vb.dma.sglist,
+ dma->sglist,
ypadding,buf->vb.width,ypadding,lines,
uoffset+cpadding,
voffset+cpadding,
@@ -812,7 +815,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
- buf->vb.dma.sglist,
+ dma->sglist,
0,buf->vb.width,0,lines,
uoffset >> 1,
voffset >> 1,
@@ -820,7 +823,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
buf->fmt->vshift,
0);
bttv_risc_planar(btv,&buf->bottom,
- buf->vb.dma.sglist,
+ dma->sglist,
lines * ypadding,buf->vb.width,0,lines,
lines * ypadding + (uoffset >> 1),
lines * ypadding + (voffset >> 1),
@@ -839,10 +842,10 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
1,tvnorm,&buf->crop);
- bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
+ bttv_risc_packed(btv, &buf->top, dma->sglist,
/* offset */ 0, RAW_BPL, /* padding */ 0,
/* skip_lines */ 0, RAW_LINES);
- bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
+ bttv_risc_packed(btv, &buf->bottom, dma->sglist,
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
}
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 93e35de5a181..346ce019bdcb 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -151,13 +150,14 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
if (redo_dma_risc) {
unsigned int bpl, padding, offset;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
bpl = 2044; /* max. vbipack */
padding = VBI_BPL - bpl;
if (fh->vbi_fmt.fmt.count[0] > 0) {
rc = bttv_risc_packed(btv, &buf->top,
- buf->vb.dma.sglist,
+ dma->sglist,
/* offset */ 0, bpl,
padding, skip_lines0,
fh->vbi_fmt.fmt.count[0]);
@@ -169,7 +169,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
rc = bttv_risc_packed(btv, &buf->bottom,
- buf->vb.dma.sglist,
+ dma->sglist,
offset, bpl,
padding, skip_lines1,
fh->vbi_fmt.fmt.count[1]);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f821ba69db99..19e75d50a107 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -170,6 +170,10 @@
#define BTTV_BOARD_MACHTV_MAGICTV 0x90
#define BTTV_BOARD_SSAI_SECURITY 0x91
#define BTTV_BOARD_SSAI_ULTRASOUND 0x92
+#define BTTV_BOARD_VOODOOTV_200 0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94
+#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95
+
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 8f44f02029be..0b92c35a8435 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,15 +33,15 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
-#include <media/v4l2-common.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
+#include <media/v4l2-common.h>
#include <linux/device.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/ir-common.h>
@@ -284,8 +284,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
-#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE (HZ) /* one second */
+#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */
struct bttv_pll_info {
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index b4aca7249276..ce0840ccd594 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -23,7 +23,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 7d47cbe6ad25..7f7e3d3398d0 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -104,6 +104,17 @@ static inline void write_lpdata(struct qcam_device *q, int d)
static inline void write_lpcontrol(struct qcam_device *q, int d)
{
+ if (d & 0x20) {
+ /* Set bidirectional mode to reverse (data in) */
+ parport_data_reverse(q->pport);
+ } else {
+ /* Set bidirectional mode to forward (data out) */
+ parport_data_forward(q->pport);
+ }
+
+ /* Now issue the regular port command, but strip out the
+ * direction flag */
+ d &= ~0x20;
parport_write_control(q->pport, d);
}
@@ -344,10 +355,13 @@ static int qc_detect(struct qcam_device *q)
/* Be (even more) liberal in what you accept... */
/* if (count > 30 && count < 200) */
- if (count > 20 && count < 300)
+ if (count > 20 && count < 400) {
return 1; /* found */
- else
+ } else {
+ printk(KERN_ERR "No Quickcam found on port %s\n",
+ q->pport->name);
return 0; /* not found */
+ }
}
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 925ff17efbbc..f76c6a6c3766 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -95,7 +95,7 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+ for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
if (qcam_ready1(qcam) == value)
return 0;
@@ -120,7 +120,7 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+ for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
if (qcam_ready2(qcam) == value)
return 0;
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index c08f650df423..b63cab336920 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h>
@@ -63,13 +62,13 @@ MODULE_SUPPORTED_DEVICE("Video");
*/
#define MAX_DMA_BUFS 3
-static int alloc_bufs_at_load = 0;
-module_param(alloc_bufs_at_load, bool, 0444);
-MODULE_PARM_DESC(alloc_bufs_at_load,
- "Non-zero value causes DMA buffers to be allocated at module "
- "load time. This increases the chances of successfully getting "
- "those buffers, but at the cost of nailing down the memory from "
- "the outset.");
+static int alloc_bufs_at_read = 0;
+module_param(alloc_bufs_at_read, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_read,
+ "Non-zero value causes DMA buffers to be allocated when the "
+ "video capture device is read, rather than at module load "
+ "time. This saves memory, but decreases the chances of "
+ "successfully getting those buffers.");
static int n_dma_bufs = 3;
module_param(n_dma_bufs, uint, 0644);
@@ -356,6 +355,7 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
{
unsigned int rval;
unsigned long flags;
+ DEFINE_WAIT(the_wait);
spin_lock_irqsave(&cam->dev_lock, flags);
rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
@@ -369,10 +369,29 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
cafe_reg_write(cam, REG_TWSIC1, rval);
spin_unlock_irqrestore(&cam->dev_lock, flags);
- msleep(2); /* Required or things flake */
+ /*
+ * Time to wait for the write to complete. THIS IS A RACY
+ * WAY TO DO IT, but the sad fact is that reading the TWSIC1
+ * register too quickly after starting the operation sends
+ * the device into a place that may be kinder and better, but
+ * which is absolutely useless for controlling the sensor. In
+ * practice we have plenty of time to get into our sleep state
+ * before the interrupt hits, and the worst case is that we
+ * time out and then see that things completed, so this seems
+ * the best way for now.
+ */
+ do {
+ prepare_to_wait(&cam->smbus_wait, &the_wait,
+ TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1); /* even 1 jiffy is too long */
+ finish_wait(&cam->smbus_wait, &the_wait);
+ } while (!cafe_smbus_write_done(cam));
+
+#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
CAFE_SMBUS_TIMEOUT);
+#endif
spin_lock_irqsave(&cam->dev_lock, flags);
rval = cafe_reg_read(cam, REG_TWSIC1);
spin_unlock_irqrestore(&cam->dev_lock, flags);
@@ -710,7 +729,7 @@ static void cafe_ctlr_init(struct cafe_camera *cam)
* Here we must wait a bit for the controller to come around.
*/
spin_unlock_irqrestore(&cam->dev_lock, flags);
- mdelay(5); /* FIXME revisit this */
+ msleep(5);
spin_lock_irqsave(&cam->dev_lock, flags);
cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
@@ -1178,7 +1197,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
buf->v4lbuf.field = V4L2_FIELD_NONE;
buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
/*
- * Offset: must be 32-bit even on a 64-bit system. video-buf
+ * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg
* just uses the length times the index, but the spec warns
* against doing just that - vma merging problems. So we
* leave a gap between each pair of buffers.
@@ -1483,7 +1502,7 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp)
}
if (cam->users == 0) {
cafe_ctlr_power_down(cam);
- if (! alloc_bufs_at_load)
+ if (alloc_bufs_at_read)
cafe_free_dma_bufs(cam);
}
mutex_unlock(&cam->s_mutex);
@@ -2142,7 +2161,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
/*
* If so requested, try to get our DMA buffers now.
*/
- if (alloc_bufs_at_load) {
+ if (!alloc_bufs_at_read) {
if (cafe_alloc_dma_bufs(cam, 1))
cam_warn(cam, "Unable to alloc DMA buffers at load"
" will try again later.");
@@ -2233,12 +2252,21 @@ static int cafe_pci_resume(struct pci_dev *pdev)
if (ret)
return ret;
ret = pci_enable_device(pdev);
+
if (ret) {
cam_warn(cam, "Unable to re-enable device on resume!\n");
return ret;
}
cafe_ctlr_init(cam);
- cafe_ctlr_power_up(cam);
+ cafe_ctlr_power_down(cam);
+
+ mutex_lock(&cam->s_mutex);
+ if (cam->users > 0) {
+ cafe_ctlr_power_up(cam);
+ __cafe_cam_reset(cam);
+ }
+ mutex_unlock(&cam->s_mutex);
+
set_bit(CF_CONFIG_NEEDED, &cam->flags);
if (cam->state == S_SPECREAD)
cam->state = S_IDLE; /* Don't bother restarting */
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index f065ad12cc61..cefd1381e8de 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -848,6 +848,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOCSFREQ32:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
+ case VIDIOCGVBIFMT:
+ case VIDIOCSVBIFMT:
#endif
case VIDIOC_QUERYCAP:
case VIDIOC_ENUM_FMT:
@@ -874,7 +876,10 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_ENUMINPUT:
case VIDIOC_ENUMINPUT32:
case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
case VIDIOC_S_CTRL32:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_G_FREQUENCY:
case VIDIOC_QUERYCTRL:
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 78c9699eafbb..a1d02e5ce0fd 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index fd771c7a2fe2..a76bd786cf13 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -663,15 +663,13 @@ int cpia2_reset_camera(struct camera_data *cam)
cpia2_send_command(cam, &cmd);
}
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
if (cam->params.pnp_id.device_type == DEVICE_STV_672)
retval = apply_vp_patch(cam);
/* wait for vp to go to sleep */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
/***
* If this is a 676, apply VP5 fixes before we start streaming
@@ -720,8 +718,7 @@ int cpia2_reset_camera(struct camera_data *cam)
set_default_user_mode(cam);
/* Give VP time to wake up */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
set_all_properties(cam);
@@ -2227,15 +2224,13 @@ struct camera_data *cpia2_init_camera_struct(void)
{
struct camera_data *cam;
- cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
if (!cam) {
ERR("couldn't kmalloc cpia2 struct\n");
return NULL;
}
- /* Default everything to 0 */
- memset(cam, 0, sizeof(struct camera_data));
cam->present = 1;
mutex_init(&cam->busy_lock);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 1bda7ad9de11..e3aaba1e0e0a 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -37,7 +37,6 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
#include "cpia2.h"
#include "cpia2dev.h"
@@ -105,7 +104,7 @@ static struct control_menu_info framerate_controls[] =
{ CPIA2_VP_FRAMERATE_25, "25 fps" },
{ CPIA2_VP_FRAMERATE_30, "30 fps" },
};
-#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
static struct control_menu_info flicker_controls[] =
{
@@ -113,7 +112,7 @@ static struct control_menu_info flicker_controls[] =
{ FLICKER_50, "50 Hz" },
{ FLICKER_60, "60 Hz" },
};
-#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
static struct control_menu_info lights_controls[] =
{
@@ -122,7 +121,7 @@ static struct control_menu_info lights_controls[] =
{ 128, "Bottom" },
{ 192, "Both" },
};
-#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
#define GPIO_LIGHTS_MASK 192
static struct v4l2_queryctrl controls[] = {
@@ -235,7 +234,7 @@ static struct v4l2_queryctrl controls[] = {
.default_value = 0,
},
};
-#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+#define NUM_CONTROLS (ARRAY_SIZE(controls))
/******************************************************************************
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index d73c86aeeaac..62304255dcae 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -191,17 +190,21 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
/* Map the control ID to the correct field in the cx2341x_mpeg_params
struct. Return -EINVAL if the ID is unknown, else return 0. */
-static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ if (busy)
+ return -EBUSY;
params->audio_sampling_freq = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
params->audio_encoding = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ if (busy)
+ return -EBUSY;
params->audio_l2_bitrate = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_MODE:
@@ -246,6 +249,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
params->video_gop_closure = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (busy)
+ return -EBUSY;
/* MPEG-1 only allows CBR */
if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
@@ -253,9 +258,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
params->video_bitrate_mode = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
+ if (busy)
+ return -EBUSY;
params->video_bitrate = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ if (busy)
+ return -EBUSY;
params->video_bitrate_peak = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
@@ -268,6 +277,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
params->video_mute_yuv = ctrl->value;
break;
case V4L2_CID_MPEG_STREAM_TYPE:
+ if (busy)
+ return -EBUSY;
params->stream_type = ctrl->value;
params->video_encoding =
(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
@@ -632,7 +643,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
(params->audio_crc << 14);
}
-int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_controls *ctrls, unsigned int cmd)
{
int err = 0;
@@ -664,7 +675,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
if (err)
break;
- err = cx2341x_set_ctrl(params, ctrl);
+ err = cx2341x_set_ctrl(params, busy, ctrl);
if (err)
break;
}
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
new file mode 100644
index 000000000000..72004a07b2d5
--- /dev/null
+++ b/drivers/media/video/cx23885/Kconfig
@@ -0,0 +1,20 @@
+config VIDEO_CX23885
+ tristate "Conexant cx23885 (2388x successor) support"
+ depends on DVB_CORE && VIDEO_DEV && PCI && I2C
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_BTCX
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ select VIDEOBUF_DVB
+ select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+ ---help---
+ This is a video4linux driver for Conexant 23885 based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx23885
+
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
new file mode 100644
index 000000000000..665067022d2a
--- /dev/null
+++ b/drivers/media/video/cx23885/Makefile
@@ -0,0 +1,9 @@
+cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+
+obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
new file mode 100644
index 000000000000..b9012acabb2f
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -0,0 +1,280 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "cx23885.h"
+
+/* ------------------------------------------------------------------ */
+/* board config info */
+
+struct cx23885_board cx23885_boards[] = {
+ [CX23885_BOARD_UNKNOWN] = {
+ .name = "UNKNOWN/GENERIC",
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 0,
+ },{
+ .type = CX23885_VMUX_COMPOSITE2,
+ .vmux = 1,
+ },{
+ .type = CX23885_VMUX_COMPOSITE3,
+ .vmux = 2,
+ },{
+ .type = CX23885_VMUX_COMPOSITE4,
+ .vmux = 3,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
+ .name = "Hauppauge WinTV-HVR1800lp",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+ .name = "Hauppauge WinTV-HVR1800",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
+ .name = "Hauppauge WinTV-HVR1250",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
+ .name = "DViCO FusionHDTV5 Express",
+ .portb = CX23885_MPEG_DVB,
+ },
+};
+const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs */
+
+struct cx23885_subid cx23885_subids[] = {
+ {
+ .subvendor = 0x0070,
+ .subdevice = 0x3400,
+ .card = CX23885_BOARD_UNKNOWN,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7600,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7800,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7801,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7911,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1250,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd500,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+ },
+};
+const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+void cx23885_card_list(struct cx23885_dev *dev)
+{
+ int i;
+
+ if (0 == dev->pci->subsystem_vendor &&
+ 0 == dev->pci->subsystem_device) {
+ printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name, dev->name, dev->name, dev->name, dev->name);
+ } else {
+ printk("%s: Your board isn't known (yet) to the driver. You can\n"
+ "%s: try to pick one of the existing card configs via\n"
+ "%s: card=<n> insmod option. Updating to the latest\n"
+ "%s: version might help as well.\n",
+ dev->name, dev->name, dev->name, dev->name);
+ }
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < cx23885_bcount; i++)
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, cx23885_boards[i].name);
+}
+
+static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data);
+
+ /* Make sure we support the board model */
+ switch (tv.model)
+ {
+ case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
+ case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+ case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+ case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+ break;
+ default:
+ printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ dev->name, tv.model);
+}
+
+void cx23885_gpio_setup(struct cx23885_dev *dev)
+{
+ switch(dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /* GPIO-0 cx24227 demodulator reset */
+ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+ // FIXME: Analog requires the tuner is brought out of reset
+ break;
+ }
+}
+
+int cx23885_ir_init(struct cx23885_dev *dev)
+{
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* FIXME: Implement me */
+ break;
+ }
+
+ return 0;
+}
+
+void cx23885_card_setup(struct cx23885_dev *dev)
+{
+ struct cx23885_tsport *ts1 = &dev->ts1;
+ struct cx23885_tsport *ts2 = &dev->ts2;
+
+ static u8 eeprom[256];
+
+ if (dev->i2c_bus[0].i2c_rc == 0) {
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[0].i2c_client,
+ eeprom, sizeof(eeprom));
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0x80);
+ break;
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ default:
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ }
+
+}
+
+/* ------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(cx23885_boards);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
new file mode 100644
index 000000000000..af16505bd2e0
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -0,0 +1,1530 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 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 <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+
+MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
+
+static unsigned int cx23885_devcount;
+
+static DEFINE_MUTEX(devlist);
+static LIST_HEAD(cx23885_devlist);
+
+#define NO_SYNC_LINE (-1U)
+
+/*
+ * CX23885 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ * 15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23885_sram_channels[] = {
+ [SRAM_CH01] = {
+ .name = "test ch1",
+ .cmds_start = 0x10000,
+ .ctrl_start = 0x10500,
+ .cdt = 0x10900,
+ .fifo_start = 0x3000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA1_PTR1,
+ .ptr2_reg = DMA1_PTR2,
+ .cnt1_reg = DMA1_CNT1,
+ .cnt2_reg = DMA1_CNT2,
+ .jumponly = 1,
+ },
+ [SRAM_CH02] = {
+ .name = "ch2",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA2_PTR1,
+ .ptr2_reg = DMA2_PTR2,
+ .cnt1_reg = DMA2_CNT1,
+ .cnt2_reg = DMA2_CNT2,
+ },
+ [SRAM_CH03] = {
+ .name = "TS1 B",
+ .cmds_start = 0x100A0,
+ .ctrl_start = 0x10780,
+ .cdt = 0x10400,
+ .fifo_start = 0x5000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA3_PTR1,
+ .ptr2_reg = DMA3_PTR2,
+ .cnt1_reg = DMA3_CNT1,
+ .cnt2_reg = DMA3_CNT2,
+ },
+ [SRAM_CH04] = {
+ .name = "ch4",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA4_PTR1,
+ .ptr2_reg = DMA4_PTR2,
+ .cnt1_reg = DMA4_CNT1,
+ .cnt2_reg = DMA4_CNT2,
+ },
+ [SRAM_CH05] = {
+ .name = "ch5",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH06] = {
+ .name = "TS2 C",
+ .cmds_start = 0x10140,
+ .ctrl_start = 0x10680,
+ .cdt = 0x10480,
+ .fifo_start = 0x6000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH07] = {
+ .name = "ch7",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA6_PTR1,
+ .ptr2_reg = DMA6_PTR2,
+ .cnt1_reg = DMA6_CNT1,
+ .cnt2_reg = DMA6_CNT2,
+ },
+ [SRAM_CH08] = {
+ .name = "ch8",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA7_PTR1,
+ .ptr2_reg = DMA7_PTR2,
+ .cnt1_reg = DMA7_CNT1,
+ .cnt2_reg = DMA7_CNT2,
+ },
+ [SRAM_CH09] = {
+ .name = "ch9",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA8_PTR1,
+ .ptr2_reg = DMA8_PTR2,
+ .cnt1_reg = DMA8_CNT1,
+ .cnt2_reg = DMA8_CNT2,
+ },
+};
+
+/* FIXME, these allocations will change when
+ * analog arrives. The be reviewed.
+ * CX23887 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ * 15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23887_sram_channels[] = {
+ [SRAM_CH01] = {
+ .name = "test ch1",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA1_PTR1,
+ .ptr2_reg = DMA1_PTR2,
+ .cnt1_reg = DMA1_CNT1,
+ .cnt2_reg = DMA1_CNT2,
+ },
+ [SRAM_CH02] = {
+ .name = "ch2",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA2_PTR1,
+ .ptr2_reg = DMA2_PTR2,
+ .cnt1_reg = DMA2_CNT1,
+ .cnt2_reg = DMA2_CNT2,
+ },
+ [SRAM_CH03] = {
+ .name = "ch3",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA3_PTR1,
+ .ptr2_reg = DMA3_PTR2,
+ .cnt1_reg = DMA3_CNT1,
+ .cnt2_reg = DMA3_CNT2,
+ },
+ [SRAM_CH04] = {
+ .name = "ch4",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA4_PTR1,
+ .ptr2_reg = DMA4_PTR2,
+ .cnt1_reg = DMA4_CNT1,
+ .cnt2_reg = DMA4_CNT2,
+ },
+ [SRAM_CH05] = {
+ .name = "ch5",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH06] = {
+ .name = "TS2 C",
+ .cmds_start = 0x10140,
+ .ctrl_start = 0x10680,
+ .cdt = 0x108d0,
+ .fifo_start = 0x6000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH07] = {
+ .name = "ch7",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA6_PTR1,
+ .ptr2_reg = DMA6_PTR2,
+ .cnt1_reg = DMA6_CNT1,
+ .cnt2_reg = DMA6_CNT2,
+ },
+ [SRAM_CH08] = {
+ .name = "ch8",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA7_PTR1,
+ .ptr2_reg = DMA7_PTR2,
+ .cnt1_reg = DMA7_CNT1,
+ .cnt2_reg = DMA7_CNT2,
+ },
+ [SRAM_CH09] = {
+ .name = "ch9",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA8_PTR1,
+ .ptr2_reg = DMA8_PTR2,
+ .cnt1_reg = DMA8_CNT1,
+ .cnt2_reg = DMA8_CNT2,
+ },
+};
+
+static int cx23885_risc_decode(u32 risc)
+{
+ static char *instr[16] = {
+ [ RISC_SYNC >> 28 ] = "sync",
+ [ RISC_WRITE >> 28 ] = "write",
+ [ RISC_WRITEC >> 28 ] = "writec",
+ [ RISC_READ >> 28 ] = "read",
+ [ RISC_READC >> 28 ] = "readc",
+ [ RISC_JUMP >> 28 ] = "jump",
+ [ RISC_SKIP >> 28 ] = "skip",
+ [ RISC_WRITERM >> 28 ] = "writerm",
+ [ RISC_WRITECM >> 28 ] = "writecm",
+ [ RISC_WRITECR >> 28 ] = "writecr",
+ };
+ static int incr[16] = {
+ [ RISC_WRITE >> 28 ] = 3,
+ [ RISC_JUMP >> 28 ] = 3,
+ [ RISC_SKIP >> 28 ] = 1,
+ [ RISC_SYNC >> 28 ] = 1,
+ [ RISC_WRITERM >> 28 ] = 3,
+ [ RISC_WRITECM >> 28 ] = 3,
+ [ RISC_WRITECR >> 28 ] = 4,
+ };
+ static char *bits[] = {
+ "12", "13", "14", "resync",
+ "cnt0", "cnt1", "18", "19",
+ "20", "21", "22", "23",
+ "irq1", "irq2", "eol", "sol",
+ };
+ int i;
+
+ printk("0x%08x [ %s", risc,
+ instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+ for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--)
+ if (risc & (1 << (i + 12)))
+ printk(" %s", bits[i]);
+ printk(" count=%d ]\n", risc & 0xfff);
+ return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+void cx23885_wakeup(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q, u32 count)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_buffer *buf;
+ int bc;
+
+ for (bc = 0;; bc++) {
+ if (list_empty(&q->active))
+ break;
+ buf = list_entry(q->active.next,
+ struct cx23885_buffer, vb.queue);
+
+ /* count comes from the hw and is is 16bit wide --
+ * this trick handles wrap-arounds correctly for
+ * up to 32767 buffers in flight... */
+ if ((s16) (count - buf->count) < 0)
+ break;
+
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+ count, buf->count);
+ buf->vb.state = STATE_DONE;
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ }
+ if (list_empty(&q->active)) {
+ del_timer(&q->timeout);
+ } else {
+ mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+ }
+ if (bc != 1)
+ printk("%s: %d buffers handled (should be 1)\n",
+ __FUNCTION__, bc);
+}
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ struct sram_channel *ch);
+
+int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ struct sram_channel *ch,
+ unsigned int bpl, u32 risc)
+{
+ unsigned int i, lines;
+ u32 cdt;
+
+ if (ch->cmds_start == 0)
+ {
+ dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__,
+ ch->name);
+ cx_write(ch->ptr1_reg, 0);
+ cx_write(ch->ptr2_reg, 0);
+ cx_write(ch->cnt2_reg, 0);
+ cx_write(ch->cnt1_reg, 0);
+ return 0;
+ } else {
+ dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__,
+ ch->name);
+ }
+
+ bpl = (bpl + 7) & ~7; /* alignment */
+ cdt = ch->cdt;
+ lines = ch->fifo_size / bpl;
+ if (lines > 6)
+ lines = 6;
+ BUG_ON(lines < 2);
+
+ cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) );
+ cx_write(8 + 4, cpu_to_le32(8) );
+ cx_write(8 + 8, cpu_to_le32(0) );
+
+ /* write CDT */
+ for (i = 0; i < lines; i++) {
+ dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i,
+ ch->fifo_start + bpl*i);
+ cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+ cx_write(cdt + 16*i + 4, 0);
+ cx_write(cdt + 16*i + 8, 0);
+ cx_write(cdt + 16*i + 12, 0);
+ }
+
+ /* write CMDS */
+ if (ch->jumponly)
+ cx_write(ch->cmds_start + 0, 8);
+ else
+ cx_write(ch->cmds_start + 0, risc);
+ cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
+ cx_write(ch->cmds_start + 8, cdt);
+ cx_write(ch->cmds_start + 12, (lines*16) >> 3);
+ cx_write(ch->cmds_start + 16, ch->ctrl_start);
+ if (ch->jumponly)
+ cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) );
+ else
+ cx_write(ch->cmds_start + 20, 64 >> 2);
+ for (i = 24; i < 80; i += 4)
+ cx_write(ch->cmds_start + i, 0);
+
+ /* fill registers */
+ cx_write(ch->ptr1_reg, ch->fifo_start);
+ cx_write(ch->ptr2_reg, cdt);
+ cx_write(ch->cnt2_reg, (lines*16) >> 3);
+ cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+
+ dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n",
+ dev->bridge,
+ ch->name,
+ bpl,
+ lines);
+
+ return 0;
+}
+
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ struct sram_channel *ch)
+{
+ static char *name[] = {
+ "init risc lo",
+ "init risc hi",
+ "cdt base",
+ "cdt size",
+ "iq base",
+ "iq size",
+ "risc pc lo",
+ "risc pc hi",
+ "iq wr ptr",
+ "iq rd ptr",
+ "cdt current",
+ "pci target lo",
+ "pci target hi",
+ "line / byte",
+ };
+ u32 risc;
+ unsigned int i, j, n;
+
+ printk("%s: %s - dma channel status dump\n",
+ dev->name, ch->name);
+ for (i = 0; i < ARRAY_SIZE(name); i++)
+ printk("%s: cmds: %-15s: 0x%08x\n",
+ dev->name, name[i],
+ cx_read(ch->cmds_start + 4*i));
+
+ for (i = 0; i < 4; i++) {
+ risc = cx_read(ch->cmds_start + 4 * (i + 14));
+ printk("%s: risc%d: ", dev->name, i);
+ cx23885_risc_decode(risc);
+ }
+ for (i = 0; i < (64 >> 2); i += n) {
+ risc = cx_read(ch->ctrl_start + 4 * i);
+ /* No consideration for bits 63-32 */
+
+ printk("%s: (0x%08x) iq %x: ", dev->name,
+ ch->ctrl_start + 4 * i, i);
+ n = cx23885_risc_decode(risc);
+ for (j = 1; j < n; j++) {
+ risc = cx_read(ch->ctrl_start + 4 * (i + j));
+ printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
+ dev->name, i+j, risc, j);
+ }
+ }
+
+ printk("%s: fifo: 0x%08x -> 0x%x\n",
+ dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+ printk("%s: ctrl: 0x%08x -> 0x%x\n",
+ dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
+ printk("%s: ptr1_reg: 0x%08x\n",
+ dev->name, cx_read(ch->ptr1_reg));
+ printk("%s: ptr2_reg: 0x%08x\n",
+ dev->name, cx_read(ch->ptr2_reg));
+ printk("%s: cnt1_reg: 0x%08x\n",
+ dev->name, cx_read(ch->cnt1_reg));
+ printk("%s: cnt2_reg: 0x%08x\n",
+ dev->name, cx_read(ch->cnt2_reg));
+}
+
+void cx23885_risc_disasm(struct cx23885_tsport *port,
+ struct btcx_riscmem *risc)
+{
+ struct cx23885_dev *dev = port->dev;
+ unsigned int i, j, n;
+
+ printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+ dev->name, risc->cpu, (unsigned long)risc->dma);
+ for (i = 0; i < (risc->size >> 2); i += n) {
+ printk("%s: %04d: ", dev->name, i);
+ n = cx23885_risc_decode(risc->cpu[i]);
+ for (j = 1; j < n; j++)
+ printk("%s: %04d: 0x%08x [ arg #%d ]\n",
+ dev->name, i + j, risc->cpu[i + j], j);
+ if (risc->cpu[i] == RISC_JUMP)
+ break;
+ }
+}
+
+void cx23885_shutdown(struct cx23885_dev *dev)
+{
+ /* disable RISC controller */
+ cx_write(DEV_CNTRL2, 0);
+
+ /* Disable all IR activity */
+ cx_write(IR_CNTRL_REG, 0);
+
+ /* Disable Video A/B activity */
+ cx_write(VID_A_DMA_CTL, 0);
+ cx_write(VID_B_DMA_CTL, 0);
+ cx_write(VID_C_DMA_CTL, 0);
+
+ /* Disable Audio activity */
+ cx_write(AUD_INT_DMA_CTL, 0);
+ cx_write(AUD_EXT_DMA_CTL, 0);
+
+ /* Disable Serial port */
+ cx_write(UART_CTL, 0);
+
+ /* Disable Interrupts */
+ cx_write(PCI_INT_MSK, 0);
+ cx_write(VID_A_INT_MSK, 0);
+ cx_write(VID_B_INT_MSK, 0);
+ cx_write(VID_C_INT_MSK, 0);
+ cx_write(AUDIO_INT_INT_MSK, 0);
+ cx_write(AUDIO_EXT_INT_MSK, 0);
+
+}
+
+void cx23885_reset(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ cx23885_shutdown(dev);
+
+ cx_write(PCI_INT_STAT, 0xffffffff);
+ cx_write(VID_A_INT_STAT, 0xffffffff);
+ cx_write(VID_B_INT_STAT, 0xffffffff);
+ cx_write(VID_C_INT_STAT, 0xffffffff);
+ cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
+ cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
+ cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
+
+ mdelay(100);
+
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
+
+ cx23885_gpio_setup(dev);
+}
+
+
+static int cx23885_pci_quirks(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ /* The cx23885 bridge has a weird bug which causes NMI to be asserted
+ * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
+ * occur on the cx23887 bridge.
+ */
+ if(dev->bridge == CX23885_BRIDGE_885)
+ cx_clear(RDR_TLCTL0, 1 << 4);
+
+ return 0;
+}
+
+static int get_resources(struct cx23885_dev *dev)
+{
+ if (request_mem_region(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0),
+ dev->name))
+ return 0;
+
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ dev->name, (unsigned long long)pci_resource_start(dev->pci,0));
+
+ return -EBUSY;
+}
+
+static void cx23885_timeout(unsigned long data);
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value);
+
+static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
+{
+ dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno);
+
+ /* Transport bus init dma queue - Common settings */
+ port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */
+ port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */
+
+ spin_lock_init(&port->slock);
+ port->dev = dev;
+ port->nr = portno;
+
+ INIT_LIST_HEAD(&port->mpegq.active);
+ INIT_LIST_HEAD(&port->mpegq.queued);
+ port->mpegq.timeout.function = cx23885_timeout;
+ port->mpegq.timeout.data = (unsigned long)port;
+ init_timer(&port->mpegq.timeout);
+
+ switch(portno) {
+ case 1:
+ port->reg_gpcnt = VID_B_GPCNT;
+ port->reg_gpcnt_ctl = VID_B_GPCNT_CTL;
+ port->reg_dma_ctl = VID_B_DMA_CTL;
+ port->reg_lngth = VID_B_LNGTH;
+ port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL;
+ port->reg_gen_ctrl = VID_B_GEN_CTL;
+ port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS;
+ port->reg_sop_status = VID_B_SOP_STATUS;
+ port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT;
+ port->reg_vld_misc = VID_B_VLD_MISC;
+ port->reg_ts_clk_en = VID_B_TS_CLK_EN;
+ port->reg_src_sel = VID_B_SRC_SEL;
+ port->reg_ts_int_msk = VID_B_INT_MSK;
+ port->reg_ts_int_stat = VID_B_INT_STAT;
+ port->sram_chno = SRAM_CH03; /* VID_B */
+ port->pci_irqmask = 0x02; /* VID_B bit1 */
+ break;
+ case 2:
+ port->reg_gpcnt = VID_C_GPCNT;
+ port->reg_gpcnt_ctl = VID_C_GPCNT_CTL;
+ port->reg_dma_ctl = VID_C_DMA_CTL;
+ port->reg_lngth = VID_C_LNGTH;
+ port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL;
+ port->reg_gen_ctrl = VID_C_GEN_CTL;
+ port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS;
+ port->reg_sop_status = VID_C_SOP_STATUS;
+ port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
+ port->reg_vld_misc = VID_C_VLD_MISC;
+ port->reg_ts_clk_en = VID_C_TS_CLK_EN;
+ port->reg_src_sel = 0;
+ port->reg_ts_int_msk = VID_C_INT_MSK;
+ port->reg_ts_int_stat = VID_C_INT_STAT;
+ port->sram_chno = SRAM_CH06; /* VID_C */
+ port->pci_irqmask = 0x04; /* VID_C bit2 */
+ break;
+ default:
+ BUG();
+ }
+
+ cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
+ port->reg_dma_ctl, port->dma_ctl_val, 0x00);
+
+ return 0;
+}
+
+static int cx23885_dev_setup(struct cx23885_dev *dev)
+{
+ int i;
+
+ mutex_init(&dev->lock);
+
+ atomic_inc(&dev->refcount);
+
+ dev->nr = cx23885_devcount++;
+ sprintf(dev->name, "cx23885[%d]", dev->nr);
+
+ mutex_lock(&devlist);
+ list_add_tail(&dev->devlist, &cx23885_devlist);
+ mutex_unlock(&devlist);
+
+ /* Configure the internal memory */
+ if(dev->pci->device == 0x8880) {
+ dev->bridge = CX23885_BRIDGE_887;
+ dev->sram_channels = cx23887_sram_channels;
+ } else
+ if(dev->pci->device == 0x8852) {
+ dev->bridge = CX23885_BRIDGE_885;
+ dev->sram_channels = cx23885_sram_channels;
+ } else
+ BUG();
+
+ dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
+ __FUNCTION__, dev->bridge);
+
+ /* board config */
+ dev->board = UNSET;
+ if (card[dev->nr] < cx23885_bcount)
+ dev->board = card[dev->nr];
+ for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++)
+ if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
+ dev->pci->subsystem_device == cx23885_subids[i].subdevice)
+ dev->board = cx23885_subids[i].card;
+ if (UNSET == dev->board) {
+ dev->board = CX23885_BOARD_UNKNOWN;
+ cx23885_card_list(dev);
+ }
+
+ dev->pci_bus = dev->pci->bus->number;
+ dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+ dev->pci_irqmask = 0x001f00;
+
+ /* External Master 1 Bus */
+ dev->i2c_bus[0].nr = 0;
+ dev->i2c_bus[0].dev = dev;
+ dev->i2c_bus[0].reg_stat = I2C1_STAT;
+ dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
+ dev->i2c_bus[0].reg_addr = I2C1_ADDR;
+ dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
+ dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
+ dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
+
+ /* External Master 2 Bus */
+ dev->i2c_bus[1].nr = 1;
+ dev->i2c_bus[1].dev = dev;
+ dev->i2c_bus[1].reg_stat = I2C2_STAT;
+ dev->i2c_bus[1].reg_ctrl = I2C2_CTRL;
+ dev->i2c_bus[1].reg_addr = I2C2_ADDR;
+ dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
+ dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
+ dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
+
+ /* Internal Master 3 Bus */
+ dev->i2c_bus[2].nr = 2;
+ dev->i2c_bus[2].dev = dev;
+ dev->i2c_bus[2].reg_stat = I2C3_STAT;
+ dev->i2c_bus[2].reg_ctrl = I2C3_CTRL;
+ dev->i2c_bus[2].reg_addr = I2C3_ADDR;
+ dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
+ dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
+ dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
+
+ if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ cx23885_init_tsport(dev, &dev->ts1, 1);
+
+ if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ cx23885_init_tsport(dev, &dev->ts2, 2);
+
+ if (get_resources(dev) < 0) {
+ printk(KERN_ERR "CORE %s No more PCIe resources for "
+ "subsystem: %04x:%04x\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device);
+
+ cx23885_devcount--;
+ goto fail_free;
+ }
+
+ /* PCIe stuff */
+ dev->lmmio = ioremap(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0));
+
+ dev->bmmio = (u8 __iomem *)dev->lmmio;
+
+ printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, cx23885_boards[dev->board].name,
+ dev->board, card[dev->nr] == dev->board ?
+ "insmod option" : "autodetected");
+
+ cx23885_pci_quirks(dev);
+
+ /* init hardware */
+ cx23885_reset(dev);
+
+ cx23885_i2c_register(&dev->i2c_bus[0]);
+ cx23885_i2c_register(&dev->i2c_bus[1]);
+ cx23885_i2c_register(&dev->i2c_bus[2]);
+ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
+ cx23885_card_setup(dev);
+ cx23885_ir_init(dev);
+
+ if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+ if (cx23885_dvb_register(&dev->ts1) < 0) {
+ printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
+ __FUNCTION__);
+ }
+ }
+
+ if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+ if (cx23885_dvb_register(&dev->ts2) < 0) {
+ printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
+ __FUNCTION__);
+ }
+ }
+
+ return 0;
+
+fail_free:
+ kfree(dev);
+ return -ENODEV;
+}
+
+void cx23885_dev_unregister(struct cx23885_dev *dev)
+{
+ release_mem_region(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0));
+
+ if (!atomic_dec_and_test(&dev->refcount))
+ return;
+
+ if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ cx23885_dvb_unregister(&dev->ts1);
+
+ if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ cx23885_dvb_unregister(&dev->ts2);
+
+ cx23885_i2c_unregister(&dev->i2c_bus[2]);
+ cx23885_i2c_unregister(&dev->i2c_bus[1]);
+ cx23885_i2c_unregister(&dev->i2c_bus[0]);
+
+ iounmap(dev->lmmio);
+}
+
+static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist,
+ unsigned int offset, u32 sync_line,
+ unsigned int bpl, unsigned int padding,
+ unsigned int lines)
+{
+ struct scatterlist *sg;
+ unsigned int line, todo;
+
+ /* sync instruction */
+ if (sync_line != NO_SYNC_LINE)
+ *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+ /* scan lines */
+ sg = sglist;
+ for (line = 0; line < lines; line++) {
+ while (offset && offset >= sg_dma_len(sg)) {
+ offset -= sg_dma_len(sg);
+ sg++;
+ }
+ if (bpl <= sg_dma_len(sg)-offset) {
+ /* fits into current chunk */
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ offset+=bpl;
+ } else {
+ /* scanline needs to be split */
+ todo = bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ (sg_dma_len(sg)-offset));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(RISC_WRITE|
+ sg_dma_len(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ todo -= sg_dma_len(sg);
+ sg++;
+ }
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ offset += todo;
+ }
+ offset += padding;
+ }
+
+ return rp;
+}
+
+int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist, unsigned int top_offset,
+ unsigned int bottom_offset, unsigned int bpl,
+ unsigned int padding, unsigned int lines)
+{
+ u32 instructions, fields;
+ u32 *rp;
+ int rc;
+
+ fields = 0;
+ if (UNSET != top_offset)
+ fields++;
+ if (UNSET != bottom_offset)
+ fields++;
+
+ /* estimate risc mem: worst case is one write per page border +
+ one write per scan line + syncs + jump (all 2 dwords). Padding
+ can cause next bpl to start close to a page border. First DMA
+ region may be smaller than PAGE_SIZE */
+ /* write and jump need and extra dword */
+ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+ instructions += 2;
+ if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ if (UNSET != top_offset)
+ rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+ bpl, padding, lines);
+ if (UNSET != bottom_offset)
+ rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+ bpl, padding, lines);
+
+ /* save pointer to jmp instruction address */
+ risc->jmp = rp;
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ return 0;
+}
+
+int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist, unsigned int bpl,
+ unsigned int lines)
+{
+ u32 instructions;
+ u32 *rp;
+ int rc;
+
+ /* estimate risc mem: worst case is one write per page border +
+ one write per scan line + syncs + jump (all 2 dwords). Here
+ there is no padding and no sync. First DMA region may be smaller
+ than PAGE_SIZE */
+ /* Jump and write need an extra dword */
+ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
+ instructions += 1;
+
+ if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+
+ /* save pointer to jmp instruction address */
+ risc->jmp = rp;
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ return 0;
+}
+
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value)
+{
+ u32 *rp;
+ int rc;
+
+ if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2);
+ *(rp++) = cpu_to_le32(reg);
+ *(rp++) = cpu_to_le32(value);
+ *(rp++) = cpu_to_le32(mask);
+ *(rp++) = cpu_to_le32(RISC_JUMP);
+ *(rp++) = cpu_to_le32(risc->dma);
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+ return 0;
+}
+
+void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+ BUG_ON(in_interrupt());
+ videobuf_waiton(&buf->vb, 0, 0);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
+ btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+ buf->vb.state = STATE_NEEDS_INIT;
+}
+
+static int cx23885_start_dma(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q,
+ struct cx23885_buffer *buf)
+{
+ struct cx23885_dev *dev = port->dev;
+
+ dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__,
+ buf->vb.width, buf->vb.height, buf->vb.field);
+
+ /* setup fifo + format */
+ cx23885_sram_channel_setup(dev,
+ &dev->sram_channels[ port->sram_chno ],
+ port->ts_packet_size, buf->risc.dma);
+ if(debug > 5) {
+ cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] );
+ cx23885_risc_disasm(port, &buf->risc);
+ }
+
+ /* write TS length to chip */
+ cx_write(port->reg_lngth, buf->vb.width);
+
+ if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
+ (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
+ printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
+ __FUNCTION__,
+ cx23885_boards[dev->board].portb,
+ cx23885_boards[dev->board].portc );
+ return -EINVAL;
+ }
+
+ udelay(100);
+
+ /* If the port supports SRC SELECT, configure it */
+ if(port->reg_src_sel)
+ cx_write(port->reg_src_sel, port->src_sel_val);
+
+ cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4);
+ cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
+ cx_write(port->reg_vld_misc, 0x00);
+ cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
+ udelay(100);
+
+ // NOTE: this is 2 (reserved) for portb, does it matter?
+ /* reset counter to zero */
+ cx_write(port->reg_gpcnt_ctl, 3);
+ q->count = 1;
+
+ switch(dev->bridge) {
+ case CX23885_BRIDGE_885:
+ case CX23885_BRIDGE_887:
+ /* enable irqs */
+ dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ );
+ cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
+ cx_set(port->reg_dma_ctl, port->dma_ctl_val);
+ cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
+ break;
+ default:
+ BUG();
+ }
+
+ cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+
+ return 0;
+}
+
+static int cx23885_stop_dma(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ /* Stop interrupts and DMA */
+ cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
+ cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+
+ return 0;
+}
+
+static int cx23885_restart_queue(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_buffer *buf;
+
+ dprintk(5, "%s()\n", __FUNCTION__);
+ if (list_empty(&q->active))
+ {
+ struct cx23885_buffer *prev;
+ prev = NULL;
+
+ dprintk(5, "%s() queue is empty\n", __FUNCTION__);
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ buf = list_entry(q->queued.next, struct cx23885_buffer,
+ vb.queue);
+ if (NULL == prev) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &q->active);
+ cx23885_start_dma(port, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(5, "[%p/%d] restart_queue - first active\n",
+ buf, buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+ dprintk(5,"[%p/%d] restart_queue - move to active\n",
+ buf, buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
+ return 0;
+ }
+
+ buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+ dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+ buf, buf->vb.i);
+ cx23885_start_dma(port, q, buf);
+ list_for_each_entry(buf, &q->active, vb.queue)
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
+ struct cx23885_buffer *buf, enum v4l2_field field)
+{
+ struct cx23885_dev *dev = port->dev;
+ int size = port->ts_packet_size * port->ts_packet_count;
+ int rc;
+
+ dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ return -EINVAL;
+
+ if (STATE_NEEDS_INIT == buf->vb.state) {
+ buf->vb.width = port->ts_packet_size;
+ buf->vb.height = port->ts_packet_count;
+ buf->vb.size = size;
+ buf->vb.field = field /*V4L2_FIELD_TOP*/;
+
+ if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+ goto fail;
+ cx23885_risc_databuffer(dev->pci, &buf->risc,
+ videobuf_to_dma(&buf->vb)->sglist,
+ buf->vb.width, buf->vb.height);
+ }
+ buf->vb.state = STATE_PREPARED;
+ return 0;
+
+ fail:
+ cx23885_free_buffer(q, buf);
+ return rc;
+}
+
+void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
+{
+ struct cx23885_buffer *prev;
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *cx88q = &port->mpegq;
+
+ /* add jump to stopper */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+ buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+ if (list_empty(&cx88q->active)) {
+ dprintk( 1, "queue is empty - first active\n" );
+ list_add_tail(&buf->vb.queue, &cx88q->active);
+ cx23885_start_dma(port, cx88q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = cx88q->count++;
+ mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+ dprintk(1, "[%p/%d] %s - first active\n",
+ buf, buf->vb.i, __FUNCTION__);
+ } else {
+ dprintk( 1, "queue is not empty - append to active\n" );
+ prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
+ vb.queue);
+ list_add_tail(&buf->vb.queue, &cx88q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = cx88q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+ dprintk( 1, "[%p/%d] %s - append to active\n",
+ buf, buf->vb.i, __FUNCTION__);
+ }
+}
+
+/* ----------------------------------------------------------- */
+
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
+ int restart)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *q = &port->mpegq;
+ struct cx23885_buffer *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->slock, flags);
+ while (!list_empty(&q->active)) {
+ buf = list_entry(q->active.next, struct cx23885_buffer,
+ vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = STATE_ERROR;
+ wake_up(&buf->vb.done);
+ dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
+ buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+ }
+ if (restart) {
+ dprintk(1, "restarting queue\n" );
+ cx23885_restart_queue(port, q);
+ }
+ spin_unlock_irqrestore(&port->slock, flags);
+}
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *q = &port->mpegq;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+ del_timer_sync(&q->timeout);
+ cx23885_stop_dma(port);
+ do_cancel_buffers(port, "cancel", 0);
+}
+
+static void cx23885_timeout(unsigned long data)
+{
+ struct cx23885_tsport *port = (struct cx23885_tsport *)data;
+ struct cx23885_dev *dev = port->dev;
+
+ dprintk(1, "%s()\n",__FUNCTION__);
+
+ if (debug > 5)
+ cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+
+ cx23885_stop_dma(port);
+ do_cancel_buffers(port, "timeout", 1);
+}
+
+static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
+{
+ struct cx23885_dev *dev = port->dev;
+ int handled = 0;
+ u32 count;
+
+ if ( (status & VID_BC_MSK_OPC_ERR) ||
+ (status & VID_BC_MSK_BAD_PKT) ||
+ (status & VID_BC_MSK_SYNC) ||
+ (status & VID_BC_MSK_OF))
+ {
+ if (status & VID_BC_MSK_OPC_ERR)
+ dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
+ if (status & VID_BC_MSK_BAD_PKT)
+ dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT);
+ if (status & VID_BC_MSK_SYNC)
+ dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC);
+ if (status & VID_BC_MSK_OF)
+ dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF);
+
+ printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
+
+ cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+
+ } else if (status & VID_BC_MSK_RISCI1) {
+
+ dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1);
+
+ spin_lock(&port->slock);
+ count = cx_read(port->reg_gpcnt);
+ cx23885_wakeup(port, &port->mpegq, count);
+ spin_unlock(&port->slock);
+
+ } else if (status & VID_BC_MSK_RISCI2) {
+
+ dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2);
+
+ spin_lock(&port->slock);
+ cx23885_restart_queue(port, &port->mpegq);
+ spin_unlock(&port->slock);
+
+ }
+ if (status) {
+ cx_write(port->reg_ts_int_stat, status);
+ handled = 1;
+ }
+
+ return handled;
+}
+
+static irqreturn_t cx23885_irq(int irq, void *dev_id)
+{
+ struct cx23885_dev *dev = dev_id;
+ struct cx23885_tsport *ts1 = &dev->ts1;
+ struct cx23885_tsport *ts2 = &dev->ts2;
+ u32 pci_status, pci_mask;
+ u32 ts1_status, ts1_mask;
+ u32 ts2_status, ts2_mask;
+ int ts1_count = 0, ts2_count = 0, handled = 0;
+
+ pci_status = cx_read(PCI_INT_STAT);
+ pci_mask = cx_read(PCI_INT_MSK);
+ ts1_status = cx_read(VID_B_INT_STAT);
+ ts1_mask = cx_read(VID_B_INT_MSK);
+ ts2_status = cx_read(VID_C_INT_STAT);
+ ts2_mask = cx_read(VID_C_INT_MSK);
+
+ if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
+ goto out;
+
+ ts1_count = cx_read(ts1->reg_gpcnt);
+ ts2_count = cx_read(ts2->reg_gpcnt);
+ dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask );
+ dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
+ dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
+
+ if ( (pci_status & PCI_MSK_RISC_RD) ||
+ (pci_status & PCI_MSK_RISC_WR) ||
+ (pci_status & PCI_MSK_AL_RD) ||
+ (pci_status & PCI_MSK_AL_WR) ||
+ (pci_status & PCI_MSK_APB_DMA) ||
+ (pci_status & PCI_MSK_VID_C) ||
+ (pci_status & PCI_MSK_VID_B) ||
+ (pci_status & PCI_MSK_VID_A) ||
+ (pci_status & PCI_MSK_AUD_INT) ||
+ (pci_status & PCI_MSK_AUD_EXT) )
+ {
+
+ if (pci_status & PCI_MSK_RISC_RD)
+ dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD);
+ if (pci_status & PCI_MSK_RISC_WR)
+ dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR);
+ if (pci_status & PCI_MSK_AL_RD)
+ dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD);
+ if (pci_status & PCI_MSK_AL_WR)
+ dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR);
+ if (pci_status & PCI_MSK_APB_DMA)
+ dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA);
+ if (pci_status & PCI_MSK_VID_C)
+ dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C);
+ if (pci_status & PCI_MSK_VID_B)
+ dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B);
+ if (pci_status & PCI_MSK_VID_A)
+ dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A);
+ if (pci_status & PCI_MSK_AUD_INT)
+ dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT);
+ if (pci_status & PCI_MSK_AUD_EXT)
+ dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT);
+
+ }
+
+ if (ts1_status)
+ handled += cx23885_irq_ts(ts1, ts1_status);
+
+ if (ts2_status)
+ handled += cx23885_irq_ts(ts2, ts2_status);
+
+ if (handled)
+ cx_write(PCI_INT_STAT, pci_status);
+out:
+ return IRQ_RETVAL(handled);
+}
+
+static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx23885_dev *dev;
+ int err;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto fail_free;
+ }
+
+ if (cx23885_dev_setup(dev) < 0) {
+ err = -EINVAL;
+ goto fail_free;
+ }
+
+ /* print pci info */
+ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%llx\n", dev->name,
+ pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0));
+
+ pci_set_master(pci_dev);
+ if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+ err = -EIO;
+ goto fail_irq;
+ }
+
+ err = request_irq(pci_dev->irq, cx23885_irq,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ if (err < 0) {
+ printk(KERN_ERR "%s: can't get IRQ %d\n",
+ dev->name, pci_dev->irq);
+ goto fail_irq;
+ }
+
+ pci_set_drvdata(pci_dev, dev);
+ return 0;
+
+fail_irq:
+ cx23885_dev_unregister(dev);
+fail_free:
+ kfree(dev);
+ return err;
+}
+
+static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+{
+ struct cx23885_dev *dev = pci_get_drvdata(pci_dev);
+
+ cx23885_shutdown(dev);
+
+ pci_disable_device(pci_dev);
+
+ /* unregister stuff */
+ free_irq(pci_dev->irq, dev);
+ pci_set_drvdata(pci_dev, NULL);
+
+ mutex_lock(&devlist);
+ list_del(&dev->devlist);
+ mutex_unlock(&devlist);
+
+ cx23885_dev_unregister(dev);
+ kfree(dev);
+}
+
+static struct pci_device_id cx23885_pci_tbl[] = {
+ {
+ /* CX23885 */
+ .vendor = 0x14f1,
+ .device = 0x8852,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* CX23887 Rev 2 */
+ .vendor = 0x14f1,
+ .device = 0x8880,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl);
+
+static struct pci_driver cx23885_pci_driver = {
+ .name = "cx23885",
+ .id_table = cx23885_pci_tbl,
+ .probe = cx23885_initdev,
+ .remove = __devexit_p(cx23885_finidev),
+ /* TODO */
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+static int cx23885_init(void)
+{
+ printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
+ (CX23885_VERSION_CODE >> 16) & 0xff,
+ (CX23885_VERSION_CODE >> 8) & 0xff,
+ CX23885_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+ return pci_register_driver(&cx23885_pci_driver);
+}
+
+static void cx23885_fini(void)
+{
+ pci_unregister_driver(&cx23885_pci_driver);
+}
+
+module_init(cx23885_init);
+module_exit(cx23885_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
new file mode 100644
index 000000000000..eda8c05d0931
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -0,0 +1,213 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#include "s5h1409.h"
+#include "mt2131.h"
+#include "lgdt330x.h"
+#include "dvb-pll.h"
+
+static unsigned int debug = 0;
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx23885_tsport *port = q->priv_data;
+
+ port->ts_packet_size = 188 * 4;
+ port->ts_packet_count = 32;
+
+ *size = port->ts_packet_size * port->ts_packet_count;
+ *count = 32;
+ return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx23885_tsport *port = q->priv_data;
+ return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx23885_tsport *port = q->priv_data;
+ cx23885_buf_queue(port, (struct cx23885_buffer*)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ cx23885_free_buffer(q, (struct cx23885_buffer*)vb);
+}
+
+static struct videobuf_queue_ops dvb_qops = {
+ .buf_setup = dvb_buf_setup,
+ .buf_prepare = dvb_buf_prepare,
+ .buf_queue = dvb_buf_queue,
+ .buf_release = dvb_buf_release,
+};
+
+static struct s5h1409_config hauppauge_generic_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .if_freq = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING
+};
+
+static struct s5h1409_config hauppauge_hvr1800lp_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .if_freq = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING
+};
+
+static struct mt2131_config hauppauge_generic_tunerconfig = {
+ 0x61
+};
+
+static struct lgdt330x_config fusionhdtv_5_express = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40,
+};
+
+static int dvb_register(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_i2c *i2c_bus = NULL;
+
+ /* init struct videobuf_dvb */
+ port->dvb.name = dev->name;
+
+ /* init frontend */
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_generic_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, port->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1800lp_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, port->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ }
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_5_express,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61,
+ &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
+ }
+ break;
+ default:
+ printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+ dev->name);
+ break;
+ }
+ if (NULL == port->dvb.frontend) {
+ printk("%s: frontend initialization failed\n", dev->name);
+ return -1;
+ }
+
+ /* Put the analog decoder in standby to keep it quiet */
+ cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
+
+ /* register everything */
+ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
+ &dev->pci->dev);
+}
+
+int cx23885_dvb_register(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ int err;
+
+ dprintk(1, "%s\n", __FUNCTION__);
+ dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ dev->board,
+ dev->name,
+ dev->pci_bus,
+ dev->pci_slot);
+
+ err = -ENODEV;
+
+ /* dvb stuff */
+ printk("%s: cx23885 based dvb card\n", dev->name);
+ videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
+ sizeof(struct cx23885_buffer), port);
+ err = dvb_register(port);
+ if (err != 0)
+ printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err);
+
+ return err;
+}
+
+int cx23885_dvb_unregister(struct cx23885_tsport *port)
+{
+ /* dvb */
+ if(port->dvb.frontend)
+ videobuf_dvb_unregister(&port->dvb);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+*/
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
new file mode 100644
index 000000000000..b517c8b5a566
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -0,0 +1,382 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "cx23885.h"
+
+#include <media/v4l2-common.h>
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+
+#define I2C_WAIT_DELAY 32
+#define I2C_WAIT_RETRY 64
+
+#define I2C_EXTEND (1 << 3)
+#define I2C_NOSTOP (1 << 4)
+
+static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ return cx_read(bus->reg_stat) & 0x01;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int last)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ u32 wdata, addr, ctrl;
+ int retval, cnt;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+ /* Deal with i2c probe functions with zero payload */
+ if (msg->len == 0) {
+ cx_write(bus->reg_addr, msg->addr << 25);
+ cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+ if (!i2c_slave_did_ack(i2c_adap))
+ return -EIO;
+
+ dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ return 0;
+ }
+
+
+ /* dev, reg + first byte */
+ addr = (msg->addr << 25) | msg->buf[0];
+ wdata = msg->buf[0];
+ ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+ if (msg->len > 1)
+ ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+ cx_write(bus->reg_addr, addr);
+ cx_write(bus->reg_wdata, wdata);
+ cx_write(bus->reg_ctrl, ctrl);
+
+ retval = i2c_wait_done(i2c_adap);
+ if (retval < 0)
+ goto err;
+ if (retval == 0)
+ goto eio;
+ if (i2c_debug) {
+ printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" >\n");
+ }
+
+ for (cnt = 1; cnt < msg->len; cnt++ ) {
+ /* following bytes */
+ wdata = msg->buf[cnt];
+ ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+ if (cnt < msg->len-1 || !last)
+ ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+ cx_write(bus->reg_addr, addr);
+ cx_write(bus->reg_wdata, wdata);
+ cx_write(bus->reg_ctrl, ctrl);
+
+ retval = i2c_wait_done(i2c_adap);
+ if (retval < 0)
+ goto err;
+ if (retval == 0)
+ goto eio;
+ if (i2c_debug) {
+ printk(" %02x", msg->buf[cnt]);
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" >\n");
+ }
+ }
+ return msg->len;
+
+ eio:
+ retval = -EIO;
+ err:
+ printk(" ERR: %d\n", retval);
+ return retval;
+}
+
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int last)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ u32 ctrl, cnt;
+ int retval;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ /* Deal with i2c probe functions with zero payload */
+ if (msg->len == 0) {
+ cx_write(bus->reg_addr, msg->addr << 25);
+ cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+ if (!i2c_slave_did_ack(i2c_adap))
+ return -EIO;
+
+
+ dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ return 0;
+ }
+
+ for(cnt = 0; cnt < msg->len; cnt++) {
+
+ ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
+
+ if (cnt < msg->len-1 || !last)
+ ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+ cx_write(bus->reg_addr, msg->addr << 25);
+ cx_write(bus->reg_ctrl, ctrl);
+
+ retval = i2c_wait_done(i2c_adap);
+ if (retval < 0)
+ goto err;
+ if (retval == 0)
+ goto eio;
+ msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
+ if (i2c_debug) {
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" <R %02x", (msg->addr << 1) +1);
+ printk(" =%02x", msg->buf[cnt]);
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" >\n");
+ }
+ }
+ return msg->len;
+
+ eio:
+ retval = -EIO;
+ err:
+ printk(" ERR: %d\n", retval);
+ return retval;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ int i, retval = 0;
+
+ dprintk(1, "%s(num = %d)\n", __FUNCTION__, num);
+
+ for (i = 0 ; i < num; i++) {
+ dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
+ __FUNCTION__, num, msgs[i].addr, msgs[i].len);
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read */
+ retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
+ if (retval < 0)
+ goto err;
+ } else {
+ /* write */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
+ if (retval < 0)
+ goto err;
+ }
+ }
+ return num;
+
+ err:
+ return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ struct cx23885_dev *dev = 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;
+
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+
+ dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+ return 0;
+}
+
+void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
+ unsigned int cmd, void *arg)
+{
+ if (bus->i2c_rc != 0)
+ return;
+
+ i2c_clients_command(&bus->i2c_adap, cmd, arg);
+}
+
+static int cx23885_algo_control(struct i2c_adapter *adap,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static u32 cx23885_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx23885_i2c_algo_template = {
+ .master_xfer = i2c_xfer,
+ .algo_control = cx23885_algo_control,
+ .functionality = cx23885_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter cx23885_i2c_adap_template = {
+ .name = "cx23885",
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_CX23885,
+ .algo = &cx23885_i2c_algo_template,
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+};
+
+static struct i2c_client cx23885_i2c_client_template = {
+ .name = "cx23885 internal",
+};
+
+static char *i2c_devs[128] = {
+ [ 0x1c >> 1 ] = "lgdt3303",
+ [ 0x86 >> 1 ] = "tda9887",
+ [ 0x32 >> 1 ] = "cx24227",
+ [ 0x88 >> 1 ] = "cx25837",
+ [ 0x84 >> 1 ] = "tda8295",
+ [ 0xa0 >> 1 ] = "eeprom",
+ [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
+ [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk("%s: i2c scan: found device @ 0x%x [%s]\n",
+ name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/* init + register i2c algo-bit adapter */
+int cx23885_i2c_register(struct cx23885_i2c *bus)
+{
+ struct cx23885_dev *dev = bus->dev;
+
+ dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr);
+
+ memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,
+ sizeof(bus->i2c_adap));
+ memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template,
+ sizeof(bus->i2c_algo));
+ memcpy(&bus->i2c_client, &cx23885_i2c_client_template,
+ sizeof(bus->i2c_client));
+
+ bus->i2c_adap.dev.parent = &dev->pci->dev;
+
+ strlcpy(bus->i2c_adap.name, bus->dev->name,
+ sizeof(bus->i2c_adap.name));
+
+ bus->i2c_algo.data = bus;
+ bus->i2c_adap.algo_data = bus;
+ i2c_add_adapter(&bus->i2c_adap);
+
+ bus->i2c_client.adapter = &bus->i2c_adap;
+
+ if (0 == bus->i2c_rc) {
+ printk("%s: i2c bus %d registered\n", dev->name, bus->nr);
+ if (i2c_scan)
+ do_i2c_scan(dev->name, &bus->i2c_client);
+ } else
+ printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr);
+
+ return bus->i2c_rc;
+}
+
+int cx23885_i2c_unregister(struct cx23885_i2c *bus)
+{
+ i2c_del_adapter(&bus->i2c_adap);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx23885_call_i2c_clients);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
new file mode 100644
index 000000000000..162169f9091b
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -0,0 +1,431 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 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 _CX23885_REG_H_
+#define _CX23885_REG_H_
+
+/*
+Address Map
+0x00000000 -> 0x00009000 TX SRAM (Fifos)
+0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT
+
+EACH CMDS struct is 0x80 bytes long
+
+DMAx_PTR1 = 0x03040 address of first cluster
+DMAx_PTR2 = 0x10600 address of the CDT
+DMAx_CNT1 = cluster size in (bytes >> 4) -1
+DMAx_CNT2 = total cdt size for all entries >> 3
+
+Cluster Descriptor entry = 4 DWORDS
+ DWORD 0 -> ptr to cluster
+ DWORD 1 Reserved
+ DWORD 2 Reserved
+ DWORD 3 Reserved
+
+Channel manager Data Structure entry = 20 DWORD
+ 0 IntialProgramCounterLow
+ 1 IntialProgramCounterHigh
+ 2 ClusterDescriptorTableBase
+ 3 ClusterDescriptorTableSize
+ 4 InstructionQueueBase
+ 5 InstructionQueueSize
+... Reserved
+ 19 Reserved
+*/
+
+/* Risc Instructions */
+#define RISC_CNT_INC 0x00010000
+#define RISC_CNT_RESET 0x00030000
+#define RISC_IRQ1 0x01000000
+#define RISC_IRQ2 0x02000000
+#define RISC_EOL 0x04000000
+#define RISC_SOL 0x08000000
+#define RISC_WRITE 0x10000000
+#define RISC_SKIP 0x20000000
+#define RISC_JUMP 0x70000000
+#define RISC_SYNC 0x80000000
+#define RISC_RESYNC 0x80008000
+#define RISC_READ 0x90000000
+#define RISC_WRITERM 0xB0000000
+#define RISC_WRITECM 0xC0000000
+#define RISC_WRITECR 0xD0000000
+#define RISC_WRITEC 0x50000000
+#define RISC_READC 0xA0000000
+
+
+/* Audio and Video Core */
+#define HOST_REG1 0x00000000
+#define HOST_REG2 0x00000001
+#define HOST_REG3 0x00000002
+
+/* Chip Configuration Registers */
+#define CHIP_CTRL 0x00000100
+#define AFE_CTRL 0x00000104
+#define VID_PLL_INT_POST 0x00000108
+#define VID_PLL_FRAC 0x0000010C
+#define AUX_PLL_INT_POST 0x00000110
+#define AUX_PLL_FRAC 0x00000114
+#define SYS_PLL_INT_POST 0x00000118
+#define SYS_PLL_FRAC 0x0000011C
+#define PIN_CTRL 0x00000120
+#define AUD_IO_CTRL 0x00000124
+#define AUD_LOCK1 0x00000128
+#define AUD_LOCK2 0x0000012C
+#define POWER_CTRL 0x00000130
+#define AFE_DIAG_CTRL1 0x00000134
+#define AFE_DIAG_CTRL3 0x0000013C
+#define PLL_DIAG_CTRL 0x00000140
+#define AFE_CLK_OUT_CTRL 0x00000144
+#define DLL1_DIAG_CTRL 0x0000015C
+
+/* GPIO[23:19] Output Enable */
+#define GPIO2_OUT_EN_REG 0x00000160
+/* GPIO[23:19] Data Registers */
+#define GPIO2 0x00000164
+
+#define IFADC_CTRL 0x00000180
+
+/* Infrared Remote Registers */
+#define IR_CNTRL_REG 0x00000200
+#define IR_TXCLK_REG 0x00000204
+#define IR_RXCLK_REG 0x00000208
+#define IR_CDUTY_REG 0x0000020C
+#define IR_STAT_REG 0x00000210
+#define IR_IRQEN_REG 0x00000214
+#define IR_FILTR_REG 0x00000218
+#define IR_FIFO_REG 0x0000023C
+
+/* Video Decoder Registers */
+#define MODE_CTRL 0x00000400
+#define OUT_CTRL1 0x00000404
+#define OUT_CTRL2 0x00000408
+#define GEN_STAT 0x0000040C
+#define INT_STAT_MASK 0x00000410
+#define LUMA_CTRL 0x00000414
+#define HSCALE_CTRL 0x00000418
+#define VSCALE_CTRL 0x0000041C
+#define CHROMA_CTRL 0x00000420
+#define VBI_LINE_CTRL1 0x00000424
+#define VBI_LINE_CTRL2 0x00000428
+#define VBI_LINE_CTRL3 0x0000042C
+#define VBI_LINE_CTRL4 0x00000430
+#define VBI_LINE_CTRL5 0x00000434
+#define VBI_FC_CFG 0x00000438
+#define VBI_MISC_CFG1 0x0000043C
+#define VBI_MISC_CFG2 0x00000440
+#define VBI_PAY1 0x00000444
+#define VBI_PAY2 0x00000448
+#define VBI_CUST1_CFG1 0x0000044C
+#define VBI_CUST1_CFG2 0x00000450
+#define VBI_CUST1_CFG3 0x00000454
+#define VBI_CUST2_CFG1 0x00000458
+#define VBI_CUST2_CFG2 0x0000045C
+#define VBI_CUST2_CFG3 0x00000460
+#define VBI_CUST3_CFG1 0x00000464
+#define VBI_CUST3_CFG2 0x00000468
+#define VBI_CUST3_CFG3 0x0000046C
+#define HORIZ_TIM_CTRL 0x00000470
+#define VERT_TIM_CTRL 0x00000474
+#define SRC_COMB_CFG 0x00000478
+#define CHROMA_VBIOFF_CFG 0x0000047C
+#define FIELD_COUNT 0x00000480
+#define MISC_TIM_CTRL 0x00000484
+#define DFE_CTRL1 0x00000488
+#define DFE_CTRL2 0x0000048C
+#define DFE_CTRL3 0x00000490
+#define PLL_CTRL 0x00000494
+#define HTL_CTRL 0x00000498
+#define COMB_CTRL 0x0000049C
+#define CRUSH_CTRL 0x000004A0
+#define SOFT_RST_CTRL 0x000004A4
+#define CX885_VERSION 0x000004B4
+#define VBI_PASS_CTRL 0x000004BC
+
+/* Audio Decoder Registers */
+/* 8051 Configuration */
+#define DL_CTL 0x00000800
+#define STD_DET_STATUS 0x00000804
+#define STD_DET_CTL 0x00000808
+#define DW8051_INT 0x0000080C
+#define GENERAL_CTL 0x00000810
+#define AAGC_CTL 0x00000814
+#define DEMATRIX_CTL 0x000008CC
+#define PATH1_CTL1 0x000008D0
+#define PATH1_VOL_CTL 0x000008D4
+#define PATH1_EQ_CTL 0x000008D8
+#define PATH1_SC_CTL 0x000008DC
+#define PATH2_CTL1 0x000008E0
+#define PATH2_VOL_CTL 0x000008E4
+#define PATH2_EQ_CTL 0x000008E8
+#define PATH2_SC_CTL 0x000008EC
+
+/* Sample Rate Converter */
+#define SRC_CTL 0x000008F0
+#define SRC_LF_COEF 0x000008F4
+#define SRC1_CTL 0x000008F8
+#define SRC2_CTL 0x000008FC
+#define SRC3_CTL 0x00000900
+#define SRC4_CTL 0x00000904
+#define SRC5_CTL 0x00000908
+#define SRC6_CTL 0x0000090C
+#define BAND_OUT_SEL 0x00000910
+#define I2S_N_CTL 0x00000914
+#define I2S_OUT_CTL 0x00000918
+#define AUTOCONFIG_REG 0x000009C4
+
+/* Audio ADC Registers */
+#define DSM_CTRL1 0x00000000
+#define DSM_CTRL2 0x00000001
+#define CHP_EN_CTRL 0x00000002
+#define CHP_CLK_CTRL1 0x00000004
+#define CHP_CLK_CTRL2 0x00000005
+#define BG_REF_CTRL 0x00000006
+#define SD2_SW_CTRL1 0x00000008
+#define SD2_SW_CTRL2 0x00000009
+#define SD2_BIAS_CTRL 0x0000000A
+#define AMP_BIAS_CTRL 0x0000000C
+#define CH_PWR_CTRL1 0x0000000E
+#define CH_PWR_CTRL2 0x0000000F
+#define DSM_STATUS1 0x00000010
+#define DSM_STATUS2 0x00000011
+#define DIG_CTL1 0x00000012
+#define DIG_CTL2 0x00000013
+#define I2S_TX_CFG 0x0000001A
+
+#define DEV_CNTRL2 0x00040000
+
+#define PCI_MSK_APB_DMA (1 << 12)
+#define PCI_MSK_AL_WR (1 << 11)
+#define PCI_MSK_AL_RD (1 << 10)
+#define PCI_MSK_RISC_WR (1 << 9)
+#define PCI_MSK_RISC_RD (1 << 8)
+#define PCI_MSK_AUD_EXT (1 << 4)
+#define PCI_MSK_AUD_INT (1 << 3)
+#define PCI_MSK_VID_C (1 << 2)
+#define PCI_MSK_VID_B (1 << 1)
+#define PCI_MSK_VID_A 1
+#define PCI_INT_MSK 0x00040010
+
+#define PCI_INT_STAT 0x00040014
+#define PCI_INT_MSTAT 0x00040018
+
+#define VID_A_INT_MSK 0x00040020
+#define VID_A_INT_STAT 0x00040024
+#define VID_A_INT_MSTAT 0x00040028
+#define VID_A_INT_SSTAT 0x0004002C
+
+#define VID_B_INT_MSK 0x00040030
+#define VID_B_INT_STAT 0x00040034
+#define VID_B_INT_MSTAT 0x00040038
+#define VID_B_INT_SSTAT 0x0004003C
+
+#define VID_B_MSK_BAD_PKT (1 << 20)
+#define VID_B_MSK_OPC_ERR (1 << 16)
+#define VID_B_MSK_SYNC (1 << 12)
+#define VID_B_MSK_OF (1 << 8)
+#define VID_B_MSK_RISCI2 (1 << 4)
+#define VID_B_MSK_RISCI1 1
+
+#define VID_C_MSK_BAD_PKT (1 << 20)
+#define VID_C_MSK_OPC_ERR (1 << 16)
+#define VID_C_MSK_SYNC (1 << 12)
+#define VID_C_MSK_OF (1 << 8)
+#define VID_C_MSK_RISCI2 (1 << 4)
+#define VID_C_MSK_RISCI1 1
+
+/* A superset for testing purposes */
+#define VID_BC_MSK_BAD_PKT (1 << 20)
+#define VID_BC_MSK_OPC_ERR (1 << 16)
+#define VID_BC_MSK_SYNC (1 << 12)
+#define VID_BC_MSK_OF (1 << 8)
+#define VID_BC_MSK_RISCI2 (1 << 4)
+#define VID_BC_MSK_RISCI1 1
+
+#define VID_C_INT_MSK 0x00040040
+#define VID_C_INT_STAT 0x00040044
+#define VID_C_INT_MSTAT 0x00040048
+#define VID_C_INT_SSTAT 0x0004004C
+
+#define AUDIO_INT_INT_MSK 0x00040050
+#define AUDIO_INT_INT_STAT 0x00040054
+#define AUDIO_INT_INT_MSTAT 0x00040058
+#define AUDIO_INT_INT_SSTAT 0x0004005C
+
+#define AUDIO_EXT_INT_MSK 0x00040060
+#define AUDIO_EXT_INT_STAT 0x00040064
+#define AUDIO_EXT_INT_MSTAT 0x00040068
+#define AUDIO_EXT_INT_SSTAT 0x0004006C
+
+#define RDR_CFG0 0x00050000
+#define RDR_CFG1 0x00050004
+#define RDR_TLCTL0 0x00050318
+
+/* APB DMAC Current Buffer Pointer */
+#define DMA1_PTR1 0x00100000
+#define DMA2_PTR1 0x00100004
+#define DMA3_PTR1 0x00100008
+#define DMA4_PTR1 0x0010000C
+#define DMA5_PTR1 0x00100010
+#define DMA6_PTR1 0x00100014
+#define DMA7_PTR1 0x00100018
+#define DMA8_PTR1 0x0010001C
+
+/* APB DMAC Current Table Pointer */
+#define DMA1_PTR2 0x00100040
+#define DMA2_PTR2 0x00100044
+#define DMA3_PTR2 0x00100048
+#define DMA4_PTR2 0x0010004C
+#define DMA5_PTR2 0x00100050
+#define DMA6_PTR2 0x00100054
+#define DMA7_PTR2 0x00100058
+#define DMA8_PTR2 0x0010005C
+
+/* APB DMAC Buffer Limit */
+#define DMA1_CNT1 0x00100080
+#define DMA2_CNT1 0x00100084
+#define DMA3_CNT1 0x00100088
+#define DMA4_CNT1 0x0010008C
+#define DMA5_CNT1 0x00100090
+#define DMA6_CNT1 0x00100094
+#define DMA7_CNT1 0x00100098
+#define DMA8_CNT1 0x0010009C
+
+/* APB DMAC Table Size */
+#define DMA1_CNT2 0x001000C0
+#define DMA2_CNT2 0x001000C4
+#define DMA3_CNT2 0x001000C8
+#define DMA4_CNT2 0x001000CC
+#define DMA5_CNT2 0x001000D0
+#define DMA6_CNT2 0x001000D4
+#define DMA7_CNT2 0x001000D8
+#define DMA8_CNT2 0x001000DC
+
+/* Timer Counters */
+#define TM_CNT_LDW 0x00110000
+#define TM_CNT_UW 0x00110004
+#define TM_LMT_LDW 0x00110008
+#define TM_LMT_UW 0x0011000C
+
+/* GPIO */
+#define GP0_IO 0x00110010
+#define GPIO_ISM 0x00110014
+#define SOFT_RESET 0x0011001C
+
+/* GPIO (417 Microsoftcontroller) RW Data */
+#define MC417_RWD 0x00110020
+
+/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
+#define MC417_OEN 0x00110024
+#define MC417_CTL 0x00110028
+#define CLK_DELAY 0x00110048
+#define PAD_CTRL 0x0011004C
+
+/* Video A Interface */
+#define VID_A_GPCNT 0x00130020
+#define VBI_A_GPCNT 0x00130024
+#define VID_A_GPCNT_CTL 0x00130030
+#define VBI_A_GPCNT_CTL 0x00130034
+#define VID_A_DMA_CTL 0x00130040
+#define VID_A_VIP_CTRL 0x00130080
+#define VID_A_PIXEL_FRMT 0x00130084
+#define VID_A_VBI_CTRL 0x00130088
+
+/* Video B Interface */
+#define VID_B_DMA 0x00130100
+#define VBI_B_DMA 0x00130108
+#define VID_B_GPCNT 0x00130120
+#define VBI_B_GPCNT 0x00130124
+#define VID_B_GPCNT_CTL 0x00130134
+#define VBI_B_GPCNT_CTL 0x00130138
+#define VID_B_DMA_CTL 0x00130140
+#define VID_B_SRC_SEL 0x00130144
+#define VID_B_LNGTH 0x00130150
+#define VID_B_HW_SOP_CTL 0x00130154
+#define VID_B_GEN_CTL 0x00130158
+#define VID_B_BD_PKT_STATUS 0x0013015C
+#define VID_B_SOP_STATUS 0x00130160
+#define VID_B_FIFO_OVFL_STAT 0x00130164
+#define VID_B_VLD_MISC 0x00130168
+#define VID_B_TS_CLK_EN 0x0013016C
+#define VID_B_VIP_CTRL 0x00130180
+#define VID_B_PIXEL_FRMT 0x00130184
+
+/* Video C Interface */
+#define VID_C_GPCNT 0x00130220
+#define VID_C_GPCNT_CTL 0x00130230
+#define VBI_C_GPCNT_CTL 0x00130234
+#define VID_C_DMA_CTL 0x00130240
+#define VID_C_LNGTH 0x00130250
+#define VID_C_HW_SOP_CTL 0x00130254
+#define VID_C_GEN_CTL 0x00130258
+#define VID_C_BD_PKT_STATUS 0x0013025C
+#define VID_C_SOP_STATUS 0x00130260
+#define VID_C_FIFO_OVFL_STAT 0x00130264
+#define VID_C_VLD_MISC 0x00130268
+#define VID_C_TS_CLK_EN 0x0013026C
+
+/* Internal Audio Interface */
+#define AUD_INT_A_GPCNT 0x00140020
+#define AUD_INT_B_GPCNT 0x00140024
+#define AUD_INT_A_GPCNT_CTL 0x00140030
+#define AUD_INT_B_GPCNT_CTL 0x00140034
+#define AUD_INT_DMA_CTL 0x00140040
+#define AUD_INT_A_LNGTH 0x00140050
+#define AUD_INT_B_LNGTH 0x00140054
+#define AUD_INT_A_MODE 0x00140058
+#define AUD_INT_B_MODE 0x0014005C
+
+/* External Audio Interface */
+#define AUD_EXT_DMA 0x00140100
+#define AUD_EXT_GPCNT 0x00140120
+#define AUD_EXT_GPCNT_CTL 0x00140130
+#define AUD_EXT_DMA_CTL 0x00140140
+#define AUD_EXT_LNGTH 0x00140150
+#define AUD_EXT_A_MODE 0x00140158
+
+/* I2C Bus 1 */
+#define I2C1_ADDR 0x00180000
+#define I2C1_WDATA 0x00180004
+#define I2C1_CTRL 0x00180008
+#define I2C1_RDATA 0x0018000C
+#define I2C1_STAT 0x00180010
+
+/* I2C Bus 2 */
+#define I2C2_ADDR 0x00190000
+#define I2C2_WDATA 0x00190004
+#define I2C2_CTRL 0x00190008
+#define I2C2_RDATA 0x0019000C
+#define I2C2_STAT 0x00190010
+
+/* I2C Bus 3 */
+#define I2C3_ADDR 0x001A0000
+#define I2C3_WDATA 0x001A0004
+#define I2C3_CTRL 0x001A0008
+#define I2C3_RDATA 0x001A000C
+#define I2C3_STAT 0x001A0010
+
+/* UART */
+#define UART_CTL 0x001B0000
+#define UART_BRD 0x001B0004
+#define UART_ISR 0x001B000C
+#define UART_CNT 0x001B0010
+
+#endif /* _CX23885_REG_H_ */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
new file mode 100644
index 000000000000..dec4dc2fcbb4
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -0,0 +1,301 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 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 <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/kdev_t.h>
+
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+
+#include "btcx-risc.h"
+#include "cx23885-reg.h"
+
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1)
+
+#define UNSET (-1U)
+
+#define CX23885_MAXBOARDS 8
+
+/* Max number of inputs by card */
+#define MAX_CX23885_INPUT 8
+
+#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */
+
+#define CX23885_BOARD_NOAUTO UNSET
+#define CX23885_BOARD_UNKNOWN 0
+#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1
+#define CX23885_BOARD_HAUPPAUGE_HVR1800 2
+#define CX23885_BOARD_HAUPPAUGE_HVR1250 3
+#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4
+
+enum cx23885_itype {
+ CX23885_VMUX_COMPOSITE1 = 1,
+ CX23885_VMUX_COMPOSITE2,
+ CX23885_VMUX_COMPOSITE3,
+ CX23885_VMUX_COMPOSITE4,
+ CX23885_VMUX_SVIDEO,
+ CX23885_VMUX_TELEVISION,
+ CX23885_VMUX_CABLE,
+ CX23885_VMUX_DVB,
+ CX23885_VMUX_DEBUG,
+ CX23885_RADIO,
+};
+
+enum cx23885_src_sel_type {
+ CX23885_SRC_SEL_EXT_656_VIDEO = 0,
+ CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
+};
+
+/* buffer for one video frame */
+struct cx23885_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ /* cx23885 specific */
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ struct cx23885_fmt *fmt;
+ u32 count;
+};
+
+struct cx23885_input {
+ enum cx23885_itype type;
+ unsigned int vmux;
+ u32 gpio0, gpio1, gpio2, gpio3;
+};
+
+typedef enum {
+ CX23885_MPEG_UNDEFINED = 0,
+ CX23885_MPEG_DVB
+} port_t;
+
+struct cx23885_board {
+ char *name;
+ port_t portb, portc;
+ struct cx23885_input input[MAX_CX23885_INPUT];
+};
+
+struct cx23885_subid {
+ u16 subvendor;
+ u16 subdevice;
+ u32 card;
+};
+
+struct cx23885_i2c {
+ struct cx23885_dev *dev;
+
+ int nr;
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* 885 registers used for raw addess */
+ u32 i2c_period;
+ u32 reg_ctrl;
+ u32 reg_stat;
+ u32 reg_addr;
+ u32 reg_rdata;
+ u32 reg_wdata;
+};
+
+struct cx23885_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+ struct btcx_riscmem stopper;
+ u32 count;
+};
+
+struct cx23885_tsport {
+ struct cx23885_dev *dev;
+
+ int nr;
+ int sram_chno;
+
+ struct videobuf_dvb dvb;
+
+ /* dma queues */
+ struct cx23885_dmaqueue mpegq;
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+
+ int width;
+ int height;
+
+ spinlock_t slock;
+
+ /* registers */
+ u32 reg_gpcnt;
+ u32 reg_gpcnt_ctl;
+ u32 reg_dma_ctl;
+ u32 reg_lngth;
+ u32 reg_hw_sop_ctrl;
+ u32 reg_gen_ctrl;
+ u32 reg_bd_pkt_status;
+ u32 reg_sop_status;
+ u32 reg_fifo_ovfl_stat;
+ u32 reg_vld_misc;
+ u32 reg_ts_clk_en;
+ u32 reg_ts_int_msk;
+ u32 reg_ts_int_stat;
+ u32 reg_src_sel;
+
+ /* Default register vals */
+ int pci_irqmask;
+ u32 dma_ctl_val;
+ u32 ts_int_msk_val;
+ u32 gen_ctrl_val;
+ u32 ts_clk_en_val;
+ u32 src_sel_val;
+};
+
+struct cx23885_dev {
+ struct list_head devlist;
+ atomic_t refcount;
+
+ /* pci stuff */
+ struct pci_dev *pci;
+ unsigned char pci_rev, pci_lat;
+ int pci_bus, pci_slot;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
+ int pci_irqmask;
+
+ /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+ struct cx23885_i2c i2c_bus[3];
+
+ int nr;
+ struct mutex lock;
+
+ /* board details */
+ unsigned int board;
+ char name[32];
+
+ struct cx23885_tsport ts1, ts2;
+
+ /* sram configuration */
+ struct sram_channel *sram_channels;
+
+ enum {
+ CX23885_BRIDGE_UNDEFINED = 0,
+ CX23885_BRIDGE_885 = 885,
+ CX23885_BRIDGE_887 = 887,
+ } bridge;
+};
+
+#define SRAM_CH01 0 /* Video A */
+#define SRAM_CH02 1 /* VBI A */
+#define SRAM_CH03 2 /* Video B */
+#define SRAM_CH04 3 /* Transport via B */
+#define SRAM_CH05 4 /* VBI B */
+#define SRAM_CH06 5 /* Video C */
+#define SRAM_CH07 6 /* Transport via C */
+#define SRAM_CH08 7 /* Audio Internal A */
+#define SRAM_CH09 8 /* Audio Internal B */
+#define SRAM_CH10 9 /* Audio External */
+#define SRAM_CH11 10 /* COMB_3D_N */
+#define SRAM_CH12 11 /* Comb 3D N1 */
+#define SRAM_CH13 12 /* Comb 3D N2 */
+#define SRAM_CH14 13 /* MOE Vid */
+#define SRAM_CH15 14 /* MOE RSLT */
+
+struct sram_channel {
+ char *name;
+ u32 cmds_start;
+ u32 ctrl_start;
+ u32 cdt;
+ u32 fifo_start;;
+ u32 fifo_size;
+ u32 ptr1_reg;
+ u32 ptr2_reg;
+ u32 cnt1_reg;
+ u32 cnt2_reg;
+ u32 jumponly;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg) readl(dev->lmmio + ((reg)>>2))
+#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2))
+
+#define cx_andor(reg,mask,value) \
+ writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+((reg)>>2))
+
+#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
+#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
+
+extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ struct sram_channel *ch,
+ unsigned int bpl, u32 risc);
+
+/* ----------------------------------------------------------- */
+/* cx23885-cards.c */
+
+extern struct cx23885_board cx23885_boards[];
+extern const unsigned int cx23885_bcount;
+
+extern struct cx23885_subid cx23885_subids[];
+extern const unsigned int cx23885_idcount;
+
+extern void cx23885_card_list(struct cx23885_dev *dev);
+extern int cx23885_ir_init(struct cx23885_dev *dev);
+extern void cx23885_gpio_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
+
+extern int cx23885_dvb_register(struct cx23885_tsport *port);
+extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
+
+extern int cx23885_buf_prepare(struct videobuf_queue *q,
+ struct cx23885_tsport *port,
+ struct cx23885_buffer *buf,
+ enum v4l2_field field);
+
+extern void cx23885_buf_queue(struct cx23885_tsport *port,
+ struct cx23885_buffer *buf);
+extern void cx23885_free_buffer(struct videobuf_queue *q,
+ struct cx23885_buffer *buf);
+
+/* ----------------------------------------------------------- */
+/* cx23885-i2c.c */
+extern int cx23885_i2c_register(struct cx23885_i2c *bus);
+extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
+extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
+ void *arg);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index f897c1ebd5f3..3d46a776df36 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -157,13 +157,12 @@ void cx25840_audio_set_path(struct i2c_client *client)
{
struct cx25840_state *state = i2c_get_clientdata(client);
+ /* assert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
/* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0);
- /* assert soft reset */
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
/* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f);
@@ -181,32 +180,46 @@ void cx25840_audio_set_path(struct i2c_client *client)
set_audclk_freq(client, state->audclk_freq);
- /* deassert soft reset */
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
+
+ /* deassert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
}
static int get_volume(struct i2c_client *client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ int vol;
+
+ if (state->unmute_volume >= 0)
+ return state->unmute_volume;
+
/* Volume runs +18dB to -96dB in 1/2dB steps
* change to fit the msp3400 -114dB to +12dB range */
/* check PATH1_VOLUME */
- int vol = 228 - cx25840_read(client, 0x8d4);
+ vol = 228 - cx25840_read(client, 0x8d4);
vol = (vol / 2) + 23;
return vol << 9;
}
static void set_volume(struct i2c_client *client, int volume)
{
- /* First convert the volume to msp3400 values (0-127) */
- int vol = volume >> 9;
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ int vol;
+
+ if (state->unmute_volume >= 0) {
+ state->unmute_volume = volume;
+ return;
+ }
+
+ /* Convert the volume to msp3400 values (0-127) */
+ vol = volume >> 9;
+
/* now scale it up to cx25840 values
* -114dB to -96dB maps to 0
* this should be 19, but in my testing that was 4dB too loud */
@@ -284,30 +297,26 @@ static void set_balance(struct i2c_client *client, int balance)
static int get_mute(struct i2c_client *client)
{
- /* check SRC1_MUTE_EN */
- return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ return state->unmute_volume >= 0;
}
static void set_mute(struct i2c_client *client, int mute)
{
struct cx25840_state *state = i2c_get_clientdata(client);
- if (state->aud_input != CX25840_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 */
- cx25840_and_or(client, 0x803, ~0x10, 0x00);
- cx25840_write(client, 0x8d3, 0x1f);
- } else {
- /* enable microcontroller */
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
- } else {
- /* SRC1_MUTE_EN */
- cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ if (mute && state->unmute_volume == -1) {
+ int vol = get_volume(client);
+
+ set_volume(client, 0);
+ state->unmute_volume = vol;
+ }
+ else if (!mute && state->unmute_volume != -1) {
+ int vol = state->unmute_volume;
+
+ state->unmute_volume = -1;
+ set_volume(client, vol);
}
}
@@ -319,18 +328,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 1);
if (state->aud_input != CX25840_AUDIO_SERIAL) {
cx25840_and_or(client, 0x803, ~0x10, 0);
cx25840_write(client, 0x8d3, 0x1f);
}
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 1);
retval = set_audclk_freq(client, *(u32 *)arg);
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 0);
if (state->aud_input != CX25840_AUDIO_SERIAL) {
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0);
return retval;
case VIDIOC_G_CTRL:
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 67bda9f9a44b..15f191e170d2 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
@@ -133,7 +134,9 @@ static void init_dll1(struct i2c_client *client)
cx25840_write(client, 0x159, 0x23);
cx25840_write(client, 0x15a, 0x87);
cx25840_write(client, 0x15b, 0x06);
+ udelay(10);
cx25840_write(client, 0x159, 0xe1);
+ udelay(10);
cx25840_write(client, 0x15a, 0x86);
cx25840_write(client, 0x159, 0xe0);
cx25840_write(client, 0x159, 0xe1);
@@ -147,6 +150,7 @@ static void init_dll2(struct i2c_client *client)
cx25840_write(client, 0x15d, 0xe3);
cx25840_write(client, 0x15e, 0x86);
cx25840_write(client, 0x15f, 0x06);
+ udelay(10);
cx25840_write(client, 0x15d, 0xe1);
cx25840_write(client, 0x15d, 0xe0);
cx25840_write(client, 0x15d, 0xe1);
@@ -165,9 +169,7 @@ static void cx25836_initialize(struct i2c_client *client)
/* 3c. */
cx25840_and_or(client, 0x159, ~0x02, 0x02);
/* 3d. */
- /* There should be a 10-us delay here, but since the
- i2c bus already has a 10-us delay we don't need to do
- anything */
+ udelay(10);
/* 3e. */
cx25840_and_or(client, 0x159, ~0x02, 0x00);
/* 3f. */
@@ -179,9 +181,18 @@ static void cx25836_initialize(struct i2c_client *client)
cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
}
-static void cx25840_initialize(struct i2c_client *client, int loadfw)
+static void cx25840_work_handler(struct work_struct *work)
{
+ struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
+ cx25840_loadfw(state->c);
+ wake_up(&state->fw_wait);
+}
+
+static void cx25840_initialize(struct i2c_client *client)
+{
+ DEFINE_WAIT(wait);
struct cx25840_state *state = i2c_get_clientdata(client);
+ struct workqueue_struct *q;
/* datasheet startup in numbered steps, refer to page 3-77 */
/* 2. */
@@ -197,8 +208,19 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
cx25840_write(client, 0x13c, 0x01);
cx25840_write(client, 0x13c, 0x00);
/* 5. */
- if (loadfw)
- cx25840_loadfw(client);
+ /* Do the firmware load in a work handler to prevent.
+ Otherwise the kernel is blocked waiting for the
+ bit-banging i2c interface to finish uploading the
+ firmware. */
+ INIT_WORK(&state->fw_work, cx25840_work_handler);
+ init_waitqueue_head(&state->fw_wait);
+ q = create_singlethread_workqueue("cx25840_fw");
+ prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+ queue_work(q, &state->fw_work);
+ schedule();
+ finish_wait(&state->fw_wait, &wait);
+ destroy_workqueue(q);
+
/* 6. */
cx25840_write(client, 0x115, 0x8c);
cx25840_write(client, 0x116, 0x07);
@@ -251,8 +273,13 @@ static void input_change(struct i2c_client *client)
}
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
+ cx25840_and_or(client, 0x810, ~0x01, 1);
- if (std & V4L2_STD_525_60) {
+ if (state->radio) {
+ cx25840_write(client, 0x808, 0xf9);
+ cx25840_write(client, 0x80b, 0x00);
+ }
+ else if (std & V4L2_STD_525_60) {
/* Certain Hauppauge PVR150 models have a hardware bug
that causes audio to drop out. For these models the
audio standard must be set explicitly.
@@ -281,11 +308,7 @@ static void input_change(struct i2c_client *client)
cx25840_write(client, 0x80b, 0x10);
}
- if (cx25840_read(client, 0x803) & 0x10) {
- /* restart audio decoder microcontroller */
- cx25840_and_or(client, 0x803, ~0x10, 0x00);
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
+ cx25840_and_or(client, 0x810, ~0x01, 0);
}
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
@@ -625,6 +648,22 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
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) {
+ v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd);
+ /* initialize on first use */
+ state->is_initialized = 1;
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client);
+ }
+
switch (cmd) {
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct access to the
@@ -825,7 +864,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
if (state->is_cx25836)
cx25836_initialize(client);
else
- cx25840_initialize(client, 0);
+ cx25840_initialize(client);
break;
case VIDIOC_G_CHIP_IDENT:
@@ -856,17 +895,16 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return 0;
- state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- if (state == 0)
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
return -ENOMEM;
- client = &state->c;
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver_cx25840;
snprintf(client->name, sizeof(client->name) - 1, "cx25840");
- v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1);
+ v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
device_id = cx25840_read(client, 0x101) << 8;
device_id |= cx25840_read(client, 0x100);
@@ -875,42 +913,44 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
* 0x83 for the cx2583x and 0x84 for the cx2584x */
if ((device_id & 0xff00) == 0x8300) {
id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
- state->is_cx25836 = 1;
}
else if ((device_id & 0xff00) == 0x8400) {
id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
- state->is_cx25836 = 0;
}
else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
- kfree(state);
+ kfree(client);
return 0;
}
+ state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
/* Note: revision '(device_id & 0x0f) == 2' was never built. The
marking skips from 0x1 == 22 to 0x3 == 23. */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
- address << 1, adapter->name);
+ client->addr << 1, client->adapter->name);
i2c_set_clientdata(client, state);
+ state->c = client;
+ state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
+ state->unmute_volume = -1;
state->vbi_line_offset = 8;
state->id = id;
state->rev = device_id;
i2c_attach_client(client);
- if (state->is_cx25836)
- cx25836_initialize(client);
- else
- cx25840_initialize(client, 1);
-
return 0;
}
@@ -932,6 +972,7 @@ static int cx25840_detach_client(struct i2c_client *client)
}
kfree(state);
+ kfree(client);
return 0;
}
@@ -1056,9 +1097,10 @@ static void log_audio_status(struct i2c_client *client)
}
v4l_info(client, "Detected audio standard: %s\n", p);
v4l_info(client, "Audio muted: %s\n",
- (mute_ctl & 0x2) ? "yes" : "no");
+ (state->unmute_volume >= 0) ? "yes" : "no");
v4l_info(client, "Audio microcontroller: %s\n",
- (download_ctl & 0x10) ? "running" : "stopped");
+ (download_ctl & 0x10) ?
+ ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
switch (audio_config >> 4) {
case 0x00: p = "undefined"; break;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index f4b56d2fd6b6..ea669b1f084d 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -35,17 +35,21 @@ extern int cx25840_debug;
#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
struct cx25840_state {
- struct i2c_client c;
+ struct i2c_client *c;
int pvr150_workaround;
int radio;
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
+ int unmute_volume; /* -1 if not muted */
int vbi_line_offset;
u32 id;
u32 rev;
int is_cx25836;
+ int is_initialized;
+ wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
+ struct work_struct fw_work; /* work entry for fw load */
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0f9d96963618..eeb5224ca101 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_CX88
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
@@ -46,8 +46,8 @@ config VIDEO_CX88_BLACKBIRD
config VIDEO_CX88_DVB
tristate "DVB/ATSC Support for cx2388x based TV cards"
depends on VIDEO_CX88 && DVB_CORE
- select VIDEO_BUF_DVB
- select DVB_PLL
+ select VIDEOBUF_DVB
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_OR51132 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 2d666b56020c..90c36c5705c3 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -3,6 +3,7 @@
* Support for audio capture
* PCI function #1 of the cx2388x.
*
+ * (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
* (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
@@ -27,7 +28,9 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
#include <linux/dma-mapping.h>
+#include <linux/pci.h>
#include <asm/delay.h>
#include <sound/driver.h>
@@ -46,21 +49,16 @@
#define dprintk_core(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
-
/****************************************************************************
Data type declarations - Can be moded to a header file later
****************************************************************************/
-/* These can be replaced after done */
-#define MIXER_ADDR_LAST MAX_CX88_INPUT
-
struct cx88_audio_dev {
struct cx88_core *core;
struct cx88_dmaqueue q;
/* pci i/o */
struct pci_dev *pci;
- unsigned char pci_rev,pci_lat;
/* audio controls */
int irq;
@@ -68,24 +66,17 @@ struct cx88_audio_dev {
struct snd_card *card;
spinlock_t reg_lock;
+ atomic_t count;
unsigned int dma_size;
unsigned int period_size;
unsigned int num_periods;
- struct videobuf_dmabuf dma_risc;
-
- int mixer_volume[MIXER_ADDR_LAST+1][2];
- int capture_source[MIXER_ADDR_LAST+1][2];
-
- long int read_count;
- long int read_offset;
-
- struct cx88_buffer *buf;
+ struct videobuf_dmabuf *dma_risc;
- long opened;
- struct snd_pcm_substream *substream;
+ struct cx88_buffer *buf;
+ struct snd_pcm_substream *substream;
};
typedef struct cx88_audio_dev snd_cx88_card_t;
@@ -98,7 +89,6 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-static struct snd_card *snd_cx88_cards[SNDRV_CARDS];
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
@@ -136,38 +126,39 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
struct cx88_core *core=chip->core;
struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
-
- dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
+ /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
/* setup fifo + format - out channel */
- cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
- buf->bpl, buf->risc.dma);
+ cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
/* sets bpl size */
cx_write(MO_AUDD_LNGTH, buf->bpl);
/* reset counter */
- cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
-
- dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
- /* enable irqs */
- cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
+ cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+ atomic_set(&chip->count, 0);
+ dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+ "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
+ chip->num_periods, buf->bpl * chip->num_periods);
/* Enables corresponding bits at AUD_INT_STAT */
- cx_write(MO_AUD_INTMSK,
- (1<<16)|
- (1<<12)|
- (1<<4)|
- (1<<0)
- );
+ cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+ /* Clean any pending interrupt bits already set */
+ cx_write(MO_AUD_INTSTAT, ~0);
+
+ /* enable audio irqs */
+ cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
/* start dma */
cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
if (debug)
- cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+ cx88_sram_channel_dump(chip->core, audio_ch);
return 0;
}
@@ -184,13 +175,9 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
cx_clear(MO_AUD_DMACNTRL, 0x11);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x02);
- cx_clear(MO_AUD_INTMSK,
- (1<<16)|
- (1<<12)|
- (1<<4)|
- (1<<0)
- );
+ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+ cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
if (debug)
cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
@@ -198,7 +185,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
return 0;
}
-#define MAX_IRQ_LOOP 10
+#define MAX_IRQ_LOOP 50
/*
* BOARD Specific: IRQ dma bits
@@ -223,42 +210,32 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip)
{
struct cx88_core *core = chip->core;
u32 status, mask;
- u32 count;
status = cx_read(MO_AUD_INTSTAT);
mask = cx_read(MO_AUD_INTMSK);
- if (0 == (status & mask)) {
- spin_unlock(&chip->reg_lock);
+ if (0 == (status & mask))
return;
- }
cx_write(MO_AUD_INTSTAT, status);
if (debug > 1 || (status & mask & ~0xff))
cx88_print_irqbits(core->name, "irq aud",
cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
status, mask);
/* risc op code error */
- if (status & (1 << 16)) {
- printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
+ if (status & AUD_INT_OPC_ERR) {
+ printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
cx_clear(MO_AUD_DMACNTRL, 0x11);
cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
}
-
- /* risc1 downstream */
- if (status & 0x01) {
- spin_lock(&chip->reg_lock);
- count = cx_read(MO_AUDD_GPCNT);
- spin_unlock(&chip->reg_lock);
- if (chip->read_count == 0)
- chip->read_count += chip->dma_size;
+ if (status & AUD_INT_DN_SYNC) {
+ dprintk(1, "Downstream sync error\n");
+ cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+ return;
}
-
- if (chip->read_count >= chip->period_size) {
- dprintk(2, "Elapsing period\n");
+ /* risc1 downstream */
+ if (status & AUD_INT_DN_RISCI1) {
+ atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
snd_pcm_period_elapsed(chip->substream);
}
-
- dprintk(3,"Leaving audio IRQ handler...\n");
-
/* FIXME: Any other status should deserve a special handling? */
}
@@ -273,27 +250,26 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id)
int loop, handled = 0;
for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_AUDINT);
if (0 == status)
goto out;
- dprintk( 3, "cx8801_irq\n" );
- dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
- dprintk( 3, " status: %d\n", status );
+ dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
+ loop, MAX_IRQ_LOOP, status);
handled = 1;
cx_write(MO_PCI_INTSTAT, status);
- if (status & 0x02)
- {
- dprintk( 2, " ALSA IRQ handling\n" );
+ if (status & core->pci_irqmask)
+ cx88_core_irq(core, status);
+ if (status & PCI_INT_AUDINT)
cx8801_aud_irq(chip);
- }
- };
+ }
if (MAX_IRQ_LOOP == loop) {
- dprintk( 0, "clearing mask\n" );
- dprintk(1,"%s/0: irq loop -- clearing mask\n",
+ printk(KERN_ERR
+ "%s/1: IRQ loop detected, disabling interrupts\n",
core->name);
- cx_clear(MO_PCI_INTMSK,0x02);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
}
out:
@@ -306,14 +282,15 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
BUG_ON(!chip->dma_size);
dprintk(2,"Freeing buffer\n");
- videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc);
- videobuf_dma_free(&chip->dma_risc);
+ videobuf_pci_dma_unmap(chip->pci, chip->dma_risc);
+ videobuf_dma_free(chip->dma_risc);
btcx_riscmem_free(chip->pci,&chip->buf->risc);
kfree(chip->buf);
+ chip->dma_risc = NULL;
chip->dma_size = 0;
- return 0;
+ return 0;
}
/****************************************************************************
@@ -323,6 +300,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
/*
* Digital hardware definition
*/
+#define DEFAULT_FIFO_SIZE 4096
static struct snd_pcm_hardware snd_cx88_digital_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
@@ -333,22 +311,18 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = {
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 2,
- .buffer_bytes_max = (2*2048),
- .period_bytes_min = 2048,
- .period_bytes_max = 2048,
- .periods_min = 2,
- .periods_max = 2,
+ /* Analog audio output will be full of clicks and pops if there
+ are not exactly four lines in the SRAM FIFO buffer. */
+ .period_bytes_min = DEFAULT_FIFO_SIZE/4,
+ .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+ .periods_min = 1,
+ .periods_max = 1024,
+ .buffer_bytes_max = (1024*1024),
};
/*
- * audio pcm capture runtime free
- */
-static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime)
-{
-}
-/*
* audio pcm capture open callback
*/
static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
@@ -357,26 +331,24 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- if (test_and_set_bit(0, &chip->opened))
- return -EBUSY;
-
- err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;
chip->substream = substream;
- chip->read_count = 0;
- chip->read_offset = 0;
-
- runtime->private_free = snd_card_cx88_runtime_free;
runtime->hw = snd_cx88_digital_hw;
+ if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
+ unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
+ bpl &= ~7; /* must be multiple of 8 */
+ runtime->hw.period_bytes_min = bpl;
+ runtime->hw.period_bytes_max = bpl;
+ }
+
return 0;
_error:
dprintk(1,"Error opening PCM!\n");
- clear_bit(0, &chip->opened);
- smp_mb__after_clear_bit();
return err;
}
@@ -385,11 +357,6 @@ _error:
*/
static int snd_cx88_close(struct snd_pcm_substream *substream)
{
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-
- clear_bit(0, &chip->opened);
- smp_mb__after_clear_bit();
-
return 0;
}
@@ -400,55 +367,67 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
struct snd_pcm_hw_params * hw_params)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ struct videobuf_dmabuf *dma;
+
struct cx88_buffer *buf;
+ int ret;
if (substream->runtime->dma_area) {
dsp_buffer_free(chip);
substream->runtime->dma_area = NULL;
}
-
chip->period_size = params_period_bytes(hw_params);
chip->num_periods = params_periods(hw_params);
chip->dma_size = chip->period_size * params_periods(hw_params);
BUG_ON(!chip->dma_size);
+ BUG_ON(chip->num_periods & (chip->num_periods-1));
- dprintk(1,"Setting buffer\n");
-
- buf = kzalloc(sizeof(*buf),GFP_KERNEL);
+ buf = videobuf_pci_alloc(sizeof(*buf));
if (NULL == buf)
return -ENOMEM;
buf->vb.memory = V4L2_MEMORY_MMAP;
+ buf->vb.field = V4L2_FIELD_NONE;
buf->vb.width = chip->period_size;
+ buf->bpl = chip->period_size;
buf->vb.height = chip->num_periods;
buf->vb.size = chip->dma_size;
- buf->vb.field = V4L2_FIELD_NONE;
- videobuf_dma_init(&buf->vb.dma);
- videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
+ dma=videobuf_to_dma(&buf->vb);
+ videobuf_dma_init(dma);
+ ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+ if (ret < 0)
+ goto error;
- videobuf_pci_dma_map(chip->pci,&buf->vb.dma);
+ ret = videobuf_pci_dma_map(chip->pci,dma);
+ if (ret < 0)
+ goto error;
+ ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+ buf->vb.width, buf->vb.height, 1);
+ if (ret < 0)
+ goto error;
- cx88_risc_databuffer(chip->pci, &buf->risc,
- buf->vb.dma.sglist,
- buf->vb.width, buf->vb.height);
-
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ /* Loop back to start of program */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
buf->vb.state = STATE_PREPARED;
- buf->bpl = chip->period_size;
chip->buf = buf;
- chip->dma_risc = buf->vb.dma;
+ chip->dma_risc = dma;
- dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
- substream->runtime->dma_area = chip->dma_risc.vmalloc;
+ substream->runtime->dma_area = chip->dma_risc->vmalloc;
+ substream->runtime->dma_bytes = chip->dma_size;
+ substream->runtime->dma_addr = 0;
return 0;
+
+error:
+ kfree(buf);
+ return ret;
}
/*
@@ -475,7 +454,6 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream)
return 0;
}
-
/*
* trigger callback
*/
@@ -484,6 +462,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
int err;
+ /* Local interrupts are already disabled by ALSA */
spin_lock(&chip->reg_lock);
switch (cmd) {
@@ -510,17 +489,24 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ u16 count;
- if (chip->read_count) {
- chip->read_count -= snd_pcm_lib_period_bytes(substream);
- chip->read_offset += snd_pcm_lib_period_bytes(substream);
- if (chip->read_offset == chip->dma_size)
- chip->read_offset = 0;
- }
+ count = atomic_read(&chip->count);
- dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
- return bytes_to_frames(runtime, chip->read_offset);
+// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
+// count, new, count & (runtime->periods-1),
+// runtime->period_size * (count & (runtime->periods-1)));
+ return runtime->period_size * (count & (runtime->periods-1));
+}
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ void *pageptr = substream->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
}
/*
@@ -535,6 +521,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = {
.prepare = snd_cx88_prepare,
.trigger = snd_cx88_card_trigger,
.pointer = snd_cx88_pointer,
+ .page = snd_cx88_page,
};
/*
@@ -562,7 +549,7 @@ static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *info)
{
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 1;
+ info->count = 2;
info->value.integer.min = 0;
info->value.integer.max = 0x3f;
@@ -575,8 +562,12 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol,
{
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
struct cx88_core *core=chip->core;
+ int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
+ bal = cx_read(AUD_BAL_CTL);
- value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+ value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
+ vol -= (bal & 0x3f);
+ value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
return 0;
}
@@ -587,16 +578,31 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
{
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
struct cx88_core *core=chip->core;
- int v;
- u32 old_control;
-
+ int v, b;
+ int changed = 0;
+ u32 old;
+
+ b = value->value.integer.value[1] - value->value.integer.value[0];
+ if (b < 0) {
+ v = 0x3f - value->value.integer.value[0];
+ b = (-b) | 0x40;
+ } else {
+ v = 0x3f - value->value.integer.value[1];
+ }
+ /* Do we really know this will always be called with IRQs on? */
spin_lock_irq(&chip->reg_lock);
- old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
- v = 0x3f - (value->value.integer.value[0] & 0x3f);
- cx_andor(AUD_VOL_CTL, 0x3f, v);
+ old = cx_read(AUD_VOL_CTL);
+ if (v != (old & 0x3f)) {
+ cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
+ changed = 1;
+ }
+ if (cx_read(AUD_BAL_CTL) != b) {
+ cx_write(AUD_BAL_CTL, b);
+ changed = 1;
+ }
spin_unlock_irq(&chip->reg_lock);
- return v != old_control;
+ return changed;
}
static struct snd_kcontrol_new snd_cx88_capture_volume = {
@@ -665,6 +671,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
snd_cx88_card_t *chip;
struct cx88_core *core;
int err;
+ unsigned char pci_lat;
*rchip = NULL;
@@ -709,13 +716,12 @@ static int __devinit snd_cx88_create(struct snd_card *card,
}
/* print pci info */
- pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
- pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat);
+ pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", core->name, devno,
- pci_name(pci), chip->pci_rev, pci->irq,
- chip->pci_lat,(unsigned long long)pci_resource_start(pci,0));
+ pci_name(pci), pci->revision, pci->irq,
+ pci_lat, (unsigned long long)pci_resource_start(pci,0));
chip->irq = pci->irq;
synchronize_irq(chip->irq);
@@ -753,17 +759,12 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
return (err);
err = snd_cx88_pcm(chip, 0, "CX88 Digital");
-
- if (err < 0) {
- snd_card_free(card);
- return (err);
- }
+ if (err < 0)
+ goto error;
err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
- if (err < 0) {
- snd_card_free(card);
- return (err);
- }
+ if (err < 0)
+ goto error;
strcpy (card->driver, "CX88x");
sprintf(card->shortname, "Conexant CX%x", pci->device);
@@ -775,16 +776,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
card->driver,devno);
err = snd_card_register(card);
- if (err < 0) {
- snd_card_free(card);
- return (err);
- }
- snd_cx88_cards[devno] = card;
-
+ if (err < 0)
+ goto error;
pci_set_drvdata(pci,card);
devno++;
return 0;
+
+error:
+ snd_card_free(card);
+ return err;
}
/*
* ALSA destructor
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a80b1cb1abe8..6d6f5048d762 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -27,7 +27,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
@@ -56,8 +55,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
/* ------------------------------------------------------------------ */
-#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
-#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
/* defines below are from ivtv-driver.h */
@@ -405,7 +403,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev)
u32 value;
int i;
- for (i = 0; i < dev->fw_size; i++) {
+ for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
memory_read(dev->core, i, &value);
if (value == signature[signaturecnt])
signaturecnt++;
@@ -453,15 +451,12 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
return -1;
}
- if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
- (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
- dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
- firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
- OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
+ if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+ dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+ firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
- dev->fw_size = firmware->size;
if (0 != memcmp(firmware->data, magic, 8)) {
dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
@@ -738,14 +733,14 @@ static int vidioc_querycap (struct file *file, void *priv,
struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx88_blackbird");
- strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+ strlcpy(cap->card, core->board.name, sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
- if (UNSET != core->tuner_type)
+ if (UNSET != core->board.tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -881,7 +876,7 @@ static int vidioc_g_ext_ctrls (struct file *file, void *priv,
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
- return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+ return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS);
}
static int vidioc_s_ext_ctrls (struct file *file, void *priv,
@@ -894,7 +889,7 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv,
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
if (!err) {
err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
dev->params = p;
@@ -912,7 +907,7 @@ static int vidioc_try_ext_ctrls (struct file *file, void *priv,
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
return err;
}
@@ -994,7 +989,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
struct cx8802_fh *fh = priv;
struct cx88_core *core = fh->dev->core;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
f->type = V4L2_TUNER_ANALOG_TV;
@@ -1032,7 +1027,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
u32 reg;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1053,7 +1048,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
{
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
- if (UNSET == core->tuner_type)
+ if (UNSET == core->board.tuner_type)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1082,7 +1077,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
struct cx8802_driver *drv = NULL;
int err;
- dev = cx8802_get_device(inode);
+ dev = cx8802_get_device(inode);
dprintk( 1, "%s\n", __FUNCTION__);
@@ -1116,7 +1111,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
- videobuf_queue_init(&fh->mpegq, &blackbird_qops,
+ videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
@@ -1239,7 +1234,7 @@ static struct video_device cx8802_mpeg_template =
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_s_std = vidioc_s_std,
.tvnorms = CX88_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
};
/* ------------------------------------------------------------------ */
@@ -1250,7 +1245,7 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
struct cx88_core *core = drv->core;
int err = 0;
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* By default, core setup will leave the cx22702 out of reset, on the bus.
* We left the hardware on power up with the cx22702 active.
@@ -1272,7 +1267,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)
struct cx88_core *core = drv->core;
int err = 0;
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Exit leaving the cx23416 on the bus */
break;
@@ -1320,13 +1315,13 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
dprintk( 1, "%s\n", __FUNCTION__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
- core->board,
+ core->boardnr,
core->name,
core->pci_bus,
core->pci_slot);
err = -ENODEV;
- if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
+ if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))
goto fail_core;
dev->width = 720;
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index e61102dc8ad7..a4eb6a87a761 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -27,10 +27,26 @@
#include "cx88.h"
+static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(tuner, int, NULL, 0444);
+module_param_array(radio, int, NULL, 0444);
+module_param_array(card, int, NULL, 0444);
+
+MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(radio,"radio tuner type");
+MODULE_PARM_DESC(card,"card type");
+
+static unsigned int latency = UNSET;
+module_param(latency,int,0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
/* ------------------------------------------------------------------ */
/* board config info */
-struct cx88_board cx88_boards[] = {
+static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
.tuner_type = UNSET,
@@ -575,35 +591,34 @@ struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ /* GPIO[2] = audio source for analog audio out connector
+ * 0 = analog audio input connector
+ * 1 = CX88 audio DACs
+ *
+ * GPIO[7] = input to CX88's audio/chroma ADC
+ * 0 = FM 10.7 MHz IF
+ * 1 = Sound 4.5 MHz IF
+ *
+ * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively
+ *
+ * GPIO[16] = Remote control input
+ */
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00008484,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00008400,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00008400,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
}},
.radio = {
.type = CX88_RADIO,
- .vmux = 2,
- .gpio0 = 0x00008400,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
+ .gpio0 = 0x00008404,
},
.mpeg = CX88_MPEG_DVB,
},
@@ -1335,13 +1350,32 @@ struct cx88_board cx88_boards[] = {
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
},
+ [CX88_BOARD_ADSTECH_PTV_390] = {
+ .name = "ADS Tech Instant Video PCI",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 3,
+ .gpio0 = 0x04ff,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x07fa,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x07fa,
+ }},
+ },
};
-const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
/* ------------------------------------------------------------------ */
/* PCI subsystem IDs */
-struct cx88_subid cx88_subids[] = {
+static const struct cx88_subid cx88_subids[] = {
{
.subvendor = 0x0070,
.subdevice = 0x3400,
@@ -1641,9 +1675,12 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x1421,
.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
.card = CX88_BOARD_KWORLD_DVBS_100,
+ },{
+ .subvendor = 0x1421,
+ .subdevice = 0x0390,
+ .card = CX88_BOARD_ADSTECH_PTV_390,
},
};
-const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
/* ----------------------------------------------------------------------- */
/* some leadtek specific stuff */
@@ -1664,12 +1701,12 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
return;
}
- core->has_radio = 1;
- core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
+ core->board.tuner_type = (eeprom_data[6] == 0x13) ?
+ TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
"tuner=%d, eeprom[0]=0x%02x\n",
- core->name, core->tuner_type, eeprom_data[0]);
+ core->name, core->board.tuner_type, eeprom_data[0]);
}
static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
@@ -1677,9 +1714,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
struct tveeprom tv;
tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
- core->tuner_type = tv.tuner_type;
+ core->board.tuner_type = tv.tuner_type;
core->tuner_formats = tv.tuner_formats;
- core->has_radio = tv.has_radio;
+ core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
/* Make sure we support the board model */
switch (tv.model)
@@ -1769,8 +1806,9 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
name ? name : "unknown");
if (NULL == name)
return;
- core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
- core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm;
+ core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
+ core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ?
+ CX88_RADIO : 0;
}
/* ----------------------------------------------------------------------- */
@@ -1809,7 +1847,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
/* ----------------------------------------------------------------------- */
-void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
+static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
{
int i;
@@ -1830,14 +1868,14 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
}
printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
core->name);
- for (i = 0; i < cx88_bcount; i++)
+ for (i = 0; i < ARRAY_SIZE(cx88_boards); i++)
printk("%s: card=%d -> %s\n",
core->name, i, cx88_boards[i].name);
}
-void cx88_card_setup_pre_i2c(struct cx88_core *core)
+static void cx88_card_setup_pre_i2c(struct cx88_core *core)
{
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
/* We leave here with the 702 on the bus */
@@ -1851,7 +1889,7 @@ void cx88_card_setup_pre_i2c(struct cx88_core *core)
}
}
-void cx88_card_setup(struct cx88_core *core)
+static void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
@@ -1860,7 +1898,7 @@ void cx88_card_setup(struct cx88_core *core)
tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
}
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_ROSLYN:
if (0 == core->i2c_rc)
@@ -1904,7 +1942,7 @@ void cx88_card_setup(struct cx88_core *core)
msleep(1);
cx_set(MO_GP0_IO, 0x00000101);
if (0 == core->i2c_rc &&
- core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+ core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
dvico_fusionhdtv_hybrid_init(core);
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -1942,13 +1980,148 @@ void cx88_card_setup(struct cx88_core *core)
}
break;
}
- if (cx88_boards[core->board].radio.type == CX88_RADIO)
- core->has_radio = 1;
}
/* ------------------------------------------------------------------ */
-EXPORT_SYMBOL(cx88_boards);
+static int cx88_pci_quirks(const char *name, struct pci_dev *pci)
+{
+ unsigned int lat = UNSET;
+ u8 ctrl = 0;
+ u8 value;
+
+ /* check pci quirks */
+ if (pci_pci_problems & PCIPCI_TRITON) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
+ name);
+ ctrl |= CX88X_EN_TBFX;
+ }
+ if (pci_pci_problems & PCIPCI_NATOMA) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
+ name);
+ ctrl |= CX88X_EN_TBFX;
+ }
+ if (pci_pci_problems & PCIPCI_VIAETBF) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
+ name);
+ ctrl |= CX88X_EN_TBFX;
+ }
+ if (pci_pci_problems & PCIPCI_VSFX) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
+ name);
+ ctrl |= CX88X_EN_VSFX;
+ }
+#ifdef PCIPCI_ALIMAGIK
+ if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+ name);
+ lat = 0x0A;
+ }
+#endif
+
+ /* check insmod options */
+ if (UNSET != latency)
+ lat = latency;
+
+ /* apply stuff */
+ if (ctrl) {
+ pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
+ value |= ctrl;
+ pci_write_config_byte(pci, CX88X_DEVCTRL, value);
+ }
+ if (UNSET != lat) {
+ printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+ name, latency);
+ pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
+ }
+ return 0;
+}
+
+int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci)
+{
+ if (request_mem_region(pci_resource_start(pci,0),
+ pci_resource_len(pci,0),
+ core->name))
+ return 0;
+ printk(KERN_ERR
+ "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n",
+ core->name, PCI_FUNC(pci->devfn),
+ (unsigned long long)pci_resource_start(pci, 0),
+ pci->subsystem_vendor, pci->subsystem_device);
+ return -EBUSY;
+}
+
+/* Allocate and initialize the cx88 core struct. One should hold the
+ * devlist mutex before calling this. */
+struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+{
+ struct cx88_core *core;
+ int i;
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+
+ atomic_inc(&core->refcount);
+ core->pci_bus = pci->bus->number;
+ core->pci_slot = PCI_SLOT(pci->devfn);
+ core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT |
+ PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT |
+ PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT;
+ mutex_init(&core->lock);
+
+ core->nr = nr;
+ sprintf(core->name, "cx88[%d]", core->nr);
+ if (0 != cx88_get_resources(core, pci)) {
+ kfree(core);
+ return NULL;
+ }
+
+ /* PCI stuff */
+ cx88_pci_quirks(core->name, pci);
+ core->lmmio = ioremap(pci_resource_start(pci, 0),
+ pci_resource_len(pci, 0));
+ core->bmmio = (u8 __iomem *)core->lmmio;
+
+ /* board config */
+ core->boardnr = UNSET;
+ if (card[core->nr] < ARRAY_SIZE(cx88_boards))
+ core->boardnr = card[core->nr];
+ for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++)
+ if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
+ pci->subsystem_device == cx88_subids[i].subdevice)
+ core->boardnr = cx88_subids[i].card;
+ if (UNSET == core->boardnr) {
+ core->boardnr = CX88_BOARD_UNKNOWN;
+ cx88_card_list(core, pci);
+ }
+
+ memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
+
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ core->name,pci->subsystem_vendor,
+ pci->subsystem_device, core->board.name,
+ core->boardnr, card[core->nr] == core->boardnr ?
+ "insmod option" : "autodetected");
+
+ if (tuner[core->nr] != UNSET)
+ core->board.tuner_type = tuner[core->nr];
+ if (radio[core->nr] != UNSET)
+ core->board.radio_type = radio[core->nr];
+
+ printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n",
+ core->name, core->board.tuner_type, core->board.radio_type);
+
+ /* init hardware */
+ cx88_reset(core);
+ cx88_card_setup_pre_i2c(core);
+ cx88_i2c_init(core, pci);
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
+ cx88_card_setup(core);
+ cx88_ir_init(core, pci);
+
+ return core;
+}
+
+/* ------------------------------------------------------------------ */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index f31ec96924b9..62e8dd24c5f5 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -52,22 +51,6 @@ static unsigned int core_debug = 0;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-static unsigned int latency = UNSET;
-module_param(latency,int,0444);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(tuner, int, NULL, 0444);
-module_param_array(radio, int, NULL, 0444);
-module_param_array(card, int, NULL, 0444);
-
-MODULE_PARM_DESC(tuner,"tuner type");
-MODULE_PARM_DESC(radio,"radio tuner type");
-MODULE_PARM_DESC(card,"card type");
-
static unsigned int nicam = 0;
module_param(nicam,int,0644);
MODULE_PARM_DESC(nicam,"tv audio is nicam");
@@ -85,13 +68,15 @@ static DEFINE_MUTEX(devlist);
#define NO_SYNC_LINE (-1U)
+/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
+ generated _after_ lpi lines are transferred. */
static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
- unsigned int lines)
+ unsigned int lines, unsigned int lpi)
{
struct scatterlist *sg;
- unsigned int line,todo;
+ unsigned int line,todo,sol;
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
@@ -104,15 +89,19 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
offset -= sg_dma_len(sg);
sg++;
}
+ if (lpi && line>0 && !(line % lpi))
+ sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+ else
+ sol = RISC_SOL;
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
offset+=bpl;
} else {
/* scanline needs to be split */
todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|
(sg_dma_len(sg)-offset));
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
todo -= (sg_dma_len(sg)-offset);
@@ -163,10 +152,10 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
rp = risc->cpu;
if (UNSET != top_offset)
rp = cx88_risc_field(rp, sglist, top_offset, 0,
- bpl, padding, lines);
+ bpl, padding, lines, 0);
if (UNSET != bottom_offset)
rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
- bpl, padding, lines);
+ bpl, padding, lines, 0);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -176,7 +165,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
struct scatterlist *sglist, unsigned int bpl,
- unsigned int lines)
+ unsigned int lines, unsigned int lpi)
{
u32 instructions;
u32 *rp;
@@ -193,7 +182,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* write risc instructions */
rp = risc->cpu;
- rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+ rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -224,10 +213,12 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
void
cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -451,10 +442,13 @@ void cx88_sram_channel_dump(struct cx88_core *core,
printk("%s: cmds: %-12s: 0x%08x\n",
core->name,name[i],
cx_read(ch->cmds_start + 4*i));
- for (i = 0; i < 4; i++) {
+ for (n = 1, i = 0; i < 4; i++) {
risc = cx_read(ch->cmds_start + 4 * (i+11));
printk("%s: risc%d: ", core->name, i);
- cx88_risc_decode(risc);
+ if (--n)
+ printk("0x%08x [ arg #%d ]\n", risc, n);
+ else
+ n = cx88_risc_decode(risc);
}
for (i = 0; i < 16; i += n) {
risc = cx_read(ch->ctrl_start + 4 * i);
@@ -514,7 +508,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status)
{
int handled = 0;
- if (status & (1<<18)) {
+ if (status & PCI_INT_IR_SMPINT) {
cx88_ir_irq(core);
handled++;
}
@@ -738,7 +732,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
value |= (1 << 15);
value |= (1 << 16);
}
- if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+ if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
value |= (1 << 13) | (1 << 5);
if (V4L2_FIELD_INTERLACED == field)
value |= (1 << 3); // VINT (interlaced vertical scaling)
@@ -833,7 +827,7 @@ static int set_tvaudio(struct cx88_core *core)
{
v4l2_std_id norm = core->tvnorm;
- if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
+ if (CX88_VMUX_TELEVISION != INPUT(core->input).type)
return 0;
if (V4L2_STD_PAL_BG & norm) {
@@ -997,61 +991,6 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
/* ------------------------------------------------------------------ */
-static int cx88_pci_quirks(char *name, struct pci_dev *pci)
-{
- unsigned int lat = UNSET;
- u8 ctrl = 0;
- u8 value;
-
- /* check pci quirks */
- if (pci_pci_problems & PCIPCI_TRITON) {
- printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
- name);
- ctrl |= CX88X_EN_TBFX;
- }
- if (pci_pci_problems & PCIPCI_NATOMA) {
- printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
- name);
- ctrl |= CX88X_EN_TBFX;
- }
- if (pci_pci_problems & PCIPCI_VIAETBF) {
- printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
- name);
- ctrl |= CX88X_EN_TBFX;
- }
- if (pci_pci_problems & PCIPCI_VSFX) {
- printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
- name);
- ctrl |= CX88X_EN_VSFX;
- }
-#ifdef PCIPCI_ALIMAGIK
- if (pci_pci_problems & PCIPCI_ALIMAGIK) {
- printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
- name);
- lat = 0x0A;
- }
-#endif
-
- /* check insmod options */
- if (UNSET != latency)
- lat = latency;
-
- /* apply stuff */
- if (ctrl) {
- pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
- value |= ctrl;
- pci_write_config_byte(pci, CX88X_DEVCTRL, value);
- }
- if (UNSET != lat) {
- printk(KERN_INFO "%s: setting pci latency timer to %d\n",
- name, latency);
- pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
- }
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
struct video_device *template,
@@ -1067,122 +1006,38 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
vfd->dev = &pci->dev;
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- core->name, type, cx88_boards[core->board].name);
+ core->name, type, core->board.name);
return vfd;
}
-static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
-{
- if (request_mem_region(pci_resource_start(pci,0),
- pci_resource_len(pci,0),
- core->name))
- return 0;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
- core->name,(unsigned long long)pci_resource_start(pci,0));
- return -EBUSY;
-}
-
struct cx88_core* cx88_core_get(struct pci_dev *pci)
{
struct cx88_core *core;
- struct list_head *item;
- int i;
mutex_lock(&devlist);
- list_for_each(item,&cx88_devlist) {
- core = list_entry(item, struct cx88_core, devlist);
+ list_for_each_entry(core, &cx88_devlist, devlist) {
if (pci->bus->number != core->pci_bus)
continue;
if (PCI_SLOT(pci->devfn) != core->pci_slot)
continue;
- if (0 != get_ressources(core,pci))
- goto fail_unlock;
+ if (0 != cx88_get_resources(core, pci)) {
+ mutex_unlock(&devlist);
+ return NULL;
+ }
atomic_inc(&core->refcount);
mutex_unlock(&devlist);
return core;
}
- core = kzalloc(sizeof(*core),GFP_KERNEL);
- if (NULL == core)
- goto fail_unlock;
-
- atomic_inc(&core->refcount);
- core->pci_bus = pci->bus->number;
- core->pci_slot = PCI_SLOT(pci->devfn);
- core->pci_irqmask = 0x00fc00;
- mutex_init(&core->lock);
-
- core->nr = cx88_devcount++;
- sprintf(core->name,"cx88[%d]",core->nr);
- if (0 != get_ressources(core,pci)) {
- printk(KERN_ERR "CORE %s No more PCI ressources for "
- "subsystem: %04x:%04x, board: %s\n",
- core->name,pci->subsystem_vendor,
- pci->subsystem_device,
- cx88_boards[core->board].name);
-
- cx88_devcount--;
- goto fail_free;
- }
- list_add_tail(&core->devlist,&cx88_devlist);
-
- /* PCI stuff */
- cx88_pci_quirks(core->name, pci);
- core->lmmio = ioremap(pci_resource_start(pci,0),
- pci_resource_len(pci,0));
- core->bmmio = (u8 __iomem *)core->lmmio;
-
- /* board config */
- core->board = UNSET;
- if (card[core->nr] < cx88_bcount)
- core->board = card[core->nr];
- for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
- if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
- pci->subsystem_device == cx88_subids[i].subdevice)
- core->board = cx88_subids[i].card;
- if (UNSET == core->board) {
- core->board = CX88_BOARD_UNKNOWN;
- cx88_card_list(core,pci);
+
+ core = cx88_core_create(pci, cx88_devcount);
+ if (NULL != core) {
+ cx88_devcount++;
+ list_add_tail(&core->devlist, &cx88_devlist);
}
- printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- core->name,pci->subsystem_vendor,
- pci->subsystem_device,cx88_boards[core->board].name,
- core->board, card[core->nr] == core->board ?
- "insmod option" : "autodetected");
-
- core->tuner_type = tuner[core->nr];
- core->radio_type = radio[core->nr];
- if (UNSET == core->tuner_type)
- core->tuner_type = cx88_boards[core->board].tuner_type;
- if (UNSET == core->radio_type)
- core->radio_type = cx88_boards[core->board].radio_type;
- if (!core->tuner_addr)
- core->tuner_addr = cx88_boards[core->board].tuner_addr;
- if (!core->radio_addr)
- core->radio_addr = cx88_boards[core->board].radio_addr;
-
- printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
- core->tuner_type, core->tuner_addr<<1,
- core->radio_type, core->radio_addr<<1);
-
- core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
-
- /* init hardware */
- cx88_reset(core);
- cx88_card_setup_pre_i2c(core);
- cx88_i2c_init(core,pci);
- cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
- cx88_card_setup(core);
- cx88_ir_init(core,pci);
mutex_unlock(&devlist);
return core;
-
-fail_free:
- kfree(core);
-fail_unlock:
- mutex_unlock(&devlist);
- return NULL;
}
void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
@@ -1229,6 +1084,9 @@ EXPORT_SYMBOL(cx88_vdev_init);
EXPORT_SYMBOL(cx88_core_get);
EXPORT_SYMBOL(cx88_core_put);
+EXPORT_SYMBOL(cx88_ir_start);
+EXPORT_SYMBOL(cx88_ir_stop);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index dbfe4dc9cf8c..d16e5c6d21c0 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -35,9 +35,7 @@
#include "mt352.h"
#include "mt352_priv.h"
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-# include "cx88-vp3054-i2c.h"
-#endif
+#include "cx88-vp3054-i2c.h"
#include "zl10353.h"
#include "cx22702.h"
#include "or51132.h"
@@ -199,7 +197,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
.demod_init = dvico_dual_demod_init,
};
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { 0x89, 0x38, 0x38 };
@@ -223,64 +221,6 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
-
- /* this message is to set up ATC and ALC */
- static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
- int err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = buf, .len = 4 };
- int err;
-
- /* Switch PLL to DVB mode */
- err = philips_fmd1216_pll_init(fe);
- if (err)
- return err;
-
- /* Tune PLL */
- dvb_pll_configure(dev->core->pll_desc, buf,
- params->frequency,
- params->u.ofdm.bandwidth);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-
- printk(KERN_WARNING "cx88-dvb: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, dev->core->pll_addr, buf[0], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
static struct mt352_config dntv_live_dvbt_pro_config = {
.demod_address = 0x0f,
.no_tuner = 1,
@@ -370,18 +310,8 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
return 0;
}
-static int nxt200x_set_pll_input(u8* buf, int input)
-{
- if (input)
- buf[3] |= 0x08;
- else
- buf[3] &= ~0x08;
- return 0;
-}
-
static struct nxt200x_config ati_hdtvwonder = {
.demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
.set_ts_params = nxt200x_set_ts_param,
};
@@ -448,7 +378,7 @@ static int dvb_register(struct cx8802_dev *dev)
dev->ts_gen_cntrl = 0x0c;
/* init frontend */
- switch (dev->core->board) {
+ switch (dev->core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
@@ -456,7 +386,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt759x);
+ DVB_PLL_THOMSON_DTT759X);
}
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -469,7 +399,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -482,7 +412,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+ &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -491,7 +421,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
break;
}
/* ZL10353 replaces MT352 on later cards */
@@ -500,7 +430,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -511,7 +441,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
break;
}
/* ZL10353 replaces MT352 on later cards */
@@ -520,7 +450,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -529,7 +459,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_lg_z201);
+ NULL, DVB_PLL_LG_Z201);
}
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -540,20 +470,19 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_unknown_1);
+ NULL, DVB_PLL_UNKNOWN_1);
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_fmd1216me;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
if (dev->dvb.frontend != NULL) {
- dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
#else
- printk("%s: built without vp3054 support\n", dev->core->name);
+ printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -563,7 +492,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_fe6600);
+ DVB_PLL_THOMSON_FE6600);
}
break;
case CX88_BOARD_PCHDTV_HD3000:
@@ -572,7 +501,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ DVB_PLL_THOMSON_DTT761X);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -594,7 +523,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_microtune_4042);
+ DVB_PLL_MICROTUNE_4042);
}
}
break;
@@ -614,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ DVB_PLL_THOMSON_DTT761X);
}
}
break;
@@ -634,7 +563,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
}
}
break;
@@ -654,7 +583,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
}
}
break;
@@ -664,7 +593,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tuv1236d);
+ NULL, DVB_PLL_TUV1236D);
}
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -696,19 +625,15 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
default:
- printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
break;
}
if (NULL == dev->dvb.frontend) {
- printk("%s: frontend initialization failed\n",dev->core->name);
+ printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name);
return -1;
}
- if (dev->core->pll_desc) {
- dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
- dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
- }
/* Ensure all frontends negotiate bus access */
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
@@ -728,7 +653,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
int err = 0;
dprintk( 1, "%s\n", __FUNCTION__);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* We arrive here with either the cx23416 or the cx22702
* on the bus. Take the bus from the cx23416 and enable the
@@ -751,7 +676,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
int err = 0;
dprintk( 1, "%s\n", __FUNCTION__);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Do Nothing, leave the cx22702 on the bus. */
break;
@@ -769,24 +694,23 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
dprintk( 1, "%s\n", __FUNCTION__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
- core->board,
+ core->boardnr,
core->name,
core->pci_bus,
core->pci_slot);
err = -ENODEV;
- if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
+ if (!(core->board.mpeg & CX88_MPEG_DVB))
goto fail_core;
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+ /* If vp3054 isn't enabled, a stub will just return 0 */
err = vp3054_i2c_probe(dev);
if (0 != err)
goto fail_core;
-#endif
/* dvb stuff */
- printk("%s/2: cx2388x based dvb card\n", core->name);
- videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
+ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
+ videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
@@ -794,7 +718,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
dev);
err = dvb_register(dev);
if (err != 0)
- printk("%s dvb_register failed err = %d\n", __FUNCTION__, err);
+ printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
+ core->name, err);
fail_core:
return err;
@@ -807,9 +732,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
vp3054_i2c_remove(dev);
-#endif
return 0;
}
@@ -825,7 +748,7 @@ static struct cx8802_driver cx8802_dvb_driver = {
static int dvb_init(void)
{
- printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n",
+ printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 7919a1f9da06..c8b1c50625f4 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -108,28 +107,28 @@ static int attach_inform(struct i2c_client *client)
if (!client->driver->command)
return 0;
- if (core->radio_type != UNSET) {
- if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
+ 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->radio_type;
- tun_setup.addr = core->radio_addr;
+ tun_setup.type = core->board.radio_type;
+ tun_setup.addr = core->board.radio_addr;
client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
}
- if (core->tuner_type != UNSET) {
- if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
+ 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->tuner_type;
- tun_setup.addr = core->tuner_addr;
+ tun_setup.type = core->board.tuner_type;
+ tun_setup.addr = core->board.tuner_addr;
client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
}
}
- if (core->tda9887_conf)
- client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
+ if (core->board.tda9887_conf)
+ client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
return 0;
}
@@ -146,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (0 != core->i2c_rc)
return;
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -160,7 +159,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
-static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
.setsda = cx8800_bit_setsda,
.setscl = cx8800_bit_setscl,
.getsda = cx8800_bit_getsda,
@@ -171,18 +170,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
/* ----------------------------------------------------------------------- */
-static struct i2c_adapter cx8800_i2c_adap_template = {
- .name = "cx2388x",
- .owner = THIS_MODULE,
- .id = I2C_HW_B_CX2388x,
- .client_register = attach_inform,
- .client_unregister = detach_inform,
-};
-
-static struct i2c_client cx8800_i2c_client_template = {
- .name = "cx88xx internal",
-};
-
static char *i2c_devs[128] = {
[ 0x1c >> 1 ] = "lgdt330x",
[ 0x86 >> 1 ] = "tda9887/cx22702",
@@ -212,26 +199,27 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
/* Prevents usage of invalid delay values */
if (i2c_udelay<5)
i2c_udelay=5;
- cx8800_i2c_algo_template.udelay=i2c_udelay;
- memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
- sizeof(core->i2c_adap));
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo));
- memcpy(&core->i2c_client, &cx8800_i2c_client_template,
- sizeof(core->i2c_client));
- if (core->tuner_type != TUNER_ABSENT)
+ if (core->board.tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
- if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB)
+ if (core->board.mpeg & CX88_MPEG_DVB)
core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+ core->i2c_adap.owner = THIS_MODULE;
+ core->i2c_adap.id = I2C_HW_B_CX2388x;
+ core->i2c_adap.client_register = attach_inform;
+ core->i2c_adap.client_unregister = detach_inform;
+ core->i2c_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap,core);
core->i2c_adap.algo_data = &core->i2c_algo;
core->i2c_client.adapter = &core->i2c_adap;
+ strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
cx8800_bit_setscl(core,1);
cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 8136673fe9e8..e52de3968c63 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -27,7 +27,6 @@
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include "cx88.h"
#include <media/ir-common.h>
@@ -74,7 +73,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
- if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+ switch (core->boardnr) {
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
/* This board apparently uses a combination of 2 GPIO
to represent the keys. Additionally, the second GPIO
can be used for parity.
@@ -90,9 +90,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
auxgpio = cx_read(MO_GP1_IO);
/* Take out the parity part */
gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
- } else
+ break;
+ case CX88_BOARD_WINFAST_DTV1000:
+ gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
auxgpio = gpio;
-
+ break;
+ default:
+ auxgpio = gpio;
+ }
if (ir->polling) {
if (ir->last_gpio == auxgpio)
return;
@@ -107,7 +112,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");
- if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) {
+ if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) {
u32 gpio_key = cx_read(MO_GP0_IO);
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
@@ -148,34 +153,30 @@ static void ir_timer(unsigned long data)
static void cx88_ir_work(struct work_struct *work)
{
struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
- unsigned long timeout;
cx88_ir_handle_key(ir);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
+ setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
INIT_WORK(&ir->work, cx88_ir_work);
- init_timer(&ir->timer);
- ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
}
if (ir->sampling) {
- core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
+ core->pci_irqmask |= PCI_INT_IR_SMPINT;
cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
}
-static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->sampling) {
cx_write(MO_DDSCFG_IO, 0x0);
- core->pci_irqmask &= ~(1 << 18);
+ core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
}
if (ir->polling) {
@@ -202,7 +203,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->input = input_dev;
/* detect & configure */
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_KWORLD_DVB_T_CX22702:
@@ -222,7 +223,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
@@ -236,6 +236,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->polling = 50; /* ms */
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
+ case CX88_BOARD_WINFAST_DTV1000:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
@@ -312,8 +313,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
}
/* init input device */
- snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)",
- cx88_boards[core->board].name);
+ snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
@@ -328,7 +328,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
input_dev->id.vendor = pci->vendor;
input_dev->id.product = pci->device;
}
- input_dev->cdev.dev = &pci->dev;
+ input_dev->dev.parent = &pci->dev;
/* record handles to ourself */
ir->core = core;
core->ir = ir;
@@ -404,7 +404,7 @@ void cx88_ir_irq(struct cx88_core *core)
ir_dump_samples(ir->samples, ir->scount);
/* decode it */
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
@@ -442,7 +442,6 @@ void cx88_ir_irq(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 543b05ebc0e7..a652f294d23d 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -23,12 +23,10 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
#include <asm/delay.h>
#include "cx88.h"
@@ -56,9 +54,9 @@ static void request_module_async(struct work_struct *work)
{
struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk);
- if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB)
+ if (dev->core->board.mpeg & CX88_MPEG_DVB)
request_module("cx88-dvb");
- if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD)
+ if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD)
request_module("cx88-blackbird");
}
@@ -96,7 +94,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
if ( (core->active_type_id == CX88_MPEG_DVB) &&
- (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) {
+ (core->board.mpeg & CX88_MPEG_DVB) ) {
dprintk( 1, "cx8802_start_dma doing .dvb\n");
/* negedge driven & software reset */
@@ -104,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
udelay(100);
cx_write(MO_PINMUX_IO, 0x00);
cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -125,7 +123,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
udelay(100);
} else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
- (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) {
+ (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) {
dprintk( 1, "cx8802_start_dma doing .blackbird\n");
cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
@@ -139,7 +137,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
udelay(100);
} else {
printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
- cx88_boards[core->board].mpeg );
+ core->board.mpeg );
return -EINVAL;
}
@@ -149,7 +147,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
/* enable irqs */
dprintk( 1, "setting the interrupt mask\n" );
- cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT);
cx_set(MO_TS_INTMSK, 0x1f0011);
/* start dma */
@@ -167,7 +165,7 @@ static int cx8802_stop_dma(struct cx8802_dev *dev)
cx_clear(MO_TS_DMACNTRL, 0x11);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x000004);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT);
cx_clear(MO_TS_INTMSK, 0x1f0011);
/* Reset the controller */
@@ -181,43 +179,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
struct cx88_buffer *buf;
struct list_head *item;
- dprintk( 1, "cx8802_restart_queue\n" );
+ dprintk( 1, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
{
- struct cx88_buffer *prev;
- prev = NULL;
-
- dprintk(1, "cx8802_restart_queue: queue is empty\n" );
-
- for (;;) {
- if (list_empty(&q->queued))
- return 0;
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
- if (NULL == prev) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue,&q->active);
- cx8802_start_dma(dev, q, buf);
- buf->vb.state = STATE_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(1,"[%p/%d] restart_queue - first active\n",
- buf,buf->vb.i);
-
- } else if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue,&q->active);
- buf->vb.state = STATE_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(1,"[%p/%d] restart_queue - move to active\n",
- buf,buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
+ struct cx88_buffer *prev;
+ prev = NULL;
+
+ dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+ if (NULL == prev) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ cx8802_start_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(1,"[%p/%d] restart_queue - first active\n",
+ buf,buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(1,"[%p/%d] restart_queue - move to active\n",
+ buf,buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
return 0;
}
@@ -239,6 +237,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
struct cx88_buffer *buf, enum v4l2_field field)
{
int size = dev->ts_packet_size * dev->ts_packet_count;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
int rc;
dprintk(1, "%s: %p\n", __FUNCTION__, buf);
@@ -254,8 +253,8 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
goto fail;
cx88_risc_databuffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
- buf->vb.width, buf->vb.height);
+ dma->sglist,
+ buf->vb.width, buf->vb.height, 0);
}
buf->vb.state = STATE_PREPARED;
return 0;
@@ -336,7 +335,7 @@ static void cx8802_timeout(unsigned long data)
{
struct cx8802_dev *dev = (struct cx8802_dev*)data;
- dprintk(0, "%s\n",__FUNCTION__);
+ dprintk(1, "%s\n",__FUNCTION__);
if (debug)
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -414,7 +413,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
int loop, handled = 0;
for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_TSINT);
if (0 == status)
goto out;
dprintk( 1, "cx8802_irq\n" );
@@ -425,7 +425,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
if (status & core->pci_irqmask)
cx88_core_irq(core,status);
- if (status & 0x04)
+ if (status & PCI_INT_TSINT)
cx8802_mpeg_irq(dev);
};
if (MAX_IRQ_LOOP == loop) {
@@ -580,7 +580,7 @@ struct cx8802_dev * cx8802_get_device(struct inode *inode)
list_for_each(list,&cx8802_devlist) {
h = list_entry(list, struct cx8802_dev, devlist);
- if (h->mpeg_dev->minor == minor)
+ if (h->mpeg_dev && h->mpeg_dev->minor == minor)
return h;
}
@@ -676,22 +676,24 @@ int cx8802_register_driver(struct cx8802_driver *drv)
struct list_head *list;
int err = 0, i = 0;
- printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ ,
- drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
- drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+ printk(KERN_INFO
+ "cx88/2: registering cx8802 driver, type: %s access: %s\n",
+ drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+ drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
if ((err = cx8802_check_driver(drv)) != 0) {
- printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ );
+ printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n");
return err;
}
list_for_each(list,&cx8802_devlist) {
h = list_entry(list, struct cx8802_dev, devlist);
- printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
- h->core->name,h->pci->subsystem_vendor,
- h->pci->subsystem_device,cx88_boards[h->core->board].name,
- h->core->board);
+ printk(KERN_INFO
+ "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+ h->core->name, h->pci->subsystem_vendor,
+ h->pci->subsystem_device, h->core->board.name,
+ h->core->boardnr);
/* Bring up a new struct for each driver instance */
driver = kzalloc(sizeof(*drv),GFP_KERNEL);
@@ -713,7 +715,9 @@ int cx8802_register_driver(struct cx8802_driver *drv)
list_add_tail(&driver->devlist,&h->drvlist.devlist);
mutex_unlock(&drv->core->lock);
} else {
- printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err);
+ printk(KERN_ERR
+ "%s/2: cx8802 probe failed, err = %d\n",
+ h->core->name, err);
}
}
@@ -733,17 +737,20 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
struct list_head *list2, *q;
int err = 0, i = 0;
- printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ ,
- drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird");
+ printk(KERN_INFO
+ "cx88/2: unregistering cx8802 driver, type: %s access: %s\n",
+ drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+ drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
list_for_each(list,&cx8802_devlist) {
i++;
h = list_entry(list, struct cx8802_dev, devlist);
- printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
- h->core->name,h->pci->subsystem_vendor,
- h->pci->subsystem_device,cx88_boards[h->core->board].name,
- h->core->board);
+ printk(KERN_INFO
+ "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+ h->core->name, h->pci->subsystem_vendor,
+ h->pci->subsystem_device, h->core->board.name,
+ h->core->boardnr);
list_for_each_safe(list2, q, &h->drvlist.devlist) {
d = list_entry(list2, struct cx8802_driver, devlist);
@@ -758,7 +765,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
list_del(list2);
mutex_unlock(&drv->core->lock);
} else
- printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err);
+ printk(KERN_ERR "%s/2: cx8802 driver remove "
+ "failed (%d)\n", h->core->name, err);
}
@@ -783,7 +791,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
err = -ENODEV;
- if (!cx88_boards[core->board].mpeg)
+ if (!core->board.mpeg)
goto fail_core;
err = -ENOMEM;
@@ -866,7 +874,7 @@ static struct pci_driver cx8802_pci_driver = {
static int cx8802_init(void)
{
- printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n",
+ printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index d3bf5b17b1d4..2ec52d1cdea0 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -582,6 +582,28 @@
/* ---------------------------------------------------------------------- */
/* various constants */
+// DMA
+/* Interrupt mask/status */
+#define PCI_INT_VIDINT (1 << 0)
+#define PCI_INT_AUDINT (1 << 1)
+#define PCI_INT_TSINT (1 << 2)
+#define PCI_INT_VIPINT (1 << 3)
+#define PCI_INT_HSTINT (1 << 4)
+#define PCI_INT_TM1INT (1 << 5)
+#define PCI_INT_SRCDMAINT (1 << 6)
+#define PCI_INT_DSTDMAINT (1 << 7)
+#define PCI_INT_RISC_RD_BERRINT (1 << 10)
+#define PCI_INT_RISC_WR_BERRINT (1 << 11)
+#define PCI_INT_BRDG_BERRINT (1 << 12)
+#define PCI_INT_SRC_DMA_BERRINT (1 << 13)
+#define PCI_INT_DST_DMA_BERRINT (1 << 14)
+#define PCI_INT_IPB_DMA_BERRINT (1 << 15)
+#define PCI_INT_I2CDONE (1 << 16)
+#define PCI_INT_I2CRACK (1 << 17)
+#define PCI_INT_IR_SMPINT (1 << 18)
+#define PCI_INT_GPIO_INT0 (1 << 19)
+#define PCI_INT_GPIO_INT1 (1 << 20)
+
#define SEL_BTSC 0x01
#define SEL_EIAJ 0x02
#define SEL_A2 0x04
@@ -590,6 +612,19 @@
#define SEL_FMRADIO 0x20
// AUD_CTL
+#define AUD_INT_DN_RISCI1 (1 << 0)
+#define AUD_INT_UP_RISCI1 (1 << 1)
+#define AUD_INT_RDS_DN_RISCI1 (1 << 2)
+#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2 (1 << 5)
+#define AUD_INT_RDS_DN_RISCI2 (1 << 6)
+#define AUD_INT_DN_SYNC (1 << 12)
+#define AUD_INT_UP_SYNC (1 << 13)
+#define AUD_INT_RDS_DN_SYNC (1 << 14)
+#define AUD_INT_OPC_ERR (1 << 16)
+#define AUD_INT_BER_IRQ (1 << 20)
+#define AUD_INT_MCHG_IRQ (1 << 21)
+
#define EN_BTSC_FORCE_MONO 0
#define EN_BTSC_FORCE_STEREO 1
#define EN_BTSC_FORCE_SAP 2
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 1cc2d286a1cb..76e5c78d8ae4 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -36,7 +36,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/freezer.h>
#include <linux/kernel.h>
@@ -62,6 +61,10 @@ static unsigned int always_analog = 0;
module_param(always_analog,int,0644);
MODULE_PARM_DESC(always_analog,"force analog audio out");
+static unsigned int radio_deemphasis = 0;
+module_param(radio_deemphasis,int,0644);
+MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
+ "0=None, 1=50us (elsewhere), 2=75us (USA)");
#define dprintk(fmt, arg...) if (audio_debug) \
printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
@@ -140,7 +143,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
cx88_start_audio_dma(core);
- if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
@@ -149,7 +152,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_I2SCNTL, 0);
/* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
}
- if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) {
+ if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) {
ctl |= EN_DAC_ENABLE;
cx_write(AUD_CTL, ctl);
}
@@ -678,6 +681,10 @@ static void set_audio_standard_FM(struct cx88_core *core,
};
/* It is enough to leave default values? */
+ /* No, it's not! The deemphasis registers are reset to the 75us
+ * values by default. Analyzing the spectrum of the decoded audio
+ * reveals that "no deemphasis" is the same as 75 us, while the 50 us
+ * setting results in less deemphasis. */
static const struct rlist fm_no_deemph[] = {
{AUD_POLYPH80SCALEFAC, 0x0003},
@@ -688,6 +695,7 @@ static void set_audio_standard_FM(struct cx88_core *core,
set_audio_start(core, SEL_FMRADIO);
switch (deemph) {
+ default:
case FM_NO_DEEMPH:
set_audio_registers(core, fm_no_deemph);
break;
@@ -757,7 +765,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
set_audio_standard_EIAJ(core);
break;
case WW_FM:
- set_audio_standard_FM(core, FM_NO_DEEMPH);
+ set_audio_standard_FM(core, radio_deemphasis);
break;
case WW_NONE:
default:
@@ -790,9 +798,9 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
core->astat = reg;
/* TODO
- Reading from AUD_STATUS is not enough
- for auto-detecting sap/dual-fm/nicam.
- Add some code here later.
+ Reading from AUD_STATUS is not enough
+ for auto-detecting sap/dual-fm/nicam.
+ Add some code here later.
*/
return;
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 86c1cf8334bc..babb08556406 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -2,7 +2,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -67,7 +66,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
q->count = 1;
/* enable irqs */
- cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
cx_set(MO_VID_INTMSK, 0x0f0088);
/* enable capture */
@@ -91,7 +90,7 @@ int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
cx_clear(VID_CAPTURE_CONTROL,0x18);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x000001);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
cx_clear(MO_VID_INTMSK, 0x0f0088);
return 0;
}
@@ -100,7 +99,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
{
struct cx88_buffer *buf;
- struct list_head *item;
if (list_empty(&q->active))
return 0;
@@ -109,10 +107,8 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
cx8800_start_vbi_dma(dev, q, buf);
- list_for_each(item,&q->active) {
- buf = list_entry(item, struct cx88_buffer, vb.queue);
+ list_for_each_entry(buf, &q->active, vb.queue)
buf->count = q->count++;
- }
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -173,6 +169,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
return -EINVAL;
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
buf->vb.width = VBI_LINE_LENGTH;
buf->vb.height = VBI_LINE_COUNT;
buf->vb.size = size;
@@ -181,7 +178,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
goto fail;
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
+ dma->sglist,
0, buf->vb.width * buf->vb.height,
buf->vb.width, 0,
buf->vb.height);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 98fa35421bdd..231ae6c4dd22 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -36,7 +35,6 @@
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/kthread.h>
-#include <linux/dma-mapping.h>
#include <asm/div64.h>
#include "cx88.h"
@@ -369,17 +367,17 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
/* struct cx88_core *core = dev->core; */
dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",
- input, INPUT(input)->vmux,
- INPUT(input)->gpio0,INPUT(input)->gpio1,
- INPUT(input)->gpio2,INPUT(input)->gpio3);
+ input, INPUT(input).vmux,
+ INPUT(input).gpio0,INPUT(input).gpio1,
+ INPUT(input).gpio2,INPUT(input).gpio3);
core->input = input;
- cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14);
- cx_write(MO_GP3_IO, INPUT(input)->gpio3);
- cx_write(MO_GP0_IO, INPUT(input)->gpio0);
- cx_write(MO_GP1_IO, INPUT(input)->gpio1);
- cx_write(MO_GP2_IO, INPUT(input)->gpio2);
+ cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14);
+ cx_write(MO_GP3_IO, INPUT(input).gpio3);
+ cx_write(MO_GP0_IO, INPUT(input).gpio0);
+ cx_write(MO_GP1_IO, INPUT(input).gpio1);
+ cx_write(MO_GP2_IO, INPUT(input).gpio2);
- switch (INPUT(input)->type) {
+ switch (INPUT(input).type) {
case CX88_VMUX_SVIDEO:
cx_set(MO_AFECFG_IO, 0x00000001);
cx_set(MO_INPUT_FORMAT, 0x00010010);
@@ -394,9 +392,9 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
break;
}
- if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
/* sets sound input from external adc */
- if (INPUT(input)->extadc)
+ if (INPUT(input).extadc)
cx_set(AUD_CTL, EN_I2SIN_ENABLE);
else
cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
@@ -424,7 +422,7 @@ static int start_video_dma(struct cx8800_dev *dev,
q->count = 1;
/* enable irqs */
- cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
/* Enables corresponding bits at PCI_INT_STAT:
bits 0 to 4: video, audio, transport stream, VIP, Host
@@ -457,7 +455,7 @@ static int stop_video_dma(struct cx8800_dev *dev)
cx_clear(VID_CAPTURE_CONTROL,0x06);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x000001);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
cx_clear(MO_VID_INTMSK, 0x0f0011);
return 0;
}
@@ -468,17 +466,14 @@ static int restart_video_queue(struct cx8800_dev *dev,
{
struct cx88_core *core = dev->core;
struct cx88_buffer *buf, *prev;
- struct list_head *item;
if (!list_empty(&q->active)) {
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
start_video_dma(dev, q, buf);
- list_for_each(item,&q->active) {
- buf = list_entry(item, struct cx88_buffer, vb.queue);
- buf->count = q->count++;
- }
+ list_for_each_entry(buf, &q->active, vb.queue)
+ buf->count = q->count++;
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -536,6 +531,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct cx8800_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
int rc, init_buffer = 0;
BUG_ON(NULL == fh->fmt);
@@ -568,30 +564,30 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist, 0, UNSET,
+ dma->sglist, 0, UNSET,
buf->bpl, 0, buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist, UNSET, 0,
+ dma->sglist, UNSET, 0,
buf->bpl, 0, buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist, 0, buf->bpl,
+ dma->sglist, 0, buf->bpl,
buf->bpl, buf->bpl,
buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
+ dma->sglist,
0, buf->bpl * (buf->vb.height >> 1),
buf->bpl, 0,
buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_BT:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
+ dma->sglist,
buf->bpl * (buf->vb.height >> 1), 0,
buf->bpl, 0,
buf->vb.height >> 1);
@@ -714,12 +710,10 @@ static int video_open(struct inode *inode, struct file *file)
struct cx8800_dev *h,*dev = NULL;
struct cx88_core *core;
struct cx8800_fh *fh;
- struct list_head *list;
enum v4l2_buf_type type = 0;
int radio = 0;
- list_for_each(list,&cx8800_devlist) {
- h = list_entry(list, struct cx8800_dev, devlist);
+ list_for_each_entry(h, &cx8800_devlist, devlist) {
if (h->video_dev->minor == minor) {
dev = h;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -754,13 +748,13 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 240;
fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
- videobuf_queue_init(&fh->vidq, &cx8800_video_qops,
+ videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
fh);
- videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops,
+ videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
@@ -768,12 +762,11 @@ static int video_open(struct inode *inode, struct file *file)
fh);
if (fh->radio) {
- int board = core->board;
dprintk(1,"video_open: setting radio device\n");
- cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
- cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0);
- cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1);
- cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2);
+ cx_write(MO_GP3_IO, core->board.radio.gpio3);
+ cx_write(MO_GP0_IO, core->board.radio.gpio0);
+ cx_write(MO_GP1_IO, core->board.radio.gpio1);
+ cx_write(MO_GP2_IO, core->board.radio.gpio2);
core->tvaudio = WW_FM;
cx88_set_tvaudio(core);
cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
@@ -1079,8 +1072,7 @@ static int vidioc_querycap (struct file *file, void *priv,
struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
+ strlcpy(cap->card, core->board.name, sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
cap->capabilities =
@@ -1088,7 +1080,7 @@ static int vidioc_querycap (struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_VBI_CAPTURE;
- if (UNSET != core->tuner_type)
+ if (UNSET != core->board.tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -1108,28 +1100,9 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
- struct cx8800_fh *fh = priv;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int err;
+ struct cx8800_fh *fh = priv;
- q = get_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
-
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
+ return videobuf_cgmbuf (get_queue(fh), mbuf, 8);
}
#endif
@@ -1222,14 +1195,14 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
n = i->index;
if (n >= 4)
return -EINVAL;
- if (0 == INPUT(n)->type)
+ if (0 == INPUT(n).type)
return -EINVAL;
memset(i,0,sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name,iname[INPUT(n)->type]);
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX88_VMUX_CABLE == INPUT(n)->type))
+ strcpy(i->name,iname[INPUT(n).type]);
+ if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
+ (CX88_VMUX_CABLE == INPUT(n).type))
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = CX88_NORMS;
return 0;
@@ -1298,7 +1271,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
u32 reg;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1319,7 +1292,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- if (UNSET == core->tuner_type)
+ if (UNSET == core->board.tuner_type)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1334,7 +1307,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
struct cx8800_fh *fh = priv;
struct cx88_core *core = fh->dev->core;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
@@ -1349,7 +1322,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
int cx88_set_freq (struct cx88_core *core,
struct v4l2_frequency *f)
{
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (unlikely(f->tuner != 0))
return -EINVAL;
@@ -1420,8 +1393,7 @@ static int radio_querycap (struct file *file, void *priv,
struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
+ strlcpy(cap->card, core->board.name, sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
cap->capabilities = V4L2_CAP_TUNER;
@@ -1608,7 +1580,8 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
int loop, handled = 0;
for (loop = 0; loop < 10; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01);
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_VIDINT);
if (0 == status)
goto out;
cx_write(MO_PCI_INTSTAT, status);
@@ -1616,7 +1589,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
if (status & core->pci_irqmask)
cx88_core_irq(core,status);
- if (status & 0x01)
+ if (status & PCI_INT_VIDINT)
cx8800_vid_irq(dev);
};
if (10 == loop) {
@@ -1717,6 +1690,10 @@ static struct video_device cx8800_radio_template =
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
};
/* ----------------------------------------------------------- */
@@ -1818,26 +1795,32 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
err = request_irq(pci_dev->irq, cx8800_irq,
IRQF_SHARED | IRQF_DISABLED, core->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get IRQ %d\n",
+ printk(KERN_ERR "%s/0: can't get IRQ %d\n",
core->name,pci_dev->irq);
goto fail_core;
}
cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* load and configure helper modules */
- if (TUNER_ABSENT != core->tuner_type)
+ if (TUNER_ABSENT != core->board.tuner_type)
request_module("tuner");
- if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775)
+ if (core->board.audio_chip == AUDIO_CHIP_WM8775)
request_module("wm8775");
+ switch (core->boardnr) {
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+ request_module("ir-kbd-i2c");
+ request_module("rtc-isl1208");
+ }
+
/* register v4l devices */
dev->video_dev = cx88_vdev_init(core,dev->pci,
&cx8800_video_template,"video");
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s: can't register video device\n",
+ printk(KERN_ERR "%s/0: can't register video device\n",
core->name);
goto fail_unreg;
}
@@ -1848,20 +1831,20 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s/0: can't register vbi device\n",
+ printk(KERN_ERR "%s/0: can't register vbi device\n",
core->name);
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device vbi%d\n",
core->name,dev->vbi_dev->minor & 0x1f);
- if (core->has_radio) {
+ if (core->board.radio.type == CX88_RADIO) {
dev->radio_dev = cx88_vdev_init(core,dev->pci,
&cx8800_radio_template,"radio");
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s/0: can't register radio device\n",
+ printk(KERN_ERR "%s/0: can't register radio device\n",
core->name);
goto fail_unreg;
}
@@ -1881,8 +1864,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
mutex_unlock(&core->lock);
/* start tvaudio thread */
- if (core->tuner_type != TUNER_ABSENT)
+ if (core->board.tuner_type != TUNER_ABSENT) {
core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+ if (IS_ERR(core->kthread)) {
+ err = PTR_ERR(core->kthread);
+ printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n",
+ core->name, err);
+ }
+ }
return 0;
fail_unreg:
@@ -1931,17 +1920,19 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
/* stop video+vbi capture */
spin_lock(&dev->slock);
if (!list_empty(&dev->vidq.active)) {
- printk("%s: suspend video\n", core->name);
+ printk("%s/0: suspend video\n", core->name);
stop_video_dma(dev);
del_timer(&dev->vidq.timeout);
}
if (!list_empty(&dev->vbiq.active)) {
- printk("%s: suspend vbi\n", core->name);
+ printk("%s/0: suspend vbi\n", core->name);
cx8800_stop_vbi_dma(dev);
del_timer(&dev->vbiq.timeout);
}
spin_unlock(&dev->slock);
+ if (core->ir)
+ cx88_ir_stop(core, core->ir);
/* FIXME -- shutdown device */
cx88_shutdown(core);
@@ -1962,8 +1953,8 @@ static int cx8800_resume(struct pci_dev *pci_dev)
if (dev->state.disabled) {
err=pci_enable_device(pci_dev);
if (err) {
- printk(KERN_ERR "%s: can't enable device\n",
- core->name);
+ printk(KERN_ERR "%s/0: can't enable device\n",
+ core->name);
return err;
}
@@ -1971,9 +1962,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
}
err= pci_set_power_state(pci_dev, PCI_D0);
if (err) {
- printk(KERN_ERR "%s: can't enable device\n",
- core->name);
-
+ printk(KERN_ERR "%s/0: can't set power state\n", core->name);
pci_disable_device(pci_dev);
dev->state.disabled = 1;
@@ -1983,15 +1972,19 @@ static int cx8800_resume(struct pci_dev *pci_dev)
/* FIXME: re-initialize hardware */
cx88_reset(core);
+ if (core->ir)
+ cx88_ir_start(core, core->ir);
+
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* restart video+vbi capture */
spin_lock(&dev->slock);
if (!list_empty(&dev->vidq.active)) {
- printk("%s: resume video\n", core->name);
+ printk("%s/0: resume video\n", core->name);
restart_video_queue(dev,&dev->vidq);
}
if (!list_empty(&dev->vbiq.active)) {
- printk("%s: resume vbi\n", core->name);
+ printk("%s/0: resume vbi\n", core->name);
cx8800_restart_vbi_queue(dev,&dev->vbiq);
}
spin_unlock(&dev->slock);
@@ -2027,7 +2020,7 @@ static struct pci_driver cx8800_pci_driver = {
static int cx8800_init(void)
{
- printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n",
+ printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 82bc3a28aa22..77c37889232b 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -23,7 +23,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -94,7 +93,7 @@ static int vp3054_bit_getsda(void *data)
/* ----------------------------------------------------------------------- */
-static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
.setsda = vp3054_bit_setsda,
.setscl = vp3054_bit_setscl,
.getsda = vp3054_bit_getsda,
@@ -105,19 +104,13 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
/* ----------------------------------------------------------------------- */
-static struct i2c_adapter vp3054_i2c_adap_template = {
- .name = "cx2388x",
- .owner = THIS_MODULE,
- .id = I2C_HW_B_CX2388x,
-};
-
int vp3054_i2c_probe(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
struct vp3054_i2c_state *vp3054_i2c;
int rc;
- if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+ if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
return 0;
dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
@@ -125,8 +118,6 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
return -ENOMEM;
vp3054_i2c = dev->card_priv;
- memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
- sizeof(vp3054_i2c->adap));
memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
sizeof(vp3054_i2c->algo));
@@ -135,6 +126,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
strlcpy(vp3054_i2c->adap.name, core->name,
sizeof(vp3054_i2c->adap.name));
+ vp3054_i2c->adap.owner = THIS_MODULE;
+ vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
vp3054_i2c->algo.data = dev;
i2c_set_adapdata(&vp3054_i2c->adap, dev);
vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
@@ -158,7 +151,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev)
struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
if (vp3054_i2c == NULL ||
- dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+ dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
return;
i2c_del_adapter(&vp3054_i2c->adap);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
index 637a7d232238..be99c931dc3e 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.h
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h
@@ -30,5 +30,12 @@ struct vp3054_i2c_state {
};
/* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
int vp3054_i2c_probe(struct cx8802_dev *dev);
void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 738d4f20c580..42e0a9b8c550 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -28,11 +28,11 @@
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
#include <media/cx2341x.h>
#include <media/audiochip.h>
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-#include <media/video-buf-dvb.h>
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+#include <media/videobuf-dvb.h>
#endif
#include "btcx-risc.h"
@@ -209,6 +209,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_NORWOOD_MICRO 54
#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
#define CX88_BOARD_HAUPPAUGE_HVR1300 56
+#define CX88_BOARD_ADSTECH_PTV_390 57
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -225,8 +226,8 @@ enum cx88_itype {
struct cx88_input {
enum cx88_itype type;
- unsigned int vmux;
u32 gpio0, gpio1, gpio2, gpio3;
+ unsigned int vmux:2;
unsigned int extadc:1;
};
@@ -249,7 +250,7 @@ struct cx88_subid {
u32 card;
};
-#define INPUT(nr) (&cx88_boards[core->board].input[nr])
+#define INPUT(nr) (core->board.input[nr])
/* ----------------------------------------------------------- */
/* device / file handle status */
@@ -258,7 +259,7 @@ struct cx88_subid {
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
/* buffer for one video frame */
struct cx88_buffer {
@@ -303,21 +304,14 @@ struct cx88_core {
u32 i2c_state, i2c_rc;
/* config info -- analog */
- unsigned int board;
- unsigned int tuner_type;
- unsigned int radio_type;
- unsigned char tuner_addr;
- unsigned char radio_addr;
- unsigned int tda9887_conf;
- unsigned int has_radio;
+ unsigned int boardnr;
+ struct cx88_board board;
/* Supported V4L _STD_ tuner formats */
unsigned int tuner_formats;
/* config info -- dvb */
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
- struct dvb_pll_desc *pll_desc;
- unsigned int pll_addr;
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
#endif
@@ -463,13 +457,10 @@ struct cx8802_dev {
u32 mailbox;
int width;
int height;
- int fw_size;
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
- void* fe_handle;
- int (*fe_release)(void *handle);
void *card_priv;
#endif
@@ -528,7 +519,7 @@ cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
extern int
cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
struct scatterlist *sglist, unsigned int bpl,
- unsigned int lines);
+ unsigned int lines, unsigned int lpi);
extern int
cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value);
@@ -589,15 +580,9 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
/* ----------------------------------------------------------- */
/* cx88-cards.c */
-extern struct cx88_board cx88_boards[];
-extern const unsigned int cx88_bcount;
-
-extern struct cx88_subid cx88_subids[];
-extern const unsigned int cx88_idcount;
-
-extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
-extern void cx88_card_setup(struct cx88_core *core);
-extern void cx88_card_setup_pre_i2c(struct cx88_core *core);
+extern int cx88_get_resources(const struct cx88_core *core,
+ struct pci_dev *pci);
+extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
/* ----------------------------------------------------------- */
/* cx88-tvaudio.c */
@@ -629,6 +614,8 @@ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
int cx88_ir_fini(struct cx88_core *core);
void cx88_ir_irq(struct cx88_core *core);
+void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir);
+void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 0fcc935828f8..255dae303708 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -92,7 +92,6 @@ static int dpc_probe(struct saa7146_dev* dev)
{
struct dpc* dpc = NULL;
struct i2c_client *client;
- struct list_head *item;
dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
if( NULL == dpc ) {
@@ -116,11 +115,9 @@ static int dpc_probe(struct saa7146_dev* dev)
}
/* loop through all i2c-devices on the bus and look who is there */
- list_for_each(item,&dpc->i2c_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
+ list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
if( I2C_SAA7111A == client->addr )
dpc->saa7111a = client;
- }
/* check if all devices are present */
if( 0 == dpc->saa7111a ) {
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 255a47dfb84f..d3282ec62c5b 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 55d45b0032cf..e3894b68c4ee 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 2c7b158ce7e1..b8d5327c438d 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -252,10 +252,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
int minor = iminor(inode);
int errCode = 0;
struct em28xx *h,*dev = NULL;
- struct list_head *list;
- list_for_each(list,&em28xx_devlist) {
- h = list_entry(list, struct em28xx, devlist);
+ list_for_each_entry(h, &em28xx_devlist, devlist) {
if (h->vdev->minor == minor) {
dev = h;
dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -268,8 +266,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
if (NULL == dev)
return -ENODEV;
- filp->private_data=dev;
-
em28xx_videodbg("open minor=%d type=%s users=%d\n",
minor,v4l2_type_names[dev->type],dev->users);
@@ -1772,6 +1768,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (dev->alt_max_pkt_size == NULL) {
em28xx_errdev("out of memory!\n");
em28xx_devused&=~(1<<nr);
+ kfree(dev);
return -ENOMEM;
}
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
index 664676f44068..dcc1a0335440 100644
--- a/drivers/media/video/et61x251/Kconfig
+++ b/drivers/media/video/et61x251/Kconfig
@@ -1,6 +1,6 @@
config USB_ET61X251
tristate "USB ET61X[12]51 PC Camera Controller support"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y here if you want support for cameras based on Etoms ET61X151
or ET61X251 PC Camera Controllers.
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 262f98e12409..02c741d8f85a 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/kref.h>
#include "et61x251_sensor.h"
@@ -134,7 +135,7 @@ struct et61x251_module_param {
};
static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
+static DECLARE_RWSEM(et61x251_dev_lock);
struct et61x251_device {
struct video_device* v4ldev;
@@ -158,12 +159,14 @@ struct et61x251_device {
struct et61x251_sysfs_attr sysfs;
struct et61x251_module_param module_param;
+ struct kref kref;
enum et61x251_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
@@ -177,7 +180,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
void
et61x251_attach_sensor(struct et61x251_device* cam,
- struct et61x251_sensor* sensor)
+ const struct et61x251_sensor* sensor)
{
memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
}
@@ -195,8 +198,8 @@ do { \
else if ((level) == 2) \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+ __FILE__, __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -205,8 +208,8 @@ do { \
if ((level) == 1 || (level) == 2) \
pr_info("et61x251: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -222,8 +225,8 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index a6525513cd1e..d5fef4c01c87 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -45,11 +44,11 @@
#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \
"PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
+#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.04"
-#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4)
+#define ET61X251_MODULE_VERSION "1:1.09"
+#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9)
/*****************************************************************************/
@@ -245,7 +244,8 @@ int et61x251_read_reg(struct et61x251_device* cam, u16 index)
static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+et61x251_i2c_wait(struct et61x251_device* cam,
+ const struct et61x251_sensor* sensor)
{
int i, r;
@@ -270,7 +270,7 @@ et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
int
et61x251_i2c_try_read(struct et61x251_device* cam,
- struct et61x251_sensor* sensor, u8 address)
+ const struct et61x251_sensor* sensor, u8 address)
{
struct usb_device* udev = cam->usbdev;
u8* data = cam->control_buffer;
@@ -303,7 +303,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,
int
et61x251_i2c_try_write(struct et61x251_device* cam,
- struct et61x251_sensor* sensor, u8 address, u8 value)
+ const struct et61x251_sensor* sensor, u8 address,
+ u8 value)
{
struct usb_device* udev = cam->usbdev;
u8* data = cam->control_buffer;
@@ -615,7 +616,7 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
return 0;
free_urbs:
- for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
+ for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -682,7 +683,7 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
if (len < 4) {
strncpy(str, buff, len);
- str[len+1] = '\0';
+ str[len] = '\0';
} else {
strncpy(str, buff, 4);
str[4] = '\0';
@@ -705,7 +706,8 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
NOTE 2: buffers are PAGE_SIZE long
*/
-static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -728,7 +730,8 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_reg(struct device* cd,
+ struct device_attribute *attr, const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 index;
@@ -760,7 +763,8 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -791,7 +795,8 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 value;
@@ -829,7 +834,8 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_i2c_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -854,7 +860,8 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 index;
@@ -886,7 +893,8 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_i2c_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -922,7 +930,8 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 value;
@@ -965,42 +974,40 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
}
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
- et61x251_show_reg, et61x251_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
- et61x251_show_val, et61x251_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
- et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
- et61x251_show_i2c_val, et61x251_store_i2c_val);
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+ et61x251_show_reg, et61x251_store_reg);
+static DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+ et61x251_show_val, et61x251_store_val);
+static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+ et61x251_show_i2c_reg, et61x251_store_i2c_reg);
+static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+ et61x251_show_i2c_val, et61x251_store_i2c_val);
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
- struct video_device *v4ldev = cam->v4ldev;
+ struct device *classdev = &(cam->v4ldev->class_dev);
int err = 0;
- if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_reg)))
goto err_out;
- if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ if ((err = device_create_file(classdev, &dev_attr_val)))
goto err_reg;
if (cam->sensor.sysfs_ops) {
- if ((err = video_device_create_file(v4ldev,
- &class_device_attr_i2c_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
goto err_val;
- if ((err = video_device_create_file(v4ldev,
- &class_device_attr_i2c_val)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
goto err_i2c_reg;
}
err_i2c_reg:
if (cam->sensor.sysfs_ops)
- video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+ device_remove_file(classdev, &dev_attr_i2c_reg);
err_val:
- video_device_remove_file(v4ldev, &class_device_attr_val);
+ device_remove_file(classdev, &dev_attr_val);
err_reg:
- video_device_remove_file(v4ldev, &class_device_attr_reg);
+ device_remove_file(classdev, &dev_attr_reg);
err_out:
return err;
}
@@ -1103,7 +1110,8 @@ static int et61x251_init(struct et61x251_device* cam)
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1185,80 @@ static int et61x251_init(struct et61x251_device* cam)
return 0;
}
+/*****************************************************************************/
-static void et61x251_release_resources(struct et61x251_device* cam)
+static void et61x251_release_resources(struct kref *kref)
{
+ struct et61x251_device *cam;
+
mutex_lock(&et61x251_sysfs_lock);
+ cam = container_of(kref, struct et61x251_device, kref);
+
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
+ kfree(cam->control_buffer);
+ kfree(cam);
mutex_unlock(&et61x251_sysfs_lock);
-
- kfree(cam->control_buffer);
}
-/*****************************************************************************/
static int et61x251_open(struct inode* inode, struct file* filp)
{
struct et61x251_device* cam;
int err = 0;
- /*
- This is the only safe way to prevent race conditions with
- disconnect
- */
- if (!down_read_trylock(&et61x251_disconnect))
+ if (!down_read_trylock(&et61x251_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&et61x251_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&et61x251_dev_lock);
return -ERESTARTSYS;
}
+ kref_get(&cam->kref);
+
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, et61x251_release_resources);
+ up_read(&et61x251_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is already in use",
+ cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&et61x251_dev_lock);
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&et61x251_disconnect);
- return err;
- }
+ down_read(&et61x251_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&et61x251_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = et61x251_init(cam);
if (err) {
@@ -1259,36 +1283,32 @@ static int et61x251_open(struct inode* inode, struct file* filp)
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&et61x251_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, et61x251_release_resources);
+ up_read(&et61x251_dev_lock);
return err;
}
static int et61x251_release(struct inode* inode, struct file* filp)
{
- struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+ struct et61x251_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&et61x251_dev_lock);
- et61x251_stop_transfer(cam);
+ cam = video_get_drvdata(video_devdata(filp));
+ et61x251_stop_transfer(cam);
et61x251_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- et61x251_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, et61x251_release_resources);
+
+ up_write(&et61x251_dev_lock);
return 0;
}
@@ -1324,7 +1344,7 @@ et61x251_read(struct file* filp, char __user * buf,
DBG(3, "Close and open the device again to choose the read "
"method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -1504,7 +1524,12 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -1535,7 +1560,6 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
vma->vm_ops = &et61x251_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
et61x251_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1788,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
/* Preserve R,G or B origin */
@@ -1921,6 +1945,8 @@ et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+ 0 : V4L2_COLORSPACE_SRGB;
pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2022,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
pix->pixelformat = pfmt->pixelformat;
pix->priv = pfmt->priv; /* bpp */
+ pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+ 0 : V4L2_COLORSPACE_SRGB;
pix->colorspace = pfmt->colorspace;
pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2041,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2129,14 +2157,14 @@ et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2284,9 +2312,6 @@ et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -2535,8 +2560,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
DBG(2, "ET61X[12]51 PC Camera Controller detected "
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
@@ -2568,7 +2591,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -2578,7 +2601,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -2599,11 +2622,15 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
"device controlling. Error #%d", err);
#else
DBG(2, "Optional device control through 'sysfs' interface disabled");
+ DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+ "configuration option to enable it.");
#endif
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -2620,40 +2647,31 @@ fail:
static void et61x251_usb_disconnect(struct usb_interface* intf)
{
- struct et61x251_device* cam = usb_get_intfdata(intf);
-
- if (!cam)
- return;
+ struct et61x251_device* cam;
- down_write(&et61x251_disconnect);
+ down_write(&et61x251_dev_lock);
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
et61x251_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- et61x251_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, et61x251_release_resources);
- up_write(&et61x251_disconnect);
+ up_write(&et61x251_dev_lock);
}
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index 5fadb5de68bf..e14586330623 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -22,7 +22,7 @@
#define _ET61X251_SENSOR_H_
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
@@ -47,7 +47,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
extern void
et61x251_attach_sensor(struct et61x251_device* cam,
- struct et61x251_sensor* sensor);
+ const struct et61x251_sensor* sensor);
/*****************************************************************************/
@@ -56,10 +56,10 @@ extern int et61x251_read_reg(struct et61x251_device*, u16 index);
extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
extern int et61x251_i2c_try_write(struct et61x251_device*,
- struct et61x251_sensor*, u8 address,
+ const struct et61x251_sensor*, u8 address,
u8 value);
extern int et61x251_i2c_try_read(struct et61x251_device*,
- struct et61x251_sensor*, u8 address);
+ const struct et61x251_sensor*, u8 address);
extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
u8 data2, u8 data3, u8 data4, u8 data5,
u8 data6, u8 data7, u8 data8, u8 address);
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
index b06643409842..04b7fbb310a8 100644
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
@@ -69,7 +69,7 @@ static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
}
-static struct et61x251_sensor tas5130d1b = {
+static const struct et61x251_sensor tas5130d1b = {
.name = "TAS5130D1B",
.interface = ET61X251_I2C_3WIRES,
.rsta = ET61X251_I2C_RSTA_STOP,
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index ed92b6f7187a..d98dd0d1e373 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -10,6 +10,8 @@
* Ulrich Mueller <ulrich.mueller42@web.de>
* modified for em2820 based USB TV tuners by
* Markus Rechberger <mrechberger@gmail.com>
+ * modified for DViCO Fusion HDTV 5 RT GOLD by
+ * Chaogui Zhang <czhang1974@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +30,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -37,6 +38,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/workqueue.h>
#include <asm/semaphore.h>
@@ -60,21 +62,22 @@ MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults
/* ----------------------------------------------------------------------- */
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int size, int offset)
{
- unsigned char buf[3];
+ unsigned char buf[6];
int start, range, toggle, dev, code;
/* poll IR chip */
- if (3 != i2c_master_recv(&ir->c,buf,3))
+ if (size != i2c_master_recv(&ir->c,buf,size))
return -EIO;
/* split rc5 data block ... */
- start = (buf[0] >> 7) & 1;
- range = (buf[0] >> 6) & 1;
- toggle = (buf[0] >> 5) & 1;
- dev = buf[0] & 0x1f;
- code = (buf[1] >> 2) & 0x3f;
+ start = (buf[offset] >> 7) & 1;
+ range = (buf[offset] >> 6) & 1;
+ toggle = (buf[offset] >> 5) & 1;
+ dev = buf[offset] & 0x1f;
+ code = (buf[offset+1] >> 2) & 0x3f;
/* rc5 has two start bits
* the first bit must be one
@@ -96,6 +99,16 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
+static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -130,6 +143,30 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
+static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char buf[4];
+
+ /* poll IR chip */
+ if (4 != i2c_master_recv(&ir->c,buf,4)) {
+ dprintk(1,"read error\n");
+ return -EIO;
+ }
+
+ if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
+ dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+ buf[0], buf[1], buf[2], buf[3]);
+
+ /* no key pressed or signal from other ir remote */
+ if(buf[0] != 0x1 || buf[1] != 0xfe)
+ return 0;
+
+ *ir_key = buf[2];
+ *ir_raw = (buf[2] << 8) | buf[3];
+
+ return 1;
+}
+
static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -270,8 +307,9 @@ static void ir_timer(unsigned long data)
static void ir_work(struct work_struct *work)
{
struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+
ir_key_poll(ir);
- mod_timer(&ir->timer, jiffies+HZ/10);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
}
/* ----------------------------------------------------------------------- */
@@ -351,12 +389,30 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir_type = IR_TYPE_OTHER;
ir_codes = ir_codes_empty;
break;
+ case 0x6b:
+ name = "FusionHDTV";
+ ir->get_key = get_key_fusionhdtv;
+ ir_type = IR_TYPE_RC5;
+ ir_codes = ir_codes_fusionhdtv_mce;
+ break;
case 0x7a:
case 0x47:
case 0x71:
- /* Handled by saa7134-input */
- name = "SAA713x remote";
- ir_type = IR_TYPE_OTHER;
+ if (adap->id == I2C_HW_B_CX2388x) {
+ /* Handled by cx88-input */
+ name = "CX2388x remote";
+ ir_type = IR_TYPE_RC5;
+ ir->get_key = get_key_haup_xvr;
+ if (hauppauge == 1) {
+ ir_codes = ir_codes_hauppauge_new;
+ } else {
+ ir_codes = ir_codes_rc5_tv;
+ }
+ } else {
+ /* Handled by saa7134-input */
+ name = "SAA713x remote";
+ ir_type = IR_TYPE_OTHER;
+ }
break;
default:
/* shouldn't happen */
@@ -450,6 +506,8 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+ static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
+ static const int probe_cx23885[] = { 0x6b, -1 };
const int *probe = NULL;
struct i2c_client c;
unsigned char buf;
@@ -468,6 +526,11 @@ static int ir_probe(struct i2c_adapter *adap)
case I2C_HW_B_EM28XX:
probe = probe_em28XX;
break;
+ case I2C_HW_B_CX2388x:
+ probe = probe_cx88;
+ case I2C_HW_B_CX23885:
+ probe = probe_cx23885;
+ break;
}
if (NULL == probe)
return 0;
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 1aaeaa02f158..854cc9c30ca9 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+ select I2C_ALGOBIT
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -13,14 +14,31 @@ config VIDEO_IVTV
select VIDEO_CS53L32A
select VIDEO_WM8775
select VIDEO_WM8739
+ select VIDEO_VP27SMPX
select VIDEO_UPD64031A
select VIDEO_UPD64083
---help---
- This is a video4linux driver for Conexant cx23416 or cx23416 based
+ This is a video4linux driver for Conexant cx23416 or cx23415 based
PCI personal video recorder devices.
This is used in devices such as the Hauppauge PVR-150/250/350/500
- cards.
+ cards. There is a driver homepage at <http://www.ivtvdriver.org>.
To compile this driver as a module, choose M here: the
module will be called ivtv.
+
+config VIDEO_FB_IVTV
+ tristate "Conexant cx23415 framebuffer support"
+ depends on VIDEO_IVTV && FB && EXPERIMENTAL
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ This is a framebuffer driver for the Conexant cx23415 MPEG
+ encoder/decoder.
+
+ This is used in the Hauppauge PVR-350 card. There is a driver
+ homepage at <http://www.ivtvdriver.org>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ivtvfb.
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index 7e95148fbf4f..e8eefd96d897 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -1,7 +1,8 @@
-ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \
+ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
- ivtv-vbi.o ivtv-video.o ivtv-yuv.o
+ ivtv-vbi.o ivtv-yuv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
+obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c
deleted file mode 100644
index d702b8b539a1..000000000000
--- a/drivers/media/video/ivtv/ivtv-audio.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- Audio-related ivtv functions.
- Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
- Copyright (C) 2005-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 "ivtv-driver.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-i2c.h"
-#include "ivtv-gpio.h"
-#include "ivtv-cards.h"
-#include "ivtv-audio.h"
-#include <media/msp3400.h>
-#include <linux/videodev.h>
-
-/* Selects the audio input and output according to the current
- settings. */
-int ivtv_audio_set_io(struct ivtv *itv)
-{
- struct v4l2_routing route;
- u32 audio_input;
- int mux_input;
-
- /* Determine which input to use */
- if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
- audio_input = itv->card->radio_input.audio_input;
- mux_input = itv->card->radio_input.muxer_input;
- } else {
- audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
- mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
- }
-
- /* handle muxer chips */
- route.input = mux_input;
- route.output = 0;
- ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-
- route.input = audio_input;
- if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
- route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
- }
- return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-}
-
-void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route)
-{
- ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
-}
-
-void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, 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;
- ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
-}
-
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 8eab02083887..b6a8be622d3c 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -616,7 +616,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
.hw_audio = IVTV_HW_GPIO,
.hw_audio_ctrl = IVTV_HW_WM8739,
- .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO |
+ .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX |
IVTV_HW_TUNER | IVTV_HW_WM8739 |
IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
.video_inputs = {
@@ -654,7 +654,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
.hw_audio = IVTV_HW_GPIO,
.hw_audio_ctrl = IVTV_HW_WM8739,
.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
- IVTV_HW_TVAUDIO | IVTV_HW_WM8739,
+ IVTV_HW_VP27SMPX | IVTV_HW_WM8739,
.video_inputs = {
{ IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 },
{ IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 },
@@ -823,9 +823,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
/* ------------------------------------------------------------------------- */
-#ifdef HAVE_XC3028
-
-/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */
+/* Yuan PG600-2/GotView PCI DVD Lite cards */
static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 },
@@ -835,29 +833,87 @@ 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, Club3D ZAP-TV1x01",
+ .name = "Yuan PG600-2, GotView PCI DVD Lite",
.v4l2_capabilities = 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,
.video_inputs = {
- { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
- { IVTV_CARD_INPUT_SVIDEO1, 1,
+ { IVTV_CARD_INPUT_SVIDEO1, 0,
CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
},
.audio_inputs = {
- { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
- .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
},
- .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
.pci_list = ivtv_pci_pg600v2,
};
-#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* Club3D ZAP-TV1x01 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_club3d[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_club3d = {
+ .type = IVTV_CARD_CLUB3D,
+ .name = "Club3D ZAP-TV1x01",
+ .v4l2_capabilities = 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,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_SVIDEO1, 0,
+ CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
+ },
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+ },
+ .pci_list = ivtv_pci_club3d,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerTV MCE 116 Plus (M116) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avertv_mce116 = {
+ .type = IVTV_CARD_AVERTV_MCE116,
+ .name = "AVerTV MCE 116 Plus",
+ .v4l2_capabilities = 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 },
+ },
+ .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+ },
+ .pci_list = ivtv_pci_avertv_mce116,
+};
static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_pvr250,
@@ -878,9 +934,9 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_gotview_pci_dvd2,
&ivtv_card_yuan_mpc622,
&ivtv_card_dctmvtvp1,
-#ifdef HAVE_XC3028
&ivtv_card_pg600v2,
-#endif
+ &ivtv_card_club3d,
+ &ivtv_card_avertv_mce116,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 91e9e90c14a5..ff46e5ae8653 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -18,6 +18,68 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_CARDS_H
+#define IVTV_CARDS_H
+
+/* Supported cards */
+#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */
+#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */
+#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two
+ PVR150s on one PCI board) */
+#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */
+#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
+#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
+ cx23415 based, but does not have tv-out */
+#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
+#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */
+#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */
+#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */
+#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */
+#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */
+#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */
+#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */
+#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */
+#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */
+#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */
+#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */
+#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */
+#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */
+#define IVTV_CARD_LAST 20
+
+/* Variants of existing cards but with the same PCI IDs. The driver
+ detects these based on other device information.
+ These cards must always come last.
+ New cards must be inserted above, and the indices of the cards below
+ must be adjusted accordingly. */
+
+/* PVR-350 V1 (uses saa7114) */
+#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1)
+/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2)
+#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_ICOMP 0x4444
+#define PCI_DEVICE_ID_IVTV15 0x0803
+#define PCI_DEVICE_ID_IVTV16 0x0016
+
+/* subsystem vendor ID */
+#define IVTV_PCI_ID_HAUPPAUGE 0x0070
+#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270
+#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070
+#define IVTV_PCI_ID_ADAPTEC 0x9005
+#define IVTV_PCI_ID_AVERMEDIA 0x1461
+#define IVTV_PCI_ID_YUAN1 0x12ab
+#define IVTV_PCI_ID_YUAN2 0xff01
+#define IVTV_PCI_ID_YUAN3 0xffab
+#define IVTV_PCI_ID_YUAN4 0xfbab
+#define IVTV_PCI_ID_DIAMONDMM 0xff92
+#define IVTV_PCI_ID_IODATA 0x10fc
+#define IVTV_PCI_ID_MELCO 0x1154
+#define IVTV_PCI_ID_GOTVIEW1 0xffac
+#define IVTV_PCI_ID_GOTVIEW2 0xffad
+
/* hardware flags */
#define IVTV_HW_CX25840 (1 << 0)
#define IVTV_HW_SAA7115 (1 << 1)
@@ -33,7 +95,8 @@
#define IVTV_HW_UPD6408X (1 << 11)
#define IVTV_HW_SAA717X (1 << 12)
#define IVTV_HW_WM8739 (1 << 13)
-#define IVTV_HW_GPIO (1 << 14)
+#define IVTV_HW_VP27SMPX (1 << 14)
+#define IVTV_HW_GPIO (1 << 15)
#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
@@ -205,3 +268,5 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output);
int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input);
int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output);
const struct ivtv_card *ivtv_get_card(u16 index);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index 7a876c3e5b19..8c02fa661591 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -21,7 +21,7 @@
#include "ivtv-driver.h"
#include "ivtv-cards.h"
#include "ivtv-ioctl.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
#include "ivtv-i2c.h"
#include "ivtv-mailbox.h"
#include "ivtv-controls.h"
@@ -231,8 +231,10 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
}
IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ static u32 freqs[3] = { 44100, 48000, 32000 };
struct cx2341x_mpeg_params p = itv->params;
- int err = cx2341x_ext_ctrls(&p, arg, cmd);
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd);
+ unsigned idx;
if (err)
return err;
@@ -254,7 +256,11 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
}
itv->params = p;
itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
- ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03);
+ idx = p.audio_properties & 0x03;
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (idx < sizeof(freqs))
+ ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
return err;
}
return -EINVAL;
@@ -282,7 +288,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
}
IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+ return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd);
return -EINVAL;
}
@@ -292,7 +298,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+ return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd);
return -EINVAL;
}
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index 5a11149725ad..bb8a6a5ed2bc 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -18,4 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_CONTROLS_H
+#define IVTV_CONTROLS_H
+
int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index efc66355339a..511a66252413 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -52,12 +52,12 @@
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include "ivtv-vbi.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
#include "ivtv-gpio.h"
#include "ivtv-yuv.h"
-#include <linux/vermagic.h>
#include <media/tveeprom.h>
+#include <media/saa7115.h>
#include <media/v4l2-chip-ident.h>
/* var to keep track of the number of array elements in use */
@@ -87,17 +87,16 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
-const u32 yuv_offset[4] = {
- IVTV_YUV_BUFFER_OFFSET,
- IVTV_YUV_BUFFER_OFFSET_1,
- IVTV_YUV_BUFFER_OFFSET_2,
- IVTV_YUV_BUFFER_OFFSET_3
-};
-
/* Parameter declarations */
static int cardtype[IVTV_MAX_CARDS];
-static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
-static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+static int tuner[IVTV_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[IVTV_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;
@@ -107,6 +106,18 @@ static char secam[] = "--";
static char ntsc[] = "-";
/* Buffers */
+
+/* DMA Buffers, Default size in MB allocated */
+#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
+#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
+#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
+/* Exception: size in kB for this stream (MB is overkill) */
+#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320
+#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
+#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
+/* Exception: size in kB for this stream (MB is way overkill) */
+#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64
+
static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS;
static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS;
static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS;
@@ -171,17 +182,27 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n"
"\t\t\t17 = Yuan MPC622\n"
"\t\t\t18 = Digital Cowboy DCT-MTVP1\n"
-#ifdef HAVE_XC3028
- "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n"
-#endif
+ "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
+ "\t\t\t20 = Club3D ZAP-TV1x01\n"
+ "\t\t\t21 = AverTV MCE 116 Plus\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: errors only\n"
- "\t\t\t(debug = 511 gives full debugging)");
+ "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: ioctl\n"
+ "\t\t\t 16/0x0010: file\n"
+ "\t\t\t 32/0x0020: dma\n"
+ "\t\t\t 64/0x0040: irq\n"
+ "\t\t\t 128/0x0080: decoder\n"
+ "\t\t\t 256/0x0100: yuv\n"
+ "\t\t\t 512/0x0200: i2c\n"
+ "\t\t\t1024/0x0400: high volume\n");
MODULE_PARM_DESC(ivtv_pci_latency,
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
"\t\t\tDefault: Yes");
@@ -202,7 +223,7 @@ MODULE_PARM_DESC(enc_vbi_buffers,
"Encoder VBI Buffers (in MB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS));
MODULE_PARM_DESC(enc_pcm_buffers,
- "Encoder PCM buffers (in MB)\n"
+ "Encoder PCM buffers (in kB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS));
MODULE_PARM_DESC(dec_mpg_buffers,
"Decoder MPG buffers (in MB)\n"
@@ -211,7 +232,7 @@ MODULE_PARM_DESC(dec_yuv_buffers,
"Decoder YUV buffers (in MB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS));
MODULE_PARM_DESC(dec_vbi_buffers,
- "Decoder VBI buffers (in MB)\n"
+ "Decoder VBI buffers (in kB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS));
MODULE_PARM_DESC(newi2c,
"Use new I2C implementation\n"
@@ -276,9 +297,10 @@ int ivtv_waitq(wait_queue_head_t *waitq)
}
/* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
{
int ret;
+ int timeout = msecs_to_jiffies(msecs);
do {
set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -339,6 +361,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
/* In a few cases the PCI subsystem IDs do not correctly
identify the card. A better method is to check the
model number from the eeprom instead. */
+ case 30012 ... 30039: /* Low profile PVR250 */
case 32000 ... 32999:
case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */
case 48400 ... 48599:
@@ -426,7 +449,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
if (itv->options.newi2c) {
- IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+ IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
exit_ivtv_i2c(itv);
init_ivtv_i2c(itv);
}
@@ -539,13 +562,13 @@ static void ivtv_process_options(struct ivtv *itv)
const char *chipname;
int i, j;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
- itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers;
- itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers;
- itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
+ itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
+ itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
itv->options.cardtype = cardtype[itv->num];
itv->options.tuner = tuner[itv->num];
itv->options.radio = radio[itv->num];
@@ -622,6 +645,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
+ mutex_init(&itv->serialize_lock);
mutex_init(&itv->i2c_bus_lock);
mutex_init(&itv->udma.lock);
@@ -643,7 +667,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
cx2341x_fill_defaults(&itv->params);
itv->params.port = CX2341X_PORT_MEMORY;
itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
- init_waitqueue_head(&itv->cap_w);
+ init_waitqueue_head(&itv->eos_waitq);
init_waitqueue_head(&itv->event_waitq);
init_waitqueue_head(&itv->vsync_waitq);
init_waitqueue_head(&itv->dma_waitq);
@@ -689,14 +713,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
break;
itv->nof_audio_inputs = i;
- /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */
- if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
- itv->digitizer = 0xF1;
- else if (itv->card->hw_all & IVTV_HW_SAA7114)
- itv->digitizer = 0xEF;
- else /* cx25840 */
- itv->digitizer = 0x140;
-
if (itv->card->hw_all & IVTV_HW_CX25840) {
itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */
} else {
@@ -725,6 +741,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
u16 cmd;
+ u8 card_rev;
unsigned char pci_latency;
IVTV_DEBUG_INFO("Enabling pci device\n");
@@ -771,7 +788,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
}
IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev);
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && ivtv_pci_latency) {
@@ -788,7 +805,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
"irq: %d, latency: %d, memory: 0x%lx\n",
- itv->dev->device, itv->card_rev, dev->bus->number,
+ itv->dev->device, card_rev, dev->bus->number,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
@@ -806,18 +823,19 @@ static void ivtv_request_module(struct ivtv *itv, const char *name)
static void ivtv_load_and_init_modules(struct ivtv *itv)
{
- struct v4l2_control ctrl;
u32 hw = itv->card->hw_all;
int i;
/* load modules */
#ifndef CONFIG_VIDEO_TUNER
if (hw & IVTV_HW_TUNER) {
- ivtv_request_module(itv, "tuner");
-#ifdef HAVE_XC3028
- if (itv->options.tuner == TUNER_XCEIVE_XC3028)
- ivtv_request_module(itv, "xc3028-tuner");
-#endif
+ if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
+ IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
+ itv->tunerid = 1;
+ }
+ else {
+ ivtv_request_module(itv, "tuner");
+ }
}
#endif
#ifndef CONFIG_VIDEO_CX25840
@@ -846,6 +864,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
if (hw & IVTV_HW_MSP34XX)
ivtv_request_module(itv, "msp3400");
#endif
+#ifndef CONFIG_VIDEO_VP27SMPX
+ if (hw & IVTV_HW_VP27SMPX)
+ ivtv_request_module(itv, "vp27smpx");
+#endif
if (hw & IVTV_HW_TVAUDIO)
ivtv_request_module(itv, "tvaudio");
#ifndef CONFIG_VIDEO_WM8775
@@ -886,13 +908,17 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
else if ((hw & IVTV_HW_UPD64031A) == 0)
itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR);
}
+ else if (itv->card->type == IVTV_CARD_GV_MVPRX ||
+ itv->card->type == IVTV_CARD_GV_MVPRX2E) {
+ struct v4l2_crystal_freq crystal_freq;
- if (hw & IVTV_HW_CX25840) {
- /* CX25840_CID_ENABLE_PVR150_WORKAROUND */
- ctrl.id = V4L2_CID_PRIVATE_BASE;
- ctrl.value = itv->pvr150_workaround;
- itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+ /* The crystal frequency of GVMVPRX is 24.576MHz */
+ crystal_freq.freq = SAA7115_FREQ_24_576_MHZ;
+ crystal_freq.flags = SAA7115_FREQ_FL_UCGC;
+ itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+ }
+ if (hw & IVTV_HW_CX25840) {
itv->vbi.raw_decoder_line_size = 1444;
itv->vbi.raw_decoder_sav_odd_field = 0x20;
itv->vbi.raw_decoder_sav_even_field = 0x60;
@@ -938,18 +964,15 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
int retval = 0;
- int video_input;
int yuv_buf_size;
int vbi_buf_size;
- int fw_retry_count = 3;
struct ivtv *itv;
- struct v4l2_frequency vf;
spin_lock(&ivtv_cards_lock);
/* Make sure we've got a place for this card */
if (ivtv_cards_active == IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: Maximum number of cards detected (%d).\n",
+ printk(KERN_ERR "ivtv: Maximum number of cards detected (%d)\n",
ivtv_cards_active);
spin_unlock(&ivtv_cards_lock);
return -ENOMEM;
@@ -964,9 +987,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
itv->dev = dev;
itv->num = ivtv_cards_active++;
snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
- if (itv->num) {
- printk(KERN_INFO "ivtv: ====================== NEXT CARD ======================\n");
- }
+ IVTV_INFO("Initializing card #%d\n", itv->num);
spin_unlock(&ivtv_cards_lock);
@@ -982,6 +1003,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
+ mutex_lock(&itv->serialize_lock);
+
/* PCI Device Setup */
if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
if (retval == -EIO)
@@ -1032,22 +1055,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
goto free_io;
}
- while (--fw_retry_count > 0) {
- /* load firmware */
- if (ivtv_firmware_init(itv) == 0)
- break;
- if (fw_retry_count > 1)
- IVTV_WARN("Retry loading firmware\n");
- }
- if (fw_retry_count == 0) {
- IVTV_ERR("Error initializing firmware\n");
- goto free_i2c;
- }
-
- /* Try and get firmware versions */
- IVTV_DEBUG_INFO("Getting firmware version..\n");
- ivtv_firmware_versions(itv);
-
/* Check yuv output filter table */
if (itv->has_cx23415) ivtv_yuv_filter_check(itv);
@@ -1135,43 +1142,22 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
if (itv->options.radio > 0)
itv->v4l2_cap |= V4L2_CAP_RADIO;
- if (itv->options.tuner > -1) {
+ if (itv->options.tuner > -1 && itv->tunerid == 0) {
struct tuner_setup setup;
setup.addr = ADDR_UNSET;
setup.type = itv->options.tuner;
setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
-#ifdef HAVE_XC3028
- setup.initmode = V4L2_TUNER_ANALOG_TV;
- if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
- setup.gpio_write = ivtv_reset_tuner_gpio;
- setup.gpio_priv = itv;
- }
-#endif
ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
}
- vf.tuner = 0;
- vf.type = V4L2_TUNER_ANALOG_TV;
- vf.frequency = 6400; /* the tuner 'baseline' frequency */
- if (itv->std & V4L2_STD_NTSC_M) {
- /* Why on earth? */
- vf.frequency = 1076; /* ch. 4 67250*16/1000 */
- }
-
/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
are not. */
itv->tuner_std = itv->std;
- video_input = itv->active_input;
- itv->active_input++; /* Force update of input */
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
-
- /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
- in one place. */
- itv->std++; /* Force full standard initialization */
- itv->std_out = itv->std;
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+ }
retval = ivtv_streams_setup(itv);
if (retval) {
@@ -1179,11 +1165,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
goto free_i2c;
}
- if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
- ivtv_init_mpeg_decoder(itv);
- }
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
-
IVTV_DEBUG_IRQ("Masking interrupts\n");
/* clear interrupt mask, effectively disabling interrupts */
ivtv_set_irq_mask(itv, 0xffffffff);
@@ -1195,26 +1176,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_ERR("Failed to register irq %d\n", retval);
goto free_streams;
}
-
- /* On a cx23416 this seems to be able to enable DMA to the chip? */
- if (!itv->has_cx23415)
- write_reg_sync(0x03, IVTV_REG_DMACONTROL);
-
- /* Default interrupts enabled. For the PVR350 this includes the
- decoder VSYNC interrupt, which is always on. It is not only used
- during decoding but also by the OSD.
- Some old PVR250 cards had a cx23415, so testing for that is too
- general. Instead test if the card has video output capability. */
- if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
- ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
- else
- ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
-
- if (itv->has_cx23415)
- ivtv_set_osd_alpha(itv);
-
- IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
-
+ mutex_unlock(&itv->serialize_lock);
+ IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
return 0;
free_irq:
@@ -1232,68 +1195,146 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
free_workqueue:
destroy_workqueue(itv->irq_work_queues);
+ mutex_unlock(&itv->serialize_lock);
err:
if (retval == 0)
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
+ spin_lock(&ivtv_cards_lock);
kfree(ivtv_cards[ivtv_cards_active]);
ivtv_cards[ivtv_cards_active] = NULL;
+ spin_unlock(&ivtv_cards_lock);
return retval;
}
-static void ivtv_remove(struct pci_dev *pci_dev)
+int ivtv_init_on_first_open(struct ivtv *itv)
{
- struct ivtv *itv = pci_get_drvdata(pci_dev);
+ struct v4l2_frequency vf;
+ int fw_retry_count = 3;
+ int video_input;
+
+ if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
+ return -ENXIO;
+
+ if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags))
+ return 0;
+
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (ivtv_firmware_init(itv) == 0)
+ break;
+ if (fw_retry_count > 1)
+ IVTV_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(IVTV_F_I_FAILED, &itv->i_flags);
+ return -ENXIO;
+ }
+
+ /* Try and get firmware versions */
+ IVTV_DEBUG_INFO("Getting firmware version..\n");
+ ivtv_firmware_versions(itv);
+
+ if (itv->card->hw_all & IVTV_HW_CX25840) {
+ struct v4l2_control ctrl;
+
+ /* CX25840_CID_ENABLE_PVR150_WORKAROUND */
+ ctrl.id = V4L2_CID_PRIVATE_BASE;
+ ctrl.value = itv->pvr150_workaround;
+ itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+ }
+
+ 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 (itv->std == V4L2_STD_NTSC_M_JP) {
+ vf.frequency = 1460; /* ch. 1 91250*16/1000 */
+ }
+ else if (itv->std & V4L2_STD_NTSC_M) {
+ vf.frequency = 1076; /* ch. 4 67250*16/1000 */
+ }
- IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+ video_input = itv->active_input;
+ itv->active_input++; /* Force update of input */
+ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
+
+ /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+ in one place. */
+ itv->std++; /* Force full standard initialization */
+ itv->std_out = itv->std;
+ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+
+ if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_init_mpeg_decoder(itv);
+ }
+ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
+
+ /* On a cx23416 this seems to be able to enable DMA to the chip? */
+ if (!itv->has_cx23415)
+ write_reg_sync(0x03, IVTV_REG_DMACONTROL);
- /* Stop all captures */
- IVTV_DEBUG_INFO(" Stopping all streams.\n");
- if (atomic_read(&itv->capturing) > 0)
- ivtv_stop_all_captures(itv);
+ /* Default interrupts enabled. For the PVR350 this includes the
+ decoder VSYNC interrupt, which is always on. It is not only used
+ during decoding but also by the OSD.
+ Some old PVR250 cards had a cx23415, so testing for that is too
+ general. Instead test if the card has video output capability. */
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
+ ivtv_set_osd_alpha(itv);
+ }
+ else
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+ return 0;
+}
- /* Stop all decoding */
- IVTV_DEBUG_INFO(" Stopping decoding.\n");
- if (atomic_read(&itv->decoding) > 0) {
- int type;
+static void ivtv_remove(struct pci_dev *pci_dev)
+{
+ struct ivtv *itv = pci_get_drvdata(pci_dev);
- if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
- type = IVTV_DEC_STREAM_TYPE_YUV;
- else
- type = IVTV_DEC_STREAM_TYPE_MPG;
- ivtv_stop_v4l2_decode_stream(&itv->streams[type],
- VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+ IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
+
+ if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
+ /* Stop all captures */
+ IVTV_DEBUG_INFO("Stopping all streams\n");
+ if (atomic_read(&itv->capturing) > 0)
+ ivtv_stop_all_captures(itv);
+
+ /* Stop all decoding */
+ IVTV_DEBUG_INFO("Stopping decoding\n");
+ if (atomic_read(&itv->decoding) > 0) {
+ int type;
+
+ if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+ type = IVTV_DEC_STREAM_TYPE_YUV;
+ else
+ type = IVTV_DEC_STREAM_TYPE_MPG;
+ ivtv_stop_v4l2_decode_stream(&itv->streams[type],
+ VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+ }
+ ivtv_halt_firmware(itv);
}
/* Interrupts */
- IVTV_DEBUG_INFO(" Disabling interrupts.\n");
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);
/* Stop all Work Queues */
- IVTV_DEBUG_INFO(" Stop Work Queues.\n");
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
- IVTV_DEBUG_INFO(" Stopping Firmware.\n");
- ivtv_halt_firmware(itv);
-
- IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
ivtv_streams_cleanup(itv);
- IVTV_DEBUG_INFO(" Freeing dma resources.\n");
ivtv_udma_free(itv);
exit_ivtv_i2c(itv);
- IVTV_DEBUG_INFO(" Releasing irq.\n");
free_irq(itv->dev->irq, (void *)itv);
+ ivtv_iounmap(itv);
- if (itv->dev) {
- ivtv_iounmap(itv);
- }
-
- IVTV_DEBUG_INFO(" Releasing mem.\n");
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)
@@ -1314,28 +1355,27 @@ static struct pci_driver ivtv_pci_driver = {
static int module_start(void)
{
- printk(KERN_INFO "ivtv: ==================== START INIT IVTV ====================\n");
- printk(KERN_INFO "ivtv: version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+ printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
memset(ivtv_cards, 0, sizeof(ivtv_cards));
/* Validate parameters */
if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: ivtv_first_minor must be between 0 and %d. Exiting...\n",
+ printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
IVTV_MAX_CARDS - 1);
return -1;
}
- if (ivtv_debug < 0 || ivtv_debug > 511) {
+ if (ivtv_debug < 0 || ivtv_debug > 2047) {
ivtv_debug = 0;
- printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n");
+ printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
}
if (pci_register_driver(&ivtv_pci_driver)) {
printk(KERN_ERR "ivtv: Error detecting PCI card\n");
return -ENODEV;
}
- printk(KERN_INFO "ivtv: ==================== END INIT IVTV ====================\n");
+ printk(KERN_INFO "ivtv: End initialization\n");
return 0;
}
@@ -1345,6 +1385,7 @@ static void module_cleanup(void)
pci_unregister_driver(&ivtv_pci_driver);
+ spin_lock(&ivtv_cards_lock);
for (i = 0; i < ivtv_cards_active; i++) {
if (ivtv_cards[i] == NULL)
continue;
@@ -1353,13 +1394,15 @@ static void module_cleanup(void)
}
kfree(ivtv_cards[i]);
}
+ spin_unlock(&ivtv_cards_lock);
}
-/* Note: These symbols are exported because they are used by the ivtv-fb
+/* Note: These symbols are exported because they are used by the ivtvfb
framebuffer module and an infrared module for the IR-blaster. */
EXPORT_SYMBOL(ivtv_set_irq_mask);
EXPORT_SYMBOL(ivtv_cards_active);
EXPORT_SYMBOL(ivtv_cards);
+EXPORT_SYMBOL(ivtv_cards_lock);
EXPORT_SYMBOL(ivtv_api);
EXPORT_SYMBOL(ivtv_vapi);
EXPORT_SYMBOL(ivtv_vapi_result);
@@ -1370,6 +1413,7 @@ EXPORT_SYMBOL(ivtv_udma_setup);
EXPORT_SYMBOL(ivtv_udma_unmap);
EXPORT_SYMBOL(ivtv_udma_alloc);
EXPORT_SYMBOL(ivtv_udma_prepare);
+EXPORT_SYMBOL(ivtv_init_on_first_open);
module_init(module_start);
module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index e6e56f175f3f..3bda1df63cb6 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -38,7 +38,6 @@
#include <linux/version.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
@@ -63,77 +62,20 @@
#include <media/tuner.h>
#include <media/cx2341x.h>
-/* #define HAVE_XC3028 1 */
+#include <linux/ivtv.h>
-#include <media/ivtv.h>
+/* Memory layout */
#define IVTV_ENCODER_OFFSET 0x00000000
-#define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */
-
+#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */
#define IVTV_DECODER_OFFSET 0x01000000
-#define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */
-
+#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */
#define IVTV_REG_OFFSET 0x02000000
#define IVTV_REG_SIZE 0x00010000
-/* Buffers on hardware offsets */
-#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */
-#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */
-
-/* Offset to filter table in firmware */
-#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
-#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
-
-extern const u32 yuv_offset[4];
-
-/* Maximum ivtv driver instances.
- Based on 6 PVR500s each with two PVR15s...
- TODO: make this dynamic. I believe it is only a global in order to support
- ivtv-fb. There must be a better way to do that. */
-#define IVTV_MAX_CARDS 12
-
-/* Supported cards */
-#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */
-#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */
-#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two
- PVR150s on one PCI board) */
-#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */
-#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
-#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
- cx23415 based, but does not have tv-out */
-#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
-#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */
-#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */
-#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */
-#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */
-#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
-#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */
-#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */
-#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */
-#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */
-#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */
-#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */
-#ifdef HAVE_XC3028
-#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */
-#define IVTV_CARD_LAST 18
-#else
-#define IVTV_CARD_LAST 17
-#endif
-
-/* Variants of existing cards but with the same PCI IDs. The driver
- detects these based on other device information.
- These cards must always come last.
- New cards must be inserted above, and the indices of the cards below
- must be adjusted accordingly. */
-
-/* PVR-350 V1 (uses saa7114) */
-#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1)
-/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
-#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2)
-#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+/* Maximum ivtv driver instances. Some people have a huge number of
+ capture cards, so set this to a high value. */
+#define IVTV_MAX_CARDS 32
#define IVTV_ENC_STREAM_TYPE_MPG 0
#define IVTV_ENC_STREAM_TYPE_YUV 1
@@ -146,70 +88,8 @@ extern const u32 yuv_offset[4];
#define IVTV_DEC_STREAM_TYPE_YUV 8
#define IVTV_MAX_STREAMS 9
-#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
-#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */
-#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */
-#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */
-
-#define IVTV_ENC_MEM_START 0x00000000
-#define IVTV_DEC_MEM_START 0x01000000
-
-/* system vendor and device IDs */
-#define PCI_VENDOR_ID_ICOMP 0x4444
-#define PCI_DEVICE_ID_IVTV15 0x0803
-#define PCI_DEVICE_ID_IVTV16 0x0016
-
-/* subsystem vendor ID */
-#define IVTV_PCI_ID_HAUPPAUGE 0x0070
-#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270
-#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070
-#define IVTV_PCI_ID_ADAPTEC 0x9005
-#define IVTV_PCI_ID_AVERMEDIA 0x1461
-#define IVTV_PCI_ID_YUAN1 0x12ab
-#define IVTV_PCI_ID_YUAN2 0xff01
-#define IVTV_PCI_ID_YUAN3 0xffab
-#define IVTV_PCI_ID_YUAN4 0xfbab
-#define IVTV_PCI_ID_DIAMONDMM 0xff92
-#define IVTV_PCI_ID_IODATA 0x10fc
-#define IVTV_PCI_ID_MELCO 0x1154
-#define IVTV_PCI_ID_GOTVIEW1 0xffac
-#define IVTV_PCI_ID_GOTVIEW2 0xffad
-
-/* Decoder Buffer hardware size on Chip */
-#define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */
-#define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */
-
-/* ======================================================================== */
-/* ========================== START USER SETTABLE DMA VARIABLES =========== */
-/* ======================================================================== */
-
#define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */
-/* DMA Buffers, Default size in MB allocated */
-#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
-#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
-#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
-#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1
-#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
-#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
-#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1
-
-/* ======================================================================== */
-/* ========================== END USER SETTABLE DMA VARIABLES ============= */
-/* ======================================================================== */
-
-/* Decoder Status Register */
-#define IVTV_DMA_ERR_LIST 0x00000010
-#define IVTV_DMA_ERR_WRITE 0x00000008
-#define IVTV_DMA_ERR_READ 0x00000004
-#define IVTV_DMA_SUCCESS_WRITE 0x00000002
-#define IVTV_DMA_SUCCESS_READ 0x00000001
-#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ)
-#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE)
-#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ)
-
/* DMA Registers */
#define IVTV_REG_DMAXFER (0x0000)
#define IVTV_REG_DMASTATUS (0x0004)
@@ -232,42 +112,24 @@ extern const u32 yuv_offset[4];
#define IVTV_REG_VPU (0x9058)
#define IVTV_REG_APU (0xA064)
-#define IVTV_IRQ_ENC_START_CAP (0x1 << 31)
-#define IVTV_IRQ_ENC_EOS (0x1 << 30)
-#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29)
-#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28)
-#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27)
-#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25)
-#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24)
-#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22)
-#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20)
-#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19)
-#define IVTV_IRQ_DMA_ERR (0x1 << 18)
-#define IVTV_IRQ_DMA_WRITE (0x1 << 17)
-#define IVTV_IRQ_DMA_READ (0x1 << 16)
-#define IVTV_IRQ_DEC_VSYNC (0x1 << 10)
-
-/* IRQ Masks */
-#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
- IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
-
-#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
-#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
-
/* i2c stuff */
#define I2C_CLIENTS_MAX 16
/* debugging */
+extern int ivtv_debug;
-#define IVTV_DBGFLG_WARN (1 << 0)
-#define IVTV_DBGFLG_INFO (1 << 1)
-#define IVTV_DBGFLG_API (1 << 2)
-#define IVTV_DBGFLG_DMA (1 << 3)
-#define IVTV_DBGFLG_IOCTL (1 << 4)
-#define IVTV_DBGFLG_I2C (1 << 5)
-#define IVTV_DBGFLG_IRQ (1 << 6)
-#define IVTV_DBGFLG_DEC (1 << 7)
-#define IVTV_DBGFLG_YUV (1 << 8)
+#define IVTV_DBGFLG_WARN (1 << 0)
+#define IVTV_DBGFLG_INFO (1 << 1)
+#define IVTV_DBGFLG_MB (1 << 2)
+#define IVTV_DBGFLG_IOCTL (1 << 3)
+#define IVTV_DBGFLG_FILE (1 << 4)
+#define IVTV_DBGFLG_DMA (1 << 5)
+#define IVTV_DBGFLG_IRQ (1 << 6)
+#define IVTV_DBGFLG_DEC (1 << 7)
+#define IVTV_DBGFLG_YUV (1 << 8)
+#define IVTV_DBGFLG_I2C (1 << 9)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 10)
/* NOTE: extra space before comma in 'itv->num , ## args' is required for
gcc-2.95, otherwise it won't compile. */
@@ -276,43 +138,37 @@ extern const u32 yuv_offset[4];
if ((x) & ivtv_debug) \
printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
} while (0)
-#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args)
-#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
+#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args)
+#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args)
+#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
-#define IVTV_FB_DEBUG(x, type, fmt, args...) \
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
do { \
- if ((x) & ivtv_debug) \
- printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \
+ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
} while (0)
-#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
-#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
-#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
/* Standard kernel messages */
#define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args)
#define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
#define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args)
-#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args)
-#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args)
-
-/* Values for IVTV_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
/* output modes (cx23415 only) */
#define OUT_NONE 0
@@ -323,22 +179,14 @@ extern const u32 yuv_offset[4];
#define IVTV_MAX_PGM_INDEX (400)
-extern int ivtv_debug;
-
-
struct ivtv_options {
- int megabytes[IVTV_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 */
- int newi2c; /* New I2C algorithm */
+ int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */
+ int cardtype; /* force card type on load */
+ int tuner; /* set tuner on load */
+ int radio; /* enable/disable radio */
+ int newi2c; /* new I2C algorithm */
};
-#define IVTV_MBOX_DMA_START 6
-#define IVTV_MBOX_DMA_END 8
-#define IVTV_MBOX_DMA 9
-#define IVTV_MBOX_FIELD_DISPLAYED 8
-
/* ivtv-specific mailbox template */
struct ivtv_mailbox {
u32 flags;
@@ -362,7 +210,7 @@ struct ivtv_mailbox_data {
};
/* per-buffer bit flags */
-#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */
+#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */
/* per-stream, s_flags */
#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */
@@ -383,23 +231,25 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DMA 0 /* DMA in progress */
#define IVTV_F_I_UDMA 1 /* UDMA in progress */
#define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */
-#define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */
-#define IVTV_F_I_EOS 4 /* End of encoder stream reached */
-#define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */
-#define IVTV_F_I_DIG_RST 6 /* Reset digitizer */
+#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */
+#define IVTV_F_I_EOS 4 /* end of encoder stream reached */
+#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */
+#define IVTV_F_I_DIG_RST 6 /* reset digitizer */
#define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */
-#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */
#define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */
#define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */
#define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */
#define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */
#define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */
#define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */
-#define IVTV_F_I_HAVE_WORK 15 /* Used in the interrupt handler: there is work to be done */
+#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */
#define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */
#define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */
#define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */
#define IVTV_F_I_PIO 19 /* PIO in progress */
+#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */
+#define IVTV_F_I_INITED 21 /* set after first open */
+#define IVTV_F_I_FAILED 22 /* set if first open failed */
/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
@@ -408,7 +258,7 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */
/* Scatter-Gather array element, used in DMA transfers */
-struct ivtv_SG_element {
+struct ivtv_sg_element {
u32 src;
u32 dst;
u32 size;
@@ -418,9 +268,11 @@ struct ivtv_user_dma {
struct mutex lock;
int page_count;
struct page *map[IVTV_DMA_SG_OSD_ENT];
+ /* Needed when dealing with highmem userspace buffers */
+ struct page *bouncemap[IVTV_DMA_SG_OSD_ENT];
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT];
+ struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT];
dma_addr_t SG_handle;
int SG_length;
@@ -440,21 +292,21 @@ struct ivtv_dma_page_info {
struct ivtv_buffer {
struct list_head list;
dma_addr_t dma_handle;
- unsigned long b_flags;
+ unsigned short b_flags;
+ unsigned short dma_xfer_cnt;
char *buf;
-
u32 bytesused;
u32 readpos;
};
struct ivtv_queue {
- struct list_head list;
- u32 buffers;
- u32 length;
- u32 bytesused;
+ struct list_head list; /* the list of buffers in this queue */
+ u32 buffers; /* number of buffers in this queue */
+ u32 length; /* total number of bytes of available buffer space */
+ u32 bytesused; /* total number of bytes used in this queue */
};
-struct ivtv; /* forward reference */
+struct ivtv; /* forward reference */
struct ivtv_stream {
/* These first four fields are always set, even if the stream
@@ -465,11 +317,13 @@ struct ivtv_stream {
int type; /* stream type */
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 */
+ 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 */
+ u32 pending_offset;
+ u32 pending_backup;
+ u64 pending_pts;
+
u32 dma_offset;
u32 dma_backup;
u64 dma_pts;
@@ -490,47 +344,53 @@ struct ivtv_stream {
struct ivtv_queue q_dma; /* waiting for DMA */
struct ivtv_queue q_predma; /* waiting for DMA */
+ /* DMA xfer counter, buffers belonging to the same DMA
+ xfer will have the same dma_xfer_cnt. */
+ u16 dma_xfer_cnt;
+
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_SG_element *SGarray;
- struct ivtv_SG_element *PIOarray;
- dma_addr_t SG_handle;
- int SG_length;
+ struct ivtv_sg_element *sg_pending;
+ struct ivtv_sg_element *sg_processing;
+ struct ivtv_sg_element *sg_dma;
+ dma_addr_t sg_handle;
+ int sg_pending_size;
+ int sg_processing_size;
+ int sg_processed;
/* SG List of Buffers */
struct scatterlist *SGlist;
};
struct ivtv_open_id {
- u32 open_id;
- int type;
- enum v4l2_priority prio;
+ u32 open_id; /* unique ID for this file descriptor */
+ int type; /* stream type */
+ int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */
+ enum v4l2_priority prio; /* priority */
struct ivtv *itv;
};
-#define IVTV_YUV_UPDATE_HORIZONTAL 0x01
-#define IVTV_YUV_UPDATE_VERTICAL 0x02
-
struct yuv_frame_info
{
u32 update;
- int src_x;
- int src_y;
- unsigned int src_w;
- unsigned int src_h;
- int dst_x;
- int dst_y;
- unsigned int dst_w;
- unsigned int dst_h;
- int pan_x;
- int pan_y;
+ s32 src_x;
+ s32 src_y;
+ u32 src_w;
+ u32 src_h;
+ s32 dst_x;
+ s32 dst_y;
+ u32 dst_w;
+ u32 dst_h;
+ s32 pan_x;
+ s32 pan_y;
u32 vis_w;
u32 vis_h;
u32 interlaced_y;
u32 interlaced_uv;
- int tru_x;
+ s32 tru_x;
u32 tru_w;
u32 tru_h;
u32 offset_y;
+ s32 lace_mode;
};
#define IVTV_YUV_MODE_INTERLACED 0x00
@@ -603,7 +463,6 @@ struct yuv_playback_info
int decode_height;
int frame_interlaced;
- int frame_interlaced_last;
int lace_mode;
int lace_threshold;
@@ -614,6 +473,11 @@ struct yuv_playback_info
u32 yuv_forced_update;
int update_frame;
+
+ int sync_field[4]; /* Field to sync on */
+ int field_delay[4]; /* Flag to extend duration of previous frame */
+ u8 fields_lapsed; /* Counter used when delaying a frame */
+
struct yuv_frame_info new_frame_info[4];
struct yuv_frame_info old_frame_info;
struct yuv_frame_info old_frame_info_args;
@@ -625,38 +489,61 @@ struct yuv_playback_info
#define IVTV_VBI_FRAMES 32
/* VBI data */
+struct vbi_cc {
+ u8 odd[2]; /* two-byte payload of odd field */
+ u8 even[2]; /* two-byte payload of even field */;
+};
+
+struct vbi_vps {
+ u8 data[5]; /* five-byte VPS payload */
+};
+
struct vbi_info {
- u32 dec_start;
- u32 enc_start, enc_size;
- int fpi;
- u32 frame;
- u32 dma_offset;
- 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;
- u32 service_set_out;
- 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];
- struct v4l2_sliced_vbi_data sliced_dec_data[36];
+ /* VBI general data, does not change during streaming */
+
+ u32 raw_decoder_line_size; /* raw VBI line size from digitizer */
+ u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */
+ u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */
+ u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */
+ u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */
+ u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */
+
+ u32 start[2]; /* start of first VBI line in the odd/even fields */
+ u32 count; /* number of VBI lines per field */
+ u32 raw_size; /* size of raw VBI line from the digitizer */
+ u32 sliced_size; /* size of sliced VBI line from the digitizer */
+
+ u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */
+ u32 enc_start; /* start in encoder memory of VBI capture buffers */
+ u32 enc_size; /* size of VBI capture area */
+ int fpi; /* number of VBI frames per interrupt */
+
+ struct v4l2_format in; /* current VBI capture format */
+ struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */
+ int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */
+
+ /* Raw VBI compatibility hack */
+
+ u32 frame; /* frame counter hack needed for backwards compatibility
+ of old VBI software */
+
+ /* Sliced VBI output data */
+
+ struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to
+ prevent dropping CC data if they couldn't be
+ processed fast enough */
+ int cc_payload_idx; /* index in cc_payload */
+ u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */
+ int wss_payload; /* sliced VBI WSS payload */
+ u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */
+ struct vbi_vps vps_payload; /* sliced VBI VPS payload */
+
+ /* Sliced VBI capture data */
+
+ struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */
+ struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */
+
+ /* VBI Embedding data */
/* Buffer for VBI data inserted into MPEG stream.
The first byte is a dummy byte that's never used.
@@ -673,12 +560,9 @@ struct vbi_info {
This pointer array will allocate 2049 bytes to store each VBI frame. */
u8 *sliced_mpeg_data[IVTV_VBI_FRAMES];
u32 sliced_mpeg_size[IVTV_VBI_FRAMES];
- struct ivtv_buffer sliced_mpeg_buf;
- u32 inserted_frame;
-
- u32 start[2], count;
- u32 raw_size;
- u32 sliced_size;
+ struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */
+ u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data
+ to be inserted in the MPEG stream */
};
/* forward declaration of struct defined in ivtv-cards.h */
@@ -686,130 +570,132 @@ struct ivtv_card;
/* Struct to hold info about ivtv cards */
struct ivtv {
- int num; /* board number, -1 during init! */
- char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */
- struct pci_dev *dev; /* PCI device */
+ /* General fixed card data */
+ int num; /* board number, -1 during init! */
+ char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */
+ struct pci_dev *dev; /* PCI device */
const struct ivtv_card *card; /* card information */
- const char *card_name; /* full name of the card */
- u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */
- u8 is_50hz;
- u8 is_60hz;
- u8 is_out_50hz;
- u8 is_out_60hz;
- u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */
- u8 nof_inputs; /* number of video inputs */
- u8 nof_audio_inputs; /* number of audio inputs */
- u32 v4l2_cap; /* V4L2 capabilities of card */
- u32 hw_flags; /* Hardware description of the board */
-
- /* controlling Video decoder function */
+ const char *card_name; /* full name of the card */
+ u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */
+ u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */
+ u8 nof_inputs; /* number of video inputs */
+ u8 nof_audio_inputs; /* number of audio inputs */
+ u32 v4l2_cap; /* V4L2 capabilities of card */
+ u32 hw_flags; /* hardware description of the board */
+ int tunerid; /* userspace tuner ID for experimental Xceive tuner support */
+ v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */
+ /* controlling video decoder function */
int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+ u32 base_addr; /* PCI resource base address */
+ volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
+ volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
+ volatile void __iomem *reg_mem; /* pointer to mapped registers */
+ struct ivtv_options options; /* user options */
+
+
+ /* High-level state info */
+ unsigned long i_flags; /* global ivtv flags */
+ u8 is_50hz; /* 1 if the current capture standard is 50 Hz */
+ u8 is_60hz /* 1 if the current capture standard is 60 Hz */;
+ u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */;
+ u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */;
+ int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */
+ u32 audio_input; /* current audio input */
+ u32 active_input; /* current video input */
+ u32 active_output; /* current video output */
+ v4l2_std_id std; /* current capture TV standard */
+ v4l2_std_id std_out; /* current TV output standard */
+ u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */
+ u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */
+ struct cx2341x_mpeg_params params; /* current encoder parameters */
+
+
+ /* Locking */
+ spinlock_t lock; /* lock access to this struct */
+ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
+
+
+ /* Streams */
+ int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */
+ struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */
+ atomic_t capturing; /* count number of active capture streams */
+ atomic_t decoding; /* count number of active decoding streams */
+
+
+ /* Interrupts & DMA */
+ u32 irqmask; /* active interrupts */
+ u32 irq_rr_idx; /* round-robin stream index */
+ struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */
+ struct work_struct irq_work_queue; /* work entry */
+ spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+ int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */
+ int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */
+ u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */
+ u32 dma_data_req_size; /* store size of current DMA request */
+ int dma_retries; /* current DMA retry attempt */
+ struct ivtv_user_dma udma; /* user based DMA for OSD */
+ struct timer_list dma_timer; /* timer used to catch unfinished DMAs */
+ u32 last_vsync_field; /* last seen vsync field */
+ wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */
+ wait_queue_head_t eos_waitq; /* wake up when EOS arrives */
+ wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */
+ wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */
+
+
+ /* Mailbox */
+ struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */
+ struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */
+ struct ivtv_api_cache api_cache[256]; /* cached API commands */
+
+
+ /* I2C */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */
+ int i2c_state; /* i2c bit state */
+ struct mutex i2c_bus_lock; /* lock i2c bus */
+
+
+ /* Program Index information */
+ u32 pgm_info_offset; /* start of pgm info in encoder memory */
+ u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */
+ u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */
+ u32 pgm_info_read_idx; /* last index in pgm_info read by the application */
+ struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */
+
+
+ /* Miscellaneous */
+ u32 open_id; /* incremented each time an open occurs, is >= 1 */
+ struct v4l2_prio_state prio; /* priority state */
+ int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */
+ int speed; /* current playback speed setting */
+ u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */
+ u64 mpg_data_received; /* number of bytes received from the MPEG stream */
+ u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */
+ u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */
+ unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */
+ u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */
+
+
+ /* VBI state info */
+ struct vbi_info vbi; /* VBI-specific data */
+
+
+ /* YUV playback */
+ struct yuv_playback_info yuv_info; /* YUV playback data */
- struct ivtv_options options; /* User options */
- int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */
- struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */
- int speed;
- u8 speed_mute_audio;
- unsigned long i_flags; /* global ivtv flags */
- atomic_t capturing; /* count number of active capture streams */
- atomic_t decoding; /* count number of active decoding streams */
- u32 irq_rr_idx; /* Round-robin stream index */
- int cur_dma_stream; /* index of stream doing DMA */
- int cur_pio_stream; /* index of stream doing PIO */
- u32 dma_data_req_offset;
- u32 dma_data_req_size;
- int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */
- spinlock_t lock; /* lock access to this struct */
- int search_pack_header;
-
- spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
-
- /* User based DMA for OSD */
- struct ivtv_user_dma udma;
-
- 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;
- u32 irqmask;
-
- struct v4l2_prio_state prio;
- struct workqueue_struct *irq_work_queues;
- struct work_struct irq_work_queue;
- struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */
-
- struct vbi_info vbi;
-
- struct ivtv_mailbox_data enc_mbox;
- struct ivtv_mailbox_data dec_mbox;
- struct ivtv_api_cache api_cache[256]; /* Cached API Commands */
-
- u8 card_rev;
- volatile void __iomem *enc_mem, *dec_mem, *reg_mem;
-
- 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[IVTV_MAX_PGM_INDEX];
-
- u64 mpg_data_received;
- u64 vbi_data_inserted;
-
- wait_queue_head_t cap_w;
- /* when the next decoder event arrives this queue is woken up */
- wait_queue_head_t event_waitq;
- /* when the next decoder vsync arrives this queue is woken up */
- wait_queue_head_t vsync_waitq;
- /* when the current DMA is finished this queue is woken up */
- wait_queue_head_t dma_waitq;
/* OSD support */
unsigned long osd_video_pbase;
- int osd_global_alpha_state; /* 0=off : 1=on */
- int osd_local_alpha_state; /* 0=off : 1=on */
- int osd_color_key_state; /* 0=off : 1=on */
- u8 osd_global_alpha; /* Current global alpha */
- u32 osd_color_key; /* Current color key */
- u32 osd_pixelformat; /* Current pixel format */
- struct v4l2_rect osd_rect; /* Current OSD position and size */
- struct v4l2_rect main_rect; /* Current Main window position and size */
-
- u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */
-
- /* i2c */
- struct i2c_adapter i2c_adap;
- struct i2c_algo_bit_data i2c_algo;
- struct i2c_client i2c_client;
- struct mutex i2c_bus_lock;
- int i2c_state;
- struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
-
- /* v4l2 and User settings */
-
- /* codec settings */
- struct cx2341x_mpeg_params params;
- u32 audio_input;
- u32 active_input;
- u32 active_output;
- v4l2_std_id std;
- v4l2_std_id std_out;
- v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
- u8 audio_stereo_mode;
- u8 audio_bilingual_mode;
-
- /* dualwatch */
- unsigned long dualwatch_jiffies;
- u16 dualwatch_stereo_mode;
-
- /* Digitizer type */
- int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
-
- u32 lastVsyncFrame;
-
- struct yuv_playback_info yuv_info;
- struct osd_info *osd_info;
+ int osd_global_alpha_state; /* 1 = global alpha is on */
+ int osd_local_alpha_state; /* 1 = local alpha is on */
+ int osd_chroma_key_state; /* 1 = chroma-keying is on */
+ u8 osd_global_alpha; /* current global alpha */
+ u32 osd_chroma_key; /* current chroma key */
+ struct v4l2_rect osd_rect; /* current OSD position and size */
+ struct v4l2_rect main_rect; /* current Main window position and size */
+ struct osd_info *osd_info; /* ivtvfb private OSD info */
};
/* Globals */
@@ -831,7 +717,7 @@ int ivtv_set_output_mode(struct ivtv *itv, int mode);
struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
/* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
/* Wait on queue, returns -EINTR if interrupted */
int ivtv_waitq(wait_queue_head_t *waitq);
@@ -840,6 +726,9 @@ int ivtv_waitq(wait_queue_head_t *waitq);
struct tveeprom; /* forward reference */
void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
+/* First-open initialization: load firmware, init cx25840, etc. */
+int ivtv_init_on_first_open(struct ivtv *itv);
+
/* 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
@@ -867,4 +756,4 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
#define write_dec_sync(val, addr) \
do { write_dec(val, addr); read_dec(addr); } while (0)
-#endif /* IVTV_DRIVER_H */
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 555d5e6369c3..da50fa4a72a5 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -27,10 +27,9 @@
#include "ivtv-irq.h"
#include "ivtv-vbi.h"
#include "ivtv-mailbox.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
#include "ivtv-streams.h"
#include "ivtv-yuv.h"
-#include "ivtv-controls.h"
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include <media/saa7115.h>
@@ -190,7 +189,9 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
u32 addr = itv->pgm_info_offset + 4 + idx * 24;
- const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 };
+ const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
+ V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
+ // 1=I, 2=P, 4=B
e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
if (e->offset > itv->mpg_data_received) {
@@ -199,7 +200,7 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
e->offset += itv->vbi_data_inserted;
e->length = read_enc(addr);
e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
- e->flags = mapping[read_enc(addr + 12) & 3];
+ e->flags = mapping[read_enc(addr + 12) & 7];
i++;
}
itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
@@ -218,7 +219,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* Process pending program info updates and pending VBI data */
ivtv_update_pgm_info(itv);
- if (jiffies - itv->dualwatch_jiffies > HZ) {
+ if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
itv->dualwatch_jiffies = jiffies;
ivtv_dualwatch(itv);
}
@@ -245,8 +246,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* do we have new data? */
buf = ivtv_dequeue(s, &s->q_full);
if (buf) {
- if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags))
+ if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
return buf;
+ buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
/* byteswap MPG data */
ivtv_buf_swap(buf);
@@ -256,19 +258,19 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
}
return buf;
}
- /* return if file was opened with O_NONBLOCK */
- if (non_block) {
- *err = -EAGAIN;
- return NULL;
- }
/* return if end of stream */
if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
IVTV_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 */
@@ -376,10 +378,20 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co
int rc;
buf = ivtv_get_buffer(s, non_block, &rc);
- if (buf == NULL && rc == -EAGAIN && tot_written)
- break;
- if (buf == NULL)
+ /* 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(IVTV_F_S_STREAMOFF, &s->s_flags);
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ ivtv_release_stream(s);
+ }
+ /* set errno */
return rc;
+ }
rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
if (buf != &itv->vbi.sliced_mpeg_buf) {
ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
@@ -406,7 +418,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co
ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
struct ivtv *itv = s->itv;
- IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+ IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
if (rc > 0)
pos += rc;
return rc;
@@ -497,9 +509,11 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
struct ivtv_stream *s = &itv->streams[id->type];
int rc;
- IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+ mutex_lock(&itv->serialize_lock);
rc = ivtv_start_capture(id);
+ mutex_unlock(&itv->serialize_lock);
if (rc)
return rc;
return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
@@ -535,7 +549,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
int rc;
DEFINE_WAIT(wait);
- IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+ IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -549,8 +563,11 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
/* This stream does not need to start any decoding */
if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+ int elems = count / sizeof(struct v4l2_sliced_vbi_data);
+
set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return ivtv_write_vbi(itv, user_buf, count);
+ ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems);
+ return elems * sizeof(struct v4l2_sliced_vbi_data);
}
mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
@@ -610,7 +627,9 @@ retry:
}
/* Start decoder (returns 0 if already started) */
+ mutex_lock(&itv->serialize_lock);
rc = ivtv_start_decoding(id, itv->speed);
+ mutex_unlock(&itv->serialize_lock);
if (rc) {
IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
@@ -643,7 +662,7 @@ retry:
to transfer the rest. */
if (count && !(filp->f_flags & O_NONBLOCK))
goto retry;
- IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+ IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
return bytes_written;
}
@@ -655,6 +674,7 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
int res = 0;
/* add stream's waitq to the poll list */
+ IVTV_DEBUG_HI_FILE("Decoder poll\n");
poll_wait(filp, &s->waitq, wait);
set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
@@ -677,16 +697,21 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
/* Start a capture if there is none */
if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- int rc = ivtv_start_capture(id);
+ int rc;
+ mutex_lock(&itv->serialize_lock);
+ rc = ivtv_start_capture(id);
+ mutex_unlock(&itv->serialize_lock);
if (rc) {
IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
s->name, rc);
return POLLERR;
}
+ IVTV_DEBUG_FILE("Encoder poll started capture\n");
}
/* add stream's waitq to the poll list */
+ IVTV_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
if (eof || s->q_full.length)
@@ -699,7 +724,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+ IVTV_DEBUG_FILE("close() of %s\n", s->name);
/* 'Unclaim' this stream */
@@ -726,10 +751,11 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
ivtv_stop_v4l2_encode_stream(s, gop_end);
}
}
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
-
- ivtv_release_stream(s);
+ if (!gop_end) {
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ ivtv_release_stream(s);
+ }
}
static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
@@ -737,13 +763,14 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+ IVTV_DEBUG_FILE("close() of %s\n", s->name);
/* Stop decoding */
if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
IVTV_DEBUG_INFO("close stopping decode\n");
ivtv_stop_v4l2_decode_stream(s, flags, pts);
+ itv->output_mode = OUT_NONE;
}
clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
@@ -751,12 +778,11 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
/* Restore registers we've changed & clean up any mess we've made */
ivtv_yuv_close(itv);
}
- if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV)
- itv->output_mode = OUT_NONE;
- else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG)
- itv->output_mode = OUT_NONE;
+ if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
+ itv->output_mode = OUT_NONE;
itv->speed = 0;
+ clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
ivtv_release_stream(s);
}
@@ -766,7 +792,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+ IVTV_DEBUG_FILE("close %s\n", s->name);
v4l2_prio_close(&itv->prio, &id->prio);
@@ -779,6 +805,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
/* 'Unclaim' this stream */
/* Stop radio */
+ mutex_lock(&itv->serialize_lock);
if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
/* Closing radio device, return to TV mode */
ivtv_mute(itv);
@@ -799,52 +826,40 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
ivtv_unmute(itv);
ivtv_release_stream(s);
} else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+ struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
+
ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+
+ /* If all output streams are closed, and if the user doesn't have
+ IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
+ if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {
+ /* disable CC on TV-out */
+ ivtv_disable_cc(itv);
+ }
} else {
ivtv_stop_capture(id, 0);
}
kfree(id);
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
-int ivtv_v4l2_open(struct inode *inode, struct file *filp)
+static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
{
- int x, y = 0;
+ struct ivtv *itv = s->itv;
struct ivtv_open_id *item;
- struct ivtv *itv = NULL;
- struct ivtv_stream *s = NULL;
- int minor = iminor(inode);
-
- /* Find which card this open was on */
- spin_lock(&ivtv_cards_lock);
- for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
- /* find out which stream this open was on */
- for (y = 0; y < IVTV_MAX_STREAMS; y++) {
- s = &ivtv_cards[x]->streams[y];
- if (s->v4l2dev && s->v4l2dev->minor == minor) {
- itv = ivtv_cards[x];
- break;
- }
- }
- }
- spin_unlock(&ivtv_cards_lock);
- if (itv == NULL) {
- /* Couldn't find a device registered
- on that minor, shouldn't happen! */
- printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
- return -ENXIO;
- }
+ IVTV_DEBUG_FILE("open %s\n", s->name);
- if (y == IVTV_DEC_STREAM_TYPE_MPG &&
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
return -EBUSY;
- if (y == IVTV_DEC_STREAM_TYPE_YUV &&
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
return -EBUSY;
- if (y == IVTV_DEC_STREAM_TYPE_YUV) {
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
if (read_reg(0x82c) == 0) {
IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
/* return -ENODEV; */
@@ -859,7 +874,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
return -ENOMEM;
}
item->itv = itv;
- item->type = y;
+ item->type = s->type;
v4l2_prio_open(&itv->prio, &item->prio);
item->open_id = itv->open_id++;
@@ -873,12 +888,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
return -EBUSY;
}
+ if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ if (atomic_read(&itv->capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+ /* Mark that the radio is being used. */
+ set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* We have the radio */
ivtv_mute(itv);
/* Switch tuner to radio */
ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
- /* Mark that the radio is being used. */
- set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Select the correct audio input (i.e. radio tuner) */
ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -893,45 +916,65 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
}
/* YUV or MPG Decoding Mode? */
- if (y == IVTV_DEC_STREAM_TYPE_MPG)
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
- else if (y == IVTV_DEC_STREAM_TYPE_YUV)
- {
+ else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
- }
-
return 0;
}
-void ivtv_mute(struct ivtv *itv)
+int ivtv_v4l2_open(struct inode *inode, struct file *filp)
{
- struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 };
+ int res, x, y = 0;
+ struct ivtv *itv = NULL;
+ struct ivtv_stream *s = NULL;
+ int minor = iminor(inode);
+
+ /* Find which card this open was on */
+ spin_lock(&ivtv_cards_lock);
+ for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+ /* find out which stream this open was on */
+ for (y = 0; y < IVTV_MAX_STREAMS; y++) {
+ s = &ivtv_cards[x]->streams[y];
+ if (s->v4l2dev && s->v4l2dev->minor == minor) {
+ itv = ivtv_cards[x];
+ break;
+ }
+ }
+ }
+ spin_unlock(&ivtv_cards_lock);
+
+ if (itv == NULL) {
+ /* Couldn't find a device registered
+ on that minor, shouldn't happen! */
+ IVTV_WARN("No ivtv device found on minor %d\n", minor);
+ return -ENXIO;
+ }
- /* Mute sound to avoid pop */
- ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
+ mutex_lock(&itv->serialize_lock);
+ if (ivtv_init_on_first_open(itv)) {
+ IVTV_ERR("Failed to initialize on minor %d\n", minor);
+ mutex_unlock(&itv->serialize_lock);
+ return -ENXIO;
+ }
+ res = ivtv_serialized_open(s, filp);
+ mutex_unlock(&itv->serialize_lock);
+ return res;
+}
+void ivtv_mute(struct ivtv *itv)
+{
if (atomic_read(&itv->capturing))
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
-
IVTV_DEBUG_INFO("Mute\n");
}
void ivtv_unmute(struct ivtv *itv)
{
- struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 };
-
- /* initialize or refresh input */
- if (atomic_read(&itv->capturing) == 0)
- ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_sleep_timeout(HZ / 10, 0);
-
if (atomic_read(&itv->capturing)) {
+ ivtv_msleep_timeout(100, 0);
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
}
-
- /* Unmute */
- ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
IVTV_DEBUG_INFO("Unmute\n");
}
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h
index 74a1745fabbc..2c8d5186c9c3 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.h
+++ b/drivers/media/video/ivtv/ivtv-fileops.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_FILEOPS_H
+#define IVTV_FILEOPS_H
+
/* Testing/Debugging */
int ivtv_v4l2_open(struct inode *inode, struct file *filp);
ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count,
@@ -42,3 +45,5 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type);
/* Release a previously claimed stream. */
void ivtv_release_stream(struct ivtv_stream *s);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index d4c910b782af..425eb1063904 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -36,7 +36,7 @@
#define IVTV_CMD_SPU_STOP 0x00000001
#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
-#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME 600
#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg"
#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024)
@@ -56,14 +56,12 @@ retry:
volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
const u32 *src = (const u32 *)fw->data;
- /* temporarily allow 256 KB encoding firmwares as well for
- compatibility with blackbird cards */
- if (fw->size != size && fw->size != 256 * 1024) {
+ 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. */
- IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+ IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
release_firmware(fw);
retries--;
goto retry;
@@ -74,12 +72,12 @@ retry:
dst++;
src++;
}
+ IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
release_firmware(fw);
- IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
return size;
}
- IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
- IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+ IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
return -ENOMEM;
}
@@ -91,7 +89,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
if (itv->enc_mbox.mbox)
ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -115,7 +113,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
IVTV_DEBUG_INFO("Stopping SPU\n");
write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -131,9 +129,8 @@ void ivtv_halt_firmware(struct ivtv *itv)
write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
}
- IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
- (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
- ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+ IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+ ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
}
void ivtv_firmware_versions(struct ivtv *itv)
@@ -206,12 +203,12 @@ int ivtv_firmware_init(struct ivtv *itv)
/* start firmware */
write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
if (itv->has_cx23415)
write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
else
write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
/* find mailboxes and ping firmware */
itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -266,7 +263,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
IVTV_DECODE_INIT_MPEG_FILENAME);
} else {
ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
}
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 8b2ffe658905..041ba94e65bc 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -19,7 +19,12 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_FIRMWARE_H
+#define IVTV_FIRMWARE_H
+
int ivtv_firmware_init(struct ivtv *itv);
void ivtv_firmware_versions(struct ivtv *itv);
void ivtv_halt_firmware(struct ivtv *itv);
void ivtv_init_mpeg_decoder(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index bc8f8ca2961f..132fb5f71366 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -115,40 +115,13 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
curout = (curout & ~0xF) | 1;
write_reg(curout, IVTV_REG_GPIO_OUT);
/* We could use something else for smaller time */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
curout |= 2;
write_reg(curout, IVTV_REG_GPIO_OUT);
curdir &= ~0x80;
write_reg(curdir, IVTV_REG_GPIO_DIR);
}
-#ifdef HAVE_XC3028
-int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
-{
- int curdir, curout;
- struct ivtv *itv = (struct ivtv *) priv;
-
- if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
- return -EINVAL;
- IVTV_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);
- write_reg(curout, IVTV_REG_GPIO_OUT);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
-
- curout |= (1 << 12);
- write_reg(curout, IVTV_REG_GPIO_OUT);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
-
- return 0;
-}
-#endif
void ivtv_gpio_init(struct ivtv *itv)
{
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h
index c301d2a39346..964a265d91a9 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/drivers/media/video/ivtv/ivtv-gpio.h
@@ -18,8 +18,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_GPIO_H
+#define IVTV_GPIO_H
+
/* GPIO stuff */
void ivtv_gpio_init(struct ivtv *itv);
void ivtv_reset_ir_gpio(struct ivtv *itv);
-int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr);
+int ivtv_reset_tuner_gpio(void *dev, int cmd, int value);
int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 50624c6a62a5..285fca676a69 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -109,6 +109,7 @@ static const u8 hw_driverids[] = {
I2C_DRIVERID_UPD64083,
I2C_DRIVERID_SAA717X,
I2C_DRIVERID_WM8739,
+ I2C_DRIVERID_VP27SMPX,
0 /* IVTV_HW_GPIO dummy driver ID */
};
@@ -128,6 +129,7 @@ static const char * const hw_drivernames[] = {
"upd64083",
"saa717x",
"wm8739",
+ "vp27smpx",
"gpio",
};
@@ -144,7 +146,7 @@ static int attach_inform(struct i2c_client *client)
}
}
if (i == I2C_CLIENTS_MAX) {
- IVTV_ERR("insufficient room for new I2C client!\n");
+ IVTV_ERR("Insufficient room for new I2C client\n");
}
return 0;
}
@@ -236,7 +238,7 @@ static int ivtv_ack(struct ivtv *itv)
int ret = 0;
if (ivtv_getscl(itv) == 1) {
- IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+ IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +265,7 @@ static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
{
int i, bit;
- IVTV_DEBUG_I2C("write %x\n",byte);
+ IVTV_DEBUG_HI_I2C("write %x\n",byte);
for (i = 0; i < 8; ++i, byte<<=1) {
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +320,7 @@ static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
ivtv_scldelay(itv);
ivtv_setscl(itv, 0);
ivtv_scldelay(itv);
- IVTV_DEBUG_I2C("read %x\n",*byte);
+ IVTV_DEBUG_HI_I2C("read %x\n",*byte);
return 0;
}
@@ -330,7 +332,7 @@ static int ivtv_start(struct ivtv *itv)
sda = ivtv_getsda(itv);
if (sda != 1) {
- IVTV_DEBUG_I2C("SDA was low at start\n");
+ IVTV_DEBUG_HI_I2C("SDA was low at start\n");
ivtv_setsda(itv, 1);
if (!ivtv_waitsda(itv, 1)) {
IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +357,7 @@ static int ivtv_stop(struct ivtv *itv)
int i;
if (ivtv_getscl(itv) != 0) {
- IVTV_DEBUG_I2C("SCL not low when stopping\n");
+ IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -534,14 +536,13 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
#endif
};
-static struct i2c_algo_bit_data ivtv_i2c_algo_template = {
- NULL, /* ?? */
- ivtv_setsda_old, /* setsda function */
- ivtv_setscl_old, /* " */
- ivtv_getsda_old, /* " */
- ivtv_getscl_old, /* " */
- 10, /* udelay */
- 200 /* timeout */
+static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+ .setsda = ivtv_setsda_old,
+ .setscl = ivtv_setscl_old,
+ .getsda = ivtv_getsda_old,
+ .getscl = ivtv_getscl_old,
+ .udelay = 5,
+ .timeout = 200,
};
static struct i2c_client ivtv_i2c_client_template = {
@@ -569,7 +570,7 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
}
}
if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+ IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
return -ENODEV;
}
@@ -640,7 +641,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
addr = ivtv_i2c_hw_addr(itv, hw);
if (addr < 0) {
- IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+ IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
hw, ivtv_i2c_hw_name(hw), cmd);
return addr;
}
@@ -655,7 +656,7 @@ int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
addr = ivtv_i2c_id_addr(itv, id);
if (addr < 0) {
if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+ IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
id, ivtv_i2c_id_name(id), cmd);
return addr;
}
@@ -696,7 +697,7 @@ int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
{
if (itv->i2c_adap.algo == NULL) {
- IVTV_ERR("adapter is not set");
+ IVTV_ERR("Adapter is not set");
return;
}
i2c_clients_command(&itv->i2c_adap, cmd, arg);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 5d210adb5c52..677c3292855e 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_I2C_H
+#define IVTV_I2C_H
+
int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
@@ -34,3 +37,5 @@ void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
/* init + register i2c algo-bit adapter */
int __devinit init_ivtv_i2c(struct ivtv *itv);
void __devexit exit_ivtv_i2c(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 57af1762de1f..206eee7542db 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -25,8 +25,7 @@
#include "ivtv-queue.h"
#include "ivtv-fileops.h"
#include "ivtv-vbi.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
+#include "ivtv-routing.h"
#include "ivtv-streams.h"
#include "ivtv-yuv.h"
#include "ivtv-ioctl.h"
@@ -164,7 +163,7 @@ void ivtv_set_osd_alpha(struct ivtv *itv)
{
ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
- ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key);
+ ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);
}
int ivtv_set_speed(struct ivtv *itv, int speed)
@@ -285,6 +284,10 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
return -EBUSY;
+ if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
+ /* forces ivtv_set_speed to be called */
+ itv->speed = 0;
+ }
return ivtv_start_decoding(id, vc->play.speed);
}
@@ -309,6 +312,7 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
if (atomic_read(&itv->decoding) > 0) {
ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
(vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
+ set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
}
break;
@@ -317,8 +321,10 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
if (try) break;
if (itv->output_mode != OUT_MPG)
return -EBUSY;
- if (atomic_read(&itv->decoding) > 0) {
- ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 0);
+ if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
+ int speed = itv->speed;
+ itv->speed = 0;
+ return ivtv_start_decoding(id, speed);
}
break;
@@ -420,7 +426,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
- fmt->fmt.win.chromakey = itv->osd_color_key;
+ fmt->fmt.win.chromakey = itv->osd_chroma_key;
fmt->fmt.win.global_alpha = itv->osd_global_alpha;
break;
@@ -540,7 +546,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
if (set_fmt) {
- itv->osd_color_key = fmt->fmt.win.chromakey;
+ itv->osd_chroma_key = fmt->fmt.win.chromakey;
itv->osd_global_alpha = fmt->fmt.win.global_alpha;
ivtv_set_osd_alpha(itv);
}
@@ -577,9 +583,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
/* set raw VBI format */
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI &&
- itv->vbi.sliced_in->service_set &&
- atomic_read(&itv->capturing) > 0) {
+ if (set_fmt && atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
if (set_fmt) {
@@ -617,7 +621,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
return 0;
if (set == 0)
return -EINVAL;
- if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) {
+ if (atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
@@ -670,13 +674,21 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
- ivtv_audio_set_route(itv, route);
+ ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
break;
}
- case VIDIOC_INT_RESET:
- ivtv_reset_ir_gpio(itv);
+ case VIDIOC_INT_RESET: {
+ u32 val = *(u32 *)arg;
+
+ if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
+ ivtv_reset_ir_gpio(itv);
+ }
+ if (val & 0x02) {
+ itv->video_dec_func(itv, cmd, 0);
+ }
break;
+ }
default:
return -EINVAL;
@@ -687,6 +699,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
{
struct ivtv_open_id *id = NULL;
+ u32 data[CX2341X_MBOX_MAX_DATA];
if (filp) id = (struct ivtv_open_id *)filp->private_data;
@@ -891,6 +904,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
IVTV_DEBUG_INFO("Input unchanged\n");
break;
}
+ if (atomic_read(&itv->capturing) > 0) {
+ return -EBUSY;
+ }
IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp);
@@ -1092,14 +1108,21 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
case VIDIOC_G_ENC_INDEX: {
struct v4l2_enc_idx *idx = arg;
+ struct v4l2_enc_idx_entry *e = idx->entry;
+ int entries;
int i;
- idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+ entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
IVTV_MAX_PGM_INDEX;
- if (idx->entries > V4L2_ENC_IDX_ENTRIES)
- idx->entries = V4L2_ENC_IDX_ENTRIES;
- for (i = 0; i < idx->entries; i++) {
- idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+ if (entries > V4L2_ENC_IDX_ENTRIES)
+ entries = V4L2_ENC_IDX_ENTRIES;
+ idx->entries = 0;
+ for (i = 0; i < entries; i++) {
+ *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+ if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+ idx->entries++;
+ e++;
+ }
}
itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
break;
@@ -1113,12 +1136,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
memset(&enc->raw, 0, sizeof(enc->raw));
switch (enc->cmd) {
case V4L2_ENC_CMD_START:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
enc->flags = 0;
if (try)
return 0;
return ivtv_start_capture(id);
case V4L2_ENC_CMD_STOP:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
if (try)
return 0;
@@ -1126,6 +1151,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
return 0;
case V4L2_ENC_CMD_PAUSE:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
enc->flags = 0;
if (try)
return 0;
@@ -1138,6 +1164,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
break;
case V4L2_ENC_CMD_RESUME:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
enc->flags = 0;
if (try)
return 0;
@@ -1149,6 +1176,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_unmute(itv);
break;
default:
+ IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
break;
@@ -1156,22 +1184,58 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
case VIDIOC_G_FBUF: {
struct v4l2_framebuffer *fb = arg;
+ int pixfmt;
+ static u32 pixel_format[16] = {
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+ V4L2_PIX_FMT_RGB565,
+ V4L2_PIX_FMT_RGB555,
+ V4L2_PIX_FMT_RGB444,
+ V4L2_PIX_FMT_RGB32,
+ 0,
+ 0,
+ 0,
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+ V4L2_PIX_FMT_YUV565,
+ V4L2_PIX_FMT_YUV555,
+ V4L2_PIX_FMT_YUV444,
+ V4L2_PIX_FMT_YUV32,
+ 0,
+ 0,
+ 0,
+ };
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- break;
+ return -EINVAL;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
- V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
- fb->fmt.pixelformat = itv->osd_pixelformat;
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ pixfmt = (data[0] >> 3) & 0xf;
+ fb->fmt.pixelformat = pixel_format[pixfmt];
fb->fmt.width = itv->osd_rect.width;
fb->fmt.height = itv->osd_rect.height;
fb->base = (void *)itv->osd_video_pbase;
+ if (itv->osd_chroma_key_state)
+ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
if (itv->osd_global_alpha_state)
fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
- if (itv->osd_local_alpha_state)
- fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
- if (itv->osd_color_key_state)
- fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ pixfmt &= 7;
+ /* no local alpha for RGB565 or unknown formats */
+ if (pixfmt == 1 || pixfmt > 4)
+ break;
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+ else
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
+ if (itv->osd_local_alpha_state) {
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+ else
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ }
break;
}
@@ -1179,10 +1243,21 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
struct v4l2_framebuffer *fb = arg;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- break;
+ return -EINVAL;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
- itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
- itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+ itv->osd_local_alpha_state =
+ (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+ itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+ ivtv_set_osd_alpha(itv);
+ break;
+ }
+
+ case VIDIOC_OVERLAY: {
+ int *on = arg;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
break;
}
@@ -1194,6 +1269,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
int i;
IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
+ IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
if (itv->hw_flags & IVTV_HW_TVEEPROM) {
struct tveeprom tv;
@@ -1202,32 +1278,72 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
ivtv_get_input(itv, itv->active_input, &vidin);
ivtv_get_audio_input(itv, itv->audio_input, &audin);
- IVTV_INFO("Video Input: %s\n", vidin.name);
- IVTV_INFO("Audio Input: %s\n", audin.name);
+ IVTV_INFO("Video Input: %s\n", vidin.name);
+ IVTV_INFO("Audio Input: %s%s\n", audin.name,
+ (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
if (has_output) {
struct v4l2_output vidout;
struct v4l2_audioout audout;
int mode = itv->output_mode;
- static const char * const output_modes[] = {
+ static const char * const output_modes[5] = {
"None",
"MPEG Streaming",
"YUV Streaming",
"YUV Frames",
"Passthrough",
};
+ static const char * const audio_modes[5] = {
+ "Stereo",
+ "Left",
+ "Right",
+ "Mono",
+ "Swapped"
+ };
+ static const char * const alpha_mode[4] = {
+ "None",
+ "Global",
+ "Local",
+ "Global and Local"
+ };
+ static const char * const pixel_format[16] = {
+ "ARGB Indexed",
+ "RGB 5:6:5",
+ "ARGB 1:5:5:5",
+ "ARGB 1:4:4:4",
+ "ARGB 8:8:8:8",
+ "5",
+ "6",
+ "7",
+ "AYUV Indexed",
+ "YUV 5:6:5",
+ "AYUV 1:5:5:5",
+ "AYUV 1:4:4:4",
+ "AYUV 8:8:8:8",
+ "13",
+ "14",
+ "15",
+ };
ivtv_get_output(itv, itv->active_output, &vidout);
ivtv_get_audio_output(itv, 0, &audout);
IVTV_INFO("Video Output: %s\n", vidout.name);
- IVTV_INFO("Audio Output: %s\n", audout.name);
+ IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
+ audio_modes[itv->audio_stereo_mode],
+ audio_modes[itv->audio_bilingual_mode]);
if (mode < 0 || mode > OUT_PASSTHROUGH)
mode = OUT_NONE;
- IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+ IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
+ data[0] & 1 ? "On" : "Off",
+ alpha_mode[(data[0] >> 1) & 0x3],
+ pixel_format[(data[0] >> 3) & 0xf]);
}
- IVTV_INFO("Tuner: %s\n",
+ IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
cx2341x_log_status(&itv->params, itv->name);
- IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
+ IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
@@ -1237,7 +1353,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
(s->buffers - s->q_free.buffers) * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
- IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
+ IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
break;
}
@@ -1273,6 +1389,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
ivtv_release_stream(s);
return -EBUSY;
}
+ /* Mark that this file handle started the UDMA_YUV mode */
+ id->yuv_frames = 1;
if (args->y_source == NULL)
return 0;
return ivtv_yuv_prep_frame(itv, args);
@@ -1381,9 +1499,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
int try = (cmd == VIDEO_TRY_COMMAND);
if (try)
- IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n");
+ IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
else
- IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n");
+ IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
return ivtv_video_command(itv, id, vc, try);
}
@@ -1414,11 +1532,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return 0;
if (nonblocking)
return -EAGAIN;
- /* wait for event */
+ /* Wait for event. Note that serialize_lock is locked,
+ so to allow other processes to access the driver while
+ we are waiting unlock first and later lock again. */
+ mutex_unlock(&itv->serialize_lock);
prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0)
schedule();
finish_wait(&itv->event_waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (signal_pending(current)) {
/* return if a signal was received */
IVTV_DEBUG_INFO("User stopped wait for event\n");
@@ -1455,6 +1577,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
case VIDIOC_S_AUDOUT:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_S_FBUF:
+ case VIDIOC_OVERLAY:
ret = v4l2_prio_check(&itv->prio, &id->prio);
if (ret)
return ret;
@@ -1508,6 +1631,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
case VIDIOC_TRY_ENCODER_CMD:
case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
+ case VIDIOC_OVERLAY:
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
@@ -1548,12 +1672,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
return 0;
}
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
- struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
- struct ivtv *itv = id->itv;
-
/* Filter dvb ioctls that cannot be handled by video_usercopy */
switch (cmd) {
case VIDEO_SELECT_SOURCE:
@@ -1588,3 +1709,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
}
return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
}
+
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+ struct ivtv *itv = id->itv;
+ int res;
+
+ mutex_lock(&itv->serialize_lock);
+ res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg);
+ mutex_unlock(&itv->serialize_lock);
+ return res;
+}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index cbccf7a9f65c..a03351b6853d 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#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);
@@ -26,3 +29,5 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
void ivtv_set_osd_alpha(struct ivtv *itv);
int ivtv_set_speed(struct ivtv *itv, int speed);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index ba98bf054f2e..fd1688e4757d 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -19,12 +19,9 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-firmware.h"
-#include "ivtv-fileops.h"
#include "ivtv-queue.h"
#include "ivtv-udma.h"
#include "ivtv-irq.h"
-#include "ivtv-ioctl.h"
#include "ivtv-mailbox.h"
#include "ivtv-vbi.h"
#include "ivtv-yuv.h"
@@ -45,10 +42,9 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
{
struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
struct ivtv_buffer *buf;
- struct list_head *p;
int i = 0;
- IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
+ IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
s->v4l2dev == NULL || !ivtv_use_pio(s)) {
itv->cur_pio_stream = -1;
@@ -56,22 +52,20 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
return;
}
- IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
- buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
- list_for_each(p, &s->q_dma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
- u32 size = s->PIOarray[i].size & 0x3ffff;
+ IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
+ list_for_each_entry(buf, &s->q_dma.list, list) {
+ u32 size = s->sg_processing[i].size & 0x3ffff;
/* Copy the data from the card to the buffer */
if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
- memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size);
+ memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size);
}
else {
- memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size);
+ memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size);
}
- if (s->PIOarray[i].size & 0x80000000)
- break;
i++;
+ if (i == s->sg_processing_size)
+ break;
}
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
}
@@ -100,12 +94,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
{
struct ivtv *itv = s->itv;
struct ivtv_buffer *buf;
- struct list_head *p;
u32 bytes_needed = 0;
u32 offset, size;
u32 UVoffset = 0, UVsize = 0;
int skip_bufs = s->q_predma.buffers;
- int idx = s->SG_length;
+ int idx = s->sg_pending_size;
int rc;
/* sanity checks */
@@ -123,7 +116,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
case IVTV_ENC_STREAM_TYPE_MPG:
offset = data[1];
size = data[2];
- s->dma_pts = 0;
+ s->pending_pts = 0;
break;
case IVTV_ENC_STREAM_TYPE_YUV:
@@ -131,13 +124,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
size = data[2];
UVoffset = data[3];
UVsize = data[4];
- s->dma_pts = ((u64) data[5] << 32) | data[6];
+ s->pending_pts = ((u64) data[5] << 32) | data[6];
break;
case IVTV_ENC_STREAM_TYPE_PCM:
offset = data[1] + 12;
size = data[2] - 12;
- s->dma_pts = read_dec(offset - 8) |
+ s->pending_pts = read_dec(offset - 8) |
((u64)(read_dec(offset - 12)) << 32);
if (itv->has_cx23415)
offset += IVTV_DECODER_OFFSET;
@@ -150,13 +143,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
IVTV_DEBUG_INFO("VBI offset == 0\n");
return -1;
}
- s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
+ s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
break;
case IVTV_DEC_STREAM_TYPE_VBI:
size = read_dec(itv->vbi.dec_start + 4) + 8;
offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
- s->dma_pts = 0;
+ s->pending_pts = 0;
offset += IVTV_DECODER_OFFSET;
break;
default:
@@ -165,17 +158,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
}
/* if this is the start of the DMA then fill in the magic cookie */
- if (s->SG_length == 0) {
+ if (s->sg_pending_size == 0 && ivtv_use_dma(s)) {
if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
- s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET);
+ s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
}
else {
- s->dma_backup = read_enc(offset);
+ s->pending_backup = read_enc(offset);
write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
}
- s->dma_offset = offset;
+ s->pending_offset = offset;
}
bytes_needed = size;
@@ -187,7 +180,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
bytes_needed += UVsize;
}
- IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+ IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
@@ -202,18 +195,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
}
s->buffers_stolen = rc;
- /* got the buffers, now fill in SGarray (DMA) */
+ /* got the buffers, now fill in sg_pending */
buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
memset(buf->buf, 0, 128);
- list_for_each(p, &s->q_predma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-
+ list_for_each_entry(buf, &s->q_predma.list, list) {
if (skip_bufs-- > 0)
continue;
- s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle);
- s->SGarray[idx].src = cpu_to_le32(offset);
- s->SGarray[idx].size = cpu_to_le32(s->buf_size);
+ s->sg_pending[idx].dst = buf->dma_handle;
+ s->sg_pending[idx].src = offset;
+ s->sg_pending[idx].size = s->buf_size;
buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
+ buf->dma_xfer_cnt = s->dma_xfer_cnt;
s->q_predma.bytesused += buf->bytesused;
size -= buf->bytesused;
@@ -229,7 +221,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
}
idx++;
}
- s->SG_length = idx;
+ s->sg_pending_size = idx;
return 0;
}
@@ -242,7 +234,7 @@ static void dma_post(struct ivtv_stream *s)
u32 *u32buf;
int x = 0;
- IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+ IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
s->name, s->dma_offset);
list_for_each(p, &s->q_dma.list) {
buf = list_entry(p, struct ivtv_buffer, list);
@@ -251,7 +243,7 @@ static void dma_post(struct ivtv_stream *s)
/* Sync Buffer */
ivtv_buf_sync_for_cpu(s, buf);
- if (x == 0) {
+ if (x == 0 && ivtv_use_dma(s)) {
offset = s->dma_last_offset;
if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
{
@@ -286,14 +278,12 @@ static void dma_post(struct ivtv_stream *s)
/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
s->type == IVTV_ENC_STREAM_TYPE_VBI)
- set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
}
if (buf)
buf->bytesused += s->dma_last_offset;
if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
- list_for_each(p, &s->q_dma.list) {
- buf = list_entry(p, struct ivtv_buffer, list);
-
+ list_for_each_entry(buf, &s->q_dma.list, list) {
/* Parse and Groom VBI Data */
s->q_dma.bytesused -= buf->bytesused;
ivtv_process_vbi_data(itv, buf, 0, s->type);
@@ -313,7 +303,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
{
struct ivtv *itv = s->itv;
struct ivtv_buffer *buf;
- struct list_head *p;
u32 y_size = itv->params.height * itv->params.width;
u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
int y_done = 0;
@@ -321,19 +310,16 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
unsigned long flags = 0;
int idx = 0;
- IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
- buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
- list_for_each(p, &s->q_predma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-
+ IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+ list_for_each_entry(buf, &s->q_predma.list, list) {
/* YUV UV Offset from Y Buffer */
if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
offset = uv_offset;
y_done = 1;
}
- s->SGarray[idx].src = cpu_to_le32(buf->dma_handle);
- s->SGarray[idx].dst = cpu_to_le32(offset);
- s->SGarray[idx].size = cpu_to_le32(buf->bytesused);
+ s->sg_pending[idx].src = buf->dma_handle;
+ s->sg_pending[idx].dst = offset;
+ s->sg_pending[idx].size = buf->bytesused;
offset += buf->bytesused;
bytes_written += buf->bytesused;
@@ -342,10 +328,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
ivtv_buf_sync_for_device(s, buf);
idx++;
}
- s->SG_length = idx;
-
- /* Mark last buffer size for Interrupt flag */
- s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+ s->sg_pending_size = idx;
/* Sync Hardware SG List of buffers */
ivtv_stream_sync_for_device(s);
@@ -361,6 +344,34 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
}
+static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+
+ s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+ s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+ s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+ s->sg_processed++;
+ /* Sync Hardware SG List of buffers */
+ 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);
+}
+
+static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+
+ s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+ s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+ s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+ s->sg_processed++;
+ /* Sync Hardware SG List of buffers */
+ 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);
+}
+
/* start the encoder DMA */
static void ivtv_dma_enc_start(struct ivtv_stream *s)
{
@@ -368,14 +379,13 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
int i;
- IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+ IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
if (ivtv_use_dma(s))
- s->SGarray[s->SG_length - 1].size =
- cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256);
+ s->sg_pending[s->sg_pending_size - 1].size += 256;
/* If this is an MPEG stream, and VBI data is also pending, then append the
VBI DMA to the MPEG DMA and transfer both sets of data at once.
@@ -386,41 +396,42 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
sure we only use the MPEG DMA to transfer the VBI DMA if both are in
use. This way no conflicts occur. */
clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length &&
- s->SG_length + s_vbi->SG_length <= s->buffers) {
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
+ s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
if (ivtv_use_dma(s_vbi))
- s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256);
- for (i = 0; i < s_vbi->SG_length; i++) {
- s->SGarray[s->SG_length++] = s_vbi->SGarray[i];
+ s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
+ for (i = 0; i < s_vbi->sg_pending_size; i++) {
+ s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
}
- itv->vbi.dma_offset = s_vbi->dma_offset;
- s_vbi->SG_length = 0;
+ s_vbi->dma_offset = s_vbi->pending_offset;
+ s_vbi->sg_pending_size = 0;
+ s_vbi->dma_xfer_cnt++;
set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
- IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
}
- /* Mark last buffer size for Interrupt flag */
- s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+ s->dma_xfer_cnt++;
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ s->sg_processing_size = s->sg_pending_size;
+ s->sg_pending_size = 0;
+ s->sg_processed = 0;
+ s->dma_offset = s->pending_offset;
+ s->dma_backup = s->pending_backup;
+ s->dma_pts = s->pending_pts;
if (ivtv_use_pio(s)) {
- for (i = 0; i < s->SG_length; i++) {
- s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
- s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size);
- }
set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
set_bit(IVTV_F_I_PIO, &itv->i_flags);
itv->cur_pio_stream = s->type;
}
else {
- /* Sync Hardware SG List of buffers */
- 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_retries = 0;
+ ivtv_dma_enc_start_xfer(s);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + HZ / 10;
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&itv->dma_timer);
}
}
@@ -431,13 +442,18 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
- IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
- /* put SG Handle into register 0x0c */
- write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
- write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+ s->dma_xfer_cnt++;
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ s->sg_processing_size = s->sg_pending_size;
+ s->sg_pending_size = 0;
+ s->sg_processed = 0;
+
+ IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
+ itv->dma_retries = 0;
+ ivtv_dma_dec_start_xfer(s);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + HZ / 10;
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&itv->dma_timer);
}
@@ -445,26 +461,43 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
{
struct ivtv_stream *s = NULL;
struct ivtv_buffer *buf;
- int hw_stream_type;
+ int hw_stream_type = 0;
- IVTV_DEBUG_IRQ("DEC DMA READ\n");
- del_timer(&itv->dma_timer);
- if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
- IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
- write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+ IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
+ if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) {
+ del_timer(&itv->dma_timer);
+ return;
}
+
if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
- if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
- s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
- hw_stream_type = 2;
+ s = &itv->streams[itv->cur_dma_stream];
+ ivtv_stream_sync_for_cpu(s);
+
+ if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
+ IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
+ read_reg(IVTV_REG_DMASTATUS),
+ s->sg_processed, s->sg_processing_size, itv->dma_retries);
+ write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+ if (itv->dma_retries == 3) {
+ /* Too many retries, give up on this frame */
+ itv->dma_retries = 0;
+ s->sg_processed = s->sg_processing_size;
+ }
+ else {
+ /* Retry, starting with the first xfer segment.
+ Just retrying the current segment is not sufficient. */
+ s->sg_processed = 0;
+ itv->dma_retries++;
+ }
}
- else {
- s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
- hw_stream_type = 0;
+ if (s->sg_processed < s->sg_processing_size) {
+ /* DMA next buffer */
+ ivtv_dma_dec_start_xfer(s);
+ return;
}
- IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
-
- ivtv_stream_sync_for_cpu(s);
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+ hw_stream_type = 2;
+ IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
/* For some reason must kick the firmware, like PIO mode,
I think this tells the firmware we are done and the size
@@ -482,6 +515,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
}
wake_up(&s->waitq);
}
+ del_timer(&itv->dma_timer);
clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
@@ -493,33 +527,46 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
- del_timer(&itv->dma_timer);
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
- IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
- if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
- data[1] = 3;
- else if (data[1] > 2)
+ IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
+ if (itv->cur_dma_stream < 0) {
+ del_timer(&itv->dma_timer);
return;
- s = &itv->streams[ivtv_stream_map[data[1]]];
+ }
+ s = &itv->streams[itv->cur_dma_stream];
+ ivtv_stream_sync_for_cpu(s);
+
if (data[0] & 0x18) {
- IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]);
+ IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
+ s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
- ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]);
+ if (itv->dma_retries == 3) {
+ /* Too many retries, give up on this frame */
+ itv->dma_retries = 0;
+ s->sg_processed = s->sg_processing_size;
+ }
+ else {
+ /* Retry, starting with the first xfer segment.
+ Just retrying the current segment is not sufficient. */
+ s->sg_processed = 0;
+ itv->dma_retries++;
+ }
+ }
+ if (s->sg_processed < s->sg_processing_size) {
+ /* DMA next buffer */
+ ivtv_dma_enc_start_xfer(s);
+ return;
}
- s->SG_length = 0;
+ del_timer(&itv->dma_timer);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
dma_post(s);
- ivtv_stream_sync_for_cpu(s);
if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
- u32 tmp;
-
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- tmp = s->dma_offset;
- s->dma_offset = itv->vbi.dma_offset;
dma_post(s);
- s->dma_offset = tmp;
}
+ s->sg_processing_size = 0;
+ s->sg_processed = 0;
wake_up(&itv->dma_waitq);
}
@@ -532,9 +579,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
return;
}
s = &itv->streams[itv->cur_pio_stream];
- IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
- s->SG_length = 0;
- clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+ IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
clear_bit(IVTV_F_I_PIO, &itv->i_flags);
itv->cur_pio_stream = -1;
dma_post(s);
@@ -546,13 +591,8 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
clear_bit(IVTV_F_I_PIO, &itv->i_flags);
if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
- u32 tmp;
-
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- tmp = s->dma_offset;
- s->dma_offset = itv->vbi.dma_offset;
dma_post(s);
- s->dma_offset = tmp;
}
wake_up(&itv->dma_waitq);
}
@@ -564,19 +604,23 @@ static void ivtv_irq_dma_err(struct ivtv *itv)
del_timer(&itv->dma_timer);
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
- read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+ read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+ write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
/* retry */
- write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
ivtv_dma_dec_start(s);
else
ivtv_dma_enc_start(s);
return;
}
+ if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+ ivtv_udma_start(itv);
+ return;
+ }
clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
@@ -590,14 +634,13 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
/* Get DMA destination and size arguments from card */
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
- IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+ IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
data[0], data[1], data[2]);
return;
}
- clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
s = &itv->streams[ivtv_stream_map[data[0]]];
if (!stream_enc_dma_append(s, data)) {
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -610,7 +653,7 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
- IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+ IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
/* If more than two VBI buffers are pending, then
@@ -621,20 +664,17 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
DMA the data. Since at most four VBI DMA buffers are available,
we just drop the old requests when there are already three
requests queued. */
- if (s->SG_length > 2) {
- struct list_head *p;
- list_for_each(p, &s->q_predma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
+ if (s->sg_pending_size > 2) {
+ struct ivtv_buffer *buf;
+ list_for_each_entry(buf, &s->q_predma.list, list)
ivtv_buf_sync_for_cpu(s, buf);
- }
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
- s->SG_length = 0;
+ s->sg_pending_size = 0;
}
/* if we can append the data, and the MPEG stream isn't capturing,
then start a DMA request for just the VBI data. */
if (!stream_enc_dma_append(s, data) &&
!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
- set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
}
}
@@ -644,7 +684,7 @@ static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
- IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+ IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
!stream_enc_dma_append(s, data)) {
set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
@@ -669,7 +709,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
itv->dma_data_req_offset = data[1];
s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
}
- IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+ IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
itv->dma_data_req_offset, itv->dma_data_req_size);
if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
@@ -695,23 +735,27 @@ static void ivtv_irq_vsync(struct ivtv *itv)
if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
- if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) ||
- (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) {
+ if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
+ ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
+ (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
int next_dma_frame = last_dma_frame;
- if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
- write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
- write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
- write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
- write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
- next_dma_frame = (next_dma_frame + 1) & 0x3;
- atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+ if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
+ if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+ write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+ write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+ write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+ write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+ next_dma_frame = (next_dma_frame + 1) & 0x3;
+ atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+ itv->yuv_info.fields_lapsed = -1;
+ }
}
}
- if (frame != (itv->lastVsyncFrame & 1)) {
+ if (frame != (itv->last_vsync_field & 1)) {
struct ivtv_stream *s = ivtv_get_output_stream(itv);
- itv->lastVsyncFrame += 1;
+ itv->last_vsync_field += 1;
if (frame == 0) {
clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
@@ -728,7 +772,10 @@ static void ivtv_irq_vsync(struct ivtv *itv)
wake_up(&s->waitq);
/* Send VBI to saa7127 */
- if (frame) {
+ if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
+ test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
+ test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
+ test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
}
@@ -746,10 +793,12 @@ static void ivtv_irq_vsync(struct ivtv *itv)
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
}
}
+
+ itv->yuv_info.fields_lapsed ++;
}
}
-#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ)
+#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT)
irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
{
@@ -774,7 +823,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
*/
if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
/* vsync is enabled, see if we're in a new field */
- if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) {
+ if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) {
/* New field, looks like we missed it */
IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16);
vsync_force = 1;
@@ -791,10 +840,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
/* Exclude interrupts noted below from the output, otherwise the log is flooded with
these messages */
if (combo & ~0xff6d0400)
- IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+ IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
- IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+ IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
}
if (combo & IVTV_IRQ_DMA_READ) {
@@ -828,7 +877,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
if (combo & IVTV_IRQ_ENC_EOS) {
IVTV_DEBUG_IRQ("ENC EOS\n");
set_bit(IVTV_F_I_EOS, &itv->i_flags);
- wake_up(&itv->cap_w);
+ wake_up(&itv->eos_waitq);
}
if (combo & IVTV_IRQ_DEC_DATA_REQ) {
@@ -850,8 +899,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+ itv->irq_rr_idx++;
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
- int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+ int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
struct ivtv_stream *s = &itv->streams[idx];
if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
@@ -868,8 +918,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
+ itv->irq_rr_idx++;
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
- int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+ int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
struct ivtv_stream *s = &itv->streams[idx];
if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
@@ -880,8 +931,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
}
- if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags))
+ if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
queue_work(itv->irq_work_queues, &itv->irq_work_queue);
+ }
spin_unlock(&itv->dma_reg_lock);
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
index a43348a30309..f879a5822e71 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -19,8 +19,35 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_IRQ_H
+#define IVTV_IRQ_H
+
+#define IVTV_IRQ_ENC_START_CAP (0x1 << 31)
+#define IVTV_IRQ_ENC_EOS (0x1 << 30)
+#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29)
+#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28)
+#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27)
+#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25)
+#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24)
+#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22)
+#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20)
+#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19)
+#define IVTV_IRQ_DMA_ERR (0x1 << 18)
+#define IVTV_IRQ_DMA_WRITE (0x1 << 17)
+#define IVTV_IRQ_DMA_READ (0x1 << 16)
+#define IVTV_IRQ_DEC_VSYNC (0x1 << 10)
+
+/* IRQ Masks */
+#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
+ IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
+
+#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
+#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
+
irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
void ivtv_irq_work_handler(struct work_struct *work);
void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
void ivtv_unfinished_dma(unsigned long arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 6ae42a3b03cc..b05436da7136 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -37,8 +37,10 @@
#define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */
#define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */
#define API_DMA (1 << 3) /* DMA mailbox, has special handling */
+#define API_HIGH_VOL (1 << 5) /* High volume command (i.e. called during encoding or decoding) */
#define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */
#define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */
+#define API_NO_POLL (1 << 6) /* Avoid pointless polling */
struct ivtv_api_info {
int flags; /* Flags, see above */
@@ -50,7 +52,7 @@ struct ivtv_api_info {
static const struct ivtv_api_info api_info[256] = {
/* MPEG encoder API */
API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT),
- API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT),
+ API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT | API_NO_POLL),
API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE),
API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE),
@@ -77,11 +79,11 @@ static const struct ivtv_api_info api_info[256] = {
API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE),
API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT),
API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT),
- API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA),
+ API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA | API_HIGH_VOL),
API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE),
API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT),
- API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB),
+ API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB | API_HIGH_VOL),
API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE),
API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE),
@@ -95,14 +97,14 @@ static const struct ivtv_api_info api_info[256] = {
/* MPEG decoder API */
API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT),
- API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT),
+ API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT | API_NO_POLL),
API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT),
API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT),
API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT),
API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE),
API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT),
API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT),
- API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA),
+ API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA | API_HIGH_VOL),
API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT),
API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT),
API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE),
@@ -175,9 +177,9 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
/* Sleep before a retry, if not atomic */
if (!(flags & API_NO_WAIT_MB)) {
- if (jiffies - then > retries * HZ / 100)
+ if (jiffies - then > msecs_to_jiffies(10*retries))
break;
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
}
}
return -ENODEV;
@@ -212,7 +214,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
{
struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
volatile struct ivtv_mailbox __iomem *mbox;
- int api_timeout = HZ;
+ int api_timeout = msecs_to_jiffies(1000);
int flags, mb, i;
unsigned long then;
@@ -223,11 +225,16 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
- IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args);
+ IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args);
return -EINVAL;
}
- IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+ if (api_info[cmd].flags & API_HIGH_VOL) {
+ IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name);
+ }
+ else {
+ IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name);
+ }
/* clear possibly uninitialized part of data array */
for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +244,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
data, then just return 0 as there is no need to issue this command again.
Just an optimization to prevent unnecessary use of mailboxes. */
if (itv->api_cache[cmd].last_jiffies &&
- jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+ jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
!memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
itv->api_cache[cmd].last_jiffies = jiffies;
return 0;
@@ -262,7 +269,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
- api_timeout = HZ / 10;
+ api_timeout = msecs_to_jiffies(100);
mb = get_mailbox(itv, mbdata, flags);
if (mb < 0) {
@@ -284,6 +291,13 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
/* Get results */
then = jiffies;
+ if (!(flags & API_NO_POLL)) {
+ /* First try to poll, then switch to delays */
+ for (i = 0; i < 100; i++) {
+ if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)
+ break;
+ }
+ }
while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
if (jiffies - then > api_timeout) {
IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
@@ -295,11 +309,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
if (flags & API_NO_WAIT_RES)
mdelay(1);
else
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(1, 0);
}
- if (jiffies - then > HZ / 10)
- IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
- api_info[cmd].name, jiffies - then, HZ);
+ if (jiffies - then > msecs_to_jiffies(100))
+ IVTV_DEBUG_WARN("%s took %u jiffies\n",
+ api_info[cmd].name,
+ jiffies_to_msecs(jiffies - then));
for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
data[i] = readl(&mbox->data[i]);
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 79b8aec14370..71a54eef8fc7 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -18,8 +18,16 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_MAILBOX_H
+#define IVTV_MAILBOX_H
+
+#define IVTV_MBOX_DMA_END 8
+#define IVTV_MBOX_DMA 9
+
void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index a04f9387f63d..39a216713244 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -20,9 +20,7 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-streams.h"
#include "ivtv-queue.h"
-#include "ivtv-mailbox.h"
int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
{
@@ -60,6 +58,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu
buf->bytesused = 0;
buf->readpos = 0;
buf->b_flags = 0;
+ buf->dma_xfer_cnt = 0;
}
spin_lock_irqsave(&s->qlock, flags);
list_add_tail(&buf->list, &q->list);
@@ -87,7 +86,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
}
static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
- struct ivtv_queue *to, int clear, int full)
+ struct ivtv_queue *to, int clear)
{
struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
@@ -97,13 +96,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
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;
- }
+ buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
to->buffers++;
to->length += s->buf_size;
to->bytesused += buf->bytesused - buf->readpos;
@@ -112,7 +105,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
/* 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.
+ needed, but only if 'from' is the free queue.
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
@@ -133,7 +126,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
int rc = 0;
int from_free = from == &s->q_free;
int to_free = to == &s->q_free;
- int bytes_available;
+ int bytes_available, bytes_steal;
spin_lock_irqsave(&s->qlock, flags);
if (needed_bytes == 0) {
@@ -142,32 +135,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
}
bytes_available = from_free ? from->length : from->bytesused;
- bytes_available += steal ? steal->length : 0;
+ bytes_steal = (from_free && steal) ? steal->length : 0;
- if (bytes_available < needed_bytes) {
+ if (bytes_available + bytes_steal < needed_bytes) {
spin_unlock_irqrestore(&s->qlock, flags);
return -ENOMEM;
}
+ while (bytes_available < needed_bytes) {
+ struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+ u16 dma_xfer_cnt = buf->dma_xfer_cnt;
+
+ /* move buffers from the tail of the 'steal' queue to the tail of the
+ 'from' queue. Always copy all the buffers with the same dma_xfer_cnt
+ value, this ensures that you do not end up with partial frame data
+ if one frame is stored in multiple buffers. */
+ while (dma_xfer_cnt == buf->dma_xfer_cnt) {
+ list_move_tail(steal->list.prev, &from->list);
+ rc++;
+ steal->buffers--;
+ steal->length -= s->buf_size;
+ steal->bytesused -= buf->bytesused - buf->readpos;
+ buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
+ from->buffers++;
+ from->length += s->buf_size;
+ bytes_available += s->buf_size;
+ if (list_empty(&steal->list))
+ break;
+ buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+ }
+ }
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 */
- ivtv_queue_move_buf(s, from, to, 1, 0);
+ ivtv_queue_move_buf(s, from, to, 1);
}
}
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 */
- ivtv_queue_move_buf(s, from, to, to_free, rc);
+ ivtv_queue_move_buf(s, from, to, to_free);
}
}
spin_unlock_irqrestore(&s->qlock, flags);
@@ -185,7 +193,7 @@ void ivtv_flush_queues(struct ivtv_stream *s)
int ivtv_stream_alloc(struct ivtv_stream *s)
{
struct ivtv *itv = s->itv;
- int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
+ int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
int i;
if (s->buffers == 0)
@@ -195,27 +203,33 @@ 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);
- if (ivtv_might_use_pio(s)) {
- s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
- if (s->PIOarray == NULL) {
- IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name);
- return -ENOMEM;
- }
+ s->sg_pending = kzalloc(SGsize, GFP_KERNEL);
+ 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;
- /* Allocate DMA SG Arrays */
- s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
- if (s->SGarray == NULL) {
- IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
- if (ivtv_might_use_pio(s)) {
- kfree(s->PIOarray);
- s->PIOarray = NULL;
- }
+ s->sg_processing = kzalloc(SGsize, GFP_KERNEL);
+ if (s->sg_processing == NULL) {
+ IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
+ kfree(s->sg_pending);
+ s->sg_pending = NULL;
+ return -ENOMEM;
+ }
+ s->sg_processing_size = 0;
+
+ s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
+ if (s->sg_dma == NULL) {
+ IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
+ kfree(s->sg_pending);
+ s->sg_pending = NULL;
+ kfree(s->sg_processing);
+ s->sg_processing = NULL;
return -ENOMEM;
}
- s->SG_length = 0;
if (ivtv_might_use_dma(s)) {
- s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
+ s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
ivtv_stream_sync_for_cpu(s);
}
@@ -262,16 +276,19 @@ void ivtv_stream_free(struct ivtv_stream *s)
}
/* Free SG Array/Lists */
- if (s->SGarray != NULL) {
- if (s->SG_handle != IVTV_DMA_UNMAPPED) {
- pci_unmap_single(s->itv->dev, s->SG_handle,
- sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
- s->SG_handle = IVTV_DMA_UNMAPPED;
+ if (s->sg_dma != NULL) {
+ if (s->sg_handle != IVTV_DMA_UNMAPPED) {
+ pci_unmap_single(s->itv->dev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+ s->sg_handle = IVTV_DMA_UNMAPPED;
}
- kfree(s->SGarray);
- kfree(s->PIOarray);
- s->PIOarray = NULL;
- s->SGarray = NULL;
- s->SG_length = 0;
+ kfree(s->sg_pending);
+ kfree(s->sg_processing);
+ kfree(s->sg_dma);
+ s->sg_pending = NULL;
+ s->sg_processing = NULL;
+ s->sg_dma = NULL;
+ s->sg_pending_size = 0;
+ s->sg_processing_size = 0;
}
}
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
index 2ed8d548255d..7cfc0c9ab050 100644
--- a/drivers/media/video/ivtv/ivtv-queue.h
+++ b/drivers/media/video/ivtv/ivtv-queue.h
@@ -19,6 +19,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_QUEUE_H
+#define IVTV_QUEUE_H
+
#define IVTV_DMA_UNMAPPED ((u32) -1)
#define SLICED_VBI_PIO 1
@@ -79,13 +82,15 @@ void ivtv_stream_free(struct ivtv_stream *s);
static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle,
- sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
}
static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle,
- sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
}
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-routing.c
index 5858b197d510..398bd33033ed 100644
--- a/drivers/media/video/ivtv/ivtv-video.c
+++ b/drivers/media/video/ivtv/ivtv-routing.c
@@ -1,6 +1,7 @@
/*
- saa7127 interface functions
- Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl>
+ Audio/video-routing-related ivtv functions.
+ Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
+ Copyright (C) 2005-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
@@ -18,73 +19,46 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-video.h"
#include "ivtv-i2c.h"
-#include "ivtv-gpio.h"
#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "ivtv-routing.h"
+
+#include <media/msp3400.h>
#include <media/upd64031a.h>
#include <media/upd64083.h>
-void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
- u8 vps4, u8 vps5)
+/* Selects the audio input and output according to the current
+ settings. */
+void ivtv_audio_set_io(struct ivtv *itv)
{
- struct v4l2_sliced_vbi_data data;
-
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return;
- data.id = V4L2_SLICED_VPS;
- data.field = 0;
- data.line = enabled ? 16 : 0;
- data.data[4] = vps1;
- data.data[10] = vps2;
- data.data[11] = vps3;
- data.data[12] = vps4;
- data.data[13] = vps5;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
+ struct v4l2_routing route;
+ u32 audio_input;
+ int mux_input;
-void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4)
-{
- struct v4l2_sliced_vbi_data data;
-
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return;
- data.id = V4L2_SLICED_CAPTION_525;
- data.field = 0;
- data.line = (mode & 1) ? 21 : 0;
- data.data[0] = cc1;
- data.data[1] = cc2;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
- data.field = 1;
- data.line = (mode & 2) ? 21 : 0;
- data.data[0] = cc3;
- data.data[1] = cc4;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
+ /* Determine which input to use */
+ if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ audio_input = itv->card->radio_input.audio_input;
+ mux_input = itv->card->radio_input.muxer_input;
+ } else {
+ audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
+ mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
+ }
-void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
-{
- struct v4l2_sliced_vbi_data data;
-
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return;
- /* When using a 50 Hz system, always turn on the
- wide screen signal with 4x3 ratio as the default.
- Turning this signal on and off can confuse certain
- TVs. As far as I can tell there is no reason not to
- transmit this signal. */
- if ((itv->std & V4L2_STD_625_50) && !enabled) {
- enabled = 1;
- mode = 0x08; /* 4x3 full format */
+ /* handle muxer chips */
+ route.input = mux_input;
+ route.output = 0;
+ ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+ route.input = audio_input;
+ if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
+ route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
}
- data.id = V4L2_SLICED_WSS_625;
- data.field = 0;
- data.line = enabled ? 23 : 0;
- data.data[0] = mode & 0xff;
- data.data[1] = (mode >> 8) & 0xff;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
}
+/* Selects the video input and output according to the current
+ settings. */
void ivtv_video_set_io(struct ivtv *itv)
{
struct v4l2_routing route;
diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-routing.h
index 9c42846d8124..c72a9731ca01 100644
--- a/drivers/media/video/ivtv/ivtv-audio.h
+++ b/drivers/media/video/ivtv/ivtv-routing.h
@@ -1,5 +1,5 @@
/*
- Audio-related ivtv functions.
+ Audio/video-routing-related ivtv functions.
Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
@@ -18,6 +18,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-int ivtv_audio_set_io(struct ivtv *itv);
-void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route);
-void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq);
+#ifndef IVTV_ROUTING_H
+#define IVTV_ROUTING_H
+
+void ivtv_audio_set_io(struct ivtv *itv);
+void ivtv_video_set_io(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 6af88ae9295f..fd135985e70f 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -35,16 +35,13 @@
#include "ivtv-driver.h"
#include "ivtv-fileops.h"
-#include "ivtv-i2c.h"
#include "ivtv-queue.h"
#include "ivtv-mailbox.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
-#include "ivtv-vbi.h"
#include "ivtv-ioctl.h"
#include "ivtv-irq.h"
-#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
#include "ivtv-cards.h"
+#include "ivtv-streams.h"
static struct file_operations ivtv_v4l2_enc_fops = {
.owner = THIS_MODULE,
@@ -66,6 +63,13 @@ static struct file_operations ivtv_v4l2_dec_fops = {
.poll = ivtv_v4l2_dec_poll,
};
+#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
+#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */
+#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */
+#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */
+
static struct {
const char *name;
int vfl_type;
@@ -75,7 +79,7 @@ static struct {
struct file_operations *fops;
} ivtv_stream_info[] = {
{ /* IVTV_ENC_STREAM_TYPE_MPG */
- "encoder MPEG",
+ "encoder MPG",
VFL_TYPE_GRABBER, 0,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
&ivtv_v4l2_enc_fops
@@ -93,7 +97,7 @@ static struct {
&ivtv_v4l2_enc_fops
},
{ /* IVTV_ENC_STREAM_TYPE_PCM */
- "encoder PCM audio",
+ "encoder PCM",
VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
&ivtv_v4l2_enc_fops
@@ -105,7 +109,7 @@ static struct {
&ivtv_v4l2_enc_fops
},
{ /* IVTV_DEC_STREAM_TYPE_MPG */
- "decoder MPEG",
+ "decoder MPG",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
&ivtv_v4l2_dec_fops
@@ -150,11 +154,11 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
s->dma = ivtv_stream_info[type].dma;
s->buf_size = itv->stream_buf_size[type];
if (s->buf_size)
- s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size;
+ s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
spin_lock_init(&s->qlock);
init_waitqueue_head(&s->waitq);
s->id = -1;
- s->SG_handle = IVTV_DMA_UNMAPPED;
+ s->sg_handle = IVTV_DMA_UNMAPPED;
ivtv_queue_init(&s->q_free);
ivtv_queue_init(&s->q_full);
ivtv_queue_init(&s->q_dma);
@@ -192,7 +196,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
/* User explicitly selected 0 buffers for these streams, so don't
create them. */
if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE &&
- itv->options.megabytes[type] == 0) {
+ itv->options.kilobytes[type] == 0) {
IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
return 0;
}
@@ -238,18 +242,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
switch (vfl_type) {
case VFL_TYPE_GRABBER:
- IVTV_INFO("Registered device video%d for %s (%d MB)\n",
- s->v4l2dev->minor, s->name, itv->options.megabytes[type]);
+ IVTV_INFO("Registered device video%d for %s (%d kB)\n",
+ s->v4l2dev->minor, s->name, itv->options.kilobytes[type]);
break;
case VFL_TYPE_RADIO:
IVTV_INFO("Registered device radio%d for %s\n",
s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
break;
case VFL_TYPE_VBI:
- if (itv->options.megabytes[type])
- IVTV_INFO("Registered device vbi%d for %s (%d MB)\n",
+ if (itv->options.kilobytes[type])
+ IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",
s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,
- s->name, itv->options.megabytes[type]);
+ s->name, itv->options.kilobytes[type]);
else
IVTV_INFO("Registered device vbi%d for %s\n",
s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
@@ -314,28 +318,9 @@ static void ivtv_vbi_setup(struct ivtv *itv)
int lines;
int i;
- /* If Embed then streamtype must be Program */
- /* TODO: should we really do this? */
- if (0 && !raw && itv->vbi.insert_mpeg) {
- itv->params.stream_type = 0;
-
- /* assign stream type */
- ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type);
- }
-
/* Reset VBI */
ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
- if (itv->is_60hz) {
- itv->vbi.count = 12;
- itv->vbi.start[0] = 10;
- itv->vbi.start[1] = 273;
- } else { /* PAL/SECAM */
- itv->vbi.count = 18;
- itv->vbi.start[0] = 6;
- itv->vbi.start[1] = 318;
- }
-
/* setup VBI registers */
itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
@@ -409,8 +394,8 @@ static void ivtv_vbi_setup(struct ivtv *itv)
if (!itv->vbi.fpi)
itv->vbi.fpi = 1;
- IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n",
- itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer);
+ IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
+ itv->vbi.enc_start, data[1], itv->vbi.fpi);
/* select VBI lines.
Note that the sliced argument seems to have no effect. */
@@ -499,6 +484,8 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
if (atomic_read(&itv->capturing) == 0) {
+ int digitizer;
+
/* Always use frame based mode. Experiments have demonstrated that byte
stream based mode results in dropped frames and corruption. Not often,
but occasionally. Many thanks go to Leonard Orb who spent a lot of
@@ -524,7 +511,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer);
+ if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
+ digitizer = 0xF1;
+ else if (itv->card->hw_all & IVTV_HW_SAA7114)
+ digitizer = 0xEF;
+ else /* cx25840 */
+ digitizer = 0x140;
+
+ ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
/* Setup VBI */
if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
@@ -559,9 +553,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */
+ itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+ ivtv_msleep_timeout(300, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_sleep_timeout(HZ / 10, 0);
+ itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
}
/* begin_capture */
@@ -597,10 +592,6 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
- /* disable VBI signals, if the MPEG stream contains VBI data,
- then that data will be processed automatically for you. */
- ivtv_disable_vbi(itv);
-
/* set audio mode to left/stereo for dual/stereo mode. */
ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
@@ -633,7 +624,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
}
if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
itv->params.width, itv->params.height, itv->params.audio_properties)) {
- IVTV_DEBUG_WARN("COULDN'T INITIALIZE DECODER SOURCE\n");
+ IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
}
return 0;
}
@@ -674,10 +665,10 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
/* Zero out decoder counters */
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
@@ -718,9 +709,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
struct ivtv *itv = s->itv;
DECLARE_WAITQUEUE(wait, current);
int cap_type;
- unsigned long then;
int stopmode;
- u32 data[CX2341X_MBOX_MAX_DATA];
if (s->v4l2dev == NULL)
return -EINVAL;
@@ -762,32 +751,20 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
- /* only run these if we're shutting down the last cap */
- if (atomic_read(&itv->capturing) - 1 == 0) {
- /* event notification (off) */
- if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
- /* type: 0 = refresh */
- /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
- ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
- ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
- }
- }
-
- then = jiffies;
-
if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
/* only run these if we're shutting down the last cap */
unsigned long duration;
+ unsigned long then = jiffies;
- then = jiffies;
- add_wait_queue(&itv->cap_w, &wait);
+ add_wait_queue(&itv->eos_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/* wait 2s for EOS interrupt */
- while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
- schedule_timeout(HZ / 100);
+ while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+ jiffies < then + msecs_to_jiffies (2000)) {
+ schedule_timeout(msecs_to_jiffies(10));
}
/* To convert jiffies to ms, we must multiply by 1000
@@ -806,33 +783,12 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&itv->cap_w, &wait);
+ remove_wait_queue(&itv->eos_waitq, &wait);
+ set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
}
- then = jiffies;
- /* Make sure DMA is complete */
- add_wait_queue(&s->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- do {
- /* check if DMA is pending */
- if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
- (read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
- /* Check for last DMA */
- ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
-
- if (data[0] == 1) {
- IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
- break;
- }
- } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
- break;
- }
-
- ivtv_sleep_timeout(HZ / 100, 1);
- } while (then + HZ * 2 > jiffies);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->waitq, &wait);
+ /* Handle any pending interrupts */
+ ivtv_msleep_timeout(100, 1);
}
atomic_dec(&itv->capturing);
@@ -849,6 +805,15 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+ del_timer(&itv->dma_timer);
+
+ /* event notification (off) */
+ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+ /* type: 0 = refresh */
+ /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+ ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+ ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+ }
wake_up(&s->waitq);
@@ -887,7 +852,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
break;
tmp = data[3];
}
- if (ivtv_sleep_timeout(HZ/10, 1))
+ if (ivtv_msleep_timeout(100, 1))
break;
}
}
@@ -897,16 +862,12 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+ del_timer(&itv->dma_timer);
clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
ivtv_flush_queues(s);
- if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
- /* disable VBI on TV-out */
- ivtv_disable_vbi(itv);
- }
-
/* decrement decoding */
atomic_dec(&itv->decoding);
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
index 8597b75384a7..8f5f5b1c7c89 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_STREAMS_H
+#define IVTV_STREAMS_H
+
int ivtv_streams_setup(struct ivtv *itv);
void ivtv_streams_cleanup(struct ivtv *itv);
@@ -29,3 +32,5 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts);
void ivtv_stop_all_captures(struct ivtv *itv);
int ivtv_passthrough_mode(struct ivtv *itv, int enable);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index bd642e1aafc3..c4626d1cdf41 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -21,7 +21,6 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-streams.h"
#include "ivtv-udma.h"
void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size)
@@ -38,19 +37,37 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long
int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset)
{
int i, offset;
+ unsigned long flags;
+
+ if (map_offset < 0)
+ return map_offset;
offset = dma_page->offset;
/* Fill SG Array with new values */
for (i = 0; i < dma_page->page_count; i++) {
- if (i == dma_page->page_count - 1) {
- dma->SGlist[map_offset].length = dma_page->tail;
+ unsigned int len = (i == dma_page->page_count - 1) ?
+ dma_page->tail : PAGE_SIZE - offset;
+
+ dma->SGlist[map_offset].length = len;
+ dma->SGlist[map_offset].offset = offset;
+ if (PageHighMem(dma->map[map_offset])) {
+ void *src;
+
+ if (dma->bouncemap[map_offset] == NULL)
+ dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL);
+ if (dma->bouncemap[map_offset] == NULL)
+ return -1;
+ local_irq_save(flags);
+ src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset;
+ memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
+ kunmap_atomic(src, KM_BOUNCE_READ);
+ local_irq_restore(flags);
+ dma->SGlist[map_offset].page = dma->bouncemap[map_offset];
}
else {
- dma->SGlist[map_offset].length = PAGE_SIZE - offset;
+ dma->SGlist[map_offset].page = dma->map[map_offset];
}
- dma->SGlist[map_offset].offset = offset;
- dma->SGlist[map_offset].page = dma->map[map_offset];
offset = 0;
map_offset++;
}
@@ -89,7 +106,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
{
struct ivtv_dma_page_info user_dma;
struct ivtv_user_dma *dma = &itv->udma;
- int err;
+ int i, err;
IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr);
@@ -123,7 +140,13 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
dma->page_count = user_dma.page_count;
/* Fill SG List with new values */
- ivtv_udma_fill_sg_list(dma, &user_dma, 0);
+ if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
+ for (i = 0; i < dma->page_count; i++) {
+ put_page(dma->map[i]);
+ }
+ dma->page_count = 0;
+ return -ENOMEM;
+ }
/* Map SG List */
dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
@@ -166,6 +189,8 @@ void ivtv_udma_unmap(struct ivtv *itv)
void ivtv_udma_free(struct ivtv *itv)
{
+ int i;
+
/* Unmap SG Array */
if (itv->udma.SG_handle) {
pci_unmap_single(itv->dev, itv->udma.SG_handle,
@@ -176,6 +201,11 @@ void ivtv_udma_free(struct ivtv *itv)
if (itv->udma.SG_length) {
pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
}
+
+ for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
+ if (itv->udma.bouncemap[i])
+ __free_page(itv->udma.bouncemap[i]);
+ }
}
void ivtv_udma_start(struct ivtv *itv)
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h
index e131bccedec0..df727e23be0a 100644
--- a/drivers/media/video/ivtv/ivtv-udma.h
+++ b/drivers/media/video/ivtv/ivtv-udma.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_UDMA_H
+#define IVTV_UDMA_H
+
/* User DMA functions */
void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size);
int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset);
@@ -41,3 +44,5 @@ static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
}
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 3ba46e07ea1f..c151bcf5519a 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -18,10 +18,69 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-video.h"
-#include "ivtv-vbi.h"
+#include "ivtv-i2c.h"
#include "ivtv-ioctl.h"
#include "ivtv-queue.h"
+#include "ivtv-vbi.h"
+
+static void ivtv_set_vps(struct ivtv *itv, int enabled)
+{
+ struct v4l2_sliced_vbi_data data;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return;
+ data.id = V4L2_SLICED_VPS;
+ data.field = 0;
+ data.line = enabled ? 16 : 0;
+ data.data[2] = itv->vbi.vps_payload.data[0];
+ data.data[8] = itv->vbi.vps_payload.data[1];
+ data.data[9] = itv->vbi.vps_payload.data[2];
+ data.data[10] = itv->vbi.vps_payload.data[3];
+ data.data[11] = itv->vbi.vps_payload.data[4];
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
+{
+ struct v4l2_sliced_vbi_data data;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return;
+ data.id = V4L2_SLICED_CAPTION_525;
+ data.field = 0;
+ data.line = (mode & 1) ? 21 : 0;
+ data.data[0] = cc->odd[0];
+ data.data[1] = cc->odd[1];
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ data.field = 1;
+ data.line = (mode & 2) ? 21 : 0;
+ data.data[0] = cc->even[0];
+ data.data[1] = cc->even[1];
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
+{
+ struct v4l2_sliced_vbi_data data;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return;
+ /* When using a 50 Hz system, always turn on the
+ wide screen signal with 4x3 ratio as the default.
+ Turning this signal on and off can confuse certain
+ TVs. As far as I can tell there is no reason not to
+ transmit this signal. */
+ if ((itv->std & V4L2_STD_625_50) && !enabled) {
+ enabled = 1;
+ mode = 0x08; /* 4x3 full format */
+ }
+ data.id = V4L2_SLICED_WSS_625;
+ data.field = 0;
+ data.line = enabled ? 23 : 0;
+ data.data[0] = mode & 0xff;
+ data.data[1] = (mode >> 8) & 0xff;
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
static int odd_parity(u8 c)
{
@@ -32,62 +91,50 @@ static int odd_parity(u8 c)
return c & 1;
}
-static void passthrough_vbi_data(struct ivtv *itv, int cnt)
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
{
- int wss = 0;
- u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
- u8 vps[13];
+ struct vbi_info *vi = &itv->vbi;
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
int found_cc = 0;
- int found_wss = 0;
- int found_vps = 0;
- int cc_pos = itv->vbi.cc_pos;
- int i;
+ size_t i;
for (i = 0; i < cnt; i++) {
- struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i;
+ const struct v4l2_sliced_vbi_data *d = sliced + i;
if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
- found_cc = 1;
if (d->field) {
- cc[2] = d->data[0];
- cc[3] = d->data[1];
+ cc.even[0] = d->data[0];
+ cc.even[1] = d->data[1];
} else {
- cc[0] = d->data[0];
- cc[1] = d->data[1];
+ cc.odd[0] = d->data[0];
+ cc.odd[1] = d->data[1];
}
+ found_cc = 1;
}
else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
- memcpy(vps, d->data, sizeof(vps));
- found_vps = 1;
+ struct vbi_vps vps;
+
+ vps.data[0] = d->data[2];
+ vps.data[1] = d->data[8];
+ vps.data[2] = d->data[9];
+ vps.data[3] = d->data[10];
+ vps.data[4] = d->data[11];
+ if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
+ vi->vps_payload = vps;
+ set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+ }
}
else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
- wss = d->data[0] | d->data[1] << 8;
- found_wss = 1;
- }
- }
+ int wss = d->data[0] | d->data[1] << 8;
- if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
- itv->vbi.wss = wss;
- itv->vbi.wss_found = found_wss;
- set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- }
-
- if (found_vps || itv->vbi.vps_found) {
- itv->vbi.vps[0] = vps[2];
- itv->vbi.vps[1] = vps[8];
- itv->vbi.vps[2] = vps[9];
- itv->vbi.vps[3] = vps[10];
- itv->vbi.vps[4] = vps[11];
- itv->vbi.vps_found = found_vps;
- set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+ if (vi->wss_payload != wss) {
+ vi->wss_payload = wss;
+ set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+ }
+ }
}
-
- if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
- itv->vbi.cc_data_odd[cc_pos] = cc[0];
- itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
- itv->vbi.cc_data_even[cc_pos] = cc[2];
- itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
- itv->vbi.cc_pos = cc_pos + 2;
+ if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
+ vi->cc_payload[vi->cc_payload_idx++] = cc;
set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
}
}
@@ -163,8 +210,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
linemask[1] = 0xf;
p += 4;
} else {
- /* unknown VBI data stream */
- return 0;
+ /* unknown VBI data, convert to empty VBI frame */
+ linemask[0] = linemask[1] = 0;
}
for (i = 0; i < 36; i++) {
int err = 0;
@@ -211,78 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
return line * sizeof(itv->vbi.sliced_dec_data[0]);
}
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
-{
- /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
- const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
- u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
- int found_cc = 0;
- int cc_pos = itv->vbi.cc_pos;
-
- if (itv->vbi.service_set_out == 0)
- return -EPERM;
-
- while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
- switch (p->id) {
- case V4L2_SLICED_CAPTION_525:
- if (p->id == V4L2_SLICED_CAPTION_525 &&
- p->line == 21 &&
- (itv->vbi.service_set_out &
- V4L2_SLICED_CAPTION_525) == 0) {
- break;
- }
- found_cc = 1;
- if (p->field) {
- cc[2] = p->data[0];
- cc[3] = p->data[1];
- } else {
- cc[0] = p->data[0];
- cc[1] = p->data[1];
- }
- break;
-
- case V4L2_SLICED_VPS:
- if (p->line == 16 && p->field == 0 &&
- (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
- itv->vbi.vps[0] = p->data[2];
- itv->vbi.vps[1] = p->data[8];
- itv->vbi.vps[2] = p->data[9];
- itv->vbi.vps[3] = p->data[10];
- itv->vbi.vps[4] = p->data[11];
- itv->vbi.vps_found = 1;
- set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
- }
- break;
-
- case V4L2_SLICED_WSS_625:
- if (p->line == 23 && p->field == 0 &&
- (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
- /* No lock needed for WSS */
- itv->vbi.wss = p->data[0] | (p->data[1] << 8);
- itv->vbi.wss_found = 1;
- set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- }
- break;
-
- default:
- break;
- }
- count -= sizeof(*p);
- p++;
- }
-
- if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
- itv->vbi.cc_data_odd[cc_pos] = cc[0];
- itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
- itv->vbi.cc_data_even[cc_pos] = cc[2];
- itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
- itv->vbi.cc_pos = cc_pos + 2;
- set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
- }
-
- return (const char __user *)p - ubuf;
-}
-
/* Compress raw VBI format, removes leading SAV codes and surplus space after the
field.
Returns new compressed size. */
@@ -431,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
buf->bytesused = cnt;
- passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0]));
+ ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
+ cnt / sizeof(itv->vbi.sliced_dec_data[0]));
return;
}
}
-void ivtv_disable_vbi(struct ivtv *itv)
+void ivtv_disable_cc(struct ivtv *itv)
{
- clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+
clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
- ivtv_set_wss(itv, 0, 0);
- ivtv_set_cc(itv, 0, 0, 0, 0, 0);
- ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
- itv->vbi.vps_found = itv->vbi.wss_found = 0;
- itv->vbi.wss = 0;
- itv->vbi.cc_pos = 0;
+ ivtv_set_cc(itv, 0, &cc);
+ itv->vbi.cc_payload_idx = 0;
}
void ivtv_vbi_work_handler(struct ivtv *itv)
{
+ struct vbi_info *vi = &itv->vbi;
struct v4l2_sliced_vbi_data data;
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
/* Lock */
if (itv->output_mode == OUT_PASSTHROUGH) {
- /* Note: currently only the saa7115 is used in a PVR350,
- so these commands are for now saa7115 specific. */
if (itv->is_50hz) {
data.id = V4L2_SLICED_WSS_625;
data.field = 0;
if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
ivtv_set_wss(itv, 1, data.data[0] & 0xf);
- itv->vbi.wss_no_update = 0;
- } else if (itv->vbi.wss_no_update == 4) {
+ vi->wss_missing_cnt = 0;
+ } else if (vi->wss_missing_cnt == 4) {
ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
} else {
- itv->vbi.wss_no_update++;
+ vi->wss_missing_cnt++;
}
}
else {
- u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
int mode = 0;
data.id = V4L2_SLICED_CAPTION_525;
data.field = 0;
if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
mode |= 1;
- c1 = data.data[0];
- c2 = data.data[1];
+ cc.odd[0] = data.data[0];
+ cc.odd[1] = data.data[1];
}
data.field = 1;
if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
mode |= 2;
- c3 = data.data[0];
- c4 = data.data[1];
+ cc.even[0] = data.data[0];
+ cc.even[1] = data.data[1];
}
if (mode) {
- itv->vbi.cc_no_update = 0;
- ivtv_set_cc(itv, mode, c1, c2, c3, c4);
- } else if (itv->vbi.cc_no_update == 4) {
- ivtv_set_cc(itv, 0, 0, 0, 0, 0);
+ vi->cc_missing_cnt = 0;
+ ivtv_set_cc(itv, mode, &cc);
+ } else if (vi->cc_missing_cnt == 4) {
+ ivtv_set_cc(itv, 0, &cc);
} else {
- itv->vbi.cc_no_update++;
+ vi->cc_missing_cnt++;
}
}
return;
}
if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
- /* Lock */
- ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
+ ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
}
- if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
- if (itv->vbi.cc_pos == 0) {
- ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80);
+ if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
+ if (vi->cc_payload_idx == 0) {
+ clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+ ivtv_set_cc(itv, 3, &cc);
}
- while (itv->vbi.cc_pos) {
- u8 cc_odd0 = itv->vbi.cc_data_odd[0];
- u8 cc_odd1 = itv->vbi.cc_data_odd[1];
- u8 cc_even0 = itv->vbi.cc_data_even[0];
- u8 cc_even1 = itv->vbi.cc_data_even[1];
-
- memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2);
- memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
- itv->vbi.cc_pos -= 2;
- if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
+ while (vi->cc_payload_idx) {
+ cc = vi->cc_payload[0];
+
+ memcpy(vi->cc_payload, vi->cc_payload + 1,
+ sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
+ vi->cc_payload_idx--;
+ if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
continue;
- /* Send to Saa7127 */
- ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
- if (itv->vbi.cc_pos == 0)
- set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+ ivtv_set_cc(itv, 3, &cc);
break;
}
}
if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
- /* Lock */
- ivtv_set_vps(itv, itv->vbi.vps_found,
- itv->vbi.vps[0], itv->vbi.vps[1],
- itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
+ ivtv_set_vps(itv, 1);
}
}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
index ec211b49702c..970567b9194d 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -17,10 +17,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count);
+#ifndef IVTV_VBI_H
+#define IVTV_VBI_H
+
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count);
void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
u64 pts_stamp, int streamtype);
int ivtv_used_line(struct ivtv *itv, int line, int field);
-void ivtv_disable_vbi(struct ivtv *itv);
+void ivtv_disable_cc(struct ivtv *itv);
void ivtv_set_vbi(unsigned long arg);
void ivtv_vbi_work_handler(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 85530a3cd369..d050de2a7229 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -17,10 +17,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_VERSION_H
+#define IVTV_VERSION_H
+
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 0
+#define IVTV_DRIVER_VERSION_MINOR 1
#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
#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)
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h
deleted file mode 100644
index c8ade5d3c413..000000000000
--- a/drivers/media/video/ivtv/ivtv-video.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- saa7127 interface functions
- Copyright (C) 2004-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 ivtv_set_wss(struct ivtv *itv, int enabled, int mode);
-void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4);
-void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
- u8 vps4, u8 vps5);
-void ivtv_video_set_io(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index bcea09542e5a..e2288f224ab6 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -19,11 +19,16 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-queue.h"
#include "ivtv-udma.h"
-#include "ivtv-irq.h"
#include "ivtv-yuv.h"
+const u32 yuv_offset[4] = {
+ IVTV_YUV_BUFFER_OFFSET,
+ IVTV_YUV_BUFFER_OFFSET_1,
+ IVTV_YUV_BUFFER_OFFSET_2,
+ IVTV_YUV_BUFFER_OFFSET_3
+};
+
static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
struct ivtv_dma_frame *args)
{
@@ -37,7 +42,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
int y_decode_height, uv_decode_height, y_size;
int frame = atomic_read(&itv->yuv_info.next_fill_frame);
- y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame];
+ y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
y_decode_height = uv_decode_height = args->src.height + args->src.top;
@@ -83,7 +88,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
}
/* Fill & map SG List */
- ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0));
+ if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
+ IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
+ for (i = 0; i < dma->page_count; i++) {
+ put_page(dma->map[i]);
+ }
+ dma->page_count = 0;
+ return -ENOMEM;
+ }
dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
/* Fill SG Array with new values */
@@ -94,7 +106,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
if (itv->yuv_info.blanking_dmaptr) {
dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
- dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]);
+ dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
dma->SG_length++;
}
}
@@ -612,7 +624,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
itv->yuv_info.v_filter_2 = v_filter_2;
}
- itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced;
}
/* Modify the supplied coordinate information to fit the visible osd area */
@@ -799,6 +810,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
(itv->yuv_info.old_frame_info.src_y != window->src_y) ||
(itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
(itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
+ (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
(itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
(itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
@@ -898,8 +910,21 @@ static void ivtv_yuv_init (struct ivtv *itv)
itv->yuv_info.decode_height = 480;
/* If no visible size set, assume full size */
- if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
- if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ if (!itv->yuv_info.osd_vis_w)
+ itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
+
+ if (!itv->yuv_info.osd_vis_h) {
+ itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ } else {
+ /* If output video standard has changed, requested height may
+ not be legal */
+ if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
+ IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+ itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
+ itv->yuv_info.decode_height);
+ itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ }
+ }
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
@@ -927,6 +952,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
int rc = 0;
int got_sig = 0;
int frame, next_fill_frame, last_fill_frame;
+ int register_update = 0;
IVTV_DEBUG_INFO("yuv_prep_frame\n");
@@ -940,6 +966,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* Buffers are full - Overwrite the last frame */
next_fill_frame = frame;
frame = (frame - 1) & 3;
+ register_update = itv->yuv_info.new_frame_info[frame].update;
}
/* Take a snapshot of the yuv coordinate information */
@@ -955,6 +982,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
+ /* Snapshot field order */
+ itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
+
/* Are we going to offset the Y plane */
if (args->src.height + args->src.top < 512-16)
itv->yuv_info.new_frame_info[frame].offset_y = 1;
@@ -970,6 +1000,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
itv->yuv_info.new_frame_info[frame].update = 0;
itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
+ itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
sizeof (itv->yuv_info.new_frame_info[frame]))) {
@@ -978,6 +1009,14 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
}
+ itv->yuv_info.new_frame_info[frame].update |= register_update;
+
+ /* Should this frame be delayed ? */
+ if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
+ itv->yuv_info.field_delay[frame] = 1;
+ else
+ itv->yuv_info.field_delay[frame] = 0;
+
/* DMA the frame */
mutex_lock(&itv->udma.lock);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 88972d3f77c4..f7215eeca018 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -18,7 +18,28 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_YUV_H
+#define IVTV_YUV_H
+
+/* Buffers on hardware offsets */
+#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */
+#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */
+
+/* Offset to filter table in firmware */
+#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
+#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
+
+#define IVTV_YUV_UPDATE_HORIZONTAL 0x01
+#define IVTV_YUV_UPDATE_VERTICAL 0x02
+
+extern const u32 yuv_offset[4];
+
int ivtv_yuv_filter_check(struct ivtv *itv);
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
void ivtv_yuv_close(struct ivtv *itv);
void ivtv_yuv_work_handler (struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
new file mode 100644
index 000000000000..9684048fe56c
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -0,0 +1,1190 @@
+/*
+ On Screen Display cx23415 Framebuffer driver
+
+ This module presents the cx23415 OSD (onscreen display) framebuffer memory
+ as a standard Linux /dev/fb style framebuffer device. The framebuffer has
+ support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
+ mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
+ local alpha. The colorspace is selectable between rgb & yuv.
+ Depending on the TV standard configured in the ivtv module at load time,
+ the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
+ Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
+ or 59.94 (NTSC)
+
+ Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
+
+ Derived from drivers/video/vesafb.c
+ Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+ 2.6 kernel port:
+ Copyright (C) 2004 Matthias Badaire
+
+ Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+
+ Copyright (C) 2006 Ian Armstrong <ian@iarmst.demon.co.uk>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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/fb.h>
+#include <linux/ivtvfb.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "ivtv-driver.h"
+#include "ivtv-udma.h"
+#include "ivtv-mailbox.h"
+
+/* card parameters */
+static int ivtvfb_card_id = -1;
+static int ivtvfb_debug = 0;
+static int osd_laced;
+static int osd_compat;
+static int osd_depth;
+static int osd_upper;
+static int osd_left;
+static int osd_yres;
+static int osd_xres;
+
+module_param(ivtvfb_card_id, int, 0444);
+module_param_named(debug,ivtvfb_debug, int, 0644);
+module_param(osd_laced, bool, 0444);
+module_param(osd_compat, bool, 0444);
+module_param(osd_depth, int, 0444);
+module_param(osd_upper, int, 0444);
+module_param(osd_left, int, 0444);
+module_param(osd_yres, int, 0444);
+module_param(osd_xres, int, 0444);
+
+MODULE_PARM_DESC(ivtvfb_card_id,
+ "Only use framebuffer of the specified ivtv card (0-31)\n"
+ "\t\t\tdefault -1: initialize all available framebuffers");
+
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: errors only\n"
+ "\t\t\t(debug = 3 gives full debugging)");
+
+MODULE_PARM_DESC(osd_compat,
+ "Compatibility mode - Display size is locked (use for old X drivers)\n"
+ "\t\t\t0=off\n"
+ "\t\t\t1=on\n"
+ "\t\t\tdefault off");
+
+/* Why upper, left, xres, yres, depth, laced ? To match terminology used
+ by fbset.
+ Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
+
+MODULE_PARM_DESC(osd_laced,
+ "Interlaced mode\n"
+ "\t\t\t0=off\n"
+ "\t\t\t1=on\n"
+ "\t\t\tdefault off");
+
+MODULE_PARM_DESC(osd_depth,
+ "Bits per pixel - 8, 16, 32\n"
+ "\t\t\tdefault 8");
+
+MODULE_PARM_DESC(osd_upper,
+ "Vertical start position\n"
+ "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_left,
+ "Horizontal start position\n"
+ "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_yres,
+ "Display height\n"
+ "\t\t\tdefault 480 (PAL)\n"
+ "\t\t\t 400 (NTSC)");
+
+MODULE_PARM_DESC(osd_xres,
+ "Display width\n"
+ "\t\t\tdefault 640");
+
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
+MODULE_LICENSE("GPL");
+
+/* --------------------------------------------------------------------- */
+
+#define IVTVFB_DBGFLG_WARN (1 << 0)
+#define IVTVFB_DBGFLG_INFO (1 << 1)
+
+#define IVTVFB_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & ivtvfb_debug) \
+ printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
+ } while (0)
+#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
+
+/* Standard kernel messages */
+#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
+
+/* --------------------------------------------------------------------- */
+
+#define IVTV_OSD_MAX_WIDTH 720
+#define IVTV_OSD_MAX_HEIGHT 576
+
+#define IVTV_OSD_BPP_8 0x00
+#define IVTV_OSD_BPP_16_444 0x03
+#define IVTV_OSD_BPP_16_555 0x02
+#define IVTV_OSD_BPP_16_565 0x01
+#define IVTV_OSD_BPP_32 0x04
+
+struct osd_info {
+ /* Physical base address */
+ unsigned long video_pbase;
+ /* Relative base address (relative to start of decoder memory) */
+ u32 video_rbase;
+ /* Mapped base address */
+ volatile char __iomem *video_vbase;
+ /* Buffer size */
+ u32 video_buffer_size;
+
+#ifdef CONFIG_MTRR
+ /* video_base rounded down as required by hardware MTRRs */
+ unsigned long fb_start_aligned_physaddr;
+ /* video_base rounded up as required by hardware MTRRs */
+ unsigned long fb_end_aligned_physaddr;
+#endif
+
+ /* Current osd mode */
+ int osd_mode;
+
+ /* Store the buffer offset */
+ int set_osd_coords_x;
+ int set_osd_coords_y;
+
+ /* Current dimensions (NOT VISIBLE SIZE!) */
+ int display_width;
+ int display_height;
+ int display_byte_stride;
+
+ /* Current bits per pixel */
+ int bits_per_pixel;
+ int bytes_per_pixel;
+
+ /* Frame buffer stuff */
+ struct fb_info ivtvfb_info;
+ struct fb_var_screeninfo ivtvfb_defined;
+ struct fb_fix_screeninfo ivtvfb_fix;
+};
+
+struct ivtv_osd_coords {
+ unsigned long offset;
+ unsigned long max_offset;
+ int pixel_stride;
+ int lines;
+ int x;
+ int y;
+};
+
+/* --------------------------------------------------------------------- */
+
+/* ivtv API calls for framebuffer related support */
+
+static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
+ u32 *fblength)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int rc;
+
+ rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
+ *fbbase = data[0];
+ *fblength = data[1];
+ return rc;
+}
+
+static int ivtvfb_get_osd_coords(struct ivtv *itv,
+ struct ivtv_osd_coords *osd)
+{
+ struct osd_info *oi = itv->osd_info;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
+
+ osd->offset = data[0] - oi->video_rbase;
+ osd->max_offset = oi->display_width * oi->display_height * 4;
+ osd->pixel_stride = data[1];
+ osd->lines = data[2];
+ osd->x = data[3];
+ osd->y = data[4];
+ return 0;
+}
+
+static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ oi->display_width = osd->pixel_stride;
+ oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
+ oi->set_osd_coords_x += osd->x;
+ oi->set_osd_coords_y = osd->y;
+
+ return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
+ osd->offset + oi->video_rbase,
+ osd->pixel_stride,
+ osd->lines, osd->x, osd->y);
+}
+
+static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
+{
+ int osd_height_limit = itv->is_50hz ? 576 : 480;
+
+ /* Only fail if resolution too high, otherwise fudge the start coords. */
+ if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
+ return -EINVAL;
+
+ /* Ensure we don't exceed display limits */
+ if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
+ IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
+ ivtv_window->top, ivtv_window->height);
+ ivtv_window->top = osd_height_limit - ivtv_window->height;
+ }
+
+ if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
+ IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
+ ivtv_window->left, ivtv_window->width);
+ ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
+ }
+
+ /* Set the OSD origin */
+ write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
+
+ /* How much to display */
+ write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
+
+ /* Pass this info back the yuv handler */
+ itv->yuv_info.osd_vis_w = ivtv_window->width;
+ itv->yuv_info.osd_vis_h = ivtv_window->height;
+ itv->yuv_info.osd_x_offset = ivtv_window->left;
+ itv->yuv_info.osd_y_offset = ivtv_window->top;
+
+ return 0;
+}
+
+static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
+ unsigned long ivtv_dest_addr, void __user *userbuf,
+ int size_in_bytes)
+{
+ DEFINE_WAIT(wait);
+ int ret = 0;
+ int got_sig = 0;
+
+ mutex_lock(&itv->udma.lock);
+ /* Map User DMA */
+ if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
+ mutex_unlock(&itv->udma.lock);
+ IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
+ "Error with get_user_pages: %d bytes, %d pages returned\n",
+ size_in_bytes, itv->udma.page_count);
+
+ /* get_user_pages must have failed completely */
+ return -EIO;
+ }
+
+ IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
+ size_in_bytes, itv->udma.page_count);
+
+ ivtv_udma_prepare(itv);
+ prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+ /* if no UDMA is pending and no UDMA is in progress, then the DMA
+ is finished */
+ while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
+ /* don't interrupt if the DMA is in progress but break off
+ a still pending DMA. */
+ got_sig = signal_pending(current);
+ if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+ break;
+ got_sig = 0;
+ schedule();
+ }
+ finish_wait(&itv->dma_waitq, &wait);
+
+ /* Unmap Last DMA Xfer */
+ ivtv_udma_unmap(itv);
+ mutex_unlock(&itv->udma.lock);
+ if (got_sig) {
+ IVTV_DEBUG_INFO("User stopped OSD\n");
+ return -EINTR;
+ }
+
+ return ret;
+}
+
+static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
+ unsigned long dest_offset, int count)
+{
+ DEFINE_WAIT(wait);
+ struct osd_info *oi = itv->osd_info;
+
+ /* Nothing to do */
+ if (count == 0) {
+ IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
+ return -EINVAL;
+ }
+
+ /* Check Total FB Size */
+ if ((dest_offset + count) > oi->video_buffer_size) {
+ IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
+ dest_offset + count, oi->video_buffer_size);
+ return -E2BIG;
+ }
+
+ /* Not fatal, but will have undesirable results */
+ if ((unsigned long)source & 3)
+ IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
+ (unsigned long)source);
+
+ if (dest_offset & 3)
+ IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
+
+ if (count & 3)
+ IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
+
+ /* Check Source */
+ if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
+ IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
+ (unsigned long)source);
+
+ IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
+ dest_offset, (unsigned long)source,
+ count);
+ return -EINVAL;
+ }
+
+ /* OSD Address to send DMA to */
+ dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
+
+ /* Fill Buffers */
+ return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
+}
+
+static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+ DEFINE_WAIT(wait);
+ struct ivtv *itv = (struct ivtv *)info->par;
+ int rc = 0;
+
+ switch (cmd) {
+ case FBIOGET_VBLANK: {
+ struct fb_vblank vblank;
+ u32 trace;
+
+ vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
+ FB_VBLANK_HAVE_VSYNC;
+ trace = read_reg(0x028c0) >> 16;
+ if (itv->is_50hz && trace > 312) trace -= 312;
+ else if (itv->is_60hz && trace > 262) trace -= 262;
+ if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
+ vblank.count = itv->last_vsync_field;
+ vblank.vcount = trace;
+ vblank.hcount = 0;
+ if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case FBIO_WAITFORVSYNC:
+ prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
+ if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
+ finish_wait(&itv->vsync_waitq, &wait);
+ return rc;
+
+ case IVTVFB_IOC_DMA_FRAME: {
+ struct ivtvfb_dma_frame args;
+
+ IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
+ if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
+ return -EFAULT;
+
+ return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
+ }
+
+ default:
+ IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Framebuffer device handling */
+
+static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
+{
+ struct osd_info *oi = itv->osd_info;
+ struct ivtv_osd_coords ivtv_osd;
+ struct v4l2_rect ivtv_window;
+ int osd_mode = -1;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
+
+ /* Select color space */
+ if (var->nonstd) /* YUV */
+ write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
+ else /* RGB */
+ write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
+
+ /* Set the color mode */
+ switch (var->bits_per_pixel) {
+ case 8:
+ osd_mode = IVTV_OSD_BPP_8;
+ break;
+ case 32:
+ osd_mode = IVTV_OSD_BPP_32;
+ break;
+ case 16:
+ switch (var->green.length) {
+ case 4:
+ osd_mode = IVTV_OSD_BPP_16_444;
+ break;
+ case 5:
+ osd_mode = IVTV_OSD_BPP_16_555;
+ break;
+ case 6:
+ osd_mode = IVTV_OSD_BPP_16_565;
+ break;
+ default:
+ IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+ }
+ break;
+ default:
+ IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+ }
+
+ /* Change osd mode if needed.
+ Although rare, things can go wrong. The extra mode
+ change seems to help... */
+ if (osd_mode != -1 && osd_mode != oi->osd_mode) {
+ ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
+ ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
+ oi->osd_mode = osd_mode;
+ }
+
+ oi->bits_per_pixel = var->bits_per_pixel;
+ oi->bytes_per_pixel = var->bits_per_pixel / 8;
+
+ /* Set the flicker filter */
+ switch (var->vmode & FB_VMODE_MASK) {
+ case FB_VMODE_NONINTERLACED: /* Filter on */
+ ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
+ break;
+ case FB_VMODE_INTERLACED: /* Filter off */
+ ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
+ break;
+ default:
+ IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
+ }
+
+ /* Read the current osd info */
+ ivtvfb_get_osd_coords(itv, &ivtv_osd);
+
+ /* Now set the OSD to the size we want */
+ ivtv_osd.pixel_stride = var->xres_virtual;
+ ivtv_osd.lines = var->yres_virtual;
+ ivtv_osd.x = 0;
+ ivtv_osd.y = 0;
+ ivtvfb_set_osd_coords(itv, &ivtv_osd);
+
+ /* Can't seem to find the right API combo for this.
+ Use another function which does what we need through direct register access. */
+ ivtv_window.width = var->xres;
+ ivtv_window.height = var->yres;
+
+ /* Minimum margin cannot be 0, as X won't allow such a mode */
+ if (!var->upper_margin) var->upper_margin++;
+ if (!var->left_margin) var->left_margin++;
+ ivtv_window.top = var->upper_margin - 1;
+ ivtv_window.left = var->left_margin - 1;
+
+ ivtvfb_set_display_window(itv, &ivtv_window);
+
+ /* Force update of yuv registers */
+ itv->yuv_info.yuv_forced_update = 1;
+
+ IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+ var->xres, var->yres,
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel);
+
+ IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+ var->left_margin, var->upper_margin);
+
+ IVTVFB_DEBUG_INFO("Display filter: %s\n",
+ (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+ IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+
+ return 0;
+}
+
+static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, "cx23415 TV out");
+ fix->smem_start = oi->video_pbase;
+ fix->smem_len = oi->video_buffer_size;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = oi->display_byte_stride;
+ fix->accel = FB_ACCEL_NONE;
+ return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+ handle it. */
+
+static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+ int osd_height_limit;
+ u32 pixclock, hlimit, vlimit;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+
+ /* Set base references for mode calcs. */
+ if (itv->is_50hz) {
+ pixclock = 84316;
+ hlimit = 776;
+ vlimit = 591;
+ osd_height_limit = 576;
+ }
+ else {
+ pixclock = 83926;
+ hlimit = 776;
+ vlimit = 495;
+ osd_height_limit = 480;
+ }
+
+ /* Check the bits per pixel */
+ if (osd_compat) {
+ if (var->bits_per_pixel != 32) {
+ IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+ }
+
+ if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ }
+ else if (var->bits_per_pixel == 16) {
+ /* To find out the true mode, check green length */
+ switch (var->green.length) {
+ case 4:
+ var->red.offset = 8;
+ var->red.length = 4;
+ var->green.offset = 4;
+ var->green.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
+ var->transp.offset = 12;
+ var->transp.length = 1;
+ break;
+ case 5:
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ break;
+ default:
+ 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 = 0;
+ var->transp.length = 0;
+ break;
+ }
+ }
+ else {
+ IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* Check the resolution */
+ if (osd_compat) {
+ if (var->xres != oi->ivtvfb_defined.xres ||
+ var->yres != oi->ivtvfb_defined.yres ||
+ var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
+ var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
+ IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
+ var->xres, var->yres, var->xres_virtual, var->yres_virtual);
+ return -EINVAL;
+ }
+ }
+ else {
+ if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
+ IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
+ var->xres, var->yres);
+ return -EINVAL;
+ }
+
+ /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
+ if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
+ var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
+ var->xres_virtual < var->xres ||
+ var->yres_virtual < var->yres) {
+ IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
+ var->xres_virtual, var->yres_virtual);
+ return -EINVAL;
+ }
+ }
+
+ /* Some extra checks if in 8 bit mode */
+ if (var->bits_per_pixel == 8) {
+ /* Width must be a multiple of 4 */
+ if (var->xres & 3) {
+ IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
+ return -EINVAL;
+ }
+ if (var->xres_virtual & 3) {
+ IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
+ return -EINVAL;
+ }
+ }
+ else if (var->bits_per_pixel == 16) {
+ /* Width must be a multiple of 2 */
+ if (var->xres & 1) {
+ IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
+ return -EINVAL;
+ }
+ if (var->xres_virtual & 1) {
+ IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
+ return -EINVAL;
+ }
+ }
+
+ /* Now check the offsets */
+ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
+ IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
+ var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
+ return -EINVAL;
+ }
+
+ /* Check pixel format */
+ if (var->nonstd > 1) {
+ IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
+ return -EINVAL;
+ }
+
+ /* Check video mode */
+ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
+ ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
+ IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
+ return -EINVAL;
+ }
+
+ /* Check the left & upper margins
+ If the margins are too large, just center the screen
+ (enforcing margins causes too many problems) */
+
+ if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
+ var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
+ }
+ if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
+ var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
+ }
+
+ /* Maintain overall 'size' for a constant refresh rate */
+ var->right_margin = hlimit - var->left_margin - var->xres;
+ var->lower_margin = vlimit - var->upper_margin - var->yres;
+
+ /* Fixed sync times */
+ var->hsync_len = 24;
+ var->vsync_len = 2;
+
+ /* Non-interlaced / interlaced mode is used to switch the OSD filter
+ on or off. Adjust the clock timings to maintain a constant
+ vertical refresh rate. */
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+ var->pixclock = pixclock / 2;
+ else
+ var->pixclock = pixclock;
+
+ IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+ var->xres, var->yres,
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel);
+
+ IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+ var->left_margin, var->upper_margin);
+
+ IVTVFB_DEBUG_INFO("Display filter: %s\n",
+ (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+ IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+ return 0;
+}
+
+static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct ivtv *itv = (struct ivtv *) info->par;
+ IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+ return _ivtvfb_check_var(var, itv);
+}
+
+static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 osd_pan_index;
+ struct ivtv *itv = (struct ivtv *) info->par;
+
+ osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
+ write_reg(osd_pan_index, 0x02A0C);
+
+ /* Pass this info back the yuv handler */
+ itv->yuv_info.osd_x_pan = var->xoffset;
+ itv->yuv_info.osd_y_pan = var->yoffset;
+ /* Force update of yuv registers */
+ itv->yuv_info.yuv_forced_update = 1;
+ return 0;
+}
+
+static int ivtvfb_set_par(struct fb_info *info)
+{
+ int rc = 0;
+ struct ivtv *itv = (struct ivtv *) info->par;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
+
+ rc = ivtvfb_set_var(itv, &info->var);
+ ivtvfb_pan_display(&info->var, info);
+ ivtvfb_get_fix(itv, &info->fix);
+ return rc;
+}
+
+static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ u32 color, *palette;
+ struct ivtv *itv = (struct ivtv *)info->par;
+
+ if (regno >= info->cmap.len)
+ return -EINVAL;
+
+ color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ if (info->var.bits_per_pixel <= 8) {
+ write_reg(regno, 0x02a30);
+ write_reg(color, 0x02a34);
+ return 0;
+ }
+ if (regno >= 16)
+ return -EINVAL;
+
+ palette = info->pseudo_palette;
+ if (info->var.bits_per_pixel == 16) {
+ switch (info->var.green.length) {
+ case 4:
+ color = ((red & 0xf000) >> 4) |
+ ((green & 0xf000) >> 8) |
+ ((blue & 0xf000) >> 12);
+ break;
+ case 5:
+ color = ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 6:
+ color = (red & 0xf800 ) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+ }
+ }
+ palette[regno] = color;
+ return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+ disable the OSD. */
+static int ivtvfb_blank(int blank_mode, struct fb_info *info)
+{
+ struct ivtv *itv = (struct ivtv *)info->par;
+
+ IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
+ break;
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops ivtvfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = ivtvfb_check_var,
+ .fb_set_par = ivtvfb_set_par,
+ .fb_setcolreg = ivtvfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = NULL,
+ .fb_ioctl = ivtvfb_ioctl,
+ .fb_pan_display = ivtvfb_pan_display,
+ .fb_blank = ivtvfb_blank,
+};
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int ivtvfb_init_vidmode(struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+ struct v4l2_rect start_window;
+ int max_height;
+
+ /* Color mode */
+
+ if (osd_compat) osd_depth = 32;
+ if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
+ oi->bits_per_pixel = osd_depth;
+ oi->bytes_per_pixel = oi->bits_per_pixel / 8;
+
+ /* Invalidate current osd mode to force a mode switch later */
+ oi->osd_mode = -1;
+
+ /* Horizontal size & position */
+
+ if (osd_xres > 720) osd_xres = 720;
+
+ /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
+ if (osd_depth == 8)
+ osd_xres &= ~3;
+ else if (osd_depth == 16)
+ osd_xres &= ~1;
+
+ if (osd_xres)
+ start_window.width = osd_xres;
+ else
+ start_window.width = osd_compat ? 720: 640;
+
+ /* Check horizontal start (osd_left). */
+ if (osd_left && osd_left + start_window.width > 721) {
+ IVTVFB_ERR("Invalid osd_left - assuming default\n");
+ osd_left = 0;
+ }
+
+ /* Hardware coords start at 0, user coords start at 1. */
+ osd_left--;
+
+ start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
+
+ oi->display_byte_stride =
+ start_window.width * oi->bytes_per_pixel;
+
+ /* Vertical size & position */
+
+ max_height = itv->is_50hz ? 576 : 480;
+
+ if (osd_yres > max_height)
+ osd_yres = max_height;
+
+ if (osd_yres)
+ start_window.height = osd_yres;
+ else
+ start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
+
+ /* Check vertical start (osd_upper). */
+ if (osd_upper + start_window.height > max_height + 1) {
+ IVTVFB_ERR("Invalid osd_upper - assuming default\n");
+ osd_upper = 0;
+ }
+
+ /* Hardware coords start at 0, user coords start at 1. */
+ osd_upper--;
+
+ start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
+
+ oi->display_width = start_window.width;
+ oi->display_height = start_window.height;
+
+ /* Generate a valid fb_var_screeninfo */
+
+ oi->ivtvfb_defined.xres = oi->display_width;
+ oi->ivtvfb_defined.yres = oi->display_height;
+ oi->ivtvfb_defined.xres_virtual = oi->display_width;
+ oi->ivtvfb_defined.yres_virtual = oi->display_height;
+ oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
+ oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
+ oi->ivtvfb_defined.left_margin = start_window.left + 1;
+ oi->ivtvfb_defined.upper_margin = start_window.top + 1;
+ oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
+ oi->ivtvfb_defined.nonstd = 0;
+
+ /* We've filled in the most data, let the usual mode check
+ routine fill in the rest. */
+ _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
+
+ /* Generate valid fb_fix_screeninfo */
+
+ ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
+
+ /* Generate valid fb_info */
+
+ oi->ivtvfb_info.node = -1;
+ oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
+ oi->ivtvfb_info.fbops = &ivtvfb_ops;
+ oi->ivtvfb_info.par = itv;
+ oi->ivtvfb_info.var = oi->ivtvfb_defined;
+ oi->ivtvfb_info.fix = oi->ivtvfb_fix;
+ oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
+ oi->ivtvfb_info.fbops = &ivtvfb_ops;
+
+ /* Supply some monitor specs. Bogus values will do for now */
+ oi->ivtvfb_info.monspecs.hfmin = 8000;
+ oi->ivtvfb_info.monspecs.hfmax = 70000;
+ oi->ivtvfb_info.monspecs.vfmin = 10;
+ oi->ivtvfb_info.monspecs.vfmax = 100;
+
+ /* Allocate color map */
+ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
+ IVTVFB_ERR("abort, unable to alloc cmap\n");
+ return -ENOMEM;
+ }
+
+ /* Allocate the pseudo palette */
+ oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+
+ if (!oi->ivtvfb_info.pseudo_palette) {
+ IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
+
+static int ivtvfb_init_io(struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ mutex_lock(&itv->serialize_lock);
+ if (ivtv_init_on_first_open(itv)) {
+ mutex_unlock(&itv->serialize_lock);
+ IVTVFB_ERR("Failed to initialize ivtv\n");
+ return -ENXIO;
+ }
+ mutex_unlock(&itv->serialize_lock);
+
+ ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
+
+ /* The osd buffer size depends on the number of video buffers allocated
+ on the PVR350 itself. For now we'll hardcode the smallest osd buffer
+ size to prevent any overlap. */
+ oi->video_buffer_size = 1704960;
+
+ oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
+ oi->video_vbase = itv->dec_mem + oi->video_rbase;
+
+ if (!oi->video_vbase) {
+ IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
+ oi->video_buffer_size, oi->video_pbase);
+ return -EIO;
+ }
+
+ IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+ oi->video_pbase, oi->video_vbase,
+ oi->video_buffer_size / 1024);
+
+#ifdef CONFIG_MTRR
+ {
+ /* Find the largest power of two that maps the whole buffer */
+ int size_shift = 31;
+
+ while (!(oi->video_buffer_size & (1 << size_shift))) {
+ size_shift--;
+ }
+ size_shift++;
+ oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
+ oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
+ oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
+ oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
+ if (mtrr_add(oi->fb_start_aligned_physaddr,
+ oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
+ MTRR_TYPE_WRCOMB, 1) < 0) {
+ IVTVFB_INFO("disabled mttr\n");
+ oi->fb_start_aligned_physaddr = 0;
+ oi->fb_end_aligned_physaddr = 0;
+ }
+ }
+#endif
+
+ /* Blank the entire osd. */
+ memset_io(oi->video_vbase, 0, oi->video_buffer_size);
+
+ return 0;
+}
+
+/* Release any memory we've grabbed & remove mtrr entry */
+static void ivtvfb_release_buffers (struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ /* Release cmap */
+ if (oi->ivtvfb_info.cmap.len)
+ fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
+
+ /* Release pseudo palette */
+ if (oi->ivtvfb_info.pseudo_palette)
+ kfree(oi->ivtvfb_info.pseudo_palette);
+
+#ifdef CONFIG_MTRR
+ if (oi->fb_end_aligned_physaddr) {
+ mtrr_del(-1, oi->fb_start_aligned_physaddr,
+ oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
+ }
+#endif
+
+ kfree(oi);
+ itv->osd_info = NULL;
+}
+
+/* Initialize the specified card */
+
+static int ivtvfb_init_card(struct ivtv *itv)
+{
+ int rc;
+
+ if (itv->osd_info) {
+ IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
+ return -EBUSY;
+ }
+
+ itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+ if (itv->osd_info == 0) {
+ IVTVFB_ERR("Failed to allocate memory for osd_info\n");
+ return -ENOMEM;
+ }
+
+ /* Find & setup the OSD buffer */
+ if ((rc = ivtvfb_init_io(itv)))
+ return rc;
+
+ /* Set the startup video mode information */
+ if ((rc = ivtvfb_init_vidmode(itv))) {
+ ivtvfb_release_buffers(itv);
+ return rc;
+ }
+
+ /* Register the framebuffer */
+ if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
+ ivtvfb_release_buffers(itv);
+ return -EINVAL;
+ }
+
+ itv->osd_video_pbase = itv->osd_info->video_pbase;
+
+ /* Set the card to the requested mode */
+ ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
+
+ /* Set color 0 to black */
+ write_reg(0, 0x02a30);
+ write_reg(0, 0x02a34);
+
+ /* Enable the osd */
+ ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
+
+ /* Note if we're running in compatibility mode */
+ if (osd_compat)
+ IVTVFB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
+
+ /* Allocate DMA */
+ ivtv_udma_alloc(itv);
+ return 0;
+
+}
+
+static int __init ivtvfb_init(void)
+{
+ struct ivtv *itv;
+ int i, registered = 0;
+
+ if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
+ printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
+ IVTV_MAX_CARDS - 1);
+ return -EINVAL;
+ }
+
+ /* Locate & initialise all cards supporting an OSD. */
+ for (i = 0; i < ivtv_cards_active; i++) {
+ if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
+ continue;
+ itv = ivtv_cards[i];
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (ivtvfb_init_card(itv) == 0) {
+ IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
+ registered++;
+ }
+ }
+ }
+ if (!registered) {
+ printk(KERN_ERR "ivtvfb: no cards found");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void ivtvfb_cleanup(void)
+{
+ struct ivtv *itv;
+ int i;
+
+ printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n");
+
+ for (i = 0; i < ivtv_cards_active; i++) {
+ itv = ivtv_cards[i];
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
+ IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
+ ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+ unregister_framebuffer(&itv->osd_info->ivtvfb_info);
+ ivtvfb_release_buffers(itv);
+ itv->osd_video_pbase = 0;
+ }
+ }
+}
+
+module_init(ivtvfb_init);
+module_exit(ivtvfb_cleanup);
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 3bb7d6634862..c0c87e06259b 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -157,8 +157,7 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
break;
v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
}
if (err == 3) {
v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -197,8 +196,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
break;
v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
}
if (err == 3) {
v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -246,17 +244,17 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val)
* ----------------------------------------------------------------------- */
static int scarts[3][9] = {
- /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */
+ /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */
/* SCART DSP Input select */
- { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 },
+ { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 },
/* SCART1 Output select */
- { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
+ { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
/* SCART2 Output select */
- { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
+ { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
};
static char *scart_names[] = {
- "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
+ "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
};
void msp_set_scart(struct i2c_client *client, int in, int out)
@@ -814,10 +812,10 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
- client = kmalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL)
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
return -ENOMEM;
- memset(client, 0, sizeof(*client));
+
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver;
@@ -829,14 +827,14 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
return 0;
}
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (state == NULL) {
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state) {
kfree(client);
return -ENOMEM;
}
+
i2c_set_clientdata(client, state);
- memset(state, 0, sizeof(*state));
state->v4l2_std = V4L2_STD_NTSC;
state->audmode = V4L2_TUNER_MODE_STEREO;
state->volume = 58880; /* 0db gain */
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index c7c9f3f8715c..f49d1f4c40db 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -1,13 +1,20 @@
/*
- *
* i2c tv tuner chip device driver
* controls microtune tuners, mt2032 + mt2050 at the moment.
+ *
+ * This "mt20xx" module was split apart from the original "tuner" module.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
-#include <linux/moduleparam.h>
-#include <media/tuner.h>
+#include "tuner-i2c.h"
+#include "mt20xx.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "mt20xx "
/* ---------------------------------------------------------------------- */
@@ -20,9 +27,6 @@ module_param(tv_antenna, int, 0644);
static unsigned int radio_antenna = 0;
module_param(radio_antenna, int, 0644);
-/* from tuner-core.c */
-extern int tuner_debug;
-
/* ---------------------------------------------------------------------- */
#define MT2032 0x04
@@ -37,11 +41,35 @@ static char *microtune_part[] = {
[ MT2050 ] = "MT2050",
};
+struct microtune_priv {
+ struct tuner_i2c_props i2c_props;
+
+ unsigned int xogc;
+ //unsigned int radio_if2;
+
+ u32 frequency;
+};
+
+static int microtune_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct microtune_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
// IsSpurInBand()?
-static int mt2032_spurcheck(struct i2c_client *c,
+static int mt2032_spurcheck(struct dvb_frontend *fe,
int f1, int f2, int spectrum_from,int spectrum_to)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
int n1=1,n2,f;
f1=f1/1000; //scale to kHz to avoid 32bit overflows
@@ -69,7 +97,7 @@ static int mt2032_spurcheck(struct i2c_client *c,
return 1;
}
-static int mt2032_compute_freq(struct i2c_client *c,
+static int mt2032_compute_freq(struct dvb_frontend *fe,
unsigned int rfin,
unsigned int if1, unsigned int if2,
unsigned int spectrum_from,
@@ -78,7 +106,7 @@ static int mt2032_compute_freq(struct i2c_client *c,
int *ret_sel,
unsigned int xogc) //all in Hz
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
@@ -128,7 +156,7 @@ static int mt2032_compute_freq(struct i2c_client *c,
return(-1);
}
- mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to);
+ mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to);
// should recalculate lo1 (one step up/down)
// set up MT2032 register map for transfer over i2c
@@ -152,16 +180,16 @@ static int mt2032_compute_freq(struct i2c_client *c,
return 0;
}
-static int mt2032_check_lo_lock(struct i2c_client *c)
+static int mt2032_check_lo_lock(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
int try,lock=0;
unsigned char buf[2];
for(try=0;try<10;try++) {
buf[0]=0x0e;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
lock=buf[0] &0x06;
@@ -174,15 +202,15 @@ static int mt2032_check_lo_lock(struct i2c_client *c)
return lock;
}
-static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int tad1;
buf[0]=0x0f;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
tad1=buf[0]&0x07;
@@ -205,57 +233,57 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
buf[0]=0x0f;
buf[1]=sel;
- i2c_master_send(c,buf,2);
- lock=mt2032_check_lo_lock(c);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+ lock=mt2032_check_lo_lock(fe);
return lock;
}
-static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin,
unsigned int if1, unsigned int if2,
unsigned int from, unsigned int to)
{
unsigned char buf[21];
int lint_try,ret,sel,lock=0;
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
rfin,if1,if2,from,to);
buf[0]=0;
- ret=i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
buf[0]=0;
- ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+ ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
if (ret<0)
return;
// send only the relevant registers per Rev. 1.2
buf[0]=0;
- ret=i2c_master_send(c,buf,4);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4);
buf[5]=5;
- ret=i2c_master_send(c,buf+5,4);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4);
buf[11]=11;
- ret=i2c_master_send(c,buf+11,3);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3);
if(ret!=3)
tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
// wait for PLLs to lock (per manual), retry LINT if not.
for(lint_try=0; lint_try<2; lint_try++) {
- lock=mt2032_check_lo_lock(c);
+ lock=mt2032_check_lo_lock(fe);
if(optimize_vco)
- lock=mt2032_optimize_vco(c,sel,lock);
+ lock=mt2032_optimize_vco(fe,sel,lock);
if(lock==6) break;
tuner_dbg("mt2032: re-init PLLs by LINT\n");
buf[0]=7;
- buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
- i2c_master_send(c,buf,2);
+ buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
mdelay(10);
- buf[1]=8+t->xogc;
- i2c_master_send(c,buf,2);
+ buf[1]=8+priv->xogc;
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
}
if (lock!=6)
@@ -263,19 +291,19 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
buf[0]=2;
buf[1]=0x20; // LOGC for optimal phase noise
- ret=i2c_master_send(c,buf,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
}
-static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int mt2032_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
int if2,from,to;
// signal bandwidth and picture carrier
- if (t->std & V4L2_STD_525_60) {
+ if (params->std & V4L2_STD_525_60) {
// NTSC
from = 40750*1000;
to = 46750*1000;
@@ -287,24 +315,64 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
if2 = 38900*1000;
}
- mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+ mt2032_set_if_freq(fe, params->frequency*62500,
1090*1000*1000, if2, from, to);
+
+ return 0;
}
-static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int mt2032_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
- int if2 = t->radio_if2;
+ struct microtune_priv *priv = fe->tuner_priv;
+ int if2;
+
+ if (params->std & V4L2_STD_525_60) {
+ tuner_dbg("pinnacle ntsc\n");
+ if2 = 41300 * 1000;
+ } else {
+ tuner_dbg("pinnacle pal\n");
+ if2 = 33300 * 1000;
+ }
// per Manual for FM tuning: first if center freq. 1085 MHz
- mt2032_set_if_freq(c, freq * 1000 / 16,
- 1085*1000*1000,if2,if2,if2);
+ mt2032_set_if_freq(fe, params->frequency * 125 / 2,
+ 1085*1000*1000,if2,if2,if2);
+
+ return 0;
+}
+
+static int mt2032_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct microtune_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = mt2032_set_radio_freq(fe, params);
+ priv->frequency = params->frequency * 125 / 2;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = mt2032_set_tv_freq(fe, params);
+ priv->frequency = params->frequency * 62500;
+ break;
+ }
+
+ return ret;
}
+static struct dvb_tuner_ops mt2032_tuner_ops = {
+ .set_analog_params = mt2032_set_params,
+ .release = microtune_release,
+ .get_frequency = microtune_get_frequency,
+};
+
// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
-static int mt2032_init(struct i2c_client *c)
+static int mt2032_init(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[21];
int ret,xogc,xok=0;
@@ -313,7 +381,7 @@ static int mt2032_init(struct i2c_client *c)
buf[2]=0xff;
buf[3]=0x0f;
buf[4]=0x1f;
- ret=i2c_master_send(c,buf+1,4);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4);
buf[5]=6; // Index register 6
buf[6]=0xe4;
@@ -321,11 +389,11 @@ static int mt2032_init(struct i2c_client *c)
buf[8]=0xc3;
buf[9]=0x4e;
buf[10]=0xec;
- ret=i2c_master_send(c,buf+5,6);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6);
buf[12]=13; // Index register 13
buf[13]=0x32;
- ret=i2c_master_send(c,buf+12,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2);
// Adjust XOGC (register 7), wait for XOK
xogc=7;
@@ -333,8 +401,8 @@ static int mt2032_init(struct i2c_client *c)
tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
mdelay(10);
buf[0]=0x0e;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
xok=buf[0]&0x01;
tuner_dbg("mt2032: xok = 0x%02x\n",xok);
if (xok == 1) break;
@@ -347,32 +415,32 @@ static int mt2032_init(struct i2c_client *c)
}
buf[0]=0x07;
buf[1]=0x88 + xogc;
- ret=i2c_master_send(c,buf,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
} while (xok != 1 );
- t->xogc=xogc;
+ priv->xogc=xogc;
+
+ memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops));
- t->set_tv_freq = mt2032_set_tv_freq;
- t->set_radio_freq = mt2032_set_radio_freq;
return(1);
}
-static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
+static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
{
- struct tuner *t = i2c_get_clientdata(c);
- unsigned char buf[2];
- int ret;
-
- buf[0] = 6;
- buf[1] = antenna ? 0x11 : 0x10;
- ret=i2c_master_send(c,buf,2);
- tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+ struct microtune_priv *priv = fe->tuner_priv;
+ unsigned char buf[2];
+ int ret;
+
+ buf[0] = 6;
+ buf[1] = antenna ? 0x11 : 0x10;
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+ tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
}
-static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
+static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned int if1=1218*1000*1000;
unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
int ret;
@@ -404,7 +472,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
div2a=(lo2/8)-1;
div2b=lo2-(div2a+1)*8;
- if (tuner_debug > 1) {
+ if (debug > 1) {
tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
num1,num2,div1a,div1b,div2a,div2b);
@@ -420,7 +488,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
buf[5]=div2a;
if(num2!=0) buf[5]=buf[5]|0x40;
- if (tuner_debug > 1) {
+ if (debug > 1) {
int i;
tuner_dbg("bufs is: ");
for(i=0;i<6;i++)
@@ -428,87 +496,131 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
printk("\n");
}
- ret=i2c_master_send(c,buf,6);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6);
if (ret!=6)
tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
}
-static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int mt2050_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
unsigned int if2;
- if (t->std & V4L2_STD_525_60) {
+ if (params->std & V4L2_STD_525_60) {
// NTSC
if2 = 45750*1000;
} else {
// PAL
if2 = 38900*1000;
}
- if (V4L2_TUNER_DIGITAL_TV == t->mode) {
+ if (V4L2_TUNER_DIGITAL_TV == params->mode) {
// DVB (pinnacle 300i)
if2 = 36150*1000;
}
- mt2050_set_if_freq(c, freq*62500, if2);
- mt2050_set_antenna(c, tv_antenna);
+ mt2050_set_if_freq(fe, params->frequency*62500, if2);
+ mt2050_set_antenna(fe, tv_antenna);
+
+ return 0;
+}
+
+static int mt2050_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct microtune_priv *priv = fe->tuner_priv;
+ int if2;
+
+ if (params->std & V4L2_STD_525_60) {
+ tuner_dbg("pinnacle ntsc\n");
+ if2 = 41300 * 1000;
+ } else {
+ tuner_dbg("pinnacle pal\n");
+ if2 = 33300 * 1000;
+ }
+
+ mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2);
+ mt2050_set_antenna(fe, radio_antenna);
+
+ return 0;
}
-static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int mt2050_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
- int if2 = t->radio_if2;
+ struct microtune_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = mt2050_set_radio_freq(fe, params);
+ priv->frequency = params->frequency * 125 / 2;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = mt2050_set_tv_freq(fe, params);
+ priv->frequency = params->frequency * 62500;
+ break;
+ }
- mt2050_set_if_freq(c, freq * 1000 / 16, if2);
- mt2050_set_antenna(c, radio_antenna);
+ return ret;
}
-static int mt2050_init(struct i2c_client *c)
+static struct dvb_tuner_ops mt2050_tuner_ops = {
+ .set_analog_params = mt2050_set_params,
+ .release = microtune_release,
+ .get_frequency = microtune_get_frequency,
+};
+
+static int mt2050_init(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int ret;
buf[0]=6;
buf[1]=0x10;
- ret=i2c_master_send(c,buf,2); // power
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power
buf[0]=0x0f;
buf[1]=0x0f;
- ret=i2c_master_send(c,buf,2); // m1lo
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo
buf[0]=0x0d;
- ret=i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
tuner_dbg("mt2050: sro is %x\n",buf[0]);
- t->set_tv_freq = mt2050_set_tv_freq;
- t->set_radio_freq = mt2050_set_radio_freq;
+
+ memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
+
return 0;
}
-int microtune_init(struct i2c_client *c)
+struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = NULL;
char *name;
unsigned char buf[21];
int company_code;
+ priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
+
+ //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+
memset(buf,0,sizeof(buf));
- t->set_tv_freq = NULL;
- t->set_radio_freq = NULL;
- t->standby = NULL;
- if (t->std & V4L2_STD_525_60) {
- tuner_dbg("pinnacle ntsc\n");
- t->radio_if2 = 41300 * 1000;
- } else {
- tuner_dbg("pinnacle pal\n");
- t->radio_if2 = 33300 * 1000;
- }
+
name = "unknown";
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
- if (tuner_debug) {
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
+ if (debug) {
int i;
tuner_dbg("MT20xx hexdump:");
for(i=0;i<21;i++) {
@@ -527,10 +639,10 @@ int microtune_init(struct i2c_client *c)
name = microtune_part[buf[0x13]];
switch (buf[0x13]) {
case MT2032:
- mt2032_init(c);
+ mt2032_init(fe);
break;
case MT2050:
- mt2050_init(c);
+ mt2050_init(fe);
break;
default:
tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
@@ -538,11 +650,18 @@ int microtune_init(struct i2c_client *c)
return 0;
}
- strlcpy(c->name, name, sizeof(c->name));
+ strlcpy(fe->ops.tuner_ops.info.name, name,
+ sizeof(fe->ops.tuner_ops.info.name));
tuner_info("microtune %s found, OK\n",name);
- return 0;
+ return fe;
}
+EXPORT_SYMBOL_GPL(microtune_attach);
+
+MODULE_DESCRIPTION("Microtune tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h
new file mode 100644
index 000000000000..5e9c825d2e91
--- /dev/null
+++ b/drivers/media/video/mt20xx.h
@@ -0,0 +1,37 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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 __MT20XX_H__
+#define __MT20XX_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr);
+#else
+static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __MT20XX_H__ */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 152cc6b3e152..98ad3092a079 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -153,7 +153,6 @@ static int mxb_probe(struct saa7146_dev* dev)
{
struct mxb* mxb = NULL;
struct i2c_client *client;
- struct list_head *item;
int result;
if ((result = request_module("saa7111")) < 0) {
@@ -196,8 +195,7 @@ static int mxb_probe(struct saa7146_dev* dev)
}
/* loop through all i2c-devices on the bus and look who is there */
- list_for_each(item,&mxb->i2c_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
+ list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
if( I2C_ADDR_TEA6420_1 == client->addr )
mxb->tea6420_1 = client;
if( I2C_ADDR_TEA6420_2 == client->addr )
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index e5edff1059a2..9eb2562347a8 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -5554,41 +5554,46 @@ error:
* sysfs
***************************************************************************/
-static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
+static inline struct usb_ov511 *cd_to_ov(struct device *cd)
{
struct video_device *vdev = to_video_device(cd);
return video_get_drvdata(vdev);
}
-static ssize_t show_custom_id(struct class_device *cd, char *buf)
+static ssize_t show_custom_id(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%d\n", ov->customid);
}
-static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
+static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-static ssize_t show_model(struct class_device *cd, char *buf)
+static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%s\n", ov->desc);
}
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-static ssize_t show_bridge(struct class_device *cd, char *buf)
+static ssize_t show_bridge(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
}
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
+static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-static ssize_t show_sensor(struct class_device *cd, char *buf)
+static ssize_t show_sensor(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
}
-static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
+static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-static ssize_t show_brightness(struct class_device *cd, char *buf)
+static ssize_t show_brightness(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5598,9 +5603,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
sensor_get_brightness(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-static ssize_t show_saturation(struct class_device *cd, char *buf)
+static ssize_t show_saturation(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5610,9 +5616,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
sensor_get_saturation(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-static ssize_t show_contrast(struct class_device *cd, char *buf)
+static ssize_t show_contrast(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5622,9 +5629,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
sensor_get_contrast(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-static ssize_t show_hue(struct class_device *cd, char *buf)
+static ssize_t show_hue(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5634,9 +5642,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
sensor_get_hue(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-static ssize_t show_exposure(struct class_device *cd, char *buf)
+static ssize_t show_exposure(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned char exp = 0;
@@ -5646,49 +5655,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf)
sensor_get_exposure(ov, &exp);
return sprintf(buf, "%d\n", exp >> 8);
}
-static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
+static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
static int ov_create_sysfs(struct video_device *vdev)
{
int rc;
- rc = video_device_create_file(vdev, &class_device_attr_custom_id);
+ rc = video_device_create_file(vdev, &dev_attr_custom_id);
if (rc) goto err;
- rc = video_device_create_file(vdev, &class_device_attr_model);
+ rc = video_device_create_file(vdev, &dev_attr_model);
if (rc) goto err_id;
- rc = video_device_create_file(vdev, &class_device_attr_bridge);
+ rc = video_device_create_file(vdev, &dev_attr_bridge);
if (rc) goto err_model;
- rc = video_device_create_file(vdev, &class_device_attr_sensor);
+ rc = video_device_create_file(vdev, &dev_attr_sensor);
if (rc) goto err_bridge;
- rc = video_device_create_file(vdev, &class_device_attr_brightness);
+ rc = video_device_create_file(vdev, &dev_attr_brightness);
if (rc) goto err_sensor;
- rc = video_device_create_file(vdev, &class_device_attr_saturation);
+ rc = video_device_create_file(vdev, &dev_attr_saturation);
if (rc) goto err_bright;
- rc = video_device_create_file(vdev, &class_device_attr_contrast);
+ rc = video_device_create_file(vdev, &dev_attr_contrast);
if (rc) goto err_sat;
- rc = video_device_create_file(vdev, &class_device_attr_hue);
+ rc = video_device_create_file(vdev, &dev_attr_hue);
if (rc) goto err_contrast;
- rc = video_device_create_file(vdev, &class_device_attr_exposure);
+ rc = video_device_create_file(vdev, &dev_attr_exposure);
if (rc) goto err_hue;
return 0;
err_hue:
- video_device_remove_file(vdev, &class_device_attr_hue);
+ video_device_remove_file(vdev, &dev_attr_hue);
err_contrast:
- video_device_remove_file(vdev, &class_device_attr_contrast);
+ video_device_remove_file(vdev, &dev_attr_contrast);
err_sat:
- video_device_remove_file(vdev, &class_device_attr_saturation);
+ video_device_remove_file(vdev, &dev_attr_saturation);
err_bright:
- video_device_remove_file(vdev, &class_device_attr_brightness);
+ video_device_remove_file(vdev, &dev_attr_brightness);
err_sensor:
- video_device_remove_file(vdev, &class_device_attr_sensor);
+ video_device_remove_file(vdev, &dev_attr_sensor);
err_bridge:
- video_device_remove_file(vdev, &class_device_attr_bridge);
+ video_device_remove_file(vdev, &dev_attr_bridge);
err_model:
- video_device_remove_file(vdev, &class_device_attr_model);
+ video_device_remove_file(vdev, &dev_attr_model);
err_id:
- video_device_remove_file(vdev, &class_device_attr_custom_id);
+ video_device_remove_file(vdev, &dev_attr_custom_id);
err:
return rc;
}
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 3ceb8a6249dd..2bc6bdc9c1f2 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -12,7 +12,6 @@
*/
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/videodev.h>
@@ -416,7 +415,10 @@ static int ov7670_read(struct i2c_client *c, unsigned char reg,
static int ov7670_write(struct i2c_client *c, unsigned char reg,
unsigned char value)
{
- return i2c_smbus_write_byte_data(c, reg, value);
+ int ret = i2c_smbus_write_byte_data(c, reg, value);
+ if (reg == REG_COM7 && (value & COM7_RESET))
+ msleep(2); /* Wait for reset to run */
+ return ret;
}
@@ -617,7 +619,7 @@ static struct ov7670_win_size {
},
};
-#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
/*
@@ -1183,7 +1185,7 @@ static struct ov7670_control {
.query = ov7670_q_hflip,
},
};
-#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
static struct ov7670_control *ov7670_find_control(__u32 id)
{
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 3fe9fa04cd84..8063e33f1c85 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "ovcamchip_priv.h"
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 1455a8f4e930..0ef73d9d5848 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -353,9 +353,8 @@ static int planb_prepare_open(struct planb *pb)
* PLANB_DUMMY)*sizeof(struct dbdma_cmd)
+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
+MAX_GBUFFERS*sizeof(unsigned int);
- if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+ if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0)
return -ENOMEM;
- memset ((void *) pb->priv_space, 0, size);
pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
DBDMA_ALIGN (pb->priv_space);
pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
@@ -845,21 +844,21 @@ cmd_tab_mask_end:
/*********************************/
static int palette2fmt[] = {
- 0,
- PLANB_GRAY,
- 0,
- 0,
- 0,
- PLANB_COLOUR32,
- PLANB_COLOUR15,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ 0,
+ PLANB_GRAY,
+ 0,
+ 0,
+ 0,
+ PLANB_COLOUR32,
+ PLANB_COLOUR15,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
};
#define PLANB_PALETTE_MAX 15
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 6bbed88d7867..22719ba861ac 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -33,8 +33,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp)
{
if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
- flush_workqueue(mp->workqueue);
- destroy_workqueue(mp->workqueue);
+ if (mp->workqueue) {
+ flush_workqueue(mp->workqueue);
+ destroy_workqueue(mp->workqueue);
+ }
kfree(mp);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index d95a8588e4f8..da6441b88f31 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -26,32 +26,33 @@ extern int pvrusb2_debug;
/* These are listed in *rough* order of decreasing usefulness and
increasing noise level. */
-#define PVR2_TRACE_INFO (1 << 0) // Normal messages
-#define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages
-#define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors
-#define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app
-#define PVR2_TRACE_INIT (1 << 4) // misc initialization steps
-#define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop
-#define PVR2_TRACE_CTL (1 << 6) // commit of control changes
-#define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code
-#define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report
-#define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation
-#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close
-#define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit
-#define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O
-#define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions
-#define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation
-#define PVR2_TRACE_I2C (1 << 15) // I2C related stuff
-#define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules
-#define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging
-#define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter
-#define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details
-#define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation
-#define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management
-#define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system
-#define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow
-#define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions
-#define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes
+#define PVR2_TRACE_INFO (1 << 0) /* Normal messages */
+#define PVR2_TRACE_ERROR_LEGS (1 << 1) /* error messages */
+#define PVR2_TRACE_TOLERANCE (1 << 2) /* track tolerance-affected errors */
+#define PVR2_TRACE_TRAP (1 << 3) /* Trap & report app misbehavior */
+#define PVR2_TRACE_STD (1 << 4) /* Log video standard stuff */
+#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */
+#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */
+#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */
+#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */
+#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */
+#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */
+#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
+#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */
+#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */
+#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */
+#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */
+#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */
+#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */
+#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */
+#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */
+#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */
+#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */
+#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */
+#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */
+#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */
+#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */
+#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index e9da9bb8f8de..6f135f4a2497 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -397,10 +397,22 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
count -= scnt; buf += scnt;
if (!wptr) return -EINVAL;
if (debugifc_match_keyword(wptr,wlen,"fetch")) {
- pvr2_hdw_cpufw_set_enabled(hdw,!0);
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (scnt && wptr) {
+ count -= scnt; buf += scnt;
+ if (debugifc_match_keyword(wptr,wlen,"prom")) {
+ pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
+ } else if (debugifc_match_keyword(wptr,wlen,
+ "ram")) {
+ pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
+ } else {
+ return -EINVAL;
+ }
+ }
+ pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
return 0;
} else if (debugifc_match_keyword(wptr,wlen,"done")) {
- pvr2_hdw_cpufw_set_enabled(hdw,0);
+ pvr2_hdw_cpufw_set_enabled(hdw,0,0);
return 0;
} else {
return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index ce66ab8ff2d8..985d9ae7f5ee 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -238,6 +238,7 @@ struct pvr2_hdw {
// CPU firmware info (used to help find / save firmware data)
char *fw_buffer;
unsigned int fw_size;
+ int fw_cpu_flag; /* True if we are dealing with the CPU */
// Which subsystem pieces have been enabled / configured
unsigned long subsys_enabled_mask;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 1311891e7ee3..27b12b4b5c88 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -492,7 +492,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
cs.controls = &c1;
cs.count = 1;
c1.id = cptr->info->v4l_id;
- ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
VIDIOC_G_EXT_CTRLS);
if (ret) return ret;
*vp = c1.value;
@@ -510,7 +510,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
cs.count = 1;
c1.id = cptr->info->v4l_id;
c1.value = v;
- ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
VIDIOC_S_EXT_CTRLS);
if (ret) return ret;
cptr->hdw->enc_stale = !0;
@@ -1143,6 +1143,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
+
+ if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
+ (!fw_file_defs[hdw->hdw_type].lst)) {
+ hdw->fw1_state = FW1_STATE_OK;
+ return 0;
+ }
+
hdw->fw1_state = FW1_STATE_FAILED; // default result
trace_firmware("pvr2_upload_firmware1");
@@ -1224,6 +1231,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
CX2341X_FIRM_ENC_FILENAME,
};
+ if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
+ (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
+ return 0;
+ }
+
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
@@ -1682,6 +1694,44 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
return result == 0;
}
+struct pvr2_std_hack {
+ v4l2_std_id pat; /* Pattern to match */
+ v4l2_std_id msk; /* Which bits we care about */
+ v4l2_std_id std; /* What additional standards or default to set */
+};
+
+/* This data structure labels specific combinations of standards from
+ tveeprom that we'll try to recognize. If we recognize one, then assume
+ a specified default standard to use. This is here because tveeprom only
+ tells us about available standards not the intended default standard (if
+ any) for the device in question. We guess the default based on what has
+ been reported as available. Note that this is only for guessing a
+ default - which can always be overridden explicitly - and if the user
+ has otherwise named a default then that default will always be used in
+ place of this table. */
+const static struct pvr2_std_hack std_eeprom_maps[] = {
+ { /* PAL(B/G) */
+ .pat = V4L2_STD_B|V4L2_STD_GH,
+ .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G,
+ },
+ { /* NTSC(M) */
+ .pat = V4L2_STD_MN,
+ .std = V4L2_STD_NTSC_M,
+ },
+ { /* PAL(I) */
+ .pat = V4L2_STD_PAL_I,
+ .std = V4L2_STD_PAL_I,
+ },
+ { /* SECAM(L/L') */
+ .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC,
+ .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC,
+ },
+ { /* PAL(D/D1/K) */
+ .pat = V4L2_STD_DK,
+ .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
+ },
+};
+
static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
{
char buf[40];
@@ -1691,7 +1741,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
std1 = get_default_standard(hdw);
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Supported video standard(s) reported by eeprom: %.*s",
bcnt,buf);
@@ -1700,7 +1750,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
std2 = std1 & ~hdw->std_mask_avail;
if (std2) {
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Expanding supported video standards"
" to include: %.*s",
bcnt,buf);
@@ -1711,7 +1761,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
if (std1) {
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Initial video standard forced to %.*s",
bcnt,buf);
hdw->std_mask_cur = std1;
@@ -1720,12 +1770,33 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
return;
}
+ {
+ unsigned int idx;
+ for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) {
+ if (std_eeprom_maps[idx].msk ?
+ ((std_eeprom_maps[idx].pat ^
+ hdw->std_mask_eeprom) &
+ std_eeprom_maps[idx].msk) :
+ (std_eeprom_maps[idx].pat !=
+ hdw->std_mask_eeprom)) continue;
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),
+ std_eeprom_maps[idx].std);
+ pvr2_trace(PVR2_TRACE_STD,
+ "Initial video standard guessed as %.*s",
+ bcnt,buf);
+ hdw->std_mask_cur = std_eeprom_maps[idx].std;
+ hdw->std_dirty = !0;
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return;
+ }
+ }
+
if (hdw->std_enum_cnt > 1) {
// Autoselect the first listed standard
hdw->std_enum_cur = 1;
hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
hdw->std_dirty = !0;
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Initial video standard auto-selected to %s",
hdw->std_defs[hdw->std_enum_cur-1].name);
return;
@@ -1742,29 +1813,35 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
unsigned int idx;
struct pvr2_ctrl *cptr;
int reloadFl = 0;
- if (!reloadFl) {
- reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
- == 0);
- if (reloadFl) {
- pvr2_trace(PVR2_TRACE_INIT,
- "USB endpoint config looks strange"
- "; possibly firmware needs to be loaded");
+ if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+ (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+ if (!reloadFl) {
+ reloadFl =
+ (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+ == 0);
+ if (reloadFl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "USB endpoint config looks strange"
+ "; possibly firmware needs to be"
+ " loaded");
+ }
}
- }
- if (!reloadFl) {
- reloadFl = !pvr2_hdw_check_firmware(hdw);
- if (reloadFl) {
- pvr2_trace(PVR2_TRACE_INIT,
- "Check for FX2 firmware failed"
- "; possibly firmware needs to be loaded");
+ if (!reloadFl) {
+ reloadFl = !pvr2_hdw_check_firmware(hdw);
+ if (reloadFl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Check for FX2 firmware failed"
+ "; possibly firmware needs to be"
+ " loaded");
+ }
}
- }
- if (reloadFl) {
- if (pvr2_upload_firmware1(hdw) != 0) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failure uploading firmware1");
+ if (reloadFl) {
+ if (pvr2_upload_firmware1(hdw) != 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failure uploading firmware1");
+ }
+ return;
}
- return;
}
hdw->fw1_state = FW1_STATE_OK;
@@ -1773,17 +1850,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
}
if (!pvr2_hdw_dev_ok(hdw)) return;
- for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
- request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+ if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
+ for (idx = 0;
+ idx < pvr2_client_lists[hdw->hdw_type].cnt;
+ idx++) {
+ request_module(
+ pvr2_client_lists[hdw->hdw_type].lst[idx]);
+ }
}
- pvr2_hdw_cmd_powerup(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
+ if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+ (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+ pvr2_hdw_cmd_powerup(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
- if (pvr2_upload_firmware2(hdw)){
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
- pvr2_hdw_render_useless(hdw);
- return;
+ if (pvr2_upload_firmware2(hdw)){
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+ pvr2_hdw_render_useless(hdw);
+ return;
+ }
}
// This step MUST happen after the earlier powerup step.
@@ -2172,6 +2257,7 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
/* Destroy hardware interaction structure */
void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
{
+ if (!hdw) return;
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
if (hdw->fw_buffer) {
kfree(hdw->fw_buffer);
@@ -2478,7 +2564,7 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cs.count = 1;
c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
c1.value = hdw->srate_val;
- cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS);
+ cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
}
/* Scan i2c core at this point - before we clear all the dirty
@@ -2604,7 +2690,85 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
} while (0); LOCK_GIVE(hdw->big_lock);
}
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+
+/* Grab EEPROM contents, needed for direct method. */
+#define EEPROM_SIZE 8192
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+ struct i2c_msg msg[2];
+ u8 *eeprom;
+ u8 iadd[2];
+ u8 addr;
+ u16 eepromSize;
+ unsigned int offs;
+ int ret;
+ int mode16 = 0;
+ unsigned pcnt,tcnt;
+ eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+ if (!eeprom) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to allocate memory"
+ " required to read eeprom");
+ return NULL;
+ }
+
+ trace_eeprom("Value for eeprom addr from controller was 0x%x",
+ hdw->eeprom_addr);
+ addr = hdw->eeprom_addr;
+ /* Seems that if the high bit is set, then the *real* eeprom
+ address is shifted right now bit position (noticed this in
+ newer PVR USB2 hardware) */
+ if (addr & 0x80) addr >>= 1;
+
+ /* FX2 documentation states that a 16bit-addressed eeprom is
+ expected if the I2C address is an odd number (yeah, this is
+ strange but it's what they do) */
+ mode16 = (addr & 1);
+ eepromSize = (mode16 ? EEPROM_SIZE : 256);
+ trace_eeprom("Examining %d byte eeprom at location 0x%x"
+ " using %d bit addressing",eepromSize,addr,
+ mode16 ? 16 : 8);
+
+ msg[0].addr = addr;
+ msg[0].flags = 0;
+ msg[0].len = mode16 ? 2 : 1;
+ msg[0].buf = iadd;
+ msg[1].addr = addr;
+ msg[1].flags = I2C_M_RD;
+
+ /* We have to do the actual eeprom data fetch ourselves, because
+ (1) we're only fetching part of the eeprom, and (2) if we were
+ getting the whole thing our I2C driver can't grab it in one
+ pass - which is what tveeprom is otherwise going to attempt */
+ memset(eeprom,0,EEPROM_SIZE);
+ for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+ pcnt = 16;
+ if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+ offs = tcnt + (eepromSize - EEPROM_SIZE);
+ if (mode16) {
+ iadd[0] = offs >> 8;
+ iadd[1] = offs;
+ } else {
+ iadd[0] = offs;
+ }
+ msg[1].len = pcnt;
+ msg[1].buf = eeprom+tcnt;
+ if ((ret = i2c_transfer(&hdw->i2c_adap,
+ msg,ARRAY_SIZE(msg))) != 2) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "eeprom fetch set offs err=%d",ret);
+ kfree(eeprom);
+ return NULL;
+ }
+ }
+ return eeprom;
+}
+
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
+ int prom_flag,
+ int enable_flag)
{
int ret;
u16 address;
@@ -2618,37 +2782,59 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
kfree(hdw->fw_buffer);
hdw->fw_buffer = NULL;
hdw->fw_size = 0;
- /* Now release the CPU. It will disconnect and
- reconnect later. */
- pvr2_hdw_cpureset_assert(hdw,0);
+ if (hdw->fw_cpu_flag) {
+ /* Now release the CPU. It will disconnect
+ and reconnect later. */
+ pvr2_hdw_cpureset_assert(hdw,0);
+ }
break;
}
- pvr2_trace(PVR2_TRACE_FIRMWARE,
- "Preparing to suck out CPU firmware");
- hdw->fw_size = 0x2000;
- hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
- if (!hdw->fw_buffer) {
- hdw->fw_size = 0;
- break;
- }
+ hdw->fw_cpu_flag = (prom_flag == 0);
+ if (hdw->fw_cpu_flag) {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Preparing to suck out CPU firmware");
+ hdw->fw_size = 0x2000;
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
+ if (!hdw->fw_buffer) {
+ hdw->fw_size = 0;
+ break;
+ }
- /* We have to hold the CPU during firmware upload. */
- pvr2_hdw_cpureset_assert(hdw,1);
+ /* We have to hold the CPU during firmware upload. */
+ pvr2_hdw_cpureset_assert(hdw,1);
- /* download the firmware from address 0000-1fff in 2048
- (=0x800) bytes chunk. */
+ /* download the firmware from address 0000-1fff in 2048
+ (=0x800) bytes chunk. */
- pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
- pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
- for(address = 0; address < hdw->fw_size; address += 0x800) {
- ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
- address,0,
- hdw->fw_buffer+address,0x800,HZ);
- if (ret < 0) break;
- }
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Grabbing CPU firmware");
+ pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+ for(address = 0; address < hdw->fw_size;
+ address += 0x800) {
+ ret = usb_control_msg(hdw->usb_dev,pipe,
+ 0xa0,0xc0,
+ address,0,
+ hdw->fw_buffer+address,
+ 0x800,HZ);
+ if (ret < 0) break;
+ }
- pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Done grabbing CPU firmware");
+ } else {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Sucking down EEPROM contents");
+ hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw);
+ if (!hdw->fw_buffer) {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "EEPROM content suck failed.");
+ break;
+ }
+ hdw->fw_size = EEPROM_SIZE;
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Done sucking down EEPROM contents");
+ }
} while (0); LOCK_GIVE(hdw->big_lock);
}
@@ -3272,7 +3458,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
int setFl,u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct list_head *item;
struct pvr2_i2c_client *cp;
struct v4l2_register req;
int stat = 0;
@@ -3285,8 +3470,7 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!v4l2_chip_match_i2c_client(
cp->client,
req.match_type, req.match_chip)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 4dba8d006324..e2f9d5e4cb65 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -197,11 +197,13 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
-/* Enable / disable retrieval of CPU firmware. This must be enabled before
- pvr2_hdw_cpufw_get() will function. Note that doing this may prevent
- the device from running (and leaving this mode may imply a device
- reset). */
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+/* Enable / disable retrieval of CPU firmware or prom contents. This must
+ be enabled before pvr2_hdw_cpufw_get() will function. Note that doing
+ this may prevent the device from running (and leaving this mode may
+ imply a device reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *,
+ int prom_flag,
+ int enable_flag);
/* Return true if we're in a mode for retrieval CPU firmware */
int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 6786d3c0c98b..898c9d2e4cdf 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -389,10 +389,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
ret = -EINVAL;
goto done;
}
- if ((msgs[0].flags & I2C_M_NOSTART)) {
- trace_i2c("i2c refusing I2C_M_NOSTART");
- goto done;
- }
if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
funcp = hdw->i2c_func[msgs[0].addr];
}
@@ -494,14 +490,12 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
cnt = msgs[idx].len;
printk(KERN_INFO
"pvrusb2 i2c xfer %u/%u:"
- " addr=0x%x len=%d %s%s",
+ " addr=0x%x len=%d %s",
idx+1,num,
msgs[idx].addr,
cnt,
(msgs[idx].flags & I2C_M_RD ?
- "read" : "write"),
- (msgs[idx].flags & I2C_M_NOSTART ?
- " nostart" : ""));
+ "read" : "write"));
if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
if (cnt > 8) cnt = 8;
printk(" [");
@@ -534,7 +528,7 @@ static int pvr2_i2c_control(struct i2c_adapter *adapter,
static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
}
static int pvr2_i2c_core_singleton(struct i2c_client *cp,
@@ -576,15 +570,13 @@ int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
{
- struct list_head *item,*nc;
- struct pvr2_i2c_client *cp;
+ struct pvr2_i2c_client *cp, *ncp;
int stat = -EINVAL;
if (!hdw) return stat;
mutex_lock(&hdw->i2c_list_lock);
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
if (!cp->recv_enable) continue;
mutex_unlock(&hdw->i2c_list_lock);
stat = pvr2_i2c_client_cmd(cp,cmd,arg);
@@ -608,13 +600,11 @@ static int handler_check(struct pvr2_i2c_client *cp)
void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
{
- struct list_head *item;
struct pvr2_i2c_client *cp;
mutex_lock(&hdw->i2c_list_lock); do {
struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
memset(vtp,0,sizeof(*vtp));
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!cp->detected_flag) continue;
if (!cp->status_poll) continue;
cp->status_poll(cp);
@@ -636,8 +626,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
{
unsigned long msk;
unsigned int idx;
- struct list_head *item,*nc;
- struct pvr2_i2c_client *cp;
+ struct pvr2_i2c_client *cp, *ncp;
if (!hdw->i2c_linked) return;
if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
@@ -655,9 +644,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
buf = kmalloc(BUFSIZE,GFP_KERNEL);
pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!cp->detected_flag) {
cp->ctl_mask = 0;
pvr2_i2c_probe(hdw,cp);
@@ -693,9 +680,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
"i2c: PEND_STALE (0x%lx)",
hdw->i2c_stale_mask);
hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
m2 = hdw->i2c_stale_mask;
m2 &= cp->ctl_mask;
m2 &= ~cp->pend_mask;
@@ -716,9 +701,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
and update each one. */
pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- list);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
+ list) {
if (!cp->handler) continue;
if (!cp->handler->func_table->update) continue;
pvr2_trace(PVR2_TRACE_I2C_CORE,
@@ -750,10 +734,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
if (!(pm & msk)) continue;
pm &= ~msk;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,
- struct pvr2_i2c_client,
- list);
+ list_for_each_entry(cp, &hdw->i2c_clients,
+ list) {
if (cp->pend_mask & msk) {
cp->pend_mask &= ~msk;
cp->recv_enable = !0;
@@ -777,7 +759,6 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
unsigned long msk,sm,pm;
unsigned int idx;
const struct pvr2_i2c_op *opf;
- struct list_head *item;
struct pvr2_i2c_client *cp;
unsigned int pt = 0;
@@ -796,11 +777,9 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
}
if (sm) pt |= PVR2_I2C_PEND_STALE;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
- if (!handler_check(cp)) continue;
- pt |= PVR2_I2C_PEND_CLIENT;
- }
+ list_for_each_entry(cp, &hdw->i2c_clients, list)
+ if (handler_check(cp))
+ pt |= PVR2_I2C_PEND_CLIENT;
if (pt) {
mutex_lock(&hdw->i2c_list_lock); do {
@@ -888,12 +867,10 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
char *buf,unsigned int maxlen)
{
unsigned int ccnt,bcnt;
- struct list_head *item;
struct pvr2_i2c_client *cp;
ccnt = 0;
mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
bcnt = pvr2_i2c_client_describe(
cp,
(PVR2_I2C_DETAIL_HANDLER|
@@ -931,13 +908,11 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
static int pvr2_i2c_detach_inform(struct i2c_client *client)
{
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
- struct pvr2_i2c_client *cp;
- struct list_head *item,*nc;
+ struct pvr2_i2c_client *cp, *ncp;
unsigned long amask = 0;
int foundfl = 0;
mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
if (cp->client == client) {
trace_i2c("pvr2_i2c_detach"
" [client=%s @ 0x%x ctxt=%p]",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 9ea41c6699bb..ca9e2789c8ca 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -24,7 +24,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
@@ -42,6 +41,7 @@
#define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \
PVR2_TRACE_INFO| \
+ PVR2_TRACE_STD| \
PVR2_TRACE_TOLERANCE| \
PVR2_TRACE_TRAP| \
0)
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index 81de26ba41d9..63e55bb59fcb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -298,7 +298,7 @@ static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
std->id = id;
bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
std->name[bcnt] = 0;
- pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+ pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s",
std->index,std->name);
return !0;
}
@@ -320,11 +320,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
v4l2_std_id idmsk,cmsk,fmsk;
struct v4l2_standard *stddefs;
- if (pvrusb2_debug & PVR2_TRACE_INIT) {
+ if (pvrusb2_debug & PVR2_TRACE_STD) {
char buf[50];
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
pvr2_trace(
- PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+ PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
(int)id,bcnt,buf);
}
@@ -355,7 +355,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
bcnt,buf);
}
- pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+ pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)",
std_cnt);
if (!std_cnt) return NULL; // paranoia
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 7ab79baa1c8c..2ee3c3049e8f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -33,16 +33,16 @@
struct pvr2_sysfs {
struct pvr2_channel channel;
- struct class_device *class_dev;
+ struct device *class_dev;
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc *debugifc;
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
- struct class_device_attribute attr_v4l_minor_number;
- struct class_device_attribute attr_v4l_radio_minor_number;
- struct class_device_attribute attr_unit_number;
- struct class_device_attribute attr_bus_info;
+ struct device_attribute attr_v4l_minor_number;
+ struct device_attribute attr_v4l_radio_minor_number;
+ struct device_attribute attr_unit_number;
+ struct device_attribute attr_bus_info;
int v4l_minor_number_created_ok;
int v4l_radio_minor_number_created_ok;
int unit_number_created_ok;
@@ -51,22 +51,22 @@ struct pvr2_sysfs {
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc {
- struct class_device_attribute attr_debugcmd;
- struct class_device_attribute attr_debuginfo;
+ struct device_attribute attr_debugcmd;
+ struct device_attribute attr_debuginfo;
int debugcmd_created_ok;
int debuginfo_created_ok;
};
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item {
- struct class_device_attribute attr_name;
- struct class_device_attribute attr_type;
- struct class_device_attribute attr_min;
- struct class_device_attribute attr_max;
- struct class_device_attribute attr_enum;
- struct class_device_attribute attr_bits;
- struct class_device_attribute attr_val;
- struct class_device_attribute attr_custom;
+ struct device_attribute attr_name;
+ struct device_attribute attr_type;
+ struct device_attribute attr_min;
+ struct device_attribute attr_max;
+ struct device_attribute attr_enum;
+ struct device_attribute attr_bits;
+ struct device_attribute attr_val;
+ struct device_attribute attr_custom;
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
@@ -80,13 +80,13 @@ struct pvr2_sysfs_class {
struct class class;
};
-static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_name(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
const char *name;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -99,14 +99,14 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}
-static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_type(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
const char *name;
enum pvr2_ctl_type tp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -126,13 +126,13 @@ static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}
-static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_min(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
long val;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -143,13 +143,13 @@ static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}
-static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_max(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
long val;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -160,14 +160,14 @@ static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}
-static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_norm(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
int val,ret;
unsigned int cnt = 0;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -184,14 +184,14 @@ static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
return cnt+1;
}
-static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_custom(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
int val,ret;
unsigned int cnt = 0;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -208,14 +208,14 @@ static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
return cnt+1;
}
-static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_enum(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
long val;
unsigned int bcnt,ccnt,ecnt;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -233,14 +233,14 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
return bcnt;
}
-static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_bits(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
int valid_bits,msk;
unsigned int bcnt,ccnt;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -278,23 +278,23 @@ static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
return ret;
}
-static ssize_t store_val_norm(int id,struct class_device *class_dev,
+static ssize_t store_val_norm(int id,struct device *class_dev,
const char *buf,size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
ret = store_val_any(id,0,sfp,buf,count);
if (!ret) ret = count;
return ret;
}
-static ssize_t store_val_custom(int id,struct class_device *class_dev,
+static ssize_t store_val_custom(int id,struct device *class_dev,
const char *buf,size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
ret = store_val_any(id,1,sfp,buf,count);
if (!ret) ret = count;
return ret;
@@ -304,7 +304,7 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev,
Mike Isely <isely@pobox.com> 30-April-2005
This next batch of horrible preprocessor hackery is needed because the
- kernel's class_device_attribute mechanism fails to pass the actual
+ kernel's device_attribute mechanism fails to pass the actual
attribute through to the show / store functions, which means we have no
way to package up any attribute-specific parameters, like for example the
control id. So we work around this brain-damage by encoding the control
@@ -314,11 +314,13 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev,
*/
#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \
+static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
+struct device_attribute *attr, char *buf) \
{ return sf_name(ctl_id,class_dev,buf); }
#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \
+static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
+struct device_attribute *attr, const char *buf, size_t count) \
{ return sf_name(ctl_id,class_dev,buf,count); }
#define CREATE_BATCH(ctl_id) \
@@ -395,17 +397,27 @@ CREATE_BATCH(58)
CREATE_BATCH(59)
struct pvr2_sysfs_func_set {
- ssize_t (*show_name)(struct class_device *,char *);
- ssize_t (*show_type)(struct class_device *,char *);
- ssize_t (*show_min)(struct class_device *,char *);
- ssize_t (*show_max)(struct class_device *,char *);
- ssize_t (*show_enum)(struct class_device *,char *);
- ssize_t (*show_bits)(struct class_device *,char *);
- ssize_t (*show_val_norm)(struct class_device *,char *);
- ssize_t (*store_val_norm)(struct class_device *,
+ ssize_t (*show_name)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_type)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_min)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_max)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_enum)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_bits)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_val_norm)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*store_val_norm)(struct device *,
+ struct device_attribute *attr,
const char *,size_t);
- ssize_t (*show_val_custom)(struct class_device *,char *);
- ssize_t (*store_val_custom)(struct class_device *,
+ ssize_t (*show_val_custom)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*store_val_custom)(struct device *,
+ struct device_attribute *attr,
const char *,size_t);
};
@@ -597,9 +609,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
}
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-static ssize_t debuginfo_show(struct class_device *,char *);
-static ssize_t debugcmd_show(struct class_device *,char *);
-static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
+static ssize_t debuginfo_show(struct device *, struct device_attribute *,
+ char *);
+static ssize_t debugcmd_show(struct device *, struct device_attribute *,
+ char *);
+static ssize_t debugcmd_store(struct device *, struct device_attribute *,
+ const char *, size_t count);
static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
{
@@ -616,16 +631,16 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
dip->attr_debuginfo.attr.mode = S_IRUGO;
dip->attr_debuginfo.show = debuginfo_show;
sfp->debugifc = dip;
- ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+ ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
dip->debugcmd_created_ok = !0;
}
- ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
dip->debuginfo_created_ok = !0;
@@ -637,11 +652,11 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
{
if (!sfp->debugifc) return;
if (sfp->debugifc->debuginfo_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->debugifc->attr_debuginfo);
}
if (sfp->debugifc->debugcmd_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->debugifc->attr_debugcmd);
}
kfree(sfp->debugifc);
@@ -683,7 +698,7 @@ static void pvr2_sysfs_class_release(struct class *class)
}
-static void pvr2_sysfs_release(struct class_device *class_dev)
+static void pvr2_sysfs_release(struct device *class_dev)
{
pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
kfree(class_dev);
@@ -698,32 +713,33 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
pvr2_sysfs_tear_down_controls(sfp);
if (sfp->bus_info_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_bus_info);
}
if (sfp->v4l_minor_number_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
}
if (sfp->v4l_radio_minor_number_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_v4l_radio_minor_number);
}
if (sfp->unit_number_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_unit_number);
}
pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
- sfp->class_dev->class_data = NULL;
- class_device_unregister(sfp->class_dev);
+ sfp->class_dev->driver_data = NULL;
+ device_unregister(sfp->class_dev);
sfp->class_dev = NULL;
}
-static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
+static ssize_t v4l_minor_number_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -731,21 +747,23 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
}
-static ssize_t bus_info_show(struct class_device *class_dev,char *buf)
+static ssize_t bus_info_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%s\n",
pvr2_hdw_get_bus_info(sfp->channel.hdw));
}
-static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
+ struct device_attribute *attr,
char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -753,10 +771,11 @@ static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
}
-static ssize_t unit_number_show(struct class_device *class_dev,char *buf)
+static ssize_t unit_number_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
pvr2_hdw_get_unit_number(sfp->channel.hdw));
@@ -767,7 +786,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
struct pvr2_sysfs_class *class_ptr)
{
struct usb_device *usb_dev;
- struct class_device *class_dev;
+ struct device *class_dev;
int ret;
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
@@ -779,23 +798,23 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
class_dev->class = &class_ptr->class;
if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
- snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu",
+ snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu",
pvr2_hdw_get_sn(sfp->channel.hdw));
} else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
- snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c",
+ snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c",
pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
} else {
kfree(class_dev);
return;
}
- class_dev->dev = &usb_dev->dev;
+ class_dev->parent = &usb_dev->dev;
sfp->class_dev = class_dev;
- class_dev->class_data = sfp;
- ret = class_device_register(class_dev);
+ class_dev->driver_data = sfp;
+ ret = device_register(class_dev);
if (ret) {
- printk(KERN_ERR "%s: class_device_register failed\n",
+ printk(KERN_ERR "%s: device_register failed\n",
__FUNCTION__);
kfree(class_dev);
return;
@@ -805,10 +824,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
sfp->attr_v4l_minor_number.store = NULL;
- ret = class_device_create_file(sfp->class_dev,
+ ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->v4l_minor_number_created_ok = !0;
@@ -818,10 +837,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
sfp->attr_v4l_radio_minor_number.store = NULL;
- ret = class_device_create_file(sfp->class_dev,
+ ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_radio_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->v4l_radio_minor_number_created_ok = !0;
@@ -831,9 +850,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_unit_number.attr.mode = S_IRUGO;
sfp->attr_unit_number.show = unit_number_show;
sfp->attr_unit_number.store = NULL;
- ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->unit_number_created_ok = !0;
@@ -843,10 +862,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_bus_info.attr.mode = S_IRUGO;
sfp->attr_bus_info.show = bus_info_show;
sfp->attr_bus_info.store = NULL;
- ret = class_device_create_file(sfp->class_dev,
+ ret = device_create_file(sfp->class_dev,
&sfp->attr_bus_info);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->bus_info_created_ok = !0;
@@ -886,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
}
-static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
- int numenvp,char *buf,int size)
+static int pvr2_sysfs_hotplug(struct device *d,
+ struct kobj_uevent_env *env)
{
/* Even though we don't do anything here, we still need this function
because sysfs will still try to call it. */
@@ -902,8 +921,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
- clp->class.release = pvr2_sysfs_release;
- clp->class.uevent = pvr2_sysfs_hotplug;
+ clp->class.dev_release = pvr2_sysfs_release;
+ clp->class.dev_uevent = pvr2_sysfs_hotplug;
if (class_register(&clp->class)) {
pvr2_sysfs_trace(
"Registration failed for pvr2_sysfs_class id=%p",clp);
@@ -921,32 +940,35 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
+static ssize_t debuginfo_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
pvr2_hdw_trigger_module_log(sfp->channel.hdw);
return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
}
-static ssize_t debugcmd_show(struct class_device *class_dev,char *buf)
+static ssize_t debugcmd_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
}
-static ssize_t debugcmd_store(struct class_device *class_dev,
- const char *buf,size_t count)
+static ssize_t debugcmd_store(struct device *class_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 338ced7188f2..ea53316d2111 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1648,7 +1648,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
ARG_OUT(cmd)
break;
}
- /*
+ /*
case VIDIOCPWCGVIDTABLE:
{
ARG_DEF(struct pwc_table_init_buffer, table);
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 085332a503de..0b67d4ec0318 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -64,7 +64,6 @@
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <asm/io.h>
-#include <linux/moduleparam.h>
#include "pwc.h"
#include "pwc-kiara.h"
@@ -127,9 +126,9 @@ static struct usb_driver pwc_driver = {
static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
- int pwc_mbufs = 2; /* Default number of mmap() buffers */
+ int pwc_mbufs = 2; /* Default number of mmap() buffers */
#ifdef CONFIG_USB_PWC_DEBUG
- int pwc_trace = PWC_DEBUG_LEVEL;
+ int pwc_trace = PWC_DEBUG_LEVEL;
#endif
static int power_save = 0;
static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
@@ -908,31 +907,49 @@ int pwc_isoc_init(struct pwc_device *pdev)
return 0;
}
-void pwc_isoc_cleanup(struct pwc_device *pdev)
+static void pwc_iso_stop(struct pwc_device *pdev)
{
int i;
- PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
- if (pdev == NULL)
- return;
- if (pdev->iso_init == 0)
- return;
-
/* Unlinking ISOC buffers one by one */
for (i = 0; i < MAX_ISO_BUFS; i++) {
struct urb *urb;
urb = pdev->sbuf[i].urb;
if (urb != 0) {
- if (pdev->iso_init) {
- PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
- usb_kill_urb(urb);
- }
+ PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
+ usb_kill_urb(urb);
+ }
+ }
+}
+
+static void pwc_iso_free(struct pwc_device *pdev)
+{
+ int i;
+
+ /* Freeing ISOC buffers one by one */
+ for (i = 0; i < MAX_ISO_BUFS; i++) {
+ struct urb *urb;
+
+ urb = pdev->sbuf[i].urb;
+ if (urb != 0) {
PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
}
}
+}
+
+void pwc_isoc_cleanup(struct pwc_device *pdev)
+{
+ PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
+ if (pdev == NULL)
+ return;
+ if (pdev->iso_init == 0)
+ return;
+
+ pwc_iso_stop(pdev);
+ pwc_iso_free(pdev);
/* Stop camera, but only if we are sure the camera is still there (unplug
is signalled by EPIPE)
@@ -979,20 +996,22 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
/*********
* sysfs
*********/
-static struct pwc_device *cd_to_pwc(struct class_device *cd)
+static struct pwc_device *cd_to_pwc(struct device *cd)
{
struct video_device *vdev = to_video_device(cd);
return video_get_drvdata(vdev);
}
-static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+static ssize_t show_pan_tilt(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pwc_device *pdev = cd_to_pwc(class_dev);
return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
}
-static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
- size_t count)
+static ssize_t store_pan_tilt(struct device *class_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pwc_device *pdev = cd_to_pwc(class_dev);
int pan, tilt;
@@ -1008,10 +1027,11 @@ static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
return ret;
return strlen(buf);
}
-static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
- store_pan_tilt);
+static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+ store_pan_tilt);
-static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+static ssize_t show_snapshot_button_status(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pwc_device *pdev = cd_to_pwc(class_dev);
int status = pdev->snapshot_button_status;
@@ -1019,26 +1039,26 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char
return sprintf(buf, "%d\n", status);
}
-static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
- NULL);
+static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+ NULL);
static int pwc_create_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
int rc;
- rc = video_device_create_file(vdev, &class_device_attr_button);
+ rc = video_device_create_file(vdev, &dev_attr_button);
if (rc)
goto err;
if (pdev->features & FEATURE_MOTOR_PANTILT) {
- rc = video_device_create_file(vdev,&class_device_attr_pan_tilt);
+ rc = video_device_create_file(vdev, &dev_attr_pan_tilt);
if (rc) goto err_button;
}
return 0;
err_button:
- video_device_remove_file(vdev, &class_device_attr_button);
+ video_device_remove_file(vdev, &dev_attr_button);
err:
return rc;
}
@@ -1047,8 +1067,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
if (pdev->features & FEATURE_MOTOR_PANTILT)
- video_device_remove_file(vdev, &class_device_attr_pan_tilt);
- video_device_remove_file(vdev, &class_device_attr_button);
+ video_device_remove_file(vdev, &dev_attr_pan_tilt);
+ video_device_remove_file(vdev, &dev_attr_button);
}
#ifdef CONFIG_USB_PWC_DEBUG
@@ -1099,7 +1119,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
return -EBUSY;
}
- down(&pdev->modlock);
+ mutex_lock(&pdev->modlock);
if (!pdev->usb_init) {
PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
@@ -1131,7 +1151,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (i < 0) {
PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1172,7 +1192,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (i) {
PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1181,7 +1201,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1191,20 +1211,28 @@ static int pwc_video_open(struct inode *inode, struct file *file)
pdev->vopen++;
file->private_data = vdev;
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
return 0;
}
+
+static void pwc_cleanup(struct pwc_device *pdev)
+{
+ pwc_remove_sysfs_files(pdev->vdev);
+ video_unregister_device(pdev->vdev);
+}
+
/* Note that all cleanup is done in the reverse order as in _open */
static int pwc_video_close(struct inode *inode, struct file *file)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
- int i;
+ int i, hint;
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
+ lock_kernel();
pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0)
PWC_DEBUG_MODULE("video_close() called on closed device?\n");
@@ -1225,7 +1253,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
pwc_free_buffers(pdev);
/* Turn off LEDS and power down camera, but only when not unplugged */
- if (pdev->error_status != EPIPE) {
+ if (!pdev->unplugged) {
/* Turn LEDs off */
if (pwc_set_leds(pdev, 0, 0) < 0)
PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
@@ -1234,9 +1262,19 @@ static int pwc_video_close(struct inode *inode, struct file *file)
if (i < 0)
PWC_ERROR("Failed to power down camera (%d)\n", i);
}
+ pdev->vopen--;
+ PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+ } else {
+ pwc_cleanup(pdev);
+ /* Free memory (don't set pdev to 0 just yet) */
+ kfree(pdev);
+ /* search device_hint[] table if we occupy a slot, by any chance */
+ for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+ if (device_hint[hint].pdev == pdev)
+ device_hint[hint].pdev = NULL;
}
- pdev->vopen--;
- PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+ unlock_kernel();
+
return 0;
}
@@ -1259,7 +1297,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
struct pwc_device *pdev;
int noblock = file->f_flags & O_NONBLOCK;
DECLARE_WAITQUEUE(wait, current);
- int bytes_to_read;
+ int bytes_to_read, rv = 0;
void *image_buffer_addr;
PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
@@ -1269,8 +1307,12 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
pdev = vdev->priv;
if (pdev == NULL)
return -EFAULT;
- if (pdev->error_status)
- return -pdev->error_status; /* Something happened, report what. */
+
+ mutex_lock(&pdev->modlock);
+ if (pdev->error_status) {
+ rv = -pdev->error_status; /* Something happened, report what. */
+ goto err_out;
+ }
/* In case we're doing partial reads, we don't have to wait for a frame */
if (pdev->image_read_pos == 0) {
@@ -1281,17 +1323,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
if (pdev->error_status) {
remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING);
- return -pdev->error_status ;
+ rv = -pdev->error_status ;
+ goto err_out;
}
if (noblock) {
remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING);
- return -EWOULDBLOCK;
+ rv = -EWOULDBLOCK;
+ goto err_out;
}
if (signal_pending(current)) {
remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING);
- return -ERESTARTSYS;
+ rv = -ERESTARTSYS;
+ goto err_out;
}
schedule();
set_current_state(TASK_INTERRUPTIBLE);
@@ -1300,8 +1345,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
set_current_state(TASK_RUNNING);
/* Decompress and release frame */
- if (pwc_handle_frame(pdev))
- return -EFAULT;
+ if (pwc_handle_frame(pdev)) {
+ rv = -EFAULT;
+ goto err_out;
+ }
}
PWC_DEBUG_READ("Copying data to user space.\n");
@@ -1316,14 +1363,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
image_buffer_addr = pdev->image_data;
image_buffer_addr += pdev->images[pdev->fill_image].offset;
image_buffer_addr += pdev->image_read_pos;
- if (copy_to_user(buf, image_buffer_addr, count))
- return -EFAULT;
+ if (copy_to_user(buf, image_buffer_addr, count)) {
+ rv = -EFAULT;
+ goto err_out;
+ }
pdev->image_read_pos += count;
if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
pdev->image_read_pos = 0;
pwc_next_image(pdev);
}
+ mutex_unlock(&pdev->modlock);
return count;
+err_out:
+ mutex_unlock(&pdev->modlock);
+ return rv;
}
static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
@@ -1349,7 +1402,20 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
static int pwc_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+ struct video_device *vdev = file->private_data;
+ struct pwc_device *pdev;
+ int r = -ENODEV;
+
+ if (!vdev)
+ goto out;
+ pdev = vdev->priv;
+
+ mutex_lock(&pdev->modlock);
+ if (!pdev->unplugged)
+ r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+ mutex_unlock(&pdev->modlock);
+out:
+ return r;
}
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1685,7 +1751,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->angle_range.tilt_max = 2500;
}
- init_MUTEX(&pdev->modlock);
+ mutex_init(&pdev->modlock);
spin_lock_init(&pdev->ptrlock);
pdev->udev = udev;
@@ -1791,26 +1857,28 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
/* Alert waiting processes */
wake_up_interruptible(&pdev->frameq);
/* Wait until device is closed */
- while (pdev->vopen)
- schedule();
- /* Device is now closed, so we can safely unregister it */
- PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
- pwc_remove_sysfs_files(pdev->vdev);
- video_unregister_device(pdev->vdev);
-
- /* Free memory (don't set pdev to 0 just yet) */
- kfree(pdev);
+ if(pdev->vopen) {
+ mutex_lock(&pdev->modlock);
+ pdev->unplugged = 1;
+ mutex_unlock(&pdev->modlock);
+ pwc_iso_stop(pdev);
+ } else {
+ /* Device is closed, so we can safely unregister it */
+ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+ pwc_cleanup(pdev);
+ /* Free memory (don't set pdev to 0 just yet) */
+ kfree(pdev);
disconnect_out:
- /* search device_hint[] table if we occupy a slot, by any chance */
- for (hint = 0; hint < MAX_DEV_HINTS; hint++)
- if (device_hint[hint].pdev == pdev)
- device_hint[hint].pdev = NULL;
+ /* search device_hint[] table if we occupy a slot, by any chance */
+ for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+ if (device_hint[hint].pdev == pdev)
+ device_hint[hint].pdev = NULL;
+ }
unlock_kernel();
}
-
/* *grunt* We have to do atoi ourselves :-( */
static int pwc_atoi(const char *s)
{
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index acbb9312960a..8e8e5b27e77e 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -31,7 +31,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/version.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/errno.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
@@ -193,6 +193,7 @@ struct pwc_device
char vsnapshot; /* snapshot mode */
char vsync; /* used by isoc handler */
char vmirror; /* for ToUCaM series */
+ char unplugged;
int cmd_len;
unsigned char cmd_buf[13];
@@ -244,7 +245,7 @@ struct pwc_device
int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */
int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */
- struct semaphore modlock; /* to prevent races in video_open(), etc */
+ struct mutex modlock; /* to prevent races in video_open(), etc */
spinlock_t ptrlock; /* for manipulating the buffer pointers */
/*** motorized pan/tilt feature */
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f2a2f34cd626..17f1e2e9a66b 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -86,9 +86,9 @@ static const int disp_modes[8][3] =
-#define PAGE_WAIT (300*HZ/1000) /* Time between requesting page and */
+#define PAGE_WAIT msecs_to_jiffies(300) /* Time between requesting page and */
/* checking status bits */
-#define PGBUF_EXPIRE (15*HZ) /* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000) /* Time to wait before retransmitting */
/* page regardless of infobits */
typedef struct {
u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
@@ -115,8 +115,8 @@ struct saa5249_device
#define CCTWR 34 /* I²C write/read-address of vtx-chip */
#define CCTRD 35
#define NOACK_REPEAT 10 /* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20) /* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000) /* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY msecs_to_jiffies(50) /* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30) /* Time to wait for ready signal of I2C-bus interface */
#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */
#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 92eabf88a09b..72e344a12c79 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -406,6 +406,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
kfree(s);
return -ENOMEM;
}
+ spin_lock_init(&s->lock);
s->client = client_template;
s->block_count = 0;
s->wr_index = 0;
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 676b9970eb2e..061134a7ba9f 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -208,7 +208,7 @@ determine_norm (struct i2c_client *client)
saa7110_write_block(client, initseq, sizeof(initseq));
saa7110_selmux(client, decoder->input);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ schedule_timeout(msecs_to_jiffies(250));
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
if (status & 0x40) {
@@ -249,7 +249,7 @@ determine_norm (struct i2c_client *client)
//saa7110_write(client,0x2E,0x9A);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ schedule_timeout(msecs_to_jiffies(250));
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index c1a392e47170..7ae2d646d000 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -37,23 +37,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0644);
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 87c3144ec7fc..677df51de1a9 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -35,28 +35,26 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
-
#include <linux/slab.h>
-
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(x) (x)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 9f986930490f..e35ef321ec71 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -332,11 +332,11 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
if (!enable)
return 0;
- state->vps_data[0] = data->data[4];
- state->vps_data[1] = data->data[10];
- state->vps_data[2] = data->data[11];
- state->vps_data[3] = data->data[12];
- state->vps_data[4] = data->data[13];
+ state->vps_data[0] = data->data[2];
+ state->vps_data[1] = data->data[8];
+ state->vps_data[2] = data->data[9];
+ state->vps_data[3] = data->data[10];
+ state->vps_data[4] = data->data[11];
v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n",
state->vps_data[0], state->vps_data[1],
state->vps_data[2], state->vps_data[3],
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 309dca368f4a..d6d8d660196d 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_SAA7134
tristate "Philips SAA7134 support"
depends on VIDEO_DEV && PCI && I2C
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_IR
select VIDEO_TUNER
select CRC32
@@ -38,9 +38,9 @@ config VIDEO_SAA7134_OSS
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
- select VIDEO_BUF_DVB
+ select VIDEOBUF_DVB
select FW_LOADER
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_NXT200X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ffb0f647a86d..c6f7279669c1 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
#include <linux/module.h>
#include <sound/driver.h>
#include <sound/core.h>
@@ -75,7 +74,8 @@ typedef struct snd_card_saa7134 {
struct saa7134_dev *dev;
unsigned long iobase;
- int irq;
+ s16 irq;
+ u16 mute_was_on;
spinlock_t lock;
} snd_card_saa7134_t;
@@ -312,7 +312,7 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
dev->dmasound.blksize = 0;
dev->dmasound.bufsize = 0;
- return 0;
+ return 0;
}
@@ -589,8 +589,10 @@ static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
struct saa7134_dev *dev = saa7134->dev;
- dev->ctl_mute = 1;
- saa7134_tvaudio_setmute(dev);
+ if (saa7134->mute_was_on) {
+ dev->ctl_mute = 1;
+ saa7134_tvaudio_setmute(dev);
+ }
return 0;
}
@@ -637,8 +639,11 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
runtime->private_free = snd_card_saa7134_runtime_free;
runtime->hw = snd_card_saa7134_capture;
- dev->ctl_mute = 0;
- saa7134_tvaudio_setmute(dev);
+ if (dev->ctl_mute != 0) {
+ saa7134->mute_was_on = 1;
+ dev->ctl_mute = 0;
+ saa7134_tvaudio_setmute(dev);
+ }
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 50f15adfa7c8..a4c192fb4e41 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -32,6 +32,7 @@ static char name_mute[] = "mute";
static char name_radio[] = "Radio";
static char name_tv[] = "Television";
static char name_tv_mono[] = "TV (mono only)";
+static char name_comp[] = "Composite";
static char name_comp1[] = "Composite1";
static char name_comp2[] = "Composite2";
static char name_comp3[] = "Composite3";
@@ -400,7 +401,7 @@ struct saa7134_board saa7134_boards[] = {
.inputs = {{
.name = name_tv,
.vmux = 1,
- .amux = LINE2,
+ .amux = TV,
.tv = 1,
.gpio = 0x20000,
},{
@@ -1535,20 +1536,15 @@ struct saa7134_board saa7134_boards[] = {
.tv = 1,
.gpio = 0x00,
},{
- .name = name_comp1,
- .vmux = 0,
- .amux = LINE2,
- .gpio = 0x00,
- },{
- .name = name_comp2,
+ .name = name_comp,
.vmux = 3,
- .amux = LINE2,
- .gpio = 0x00,
+ .amux = LINE1,
+ .gpio = 0x02,
},{
.name = name_svideo,
.vmux = 8,
- .amux = LINE2,
- .gpio = 0x00,
+ .amux = LINE1,
+ .gpio = 0x02,
}},
.radio = {
.name = name_radio,
@@ -2771,6 +2767,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 1 << 21,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -2781,13 +2778,18 @@ struct saa7134_board saa7134_boards[] = {
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .name = name_comp2,
.vmux = 0,
.amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
}},
.radio = {
.name = name_radio,
- .amux = LINE1,
+ .amux = TV,
+ .gpio = 0x0200000,
},
},
[SAA7134_BOARD_KWORLD_DVBT_210] = {
@@ -2820,7 +2822,7 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_KWORLD_ATSC110] = {
- .name = "Kworld ATSC110",
+ .name = "Kworld ATSC110/115",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_TUV1236D,
.radio_type = UNSET,
@@ -2896,7 +2898,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
},
[SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
- .name = "LifeView FlyDVB-T Hybrid Cardbus",
+ .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
@@ -3502,6 +3504,54 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_10MOONSTVMASTER3] = {
+ /* Tony Wan <aloha_cn@hotmail.com> */
+ .name = "10MOONS TM300 TV Card",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x7000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ }},
+ .mute = {
+ .name = name_mute,
+ .amux = LINE2,
+ .gpio = 0x3000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_SUPER_007] = {
+ .name = "Avermedia Super 007",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 0,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv, /* FIXME: analog tv untested */
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }},
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4034,6 +4084,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_KWORLD_ATSC110,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0x7352,
+ .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1461,
.subdevice = 0x7360,
@@ -4219,6 +4275,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x2003, /* OEM cardbus */
.driver_data = SAA7134_BOARD_SABRENT_TV_PCB05,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2304,
+ .driver_data = SAA7134_BOARD_10MOONSTVMASTER3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */
+ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x3502,
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4330,6 +4404,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_A16AR:
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ case SAA7134_BOARD_10MOONSTVMASTER3:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4525,6 +4600,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_PHILIPS_TIGER:
case SAA7134_BOARD_PHILIPS_TIGER_S:
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
{
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 25f84701a8e8..1a4a24471f20 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -32,6 +31,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/dma-mapping.h>
+#include <linux/pm.h>
#include "saa7134-reg.h"
#include "saa7134.h"
@@ -237,9 +237,10 @@ int saa7134_buffer_startpage(struct saa7134_buf *buf)
unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
{
unsigned long base;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
base = saa7134_buffer_startpage(buf) * 4096;
- base += buf->vb.dma.sglist[0].offset;
+ base += dma->sglist[0].offset;
return base;
}
@@ -287,11 +288,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -391,6 +393,32 @@ void saa7134_buffer_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock,flags);
}
+/* resends a current buffer in queue after resume */
+
+int saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
+{
+ struct saa7134_buf *buf, *next;
+
+ assert_spin_locked(&dev->slock);
+
+ buf = q->curr;
+ next = buf;
+ dprintk("buffer_requeue\n");
+
+ if (!buf)
+ return 0;
+
+ dprintk("buffer_requeue : resending active buffers \n");
+
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ vb.queue);
+ buf->activate(dev, buf, next);
+
+ return 0;
+}
+
/* ------------------------------------------------------------------ */
int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -401,6 +429,9 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
assert_spin_locked(&dev->slock);
+ if (dev->inresume)
+ return 0;
+
/* video capture -- dma 0 + video task A */
if (dev->video_q.curr) {
task |= 0x01;
@@ -560,8 +591,10 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
print_irqstatus(dev,loop,report,status);
- if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */)
- saa7134_irq_video_intl(dev);
+ if ((report & SAA7134_IRQ_REPORT_RDCAP) ||
+ (report & SAA7134_IRQ_REPORT_INTL))
+ saa7134_irq_video_signalchange(dev);
+
if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
(status & 0x60) == 0)
@@ -646,6 +679,39 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
/* ------------------------------------------------------------------ */
/* early init (no i2c, no irq) */
+
+static int saa7134_hw_enable1(struct saa7134_dev *dev)
+{
+ /* RAM FIFO config */
+ saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
+ saa_writel(SAA7134_THRESHOULD, 0x02020202);
+
+ /* enable audio + video processing */
+ saa_writel(SAA7134_MAIN_CTRL,
+ SAA7134_MAIN_CTRL_VPLLE |
+ SAA7134_MAIN_CTRL_APLLE |
+ SAA7134_MAIN_CTRL_EXOSC |
+ SAA7134_MAIN_CTRL_EVFE1 |
+ SAA7134_MAIN_CTRL_EVFE2 |
+ SAA7134_MAIN_CTRL_ESFE |
+ SAA7134_MAIN_CTRL_EBDAC);
+
+ /*
+ * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+ * OSS initialization writes to registers via the audio DSP; these
+ * writes will fail unless the audio clock has been started. At worst,
+ * audio will not work.
+ */
+
+ /* enable peripheral devices */
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+
+ /* set vertical line numbering start (vbi needs this) */
+ saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+
+ return 0;
+}
+
static int saa7134_hwinit1(struct saa7134_dev *dev)
{
dprintk("hwinit1\n");
@@ -662,44 +728,16 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa7134_ts_init1(dev);
saa7134_input_init1(dev);
- /* RAM FIFO config */
- saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
- saa_writel(SAA7134_THRESHOULD,0x02020202);
-
- /* enable audio + video processing */
- saa_writel(SAA7134_MAIN_CTRL,
- SAA7134_MAIN_CTRL_VPLLE |
- SAA7134_MAIN_CTRL_APLLE |
- SAA7134_MAIN_CTRL_EXOSC |
- SAA7134_MAIN_CTRL_EVFE1 |
- SAA7134_MAIN_CTRL_EVFE2 |
- SAA7134_MAIN_CTRL_ESFE |
- SAA7134_MAIN_CTRL_EBDAC);
-
- /*
- * Initialize OSS _after_ enabling audio clock PLL and audio processing.
- * OSS initialization writes to registers via the audio DSP; these
- * writes will fail unless the audio clock has been started. At worst,
- * audio will not work.
- */
-
- /* enable peripheral devices */
- saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
-
- /* set vertical line numbering start (vbi needs this) */
- saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+ saa7134_hw_enable1(dev);
return 0;
}
/* late init (with i2c + irq) */
-static int saa7134_hwinit2(struct saa7134_dev *dev)
+static int saa7134_hw_enable2(struct saa7134_dev *dev)
{
- unsigned int irq2_mask;
- dprintk("hwinit2\n");
- saa7134_video_init2(dev);
- saa7134_tvaudio_init2(dev);
+ unsigned int irq2_mask;
/* enable IRQ's */
irq2_mask =
@@ -725,6 +763,20 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
return 0;
}
+static int saa7134_hwinit2(struct saa7134_dev *dev)
+{
+
+ dprintk("hwinit2\n");
+
+ saa7134_video_init2(dev);
+ saa7134_tvaudio_init2(dev);
+
+ saa7134_hw_enable2(dev);
+
+ return 0;
+}
+
+
/* shutdown */
static int saa7134_hwfini(struct saa7134_dev *dev)
{
@@ -838,7 +890,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct saa7134_dev *dev;
- struct list_head *item;
struct saa7134_mpeg_ops *mops;
int err;
@@ -1020,15 +1071,13 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
saa7134_devcount++;
mutex_lock(&devlist_lock);
- list_for_each(item,&mops_list) {
- mops = list_entry(item, struct saa7134_mpeg_ops, next);
+ list_for_each_entry(mops, &mops_list, next)
mpeg_ops_attach(mops, dev);
- }
list_add_tail(&dev->devlist,&saa7134_devlist);
mutex_unlock(&devlist_lock);
/* check for signal */
- saa7134_irq_video_intl(dev);
+ saa7134_irq_video_signalchange(dev);
if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
saa7134_dmasound_init(dev);
@@ -1057,7 +1106,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
{
struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
- struct list_head *item;
struct saa7134_mpeg_ops *mops;
/* Release DMA sound modules if present */
@@ -1086,10 +1134,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
/* unregister */
mutex_lock(&devlist_lock);
list_del(&dev->devlist);
- list_for_each(item,&mops_list) {
- mops = list_entry(item, struct saa7134_mpeg_ops, next);
+ list_for_each_entry(mops, &mops_list, next)
mpeg_ops_detach(mops, dev);
- }
mutex_unlock(&devlist_lock);
saa7134_devcount--;
@@ -1117,18 +1163,79 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
+static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+
+ struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+
+ /* disable overlay - apps should enable it explicitly on resume*/
+ dev->ovenable = 0;
+
+ /* Disable interrupts, DMA, and rest of the chip*/
+ saa_writel(SAA7134_IRQ1, 0);
+ saa_writel(SAA7134_IRQ2, 0);
+ saa_writel(SAA7134_MAIN_CTRL, 0);
+
+ pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+ pci_save_state(pci_dev);
+
+ return 0;
+}
+
+static int saa7134_resume(struct pci_dev *pci_dev)
+{
+
+ struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+ unsigned int flags;
+
+ pci_restore_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D0);
+
+ /* Do things that are done in saa7134_initdev ,
+ except of initializing memory structures.*/
+
+ dev->inresume = 1;
+ saa7134_board_init1(dev);
+
+ if (saa7134_boards[dev->board].video_out)
+ saa7134_videoport_init(dev);
+
+ if (card_has_mpeg(dev))
+ saa7134_ts_init_hw(dev);
+
+ saa7134_hw_enable1(dev);
+ saa7134_set_decoder(dev);
+ saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+ saa7134_board_init2(dev);
+ saa7134_hw_enable2(dev);
+
+ saa7134_tvaudio_setmute(dev);
+ saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+ saa7134_enable_i2s(dev);
+
+ /*resume unfinished buffer(s)*/
+ spin_lock_irqsave(&dev->slock, flags);
+ saa7134_buffer_requeue(dev, &dev->video_q);
+ saa7134_buffer_requeue(dev, &dev->vbi_q);
+ saa7134_buffer_requeue(dev, &dev->ts_q);
+
+ /* start DMA now*/
+ dev->inresume = 0;
+ saa7134_set_dmabits(dev);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ return 0;
+}
+
/* ----------------------------------------------------------- */
int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
{
- struct list_head *item;
struct saa7134_dev *dev;
mutex_lock(&devlist_lock);
- list_for_each(item,&saa7134_devlist) {
- dev = list_entry(item, struct saa7134_dev, devlist);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
mpeg_ops_attach(ops, dev);
- }
list_add_tail(&ops->next,&mops_list);
mutex_unlock(&devlist_lock);
return 0;
@@ -1136,15 +1243,12 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
{
- struct list_head *item;
struct saa7134_dev *dev;
mutex_lock(&devlist_lock);
list_del(&ops->next);
- list_for_each(item,&saa7134_devlist) {
- dev = list_entry(item, struct saa7134_dev, devlist);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
mpeg_ops_detach(ops, dev);
- }
mutex_unlock(&devlist_lock);
}
@@ -1158,6 +1262,8 @@ static struct pci_driver saa7134_pci_driver = {
.id_table = saa7134_pci_tbl,
.probe = saa7134_initdev,
.remove = __devexit_p(saa7134_finidev),
+ .suspend = saa7134_suspend,
+ .resume = saa7134_resume
};
static int saa7134_init(void)
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e0eec80088c7..38d87332cc5d 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -175,18 +175,6 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
return mt352_pinnacle_init(fe);
}
-static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
- if (buf_len < 5)
- return -EINVAL;
-
- pllbuf[0] = 0x61;
- dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 5;
-}
-
static struct mt352_config pinnacle_300i = {
.demod_address = 0x3c >> 1,
.adc_clock = 20333,
@@ -444,135 +432,6 @@ static struct tda1004x_config philips_europa_config = {
/* ------------------------------------------------------------------ */
-static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- /* this message is to set up ATC and ALC */
- static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
- msleep(1);
-
- return 0;
-}
-
-static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- /* this message actually turns the tuner back to analog mode */
- u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
- msleep(1);
- fmd1216_init[2] = 0x86;
- fmd1216_init[3] = 0x54;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
- msleep(1);
- return 0;
-}
-
-static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
- sizeof(tuner_buf) };
- int tuner_frequency = 0;
- int divider = 0;
- u8 band, mode, cp;
-
- /* determine charge pump */
- tuner_frequency = params->frequency + 36130000;
- if (tuner_frequency < 87000000)
- return -EINVAL;
- /* low band */
- else if (tuner_frequency < 180000000) {
- band = 1;
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 195000000) {
- band = 1;
- mode = 6;
- cp = 1;
- /* mid band */
- } else if (tuner_frequency < 366000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 10;
- } else {
- band = 2;
- }
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 478000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 10;
- } else {
- band = 2;
- }
- mode = 6;
- cp = 1;
- /* high band */
- } else if (tuner_frequency < 662000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 840000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 6;
- cp = 1;
- } else {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 7;
- cp = 1;
-
- }
- /* calculate divisor */
- /* ((36166000 + Finput) / 166666) rounded! */
- divider = (tuner_frequency + 83333) / 166667;
-
- /* setup tuner buffer */
- tuner_buf[0] = (divider >> 8) & 0x7f;
- tuner_buf[1] = divider & 0xff;
- tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
- tuner_buf[3] = 0x40 | band;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
- wprintk("could not write to tuner at addr: 0x%02x\n",
- addr << 1);
- return -EIO;
- }
- return 0;
-}
-
static struct tda1004x_config medion_cardbus = {
.demod_address = 0x08,
.invert = 1,
@@ -708,6 +567,7 @@ static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config
}
/* ------------------------------------------------------------------ */
+
static struct tda1004x_config tda827x_lifeview_config = {
.demod_address = 0x08,
.invert = 1,
@@ -887,6 +747,7 @@ static struct tda1004x_config asus_p7131_hybrid_lna_config = {
.antenna_switch= 2,
.request_firmware = philips_tda1004x_request_firmware
};
+
static struct tda1004x_config kworld_dvb_t_210_config = {
.demod_address = 0x08,
.invert = 1,
@@ -901,6 +762,22 @@ static struct tda1004x_config kworld_dvb_t_210_config = {
.antenna_switch= 1,
.request_firmware = philips_tda1004x_request_firmware
};
+
+static struct tda1004x_config avermedia_super_007_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .tuner_config = 0,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
/* ------------------------------------------------------------------
* special case: this card uses saa713x GPIO22 for the mode switch
*/
@@ -958,18 +835,8 @@ static struct nxt200x_config avertvhda180 = {
.demod_address = 0x0a,
};
-static int nxt200x_set_pll_input(u8 *buf, int input)
-{
- if (input)
- buf[3] |= 0x08;
- else
- buf[3] &= ~0x08;
- return 0;
-}
-
static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
};
/* ==================================================================
@@ -983,7 +850,7 @@ static int dvb_init(struct saa7134_dev *dev)
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
dev->dvb.name = dev->name;
- videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+ videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
@@ -1005,7 +872,8 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, DVB_PLL_PHILIPS_TD1316);
}
break;
case SAA7134_BOARD_MD7134:
@@ -1013,9 +881,8 @@ static int dvb_init(struct saa7134_dev *dev)
&medion_cardbus,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+ &dev->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1113,7 +980,7 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tdhu2);
+ NULL, DVB_PLL_TDHU2);
}
break;
case SAA7134_BOARD_KWORLD_ATSC110:
@@ -1121,7 +988,7 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tuv1236d);
+ NULL, DVB_PLL_TUV1236D);
}
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1144,9 +1011,9 @@ static int dvb_init(struct saa7134_dev *dev)
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+ &dev->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -1173,6 +1040,9 @@ static int dvb_init(struct saa7134_dev *dev)
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
break;
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ configure_tda827x_fe(dev, &avermedia_super_007_config);
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index f521603482ca..34ca874dd7fe 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -20,7 +20,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -77,17 +76,14 @@ static int ts_init_encoder(struct saa7134_dev* dev)
static int ts_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev;
int err;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->empress_dev && h->empress_dev->minor == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ if (dev->empress_dev && dev->empress_dev->minor == minor)
+ goto found;
+ return -ENODEV;
+ found:
dprintk("open minor=%d\n",minor);
err = -EBUSY;
@@ -96,6 +92,10 @@ static int ts_open(struct inode *inode, struct file *file)
if (dev->empress_users)
goto done_up;
+ /* Unmute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
dev->empress_users++;
file->private_data = dev;
err = 0;
@@ -121,6 +121,10 @@ static int ts_release(struct inode *inode, struct file *file)
/* stop the encoder */
ts_reset_encoder(dev);
+ /* Mute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
mutex_unlock(&dev->empress_tsq.lock);
return 0;
}
@@ -393,7 +397,7 @@ static int empress_init(struct saa7134_dev *dev)
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
dev->name,dev->empress_dev->minor & 0x1f);
- videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops,
+ videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 1cb8c709ca90..cc87f5855a21 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index c0de37e3f5c6..80d2644f765a 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -19,7 +19,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -153,21 +152,18 @@ void saa7134_input_irq(struct saa7134_dev *dev)
static void saa7134_input_timer(unsigned long data)
{
- struct saa7134_dev *dev = (struct saa7134_dev*)data;
+ struct saa7134_dev *dev = (struct saa7134_dev *)data;
struct card_ir *ir = dev->remote;
- unsigned long timeout;
build_key(dev);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = saa7134_input_timer;
- ir->timer.data = (unsigned long)dev;
+ setup_timer(&ir->timer, saa7134_input_timer,
+ (unsigned long)dev);
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
@@ -314,6 +310,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x003F00;
mask_keyup = 0x040000;
break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_FLYDVBTDUO:
ir_codes = ir_codes_flydvb;
@@ -333,6 +330,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x040000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_10MOONSTVMASTER3:
+ ir_codes = ir_codes_encore_enltv;
+ mask_keycode = 0x5f80000;
+ mask_keyup = 0x8000000;
+ polling = 50; //ms
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -374,7 +377,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
input_dev->id.vendor = dev->pci->vendor;
input_dev->id.product = dev->pci->device;
}
- input_dev->cdev.dev = &dev->pci->dev;
+ input_dev->dev.parent = &dev->pci->dev;
dev->remote = ir;
saa7134_ir_start(dev, ir);
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 72444f039e3d..aedf04653e0e 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -240,17 +239,14 @@ static int dsp_rec_stop(struct saa7134_dev *dev)
static int dsp_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev;
int err;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->dmasound.minor_dsp == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ if (dev->dmasound.minor_dsp == minor)
+ goto found;
+ return -ENODEV;
+ found:
mutex_lock(&dev->dmasound.lock);
err = -EBUSY;
@@ -681,19 +677,14 @@ mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
static int mixer_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->dmasound.minor_mixer == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
-
- file->private_data = dev;
- return 0;
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ if (dev->dmasound.minor_mixer == minor) {
+ file->private_data = dev;
+ return 0;
+ }
+ return -ENODEV;
}
static int mixer_release(struct inode *inode, struct file *file)
@@ -1023,18 +1014,14 @@ static int saa7134_oss_init(void)
static void saa7134_oss_exit(void)
{
- struct saa7134_dev *dev = NULL;
- struct list_head *list;
-
- list_for_each(list,&saa7134_devlist) {
- dev = list_entry(list, struct saa7134_dev, devlist);
+ struct saa7134_dev *dev;
+ list_for_each_entry(dev, &saa7134_devlist, devlist) {
/* Device isn't registered by OSS, probably ALSA's */
if (!dev->dmasound.minor_dsp)
continue;
oss_device_exit(dev);
-
}
saa7134_dmasound_init = NULL;
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 60a90a2617ae..4b63ad3e8466 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -93,6 +92,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
}
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -102,8 +103,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci,buf->pt,
- buf->vb.dma.sglist,
- buf->vb.dma.sglen,
+ dma->sglist,
+ dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
@@ -176,6 +177,22 @@ static unsigned int ts_nr_packets = 64;
module_param(ts_nr_packets, int, 0444);
MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
+int saa7134_ts_init_hw(struct saa7134_dev *dev)
+{
+ /* deactivate TS softreset */
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ /* TSSOP high active, TSVAL high active, TSLOCK ignored */
+ saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
+ saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
+ saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));
+
+ return 0;
+}
+
int saa7134_ts_init1(struct saa7134_dev *dev)
{
/* sanitycheck insmod options */
@@ -199,12 +216,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
/* init TS hw */
- saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */
- saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */
- saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
- saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
- saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
- saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+ saa7134_ts_init_hw(dev);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 30395d6b5f14..1b9e39a5ea47 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -23,8 +23,8 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/div64.h>
@@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev)
}
if (dev->hw_mute == mute &&
- dev->hw_input == in) {
+ dev->hw_input == in && !dev->inresume) {
dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
mute,in->name);
return;
@@ -341,10 +341,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&dev->thread.wq, &wait);
- if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+ if (dev->thread.scan1 == dev->thread.scan2 &&
+ !kthread_should_stop()) {
if (timeout < 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
@@ -353,7 +351,6 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
(msecs_to_jiffies(timeout));
}
}
- remove_wait_queue(&dev->thread.wq, &wait);
return dev->thread.scan1 != dev->thread.scan2;
}
@@ -505,11 +502,10 @@ static int tvaudio_thread(void *data)
unsigned int i, audio, nscan;
int max1,max2,carrier,rx,mode,lastmode,default_carrier;
- daemonize("%s", dev->name);
allow_signal(SIGTERM);
for (;;) {
tvaudio_sleep(dev,-1);
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
goto done;
restart:
@@ -618,7 +614,7 @@ static int tvaudio_thread(void *data)
for (;;) {
if (tvaudio_sleep(dev,5000))
goto restart;
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
break;
if (UNSET == dev->thread.mode) {
rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -634,7 +630,6 @@ static int tvaudio_thread(void *data)
}
done:
- complete_and_exit(&dev->thread.exit, 0);
return 0;
}
@@ -782,7 +777,6 @@ static int tvaudio_thread_ddep(void *data)
struct saa7134_dev *dev = data;
u32 value, norms, clock;
- daemonize("%s", dev->name);
allow_signal(SIGTERM);
clock = saa7134_boards[dev->board].audio_clock;
@@ -796,7 +790,7 @@ static int tvaudio_thread_ddep(void *data)
for (;;) {
tvaudio_sleep(dev,-1);
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
goto done;
restart:
@@ -876,14 +870,13 @@ static int tvaudio_thread_ddep(void *data)
}
done:
- complete_and_exit(&dev->thread.exit, 0);
return 0;
}
/* ------------------------------------------------------------------ */
/* common stuff + external entry points */
-static void saa7134_enable_i2s(struct saa7134_dev *dev)
+void saa7134_enable_i2s(struct saa7134_dev *dev)
{
int i2s_format;
@@ -973,7 +966,6 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
int saa7134_tvaudio_init2(struct saa7134_dev *dev)
{
- DECLARE_MUTEX_LOCKED(sem);
int (*my_thread)(void *data) = NULL;
switch (dev->pci->device) {
@@ -986,15 +978,15 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
break;
}
- dev->thread.pid = -1;
+ dev->thread.thread = NULL;
if (my_thread) {
/* start tvaudio thread */
- init_waitqueue_head(&dev->thread.wq);
- init_completion(&dev->thread.exit);
- dev->thread.pid = kernel_thread(my_thread,dev,0);
- if (dev->thread.pid < 0)
+ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+ if (IS_ERR(dev->thread.thread)) {
printk(KERN_WARNING "%s: kernel_thread() failed\n",
dev->name);
+ /* XXX: missing error handling here */
+ }
saa7134_tvaudio_do_scan(dev);
}
@@ -1005,11 +997,9 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
int saa7134_tvaudio_fini(struct saa7134_dev *dev)
{
/* shutdown tvaudio thread */
- if (dev->thread.pid > 0) {
- dev->thread.shutdown = 1;
- wake_up_interruptible(&dev->thread.wq);
- wait_for_completion(&dev->thread.exit);
- }
+ if (dev->thread.thread)
+ kthread_stop(dev->thread.thread);
+
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
return 0;
}
@@ -1020,10 +1010,10 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
dprintk("sound IF not in use, skipping scan\n");
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
- } else if (dev->thread.pid >= 0) {
+ } else if (dev->thread.thread) {
dev->thread.mode = UNSET;
dev->thread.scan2++;
- wake_up_interruptible(&dev->thread.wq);
+ wake_up_process(dev->thread.thread);
} else {
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
@@ -1040,4 +1030,3 @@ EXPORT_SYMBOL(saa7134_tvaudio_setmute);
* c-basic-offset: 8
* End:
*/
-
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index f38366a470fa..81a2aedeff5c 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -138,6 +137,8 @@ static int buffer_prepare(struct videobuf_queue *q,
saa7134_dma_free(q,buf);
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -147,8 +148,8 @@ static int buffer_prepare(struct videobuf_queue *q,
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci,buf->pt,
- buf->vb.dma.sglist,
- buf->vb.dma.sglen,
+ dma->sglist,
+ dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 9985ded20950..471b92793c12 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sort.h>
@@ -41,7 +40,7 @@
static unsigned int video_debug = 0;
static unsigned int gbuffers = 8;
-static unsigned int noninterlaced = 1;
+static unsigned int noninterlaced = 0;
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
static char secam[] = "--";
@@ -541,22 +540,12 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
/* ------------------------------------------------------------------ */
-static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
{
- int luma_control,sync_control,mux;
dprintk("set tv norm = %s\n",norm->name);
dev->tvnorm = norm;
- mux = card_in(dev,dev->ctl_input).vmux;
- luma_control = norm->luma_control;
- sync_control = norm->sync_control;
-
- if (mux > 5)
- luma_control |= 0x80; /* svideo */
- if (noninterlaced || dev->nosignal)
- sync_control |= 0x20;
-
/* setup cropping */
dev->crop_bounds.left = norm->h_start;
dev->crop_defrect.left = norm->h_start;
@@ -571,6 +560,40 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
dev->crop_current = dev->crop_defrect;
+ saa7134_set_decoder(dev);
+
+ if (card_in(dev, dev->ctl_input).tv) {
+ if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
+ && ((card(dev).tuner_config == 1)
+ || (card(dev).tuner_config == 2)))
+ saa7134_set_gpio(dev, 22, 5);
+ saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id);
+ }
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+ dprintk("video input = %d [%s]\n", input, card_in(dev, input).name);
+ dev->ctl_input = input;
+ set_tvnorm(dev, dev->tvnorm);
+ saa7134_tvaudio_setinput(dev, &card_in(dev, input));
+}
+
+void saa7134_set_decoder(struct saa7134_dev *dev)
+{
+ int luma_control, sync_control, mux;
+
+ struct saa7134_tvnorm *norm = dev->tvnorm;
+ mux = card_in(dev, dev->ctl_input).vmux;
+
+ luma_control = norm->luma_control;
+ sync_control = norm->sync_control;
+
+ if (mux > 5)
+ luma_control |= 0x80; /* svideo */
+ if (noninterlaced || dev->nosignal)
+ sync_control |= 0x20;
+
/* setup video decoder */
saa_writeb(SAA7134_INCR_DELAY, 0x08);
saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux);
@@ -585,9 +608,13 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
saa_writeb(SAA7134_SYNC_CTRL, sync_control);
saa_writeb(SAA7134_LUMA_CTRL, luma_control);
saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);
- saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast);
- saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation);
+ saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+ dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+
+ saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+ dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+
saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1);
saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain);
@@ -601,23 +628,6 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc);
saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40);
saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80);
-
- /* only tell the tuner if this is a tv input */
- if (card_in(dev,dev->ctl_input).tv) {
- if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
- && ((card(dev).tuner_config == 1)
- || (card(dev).tuner_config == 2)))
- saa7134_set_gpio(dev, 22, 5);
- saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
- }
-}
-
-static void video_mux(struct saa7134_dev *dev, int input)
-{
- dprintk("video input = %d [%s]\n",input,card_in(dev,input).name);
- dev->ctl_input = input;
- set_tvnorm(dev,dev->tvnorm);
- saa7134_tvaudio_setinput(dev,&card_in(dev,input));
}
static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1038,6 +1048,8 @@ static int buffer_prepare(struct videobuf_queue *q,
}
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = fh->width;
buf->vb.height = fh->height;
buf->vb.size = size;
@@ -1049,8 +1061,8 @@ static int buffer_prepare(struct videobuf_queue *q,
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci,buf->pt,
- buf->vb.dma.sglist,
- buf->vb.dma.sglen,
+ dma->sglist,
+ dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
@@ -1273,26 +1285,24 @@ static int saa7134_resource(struct saa7134_fh *fh)
static int video_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
+ struct saa7134_dev *dev;
struct saa7134_fh *fh;
- struct list_head *list;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int radio = 0;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->video_dev && (h->video_dev->minor == minor))
- dev = h;
- if (h->radio_dev && (h->radio_dev->minor == minor)) {
+ list_for_each_entry(dev, &saa7134_devlist, devlist) {
+ if (dev->video_dev && (dev->video_dev->minor == minor))
+ goto found;
+ if (dev->radio_dev && (dev->radio_dev->minor == minor)) {
radio = 1;
- dev = h;
+ goto found;
}
- if (h->vbi_dev && (h->vbi_dev->minor == minor)) {
+ if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) {
type = V4L2_BUF_TYPE_VBI_CAPTURE;
- dev = h;
+ goto found;
}
}
- if (NULL == dev)
- return -ENODEV;
+ return -ENODEV;
+ found:
dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
v4l2_type_names[type]);
@@ -1310,13 +1320,13 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 576;
v4l2_prio_open(&dev->prio,&fh->prio);
- videobuf_queue_init(&fh->cap, &video_qops,
+ videobuf_queue_pci_init(&fh->cap, &video_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7134_buf),
fh);
- videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops,
+ videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
@@ -1833,7 +1843,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
if (res_check(fh, RESOURCE_OVERLAY)) {
spin_lock_irqsave(&dev->slock,flags);
stop_preview(dev,fh);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
set_tvnorm(dev,&tvnorms[i]);
+
+ spin_lock_irqsave(&dev->slock, flags);
start_preview(dev,fh);
spin_unlock_irqrestore(&dev->slock,flags);
} else
@@ -2138,29 +2152,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- q = saa7134_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = gbuffers;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
- }
+ return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
#endif
case VIDIOC_REQBUFS:
return videobuf_reqbufs(saa7134_queue(fh),arg);
@@ -2412,34 +2404,40 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->video_q.timeout.data = (unsigned long)(&dev->video_q);
dev->video_q.dev = dev;
- if (saa7134_boards[dev->board].video_out) {
- /* enable video output */
- int vo = saa7134_boards[dev->board].video_out;
- int video_reg;
- unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
- saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
- video_reg = video_out[vo][1];
- if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
- video_reg &= ~VP_T_CODE_P_INVERTED;
- saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
- video_reg = video_out[vo][5];
- if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
- video_reg &= ~VP_CLK_CTRL2_DELAYED;
- if (vid_port_opts & SET_CLOCK_INVERTED)
- video_reg |= VP_CLK_CTRL1_INVERTED;
- saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
- video_reg = video_out[vo][6];
- if (vid_port_opts & SET_VSYNC_OFF) {
- video_reg &= ~VP_VS_TYPE_MASK;
- video_reg |= VP_VS_TYPE_OFF;
- }
- saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
- }
+ if (saa7134_boards[dev->board].video_out)
+ saa7134_videoport_init(dev);
+
+ return 0;
+}
+
+int saa7134_videoport_init(struct saa7134_dev *dev)
+{
+ /* enable video output */
+ int vo = saa7134_boards[dev->board].video_out;
+ int video_reg;
+ unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+ video_reg = video_out[vo][1];
+ if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+ video_reg &= ~VP_T_CODE_P_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+ video_reg = video_out[vo][5];
+ if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+ video_reg &= ~VP_CLK_CTRL2_DELAYED;
+ if (vid_port_opts & SET_CLOCK_INVERTED)
+ video_reg |= VP_CLK_CTRL1_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+ video_reg = video_out[vo][6];
+ if (vid_port_opts & SET_VSYNC_OFF) {
+ video_reg &= ~VP_VS_TYPE_MASK;
+ video_reg |= VP_VS_TYPE_OFF;
+ }
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
return 0;
}
@@ -2454,7 +2452,7 @@ int saa7134_video_init2(struct saa7134_dev *dev)
return 0;
}
-void saa7134_irq_video_intl(struct saa7134_dev *dev)
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
{
static const char *st[] = {
"(no signal)", "NTSC", "PAL", "SECAM" };
@@ -2466,24 +2464,28 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev)
(st1 & 0x40) ? "not locked" : "locked",
(st2 & 0x40) ? "no" : "yes",
st[st1 & 0x03]);
- dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
+ dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1);
if (dev->nosignal) {
/* no video signal -> mute audio */
if (dev->ctl_automute)
dev->automute = 1;
saa7134_tvaudio_setmute(dev);
- saa_setb(SAA7134_SYNC_CTRL, 0x20);
} else {
/* wake up tvaudio audio carrier scan thread */
saa7134_tvaudio_do_scan(dev);
- if (!noninterlaced)
- saa_clearb(SAA7134_SYNC_CTRL, 0x20);
}
+
+ if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
+ saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+ else
+ saa_setb(SAA7134_SYNC_CTRL, 0x20);
+
if (dev->mops && dev->mops->signal_change)
dev->mops->signal_change(dev);
}
+
void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
{
enum v4l2_field field;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 15623b27ad2e..28ec6804bd5d 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,12 +37,12 @@
#include <media/tuner.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-#include <media/video-buf-dvb.h>
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#include <media/videobuf-dvb.h>
#endif
#define UNSET (-1U)
@@ -238,6 +238,8 @@ struct saa7134_format {
#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113
#define SAA7134_BOARD_KWORLD_DVBT_210 114
#define SAA7134_BOARD_SABRENT_TV_PCB05 115
+#define SAA7134_BOARD_10MOONSTVMASTER3 116
+#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -313,7 +315,7 @@ struct saa7134_board {
#define INTERLACE_ON 1
#define INTERLACE_OFF 2
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
struct saa7134_dev;
struct saa7134_dma;
@@ -327,10 +329,7 @@ struct saa7134_pgtable {
/* tvaudio thread status */
struct saa7134_thread {
- pid_t pid;
- struct completion exit;
- wait_queue_head_t wq;
- unsigned int shutdown;
+ struct task_struct *thread;
unsigned int scan1;
unsigned int scan2;
unsigned int mode;
@@ -525,6 +524,7 @@ struct saa7134_dev {
unsigned int hw_mute;
int last_carrier;
int nosignal;
+ unsigned int inresume;
/* SAA7134_MPEG_* */
struct saa7134_ts ts;
@@ -538,7 +538,7 @@ struct saa7134_dev {
struct work_struct empress_workqueue;
int empress_started;
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
int (*original_demod_sleep)(struct dvb_frontend* fe);
@@ -595,6 +595,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
void saa7134_buffer_timeout(unsigned long data);
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
+int saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q);
+
int saa7134_set_dmabits(struct saa7134_dev *dev);
extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
@@ -627,12 +630,16 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;
+void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
+int saa7134_videoport_init(struct saa7134_dev *dev);
+void saa7134_set_decoder(struct saa7134_dev *dev);
+
int saa7134_common_ioctl(struct saa7134_dev *dev,
unsigned int cmd, void *arg);
int saa7134_video_init1(struct saa7134_dev *dev);
int saa7134_video_init2(struct saa7134_dev *dev);
-void saa7134_irq_video_intl(struct saa7134_dev *dev);
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
@@ -650,6 +657,8 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
+int saa7134_ts_init_hw(struct saa7134_dev *dev);
+
/* ----------------------------------------------------------- */
/* saa7134-vbi.c */
@@ -678,6 +687,8 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
+void saa7134_enable_i2s(struct saa7134_dev *dev);
+
/* ----------------------------------------------------------- */
/* saa7134-oss.c */
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 339592e7722d..66cc92c0ea66 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -34,23 +34,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 8615a6081a5d..b4018cce3285 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -130,7 +130,7 @@ static int saa7191_write_reg(struct i2c_client *client, u8 reg,
/* the first byte of data must be the first subaddress number (register) */
static int saa7191_write_block(struct i2c_client *client,
- u8 length, u8 *data)
+ u8 length, const u8 *data)
{
int i;
int ret;
@@ -592,7 +592,7 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind)
if (err)
goto out_free_decoder;
- err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq);
+ err = saa7191_write_block(client, sizeof(initseq), initseq);
if (err) {
printk(KERN_ERR "SAA7191 initialization failed\n");
goto out_detach_client;
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 11fcb49f5b99..2e3c3de793a7 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/stddef.h>
+#include <linux/kref.h>
#include "sn9c102_config.h"
#include "sn9c102_sensor.h"
@@ -94,7 +95,7 @@ struct sn9c102_module_param {
};
static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
+static DECLARE_RWSEM(sn9c102_dev_lock);
struct sn9c102_device {
struct video_device* v4ldev;
@@ -122,12 +123,14 @@ struct sn9c102_device {
struct sn9c102_module_param module_param;
+ struct kref kref;
enum sn9c102_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 74a204f8ebc8..6991e06f7651 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -48,8 +47,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.44"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 44)
+#define SN9C102_MODULE_VERSION "1:1.47"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47)
/*****************************************************************************/
@@ -64,9 +63,10 @@ MODULE_LICENSE(SN9C102_MODULE_LICENSE);
static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
module_param_array(video_nr, short, NULL, 0444);
MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L2 minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
+ " <-1|n[,...]>"
+ "\nSpecify V4L2 minor mode number."
+ "\n-1 = use next available (default)"
+ "\n n = use minor number n (integer >= 0)"
"\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
" cameras this way."
"\nFor example:"
@@ -79,13 +79,14 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
SN9C102_FORCE_MUNMAP};
module_param_array(force_munmap, bool, NULL, 0444);
MODULE_PARM_DESC(force_munmap,
- "\n<0|1[,...]> Force the application to unmap previously"
+ " <0|1[,...]>"
+ "\nForce the application to unmap previously"
"\nmapped buffer memory before calling any VIDIOC_S_CROP or"
"\nVIDIOC_S_FMT ioctl's. Not all the applications support"
"\nthis feature. This parameter is specific for each"
"\ndetected camera."
- "\n 0 = do not force memory unmapping"
- "\n 1 = force memory unmapping (save memory)"
+ "\n0 = do not force memory unmapping"
+ "\n1 = force memory unmapping (save memory)"
"\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
"\n");
@@ -93,7 +94,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
SN9C102_FRAME_TIMEOUT};
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
- "\n<0|n[,...]> Timeout for a video frame in seconds before"
+ " <0|n[,...]>"
+ "\nTimeout for a video frame in seconds before"
"\nreturning an I/O error; 0 for infinity."
"\nThis parameter is specific for each detected camera."
"\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
@@ -103,7 +105,8 @@ MODULE_PARM_DESC(frame_timeout,
static unsigned short debug = SN9C102_DEBUG_LEVEL;
module_param(debug, ushort, 0644);
MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 3:"
+ " <n>"
+ "\nDebugging information level, from 0 to 3:"
"\n0 = none (use carefully)"
"\n1 = critical errors"
"\n2 = significant informations"
@@ -1026,7 +1029,8 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
NOTE 2: buffers are PAGE_SIZE long
*/
-static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1050,7 +1054,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 index;
@@ -1083,7 +1088,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1115,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 value;
@@ -1154,7 +1161,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_i2c_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1180,7 +1188,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 index;
@@ -1213,7 +1222,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_i2c_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1250,7 +1260,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 value;
@@ -1295,7 +1306,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
static ssize_t
-sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_green(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
enum sn9c102_bridge bridge;
@@ -1326,16 +1338,16 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
case BRIDGE_SN9C102:
if (value > 0x0f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
break;
case BRIDGE_SN9C103:
case BRIDGE_SN9C105:
case BRIDGE_SN9C120:
if (value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
break;
}
@@ -1344,7 +1356,8 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
static ssize_t
-sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
ssize_t res = 0;
u16 value;
@@ -1354,15 +1367,16 @@ sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
if (!count || value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
return res;
}
static ssize_t
-sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_red(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
ssize_t res = 0;
u16 value;
@@ -1372,14 +1386,16 @@ sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
if (!count || value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
return res;
}
-static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_frame_header(struct device* cd,
+ struct device_attribute *attr,
+ char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1398,72 +1414,63 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
}
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
- sn9c102_show_reg, sn9c102_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
- sn9c102_show_val, sn9c102_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
- sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
- sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
-static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
-static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
-static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
- sn9c102_show_frame_header, NULL);
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);
+static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);
+static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+ sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
+static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+ sn9c102_show_i2c_val, sn9c102_store_i2c_val);
+static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
+static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
static int sn9c102_create_sysfs(struct sn9c102_device* cam)
{
- struct class_device *classdev = &(cam->v4ldev->class_dev);
+ struct device *classdev = &(cam->v4ldev->class_dev);
int err = 0;
- if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_reg)))
goto err_out;
- if ((err = class_device_create_file(classdev, &class_device_attr_val)))
+ if ((err = device_create_file(classdev, &dev_attr_val)))
goto err_reg;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_frame_header)))
+ if ((err = device_create_file(classdev, &dev_attr_frame_header)))
goto err_val;
if (cam->sensor.sysfs_ops) {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_i2c_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
goto err_frame_header;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_i2c_val)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
goto err_i2c_reg;
}
if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_green)))
+ if ((err = device_create_file(classdev, &dev_attr_green)))
goto err_i2c_val;
} else {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_blue)))
+ if ((err = device_create_file(classdev, &dev_attr_blue)))
goto err_i2c_val;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_red)))
+ if ((err = device_create_file(classdev, &dev_attr_red)))
goto err_blue;
}
return 0;
err_blue:
- class_device_remove_file(classdev, &class_device_attr_blue);
+ device_remove_file(classdev, &dev_attr_blue);
err_i2c_val:
if (cam->sensor.sysfs_ops)
- class_device_remove_file(classdev, &class_device_attr_i2c_val);
+ device_remove_file(classdev, &dev_attr_i2c_val);
err_i2c_reg:
if (cam->sensor.sysfs_ops)
- class_device_remove_file(classdev, &class_device_attr_i2c_reg);
+ device_remove_file(classdev, &dev_attr_i2c_reg);
err_frame_header:
- class_device_remove_file(classdev, &class_device_attr_frame_header);
+ device_remove_file(classdev, &dev_attr_frame_header);
err_val:
- class_device_remove_file(classdev, &class_device_attr_val);
+ device_remove_file(classdev, &dev_attr_val);
err_reg:
- class_device_remove_file(classdev, &class_device_attr_reg);
+ device_remove_file(classdev, &dev_attr_reg);
err_out:
return err;
}
@@ -1616,7 +1623,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
} else { /* use current values */
@@ -1706,21 +1714,27 @@ static int sn9c102_init(struct sn9c102_device* cam)
return 0;
}
+/*****************************************************************************/
-static void sn9c102_release_resources(struct sn9c102_device* cam)
+static void sn9c102_release_resources(struct kref *kref)
{
+ struct sn9c102_device *cam;
+
mutex_lock(&sn9c102_sysfs_lock);
+ cam = container_of(kref, struct sn9c102_device, kref);
+
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
+ kfree(cam->control_buffer);
+ kfree(cam);
mutex_unlock(&sn9c102_sysfs_lock);
- kfree(cam->control_buffer);
}
-/*****************************************************************************/
static int sn9c102_open(struct inode* inode, struct file* filp)
{
@@ -1728,43 +1742,78 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
int err = 0;
/*
- This is the only safe way to prevent race conditions with
- disconnect
+ A read_trylock() in open() is the only safe way to prevent race
+ conditions with disconnect(), one close() and multiple (not
+ necessarily simultaneous) attempts to open(). For example, it
+ prevents from waiting for a second access, while the device
+ structure is being deallocated, after a possible disconnect() and
+ during a following close() holding the write lock: given that, after
+ this deallocation, no access will be possible anymore, using the
+ non-trylock version would have let open() gain the access to the
+ device structure improperly.
+ For this reason the lock must also not be per-device.
*/
- if (!down_read_trylock(&sn9c102_disconnect))
+ if (!down_read_trylock(&sn9c102_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&sn9c102_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&sn9c102_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ kref_get(&cam->kref);
+
+ /*
+ Make sure to isolate all the simultaneous opens.
+ */
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, sn9c102_release_resources);
+ up_read(&sn9c102_dev_lock);
return -ERESTARTSYS;
}
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is already in use",
+ cam->v4ldev->minor);
DBG(3, "Simultaneous opens are not supported");
+ /*
+ open() must follow the open flags and should block
+ eventually while the device is in use.
+ */
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&sn9c102_dev_lock);
+ /*
+ We will not release the "open_mutex" lock, so that only one
+ process can be in the wait queue below. This way the process
+ will be sleeping while holding the lock, without loosing its
+ priority after any wake_up().
+ */
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&sn9c102_disconnect);
- return err;
- }
+ down_read(&sn9c102_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&sn9c102_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = sn9c102_init(cam);
if (err) {
@@ -1789,36 +1838,33 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&sn9c102_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, sn9c102_release_resources);
+
+ up_read(&sn9c102_dev_lock);
return err;
}
static int sn9c102_release(struct inode* inode, struct file* filp)
{
- struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+ struct sn9c102_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&sn9c102_dev_lock);
- sn9c102_stop_transfer(cam);
+ cam = video_get_drvdata(video_devdata(filp));
+ sn9c102_stop_transfer(cam);
sn9c102_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- sn9c102_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, sn9c102_release_resources);
+
+ up_write(&sn9c102_dev_lock);
return 0;
}
@@ -2085,7 +2131,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
vma->vm_ops = &sn9c102_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
sn9c102_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -3215,8 +3260,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
r = sn9c102_read_reg(cam, 0x00);
if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
DBG(1, "Sorry, this is not a SN9C1xx-based camera "
@@ -3282,7 +3325,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -3292,7 +3335,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -3318,8 +3361,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
#endif
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -3336,40 +3381,31 @@ fail:
static void sn9c102_usb_disconnect(struct usb_interface* intf)
{
- struct sn9c102_device* cam = usb_get_intfdata(intf);
-
- if (!cam)
- return;
+ struct sn9c102_device* cam;
- down_write(&sn9c102_disconnect);
+ down_write(&sn9c102_dev_lock);
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
sn9c102_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- sn9c102_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, sn9c102_release_resources);
- up_write(&sn9c102_disconnect);
+ up_write(&sn9c102_dev_lock);
}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index e6832347894f..e4856fd77982 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -104,6 +104,145 @@ static int ov7630_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x74, 0x21);
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+ {0x1a, 0x04}, {0x03, 0x10},
+ {0x0a, 0x14}, {0xe2, 0x17},
+ {0x0b, 0x18}, {0x00, 0x19},
+ {0x1d, 0x1a}, {0x10, 0x1b},
+ {0x02, 0x1c}, {0x03, 0x1d},
+ {0x0f, 0x1e}, {0x0c, 0x1f},
+ {0x00, 0x20}, {0x24, 0x21},
+ {0x3b, 0x22}, {0x47, 0x23},
+ {0x60, 0x24}, {0x71, 0x25},
+ {0x80, 0x26}, {0x8f, 0x27},
+ {0x9d, 0x28}, {0xaa, 0x29},
+ {0xb8, 0x2a}, {0xc4, 0x2b},
+ {0xd1, 0x2c}, {0xdd, 0x2d},
+ {0xe8, 0x2e}, {0xf4, 0x2f},
+ {0xff, 0x30}, {0x00, 0x3f},
+ {0xc7, 0x40}, {0x01, 0x41},
+ {0x44, 0x42}, {0x00, 0x43},
+ {0x44, 0x44}, {0x00, 0x45},
+ {0x44, 0x46}, {0x00, 0x47},
+ {0xc7, 0x48}, {0x01, 0x49},
+ {0xc7, 0x4a}, {0x01, 0x4b},
+ {0xc7, 0x4c}, {0x01, 0x4d},
+ {0x44, 0x4e}, {0x00, 0x4f},
+ {0x44, 0x50}, {0x00, 0x51},
+ {0x44, 0x52}, {0x00, 0x53},
+ {0xc7, 0x54}, {0x01, 0x55},
+ {0xc7, 0x56}, {0x01, 0x57},
+ {0xc7, 0x58}, {0x01, 0x59},
+ {0x44, 0x5a}, {0x00, 0x5b},
+ {0x44, 0x5c}, {0x00, 0x5d},
+ {0x44, 0x5e}, {0x00, 0x5f},
+ {0xc7, 0x60}, {0x01, 0x61},
+ {0xc7, 0x62}, {0x01, 0x63},
+ {0xc7, 0x64}, {0x01, 0x65},
+ {0x44, 0x66}, {0x00, 0x67},
+ {0x44, 0x68}, {0x00, 0x69},
+ {0x44, 0x6a}, {0x00, 0x6b},
+ {0xc7, 0x6c}, {0x01, 0x6d},
+ {0xc7, 0x6e}, {0x01, 0x6f},
+ {0xc7, 0x70}, {0x01, 0x71},
+ {0x44, 0x72}, {0x00, 0x73},
+ {0x44, 0x74}, {0x00, 0x75},
+ {0x44, 0x76}, {0x00, 0x77},
+ {0xc7, 0x78}, {0x01, 0x79},
+ {0xc7, 0x7a}, {0x01, 0x7b},
+ {0xc7, 0x7c}, {0x01, 0x7d},
+ {0x44, 0x7e}, {0x00, 0x7f},
+ {0x17, 0x84}, {0x00, 0x85},
+ {0x2e, 0x86}, {0x00, 0x87},
+ {0x09, 0x88}, {0x00, 0x89},
+ {0xe8, 0x8a}, {0x0f, 0x8b},
+ {0xda, 0x8c}, {0x0f, 0x8d},
+ {0x40, 0x8e}, {0x00, 0x8f},
+ {0x37, 0x90}, {0x00, 0x91},
+ {0xcf, 0x92}, {0x0f, 0x93},
+ {0xfa, 0x94}, {0x0f, 0x95},
+ {0x00, 0x96}, {0x00, 0x97},
+ {0x00, 0x98}, {0x66, 0x99},
+ {0x00, 0x9a}, {0x40, 0x9b},
+ {0x20, 0x9c}, {0x00, 0x9d},
+ {0x00, 0x9e}, {0x00, 0x9f},
+ {0x2d, 0xc0}, {0x2d, 0xc1},
+ {0x3a, 0xc2}, {0x00, 0xc3},
+ {0x04, 0xc4}, {0x3f, 0xc5},
+ {0x00, 0xc6}, {0x00, 0xc7},
+ {0x50, 0xc8}, {0x3c, 0xc9},
+ {0x28, 0xca}, {0xd8, 0xcb},
+ {0x14, 0xcc}, {0xec, 0xcd},
+ {0x32, 0xce}, {0xdd, 0xcf},
+ {0x32, 0xd0}, {0xdd, 0xd1},
+ {0x6a, 0xd2}, {0x50, 0xd3},
+ {0x60, 0xd4}, {0x00, 0xd5},
+ {0x00, 0xd6});
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x80);
+ err += sn9c102_i2c_write(cam, 0x12, 0x48);
+ err += sn9c102_i2c_write(cam, 0x01, 0x80);
+ err += sn9c102_i2c_write(cam, 0x02, 0x80);
+ err += sn9c102_i2c_write(cam, 0x03, 0x80);
+ err += sn9c102_i2c_write(cam, 0x04, 0x10);
+ err += sn9c102_i2c_write(cam, 0x05, 0x20);
+ err += sn9c102_i2c_write(cam, 0x06, 0x80);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
+ err += sn9c102_i2c_write(cam, 0x0c, 0x20);
+ err += sn9c102_i2c_write(cam, 0x0d, 0x20);
+ err += sn9c102_i2c_write(cam, 0x15, 0x80);
+ err += sn9c102_i2c_write(cam, 0x16, 0x03);
+ err += sn9c102_i2c_write(cam, 0x17, 0x1b);
+ err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+ err += sn9c102_i2c_write(cam, 0x19, 0x05);
+ err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+ err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+ err += sn9c102_i2c_write(cam, 0x21, 0x1b);
+ err += sn9c102_i2c_write(cam, 0x22, 0x00);
+ err += sn9c102_i2c_write(cam, 0x23, 0xde);
+ err += sn9c102_i2c_write(cam, 0x24, 0x10);
+ err += sn9c102_i2c_write(cam, 0x25, 0x8a);
+ err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x27, 0xca);
+ err += sn9c102_i2c_write(cam, 0x28, 0xa2);
+ err += sn9c102_i2c_write(cam, 0x29, 0x74);
+ err += sn9c102_i2c_write(cam, 0x2a, 0x88);
+ err += sn9c102_i2c_write(cam, 0x2b, 0x34);
+ err += sn9c102_i2c_write(cam, 0x2c, 0x88);
+ err += sn9c102_i2c_write(cam, 0x2e, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2f, 0x00);
+ err += sn9c102_i2c_write(cam, 0x30, 0x00);
+ err += sn9c102_i2c_write(cam, 0x32, 0xc2);
+ err += sn9c102_i2c_write(cam, 0x33, 0x08);
+ err += sn9c102_i2c_write(cam, 0x4c, 0x40);
+ err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
+ err += sn9c102_i2c_write(cam, 0x60, 0x05);
+ err += sn9c102_i2c_write(cam, 0x61, 0x40);
+ err += sn9c102_i2c_write(cam, 0x62, 0x12);
+ err += sn9c102_i2c_write(cam, 0x63, 0x57);
+ err += sn9c102_i2c_write(cam, 0x64, 0x73);
+ err += sn9c102_i2c_write(cam, 0x65, 0x00);
+ err += sn9c102_i2c_write(cam, 0x66, 0x55);
+ err += sn9c102_i2c_write(cam, 0x67, 0x01);
+ err += sn9c102_i2c_write(cam, 0x68, 0xac);
+ err += sn9c102_i2c_write(cam, 0x69, 0x38);
+ err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
+ err += sn9c102_i2c_write(cam, 0x70, 0x01);
+ err += sn9c102_i2c_write(cam, 0x71, 0x00);
+ err += sn9c102_i2c_write(cam, 0x72, 0x10);
+ err += sn9c102_i2c_write(cam, 0x73, 0x50);
+ err += sn9c102_i2c_write(cam, 0x74, 0x20);
+ err += sn9c102_i2c_write(cam, 0x76, 0x01);
+ err += sn9c102_i2c_write(cam, 0x77, 0xf3);
+ err += sn9c102_i2c_write(cam, 0x78, 0x90);
+ err += sn9c102_i2c_write(cam, 0x79, 0x98);
+ err += sn9c102_i2c_write(cam, 0x7a, 0x98);
+ err += sn9c102_i2c_write(cam, 0x7b, 0x00);
+ err += sn9c102_i2c_write(cam, 0x7c, 0x38);
+ err += sn9c102_i2c_write(cam, 0x7d, 0xff);
+ break;
default:
break;
}
@@ -115,6 +254,7 @@ static int ov7630_init(struct sn9c102_device* cam)
static int ov7630_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
+ enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
switch (ctrl->id) {
@@ -123,13 +263,20 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
return -EIO;
break;
case V4L2_CID_RED_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ else
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
ctrl->value = sn9c102_pread_reg(cam, 0x06);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ else
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ break;
break;
case V4L2_CID_GAIN:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
@@ -177,6 +324,7 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
static int ov7630_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
+ enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
switch (ctrl->id) {
@@ -184,13 +332,19 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
case V4L2_CID_RED_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ else
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_write_reg(cam, ctrl->value, 0x06);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ else
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
break;
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -227,8 +381,21 @@ static int ov7630_set_crop(struct sn9c102_device* cam,
{
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+ break;
+ default:
+ break;
+ }
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -242,10 +409,28 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
{
int err = 0;
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x20, 0x19);
- else
- err += sn9c102_write_reg(cam, 0x50, 0x19);
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+ else
+ err += sn9c102_write_reg(cam, 0x20, 0x19);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+ err += sn9c102_write_reg(cam, 0xe5, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x04);
+ } else {
+ err += sn9c102_write_reg(cam, 0xe2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x02);
+ }
+ break;
+ default:
+ break;
+ }
return err;
}
@@ -254,7 +439,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
static const struct sn9c102_sensor ov7630 = {
.name = "OV7630",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
+ BRIDGE_SN9C105 | BRIDGE_SN9C120,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
@@ -417,6 +603,12 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
err += sn9c102_write_const_regs(cam, {0x01, 0x01},
{0x00, 0x01});
break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+ {0x29, 0x01}, {0x74, 0x02},
+ {0x0e, 0x01}, {0x44, 0x01});
+ break;
default:
break;
}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
index 4b6474048a72..8aae416ba8ec 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -41,65 +41,65 @@ static int ov7660_init(struct sn9c102_device* cam)
{0xbb, 0x2a}, {0xc7, 0x2b},
{0xd3, 0x2c}, {0xde, 0x2d},
{0xea, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3F},
- {0xC7, 0x40}, {0x01, 0x41},
+ {0xff, 0x30}, {0x00, 0x3f},
+ {0xc7, 0x40}, {0x01, 0x41},
{0x44, 0x42}, {0x00, 0x43},
{0x44, 0x44}, {0x00, 0x45},
{0x44, 0x46}, {0x00, 0x47},
- {0xC7, 0x48}, {0x01, 0x49},
- {0xC7, 0x4A}, {0x01, 0x4B},
- {0xC7, 0x4C}, {0x01, 0x4D},
- {0x44, 0x4E}, {0x00, 0x4F},
+ {0xc7, 0x48}, {0x01, 0x49},
+ {0xc7, 0x4a}, {0x01, 0x4b},
+ {0xc7, 0x4c}, {0x01, 0x4d},
+ {0x44, 0x4e}, {0x00, 0x4f},
{0x44, 0x50}, {0x00, 0x51},
{0x44, 0x52}, {0x00, 0x53},
- {0xC7, 0x54}, {0x01, 0x55},
- {0xC7, 0x56}, {0x01, 0x57},
- {0xC7, 0x58}, {0x01, 0x59},
- {0x44, 0x5A}, {0x00, 0x5B},
- {0x44, 0x5C}, {0x00, 0x5D},
- {0x44, 0x5E}, {0x00, 0x5F},
- {0xC7, 0x60}, {0x01, 0x61},
- {0xC7, 0x62}, {0x01, 0x63},
- {0xC7, 0x64}, {0x01, 0x65},
+ {0xc7, 0x54}, {0x01, 0x55},
+ {0xc7, 0x56}, {0x01, 0x57},
+ {0xc7, 0x58}, {0x01, 0x59},
+ {0x44, 0x5a}, {0x00, 0x5b},
+ {0x44, 0x5c}, {0x00, 0x5d},
+ {0x44, 0x5e}, {0x00, 0x5f},
+ {0xc7, 0x60}, {0x01, 0x61},
+ {0xc7, 0x62}, {0x01, 0x63},
+ {0xc7, 0x64}, {0x01, 0x65},
{0x44, 0x66}, {0x00, 0x67},
{0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6A}, {0x00, 0x6B},
- {0xC7, 0x6C}, {0x01, 0x6D},
- {0xC7, 0x6E}, {0x01, 0x6F},
- {0xC7, 0x70}, {0x01, 0x71},
+ {0x44, 0x6a}, {0x00, 0x6b},
+ {0xc7, 0x6c}, {0x01, 0x6d},
+ {0xc7, 0x6e}, {0x01, 0x6f},
+ {0xc7, 0x70}, {0x01, 0x71},
{0x44, 0x72}, {0x00, 0x73},
{0x44, 0x74}, {0x00, 0x75},
{0x44, 0x76}, {0x00, 0x77},
- {0xC7, 0x78}, {0x01, 0x79},
- {0xC7, 0x7A}, {0x01, 0x7B},
- {0xC7, 0x7C}, {0x01, 0x7D},
- {0x44, 0x7E}, {0x00, 0x7F},
+ {0xc7, 0x78}, {0x01, 0x79},
+ {0xc7, 0x7a}, {0x01, 0x7b},
+ {0xc7, 0x7c}, {0x01, 0x7d},
+ {0x44, 0x7e}, {0x00, 0x7f},
{0x14, 0x84}, {0x00, 0x85},
{0x27, 0x86}, {0x00, 0x87},
{0x07, 0x88}, {0x00, 0x89},
- {0xEC, 0x8A}, {0x0f, 0x8B},
- {0xD8, 0x8C}, {0x0f, 0x8D},
- {0x3D, 0x8E}, {0x00, 0x8F},
- {0x3D, 0x90}, {0x00, 0x91},
- {0xCD, 0x92}, {0x0f, 0x93},
+ {0xec, 0x8a}, {0x0f, 0x8b},
+ {0xd8, 0x8c}, {0x0f, 0x8d},
+ {0x3d, 0x8e}, {0x00, 0x8f},
+ {0x3d, 0x90}, {0x00, 0x91},
+ {0xcd, 0x92}, {0x0f, 0x93},
{0xf7, 0x94}, {0x0f, 0x95},
- {0x0C, 0x96}, {0x00, 0x97},
+ {0x0c, 0x96}, {0x00, 0x97},
{0x00, 0x98}, {0x66, 0x99},
- {0x05, 0x9A}, {0x00, 0x9B},
- {0x04, 0x9C}, {0x00, 0x9D},
- {0x08, 0x9E}, {0x00, 0x9F},
- {0x2D, 0xC0}, {0x2D, 0xC1},
- {0x3A, 0xC2}, {0x05, 0xC3},
- {0x04, 0xC4}, {0x3F, 0xC5},
- {0x00, 0xC6}, {0x00, 0xC7},
- {0x50, 0xC8}, {0x3C, 0xC9},
- {0x28, 0xCA}, {0xD8, 0xCB},
- {0x14, 0xCC}, {0xEC, 0xCD},
- {0x32, 0xCE}, {0xDD, 0xCF},
- {0x32, 0xD0}, {0xDD, 0xD1},
- {0x6A, 0xD2}, {0x50, 0xD3},
- {0x00, 0xD4}, {0x00, 0xD5},
- {0x00, 0xD6});
+ {0x05, 0x9a}, {0x00, 0x9b},
+ {0x04, 0x9c}, {0x00, 0x9d},
+ {0x08, 0x9e}, {0x00, 0x9f},
+ {0x2d, 0xc0}, {0x2d, 0xc1},
+ {0x3a, 0xc2}, {0x05, 0xc3},
+ {0x04, 0xc4}, {0x3f, 0xc5},
+ {0x00, 0xc6}, {0x00, 0xc7},
+ {0x50, 0xc8}, {0x3C, 0xc9},
+ {0x28, 0xca}, {0xd8, 0xcb},
+ {0x14, 0xcc}, {0xec, 0xcd},
+ {0x32, 0xce}, {0xdd, 0xcf},
+ {0x32, 0xd0}, {0xdd, 0xd1},
+ {0x6a, 0xd2}, {0x50, 0xd3},
+ {0x00, 0xd4}, {0x00, 0xd5},
+ {0x00, 0xd6});
err += sn9c102_i2c_write(cam, 0x12, 0x80);
err += sn9c102_i2c_write(cam, 0x11, 0x09);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 3e736be5de84..eb220461ac77 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1321,7 +1321,7 @@ static int saa_ioctl(struct inode *inode, struct file *file,
u32 format;
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
- if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+ if (p.palette < ARRAY_SIZE(palette2fmt)) {
format = palette2fmt[p.palette];
saa->win.color_fmt = format;
saawrite(format | 0x60,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index bf3aa8d2d57e..9e009a7ab863 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -499,13 +499,14 @@ exit:
* sysfs
***************************************************************************/
#define stv680_file(name, variable, field) \
-static ssize_t show_##name(struct class_device *class_dev, char *buf) \
+static ssize_t show_##name(struct device *class_dev, \
+ struct device_attribute *attr, char *buf) \
{ \
struct video_device *vdev = to_video_device(class_dev); \
struct usb_stv *stv = video_get_drvdata(vdev); \
return sprintf(buf, field, stv->variable); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
stv680_file(model, camera_name, "%s\n");
stv680_file(in_use, user, "%d\n");
@@ -520,53 +521,53 @@ static int stv680_create_sysfs_files(struct video_device *vdev)
{
int rc;
- rc = video_device_create_file(vdev, &class_device_attr_model);
+ rc = video_device_create_file(vdev, &dev_attr_model);
if (rc) goto err;
- rc = video_device_create_file(vdev, &class_device_attr_in_use);
+ rc = video_device_create_file(vdev, &dev_attr_in_use);
if (rc) goto err_model;
- rc = video_device_create_file(vdev, &class_device_attr_streaming);
+ rc = video_device_create_file(vdev, &dev_attr_streaming);
if (rc) goto err_inuse;
- rc = video_device_create_file(vdev, &class_device_attr_palette);
+ rc = video_device_create_file(vdev, &dev_attr_palette);
if (rc) goto err_stream;
- rc = video_device_create_file(vdev, &class_device_attr_frames_total);
+ rc = video_device_create_file(vdev, &dev_attr_frames_total);
if (rc) goto err_pal;
- rc = video_device_create_file(vdev, &class_device_attr_frames_read);
+ rc = video_device_create_file(vdev, &dev_attr_frames_read);
if (rc) goto err_framtot;
- rc = video_device_create_file(vdev, &class_device_attr_packets_dropped);
+ rc = video_device_create_file(vdev, &dev_attr_packets_dropped);
if (rc) goto err_framread;
- rc = video_device_create_file(vdev, &class_device_attr_decoding_errors);
+ rc = video_device_create_file(vdev, &dev_attr_decoding_errors);
if (rc) goto err_dropped;
return 0;
err_dropped:
- video_device_remove_file(vdev, &class_device_attr_packets_dropped);
+ video_device_remove_file(vdev, &dev_attr_packets_dropped);
err_framread:
- video_device_remove_file(vdev, &class_device_attr_frames_read);
+ video_device_remove_file(vdev, &dev_attr_frames_read);
err_framtot:
- video_device_remove_file(vdev, &class_device_attr_frames_total);
+ video_device_remove_file(vdev, &dev_attr_frames_total);
err_pal:
- video_device_remove_file(vdev, &class_device_attr_palette);
+ video_device_remove_file(vdev, &dev_attr_palette);
err_stream:
- video_device_remove_file(vdev, &class_device_attr_streaming);
+ video_device_remove_file(vdev, &dev_attr_streaming);
err_inuse:
- video_device_remove_file(vdev, &class_device_attr_in_use);
+ video_device_remove_file(vdev, &dev_attr_in_use);
err_model:
- video_device_remove_file(vdev, &class_device_attr_model);
+ video_device_remove_file(vdev, &dev_attr_model);
err:
return rc;
}
static void stv680_remove_sysfs_files(struct video_device *vdev)
{
- video_device_remove_file(vdev, &class_device_attr_model);
- video_device_remove_file(vdev, &class_device_attr_in_use);
- video_device_remove_file(vdev, &class_device_attr_streaming);
- video_device_remove_file(vdev, &class_device_attr_palette);
- video_device_remove_file(vdev, &class_device_attr_frames_total);
- video_device_remove_file(vdev, &class_device_attr_frames_read);
- video_device_remove_file(vdev, &class_device_attr_packets_dropped);
- video_device_remove_file(vdev, &class_device_attr_decoding_errors);
+ video_device_remove_file(vdev, &dev_attr_model);
+ video_device_remove_file(vdev, &dev_attr_in_use);
+ video_device_remove_file(vdev, &dev_attr_streaming);
+ video_device_remove_file(vdev, &dev_attr_palette);
+ video_device_remove_file(vdev, &dev_attr_frames_total);
+ video_device_remove_file(vdev, &dev_attr_frames_read);
+ video_device_remove_file(vdev, &dev_attr_packets_dropped);
+ video_device_remove_file(vdev, &dev_attr_decoding_errors);
}
/********************************************************************
@@ -715,8 +716,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
stv680_video_irq, stv680);
stv680->urb[i] = urb;
err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
- if (err)
- PDEBUG (0, "STV(e): urb burned down in start stream");
+ if (err) {
+ PDEBUG (0, "STV(e): urb burned down with err "
+ "%d in start stream %d", err, i);
+ goto nomem_err;
+ }
} /* i STV680_NUMSBUF */
stv680->framecount = 0;
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
new file mode 100644
index 000000000000..41cd6a0b0485
--- /dev/null
+++ b/drivers/media/video/tcm825x.c
@@ -0,0 +1,928 @@
+/*
+ * drivers/media/video/tcm825x.c
+ *
+ * TCM825X camera sensor driver.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from David Cohen <david.cohen@indt.org.br>
+ *
+ * This driver was based on ov9640 sensor driver from MontaVista
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/i2c.h>
+#include <media/v4l2-int-device.h>
+
+#include "tcm825x.h"
+
+/*
+ * The sensor has two fps modes: the lower one just gives half the fps
+ * at the same xclk than the high one.
+ */
+#define MAX_FPS 30
+#define MIN_FPS 8
+#define MAX_HALF_FPS (MAX_FPS / 2)
+#define HIGH_FPS_MODE_LOWER_LIMIT 14
+#define DEFAULT_FPS MAX_HALF_FPS
+
+struct tcm825x_sensor {
+ const struct tcm825x_platform_data *platform_data;
+ struct v4l2_int_device *v4l2_int_device;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ struct v4l2_fract timeperframe;
+};
+
+/* list of image formats supported by TCM825X sensor */
+const static struct v4l2_fmtdesc tcm825x_formats[] = {
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ }, {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * We interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+};
+
+#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats)
+
+/*
+ * TCM825X register configuration for all combinations of pixel format and
+ * image size
+ */
+const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
+const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
+const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
+const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
+const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
+const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
+
+const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
+const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
+
+/* Our own specific controls */
+#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2
+#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3
+#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4
+#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
+
+/* Video controls */
+static struct vcontrol {
+ struct v4l2_queryctrl qc;
+ u16 reg;
+ u16 start_bit;
+} video_control[] = {
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ },
+ .reg = TCM825X_AG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ },
+ .reg = TCM825X_MRG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ },
+ .reg = TCM825X_MBG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_AWBSW,
+ .start_bit = 7,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure Time",
+ .minimum = 0,
+ .maximum = 0x1fff,
+ .step = 1,
+ },
+ .reg = TCM825X_ESRSPD_U,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_H_INV,
+ .start_bit = 6,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_V_INV,
+ .start_bit = 7,
+ },
+ /* Private controls */
+ {
+ {
+ .id = V4L2_CID_ALC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Luminance Control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_ALCSW,
+ .start_bit = 7,
+ },
+ {
+ {
+ .id = V4L2_CID_H_EDGE_EN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Horizontal Edge Enhancement",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ },
+ .reg = TCM825X_HDTG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_V_EDGE_EN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical Edge Enhancement",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ },
+ .reg = TCM825X_VDTG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_LENS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Lens Shading Compensation",
+ .minimum = 0,
+ .maximum = 0x3f,
+ .step = 1,
+ },
+ .reg = TCM825X_LENS,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_MAX_EXPOSURE_TIME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Maximum Exposure Time",
+ .minimum = 0,
+ .maximum = 0x3,
+ .step = 1,
+ },
+ .reg = TCM825X_ESRLIM,
+ .start_bit = 5,
+ },
+};
+
+
+const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+
+const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+{ &yuv422, &rgb565 };
+
+/*
+ * Read a value from a register in an TCM825X sensor device. The value is
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_read_reg(struct i2c_client *client, int reg)
+{
+ int err;
+ struct i2c_msg msg[2];
+ u8 reg_buf, data_buf = 0;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &reg_buf;
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = &data_buf;
+
+ reg_buf = reg;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (err < 0)
+ return err;
+ return data_buf;
+}
+
+/*
+ * Write a value to a register in an TCM825X sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 2;
+ msg->buf = data;
+ data[0] = reg;
+ data[1] = val;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0)
+ return 0;
+ return err;
+}
+
+static int __tcm825x_write_reg_mask(struct i2c_client *client,
+ u8 reg, u8 val, u8 mask)
+{
+ int rc;
+
+ /* need to do read - modify - write */
+ rc = tcm825x_read_reg(client, reg);
+ if (rc < 0)
+ return rc;
+
+ rc &= (~mask); /* Clear the masked bits */
+ val &= mask; /* Enforce mask on value */
+ val |= rc;
+
+ /* write the new value to the register */
+ rc = tcm825x_write_reg(client, reg, val);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+#define tcm825x_write_reg_mask(client, regmask, val) \
+ __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \
+ TCM825X_MASK((regmask)))
+
+
+/*
+ * Initialize a list of TCM825X registers.
+ * The list of registers is terminated by the pair of values
+ * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_default_regs(struct i2c_client *client,
+ const struct tcm825x_reg *reglist)
+{
+ int err;
+ const struct tcm825x_reg *next = reglist;
+
+ while (!((next->reg == TCM825X_REG_TERM)
+ && (next->val == TCM825X_VAL_TERM))) {
+ err = tcm825x_write_reg(client, next->reg, next->val);
+ if (err) {
+ dev_err(&client->dev, "register writing failed\n");
+ return err;
+ }
+ next++;
+ }
+
+ return 0;
+}
+
+static struct vcontrol *find_vctrl(int id)
+{
+ int i;
+
+ if (id < V4L2_CID_BASE)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(video_control); i++)
+ if (video_control[i].qc.id == id)
+ return &video_control[i];
+
+ return NULL;
+}
+
+/*
+ * Find the best match for a requested image capture size. The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
+ unsigned int width,
+ unsigned int height)
+{
+ enum image_size isize;
+ unsigned long pixels = width * height;
+ struct tcm825x_sensor *sensor = s->priv;
+
+ for (isize = subQCIF; isize < VGA; isize++) {
+ if (tcm825x_sizes[isize + 1].height
+ * tcm825x_sizes[isize + 1].width > pixels) {
+ dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
+
+ return isize;
+ }
+ }
+
+ dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
+
+ return VGA;
+}
+
+/*
+ * Configure the TCM825X for current image size, pixel format, and
+ * frame period. fper is the frame period (in seconds) expressed as a
+ * fraction. Returns zero if successful, or non-zero otherwise. The
+ * actual frame period is returned in fper.
+ */
+static int tcm825x_configure(struct v4l2_int_device *s)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &sensor->pix;
+ enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
+ struct v4l2_fract *fper = &sensor->timeperframe;
+ enum pixel_format pfmt;
+ int err;
+ u32 tgt_fps;
+ u8 val;
+
+ /* common register initialization */
+ err = tcm825x_write_default_regs(
+ sensor->i2c_client, sensor->platform_data->default_regs());
+ if (err)
+ return err;
+
+ /* configure image size */
+ val = tcm825x_siz_reg[isize]->val;
+ dev_dbg(&sensor->i2c_client->dev,
+ "configuring image size %d\n", isize);
+ err = tcm825x_write_reg_mask(sensor->i2c_client,
+ tcm825x_siz_reg[isize]->reg, val);
+ if (err)
+ return err;
+
+ /* configure pixel format */
+ switch (pix->pixelformat) {
+ default:
+ case V4L2_PIX_FMT_RGB565:
+ pfmt = RGB565;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ pfmt = YUV422;
+ break;
+ }
+
+ dev_dbg(&sensor->i2c_client->dev,
+ "configuring pixel format %d\n", pfmt);
+ val = tcm825x_fmt_reg[pfmt]->val;
+
+ err = tcm825x_write_reg_mask(sensor->i2c_client,
+ tcm825x_fmt_reg[pfmt]->reg, val);
+ if (err)
+ return err;
+
+ /*
+ * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
+ * set. Frame rate will be halved from the normal.
+ */
+ tgt_fps = fper->denominator / fper->numerator;
+ if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
+ val = tcm825x_read_reg(sensor->i2c_client, 0x02);
+ val |= 0x80;
+ tcm825x_write_reg(sensor->i2c_client, 0x02, val);
+ }
+
+ return 0;
+}
+
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ struct vcontrol *control;
+
+ control = find_vctrl(qc->id);
+
+ if (control == NULL)
+ return -EINVAL;
+
+ *qc = control->qc;
+
+ return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int val, r;
+ struct vcontrol *lvc;
+
+ /* exposure time is special, spread accross 2 registers */
+ if (vc->id == V4L2_CID_EXPOSURE) {
+ int val_lower, val_upper;
+
+ val_upper = tcm825x_read_reg(client,
+ TCM825X_ADDR(TCM825X_ESRSPD_U));
+ if (val_upper < 0)
+ return val_upper;
+ val_lower = tcm825x_read_reg(client,
+ TCM825X_ADDR(TCM825X_ESRSPD_L));
+ if (val_lower < 0)
+ return val_lower;
+
+ vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
+ return 0;
+ }
+
+ lvc = find_vctrl(vc->id);
+ if (lvc == NULL)
+ return -EINVAL;
+
+ r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
+ if (r < 0)
+ return r;
+ val = r & TCM825X_MASK(lvc->reg);
+ val >>= lvc->start_bit;
+
+ if (val < 0)
+ return val;
+
+ vc->value = val;
+ return 0;
+}
+
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ struct vcontrol *lvc;
+ int val = vc->value;
+
+ /* exposure time is special, spread accross 2 registers */
+ if (vc->id == V4L2_CID_EXPOSURE) {
+ int val_lower, val_upper;
+ val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
+ val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
+
+ if (tcm825x_write_reg_mask(client,
+ TCM825X_ESRSPD_U, val_upper))
+ return -EIO;
+
+ if (tcm825x_write_reg_mask(client,
+ TCM825X_ESRSPD_L, val_lower))
+ return -EIO;
+
+ return 0;
+ }
+
+ lvc = find_vctrl(vc->id);
+ if (lvc == NULL)
+ return -EINVAL;
+
+ val = val << lvc->start_bit;
+ if (tcm825x_write_reg_mask(client, lvc->reg, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ int index = fmt->index;
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (index >= TCM825X_NUM_CAPTURE_FORMATS)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ fmt->flags = tcm825x_formats[index].flags;
+ strlcpy(fmt->description, tcm825x_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = tcm825x_formats[index].pixelformat;
+
+ return 0;
+}
+
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ enum image_size isize;
+ int ifmt;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ isize = tcm825x_find_size(s, pix->width, pix->height);
+ dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
+ isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
+
+ pix->width = tcm825x_sizes[isize].width;
+ pix->height = tcm825x_sizes[isize].height;
+
+ for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
+ if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
+ break;
+
+ if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
+ ifmt = 0; /* Default = YUV 4:2:2 */
+
+ pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->priv = 0;
+ dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
+ pix->pixelformat);
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ return 0;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int rval;
+
+ rval = ioctl_try_fmt_cap(s, f);
+ if (rval)
+ return rval;
+
+ rval = tcm825x_configure(s);
+
+ sensor->pix = *pix;
+
+ return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe = sensor->timeperframe;
+
+ return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if ((timeperframe->numerator == 0)
+ || (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ sensor->timeperframe = *timeperframe;
+
+ rval = tcm825x_configure(s);
+
+ return rval;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ return sensor->platform_data->power_set(on);
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency.
+ *
+ * TCM825X input frequency characteristics are:
+ * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
+ */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &sensor->timeperframe;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ int rval;
+
+ rval = sensor->platform_data->ifparm(p);
+ if (rval)
+ return rval;
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
+ (2457 * tgt_fps) / MAX_HALF_FPS :
+ (2457 * tgt_fps) / MAX_FPS;
+ tgt_xclk *= 10000;
+
+ tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
+
+ p->u.bt656.clock_curr = tgt_xclk;
+
+ return 0;
+}
+
+static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
+}
+
+static int ioctl_reset(struct v4l2_int_device *s)
+{
+ return -EBUSY;
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ return tcm825x_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ int r;
+
+ r = tcm825x_read_reg(sensor->i2c_client, 0x01);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(&sensor->i2c_client->dev, "device not detected\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
+ { vidioc_int_dev_exit_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_exit },
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)ioctl_s_power },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+ { vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
+ { vidioc_int_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_reset },
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+ { vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+ { vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
+ { vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_queryctrl },
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave tcm825x_slave = {
+ .ioctls = tcm825x_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
+};
+
+static struct tcm825x_sensor tcm825x;
+
+static struct v4l2_int_device tcm825x_int_device = {
+ .module = THIS_MODULE,
+ .name = TCM825X_NAME,
+ .priv = &tcm825x,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &tcm825x_slave,
+ },
+};
+
+static int tcm825x_probe(struct i2c_client *client)
+{
+ struct tcm825x_sensor *sensor = &tcm825x;
+ int rval;
+
+ if (i2c_get_clientdata(client))
+ return -EBUSY;
+
+ sensor->platform_data = client->dev.platform_data;
+
+ if (sensor->platform_data == NULL
+ && !sensor->platform_data->is_okay())
+ return -ENODEV;
+
+ sensor->v4l2_int_device = &tcm825x_int_device;
+
+ sensor->i2c_client = client;
+ i2c_set_clientdata(client, sensor);
+
+ /* Make the default capture format QVGA RGB565 */
+ sensor->pix.width = tcm825x_sizes[QVGA].width;
+ sensor->pix.height = tcm825x_sizes[QVGA].height;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+ rval = v4l2_int_device_register(sensor->v4l2_int_device);
+ if (rval)
+ i2c_set_clientdata(client, NULL);
+
+ return rval;
+}
+
+static int __exit tcm825x_remove(struct i2c_client *client)
+{
+ struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ v4l2_int_device_unregister(sensor->v4l2_int_device);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static struct i2c_driver tcm825x_i2c_driver = {
+ .driver = {
+ .name = TCM825X_NAME,
+ },
+ .probe = tcm825x_probe,
+ .remove = __exit_p(tcm825x_remove),
+};
+
+static struct tcm825x_sensor tcm825x = {
+ .timeperframe = {
+ .numerator = 1,
+ .denominator = DEFAULT_FPS,
+ },
+};
+
+static int __init tcm825x_init(void)
+{
+ int rval;
+
+ rval = i2c_add_driver(&tcm825x_i2c_driver);
+ if (rval)
+ printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
+ __FUNCTION__);
+
+ return rval;
+}
+
+static void __exit tcm825x_exit(void)
+{
+ i2c_del_driver(&tcm825x_i2c_driver);
+}
+
+/*
+ * FIXME: Menelaus isn't ready (?) at module_init stage, so use
+ * late_initcall for now.
+ */
+late_initcall(tcm825x_init);
+module_exit(tcm825x_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("TCM825x camera sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
new file mode 100644
index 000000000000..966765b66b3a
--- /dev/null
+++ b/drivers/media/video/tcm825x.h
@@ -0,0 +1,199 @@
+/*
+ * drivers/media/video/tcm825x.h
+ *
+ * Register definitions for the TCM825X CameraChip.
+ *
+ * Author: David Cohen (david.cohen@indt.org.br)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This file was based on ov9640.h from MontaVista
+ */
+
+#ifndef TCM825X_H
+#define TCM825X_H
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-int-device.h>
+
+#define TCM825X_NAME "tcm825x"
+
+#define TCM825X_MASK(x) x & 0x00ff
+#define TCM825X_ADDR(x) (x & 0xff00) >> 8
+
+/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
+#define TCM825X_I2C_ADDR 0x3d
+
+/*
+ * define register offsets for the TCM825X sensor chip
+ * OFFSET(8 bits) + MASK(8 bits)
+ * MASK bit 4 and 3 are used when the register uses more than one address
+ */
+#define TCM825X_FPS 0x0280
+#define TCM825X_ACF 0x0240
+#define TCM825X_DOUTBUF 0x020C
+#define TCM825X_DCLKP 0x0202
+#define TCM825X_ACFDET 0x0201
+#define TCM825X_DOUTSW 0x0380
+#define TCM825X_DATAHZ 0x0340
+#define TCM825X_PICSIZ 0x033c
+#define TCM825X_PICFMT 0x0302
+#define TCM825X_V_INV 0x0480
+#define TCM825X_H_INV 0x0440
+#define TCM825X_ESRLSW 0x0430
+#define TCM825X_V_LENGTH 0x040F
+#define TCM825X_ALCSW 0x0580
+#define TCM825X_ESRLIM 0x0560
+#define TCM825X_ESRSPD_U 0x051F
+#define TCM825X_ESRSPD_L 0x06FF
+#define TCM825X_AG 0x07FF
+#define TCM825X_ESRSPD2 0x06FF
+#define TCM825X_ALCMODE 0x0830
+#define TCM825X_ALCH 0x080F
+#define TCM825X_ALCL 0x09FF
+#define TCM825X_AWBSW 0x0A80
+#define TCM825X_MRG 0x0BFF
+#define TCM825X_MBG 0x0CFF
+#define TCM825X_GAMSW 0x0D80
+#define TCM825X_HDTG 0x0EFF
+#define TCM825X_VDTG 0x0FFF
+#define TCM825X_HDTCORE 0x10F0
+#define TCM825X_VDTCORE 0x100F
+#define TCM825X_CONT 0x11FF
+#define TCM825X_BRIGHT 0x12FF
+#define TCM825X_VHUE 0x137F
+#define TCM825X_UHUE 0x147F
+#define TCM825X_VGAIN 0x153F
+#define TCM825X_UGAIN 0x163F
+#define TCM825X_UVCORE 0x170F
+#define TCM825X_SATU 0x187F
+#define TCM825X_MHMODE 0x1980
+#define TCM825X_MHLPFSEL 0x1940
+#define TCM825X_YMODE 0x1930
+#define TCM825X_MIXHG 0x1907
+#define TCM825X_LENS 0x1A3F
+#define TCM825X_AGLIM 0x1BE0
+#define TCM825X_LENSRPOL 0x1B10
+#define TCM825X_LENSRGAIN 0x1B0F
+#define TCM825X_ES100S 0x1CFF
+#define TCM825X_ES120S 0x1DFF
+#define TCM825X_DMASK 0x1EC0
+#define TCM825X_CODESW 0x1E20
+#define TCM825X_CODESEL 0x1E10
+#define TCM825X_TESPIC 0x1E04
+#define TCM825X_PICSEL 0x1E03
+#define TCM825X_HNUM 0x20FF
+#define TCM825X_VOUTPH 0x287F
+#define TCM825X_ESROUT 0x327F
+#define TCM825X_ESROUT2 0x33FF
+#define TCM825X_AGOUT 0x34FF
+#define TCM825X_DGOUT 0x353F
+#define TCM825X_AGSLOW1 0x39C0
+#define TCM825X_FLLSMODE 0x3930
+#define TCM825X_FLLSLIM 0x390F
+#define TCM825X_DETSEL 0x3AF0
+#define TCM825X_ACDETNC 0x3A0F
+#define TCM825X_AGSLOW2 0x3BC0
+#define TCM825X_DG 0x3B3F
+#define TCM825X_REJHLEV 0x3CFF
+#define TCM825X_ALCLOCK 0x3D80
+#define TCM825X_FPSLNKSW 0x3D40
+#define TCM825X_ALCSPD 0x3D30
+#define TCM825X_REJH 0x3D03
+#define TCM825X_SHESRSW 0x3E80
+#define TCM825X_ESLIMSEL 0x3E40
+#define TCM825X_SHESRSPD 0x3E30
+#define TCM825X_ELSTEP 0x3E0C
+#define TCM825X_ELSTART 0x3E03
+#define TCM825X_AGMIN 0x3FFF
+#define TCM825X_PREGRG 0x423F
+#define TCM825X_PREGBG 0x433F
+#define TCM825X_PRERG 0x443F
+#define TCM825X_PREBG 0x453F
+#define TCM825X_MSKBR 0x477F
+#define TCM825X_MSKGR 0x487F
+#define TCM825X_MSKRB 0x497F
+#define TCM825X_MSKGB 0x4A7F
+#define TCM825X_MSKRG 0x4B7F
+#define TCM825X_MSKBG 0x4C7F
+#define TCM825X_HDTCSW 0x4D80
+#define TCM825X_VDTCSW 0x4D40
+#define TCM825X_DTCYL 0x4D3F
+#define TCM825X_HDTPSW 0x4E80
+#define TCM825X_VDTPSW 0x4E40
+#define TCM825X_DTCGAIN 0x4E3F
+#define TCM825X_DTLLIMSW 0x4F10
+#define TCM825X_DTLYLIM 0x4F0F
+#define TCM825X_YLCUTLMSK 0x5080
+#define TCM825X_YLCUTL 0x503F
+#define TCM825X_YLCUTHMSK 0x5180
+#define TCM825X_YLCUTH 0x513F
+#define TCM825X_UVSKNC 0x527F
+#define TCM825X_UVLJ 0x537F
+#define TCM825X_WBGMIN 0x54FF
+#define TCM825X_WBGMAX 0x55FF
+#define TCM825X_WBSPDUP 0x5603
+#define TCM825X_ALLAREA 0x5820
+#define TCM825X_WBLOCK 0x5810
+#define TCM825X_WB2SP 0x580F
+#define TCM825X_KIZUSW 0x5920
+#define TCM825X_PBRSW 0x5910
+#define TCM825X_ABCSW 0x5903
+#define TCM825X_PBDLV 0x5AFF
+#define TCM825X_PBC1LV 0x5BFF
+
+#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1)
+
+#define TCM825X_BYTES_PER_PIXEL 2
+
+#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */
+#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */
+
+/* define a structure for tcm825x register initialization values */
+struct tcm825x_reg {
+ u8 val;
+ u16 reg;
+};
+
+enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
+enum pixel_format { YUV422 = 0, RGB565 };
+#define NUM_IMAGE_SIZES 6
+#define NUM_PIXEL_FORMATS 2
+
+#define TCM825X_XCLK_MIN 11900000
+#define TCM825X_XCLK_MAX 25000000
+
+struct capture_size {
+ unsigned long width;
+ unsigned long height;
+};
+
+struct tcm825x_platform_data {
+ /* Is the sensor usable? Doesn't yet mean it's there, but you
+ * can try! */
+ int (*is_okay)(void);
+ /* Set power state, zero is off, non-zero is on. */
+ int (*power_set)(int power);
+ /* Default registers written after power-on or reset. */
+ const struct tcm825x_reg *(*default_regs)(void);
+ int (*needs_reset)(struct v4l2_int_device *s, void *buf,
+ struct v4l2_pix_format *fmt);
+ int (*ifparm)(struct v4l2_ifparm *p);
+};
+
+/* Array of image sizes supported by TCM825X. These must be ordered from
+ * smallest image size to largest.
+ */
+const static struct capture_size tcm825x_sizes[] = {
+ { 128, 96 }, /* subQCIF */
+ { 160, 120 }, /* QQVGA */
+ { 176, 144 }, /* QCIF */
+ { 320, 240 }, /* QVGA */
+ { 352, 288 }, /* CIF */
+ { 640, 480 }, /* VGA */
+};
+
+#endif /* ifndef TCM825X_H */
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 1a1bef0e9c3d..0e5cf459d3ed 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -16,12 +16,38 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This "tda8290" module was split apart from the original "tuner" module.
*/
#include <linux/i2c.h>
-#include <linux/videodev.h>
#include <linux/delay.h>
-#include <media/tuner.h>
+#include <linux/videodev.h>
+#include "tuner-i2c.h"
+#include "tda8290.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tda8290 "
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+ struct tuner_i2c_props i2c_props;
+
+ unsigned char tda8290_easy_mode;
+ unsigned char tda827x_lpsel;
+ unsigned char tda827x_addr;
+ unsigned char tda827x_ver;
+ unsigned int sgIF;
+
+ u32 frequency;
+
+ unsigned int *lna_cfg;
+ int (*tuner_callback) (void *dev, int command,int arg);
+};
/* ---------------------------------------------------------------------- */
@@ -69,19 +95,21 @@ static struct tda827x_data tda827x_analog[] = {
{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */
};
-static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void tda827x_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
unsigned char tuner_reg[8];
unsigned char reg2[2];
u32 N;
int i;
- struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+ struct tda8290_priv *priv = fe->tuner_priv;
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
+ unsigned int freq = params->frequency;
- if (t->mode == V4L2_TUNER_RADIO)
+ if (params->mode == V4L2_TUNER_RADIO)
freq = freq / 1000;
- N = freq + ifc;
+ N = freq + priv->sgIF;
i = 0;
while (tda827x_analog[i].lomax < N) {
if(tda827x_analog[i + 1].lomax == 0)
@@ -95,7 +123,7 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
tuner_reg[1] = (unsigned char)(N>>8);
tuner_reg[2] = (unsigned char) N;
tuner_reg[3] = 0x40;
- tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+ tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) +
(tda827x_analog[i].bs <<3) + tda827x_analog[i].bp;
tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
@@ -103,53 +131,53 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
msg.buf = tuner_reg;
msg.len = 8;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msg.buf= reg2;
msg.len = 2;
reg2[0] = 0x80;
reg2[1] = 0;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x60;
reg2[1] = 0xbf;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x30;
reg2[1] = tuner_reg[4] + 0x80;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(1);
reg2[0] = 0x30;
reg2[1] = tuner_reg[4] + 4;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(1);
reg2[0] = 0x30;
reg2[1] = tuner_reg[4];
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(550);
reg2[0] = 0x30;
reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x60;
reg2[1] = 0x3f;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x80;
reg2[1] = 0x08; // Vsync en
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
-static void tda827x_agcf(struct i2c_client *c)
+static void tda827x_agcf(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char data[] = {0x80, 0x0c};
- struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
/* ---------------------------------------------------------------------- */
@@ -192,57 +220,64 @@ static struct tda827xa_data tda827xa_analog[] = {
{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */
};
-static void tda827xa_lna_gain(struct i2c_client *c, int high)
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char buf[] = {0x22, 0x01};
int arg;
- struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
- if (t->config) {
+ struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+ if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL))
+ return;
+
+ if (*priv->lna_cfg) {
if (high)
tuner_dbg("setting LNA to high gain\n");
else
tuner_dbg("setting LNA to low gain\n");
}
- switch (t->config) {
+ switch (*priv->lna_cfg) {
case 0: /* no LNA */
break;
case 1: /* switch is GPIO 0 of tda8290 */
case 2:
/* turn Vsync on */
- if (t->std & V4L2_STD_MN)
+ if (params->std & V4L2_STD_MN)
arg = 1;
else
arg = 0;
- if (t->tuner_callback)
- t->tuner_callback(c->adapter->algo_data, 1, arg);
+ if (priv->tuner_callback)
+ priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
buf[1] = high ? 0 : 1;
- if (t->config == 2)
+ if (*priv->lna_cfg == 2)
buf[1] = high ? 1 : 0;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
break;
case 3: /* switch with GPIO of saa713x */
- if (t->tuner_callback)
- t->tuner_callback(c->adapter->algo_data, 0, high);
+ if (priv->tuner_callback)
+ priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
break;
}
}
-static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void tda827xa_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
unsigned char tuner_reg[11];
u32 N;
int i;
- struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+ struct tda8290_priv *priv = fe->tuner_priv;
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
+ unsigned int freq = params->frequency;
- tda827xa_lna_gain( c, 1);
+ tda827xa_lna_gain(fe, 1, params);
msleep(10);
- if (t->mode == V4L2_TUNER_RADIO)
+ if (params->mode == V4L2_TUNER_RADIO)
freq = freq / 1000;
- N = freq + ifc;
+ N = freq + priv->sgIF;
i = 0;
while (tda827xa_analog[i].lomax < N) {
if(tda827xa_analog[i + 1].lomax == 0)
@@ -265,90 +300,141 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
tuner_reg[9] = 0x20;
tuner_reg[10] = 0x00;
msg.len = 11;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0x90;
tuner_reg[1] = 0xff;
tuner_reg[2] = 0xe0;
tuner_reg[3] = 0;
- tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+ tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
msg.len = 5;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0xa0;
tuner_reg[1] = 0xc0;
msg.len = 2;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0x30;
tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msg.flags = I2C_M_RD;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msg.flags = 0;
tuner_reg[1] >>= 4;
tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
if (tuner_reg[1] < 1)
- tda827xa_lna_gain( c, 0);
+ tda827xa_lna_gain(fe, 0, params);
msleep(100);
tuner_reg[0] = 0x60;
tuner_reg[1] = 0x3c;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(163);
tuner_reg[0] = 0x50;
tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0x80;
tuner_reg[1] = 0x28;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0xb0;
tuner_reg[1] = 0x01;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0xc0;
- tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
- i2c_transfer(c->adapter, &msg, 1);
+ tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
-static void tda827xa_agcf(struct i2c_client *c)
+static void tda827xa_agcf(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char data[] = {0x80, 0x2c};
- struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
/*---------------------------------------------------------------------*/
-static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
{
+ struct tda8290_priv *priv = fe->tuner_priv;
+
unsigned char enable[2] = { 0x21, 0xC0 };
unsigned char disable[2] = { 0x21, 0x00 };
unsigned char *msg;
if(close) {
msg = enable;
- i2c_master_send(c, msg, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
/* let the bridge stabilize */
msleep(20);
} else {
msg = disable;
- i2c_master_send(c, msg, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
}
}
/*---------------------------------------------------------------------*/
-static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void set_audio(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct tda8290_priv *priv = fe->tuner_priv;
+ char* mode;
+
+ priv->tda827x_lpsel = 0;
+ if (params->std & V4L2_STD_MN) {
+ priv->sgIF = 92;
+ priv->tda8290_easy_mode = 0x01;
+ priv->tda827x_lpsel = 1;
+ mode = "MN";
+ } else if (params->std & V4L2_STD_B) {
+ priv->sgIF = 108;
+ priv->tda8290_easy_mode = 0x02;
+ mode = "B";
+ } else if (params->std & V4L2_STD_GH) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x04;
+ mode = "GH";
+ } else if (params->std & V4L2_STD_PAL_I) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x08;
+ mode = "I";
+ } else if (params->std & V4L2_STD_DK) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
+ mode = "DK";
+ } else if (params->std & V4L2_STD_SECAM_L) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x20;
+ mode = "L";
+ } else if (params->std & V4L2_STD_SECAM_LC) {
+ priv->sgIF = 20;
+ priv->tda8290_easy_mode = 0x40;
+ mode = "LC";
+ } else {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
+ mode = "xx";
+ }
+
+ if (params->mode == V4L2_TUNER_RADIO)
+ priv->sgIF = 88; /* if frequency is 5.5 MHz */
+
+ tuner_dbg("setting tda8290 to system %s\n", mode);
+}
+
+static int tda8290_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char soft_reset[] = { 0x00, 0x00 };
- unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode };
+ unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode };
unsigned char expert_mode[] = { 0x01, 0x80 };
unsigned char agc_out_on[] = { 0x02, 0x00 };
unsigned char gainset_off[] = { 0x28, 0x14 };
@@ -369,35 +455,38 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
pll_stat;
int i;
- tuner_dbg("tda827xa config is 0x%02x\n", t->config);
- i2c_master_send(c, easy_mode, 2);
- i2c_master_send(c, agc_out_on, 2);
- i2c_master_send(c, soft_reset, 2);
+ set_audio(fe, params);
+
+ if (priv->lna_cfg)
+ tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
+ tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
msleep(1);
- expert_mode[1] = t->tda8290_easy_mode + 0x80;
- i2c_master_send(c, expert_mode, 2);
- i2c_master_send(c, gainset_off, 2);
- i2c_master_send(c, if_agc_spd, 2);
- if (t->tda8290_easy_mode & 0x60)
- i2c_master_send(c, adc_head_9, 2);
+ expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+ tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+ if (priv->tda8290_easy_mode & 0x60)
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
else
- i2c_master_send(c, adc_head_6, 2);
- i2c_master_send(c, pll_bw_nom, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
- tda8290_i2c_bridge(c, 1);
- if (t->tda827x_ver != 0)
- tda827xa_tune(c, ifc, freq);
+ tda8290_i2c_bridge(fe, 1);
+ if (priv->tda827x_ver != 0)
+ tda827xa_set_analog_params(fe, params);
else
- tda827x_tune(c, ifc, freq);
+ tda827x_set_analog_params(fe, params);
for (i = 0; i < 3; i++) {
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if (pll_stat & 0x80) {
- i2c_master_send(c, &addr_adc_sat, 1);
- i2c_master_recv(c, &adc_sat, 1);
- i2c_master_send(c, &addr_agc_stat, 1);
- i2c_master_recv(c, &agc_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
break;
} else {
@@ -409,188 +498,205 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
agc_stat, adc_sat, pll_stat & 0x80);
- i2c_master_send(c, gainset_2, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
msleep(100);
- i2c_master_send(c, &addr_agc_stat, 1);
- i2c_master_recv(c, &agc_stat, 1);
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if ((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
agc_stat, pll_stat & 0x80);
- if (t->tda827x_ver != 0)
- tda827xa_agcf(c);
+ if (priv->tda827x_ver != 0)
+ tda827xa_agcf(fe);
else
- tda827x_agcf(c);
+ tda827x_agcf(fe);
msleep(100);
- i2c_master_send(c, &addr_agc_stat, 1);
- i2c_master_recv(c, &agc_stat, 1);
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
- i2c_master_send(c, adc_head_12, 2);
- i2c_master_send(c, pll_bw_low, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2);
msleep(100);
}
}
}
/* l/ l' deadlock? */
- if(t->tda8290_easy_mode & 0x60) {
- i2c_master_send(c, &addr_adc_sat, 1);
- i2c_master_recv(c, &adc_sat, 1);
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ if(priv->tda8290_easy_mode & 0x60) {
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if ((adc_sat > 20) || !(pll_stat & 0x80)) {
tuner_dbg("trying to resolve SECAM L deadlock\n");
- i2c_master_send(c, agc_rst_on, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
msleep(40);
- i2c_master_send(c, agc_rst_off, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2);
}
}
- tda8290_i2c_bridge(c, 0);
- i2c_master_send(c, if_agc_set, 2);
+ tda8290_i2c_bridge(fe, 0);
+ tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
+
+ priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
+ params->frequency * 125 / 2 : params->frequency * 62500;
+
return 0;
}
/*---------------------------------------------------------------------*/
-static void set_audio(struct tuner *t)
+static int tda8290_has_signal(struct dvb_frontend *fe)
{
- char* mode;
+ struct tda8290_priv *priv = fe->tuner_priv;
+ int ret;
- t->tda827x_lpsel = 0;
- if (t->std & V4L2_STD_MN) {
- t->sgIF = 92;
- t->tda8290_easy_mode = 0x01;
- t->tda827x_lpsel = 1;
- mode = "MN";
- } else if (t->std & V4L2_STD_B) {
- t->sgIF = 108;
- t->tda8290_easy_mode = 0x02;
- mode = "B";
- } else if (t->std & V4L2_STD_GH) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x04;
- mode = "GH";
- } else if (t->std & V4L2_STD_PAL_I) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x08;
- mode = "I";
- } else if (t->std & V4L2_STD_DK) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x10;
- mode = "DK";
- } else if (t->std & V4L2_STD_SECAM_L) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x20;
- mode = "L";
- } else if (t->std & V4L2_STD_SECAM_LC) {
- t->sgIF = 20;
- t->tda8290_easy_mode = 0x40;
- mode = "LC";
- } else {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x10;
- mode = "xx";
- }
- tuner_dbg("setting tda8290 to system %s\n", mode);
-}
+ unsigned char i2c_get_afc[1] = { 0x1B };
+ unsigned char afc = 0;
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
- struct tuner *t = i2c_get_clientdata(c);
+ /* for now, report based on afc status */
+ tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+ tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+
+ ret = (afc & 0x80) ? 65535 : 0;
- set_audio(t);
- tda8290_tune(c, t->sgIF, freq);
+ tuner_dbg("AFC status: %d\n", ret);
+
+ return ret;
}
-static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
{
- /* if frequency is 5.5 MHz */
- tda8290_tune(c, 88, freq);
+ *status = 0;
+
+ if (tda8290_has_signal(fe))
+ *status = TUNER_STATUS_LOCKED;
+
+ return 0;
}
-static int has_signal(struct i2c_client *c)
+static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
{
- unsigned char i2c_get_afc[1] = { 0x1B };
- unsigned char afc = 0;
+ *strength = tda8290_has_signal(fe);
- i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
- i2c_master_recv(c, &afc, 1);
- return (afc & 0x80)? 65535:0;
+ return 0;
}
/*---------------------------------------------------------------------*/
-static void standby(struct i2c_client *c)
+static int tda8290_standby(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char cb1[] = { 0x30, 0xD0 };
unsigned char tda8290_standby[] = { 0x00, 0x02 };
unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
- tda8290_i2c_bridge(c, 1);
- if (t->tda827x_ver != 0)
+ tda8290_i2c_bridge(fe, 1);
+ if (priv->tda827x_ver != 0)
cb1[1] = 0x90;
- i2c_transfer(c->adapter, &msg, 1);
- tda8290_i2c_bridge(c, 0);
- i2c_master_send(c, tda8290_agc_tri, 2);
- i2c_master_send(c, tda8290_standby, 2);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ tda8290_i2c_bridge(fe, 0);
+ tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
+
+ return 0;
}
-static void tda8290_init_if(struct i2c_client *c)
+static void tda8290_init_if(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
+
unsigned char set_VS[] = { 0x30, 0x6F };
unsigned char set_GP00_CF[] = { 0x20, 0x01 };
unsigned char set_GP01_CF[] = { 0x20, 0x0B };
- if ((t->config == 1) || (t->config == 2))
- i2c_master_send(c, set_GP00_CF, 2);
+ if ((priv->lna_cfg) &&
+ ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
+ tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
else
- i2c_master_send(c, set_GP01_CF, 2);
- i2c_master_send(c, set_VS, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
}
-static void tda8290_init_tuner(struct i2c_client *c)
+static void tda8290_init_tuner(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
.buf=tda8275_init, .len = 14};
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
msg.buf = tda8275a_init;
- tda8290_i2c_bridge(c, 1);
- i2c_transfer(c->adapter, &msg, 1);
- tda8290_i2c_bridge(c, 0);
+ tda8290_i2c_bridge(fe, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ tda8290_i2c_bridge(fe, 0);
}
/*---------------------------------------------------------------------*/
-int tda8290_init(struct i2c_client *c)
+static int tda8290_release(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda8290_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tda8290_tuner_ops = {
+ .sleep = tda8290_standby,
+ .set_analog_params = tda8290_set_params,
+ .release = tda8290_release,
+ .get_frequency = tda8290_get_frequency,
+ .get_status = tda8290_get_status,
+ .get_rf_strength = tda8290_get_rf_strength,
+};
+
+struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr,
+ struct tda8290_config *cfg)
+{
+ struct tda8290_priv *priv = NULL;
u8 data;
int i, ret, tuners_found;
u32 tuner_addrs;
struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
- tda8290_i2c_bridge(c, 1);
+ priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
+ if (cfg) {
+ priv->lna_cfg = cfg->lna_cfg;
+ priv->tuner_callback = cfg->tuner_callback;
+ }
+
+ tda8290_i2c_bridge(fe, 1);
/* probe for tuner chip */
tuners_found = 0;
tuner_addrs = 0;
for (i=0x60; i<= 0x63; i++) {
msg.addr = i;
- ret = i2c_transfer(c->adapter, &msg, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if (ret == 1) {
tuners_found++;
tuner_addrs = (tuner_addrs << 8) + i;
@@ -600,11 +706,11 @@ int tda8290_init(struct i2c_client *c)
behind the bridge and we choose the highest address that doesn't
give a response now
*/
- tda8290_i2c_bridge(c, 0);
+ tda8290_i2c_bridge(fe, 0);
if(tuners_found > 1)
for (i = 0; i < tuners_found; i++) {
msg.addr = tuner_addrs & 0xff;
- ret = i2c_transfer(c->adapter, &msg, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if(ret == 1)
tuner_addrs = tuner_addrs >> 8;
else
@@ -612,42 +718,53 @@ int tda8290_init(struct i2c_client *c)
}
if (tuner_addrs == 0) {
tuner_addrs = 0x61;
- tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+ tuner_info("could not clearly identify tuner address, defaulting to %x\n",
tuner_addrs);
} else {
tuner_addrs = tuner_addrs & 0xff;
- tuner_info ("setting tuner address to %x\n", tuner_addrs);
+ tuner_info("setting tuner address to %x\n", tuner_addrs);
}
- t->tda827x_addr = tuner_addrs;
+ priv->tda827x_addr = tuner_addrs;
msg.addr = tuner_addrs;
- tda8290_i2c_bridge(c, 1);
- ret = i2c_transfer(c->adapter, &msg, 1);
+ tda8290_i2c_bridge(fe, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if( ret != 1)
- tuner_warn ("TDA827x access failed!\n");
+ tuner_warn("TDA827x access failed!\n");
+
+ memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
if ((data & 0x3c) == 0) {
- strlcpy(c->name, "tda8290+75", sizeof(c->name));
- t->tda827x_ver = 0;
+ strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
+ sizeof(fe->ops.tuner_ops.info.name));
+ fe->ops.tuner_ops.info.frequency_min = 55000000;
+ fe->ops.tuner_ops.info.frequency_max = 860000000;
+ fe->ops.tuner_ops.info.frequency_step = 250000;
+ priv->tda827x_ver = 0;
} else {
- strlcpy(c->name, "tda8290+75a", sizeof(c->name));
- t->tda827x_ver = 2;
+ strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
+ sizeof(fe->ops.tuner_ops.info.name));
+ fe->ops.tuner_ops.info.frequency_min = 44000000;
+ fe->ops.tuner_ops.info.frequency_max = 906000000;
+ fe->ops.tuner_ops.info.frequency_step = 62500;
+ priv->tda827x_ver = 2;
}
- tuner_info("type set to %s\n", c->name);
- t->set_tv_freq = set_tv_freq;
- t->set_radio_freq = set_radio_freq;
- t->has_signal = has_signal;
- t->standby = standby;
- t->tda827x_lpsel = 0;
- t->mode = V4L2_TUNER_ANALOG_TV;
+ priv->tda827x_lpsel = 0;
- tda8290_init_tuner(c);
- tda8290_init_if(c);
- return 0;
+ tda8290_init_tuner(fe);
+ tda8290_init_if(fe);
+ return fe;
}
-int tda8290_probe(struct i2c_client *c)
+int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
{
+ struct tuner_i2c_props i2c_props = {
+ .adap = i2c_adap,
+ .addr = i2c_addr
+ };
+
unsigned char soft_reset[] = { 0x00, 0x00 };
unsigned char easy_mode_b[] = { 0x01, 0x02 };
unsigned char easy_mode_g[] = { 0x01, 0x04 };
@@ -655,23 +772,30 @@ int tda8290_probe(struct i2c_client *c)
unsigned char addr_dto_lsb = 0x07;
unsigned char data;
- i2c_master_send(c, easy_mode_b, 2);
- i2c_master_send(c, soft_reset, 2);
- i2c_master_send(c, &addr_dto_lsb, 1);
- i2c_master_recv(c, &data, 1);
+ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
+ tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+ tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+ tuner_i2c_xfer_recv(&i2c_props, &data, 1);
if (data == 0) {
- i2c_master_send(c, easy_mode_g, 2);
- i2c_master_send(c, soft_reset, 2);
- i2c_master_send(c, &addr_dto_lsb, 1);
- i2c_master_recv(c, &data, 1);
+ tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
+ tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+ tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+ tuner_i2c_xfer_recv(&i2c_props, &data, 1);
if (data == 0x7b) {
return 0;
}
}
- i2c_master_send(c, restore_9886, 3);
+ tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
return -1;
}
+EXPORT_SYMBOL_GPL(tda8290_probe);
+EXPORT_SYMBOL_GPL(tda8290_attach);
+
+MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
+MODULE_LICENSE("GPL");
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
new file mode 100644
index 000000000000..107b24b05aa1
--- /dev/null
+++ b/drivers/media/video/tda8290.h
@@ -0,0 +1,54 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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 __TDA8290_H__
+#define __TDA8290_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda8290_config
+{
+ unsigned int *lna_cfg;
+ int (*tuner_callback) (void *dev, int command,int arg);
+};
+
+#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
+extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr,
+ struct tda8290_config *cfg);
+#else
+static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __FUNCTION__);
+ return -EINVAL;
+}
+
+static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr,
+ struct tda8290_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TDA8290_H__ */
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index fde576f1101c..be5387f11afb 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -1,16 +1,15 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/types.h>
-#include <linux/videodev.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
-
+#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
+#include "tuner-driver.h"
/* Chips:
@@ -29,6 +28,11 @@
printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+struct tda9887_priv {
+ struct tuner_i2c_props i2c_props;
+
+ unsigned char data[4];
+};
/* ---------------------------------------------------------------------- */
@@ -93,6 +97,8 @@ struct tvnorm {
#define cAudioIF_6_5 0x03 // bit e0:1
+#define cVideoIFMask 0x1c // bit e2:4
+/* Video IF selection in TV Mode (bit B3=0) */
#define cVideoIF_58_75 0x00 // bit e2:4
#define cVideoIF_45_75 0x04 // bit e2:4
#define cVideoIF_38_90 0x08 // bit e2:4
@@ -102,6 +108,13 @@ struct tvnorm {
#define cRadioIF_45_75 0x18 // bit e2:4
#define cRadioIF_38_90 0x1C // bit e2:4
+/* IF1 selection in Radio Mode (bit B3=1) */
+#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
+#define cRadioIF_41_30 0x04 // bit e2,4
+
+/* Output of AFC pin in radio mode when bit E7=1 */
+#define cRadioAGC_SIF 0x00 // bit e3
+#define cRadioAGC_FM 0x08 // bit e3
#define cTunerGainNormal 0x00 // bit e5
#define cTunerGainLow 0x20 // bit e5
@@ -483,9 +496,13 @@ static int tda9887_set_config(struct tuner *t, char *buf)
if (t->tda9887_config & TDA9887_GATING_18)
buf[3] &= ~cGating_36;
- if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
- radio_stereo.e &= ~cTunerGainLow;
- radio_mono.e &= ~cTunerGainLow;
+ if (t->mode == V4L2_TUNER_RADIO) {
+ if (t->tda9887_config & TDA9887_RIF_41_3) {
+ buf[3] &= ~cVideoIFMask;
+ buf[3] |= cRadioIF_41_30;
+ }
+ if (t->tda9887_config & TDA9887_GAIN_NORMAL)
+ buf[3] &= ~cTunerGainLow;
}
return 0;
@@ -495,23 +512,24 @@ static int tda9887_set_config(struct tuner *t, char *buf)
static int tda9887_status(struct tuner *t)
{
+ struct tda9887_priv *priv = t->priv;
unsigned char buf[1];
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
+ if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
dump_read_message(t, buf);
return 0;
}
-static void tda9887_configure(struct i2c_client *client)
+static void tda9887_configure(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
+ struct tda9887_priv *priv = t->priv;
int rc;
- memset(t->tda9887_data,0,sizeof(t->tda9887_data));
- tda9887_set_tvnorm(t,t->tda9887_data);
+ memset(priv->data,0,sizeof(priv->data));
+ tda9887_set_tvnorm(t,priv->data);
/* A note on the port settings:
These settings tend to depend on the specifics of the board.
@@ -526,22 +544,22 @@ static void tda9887_configure(struct i2c_client *client)
the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration.
*/
- t->tda9887_data[1] |= cOutputPort1Inactive;
- t->tda9887_data[1] |= cOutputPort2Inactive;
+ priv->data[1] |= cOutputPort1Inactive;
+ priv->data[1] |= cOutputPort2Inactive;
- tda9887_set_config(t,t->tda9887_data);
- tda9887_set_insmod(t,t->tda9887_data);
+ tda9887_set_config(t,priv->data);
+ tda9887_set_insmod(t,priv->data);
if (t->mode == T_STANDBY) {
- t->tda9887_data[1] |= cForcedMuteAudioON;
+ priv->data[1] |= cForcedMuteAudioON;
}
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
- t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+ priv->data[1],priv->data[2],priv->data[3]);
if (tuner_debug > 1)
- dump_write_message(t, t->tda9887_data);
+ dump_write_message(t, priv->data);
- if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (tuner_debug > 2) {
@@ -552,15 +570,15 @@ static void tda9887_configure(struct i2c_client *client)
/* ---------------------------------------------------------------------- */
-static void tda9887_tuner_status(struct i2c_client *client)
+static void tda9887_tuner_status(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
- tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+ struct tda9887_priv *priv = t->priv;
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
}
-static int tda9887_get_afc(struct i2c_client *client)
+static int tda9887_get_afc(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
+ struct tda9887_priv *priv = t->priv;
static int AFC_BITS_2_kHz[] = {
-12500, -37500, -62500, -97500,
-112500, -137500, -162500, -187500,
@@ -570,36 +588,55 @@ static int tda9887_get_afc(struct i2c_client *client)
int afc=0;
__u8 reg = 0;
- if (1 == i2c_master_recv(&t->i2c,&reg,1))
+ if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
return afc;
}
-static void tda9887_standby(struct i2c_client *client)
+static void tda9887_standby(struct tuner *t)
{
- tda9887_configure(client);
+ tda9887_configure(t);
}
-static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
+static void tda9887_set_freq(struct tuner *t, unsigned int freq)
{
- tda9887_configure(client);
+ tda9887_configure(t);
}
-int tda9887_tuner_init(struct i2c_client *c)
+static void tda9887_release(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(c);
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
+static struct tuner_operations tda9887_tuner_ops = {
+ .set_tv_freq = tda9887_set_freq,
+ .set_radio_freq = tda9887_set_freq,
+ .standby = tda9887_standby,
+ .tuner_status = tda9887_tuner_status,
+ .get_afc = tda9887_get_afc,
+ .release = tda9887_release,
+};
+
+int tda9887_tuner_init(struct tuner *t)
+{
+ struct tda9887_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
+ priv->i2c_props.addr = t->i2c.addr;
+ priv->i2c_props.adap = t->i2c.adapter;
- strlcpy(c->name, "tda9887", sizeof(c->name));
+ strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
t->i2c.driver->driver.name);
- t->set_tv_freq = tda9887_set_freq;
- t->set_radio_freq = tda9887_set_freq;
- t->standby = tda9887_standby;
- t->tuner_status = tda9887_tuner_status;
- t->get_afc = tda9887_get_afc;
+ memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
return 0;
}
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
new file mode 100644
index 000000000000..2150222a3860
--- /dev/null
+++ b/drivers/media/video/tea5761.c
@@ -0,0 +1,320 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev.h>
+#include <media/tuner.h>
+#include "tuner-i2c.h"
+#include "tea5761.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tea5761 "
+
+struct tea5761_priv {
+ struct tuner_i2c_props i2c_props;
+
+ u32 frequency;
+};
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+ /* first byte for reading */
+#define TEA5761_INTREG_IFFLAG 0x10
+#define TEA5761_INTREG_LEVFLAG 0x8
+#define TEA5761_INTREG_FRRFLAG 0x2
+#define TEA5761_INTREG_BLFLAG 0x1
+
+ /* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK 0x10
+#define TEA5761_INTREG_LEVMSK 0x8
+#define TEA5761_INTREG_FRMSK 0x2
+#define TEA5761_INTREG_BLMSK 0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+ /* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */
+
+ /* Bits 0-5 for divider MSB */
+
+ /* Second byte */
+ /* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+ /* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM 0x04
+#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC 0x01
+
+ /* second byte */
+
+#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1 0x40
+#define TEA5761_TNCTRL_SSL_0 0x20
+#define TEA5761_TNCTRL_HLSI 0x10
+#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */
+#define TEA5761_TNCTRL_SWP 0x04
+#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI 0x01
+
+/* FRQCHECK - Read: bytes 6 and 7 */
+ /* First byte */
+
+ /* Bits 0-5 for divider MSB */
+
+ /* Second byte */
+ /* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9 */
+
+ /* First byte */
+#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */
+#define TEA5761_TUNCHECK_TUNTO 0x01
+
+ /* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */
+#define TEA5761_TUNCHECK_LD 0x08
+#define TEA5761_TUNCHECK_STEREO 0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+ /* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+ /* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */
+
+ /* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+ /* First byte - should be 0x57 */
+
+ /* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+ unsigned int div, frq;
+
+ div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+ frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */
+
+ printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+ frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static int set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+ unsigned int frq = params->frequency;
+ unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+ unsigned div;
+ int rc;
+
+ tuner_dbg("radio freq counter %d\n", frq);
+
+ if (params->mode == T_STANDBY) {
+ tuner_dbg("TEA5761 set to standby mode\n");
+ buffer[5] |= TEA5761_TNCTRL_MU;
+ } else {
+ buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+ }
+
+
+ if (params->audmode == V4L2_TUNER_MODE_MONO) {
+ tuner_dbg("TEA5761 set to mono\n");
+ buffer[5] |= TEA5761_TNCTRL_MST;
+ } else {
+ tuner_dbg("TEA5761 set to stereo\n");
+ }
+
+ div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+ buffer[1] = (div >> 8) & 0x3f;
+ buffer[2] = div & 0xff;
+
+ if (debug)
+ tea5761_status_dump(buffer);
+
+ if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ priv->frequency = frq * 125 / 2;
+
+ return 0;
+}
+
+static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+ int rc;
+
+ memset(buffer, 0, 16);
+ if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) {
+ tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+
+ int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+
+ tuner_dbg("Signal strength: %d\n", signal);
+
+ return signal;
+}
+
+static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+
+ int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+ tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+ return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+static int tea5761_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ unsigned char buffer[16];
+
+ *status = 0;
+
+ if (0 == tea5761_read_status(fe, buffer)) {
+ if (tea5761_signal(fe, buffer))
+ *status = TUNER_STATUS_LOCKED;
+ if (tea5761_stereo(fe, buffer))
+ *status |= TUNER_STATUS_STEREO;
+ }
+
+ return 0;
+}
+
+static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ unsigned char buffer[16];
+
+ *strength = 0;
+
+ if (0 == tea5761_read_status(fe, buffer))
+ *strength = tea5761_signal(fe, buffer);
+
+ return 0;
+}
+
+int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
+
+ if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
+ printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
+ return EINVAL;
+ }
+
+ if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
+ printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+ return EINVAL;
+ }
+ printk(KERN_WARNING "TEA5761 detected.\n");
+ return 0;
+}
+
+static int tea5761_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tea5761_tuner_ops = {
+ .info = {
+ .name = "tea5761", // Philips TEA5761HN FM Radio
+ },
+ .set_analog_params = set_radio_freq,
+ .release = tea5761_release,
+ .get_frequency = tea5761_get_frequency,
+ .get_status = tea5761_get_status,
+ .get_rf_strength = tea5761_get_rf_strength,
+};
+
+struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ struct tea5761_priv *priv = NULL;
+
+ if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL)
+ return NULL;
+
+ priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
+
+ memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio");
+
+ return fe;
+}
+
+
+EXPORT_SYMBOL_GPL(tea5761_attach);
+EXPORT_SYMBOL_GPL(tea5761_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h
new file mode 100644
index 000000000000..73a03b427843
--- /dev/null
+++ b/drivers/media/video/tea5761.h
@@ -0,0 +1,47 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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 __TEA5761_H__
+#define __TEA5761_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_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,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr);
+#else
+static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __FUNCTION__);
+ return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TEA5761_H__ */
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index d1c41781ccc4..71df419df7bc 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -11,14 +11,22 @@
*/
#include <linux/i2c.h>
-#include <linux/videodev.h>
#include <linux/delay.h>
-#include <media/tuner.h>
+#include <linux/videodev.h>
+#include "tuner-i2c.h"
+#include "tea5767.h"
-#define PREFIX "TEA5767 "
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
-/* from tuner-core.c */
-extern int tuner_debug;
+#define PREFIX "tea5767 "
+
+struct tea5767_priv {
+ struct tuner_i2c_props i2c_props;
+
+ u32 frequency;
+};
/*****************************************************************************/
@@ -129,13 +137,6 @@ enum tea5767_xtal_freq {
/*****************************************************************************/
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
- struct tuner *t = i2c_get_clientdata(c);
-
- tuner_warn("This tuner doesn't support TV freq.\n");
-}
-
static void tea5767_status_dump(unsigned char *buffer)
{
unsigned int div, frq;
@@ -190,14 +191,16 @@ static void tea5767_status_dump(unsigned char *buffer)
}
/* Freq should be specifyed at 62.5 Hz */
-static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+static int set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5767_priv *priv = fe->tuner_priv;
+ unsigned int frq = params->frequency;
unsigned char buffer[5];
unsigned div;
int rc;
- tuner_dbg (PREFIX "radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
+ tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
/* Rounds freq to next decimal value - for 62.5 KHz step */
/* frq = 20*(frq/16)+radio_frq[frq%16]; */
@@ -207,7 +210,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
buffer[4] = 0;
- if (t->audmode == V4L2_TUNER_MODE_MONO) {
+ if (params->audmode == V4L2_TUNER_MODE_MONO) {
tuner_dbg("TEA5767 set to mono\n");
buffer[2] |= TEA5767_MONO;
} else {
@@ -217,26 +220,26 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
/* Should be replaced */
switch (TEA5767_HIGH_LO_32768) {
case TEA5767_HIGH_LO_13MHz:
- tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
+ tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
buffer[2] |= TEA5767_HIGH_LO_INJECT;
buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
break;
case TEA5767_LOW_LO_13MHz:
- tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
+ tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
break;
case TEA5767_LOW_LO_32768:
- tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
+ tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n");
buffer[3] |= TEA5767_XTAL_32768;
/* const 700=4000*175 Khz - to adjust freq to right value */
div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
break;
case TEA5767_HIGH_LO_32768:
default:
- tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n");
+ tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n");
buffer[2] |= TEA5767_HIGH_LO_INJECT;
buffer[3] |= TEA5767_XTAL_32768;
@@ -246,51 +249,89 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
buffer[0] = (div >> 8) & 0x3f;
buffer[1] = div & 0xff;
- if (5 != (rc = i2c_master_send(c, buffer, 5)))
+ if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- if (tuner_debug) {
- if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+ if (debug) {
+ if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
else
tea5767_status_dump(buffer);
}
+
+ priv->frequency = frq * 125 / 2;
+
+ return 0;
}
-static int tea5767_signal(struct i2c_client *c)
+static int tea5767_read_status(struct dvb_frontend *fe, char *buffer)
{
- unsigned char buffer[5];
+ struct tea5767_priv *priv = fe->tuner_priv;
int rc;
- struct tuner *t = i2c_get_clientdata(c);
- memset(buffer, 0, sizeof(buffer));
- if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+ memset(buffer, 0, 5);
+ if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) {
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ return -EREMOTEIO;
+ }
- return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
+ return 0;
+}
+
+static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5767_priv *priv = fe->tuner_priv;
+
+ int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
+
+ tuner_dbg("Signal strength: %d\n", signal);
+
+ return signal;
}
-static int tea5767_stereo(struct i2c_client *c)
+static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5767_priv *priv = fe->tuner_priv;
+
+ int stereo = buffer[2] & TEA5767_STEREO_MASK;
+
+ tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+ return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+static int tea5767_get_status(struct dvb_frontend *fe, u32 *status)
{
unsigned char buffer[5];
- int rc;
- struct tuner *t = i2c_get_clientdata(c);
- memset(buffer, 0, sizeof(buffer));
- if (5 != (rc = i2c_master_recv(c, buffer, 5)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ *status = 0;
+
+ if (0 == tea5767_read_status(fe, buffer)) {
+ if (tea5767_signal(fe, buffer))
+ *status = TUNER_STATUS_LOCKED;
+ if (tea5767_stereo(fe, buffer))
+ *status |= TUNER_STATUS_STEREO;
+ }
+
+ return 0;
+}
+
+static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ unsigned char buffer[5];
- rc = buffer[2] & TEA5767_STEREO_MASK;
+ *strength = 0;
- tuner_dbg("TEA5767 radio ST GET = %02x\n", rc);
+ if (0 == tea5767_read_status(fe, buffer))
+ *strength = tea5767_signal(fe, buffer);
- return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0);
+ return 0;
}
-static void tea5767_standby(struct i2c_client *c)
+static int tea5767_standby(struct dvb_frontend *fe)
{
unsigned char buffer[5];
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5767_priv *priv = fe->tuner_priv;
unsigned div, rc;
div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */
@@ -301,25 +342,27 @@ static void tea5767_standby(struct i2c_client *c)
TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY;
buffer[4] = 0;
- if (5 != (rc = i2c_master_send(c, buffer, 5)))
+ if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ return 0;
}
-int tea5767_autodetection(struct i2c_client *c)
+int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
{
+ struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int rc;
- struct tuner *t = i2c_get_clientdata(c);
- if ((rc = i2c_master_recv(c, buffer, 7))< 5) {
- tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc);
+ 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;
}
/* 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]) {
- tuner_warn("All bytes are equal. It is not a TEA5767\n");
+ printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
return EINVAL;
}
@@ -329,32 +372,74 @@ int tea5767_autodetection(struct i2c_client *c)
* Byte 5: bit 7:0 : == 0
*/
if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
- tuner_warn("Chip ID is not zero. It is not a TEA5767\n");
+ printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
return EINVAL;
}
/* It seems that tea5767 returns 0xff after the 5th byte */
if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) {
- tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n");
+ printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n");
return EINVAL;
}
- tuner_warn("TEA5767 detected.\n");
+ printk(KERN_WARNING "TEA5767 detected.\n");
+ return 0;
+}
+
+static int tea5767_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tea5767_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
return 0;
}
-int tea5767_tuner_init(struct i2c_client *c)
+static struct dvb_tuner_ops tea5767_tuner_ops = {
+ .info = {
+ .name = "tea5767", // Philips TEA5767HN FM Radio
+ },
+
+ .set_analog_params = set_radio_freq,
+ .sleep = tea5767_standby,
+ .release = tea5767_release,
+ .get_frequency = tea5767_get_frequency,
+ .get_status = tea5767_get_status,
+ .get_rf_strength = tea5767_get_rf_strength,
+};
+
+struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5767_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
- tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
- strlcpy(c->name, "tea5767", sizeof(c->name));
+ memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
- t->set_tv_freq = set_tv_freq;
- t->set_radio_freq = set_radio_freq;
- t->has_signal = tea5767_signal;
- t->is_stereo = tea5767_stereo;
- t->standby = tea5767_standby;
+ tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio");
- return (0);
+ return fe;
}
+
+
+EXPORT_SYMBOL_GPL(tea5767_attach);
+EXPORT_SYMBOL_GPL(tea5767_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
new file mode 100644
index 000000000000..5d78281adcc2
--- /dev/null
+++ b/drivers/media/video/tea5767.h
@@ -0,0 +1,47 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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 __TEA5767_H__
+#define __TEA5767_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_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,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr);
+#else
+static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __FUNCTION__);
+ return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TEA5767_H__ */
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 505591a7abe9..94843086cda9 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -5,7 +5,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
@@ -15,16 +14,25 @@
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/types.h>
-#include <linux/videodev.h>
#include <linux/init.h>
-
+#include <linux/videodev.h>
#include <media/tuner.h>
+#include <media/tuner-types.h>
#include <media/v4l2-common.h>
+#include "tuner-driver.h"
+#include "mt20xx.h"
+#include "tda8290.h"
+#include "tea5761.h"
+#include "tea5767.h"
+#include "tuner-simple.h"
#define UNSET (-1U)
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
+#ifdef CONFIG_TUNER_TEA5761
+ 0x10,
+#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@@ -68,6 +76,51 @@ static struct i2c_client client_template;
/* ---------------------------------------------------------------------- */
+static void fe_set_freq(struct tuner *t, unsigned int freq)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ struct analog_parameters params = {
+ .frequency = freq,
+ .mode = t->mode,
+ .audmode = t->audmode,
+ .std = t->std
+ };
+
+ if (NULL == fe_tuner_ops->set_analog_params) {
+ tuner_warn("Tuner frontend module has no way to set freq\n");
+ return;
+ }
+ fe_tuner_ops->set_analog_params(&t->fe, &params);
+}
+
+static void fe_release(struct tuner *t)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ if (fe_tuner_ops->release)
+ fe_tuner_ops->release(&t->fe);
+}
+
+static void fe_standby(struct tuner *t)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ if (fe_tuner_ops->sleep)
+ fe_tuner_ops->sleep(&t->fe);
+}
+
+static int fe_has_signal(struct tuner *t)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+ u16 strength;
+
+ if (fe_tuner_ops->get_rf_strength)
+ fe_tuner_ops->get_rf_strength(&t->fe, &strength);
+
+ return strength;
+}
+
/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
@@ -77,7 +130,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n");
return;
}
- if (NULL == t->set_tv_freq) {
+ if (NULL == t->ops.set_tv_freq) {
tuner_warn ("Tuner has no way to set tv freq\n");
return;
}
@@ -92,7 +145,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
else
freq = tv_range[1] * 16;
}
- t->set_tv_freq(c, freq);
+ t->ops.set_tv_freq(t, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -103,7 +156,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n");
return;
}
- if (NULL == t->set_radio_freq) {
+ if (NULL == t->ops.set_radio_freq) {
tuner_warn ("tuner has no way to set radio frequency\n");
return;
}
@@ -119,7 +172,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
freq = radio_range[1] * 16000;
}
- t->set_radio_freq(c, freq);
+ t->ops.set_radio_freq(t, freq);
}
static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -143,11 +196,51 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
}
}
+static void tuner_i2c_address_check(struct tuner *t)
+{
+ if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
+ ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
+ return;
+
+ tuner_warn("====================== WARNING! ======================\n");
+ tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
+ tuner_warn("will soon be dropped. This message indicates that your\n");
+ tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
+ t->i2c.name, t->i2c.addr);
+ tuner_warn("To ensure continued support for your device, please\n");
+ tuner_warn("send a copy of this message, along with full dmesg\n");
+ tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
+ tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
+ tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
+ t->i2c.adapter->name, t->i2c.addr, t->type,
+ tuners[t->type].name);
+ tuner_warn("====================== WARNING! ======================\n");
+}
+
+static void attach_tda8290(struct tuner *t)
+{
+ struct tda8290_config cfg = {
+ .lna_cfg = &t->config,
+ .tuner_callback = t->tuner_callback
+ };
+ tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+}
+
+static void attach_simple_tuner(struct tuner *t)
+{
+ struct simple_tuner_config cfg = {
+ .type = t->type,
+ .tun = &tuners[t->type]
+ };
+ simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+}
+
static void set_type(struct i2c_client *c, unsigned int type,
unsigned int new_mode_mask, unsigned int new_config,
int (*tuner_callback) (void *dev, int command,int arg))
{
struct tuner *t = i2c_get_clientdata(c);
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
unsigned char buffer[4];
if (type == UNSET || type == TUNER_ABSENT) {
@@ -174,21 +267,41 @@ static void set_type(struct i2c_client *c, unsigned int type,
return;
}
+ /* discard private data, in case set_type() was previously called */
+ if (t->ops.release)
+ t->ops.release(t);
+ else {
+ kfree(t->priv);
+ t->priv = NULL;
+ }
+
switch (t->type) {
case TUNER_MT2032:
- microtune_init(c);
+ microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
break;
case TUNER_PHILIPS_TDA8290:
- tda8290_init(c);
+ {
+ attach_tda8290(t);
break;
+ }
case TUNER_TEA5767:
- if (tea5767_tuner_init(c) == EINVAL) {
+ if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
t->mode_mask = T_RADIO;
break;
+#ifdef CONFIG_TUNER_TEA5761
+ case TUNER_TEA5761:
+ if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
+ t->mode_mask = T_RADIO;
+ break;
+#endif
case TUNER_PHILIPS_FMD1216ME_MK3:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
@@ -199,7 +312,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- default_tuner_init(c);
+ attach_simple_tuner(t);
break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
@@ -207,16 +320,28 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0xa4;
i2c_master_send(c,buffer,4);
- default_tuner_init(c);
+ attach_simple_tuner(t);
break;
case TUNER_TDA9887:
- tda9887_tuner_init(c);
+ tda9887_tuner_init(t);
break;
default:
- default_tuner_init(c);
+ attach_simple_tuner(t);
break;
}
+ if (fe_tuner_ops->set_analog_params) {
+ strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
+
+ t->ops.set_tv_freq = fe_set_freq;
+ t->ops.set_radio_freq = fe_set_freq;
+ t->ops.standby = fe_standby;
+ t->ops.release = fe_release;
+ t->ops.has_signal = fe_has_signal;
+ }
+
+ tuner_info("type set to %s\n", t->i2c.name);
+
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
@@ -224,6 +349,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask);
+ tuner_i2c_address_check(t);
}
/*
@@ -384,10 +510,10 @@ static int tuner_fixup_std(struct tuner *t)
return 0;
}
-static void tuner_status(struct i2c_client *client)
+static void tuner_status(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
unsigned long freq, freq_fraction;
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
const char *p;
switch (t->mode) {
@@ -408,11 +534,20 @@ static void tuner_status(struct i2c_client *client)
tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
if (t->mode != V4L2_TUNER_RADIO)
return;
- if (t->has_signal) {
- tuner_info("Signal strength: %d\n", t->has_signal(client));
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ if (tuner_status & TUNER_STATUS_LOCKED)
+ tuner_info("Tuner is locked.\n");
+ if (tuner_status & TUNER_STATUS_STEREO)
+ tuner_info("Stereo: yes\n");
+ }
+ if (t->ops.has_signal) {
+ tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
}
- if (t->is_stereo) {
- tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
+ if (t->ops.is_stereo) {
+ tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no");
}
}
@@ -437,10 +572,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
i2c_set_clientdata(&t->i2c, t);
t->type = UNSET;
- t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
- t->tuner_status = tuner_status;
+ t->ops.tuner_status = tuner_status;
if (show_i2c) {
unsigned char buffer[16];
@@ -460,13 +594,26 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
/* autodetection code based on the i2c addr */
if (!no_autodetect) {
switch (addr) {
+#ifdef CONFIG_TUNER_TEA5761
+ case 0x10:
+ if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
+ t->type = TUNER_TEA5761;
+ t->mode_mask = T_RADIO;
+ t->mode = T_STANDBY;
+ t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+ default_mode_mask &= ~T_RADIO;
+
+ goto register_client;
+ }
+ break;
+#endif
case 0x42:
case 0x43:
case 0x4a:
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda8290_probe(&t->i2c) == 0) {
+ if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
tuner_dbg("chip at addr %x is a tda8290\n", addr);
} else {
/* Default is being tda9887 */
@@ -477,7 +624,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
}
break;
case 0x60:
- if (tea5767_autodetection(&t->i2c) != EINVAL) {
+ if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -514,6 +661,28 @@ static int tuner_probe(struct i2c_adapter *adap)
normal_i2c[1] = I2C_CLIENT_END;
}
+ /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
+ * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+ * and an RTC at 0x6f which can get corrupted if probed.
+ */
+ if ((adap->id == I2C_HW_B_CX2388x) ||
+ (adap->id == I2C_HW_B_CX23885)) {
+ unsigned int i = 0;
+
+ while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
+ i += 2;
+ if (i + 4 < I2C_CLIENT_MAX_OPTS) {
+ ignore[i+0] = adap->nr;
+ ignore[i+1] = 0x6b;
+ ignore[i+2] = adap->nr;
+ ignore[i+3] = 0x6f;
+ ignore[i+4] = I2C_CLIENT_END;
+ } else
+ printk(KERN_WARNING "tuner: "
+ "too many options specified "
+ "in i2c probe ignore list!\n");
+ }
+
default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
if (adap->class & I2C_CLASS_TV_ANALOG)
@@ -533,6 +702,11 @@ static int tuner_detach(struct i2c_client *client)
return err;
}
+ if (t->ops.release)
+ t->ops.release(t);
+ else {
+ kfree(t->priv);
+ }
kfree(t);
return 0;
}
@@ -553,8 +727,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
if (check_mode(t, cmd) == EINVAL) {
t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
+ if (t->ops.standby)
+ t->ops.standby(t);
return EINVAL;
}
return 0;
@@ -576,6 +750,7 @@ static inline int check_v4l2(struct tuner *t)
static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct tuner *t = i2c_get_clientdata(client);
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
if (tuner_debug>1)
v4l_i2c_print_ioctl(&(t->i2c),cmd);
@@ -602,8 +777,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
+ if (t->ops.standby)
+ t->ops.standby(t);
break;
#ifdef CONFIG_VIDEO_V4L1
case VIDIOCSAUDIO:
@@ -662,16 +837,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
- if (t->has_signal)
- vt->signal = t->has_signal(client);
- if (t->is_stereo) {
- if (t->is_stereo(client))
- vt->flags |=
- VIDEO_TUNER_STEREO_ON;
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ if (tuner_status & TUNER_STATUS_STEREO)
+ vt->flags |= VIDEO_TUNER_STEREO_ON;
else
- vt->flags &=
- ~VIDEO_TUNER_STEREO_ON;
+ vt->flags &= ~VIDEO_TUNER_STEREO_ON;
+ } else {
+ if (t->ops.is_stereo) {
+ if (t->ops.is_stereo(t))
+ vt->flags |=
+ VIDEO_TUNER_STEREO_ON;
+ else
+ vt->flags &=
+ ~VIDEO_TUNER_STEREO_ON;
+ }
}
+ if (t->ops.has_signal)
+ vt->signal = t->ops.has_signal(t);
+
vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
vt->rangelow = radio_range[0] * 16000;
@@ -693,9 +879,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (check_v4l2(t) == EINVAL)
return 0;
- if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
- va->mode = t->is_stereo(client)
- ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ if (V4L2_TUNER_RADIO == t->mode) {
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ va->mode = (tuner_status & TUNER_STATUS_STEREO)
+ ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ } else if (t->ops.is_stereo)
+ va->mode = t->ops.is_stereo(t)
+ ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ }
return 0;
}
#endif
@@ -746,6 +940,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
switch_v4l2();
f->type = t->mode;
+ if (fe_tuner_ops->get_frequency) {
+ u32 abs_freq;
+
+ fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
+ f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+ (abs_freq * 2 + 125/2) / 125 :
+ (abs_freq + 62500/2) / 62500;
+ break;
+ }
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq;
break;
@@ -759,8 +962,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
tuner->type = t->mode;
- if (t->get_afc)
- tuner->afc=t->get_afc(client);
+ if (t->ops.get_afc)
+ tuner->afc=t->ops.get_afc(t);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
@@ -770,16 +973,22 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
/* radio mode */
- if (t->has_signal)
- tuner->signal = t->has_signal(client);
-
tuner->rxsubchans =
V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (t->is_stereo) {
- tuner->rxsubchans = t->is_stereo(client) ?
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ } else {
+ if (t->ops.is_stereo) {
+ tuner->rxsubchans = t->ops.is_stereo(t) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ }
}
-
+ if (t->ops.has_signal)
+ tuner->signal = t->ops.has_signal(t);
tuner->capability |=
V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
tuner->audmode = t->audmode;
@@ -804,8 +1013,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
case VIDIOC_LOG_STATUS:
- if (t->tuner_status)
- t->tuner_status(client);
+ if (t->ops.tuner_status)
+ t->ops.tuner_status(t);
break;
}
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
new file mode 100644
index 000000000000..28a10da76d12
--- /dev/null
+++ b/drivers/media/video/tuner-driver.h
@@ -0,0 +1,99 @@
+/*
+ tuner-driver.h - interface for different tuners
+
+ Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+ minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU 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 __TUNER_DRIVER_H__
+#define __TUNER_DRIVER_H__
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include "tuner-i2c.h"
+#include "dvb_frontend.h"
+
+extern unsigned const int tuner_count;
+
+struct tuner;
+
+struct tuner_operations {
+ void (*set_tv_freq)(struct tuner *t, unsigned int freq);
+ void (*set_radio_freq)(struct tuner *t, unsigned int freq);
+ int (*has_signal)(struct tuner *t);
+ int (*is_stereo)(struct tuner *t);
+ int (*get_afc)(struct tuner *t);
+ void (*tuner_status)(struct tuner *t);
+ void (*standby)(struct tuner *t);
+ void (*release)(struct tuner *t);
+};
+
+struct tuner {
+ /* device */
+ struct i2c_client i2c;
+
+ unsigned int type; /* chip type */
+
+ unsigned int mode;
+ unsigned int mode_mask; /* Combination of allowable modes */
+
+ unsigned int tv_freq; /* keep track of the current settings */
+ unsigned int radio_freq;
+ unsigned int audmode;
+ v4l2_std_id std;
+
+ int using_v4l2;
+ void *priv;
+
+ struct dvb_frontend fe;
+
+ /* used by tda9887 */
+ unsigned int tda9887_config;
+
+ unsigned int config;
+ int (*tuner_callback) (void *dev, int command,int arg);
+
+ struct tuner_operations ops;
+};
+
+/* ------------------------------------------------------------------------ */
+
+extern int tda9887_tuner_init(struct tuner *t);
+
+/* ------------------------------------------------------------------------ */
+
+#define tuner_warn(fmt, arg...) do {\
+ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+ extern int tuner_debug; \
+ if (tuner_debug) \
+ printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+
+#endif /* __TUNER_DRIVER_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
new file mode 100644
index 000000000000..159019ec3373
--- /dev/null
+++ b/drivers/media/video/tuner-i2c.h
@@ -0,0 +1,70 @@
+/*
+ tuner-i2c.h - i2c interface for different tuners
+
+ Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, 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 __TUNER_I2C_H__
+#define __TUNER_I2C_H__
+
+#include <linux/i2c.h>
+
+struct tuner_i2c_props {
+ u8 addr;
+ struct i2c_adapter *adap;
+};
+
+static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
+{
+ struct i2c_msg msg = { .addr = props->addr, .flags = 0,
+ .buf = buf, .len = len };
+ int ret = i2c_transfer(props->adap, &msg, 1);
+
+ return (ret == 1) ? len : ret;
+}
+
+static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len)
+{
+ struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
+ .buf = buf, .len = len };
+ int ret = i2c_transfer(props->adap, &msg, 1);
+
+ return (ret == 1) ? len : ret;
+}
+
+#ifndef __TUNER_DRIVER_H__
+#define tuner_warn(fmt, arg...) do {\
+ printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+ printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+ if ((debug)) \
+ printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#endif /* __TUNER_DRIVER_H__ */
+
+#endif /* __TUNER_I2C_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index c40b92ce1fad..7b93d3b1f4c6 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -1,13 +1,23 @@
/*
- *
* i2c tv tuner chip device driver
* controls all those simple 4-control-bytes style tuners.
+ *
+ * This "tuner-simple" module was split apart from the original "tuner" module.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-i2c.h"
+#include "tuner-simple.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tuner-simple "
static int offset = 0;
module_param(offset, int, 0664);
@@ -54,9 +64,9 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
sound 2 33.16 - -
NICAM 33.05 33.05 39.80
*/
-#define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L 0x03 // France
-#define PHILIPS_MF_SET_PAL_L2 0x02 // L'
+#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */
/* Control byte */
@@ -80,59 +90,102 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
#define TUNER_PLL_LOCKED 0x40
#define TUNER_STEREO_MK3 0x04
+struct tuner_simple_priv {
+ u16 last_div;
+ struct tuner_i2c_props i2c_props;
+
+ unsigned int type;
+ struct tunertype *tun;
+
+ u32 frequency;
+};
+
/* ---------------------------------------------------------------------- */
-static int tuner_getstatus(struct i2c_client *c)
+static int tuner_read_status(struct dvb_frontend *fe)
{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
unsigned char byte;
- if (1 != i2c_master_recv(c,&byte,1))
+ if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1))
return 0;
return byte;
}
-static int tuner_signal(struct i2c_client *c)
+static inline int tuner_signal(const int status)
{
- return (tuner_getstatus(c) & TUNER_SIGNAL) << 13;
+ return (status & TUNER_SIGNAL) << 13;
}
-static int tuner_stereo(struct i2c_client *c)
+static inline int tuner_stereo(const int type, const int status)
{
- int stereo, status;
- struct tuner *t = i2c_get_clientdata(c);
-
- status = tuner_getstatus (c);
-
- switch (t->type) {
+ switch (type) {
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
case TUNER_LG_NTSC_TAPE:
- stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
- break;
+ return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
default:
- stereo = status & TUNER_STEREO;
+ return status & TUNER_STEREO;
}
+}
+
+static inline int tuner_islocked(const int status)
+{
+ return (status & TUNER_FL);
+}
+
+static inline int tuner_afcstatus(const int status)
+{
+ return (status & TUNER_AFC) - 2;
+}
+
+
+static int simple_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int tuner_status = tuner_read_status(fe);
+
+ *status = 0;
+
+ if (tuner_islocked(tuner_status))
+ *status = TUNER_STATUS_LOCKED;
+ if (tuner_stereo(priv->type, tuner_status))
+ *status |= TUNER_STATUS_STEREO;
- return stereo;
+ tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
+
+ return 0;
}
+static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int signal = tuner_signal(tuner_read_status(fe));
+
+ *strength = signal;
+
+ tuner_dbg("Signal strength: %d\n", signal);
+
+ return 0;
+}
/* ---------------------------------------------------------------------- */
-static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int simple_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_simple_priv *priv = fe->tuner_priv;
u8 config, cb, tuneraddr;
u16 div;
struct tunertype *tun;
u8 buffer[4];
int rc, IFPCoff, i, j;
enum param_type desired_type;
- struct tuner_params *params;
+ struct tuner_params *t_params;
- tun = &tuners[t->type];
+ tun = priv->tun;
/* IFPCoff = Video Intermediate Frequency - Vif:
940 =16*58.75 NTSC/J (Japan)
@@ -146,14 +199,14 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
171.2=16*10.70 FM Radio (at set_radio_freq)
*/
- if (t->std == V4L2_STD_NTSC_M_JP) {
+ if (params->std == V4L2_STD_NTSC_M_JP) {
IFPCoff = 940;
desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if ((t->std & V4L2_STD_MN) &&
- !(t->std & ~V4L2_STD_MN)) {
+ } else if ((params->std & V4L2_STD_MN) &&
+ !(params->std & ~V4L2_STD_MN)) {
IFPCoff = 732;
desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if (t->std == V4L2_STD_SECAM_LC) {
+ } else if (params->std == V4L2_STD_SECAM_LC) {
IFPCoff = 543;
desired_type = TUNER_PARAM_TYPE_SECAM;
} else {
@@ -166,67 +219,67 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
continue;
break;
}
- /* use default tuner_params if desired_type not available */
+ /* use default tuner_t_params if desired_type not available */
if (desired_type != tun->params[j].type) {
- tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n",
- IFPCoff,t->type);
+ tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n",
+ IFPCoff, priv->type);
j = 0;
}
- params = &tun->params[j];
+ t_params = &tun->params[j];
- for (i = 0; i < params->count; i++) {
- if (freq > params->ranges[i].limit)
+ for (i = 0; i < t_params->count; i++) {
+ if (params->frequency > t_params->ranges[i].limit)
continue;
break;
}
- if (i == params->count) {
+ if (i == t_params->count) {
tuner_dbg("TV frequency out of range (%d > %d)",
- freq, params->ranges[i - 1].limit);
- freq = params->ranges[--i].limit;
+ params->frequency, t_params->ranges[i - 1].limit);
+ params->frequency = t_params->ranges[--i].limit;
}
- config = params->ranges[i].config;
- cb = params->ranges[i].cb;
+ config = t_params->ranges[i].config;
+ cb = t_params->ranges[i].cb;
/* i == 0 -> VHF_LO
* i == 1 -> VHF_HI
* i == 2 -> UHF */
tuner_dbg("tv: param %d, range %d\n",j,i);
- div=freq + IFPCoff + offset;
+ div=params->frequency + IFPCoff + offset;
tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
- freq / 16, freq % 16 * 100 / 16,
+ params->frequency / 16, params->frequency % 16 * 100 / 16,
IFPCoff / 16, IFPCoff % 16 * 100 / 16,
offset / 16, offset % 16 * 100 / 16,
div);
/* tv norm specific stuff for multi-norm tuners */
- switch (t->type) {
+ switch (priv->type) {
case TUNER_PHILIPS_SECAM: // FI1216MF
/* 0x01 -> ??? no change ??? */
/* 0x02 -> PAL BDGHI / SECAM L */
/* 0x04 -> ??? PAL others / SECAM others ??? */
cb &= ~0x03;
- if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
- cb |= PHILIPS_MF_SET_PAL_L;
- else if (t->std & V4L2_STD_SECAM_LC)
- cb |= PHILIPS_MF_SET_PAL_L2;
+ if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
+ cb |= PHILIPS_MF_SET_STD_L;
+ else if (params->std & V4L2_STD_SECAM_LC)
+ cb |= PHILIPS_MF_SET_STD_LC;
else /* V4L2_STD_B|V4L2_STD_GH */
- cb |= PHILIPS_MF_SET_BG;
+ cb |= PHILIPS_MF_SET_STD_BG;
break;
case TUNER_TEMIC_4046FM5:
cb &= ~0x0f;
- if (t->std & V4L2_STD_PAL_BG) {
+ if (params->std & V4L2_STD_PAL_BG) {
cb |= TEMIC_SET_PAL_BG;
- } else if (t->std & V4L2_STD_PAL_I) {
+ } else if (params->std & V4L2_STD_PAL_I) {
cb |= TEMIC_SET_PAL_I;
- } else if (t->std & V4L2_STD_PAL_DK) {
+ } else if (params->std & V4L2_STD_PAL_DK) {
cb |= TEMIC_SET_PAL_DK;
- } else if (t->std & V4L2_STD_SECAM_L) {
+ } else if (params->std & V4L2_STD_SECAM_L) {
cb |= TEMIC_SET_PAL_L;
}
@@ -235,13 +288,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
case TUNER_PHILIPS_FQ1216ME:
cb &= ~0x0f;
- if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+ if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
cb |= PHILIPS_SET_PAL_BGDK;
- } else if (t->std & V4L2_STD_PAL_I) {
+ } else if (params->std & V4L2_STD_PAL_I) {
cb |= PHILIPS_SET_PAL_I;
- } else if (t->std & V4L2_STD_SECAM_L) {
+ } else if (params->std & V4L2_STD_SECAM_L) {
cb |= PHILIPS_SET_PAL_L;
}
@@ -253,7 +306,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* 0x02 -> NTSC antenna input 1 */
/* 0x03 -> NTSC antenna input 2 */
cb &= ~0x03;
- if (!(t->std & V4L2_STD_ATSC))
+ if (!(params->std & V4L2_STD_ATSC))
cb |= 2;
/* FIXME: input */
break;
@@ -273,23 +326,23 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = 0x17;
buffer[3] = 0x00;
cb &= ~0x40;
- if (t->std & V4L2_STD_ATSC) {
+ if (params->std & V4L2_STD_ATSC) {
cb |= 0x40;
buffer[1] = 0x04;
}
/* set to the correct mode (analog or digital) */
- tuneraddr = c->addr;
- c->addr = 0x0a;
- if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+ tuneraddr = priv->i2c_props.addr;
+ priv->i2c_props.addr = 0x0a;
+ if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2)))
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
- if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+ if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2)))
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
- c->addr = tuneraddr;
+ priv->i2c_props.addr = tuneraddr;
/* FIXME: input */
break;
}
- if (params->cb_first_if_lower_freq && div < t->last_div) {
+ if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
buffer[0] = config;
buffer[1] = cb;
buffer[2] = (div>>8) & 0x7f;
@@ -300,53 +353,53 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = config;
buffer[3] = cb;
}
- t->last_div = div;
- if (params->has_tda9887) {
+ priv->last_div = div;
+ if (t_params->has_tda9887) {
int config = 0;
- int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
- !(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+ int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
+ !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
- if (t->std == V4L2_STD_SECAM_LC) {
- if (params->port1_active ^ params->port1_invert_for_secam_lc)
+ if (params->std == V4L2_STD_SECAM_LC) {
+ if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
config |= TDA9887_PORT1_ACTIVE;
- if (params->port2_active ^ params->port2_invert_for_secam_lc)
+ if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
config |= TDA9887_PORT2_ACTIVE;
}
else {
- if (params->port1_active)
+ if (t_params->port1_active)
config |= TDA9887_PORT1_ACTIVE;
- if (params->port2_active)
+ if (t_params->port2_active)
config |= TDA9887_PORT2_ACTIVE;
}
- if (params->intercarrier_mode)
+ if (t_params->intercarrier_mode)
config |= TDA9887_INTERCARRIER;
if (is_secam_l) {
- if (i == 0 && params->default_top_secam_low)
- config |= TDA9887_TOP(params->default_top_secam_low);
- else if (i == 1 && params->default_top_secam_mid)
- config |= TDA9887_TOP(params->default_top_secam_mid);
- else if (params->default_top_secam_high)
- config |= TDA9887_TOP(params->default_top_secam_high);
+ if (i == 0 && t_params->default_top_secam_low)
+ config |= TDA9887_TOP(t_params->default_top_secam_low);
+ else if (i == 1 && t_params->default_top_secam_mid)
+ config |= TDA9887_TOP(t_params->default_top_secam_mid);
+ else if (t_params->default_top_secam_high)
+ config |= TDA9887_TOP(t_params->default_top_secam_high);
}
else {
- if (i == 0 && params->default_top_low)
- config |= TDA9887_TOP(params->default_top_low);
- else if (i == 1 && params->default_top_mid)
- config |= TDA9887_TOP(params->default_top_mid);
- else if (params->default_top_high)
- config |= TDA9887_TOP(params->default_top_high);
+ if (i == 0 && t_params->default_top_low)
+ config |= TDA9887_TOP(t_params->default_top_low);
+ else if (i == 1 && t_params->default_top_mid)
+ config |= TDA9887_TOP(t_params->default_top_mid);
+ else if (t_params->default_top_high)
+ config |= TDA9887_TOP(t_params->default_top_high);
}
- if (params->default_pll_gating_18)
+ if (t_params->default_pll_gating_18)
config |= TDA9887_GATING_18;
- i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
}
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
- switch (t->type) {
+ switch (priv->type) {
case TUNER_LG_TDVS_H06XF:
/* Set the Auxiliary Byte. */
buffer[0] = buffer[2];
@@ -355,7 +408,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[1] = 0x20;
tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
- if (2 != (rc = i2c_master_send(c,buffer,2)))
+ if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2)))
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
break;
case TUNER_MICROTUNE_4042FI5:
@@ -367,8 +420,8 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* Wait until the PLL locks */
for (;;) {
if (time_after(jiffies,timeout))
- return;
- if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {
+ return 0;
+ if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) {
tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
break;
}
@@ -386,68 +439,86 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
break;
}
}
+ return 0;
}
-static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int simple_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
struct tunertype *tun;
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_simple_priv *priv = fe->tuner_priv;
u8 buffer[4];
u16 div;
int rc, j;
- enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
- struct tuner_params *params;
+ struct tuner_params *t_params;
+ unsigned int freq = params->frequency;
- tun = &tuners[t->type];
+ tun = priv->tun;
- for (j = 0; j < tun->count-1; j++) {
- if (desired_type != tun->params[j].type)
- continue;
+ for (j = tun->count-1; j > 0; j--)
+ if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
+ break;
+ /* default t_params (j=0) will be used if desired type wasn't found */
+ t_params = &tun->params[j];
+
+ /* Select Radio 1st IF used */
+ switch (t_params->radio_if) {
+ case 0: /* 10.7 MHz */
+ freq += (unsigned int)(10.7*16000);
+ break;
+ case 1: /* 33.3 MHz */
+ freq += (unsigned int)(33.3*16000);
break;
+ case 2: /* 41.3 MHz */
+ freq += (unsigned int)(41.3*16000);
+ break;
+ default:
+ tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if);
+ return 0;
}
- /* use default tuner_params if desired_type not available */
- if (desired_type != tun->params[j].type)
- j = 0;
-
- div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
- params = &tun->params[j];
- buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
- switch (t->type) {
+ /* Bandswitch byte */
+ switch (priv->type) {
case TUNER_TENA_9533_DI:
case TUNER_YMEC_TVF_5533MF:
- tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n");
- return;
+ tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
+ return 0;
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FMD1216ME_MK3:
case TUNER_LG_NTSC_TAPE:
+ case TUNER_PHILIPS_FM1256_IH3:
buffer[3] = 0x19;
break;
case TUNER_TNF_5335MF:
buffer[3] = 0x11;
break;
- case TUNER_PHILIPS_FM1256_IH3:
- div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
- buffer[3] = 0x19;
- break;
case TUNER_LG_PAL_FM:
buffer[3] = 0xa5;
break;
- case TUNER_MICROTUNE_4049FM5:
- div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
- buffer[3] = 0xa4;
+ case TUNER_THOMSON_DTT761X:
+ buffer[3] = 0x39;
break;
+ case TUNER_MICROTUNE_4049FM5:
default:
buffer[3] = 0xa4;
break;
}
- if (params->cb_first_if_lower_freq && div < t->last_div) {
+
+ buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
+ TUNER_RATIO_SELECT_50; /* 50 kHz step */
+
+ /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
+ freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
+ freq * (1/800) */
+ div = (freq + 400) / 800;
+
+ if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
buffer[0] = buffer[2];
buffer[1] = buffer[3];
buffer[2] = (div>>8) & 0x7f;
@@ -459,43 +530,108 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- t->last_div = div;
+ priv->last_div = div;
- if (params->has_tda9887) {
+ if (t_params->has_tda9887) {
int config = 0;
- if (params->port1_active && !params->port1_fm_high_sensitivity)
+ if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
config |= TDA9887_PORT1_ACTIVE;
- if (params->port2_active && !params->port2_fm_high_sensitivity)
+ if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
config |= TDA9887_PORT2_ACTIVE;
- if (params->intercarrier_mode)
+ if (t_params->intercarrier_mode)
config |= TDA9887_INTERCARRIER;
-/* if (params->port1_set_for_fm_mono)
+/* if (t_params->port1_set_for_fm_mono)
config &= ~TDA9887_PORT1_ACTIVE;*/
- if (params->fm_gain_normal)
+ if (t_params->fm_gain_normal)
config |= TDA9887_GAIN_NORMAL;
- i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ if (t_params->radio_if == 2)
+ config |= TDA9887_RIF_41_3;
+ i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
}
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+
+ return 0;
}
-int default_tuner_init(struct i2c_client *c)
+static int simple_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
- tuner_info("type set to %d (%s)\n",
- t->type, tuners[t->type].name);
- strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = simple_set_radio_freq(fe, params);
+ priv->frequency = params->frequency * 125 / 2;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = simple_set_tv_freq(fe, params);
+ priv->frequency = params->frequency * 62500;
+ break;
+ }
- t->set_tv_freq = default_set_tv_freq;
- t->set_radio_freq = default_set_radio_freq;
- t->has_signal = tuner_signal;
- t->is_stereo = tuner_stereo;
- t->standby = NULL;
+ return ret;
+}
+
+static int simple_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
return 0;
}
+static struct dvb_tuner_ops simple_tuner_ops = {
+ .set_analog_params = simple_set_params,
+ .release = simple_release,
+ .get_frequency = simple_get_frequency,
+ .get_status = simple_get_status,
+ .get_rf_strength = simple_get_rf_strength,
+};
+
+struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct simple_tuner_config *cfg)
+{
+ struct tuner_simple_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
+ priv->type = cfg->type;
+ priv->tun = cfg->tun;
+
+ memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name);
+
+ strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name));
+
+ return fe;
+}
+
+
+EXPORT_SYMBOL_GPL(simple_tuner_attach);
+
+MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h
new file mode 100644
index 000000000000..9089939a8c02
--- /dev/null
+++ b/drivers/media/video/tuner-simple.h
@@ -0,0 +1,46 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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 __TUNER_SIMPLE_H__
+#define __TUNER_SIMPLE_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct simple_tuner_config
+{
+ /* chip type */
+ unsigned int type;
+ struct tunertype *tun;
+};
+
+#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
+extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct simple_tuner_config *cfg);
+#else
+static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct simple_tuner_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TUNER_SIMPLE_H__ */
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 74c3e6f96f1a..c6a7934bd5a6 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -594,19 +594,19 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
},
};
-/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
+/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
-static struct tuner_range tuner_philips_atsc_ranges[] = {
+static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
{ 16 * 999.99 , 0x8e, 0x30, },
};
-static struct tuner_params tuner_philips_atsc_params[] = {
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_atsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_atsc_ranges),
+ .ranges = tuner_philips_fcv1236d_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
},
};
@@ -652,6 +652,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
.port1_invert_for_secam_lc = 1,
.default_pll_gating_18 = 1,
.fm_gain_normal=1,
+ .radio_if = 1, /* 33.3 MHz */
},
};
@@ -670,6 +671,9 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
.count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
.has_tda9887 = 1,
.intercarrier_mode = 1,
+ .default_top_low = -3,
+ .default_top_mid = -3,
+ .default_top_high = -3,
},
};
@@ -730,6 +734,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_fm1236_mk3_ntsc_ranges,
.count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+ .radio_if = 1, /* 33.3 MHz */
},
};
@@ -856,6 +861,9 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_thomson_dtt761x_ntsc_ranges,
.count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
+ .has_tda9887 = 1,
+ .fm_gain_normal = 1,
+ .radio_if = 2, /* 41.3 MHz */
},
};
@@ -1296,9 +1304,9 @@ struct tunertype tuners[] = {
.count = ARRAY_SIZE(tuner_philips_pal_mk_params),
},
[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
- .name = "Philips 1236D ATSC/NTSC dual in",
- .params = tuner_philips_atsc_params,
- .count = ARRAY_SIZE(tuner_philips_atsc_params),
+ .name = "Philips FCV1236D ATSC/NTSC dual in",
+ .params = tuner_philips_fcv1236d_params,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_params),
},
[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
.name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1463,6 +1471,10 @@ struct tunertype tuners[] = {
.name = "Philips TDA988[5,6,7] IF PLL Demodulator",
/* see tda9887.c for details */
},
+ [TUNER_TEA5761] = { /* Philips RADIO */
+ .name = "Philips TEA5761 FM Radio",
+ /* see tea5767.c for details */
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 9da338dc4f3b..a19cdcc17ef7 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -290,7 +289,7 @@ static int chip_thread(void *data)
desc->checkmode(chip);
/* schedule next check */
- mod_timer(&chip->wt, jiffies+2*HZ);
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
}
v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1769,7 @@ static int chip_command(struct i2c_client *client,
desc->setmode(chip,VIDEO_SOUND_MONO);
if (chip->prevmode != VIDEO_SOUND_MONO)
chip->prevmode = -1; /* reset previous mode */
- mod_timer(&chip->wt, jiffies+2*HZ);
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
/* the thread will call checkmode() later */
}
break;
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index a1136da74ba8..4b2c4034f5b3 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -183,7 +182,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
{ TUNER_ABSENT, "Thompson DTT757"},
/* 80-89 */
- { TUNER_ABSENT, "Philips FQ1216LME MK3"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -490,7 +489,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+2] & 0x7f;
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tvee->audio_processor = audioIC[audioic].id;
else
tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -523,7 +522,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+1] & 0x7f;
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tvee->audio_processor = audioIC[audioic].id;
else
tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -678,7 +677,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tveeprom_info("audio processor is unknown (no idx)\n");
tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
} else {
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tveeprom_info("audio processor is %s (idx %d)\n",
audioIC[audioic].name,audioic);
else
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 3ae5a9cd2e28..9fa5b702e073 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -2,7 +2,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
@@ -238,13 +237,10 @@ static const struct file_operations tvmixer_fops = {
static int tvmixer_adapters(struct i2c_adapter *adap)
{
- struct list_head *item;
struct i2c_client *client;
- list_for_each(item,&adap->clients) {
- client = list_entry(item, struct i2c_client, list);
+ list_for_each_entry(client, &adap->clients, list)
tvmixer_clients(client);
- }
return 0;
}
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index d5ec05f56adf..e2f1c972754b 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -1006,7 +1006,7 @@ static int tvp5150_command(struct i2c_client *c,
{
struct v4l2_control *ctrl = arg;
u8 i, n;
- n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ n = ARRAY_SIZE(tvp5150_qctrl);
for (i = 0; i < n; i++)
if (ctrl->id == tvp5150_qctrl[i].id) {
if (ctrl->value <
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index abe214619092..491505d6fdee 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -236,7 +236,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
input_dev->name = "Konicawc snapshot button";
input_dev->phys = cam->input_physname;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY);
input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index ec0ff2247f06..dd1a6d6bbc9e 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -100,7 +100,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
input_dev->name = "QCM button";
input_dev->phys = cam->input_physname;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY);
input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
@@ -439,7 +439,7 @@ static int qcm_sensor_init(struct uvd *uvd)
int ret;
int i;
- for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+ for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
CHECK_RET(ret, qcm_stv_setb(uvd->dev,
regval_table[i].reg,
regval_table[i].val));
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 982b115193f8..ff555129c82f 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -42,7 +42,6 @@
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include "usbvideo.h"
@@ -417,11 +416,6 @@ struct vicam_camera {
u8 open_count;
u8 bulkEndpoint;
int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
- struct proc_dir_entry *proc_dir;
-#endif
-
};
static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
@@ -1065,175 +1059,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
- int count, int *eof, int value)
-{
- char *out = page;
- int len;
-
- out += sprintf(out, "%d",value);
-
- len = out - page;
- len -= off;
- if (len < count) {
- *eof = 1;
- if (len <= 0)
- return 0;
- } else
- len = count;
-
- *start = page + off;
- return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return vicam_read_helper(page,start,off,count,eof,
- ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return vicam_read_helper(page,start,off,count,eof,
- ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- u16 stmp;
- char kbuf[8];
- struct vicam_camera *cam = (struct vicam_camera *) data;
-
- if (count > 6)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buffer, count))
- return -EFAULT;
-
- stmp = (u16) simple_strtoul(kbuf, NULL, 10);
- if (stmp < 4 || stmp > 32000)
- return -EINVAL;
-
- cam->shutter_speed = stmp;
-
- return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- u16 gtmp;
- char kbuf[8];
-
- struct vicam_camera *cam = (struct vicam_camera *) data;
-
- if (count > 4)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buffer, count))
- return -EFAULT;
-
- gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
- if (gtmp > 255)
- return -EINVAL;
- cam->gain = gtmp;
-
- return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
- vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
- if (vicam_proc_root)
- vicam_proc_root->owner = THIS_MODULE;
- else
- printk(KERN_ERR
- "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
- if (vicam_proc_root)
- remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
- char name[64];
- struct proc_dir_entry *ent;
-
- DBG(KERN_INFO "vicam: creating proc entry\n");
-
- if (!vicam_proc_root || !cam) {
- printk(KERN_INFO
- "vicam: could not create proc entry, %s pointer is null.\n",
- (!cam ? "camera" : "root"));
- return;
- }
-
- sprintf(name, "video%d", cam->vdev.minor);
-
- cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
- if ( !cam->proc_dir )
- return; // FIXME: We should probably return an error here
-
- ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
- cam->proc_dir);
- if (ent) {
- ent->data = cam;
- ent->read_proc = vicam_read_proc_shutter;
- ent->write_proc = vicam_write_proc_shutter;
- ent->size = 64;
- }
-
- ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
- cam->proc_dir);
- if (ent) {
- ent->data = cam;
- ent->read_proc = vicam_read_proc_gain;
- ent->write_proc = vicam_write_proc_gain;
- ent->size = 64;
- }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
- struct vicam_camera *cam = (struct vicam_camera *) ptr;
- char name[16];
-
- if ( !cam->proc_dir )
- return;
-
- sprintf(name, "video%d", cam->vdev.minor);
- remove_proc_entry("shutter", cam->proc_dir);
- remove_proc_entry("gain", cam->proc_dir);
- remove_proc_entry(name,vicam_proc_root);
- cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
static const struct file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_open,
@@ -1305,13 +1130,12 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
}
if ((cam =
- kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+ kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING
"could not allocate kernel memory for vicam_camera struct\n");
return -ENOMEM;
}
- memset(cam, 0, sizeof (struct vicam_camera));
cam->shutter_speed = 15;
@@ -1330,8 +1154,6 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
return -EIO;
}
- vicam_create_proc_entry(cam);
-
printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
usb_set_intfdata (intf, cam);
@@ -1363,8 +1185,6 @@ vicam_disconnect(struct usb_interface *intf)
cam->udev = NULL;
- vicam_destroy_proc_entry(cam);
-
/* the only thing left to do is synchronize with
* our close/release function on who should release
* the camera memory. if there are any users using the
@@ -1390,7 +1210,6 @@ usb_vicam_init(void)
{
int retval;
DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
- vicam_create_proc_root();
retval = usb_register(&vicam_driver);
if (retval)
printk(KERN_WARNING "usb_register failed!\n");
@@ -1404,7 +1223,6 @@ usb_vicam_exit(void)
"ViCam-based WebCam driver shutdown\n");
usb_deregister(&vicam_driver);
- vicam_destroy_proc_root();
}
module_init(usb_vicam_init);
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 51ab265d566a..f09eb102731b 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -79,7 +79,7 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.Interface = -1,
.Codec = CODEC_SAA7113,
.VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
+ .VideoNorm = V4L2_STD_NTSC,
.AudioChannels = 1,
.Radio = 0,
.vbi = 1,
@@ -311,8 +311,8 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.vbi = 1,
.Tuner = 1,
.TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = -1,
- .Y_Offset = -1,
+ .X_Offset = 0x80,
+ .Y_Offset = 0x16,
.ModelString = "Hauppauge WinTV USB (PAL/SECAM L)",
},
[HPG_WINTV_PAL_D_K] = {
@@ -586,7 +586,7 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.Radio = 0,
.vbi = 1,
.Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
+ .TunerType = TUNER_LG_PAL_NEW_TAPC,
.X_Offset = 0,
.Y_Offset = 3,
.Dvi_yuv_override = 1,
@@ -1081,6 +1081,7 @@ struct usb_device_id usbvision_table [] = {
{ USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL },
{ USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM },
{ USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV },
+ { }, /* terminate list */
};
MODULE_DEVICE_TABLE (usb, usbvision_table);
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 7df071eb0a3b..c7d5f9ed22d7 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -45,7 +45,6 @@
#include <media/tuner.h>
#include <media/audiochip.h>
-#include <linux/moduleparam.h>
#include <linux/workqueue.h>
#ifdef CONFIG_KMOD
@@ -1742,7 +1741,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
format = ISOC_MODE_YUV420;
}
value[0] = 0x0A; //TODO: See the effect of the filter
- value[1] = format;
+ value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1831,10 +1830,10 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
frameRate = FRAMERATE_MAX;
}
- if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+ if (usbvision->tvnormId & V4L2_STD_625_50) {
frameDrop = frameRate * 32 / 25 - 1;
}
- else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+ else if (usbvision->tvnormId & V4L2_STD_525_60) {
frameDrop = frameRate * 32 / 30 - 1;
}
@@ -2067,7 +2066,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
}
- if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+ if (usbvision->tvnormId & V4L2_STD_PAL) {
value[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20;
@@ -2076,7 +2075,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
value[5] = 0x00; //0x0060 -> 96 Input video h offset
value[6] = 0x16;
value[7] = 0x00; //0x0016 -> 22 Input video v offset
- } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+ } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
value[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20;
@@ -2537,7 +2536,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
{
- int mode[4];
+ /* inputs #0 and #3 are constant for every SAA711x. */
+ /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
+ int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
int audio[]= {1, 0, 0, 0};
struct v4l2_routing route;
//channel 0 is TV with audiochannel 1 (tuner mono)
@@ -2547,10 +2548,6 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
- route.input = SAA7115_COMPOSITE1;
- route.output = 0;
- call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
- call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
// set the new channel
// Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
@@ -2558,28 +2555,27 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
switch (usbvision_device_data[usbvision->DevModel].Codec) {
case CODEC_SAA7113:
- if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices. Use SwitchSVideoInput parameter when loading the module.
- mode[2] = 1;
+ mode[1] = SAA7115_COMPOSITE2;
+ if (SwitchSVideoInput) {
+ /* To handle problems with S-Video Input for
+ * some devices. Use SwitchSVideoInput
+ * parameter when loading the module.*/
+ mode[2] = SAA7115_COMPOSITE1;
}
else {
- mode[2] = 7;
- }
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices
- }
- else {
- mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+ mode[2] = SAA7115_SVIDEO1;
}
break;
case CODEC_SAA7111:
- mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
- break;
default:
- mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+ /* modes for saa7111 */
+ mode[1] = SAA7115_COMPOSITE1;
+ mode[2] = SAA7115_SVIDEO1;
+ break;
}
route.input = mode[channel];
+ route.output = 0;
call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
- usbvision->channel = channel;
usbvision_set_audio(usbvision, audio[channel]);
return 0;
}
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 025be555194f..c66aef63916f 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -134,8 +134,6 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
addr = (msg->addr << 1);
if (flags & I2C_M_RD)
addr |= 1;
- if (flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
add[0] = addr;
if (flags & I2C_M_RD)
@@ -192,7 +190,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned
static u32 functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index aa3258bbb4af..e2f3c01cfa13 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -36,7 +36,8 @@
* - use submit_urb for all setup packets
* - Fix memory settings for nt1004. It is 4 times as big as the
* nt1003 memory.
- * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one?
+ * - Add audio on endpoint 3 for nt1004 chip.
+ * Seems impossible, needs a codec interface. Which one?
* - Clean up the driver.
* - optimization for performance.
* - Add Videotext capability (VBI). Working on it.....
@@ -67,7 +68,6 @@
#include <media/tuner.h>
#include <media/audiochip.h>
-#include <linux/moduleparam.h>
#include <linux/workqueue.h>
#ifdef CONFIG_KMOD
@@ -77,7 +77,8 @@
#include "usbvision.h"
#include "usbvision-cards.h"
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
+ Dwaine Garden <DwaineGarden@rogers.com>"
#define DRIVER_NAME "usbvision"
#define DRIVER_ALIAS "USBVision"
#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -85,20 +86,25 @@
#define USBVISION_DRIVER_VERSION_MAJOR 0
#define USBVISION_DRIVER_VERSION_MINOR 9
#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
+USBVISION_DRIVER_VERSION_MINOR,\
+USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
#ifdef USBVISION_DEBUG
#define PDEBUG(level, fmt, args...) \
- if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+ if (video_debug & (level)) \
+ info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
+ ## args)
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
-#define DBG_IOCTL 1<<0
#define DBG_IO 1<<1
#define DBG_PROBE 1<<2
#define DBG_MMAP 1<<3
@@ -108,7 +114,8 @@
#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
-static int usbvision_nr = 0; // sequential number of usbvision device
+/* sequential number of usbvision device */
+static int usbvision_nr = 0;
static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
@@ -121,55 +128,32 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
};
-/* supported tv norms */
-static struct usbvision_tvnorm tvnorms[] = {
- {
- .name = "PAL",
- .id = V4L2_STD_PAL,
- }, {
- .name = "NTSC",
- .id = V4L2_STD_NTSC,
- }, {
- .name = "SECAM",
- .id = V4L2_STD_SECAM,
- }, {
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- }
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
-// Function prototypes
+/* Function prototypes */
static void usbvision_release(struct usb_usbvision *usbvision);
-// Default initalization of device driver parameters
-static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint
-static int video_debug = 0; // Set the default Debug Mode of the device driver
-static int PowerOnAtOpen = 1; // Set the default device to power on at startup
-static int video_nr = -1; // Sequential Number of Video Device
-static int radio_nr = -1; // Sequential Number of Radio Device
-static int vbi_nr = -1; // Sequential Number of VBI Device
-
-// Grab parameters for the device driver
-
-#if defined(module_param) // Showing parameters under SYSFS
+/* Default initalization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isocMode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug = 0;
+/* Set the default device to power on at startup */
+static int PowerOnAtOpen = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+/* Sequential Number of VBI Device */
+static int vbi_nr = -1;
+
+/* Grab parameters for the device driver */
+
+/* Showing parameters under SYSFS */
module_param(isocMode, int, 0444);
module_param(video_debug, int, 0444);
module_param(PowerOnAtOpen, int, 0444);
module_param(video_nr, int, 0444);
module_param(radio_nr, int, 0444);
module_param(vbi_nr, int, 0444);
-#else // Old Style
-MODULE_PARAM(isocMode, "i");
-MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver
-MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive
-MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup
-MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently.
-MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
-MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
-MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-#endif
MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
@@ -187,39 +171,47 @@ MODULE_VERSION(USBVISION_VERSION_STRING);
MODULE_ALIAS(DRIVER_ALIAS);
-/****************************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module. */
-/* Device information is located at /sys/class/video4linux/video0 */
-/* Device parameters information is located at /sys/module/usbvision */
-/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */
-/****************************************************************************************/
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module. */
+/* Device information is located at /sys/class/video4linux/video0 */
+/* Device parameters information is located at /sys/module/usbvision */
+/* Device USB Information is located at */
+/* /sys/bus/usb/drivers/USBVision Video Grabber */
+/*****************************************************************************/
#define YES_NO(x) ((x) ? "Yes" : "No")
-static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
+static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
return video_get_drvdata(vdev);
}
-static ssize_t show_version(struct class_device *cd, char *buf)
+static ssize_t show_version(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
}
-static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
-static ssize_t show_model(struct class_device *cd, char *buf)
+static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+ return sprintf(buf, "%s\n",
+ usbvision_device_data[usbvision->DevModel].ModelString);
}
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-static ssize_t show_hue(struct class_device *cd, char *buf)
+static ssize_t show_hue(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_HUE;
@@ -228,11 +220,13 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-static ssize_t show_contrast(struct class_device *cd, char *buf)
+static ssize_t show_contrast(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_CONTRAST;
@@ -241,11 +235,13 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-static ssize_t show_brightness(struct class_device *cd, char *buf)
+static ssize_t show_brightness(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -254,11 +250,13 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-static ssize_t show_saturation(struct class_device *cd, char *buf)
+static ssize_t show_saturation(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_SATURATION;
@@ -267,31 +265,39 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-static ssize_t show_streaming(struct class_device *cd, char *buf)
+static ssize_t show_streaming(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->streaming==Stream_On?1:0));
}
-static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
+static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
-static ssize_t show_compression(struct class_device *cd, char *buf)
+static ssize_t show_compression(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
}
-static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
+static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
-static ssize_t show_device_bridge(struct class_device *cd, char *buf)
+static ssize_t show_device_bridge(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%d\n", usbvision->bridgeType);
}
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
+static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
static void usbvision_create_sysfs(struct video_device *vdev)
{
@@ -299,40 +305,40 @@ static void usbvision_create_sysfs(struct video_device *vdev)
if (!vdev)
return;
do {
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_version);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_version);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_model);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_model);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_hue);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_hue);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_contrast);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_contrast);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_brightness);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_brightness);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_saturation);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_saturation);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_streaming);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_streaming);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_compression);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_compression);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_bridge);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_bridge);
if (res>=0)
return;
} while (0);
@@ -343,24 +349,24 @@ static void usbvision_create_sysfs(struct video_device *vdev)
static void usbvision_remove_sysfs(struct video_device *vdev)
{
if (vdev) {
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_version);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_model);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_hue);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_contrast);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_brightness);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_saturation);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_streaming);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_compression);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_bridge);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_version);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_model);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_hue);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_contrast);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_brightness);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_saturation);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_streaming);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_compression);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_bridge);
}
}
@@ -376,7 +382,8 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
static int usbvision_v4l2_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "open");
@@ -390,7 +397,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
/* Allocate memory for the scratch ring buffer */
errCode = usbvision_scratch_alloc(usbvision);
if (isocMode==ISOC_MODE_COMPRESS) {
- /* Allocate intermediate decompression buffers only if needed */
+ /* Allocate intermediate decompression buffers
+ only if needed */
errCode = usbvision_decompress_alloc(usbvision);
}
if (errCode) {
@@ -421,11 +429,10 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
if (!errCode) {
usbvision_begin_streaming(usbvision);
errCode = usbvision_init_isoc(usbvision);
- /* device needs to be initialized before isoc transfer */
+ /* device must be initialized before isoc transfer */
usbvision_muxsel(usbvision,0);
usbvision->user++;
- }
- else {
+ } else {
if (PowerOnAtOpen) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
@@ -456,7 +463,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
static int usbvision_v4l2_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
PDEBUG(DBG_IO, "close");
down(&usbvision->lock);
@@ -473,7 +481,8 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
usbvision->user--;
if (PowerOnAtOpen) {
- /* power off in a little while to avoid off/on every close/open short sequences */
+ /* power off in a little while
+ to avoid off/on every close/open short sequences */
usbvision_set_powerOffTimer(usbvision);
usbvision->initialized = 0;
}
@@ -498,583 +507,613 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
* This is part of Video 4 Linux API. The procedure handles ioctl() calls.
*
*/
-static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EFAULT;
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode;
- switch (cmd) {
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (errCode < 0) {
+ err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+ __FUNCTION__, errCode);
+ return errCode;
+ }
+ reg->val = errCode;
+ return 0;
+}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct acces to the NT100x registers */
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- int errCode;
-
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- /* NT100x has a 8-bit register space */
- if (cmd == VIDIOC_DBG_G_REGISTER)
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- else
- errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
- if (errCode < 0) {
- err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
- cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
- return errCode;
- }
- if (cmd == VIDIOC_DBG_S_REGISTER)
- reg->val = (u8)errCode;
+static int vidioc_s_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode;
- PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
- cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
- (unsigned int)reg->reg, (unsigned int)reg->val);
- return 0;
- }
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ if (errCode < 0) {
+ err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+ __FUNCTION__, errCode);
+ return errCode;
+ }
+ return 0;
+}
#endif
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *vc=arg;
-
- memset(vc, 0, sizeof(*vc));
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
- sizeof(vc->card));
- strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
- sizeof(vc->bus_info));
- vc->version = USBVISION_DRIVER_VERSION;
- vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
- return 0;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *vi = arg;
- int chan;
-
- if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
- return -EINVAL;
- if (usbvision->have_tuner) {
- chan = vi->index;
- }
- else {
- chan = vi->index + 1; //skip Television string
- }
- switch(chan) {
- case 0:
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "White Video Input");
- }
- else {
- strcpy(vi->name, "Television");
- vi->type = V4L2_INPUT_TYPE_TUNER;
- vi->audioset = 1;
- vi->tuner = chan;
- vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
- }
- break;
- case 1:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "Green Video Input");
- }
- else {
- strcpy(vi->name, "Composite Video Input");
- }
- vi->std = V4L2_STD_PAL;
- break;
- case 2:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "Yellow Video Input");
- }
- else {
- strcpy(vi->name, "S-Video Input");
- }
- vi->std = V4L2_STD_PAL;
- break;
- case 3:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(vi->name, "Red Video Input");
- vi->std = V4L2_STD_PAL;
- break;
- }
- PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
- vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
- return 0;
- }
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
- int ret;
-
- i = e->index;
- if (i >= TVNORMS)
- return -EINVAL;
- ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (ret < 0)
- return ret;
- return 0;
+
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *vc)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strlcpy(vc->card,
+ usbvision_device_data[usbvision->DevModel].ModelString,
+ sizeof(vc->card));
+ strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+ sizeof(vc->bus_info));
+ vc->version = USBVISION_DRIVER_VERSION;
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *vi)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int chan;
+
+ if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+ return -EINVAL;
+ if (usbvision->have_tuner) {
+ chan = vi->index;
+ } else {
+ chan = vi->index + 1; /*skip Television string*/
+ }
+ /* Determine the requested input characteristics
+ specific for each usbvision card model */
+ switch(chan) {
+ case 0:
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "White Video Input");
+ } else {
+ strcpy(vi->name, "Television");
+ vi->type = V4L2_INPUT_TYPE_TUNER;
+ vi->audioset = 1;
+ vi->tuner = chan;
+ vi->std = USBVISION_NORMS;
}
- case VIDIOC_G_INPUT:
- {
- int *input = arg;
- *input = usbvision->ctl_input;
- return 0;
+ break;
+ case 1:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Green Video Input");
+ } else {
+ strcpy(vi->name, "Composite Video Input");
}
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
- if ((*input >= usbvision->video_inputs) || (*input < 0) )
- return -EINVAL;
- usbvision->ctl_input = *input;
-
- down(&usbvision->lock);
- usbvision_muxsel(usbvision, usbvision->ctl_input);
- usbvision_set_input(usbvision);
- usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
- up(&usbvision->lock);
- return 0;
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 2:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Yellow Video Input");
+ } else {
+ strcpy(vi->name, "S-Video Input");
}
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 3:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(vi->name, "Red Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ }
+ return 0;
+}
- *id = usbvision->tvnorm->id;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
-
- for (i = 0; i < TVNORMS; i++)
- if (*id == tvnorms[i].id)
- break;
- if (i == TVNORMS)
- for (i = 0; i < TVNORMS; i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == TVNORMS)
- return -EINVAL;
-
- down(&usbvision->lock);
- usbvision->tvnorm = &tvnorms[i];
-
- call_i2c_clients(usbvision, VIDIOC_S_STD,
- &usbvision->tvnorm->id);
+ *input = usbvision->ctl_input;
+ return 0;
+}
- up(&usbvision->lock);
+static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- if (!usbvision->have_tuner || vt->index) // Only tuner 0
- return -EINVAL;
- strcpy(vt->name, "Television");
- /* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *freq = arg;
-
- freq->tuner = 0; // Only one tuner
- freq->type = V4L2_TUNER_ANALOG_TV;
- freq->frequency = usbvision->freq;
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *freq = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || freq->tuner)
- return -EINVAL;
-
- usbvision->freq = freq->frequency;
- call_i2c_clients(usbvision, cmd, freq);
- PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *v = arg;
- memset(v,0, sizeof(v));
- strcpy(v->name, "TV");
- PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
- return 0;
- }
- case VIDIOC_S_AUDIO:
- {
- struct v4l2_audio *v = arg;
- if(v->index) {
- return -EINVAL;
- }
- PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- int id=ctrl->id;
+ if ((input >= usbvision->video_inputs) || (input < 0) )
+ return -EINVAL;
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
+ down(&usbvision->lock);
+ usbvision_muxsel(usbvision, input);
+ usbvision_set_input(usbvision);
+ usbvision_set_output(usbvision,
+ usbvision->curwidth,
+ usbvision->curheight);
+ up(&usbvision->lock);
+ return 0;
+}
- call_i2c_clients(usbvision, cmd, arg);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ usbvision->tvnormId=*id;
- if (ctrl->type)
- return 0;
- else
- return -EINVAL;
+ down(&usbvision->lock);
+ call_i2c_clients(usbvision, VIDIOC_S_STD,
+ &usbvision->tvnormId);
+ up(&usbvision->lock);
+ /* propagate the change to the decoder */
+ usbvision_muxsel(usbvision, usbvision->ctl_input);
- PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
- PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
+ return 0;
+}
- PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
- return 0;
- }
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *vr = arg;
- int ret;
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+ if (!usbvision->have_tuner || vt->index) // Only tuner 0
+ return -EINVAL;
+ if(usbvision->radio) {
+ strcpy(vt->name, "Radio");
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strcpy(vt->name, "Television");
+ }
+ /* Let clients fill in the remainder of this struct */
+ call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
- // Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
- if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (vr->memory != V4L2_MEMORY_MMAP))
- return -EINVAL;
+ return 0;
+}
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
- return ret;
- }
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
- vr->count = usbvision_frames_alloc(usbvision,vr->count);
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+ call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
- usbvision->curFrame = NULL;
+ return 0;
+}
- PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
- return 0;
- }
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *vb = arg;
- struct usbvision_frame *frame;
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
+ freq->tuner = 0; // Only one tuner
+ if(usbvision->radio) {
+ freq->type = V4L2_TUNER_RADIO;
+ } else {
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ }
+ freq->frequency = usbvision->freq;
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
- if(vb->index>=usbvision->num_frames) {
- return -EINVAL;
- }
- // Updating the corresponding frame state
- vb->flags = 0;
- frame = &usbvision->frame[vb->index];
- if(frame->grabstate >= FrameState_Ready)
- vb->flags |= V4L2_BUF_FLAG_QUEUED;
- if(frame->grabstate >= FrameState_Done)
- vb->flags |= V4L2_BUF_FLAG_DONE;
- if(frame->grabstate == FrameState_Unused)
- vb->flags |= V4L2_BUF_FLAG_MAPPED;
- vb->memory = V4L2_MEMORY_MMAP;
-
- vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->field = V4L2_FIELD_NONE;
- vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
- vb->timestamp = usbvision->frame[vb->index].timestamp;
- vb->sequence = usbvision->frame[vb->index].sequence;
- return 0;
- }
- case VIDIOC_QBUF:
- {
- struct v4l2_buffer *vb = arg;
- struct usbvision_frame *frame;
- unsigned long lock_flags;
-
- // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
- if(vb->index>=usbvision->num_frames) {
- return -EINVAL;
- }
+ return 0;
+}
- frame = &usbvision->frame[vb->index];
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- if (frame->grabstate != FrameState_Unused) {
- return -EAGAIN;
- }
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || freq->tuner)
+ return -EINVAL;
- /* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+ usbvision->freq = freq->frequency;
+ call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
- vb->flags &= ~V4L2_BUF_FLAG_DONE;
+ return 0;
+}
- /* set v4l2_format index */
- frame->v4l2_format = usbvision->palette;
+static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+ memset(a,0,sizeof(*a));
+ if(usbvision->radio) {
+ strcpy(a->name,"Radio");
+ } else {
+ strcpy(a->name, "TV");
+ }
- PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
- return 0;
- }
- case VIDIOC_DQBUF:
- {
- struct v4l2_buffer *vb = arg;
- int ret;
- struct usbvision_frame *f;
- unsigned long lock_flags;
-
- if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (list_empty(&(usbvision->outqueue))) {
- if (usbvision->streaming == Stream_Idle)
- return -EINVAL;
- ret = wait_event_interruptible
- (usbvision->wait_frame,
- !list_empty(&(usbvision->outqueue)));
- if (ret)
- return ret;
- }
+ return 0;
+}
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- f = list_entry(usbvision->outqueue.next,
- struct usbvision_frame, frame);
- list_del(usbvision->outqueue.next);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- f->grabstate = FrameState_Unused;
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
- vb->index = f->index;
- vb->sequence = f->sequence;
- vb->timestamp = f->timestamp;
- vb->field = V4L2_FIELD_NONE;
- vb->bytesused = f->scanlength;
-
- return 0;
- }
- case VIDIOC_STREAMON:
- {
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+static int vidioc_s_audio (struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ if(a->index) {
+ return -EINVAL;
+ }
- usbvision->streaming = Stream_On;
+ return 0;
+}
- call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int id=ctrl->id;
- PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
+ memset(ctrl,0,sizeof(*ctrl));
+ ctrl->id=id;
- return 0;
- }
- case VIDIOC_STREAMOFF:
- {
- int *type = arg;
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if(usbvision->streaming == Stream_On) {
- usbvision_stream_interrupt(usbvision);
- // Stop all video streamings
- call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
- }
- usbvision_empty_framequeues(usbvision);
+ call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
- PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
- return 0;
- }
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *vfd = arg;
+ if (!ctrl->type)
+ return -EINVAL;
- if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
- return -EINVAL;
- }
- vfd->flags = 0;
- vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
- vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
- memset(vfd->reserved, 0, sizeof(vfd->reserved));
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *vf = arg;
-
- switch (vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- vf->fmt.pix.width = usbvision->curwidth;
- vf->fmt.pix.height = usbvision->curheight;
- vf->fmt.pix.pixelformat = usbvision->palette.format;
- vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
- vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
- default:
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
- return -EINVAL;
- }
- return 0;
- }
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *vf = arg;
- int formatIdx,ret;
-
- switch(vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- /* Find requested format in available ones */
- for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
- if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
- usbvision->palette = usbvision_v4l2_format[formatIdx];
- break;
- }
- }
- /* robustness */
- if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
- return -EINVAL;
- }
- RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
- RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
- vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
- if(cmd == VIDIOC_TRY_FMT) {
- PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
-
- /* stop io in case it is already in progress */
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
- return ret;
- }
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
-
- usbvision->curFrame = NULL;
-
- // by now we are committed to the new data...
- down(&usbvision->lock);
- usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
- up(&usbvision->lock);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
- default:
- return -EINVAL;
- }
- }
- default:
- return -ENOIOCTLCMD;
+ return 0;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_reqbufs (struct file *file,
+ void *priv, struct v4l2_requestbuffers *vr)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+
+ RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+ /* Check input validity:
+ the user must do a VIDEO CAPTURE and MMAP method. */
+ if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+ (vr->memory != V4L2_MEMORY_MMAP))
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
}
+
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ vr->count = usbvision_frames_alloc(usbvision,vr->count);
+
+ usbvision->curFrame = NULL;
+
return 0;
}
-static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_querybuf (struct file *file,
+ void *priv, struct v4l2_buffer *vb)
{
- return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usbvision_frame *frame;
+
+ /* FIXME : must control
+ that buffers are mapped (VIDIOC_REQBUFS has been called) */
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+ /* Updating the corresponding frame state */
+ vb->flags = 0;
+ frame = &usbvision->frame[vb->index];
+ if(frame->grabstate >= FrameState_Ready)
+ vb->flags |= V4L2_BUF_FLAG_QUEUED;
+ if(frame->grabstate >= FrameState_Done)
+ vb->flags |= V4L2_BUF_FLAG_DONE;
+ if(frame->grabstate == FrameState_Unused)
+ vb->flags |= V4L2_BUF_FLAG_MAPPED;
+ vb->memory = V4L2_MEMORY_MMAP;
+
+ vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->field = V4L2_FIELD_NONE;
+ vb->length = usbvision->curwidth*
+ usbvision->curheight*
+ usbvision->palette.bytes_per_pixel;
+ vb->timestamp = usbvision->frame[vb->index].timestamp;
+ vb->sequence = usbvision->frame[vb->index].sequence;
+ return 0;
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usbvision_frame *frame;
+ unsigned long lock_flags;
+
+ /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+
+ frame = &usbvision->frame[vb->index];
+
+ if (frame->grabstate != FrameState_Unused) {
+ return -EAGAIN;
+ }
+
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = FrameState_Ready;
+ frame->scanstate = ScanState_Scanning;
+ frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+
+ vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ return 0;
}
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+ struct usbvision_frame *f;
+ unsigned long lock_flags;
+
+ if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (list_empty(&(usbvision->outqueue))) {
+ if (usbvision->streaming == Stream_Idle)
+ return -EINVAL;
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ f = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ f->grabstate = FrameState_Unused;
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->flags = V4L2_BUF_FLAG_MAPPED |
+ V4L2_BUF_FLAG_QUEUED |
+ V4L2_BUF_FLAG_DONE;
+ vb->index = f->index;
+ vb->sequence = f->sequence;
+ vb->timestamp = f->timestamp;
+ vb->field = V4L2_FIELD_NONE;
+ vb->bytesused = f->scanlength;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ usbvision->streaming = Stream_On;
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+ return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+ void *priv, enum v4l2_buf_type type)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ usbvision_stream_interrupt(usbvision);
+ /* Stop all video streamings */
+ call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+ }
+ usbvision_empty_framequeues(usbvision);
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *vfd)
+{
+ if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ return -EINVAL;
+ }
+ vfd->flags = 0;
+ vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+ memset(vfd->reserved, 0, sizeof(vfd->reserved));
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ vf->fmt.pix.width = usbvision->curwidth;
+ vf->fmt.pix.height = usbvision->curheight;
+ vf->fmt.pix.pixelformat = usbvision->palette.format;
+ vf->fmt.pix.bytesperline =
+ usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+ vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int formatIdx;
+
+ /* Find requested format in available ones */
+ for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+ if(vf->fmt.pix.pixelformat ==
+ usbvision_v4l2_format[formatIdx].format) {
+ usbvision->palette = usbvision_v4l2_format[formatIdx];
+ break;
+ }
+ }
+ /* robustness */
+ if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+ return -EINVAL;
+ }
+ RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+ RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+ vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+ usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+
+ if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+ return ret;
+ }
+
+ /* stop io in case it is already in progress */
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
+ }
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+
+ usbvision->curFrame = NULL;
+
+ /* by now we are committed to the new data... */
+ down(&usbvision->lock);
+ usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+ up(&usbvision->lock);
+
+ return 0;
+}
static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int noblock = file->f_flags & O_NONBLOCK;
unsigned long lock_flags;
int ret,i;
struct usbvision_frame *frame;
- PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+ PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+ (unsigned long)count, noblock);
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
return -EFAULT;
- /* This entry point is compatible with the mmap routines so that a user can do either
- VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+ /* This entry point is compatible with the mmap routines
+ so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+ to get frames or call read on the device. */
if(!usbvision->num_frames) {
- /* First, allocate some frames to work with if this has not been done with
- VIDIOC_REQBUF */
+ /* First, allocate some frames to work with
+ if this has not been done with VIDIOC_REQBUF */
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
@@ -1086,21 +1125,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
}
- /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+ /* Then, enqueue as many frames as possible
+ (like a user of VIDIOC_QBUF would do) */
for(i=0;i<usbvision->num_frames;i++) {
frame = &usbvision->frame[i];
if(frame->grabstate == FrameState_Unused) {
/* Mark it as ready and enqueue frame */
frame->grabstate = FrameState_Ready;
frame->scanstate = ScanState_Scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+ /* Accumulated in usbvision_parse_data() */
+ frame->scanlength = 0;
/* set v4l2_format index */
frame->v4l2_format = usbvision->palette;
spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
list_add_tail(&frame->frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+ spin_unlock_irqrestore(&usbvision->queue_lock,
+ lock_flags);
}
}
@@ -1128,8 +1170,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
return 0;
}
- PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
- frame->index, frame->bytes_read, frame->scanlength);
+ PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+ __FUNCTION__,
+ frame->index, frame->bytes_read, frame->scanlength);
/* copy bytes to user space; we allow for partials reads */
if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
@@ -1140,10 +1183,11 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
}
frame->bytes_read += count;
- PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
- (unsigned long)count, frame->bytes_read);
+ PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+ __FUNCTION__,
+ (unsigned long)count, frame->bytes_read);
- // For now, forget the frame if it has not been read in one shot.
+ /* For now, forget the frame if it has not been read in one shot. */
/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */
frame->bytes_read = 0;
@@ -1162,7 +1206,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
u32 i;
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
PDEBUG(DBG_MMAP, "mmap");
@@ -1180,11 +1225,13 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
}
for (i = 0; i < usbvision->num_frames; i++) {
- if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+ if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+ vma->vm_pgoff)
break;
}
if (i == usbvision->num_frames) {
- PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+ PDEBUG(DBG_MMAP,
+ "mmap: user supplied mapping address is out of range");
up(&usbvision->lock);
return -EINVAL;
}
@@ -1218,8 +1265,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
static int usbvision_radio_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
- struct v4l2_frequency freq;
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "%s:", __FUNCTION__);
@@ -1249,8 +1296,6 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
// If so far no errors then we shall start the radio
usbvision->radio = 1;
call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
- freq.frequency = 1517; //SWR3 @ 94.8MHz
- call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
usbvision->user++;
}
@@ -1270,7 +1315,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
static int usbvision_radio_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "");
@@ -1304,149 +1350,6 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
return errCode;
}
-static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EIO;
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *vc=arg;
-
- memset(vc, 0, sizeof(*vc));
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
- sizeof(vc->card));
- strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
- sizeof(vc->bus_info));
- vc->version = USBVISION_DRIVER_VERSION;
- vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- int id=ctrl->id;
-
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
-
- call_i2c_clients(usbvision, cmd, arg);
- PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-
- if (ctrl->type)
- return 0;
- else
- return -EINVAL;
-
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
- PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
- PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
-
- if (t->index > 0)
- return -EINVAL;
-
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- /* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
- PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
- PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
-
- memset(a,0,sizeof(*a));
- strcpy(a->name,"Radio");
- PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
- return 0;
- }
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_STD:
- return 0;
-
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- memset(f,0,sizeof(*f));
-
- f->type = V4L2_TUNER_RADIO;
- f->frequency = usbvision->freq;
- call_i2c_clients(usbvision, cmd, f);
- PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (f->tuner != 0)
- return -EINVAL;
- usbvision->freq = f->frequency;
- call_i2c_clients(usbvision, cmd, f);
- PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
- return 0;
- }
- default:
- {
- PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
- return -ENOIOCTLCMD;
- }
- }
- return 0;
-}
-
-
-static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
-}
-
-
/*
* Here comes the stuff for vbi on usbvision based devices
*
@@ -1454,21 +1357,21 @@ static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
static int usbvision_vbi_open(struct inode *inode, struct file *file)
{
/* TODO */
- return -EINVAL;
+ return -ENODEV;
}
static int usbvision_vbi_close(struct inode *inode, struct file *file)
{
/* TODO */
- return -EINVAL;
+ return -ENODEV;
}
static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
/* TODO */
- return -EINVAL;
+ return -ENOIOCTLCMD;
}
static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
@@ -1489,8 +1392,10 @@ static const struct file_operations usbvision_fops = {
.release = usbvision_v4l2_close,
.read = usbvision_v4l2_read,
.mmap = usbvision_v4l2_mmap,
- .ioctl = usbvision_v4l2_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
+/* .poll = video_poll, */
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_video_template = {
.owner = THIS_MODULE,
@@ -1500,6 +1405,39 @@ static struct video_device usbvision_video_template = {
.name = "usbvision-video",
.release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* .vidiocgmbuf = vidiocgmbuf, */
+#endif
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
@@ -1508,8 +1446,9 @@ static const struct file_operations usbvision_radio_fops = {
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
- .ioctl = usbvision_radio_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_radio_template=
@@ -1518,12 +1457,27 @@ static struct video_device usbvision_radio_template=
.type = VID_TYPE_TUNER,
.hardware = VID_HARDWARE_USBVISION,
.fops = &usbvision_radio_fops,
- .release = video_device_release,
.name = "usbvision-radio",
+ .release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
-
// vbi template
static const struct file_operations usbvision_vbi_fops = {
.owner = THIS_MODULE,
@@ -1531,6 +1485,7 @@ static const struct file_operations usbvision_vbi_fops = {
.release = usbvision_vbi_close,
.ioctl = usbvision_vbi_ioctl,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_vbi_template=
@@ -1574,11 +1529,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
{
// vbi Device:
if (usbvision->vbi) {
- PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
+ usbvision->vbi->minor & 0x1f);
if (usbvision->vbi->minor != -1) {
video_unregister_device(usbvision->vbi);
- }
- else {
+ } else {
video_device_release(usbvision->vbi);
}
usbvision->vbi = NULL;
@@ -1586,11 +1541,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// Radio Device:
if (usbvision->rdev) {
- PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
+ usbvision->rdev->minor & 0x1f);
if (usbvision->rdev->minor != -1) {
video_unregister_device(usbvision->rdev);
- }
- else {
+ } else {
video_device_release(usbvision->rdev);
}
usbvision->rdev = NULL;
@@ -1598,11 +1553,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// Video Device:
if (usbvision->vdev) {
- PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
+ usbvision->vdev->minor & 0x1f);
if (usbvision->vdev->minor != -1) {
video_unregister_device(usbvision->vdev);
- }
- else {
+ } else {
video_device_release(usbvision->vdev);
}
usbvision->vdev = NULL;
@@ -1613,37 +1568,52 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
{
// Video Device:
- usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+ usbvision->vdev = usbvision_vdev_init(usbvision,
+ &usbvision_video_template,
+ "USBVision Video");
if (usbvision->vdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+ if (video_register_device(usbvision->vdev,
+ VFL_TYPE_GRABBER,
+ video_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
+ usbvision->nr,usbvision->vdev->minor & 0x1f);
// Radio Device:
if (usbvision_device_data[usbvision->DevModel].Radio) {
// usbvision has radio
- usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+ usbvision->rdev = usbvision_vdev_init(usbvision,
+ &usbvision_radio_template,
+ "USBVision Radio");
if (usbvision->rdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+ if (video_register_device(usbvision->rdev,
+ VFL_TYPE_RADIO,
+ radio_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
+ usbvision->nr, usbvision->rdev->minor & 0x1f);
}
// vbi Device:
if (usbvision_device_data[usbvision->DevModel].vbi) {
- usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+ usbvision->vbi = usbvision_vdev_init(usbvision,
+ &usbvision_vbi_template,
+ "USBVision VBI");
if (usbvision->vdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+ if (video_register_device(usbvision->vbi,
+ VFL_TYPE_VBI,
+ vbi_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
+ usbvision->nr,usbvision->vbi->minor & 0x1f);
}
// all done
return 0;
@@ -1657,7 +1627,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
/*
* usbvision_alloc()
*
- * This code allocates the struct usb_usbvision. It is filled with default values.
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
*
* Returns NULL on error, a pointer to usb_usbvision else.
*
@@ -1666,7 +1637,8 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
{
struct usb_usbvision *usbvision;
- if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+ if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+ NULL) {
goto err_exit;
}
@@ -1728,11 +1700,11 @@ static void usbvision_release(struct usb_usbvision *usbvision)
}
-/******************************** usb interface *****************************************/
+/*********************** usb interface **********************************/
static void usbvision_configure_video(struct usb_usbvision *usbvision)
{
- int model,i;
+ int model;
if (usbvision == NULL)
return;
@@ -1741,25 +1713,23 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
- usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+ usbvision->Vin_Reg2_Preset =
+ usbvision_device_data[usbvision->DevModel].Vin_Reg2;
} else {
usbvision->Vin_Reg2_Preset = 0;
}
- for (i = 0; i < TVNORMS; i++)
- if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
- break;
- if (i == TVNORMS)
- i = 0;
- usbvision->tvnorm = &tvnorms[i]; /* set default norm */
+ usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
usbvision->ctl_input = 0;
/* This should be here to make i2c clients to be able to register */
- usbvision_audio_off(usbvision); //first switch off audio
+ /* first switch off audio */
+ usbvision_audio_off(usbvision);
if (!PowerOnAtOpen) {
- usbvision_power_on(usbvision); //and then power up the noisy tuner
+ /* and then power up the noisy tuner */
+ usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
}
}
@@ -1796,18 +1766,22 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
if (usbvision_device_data[model].Interface >= 0) {
interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
- }
- else {
+ } else {
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
}
endpoint = &interface->endpoint[1].desc;
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
- err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
- err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_ISOC) {
+ err("%s: interface %d. has non-ISO endpoint!",
+ __FUNCTION__, ifnum);
+ err("%s: Endpoint attributes %d",
+ __FUNCTION__, endpoint->bmAttributes);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
- err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+ USB_DIR_OUT) {
+ err("%s: interface %d. has ISO OUT endpoint!",
+ __FUNCTION__, ifnum);
return -ENODEV;
}
@@ -1818,11 +1792,9 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
if (dev->descriptor.bNumConfigurations > 1) {
usbvision->bridgeType = BRIDGE_NT1004;
- }
- else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
+ } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
usbvision->bridgeType = BRIDGE_NT1005;
- }
- else {
+ } else {
usbvision->bridgeType = BRIDGE_NT1003;
}
PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
@@ -1919,11 +1891,11 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
up(&usbvision->lock);
if (usbvision->user) {
- printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
+ printk(KERN_INFO "%s: In use, disconnect pending\n",
+ __FUNCTION__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
- }
- else {
+ } else {
usbvision_release(usbvision);
}
@@ -1950,7 +1922,6 @@ static int __init usbvision_init(void)
PDEBUG(DBG_PROBE, "");
- PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]");
PDEBUG(DBG_IO, "IO debugging is enabled [video]");
PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]");
PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index c759d00d7014..c5b6c501c869 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -221,6 +221,8 @@ enum {
#define I2C_USB_ADAP_MAX 16
+#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M)
+
/* ----------------------------------------------------------------- */
/* usbvision video structures */
/* ----------------------------------------------------------------- */
@@ -301,14 +303,6 @@ struct usbvision_frame_header {
__u16 frameHeight; /* 10 - 11 after endian correction*/
};
-/* tvnorms */
-struct usbvision_tvnorm {
- char *name;
- v4l2_std_id id;
- /* mode for saa7113h */
- int mode;
-};
-
struct usbvision_frame {
char *data; /* Frame buffer */
struct usbvision_frame_header isocHeader; /* Header from stream */
@@ -386,7 +380,6 @@ struct usb_usbvision {
int tuner_type;
int tuner_addr;
int bridgeType; // NT1003, NT1004, NT1005
- int channel;
int radio;
int video_inputs; // # of inputs
unsigned long freq;
@@ -441,7 +434,7 @@ struct usb_usbvision {
struct v4l2_capability vcap; /* Video capabilities */
unsigned int ctl_input; /* selected input */
- struct usbvision_tvnorm *tvnorm; /* selected tv norm */
+ v4l2_std_id tvnormId; /* selected tv norm */
unsigned char video_endp; /* 0x82 for USBVISION devices based */
// Decompression stuff:
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index ede8543818bf..9eac65f34bff 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -19,7 +19,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 13ee550d3215..c3440b280d20 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -65,11 +65,6 @@
#include <linux/kmod.h>
#endif
-#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE)
-#include <linux/ust.h>
-#endif
-
-
#include <linux/videodev.h>
MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr");
@@ -716,6 +711,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_LOUDNESS:
case V4L2_CID_MPEG_AUDIO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_MUTE:
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
case V4L2_CID_MPEG_VIDEO_PULLDOWN:
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
@@ -939,16 +935,25 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
When no more controls are available 0 is returned. */
u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
{
- u32 ctrl_class;
+ u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
const u32 *pctrl;
- /* if no query is desired, then just return the control ID */
- if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
- return id;
if (ctrl_classes == NULL)
return 0;
+
+ /* if no query is desired, then check if the ID is part of ctrl_classes */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+ /* find class */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find control ID */
+ while (*pctrl && *pctrl != id) pctrl++;
+ return *pctrl ? id : 0;
+ }
id &= V4L2_CTRL_ID_MASK;
- ctrl_class = V4L2_CTRL_ID2CLASS(id);
id++; /* select next control */
/* find first class that matches (or is greater than) the class of
the ID */
diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
new file mode 100644
index 000000000000..8b4ef530a3a8
--- /dev/null
+++ b/drivers/media/video/v4l2-int-device.c
@@ -0,0 +1,158 @@
+/*
+ * drivers/media/video/v4l2-int-device.c
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+
+#include <media/v4l2-int-device.h>
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(int_list);
+
+static void v4l2_int_device_try_attach_all(void)
+{
+ struct v4l2_int_device *m, *s;
+
+ list_for_each_entry(m, &int_list, head) {
+ if (m->type != v4l2_int_type_master)
+ continue;
+
+ list_for_each_entry(s, &int_list, head) {
+ if (s->type != v4l2_int_type_slave)
+ continue;
+
+ /* Slave is connected? */
+ if (s->u.slave->master)
+ continue;
+
+ /* Slave wants to attach to master? */
+ if (s->u.slave->attach_to[0] != 0
+ && strncmp(m->name, s->u.slave->attach_to,
+ V4L2NAMESIZE))
+ continue;
+
+ if (!try_module_get(m->module))
+ continue;
+
+ if (m->u.master->attach(m, s)) {
+ module_put(m->module);
+ continue;
+ }
+
+ s->u.slave->master = m;
+ }
+ }
+}
+
+static int ioctl_sort_cmp(const void *a, const void *b)
+{
+ const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
+
+ if (d1->num > d2->num)
+ return 1;
+
+ if (d1->num < d2->num)
+ return -1;
+
+ return 0;
+}
+
+int v4l2_int_device_register(struct v4l2_int_device *d)
+{
+ if (d->type == v4l2_int_type_slave)
+ sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
+ sizeof(struct v4l2_int_ioctl_desc),
+ &ioctl_sort_cmp, NULL);
+ mutex_lock(&mutex);
+ list_add(&d->head, &int_list);
+ v4l2_int_device_try_attach_all();
+ mutex_unlock(&mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_register);
+
+void v4l2_int_device_unregister(struct v4l2_int_device *d)
+{
+ mutex_lock(&mutex);
+ list_del(&d->head);
+ if (d->type == v4l2_int_type_slave
+ && d->u.slave->master != NULL) {
+ d->u.slave->master->u.master->detach(d);
+ module_put(d->u.slave->master->module);
+ d->u.slave->master = NULL;
+ }
+ mutex_unlock(&mutex);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
+
+/* Adapted from search_extable in extable.c. */
+static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
+ v4l2_int_ioctl_func *no_such_ioctl)
+{
+ const struct v4l2_int_ioctl_desc *first = slave->ioctls;
+ const struct v4l2_int_ioctl_desc *last =
+ first + slave->num_ioctls - 1;
+
+ while (first <= last) {
+ const struct v4l2_int_ioctl_desc *mid;
+
+ mid = (last - first) / 2 + first;
+
+ if (mid->num < cmd)
+ first = mid + 1;
+ else if (mid->num > cmd)
+ last = mid - 1;
+ else
+ return mid->func;
+ }
+
+ return no_such_ioctl;
+}
+
+static int no_such_ioctl_0(struct v4l2_int_device *d)
+{
+ return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
+{
+ return ((v4l2_int_ioctl_func_0 *)
+ find_ioctl(d->u.slave, cmd,
+ (v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
+}
+
+static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
+{
+ return ((v4l2_int_ioctl_func_1 *)
+ find_ioctl(d->u.slave, cmd,
+ (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
+}
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/videobuf-core.c
index a32dfbe0585a..c606332512b6 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/videobuf-core.c
@@ -1,313 +1,63 @@
/*
+ * generic helper functions for handling video4linux capture buffers
*
- * generic helper functions for video4linux capture buffers, to handle
- * memory management and PCI DMA.
- * Right now, bttv, saa7134, saa7146 and cx88 use it.
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
*
- * The functions expect the hardware being able to scatter gatter
- * (i.e. the buffers are not linear in physical memory, but fragmented
- * into PAGE_SIZE chunks). They also assume the driver does not need
- * to touch the video data.
- *
- * device specific map/unmap/sync stuff now are mapped as operations
- * to allow its usage by USB and virtual devices.
- *
- * (c) 2001-2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
- * (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Highly based on video-buf written originally by:
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
* (c) 2006 Ted Walther and John Sokol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; either version 2
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <media/video-buf.h>
+#include <media/videobuf-core.h>
-#define MAGIC_DMABUF 0x19721112
-#define MAGIC_BUFFER 0x20040302
+#define MAGIC_BUFFER 0x20070728
#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
static int debug = 0;
module_param(debug, int, 0644);
-MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_DESCRIPTION("helper module to manage video4linux buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "vbuf: " fmt , ## arg)
-struct scatterlist*
-videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
-{
- struct scatterlist *sglist;
- struct page *pg;
- int i;
-
- sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
- if (NULL == sglist)
- return NULL;
- for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
- pg = vmalloc_to_page(virt);
- if (NULL == pg)
- goto err;
- BUG_ON(PageHighMem(pg));
- sglist[i].page = pg;
- sglist[i].length = PAGE_SIZE;
- }
- return sglist;
-
- err:
- kfree(sglist);
- return NULL;
-}
-
-struct scatterlist*
-videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
-{
- struct scatterlist *sglist;
- int i = 0;
-
- if (NULL == pages[0])
- return NULL;
- sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
- if (NULL == sglist)
- return NULL;
-
- if (NULL == pages[0])
- goto nopage;
- if (PageHighMem(pages[0]))
- /* DMA to highmem pages might not work */
- goto highmem;
- sglist[0].page = pages[0];
- sglist[0].offset = offset;
- sglist[0].length = PAGE_SIZE - offset;
- for (i = 1; i < nr_pages; i++) {
- if (NULL == pages[i])
- goto nopage;
- if (PageHighMem(pages[i]))
- goto highmem;
- sglist[i].page = pages[i];
- sglist[i].length = PAGE_SIZE;
- }
- return sglist;
-
- nopage:
- dprintk(2,"sgl: oops - no page\n");
- kfree(sglist);
- return NULL;
-
- highmem:
- dprintk(2,"sgl: oops - highmem page\n");
- kfree(sglist);
- return NULL;
-}
-
/* --------------------------------------------------------------------- */
-void videobuf_dma_init(struct videobuf_dmabuf *dma)
-{
- memset(dma,0,sizeof(*dma));
- dma->magic = MAGIC_DMABUF;
-}
+#define CALL(q, f, arg...) \
+ ( (q->int_ops->f)? q->int_ops->f(arg) : 0)
-int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
- unsigned long data, unsigned long size)
+void* videobuf_alloc(struct videobuf_queue* q)
{
- unsigned long first,last;
- int err, rw = 0;
-
- dma->direction = direction;
- switch (dma->direction) {
- case PCI_DMA_FROMDEVICE: rw = READ; break;
- case PCI_DMA_TODEVICE: rw = WRITE; break;
- default: BUG();
- }
-
- first = (data & PAGE_MASK) >> PAGE_SHIFT;
- last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
- dma->offset = data & ~PAGE_MASK;
- dma->nr_pages = last-first+1;
- dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
- GFP_KERNEL);
- if (NULL == dma->pages)
- return -ENOMEM;
- dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
- data,size,dma->nr_pages);
-
- dma->varea = (void *) data;
-
- down_read(&current->mm->mmap_sem);
- err = get_user_pages(current,current->mm,
- data & PAGE_MASK, dma->nr_pages,
- rw == READ, 1, /* force */
- dma->pages, NULL);
- up_read(&current->mm->mmap_sem);
- if (err != dma->nr_pages) {
- dma->nr_pages = (err >= 0) ? err : 0;
- dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
- return err < 0 ? err : -EINVAL;
- }
- return 0;
-}
-
-int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
- int nr_pages)
-{
- dprintk(1,"init kernel [%d pages]\n",nr_pages);
- dma->direction = direction;
- dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
- if (NULL == dma->vmalloc) {
- dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
- return -ENOMEM;
- }
- dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)dma->vmalloc,
- nr_pages << PAGE_SHIFT);
- memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
- dma->nr_pages = nr_pages;
- return 0;
-}
-
-int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
- dma_addr_t addr, int nr_pages)
-{
- dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
- nr_pages,(unsigned long)addr);
- dma->direction = direction;
- if (0 == addr)
- return -EINVAL;
-
- dma->bus_addr = addr;
- dma->nr_pages = nr_pages;
- return 0;
-}
-
-int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(0 == dma->nr_pages);
-
- if (dma->pages) {
- dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
- dma->offset);
- }
- if (dma->vmalloc) {
- dma->sglist = videobuf_vmalloc_to_sg
- (dma->vmalloc,dma->nr_pages);
- }
- if (dma->bus_addr) {
- dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
- if (NULL != dma->sglist) {
- dma->sglen = 1;
- sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
- dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
- sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
- }
- }
- if (NULL == dma->sglist) {
- dprintk(1,"scatterlist is NULL\n");
- return -ENOMEM;
- }
- if (!dma->bus_addr) {
- if (q->ops->vb_map_sg) {
- dma->sglen = q->ops->vb_map_sg(dev,dma->sglist,
- dma->nr_pages, dma->direction);
- }
- if (0 == dma->sglen) {
- printk(KERN_WARNING
- "%s: videobuf_map_sg failed\n",__FUNCTION__);
- kfree(dma->sglist);
- dma->sglist = NULL;
- dma->sglen = 0;
- return -EIO;
- }
- }
- return 0;
-}
-
-int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(!dma->sglen);
-
- if (!dma->bus_addr && q->ops->vb_dma_sync_sg)
- q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages,
- dma->direction);
-
- return 0;
-}
-
-int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- if (!dma->sglen)
- return 0;
-
- if (!dma->bus_addr && q->ops->vb_unmap_sg)
- q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages,
- dma->direction);
- kfree(dma->sglist);
- dma->sglist = NULL;
- dma->sglen = 0;
- return 0;
-}
-
-int videobuf_dma_free(struct videobuf_dmabuf *dma)
-{
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(dma->sglen);
-
- if (dma->pages) {
- int i;
- for (i=0; i < dma->nr_pages; i++)
- page_cache_release(dma->pages[i]);
- kfree(dma->pages);
- dma->pages = NULL;
- }
+ struct videobuf_buffer *vb;
- vfree(dma->vmalloc);
- dma->vmalloc = NULL;
- dma->varea = NULL;
+ BUG_ON (q->msize<sizeof(*vb));
- if (dma->bus_addr) {
- dma->bus_addr = 0;
+ if (!q->int_ops || !q->int_ops->alloc) {
+ printk(KERN_ERR "No specific ops defined!\n");
+ BUG();
}
- dma->direction = PCI_DMA_NONE;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-void* videobuf_alloc(unsigned int size)
-{
- struct videobuf_buffer *vb;
+ vb = q->int_ops->alloc(q->msize);
- vb = kzalloc(size,GFP_KERNEL);
if (NULL != vb) {
- videobuf_dma_init(&vb->dma);
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
}
+
return vb;
}
@@ -338,127 +88,65 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
return retval;
}
-int
-videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
- struct v4l2_framebuffer *fbuf)
+int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
+ struct v4l2_framebuffer *fbuf)
{
- int err,pages;
- dma_addr_t bus;
-
MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
- switch (vb->memory) {
- case V4L2_MEMORY_MMAP:
- case V4L2_MEMORY_USERPTR:
- if (0 == vb->baddr) {
- /* no userspace addr -- kernel bounce buffer */
- pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
- err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE,
- pages);
- if (0 != err)
- return err;
- } else {
- /* dma directly to userspace */
- err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE,
- vb->baddr,vb->bsize);
- if (0 != err)
- return err;
- }
- break;
- case V4L2_MEMORY_OVERLAY:
- if (NULL == fbuf)
- return -EINVAL;
- /* FIXME: need sanity checks for vb->boff */
- /*
- * Using a double cast to avoid compiler warnings when
- * building for PAE. Compiler doesn't like direct casting
- * of a 32 bit ptr to 64 bit integer.
- */
- bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
- pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
- err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE,
- bus, pages);
- if (0 != err)
- return err;
- break;
- default:
- BUG();
- }
- err = videobuf_dma_map(q,&vb->dma);
- if (0 != err)
- return err;
-
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-void videobuf_queue_pci(struct videobuf_queue* q)
-{
- /* If not specified, defaults to PCI map sg */
- if (!q->ops->vb_map_sg)
- q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg;
-
- if (!q->ops->vb_dma_sync_sg)
- q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu;
- if (!q->ops->vb_unmap_sg)
- q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
-}
-
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
- struct videobuf_queue_ops qops;
+ /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
+ method should be called before _iolock.
+ On some cases, the mmap_mapper() is called only after scheduling.
- q.dev=pci;
- qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
- qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
- q.ops = &qops;
+ However, this way is just too dirty! Better to wait for some event.
+ */
+ schedule_timeout(HZ);
- return (videobuf_dma_map(&q,dma));
+ return CALL(q,iolock,q,vb,fbuf);
}
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
- struct videobuf_queue_ops qops;
-
- q.dev=pci;
- qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
- qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
- q.ops = &qops;
+/* --------------------------------------------------------------------- */
- return (videobuf_dma_unmap(&q,dma));
-}
-void videobuf_queue_init(struct videobuf_queue* q,
+void videobuf_queue_core_init(struct videobuf_queue* q,
struct videobuf_queue_ops *ops,
void *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize,
- void *priv)
+ void *priv,
+ struct videobuf_qtype_ops *int_ops)
{
memset(q,0,sizeof(*q));
- q->irqlock = irqlock;
- q->dev = dev;
- q->type = type;
- q->field = field;
- q->msize = msize;
- q->ops = ops;
+ q->irqlock = irqlock;
+ q->dev = dev;
+ q->type = type;
+ q->field = field;
+ q->msize = msize;
+ q->ops = ops;
q->priv_data = priv;
+ q->int_ops = int_ops;
- videobuf_queue_pci(q);
+ /* All buffer operations are mandatory */
+ BUG_ON (!q->ops->buf_setup);
+ BUG_ON (!q->ops->buf_prepare);
+ BUG_ON (!q->ops->buf_queue);
+ BUG_ON (!q->ops->buf_release);
+
+ /* Having implementations for abstract methods are mandatory */
+ BUG_ON (!q->int_ops);
mutex_init(&q->lock);
INIT_LIST_HEAD(&q->stream);
}
-int
-videobuf_queue_is_busy(struct videobuf_queue *q)
+int videobuf_queue_is_busy(struct videobuf_queue *q)
{
int i;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
if (q->streaming) {
dprintk(1,"busy: streaming active\n");
return 1;
@@ -490,8 +178,7 @@ videobuf_queue_is_busy(struct videobuf_queue *q)
return 0;
}
-void
-videobuf_queue_cancel(struct videobuf_queue *q)
+void videobuf_queue_cancel(struct videobuf_queue *q)
{
unsigned long flags=0;
int i;
@@ -521,8 +208,7 @@ videobuf_queue_cancel(struct videobuf_queue *q)
/* --------------------------------------------------------------------- */
-enum v4l2_field
-videobuf_next_field(struct videobuf_queue *q)
+enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
{
enum v4l2_field field = q->field;
@@ -540,11 +226,11 @@ videobuf_next_field(struct videobuf_queue *q)
return field;
}
-void
-videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
- enum v4l2_buf_type type)
+static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
+ struct videobuf_buffer *vb, enum v4l2_buf_type type)
{
MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
b->index = vb->i;
b->type = type;
@@ -595,8 +281,7 @@ videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
b->sequence = vb->field_count >> 1;
}
-int
-videobuf_reqbufs(struct videobuf_queue *q,
+int videobuf_reqbufs(struct videobuf_queue *q,
struct v4l2_requestbuffers *req)
{
unsigned int size,count;
@@ -617,16 +302,18 @@ videobuf_reqbufs(struct videobuf_queue *q,
return -EINVAL;
}
+ mutex_lock(&q->lock);
if (q->streaming) {
dprintk(1,"reqbufs: streaming already exists\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto done;
}
if (!list_empty(&q->stream)) {
dprintk(1,"reqbufs: stream running\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto done;
}
- mutex_lock(&q->lock);
count = req->count;
if (count > VIDEO_MAX_FRAME)
count = VIDEO_MAX_FRAME;
@@ -642,15 +329,14 @@ videobuf_reqbufs(struct videobuf_queue *q,
goto done;
}
- req->count = count;
+ req->count = retval;
done:
mutex_unlock(&q->lock);
return retval;
}
-int
-videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
+int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
if (unlikely(b->type != q->type)) {
dprintk(1,"querybuf: Wrong type.\n");
@@ -664,12 +350,11 @@ videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
dprintk(1,"querybuf: buffer is null.\n");
return -EINVAL;
}
- videobuf_status(b,q->bufs[b->index],q->type);
+ videobuf_status(q,b,q->bufs[b->index],q->type);
return 0;
}
-int
-videobuf_qbuf(struct videobuf_queue *q,
+int videobuf_qbuf(struct videobuf_queue *q,
struct v4l2_buffer *b)
{
struct videobuf_buffer *buf;
@@ -677,6 +362,11 @@ videobuf_qbuf(struct videobuf_queue *q,
unsigned long flags=0;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+ if (b->memory == V4L2_MEMORY_MMAP)
+ down_read(&current->mm->mmap_sem);
+
mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading) {
@@ -762,16 +452,21 @@ videobuf_qbuf(struct videobuf_queue *q,
done:
mutex_unlock(&q->lock);
+
+ if (b->memory == V4L2_MEMORY_MMAP)
+ up_read(&current->mm->mmap_sem);
+
return retval;
}
-int
-videobuf_dqbuf(struct videobuf_queue *q,
+int videobuf_dqbuf(struct videobuf_queue *q,
struct v4l2_buffer *b, int nonblocking)
{
struct videobuf_buffer *buf;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading) {
@@ -797,12 +492,12 @@ videobuf_dqbuf(struct videobuf_queue *q,
case STATE_ERROR:
dprintk(1,"dqbuf: state is error\n");
retval = -EIO;
- videobuf_dma_sync(q,&buf->dma);
+ CALL(q,sync,q, buf);
buf->state = STATE_IDLE;
break;
case STATE_DONE:
dprintk(1,"dqbuf: state is done\n");
- videobuf_dma_sync(q,&buf->dma);
+ CALL(q,sync,q, buf);
buf->state = STATE_IDLE;
break;
default:
@@ -812,7 +507,7 @@ videobuf_dqbuf(struct videobuf_queue *q,
}
list_del(&buf->stream);
memset(b,0,sizeof(*b));
- videobuf_status(b,buf,q->type);
+ videobuf_status(q,b,buf,q->type);
done:
mutex_unlock(&q->lock);
@@ -822,7 +517,6 @@ videobuf_dqbuf(struct videobuf_queue *q,
int videobuf_streamon(struct videobuf_queue *q)
{
struct videobuf_buffer *buf;
- struct list_head *list;
unsigned long flags=0;
int retval;
@@ -836,11 +530,9 @@ int videobuf_streamon(struct videobuf_queue *q)
q->streaming = 1;
if (q->irqlock)
spin_lock_irqsave(q->irqlock,flags);
- list_for_each(list,&q->stream) {
- buf = list_entry(list, struct videobuf_buffer, stream);
+ list_for_each_entry(buf, &q->stream, stream)
if (buf->state == STATE_PREPARED)
q->ops->buf_queue(q,buf);
- }
if (q->irqlock)
spin_unlock_irqrestore(q->irqlock,flags);
@@ -865,22 +557,25 @@ int videobuf_streamoff(struct videobuf_queue *q)
return retval;
}
-static ssize_t
-videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
- size_t count, loff_t *ppos)
+static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+ char __user *data,
+ size_t count, loff_t *ppos)
{
enum v4l2_field field;
unsigned long flags=0;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
/* setup stuff */
- q->read_buf = videobuf_alloc(q->msize);
+ q->read_buf = videobuf_alloc(q);
if (NULL == q->read_buf)
return -ENOMEM;
q->read_buf->memory = V4L2_MEMORY_USERPTR;
q->read_buf->baddr = (unsigned long)data;
q->read_buf->bsize = count;
+
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q,q->read_buf,field);
if (0 != retval)
@@ -894,7 +589,7 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
spin_unlock_irqrestore(q->irqlock,flags);
retval = videobuf_waiton(q->read_buf,0,0);
if (0 == retval) {
- videobuf_dma_sync(q,&q->read_buf->dma);
+ CALL(q,sync,q,q->read_buf);
if (STATE_ERROR == q->read_buf->state)
retval = -EIO;
else
@@ -915,13 +610,16 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
{
enum v4l2_field field;
unsigned long flags=0;
- unsigned size, nbufs, bytes;
+ unsigned size, nbufs;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
mutex_lock(&q->lock);
nbufs = 1; size = 0;
q->ops->buf_setup(q,&nbufs,&size);
+
if (NULL == q->read_buf &&
count >= size &&
!nonblocking) {
@@ -935,7 +633,8 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
if (NULL == q->read_buf) {
/* need to capture a new frame */
retval = -ENOMEM;
- q->read_buf = videobuf_alloc(q->msize);
+ q->read_buf = videobuf_alloc(q);
+
dprintk(1,"video alloc=0x%p\n", q->read_buf);
if (NULL == q->read_buf)
goto done;
@@ -943,6 +642,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
q->read_buf->bsize = count; /* preferred size */
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q,q->read_buf,field);
+
if (0 != retval) {
kfree (q->read_buf);
q->read_buf = NULL;
@@ -950,6 +650,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
if (q->irqlock)
spin_lock_irqsave(q->irqlock,flags);
+
q->ops->buf_queue(q,q->read_buf);
if (q->irqlock)
spin_unlock_irqrestore(q->irqlock,flags);
@@ -960,7 +661,8 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
retval = videobuf_waiton(q->read_buf, nonblocking, 1);
if (0 != retval)
goto done;
- videobuf_dma_sync(q,&q->read_buf->dma);
+
+ CALL(q,sync,q,q->read_buf);
if (STATE_ERROR == q->read_buf->state) {
/* catch I/O errors */
@@ -971,16 +673,12 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
goto done;
}
- /* copy to userspace */
- bytes = count;
- if (bytes > q->read_buf->size - q->read_off)
- bytes = q->read_buf->size - q->read_off;
- retval = -EFAULT;
- if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes))
+ /* Copy to userspace */
+ retval=CALL(q,copy_to_user,q,data,count,nonblocking);
+ if (retval<0)
goto done;
- retval = bytes;
- q->read_off += bytes;
+ q->read_off += retval;
if (q->read_off == q->read_buf->size) {
/* all data copied, cleanup */
q->ops->buf_release(q,q->read_buf);
@@ -997,7 +695,7 @@ int videobuf_read_start(struct videobuf_queue *q)
{
enum v4l2_field field;
unsigned long flags=0;
- int count = 0, size = 0;
+ unsigned int count = 0, size = 0;
int err, i;
q->ops->buf_setup(q,&count,&size);
@@ -1008,8 +706,11 @@ int videobuf_read_start(struct videobuf_queue *q)
size = PAGE_ALIGN(size);
err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
- if (err)
+ if (err < 0)
return err;
+
+ count = err;
+
for (i = 0; i < count; i++) {
field = videobuf_next_field(q);
err = q->ops->buf_prepare(q,q->bufs[i],field);
@@ -1048,10 +749,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
char __user *data, size_t count, loff_t *ppos,
int vbihack, int nonblocking)
{
- unsigned int *fc, bytes;
- int err, retval;
+ int rc, retval;
unsigned long flags=0;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
dprintk(2,"%s\n",__FUNCTION__);
mutex_lock(&q->lock);
retval = -EBUSY;
@@ -1073,39 +775,23 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
list_del(&q->read_buf->stream);
q->read_off = 0;
}
- err = videobuf_waiton(q->read_buf, nonblocking, 1);
- if (err < 0) {
+ rc = videobuf_waiton(q->read_buf, nonblocking, 1);
+ if (rc < 0) {
if (0 == retval)
- retval = err;
+ retval = rc;
break;
}
if (q->read_buf->state == STATE_DONE) {
- if (vbihack) {
- /* dirty, undocumented hack -- pass the frame counter
- * within the last four bytes of each vbi data block.
- * We need that one to maintain backward compatibility
- * to all vbi decoding software out there ... */
- fc = (unsigned int*)q->read_buf->dma.vmalloc;
- fc += (q->read_buf->size>>2) -1;
- *fc = q->read_buf->field_count >> 1;
- dprintk(1,"vbihack: %d\n",*fc);
- }
-
- /* copy stuff */
- bytes = count;
- if (bytes > q->read_buf->size - q->read_off)
- bytes = q->read_buf->size - q->read_off;
- if (copy_to_user(data + retval,
- q->read_buf->dma.vmalloc + q->read_off,
- bytes)) {
- if (0 == retval)
- retval = -EFAULT;
+ rc = CALL (q,copy_stream, q, data + retval, count,
+ retval, vbihack, nonblocking);
+ if (rc < 0) {
+ retval = rc;
break;
}
- count -= bytes;
- retval += bytes;
- q->read_off += bytes;
+ retval += rc;
+ count -= rc;
+ q->read_off += rc;
} else {
/* some error */
q->read_off = q->read_buf->size;
@@ -1172,81 +858,6 @@ unsigned int videobuf_poll_stream(struct file *file,
return rc;
}
-/* --------------------------------------------------------------------- */
-
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
-{
- struct videobuf_mapping *map = vma->vm_private_data;
-
- dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
- map->count,vma->vm_start,vma->vm_end);
- map->count++;
-}
-
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
-{
- struct videobuf_mapping *map = vma->vm_private_data;
- struct videobuf_queue *q = map->q;
- int i;
-
- dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
- map->count,vma->vm_start,vma->vm_end);
-
- map->count--;
- if (0 == map->count) {
- dprintk(1,"munmap %p q=%p\n",map,q);
- mutex_lock(&q->lock);
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == q->bufs[i])
- continue;
- if (q->bufs[i])
- ;
- if (q->bufs[i]->map != map)
- continue;
- q->bufs[i]->map = NULL;
- q->bufs[i]->baddr = 0;
- q->ops->buf_release(q,q->bufs[i]);
- }
- mutex_unlock(&q->lock);
- kfree(map);
- }
- return;
-}
-
-/*
- * Get a anonymous page for the mapping. Make sure we can DMA to that
- * memory location with 32bit PCI devices (i.e. don't use highmem for
- * now ...). Bounce buffers don't work very well for the data rates
- * video capture has.
- */
-static struct page*
-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
- int *type)
-{
- struct page *page;
-
- dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
- vaddr,vma->vm_start,vma->vm_end);
- if (vaddr > vma->vm_end)
- return NOPAGE_SIGBUS;
- page = alloc_page(GFP_USER | __GFP_DMA32);
- if (!page)
- return NOPAGE_OOM;
- clear_user_page(page_address(page), vaddr, page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
-}
-
-static struct vm_operations_struct videobuf_vm_ops =
-{
- .open = videobuf_vm_open,
- .close = videobuf_vm_close,
- .nopage = videobuf_vm_nopage,
-};
-
int videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int bcount, unsigned int bsize,
enum v4l2_memory memory)
@@ -1254,12 +865,19 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int i;
int err;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
err = videobuf_mmap_free(q);
if (0 != err)
return err;
+ /* Allocate and initialize buffers */
for (i = 0; i < bcount; i++) {
- q->bufs[i] = videobuf_alloc(q->msize);
+ q->bufs[i] = videobuf_alloc(q);
+
+ if (q->bufs[i] == NULL)
+ break;
+
q->bufs[i]->i = i;
q->bufs[i]->input = UNSET;
q->bufs[i]->memory = memory;
@@ -1274,18 +892,30 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
break;
}
}
+
+ if (!i)
+ return -ENOMEM;
+
dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
- bcount,bsize);
- return 0;
+ i, bsize);
+
+ return i;
}
int videobuf_mmap_free(struct videobuf_queue *q)
{
int i;
+ int rc;
+
+ if (!q)
+ return 0;
+
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+ rc = CALL(q,mmap_free,q);
+ if (rc<0)
+ return rc;
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
- if (q->bufs[i] && q->bufs[i]->map)
- return -EBUSY;
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -1293,118 +923,69 @@ int videobuf_mmap_free(struct videobuf_queue *q)
kfree(q->bufs[i]);
q->bufs[i] = NULL;
}
- return 0;
+
+ return rc;
}
int videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma)
{
- struct videobuf_mapping *map;
- unsigned int first,last,size,i;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
mutex_lock(&q->lock);
- retval = -EINVAL;
- if (!(vma->vm_flags & VM_WRITE)) {
- dprintk(1,"mmap app bug: PROT_WRITE please\n");
- goto done;
- }
- if (!(vma->vm_flags & VM_SHARED)) {
- dprintk(1,"mmap app bug: MAP_SHARED please\n");
- goto done;
- }
+ retval=CALL(q,mmap_mapper,q,vma);
+ mutex_unlock(&q->lock);
- /* look for first buffer to map */
- for (first = 0; first < VIDEO_MAX_FRAME; first++) {
- if (NULL == q->bufs[first])
- continue;
- if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
- continue;
- if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
- break;
- }
- if (VIDEO_MAX_FRAME == first) {
- dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
- (vma->vm_pgoff << PAGE_SHIFT));
- goto done;
- }
+ return retval;
+}
- /* look for last buffer to map */
- for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
- if (NULL == q->bufs[last])
- continue;
- if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
- continue;
- if (q->bufs[last]->map) {
- retval = -EBUSY;
- goto done;
- }
- size += q->bufs[last]->bsize;
- if (size == (vma->vm_end - vma->vm_start))
- break;
- }
- if (VIDEO_MAX_FRAME == last) {
- dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
- (vma->vm_end - vma->vm_start));
- goto done;
- }
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int videobuf_cgmbuf(struct videobuf_queue *q,
+ struct video_mbuf *mbuf, int count)
+{
+ struct v4l2_requestbuffers req;
+ int rc,i;
- /* create mapping + update buffer list */
- retval = -ENOMEM;
- map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
- if (NULL == map)
- goto done;
- for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
- q->bufs[i]->map = map;
- q->bufs[i]->baddr = vma->vm_start + size;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+ memset(&req,0,sizeof(req));
+ req.type = q->type;
+ req.count = count;
+ req.memory = V4L2_MEMORY_MMAP;
+ rc = videobuf_reqbufs(q,&req);
+ if (rc < 0)
+ return rc;
+
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
- map->count = 1;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
- map->q = q;
- vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
- vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
- vma->vm_private_data = map;
- dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
- map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
- retval = 0;
- done:
- mutex_unlock(&q->lock);
- return retval;
+ return 0;
}
+#endif
/* --------------------------------------------------------------------- */
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-
-EXPORT_SYMBOL_GPL(videobuf_dma_init);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-EXPORT_SYMBOL_GPL(videobuf_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_dma_sync);
-EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_dma_free);
-
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
-
-EXPORT_SYMBOL_GPL(videobuf_alloc);
EXPORT_SYMBOL_GPL(videobuf_waiton);
EXPORT_SYMBOL_GPL(videobuf_iolock);
-EXPORT_SYMBOL_GPL(videobuf_queue_init);
+EXPORT_SYMBOL_GPL(videobuf_alloc);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_core_init);
EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
EXPORT_SYMBOL_GPL(videobuf_next_field);
-EXPORT_SYMBOL_GPL(videobuf_status);
EXPORT_SYMBOL_GPL(videobuf_reqbufs);
EXPORT_SYMBOL_GPL(videobuf_querybuf);
EXPORT_SYMBOL_GPL(videobuf_qbuf);
EXPORT_SYMBOL_GPL(videobuf_dqbuf);
+EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
EXPORT_SYMBOL_GPL(videobuf_streamon);
EXPORT_SYMBOL_GPL(videobuf_streamoff);
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
new file mode 100644
index 000000000000..8bb7fdd306d6
--- /dev/null
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -0,0 +1,726 @@
+/*
+ * helper functions for PCI DMA video4linux capture buffers
+ *
+ * The functions expect the hardware being able to scatter gatter
+ * (i.e. the buffers are not linear in physical memory, but fragmented
+ * into PAGE_SIZE chunks). They also assume the driver does not need
+ * to touch the video data.
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * Highly based on video-buf written originally by:
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ * (c) 2006 Ted Walther and John Sokol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <media/videobuf-dma-sg.h>
+
+#define MAGIC_DMABUF 0x19721112
+#define MAGIC_SG_MEM 0x17890714
+
+#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
+ { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+
+/* --------------------------------------------------------------------- */
+
+struct scatterlist*
+videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+{
+ struct scatterlist *sglist;
+ struct page *pg;
+ int i;
+
+ sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+ for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
+ pg = vmalloc_to_page(virt);
+ if (NULL == pg)
+ goto err;
+ BUG_ON(PageHighMem(pg));
+ sglist[i].page = pg;
+ sglist[i].length = PAGE_SIZE;
+ }
+ return sglist;
+
+ err:
+ kfree(sglist);
+ return NULL;
+}
+
+struct scatterlist*
+videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
+{
+ struct scatterlist *sglist;
+ int i = 0;
+
+ if (NULL == pages[0])
+ return NULL;
+ sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+
+ if (NULL == pages[0])
+ goto nopage;
+ if (PageHighMem(pages[0]))
+ /* DMA to highmem pages might not work */
+ goto highmem;
+ sglist[0].page = pages[0];
+ sglist[0].offset = offset;
+ sglist[0].length = PAGE_SIZE - offset;
+ for (i = 1; i < nr_pages; i++) {
+ if (NULL == pages[i])
+ goto nopage;
+ if (PageHighMem(pages[i]))
+ goto highmem;
+ sglist[i].page = pages[i];
+ sglist[i].length = PAGE_SIZE;
+ }
+ return sglist;
+
+ nopage:
+ dprintk(2,"sgl: oops - no page\n");
+ kfree(sglist);
+ return NULL;
+
+ highmem:
+ dprintk(2,"sgl: oops - highmem page\n");
+ kfree(sglist);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
+{
+ struct videbuf_pci_sg_memory *mem=buf->priv;
+ BUG_ON (!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ return &mem->dma;
+}
+
+void videobuf_dma_init(struct videobuf_dmabuf *dma)
+{
+ memset(dma,0,sizeof(*dma));
+ dma->magic = MAGIC_DMABUF;
+}
+
+static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
+ int direction, unsigned long data, unsigned long size)
+{
+ unsigned long first,last;
+ int err, rw = 0;
+
+ dma->direction = direction;
+ switch (dma->direction) {
+ case PCI_DMA_FROMDEVICE: rw = READ; break;
+ case PCI_DMA_TODEVICE: rw = WRITE; break;
+ default: BUG();
+ }
+
+ first = (data & PAGE_MASK) >> PAGE_SHIFT;
+ last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
+ dma->offset = data & ~PAGE_MASK;
+ dma->nr_pages = last-first+1;
+ dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
+ GFP_KERNEL);
+ if (NULL == dma->pages)
+ return -ENOMEM;
+ dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
+ data,size,dma->nr_pages);
+
+ dma->varea = (void *) data;
+
+
+ err = get_user_pages(current,current->mm,
+ data & PAGE_MASK, dma->nr_pages,
+ rw == READ, 1, /* force */
+ dma->pages, NULL);
+
+ if (err != dma->nr_pages) {
+ dma->nr_pages = (err >= 0) ? err : 0;
+ dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
+ return err < 0 ? err : -EINVAL;
+ }
+ return 0;
+}
+
+int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
+ unsigned long data, unsigned long size)
+{
+ int ret;
+ down_read(&current->mm->mmap_sem);
+ ret = videobuf_dma_init_user_locked(dma, direction, data, size);
+ up_read(&current->mm->mmap_sem);
+
+ return ret;
+}
+
+int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
+ int nr_pages)
+{
+ dprintk(1,"init kernel [%d pages]\n",nr_pages);
+ dma->direction = direction;
+ dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == dma->vmalloc) {
+ dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
+ return -ENOMEM;
+ }
+ dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)dma->vmalloc,
+ nr_pages << PAGE_SHIFT);
+ memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
+ dma->nr_pages = nr_pages;
+ return 0;
+}
+
+int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
+ dma_addr_t addr, int nr_pages)
+{
+ dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
+ nr_pages,(unsigned long)addr);
+ dma->direction = direction;
+ if (0 == addr)
+ return -EINVAL;
+
+ dma->bus_addr = addr;
+ dma->nr_pages = nr_pages;
+ return 0;
+}
+
+int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+{
+ void *dev=q->dev;
+
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ BUG_ON(0 == dma->nr_pages);
+
+ if (dma->pages) {
+ dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
+ dma->offset);
+ }
+ if (dma->vmalloc) {
+ dma->sglist = videobuf_vmalloc_to_sg
+ (dma->vmalloc,dma->nr_pages);
+ }
+ if (dma->bus_addr) {
+ dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+ if (NULL != dma->sglist) {
+ dma->sglen = 1;
+ sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
+ dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
+ sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
+ }
+ }
+ if (NULL == dma->sglist) {
+ dprintk(1,"scatterlist is NULL\n");
+ return -ENOMEM;
+ }
+ if (!dma->bus_addr) {
+ dma->sglen = pci_map_sg(dev,dma->sglist,
+ dma->nr_pages, dma->direction);
+ if (0 == dma->sglen) {
+ printk(KERN_WARNING
+ "%s: videobuf_map_sg failed\n",__FUNCTION__);
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma)
+{
+ void *dev=q->dev;
+
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ BUG_ON(!dma->sglen);
+
+ pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction);
+ return 0;
+}
+
+int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+{
+ void *dev=q->dev;
+
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ if (!dma->sglen)
+ return 0;
+
+ pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction);
+
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ return 0;
+}
+
+int videobuf_dma_free(struct videobuf_dmabuf *dma)
+{
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ BUG_ON(dma->sglen);
+
+ if (dma->pages) {
+ int i;
+ for (i=0; i < dma->nr_pages; i++)
+ page_cache_release(dma->pages[i]);
+ kfree(dma->pages);
+ dma->pages = NULL;
+ }
+
+ vfree(dma->vmalloc);
+ dma->vmalloc = NULL;
+ dma->varea = NULL;
+
+ if (dma->bus_addr) {
+ dma->bus_addr = 0;
+ }
+ dma->direction = PCI_DMA_NONE;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+ struct videobuf_queue q;
+
+ q.dev=pci;
+
+ return (videobuf_dma_map(&q,dma));
+}
+
+int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+ struct videobuf_queue q;
+
+ q.dev=pci;
+
+ return (videobuf_dma_unmap(&q,dma));
+}
+
+/* --------------------------------------------------------------------- */
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+
+ dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+ map->count++;
+}
+
+static void
+videobuf_vm_close(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
+ struct videbuf_pci_sg_memory *mem;
+ int i;
+
+ dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+
+ map->count--;
+ if (0 == map->count) {
+ dprintk(1,"munmap %p q=%p\n",map,q);
+ mutex_lock(&q->lock);
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ mem=q->bufs[i]->priv;
+
+ if (!mem)
+ continue;
+
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ if (q->bufs[i]->map != map)
+ continue;
+ q->bufs[i]->map = NULL;
+ q->bufs[i]->baddr = 0;
+ q->ops->buf_release(q,q->bufs[i]);
+ }
+ mutex_unlock(&q->lock);
+ kfree(map);
+ }
+ return;
+}
+
+/*
+ * Get a anonymous page for the mapping. Make sure we can DMA to that
+ * memory location with 32bit PCI devices (i.e. don't use highmem for
+ * now ...). Bounce buffers don't work very well for the data rates
+ * video capture has.
+ */
+static struct page*
+videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
+ int *type)
+{
+ struct page *page;
+
+ dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
+ vaddr,vma->vm_start,vma->vm_end);
+ if (vaddr > vma->vm_end)
+ return NOPAGE_SIGBUS;
+ page = alloc_page(GFP_USER | __GFP_DMA32);
+ if (!page)
+ return NOPAGE_OOM;
+ clear_user_page(page_address(page), vaddr, page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return page;
+}
+
+static struct vm_operations_struct videobuf_vm_ops =
+{
+ .open = videobuf_vm_open,
+ .close = videobuf_vm_close,
+ .nopage = videobuf_vm_nopage,
+};
+
+/* ---------------------------------------------------------------------
+ * PCI handlers for the generic methods
+ */
+
+/* Allocated area consists on 3 parts:
+ struct video_buffer
+ struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
+ struct videobuf_pci_sg_memory
+ */
+
+static void *__videobuf_alloc(size_t size)
+{
+ struct videbuf_pci_sg_memory *mem;
+ struct videobuf_buffer *vb;
+
+ vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+
+ mem = vb->priv = ((char *)vb)+size;
+ mem->magic=MAGIC_SG_MEM;
+
+ videobuf_dma_init(&mem->dma);
+
+ dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+ __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ mem,(long)sizeof(*mem));
+
+ return vb;
+}
+
+static int __videobuf_iolock (struct videobuf_queue* q,
+ struct videobuf_buffer *vb,
+ struct v4l2_framebuffer *fbuf)
+{
+ int err,pages;
+ dma_addr_t bus;
+ struct videbuf_pci_sg_memory *mem=vb->priv;
+ BUG_ON(!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ switch (vb->memory) {
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_USERPTR:
+ if (0 == vb->baddr) {
+ /* no userspace addr -- kernel bounce buffer */
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ err = videobuf_dma_init_kernel( &mem->dma,
+ PCI_DMA_FROMDEVICE,
+ pages );
+ if (0 != err)
+ return err;
+ } else if (vb->memory == V4L2_MEMORY_USERPTR) {
+ /* dma directly to userspace */
+ err = videobuf_dma_init_user( &mem->dma,
+ PCI_DMA_FROMDEVICE,
+ vb->baddr,vb->bsize );
+ if (0 != err)
+ return err;
+ } else {
+ /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP
+ buffers can only be called from videobuf_qbuf
+ we take current->mm->mmap_sem there, to prevent
+ locking inversion, so don't take it here */
+
+ err = videobuf_dma_init_user_locked(&mem->dma,
+ PCI_DMA_FROMDEVICE,
+ vb->baddr, vb->bsize);
+ if (0 != err)
+ return err;
+ }
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ if (NULL == fbuf)
+ return -EINVAL;
+ /* FIXME: need sanity checks for vb->boff */
+ /*
+ * Using a double cast to avoid compiler warnings when
+ * building for PAE. Compiler doesn't like direct casting
+ * of a 32 bit ptr to 64 bit integer.
+ */
+ bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE,
+ bus, pages);
+ if (0 != err)
+ return err;
+ break;
+ default:
+ BUG();
+ }
+ err = videobuf_dma_map(q,&mem->dma);
+ if (0 != err)
+ return err;
+
+ return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
+{
+ struct videbuf_pci_sg_memory *mem=buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ return videobuf_dma_sync(q,&mem->dma);
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+ int i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (q->bufs[i]) {
+ if (q->bufs[i]->map)
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+ struct vm_area_struct *vma)
+{
+ struct videbuf_pci_sg_memory *mem;
+ struct videobuf_mapping *map;
+ unsigned int first,last,size,i;
+ int retval;
+
+ retval = -EINVAL;
+ if (!(vma->vm_flags & VM_WRITE)) {
+ dprintk(1,"mmap app bug: PROT_WRITE please\n");
+ goto done;
+ }
+ if (!(vma->vm_flags & VM_SHARED)) {
+ dprintk(1,"mmap app bug: MAP_SHARED please\n");
+ goto done;
+ }
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == q->bufs[first])
+ continue;
+ mem=q->bufs[first]->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+ continue;
+ if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+ if (VIDEO_MAX_FRAME == first) {
+ dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+ goto done;
+ }
+
+ /* look for last buffer to map */
+ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+ if (NULL == q->bufs[last])
+ continue;
+ if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
+ continue;
+ if (q->bufs[last]->map) {
+ retval = -EBUSY;
+ goto done;
+ }
+ size += q->bufs[last]->bsize;
+ if (size == (vma->vm_end - vma->vm_start))
+ break;
+ }
+ if (VIDEO_MAX_FRAME == last) {
+ dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
+ (vma->vm_end - vma->vm_start));
+ goto done;
+ }
+
+ /* create mapping + update buffer list */
+ retval = -ENOMEM;
+ map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+ if (NULL == map)
+ goto done;
+ for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
+ q->bufs[i]->map = map;
+ q->bufs[i]->baddr = vma->vm_start + size;
+ }
+ map->count = 1;
+ map->start = vma->vm_start;
+ map->end = vma->vm_end;
+ map->q = q;
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ vma->vm_private_data = map;
+ dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
+ map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
+ retval = 0;
+
+ done:
+ return retval;
+}
+
+static int __videobuf_copy_to_user ( struct videobuf_queue *q,
+ char __user *data, size_t count,
+ int nonblocking )
+{
+ struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ /* copy to userspace */
+ if (count > q->read_buf->size - q->read_off)
+ count = q->read_buf->size - q->read_off;
+
+ if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static int __videobuf_copy_stream ( struct videobuf_queue *q,
+ char __user *data, size_t count, size_t pos,
+ int vbihack, int nonblocking )
+{
+ unsigned int *fc;
+ struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ if (vbihack) {
+ /* dirty, undocumented hack -- pass the frame counter
+ * within the last four bytes of each vbi data block.
+ * We need that one to maintain backward compatibility
+ * to all vbi decoding software out there ... */
+ fc = (unsigned int*)mem->dma.vmalloc;
+ fc += (q->read_buf->size>>2) -1;
+ *fc = q->read_buf->field_count >> 1;
+ dprintk(1,"vbihack: %d\n",*fc);
+ }
+
+ /* copy stuff using the common method */
+ count = __videobuf_copy_to_user (q,data,count,nonblocking);
+
+ if ( (count==-EFAULT) && (0 == pos) )
+ return -EFAULT;
+
+ return count;
+}
+
+static struct videobuf_qtype_ops pci_ops = {
+ .magic = MAGIC_QTYPE_OPS,
+
+ .alloc = __videobuf_alloc,
+ .iolock = __videobuf_iolock,
+ .sync = __videobuf_sync,
+ .mmap_free = __videobuf_mmap_free,
+ .mmap_mapper = __videobuf_mmap_mapper,
+ .copy_to_user = __videobuf_copy_to_user,
+ .copy_stream = __videobuf_copy_stream,
+};
+
+void *videobuf_pci_alloc (size_t size)
+{
+ struct videobuf_queue q;
+
+ /* Required to make generic handler to call __videobuf_alloc */
+ q.int_ops=&pci_ops;
+
+ q.msize=size;
+
+ return videobuf_alloc (&q);
+}
+
+void videobuf_queue_pci_init(struct videobuf_queue* q,
+ struct videobuf_queue_ops *ops,
+ void *dev,
+ spinlock_t *irqlock,
+ enum v4l2_buf_type type,
+ enum v4l2_field field,
+ unsigned int msize,
+ void *priv)
+{
+ videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+ priv, &pci_ops);
+}
+
+/* --------------------------------------------------------------------- */
+
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
+
+EXPORT_SYMBOL_GPL(videobuf_to_dma);
+EXPORT_SYMBOL_GPL(videobuf_dma_init);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
+EXPORT_SYMBOL_GPL(videobuf_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_dma_sync);
+EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_dma_free);
+
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_pci_alloc);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_pci_init);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/videobuf-dvb.c
index e617925ba31e..880317e04a02 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -22,8 +22,8 @@
#include <linux/file.h>
#include <linux/freezer.h>
-#include <media/video-buf.h>
-#include <media/video-buf-dvb.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
/* ------------------------------------------------------------------ */
@@ -45,6 +45,7 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_buffer *buf;
unsigned long flags;
int err;
+ struct videobuf_dmabuf *dma;
dprintk("dvb thread started\n");
set_freezable();
@@ -56,7 +57,6 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_buffer, stream);
list_del(&buf->stream);
err = videobuf_waiton(buf,0,1);
- BUG_ON(0 != err);
/* no more feeds left or stop_feed() asked us to quit */
if (0 == dvb->nfeeds)
@@ -66,8 +66,9 @@ static int videobuf_dvb_thread(void *data)
try_to_freeze();
/* feed buffer data to demux */
+ dma=videobuf_to_dma(buf);
if (buf->state == STATE_DONE)
- dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc,
+ dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
buf->size);
/* requeue buffer */
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
new file mode 100644
index 000000000000..2e3689a12a28
--- /dev/null
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -0,0 +1,370 @@
+/*
+ * helper functions for vmalloc video4linux capture buffers
+ *
+ * The functions expect the hardware being able to scatter gatter
+ * (i.e. the buffers are not linear in physical memory, but fragmented
+ * into PAGE_SIZE chunks). They also assume the driver does not need
+ * to touch the video data.
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <media/videobuf-vmalloc.h>
+
+#define MAGIC_DMABUF 0x17760309
+#define MAGIC_VMAL_MEM 0x18221223
+
+#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
+ { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+
+
+/***************************************************************************/
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+
+ dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+
+ map->count++;
+}
+
+static void
+videobuf_vm_close(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
+ int i;
+
+ dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+
+ map->count--;
+ if (0 == map->count) {
+ dprintk(1,"munmap %p q=%p\n",map,q);
+ mutex_lock(&q->lock);
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+
+ if (q->bufs[i]->map != map)
+ continue;
+
+ q->ops->buf_release(q,q->bufs[i]);
+
+ q->bufs[i]->map = NULL;
+ q->bufs[i]->baddr = 0;
+ }
+ mutex_unlock(&q->lock);
+ kfree(map);
+ }
+ return;
+}
+
+static struct vm_operations_struct videobuf_vm_ops =
+{
+ .open = videobuf_vm_open,
+ .close = videobuf_vm_close,
+};
+
+/* ---------------------------------------------------------------------
+ * vmalloc handlers for the generic methods
+ */
+
+/* Allocated area consists on 3 parts:
+ struct video_buffer
+ struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
+ struct videobuf_pci_sg_memory
+ */
+
+static void *__videobuf_alloc(size_t size)
+{
+ struct videbuf_vmalloc_memory *mem;
+ struct videobuf_buffer *vb;
+
+ vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+
+ mem = vb->priv = ((char *)vb)+size;
+ mem->magic=MAGIC_VMAL_MEM;
+
+ dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+ __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ mem,(long)sizeof(*mem));
+
+ return vb;
+}
+
+static int __videobuf_iolock (struct videobuf_queue* q,
+ struct videobuf_buffer *vb,
+ struct v4l2_framebuffer *fbuf)
+{
+ int pages;
+
+ struct videbuf_vmalloc_memory *mem=vb->priv;
+
+
+ BUG_ON(!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+
+ /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
+ if ((vb->memory != V4L2_MEMORY_MMAP) &&
+ (vb->memory != V4L2_MEMORY_USERPTR) ) {
+ printk(KERN_ERR "Method currently unsupported.\n");
+ return -EINVAL;
+ }
+
+ /* FIXME: should be tested with kernel mmap mem */
+ mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
+ if (NULL == mem->vmalloc) {
+ printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
+ return -ENOMEM;
+ }
+
+ dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)mem->vmalloc,
+ pages << PAGE_SHIFT);
+
+ /* It seems that some kernel versions need to do remap *after*
+ the mmap() call
+ */
+ if (mem->vma) {
+ int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0);
+ kfree(mem->vma);
+ mem->vma=NULL;
+ if (retval<0) {
+ dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n",
+ mem->vmalloc,retval);
+ return retval;
+ }
+ }
+
+ return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
+{
+ return 0;
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+ unsigned int i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (q->bufs[i]) {
+ if (q->bufs[i]->map)
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+ struct vm_area_struct *vma)
+{
+ struct videbuf_vmalloc_memory *mem;
+ struct videobuf_mapping *map;
+ unsigned int first;
+ int retval;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == q->bufs[first])
+ continue;
+
+ if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+ continue;
+ if (q->bufs[first]->boff == offset)
+ break;
+ }
+ if (VIDEO_MAX_FRAME == first) {
+ dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+ return -EINVAL;
+ }
+
+ /* create mapping + update buffer list */
+ map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+ if (NULL == map)
+ return -ENOMEM;
+
+ map->start = vma->vm_start;
+ map->end = vma->vm_end;
+ map->q = q;
+
+ q->bufs[first]->baddr = vma->vm_start;
+
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = map;
+
+ mem=q->bufs[first]->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ /* Try to remap memory */
+ retval=remap_vmalloc_range(vma, mem->vmalloc,0);
+ if (retval<0) {
+ dprintk(1,"mmap: postponing remap_vmalloc_range\n");
+
+ mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL);
+ if (!mem->vma) {
+ kfree(map);
+ q->bufs[first]->map=NULL;
+ return -ENOMEM;
+ }
+ memcpy(mem->vma,vma,sizeof(*vma));
+ }
+
+ dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+ map,q,vma->vm_start,vma->vm_end,
+ (long int) q->bufs[first]->bsize,
+ vma->vm_pgoff,first);
+
+ videobuf_vm_open(vma);
+
+ return (0);
+}
+
+static int __videobuf_copy_to_user ( struct videobuf_queue *q,
+ char __user *data, size_t count,
+ int nonblocking )
+{
+ struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ BUG_ON (!mem->vmalloc);
+
+ /* copy to userspace */
+ if (count > q->read_buf->size - q->read_off)
+ count = q->read_buf->size - q->read_off;
+
+ if (copy_to_user(data, mem->vmalloc+q->read_off, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static int __videobuf_copy_stream ( struct videobuf_queue *q,
+ char __user *data, size_t count, size_t pos,
+ int vbihack, int nonblocking )
+{
+ unsigned int *fc;
+ struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ if (vbihack) {
+ /* dirty, undocumented hack -- pass the frame counter
+ * within the last four bytes of each vbi data block.
+ * We need that one to maintain backward compatibility
+ * to all vbi decoding software out there ... */
+ fc = (unsigned int*)mem->vmalloc;
+ fc += (q->read_buf->size>>2) -1;
+ *fc = q->read_buf->field_count >> 1;
+ dprintk(1,"vbihack: %d\n",*fc);
+ }
+
+ /* copy stuff using the common method */
+ count = __videobuf_copy_to_user (q,data,count,nonblocking);
+
+ if ( (count==-EFAULT) && (0 == pos) )
+ return -EFAULT;
+
+ return count;
+}
+
+static struct videobuf_qtype_ops qops = {
+ .magic = MAGIC_QTYPE_OPS,
+
+ .alloc = __videobuf_alloc,
+ .iolock = __videobuf_iolock,
+ .sync = __videobuf_sync,
+ .mmap_free = __videobuf_mmap_free,
+ .mmap_mapper = __videobuf_mmap_mapper,
+ .copy_to_user = __videobuf_copy_to_user,
+ .copy_stream = __videobuf_copy_stream,
+};
+
+void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
+ struct videobuf_queue_ops *ops,
+ void *dev,
+ spinlock_t *irqlock,
+ enum v4l2_buf_type type,
+ enum v4l2_field field,
+ unsigned int msize,
+ void *priv)
+{
+ videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+ priv, &qops);
+}
+
+EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
+
+void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
+{
+ struct videbuf_vmalloc_memory *mem=buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ return mem->vmalloc;
+}
+EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
+
+void videobuf_vmalloc_free (struct videobuf_buffer *buf)
+{
+ struct videbuf_vmalloc_memory *mem=buf->priv;
+ BUG_ON (!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ vfree(mem->vmalloc);
+ mem->vmalloc=NULL;
+
+ return;
+}
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index b876aca69c73..8d8e517b344f 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -54,15 +54,14 @@
* sysfs stuff
*/
-static ssize_t show_name(struct class_device *cd, char *buf)
+static ssize_t show_name(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vfd = container_of(cd, struct video_device,
- class_dev);
- return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
+ class_dev);
+ return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
}
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
struct video_device *video_device_alloc(void)
{
struct video_device *vfd;
@@ -76,7 +75,7 @@ void video_device_release(struct video_device *vfd)
kfree(vfd);
}
-static void video_release(struct class_device *cd)
+static void video_release(struct device *cd)
{
struct video_device *vfd = container_of(cd, struct video_device,
class_dev);
@@ -89,9 +88,15 @@ static void video_release(struct class_device *cd)
vfd->release(vfd);
}
+static struct device_attribute video_device_attrs[] = {
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR_NULL
+};
+
static struct class video_class = {
.name = VIDEO_NAME,
- .release = video_release,
+ .dev_attrs = video_device_attrs,
+ .dev_release = video_release,
};
/*
@@ -448,7 +453,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if (cmd == VIDIOCGMBUF) {
struct video_mbuf *p=arg;
- memset(p,0,sizeof(p));
+ memset(p, 0, sizeof(*p));
if (!vfd->vidiocgmbuf)
return ret;
@@ -1753,22 +1758,16 @@ int video_register_device(struct video_device *vfd, int type, int nr)
/* sysfs class */
memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
if (vfd->dev)
- vfd->class_dev.dev = vfd->dev;
+ vfd->class_dev.parent = vfd->dev;
vfd->class_dev.class = &video_class;
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
- sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
- ret = class_device_register(&vfd->class_dev);
+ sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
+ ret = device_register(&vfd->class_dev);
if (ret < 0) {
- printk(KERN_ERR "%s: class_device_register failed\n",
+ printk(KERN_ERR "%s: device_register failed\n",
__FUNCTION__);
goto fail_minor;
}
- ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
- if (ret < 0) {
- printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
- __FUNCTION__);
- goto fail_classdev;
- }
#if 1
/* needed until all drivers are fixed */
@@ -1779,8 +1778,6 @@ int video_register_device(struct video_device *vfd, int type, int nr)
#endif
return 0;
-fail_classdev:
- class_device_unregister(&vfd->class_dev);
fail_minor:
mutex_lock(&videodev_lock);
video_device[vfd->minor] = NULL;
@@ -1804,7 +1801,7 @@ void video_unregister_device(struct video_device *vfd)
panic("videodev: bad unregister");
video_device[vfd->minor]=NULL;
- class_device_unregister(&vfd->class_dev);
+ device_unregister(&vfd->class_dev);
mutex_unlock(&videodev_lock);
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 0c658b74f2c4..9a03dc82c6ca 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -28,7 +28,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/version.h>
@@ -2077,12 +2076,10 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs)
init_waitqueue_entry(&wait, current);
/* add ourselves into wait queue */
add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
- /* and set current state */
- set_current_state(TASK_INTERRUPTIBLE);
/* to ensure that schedule_timeout will return immediately
- * if VINO interrupt was triggred meanwhile */
- schedule_timeout(HZ / 10);
+ * if VINO interrupt was triggered meanwhile */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
if (signal_pending(current))
err = -EINTR;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 3ef4d0159c33..b532aa280a1b 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/random.h>
#include <linux/version.h>
+#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -32,7 +33,7 @@
#include <linux/videodev.h>
#endif
#include <linux/interrupt.h>
-#include <media/video-buf.h>
+#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
@@ -144,10 +145,6 @@ struct vivi_buffer {
struct videobuf_buffer vb;
struct vivi_fmt *fmt;
-
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr;
-#endif
};
struct vivi_dmaqueue {
@@ -168,12 +165,11 @@ static LIST_HEAD(vivi_devlist);
struct vivi_dev {
struct list_head vivi_devlist;
- struct semaphore lock;
+ struct mutex lock;
int users;
/* various device info */
- unsigned int resources;
struct video_device vfd;
struct vivi_dmaqueue vidq;
@@ -232,91 +228,25 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
- struct videobuf_buffer *vb)
-{
- int i, pos=0;
-
- for (i=0;i<vb->dma.nr_pages;i++) {
- to_addr[i].sg=&vb->dma.sglist[i];
- to_addr[i].pos=pos;
- pos += vb->dma.sglist[i].length;
- }
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
- int p1=0,p2=pages-1,p3=pages/2;
-
- /* Sanity test */
- BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
- while (p1+1<p2) {
- if (pos < to_addr[p3].pos) {
- p2=p3;
- } else {
- p1=p3;
- }
- p3=(p1+p2)/2;
- }
- if (pos >= to_addr[p2].pos)
- p1=p2;
-
- return (p1);
-}
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
-#else
static void gen_line(char *basep,int inipos,int wmax,
- int hmax, int line, char *timestr)
-#endif
+ int hmax, int line, int count, char *timestr)
{
int w,i,j,pos=inipos,y;
char *p,*s;
u8 chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
- int pgpos,oldpg;
- char *basep;
- struct page *pg;
-
- unsigned long flags;
- spinlock_t spinlock;
-
- spin_lock_init(&spinlock);
-
- /* Get first addr pointed to pixel position */
- oldpg=get_addr_pos(pos,pages,to_addr);
- pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
- spin_lock_irqsave(&spinlock,flags);
- basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
/* We will just duplicate the second pixel at the packet */
wmax/=2;
/* Generate a standard color bar pattern */
for (w=0;w<wmax;w++) {
- r=bars[w*7/wmax][0];
- g=bars[w*7/wmax][1];
- b=bars[w*7/wmax][2];
+ int colorpos=((w+count)*8/(wmax+1)) % 8;
+ r=bars[colorpos][0];
+ g=bars[colorpos][1];
+ b=bars[colorpos][2];
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
- kunmap_atomic(basep, KM_BOUNCE_READ);
- basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
switch (color) {
case 0:
@@ -361,23 +291,7 @@ static void gen_line(char *basep,int inipos,int wmax,
pos=inipos+j*2;
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(
- to_addr[pgpos].sg)
- >> PAGE_SHIFT);
- kunmap_atomic(basep,
- KM_BOUNCE_READ);
- basep= kmap_atomic(pg,
- KM_BOUNCE_READ)+
- to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
y=TO_Y(r,g,b);
@@ -402,12 +316,7 @@ static void gen_line(char *basep,int inipos,int wmax,
end:
-#ifdef CONFIG_VIVI_SCATTER
- kunmap_atomic(basep, KM_BOUNCE_READ);
- spin_unlock_irqrestore(&spinlock,flags);
-#else
return;
-#endif
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
@@ -415,47 +324,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr=buf->to_addr;
- struct videobuf_buffer *vb=&buf->vb;
-#else
- char *tmpbuf;
-#endif
+ char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
+ void *vbuf=videobuf_to_vmalloc (&buf->vb);
+ /* FIXME: move to dev struct */
+ static int mv_count=0;
-#ifdef CONFIG_VIVI_SCATTER
- /* Test if DMA mapping is ready */
- if (!sg_dma_address(&vb->dma.sglist[0]))
+ if (!tmpbuf)
return;
- prep_to_addr(to_addr,vb);
-
- /* Check if there is enough memory */
- BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
- if (buf->vb.dma.varea) {
- tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
- } else {
- tmpbuf=buf->vb.dma.vmalloc;
- }
-
-#endif
-
for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
- gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
- if (buf->vb.dma.varea) {
- gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
- /* FIXME: replacing to __copy_to_user */
- if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
- dprintk(2,"vivifill copy_to_user failed.\n");
- } else {
- gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
- }
-#endif
+ gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
+ dev->timestr);
+ /* FIXME: replacing to __copy_to_user */
+ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
+ dprintk(2,"vivifill copy_to_user failed.\n");
pos += wmax*2;
}
+ mv_count++;
+
+ kfree(tmpbuf);
+
/* Updates stream time */
dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
@@ -478,7 +367,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
dev->h,dev->m,dev->s,(dev->us+500)/1000);
dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
- (unsigned long)buf->vb.dma.varea,pos);
+ (unsigned long)tmpbuf,pos);
/* Advice that buffer was filled */
buf->vb.state = STATE_DONE;
@@ -618,7 +507,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
static int restart_video_queue(struct vivi_dmaqueue *dma_q)
{
struct vivi_buffer *buf, *prev;
- struct list_head *item;
dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
@@ -632,9 +520,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
// vivi_start_thread(dma_q);
/* cancel all outstanding capture / vbi requests */
- list_for_each(item,&dma_q->active) {
- buf = list_entry(item, struct vivi_buffer, vb.queue);
-
+ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
list_del(&buf->vb.queue);
buf->vb.state = STATE_ERROR;
wake_up(&buf->vb.done);
@@ -706,8 +592,12 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
if (0 == *count)
*count = 32;
+
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
+
+ dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
+
return 0;
}
@@ -718,15 +608,8 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
if (in_interrupt())
BUG();
-#ifdef CONFIG_VIVI_SCATTER
- /*FIXME: Maybe a spinlock is required here */
- kfree(buf->to_addr);
- buf->to_addr=NULL;
-#endif
-
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(vq, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_vmalloc_free(&buf->vb);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -740,7 +623,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
int rc, init_buffer = 0;
-// dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+ dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
BUG_ON(NULL == fh->fmt);
if (fh->width < 48 || fh->width > norm_maxw() ||
@@ -768,12 +651,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
buf->vb.state = STATE_PREPARED;
-#ifdef CONFIG_VIVI_SCATTER
- if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
- rc=-ENOMEM;
- goto fail;
- }
-#endif
return 0;
fail:
@@ -838,88 +715,14 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
- int direction)
-{
- int i;
-
- dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
- BUG_ON(direction == DMA_NONE);
-
- for (i = 0; i < nents; i++ ) {
- BUG_ON(!sg[i].page);
-
- sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
- }
-
- return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
-{
- dprintk(1,"%s\n",__FUNCTION__);
- return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
- int direction)
-{
-// dprintk(1,"%s\n",__FUNCTION__);
-
-// flush_write_buffers();
- return 0;
-}
-#endif
-
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
-
- /* Non-pci handling routines */
-// .vb_map_sg = vivi_map_sg,
-// .vb_dma_sync_sg = vivi_dma_sync_sg,
-// .vb_unmap_sg = vivi_unmap_sg,
};
/* ------------------------------------------------------------------
- IOCTL handling
- ------------------------------------------------------------------*/
-
-
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- /* is it free? */
- down(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- up(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(1,"res: get\n");
- up(&dev->lock);
- return 1;
-}
-
-static int res_locked(struct vivi_dev *dev)
-{
- return (dev->resources);
-}
-
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- down(&dev->lock);
- dev->resources = 0;
- dprintk(1,"res: put\n");
- up(&dev->lock);
-}
-
-/* ------------------------------------------------------------------
IOCTL vidioc handling
------------------------------------------------------------------*/
static int vidioc_querycap (struct file *file, void *priv,
@@ -979,8 +782,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
-// field=V4L2_FIELD_INTERLACED;
- field=V4L2_FIELD_SEQ_TB;
+ field=V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != field) {
dprintk(1,"Field type invalid.\n");
return -EINVAL;
@@ -1058,57 +860,33 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
struct vivi_fh *fh=priv;
- struct videobuf_queue *q=&fh->vb_vidq;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int ret;
-
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- ret = videobuf_reqbufs(q,&req);
- if (ret < 0)
- return (ret);
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return (0);
+ return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
}
#endif
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_fh *fh=priv;
- struct vivi_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL;
- if (!res_get(dev,fh))
- return -EBUSY;
- return (videobuf_streamon(&fh->vb_vidq));
+ return videobuf_streamon(&fh->vb_vidq);
}
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_fh *fh=priv;
- struct vivi_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL;
- videobuf_streamoff(&fh->vb_vidq);
- res_free(dev,fh);
-
- return (0);
+ return videobuf_streamoff(&fh->vb_vidq);
}
static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
@@ -1201,31 +979,25 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct vivi_dev *h,*dev = NULL;
+ struct vivi_dev *dev;
struct vivi_fh *fh;
- struct list_head *list;
- enum v4l2_buf_type type = 0;
int i;
printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
- list_for_each(list,&vivi_devlist) {
- h = list_entry(list, struct vivi_dev, vivi_devlist);
- if (h->vfd.minor == minor) {
- dev = h;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- }
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
+ if (dev->vfd.minor == minor)
+ goto found;
+ return -ENODEV;
+found:
/* If more than one user, mutex should be added */
dev->users++;
- dprintk(1,"open minor=%d type=%s users=%d\n",
- minor,v4l2_type_names[type],dev->users);
+ dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
@@ -1260,19 +1032,11 @@ static int vivi_open(struct inode *inode, struct file *file)
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
-#ifdef CONFIG_VIVI_SCATTER
- videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer),fh);
-#else
- videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
- NULL, NULL,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct vivi_buffer),fh);
-#endif
return 0;
}
@@ -1283,9 +1047,7 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
struct vivi_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(fh->dev))
- return -EBUSY;
- return videobuf_read_one(&fh->vb_vidq, data, count, ppos,
+ return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
file->f_flags & O_NONBLOCK);
}
return 0;
@@ -1295,31 +1057,14 @@ static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
struct vivi_fh *fh = file->private_data;
- struct vivi_buffer *buf;
+ struct videobuf_queue *q = &fh->vb_vidq;
dprintk(1,"%s\n",__FUNCTION__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
- if (res_get(fh->dev,fh)) {
- dprintk(1,"poll: mmap interface\n");
- /* streaming capture */
- if (list_empty(&fh->vb_vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream);
- } else {
- dprintk(1,"poll: read() interface\n");
- /* read() capture */
- buf = (struct vivi_buffer*)fh->vb_vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == STATE_DONE ||
- buf->vb.state == STATE_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ return videobuf_poll_stream(file, q, wait);
}
static int vivi_release(struct inode *inode, struct file *file)
@@ -1367,7 +1112,7 @@ static const struct file_operations vivi_fops = {
.read = vivi_read,
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = vivi_mmap,
+ .mmap = vivi_mmap,
.llseek = no_llseek,
};
@@ -1423,7 +1168,7 @@ static int __init vivi_init(void)
init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
dev->vidq.timeout.function = vivi_vid_timeout;
dev->vidq.timeout.data = (unsigned long)dev;
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
new file mode 100644
index 000000000000..63002e0ac764
--- /dev/null
+++ b/drivers/media/video/vp27smpx.c
@@ -0,0 +1,212 @@
+/*
+ * vp27smpx - driver version 0.0.1
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com>
+ * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("vp27smpx driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct vp27smpx_state {
+ int radio;
+ u32 audmode;
+};
+
+static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
+{
+ struct vp27smpx_state *state = i2c_get_clientdata(client);
+ u8 data[3] = { 0x00, 0x00, 0x04 };
+
+ switch (audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ data[1] = 0x01;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ data[1] = 0x02;
+ break;
+ }
+
+ if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
+ v4l_err(client, "%s: I/O error setting audmode\n", client->name);
+ }
+ else {
+ state->audmode = audmode;
+ }
+}
+
+static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct vp27smpx_state *state = i2c_get_clientdata(client);
+ struct v4l2_tuner *vt = arg;
+
+ switch (cmd) {
+ case AUDC_SET_RADIO:
+ state->radio = 1;
+ break;
+
+ case VIDIOC_S_STD:
+ state->radio = 0;
+ break;
+
+ case VIDIOC_S_TUNER:
+ if (!state->radio)
+ vp27smpx_set_audmode(client, vt->audmode);
+ break;
+
+ case VIDIOC_G_TUNER:
+ if (state->radio)
+ break;
+ vt->audmode = state->audmode;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ break;
+
+ case VIDIOC_G_CHIP_IDENT:
+ return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
+
+ case VIDIOC_LOG_STATUS:
+ v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
+ state->radio ? " (Radio)" : "");
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct vp27smpx_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->audmode = V4L2_TUNER_MODE_STEREO;
+ i2c_set_clientdata(client, state);
+
+ /* initialize vp27smpx */
+ vp27smpx_set_audmode(client, state->audmode);
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int vp27smpx_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+ return i2c_probe(adapter, &addr_data, vp27smpx_attach);
+ return 0;
+}
+
+static int vp27smpx_detach(struct i2c_client *client)
+{
+ struct vp27smpx_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(state);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .driver = {
+ .name = "vp27smpx",
+ },
+ .id = I2C_DRIVERID_VP27SMPX,
+ .attach_adapter = vp27smpx_probe,
+ .detach_client = vp27smpx_detach,
+ .command = vp27smpx_command,
+};
+
+
+static int __init vp27smpx_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit vp27smpx_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(vp27smpx_init_module);
+module_exit(vp27smpx_cleanup_module);
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 8f31613b9903..5a1b5f5a7d46 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -42,7 +42,6 @@
#include <asm/page.h>
#include <asm/uaccess.h>
#include <linux/page-flags.h>
-#include <linux/moduleparam.h>
#include "w9968cf.h"
#include "w9968cf_decoder.h"
@@ -2680,7 +2679,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
/* This the only safe way to prevent race conditions with disconnect */
if (!down_read_trylock(&w9968cf_disconnect))
- return -ERESTARTSYS;
+ return -EAGAIN;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 8f6741a28a47..1bf4cbec6a87 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -321,12 +321,14 @@ static int wm8739_probe(struct i2c_adapter *adapter)
static int wm8739_detach(struct i2c_client *client)
{
+ struct wm8739_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err)
return err;
+ kfree(state);
kfree(client);
return 0;
}
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 4df5d30d4d09..9f7e894ef962 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -222,12 +222,14 @@ static int wm8775_probe(struct i2c_adapter *adapter)
static int wm8775_detach(struct i2c_client *client)
{
+ struct wm8775_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err) {
return err;
}
+ kfree(state);
kfree(client);
return 0;
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 47cd93f9c7de..edb00293cd59 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,6 +1,6 @@
config USB_ZC0301
tristate "USB ZC0301[P] Image Processor and Control Chip support"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y here if you want support for cameras based on the ZC0301 or
ZC0301P Image Processors and Control Chips.
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index 710f12eb9126..a2de50efa31a 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -36,6 +36,7 @@
#include <linux/rwsem.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/kref.h>
#include "zc0301_sensor.h"
@@ -98,7 +99,7 @@ struct zc0301_module_param {
u16 frame_timeout;
};
-static DECLARE_RWSEM(zc0301_disconnect);
+static DECLARE_RWSEM(zc0301_dev_lock);
struct zc0301_device {
struct video_device* v4ldev;
@@ -121,12 +122,14 @@ struct zc0301_device {
struct zc0301_module_param module_param;
+ struct kref kref;
enum zc0301_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
@@ -156,8 +159,8 @@ do { \
else if ((level) == 2) \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+ __FILE__, __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -166,8 +169,8 @@ do { \
if ((level) == 1 || (level) == 2) \
pr_info("zc0301: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -183,8 +186,8 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index f1120551c70c..08a93c31c0a0 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -49,11 +48,11 @@
#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
"Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
+#define ZC0301_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.07"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 7)
+#define ZC0301_MODULE_VERSION "1:1.10"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 10)
/*****************************************************************************/
@@ -573,7 +572,8 @@ static int zc0301_init(struct zc0301_device* cam)
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
@@ -634,59 +634,73 @@ static int zc0301_init(struct zc0301_device* cam)
return 0;
}
+/*****************************************************************************/
-static void zc0301_release_resources(struct zc0301_device* cam)
+static void zc0301_release_resources(struct kref *kref)
{
+ struct zc0301_device *cam = container_of(kref, struct zc0301_device,
+ kref);
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
kfree(cam->control_buffer);
+ kfree(cam);
}
-/*****************************************************************************/
static int zc0301_open(struct inode* inode, struct file* filp)
{
struct zc0301_device* cam;
int err = 0;
- /*
- This is the only safe way to prevent race conditions with
- disconnect
- */
- if (!down_read_trylock(&zc0301_disconnect))
- return -ERESTARTSYS;
+ if (!down_read_trylock(&zc0301_dev_lock))
+ return -EAGAIN;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&zc0301_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&zc0301_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ kref_get(&cam->kref);
+
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, zc0301_release_resources);
+ up_read(&zc0301_dev_lock);
return -ERESTARTSYS;
}
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&zc0301_dev_lock);
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&zc0301_disconnect);
- return err;
- }
+ down_read(&zc0301_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&zc0301_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = zc0301_init(cam);
if (err) {
@@ -711,36 +725,32 @@ static int zc0301_open(struct inode* inode, struct file* filp)
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&zc0301_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, zc0301_release_resources);
+ up_read(&zc0301_dev_lock);
return err;
}
static int zc0301_release(struct inode* inode, struct file* filp)
{
- struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+ struct zc0301_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&zc0301_dev_lock);
- zc0301_stop_transfer(cam);
+ cam = video_get_drvdata(video_devdata(filp));
+ zc0301_stop_transfer(cam);
zc0301_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- zc0301_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, zc0301_release_resources);
+
+ up_write(&zc0301_dev_lock);
return 0;
}
@@ -775,7 +785,7 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
DBG(3, "Close and open the device again to choose the read "
"method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -953,7 +963,12 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -984,7 +999,6 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
vma->vm_ops = &zc0301_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
zc0301_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -1211,7 +1225,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (!s->set_crop) {
@@ -1434,7 +1448,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -1544,14 +1558,14 @@ zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -1699,9 +1713,6 @@ zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -1949,8 +1960,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
@@ -1982,7 +1991,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -1992,7 +2001,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -2004,8 +2013,10 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -2022,40 +2033,31 @@ fail:
static void zc0301_usb_disconnect(struct usb_interface* intf)
{
- struct zc0301_device* cam = usb_get_intfdata(intf);
-
- if (!cam)
- return;
+ struct zc0301_device* cam;
- down_write(&zc0301_disconnect);
+ down_write(&zc0301_dev_lock);
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
zc0301_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- zc0301_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, zc0301_release_resources);
- up_write(&zc0301_disconnect);
+ up_write(&zc0301_dev_lock);
}
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index 3efb92a0d0da..24b0dfba357e 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -327,6 +327,7 @@ static struct zc0301_sensor pas202bcb = {
.height = 480,
.pixelformat = V4L2_PIX_FMT_JPEG,
.priv = 8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
},
};
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
index 5784b1d1491c..9519aba3612e 100644
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -157,6 +157,7 @@ static struct zc0301_sensor pb0330 = {
.height = 480,
.pixelformat = V4L2_PIX_FMT_JPEG,
.priv = 8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
},
};
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 44e82cff9319..70fe6fc6cdd5 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -23,7 +23,7 @@
#define _ZC0301_SENSOR_H_
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 8fb4a3414e0a..937c4a616c0e 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -240,11 +240,16 @@ enum gpcs_type {
struct zoran_format {
char *name;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
int palette;
+#endif
+#ifdef CONFIG_VIDEO_V4L2
__u32 fourcc;
int colorspace;
+#endif
int depth;
__u32 flags;
+ __u32 vfespfr;
};
/* flags */
#define ZORAN_FORMAT_COMPRESSED 1<<0
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 73162a3a61dd..48da36a15fca 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -64,15 +64,15 @@
extern const struct zoran_format zoran_formats[];
static int card[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(card, int, NULL, 0);
+module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "The type of card");
static int encoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(encoder, int, NULL, 0);
+module_param_array(encoder, int, NULL, 0444);
MODULE_PARM_DESC(encoder, "i2c TV encoder");
static int decoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(decoder, int, NULL, 0);
+module_param_array(decoder, int, NULL, 0444);
MODULE_PARM_DESC(decoder, "i2c TV decoder");
/*
@@ -84,29 +84,31 @@ MODULE_PARM_DESC(decoder, "i2c TV decoder");
*/
static unsigned long vidmem = 0; /* Video memory base address */
-module_param(vidmem, ulong, 0);
+module_param(vidmem, ulong, 0444);
+MODULE_PARM_DESC(vidmem, "Default video memory base address");
/*
Default input and video norm at startup of the driver.
*/
-static int default_input = 0; /* 0=Composite, 1=S-Video */
-module_param(default_input, int, 0);
+static unsigned int default_input = 0; /* 0=Composite, 1=S-Video */
+module_param(default_input, uint, 0444);
MODULE_PARM_DESC(default_input,
"Default input (0=Composite, 1=S-Video, 2=Internal)");
static int default_mux = 1; /* 6 Eyes input selection */
-module_param(default_mux, int, 0);
+module_param(default_mux, int, 0644);
MODULE_PARM_DESC(default_mux,
"Default 6 Eyes mux setting (Input selection)");
static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */
-module_param(default_norm, int, 0);
+module_param(default_norm, int, 0444);
MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "video device number");
+/* /dev/videoN, -1 for autodetect */
+static int video_nr[BUZ_MAX] = {-1, -1, -1, -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
/*
Number and size of grab buffers for Video 4 Linux
@@ -127,28 +129,27 @@ MODULE_PARM_DESC(video_nr, "video device number");
int v4l_nbufs = 2;
int v4l_bufsize = 128; /* Everybody should be able to work with this setting */
-module_param(v4l_nbufs, int, 0);
+module_param(v4l_nbufs, int, 0644);
MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
-module_param(v4l_bufsize, int, 0);
+module_param(v4l_bufsize, int, 0644);
MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
int jpg_nbufs = 32;
int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */
-module_param(jpg_nbufs, int, 0);
+module_param(jpg_nbufs, int, 0644);
MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
-module_param(jpg_bufsize, int, 0);
+module_param(jpg_bufsize, int, 0644);
MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
int pass_through = 0; /* 1=Pass through TV signal when device is not used */
/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
-module_param(pass_through, int, 0);
+module_param(pass_through, int, 0644);
MODULE_PARM_DESC(pass_through,
"Pass TV signal through to TV-out when idling");
-static int debug = 1;
-int *zr_debug = &debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0-4)");
+int zr36067_debug = 1;
+module_param_named(debug, zr36067_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-5)");
MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
MODULE_AUTHOR("Serguei Miridonov");
@@ -161,12 +162,6 @@ static struct pci_device_id zr36067_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
-
int zoran_num; /* number of Buzs in use */
struct zoran zoran[BUZ_MAX];
@@ -1075,7 +1070,7 @@ test_interrupts (struct zoran *zr)
if (timeout) {
dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
}
- if (*zr_debug > 1)
+ if (zr36067_debug > 1)
print_interrupts(zr);
btwrite(icr, ZR36057_ICR);
}
@@ -1121,7 +1116,14 @@ zr36057_init (struct zoran *zr)
zr->timing = zr->card.tvn[zr->norm];
}
- zr->input = default_input = (default_input ? 1 : 0);
+ if (default_input > zr->card.inputs-1) {
+ dprintk(1,
+ KERN_WARNING
+ "%s: default_input value %d out of range (0-%d)\n",
+ ZR_DEVNAME(zr), default_input, zr->card.inputs-1);
+ default_input = 0;
+ }
+ zr->input = default_input;
/* Should the following be reset at every open ? */
zr->hue = 32768;
@@ -1153,12 +1155,12 @@ zr36057_init (struct zoran *zr)
*/
memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
- err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr);
+ err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
if (err < 0)
goto exit_unregister;
zoran_init_hardware(zr);
- if (*zr_debug > 2)
+ if (zr36067_debug > 2)
detect_guest_activity(zr);
test_interrupts(zr);
if (!pass_through) {
@@ -1620,7 +1622,7 @@ init_dc10_cards (void)
}
/* random nonsense */
- dprintk(5, KERN_DEBUG "Jotti is een held!\n");
+ dprintk(6, KERN_DEBUG "Jotti is een held!\n");
/* some mainboards might not do PCI-PCI data transfer well */
if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h
index ad997c30bee5..8444ca0a5f3f 100644
--- a/drivers/media/video/zoran_card.h
+++ b/drivers/media/video/zoran_card.h
@@ -30,6 +30,14 @@
#ifndef __ZORAN_CARD_H__
#define __ZORAN_CARD_H__
+extern int zr36067_debug;
+
+#define dprintk(num, format, args...) \
+ do { \
+ if (zr36067_debug >= num) \
+ printk(format, ##args); \
+ } while (0)
+
/* Anybody who uses more than four? */
#define BUZ_MAX 4
extern int zoran_num;
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index b0752767ee4f..68c7c505587e 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -52,6 +52,7 @@
#include "videocodec.h"
#include "zoran.h"
#include "zoran_device.h"
+#include "zoran_card.h"
#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
ZR36057_ISR_GIRQ1 | \
@@ -59,14 +60,6 @@
extern const struct zoran_format zoran_formats[];
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
-
static int lml33dpath = 0; /* 1 will use digital path in capture
* mode instead of analog. It can be
* used for picture adjustments using
@@ -76,7 +69,7 @@ static int lml33dpath = 0; /* 1 will use digital path in capture
* load on Bt819 input, there will be
* some image imperfections */
-module_param(lml33dpath, bool, 0);
+module_param(lml33dpath, bool, 0644);
MODULE_PARM_DESC(lml33dpath,
"Use digital path capture mode (on LML33 cards)");
@@ -174,7 +167,7 @@ post_office_read (struct zoran *zr,
static void
dump_guests (struct zoran *zr)
{
- if (*zr_debug > 2) {
+ if (zr36067_debug > 2) {
int i, guest[8];
for (i = 1; i < 8; i++) { // Don't read jpeg codec here
@@ -429,8 +422,6 @@ zr36057_set_vfe (struct zoran *zr,
reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
reg |= (DispMode << ZR36057_VFESPFR_DispMode);
- if (format->palette != VIDEO_PALETTE_YUV422 && format->palette != VIDEO_PALETTE_YUYV)
- reg |= ZR36057_VFESPFR_LittleEndian;
/* RJ: I don't know, why the following has to be the opposite
* of the corresponding ZR36060 setting, but only this way
* we get the correct colors when uncompressing to the screen */
@@ -439,36 +430,6 @@ zr36057_set_vfe (struct zoran *zr,
if (zr->norm != VIDEO_MODE_NTSC)
reg |= ZR36057_VFESPFR_ExtFl; // NEEDED!!!!!!! Wolfgang
reg |= ZR36057_VFESPFR_TopField;
- switch (format->palette) {
-
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_YUV422:
- reg |= ZR36057_VFESPFR_YUV422;
- break;
-
- case VIDEO_PALETTE_RGB555:
- reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
- break;
-
- case VIDEO_PALETTE_RGB565:
- reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
- break;
-
- case VIDEO_PALETTE_RGB24:
- reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
- break;
-
- case VIDEO_PALETTE_RGB32:
- reg |= ZR36057_VFESPFR_RGB888;
- break;
-
- default:
- dprintk(1,
- KERN_INFO "%s: set_vfe() - unknown color_fmt=%x\n",
- ZR_DEVNAME(zr), format->palette);
- return;
-
- }
if (HorDcm >= 48) {
reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */
} else if (HorDcm >= 32) {
@@ -476,6 +437,7 @@ zr36057_set_vfe (struct zoran *zr,
} else if (HorDcm >= 16) {
reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */
}
+ reg |= format->vfespfr;
btwrite(reg, ZR36057_VFESPFR);
/* display configuration */
@@ -651,11 +613,17 @@ zr36057_set_memgrab (struct zoran *zr,
int mode)
{
if (mode) {
- if (btread(ZR36057_VSSFGR) &
- (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
+ /* We only check SnapShot and not FrameGrab here. SnapShot==1
+ * means a capture is already in progress, but FrameGrab==1
+ * doesn't necessary mean that. It's more correct to say a 1
+ * to 0 transition indicates a capture completed. If a
+ * capture is pending when capturing is tuned off, FrameGrab
+ * will be stuck at 1 until capturing is turned back on.
+ */
+ if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot)
dprintk(1,
KERN_WARNING
- "%s: zr36057_set_memgrab(1) with SnapShot or FrameGrab on!?\n",
+ "%s: zr36057_set_memgrab(1) with SnapShot on!?\n",
ZR_DEVNAME(zr));
/* switch on VSync interrupts */
@@ -672,11 +640,12 @@ zr36057_set_memgrab (struct zoran *zr,
zr->v4l_memgrab_active = 1;
} else {
- zr->v4l_memgrab_active = 0;
-
/* switch off VSync interrupts */
btand(~zr->card.vsync_int, ZR36057_ICR); // SW
+ zr->v4l_memgrab_active = 0;
+ zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+
/* reenable grabbing to screen if it was running */
if (zr->v4l_overlay_active) {
zr36057_overlay(zr, 1);
@@ -1295,7 +1264,7 @@ error_handler (struct zoran *zr,
zr->num_errors++;
/* Report error */
- if (*zr_debug > 1 && zr->num_errors <= 8) {
+ if (zr36067_debug > 1 && zr->num_errors <= 8) {
long frame;
frame =
zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
@@ -1555,7 +1524,7 @@ zoran_irq (int irq,
if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
- if (*zr_debug > 1 &&
+ if (zr36067_debug > 1 &&
(!zr->frame_num || zr->JPEG_error)) {
printk(KERN_INFO
"%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
@@ -1592,7 +1561,7 @@ zoran_irq (int irq,
zr->JPEG_missed;
}
- if (*zr_debug > 2 && zr->frame_num < 6) {
+ if (zr36067_debug > 2 && zr->frame_num < 6) {
int i;
printk("%s: seq=%ld stat_com:",
ZR_DEVNAME(zr), zr->jpg_seq_num);
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index cf0ed6cbb0e3..1c14fa2bd411 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -99,106 +99,106 @@
#include <asm/byteorder.h>
-const struct zoran_format zoran_formats[] = {
- {
- .name = "15-bit RGB",
- .palette = VIDEO_PALETTE_RGB555,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
- .fourcc = V4L2_PIX_FMT_RGB555,
+#if defined(CONFIG_VIDEO_V4L2) && defined(CONFIG_VIDEO_V4L1_COMPAT)
+#define ZFMT(pal, fcc, cs) \
+ .palette = (pal), .fourcc = (fcc), .colorspace = (cs)
+#elif defined(CONFIG_VIDEO_V4L2)
+#define ZFMT(pal, fcc, cs) \
+ .fourcc = (fcc), .colorspace = (cs)
#else
- .fourcc = V4L2_PIX_FMT_RGB555X,
-#endif
- .colorspace = V4L2_COLORSPACE_SRGB,
+#define ZFMT(pal, fcc, cs) \
+ .palette = (pal)
#endif
+
+const struct zoran_format zoran_formats[] = {
+ {
+ .name = "15-bit RGB LE",
+ ZFMT(VIDEO_PALETTE_RGB555,
+ V4L2_PIX_FMT_RGB555, V4L2_COLORSPACE_SRGB),
.depth = 15,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif|
+ ZR36057_VFESPFR_LittleEndian,
}, {
- .name = "16-bit RGB",
- .palette = VIDEO_PALETTE_RGB565,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
- .fourcc = V4L2_PIX_FMT_RGB565,
-#else
- .fourcc = V4L2_PIX_FMT_RGB565X,
-#endif
- .colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+ .name = "15-bit RGB BE",
+ ZFMT(-1,
+ V4L2_PIX_FMT_RGB555X, V4L2_COLORSPACE_SRGB),
+ .depth = 15,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
+ }, {
+ .name = "16-bit RGB LE",
+ ZFMT(VIDEO_PALETTE_RGB565,
+ V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
.depth = 16,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif|
+ ZR36057_VFESPFR_LittleEndian,
+ }, {
+ .name = "16-bit RGB BE",
+ ZFMT(-1,
+ V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
+ .depth = 16,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
}, {
.name = "24-bit RGB",
- .palette = VIDEO_PALETTE_RGB24,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
- .fourcc = V4L2_PIX_FMT_BGR24,
-#else
- .fourcc = V4L2_PIX_FMT_RGB24,
-#endif
- .colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+ ZFMT(VIDEO_PALETTE_RGB24,
+ V4L2_PIX_FMT_BGR24, V4L2_COLORSPACE_SRGB),
.depth = 24,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
}, {
- .name = "32-bit RGB",
- .palette = VIDEO_PALETTE_RGB32,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
- .fourcc = V4L2_PIX_FMT_BGR32,
-#else
- .fourcc = V4L2_PIX_FMT_RGB32,
-#endif
- .colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+ .name = "32-bit RGB LE",
+ ZFMT(VIDEO_PALETTE_RGB32,
+ V4L2_PIX_FMT_BGR32, V4L2_COLORSPACE_SRGB),
.depth = 32,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
+ }, {
+ .name = "32-bit RGB BE",
+ ZFMT(-1,
+ V4L2_PIX_FMT_RGB32, V4L2_COLORSPACE_SRGB),
+ .depth = 32,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_RGB888,
}, {
.name = "4:2:2, packed, YUYV",
- .palette = VIDEO_PALETTE_YUV422,
-#ifdef CONFIG_VIDEO_V4L2
- .fourcc = V4L2_PIX_FMT_YUYV,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
-#endif
+ ZFMT(VIDEO_PALETTE_YUV422,
+ V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_SMPTE170M),
.depth = 16,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_YUV422,
+ }, {
+ .name = "4:2:2, packed, UYVY",
+ ZFMT(VIDEO_PALETTE_UYVY,
+ V4L2_PIX_FMT_UYVY, V4L2_COLORSPACE_SMPTE170M),
+ .depth = 16,
+ .flags = ZORAN_FORMAT_CAPTURE |
+ ZORAN_FORMAT_OVERLAY,
+ .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
}, {
.name = "Hardware-encoded Motion-JPEG",
- .palette = -1,
-#ifdef CONFIG_VIDEO_V4L2
- .fourcc = V4L2_PIX_FMT_MJPEG,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
-#endif
+ ZFMT(-1,
+ V4L2_PIX_FMT_MJPEG, V4L2_COLORSPACE_SMPTE170M),
.depth = 0,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_PLAYBACK |
ZORAN_FORMAT_COMPRESSED,
}
};
-static const int zoran_num_formats =
- (sizeof(zoran_formats) / sizeof(struct zoran_format));
+#define NUM_FORMATS ARRAY_SIZE(zoran_formats)
// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
-
-#if defined(CONFIG_BIGPHYS_AREA)
-# include <linux/bigphysarea.h>
-#endif
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
extern int v4l_nbufs;
extern int v4l_bufsize;
@@ -207,8 +207,8 @@ extern int jpg_bufsize;
extern int pass_through;
static int lock_norm = 0; /* 1=Don't change TV standard (norm) */
-module_param(lock_norm, int, 0);
-MODULE_PARM_DESC(lock_norm, "Users can't change norm");
+module_param(lock_norm, int, 0644);
+MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
#ifdef CONFIG_VIDEO_V4L2
/* small helper function for calculating buffersizes for v4l2
@@ -250,7 +250,6 @@ static void jpg_fbuffer_free(struct file *file);
* Linux with the necessary memory left over).
*/
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
static unsigned long
get_high_mem (unsigned long size)
{
@@ -314,7 +313,6 @@ get_high_mem (unsigned long size)
return hi_mem_ph;
}
-#endif
static int
v4l_fbuffer_alloc (struct file *file)
@@ -323,9 +321,7 @@ v4l_fbuffer_alloc (struct file *file)
struct zoran *zr = fh->zr;
int i, off;
unsigned char *mem;
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
unsigned long pmem = 0;
-#endif
/* we might have old buffers lying around... */
if (fh->v4l_buffers.ready_to_be_freed) {
@@ -343,10 +339,7 @@ v4l_fbuffer_alloc (struct file *file)
if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
/* Use kmalloc */
- mem =
- (unsigned char *) kmalloc(fh->v4l_buffers.
- buffer_size,
- GFP_KERNEL);
+ mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
if (mem == 0) {
dprintk(1,
KERN_ERR
@@ -369,39 +362,6 @@ v4l_fbuffer_alloc (struct file *file)
ZR_DEVNAME(zr), i, (unsigned long) mem,
virt_to_bus(mem));
} else {
-#if defined(CONFIG_BIGPHYS_AREA)
- /* Use bigphysarea_alloc_pages */
-
- int n =
- (fh->v4l_buffers.buffer_size + PAGE_SIZE -
- 1) / PAGE_SIZE;
-
- mem =
- (unsigned char *) bigphysarea_alloc_pages(n, 0,
- GFP_KERNEL);
- if (mem == 0) {
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
- ZR_DEVNAME(zr), i);
- v4l_fbuffer_free(file);
- return -ENOBUFS;
- }
- fh->v4l_buffers.buffer[i].fbuffer = mem;
- fh->v4l_buffers.buffer[i].fbuffer_phys =
- virt_to_phys(mem);
- fh->v4l_buffers.buffer[i].fbuffer_bus =
- virt_to_bus(mem);
- dprintk(4,
- KERN_INFO
- "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
- ZR_DEVNAME(zr), i, (unsigned) mem,
- (unsigned) virt_to_bus(mem));
-
- /* Zero out the allocated memory */
- memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
- fh->v4l_buffers.buffer_size);
-#elif defined(BUZ_USE_HIMEM)
/* Use high memory which has been left at boot time */
@@ -441,20 +401,6 @@ v4l_fbuffer_alloc (struct file *file)
fh->v4l_buffers.buffer[i].fbuffer_bus =
pmem + i * fh->v4l_buffers.buffer_size;
}
-#else
- /* No bigphysarea present, usage of high memory disabled,
- * but user wants buffers of more than MAX_KMALLOC_MEM */
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
- ZR_DEVNAME(zr));
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
- ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
- fh->v4l_buffers.buffer_size >> 10);
- return -ENOBUFS;
-#endif
}
}
@@ -485,11 +431,6 @@ v4l_fbuffer_free (struct file *file)
ClearPageReserved(MAP_NR(mem + off));
kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
}
-#if defined(CONFIG_BIGPHYS_AREA)
- else
- bigphysarea_free_pages((void *) fh->v4l_buffers.
- buffer[i].fbuffer);
-#endif
fh->v4l_buffers.buffer[i].fbuffer = NULL;
}
@@ -831,13 +772,13 @@ v4l_grab (struct file *file,
struct zoran *zr = fh->zr;
int res = 0, i;
- for (i = 0; i < zoran_num_formats; i++) {
+ for (i = 0; i < NUM_FORMATS; i++) {
if (zoran_formats[i].palette == mp->format &&
zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE &&
!(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED))
break;
}
- if (i == zoran_num_formats || zoran_formats[i].depth == 0) {
+ if (i == NUM_FORMATS || zoran_formats[i].depth == 0) {
dprintk(1,
KERN_ERR
"%s: v4l_grab() - wrong bytes-per-pixel format\n",
@@ -1154,12 +1095,10 @@ jpg_sync (struct file *file,
frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
/* buffer should now be in BUZ_STATE_DONE */
- if (*zr_debug > 0)
- if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
- dprintk(2,
- KERN_ERR
- "%s: jpg_sync() - internal state error\n",
- ZR_DEVNAME(zr));
+ if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+ dprintk(2,
+ KERN_ERR "%s: jpg_sync() - internal state error\n",
+ ZR_DEVNAME(zr));
*bs = zr->jpg_buffers.buffer[frame].bs;
bs->frame = frame;
@@ -1236,10 +1175,14 @@ zoran_close_end_session (struct file *file)
/* v4l capture */
if (fh->v4l_buffers.active != ZORAN_FREE) {
+ long flags;
+
+ spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
zr->v4l_buffers.allocated = 0;
zr->v4l_buffers.active = fh->v4l_buffers.active =
ZORAN_FREE;
+ spin_unlock_irqrestore(&zr->spinlock, flags);
}
/* v4l buffers */
@@ -1433,7 +1376,7 @@ zoran_close (struct inode *inode,
/* disable interrupts */
btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
- if (*zr_debug > 1)
+ if (zr36067_debug > 1)
print_interrupts(zr);
/* Overlay off */
@@ -2170,7 +2113,7 @@ zoran_do_ioctl (struct inode *inode,
vpict->colour, vpict->contrast, vpict->depth,
vpict->palette);
- for (i = 0; i < zoran_num_formats; i++) {
+ for (i = 0; i < NUM_FORMATS; i++) {
const struct zoran_format *fmt = &zoran_formats[i];
if (fmt->palette != -1 &&
@@ -2179,7 +2122,7 @@ zoran_do_ioctl (struct inode *inode,
fmt->depth == vpict->depth)
break;
}
- if (i == zoran_num_formats) {
+ if (i == NUM_FORMATS) {
dprintk(1,
KERN_ERR
"%s: VIDIOCSPICT - Invalid palette %d\n",
@@ -2283,10 +2226,10 @@ zoran_do_ioctl (struct inode *inode,
ZR_DEVNAME(zr), vbuf->base, vbuf->width,
vbuf->height, vbuf->depth, vbuf->bytesperline);
- for (i = 0; i < zoran_num_formats; i++)
+ for (i = 0; i < NUM_FORMATS; i++)
if (zoran_formats[i].depth == vbuf->depth)
break;
- if (i == zoran_num_formats) {
+ if (i == NUM_FORMATS) {
dprintk(1,
KERN_ERR
"%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
@@ -2735,14 +2678,14 @@ zoran_do_ioctl (struct inode *inode,
return -EINVAL;
}
- for (i = 0; i < zoran_num_formats; i++) {
+ for (i = 0; i < NUM_FORMATS; i++) {
if (zoran_formats[i].flags & flag)
num++;
if (num == fmt->index)
break;
}
if (fmt->index < 0 /* late, but not too late */ ||
- i == zoran_num_formats)
+ i == NUM_FORMATS)
return -EINVAL;
memset(fmt, 0, sizeof(*fmt));
@@ -2800,7 +2743,8 @@ zoran_do_ioctl (struct inode *inode,
fmt->fmt.pix.height =
fh->v4l_settings.height;
fmt->fmt.pix.sizeimage =
- fh->v4l_buffers.buffer_size;
+ fh->v4l_settings.bytesperline *
+ fh->v4l_settings.height;
fmt->fmt.pix.pixelformat =
fh->v4l_settings.format->fourcc;
fmt->fmt.pix.colorspace =
@@ -3004,11 +2948,11 @@ zoran_do_ioctl (struct inode *inode,
sfmtjpg_unlock_and_return:
mutex_unlock(&zr->resource_lock);
} else {
- for (i = 0; i < zoran_num_formats; i++)
+ for (i = 0; i < NUM_FORMATS; i++)
if (fmt->fmt.pix.pixelformat ==
zoran_formats[i].fourcc)
break;
- if (i == zoran_num_formats) {
+ if (i == NUM_FORMATS) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
@@ -3047,8 +2991,9 @@ zoran_do_ioctl (struct inode *inode,
/* tell the user the
* results/missing stuff */
- fmt->fmt.pix.sizeimage = fh->v4l_buffers.buffer_size /*zr->gbpl * zr->gheight */
- ;
+ fmt->fmt.pix.sizeimage =
+ fh->v4l_settings.height *
+ fh->v4l_settings.bytesperline;
if (BUZ_MAX_HEIGHT <
(fh->v4l_settings.height * 2))
fmt->fmt.pix.field =
@@ -3116,10 +3061,10 @@ zoran_do_ioctl (struct inode *inode,
fb->fmt.bytesperline, fb->fmt.pixelformat,
(char *) &printformat);
- for (i = 0; i < zoran_num_formats; i++)
+ for (i = 0; i < NUM_FORMATS; i++)
if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
break;
- if (i == zoran_num_formats) {
+ if (i == NUM_FORMATS) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
@@ -3248,7 +3193,7 @@ zoran_do_ioctl (struct inode *inode,
"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
ZR_DEVNAME(zr), buf->index, buf->type);
- memset(buf, 0, sizeof(buf));
+ memset(buf, 0, sizeof(*buf));
buf->type = type;
buf->index = index;
@@ -3502,8 +3447,13 @@ zoran_do_ioctl (struct inode *inode,
goto strmoff_unlock_and_return;
/* unload capture */
- if (zr->v4l_memgrab_active)
+ if (zr->v4l_memgrab_active) {
+ long flags;
+
+ spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+ }
for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
zr->v4l_buffers.buffer[i].state =
@@ -3767,11 +3717,11 @@ zoran_do_ioctl (struct inode *inode,
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
ZR_DEVNAME(zr), (unsigned long long)*std);
- if (*std == V4L2_STD_PAL)
+ if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
norm = VIDEO_MODE_PAL;
- else if (*std == V4L2_STD_NTSC)
+ else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
norm = VIDEO_MODE_NTSC;
- else if (*std == V4L2_STD_SECAM)
+ else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
norm = VIDEO_MODE_SECAM;
else if (*std == V4L2_STD_ALL)
norm = VIDEO_MODE_AUTO;
@@ -4212,11 +4162,11 @@ zoran_do_ioctl (struct inode *inode,
V4L2_BUF_TYPE_VIDEO_CAPTURE) {
int i;
- for (i = 0; i < zoran_num_formats; i++)
+ for (i = 0; i < NUM_FORMATS; i++)
if (zoran_formats[i].fourcc ==
fmt->fmt.pix.pixelformat)
break;
- if (i == zoran_num_formats) {
+ if (i == NUM_FORMATS) {
res = -EINVAL;
goto tryfmt_unlock_and_return;
}
@@ -4276,8 +4226,8 @@ zoran_poll (struct file *file,
{
struct zoran_fh *fh = file->private_data;
struct zoran *zr = fh->zr;
- wait_queue_head_t *queue = NULL;
int res = 0, frame;
+ unsigned long flags;
/* we should check whether buffers are ready to be synced on
* (w/o waits - O_NONBLOCK) here
@@ -4291,51 +4241,58 @@ zoran_poll (struct file *file,
switch (fh->map_mode) {
case ZORAN_MAP_MODE_RAW:
- if (fh->v4l_buffers.active == ZORAN_FREE ||
- zr->v4l_pend_head == zr->v4l_pend_tail) {
- dprintk(1,
- "%s: zoran_poll() - no buffers queued\n",
- ZR_DEVNAME(zr));
- res = POLLNVAL;
- goto poll_unlock_and_return;
- }
- queue = &zr->v4l_capq;
- frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
- poll_wait(file, queue, wait);
- if (fh->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+ poll_wait(file, &zr->v4l_capq, wait);
+ frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+
+ spin_lock_irqsave(&zr->spinlock, flags);
+ dprintk(3,
+ KERN_DEBUG
+ "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
+ ZR_DEVNAME(zr), __FUNCTION__,
+ "FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
+ "UPMD"[zr->v4l_buffers.buffer[frame].state],
+ zr->v4l_pend_tail, zr->v4l_pend_head);
+ /* Process is the one capturing? */
+ if (fh->v4l_buffers.active != ZORAN_FREE &&
+ /* Buffer ready to DQBUF? */
+ zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
res = POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+
break;
case ZORAN_MAP_MODE_JPG_REC:
case ZORAN_MAP_MODE_JPG_PLAY:
- if (fh->jpg_buffers.active == ZORAN_FREE ||
- zr->jpg_que_head == zr->jpg_que_tail) {
- dprintk(1,
- "%s: zoran_poll() - no buffers queued\n",
- ZR_DEVNAME(zr));
- res = POLLNVAL;
- goto poll_unlock_and_return;
- }
- queue = &zr->jpg_capq;
+ poll_wait(file, &zr->jpg_capq, wait);
frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
- poll_wait(file, queue, wait);
- if (fh->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
+
+ spin_lock_irqsave(&zr->spinlock, flags);
+ dprintk(3,
+ KERN_DEBUG
+ "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
+ ZR_DEVNAME(zr), __FUNCTION__,
+ "FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
+ "UPMD"[zr->jpg_buffers.buffer[frame].state],
+ zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
+ if (fh->jpg_buffers.active != ZORAN_FREE &&
+ zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
res = POLLIN | POLLRDNORM;
else
res = POLLOUT | POLLWRNORM;
}
+ spin_unlock_irqrestore(&zr->spinlock, flags);
+
break;
default:
dprintk(1,
+ KERN_ERR
"%s: zoran_poll() - internal error, unknown map_mode=%d\n",
ZR_DEVNAME(zr), fh->map_mode);
res = POLLNVAL;
- goto poll_unlock_and_return;
}
-poll_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
@@ -4431,11 +4388,15 @@ zoran_vm_close (struct vm_area_struct *vma)
mutex_lock(&zr->resource_lock);
if (fh->v4l_buffers.active != ZORAN_FREE) {
+ long flags;
+
+ spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
zr->v4l_buffers.allocated = 0;
zr->v4l_buffers.active =
fh->v4l_buffers.active =
ZORAN_FREE;
+ spin_unlock_irqrestore(&zr->spinlock, flags);
}
//v4l_fbuffer_free(file);
fh->v4l_buffers.allocated = 0;
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index 446ae8d5c3df..328ed6e7ac6a 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -48,14 +48,7 @@
#include "videocodec.h"
#include "zoran.h"
#include "zoran_procfs.h"
-
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
+#include "zoran_card.h"
#ifdef CONFIG_PROC_FS
struct procfs_params_zr36067 {
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index 62f77584fb85..dd084555da8f 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -38,11 +38,11 @@
#include<linux/videodev.h> */
/* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
//#include<errno.h>
/* v4l API */
-#include<linux/videodev.h>
+#include <linux/videodev.h>
/* headerfile of this module */
#include"zr36016.h"
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index a6bbd125631c..9f622e00c479 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -38,14 +38,14 @@
#include<linux/videodev.h> */
/* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
//#include<errno.h>
/* headerfile of this module */
-#include"zr36050.h"
+#include "zr36050.h"
/* codec io API */
-#include"videocodec.h"
+#include "videocodec.h"
/* it doesn't make sense to have more than 20 or so,
just to prevent some unwanted loops */
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index 97c8f9b9dc12..1ef14fef08e6 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -38,14 +38,14 @@
#include<linux/videodev.h> */
/* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
//#include<errno.h>
/* headerfile of this module */
-#include"zr36060.h"
+#include "zr36060.h"
/* codec io API */
-#include"videocodec.h"
+#include "videocodec.h"
/* it doesn't make sense to have more than 20 or so,
just to prevent some unwanted loops */
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index b5d3364c94c7..6f1892585cbb 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -92,6 +92,7 @@ static struct usb_device_id device_table[] = {
{USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
{USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
{USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+ {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
{} /* Terminating entry */
};
@@ -792,6 +793,7 @@ static int zr364xx_probe(struct usb_interface *intf,
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ int err;
DBG("probing...");
@@ -799,12 +801,11 @@ static int zr364xx_probe(struct usb_interface *intf,
info("model %04x:%04x detected", udev->descriptor.idVendor,
udev->descriptor.idProduct);
- if ((cam =
- kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+ cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
+ if (cam == NULL) {
info("cam: out of memory !");
- return -ENODEV;
+ return -ENOMEM;
}
- memset(cam, 0x00, sizeof(struct zr364xx_camera));
/* save the init method used by this camera */
cam->method = id->driver_info;
@@ -812,7 +813,7 @@ static int zr364xx_probe(struct usb_interface *intf,
if (cam->vdev == NULL) {
info("cam->vdev: out of memory !");
kfree(cam);
- return -ENODEV;
+ return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
video_set_drvdata(cam->vdev, cam);
@@ -858,12 +859,13 @@ static int zr364xx_probe(struct usb_interface *intf,
cam->brightness = 64;
mutex_init(&cam->lock);
- if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+ err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (err) {
info("video_register_device failed");
video_device_release(cam->vdev);
kfree(cam->buffer);
kfree(cam);
- return -ENODEV;
+ return err;
}
usb_set_intfdata(intf, cam);
@@ -905,7 +907,7 @@ static struct usb_driver zr364xx_driver = {
static int __init zr364xx_init(void)
{
int retval;
- retval = usb_register(&zr364xx_driver) < 0;
+ retval = usb_register(&zr364xx_driver);
if (retval)
info("usb_register failed!");
else
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index c88cc75ab49b..f55cc03a75c9 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -37,6 +37,7 @@ config FUSION_FC
LSIFC929
LSIFC929X
LSIFC929XL
+ Brocade FC 410/420
config FUSION_SAS
tristate "Fusion MPT ScsiHost drivers for SAS"
@@ -101,4 +102,18 @@ config FUSION_LAN
If unsure whether you really want or need this, say N.
+config FUSION_LOGGING
+ bool "Fusion MPT logging facility"
+ depends on FUSION
+ ---help---
+ This turns on a logging facility that can be used to debug a number
+ of Fusion MPT related problems.
+
+ The debug level can be programmed on the fly via SysFS (hex values)
+
+ echo [level] > /sys/class/scsi_host/host#/debug_level
+
+ There are various debug levels that an be found in the source:
+ file:drivers/message/fusion/mptdebug.h
+
endmenu
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
index 6003b46c8438..95c9532cb07c 100644
--- a/drivers/message/fusion/Makefile
+++ b/drivers/message/fusion/Makefile
@@ -1,39 +1,8 @@
# Fusion MPT drivers; recognized debug defines...
-# MPT general:
-#EXTRA_CFLAGS += -DMPT_DEBUG
-#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
-#EXTRA_CFLAGS += -DMPT_DEBUG_SG
-#EXTRA_CFLAGS += -DMPT_DEBUG_EVENTS
-#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE_EVENTS
-#EXTRA_CFLAGS += -DMPT_DEBUG_INIT
-#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
-#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
-#EXTRA_CFLAGS += -DMPT_DEBUG_DV
-#EXTRA_CFLAGS += -DMPT_DEBUG_TM
-#EXTRA_CFLAGS += -DMPT_DEBUG_REPLY
-#
-# driver/module specifics...
-#
-# For mptbase:
-#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
-#CFLAGS_mptbase.o += -DMPT_DEBUG_CONFIG
-#CFLAGS_mptbase.o += -DMPT_DEBUG_DL
-#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
-#CFLAGS_mptbase.o += -DMPT_DEBUG_RESET
-#
-# For mptscsih:
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCSI
-#
-# For mptctl:
-#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
-#
-# For mptfc:
-#CFLAGS_mptfc.o += -DMPT_DEBUG_FC
-
-# For mptsas:
-#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS
-#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS_WIDE
+# enable verbose logging
+# CONFIG_FUSION_LOGGING needs to be enabled in Kconfig
+#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5a10c87239c2..414c109f4cf5 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -87,6 +87,12 @@ static int mpt_channel_mapping;
module_param(mpt_channel_mapping, int, 0);
MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
+static int mpt_debug_level;
+static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
+module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
+ &mpt_debug_level, 0600);
+MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
+
#ifdef MFCNT
static int mfcounter = 0;
#define PRINT_MF_COUNT 20000
@@ -161,6 +167,7 @@ static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
static void mpt_timer_expired(unsigned long data);
+static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
@@ -178,9 +185,7 @@ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
-#ifdef MPT_DEBUG_REPLY
static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
-#endif
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
@@ -217,6 +222,19 @@ pci_enable_io_access(struct pci_dev *pdev)
pci_write_config_word(pdev, PCI_COMMAND, command_reg);
}
+static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+ MPT_ADAPTER *ioc;
+
+ if (ret)
+ return ret;
+
+ list_for_each_entry(ioc, &ioc_list, list)
+ ioc->debug_level = mpt_debug_level;
+ return 0;
+}
+
/*
* Process turbo (context) reply...
*/
@@ -228,7 +246,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
int req_idx = 0;
int cb_idx;
- dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
ioc->name, pa));
switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
@@ -311,9 +329,9 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
- dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
- DBG_DUMP_REPLY_FRAME(mr)
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr)
/* Check/log IOC log info
*/
@@ -328,10 +346,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
mpt_sas_log_info(ioc, log_info);
}
-#ifdef MPT_DEBUG_REPLY
if (ioc_stat & MPI_IOCSTATUS_MASK)
mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
-#endif
/* Check for (valid) IO callback! */
if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
@@ -413,17 +429,17 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
int freereq = 1;
u8 func;
- dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
-
-#if defined(MPT_DEBUG_MSG_FRAME)
- if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
- dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
- DBG_DUMP_REQUEST_FRAME_HDR(mf)
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
+#ifdef CONFIG_FUSION_LOGGING
+ if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
+ !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+ dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
+ DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
}
#endif
func = reply->u.hdr.Function;
- dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
ioc->name, func));
if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
@@ -434,7 +450,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
if (results != evHandlers) {
/* CHECKME! Any special handling needed here? */
- devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
ioc->name, evHandlers, results));
}
@@ -445,7 +461,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
freereq = 0;
} else {
- devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
ioc->name, pEvReply));
}
@@ -454,13 +470,13 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
#endif
} else if (func == MPI_FUNCTION_EVENT_ACK) {
- dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
ioc->name));
} else if (func == MPI_FUNCTION_CONFIG) {
CONFIGPARMS *pCfg;
unsigned long flags;
- dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
ioc->name, mf, reply));
pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
@@ -483,7 +499,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
u16 status;
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+ dcprintk(ioc, printk(KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
status, le32_to_cpu(pReply->IOCLogInfo)));
pCfg->status = status;
@@ -788,7 +804,7 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
#endif
- dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
+ dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
ioc->name, handle, ioc->id, mf));
return mf;
}
@@ -819,27 +835,10 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
-#ifdef MPT_DEBUG_MSG_FRAME
- {
- u32 *m = mf->u.frame.hwhdr.__hdr;
- int ii, n;
-
- printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
- ioc->name, m);
- n = ioc->req_sz/4 - 1;
- while (m[n] == 0)
- n--;
- for (ii=0; ii<=n; ii++) {
- if (ii && ((ii%8)==0))
- printk("\n" KERN_INFO " ");
- printk(" %08x", le32_to_cpu(m[ii]));
- }
- printk("\n");
- }
-#endif
+ DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
- dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
}
@@ -954,7 +953,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
return -5;
- dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+ dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
ioc->name, ii));
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -1065,7 +1064,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
host_page_buffer_sz,
&ioc->HostPageBuffer_dma)) != NULL) {
- dinitprintk((MYIOC_s_INFO_FMT
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
ioc->name, ioc->HostPageBuffer,
(u32)ioc->HostPageBuffer_dma,
@@ -1131,6 +1130,248 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
return -1;
}
+/**
+ * mpt_get_product_name - returns product string
+ * @vendor: pci vendor id
+ * @device: pci device id
+ * @revision: pci revision id
+ * @prod_name: string returned
+ *
+ * Returns product string displayed when driver loads,
+ * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
+ *
+ **/
+static void
+mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
+{
+ char *product_str = NULL;
+
+ if (vendor == PCI_VENDOR_ID_BROCADE) {
+ switch (device)
+ {
+ case MPI_MANUFACTPAGE_DEVICEID_FC949E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "BRE040 A0";
+ break;
+ case 0x01:
+ product_str = "BRE040 A1";
+ break;
+ default:
+ product_str = "BRE040";
+ break;
+ }
+ break;
+ }
+ goto out;
+ }
+
+ switch (device)
+ {
+ case MPI_MANUFACTPAGE_DEVICEID_FC909:
+ product_str = "LSIFC909 B1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC919:
+ product_str = "LSIFC919 B0";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC929:
+ product_str = "LSIFC929 B0";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC919X:
+ if (revision < 0x80)
+ product_str = "LSIFC919X A0";
+ else
+ product_str = "LSIFC919XL A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC929X:
+ if (revision < 0x80)
+ product_str = "LSIFC929X A0";
+ else
+ product_str = "LSIFC929XL A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+ product_str = "LSIFC939X A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+ product_str = "LSIFC949X A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC949E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSIFC949E A0";
+ break;
+ case 0x01:
+ product_str = "LSIFC949E A1";
+ break;
+ default:
+ product_str = "LSIFC949E";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_53C1030:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSI53C1030 A0";
+ break;
+ case 0x01:
+ product_str = "LSI53C1030 B0";
+ break;
+ case 0x03:
+ product_str = "LSI53C1030 B1";
+ break;
+ case 0x07:
+ product_str = "LSI53C1030 B2";
+ break;
+ case 0x08:
+ product_str = "LSI53C1030 C0";
+ break;
+ case 0x80:
+ product_str = "LSI53C1030T A0";
+ break;
+ case 0x83:
+ product_str = "LSI53C1030T A2";
+ break;
+ case 0x87:
+ product_str = "LSI53C1030T A3";
+ break;
+ case 0xc1:
+ product_str = "LSI53C1020A A1";
+ break;
+ default:
+ product_str = "LSI53C1030";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
+ switch (revision)
+ {
+ case 0x03:
+ product_str = "LSI53C1035 A2";
+ break;
+ case 0x04:
+ product_str = "LSI53C1035 B0";
+ break;
+ default:
+ product_str = "LSI53C1035";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1064:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1064 A1";
+ break;
+ case 0x01:
+ product_str = "LSISAS1064 A2";
+ break;
+ case 0x02:
+ product_str = "LSISAS1064 A3";
+ break;
+ case 0x03:
+ product_str = "LSISAS1064 A4";
+ break;
+ default:
+ product_str = "LSISAS1064";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1064E A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1064E B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1064E B1";
+ break;
+ case 0x04:
+ product_str = "LSISAS1064E B2";
+ break;
+ case 0x08:
+ product_str = "LSISAS1064E B3";
+ break;
+ default:
+ product_str = "LSISAS1064E";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1068:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1068 A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1068 B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1068 B1";
+ break;
+ default:
+ product_str = "LSISAS1068";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1068E A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1068E B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1068E B1";
+ break;
+ case 0x04:
+ product_str = "LSISAS1068E B2";
+ break;
+ case 0x08:
+ product_str = "LSISAS1068E B3";
+ break;
+ default:
+ product_str = "LSISAS1068E";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1078:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1078 A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1078 B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1078 C0";
+ break;
+ case 0x03:
+ product_str = "LSISAS1078 C1";
+ break;
+ case 0x04:
+ product_str = "LSISAS1078 C2";
+ break;
+ default:
+ product_str = "LSISAS1078";
+ break;
+ }
+ break;
+ }
+
+ out:
+ if (product_str)
+ sprintf(prod_name, "%s", product_str);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_attach - Install a PCI intelligent MPT adapter.
@@ -1167,31 +1408,37 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
struct proc_dir_entry *dent, *ent;
#endif
+ ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+ if (ioc == NULL) {
+ printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+ return -ENOMEM;
+ }
+
+ ioc->debug_level = mpt_debug_level;
+ if (mpt_debug_level)
+ printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+
if (pci_enable_device(pdev))
return r;
- dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+ dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- dprintk((KERN_INFO MYNAM
+ dprintk(ioc, printk(KERN_INFO MYNAM
": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
} else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
return r;
}
- if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
- dprintk((KERN_INFO MYNAM
+ if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+ dprintk(ioc, printk(KERN_INFO MYNAM
": Using 64 bit consistent mask\n"));
- else
- dprintk((KERN_INFO MYNAM
+ } else {
+ dprintk(ioc, printk(KERN_INFO MYNAM
": Not using 64 bit consistent mask\n"));
-
- ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
- if (ioc == NULL) {
- printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
- return -ENOMEM;
}
+
ioc->alloc_total = sizeof(MPT_ADAPTER);
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
@@ -1259,9 +1506,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
return -EINVAL;
}
ioc->memmap = mem;
- dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+ dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
- dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
+ dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
&ioc->facts, &ioc->pfacts[0]));
ioc->mem_phys = mem_phys;
@@ -1274,23 +1521,23 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
}
- if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
- ioc->prod_name = "LSIFC909";
- ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
- ioc->prod_name = "LSIFC929";
- ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
- ioc->prod_name = "LSIFC919";
- ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
+
+ switch (pdev->device)
+ {
+ case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+ case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+ ioc->errata_flag_1064 = 1;
+ case MPI_MANUFACTPAGE_DEVICEID_FC909:
+ case MPI_MANUFACTPAGE_DEVICEID_FC929:
+ case MPI_MANUFACTPAGE_DEVICEID_FC919:
+ case MPI_MANUFACTPAGE_DEVICEID_FC949E:
ioc->bus_type = FC;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVICEID_FC929X:
if (revision < XL_929) {
- ioc->prod_name = "LSIFC929X";
/* 929X Chip Fix. Set Split transactions level
* for PCIX. Set MOST bits to zero.
*/
@@ -1298,75 +1545,46 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
pcixcmd &= 0x8F;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
} else {
- ioc->prod_name = "LSIFC929XL";
/* 929XL Chip Fix. Set MMRBC to 0x08.
*/
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
pcixcmd |= 0x08;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
}
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
- ioc->prod_name = "LSIFC919X";
ioc->bus_type = FC;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVICEID_FC919X:
/* 919X Chip Fix. Set Split transactions level
* for PCIX. Set MOST bits to zero.
*/
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
pcixcmd &= 0x8F;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
- ioc->prod_name = "LSIFC939X";
- ioc->bus_type = FC;
- ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
- ioc->prod_name = "LSIFC949X";
- ioc->bus_type = FC;
- ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
- ioc->prod_name = "LSIFC949E";
ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
- ioc->prod_name = "LSI53C1030";
- ioc->bus_type = SPI;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVID_53C1030:
/* 1030 Chip Fix. Disable Split transactions
* for PCIX. Set MOST bits to zero if Rev < C0( = 8).
*/
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
if (revision < C0_1030) {
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
pcixcmd &= 0x8F;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
}
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
- ioc->prod_name = "LSI53C1035";
+
+ case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
ioc->bus_type = SPI;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
- ioc->prod_name = "LSISAS1064";
- ioc->bus_type = SAS;
- ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
- ioc->prod_name = "LSISAS1068";
- ioc->bus_type = SAS;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVID_SAS1064:
+ case MPI_MANUFACTPAGE_DEVID_SAS1068:
ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
- ioc->prod_name = "LSISAS1064E";
- ioc->bus_type = SAS;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
- ioc->prod_name = "LSISAS1068E";
- ioc->bus_type = SAS;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
- ioc->prod_name = "LSISAS1078";
+
+ case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+ case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+ case MPI_MANUFACTPAGE_DEVID_SAS1078:
ioc->bus_type = SAS;
}
@@ -1616,6 +1834,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
int ret = 0;
int reset_alt_ioc_active = 0;
int irq_allocated = 0;
+ u8 *a;
printk(KERN_INFO MYNAM ": Initiating %s %s\n",
ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
@@ -1644,7 +1863,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
- dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+ dprintk(ioc, printk(KERN_INFO MYNAM
+ ": alt-%s reply irq re-enabled\n",
ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
@@ -1677,7 +1897,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (ii == 5) {
- dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
ret = -2;
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
MptDisplayIocCapabilities(ioc);
@@ -1685,13 +1905,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (alt_ioc_ready) {
if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
- dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
/* Retry - alt IOC was initialized once
*/
rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
}
if (rc) {
- dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
@@ -1724,7 +1946,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
ioc->pci_irq = ioc->pcidev->irq;
pci_set_master(ioc->pcidev); /* ?? */
pci_set_drvdata(ioc->pcidev, ioc);
- dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
+ dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
"%d\n", ioc->name, ioc->pcidev->irq));
}
}
@@ -1762,7 +1984,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
if (ioc->upload_fw) {
- ddlprintk((MYIOC_s_INFO_FMT
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"firmware upload required!\n", ioc->name));
/* Controller is not operational, cannot do upload
@@ -1778,7 +2000,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* chips (mpt_adapter_disable,
* mpt_diag_reset)
*/
- ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": mpt_upload: alt_%s has cached_fw=%p \n",
ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
ioc->alt_ioc->cached_fw = NULL;
}
@@ -1798,7 +2021,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt) */
- dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+ dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
@@ -1850,13 +2073,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* (LANPage1_t stuff)
*/
(void) GetLanConfigPages(ioc);
-#ifdef MPT_DEBUG
- {
- u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
- dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
- ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
- }
-#endif
+ a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "LanAddr = %02X:%02X:%02X:"
+ "%02X:%02X:%02X\n",
+ ioc->name, a[5], a[4],
+ a[3], a[2], a[1], a[0] ));
+
}
} else {
/* Get NVRAM and adapter maximums from SPP 0 and 2
@@ -1880,6 +2103,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
}
GetIoUnitPage2(ioc);
+ mpt_get_manufacturing_pg_0(ioc);
}
/*
@@ -1892,15 +2116,17 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
rc = handlers = 0;
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
if ((ret == 0) && MptResetHandlers[ii]) {
- dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
- ioc->name, ii));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Calling IOC post_reset handler #%d\n",
+ ioc->name, ii));
rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
handlers++;
}
if (alt_ioc_ready && MptResetHandlers[ii]) {
- drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Calling alt-%s post_reset handler #%d\n",
+ ioc->name, ioc->alt_ioc->name, ii));
rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
handlers++;
}
@@ -1938,7 +2164,7 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
unsigned int func = PCI_FUNC(pdev->devfn);
MPT_ADAPTER *ioc_srch;
- dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
" searching for devfn match on %x or %x\n",
ioc->name, pci_name(pdev), pdev->bus->number,
pdev->devfn, func-1, func+1));
@@ -1963,7 +2189,7 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
ioc_srch->name, ioc_srch->alt_ioc->name);
break;
}
- dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+ dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
ioc->name, ioc_srch->name));
ioc_srch->alt_ioc = ioc;
ioc->alt_ioc = ioc_srch;
@@ -1984,7 +2210,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
int ret;
if (ioc->cached_fw != NULL) {
- ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
+ ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
printk(KERN_WARNING MYNAM
": firmware downloadboot failure (%d)!\n", ret);
@@ -1999,7 +2225,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
if (ioc->alloc != NULL) {
sz = ioc->alloc_sz;
- dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
+ dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
ioc->name, ioc->alloc, ioc->alloc_sz));
pci_free_consistent(ioc->pcidev, sz,
ioc->alloc, ioc->alloc_dma);
@@ -2041,7 +2267,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
if (ioc->spi_data.pIocPg4 != NULL) {
sz = ioc->spi_data.IocPg4Sz;
- pci_free_consistent(ioc->pcidev, sz,
+ pci_free_consistent(ioc->pcidev, sz,
ioc->spi_data.pIocPg4,
ioc->spi_data.IocPg4_dma);
ioc->spi_data.pIocPg4 = NULL;
@@ -2064,7 +2290,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
": %s: host page buffers free failed (%d)!\n",
__FUNCTION__, ret);
}
- dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
+ dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
ioc->HostPageBuffer,
@@ -2110,7 +2336,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
#if defined(CONFIG_MTRR) && 0
if (ioc->mtrr_reg > 0) {
mtrr_del(ioc->mtrr_reg, 0, 0);
- dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
+ dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
}
#endif
@@ -2118,7 +2344,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
list_del(&ioc->list);
sz_last = ioc->alloc_total;
- dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+ dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
if (ioc->alt_ioc)
@@ -2138,8 +2364,8 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
int i = 0;
printk(KERN_INFO "%s: ", ioc->name);
- if (ioc->prod_name && strlen(ioc->prod_name) > 3)
- printk("%s: ", ioc->prod_name+3);
+ if (ioc->prod_name)
+ printk("%s: ", ioc->prod_name);
printk("Capabilities={");
if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
@@ -2198,7 +2424,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
/* Get current [raw] IOC state */
ioc_state = mpt_GetIocState(ioc, 0);
- dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+ dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
/*
* Check to see if IOC got left/stuck in doorbell handshake
@@ -2229,7 +2455,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
* Hmmm... Did it get left operational?
*/
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
- dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
ioc->name));
/* Check WhoInit.
@@ -2238,7 +2464,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
* Else, fall through to KickStart case
*/
whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
- dinitprintk((KERN_INFO MYNAM
+ dinitprintk(ioc, printk(KERN_INFO MYNAM
": whoinit 0x%x statefault %d force %d\n",
whoinit, statefault, force));
if (whoinit == MPI_WHOINIT_PCI_PEER)
@@ -2374,7 +2600,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
get_facts.Function = MPI_FUNCTION_IOC_FACTS;
/* Assert: All other get_facts fields are zero! */
- dinitprintk((MYIOC_s_INFO_FMT
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Sending get IocFacts request req_sz=%d reply_sz=%d\n",
ioc->name, req_sz, reply_sz));
@@ -2476,8 +2702,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
sz = sz >> 1;
}
ioc->NBShiftFactor = shiftFactor;
- dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
- ioc->name, vv, shiftFactor, r));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
+ ioc->name, vv, shiftFactor, r));
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
/*
@@ -2489,9 +2716,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
- dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
ioc->name, ioc->reply_sz, ioc->reply_depth));
- dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
ioc->name, ioc->req_sz, ioc->req_depth));
/* Get port facts! */
@@ -2550,7 +2777,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
get_pfacts.PortNumber = portnum;
/* Assert: All other get_pfacts fields are zero! */
- dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
ioc->name, portnum));
/* No non-zero fields in the get_pfacts request are greater than
@@ -2626,12 +2853,12 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
ioc->upload_fw = 1;
else
ioc->upload_fw = 0;
- ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
ioc->name, ioc->upload_fw, ioc->facts.Flags));
ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
ioc_init.MaxBuses = (U8)ioc->number_of_buses;
- dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
ioc->name, ioc->facts.MsgVersion));
if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
// set MsgVersion and HeaderVersion host driver was built with
@@ -2662,7 +2889,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
ioc->facts.MaxDevices = ioc_init.MaxDevices;
ioc->facts.MaxBuses = ioc_init.MaxBuses;
- dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
ioc->name, &ioc_init));
r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
@@ -2676,7 +2903,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
* since we don't even look at its contents.
*/
- dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
ioc->name, &ioc_init));
if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
@@ -2707,7 +2934,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
state = mpt_GetIocState(ioc, 1);
count++;
}
- dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
ioc->aen_event_read_flag=0;
@@ -2747,7 +2974,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
/* port_enable.MsgFlags = 0; */
/* port_enable.MsgContext = 0; */
- dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
ioc->name, portnum, &port_enable));
/* RAID FW may take a long time to enable
@@ -2800,7 +3027,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
int sz;
sz = ioc->facts.FWImageSize;
- dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
pci_free_consistent(ioc->pcidev, sz,
ioc->cached_fw, ioc->cached_fw_dma);
@@ -2844,7 +3071,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
mpt_alloc_fw_memory(ioc, sz);
- dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
if (ioc->cached_fw == NULL) {
@@ -2876,14 +3103,14 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
- dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
+ dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
prequest, sgeoffset));
- DBG_DUMP_FW_REQUEST_FRAME(prequest)
+ DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
- dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
+ dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
cmdStatus = -EFAULT;
if (ii == 0) {
@@ -2898,13 +3125,13 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
cmdStatus = 0;
}
}
- dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
ioc->name, cmdStatus));
if (cmdStatus) {
- ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
ioc->name));
mpt_free_fw_memory(ioc);
}
@@ -2939,7 +3166,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
u32 load_addr;
u32 ioc_state=0;
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
@@ -2964,7 +3191,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
for (count = 0; count < 30; count ++) {
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
- ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
ioc->name, count));
break;
}
@@ -2977,7 +3204,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
}
if ( count == 30 ) {
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
"Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
ioc->name, diag0val));
return -3;
@@ -3003,10 +3230,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
pci_enable_io_access(ioc->pcidev);
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
- ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
ioc->name, pFwHeader->LoadStartAddress));
- ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
ioc->name, fwSize*4, ptrFw));
while (fwSize--) {
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
@@ -3021,7 +3248,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
fwSize = (pExtImage->ImageSize + 3) >> 2;
ptrFw = (u32 *)pExtImage;
- ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
@@ -3032,11 +3259,11 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
}
/* Write the IopResetVectorRegAddr */
- ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
/* Write the IopResetVectorValue */
- ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
/* Clear the internal flash bad bit - autoincrementing register,
@@ -3070,11 +3297,11 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
pci_disable_io_access(ioc->pcidev);
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
"turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
ioc->name, diag0val));
diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
ioc->name, diag0val));
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
@@ -3085,7 +3312,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
ioc_state = mpt_GetIocState(ioc, 0);
if ( (GetIocFacts(ioc, sleepFlag,
MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
- ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
ioc->name, ioc_state));
return -EFAULT;
}
@@ -3093,17 +3320,20 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
for (count=0; count<HZ*20; count++) {
if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
- ioc->name, count, ioc_state));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "downloadboot successful! (count=%d) IocState=%x\n",
+ ioc->name, count, ioc_state));
if (ioc->bus_type == SAS) {
return 0;
}
if ((SendIocInit(ioc, sleepFlag)) != 0) {
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "downloadboot: SendIocInit failed\n",
ioc->name));
return -EFAULT;
}
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "downloadboot: SendIocInit successful\n",
ioc->name));
return 0;
}
@@ -3113,8 +3343,8 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
mdelay (10);
}
}
- ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
- ioc->name, ioc_state));
+ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
return -EFAULT;
}
@@ -3151,7 +3381,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
u32 ioc_state=0;
int cnt,cntdn;
- dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+ dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
if (ioc->bus_type == SPI) {
/* Always issue a Msg Unit Reset first. This will clear some
* SCSI bus hang conditions.
@@ -3169,14 +3399,14 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
if (hard_reset_done < 0)
return hard_reset_done;
- dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
ioc->name));
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
for (cnt=0; cnt<cntdn; cnt++) {
ioc_state = mpt_GetIocState(ioc, 1);
if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
- dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
ioc->name, cnt));
return hard_reset_done;
}
@@ -3219,15 +3449,13 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
u32 doorbell;
int hard_reset_done = 0;
int count = 0;
-#ifdef MPT_DEBUG
u32 diag1val = 0;
-#endif
/* Clear any existing interrupts */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
- drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
+ drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
"address=%p\n", ioc->name, __FUNCTION__,
&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
@@ -3240,7 +3468,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
doorbell &= MPI_IOC_STATE_MASK;
- drsprintk((MYIOC_s_INFO_FMT
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"looking for READY STATE: doorbell=%x"
" count=%d\n",
ioc->name, doorbell, count));
@@ -3260,12 +3488,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
/* Use "Diagnostic reset" method! (only thing available!) */
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-#ifdef MPT_DEBUG
- if (ioc->alt_ioc)
- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+ if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
-#endif
+ }
/* Do the reset if we are told to ignore the reset history
* or if the reset history is 0
@@ -3299,16 +3527,16 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
- dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
ioc->name, diag0val));
}
-#ifdef MPT_DEBUG
- if (ioc->alt_ioc)
- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+ if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
-#endif
+ }
/*
* Disable the ARM (Bug fix)
*
@@ -3322,7 +3550,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
*/
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
hard_reset_done = 1;
- dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
ioc->name));
/*
@@ -3337,12 +3565,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
if (MptResetHandlers[ii]) {
- dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
- ioc->name, ii));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Calling IOC pre_reset handler #%d\n",
+ ioc->name, ii));
r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
if (ioc->alt_ioc) {
- dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Calling alt-%s pre_reset handler #%d\n",
+ ioc->name, ioc->alt_ioc->name, ii));
r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
}
}
@@ -3365,7 +3595,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
break;
}
- dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
iocp->name, diag0val, count));
/* wait 1 sec */
if (sleepFlag == CAN_SLEEP) {
@@ -3406,12 +3636,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
}
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-#ifdef MPT_DEBUG
- if (ioc->alt_ioc)
- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
- ioc->name, diag0val, diag1val));
-#endif
+ if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+ }
/* Clear RESET_HISTORY bit! Place board in the
* diagnostic mode to update the diag register.
@@ -3465,12 +3695,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
return -3;
}
-#ifdef MPT_DEBUG
- if (ioc->alt_ioc)
- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
+ if (ioc->debug_level & MPT_DEBUG) {
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
-#endif
+ }
/*
* Reset flag that says we've enabled event notification
@@ -3502,7 +3732,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
u32 state;
int cntdn, count;
- drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
ioc->name, reset_type));
CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
@@ -3567,14 +3797,14 @@ initChainBuffers(MPT_ADAPTER *ioc)
return -1;
ioc->ReqToChain = (int *) mem;
- dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
ioc->name, mem, sz));
mem = kmalloc(sz, GFP_ATOMIC);
if (mem == NULL)
return -1;
ioc->RequestNB = (int *) mem;
- dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
ioc->name, mem, sz));
}
for (ii = 0; ii < ioc->req_depth; ii++) {
@@ -3604,7 +3834,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
(ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
}
- dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
ioc->name, num_sge, numSGE));
if ( numSGE > MPT_SCSI_SG_DEPTH )
@@ -3617,7 +3847,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
}
num_chain++;
- dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
ioc->name, numSGE, num_sge, num_chain));
if (ioc->bus_type == SPI)
@@ -3634,7 +3864,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
return -1;
ioc->ChainToChain = (int *) mem;
- dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
ioc->name, mem, sz));
} else {
mem = (u8 *) ioc->ChainToChain;
@@ -3670,22 +3900,22 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
return -1;
total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
- dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
ioc->name, ioc->reply_sz, ioc->reply_depth));
- dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
ioc->name, reply_sz, reply_sz));
sz = (ioc->req_sz * ioc->req_depth);
- dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
ioc->name, ioc->req_sz, ioc->req_depth));
- dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
ioc->name, sz, sz));
total_size += sz;
sz = num_chain * ioc->req_sz; /* chain buffer pool size */
- dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
ioc->name, ioc->req_sz, num_chain));
- dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
ioc->name, sz, sz, num_chain));
total_size += sz;
@@ -3696,7 +3926,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
goto out_fail;
}
- dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
memset(mem, 0, total_size);
@@ -3707,7 +3937,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
ioc->reply_frames = (MPT_FRAME_HDR *) mem;
ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
- dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
alloc_dma += reply_sz;
@@ -3718,7 +3948,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
ioc->req_frames = (MPT_FRAME_HDR *) mem;
ioc->req_frames_dma = alloc_dma;
- dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
ioc->name, mem, (void *)(ulong)alloc_dma));
ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
@@ -3732,7 +3962,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
sz,
MTRR_TYPE_WRCOMB, 1);
- dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
ioc->name, ioc->req_frames_dma, sz));
#endif
@@ -3744,7 +3974,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
ioc->ChainBuffer = mem;
ioc->ChainBufferDMA = alloc_dma;
- dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
/* Initialize the free chain Q.
@@ -3789,7 +4019,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
ioc->alloc_total += sz;
- dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
}
@@ -3797,7 +4027,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
/* Post Reply frames to FIFO
*/
alloc_dma = ioc->alloc_dma;
- dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
for (i = 0; i < ioc->reply_depth; i++) {
@@ -3878,7 +4108,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
failcnt++;
- dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
/* Read doorbell and check for active bit */
@@ -3913,10 +4143,10 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
failcnt++;
}
- dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
- DBG_DUMP_REQUEST_FRAME_HDR(req)
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
+ DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
- dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
/*
@@ -3925,7 +4155,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
failcnt++;
- dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
/*
@@ -3981,7 +4211,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
}
if (cntdn) {
- dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
ioc->name, count));
return count;
}
@@ -4030,7 +4260,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
}
if (cntdn) {
- dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
ioc->name, count, howlong));
return count;
}
@@ -4082,7 +4312,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
}
}
- dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
@@ -4118,10 +4348,10 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
}
#endif
- dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
- DBG_DUMP_REPLY_FRAME(mptReply)
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
- dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
ioc->name, t, u16cnt/2));
return u16cnt/2;
}
@@ -4546,7 +4776,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
ioc->spi_data.nvram = (int *) mem;
- dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
ioc->name, ioc->spi_data.nvram, sz));
}
@@ -4582,7 +4812,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
ioc->spi_data.minSyncFactor = MPT_ASYNC;
ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
rc = 1;
- ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Unable to read PortPage0 minSyncFactor=%x\n",
ioc->name, ioc->spi_data.minSyncFactor));
} else {
/* Save the Port Page 0 data
@@ -4593,7 +4824,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
- ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
+ ddvprintk(ioc, printk(KERN_INFO MYNAM
+ " :%s noQas due to Capabilities=%x\n",
ioc->name, pPP0->Capabilities));
}
ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4602,7 +4834,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
ioc->spi_data.minSyncFactor = (u8) (data >> 8);
- ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "PortPage0 minSyncFactor=%x\n",
ioc->name, ioc->spi_data.minSyncFactor));
} else {
ioc->spi_data.maxSyncOffset = 0;
@@ -4618,7 +4851,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
ioc->spi_data.minSyncFactor = MPT_ULTRA;
- ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "HVD or SE detected, minSyncFactor=%x\n",
ioc->name, ioc->spi_data.minSyncFactor));
}
}
@@ -4734,10 +4968,10 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
- dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
- dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
return 0;
}
@@ -5146,12 +5380,12 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
cfg.physAddr = ioc1_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
-
+
tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
- dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
ioc->name, tmp));
if (tmp > MPT_COALESCING_TIMEOUT) {
@@ -5162,26 +5396,29 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
cfg.dir = 1;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
- dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
ioc->name, MPT_COALESCING_TIMEOUT));
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
if (mpt_config(ioc, &cfg) == 0) {
- dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Reset NVRAM Coalescing Timeout to = %d\n",
ioc->name, MPT_COALESCING_TIMEOUT));
} else {
- dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
- ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Reset NVRAM Coalescing Timeout Failed\n",
+ ioc->name));
}
} else {
- dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
- ioc->name));
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT
+ "Reset of Current Coalescing Timeout Failed!\n",
+ ioc->name));
}
}
} else {
- dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
}
}
@@ -5190,6 +5427,49 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
return;
}
+static void
+mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
+{
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+ dma_addr_t buf_dma;
+ ManufacturingPage0_t *pbuf = NULL;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+ hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.timeout = 10;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ if (!cfg.cfghdr.hdr->PageLength)
+ goto out;
+
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+ if (!pbuf)
+ goto out;
+
+ cfg.physAddr = buf_dma;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
+ memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
+ memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
+
+ out:
+
+ if (pbuf)
+ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendEventNotification - Send EventNotification (on or off) request to adapter
@@ -5203,13 +5483,13 @@ SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
if (evnp == NULL) {
- devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
ioc->name));
return 0;
}
memset(evnp, 0, sizeof(*evnp));
- devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
evnp->ChainOffset = 0;
@@ -5233,12 +5513,12 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
EventAck_t *pAck;
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
- dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
ioc->name,__FUNCTION__));
return -1;
}
- devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
pAck->Function = MPI_FUNCTION_EVENT_ACK;
pAck->ChainOffset = 0;
@@ -5283,7 +5563,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
*/
in_isr = in_interrupt();
if (in_isr) {
- dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+ dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
ioc->name));
return -EPERM;
}
@@ -5291,7 +5571,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
/* Get and Populate a free Frame
*/
if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
- dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+ dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
ioc->name));
return -EAGAIN;
}
@@ -5336,13 +5616,13 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
flagsLength |= pExtHdr->ExtPageLength * 4;
- dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
}
else {
flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
- dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
}
@@ -5392,7 +5672,7 @@ mpt_timer_expired(unsigned long data)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
- dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
/* Perform a FW reload */
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
@@ -5402,7 +5682,7 @@ mpt_timer_expired(unsigned long data)
* Hard reset clean-up will wake up
* process and free all resources.
*/
- dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
return;
}
@@ -5421,7 +5701,7 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
CONFIGPARMS *pCfg;
unsigned long flags;
- dprintk((KERN_WARNING MYNAM
+ dprintk(ioc, printk(KERN_DEBUG MYNAM
": IOC %s_reset routed to MPT base driver!\n",
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -5792,7 +6072,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
int rc;
unsigned long flags;
- dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
#ifdef MFCNT
printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
printk("MF count 0x%x !\n", ioc->mfcnt);
@@ -5824,11 +6104,11 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
if (MptResetHandlers[ii]) {
- dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
ioc->name, ii));
r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
if (ioc->alt_ioc) {
- dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
ioc->name, ioc->alt_ioc->name, ii));
r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
}
@@ -5850,7 +6130,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
ioc->alt_ioc->diagPending = 0;
spin_unlock_irqrestore(&ioc->diagLock, flags);
- dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
return rc;
}
@@ -6251,16 +6531,18 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
}
EventDescriptionStr(event, evData0, evStr);
- devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
ioc->name,
event,
evStr));
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
- printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
+#ifdef CONFIG_FUSION_LOGGING
+ devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
+ ": Event data:\n"));
for (ii = 0; ii < evDataLen; ii++)
- printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
- printk("\n");
+ devtverboseprintk(ioc, printk(" %08x",
+ le32_to_cpu(pEventReply->Data[ii])));
+ devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
#endif
/*
@@ -6315,7 +6597,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
*/
for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
if (MptEvHandlers[ii]) {
- devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
ioc->name, ii));
r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
handlers++;
@@ -6327,10 +6609,10 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
* If needed, send (a single) EventAck.
*/
if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
- devtverboseprintk((MYIOC_s_WARN_FMT
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"EventAck required\n",ioc->name));
if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
- devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
ioc->name, ii));
}
}
@@ -6677,7 +6959,6 @@ union loginfo_type {
sas_loginfo.dw.code, sas_loginfo.dw.subcode);
}
-#ifdef MPT_DEBUG_REPLY
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_iocstatus_info_config - IOCSTATUS information for config pages
@@ -6982,7 +7263,6 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
}
-#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
EXPORT_SYMBOL(mpt_attach);
@@ -7047,11 +7327,7 @@ fusion_init(void)
/* Register for hard reset handling callbacks.
*/
- if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
- dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
- } else {
- /* FIXME! */
- }
+ mpt_reset_register(mpt_base_index, mpt_ioc_reset);
#ifdef CONFIG_PROC_FS
(void) procmpt_create();
@@ -7070,8 +7346,6 @@ static void __exit
fusion_exit(void)
{
- dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
-
mpt_reset_deregister(mpt_base_index);
#ifdef CONFIG_PROC_FS
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 05eb6e528753..15ff22645844 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -186,6 +186,7 @@
* MPT drivers. NOTE: Users of these macro defs must
* themselves define their own MYNAM.
*/
+#define MYIOC_s_DEBUG_FMT KERN_DEBUG MYNAM ": %s: "
#define MYIOC_s_INFO_FMT KERN_INFO MYNAM ": %s: "
#define MYIOC_s_NOTE_FMT KERN_NOTICE MYNAM ": %s: "
#define MYIOC_s_WARN_FMT KERN_WARNING MYNAM ": %s: WARNING - "
@@ -537,7 +538,15 @@ typedef struct _MPT_ADAPTER
int id; /* Unique adapter id N {0,1,2,...} */
int pci_irq; /* This irq */
char name[MPT_NAME_LENGTH]; /* "iocN" */
- char *prod_name; /* "LSIFC9x9" */
+ char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */
+ char board_name[16];
+ char board_assembly[16];
+ char board_tracer[16];
+ u16 nvdata_version_persistent;
+ u16 nvdata_version_default;
+ int debug_level;
+ u8 io_missing_delay;
+ u8 device_missing_delay;
SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */
SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */
u8 bus_type;
@@ -711,171 +720,7 @@ typedef struct _mpt_sge {
/*
* Funky (private) macros...
*/
-#ifdef MPT_DEBUG
-#define dprintk(x) printk x
-#else
-#define dprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_INIT
-#define dinitprintk(x) printk x
-#define DBG_DUMP_FW_REQUEST_FRAME(mfp) \
- { int i, n = 10; \
- u32 *m = (u32 *)(mfp); \
- printk(KERN_INFO " "); \
- for (i=0; i<n; i++) \
- printk(" %08x", le32_to_cpu(m[i])); \
- printk("\n"); \
- }
-#else
-#define dinitprintk(x)
-#define DBG_DUMP_FW_REQUEST_FRAME(mfp)
-#endif
-
-#ifdef MPT_DEBUG_EXIT
-#define dexitprintk(x) printk x
-#else
-#define dexitprintk(x)
-#endif
-
-#if defined MPT_DEBUG_FAIL || defined (MPT_DEBUG_SG)
-#define dfailprintk(x) printk x
-#else
-#define dfailprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_HANDSHAKE
-#define dhsprintk(x) printk x
-#else
-#define dhsprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_EVENTS) || defined(MPT_DEBUG_VERBOSE_EVENTS)
-#define devtprintk(x) printk x
-#else
-#define devtprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_VERBOSE_EVENTS
-#define devtverboseprintk(x) printk x
-#else
-#define devtverboseprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_RESET
-#define drsprintk(x) printk x
-#else
-#define drsprintk(x)
-#endif
-
-//#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
-#if defined(MPT_DEBUG_MSG_FRAME)
-#define dmfprintk(x) printk x
-#define DBG_DUMP_REQUEST_FRAME(mfp) \
- { int i, n = 24; \
- u32 *m = (u32 *)(mfp); \
- for (i=0; i<n; i++) { \
- if (i && ((i%8)==0)) \
- printk("\n"); \
- printk("%08x ", le32_to_cpu(m[i])); \
- } \
- printk("\n"); \
- }
-#else
-#define dmfprintk(x)
-#define DBG_DUMP_REQUEST_FRAME(mfp)
-#endif
-
-#ifdef MPT_DEBUG_IRQ
-#define dirqprintk(x) printk x
-#else
-#define dirqprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_SG
-#define dsgprintk(x) printk x
-#else
-#define dsgprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_DL) || defined(MPT_DEBUG)
-#define ddlprintk(x) printk x
-#else
-#define ddlprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_DV
-#define ddvprintk(x) printk x
-#else
-#define ddvprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
-#define ddvtprintk(x) printk x
-#else
-#define ddvtprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_IOCTL
-#define dctlprintk(x) printk x
-#else
-#define dctlprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_REPLY
-#define dreplyprintk(x) printk x
-#else
-#define dreplyprintk(x)
-#endif
-
-#ifdef DMPT_DEBUG_FC
-#define dfcprintk(x) printk x
-#else
-#define dfcprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_TM
-#define dtmprintk(x) printk x
-#define DBG_DUMP_TM_REQUEST_FRAME(mfp) \
- { u32 *m = (u32 *)(mfp); \
- int i, n = 13; \
- printk("TM_REQUEST:\n"); \
- for (i=0; i<n; i++) { \
- if (i && ((i%8)==0)) \
- printk("\n"); \
- printk("%08x ", le32_to_cpu(m[i])); \
- } \
- printk("\n"); \
- }
-#define DBG_DUMP_TM_REPLY_FRAME(mfp) \
- { u32 *m = (u32 *)(mfp); \
- int i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16; \
- printk("TM_REPLY MessageLength=%d:\n", n); \
- for (i=0; i<n; i++) { \
- if (i && ((i%8)==0)) \
- printk("\n"); \
- printk(" %08x", le32_to_cpu(m[i])); \
- } \
- printk("\n"); \
- }
-#else
-#define dtmprintk(x)
-#define DBG_DUMP_TM_REQUEST_FRAME(mfp)
-#define DBG_DUMP_TM_REPLY_FRAME(mfp)
-#endif
-
-#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
-#define dcprintk(x) printk x
-#else
-#define dcprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_SCSI) || defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
-#define dsprintk(x) printk x
-#else
-#define dsprintk(x)
-#endif
-
+#include "mptdebug.h"
#define MPT_INDEX_2_MFPTR(ioc,idx) \
(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
@@ -886,36 +731,6 @@ typedef struct _mpt_sge {
#define MPT_INDEX_2_RFPTR(ioc,idx) \
(MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) )
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
-#define DBG_DUMP_REPLY_FRAME(mfp) \
- { u32 *m = (u32 *)(mfp); \
- int i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16; \
- printk(KERN_INFO " "); \
- for (i=0; i<n; i++) \
- printk(" %08x", le32_to_cpu(m[i])); \
- printk("\n"); \
- }
-#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \
- { int i, n = 3; \
- u32 *m = (u32 *)(mfp); \
- printk(KERN_INFO " "); \
- for (i=0; i<n; i++) \
- printk(" %08x", le32_to_cpu(m[i])); \
- printk("\n"); \
- }
-#else
-#define DBG_DUMP_REPLY_FRAME(mfp)
-#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
-#endif
-
-// debug sas wide ports
-#ifdef MPT_DEBUG_SAS_WIDE
-#define dsaswideprintk(x) printk x
-#else
-#define dsaswideprintk(x)
-#endif
-
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define SCSI_STD_SENSE_BYTES 18
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 58e6c319cc76..89695e705bdc 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -181,7 +181,7 @@ static inline int
mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
{
int rc = 0;
- dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
+// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
if (nonblock) {
if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
@@ -190,7 +190,7 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
rc = -ERESTARTSYS;
}
- dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
+// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down return %d\n", rc));
return rc;
}
@@ -209,18 +209,19 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
u16 iocStatus;
u8 cmd;
- dctlprintk(("mptctl_reply()!\n"));
if (req)
cmd = req->u.hdr.Function;
else
return 1;
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
+ "reply=%p\n", ioc->name, req->u.hdr.Function, req, reply));
if (ioc->ioctl) {
if (reply==NULL) {
- dctlprintk(("mptctl_reply() NULL Reply "
- "Function=%x!\n", cmd));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
+ "Function=%x!\n", ioc->name, cmd));
ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
@@ -233,14 +234,9 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
}
- dctlprintk(("mptctl_reply() with req=%p "
- "reply=%p Function=%x!\n", req, reply, cmd));
-
/* Copy the reply frame (which much exist
* for non-SCSI I/O) to the IOC structure.
*/
- dctlprintk(("Copying Reply Frame @%p to ioc%d!\n",
- reply, ioc->id));
memcpy(ioc->ioctl->ReplyFrame, reply,
min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
@@ -252,8 +248,24 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
if (iocStatus == MPI_IOCSTATUS_SUCCESS)
ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+ if (iocStatus || reply->u.reply.IOCLogInfo)
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
+ "loginfo (0x%08X)\n", ioc->name,
+ iocStatus,
+ le32_to_cpu(reply->u.reply.IOCLogInfo)));
+
if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+
+ if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "\tscsi_status (0x%02x), scsi_state (0x%02x), "
+ "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
+ reply->u.sreply.SCSIStatus,
+ reply->u.sreply.SCSIState,
+ le16_to_cpu(reply->u.sreply.TaskTag),
+ le32_to_cpu(reply->u.sreply.TransferCount)));
+
ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
@@ -298,8 +310,8 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
{
int rc = 1;
- dctlprintk((KERN_NOTICE MYNAM ": Timeout Expired! Host %d\n",
- ioctl->ioc->id));
+ dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
+ ioctl->ioc->name, ioctl->ioc->id));
if (ioctl == NULL)
return;
@@ -311,7 +323,7 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
/* Issue a reset for this device.
* The IOC is not responding.
*/
- dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+ dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
ioctl->ioc->name));
mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
}
@@ -350,14 +362,14 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
/* Send request
*/
if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
- dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+ dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
ioctl->ioc->name));
mptctl_free_tm_flags(ioctl->ioc);
return -ENOMEM;
}
- dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+ dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
ioctl->ioc->name, mf));
pScsiTm = (SCSITaskMgmt_t *) mf;
@@ -377,15 +389,15 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
pScsiTm->Reserved2[ii] = 0;
pScsiTm->TaskMsgContext = 0;
- dtmprintk((MYIOC_s_INFO_FMT
+ dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
"mptctl_bus_reset: issued.\n", ioctl->ioc->name));
- DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
+ DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
ioctl->wait_done=0;
if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
- dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+ dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
hd->ioc, mf));
goto mptctl_bus_reset_done;
@@ -456,7 +468,7 @@ static int
mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
MPT_IOCTL *ioctl = ioc->ioctl;
- dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to IOCTL driver!\n",ioc->name,
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -487,7 +499,8 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
event = le32_to_cpu(pEvReply->Event) & 0xFF;
- dctlprintk(("%s() called\n", __FUNCTION__));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
+ ioc->name, __FUNCTION__));
if(async_queue == NULL)
return 1;
@@ -497,8 +510,10 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
*/
if (event == 0x21 ) {
ioc->aen_event_read_flag=1;
- dctlprintk(("Raised SIGIO to application\n"));
- devtverboseprintk(("Raised SIGIO to application\n"));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Raised SIGIO to application\n",
+ ioc->name));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Raised SIGIO to application\n", ioc->name));
kill_fasync(&async_queue, SIGIO, POLL_IN);
return 1;
}
@@ -515,8 +530,10 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
*/
if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
ioc->aen_event_read_flag=1;
- dctlprintk(("Raised SIGIO to application\n"));
- devtverboseprintk(("Raised SIGIO to application\n"));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Raised SIGIO to application\n", ioc->name));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Raised SIGIO to application\n", ioc->name));
kill_fasync(&async_queue, SIGIO, POLL_IN);
}
return 1;
@@ -530,14 +547,12 @@ mptctl_fasync(int fd, struct file *filep, int mode)
list_for_each_entry(ioc, &ioc_list, list)
ioc->aen_event_read_flag=0;
- dctlprintk(("%s() called\n", __FUNCTION__));
return fasync_helper(fd, filep, mode, &async_queue);
}
static int
mptctl_release(struct inode *inode, struct file *filep)
{
- dctlprintk(("%s() called\n", __FUNCTION__));
return fasync_helper(-1, filep, 0, &async_queue);
}
@@ -558,8 +573,6 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int ret;
MPT_ADAPTER *iocp = NULL;
- dctlprintk(("mptctl_ioctl() called\n"));
-
if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
"Unable to copy mpt_ioctl_header data @ %p\n",
@@ -574,13 +587,13 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
iocnumX = khdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnumX));
+ printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnumX);
return -ENODEV;
}
if (!iocp->active) {
- printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+ printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - Controller disabled.\n",
__FILE__, __LINE__);
return -EFAULT;
}
@@ -612,8 +625,6 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
return ret;
- dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name));
-
if (cmd == MPTFWDOWNLOAD)
ret = mptctl_fw_download(arg);
else if (cmd == MPTCOMMAND)
@@ -648,8 +659,6 @@ static int mptctl_do_reset(unsigned long arg)
struct mpt_ioctl_diag_reset krinfo;
MPT_ADAPTER *iocp;
- dctlprintk((KERN_INFO "mptctl_do_reset called.\n"));
-
if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
printk(KERN_ERR "%s@%d::mptctl_do_reset - "
"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
@@ -658,11 +667,14 @@ static int mptctl_do_reset(unsigned long arg)
}
if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
- dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
- __FILE__, __LINE__, krinfo.hdr.iocnum));
+ printk(KERN_DEBUG "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+ __FILE__, __LINE__, krinfo.hdr.iocnum);
return -ENODEV; /* (-6) No such device or address */
}
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n",
+ iocp->name));
+
if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
__FILE__, __LINE__);
@@ -695,7 +707,6 @@ mptctl_fw_download(unsigned long arg)
struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
struct mpt_fw_xfer kfwdl;
- dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
"Unable to copy mpt_fw_xfer struct @ %p\n",
@@ -744,15 +755,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
u16 iocstat;
pFWDownloadReply_t ReplyMsg = NULL;
- dctlprintk(("mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
-
- dctlprintk(("DbG: kfwdl.bufp = %p\n", ufwbuf));
- dctlprintk(("DbG: kfwdl.fwlen = %d\n", (int)fwlen));
- dctlprintk(("DbG: kfwdl.ioc = %04xh\n", ioc));
-
if (mpt_verify_adapter(ioc, &iocp) < 0) {
- dctlprintk(("ioctl_fwdl - ioc%d not found!\n",
- ioc));
+ printk(KERN_DEBUG "ioctl_fwdl - ioc%d not found!\n", ioc);
return -ENODEV; /* (-6) No such device or address */
} else {
@@ -761,6 +765,16 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
return -EAGAIN;
}
+
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT
+ "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id));
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.bufp = %p\n",
+ iocp->name, ufwbuf));
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n",
+ iocp->name, (int)fwlen));
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc = %04xh\n",
+ iocp->name, ioc));
+
dlmsg = (FWDownload_t*) mf;
ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
sgOut = (char *) (ptsge + 1);
@@ -829,7 +843,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
goto fwdl_out;
}
- dctlprintk(("DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags));
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
+ iocp->name, sgl, numfrags));
/*
* Parse SG list, copying sgl itself,
@@ -865,15 +880,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
sgOut += (sizeof(dma_addr_t) + sizeof(u32));
}
-#ifdef MPT_DEBUG
- {
- u32 *m = (u32 *)mf;
- printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
- for (i=0; i < 7+numfrags*2; i++)
- printk(" %08x", le32_to_cpu(m[i]));
- printk("\n");
- }
-#endif
+ DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
/*
* Finally, perform firmware download.
@@ -1049,13 +1056,11 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
*frags = numfrags;
*blp = buflist;
- dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
- "%d SG frags generated!\n",
- numfrags));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
+ "%d SG frags generated!\n", ioc->name, numfrags));
- dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
- "last (big) alloc_sz=%d\n",
- alloc_sz));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
+ "last (big) alloc_sz=%d\n", ioc->name, alloc_sz));
return sglbuf;
@@ -1139,7 +1144,8 @@ kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTE
pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
kfree(buflist);
- dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: Free'd 1 SGL buf + %d kbufs!\n",
+ ioc->name, n));
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1166,7 +1172,6 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
struct scsi_device *sdev;
VirtDevice *vdev;
- dctlprintk((": mptctl_getiocinfo called.\n"));
/* Add of PCI INFO results in unaligned access for
* IA64 and Sparc. Reset long to int. Return no PCI
* data for obsolete format.
@@ -1199,8 +1204,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
kfree(karg);
return -ENODEV;
}
@@ -1214,6 +1219,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
return -EFAULT;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_getiocinfo called.\n",
+ ioc->name));
+
/* Fill in the data and return the structure to the calling
* program
*/
@@ -1320,7 +1328,6 @@ mptctl_gettargetinfo (unsigned long arg)
u8 port;
struct scsi_device *sdev;
- dctlprintk(("mptctl_gettargetinfo called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
@@ -1330,11 +1337,13 @@ mptctl_gettargetinfo (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
+ ioc->name));
/* Get the port number and set the maximum number of bytes
* in the returned structure.
* Ignore the port setting.
@@ -1434,7 +1443,6 @@ mptctl_readtest (unsigned long arg)
MPT_ADAPTER *ioc;
int iocnum;
- dctlprintk(("mptctl_readtest called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
printk(KERN_ERR "%s@%d::mptctl_readtest - "
"Unable to read in mpt_ioctl_test struct @ %p\n",
@@ -1444,11 +1452,13 @@ mptctl_readtest (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
+ ioc->name));
/* Fill in the data and return the structure to the calling
* program
*/
@@ -1494,7 +1504,6 @@ mptctl_eventquery (unsigned long arg)
MPT_ADAPTER *ioc;
int iocnum;
- dctlprintk(("mptctl_eventquery called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
printk(KERN_ERR "%s@%d::mptctl_eventquery - "
"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
@@ -1504,11 +1513,13 @@ mptctl_eventquery (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
+ ioc->name));
karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
karg.eventTypes = ioc->eventTypes;
@@ -1532,7 +1543,6 @@ mptctl_eventenable (unsigned long arg)
MPT_ADAPTER *ioc;
int iocnum;
- dctlprintk(("mptctl_eventenable called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
printk(KERN_ERR "%s@%d::mptctl_eventenable - "
"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
@@ -1542,11 +1552,13 @@ mptctl_eventenable (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
+ ioc->name));
if (ioc->events == NULL) {
/* Have not yet allocated memory - do so now.
*/
@@ -1579,7 +1591,6 @@ mptctl_eventreport (unsigned long arg)
int iocnum;
int numBytes, maxEvents, max;
- dctlprintk(("mptctl_eventreport called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
printk(KERN_ERR "%s@%d::mptctl_eventreport - "
"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
@@ -1589,10 +1600,12 @@ mptctl_eventreport (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
+ ioc->name));
numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
@@ -1632,7 +1645,6 @@ mptctl_replace_fw (unsigned long arg)
int iocnum;
int newFwSize;
- dctlprintk(("mptctl_replace_fw called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
@@ -1642,11 +1654,13 @@ mptctl_replace_fw (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
+ ioc->name));
/* If caching FW, Free the old FW image
*/
if (ioc->cached_fw == NULL)
@@ -1704,7 +1718,6 @@ mptctl_mpt_command (unsigned long arg)
int iocnum;
int rc;
- dctlprintk(("mptctl_command called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
@@ -1715,8 +1728,8 @@ mptctl_mpt_command (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1756,13 +1769,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ulong timeout;
struct scsi_device *sdev;
- dctlprintk(("mptctl_do_mpt_command called.\n"));
bufIn.kptr = bufOut.kptr = NULL;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
if (!ioc->ioctl) {
@@ -1816,6 +1828,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
/* Verify that this request is allowed.
*/
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
+ ioc->name, hdr->Function, mf));
+
switch (hdr->Function) {
case MPI_FUNCTION_IOC_FACTS:
case MPI_FUNCTION_PORT_FACTS:
@@ -1823,6 +1838,18 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
break;
case MPI_FUNCTION_CONFIG:
+ {
+ Config_t *config_frame;
+ config_frame = (Config_t *)mf;
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x "
+ "number=0x%02x action=0x%02x\n", ioc->name,
+ config_frame->Header.PageType,
+ config_frame->ExtPageType,
+ config_frame->Header.PageNumber,
+ config_frame->Action));
+ break;
+ }
+
case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
case MPI_FUNCTION_FW_UPLOAD:
@@ -2158,12 +2185,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ioc->ioctl->wait_done = 0;
if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
- DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
+ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
if (mpt_send_handshake_request(mptctl_id, ioc,
sizeof(SCSITaskMgmt_t), (u32*)mf,
CAN_SLEEP) != 0) {
- dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
" (ioc %p, mf %p) \n", ioc->name,
ioc, mf));
mptctl_free_tm_flags(ioc);
@@ -2303,7 +2330,6 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
MPT_FRAME_HDR *mf = NULL;
MPIHeader_t *mpi_hdr;
- dctlprintk((": mptctl_hp_hostinfo called.\n"));
/* Reset long to int. Should affect IA64 and SPARC only
*/
if (data_size == sizeof(hp_host_info_t))
@@ -2322,10 +2348,12 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
+ ioc->name));
/* Fill in the data and return the structure to the calling
* program
@@ -2441,7 +2469,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
* Gather ISTWI(Industry Standard Two Wire Interface) Data
*/
if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
- dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
ioc->name,__FUNCTION__));
goto out;
}
@@ -2474,7 +2502,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
- /*
+ /*
* Now we need to reset the board
*/
mpt_free_msg_frame(ioc, mf);
@@ -2482,7 +2510,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
goto out;
}
- /*
+ /*
*ISTWI Data Definition
* pbuf[0] = FW_VERSION = 0x4
* pbuf[1] = Bay Count = 6 or 4 or 2, depending on
@@ -2538,7 +2566,6 @@ mptctl_hp_targetinfo(unsigned long arg)
ConfigPageHeader_t hdr;
int tmp, np, rc = 0;
- dctlprintk((": mptctl_hp_targetinfo called.\n"));
if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
"Unable to read in hp_host_targetinfo struct @ %p\n",
@@ -2548,10 +2575,12 @@ mptctl_hp_targetinfo(unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnum));
+ printk(KERN_DEBUG "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+ __FILE__, __LINE__, iocnum);
return -ENODEV;
}
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
+ ioc->name));
/* There is nothing to do for FCP parts.
*/
@@ -2694,7 +2723,6 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
int nonblock = (filp->f_flags & O_NONBLOCK);
int ret;
- dctlprintk((KERN_INFO MYNAM "::compat_mptfwxfer_ioctl() called\n"));
if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
return -EFAULT;
@@ -2703,14 +2731,16 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
iocnumX = kfw32.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
- dctlprintk((KERN_ERR MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
- __LINE__, iocnumX));
+ printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+ __LINE__, iocnumX);
return -ENODEV;
}
if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
return ret;
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n",
+ iocp->name));
kfw.iocnum = iocnum;
kfw.fwlen = kfw32.fwlen;
kfw.bufp = compat_ptr(kfw32.bufp);
@@ -2734,8 +2764,6 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
int nonblock = (filp->f_flags & O_NONBLOCK);
int ret;
- dctlprintk((KERN_INFO MYNAM "::compat_mpt_command() called\n"));
-
if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
return -EFAULT;
@@ -2743,14 +2771,16 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
iocnumX = karg32.hdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
- dctlprintk((KERN_ERR MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
- __LINE__, iocnumX));
+ printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
+ __LINE__, iocnumX);
return -ENODEV;
}
if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
return ret;
+ dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n",
+ iocp->name));
/* Copy data to karg */
karg.hdr.iocnum = karg32.hdr.iocnum;
karg.hdr.port = karg32.hdr.port;
@@ -2878,11 +2908,7 @@ static int __init mptctl_init(void)
show_mptmod_ver(my_NAME, my_VERSION);
- if(mpt_device_driver_register(&mptctl_driver,
- MPTCTL_DRIVER) != 0 ) {
- dprintk((KERN_INFO MYNAM
- ": failed to register dd callbacks\n"));
- }
+ mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER);
/* Register this device */
err = misc_register(&mptctl_miscdev);
@@ -2905,16 +2931,8 @@ static int __init mptctl_init(void)
goto out_fail;
}
- if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) {
- dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
- } else {
- /* FIXME! */
- }
-
- if (mpt_event_register(mptctl_id, mptctl_event_process) == 0) {
- devtverboseprintk((KERN_INFO MYNAM
- ": Registered for IOC event notifications\n"));
- }
+ mpt_reset_register(mptctl_id, mptctl_ioc_reset);
+ mpt_event_register(mptctl_id, mptctl_event_process);
return 0;
@@ -2934,11 +2952,9 @@ static void mptctl_exit(void)
/* De-register reset handler from base module */
mpt_reset_deregister(mptctl_id);
- dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
/* De-register callback handler from base module */
mpt_deregister(mptctl_id);
- printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
mpt_device_driver_deregister(MPTCTL_DRIVER);
diff --git a/drivers/message/fusion/mptdebug.h b/drivers/message/fusion/mptdebug.h
new file mode 100644
index 000000000000..ffdb0a6191b4
--- /dev/null
+++ b/drivers/message/fusion/mptdebug.h
@@ -0,0 +1,288 @@
+/*
+ * linux/drivers/message/fusion/mptdebug.h
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
+ *
+ * Copyright (c) 1999-2007 LSI Corporation
+ * (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef MPTDEBUG_H_INCLUDED
+#define MPTDEBUG_H_INCLUDED
+
+/*
+ * debug level can be programmed on the fly via SysFS (hex values)
+ *
+ * Example: (programming for MPT_DEBUG_EVENTS on host 5)
+ *
+ * echo 8 > /sys/class/scsi_host/host5/debug_level
+ *
+ * --------------------------------------------------------
+ * mpt_debug_level - command line parameter
+ * this allow enabling debug at driver load time (for all iocs)
+ *
+ * Example (programming for MPT_DEBUG_EVENTS)
+ *
+ * insmod mptbase.ko mpt_debug_level=8
+ *
+ * --------------------------------------------------------
+ * CONFIG_FUSION_LOGGING - enables compiling debug into driver
+ * this can be enabled in the driver Makefile
+ *
+ *
+ * --------------------------------------------------------
+ * Please note most debug prints are set to logging priority = debug
+ * This is the lowest level, and most verbose. Please refer to manual
+ * pages for syslogd or syslogd-ng on how to configure this.
+ */
+
+#define MPT_DEBUG 0x00000001
+#define MPT_DEBUG_MSG_FRAME 0x00000002
+#define MPT_DEBUG_SG 0x00000004
+#define MPT_DEBUG_EVENTS 0x00000008
+#define MPT_DEBUG_VERBOSE_EVENTS 0x00000010
+#define MPT_DEBUG_INIT 0x00000020
+#define MPT_DEBUG_EXIT 0x00000040
+#define MPT_DEBUG_FAIL 0x00000080
+#define MPT_DEBUG_TM 0x00000100
+#define MPT_DEBUG_DV 0x00000200
+#define MPT_DEBUG_REPLY 0x00000400
+#define MPT_DEBUG_HANDSHAKE 0x00000800
+#define MPT_DEBUG_CONFIG 0x00001000
+#define MPT_DEBUG_DL 0x00002000
+#define MPT_DEBUG_RESET 0x00008000
+#define MPT_DEBUG_SCSI 0x00010000
+#define MPT_DEBUG_IOCTL 0x00020000
+#define MPT_DEBUG_FC 0x00080000
+#define MPT_DEBUG_SAS 0x00100000
+#define MPT_DEBUG_SAS_WIDE 0x00200000
+
+/*
+ * CONFIG_FUSION_LOGGING - enabled in Kconfig
+ */
+
+#ifdef CONFIG_FUSION_LOGGING
+#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \
+{ \
+ if (IOC->debug_level & BITS) \
+ CMD; \
+}
+#else
+#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
+#endif
+
+
+/*
+ * debug macros
+ */
+
+#define dprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG)
+
+#define dsgprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG)
+
+#define devtprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS)
+
+#define devtverboseprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_VERBOSE_EVENTS)
+
+#define dinitprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT)
+
+#define dexitprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT)
+
+#define dfailprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL)
+
+#define dtmprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM)
+
+#define ddvprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DV)
+
+#define dreplyprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY)
+
+#define dhsprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE)
+
+#define dcprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG)
+
+#define ddlprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL)
+
+#define drsprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET)
+
+#define dsprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI)
+
+#define dctlprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
+
+#define dfcprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FC)
+
+#define dsasprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS)
+
+#define dsaswideprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
+
+
+
+/*
+ * Verbose logging
+ */
+#if defined(MPT_DEBUG_VERBOSE) && defined(CONFIG_FUSION_LOGGING)
+static inline void
+DBG_DUMP_FW_DOWNLOAD(MPT_ADAPTER *ioc, u32 *mfp, int numfrags)
+{
+ int i;
+
+ if (!(ioc->debug_level & MPT_DEBUG))
+ return;
+ printk(KERN_DEBUG "F/W download request:\n");
+ for (i=0; i < 7+numfrags*2; i++)
+ printk(" %08x", le32_to_cpu(mfp[i]));
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_PUT_MSG_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int ii, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+ return;
+ printk(KERN_DEBUG "%s: About to Put msg frame @ %p:\n",
+ ioc->name, mfp);
+ n = ioc->req_sz/4 - 1;
+ while (mfp[n] == 0)
+ n--;
+ for (ii=0; ii<=n; ii++) {
+ if (ii && ((ii%8)==0))
+ printk("\n");
+ printk(" %08x", le32_to_cpu(mfp[ii]));
+ }
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_FW_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int i, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+ return;
+ n = 10;
+ printk(KERN_INFO " ");
+ for (i = 0; i < n; i++)
+ printk(" %08x", le32_to_cpu(mfp[i]));
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int i, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+ return;
+ n = 24;
+ for (i=0; i<n; i++) {
+ if (i && ((i%8)==0))
+ printk("\n");
+ printk("%08x ", le32_to_cpu(mfp[i]));
+ }
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_REPLY_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int i, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+ return;
+ n = (le32_to_cpu(mfp[0]) & 0x00FF0000) >> 16;
+ printk(KERN_INFO " ");
+ for (i=0; i<n; i++)
+ printk(" %08x", le32_to_cpu(mfp[i]));
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_REQUEST_FRAME_HDR(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int i, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+ return;
+ n = 3;
+ printk(KERN_INFO " ");
+ for (i=0; i<n; i++)
+ printk(" %08x", le32_to_cpu(mfp[i]));
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_TM_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int i, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_TM))
+ return;
+ n = 13;
+ printk(KERN_DEBUG "TM_REQUEST:\n");
+ for (i=0; i<n; i++) {
+ if (i && ((i%8)==0))
+ printk("\n");
+ printk("%08x ", le32_to_cpu(mfp[i]));
+ }
+ printk("\n");
+}
+
+static inline void
+DBG_DUMP_TM_REPLY_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+ int i, n;
+
+ if (!(ioc->debug_level & MPT_DEBUG_TM))
+ return;
+ n = (le32_to_cpu(mfp[0]) & 0x00FF0000) >> 16;
+ printk(KERN_DEBUG "TM_REPLY MessageLength=%d:\n", n);
+ for (i=0; i<n; i++) {
+ if (i && ((i%8)==0))
+ printk("\n");
+ printk(" %08x", le32_to_cpu(mfp[i]));
+ }
+ printk("\n");
+}
+
+#define dmfprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
+
+# else /* ifdef MPT_DEBUG_MF */
+
+#define DBG_DUMP_FW_DOWNLOAD(IOC, mfp, numfrags)
+#define DBG_DUMP_PUT_MSG_FRAME(IOC, mfp)
+#define DBG_DUMP_FW_REQUEST_FRAME(IOC, mfp)
+#define DBG_DUMP_REQUEST_FRAME(IOC, mfp)
+#define DBG_DUMP_REPLY_FRAME(IOC, mfp)
+#define DBG_DUMP_REQUEST_FRAME_HDR(IOC, mfp)
+#define DBG_DUMP_TM_REQUEST_FRAME(IOC, mfp)
+#define DBG_DUMP_TM_REPLY_FRAME(IOC, mfp)
+
+#define dmfprintk(IOC, CMD) \
+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
+
+#endif /* defined(MPT_DEBUG_VERBOSE) && defined(CONFIG_FUSION_LOGGING) */
+
+#endif /* ifndef MPTDEBUG_H_INCLUDED */
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index b766445f19aa..8422c25e4a3e 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -130,6 +130,7 @@ static struct scsi_host_template mptfc_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mptscsih_host_attrs,
};
/****************************************************************************
@@ -153,6 +154,8 @@ static struct pci_device_id mptfc_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E,
+ PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
@@ -185,16 +188,18 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
int (*func)(struct scsi_cmnd *SCpnt),
const char *caller)
{
+ MPT_SCSI_HOST *hd;
struct scsi_device *sdev = SCpnt->device;
struct Scsi_Host *shost = sdev->host;
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
unsigned long flags;
int ready;
+ hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
spin_lock_irqsave(shost->host_lock, flags);
while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
spin_unlock_irqrestore(shost->host_lock, flags);
- dfcprintk ((MYIOC_s_INFO_FMT
+ dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_block_error_handler.%d: %d:%d, port status is "
"DID_IMM_RETRY, deferring %s recovery.\n",
((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
@@ -206,7 +211,7 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
spin_unlock_irqrestore(shost->host_lock, flags);
if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
- dfcprintk ((MYIOC_s_INFO_FMT
+ dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, failing recovery, "
"port state %d, vdev %p.\n", caller,
((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
@@ -215,7 +220,7 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
SCpnt->device->hostdata));
return FAILED;
}
- dfcprintk ((MYIOC_s_INFO_FMT
+ dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, executing recovery.\n", caller,
((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
@@ -480,7 +485,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
- dfcprintk ((MYIOC_s_INFO_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
"rport tid %d, tmo %d\n",
ioc->name,
@@ -556,6 +561,35 @@ mptfc_target_alloc(struct scsi_target *starget)
return rc;
}
+/*
+ * mptfc_dump_lun_info
+ * @ioc
+ * @rport
+ * @sdev
+ *
+ */
+static void
+mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev,
+ VirtTarget *vtarget)
+{
+ u64 nn, pn;
+ struct mptfc_rport_info *ri;
+
+ ri = *((struct mptfc_rport_info **)rport->dd_data);
+ pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+ nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
+ "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
+ "CurrentTargetID %d, %x %llx %llx\n",
+ ioc->name,
+ sdev->host->host_no,
+ vtarget->num_luns,
+ sdev->id, ri->pg0.CurrentTargetID,
+ ri->pg0.PortIdentifier,
+ (unsigned long long)pn,
+ (unsigned long long)nn));
+}
+
/*
* OS entry point to allow host driver to alloc memory
@@ -603,25 +637,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
vtarget->num_luns++;
-#ifdef DMPT_DEBUG_FC
- {
- u64 nn, pn;
- struct mptfc_rport_info *ri;
- ri = *((struct mptfc_rport_info **)rport->dd_data);
- pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
- nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
- dfcprintk ((MYIOC_s_INFO_FMT
- "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
- "CurrentTargetID %d, %x %llx %llx\n",
- hd->ioc->name,
- sdev->host->host_no,
- vtarget->num_luns,
- sdev->id, ri->pg0.CurrentTargetID,
- ri->pg0.PortIdentifier,
- (unsigned long long)pn,
- (unsigned long long)nn));
- }
-#endif
+ mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget);
return 0;
}
@@ -650,27 +666,12 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/* dd_data is null until finished adding target */
ri = *((struct mptfc_rport_info **)rport->dd_data);
if (unlikely(!ri)) {
- dfcprintk ((MYIOC_s_INFO_FMT
- "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
- ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun));
SCpnt->result = DID_IMM_RETRY << 16;
done(SCpnt);
return 0;
}
- err = mptscsih_qcmd(SCpnt,done);
-#ifdef DMPT_DEBUG_FC
- if (unlikely(err)) {
- dfcprintk ((MYIOC_s_INFO_FMT
- "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
- ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun,err));
- }
-#endif
- return err;
+ return mptscsih_qcmd(SCpnt,done);
}
/*
@@ -1038,7 +1039,7 @@ mptfc_setup_reset(struct work_struct *work)
pn = (u64)ri->pg0.WWPN.High << 32 |
(u64)ri->pg0.WWPN.Low;
- dfcprintk ((MYIOC_s_INFO_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_setup_reset.%d: %llx deleted\n",
ioc->name,
ioc->sh->host_no,
@@ -1085,7 +1086,7 @@ mptfc_rescan_devices(struct work_struct *work)
pn = (u64)ri->pg0.WWPN.High << 32 |
(u64)ri->pg0.WWPN.Low;
- dfcprintk ((MYIOC_s_INFO_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_rescan.%d: %llx deleted\n",
ioc->name,
ioc->sh->host_no,
@@ -1209,7 +1210,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (numSGE < sh->sg_tablesize) {
/* Reset this value */
- dprintk((MYIOC_s_INFO_FMT
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Resetting sg_tablesize to %d from %d\n",
ioc->name, numSGE, sh->sg_tablesize));
sh->sg_tablesize = numSGE;
@@ -1229,7 +1230,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_mptfc_probe;
}
- dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, hd->ScsiLookup));
/* Clear the TM flags
@@ -1261,7 +1262,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->transportt = mptfc_transport_template;
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
- dprintk((KERN_ERR MYNAM
+ dprintk(ioc, printk(KERN_ERR MYNAM
"scsi_add_host failed\n"));
goto out_mptfc_probe;
}
@@ -1320,7 +1321,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
unsigned long flags;
int rc=1;
- devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
ioc->name, event));
if (ioc->sh == NULL ||
@@ -1354,8 +1355,8 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
return rc;
- dtmprintk((KERN_WARNING MYNAM
- ": IOC %s_reset routed to FC host driver!\n",
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": IOC %s_reset routed to FC host driver!\n",ioc->name,
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -1410,15 +1411,8 @@ mptfc_init(void)
mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
- if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
- devtverboseprintk((KERN_INFO MYNAM
- ": Registered for IOC event notifications\n"));
- }
-
- if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
- dprintk((KERN_INFO MYNAM
- ": Registered for IOC reset notifications\n"));
- }
+ mpt_event_register(mptfcDoneCtx, mptfc_event_process);
+ mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
error = pci_register_driver(&mptfc_driver);
if (error)
@@ -1483,12 +1477,7 @@ mptfc_exit(void)
fc_release_transport(mptfc_transport_template);
mpt_reset_deregister(mptfcDoneCtx);
- dprintk((KERN_INFO MYNAM
- ": Deregistered for IOC reset notifications\n"));
-
mpt_event_deregister(mptfcDoneCtx);
- dprintk((KERN_INFO MYNAM
- ": Deregistered for IOC event notifications\n"));
mpt_deregister(mptfcInternalCtx);
mpt_deregister(mptfcTaskCtx);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 7e8a90cb484e..3da4c37846ec 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -1427,8 +1427,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
dlprintk((KERN_INFO MYNAM ": Finished registering dev "
"and setting initial values\n"));
- SET_MODULE_OWNER(dev);
-
if (register_netdev(dev) != 0) {
free_netdev(dev);
dev = NULL;
@@ -1524,8 +1522,7 @@ static int __init mpt_lan_init (void)
dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
- if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER))
- dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n"));
+ mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER);
return 0;
}
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 9e5424e1871f..b9c69bff218c 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -201,103 +201,91 @@ struct mptsas_enclosure {
u8 sep_channel; /* SEP channel logical channel id */
};
-#ifdef MPT_DEBUG_SAS
-static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
-{
- printk("---- IO UNIT PAGE 0 ------------\n");
- printk("Handle=0x%X\n",
- le16_to_cpu(phy_data->AttachedDeviceHandle));
- printk("Controller Handle=0x%X\n",
- le16_to_cpu(phy_data->ControllerDevHandle));
- printk("Port=0x%X\n", phy_data->Port);
- printk("Port Flags=0x%X\n", phy_data->PortFlags);
- printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
- printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
- printk("Controller PHY Device Info=0x%X\n",
- le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
- printk("DiscoveryStatus=0x%X\n",
- le32_to_cpu(phy_data->DiscoveryStatus));
- printk("\n");
-}
-
-static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
+static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
+ MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
+{
+ dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
+ dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
+ le16_to_cpu(phy_data->AttachedDeviceHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
+ le16_to_cpu(phy_data->ControllerDevHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
+ dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
+ dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
+ dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
+ dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
+ le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
+ dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
+ le32_to_cpu(phy_data->DiscoveryStatus)));
+}
+
+static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
{
__le64 sas_address;
memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
- printk("---- SAS PHY PAGE 0 ------------\n");
- printk("Attached Device Handle=0x%X\n",
- le16_to_cpu(pg0->AttachedDevHandle));
- printk("SAS Address=0x%llX\n",
- (unsigned long long)le64_to_cpu(sas_address));
- printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
- printk("Attached Device Info=0x%X\n",
- le32_to_cpu(pg0->AttachedDeviceInfo));
- printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
- printk("Change Count=0x%X\n", pg0->ChangeCount);
- printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
- printk("\n");
+ dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
+ dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
+ le16_to_cpu(pg0->AttachedDevHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
+ (unsigned long long)le64_to_cpu(sas_address)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
+ dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
+ le32_to_cpu(pg0->AttachedDeviceInfo)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
+ dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
+ dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
}
-static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
+static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
{
- printk("---- SAS PHY PAGE 1 ------------\n");
- printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
- printk("Running Disparity Error Count=0x%x\n",
- pg1->RunningDisparityErrorCount);
- printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
- printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
- printk("\n");
+ dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
+ dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
+ dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
+ pg1->RunningDisparityErrorCount));
+ dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
+ dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
}
-static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
+static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
{
__le64 sas_address;
memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
- printk("---- SAS DEVICE PAGE 0 ---------\n");
- printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
- printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
- printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
- printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
- printk("SAS Address=0x%llX\n", (unsigned long long)
- le64_to_cpu(sas_address));
- printk("Target ID=0x%X\n", pg0->TargetID);
- printk("Bus=0x%X\n", pg0->Bus);
+ dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
+ dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
+ dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
+ le64_to_cpu(sas_address)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
+ dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
/* The PhyNum field specifies the PHY number of the parent
* device this device is linked to
*/
- printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
- printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
- printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
- printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
- printk("Physical Port=0x%X\n", pg0->PhysicalPort);
- printk("\n");
-}
-
-static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
-{
- printk("---- SAS EXPANDER PAGE 1 ------------\n");
-
- printk("Physical Port=0x%X\n", pg1->PhysicalPort);
- printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
- printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
- printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
- printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
- printk("Owner Device Handle=0x%X\n",
- le16_to_cpu(pg1->OwnerDevHandle));
- printk("Attached Device Handle=0x%X\n",
- le16_to_cpu(pg1->AttachedDevHandle));
-}
-#else
-#define mptsas_print_phy_data(phy_data) do { } while (0)
-#define mptsas_print_phy_pg0(pg0) do { } while (0)
-#define mptsas_print_phy_pg1(pg1) do { } while (0)
-#define mptsas_print_device_pg0(pg0) do { } while (0)
-#define mptsas_print_expander_pg1(pg1) do { } while (0)
-#endif
+ dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
+ dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
+}
+
+static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
+{
+ dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
+ dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
+ dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
+ dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
+ dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
+ dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
+ dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
+ le16_to_cpu(pg1->OwnerDevHandle)));
+ dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
+ le16_to_cpu(pg1->AttachedDevHandle)));
+}
static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
{
@@ -354,7 +342,7 @@ mptsas_is_end_device(struct mptsas_devinfo * attached)
/* no mutex */
static void
-mptsas_port_delete(struct mptsas_portinfo_details * port_details)
+mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
{
struct mptsas_portinfo *port_info;
struct mptsas_phyinfo *phy_info;
@@ -366,7 +354,7 @@ mptsas_port_delete(struct mptsas_portinfo_details * port_details)
port_info = port_details->port_info;
phy_info = port_info->phy_info;
- dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
+ dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
"bitmask=0x%016llX\n", __FUNCTION__, port_details,
port_details->num_phys, (unsigned long long)
port_details->phy_bitmask));
@@ -390,20 +378,19 @@ mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
}
static inline void
-mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
+mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
{
if (phy_info->port_details) {
phy_info->port_details->rphy = rphy;
- dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
+ dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
}
-#ifdef MPT_DEBUG_SAS_WIDE
if (rphy) {
- dev_printk(KERN_DEBUG, &rphy->dev, "add:");
- printk("rphy=%p release=%p\n",
- rphy, rphy->dev.release);
+ dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
+ &rphy->dev, "add:"));
+ dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
+ rphy, rphy->dev.release));
}
-#endif
}
static inline struct sas_port *
@@ -416,18 +403,17 @@ mptsas_get_port(struct mptsas_phyinfo *phy_info)
}
static inline void
-mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
+mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
{
if (phy_info->port_details)
phy_info->port_details->port = port;
-#ifdef MPT_DEBUG_SAS_WIDE
if (port) {
- dev_printk(KERN_DEBUG, &port->dev, "add: ");
- printk("port=%p release=%p\n",
- port, port->dev.release);
+ dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
+ &port->dev, "add:"));
+ dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
+ port, port->dev.release));
}
-#endif
}
static inline struct scsi_target *
@@ -477,7 +463,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
* Removing a phy from a port, letting the last
* phy be removed by firmware events.
*/
- dsaswideprintk((KERN_DEBUG
+ dsaswideprintk(ioc, printk(KERN_DEBUG
"%s: [%p]: deleting phy = %d\n",
__FUNCTION__, port_details, i));
port_details->num_phys--;
@@ -493,7 +479,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
phy_info = port_info->phy_info;
for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
sas_address = phy_info->attached.sas_address;
- dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
+ dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
i, (unsigned long long)sas_address));
if (!sas_address)
continue;
@@ -512,7 +498,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_details->phy_bitmask |=
(1 << phy_info->phy_id);
phy_info->sas_port_add_phy=1;
- dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
+ dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
"phy_id=%d sas_address=0x%018llX\n",
i, (unsigned long long)sas_address));
phy_info->port_details = port_details;
@@ -529,7 +515,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
continue;
if (phy_info_cmp->port_details == port_details )
continue;
- dsaswideprintk((KERN_DEBUG
+ dsaswideprintk(ioc, printk(KERN_DEBUG
"\t\tphy_id=%d sas_address=0x%018llX\n",
j, (unsigned long long)
phy_info_cmp->attached.sas_address));
@@ -559,21 +545,19 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
out:
-#ifdef MPT_DEBUG_SAS_WIDE
for (i = 0; i < port_info->num_phys; i++) {
port_details = port_info->phy_info[i].port_details;
if (!port_details)
continue;
- dsaswideprintk((KERN_DEBUG
+ dsaswideprintk(ioc, printk(KERN_DEBUG
"%s: [%p]: phy_id=%02d num_phys=%02d "
"bitmask=0x%016llX\n", __FUNCTION__,
port_details, i, port_details->num_phys,
(unsigned long long)port_details->phy_bitmask));
- dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
+ dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
port_details->port, port_details->rphy));
}
- dsaswideprintk((KERN_DEBUG"\n"));
-#endif
+ dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
mutex_unlock(&ioc->sas_topology_mutex);
}
@@ -622,7 +606,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
SCSITaskMgmt_t *pScsiTm;
if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
- dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
ioc->name,__FUNCTION__, __LINE__));
return 0;
}
@@ -637,12 +621,12 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
- DBG_DUMP_TM_REQUEST_FRAME(mf);
+ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
mpt_free_msg_frame(ioc, mf);
- dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
ioc->name,__FUNCTION__, __LINE__));
return 0;
}
@@ -681,7 +665,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
target_reset_list = kzalloc(sizeof(*target_reset_list),
GFP_ATOMIC);
if (!target_reset_list) {
- dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
ioc->name,__FUNCTION__, __LINE__));
return;
}
@@ -748,7 +732,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
ioc->name,__FUNCTION__, __LINE__));
return;
}
@@ -1119,6 +1103,7 @@ static struct scsi_host_template mptsas_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mptscsih_host_attrs,
};
static int mptsas_get_linkerrors(struct sas_phy *phy)
@@ -1167,7 +1152,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
if (error)
goto out_free_consistent;
- mptsas_print_phy_pg1(buffer);
+ mptsas_print_phy_pg1(ioc, buffer);
phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
phy->running_disparity_error_count =
@@ -1327,11 +1312,137 @@ mptsas_get_bay_identifier(struct sas_rphy *rphy)
return rc;
}
+static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ struct request *req)
+{
+ MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
+ MPT_FRAME_HDR *mf;
+ SmpPassthroughRequest_t *smpreq;
+ struct request *rsp = req->next_rq;
+ int ret;
+ int flagsLength;
+ unsigned long timeleft;
+ char *psge;
+ dma_addr_t dma_addr_in = 0;
+ dma_addr_t dma_addr_out = 0;
+ u64 sas_address = 0;
+
+ if (!rsp) {
+ printk(KERN_ERR "%s: the smp response space is missing\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* do we need to support multiple segments? */
+ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+ printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
+ __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+ rsp->bio->bi_vcnt, rsp->data_len);
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
+ if (ret)
+ goto out;
+
+ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+ if (!mf) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ smpreq = (SmpPassthroughRequest_t *)mf;
+ memset(smpreq, 0, sizeof(*smpreq));
+
+ smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
+ smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
+
+ if (rphy)
+ sas_address = rphy->identify.sas_address;
+ else {
+ struct mptsas_portinfo *port_info;
+
+ mutex_lock(&ioc->sas_topology_mutex);
+ port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
+ if (port_info && port_info->phy_info)
+ sas_address =
+ port_info->phy_info[0].phy->identify.sas_address;
+ mutex_unlock(&ioc->sas_topology_mutex);
+ }
+
+ *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
+
+ psge = (char *)
+ (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
+
+ /* request */
+ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_DIRECTION |
+ mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
+ flagsLength |= (req->data_len - 4);
+
+ dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
+ req->data_len, PCI_DMA_BIDIRECTIONAL);
+ if (!dma_addr_out)
+ goto put_mf;
+ mpt_add_sge(psge, flagsLength, dma_addr_out);
+ psge += (sizeof(u32) + sizeof(dma_addr_t));
+
+ /* response */
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+ flagsLength |= rsp->data_len + 4;
+ dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
+ rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+ if (!dma_addr_in)
+ goto unmap;
+ mpt_add_sge(psge, flagsLength, dma_addr_in);
+
+ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
+
+ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
+ if (!timeleft) {
+ printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
+ /* On timeout reset the board */
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ ret = -ETIMEDOUT;
+ goto unmap;
+ }
+ mf = NULL;
+
+ if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
+ SmpPassthroughReply_t *smprep;
+
+ smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
+ memcpy(req->sense, smprep, sizeof(*smprep));
+ req->sense_len = sizeof(*smprep);
+ } else {
+ printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
+ __FUNCTION__);
+ ret = -ENXIO;
+ }
+unmap:
+ if (dma_addr_out)
+ pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
+ PCI_DMA_BIDIRECTIONAL);
+ if (dma_addr_in)
+ pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
+ PCI_DMA_BIDIRECTIONAL);
+put_mf:
+ if (mf)
+ mpt_free_msg_frame(ioc, mf);
+out_unlock:
+ mutex_unlock(&ioc->sas_mgmt.mutex);
+out:
+ return ret;
+}
+
static struct sas_function_template mptsas_transport_functions = {
.get_linkerrors = mptsas_get_linkerrors,
.get_enclosure_identifier = mptsas_get_enclosure_identifier,
.get_bay_identifier = mptsas_get_bay_identifier,
.phy_reset = mptsas_phy_reset,
+ .smp_handler = mptsas_smp_handler,
};
static struct scsi_transport_template *mptsas_transport_template;
@@ -1390,8 +1501,13 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
goto out_free_consistent;
}
+ ioc->nvdata_version_persistent =
+ le16_to_cpu(buffer->NvdataVersionPersistent);
+ ioc->nvdata_version_default =
+ le16_to_cpu(buffer->NvdataVersionDefault);
+
for (i = 0; i < port_info->num_phys; i++) {
- mptsas_print_phy_data(&buffer->PhyData[i]);
+ mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
port_info->phy_info[i].phy_id = i;
port_info->phy_info[i].port_id =
buffer->PhyData[i].Port;
@@ -1410,6 +1526,63 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
}
static int
+mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
+{
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ SasIOUnitPage1_t *buffer;
+ dma_addr_t dma_handle;
+ int error;
+ u16 device_missing_delay;
+
+ memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
+ memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.timeout = 10;
+ cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+ cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
+ cfg.cfghdr.ehdr->PageNumber = 1;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+ goto out;
+ if (!hdr.ExtPageLength) {
+ error = -ENXIO;
+ goto out;
+ }
+
+ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+ &dma_handle);
+ if (!buffer) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+ goto out_free_consistent;
+
+ ioc->io_missing_delay =
+ le16_to_cpu(buffer->IODeviceMissingDelay);
+ device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
+ ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
+ (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
+ device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+
+ out_free_consistent:
+ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+ buffer, dma_handle);
+ out:
+ return error;
+}
+
+static int
mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
u32 form, u32 form_specific)
{
@@ -1459,7 +1632,7 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
if (error)
goto out_free_consistent;
- mptsas_print_phy_pg0(buffer);
+ mptsas_print_phy_pg0(ioc, buffer);
phy_info->hw_link_rate = buffer->HwLinkRate;
phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
@@ -1526,7 +1699,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
if (error)
goto out_free_consistent;
- mptsas_print_device_pg0(buffer);
+ mptsas_print_device_pg0(ioc, buffer);
device_info->handle = le16_to_cpu(buffer->DevHandle);
device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
@@ -1674,7 +1847,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
goto out_free_consistent;
- mptsas_print_expander_pg1(buffer);
+ mptsas_print_expander_pg1(ioc, buffer);
/* save config data */
phy_info->phy_id = buffer->PhyIdentifier;
@@ -1883,17 +2056,17 @@ static int mptsas_probe_one_phy(struct device *dev,
}
error = sas_port_add(port);
if (error) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
goto out;
}
- mptsas_set_port(phy_info, port);
- dsaswideprintk((KERN_DEBUG
+ mptsas_set_port(ioc, phy_info, port);
+ dsaswideprintk(ioc, printk(KERN_DEBUG
"sas_port_alloc: port=%p dev=%p port_id=%d\n",
port, dev, port->port_identifier));
}
- dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
+ dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
phy_info->phy_id));
sas_port_add_phy(port, phy_info->phy);
phy_info->sas_port_add_phy = 0;
@@ -1954,7 +2127,7 @@ static int mptsas_probe_one_phy(struct device *dev,
break;
}
if (!rphy) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
goto out;
@@ -1963,13 +2136,13 @@ static int mptsas_probe_one_phy(struct device *dev,
rphy->identify = identify;
error = sas_rphy_add(rphy);
if (error) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
sas_rphy_free(rphy);
goto out;
}
- mptsas_set_rphy(phy_info, rphy);
+ mptsas_set_rphy(ioc, phy_info, rphy);
}
out:
@@ -1990,6 +2163,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
if (error)
goto out_free_port_info;
+ mptsas_sas_io_unit_pg1(ioc);
mutex_lock(&ioc->sas_topology_mutex);
ioc->handle = hba->phy_info[0].handle;
port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
@@ -2194,18 +2368,17 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
if (phy_info->attached.sas_address !=
expander_sas_address)
continue;
-#ifdef MPT_DEBUG_SAS_WIDE
- dev_printk(KERN_DEBUG, &port->dev,
- "delete port (%d)\n", port->port_identifier);
-#endif
+ dsaswideprintk(ioc,
+ dev_printk(KERN_DEBUG, &port->dev,
+ "delete port (%d)\n", port->port_identifier));
sas_port_delete(port);
- mptsas_port_delete(phy_info->port_details);
+ mptsas_port_delete(ioc, phy_info->port_details);
}
next_port:
phy_info = port_info->phy_info;
for (i = 0; i < port_info->num_phys; i++, phy_info++)
- mptsas_port_delete(phy_info->port_details);
+ mptsas_port_delete(ioc, phy_info->port_details);
list_del(&port_info->list);
kfree(port_info->phy_info);
@@ -2491,7 +2664,7 @@ mptsas_hotplug_work(struct work_struct *work)
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
(ev->channel << 8) + ev->id)) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2511,20 +2684,20 @@ mptsas_hotplug_work(struct work_struct *work)
* Sanity checks, for non-existing phys and remote rphys.
*/
if (!phy_info){
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
}
if (!phy_info->port_details) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
}
rphy = mptsas_get_rphy(phy_info);
if (!rphy) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2532,7 +2705,7 @@ mptsas_hotplug_work(struct work_struct *work)
port = mptsas_get_port(phy_info);
if (!port) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2543,7 +2716,7 @@ mptsas_hotplug_work(struct work_struct *work)
vtarget = starget->hostdata;
if (!vtarget) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2581,12 +2754,10 @@ mptsas_hotplug_work(struct work_struct *work)
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-#ifdef MPT_DEBUG_SAS_WIDE
dev_printk(KERN_DEBUG, &port->dev,
"delete port (%d)\n", port->port_identifier);
-#endif
sas_port_delete(port);
- mptsas_port_delete(phy_info->port_details);
+ mptsas_port_delete(ioc, phy_info->port_details);
break;
case MPTSAS_ADD_DEVICE:
@@ -2600,7 +2771,7 @@ mptsas_hotplug_work(struct work_struct *work)
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
(ev->channel << 8) + ev->id)) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2612,7 +2783,7 @@ mptsas_hotplug_work(struct work_struct *work)
sas_device.sas_address);
if (!phy_info || !phy_info->port_details) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2624,7 +2795,7 @@ mptsas_hotplug_work(struct work_struct *work)
vtarget = starget->hostdata;
if (!vtarget) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2647,7 +2818,7 @@ mptsas_hotplug_work(struct work_struct *work)
}
if (mptsas_get_rphy(phy_info)) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
if (ev->channel) printk("%d\n", __LINE__);
@@ -2656,7 +2827,7 @@ mptsas_hotplug_work(struct work_struct *work)
port = mptsas_get_port(phy_info);
if (!port) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
@@ -2681,7 +2852,7 @@ mptsas_hotplug_work(struct work_struct *work)
mptsas_parse_device_info(&identify, &phy_info->attached);
rphy = sas_end_device_alloc(port);
if (!rphy) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break; /* non-fatal: an rphy can be added later */
@@ -2689,13 +2860,13 @@ mptsas_hotplug_work(struct work_struct *work)
rphy->identify = identify;
if (sas_rphy_add(rphy)) {
- dfailprintk((MYIOC_s_ERR_FMT
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
sas_rphy_free(rphy);
break;
}
- mptsas_set_rphy(phy_info, rphy);
+ mptsas_set_rphy(ioc, phy_info, rphy);
break;
case MPTSAS_ADD_RAID:
sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
@@ -3111,7 +3282,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (numSGE < sh->sg_tablesize) {
/* Reset this value */
- dprintk((MYIOC_s_INFO_FMT
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Resetting sg_tablesize to %d from %d\n",
ioc->name, numSGE, sh->sg_tablesize));
sh->sg_tablesize = numSGE;
@@ -3129,7 +3300,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_mptsas_probe;
}
- dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, hd->ScsiLookup));
/* Clear the TM flags
@@ -3169,7 +3340,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
error = scsi_add_host(sh, &ioc->pcidev->dev);
if (error) {
- dprintk((KERN_ERR MYNAM
+ dprintk(ioc, printk(KERN_ERR MYNAM
"scsi_add_host failed\n"));
goto out_mptsas_probe;
}
@@ -3197,7 +3368,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
list_del(&p->list);
for (i = 0 ; i < p->num_phys ; i++)
- mptsas_port_delete(p->phy_info[i].port_details);
+ mptsas_port_delete(ioc, p->phy_info[i].port_details);
kfree(p->phy_info);
kfree(p);
}
@@ -3237,6 +3408,8 @@ static struct pci_driver mptsas_driver = {
static int __init
mptsas_init(void)
{
+ int error;
+
show_mptmod_ver(my_NAME, my_VERSION);
mptsas_transport_template =
@@ -3250,17 +3423,14 @@ mptsas_init(void)
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
- if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
- devtverboseprintk((KERN_INFO MYNAM
- ": Registered for IOC event notifications\n"));
- }
+ mpt_event_register(mptsasDoneCtx, mptsas_event_process);
+ mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
- if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
- dprintk((KERN_INFO MYNAM
- ": Registered for IOC reset notifications\n"));
- }
+ error = pci_register_driver(&mptsas_driver);
+ if (error)
+ sas_release_transport(mptsas_transport_template);
- return pci_register_driver(&mptsas_driver);
+ return error;
}
static void __exit
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index d35617376f87..5431529741ad 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -191,7 +191,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
int rc;
int chain_idx;
- dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
ioc->name));
spin_lock_irqsave(&ioc->FreeQlock, flags);
if (!list_empty(&ioc->FreeChainQ)) {
@@ -203,12 +203,12 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
chain_idx = offset / ioc->req_sz;
rc = SUCCESS;
- dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
} else {
rc = FAILED;
chain_idx = MPT_HOST_NO_CHAIN;
- dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n",
ioc->name));
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -337,7 +337,7 @@ nextSGEset:
*/
pReq->ChainOffset = 0;
RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
- dsgprintk((MYIOC_s_INFO_FMT
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
ioc->RequestNB[req_idx] = RequestNB;
}
@@ -353,7 +353,7 @@ nextSGEset:
* Loop until done.
*/
- dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
ioc->name, sg_done));
/* Set LAST_ELEMENT flag for last non-chain element
@@ -386,7 +386,7 @@ nextSGEset:
*/
pReq->ChainOffset = (u8) (sgeOffset >> 2);
RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
- dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
ioc->RequestNB[req_idx] = RequestNB;
}
@@ -397,7 +397,7 @@ nextSGEset:
* in current buffer. Get a chain buffer.
*/
if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
- dfailprintk((MYIOC_s_INFO_FMT
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
ioc->name, pReq->CDB[0], SCpnt));
return FAILED;
@@ -419,7 +419,7 @@ nextSGEset:
* out the Address and Flags fields.
*/
chainSge = (char *) psge;
- dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
+ dsgprintk(ioc, printk(KERN_DEBUG " Current buff @ %p (index 0x%x)",
psge, req_idx));
/* Start the SGE for the next buffer
@@ -428,7 +428,7 @@ nextSGEset:
sgeOffset = 0;
sg_done = 0;
- dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
+ dsgprintk(ioc, printk(KERN_DEBUG " Chain buff @ %p (index 0x%x)\n",
psge, chain_idx));
/* Start the SGE for the next buffer
@@ -456,7 +456,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
return;
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
- dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
ioc->name,__FUNCTION__));
return;
}
@@ -467,93 +467,158 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
SEPMsg->TargetID = vtarget->id;
SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
SEPMsg->SlotStatus = SlotStatus;
- devtverboseprintk((MYIOC_s_WARN_FMT
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Sending SEP cmd=%x channel=%d id=%d\n",
ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
}
-#ifdef MPT_DEBUG_REPLY
+#ifdef CONFIG_FUSION_LOGGING
/**
- * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
+ * mptscsih_info_scsiio - debug print info on reply frame
* @ioc: Pointer to MPT_ADAPTER structure
- * @ioc_status: U32 IOCStatus word from IOC
- * @scsi_status: U8 sam status from target
- * @scsi_state: U8 scsi state
* @sc: original scsi cmnd pointer
- * @mf: Pointer to MPT request frame
+ * @pScsiReply: Pointer to MPT reply frame
+ *
+ * MPT_DEBUG_REPLY needs to be enabled to obtain this info
*
* Refer to lsi/mpi.h.
**/
static void
-mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
- u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
+mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
{
- char extend_desc[EVENT_DESCR_STR_SZ];
- char *desc = NULL;
+ char *desc = NULL;
+ char *desc1 = NULL;
+ u16 ioc_status;
+ u8 skey, asc, ascq;
+
+ ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
switch (ioc_status) {
- case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
- desc = "SCSI Invalid Bus";
+ case MPI_IOCSTATUS_SUCCESS:
+ desc = "success";
break;
-
- case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
- desc = "SCSI Invalid TargetID";
+ case MPI_IOCSTATUS_SCSI_INVALID_BUS:
+ desc = "invalid bus";
break;
-
- case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
- /*
- * Inquiry is issued for device scanning
- */
- if (sc->cmnd[0] != 0x12)
- desc = "SCSI Device Not There";
+ case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
+ desc = "invalid target_id";
break;
-
- case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
- desc = "SCSI Data Overrun";
+ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+ desc = "device not there";
break;
-
- case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
- desc = "SCSI I/O Data Error";
+ case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
+ desc = "data overrun";
break;
-
- case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
- desc = "SCSI Protocol Error";
+ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
+ desc = "data underrun";
break;
-
- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
- desc = "SCSI Task Terminated";
+ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
+ desc = "I/O data error";
break;
-
- case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
- desc = "SCSI Residual Mismatch";
+ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+ desc = "protocol error";
break;
-
- case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
- desc = "SCSI Task Management Failed";
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
+ desc = "task terminated";
break;
-
- case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
- desc = "SCSI IOC Terminated";
+ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+ desc = "residual mismatch";
+ break;
+ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+ desc = "task management failed";
+ break;
+ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
+ desc = "IOC terminated";
+ break;
+ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
+ desc = "ext terminated";
break;
+ default:
+ desc = "";
+ break;
+ }
+
+ switch (pScsiReply->SCSIStatus)
+ {
- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
- desc = "SCSI Ext Terminated";
+ case MPI_SCSI_STATUS_SUCCESS:
+ desc1 = "success";
+ break;
+ case MPI_SCSI_STATUS_CHECK_CONDITION:
+ desc1 = "check condition";
+ break;
+ case MPI_SCSI_STATUS_CONDITION_MET:
+ desc1 = "condition met";
+ break;
+ case MPI_SCSI_STATUS_BUSY:
+ desc1 = "busy";
+ break;
+ case MPI_SCSI_STATUS_INTERMEDIATE:
+ desc1 = "intermediate";
+ break;
+ case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
+ desc1 = "intermediate condmet";
+ break;
+ case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
+ desc1 = "reservation conflict";
+ break;
+ case MPI_SCSI_STATUS_COMMAND_TERMINATED:
+ desc1 = "command terminated";
+ break;
+ case MPI_SCSI_STATUS_TASK_SET_FULL:
+ desc1 = "task set full";
+ break;
+ case MPI_SCSI_STATUS_ACA_ACTIVE:
+ desc1 = "aca active";
+ break;
+ case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
+ desc1 = "fcpext device logged out";
+ break;
+ case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
+ desc1 = "fcpext no link";
+ break;
+ case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
+ desc1 = "fcpext unassigned";
+ break;
+ default:
+ desc1 = "";
break;
}
- if (!desc)
- return;
+ scsi_print_command(sc);
+ printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n",
+ pScsiReply->Bus, pScsiReply->TargetID);
+ printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n",
+ scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
+ printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
+ le16_to_cpu(pScsiReply->TaskTag),
+ le32_to_cpu(pScsiReply->TransferCount), sc->result);
+
+ printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), "
+ "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
+ desc, ioc_status,
+ desc1, pScsiReply->SCSIStatus,
+ pScsiReply->SCSIState);
- snprintf(extend_desc, EVENT_DESCR_STR_SZ,
- "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
- sc->device->host->host_no,
- sc->device->channel, sc->device->id, sc->device->lun,
- sc->cmnd[0], scsi_status, scsi_state);
+ if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ skey = sc->sense_buffer[2] & 0x0F;
+ asc = sc->sense_buffer[12];
+ ascq = sc->sense_buffer[13];
- printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
- ioc->name, ioc_status, desc, extend_desc);
+ printk(KERN_DEBUG "\t[sense_key,asc,ascq]: "
+ "[0x%02x,0x%02x,0x%02x]\n",
+ skey, asc, ascq);
+ }
+
+ /*
+ * Look for + dump FCP ResponseInfo[]!
+ */
+ if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
+ pScsiReply->ResponseInfo)
+ printk(KERN_DEBUG "response_info = %08xh\n",
+ le32_to_cpu(pScsiReply->ResponseInfo));
}
#endif
@@ -627,11 +692,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
pScsiReply = (SCSIIOReply_t *) mr;
if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
- dmfprintk((MYIOC_s_INFO_FMT
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
}else{
- dmfprintk((MYIOC_s_INFO_FMT
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
ioc->name, mf, mr, sc, req_idx));
}
@@ -759,7 +824,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
- dreplyprintk((KERN_NOTICE
+ dreplyprintk(ioc, printk(KERN_DEBUG
"RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
sc->result, sc->device->channel, sc->device->id));
break;
@@ -792,9 +857,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
}
- dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+
+ dreplyprintk(ioc, printk(KERN_DEBUG " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
sc->underflow));
- dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
+ dreplyprintk(ioc, printk(KERN_DEBUG " ActBytesXferd=%02xh\n", xfer_cnt));
+
/* Report Queue Full
*/
if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
@@ -871,27 +938,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
} /* switch(status) */
-#ifdef MPT_DEBUG_REPLY
- if (sc->result) {
-
- mptscsih_iocstatus_info_scsiio(ioc, status,
- scsi_status, scsi_state, sc);
-
- dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
- "result=0x%08x\n\tiocstatus=0x%04X "
- "scsi_state=0x%02X scsi_status=0x%02X "
- "loginfo=0x%08X\n", __FUNCTION__,
- sc->device->host->host_no, sc->device->channel, sc->device->id,
- sc->device->lun, sc->cmnd[0], sc->result, status,
- scsi_state, scsi_status, log_info));
-
- dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
- "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
- sc->device->host->host_no,
- sc->device->channel, sc->device->id,
- sc->device->lun, scsi_get_resid(sc),
- scsi_bufflen(sc), xfer_cnt));
- }
+#ifdef CONFIG_FUSION_LOGGING
+ if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
+ mptscsih_info_scsiio(ioc, sc, pScsiReply);
#endif
} /* end of address reply case */
@@ -925,7 +974,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
int ii;
int max = ioc->req_depth;
- dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
+ dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n"));
for (ii= 0; ii < max; ii++) {
if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
@@ -937,7 +986,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
hd->ScsiLookup[ii] = NULL;
mf = MPT_INDEX_2_MFPTR(ioc, ii);
- dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
+ dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n",
mf, SCpnt));
/* Free Chain buffers */
@@ -987,7 +1036,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
struct scsi_cmnd *sc;
struct scsi_lun lun;
- dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
+ dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n",
vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
for (ii=0; ii < max; ii++) {
@@ -1020,9 +1069,9 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
scsi_dma_unmap(sc);
sc->host_scribble = NULL;
sc->result = DID_NO_CONNECT << 16;
- dsprintk(( "search_running: found (sc=%p, mf = %p) "
- "channel %d id %d, lun %d \n", sc, mf,
- vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun));
+ sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d,"
+ "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel,
+ vdevice->vtarget->id, sc, mf, ii);
sc->scsi_done(sc);
}
}
@@ -1057,7 +1106,7 @@ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSI
return;
if (time - hd->last_queue_full > 10 * HZ) {
- dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+ dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
hd->ioc->name, 0, sc->device->id, sc->device->lun));
hd->last_queue_full = time;
}
@@ -1098,7 +1147,7 @@ mptscsih_remove(struct pci_dev *pdev)
hd->ScsiLookup = NULL;
}
- dprintk((MYIOC_s_INFO_FMT
+ dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
"Free'd ScsiLookup (%d) memory\n",
hd->ioc->name, sz1));
@@ -1317,17 +1366,19 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
u32 cmd_len;
int my_idx;
int ii;
+ MPT_ADAPTER *ioc;
hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+ ioc = hd->ioc;
lun = SCpnt->device->lun;
SCpnt->scsi_done = done;
- dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
- (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
+ ioc->name, SCpnt, done));
if (hd->resetPending) {
- dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
- (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
+ ioc->name, SCpnt));
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1335,8 +1386,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
* Put together a MPT SCSI request...
*/
if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
- dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
- hd->ioc->name));
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+ ioc->name));
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1422,9 +1473,9 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
hd->ScsiLookup[my_idx] = SCpnt;
mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
- dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
- hd->ioc->name, SCpnt, mf, my_idx));
- DBG_DUMP_REQUEST_FRAME(mf)
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+ ioc->name, SCpnt, mf, my_idx));
+ DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf)
return 0;
fail:
@@ -1475,7 +1526,7 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
ioc->name, chain_idx));
/* handle next */
@@ -1519,7 +1570,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
unsigned long flags;
ioc = hd->ioc;
- dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
// SJR - CHECKME - Can we avoid this here?
// (mpt_HardResetHandler has this check...)
@@ -1539,20 +1590,20 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
*/
if (mptscsih_tm_pending_wait(hd) == FAILED) {
if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
- dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
+ dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: "
"Timed out waiting for last TM (%d) to complete! \n",
- hd->ioc->name, hd->tmPending));
+ ioc->name, hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
- dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
+ dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target "
"reset: Timed out waiting for last TM (%d) "
- "to complete! \n", hd->ioc->name,
+ "to complete! \n", ioc->name,
hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
- dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
+ dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: "
"Timed out waiting for last TM (%d) to complete! \n",
- hd->ioc->name, hd->tmPending));
+ ioc->name, hd->tmPending));
return FAILED;
}
} else {
@@ -1591,12 +1642,13 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
ctx2abort, timeout);
if (rc)
printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
- hd->ioc->name);
+ ioc->name);
else
- dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
- hd->ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
+ ioc->name));
- dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "TMHandler rc = %d!\n", ioc->name, rc));
return rc;
}
@@ -1632,11 +1684,11 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
/* Return Fail to calling function if no message frames available.
*/
if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
- dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+ dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
hd->ioc->name));
return FAILED;
}
- dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+ dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
hd->ioc->name, mf));
/* Format the Request
@@ -1660,27 +1712,27 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
pScsiTm->TaskMsgContext = ctx2abort;
- dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+ dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
"type=%d\n", hd->ioc->name, ctx2abort, type));
- DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
+ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
- dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
+ dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
" (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
hd->ioc, mf, retval));
goto fail_out;
}
if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
- dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
+ dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
hd->ioc, mf));
- dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+ dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
hd->ioc->name));
retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
- dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
+ dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
hd->ioc->name, retval));
goto fail_out;
}
@@ -1748,8 +1800,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
SCpnt->result = DID_RESET << 16;
SCpnt->scsi_done(SCpnt);
- dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
- "host! (sc=%p)\n", SCpnt));
+ printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate "
+ "host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1760,7 +1812,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice = SCpnt->device->hostdata;
if (!vdevice || !vdevice->vtarget) {
- dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been "
"deleted (sc=%p)\n", ioc->name, SCpnt));
SCpnt->result = DID_NO_CONNECT << 16;
SCpnt->scsi_done(SCpnt);
@@ -1771,7 +1823,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* Task aborts are not supported for hidden raid components.
*/
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
- dtmprintk((MYIOC_s_DEBUG_FMT "task abort: hidden raid "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid "
"component (sc=%p)\n", ioc->name, SCpnt));
SCpnt->result = DID_RESET << 16;
retval = FAILED;
@@ -1785,7 +1837,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
* Do OS callback.
*/
SCpnt->result = DID_RESET << 16;
- dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
+ dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: "
"Command not in the active list! (sc=%p)\n", ioc->name,
SCpnt));
retval = 0;
@@ -1850,8 +1902,8 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt));
+ printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1913,8 +1965,8 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt ));
+ printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt );
return FAILED;
}
@@ -1957,8 +2009,8 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
/* If we can't locate the host to reset, then we failed. */
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt));
+ printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -2106,16 +2158,16 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
u8 tmType;
u32 termination_count;
- dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
ioc->name, mf, mr));
if (!ioc->sh) {
- dtmprintk((MYIOC_s_WARN_FMT
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
"TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
return 1;
}
if (mr == NULL) {
- dtmprintk((MYIOC_s_WARN_FMT
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
"ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
return 1;
}
@@ -2131,19 +2183,21 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
pScsiTmReply->ResponseCode)
mptscsih_taskmgmt_response_code(ioc,
pScsiTmReply->ResponseCode);
- DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
-
-#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
- printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
- "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
- "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
- pScsiTmReply->TargetID, pScsiTmReq->TaskType,
- le16_to_cpu(pScsiTmReply->IOCStatus),
- le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
- le32_to_cpu(pScsiTmReply->TerminationCount));
+ DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
+
+#ifdef CONFIG_FUSION_LOGGING
+ if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
+ (ioc->debug_level & MPT_DEBUG_TM ))
+ printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
+ "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
+ "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
+ pScsiTmReply->TargetID, pScsiTmReq->TaskType,
+ le16_to_cpu(pScsiTmReply->IOCStatus),
+ le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
+ le32_to_cpu(pScsiTmReply->TerminationCount));
#endif
if (!iocstatus) {
- dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
hd->abortSCpnt = NULL;
goto out;
}
@@ -2224,10 +2278,6 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
geom[1] = sectors;
geom[2] = cylinders;
- dprintk((KERN_NOTICE
- ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
- sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
-
return 0;
}
@@ -2393,11 +2443,11 @@ mptscsih_slave_configure(struct scsi_device *sdev)
vtarget = starget->hostdata;
vdevice = sdev->hostdata;
- dsprintk((MYIOC_s_INFO_FMT
+ dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
"device @ %p, channel=%d, id=%d, lun=%d\n",
hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
if (hd->ioc->bus_type == SPI)
- dsprintk((MYIOC_s_INFO_FMT
+ dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
"sdtr %d wdtr %d ppr %d inq length=%d\n",
hd->ioc->name, sdev->sdtr, sdev->wdtr,
sdev->ppr, sdev->inquiry_len));
@@ -2411,19 +2461,19 @@ mptscsih_slave_configure(struct scsi_device *sdev)
vdevice->configured_lun = 1;
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
- dsprintk((MYIOC_s_INFO_FMT
+ dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
"Queue depth=%d, tflags=%x\n",
hd->ioc->name, sdev->queue_depth, vtarget->tflags));
if (hd->ioc->bus_type == SPI)
- dsprintk((MYIOC_s_INFO_FMT
+ dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
"negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
vtarget->minSyncFactor));
slave_configure_exit:
- dsprintk((MYIOC_s_INFO_FMT
+ dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
"tagged %d, simple %d, ordered %d\n",
hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
@@ -2490,7 +2540,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
}
}
} else {
- dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
+ dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
hd->ioc->name));
}
}
@@ -2520,7 +2570,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
unsigned long flags;
int ii;
- dtmprintk((KERN_WARNING MYNAM
+ dtmprintk(ioc, printk(KERN_DEBUG MYNAM
": IOC %s_reset routed to SCSI host driver!\n",
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -2535,7 +2585,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
if (reset_phase == MPT_IOC_SETUP_RESET) {
- dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
/* Clean Up:
* 1. Set Hard Reset Pending Flag
@@ -2544,7 +2594,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
hd->resetPending = 1;
} else if (reset_phase == MPT_IOC_PRE_RESET) {
- dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
/* 2. Flush running commands
* Clean ScsiLookup (and associated memory)
@@ -2564,10 +2614,10 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
mpt_free_msg_frame(ioc, hd->cmdPtr);
}
- dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
} else {
- dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
/* Once a FW reload begins, all new OS commands are
* redirected to the doneQ w/ a reset status.
@@ -2607,7 +2657,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
hd->cmdPtr = NULL;
}
- dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
}
@@ -2621,7 +2671,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
MPT_SCSI_HOST *hd;
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
- devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
ioc->name, event));
if (ioc->sh == NULL ||
@@ -2663,7 +2713,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
case MPI_EVENT_STATE_CHANGE: /* 02 */
case MPI_EVENT_EVENT_CHANGE: /* 0A */
default:
- dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
+ dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event));
break;
}
@@ -2724,7 +2774,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
hd->cmdPtr = NULL;
- ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
hd->ioc->name, mf, mr, req_idx));
hd->pLocal = &hd->localReply;
@@ -2744,9 +2794,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
scsi_status = pReply->SCSIStatus;
- ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
- status, pReply->SCSIState, scsi_status,
- le32_to_cpu(pReply->IOCLogInfo)));
switch(status) {
@@ -2799,7 +2846,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
SCSI_STD_SENSE_BYTES);
memcpy(hd->pLocal->sense, sense_data, sz);
- ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
+ ddvprintk(ioc, printk(KERN_DEBUG " Check Condition, sense ptr %p\n",
sense_data));
} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
if (pReq->CDB[0] == INQUIRY)
@@ -2830,8 +2877,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
} /* switch(status) */
- ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
- completionCode));
} /* end of address reply case */
hd->pLocal->completion = completionCode;
@@ -2862,7 +2907,7 @@ mptscsih_timer_expired(unsigned long data)
{
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
- ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
if (hd->cmdPtr) {
MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
@@ -2874,7 +2919,6 @@ mptscsih_timer_expired(unsigned long data)
* If new eh code, do nothing. Wait for OS cmd timeout
* for bus reset.
*/
- ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
} else {
/* Perform a FW reload */
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
@@ -2891,7 +2935,7 @@ mptscsih_timer_expired(unsigned long data)
* The FW will reply to all outstanding commands, callback will finish cleanup.
* Hard reset clean-up will free all resources.
*/
- ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
return;
}
@@ -2932,7 +2976,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
in_isr = in_interrupt();
if (in_isr) {
- dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+ dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
hd->ioc->name));
return -EPERM;
}
@@ -3035,7 +3079,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
/* Get and Populate a free Frame
*/
if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
- ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n",
hd->ioc->name));
return -EBUSY;
}
@@ -3075,7 +3119,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
if (cmd == REQUEST_SENSE) {
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
- ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
hd->ioc->name, cmd));
}
@@ -3086,7 +3130,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
- ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
hd->ioc->name, cmd, io->channel, io->id, io->lun));
if (dir == MPI_SCSIIO_CONTROL_READ) {
@@ -3138,7 +3182,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
} else {
rc = -EFAULT;
/* This should never happen. */
- ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
hd->ioc->name));
}
@@ -3187,6 +3231,189 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
mptscsih_do_cmd(hd, &iocmd);
}
+static ssize_t
+mptscsih_version_fw_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+ ioc->facts.FWVersion.Word & 0x000000FF);
+}
+static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
+
+static ssize_t
+mptscsih_version_bios_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ (ioc->biosVersion & 0xFF000000) >> 24,
+ (ioc->biosVersion & 0x00FF0000) >> 16,
+ (ioc->biosVersion & 0x0000FF00) >> 8,
+ ioc->biosVersion & 0x000000FF);
+}
+static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
+
+static ssize_t
+mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
+}
+static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
+
+static ssize_t
+mptscsih_version_product_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
+}
+static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
+ mptscsih_version_product_show, NULL);
+
+static ssize_t
+mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02xh\n",
+ ioc->nvdata_version_persistent);
+}
+static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
+ mptscsih_version_nvdata_persistent_show, NULL);
+
+static ssize_t
+mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
+}
+static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
+ mptscsih_version_nvdata_default_show, NULL);
+
+static ssize_t
+mptscsih_board_name_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
+}
+static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
+
+static ssize_t
+mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
+}
+static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
+ mptscsih_board_assembly_show, NULL);
+
+static ssize_t
+mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
+}
+static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
+ mptscsih_board_tracer_show, NULL);
+
+static ssize_t
+mptscsih_io_delay_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
+}
+static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
+ mptscsih_io_delay_show, NULL);
+
+static ssize_t
+mptscsih_device_delay_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
+}
+static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
+ mptscsih_device_delay_show, NULL);
+
+static ssize_t
+mptscsih_debug_level_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
+}
+static ssize_t
+mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+ int val = 0;
+
+ if (sscanf(buf, "%x", &val) != 1)
+ return -EINVAL;
+
+ ioc->debug_level = val;
+ printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
+ ioc->name, ioc->debug_level);
+ return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
+ mptscsih_debug_level_show, mptscsih_debug_level_store);
+
+struct class_device_attribute *mptscsih_host_attrs[] = {
+ &class_device_attr_version_fw,
+ &class_device_attr_version_bios,
+ &class_device_attr_version_mpi,
+ &class_device_attr_version_product,
+ &class_device_attr_version_nvdata_persistent,
+ &class_device_attr_version_nvdata_default,
+ &class_device_attr_board_name,
+ &class_device_attr_board_assembly,
+ &class_device_attr_board_tracer,
+ &class_device_attr_io_delay,
+ &class_device_attr_device_delay,
+ &class_device_attr_debug_level,
+ NULL,
+};
+EXPORT_SYMBOL(mptscsih_host_attrs);
+
EXPORT_SYMBOL(mptscsih_remove);
EXPORT_SYMBOL(mptscsih_shutdown);
#ifdef CONFIG_PM
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 8eccdfe5701a..67b088db2f10 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -129,3 +129,4 @@ extern void mptscsih_timer_expired(unsigned long data);
extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
+extern struct class_device_attribute *mptscsih_host_attrs[];
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 6b3e0c00952b..8c98420640a5 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -138,7 +138,9 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
else {
factor = MPT_ULTRA320;
if (scsi_device_qas(sdev)) {
- ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
+ ddvprintk(hd->ioc,
+ printk(KERN_DEBUG "Enabling QAS due to "
+ "byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
noQas = 0;
}
if (sdev->type == TYPE_TAPE &&
@@ -225,7 +227,8 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
/* Disable QAS in a mixed configuration case
*/
- ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+ ddvprintk(hd->ioc, printk(KERN_DEBUG
+ "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
}
}
@@ -256,8 +259,8 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
/* Get a MF for this command.
*/
if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
- dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
- ioc->name));
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+ "writeIOCPage4 : no msg frames!\n",ioc->name));
return -EAGAIN;
}
@@ -297,7 +300,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
- ddvprintk((MYIOC_s_INFO_FMT
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
@@ -422,7 +425,7 @@ static int mptspi_target_alloc(struct scsi_target *starget)
if (starget->channel == 0 &&
mptspi_is_raid(hd, starget->id)) {
vtarget->raidVolume = 1;
- ddvprintk((KERN_INFO
+ ddvprintk(hd->ioc, printk(KERN_DEBUG
"RAID Volume @ channel=%d id=%d\n", starget->channel,
starget->id));
}
@@ -462,7 +465,7 @@ mptspi_target_destroy(struct scsi_target *starget)
static void
mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
{
- ddvprintk((MYIOC_s_INFO_FMT "id=%d Requested = 0x%08x"
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
" ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
hd->ioc->name, starget->id, ii,
ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
@@ -487,7 +490,7 @@ mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget,
static void
mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
{
- ddvprintk((MYIOC_s_INFO_FMT "id=%d Read = 0x%08x"
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
" ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
hd->ioc->name, starget->id, ii,
ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
@@ -613,7 +616,7 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
/* Get and Populate a free Frame
*/
if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
- ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+ ddvprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
hd->ioc->name));
return -EAGAIN;
}
@@ -635,7 +638,7 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
mpt_add_sge((char *)&pReq->ActionDataSGE,
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
- ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n",
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
hd->ioc->name, pReq->Action, channel, id));
hd->pLocal = NULL;
@@ -735,7 +738,7 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
if (ret)
return ret;
- ddvprintk((MYIOC_s_INFO_FMT "id=%d min_period=0x%02x"
+ ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
" max_offset=0x%02x max_width=%d\n", hd->ioc->name,
sdev->id, spi_min_period(scsi_target(sdev)),
spi_max_offset(scsi_target(sdev)),
@@ -768,10 +771,8 @@ mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return 0;
}
-#ifdef MPT_DEBUG_DV
if (spi_dv_pending(scsi_target(SCpnt->device)))
- scsi_print_command(SCpnt);
-#endif
+ ddvprintk(hd->ioc, scsi_print_command(SCpnt));
return mptscsih_qcmd(SCpnt,done);
}
@@ -821,6 +822,7 @@ static struct scsi_host_template mptspi_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mptscsih_host_attrs,
};
static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
@@ -1414,7 +1416,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (numSGE < sh->sg_tablesize) {
/* Reset this value */
- dprintk((MYIOC_s_INFO_FMT
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
"Resetting sg_tablesize to %d from %d\n",
ioc->name, numSGE, sh->sg_tablesize));
sh->sg_tablesize = numSGE;
@@ -1434,7 +1436,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_mptspi_probe;
}
- dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, hd->ScsiLookup));
/* Clear the TM flags
@@ -1462,7 +1464,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->spi_data.Saf_Te = mpt_saf_te;
hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
- ddvprintk((MYIOC_s_INFO_FMT
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"saf_te %x\n",
ioc->name,
mpt_saf_te));
@@ -1480,7 +1482,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
- dprintk((KERN_ERR MYNAM
+ dprintk(ioc, printk(KERN_ERR MYNAM
"scsi_add_host failed\n"));
goto out_mptspi_probe;
}
@@ -1523,6 +1525,8 @@ static struct pci_driver mptspi_driver = {
static int __init
mptspi_init(void)
{
+ int error;
+
show_mptmod_ver(my_NAME, my_VERSION);
mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
@@ -1533,17 +1537,14 @@ mptspi_init(void)
mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
- if (mpt_event_register(mptspiDoneCtx, mptspi_event_process) == 0) {
- devtverboseprintk((KERN_INFO MYNAM
- ": Registered for IOC event notifications\n"));
- }
+ mpt_event_register(mptspiDoneCtx, mptspi_event_process);
+ mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
- if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) {
- dprintk((KERN_INFO MYNAM
- ": Registered for IOC reset notifications\n"));
- }
+ error = pci_register_driver(&mptspi_driver);
+ if (error)
+ spi_release_transport(mptspi_transport_template);
- return pci_register_driver(&mptspi_driver);
+ return error;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1557,12 +1558,7 @@ mptspi_exit(void)
pci_unregister_driver(&mptspi_driver);
mpt_reset_deregister(mptspiDoneCtx);
- dprintk((KERN_INFO MYNAM
- ": Deregistered for IOC reset notifications\n"));
-
mpt_event_deregister(mptspiDoneCtx);
- dprintk((KERN_INFO MYNAM
- ": Deregistered for IOC event notifications\n"));
mpt_deregister(mptspiInternalCtx);
mpt_deregister(mptspiTaskCtx);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 64a52bd7544a..50b2c7334410 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -159,7 +159,7 @@ static int i2o_block_device_flush(struct i2o_device *dev)
* Returns 0 on success or negative error code on failure.
*/
-static int i2o_block_issue_flush(request_queue_t * queue, struct gendisk *disk,
+static int i2o_block_issue_flush(struct request_queue * queue, struct gendisk *disk,
sector_t * error_sector)
{
struct i2o_block_device *i2o_blk_dev = queue->queuedata;
@@ -445,7 +445,7 @@ static void i2o_block_end_request(struct request *req, int uptodate,
{
struct i2o_block_request *ireq = req->special;
struct i2o_block_device *dev = ireq->i2o_blk_dev;
- request_queue_t *q = req->q;
+ struct request_queue *q = req->q;
unsigned long flags;
if (end_that_request_chunk(req, uptodate, nr_bytes)) {
@@ -744,7 +744,7 @@ static int i2o_block_transfer(struct request *req)
{
struct i2o_block_device *dev = req->rq_disk->private_data;
struct i2o_controller *c;
- int tid = dev->i2o_dev->lct_data.tid;
+ u32 tid = dev->i2o_dev->lct_data.tid;
struct i2o_message *msg;
u32 *mptr;
struct i2o_block_request *ireq = req->special;
@@ -1171,8 +1171,7 @@ static int __init i2o_block_init(void)
/* Allocate request mempool and slab */
size = sizeof(struct i2o_block_request);
i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
- SLAB_HWCACHE_ALIGN, NULL,
- NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!i2o_blk_req_pool.slab) {
osm_err("can't init request slab\n");
rc = -ENOMEM;
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 75f401d52fda..b4ed57e02729 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -200,9 +200,8 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
{
struct mcp *mcp;
- mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL);
+ mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
if (mcp) {
- memset(mcp, 0, sizeof(struct mcp) + size);
spin_lock_init(&mcp->lock);
mcp->attached_device.parent = parent;
mcp->attached_device.bus = &mcp_bus_type;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 149810a084f5..e03f1bcd4f9f 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -484,12 +484,11 @@ static int ucb1x00_probe(struct mcp *mcp)
goto err_disable;
}
- ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
+ ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
ret = -ENOMEM;
if (!ucb)
goto err_disable;
- memset(ucb, 0, sizeof(struct ucb1x00));
ucb->cdev.class = &ucb1x00_class;
ucb->cdev.dev = &mcp->attached_device;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1d516f24ba53..73e248fb2ff1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -5,6 +5,11 @@
menuconfig MISC_DEVICES
bool "Misc devices"
default y
+ ---help---
+ Say Y here to get to see options for device drivers from various
+ different categories. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if MISC_DEVICES
@@ -150,6 +155,7 @@ config THINKPAD_ACPI
depends on X86 && ACPI
select BACKLIGHT_CLASS_DEVICE
select HWMON
+ select NVRAM
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -196,4 +202,5 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
+
endif # MISC_DEVICES
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 7798f590e5aa..7dce318df1bd 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -53,7 +53,6 @@
#define ASUS_HOTK_NAME "Asus Laptop Support"
#define ASUS_HOTK_CLASS "hotkey"
#define ASUS_HOTK_DEVICE_NAME "Hotkey"
-#define ASUS_HOTK_HID "ATK0100"
#define ASUS_HOTK_FILE "asus-laptop"
#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
@@ -197,12 +196,18 @@ static struct asus_hotk *hotk;
/*
* The hotkey driver declaration
*/
+static const struct acpi_device_id asus_device_ids[] = {
+ {"ATK0100", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+
static int asus_hotk_add(struct acpi_device *device);
static int asus_hotk_remove(struct acpi_device *device, int type);
static struct acpi_driver asus_hotk_driver = {
.name = ASUS_HOTK_NAME,
.class = ASUS_HOTK_CLASS,
- .ids = ASUS_HOTK_HID,
+ .ids = asus_device_ids,
.ops = {
.add = asus_hotk_add,
.remove = asus_hotk_remove,
@@ -727,7 +732,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
lcd_blank(FB_BLANK_POWERDOWN);
}
- acpi_bus_generate_event(hotk->device, event,
+ acpi_bus_generate_proc_event(hotk->device, event,
hotk->event_count[event % 128]++);
return;
@@ -979,10 +984,9 @@ static int asus_hotk_add(struct acpi_device *device)
printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
ASUS_LAPTOP_VERSION);
- hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
if (!hotk)
return -ENOMEM;
- memset(hotk, 0, sizeof(struct asus_hotk));
hotk->handle = device->handle;
strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
@@ -1068,19 +1072,17 @@ static void asus_backlight_exit(void)
}
#define ASUS_LED_UNREGISTER(object) \
- if(object##_led.class_dev \
- && !IS_ERR(object##_led.class_dev)) \
+ if (object##_led.dev) \
led_classdev_unregister(&object##_led)
static void asus_led_exit(void)
{
+ destroy_workqueue(led_workqueue);
ASUS_LED_UNREGISTER(mled);
ASUS_LED_UNREGISTER(tled);
ASUS_LED_UNREGISTER(pled);
ASUS_LED_UNREGISTER(rled);
ASUS_LED_UNREGISTER(gled);
-
- destroy_workqueue(led_workqueue);
}
static void __exit asus_laptop_exit(void)
@@ -1136,29 +1138,42 @@ static int asus_led_init(struct device *dev)
rv = ASUS_LED_REGISTER(mled, dev);
if (rv)
- return rv;
+ goto out;
rv = ASUS_LED_REGISTER(tled, dev);
if (rv)
- return rv;
+ goto out1;
rv = ASUS_LED_REGISTER(rled, dev);
if (rv)
- return rv;
+ goto out2;
rv = ASUS_LED_REGISTER(pled, dev);
if (rv)
- return rv;
+ goto out3;
rv = ASUS_LED_REGISTER(gled, dev);
if (rv)
- return rv;
+ goto out4;
led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!led_workqueue)
- return -ENOMEM;
+ goto out5;
return 0;
+out5:
+ rv = -ENOMEM;
+ ASUS_LED_UNREGISTER(gled);
+out4:
+ ASUS_LED_UNREGISTER(pled);
+out3:
+ ASUS_LED_UNREGISTER(rled);
+out2:
+ ASUS_LED_UNREGISTER(tled);
+out1:
+ ASUS_LED_UNREGISTER(mled);
+out:
+ return rv;
}
static int __init asus_laptop_init(void)
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 276ba3c5143f..aa8ce7abe922 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -19,16 +19,41 @@
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
+#include <linux/hdpu_features.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
-#include <linux/hdpu_features.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
#define SKY_CPUSTATE_VERSION "1.1"
static int hdpu_cpustate_probe(struct platform_device *pdev);
static int hdpu_cpustate_remove(struct platform_device *pdev);
-struct cpustate_t cpustate;
+static unsigned char cpustate_get_state(void);
+static int cpustate_proc_open(struct inode *inode, struct file *file);
+static int cpustate_proc_read(struct seq_file *seq, void *offset);
+
+static struct cpustate_t cpustate;
+
+static const struct file_operations proc_cpustate = {
+ .open = cpustate_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int cpustate_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cpustate_proc_read, NULL);
+}
+
+static int cpustate_proc_read(struct seq_file *seq, void *offset)
+{
+ seq_printf(seq, "CPU State: %04x\n", cpustate_get_state());
+ return 0;
+}
static int cpustate_get_ref(int excl)
{
@@ -66,13 +91,13 @@ static int cpustate_free_ref(void)
return 0;
}
-unsigned char cpustate_get_state(void)
+static unsigned char cpustate_get_state(void)
{
return cpustate.cached_val;
}
-void cpustate_set_state(unsigned char new_state)
+static void cpustate_set_state(unsigned char new_state)
{
unsigned int state = (new_state << 21);
@@ -134,29 +159,6 @@ static int cpustate_release(struct inode *inode, struct file *file)
return cpustate_free_ref();
}
-/*
- * Info exported via "/proc/sky_cpustate".
- */
-static int cpustate_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- int len = 0;
-
- p += sprintf(p, "CPU State: %04x\n", cpustate_get_state());
- len = p - page;
-
- if (len <= off + count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-}
-
static struct platform_driver hdpu_cpustate_driver = {
.probe = hdpu_cpustate_probe,
.remove = hdpu_cpustate_remove,
@@ -169,22 +171,18 @@ static struct platform_driver hdpu_cpustate_driver = {
* The various file operations we support.
*/
static const struct file_operations cpustate_fops = {
- owner:THIS_MODULE,
- open:cpustate_open,
- release:cpustate_release,
- read:cpustate_read,
- write:cpustate_write,
- fasync:NULL,
- poll:NULL,
- ioctl:NULL,
- llseek:no_llseek,
-
+ .owner = THIS_MODULE,
+ .open = cpustate_open,
+ .release = cpustate_release,
+ .read = cpustate_read,
+ .write = cpustate_write,
+ .llseek = no_llseek,
};
static struct miscdevice cpustate_dev = {
- MISC_DYNAMIC_MINOR,
- "sky_cpustate",
- &cpustate_fops
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sky_cpustate",
+ .fops = &cpustate_fops,
};
static int hdpu_cpustate_probe(struct platform_device *pdev)
@@ -194,23 +192,31 @@ static int hdpu_cpustate_probe(struct platform_device *pdev)
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ printk(KERN_ERR "sky_cpustate: "
+ "Invalid memory resource.\n");
+ return -EINVAL;
+ }
cpustate.set_addr = (unsigned long *)res->start;
cpustate.clr_addr = (unsigned long *)res->end - 1;
ret = misc_register(&cpustate_dev);
if (ret) {
- printk(KERN_WARNING "sky_cpustate: Unable to register misc "
- "device.\n");
+ printk(KERN_WARNING "sky_cpustate: "
+ "Unable to register misc device.\n");
cpustate.set_addr = NULL;
cpustate.clr_addr = NULL;
return ret;
}
- proc_de = create_proc_read_entry("sky_cpustate", 0, 0,
- cpustate_read_proc, NULL);
- if (proc_de == NULL)
- printk(KERN_WARNING "sky_cpustate: Unable to create proc "
- "dir entry\n");
+ proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root);
+ 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");
return 0;
@@ -218,21 +224,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev)
static int hdpu_cpustate_remove(struct platform_device *pdev)
{
-
cpustate.set_addr = NULL;
cpustate.clr_addr = NULL;
remove_proc_entry("sky_cpustate", NULL);
misc_deregister(&cpustate_dev);
- return 0;
+ return 0;
}
static int __init cpustate_init(void)
{
- int rc;
- rc = platform_driver_register(&hdpu_cpustate_driver);
- return rc;
+ return platform_driver_register(&hdpu_cpustate_driver);
}
static void __exit cpustate_exit(void)
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 60c8b26f0678..2887b2147980 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -18,17 +18,38 @@
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/hdpu_features.h>
-
#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
static int hdpu_nexus_probe(struct platform_device *pdev);
static int hdpu_nexus_remove(struct platform_device *pdev);
+static int hdpu_slot_id_open(struct inode *inode, struct file *file);
+static int hdpu_slot_id_read(struct seq_file *seq, void *offset);
+static int hdpu_chassis_id_open(struct inode *inode, struct file *file);
+static int hdpu_chassis_id_read(struct seq_file *seq, void *offset);
static struct proc_dir_entry *hdpu_slot_id;
static struct proc_dir_entry *hdpu_chassis_id;
static int slot_id = -1;
static int chassis_id = -1;
+static const struct file_operations proc_slot_id = {
+ .open = hdpu_slot_id_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations proc_chassis_id = {
+ .open = hdpu_chassis_id_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static struct platform_driver hdpu_nexus_driver = {
.probe = hdpu_nexus_probe,
.remove = hdpu_nexus_remove,
@@ -37,43 +58,67 @@ static struct platform_driver hdpu_nexus_driver = {
},
};
-int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset,
- int buffer_length, int *zero, void *ptr)
+static int hdpu_slot_id_open(struct inode *inode, struct file *file)
{
+ return single_open(file, hdpu_slot_id_read, NULL);
+}
- if (offset > 0)
- return 0;
- return sprintf(buffer, "%d\n", slot_id);
+static int hdpu_slot_id_read(struct seq_file *seq, void *offset)
+{
+ seq_printf(seq, "%d\n", slot_id);
+ return 0;
}
-int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset,
- int buffer_length, int *zero, void *ptr)
+static int hdpu_chassis_id_open(struct inode *inode, struct file *file)
{
+ return single_open(file, hdpu_chassis_id_read, NULL);
+}
- if (offset > 0)
- return 0;
- return sprintf(buffer, "%d\n", chassis_id);
+static int hdpu_chassis_id_read(struct seq_file *seq, void *offset)
+{
+ seq_printf(seq, "%d\n", chassis_id);
+ return 0;
}
static int hdpu_nexus_probe(struct platform_device *pdev)
{
struct resource *res;
+ int *nexus_id_addr;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- int *nexus_id_addr;
- nexus_id_addr =
- ioremap(res->start, (unsigned long)(res->end - res->start));
+ if (!res) {
+ printk(KERN_ERR "sky_nexus: "
+ "Invalid memory resource.\n");
+ return -EINVAL;
+ }
+ nexus_id_addr = ioremap(res->start,
+ (unsigned long)(res->end - res->start));
if (nexus_id_addr) {
slot_id = (*nexus_id_addr >> 8) & 0x1f;
chassis_id = *nexus_id_addr & 0xff;
iounmap(nexus_id_addr);
- } else
- printk("Could not map slot id\n");
+ } else {
+ 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->read_proc = hdpu_slot_id_read;
+ 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);
- hdpu_chassis_id->read_proc = hdpu_chassis_id_read;
+ 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;
}
@@ -81,18 +126,19 @@ 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);
+
hdpu_slot_id = 0;
hdpu_chassis_id = 0;
+
return 0;
}
static int __init nexus_init(void)
{
- int rc;
- rc = platform_driver_register(&hdpu_nexus_driver);
- return rc;
+ return platform_driver_register(&hdpu_nexus_driver);
}
static void __exit nexus_exit(void)
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index b5df347c81b9..6497872df524 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -41,18 +41,16 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
return NULL;
- cmd = kmalloc(sizeof(struct command), GFP_KERNEL);
+ cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
if (cmd == NULL)
return NULL;
- memset(cmd, 0, sizeof(*cmd));
- cmd->buffer = kmalloc(buffer_size, GFP_KERNEL);
+ cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
if (cmd->buffer == NULL) {
kfree(cmd);
return NULL;
}
- memset(cmd->buffer, 0, buffer_size);
cmd->buffer_size = buffer_size;
kobject_init(&cmd->kobj);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index eb7b073734b8..22a7e8ba211d 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -563,11 +563,10 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user *
if (*offset != 0)
return 0;
- buff = kmalloc (count + 1, GFP_KERNEL);
+ buff = kzalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
- memset(buff, 0x0, count + 1);
if (copy_from_user(buff, ubuff, count)) {
kfree(buff);
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index fb03a853fac4..4f9d4a9da983 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -77,13 +77,12 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
/* vnc client won't work without bus-mastering */
pci_set_master(pdev);
- sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
+ sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
if (sp == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory\n");
result = -ENOMEM;
goto error_kmalloc;
}
- memset(sp, 0, sizeof(struct service_processor));
spin_lock_init(&sp->lock);
INIT_LIST_HEAD(&sp->command_queue);
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 932a415197b3..83679c762925 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -283,7 +283,7 @@ static struct platform_device *msipf_device;
/* Initialization */
-static int dmi_check_cb(struct dmi_system_id *id)
+static int dmi_check_cb(const struct dmi_system_id *id)
{
printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
return 0;
@@ -353,7 +353,7 @@ static int __init msi_init(void)
if (IS_ERR(msibl_device))
return PTR_ERR(msibl_device);
- msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1,
+ msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
ret = platform_driver_register(&msipf_driver);
if (ret)
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 9623eaf4f89f..e73a71f04bb4 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -142,43 +142,124 @@ struct sony_laptop_keypress {
int key;
};
-/* Correspondance table between sonypi events and input layer events */
-static struct {
- int sonypiev;
- int inputev;
-} sony_laptop_inputkeys[] = {
- { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
- { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
- { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
- { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
- { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
- { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
- { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
- { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
- { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
- { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
- { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
- { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
- { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
- { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
- { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
- { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
- { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
- { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
- { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
- { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
- { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
- { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
- { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
- { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
- { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
- { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
- { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
- { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
- { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
- { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
- { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
- { 0, 0 },
+/* Correspondance table between sonypi events
+ * and input layer indexes in the keymap
+ */
+static int sony_laptop_input_index[] = {
+ -1, /* no event */
+ -1, /* SONYPI_EVENT_JOGDIAL_DOWN */
+ -1, /* SONYPI_EVENT_JOGDIAL_UP */
+ -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+ -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+ -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */
+ -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */
+ 0, /* SONYPI_EVENT_CAPTURE_PRESSED */
+ 1, /* SONYPI_EVENT_CAPTURE_RELEASED */
+ 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+ 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+ 4, /* SONYPI_EVENT_FNKEY_ESC */
+ 5, /* SONYPI_EVENT_FNKEY_F1 */
+ 6, /* SONYPI_EVENT_FNKEY_F2 */
+ 7, /* SONYPI_EVENT_FNKEY_F3 */
+ 8, /* SONYPI_EVENT_FNKEY_F4 */
+ 9, /* SONYPI_EVENT_FNKEY_F5 */
+ 10, /* SONYPI_EVENT_FNKEY_F6 */
+ 11, /* SONYPI_EVENT_FNKEY_F7 */
+ 12, /* SONYPI_EVENT_FNKEY_F8 */
+ 13, /* SONYPI_EVENT_FNKEY_F9 */
+ 14, /* SONYPI_EVENT_FNKEY_F10 */
+ 15, /* SONYPI_EVENT_FNKEY_F11 */
+ 16, /* SONYPI_EVENT_FNKEY_F12 */
+ 17, /* SONYPI_EVENT_FNKEY_1 */
+ 18, /* SONYPI_EVENT_FNKEY_2 */
+ 19, /* SONYPI_EVENT_FNKEY_D */
+ 20, /* SONYPI_EVENT_FNKEY_E */
+ 21, /* SONYPI_EVENT_FNKEY_F */
+ 22, /* SONYPI_EVENT_FNKEY_S */
+ 23, /* SONYPI_EVENT_FNKEY_B */
+ 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */
+ 25, /* SONYPI_EVENT_PKEY_P1 */
+ 26, /* SONYPI_EVENT_PKEY_P2 */
+ 27, /* SONYPI_EVENT_PKEY_P3 */
+ 28, /* SONYPI_EVENT_BACK_PRESSED */
+ -1, /* SONYPI_EVENT_LID_CLOSED */
+ -1, /* SONYPI_EVENT_LID_OPENED */
+ 29, /* SONYPI_EVENT_BLUETOOTH_ON */
+ 30, /* SONYPI_EVENT_BLUETOOTH_OFF */
+ 31, /* SONYPI_EVENT_HELP_PRESSED */
+ 32, /* SONYPI_EVENT_FNKEY_ONLY */
+ 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+ 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */
+ 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+ 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+ 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+ 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
+ 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+ 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+ 41, /* SONYPI_EVENT_ZOOM_PRESSED */
+ 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
+ 43, /* SONYPI_EVENT_MEYE_FACE */
+ 44, /* SONYPI_EVENT_MEYE_OPPOSITE */
+ 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */
+ 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */
+ -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */
+ -1, /* SONYPI_EVENT_BATTERY_INSERT */
+ -1, /* SONYPI_EVENT_BATTERY_REMOVE */
+ -1, /* SONYPI_EVENT_FNKEY_RELEASED */
+ 47, /* SONYPI_EVENT_WIRELESS_ON */
+ 48, /* SONYPI_EVENT_WIRELESS_OFF */
+};
+
+static int sony_laptop_input_keycode_map[] = {
+ KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */
+ KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */
+ KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+ KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+ KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */
+ KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */
+ KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */
+ KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */
+ KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */
+ KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */
+ KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */
+ KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */
+ KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */
+ KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */
+ KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */
+ KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */
+ KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */
+ KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */
+ KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */
+ KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */
+ KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */
+ KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */
+ KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */
+ KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */
+ KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
+ KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */
+ KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */
+ KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */
+ KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */
+ KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */
+ KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */
+ KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */
+ KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */
+ KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+ KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
+ KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+ KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+ KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+ KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+ KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+ KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+ KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */
+ BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+ KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */
+ KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */
+ KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
+ KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
+ KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
+ KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
};
/* release buttons after a short delay if pressed */
@@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event)
struct input_dev *jog_dev = sony_laptop_input.jog_dev;
struct input_dev *key_dev = sony_laptop_input.key_dev;
struct sony_laptop_keypress kp = { NULL };
- int i;
if (event == SONYPI_EVENT_FNKEY_RELEASED) {
/* Nothing, not all VAIOs generate this event */
@@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event)
break;
default:
- for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
- if (event == sony_laptop_inputkeys[i].sonypiev) {
+ if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+ dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
+ break;
+ }
+ if (sony_laptop_input_index[event] != -1) {
+ kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+ if (kp.key != KEY_UNKNOWN)
kp.dev = key_dev;
- kp.key = sony_laptop_inputkeys[i].inputev;
- break;
- }
+ }
break;
}
if (kp.dev) {
input_report_key(kp.dev, kp.key, 1);
+ /* we emit the scancode so we can always remap the key */
+ input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
kfifo_put(sony_laptop_input.fifo,
(unsigned char *)&kp, sizeof(kp));
@@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void)
key_dev->id.vendor = PCI_VENDOR_ID_SONY;
/* Initialize the Input Drivers: special keys */
- key_dev->evbit[0] = BIT(EV_KEY);
- for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
- if (sony_laptop_inputkeys[i].inputev)
- set_bit(sony_laptop_inputkeys[i].inputev,
- key_dev->keybit);
+ set_bit(EV_KEY, key_dev->evbit);
+ set_bit(EV_MSC, key_dev->evbit);
+ set_bit(MSC_SCAN, key_dev->mscbit);
+ key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
+ key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
+ key_dev->keycode = &sony_laptop_input_keycode_map;
+ for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
+ if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
+ set_bit(sony_laptop_input_keycode_map[i],
+ key_dev->keybit);
+ }
+ }
error = input_register_device(key_dev);
if (error)
@@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW");
SNC_HANDLE_NAMES(lanpower_get, "GLNP");
SNC_HANDLE_NAMES(lanpower_set, "LNPW");
+SNC_HANDLE_NAMES(lidstate_get, "GLID");
+
+SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
+SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
+
+SNC_HANDLE_NAMES(gainbass_get, "GMGB");
+SNC_HANDLE_NAMES(gainbass_set, "CMGB");
+
SNC_HANDLE_NAMES(PID_get, "GPID");
SNC_HANDLE_NAMES(CTR_get, "GCTR");
@@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = {
boolean_validate, 0),
SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
boolean_validate, 1),
+ SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
+ boolean_validate, 0),
+ SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
+ boolean_validate, 0),
+ SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
+ boolean_validate, 0),
/* unknown methods */
SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
@@ -689,13 +795,125 @@ static struct backlight_ops sony_backlight_ops = {
};
/*
+ * New SNC-only Vaios event mapping to driver known keys
+ */
+struct sony_nc_event {
+ u8 data;
+ u8 event;
+};
+
+static struct sony_nc_event *sony_nc_events;
+
+/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
+ * for Fn keys
+ */
+static int sony_nc_C_enable(const struct dmi_system_id *id)
+{
+ int result = 0;
+
+ printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
+
+ sony_nc_events = id->driver_data;
+
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
+ printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
+ "functionalities may be missing\n");
+ return 1;
+ }
+ return 0;
+}
+
+static struct sony_nc_event sony_C_events[] = {
+ { 0x81, SONYPI_EVENT_FNKEY_F1 },
+ { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x85, SONYPI_EVENT_FNKEY_F5 },
+ { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x86, SONYPI_EVENT_FNKEY_F6 },
+ { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x87, SONYPI_EVENT_FNKEY_F7 },
+ { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x8A, SONYPI_EVENT_FNKEY_F10 },
+ { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x8C, SONYPI_EVENT_FNKEY_F12 },
+ { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0, 0 },
+};
+
+/* SNC-only model map */
+static const struct dmi_system_id sony_nc_ids[] = {
+ {
+ .ident = "Sony Vaio FE Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
+ },
+ },
+ {
+ .ident = "Sony Vaio FZ Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"),
+ },
+ },
+ {
+ .ident = "Sony Vaio C Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
+ },
+ },
+ { }
+};
+
+/*
* ACPI callbacks
*/
static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
{
- dprintk("sony_acpi_notify, event: %d\n", event);
- sony_laptop_report_input_event(event);
- acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
+ struct sony_nc_event *evmap;
+ u32 ev = event;
+ int result;
+
+ if (ev == 0x92) {
+ /* read the key pressed from EC.GECR
+ * A call to SN07 with 0x0202 will do it as well respecting
+ * the current protocol on different OSes
+ *
+ * Note: the path for GECR may be
+ * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends)
+ * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR)
+ *
+ * TODO: we may want to do the same for the older GHKE -need
+ * dmi list- so this snippet may become one more callback.
+ */
+ if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
+ dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
+ else
+ ev = result & 0xFF;
+ }
+
+ if (sony_nc_events)
+ for (evmap = sony_nc_events; evmap->event; evmap++) {
+ if (evmap->data == ev) {
+ ev = evmap->event;
+ break;
+ }
+ }
+
+ dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
+ sony_laptop_report_input_event(ev);
+ acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
}
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -732,6 +950,15 @@ static int sony_nc_resume(struct acpi_device *device)
break;
}
}
+
+ /* set the last requested brightness level */
+ if (sony_backlight_device &&
+ !sony_backlight_update_status(sony_backlight_device))
+ printk(KERN_WARNING DRV_PFX "unable to restore brightness level");
+
+ /* re-initialize models with specific requirements */
+ dmi_check_system(sony_nc_ids);
+
return 0;
}
@@ -750,6 +977,15 @@ static int sony_nc_add(struct acpi_device *device)
sony_nc_acpi_handle = device->handle;
+ /* read device status */
+ result = acpi_bus_get_status(device);
+ /* bail IFF the above call was successful and the device is not present */
+ if (!result && !device->status.present) {
+ dprintk("Device not present\n");
+ result = -ENODEV;
+ goto outwalk;
+ }
+
if (debug) {
status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
1, sony_walk_callback, NULL, NULL);
@@ -760,6 +996,15 @@ static int sony_nc_add(struct acpi_device *device)
}
}
+ /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
+ * should be respected as we already checked for the device presence above */
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
+ dprintk("Invoking _INI\n");
+ if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
+ NULL, NULL)))
+ dprintk("_INI Method failed\n");
+ }
+
/* setup input devices and helper fifo */
result = sony_laptop_setup_input();
if (result) {
@@ -772,7 +1017,7 @@ static int sony_nc_add(struct acpi_device *device)
ACPI_DEVICE_NOTIFY,
sony_acpi_notify, NULL);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
result = -ENODEV;
goto outinput;
}
@@ -795,6 +1040,9 @@ static int sony_nc_add(struct acpi_device *device)
}
+ /* initialize models with specific requirements */
+ dmi_check_system(sony_nc_ids);
+
result = sony_pf_add();
if (result)
goto outbacklight;
@@ -890,10 +1138,22 @@ static int sony_nc_remove(struct acpi_device *device, int type)
return 0;
}
+static const struct acpi_device_id sony_device_ids[] = {
+ {SONY_NC_HID, 0},
+ {SONY_PIC_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, sony_device_ids);
+
+static const struct acpi_device_id sony_nc_device_ids[] = {
+ {SONY_NC_HID, 0},
+ {"", 0},
+};
+
static struct acpi_driver sony_nc_driver = {
.name = SONY_NC_DRIVER_NAME,
.class = SONY_NC_CLASS,
- .ids = SONY_NC_HID,
+ .ids = sony_nc_device_ids,
.owner = THIS_MODULE,
.ops = {
.add = sony_nc_add,
@@ -908,7 +1168,9 @@ static struct acpi_driver sony_nc_driver = {
#define SONYPI_DEVICE_TYPE2 0x00000002
#define SONYPI_DEVICE_TYPE3 0x00000004
-#define SONY_PIC_EV_MASK 0xff
+#define SONYPI_TYPE1_OFFSET 0x04
+#define SONYPI_TYPE2_OFFSET 0x12
+#define SONYPI_TYPE3_OFFSET 0x12
struct sony_pic_ioport {
struct acpi_resource_io io;
@@ -922,6 +1184,7 @@ struct sony_pic_irq {
struct sony_pic_dev {
int model;
+ u16 evport_offset;
u8 camera_power;
u8 bluetooth_power;
u8 wwan_power;
@@ -1999,20 +2262,17 @@ end:
static irqreturn_t sony_pic_irq(int irq, void *dev_id)
{
int i, j;
- u32 port_val = 0;
u8 ev = 0;
u8 data_mask = 0;
u8 device_event = 0;
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
- acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
- dev->cur_ioport->io.address_length);
- ev = port_val & SONY_PIC_EV_MASK;
- data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+ ev = inb_p(dev->cur_ioport->io.minimum);
+ data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
- dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
- port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+ dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+ ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED;
@@ -2041,7 +2301,7 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
found:
sony_laptop_report_input_event(device_event);
- acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
+ acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event);
sonypi_compat_report_event(device_event);
return IRQ_HANDLED;
@@ -2057,8 +2317,6 @@ static int sony_pic_remove(struct acpi_device *device, int type)
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
- sonypi_compat_exit();
-
if (sony_pic_disable(device)) {
printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
return -ENXIO;
@@ -2068,6 +2326,8 @@ static int sony_pic_remove(struct acpi_device *device, int type)
release_region(spic_dev.cur_ioport->io.minimum,
spic_dev.cur_ioport->io.address_length);
+ sonypi_compat_exit();
+
sony_laptop_remove_input();
/* pf attrs */
@@ -2103,6 +2363,20 @@ static int sony_pic_add(struct acpi_device *device)
spic_dev.model = sony_pic_detect_device_type();
mutex_init(&spic_dev.lock);
+ /* model specific characteristics */
+ switch(spic_dev.model) {
+ case SONYPI_DEVICE_TYPE1:
+ spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
+ break;
+ case SONYPI_DEVICE_TYPE3:
+ spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
+ break;
+ case SONYPI_DEVICE_TYPE2:
+ default:
+ spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
+ break;
+ }
+
/* read _PRS resources */
result = sony_pic_possible_resources(device);
if (result) {
@@ -2119,6 +2393,9 @@ static int sony_pic_add(struct acpi_device *device)
goto err_free_resources;
}
+ if (sonypi_compat_init())
+ goto err_remove_input;
+
/* request io port */
list_for_each_entry(io, &spic_dev.ioports, list) {
if (request_region(io->io.minimum, io->io.address_length,
@@ -2133,7 +2410,7 @@ static int sony_pic_add(struct acpi_device *device)
if (!spic_dev.cur_ioport) {
printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
result = -ENODEV;
- goto err_remove_input;
+ goto err_remove_compat;
}
/* request IRQ */
@@ -2173,9 +2450,6 @@ static int sony_pic_add(struct acpi_device *device)
if (result)
goto err_remove_pf;
- if (sonypi_compat_init())
- goto err_remove_pf;
-
return 0;
err_remove_pf:
@@ -2191,6 +2465,9 @@ err_release_region:
release_region(spic_dev.cur_ioport->io.minimum,
spic_dev.cur_ioport->io.address_length);
+err_remove_compat:
+ sonypi_compat_exit();
+
err_remove_input:
sony_laptop_remove_input();
@@ -2222,10 +2499,15 @@ static int sony_pic_resume(struct acpi_device *device)
return 0;
}
+static const struct acpi_device_id sony_pic_device_ids[] = {
+ {SONY_PIC_HID, 0},
+ {"", 0},
+};
+
static struct acpi_driver sony_pic_driver = {
.name = SONY_PIC_DRIVER_NAME,
.class = SONY_PIC_CLASS,
- .ids = SONY_PIC_HID,
+ .ids = sony_pic_device_ids,
.owner = THIS_MODULE,
.ops = {
.add = sony_pic_add,
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 95c0b96e83f2..6c0b2f0a51ab 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,8 +21,8 @@
* 02110-1301, USA.
*/
-#define IBM_VERSION "0.14"
-#define TPACPI_SYSFS_VERSION 0x000100
+#define IBM_VERSION "0.16"
+#define TPACPI_SYSFS_VERSION 0x010000
/*
* Changelog:
@@ -92,6 +92,29 @@ MODULE_LICENSE("GPL");
/* Please remove this in year 2009 */
MODULE_ALIAS("ibm_acpi");
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+ MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
+
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+
#define __unused __attribute__ ((unused))
/****************************************************************************
@@ -106,7 +129,7 @@ MODULE_ALIAS("ibm_acpi");
* ACPI basic handles
*/
-static acpi_handle root_handle = NULL;
+static acpi_handle root_handle;
#define IBM_HANDLE(object, parent, paths...) \
static acpi_handle object##_handle; \
@@ -388,12 +411,13 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
ibm->acpi->driver->ids = ibm->acpi->hid;
+
ibm->acpi->driver->ops.add = &tpacpi_device_add;
rc = acpi_bus_register_driver(ibm->acpi->driver);
if (rc < 0) {
printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
- ibm->acpi->hid, rc);
+ ibm->name, rc);
kfree(ibm->acpi->driver);
ibm->acpi->driver = NULL;
} else if (!rc)
@@ -487,19 +511,36 @@ static char *next_cmd(char **cmds)
/****************************************************************************
****************************************************************************
*
- * Device model: hwmon and platform
+ * Device model: input, hwmon and platform
*
****************************************************************************
****************************************************************************/
-static struct platform_device *tpacpi_pdev = NULL;
-static struct class_device *tpacpi_hwmon = NULL;
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct input_dev *tpacpi_inputdev;
+
+
+static int tpacpi_resume_handler(struct platform_device *pdev)
+{
+ struct ibm_struct *ibm, *itmp;
+
+ list_for_each_entry_safe(ibm, itmp,
+ &tpacpi_all_drivers,
+ all_drivers) {
+ if (ibm->resume)
+ (ibm->resume)();
+ }
+
+ return 0;
+}
static struct platform_driver tpacpi_pdriver = {
.driver = {
.name = IBM_DRVR_NAME,
.owner = THIS_MODULE,
},
+ .resume = tpacpi_resume_handler,
};
@@ -677,9 +718,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
printk(IBM_INFO "%s\n", IBM_URL);
- if (ibm_thinkpad_ec_found)
- printk(IBM_INFO "ThinkPad EC firmware %s\n",
- ibm_thinkpad_ec_found);
+ printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+ (thinkpad_id.bios_version_str) ?
+ thinkpad_id.bios_version_str : "unknown",
+ (thinkpad_id.ec_version_str) ?
+ thinkpad_id.ec_version_str : "unknown");
+
+ if (thinkpad_id.vendor && thinkpad_id.model_str)
+ printk(IBM_INFO "%s %s\n",
+ (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+ "IBM" : ((thinkpad_id.vendor ==
+ PCI_VENDOR_ID_LENOVO) ?
+ "Lenovo" : "Unknown vendor"),
+ thinkpad_id.model_str);
return 0;
}
@@ -704,16 +755,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
*/
static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
+static u32 hotkey_all_mask;
+static u32 hotkey_reserved_mask;
-static struct attribute_set *hotkey_dev_attributes = NULL;
+static u16 *hotkey_keycode_map;
+
+static struct attribute_set *hotkey_dev_attributes;
+
+static int hotkey_get_wlsw(int *status)
+{
+ if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+ return -EIO;
+ return 0;
+}
/* sysfs hotkey enable ------------------------------------------------- */
static ssize_t hotkey_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
res = hotkey_get(&status, &mask);
if (res)
@@ -727,7 +790,8 @@ static ssize_t hotkey_enable_store(struct device *dev,
const char *buf, size_t count)
{
unsigned long t;
- int res, status, mask;
+ int res, status;
+ u32 mask;
if (parse_strtoul(buf, 1, &t))
return -EINVAL;
@@ -748,13 +812,14 @@ static ssize_t hotkey_mask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
res = hotkey_get(&status, &mask);
if (res)
return res;
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
}
static ssize_t hotkey_mask_store(struct device *dev,
@@ -762,9 +827,10 @@ static ssize_t hotkey_mask_store(struct device *dev,
const char *buf, size_t count)
{
unsigned long t;
- int res, status, mask;
+ int res, status;
+ u32 mask;
- if (parse_strtoul(buf, 0xffff, &t))
+ if (parse_strtoul(buf, 0xffffffffUL, &t))
return -EINVAL;
res = hotkey_get(&status, &mask);
@@ -794,26 +860,140 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
}
static struct device_attribute dev_attr_hotkey_bios_mask =
__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
+/* sysfs hotkey all_mask ----------------------------------------------- */
+static ssize_t hotkey_all_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_all_mask =
+ __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
+
+/* sysfs hotkey recommended_mask --------------------------------------- */
+static ssize_t hotkey_recommended_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+ hotkey_all_mask & ~hotkey_reserved_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_recommended_mask =
+ __ATTR(hotkey_recommended_mask, S_IRUGO,
+ hotkey_recommended_mask_show, NULL);
+
+/* sysfs hotkey radio_sw ----------------------------------------------- */
+static ssize_t hotkey_radio_sw_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, s;
+ res = hotkey_get_wlsw(&s);
+ if (res < 0)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_radio_sw =
+ __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+
+/* sysfs hotkey report_mode -------------------------------------------- */
+static ssize_t hotkey_report_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (hotkey_report_mode != 0) ? hotkey_report_mode : 1);
+}
+
+static struct device_attribute dev_attr_hotkey_report_mode =
+ __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
+
/* --------------------------------------------------------------------- */
-static struct attribute *hotkey_mask_attributes[] = {
+static struct attribute *hotkey_attributes[] __initdata = {
+ &dev_attr_hotkey_enable.attr,
+ &dev_attr_hotkey_report_mode.attr,
+};
+
+static struct attribute *hotkey_mask_attributes[] __initdata = {
&dev_attr_hotkey_mask.attr,
&dev_attr_hotkey_bios_enabled.attr,
&dev_attr_hotkey_bios_mask.attr,
+ &dev_attr_hotkey_all_mask.attr,
+ &dev_attr_hotkey_recommended_mask.attr,
};
static int __init hotkey_init(struct ibm_init_struct *iibm)
{
- int res;
+
+ static u16 ibm_keycode_map[] __initdata = {
+ /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+ KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
+ KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+ KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
+ /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
+ KEY_UNKNOWN, /* 0x0D: FN+INSERT */
+ KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
+ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+ KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
+ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
+ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
+ KEY_RESERVED, /* 0x14: VOLUME UP */
+ KEY_RESERVED, /* 0x15: VOLUME DOWN */
+ KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
+ /* (assignments unknown, please report if found) */
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ };
+ static u16 lenovo_keycode_map[] __initdata = {
+ /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
+ KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+ KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
+ /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
+ KEY_UNKNOWN, /* 0x0D: FN+INSERT */
+ KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
+ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+ KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
+ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
+ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
+ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
+ KEY_RESERVED, /* 0x14: VOLUME UP */
+ KEY_RESERVED, /* 0x15: VOLUME DOWN */
+ KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
+ /* (assignments unknown, please report if found) */
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ };
+
+#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0])
+
+ int res, i;
+ int status;
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
+ BUG_ON(!tpacpi_inputdev);
+
IBM_ACPIHANDLE_INIT(hkey);
mutex_init(&hotkey_mutex);
@@ -824,11 +1004,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
str_supported(tp_features.hotkey));
if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(4, NULL);
+ hotkey_dev_attributes = create_attr_set(8, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
- res = add_to_attr_set(hotkey_dev_attributes,
- &dev_attr_hotkey_enable.attr);
+ res = add_many_to_attr_set(hotkey_dev_attributes,
+ hotkey_attributes,
+ ARRAY_SIZE(hotkey_attributes));
if (res)
return res;
@@ -840,19 +1021,90 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
str_supported(tp_features.hotkey_mask));
+ if (tp_features.hotkey_mask) {
+ /* MHKA available in A31, R40, R40e, T4x, X31, and later */
+ if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+ "MHKA", "qd"))
+ hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+ }
+
res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
if (!res && tp_features.hotkey_mask) {
res = add_many_to_attr_set(hotkey_dev_attributes,
hotkey_mask_attributes,
ARRAY_SIZE(hotkey_mask_attributes));
}
+
+ /* Not all thinkpads have a hardware radio switch */
+ if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+ tp_features.hotkey_wlsw = 1;
+ printk(IBM_INFO
+ "radio switch found; radios are %s\n",
+ enabled(status, 0));
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_radio_sw.attr);
+ }
+
if (!res)
res = register_attr_set_with_sysfs(
hotkey_dev_attributes,
&tpacpi_pdev->dev.kobj);
+ if (res)
+ return res;
+
+ /* Set up key map */
+
+ hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+ GFP_KERNEL);
+ if (!hotkey_keycode_map) {
+ printk(IBM_ERR "failed to allocate memory for key map\n");
+ return -ENOMEM;
+ }
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "using Lenovo default hot key map\n");
+ memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+ TPACPI_HOTKEY_MAP_SIZE);
+ } else {
+ dbg_printk(TPACPI_DBG_INIT,
+ "using IBM default hot key map\n");
+ memcpy(hotkey_keycode_map, &ibm_keycode_map,
+ TPACPI_HOTKEY_MAP_SIZE);
+ }
+
+ set_bit(EV_KEY, tpacpi_inputdev->evbit);
+ set_bit(EV_MSC, tpacpi_inputdev->evbit);
+ set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+ tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+ tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+ tpacpi_inputdev->keycode = hotkey_keycode_map;
+ for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+ if (hotkey_keycode_map[i] != KEY_RESERVED) {
+ set_bit(hotkey_keycode_map[i],
+ tpacpi_inputdev->keybit);
+ } else {
+ if (i < sizeof(hotkey_reserved_mask)*8)
+ hotkey_reserved_mask |= 1 << i;
+ }
+ }
+
+ if (tp_features.hotkey_wlsw) {
+ set_bit(EV_SW, tpacpi_inputdev->evbit);
+ set_bit(SW_RADIO, tpacpi_inputdev->swbit);
+ }
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "enabling hot key handling\n");
+ res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
+ | hotkey_orig_mask);
if (res)
return res;
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "legacy hot key reporting over procfs %s\n",
+ (hotkey_report_mode < 2) ?
+ "enabled" : "disabled");
}
return (tp_features.hotkey)? 0 : 1;
@@ -875,22 +1127,108 @@ static void hotkey_exit(void)
}
}
+static void tpacpi_input_send_key(unsigned int scancode,
+ unsigned int keycode)
+{
+ if (keycode != KEY_RESERVED) {
+ input_report_key(tpacpi_inputdev, keycode, 1);
+ if (keycode == KEY_UNKNOWN)
+ input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+ scancode);
+ input_sync(tpacpi_inputdev);
+
+ input_report_key(tpacpi_inputdev, keycode, 0);
+ if (keycode == KEY_UNKNOWN)
+ input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+ scancode);
+ input_sync(tpacpi_inputdev);
+ }
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+ int wlsw;
+
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+ input_report_switch(tpacpi_inputdev,
+ SW_RADIO, !!wlsw);
+}
+
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
- int hkey;
+ u32 hkey;
+ unsigned int keycode, scancode;
+ int send_acpi_ev = 0;
+
+ if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+ switch (hkey >> 12) {
+ case 1:
+ /* 0x1000-0x1FFF: key presses */
+ scancode = hkey & 0xfff;
+ if (scancode > 0 && scancode < 0x21) {
+ scancode--;
+ keycode = hotkey_keycode_map[scancode];
+ tpacpi_input_send_key(scancode, keycode);
+ } else {
+ printk(IBM_ERR
+ "hotkey 0x%04x out of range for keyboard map\n",
+ hkey);
+ send_acpi_ev = 1;
+ }
+ break;
+ case 5:
+ /* 0x5000-0x5FFF: LID */
+ /* we don't handle it through this path, just
+ * eat up known LID events */
+ if (hkey != 0x5001 && hkey != 0x5002) {
+ printk(IBM_ERR
+ "unknown LID-related hotkey event: 0x%04x\n",
+ hkey);
+ send_acpi_ev = 1;
+ }
+ break;
+ case 7:
+ /* 0x7000-0x7FFF: misc */
+ if (tp_features.hotkey_wlsw && hkey == 0x7000) {
+ tpacpi_input_send_radiosw();
+ break;
+ }
+ /* fallthrough to default */
+ default:
+ /* case 2: dock-related */
+ /* 0x2305 - T43 waking up due to bay lever eject while aslept */
+ /* case 3: ultra-bay related. maybe bay in dock? */
+ /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
+ printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
+ send_acpi_ev = 1;
+ }
+ } else {
+ printk(IBM_ERR "unknown hotkey notification event %d\n", event);
+ hkey = 0;
+ send_acpi_ev = 1;
+ }
- if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
- acpi_bus_generate_event(ibm->acpi->device, event, hkey);
- else {
- printk(IBM_ERR "unknown hotkey event %d\n", event);
- acpi_bus_generate_event(ibm->acpi->device, event, 0);
+ /* Legacy events */
+ if (send_acpi_ev || hotkey_report_mode < 2)
+ acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+
+ /* netlink events */
+ if (send_acpi_ev) {
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, hkey);
}
}
+static void hotkey_resume(void)
+{
+ tpacpi_input_send_radiosw();
+}
+
/*
* Call with hotkey_mutex held
*/
-static int hotkey_get(int *status, int *mask)
+static int hotkey_get(int *status, u32 *mask)
{
if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
return -EIO;
@@ -905,7 +1243,7 @@ static int hotkey_get(int *status, int *mask)
/*
* Call with hotkey_mutex held
*/
-static int hotkey_set(int status, int mask)
+static int hotkey_set(int status, u32 mask)
{
int i;
@@ -926,7 +1264,8 @@ static int hotkey_set(int status, int mask)
/* procfs -------------------------------------------------------------- */
static int hotkey_read(char *p)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
int len = 0;
if (!tp_features.hotkey) {
@@ -944,7 +1283,7 @@ static int hotkey_read(char *p)
len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
if (tp_features.hotkey_mask) {
- len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+ len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
len += sprintf(p + len,
"commands:\tenable, disable, reset, <mask>\n");
} else {
@@ -957,7 +1296,8 @@ static int hotkey_read(char *p)
static int hotkey_write(char *buf)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
char *cmd;
int do_cmd = 0;
@@ -1000,8 +1340,13 @@ errexit:
return res;
}
+static const struct acpi_device_id ibm_htk_device_ids[] = {
+ {IBM_HKEY_HID, 0},
+ {"", 0},
+};
+
static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
- .hid = IBM_HKEY_HID,
+ .hid = ibm_htk_device_ids,
.notify = hotkey_notify,
.handle = &hkey_handle,
.type = ACPI_DEVICE_NOTIFY,
@@ -1012,6 +1357,7 @@ static struct ibm_struct hotkey_driver_data = {
.read = hotkey_read,
.write = hotkey_write,
.exit = hotkey_exit,
+ .resume = hotkey_resume,
.acpi = &ibm_hotkey_acpidriver,
};
@@ -1763,6 +2109,11 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
/* don't list other alternatives as we install a notify handler on the 570 */
IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
+static const struct acpi_device_id ibm_pci_device_ids[] = {
+ {PCI_ROOT_HID_STRING, 0},
+ {"", 0},
+};
+
static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
{
.notify = dock_notify,
@@ -1770,7 +2121,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
.type = ACPI_SYSTEM_NOTIFY,
},
{
- .hid = IBM_PCI_HID,
+ /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
+ * We just use it to get notifications of dock hotplug
+ * in very old thinkpads */
+ .hid = ibm_pci_device_ids,
.notify = dock_notify,
.handle = &pci_handle,
.type = ACPI_SYSTEM_NOTIFY,
@@ -1829,23 +2183,29 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
static void dock_notify(struct ibm_struct *ibm, u32 event)
{
int docked = dock_docked();
- int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+ int pci = ibm->acpi->hid && ibm->acpi->device &&
+ acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids);
+ int data;
if (event == 1 && !pci) /* 570 */
- acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
+ data = 1; /* button */
else if (event == 1 && pci) /* 570 */
- acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
+ data = 3; /* dock */
else if (event == 3 && docked)
- acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
+ data = 1; /* button */
else if (event == 3 && !docked)
- acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */
+ data = 2; /* undock */
else if (event == 0 && docked)
- acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
+ data = 3; /* dock */
else {
printk(IBM_ERR "unknown dock event %d, status %d\n",
event, _sta(dock_handle));
- acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */
+ data = 0; /* unknown */
}
+ acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, data);
}
static int dock_read(char *p)
@@ -1943,7 +2303,10 @@ static int __init bay_init(struct ibm_init_struct *iibm)
static void bay_notify(struct ibm_struct *ibm, u32 event)
{
- acpi_bus_generate_event(ibm->acpi->device, event, 0);
+ acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, 0);
}
#define bay_occupied(b) (_sta(b##_handle) & 1)
@@ -2389,7 +2752,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
- if (ibm_thinkpad_ec_found && experimental) {
+ if (thinkpad_id.ec_model) {
/*
* Direct EC access mode: sensors at registers
* 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
@@ -2533,6 +2896,8 @@ static int thermal_get_sensor(int idx, s32 *value)
snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
return -EIO;
+ if (t > 127 || t < -127)
+ t = TP_EC_THERMAL_TMP_NA;
*value = t * 1000;
return 0;
}
@@ -2671,22 +3036,39 @@ static struct ibm_struct ecdump_driver_data = {
* Backlight/brightness subdriver
*/
-static struct backlight_device *ibm_backlight_device = NULL;
+static struct backlight_device *ibm_backlight_device;
static struct backlight_ops ibm_backlight_data = {
.get_brightness = brightness_get,
.update_status = brightness_update_status,
};
+static struct mutex brightness_mutex;
+
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+ mutex_init(&brightness_mutex);
+
+ if (!brightness_mode) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+ brightness_mode = 2;
+ else
+ brightness_mode = 3;
+
+ dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+ brightness_mode);
+ }
+
+ if (brightness_mode > 3)
+ return -EINVAL;
+
b = brightness_get(NULL);
if (b < 0)
- return b;
+ return 1;
ibm_backlight_device = backlight_device_register(
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2722,34 +3104,79 @@ static int brightness_update_status(struct backlight_device *bd)
bd->props.brightness : 0);
}
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
static int brightness_get(struct backlight_device *bd)
{
- u8 level;
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
+ u8 lec = 0, lcmos = 0, level = 0;
+
+ if (brightness_mode & 1) {
+ if (!acpi_ec_read(brightness_offset, &lec))
+ return -EIO;
+ lec &= 7;
+ level = lec;
+ };
+ if (brightness_mode & 2) {
+ lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+ & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+ >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+ level = lcmos;
+ }
- level &= 0x7;
+ if (brightness_mode == 3 && lec != lcmos) {
+ printk(IBM_ERR
+ "CMOS NVRAM (%u) and EC (%u) do not agree "
+ "on display brightness level\n",
+ (unsigned int) lcmos,
+ (unsigned int) lec);
+ return -EIO;
+ }
return level;
}
static int brightness_set(int value)
{
- int cmos_cmd, inc, i;
- int current_value = brightness_get(NULL);
+ int cmos_cmd, inc, i, res;
+ int current_value;
+
+ if (value > 7)
+ return -EINVAL;
- value &= 7;
+ res = mutex_lock_interruptible(&brightness_mutex);
+ if (res < 0)
+ return res;
- cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+ current_value = brightness_get(NULL);
+ if (current_value < 0) {
+ res = current_value;
+ goto errout;
+ }
+
+ cmos_cmd = value > current_value ?
+ TP_CMOS_BRIGHTNESS_UP :
+ TP_CMOS_BRIGHTNESS_DOWN;
inc = value > current_value ? 1 : -1;
+
+ res = 0;
for (i = current_value; i != value; i += inc) {
- if (issue_thinkpad_cmos_command(cmos_cmd))
- return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
+ if ((brightness_mode & 2) &&
+ issue_thinkpad_cmos_command(cmos_cmd)) {
+ res = -EIO;
+ goto errout;
+ }
+ if ((brightness_mode & 1) &&
+ !acpi_ec_write(brightness_offset, i + inc)) {
+ res = -EIO;
+ goto errout;;
+ }
}
- return 0;
+errout:
+ mutex_unlock(&brightness_mutex);
+ return res;
}
static int brightness_read(char *p)
@@ -3273,20 +3700,19 @@ static int __init fan_init(struct ibm_init_struct *iibm)
* Enable for TP-1Y (T43), TP-78 (R51e),
* TP-76 (R52), TP-70 (T43, R52), which are known
* to be buggy. */
- if (fan_control_initial_status == 0x07 &&
- ibm_thinkpad_ec_found &&
- ((ibm_thinkpad_ec_found[0] == '1' &&
- ibm_thinkpad_ec_found[1] == 'Y') ||
- (ibm_thinkpad_ec_found[0] == '7' &&
- (ibm_thinkpad_ec_found[1] == '6' ||
- ibm_thinkpad_ec_found[1] == '8' ||
- ibm_thinkpad_ec_found[1] == '0'))
- )) {
- printk(IBM_NOTICE
- "fan_init: initial fan status is "
- "unknown, assuming it is in auto "
- "mode\n");
- tp_features.fan_ctrl_status_undef = 1;
+ if (fan_control_initial_status == 0x07) {
+ switch (thinkpad_id.ec_model) {
+ case 0x5931: /* TP-1Y */
+ case 0x3837: /* TP-78 */
+ case 0x3637: /* TP-76 */
+ case 0x3037: /* TP-70 */
+ printk(IBM_NOTICE
+ "fan_init: initial fan status is "
+ "unknown, assuming it is in auto "
+ "mode\n");
+ tp_features.fan_ctrl_status_undef = 1;
+ ;;
+ }
}
} else {
printk(IBM_ERR
@@ -3474,7 +3900,7 @@ static void fan_watchdog_fire(struct work_struct *ignored)
static void fan_watchdog_reset(void)
{
- static int fan_watchdog_active = 0;
+ static int fan_watchdog_active;
if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
return;
@@ -3877,7 +4303,7 @@ static struct ibm_struct fan_driver_data = {
****************************************************************************/
/* /proc support */
-static struct proc_dir_entry *proc_dir = NULL;
+static struct proc_dir_entry *proc_dir;
/* Subdriver registry */
static LIST_HEAD(tpacpi_all_drivers);
@@ -4020,13 +4446,30 @@ static void ibm_exit(struct ibm_struct *ibm)
/* Probing */
-static char *ibm_thinkpad_ec_found = NULL;
-
-static char* __init check_dmi_for_ec(void)
+static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
{
- struct dmi_device *dev = NULL;
+ const struct dmi_device *dev = NULL;
char ec_fw_string[18];
+ if (!tp)
+ return;
+
+ memset(tp, 0, sizeof(*tp));
+
+ if (dmi_name_in_vendors("IBM"))
+ tp->vendor = PCI_VENDOR_ID_IBM;
+ else if (dmi_name_in_vendors("LENOVO"))
+ tp->vendor = PCI_VENDOR_ID_LENOVO;
+ else
+ return;
+
+ tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
+ GFP_KERNEL);
+ if (!tp->bios_version_str)
+ return;
+ tp->bios_model = tp->bios_version_str[0]
+ | (tp->bios_version_str[1] << 8);
+
/*
* ThinkPad T23 or newer, A31 or newer, R50e or newer,
* X32 or newer, all Z series; Some models must have an
@@ -4040,10 +4483,20 @@ static char* __init check_dmi_for_ec(void)
ec_fw_string) == 1) {
ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
- return kstrdup(ec_fw_string, GFP_KERNEL);
+
+ tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+ tp->ec_model = ec_fw_string[0]
+ | (ec_fw_string[1] << 8);
+ break;
}
}
- return NULL;
+
+ tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
+ GFP_KERNEL);
+ if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+ kfree(tp->model_str);
+ tp->model_str = NULL;
+ }
}
static int __init probe_for_thinkpad(void)
@@ -4057,7 +4510,7 @@ static int __init probe_for_thinkpad(void)
* Non-ancient models have better DMI tagging, but very old models
* don't.
*/
- is_thinkpad = dmi_name_in_vendors("ThinkPad");
+ is_thinkpad = (thinkpad_id.model_str != NULL);
/* ec is required because many other handles are relative to it */
IBM_ACPIHANDLE_INIT(ec);
@@ -4073,7 +4526,7 @@ static int __init probe_for_thinkpad(void)
* false positives a damn great deal
*/
if (!is_thinkpad)
- is_thinkpad = dmi_name_in_vendors("IBM");
+ is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
if (!is_thinkpad && !force_load)
return -ENODEV;
@@ -4185,10 +4638,16 @@ static u32 dbg_level;
module_param_named(debug, dbg_level, uint, 0);
static int force_load;
-module_param(force_load, int, 0);
+module_param(force_load, bool, 0);
static int fan_control_allowed;
-module_param_named(fan_control, fan_control_allowed, int, 0);
+module_param_named(fan_control, fan_control_allowed, bool, 0);
+
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
+
+static unsigned int hotkey_report_mode;
+module_param(hotkey_report_mode, uint, 0);
#define IBM_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4215,13 +4674,21 @@ static int __init thinkpad_acpi_module_init(void)
{
int ret, i;
+ /* Parameter checking */
+ if (hotkey_report_mode > 2)
+ return -EINVAL;
+
/* Driver-level probe */
+
+ get_thinkpad_model_data(&thinkpad_id);
ret = probe_for_thinkpad();
- if (ret)
+ if (ret) {
+ thinkpad_acpi_module_exit();
return ret;
+ }
/* Driver initialization */
- ibm_thinkpad_ec_found = check_dmi_for_ec();
+
IBM_ACPIHANDLE_INIT(ecrd);
IBM_ACPIHANDLE_INIT(ecwr);
@@ -4239,12 +4706,15 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit();
return ret;
}
+ tp_features.platform_drv_registered = 1;
+
ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
if (ret) {
printk(IBM_ERR "unable to create sysfs driver attributes\n");
thinkpad_acpi_module_exit();
return ret;
}
+ tp_features.platform_drv_attrs_registered = 1;
/* Device initialization */
@@ -4265,6 +4735,22 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit();
return ret;
}
+ tpacpi_inputdev = input_allocate_device();
+ if (!tpacpi_inputdev) {
+ printk(IBM_ERR "unable to allocate input device\n");
+ thinkpad_acpi_module_exit();
+ return -ENOMEM;
+ } else {
+ /* Prepare input device, but don't register */
+ tpacpi_inputdev->name = "ThinkPad Extra Buttons";
+ tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
+ tpacpi_inputdev->id.bustype = BUS_HOST;
+ tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+ thinkpad_id.vendor :
+ PCI_VENDOR_ID_IBM;
+ tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+ tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
+ }
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
ret = ibm_init(&ibms_init[i]);
if (ret >= 0 && *ibms_init[i].param)
@@ -4274,6 +4760,14 @@ static int __init thinkpad_acpi_module_init(void)
return ret;
}
}
+ ret = input_register_device(tpacpi_inputdev);
+ if (ret < 0) {
+ printk(IBM_ERR "unable to register input device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ } else {
+ tp_features.input_device_registered = 1;
+ }
return 0;
}
@@ -4290,19 +4784,31 @@ static void thinkpad_acpi_module_exit(void)
dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+ if (tpacpi_inputdev) {
+ if (tp_features.input_device_registered)
+ input_unregister_device(tpacpi_inputdev);
+ else
+ input_free_device(tpacpi_inputdev);
+ }
+
if (tpacpi_hwmon)
hwmon_device_unregister(tpacpi_hwmon);
if (tpacpi_pdev)
platform_device_unregister(tpacpi_pdev);
- tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
- platform_driver_unregister(&tpacpi_pdriver);
+ if (tp_features.platform_drv_attrs_registered)
+ tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+
+ if (tp_features.platform_drv_registered)
+ platform_driver_unregister(&tpacpi_pdriver);
if (proc_dir)
remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
- kfree(ibm_thinkpad_ec_found);
+ kfree(thinkpad_id.bios_version_str);
+ kfree(thinkpad_id.ec_version_str);
+ kfree(thinkpad_id.model_str);
}
module_init(thinkpad_acpi_module_init);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 72d62f2dabb9..082a1cbc16c0 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -32,6 +32,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/nvram.h>
#include <linux/proc_fs.h>
#include <linux/sysfs.h>
#include <linux/backlight.h>
@@ -39,6 +40,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
@@ -48,6 +50,7 @@
#include <acpi/acpi_drivers.h>
#include <acpi/acnamesp.h>
+#include <linux/pci_ids.h>
/****************************************************************************
* Main driver
@@ -78,6 +81,11 @@
#define TP_CMOS_BRIGHTNESS_UP 4
#define TP_CMOS_BRIGHTNESS_DOWN 5
+/* ThinkPad CMOS NVRAM constants */
+#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
+#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
+#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
+
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -98,9 +106,13 @@ static const char *str_supported(int is_supported);
#define vdbg_printk(a_dbg_level, format, arg...)
#endif
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
+#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION 0x4101
+
/* ACPI HIDs */
#define IBM_HKEY_HID "IBM0068"
-#define IBM_PCI_HID "PNP0A03"
/* ACPI helpers */
static int __must_check acpi_evalf(acpi_handle handle,
@@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
static struct platform_device *tpacpi_pdev;
static struct class_device *tpacpi_hwmon;
static struct platform_driver tpacpi_pdriver;
+static struct input_dev *tpacpi_inputdev;
static int tpacpi_create_driver_attributes(struct device_driver *drv);
static void tpacpi_remove_driver_attributes(struct device_driver *drv);
@@ -168,9 +181,8 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv);
static int experimental;
static u32 dbg_level;
static int force_load;
-static char *ibm_thinkpad_ec_found;
+static unsigned int hotkey_report_mode;
-static char* check_dmi_for_ec(void);
static int thinkpad_acpi_module_init(void);
static void thinkpad_acpi_module_exit(void);
@@ -182,7 +194,7 @@ static void thinkpad_acpi_module_exit(void);
struct ibm_struct;
struct tp_acpi_drv_struct {
- char *hid;
+ const struct acpi_device_id *hid;
struct acpi_driver *driver;
void (*notify) (struct ibm_struct *, u32);
@@ -197,6 +209,7 @@ struct ibm_struct {
int (*read) (char *);
int (*write) (char *);
void (*exit) (void);
+ void (*resume) (void);
struct list_head all_drivers;
@@ -228,12 +241,31 @@ static struct {
u16 bluetooth:1;
u16 hotkey:1;
u16 hotkey_mask:1;
+ u16 hotkey_wlsw:1;
u16 light:1;
u16 light_status:1;
u16 wan:1;
u16 fan_ctrl_status_undef:1;
+ u16 input_device_registered:1;
+ u16 platform_drv_registered:1;
+ u16 platform_drv_attrs_registered:1;
} tp_features;
+struct thinkpad_id_data {
+ unsigned int vendor; /* ThinkPad vendor:
+ * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+ char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
+ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
+
+ u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+ u16 ec_model;
+
+ char *model_str;
+};
+
+static struct thinkpad_id_data thinkpad_id;
+
static struct list_head tpacpi_all_drivers;
static struct ibm_init_struct ibms_init[];
@@ -300,6 +332,7 @@ static int bluetooth_write(char *buf);
static struct backlight_device *ibm_backlight_device;
static int brightness_offset = 0x31;
+static int brightness_mode;
static int brightness_init(struct ibm_init_struct *iibm);
static void brightness_exit(void);
@@ -415,14 +448,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc);
*/
static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
static struct mutex hotkey_mutex;
static int hotkey_init(struct ibm_init_struct *iibm);
static void hotkey_exit(void);
-static int hotkey_get(int *status, int *mask);
-static int hotkey_set(int status, int mask);
+static int hotkey_get(int *status, u32 *mask);
+static int hotkey_set(int status, u32 mask);
static void hotkey_notify(struct ibm_struct *ibm, u32 event);
static int hotkey_read(char *p);
static int hotkey_write(char *buf);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d195fb088f4a..8f77949f93dd 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int tifm_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
- int i = 0;
- int length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "TIFM_CARD_TYPE=%s",
- tifm_media_type_name(sock->type, 1)))
+ if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
return -ENOMEM;
return 0;
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index a49cb9737cd8..aa8a4e461942 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,3 +32,10 @@ config MMC_BLOCK_BOUNCE
If unsure, say Y here.
+config SDIO_UART
+ tristate "SDIO UART/GPS class support"
+ depends on MMC
+ help
+ SDIO function driver for SDIO cards that implements the UART
+ class, as well as the GPS class which appears like a UART.
+
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index cf8c939867f5..fc5a784cfa1a 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -9,3 +9,5 @@ endif
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
+obj-$(CONFIG_SDIO_UART) += sdio_uart.o
+
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index cbd4b6e3e17c..e38d5a3b2a89 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
+ if (err)
+ return (u32)-1;
+ if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
return (u32)-1;
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
memset(&data, 0, sizeof(struct mmc_data));
@@ -192,7 +194,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
mmc_wait_for_req(card->host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
+ if (cmd.error || data.error)
return (u32)-1;
blocks = ntohl(blocks);
@@ -220,17 +222,15 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.cmd.arg = req->sector;
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
- brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
- brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
if (brq.data.blocks > card->host->max_blk_count)
brq.data.blocks = card->host->max_blk_count;
- mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
-
/*
* If the host doesn't support multiple block writes, force
* block writes to single block. SD cards are excepted from
@@ -243,8 +243,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.blocks = 1;
if (brq.data.blocks > 1) {
- brq.data.flags |= MMC_DATA_MULTI;
- brq.mrq.stop = &brq.stop;
+ /* SPI multiblock writes terminate using a special
+ * token, not a STOP_TRANSMISSION request.
+ */
+ if (!mmc_host_is_spi(card->host)
+ || rq_data_dir(req) == READ)
+ brq.mrq.stop = &brq.stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else {
@@ -261,6 +265,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.flags |= MMC_DATA_WRITE;
}
+ mmc_set_data_timeout(&brq.data, card);
+
brq.data.sg = mq->sg;
brq.data.sg_len = mmc_queue_map_sg(mq);
@@ -302,7 +308,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
goto cmd_err;
}
- if (rq_data_dir(req) != READ) {
+ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
do {
int err;
@@ -414,13 +420,12 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
return ERR_PTR(-ENOSPC);
__set_bit(devidx, dev_use);
- md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+ md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
if (!md) {
ret = -ENOMEM;
goto out;
}
- memset(md, 0, sizeof(struct mmc_blk_data));
/*
* Set the read-only status based on the supported commands
@@ -511,7 +516,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_release_host(card->host);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b53dac8d1b69..b0abc7d92805 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/queue.c
+ * linux/drivers/mmc/card/queue.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2006-2007 Pierre Ossman
@@ -83,7 +83,7 @@ static int mmc_queue_thread(void *d)
* on any queue on this host, and attempt to issue it. This may
* not be the queue we were asked to process.
*/
-static void mmc_request(request_queue_t *q)
+static void mmc_request(struct request_queue *q)
{
struct mmc_queue *mq = q->queuedata;
struct request *req;
@@ -117,7 +117,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
struct mmc_host *host = card->host;
u64 limit = BLK_BOUNCE_HIGH;
int ret;
- unsigned int bouncesz;
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = *mmc_dev(host)->dma_mask;
@@ -134,6 +133,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
+ unsigned int bouncesz;
+
bouncesz = MMC_QUEUE_BOUNCESZ;
if (bouncesz > host->max_req_size)
@@ -156,14 +157,14 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
- goto free_bounce_buf;
+ goto cleanup_queue;
}
mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
bouncesz / 512, GFP_KERNEL);
if (!mq->bounce_sg) {
ret = -ENOMEM;
- goto free_sg;
+ goto cleanup_queue;
}
}
}
@@ -197,21 +198,20 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
if (mq->bounce_sg)
kfree(mq->bounce_sg);
mq->bounce_sg = NULL;
- free_sg:
- kfree(mq->sg);
+ cleanup_queue:
+ if (mq->sg)
+ kfree(mq->sg);
mq->sg = NULL;
- free_bounce_buf:
if (mq->bounce_buf)
kfree(mq->bounce_buf);
mq->bounce_buf = NULL;
- cleanup_queue:
blk_cleanup_queue(mq->queue);
return ret;
}
void mmc_cleanup_queue(struct mmc_queue *mq)
{
- request_queue_t *q = mq->queue;
+ struct request_queue *q = mq->queue;
unsigned long flags;
/* Mark that we should start throwing out stragglers */
@@ -252,7 +252,7 @@ EXPORT_SYMBOL(mmc_cleanup_queue);
*/
void mmc_queue_suspend(struct mmc_queue *mq)
{
- request_queue_t *q = mq->queue;
+ struct request_queue *q = mq->queue;
unsigned long flags;
if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
@@ -272,7 +272,7 @@ void mmc_queue_suspend(struct mmc_queue *mq)
*/
void mmc_queue_resume(struct mmc_queue *mq)
{
- request_queue_t *q = mq->queue;
+ struct request_queue *q = mq->queue;
unsigned long flags;
if (mq->flags & MMC_QUEUE_SUSPENDED) {
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
new file mode 100644
index 000000000000..d552de683110
--- /dev/null
+++ b/drivers/mmc/card/sdio_uart.c
@@ -0,0 +1,1158 @@
+/*
+ * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver
+ *
+ * Based on drivers/serial/8250.c and drivers/serial/serial_core.c
+ * by Russell King.
+ *
+ * Author: Nicolas Pitre
+ * Created: June 15, 2007
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/*
+ * Note: Although this driver assumes a 16550A-like UART implementation,
+ * it is not possible to leverage the common 8250/16550 driver, nor the
+ * core UART infrastructure, as they assumes direct access to the hardware
+ * registers, often under a spinlock. This is not possible in the SDIO
+ * context as SDIO access functions must be able to sleep.
+ *
+ * Because we need to lock the SDIO host to ensure an exclusive access to
+ * the card, we simply rely on that lock to also prevent and serialize
+ * concurrent access to the same port.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/gfp.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+
+#define UART_NR 8 /* Number of UARTs this driver can handle */
+
+
+#define UART_XMIT_SIZE PAGE_SIZE
+#define WAKEUP_CHARS 256
+
+#define circ_empty(circ) ((circ)->head == (circ)->tail)
+#define circ_clear(circ) ((circ)->head = (circ)->tail = 0)
+
+#define circ_chars_pending(circ) \
+ (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+#define circ_chars_free(circ) \
+ (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+
+struct uart_icount {
+ __u32 cts;
+ __u32 dsr;
+ __u32 rng;
+ __u32 dcd;
+ __u32 rx;
+ __u32 tx;
+ __u32 frame;
+ __u32 overrun;
+ __u32 parity;
+ __u32 brk;
+};
+
+struct sdio_uart_port {
+ struct kref kref;
+ struct tty_struct *tty;
+ unsigned int index;
+ unsigned int opened;
+ struct mutex open_lock;
+ struct sdio_func *func;
+ struct mutex func_lock;
+ struct task_struct *in_sdio_uart_irq;
+ unsigned int regs_offset;
+ struct circ_buf xmit;
+ spinlock_t write_lock;
+ struct uart_icount icount;
+ unsigned int uartclk;
+ unsigned int mctrl;
+ unsigned int read_status_mask;
+ unsigned int ignore_status_mask;
+ unsigned char x_char;
+ unsigned char ier;
+ unsigned char lcr;
+};
+
+static struct sdio_uart_port *sdio_uart_table[UART_NR];
+static DEFINE_SPINLOCK(sdio_uart_table_lock);
+
+static int sdio_uart_add_port(struct sdio_uart_port *port)
+{
+ int index, ret = -EBUSY;
+
+ kref_init(&port->kref);
+ mutex_init(&port->open_lock);
+ mutex_init(&port->func_lock);
+ spin_lock_init(&port->write_lock);
+
+ spin_lock(&sdio_uart_table_lock);
+ for (index = 0; index < UART_NR; index++) {
+ if (!sdio_uart_table[index]) {
+ port->index = index;
+ sdio_uart_table[index] = port;
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock(&sdio_uart_table_lock);
+
+ return ret;
+}
+
+static struct sdio_uart_port *sdio_uart_port_get(unsigned index)
+{
+ struct sdio_uart_port *port;
+
+ if (index >= UART_NR)
+ return NULL;
+
+ spin_lock(&sdio_uart_table_lock);
+ port = sdio_uart_table[index];
+ if (port)
+ kref_get(&port->kref);
+ spin_unlock(&sdio_uart_table_lock);
+
+ return port;
+}
+
+static void sdio_uart_port_destroy(struct kref *kref)
+{
+ struct sdio_uart_port *port =
+ container_of(kref, struct sdio_uart_port, kref);
+ kfree(port);
+}
+
+static void sdio_uart_port_put(struct sdio_uart_port *port)
+{
+ kref_put(&port->kref, sdio_uart_port_destroy);
+}
+
+static void sdio_uart_port_remove(struct sdio_uart_port *port)
+{
+ struct sdio_func *func;
+
+ BUG_ON(sdio_uart_table[port->index] != port);
+
+ spin_lock(&sdio_uart_table_lock);
+ sdio_uart_table[port->index] = NULL;
+ spin_unlock(&sdio_uart_table_lock);
+
+ /*
+ * We're killing a port that potentially still is in use by
+ * the tty layer. Be careful to prevent any further access
+ * to the SDIO function and arrange for the tty layer to
+ * give up on that port ASAP.
+ * Beware: the lock ordering is critical.
+ */
+ mutex_lock(&port->open_lock);
+ mutex_lock(&port->func_lock);
+ func = port->func;
+ sdio_claim_host(func);
+ port->func = NULL;
+ mutex_unlock(&port->func_lock);
+ if (port->opened)
+ tty_hangup(port->tty);
+ mutex_unlock(&port->open_lock);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ sdio_uart_port_put(port);
+}
+
+static int sdio_uart_claim_func(struct sdio_uart_port *port)
+{
+ mutex_lock(&port->func_lock);
+ if (unlikely(!port->func)) {
+ mutex_unlock(&port->func_lock);
+ return -ENODEV;
+ }
+ if (likely(port->in_sdio_uart_irq != current))
+ sdio_claim_host(port->func);
+ mutex_unlock(&port->func_lock);
+ return 0;
+}
+
+static inline void sdio_uart_release_func(struct sdio_uart_port *port)
+{
+ if (likely(port->in_sdio_uart_irq != current))
+ sdio_release_host(port->func);
+}
+
+static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
+{
+ unsigned char c;
+ c = sdio_readb(port->func, port->regs_offset + offset, NULL);
+ return c;
+}
+
+static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
+{
+ sdio_writeb(port->func, value, port->regs_offset + offset, NULL);
+}
+
+static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
+{
+ unsigned char status;
+ unsigned int ret;
+
+ status = sdio_in(port, UART_MSR);
+
+ ret = 0;
+ if (status & UART_MSR_DCD)
+ ret |= TIOCM_CAR;
+ if (status & UART_MSR_RI)
+ ret |= TIOCM_RNG;
+ if (status & UART_MSR_DSR)
+ ret |= TIOCM_DSR;
+ if (status & UART_MSR_CTS)
+ ret |= TIOCM_CTS;
+ return ret;
+}
+
+static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl)
+{
+ unsigned char mcr = 0;
+
+ if (mctrl & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (mctrl & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (mctrl & TIOCM_OUT1)
+ mcr |= UART_MCR_OUT1;
+ if (mctrl & TIOCM_OUT2)
+ mcr |= UART_MCR_OUT2;
+ if (mctrl & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ sdio_out(port, UART_MCR, mcr);
+}
+
+static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
+ unsigned int set, unsigned int clear)
+{
+ unsigned int old;
+
+ old = port->mctrl;
+ port->mctrl = (old & ~clear) | set;
+ if (old != port->mctrl)
+ sdio_uart_write_mctrl(port, port->mctrl);
+}
+
+#define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0)
+#define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x)
+
+static void sdio_uart_change_speed(struct sdio_uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned char cval, fcr = 0;
+ unsigned int baud, quot;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ cval = UART_LCR_WLEN5;
+ break;
+ case CS6:
+ cval = UART_LCR_WLEN6;
+ break;
+ case CS7:
+ cval = UART_LCR_WLEN7;
+ break;
+ default:
+ case CS8:
+ cval = UART_LCR_WLEN8;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ cval |= UART_LCR_STOP;
+ if (termios->c_cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(termios->c_cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+
+ for (;;) {
+ baud = tty_termios_baud_rate(termios);
+ if (baud == 0)
+ baud = 9600; /* Special case: B0 rate. */
+ if (baud <= port->uartclk)
+ break;
+ /*
+ * Oops, the quotient was zero. Try again with the old
+ * baud rate if possible, otherwise default to 9600.
+ */
+ termios->c_cflag &= ~CBAUD;
+ if (old) {
+ termios->c_cflag |= old->c_cflag & CBAUD;
+ old = NULL;
+ } else
+ termios->c_cflag |= B9600;
+ }
+ quot = (2 * port->uartclk + baud) / (2 * baud);
+
+ if (baud < 2400)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+ else
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+
+ port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= UART_LSR_BI;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART_LSR_OE;
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_LSR_DR;
+
+ /*
+ * CTS flow control flag and modem status interrupts
+ */
+ port->ier &= ~UART_IER_MSI;
+ if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
+ port->ier |= UART_IER_MSI;
+
+ port->lcr = cval;
+
+ sdio_out(port, UART_IER, port->ier);
+ sdio_out(port, UART_LCR, cval | UART_LCR_DLAB);
+ sdio_out(port, UART_DLL, quot & 0xff);
+ sdio_out(port, UART_DLM, quot >> 8);
+ sdio_out(port, UART_LCR, cval);
+ sdio_out(port, UART_FCR, fcr);
+
+ sdio_uart_write_mctrl(port, port->mctrl);
+}
+
+static void sdio_uart_start_tx(struct sdio_uart_port *port)
+{
+ if (!(port->ier & UART_IER_THRI)) {
+ port->ier |= UART_IER_THRI;
+ sdio_out(port, UART_IER, port->ier);
+ }
+}
+
+static void sdio_uart_stop_tx(struct sdio_uart_port *port)
+{
+ if (port->ier & UART_IER_THRI) {
+ port->ier &= ~UART_IER_THRI;
+ sdio_out(port, UART_IER, port->ier);
+ }
+}
+
+static void sdio_uart_stop_rx(struct sdio_uart_port *port)
+{
+ port->ier &= ~UART_IER_RLSI;
+ port->read_status_mask &= ~UART_LSR_DR;
+ sdio_out(port, UART_IER, port->ier);
+}
+
+static void sdio_uart_receive_chars(struct sdio_uart_port *port, int *status)
+{
+ struct tty_struct *tty = port->tty;
+ unsigned int ch, flag;
+ int max_count = 256;
+
+ do {
+ ch = sdio_in(port, UART_RX);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+ UART_LSR_FE | UART_LSR_OE))) {
+ /*
+ * For statistics only
+ */
+ if (*status & UART_LSR_BI) {
+ *status &= ~(UART_LSR_FE | UART_LSR_PE);
+ port->icount.brk++;
+ } else if (*status & UART_LSR_PE)
+ port->icount.parity++;
+ else if (*status & UART_LSR_FE)
+ port->icount.frame++;
+ if (*status & UART_LSR_OE)
+ port->icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ *status &= port->read_status_mask;
+ if (*status & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ } else if (*status & UART_LSR_PE)
+ flag = TTY_PARITY;
+ else if (*status & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+
+ /*
+ * Overrun is special. Since it's reported immediately,
+ * it doesn't affect the current character.
+ */
+ if (*status & ~port->ignore_status_mask & UART_LSR_OE)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+ *status = sdio_in(port, UART_LSR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+ tty_flip_buffer_push(tty);
+}
+
+static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
+{
+ struct circ_buf *xmit = &port->xmit;
+ int count;
+
+ if (port->x_char) {
+ sdio_out(port, UART_TX, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) {
+ sdio_uart_stop_tx(port);
+ return;
+ }
+
+ count = 16;
+ do {
+ sdio_out(port, UART_TX, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (circ_chars_pending(xmit) < WAKEUP_CHARS)
+ tty_wakeup(port->tty);
+
+ if (circ_empty(xmit))
+ sdio_uart_stop_tx(port);
+}
+
+static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
+{
+ int status;
+
+ status = sdio_in(port, UART_MSR);
+
+ if ((status & UART_MSR_ANY_DELTA) == 0)
+ return;
+
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS) {
+ port->icount.cts++;
+ if (port->tty->termios->c_cflag & CRTSCTS) {
+ int cts = (status & UART_MSR_CTS);
+ if (port->tty->hw_stopped) {
+ if (cts) {
+ port->tty->hw_stopped = 0;
+ sdio_uart_start_tx(port);
+ tty_wakeup(port->tty);
+ }
+ } else {
+ if (!cts) {
+ port->tty->hw_stopped = 1;
+ sdio_uart_stop_tx(port);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static void sdio_uart_irq(struct sdio_func *func)
+{
+ struct sdio_uart_port *port = sdio_get_drvdata(func);
+ unsigned int iir, lsr;
+
+ /*
+ * In a few places sdio_uart_irq() is called directly instead of
+ * waiting for the actual interrupt to be raised and the SDIO IRQ
+ * thread scheduled in order to reduce latency. However, some
+ * interaction with the tty core may end up calling us back
+ * (serial echo, flow control, etc.) through those same places
+ * causing undesirable effects. Let's stop the recursion here.
+ */
+ if (unlikely(port->in_sdio_uart_irq == current))
+ return;
+
+ iir = sdio_in(port, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return;
+
+ port->in_sdio_uart_irq = current;
+ lsr = sdio_in(port, UART_LSR);
+ if (lsr & UART_LSR_DR)
+ sdio_uart_receive_chars(port, &lsr);
+ sdio_uart_check_modem_status(port);
+ if (lsr & UART_LSR_THRE)
+ sdio_uart_transmit_chars(port);
+ port->in_sdio_uart_irq = NULL;
+}
+
+static int sdio_uart_startup(struct sdio_uart_port *port)
+{
+ unsigned long page;
+ int ret;
+
+ /*
+ * Set the TTY IO error marker - we will only clear this
+ * once we have successfully opened the port.
+ */
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ /* Initialise and allocate the transmit buffer. */
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ port->xmit.buf = (unsigned char *)page;
+ circ_clear(&port->xmit);
+
+ ret = sdio_uart_claim_func(port);
+ if (ret)
+ goto err1;
+ ret = sdio_enable_func(port->func);
+ if (ret)
+ goto err2;
+ ret = sdio_claim_irq(port->func, sdio_uart_irq);
+ if (ret)
+ goto err3;
+
+ /*
+ * Clear the FIFO buffers and disable them.
+ * (they will be reenabled in sdio_change_speed())
+ */
+ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ sdio_out(port, UART_FCR, 0);
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) sdio_in(port, UART_LSR);
+ (void) sdio_in(port, UART_RX);
+ (void) sdio_in(port, UART_IIR);
+ (void) sdio_in(port, UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ sdio_out(port, UART_LCR, UART_LCR_WLEN8);
+
+ port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+ port->mctrl = TIOCM_OUT2;
+
+ sdio_uart_change_speed(port, port->tty->termios, NULL);
+
+ if (port->tty->termios->c_cflag & CBAUD)
+ sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+ if (port->tty->termios->c_cflag & CRTSCTS)
+ if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
+ port->tty->hw_stopped = 1;
+
+ clear_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ /* Kick the IRQ handler once while we're still holding the host lock */
+ sdio_uart_irq(port->func);
+
+ sdio_uart_release_func(port);
+ return 0;
+
+err3:
+ sdio_disable_func(port->func);
+err2:
+ sdio_uart_release_func(port);
+err1:
+ free_page((unsigned long)port->xmit.buf);
+ return ret;
+}
+
+static void sdio_uart_shutdown(struct sdio_uart_port *port)
+{
+ int ret;
+
+ ret = sdio_uart_claim_func(port);
+ if (ret)
+ goto skip;
+
+ sdio_uart_stop_rx(port);
+
+ /* TODO: wait here for TX FIFO to drain */
+
+ /* Turn off DTR and RTS early. */
+ if (port->tty->termios->c_cflag & HUPCL)
+ sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+ /* Disable interrupts from this port */
+ sdio_release_irq(port->func);
+ port->ier = 0;
+ sdio_out(port, UART_IER, 0);
+
+ sdio_uart_clear_mctrl(port, TIOCM_OUT2);
+
+ /* Disable break condition and FIFOs. */
+ port->lcr &= ~UART_LCR_SBC;
+ sdio_out(port, UART_LCR, port->lcr);
+ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT);
+ sdio_out(port, UART_FCR, 0);
+
+ sdio_disable_func(port->func);
+
+ sdio_uart_release_func(port);
+
+skip:
+ /* Free the transmit buffer page. */
+ free_page((unsigned long)port->xmit.buf);
+}
+
+static int sdio_uart_open (struct tty_struct *tty, struct file * filp)
+{
+ struct sdio_uart_port *port;
+ int ret;
+
+ port = sdio_uart_port_get(tty->index);
+ if (!port)
+ return -ENODEV;
+
+ mutex_lock(&port->open_lock);
+
+ /*
+ * Make sure not to mess up with a dead port
+ * which has not been closed yet.
+ */
+ if (tty->driver_data && tty->driver_data != port) {
+ mutex_unlock(&port->open_lock);
+ sdio_uart_port_put(port);
+ return -EBUSY;
+ }
+
+ if (!port->opened) {
+ tty->driver_data = port;
+ port->tty = tty;
+ ret = sdio_uart_startup(port);
+ if (ret) {
+ tty->driver_data = NULL;
+ port->tty = NULL;
+ mutex_unlock(&port->open_lock);
+ sdio_uart_port_put(port);
+ return ret;
+ }
+ }
+ port->opened++;
+ mutex_unlock(&port->open_lock);
+ return 0;
+}
+
+static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (!port)
+ return;
+
+ mutex_lock(&port->open_lock);
+ BUG_ON(!port->opened);
+
+ /*
+ * This is messy. The tty layer calls us even when open()
+ * returned an error. Ignore this close request if tty->count
+ * is larger than port->count.
+ */
+ if (tty->count > port->opened) {
+ mutex_unlock(&port->open_lock);
+ return;
+ }
+
+ if (--port->opened == 0) {
+ tty->closing = 1;
+ sdio_uart_shutdown(port);
+ tty_ldisc_flush(tty);
+ port->tty = NULL;
+ tty->driver_data = NULL;
+ tty->closing = 0;
+ }
+ mutex_unlock(&port->open_lock);
+ sdio_uart_port_put(port);
+}
+
+static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
+ int count)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ struct circ_buf *circ = &port->xmit;
+ int c, ret = 0;
+
+ if (!port->func)
+ return -ENODEV;
+
+ spin_lock(&port->write_lock);
+ while (1) {
+ c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(circ->buf + circ->head, buf, c);
+ circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ spin_unlock(&port->write_lock);
+
+ if ( !(port->ier & UART_IER_THRI)) {
+ int err = sdio_uart_claim_func(port);
+ if (!err) {
+ sdio_uart_start_tx(port);
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+ } else
+ ret = err;
+ }
+
+ return ret;
+}
+
+static int sdio_uart_write_room(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ return port ? circ_chars_free(&port->xmit) : 0;
+}
+
+static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ return port ? circ_chars_pending(&port->xmit) : 0;
+}
+
+static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ port->x_char = ch;
+ if (ch && !(port->ier & UART_IER_THRI)) {
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+ sdio_uart_start_tx(port);
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+ }
+}
+
+static void sdio_uart_throttle(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ return;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ if (I_IXOFF(tty)) {
+ port->x_char = STOP_CHAR(tty);
+ sdio_uart_start_tx(port);
+ }
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ sdio_uart_clear_mctrl(port, TIOCM_RTS);
+
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+}
+
+static void sdio_uart_unthrottle(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ return;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ if (I_IXOFF(tty)) {
+ if (port->x_char) {
+ port->x_char = 0;
+ } else {
+ port->x_char = START_CHAR(tty);
+ sdio_uart_start_tx(port);
+ }
+ }
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ sdio_uart_set_mctrl(port, TIOCM_RTS);
+
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+}
+
+static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ unsigned int cflag = tty->termios->c_cflag;
+
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+ if ((cflag ^ old_termios->c_cflag) == 0 &&
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ return;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ sdio_uart_change_speed(port, tty->termios, old_termios);
+
+ /* Handle transition to B0 status */
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+ sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+ unsigned int mask = TIOCM_DTR;
+ if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+ mask |= TIOCM_RTS;
+ sdio_uart_set_mctrl(port, mask);
+ }
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ sdio_uart_start_tx(port);
+ }
+
+ /* Handle turning on CRTSCTS */
+ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+ if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
+ tty->hw_stopped = 1;
+ sdio_uart_stop_tx(port);
+ }
+ }
+
+ sdio_uart_release_func(port);
+}
+
+static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ if (break_state == -1)
+ port->lcr |= UART_LCR_SBC;
+ else
+ port->lcr &= ~UART_LCR_SBC;
+ sdio_out(port, UART_LCR, port->lcr);
+
+ sdio_uart_release_func(port);
+}
+
+static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ int result;
+
+ result = sdio_uart_claim_func(port);
+ if (!result) {
+ result = port->mctrl | sdio_uart_get_mctrl(port);
+ sdio_uart_release_func(port);
+ }
+
+ return result;
+}
+
+static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ int result;
+
+ result =sdio_uart_claim_func(port);
+ if(!result) {
+ sdio_uart_update_mctrl(port, set, clear);
+ sdio_uart_release_func(port);
+ }
+
+ return result;
+}
+
+static int sdio_uart_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int i, len = 0;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+ "", "", "");
+ for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) {
+ struct sdio_uart_port *port = sdio_uart_port_get(i);
+ if (port) {
+ len += sprintf(page+len, "%d: uart:SDIO", i);
+ if(capable(CAP_SYS_ADMIN)) {
+ len += sprintf(page + len, " tx:%d rx:%d",
+ port->icount.tx, port->icount.rx);
+ if (port->icount.frame)
+ len += sprintf(page + len, " fe:%d",
+ port->icount.frame);
+ if (port->icount.parity)
+ len += sprintf(page + len, " pe:%d",
+ port->icount.parity);
+ if (port->icount.brk)
+ len += sprintf(page + len, " brk:%d",
+ port->icount.brk);
+ if (port->icount.overrun)
+ len += sprintf(page + len, " oe:%d",
+ port->icount.overrun);
+ if (port->icount.cts)
+ len += sprintf(page + len, " cts:%d",
+ port->icount.cts);
+ if (port->icount.dsr)
+ len += sprintf(page + len, " dsr:%d",
+ port->icount.dsr);
+ if (port->icount.rng)
+ len += sprintf(page + len, " rng:%d",
+ port->icount.rng);
+ if (port->icount.dcd)
+ len += sprintf(page + len, " dcd:%d",
+ port->icount.dcd);
+ }
+ strcat(page, "\n");
+ len++;
+ sdio_uart_port_put(port);
+ }
+
+ if (len + begin > off + count)
+ goto done;
+ if (len + begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ *eof = 1;
+
+done:
+ if (off >= len + begin)
+ return 0;
+ *start = page + (off - begin);
+ return (count < begin + len - off) ? count : (begin + len - off);
+}
+
+static const struct tty_operations sdio_uart_ops = {
+ .open = sdio_uart_open,
+ .close = sdio_uart_close,
+ .write = sdio_uart_write,
+ .write_room = sdio_uart_write_room,
+ .chars_in_buffer = sdio_uart_chars_in_buffer,
+ .send_xchar = sdio_uart_send_xchar,
+ .throttle = sdio_uart_throttle,
+ .unthrottle = sdio_uart_unthrottle,
+ .set_termios = sdio_uart_set_termios,
+ .break_ctl = sdio_uart_break_ctl,
+ .tiocmget = sdio_uart_tiocmget,
+ .tiocmset = sdio_uart_tiocmset,
+ .read_proc = sdio_uart_read_proc,
+};
+
+static struct tty_driver *sdio_uart_tty_driver;
+
+static int sdio_uart_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct sdio_uart_port *port;
+ int ret;
+
+ port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ if (func->class == SDIO_CLASS_UART) {
+ printk(KERN_WARNING "%s: need info on UART class basic setup\n",
+ sdio_func_id(func));
+ kfree(port);
+ return -ENOSYS;
+ } else if (func->class == SDIO_CLASS_GPS) {
+ /*
+ * We need tuple 0x91. It contains SUBTPL_SIOREG
+ * and SUBTPL_RCVCAPS.
+ */
+ struct sdio_func_tuple *tpl;
+ for (tpl = func->tuples; tpl; tpl = tpl->next) {
+ if (tpl->code != 0x91)
+ continue;
+ if (tpl->size < 10)
+ continue;
+ if (tpl->data[1] == 0) /* SUBTPL_SIOREG */
+ break;
+ }
+ if (!tpl) {
+ printk(KERN_WARNING
+ "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+ sdio_func_id(func));
+ kfree(port);
+ return -EINVAL;
+ }
+ printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
+ sdio_func_id(func), tpl->data[2], tpl->data[3]);
+ port->regs_offset = (tpl->data[4] << 0) |
+ (tpl->data[5] << 8) |
+ (tpl->data[6] << 16);
+ printk(KERN_DEBUG "%s: regs offset = 0x%x\n",
+ sdio_func_id(func), port->regs_offset);
+ port->uartclk = tpl->data[7] * 115200;
+ if (port->uartclk == 0)
+ port->uartclk = 115200;
+ printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n",
+ sdio_func_id(func), port->uartclk,
+ tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
+ } else {
+ kfree(port);
+ return -EINVAL;
+ }
+
+ port->func = func;
+ sdio_set_drvdata(func, port);
+
+ ret = sdio_uart_add_port(port);
+ if (ret) {
+ kfree(port);
+ } else {
+ struct device *dev;
+ dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev);
+ if (IS_ERR(dev)) {
+ sdio_uart_port_remove(port);
+ ret = PTR_ERR(dev);
+ }
+ }
+
+ return ret;
+}
+
+static void sdio_uart_remove(struct sdio_func *func)
+{
+ struct sdio_uart_port *port = sdio_get_drvdata(func);
+
+ tty_unregister_device(sdio_uart_tty_driver, port->index);
+ sdio_uart_port_remove(port);
+}
+
+static const struct sdio_device_id sdio_uart_ids[] = {
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) },
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, sdio_uart_ids);
+
+static struct sdio_driver sdio_uart_driver = {
+ .probe = sdio_uart_probe,
+ .remove = sdio_uart_remove,
+ .name = "sdio_uart",
+ .id_table = sdio_uart_ids,
+};
+
+static int __init sdio_uart_init(void)
+{
+ int ret;
+ struct tty_driver *tty_drv;
+
+ sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
+ if (!tty_drv)
+ return -ENOMEM;
+
+ tty_drv->owner = THIS_MODULE;
+ tty_drv->driver_name = "sdio_uart";
+ tty_drv->name = "ttySDIO";
+ tty_drv->major = 0; /* dynamically allocated */
+ tty_drv->minor_start = 0;
+ tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+ tty_drv->subtype = SERIAL_TYPE_NORMAL;
+ tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_drv->init_termios = tty_std_termios;
+ tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty_drv->init_termios.c_ispeed = 4800;
+ tty_drv->init_termios.c_ospeed = 4800;
+ tty_set_operations(tty_drv, &sdio_uart_ops);
+
+ ret = tty_register_driver(tty_drv);
+ if (ret)
+ goto err1;
+
+ ret = sdio_register_driver(&sdio_uart_driver);
+ if (ret)
+ goto err2;
+
+ return 0;
+
+err2:
+ tty_unregister_driver(tty_drv);
+err1:
+ put_tty_driver(tty_drv);
+ return ret;
+}
+
+static void __exit sdio_uart_exit(void)
+{
+ sdio_unregister_driver(&sdio_uart_driver);
+ tty_unregister_driver(sdio_uart_tty_driver);
+ put_tty_driver(sdio_uart_tty_driver);
+}
+
+module_init(sdio_uart_init);
+module_exit(sdio_uart_exit);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 3fdd08c7f143..4985807257a8 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -8,5 +8,7 @@ endif
obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o sysfs.o bus.o host.o \
- mmc.o mmc_ops.o sd.o sd_ops.o
+ mmc.o mmc_ops.o sd.o sd_ops.o \
+ sdio.o sdio_ops.o sdio_bus.o \
+ sdio_cis.o sdio_io.o sdio_irq.o
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 348b566bf4fd..b0c22cad9423 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -19,6 +19,7 @@
#include "sysfs.h"
#include "core.h"
+#include "sdio_cis.h"
#include "bus.h"
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
@@ -34,6 +35,8 @@ static ssize_t mmc_type_show(struct device *dev,
return sprintf(buf, "MMC\n");
case MMC_TYPE_SD:
return sprintf(buf, "SD\n");
+ case MMC_TYPE_SDIO:
+ return sprintf(buf, "SDIO\n");
default:
return -EFAULT;
}
@@ -55,36 +58,35 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
}
static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
- int buf_size)
+mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct mmc_card *card = dev_to_mmc_card(dev);
- int retval = 0, i = 0, length = 0;
-
-#define add_env(fmt,val) do { \
- retval = add_uevent_var(envp, num_envp, &i, \
- buf, buf_size, &length, \
- fmt, val); \
- if (retval) \
- return retval; \
-} while (0);
+ const char *type;
+ int retval = 0;
switch (card->type) {
case MMC_TYPE_MMC:
- add_env("MMC_TYPE=%s", "MMC");
+ type = "MMC";
break;
case MMC_TYPE_SD:
- add_env("MMC_TYPE=%s", "SD");
+ type = "SD";
+ break;
+ case MMC_TYPE_SDIO:
+ type = "SDIO";
break;
+ default:
+ type = NULL;
}
- add_env("MMC_NAME=%s", mmc_card_name(card));
-
-#undef add_env
+ if (type) {
+ retval = add_uevent_var(env, "MMC_TYPE=%s", type);
+ if (retval)
+ return retval;
+ }
- envp[i] = NULL;
+ retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
- return 0;
+ return retval;
}
static int mmc_bus_probe(struct device *dev)
@@ -176,6 +178,11 @@ static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
+ sdio_free_common_cis(card);
+
+ if (card->info)
+ kfree(card->info);
+
kfree(card);
}
@@ -186,12 +193,10 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host)
{
struct mmc_card *card;
- card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+ card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
if (!card)
return ERR_PTR(-ENOMEM);
- memset(card, 0, sizeof(struct mmc_card));
-
card->host = host;
device_initialize(&card->dev);
@@ -209,10 +214,40 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host)
int mmc_add_card(struct mmc_card *card)
{
int ret;
+ const char *type;
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
"%s:%04x", mmc_hostname(card->host), card->rca);
+ switch (card->type) {
+ case MMC_TYPE_MMC:
+ type = "MMC";
+ break;
+ case MMC_TYPE_SD:
+ type = "SD";
+ if (mmc_card_blockaddr(card))
+ type = "SDHC";
+ break;
+ case MMC_TYPE_SDIO:
+ type = "SDIO";
+ break;
+ default:
+ type = "?";
+ break;
+ }
+
+ if (mmc_host_is_spi(card->host)) {
+ printk(KERN_INFO "%s: new %s%s card on SPI\n",
+ mmc_hostname(card->host),
+ mmc_card_highspeed(card) ? "high speed " : "",
+ type);
+ } else {
+ printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+ mmc_hostname(card->host),
+ mmc_card_highspeed(card) ? "high speed " : "",
+ type, card->rca);
+ }
+
card->dev.uevent_suppress = 1;
ret = device_add(&card->dev);
@@ -243,6 +278,14 @@ int mmc_add_card(struct mmc_card *card)
void mmc_remove_card(struct mmc_card *card)
{
if (mmc_card_present(card)) {
+ if (mmc_host_is_spi(card->host)) {
+ printk(KERN_INFO "%s: SPI card removed\n",
+ mmc_hostname(card->host));
+ } else {
+ printk(KERN_INFO "%s: card %04x removed\n",
+ mmc_hostname(card->host), card->rca);
+ }
+
if (card->host->bus_ops->sysfs_remove)
card->host->bus_ops->sysfs_remove(card->host, card);
device_del(&card->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b5d8a6d90cca..09435e0ec680 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
+#include <linux/leds.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
@@ -29,16 +30,27 @@
#include "core.h"
#include "bus.h"
#include "host.h"
+#include "sdio_bus.h"
#include "mmc_ops.h"
#include "sd_ops.h"
+#include "sdio_ops.h"
extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
static struct workqueue_struct *workqueue;
/*
+ * Enabling software CRCs on the data blocks can be a significant (30%)
+ * performance cost, and for other reasons may not always be desired.
+ * So we allow it it to be disabled.
+ */
+int use_spi_crc = 1;
+module_param(use_spi_crc, bool, 0);
+
+/*
* Internal function. Schedule delayed work in the MMC work queue.
*/
static int mmc_schedule_delayed_work(struct delayed_work *work,
@@ -68,32 +80,48 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
int err = cmd->error;
- pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
- mmc_hostname(host), cmd->opcode, err,
- mrq->data ? mrq->data->error : 0,
- mrq->stop ? mrq->stop->error : 0,
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+ if (err && cmd->retries && mmc_host_is_spi(host)) {
+ if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+ cmd->retries = 0;
+ }
if (err && cmd->retries) {
+ pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+ mmc_hostname(host), cmd->opcode, err);
+
cmd->retries--;
cmd->error = 0;
host->ops->request(host, mrq);
- } else if (mrq->done) {
- mrq->done(mrq);
+ } else {
+ led_trigger_event(host->led, LED_OFF);
+
+ pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), cmd->opcode, err,
+ cmd->resp[0], cmd->resp[1],
+ cmd->resp[2], cmd->resp[3]);
+
+ if (mrq->data) {
+ pr_debug("%s: %d bytes transferred: %d\n",
+ mmc_hostname(host),
+ mrq->data->bytes_xfered, mrq->data->error);
+ }
+
+ if (mrq->stop) {
+ pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), mrq->stop->opcode,
+ mrq->stop->error,
+ mrq->stop->resp[0], mrq->stop->resp[1],
+ mrq->stop->resp[2], mrq->stop->resp[3]);
+ }
+
+ if (mrq->done)
+ mrq->done(mrq);
}
}
EXPORT_SYMBOL(mmc_request_done);
-/**
- * mmc_start_request - start a command on a host
- * @host: MMC host to start command on
- * @mrq: MMC request to start
- *
- * Queue a command on the specified host. We expect the
- * caller to be holding the host lock with interrupts disabled.
- */
-void
+static void
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
@@ -104,8 +132,25 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
+ if (mrq->data) {
+ pr_debug("%s: blksz %d blocks %d flags %08x "
+ "tsac %d ms nsac %d\n",
+ mmc_hostname(host), mrq->data->blksz,
+ mrq->data->blocks, mrq->data->flags,
+ mrq->data->timeout_ns / 1000000,
+ mrq->data->timeout_clks);
+ }
+
+ if (mrq->stop) {
+ pr_debug("%s: CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->stop->opcode,
+ mrq->stop->arg, mrq->stop->flags);
+ }
+
WARN_ON(!host->claimed);
+ led_trigger_event(host->led, LED_FULL);
+
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
@@ -133,14 +178,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
host->ops->request(host, mrq);
}
-EXPORT_SYMBOL(mmc_start_request);
-
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(mrq->done_data);
}
-int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+/**
+ * mmc_wait_for_req - start a request and wait for completion
+ * @host: MMC host to start command
+ * @mrq: MMC request to start
+ *
+ * Start a new MMC custom command request for a host, and wait
+ * for the command to complete. Does not attempt to parse the
+ * response.
+ */
+void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
DECLARE_COMPLETION_ONSTACK(complete);
@@ -150,8 +202,6 @@ int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
mmc_start_request(host, mrq);
wait_for_completion(&complete);
-
- return 0;
}
EXPORT_SYMBOL(mmc_wait_for_req);
@@ -170,7 +220,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -191,14 +241,24 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
* mmc_set_data_timeout - set the timeout for a data command
* @data: data phase for command
* @card: the MMC card associated with the data transfer
- * @write: flag to differentiate reads from writes
+ *
+ * Computes the data timeout parameters according to the
+ * correct algorithm given the card type.
*/
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
- int write)
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
{
unsigned int mult;
/*
+ * SDIO cards only define an upper 1 s limit on access.
+ */
+ if (mmc_card_sdio(card)) {
+ data->timeout_ns = 1000000000;
+ data->timeout_clks = 0;
+ return;
+ }
+
+ /*
* SD cards use a 100 multiplier rather than 10
*/
mult = mmc_card_sd(card) ? 100 : 10;
@@ -207,7 +267,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
* Scale up the multiplier (and therefore the timeout) by
* the r2w factor for writes.
*/
- if (write)
+ if (data->flags & MMC_DATA_WRITE)
mult <<= card->csd.r2w_factor;
data->timeout_ns = card->csd.tacc_ns * mult;
@@ -223,7 +283,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
timeout_us += data->timeout_clks * 1000 /
(card->host->ios.clock / 1000);
- if (write)
+ if (data->flags & MMC_DATA_WRITE)
limit_us = 250000;
else
limit_us = 100000;
@@ -242,36 +302,43 @@ EXPORT_SYMBOL(mmc_set_data_timeout);
/**
* __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
- * @card: mmc card to claim host for
+ * @abort: whether or not the operation should be aborted
*
- * Claim a host for a set of operations. If a valid card
- * is passed and this wasn't the last card selected, select
- * the card before returning.
- *
- * Note: you should use mmc_card_claim_host or mmc_claim_host.
+ * Claim a host for a set of operations. If @abort is non null and
+ * dereference a non-zero value then this will return prematurely with
+ * that non-zero value without acquiring the lock. Returns zero
+ * with the lock held otherwise.
*/
-void mmc_claim_host(struct mmc_host *host)
+int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
+ int stop;
+
+ might_sleep();
add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (!host->claimed)
+ stop = abort ? atomic_read(abort) : 0;
+ if (stop || !host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- host->claimed = 1;
+ if (!stop)
+ host->claimed = 1;
+ else
+ wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
+ return stop;
}
-EXPORT_SYMBOL(mmc_claim_host);
+EXPORT_SYMBOL(__mmc_claim_host);
/**
* mmc_release_host - release a host
@@ -284,7 +351,7 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
host->claimed = 0;
@@ -404,19 +471,32 @@ static void mmc_power_up(struct mmc_host *host)
int bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
+ if (mmc_host_is_spi(host)) {
+ host->ios.chip_select = MMC_CS_HIGH;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ } else {
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ }
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
- mmc_delay(1);
+ /*
+ * This delay should be sufficient to allow the power supply
+ * to reach the minimum voltage.
+ */
+ mmc_delay(2);
host->ios.clock = host->f_min;
host->ios.power_mode = MMC_POWER_ON;
mmc_set_ios(host);
+ /*
+ * This delay must be at least 74 clock sizes, or 1 ms, or the
+ * time required to reach a stable voltage.
+ */
mmc_delay(2);
}
@@ -424,8 +504,10 @@ static void mmc_power_off(struct mmc_host *host)
{
host->ios.clock = 0;
host->ios.vdd = 0;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
+ if (!mmc_host_is_spi(host)) {
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ }
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
@@ -433,6 +515,45 @@ static void mmc_power_off(struct mmc_host *host)
}
/*
+ * Cleanup when the last reference to the bus operator is dropped.
+ */
+void __mmc_release_bus(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(host->bus_refs);
+ BUG_ON(!host->bus_dead);
+
+ host->bus_ops = NULL;
+}
+
+/*
+ * Increase reference count of bus operator
+ */
+static inline void mmc_bus_get(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs++;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * Decrease reference count of bus operator and free it if
+ * it is the last reference.
+ */
+static inline void mmc_bus_put(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs--;
+ if ((host->bus_refs == 0) && host->bus_ops)
+ __mmc_release_bus(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
* Assign a mmc bus handler to a host. Only one bus handler may control a
* host at any given time.
*/
@@ -443,7 +564,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
BUG_ON(!host);
BUG_ON(!ops);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
@@ -467,8 +588,8 @@ void mmc_detach_bus(struct mmc_host *host)
BUG_ON(!host);
- BUG_ON(!host->claimed);
- BUG_ON(!host->bus_ops);
+ WARN_ON(!host->claimed);
+ WARN_ON(!host->bus_ops);
spin_lock_irqsave(&host->lock, flags);
@@ -481,32 +602,22 @@ void mmc_detach_bus(struct mmc_host *host)
mmc_bus_put(host);
}
-/*
- * Cleanup when the last reference to the bus operator is dropped.
- */
-void __mmc_release_bus(struct mmc_host *host)
-{
- BUG_ON(!host);
- BUG_ON(host->bus_refs);
- BUG_ON(!host->bus_dead);
-
- host->bus_ops = NULL;
-}
-
/**
* mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state.
* @delay: optional delay to wait before detection (jiffies)
*
- * All we know is that card(s) have been inserted or removed
- * from the socket(s). We don't know which socket or cards.
+ * MMC drivers should call this when they detect a card has been
+ * inserted or removed. The MMC layer will confirm that any
+ * present card is still functional, and initialize any newly
+ * inserted.
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
- BUG_ON(host->removed);
+ WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
@@ -539,24 +650,38 @@ void mmc_rescan(struct work_struct *work)
mmc_send_if_cond(host, host->ocr_avail);
+ /*
+ * First we search for SDIO...
+ */
+ err = mmc_send_io_op_cond(host, 0, &ocr);
+ if (!err) {
+ if (mmc_attach_sdio(host, ocr))
+ mmc_power_off(host);
+ return;
+ }
+
+ /*
+ * ...then normal SD...
+ */
err = mmc_send_app_op_cond(host, 0, &ocr);
- if (err == MMC_ERR_NONE) {
+ if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
- } else {
- /*
- * If we fail to detect any SD cards then try
- * searching for MMC cards.
- */
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err == MMC_ERR_NONE) {
- if (mmc_attach_mmc(host, ocr))
- mmc_power_off(host);
- } else {
+ return;
+ }
+
+ /*
+ * ...and finally MMC.
+ */
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (!err) {
+ if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
- mmc_release_host(host);
- }
+ return;
}
+
+ mmc_release_host(host);
+ mmc_power_off(host);
} else {
if (host->bus_ops->detect && !host->bus_dead)
host->bus_ops->detect(host);
@@ -667,22 +792,38 @@ static int __init mmc_init(void)
return -ENOMEM;
ret = mmc_register_bus();
- if (ret == 0) {
- ret = mmc_register_host_class();
- if (ret)
- mmc_unregister_bus();
- }
+ if (ret)
+ goto destroy_workqueue;
+
+ ret = mmc_register_host_class();
+ if (ret)
+ goto unregister_bus;
+
+ ret = sdio_register_bus();
+ if (ret)
+ goto unregister_host_class;
+
+ return 0;
+
+unregister_host_class:
+ mmc_unregister_host_class();
+unregister_bus:
+ mmc_unregister_bus();
+destroy_workqueue:
+ destroy_workqueue(workqueue);
+
return ret;
}
static void __exit mmc_exit(void)
{
+ sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
destroy_workqueue(workqueue);
}
-module_init(mmc_init);
+subsys_initcall(mmc_init);
module_exit(mmc_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index ae006b30dd86..39daf2fb5dc4 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -27,28 +27,6 @@ struct mmc_bus_ops {
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);
-void __mmc_release_bus(struct mmc_host *host);
-
-static inline void mmc_bus_get(struct mmc_host *host)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs++;
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static inline void mmc_bus_put(struct mmc_host *host)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs--;
- if ((host->bus_refs == 0) && host->bus_ops)
- __mmc_release_bus(host);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
@@ -70,5 +48,7 @@ void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
+extern int use_spi_crc;
+
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 1433d95c40bb..c65d203a846d 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/pagemap.h>
+#include <linux/leds.h>
#include <linux/mmc/host.h>
@@ -58,12 +59,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
struct mmc_host *host;
- host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+ host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host)
return NULL;
- memset(host, 0, sizeof(struct mmc_host) + extra);
-
host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
@@ -93,11 +92,18 @@ EXPORT_SYMBOL(mmc_alloc_host);
/**
* mmc_add_host - initialise host hardware
* @host: mmc host
+ *
+ * Register the host with the driver model. The host must be
+ * prepared to start servicing requests before this function
+ * completes.
*/
int mmc_add_host(struct mmc_host *host)
{
int err;
+ WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
+ !host->ops->enable_sdio_irq);
+
if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
return -ENOMEM;
@@ -110,6 +116,8 @@ int mmc_add_host(struct mmc_host *host)
snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
"mmc%d", host->index);
+ led_trigger_register_simple(host->class_dev.bus_id, &host->led);
+
err = device_add(&host->class_dev);
if (err)
return err;
@@ -126,7 +134,8 @@ EXPORT_SYMBOL(mmc_add_host);
* @host: mmc host
*
* Unregister and remove all cards associated with this host,
- * and power down the MMC bus.
+ * and power down the MMC bus. No new requests will be issued
+ * after this function has returned.
*/
void mmc_remove_host(struct mmc_host *host)
{
@@ -134,6 +143,8 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev);
+ led_trigger_unregister_simple(host->led);
+
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
spin_unlock(&mmc_host_lock);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 66f85bfa8dbb..65fe28860f54 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc.c
+ * linux/drivers/mmc/core/mmc.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
@@ -100,7 +100,7 @@ static int mmc_decode_cid(struct mmc_card *card)
break;
default:
- printk("%s: card has unknown MMCA version %d\n",
+ printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
mmc_hostname(card->host), card->csd.mmca_vsn);
return -EINVAL;
}
@@ -123,7 +123,7 @@ static int mmc_decode_csd(struct mmc_card *card)
*/
csd_struct = UNSTUFF_BITS(resp, 126, 2);
if (csd_struct != 1 && csd_struct != 2) {
- printk("%s: unrecognised CSD structure version %d\n",
+ printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
return -EINVAL;
}
@@ -161,13 +161,12 @@ static int mmc_read_ext_csd(struct mmc_card *card)
{
int err;
u8 *ext_csd;
+ unsigned int ext_csd_struct;
BUG_ON(!card);
- err = MMC_ERR_FAILED;
-
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return MMC_ERR_NONE;
+ return 0;
/*
* As the ext_csd is so large and mostly unused, we don't store the
@@ -176,13 +175,19 @@ static int mmc_read_ext_csd(struct mmc_card *card)
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
printk(KERN_ERR "%s: could not allocate a buffer to "
- "receive the ext_csd. mmc v4 cards will be "
- "treated as v3.\n", mmc_hostname(card->host));
- return MMC_ERR_FAILED;
+ "receive the ext_csd.\n", mmc_hostname(card->host));
+ return -ENOMEM;
}
err = mmc_send_ext_csd(card, ext_csd);
- if (err != MMC_ERR_NONE) {
+ if (err) {
+ /*
+ * We all hosts that cannot perform the command
+ * to fail more gracefully
+ */
+ if (err != -EINVAL)
+ goto out;
+
/*
* High capacity cards should have this "magic" size
* stored in their CSD.
@@ -197,18 +202,29 @@ static int mmc_read_ext_csd(struct mmc_card *card)
"EXT_CSD, performance might "
"suffer.\n",
mmc_hostname(card->host));
- err = MMC_ERR_NONE;
+ err = 0;
}
+
goto out;
}
- card->ext_csd.sectors =
- ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
- ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
- ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
- ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
- if (card->ext_csd.sectors)
- mmc_card_set_blockaddr(card);
+ ext_csd_struct = ext_csd[EXT_CSD_REV];
+ if (ext_csd_struct > 2) {
+ printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
+ "version %d\n", mmc_hostname(card->host),
+ ext_csd_struct);
+ return -EINVAL;
+ }
+
+ if (ext_csd_struct >= 2) {
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+ ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+ ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ if (card->ext_csd.sectors)
+ mmc_card_set_blockaddr(card);
+ }
switch (ext_csd[EXT_CSD_CARD_TYPE]) {
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
@@ -246,7 +262,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
unsigned int max_dtr;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
/*
* Since we're changing the OCR value, we seem to
@@ -258,19 +274,33 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
/* The extra bit indicates that we support high capacity */
err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
/*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
* Fetch CID from card.
*/
- err = mmc_all_send_cid(host, cid);
- if (err != MMC_ERR_NONE)
+ if (mmc_host_is_spi(host))
+ err = mmc_send_cid(host, cid);
+ else
+ err = mmc_all_send_cid(host, cid);
+ if (err)
goto err;
if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+ err = -ENOENT;
goto err;
+ }
card = oldcard;
} else {
@@ -278,8 +308,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* Allocate card structure.
*/
card = mmc_alloc_card(host);
- if (IS_ERR(card))
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
goto err;
+ }
card->type = MMC_TYPE_MMC;
card->rca = 1;
@@ -287,43 +319,47 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
- * Set card RCA.
+ * For native busses: set card RCA and quit open drain mode.
*/
- err = mmc_set_relative_addr(card);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_set_relative_addr(card);
+ if (err)
+ goto free_card;
- mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
if (!oldcard) {
/*
* Fetch CSD from card.
*/
err = mmc_send_csd(card, card->raw_csd);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
err = mmc_decode_csd(card);
- if (err < 0)
+ if (err)
goto free_card;
err = mmc_decode_cid(card);
- if (err < 0)
+ if (err)
goto free_card;
}
/*
* Select card, as all following commands rely on that.
*/
- err = mmc_select_card(card);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto free_card;
+ }
if (!oldcard) {
/*
- * Fetch and process extened CSD.
+ * Fetch and process extended CSD.
*/
err = mmc_read_ext_csd(card);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
}
@@ -334,7 +370,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
mmc_card_set_highspeed(card);
@@ -363,7 +399,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
(host->caps & MMC_CAP_4_BIT_DATA)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
@@ -372,14 +408,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
- return MMC_ERR_NONE;
+ return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- return MMC_ERR_FAILED;
+ return err;
}
/*
@@ -413,7 +449,7 @@ static void mmc_detect(struct mmc_host *host)
mmc_release_host(host);
- if (err != MMC_ERR_NONE) {
+ if (err) {
mmc_remove(host);
mmc_claim_host(host);
@@ -480,7 +516,8 @@ static void mmc_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- mmc_deselect_cards(host);
+ if (!mmc_host_is_spi(host))
+ mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
}
@@ -499,14 +536,17 @@ static void mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
-
err = mmc_init_card(host, host->ocr, host->card);
- if (err != MMC_ERR_NONE) {
+ mmc_release_host(host);
+
+ if (err) {
mmc_remove(host);
+
+ mmc_claim_host(host);
mmc_detach_bus(host);
+ mmc_release_host(host);
}
- mmc_release_host(host);
}
#else
@@ -533,11 +573,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
int err;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
mmc_attach_bus(host, &mmc_ops);
/*
+ * We need to get OCR a different way for SPI.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_read_ocr(host, 1, &ocr);
+ if (err)
+ goto err;
+ }
+
+ /*
* Sanity check the voltages that the card claims to
* support.
*/
@@ -553,32 +602,37 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
/*
* Can we support the voltage of the card?
*/
- if (!host->ocr)
+ if (!host->ocr) {
+ err = -EINVAL;
goto err;
+ }
/*
* Detect and init the card.
*/
err = mmc_init_card(host, host->ocr, NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
mmc_release_host(host);
err = mmc_add_card(host->card);
if (err)
- goto reclaim_host;
+ goto remove_card;
return 0;
-reclaim_host:
- mmc_claim_host(host);
+remove_card:
mmc_remove_card(host->card);
host->card = NULL;
+ mmc_claim_host(host);
err:
mmc_detach_bus(host);
mmc_release_host(host);
- return 0;
+ printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
+ mmc_hostname(host), err);
+
+ return err;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 7dd720fa5895..bf4bc6adcfef 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc_ops.h
+ * linux/drivers/mmc/core/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
@@ -40,10 +40,10 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
}
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_select_card(struct mmc_card *card)
@@ -63,23 +63,36 @@ int mmc_go_idle(struct mmc_host *host)
int err;
struct mmc_command cmd;
- mmc_set_chip_select(host, MMC_CS_HIGH);
-
- mmc_delay(1);
+ /*
+ * Non-SPI hosts need to prevent chipselect going active during
+ * GO_IDLE; that would put chips into SPI mode. Remind them of
+ * that in case of hardware that won't pull up DAT3/nCS otherwise.
+ *
+ * SPI hosts ignore ios.chip_select; it's managed according to
+ * rules that must accomodate non-MMC slaves which this layer
+ * won't even know about.
+ */
+ if (!mmc_host_is_spi(host)) {
+ mmc_set_chip_select(host, MMC_CS_HIGH);
+ mmc_delay(1);
+ }
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
err = mmc_wait_for_cmd(host, &cmd, 0);
mmc_delay(1);
- mmc_set_chip_select(host, MMC_CS_DONTCARE);
+ if (!mmc_host_is_spi(host)) {
+ mmc_set_chip_select(host, MMC_CS_DONTCARE);
+ mmc_delay(1);
+ }
- mmc_delay(1);
+ host->use_spi_crc = 0;
return err;
}
@@ -94,23 +107,33 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
+ if (err)
break;
- if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
break;
- err = MMC_ERR_TIMEOUT;
+ /* otherwise wait until reset completes */
+ if (mmc_host_is_spi(host)) {
+ if (!(cmd.resp[0] & R1_SPI_IDLE))
+ break;
+ } else {
+ if (cmd.resp[0] & MMC_CARD_BUSY)
+ break;
+ }
+
+ err = -ETIMEDOUT;
mmc_delay(10);
}
- if (rocr)
+ if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0];
return err;
@@ -131,12 +154,12 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
memcpy(cid, cmd.resp, sizeof(u32) * 4);
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_set_relative_addr(struct mmc_card *card)
@@ -154,46 +177,52 @@ int mmc_set_relative_addr(struct mmc_card *card)
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
-int mmc_send_csd(struct mmc_card *card, u32 *csd)
+static int
+mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
{
int err;
struct mmc_command cmd;
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!csd);
+ BUG_ON(!host);
+ BUG_ON(!cxd);
memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = MMC_SEND_CSD;
- cmd.arg = card->rca << 16;
+ cmd.opcode = opcode;
+ cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
return err;
- memcpy(csd, cmd.resp, sizeof(u32) * 4);
+ memcpy(cxd, cmd.resp, sizeof(u32) * 4);
- return MMC_ERR_NONE;
+ return 0;
}
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+static int
+mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
+ u32 opcode, void *buf, unsigned len)
{
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
struct scatterlist sg;
+ void *data_buf;
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!ext_csd);
+ /* dma onto stack is unsafe/nonportable, but callers to this
+ * routine normally provide temporary on-stack buffers ...
+ */
+ data_buf = kmalloc(len, GFP_KERNEL);
+ if (data_buf == NULL)
+ return -ENOMEM;
memset(&mrq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command));
@@ -202,28 +231,99 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
mrq.cmd = &cmd;
mrq.data = &data;
- cmd.opcode = MMC_SEND_EXT_CSD;
+ cmd.opcode = opcode;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- data.blksz = 512;
+ /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we
+ * rely on callers to never use this with "native" calls for reading
+ * CSD or CID. Native versions of those commands use the R2 type,
+ * not R1 plus a data block.
+ */
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = len;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
- sg_init_one(&sg, ext_csd, 512);
+ sg_init_one(&sg, data_buf, len);
- mmc_set_data_timeout(&data, card, 0);
+ if (card)
+ mmc_set_data_timeout(&data, card);
- mmc_wait_for_req(card->host, &mrq);
+ mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE)
+ memcpy(buf, data_buf, len);
+ kfree(data_buf);
+
+ if (cmd.error)
return cmd.error;
- if (data.error != MMC_ERR_NONE)
+ if (data.error)
return data.error;
- return MMC_ERR_NONE;
+ return 0;
+}
+
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+ if (!mmc_host_is_spi(card->host))
+ return mmc_send_cxd_native(card->host, card->rca << 16,
+ csd, MMC_SEND_CSD);
+
+ return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+}
+
+int mmc_send_cid(struct mmc_host *host, u32 *cid)
+{
+ if (!mmc_host_is_spi(host)) {
+ if (!host->card)
+ return -EINVAL;
+ return mmc_send_cxd_native(host, host->card->rca << 16,
+ cid, MMC_SEND_CID);
+ }
+
+ return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+ return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
+ ext_csd, 512);
+}
+
+int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
+{
+ struct mmc_command cmd;
+ int err;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SPI_READ_OCR;
+ cmd.arg = highcap ? (1 << 30) : 0;
+ cmd.flags = MMC_RSP_SPI_R3;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+
+ *ocrp = cmd.resp[1];
+ return err;
+}
+
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
+{
+ struct mmc_command cmd;
+ int err;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SPI_CRC_ON_OFF;
+ cmd.flags = MMC_RSP_SPI_R1;
+ cmd.arg = use_crc;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (!err)
+ host->use_spi_crc = use_crc;
+ return err;
}
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
@@ -241,13 +341,13 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_send_status(struct mmc_card *card, u32 *status)
@@ -261,16 +361,20 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
+ /* NOTE: callers are required to understand the difference
+ * between "native" and SPI format status words!
+ */
if (status)
*status = cmd.resp[0];
- return MMC_ERR_NONE;
+ return 0;
}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 7a481e8ca5ea..17854bf7cf0d 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc_ops.h
+ * linux/drivers/mmc/core/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
@@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd);
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
int mmc_send_status(struct mmc_card *card, u32 *status);
+int mmc_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
#endif
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 1240684083f1..d1c1e0f592f1 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sd.c
+ * linux/drivers/mmc/core/sd.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
@@ -149,7 +149,7 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->write_partial = 0;
break;
default:
- printk("%s: unrecognised CSD structure version %d\n",
+ printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
return -EINVAL;
}
@@ -166,14 +166,12 @@ static int mmc_decode_scr(struct mmc_card *card)
unsigned int scr_struct;
u32 resp[4];
- BUG_ON(!mmc_card_sd(card));
-
resp[3] = card->raw_scr[1];
resp[2] = card->raw_scr[0];
scr_struct = UNSTUFF_BITS(resp, 60, 4);
if (scr_struct != 0) {
- printk("%s: unrecognised SCR structure version %d\n",
+ printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
mmc_hostname(card->host), scr_struct);
return -EINVAL;
}
@@ -193,31 +191,38 @@ static int mmc_read_switch(struct mmc_card *card)
u8 *status;
if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- return MMC_ERR_NONE;
+ return 0;
if (!(card->csd.cmdclass & CCC_SWITCH)) {
printk(KERN_WARNING "%s: card lacks mandatory switch "
"function, performance might suffer.\n",
mmc_hostname(card->host));
- return MMC_ERR_NONE;
+ return 0;
}
- err = MMC_ERR_FAILED;
+ err = -EIO;
status = kmalloc(64, GFP_KERNEL);
if (!status) {
- printk("%s: could not allocate a buffer for switch "
- "capabilities.\n",
- mmc_hostname(card->host));
- return err;
+ printk(KERN_ERR "%s: could not allocate a buffer for "
+ "switch capabilities.\n", mmc_hostname(card->host));
+ return -ENOMEM;
}
err = mmc_sd_switch(card, 0, 0, 1, status);
- if (err != MMC_ERR_NONE) {
+ if (err) {
+ /*
+ * We all hosts that cannot perform the command
+ * to fail more gracefully
+ */
+ if (err != -EINVAL)
+ goto out;
+
printk(KERN_WARNING "%s: problem reading switch "
"capabilities, performance might suffer.\n",
mmc_hostname(card->host));
- err = MMC_ERR_NONE;
+ err = 0;
+
goto out;
}
@@ -239,29 +244,28 @@ static int mmc_switch_hs(struct mmc_card *card)
u8 *status;
if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- return MMC_ERR_NONE;
+ return 0;
if (!(card->csd.cmdclass & CCC_SWITCH))
- return MMC_ERR_NONE;
+ return 0;
if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
- return MMC_ERR_NONE;
+ return 0;
if (card->sw_caps.hs_max_dtr == 0)
- return MMC_ERR_NONE;
+ return 0;
- err = MMC_ERR_FAILED;
+ err = -EIO;
status = kmalloc(64, GFP_KERNEL);
if (!status) {
- printk("%s: could not allocate a buffer for switch "
- "capabilities.\n",
- mmc_hostname(card->host));
- return err;
+ printk(KERN_ERR "%s: could not allocate a buffer for "
+ "switch capabilities.\n", mmc_hostname(card->host));
+ return -ENOMEM;
}
err = mmc_sd_switch(card, 1, 0, 1, status);
- if (err != MMC_ERR_NONE)
+ if (err)
goto out;
if ((status[16] & 0xF) != 1) {
@@ -294,7 +298,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
unsigned int max_dtr;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
/*
* Since we're changing the OCR value, we seem to
@@ -311,23 +315,37 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* block-addressed SDHC cards.
*/
err = mmc_send_if_cond(host, ocr);
- if (err == MMC_ERR_NONE)
+ if (!err)
ocr |= 1 << 30;
err = mmc_send_app_op_cond(host, ocr, NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
/*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
* Fetch CID from card.
*/
- err = mmc_all_send_cid(host, cid);
- if (err != MMC_ERR_NONE)
+ if (mmc_host_is_spi(host))
+ err = mmc_send_cid(host, cid);
+ else
+ err = mmc_all_send_cid(host, cid);
+ if (err)
goto err;
if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+ err = -ENOENT;
goto err;
+ }
card = oldcard;
} else {
@@ -335,32 +353,36 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Allocate card structure.
*/
card = mmc_alloc_card(host);
- if (IS_ERR(card))
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
goto err;
+ }
card->type = MMC_TYPE_SD;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}
/*
- * Set card RCA.
+ * For native busses: get card RCA and quit open drain mode.
*/
- err = mmc_send_relative_addr(host, &card->rca);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto free_card;
- mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
if (!oldcard) {
/*
* Fetch CSD from card.
*/
err = mmc_send_csd(card, card->raw_csd);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
err = mmc_decode_csd(card);
- if (err < 0)
+ if (err)
goto free_card;
mmc_decode_cid(card);
@@ -369,16 +391,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
/*
* Select card, as all following commands rely on that.
*/
- err = mmc_select_card(card);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto free_card;
+ }
if (!oldcard) {
/*
* Fetch SCR from card.
*/
err = mmc_app_send_scr(card, card->raw_scr);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
err = mmc_decode_scr(card);
@@ -389,7 +413,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Fetch switch information from card.
*/
err = mmc_read_switch(card);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
}
@@ -397,7 +421,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Attempt to change to high-speed (if supported)
*/
err = mmc_switch_hs(card);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
/*
@@ -420,7 +444,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if ((host->caps & MMC_CAP_4_BIT_DATA) &&
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
@@ -444,14 +468,14 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
- return MMC_ERR_NONE;
+ return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- return MMC_ERR_FAILED;
+ return err;
}
/*
@@ -485,7 +509,7 @@ static void mmc_sd_detect(struct mmc_host *host)
mmc_release_host(host);
- if (err != MMC_ERR_NONE) {
+ if (err) {
mmc_sd_remove(host);
mmc_claim_host(host);
@@ -554,7 +578,8 @@ static void mmc_sd_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- mmc_deselect_cards(host);
+ if (!mmc_host_is_spi(host))
+ mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
}
@@ -573,14 +598,17 @@ static void mmc_sd_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
-
err = mmc_sd_init_card(host, host->ocr, host->card);
- if (err != MMC_ERR_NONE) {
+ mmc_release_host(host);
+
+ if (err) {
mmc_sd_remove(host);
+
+ mmc_claim_host(host);
mmc_detach_bus(host);
+ mmc_release_host(host);
}
- mmc_release_host(host);
}
#else
@@ -607,11 +635,22 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
int err;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
mmc_attach_bus(host, &mmc_sd_ops);
/*
+ * We need to get OCR a different way for SPI.
+ */
+ if (mmc_host_is_spi(host)) {
+ mmc_go_idle(host);
+
+ err = mmc_spi_read_ocr(host, 0, &ocr);
+ if (err)
+ goto err;
+ }
+
+ /*
* Sanity check the voltages that the card claims to
* support.
*/
@@ -634,32 +673,37 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
/*
* Can we support the voltage(s) of the card(s)?
*/
- if (!host->ocr)
+ if (!host->ocr) {
+ err = -EINVAL;
goto err;
+ }
/*
* Detect and init the card.
*/
err = mmc_sd_init_card(host, host->ocr, NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
mmc_release_host(host);
err = mmc_add_card(host->card);
if (err)
- goto reclaim_host;
+ goto remove_card;
return 0;
-reclaim_host:
- mmc_claim_host(host);
+remove_card:
mmc_remove_card(host->card);
host->card = NULL;
+ mmc_claim_host(host);
err:
mmc_detach_bus(host);
mmc_release_host(host);
- return 0;
+ printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
+ mmc_hostname(host), err);
+
+ return err;
}
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 9697ce581101..ee4029a24efd 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sd_ops.h
+ * linux/drivers/mmc/core/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
@@ -21,11 +21,40 @@
#include "core.h"
#include "sd_ops.h"
+static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!host);
+ BUG_ON(card && (card->host != host));
+
+ cmd.opcode = MMC_APP_CMD;
+
+ if (card) {
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ } else {
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
+ }
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ /* Check that card supported application commands */
+ if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
/**
* mmc_wait_for_app_cmd - start an application command and wait for
completion
* @host: MMC host to start command
- * @rca: RCA to send MMC_APP_CMD to
+ * @card: Card to send MMC_APP_CMD to
* @cmd: MMC command to start
* @retries: maximum number of retries
*
@@ -44,7 +73,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
BUG_ON(!cmd);
BUG_ON(retries < 0);
- err = MMC_ERR_INVALID;
+ err = -EIO;
/*
* We have to resend MMC_APP_CMD for each attempt so
@@ -54,8 +83,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
memset(&mrq, 0, sizeof(struct mmc_request));
err = mmc_app_cmd(host, card);
- if (err != MMC_ERR_NONE)
+ if (err) {
+ /* no point in retrying; no APP commands allowed */
+ if (mmc_host_is_spi(host)) {
+ if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+ break;
+ }
continue;
+ }
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -68,8 +103,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
mmc_wait_for_req(host, &mrq);
err = cmd->error;
- if (cmd->error == MMC_ERR_NONE)
+ if (!cmd->error)
break;
+
+ /* no point in retrying illegal APP commands */
+ if (mmc_host_is_spi(host)) {
+ if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+ break;
+ }
}
return err;
@@ -77,35 +118,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
-{
- int err;
- struct mmc_command cmd;
-
- BUG_ON(!host);
- BUG_ON(card && (card->host != host));
-
- cmd.opcode = MMC_APP_CMD;
-
- if (card) {
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
- }
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
- return err;
-
- /* Check that card supported application commands */
- if (!(cmd.resp[0] & R1_APP_CMD))
- return MMC_ERR_FAILED;
-
- return MMC_ERR_NONE;
-}
-
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
int err;
@@ -127,14 +139,14 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
cmd.arg = SD_BUS_WIDTH_4;
break;
default:
- return MMC_ERR_INVALID;
+ return -EINVAL;
}
err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
@@ -147,23 +159,36 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ if (mmc_host_is_spi(host))
+ cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
+ else
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
break;
- if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
break;
- err = MMC_ERR_TIMEOUT;
+ /* otherwise wait until reset completes */
+ if (mmc_host_is_spi(host)) {
+ if (!(cmd.resp[0] & R1_SPI_IDLE))
+ break;
+ } else {
+ if (cmd.resp[0] & MMC_CARD_BUSY)
+ break;
+ }
+
+ err = -ETIMEDOUT;
mmc_delay(10);
}
- if (rocr)
+ if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0];
return err;
@@ -174,6 +199,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
struct mmc_command cmd;
int err;
static const u8 test_pattern = 0xAA;
+ u8 result_pattern;
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
@@ -182,16 +208,21 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
*/
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
- cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- if ((cmd.resp[0] & 0xFF) != test_pattern)
- return MMC_ERR_FAILED;
+ if (mmc_host_is_spi(host))
+ result_pattern = cmd.resp[1] & 0xFF;
+ else
+ result_pattern = cmd.resp[0] & 0xFF;
- return MMC_ERR_NONE;
+ if (result_pattern != test_pattern)
+ return -EIO;
+
+ return 0;
}
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
@@ -209,12 +240,12 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
*rca = cmd.resp[0] >> 16;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
@@ -229,8 +260,10 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
BUG_ON(!card->host);
BUG_ON(!scr);
+ /* NOTE: caller guarantees scr is heap-allocated */
+
err = mmc_app_cmd(card->host, card);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -242,7 +275,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 8;
data.blocks = 1;
@@ -252,19 +285,19 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
sg_init_one(&sg, scr, 8);
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
- if (cmd.error != MMC_ERR_NONE)
+ if (cmd.error)
return cmd.error;
- if (data.error != MMC_ERR_NONE)
+ if (data.error)
return data.error;
scr[0] = ntohl(scr[0]);
scr[1] = ntohl(scr[1]);
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
@@ -278,6 +311,8 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
BUG_ON(!card);
BUG_ON(!card->host);
+ /* NOTE: caller guarantees resp is heap-allocated */
+
mode = !!mode;
value &= 0xF;
@@ -292,7 +327,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
cmd.arg = mode << 31 | 0x00FFFFFF;
cmd.arg &= ~(0xF << (group * 4));
cmd.arg |= value << (group * 4);
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 64;
data.blocks = 1;
@@ -302,15 +337,15 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
sg_init_one(&sg, resp, 64);
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
- if (cmd.error != MMC_ERR_NONE)
+ if (cmd.error)
return cmd.error;
- if (data.error != MMC_ERR_NONE)
+ if (data.error)
return data.error;
- return MMC_ERR_NONE;
+ return 0;
}
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 1240fddba5e3..9742d8a30664 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sd_ops.h
+ * linux/drivers/mmc/core/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
@@ -12,7 +12,6 @@
#ifndef _MMC_SD_OPS_H
#define _MMC_SD_OPS_H
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
new file mode 100644
index 000000000000..87a50f456efc
--- /dev/null
+++ b/drivers/mmc/core/sdio.c
@@ -0,0 +1,395 @@
+/*
+ * linux/drivers/mmc/sdio.c
+ *
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "core.h"
+#include "bus.h"
+#include "sdio_bus.h"
+#include "mmc_ops.h"
+#include "sd_ops.h"
+#include "sdio_ops.h"
+#include "sdio_cis.h"
+
+static int sdio_read_fbr(struct sdio_func *func)
+{
+ int ret;
+ unsigned char data;
+
+ ret = mmc_io_rw_direct(func->card, 0, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
+ if (ret)
+ goto out;
+
+ data &= 0x0f;
+
+ if (data == 0x0f) {
+ ret = mmc_io_rw_direct(func->card, 0, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data);
+ if (ret)
+ goto out;
+ }
+
+ func->class = data;
+
+out:
+ return ret;
+}
+
+static int sdio_init_func(struct mmc_card *card, unsigned int fn)
+{
+ int ret;
+ struct sdio_func *func;
+
+ BUG_ON(fn > SDIO_MAX_FUNCS);
+
+ func = sdio_alloc_func(card);
+ if (IS_ERR(func))
+ return PTR_ERR(func);
+
+ func->num = fn;
+
+ ret = sdio_read_fbr(func);
+ if (ret)
+ goto fail;
+
+ ret = sdio_read_func_cis(func);
+ if (ret)
+ goto fail;
+
+ card->sdio_func[fn - 1] = func;
+
+ return 0;
+
+fail:
+ /*
+ * It is okay to remove the function here even though we hold
+ * the host lock as we haven't registered the device yet.
+ */
+ sdio_remove_func(func);
+ return ret;
+}
+
+static int sdio_read_cccr(struct mmc_card *card)
+{
+ int ret;
+ int cccr_vsn;
+ unsigned char data;
+
+ memset(&card->cccr, 0, sizeof(struct sdio_cccr));
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
+ if (ret)
+ goto out;
+
+ cccr_vsn = data & 0x0f;
+
+ if (cccr_vsn > SDIO_CCCR_REV_1_20) {
+ printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n",
+ mmc_hostname(card->host), cccr_vsn);
+ return -EINVAL;
+ }
+
+ card->cccr.sdio_vsn = (data & 0xf0) >> 4;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_CCCR_CAP_SMB)
+ card->cccr.multi_block = 1;
+ if (data & SDIO_CCCR_CAP_LSC)
+ card->cccr.low_speed = 1;
+ if (data & SDIO_CCCR_CAP_4BLS)
+ card->cccr.wide_bus = 1;
+
+ if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_POWER_SMPC)
+ card->cccr.high_power = 1;
+ }
+
+ if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_SPEED_SHS)
+ card->cccr.high_speed = 1;
+ }
+
+out:
+ return ret;
+}
+
+static int sdio_enable_wide(struct mmc_card *card)
+{
+ int ret;
+ u8 ctrl;
+
+ if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
+ return 0;
+
+ if (card->cccr.low_speed && !card->cccr.wide_bus)
+ return 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+ if (ret)
+ return ret;
+
+ ctrl |= SDIO_BUS_WIDTH_4BIT;
+
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+ if (ret)
+ return ret;
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+
+ return 0;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_sdio_remove(struct mmc_host *host)
+{
+ int i;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ for (i = 0;i < host->card->sdio_funcs;i++) {
+ if (host->card->sdio_func[i]) {
+ sdio_remove_func(host->card->sdio_func[i]);
+ host->card->sdio_func[i] = NULL;
+ }
+ }
+
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_sdio_detect(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ /*
+ * Just check if our card has been removed.
+ */
+ err = mmc_select_card(host->card);
+
+ mmc_release_host(host);
+
+ if (err) {
+ mmc_sdio_remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+}
+
+
+static const struct mmc_bus_ops mmc_sdio_ops = {
+ .remove = mmc_sdio_remove,
+ .detect = mmc_sdio_detect,
+};
+
+
+/*
+ * Starting point for SDIO card init.
+ */
+int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
+{
+ int err;
+ int i, funcs;
+ struct mmc_card *card;
+
+ BUG_ON(!host);
+ WARN_ON(!host->claimed);
+
+ mmc_attach_bus(host, &mmc_sdio_ops);
+
+ /*
+ * Sanity check the voltages that the card claims to
+ * support.
+ */
+ if (ocr & 0x7F) {
+ printk(KERN_WARNING "%s: card claims to support voltages "
+ "below the defined range. These will be ignored.\n",
+ mmc_hostname(host));
+ ocr &= ~0x7F;
+ }
+
+ if (ocr & MMC_VDD_165_195) {
+ printk(KERN_WARNING "%s: SDIO card claims to support the "
+ "incompletely defined 'low voltage range'. This "
+ "will be ignored.\n", mmc_hostname(host));
+ ocr &= ~MMC_VDD_165_195;
+ }
+
+ host->ocr = mmc_select_voltage(host, ocr);
+
+ /*
+ * Can we support the voltage(s) of the card(s)?
+ */
+ if (!host->ocr) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Inform the card of the voltage
+ */
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+
+ /*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
+ * The number of functions on the card is encoded inside
+ * the ocr.
+ */
+ funcs = (ocr & 0x70000000) >> 28;
+
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host);
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
+ goto err;
+ }
+
+ card->type = MMC_TYPE_SDIO;
+ card->sdio_funcs = funcs;
+
+ host->card = card;
+
+ /*
+ * For native busses: set card RCA and quit open drain mode.
+ */
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto remove;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
+
+ /*
+ * Select card, as all following commands rely on that.
+ */
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto remove;
+ }
+
+ /*
+ * Read the common registers.
+ */
+ err = sdio_read_cccr(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Read the common CIS tuples.
+ */
+ err = sdio_read_common_cis(card);
+ if (err)
+ goto remove;
+
+ /*
+ * No support for high-speed yet, so just set
+ * the card's maximum speed.
+ */
+ mmc_set_clock(host, card->cis.max_dtr);
+
+ /*
+ * Switch to wider bus (if supported).
+ */
+ err = sdio_enable_wide(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Initialize (but don't add) all present functions.
+ */
+ for (i = 0;i < funcs;i++) {
+ err = sdio_init_func(host->card, i + 1);
+ if (err)
+ goto remove;
+ }
+
+ mmc_release_host(host);
+
+ /*
+ * First add the card to the driver model...
+ */
+ err = mmc_add_card(host->card);
+ if (err)
+ goto remove_added;
+
+ /*
+ * ...then the SDIO functions.
+ */
+ for (i = 0;i < funcs;i++) {
+ err = sdio_add_func(host->card->sdio_func[i]);
+ if (err)
+ goto remove_added;
+ }
+
+ return 0;
+
+
+remove_added:
+ /* Remove without lock if the device has been added. */
+ mmc_sdio_remove(host);
+ mmc_claim_host(host);
+remove:
+ /* And with lock if it hasn't been added. */
+ if (host->card)
+ mmc_sdio_remove(host);
+err:
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
+ mmc_hostname(host), err);
+
+ return err;
+}
+
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
new file mode 100644
index 000000000000..0713a8c71e54
--- /dev/null
+++ b/drivers/mmc/core/sdio_bus.c
@@ -0,0 +1,270 @@
+/*
+ * linux/drivers/mmc/core/sdio_bus.c
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * SDIO function driver model
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_cis.h"
+#include "sdio_bus.h"
+
+#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
+#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
+
+/* show configuration fields */
+#define sdio_config_attr(field, format_string) \
+static ssize_t \
+field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct sdio_func *func; \
+ \
+ func = dev_to_sdio_func (dev); \
+ return sprintf (buf, format_string, func->field); \
+}
+
+sdio_config_attr(class, "0x%02x\n");
+sdio_config_attr(vendor, "0x%04x\n");
+sdio_config_attr(device, "0x%04x\n");
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sdio_func *func = dev_to_sdio_func (dev);
+
+ return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
+ func->class, func->vendor, func->device);
+}
+
+static struct device_attribute sdio_dev_attrs[] = {
+ __ATTR_RO(class),
+ __ATTR_RO(vendor),
+ __ATTR_RO(device),
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
+ return NULL;
+ if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
+ return NULL;
+ if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
+ return NULL;
+ return id;
+}
+
+static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
+ struct sdio_driver *sdrv)
+{
+ const struct sdio_device_id *ids;
+
+ ids = sdrv->id_table;
+
+ if (ids) {
+ while (ids->class || ids->vendor || ids->device) {
+ if (sdio_match_one(func, ids))
+ return ids;
+ ids++;
+ }
+ }
+
+ return NULL;
+}
+
+static int sdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct sdio_driver *sdrv = to_sdio_driver(drv);
+
+ if (sdio_match_device(func, sdrv))
+ return 1;
+
+ return 0;
+}
+
+static int
+sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
+ int buf_size)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ int i = 0, length = 0;
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buf, buf_size, &length,
+ "SDIO_CLASS=%02X", func->class))
+ return -ENOMEM;
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buf, buf_size, &length,
+ "SDIO_ID=%04X:%04X", func->vendor, func->device))
+ return -ENOMEM;
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buf, buf_size, &length,
+ "MODALIAS=sdio:c%02Xv%04Xd%04X",
+ func->class, func->vendor, func->device))
+ return -ENOMEM;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+static int sdio_bus_probe(struct device *dev)
+{
+ struct sdio_driver *drv = to_sdio_driver(dev->driver);
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ const struct sdio_device_id *id;
+ int ret;
+
+ id = sdio_match_device(func, drv);
+ if (!id)
+ return -ENODEV;
+
+ /* Set the default block size so the driver is sure it's something
+ * sensible. */
+ sdio_claim_host(func);
+ ret = sdio_set_block_size(func, 0);
+ sdio_release_host(func);
+ if (ret)
+ return ret;
+
+ return drv->probe(func, id);
+}
+
+static int sdio_bus_remove(struct device *dev)
+{
+ struct sdio_driver *drv = to_sdio_driver(dev->driver);
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ drv->remove(func);
+
+ if (func->irq_handler) {
+ printk(KERN_WARNING "WARNING: driver %s did not remove "
+ "its interrupt handler!\n", drv->name);
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+ }
+
+ return 0;
+}
+
+static struct bus_type sdio_bus_type = {
+ .name = "sdio",
+ .dev_attrs = sdio_dev_attrs,
+ .match = sdio_bus_match,
+ .uevent = sdio_bus_uevent,
+ .probe = sdio_bus_probe,
+ .remove = sdio_bus_remove,
+};
+
+int sdio_register_bus(void)
+{
+ return bus_register(&sdio_bus_type);
+}
+
+void sdio_unregister_bus(void)
+{
+ bus_unregister(&sdio_bus_type);
+}
+
+/**
+ * sdio_register_driver - register a function driver
+ * @drv: SDIO function driver
+ */
+int sdio_register_driver(struct sdio_driver *drv)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &sdio_bus_type;
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_register_driver);
+
+/**
+ * sdio_unregister_driver - unregister a function driver
+ * @drv: SDIO function driver
+ */
+void sdio_unregister_driver(struct sdio_driver *drv)
+{
+ drv->drv.bus = &sdio_bus_type;
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_unregister_driver);
+
+static void sdio_release_func(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ sdio_free_func_cis(func);
+
+ if (func->info)
+ kfree(func->info);
+
+ kfree(func);
+}
+
+/*
+ * Allocate and initialise a new SDIO function structure.
+ */
+struct sdio_func *sdio_alloc_func(struct mmc_card *card)
+{
+ struct sdio_func *func;
+
+ func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
+ if (!func)
+ return ERR_PTR(-ENOMEM);
+
+ func->card = card;
+
+ device_initialize(&func->dev);
+
+ func->dev.parent = &card->dev;
+ func->dev.bus = &sdio_bus_type;
+ func->dev.release = sdio_release_func;
+
+ return func;
+}
+
+/*
+ * Register a new SDIO function with the driver model.
+ */
+int sdio_add_func(struct sdio_func *func)
+{
+ int ret;
+
+ snprintf(func->dev.bus_id, sizeof(func->dev.bus_id),
+ "%s:%d", mmc_card_id(func->card), func->num);
+
+ ret = device_add(&func->dev);
+ if (ret == 0)
+ sdio_func_set_present(func);
+
+ return ret;
+}
+
+/*
+ * Unregister a SDIO function with the driver model, and
+ * (eventually) free it.
+ */
+void sdio_remove_func(struct sdio_func *func)
+{
+ if (sdio_func_present(func))
+ device_del(&func->dev);
+
+ put_device(&func->dev);
+}
+
diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h
new file mode 100644
index 000000000000..567a76821ba7
--- /dev/null
+++ b/drivers/mmc/core/sdio_bus.h
@@ -0,0 +1,22 @@
+/*
+ * linux/drivers/mmc/core/sdio_bus.h
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+#ifndef _MMC_CORE_SDIO_BUS_H
+#define _MMC_CORE_SDIO_BUS_H
+
+struct sdio_func *sdio_alloc_func(struct mmc_card *card);
+int sdio_add_func(struct sdio_func *func);
+void sdio_remove_func(struct sdio_func *func);
+
+int sdio_register_bus(void);
+void sdio_unregister_bus(void);
+
+#endif
+
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
new file mode 100644
index 000000000000..d5e51b1c7b3f
--- /dev/null
+++ b/drivers/mmc/core/sdio_cis.c
@@ -0,0 +1,346 @@
+/*
+ * linux/drivers/mmc/core/sdio_cis.c
+ *
+ * Author: Nicolas Pitre
+ * Created: June 11, 2007
+ * Copyright: MontaVista Software Inc.
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_cis.h"
+#include "sdio_ops.h"
+
+static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ unsigned i, nr_strings;
+ char **buffer, *string;
+
+ buf += 2;
+ size -= 2;
+
+ nr_strings = 0;
+ for (i = 0; i < size; i++) {
+ if (buf[i] == 0xff)
+ break;
+ if (buf[i] == 0)
+ nr_strings++;
+ }
+
+ if (buf[i-1] != '\0') {
+ printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
+ return 0;
+ }
+
+ size = i;
+
+ buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ string = (char*)(buffer + nr_strings);
+
+ for (i = 0; i < nr_strings; i++) {
+ buffer[i] = string;
+ strcpy(string, buf);
+ string += strlen(string) + 1;
+ buf += strlen(buf) + 1;
+ }
+
+ if (func) {
+ func->num_info = nr_strings;
+ func->info = (const char**)buffer;
+ } else {
+ card->num_info = nr_strings;
+ card->info = (const char**)buffer;
+ }
+
+ return 0;
+}
+
+static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ unsigned int vendor, device;
+
+ /* TPLMID_MANF */
+ vendor = buf[0] | (buf[1] << 8);
+
+ /* TPLMID_CARD */
+ device = buf[2] | (buf[3] << 8);
+
+ if (func) {
+ func->vendor = vendor;
+ func->device = device;
+ } else {
+ card->cis.vendor = vendor;
+ card->cis.device = device;
+ }
+
+ return 0;
+}
+
+static const unsigned char speed_val[16] =
+ { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
+static const unsigned int speed_unit[8] =
+ { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
+
+static int cistpl_funce_common(struct mmc_card *card,
+ const unsigned char *buf, unsigned size)
+{
+ if (size < 0x04 || buf[0] != 0)
+ return -EINVAL;
+
+ /* TPLFE_FN0_BLK_SIZE */
+ card->cis.blksize = buf[1] | (buf[2] << 8);
+
+ /* TPLFE_MAX_TRAN_SPEED */
+ card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
+ speed_unit[buf[3] & 7];
+
+ return 0;
+}
+
+static int cistpl_funce_func(struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ unsigned vsn;
+ unsigned min_size;
+
+ vsn = func->card->cccr.sdio_vsn;
+ min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
+
+ if (size < min_size || buf[0] != 1)
+ return -EINVAL;
+
+ /* TPLFE_MAX_BLK_SIZE */
+ func->max_blksize = buf[12] | (buf[13] << 8);
+
+ return 0;
+}
+
+static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ int ret;
+
+ /*
+ * There should be two versions of the CISTPL_FUNCE tuple,
+ * one for the common CIS (function 0) and a version used by
+ * the individual function's CIS (1-7). Yet, the later has a
+ * different length depending on the SDIO spec version.
+ */
+ if (func)
+ ret = cistpl_funce_func(func, buf, size);
+ else
+ ret = cistpl_funce_common(card, buf, size);
+
+ if (ret) {
+ printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
+ "type %u\n", mmc_hostname(card->host), size, buf[0]);
+ return ret;
+ }
+
+ return 0;
+}
+
+typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
+ const unsigned char *, unsigned);
+
+struct cis_tpl {
+ unsigned char code;
+ unsigned char min_size;
+ tpl_parse_t *parse;
+};
+
+static const struct cis_tpl cis_tpl_list[] = {
+ { 0x15, 3, cistpl_vers_1 },
+ { 0x20, 4, cistpl_manfid },
+ { 0x21, 2, /* cistpl_funcid */ },
+ { 0x22, 0, cistpl_funce },
+};
+
+static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+{
+ int ret;
+ struct sdio_func_tuple *this, **prev;
+ unsigned i, ptr = 0;
+
+ /*
+ * Note that this works for the common CIS (function number 0) as
+ * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
+ * have the same offset.
+ */
+ for (i = 0; i < 3; i++) {
+ unsigned char x, fn;
+
+ if (func)
+ fn = func->num;
+ else
+ fn = 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0,
+ SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
+ if (ret)
+ return ret;
+ ptr |= x << (i * 8);
+ }
+
+ if (func)
+ prev = &func->tuples;
+ else
+ prev = &card->tuples;
+
+ BUG_ON(*prev);
+
+ do {
+ unsigned char tpl_code, tpl_link;
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
+ if (ret)
+ break;
+
+ /* 0xff means we're done */
+ if (tpl_code == 0xff)
+ break;
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
+ if (ret)
+ break;
+
+ this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
+ if (!this)
+ return -ENOMEM;
+
+ for (i = 0; i < tpl_link; i++) {
+ ret = mmc_io_rw_direct(card, 0, 0,
+ ptr + i, 0, &this->data[i]);
+ if (ret)
+ break;
+ }
+ if (ret) {
+ kfree(this);
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
+ if (cis_tpl_list[i].code == tpl_code)
+ break;
+ if (i >= ARRAY_SIZE(cis_tpl_list)) {
+ /* this tuple is unknown to the core */
+ this->next = NULL;
+ this->code = tpl_code;
+ this->size = tpl_link;
+ *prev = this;
+ prev = &this->next;
+ printk(KERN_DEBUG
+ "%s: queuing CIS tuple 0x%02x length %u\n",
+ mmc_hostname(card->host), tpl_code, tpl_link);
+ } else {
+ const struct cis_tpl *tpl = cis_tpl_list + i;
+ if (tpl_link < tpl->min_size) {
+ printk(KERN_ERR
+ "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
+ mmc_hostname(card->host),
+ tpl_code, tpl_link, tpl->min_size);
+ ret = -EINVAL;
+ } else if (tpl->parse) {
+ ret = tpl->parse(card, func,
+ this->data, tpl_link);
+ }
+ kfree(this);
+ }
+
+ ptr += tpl_link;
+ } while (!ret);
+
+ /*
+ * Link in all unknown tuples found in the common CIS so that
+ * drivers don't have to go digging in two places.
+ */
+ if (func)
+ *prev = card->tuples;
+
+ return ret;
+}
+
+int sdio_read_common_cis(struct mmc_card *card)
+{
+ return sdio_read_cis(card, NULL);
+}
+
+void sdio_free_common_cis(struct mmc_card *card)
+{
+ struct sdio_func_tuple *tuple, *victim;
+
+ tuple = card->tuples;
+
+ while (tuple) {
+ victim = tuple;
+ tuple = tuple->next;
+ kfree(victim);
+ }
+
+ card->tuples = NULL;
+}
+
+int sdio_read_func_cis(struct sdio_func *func)
+{
+ int ret;
+
+ ret = sdio_read_cis(func->card, func);
+ if (ret)
+ return ret;
+
+ /*
+ * Since we've linked to tuples in the card structure,
+ * we must make sure we have a reference to it.
+ */
+ get_device(&func->card->dev);
+
+ /*
+ * Vendor/device id is optional for function CIS, so
+ * copy it from the card structure as needed.
+ */
+ if (func->vendor == 0) {
+ func->vendor = func->card->cis.vendor;
+ func->device = func->card->cis.device;
+ }
+
+ return 0;
+}
+
+void sdio_free_func_cis(struct sdio_func *func)
+{
+ struct sdio_func_tuple *tuple, *victim;
+
+ tuple = func->tuples;
+
+ while (tuple && tuple != func->card->tuples) {
+ victim = tuple;
+ tuple = tuple->next;
+ kfree(victim);
+ }
+
+ func->tuples = NULL;
+
+ /*
+ * We have now removed the link to the tuples in the
+ * card structure, so remove the reference.
+ */
+ put_device(&func->card->dev);
+}
+
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
new file mode 100644
index 000000000000..4d903c2e425e
--- /dev/null
+++ b/drivers/mmc/core/sdio_cis.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/mmc/core/sdio_cis.h
+ *
+ * Author: Nicolas Pitre
+ * Created: June 11, 2007
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _MMC_SDIO_CIS_H
+#define _MMC_SDIO_CIS_H
+
+int sdio_read_common_cis(struct mmc_card *card);
+void sdio_free_common_cis(struct mmc_card *card);
+
+int sdio_read_func_cis(struct sdio_func *func);
+void sdio_free_func_cis(struct sdio_func *func);
+
+#endif
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
new file mode 100644
index 000000000000..625b92ce9cef
--- /dev/null
+++ b/drivers/mmc/core/sdio_io.c
@@ -0,0 +1,548 @@
+/*
+ * linux/drivers/mmc/core/sdio_io.c
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_ops.h"
+
+/**
+ * sdio_claim_host - exclusively claim a bus for a certain SDIO function
+ * @func: SDIO function that will be accessed
+ *
+ * Claim a bus for a set of operations. The SDIO function given
+ * is used to figure out which bus is relevant.
+ */
+void sdio_claim_host(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ mmc_claim_host(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_claim_host);
+
+/**
+ * sdio_release_host - release a bus for a certain SDIO function
+ * @func: SDIO function that was accessed
+ *
+ * Release a bus, allowing others to claim the bus for their
+ * operations.
+ */
+void sdio_release_host(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ mmc_release_host(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_release_host);
+
+/**
+ * sdio_enable_func - enables a SDIO function for usage
+ * @func: SDIO function to enable
+ *
+ * Powers up and activates a SDIO function so that register
+ * access is possible.
+ */
+int sdio_enable_func(struct sdio_func *func)
+{
+ int ret;
+ unsigned char reg;
+ unsigned long timeout;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
+ if (ret)
+ goto err;
+
+ reg |= 1 << func->num;
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
+ if (ret)
+ goto err;
+
+ /*
+ * FIXME: This should timeout based on information in the CIS,
+ * but we don't have card to parse that yet.
+ */
+ timeout = jiffies + HZ;
+
+ while (1) {
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, &reg);
+ if (ret)
+ goto err;
+ if (reg & (1 << func->num))
+ break;
+ ret = -ETIME;
+ if (time_after(jiffies, timeout))
+ goto err;
+ }
+
+ pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func));
+
+ return 0;
+
+err:
+ pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func));
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_enable_func);
+
+/**
+ * sdio_disable_func - disable a SDIO function
+ * @func: SDIO function to disable
+ *
+ * Powers down and deactivates a SDIO function. Register access
+ * to this function will fail until the function is reenabled.
+ */
+int sdio_disable_func(struct sdio_func *func)
+{
+ int ret;
+ unsigned char reg;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func));
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
+ if (ret)
+ goto err;
+
+ reg &= ~(1 << func->num);
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
+ if (ret)
+ goto err;
+
+ pr_debug("SDIO: Disabled device %s\n", sdio_func_id(func));
+
+ return 0;
+
+err:
+ pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
+ return -EIO;
+}
+EXPORT_SYMBOL_GPL(sdio_disable_func);
+
+/**
+ * sdio_set_block_size - set the block size of an SDIO function
+ * @func: SDIO function to change
+ * @blksz: new block size or 0 to use the default.
+ *
+ * The default block size is the largest supported by both the function
+ * and the host, with a maximum of 512 to ensure that arbitrarily sized
+ * data transfer use the optimal (least) number of commands.
+ *
+ * A driver may call this to override the default block size set by the
+ * core. This can be used to set a block size greater than the maximum
+ * that reported by the card; it is the driver's responsibility to ensure
+ * it uses a value that the card supports.
+ *
+ * Returns 0 on success, -EINVAL if the host does not support the
+ * requested block size, or -EIO (etc.) if one of the resultant FBR block
+ * size register writes failed.
+ *
+ */
+int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
+{
+ int ret;
+
+ if (blksz > func->card->host->max_blk_size)
+ return -EINVAL;
+
+ if (blksz == 0) {
+ blksz = min(min(
+ func->max_blksize,
+ func->card->host->max_blk_size),
+ 512u);
+ }
+
+ ret = mmc_io_rw_direct(func->card, 1, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE,
+ blksz & 0xff, NULL);
+ if (ret)
+ return ret;
+ ret = mmc_io_rw_direct(func->card, 1, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1,
+ (blksz >> 8) & 0xff, NULL);
+ if (ret)
+ return ret;
+ func->cur_blksize = blksz;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(sdio_set_block_size);
+
+/* Split an arbitrarily sized data transfer into several
+ * IO_RW_EXTENDED commands. */
+static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
+ unsigned addr, int incr_addr, u8 *buf, unsigned size)
+{
+ unsigned remainder = size;
+ unsigned max_blocks;
+ int ret;
+
+ /* Do the bulk of the transfer using block mode (if supported). */
+ if (func->card->cccr.multi_block) {
+ /* Blocks per command is limited by host count, host transfer
+ * size (we only use a single sg entry) and the maximum for
+ * IO_RW_EXTENDED of 511 blocks. */
+ max_blocks = min(min(
+ func->card->host->max_blk_count,
+ func->card->host->max_seg_size / func->cur_blksize),
+ 511u);
+
+ while (remainder > func->cur_blksize) {
+ unsigned blocks;
+
+ blocks = remainder / func->cur_blksize;
+ if (blocks > max_blocks)
+ blocks = max_blocks;
+ size = blocks * func->cur_blksize;
+
+ ret = mmc_io_rw_extended(func->card, write,
+ func->num, addr, incr_addr, buf,
+ blocks, func->cur_blksize);
+ if (ret)
+ return ret;
+
+ remainder -= size;
+ buf += size;
+ if (incr_addr)
+ addr += size;
+ }
+ }
+
+ /* Write the remainder using byte mode. */
+ while (remainder > 0) {
+ size = remainder;
+ if (size > func->cur_blksize)
+ size = func->cur_blksize;
+ if (size > 512)
+ size = 512; /* maximum size for byte mode */
+
+ ret = mmc_io_rw_extended(func->card, write, func->num, addr,
+ incr_addr, buf, 1, size);
+ if (ret)
+ return ret;
+
+ remainder -= size;
+ buf += size;
+ if (incr_addr)
+ addr += size;
+ }
+ return 0;
+}
+
+/**
+ * sdio_readb - read a single byte from a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a single byte from the address space of a given SDIO
+ * function. If there is a problem reading the address, 0xff
+ * is returned and @err_ret will contain the error code.
+ */
+unsigned char sdio_readb(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+ unsigned char val;
+
+ BUG_ON(!func);
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFF;
+ }
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(sdio_readb);
+
+/**
+ * sdio_writeb - write a single byte to a SDIO function
+ * @func: SDIO function to access
+ * @b: byte to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a single byte to the address space of a given SDIO
+ * function. @err_ret will contain the status of the actual
+ * transfer.
+ */
+void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ BUG_ON(!func);
+
+ ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writeb);
+
+/**
+ * sdio_memcpy_fromio - read a chunk of memory from a SDIO function
+ * @func: SDIO function to access
+ * @dst: buffer to store the data
+ * @addr: address to begin reading from
+ * @count: number of bytes to read
+ *
+ * Reads from the address space of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
+ unsigned int addr, int count)
+{
+ return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_fromio);
+
+/**
+ * sdio_memcpy_toio - write a chunk of memory to a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to start writing to
+ * @src: buffer that contains the data to write
+ * @count: number of bytes to write
+ *
+ * Writes to the address space of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
+ void *src, int count)
+{
+ return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_toio);
+
+/**
+ * sdio_readsb - read from a FIFO on a SDIO function
+ * @func: SDIO function to access
+ * @dst: buffer to store the data
+ * @addr: address of (single byte) FIFO
+ * @count: number of bytes to read
+ *
+ * Reads from the specified FIFO of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
+ int count)
+{
+ return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
+}
+
+EXPORT_SYMBOL_GPL(sdio_readsb);
+
+/**
+ * sdio_writesb - write to a FIFO of a SDIO function
+ * @func: SDIO function to access
+ * @addr: address of (single byte) FIFO
+ * @src: buffer that contains the data to write
+ * @count: number of bytes to write
+ *
+ * Writes to the specified FIFO of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src,
+ int count)
+{
+ return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count);
+}
+EXPORT_SYMBOL_GPL(sdio_writesb);
+
+/**
+ * sdio_readw - read a 16 bit integer from a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a 16 bit integer from the address space of a given SDIO
+ * function. If there is a problem reading the address, 0xffff
+ * is returned and @err_ret will contain the error code.
+ */
+unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFFFF;
+ }
+
+ return le16_to_cpu(*(u16*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readw);
+
+/**
+ * sdio_writew - write a 16 bit integer to a SDIO function
+ * @func: SDIO function to access
+ * @b: integer to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a 16 bit integer to the address space of a given SDIO
+ * function. @err_ret will contain the status of the actual
+ * transfer.
+ */
+void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ *(u16*)func->tmpbuf = cpu_to_le16(b);
+
+ ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writew);
+
+/**
+ * sdio_readl - read a 32 bit integer from a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a 32 bit integer from the address space of a given SDIO
+ * function. If there is a problem reading the address,
+ * 0xffffffff is returned and @err_ret will contain the error
+ * code.
+ */
+unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFFFFFFFF;
+ }
+
+ return le32_to_cpu(*(u32*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readl);
+
+/**
+ * sdio_writel - write a 32 bit integer to a SDIO function
+ * @func: SDIO function to access
+ * @b: integer to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a 32 bit integer to the address space of a given SDIO
+ * function. @err_ret will contain the status of the actual
+ * transfer.
+ */
+void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ *(u32*)func->tmpbuf = cpu_to_le32(b);
+
+ ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writel);
+
+/**
+ * sdio_f0_readb - read a single byte from SDIO function 0
+ * @func: an SDIO function of the card
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a single byte from the address space of SDIO function 0.
+ * If there is a problem reading the address, 0xff is returned
+ * and @err_ret will contain the error code.
+ */
+unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+ unsigned char val;
+
+ BUG_ON(!func);
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFF;
+ }
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(sdio_f0_readb);
+
+/**
+ * sdio_f0_writeb - write a single byte to SDIO function 0
+ * @func: an SDIO function of the card
+ * @b: byte to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a single byte to the address space of SDIO function 0.
+ * @err_ret will contain the status of the actual transfer.
+ *
+ * Only writes to the vendor specific CCCR registers (0xF0 -
+ * 0xFF) are permiited; @err_ret will be set to -EINVAL for *
+ * writes outside this range.
+ */
+void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ BUG_ON(!func);
+
+ if (addr < 0xF0 || addr > 0xFF) {
+ if (err_ret)
+ *err_ret = -EINVAL;
+ return;
+ }
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_f0_writeb);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
new file mode 100644
index 000000000000..3bd3021f5e80
--- /dev/null
+++ b/drivers/mmc/core/sdio_irq.c
@@ -0,0 +1,267 @@
+/*
+ * linux/drivers/mmc/core/sdio_irq.c
+ *
+ * Author: Nicolas Pitre
+ * Created: June 18, 2007
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_ops.h"
+
+static int process_sdio_pending_irqs(struct mmc_card *card)
+{
+ int i, ret, count;
+ unsigned char pending;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
+ if (ret) {
+ printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n",
+ mmc_card_id(card), ret);
+ return ret;
+ }
+
+ count = 0;
+ for (i = 1; i <= 7; i++) {
+ if (pending & (1 << i)) {
+ struct sdio_func *func = card->sdio_func[i - 1];
+ if (!func) {
+ printk(KERN_WARNING "%s: pending IRQ for "
+ "non-existant function\n",
+ mmc_card_id(card));
+ ret = -EINVAL;
+ } else if (func->irq_handler) {
+ func->irq_handler(func);
+ count++;
+ } else {
+ printk(KERN_WARNING "%s: pending IRQ with no handler\n",
+ sdio_func_id(func));
+ ret = -EINVAL;
+ }
+ }
+ }
+
+ if (count)
+ return count;
+
+ return ret;
+}
+
+static int sdio_irq_thread(void *_host)
+{
+ struct mmc_host *host = _host;
+ struct sched_param param = { .sched_priority = 1 };
+ unsigned long period, idle_period;
+ int ret;
+
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ /*
+ * We want to allow for SDIO cards to work even on non SDIO
+ * aware hosts. One thing that non SDIO host cannot do is
+ * asynchronous notification of pending SDIO card interrupts
+ * hence we poll for them in that case.
+ */
+ idle_period = msecs_to_jiffies(10);
+ period = (host->caps & MMC_CAP_SDIO_IRQ) ?
+ MAX_SCHEDULE_TIMEOUT : idle_period;
+
+ pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
+ mmc_hostname(host), period);
+
+ do {
+ /*
+ * We claim the host here on drivers behalf for a couple
+ * reasons:
+ *
+ * 1) it is already needed to retrieve the CCCR_INTx;
+ * 2) we want the driver(s) to clear the IRQ condition ASAP;
+ * 3) we need to control the abort condition locally.
+ *
+ * Just like traditional hard IRQ handlers, we expect SDIO
+ * IRQ handlers to be quick and to the point, so that the
+ * holding of the host lock does not cover too much work
+ * that doesn't require that lock to be held.
+ */
+ ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
+ if (ret)
+ break;
+ ret = process_sdio_pending_irqs(host->card);
+ mmc_release_host(host);
+
+ /*
+ * Give other threads a chance to run in the presence of
+ * errors. FIXME: determine if due to card removal and
+ * possibly exit this thread if so.
+ */
+ if (ret < 0)
+ ssleep(1);
+
+ /*
+ * Adaptive polling frequency based on the assumption
+ * that an interrupt will be closely followed by more.
+ * This has a substantial benefit for network devices.
+ */
+ if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
+ if (ret > 0)
+ period /= 2;
+ else {
+ period++;
+ if (period > idle_period)
+ period = idle_period;
+ }
+ }
+
+ set_task_state(current, TASK_INTERRUPTIBLE);
+ if (host->caps & MMC_CAP_SDIO_IRQ)
+ host->ops->enable_sdio_irq(host, 1);
+ if (!kthread_should_stop())
+ schedule_timeout(period);
+ set_task_state(current, TASK_RUNNING);
+ } while (!kthread_should_stop());
+
+ if (host->caps & MMC_CAP_SDIO_IRQ)
+ host->ops->enable_sdio_irq(host, 0);
+
+ pr_debug("%s: IRQ thread exiting with code %d\n",
+ mmc_hostname(host), ret);
+
+ return ret;
+}
+
+static int sdio_card_irq_get(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+
+ WARN_ON(!host->claimed);
+
+ if (!host->sdio_irqs++) {
+ atomic_set(&host->sdio_irq_thread_abort, 0);
+ host->sdio_irq_thread =
+ kthread_run(sdio_irq_thread, host, "ksdiorqd");
+ if (IS_ERR(host->sdio_irq_thread)) {
+ int err = PTR_ERR(host->sdio_irq_thread);
+ host->sdio_irqs--;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int sdio_card_irq_put(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+
+ WARN_ON(!host->claimed);
+ BUG_ON(host->sdio_irqs < 1);
+
+ if (!--host->sdio_irqs) {
+ atomic_set(&host->sdio_irq_thread_abort, 1);
+ kthread_stop(host->sdio_irq_thread);
+ }
+
+ return 0;
+}
+
+/**
+ * sdio_claim_irq - claim the IRQ for a SDIO function
+ * @func: SDIO function
+ * @handler: IRQ handler callback
+ *
+ * Claim and activate the IRQ for the given SDIO function. The provided
+ * handler will be called when that IRQ is asserted. The host is always
+ * claimed already when the handler is called so the handler must not
+ * call sdio_claim_host() nor sdio_release_host().
+ */
+int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
+{
+ int ret;
+ unsigned char reg;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
+
+ if (func->irq_handler) {
+ pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
+ return -EBUSY;
+ }
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
+ if (ret)
+ return ret;
+
+ reg |= 1 << func->num;
+
+ reg |= 1; /* Master interrupt enable */
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
+ if (ret)
+ return ret;
+
+ func->irq_handler = handler;
+ ret = sdio_card_irq_get(func->card);
+ if (ret)
+ func->irq_handler = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_claim_irq);
+
+/**
+ * sdio_release_irq - release the IRQ for a SDIO function
+ * @func: SDIO function
+ *
+ * Disable and release the IRQ for the given SDIO function.
+ */
+int sdio_release_irq(struct sdio_func *func)
+{
+ int ret;
+ unsigned char reg;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
+
+ if (func->irq_handler) {
+ func->irq_handler = NULL;
+ sdio_card_irq_put(func->card);
+ }
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~(1 << func->num);
+
+ /* Disable master interrupt with the last function interrupt */
+ if (!(reg & 0xFE))
+ reg = 0;
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdio_release_irq);
+
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
new file mode 100644
index 000000000000..4d289b275031
--- /dev/null
+++ b/drivers/mmc/core/sdio_ops.c
@@ -0,0 +1,176 @@
+/*
+ * linux/drivers/mmc/sdio_ops.c
+ *
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+
+#include "core.h"
+
+int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ BUG_ON(!host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_IO_SEND_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ break;
+
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
+ break;
+
+ /* otherwise wait until reset completes */
+ if (mmc_host_is_spi(host)) {
+ /*
+ * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
+ * an initialized card under SPI, but some cards
+ * (Marvell's) only behave when looking at this
+ * one.
+ */
+ if (cmd.resp[1] & MMC_CARD_BUSY)
+ break;
+ } else {
+ if (cmd.resp[0] & MMC_CARD_BUSY)
+ break;
+ }
+
+ err = -ETIMEDOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
+
+ return err;
+}
+
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8* out)
+{
+ struct mmc_command cmd;
+ int err;
+
+ BUG_ON(!card);
+ BUG_ON(fn > 7);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_IO_RW_DIRECT;
+ cmd.arg = write ? 0x80000000 : 0x00000000;
+ cmd.arg |= fn << 28;
+ cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+ cmd.arg |= addr << 9;
+ cmd.arg |= in;
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err)
+ return err;
+
+ if (mmc_host_is_spi(card->host)) {
+ /* host driver already reported errors */
+ } else {
+ if (cmd.resp[0] & R5_ERROR)
+ return -EIO;
+ if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ return -EINVAL;
+ if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ return -ERANGE;
+ }
+
+ if (out) {
+ if (mmc_host_is_spi(card->host))
+ *out = (cmd.resp[0] >> 8) & 0xFF;
+ else
+ *out = cmd.resp[0] & 0xFF;
+ }
+
+ return 0;
+}
+
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+
+ BUG_ON(!card);
+ BUG_ON(fn > 7);
+ BUG_ON(blocks == 1 && blksz > 512);
+ WARN_ON(blocks == 0);
+ WARN_ON(blksz == 0);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = SD_IO_RW_EXTENDED;
+ cmd.arg = write ? 0x80000000 : 0x00000000;
+ cmd.arg |= fn << 28;
+ cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
+ cmd.arg |= addr << 9;
+ if (blocks == 1 && blksz <= 512)
+ cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
+ else
+ cmd.arg |= 0x08000000 | blocks; /* block mode */
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ data.blksz = blksz;
+ data.blocks = blocks;
+ data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, buf, blksz * blocks);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ if (mmc_host_is_spi(card->host)) {
+ /* host driver already reported errors */
+ } else {
+ if (cmd.resp[0] & R5_ERROR)
+ return -EIO;
+ if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ return -EINVAL;
+ if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
new file mode 100644
index 000000000000..e2e74b0d17d8
--- /dev/null
+++ b/drivers/mmc/core/sdio_ops.h
@@ -0,0 +1,22 @@
+/*
+ * linux/drivers/mmc/sdio_ops.c
+ *
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _MMC_SDIO_OPS_H
+#define _MMC_SDIO_OPS_H
+
+int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8* out);
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+
+#endif
+
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index e23082fe88d0..5fef6783c716 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -35,6 +35,23 @@ config MMC_SDHCI
If unsure, say N.
+config MMC_RICOH_MMC
+ tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL && MMC_SDHCI
+ help
+ This selects the disabler for the Ricoh MMC Controller. This
+ proprietary controller is unnecessary because the SDHCI driver
+ supports MMC cards on the SD controller, but if it is not
+ disabled, it will steal the MMC cards away - rendering them
+ useless. It is safe to select this driver even if you don't
+ have a Ricoh based card reader.
+
+
+ To compile this driver as a module, choose M here:
+ the module will be called ricoh_mmc.
+
+ If unsure, say Y.
+
config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support"
depends on ARCH_OMAP
@@ -100,3 +117,16 @@ config MMC_TIFM_SD
To compile this driver as a module, choose M here: the
module will be called tifm_sd.
+config MMC_SPI
+ tristate "MMC/SD over SPI (EXPERIMENTAL)"
+ depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL
+ select CRC7
+ select CRC_ITU_T
+ help
+ Some systems accss MMC/SD cards using a SPI controller instead of
+ using a "native" MMC/SD controller. This has a disadvantage of
+ being relatively high overhead, but a compensating advantage of
+ working on many systems without dedicated MMC/SD controllers.
+
+ If unsure, or if your system has no SPI master driver, say N.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 6685f64345b4..3877c87e6da2 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -10,9 +10,11 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
+obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
+obj-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 28c881895ab7..6ba98a49612d 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
+ * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
*
* Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
*
@@ -83,7 +83,7 @@
#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \
- | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
+ | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
@@ -328,7 +328,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
data = cmd->data;
if (!data) return;
- if (cmd->data->flags & MMC_DATA_MULTI) {
+ if (cmd->data->blocks > 1) {
pr_debug("multiple write : wait for BLKE...\n");
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
} else
@@ -428,6 +428,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
}
if (data) {
+
+ if ( data->blksz & 0x3 ) {
+ pr_debug("Unsupported block size\n");
+ cmd->error = -EINVAL;
+ mmc_request_done(host->mmc, host->request);
+ return;
+ }
+
block_length = data->blksz;
blocks = data->blocks;
@@ -439,7 +447,7 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
if (data->flags & MMC_DATA_STREAM)
cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->flags & MMC_DATA_MULTI)
+ if (data->blocks > 1)
cmdr |= AT91_MCI_TRTYP_MULTIPLE;
}
else {
@@ -577,24 +585,22 @@ static void at91_mci_completed_command(struct at91mci_host *host)
AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
}
else {
if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
- cmd->error = MMC_ERR_BADCRC;
- else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
- cmd->error = MMC_ERR_FIFO;
+ cmd->error = -EILSEQ;
else
- cmd->error = MMC_ERR_FAILED;
+ cmd->error = -EIO;
pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
cmd->error, cmd->opcode, cmd->retries);
}
}
else
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
at91_mci_process_next(host);
}
@@ -676,15 +682,15 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
int_status = at91_mci_read(host, AT91_MCI_SR);
int_mask = at91_mci_read(host, AT91_MCI_IMR);
-
+
pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
int_status & int_mask);
-
+
int_status = int_status & int_mask;
if (int_status & AT91_MCI_ERRORS) {
completed = 1;
-
+
if (int_status & AT91_MCI_UNRE)
pr_debug("MMC: Underrun error\n");
if (int_status & AT91_MCI_OVRE)
@@ -836,7 +842,6 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->f_min = 375000;
mmc->f_max = 25000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_BYTEBLOCK;
mmc->max_blk_size = 4095;
mmc->max_blk_count = mmc->max_req_size;
@@ -903,8 +908,10 @@ static int __init at91_mci_probe(struct platform_device *pdev)
/*
* Add host to MMC layer
*/
- if (host->board->det_pin)
+ if (host->board->det_pin) {
host->present = !at91_get_gpio_value(host->board->det_pin);
+ device_init_wakeup(&pdev->dev, 1);
+ }
else
host->present = -1;
@@ -939,7 +946,8 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
host = mmc_priv(mmc);
- if (host->present != -1) {
+ if (host->board->det_pin) {
+ device_init_wakeup(&pdev->dev, 0);
free_irq(host->board->det_pin, host);
cancel_delayed_work(&host->mmc->detect);
}
@@ -966,8 +974,12 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct at91mci_host *host = mmc_priv(mmc);
int ret = 0;
+ if (host->board->det_pin && device_may_wakeup(&pdev->dev))
+ enable_irq_wake(host->board->det_pin);
+
if (mmc)
ret = mmc_suspend_host(mmc, state);
@@ -977,8 +989,12 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
static int at91_mci_resume(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct at91mci_host *host = mmc_priv(mmc);
int ret = 0;
+ if (host->board->det_pin && device_may_wakeup(&pdev->dev))
+ disable_irq_wake(host->board->det_pin);
+
if (mmc)
ret = mmc_resume_host(mmc);
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 52b63f11ddd6..92c4d0dfee43 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
+ * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
*
* Copyright (c) 2005, Advanced Micro Devices, Inc.
*
@@ -186,7 +186,7 @@ static void au1xmmc_tasklet_finish(unsigned long param)
}
static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
- struct mmc_command *cmd, unsigned int flags)
+ struct mmc_command *cmd, struct mmc_data *data)
{
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
@@ -208,19 +208,21 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
default:
printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
mmc_resp_type(cmd));
- return MMC_ERR_INVALID;
+ return -EINVAL;
}
- if (flags & MMC_DATA_READ) {
- if (flags & MMC_DATA_MULTI)
- mmccmd |= SD_CMD_CT_4;
- else
- mmccmd |= SD_CMD_CT_2;
- } else if (flags & MMC_DATA_WRITE) {
- if (flags & MMC_DATA_MULTI)
- mmccmd |= SD_CMD_CT_3;
- else
- mmccmd |= SD_CMD_CT_1;
+ if (data) {
+ if (flags & MMC_DATA_READ) {
+ if (data->blocks > 1)
+ mmccmd |= SD_CMD_CT_4;
+ else
+ mmccmd |= SD_CMD_CT_2;
+ } else if (flags & MMC_DATA_WRITE) {
+ if (data->blocks > 1)
+ mmccmd |= SD_CMD_CT_3;
+ else
+ mmccmd |= SD_CMD_CT_1;
+ }
}
au_writel(cmd->arg, HOST_CMDARG(host));
@@ -253,7 +255,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
IRQ_ON(host, SD_CONFIG_CR);
}
- return MMC_ERR_NONE;
+ return 0;
}
static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
@@ -278,7 +280,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
status = au_readl(HOST_STATUS(host));
- data->error = MMC_ERR_NONE;
+ data->error = 0;
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
/* Process any errors */
@@ -288,14 +290,14 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
crc |= ((status & 0x07) == 0x02) ? 0 : 1;
if (crc)
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
/* Clear the CRC bits */
au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
data->bytes_xfered = 0;
- if (data->error == MMC_ERR_NONE) {
+ if (!data->error) {
if (host->flags & HOST_F_DMA) {
u32 chan = DMA_CHANNEL(host);
@@ -475,7 +477,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
return;
cmd = mrq->cmd;
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
@@ -512,11 +514,11 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
/* Figure out errors */
if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
- if (!trans || cmd->error != MMC_ERR_NONE) {
+ if (!trans || cmd->error) {
IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
tasklet_schedule(&host->finish_task);
@@ -589,7 +591,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
data->sg_len, host->dma.dir);
if (host->dma.len == 0)
- return MMC_ERR_TIMEOUT;
+ return -ETIMEDOUT;
au_writel(data->blksz - 1, HOST_BLKSIZE(host));
@@ -640,11 +642,11 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
//IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
}
- return MMC_ERR_NONE;
+ return 0;
dataerr:
dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
- return MMC_ERR_TIMEOUT;
+ return -ETIMEDOUT;
}
/* static void au1xmmc_request
@@ -656,7 +658,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
struct au1xmmc_host *host = mmc_priv(mmc);
unsigned int flags = 0;
- int ret = MMC_ERR_NONE;
+ int ret = 0;
WARN_ON(irqs_disabled());
WARN_ON(host->status != HOST_S_IDLE);
@@ -672,10 +674,10 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
ret = au1xmmc_prepare_data(host, mrq->data);
}
- if (ret == MMC_ERR_NONE)
- ret = au1xmmc_send_command(host, 0, mrq->cmd, flags);
+ if (!ret)
+ ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data);
- if (ret != MMC_ERR_NONE) {
+ if (ret) {
mrq->cmd->error = ret;
au1xmmc_finish_request(host);
}
@@ -764,10 +766,10 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
if (host->mrq && (status & STATUS_TIMEOUT)) {
if (status & SD_STATUS_RAT)
- host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+ host->mrq->cmd->error = -ETIMEDOUT;
else if (status & SD_STATUS_DT)
- host->mrq->data->error = MMC_ERR_TIMEOUT;
+ host->mrq->data->error = -ETIMEDOUT;
/* In PIO mode, interrupts might still be enabled */
IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index 7ee2045acbef..6ebc41e7592c 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
+ * linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver
*
* Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
* Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
@@ -428,11 +428,11 @@ static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
if ( stat & STATUS_ERR_MASK ) {
dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
else if(stat & STATUS_TIME_OUT_READ)
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
else
- data->error = MMC_ERR_FAILED;
+ data->error = -EIO;
} else {
data->bytes_xfered = host->dma_size;
}
@@ -458,10 +458,10 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
if (stat & STATUS_TIME_OUT_RESP) {
dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
} else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
}
if(cmd->flags & MMC_RSP_PRESENT) {
@@ -482,7 +482,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
- if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+ if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) {
if (host->req->data->flags & MMC_DATA_WRITE) {
/* Wait for FIFO to be empty before starting DMA write */
@@ -491,7 +491,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
if(imxmci_busy_wait_for_status(host, &stat,
STATUS_APPL_BUFF_FE,
40, "imxmci_cmd_done DMA WR") < 0) {
- cmd->error = MMC_ERR_FIFO;
+ cmd->error = -EIO;
imxmci_finish_data(host, stat);
if(host->req)
imxmci_finish_request(host, host->req);
@@ -884,9 +884,21 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+static int imxmci_get_ro(struct mmc_host *mmc)
+{
+ struct imxmci_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc_dev(mmc));
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
+
static const struct mmc_host_ops imxmci_ops = {
.request = imxmci_request,
.set_ios = imxmci_set_ios,
+ .get_ro = imxmci_get_ro,
};
static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
@@ -913,7 +925,7 @@ static void imxmci_check_status(unsigned long data)
{
struct imxmci_host *host = (struct imxmci_host *)data;
- if( host->pdata->card_present() != host->present ) {
+ if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) {
host->present ^= 1;
dev_info(mmc_dev(host->mmc), "card %s\n",
host->present ? "inserted" : "removed");
@@ -963,7 +975,7 @@ static int imxmci_probe(struct platform_device *pdev)
mmc->f_min = 150000;
mmc->f_max = CLK_RATE/2;
mmc->ocr_avail = MMC_VDD_32_33;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
@@ -1022,7 +1034,7 @@ static int imxmci_probe(struct platform_device *pdev)
if (ret)
goto out;
- host->present = host->pdata->card_present();
+ host->present = host->pdata->card_present(mmc_dev(mmc));
init_timer(&host->timer);
host->timer.data = (unsigned long)host;
host->timer.function = imxmci_check_status;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
new file mode 100644
index 000000000000..f30327bba6f6
--- /dev/null
+++ b/drivers/mmc/host/mmc_spi.c
@@ -0,0 +1,1408 @@
+/*
+ * mmc_spi.c - Access SD/MMC cards through SPI master controllers
+ *
+ * (C) Copyright 2005, Intec Automation,
+ * Mike Lavender (mike@steroidmicros)
+ * (C) Copyright 2006-2007, David Brownell
+ * (C) Copyright 2007, Axis Communications,
+ * Hans-Peter Nilsson (hp@axis.com)
+ * (C) Copyright 2007, ATRON electronic GmbH,
+ * Jan Nikitenko <jan.nikitenko@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc7.h>
+#include <linux/crc-itu-t.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+
+#include <asm/unaligned.h>
+
+
+/* NOTES:
+ *
+ * - For now, we won't try to interoperate with a real mmc/sd/sdio
+ * controller, although some of them do have hardware support for
+ * SPI protocol. The main reason for such configs would be mmc-ish
+ * cards like DataFlash, which don't support that "native" protocol.
+ *
+ * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to
+ * switch between driver stacks, and in any case if "native" mode
+ * is available, it will be faster and hence preferable.
+ *
+ * - MMC depends on a different chipselect management policy than the
+ * SPI interface currently supports for shared bus segments: it needs
+ * to issue multiple spi_message requests with the chipselect active,
+ * using the results of one message to decide the next one to issue.
+ *
+ * Pending updates to the programming interface, this driver expects
+ * that it not share the bus with other drivers (precluding conflicts).
+ *
+ * - We tell the controller to keep the chipselect active from the
+ * beginning of an mmc_host_ops.request until the end. So beware
+ * of SPI controller drivers that mis-handle the cs_change flag!
+ *
+ * However, many cards seem OK with chipselect flapping up/down
+ * during that time ... at least on unshared bus segments.
+ */
+
+
+/*
+ * Local protocol constants, internal to data block protocols.
+ */
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */
+#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */
+
+#define MMC_SPI_BLOCKSIZE 512
+
+
+/* These fixed timeouts come from the latest SD specs, which say to ignore
+ * the CSD values. The R1B value is for card erase (e.g. the "I forgot the
+ * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after
+ * reads which takes nowhere near that long. Older cards may be able to use
+ * shorter timeouts ... but why bother?
+ */
+#define readblock_timeout ktime_set(0, 100 * 1000 * 1000)
+#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000)
+#define r1b_timeout ktime_set(3, 0)
+
+
+/****************************************************************************/
+
+/*
+ * Local Data Structures
+ */
+
+/* "scratch" is per-{command,block} data exchanged with the card */
+struct scratch {
+ u8 status[29];
+ u8 data_token;
+ __be16 crc_val;
+};
+
+struct mmc_spi_host {
+ struct mmc_host *mmc;
+ struct spi_device *spi;
+
+ unsigned char power_mode;
+ u16 powerup_msecs;
+
+ struct mmc_spi_platform_data *pdata;
+
+ /* for bulk data transfers */
+ struct spi_transfer token, t, crc, early_status;
+ struct spi_message m;
+
+ /* for status readback */
+ struct spi_transfer status;
+ struct spi_message readback;
+
+ /* underlying DMA-aware controller, or null */
+ struct device *dma_dev;
+
+ /* buffer used for commands and for message "overhead" */
+ struct scratch *data;
+ dma_addr_t data_dma;
+
+ /* Specs say to write ones most of the time, even when the card
+ * has no need to read its input data; and many cards won't care.
+ * This is our source of those ones.
+ */
+ void *ones;
+ dma_addr_t ones_dma;
+};
+
+
+/****************************************************************************/
+
+/*
+ * MMC-over-SPI protocol glue, used by the MMC stack interface
+ */
+
+static inline int mmc_cs_off(struct mmc_spi_host *host)
+{
+ /* chipselect will always be inactive after setup() */
+ return spi_setup(host->spi);
+}
+
+static int
+mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
+{
+ int status;
+
+ if (len > sizeof(*host->data)) {
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ host->status.len = len;
+
+ if (host->dma_dev)
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_FROM_DEVICE);
+
+ status = spi_sync(host->spi, &host->readback);
+ if (status == 0)
+ status = host->readback.status;
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_FROM_DEVICE);
+
+ return status;
+}
+
+static int
+mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte)
+{
+ u8 *cp = host->data->status;
+
+ timeout = ktime_add(timeout, ktime_get());
+
+ while (1) {
+ int status;
+ unsigned i;
+
+ status = mmc_spi_readbytes(host, n);
+ if (status < 0)
+ return status;
+
+ for (i = 0; i < n; i++) {
+ if (cp[i] != byte)
+ return cp[i];
+ }
+
+ /* REVISIT investigate msleep() to avoid busy-wait I/O
+ * in at least some cases.
+ */
+ if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0)
+ break;
+ }
+ return -ETIMEDOUT;
+}
+
+static inline int
+mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
+{
+ return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
+}
+
+static int mmc_spi_readtoken(struct mmc_spi_host *host)
+{
+ return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+}
+
+
+/*
+ * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol
+ * hosts return! The low byte holds R1_SPI bits. The next byte may hold
+ * R2_SPI bits ... for SEND_STATUS, or after data read errors.
+ *
+ * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on
+ * newer cards R7 (IF_COND).
+ */
+
+static char *maptype(struct mmc_command *cmd)
+{
+ switch (mmc_spi_resp_type(cmd)) {
+ case MMC_RSP_SPI_R1: return "R1";
+ case MMC_RSP_SPI_R1B: return "R1B";
+ case MMC_RSP_SPI_R2: return "R2/R5";
+ case MMC_RSP_SPI_R3: return "R3/R4/R7";
+ default: return "?";
+ }
+}
+
+/* return zero, else negative errno after setting cmd->error */
+static int mmc_spi_response_get(struct mmc_spi_host *host,
+ struct mmc_command *cmd, int cs_on)
+{
+ u8 *cp = host->data->status;
+ u8 *end = cp + host->t.len;
+ int value = 0;
+ char tag[32];
+
+ snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s",
+ cmd->opcode, maptype(cmd));
+
+ /* Except for data block reads, the whole response will already
+ * be stored in the scratch buffer. It's somewhere after the
+ * command and the first byte we read after it. We ignore that
+ * first byte. After STOP_TRANSMISSION command it may include
+ * two data bits, but otherwise it's all ones.
+ */
+ cp += 8;
+ while (cp < end && *cp == 0xff)
+ cp++;
+
+ /* Data block reads (R1 response types) may need more data... */
+ if (cp == end) {
+ unsigned i;
+
+ cp = host->data->status;
+
+ /* Card sends N(CR) (== 1..8) bytes of all-ones then one
+ * status byte ... and we already scanned 2 bytes.
+ *
+ * REVISIT block read paths use nasty byte-at-a-time I/O
+ * so it can always DMA directly into the target buffer.
+ * It'd probably be better to memcpy() the first chunk and
+ * avoid extra i/o calls...
+ */
+ for (i = 2; i < 9; i++) {
+ value = mmc_spi_readbytes(host, 1);
+ if (value < 0)
+ goto done;
+ if (*cp != 0xff)
+ goto checkstatus;
+ }
+ value = -ETIMEDOUT;
+ goto done;
+ }
+
+checkstatus:
+ if (*cp & 0x80) {
+ dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n",
+ tag, *cp);
+ value = -EBADR;
+ goto done;
+ }
+
+ cmd->resp[0] = *cp++;
+ cmd->error = 0;
+
+ /* Status byte: the entire seven-bit R1 response. */
+ if (cmd->resp[0] != 0) {
+ if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
+ | R1_SPI_ILLEGAL_COMMAND)
+ & cmd->resp[0])
+ value = -EINVAL;
+ else if (R1_SPI_COM_CRC & cmd->resp[0])
+ value = -EILSEQ;
+ else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET)
+ & cmd->resp[0])
+ value = -EIO;
+ /* else R1_SPI_IDLE, "it's resetting" */
+ }
+
+ switch (mmc_spi_resp_type(cmd)) {
+
+ /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads)
+ * and less-common stuff like various erase operations.
+ */
+ case MMC_RSP_SPI_R1B:
+ /* maybe we read all the busy tokens already */
+ while (cp < end && *cp == 0)
+ cp++;
+ if (cp == end)
+ mmc_spi_wait_unbusy(host, r1b_timeout);
+ break;
+
+ /* SPI R2 == R1 + second status byte; SEND_STATUS
+ * SPI R5 == R1 + data byte; IO_RW_DIRECT
+ */
+ case MMC_RSP_SPI_R2:
+ cmd->resp[0] |= *cp << 8;
+ break;
+
+ /* SPI R3, R4, or R7 == R1 + 4 bytes */
+ case MMC_RSP_SPI_R3:
+ cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp));
+ break;
+
+ /* SPI R1 == just one status byte */
+ case MMC_RSP_SPI_R1:
+ break;
+
+ default:
+ dev_dbg(&host->spi->dev, "bad response type %04x\n",
+ mmc_spi_resp_type(cmd));
+ if (value >= 0)
+ value = -EINVAL;
+ goto done;
+ }
+
+ if (value < 0)
+ dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n",
+ tag, cmd->resp[0], cmd->resp[1]);
+
+ /* disable chipselect on errors and some success cases */
+ if (value >= 0 && cs_on)
+ return value;
+done:
+ if (value < 0)
+ cmd->error = value;
+ mmc_cs_off(host);
+ return value;
+}
+
+/* Issue command and read its response.
+ * Returns zero on success, negative for error.
+ *
+ * On error, caller must cope with mmc core retry mechanism. That
+ * means immediate low-level resubmit, which affects the bus lock...
+ */
+static int
+mmc_spi_command_send(struct mmc_spi_host *host,
+ struct mmc_request *mrq,
+ struct mmc_command *cmd, int cs_on)
+{
+ struct scratch *data = host->data;
+ u8 *cp = data->status;
+ u32 arg = cmd->arg;
+ int status;
+ struct spi_transfer *t;
+
+ /* We can handle most commands (except block reads) in one full
+ * duplex I/O operation before either starting the next transfer
+ * (data block or command) or else deselecting the card.
+ *
+ * First, write 7 bytes:
+ * - an all-ones byte to ensure the card is ready
+ * - opcode byte (plus start and transmission bits)
+ * - four bytes of big-endian argument
+ * - crc7 (plus end bit) ... always computed, it's cheap
+ *
+ * We init the whole buffer to all-ones, which is what we need
+ * to write while we're reading (later) response data.
+ */
+ memset(cp++, 0xff, sizeof(data->status));
+
+ *cp++ = 0x40 | cmd->opcode;
+ *cp++ = (u8)(arg >> 24);
+ *cp++ = (u8)(arg >> 16);
+ *cp++ = (u8)(arg >> 8);
+ *cp++ = (u8)arg;
+ *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01;
+
+ /* Then, read up to 13 bytes (while writing all-ones):
+ * - N(CR) (== 1..8) bytes of all-ones
+ * - status byte (for all response types)
+ * - the rest of the response, either:
+ * + nothing, for R1 or R1B responses
+ * + second status byte, for R2 responses
+ * + four data bytes, for R3 and R7 responses
+ *
+ * Finally, read some more bytes ... in the nice cases we know in
+ * advance how many, and reading 1 more is always OK:
+ * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish
+ * - N(RC) (== 1..N) bytes of all-ones, before next command
+ * - N(WR) (== 1..N) bytes of all-ones, before data write
+ *
+ * So in those cases one full duplex I/O of at most 21 bytes will
+ * handle the whole command, leaving the card ready to receive a
+ * data block or new command. We do that whenever we can, shaving
+ * CPU and IRQ costs (especially when using DMA or FIFOs).
+ *
+ * There are two other cases, where it's not generally practical
+ * to rely on a single I/O:
+ *
+ * - R1B responses need at least N(EC) bytes of all-zeroes.
+ *
+ * In this case we can *try* to fit it into one I/O, then
+ * maybe read more data later.
+ *
+ * - Data block reads are more troublesome, since a variable
+ * number of padding bytes precede the token and data.
+ * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID
+ * + N(AC) (== 1..many) bytes of all-ones
+ *
+ * In this case we currently only have minimal speedups here:
+ * when N(CR) == 1 we can avoid I/O in response_get().
+ */
+ if (cs_on && (mrq->data->flags & MMC_DATA_READ)) {
+ cp += 2; /* min(N(CR)) + status */
+ /* R1 */
+ } else {
+ cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */
+ if (cmd->flags & MMC_RSP_SPI_S2) /* R2/R5 */
+ cp++;
+ else if (cmd->flags & MMC_RSP_SPI_B4) /* R3/R4/R7 */
+ cp += 4;
+ else if (cmd->flags & MMC_RSP_BUSY) /* R1B */
+ cp = data->status + sizeof(data->status);
+ /* else: R1 (most commands) */
+ }
+
+ dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n",
+ cmd->opcode, maptype(cmd));
+
+ /* send command, leaving chipselect active */
+ spi_message_init(&host->m);
+
+ t = &host->t;
+ memset(t, 0, sizeof(*t));
+ t->tx_buf = t->rx_buf = data->status;
+ t->tx_dma = t->rx_dma = host->data_dma;
+ t->len = cp - data->status;
+ t->cs_change = 1;
+ spi_message_add_tail(t, &host->m);
+
+ if (host->dma_dev) {
+ host->m.is_dma_mapped = 1;
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_BIDIRECTIONAL);
+ }
+ status = spi_sync(host->spi, &host->m);
+ if (status == 0)
+ status = host->m.status;
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_BIDIRECTIONAL);
+ if (status < 0) {
+ dev_dbg(&host->spi->dev, " ... write returned %d\n", status);
+ cmd->error = status;
+ return status;
+ }
+
+ /* after no-data commands and STOP_TRANSMISSION, chipselect off */
+ return mmc_spi_response_get(host, cmd, cs_on);
+}
+
+/* Build data message with up to four separate transfers. For TX, we
+ * start by writing the data token. And in most cases, we finish with
+ * a status transfer.
+ *
+ * We always provide TX data for data and CRC. The MMC/SD protocol
+ * requires us to write ones; but Linux defaults to writing zeroes;
+ * so we explicitly initialize it to all ones on RX paths.
+ *
+ * We also handle DMA mapping, so the underlying SPI controller does
+ * not need to (re)do it for each message.
+ */
+static void
+mmc_spi_setup_data_message(
+ struct mmc_spi_host *host,
+ int multiple,
+ enum dma_data_direction direction)
+{
+ struct spi_transfer *t;
+ struct scratch *scratch = host->data;
+ dma_addr_t dma = host->data_dma;
+
+ spi_message_init(&host->m);
+ if (dma)
+ host->m.is_dma_mapped = 1;
+
+ /* for reads, readblock() skips 0xff bytes before finding
+ * the token; for writes, this transfer issues that token.
+ */
+ if (direction == DMA_TO_DEVICE) {
+ t = &host->token;
+ memset(t, 0, sizeof(*t));
+ t->len = 1;
+ if (multiple)
+ scratch->data_token = SPI_TOKEN_MULTI_WRITE;
+ else
+ scratch->data_token = SPI_TOKEN_SINGLE;
+ t->tx_buf = &scratch->data_token;
+ if (dma)
+ t->tx_dma = dma + offsetof(struct scratch, data_token);
+ spi_message_add_tail(t, &host->m);
+ }
+
+ /* Body of transfer is buffer, then CRC ...
+ * either TX-only, or RX with TX-ones.
+ */
+ t = &host->t;
+ memset(t, 0, sizeof(*t));
+ t->tx_buf = host->ones;
+ t->tx_dma = host->ones_dma;
+ /* length and actual buffer info are written later */
+ spi_message_add_tail(t, &host->m);
+
+ t = &host->crc;
+ memset(t, 0, sizeof(*t));
+ t->len = 2;
+ if (direction == DMA_TO_DEVICE) {
+ /* the actual CRC may get written later */
+ t->tx_buf = &scratch->crc_val;
+ if (dma)
+ t->tx_dma = dma + offsetof(struct scratch, crc_val);
+ } else {
+ t->tx_buf = host->ones;
+ t->tx_dma = host->ones_dma;
+ t->rx_buf = &scratch->crc_val;
+ if (dma)
+ t->rx_dma = dma + offsetof(struct scratch, crc_val);
+ }
+ spi_message_add_tail(t, &host->m);
+
+ /*
+ * A single block read is followed by N(EC) [0+] all-ones bytes
+ * before deselect ... don't bother.
+ *
+ * Multiblock reads are followed by N(AC) [1+] all-ones bytes before
+ * the next block is read, or a STOP_TRANSMISSION is issued. We'll
+ * collect that single byte, so readblock() doesn't need to.
+ *
+ * For a write, the one-byte data response follows immediately, then
+ * come zero or more busy bytes, then N(WR) [1+] all-ones bytes.
+ * Then single block reads may deselect, and multiblock ones issue
+ * the next token (next data block, or STOP_TRAN). We can try to
+ * minimize I/O ops by using a single read to collect end-of-busy.
+ */
+ if (multiple || direction == DMA_TO_DEVICE) {
+ t = &host->early_status;
+ memset(t, 0, sizeof(*t));
+ t->len = (direction == DMA_TO_DEVICE)
+ ? sizeof(scratch->status)
+ : 1;
+ t->tx_buf = host->ones;
+ t->tx_dma = host->ones_dma;
+ t->rx_buf = scratch->status;
+ if (dma)
+ t->rx_dma = dma + offsetof(struct scratch, status);
+ t->cs_change = 1;
+ spi_message_add_tail(t, &host->m);
+ }
+}
+
+/*
+ * Write one block:
+ * - caller handled preceding N(WR) [1+] all-ones bytes
+ * - data block
+ * + token
+ * + data bytes
+ * + crc16
+ * - an all-ones byte ... card writes a data-response byte
+ * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy'
+ *
+ * Return negative errno, else success.
+ */
+static int
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+ struct spi_device *spi = host->spi;
+ int status, i;
+ struct scratch *scratch = host->data;
+
+ if (host->mmc->use_spi_crc)
+ scratch->crc_val = cpu_to_be16(
+ crc_itu_t(0, t->tx_buf, t->len));
+ if (host->dma_dev)
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ status = spi_sync(spi, &host->m);
+ if (status == 0)
+ status = host->m.status;
+
+ if (status != 0) {
+ dev_dbg(&spi->dev, "write error (%d)\n", status);
+ return status;
+ }
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ /*
+ * Get the transmission data-response reply. It must follow
+ * immediately after the data block we transferred. This reply
+ * doesn't necessarily tell whether the write operation succeeded;
+ * it just says if the transmission was ok and whether *earlier*
+ * writes succeeded; see the standard.
+ */
+ switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) {
+ case SPI_RESPONSE_ACCEPTED:
+ status = 0;
+ break;
+ case SPI_RESPONSE_CRC_ERR:
+ /* host shall then issue MMC_STOP_TRANSMISSION */
+ status = -EILSEQ;
+ break;
+ case SPI_RESPONSE_WRITE_ERR:
+ /* host shall then issue MMC_STOP_TRANSMISSION,
+ * and should MMC_SEND_STATUS to sort it out
+ */
+ status = -EIO;
+ break;
+ default:
+ status = -EPROTO;
+ break;
+ }
+ if (status != 0) {
+ dev_dbg(&spi->dev, "write error %02x (%d)\n",
+ scratch->status[0], status);
+ return status;
+ }
+
+ t->tx_buf += t->len;
+ if (host->dma_dev)
+ t->tx_dma += t->len;
+
+ /* Return when not busy. If we didn't collect that status yet,
+ * we'll need some more I/O.
+ */
+ for (i = 1; i < sizeof(scratch->status); i++) {
+ if (scratch->status[i] != 0)
+ return 0;
+ }
+ return mmc_spi_wait_unbusy(host, writeblock_timeout);
+}
+
+/*
+ * Read one block:
+ * - skip leading all-ones bytes ... either
+ * + N(AC) [1..f(clock,CSD)] usually, else
+ * + N(CX) [0..8] when reading CSD or CID
+ * - data block
+ * + token ... if error token, no data or crc
+ * + data bytes
+ * + crc16
+ *
+ * After single block reads, we're done; N(EC) [0+] all-ones bytes follow
+ * before dropping chipselect.
+ *
+ * For multiblock reads, caller either reads the next block or issues a
+ * STOP_TRANSMISSION command.
+ */
+static int
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+ struct spi_device *spi = host->spi;
+ int status;
+ struct scratch *scratch = host->data;
+
+ /* At least one SD card sends an all-zeroes byte when N(CX)
+ * applies, before the all-ones bytes ... just cope with that.
+ */
+ status = mmc_spi_readbytes(host, 1);
+ if (status < 0)
+ return status;
+ status = scratch->status[0];
+ if (status == 0xff || status == 0)
+ status = mmc_spi_readtoken(host);
+
+ if (status == SPI_TOKEN_SINGLE) {
+ if (host->dma_dev) {
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(host->dma_dev,
+ t->rx_dma, t->len,
+ DMA_FROM_DEVICE);
+ }
+
+ status = spi_sync(spi, &host->m);
+ if (status == 0)
+ status = host->m.status;
+
+ if (host->dma_dev) {
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+ dma_sync_single_for_cpu(host->dma_dev,
+ t->rx_dma, t->len,
+ DMA_FROM_DEVICE);
+ }
+
+ } else {
+ dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
+
+ /* we've read extra garbage, timed out, etc */
+ if (status < 0)
+ return status;
+
+ /* low four bits are an R2 subset, fifth seems to be
+ * vendor specific ... map them all to generic error..
+ */
+ return -EIO;
+ }
+
+ if (host->mmc->use_spi_crc) {
+ u16 crc = crc_itu_t(0, t->rx_buf, t->len);
+
+ be16_to_cpus(&scratch->crc_val);
+ if (scratch->crc_val != crc) {
+ dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, "
+ "computed=0x%04x len=%d\n",
+ scratch->crc_val, crc, t->len);
+ return -EILSEQ;
+ }
+ }
+
+ t->rx_buf += t->len;
+ if (host->dma_dev)
+ t->rx_dma += t->len;
+
+ return 0;
+}
+
+/*
+ * An MMC/SD data stage includes one or more blocks, optional CRCs,
+ * and inline handshaking. That handhaking makes it unlike most
+ * other SPI protocol stacks.
+ */
+static void
+mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
+ struct mmc_data *data, u32 blk_size)
+{
+ struct spi_device *spi = host->spi;
+ struct device *dma_dev = host->dma_dev;
+ struct spi_transfer *t;
+ enum dma_data_direction direction;
+ struct scatterlist *sg;
+ unsigned n_sg;
+ int multiple = (data->blocks > 1);
+
+ if (data->flags & MMC_DATA_READ)
+ direction = DMA_FROM_DEVICE;
+ else
+ direction = DMA_TO_DEVICE;
+ mmc_spi_setup_data_message(host, multiple, direction);
+ t = &host->t;
+
+ /* Handle scatterlist segments one at a time, with synch for
+ * each 512-byte block
+ */
+ for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) {
+ int status = 0;
+ dma_addr_t dma_addr = 0;
+ void *kmap_addr;
+ unsigned length = sg->length;
+ enum dma_data_direction dir = direction;
+
+ /* set up dma mapping for controller drivers that might
+ * use DMA ... though they may fall back to PIO
+ */
+ if (dma_dev) {
+ /* never invalidate whole *shared* pages ... */
+ if ((sg->offset != 0 || length != PAGE_SIZE)
+ && dir == DMA_FROM_DEVICE)
+ dir = DMA_BIDIRECTIONAL;
+
+ dma_addr = dma_map_page(dma_dev, sg->page, 0,
+ PAGE_SIZE, dir);
+ if (direction == DMA_TO_DEVICE)
+ t->tx_dma = dma_addr + sg->offset;
+ else
+ t->rx_dma = dma_addr + sg->offset;
+ }
+
+ /* allow pio too; we don't allow highmem */
+ kmap_addr = kmap(sg->page);
+ if (direction == DMA_TO_DEVICE)
+ t->tx_buf = kmap_addr + sg->offset;
+ else
+ t->rx_buf = kmap_addr + sg->offset;
+
+ /* transfer each block, and update request status */
+ while (length) {
+ t->len = min(length, blk_size);
+
+ dev_dbg(&host->spi->dev,
+ " mmc_spi: %s block, %d bytes\n",
+ (direction == DMA_TO_DEVICE)
+ ? "write"
+ : "read",
+ t->len);
+
+ if (direction == DMA_TO_DEVICE)
+ status = mmc_spi_writeblock(host, t);
+ else
+ status = mmc_spi_readblock(host, t);
+ if (status < 0)
+ break;
+
+ data->bytes_xfered += t->len;
+ length -= t->len;
+
+ if (!multiple)
+ break;
+ }
+
+ /* discard mappings */
+ if (direction == DMA_FROM_DEVICE)
+ flush_kernel_dcache_page(sg->page);
+ kunmap(sg->page);
+ if (dma_dev)
+ dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
+
+ if (status < 0) {
+ data->error = status;
+ dev_dbg(&spi->dev, "%s status %d\n",
+ (direction == DMA_TO_DEVICE)
+ ? "write" : "read",
+ status);
+ break;
+ }
+ }
+
+ /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that
+ * can be issued before multiblock writes. Unlike its more widely
+ * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23),
+ * that can affect the STOP_TRAN logic. Complete (and current)
+ * MMC specs should sort that out before Linux starts using CMD23.
+ */
+ if (direction == DMA_TO_DEVICE && multiple) {
+ struct scratch *scratch = host->data;
+ int tmp;
+ const unsigned statlen = sizeof(scratch->status);
+
+ dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n");
+
+ /* Tweak the per-block message we set up earlier by morphing
+ * it to hold single buffer with the token followed by some
+ * all-ones bytes ... skip N(BR) (0..1), scan the rest for
+ * "not busy any longer" status, and leave chip selected.
+ */
+ INIT_LIST_HEAD(&host->m.transfers);
+ list_add(&host->early_status.transfer_list,
+ &host->m.transfers);
+
+ memset(scratch->status, 0xff, statlen);
+ scratch->status[0] = SPI_TOKEN_STOP_TRAN;
+
+ host->early_status.tx_buf = host->early_status.rx_buf;
+ host->early_status.tx_dma = host->early_status.rx_dma;
+ host->early_status.len = statlen;
+
+ if (host->dma_dev)
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ tmp = spi_sync(spi, &host->m);
+ if (tmp == 0)
+ tmp = host->m.status;
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ if (tmp < 0) {
+ if (!data->error)
+ data->error = tmp;
+ return;
+ }
+
+ /* Ideally we collected "not busy" status with one I/O,
+ * avoiding wasteful byte-at-a-time scanning... but more
+ * I/O is often needed.
+ */
+ for (tmp = 2; tmp < statlen; tmp++) {
+ if (scratch->status[tmp] != 0)
+ return;
+ }
+ tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+ if (tmp < 0 && !data->error)
+ data->error = tmp;
+ }
+}
+
+/****************************************************************************/
+
+/*
+ * MMC driver implementation -- the interface to the MMC stack
+ */
+
+static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+ int status = -EINVAL;
+
+#ifdef DEBUG
+ /* MMC core and layered drivers *MUST* issue SPI-aware commands */
+ {
+ struct mmc_command *cmd;
+ int invalid = 0;
+
+ cmd = mrq->cmd;
+ if (!mmc_spi_resp_type(cmd)) {
+ dev_dbg(&host->spi->dev, "bogus command\n");
+ cmd->error = -EINVAL;
+ invalid = 1;
+ }
+
+ cmd = mrq->stop;
+ if (cmd && !mmc_spi_resp_type(cmd)) {
+ dev_dbg(&host->spi->dev, "bogus STOP command\n");
+ cmd->error = -EINVAL;
+ invalid = 1;
+ }
+
+ if (invalid) {
+ dump_stack();
+ mmc_request_done(host->mmc, mrq);
+ return;
+ }
+ }
+#endif
+
+ /* issue command; then optionally data and stop */
+ status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
+ if (status == 0 && mrq->data) {
+ mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+ if (mrq->stop)
+ status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
+ else
+ mmc_cs_off(host);
+ }
+
+ mmc_request_done(host->mmc, mrq);
+}
+
+/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0"
+ *
+ * NOTE that here we can't know that the card has just been powered up;
+ * not all MMC/SD sockets support power switching.
+ *
+ * FIXME when the card is still in SPI mode, e.g. from a previous kernel,
+ * this doesn't seem to do the right thing at all...
+ */
+static void mmc_spi_initsequence(struct mmc_spi_host *host)
+{
+ /* Try to be very sure any previous command has completed;
+ * wait till not-busy, skip debris from any old commands.
+ */
+ mmc_spi_wait_unbusy(host, r1b_timeout);
+ mmc_spi_readbytes(host, 10);
+
+ /*
+ * Do a burst with chipselect active-high. We need to do this to
+ * meet the requirement of 74 clock cycles with both chipselect
+ * and CMD (MOSI) high before CMD0 ... after the card has been
+ * powered up to Vdd(min), and so is ready to take commands.
+ *
+ * Some cards are particularly needy of this (e.g. Viking "SD256")
+ * while most others don't seem to care.
+ *
+ * Note that this is one of the places MMC/SD plays games with the
+ * SPI protocol. Another is that when chipselect is released while
+ * the card returns BUSY status, the clock must issue several cycles
+ * with chipselect high before the card will stop driving its output.
+ */
+ host->spi->mode |= SPI_CS_HIGH;
+ if (spi_setup(host->spi) != 0) {
+ /* Just warn; most cards work without it. */
+ dev_warn(&host->spi->dev,
+ "can't change chip-select polarity\n");
+ host->spi->mode &= ~SPI_CS_HIGH;
+ } else {
+ mmc_spi_readbytes(host, 18);
+
+ host->spi->mode &= ~SPI_CS_HIGH;
+ if (spi_setup(host->spi) != 0) {
+ /* Wot, we can't get the same setup we had before? */
+ dev_err(&host->spi->dev,
+ "can't restore chip-select polarity\n");
+ }
+ }
+}
+
+static char *mmc_powerstring(u8 power_mode)
+{
+ switch (power_mode) {
+ case MMC_POWER_OFF: return "off";
+ case MMC_POWER_UP: return "up";
+ case MMC_POWER_ON: return "on";
+ }
+ return "?";
+}
+
+static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+
+ if (host->power_mode != ios->power_mode) {
+ int canpower;
+
+ canpower = host->pdata && host->pdata->setpower;
+
+ dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
+ mmc_powerstring(ios->power_mode),
+ ios->vdd,
+ canpower ? ", can switch" : "");
+
+ /* switch power on/off if possible, accounting for
+ * max 250msec powerup time if needed.
+ */
+ if (canpower) {
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ case MMC_POWER_UP:
+ host->pdata->setpower(&host->spi->dev,
+ ios->vdd);
+ if (ios->power_mode == MMC_POWER_UP)
+ msleep(host->powerup_msecs);
+ }
+ }
+
+ /* See 6.4.1 in the simplified SD card physical spec 2.0 */
+ if (ios->power_mode == MMC_POWER_ON)
+ mmc_spi_initsequence(host);
+
+ /* If powering down, ground all card inputs to avoid power
+ * delivery from data lines! On a shared SPI bus, this
+ * will probably be temporary; 6.4.2 of the simplified SD
+ * spec says this must last at least 1msec.
+ *
+ * - Clock low means CPOL 0, e.g. mode 0
+ * - MOSI low comes from writing zero
+ * - Chipselect is usually active low...
+ */
+ if (canpower && ios->power_mode == MMC_POWER_OFF) {
+ int mres;
+
+ host->spi->mode &= ~(SPI_CPOL|SPI_CPHA);
+ mres = spi_setup(host->spi);
+ if (mres < 0)
+ dev_dbg(&host->spi->dev,
+ "switch to SPI mode 0 failed\n");
+
+ if (spi_w8r8(host->spi, 0x00) < 0)
+ dev_dbg(&host->spi->dev,
+ "put spi signals to low failed\n");
+
+ /*
+ * Now clock should be low due to spi mode 0;
+ * MOSI should be low because of written 0x00;
+ * chipselect should be low (it is active low)
+ * power supply is off, so now MMC is off too!
+ *
+ * FIXME no, chipselect can be high since the
+ * device is inactive and SPI_CS_HIGH is clear...
+ */
+ msleep(10);
+ if (mres == 0) {
+ host->spi->mode |= (SPI_CPOL|SPI_CPHA);
+ mres = spi_setup(host->spi);
+ if (mres < 0)
+ dev_dbg(&host->spi->dev,
+ "switch back to SPI mode 3"
+ " failed\n");
+ }
+ }
+
+ host->power_mode = ios->power_mode;
+ }
+
+ if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) {
+ int status;
+
+ host->spi->max_speed_hz = ios->clock;
+ status = spi_setup(host->spi);
+ dev_dbg(&host->spi->dev,
+ "mmc_spi: clock to %d Hz, %d\n",
+ host->spi->max_speed_hz, status);
+ }
+}
+
+static int mmc_spi_get_ro(struct mmc_host *mmc)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc->parent);
+ /* board doesn't support read only detection; assume writeable */
+ return 0;
+}
+
+
+static const struct mmc_host_ops mmc_spi_ops = {
+ .request = mmc_spi_request,
+ .set_ios = mmc_spi_set_ios,
+ .get_ro = mmc_spi_get_ro,
+};
+
+
+/****************************************************************************/
+
+/*
+ * SPI driver implementation
+ */
+
+static irqreturn_t
+mmc_spi_detect_irq(int irq, void *mmc)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+ u16 delay_msec = max(host->pdata->detect_delay, (u16)100);
+
+ mmc_detect_change(mmc, msecs_to_jiffies(delay_msec));
+ return IRQ_HANDLED;
+}
+
+static int mmc_spi_probe(struct spi_device *spi)
+{
+ void *ones;
+ struct mmc_host *mmc;
+ struct mmc_spi_host *host;
+ int status;
+
+ /* MMC and SD specs only seem to care that sampling is on the
+ * rising edge ... meaning SPI modes 0 or 3. So either SPI mode
+ * should be legit. We'll use mode 0 since it seems to be a
+ * bit less troublesome on some hardware ... unclear why.
+ */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+
+ status = spi_setup(spi);
+ if (status < 0) {
+ dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n",
+ spi->mode, spi->max_speed_hz / 1000,
+ status);
+ return status;
+ }
+
+ /* We can use the bus safely iff nobody else will interfere with
+ * us. That is, either we have the experimental exclusive access
+ * primitives ... or else there's nobody to share it with.
+ */
+ if (spi->master->num_chipselect > 1) {
+ struct device *parent = spi->dev.parent;
+
+ /* If there are multiple devices on this bus, we
+ * can't proceed.
+ */
+ spin_lock(&parent->klist_children.k_lock);
+ if (parent->klist_children.k_list.next
+ != parent->klist_children.k_list.prev)
+ status = -EMLINK;
+ else
+ status = 0;
+ spin_unlock(&parent->klist_children.k_lock);
+ if (status < 0) {
+ dev_err(&spi->dev, "can't share SPI bus\n");
+ return status;
+ }
+
+ /* REVISIT we can't guarantee another device won't
+ * be added later. It's uncommon though ... for now,
+ * work as if this is safe.
+ */
+ dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n");
+ }
+
+ /* We need a supply of ones to transmit. This is the only time
+ * the CPU touches these, so cache coherency isn't a concern.
+ *
+ * NOTE if many systems use more than one MMC-over-SPI connector
+ * it'd save some memory to share this. That's evidently rare.
+ */
+ status = -ENOMEM;
+ ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL);
+ if (!ones)
+ goto nomem;
+ memset(ones, 0xff, MMC_SPI_BLOCKSIZE);
+
+ mmc = mmc_alloc_host(sizeof(*host), &spi->dev);
+ if (!mmc)
+ goto nomem;
+
+ mmc->ops = &mmc_spi_ops;
+ mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
+
+ /* As long as we keep track of the number of successfully
+ * transmitted blocks, we're good for multiwrite.
+ */
+ mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE;
+
+ /* SPI doesn't need the lowspeed device identification thing for
+ * MMC or SD cards, since it never comes up in open drain mode.
+ * That's good; some SPI masters can't handle very low speeds!
+ *
+ * However, low speed SDIO cards need not handle over 400 KHz;
+ * that's the only reason not to use a few MHz for f_min (until
+ * the upper layer reads the target frequency from the CSD).
+ */
+ mmc->f_min = 400000;
+ mmc->f_max = spi->max_speed_hz;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->spi = spi;
+
+ host->ones = ones;
+
+ /* Platform data is used to hook up things like card sensing
+ * and power switching gpios.
+ */
+ host->pdata = spi->dev.platform_data;
+ if (host->pdata)
+ mmc->ocr_avail = host->pdata->ocr_mask;
+ if (!mmc->ocr_avail) {
+ dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
+ mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ }
+ if (host->pdata && host->pdata->setpower) {
+ host->powerup_msecs = host->pdata->powerup_msecs;
+ if (!host->powerup_msecs || host->powerup_msecs > 250)
+ host->powerup_msecs = 250;
+ }
+
+ dev_set_drvdata(&spi->dev, mmc);
+
+ /* preallocate dma buffers */
+ host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
+ if (!host->data)
+ goto fail_nobuf1;
+
+ if (spi->master->cdev.dev->dma_mask) {
+ struct device *dev = spi->master->cdev.dev;
+
+ host->dma_dev = dev;
+ host->ones_dma = dma_map_single(dev, ones,
+ MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+ host->data_dma = dma_map_single(dev, host->data,
+ sizeof(*host->data), DMA_BIDIRECTIONAL);
+
+ /* REVISIT in theory those map operations can fail... */
+
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_BIDIRECTIONAL);
+ }
+
+ /* setup message for status/busy readback */
+ spi_message_init(&host->readback);
+ host->readback.is_dma_mapped = (host->dma_dev != NULL);
+
+ spi_message_add_tail(&host->status, &host->readback);
+ host->status.tx_buf = host->ones;
+ host->status.tx_dma = host->ones_dma;
+ host->status.rx_buf = &host->data->status;
+ host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
+ host->status.cs_change = 1;
+
+ /* register card detect irq */
+ if (host->pdata && host->pdata->init) {
+ status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc);
+ if (status != 0)
+ goto fail_glue_init;
+ }
+
+ status = mmc_add_host(mmc);
+ if (status != 0)
+ goto fail_add_host;
+
+ dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n",
+ mmc->class_dev.bus_id,
+ host->dma_dev ? "" : ", no DMA",
+ (host->pdata && host->pdata->get_ro)
+ ? "" : ", no WP",
+ (host->pdata && host->pdata->setpower)
+ ? "" : ", no poweroff");
+ return 0;
+
+fail_add_host:
+ mmc_remove_host (mmc);
+fail_glue_init:
+ if (host->dma_dev)
+ dma_unmap_single(host->dma_dev, host->data_dma,
+ sizeof(*host->data), DMA_BIDIRECTIONAL);
+ kfree(host->data);
+
+fail_nobuf1:
+ mmc_free_host(mmc);
+ dev_set_drvdata(&spi->dev, NULL);
+
+nomem:
+ kfree(ones);
+ return status;
+}
+
+
+static int __devexit mmc_spi_remove(struct spi_device *spi)
+{
+ struct mmc_host *mmc = dev_get_drvdata(&spi->dev);
+ struct mmc_spi_host *host;
+
+ if (mmc) {
+ host = mmc_priv(mmc);
+
+ /* prevent new mmc_detect_change() calls */
+ if (host->pdata && host->pdata->exit)
+ host->pdata->exit(&spi->dev, mmc);
+
+ mmc_remove_host(mmc);
+
+ if (host->dma_dev) {
+ dma_unmap_single(host->dma_dev, host->ones_dma,
+ MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+ dma_unmap_single(host->dma_dev, host->data_dma,
+ sizeof(*host->data), DMA_BIDIRECTIONAL);
+ }
+
+ kfree(host->data);
+ kfree(host->ones);
+
+ spi->max_speed_hz = mmc->f_max;
+ mmc_free_host(mmc);
+ dev_set_drvdata(&spi->dev, NULL);
+ }
+ return 0;
+}
+
+
+static struct spi_driver mmc_spi_driver = {
+ .driver = {
+ .name = "mmc_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = mmc_spi_probe,
+ .remove = __devexit_p(mmc_spi_remove),
+};
+
+
+static int __init mmc_spi_init(void)
+{
+ return spi_register_driver(&mmc_spi_driver);
+}
+module_init(mmc_spi_init);
+
+
+static void __exit mmc_spi_exit(void)
+{
+ spi_unregister_driver(&mmc_spi_driver);
+}
+module_exit(mmc_spi_exit);
+
+
+MODULE_AUTHOR("Mike Lavender, David Brownell, "
+ "Hans-Peter Nilsson, Jan Nikitenko");
+MODULE_DESCRIPTION("SPI SD/MMC host driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index d11c2d23ceea..d0eb0a2abf4d 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
+ * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
*
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/highmem.h>
+#include <linux/log2.h>
#include <linux/mmc/host.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
@@ -154,11 +155,11 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
}
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
if (status & MCI_DATACRCFAIL)
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
else if (status & MCI_DATATIMEOUT)
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
- data->error = MMC_ERR_FIFO;
+ data->error = -EIO;
status |= MCI_DATAEND;
/*
@@ -193,12 +194,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
cmd->resp[3] = readl(base + MMCIRESPONSE3);
if (status & MCI_CMDTIMEOUT) {
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
}
- if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+ if (!cmd->data || cmd->error) {
if (host->data)
mmci_stop_data(host);
mmci_request_end(host, cmd->mrq);
@@ -391,6 +392,14 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(host->mrq != NULL);
+ if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+ printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
+ mmc_hostname(mmc), mrq->data->blksz);
+ mrq->cmd->error = -EINVAL;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
spin_lock_irq(&host->lock);
host->mrq = mrq;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 6d7eadc9a678..000e6a919782 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
+ * linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
*
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index b0824a38f425..60a67dfcda6a 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/media/mmc/omap.c
+ * linux/drivers/mmc/host/omap.c
*
* Copyright (C) 2004 Nokia Corporation
* Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
@@ -263,7 +263,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
enum dma_data_direction dma_data_dir;
BUG_ON(host->dma_ch < 0);
- if (data->error != MMC_ERR_NONE)
+ if (data->error)
omap_stop_dma(host->dma_ch);
/* Release DMA channel lazily */
mod_timer(&host->dma_timer, jiffies + HZ);
@@ -368,7 +368,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
}
}
- if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+ if (host->data == NULL || cmd->error) {
host->mrq = NULL;
clk_disable(host->fclk);
mmc_request_done(host->mmc, cmd->mrq);
@@ -475,14 +475,14 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
if (status & OMAP_MMC_STAT_DATA_TOUT) {
dev_dbg(mmc_dev(host->mmc), "data timeout\n");
if (host->data) {
- host->data->error |= MMC_ERR_TIMEOUT;
+ host->data->error = -ETIMEDOUT;
transfer_error = 1;
}
}
if (status & OMAP_MMC_STAT_DATA_CRC) {
if (host->data) {
- host->data->error |= MMC_ERR_BADCRC;
+ host->data->error = -EILSEQ;
dev_dbg(mmc_dev(host->mmc),
"data CRC error, bytes left %d\n",
host->total_bytes_left);
@@ -504,7 +504,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
dev_err(mmc_dev(host->mmc),
"command timeout, CMD %d\n",
host->cmd->opcode);
- host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
end_command = 1;
}
}
@@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
dev_err(mmc_dev(host->mmc),
"command CRC error (CMD%d, arg 0x%08x)\n",
host->cmd->opcode, host->cmd->arg);
- host->cmd->error = MMC_ERR_BADCRC;
+ host->cmd->error = -EILSEQ;
end_command = 1;
} else
dev_err(mmc_dev(host->mmc),
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index f8985c508bb9..657901eecfce 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/pxa.c - PXA MMCI driver
+ * linux/drivers/mmc/host/pxa.c - PXA MMCI driver
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
*
@@ -142,6 +142,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->dma_dir);
for (i = 0; i < host->dma_len; i++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ host->sg_cpu[i].dcmd = dcmd | length;
+ if (length & 31 && !(data->flags & MMC_DATA_READ))
+ host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
if (data->flags & MMC_DATA_READ) {
host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -149,7 +153,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
}
- host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
sizeof(struct pxa_dma_desc);
}
@@ -226,7 +229,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
}
if (stat & STAT_TIME_OUT_RESPONSE) {
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
#ifdef CONFIG_PXA27x
/*
@@ -239,11 +242,11 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
} else
#endif
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
}
pxamci_disable_irq(host, END_CMD_RES);
- if (host->data && cmd->error == MMC_ERR_NONE) {
+ if (host->data && !cmd->error) {
pxamci_enable_irq(host, DATA_TRAN_DONE);
} else {
pxamci_finish_request(host, host->mrq);
@@ -264,9 +267,9 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
host->dma_dir);
if (stat & STAT_READ_TIME_OUT)
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
/*
* There appears to be a hardware design bug here. There seems to
@@ -274,7 +277,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
* This means that if there was an error on any block, we mark all
* data blocks as being in error.
*/
- if (data->error == MMC_ERR_NONE)
+ if (!data->error)
data->bytes_xfered = data->blocks * data->blksz;
else
data->bytes_xfered = 0;
@@ -284,7 +287,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
host->data = NULL;
if (host->mrq->stop) {
pxamci_stop_clock(host);
- pxamci_start_cmd(host, host->mrq->stop, 0);
+ pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
} else {
pxamci_finish_request(host, host->mrq);
}
@@ -298,7 +301,7 @@ static irqreturn_t pxamci_irq(int irq, void *devid)
unsigned int ireg;
int handled = 0;
- ireg = readl(host->base + MMC_I_REG);
+ ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
if (ireg) {
unsigned stat = readl(host->base + MMC_STAT);
@@ -309,6 +312,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid)
handled |= pxamci_cmd_done(host, stat);
if (ireg & DATA_TRAN_DONE)
handled |= pxamci_data_done(host, stat);
+ if (ireg & SDIO_INT) {
+ mmc_signal_sdio_irq(host->mmc);
+ handled = 1;
+ }
}
return IRQ_RETVAL(handled);
@@ -382,20 +389,46 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->cmdat |= CMDAT_INIT;
}
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ host->cmdat |= CMDAT_SD_4DAT;
+ else
+ host->cmdat &= ~CMDAT_SD_4DAT;
+
pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
host->clkrt, host->cmdat);
}
+static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
+{
+ struct pxamci_host *pxa_host = mmc_priv(host);
+
+ if (enable)
+ pxamci_enable_irq(pxa_host, SDIO_INT);
+ else
+ pxamci_disable_irq(pxa_host, SDIO_INT);
+}
+
static const struct mmc_host_ops pxamci_ops = {
- .request = pxamci_request,
- .get_ro = pxamci_get_ro,
- .set_ios = pxamci_set_ios,
+ .request = pxamci_request,
+ .get_ro = pxamci_get_ro,
+ .set_ios = pxamci_set_ios,
+ .enable_sdio_irq = pxamci_enable_sdio_irq,
};
static void pxamci_dma_irq(int dma, void *devid)
{
- printk(KERN_ERR "DMA%d: IRQ???\n", dma);
- DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+ struct pxamci_host *host = devid;
+ int dcsr = DCSR(dma);
+ DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
+
+ if (dcsr & DCSR_ENDINTR) {
+ writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
+ } else {
+ printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+ mmc_hostname(host->mmc), dma, dcsr);
+ host->data->error = -EIO;
+ pxamci_data_done(host, 0);
+ }
}
static irqreturn_t pxamci_detect_irq(int irq, void *devid)
@@ -444,9 +477,9 @@ static int pxamci_probe(struct platform_device *pdev)
mmc->max_seg_size = PAGE_SIZE;
/*
- * Block length register is 10 bits.
+ * Block length register is only 10 bits before PXA27x.
*/
- mmc->max_blk_size = 1023;
+ mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048;
/*
* Block count register is 16 bits.
@@ -460,6 +493,12 @@ static int pxamci_probe(struct platform_device *pdev)
mmc->ocr_avail = host->pdata ?
host->pdata->ocr_mask :
MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = 0;
+ host->cmdat = 0;
+ if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {
+ mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+ host->cmdat |= CMDAT_SDIO_INT_EN;
+ }
host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index df17c281278a..3153e779d46a 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -25,6 +25,8 @@
#define SPI_EN (1 << 0)
#define MMC_CMDAT 0x0010
+#define CMDAT_SDIO_INT_EN (1 << 11)
+#define CMDAT_SD_4DAT (1 << 8)
#define CMDAT_DMAEN (1 << 7)
#define CMDAT_INIT (1 << 6)
#define CMDAT_BUSY (1 << 5)
diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c
new file mode 100644
index 000000000000..1e8704533bc5
--- /dev/null
+++ b/drivers/mmc/host/ricoh_mmc.c
@@ -0,0 +1,151 @@
+/*
+ * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
+ *
+ * Copyright (C) 2007 Philip Langdale, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/*
+ * This is a conceptually ridiculous driver, but it is required by the way
+ * the Ricoh multi-function R5C832 works. This chip implements firewire
+ * and four different memory card controllers. Two of those controllers are
+ * an SDHCI controller and a proprietary MMC controller. The linux SDHCI
+ * driver supports MMC cards but the chip detects MMC cards in hardware
+ * and directs them to the MMC controller - so the SDHCI driver never sees
+ * them. To get around this, we must disable the useless MMC controller.
+ * At that point, the SDHCI controller will start seeing them. As a bonus,
+ * a detection event occurs immediately, even if the MMC card is already
+ * in the reader.
+ *
+ * The relevant registers live on the firewire function, so this is unavoidably
+ * ugly. Such is life.
+ */
+
+#include <linux/pci.h>
+
+#define DRIVER_NAME "ricoh-mmc"
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+ {
+ .vendor = PCI_VENDOR_ID_RICOH,
+ .device = PCI_DEVICE_ID_RICOH_R5C843,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ u8 rev;
+
+ struct pci_dev *fw_dev = NULL;
+
+ BUG_ON(pdev == NULL);
+ BUG_ON(ent == NULL);
+
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
+ pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
+ (int)rev);
+
+ while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
+ if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
+ pdev->bus == fw_dev->bus) {
+ u8 write_enable;
+ u8 disable;
+
+ pci_read_config_byte(fw_dev, 0xCB, &disable);
+ if (disable & 0x02) {
+ printk(KERN_INFO DRIVER_NAME
+ ": Controller already disabled. Nothing to do.\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(fw_dev, 0xCA, &write_enable);
+ pci_write_config_byte(fw_dev, 0xCA, 0x57);
+ pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
+ pci_write_config_byte(fw_dev, 0xCA, write_enable);
+
+ pci_set_drvdata(pdev, fw_dev);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": Controller is now disabled.\n");
+
+ break;
+ }
+ }
+
+ if (pci_get_drvdata(pdev) == NULL) {
+ printk(KERN_WARNING DRIVER_NAME
+ ": Main firewire function not found. Cannot disable controller.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
+{
+ u8 write_enable;
+ u8 disable;
+ struct pci_dev *fw_dev = NULL;
+
+ fw_dev = pci_get_drvdata(pdev);
+ BUG_ON(fw_dev == NULL);
+
+ pci_read_config_byte(fw_dev, 0xCA, &write_enable);
+ pci_read_config_byte(fw_dev, 0xCB, &disable);
+ pci_write_config_byte(fw_dev, 0xCA, 0x57);
+ pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
+ pci_write_config_byte(fw_dev, 0xCA, write_enable);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": Controller is now re-enabled.\n");
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver ricoh_mmc_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pci_ids,
+ .probe = ricoh_mmc_probe,
+ .remove = __devexit_p(ricoh_mmc_remove),
+};
+
+/*****************************************************************************\
+ * *
+ * Driver init/exit *
+ * *
+\*****************************************************************************/
+
+static int __init ricoh_mmc_drv_init(void)
+{
+ printk(KERN_INFO DRIVER_NAME
+ ": Ricoh MMC Controller disabling driver\n");
+ printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
+
+ return pci_register_driver(&ricoh_mmc_driver);
+}
+
+static void __exit ricoh_mmc_drv_exit(void)
+{
+ pci_unregister_driver(&ricoh_mmc_driver);
+}
+
+module_init(ricoh_mmc_drv_init);
+module_exit(ricoh_mmc_drv_exit);
+
+MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
+MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 10d15c39d003..b397121b947d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
+ * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
@@ -25,8 +25,6 @@
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-static unsigned int debug_nodma = 0;
-static unsigned int debug_forcedma = 0;
static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
@@ -34,6 +32,8 @@ static unsigned int debug_quirks = 0;
/* Controller doesn't like some resets when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
+#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -67,7 +67,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_ENE_CB712_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_BROKEN_DMA,
},
{
@@ -75,7 +76,26 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_ENE_CB712_SD_2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_BROKEN_DMA,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_ENE,
+ .device = PCI_DEVICE_ID_ENE_CB714_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_ENE,
+ .device = PCI_DEVICE_ID_ENE_CB714_SD_2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
},
{ /* Generic SD host controller */
@@ -113,7 +133,7 @@ static void sdhci_dumpregs(struct sdhci_host *host)
readb(host->ioaddr + SDHCI_POWER_CONTROL),
readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
- readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
+ readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL),
readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
@@ -361,16 +381,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
if (data == NULL)
return;
- DBG("blksz %04x blks %04x flags %08x\n",
- data->blksz, data->blocks, data->flags);
- DBG("tsac %d ms nsac %d clk\n",
- data->timeout_ns / 1000000, data->timeout_clks);
-
/* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288);
BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
+ host->data = data;
+ host->data_early = 0;
+
/* timeout in us */
target_timeout = data->timeout_ns / 1000 +
data->timeout_clks / host->clock;
@@ -429,11 +447,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
{
u16 mode;
- WARN_ON(host->data);
-
if (data == NULL)
return;
+ WARN_ON(!host->data);
+
mode = SDHCI_TRNS_BLK_CNT_EN;
if (data->blocks > 1)
mode |= SDHCI_TRNS_MULTI;
@@ -463,27 +481,25 @@ static void sdhci_finish_data(struct sdhci_host *host)
/*
* Controller doesn't count down when in single block mode.
*/
- if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
- blocks = 0;
+ if (data->blocks == 1)
+ blocks = (data->error == 0) ? 0 : 1;
else
blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
data->bytes_xfered = data->blksz * (data->blocks - blocks);
- if ((data->error == MMC_ERR_NONE) && blocks) {
+ if (!data->error && blocks) {
printk(KERN_ERR "%s: Controller signalled completion even "
"though there were blocks left.\n",
mmc_hostname(host->mmc));
- data->error = MMC_ERR_FAILED;
+ data->error = -EIO;
}
- DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
if (data->stop) {
/*
* The controller needs a reset of internal state machines
* upon error conditions.
*/
- if (data->error != MMC_ERR_NONE) {
+ if (data->error) {
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
}
@@ -501,8 +517,6 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
WARN_ON(host->cmd);
- DBG("Sending cmd (%x)\n", cmd->opcode);
-
/* Wait max 10 ms */
timeout = 10;
@@ -520,7 +534,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
printk(KERN_ERR "%s: Controller never released "
"inhibit bit(s).\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
- cmd->error = MMC_ERR_FAILED;
+ cmd->error = -EIO;
tasklet_schedule(&host->finish_tasklet);
return;
}
@@ -541,7 +555,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
printk(KERN_ERR "%s: Unsupported response type!\n",
mmc_hostname(host->mmc));
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EINVAL;
tasklet_schedule(&host->finish_tasklet);
return;
}
@@ -588,13 +602,12 @@ static void sdhci_finish_command(struct sdhci_host *host)
}
}
- host->cmd->error = MMC_ERR_NONE;
+ host->cmd->error = 0;
- DBG("Ending cmd (%x)\n", host->cmd->opcode);
+ if (host->data && host->data_early)
+ sdhci_finish_data(host);
- if (host->cmd->data)
- host->data = host->cmd->data;
- else
+ if (!host->cmd->data)
tasklet_schedule(&host->finish_tasklet);
host->cmd = NULL;
@@ -710,7 +723,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
- host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+ host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
} else
sdhci_send_command(host, mrq->cmd);
@@ -759,6 +772,14 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ /*
+ * Some (ENE) controllers go apeshit on some ios operation,
+ * signalling timeout and CRC errors even on CMD0. Resetting
+ * it on each ios seems to solve the problem.
+ */
+ if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
+ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -780,10 +801,35 @@ static int sdhci_get_ro(struct mmc_host *mmc)
return !(present & SDHCI_WRITE_PROTECT);
}
+static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct sdhci_host *host;
+ unsigned long flags;
+ u32 ier;
+
+ host = mmc_priv(mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
+
+ ier &= ~SDHCI_INT_CARD_INT;
+ if (enable)
+ ier |= SDHCI_INT_CARD_INT;
+
+ writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
+ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+ mmiowb();
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
+ .enable_sdio_irq = sdhci_enable_sdio_irq,
};
/*****************************************************************************\
@@ -811,7 +857,7 @@ static void sdhci_tasklet_card(unsigned long param)
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
- host->mrq->cmd->error = MMC_ERR_FAILED;
+ host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
}
}
@@ -835,15 +881,13 @@ static void sdhci_tasklet_finish(unsigned long param)
mrq = host->mrq;
- DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
/*
* The controller needs a reset of internal state machines
* upon error conditions.
*/
- if ((mrq->cmd->error != MMC_ERR_NONE) ||
- (mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
- (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+ if (mrq->cmd->error ||
+ (mrq->data && (mrq->data->error ||
+ (mrq->data->stop && mrq->data->stop->error)))) {
/* Some controllers need this kick or reset won't work here */
if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
@@ -888,13 +932,13 @@ static void sdhci_timeout_timer(unsigned long data)
sdhci_dumpregs(host);
if (host->data) {
- host->data->error = MMC_ERR_TIMEOUT;
+ host->data->error = -ETIMEDOUT;
sdhci_finish_data(host);
} else {
if (host->cmd)
- host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
else
- host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+ host->mrq->cmd->error = -ETIMEDOUT;
tasklet_schedule(&host->finish_tasklet);
}
@@ -915,27 +959,23 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
BUG_ON(intmask == 0);
if (!host->cmd) {
- printk(KERN_ERR "%s: Got command interrupt even though no "
- "command operation was in progress.\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
+ "though no command operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_dumpregs(host);
return;
}
- if (intmask & SDHCI_INT_RESPONSE)
- sdhci_finish_command(host);
- else {
- if (intmask & SDHCI_INT_TIMEOUT)
- host->cmd->error = MMC_ERR_TIMEOUT;
- else if (intmask & SDHCI_INT_CRC)
- host->cmd->error = MMC_ERR_BADCRC;
- else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
- host->cmd->error = MMC_ERR_FAILED;
- else
- host->cmd->error = MMC_ERR_INVALID;
+ if (intmask & SDHCI_INT_TIMEOUT)
+ host->cmd->error = -ETIMEDOUT;
+ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+ SDHCI_INT_INDEX))
+ host->cmd->error = -EILSEQ;
+ if (host->cmd->error)
tasklet_schedule(&host->finish_tasklet);
- }
+ else if (intmask & SDHCI_INT_RESPONSE)
+ sdhci_finish_command(host);
}
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
@@ -950,22 +990,20 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (intmask & SDHCI_INT_DATA_END)
return;
- printk(KERN_ERR "%s: Got data interrupt even though no "
- "data operation was in progress.\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
+ "though no data operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_dumpregs(host);
return;
}
if (intmask & SDHCI_INT_DATA_TIMEOUT)
- host->data->error = MMC_ERR_TIMEOUT;
- else if (intmask & SDHCI_INT_DATA_CRC)
- host->data->error = MMC_ERR_BADCRC;
- else if (intmask & SDHCI_INT_DATA_END_BIT)
- host->data->error = MMC_ERR_FAILED;
+ host->data->error = -ETIMEDOUT;
+ else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
+ host->data->error = -EILSEQ;
- if (host->data->error != MMC_ERR_NONE)
+ if (host->data->error)
sdhci_finish_data(host);
else {
if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
@@ -980,8 +1018,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
host->ioaddr + SDHCI_DMA_ADDRESS);
- if (intmask & SDHCI_INT_DATA_END)
- sdhci_finish_data(host);
+ if (intmask & SDHCI_INT_DATA_END) {
+ if (host->cmd) {
+ /*
+ * Data managed to finish before the
+ * command completed. Make sure we do
+ * things in the proper order.
+ */
+ host->data_early = 1;
+ } else {
+ sdhci_finish_data(host);
+ }
+ }
}
}
@@ -990,6 +1038,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
irqreturn_t result;
struct sdhci_host* host = dev_id;
u32 intmask;
+ int cardint = 0;
spin_lock(&host->lock);
@@ -1024,6 +1073,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+ intmask &= ~SDHCI_INT_ERROR;
+
if (intmask & SDHCI_INT_BUS_POWER) {
printk(KERN_ERR "%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc));
@@ -1032,6 +1083,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= ~SDHCI_INT_BUS_POWER;
+ if (intmask & SDHCI_INT_CARD_INT)
+ cardint = 1;
+
+ intmask &= ~SDHCI_INT_CARD_INT;
+
if (intmask) {
printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), intmask);
@@ -1046,6 +1102,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
out:
spin_unlock(&host->lock);
+ /*
+ * We have to delay this as it calls back into the driver.
+ */
+ if (cardint)
+ mmc_signal_sdio_irq(host->mmc);
+
return result;
}
@@ -1231,20 +1293,26 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
- if (debug_nodma)
- DBG("DMA forced off\n");
- else if (debug_forcedma) {
- DBG("DMA forced on\n");
+ if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
host->flags |= SDHCI_USE_DMA;
- } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
- host->flags |= SDHCI_USE_DMA;
- else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
- DBG("Controller doesn't have DMA interface\n");
else if (!(caps & SDHCI_CAN_DO_DMA))
DBG("Controller doesn't have DMA capability\n");
else
host->flags |= SDHCI_USE_DMA;
+ if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+ (host->flags & SDHCI_USE_DMA)) {
+ DBG("Disabling DMA as it is marked broken");
+ host->flags &= ~SDHCI_USE_DMA;
+ }
+
+ if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
+ (host->flags & SDHCI_USE_DMA)) {
+ printk(KERN_WARNING "%s: Will use DMA "
+ "mode even though HW doesn't fully "
+ "claim to support it.\n", host->slot_descr);
+ }
+
if (host->flags & SDHCI_USE_DMA) {
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "%s: No suitable DMA available. "
@@ -1285,7 +1353,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ops = &sdhci_ops;
mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ;
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
@@ -1334,12 +1402,11 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
*/
mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
if (mmc->max_blk_size >= 3) {
- printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
host->slot_descr);
- ret = -ENODEV;
- goto unmap;
- }
- mmc->max_blk_size = 512 << mmc->max_blk_size;
+ mmc->max_blk_size = 512;
+ } else
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
/*
* Maximum block count.
@@ -1539,14 +1606,10 @@ static void __exit sdhci_drv_exit(void)
module_init(sdhci_drv_init);
module_exit(sdhci_drv_exit);
-module_param(debug_nodma, uint, 0444);
-module_param(debug_forcedma, uint, 0444);
module_param(debug_quirks, uint, 0444);
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7400f4bc114f..05195ea900f4 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
+ * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
@@ -81,7 +81,7 @@
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
-#define SDHCI_WALK_UP_CONTROL 0x2B
+#define SDHCI_WAKE_UP_CONTROL 0x2B
#define SDHCI_CLOCK_CONTROL 0x2C
#define SDHCI_DIVIDER_SHIFT 8
@@ -107,6 +107,7 @@
#define SDHCI_INT_CARD_INSERT 0x00000040
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_INT 0x00000100
+#define SDHCI_INT_ERROR 0x00008000
#define SDHCI_INT_TIMEOUT 0x00010000
#define SDHCI_INT_CRC 0x00020000
#define SDHCI_INT_END_BIT 0x00040000
@@ -181,6 +182,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 */
struct scatterlist *cur_sg; /* We're working on this */
int num_sg; /* Entries left */
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 8b736e968447..9b904795eb77 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
#include <linux/mmc/host.h>
#include <linux/highmem.h>
#include <linux/scatterlist.h>
+#include <linux/log2.h>
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
@@ -404,14 +405,14 @@ static void tifm_sd_check_status(struct tifm_sd *host)
struct tifm_dev *sock = host->dev;
struct mmc_command *cmd = host->req->cmd;
- if (cmd->error != MMC_ERR_NONE)
+ if (cmd->error)
goto finish_request;
if (!(host->cmd_flags & CMD_READY))
return;
if (cmd->data) {
- if (cmd->data->error != MMC_ERR_NONE) {
+ if (cmd->data->error) {
if ((host->cmd_flags & SCMD_ACTIVE)
&& !(host->cmd_flags & SCMD_READY))
return;
@@ -504,7 +505,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
{
struct tifm_sd *host;
unsigned int host_status = 0;
- int cmd_error = MMC_ERR_NONE;
+ int cmd_error = 0;
struct mmc_command *cmd = NULL;
unsigned long flags;
@@ -521,15 +522,15 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
writel(host_status & TIFM_MMCSD_ERRMASK,
sock->addr + SOCK_MMCSD_STATUS);
if (host_status & TIFM_MMCSD_CTO)
- cmd_error = MMC_ERR_TIMEOUT;
+ cmd_error = -ETIMEDOUT;
else if (host_status & TIFM_MMCSD_CCRC)
- cmd_error = MMC_ERR_BADCRC;
+ cmd_error = -EILSEQ;
if (cmd->data) {
if (host_status & TIFM_MMCSD_DTO)
- cmd->data->error = MMC_ERR_TIMEOUT;
+ cmd->data->error = -ETIMEDOUT;
else if (host_status & TIFM_MMCSD_DCRC)
- cmd->data->error = MMC_ERR_BADCRC;
+ cmd->data->error = -EILSEQ;
}
writel(TIFM_FIFO_INT_SETALL,
@@ -626,14 +627,21 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_lock_irqsave(&sock->lock, flags);
if (host->eject) {
- spin_unlock_irqrestore(&sock->lock, flags);
+ mrq->cmd->error = -ENOMEDIUM;
goto err_out;
}
if (host->req) {
printk(KERN_ERR "%s : unfinished request detected\n",
sock->dev.bus_id);
- spin_unlock_irqrestore(&sock->lock, flags);
+ mrq->cmd->error = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+ printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
+ sock->dev.bus_id, mrq->data->blksz);
+ mrq->cmd->error = -EINVAL;
goto err_out;
}
@@ -722,7 +730,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
return;
err_out:
- mrq->cmd->error = MMC_ERR_TIMEOUT;
+ spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, mrq);
}
@@ -1012,9 +1020,9 @@ static void tifm_sd_remove(struct tifm_dev *sock)
writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
- host->req->cmd->error = MMC_ERR_TIMEOUT;
+ host->req->cmd->error = -ENOMEDIUM;
if (host->req->stop)
- host->req->stop->error = MMC_ERR_TIMEOUT;
+ host->req->stop->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
}
spin_unlock_irqrestore(&sock->lock, flags);
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index 867ca6a69298..80db11c05f2a 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
+ * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
*
* Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
*
@@ -207,8 +207,6 @@ static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
{
unsigned long dmaflags;
- DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
if (host->dma >= 0) {
/*
* Release ISA DMA controller.
@@ -319,7 +317,7 @@ static inline void wbsd_get_short_reply(struct wbsd_host *host,
* Correct response type?
*/
if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EILSEQ;
return;
}
@@ -339,7 +337,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host *host,
* Correct response type?
*/
if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EILSEQ;
return;
}
@@ -360,8 +358,6 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
int i;
u8 status, isr;
- DBGF("Sending cmd (%x)\n", cmd->opcode);
-
/*
* Clear accumulated ISR. The interrupt routine
* will fill this one with events that occur during
@@ -376,7 +372,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
for (i = 3; i >= 0; i--)
outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
/*
* Wait for the request to complete.
@@ -396,13 +392,13 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
/* Card removed? */
if (isr & WBSD_INT_CARD)
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ENOMEDIUM;
/* Timeout? */
else if (isr & WBSD_INT_TIMEOUT)
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
/* CRC? */
else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
/* All ok */
else {
if (cmd->flags & MMC_RSP_136)
@@ -411,8 +407,6 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
wbsd_get_short_reply(host, cmd);
}
}
-
- DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
}
/*
@@ -550,11 +544,6 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
unsigned long dmaflags;
unsigned int size;
- DBGF("blksz %04x blks %04x flags %08x\n",
- data->blksz, data->blocks, data->flags);
- DBGF("tsac %d ms nsac %d clk\n",
- data->timeout_ns / 1000000, data->timeout_clks);
-
/*
* Calculate size.
*/
@@ -596,7 +585,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
} else {
- data->error = MMC_ERR_INVALID;
+ data->error = -EINVAL;
return;
}
@@ -618,7 +607,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
*/
BUG_ON(size > 0x10000);
if (size > 0x10000) {
- data->error = MMC_ERR_INVALID;
+ data->error = -EINVAL;
return;
}
@@ -680,7 +669,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
}
}
- data->error = MMC_ERR_NONE;
+ data->error = 0;
}
static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
@@ -735,8 +724,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
"%d bytes left.\n",
mmc_hostname(host->mmc), count);
- if (data->error == MMC_ERR_NONE)
- data->error = MMC_ERR_FAILED;
+ if (!data->error)
+ data->error = -EIO;
} else {
/*
* Transfer data from DMA buffer to
@@ -746,14 +735,12 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
wbsd_dma_to_sg(host, data);
}
- if (data->error != MMC_ERR_NONE) {
+ if (data->error) {
if (data->bytes_xfered)
data->bytes_xfered -= data->blksz;
}
}
- DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
wbsd_request_end(host, host->mrq);
}
@@ -780,11 +767,10 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
/*
- * If there is no card in the slot then
- * timeout immediatly.
+ * Check that there is actually a card in the slot.
*/
if (!(host->flags & WBSD_FCARD_PRESENT)) {
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ENOMEDIUM;
goto done;
}
@@ -820,7 +806,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
"supported by this controller.\n",
mmc_hostname(host->mmc), cmd->opcode);
#endif
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EINVAL;
goto done;
};
@@ -832,7 +818,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (cmd->data) {
wbsd_prepare_data(host, cmd->data);
- if (cmd->data->error != MMC_ERR_NONE)
+ if (cmd->data->error)
goto done;
}
@@ -843,7 +829,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
* will be finished after the data has
* transfered.
*/
- if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
+ if (cmd->data && !cmd->error) {
/*
* Dirty fix for hardware bug.
*/
@@ -1046,7 +1032,7 @@ static void wbsd_tasklet_card(unsigned long param)
mmc_hostname(host->mmc));
wbsd_reset(host);
- host->mrq->cmd->error = MMC_ERR_FAILED;
+ host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
}
@@ -1110,7 +1096,7 @@ static void wbsd_tasklet_crc(unsigned long param)
DBGF("CRC error\n");
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
tasklet_schedule(&host->finish_tasklet);
@@ -1134,7 +1120,7 @@ static void wbsd_tasklet_timeout(unsigned long param)
DBGF("Timeout\n");
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
tasklet_schedule(&host->finish_tasklet);
@@ -1233,7 +1219,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
spin_lock_init(&host->lock);
@@ -1279,7 +1265,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
return 0;
}
-static void __devexit wbsd_free_mmc(struct device *dev)
+static void wbsd_free_mmc(struct device *dev)
{
struct mmc_host *mmc;
struct wbsd_host *host;
@@ -1371,7 +1357,7 @@ static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
return 0;
}
-static void __devexit wbsd_release_regions(struct wbsd_host *host)
+static void wbsd_release_regions(struct wbsd_host *host)
{
if (host->base)
release_region(host->base, 8);
@@ -1447,7 +1433,7 @@ err:
"Falling back on FIFO.\n", dma);
}
-static void __devexit wbsd_release_dma(struct wbsd_host *host)
+static void wbsd_release_dma(struct wbsd_host *host)
{
if (host->dma_addr) {
dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
@@ -1497,7 +1483,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
return 0;
}
-static void __devexit wbsd_release_irq(struct wbsd_host *host)
+static void wbsd_release_irq(struct wbsd_host *host)
{
if (!host->irq)
return;
@@ -1548,7 +1534,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host *host,
* Release all resources for the host.
*/
-static void __devexit wbsd_release_resources(struct wbsd_host *host)
+static void wbsd_release_resources(struct wbsd_host *host)
{
wbsd_release_dma(host);
wbsd_release_irq(host);
diff --git a/drivers/mmc/host/wbsd.h b/drivers/mmc/host/wbsd.h
index 873bda1e59b4..0877866f8d28 100644
--- a/drivers/mmc/host/wbsd.h
+++ b/drivers/mmc/host/wbsd.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
+ * linux/drivers/mmc/host/wbsd.h - Winbond W83L51xD SD/MMC driver
*
* Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
*
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 451adcc52b3c..6d958a4566ff 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -3,9 +3,9 @@
#
# Core functionality.
+obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o
mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
-obj-$(CONFIG_MTD) += $(mtd-y)
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
index b96ac8e119dc..54aa75907640 100644
--- a/drivers/mtd/devices/docprobe.c
+++ b/drivers/mtd/devices/docprobe.c
@@ -81,9 +81,6 @@ static unsigned long __initdata doc_locations[] = {
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#elif defined(__PPC__)
0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT)
- 0x2f000000,
- 0xff000000,
#elif defined(CONFIG_MOMENCO_OCELOT_G)
0xff000000,
##else
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index f88ebc5b685e..6cd132c75187 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -103,7 +103,7 @@ config MTD_PMC_MSP_RAMROOT
config MTD_SUN_UFLASH
tristate "Sun Microsystems userflash support"
- depends on SPARC && MTD_CFI
+ depends on SPARC && MTD_CFI && PCI
help
This provides a 'mapping' driver which supports the way in
which user-programmable flash chips are connected on various
@@ -362,7 +362,7 @@ config MTD_WALNUT
config MTD_EBONY
tristate "Flash devices mapped on IBM 440GP Ebony"
- depends on MTD_JEDECPROBE && EBONY
+ depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE
help
This enables access routines for the flash chips on the IBM 440GP
Ebony board. If you have one of these boards and would like to
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c
index 1aa0447c5e66..e8560683b973 100644
--- a/drivers/mtd/maps/lubbock-flash.c
+++ b/drivers/mtd/maps/lubbock-flash.c
@@ -15,9 +15,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
@@ -26,7 +24,7 @@
#include <asm/hardware.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/lubbock.h>
-
+#include <asm/cacheflush.h>
#define ROM_ADDR 0x00000000
#define FLASH_ADDR 0x04000000
@@ -35,7 +33,7 @@
static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
{
- consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+ flush_ioremap_region(map->phys, map->cached, from, len);
}
static struct map_info lubbock_maps[2] = { {
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
index eaa4bbb868a3..d76487d82dcd 100644
--- a/drivers/mtd/maps/mainstone-flash.c
+++ b/drivers/mtd/maps/mainstone-flash.c
@@ -15,8 +15,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@@ -26,6 +24,7 @@
#include <asm/hardware.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/mainstone.h>
+#include <asm/cacheflush.h>
#define ROM_ADDR 0x00000000
@@ -36,7 +35,7 @@
static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
ssize_t len)
{
- consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+ flush_ioremap_region(map->phys, map->cached, from, len);
}
static struct map_info mainstone_maps[2] = { {
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index bbb42c35b69b..cf75a566442e 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -1,9 +1,12 @@
/*
- * Normal mappings of chips in physical memory for OF devices
+ * Flash mappings described by the OF (or flattened) device tree
*
* Copyright (C) 2006 MontaVista Software Inc.
* Author: Vitaly Wool <vwool@ru.mvista.com>
*
+ * Revised to handle newer style flash binding by:
+ * Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -12,102 +15,157 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
-struct physmap_flash_info {
+struct of_flash {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
#ifdef CONFIG_MTD_PARTITIONS
- int nr_parts;
struct mtd_partition *parts;
#endif
};
-static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
#ifdef CONFIG_MTD_PARTITIONS
-static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
-#endif
+#define OF_FLASH_PARTS(info) ((info)->parts)
-#ifdef CONFIG_MTD_PARTITIONS
-static int parse_flash_partitions(struct device_node *node,
- struct mtd_partition **parts)
+static int parse_obsolete_partitions(struct of_device *dev,
+ struct of_flash *info,
+ struct device_node *dp)
{
- int i, plen, retval = -ENOMEM;
- const u32 *part;
- const char *name;
-
- part = of_get_property(node, "partitions", &plen);
- if (part == NULL)
- goto err;
-
- retval = plen / (2 * sizeof(u32));
- *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL);
- if (*parts == NULL) {
- printk(KERN_ERR "Can't allocate the flash partition data!\n");
- goto err;
- }
+ int i, plen, nr_parts;
+ const struct {
+ u32 offset, len;
+ } *part;
+ const char *names;
+
+ part = of_get_property(dp, "partitions", &plen);
+ if (!part)
+ return 0; /* No partitions found */
+
+ dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
+
+ nr_parts = plen / sizeof(part[0]);
+
+ info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
+ if (!info->parts)
+ return -ENOMEM;
- name = of_get_property(node, "partition-names", &plen);
+ names = of_get_property(dp, "partition-names", &plen);
- for (i = 0; i < retval; i++) {
- (*parts)[i].offset = *part++;
- (*parts)[i].size = *part & ~1;
- if (*part++ & 1) /* bit 0 set signifies read only partition */
- (*parts)[i].mask_flags = MTD_WRITEABLE;
+ for (i = 0; i < nr_parts; i++) {
+ info->parts[i].offset = part->offset;
+ info->parts[i].size = part->len & ~1;
+ if (part->len & 1) /* bit 0 set signifies read only partition */
+ info->parts[i].mask_flags = MTD_WRITEABLE;
- if (name != NULL && plen > 0) {
- int len = strlen(name) + 1;
+ if (names && (plen > 0)) {
+ int len = strlen(names) + 1;
- (*parts)[i].name = (char *)name;
+ info->parts[i].name = (char *)names;
plen -= len;
- name += len;
- } else
- (*parts)[i].name = "unnamed";
+ names += len;
+ } else {
+ info->parts[i].name = "unnamed";
+ }
+
+ part++;
}
-err:
- return retval;
+
+ return nr_parts;
}
-#endif
-static int of_physmap_remove(struct of_device *dev)
+static int __devinit parse_partitions(struct of_flash *info,
+ struct of_device *dev)
+{
+ const char *partname;
+ static const char *part_probe_types[]
+ = { "cmdlinepart", "RedBoot", NULL };
+ struct device_node *dp = dev->node, *pp;
+ int nr_parts, i;
+
+ /* First look for RedBoot table or partitions on the command
+ * line, these take precedence over device tree information */
+ nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
+ &info->parts, 0);
+ if (nr_parts > 0) {
+ add_mtd_partitions(info->mtd, info->parts, nr_parts);
+ return 0;
+ }
+
+ /* First count the subnodes */
+ nr_parts = 0;
+ for (pp = dp->child; pp; pp = pp->sibling)
+ nr_parts++;
+
+ if (nr_parts == 0)
+ return parse_obsolete_partitions(dev, info, dp);
+
+ info->parts = kzalloc(nr_parts * sizeof(*info->parts),
+ GFP_KERNEL);
+ if (!info->parts)
+ return -ENOMEM;
+
+ for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
+ const u32 *reg;
+ int len;
+
+ reg = of_get_property(pp, "reg", &len);
+ if (!reg || (len != 2*sizeof(u32))) {
+ dev_err(&dev->dev, "Invalid 'reg' on %s\n",
+ dp->full_name);
+ kfree(info->parts);
+ info->parts = NULL;
+ return -EINVAL;
+ }
+ info->parts[i].offset = reg[0];
+ info->parts[i].size = reg[1];
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+ info->parts[i].name = (char *)partname;
+
+ if (of_get_property(pp, "read-only", &len))
+ info->parts[i].mask_flags = MTD_WRITEABLE;
+ }
+
+ return nr_parts;
+}
+#else /* MTD_PARTITIONS */
+#define OF_FLASH_PARTS(info) (0)
+#define parse_partitions(info, dev) (0)
+#endif /* MTD_PARTITIONS */
+
+static int of_flash_remove(struct of_device *dev)
{
- struct physmap_flash_info *info;
+ struct of_flash *info;
info = dev_get_drvdata(&dev->dev);
- if (info == NULL)
+ if (!info)
return 0;
dev_set_drvdata(&dev->dev, NULL);
- if (info->mtd != NULL) {
-#ifdef CONFIG_MTD_PARTITIONS
- if (info->nr_parts) {
+ if (info->mtd) {
+ if (OF_FLASH_PARTS(info)) {
del_mtd_partitions(info->mtd);
- kfree(info->parts);
+ kfree(OF_FLASH_PARTS(info));
} else {
del_mtd_device(info->mtd);
}
-#else
- del_mtd_device(info->mtd);
-#endif
map_destroy(info->mtd);
}
- if (info->map.virt != NULL)
+ if (info->map.virt)
iounmap(info->map.virt);
- if (info->res != NULL) {
+ if (info->res) {
release_resource(info->res);
kfree(info->res);
}
@@ -115,48 +173,79 @@ static int of_physmap_remove(struct of_device *dev)
return 0;
}
-static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match)
+/* Helper function to handle probing of the obsolete "direct-mapped"
+ * compatible binding, which has an extra "probe-type" property
+ * describing the type of flash probe necessary. */
+static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
+ struct map_info *map)
{
struct device_node *dp = dev->node;
- struct resource res;
- struct physmap_flash_info *info;
- const char **probe_type;
const char *of_probe;
+ struct mtd_info *mtd;
+ static const char *rom_probe_types[]
+ = { "cfi_probe", "jedec_probe", "map_rom"};
+ int i;
+
+ dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
+ "flash binding\n");
+
+ of_probe = of_get_property(dp, "probe-type", NULL);
+ if (!of_probe) {
+ for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
+ mtd = do_map_probe(rom_probe_types[i], map);
+ if (mtd)
+ return mtd;
+ }
+ return NULL;
+ } else if (strcmp(of_probe, "CFI") == 0) {
+ return do_map_probe("cfi_probe", map);
+ } else if (strcmp(of_probe, "JEDEC") == 0) {
+ return do_map_probe("jedec_probe", map);
+ } else {
+ if (strcmp(of_probe, "ROM") != 0)
+ dev_warn(&dev->dev, "obsolete_probe: don't know probe "
+ "type '%s', mapping as rom\n", of_probe);
+ return do_map_probe("mtd_rom", map);
+ }
+}
+
+static int __devinit of_flash_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct device_node *dp = dev->node;
+ struct resource res;
+ struct of_flash *info;
+ const char *probe_type = match->data;
const u32 *width;
int err;
-
+ err = -ENXIO;
if (of_address_to_resource(dp, 0, &res)) {
- dev_err(&dev->dev, "Can't get the flash mapping!\n");
- err = -EINVAL;
+ dev_err(&dev->dev, "Can't get IO address from device tree\n");
goto err_out;
}
- dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n",
- (unsigned long long)res.end - res.start + 1,
- (unsigned long long)res.start);
+ dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
+ (unsigned long long)res.start, (unsigned long long)res.end);
- info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
- if (info == NULL) {
- err = -ENOMEM;
+ err = -ENOMEM;
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
goto err_out;
- }
memset(info, 0, sizeof(*info));
dev_set_drvdata(&dev->dev, info);
+ err = -EBUSY;
info->res = request_mem_region(res.start, res.end - res.start + 1,
- dev->dev.bus_id);
- if (info->res == NULL) {
- dev_err(&dev->dev, "Could not reserve memory region\n");
- err = -ENOMEM;
+ dev->dev.bus_id);
+ if (!info->res)
goto err_out;
- }
+ err = -ENXIO;
width = of_get_property(dp, "bank-width", NULL);
- if (width == NULL) {
- dev_err(&dev->dev, "Can't get the flash bank width!\n");
- err = -EINVAL;
+ if (!width) {
+ dev_err(&dev->dev, "Can't get bank width from device tree\n");
goto err_out;
}
@@ -165,91 +254,87 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
info->map.size = res.end - res.start + 1;
info->map.bankwidth = *width;
+ err = -ENOMEM;
info->map.virt = ioremap(info->map.phys, info->map.size);
- if (info->map.virt == NULL) {
- dev_err(&dev->dev, "Failed to ioremap flash region\n");
- err = EIO;
+ if (!info->map.virt) {
+ dev_err(&dev->dev, "Failed to ioremap() flash region\n");
goto err_out;
}
simple_map_init(&info->map);
- of_probe = of_get_property(dp, "probe-type", NULL);
- if (of_probe == NULL) {
- probe_type = rom_probe_types;
- for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
- info->mtd = do_map_probe(*probe_type, &info->map);
- } else if (!strcmp(of_probe, "CFI"))
- info->mtd = do_map_probe("cfi_probe", &info->map);
- else if (!strcmp(of_probe, "JEDEC"))
- info->mtd = do_map_probe("jedec_probe", &info->map);
- else {
- if (strcmp(of_probe, "ROM"))
- dev_dbg(&dev->dev, "map_probe: don't know probe type "
- "'%s', mapping as rom\n", of_probe);
- info->mtd = do_map_probe("mtd_rom", &info->map);
- }
- if (info->mtd == NULL) {
- dev_err(&dev->dev, "map_probe failed\n");
- err = -ENXIO;
+ if (probe_type)
+ info->mtd = do_map_probe(probe_type, &info->map);
+ else
+ info->mtd = obsolete_probe(dev, &info->map);
+
+ err = -ENXIO;
+ if (!info->mtd) {
+ dev_err(&dev->dev, "do_map_probe() failed\n");
goto err_out;
}
info->mtd->owner = THIS_MODULE;
-#ifdef CONFIG_MTD_PARTITIONS
- err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
- if (err > 0) {
- add_mtd_partitions(info->mtd, info->parts, err);
- } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) {
- dev_info(&dev->dev, "Using OF partition information\n");
- add_mtd_partitions(info->mtd, info->parts, err);
- info->nr_parts = err;
- } else
-#endif
+ err = parse_partitions(info, dev);
+ if (err < 0)
+ goto err_out;
+
+ if (err > 0)
+ add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+ else
+ add_mtd_device(info->mtd);
- add_mtd_device(info->mtd);
return 0;
err_out:
- of_physmap_remove(dev);
+ of_flash_remove(dev);
return err;
-
- return 0;
-
-
}
-static struct of_device_id of_physmap_match[] = {
+static struct of_device_id of_flash_match[] = {
+ {
+ .compatible = "cfi-flash",
+ .data = (void *)"cfi_probe",
+ },
+ {
+ /* FIXME: JEDEC chips can't be safely and reliably
+ * probed, although the mtd code gets it right in
+ * practice most of the time. We should use the
+ * vendor and device ids specified by the binding to
+ * bypass the heuristic probe code, but the mtd layer
+ * provides, at present, no interface for doing so
+ * :(. */
+ .compatible = "jedec-flash",
+ .data = (void *)"jedec_probe",
+ },
{
.type = "rom",
.compatible = "direct-mapped"
},
{ },
};
+MODULE_DEVICE_TABLE(of, of_flash_match);
-MODULE_DEVICE_TABLE(of, of_physmap_match);
-
-
-static struct of_platform_driver of_physmap_flash_driver = {
- .name = "physmap-flash",
- .match_table = of_physmap_match,
- .probe = of_physmap_probe,
- .remove = of_physmap_remove,
+static struct of_platform_driver of_flash_driver = {
+ .name = "of-flash",
+ .match_table = of_flash_match,
+ .probe = of_flash_probe,
+ .remove = of_flash_remove,
};
-static int __init of_physmap_init(void)
+static int __init of_flash_init(void)
{
- return of_register_platform_driver(&of_physmap_flash_driver);
+ return of_register_platform_driver(&of_flash_driver);
}
-static void __exit of_physmap_exit(void)
+static void __exit of_flash_exit(void)
{
- of_unregister_platform_driver(&of_physmap_flash_driver);
+ of_unregister_platform_driver(&of_flash_driver);
}
-module_init(of_physmap_init);
-module_exit(of_physmap_exit);
+module_init(of_flash_init);
+module_exit(of_flash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
-MODULE_DESCRIPTION("Configurable MTD map driver for OF");
+MODULE_DESCRIPTION("Device tree based MTD map driver");
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 8c86b802f212..d091b2430b48 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 9c6236852942..6174a97d7902 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -560,7 +560,3 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
EXPORT_SYMBOL_GPL(parse_mtd_partitions);
EXPORT_SYMBOL_GPL(register_mtd_parser);
EXPORT_SYMBOL_GPL(deregister_mtd_parser);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("Generic support for partitioning of MTD devices");
diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c
index aca331971201..9b430f20b640 100644
--- a/drivers/mtd/mtdsuper.c
+++ b/drivers/mtd/mtdsuper.c
@@ -70,6 +70,8 @@ static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags,
DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n",
mtd->index, mtd->name);
+ sb->s_flags = flags;
+
ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
if (ret < 0) {
up_write(&sb->s_umount);
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 512e999177f7..b2a5672df6e0 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -128,7 +128,10 @@ static int __init at91_nand_probe(struct platform_device *pdev)
nand_chip->IO_ADDR_R = host->io_base;
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
- nand_chip->dev_ready = at91_nand_device_ready;
+
+ if (host->board->rdy_pin)
+ nand_chip->dev_ready = at91_nand_device_ready;
+
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
nand_chip->chip_delay = 20; /* 20us command delay time */
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index cff969d05d4a..6f32a35eb106 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -816,7 +816,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
}
static struct pci_device_id cafe_nand_tbl[] = {
- { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }
+ { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 },
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 17c868034aad..e96259f22cca 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -56,9 +56,6 @@ static unsigned long __initdata doc_locations[] = {
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#elif defined(__PPC__)
0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT)
- 0x2f000000,
- 0xff000000,
#elif defined(CONFIG_MOMENCO_OCELOT_G)
0xff000000,
#else
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
index 1daf8231aaef..0146cdc48039 100644
--- a/drivers/mtd/nand/edb7312.c
+++ b/drivers/mtd/nand/edb7312.c
@@ -74,7 +74,7 @@ static struct mtd_partition partition_info[] = {
/*
* hardware specific access to control-lines
*
- * NAND_NCE: bit 0 -> bit 7
+ * NAND_NCE: bit 0 -> bit 6 (bit 7 = 1)
* NAND_CLE: bit 1 -> bit 4
* NAND_ALE: bit 2 -> bit 5
*/
@@ -83,12 +83,12 @@ static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
struct nand_chip *chip = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
- unsigned char bits;
+ unsigned char bits = 0x80;
- bits = (ctrl & (NAND_CLE | NAND_ALE)) << 3;
- bits = (ctrl & NAND_NCE) << 7;
+ bits |= (ctrl & (NAND_CLE | NAND_ALE)) << 3;
+ bits |= (ctrl & NAND_NCE) ? 0x00 : 0x40;
- clps_writeb((clps_readb(ep7312_pxdr) & 0xB0) | 0x10,
+ clps_writeb((clps_readb(ep7312_pxdr) & 0xF0) | bits,
ep7312_pxdr);
}
if (cmd != NAND_CMD_NONE)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 7e68203fe1ba..24ac6778b1a8 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -24,6 +24,7 @@
* if we have HW ecc support.
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
+ * BBT table is not serialized, has to be fixed
*
* 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
@@ -360,6 +361,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* We write two bytes, so we dont have to mess with 16 bit
* access
*/
+ nand_get_device(chip, mtd, FL_WRITING);
ofs += mtd->oobsize;
chip->ops.len = chip->ops.ooblen = 2;
chip->ops.datbuf = NULL;
@@ -367,9 +369,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
chip->ops.ooboffs = chip->badblockpos & ~0x01;
ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+ nand_release_device(mtd);
}
if (!ret)
mtd->ecc_stats.badblocks++;
+
return ret;
}
@@ -768,7 +772,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
- int *eccpos = chip->ecc.layout->eccpos;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
chip->ecc.read_page_raw(mtd, chip, buf);
@@ -810,7 +814,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc;
uint8_t *ecc_code = chip->buffers->ecccode;
- int *eccpos = chip->ecc.layout->eccpos;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_READ);
@@ -1416,7 +1420,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
- int *eccpos = chip->ecc.layout->eccpos;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
/* Software ecc calculation */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
@@ -1442,7 +1446,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccsteps = chip->ecc.steps;
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
- int *eccpos = chip->ecc.layout->eccpos;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index d4b1ba8f23ef..006c03aacb55 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -779,6 +779,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
else {
if (!mtd->erasesize) {
printk(KERN_WARNING PREFIX "please provide block_size");
+ kfree(part);
return;
}
else
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 555d594d1811..1cb22bfae750 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -33,6 +33,7 @@
#include <linux/moduleparam.h>
#include <linux/stringify.h>
#include <linux/stat.h>
+#include <linux/log2.h>
#include "ubi.h"
/* Maximum length of the 'mtd=' parameter */
@@ -369,7 +370,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
out_wl:
ubi_wl_close(ubi);
out_vtbl:
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
out_si:
ubi_scan_destroy_si(si);
return err;
@@ -422,8 +423,7 @@ static int io_init(struct ubi_device *ubi)
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/* Make sure minimal I/O unit is power of 2 */
- if (ubi->min_io_size == 0 ||
- (ubi->min_io_size & (ubi->min_io_size - 1))) {
+ if (!is_power_of_2(ubi->min_io_size)) {
ubi_err("bad min. I/O unit");
return -EINVAL;
}
@@ -593,8 +593,6 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
if (err)
goto out_detach;
- ubi_devices_cnt += 1;
-
ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
@@ -624,12 +622,13 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
wake_up_process(ubi->bgt_thread);
}
+ ubi_devices_cnt += 1;
return 0;
out_detach:
ubi_eba_close(ubi);
ubi_wl_close(ubi);
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
out_free:
kfree(ubi);
out_mtd:
@@ -650,7 +649,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
uif_close(ubi);
ubi_eba_close(ubi);
ubi_wl_close(ubi);
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL;
@@ -686,13 +685,6 @@ static int __init ubi_init(void)
struct mtd_dev_param *p = &mtd_dev_param[i];
cond_resched();
-
- if (!p->name) {
- dbg_err("empty name");
- err = -EINVAL;
- goto out_detach;
- }
-
err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
if (err)
goto out_detach;
@@ -799,7 +791,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
/* Get rid of the final newline */
if (buf[len - 1] == '\n')
- buf[len - 1] = 0;
+ buf[len - 1] = '\0';
for (i = 0; i < 3; i++)
tokens[i] = strsep(&pbuf, ",");
@@ -809,9 +801,6 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
return -EINVAL;
}
- if (tokens[0] == '\0')
- return -EINVAL;
-
p = &mtd_dev_param[mtd_devs];
strcpy(&p->name[0], tokens[0]);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 6612eb79bf17..fe4da1e96c52 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -64,6 +64,7 @@ static struct ubi_device *major_to_device(int major)
if (ubi_devices[i] && ubi_devices[i]->major == major)
return ubi_devices[i];
BUG();
+ return NULL;
}
/**
@@ -153,7 +154,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
ubi_warn("update of volume %d not finished, volume is damaged",
vol->vol_id);
vol->updating = 0;
- kfree(vol->upd_buf);
+ vfree(vol->upd_buf);
}
ubi_close_volume(desc);
@@ -232,7 +233,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
tbuf_size = vol->usable_leb_size;
if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size);
- tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+ tbuf = vmalloc(tbuf_size);
if (!tbuf)
return -ENOMEM;
@@ -271,7 +272,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
len = count > tbuf_size ? tbuf_size : count;
} while (count);
- kfree(tbuf);
+ vfree(tbuf);
return err ? err : count_save - count;
}
@@ -320,7 +321,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
tbuf_size = vol->usable_leb_size;
if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size);
- tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+ tbuf = vmalloc(tbuf_size);
if (!tbuf)
return -ENOMEM;
@@ -355,7 +356,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
len = count > tbuf_size ? tbuf_size : count;
}
- kfree(tbuf);
+ vfree(tbuf);
return err ? err : count_save - count;
}
@@ -397,6 +398,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
vol->corrupted = 1;
}
vol->checked = 1;
+ ubi_gluebi_updated(vol);
revoke_exclusive(desc, UBI_READWRITE);
}
@@ -413,19 +415,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_device *ubi = vol->ubi;
void __user *argp = (void __user *)arg;
- if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
- _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) && _IOC_READ)
- err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) && _IOC_WRITE)
- err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
-
switch (cmd) {
-
/* Volume update command */
case UBI_IOCVOLUP:
{
@@ -471,7 +461,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
{
int32_t lnum;
- err = __get_user(lnum, (__user int32_t *)argp);
+ err = get_user(lnum, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
@@ -587,17 +577,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_volume_desc *desc;
void __user *argp = (void __user *)arg;
- if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
- _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) && _IOC_READ)
- err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) && _IOC_WRITE)
- err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
-
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
@@ -612,7 +591,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_mkvol_req req;
dbg_msg("create volume");
- err = __copy_from_user(&req, argp,
+ err = copy_from_user(&req, argp,
sizeof(struct ubi_mkvol_req));
if (err) {
err = -EFAULT;
@@ -629,7 +608,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
if (err)
break;
- err = __put_user(req.vol_id, (__user int32_t *)argp);
+ err = put_user(req.vol_id, (__user int32_t *)argp);
if (err)
err = -EFAULT;
@@ -642,7 +621,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
int vol_id;
dbg_msg("remove volume");
- err = __get_user(vol_id, (__user int32_t *)argp);
+ err = get_user(vol_id, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
@@ -669,7 +648,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_rsvol_req req;
dbg_msg("re-size volume");
- err = __copy_from_user(&req, argp,
+ err = copy_from_user(&req, argp,
sizeof(struct ubi_rsvol_req));
if (err) {
err = -EFAULT;
@@ -707,7 +686,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct file_operations ubi_cdev_operations = {
.owner = THIS_MODULE,
.ioctl = ubi_cdev_ioctl,
- .llseek = no_llseek
+ .llseek = no_llseek,
};
/* UBI volume character device operations */
@@ -718,5 +697,5 @@ struct file_operations ubi_vol_cdev_operations = {
.llseek = vol_cdev_llseek,
.read = vol_cdev_read,
.write = vol_cdev_write,
- .ioctl = vol_cdev_ioctl
+ .ioctl = vol_cdev_ioctl,
};
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 86364221fafe..310341e5cd43 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -35,12 +35,12 @@
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{
dbg_msg("erase counter header dump:");
- dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic));
+ dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic));
dbg_msg("version %d", (int)ec_hdr->version);
- dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec));
- dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset));
- dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset));
- dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+ dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec));
+ dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset));
+ dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
+ dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:");
ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
}
@@ -52,20 +52,20 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
dbg_msg("volume identifier header dump:");
- dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic));
+ dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic));
dbg_msg("version %d", (int)vid_hdr->version);
dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
dbg_msg("compat %d", (int)vid_hdr->compat);
- dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id));
- dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum));
- dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver));
- dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size));
- dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs));
- dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad));
+ dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id));
+ dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum));
+ dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver));
+ dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size));
+ dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs));
+ dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad));
dbg_msg("sqnum %llu",
- (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
- dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+ (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+ dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc));
dbg_msg("volume identifier header hexdump:");
}
@@ -91,7 +91,7 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
- dbg_msg("name %s", vol->name);
+ dbg_msg("name %s", vol->name);
} else {
dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
vol->name[0], vol->name[1], vol->name[2],
@@ -106,30 +106,30 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
*/
void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{
- int name_len = ubi16_to_cpu(r->name_len);
+ int name_len = be16_to_cpu(r->name_len);
dbg_msg("volume table record %d dump:", idx);
- dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs));
- dbg_msg("alignment %d", ubi32_to_cpu(r->alignment));
- dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad));
+ dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs));
+ dbg_msg("alignment %d", be32_to_cpu(r->alignment));
+ dbg_msg("data_pad %d", be32_to_cpu(r->data_pad));
dbg_msg("vol_type %d", (int)r->vol_type);
dbg_msg("upd_marker %d", (int)r->upd_marker);
dbg_msg("name_len %d", name_len);
if (r->name[0] == '\0') {
- dbg_msg("name NULL");
+ dbg_msg("name NULL");
return;
}
if (name_len <= UBI_VOL_NAME_MAX &&
strnlen(&r->name[0], name_len + 1) == name_len) {
- dbg_msg("name %s", &r->name[0]);
+ dbg_msg("name %s", &r->name[0]);
} else {
dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
r->name[0], r->name[1], r->name[2], r->name[3],
r->name[4]);
}
- dbg_msg("crc %#08x", ubi32_to_cpu(r->crc));
+ dbg_msg("crc %#08x", be32_to_cpu(r->crc));
}
/**
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index f816ad9a36c0..ff8f39548cd8 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -52,7 +52,6 @@ struct ubi_scan_volume;
struct ubi_scan_leb;
struct ubi_mkvol_req;
-void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@@ -66,7 +65,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
#define dbg_msg(fmt, ...) ({})
#define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_print(func, fmt, ...) ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({})
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c6b223b3f8a..7c5e29eaf118 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -425,10 +425,10 @@ retry:
} else if (err == UBI_IO_BITFLIPS)
scrub = 1;
- ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
- ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+ ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+ ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
- crc = ubi32_to_cpu(vid_hdr->data_crc);
+ crc = be32_to_cpu(vid_hdr->data_crc);
ubi_free_vid_hdr(ubi, vid_hdr);
}
@@ -518,13 +518,13 @@ retry:
goto out_put;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
if (err)
goto write_error;
data_size = offset + len;
- new_buf = kmalloc(data_size, GFP_KERNEL);
+ new_buf = vmalloc(data_size);
if (!new_buf) {
err = -ENOMEM;
goto out_put;
@@ -535,7 +535,7 @@ retry:
if (offset > 0) {
err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
if (err && err != UBI_IO_BITFLIPS) {
- kfree(new_buf);
+ vfree(new_buf);
goto out_put;
}
}
@@ -544,11 +544,11 @@ retry:
err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
if (err) {
- kfree(new_buf);
+ vfree(new_buf);
goto write_error;
}
- kfree(new_buf);
+ vfree(new_buf);
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
@@ -634,11 +634,11 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
}
vid_hdr->vol_type = UBI_VID_DYNAMIC;
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -692,7 +692,7 @@ write_error:
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -748,17 +748,17 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, data_size);
vid_hdr->vol_type = UBI_VID_STATIC;
- vid_hdr->data_size = cpu_to_ubi32(data_size);
- vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+ vid_hdr->data_crc = cpu_to_be32(crc);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -813,7 +813,7 @@ write_error:
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -854,17 +854,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, len);
- vid_hdr->vol_type = UBI_VID_STATIC;
- vid_hdr->data_size = cpu_to_ubi32(len);
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->data_size = cpu_to_be32(len);
vid_hdr->copy_flag = 1;
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_crc = cpu_to_be32(crc);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -891,11 +891,13 @@ retry:
goto write_error;
}
- err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return err;
+ if (vol->eba_tbl[lnum] >= 0) {
+ err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+ if (err) {
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ leb_write_unlock(ubi, vol_id, lnum);
+ return err;
+ }
}
vol->eba_tbl[lnum] = pnum;
@@ -924,7 +926,7 @@ write_error:
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -965,19 +967,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
uint32_t crc;
void *buf, *buf1 = NULL;
- vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- lnum = ubi32_to_cpu(vid_hdr->lnum);
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
if (vid_hdr->vol_type == UBI_VID_STATIC) {
- data_size = ubi32_to_cpu(vid_hdr->data_size);
+ data_size = be32_to_cpu(vid_hdr->data_size);
aldata_size = ALIGN(data_size, ubi->min_io_size);
} else
data_size = aldata_size =
- ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+ ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
- buf = kmalloc(aldata_size, GFP_KERNEL);
+ buf = vmalloc(aldata_size);
if (!buf)
return -ENOMEM;
@@ -987,7 +989,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/
err = leb_write_lock(ubi, vol_id, lnum);
if (err) {
- kfree(buf);
+ vfree(buf);
return err;
}
@@ -1054,10 +1056,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/
if (data_size > 0) {
vid_hdr->copy_flag = 1;
- vid_hdr->data_size = cpu_to_ubi32(data_size);
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->data_crc = cpu_to_be32(crc);
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
if (err)
@@ -1082,7 +1084,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
* We've written the data and are going to read it back to make
* sure it was written correctly.
*/
- buf1 = kmalloc(aldata_size, GFP_KERNEL);
+ buf1 = vmalloc(aldata_size);
if (!buf1) {
err = -ENOMEM;
goto out_unlock;
@@ -1111,15 +1113,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
vol->eba_tbl[lnum] = to;
leb_write_unlock(ubi, vol_id, lnum);
- kfree(buf);
- kfree(buf1);
+ vfree(buf);
+ vfree(buf1);
return 0;
out_unlock:
leb_write_unlock(ubi, vol_id, lnum);
- kfree(buf);
- kfree(buf1);
+ vfree(buf);
+ vfree(buf1);
return err;
}
@@ -1147,7 +1149,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi_devices_cnt == 0) {
ltree_slab = kmem_cache_create("ubi_ltree_slab",
sizeof(struct ltree_entry), 0,
- 0, &ltree_entry_ctor, NULL);
+ 0, &ltree_entry_ctor);
if (!ltree_slab)
return -ENOMEM;
}
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index fc9478d605ff..41ff74c60e14 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -282,7 +282,6 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->flags = MTD_WRITEABLE;
mtd->writesize = ubi->min_io_size;
mtd->owner = THIS_MODULE;
- mtd->size = vol->usable_leb_size * vol->reserved_pebs;
mtd->erasesize = vol->usable_leb_size;
mtd->read = gluebi_read;
mtd->write = gluebi_write;
@@ -290,6 +289,15 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->get_device = gluebi_get_device;
mtd->put_device = gluebi_put_device;
+ /*
+ * In case of dynamic volume, MTD device size is just volume size. In
+ * case of a static volume the size is equivalent to the amount of data
+ * bytes, which is zero at this moment and will be changed after volume
+ * update.
+ */
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+
if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n");
kfree(mtd->name);
@@ -321,3 +329,20 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
kfree(mtd->name);
return 0;
}
+
+/**
+ * ubi_gluebi_updated - UBI volume was updated notifier.
+ * @vol: volume description object
+ *
+ * This function is called every time an UBI volume is updated. This function
+ * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * volume is static. This is needed because static volumes cannot be read past
+ * data they contain.
+ */
+void ubi_gluebi_updated(struct ubi_volume *vol)
+{
+ struct mtd_info *mtd = &vol->gluebi_mtd;
+
+ if (vol->vol_type == UBI_STATIC_VOLUME)
+ mtd->size = vol->used_bytes;
+}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 438914d05151..b0d8f4cede97 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -125,9 +125,9 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
* o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
* correctable bit-flips were detected; this is harmless but may indicate
* that this eraseblock may become bad soon (but do not have to);
- * o %-EBADMSG if the MTD subsystem reported about data data integrity
- * problems, for example it can me an ECC error in case of NAND; this most
- * probably means that the data is corrupted;
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ * example it can be an ECC error in case of NAND; this most probably means
+ * that the data is corrupted;
* o %-EIO if some I/O error occurred;
* o other negative error codes in case of other errors.
*/
@@ -298,7 +298,7 @@ retry:
memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = ubi->mtd;
- ei.addr = pnum * ubi->peb_size;
+ ei.addr = (loff_t)pnum * ubi->peb_size;
ei.len = ubi->peb_size;
ei.callback = erase_callback;
ei.priv = (unsigned long)&wq;
@@ -382,7 +382,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
void *buf;
int err, i, patt_count;
- buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+ buf = vmalloc(ubi->peb_size);
if (!buf)
return -ENOMEM;
@@ -437,7 +437,7 @@ out:
* physical eraseblock which means something is wrong with it.
*/
err = -EIO;
- kfree(buf);
+ vfree(buf);
return err;
}
@@ -557,9 +557,9 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
long long ec;
int vid_hdr_offset, leb_start;
- ec = ubi64_to_cpu(ec_hdr->ec);
- vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
- leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+ ec = be64_to_cpu(ec_hdr->ec);
+ vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+ leb_start = be32_to_cpu(ec_hdr->data_offset);
if (ec_hdr->version != UBI_VERSION) {
ubi_err("node with incompatible UBI version found: "
@@ -640,7 +640,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
read_err = err;
}
- magic = ubi32_to_cpu(ec_hdr->magic);
+ magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
/*
* The magic field is wrong. Let's check if we have read all
@@ -684,7 +684,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
}
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
if (verbose) {
@@ -729,12 +729,12 @@ int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
dbg_io("write EC header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+ ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
ec_hdr->version = UBI_VERSION;
- ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
- ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+ ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+ ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+ ec_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
if (err)
@@ -757,13 +757,13 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
{
int vol_type = vid_hdr->vol_type;
int copy_flag = vid_hdr->copy_flag;
- int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- int lnum = ubi32_to_cpu(vid_hdr->lnum);
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int lnum = be32_to_cpu(vid_hdr->lnum);
int compat = vid_hdr->compat;
- int data_size = ubi32_to_cpu(vid_hdr->data_size);
- int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
- int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+ int data_size = be32_to_cpu(vid_hdr->data_size);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
+ int data_crc = be32_to_cpu(vid_hdr->data_crc);
int usable_leb_size = ubi->leb_size - data_pad;
if (copy_flag != 0 && copy_flag != 1) {
@@ -914,7 +914,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
read_err = err;
}
- magic = ubi32_to_cpu(vid_hdr->magic);
+ magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
/*
* If we have read all 0xFF bytes, the VID header probably does
@@ -957,7 +957,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
}
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
if (verbose) {
@@ -1007,10 +1007,10 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
if (err)
return err > 0 ? -EINVAL: err;
- vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+ vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
vid_hdr->version = UBI_VERSION;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
- vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+ vid_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
if (err)
@@ -1060,7 +1060,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
int err;
uint32_t magic;
- magic = ubi32_to_cpu(ec_hdr->magic);
+ magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
ubi_err("bad magic %#08x, must be %#08x",
magic, UBI_EC_HDR_MAGIC);
@@ -1105,7 +1105,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
goto exit;
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
ubi_err("paranoid check failed for PEB %d", pnum);
@@ -1137,7 +1137,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
int err;
uint32_t magic;
- magic = ubi32_to_cpu(vid_hdr->magic);
+ magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
magic, pnum, UBI_VID_HDR_MAGIC);
@@ -1187,7 +1187,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
goto exit;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
@@ -1224,9 +1224,10 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- buf = kzalloc(len, GFP_KERNEL);
+ buf = vmalloc(len);
if (!buf)
return -ENOMEM;
+ memset(buf, 0, len);
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err && err != -EUCLEAN) {
@@ -1242,7 +1243,7 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
goto fail;
}
- kfree(buf);
+ vfree(buf);
return 0;
fail:
@@ -1252,7 +1253,7 @@ fail:
err = 1;
error:
ubi_dbg_dump_stack();
- kfree(buf);
+ vfree(buf);
return err;
}
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d352c4575c3d..4a458e83e4e9 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -37,14 +37,9 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
{
const struct ubi_device *ubi;
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
- !ubi_devices[ubi_num]) {
- module_put(THIS_MODULE);
+ !ubi_devices[ubi_num])
return -ENODEV;
- }
ubi = ubi_devices[ubi_num];
di->ubi_num = ubi->ubi_num;
@@ -52,7 +47,6 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
di->min_io_size = ubi->min_io_size;
di->ro_mode = ubi->ro_mode;
di->cdev = MKDEV(ubi->major, 0);
- module_put(THIS_MODULE);
return 0;
}
EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -319,9 +313,14 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
offset + len > vol->usable_leb_size)
return -EINVAL;
- if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
- offset + len > vol->last_eb_bytes)
- return -EINVAL;
+ if (vol->vol_type == UBI_STATIC_VOLUME) {
+ if (vol->used_ebs == 0)
+ /* Empty static UBI volume */
+ return 0;
+ if (lnum == vol->used_ebs - 1 &&
+ offset + len > vol->last_eb_bytes)
+ return -EINVAL;
+ }
if (vol->upd_marker)
return -EBADF;
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 38d4e6757dc7..9e2338c8e2cf 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -67,7 +67,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
if (vol->vol_type != UBI_STATIC_VOLUME)
return 0;
- buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+ buf = vmalloc(vol->usable_leb_size);
if (!buf)
return -ENOMEM;
@@ -87,7 +87,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
}
}
- kfree(buf);
+ vfree(buf);
return err;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 473f3200b868..94ee54934411 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -24,7 +24,7 @@
* This unit is responsible for scanning the flash media, checking UBI
* headers and providing complete information about the UBI flash image.
*
- * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * The scanning information is represented by a &struct ubi_scan_info' object.
* Information about found volumes is represented by &struct ubi_scan_volume
* objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID.
@@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi,
static struct ubi_ec_hdr *ech;
static struct ubi_vid_hdr *vidh;
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
- struct list_head *list)
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+ struct list_head *list)
{
struct ubi_scan_leb *seb;
@@ -121,9 +132,9 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
const struct ubi_scan_volume *sv, int pnum)
{
int vol_type = vid_hdr->vol_type;
- int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
if (sv->leb_count != 0) {
int sv_vol_type;
@@ -189,7 +200,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
struct ubi_scan_volume *sv;
struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
- ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+ ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
/* Walk the volume RB-tree to look if this volume is already present */
while (*p) {
@@ -211,11 +222,10 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
return ERR_PTR(-ENOMEM);
sv->highest_lnum = sv->leb_count = 0;
- si->max_sqnum = 0;
sv->vol_id = vol_id;
sv->root = RB_ROOT;
- sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+ sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
sv->compat = vid_hdr->compat;
sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
: UBI_STATIC_VOLUME;
@@ -257,10 +267,10 @@ static int compare_lebs(const struct ubi_device *ubi,
int len, err, second_is_newer, bitflips = 0, corrupted = 0;
uint32_t data_crc, crc;
struct ubi_vid_hdr *vidh = NULL;
- unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+ unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) {
- long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+ long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
/*
* UBI constantly increases the logical eraseblock version
@@ -344,8 +354,8 @@ static int compare_lebs(const struct ubi_device *ubi,
/* Read the data of the copy and check the CRC */
- len = ubi32_to_cpu(vid_hdr->data_size);
- buf = kmalloc(len, GFP_KERNEL);
+ len = be32_to_cpu(vid_hdr->data_size);
+ buf = vmalloc(len);
if (!buf) {
err = -ENOMEM;
goto out_free_vidh;
@@ -355,7 +365,7 @@ static int compare_lebs(const struct ubi_device *ubi,
if (err && err != UBI_IO_BITFLIPS)
goto out_free_buf;
- data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+ data_crc = be32_to_cpu(vid_hdr->data_crc);
crc = crc32(UBI_CRC32_INIT, buf, len);
if (crc != data_crc) {
dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@@ -368,7 +378,7 @@ static int compare_lebs(const struct ubi_device *ubi,
bitflips = !!err;
}
- kfree(buf);
+ vfree(buf);
ubi_free_vid_hdr(ubi, vidh);
if (second_is_newer)
@@ -379,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
return second_is_newer | (bitflips << 1) | (corrupted << 2);
out_free_buf:
- kfree(buf);
+ vfree(buf);
out_free_vidh:
ubi_free_vid_hdr(ubi, vidh);
ubi_assert(err < 0);
@@ -396,8 +406,12 @@ out_free_vidh:
* @vid_hdr: the volume identifier header
* @bitflips: if bit-flips were detected when this physical eraseblock was read
*
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
*/
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@@ -410,10 +424,10 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
struct ubi_scan_leb *seb;
struct rb_node **p, *parent = NULL;
- vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- lnum = ubi32_to_cpu(vid_hdr->lnum);
- sqnum = ubi64_to_cpu(vid_hdr->sqnum);
- leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
+ sqnum = be64_to_cpu(vid_hdr->sqnum);
+ leb_ver = be32_to_cpu(vid_hdr->leb_ver);
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@@ -422,6 +436,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (IS_ERR(sv) < 0)
return PTR_ERR(sv);
+ if (si->max_sqnum < sqnum)
+ si->max_sqnum = sqnum;
+
/*
* Walk the RB-tree of logical eraseblocks of volume @vol_id to look
* if this is the first instance of this logical eraseblock or not.
@@ -492,11 +509,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
return err;
if (cmp_res & 4)
- err = ubi_scan_add_to_list(si, seb->pnum,
- seb->ec, &si->corr);
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->corr);
else
- err = ubi_scan_add_to_list(si, seb->pnum,
- seb->ec, &si->erase);
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->erase);
if (err)
return err;
@@ -508,7 +525,7 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (sv->highest_lnum == lnum)
sv->last_data_size =
- ubi32_to_cpu(vid_hdr->data_size);
+ be32_to_cpu(vid_hdr->data_size);
return 0;
} else {
@@ -517,11 +534,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
* previously.
*/
if (cmp_res & 4)
- return ubi_scan_add_to_list(si, pnum, ec,
- &si->corr);
+ return add_to_list(si, pnum, ec, &si->corr);
else
- return ubi_scan_add_to_list(si, pnum, ec,
- &si->erase);
+ return add_to_list(si, pnum, ec, &si->erase);
}
}
@@ -547,12 +562,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (sv->highest_lnum <= lnum) {
sv->highest_lnum = lnum;
- sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+ sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
}
- if (si->max_sqnum < sqnum)
- si->max_sqnum = sqnum;
-
sv->leb_count += 1;
rb_link_node(&seb->u.rb, parent, p);
rb_insert_color(&seb->u.rb, &sv->root);
@@ -674,7 +686,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
return -EINVAL;
}
- ec_hdr->ec = cpu_to_ubi64(ec);
+ ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0);
if (err < 0)
@@ -754,7 +766,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
* @si: scanning information
* @pnum: the physical eraseblock number
*
- * This function returns a zero if the physical eraseblock was succesfully
+ * This function returns a zero if the physical eraseblock was successfully
* handled and a negative error code in case of failure.
*/
static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@@ -783,8 +795,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BITFLIPS)
bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY)
- return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
- &si->erase);
+ return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
else if (err == UBI_IO_BAD_EC_HDR) {
/*
* We have to also look at the VID header, possibly it is not
@@ -806,7 +817,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
return -EINVAL;
}
- ec = ubi64_to_cpu(ech->ec);
+ ec = be64_to_cpu(ech->ec);
if (ec > UBI_MAX_ERASECOUNTER) {
/*
* Erase counter overflow. The EC headers have 64 bits
@@ -832,28 +843,28 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BAD_VID_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */
- err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+ err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
goto adjust_mean_ec;
} else if (err == UBI_IO_PEB_FREE) {
/* No VID header - the physical eraseblock is free */
- err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+ err = add_to_list(si, pnum, ec, &si->free);
if (err)
return err;
goto adjust_mean_ec;
}
- vol_id = ubi32_to_cpu(vidh->vol_id);
+ vol_id = be32_to_cpu(vidh->vol_id);
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
- int lnum = ubi32_to_cpu(vidh->lnum);
+ int lnum = be32_to_cpu(vidh->lnum);
/* Unsupported internal volume */
switch (vidh->compat) {
case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, remove it", vol_id, lnum);
- err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+ err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
break;
@@ -868,7 +879,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum);
- err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+ err = add_to_list(si, pnum, ec, &si->alien);
if (err)
return err;
si->alien_peb_count += 1;
@@ -1109,7 +1120,7 @@ static int paranoid_check_si(const struct ubi_device *ubi,
uint8_t *buf;
/*
- * At first, check that scanning information is ok.
+ * At first, check that scanning information is OK.
*/
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
int leb_count = 0;
@@ -1249,12 +1260,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
goto bad_vid_hdr;
}
- if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+ if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
ubi_err("bad sqnum %llu", seb->sqnum);
goto bad_vid_hdr;
}
- if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+ if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
ubi_err("bad vol_id %d", sv->vol_id);
goto bad_vid_hdr;
}
@@ -1264,22 +1275,22 @@ static int paranoid_check_si(const struct ubi_device *ubi,
goto bad_vid_hdr;
}
- if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+ if (seb->lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad lnum %d", seb->lnum);
goto bad_vid_hdr;
}
- if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+ if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
ubi_err("bad used_ebs %d", sv->used_ebs);
goto bad_vid_hdr;
}
- if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+ if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
ubi_err("bad data_pad %d", sv->data_pad);
goto bad_vid_hdr;
}
- if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+ if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
ubi_err("bad leb_ver %u", seb->leb_ver);
goto bad_vid_hdr;
}
@@ -1288,12 +1299,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
if (!last_seb)
continue;
- if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+ if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad highest_lnum %d", sv->highest_lnum);
goto bad_vid_hdr;
}
- if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+ if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
ubi_err("bad last_data_size %d", sv->last_data_size);
goto bad_vid_hdr;
}
@@ -1310,8 +1321,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
memset(buf, 1, ubi->peb_count);
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
err = ubi_io_is_bad(ubi, pnum);
- if (err < 0)
+ if (err < 0) {
+ kfree(buf);
return err;
+ }
else if (err)
buf[pnum] = 0;
}
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 3949f6192c76..140e82e26534 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
list_add_tail(&seb->u.list, list);
}
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
- struct list_head *list);
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index feb647f108f0..5959f91be240 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -35,6 +35,7 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/string.h>
+#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include <mtd/ubi-header.h>
@@ -374,9 +375,11 @@ void ubi_calculate_reserved(struct ubi_device *ubi);
#ifdef CONFIG_MTD_UBI_GLUEBI
int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
#else
#define ubi_create_gluebi(ubi, vol) 0
#define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
#endif
/* eba.c */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 8925b977e3dc..0efc586a8328 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -150,7 +150,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
vol->updating = 0;
}
- vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+ vol->upd_buf = vmalloc(ubi->leb_size);
if (!vol->upd_buf)
return -ENOMEM;
@@ -339,7 +339,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
err = ubi_wl_flush(ubi);
if (err == 0) {
err = to_write;
- kfree(vol->upd_buf);
+ vfree(vol->upd_buf);
vol->updating = 0;
}
}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 622d0d18952c..ea0d5c825ab4 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -228,7 +228,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
for (i = 0; i < ubi->vtbl_slots; i++)
if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len &&
- strcmp(ubi->volumes[i]->name, req->name) == 0) {
+ !strcmp(ubi->volumes[i]->name, req->name)) {
dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock;
}
@@ -243,7 +243,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
- spin_unlock(&ubi->volumes_lock);
err = -ENOSPC;
goto out_unlock;
}
@@ -281,7 +280,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
} else {
bytes = vol->used_bytes;
vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@@ -320,10 +320,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Fill volume table record */
memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
- vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
- vtbl_rec.alignment = cpu_to_ubi32(vol->alignment);
- vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad);
- vtbl_rec.name_len = cpu_to_ubi16(vol->name_len);
+ vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+ vtbl_rec.alignment = cpu_to_be32(vol->alignment);
+ vtbl_rec.data_pad = cpu_to_be32(vol->data_pad);
+ vtbl_rec.name_len = cpu_to_be16(vol->name_len);
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
vtbl_rec.vol_type = UBI_VID_DYNAMIC;
else
@@ -352,6 +352,7 @@ out_acc:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
+ ubi->volumes[vol_id] = NULL;
out_unlock:
spin_unlock(&ubi->volumes_lock);
kfree(vol);
@@ -368,6 +369,7 @@ out_sysfs:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
+ ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
volume_sysfs_close(vol);
return err;
@@ -503,7 +505,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
/* Change volume table record */
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
- vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+ vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_acc;
@@ -537,7 +539,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
}
paranoid_check_volumes(ubi);
@@ -643,21 +646,33 @@ void ubi_free_volume(struct ubi_device *ubi, int vol_id)
* @ubi: UBI device description object
* @vol_id: volume ID
*/
-static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
{
int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
- const struct ubi_volume *vol = ubi->volumes[idx];
+ const struct ubi_volume *vol;
long long n;
const char *name;
- reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ spin_lock(&ubi->volumes_lock);
+ reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ vol = ubi->volumes[idx];
if (!vol) {
if (reserved_pebs) {
ubi_err("no volume info, but volume exists");
goto fail;
}
+ spin_unlock(&ubi->volumes_lock);
+ return;
+ }
+
+ if (vol->exclusive) {
+ /*
+ * The volume may be being created at the moment, do not check
+ * it (e.g., it may be in the middle of ubi_create_volume().
+ */
+ spin_unlock(&ubi->volumes_lock);
return;
}
@@ -726,7 +741,7 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
goto fail;
}
- n = vol->used_ebs * vol->usable_leb_size;
+ n = (long long)vol->used_ebs * vol->usable_leb_size;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
if (vol->corrupted != 0) {
ubi_err("corrupted dynamic volume");
@@ -765,9 +780,9 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
}
}
- alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
- data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
- name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+ alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+ data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+ name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len);
upd_marker = ubi->vtbl[vol_id].upd_marker;
name = &ubi->vtbl[vol_id].name[0];
if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@@ -782,12 +797,14 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
goto fail;
}
+ spin_unlock(&ubi->volumes_lock);
return;
fail:
- ubi_err("paranoid check failed");
+ ubi_err("paranoid check failed for volume %d", vol_id);
ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+ spin_unlock(&ubi->volumes_lock);
BUG();
}
@@ -800,10 +817,8 @@ static void paranoid_check_volumes(struct ubi_device *ubi)
int i;
mutex_lock(&ubi->vtbl_mutex);
- spin_lock(&ubi->volumes_lock);
for (i = 0; i < ubi->vtbl_slots; i++)
paranoid_check_volume(ubi, i);
- spin_unlock(&ubi->volumes_lock);
mutex_unlock(&ubi->vtbl_mutex);
}
#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index b6fd6bbd941e..bc5df50813d6 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -93,12 +93,9 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
vtbl_rec = &empty_vtbl_record;
else {
crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
- vtbl_rec->crc = cpu_to_ubi32(crc);
+ vtbl_rec->crc = cpu_to_be32(crc);
}
- dbg_msg("change record %d", idx);
- ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
-
mutex_lock(&ubi->vtbl_mutex);
memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@@ -141,18 +138,18 @@ static int vtbl_check(const struct ubi_device *ubi,
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
- reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
- alignment = ubi32_to_cpu(vtbl[i].alignment);
- data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+ reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ alignment = be32_to_cpu(vtbl[i].alignment);
+ data_pad = be32_to_cpu(vtbl[i].data_pad);
upd_marker = vtbl[i].upd_marker;
vol_type = vtbl[i].vol_type;
- name_len = ubi16_to_cpu(vtbl[i].name_len);
+ name_len = be16_to_cpu(vtbl[i].name_len);
name = &vtbl[i].name[0];
crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
- if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+ if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x",
- i, crc, ubi32_to_cpu(vtbl[i].crc));
+ i, crc, be32_to_cpu(vtbl[i].crc));
ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return 1;
}
@@ -225,8 +222,8 @@ static int vtbl_check(const struct ubi_device *ubi,
/* Checks that all names are unique */
for (i = 0; i < ubi->vtbl_slots - 1; i++) {
for (n = i + 1; n < ubi->vtbl_slots; n++) {
- int len1 = ubi16_to_cpu(vtbl[i].name_len);
- int len2 = ubi16_to_cpu(vtbl[n].name_len);
+ int len1 = be16_to_cpu(vtbl[i].name_len);
+ int len2 = be16_to_cpu(vtbl[n].name_len);
if (len1 > 0 && len1 == len2 &&
!strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@@ -288,13 +285,13 @@ retry:
}
vid_hdr->vol_type = UBI_VID_DYNAMIC;
- vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
vid_hdr->data_size = vid_hdr->used_ebs =
- vid_hdr->data_pad = cpu_to_ubi32(0);
- vid_hdr->lnum = cpu_to_ubi32(copy);
- vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
- vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+ vid_hdr->data_pad = cpu_to_be32(0);
+ vid_hdr->lnum = cpu_to_be32(copy);
+ vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+ vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
/* The EC header is already there, write the VID header */
err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@@ -317,14 +314,15 @@ retry:
return err;
write_error:
- kfree(new_seb);
- /* May be this physical eraseblock went bad, try to pick another one */
- if (++tries <= 5) {
- err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
- &si->corr);
- if (!err)
- goto retry;
+ if (err == -EIO && ++tries <= 5) {
+ /*
+ * Probably this physical eraseblock went bad, try to pick
+ * another one.
+ */
+ list_add_tail(&new_seb->u.list, &si->corr);
+ goto retry;
}
+ kfree(new_seb);
out_free:
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -380,11 +378,12 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
/* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+ leb[seb->lnum] = vmalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) {
err = -ENOMEM;
goto out_free;
}
+ memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size);
@@ -415,7 +414,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
}
/* Both LEB 1 and LEB 2 are OK and consistent */
- kfree(leb[1]);
+ vfree(leb[1]);
return leb[0];
} else {
/* LEB 0 is corrupted or does not exist */
@@ -436,13 +435,13 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
goto out_free;
ubi_msg("volume table was restored");
- kfree(leb[0]);
+ vfree(leb[0]);
return leb[1];
}
out_free:
- kfree(leb[0]);
- kfree(leb[1]);
+ vfree(leb[0]);
+ vfree(leb[1]);
return ERR_PTR(err);
}
@@ -460,9 +459,10 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
int i;
struct ubi_vtbl_record *vtbl;
- vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+ vtbl = vmalloc(ubi->vtbl_size);
if (!vtbl)
return ERR_PTR(-ENOMEM);
+ memset(vtbl, 0, ubi->vtbl_size);
for (i = 0; i < ubi->vtbl_slots; i++)
memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@@ -472,7 +472,7 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
err = create_vtbl(ubi, si, i, vtbl);
if (err) {
- kfree(vtbl);
+ vfree(vtbl);
return ERR_PTR(err);
}
}
@@ -500,19 +500,19 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
- if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+ if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
continue; /* Empty record */
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol)
return -ENOMEM;
- vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
- vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
- vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+ vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ vol->alignment = be32_to_cpu(vtbl[i].alignment);
+ vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
- vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+ vol->name_len = be16_to_cpu(vtbl[i].name_len);
vol->usable_leb_size = ubi->leb_size - vol->data_pad;
memcpy(vol->name, vtbl[i].name, vol->name_len);
vol->name[vol->name_len] = '\0';
@@ -531,7 +531,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
continue;
}
@@ -561,7 +562,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
}
vol->used_ebs = sv->used_ebs;
- vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
vol->used_bytes += sv->last_data_size;
vol->last_eb_bytes = sv->last_data_size;
}
@@ -578,7 +580,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
vol->usable_leb_size = ubi->leb_size;
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->reserved_pebs;
- vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+ vol->used_bytes =
+ (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
vol->vol_id = UBI_LAYOUT_VOL_ID;
ubi_assert(!ubi->volumes[i]);
@@ -718,7 +721,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
int i, err;
struct ubi_scan_volume *sv;
- empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+ empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
/*
* The number of supported volumes is limited by the eraseblock size
@@ -783,7 +786,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return 0;
out_free:
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
if (ubi->volumes[i]) {
kfree(ubi->volumes[i]);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index ab2174a56bc2..a5a9b8d87302 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -667,7 +667,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
- ec_hdr->ec = cpu_to_ubi64(ec);
+ ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
if (err)
@@ -1060,9 +1060,8 @@ out_unlock:
static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int cancel)
{
- int err;
struct ubi_wl_entry *e = wl_wrk->e;
- int pnum = e->pnum;
+ int pnum = e->pnum, err, need;
if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e);
- if (err != -EIO) {
+ if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+ err == -EBUSY) {
+ int err1;
+
+ /* Re-schedule the LEB for erasure */
+ err1 = schedule_erase(ubi, e, 0);
+ if (err1) {
+ err = err1;
+ goto out_ro;
+ }
+ return err;
+ } else if (err != -EIO) {
/*
* If this is not %-EIO, we have no idea what to do. Scheduling
* this physical eraseblock for erasure again would cause
* errors again and again. Well, lets switch to RO mode.
*/
- ubi_ro_mode(ubi);
- return err;
+ goto out_ro;
}
/* It is %-EIO, the PEB went bad */
if (!ubi->bad_allowed) {
ubi_err("bad physical eraseblock %d detected", pnum);
- ubi_ro_mode(ubi);
- err = -EIO;
- } else {
- int need;
-
- spin_lock(&ubi->volumes_lock);
- need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
- if (need > 0) {
- need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
- ubi->avail_pebs -= need;
- ubi->rsvd_pebs += need;
- ubi->beb_rsvd_pebs += need;
- if (need > 0)
- ubi_msg("reserve more %d PEBs", need);
- }
+ goto out_ro;
+ }
- if (ubi->beb_rsvd_pebs == 0) {
- spin_unlock(&ubi->volumes_lock);
- ubi_err("no reserved physical eraseblocks");
- ubi_ro_mode(ubi);
- return -EIO;
- }
+ spin_lock(&ubi->volumes_lock);
+ need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+ if (need > 0) {
+ need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+ ubi->avail_pebs -= need;
+ ubi->rsvd_pebs += need;
+ ubi->beb_rsvd_pebs += need;
+ if (need > 0)
+ ubi_msg("reserve more %d PEBs", need);
+ }
+ if (ubi->beb_rsvd_pebs == 0) {
spin_unlock(&ubi->volumes_lock);
- ubi_msg("mark PEB %d as bad", pnum);
+ ubi_err("no reserved physical eraseblocks");
+ goto out_ro;
+ }
- err = ubi_io_mark_bad(ubi, pnum);
- if (err) {
- ubi_ro_mode(ubi);
- return err;
- }
+ spin_unlock(&ubi->volumes_lock);
+ ubi_msg("mark PEB %d as bad", pnum);
- spin_lock(&ubi->volumes_lock);
- ubi->beb_rsvd_pebs -= 1;
- ubi->bad_peb_count += 1;
- ubi->good_peb_count -= 1;
- ubi_calculate_reserved(ubi);
- if (ubi->beb_rsvd_pebs == 0)
- ubi_warn("last PEB from the reserved pool was used");
- spin_unlock(&ubi->volumes_lock);
- }
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ goto out_ro;
+
+ spin_lock(&ubi->volumes_lock);
+ ubi->beb_rsvd_pebs -= 1;
+ ubi->bad_peb_count += 1;
+ ubi->good_peb_count -= 1;
+ ubi_calculate_reserved(ubi);
+ if (ubi->beb_rsvd_pebs == 0)
+ ubi_warn("last PEB from the reserved pool was used");
+ spin_unlock(&ubi->volumes_lock);
+
+ return err;
+out_ro:
+ ubi_ro_mode(ubi);
return err;
}
@@ -1445,7 +1452,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi_devices_cnt == 0) {
wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab",
sizeof(struct ubi_wl_entry),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!wl_entries_slab)
return -ENOMEM;
}
@@ -1634,7 +1641,7 @@ static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
goto out_free;
}
- read_ec = ubi64_to_cpu(ec_hdr->ec);
+ read_ec = be64_to_cpu(ec_hdr->ec);
if (ec != read_ec) {
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_err("read EC is %lld, should be %d", read_ec, ec);
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 4bee99ba7dbb..be71868d1513 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -174,8 +174,6 @@ struct net_device * __init el1_probe(int unit)
mem_start = dev->mem_start & 7;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = el1_probe1(dev, io);
} else if (io != 0) {
@@ -317,7 +315,6 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
dev->tx_timeout = &el_timeout;
dev->watchdog_timeo = HZ;
dev->stop = &el1_close;
- dev->get_stats = &el1_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->ethtool_ops = &netdev_ethtool_ops;
return 0;
@@ -376,7 +373,7 @@ static void el_timeout(struct net_device *dev)
if (el_debug)
printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
outb(TX_NORM, TX_CMD);
outb(RX_NORM, RX_CMD);
outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */
@@ -443,7 +440,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->tx_pkt_start = gp_start;
lp->collisions = 0;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/*
* Command mode with status cleared should [in theory]
@@ -590,7 +587,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);
outb(AX_SYS, AX_CMD);
lp->txing = 0;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
netif_wake_queue(dev);
}
else if (txsr & TX_COLLISION)
@@ -608,7 +605,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
outb(AX_SYS, AX_CMD);
outw(lp->tx_pkt_start, GP_LOW);
outb(AX_XMIT, AX_CMD);
- lp->stats.collisions++;
+ dev->stats.collisions++;
spin_unlock(&lp->lock);
goto out;
}
@@ -617,7 +614,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
/*
* It worked.. we will now fall through and receive
*/
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
if (el_debug > 6)
printk(KERN_DEBUG " Tx succeeded %s\n",
(txsr & TX_RDY) ? "." : "but tx is busy!");
@@ -642,10 +639,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
* Just reading rx_status fixes most errors.
*/
if (rxsr & RX_MISSED)
- lp->stats.rx_missed_errors++;
+ dev->stats.rx_missed_errors++;
else if (rxsr & RX_RUNT)
{ /* Handled to avoid board lock-up. */
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (el_debug > 5)
printk(KERN_DEBUG " runt.\n");
}
@@ -696,7 +693,6 @@ out:
static void el_receive(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int pkt_len;
struct sk_buff *skb;
@@ -710,7 +706,7 @@ static void el_receive(struct net_device *dev)
{
if (el_debug)
printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len);
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
return;
}
@@ -729,7 +725,7 @@ static void el_receive(struct net_device *dev)
if (skb == NULL)
{
printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
else
@@ -744,8 +740,8 @@ static void el_receive(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes+=pkt_len;
}
return;
}
@@ -813,23 +809,6 @@ static int el1_close(struct net_device *dev)
}
/**
- * el1_get_stats:
- * @dev: The card to get the statistics for
- *
- * In smarter devices this function is needed to pull statistics off the
- * board itself. The 3c501 has no hardware statistics. We maintain them all
- * so they are by definition always up to date.
- *
- * Returns the statistics for the card from the card private data
- */
-
-static struct net_device_stats *el1_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-/**
* set_multicast_list:
* @dev: The device to adjust
*
diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
index c56a2c62f7de..cfec64efff78 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/3c501.h
@@ -11,7 +11,6 @@ static irqreturn_t el_interrupt(int irq, void *dev_id);
static void el_receive(struct net_device *dev);
static void el_reset(struct net_device *dev);
static int el1_close(struct net_device *dev);
-static struct net_device_stats *el1_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static const struct ethtool_ops netdev_ethtool_ops;
@@ -29,7 +28,6 @@ static int el_debug = EL_DEBUG;
struct net_local
{
- struct net_device_stats stats;
int tx_pkt_start; /* The length of the current Tx packet. */
int collisions; /* Tx collisions this packet */
int loading; /* Spot buffer load collisions */
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index bc7e906571d3..9c23336750e2 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -95,8 +95,6 @@ static int __init do_el2_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return el2_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -179,6 +177,7 @@ el2_probe1(struct net_device *dev, int ioaddr)
int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
static unsigned version_printed;
unsigned long vendor_id;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -228,7 +227,8 @@ el2_probe1(struct net_device *dev, int ioaddr)
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+ printk("%s", print_mac(mac, dev->dev_addr));
/* Map the 8390 back into the window. */
outb(ECNTRL_THIN, ioaddr + 0x406);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index e985a85a5623..9c6573419f5a 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -169,21 +169,6 @@ static int elp_debug;
/*****************************************************************
*
- * useful macros
- *
- *****************************************************************/
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-
-/*****************************************************************
- *
* List of I/O-addresses we try to auto-sense
* Last element MUST BE 0!
*****************************************************************/
@@ -270,7 +255,7 @@ static inline void set_hsf(struct net_device *dev, int hsf)
spin_unlock_irqrestore(&adapter->lock, flags);
}
-static int start_receive(struct net_device *, pcb_struct *);
+static bool start_receive(struct net_device *, pcb_struct *);
static inline void adapter_reset(struct net_device *dev)
{
@@ -328,28 +313,28 @@ static inline void check_3c505_dma(struct net_device *dev)
}
/* Primitive functions used by send_pcb() */
-static inline unsigned int send_pcb_slow(unsigned int base_addr, unsigned char byte)
+static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
{
unsigned long timeout;
outb_command(byte, base_addr);
for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
if (inb_status(base_addr) & HCRE)
- return FALSE;
+ return false;
}
printk(KERN_WARNING "3c505: send_pcb_slow timed out\n");
- return TRUE;
+ return true;
}
-static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char byte)
+static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
{
unsigned int timeout;
outb_command(byte, base_addr);
for (timeout = 0; timeout < 40000; timeout++) {
if (inb_status(base_addr) & HCRE)
- return FALSE;
+ return false;
}
printk(KERN_WARNING "3c505: send_pcb_fast timed out\n");
- return TRUE;
+ return true;
}
/* Check to see if the receiver needs restarting, and kick it if so */
@@ -386,7 +371,7 @@ static inline void prime_rx(struct net_device *dev)
* timeout is reduced to 500us).
*/
-static int send_pcb(struct net_device *dev, pcb_struct * pcb)
+static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
{
int i;
unsigned long timeout;
@@ -396,14 +381,14 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
check_3c505_dma(dev);
if (adapter->dmaing && adapter->current_dma.direction == 0)
- return FALSE;
+ return false;
/* Avoid contention */
if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
if (elp_debug >= 3) {
printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name);
}
- return FALSE;
+ return false;
}
/*
* load each byte into the command register and
@@ -435,7 +420,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
switch (GET_ASF(dev->base_addr)) {
case ASF_PCB_ACK:
adapter->send_pcb_semaphore = 0;
- return TRUE;
+ return true;
case ASF_PCB_NAK:
#ifdef ELP_DEBUG
@@ -453,7 +438,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
spin_unlock_irqrestore(&adapter->lock, flags);
abort:
adapter->send_pcb_semaphore = 0;
- return FALSE;
+ return false;
}
@@ -470,7 +455,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
*
*****************************************************************/
-static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
+static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
{
int i, j;
int total_length;
@@ -487,7 +472,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
- return FALSE;
+ return false;
}
pcb->command = inb_command(dev->base_addr);
@@ -497,14 +482,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
printk(KERN_INFO "%s: status %02x\n", dev->name, stat);
- return FALSE;
+ return false;
}
pcb->length = inb_command(dev->base_addr);
if (pcb->length > MAX_PCB_DATA) {
INVALID_PCB_MSG(pcb->length);
adapter_reset(dev);
- return FALSE;
+ return false;
}
/* read the data */
spin_lock_irqsave(&adapter->lock, flags);
@@ -519,7 +504,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
spin_unlock_irqrestore(&adapter->lock, flags);
if (j >= 20000) {
TIMEOUT_MSG(__LINE__);
- return FALSE;
+ return false;
}
/* woops, the last "data" byte was really the length! */
total_length = pcb->data.raw[--i];
@@ -529,7 +514,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
if (elp_debug >= 2)
printk(KERN_WARNING "%s: mangled PCB received\n", dev->name);
set_hsf(dev, HSF_PCB_NAK);
- return FALSE;
+ return false;
}
if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
@@ -538,14 +523,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
set_hsf(dev, HSF_PCB_NAK);
printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
pcb->command = 0;
- return TRUE;
+ return true;
} else {
pcb->command = 0xff;
}
}
}
set_hsf(dev, HSF_PCB_ACK);
- return TRUE;
+ return true;
}
/******************************************************
@@ -555,9 +540,9 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
*
******************************************************/
-static int start_receive(struct net_device *dev, pcb_struct * tx_pcb)
+static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
{
- int status;
+ bool status;
elp_device *adapter = dev->priv;
if (elp_debug >= 3)
@@ -984,7 +969,7 @@ static int elp_open(struct net_device *dev)
*
******************************************************/
-static int send_packet(struct net_device *dev, struct sk_buff *skb)
+static bool send_packet(struct net_device *dev, struct sk_buff *skb)
{
elp_device *adapter = dev->priv;
unsigned long target;
@@ -998,7 +983,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
if (test_and_set_bit(0, (void *) &adapter->busy)) {
if (elp_debug >= 2)
printk(KERN_DEBUG "%s: transmit blocked\n", dev->name);
- return FALSE;
+ return false;
}
adapter->stats.tx_bytes += nlen;
@@ -1015,7 +1000,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
if (!send_pcb(dev, &adapter->tx_pcb)) {
adapter->busy = 0;
- return FALSE;
+ return false;
}
/* if this happens, we die */
if (test_and_set_bit(0, (void *) &adapter->dmaing))
@@ -1047,7 +1032,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);
- return TRUE;
+ return true;
}
/*
@@ -1401,8 +1386,7 @@ static int __init elplus_setup(struct net_device *dev)
unsigned long timeout;
unsigned long cookie = 0;
int err = -ENODEV;
-
- SET_MODULE_OWNER(dev);
+ DECLARE_MAC_BUF(mac);
/*
* setup adapter structure
@@ -1538,11 +1522,10 @@ static int __init elplus_setup(struct net_device *dev)
/*
* print remainder of startup message
*/
- printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ",
- dev->name, dev->base_addr, dev->irq, dev->dma);
- printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, "
+ "addr %s, ",
+ dev->name, dev->base_addr, dev->irq, dev->dma,
+ print_mac(mac, dev->dev_addr));
/*
* read more information from the adapter
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index eed4299dc426..964d31ac9449 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -118,7 +118,6 @@ enum commands {
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
int last_restart;
ushort rx_head;
ushort rx_tail;
@@ -289,7 +288,6 @@ static int el16_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t el16_interrupt(int irq, void *dev_id);
static void el16_rx(struct net_device *dev);
static int el16_close(struct net_device *dev);
-static struct net_device_stats *el16_get_stats(struct net_device *dev);
static void el16_tx_timeout (struct net_device *dev);
static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
@@ -327,8 +325,6 @@ struct net_device * __init el16_probe(int unit)
mem_start = dev->mem_start & 15;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) /* Check a single specified location. */
err = el16_probe1(dev, io);
else if (io != 0)
@@ -361,6 +357,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
static unsigned char init_ID_done, version_printed;
int i, irq, irqval, retval;
struct net_local *lp;
+ DECLARE_MAC_BUF(mac);
if (init_ID_done == 0) {
ushort lrs_state = 0xff;
@@ -406,10 +403,9 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
outb(0x01, ioaddr + MISC_CTRL);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(ioaddr + i);
- printk(" %02x", dev->dev_addr[i]);
- }
+ printk(" %s", print_mac(mac, dev->dev_addr));
if (mem_start)
net_debug = mem_start & 7;
@@ -457,7 +453,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
dev->open = el16_open;
dev->stop = el16_close;
dev->hard_start_xmit = el16_send_packet;
- dev->get_stats = el16_get_stats;
dev->tx_timeout = el16_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->ethtool_ops = &netdev_ethtool_ops;
@@ -491,7 +486,7 @@ static void el16_tx_timeout (struct net_device *dev)
readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
"network cable problem");
/* Try to restart the adaptor. */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
if (net_debug > 1)
printk ("Resetting board.\n");
/* Completely reset the adaptor. */
@@ -503,7 +498,7 @@ static void el16_tx_timeout (struct net_device *dev)
printk ("Kicking board.\n");
writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies;
netif_wake_queue (dev);
@@ -522,7 +517,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave (&lp->lock, flags);
- lp->stats.tx_bytes += length;
+ dev->stats.tx_bytes += length;
/* Disable the 82586's input to the interrupt line. */
outb (0x80, ioaddr + MISC_CTRL);
@@ -581,14 +576,14 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id)
}
/* Tx unsuccessful or some interesting status bit set. */
if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
- lp->stats.tx_errors++;
- if (tx_status & 0x0600) lp->stats.tx_carrier_errors++;
- if (tx_status & 0x0100) lp->stats.tx_fifo_errors++;
- if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++;
- if (tx_status & 0x0020) lp->stats.tx_aborted_errors++;
- lp->stats.collisions += tx_status & 0xf;
+ dev->stats.tx_errors++;
+ if (tx_status & 0x0600) dev->stats.tx_carrier_errors++;
+ if (tx_status & 0x0100) dev->stats.tx_fifo_errors++;
+ if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++;
+ if (tx_status & 0x0020) dev->stats.tx_aborted_errors++;
+ dev->stats.collisions += tx_status & 0xf;
}
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
if (net_debug > 5)
printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
lp->tx_reap += TX_BUF_SIZE;
@@ -667,17 +662,6 @@ static int el16_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *el16_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- /* ToDo: decide if there are any useful statistics from the SCB. */
-
- return &lp->stats;
-}
-
/* Initialize the Rx-block list. */
static void init_rx_bufs(struct net_device *dev)
{
@@ -854,12 +838,12 @@ static void el16_rx(struct net_device *dev)
pkt_len);
} else if ((frame_status & 0x2000) == 0) {
/* Frame Rxed, but with error. */
- lp->stats.rx_errors++;
- if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
- if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
- if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
- if (frame_status & 0x0100) lp->stats.rx_over_errors++;
- if (frame_status & 0x0080) lp->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
+ if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
+ if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
+ if (frame_status & 0x0100) dev->stats.rx_over_errors++;
+ if (frame_status & 0x0080) dev->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
@@ -868,7 +852,7 @@ static void el16_rx(struct net_device *dev)
skb = dev_alloc_skb(pkt_len+2);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -880,8 +864,8 @@ static void el16_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
/* Clear the status word and set End-of-List on the rx frame. */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 127f60841b10..edda6e10ebe5 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -299,7 +299,7 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
{ } /* terminate list */
};
-static u16 el3_isapnp_phys_addr[8][3];
+static __be16 el3_isapnp_phys_addr[8][3];
static int nopnp;
#endif /* __ISAPNP__ */
@@ -313,8 +313,9 @@ static int nopnp;
static int __init el3_common_init(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- short i;
int err;
+ DECLARE_MAC_BUF(mac);
+ const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
spin_lock_init(&lp->lock);
@@ -346,17 +347,10 @@ static int __init el3_common_init(struct net_device *dev)
return err;
}
- {
- const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
- printk("%s: 3c5x9 found at %#3.3lx, %s port, address ",
- dev->name, dev->base_addr,
- if_names[(dev->if_port & 0x03)]);
- }
-
- /* Read in the station address. */
- for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk(", IRQ %d.\n", dev->irq);
+ printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, "
+ "address %s, IRQ %d.\n",
+ dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
+ print_mac(mac, dev->dev_addr), dev->irq);
if (el3_debug > 0)
printk(KERN_INFO "%s", version);
@@ -385,7 +379,7 @@ static int __init el3_probe(int card_idx)
struct el3_private *lp;
short lrs_state = 0xff, i;
int ioaddr, irq, if_port;
- u16 phys_addr[3];
+ __be16 phys_addr[3];
static int current_tag;
int err = -ENODEV;
#if defined(__ISAPNP__)
@@ -432,7 +426,6 @@ __again:
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &idev->dev);
pnp_cards++;
@@ -524,8 +517,6 @@ no_pnp:
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
-
netdev_boot_setup_check(dev);
/* Set passed-in IRQ or I/O Addr. */
@@ -644,7 +635,6 @@ static int __init el3_mca_probe(struct device *device)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
netdev_boot_setup_check(dev);
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
@@ -704,8 +694,6 @@ static int __init el3_eisa_probe (struct device *device)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
-
netdev_boot_setup_check(dev);
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 290166d5e7d1..275e7510ebaf 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -501,8 +501,6 @@ static struct net_device *corkscrew_scan(int unit)
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
-
#ifdef __ISAPNP__
if(nopnp == 1)
goto no_pnp;
@@ -571,6 +569,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
int irq;
+ DECLARE_MAC_BUF(mac);
if (idev) {
irq = pnp_irq(idev, 0);
@@ -632,8 +631,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
checksum = (checksum ^ (checksum >> 8)) & 0xff;
if (checksum != 0x00)
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
- for (i = 0; i < 6; i++)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+ printk(" %s", print_mac(mac, dev->dev_addr));
if (eeprom[16] == 0x11c7) { /* Corkscrew */
if (request_dma(dev->dma, "3c515")) {
printk(", DMA %d allocation failed", dev->dma);
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index ab18343e58ef..239fc42fb8df 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -383,8 +383,8 @@ void alloc586(struct net_device *dev)
static int elmc_getinfo(char *buf, int slot, void *d)
{
int len = 0;
- struct net_device *dev = (struct net_device *) d;
- int i;
+ struct net_device *dev = d;
+ DECLARE_MAC_BUF(mac);
if (dev == NULL)
return len;
@@ -399,12 +399,8 @@ static int elmc_getinfo(char *buf, int slot, void *d)
len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
"External" : "Internal");
len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "Hardware Address:");
- for (i = 0; i < 6; i++) {
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- }
- buf[len++] = '\n';
- buf[len] = 0;
+ len += sprintf(buf + len, "Hardware Address: %s\n",
+ print_mac(mac, dev->dev_addr));
return len;
} /* elmc_getinfo() */
@@ -422,8 +418,8 @@ static int __init do_elmc_probe(struct net_device *dev)
unsigned int size = 0;
int retval;
struct priv *pr = dev->priv;
+ DECLARE_MAC_BUF(mac);
- SET_MODULE_OWNER(dev);
if (MCA_bus == 0) {
return -ENODEV;
}
@@ -545,12 +541,11 @@ static int __init do_elmc_probe(struct net_device *dev)
/* The hardware address for the 3c523 is stored in the first six
bytes of the IO address. */
- printk(KERN_INFO "%s: hardware address ", dev->name);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(dev->base_addr + i);
- printk(" %02x", dev->dev_addr[i]);
- }
- printk("\n");
+
+ printk(KERN_INFO "%s: hardware address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
dev->open = &elmc_open;
dev->stop = &elmc_close;
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index c7b571be20e0..b72b89d53ec8 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -257,8 +257,6 @@ struct net_device *__init mc32_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
/* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
@@ -338,6 +336,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
"82586 initialisation failure",
"Adapter list configuration error"
};
+ DECLARE_MAC_BUF(mac);
/* Time to play MCA games */
@@ -398,17 +397,17 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
* Go PROM browsing
*/
- printk("%s: Address ", dev->name);
-
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
{
mca_write_pos(slot, 6, i+12);
mca_write_pos(slot, 7, 0);
- printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3));
+ dev->dev_addr[i] = mca_read_pos(slot,3);
}
+ printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr));
+
mca_write_pos(slot, 6, 0);
mca_write_pos(slot, 7, 0);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 6deb20fc7a08..8d3893da06f5 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -538,10 +538,10 @@ enum MasterCtrl {
#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */
#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */
struct boom_rx_desc {
- u32 next; /* Last entry points to 0. */
- s32 status;
- u32 addr; /* Up to 63 addr/len pairs possible. */
- s32 length; /* Set LAST_FRAG to indicate last pair. */
+ __le32 next; /* Last entry points to 0. */
+ __le32 status;
+ __le32 addr; /* Up to 63 addr/len pairs possible. */
+ __le32 length; /* Set LAST_FRAG to indicate last pair. */
};
/* Values for the Rx status entry. */
enum rx_desc_status {
@@ -558,16 +558,16 @@ enum rx_desc_status {
#endif
struct boom_tx_desc {
- u32 next; /* Last entry points to 0. */
- s32 status; /* bits 0:12 length, others see below. */
+ __le32 next; /* Last entry points to 0. */
+ __le32 status; /* bits 0:12 length, others see below. */
#if DO_ZEROCOPY
struct {
- u32 addr;
- s32 length;
+ __le32 addr;
+ __le32 length;
} frag[1+MAX_SKB_FRAGS];
#else
- u32 addr;
- s32 length;
+ __le32 addr;
+ __le32 length;
#endif
};
@@ -705,7 +705,7 @@ static struct {
static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
int chip_idx, int card_idx);
-static void vortex_up(struct net_device *dev);
+static int vortex_up(struct net_device *dev);
static void vortex_down(struct net_device *dev, int final);
static int vortex_open(struct net_device *dev);
static void mdio_sync(void __iomem *ioaddr, int bits);
@@ -841,8 +841,11 @@ static int vortex_resume(struct pci_dev *pdev)
return -EBUSY;
}
if (netif_running(dev)) {
- vortex_up(dev);
- netif_device_attach(dev);
+ err = vortex_up(dev);
+ if (err)
+ return err;
+ else
+ netif_device_attach(dev);
}
}
return 0;
@@ -1011,6 +1014,7 @@ static int __devinit vortex_probe1(struct device *gendev,
char *print_name = "3c59x";
struct pci_dev *pdev = NULL;
struct eisa_device *edev = NULL;
+ DECLARE_MAC_BUF(mac);
if (!printed_version) {
printk (version);
@@ -1033,7 +1037,6 @@ static int __devinit vortex_probe1(struct device *gendev,
printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
goto out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gendev);
vp = netdev_priv(dev);
@@ -1128,7 +1131,7 @@ static int __devinit vortex_probe1(struct device *gendev,
+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
&vp->rx_ring_dma);
retval = -ENOMEM;
- if (vp->rx_ring == 0)
+ if (!vp->rx_ring)
goto free_region;
vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
@@ -1201,12 +1204,10 @@ static int __devinit vortex_probe1(struct device *gendev,
if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 3; i++)
- ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
+ ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (print_info) {
- for (i = 0; i < 6; i++)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- }
+ if (print_info)
+ printk(" %s", print_mac(mac, dev->dev_addr));
/* Unfortunately an all zero eeprom passes the checksum and this
gets found in the wild in failure cases. Crypto is hard 8) */
if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -1484,19 +1485,24 @@ static void vortex_check_media(struct net_device *dev, unsigned int init)
}
}
-static void
+static int
vortex_up(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
void __iomem *ioaddr = vp->ioaddr;
unsigned int config;
- int i, mii_reg1, mii_reg5;
+ int i, mii_reg1, mii_reg5, err;
if (VORTEX_PCI(vp)) {
pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */
if (vp->pm_state_valid)
pci_restore_state(VORTEX_PCI(vp));
- pci_enable_device(VORTEX_PCI(vp));
+ err = pci_enable_device(VORTEX_PCI(vp));
+ if (err) {
+ printk(KERN_WARNING "%s: Could not enable device \n",
+ dev->name);
+ goto err_out;
+ }
}
/* Before initializing select the active media port. */
@@ -1555,6 +1561,7 @@ vortex_up(struct net_device *dev)
mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
+ vp->mii.full_duplex = vp->full_duplex;
vortex_check_media(dev, 1);
}
@@ -1660,6 +1667,8 @@ vortex_up(struct net_device *dev)
if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
iowrite32(0x8000, vp->cb_fn_base + 4);
netif_start_queue (dev);
+err_out:
+ return err;
}
static int
@@ -1673,7 +1682,7 @@ vortex_open(struct net_device *dev)
if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
&boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
- goto out;
+ goto err;
}
if (vp->full_bus_master_rx) { /* Boomerang bus master. */
@@ -1702,20 +1711,22 @@ vortex_open(struct net_device *dev)
}
}
retval = -ENOMEM;
- goto out_free_irq;
+ goto err_free_irq;
}
/* Wrap the ring. */
vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
}
- vortex_up(dev);
- return 0;
+ retval = vortex_up(dev);
+ if (!retval)
+ goto out;
-out_free_irq:
+err_free_irq:
free_irq(dev->irq, dev);
-out:
+err:
if (vortex_debug > 1)
printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
+out:
return retval;
}
@@ -2489,7 +2500,7 @@ boomerang_rx(struct net_device *dev)
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
- if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
/* 'skb_put()' points to the start of sk_buff data area. */
@@ -2822,9 +2833,14 @@ static void vortex_set_msglevel(struct net_device *dev, u32 dbg)
vortex_debug = dbg;
}
-static int vortex_get_stats_count(struct net_device *dev)
+static int vortex_get_sset_count(struct net_device *dev, int sset)
{
- return VORTEX_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return VORTEX_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void vortex_get_ethtool_stats(struct net_device *dev,
@@ -2881,12 +2897,11 @@ static const struct ethtool_ops vortex_ethtool_ops = {
.get_msglevel = vortex_get_msglevel,
.set_msglevel = vortex_set_msglevel,
.get_ethtool_stats = vortex_get_ethtool_stats,
- .get_stats_count = vortex_get_stats_count,
+ .get_sset_count = vortex_get_sset_count,
.get_settings = vortex_get_settings,
.set_settings = vortex_set_settings,
.get_link = ethtool_op_get_link,
.nway_reset = vortex_nway_reset,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
#ifdef CONFIG_PCI
@@ -2899,7 +2914,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
struct vortex_private *vp = netdev_priv(dev);
void __iomem *ioaddr = vp->ioaddr;
unsigned long flags;
- int state = 0;
+ pci_power_t state = 0;
if(VORTEX_PCI(vp))
state = VORTEX_PCI(vp)->current_state;
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index e89ace109a5d..224e0bff1ae0 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -305,18 +305,18 @@ static int lance_rx (struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
continue;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (rd->mblength & 0xfff) - 4;
skb = dev_alloc_skb (len+2);
@@ -324,7 +324,7 @@ static int lance_rx (struct net_device *dev)
if (skb == 0) {
printk ("%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
@@ -339,8 +339,8 @@ static int lance_rx (struct net_device *dev)
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
/* Return the packet to the pool */
@@ -377,12 +377,12 @@ static int lance_tx (struct net_device *dev)
if (td->tmd1_bits & LE_T1_ERR) {
status = td->misc;
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk("%s: Carrier Lost, trying %s\n",
@@ -400,7 +400,7 @@ static int lance_tx (struct net_device *dev)
/* buffer errors and underflows turn off the transmitter */
/* Restart the adapter */
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -420,13 +420,13 @@ static int lance_tx (struct net_device *dev)
/* One collision before packet was sent. */
if (td->tmd1_bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (td->tmd1_bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = (j + 1) & lp->tx_ring_mod_mask;
@@ -471,9 +471,9 @@ lance_interrupt (int irq, void *dev_id)
/* Log misc errors. */
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++; /* Tx babble. */
+ dev->stats.tx_errors++; /* Tx babble. */
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++; /* Missed a Rx frame. */
+ dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & LE_C0_MERR) {
printk("%s: Bus master arbitration failure, status %4.4x.\n",
dev->name, csr0);
@@ -589,13 +589,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 0;
}
-struct net_device_stats *lance_get_stats (struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* taken from the depca driver via a2065.c */
static void lance_load_multicast (struct net_device *dev)
{
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
index b1212b5ed92f..0a5837b96421 100644
--- a/drivers/net/7990.h
+++ b/drivers/net/7990.h
@@ -111,7 +111,6 @@ struct lance_private
int lance_log_rx_bufs, lance_log_tx_bufs;
int rx_ring_mod_mask, tx_ring_mod_mask;
- struct net_device_stats stats;
int tpe; /* TPE is selected */
int auto_select; /* cable-selection is by carrier */
unsigned short busmaster_regval;
@@ -246,7 +245,6 @@ struct lance_private
extern int lance_open(struct net_device *dev);
extern int lance_close (struct net_device *dev);
extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev);
-extern struct net_device_stats *lance_get_stats (struct net_device *dev);
extern void lance_set_multicast (struct net_device *dev);
extern void lance_tx_timeout(struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index e970e64bf966..a453eda834d5 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -78,7 +78,7 @@
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define CP_VLAN_TAG_USED 1
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
- do { (tx_desc)->opts2 = (vlan_tag_value); } while (0)
+ do { (tx_desc)->opts2 = cpu_to_le32(vlan_tag_value); } while (0)
#else
#define CP_VLAN_TAG_USED 0
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
@@ -303,25 +303,25 @@ static const unsigned int cp_rx_config =
(RX_DMA_BURST << RxCfgDMAShift);
struct cp_desc {
- u32 opts1;
- u32 opts2;
- u64 addr;
+ __le32 opts1;
+ __le32 opts2;
+ __le64 addr;
};
struct cp_dma_stats {
- u64 tx_ok;
- u64 rx_ok;
- u64 tx_err;
- u32 rx_err;
- u16 rx_fifo;
- u16 frame_align;
- u32 tx_ok_1col;
- u32 tx_ok_mcol;
- u64 rx_ok_phys;
- u64 rx_ok_bcast;
- u32 rx_ok_mcast;
- u16 tx_abort;
- u16 tx_underrun;
+ __le64 tx_ok;
+ __le64 rx_ok;
+ __le64 tx_err;
+ __le32 rx_err;
+ __le16 rx_fifo;
+ __le16 frame_align;
+ __le32 tx_ok_1col;
+ __le32 tx_ok_mcol;
+ __le64 rx_ok_phys;
+ __le64 rx_ok_bcast;
+ __le32 rx_ok_mcast;
+ __le16 tx_abort;
+ __le16 tx_underrun;
} __attribute__((packed));
struct cp_extra_stats {
@@ -334,6 +334,8 @@ struct cp_private {
spinlock_t lock;
u32 msg_enable;
+ struct napi_struct napi;
+
struct pci_dev *pdev;
u32 rx_config;
u16 cpcmd;
@@ -460,9 +462,9 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
cp->dev->last_rx = jiffies;
#if CP_VLAN_TAG_USED
- if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {
+ if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) {
vlan_hwaccel_receive_skb(skb, cp->vlgrp,
- be16_to_cpu(desc->opts2 & 0xffff));
+ swab16(le32_to_cpu(desc->opts2) & 0xffff));
} else
#endif
netif_receive_skb(skb);
@@ -501,12 +503,12 @@ static inline unsigned int cp_rx_csum_ok (u32 status)
return 0;
}
-static int cp_rx_poll (struct net_device *dev, int *budget)
+static int cp_rx_poll(struct napi_struct *napi, int budget)
{
- struct cp_private *cp = netdev_priv(dev);
- unsigned rx_tail = cp->rx_tail;
- unsigned rx_work = dev->quota;
- unsigned rx;
+ struct cp_private *cp = container_of(napi, struct cp_private, napi);
+ struct net_device *dev = cp->dev;
+ unsigned int rx_tail = cp->rx_tail;
+ int rx;
rx_status_loop:
rx = 0;
@@ -560,7 +562,7 @@ rx_status_loop:
skb_reserve(new_skb, RX_OFFSET);
- pci_unmap_single(cp->pdev, mapping,
+ dma_unmap_single(&cp->pdev->dev, mapping,
buflen, PCI_DMA_FROMDEVICE);
/* Handle checksum offloading for incoming packets. */
@@ -571,7 +573,7 @@ rx_status_loop:
skb_put(skb, len);
- mapping = pci_map_single(cp->pdev, new_skb->data, buflen,
+ mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
PCI_DMA_FROMDEVICE);
cp->rx_skb[rx_tail] = new_skb;
@@ -588,33 +590,28 @@ rx_next:
desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
rx_tail = NEXT_RX(rx_tail);
- if (!rx_work--)
+ if (rx >= budget)
break;
}
cp->rx_tail = rx_tail;
- dev->quota -= rx;
- *budget -= rx;
-
/* if we did not reach work limit, then we're done with
* this round of polling
*/
- if (rx_work) {
+ if (rx < budget) {
unsigned long flags;
if (cpr16(IntrStatus) & cp_rx_intr_mask)
goto rx_status_loop;
- local_irq_save(flags);
+ spin_lock_irqsave(&cp->lock, flags);
cpw16_f(IntrMask, cp_intr_mask);
- __netif_rx_complete(dev);
- local_irq_restore(flags);
-
- return 0; /* done */
+ __netif_rx_complete(dev, napi);
+ spin_unlock_irqrestore(&cp->lock, flags);
}
- return 1; /* not done */
+ return rx;
}
static irqreturn_t cp_interrupt (int irq, void *dev_instance)
@@ -647,9 +644,9 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
}
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &cp->napi)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &cp->napi);
}
if (status & (TxOK | TxErr | TxEmpty | SWInt))
@@ -704,7 +701,7 @@ static void cp_tx (struct cp_private *cp)
skb = cp->tx_skb[tx_tail];
BUG_ON(!skb);
- pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr),
+ dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
le32_to_cpu(txd->opts1) & 0xffff,
PCI_DMA_TODEVICE);
@@ -768,7 +765,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
#if CP_VLAN_TAG_USED
if (cp->vlgrp && vlan_tx_tag_present(skb))
- vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb));
+ vlan_tag = TxVlanTag | swab16(vlan_tx_tag_get(skb));
#endif
entry = cp->tx_head;
@@ -782,7 +779,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
len = skb->len;
- mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
CP_VLAN_TX_TAG(txd, vlan_tag);
txd->addr = cpu_to_le64(mapping);
wmb();
@@ -818,7 +815,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
*/
first_eor = eor;
first_len = skb_headlen(skb);
- first_mapping = pci_map_single(cp->pdev, skb->data,
+ first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
first_len, PCI_DMA_TODEVICE);
cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
@@ -830,7 +827,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
len = this_frag->size;
- mapping = pci_map_single(cp->pdev,
+ mapping = dma_map_single(&cp->pdev->dev,
((void *) page_address(this_frag->page) +
this_frag->page_offset),
len, PCI_DMA_TODEVICE);
@@ -1021,8 +1018,8 @@ static void cp_init_hw (struct cp_private *cp)
cpw8_f (Cfg9346, Cfg9346_Unlock);
/* Restore our idea of the MAC address. */
- cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
- cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+ cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
+ cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
cp_start_hw(cp);
cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
@@ -1069,8 +1066,8 @@ static int cp_refill_rx (struct cp_private *cp)
skb_reserve(skb, RX_OFFSET);
- mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ mapping = dma_map_single(&cp->pdev->dev, skb->data,
+ cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
cp->rx_skb[i] = skb;
cp->rx_ring[i].opts2 = 0;
@@ -1110,7 +1107,8 @@ static int cp_alloc_rings (struct cp_private *cp)
{
void *mem;
- mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
+ mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES,
+ &cp->ring_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
@@ -1128,7 +1126,7 @@ static void cp_clean_rings (struct cp_private *cp)
for (i = 0; i < CP_RX_RING_SIZE; i++) {
if (cp->rx_skb[i]) {
desc = cp->rx_ring + i;
- pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+ dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
dev_kfree_skb(cp->rx_skb[i]);
}
@@ -1139,7 +1137,7 @@ static void cp_clean_rings (struct cp_private *cp)
struct sk_buff *skb = cp->tx_skb[i];
desc = cp->tx_ring + i;
- pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+ dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
le32_to_cpu(desc->opts1) & 0xffff,
PCI_DMA_TODEVICE);
if (le32_to_cpu(desc->opts1) & LastFrag)
@@ -1158,7 +1156,8 @@ static void cp_clean_rings (struct cp_private *cp)
static void cp_free_rings (struct cp_private *cp)
{
cp_clean_rings(cp);
- pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+ dma_free_coherent(&cp->pdev->dev, CP_RING_BYTES, cp->rx_ring,
+ cp->ring_dma);
cp->rx_ring = NULL;
cp->tx_ring = NULL;
}
@@ -1175,6 +1174,8 @@ static int cp_open (struct net_device *dev)
if (rc)
return rc;
+ napi_enable(&cp->napi);
+
cp_init_hw(cp);
rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev);
@@ -1188,6 +1189,7 @@ static int cp_open (struct net_device *dev)
return 0;
err_out_hw:
+ napi_disable(&cp->napi);
cp_stop_hw(cp);
cp_free_rings(cp);
return rc;
@@ -1198,6 +1200,8 @@ static int cp_close (struct net_device *dev)
struct cp_private *cp = netdev_priv(dev);
unsigned long flags;
+ napi_disable(&cp->napi);
+
if (netif_msg_ifdown(cp))
printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
@@ -1379,9 +1383,14 @@ static int cp_get_regs_len(struct net_device *dev)
return CP_REGS_SIZE;
}
-static int cp_get_stats_count (struct net_device *dev)
+static int cp_get_sset_count (struct net_device *dev, int sset)
{
- return CP_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return CP_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1517,7 +1526,8 @@ static void cp_get_ethtool_stats (struct net_device *dev,
dma_addr_t dma;
int i;
- nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma);
+ nic_stats = dma_alloc_coherent(&cp->pdev->dev, sizeof(*nic_stats),
+ &dma, GFP_KERNEL);
if (!nic_stats)
return;
@@ -1552,13 +1562,13 @@ static void cp_get_ethtool_stats (struct net_device *dev,
tmp_stats[i++] = cp->cp_stats.rx_frags;
BUG_ON(i != CP_NUM_STATS);
- pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
+ dma_free_coherent(&cp->pdev->dev, sizeof(*nic_stats), nic_stats, dma);
}
static const struct ethtool_ops cp_ethtool_ops = {
.get_drvinfo = cp_get_drvinfo,
.get_regs_len = cp_get_regs_len,
- .get_stats_count = cp_get_stats_count,
+ .get_sset_count = cp_get_sset_count,
.get_settings = cp_get_settings,
.set_settings = cp_set_settings,
.nway_reset = cp_nway_reset,
@@ -1567,18 +1577,14 @@ static const struct ethtool_ops cp_ethtool_ops = {
.set_msglevel = cp_set_msglevel,
.get_rx_csum = cp_get_rx_csum,
.set_rx_csum = cp_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_regs = cp_get_regs,
.get_wol = cp_get_wol,
.set_wol = cp_set_wol,
.get_strings = cp_get_strings,
.get_ethtool_stats = cp_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
.get_eeprom_len = cp_get_eeprom_len,
.get_eeprom = cp_get_eeprom,
.set_eeprom = cp_set_eeprom,
@@ -1822,6 +1828,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *regs;
resource_size_t pciaddr;
unsigned int addr_len, i, pci_using_dac;
+ DECLARE_MAC_BUF(mac);
#ifndef MODULE
static int version_printed;
@@ -1841,7 +1848,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev = alloc_etherdev(sizeof(struct cp_private));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
cp = netdev_priv(dev);
@@ -1924,8 +1930,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* read MAC address from EEPROM */
addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6;
for (i = 0; i < 3; i++)
- ((u16 *) (dev->dev_addr))[i] =
- le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+ ((__le16 *) (dev->dev_addr))[i] =
+ cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->open = cp_open;
@@ -1934,11 +1940,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->hard_start_xmit = cp_start_xmit;
dev->get_stats = cp_get_stats;
dev->do_ioctl = cp_ioctl;
- dev->poll = cp_rx_poll;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = cp_poll_controller;
#endif
- dev->weight = 16; /* arbitrary? from NAPI_HOWTO.txt. */
+ netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
#ifdef BROKEN
dev->change_mtu = cp_change_mtu;
#endif
@@ -1965,13 +1970,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iomap;
printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
- "%02x:%02x:%02x:%02x:%02x:%02x, "
- "IRQ %d\n",
+ "%s, IRQ %d\n",
dev->name,
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 327eaa7b4999..973b684c11e3 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -291,198 +291,197 @@ static struct {
/* Symbolic offsets to registers. */
enum RTL8139_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- TxSummary = 0x60,
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAR0 = 8, /* Multicast filter. */
+ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
+ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf = 0x30,
+ ChipCmd = 0x37,
+ RxBufPtr = 0x38,
+ RxBufAddr = 0x3A,
+ IntrMask = 0x3C,
+ IntrStatus = 0x3E,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ Timer = 0x48, /* A general-purpose counter. */
+ RxMissed = 0x4C, /* 24 bits valid, write clears. */
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ FlashReg = 0x54,
+ MediaStatus = 0x58,
+ Config3 = 0x59,
+ Config4 = 0x5A, /* absent on RTL-8139A */
+ HltClk = 0x5B,
+ MultiIntr = 0x5C,
+ TxSummary = 0x60,
+ BasicModeCtrl = 0x62,
+ BasicModeStatus = 0x64,
+ NWayAdvert = 0x66,
+ NWayLPAR = 0x68,
+ NWayExpansion = 0x6A,
/* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
+ FIFOTMS = 0x70, /* FIFO Control and test. */
+ CSCR = 0x74, /* Chip Status and Configuration Register. */
+ PARA78 = 0x78,
+ PARA7c = 0x7c, /* Magic transceiver parameter register. */
+ Config5 = 0xD8, /* absent on RTL-8139A */
};
enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+ MultiIntrClear = 0xF000,
+ ChipCmdClear = 0xE2,
+ Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
};
enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
};
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+ PCIErr = 0x8000,
+ PCSTimeout = 0x4000,
+ RxFIFOOver = 0x40,
+ RxUnderrun = 0x20,
+ RxOverflow = 0x10,
+ TxErr = 0x08,
+ TxOK = 0x04,
+ RxErr = 0x02,
+ RxOK = 0x01,
+
+ RxAckBits = RxFIFOOver | RxOverflow | RxOK,
};
enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
+ TxHostOwns = 0x2000,
+ TxUnderrun = 0x4000,
+ TxStatOK = 0x8000,
+ TxOutOfWindow = 0x20000000,
+ TxAborted = 0x40000000,
+ TxCarrierLost = 0x80000000,
};
enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
+ RxMulticast = 0x8000,
+ RxPhysical = 0x4000,
+ RxBroadcast = 0x2000,
+ RxBadSymbol = 0x0020,
+ RxRunt = 0x0010,
+ RxTooLong = 0x0008,
+ RxCRCErr = 0x0004,
+ RxBadAlign = 0x0002,
+ RxStatusOK = 0x0001,
};
/* Bits in RxConfig. */
enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
};
/* Bits in TxConfig. */
enum tx_config_bits {
-
/* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
- TxIFGShift = 24,
- TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
- TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
- TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
- TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
-
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
- TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+ TxIFGShift = 24,
+ TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
+ TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
+ TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
+ TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
+
+ TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+ TxCRC = (1 << 16), /* DISABLE Tx pkt CRC append */
+ TxClearAbt = (1 << 0), /* Clear abort (WO) */
+ TxDMAShift = 8, /* DMA burst value (0-7) is shifted X many bits */
+ TxRetryShift = 4, /* TXRR value (0-15) is shifted X many bits */
+
+ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
};
/* Bits in Config1 */
enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- LWAKE = 0x10, /* not on 8139, 8139A */
+ Cfg1_PM_Enable = 0x01,
+ Cfg1_VPD_Enable = 0x02,
+ Cfg1_PIO = 0x04,
+ Cfg1_MMIO = 0x08,
+ LWAKE = 0x10, /* not on 8139, 8139A */
Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
- SLEEP = (1 << 1), /* only on 8139, 8139A */
- PWRDN = (1 << 0), /* only on 8139, 8139A */
+ Cfg1_LED0 = 0x40,
+ Cfg1_LED1 = 0x80,
+ SLEEP = (1 << 1), /* only on 8139, 8139A */
+ PWRDN = (1 << 0), /* only on 8139, 8139A */
};
/* Bits in Config3 */
enum Config3Bits {
- Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
- Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
- Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
- Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
- Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
- Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
- Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
- Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+ Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
+ Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+ Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+ Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
+ Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
+ Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+ Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
+ Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
};
/* Bits in Config4 */
enum Config4Bits {
- LWPTN = (1 << 2), /* not on 8139, 8139A */
+ LWPTN = (1 << 2), /* not on 8139, 8139A */
};
/* Bits in Config5 */
enum Config5Bits {
- Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
- Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
- Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
- Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
- Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
- Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
- Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
+ Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
+ Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
+ Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
+ Cfg5_FIFOAddrPtr= (1 << 3), /* Realtek internal SRAM testing */
+ Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
+ Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
+ Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
};
enum RxConfigBits {
/* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
+ RxCfgFIFOShift = 13,
+ RxCfgFIFONone = (7 << RxCfgFIFOShift),
/* Max DMA burst */
- RxCfgDMAShift = 8,
+ RxCfgDMAShift = 8,
RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
/* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
+ RxCfgRcv8K = 0,
+ RxCfgRcv16K = (1 << 11),
+ RxCfgRcv32K = (1 << 12),
+ RxCfgRcv64K = (1 << 11) | (1 << 12),
/* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
- RxNoWrap = (1 << 7),
+ RxNoWrap = (1 << 7),
};
/* Twister tuning parameters from RealTek.
Completely undocumented, but required to tune bad links on some boards. */
enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
+ CSCR_LinkOKBit = 0x0400,
+ CSCR_LinkChangeBit = 0x0800,
+ CSCR_LinkStatusBits = 0x0f000,
+ CSCR_LinkDownOffCmd = 0x003c0,
+ CSCR_LinkDownCmd = 0x0f3c0,
};
enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xC0,
};
typedef enum {
- CH_8139 = 0,
+ CH_8139 = 0,
CH_8139_K,
CH_8139A,
CH_8139A_G,
@@ -495,8 +494,8 @@ typedef enum {
} chip_t;
enum chip_flags {
- HasHltClk = (1 << 0),
- HasLWake = (1 << 1),
+ HasHltClk = (1 << 0),
+ HasLWake = (1 << 1),
};
#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
@@ -569,36 +568,46 @@ struct rtl_extra_stats {
};
struct rtl8139_private {
- void __iomem *mmio_addr;
- int drv_flags;
- struct pci_dev *pci_dev;
- u32 msg_enable;
- struct net_device_stats stats;
- unsigned char *rx_ring;
- unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
- unsigned int tx_flag;
- unsigned long cur_tx;
- unsigned long dirty_tx;
- unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_bufs_dma;
- signed char phys[4]; /* MII device addresses. */
- char twistie, twist_row, twist_col; /* Twister tune state. */
- unsigned int watchdog_fired : 1;
- unsigned int default_port : 4; /* Last dev->if_port value. */
- unsigned int have_thread : 1;
- spinlock_t lock;
- spinlock_t rx_lock;
- chip_t chipset;
- u32 rx_config;
- struct rtl_extra_stats xstats;
-
- struct delayed_work thread;
-
- struct mii_if_info mii;
- unsigned int regs_len;
- unsigned long fifo_copy_timeout;
+ void __iomem *mmio_addr;
+ int drv_flags;
+ struct pci_dev *pci_dev;
+ u32 msg_enable;
+ struct napi_struct napi;
+ struct net_device *dev;
+ struct net_device_stats stats;
+
+ unsigned char *rx_ring;
+ unsigned int cur_rx; /* RX buf index of next pkt */
+ dma_addr_t rx_ring_dma;
+
+ unsigned int tx_flag;
+ unsigned long cur_tx;
+ unsigned long dirty_tx;
+ unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
+ unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ dma_addr_t tx_bufs_dma;
+
+ signed char phys[4]; /* MII device addresses. */
+
+ /* Twister tune state. */
+ char twistie, twist_row, twist_col;
+
+ unsigned int watchdog_fired : 1;
+ unsigned int default_port : 4; /* Last dev->if_port value. */
+ unsigned int have_thread : 1;
+
+ spinlock_t lock;
+ spinlock_t rx_lock;
+
+ chip_t chipset;
+ u32 rx_config;
+ struct rtl_extra_stats xstats;
+
+ struct delayed_work thread;
+
+ struct mii_if_info mii;
+ unsigned int regs_len;
+ unsigned long fifo_copy_timeout;
};
MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
@@ -625,10 +634,10 @@ static void rtl8139_tx_timeout (struct net_device *dev);
static void rtl8139_init_ring (struct net_device *dev);
static int rtl8139_start_xmit (struct sk_buff *skb,
struct net_device *dev);
-static int rtl8139_poll(struct net_device *dev, int *budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void rtl8139_poll_controller(struct net_device *dev);
#endif
+static int rtl8139_poll(struct napi_struct *napi, int budget);
static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
static int rtl8139_close (struct net_device *dev);
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
@@ -646,24 +655,11 @@ static const struct ethtool_ops rtl8139_ethtool_ops;
#define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
#define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
-
-#define MMIO_FLUSH_AUDIT_COMPLETE 1
-#if MMIO_FLUSH_AUDIT_COMPLETE
-
/* write MMIO register */
#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg))
#define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg))
#define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg))
-#else
-
-/* write MMIO register, then flush */
-#define RTL_W8 RTL_W8_F
-#define RTL_W16 RTL_W16_F
-#define RTL_W32 RTL_W32_F
-
-#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
-
/* read MMIO register */
#define RTL_R8(reg) ioread8 (ioaddr + (reg))
#define RTL_R16(reg) ioread16 (ioaddr + (reg))
@@ -770,7 +766,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
dev_err(&pdev->dev, "Unable to alloc new net device\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
@@ -931,6 +926,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
int i, addr_len, option;
void __iomem *ioaddr;
static int board_idx = -1;
+ DECLARE_MAC_BUF(mac);
assert (pdev != NULL);
assert (ent != NULL);
@@ -963,6 +959,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
assert (dev != NULL);
tp = netdev_priv(dev);
+ tp->dev = dev;
ioaddr = tp->mmio_addr;
assert (ioaddr != NULL);
@@ -976,8 +973,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
/* The Rtl8139-specific entries in the device structure. */
dev->open = rtl8139_open;
dev->hard_start_xmit = rtl8139_start_xmit;
- dev->poll = rtl8139_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
dev->stop = rtl8139_close;
dev->get_stats = rtl8139_get_stats;
dev->set_multicast_list = rtl8139_set_rx_mode;
@@ -1022,14 +1018,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
pci_set_drvdata (pdev, dev);
printk (KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
+ "%s, IRQ %d\n",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
@@ -1314,24 +1307,26 @@ static int rtl8139_open (struct net_device *dev)
if (retval)
return retval;
- tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- &tp->tx_bufs_dma);
- tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- &tp->rx_ring_dma);
+ tp->tx_bufs = dma_alloc_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
+ &tp->tx_bufs_dma, GFP_KERNEL);
+ tp->rx_ring = dma_alloc_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
+ &tp->rx_ring_dma, GFP_KERNEL);
if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
free_irq(dev->irq, dev);
if (tp->tx_bufs)
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
tp->tx_bufs, tp->tx_bufs_dma);
if (tp->rx_ring)
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
return -ENOMEM;
}
+ napi_enable(&tp->napi);
+
tp->mii.full_duplex = tp->mii.force_media;
tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
@@ -2103,39 +2098,32 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
}
}
-static int rtl8139_poll(struct net_device *dev, int *budget)
+static int rtl8139_poll(struct napi_struct *napi, int budget)
{
- struct rtl8139_private *tp = netdev_priv(dev);
+ struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi);
+ struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->mmio_addr;
- int orig_budget = min(*budget, dev->quota);
- int done = 1;
+ int work_done;
spin_lock(&tp->rx_lock);
- if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
- int work_done;
-
- work_done = rtl8139_rx(dev, tp, orig_budget);
- if (likely(work_done > 0)) {
- *budget -= work_done;
- dev->quota -= work_done;
- done = (work_done < orig_budget);
- }
- }
+ work_done = 0;
+ if (likely(RTL_R16(IntrStatus) & RxAckBits))
+ work_done += rtl8139_rx(dev, tp, budget);
- if (done) {
+ if (work_done < budget) {
unsigned long flags;
/*
* Order is important since data can get interrupted
* again when we think we are done.
*/
- local_irq_save(flags);
+ spin_lock_irqsave(&tp->lock, flags);
RTL_W16_F(IntrMask, rtl8139_intr_mask);
- __netif_rx_complete(dev);
- local_irq_restore(flags);
+ __netif_rx_complete(dev, napi);
+ spin_unlock_irqrestore(&tp->lock, flags);
}
spin_unlock(&tp->rx_lock);
- return !done;
+ return work_done;
}
/* The interrupt handler does all of the Rx thread work and cleans up
@@ -2180,9 +2168,9 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
/* Receive packets are processed by poll routine.
If not running start it now. */
if (status & RxAckBits){
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &tp->napi)) {
RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
- __netif_rx_schedule (dev);
+ __netif_rx_schedule(dev, &tp->napi);
}
}
@@ -2223,7 +2211,8 @@ static int rtl8139_close (struct net_device *dev)
void __iomem *ioaddr = tp->mmio_addr;
unsigned long flags;
- netif_stop_queue (dev);
+ netif_stop_queue(dev);
+ napi_disable(&tp->napi);
if (netif_msg_ifdown(tp))
printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
@@ -2248,10 +2237,10 @@ static int rtl8139_close (struct net_device *dev)
rtl8139_tx_clear (tp);
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
+ dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
+ tp->rx_ring, tp->rx_ring_dma);
+ dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
+ tp->tx_bufs, tp->tx_bufs_dma);
tp->rx_ring = NULL;
tp->tx_bufs = NULL;
@@ -2417,9 +2406,14 @@ static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
#endif /* CONFIG_8139TOO_MMIO */
-static int rtl8139_get_stats_count(struct net_device *dev)
+static int rtl8139_get_sset_count(struct net_device *dev, int sset)
{
- return RTL_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return RTL_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
@@ -2450,9 +2444,8 @@ static const struct ethtool_ops rtl8139_ethtool_ops = {
.get_wol = rtl8139_get_wol,
.set_wol = rtl8139_set_wol,
.get_strings = rtl8139_get_strings,
- .get_stats_count = rtl8139_get_stats_count,
+ .get_sset_count = rtl8139_get_sset_count,
.get_ethtool_stats = rtl8139_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 3ff1155459a3..bb30d5be7824 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -57,6 +57,7 @@
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
static char version[] __initdata =
"82596.c $Revision: 1.5 $\n";
@@ -325,7 +326,6 @@ struct i596_private {
struct i596_cmd *cmd_head;
int cmd_backlog;
unsigned long last_cmd;
- struct net_device_stats stats;
struct i596_rfd rfds[RX_RING_SIZE];
struct i596_rbd rbds[RX_RING_SIZE];
struct tx_cmd tx_cmds[TX_RING_SIZE];
@@ -359,7 +359,6 @@ static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void i596_tx_timeout (struct net_device *dev);
static void print_eth(unsigned char *buf, char *str);
@@ -827,7 +826,7 @@ memory_squeeze:
if (skb == NULL) {
/* XXX tulip.c can defer packets here!! */
printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
else {
if (!rx_in_place) {
@@ -843,28 +842,28 @@ memory_squeeze:
#endif
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes+=pkt_len;
}
}
else {
DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
dev->name, rfd->stat));
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if ((rfd->stat) & 0x0001)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if ((rfd->stat) & 0x0080)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if ((rfd->stat) & 0x0100)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if ((rfd->stat) & 0x0200)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if ((rfd->stat) & 0x0400)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if ((rfd->stat) & 0x0800)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if ((rfd->stat) & 0x1000)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
/* Clear the buffer descriptor count and EOF + F flags */
@@ -915,8 +914,8 @@ static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
dev_kfree_skb(skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
ptr->v_next = ptr->b_next = I596_NULL;
tx_cmd->cmd.command = 0; /* Mark as free */
@@ -1037,10 +1036,10 @@ static void i596_tx_timeout (struct net_device *dev)
DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
dev->name));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
/* Shutdown and restart */
i596_reset (dev, lp, ioaddr);
@@ -1049,7 +1048,7 @@ static void i596_tx_timeout (struct net_device *dev)
DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
lp->scb.command = CUC_START | RX_START;
CA (dev);
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies;
@@ -1081,7 +1080,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (tx_cmd->cmd.command) {
printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
dev->name);
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
} else {
@@ -1106,8 +1105,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
i596_add_cmd(dev, &tx_cmd->cmd);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
}
netif_start_queue(dev);
@@ -1117,15 +1116,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void print_eth(unsigned char *add, char *str)
{
- int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
- printk(KERN_DEBUG "i596 0x%p, ", add);
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i + 6]);
- printk(" -->");
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i]);
- printk(" %02X%02X, %s\n", add[12], add[13], str);
+ printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
+ add, print_mac(mac, add + 6), print_mac(mac2, add),
+ add[12], add[13], str);
}
static int io = 0x300;
@@ -1233,11 +1229,9 @@ struct net_device * __init i82596_probe(int unit)
DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
/* The 82596-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->open = i596_open;
dev->stop = i596_close;
dev->hard_start_xmit = i596_start_xmit;
- dev->get_stats = i596_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->tx_timeout = i596_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1343,17 +1337,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
if ((ptr->status) & STAT_OK) {
DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
} else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if ((ptr->status) & 0x0020)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (!((ptr->status) & 0x0040))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if ((ptr->status) & 0x0400)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if ((ptr->status) & 0x0800)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if ((ptr->status) & 0x1000)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
dev_kfree_skb_irq(skb);
@@ -1408,8 +1402,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
if (netif_running(dev)) {
DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
ack_cmd |= RX_START;
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
rebuild_rx_bufs(dev);
}
}
@@ -1492,14 +1486,6 @@ static int i596_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *
- i596_get_stats(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
-
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
*/
@@ -1550,6 +1536,7 @@ static void set_multicast_list(struct net_device *dev)
struct dev_mc_list *dmi;
unsigned char *cp;
struct mc_cmd *cmd;
+ DECLARE_MAC_BUF(mac);
if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
return;
@@ -1560,8 +1547,8 @@ static void set_multicast_list(struct net_device *dev)
for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
memcpy(cp, dmi->dmi_addr, 6);
if (i596_debug > 1)
- DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
+ DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n",
+ dev->name, print_mac(mac, cp)));
}
i596_add_cmd(dev, &cmd->cmd);
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 43d03178064d..9c635a237a9d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -5,6 +5,7 @@
menuconfig NETDEVICES
default y if UML
+ depends on NET
bool "Network device support"
---help---
You can say N here if you don't intend to connect your Linux box to
@@ -134,6 +135,12 @@ config TUN
If you don't know what to use this for, you don't need it.
+config VETH
+ tristate "Virtual ethernet device"
+ ---help---
+ The device is an ethernet tunnel. Devices are created in pairs. When
+ one end receives the packet it appears on its pair and vice versa.
+
config NET_SB1000
tristate "General Instruments Surfboard 1000"
depends on PNP
@@ -158,6 +165,15 @@ config NET_SB1000
If you don't have this card, of course say N.
+config IP1000
+ tristate "IP1000 Gigabit Ethernet support"
+ depends on PCI && EXPERIMENTAL
+ ---help---
+ This driver supports IP1000 gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ipg. This is recommended.
+
source "drivers/net/arcnet/Kconfig"
source "drivers/net/phy/Kconfig"
@@ -224,6 +240,13 @@ config AX88796
AX88796 driver, using platform bus to provide
chip detection and resources
+config AX88796_93CX6
+ bool "ASIX AX88796 external 93CX6 eeprom support"
+ depends on AX88796
+ select EEPROM_93CX6
+ help
+ Select this if your platform comes with an external 93CX6 eeprom.
+
config MACE
tristate "MACE (Power Mac ethernet) support"
depends on PPC_PMAC && PPC32
@@ -465,10 +488,6 @@ config MIPS_AU1X00_ENET
If you have an Alchemy Semi AU1X00 based system
say Y. Otherwise, say N.
-config NET_SB1250_MAC
- tristate "SB1250 Ethernet support"
- depends on SIBYTE_SB1xxx_SOC
-
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
depends on PCI && SGI_IP27
@@ -479,26 +498,6 @@ config SGI_IOC3_ETH
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
-config SGI_IOC3_ETH_HW_RX_CSUM
- bool "Receive hardware checksums"
- depends on SGI_IOC3_ETH && INET
- default y
- help
- The SGI IOC3 network adapter supports TCP and UDP checksums in
- hardware to offload processing of these checksums from the CPU. At
- the moment only acceleration of IPv4 is supported. This option
- enables offloading for checksums on receive. If unsure, say Y.
-
-config SGI_IOC3_ETH_HW_TX_CSUM
- bool "Transmit hardware checksums"
- depends on SGI_IOC3_ETH && INET
- default y
- help
- The SGI IOC3 network adapter supports TCP and UDP checksums in
- hardware to offload processing of these checksums from the CPU. At
- the moment only acceleration of IPv4 is supported. This option
- enables offloading for checksums on transmit. If unsure, say Y.
-
config MIPS_SIM_NET
tristate "MIPS simulator Network device"
depends on MIPS_SIM
@@ -838,6 +837,52 @@ config ULTRA32
<file:Documentation/networking/net-modules.txt>. The module
will be called smc-ultra32.
+config BFIN_MAC
+ tristate "Blackfin 536/537 on-chip mac support"
+ depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+ select CRC32
+ select MII
+ select PHYLIB
+ select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
+ help
+ This is the driver for blackfin on-chip mac device. Say Y if you want it
+ compiled into the kernel. This driver is also available as a module
+ ( = code which can be inserted in and removed from the running kernel
+ whenever you want). The module will be called bfin_mac.
+
+config BFIN_MAC_USE_L1
+ bool "Use L1 memory for rx/tx packets"
+ depends on BFIN_MAC && BF537
+ default y
+ help
+ To get maximum network performace, you should use L1 memory as rx/tx buffers.
+ Say N here if you want to reserve L1 memory for other uses.
+
+config BFIN_TX_DESC_NUM
+ int "Number of transmit buffer packets"
+ depends on BFIN_MAC
+ range 6 10 if BFIN_MAC_USE_L1
+ range 10 100
+ default "10"
+ help
+ Set the number of buffer packets used in driver.
+
+config BFIN_RX_DESC_NUM
+ int "Number of receive buffer packets"
+ depends on BFIN_MAC
+ range 20 100 if BFIN_MAC_USE_L1
+ range 20 800
+ default "20"
+ help
+ Set the number of buffer packets used in driver.
+
+config BFIN_MAC_RMII
+ bool "RMII PHY Interface (EXPERIMENTAL)"
+ depends on BFIN_MAC && EXPERIMENTAL
+ default n
+ help
+ Use Reduced PHY MII Interface
+
config SMC9194
tristate "SMC 9194 support"
depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
@@ -899,7 +944,7 @@ config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
select MII
- depends on ARCH_PXA
+ depends on ARCH_PXA || SUPERH
help
This is a driver for SMSC's LAN911x series of Ethernet chipsets
including the new LAN9115, LAN9116, LAN9117, and LAN9118.
@@ -1205,75 +1250,8 @@ config IBMVETH
<file:Documentation/networking/net-modules.txt>. The module will
be called ibmveth.
-config IBM_EMAC
- tristate "PowerPC 4xx on-chip Ethernet support"
- depends on 4xx && !PPC_MERGE
- help
- This driver supports the PowerPC 4xx EMAC family of on-chip
- Ethernet controllers.
-
-config IBM_EMAC_RXB
- int "Number of receive buffers"
- depends on IBM_EMAC
- default "128"
-
-config IBM_EMAC_TXB
- int "Number of transmit buffers"
- depends on IBM_EMAC
- default "64"
-
-config IBM_EMAC_POLL_WEIGHT
- int "MAL NAPI polling weight"
- depends on IBM_EMAC
- default "32"
-
-config IBM_EMAC_RX_COPY_THRESHOLD
- int "RX skb copy threshold (bytes)"
- depends on IBM_EMAC
- default "256"
-
-config IBM_EMAC_RX_SKB_HEADROOM
- int "Additional RX skb headroom (bytes)"
- depends on IBM_EMAC
- default "0"
- help
- Additional receive skb headroom. Note, that driver
- will always reserve at least 2 bytes to make IP header
- aligned, so usually there is no need to add any additional
- headroom.
-
- If unsure, set to 0.
-
-config IBM_EMAC_PHY_RX_CLK_FIX
- bool "PHY Rx clock workaround"
- depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
- help
- Enable this if EMAC attached to a PHY which doesn't generate
- RX clock if there is no link, if this is the case, you will
- see "TX disable timeout" or "RX disable timeout" in the system
- log.
-
- If unsure, say N.
-
-config IBM_EMAC_DEBUG
- bool "Debugging"
- depends on IBM_EMAC
- default n
-
-config IBM_EMAC_ZMII
- bool
- depends on IBM_EMAC && (NP405H || NP405L || 44x)
- default y
-
-config IBM_EMAC_RGMII
- bool
- depends on IBM_EMAC && 440GX
- default y
-
-config IBM_EMAC_TAH
- bool
- depends on IBM_EMAC && 440GX
- default y
+source "drivers/net/ibm_emac/Kconfig"
+source "drivers/net/ibm_newemac/Kconfig"
config NET_PCI
bool "EISA, VLB, PCI and on board controllers"
@@ -1408,18 +1386,38 @@ config APRICOT
called apricot.
config B44
- tristate "Broadcom 4400 ethernet support"
- depends on NET_PCI && PCI
+ tristate "Broadcom 440x/47xx ethernet support"
+ depends on SSB_POSSIBLE
+ select SSB
select MII
help
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
+ If you have a network (Ethernet) controller of this type, say Y
+ or M and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module will be
called b44.
+# Auto-select SSB PCI-HOST support, if possible
+config B44_PCI_AUTOSELECT
+ bool
+ depends on B44 && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B44_PCICORE_AUTOSELECT
+ bool
+ depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B44_PCI
+ bool
+ depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
+ default y
+
config FORCEDETH
tristate "nForce Ethernet support"
depends on NET_PCI && PCI
@@ -1468,21 +1466,6 @@ config TC35815
depends on NET_PCI && PCI && MIPS
select MII
-config DGRS
- tristate "Digi Intl. RightSwitch SE-X support"
- depends on NET_PCI && (PCI || EISA)
- ---help---
- This is support for the Digi International RightSwitch series of
- PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
- models. If you have a network card of this type, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. More specific
- information is contained in <file:Documentation/networking/dgrs.txt>.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called dgrs.
-
config EEPRO100
tristate "EtherExpressPro/100 support (eepro100, original Becker driver)"
depends on NET_PCI && PCI
@@ -1923,6 +1906,16 @@ menuconfig NETDEV_1000
bool "Ethernet (1000 Mbit)"
depends on !UML
default y
+ ---help---
+ Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+ type of Local Area Network (LAN) in universities and companies.
+
+ Say Y here to get to see options for Gigabit Ethernet drivers.
+ This option alone does not add any kernel code.
+ Note that drivers supporting both 100 and 1000 MBit may be listed
+ under "Ethernet (10 or 100MBit)" instead.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if NETDEV_1000
@@ -1954,14 +1947,15 @@ config ACENIC_OMIT_TIGON_I
The safe and default value for this is N.
config DL2K
- tristate "D-Link DL2000-based Gigabit Ethernet support"
+ tristate "DL2000/TC902x-based Gigabit Ethernet support"
depends on PCI
select CRC32
help
- This driver supports D-Link 2000-based gigabit ethernet cards, which
- includes
+ This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+ which includes
D-Link DGE-550T Gigabit Ethernet Adapter.
D-Link DL2000-based Gigabit Ethernet Adapter.
+ Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
To compile this driver as a module, choose M here: the
module will be called dl2k.
@@ -2014,6 +2008,29 @@ config E1000_DISABLE_PACKET_SPLIT
If in doubt, say N.
+config E1000E
+ tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
+ ethernet family of adapters. For PCI or PCI-X e1000 adapters,
+ use the regular e1000 driver For more information on how to
+ identify your adapter, go to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000e.txt>.
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called e1000e.
+
source "drivers/net/ixp2000/Kconfig"
config MYRI_SBUS
@@ -2098,6 +2115,19 @@ config R8169_VLAN
If in doubt, say Y.
+config SB1250_MAC
+ tristate "SB1250 Gigabit Ethernet support"
+ depends on SIBYTE_SB1xxx_SOC
+ select PHYLIB
+ ---help---
+ This driver supports Gigabit Ethernet interfaces based on the
+ Broadcom SiByte family of System-On-a-Chip parts. They include
+ the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455
+ and BCM1480 chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sb1250-mac.
+
config SIS190
tristate "SiS190/SiS191 gigabit ethernet support"
depends on PCI
@@ -2122,7 +2152,7 @@ config SKGE
with better performance and more complete ethtool support.
It does not support the link failover and network management
- features available in the hardware.
+ features that "portable" vendor supplied sk98lin driver does.
This driver supports adapters based on the original Yukon chipset:
Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
@@ -2160,6 +2190,93 @@ config SKY2_DEBUG
If unsure, say N.
+config SK98LIN
+ tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)"
+ depends on PCI
+ ---help---
+ Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+ compliant Gigabit Ethernet Adapter.
+
+ This driver supports the original Yukon chipset. This driver is
+ deprecated and will be removed from the kernel in the near future,
+ it has been replaced by the skge driver. skge is cleaner and
+ seems to work better.
+
+ This driver does not support the newer Yukon2 chipset. A separate
+ driver, sky2, is provided to support Yukon2-based adapters.
+
+ The following adapters are supported by this driver:
+ - 3Com 3C940 Gigabit LOM Ethernet Adapter
+ - 3Com 3C941 Gigabit LOM Ethernet Adapter
+ - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter
+ - Allied Telesyn AT-2971T Gigabit Ethernet Adapter
+ - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45
+ - EG1032 v2 Instant Gigabit Network Adapter
+ - EG1064 v2 Instant Gigabit Network Adapter
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte)
+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill)
+ - Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel)
+ - Marvell RDK-8001 Adapter
+ - Marvell RDK-8002 Adapter
+ - Marvell RDK-8003 Adapter
+ - Marvell RDK-8004 Adapter
+ - Marvell RDK-8006 Adapter
+ - Marvell RDK-8007 Adapter
+ - Marvell RDK-8008 Adapter
+ - Marvell RDK-8009 Adapter
+ - Marvell RDK-8010 Adapter
+ - Marvell RDK-8011 Adapter
+ - Marvell RDK-8012 Adapter
+ - Marvell RDK-8052 Adapter
+ - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit)
+ - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit)
+ - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
+ - SK-9521 10/100/1000Base-T Adapter
+ - SK-9521 V2.0 10/100/1000Base-T Adapter
+ - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T)
+ - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+ - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link)
+ - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX)
+ - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+ - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link)
+ - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX)
+ - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+ - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link)
+ - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+ - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition)
+ - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+ - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link)
+ - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX)
+ - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+ - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)
+ - SMC EZ Card 1000 (SMC9452TXV.2)
+
+ The adapters support Jumbo Frames.
+ The dual link adapters support link-failover and dual port features.
+ Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support
+ the scatter-gather functionality with sendfile(). Please refer to
+ <file:Documentation/networking/sk98lin.txt> for more information about
+ optional driver parameters.
+ Questions concerning this driver may be addressed to:
+ <linux@syskonnect.de>
+
+ If you want to compile this driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read <file:Documentation/kbuild/modules.txt>. The module will
+ be called sk98lin. This is recommended.
+
config VIA_VELOCITY
tristate "VIA Velocity support"
depends on PCI
@@ -2294,6 +2411,11 @@ menuconfig NETDEV_10000
bool "Ethernet (10000 Mbit)"
depends on !UML
default y
+ ---help---
+ Say Y here to get to see options for 10 Gigabit Ethernet drivers.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
if NETDEV_10000
@@ -2354,18 +2476,42 @@ config CHELSIO_T3
config EHEA
tristate "eHEA Ethernet support"
depends on IBMEBUS
+ select INET_LRO
---help---
This driver supports the IBM pSeries eHEA ethernet adapter.
To compile the driver as a module, choose M here. The module
will be called ehea.
+config IXGBE
+ tristate "Intel(R) 10GbE PCI Express adapters support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) 10GbE PCI Express family of
+ adapters. For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgbe.txt>.
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called ixgbe.
+
config IXGB
tristate "Intel(R) PRO/10GbE support"
depends on PCI
---help---
- This driver supports Intel(R) PRO/10GbE family of
- adapters. For more information on how to identify your adapter, go
+ This driver supports Intel(R) PRO/10GbE family of adapters for
+ PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
+ instead. For more information on how to identify your adapter, go
to the Adapter & Driver ID Guide at:
<http://support.intel.com/support/network/adapter/pro100/21397.htm>
@@ -2429,6 +2575,7 @@ config MYRI10GE
depends on PCI
select FW_LOADER
select CRC32
+ select INET_LRO
---help---
This driver supports Myricom Myri-10G Dual Protocol interface in
Ethernet mode. If the eeprom on your board is not recent enough,
@@ -2447,6 +2594,13 @@ config NETXEN_NIC
help
This enables the support for NetXen's Gigabit Ethernet card.
+config NIU
+ tristate "Sun Neptune 10Gbit Ethernet support"
+ depends on PCI
+ help
+ This enables support for cards based upon Sun's
+ Neptune chipset.
+
config PASEMI_MAC
tristate "PA Semi 1/10Gbit MAC"
depends on PPC64 && PCI
@@ -2470,6 +2624,12 @@ config MLX4_DEBUG
debug_level module parameter (which can also be set after
the driver is loaded through sysfs).
+config TEHUTI
+ tristate "Tehuti Networks 10G Ethernet"
+ depends on PCI
+ help
+ Tehuti Networks 10G Ethernet NIC
+
endif # NETDEV_10000
source "drivers/net/tokenring/Kconfig"
@@ -2486,6 +2646,18 @@ source "drivers/atm/Kconfig"
source "drivers/s390/net/Kconfig"
+config XEN_NETDEV_FRONTEND
+ tristate "Xen network device frontend driver"
+ depends on XEN
+ default y
+ help
+ The network device frontend driver allows the kernel to
+ access network devices exported exported by a virtual
+ machine containing a physical network device driver. The
+ frontend driver is intended for unprivileged guest domains;
+ if you are compiling a kernel for a Xen guest, you almost
+ certainly want to enable this.
+
config ISERIES_VETH
tristate "iSeries Virtual Ethernet driver support"
depends on PPC_ISERIES
@@ -2794,7 +2966,7 @@ config PPPOATM
config PPPOL2TP
tristate "PPP over L2TP (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PPP
+ depends on EXPERIMENTAL && PPP && INET
help
Support for PPP-over-L2TP socket family. L2TP is a protocol
used by ISPs and enterprises to tunnel PPP traffic over UDP
@@ -2915,6 +3087,16 @@ config NETCONSOLE
If you want to log kernel messages over the network, enable this.
See <file:Documentation/networking/netconsole.txt> for details.
+config NETCONSOLE_DYNAMIC
+ bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)"
+ depends on NETCONSOLE && SYSFS && EXPERIMENTAL
+ select CONFIGFS_FS
+ help
+ This option enables the ability to dynamically reconfigure target
+ parameters (interface, IP addresses, port numbers, MAC addresses)
+ at runtime through a userspace interface exported using configfs.
+ See <file:Documentation/networking/netconsole.txt> for details.
+
config NETPOLL
def_bool NETCONSOLE
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index eb4167622a6a..d2e0f35da42e 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -3,14 +3,19 @@
#
obj-$(CONFIG_E1000) += e1000/
+obj-$(CONFIG_E1000E) += e1000e/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
+obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
+obj-$(CONFIG_IXGBE) += ixgbe/
obj-$(CONFIG_IXGB) += ixgb/
+obj-$(CONFIG_IP1000) += ipg.o
obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_ATL1) += atl1/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_TEHUTI) += tehuti.o
gianfar_driver-objs := gianfar.o \
gianfar_ethtool.o \
@@ -18,7 +23,7 @@ gianfar_driver-objs := gianfar.o \
gianfar_sysfs.o
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o ucc_geth_ethtool.o
#
# link order important here
@@ -39,7 +44,6 @@ obj-$(CONFIG_SUNVNET) += sunvnet.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
-obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
@@ -66,6 +70,7 @@ ps3_gelic-objs += ps3_gelic_net.o
obj-$(CONFIG_TC35815) += tc35815.o
obj-$(CONFIG_SKGE) += skge.o
obj-$(CONFIG_SKY2) += sky2.o
+obj-$(CONFIG_SK98LIN) += sk98lin/
obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
@@ -105,7 +110,7 @@ obj-$(CONFIG_E2100) += e2100.o 8390.o
obj-$(CONFIG_ES3210) += es3210.o 8390.o
obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
-obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
+obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o
@@ -127,6 +132,8 @@ obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o
obj-$(CONFIG_SLIP) += slip.o
obj-$(CONFIG_SLHC) += slhc.o
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACVLAN) += macvlan.o
@@ -175,6 +182,7 @@ obj-$(CONFIG_ZORRO8390) += zorro8390.o
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
obj-$(CONFIG_EQUALIZER) += eql.o
+obj-$(CONFIG_LGUEST_NET) += lguest_net.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
@@ -189,6 +197,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_VETH) += veth.o
obj-$(CONFIG_NET_NETX) += netx-eth.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
@@ -198,6 +207,7 @@ obj-$(CONFIG_S2IO) += s2io.o
obj-$(CONFIG_MYRI10GE) += myri10ge/
obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
@@ -231,3 +241,4 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o
obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
+obj-$(CONFIG_NIU) += niu.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index a45de6975bfe..18f7f815f66e 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -119,7 +119,6 @@ struct lance_private {
int lance_log_rx_bufs, lance_log_tx_bufs;
int rx_ring_mod_mask, tx_ring_mod_mask;
- struct net_device_stats stats;
int tpe; /* cable-selection is TPE */
int auto_select; /* cable-selection by carrier */
unsigned short busmaster_regval;
@@ -294,18 +293,18 @@ static int lance_rx (struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
continue;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (rd->mblength & 0xfff) - 4;
skb = dev_alloc_skb (len+2);
@@ -313,7 +312,7 @@ static int lance_rx (struct net_device *dev)
if (skb == 0) {
printk(KERN_WARNING "%s: Memory squeeze, "
"deferring packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
@@ -328,8 +327,8 @@ static int lance_rx (struct net_device *dev)
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
/* Return the packet to the pool */
@@ -364,12 +363,12 @@ static int lance_tx (struct net_device *dev)
if (td->tmd1_bits & LE_T1_ERR) {
status = td->misc;
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk(KERN_ERR "%s: Carrier Lost, "
@@ -388,7 +387,7 @@ static int lance_tx (struct net_device *dev)
/* buffer errors and underflows turn off the transmitter */
/* Restart the adapter */
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, "
"restarting\n", dev->name);
@@ -408,13 +407,13 @@ static int lance_tx (struct net_device *dev)
/* One collision before packet was sent. */
if (td->tmd1_bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (td->tmd1_bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = (j + 1) & lp->tx_ring_mod_mask;
@@ -459,9 +458,9 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id)
/* Log misc errors. */
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++; /* Tx babble. */
+ dev->stats.tx_errors++; /* Tx babble. */
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++; /* Missed a Rx frame. */
+ dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & LE_C0_MERR) {
printk(KERN_ERR "%s: Bus master arbitration failure, status "
"%4.4x.\n", dev->name, csr0);
@@ -606,7 +605,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
/* Now, give the packet to the lance */
ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
- lp->stats.tx_bytes += skblen;
+ dev->stats.tx_bytes += skblen;
if (TX_BUFFS_AVAIL <= 0)
netif_stop_queue(dev);
@@ -621,13 +620,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
return status;
}
-static struct net_device_stats *lance_get_stats (struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* taken from the depca driver */
static void lance_load_multicast (struct net_device *dev)
{
@@ -724,6 +716,7 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
unsigned long board, base_addr, mem_start;
struct resource *r1, *r2;
int err;
+ DECLARE_MAC_BUF(mac);
board = z->resource.start;
base_addr = board+A2065_LANCE;
@@ -746,7 +739,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
priv = netdev_priv(dev);
r1->name = dev->name;
@@ -783,7 +775,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
dev->hard_start_xmit = &lance_start_xmit;
dev->tx_timeout = &lance_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0;
@@ -802,9 +793,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
zorro_set_drvdata(z, dev);
printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ "%s\n", dev->name, board,
+ print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 644c408515df..5136d94923aa 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -103,8 +103,6 @@ static int __init do_ac3200_probe(struct net_device *dev)
int irq = dev->irq;
int mem_start = dev->mem_start;
- SET_MODULE_OWNER(dev);
-
if (ioaddr > 0x1ff) /* Check a single specified location. */
return ac_probe1(ioaddr, dev);
else if (ioaddr > 0) /* Don't probe at all. */
@@ -148,6 +146,7 @@ out:
static int __init ac_probe1(int ioaddr, struct net_device *dev)
{
int i, retval;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -169,10 +168,11 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
#endif
- printk("AC3200 in EISA slot %d, node", ioaddr/0x1000);
- for(i = 0; i < 6; i++)
- printk(" %02x", dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i));
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
+ printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s",
+ ioaddr/0x1000, print_mac(mac, dev->dev_addr));
#if 0
/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index b78a4e5ceeb2..6c192650d349 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -406,7 +406,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define DEF_STAT (2 * TICKS_PER_SEC)
-static int link[ACE_MAX_MOD_PARMS];
+static int link_state[ACE_MAX_MOD_PARMS];
static int trace[ACE_MAX_MOD_PARMS];
static int tx_coal_tick[ACE_MAX_MOD_PARMS];
static int rx_coal_tick[ACE_MAX_MOD_PARMS];
@@ -419,7 +419,7 @@ MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
-module_param_array(link, int, NULL, 0);
+module_param_array_named(link, link_state, int, NULL, 0);
module_param_array(trace, int, NULL, 0);
module_param_array(tx_coal_tick, int, NULL, 0);
module_param_array(max_tx_desc, int, NULL, 0);
@@ -465,7 +465,6 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
ap = dev->priv;
@@ -894,6 +893,7 @@ static int __devinit ace_init(struct net_device *dev)
int board_idx, ecode = 0;
short i;
unsigned char cache_size;
+ DECLARE_MAC_BUF(mac);
ap = netdev_priv(dev);
regs = ap->regs;
@@ -987,36 +987,32 @@ static int __devinit ace_init(struct net_device *dev)
mac1 = 0;
for(i = 0; i < 4; i++) {
- int tmp;
+ int t;
mac1 = mac1 << 8;
- tmp = read_eeprom_byte(dev, 0x8c+i);
- if (tmp < 0) {
+ t = read_eeprom_byte(dev, 0x8c+i);
+ if (t < 0) {
ecode = -EIO;
goto init_error;
} else
- mac1 |= (tmp & 0xff);
+ mac1 |= (t & 0xff);
}
mac2 = 0;
for(i = 4; i < 8; i++) {
- int tmp;
+ int t;
mac2 = mac2 << 8;
- tmp = read_eeprom_byte(dev, 0x8c+i);
- if (tmp < 0) {
+ t = read_eeprom_byte(dev, 0x8c+i);
+ if (t < 0) {
ecode = -EIO;
goto init_error;
} else
- mac2 |= (tmp & 0xff);
+ mac2 |= (t & 0xff);
}
writel(mac1, &regs->MacAddrHi);
writel(mac2, &regs->MacAddrLo);
- printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
- (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff,
- (mac2 >> 16) & 0xff, (mac2 >> 8) & 0xff, mac2 & 0xff);
-
dev->dev_addr[0] = (mac1 >> 8) & 0xff;
dev->dev_addr[1] = mac1 & 0xff;
dev->dev_addr[2] = (mac2 >> 24) & 0xff;
@@ -1024,6 +1020,8 @@ static int __devinit ace_init(struct net_device *dev)
dev->dev_addr[4] = (mac2 >> 8) & 0xff;
dev->dev_addr[5] = mac2 & 0xff;
+ printk("MAC: %s\n", print_mac(mac, dev->dev_addr));
+
/*
* Looks like this is necessary to deal with on all architectures,
* even this %$#%$# N440BX Intel based thing doesn't get it right.
@@ -1307,10 +1305,10 @@ static int __devinit ace_init(struct net_device *dev)
writel(TX_RING_BASE, &regs->WinBase);
if (ACE_IS_TIGON_I(ap)) {
- ap->tx_ring = (struct tx_desc *) regs->Window;
+ ap->tx_ring = (__force struct tx_desc *) regs->Window;
for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
* sizeof(struct tx_desc)) / sizeof(u32); i++)
- writel(0, (void __iomem *)ap->tx_ring + i * 4);
+ writel(0, (__force void __iomem *)ap->tx_ring + i * 4);
set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
} else {
@@ -1396,8 +1394,8 @@ static int __devinit ace_init(struct net_device *dev)
/*
* Override link default parameters
*/
- if ((board_idx >= 0) && link[board_idx]) {
- int option = link[board_idx];
+ if ((board_idx >= 0) && link_state[board_idx]) {
+ int option = link_state[board_idx];
tmp = LNK_ENABLE;
@@ -2385,8 +2383,9 @@ static int ace_close(struct net_device *dev)
if (mapping) {
if (ACE_IS_TIGON_I(ap)) {
- struct tx_desc __iomem *tx
- = (struct tx_desc __iomem *) &ap->tx_ring[i];
+ /* NB: TIGON_1 is special, tx_ring is in io space */
+ struct tx_desc __iomem *tx;
+ tx = (__force struct tx_desc __iomem *) &ap->tx_ring[i];
writel(0, &tx->addr.addrhi);
writel(0, &tx->addr.addrlo);
writel(0, &tx->flagsize);
@@ -2446,7 +2445,7 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr,
#endif
if (ACE_IS_TIGON_I(ap)) {
- struct tx_desc __iomem *io = (struct tx_desc __iomem *) desc;
+ struct tx_desc __iomem *io = (__force struct tx_desc __iomem *) desc;
writel(addr >> 32, &io->addr.addrhi);
writel(addr & 0xffffffff, &io->addr.addrlo);
writel(flagsize, &io->flagsize);
@@ -2938,7 +2937,7 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz
* This operation requires the NIC to be halted and is performed with
* interrupts disabled and with the spinlock hold.
*/
-int __devinit ace_load_firmware(struct net_device *dev)
+static int __devinit ace_load_firmware(struct net_device *dev)
{
struct ace_private *ap = netdev_priv(dev);
struct ace_regs __iomem *regs = ap->regs;
@@ -3128,12 +3127,6 @@ static int __devinit read_eeprom_byte(struct net_device *dev,
int result = 0;
short i;
- if (!dev) {
- printk(KERN_ERR "No device!\n");
- result = -ENODEV;
- goto out;
- }
-
/*
* Don't take interrupts on this CPU will bit banging
* the %#%#@$ I2C device
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index a61b2f89fc33..1cc74ec88a58 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -709,7 +709,8 @@ static int amd8111e_tx(struct net_device *dev)
lp->tx_complete_idx++;
/*COAL update tx coalescing parameters */
lp->coal_conf.tx_packets++;
- lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
+ lp->coal_conf.tx_bytes +=
+ le16_to_cpu(lp->tx_ring[tx_index].buff_count);
if (netif_queue_stopped(dev) &&
lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
@@ -723,9 +724,10 @@ static int amd8111e_tx(struct net_device *dev)
#ifdef CONFIG_AMD8111E_NAPI
/* This function handles the driver receive operation in polling mode */
-static int amd8111e_rx_poll(struct net_device *dev, int * budget)
+static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
{
- struct amd8111e_priv *lp = netdev_priv(dev);
+ struct amd8111e_priv *lp = container_of(napi, struct amd8111e_priv, napi);
+ struct net_device *dev = lp->amd8111e_net_dev;
int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
void __iomem *mmio = lp->mmio;
struct sk_buff *skb,*new_skb;
@@ -737,7 +739,7 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
#if AMD8111E_VLAN_TAG_USED
short vtag;
#endif
- int rx_pkt_limit = dev->quota;
+ int rx_pkt_limit = budget;
unsigned long flags;
do{
@@ -838,21 +840,14 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
} while(intr0 & RINT0);
/* Receive descriptor is empty now */
- dev->quota -= num_rx_pkt;
- *budget -= num_rx_pkt;
-
spin_lock_irqsave(&lp->lock, flags);
- netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
writel(VAL0|RINTEN0, mmio + INTEN0);
writel(VAL2 | RDMD0, mmio + CMD0);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
rx_not_empty:
- /* Do not call a netif_rx_complete */
- dev->quota -= num_rx_pkt;
- *budget -= num_rx_pkt;
- return 1;
+ return num_rx_pkt;
}
#else
@@ -1287,11 +1282,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id)
/* Check if Receive Interrupt has occurred. */
#ifdef CONFIG_AMD8111E_NAPI
if(intr0 & RINT0){
- if(netif_rx_schedule_prep(dev)){
+ if(netif_rx_schedule_prep(dev, &lp->napi)){
/* Disable receive interupts */
writel(RINTEN0, mmio + INTEN0);
/* Schedule a polling routine */
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &lp->napi);
}
else if (intren0 & RINTEN0) {
printk("************Driver bug! \
@@ -1345,6 +1340,8 @@ static int amd8111e_close(struct net_device * dev)
struct amd8111e_priv *lp = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&lp->napi);
+
spin_lock_irq(&lp->lock);
amd8111e_disable_interrupt(lp);
@@ -1375,12 +1372,15 @@ static int amd8111e_open(struct net_device * dev )
dev->name, dev))
return -EAGAIN;
+ napi_enable(&lp->napi);
+
spin_lock_irq(&lp->lock);
amd8111e_init_hw_default(lp);
if(amd8111e_restart(dev)){
spin_unlock_irq(&lp->lock);
+ napi_disable(&lp->napi);
if (dev->irq)
free_irq(dev->irq, dev);
return -ENOMEM;
@@ -1405,7 +1405,7 @@ This function checks if there is any transmit descriptors available to queue mo
static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp )
{
int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK;
- if(lp->tx_skbuff[tx_index] != 0)
+ if (lp->tx_skbuff[tx_index])
return -1;
else
return 0;
@@ -1442,7 +1442,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
lp->tx_dma_addr[tx_index] =
pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
lp->tx_ring[tx_index].buff_phy_addr =
- (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
+ cpu_to_le32(lp->tx_dma_addr[tx_index]);
/* Set FCS and LTINT bits */
wmb();
@@ -1935,6 +1935,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
unsigned long reg_addr,reg_len;
struct amd8111e_priv* lp;
struct net_device* dev;
+ DECLARE_MAC_BUF(mac);
err = pci_enable_device(pdev);
if(err){
@@ -1983,7 +1984,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
goto err_free_reg;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#if AMD8111E_VLAN_TAG_USED
@@ -1999,7 +1999,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
spin_lock_init(&lp->lock);
lp->mmio = ioremap(reg_addr, reg_len);
- if (lp->mmio == 0) {
+ if (!lp->mmio) {
printk(KERN_ERR "amd8111e: Cannot map device registers, "
"exiting\n");
err = -ENOMEM;
@@ -2008,7 +2008,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
/* Initializing MAC address */
for(i = 0; i < ETH_ADDR_LEN; i++)
- dev->dev_addr[i] =readb(lp->mmio + PADR + i);
+ dev->dev_addr[i] = readb(lp->mmio + PADR + i);
/* Setting user defined parametrs */
lp->ext_phy_option = speed_duplex[card_idx];
@@ -2031,8 +2031,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
dev->tx_timeout = amd8111e_tx_timeout;
dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
#ifdef CONFIG_AMD8111E_NAPI
- dev->poll = amd8111e_rx_poll;
- dev->weight = 32;
+ netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = amd8111e_poll;
@@ -2078,11 +2077,10 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
/* display driver and device information */
chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
- printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS);
- printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
- printk( "\n");
+ printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n",
+ dev->name,MODULE_VERS);
+ printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n",
+ dev->name, chip_version, print_mac(mac, dev->dev_addr));
if (lp->ext_phy_id)
printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
dev->name, lp->ext_phy_id, lp->ext_phy_addr);
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index e65080a5994a..28c60a71ed50 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -655,32 +655,32 @@ typedef enum {
struct amd8111e_tx_dr{
- u16 buff_count; /* Size of the buffer pointed by this descriptor */
+ __le16 buff_count; /* Size of the buffer pointed by this descriptor */
- u16 tx_flags;
+ __le16 tx_flags;
- u16 tag_ctrl_info;
+ __le16 tag_ctrl_info;
- u16 tag_ctrl_cmd;
+ __le16 tag_ctrl_cmd;
- u32 buff_phy_addr;
+ __le32 buff_phy_addr;
- u32 reserved;
+ __le32 reserved;
};
struct amd8111e_rx_dr{
- u32 reserved;
+ __le32 reserved;
- u16 msg_count; /* Received message len */
+ __le16 msg_count; /* Received message len */
- u16 tag_ctrl_info;
+ __le16 tag_ctrl_info;
- u16 buff_count; /* Len of the buffer pointed by descriptor. */
+ __le16 buff_count; /* Len of the buffer pointed by descriptor. */
- u16 rx_flags;
+ __le16 rx_flags;
- u32 buff_phy_addr;
+ __le32 buff_phy_addr;
};
struct amd8111e_link_config{
@@ -763,6 +763,8 @@ struct amd8111e_priv{
/* Reg memory mapped address */
void __iomem *mmio;
+ struct napi_struct napi;
+
spinlock_t lock; /* Guard lock */
unsigned long rx_idx, tx_idx; /* The next free ring entry */
unsigned long tx_complete_idx;
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index 954191119d35..c12cbdf368b1 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -148,7 +148,6 @@ struct net_device * __init apne_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
/* disable pcmcia irq for readtuple */
pcmcia_disable_irq();
@@ -205,6 +204,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
int neX000, ctron;
#endif
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -247,7 +247,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
{0x00, NE_EN0_RSARHI},
{E8390_RREAD+E8390_START, NE_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
outb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -317,12 +317,12 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
- }
- printk("\n%s: %s found.\n", dev->name, name);
+ printk(" %s\n", print_mac(mac, dev->dev_addr));
+
+ printk("%s: %s found.\n", dev->name, name);
ei_status.name = name;
ei_status.tx_start_page = start_page;
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index da6ffa8cd81e..92c3a4cf0bb1 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -194,10 +194,6 @@ static void cops_timeout(struct net_device *dev);
static void cops_rx (struct net_device *dev);
static int cops_send_packet (struct sk_buff *skb, struct net_device *dev);
static void set_multicast_list (struct net_device *dev);
-static int cops_hard_header (struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len);
-
static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static int cops_close (struct net_device *dev);
static struct net_device_stats *cops_get_stats (struct net_device *dev);
@@ -235,8 +231,6 @@ struct net_device * __init cops_probe(int unit)
base_addr = dev->base_addr = io;
}
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) { /* Check a single specified location. */
err = cops_probe1(dev, base_addr);
} else if (base_addr != 0) { /* Don't probe at all. */
@@ -333,7 +327,6 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
lp = netdev_priv(dev);
- memset(lp, 0, sizeof(struct cops_local));
spin_lock_init(&lp->lock);
/* Copy local board variable to lp struct. */
@@ -342,7 +335,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
dev->hard_start_xmit = cops_send_packet;
dev->tx_timeout = cops_timeout;
dev->watchdog_timeo = HZ * 2;
- dev->hard_header = cops_hard_header;
+
dev->get_stats = cops_get_stats;
dev->open = cops_open;
dev->stop = cops_close;
@@ -947,19 +940,6 @@ static void set_multicast_list(struct net_device *dev)
}
/*
- * Another Dummy function to keep the Appletalk layer happy.
- */
-
-static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
-{
- if(cops_debug >= 3)
- printk("%s: cops_hard_header executed. Wow!\n", dev->name);
- return 0;
-}
-
-/*
* System ioctls for the COPS LocalTalk card.
*/
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index f22e46dfd770..1071144edd66 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -65,7 +65,6 @@ static struct net_device * __init ipddp_init(void)
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
strcpy(dev->name, "ipddp%d");
if (version_printed++ == 0)
@@ -117,7 +116,7 @@ static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
*/
static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
{
- u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
+ __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
struct ddpehdr *ddp;
struct ipddp_route *rt;
struct atalk_addr *our_addr;
diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h
index 52072fb0c610..531519da99a3 100644
--- a/drivers/net/appletalk/ipddp.h
+++ b/drivers/net/appletalk/ipddp.h
@@ -14,7 +14,7 @@
struct ipddp_route
{
struct net_device *dev; /* Carrier device */
- __u32 ip; /* IP address */
+ __be32 ip; /* IP address */
struct atalk_addr at; /* Gateway appletalk address */
int flags;
struct ipddp_route *next;
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 6a6cbd331a16..6ab2c2d4d673 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -870,15 +870,6 @@ static void set_multicast_list(struct net_device *dev)
/* Actually netatalk needs fixing! */
}
-static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
-{
- if(debug & DEBUG_VERBOSE)
- printk("ltpc_hard_header called for device %s\n",
- dev->name);
- return 0;
-}
-
static int ltpc_poll_counter;
static void ltpc_poll(unsigned long l)
@@ -1046,8 +1037,6 @@ struct net_device * __init ltpc_probe(void)
if (!dev)
goto out;
- SET_MODULE_OWNER(dev);
-
/* probe for the I/O port address */
if (io != 0x240 && request_region(0x220,8,"ltpc")) {
@@ -1143,7 +1132,6 @@ struct net_device * __init ltpc_probe(void)
/* Fill in the fields of the device structure with ethernet-generic values. */
dev->hard_start_xmit = ltpc_xmit;
- dev->hard_header = ltpc_hard_header;
dev->get_stats = ltpc_get_stats;
/* add the ltpc-specific things */
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 681e20b8466f..c59c8067de99 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -102,8 +102,8 @@ static int arcnet_close(struct net_device *dev);
static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
static void arcnet_timeout(struct net_device *dev);
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len);
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len);
static int arcnet_rebuild_header(struct sk_buff *skb);
static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
static int go_tx(struct net_device *dev);
@@ -317,11 +317,17 @@ static int choose_mtu(void)
return mtu == 65535 ? XMTU : mtu;
}
+static const struct header_ops arcnet_header_ops = {
+ .create = arcnet_header,
+ .rebuild = arcnet_rebuild_header,
+};
+
/* Setup a struct device for ARCnet. */
static void arcdev_setup(struct net_device *dev)
{
dev->type = ARPHRD_ARCNET;
+ dev->header_ops = &arcnet_header_ops;
dev->hard_header_len = sizeof(struct archdr);
dev->mtu = choose_mtu();
@@ -342,8 +348,6 @@ static void arcdev_setup(struct net_device *dev)
dev->hard_start_xmit = arcnet_send_packet;
dev->tx_timeout = arcnet_timeout;
dev->get_stats = arcnet_get_stats;
- dev->hard_header = arcnet_header;
- dev->rebuild_header = arcnet_rebuild_header;
}
struct net_device *alloc_arcdev(char *name)
@@ -488,10 +492,10 @@ static int arcnet_close(struct net_device *dev)
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
- struct arcnet_local *lp = dev->priv;
+ const struct arcnet_local *lp = netdev_priv(dev);
uint8_t _daddr, proto_num;
struct ArcProto *proto;
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 1f0302735416..6599f1046c7b 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -398,8 +398,6 @@ static int __init com90io_init(void)
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
-
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
index 2de8877ece29..dab185bc51f1 100644
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -34,7 +34,7 @@
#define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n"
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev);
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
static int build_header(struct sk_buff *skb, struct net_device *dev,
@@ -86,7 +86,7 @@ MODULE_LICENSE("GPL");
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = dev->priv;
struct archdr *pkt = (struct archdr *) skb->data;
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index 460a095000c2..6d6d95cc4404 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -34,7 +34,7 @@ MODULE_LICENSE("GPL");
#define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n"
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev);
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
static int build_header(struct sk_buff *skb, struct net_device *dev,
@@ -88,7 +88,7 @@ module_exit(arcnet_rfc1201_exit);
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct archdr *pkt = (struct archdr *) skb->data;
struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
@@ -456,7 +456,7 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
excsoft.proto = soft->proto;
excsoft.split_flag = 0xff;
- excsoft.sequence = 0xffff;
+ excsoft.sequence = htons(0xffff);
hard->offset[0] = 0;
ofs = 512 - softlen;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index bc5a38a6705f..3fa3bccd1adb 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -166,6 +166,7 @@ static int __devinit ariadne_init_one(struct zorro_dev *z,
struct net_device *dev;
struct ariadne_private *priv;
int err;
+ DECLARE_MAC_BUF(mac);
r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960");
if (!r1)
@@ -183,7 +184,6 @@ static int __devinit ariadne_init_one(struct zorro_dev *z,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
priv = netdev_priv(dev);
r1->name = dev->name;
@@ -217,9 +217,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z,
zorro_set_drvdata(z, dev);
printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ "%s\n", dev->name, board,
+ print_mac(mac, dev->dev_addr));
return 0;
}
@@ -615,21 +614,17 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fill in a Tx ring entry */
#if 0
- printk(KERN_DEBUG "TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
- {
- int i;
- u_char *ptr = &((u_char *)skb->data)[6];
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
- }
- printk(" to ");
- {
- int i;
- u_char *ptr = (u_char *)skb->data;
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
- }
- printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+{
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s "
+ " data 0x%08x len %d\n",
+ ((u_short *)skb->data)[6],
+ print_mac(mac, ((const u8 *)skb->data)+6),
+ print_mac(mac, (const u8 *)skb->data),
+ (int)skb->data, (int)skb->len);
+}
#endif
local_irq_save(flags);
@@ -749,22 +744,22 @@ static int ariadne_rx(struct net_device *dev)
skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len);
skb->protocol=eth_type_trans(skb,dev);
#if 0
+{
+ DECLARE_MAC_BUF(mac);
+
printk(KERN_DEBUG "RX pkt type 0x%04x from ",
((u_short *)skb->data)[6]);
{
- int i;
u_char *ptr = &((u_char *)skb->data)[6];
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
+ printk("%s", print_mac(mac, ptr));
}
printk(" to ");
{
- int i;
u_char *ptr = (u_char *)skb->data;
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
+ printk("%s", print_mac(mac, ptr));
}
printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+}
#endif
netif_rx(skb);
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 2143eeb7a2b0..ba6bd03a015f 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -414,7 +414,7 @@ static void am79c961_setmulticastlist (struct net_device *dev)
/*
* Update the multicast hash table
*/
- for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(multi_hash); i++)
write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
/*
@@ -741,12 +741,10 @@ static int __init am79c961_probe(struct platform_device *pdev)
ret = register_netdev(dev);
if (ret == 0) {
- printk(KERN_INFO "%s: ether address ", dev->name);
-
- /* Retrive and print the ethernet address. */
- for (i = 0; i < 6; i++)
- printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_INFO "%s: ether address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index ef2cc80256a3..25b114a4e2b1 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -485,6 +485,7 @@ static void update_mac_address(struct net_device *dev)
static int set_mac_address(struct net_device *dev, void* addr)
{
struct sockaddr *address = addr;
+ DECLARE_MAC_BUF(mac);
if (!is_valid_ether_addr(address->sa_data))
return -EADDRNOTAVAIL;
@@ -492,9 +493,8 @@ static int set_mac_address(struct net_device *dev, void* addr)
memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
update_mac_address(dev);
- printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk("%s: Setting MAC address to %s\n", dev->name,
+ print_mac(mac, dev->dev_addr));
return 0;
}
@@ -979,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
struct at91_private *lp;
unsigned int val;
int res;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct at91_private));
if (!dev)
@@ -986,7 +987,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
dev->base_addr = AT91_VA_BASE_EMAC;
dev->irq = AT91RM9200_ID_EMAC;
- SET_MODULE_OWNER(dev);
/* Install the interrupt handler */
if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
@@ -1082,12 +1082,11 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
}
/* Display ethernet banner */
- printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- dev->name, (uint) dev->base_addr, dev->irq,
- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n",
+ dev->name, (uint) dev->base_addr, dev->irq,
+ at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+ at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+ print_mac(mac, dev->dev_addr));
if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
else if (phy_type == MII_LXT971A_ID)
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index f6ece1d43f6e..7f016f3d5bf0 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -169,6 +169,9 @@ struct ep93xx_priv
spinlock_t tx_pending_lock;
unsigned int tx_pending;
+ struct net_device *dev;
+ struct napi_struct napi;
+
struct net_device_stats stats;
struct mii_if_info mii;
@@ -190,15 +193,11 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
return &(ep->stats);
}
-static int ep93xx_rx(struct net_device *dev, int *budget)
+static int ep93xx_rx(struct net_device *dev, int processed, int budget)
{
struct ep93xx_priv *ep = netdev_priv(dev);
- int rx_done;
- int processed;
- rx_done = 0;
- processed = 0;
- while (*budget > 0) {
+ while (processed < budget) {
int entry;
struct ep93xx_rstat *rstat;
u32 rstat0;
@@ -211,10 +210,8 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
rstat0 = rstat->rstat0;
rstat1 = rstat->rstat1;
- if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) {
- rx_done = 1;
+ if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP))
break;
- }
rstat->rstat0 = 0;
rstat->rstat1 = 0;
@@ -275,8 +272,6 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
err:
ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1);
processed++;
- dev->quota--;
- (*budget)--;
}
if (processed) {
@@ -284,7 +279,7 @@ err:
wrw(ep, REG_RXSTSENQ, processed);
}
- return !rx_done;
+ return processed;
}
static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
@@ -293,36 +288,32 @@ static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
}
-static int ep93xx_poll(struct net_device *dev, int *budget)
+static int ep93xx_poll(struct napi_struct *napi, int budget)
{
- struct ep93xx_priv *ep = netdev_priv(dev);
-
- /*
- * @@@ Have to stop polling if device is downed while we
- * are polling.
- */
+ struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi);
+ struct net_device *dev = ep->dev;
+ int rx = 0;
poll_some_more:
- if (ep93xx_rx(dev, budget))
- return 1;
-
- netif_rx_complete(dev);
-
- spin_lock_irq(&ep->rx_lock);
- wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
- if (ep93xx_have_more_rx(ep)) {
- wrl(ep, REG_INTEN, REG_INTEN_TX);
- wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+ rx = ep93xx_rx(dev, rx, budget);
+ if (rx < budget) {
+ int more = 0;
+
+ spin_lock_irq(&ep->rx_lock);
+ __netif_rx_complete(dev, napi);
+ wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
+ if (ep93xx_have_more_rx(ep)) {
+ wrl(ep, REG_INTEN, REG_INTEN_TX);
+ wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+ more = 1;
+ }
spin_unlock_irq(&ep->rx_lock);
- if (netif_rx_reschedule(dev, 0))
+ if (more && netif_rx_reschedule(dev, napi))
goto poll_some_more;
-
- return 0;
}
- spin_unlock_irq(&ep->rx_lock);
- return 0;
+ return rx;
}
static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -426,9 +417,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id)
if (status & REG_INTSTS_RX) {
spin_lock(&ep->rx_lock);
- if (likely(__netif_rx_schedule_prep(dev))) {
+ if (likely(__netif_rx_schedule_prep(dev, &ep->napi))) {
wrl(ep, REG_INTEN, REG_INTEN_TX);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &ep->napi);
}
spin_unlock(&ep->rx_lock);
}
@@ -648,7 +639,10 @@ static int ep93xx_open(struct net_device *dev)
dev->dev_addr[4], dev->dev_addr[5]);
}
+ napi_enable(&ep->napi);
+
if (ep93xx_start_hw(dev)) {
+ napi_disable(&ep->napi);
ep93xx_free_buffers(ep);
return -EIO;
}
@@ -662,6 +656,7 @@ static int ep93xx_open(struct net_device *dev)
err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev);
if (err) {
+ napi_disable(&ep->napi);
ep93xx_stop_hw(dev);
ep93xx_free_buffers(ep);
return err;
@@ -678,6 +673,7 @@ static int ep93xx_close(struct net_device *dev)
{
struct ep93xx_priv *ep = netdev_priv(dev);
+ napi_disable(&ep->napi);
netif_stop_queue(dev);
wrl(ep, REG_GIINTMSK, 0);
@@ -788,14 +784,12 @@ struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
dev->get_stats = ep93xx_get_stats;
dev->ethtool_ops = &ep93xx_ethtool_ops;
- dev->poll = ep93xx_poll;
dev->hard_start_xmit = ep93xx_xmit;
dev->open = ep93xx_open;
dev->stop = ep93xx_close;
dev->do_ioctl = ep93xx_ioctl;
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->weight = 64;
return dev;
}
@@ -847,6 +841,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
goto err_out;
}
ep = netdev_priv(dev);
+ ep->dev = dev;
+ netif_napi_add(dev, &ep->napi, ep93xx_poll, 64);
platform_set_drvdata(pdev, dev);
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index f21148e7b579..3bb9e293e2ef 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -36,7 +36,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
@@ -75,7 +74,7 @@ static void ether1_timeout(struct net_device *dev);
/* ------------------------------------------------------------------------- */
-static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
#define BUS_16 16
#define BUS_8 8
@@ -997,6 +996,7 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct net_device *dev;
int i, ret = 0;
+ DECLARE_MAC_BUF(mac);
ether1_banner();
@@ -1010,7 +1010,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
dev->irq = ec->irq;
@@ -1045,12 +1044,9 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto free;
- printk(KERN_INFO "%s: ether1 in slot %d, ",
- dev->name, ec->slot_no);
+ printk(KERN_INFO "%s: ether1 in slot %d, %s\n",
+ dev->name, ec->slot_no, print_mac(mac, dev->dev_addr));
- for (i = 0; i < 6; i++)
- printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
ecard_set_drvdata(ec, dev);
return 0;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index da713500654d..67e96ae85035 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -51,7 +51,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
@@ -69,7 +68,7 @@
#include <asm/ecard.h>
#include <asm/io.h>
-static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __devinitdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
#include "ether3.h"
@@ -464,7 +463,7 @@ static void ether3_setmulticastlist(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
/* promiscuous mode */
priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
- } else if (dev->flags & IFF_ALLMULTI) {
+ } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
} else
priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
@@ -776,7 +775,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
{
const struct ether3_data *data = id->data;
struct net_device *dev;
- int i, bus_type, ret;
+ int bus_type, ret;
+ DECLARE_MAC_BUF(mac);
ether3_banner();
@@ -790,7 +790,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
priv(dev)->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
@@ -860,9 +859,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto free;
- printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk("%s: %s in slot %d, %s\n",
+ dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
ecard_set_drvdata(ec, dev);
return 0;
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 769ba69451f4..00081d2b9cd5 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -31,7 +31,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
@@ -649,6 +648,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
struct net_device *dev;
struct etherh_priv *eh;
int i, ret;
+ DECLARE_MAC_BUF(mac);
etherh_banner();
@@ -662,7 +662,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
dev->open = etherh_open;
@@ -747,11 +746,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto free;
- printk(KERN_INFO "%s: %s in slot %d, ",
- dev->name, data->name, ec->slot_no);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: %s in slot %d, %s\n",
+ dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
ecard_set_drvdata(ec, dev);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index bed8e0ebaf19..b032c1bf492f 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -109,7 +109,6 @@ typedef unsigned char uchar;
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
spinlock_t lock;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
@@ -164,7 +163,6 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t net_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void net_tx_timeout (struct net_device *dev);
@@ -225,8 +223,6 @@ struct net_device * __init at1700_probe(int unit)
dev->irq = irq;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = at1700_probe1(dev, io);
} else if (io != 0) { /* Don't probe at all. */
@@ -269,6 +265,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
int slot, ret = -ENODEV;
struct net_local *lp = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -392,16 +389,15 @@ found:
if (is_at1700) {
for(i = 0; i < 3; i++) {
unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
- printk("%04x", eeprom_val);
((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val);
}
} else {
for(i = 0; i < 6; i++) {
unsigned char val = inb(ioaddr + SAPROM + i);
- printk("%02x", val);
dev->dev_addr[i] = val;
}
}
+ printk("%s", print_mac(mac, dev->dev_addr));
/* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
rather than 150 ohm shielded twisted pair compensation.
@@ -458,7 +454,6 @@ found:
dev->open = net_open;
dev->stop = net_close;
dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->tx_timeout = net_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -573,7 +568,7 @@ static void net_tx_timeout (struct net_device *dev)
dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
outw(0xffff, ioaddr + MODE24);
outw (0xffff, ioaddr + TX_STATUS);
@@ -693,10 +688,10 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
printk("%s: 16 Collision occur during Txing.\n", dev->name);
/* Cancel sending a packet. */
outb(0x03, ioaddr + COL16CNTL);
- lp->stats.collisions++;
+ dev->stats.collisions++;
}
if (status & 0x82) {
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* The Tx queue has any packets and is not being
transferred a packet from the host, start
transmitting. */
@@ -721,7 +716,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
static void
net_rx(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int boguscount = 5;
@@ -740,11 +734,11 @@ net_rx(struct net_device *dev)
#endif
if ((status & 0xF0) != 0x20) { /* There was an error. */
- lp->stats.rx_errors++;
- if (status & 0x08) lp->stats.rx_length_errors++;
- if (status & 0x04) lp->stats.rx_frame_errors++;
- if (status & 0x02) lp->stats.rx_crc_errors++;
- if (status & 0x01) lp->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
+ if (status & 0x08) dev->stats.rx_length_errors++;
+ if (status & 0x04) dev->stats.rx_frame_errors++;
+ if (status & 0x02) dev->stats.rx_crc_errors++;
+ if (status & 0x01) dev->stats.rx_over_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
@@ -755,7 +749,7 @@ net_rx(struct net_device *dev)
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
outb(0x05, ioaddr + RX_CTRL);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
break;
}
skb = dev_alloc_skb(pkt_len+3);
@@ -765,7 +759,7 @@ net_rx(struct net_device *dev)
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
outb(0x05, ioaddr + RX_CTRL);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb,2);
@@ -774,8 +768,8 @@ net_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
if (--boguscount <= 0)
break;
@@ -824,17 +818,6 @@ static int net_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics.
- This may be called with the card open or closed.
- There are no on-chip counters, so this function is trivial.
-*/
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
/*
Set the multicast/promiscuous mode for this adaptor.
*/
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index dfa8b9ba4c80..ebf1a3a88e15 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -224,7 +224,6 @@ struct lance_private {
int dirty_tx; /* Ring entries to be freed. */
/* copy function */
void *(*memcpy_f)( void *, const void *, size_t );
- struct net_device_stats stats;
/* This must be long for set_bit() */
long tx_full;
spinlock_t devlock;
@@ -263,7 +262,7 @@ struct lance_addr {
(highest byte stripped) */
};
-#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+#define N_LANCE_ADDR ARRAY_SIZE(lance_addr_list)
/* Definitions for the Lance */
@@ -347,7 +346,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
static irqreturn_t lance_interrupt( int irq, void *dev_id );
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
static void set_multicast_list( struct net_device *dev );
static int lance_set_mac_address( struct net_device *dev, void *addr );
static void lance_tx_timeout (struct net_device *dev);
@@ -390,7 +388,6 @@ struct net_device * __init atarilance_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
for( i = 0; i < N_LANCE_ADDR; ++i ) {
if (lance_probe1( dev, &lance_addr_list[i] )) {
@@ -470,6 +467,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
int i;
static int did_version;
unsigned short save1, save2;
+ DECLARE_MAC_BUF(mac);
PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
(long)memaddr, (long)ioaddr ));
@@ -598,8 +596,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
i = IO->mem;
break;
}
- for( i = 0; i < 6; ++i )
- printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+ printk("%s\n", print_mac(mac, dev->dev_addr));
if (lp->cardtype == OLD_RIEBL) {
printk( "%s: Warning: This is a default ethernet address!\n",
dev->name );
@@ -632,7 +629,6 @@ static unsigned long __init lance_probe1( struct net_device *dev,
dev->open = &lance_open;
dev->hard_start_xmit = &lance_start_xmit;
dev->stop = &lance_close;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->set_mac_address = &lance_set_mac_address;
@@ -640,13 +636,6 @@ static unsigned long __init lance_probe1( struct net_device *dev,
dev->tx_timeout = lance_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-
-#if 0
- dev->start = 0;
-#endif
-
- memset( &lp->stats, 0, sizeof(lp->stats) );
-
return( 1 );
}
@@ -754,7 +743,7 @@ static void lance_tx_timeout (struct net_device *dev)
* little endian mode.
*/
REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
#ifndef final_version
{ int i;
DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
@@ -790,6 +779,8 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
int entry, len;
struct lance_tx_head *head;
unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
dev->name, DREG ));
@@ -812,17 +803,13 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* Fill in a Tx ring entry */
if (lance_debug >= 3) {
- u_char *p;
- int i;
- printk( "%s: TX pkt type 0x%04x from ", dev->name,
- ((u_short *)skb->data)[6]);
- for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" data at 0x%08x len %d\n", (int)skb->data,
- (int)skb->len );
+ printk( "%s: TX pkt type 0x%04x from "
+ "%s to %s"
+ " data at 0x%08x len %d\n",
+ dev->name, ((u_short *)skb->data)[6],
+ print_mac(mac, &skb->data[6]),
+ print_mac(mac2, skb->data),
+ (int)skb->data, (int)skb->len );
}
/* We're not prepared for the int until the last flags are set/reset. And
@@ -842,7 +829,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
head->misc = 0;
lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dev_kfree_skb( skb );
lp->cur_tx++;
while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
@@ -913,13 +900,13 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id )
if (status & TMD1_ERR) {
/* There was an major error, log it. */
int err_status = MEM->tx_head[entry].misc;
- lp->stats.tx_errors++;
- if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
+ if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
+ if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++;
if (err_status & TMD3_UFLO) {
/* Ackk! On FIFO errors the Tx unit is turned off! */
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
/* Remove this verbosity later! */
DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
dev->name, csr0 ));
@@ -928,8 +915,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id )
}
} else {
if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
- lp->stats.collisions++;
- lp->stats.tx_packets++;
+ dev->stats.collisions++;
+ dev->stats.tx_packets++;
}
/* XXX MSch: free skb?? */
@@ -956,8 +943,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id )
}
/* Log misc errors. */
- if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
- if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & CSR0_MERR) {
DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
"status %04x.\n", dev->name, csr0 ));
@@ -998,11 +985,11 @@ static int lance_rx( struct net_device *dev )
buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & RMD1_ENP) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet.*/
- if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
- if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
- if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
- if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++; /* end of a packet.*/
+ if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
+ if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
+ if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
+ if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
head->flag &= (RMD1_ENP|RMD1_STP);
} else {
/* Malloc up new buffer, compatible with net-3. */
@@ -1011,7 +998,7 @@ static int lance_rx( struct net_device *dev )
if (pkt_len < 60) {
printk( "%s: Runt packet!\n", dev->name );
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
else {
skb = dev_alloc_skb( pkt_len+2 );
@@ -1024,7 +1011,7 @@ static int lance_rx( struct net_device *dev )
break;
if (i > RX_RING_SIZE - 2) {
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
head->flag |= RMD1_OWN_CHIP;
lp->cur_rx++;
}
@@ -1032,19 +1019,18 @@ static int lance_rx( struct net_device *dev )
}
if (lance_debug >= 3) {
- u_char *data = PKTBUF_ADDR(head), *p;
- printk( "%s: RX pkt type 0x%04x from ", dev->name,
- ((u_short *)data)[6]);
- for( p = &data[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+ u_char *data = PKTBUF_ADDR(head);
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ",
+ "data %02x %02x %02x %02x %02x %02x %02x %02x "
"len %d\n",
+ dev->name, ((u_short *)data)[6],
+ print_mac(mac, &data[6]), print_mac(mac2, data),
data[15], data[16], data[17], data[18],
data[19], data[20], data[21], data[22],
- pkt_len );
+ pkt_len);
}
skb_reserve( skb, 2 ); /* 16 byte align */
@@ -1053,8 +1039,8 @@ static int lance_rx( struct net_device *dev )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
}
@@ -1091,14 +1077,6 @@ static int lance_close( struct net_device *dev )
}
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-
-{ struct lance_private *lp = (struct lance_private *)dev->priv;
-
- return &lp->stats;
-}
-
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
index 1f616c5c1473..68a83be843ab 100644
--- a/drivers/net/atl1/atl1_ethtool.c
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -88,9 +88,14 @@ static void atl1_get_ethtool_stats(struct net_device *netdev,
}
-static int atl1_get_stats_count(struct net_device *netdev)
+static int atl1_get_sset_count(struct net_device *netdev, int sset)
{
- return ARRAY_SIZE(atl1_gstrings_stats);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(atl1_gstrings_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int atl1_get_settings(struct net_device *netdev,
@@ -489,15 +494,12 @@ const struct ethtool_ops atl1_ethtool_ops = {
.get_pauseparam = atl1_get_pauseparam,
.set_pauseparam = atl1_set_pauseparam,
.get_rx_csum = atl1_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_link = ethtool_op_get_link,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_strings = atl1_get_strings,
.nway_reset = atl1_nway_reset,
.get_ethtool_stats = atl1_get_ethtool_stats,
- .get_stats_count = atl1_get_stats_count,
- .get_tso = ethtool_op_get_tso,
+ .get_sset_count = atl1_get_sset_count,
.set_tso = ethtool_op_set_tso,
};
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
index ef886bdeac13..9d3bd22e3a82 100644
--- a/drivers/net/atl1/atl1_hw.c
+++ b/drivers/net/atl1/atl1_hw.c
@@ -603,7 +603,7 @@ static struct atl1_spi_flash_dev flash_table[] = {
static void atl1_init_flash_opcode(struct atl1_hw *hw)
{
- if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+ if (hw->flash_vendor >= ARRAY_SIZE(flash_table))
hw->flash_vendor = 0; /* ATMEL */
/* Init OP table */
diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h
index 100c09c66e64..939aa0f53f6e 100644
--- a/drivers/net/atl1/atl1_hw.h
+++ b/drivers/net/atl1/atl1_hw.h
@@ -680,11 +680,6 @@ void atl1_check_options(struct atl1_adapter *adapter);
#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */
#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */
-/* The size (in bytes) of a ethernet packet */
-#define ENET_HEADER_SIZE 14
-#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */
-#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */
-#define ETHERNET_FCS_SIZE 4
#define MAX_JUMBO_FRAME_SIZE 0x2800
#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
@@ -929,8 +924,8 @@ enum atl1_dma_req_block {
atl1_dma_req_128 = 0,
atl1_dma_req_256 = 1,
atl1_dma_req_512 = 2,
- atl1_dam_req_1024 = 3,
- atl1_dam_req_2048 = 4,
+ atl1_dma_req_1024 = 3,
+ atl1_dma_req_2048 = 4,
atl1_dma_req_4096 = 5
};
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index fd1e156f1747..35b0a7dd4ef4 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -59,6 +59,7 @@
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
+#include <linux/if_ether.h>
#include <linux/irqreturn.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
@@ -75,7 +76,6 @@
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/mii.h>
-#include <linux/interrupt.h>
#include <net/checksum.h>
#include <asm/atomic.h>
@@ -120,8 +120,8 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
struct atl1_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
- hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
- hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+ hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ hw->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
adapter->wol = 0;
adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7;
@@ -314,7 +314,7 @@ err_nomem:
return -ENOMEM;
}
-void atl1_init_ring_ptrs(struct atl1_adapter *adapter)
+static void atl1_init_ring_ptrs(struct atl1_adapter *adapter)
{
struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
@@ -688,9 +688,9 @@ static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
{
struct atl1_adapter *adapter = netdev_priv(netdev);
int old_mtu = netdev->mtu;
- int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
- if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
(max_frame > MAX_JUMBO_FRAME_SIZE)) {
dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
return -EINVAL;
@@ -908,8 +908,8 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
/* config DMA Engine */
value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
<< DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
- ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
- << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | DMA_CTRL_DMAR_EN |
+ ((((u32) hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK)
+ << DMA_CTRL_DMAW_BURST_LEN_SHIFT) | DMA_CTRL_DMAR_EN |
DMA_CTRL_DMAW_EN;
value |= (u32) hw->dma_ord;
if (atl1_rcb_128 == hw->rcb_value)
@@ -917,7 +917,10 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
iowrite32(value, hw->hw_addr + REG_DMA_CTRL);
/* config CMB / SMB */
- value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16);
+ value = (hw->cmb_tpd > adapter->tpd_ring.count) ?
+ hw->cmb_tpd : adapter->tpd_ring.count;
+ value <<= 16;
+ value |= hw->cmb_rrd;
iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH);
value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16);
iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER);
@@ -1334,7 +1337,7 @@ rrd_ok:
skb = buffer_info->skb;
length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
- skb_put(skb, length - ETHERNET_FCS_SIZE);
+ skb_put(skb, length - ETH_FCS_LEN);
/* Receive Checksum Offload */
atl1_rx_checksum(adapter, rrd, skb);
@@ -1364,7 +1367,6 @@ rrd_ok:
if (count) {
u32 tpd_next_to_use;
u32 rfd_next_to_use;
- u32 rrd_next_to_clean;
spin_lock(&adapter->mb_lock);
@@ -1422,7 +1424,7 @@ static void atl1_intr_tx(struct atl1_adapter *adapter)
netif_wake_queue(adapter->netdev);
}
-static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
+static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
{
u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
@@ -1453,7 +1455,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
iph->daddr, 0, IPPROTO_TCP, 0);
ipofst = skb_network_offset(skb);
- if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
+ if (ipofst != ETH_HLEN) /* 802.3 frame */
tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
tso->tsopl |= (iph->ihl &
@@ -1509,7 +1511,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
unsigned int f;
u16 tpd_next_to_use;
u16 proto_hdr_len;
- u16 i, m, len12;
+ u16 len12;
first_buf_len -= skb->data_len;
nr_frags = skb_shinfo(skb)->nr_frags;
@@ -1533,6 +1535,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
tpd_next_to_use = 0;
if (first_buf_len > proto_hdr_len) {
+ int i, m;
+
len12 = first_buf_len - proto_hdr_len;
m = (len12 + ATL1_MAX_TX_BUF_LEN - 1) /
ATL1_MAX_TX_BUF_LEN;
@@ -1700,15 +1704,13 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
}
- local_irq_save(flags);
- if (!spin_trylock(&adapter->lock)) {
+ if (!spin_trylock_irqsave(&adapter->lock, flags)) {
/* Can't get lock - tell upper layer to requeue */
- local_irq_restore(flags);
dev_printk(KERN_DEBUG, &adapter->pdev->dev, "tx locked\n");
return NETDEV_TX_LOCKED;
}
- if (tpd_avail(&adapter->tpd_ring) < count) {
+ if (atl1_tpd_avail(&adapter->tpd_ring) < count) {
/* not enough descriptors */
netif_stop_queue(netdev);
spin_unlock_irqrestore(&adapter->lock, flags);
@@ -2201,21 +2203,26 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct atl1_adapter *adapter;
static int cards_found = 0;
- bool pci_using_64 = true;
int err;
err = pci_enable_device(pdev);
if (err)
return err;
- err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ /*
+ * The atl1 chip can DMA to 64-bit addresses, but it uses a single
+ * shared register for the high 32 bits, so only a single, aligned,
+ * 4 GB physical address range can be used at a time.
+ *
+ * Supporting 64-bit DMA on this hardware is more trouble than it's
+ * worth. It is far easier to limit to 32-bit DMA than update
+ * various kernel subsystems to support the mechanics required by a
+ * fixed-high-32-bit system.
+ */
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (err) {
- dev_err(&pdev->dev, "no usable DMA configuration\n");
- goto err_dma;
- }
- pci_using_64 = false;
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
+ goto err_dma;
}
/* Mark all PCI regions associated with PCI device
* pdev as being reserved by owner atl1_driver_name
@@ -2234,7 +2241,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
err = -ENOMEM;
goto err_alloc_etherdev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
@@ -2280,7 +2286,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
netdev->ethtool_ops = &atl1_ethtool_ops;
adapter->bd_number = cards_found;
- adapter->pci_using_64 = pci_using_64;
/* setup the private structure */
err = atl1_sw_init(adapter);
@@ -2297,9 +2302,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
*/
/* netdev->features |= NETIF_F_TSO; */
- if (pci_using_64)
- netdev->features |= NETIF_F_HIGHDMA;
-
netdev->features |= NETIF_F_LLTX;
/*
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 82d78ff8399b..62f09e59d9c4 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -171,7 +171,6 @@ static char mux_8012[] = { 0xff, 0xf7, 0xff, 0xfb, 0xf3, 0xfb, 0xff, 0xf7,};
struct net_local {
spinlock_t lock;
struct net_device *next_module;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
int saved_tx_size;
@@ -205,7 +204,6 @@ static irqreturn_t atp_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode);
static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_rx_mode_8002(struct net_device *dev);
static void set_rx_mode_8012(struct net_device *dev);
static void tx_timeout(struct net_device *dev);
@@ -250,6 +248,7 @@ static int __init atp_probe1(long ioaddr)
struct net_local *lp;
int saved_ctrl_reg, status, i;
int res;
+ DECLARE_MAC_BUF(mac);
outb(0xff, ioaddr + PAR_DATA);
/* Save the original value of the Control register, in case we guessed
@@ -299,7 +298,6 @@ static int __init atp_probe1(long ioaddr)
dev = alloc_etherdev(sizeof(struct net_local));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
/* Find the IRQ used by triggering an interrupt. */
write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */
@@ -325,10 +323,9 @@ static int __init atp_probe1(long ioaddr)
printk(KERN_INFO "%s", version);
#endif
- printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
- "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
- dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, "
+ "SAPROM %s.\n",
+ dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
/* Reset the ethernet hardware and activate the printer pass-through. */
write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
@@ -349,7 +346,6 @@ static int __init atp_probe1(long ioaddr)
dev->open = net_open;
dev->stop = net_close;
dev->hard_start_xmit = atp_send_packet;
- dev->get_stats = net_get_stats;
dev->set_multicast_list =
lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012;
dev->tx_timeout = tx_timeout;
@@ -539,18 +535,17 @@ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad
static void tx_timeout(struct net_device *dev)
{
- struct net_local *np = netdev_priv(dev);
long ioaddr = dev->base_addr;
printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name,
inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
: "IRQ conflict");
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adapter. */
hardware_init(dev);
dev->trans_start = jiffies;
netif_wake_queue(dev);
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
@@ -630,7 +625,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
/* We acknowledged the normal Rx interrupt, so if the interrupt
is still outstanding we must have a Rx error. */
if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
/* Set to no-accept mode long enough to remove a packet. */
write_reg_high(ioaddr, CMR2, CMR2h_OFF);
net_rx(dev);
@@ -650,9 +645,9 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
and reinitialize the adapter. */
write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK);
if (status & (ISR_TxErr<<3)) {
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (++lp->re_tx > 15) {
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
hardware_init(dev);
break;
}
@@ -661,7 +656,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
} else {
/* Finish up the transmit. */
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
lp->pac_cnt_in_tx_buf--;
if ( lp->saved_tx_size) {
trigger_send(ioaddr, lp->saved_tx_size);
@@ -679,7 +674,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
"%ld jiffies status %02x CMR1 %02x.\n", dev->name,
num_tx_since_rx, jiffies - dev->last_rx, status,
(read_nibble(ioaddr, CMR1) >> 3) & 15);
- lp->stats.rx_missed_errors++;
+ dev->stats.rx_missed_errors++;
hardware_init(dev);
num_tx_since_rx = 0;
break;
@@ -736,13 +731,13 @@ static void atp_timed_checker(unsigned long data)
struct net_local *lp = netdev_priv(atp_timed_dev);
write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
if (i == 2)
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
else if (i == 3)
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
else if (i == 4)
- lp->stats.collisions++;
+ dev->stats.collisions++;
else
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
#endif
}
@@ -766,14 +761,14 @@ static void net_rx(struct net_device *dev)
printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad,
rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr);
if ((rx_head.rx_status & 0x77) != 0x01) {
- lp->stats.rx_errors++;
- if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++;
- else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++;
+ dev->stats.rx_errors++;
+ if (rx_head.rx_status & 0x0004) dev->stats.rx_frame_errors++;
+ else if (rx_head.rx_status & 0x0002) dev->stats.rx_crc_errors++;
if (net_debug > 3)
printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n",
dev->name, rx_head.rx_status);
if (rx_head.rx_status & 0x0020) {
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE);
write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
} else if (rx_head.rx_status & 0x0050)
@@ -788,7 +783,7 @@ static void net_rx(struct net_device *dev)
if (skb == NULL) {
printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto done;
}
@@ -797,8 +792,8 @@ static void net_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
done:
write_reg(ioaddr, CMR1, CMR1_NextPkt);
@@ -850,15 +845,6 @@ net_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adapter.
*/
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index e86b3691765b..b46c5d8a77bd 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -90,7 +90,6 @@ static int au1000_rx(struct net_device *);
static irqreturn_t au1000_interrupt(int, void *);
static void au1000_tx_timeout(struct net_device *);
static void set_rx_mode(struct net_device *);
-static struct net_device_stats *au1000_get_stats(struct net_device *);
static int au1000_ioctl(struct net_device *, struct ifreq *, int);
static int mdio_read(struct net_device *, int, int);
static void mdio_write(struct net_device *, int, int, u16);
@@ -772,7 +771,6 @@ static struct net_device * au1000_probe(int port_num)
dev->open = au1000_open;
dev->hard_start_xmit = au1000_tx;
dev->stop = au1000_close;
- dev->get_stats = au1000_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &au1000_ioctl;
SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
@@ -1038,7 +1036,7 @@ static void __exit au1000_cleanup_module(void)
static void update_tx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
+ struct net_device_stats *ps = &dev->stats;
if (status & TX_FRAME_ABORTED) {
if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
@@ -1094,7 +1092,7 @@ static void au1000_tx_ack(struct net_device *dev)
static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
+ struct net_device_stats *ps = &dev->stats;
volatile tx_dma_t *ptxd;
u32 buff_stat;
db_dest_t *pDB;
@@ -1148,7 +1146,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
static inline void update_rx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
+ struct net_device_stats *ps = &dev->stats;
ps->rx_packets++;
if (status & RX_MCAST_FRAME)
@@ -1201,7 +1199,7 @@ static int au1000_rx(struct net_device *dev)
printk(KERN_ERR
"%s: Memory squeeze, dropping packet.\n",
dev->name);
- aup->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
continue;
}
skb_reserve(skb, 2); /* 16 byte IP header align */
@@ -1324,18 +1322,5 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
}
-static struct net_device_stats *au1000_get_stats(struct net_device *dev)
-{
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
-
- if (au1000_debug > 4)
- printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev);
-
- if (netif_device_present(dev)) {
- return &aup->stats;
- }
- return 0;
-}
-
module_init(au1000_init_module);
module_exit(au1000_cleanup_module);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 52fe00dd6d24..f3baeaa12854 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -115,6 +115,5 @@ struct au1000_private {
u32 vaddr; /* virtual address of rx/tx buffers */
dma_addr_t dma_addr; /* dma address of rx/tx buffers */
- struct net_device_stats stats;
spinlock_t lock; /* Serialise access to device */
};
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 1d882360b34d..9fe0517cf893 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -24,6 +24,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/eeprom_93cx6.h>
#include <net/ax88796.h>
@@ -580,9 +581,39 @@ static const struct ethtool_ops ax_ethtool_ops = {
.set_settings = ax_set_settings,
.nway_reset = ax_nway_reset,
.get_link = ax_get_link,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
+#ifdef CONFIG_AX88796_93CX6
+static void ax_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+ struct ei_device *ei_local = eeprom->data;
+ u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+ eeprom->reg_data_in = reg & AX_MEMR_EEI;
+ eeprom->reg_data_out = reg & AX_MEMR_EEO; /* Input pin */
+ eeprom->reg_data_clock = reg & AX_MEMR_EECLK;
+ eeprom->reg_chip_select = reg & AX_MEMR_EECS;
+}
+
+static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+ struct ei_device *ei_local = eeprom->data;
+ u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+ reg &= ~(AX_MEMR_EEI | AX_MEMR_EECLK | AX_MEMR_EECS);
+
+ if (eeprom->reg_data_in)
+ reg |= AX_MEMR_EEI;
+ if (eeprom->reg_data_clock)
+ reg |= AX_MEMR_EECLK;
+ if (eeprom->reg_chip_select)
+ reg |= AX_MEMR_EECS;
+
+ ei_outb(reg, ei_local->mem + AX_MEMR);
+ udelay(10);
+}
+#endif
+
/* setup code */
static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local)
@@ -641,6 +672,23 @@ static int ax_init_dev(struct net_device *dev, int first_init)
memcpy(dev->dev_addr, SA_prom, 6);
}
+#ifdef CONFIG_AX88796_93CX6
+ if (first_init && ax->plat->flags & AXFLG_HAS_93CX6) {
+ unsigned char mac_addr[6];
+ struct eeprom_93cx6 eeprom;
+
+ eeprom.data = ei_local;
+ eeprom.register_read = ax_eeprom_register_read;
+ eeprom.register_write = ax_eeprom_register_write;
+ eeprom.width = PCI_EEPROM_WIDTH_93C56;
+
+ eeprom_93cx6_multiread(&eeprom, 0,
+ (__le16 __force *)mac_addr,
+ sizeof(mac_addr) >> 1);
+
+ memcpy(dev->dev_addr, mac_addr, 6);
+ }
+#endif
if (ax->plat->wordlength == 2) {
/* We must set the 8390 for word mode. */
ei_outb(ax->plat->dcr_val, ei_local->mem + EN0_DCFG);
@@ -819,11 +867,12 @@ static int ax_probe(struct platform_device *pdev)
}
ei_status.mem = ioremap(res->start, size);
- dev->base_addr = (long)ei_status.mem;
+ dev->base_addr = (unsigned long)ei_status.mem;
if (ei_status.mem == NULL) {
- dev_err(&pdev->dev, "Cannot ioremap area (%08zx,%08zx)\n",
- res->start, res->end);
+ dev_err(&pdev->dev, "Cannot ioremap area (%08llx,%08llx)\n",
+ (unsigned long long)res->start,
+ (unsigned long long)res->end);
ret = -ENXIO;
goto exit_req;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 96fb0ec905a7..3d247f3f4a3c 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1,8 +1,11 @@
-/* b44.c: Broadcom 4400 device driver.
+/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver.
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
* Copyright (C) 2006 Broadcom Corporation.
+ * Copyright (C) 2007 Michael Buesch <mb@bu3sch.de>
*
* Distribute under GPL.
*/
@@ -21,17 +24,18 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
+#include <linux/ssb/ssb.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
+
#include "b44.h"
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.01"
-#define DRV_MODULE_RELDATE "Jun 16, 2006"
+#define DRV_MODULE_VERSION "2.0"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -85,10 +89,10 @@
#define B44_ETHIPV4UDP_HLEN 42
static char version[] __devinitdata =
- DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n";
-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
+MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
+MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
@@ -96,18 +100,28 @@ static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */
module_param(b44_debug, int, 0);
MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
-static struct pci_device_id b44_pci_tbl[] = {
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { } /* terminate list with empty entry */
-};
+#ifdef CONFIG_B44_PCI
+static const struct pci_device_id b44_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
+ { 0 } /* terminate list with empty entry */
+};
MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
+static struct pci_driver b44_pci_driver = {
+ .name = DRV_MODULE_NAME,
+ .id_table = b44_pci_tbl,
+};
+#endif /* CONFIG_B44_PCI */
+
+static const struct ssb_device_id b44_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl);
+
static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *);
@@ -119,6 +133,7 @@ static void b44_init_hw(struct b44 *, int);
static int dma_desc_align_mask;
static int dma_desc_sync_size;
+static int instance;
static const char b44_gstrings[][ETH_GSTRING_LEN] = {
#define _B44(x...) # x,
@@ -126,35 +141,35 @@ B44_STAT_REG_DECLARE
#undef _B44
};
-static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
- dma_addr_t dma_base,
- unsigned long offset,
- enum dma_data_direction dir)
+static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
{
- dma_sync_single_range_for_device(&pdev->dev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_range_for_device(sdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
}
-static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
- dma_addr_t dma_base,
- unsigned long offset,
- enum dma_data_direction dir)
+static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
{
- dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_range_for_cpu(sdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
}
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
{
- return readl(bp->regs + reg);
+ return ssb_read32(bp->sdev, reg);
}
static inline void bw32(const struct b44 *bp,
unsigned long reg, unsigned long val)
{
- writel(val, bp->regs + reg);
+ ssb_write32(bp->sdev, reg, val);
}
static int b44_wait_bit(struct b44 *bp, unsigned long reg,
@@ -182,117 +197,29 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg,
return 0;
}
-/* Sonics SiliconBackplane support routines. ROFL, you should see all the
- * buzz words used on this company's website :-)
- *
- * All of these routines must be invoked with bp->lock held and
- * interrupts disabled.
- */
-
-#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
-#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */
-
-static u32 ssb_get_core_rev(struct b44 *bp)
-{
- return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
-}
-
-static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
-{
- u32 bar_orig, pci_rev, val;
-
- pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
- pci_rev = ssb_get_core_rev(bp);
-
- val = br32(bp, B44_SBINTVEC);
- val |= cores;
- bw32(bp, B44_SBINTVEC, val);
-
- val = br32(bp, SSB_PCI_TRANS_2);
- val |= SSB_PCI_PREF | SSB_PCI_BURST;
- bw32(bp, SSB_PCI_TRANS_2, val);
-
- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
-
- return pci_rev;
-}
-
-static void ssb_core_disable(struct b44 *bp)
-{
- if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
- return;
-
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
- b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
- b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
- SBTMSLOW_REJECT | SBTMSLOW_RESET));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-}
-
-static void ssb_core_reset(struct b44 *bp)
+static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
{
u32 val;
- ssb_core_disable(bp);
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-
- /* Clear SERR if set, this is a hw bug workaround. */
- if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
- bw32(bp, B44_SBTMSHIGH, 0);
-
- val = br32(bp, B44_SBIMSTATE);
- if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
- bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
-
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-}
+ bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
+ (index << CAM_CTRL_INDEX_SHIFT)));
-static int ssb_core_unit(struct b44 *bp)
-{
-#if 0
- u32 val = br32(bp, B44_SBADMATCH0);
- u32 base;
+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
- type = val & SBADMATCH0_TYPE_MASK;
- switch (type) {
- case 0:
- base = val & SBADMATCH0_BS0_MASK;
- break;
+ val = br32(bp, B44_CAM_DATA_LO);
- case 1:
- base = val & SBADMATCH0_BS1_MASK;
- break;
+ data[2] = (val >> 24) & 0xFF;
+ data[3] = (val >> 16) & 0xFF;
+ data[4] = (val >> 8) & 0xFF;
+ data[5] = (val >> 0) & 0xFF;
- case 2:
- default:
- base = val & SBADMATCH0_BS2_MASK;
- break;
- };
-#endif
- return 0;
-}
+ val = br32(bp, B44_CAM_DATA_HI);
-static int ssb_is_core_up(struct b44 *bp)
-{
- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
- == SBTMSLOW_CLOCK);
+ data[0] = (val >> 8) & 0xFF;
+ data[1] = (val >> 0) & 0xFF;
}
-static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
+static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
{
u32 val;
@@ -328,14 +255,14 @@ static void b44_enable_ints(struct b44 *bp)
bw32(bp, B44_IMASK, bp->imask);
}
-static int b44_readphy(struct b44 *bp, int reg, u32 *val)
+static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
{
int err;
bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
(MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (phy_addr << MDIO_DATA_PMD_SHIFT) |
(reg << MDIO_DATA_RA_SHIFT) |
(MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
@@ -344,29 +271,40 @@ static int b44_readphy(struct b44 *bp, int reg, u32 *val)
return err;
}
-static int b44_writephy(struct b44 *bp, int reg, u32 val)
+static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
{
bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
(MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (phy_addr << MDIO_DATA_PMD_SHIFT) |
(reg << MDIO_DATA_RA_SHIFT) |
(MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
(val & MDIO_DATA_DATA)));
return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
}
+static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
+{
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
+
+ return __b44_readphy(bp, bp->phy_addr, reg, val);
+}
+
+static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
+{
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
+
+ return __b44_writephy(bp, bp->phy_addr, reg, val);
+}
+
/* miilib interface */
-/* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
- * due to code existing before miilib use was added to this driver.
- * Someone should remove this artificial driver limitation in
- * b44_{read,write}phy. bp->phy_addr itself is fine (and needed).
- */
static int b44_mii_read(struct net_device *dev, int phy_id, int location)
{
u32 val;
struct b44 *bp = netdev_priv(dev);
- int rc = b44_readphy(bp, location, &val);
+ int rc = __b44_readphy(bp, phy_id, location, &val);
if (rc)
return 0xffffffff;
return val;
@@ -376,7 +314,7 @@ static void b44_mii_write(struct net_device *dev, int phy_id, int location,
int val)
{
struct b44 *bp = netdev_priv(dev);
- b44_writephy(bp, location, val);
+ __b44_writephy(bp, phy_id, location, val);
}
static int b44_phy_reset(struct b44 *bp)
@@ -384,6 +322,8 @@ static int b44_phy_reset(struct b44 *bp)
u32 val;
int err;
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
if (err)
return err;
@@ -442,11 +382,52 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
__b44_set_flow_ctrl(bp, pause_enab);
}
+#ifdef SSB_DRIVER_MIPS
+extern char *nvram_get(char *name);
+static void b44_wap54g10_workaround(struct b44 *bp)
+{
+ const char *str;
+ u32 val;
+ int err;
+
+ /*
+ * workaround for bad hardware design in Linksys WAP54G v1.0
+ * see https://dev.openwrt.org/ticket/146
+ * check and reset bit "isolate"
+ */
+ str = nvram_get("boardnum");
+ if (!str)
+ return;
+ if (simple_strtoul(str, NULL, 0) == 2) {
+ err = __b44_readphy(bp, 0, MII_BMCR, &val);
+ if (err)
+ goto error;
+ if (!(val & BMCR_ISOLATE))
+ return;
+ val &= ~BMCR_ISOLATE;
+ err = __b44_writephy(bp, 0, MII_BMCR, val);
+ if (err)
+ goto error;
+ }
+ return;
+error:
+ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
+}
+#else
+static inline void b44_wap54g10_workaround(struct b44 *bp)
+{
+}
+#endif
+
static int b44_setup_phy(struct b44 *bp)
{
u32 val;
int err;
+ b44_wap54g10_workaround(bp);
+
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
goto out;
if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
@@ -542,6 +523,19 @@ static void b44_check_phy(struct b44 *bp)
{
u32 bmsr, aux;
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+ bp->flags |= B44_FLAG_100_BASE_T;
+ bp->flags |= B44_FLAG_FULL_DUPLEX;
+ if (!netif_carrier_ok(bp->dev)) {
+ u32 val = br32(bp, B44_TX_CTRL);
+ val |= TX_CTRL_DUPLEX;
+ bw32(bp, B44_TX_CTRL, val);
+ netif_carrier_on(bp->dev);
+ b44_link_report(bp);
+ }
+ return;
+ }
+
if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
!b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
(bmsr != 0xffff)) {
@@ -617,10 +611,10 @@ static void b44_tx(struct b44 *bp)
BUG_ON(skb == NULL);
- pci_unmap_single(bp->pdev,
- pci_unmap_addr(rp, mapping),
+ dma_unmap_single(bp->sdev->dev,
+ rp->mapping,
skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
rp->skb = NULL;
dev_kfree_skb_irq(skb);
}
@@ -657,9 +651,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (skb == NULL)
return -ENOMEM;
- mapping = pci_map_single(bp->pdev, skb->data,
+ mapping = dma_map_single(bp->sdev->dev, skb->data,
RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
@@ -667,18 +661,19 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
/* Sigh... */
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping,
+ RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
if (skb == NULL)
return -ENOMEM;
- mapping = pci_map_single(bp->pdev, skb->data,
+ mapping = dma_map_single(bp->sdev->dev, skb->data,
RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (dma_mapping_error(mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
@@ -691,7 +686,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
rh->flags = 0;
map->skb = skb;
- pci_unmap_addr_set(map, mapping, mapping);
+ map->mapping = mapping;
if (src_map != NULL)
src_map->skb = NULL;
@@ -705,9 +700,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
if (bp->flags & B44_FLAG_RX_RING_HACK)
- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
- dest_idx * sizeof(dp),
- DMA_BIDIRECTIONAL);
+ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dp),
+ DMA_BIDIRECTIONAL);
return RX_PKT_BUF_SZ;
}
@@ -730,13 +725,12 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
rh = (struct rx_header *) src_map->skb->data;
rh->len = 0;
rh->flags = 0;
- pci_unmap_addr_set(dest_map, mapping,
- pci_unmap_addr(src_map, mapping));
+ dest_map->mapping = src_map->mapping;
if (bp->flags & B44_FLAG_RX_RING_HACK)
- b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
- src_idx * sizeof(src_desc),
- DMA_BIDIRECTIONAL);
+ b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma,
+ src_idx * sizeof(src_desc),
+ DMA_BIDIRECTIONAL);
ctrl = src_desc->ctrl;
if (dest_idx == (B44_RX_RING_SIZE - 1))
@@ -750,13 +744,13 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
src_map->skb = NULL;
if (bp->flags & B44_FLAG_RX_RING_HACK)
- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
- dest_idx * sizeof(dest_desc),
- DMA_BIDIRECTIONAL);
+ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dest_desc),
+ DMA_BIDIRECTIONAL);
- pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr),
- RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr),
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
}
static int b44_rx(struct b44 *bp, int budget)
@@ -772,13 +766,13 @@ static int b44_rx(struct b44 *bp, int budget)
while (cons != prod && budget > 0) {
struct ring_info *rp = &bp->rx_buffers[cons];
struct sk_buff *skb = rp->skb;
- dma_addr_t map = pci_unmap_addr(rp, mapping);
+ dma_addr_t map = rp->mapping;
struct rx_header *rh;
u16 len;
- pci_dma_sync_single_for_cpu(bp->pdev, map,
+ dma_sync_single_for_cpu(bp->sdev->dev, map,
RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
rh = (struct rx_header *) skb->data;
len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
@@ -810,8 +804,8 @@ static int b44_rx(struct b44 *bp, int budget)
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
if (skb_size < 0)
goto drop_it;
- pci_unmap_single(bp->pdev, map,
- skb_size, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, map,
+ skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
skb_put(skb, len + RX_PKT_OFFSET);
skb_pull(skb, RX_PKT_OFFSET);
@@ -848,10 +842,11 @@ static int b44_rx(struct b44 *bp, int budget)
return received;
}
-static int b44_poll(struct net_device *netdev, int *budget)
+static int b44_poll(struct napi_struct *napi, int budget)
{
- struct b44 *bp = netdev_priv(netdev);
- int done;
+ struct b44 *bp = container_of(napi, struct b44, napi);
+ struct net_device *netdev = bp->dev;
+ int work_done;
spin_lock_irq(&bp->lock);
@@ -862,22 +857,9 @@ static int b44_poll(struct net_device *netdev, int *budget)
}
spin_unlock_irq(&bp->lock);
- done = 1;
- if (bp->istat & ISTAT_RX) {
- int orig_budget = *budget;
- int work_done;
-
- if (orig_budget > netdev->quota)
- orig_budget = netdev->quota;
-
- work_done = b44_rx(bp, orig_budget);
-
- *budget -= work_done;
- netdev->quota -= work_done;
-
- if (work_done >= orig_budget)
- done = 0;
- }
+ work_done = 0;
+ if (bp->istat & ISTAT_RX)
+ work_done += b44_rx(bp, budget);
if (bp->istat & ISTAT_ERRORS) {
unsigned long flags;
@@ -888,15 +870,15 @@ static int b44_poll(struct net_device *netdev, int *budget)
b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
netif_wake_queue(bp->dev);
spin_unlock_irqrestore(&bp->lock, flags);
- done = 1;
+ work_done = 0;
}
- if (done) {
- netif_rx_complete(netdev);
+ if (work_done < budget) {
+ netif_rx_complete(netdev, napi);
b44_enable_ints(bp);
}
- return (done ? 0 : 1);
+ return work_done;
}
static irqreturn_t b44_interrupt(int irq, void *dev_id)
@@ -924,13 +906,13 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id)
goto irq_ack;
}
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
/* NOTE: These writes are posted by the readback of
* the ISTAT register below.
*/
bp->istat = istat;
__b44_disable_ints(bp);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
} else {
printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
dev->name);
@@ -982,24 +964,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_out;
}
- mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
struct sk_buff *bounce_skb;
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping, len,
+ DMA_TO_DEVICE);
bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb)
goto err_out;
- mapping = pci_map_single(bp->pdev, bounce_skb->data,
- len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(bp->sdev->dev, bounce_skb->data,
+ len, DMA_TO_DEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping,
- len, PCI_DMA_TODEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping,
+ len, DMA_TO_DEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
}
@@ -1011,7 +994,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = bp->tx_prod;
bp->tx_buffers[entry].skb = skb;
- pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
+ bp->tx_buffers[entry].mapping = mapping;
ctrl = (len & DESC_CTRL_LEN);
ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
@@ -1022,9 +1005,9 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
if (bp->flags & B44_FLAG_TX_RING_HACK)
- b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
- entry * sizeof(bp->tx_ring[0]),
- DMA_TO_DEVICE);
+ b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma,
+ entry * sizeof(bp->tx_ring[0]),
+ DMA_TO_DEVICE);
entry = NEXT_TX(entry);
@@ -1097,10 +1080,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- pci_unmap_single(bp->pdev,
- pci_unmap_addr(rp, mapping),
- RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1111,10 +1092,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- pci_unmap_single(bp->pdev,
- pci_unmap_addr(rp, mapping),
- rp->skb->len,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1136,14 +1115,14 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
if (bp->flags & B44_FLAG_RX_RING_HACK)
- dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- PCI_DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
if (bp->flags & B44_FLAG_TX_RING_HACK)
- dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- PCI_DMA_TODEVICE);
+ dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1163,24 +1142,24 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
if (bp->rx_ring) {
if (bp->flags & B44_FLAG_RX_RING_HACK) {
- dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
kfree(bp->rx_ring);
} else
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
bp->rx_ring, bp->rx_ring_dma);
bp->rx_ring = NULL;
bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
if (bp->flags & B44_FLAG_TX_RING_HACK) {
- dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
kfree(bp->tx_ring);
} else
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
bp->flags &= ~B44_FLAG_TX_RING_HACK;
@@ -1191,22 +1170,22 @@ static void b44_free_consistent(struct b44 *bp)
* Must not be invoked with interrupt sources disabled and
* the hardware shutdown down. Can sleep.
*/
-static int b44_alloc_consistent(struct b44 *bp)
+static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
{
int size;
size = B44_RX_RING_SIZE * sizeof(struct ring_info);
- bp->rx_buffers = kzalloc(size, GFP_KERNEL);
+ bp->rx_buffers = kzalloc(size, gfp);
if (!bp->rx_buffers)
goto out_err;
size = B44_TX_RING_SIZE * sizeof(struct ring_info);
- bp->tx_buffers = kzalloc(size, GFP_KERNEL);
+ bp->tx_buffers = kzalloc(size, gfp);
if (!bp->tx_buffers)
goto out_err;
size = DMA_TABLE_BYTES;
- bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
+ bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, gfp);
if (!bp->rx_ring) {
/* Allocation may have failed due to pci_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@@ -1214,13 +1193,13 @@ static int b44_alloc_consistent(struct b44 *bp)
struct dma_desc *rx_ring;
dma_addr_t rx_ring_dma;
- rx_ring = kzalloc(size, GFP_KERNEL);
+ rx_ring = kzalloc(size, gfp);
if (!rx_ring)
goto out_err;
- rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
if (dma_mapping_error(rx_ring_dma) ||
rx_ring_dma + size > DMA_30BIT_MASK) {
@@ -1233,21 +1212,21 @@ static int b44_alloc_consistent(struct b44 *bp)
bp->flags |= B44_FLAG_RX_RING_HACK;
}
- bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
+ bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, gfp);
if (!bp->tx_ring) {
- /* Allocation may have failed due to pci_alloc_consistent
+ /* Allocation may have failed due to dma_alloc_coherent
insisting on use of GFP_DMA, which is more restrictive
than necessary... */
struct dma_desc *tx_ring;
dma_addr_t tx_ring_dma;
- tx_ring = kzalloc(size, GFP_KERNEL);
+ tx_ring = kzalloc(size, gfp);
if (!tx_ring)
goto out_err;
- tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
if (dma_mapping_error(tx_ring_dma) ||
tx_ring_dma + size > DMA_30BIT_MASK) {
@@ -1282,7 +1261,9 @@ static void b44_clear_stats(struct b44 *bp)
/* bp->lock is held. */
static void b44_chip_reset(struct b44 *bp)
{
- if (ssb_is_core_up(bp)) {
+ struct ssb_device *sdev = bp->sdev;
+
+ if (ssb_device_is_enabled(bp->sdev)) {
bw32(bp, B44_RCV_LAZY, 0);
bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
@@ -1294,19 +1275,25 @@ static void b44_chip_reset(struct b44 *bp)
}
bw32(bp, B44_DMARX_CTRL, 0);
bp->rx_prod = bp->rx_cons = 0;
- } else {
- ssb_pci_setup(bp, (bp->core_unit == 0 ?
- SBINTVEC_ENET0 :
- SBINTVEC_ENET1));
- }
-
- ssb_core_reset(bp);
+ } else
+ ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev);
+ ssb_device_enable(bp->sdev, 0);
b44_clear_stats(bp);
- /* Make PHY accessible. */
- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
- (0x0d & MDIO_CTRL_MAXF_MASK)));
+ switch (sdev->bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+ (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
+ & MDIO_CTRL_MAXF_MASK)));
+ break;
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+ (0x0d & MDIO_CTRL_MAXF_MASK)));
+ break;
+ }
+
br32(bp, B44_MDIO_CTRL);
if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
@@ -1349,6 +1336,7 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
{
struct b44 *bp = netdev_priv(dev);
struct sockaddr *addr = p;
+ u32 val;
if (netif_running(dev))
return -EBUSY;
@@ -1359,7 +1347,11 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
spin_lock_irq(&bp->lock);
- __b44_set_mac_addr(bp);
+
+ val = br32(bp, B44_RXCONFIG);
+ if (!(val & RXCONFIG_CAM_ABSENT))
+ __b44_set_mac_addr(bp);
+
spin_unlock_irq(&bp->lock);
return 0;
@@ -1416,10 +1408,12 @@ static int b44_open(struct net_device *dev)
struct b44 *bp = netdev_priv(dev);
int err;
- err = b44_alloc_consistent(bp);
+ err = b44_alloc_consistent(bp, GFP_KERNEL);
if (err)
goto out;
+ napi_enable(&bp->napi);
+
b44_init_rings(bp);
b44_init_hw(bp, B44_FULL_RESET);
@@ -1427,6 +1421,7 @@ static int b44_open(struct net_device *dev)
err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (unlikely(err < 0)) {
+ napi_disable(&bp->napi);
b44_chip_reset(bp);
b44_free_rings(bp);
b44_free_consistent(bp);
@@ -1445,18 +1440,6 @@ out:
return err;
}
-#if 0
-/*static*/ void b44_dump_state(struct b44 *bp)
-{
- u32 val32, val32_2, val32_3, val32_4, val32_5;
- u16 val16;
-
- pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
- printk("DEBUG: PCI status [%04x] \n", val16);
-
-}
-#endif
-
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling receive - used by netconsole and other diagnostic tools
@@ -1519,14 +1502,13 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
u8 *pwol_pattern;
u8 pwol_mask[B44_PMASK_SIZE];
- pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+ pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
if (!pwol_pattern) {
printk(KERN_ERR PFX "Memory not available for WOL\n");
return;
}
/* Ipv4 magic packet pattern - pattern 0.*/
- memset(pwol_pattern, 0, B44_PATTERN_SIZE);
memset(pwol_mask, 0, B44_PMASK_SIZE);
plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
B44_ETHIPV4UDP_HLEN);
@@ -1568,10 +1550,24 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
}
+#ifdef CONFIG_B44_PCI
+static void b44_setup_wol_pci(struct b44 *bp)
+{
+ u16 val;
+
+ if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) {
+ bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE);
+ pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val);
+ pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE);
+ }
+}
+#else
+static inline void b44_setup_wol_pci(struct b44 *bp) { }
+#endif /* CONFIG_B44_PCI */
+
static void b44_setup_wol(struct b44 *bp)
{
u32 val;
- u16 pmval;
bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
@@ -1595,13 +1591,7 @@ static void b44_setup_wol(struct b44 *bp)
} else {
b44_setup_pseudo_magicp(bp);
}
-
- val = br32(bp, B44_SBTMSLOW);
- bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
-
- pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
- pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
-
+ b44_setup_wol_pci(bp);
}
static int b44_close(struct net_device *dev)
@@ -1610,15 +1600,12 @@ static int b44_close(struct net_device *dev)
netif_stop_queue(dev);
- netif_poll_disable(dev);
+ napi_disable(&bp->napi);
del_timer_sync(&bp->timer);
spin_lock_irq(&bp->lock);
-#if 0
- b44_dump_state(bp);
-#endif
b44_halt(bp);
b44_free_rings(bp);
netif_carrier_off(dev);
@@ -1627,8 +1614,6 @@ static int b44_close(struct net_device *dev)
free_irq(dev->irq, dev);
- netif_poll_enable(dev);
-
if (bp->flags & B44_FLAG_WOL_ENABLE) {
b44_init_hw(bp, B44_PARTIAL_RESET);
b44_setup_wol(bp);
@@ -1701,7 +1686,7 @@ static void __b44_set_rx_mode(struct net_device *dev)
val = br32(bp, B44_RXCONFIG);
val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
- if (dev->flags & IFF_PROMISC) {
+ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
val |= RXCONFIG_PROMISC;
bw32(bp, B44_RXCONFIG, val);
} else {
@@ -1749,11 +1734,19 @@ static void b44_set_msglevel(struct net_device *dev, u32 value)
static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
{
struct b44 *bp = netdev_priv(dev);
- struct pci_dev *pci_dev = bp->pdev;
+ struct ssb_bus *bus = bp->sdev->bus;
- strcpy (info->driver, DRV_MODULE_NAME);
- strcpy (info->version, DRV_MODULE_VERSION);
- strcpy (info->bus_info, pci_name(pci_dev));
+ strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+ strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+ break;
+ case SSB_BUSTYPE_PCMCIA:
+ case SSB_BUSTYPE_SSB:
+ strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+ break;
+ }
}
static int b44_nway_reset(struct net_device *dev)
@@ -1969,9 +1962,14 @@ static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static int b44_get_stats_count(struct net_device *dev)
+static int b44_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(b44_gstrings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(b44_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void b44_get_ethtool_stats(struct net_device *dev,
@@ -2032,9 +2030,8 @@ static const struct ethtool_ops b44_ethtool_ops = {
.get_msglevel = b44_get_msglevel,
.set_msglevel = b44_set_msglevel,
.get_strings = b44_get_strings,
- .get_stats_count = b44_get_stats_count,
+ .get_sset_count = b44_get_sset_count,
.get_ethtool_stats = b44_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -2053,33 +2050,23 @@ out:
return err;
}
-/* Read 128-bytes of EEPROM. */
-static int b44_read_eeprom(struct b44 *bp, u8 *data)
-{
- long i;
- __le16 *ptr = (__le16 *) data;
-
- for (i = 0; i < 128; i += 2)
- ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
-
- return 0;
-}
-
static int __devinit b44_get_invariants(struct b44 *bp)
{
- u8 eeprom[128];
- int err;
+ struct ssb_device *sdev = bp->sdev;
+ int err = 0;
+ u8 *addr;
- err = b44_read_eeprom(bp, &eeprom[0]);
- if (err)
- goto out;
+ bp->dma_offset = ssb_dma_translation(sdev);
- bp->dev->dev_addr[0] = eeprom[79];
- bp->dev->dev_addr[1] = eeprom[78];
- bp->dev->dev_addr[2] = eeprom[81];
- bp->dev->dev_addr[3] = eeprom[80];
- bp->dev->dev_addr[4] = eeprom[83];
- bp->dev->dev_addr[5] = eeprom[82];
+ if (sdev->bus->bustype == SSB_BUSTYPE_SSB &&
+ instance > 1) {
+ addr = sdev->bus->sprom.r1.et1mac;
+ bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr;
+ } else {
+ addr = sdev->bus->sprom.r1.et0mac;
+ bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr;
+ }
+ memcpy(bp->dev->dev_addr, addr, 6);
if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
@@ -2088,103 +2075,53 @@ static int __devinit b44_get_invariants(struct b44 *bp)
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
- bp->phy_addr = eeprom[90] & 0x1f;
-
bp->imask = IMASK_DEF;
- bp->core_unit = ssb_core_unit(bp);
- bp->dma_offset = SB_PCI_DMA;
-
/* XXX - really required?
bp->flags |= B44_FLAG_BUGGY_TXPTR;
- */
+ */
- if (ssb_get_core_rev(bp) >= 7)
- bp->flags |= B44_FLAG_B0_ANDLATER;
+ if (bp->sdev->id.revision >= 7)
+ bp->flags |= B44_FLAG_B0_ANDLATER;
-out:
return err;
}
-static int __devinit b44_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit b44_init_one(struct ssb_device *sdev,
+ const struct ssb_device_id *ent)
{
static int b44_version_printed = 0;
- unsigned long b44reg_base, b44reg_len;
struct net_device *dev;
struct b44 *bp;
- int err, i;
+ int err;
+ DECLARE_MAC_BUF(mac);
+
+ instance++;
if (b44_version_printed++ == 0)
printk(KERN_INFO "%s", version);
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "Cannot enable PCI device, "
- "aborting.\n");
- return err;
- }
-
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- dev_err(&pdev->dev,
- "Cannot find proper PCI device "
- "base address, aborting.\n");
- err = -ENODEV;
- goto err_out_disable_pdev;
- }
-
- err = pci_request_regions(pdev, DRV_MODULE_NAME);
- if (err) {
- dev_err(&pdev->dev,
- "Cannot obtain PCI resources, aborting.\n");
- goto err_out_disable_pdev;
- }
-
- pci_set_master(pdev);
-
- err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK);
- if (err) {
- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
- goto err_out_free_res;
- }
-
- err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK);
- if (err) {
- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
- goto err_out_free_res;
- }
-
- b44reg_base = pci_resource_start(pdev, 0);
- b44reg_len = pci_resource_len(pdev, 0);
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
- dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
+ dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
- goto err_out_free_res;
+ goto out;
}
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev,&pdev->dev);
+ SET_NETDEV_DEV(dev, sdev->dev);
/* No interesting netdevice features in this card... */
dev->features |= 0;
bp = netdev_priv(dev);
- bp->pdev = pdev;
+ bp->sdev = sdev;
bp->dev = dev;
bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
spin_lock_init(&bp->lock);
- bp->regs = ioremap(b44reg_base, b44reg_len);
- if (bp->regs == 0UL) {
- dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
- err = -ENOMEM;
- goto err_out_free_dev;
- }
-
bp->rx_pending = B44_DEF_RX_RING_PENDING;
bp->tx_pending = B44_DEF_TX_RING_PENDING;
@@ -2196,23 +2133,34 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
dev->set_mac_address = b44_set_mac_addr;
dev->do_ioctl = b44_ioctl;
dev->tx_timeout = b44_tx_timeout;
- dev->poll = b44_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &bp->napi, b44_poll, 64);
dev->watchdog_timeo = B44_TX_TIMEOUT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = b44_poll_controller;
#endif
dev->change_mtu = b44_change_mtu;
- dev->irq = pdev->irq;
+ dev->irq = sdev->irq;
SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
netif_carrier_off(dev);
+ err = ssb_bus_powerup(sdev->bus, 0);
+ if (err) {
+ dev_err(sdev->dev,
+ "Failed to powerup the bus\n");
+ goto err_out_free_dev;
+ }
+ err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK);
+ if (err) {
+ dev_err(sdev->dev,
+ "Required 30BIT DMA mask unsupported by the system.\n");
+ goto err_out_powerdown;
+ }
err = b44_get_invariants(bp);
if (err) {
- dev_err(&pdev->dev,
+ dev_err(sdev->dev,
"Problem fetching invariants of chip, aborting.\n");
- goto err_out_iounmap;
+ goto err_out_powerdown;
}
bp->mii_if.dev = dev;
@@ -2231,61 +2179,49 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
- goto err_out_iounmap;
+ dev_err(sdev->dev, "Cannot register net device, aborting.\n");
+ goto err_out_powerdown;
}
- pci_set_drvdata(pdev, dev);
-
- pci_save_state(bp->pdev);
+ ssb_set_drvdata(sdev, dev);
/* Chip reset provides power to the b44 MAC & PCI cores, which
* is necessary for MAC register access.
*/
b44_chip_reset(bp);
- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
-err_out_iounmap:
- iounmap(bp->regs);
+err_out_powerdown:
+ ssb_bus_may_powerdown(sdev->bus);
err_out_free_dev:
free_netdev(dev);
-err_out_free_res:
- pci_release_regions(pdev);
-
-err_out_disable_pdev:
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+out:
return err;
}
-static void __devexit b44_remove_one(struct pci_dev *pdev)
+static void __devexit b44_remove_one(struct ssb_device *sdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct b44 *bp = netdev_priv(dev);
+ struct net_device *dev = ssb_get_drvdata(sdev);
unregister_netdev(dev);
- iounmap(bp->regs);
+ ssb_bus_may_powerdown(sdev->bus);
free_netdev(dev);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+ ssb_set_drvdata(sdev, NULL);
}
-static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
+static int b44_suspend(struct ssb_device *sdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata(pdev);
+ struct net_device *dev = ssb_get_drvdata(sdev);
struct b44 *bp = netdev_priv(dev);
- if (!netif_running(dev))
- return 0;
+ if (!netif_running(dev))
+ return 0;
del_timer_sync(&bp->timer);
@@ -2303,33 +2239,29 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
b44_init_hw(bp, B44_PARTIAL_RESET);
b44_setup_wol(bp);
}
- pci_disable_device(pdev);
+
return 0;
}
-static int b44_resume(struct pci_dev *pdev)
+static int b44_resume(struct ssb_device *sdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
+ struct net_device *dev = ssb_get_drvdata(sdev);
struct b44 *bp = netdev_priv(dev);
int rc = 0;
- pci_restore_state(pdev);
- rc = pci_enable_device(pdev);
+ rc = ssb_bus_powerup(sdev->bus, 0);
if (rc) {
- printk(KERN_ERR PFX "%s: pci_enable_device failed\n",
- dev->name);
+ dev_err(sdev->dev,
+ "Failed to powerup the bus\n");
return rc;
}
- pci_set_master(pdev);
-
if (!netif_running(dev))
return 0;
rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
- pci_disable_device(pdev);
return rc;
}
@@ -2348,29 +2280,53 @@ static int b44_resume(struct pci_dev *pdev)
return 0;
}
-static struct pci_driver b44_driver = {
+static struct ssb_driver b44_ssb_driver = {
.name = DRV_MODULE_NAME,
- .id_table = b44_pci_tbl,
+ .id_table = b44_ssb_tbl,
.probe = b44_init_one,
.remove = __devexit_p(b44_remove_one),
- .suspend = b44_suspend,
- .resume = b44_resume,
+ .suspend = b44_suspend,
+ .resume = b44_resume,
};
+static inline int b44_pci_init(void)
+{
+ int err = 0;
+#ifdef CONFIG_B44_PCI
+ err = ssb_pcihost_register(&b44_pci_driver);
+#endif
+ return err;
+}
+
+static inline void b44_pci_exit(void)
+{
+#ifdef CONFIG_B44_PCI
+ ssb_pcihost_unregister(&b44_pci_driver);
+#endif
+}
+
static int __init b44_init(void)
{
unsigned int dma_desc_align_size = dma_get_cache_alignment();
+ int err;
/* Setup paramaters for syncing RX/TX DMA descriptors */
dma_desc_align_mask = ~(dma_desc_align_size - 1);
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
- return pci_register_driver(&b44_driver);
+ err = b44_pci_init();
+ if (err)
+ return err;
+ err = ssb_driver_register(&b44_ssb_driver);
+ if (err)
+ b44_pci_exit();
+ return err;
}
static void __exit b44_cleanup(void)
{
- pci_unregister_driver(&b44_driver);
+ ssb_driver_unregister(&b44_ssb_driver);
+ b44_pci_exit();
}
module_init(b44_init);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index e537e63f292e..7db0c84a7950 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -129,6 +129,7 @@
#define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
#define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
#define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
+#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */
#define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
#define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
#define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
@@ -227,76 +228,6 @@
#define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */
#define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */
-/* Silicon backplane register definitions */
-#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
-#define SBIMSTATE_PC 0x0000000f /* Pipe Count */
-#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
-#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */
-#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */
-#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */
-#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */
-#define SBIMSTATE_IBE 0x00020000 /* In Band Error */
-#define SBIMSTATE_TO 0x00040000 /* Timeout */
-#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */
-#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
-#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */
-#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */
-#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */
-#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */
-#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */
-#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */
-#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */
-#define SBTMSLOW_RESET 0x00000001 /* Reset */
-#define SBTMSLOW_REJECT 0x00000002 /* Reject */
-#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */
-#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
-#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */
-#define SBTMSLOW_BE 0x80000000 /* BIST Enable */
-#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */
-#define SBTMSHIGH_SERR 0x00000001 /* S-error */
-#define SBTMSHIGH_INT 0x00000002 /* Interrupt */
-#define SBTMSHIGH_BUSY 0x00000004 /* Busy */
-#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */
-#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */
-#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */
-#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */
-#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */
-#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
-#define SBIDHIGH_CC_SHIFT 4
-#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */
-#define SBIDHIGH_VC_SHIFT 16
-
-/* SSB PCI config space registers. */
-#define SSB_PMCSR 0x44
-#define SSB_PE 0x100
-#define SSB_BAR0_WIN 0x80
-#define SSB_BAR1_WIN 0x84
-#define SSB_SPROM_CONTROL 0x88
-#define SSB_BAR1_CONTROL 0x8c
-
-/* SSB core and host control registers. */
-#define SSB_CONTROL 0x0000UL
-#define SSB_ARBCONTROL 0x0010UL
-#define SSB_ISTAT 0x0020UL
-#define SSB_IMASK 0x0024UL
-#define SSB_MBOX 0x0028UL
-#define SSB_BCAST_ADDR 0x0050UL
-#define SSB_BCAST_DATA 0x0054UL
-#define SSB_PCI_TRANS_0 0x0100UL
-#define SSB_PCI_TRANS_1 0x0104UL
-#define SSB_PCI_TRANS_2 0x0108UL
-#define SSB_SPROM 0x0800UL
-
-#define SSB_PCI_MEM 0x00000000
-#define SSB_PCI_IO 0x00000001
-#define SSB_PCI_CFG0 0x00000002
-#define SSB_PCI_CFG1 0x00000003
-#define SSB_PCI_PREF 0x00000004
-#define SSB_PCI_BURST 0x00000008
-#define SSB_PCI_MASK0 0xfc000000
-#define SSB_PCI_MASK1 0xfc000000
-#define SSB_PCI_MASK2 0xc0000000
-
/* 4400 PHY registers */
#define B44_MII_AUXCTRL 24 /* Auxiliary Control */
#define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */
@@ -346,10 +277,12 @@ struct rx_header {
struct ring_info {
struct sk_buff *skb;
- DECLARE_PCI_UNMAP_ADDR(mapping);
+ dma_addr_t mapping;
};
#define B44_MCAST_TABLE_SIZE 32
+#define B44_PHY_ADDR_NO_PHY 30
+#define B44_MDC_RATIO 5000000
#define B44_STAT_REG_DECLARE \
_B44(tx_good_octets) \
@@ -410,6 +343,8 @@ B44_STAT_REG_DECLARE
#undef _B44
};
+struct ssb_device;
+
struct b44 {
spinlock_t lock;
@@ -423,6 +358,8 @@ struct b44 {
struct ring_info *rx_buffers;
struct ring_info *tx_buffers;
+ struct napi_struct napi;
+
u32 dma_offset;
u32 flags;
#define B44_FLAG_B0_ANDLATER 0x00000001
@@ -450,8 +387,7 @@ struct b44 {
struct net_device_stats stats;
struct b44_hw_stats hw_stats;
- void __iomem *regs;
- struct pci_dev *pdev;
+ struct ssb_device *sdev;
struct net_device *dev;
dma_addr_t rx_ring_dma, tx_ring_dma;
@@ -459,7 +395,6 @@ struct b44 {
u32 rx_pending;
u32 tx_pending;
u8 phy_addr;
- u8 core_unit;
struct mii_if_info mii_if;
};
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
new file mode 100644
index 000000000000..53fe7ded5d50
--- /dev/null
+++ b/drivers/net/bfin_mac.c
@@ -0,0 +1,1081 @@
+/*
+ * File: drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ * Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program ; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/portmux.h>
+
+#include "bfin_mac.h"
+
+#define DRV_NAME "bfin_mac"
+#define DRV_VERSION "1.1"
+#define DRV_AUTHOR "Bryan Wu, Luke Yang"
+#define DRV_DESC "Blackfin BF53[67] on-chip Ethernet MAC driver"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
+
+#if defined(CONFIG_BFIN_MAC_USE_L1)
+# define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size)
+# define bfin_mac_free(dma_handle, ptr) l1_data_sram_free(ptr)
+#else
+# define bfin_mac_alloc(dma_handle, size) \
+ dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL)
+# define bfin_mac_free(dma_handle, ptr) \
+ dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle)
+#endif
+
+#define PKT_BUF_SZ 1580
+
+#define MAX_TIMEOUT_CNT 500
+
+/* pointers to maintain transmit list */
+static struct net_dma_desc_tx *tx_list_head;
+static struct net_dma_desc_tx *tx_list_tail;
+static struct net_dma_desc_rx *rx_list_head;
+static struct net_dma_desc_rx *rx_list_tail;
+static struct net_dma_desc_rx *current_rx_ptr;
+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);
+
+static void desc_list_free(void)
+{
+ struct net_dma_desc_rx *r;
+ struct net_dma_desc_tx *t;
+ int i;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+ dma_addr_t dma_handle = 0;
+#endif
+
+ if (tx_desc) {
+ t = tx_list_head;
+ for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+ if (t) {
+ if (t->skb) {
+ dev_kfree_skb(t->skb);
+ t->skb = NULL;
+ }
+ t = t->next;
+ }
+ }
+ bfin_mac_free(dma_handle, tx_desc);
+ }
+
+ if (rx_desc) {
+ r = rx_list_head;
+ for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+ if (r) {
+ if (r->skb) {
+ dev_kfree_skb(r->skb);
+ r->skb = NULL;
+ }
+ r = r->next;
+ }
+ }
+ bfin_mac_free(dma_handle, rx_desc);
+ }
+}
+
+static int desc_list_init(void)
+{
+ int i;
+ struct sk_buff *new_skb;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+ /*
+ * This dma_handle is useless in Blackfin dma_alloc_coherent().
+ * The real dma handler is the return value of dma_alloc_coherent().
+ */
+ dma_addr_t dma_handle;
+#endif
+
+ tx_desc = bfin_mac_alloc(&dma_handle,
+ sizeof(struct net_dma_desc_tx) *
+ CONFIG_BFIN_TX_DESC_NUM);
+ if (tx_desc == NULL)
+ goto init_error;
+
+ rx_desc = bfin_mac_alloc(&dma_handle,
+ sizeof(struct net_dma_desc_rx) *
+ CONFIG_BFIN_RX_DESC_NUM);
+ if (rx_desc == NULL)
+ goto init_error;
+
+ /* init tx_list */
+ tx_list_head = tx_list_tail = tx_desc;
+
+ for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+ struct net_dma_desc_tx *t = tx_desc + i;
+ struct dma_descriptor *a = &(t->desc_a);
+ struct dma_descriptor *b = &(t->desc_b);
+
+ /*
+ * disable DMA
+ * read from memory WNR = 0
+ * wordsize is 32 bits
+ * 6 half words is desc size
+ * large desc flow
+ */
+ a->config = WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+ a->start_addr = (unsigned long)t->packet;
+ a->x_count = 0;
+ a->next_dma_desc = b;
+
+ /*
+ * enabled DMA
+ * write to memory WNR = 1
+ * wordsize is 32 bits
+ * disable interrupt
+ * 6 half words is desc size
+ * large desc flow
+ */
+ b->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+ b->start_addr = (unsigned long)(&(t->status));
+ b->x_count = 0;
+
+ t->skb = NULL;
+ tx_list_tail->desc_b.next_dma_desc = a;
+ tx_list_tail->next = t;
+ tx_list_tail = t;
+ }
+ tx_list_tail->next = tx_list_head; /* tx_list is a circle */
+ tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a);
+ current_tx_ptr = tx_list_head;
+
+ /* init rx_list */
+ rx_list_head = rx_list_tail = rx_desc;
+
+ for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+ struct net_dma_desc_rx *r = rx_desc + i;
+ struct dma_descriptor *a = &(r->desc_a);
+ struct dma_descriptor *b = &(r->desc_b);
+
+ /* allocate a new skb for next time receive */
+ new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+ if (!new_skb) {
+ printk(KERN_NOTICE DRV_NAME
+ ": init: low on mem - packet dropped\n");
+ goto init_error;
+ }
+ skb_reserve(new_skb, 2);
+ r->skb = new_skb;
+
+ /*
+ * enabled DMA
+ * write to memory WNR = 1
+ * wordsize is 32 bits
+ * disable interrupt
+ * 6 half words is desc size
+ * large desc flow
+ */
+ a->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+ /* since RXDWA is enabled */
+ a->start_addr = (unsigned long)new_skb->data - 2;
+ a->x_count = 0;
+ a->next_dma_desc = b;
+
+ /*
+ * enabled DMA
+ * write to memory WNR = 1
+ * wordsize is 32 bits
+ * enable interrupt
+ * 6 half words is desc size
+ * large desc flow
+ */
+ b->config = DMAEN | WNR | WDSIZE_32 | DI_EN |
+ NDSIZE_6 | DMAFLOW_LARGE;
+ b->start_addr = (unsigned long)(&(r->status));
+ b->x_count = 0;
+
+ rx_list_tail->desc_b.next_dma_desc = a;
+ rx_list_tail->next = r;
+ rx_list_tail = r;
+ }
+ rx_list_tail->next = rx_list_head; /* rx_list is a circle */
+ rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a);
+ current_rx_ptr = rx_list_head;
+
+ return 0;
+
+init_error:
+ desc_list_free();
+ printk(KERN_ERR DRV_NAME ": kmalloc failed\n");
+ return -ENOMEM;
+}
+
+
+/*---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
+ */
+/* Wait until the previous MDC/MDIO transaction has completed */
+static void mdio_poll(void)
+{
+ int timeout_cnt = MAX_TIMEOUT_CNT;
+
+ /* poll the STABUSY bit */
+ while ((bfin_read_EMAC_STAADD()) & STABUSY) {
+ mdelay(10);
+ if (timeout_cnt-- < 0) {
+ printk(KERN_ERR DRV_NAME
+ ": wait MDC/MDIO transaction to complete timeout\n");
+ break;
+ }
+ }
+}
+
+/* Read an off-chip register in a PHY through the MDC/MDIO port */
+static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+ mdio_poll();
+
+ /* read mode */
+ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
+ SET_REGAD((u16) regnum) |
+ STABUSY);
+
+ mdio_poll();
+
+ return (int) bfin_read_EMAC_STADAT();
+}
+
+/* Write an off-chip register in a PHY through the MDC/MDIO port */
+static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+ u16 value)
+{
+ mdio_poll();
+
+ bfin_write_EMAC_STADAT((u32) value);
+
+ /* write mode */
+ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
+ SET_REGAD((u16) regnum) |
+ STAOP |
+ STABUSY);
+
+ mdio_poll();
+
+ return 0;
+}
+
+static int mdiobus_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+static void bf537_adjust_link(struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ struct phy_device *phydev = lp->phydev;
+ unsigned long flags;
+ int new_state = 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+ if (phydev->link) {
+ /* Now we make sure that we can be in full duplex mode.
+ * If not, we operate in half-duplex mode. */
+ if (phydev->duplex != lp->old_duplex) {
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ new_state = 1;
+
+ if (phydev->duplex)
+ opmode |= FDMODE;
+ else
+ opmode &= ~(FDMODE);
+
+ bfin_write_EMAC_OPMODE(opmode);
+ lp->old_duplex = phydev->duplex;
+ }
+
+ if (phydev->speed != lp->old_speed) {
+#if defined(CONFIG_BFIN_MAC_RMII)
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ bf537mac_disable();
+ switch (phydev->speed) {
+ case 10:
+ opmode |= RMII_10;
+ break;
+ case 100:
+ opmode &= ~(RMII_10);
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Ack! Speed (%d) is not 10/100!\n",
+ DRV_NAME, phydev->speed);
+ break;
+ }
+ bfin_write_EMAC_OPMODE(opmode);
+ bf537mac_enable();
+#endif
+
+ new_state = 1;
+ lp->old_speed = phydev->speed;
+ }
+
+ if (!lp->old_link) {
+ new_state = 1;
+ lp->old_link = 1;
+ netif_schedule(dev);
+ }
+ } else if (lp->old_link) {
+ new_state = 1;
+ lp->old_link = 0;
+ lp->old_speed = 0;
+ lp->old_duplex = -1;
+ }
+
+ if (new_state) {
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ phy_print_status(phydev);
+ pr_debug("EMAC_OPMODE = 0x%08x\n", opmode);
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static int mii_probe(struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ unsigned short sysctl;
+ int i;
+
+ /* Enable PHY output early */
+ if (!(bfin_read_VR_CTL() & PHYCLKOE))
+ bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+
+ /* MDC = 2.5 MHz */
+ sysctl = bfin_read_EMAC_SYSCTL();
+ sysctl |= SET_MDCDIV(24);
+ bfin_write_EMAC_SYSCTL(sysctl);
+
+ /* search for connect PHY device */
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i];
+
+ if (!tmp_phydev)
+ continue; /* no PHY here... */
+
+ phydev = tmp_phydev;
+ break; /* found it */
+ }
+
+ /* now we are supposed to have a proper phydev, to attach to... */
+ if (!phydev) {
+ printk(KERN_INFO "%s: Don't found any phy device at all\n",
+ dev->name);
+ return -ENODEV;
+ }
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ PHY_INTERFACE_MODE_RMII);
+#else
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+#endif
+
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_Pause | SUPPORTED_Asym_Pause
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+
+ lp->old_link = 0;
+ lp->old_speed = 0;
+ lp->old_duplex = -1;
+ lp->phydev = phydev;
+
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, irq=%d)\n",
+ DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+
+ return 0;
+}
+
+/**************************************************************************/
+void setup_system_regs(struct net_device *dev)
+{
+ unsigned short sysctl;
+
+ /*
+ * Odd word alignment for Receive Frame DMA word
+ * Configure checksum support and rcve frame word alignment
+ */
+ sysctl = bfin_read_EMAC_SYSCTL();
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ sysctl |= RXDWA | RXCKS;
+#else
+ sysctl |= RXDWA;
+#endif
+ bfin_write_EMAC_SYSCTL(sysctl);
+
+ bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
+
+ /* Initialize the TX DMA channel registers */
+ bfin_write_DMA2_X_COUNT(0);
+ bfin_write_DMA2_X_MODIFY(4);
+ bfin_write_DMA2_Y_COUNT(0);
+ bfin_write_DMA2_Y_MODIFY(0);
+
+ /* Initialize the RX DMA channel registers */
+ bfin_write_DMA1_X_COUNT(0);
+ bfin_write_DMA1_X_MODIFY(4);
+ bfin_write_DMA1_Y_COUNT(0);
+ bfin_write_DMA1_Y_MODIFY(0);
+}
+
+static void setup_mac_addr(u8 *mac_addr)
+{
+ u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]);
+ u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]);
+
+ /* this depends on a little-endian machine */
+ bfin_write_EMAC_ADDRLO(addr_low);
+ bfin_write_EMAC_ADDRHI(addr_hi);
+}
+
+static int bf537mac_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ if (netif_running(dev))
+ return -EBUSY;
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ setup_mac_addr(dev->dev_addr);
+ return 0;
+}
+
+static void adjust_tx_list(void)
+{
+ int timeout_cnt = MAX_TIMEOUT_CNT;
+
+ if (tx_list_head->status.status_word != 0
+ && current_tx_ptr != tx_list_head) {
+ goto adjust_head; /* released something, just return; */
+ }
+
+ /*
+ * if nothing released, check wait condition
+ * current's next can not be the head,
+ * otherwise the dma will not stop as we want
+ */
+ if (current_tx_ptr->next->next == tx_list_head) {
+ while (tx_list_head->status.status_word == 0) {
+ mdelay(10);
+ if (tx_list_head->status.status_word != 0
+ || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
+ goto adjust_head;
+ }
+ if (timeout_cnt-- < 0) {
+ printk(KERN_ERR DRV_NAME
+ ": wait for adjust tx list head timeout\n");
+ break;
+ }
+ }
+ if (tx_list_head->status.status_word != 0) {
+ goto adjust_head;
+ }
+ }
+
+ return;
+
+adjust_head:
+ do {
+ tx_list_head->desc_a.config &= ~DMAEN;
+ tx_list_head->status.status_word = 0;
+ if (tx_list_head->skb) {
+ dev_kfree_skb(tx_list_head->skb);
+ tx_list_head->skb = NULL;
+ } else {
+ printk(KERN_ERR DRV_NAME
+ ": no sk_buff in a transmitted frame!\n");
+ }
+ tx_list_head = tx_list_head->next;
+ } while (tx_list_head->status.status_word != 0
+ && current_tx_ptr != tx_list_head);
+ return;
+
+}
+
+static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ unsigned int data;
+
+ current_tx_ptr->skb = skb;
+
+ /*
+ * Is skb->data always 16-bit aligned?
+ * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)?
+ */
+ if ((((unsigned int)(skb->data)) & 0x02) == 2) {
+ /* move skb->data to current_tx_ptr payload */
+ data = (unsigned int)(skb->data) - 2;
+ *((unsigned short *)data) = (unsigned short)(skb->len);
+ current_tx_ptr->desc_a.start_addr = (unsigned long)data;
+ /* this is important! */
+ blackfin_dcache_flush_range(data, (data + (skb->len)) + 2);
+
+ } else {
+ *((unsigned short *)(current_tx_ptr->packet)) =
+ (unsigned short)(skb->len);
+ memcpy((char *)(current_tx_ptr->packet + 2), skb->data,
+ (skb->len));
+ current_tx_ptr->desc_a.start_addr =
+ (unsigned long)current_tx_ptr->packet;
+ if (current_tx_ptr->status.status_word != 0)
+ current_tx_ptr->status.status_word = 0;
+ blackfin_dcache_flush_range((unsigned int)current_tx_ptr->
+ packet,
+ (unsigned int)(current_tx_ptr->
+ packet + skb->len) +
+ 2);
+ }
+
+ /* enable this packet's dma */
+ current_tx_ptr->desc_a.config |= DMAEN;
+
+ /* tx dma is running, just return */
+ if (bfin_read_DMA2_IRQ_STATUS() & 0x08)
+ goto out;
+
+ /* tx dma is not running */
+ bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a));
+ /* dma enabled, read from memory, size is 6 */
+ bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config);
+ /* Turn on the EMAC tx */
+ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
+
+out:
+ adjust_tx_list();
+ current_tx_ptr = current_tx_ptr->next;
+ dev->trans_start = jiffies;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += (skb->len);
+ return 0;
+}
+
+static void bf537mac_rx(struct net_device *dev)
+{
+ struct sk_buff *skb, *new_skb;
+ struct bf537mac_local *lp = netdev_priv(dev);
+ unsigned short len;
+
+ /* allocate a new skb for next time receive */
+ skb = current_rx_ptr->skb;
+ new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+ if (!new_skb) {
+ printk(KERN_NOTICE DRV_NAME
+ ": rx: low on mem - packet dropped\n");
+ dev->stats.rx_dropped++;
+ goto out;
+ }
+ /* reserve 2 bytes for RXDWA padding */
+ skb_reserve(new_skb, 2);
+ current_rx_ptr->skb = new_skb;
+ current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
+
+ len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
+ skb_put(skb, len);
+ blackfin_dcache_invalidate_range((unsigned long)skb->head,
+ (unsigned long)skb->tail);
+
+ dev->last_rx = jiffies;
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ skb->csum = current_rx_ptr->status.ip_payload_csum;
+ skb->ip_summed = CHECKSUM_PARTIAL;
+#endif
+
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ current_rx_ptr->status.status_word = 0x00000000;
+ current_rx_ptr = current_rx_ptr->next;
+
+out:
+ return;
+}
+
+/* interrupt routine to handle rx and error signal */
+static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ int number = 0;
+
+get_one_packet:
+ if (current_rx_ptr->status.status_word == 0) {
+ /* no more new packet received */
+ if (number == 0) {
+ if (current_rx_ptr->next->status.status_word != 0) {
+ current_rx_ptr = current_rx_ptr->next;
+ goto real_rx;
+ }
+ }
+ bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() |
+ DMA_DONE | DMA_ERR);
+ return IRQ_HANDLED;
+ }
+
+real_rx:
+ bf537mac_rx(dev);
+ number++;
+ goto get_one_packet;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bf537mac_poll(struct net_device *dev)
+{
+ disable_irq(IRQ_MAC_RX);
+ bf537mac_interrupt(IRQ_MAC_RX, dev);
+ enable_irq(IRQ_MAC_RX);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+static void bf537mac_disable(void)
+{
+ unsigned int opmode;
+
+ opmode = bfin_read_EMAC_OPMODE();
+ opmode &= (~RE);
+ opmode &= (~TE);
+ /* Turn off the EMAC */
+ bfin_write_EMAC_OPMODE(opmode);
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static void bf537mac_enable(void)
+{
+ u32 opmode;
+
+ pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);
+
+ /* Set RX DMA */
+ bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
+ bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
+
+ /* Wait MII done */
+ mdio_poll();
+
+ /* We enable only RX here */
+ /* ASTP : Enable Automatic Pad Stripping
+ PR : Promiscuous Mode for test
+ PSF : Receive frames with total length less than 64 bytes.
+ FDMODE : Full Duplex Mode
+ LB : Internal Loopback for test
+ RE : Receiver Enable */
+ opmode = bfin_read_EMAC_OPMODE();
+ if (opmode & FDMODE)
+ opmode |= PSF;
+ else
+ opmode |= DRO | DC | PSF;
+ opmode |= RE;
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+ opmode |= RMII; /* For Now only 100MBit are supported */
+#ifdef CONFIG_BF_REV_0_2
+ opmode |= TE;
+#endif
+#endif
+ /* Turn on the EMAC rx */
+ bfin_write_EMAC_OPMODE(opmode);
+}
+
+/* Our watchdog timed out. Called by the networking layer */
+static void bf537mac_timeout(struct net_device *dev)
+{
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ bf537mac_disable();
+
+ /* reset tx queue */
+ tx_list_tail = tx_list_head->next;
+
+ bf537mac_enable();
+
+ /* We can accept TX packets again */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void bf537mac_set_multicast_list(struct net_device *dev)
+{
+ u32 sysctl;
+
+ if (dev->flags & IFF_PROMISC) {
+ printk(KERN_INFO "%s: set to promisc mode\n", dev->name);
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl |= RAF;
+ bfin_write_EMAC_OPMODE(sysctl);
+ } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+ /* accept all multicast */
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl |= PAM;
+ bfin_write_EMAC_OPMODE(sysctl);
+ } else {
+ /* clear promisc or multicast mode */
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl &= ~(RAF | PAM);
+ bfin_write_EMAC_OPMODE(sysctl);
+ }
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void bf537mac_shutdown(struct net_device *dev)
+{
+ /* Turn off the EMAC */
+ bfin_write_EMAC_OPMODE(0x00000000);
+ /* Turn off the EMAC RX DMA */
+ bfin_write_DMA1_CONFIG(0x0000);
+ bfin_write_DMA2_CONFIG(0x0000);
+}
+
+/*
+ * Open and Initialize the interface
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int bf537mac_open(struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ int retval;
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ /*
+ * Check that the address is valid. If its not, refuse
+ * to bring the device up. The user must specify an
+ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+ */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_WARNING DRV_NAME ": no valid ethernet hw addr\n");
+ return -EINVAL;
+ }
+
+ /* initial rx and tx list */
+ retval = desc_list_init();
+
+ if (retval)
+ return retval;
+
+ phy_start(lp->phydev);
+ setup_system_regs(dev);
+ bf537mac_disable();
+ bf537mac_enable();
+
+ pr_debug("hardware init finished\n");
+ netif_start_queue(dev);
+ netif_carrier_on(dev);
+
+ return 0;
+}
+
+/*
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world. Caused by
+ * an 'ifconfig ethX down'
+ */
+static int bf537mac_close(struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ phy_stop(lp->phydev);
+
+ /* clear everything */
+ bf537mac_shutdown(dev);
+
+ /* free the rx/tx buffers */
+ desc_list_free();
+
+ return 0;
+}
+
+static int __init bf537mac_probe(struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ int retval;
+ int i;
+
+ /* 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());
+
+ /* 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;
+ }
+
+ /* 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 */
+ get_bf537_ether_addr(dev->dev_addr);
+ }
+
+ /* If still not valid, get a random one */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ random_ether_addr(dev->dev_addr);
+ }
+
+ setup_mac_addr(dev->dev_addr);
+
+ /* MDIO bus initial */
+ lp->mii_bus.priv = dev;
+ lp->mii_bus.read = mdiobus_read;
+ lp->mii_bus.write = mdiobus_write;
+ lp->mii_bus.reset = mdiobus_reset;
+ lp->mii_bus.name = "bfin_mac_mdio";
+ lp->mii_bus.id = 0;
+ lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ lp->mii_bus.irq[i] = PHY_POLL;
+
+ mdiobus_register(&lp->mii_bus);
+
+ retval = mii_probe(dev);
+ if (retval)
+ return retval;
+
+ /* 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;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = bf537mac_poll;
+#endif
+
+ spin_lock_init(&lp->lock);
+
+ /* now, enable interrupts */
+ /* register irq handler */
+ if (request_irq
+ (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ "BFIN537_MAC_RX", dev)) {
+ printk(KERN_WARNING DRV_NAME
+ ": Unable to attach BlackFin MAC RX interrupt\n");
+ return -EBUSY;
+ }
+
+
+ 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;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ platform_set_drvdata(pdev, ndev);
+
+ if (bf537mac_probe(ndev) != 0) {
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+ printk(KERN_WARNING DRV_NAME ": not found\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int bfin_mac_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ unregister_netdev(ndev);
+
+ free_irq(IRQ_MAC_RX, ndev);
+
+ free_netdev(ndev);
+
+ setup_pin_mux(0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+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);
+
+ return 0;
+}
+
+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);
+
+ return 0;
+}
+#else
+#define bfin_mac_suspend NULL
+#define bfin_mac_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver bfin_mac_driver = {
+ .probe = bfin_mac_probe,
+ .remove = bfin_mac_remove,
+ .resume = bfin_mac_resume,
+ .suspend = bfin_mac_suspend,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init bfin_mac_init(void)
+{
+ return platform_driver_register(&bfin_mac_driver);
+}
+
+module_init(bfin_mac_init);
+
+static void __exit bfin_mac_cleanup(void)
+{
+ platform_driver_unregister(&bfin_mac_driver);
+}
+
+module_exit(bfin_mac_cleanup);
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
new file mode 100644
index 000000000000..3a107ad75381
--- /dev/null
+++ b/drivers/net/bfin_mac.h
@@ -0,0 +1,95 @@
+/*
+ * File: drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ * Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program ; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define BFIN_MAC_CSUM_OFFLOAD
+
+struct dma_descriptor {
+ struct dma_descriptor *next_dma_desc;
+ unsigned long start_addr;
+ unsigned short config;
+ unsigned short x_count;
+};
+
+struct status_area_rx {
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ unsigned short ip_hdr_csum; /* ip header checksum */
+ /* ip payload(udp or tcp or others) checksum */
+ unsigned short ip_payload_csum;
+#endif
+ unsigned long status_word; /* the frame status word */
+};
+
+struct status_area_tx {
+ unsigned long status_word; /* the frame status word */
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_rx {
+ struct net_dma_desc_rx *next;
+ struct sk_buff *skb;
+ struct dma_descriptor desc_a;
+ struct dma_descriptor desc_b;
+ struct status_area_rx status;
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_tx {
+ struct net_dma_desc_tx *next;
+ struct sk_buff *skb;
+ struct dma_descriptor desc_a;
+ struct dma_descriptor desc_b;
+ unsigned char packet[1560];
+ struct status_area_tx status;
+};
+
+struct bf537mac_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
+ * performing
+ */
+ struct net_device_stats stats;
+
+ unsigned char Mac[6]; /* MAC address of the board */
+ spinlock_t lock;
+
+ /* MII and PHY stuffs */
+ int old_link; /* used by bf537_adjust_link */
+ int old_speed;
+ int old_duplex;
+
+ struct phy_device *phydev;
+ struct mii_bus mii_bus;
+};
+
+extern void get_bf537_ether_addr(char *addr);
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 9b8d7d9dbe86..a42bd19646d3 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/bitrev.h>
+#include <linux/ethtool.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -74,7 +75,6 @@ struct bmac_data {
int tx_fill;
int tx_empty;
unsigned char tx_fullup;
- struct net_device_stats stats;
struct timer_list tx_timeout;
int timeout_active;
int sleeping;
@@ -144,7 +144,6 @@ static unsigned char *bmac_emergency_rxbuf;
static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *bmac_stats(struct net_device *dev);
static void bmac_set_multicast(struct net_device *dev);
static void bmac_reset_and_enable(struct net_device *dev);
static void bmac_start_chip(struct net_device *dev);
@@ -667,7 +666,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
bp->tx_bufs[bp->tx_fill] = skb;
bp->tx_fill = i;
- bp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dbdma_continue(td);
@@ -706,8 +705,8 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
nb = RX_BUFLEN - residual - 2;
if (nb < (ETHERMINPACKET - ETHERCRC)) {
skb = NULL;
- bp->stats.rx_length_errors++;
- bp->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
} else {
skb = bp->rx_bufs[i];
bp->rx_bufs[i] = NULL;
@@ -718,10 +717,10 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- ++bp->stats.rx_packets;
- bp->stats.rx_bytes += nb;
+ ++dev->stats.rx_packets;
+ dev->stats.rx_bytes += nb;
} else {
- ++bp->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
}
dev->last_rx = jiffies;
if ((skb = bp->rx_bufs[i]) == NULL) {
@@ -784,7 +783,7 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
}
if (bp->tx_bufs[bp->tx_empty]) {
- ++bp->stats.tx_packets;
+ ++dev->stats.tx_packets;
dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]);
}
bp->tx_bufs[bp->tx_empty] = NULL;
@@ -806,13 +805,6 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct net_device_stats *bmac_stats(struct net_device *dev)
-{
- struct bmac_data *p = netdev_priv(dev);
-
- return &p->stats;
-}
-
#ifndef SUNHME_MULTICAST
/* Real fast bit-reversal algorithm, 6-bit values */
static int reverse6[64] = {
@@ -1079,17 +1071,17 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id)
}
/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
/* bmac_txdma_intr_inner(irq, dev_id); */
- /* if (status & FrameReceived) bp->stats.rx_dropped++; */
- if (status & RxErrorMask) bp->stats.rx_errors++;
- if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
- if (status & RxLenCntExp) bp->stats.rx_length_errors++;
- if (status & RxOverFlow) bp->stats.rx_over_errors++;
- if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
-
- /* if (status & FrameSent) bp->stats.tx_dropped++; */
- if (status & TxErrorMask) bp->stats.tx_errors++;
- if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
- if (status & TxNormalCollExp) bp->stats.collisions++;
+ /* if (status & FrameReceived) dev->stats.rx_dropped++; */
+ if (status & RxErrorMask) dev->stats.rx_errors++;
+ if (status & RxCRCCntExp) dev->stats.rx_crc_errors++;
+ if (status & RxLenCntExp) dev->stats.rx_length_errors++;
+ if (status & RxOverFlow) dev->stats.rx_over_errors++;
+ if (status & RxAlignCntExp) dev->stats.rx_frame_errors++;
+
+ /* if (status & FrameSent) dev->stats.tx_dropped++; */
+ if (status & TxErrorMask) dev->stats.tx_errors++;
+ if (status & TxUnderrun) dev->stats.tx_fifo_errors++;
+ if (status & TxNormalCollExp) dev->stats.collisions++;
return IRQ_HANDLED;
}
@@ -1246,6 +1238,17 @@ static void bmac_reset_and_enable(struct net_device *dev)
}
spin_unlock_irqrestore(&bp->lock, flags);
}
+static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct bmac_data *bp = netdev_priv(dev);
+ strcpy(info->driver, "bmac");
+ strcpy(info->bus_info, bp->mdev->ofdev.dev.bus_id);
+}
+
+static const struct ethtool_ops bmac_ethtool_ops = {
+ .get_drvinfo = bmac_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
@@ -1255,6 +1258,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
unsigned char addr[6];
struct net_device *dev;
int is_bmac_plus = ((int)match->data) != 0;
+ DECLARE_MAC_BUF(mac);
if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
@@ -1279,7 +1283,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
}
bp = netdev_priv(dev);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
macio_set_drvdata(mdev, dev);
@@ -1311,8 +1314,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
dev->open = bmac_open;
dev->stop = bmac_close;
+ dev->ethtool_ops = &bmac_ethtool_ops;
dev->hard_start_xmit = bmac_output;
- dev->get_stats = bmac_stats;
dev->set_multicast_list = bmac_set_multicast;
dev->set_mac_address = bmac_set_address;
@@ -1365,9 +1368,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
goto err_out_irq2;
}
- printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
- for (j = 0; j < 6; ++j)
- printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+ printk(KERN_INFO "%s: BMAC%s at %s",
+ dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr));
XXDEBUG((", base_addr=%#0lx", dev->base_addr));
printk("\n");
@@ -1530,7 +1532,7 @@ static void bmac_tx_timeout(unsigned long data)
XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
bp->tx_empty, bp->tx_fill, bp->tx_fullup));
i = bp->tx_empty;
- ++bp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (i != bp->tx_fill) {
dev_kfree_skb(bp->tx_bufs[i]);
bp->tx_bufs[i] = NULL;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index d23861c8658c..78ed633ceb82 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -52,10 +52,12 @@
#include "bnx2_fw.h"
#include "bnx2_fw2.h"
+#define FW_BUF_SIZE 0x8000
+
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.6.2"
-#define DRV_MODULE_RELDATE "July 6, 2007"
+#define DRV_MODULE_VERSION "1.6.7"
+#define DRV_MODULE_RELDATE "October 10, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -126,91 +128,102 @@ static struct pci_device_id bnx2_pci_tbl[] = {
static struct flash_spec flash_table[] =
{
+#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
+#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
/* Slow EEPROM */
{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
- 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+ BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
"EEPROM - slow"},
/* Expansion entry 0001 */
{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0001"},
/* Saifun SA25F010 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
"Non-buffered flash (128kB)"},
/* Saifun SA25F020 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
"Non-buffered flash (256kB)"},
/* Expansion entry 0100 */
{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0100"},
/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
- 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
"Entry 0101: ST M45PE10 (128kB non-bufferred)"},
/* Entry 0110: ST M45PE20 (non-buffered flash)*/
{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
- 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
"Entry 0110: ST M45PE20 (256kB non-bufferred)"},
/* Saifun SA25F005 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
"Non-buffered flash (64kB)"},
/* Fast EEPROM */
{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
- 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+ BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
"EEPROM - fast"},
/* Expansion entry 1001 */
{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1001"},
/* Expansion entry 1010 */
{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1010"},
/* ATMEL AT45DB011B (buffered flash) */
{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
"Buffered flash (128kB)"},
/* Expansion entry 1100 */
{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1100"},
/* Expansion entry 1101 */
{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1101"},
/* Ateml Expansion entry 1110 */
{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1110 (Atmel)"},
/* ATMEL AT45DB021B (buffered flash) */
{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
"Buffered flash (256kB)"},
};
+static struct flash_spec flash_5709 = {
+ .flags = BNX2_NV_BUFFERED,
+ .page_bits = BCM5709_FLASH_PAGE_BITS,
+ .page_size = BCM5709_FLASH_PAGE_SIZE,
+ .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
+ .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
+ .name = "5709 Buffered flash (256kB)",
+};
+
MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
static inline u32 bnx2_tx_avail(struct bnx2 *bp)
@@ -417,7 +430,7 @@ bnx2_netif_stop(struct bnx2 *bp)
{
bnx2_disable_int_sync(bp);
if (netif_running(bp->dev)) {
- netif_poll_disable(bp->dev);
+ napi_disable(&bp->napi);
netif_tx_disable(bp->dev);
bp->dev->trans_start = jiffies; /* prevent tx timeout */
}
@@ -429,7 +442,7 @@ bnx2_netif_start(struct bnx2 *bp)
if (atomic_dec_and_test(&bp->intr_sem)) {
if (netif_running(bp->dev)) {
netif_wake_queue(bp->dev);
- netif_poll_enable(bp->dev);
+ napi_enable(&bp->napi);
bnx2_enable_int(bp);
}
}
@@ -2540,7 +2553,7 @@ bnx2_msi(int irq, void *dev_instance)
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &bp->napi);
return IRQ_HANDLED;
}
@@ -2557,7 +2570,7 @@ bnx2_msi_1shot(int irq, void *dev_instance)
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &bp->napi);
return IRQ_HANDLED;
}
@@ -2593,9 +2606,9 @@ bnx2_interrupt(int irq, void *dev_instance)
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
bp->last_status_idx = sblk->status_idx;
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
}
return IRQ_HANDLED;
@@ -2620,10 +2633,8 @@ bnx2_has_work(struct bnx2 *bp)
return 0;
}
-static int
-bnx2_poll(struct net_device *dev, int *budget)
+static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
{
- struct bnx2 *bp = netdev_priv(dev);
struct status_block *sblk = bp->status_blk;
u32 status_attn_bits = sblk->status_attn_bits;
u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
@@ -2641,44 +2652,54 @@ bnx2_poll(struct net_device *dev, int *budget)
REG_RD(bp, BNX2_HC_COMMAND);
}
- if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+ if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
bnx2_tx_int(bp);
- if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
- int orig_budget = *budget;
- int work_done;
+ if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+ work_done += bnx2_rx_int(bp, budget - work_done);
- if (orig_budget > dev->quota)
- orig_budget = dev->quota;
+ return work_done;
+}
- work_done = bnx2_rx_int(bp, orig_budget);
- *budget -= work_done;
- dev->quota -= work_done;
- }
+static int bnx2_poll(struct napi_struct *napi, int budget)
+{
+ struct bnx2 *bp = container_of(napi, struct bnx2, napi);
+ int work_done = 0;
+ struct status_block *sblk = bp->status_blk;
- bp->last_status_idx = bp->status_blk->status_idx;
- rmb();
+ while (1) {
+ work_done = bnx2_poll_work(bp, work_done, budget);
+
+ if (unlikely(work_done >= budget))
+ break;
- if (!bnx2_has_work(bp)) {
- netif_rx_complete(dev);
- if (likely(bp->flags & USING_MSI_FLAG)) {
+ /* bp->last_status_idx is used below to tell the hw how
+ * much work has been processed, so we must read it before
+ * checking for more work.
+ */
+ bp->last_status_idx = sblk->status_idx;
+ rmb();
+ if (likely(!bnx2_has_work(bp))) {
+ netif_rx_complete(bp->dev, napi);
+ if (likely(bp->flags & USING_MSI_FLAG)) {
+ REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+ BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+ bp->last_status_idx);
+ break;
+ }
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+ BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
bp->last_status_idx);
- return 0;
- }
- REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
- BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
- BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
- bp->last_status_idx);
- REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
- BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
- bp->last_status_idx);
- return 0;
+ REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+ BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+ bp->last_status_idx);
+ break;
+ }
}
- return 1;
+ return work_done;
}
/* Called with rtnl_lock from vlan functions and also netif_tx_lock
@@ -2756,92 +2777,6 @@ bnx2_set_rx_mode(struct net_device *dev)
spin_unlock_bh(&bp->phy_lock);
}
-#define FW_BUF_SIZE 0x8000
-
-static int
-bnx2_gunzip_init(struct bnx2 *bp)
-{
- if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
- goto gunzip_nomem1;
-
- if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
- goto gunzip_nomem2;
-
- bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
- if (bp->strm->workspace == NULL)
- goto gunzip_nomem3;
-
- return 0;
-
-gunzip_nomem3:
- kfree(bp->strm);
- bp->strm = NULL;
-
-gunzip_nomem2:
- vfree(bp->gunzip_buf);
- bp->gunzip_buf = NULL;
-
-gunzip_nomem1:
- printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
- "uncompression.\n", bp->dev->name);
- return -ENOMEM;
-}
-
-static void
-bnx2_gunzip_end(struct bnx2 *bp)
-{
- kfree(bp->strm->workspace);
-
- kfree(bp->strm);
- bp->strm = NULL;
-
- if (bp->gunzip_buf) {
- vfree(bp->gunzip_buf);
- bp->gunzip_buf = NULL;
- }
-}
-
-static int
-bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
-{
- int n, rc;
-
- /* check gzip header */
- if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
- return -EINVAL;
-
- n = 10;
-
-#define FNAME 0x8
- if (zbuf[3] & FNAME)
- while ((zbuf[n++] != 0) && (n < len));
-
- bp->strm->next_in = zbuf + n;
- bp->strm->avail_in = len - n;
- bp->strm->next_out = bp->gunzip_buf;
- bp->strm->avail_out = FW_BUF_SIZE;
-
- rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
- if (rc != Z_OK)
- return rc;
-
- rc = zlib_inflate(bp->strm, Z_FINISH);
-
- *outlen = FW_BUF_SIZE - bp->strm->avail_out;
- *outbuf = bp->gunzip_buf;
-
- if ((rc != Z_OK) && (rc != Z_STREAM_END))
- printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
- bp->dev->name, bp->strm->msg);
-
- zlib_inflateEnd(bp->strm);
-
- if (rc == Z_STREAM_END)
- return 0;
-
- return rc;
-}
-
static void
load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
u32 rv2p_proc)
@@ -2891,19 +2826,13 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
/* Load the Text area. */
offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
if (fw->gz_text) {
- u32 text_len;
- void *text;
+ int j;
- rc = bnx2_gunzip(bp, fw->gz_text, fw->gz_text_len, &text,
- &text_len);
- if (rc)
+ rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
+ fw->gz_text_len);
+ if (rc < 0)
return rc;
- fw->text = text;
- }
- if (fw->gz_text) {
- int j;
-
for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
}
@@ -2921,21 +2850,21 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
/* Load the SBSS area. */
offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
- if (fw->sbss) {
+ if (fw->sbss_len) {
int j;
for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
- REG_WR_IND(bp, offset, fw->sbss[j]);
+ REG_WR_IND(bp, offset, 0);
}
}
/* Load the BSS area. */
offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
- if (fw->bss) {
+ if (fw->bss_len) {
int j;
for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
- REG_WR_IND(bp, offset, fw->bss[j]);
+ REG_WR_IND(bp, offset, 0);
}
}
@@ -2968,27 +2897,24 @@ bnx2_init_cpus(struct bnx2 *bp)
{
struct cpu_reg cpu_reg;
struct fw_info *fw;
- int rc = 0;
+ int rc;
void *text;
- u32 text_len;
-
- if ((rc = bnx2_gunzip_init(bp)) != 0)
- return rc;
/* Initialize the RV2P processor. */
- rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
- &text_len);
- if (rc)
+ text = vmalloc(FW_BUF_SIZE);
+ if (!text)
+ return -ENOMEM;
+ rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1));
+ if (rc < 0)
goto init_cpu_err;
- load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
+ load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
- rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
- &text_len);
- if (rc)
+ rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2));
+ if (rc < 0)
goto init_cpu_err;
- load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
+ load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
/* Initialize the RX Processor. */
cpu_reg.mode = BNX2_RXP_CPU_MODE;
@@ -3009,6 +2935,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_rxp_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3032,6 +2959,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_txp_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3055,6 +2983,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_tpat_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3078,6 +3007,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_com_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3099,12 +3029,13 @@ bnx2_init_cpus(struct bnx2 *bp)
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
fw = &bnx2_cp_fw_09;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
}
init_cpu_err:
- bnx2_gunzip_end(bp);
+ vfree(text);
return rc;
}
@@ -3289,7 +3220,7 @@ bnx2_enable_nvram_write(struct bnx2 *bp)
val = REG_RD(bp, BNX2_MISC_CFG);
REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
- if (!bp->flash_info->buffered) {
+ if (bp->flash_info->flags & BNX2_NV_WREN) {
int j;
REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
@@ -3349,7 +3280,7 @@ bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
u32 cmd;
int j;
- if (bp->flash_info->buffered)
+ if (bp->flash_info->flags & BNX2_NV_BUFFERED)
/* Buffered flash, no erase needed */
return 0;
@@ -3392,8 +3323,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
/* Build the command word. */
cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
- /* Calculate an offset of a buffered flash. */
- if (bp->flash_info->buffered) {
+ /* Calculate an offset of a buffered flash, not needed for 5709. */
+ if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
offset = ((offset / bp->flash_info->page_size) <<
bp->flash_info->page_bits) +
(offset % bp->flash_info->page_size);
@@ -3439,8 +3370,8 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
/* Build the command word. */
cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
- /* Calculate an offset of a buffered flash. */
- if (bp->flash_info->buffered) {
+ /* Calculate an offset of a buffered flash, not needed for 5709. */
+ if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
offset = ((offset / bp->flash_info->page_size) <<
bp->flash_info->page_bits) +
(offset % bp->flash_info->page_size);
@@ -3478,15 +3409,19 @@ static int
bnx2_init_nvram(struct bnx2 *bp)
{
u32 val;
- int j, entry_count, rc;
+ int j, entry_count, rc = 0;
struct flash_spec *flash;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ bp->flash_info = &flash_5709;
+ goto get_flash_size;
+ }
+
/* Determine the selected interface. */
val = REG_RD(bp, BNX2_NVM_CFG1);
- entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
+ entry_count = ARRAY_SIZE(flash_table);
- rc = 0;
if (val & 0x40000000) {
/* Flash interface has been reconfigured */
@@ -3542,6 +3477,7 @@ bnx2_init_nvram(struct bnx2 *bp)
return -ENODEV;
}
+get_flash_size:
val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
if (val)
@@ -3706,7 +3642,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
buf = align_buf;
}
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
flash_buffer = kmalloc(264, GFP_KERNEL);
if (flash_buffer == NULL) {
rc = -ENOMEM;
@@ -3739,7 +3675,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
bnx2_enable_nvram_access(bp);
cmd_flags = BNX2_NVM_COMMAND_FIRST;
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
int j;
/* Read the whole page into the buffer
@@ -3767,7 +3703,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Loop to write back the buffer data from page_start to
* data_start */
i = 0;
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
/* Erase the page */
if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
goto nvram_write_end;
@@ -3791,7 +3727,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Loop to write the new data from data_start to data_end */
for (addr = data_start; addr < data_end; addr += 4, i += 4) {
if ((addr == page_end - 4) ||
- ((bp->flash_info->buffered) &&
+ ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
(addr == data_end - 4))) {
cmd_flags |= BNX2_NVM_COMMAND_LAST;
@@ -3808,7 +3744,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Loop to write back the buffer data from data_end
* to page_end */
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
for (addr = data_end; addr < page_end;
addr += 4, i += 4) {
@@ -3856,12 +3792,6 @@ bnx2_init_remote_phy(struct bnx2 *bp)
return;
if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
- if (netif_running(bp->dev)) {
- val = BNX2_DRV_ACK_CAP_SIGNATURE |
- BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
- REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
- val);
- }
bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
@@ -3869,6 +3799,22 @@ bnx2_init_remote_phy(struct bnx2 *bp)
bp->phy_port = PORT_FIBRE;
else
bp->phy_port = PORT_TP;
+
+ 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;
+ REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
+ sig);
+ }
}
}
@@ -3877,6 +3823,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
{
u32 val;
int i, rc = 0;
+ u8 old_port;
/* Wait for the current PCI transaction to complete before
* issuing a reset. */
@@ -3918,11 +3865,13 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
/* Chip reset. */
REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
+ /* Reading back any register after chip reset will hang the
+ * bus on 5706 A0 and A1. The msleep below provides plenty
+ * of margin for write posting.
+ */
if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
- (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(HZ / 50);
- }
+ (CHIP_ID(bp) == CHIP_ID_5706_A1))
+ msleep(20);
/* Reset takes approximate 30 usec */
for (i = 0; i < 10; i++) {
@@ -3953,8 +3902,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
return rc;
spin_lock_bh(&bp->phy_lock);
+ old_port = bp->phy_port;
bnx2_init_remote_phy(bp);
- if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port)
bnx2_set_default_remote_link(bp);
spin_unlock_bh(&bp->phy_lock);
@@ -4107,7 +4057,7 @@ bnx2_init_chip(struct bnx2 *bp)
if (CHIP_NUM(bp) == CHIP_NUM_5708)
REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
else
- REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+ REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
if (CHIP_ID(bp) == CHIP_ID_5706_A1)
@@ -4127,10 +4077,6 @@ bnx2_init_chip(struct bnx2 *bp)
REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
- if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
- BNX2_PORT_FEATURE_ASF_ENABLED)
- bp->flags |= ASF_ENABLE_FLAG;
-
/* Initialize the receive filter. */
bnx2_set_rx_mode(bp->dev);
@@ -4647,6 +4593,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
bnx2_set_mac_loopback(bp);
}
else if (loopback_mode == BNX2_PHY_LOOPBACK) {
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return 0;
+
bp->loopback = PHY_LOOPBACK;
bnx2_set_phy_loopback(bp);
}
@@ -4815,6 +4764,11 @@ bnx2_test_link(struct bnx2 *bp)
{
u32 bmsr;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+ if (bp->link_up)
+ return 0;
+ return -ENODEV;
+ }
spin_lock_bh(&bp->phy_lock);
bnx2_enable_bmsr1(bp);
bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
@@ -5025,6 +4979,8 @@ bnx2_open(struct net_device *dev)
if (rc)
return rc;
+ napi_enable(&bp->napi);
+
if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
if (pci_enable_msi(bp->pdev) == 0) {
bp->flags |= USING_MSI_FLAG;
@@ -5035,6 +4991,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_request_irq(bp);
if (rc) {
+ napi_disable(&bp->napi);
bnx2_free_mem(bp);
return rc;
}
@@ -5042,6 +4999,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_init_nic(bp);
if (rc) {
+ napi_disable(&bp->napi);
bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
@@ -5074,6 +5032,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_request_irq(bp);
if (rc) {
+ napi_disable(&bp->napi);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
del_timer_sync(&bp->timer);
@@ -5287,7 +5246,8 @@ bnx2_close(struct net_device *dev)
while (bp->in_reset_task)
msleep(1);
- bnx2_netif_stop(bp);
+ bnx2_disable_int_sync(bp);
+ napi_disable(&bp->napi);
del_timer_sync(&bp->timer);
if (bp->flags & NO_WOL_FLAG)
reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
@@ -5786,8 +5746,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
bp->stats_ticks = USEC_PER_SEC;
}
- if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
- bp->stats_ticks &= 0xffff00;
+ if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
+ bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
+ bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
if (netif_running(bp->dev)) {
bnx2_netif_stop(bp);
@@ -6055,9 +6016,16 @@ static struct {
};
static int
-bnx2_self_test_count(struct net_device *dev)
+bnx2_get_sset_count(struct net_device *dev, int sset)
{
- return BNX2_NUM_TESTS;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return BNX2_NUM_TESTS;
+ case ETH_SS_STATS:
+ return BNX2_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -6131,12 +6099,6 @@ bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
}
-static int
-bnx2_get_stats_count(struct net_device *dev)
-{
- return BNX2_NUM_STATS;
-}
-
static void
bnx2_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
@@ -6244,19 +6206,14 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.set_pauseparam = bnx2_set_pauseparam,
.get_rx_csum = bnx2_get_rx_csum,
.set_rx_csum = bnx2_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = bnx2_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = bnx2_set_tso,
- .self_test_count = bnx2_self_test_count,
.self_test = bnx2_self_test,
.get_strings = bnx2_get_strings,
.phys_id = bnx2_phys_id,
- .get_stats_count = bnx2_get_stats_count,
.get_ethtool_stats = bnx2_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_sset_count = bnx2_get_sset_count,
};
/* Called with rtnl_lock */
@@ -6462,7 +6419,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
u32 reg;
u64 dma_mask, persist_dma_mask;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
bp = netdev_priv(dev);
@@ -6629,6 +6585,21 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (i != 2)
bp->fw_version[j++] = '.';
}
+ reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE);
+ if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
+ bp->wol = 1;
+
+ if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
+ bp->flags |= ASF_ENABLE_FLAG;
+
+ for (i = 0; i < 30; i++) {
+ reg = REG_RD_IND(bp, bp->shmem_base +
+ BNX2_BC_STATE_CONDITION);
+ if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+ break;
+ msleep(10);
+ }
+ }
reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
reg &= BNX2_CONDITION_MFW_RUN_MASK;
if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
@@ -6672,7 +6643,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->rx_ticks_int = 18;
bp->rx_ticks = 18;
- bp->stats_ticks = 1000000 & 0xffff00;
+ bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
bp->timer_interval = HZ;
bp->current_interval = HZ;
@@ -6688,11 +6659,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->phy_port = PORT_TP;
if (bp->phy_flags & PHY_SERDES_FLAG) {
bp->phy_port = PORT_FIBRE;
- bp->flags |= NO_WOL_FLAG;
+ reg = REG_RD_IND(bp, bp->shmem_base +
+ BNX2_SHARED_HW_CFG_CONFIG);
+ if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
+ bp->flags |= NO_WOL_FLAG;
+ bp->wol = 0;
+ }
if (CHIP_NUM(bp) != CHIP_NUM_5706) {
bp->phy_addr = 2;
- reg = REG_RD_IND(bp, bp->shmem_base +
- BNX2_SHARED_HW_CFG_CONFIG);
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
}
@@ -6701,13 +6675,16 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
CHIP_NUM(bp) == CHIP_NUM_5708)
bp->phy_flags |= PHY_CRC_FIX_FLAG;
- else if (CHIP_ID(bp) == CHIP_ID_5709_A0)
+ else if (CHIP_ID(bp) == CHIP_ID_5709_A0 ||
+ CHIP_ID(bp) == CHIP_ID_5709_A1)
bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
(CHIP_ID(bp) == CHIP_ID_5708_B0) ||
- (CHIP_ID(bp) == CHIP_ID_5708_B1))
+ (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
bp->flags |= NO_WOL_FLAG;
+ bp->wol = 0;
+ }
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
bp->tx_quick_cons_trip_int =
@@ -6800,8 +6777,9 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
static int version_printed = 0;
struct net_device *dev = NULL;
struct bnx2 *bp;
- int rc, i;
+ int rc;
char str[40];
+ DECLARE_MAC_BUF(mac);
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -6831,11 +6809,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef BCM_VLAN
dev->vlan_rx_register = bnx2_vlan_rx_register;
#endif
- dev->poll = bnx2_poll;
dev->ethtool_ops = &bnx2_ethtool_ops;
- dev->weight = 64;
bp = netdev_priv(dev);
+ netif_napi_add(dev, &bp->napi, bnx2_poll, 64);
#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
dev->poll_controller = poll_bnx2;
@@ -6870,19 +6847,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
- "IRQ %d, ",
+ "IRQ %d, node addr %s\n",
dev->name,
bp->name,
((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
((CHIP_ID(bp) & 0x0ff0) >> 4),
bnx2_bus_string(bp, str),
dev->base_addr,
- bp->pdev->irq);
-
- printk("node addr ");
- for (i = 0; i < 6; i++)
- printk("%2.2x", dev->dev_addr[i]);
- printk("\n");
+ bp->pdev->irq, print_mac(mac, dev->dev_addr));
return 0;
}
@@ -6913,6 +6885,11 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
struct bnx2 *bp = netdev_priv(dev);
u32 reset_code;
+ /* PCI register 4 needs to be saved whether netif_running() or not.
+ * MSI address and data need to be saved if using MSI and
+ * netif_running().
+ */
+ pci_save_state(pdev);
if (!netif_running(dev))
return 0;
@@ -6928,7 +6905,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
bnx2_reset_chip(bp, reset_code);
bnx2_free_skbs(bp);
- pci_save_state(pdev);
bnx2_set_power_state(bp, pci_choose_state(pdev, state));
return 0;
}
@@ -6939,10 +6915,10 @@ bnx2_resume(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct bnx2 *bp = netdev_priv(dev);
+ pci_restore_state(pdev);
if (!netif_running(dev))
return 0;
- pci_restore_state(pdev);
bnx2_set_power_state(bp, PCI_D0);
netif_device_attach(dev);
bnx2_init_nic(bp);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index d8cd1afeb23d..1dce0d1a2581 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6433,6 +6433,11 @@ struct sw_bd {
#define ST_MICRO_FLASH_PAGE_SIZE 256
#define ST_MICRO_FLASH_BASE_TOTAL_SIZE 65536
+#define BCM5709_FLASH_PAGE_BITS 8
+#define BCM5709_FLASH_PHY_PAGE_SIZE (1 << BCM5709_FLASH_PAGE_BITS)
+#define BCM5709_FLASH_BYTE_ADDR_MASK (BCM5709_FLASH_PHY_PAGE_SIZE-1)
+#define BCM5709_FLASH_PAGE_SIZE 256
+
#define NVRAM_TIMEOUT_COUNT 30000
@@ -6449,7 +6454,10 @@ struct flash_spec {
u32 config2;
u32 config3;
u32 write1;
- u32 buffered;
+ u32 flags;
+#define BNX2_NV_BUFFERED 0x00000001
+#define BNX2_NV_TRANSLATE 0x00000002
+#define BNX2_NV_WREN 0x00000004
u32 page_bits;
u32 page_size;
u32 addr_mask;
@@ -6465,6 +6473,8 @@ struct bnx2 {
struct net_device *dev;
struct pci_dev *pdev;
+ struct napi_struct napi;
+
atomic_t intr_sem;
struct status_block *status_blk;
@@ -6671,9 +6681,6 @@ struct bnx2 {
u32 flash_size;
int status_stats_size;
-
- struct z_stream_s *strm;
- void *gunzip_buf;
};
static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
@@ -6745,13 +6752,11 @@ struct fw_info {
const u32 sbss_addr;
const u32 sbss_len;
const u32 sbss_index;
- const u32 *sbss;
/* BSS section. */
const u32 bss_addr;
const u32 bss_len;
const u32 bss_index;
- const u32 *bss;
/* Read-only section. */
const u32 rodata_addr;
@@ -6903,6 +6908,7 @@ struct fw_info {
#define BNX2_SHARED_HW_CFG_LED_MODE_MAC 0
#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1 0x100
#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2 0x200
+#define BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX 0x8000
#define BNX2_SHARED_HW_CFG_CONFIG2 0x00000040
#define BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK 0x00fff000
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index b49f439e0f67..a6d78243163b 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -15,7 +15,8 @@
*/
static u8 bnx2_COM_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */
+ 0xdc, 0x5a,
0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15,
0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96,
0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1,
@@ -1047,8 +1048,6 @@ static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = {
0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc,
0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140,
0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 };
-static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 };
static struct fw_info bnx2_com_fw_06 = {
.ver_major = 0x3,
@@ -1071,12 +1070,10 @@ static struct fw_info bnx2_com_fw_06 = {
.sbss_addr = 0x08007e00,
.sbss_len = 0x60,
.sbss_index = 0x0,
- .sbss = bnx2_COM_b06FwSbss,
.bss_addr = 0x08007e60,
.bss_len = 0x88,
.bss_index = 0x0,
- .bss = bnx2_COM_b06FwBss,
.rodata_addr = 0x08007d58,
.rodata_len = 0x88,
@@ -1085,8 +1082,9 @@ static struct fw_info bnx2_com_fw_06 = {
};
static u8 bnx2_RXP_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6f, 0x6c,
+/* 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xec, 0x5c, 0x6f, 0x6c,
0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e,
0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d,
0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a,
@@ -1760,9 +1758,6 @@ static u32 bnx2_RXP_b06FwRodata[(0x278/4) + 1] = {
0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030,
0x08006024, 0x00000000, 0x00000000 };
-static u32 bnx2_RXP_b06FwBss[(0x13dc/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b06FwSbss[(0x2c/4) + 1] = { 0x0 };
-
static struct fw_info bnx2_rxp_fw_06 = {
.ver_major = 0x2,
.ver_minor = 0x8,
@@ -1784,12 +1779,10 @@ static struct fw_info bnx2_rxp_fw_06 = {
.sbss_addr = 0x080069c0,
.sbss_len = 0x2c,
.sbss_index = 0x0,
- .sbss = bnx2_RXP_b06FwSbss,
.bss_addr = 0x080069f0,
.bss_len = 0x13dc,
.bss_index = 0x0,
- .bss = bnx2_RXP_b06FwBss,
.rodata_addr = 0x08006728,
.rodata_len = 0x278,
@@ -1798,8 +1791,9 @@ static struct fw_info bnx2_rxp_fw_06 = {
};
static u8 bnx2_rv2p_proc1[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x56, 0xcf, 0x6b,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xc5, 0x56, 0xcf, 0x6b,
0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b,
0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82,
0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a,
@@ -1877,8 +1871,9 @@ static u8 bnx2_rv2p_proc1[] = {
0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 };
static u8 bnx2_rv2p_proc2[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x58, 0x5b, 0x6c,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xcd, 0x58, 0x5b, 0x6c,
0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2,
0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18,
0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda,
@@ -2057,8 +2052,9 @@ static u8 bnx2_rv2p_proc2[] = {
0x17, 0x00, 0x00, 0x00 };
static u8 bnx2_TPAT_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x57, 0x4d, 0x68,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xc5, 0x57, 0x4d, 0x68,
0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d,
0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5,
0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08,
@@ -2252,8 +2248,6 @@ static u8 bnx2_TPAT_b06FwText[] = {
static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 };
static struct fw_info bnx2_tpat_fw_06 = {
.ver_major = 0x1,
@@ -2276,12 +2270,10 @@ static struct fw_info bnx2_tpat_fw_06 = {
.sbss_addr = 0x08001a60,
.sbss_len = 0x34,
.sbss_index = 0x0,
- .sbss = bnx2_TPAT_b06FwSbss,
.bss_addr = 0x08001aa0,
.bss_len = 0x250,
.bss_index = 0x0,
- .bss = bnx2_TPAT_b06FwBss,
.rodata_addr = 0x00000000,
.rodata_len = 0x0,
@@ -2290,8 +2282,9 @@ static struct fw_info bnx2_tpat_fw_06 = {
};
static u8 bnx2_TXP_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x6d, 0x6c,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xed, 0x5c, 0x6d, 0x6c,
0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2,
0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05,
0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71,
@@ -2708,8 +2701,6 @@ static u8 bnx2_TXP_b06FwText[] = {
static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 };
static struct fw_info bnx2_txp_fw_06 = {
.ver_major = 0x1,
@@ -2732,12 +2723,10 @@ static struct fw_info bnx2_txp_fw_06 = {
.sbss_addr = 0x08005760,
.sbss_len = 0x38,
.sbss_index = 0x0,
- .sbss = bnx2_TXP_b06FwSbss,
.bss_addr = 0x080057a0,
.bss_len = 0x1c4,
.bss_index = 0x0,
- .bss = bnx2_TXP_b06FwBss,
.rodata_addr = 0x00000000,
.rodata_len = 0x0,
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index 2c067531f031..5bd52bead9bf 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -15,7 +15,8 @@
*/
static u8 bnx2_COM_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+ 0xdc, 0x5b,
0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92,
0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0,
0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c,
@@ -1045,8 +1046,6 @@ static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c,
0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8,
0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 };
-static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 };
static struct fw_info bnx2_com_fw_09 = {
.ver_major = 0x3,
@@ -1069,12 +1068,10 @@ static struct fw_info bnx2_com_fw_09 = {
.sbss_addr = 0x08007e60,
.sbss_len = 0x60,
.sbss_index = 0x0,
- .sbss = bnx2_COM_b09FwSbss,
.bss_addr = 0x08007ec0,
.bss_len = 0x88,
.bss_index = 0x0,
- .bss = bnx2_COM_b09FwBss,
.rodata_addr = 0x08007dc0,
.rodata_len = 0x88,
@@ -1083,7 +1080,8 @@ static struct fw_info bnx2_com_fw_09 = {
};
static u8 bnx2_CP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+ 0xbd, 0x7d,
0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59,
0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22,
0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12,
@@ -2241,8 +2239,6 @@ static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338,
0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc,
0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 };
-static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 };
-static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 };
static struct fw_info bnx2_cp_fw_09 = {
.ver_major = 0x3,
@@ -2265,12 +2261,10 @@ static struct fw_info bnx2_cp_fw_09 = {
.sbss_addr = 0x08007024,
.sbss_len = 0xa1,
.sbss_index = 0x0,
- .sbss = bnx2_CP_b09FwSbss,
.bss_addr = 0x080070d0,
.bss_len = 0x3b0,
.bss_index = 0x0,
- .bss = bnx2_CP_b09FwBss,
.rodata_addr = 0x08006ee8,
.rodata_len = 0x118,
@@ -2279,7 +2273,8 @@ static struct fw_info bnx2_cp_fw_09 = {
};
static u8 bnx2_RXP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+ 0xec, 0x5c,
0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67,
0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a,
0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1,
@@ -2950,8 +2945,6 @@ static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070,
0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
0x08006064, 0x00000000, 0x00000000 };
-static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
-static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 };
static struct fw_info bnx2_rxp_fw_09 = {
.ver_major = 0x3,
@@ -2974,12 +2967,10 @@ static struct fw_info bnx2_rxp_fw_09 = {
.sbss_addr = 0x08006a00,
.sbss_len = 0x20,
.sbss_index = 0x0,
- .sbss = bnx2_RXP_b09FwSbss,
.bss_addr = 0x08006a20,
.bss_len = 0x13dc,
.bss_index = 0x0,
- .bss = bnx2_RXP_b09FwBss,
.rodata_addr = 0x08006768,
.rodata_len = 0x278,
@@ -2988,7 +2979,8 @@ static struct fw_info bnx2_rxp_fw_09 = {
};
static u8 bnx2_TPAT_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+ 0xcd, 0x58,
0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb,
0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13,
0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c,
@@ -3241,8 +3233,6 @@ static u8 bnx2_TPAT_b09FwText[] = {
static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
static struct fw_info bnx2_tpat_fw_09 = {
.ver_major = 0x3,
@@ -3265,12 +3255,10 @@ static struct fw_info bnx2_tpat_fw_09 = {
.sbss_addr = 0x08002088,
.sbss_len = 0x2c,
.sbss_index = 0x0,
- .sbss = bnx2_TPAT_b09FwSbss,
.bss_addr = 0x080020c0,
.bss_len = 0x850,
.bss_index = 0x0,
- .bss = bnx2_TPAT_b09FwBss,
.rodata_addr = 0x00000000,
.rodata_len = 0x0,
@@ -3279,7 +3267,8 @@ static struct fw_info bnx2_tpat_fw_09 = {
};
static u8 bnx2_TXP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+ 0xcd, 0x7c,
0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1,
0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42,
0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48,
@@ -4055,8 +4044,6 @@ static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c,
0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000,
0x00000000 };
-static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
-static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 };
static struct fw_info bnx2_txp_fw_09 = {
.ver_major = 0x3,
@@ -4079,12 +4066,10 @@ static struct fw_info bnx2_txp_fw_09 = {
.sbss_addr = 0x08004750,
.sbss_len = 0x8c,
.sbss_index = 0x0,
- .sbss = bnx2_TXP_b09FwSbss,
.bss_addr = 0x080047e0,
.bss_len = 0xa20,
.bss_index = 0x0,
- .bss = bnx2_TXP_b09FwBss,
.rodata_addr = 0x08004638,
.rodata_len = 0x30,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index f829e4ad8b49..7a045a37056e 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -29,6 +29,7 @@
#include <linux/ethtool.h>
#include <linux/if_bonding.h>
#include <linux/pkt_sched.h>
+#include <net/net_namespace.h>
#include "bonding.h"
#include "bond_3ad.h"
@@ -100,7 +101,6 @@ static u16 __get_link_speed(struct port *port);
static u8 __get_duplex(struct port *port);
static inline void __initialize_port_locks(struct port *port);
//conversions
-static void __htons_lacpdu(struct lacpdu *lacpdu);
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
@@ -419,26 +419,6 @@ static inline void __initialize_port_locks(struct port *port)
}
//conversions
-/**
- * __htons_lacpdu - convert the contents of a LACPDU to network byte order
- * @lacpdu: the speicifed lacpdu
- *
- * For each multi-byte field in the lacpdu, convert its content
- */
-static void __htons_lacpdu(struct lacpdu *lacpdu)
-{
- if (lacpdu) {
- lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
- lacpdu->actor_key = htons(lacpdu->actor_key);
- lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
- lacpdu->actor_port = htons(lacpdu->actor_port);
- lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
- lacpdu->partner_key = htons(lacpdu->partner_key);
- lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
- lacpdu->partner_port = htons(lacpdu->partner_port);
- lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
- }
-}
/**
* __ad_timer_to_ticks - convert a given timer type to AD module ticks
@@ -826,11 +806,11 @@ static inline void __update_lacpdu_from_port(struct port *port)
* lacpdu->actor_information_length initialized
*/
- lacpdu->actor_system_priority = port->actor_system_priority;
+ lacpdu->actor_system_priority = htons(port->actor_system_priority);
lacpdu->actor_system = port->actor_system;
- lacpdu->actor_key = port->actor_oper_port_key;
- lacpdu->actor_port_priority = port->actor_port_priority;
- lacpdu->actor_port = port->actor_port_number;
+ lacpdu->actor_key = htons(port->actor_oper_port_key);
+ lacpdu->actor_port_priority = htons(port->actor_port_priority);
+ lacpdu->actor_port = htons(port->actor_port_number);
lacpdu->actor_state = port->actor_oper_port_state;
/* lacpdu->reserved_3_1 initialized
@@ -838,11 +818,11 @@ static inline void __update_lacpdu_from_port(struct port *port)
* lacpdu->partner_information_length initialized
*/
- lacpdu->partner_system_priority = port->partner_oper_system_priority;
+ lacpdu->partner_system_priority = htons(port->partner_oper_system_priority);
lacpdu->partner_system = port->partner_oper_system;
- lacpdu->partner_key = port->partner_oper_key;
- lacpdu->partner_port_priority = port->partner_oper_port_priority;
- lacpdu->partner_port = port->partner_oper_port_number;
+ lacpdu->partner_key = htons(port->partner_oper_key);
+ lacpdu->partner_port_priority = htons(port->partner_oper_port_priority);
+ lacpdu->partner_port = htons(port->partner_oper_port_number);
lacpdu->partner_state = port->partner_oper_port_state;
/* lacpdu->reserved_3_2 initialized
@@ -854,9 +834,6 @@ static inline void __update_lacpdu_from_port(struct port *port)
* terminator_length initialized
* reserved_50[50] initialized
*/
-
- /* Convert all non u8 parameters to Big Endian for transmit */
- __htons_lacpdu(lacpdu);
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -1833,7 +1810,7 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu)
}
lacpdu->tlv_type_collector_info = 0x03;
lacpdu->collector_information_length= 0x10;
- lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY;
+ lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY);
for (index=0; index<=11; index++) {
lacpdu->reserved_12[index]=0;
}
@@ -2448,6 +2425,9 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
struct slave *slave = NULL;
int ret = NET_RX_DROP;
+ if (dev->nd_net != &init_net)
+ goto out;
+
if (!(dev->flags & IFF_MASTER))
goto out;
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 6ad5ad6e65d5..862952fa6fd9 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -108,7 +108,7 @@ typedef enum {
typedef struct ad_header {
struct mac_addr destination_address;
struct mac_addr source_address;
- u16 length_type;
+ __be16 length_type;
} ad_header_t;
// Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
@@ -117,25 +117,25 @@ typedef struct lacpdu {
u8 version_number;
u8 tlv_type_actor_info; // = actor information(type/length/value)
u8 actor_information_length; // = 20
- u16 actor_system_priority;
+ __be16 actor_system_priority;
struct mac_addr actor_system;
- u16 actor_key;
- u16 actor_port_priority;
- u16 actor_port;
+ __be16 actor_key;
+ __be16 actor_port_priority;
+ __be16 actor_port;
u8 actor_state;
u8 reserved_3_1[3]; // = 0
u8 tlv_type_partner_info; // = partner information
u8 partner_information_length; // = 20
- u16 partner_system_priority;
+ __be16 partner_system_priority;
struct mac_addr partner_system;
- u16 partner_key;
- u16 partner_port_priority;
- u16 partner_port;
+ __be16 partner_key;
+ __be16 partner_port_priority;
+ __be16 partner_port;
u8 partner_state;
u8 reserved_3_2[3]; // = 0
u8 tlv_type_collector_info; // = collector information
u8 collector_information_length; // = 16
- u16 collector_max_delay;
+ __be16 collector_max_delay;
u8 reserved_12[12];
u8 tlv_type_terminator; // = terminator
u8 terminator_length; // = 0
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 92c3b6f6a8e7..aea2217c56eb 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -87,20 +87,20 @@ static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
struct learning_pkt {
u8 mac_dst[ETH_ALEN];
u8 mac_src[ETH_ALEN];
- u16 type;
+ __be16 type;
u8 padding[ETH_ZLEN - ETH_HLEN];
};
struct arp_pkt {
- u16 hw_addr_space;
- u16 prot_addr_space;
+ __be16 hw_addr_space;
+ __be16 prot_addr_space;
u8 hw_addr_len;
u8 prot_addr_len;
- u16 op_code;
+ __be16 op_code;
u8 mac_src[ETH_ALEN]; /* sender hardware address */
- u32 ip_src; /* sender IP address */
+ __be32 ip_src; /* sender IP address */
u8 mac_dst[ETH_ALEN]; /* target hardware address */
- u32 ip_dst; /* target IP address */
+ __be32 ip_dst; /* target IP address */
};
#pragma pack()
@@ -345,6 +345,9 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
struct arp_pkt *arp = (struct arp_pkt *)skb->data;
int res = NET_RX_DROP;
+ if (bond_dev->nd_net != &init_net)
+ goto out;
+
if (!(bond_dev->flags & IFF_MASTER))
goto out;
@@ -579,7 +582,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
}
/* mark all clients using src_ip to be updated */
-static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
+static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct rlb_client_info *client_info;
@@ -1264,7 +1267,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
struct ethhdr *eth_data;
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *tx_slave = NULL;
- static const u32 ip_bcast = 0xffffffff;
+ static const __be32 ip_bcast = htonl(0xffffffff);
int hash_size = 0;
int do_tx_balance = 1;
u32 hash_index = 0;
@@ -1308,8 +1311,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
hash_size = sizeof(ipv6_hdr(skb)->daddr);
break;
case ETH_P_IPX:
- if (ipx_hdr(skb)->ipx_checksum !=
- __constant_htons(IPX_NO_CHECKSUM)) {
+ if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
/* something is wrong with this packet */
do_tx_balance = 0;
break;
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 28f2a2fd1b5a..fd8726429890 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -60,8 +60,8 @@ struct tlb_client_info {
* -------------------------------------------------------------------------
*/
struct rlb_client_info {
- u32 ip_src; /* the server IP address */
- u32 ip_dst; /* the client IP address */
+ __be32 ip_src; /* the server IP address */
+ __be32 ip_dst; /* the client IP address */
u8 mac_dst[ETH_ALEN]; /* the client MAC address */
u32 next; /* The next Hash table entry index */
u32 prev; /* The previous Hash table entry index */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index cb9cb3013f42..64bfec32e2a6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -75,6 +75,7 @@
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
#include <net/route.h>
+#include <net/net_namespace.h>
#include "bonding.h"
#include "bond_3ad.h"
#include "bond_alb.h"
@@ -143,7 +144,7 @@ static struct proc_dir_entry *bond_proc_dir = NULL;
#endif
extern struct rw_semaphore bonding_rwsem;
-static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
+static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
static int arp_ip_count = 0;
static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
@@ -613,38 +614,20 @@ down:
static int bond_update_speed_duplex(struct slave *slave)
{
struct net_device *slave_dev = slave->dev;
- static int (* ioctl)(struct net_device *, struct ifreq *, int);
- struct ifreq ifr;
struct ethtool_cmd etool;
+ int res;
/* Fake speed and duplex */
slave->speed = SPEED_100;
slave->duplex = DUPLEX_FULL;
- if (slave_dev->ethtool_ops) {
- int res;
-
- if (!slave_dev->ethtool_ops->get_settings) {
- return -1;
- }
-
- res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
- if (res < 0) {
- return -1;
- }
-
- goto verify;
- }
+ if (!slave_dev->ethtool_ops || !slave_dev->ethtool_ops->get_settings)
+ return -1;
- ioctl = slave_dev->do_ioctl;
- strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
- etool.cmd = ETHTOOL_GSET;
- ifr.ifr_data = (char*)&etool;
- if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) {
+ res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
+ if (res < 0)
return -1;
- }
-verify:
switch (etool.speed) {
case SPEED_10:
case SPEED_100:
@@ -690,7 +673,6 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de
static int (* ioctl)(struct net_device *, struct ifreq *, int);
struct ifreq ifr;
struct mii_ioctl_data *mii;
- struct ethtool_value etool;
if (bond->params.use_carrier) {
return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;
@@ -721,9 +703,10 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de
}
}
- /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
- /* for a period of time so we attempt to get link status */
- /* from it last if the above MII ioctls fail... */
+ /*
+ * Some drivers cache ETHTOOL_GLINK for a period of time so we only
+ * attempt to get link status from it if the above MII ioctls fail.
+ */
if (slave_dev->ethtool_ops) {
if (slave_dev->ethtool_ops->get_link) {
u32 link;
@@ -734,23 +717,9 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de
}
}
- if (ioctl) {
- strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
- etool.cmd = ETHTOOL_GLINK;
- ifr.ifr_data = (char*)&etool;
- if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {
- if (etool.data == 1) {
- return BMSR_LSTATUS;
- } else {
- dprintk("SIOCETHTOOL shows link down\n");
- return 0;
- }
- }
- }
-
/*
* If reporting, report that either there's no dev->do_ioctl,
- * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we
+ * or both SIOCGMIIREG and get_link failed (meaning that we
* cannot report link status). If not reporting, pretend
* we're ok.
*/
@@ -1234,43 +1203,35 @@ static int bond_sethwaddr(struct net_device *bond_dev,
return 0;
}
-#define BOND_INTERSECT_FEATURES \
- (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
+#define BOND_VLAN_FEATURES \
+ (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
+ NETIF_F_HW_VLAN_FILTER)
/*
* Compute the common dev->feature set available to all slaves. Some
- * feature bits are managed elsewhere, so preserve feature bits set on
- * master device that are not part of the examined set.
+ * feature bits are managed elsewhere, so preserve those feature bits
+ * on the master device.
*/
static int bond_compute_features(struct bonding *bond)
{
- unsigned long features = BOND_INTERSECT_FEATURES;
struct slave *slave;
struct net_device *bond_dev = bond->dev;
+ unsigned long features = bond_dev->features;
unsigned short max_hard_header_len = ETH_HLEN;
int i;
+ features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
+ features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
+ NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
+
bond_for_each_slave(bond, slave, i) {
- features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
+ features = netdev_compute_features(features,
+ slave->dev->features);
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
}
- if ((features & NETIF_F_SG) &&
- !(features & NETIF_F_ALL_CSUM))
- features &= ~NETIF_F_SG;
-
- /*
- * features will include NETIF_F_TSO (NETIF_F_UFO) iff all
- * slave devices support NETIF_F_TSO (NETIF_F_UFO), which
- * implies that all slaves also support scatter-gather
- * (NETIF_F_SG), which implies that features also includes
- * NETIF_F_SG. So no need to check whether we have an
- * illegal combination of NETIF_F_{TSO,UFO} and
- * !NETIF_F_SG
- */
-
- features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
+ features |= (bond_dev->features & BOND_VLAN_FEATURES);
bond_dev->features = features;
bond_dev->hard_header_len = max_hard_header_len;
@@ -1643,6 +1604,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
struct slave *slave, *oldcurrent;
struct sockaddr addr;
int mac_addr_differ;
+ DECLARE_MAC_BUF(mac);
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -1670,19 +1632,13 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
ETH_ALEN);
if (!mac_addr_differ && (bond->slave_cnt > 1)) {
printk(KERN_WARNING DRV_NAME
- ": %s: Warning: the permanent HWaddr of %s "
- "- %02X:%02X:%02X:%02X:%02X:%02X - is "
- "still in use by %s. Set the HWaddr of "
- "%s to a different address to avoid "
- "conflicts.\n",
+ ": %s: Warning: the permanent HWaddr of %s - "
+ "%s - is still in use by %s. "
+ "Set the HWaddr of %s to a different address "
+ "to avoid conflicts.\n",
bond_dev->name,
slave_dev->name,
- slave->perm_hwaddr[0],
- slave->perm_hwaddr[1],
- slave->perm_hwaddr[2],
- slave->perm_hwaddr[3],
- slave->perm_hwaddr[4],
- slave->perm_hwaddr[5],
+ print_mac(mac, slave->perm_hwaddr),
bond_dev->name,
slave_dev->name);
}
@@ -2270,7 +2226,7 @@ out:
}
-static u32 bond_glean_dev_ip(struct net_device *dev)
+static __be32 bond_glean_dev_ip(struct net_device *dev)
{
struct in_device *idev;
struct in_ifaddr *ifa;
@@ -2313,7 +2269,7 @@ static int bond_has_ip(struct bonding *bond)
return 0;
}
-static int bond_has_this_ip(struct bonding *bond, u32 ip)
+static int bond_has_this_ip(struct bonding *bond, __be32 ip)
{
struct vlan_entry *vlan, *vlan_next;
@@ -2337,7 +2293,7 @@ static int bond_has_this_ip(struct bonding *bond, u32 ip)
* switches in VLAN mode (especially if ports are configured as
* "native" to a VLAN) might not pass non-tagged frames.
*/
-static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id)
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id)
{
struct sk_buff *skb;
@@ -2365,7 +2321,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip,
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
int i, vlan_id, rv;
- u32 *targets = bond->params.arp_targets;
+ __be32 *targets = bond->params.arp_targets;
struct vlan_entry *vlan, *vlan_next;
struct net_device *vlan_dev;
struct flowi fl;
@@ -2470,10 +2426,10 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
}
}
-static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip)
{
int i;
- u32 *targets = bond->params.arp_targets;
+ __be32 *targets = bond->params.arp_targets;
targets = bond->params.arp_targets;
for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
@@ -2495,7 +2451,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
struct slave *slave;
struct bonding *bond;
unsigned char *arp_ptr;
- u32 sip, tip;
+ __be32 sip, tip;
+
+ if (dev->nd_net != &init_net)
+ goto out;
if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
goto out;
@@ -3042,6 +3001,7 @@ static void bond_info_show_master(struct seq_file *seq)
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
+ DECLARE_MAC_BUF(mac);
seq_puts(seq, "\n802.3ad info\n");
seq_printf(seq, "LACP rate: %s\n",
@@ -3061,13 +3021,8 @@ static void bond_info_show_master(struct seq_file *seq)
ad_info.actor_key);
seq_printf(seq, "\tPartner Key: %d\n",
ad_info.partner_key);
- seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- ad_info.partner_system[0],
- ad_info.partner_system[1],
- ad_info.partner_system[2],
- ad_info.partner_system[3],
- ad_info.partner_system[4],
- ad_info.partner_system[5]);
+ seq_printf(seq, "\tPartner Mac Address: %s\n",
+ print_mac(mac, ad_info.partner_system));
}
}
}
@@ -3075,6 +3030,7 @@ static void bond_info_show_master(struct seq_file *seq)
static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave)
{
struct bonding *bond = seq->private;
+ DECLARE_MAC_BUF(mac);
seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
seq_printf(seq, "MII Status: %s\n",
@@ -3083,10 +3039,8 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave
slave->link_failure_count);
seq_printf(seq,
- "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
- slave->perm_hwaddr[0], slave->perm_hwaddr[1],
- slave->perm_hwaddr[2], slave->perm_hwaddr[3],
- slave->perm_hwaddr[4], slave->perm_hwaddr[5]);
+ "Permanent HW addr: %s\n",
+ print_mac(mac, slave->perm_hwaddr));
if (bond->params.mode == BOND_MODE_8023AD) {
const struct aggregator *agg
@@ -3184,7 +3138,7 @@ static void bond_create_proc_dir(void)
{
int len = strlen(DRV_NAME);
- for (bond_proc_dir = proc_net->subdir; bond_proc_dir;
+ for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir;
bond_proc_dir = bond_proc_dir->next) {
if ((bond_proc_dir->namelen == len) &&
!memcmp(bond_proc_dir->name, DRV_NAME, len)) {
@@ -3193,7 +3147,7 @@ static void bond_create_proc_dir(void)
}
if (!bond_proc_dir) {
- bond_proc_dir = proc_mkdir(DRV_NAME, proc_net);
+ bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net);
if (bond_proc_dir) {
bond_proc_dir->owner = THIS_MODULE;
} else {
@@ -3228,7 +3182,7 @@ static void bond_destroy_proc_dir(void)
bond_proc_dir->owner = NULL;
}
} else {
- remove_proc_entry(DRV_NAME, proc_net);
+ remove_proc_entry(DRV_NAME, init_net.proc_net);
bond_proc_dir = NULL;
}
}
@@ -3335,6 +3289,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
{
struct net_device *event_dev = (struct net_device *)ptr;
+ if (event_dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
dprintk("event_dev: %s, event: %lx\n",
(event_dev ? event_dev->name : "None"),
event);
@@ -3470,14 +3427,14 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
{
struct ethhdr *data = (struct ethhdr *)skb->data;
struct iphdr *iph = ip_hdr(skb);
- u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
+ __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
int layer4_xor = 0;
if (skb->protocol == __constant_htons(ETH_P_IP)) {
if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
(iph->protocol == IPPROTO_TCP ||
iph->protocol == IPPROTO_UDP)) {
- layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1)));
+ layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
}
return (layer4_xor ^
((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
@@ -3752,7 +3709,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
}
down_write(&(bonding_rwsem));
- slave_dev = dev_get_by_name(ifr->ifr_slave);
+ slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave);
dprintk("slave_dev=%p: \n", slave_dev);
@@ -4235,10 +4192,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
}
static const struct ethtool_ops bond_ethtool_ops = {
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_sg = ethtool_op_get_sg,
.get_drvinfo = bond_ethtool_get_drvinfo,
};
@@ -4568,7 +4521,7 @@ static int bond_check_params(struct bond_params *params)
arp_ip_target[arp_ip_count]);
arp_interval = 0;
} else {
- u32 ip = in_aton(arp_ip_target[arp_ip_count]);
+ __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
arp_target[arp_ip_count] = ip;
}
}
@@ -4707,8 +4660,6 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
goto out_netdev;
}
- SET_MODULE_OWNER(bond_dev);
-
res = register_netdevice(bond_dev);
if (res < 0) {
goto out_bond;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 60cccf2aa959..6f49ca7e9b66 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -31,10 +31,10 @@
#include <linux/inetdevice.h>
#include <linux/in.h>
#include <linux/sysfs.h>
-#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/rtnetlink.h>
+#include <net/net_namespace.h>
/* #define BONDING_DEBUG 1 */
#include "bonding.h"
@@ -299,7 +299,7 @@ static ssize_t bonding_store_slaves(struct device *d,
read_unlock_bh(&bond->lock);
printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",
bond->dev->name, ifname);
- dev = dev_get_by_name(ifname);
+ dev = dev_get_by_name(&init_net, ifname);
if (!dev) {
printk(KERN_INFO DRV_NAME
": %s: Interface %s does not exist!\n",
@@ -682,16 +682,16 @@ static ssize_t bonding_store_arp_targets(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
- u32 newtarget;
+ __be32 newtarget;
int i = 0, done = 0, ret = count;
struct bonding *bond = to_bond(d);
- u32 *targets;
+ __be32 *targets;
targets = bond->params.arp_targets;
newtarget = in_aton(buf + 1);
/* look for adds */
if (buf[0] == '+') {
- if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
+ if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
printk(KERN_ERR DRV_NAME
": %s: invalid ARP target %u.%u.%u.%u specified for addition\n",
bond->dev->name, NIPQUAD(newtarget));
@@ -727,7 +727,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
}
else if (buf[0] == '-') {
- if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
+ if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
printk(KERN_ERR DRV_NAME
": %s: invalid ARP target %d.%d.%d.%d specified for removal\n",
bond->dev->name, NIPQUAD(newtarget));
@@ -1361,17 +1361,14 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
{
int count = 0;
struct bonding *bond = to_bond(d);
+ DECLARE_MAC_BUF(mac);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
if (!bond_3ad_get_active_agg_info(bond, &ad_info)) {
- count = sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x\n",
- ad_info.partner_system[0],
- ad_info.partner_system[1],
- ad_info.partner_system[2],
- ad_info.partner_system[3],
- ad_info.partner_system[4],
- ad_info.partner_system[5]) + 1;
+ count = sprintf(buf,"%s\n",
+ print_mac(mac, ad_info.partner_system))
+ + 1;
}
}
else
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 6dcbd25e3ef0..2a6af7d23728 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -132,7 +132,7 @@ struct bond_params {
int downdelay;
int lacp_fast;
char primary[IFNAMSIZ];
- u32 arp_targets[BOND_MAX_ARP_TARGETS];
+ __be32 arp_targets[BOND_MAX_ARP_TARGETS];
};
struct bond_parm_tbl {
@@ -142,7 +142,7 @@ struct bond_parm_tbl {
struct vlan_entry {
struct list_head vlan_list;
- u32 vlan_ip;
+ __be32 vlan_ip;
unsigned short vlan_id;
};
@@ -193,7 +193,7 @@ struct bonding {
struct list_head bond_list;
struct dev_mc_list *mc_list;
int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
- u32 master_ip;
+ __be32 master_ip;
u16 flags;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
index 7845eaf6f29f..88edb986691a 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/bsd_comp.c
@@ -395,20 +395,18 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
* Allocate the main control structure for this instance.
*/
maxmaxcode = MAXCODE(bits);
- db = kmalloc(sizeof (struct bsd_db),
+ db = kzalloc(sizeof (struct bsd_db),
GFP_KERNEL);
if (!db)
{
return NULL;
}
- memset (db, 0, sizeof(struct bsd_db));
/*
* Allocate space for the dictionary. This may be more than one page in
* length.
*/
- db->dict = (struct bsd_dict *) vmalloc (hsize *
- sizeof (struct bsd_dict));
+ db->dict = vmalloc(hsize * sizeof(struct bsd_dict));
if (!db->dict)
{
bsd_free (db);
@@ -427,8 +425,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
*/
else
{
- db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
- sizeof (db->lens[0]));
+ db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0]));
if (!db->lens)
{
bsd_free (db);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index f6e4030c73d1..563bf5f6fa2a 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2485,7 +2485,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id)
if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
#ifdef USE_NAPI
cas_mask_intr(cp);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &cp->napi);
#else
cas_rx_ringN(cp, ring, 0);
#endif
@@ -2536,7 +2536,7 @@ static irqreturn_t cas_interrupt1(int irq, void *dev_id)
if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
#ifdef USE_NAPI
cas_mask_intr(cp);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &cp->napi);
#else
cas_rx_ringN(cp, 1, 0);
#endif
@@ -2592,7 +2592,7 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id)
if (status & INTR_RX_DONE) {
#ifdef USE_NAPI
cas_mask_intr(cp);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &cp->napi);
#else
cas_rx_ringN(cp, 0, 0);
#endif
@@ -2607,9 +2607,10 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id)
#ifdef USE_NAPI
-static int cas_poll(struct net_device *dev, int *budget)
+static int cas_poll(struct napi_struct *napi, int budget)
{
- struct cas *cp = netdev_priv(dev);
+ struct cas *cp = container_of(napi, struct cas, napi);
+ struct net_device *dev = cp->dev;
int i, enable_intr, todo, credits;
u32 status = readl(cp->regs + REG_INTR_STATUS);
unsigned long flags;
@@ -2620,20 +2621,18 @@ static int cas_poll(struct net_device *dev, int *budget)
/* NAPI rx packets. we spread the credits across all of the
* rxc rings
- */
- todo = min(*budget, dev->quota);
-
- /* to make sure we're fair with the work we loop through each
+ *
+ * to make sure we're fair with the work we loop through each
* ring N_RX_COMP_RING times with a request of
- * todo / N_RX_COMP_RINGS
+ * budget / N_RX_COMP_RINGS
*/
enable_intr = 1;
credits = 0;
for (i = 0; i < N_RX_COMP_RINGS; i++) {
int j;
for (j = 0; j < N_RX_COMP_RINGS; j++) {
- credits += cas_rx_ringN(cp, j, todo / N_RX_COMP_RINGS);
- if (credits >= todo) {
+ credits += cas_rx_ringN(cp, j, budget / N_RX_COMP_RINGS);
+ if (credits >= budget) {
enable_intr = 0;
goto rx_comp;
}
@@ -2641,9 +2640,6 @@ static int cas_poll(struct net_device *dev, int *budget)
}
rx_comp:
- *budget -= credits;
- dev->quota -= credits;
-
/* final rx completion */
spin_lock_irqsave(&cp->lock, flags);
if (status)
@@ -2674,11 +2670,10 @@ rx_comp:
#endif
spin_unlock_irqrestore(&cp->lock, flags);
if (enable_intr) {
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
cas_unmask_intr(cp);
- return 0;
}
- return 1;
+ return credits;
}
#endif
@@ -4351,6 +4346,9 @@ static int cas_open(struct net_device *dev)
goto err_spare;
}
+#ifdef USE_NAPI
+ napi_enable(&cp->napi);
+#endif
/* init hw */
cas_lock_all_save(cp, flags);
cas_clean_rings(cp);
@@ -4376,6 +4374,9 @@ static int cas_close(struct net_device *dev)
unsigned long flags;
struct cas *cp = netdev_priv(dev);
+#ifdef USE_NAPI
+ napi_enable(&cp->napi);
+#endif
/* Make sure we don't get distracted by suspend/resume */
mutex_lock(&cp->pm_mutex);
@@ -4771,9 +4772,14 @@ static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs,
cas_read_regs(cp, p, regs->len / sizeof(u32));
}
-static int cas_get_stats_count(struct net_device *dev)
+static int cas_get_sset_count(struct net_device *dev, int sset)
{
- return CAS_NUM_STAT_KEYS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return CAS_NUM_STAT_KEYS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -4817,7 +4823,7 @@ static const struct ethtool_ops cas_ethtool_ops = {
.set_msglevel = cas_set_msglevel,
.get_regs_len = cas_get_regs_len,
.get_regs = cas_get_regs,
- .get_stats_count = cas_get_stats_count,
+ .get_sset_count = cas_get_sset_count,
.get_strings = cas_get_strings,
.get_ethtool_stats = cas_get_ethtool_stats,
};
@@ -4876,6 +4882,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
int i, err, pci_using_dac;
u16 pci_cmd;
u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
+ DECLARE_MAC_BUF(mac);
if (cas_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -4899,7 +4906,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_out_disable_pdev;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = pci_request_regions(pdev, dev->name);
@@ -5062,8 +5068,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->watchdog_timeo = CAS_TX_TIMEOUT;
dev->change_mtu = cas_change_mtu;
#ifdef USE_NAPI
- dev->poll = cas_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &cp->napi, cas_poll, 64);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = cas_netpoll;
@@ -5085,16 +5090,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
i = readl(cp->regs + REG_BIM_CFG);
printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
- "Ethernet[%d] ", dev->name,
+ "Ethernet[%d] %s\n", dev->name,
(cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
(i & BIM_CFG_32BIT) ? "32" : "64",
(i & BIM_CFG_66MHZ) ? "66" : "33",
- (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
+ print_mac(mac, dev->dev_addr));
pci_set_drvdata(pdev, dev);
cp->hw_running = 1;
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index a970804487c7..2f93f83342d2 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -4280,6 +4280,8 @@ struct cas {
int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS];
int rx_last[N_RX_DESC_RINGS];
+ struct napi_struct napi;
+
/* Set when chip is actually in operational state
* (ie. not power managed) */
int hw_running;
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 743ad8b41b5e..57a4b262fd3f 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,6 +4,6 @@
obj-$(CONFIG_CHELSIO_T1) += cxgb.o
-cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o
cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
mv88x201x.o my3126.o $(cxgb-y)
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 8ba702c8b560..846ca5383d3c 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -278,6 +278,7 @@ struct adapter {
struct peespi *espi;
struct petp *tp;
+ struct napi_struct napi;
struct port_info port[MAX_NPORTS];
struct delayed_work stats_update_task;
struct timer_list stats_update_timer;
@@ -371,6 +372,7 @@ extern void t1_interrupts_enable(adapter_t *adapter);
extern void t1_interrupts_disable(adapter_t *adapter);
extern void t1_interrupts_clear(adapter_t *adapter);
extern int t1_elmer0_ext_intr_handler(adapter_t *adapter);
+extern void t1_elmer0_ext_intr(adapter_t *adapter);
extern int t1_slow_intr_handler(adapter_t *adapter);
extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 231ce43b97cf..2dbf8dc116c6 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -255,8 +255,11 @@ static int cxgb_open(struct net_device *dev)
struct adapter *adapter = dev->priv;
int other_ports = adapter->open_device_map & PORT_MASK;
- if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ napi_enable(&adapter->napi);
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+ napi_disable(&adapter->napi);
return err;
+ }
__set_bit(dev->if_port, &adapter->open_device_map);
link_start(&adapter->port[dev->if_port]);
@@ -274,6 +277,7 @@ static int cxgb_close(struct net_device *dev)
struct cmac *mac = p->mac;
netif_stop_queue(dev);
+ napi_disable(&adapter->napi);
mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
netif_carrier_off(dev);
@@ -435,9 +439,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strcpy(info->bus_info, pci_name(adapter->pdev));
}
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(stats_strings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(stats_strings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -790,17 +799,14 @@ static const struct ethtool_ops t1_ethtool_ops = {
.set_pauseparam = set_pauseparam,
.get_rx_csum = get_rx_csum,
.set_rx_csum = set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
.get_strings = get_strings,
- .get_stats_count = get_stats_count,
+ .get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
- .get_tso = ethtool_op_get_tso,
.set_tso = set_tso,
};
@@ -1032,7 +1038,6 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
if (!adapter) {
@@ -1113,8 +1118,7 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->poll_controller = t1_netpoll;
#endif
#ifdef CONFIG_CHELSIO_T1_NAPI
- netdev->weight = 64;
- netdev->poll = t1_poll;
+ netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
#endif
SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
deleted file mode 100644
index 1d972825eac3..000000000000
--- a/drivers/net/chelsio/mac.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */
-#include "gmac.h"
-#include "regs.h"
-#include "fpga_defs.h"
-
-#define MAC_CSR_INTERFACE_GMII 0x0
-#define MAC_CSR_INTERFACE_TBI 0x1
-#define MAC_CSR_INTERFACE_MII 0x2
-#define MAC_CSR_INTERFACE_RMII 0x3
-
-/* Chelsio's MAC statistics. */
-struct mac_statistics {
-
- /* Transmit */
- u32 TxFramesTransmittedOK;
- u32 TxReserved1;
- u32 TxReserved2;
- u32 TxOctetsTransmittedOK;
- u32 TxFramesWithDeferredXmissions;
- u32 TxLateCollisions;
- u32 TxFramesAbortedDueToXSCollisions;
- u32 TxFramesLostDueToIntMACXmitError;
- u32 TxReserved3;
- u32 TxMulticastFrameXmittedOK;
- u32 TxBroadcastFramesXmittedOK;
- u32 TxFramesWithExcessiveDeferral;
- u32 TxPAUSEMACCtrlFramesTransmitted;
-
- /* Receive */
- u32 RxFramesReceivedOK;
- u32 RxFrameCheckSequenceErrors;
- u32 RxAlignmentErrors;
- u32 RxOctetsReceivedOK;
- u32 RxFramesLostDueToIntMACRcvError;
- u32 RxMulticastFramesReceivedOK;
- u32 RxBroadcastFramesReceivedOK;
- u32 RxInRangeLengthErrors;
- u32 RxTxOutOfRangeLengthField;
- u32 RxFrameTooLongErrors;
- u32 RxPAUSEMACCtrlFramesReceived;
-};
-
-static int static_aPorts[] = {
- FPGA_GMAC_INTERRUPT_PORT0,
- FPGA_GMAC_INTERRUPT_PORT1,
- FPGA_GMAC_INTERRUPT_PORT2,
- FPGA_GMAC_INTERRUPT_PORT3
-};
-
-struct _cmac_instance {
- u32 index;
-};
-
-static int mac_intr_enable(struct cmac *mac)
-{
- u32 mac_intr;
-
- if (t1_is_asic(mac->adapter)) {
- /* ASIC */
-
- /* We don't use the on chip MAC for ASIC products. */
- } else {
- /* FPGA */
-
- /* Set parent gmac interrupt. */
- mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
- mac_intr |= FPGA_PCIX_INTERRUPT_GMAC;
- writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
-
- mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- mac_intr |= static_aPorts[mac->instance->index];
- writel(mac_intr,
- mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- }
-
- return 0;
-}
-
-static int mac_intr_disable(struct cmac *mac)
-{
- u32 mac_intr;
-
- if (t1_is_asic(mac->adapter)) {
- /* ASIC */
-
- /* We don't use the on chip MAC for ASIC products. */
- } else {
- /* FPGA */
-
- /* Set parent gmac interrupt. */
- mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
- mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC;
- writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
-
- mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- mac_intr &= ~(static_aPorts[mac->instance->index]);
- writel(mac_intr,
- mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- }
-
- return 0;
-}
-
-static int mac_intr_clear(struct cmac *mac)
-{
- u32 mac_intr;
-
- if (t1_is_asic(mac->adapter)) {
- /* ASIC */
-
- /* We don't use the on chip MAC for ASIC products. */
- } else {
- /* FPGA */
-
- /* Set parent gmac interrupt. */
- writel(FPGA_PCIX_INTERRUPT_GMAC,
- mac->adapter->regs + A_PL_CAUSE);
- mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
- mac_intr |= (static_aPorts[mac->instance->index]);
- writel(mac_intr,
- mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
- }
-
- return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
- u32 data32_lo, data32_hi;
-
- data32_lo = readl(mac->adapter->regs
- + MAC_REG_IDLO(mac->instance->index));
- data32_hi = readl(mac->adapter->regs
- + MAC_REG_IDHI(mac->instance->index));
-
- addr[0] = (u8) ((data32_hi >> 8) & 0xFF);
- addr[1] = (u8) ((data32_hi) & 0xFF);
- addr[2] = (u8) ((data32_lo >> 24) & 0xFF);
- addr[3] = (u8) ((data32_lo >> 16) & 0xFF);
- addr[4] = (u8) ((data32_lo >> 8) & 0xFF);
- addr[5] = (u8) ((data32_lo) & 0xFF);
- return 0;
-}
-
-static int mac_reset(struct cmac *mac)
-{
- u32 data32;
- int mac_in_reset, time_out = 100;
- int idx = mac->instance->index;
-
- data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
- writel(data32 | F_MAC_RESET,
- mac->adapter->regs + MAC_REG_CSR(idx));
-
- do {
- data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
-
- mac_in_reset = data32 & F_MAC_RESET;
- if (mac_in_reset)
- udelay(1);
- } while (mac_in_reset && --time_out);
-
- if (mac_in_reset) {
- CH_ERR("%s: MAC %d reset timed out\n",
- mac->adapter->name, idx);
- return 2;
- }
-
- return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
- u32 val;
-
- val = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE);
- val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0);
- val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0);
- writel(val,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
-
- return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
- int fc)
-{
- u32 data32;
-
- data32 = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) |
- V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE |
- F_MAC_RX_PAUSE_ENABLE);
-
- switch (speed) {
- case SPEED_10:
- case SPEED_100:
- data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII);
- data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1);
- break;
- case SPEED_1000:
- data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII);
- data32 |= V_MAC_SPEED(2);
- break;
- }
-
- if (duplex >= 0)
- data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF);
-
- if (fc >= 0) {
- data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0);
- data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0);
- }
-
- writel(data32,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
- return 0;
-}
-
-static int mac_enable(struct cmac *mac, int which)
-{
- u32 val;
-
- val = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- if (which & MAC_DIRECTION_RX)
- val |= F_MAC_RX_ENABLE;
- if (which & MAC_DIRECTION_TX)
- val |= F_MAC_TX_ENABLE;
- writel(val,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
- return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
- u32 val;
-
- val = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- if (which & MAC_DIRECTION_RX)
- val &= ~F_MAC_RX_ENABLE;
- if (which & MAC_DIRECTION_TX)
- val &= ~F_MAC_TX_ENABLE;
- writel(val,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
- return 0;
-}
-
-#if 0
-static int mac_set_ifs(struct cmac *mac, u32 mode)
-{
- t1_write_reg_4(mac->adapter,
- MAC_REG_IFS(mac->instance->index),
- mode);
- return 0;
-}
-
-static int mac_enable_isl(struct cmac *mac)
-{
- u32 data32 = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE;
- t1_write_reg_4(mac->adapter,
- MAC_REG_CSR(mac->instance->index),
- data32);
- return 0;
-}
-#endif
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
- if (mtu > 9600)
- return -EINVAL;
- writel(mtu + ETH_HLEN + VLAN_HLEN,
- mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index));
-
- return 0;
-}
-
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
- int flag)
-{
- struct mac_statistics st;
- u32 *p = (u32 *) & st, i;
-
- writel(0,
- mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index));
-
- for (i = 0; i < sizeof(st) / sizeof(u32); i++)
- *p++ = readl(mac->adapter->regs
- + MAC_REG_RMDATA(mac->instance->index));
-
- /* XXX convert stats */
- return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
- kfree(mac);
-}
-
-static struct cmac_ops chelsio_mac_ops = {
- .destroy = mac_destroy,
- .reset = mac_reset,
- .interrupt_enable = mac_intr_enable,
- .interrupt_disable = mac_intr_disable,
- .interrupt_clear = mac_intr_clear,
- .enable = mac_enable,
- .disable = mac_disable,
- .set_mtu = mac_set_mtu,
- .set_rx_mode = mac_set_rx_mode,
- .set_speed_duplex_fc = mac_set_speed_duplex_fc,
- .macaddress_get = mac_get_address,
- .statistics_update = mac_update_statistics,
-};
-
-static struct cmac *mac_create(adapter_t *adapter, int index)
-{
- struct cmac *mac;
- u32 data32;
-
- if (index >= 4)
- return NULL;
-
- mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac)
- return NULL;
-
- mac->ops = &chelsio_mac_ops;
- mac->instance = (cmac_instance *) (mac + 1);
-
- mac->instance->index = index;
- mac->adapter = adapter;
-
- data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index));
- data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC |
- F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE);
- data32 |= F_MAC_JUMBO_ENABLE;
- writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index));
-
- /* Initialize the random backoff seed. */
- data32 = 0x55aa + (3 * index);
- writel(data32,
- adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index));
-
- /* Check to see if the mac address needs to be set manually. */
- data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index));
- if (data32 == 0 || data32 == 0xffffffff) {
- /*
- * Add a default MAC address if we can't read one.
- */
- writel(0x43FFFFFF - index,
- adapter->regs + MAC_REG_IDLO(mac->instance->index));
- writel(0x0007,
- adapter->regs + MAC_REG_IDHI(mac->instance->index));
- }
-
- (void) mac_set_mtu(mac, 1500);
- return mac;
-}
-
-const struct gmac t1_chelsio_mac_ops = {
- .create = mac_create
-};
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index e4f874a70fe5..ffa7e649a6ef 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1620,23 +1620,20 @@ static int process_pure_responses(struct adapter *adapter)
* or protection from interrupts as data interrupts are off at this point and
* other adapter interrupts do not interfere.
*/
-int t1_poll(struct net_device *dev, int *budget)
+int t1_poll(struct napi_struct *napi, int budget)
{
- struct adapter *adapter = dev->priv;
+ struct adapter *adapter = container_of(napi, struct adapter, napi);
+ struct net_device *dev = adapter->port[0].dev;
int work_done;
- work_done = process_responses(adapter, min(*budget, dev->quota));
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (unlikely(responses_pending(adapter)))
- return 1;
-
- netif_rx_complete(dev);
- writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-
- return 0;
+ work_done = process_responses(adapter, budget);
+ if (likely(!responses_pending(adapter))) {
+ netif_rx_complete(dev, napi);
+ writel(adapter->sge->respQ.cidx,
+ adapter->regs + A_SG_SLEEPING);
+ }
+ return work_done;
}
/*
@@ -1653,13 +1650,13 @@ irqreturn_t t1_interrupt(int irq, void *data)
writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
- if (__netif_rx_schedule_prep(dev)) {
+ if (napi_schedule_prep(&adapter->napi)) {
if (process_pure_responses(adapter))
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &adapter->napi);
else {
/* no data, no NAPI needed */
writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
- netif_poll_enable(dev); /* undo schedule_prep */
+ napi_enable(&adapter->napi); /* undo schedule_prep */
}
}
return IRQ_HANDLED;
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
index d132a0ef2a22..713d9c55f24d 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/chelsio/sge.h
@@ -77,7 +77,7 @@ int t1_sge_configure(struct sge *, struct sge_params *);
int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
void t1_sge_destroy(struct sge *);
irqreturn_t t1_interrupt(int irq, void *cookie);
-int t1_poll(struct net_device *, int *);
+int t1_poll(struct napi_struct *, int);
int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
void t1_set_vlan_accel(struct adapter *adapter, int on_off);
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 7de9a611e1f7..dc50151bed81 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -884,7 +884,7 @@ static int asic_slow_intr(adapter_t *adapter)
if (cause & F_PL_INTR_PCIX)
t1_pci_intr_handler(adapter);
if (cause & F_PL_INTR_EXT)
- t1_elmer0_ext_intr_handler(adapter);
+ t1_elmer0_ext_intr(adapter);
/* Clear the interrupts just processed. */
writel(cause, adapter->regs + A_PL_CAUSE);
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 5bdf5ca85a65..314b2f68f78f 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -618,12 +618,8 @@ e100_set_mac_address(struct net_device *dev, void *p)
/* show it in the log as well */
- printk(KERN_INFO "%s: changed MAC to ", dev->name);
-
- for (i = 0; i < 5; i++)
- printk("%02X:", dev->dev_addr[i]);
-
- printk("%02X\n", dev->dev_addr[i]);
+ printk(KERN_INFO "%s: changed MAC to %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
spin_unlock(&np->lock);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 9774bb1b3e80..571750975137 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -516,8 +516,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
unsigned rev_type = 0;
int eeprom_buff[CHKSUM_LEN];
int retval;
+ DECLARE_MAC_BUF(mac);
- SET_MODULE_OWNER(dev);
/* Initialize the device structure. */
if (!modular) {
memset(lp, 0, sizeof(*lp));
@@ -806,7 +806,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
i = cs8900_irq_map[0];
#else
/* Translate the IRQ using the IRQ mapping table. */
- if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+ if (i >= ARRAY_SIZE(cs8900_irq_map))
printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
else
i = cs8900_irq_map[i];
@@ -841,11 +841,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
}
/* print the ethernet address. */
- printk(", MAC");
- for (i = 0; i < ETH_ALEN; i++)
- {
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- }
+ printk(", MAC %s", print_mac(mac, dev->dev_addr));
dev->open = net_open;
dev->stop = net_close;
@@ -1247,11 +1243,11 @@ write_irq(struct net_device *dev, int chip_type, int irq)
if (chip_type == CS8900) {
/* Search the mapping table for the corresponding IRQ pin. */
- for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
+ for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
if (cs8900_irq_map[i] == irq)
break;
/* Not found */
- if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+ if (i == ARRAY_SIZE(cs8900_irq_map))
i = 3;
writereg(dev, PP_CS8900_ISAINT, i);
} else {
@@ -1807,17 +1803,15 @@ static int set_mac_address(struct net_device *dev, void *p)
int i;
struct sockaddr *addr = p;
-
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (net_debug) {
- printk("%s: Setting MAC address to ", dev->name);
- for (i = 0; i < dev->addr_len; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk(".\n");
+ DECLARE_MAC_BUF(mac);
+ printk("%s: Setting MAC address to %s.\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
/* set the Ethernet address */
for (i=0; i < ETH_ALEN/2; i++)
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index ab72563b81ee..044261703381 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -49,9 +49,13 @@
typedef irqreturn_t(*intr_handler_t) (int, void *);
struct vlan_group;
+struct adapter;
+struct sge_qset;
struct port_info {
+ struct adapter *adapter;
struct vlan_group *vlan_grp;
+ struct sge_qset *qs;
const struct port_type_info *port_type;
u8 port_id;
u8 rx_csum_offload;
@@ -171,10 +175,12 @@ enum { /* per port SGE statistics */
};
struct sge_qset { /* an SGE queue set */
+ struct adapter *adap;
+ struct napi_struct napi;
struct sge_rspq rspq;
struct sge_fl fl[SGE_RXQ_PER_SET];
struct sge_txq txq[SGE_TXQ_PER_SET];
- struct net_device *netdev; /* associated net device */
+ struct net_device *netdev;
unsigned long txq_stopped; /* which Tx queues are stopped */
struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
unsigned long port_stats[SGE_PSTAT_MAX];
@@ -219,12 +225,6 @@ struct adapter {
struct delayed_work adap_check_task;
struct work_struct ext_intr_handler_task;
- /*
- * Dummy netdevices are needed when using multiple receive queues with
- * NAPI as each netdevice can service only one queue.
- */
- struct net_device *dummy_netdev[SGE_QSETS - 1];
-
struct dentry *debugfs_root;
struct mutex mdio_lock;
@@ -251,12 +251,6 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
return netdev_priv(adap->port[idx]);
}
-/*
- * We use the spare atalk_ptr to map a net device to its SGE queue set.
- * This is a macro so it can be used as l-value.
- */
-#define dev2qset(netdev) ((netdev)->atalk_ptr)
-
#define OFFLOAD_DEVMAP_BIT 15
#define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -282,7 +276,7 @@ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int irq_vec_idx, const struct qset_params *p,
- int ntxq, struct net_device *netdev);
+ int ntxq, struct net_device *dev);
int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 16378004507a..99c75d30f67a 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -97,6 +97,7 @@ enum {
MAX_NPORTS = 2, /* max # of ports */
MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */
EEPROMSIZE = 8192, /* Serial EEPROM size */
+ SERNUM_LEN = 16, /* Serial # length */
RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
@@ -104,7 +105,7 @@ enum {
PROTO_SRAM_LINES = 128, /* size of TP sram */
};
-#define MAX_RX_COALESCING_LEN 16224U
+#define MAX_RX_COALESCING_LEN 12288U
enum {
PAUSE_RX = 1 << 0,
@@ -126,8 +127,8 @@ enum { /* adapter interrupt-maintained statistics */
enum {
TP_VERSION_MAJOR = 1,
- TP_VERSION_MINOR = 0,
- TP_VERSION_MICRO = 44
+ TP_VERSION_MINOR = 1,
+ TP_VERSION_MICRO = 0
};
#define S_TP_VERSION_MAJOR 16
@@ -167,8 +168,8 @@ enum {
};
struct sg_ent { /* SGE scatter/gather entry */
- u32 len[2];
- u64 addr[2];
+ __be32 len[2];
+ __be64 addr[2];
};
#ifndef SGE_NUM_GENBITS
@@ -391,6 +392,7 @@ struct vpd_params {
unsigned int uclk;
unsigned int mdc;
unsigned int mem_timing;
+ u8 sn[SERNUM_LEN + 1];
u8 eth_base[6];
u8 port_type[MAX_NPORTS];
unsigned short xauicfg[2];
@@ -436,6 +438,7 @@ enum { /* chip revisions */
T3_REV_A = 0,
T3_REV_B = 2,
T3_REV_B2 = 3,
+ T3_REV_C = 4,
};
struct trace_params {
@@ -507,9 +510,11 @@ struct cmac {
unsigned int tx_xcnt;
u64 tx_mcnt;
unsigned int rx_xcnt;
+ unsigned int rx_ocnt;
u64 rx_mcnt;
unsigned int toggle_cnt;
unsigned int txen;
+ u64 rx_pause;
struct mac_stats stats;
};
@@ -679,14 +684,15 @@ const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
int t3_seeprom_wp(struct adapter *adapter, int enable);
-int t3_check_tpsram_version(struct adapter *adapter);
+int t3_get_tp_version(struct adapter *adapter, u32 *vers);
+int t3_check_tpsram_version(struct adapter *adapter, int *must_load);
int t3_check_tpsram(struct adapter *adapter, u8 *tp_ram, unsigned int size);
int t3_set_proto_sram(struct adapter *adap, u8 *data);
int t3_read_flash(struct adapter *adapter, unsigned int addr,
unsigned int nwords, u32 *data, int byte_oriented);
int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
int t3_get_fw_version(struct adapter *adapter, u32 *vers);
-int t3_check_fw_version(struct adapter *adapter);
+int t3_check_fw_version(struct adapter *adapter, int *must_load);
int t3_init_hw(struct adapter *adapter, u32 fw_params);
void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 2095ddacff78..6c4f32066919 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -33,27 +33,29 @@
#define _CXGB3_OFFLOAD_CTL_DEFS_H
enum {
- GET_MAX_OUTSTANDING_WR,
- GET_TX_MAX_CHUNK,
- GET_TID_RANGE,
- GET_STID_RANGE,
- GET_RTBL_RANGE,
- GET_L2T_CAPACITY,
- GET_MTUS,
- GET_WR_LEN,
- GET_IFF_FROM_MAC,
- GET_DDP_PARAMS,
- GET_PORTS,
-
- ULP_ISCSI_GET_PARAMS,
- ULP_ISCSI_SET_PARAMS,
-
- RDMA_GET_PARAMS,
- RDMA_CQ_OP,
- RDMA_CQ_SETUP,
- RDMA_CQ_DISABLE,
- RDMA_CTRL_QP_SETUP,
- RDMA_GET_MEM,
+ GET_MAX_OUTSTANDING_WR = 0,
+ GET_TX_MAX_CHUNK = 1,
+ GET_TID_RANGE = 2,
+ GET_STID_RANGE = 3,
+ GET_RTBL_RANGE = 4,
+ GET_L2T_CAPACITY = 5,
+ GET_MTUS = 6,
+ GET_WR_LEN = 7,
+ GET_IFF_FROM_MAC = 8,
+ GET_DDP_PARAMS = 9,
+ GET_PORTS = 10,
+
+ ULP_ISCSI_GET_PARAMS = 11,
+ ULP_ISCSI_SET_PARAMS = 12,
+
+ RDMA_GET_PARAMS = 13,
+ RDMA_CQ_OP = 14,
+ RDMA_CQ_SETUP = 15,
+ RDMA_CQ_DISABLE = 16,
+ RDMA_CTRL_QP_SETUP = 17,
+ RDMA_GET_MEM = 18,
+
+ GET_RX_PAGE_INFO = 50,
};
/*
@@ -161,4 +163,12 @@ struct rdma_ctrlqp_setup {
unsigned long long base_addr;
unsigned int size;
};
+
+/*
+ * Offload TX/RX page information.
+ */
+struct ofld_page_info {
+ unsigned int page_size; /* Page size, should be a power of 2 */
+ unsigned int num; /* Number of pages */
+};
#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 483a594210a7..45e92164c260 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -79,9 +79,17 @@ static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
unsigned int tid)
{
+ union listen_entry *e;
+
if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
return NULL;
- return &(stid2entry(t, tid)->t3c_tid);
+
+ e = stid2entry(t, tid);
+ if ((void *)e->next >= (void *)t->tid_tab &&
+ (void *)e->next < (void *)&t->atid_tab[t->natids])
+ return NULL;
+
+ return &e->t3c_tid;
}
/*
@@ -90,9 +98,17 @@ static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
unsigned int tid)
{
+ union active_open_entry *e;
+
if (tid < t->atid_base || tid >= t->atid_base + t->natids)
return NULL;
- return &(atid2entry(t, tid)->t3c_tid);
+
+ e = atid2entry(t, tid);
+ if ((void *)e->next >= (void *)t->tid_tab &&
+ (void *)e->next < (void *)&t->atid_tab[t->natids])
+ return NULL;
+
+ return &e->t3c_tid;
}
int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 6fd1e5241833..61ffc925eae7 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -339,46 +339,17 @@ static void setup_rss(struct adapter *adap)
V_RRCPLCPUSIZE(6), cpus, rspq_map);
}
-/*
- * If we have multiple receive queues per port serviced by NAPI we need one
- * netdevice per queue as NAPI operates on netdevices. We already have one
- * netdevice, namely the one associated with the interface, so we use dummy
- * ones for any additional queues. Note that these netdevices exist purely
- * so that NAPI has something to work with, they do not represent network
- * ports and are not registered.
- */
-static int init_dummy_netdevs(struct adapter *adap)
+static void init_napi(struct adapter *adap)
{
- int i, j, dummy_idx = 0;
- struct net_device *nd;
-
- for_each_port(adap, i) {
- struct net_device *dev = adap->port[i];
- const struct port_info *pi = netdev_priv(dev);
-
- for (j = 0; j < pi->nqsets - 1; j++) {
- if (!adap->dummy_netdev[dummy_idx]) {
- nd = alloc_netdev(0, "", ether_setup);
- if (!nd)
- goto free_all;
+ int i;
- nd->priv = adap;
- nd->weight = 64;
- set_bit(__LINK_STATE_START, &nd->state);
- adap->dummy_netdev[dummy_idx] = nd;
- }
- strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
- dummy_idx++;
- }
- }
- return 0;
+ for (i = 0; i < SGE_QSETS; i++) {
+ struct sge_qset *qs = &adap->sge.qs[i];
-free_all:
- while (--dummy_idx >= 0) {
- free_netdev(adap->dummy_netdev[dummy_idx]);
- adap->dummy_netdev[dummy_idx] = NULL;
+ if (qs->adap)
+ netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
+ 64);
}
- return -ENOMEM;
}
/*
@@ -389,20 +360,18 @@ free_all:
static void quiesce_rx(struct adapter *adap)
{
int i;
- struct net_device *dev;
- for_each_port(adap, i) {
- dev = adap->port[i];
- while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
- msleep(1);
- }
+ for (i = 0; i < SGE_QSETS; i++)
+ if (adap->sge.qs[i].adap)
+ napi_disable(&adap->sge.qs[i].napi);
+}
- for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
- dev = adap->dummy_netdev[i];
- if (dev)
- while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
- msleep(1);
- }
+static void enable_all_napi(struct adapter *adap)
+{
+ int i;
+ for (i = 0; i < SGE_QSETS; i++)
+ if (adap->sge.qs[i].adap)
+ napi_enable(&adap->sge.qs[i].napi);
}
/**
@@ -415,7 +384,7 @@ static void quiesce_rx(struct adapter *adap)
*/
static int setup_sge_qsets(struct adapter *adap)
{
- int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+ int i, j, err, irq_idx = 0, qset_idx = 0;
unsigned int ntxq = SGE_TXQ_PER_SET;
if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
@@ -423,15 +392,14 @@ static int setup_sge_qsets(struct adapter *adap)
for_each_port(adap, i) {
struct net_device *dev = adap->port[i];
- const struct port_info *pi = netdev_priv(dev);
+ struct port_info *pi = netdev_priv(dev);
+ pi->qs = &adap->sge.qs[pi->first_qset];
for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
err = t3_sge_alloc_qset(adap, qset_idx, 1,
(adap->flags & USING_MSIX) ? qset_idx + 1 :
irq_idx,
- &adap->params.sge.qset[qset_idx], ntxq,
- j == 0 ? dev :
- adap-> dummy_netdev[dummy_dev_idx++]);
+ &adap->params.sge.qset[qset_idx], ntxq, dev);
if (err) {
t3_free_sge_resources(adap);
return err;
@@ -482,7 +450,8 @@ static ssize_t attr_store(struct device *d, struct device_attribute *attr,
#define CXGB3_SHOW(name, val_expr) \
static ssize_t format_##name(struct net_device *dev, char *buf) \
{ \
- struct adapter *adap = dev->priv; \
+ struct port_info *pi = netdev_priv(dev); \
+ struct adapter *adap = pi->adapter; \
return sprintf(buf, "%u\n", val_expr); \
} \
static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
@@ -493,7 +462,8 @@ static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
{
- struct adapter *adap = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adap = pi->adapter;
int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
if (adap->flags & FULL_INIT_DONE)
@@ -515,7 +485,8 @@ static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
static ssize_t set_nservers(struct net_device *dev, unsigned int val)
{
- struct adapter *adap = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adap = pi->adapter;
if (adap->flags & FULL_INIT_DONE)
return -EBUSY;
@@ -556,9 +527,10 @@ static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
char *buf, int sched)
{
- ssize_t len;
+ struct port_info *pi = netdev_priv(to_net_dev(d));
+ struct adapter *adap = pi->adapter;
unsigned int v, addr, bpt, cpt;
- struct adapter *adap = to_net_dev(d)->priv;
+ ssize_t len;
addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
rtnl_lock();
@@ -581,10 +553,11 @@ static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t len, int sched)
{
+ struct port_info *pi = netdev_priv(to_net_dev(d));
+ struct adapter *adap = pi->adapter;
+ unsigned int val;
char *endp;
ssize_t ret;
- unsigned int val;
- struct adapter *adap = to_net_dev(d)->priv;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -721,6 +694,7 @@ static void bind_qsets(struct adapter *adap)
}
#define FW_FNAME "t3fw-%d.%d.%d.bin"
+#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
static int upgrade_fw(struct adapter *adap)
{
@@ -739,6 +713,74 @@ static int upgrade_fw(struct adapter *adap)
}
ret = t3_load_fw(adap, fw->data, fw->size);
release_firmware(fw);
+
+ if (ret == 0)
+ dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
+ FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
+ else
+ dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
+ FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
+
+ return ret;
+}
+
+static inline char t3rev2char(struct adapter *adapter)
+{
+ char rev = 0;
+
+ switch(adapter->params.rev) {
+ case T3_REV_B:
+ case T3_REV_B2:
+ rev = 'b';
+ break;
+ case T3_REV_C:
+ rev = 'c';
+ break;
+ }
+ return rev;
+}
+
+static int update_tpsram(struct adapter *adap)
+{
+ const struct firmware *tpsram;
+ char buf[64];
+ struct device *dev = &adap->pdev->dev;
+ int ret;
+ char rev;
+
+ rev = t3rev2char(adap);
+ if (!rev)
+ return 0;
+
+ snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
+ TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+
+ ret = request_firmware(&tpsram, buf, dev);
+ if (ret < 0) {
+ dev_err(dev, "could not load TP SRAM: unable to load %s\n",
+ buf);
+ return ret;
+ }
+
+ ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
+ if (ret)
+ goto release_tpsram;
+
+ ret = t3_set_proto_sram(adap, tpsram->data);
+ if (ret == 0)
+ dev_info(dev,
+ "successful update of protocol engine "
+ "to %d.%d.%d\n",
+ TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+ else
+ dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
+ TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+ if (ret)
+ dev_err(dev, "loading protocol SRAM failed\n");
+
+release_tpsram:
+ release_firmware(tpsram);
+
return ret;
}
@@ -754,30 +796,36 @@ static int upgrade_fw(struct adapter *adap)
*/
static int cxgb_up(struct adapter *adap)
{
- int err = 0;
+ int err;
+ int must_load;
if (!(adap->flags & FULL_INIT_DONE)) {
- err = t3_check_fw_version(adap);
- if (err == -EINVAL)
+ err = t3_check_fw_version(adap, &must_load);
+ if (err == -EINVAL) {
err = upgrade_fw(adap);
- if (err)
- goto out;
+ if (err && must_load)
+ goto out;
+ }
- err = init_dummy_netdevs(adap);
- if (err)
- goto out;
+ err = t3_check_tpsram_version(adap, &must_load);
+ if (err == -EINVAL) {
+ err = update_tpsram(adap);
+ if (err && must_load)
+ goto out;
+ }
err = t3_init_hw(adap, 0);
if (err)
goto out;
t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
-
+
err = setup_sge_qsets(adap);
if (err)
goto out;
setup_rss(adap);
+ init_napi(adap);
adap->flags |= FULL_INIT_DONE;
}
@@ -804,6 +852,7 @@ static int cxgb_up(struct adapter *adap)
adap->name, adap)))
goto irq_err;
+ enable_all_napi(adap);
t3_sge_start(adap);
t3_intr_enable(adap);
@@ -858,10 +907,11 @@ static void schedule_chk_task(struct adapter *adap)
static int offload_open(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
- struct t3cdev *tdev = T3CDEV(dev);
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+ struct t3cdev *tdev = dev2t3cdev(dev);
int adap_up = adapter->open_device_map & PORT_MASK;
- int err = 0;
+ int err;
if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
return 0;
@@ -924,13 +974,15 @@ static int offload_close(struct t3cdev *tdev)
static int cxgb_open(struct net_device *dev)
{
- int err;
- struct adapter *adapter = dev->priv;
struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
int other_ports = adapter->open_device_map & PORT_MASK;
+ int err;
- if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+ quiesce_rx(adapter);
return err;
+ }
set_bit(pi->port_id, &adapter->open_device_map);
if (is_offload(adapter) && !ofld_disable) {
@@ -951,17 +1003,17 @@ static int cxgb_open(struct net_device *dev)
static int cxgb_close(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
- struct port_info *p = netdev_priv(dev);
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
- t3_port_intr_disable(adapter, p->port_id);
+ t3_port_intr_disable(adapter, pi->port_id);
netif_stop_queue(dev);
- p->phy.ops->power_down(&p->phy, 1);
+ pi->phy.ops->power_down(&pi->phy, 1);
netif_carrier_off(dev);
- t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+ t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
spin_lock(&adapter->work_lock); /* sync with update task */
- clear_bit(p->port_id, &adapter->open_device_map);
+ clear_bit(pi->port_id, &adapter->open_device_map);
spin_unlock(&adapter->work_lock);
if (!(adapter->open_device_map & PORT_MASK))
@@ -976,13 +1028,13 @@ static int cxgb_close(struct net_device *dev)
static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
- struct port_info *p = netdev_priv(dev);
- struct net_device_stats *ns = &p->netstats;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+ struct net_device_stats *ns = &pi->netstats;
const struct mac_stats *pstats;
spin_lock(&adapter->stats_lock);
- pstats = t3_mac_update_stats(&p->mac);
+ pstats = t3_mac_update_stats(&pi->mac);
spin_unlock(&adapter->stats_lock);
ns->tx_bytes = pstats->tx_octets;
@@ -1015,14 +1067,16 @@ static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
static u32 get_msglevel(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
return adapter->msg_enable;
}
static void set_msglevel(struct net_device *dev, u32 val)
{
- struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
adapter->msg_enable = val;
}
@@ -1077,9 +1131,14 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
};
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(stats_strings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(stats_strings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
#define T3_REGMAP_SIZE (3 * 1024)
@@ -1096,10 +1155,13 @@ static int get_eeprom_len(struct net_device *dev)
static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
u32 fw_vers = 0;
- struct adapter *adapter = dev->priv;
+ u32 tp_vers = 0;
t3_get_fw_version(adapter, &fw_vers);
+ t3_get_tp_version(adapter, &tp_vers);
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
@@ -1108,11 +1170,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strcpy(info->fw_version, "N/A");
else {
snprintf(info->fw_version, sizeof(info->fw_version),
- "%s %u.%u.%u",
+ "%s %u.%u.%u TP %u.%u.%u",
G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
G_FW_VERSION_MAJOR(fw_vers),
G_FW_VERSION_MINOR(fw_vers),
- G_FW_VERSION_MICRO(fw_vers));
+ G_FW_VERSION_MICRO(fw_vers),
+ G_TP_VERSION_MAJOR(tp_vers),
+ G_TP_VERSION_MINOR(tp_vers),
+ G_TP_VERSION_MICRO(tp_vers));
}
}
@@ -1136,8 +1201,8 @@ static unsigned long collect_sge_port_stats(struct adapter *adapter,
static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
u64 *data)
{
- struct adapter *adapter = dev->priv;
struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
const struct mac_stats *s;
spin_lock(&adapter->stats_lock);
@@ -1205,7 +1270,8 @@ static inline void reg_block_dump(struct adapter *ap, void *buf,
static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *buf)
{
- struct adapter *ap = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *ap = pi->adapter;
/*
* Version scheme:
@@ -1246,8 +1312,9 @@ static int restart_autoneg(struct net_device *dev)
static int cxgb3_phys_id(struct net_device *dev, u32 data)
{
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
int i;
- struct adapter *adapter = dev->priv;
if (data == 0)
data = 2;
@@ -1408,8 +1475,8 @@ static int set_rx_csum(struct net_device *dev, u32 data)
static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
{
- const struct adapter *adapter = dev->priv;
- const struct port_info *pi = netdev_priv(dev);
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
e->rx_max_pending = MAX_RX_BUFFERS;
@@ -1425,10 +1492,10 @@ static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
{
- int i;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
struct qset_params *q;
- struct adapter *adapter = dev->priv;
- const struct port_info *pi = netdev_priv(dev);
+ int i;
if (e->rx_pending > MAX_RX_BUFFERS ||
e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
@@ -1457,7 +1524,8 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
{
- struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
struct qset_params *qsp = &adapter->params.sge.qset[0];
struct sge_qset *qs = &adapter->sge.qs[0];
@@ -1471,7 +1539,8 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
{
- struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
struct qset_params *q = adapter->params.sge.qset;
c->rx_coalesce_usecs = q->coalesce_usecs;
@@ -1481,8 +1550,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
u8 * data)
{
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
int i, err = 0;
- struct adapter *adapter = dev->priv;
u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
if (!buf)
@@ -1501,10 +1571,11 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 * data)
{
- u8 *buf;
- int err = 0;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
u32 aligned_offset, aligned_len, *p;
- struct adapter *adapter = dev->priv;
+ u8 *buf;
+ int err;
if (eeprom->magic != EEPROM_MAGIC)
return -EINVAL;
@@ -1568,22 +1639,18 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.set_pauseparam = set_pauseparam,
.get_rx_csum = get_rx_csum,
.set_rx_csum = set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
.get_strings = get_strings,
.phys_id = cxgb3_phys_id,
.nway_reset = restart_autoneg,
- .get_stats_count = get_stats_count,
+ .get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
.get_wol = get_wol,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
- .get_perm_addr = ethtool_op_get_perm_addr
};
static int in_range(int val, int lo, int hi)
@@ -1593,9 +1660,10 @@ static int in_range(int val, int lo, int hi)
static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
{
- int ret;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
u32 cmd;
- struct adapter *adapter = dev->priv;
+ int ret;
if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
return -EFAULT;
@@ -1701,7 +1769,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
}
case CHELSIO_SET_QSET_NUM:{
struct ch_reg edata;
- struct port_info *pi = netdev_priv(dev);
unsigned int i, first_qset = 0, other_qsets = 0;
if (!capable(CAP_NET_ADMIN))
@@ -1733,7 +1800,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
}
case CHELSIO_GET_QSET_NUM:{
struct ch_reg edata;
- struct port_info *pi = netdev_priv(dev);
edata.cmd = CHELSIO_GET_QSET_NUM;
edata.val = pi->nqsets;
@@ -1924,10 +1990,10 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
- int ret, mmd;
- struct adapter *adapter = dev->priv;
- struct port_info *pi = netdev_priv(dev);
struct mii_ioctl_data *data = if_mii(req);
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+ int ret, mmd;
switch (cmd) {
case SIOCGMIIPHY:
@@ -1995,9 +2061,9 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
{
- int ret;
- struct adapter *adapter = dev->priv;
struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+ int ret;
if (new_mtu < 81) /* accommodate SACK */
return -EINVAL;
@@ -2014,8 +2080,8 @@ static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
static int cxgb_set_mac_addr(struct net_device *dev, void *p)
{
- struct adapter *adapter = dev->priv;
struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
@@ -2051,8 +2117,8 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
- struct adapter *adapter = dev->priv;
struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
pi->vlan_grp = grp;
if (adapter->params.rev > 0)
@@ -2071,8 +2137,8 @@ static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cxgb_netpoll(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
int qidx;
for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
@@ -2089,42 +2155,6 @@ static void cxgb_netpoll(struct net_device *dev)
}
#endif
-#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
-int update_tpsram(struct adapter *adap)
-{
- const struct firmware *tpsram;
- char buf[64];
- struct device *dev = &adap->pdev->dev;
- int ret;
- char rev;
-
- rev = adap->params.rev == T3_REV_B2 ? 'b' : 'a';
-
- snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
- TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
-
- ret = request_firmware(&tpsram, buf, dev);
- if (ret < 0) {
- dev_err(dev, "could not load TP SRAM: unable to load %s\n",
- buf);
- return ret;
- }
-
- ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
- if (ret)
- goto release_tpsram;
-
- ret = t3_set_proto_sram(adap, tpsram->data);
- if (ret)
- dev_err(dev, "loading protocol SRAM failed\n");
-
-release_tpsram:
- release_firmware(tpsram);
-
- return ret;
-}
-
-
/*
* Periodic accumulation of MAC statistics.
*/
@@ -2271,6 +2301,10 @@ void t3_fatal_err(struct adapter *adapter)
if (adapter->flags & FULL_INIT_DONE) {
t3_sge_stop(adapter);
+ t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
+ t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
+ t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
+ t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
t3_intr_disable(adapter);
}
CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
@@ -2330,10 +2364,12 @@ static void __devinit print_port_info(struct adapter *adap,
(adap->flags & USING_MSIX) ? " MSI-X" :
(adap->flags & USING_MSI) ? " MSI" : "");
if (adap->name == dev->name && adap->params.vpd.mclk)
- printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+ printk(KERN_INFO
+ "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
adap->name, t3_mc7_size(&adap->cm) >> 20,
t3_mc7_size(&adap->pmtx) >> 20,
- t3_mc7_size(&adap->pmrx) >> 20);
+ t3_mc7_size(&adap->pmrx) >> 20,
+ adap->params.vpd.sn);
}
}
@@ -2429,11 +2465,11 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
adapter->port[i] = netdev;
pi = netdev_priv(netdev);
+ pi->adapter = adapter;
pi->rx_csum_offload = 1;
pi->nqsets = 1;
pi->first_qset = i;
@@ -2443,7 +2479,6 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->irq = pdev->irq;
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len - 1;
- netdev->priv = adapter;
netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
netdev->features |= NETIF_F_LLTX;
if (pci_using_dac)
@@ -2463,23 +2498,15 @@ static int __devinit init_one(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = cxgb_netpoll;
#endif
- netdev->weight = 64;
SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
}
- pci_set_drvdata(pdev, adapter->port[0]);
+ pci_set_drvdata(pdev, adapter);
if (t3_prep_adapter(adapter, ai, 1) < 0) {
err = -ENODEV;
goto out_free_dev;
}
-
- err = t3_check_tpsram_version(adapter);
- if (err == -EINVAL)
- err = update_tpsram(adapter);
-
- if (err)
- goto out_free_dev;
/*
* The card is now ready to go. If any errors occur during device
@@ -2548,11 +2575,10 @@ out_release_regions:
static void __devexit remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
+ struct adapter *adapter = pci_get_drvdata(pdev);
- if (dev) {
+ if (adapter) {
int i;
- struct adapter *adapter = dev->priv;
t3_sge_stop(adapter);
sysfs_remove_group(&adapter->port[0]->dev.kobj,
@@ -2572,12 +2598,6 @@ static void __devexit remove_one(struct pci_dev *pdev)
t3_free_sge_resources(adapter);
cxgb_disable_msi(adapter);
- for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
- if (adapter->dummy_netdev[i]) {
- free_netdev(adapter->dummy_netdev[i]);
- adapter->dummy_netdev[i] = NULL;
- }
-
for_each_port(adapter, i)
if (adapter->port[i])
free_netdev(adapter->port[i]);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index ebcf35e4cf5b..bd25421bc12a 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -57,7 +57,7 @@ static DEFINE_RWLOCK(adapter_list_lock);
static LIST_HEAD(adapter_list);
static const unsigned int MAX_ATIDS = 64 * 1024;
-static const unsigned int ATID_BASE = 0x100000;
+static const unsigned int ATID_BASE = 0x10000;
static inline int offload_activated(struct t3cdev *tdev)
{
@@ -222,32 +222,32 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
int ret = 0;
switch (req) {
- case RDMA_GET_PARAMS:{
- struct rdma_info *req = data;
+ case RDMA_GET_PARAMS: {
+ struct rdma_info *rdma = data;
struct pci_dev *pdev = adapter->pdev;
- req->udbell_physbase = pci_resource_start(pdev, 2);
- req->udbell_len = pci_resource_len(pdev, 2);
- req->tpt_base =
+ rdma->udbell_physbase = pci_resource_start(pdev, 2);
+ rdma->udbell_len = pci_resource_len(pdev, 2);
+ rdma->tpt_base =
t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
- req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
- req->pbl_base =
+ rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+ rdma->pbl_base =
t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
- req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
- req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
- req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
- req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
- req->pdev = pdev;
+ rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+ rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+ rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+ rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+ rdma->pdev = pdev;
break;
}
case RDMA_CQ_OP:{
unsigned long flags;
- struct rdma_cq_op *req = data;
+ struct rdma_cq_op *rdma = data;
/* may be called in any context */
spin_lock_irqsave(&adapter->sge.reg_lock, flags);
- ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
- req->credits);
+ ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op,
+ rdma->credits);
spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
break;
}
@@ -274,15 +274,15 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
break;
}
case RDMA_CQ_SETUP:{
- struct rdma_cq_setup *req = data;
+ struct rdma_cq_setup *rdma = data;
spin_lock_irq(&adapter->sge.reg_lock);
ret =
- t3_sge_init_cqcntxt(adapter, req->id,
- req->base_addr, req->size,
+ t3_sge_init_cqcntxt(adapter, rdma->id,
+ rdma->base_addr, rdma->size,
ASYNC_NOTIF_RSPQ,
- req->ovfl_mode, req->credits,
- req->credit_thres);
+ rdma->ovfl_mode, rdma->credits,
+ rdma->credit_thres);
spin_unlock_irq(&adapter->sge.reg_lock);
break;
}
@@ -292,13 +292,13 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
spin_unlock_irq(&adapter->sge.reg_lock);
break;
case RDMA_CTRL_QP_SETUP:{
- struct rdma_ctrlqp_setup *req = data;
+ struct rdma_ctrlqp_setup *rdma = data;
spin_lock_irq(&adapter->sge.reg_lock);
ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
SGE_CNTXT_RDMA,
ASYNC_NOTIF_RSPQ,
- req->base_addr, req->size,
+ rdma->base_addr, rdma->size,
FW_RI_TID_START, 1, 0);
spin_unlock_irq(&adapter->sge.reg_lock);
break;
@@ -317,6 +317,8 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
struct iff_mac *iffmacp;
struct ddp_params *ddpp;
struct adap_ports *ports;
+ struct ofld_page_info *rx_page_info;
+ struct tp_params *tp = &adapter->params.tp;
int i;
switch (req) {
@@ -382,6 +384,11 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
if (!offload_running(adapter))
return -EAGAIN;
return cxgb_rdma_ctl(adapter, req, data);
+ case GET_RX_PAGE_INFO:
+ rx_page_info = data;
+ rx_page_info->page_size = tp->rx_pg_size;
+ rx_page_info->num = tp->rx_num_pgs;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -593,6 +600,16 @@ int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
EXPORT_SYMBOL(cxgb3_alloc_stid);
+/* Get the t3cdev associated with a net_device */
+struct t3cdev *dev2t3cdev(struct net_device *dev)
+{
+ const struct port_info *pi = netdev_priv(dev);
+
+ return (struct t3cdev *)pi->adapter;
+}
+
+EXPORT_SYMBOL(dev2t3cdev);
+
static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
{
struct cpl_smt_write_rpl *rpl = cplhdr(skb);
@@ -677,10 +694,19 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
{
struct cpl_pass_accept_req *req = cplhdr(skb);
unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
struct t3c_tid_entry *t3c_tid;
+ unsigned int tid = GET_TID(req);
- t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
- if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ if (unlikely(tid >= t->ntids)) {
+ printk("%s: passive open TID %u too large\n",
+ dev->name, tid);
+ t3_fatal_err(tdev2adap(dev));
+ return CPL_RET_BUF_DONE;
+ }
+
+ t3c_tid = lookup_stid(t, stid);
+ if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
(dev, skb, t3c_tid->ctx);
@@ -699,7 +725,7 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
* the buffer.
*/
static struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len,
- int gfp)
+ gfp_t gfp)
{
if (likely(!skb_cloned(skb))) {
BUG_ON(skb->len < len);
@@ -762,16 +788,25 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
{
struct cpl_act_establish *req = cplhdr(skb);
unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
struct t3c_tid_entry *t3c_tid;
+ unsigned int tid = GET_TID(req);
- t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (unlikely(tid >= t->ntids)) {
+ printk("%s: active establish TID %u too large\n",
+ dev->name, tid);
+ t3_fatal_err(tdev2adap(dev));
+ return CPL_RET_BUF_DONE;
+ }
+
+ t3c_tid = lookup_atid(t, atid);
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
(dev, skb, t3c_tid->ctx);
} else {
printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
- dev->name, CPL_PASS_ACCEPT_REQ);
+ dev->name, CPL_ACT_ESTABLISH);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
}
@@ -925,7 +960,7 @@ void cxgb_neigh_update(struct neighbour *neigh)
struct net_device *dev = neigh->dev;
if (dev && (is_offloading(dev))) {
- struct t3cdev *tdev = T3CDEV(dev);
+ struct t3cdev *tdev = dev2t3cdev(dev);
BUG_ON(!tdev);
t3_l2t_update(tdev, neigh);
@@ -973,9 +1008,9 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
"device ignored.\n", __FUNCTION__);
return;
}
- tdev = T3CDEV(olddev);
+ tdev = dev2t3cdev(olddev);
BUG_ON(!tdev);
- if (tdev != T3CDEV(newdev)) {
+ if (tdev != dev2t3cdev(newdev)) {
printk(KERN_WARNING "%s: Redirect to different "
"offload device ignored.\n", __FUNCTION__);
return;
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
index f15446a32efc..7a379138b5a6 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -51,6 +51,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter);
void cxgb3_set_dummy_ops(struct t3cdev *dev);
+struct t3cdev *dev2t3cdev(struct net_device *dev);
+
/*
* Client registration. Users of T3 driver must register themselves.
* The T3 driver will call the add function of every client for each T3
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index aa80313c922e..5e1bc0dec5f1 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -172,6 +172,14 @@
#define A_SG_INT_CAUSE 0x5c
+#define S_HIPIODRBDROPERR 11
+#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR)
+#define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U)
+
+#define S_LOPIODRBDROPERR 10
+#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR)
+#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U)
+
#define S_RSPQDISABLED 3
#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
#define F_RSPQDISABLED V_RSPQDISABLED(1U)
@@ -1318,6 +1326,7 @@
#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
#define A_PM1_RX_CFG 0x5c0
+#define A_PM1_RX_MODE 0x5c4
#define A_PM1_RX_INT_ENABLE 0x5d8
@@ -1386,6 +1395,7 @@
#define A_PM1_RX_INT_CAUSE 0x5dc
#define A_PM1_TX_CFG 0x5e0
+#define A_PM1_TX_MODE 0x5e4
#define A_PM1_TX_INT_ENABLE 0x5f8
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index a2cfd68ac757..994b5d6404df 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -79,7 +79,7 @@ enum {
};
struct tx_desc {
- u64 flit[TX_DESC_FLITS];
+ __be64 flit[TX_DESC_FLITS];
};
struct rx_desc {
@@ -544,7 +544,7 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
* as HW contexts, packet buffers, and descriptor rings. Traffic to the
* queue set must be quiesced prior to calling this.
*/
-void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+static void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
{
int i;
struct pci_dev *pdev = adapter->pdev;
@@ -591,9 +591,6 @@ void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
q->rspq.desc, q->rspq.phys_addr);
}
- if (q->netdev)
- q->netdev->atalk_ptr = NULL;
-
memset(q, 0, sizeof(*q));
}
@@ -907,8 +904,8 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
const struct sge_txq *q,
const struct sg_ent *sgl,
unsigned int flits, unsigned int sgl_flits,
- unsigned int gen, unsigned int wr_hi,
- unsigned int wr_lo)
+ unsigned int gen, __be32 wr_hi,
+ __be32 wr_lo)
{
struct work_request_hdr *wrp = (struct work_request_hdr *)d;
struct tx_sw_desc *sd = &q->sdesc[pidx];
@@ -1073,8 +1070,8 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned int ndesc, pidx, credits, gen, compl;
const struct port_info *pi = netdev_priv(dev);
- struct adapter *adap = dev->priv;
- struct sge_qset *qs = dev2qset(dev);
+ struct adapter *adap = pi->adapter;
+ struct sge_qset *qs = pi->qs;
struct sge_txq *q = &qs->txq[TXQ_ETH];
/*
@@ -1182,8 +1179,8 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
*
* Writes a packet as immediate data into a Tx descriptor. The packet
* contains a work request at its beginning. We must write the packet
- * carefully so the SGE doesn't read accidentally before it's written in
- * its entirety.
+ * carefully so the SGE doesn't read it accidentally before it's written
+ * in its entirety.
*/
static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
unsigned int len, unsigned int gen)
@@ -1191,7 +1188,11 @@ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
struct work_request_hdr *to = (struct work_request_hdr *)d;
- memcpy(&to[1], &from[1], len - sizeof(*from));
+ if (likely(!skb->data_len))
+ memcpy(&to[1], &from[1], len - sizeof(*from));
+ else
+ skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from));
+
to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
V_WR_BCNTLFLT(len & 7));
wmb();
@@ -1261,7 +1262,7 @@ static inline void reclaim_completed_tx_imm(struct sge_txq *q)
static inline int immediate(const struct sk_buff *skb)
{
- return skb->len <= WR_LEN && !skb->data_len;
+ return skb->len <= WR_LEN;
}
/**
@@ -1326,12 +1327,12 @@ static void restart_ctrlq(unsigned long data)
struct sk_buff *skb;
struct sge_qset *qs = (struct sge_qset *)data;
struct sge_txq *q = &qs->txq[TXQ_CTRL];
- struct adapter *adap = qs->netdev->priv;
spin_lock(&q->lock);
again:reclaim_completed_tx_imm(q);
- while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+ while (q->in_use < q->size &&
+ (skb = __skb_dequeue(&q->sendq)) != NULL) {
write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
@@ -1353,7 +1354,7 @@ static void restart_ctrlq(unsigned long data)
}
spin_unlock(&q->lock);
- t3_write_reg(adap, A_SG_KDOORBELL,
+ t3_write_reg(qs->adap, A_SG_KDOORBELL,
F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
}
@@ -1467,12 +1468,13 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
*/
static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
{
- unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+ unsigned int flits, cnt;
- if (skb->len <= WR_LEN && cnt == 0)
+ if (skb->len <= WR_LEN)
return 1; /* packet fits as immediate data */
flits = skb_transport_offset(skb) / 8; /* headers */
+ cnt = skb_shinfo(skb)->nr_frags;
if (skb->tail != skb->transport_header)
cnt++;
return flits_to_desc(flits + sgl_len(cnt));
@@ -1531,7 +1533,8 @@ static void restart_offloadq(unsigned long data)
struct sk_buff *skb;
struct sge_qset *qs = (struct sge_qset *)data;
struct sge_txq *q = &qs->txq[TXQ_OFLD];
- struct adapter *adap = qs->netdev->priv;
+ const struct port_info *pi = netdev_priv(qs->netdev);
+ struct adapter *adap = pi->adapter;
spin_lock(&q->lock);
again:reclaim_completed_tx(adap, q);
@@ -1636,8 +1639,7 @@ static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
else {
struct sge_qset *qs = rspq_to_qset(q);
- if (__netif_rx_schedule_prep(qs->netdev))
- __netif_rx_schedule(qs->netdev);
+ napi_schedule(&qs->napi);
q->rx_head = skb;
}
q->rx_tail = skb;
@@ -1673,33 +1675,30 @@ static inline void deliver_partial_bundle(struct t3cdev *tdev,
* receive handler. Batches need to be of modest size as we do prefetches
* on the packets in each.
*/
-static int ofld_poll(struct net_device *dev, int *budget)
+static int ofld_poll(struct napi_struct *napi, int budget)
{
- struct adapter *adapter = dev->priv;
- struct sge_qset *qs = dev2qset(dev);
+ struct sge_qset *qs = container_of(napi, struct sge_qset, napi);
struct sge_rspq *q = &qs->rspq;
- int work_done, limit = min(*budget, dev->quota), avail = limit;
+ struct adapter *adapter = qs->adap;
+ int work_done = 0;
- while (avail) {
+ while (work_done < budget) {
struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
int ngathered;
spin_lock_irq(&q->lock);
head = q->rx_head;
if (!head) {
- work_done = limit - avail;
- *budget -= work_done;
- dev->quota -= work_done;
- __netif_rx_complete(dev);
+ napi_complete(napi);
spin_unlock_irq(&q->lock);
- return 0;
+ return work_done;
}
tail = q->rx_tail;
q->rx_head = q->rx_tail = NULL;
spin_unlock_irq(&q->lock);
- for (ngathered = 0; avail && head; avail--) {
+ for (ngathered = 0; work_done < budget && head; work_done++) {
prefetch(head->data);
skbs[ngathered] = head;
head = head->next;
@@ -1721,10 +1720,8 @@ static int ofld_poll(struct net_device *dev, int *budget)
}
deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
}
- work_done = limit - avail;
- *budget -= work_done;
- dev->quota -= work_done;
- return 1;
+
+ return work_done;
}
/**
@@ -2068,49 +2065,47 @@ static inline int is_pure_response(const struct rsp_desc *r)
/**
* napi_rx_handler - the NAPI handler for Rx processing
- * @dev: the net device
+ * @napi: the napi instance
* @budget: how many packets we can process in this round
*
* Handler for new data events when using NAPI.
*/
-static int napi_rx_handler(struct net_device *dev, int *budget)
+static int napi_rx_handler(struct napi_struct *napi, int budget)
{
- struct adapter *adap = dev->priv;
- struct sge_qset *qs = dev2qset(dev);
- int effective_budget = min(*budget, dev->quota);
-
- int work_done = process_responses(adap, qs, effective_budget);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done >= effective_budget)
- return 1;
+ struct sge_qset *qs = container_of(napi, struct sge_qset, napi);
+ struct adapter *adap = qs->adap;
+ int work_done = process_responses(adap, qs, budget);
- netif_rx_complete(dev);
+ if (likely(work_done < budget)) {
+ napi_complete(napi);
- /*
- * Because we don't atomically flush the following write it is
- * possible that in very rare cases it can reach the device in a way
- * that races with a new response being written plus an error interrupt
- * causing the NAPI interrupt handler below to return unhandled status
- * to the OS. To protect against this would require flushing the write
- * and doing both the write and the flush with interrupts off. Way too
- * expensive and unjustifiable given the rarity of the race.
- *
- * The race cannot happen at all with MSI-X.
- */
- t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
- V_NEWTIMER(qs->rspq.next_holdoff) |
- V_NEWINDEX(qs->rspq.cidx));
- return 0;
+ /*
+ * Because we don't atomically flush the following
+ * write it is possible that in very rare cases it can
+ * reach the device in a way that races with a new
+ * response being written plus an error interrupt
+ * causing the NAPI interrupt handler below to return
+ * unhandled status to the OS. To protect against
+ * this would require flushing the write and doing
+ * both the write and the flush with interrupts off.
+ * Way too expensive and unjustifiable given the
+ * rarity of the race.
+ *
+ * The race cannot happen at all with MSI-X.
+ */
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+ V_NEWTIMER(qs->rspq.next_holdoff) |
+ V_NEWINDEX(qs->rspq.cidx));
+ }
+ return work_done;
}
/*
* Returns true if the device is already scheduled for polling.
*/
-static inline int napi_is_scheduled(struct net_device *dev)
+static inline int napi_is_scheduled(struct napi_struct *napi)
{
- return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+ return test_bit(NAPI_STATE_SCHED, &napi->state);
}
/**
@@ -2193,8 +2188,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
return 0;
}
- if (likely(__netif_rx_schedule_prep(qs->netdev)))
- __netif_rx_schedule(qs->netdev);
+ napi_schedule(&qs->napi);
return 1;
}
@@ -2205,7 +2199,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
{
struct sge_qset *qs = cookie;
- struct adapter *adap = qs->netdev->priv;
+ struct adapter *adap = qs->adap;
struct sge_rspq *q = &qs->rspq;
spin_lock(&q->lock);
@@ -2221,15 +2215,14 @@ irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
* The MSI-X interrupt handler for an SGE response queue for the NAPI case
* (i.e., response queue serviced by NAPI polling).
*/
-irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
{
struct sge_qset *qs = cookie;
- struct adapter *adap = qs->netdev->priv;
struct sge_rspq *q = &qs->rspq;
spin_lock(&q->lock);
- if (handle_responses(adap, q) < 0)
+ if (handle_responses(qs->adap, q) < 0)
q->unhandled_irqs++;
spin_unlock(&q->lock);
return IRQ_HANDLED;
@@ -2272,11 +2265,13 @@ static irqreturn_t t3_intr_msi(int irq, void *cookie)
return IRQ_HANDLED;
}
-static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+static int rspq_check_napi(struct sge_qset *qs)
{
- if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
- if (likely(__netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
+ struct sge_rspq *q = &qs->rspq;
+
+ if (!napi_is_scheduled(&qs->napi) &&
+ is_new_response(&q->desc[q->cidx], q)) {
+ napi_schedule(&qs->napi);
return 1;
}
return 0;
@@ -2289,7 +2284,7 @@ static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
* one SGE response queue per port in this mode and protect all response
* queues with queue 0's lock.
*/
-irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+static irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
{
int new_packets;
struct adapter *adap = cookie;
@@ -2297,10 +2292,9 @@ irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
spin_lock(&q->lock);
- new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+ new_packets = rspq_check_napi(&adap->sge.qs[0]);
if (adap->params.nports == 2)
- new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
- &adap->sge.qs[1].rspq);
+ new_packets += rspq_check_napi(&adap->sge.qs[1]);
if (!new_packets && t3_slow_intr_handler(adap) == 0)
q->unhandled_irqs++;
@@ -2403,9 +2397,9 @@ static irqreturn_t t3b_intr(int irq, void *cookie)
static irqreturn_t t3b_intr_napi(int irq, void *cookie)
{
u32 map;
- struct net_device *dev;
struct adapter *adap = cookie;
- struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+ struct sge_qset *qs0 = &adap->sge.qs[0];
+ struct sge_rspq *q0 = &qs0->rspq;
t3_write_reg(adap, A_PL_CLI, 0);
map = t3_read_reg(adap, A_SG_DATA_INTR);
@@ -2418,18 +2412,11 @@ static irqreturn_t t3b_intr_napi(int irq, void *cookie)
if (unlikely(map & F_ERRINTR))
t3_slow_intr_handler(adap);
- if (likely(map & 1)) {
- dev = adap->sge.qs[0].netdev;
-
- if (likely(__netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
- }
- if (map & 2) {
- dev = adap->sge.qs[1].netdev;
+ if (likely(map & 1))
+ napi_schedule(&qs0->napi);
- if (likely(__netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
- }
+ if (map & 2)
+ napi_schedule(&adap->sge.qs[1].napi);
spin_unlock(&q0->lock);
return IRQ_HANDLED;
@@ -2476,6 +2463,10 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
"(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
}
+ if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR))
+ CH_ALERT(adapter, "SGE dropped %s priority doorbell\n",
+ status & F_HIPIODRBDROPERR ? "high" : "lo");
+
t3_write_reg(adapter, A_SG_INT_CAUSE, status);
if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
t3_fatal_err(adapter);
@@ -2508,7 +2499,7 @@ static void sge_timer_cb(unsigned long data)
{
spinlock_t *lock;
struct sge_qset *qs = (struct sge_qset *)data;
- struct adapter *adap = qs->netdev->priv;
+ struct adapter *adap = qs->adap;
if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
@@ -2519,9 +2510,9 @@ static void sge_timer_cb(unsigned long data)
spin_unlock(&qs->txq[TXQ_OFLD].lock);
}
lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
- &adap->sge.qs[0].rspq.lock;
+ &adap->sge.qs[0].rspq.lock;
if (spin_trylock_irq(lock)) {
- if (!napi_is_scheduled(qs->netdev)) {
+ if (!napi_is_scheduled(&qs->napi)) {
u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
if (qs->fl[0].credits < qs->fl[0].size)
@@ -2555,12 +2546,9 @@ static void sge_timer_cb(unsigned long data)
*/
void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
{
- if (!qs->netdev)
- return;
-
qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
qs->rspq.polling = p->polling;
- qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+ qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll;
}
/**
@@ -2580,7 +2568,7 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
*/
int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int irq_vec_idx, const struct qset_params *p,
- int ntxq, struct net_device *netdev)
+ int ntxq, struct net_device *dev)
{
int i, ret = -ENOMEM;
struct sge_qset *q = &adapter->sge.qs[id];
@@ -2701,16 +2689,10 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
}
spin_unlock(&adapter->sge.reg_lock);
- q->netdev = netdev;
- t3_update_qset_coalesce(q, p);
- /*
- * We use atalk_ptr as a backpointer to a qset. In case a device is
- * associated with multiple queue sets only the first one sets
- * atalk_ptr.
- */
- if (netdev->atalk_ptr == NULL)
- netdev->atalk_ptr = q;
+ q->adap = adapter;
+ q->netdev = dev;
+ t3_update_qset_coalesce(q, p);
refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
index 514869e26a76..29b6c800b238 100644
--- a/drivers/net/cxgb3/sge_defs.h
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -106,6 +106,10 @@
#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
#define F_CQ_GEN V_CQ_GEN(1U)
+#define S_CQ_ERR 30
+#define V_CQ_ERR(x) ((x) << S_CQ_ERR)
+#define F_CQ_ERR V_CQ_ERR(1U)
+
#define S_CQ_OVERFLOW_MODE 31
#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U)
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index dd3149d94ba8..d4ee00d32219 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -119,9 +119,9 @@ void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
* Reads registers that are accessed indirectly through an address/data
* register pair.
*/
-void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
- unsigned int data_reg, u32 *vals, unsigned int nregs,
- unsigned int start_idx)
+static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+ unsigned int data_reg, u32 *vals,
+ unsigned int nregs, unsigned int start_idx)
{
while (nregs--) {
t3_write_reg(adap, addr_reg, start_idx);
@@ -505,7 +505,7 @@ struct t3_vpd {
u8 vpdr_len[2];
VPD_ENTRY(pn, 16); /* part number */
VPD_ENTRY(ec, 16); /* EC level */
- VPD_ENTRY(sn, 16); /* serial number */
+ VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
VPD_ENTRY(na, 12); /* MAC address base */
VPD_ENTRY(cclk, 6); /* core clock */
VPD_ENTRY(mclk, 6); /* mem clock */
@@ -648,6 +648,7 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+ memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
/* Old eeproms didn't have port information */
if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
@@ -848,16 +849,15 @@ static int t3_write_flash(struct adapter *adapter, unsigned int addr,
}
/**
- * t3_check_tpsram_version - read the tp sram version
+ * t3_get_tp_version - read the tp sram version
* @adapter: the adapter
+ * @vers: where to place the version
*
- * Reads the protocol sram version from serial eeprom.
+ * Reads the protocol sram version from sram.
*/
-int t3_check_tpsram_version(struct adapter *adapter)
+int t3_get_tp_version(struct adapter *adapter, u32 *vers)
{
int ret;
- u32 vers;
- unsigned int major, minor;
/* Get version loaded in SRAM */
t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
@@ -866,7 +866,32 @@ int t3_check_tpsram_version(struct adapter *adapter)
if (ret)
return ret;
- vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+ *vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+
+ return 0;
+}
+
+/**
+ * t3_check_tpsram_version - read the tp sram version
+ * @adapter: the adapter
+ * @must_load: set to 1 if loading a new microcode image is required
+ *
+ * Reads the protocol sram version from flash.
+ */
+int t3_check_tpsram_version(struct adapter *adapter, int *must_load)
+{
+ int ret;
+ u32 vers;
+ unsigned int major, minor;
+
+ if (adapter->params.rev == T3_REV_A)
+ return 0;
+
+ *must_load = 1;
+
+ ret = t3_get_tp_version(adapter, &vers);
+ if (ret)
+ return ret;
major = G_TP_VERSION_MAJOR(vers);
minor = G_TP_VERSION_MINOR(vers);
@@ -874,6 +899,16 @@ int t3_check_tpsram_version(struct adapter *adapter)
if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
return 0;
+ if (major != TP_VERSION_MAJOR)
+ CH_ERR(adapter, "found wrong TP version (%u.%u), "
+ "driver needs version %d.%d\n", major, minor,
+ TP_VERSION_MAJOR, TP_VERSION_MINOR);
+ else {
+ *must_load = 0;
+ CH_ERR(adapter, "found wrong TP version (%u.%u), "
+ "driver compiled for version %d.%d\n", major, minor,
+ TP_VERSION_MAJOR, TP_VERSION_MINOR);
+ }
return -EINVAL;
}
@@ -925,16 +960,18 @@ int t3_get_fw_version(struct adapter *adapter, u32 *vers)
/**
* t3_check_fw_version - check if the FW is compatible with this driver
* @adapter: the adapter
- *
+ * @must_load: set to 1 if loading a new FW image is required
+
* Checks if an adapter's FW is compatible with the driver. Returns 0
* if the versions are compatible, a negative error otherwise.
*/
-int t3_check_fw_version(struct adapter *adapter)
+int t3_check_fw_version(struct adapter *adapter, int *must_load)
{
int ret;
u32 vers;
unsigned int type, major, minor;
+ *must_load = 1;
ret = t3_get_fw_version(adapter, &vers);
if (ret)
return ret;
@@ -947,9 +984,17 @@ int t3_check_fw_version(struct adapter *adapter)
minor == FW_VERSION_MINOR)
return 0;
- CH_ERR(adapter, "found wrong FW version(%u.%u), "
- "driver needs version %u.%u\n", major, minor,
- FW_VERSION_MAJOR, FW_VERSION_MINOR);
+ if (major != FW_VERSION_MAJOR)
+ CH_ERR(adapter, "found wrong FW version(%u.%u), "
+ "driver needs version %u.%u\n", major, minor,
+ FW_VERSION_MAJOR, FW_VERSION_MINOR);
+ else {
+ *must_load = 0;
+ CH_WARN(adapter, "found wrong FW minor version(%u.%u), "
+ "driver compiled for version %u.%u\n", major, minor,
+ FW_VERSION_MAJOR, FW_VERSION_MINOR);
+ }
+
return -EINVAL;
}
@@ -1313,6 +1358,10 @@ static void pcie_intr_handler(struct adapter *adapter)
{0}
};
+ if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
+ CH_ALERT(adapter, "PEX error code 0x%x\n",
+ t3_read_reg(adapter, A_PCIE_PEX_ERR));
+
if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
pcie_intr_info, adapter->irq_stats))
t3_fatal_err(adapter);
@@ -1764,6 +1813,8 @@ void t3_intr_clear(struct adapter *adapter)
for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+ if (is_pcie(adapter))
+ t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
}
@@ -1819,6 +1870,8 @@ void t3_port_intr_clear(struct adapter *adapter, int idx)
phy->ops->intr_clear(phy);
}
+#define SG_CONTEXT_CMD_ATTEMPTS 100
+
/**
* t3_sge_write_context - write an SGE context
* @adapter: the adapter
@@ -1838,7 +1891,7 @@ static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -1995,7 +2048,8 @@ int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
base_addr >>= 32;
t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
- V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+ V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
+ V_CQ_ERR(ovfl_mode));
t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
V_CQ_CREDIT_THRES(credit_thres));
return t3_sge_write_context(adapter, id, F_CQ);
@@ -2023,7 +2077,7 @@ int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2047,7 +2101,7 @@ int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2071,7 +2125,7 @@ int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2095,7 +2149,7 @@ int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2120,7 +2174,7 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
V_CONTEXT(id) | F_CQ);
if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1, &val))
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
return -EIO;
if (op >= 2 && op < 7) {
@@ -2130,7 +2184,8 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
- F_CONTEXT_CMD_BUSY, 0, 5, 1))
+ F_CONTEXT_CMD_BUSY, 0,
+ SG_CONTEXT_CMD_ATTEMPTS, 1))
return -EIO;
return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
}
@@ -2156,7 +2211,7 @@ static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
- 5, 1))
+ SG_CONTEXT_CMD_ATTEMPTS, 1))
return -EIO;
data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
@@ -3188,6 +3243,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
+ t3_write_reg(adapter, A_PM1_RX_MODE, 0);
+ t3_write_reg(adapter, A_PM1_TX_MODE, 0);
init_hw_for_avail_ports(adapter, adapter->params.nports);
t3_sge_init(adapter, &adapter->params.sge);
@@ -3350,7 +3407,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
* Older PCIe cards lose their config space during reset, PCI-X
* ones don't.
*/
-int t3_reset_adapter(struct adapter *adapter)
+static int t3_reset_adapter(struct adapter *adapter)
{
int i, save_and_restore_pcie =
adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
index fa4099bc0416..77fcc1a4984e 100644
--- a/drivers/net/cxgb3/t3cdev.h
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -42,9 +42,6 @@
#define T3CNAMSIZ 16
-/* Get the t3cdev associated with a net_device */
-#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
-
struct cxgb3_client;
enum t3ctype {
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index eb508bf8022a..ef1c6339c806 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -39,6 +39,6 @@
/* Firmware version */
#define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 3
+#define FW_VERSION_MINOR 6
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index c302b1a30cba..eeb766aeced9 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -142,7 +142,7 @@ int t3_mac_reset(struct cmac *mac)
return 0;
}
-int t3b2_mac_reset(struct cmac *mac)
+static int t3b2_mac_reset(struct cmac *mac)
{
struct adapter *adap = mac->adapter;
unsigned int oft = mac->offset;
@@ -437,12 +437,13 @@ int t3_mac_enable(struct cmac *mac, int which)
struct mac_stats *s = &mac->stats;
if (which & MAC_DIRECTION_TX) {
- t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+ t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
mac->tx_mcnt = s->tx_frames;
mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
@@ -451,9 +452,11 @@ int t3_mac_enable(struct cmac *mac, int which)
A_XGM_TX_SPI4_SOP_EOP_CNT +
oft)));
mac->rx_mcnt = s->rx_frames;
+ mac->rx_pause = s->rx_pause;
mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_RX_SPI4_SOP_EOP_CNT +
oft)));
+ mac->rx_ocnt = s->rx_fifo_ovfl;
mac->txen = F_TXEN;
mac->toggle_cnt = 0;
}
@@ -464,24 +467,19 @@ int t3_mac_enable(struct cmac *mac, int which)
int t3_mac_disable(struct cmac *mac, int which)
{
- int idx = macidx(mac);
struct adapter *adap = mac->adapter;
- int val;
if (which & MAC_DIRECTION_TX) {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
- t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
- t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
- t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
- t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
mac->txen = 0;
}
if (which & MAC_DIRECTION_RX) {
+ int val = F_MAC_RESET_;
+
t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
F_PCS_RESET_, 0);
msleep(100);
t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
- val = F_MAC_RESET_;
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
@@ -507,7 +505,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
tx_xcnt = 1; /* By default tx_xcnt is making progress */
tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */
rx_xcnt = 1; /* By default rx_xcnt is making progress */
- if (tx_mcnt == mac->tx_mcnt) {
+ if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_TX_SPI4_SOP_EOP_CNT +
mac->offset)));
@@ -524,10 +522,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
goto rxcheck;
}
- if (((tx_tcnt != mac->tx_tcnt) &&
- (tx_xcnt == 0) && (mac->tx_xcnt == 0)) ||
- ((mac->tx_mcnt == tx_mcnt) &&
- (tx_xcnt != 0) && (mac->tx_xcnt != 0))) {
+ if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
if (mac->toggle_cnt > 4) {
status = 2;
goto out;
@@ -541,11 +536,14 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
}
rxcheck:
- if (rx_mcnt != mac->rx_mcnt)
+ if (rx_mcnt != mac->rx_mcnt) {
rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_RX_SPI4_SOP_EOP_CNT +
- mac->offset)));
- else
+ mac->offset))) +
+ (s->rx_fifo_ovfl -
+ mac->rx_ocnt);
+ mac->rx_ocnt = s->rx_fifo_ovfl;
+ } else
goto out;
if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 &&
@@ -560,6 +558,7 @@ out:
mac->tx_mcnt = s->tx_frames;
mac->rx_xcnt = rx_xcnt;
mac->rx_mcnt = s->rx_frames;
+ mac->rx_pause = s->rx_pause;
if (status == 1) {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index dae97b860daa..cb849b091f98 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -154,11 +154,6 @@ static int de600_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
- return (struct net_device_stats *)(dev->priv);
-}
-
static inline void trigger_interrupt(struct net_device *dev)
{
de600_put_command(FLIP_IRQ);
@@ -308,7 +303,7 @@ static int de600_tx_intr(struct net_device *dev, int irq_status)
if (!(irq_status & TX_FAILED16)) {
tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
++free_tx_pages;
- ((struct net_device_stats *)(dev->priv))->tx_packets++;
+ dev->stats.tx_packets++;
netif_wake_queue(dev);
}
@@ -375,8 +370,8 @@ static void de600_rx_intr(struct net_device *dev)
/* update stats */
dev->last_rx = jiffies;
- ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
- ((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */
+ dev->stats.rx_packets++; /* count all receives */
+ dev->stats.rx_bytes += size; /* count all received bytes */
/*
* If any worth-while packets have been received, netif_rx()
@@ -389,12 +384,12 @@ static struct net_device * __init de600_probe(void)
int i;
struct net_device *dev;
int err;
+ DECLARE_MAC_BUF(mac);
- dev = alloc_etherdev(sizeof(struct net_device_stats));
+ dev = alloc_etherdev(0);
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
if (!request_region(DE600_IO, 3, "de600")) {
printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
@@ -444,12 +439,7 @@ static struct net_device * __init de600_probe(void)
goto out1;
}
- printk(", Ethernet Address: %02X", dev->dev_addr[0]);
- for (i = 1; i < ETH_ALEN; i++)
- printk(":%02X",dev->dev_addr[i]);
- printk("\n");
-
- dev->get_stats = get_stats;
+ printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr));
dev->open = de600_open;
dev->stop = de600_close;
diff --git a/drivers/net/de600.h b/drivers/net/de600.h
index 1288e48ba704..e80ecbabcf4e 100644
--- a/drivers/net/de600.h
+++ b/drivers/net/de600.h
@@ -121,7 +121,6 @@ static u8 de600_read_byte(unsigned char type, struct net_device *dev);
/* Put in the device structure. */
static int de600_open(struct net_device *dev);
static int de600_close(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* Dispatch from interrupts. */
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index dc4892426174..3f5190c654cf 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -216,7 +216,6 @@ MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)");
/* Put in the device structure. */
static int de620_open(struct net_device *);
static int de620_close(struct net_device *);
-static struct net_device_stats *get_stats(struct net_device *);
static void de620_set_multicast_list(struct net_device *);
static int de620_start_xmit(struct sk_buff *, struct net_device *);
@@ -480,16 +479,6 @@ static int de620_close(struct net_device *dev)
/*********************************************
*
- * Return current statistics
- *
- */
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
- return (struct net_device_stats *)(dev->priv);
-}
-
-/*********************************************
- *
* Set or clear the multicast filter for this adaptor.
* (no real multicast implemented for the DE-620, but she can be promiscuous...)
*
@@ -579,7 +568,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
if(!(using_txbuf == (TXBF0 | TXBF1)))
netif_wake_queue(dev);
- ((struct net_device_stats *)(dev->priv))->tx_packets++;
+ dev->stats.tx_packets++;
spin_unlock_irqrestore(&de620_lock, flags);
dev_kfree_skb (skb);
return 0;
@@ -660,7 +649,7 @@ static int de620_rx_intr(struct net_device *dev)
/* You win some, you lose some. And sometimes plenty... */
adapter_init(dev);
netif_wake_queue(dev);
- ((struct net_device_stats *)(dev->priv))->rx_over_errors++;
+ dev->stats.rx_over_errors++;
return 0;
}
@@ -680,7 +669,7 @@ static int de620_rx_intr(struct net_device *dev)
next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
de620_send_command(dev, W_DUMMY);
de620_set_register(dev, W_NPRF, next_rx_page);
- ((struct net_device_stats *)(dev->priv))->rx_over_errors++;
+ dev->stats.rx_over_errors++;
return 0;
}
next_rx_page = pagelink;
@@ -693,7 +682,7 @@ static int de620_rx_intr(struct net_device *dev)
skb = dev_alloc_skb(size+2);
if (skb == NULL) { /* Yeah, but no place to put it... */
printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
- ((struct net_device_stats *)(dev->priv))->rx_dropped++;
+ dev->stats.rx_dropped++;
}
else { /* Yep! Go get it! */
skb_reserve(skb,2); /* Align */
@@ -706,8 +695,8 @@ static int de620_rx_intr(struct net_device *dev)
netif_rx(skb); /* deliver it "upstairs" */
dev->last_rx = jiffies;
/* count all receives */
- ((struct net_device_stats *)(dev->priv))->rx_packets++;
- ((struct net_device_stats *)(dev->priv))->rx_bytes += size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += size;
}
}
@@ -818,13 +807,12 @@ struct net_device * __init de620_probe(int unit)
struct net_device *dev;
int err = -ENOMEM;
int i;
+ DECLARE_MAC_BUF(mac);
- dev = alloc_etherdev(sizeof(struct net_device_stats));
+ dev = alloc_etherdev(0);
if (!dev)
goto out;
- SET_MODULE_OWNER(dev);
-
spin_lock_init(&de620_lock);
/*
@@ -866,13 +854,14 @@ struct net_device * __init de620_probe(int unit)
}
/* else, got it! */
- printk(", Ethernet Address: %2.2X",
- dev->dev_addr[0] = nic_data.NodeID[0]);
+ dev->dev_addr[0] = nic_data.NodeID[0];
for (i = 1; i < ETH_ALEN; i++) {
- printk(":%2.2X", dev->dev_addr[i] = nic_data.NodeID[i]);
+ dev->dev_addr[i] = nic_data.NodeID[i];
dev->broadcast[i] = 0xff;
}
+ printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr));
+
printk(" (%dk RAM,",
(nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
@@ -881,7 +870,6 @@ struct net_device * __init de620_probe(int unit)
else
printk(" UTP)\n");
- dev->get_stats = get_stats;
dev->open = de620_open;
dev->stop = de620_close;
dev->hard_start_xmit = de620_start_xmit;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index b2577f40124e..00e0194bfef0 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -258,8 +258,6 @@ struct lance_private {
int rx_new, tx_new;
int rx_old, tx_old;
- struct net_device_stats stats;
-
unsigned short busmaster_regval;
struct timer_list multicast_timer;
@@ -583,22 +581,22 @@ static int lance_rx(struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
if (bits & LE_R1_BUF)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (bits & LE_R1_CRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (bits & LE_R1_OFL)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (bits & LE_R1_FRA)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (bits & LE_R1_EOP)
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
} else {
len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4;
skb = dev_alloc_skb(len + 2);
@@ -606,7 +604,7 @@ static int lance_rx(struct net_device *dev)
if (skb == 0) {
printk("%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
*rds_ptr(rd, mblength, lp->type) = 0;
*rds_ptr(rd, rmd1, lp->type) =
((lp->rx_buf_ptr_lnc[entry] >> 16) &
@@ -614,7 +612,7 @@ static int lance_rx(struct net_device *dev)
lp->rx_new = (entry + 1) & RX_RING_MOD_MASK;
return 0;
}
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
@@ -625,7 +623,7 @@ static int lance_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++;
}
/* Return the packet to the pool */
@@ -660,14 +658,14 @@ static void lance_tx(struct net_device *dev)
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) {
status = *tds_ptr(td, misc, lp->type);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & LE_T3_RTY)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
printk("%s: Carrier Lost\n", dev->name);
/* Stop the lance */
writereg(&ll->rap, LE_CSR0);
@@ -681,7 +679,7 @@ static void lance_tx(struct net_device *dev)
* transmitter, restart the adapter.
*/
if (status & (LE_T3_BUF | LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -702,13 +700,13 @@ static void lance_tx(struct net_device *dev)
/* One collision before packet was sent. */
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = (j + 1) & TX_RING_MOD_MASK;
}
@@ -754,10 +752,10 @@ static irqreturn_t lance_interrupt(const int irq, void *dev_id)
lance_tx(dev);
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (csr0 & LE_C0_MERR) {
printk("%s: Memory error, status %04x\n", dev->name, csr0);
@@ -912,7 +910,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = ETH_ZLEN;
}
- lp->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
entry = lp->tx_new;
*lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len);
@@ -938,13 +936,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
static void lance_load_multicast(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
@@ -1036,6 +1027,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type)
int i, ret;
unsigned long esar_base;
unsigned char *esar;
+ DECLARE_MAC_BUF(mac);
if (dec_lance_debug && version_printed++ == 0)
printk(version);
@@ -1223,28 +1215,26 @@ static int __init dec_lance_probe(struct device *bdev, const int type)
*/
switch (type) {
case ASIC_LANCE:
- printk("%s: IOASIC onboard LANCE, addr = ", name);
+ printk("%s: IOASIC onboard LANCE", name);
break;
case PMAD_LANCE:
- printk("%s: PMAD-AA, addr = ", name);
+ printk("%s: PMAD-AA", name);
break;
case PMAX_LANCE:
- printk("%s: PMAX onboard LANCE, addr = ", name);
+ printk("%s: PMAX onboard LANCE", name);
break;
}
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = esar[i * 4];
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':');
- }
- printk(" irq = %d\n", dev->irq);
+ printk(", addr = %s, irq = %d\n",
+ print_mac(mac, dev->dev_addr), dev->irq);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
dev->tx_timeout = &lance_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
/* lp->ll is the location of the registers for lance card */
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 7df23dc28190..b07613e61f53 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -200,6 +200,7 @@
/* Include files */
#include <linux/bitops.h>
+#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/eisa.h>
@@ -240,8 +241,6 @@ static char version[] __devinitdata =
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
-#define __unused __attribute__ ((unused))
-
#ifdef CONFIG_PCI
#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
#else
@@ -375,7 +374,7 @@ static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
{
- struct device __unused *bdev = bp->bus_dev;
+ struct device __maybe_unused *bdev = bp->bus_dev;
int dfx_bus_tc = DFX_BUS_TC(bdev);
int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
@@ -399,7 +398,7 @@ static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
{
- struct device __unused *bdev = bp->bus_dev;
+ struct device __maybe_unused *bdev = bp->bus_dev;
int dfx_bus_tc = DFX_BUS_TC(bdev);
int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
@@ -540,7 +539,6 @@ static int __devinit dfx_register(struct device *bdev)
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, bdev);
bp = netdev_priv(dev);
@@ -866,7 +864,7 @@ static void __devinit dfx_bus_uninit(struct net_device *dev)
static void __devinit dfx_bus_config_check(DFX_board_t *bp)
{
- struct device __unused *bdev = bp->bus_dev;
+ struct device __maybe_unused *bdev = bp->bus_dev;
int dfx_bus_eisa = DFX_BUS_EISA(bdev);
int status; /* return code from adapter port control call */
u32 host_data; /* LW data returned from port control call */
@@ -3624,8 +3622,8 @@ static void __devexit dfx_unregister(struct device *bdev)
}
-static int __devinit __unused dfx_dev_register(struct device *);
-static int __devexit __unused dfx_dev_unregister(struct device *);
+static int __devinit __maybe_unused dfx_dev_register(struct device *);
+static int __devexit __maybe_unused dfx_dev_unregister(struct device *);
#ifdef CONFIG_PCI
static int __devinit dfx_pci_register(struct pci_dev *,
@@ -3699,7 +3697,7 @@ static struct tc_driver dfx_tc_driver = {
};
#endif /* CONFIG_TC */
-static int __devinit __unused dfx_dev_register(struct device *dev)
+static int __devinit __maybe_unused dfx_dev_register(struct device *dev)
{
int status;
@@ -3709,7 +3707,7 @@ static int __devinit __unused dfx_dev_register(struct device *dev)
return status;
}
-static int __devexit __unused dfx_dev_unregister(struct device *dev)
+static int __devexit __maybe_unused dfx_dev_unregister(struct device *dev)
{
put_device(dev);
dfx_unregister(dev);
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 183497020bfc..ace39ec0a367 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -485,7 +485,6 @@ struct depca_private {
/* Kernel-only (not device) fields */
int rx_new, tx_new; /* The next free ring entry */
int rx_old, tx_old; /* The ring entries to be free()ed. */
- struct net_device_stats stats;
spinlock_t lock;
struct { /* Private stats counters */
u32 bins[DEPCA_PKT_STAT_SZ];
@@ -522,7 +521,6 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id);
static int depca_close(struct net_device *dev);
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void depca_tx_timeout(struct net_device *dev);
-static struct net_device_stats *depca_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
/*
@@ -575,6 +573,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
s16 nicsr;
u_long ioaddr;
u_long mem_start;
+ DECLARE_MAC_BUF(mac);
/*
* We are now supposed to enter this function with the
@@ -634,14 +633,11 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
printk(", h/w address ");
status = get_hw_addr(dev);
+ printk("%s", print_mac(mac, dev->dev_addr));
if (status != 0) {
printk(" which has an Ethernet PROM CRC error.\n");
return -ENXIO;
}
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x", dev->dev_addr[i]);
/* Set up the maximum amount of network RAM(kB) */
netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
@@ -801,7 +797,6 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
dev->open = &depca_open;
dev->hard_start_xmit = &depca_start_xmit;
dev->stop = &depca_close;
- dev->get_stats = &depca_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &depca_ioctl;
dev->tx_timeout = depca_tx_timeout;
@@ -1026,15 +1021,15 @@ static int depca_rx(struct net_device *dev)
}
if (status & R_ENP) { /* Valid frame status */
if (status & R_ERR) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
+ dev->stats.rx_errors++; /* Update the error stats. */
if (status & R_FRAM)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & R_OFLO)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (status & R_CRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & R_BUFF)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
} else {
short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
struct sk_buff *skb;
@@ -1063,8 +1058,8 @@ static int depca_rx(struct net_device *dev)
** Update stats
*/
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
lp->pktStats.bins[i]++;
@@ -1087,7 +1082,7 @@ static int depca_rx(struct net_device *dev)
}
} else {
printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
+ dev->stats.rx_dropped++; /* Really, deferred. */
break;
}
}
@@ -1125,24 +1120,24 @@ static int depca_tx(struct net_device *dev)
break;
} else if (status & T_ERR) { /* An error occurred. */
status = readl(&lp->tx_ring[entry].misc);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & TMD3_RTRY)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & TMD3_LCAR)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (status & TMD3_LCOL)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (status & TMD3_UFLO)
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (status & (TMD3_BUFF | TMD3_UFLO)) {
/* Trigger an immediate send demand. */
outw(CSR0, DEPCA_ADDR);
outw(INEA | TDMD, DEPCA_DATA);
}
} else if (status & (T_MORE | T_ONE)) {
- lp->stats.collisions++;
+ dev->stats.collisions++;
} else {
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
/* Update all the pointers */
@@ -1234,15 +1229,6 @@ static int InitRestartDepca(struct net_device *dev)
return status;
}
-static struct net_device_stats *depca_get_stats(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *) dev->priv;
-
- /* Null body since there is no framing error counter */
-
- return &lp->stats;
-}
-
/*
** Set or clear the multicast filter for this adaptor.
*/
@@ -1855,6 +1841,7 @@ static void depca_dbg_open(struct net_device *dev)
u_long ioaddr = dev->base_addr;
struct depca_init *p = &lp->init_block;
int i;
+ DECLARE_MAC_BUF(mac);
if (depca_debug > 1) {
/* Do not copy the shadow init block into shared memory */
@@ -1893,11 +1880,7 @@ static void depca_dbg_open(struct net_device *dev)
printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
printk(" mode: 0x%4.4x\n", p->mode);
- printk(" physical address: ");
- for (i = 0; i < ETH_ALEN - 1; i++) {
- printk("%2.2x:", p->phys_addr[i]);
- }
- printk("%2.2x\n", p->phys_addr[i]);
+ printk(" physical address: %s\n", print_mac(mac, p->phys_addr));
printk(" multicast hash table: ");
for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
printk("%2.2x:", p->mcast_table[i]);
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
deleted file mode 100644
index df62c0232f36..000000000000
--- a/drivers/net/dgrs.c
+++ /dev/null
@@ -1,1615 +0,0 @@
-/*
- * Digi RightSwitch SE-X loadable device driver for Linux
- *
- * The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and
- * a NIC on an internal board.
- *
- * Author: Rick Richardson, rick@remotepoint.com
- * Derived from the SVR4.2 (UnixWare) driver for the same card.
- *
- * Copyright 1995-1996 Digi International Inc.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For information on purchasing a RightSwitch SE-4 or SE-6
- * board, please contact Digi's sales department at 1-612-912-3444
- * or 1-800-DIGIBRD. Outside the U.S., please check our Web page
- * at http://www.dgii.com for sales offices worldwide.
- *
- * OPERATION:
- * When compiled as a loadable module, this driver can operate
- * the board as either a 4/6 port switch with a 5th or 7th port
- * that is a conventional NIC interface as far as the host is
- * concerned, OR as 4/6 independent NICs. To select multi-NIC
- * mode, add "nicmode=1" on the insmod load line for the driver.
- *
- * This driver uses the "dev" common ethernet device structure
- * and a private "priv" (dev->priv) structure that contains
- * mostly DGRS-specific information and statistics. To keep
- * the code for both the switch mode and the multi-NIC mode
- * as similar as possible, I have introduced the concept of
- * "dev0"/"priv0" and "devN"/"privN" pointer pairs in subroutines
- * where needed. The first pair of pointers points to the
- * "dev" and "priv" structures of the zeroth (0th) device
- * interface associated with a board. The second pair of
- * pointers points to the current (Nth) device interface
- * for the board: the one for which we are processing data.
- *
- * In switch mode, the pairs of pointers are always the same,
- * that is, dev0 == devN and priv0 == privN. This is just
- * like previous releases of this driver which did not support
- * NIC mode.
- *
- * In multi-NIC mode, the pairs of pointers may be different.
- * We use the devN and privN pointers to reference just the
- * name, port number, and statistics for the current interface.
- * We use the dev0 and priv0 pointers to access the variables
- * that control access to the board, such as board address
- * and simulated 82596 variables. This is because there is
- * only one "fake" 82596 that serves as the interface to
- * the board. We do not want to try to keep the variables
- * associated with this 82596 in sync across all devices.
- *
- * This scheme works well. As you will see, except for
- * initialization, there is very little difference between
- * the two modes as far as this driver is concerned. On the
- * receive side in NIC mode, the interrupt *always* comes in on
- * the 0th interface (dev0/priv0). We then figure out which
- * real 82596 port it came in on from looking at the "chan"
- * member that the board firmware adds at the end of each
- * RBD (a.k.a. TBD). We get the channel number like this:
- * int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
- *
- * On the transmit side in multi-NIC mode, we specify the
- * output 82596 port by setting the new "dstchan" structure
- * member that is at the end of the RFD, like this:
- * priv0->rfdp->dstchan = privN->chan;
- *
- * TODO:
- * - Multi-NIC mode is not yet supported when the driver is linked
- * into the kernel.
- * - Better handling of multicast addresses.
- *
- * Fixes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
- * - fix dgrs_found_device wrt checking kmalloc return and
- * rollbacking the partial steps of the whole process when
- * one of the devices can't be allocated. Fix SET_MODULE_OWNER
- * on the loop to use devN instead of repeated calls to dev.
- *
- * davej <davej@suse.de> - 9/2/2001
- * - Enable PCI device before reading ioaddr/irq
- *
- */
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-static char version[] __initdata =
- "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
-
-/*
- * DGRS include files
- */
-typedef unsigned char uchar;
-#define vol volatile
-
-#include "dgrs.h"
-#include "dgrs_es4h.h"
-#include "dgrs_plx9060.h"
-#include "dgrs_i82596.h"
-#include "dgrs_ether.h"
-#include "dgrs_asstruct.h"
-#include "dgrs_bcomm.h"
-
-#ifdef CONFIG_PCI
-static struct pci_device_id dgrs_pci_tbl[] = {
- { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
-#endif
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id dgrs_eisa_tbl[] = {
- { "DBI0A01" },
- { }
-};
-MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl);
-#endif
-
-MODULE_LICENSE("GPL");
-
-
-/*
- * Firmware. Compiled separately for local compilation,
- * but #included for Linux distribution.
- */
-#ifndef NOFW
- #include "dgrs_firmware.c"
-#else
- extern int dgrs_firmnum;
- extern char dgrs_firmver[];
- extern char dgrs_firmdate[];
- extern uchar dgrs_code[];
- extern int dgrs_ncode;
-#endif
-
-/*
- * Linux out*() is backwards from all other operating systems
- */
-#define OUTB(ADDR, VAL) outb(VAL, ADDR)
-#define OUTW(ADDR, VAL) outw(VAL, ADDR)
-#define OUTL(ADDR, VAL) outl(VAL, ADDR)
-
-/*
- * Macros to convert switch to host and host to switch addresses
- * (assumes a local variable priv points to board dependent struct)
- */
-#define S2H(A) ( ((unsigned long)(A)&0x00ffffff) + priv0->vmem )
-#define S2HN(A) ( ((unsigned long)(A)&0x00ffffff) + privN->vmem )
-#define H2S(A) ( ((char *) (A) - priv0->vmem) + 0xA3000000 )
-
-/*
- * Convert a switch address to a "safe" address for use with the
- * PLX 9060 DMA registers and the associated HW kludge that allows
- * for host access of the DMA registers.
- */
-#define S2DMA(A) ( (unsigned long)(A) & 0x00ffffff)
-
-/*
- * "Space.c" variables, now settable from module interface
- * Use the name below, minus the "dgrs_" prefix. See init_module().
- */
-static int dgrs_debug = 1;
-static int dgrs_dma = 1;
-static int dgrs_spantree = -1;
-static int dgrs_hashexpire = -1;
-static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
-static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
-static __u32 dgrs_ipxnet = -1;
-static int dgrs_nicmode;
-
-/*
- * Private per-board data structure (dev->priv)
- */
-typedef struct
-{
- /*
- * Stuff for generic ethercard I/F
- */
- struct net_device_stats stats;
-
- /*
- * DGRS specific data
- */
- char *vmem;
-
- struct bios_comm *bcomm; /* Firmware BIOS comm structure */
- PORT *port; /* Ptr to PORT[0] struct in VM */
- I596_SCB *scbp; /* Ptr to SCB struct in VM */
- I596_RFD *rfdp; /* Current RFD list */
- I596_RBD *rbdp; /* Current RBD list */
-
- volatile int intrcnt; /* Count of interrupts */
-
- /*
- * SE-4 (EISA) board variables
- */
- uchar is_reg; /* EISA: Value for ES4H_IS reg */
-
- /*
- * SE-6 (PCI) board variables
- *
- * The PLX "expansion rom" space is used for DMA register
- * access from the host on the SE-6. These are the physical
- * and virtual addresses of that space.
- */
- ulong plxreg; /* Phys address of PLX chip */
- char *vplxreg; /* Virtual address of PLX chip */
- ulong plxdma; /* Phys addr of PLX "expansion rom" */
- ulong volatile *vplxdma; /* Virtual addr of "expansion rom" */
- int use_dma; /* Flag: use DMA */
- DMACHAIN *dmadesc_s; /* area for DMA chains (SW addr.) */
- DMACHAIN *dmadesc_h; /* area for DMA chains (Host Virtual) */
-
- /*
- * Multi-NIC mode variables
- *
- * All entries of the devtbl[] array are valid for the 0th
- * device (i.e. eth0, but not eth1...eth5). devtbl[0] is
- * valid for all devices (i.e. eth0, eth1, ..., eth5).
- */
- int nports; /* Number of physical ports (4 or 6) */
- int chan; /* Channel # (1-6) for this device */
- struct net_device *devtbl[6]; /* Ptrs to N device structs */
-
-} DGRS_PRIV;
-
-
-/*
- * reset or un-reset the IDT processor
- */
-static void
-proc_reset(struct net_device *dev0, int reset)
-{
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
-
- if (priv0->plxreg)
- {
- ulong val;
- val = inl(dev0->base_addr + PLX_MISC_CSR);
- if (reset)
- val |= SE6_RESET;
- else
- val &= ~SE6_RESET;
- OUTL(dev0->base_addr + PLX_MISC_CSR, val);
- }
- else
- {
- OUTB(dev0->base_addr + ES4H_PC, reset ? ES4H_PC_RESET : 0);
- }
-}
-
-/*
- * See if the board supports bus master DMA
- */
-static int
-check_board_dma(struct net_device *dev0)
-{
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
- ulong x;
-
- /*
- * If Space.c says not to use DMA, or if it's not a PLX based
- * PCI board, or if the expansion ROM space is not PCI
- * configured, then return false.
- */
- if (!dgrs_dma || !priv0->plxreg || !priv0->plxdma)
- return (0);
-
- /*
- * Set the local address remap register of the "expansion rom"
- * area to 0x80000000 so that we can use it to access the DMA
- * registers from the host side.
- */
- OUTL(dev0->base_addr + PLX_ROM_BASE_ADDR, 0x80000000);
-
- /*
- * Set the PCI region descriptor to:
- * Space 0:
- * disable read-prefetch
- * enable READY
- * enable BURST
- * 0 internal wait states
- * Expansion ROM: (used for host DMA register access)
- * disable read-prefetch
- * enable READY
- * disable BURST
- * 0 internal wait states
- */
- OUTL(dev0->base_addr + PLX_BUS_REGION, 0x49430343);
-
- /*
- * Now map the DMA registers into our virtual space
- */
- priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256);
- if (!priv0->vplxdma)
- {
- printk("%s: can't *remap() the DMA regs\n", dev0->name);
- return (0);
- }
-
- /*
- * Now test to see if we can access the DMA registers
- * If we write -1 and get back 1FFF, then we accessed the
- * DMA register. Otherwise, we probably have an old board
- * and wrote into regular RAM.
- */
- priv0->vplxdma[PLX_DMA0_MODE/4] = 0xFFFFFFFF;
- x = priv0->vplxdma[PLX_DMA0_MODE/4];
- if (x != 0x00001FFF) {
- iounmap((void *)priv0->vplxdma);
- return (0);
- }
-
- return (1);
-}
-
-/*
- * Initiate DMA using PLX part on PCI board. Spin the
- * processor until completed. All addresses are physical!
- *
- * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
- * the address of the first DMA descriptor in the chain.
- *
- * If pciaddr is not NULL, then it's a single DMA.
- *
- * In either case, "lcladdr" must have been fixed up to make
- * sure the MSB isn't set using the S2DMA macro before passing
- * the address to this routine.
- */
-static int
-do_plx_dma(
- struct net_device *dev,
- ulong pciaddr,
- ulong lcladdr,
- int len,
- int to_host
-)
-{
- int i;
- ulong csr = 0;
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
-
- if (pciaddr)
- {
- /*
- * Do a single, non-chain DMA
- */
- priv->vplxdma[PLX_DMA0_PCI_ADDR/4] = pciaddr;
- priv->vplxdma[PLX_DMA0_LCL_ADDR/4] = lcladdr;
- priv->vplxdma[PLX_DMA0_SIZE/4] = len;
- priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = to_host
- ? PLX_DMA_DESC_TO_HOST
- : PLX_DMA_DESC_TO_BOARD;
- priv->vplxdma[PLX_DMA0_MODE/4] =
- PLX_DMA_MODE_WIDTH32
- | PLX_DMA_MODE_WAITSTATES(0)
- | PLX_DMA_MODE_READY
- | PLX_DMA_MODE_NOBTERM
- | PLX_DMA_MODE_BURST
- | PLX_DMA_MODE_NOCHAIN;
- }
- else
- {
- /*
- * Do a chaining DMA
- */
- priv->vplxdma[PLX_DMA0_MODE/4] =
- PLX_DMA_MODE_WIDTH32
- | PLX_DMA_MODE_WAITSTATES(0)
- | PLX_DMA_MODE_READY
- | PLX_DMA_MODE_NOBTERM
- | PLX_DMA_MODE_BURST
- | PLX_DMA_MODE_CHAIN;
- priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = lcladdr;
- }
-
- priv->vplxdma[PLX_DMA_CSR/4] =
- PLX_DMA_CSR_0_ENABLE | PLX_DMA_CSR_0_START;
-
- /*
- * Wait for DMA to complete
- */
- for (i = 0; i < 1000000; ++i)
- {
- /*
- * Spin the host CPU for 1 usec, so we don't thrash
- * the PCI bus while the PLX 9060 is doing DMA.
- */
- udelay(1);
-
- csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4];
-
- if (csr & PLX_DMA_CSR_0_DONE)
- break;
- }
-
- if ( ! (csr & PLX_DMA_CSR_0_DONE) )
- {
- printk("%s: DMA done never occurred. DMA disabled.\n",
- dev->name);
- priv->use_dma = 0;
- return 1;
- }
- return 0;
-}
-
-/*
- * dgrs_rcv_frame()
- *
- * Process a received frame. This is called from the interrupt
- * routine, and works for both switch mode and multi-NIC mode.
- *
- * Note that when in multi-NIC mode, we want to always access the
- * hardware using the dev and priv structures of the first port,
- * so that we are using only one set of variables to maintain
- * the board interface status, but we want to use the Nth port
- * dev and priv structures to maintain statistics and to pass
- * the packet up.
- *
- * Only the first device structure is attached to the interrupt.
- * We use the special "chan" variable at the end of the first RBD
- * to select the Nth device in multi-NIC mode.
- *
- * We currently do chained DMA on a per-packet basis when the
- * packet is "long", and we spin the CPU a short time polling
- * for DMA completion. This avoids a second interrupt overhead,
- * and gives the best performance for light traffic to the host.
- *
- * However, a better scheme that could be implemented would be
- * to see how many packets are outstanding for the host, and if
- * the number is "large", create a long chain to DMA several
- * packets into the host in one go. In this case, we would set
- * up some state variables to let the host CPU continue doing
- * other things until a DMA completion interrupt comes along.
- */
-static void
-dgrs_rcv_frame(
- struct net_device *dev0,
- DGRS_PRIV *priv0,
- I596_CB *cbp
-)
-{
- int len;
- I596_TBD *tbdp;
- struct sk_buff *skb;
- uchar *putp;
- uchar *p;
- struct net_device *devN;
- DGRS_PRIV *privN;
-
- /*
- * Determine Nth priv and dev structure pointers
- */
- if (dgrs_nicmode)
- { /* Multi-NIC mode */
- int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
-
- devN = priv0->devtbl[chan-1];
- /*
- * If devN is null, we got an interrupt before the I/F
- * has been initialized. Pitch the packet.
- */
- if (devN == NULL)
- goto out;
- privN = (DGRS_PRIV *) devN->priv;
- }
- else
- { /* Switch mode */
- devN = dev0;
- privN = priv0;
- }
-
- if (0) printk("%s: rcv len=%ld\n", devN->name, cbp->xmit.count);
-
- /*
- * Allocate a message block big enough to hold the whole frame
- */
- len = cbp->xmit.count;
- if ((skb = dev_alloc_skb(len+5)) == NULL)
- {
- printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name);
- ++privN->stats.rx_dropped;
- /* discarding the frame */
- goto out;
- }
- skb_reserve(skb, 2); /* Align IP header */
-
-again:
- putp = p = skb_put(skb, len);
-
- /*
- * There are three modes here for doing the packet copy.
- * If we have DMA, and the packet is "long", we use the
- * chaining mode of DMA. If it's shorter, we use single
- * DMA's. Otherwise, we use memcpy().
- */
- if (priv0->use_dma && priv0->dmadesc_h && len > 64)
- {
- /*
- * If we can use DMA and it's a long frame, copy it using
- * DMA chaining.
- */
- DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */
- DMACHAIN *ddp_s; /* Switch physical DMA desc. pointer */
- uchar *phys_p;
-
- /*
- * Get the physical address of the STREAMS buffer.
- * NOTE: allocb() guarantees that the whole buffer
- * is in a single page if the length < 4096.
- */
- phys_p = (uchar *) virt_to_phys(putp);
-
- ddp_h = priv0->dmadesc_h;
- ddp_s = priv0->dmadesc_s;
- tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
- for (;;)
- {
- int count;
- int amt;
-
- count = tbdp->count;
- amt = count & 0x3fff;
- if (amt == 0)
- break; /* For safety */
- if ( (p-putp) >= len)
- {
- printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
- proc_reset(dev0, 1); /* Freeze IDT */
- break; /* For Safety */
- }
-
- ddp_h->pciaddr = (ulong) phys_p;
- ddp_h->lcladdr = S2DMA(tbdp->buf);
- ddp_h->len = amt;
-
- phys_p += amt;
- p += amt;
-
- if (count & I596_TBD_EOF)
- {
- ddp_h->next = PLX_DMA_DESC_TO_HOST
- | PLX_DMA_DESC_EOC;
- ++ddp_h;
- break;
- }
- else
- {
- ++ddp_s;
- ddp_h->next = PLX_DMA_DESC_TO_HOST
- | (ulong) ddp_s;
- tbdp = (I596_TBD *) S2H(tbdp->next);
- ++ddp_h;
- }
- }
- if (ddp_h - priv0->dmadesc_h)
- {
- int rc;
-
- rc = do_plx_dma(dev0,
- 0, (ulong) priv0->dmadesc_s, len, 0);
- if (rc)
- {
- printk("%s: Chained DMA failure\n", devN->name);
- goto again;
- }
- }
- }
- else if (priv0->use_dma)
- {
- /*
- * If we can use DMA and it's a shorter frame, copy it
- * using single DMA transfers.
- */
- uchar *phys_p;
-
- /*
- * Get the physical address of the STREAMS buffer.
- * NOTE: allocb() guarantees that the whole buffer
- * is in a single page if the length < 4096.
- */
- phys_p = (uchar *) virt_to_phys(putp);
-
- tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
- for (;;)
- {
- int count;
- int amt;
- int rc;
-
- count = tbdp->count;
- amt = count & 0x3fff;
- if (amt == 0)
- break; /* For safety */
- if ( (p-putp) >= len)
- {
- printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
- proc_reset(dev0, 1); /* Freeze IDT */
- break; /* For Safety */
- }
- rc = do_plx_dma(dev0, (ulong) phys_p,
- S2DMA(tbdp->buf), amt, 1);
- if (rc)
- {
- memcpy(p, S2H(tbdp->buf), amt);
- printk("%s: Single DMA failed\n", devN->name);
- }
- phys_p += amt;
- p += amt;
- if (count & I596_TBD_EOF)
- break;
- tbdp = (I596_TBD *) S2H(tbdp->next);
- }
- }
- else
- {
- /*
- * Otherwise, copy it piece by piece using memcpy()
- */
- tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
- for (;;)
- {
- int count;
- int amt;
-
- count = tbdp->count;
- amt = count & 0x3fff;
- if (amt == 0)
- break; /* For safety */
- if ( (p-putp) >= len)
- {
- printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
- proc_reset(dev0, 1); /* Freeze IDT */
- break; /* For Safety */
- }
- memcpy(p, S2H(tbdp->buf), amt);
- p += amt;
- if (count & I596_TBD_EOF)
- break;
- tbdp = (I596_TBD *) S2H(tbdp->next);
- }
- }
-
- /*
- * Pass the frame to upper half
- */
- skb->protocol = eth_type_trans(skb, devN);
- netif_rx(skb);
- devN->last_rx = jiffies;
- ++privN->stats.rx_packets;
- privN->stats.rx_bytes += len;
-
-out:
- cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
-}
-
-/*
- * Start transmission of a frame
- *
- * The interface to the board is simple: we pretend that we are
- * a fifth 82596 ethernet controller 'receiving' data, and copy the
- * data into the same structures that a real 82596 would. This way,
- * the board firmware handles the host 'port' the same as any other.
- *
- * NOTE: we do not use Bus master DMA for this routine. Turns out
- * that it is not needed. Slave writes over the PCI bus are about
- * as fast as DMA, due to the fact that the PLX part can do burst
- * writes. The same is not true for data being read from the board.
- *
- * For multi-NIC mode, we tell the firmware the desired 82596
- * output port by setting the special "dstchan" member at the
- * end of the traditional 82596 RFD structure.
- */
-
-static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN)
-{
- DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv;
- struct net_device *dev0;
- DGRS_PRIV *priv0;
- I596_RBD *rbdp;
- int count;
- int i, len, amt;
-
- /*
- * Determine 0th priv and dev structure pointers
- */
- if (dgrs_nicmode)
- {
- dev0 = privN->devtbl[0];
- priv0 = (DGRS_PRIV *) dev0->priv;
- }
- else
- {
- dev0 = devN;
- priv0 = privN;
- }
-
- if (dgrs_debug > 1)
- printk("%s: xmit len=%d\n", devN->name, (int) skb->len);
-
- devN->trans_start = jiffies;
- netif_start_queue(devN);
-
- if (priv0->rfdp->cmd & I596_RFD_EL)
- { /* Out of RFD's */
- if (0) printk("%s: NO RFD's\n", devN->name);
- goto no_resources;
- }
-
- rbdp = priv0->rbdp;
- count = 0;
- priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp);
-
- i = 0; len = skb->len;
- for (;;)
- {
- if (rbdp->size & I596_RBD_EL)
- { /* Out of RBD's */
- if (0) printk("%s: NO RBD's\n", devN->name);
- goto no_resources;
- }
-
- amt = min_t(unsigned int, len, rbdp->size - count);
- skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt);
- i += amt;
- count += amt;
- len -= amt;
- if (len == 0)
- {
- if (skb->len < 60)
- rbdp->count = 60 | I596_RBD_EOF;
- else
- rbdp->count = count | I596_RBD_EOF;
- rbdp = (I596_RBD *) S2H(rbdp->next);
- goto frame_done;
- }
- else if (count < 32)
- {
- /* More data to come, but we used less than 32
- * bytes of this RBD. Keep filling this RBD.
- */
- {} /* Yes, we do nothing here */
- }
- else
- {
- rbdp->count = count;
- rbdp = (I596_RBD *) S2H(rbdp->next);
- count = 0;
- }
- }
-
-frame_done:
- priv0->rbdp = rbdp;
- if (dgrs_nicmode)
- priv0->rfdp->dstchan = privN->chan;
- priv0->rfdp->status = I596_RFD_C | I596_RFD_OK;
- priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next);
-
- ++privN->stats.tx_packets;
-
- dev_kfree_skb (skb);
- return (0);
-
-no_resources:
- priv0->scbp->status |= I596_SCB_RNR; /* simulate I82596 */
- return (-EAGAIN);
-}
-
-/*
- * Open the interface
- */
-static int
-dgrs_open( struct net_device *dev )
-{
- netif_start_queue(dev);
- return (0);
-}
-
-/*
- * Close the interface
- */
-static int dgrs_close( struct net_device *dev )
-{
- netif_stop_queue(dev);
- return (0);
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *dgrs_get_stats( struct net_device *dev )
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
-
- return (&priv->stats);
-}
-
-/*
- * Set multicast list and/or promiscuous mode
- */
-
-static void dgrs_set_multicast_list( struct net_device *dev)
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
-
- priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
-}
-
-/*
- * Unique ioctl's
- */
-static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd)
-{
- DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv;
- DGRS_IOCTL ioc;
- int i;
-
- if (cmd != DGRSIOCTL)
- return -EINVAL;
-
- if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
- return -EFAULT;
-
- switch (ioc.cmd)
- {
- case DGRS_GETMEM:
- if (ioc.len != sizeof(ulong))
- return -EINVAL;
- if(copy_to_user(ioc.data, &devN->mem_start, ioc.len))
- return -EFAULT;
- return (0);
- case DGRS_SETFILTER:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (ioc.port > privN->bcomm->bc_nports)
- return -EINVAL;
- if (ioc.filter >= NFILTERS)
- return -EINVAL;
- if (ioc.len > privN->bcomm->bc_filter_area_len)
- return -EINVAL;
-
- /* Wait for old command to finish */
- for (i = 0; i < 1000; ++i)
- {
- if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 )
- break;
- udelay(1);
- }
- if (i >= 1000)
- return -EIO;
-
- privN->bcomm->bc_filter_port = ioc.port;
- privN->bcomm->bc_filter_num = ioc.filter;
- privN->bcomm->bc_filter_len = ioc.len;
-
- if (ioc.len)
- {
- if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
- ioc.data, ioc.len))
- return -EFAULT;
- privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
- }
- else
- privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
- return(0);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/*
- * Process interrupts
- *
- * dev, priv will always refer to the 0th device in Multi-NIC mode.
- */
-
-static irqreturn_t dgrs_intr(int irq, void *dev_id)
-{
- struct net_device *dev0 = dev_id;
- DGRS_PRIV *priv0 = dev0->priv;
- I596_CB *cbp;
- int cmd;
- int i;
-
- ++priv0->intrcnt;
- if (1) ++priv0->bcomm->bc_cnt[4];
- if (0)
- {
- static int cnt = 100;
- if (--cnt > 0)
- printk("%s: interrupt: irq %d\n", dev0->name, irq);
- }
-
- /*
- * Get 596 command
- */
- cmd = priv0->scbp->cmd;
-
- /*
- * See if RU has been restarted
- */
- if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START)
- {
- if (0) printk("%s: RUC start\n", dev0->name);
- priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
- priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
- priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS);
- /*
- * Tell upper half (halves)
- */
- if (dgrs_nicmode)
- {
- for (i = 0; i < priv0->nports; ++i)
- netif_wake_queue (priv0->devtbl[i]);
- }
- else
- netif_wake_queue (dev0);
- /* if (bd->flags & TX_QUEUED)
- DL_sched(bd, bdd); */
- }
-
- /*
- * See if any CU commands to process
- */
- if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START)
- {
- priv0->scbp->cmd = 0; /* Ignore all other commands */
- goto ack_intr;
- }
- priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS);
-
- /*
- * Process a command
- */
- cbp = (I596_CB *) S2H(priv0->scbp->cbp);
- priv0->scbp->cmd = 0; /* Safe to clear the command */
- for (;;)
- {
- switch (cbp->nop.cmd & I596_CB_CMD)
- {
- case I596_CB_CMD_XMIT:
- dgrs_rcv_frame(dev0, priv0, cbp);
- break;
- default:
- cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
- break;
- }
- if (cbp->nop.cmd & I596_CB_CMD_EL)
- break;
- cbp = (I596_CB *) S2H(cbp->nop.next);
- }
- priv0->scbp->status |= I596_SCB_CNA;
-
- /*
- * Ack the interrupt
- */
-ack_intr:
- if (priv0->plxreg)
- OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
- return IRQ_HANDLED;
-}
-
-/*
- * Download the board firmware
- */
-static int __init
-dgrs_download(struct net_device *dev0)
-{
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
- int is;
- unsigned long i;
-
- static const int iv2is[16] = {
- 0, 0, 0, ES4H_IS_INT3,
- 0, ES4H_IS_INT5, 0, ES4H_IS_INT7,
- 0, 0, ES4H_IS_INT10, ES4H_IS_INT11,
- ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 };
-
- /*
- * Map in the dual port memory
- */
- priv0->vmem = ioremap(dev0->mem_start, 2048*1024);
- if (!priv0->vmem)
- {
- printk("%s: cannot map in board memory\n", dev0->name);
- return -ENXIO;
- }
-
- /*
- * Hold the processor and configure the board addresses
- */
- if (priv0->plxreg)
- { /* PCI bus */
- proc_reset(dev0, 1);
- }
- else
- { /* EISA bus */
- is = iv2is[dev0->irq & 0x0f];
- if (!is)
- {
- printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq);
- iounmap(priv0->vmem);
- priv0->vmem = NULL;
- return -ENXIO;
- }
- OUTB(dev0->base_addr + ES4H_AS_31_24,
- (uchar) (dev0->mem_start >> 24) );
- OUTB(dev0->base_addr + ES4H_AS_23_16,
- (uchar) (dev0->mem_start >> 16) );
- priv0->is_reg = ES4H_IS_LINEAR | is |
- ((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15);
- OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg);
- OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE);
- OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET);
- OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00);
- }
-
- /*
- * See if we can do DMA on the SE-6
- */
- priv0->use_dma = check_board_dma(dev0);
- if (priv0->use_dma)
- printk("%s: Bus Master DMA is enabled.\n", dev0->name);
-
- /*
- * Load and verify the code at the desired address
- */
- memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */
- if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode))
- {
- iounmap(priv0->vmem);
- priv0->vmem = NULL;
- printk("%s: download compare failed\n", dev0->name);
- return -ENXIO;
- }
-
- /*
- * Configurables
- */
- priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100);
- priv0->bcomm->bc_nowait = 1; /* Tell board to make printf not wait */
- priv0->bcomm->bc_squelch = 0; /* Flag from Space.c */
- priv0->bcomm->bc_150ohm = 0; /* Flag from Space.c */
-
- priv0->bcomm->bc_spew = 0; /* Debug flag from Space.c */
- priv0->bcomm->bc_maxrfd = 0; /* Debug flag from Space.c */
- priv0->bcomm->bc_maxrbd = 0; /* Debug flag from Space.c */
-
- /*
- * Tell board we are operating in switch mode (1) or in
- * multi-NIC mode (2).
- */
- priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH;
-
- /*
- * Request memory space on board for DMA chains
- */
- if (priv0->use_dma)
- priv0->bcomm->bc_hostarea_len = (2048/64) * 16;
-
- /*
- * NVRAM configurables from Space.c
- */
- priv0->bcomm->bc_spantree = dgrs_spantree;
- priv0->bcomm->bc_hashexpire = dgrs_hashexpire;
- memcpy(priv0->bcomm->bc_ipaddr, dgrs_ipaddr, 4);
- memcpy(priv0->bcomm->bc_iptrap, dgrs_iptrap, 4);
- memcpy(priv0->bcomm->bc_ipxnet, &dgrs_ipxnet, 4);
-
- /*
- * Release processor, wait 8 seconds for board to initialize
- */
- proc_reset(dev0, 0);
-
- for (i = jiffies + 8 * HZ; time_after(i, jiffies); )
- {
- barrier(); /* Gcc 2.95 needs this */
- if (priv0->bcomm->bc_status >= BC_RUN)
- break;
- }
-
- if (priv0->bcomm->bc_status < BC_RUN)
- {
- printk("%s: board not operating\n", dev0->name);
- iounmap(priv0->vmem);
- priv0->vmem = NULL;
- return -ENXIO;
- }
-
- priv0->port = (PORT *) S2H(priv0->bcomm->bc_port);
- priv0->scbp = (I596_SCB *) S2H(priv0->port->scbp);
- priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
- priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
-
- priv0->scbp->status = I596_SCB_CNA; /* CU is idle */
-
- /*
- * Get switch physical and host virtual pointers to DMA
- * chaining area. NOTE: the MSB of the switch physical
- * address *must* be turned off. Otherwise, the HW kludge
- * that allows host access of the PLX DMA registers will
- * erroneously select the PLX registers.
- */
- priv0->dmadesc_s = (DMACHAIN *) S2DMA(priv0->bcomm->bc_hostarea);
- if (priv0->dmadesc_s)
- priv0->dmadesc_h = (DMACHAIN *) S2H(priv0->dmadesc_s);
- else
- priv0->dmadesc_h = NULL;
-
- /*
- * Enable board interrupts
- */
- if (priv0->plxreg)
- { /* PCI bus */
- OUTL(dev0->base_addr + PLX_INT_CSR,
- inl(dev0->base_addr + PLX_INT_CSR)
- | PLX_PCI_DOORBELL_IE); /* Enable intr to host */
- OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
- }
- else
- { /* EISA bus */
- }
-
- return (0);
-}
-
-/*
- * Probe (init) a board
- */
-static int __init
-dgrs_probe1(struct net_device *dev)
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
- unsigned long i;
- int rc;
-
- printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n",
- dev->name, dev->base_addr, dev->mem_start, dev->irq,
- priv->plxreg, priv->plxdma);
-
- /*
- * Download the firmware and light the processor
- */
- rc = dgrs_download(dev);
- if (rc)
- goto err_out;
-
- /*
- * Get ether address of board
- */
- printk("%s: Ethernet address", dev->name);
- memcpy(dev->dev_addr, priv->port->ethaddr, 6);
- for (i = 0; i < 6; ++i)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- printk("\n");
-
- if (dev->dev_addr[0] & 1)
- {
- printk("%s: Illegal Ethernet Address\n", dev->name);
- rc = -ENXIO;
- goto err_out;
- }
-
- /*
- * ACK outstanding interrupts, hook the interrupt,
- * and verify that we are getting interrupts from the board.
- */
- if (priv->plxreg)
- OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
- rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev);
- if (rc)
- goto err_out;
-
- priv->intrcnt = 0;
- for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
- {
- cpu_relax();
- if (priv->intrcnt >= 2)
- break;
- }
- if (priv->intrcnt < 2)
- {
- printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n",
- dev->name, dev->irq, priv->intrcnt);
- rc = -ENXIO;
- goto err_free_irq;
- }
-
- /*
- * Entry points...
- */
- dev->open = &dgrs_open;
- dev->stop = &dgrs_close;
- dev->get_stats = &dgrs_get_stats;
- dev->hard_start_xmit = &dgrs_start_xmit;
- dev->set_multicast_list = &dgrs_set_multicast_list;
- dev->do_ioctl = &dgrs_ioctl;
-
- return rc;
-
-err_free_irq:
- free_irq(dev->irq, dev);
-err_out:
- return rc;
-}
-
-static int __init
-dgrs_initclone(struct net_device *dev)
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
- int i;
-
- printk("%s: Digi RightSwitch port %d ",
- dev->name, priv->chan);
- for (i = 0; i < 6; ++i)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- printk("\n");
-
- return (0);
-}
-
-static struct net_device * __init
-dgrs_found_device(
- int io,
- ulong mem,
- int irq,
- ulong plxreg,
- ulong plxdma,
- struct device *pdev
-)
-{
- DGRS_PRIV *priv;
- struct net_device *dev;
- int i, ret = -ENOMEM;
-
- dev = alloc_etherdev(sizeof(DGRS_PRIV));
- if (!dev)
- goto err0;
-
- priv = (DGRS_PRIV *)dev->priv;
-
- dev->base_addr = io;
- dev->mem_start = mem;
- dev->mem_end = mem + 2048 * 1024 - 1;
- dev->irq = irq;
- priv->plxreg = plxreg;
- priv->plxdma = plxdma;
- priv->vplxdma = NULL;
-
- priv->chan = 1;
- priv->devtbl[0] = dev;
-
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, pdev);
-
- ret = dgrs_probe1(dev);
- if (ret)
- goto err1;
-
- ret = register_netdev(dev);
- if (ret)
- goto err2;
-
- if ( !dgrs_nicmode )
- return dev; /* Switch mode, we are done */
-
- /*
- * Operating card as N separate NICs
- */
-
- priv->nports = priv->bcomm->bc_nports;
-
- for (i = 1; i < priv->nports; ++i)
- {
- struct net_device *devN;
- DGRS_PRIV *privN;
- /* Allocate new dev and priv structures */
- devN = alloc_etherdev(sizeof(DGRS_PRIV));
- ret = -ENOMEM;
- if (!devN)
- goto fail;
-
- /* Don't copy the network device structure! */
-
- /* copy the priv structure of dev[0] */
- privN = (DGRS_PRIV *)devN->priv;
- *privN = *priv;
-
- /* ... and zero out VM areas */
- privN->vmem = NULL;
- privN->vplxdma = NULL;
- /* ... and zero out IRQ */
- devN->irq = 0;
- /* ... and base MAC address off address of 1st port */
- devN->dev_addr[5] += i;
-
- ret = dgrs_initclone(devN);
- if (ret)
- goto fail;
-
- SET_MODULE_OWNER(devN);
- SET_NETDEV_DEV(dev, pdev);
-
- ret = register_netdev(devN);
- if (ret) {
- free_netdev(devN);
- goto fail;
- }
- privN->chan = i+1;
- priv->devtbl[i] = devN;
- }
- return dev;
-
- fail:
- while (i >= 0) {
- struct net_device *d = priv->devtbl[i--];
- unregister_netdev(d);
- free_netdev(d);
- }
-
- err2:
- free_irq(dev->irq, dev);
- err1:
- free_netdev(dev);
- err0:
- return ERR_PTR(ret);
-}
-
-static void __devexit dgrs_remove(struct net_device *dev)
-{
- DGRS_PRIV *priv = dev->priv;
- int i;
-
- unregister_netdev(dev);
-
- for (i = 1; i < priv->nports; ++i) {
- struct net_device *d = priv->devtbl[i];
- if (d) {
- unregister_netdev(d);
- free_netdev(d);
- }
- }
-
- proc_reset(priv->devtbl[0], 1);
-
- if (priv->vmem)
- iounmap(priv->vmem);
- if (priv->vplxdma)
- iounmap((uchar *) priv->vplxdma);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- for (i = 1; i < priv->nports; ++i) {
- if (priv->devtbl[i])
- unregister_netdev(priv->devtbl[i]);
- }
-}
-
-#ifdef CONFIG_PCI
-static int __init dgrs_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct net_device *dev;
- int err;
- uint io;
- uint mem;
- uint irq;
- uint plxreg;
- uint plxdma;
-
- /*
- * Get and check the bus-master and latency values.
- * Some PCI BIOSes fail to set the master-enable bit,
- * and the latency timer must be set to the maximum
- * value to avoid data corruption that occurs when the
- * timer expires during a transfer. Yes, it's a bug.
- */
- err = pci_enable_device(pdev);
- if (err)
- return err;
- err = pci_request_regions(pdev, "RightSwitch");
- if (err)
- return err;
-
- pci_set_master(pdev);
-
- plxreg = pci_resource_start (pdev, 0);
- io = pci_resource_start (pdev, 1);
- mem = pci_resource_start (pdev, 2);
- pci_read_config_dword(pdev, 0x30, &plxdma);
- irq = pdev->irq;
- plxdma &= ~15;
-
- /*
- * On some BIOSES, the PLX "expansion rom" (used for DMA)
- * address comes up as "0". This is probably because
- * the BIOS doesn't see a valid 55 AA ROM signature at
- * the "ROM" start and zeroes the address. To get
- * around this problem the SE-6 is configured to ask
- * for 4 MB of space for the dual port memory. We then
- * must set its range back to 2 MB, and use the upper
- * half for DMA register access
- */
- OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
- if (plxdma == 0)
- plxdma = mem + (2048L * 1024L);
- pci_write_config_dword(pdev, 0x30, plxdma + 1);
- pci_read_config_dword(pdev, 0x30, &plxdma);
- plxdma &= ~15;
-
- dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev);
- if (IS_ERR(dev)) {
- pci_release_regions(pdev);
- return PTR_ERR(dev);
- }
-
- pci_set_drvdata(pdev, dev);
- return 0;
-}
-
-static void __devexit dgrs_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
-
- dgrs_remove(dev);
- pci_release_regions(pdev);
- free_netdev(dev);
-}
-
-static struct pci_driver dgrs_pci_driver = {
- .name = "dgrs",
- .id_table = dgrs_pci_tbl,
- .probe = dgrs_pci_probe,
- .remove = __devexit_p(dgrs_pci_remove),
-};
-#else
-static struct pci_driver dgrs_pci_driver = {};
-#endif
-
-
-#ifdef CONFIG_EISA
-static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
-
-static int __init dgrs_eisa_probe (struct device *gendev)
-{
- struct net_device *dev;
- struct eisa_device *edev = to_eisa_device(gendev);
- uint io = edev->base_addr;
- uint mem;
- uint irq;
- int rc = -ENODEV; /* Not EISA configured */
-
- if (!request_region(io, 256, "RightSwitch")) {
- printk(KERN_ERR "dgrs: eisa io 0x%x, which is busy.\n", io);
- return -EBUSY;
- }
-
- if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
- goto err_out;
-
- mem = (inb(io+ES4H_AS_31_24) << 24)
- + (inb(io+ES4H_AS_23_16) << 16);
-
- irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ];
-
- dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev);
- if (IS_ERR(dev)) {
- rc = PTR_ERR(dev);
- goto err_out;
- }
-
- gendev->driver_data = dev;
- return 0;
- err_out:
- release_region(io, 256);
- return rc;
-}
-
-static int __devexit dgrs_eisa_remove(struct device *gendev)
-{
- struct net_device *dev = gendev->driver_data;
-
- dgrs_remove(dev);
-
- release_region(dev->base_addr, 256);
-
- free_netdev(dev);
- return 0;
-}
-
-
-static struct eisa_driver dgrs_eisa_driver = {
- .id_table = dgrs_eisa_tbl,
- .driver = {
- .name = "dgrs",
- .probe = dgrs_eisa_probe,
- .remove = __devexit_p(dgrs_eisa_remove),
- }
-};
-#endif
-
-/*
- * Variables that can be overriden from module command line
- */
-static int debug = -1;
-static int dma = -1;
-static int hashexpire = -1;
-static int spantree = -1;
-static int ipaddr[4] = { -1 };
-static int iptrap[4] = { -1 };
-static __u32 ipxnet = -1;
-static int nicmode = -1;
-
-module_param(debug, int, 0);
-module_param(dma, int, 0);
-module_param(hashexpire, int, 0);
-module_param(spantree, int, 0);
-module_param_array(ipaddr, int, NULL, 0);
-module_param_array(iptrap, int, NULL, 0);
-module_param(ipxnet, int, 0);
-module_param(nicmode, int, 0);
-MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)");
-MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)");
-MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)");
-
-static int __init dgrs_init_module (void)
-{
- int i;
- int err;
-
- /*
- * Command line variable overrides
- * debug=NNN
- * dma=0/1
- * spantree=0/1
- * hashexpire=NNN
- * ipaddr=A,B,C,D
- * iptrap=A,B,C,D
- * ipxnet=NNN
- * nicmode=NNN
- */
- if (debug >= 0)
- dgrs_debug = debug;
- if (dma >= 0)
- dgrs_dma = dma;
- if (nicmode >= 0)
- dgrs_nicmode = nicmode;
- if (hashexpire >= 0)
- dgrs_hashexpire = hashexpire;
- if (spantree >= 0)
- dgrs_spantree = spantree;
- if (ipaddr[0] != -1)
- for (i = 0; i < 4; ++i)
- dgrs_ipaddr[i] = ipaddr[i];
- if (iptrap[0] != -1)
- for (i = 0; i < 4; ++i)
- dgrs_iptrap[i] = iptrap[i];
- if (ipxnet != -1)
- dgrs_ipxnet = htonl( ipxnet );
-
- if (dgrs_debug)
- {
- printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n",
- version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver);
- }
-
- /*
- * Find and configure all the cards
- */
-#ifdef CONFIG_EISA
- err = eisa_driver_register(&dgrs_eisa_driver);
- if (err)
- return err;
-#endif
- err = pci_register_driver(&dgrs_pci_driver);
- if (err)
- return err;
- return 0;
-}
-
-static void __exit dgrs_cleanup_module (void)
-{
-#ifdef CONFIG_EISA
- eisa_driver_unregister (&dgrs_eisa_driver);
-#endif
-#ifdef CONFIG_PCI
- pci_unregister_driver (&dgrs_pci_driver);
-#endif
-}
-
-module_init(dgrs_init_module);
-module_exit(dgrs_cleanup_module);
diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h
deleted file mode 100644
index 6058d5301cb6..000000000000
--- a/drivers/net/dgrs.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ioctl's for the Digi Intl. RightSwitch
- *
- * These network driver ioctl's are a bit obtuse compared to the usual
- * ioctl's for a "normal" device driver. Hey, I didn't invent it.
- *
- * Typical use:
- *
- * struct ifreq ifr;
- * DGRS_IOCTL ioc;
- * int x;
- *
- * strcpy(ifr.ifr_name, "eth1");
- * ifr.ifr_data = (caddr_t) &ioc;
- * ioc.cmd = DGRS_GETMEM;
- * ioc.len = sizeof(x);
- * ioc.data = (caddr_t) &x;
- * rc = ioctl(fd, DGRSIOCTL, &ifr);
- * printf("rc=%d mem=%x\n", rc, x);
- *
- */
-#include <linux/sockios.h>
-
-#define DGRSIOCTL SIOCDEVPRIVATE
-
-typedef struct dgrs_ioctl {
- unsigned short cmd; /* Command to run */
- unsigned short len; /* Length of the data buffer */
- unsigned char __user *data; /* Pointer to the data buffer */
- unsigned short port; /* port number for command, if needed */
- unsigned short filter; /* filter number for command, if needed */
-} DGRS_IOCTL;
-
-/*
- * Commands for the driver
- */
-#define DGRS_GETMEM 0x01 /* Get the dual port memory address */
-#define DGRS_SETFILTER 0x02 /* Set a filter */
diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h
deleted file mode 100644
index f0e2121770f1..000000000000
--- a/drivers/net/dgrs_asstruct.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * For declaring structures shared with assembly routines
- *
- * $Id: asstruct.h,v 1.1.1.1 1994/10/23 05:08:32 rick Exp $
- */
-
-#ifdef ASSEMBLER
-
-# define MO(t,a) (a)
-# define VMO(t,a) (a)
-
-# define BEGIN_STRUCT(x) _Off=0
-# define S1A(t,x,n) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+(1*n)
-# define S2A(t,x,n) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+(2*n)
-# define S4A(t,x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
-# define WORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define WORDA(x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
-# define VWORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1
-# define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2
-# define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
-
-#else /* C */
-
-#define VMO(t,a) (*(volatile t *)(a))
-
-# define BEGIN_STRUCT(x) struct x {
-# define S1(t,x) t x ;
-# define S1A(t,x,n) t x[n] ;
-# define S2(t,x) t x ;
-# define S2A(t,x,n) t x[n] ;
-# define S4(t,x) t x ;
-# define S4A(t,x,n) t x[n] ;
-# define END_STRUCT(x) } ;
-
-#endif
diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h
deleted file mode 100644
index 5e9c25273981..000000000000
--- a/drivers/net/dgrs_bcomm.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * The bios low-memory structure
- *
- * Some of the variables in here can be used to set parameters that
- * are stored in NVRAM and will retain their old values the next time
- * the card is brought up. To use the values stored in NVRAM, the
- * parameter should be set to "all ones". This tells the firmware to
- * use the NVRAM value or a suitable default. The value that is used
- * will be stored back into this structure by the firmware. If the
- * value of the variable is not "all ones", then that value will be
- * used and will be stored into NVRAM if it isn't already there.
- * The variables this applies to are the following:
- * Variable Set to: Gets default of:
- * bc_hashexpire -1 300 (5 minutes)
- * bc_spantree -1 1 (spanning tree on)
- * bc_ipaddr FF:FF:FF:FF 0 (no SNMP IP address)
- * bc_ipxnet FF:FF:FF:FF 0 (no SNMP IPX net)
- * bc_iptrap FF:FF:FF:FF 0 (no SNMP IP trap address)
- *
- * Some variables MUST have their value set after the firmware
- * is loaded onto the board, but before the processor is released.
- * These are:
- * bc_host 0 means no host "port", run as standalone switch.
- * 1 means run as a switch, with a host port. (normal)
- * 2 means run as multiple NICs, not as a switch.
- * -1 means run in diagnostics mode.
- * bc_nowait
- * bc_hostarea_len
- * bc_filter_len
- *
- */
-BEGIN_STRUCT(bios_comm)
- S4(ulong, bc_intflag) /* Count of all interrupts */
- S4(ulong, bc_lbolt) /* Count of timer interrupts */
- S4(ulong, bc_maincnt) /* Count of main loops */
- S4(ulong, bc_hashcnt) /* Count of entries in hash table */
- S4A(ulong, bc_cnt, 8) /* Misc counters, for debugging */
- S4A(ulong, bc_flag, 8) /* Misc flags, for debugging */
- S4(ulong, bc_memsize) /* Size of memory */
- S4(ulong, bc_dcache) /* Size of working dcache */
- S4(ulong, bc_icache) /* Size of working icache */
- S4(long, bc_status) /* Firmware status */
- S1A(char, bc_file, 8) /* File name of assertion failure */
- S4(ulong, bc_line) /* Line # of assertion failure */
- S4(uchar *, bc_ramstart)
- S4(uchar *, bc_ramend)
- S4(uchar *, bc_heapstart) /* Start of heap (end of loaded memory) */
- S4(uchar *, bc_heapend) /* End of heap */
-
- /* Configurable Parameters */
- S4(long, bc_host) /* 1=Host Port, 0=No Host Port, -1=Test Mode */
- S4(long, bc_nowait) /* Don't wait for 2host circ buffer to empty*/
- S4(long, bc_150ohm) /* 0 == 100 ohm UTP, 1 == 150 ohm STP */
- S4(long, bc_squelch) /* 0 == normal squelch, 1 == reduced squelch */
- S4(ulong, bc_hashexpire) /* Expiry time in seconds for hash table */
- S4(long, bc_spantree) /* 1 == enable IEEE spanning tree */
-
- S2A(ushort, bc_eaddr, 3) /* New ether address */
- S2(ushort, bc_dummy1) /* padding for DOS compilers */
-
- /* Various debugging aids */
- S4(long, bc_debug) /* Debugging is turned on */
- S4(long, bc_spew) /* Spew data on port 4 for bs_spew seconds */
- S4(long, bc_spewlen) /* Length of spewed data packets */
- S4(long, bc_maxrfd) /* If != 0, max number of RFD's to allocate */
- S4(long, bc_maxrbd) /* If != 0, max number of RBD's to allocate */
-
- /* Circular buffers for messages to/from host */
- S4(ulong, bc_2host_head)
- S4(ulong, bc_2host_tail)
- S4(ulong, bc_2host_mask)
- S1A(char, bc_2host, 0x200) /* Circ buff to host */
-
- S4(ulong, bc_2idt_head)
- S4(ulong, bc_2idt_tail)
- S4(ulong, bc_2idt_mask)
- S1A(char, bc_2idt, 0x200) /* Circ buff to idt */
-
- /* Pointers to structures for driver access */
- S4(uchar *, bc_port) /* pointer to Port[] structures */
- S4(long, bc_nports) /* Number of ports */
- S4(long, bc_portlen) /* sizeof(PORT) */
- S4(uchar *, bc_hash) /* Pointer to hash table */
- S4(long, bc_hashlen) /* sizeof(Table) */
-
- /* SNMP agent addresses */
- S1A(uchar, bc_ipaddr, 4) /* IP address for SNMP */
- S1A(uchar, bc_ipxnet, 4) /* IPX net address for SNMP */
-
- S4(long, bc_nohostintr) /* Do not cause periodic host interrupts */
-
- S4(uchar *, bc_dmaaddr) /* Physical addr of host DMA buf for diags */
- S4(ulong, bc_dmalen) /* Length of DMA buffer 0..2048 */
-
- /*
- * Board memory allocated on startup for use by host, usually
- * for the purposes of creating DMA chain descriptors. The
- * "len" must be set before the processor is released. The
- * address of the area is returned in bc_hostarea. The area
- * is guaranteed to be aligned on a 16 byte boundary.
- */
- S4(ulong, bc_hostarea_len) /* RW: Number of bytes to allocate */
- S4(uchar *, bc_hostarea) /* RO: Address of allocated memory */
-
- /*
- * Variables for communicating filters into the board
- */
- S4(ulong *, bc_filter_area) /* RO: Space to put filter into */
- S4(ulong, bc_filter_area_len) /* RO: Length of area, in bytes */
- S4(long, bc_filter_cmd) /* RW: Filter command, see below */
- S4(ulong, bc_filter_len) /* RW: Actual length of filter */
- S4(ulong, bc_filter_port) /* RW: Port # for filter 0..6 */
- S4(ulong, bc_filter_num) /* RW: Filter #, 0=input, 1=output */
-
- /* more SNMP agent addresses */
- S1A(uchar, bc_iptrap, 4) /* IP address for SNMP */
-
- S4A(long, bc_spare, 2) /* spares */
-END_STRUCT(bios_comm)
-
-#define bc VMO(struct bios_comm, 0xa3000100)
-
-/*
- * bc_status values
- */
-#define BC_INIT 0
-#define BC_RUN 100
-
-/*
- * bc_host values
- */
-#define BC_DIAGS -1
-#define BC_SASWITCH 0
-#define BC_SWITCH 1
-#define BC_MULTINIC 2
-
-/*
- * Values for spew (debugging)
- */
-#define BC_SPEW_ENABLE 0x80000000
-
-/*
- * filter commands
- */
-#define BC_FILTER_ERR -1
-#define BC_FILTER_OK 0
-#define BC_FILTER_SET 1
-#define BC_FILTER_CLR 2
diff --git a/drivers/net/dgrs_es4h.h b/drivers/net/dgrs_es4h.h
deleted file mode 100644
index 5518fba46b2c..000000000000
--- a/drivers/net/dgrs_es4h.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/************************************************************************/
-/* */
-/* es4h.h: Hardware definition of the ES/4h Ethernet Switch, from */
-/* both the host and the 3051's point of view. */
-/* NOTE: this name is a misnomer now that there is a PCI */
-/* board. Everything that says "es4h" should really be */
-/* "se4". But we'll keep the old name for now. */
-/* */
-/* $Id: es4h.h,v 1.10 1996/08/22 17:16:53 rick Exp $ */
-/* */
-/************************************************************************/
-
-/************************************************************************/
-/* */
-/* EISA I/O Registers. These are located at 0x1000 * slot-number */
-/* plus the indicated address. I.E. 0x4000-0x4009 for slot 4. */
-/* */
-/************************************************************************/
-
-#define ES4H_MANUFmsb 0x00 /* Read-only */
-#define ES4H_MANUFlsb 0x01 /* Read-only */
-# define ES4H_MANUF_CODE 0x1049 /* = "DBI" */
-
-#define ES4H_PRODUCT 0x02 /* Read-only */
-# define ES4H_PRODUCT_CODE 0x0A
-# define EPC_PRODUCT_CODE 0x03
-
-#define ES4H_REVISION 0x03 /* Read-only */
-# define ES4H_REVISION_CODE 0x01
-
-#define ES4H_EC 0x04 /* EISA Control */
-# define ES4H_EC_RESET 0x04 /* WO, EISA reset */
-# define ES4H_EC_ENABLE 0x01 /* RW, EISA enable - set to */
- /* 1 before memory enable */
-#define ES4H_PC 0x05 /* Processor Control */
-# define ES4H_PC_RESET 0x04 /* RW, 3051 reset */
-# define ES4H_PC_INT 0x08 /* WO, assert 3051 intr. 3 */
-
-#define ES4H_MW 0x06 /* Memory Window select and enable */
-# define ES4H_MW_ENABLE 0x80 /* WO, enable memory */
-# define ES4H_MW_SELECT_MASK 0x1f /* WO, 32k window selected */
-
-#define ES4H_IS 0x07 /* Interrupt, addr select */
-# define ES4H_IS_INTMASK 0x07 /* WO, interrupt select */
-# define ES4H_IS_INTOFF 0x00 /* No IRQ */
-# define ES4H_IS_INT3 0x03 /* IRQ 3 */
-# define ES4H_IS_INT5 0x02 /* IRQ 5 */
-# define ES4H_IS_INT7 0x01 /* IRQ 7 */
-# define ES4H_IS_INT10 0x04 /* IRQ 10 */
-# define ES4H_IS_INT11 0x05 /* IRQ 11 */
-# define ES4H_IS_INT12 0x06 /* IRQ 12 */
-# define ES4H_IS_INT15 0x07 /* IRQ 15 */
-# define ES4H_IS_INTACK 0x10 /* WO, interrupt ack */
-# define ES4H_IS_INTPEND 0x10 /* RO, interrupt pending */
-# define ES4H_IS_LINEAR 0x40 /* WO, no memory windowing */
-# define ES4H_IS_AS15 0x80 /* RW, address select bit 15 */
-
-#define ES4H_AS_23_16 0x08 /* Address select bits 23-16 */
-#define ES4H_AS_31_24 0x09 /* Address select bits 31-24 */
-
-#define ES4H_IO_MAX 0x09 /* Size of I/O space */
-
-/*
- * PCI
- */
-#define SE6_RESET PLX_USEROUT
-
-/************************************************************************/
-/* */
-/* 3051 Memory Map */
-/* */
-/* Note: 3051 has 4K I-cache, 2K D-cache. 1 cycle is 50 nsec. */
-/* */
-/************************************************************************/
-#define SE4_NPORTS 4 /* # of ethernet ports */
-#define SE6_NPORTS 6 /* # of ethernet ports */
-#define SE_NPORTS 6 /* Max # of ethernet ports */
-
-#define ES4H_RAM_BASE 0x83000000 /* Base address of RAM */
-#define ES4H_RAM_SIZE 0x00200000 /* Size of RAM (2MB) */
-#define ES4H_RAM_INTBASE 0x83800000 /* Base of int-on-write RAM */
- /* a.k.a. PKT RAM */
-
- /* Ethernet controllers */
- /* See: i82596.h */
-#define ES4H_ETHER0_PORT 0xA2000000
-#define ES4H_ETHER0_CMD 0xA2000100
-#define ES4H_ETHER1_PORT 0xA2000200
-#define ES4H_ETHER1_CMD 0xA2000300
-#define ES4H_ETHER2_PORT 0xA2000400
-#define ES4H_ETHER2_CMD 0xA2000500
-#define ES4H_ETHER3_PORT 0xA2000600
-#define ES4H_ETHER3_CMD 0xA2000700
-#define ES4H_ETHER4_PORT 0xA2000800 /* RS SE-6 only */
-#define ES4H_ETHER4_CMD 0xA2000900 /* RS SE-6 only */
-#define ES4H_ETHER5_PORT 0xA2000A00 /* RS SE-6 only */
-#define ES4H_ETHER5_CMD 0xA2000B00 /* RS SE-6 only */
-
-#define ES4H_I8254 0xA2040000 /* 82C54 timers */
- /* See: i8254.h */
-
-#define SE4_I8254_HZ (23000000/4) /* EISA clock input freq. */
-#define SE4_IDT_HZ (46000000) /* EISA CPU freq. */
-#define SE6_I8254_HZ (20000000/4) /* PCI clock input freq. */
-#define SE6_IDT_HZ (50000000) /* PCI CPU freq. */
-#define ES4H_I8254_HZ (23000000/4) /* EISA clock input freq. */
-
-#define ES4H_GPP 0xA2050000 /* General purpose port */
- /*
- * SE-4 (EISA) GPP bits
- */
-# define ES4H_GPP_C0_100 0x0001 /* WO, Chan 0: 100 ohm TP */
-# define ES4H_GPP_C0_SQE 0x0002 /* WO, Chan 0: normal squelch */
-# define ES4H_GPP_C1_100 0x0004 /* WO, Chan 1: 100 ohm TP */
-# define ES4H_GPP_C1_SQE 0x0008 /* WO, Chan 1: normal squelch */
-# define ES4H_GPP_C2_100 0x0010 /* WO, Chan 2: 100 ohm TP */
-# define ES4H_GPP_C2_SQE 0x0020 /* WO, Chan 2: normal squelch */
-# define ES4H_GPP_C3_100 0x0040 /* WO, Chan 3: 100 ohm TP */
-# define ES4H_GPP_C3_SQE 0x0080 /* WO, Chan 3: normal squelch */
-# define ES4H_GPP_SQE 0x00AA /* WO, All: normal squelch */
-# define ES4H_GPP_100 0x0055 /* WO, All: 100 ohm TP */
-# define ES4H_GPP_HOSTINT 0x0100 /* RO, cause intr. to host */
- /* Hold high > 250 nsec */
-# define SE4_GPP_EED 0x0200 /* RW, EEPROM data bit */
-# define SE4_GPP_EECS 0x0400 /* RW, EEPROM chip select */
-# define SE4_GPP_EECK 0x0800 /* RW, EEPROM clock */
-
- /*
- * SE-6 (PCI) GPP bits
- */
-# define SE6_GPP_EED 0x0001 /* RW, EEPROM data bit */
-# define SE6_GPP_EECS 0x0002 /* RW, EEPROM chip select */
-# define SE6_GPP_EECK 0x0004 /* RW, EEPROM clock */
-# define SE6_GPP_LINK 0x00fc /* R, Link status LEDs */
-
-#define ES4H_INTVEC 0xA2060000 /* RO: Interrupt Vector */
-# define ES4H_IV_DMA0 0x01 /* Chan 0 DMA interrupt */
-# define ES4H_IV_PKT0 0x02 /* Chan 0 PKT interrupt */
-# define ES4H_IV_DMA1 0x04 /* Chan 1 DMA interrupt */
-# define ES4H_IV_PKT1 0x08 /* Chan 1 PKT interrupt */
-# define ES4H_IV_DMA2 0x10 /* Chan 2 DMA interrupt */
-# define ES4H_IV_PKT2 0x20 /* Chan 2 PKT interrupt */
-# define ES4H_IV_DMA3 0x40 /* Chan 3 DMA interrupt */
-# define ES4H_IV_PKT3 0x80 /* Chan 3 PKT interrupt */
-
-#define ES4H_INTACK 0xA2060000 /* WO: Interrupt Ack */
-# define ES4H_INTACK_8254 0x01 /* Real Time Clock (int 0) */
-# define ES4H_INTACK_HOST 0x02 /* Host (int 1) */
-# define ES4H_INTACK_PKT0 0x04 /* Chan 0 Pkt (int 2) */
-# define ES4H_INTACK_PKT1 0x08 /* Chan 1 Pkt (int 3) */
-# define ES4H_INTACK_PKT2 0x10 /* Chan 2 Pkt (int 4) */
-# define ES4H_INTACK_PKT3 0x20 /* Chan 3 Pkt (int 5) */
-
-#define SE6_PLX 0xA2070000 /* PLX 9060, SE-6 (PCI) only */
- /* see plx9060.h */
-
-#define SE6_PCI_VENDOR_ID 0x114F /* Digi PCI vendor ID */
-#define SE6_PCI_DEVICE_ID 0x0003 /* RS SE-6 device ID */
-#define SE6_PCI_ID ((SE6_PCI_DEVICE_ID<<16) | SE6_PCI_VENDOR_ID)
-
-/*
- * IDT Interrupts
- */
-#define ES4H_INT_8254 IDT_INT0
-#define ES4H_INT_HOST IDT_INT1
-#define ES4H_INT_ETHER0 IDT_INT2
-#define ES4H_INT_ETHER1 IDT_INT3
-#define ES4H_INT_ETHER2 IDT_INT4
-#define ES4H_INT_ETHER3 IDT_INT5
-
-/*
- * Because there are differences between the SE-4 and the SE-6,
- * we assume that the following globals will be set up at init
- * time in main.c to containt the appropriate constants from above
- */
-extern ushort Gpp; /* Softcopy of GPP register */
-extern ushort EEck; /* Clock bit */
-extern ushort EEcs; /* CS bit */
-extern ushort EEd; /* Data bit */
-extern ulong I8254_Hz; /* i8254 input frequency */
-extern ulong IDT_Hz; /* IDT CPU frequency */
-extern int Nports; /* Number of ethernet controllers */
-extern int Nchan; /* Nports+1 */
diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h
deleted file mode 100644
index 7539b596bff8..000000000000
--- a/drivers/net/dgrs_ether.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * A filtering function. There are two filters/port. Filter "0"
- * is the input filter, and filter "1" is the output filter.
- */
-typedef int (FILTER_FUNC)(uchar *pktp, int pktlen, ulong *scratch, int port);
-#define NFILTERS 2
-
-/*
- * The per port structure
- */
-typedef struct
-{
- int chan; /* Channel number (0-3) */
- ulong portaddr; /* address of 596 port register */
- volatile ulong *ca; /* address of 596 chan attention */
- ulong intmask; /* Interrupt mask for this port */
- ulong intack; /* Ack bit for this port */
-
- uchar ethaddr[6]; /* Ethernet address of this port */
- int is_promisc; /* Port is promiscuous */
-
- int debug; /* Debugging turned on */
-
- I596_ISCP *iscpp; /* Uncached ISCP pointer */
- I596_SCP *scpp; /* Uncached SCP pointer */
- I596_SCB *scbp; /* Uncached SCB pointer */
-
- I596_ISCP iscp;
- I596_SCB scb;
-
- /* Command Queue */
- I596_CB *cb0;
- I596_CB *cbN;
- I596_CB *cb_head;
- I596_CB *cb_tail;
-
- /* Receive Queue */
- I596_RFD *rfd0;
- I596_RFD *rfdN;
- I596_RFD *rfd_head;
- I596_RFD *rfd_tail;
-
- /* Receive Buffers */
- I596_RBD *rbd0;
- I596_RBD *rbdN;
- I596_RBD *rbd_head;
- I596_RBD *rbd_tail;
- int buf_size; /* Size of an RBD buffer */
- int buf_cnt; /* Total RBD's allocated */
-
- /* Rx Statistics */
- ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
- ulong cnt_rx_good; /* Total good packets rcvd */
- ulong cnt_rx_bad; /* Total of all bad packets rcvd */
- /* Subtotals can be gotten from SCB */
- ulong cnt_rx_nores; /* No resources */
- ulong cnt_rx_bytes; /* Total bytes rcvd */
-
- /* Tx Statistics */
- ulong cnt_tx_queued;
- ulong cnt_tx_done;
- ulong cnt_tx_freed;
- ulong cnt_tx_nores; /* No resources */
-
- ulong cnt_tx_bad;
- ulong cnt_tx_err_late;
- ulong cnt_tx_err_nocrs;
- ulong cnt_tx_err_nocts;
- ulong cnt_tx_err_under;
- ulong cnt_tx_err_maxcol;
- ulong cnt_tx_collisions;
-
- /* Special stuff for host */
-# define rfd_freed cnt_rx_cnt
- ulong rbd_freed;
- int host_timer;
-
- /* Added after first beta */
- ulong cnt_tx_races; /* Counts race conditions */
- int spanstate;
- ulong cnt_st_tx; /* send span tree pkts */
- ulong cnt_st_fail_tx; /* Failures to send span tree pkts */
- ulong cnt_st_fail_rbd;/* Failures to send span tree pkts */
- ulong cnt_st_rx; /* rcv span tree pkts */
- ulong cnt_st_rx_bad; /* bogus st packets rcvd */
- ulong cnt_rx_fwd; /* Rcvd packets that were forwarded */
-
- ulong cnt_rx_mcast; /* Multicast pkts received */
- ulong cnt_tx_mcast; /* Multicast pkts transmitted */
- ulong cnt_tx_bytes; /* Bytes transmitted */
-
- /*
- * Packet filtering
- * Filter 0: input filter
- * Filter 1: output filter
- */
-
- ulong *filter_space[NFILTERS];
- FILTER_FUNC *filter_func[NFILTERS];
- ulong filter_cnt[NFILTERS];
- ulong filter_len[NFILTERS];
-
- ulong pad[ (512-300) / 4];
-} PORT;
-
-/*
- * Port[0] is host interface
- * Port[1..SE_NPORTS] are external 10 Base T ports. Fewer may be in
- * use, depending on whether this is an SE-4 or
- * an SE-6.
- * Port[SE_NPORTS] Pseudo-port for Spanning tree and SNMP
- */
-extern PORT Port[1+SE_NPORTS+1];
-
-extern int Nports; /* Number of genuine ethernet controllers */
-extern int Nchan; /* ... plus one for host interface */
-
-extern int FirstChan; /* 0 or 1, depedning on whether host is used */
-extern int NumChan; /* 4 or 5 */
-
-/*
- * A few globals
- */
-extern int IsPromisc;
-extern int MultiNicMode;
-
-/*
- * Functions
- */
-extern void eth_xmit_spew_on(PORT *p, int cnt);
-extern void eth_xmit_spew_off(PORT *p);
-
-extern I596_RBD *alloc_rbds(PORT *p, int num);
-
-extern I596_CB * eth_cb_alloc(PORT *p);
diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c
deleted file mode 100644
index 8c20d4c99937..000000000000
--- a/drivers/net/dgrs_firmware.c
+++ /dev/null
@@ -1,9966 +0,0 @@
-static const int dgrs_firmnum = 550;
-static char dgrs_firmver[] = "$Version$";
-static char dgrs_firmdate[] = "11/16/96 03:45:15";
-static unsigned char dgrs_code[] __initdata = {
- 213,5,192,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,64,40,35,41,
- 101,115,52,104,46,98,105,110,32,32,32,32,
- 32,32,49,46,48,32,48,48,47,48,48,47,
- 57,52,0,64,40,35,41,67,111,112,121,114,
- 105,103,104,116,32,49,57,57,53,44,32,68,
- 105,103,105,32,73,110,116,101,114,110,97,116,
- 105,111,110,97,108,46,32,32,65,108,108,32,
- 82,105,103,104,116,115,32,82,101,115,101,114,
- 118,101,100,46,0,0,0,0,97,5,192,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,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,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,0,16,0,0,0,0,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 148,255,189,39,16,0,161,175,20,0,162,175,
- 24,0,163,175,28,0,164,175,32,0,165,175,
- 36,0,166,175,40,0,167,175,44,0,168,175,
- 48,0,169,175,52,0,170,175,56,0,171,175,
- 60,0,172,175,64,0,173,175,68,0,174,175,
- 72,0,175,175,76,0,184,175,80,0,185,175,
- 88,0,190,175,92,0,191,175,0,112,8,64,
- 18,72,0,0,16,80,0,0,0,96,11,64,
- 84,0,168,175,96,0,169,175,100,0,170,175,
- 104,0,171,175,33,56,0,1,0,131,24,60,
- 0,1,24,39,0,0,8,143,0,0,0,0,
- 1,0,8,33,0,0,8,175,0,104,5,64,
- 0,96,6,64,124,0,168,48,212,255,0,21,
- 0,0,0,0,36,64,166,0,0,255,8,49,
- 27,0,0,17,0,0,0,0,130,65,8,0,
- 2,131,9,60,33,72,40,1,0,220,41,141,
- 66,64,8,0,2,131,10,60,33,80,72,1,
- 0,224,74,141,0,0,0,0,38,80,70,1,
- 1,255,74,49,33,40,192,0,38,48,202,0,
- 0,96,134,64,66,64,8,0,2,131,4,60,
- 33,32,136,0,0,226,132,144,9,248,32,1,
- 0,0,0,0,104,0,166,143,0,0,0,0,
- 0,96,134,64,0,104,5,64,227,255,0,16,
- 0,0,0,0,104,0,168,143,96,0,169,143,
- 100,0,170,143,0,0,0,0,0,96,136,64,
- 19,0,32,1,17,0,64,1,20,0,162,143,
- 24,0,163,143,28,0,164,143,32,0,165,143,
- 36,0,166,143,40,0,167,143,44,0,168,143,
- 48,0,169,143,52,0,170,143,56,0,171,143,
- 60,0,172,143,64,0,173,143,68,0,174,143,
- 72,0,175,143,76,0,184,143,80,0,185,143,
- 88,0,190,143,92,0,191,143,0,0,0,0,
- 84,0,186,143,16,0,161,143,108,0,189,39,
- 8,0,64,3,16,0,0,66,0,96,26,64,
- 0,0,0,0,255,255,27,60,254,0,123,55,
- 0,0,0,0,36,208,91,3,0,0,0,0,
- 0,96,154,64,0,0,0,0,0,112,26,64,
- 0,0,0,0,16,0,0,66,0,0,0,0,
- 8,0,64,3,0,0,0,0,255,255,8,36,
- 133,255,0,17,0,0,0,0,1,0,8,37,
- 130,255,0,21,0,0,0,0,255,255,8,36,
- 33,8,0,1,126,255,40,20,0,0,0,0,
- 1,0,33,36,123,255,32,20,0,0,0,0,
- 255,255,2,36,120,255,72,20,0,0,0,0,
- 1,0,66,36,117,255,64,20,0,0,0,0,
- 255,255,3,36,114,255,104,20,0,0,0,0,
- 1,0,99,36,111,255,96,20,0,0,0,0,
- 255,255,4,36,108,255,136,20,0,0,0,0,
- 1,0,132,36,105,255,128,20,0,0,0,0,
- 255,255,5,36,102,255,168,20,0,0,0,0,
- 1,0,165,36,99,255,160,20,0,0,0,0,
- 255,255,6,36,96,255,200,20,0,0,0,0,
- 1,0,198,36,93,255,192,20,0,0,0,0,
- 255,255,7,36,90,255,232,20,0,0,0,0,
- 1,0,231,36,87,255,224,20,0,0,0,0,
- 255,255,9,36,84,255,40,21,0,0,0,0,
- 1,0,41,37,81,255,32,21,0,0,0,0,
- 255,255,10,36,78,255,72,21,0,0,0,0,
- 1,0,74,37,75,255,64,21,0,0,0,0,
- 255,255,11,36,72,255,104,21,0,0,0,0,
- 1,0,107,37,69,255,96,21,0,0,0,0,
- 255,255,12,36,66,255,136,21,0,0,0,0,
- 1,0,140,37,63,255,128,21,0,0,0,0,
- 255,255,13,36,60,255,168,21,0,0,0,0,
- 1,0,173,37,57,255,160,21,0,0,0,0,
- 255,255,14,36,54,255,200,21,0,0,0,0,
- 1,0,206,37,51,255,192,21,0,0,0,0,
- 255,255,15,36,48,255,232,21,0,0,0,0,
- 1,0,239,37,45,255,224,21,0,0,0,0,
- 255,255,24,36,42,255,8,23,0,0,0,0,
- 1,0,24,39,39,255,0,23,0,0,0,0,
- 255,255,16,36,36,255,8,22,0,0,0,0,
- 1,0,16,38,33,255,0,22,0,0,0,0,
- 255,255,17,36,30,255,40,22,0,0,0,0,
- 1,0,49,38,27,255,32,22,0,0,0,0,
- 255,255,18,36,24,255,72,22,0,0,0,0,
- 1,0,82,38,21,255,64,22,0,0,0,0,
- 255,255,19,36,18,255,104,22,0,0,0,0,
- 1,0,115,38,15,255,96,22,0,0,0,0,
- 255,255,20,36,12,255,136,22,0,0,0,0,
- 1,0,148,38,9,255,128,22,0,0,0,0,
- 255,255,21,36,6,255,168,22,0,0,0,0,
- 1,0,181,38,3,255,160,22,0,0,0,0,
- 255,255,22,36,0,255,200,22,0,0,0,0,
- 1,0,214,38,253,254,192,22,0,0,0,0,
- 255,255,23,36,250,254,232,22,0,0,0,0,
- 1,0,247,38,247,254,224,22,0,0,0,0,
- 255,255,26,36,244,254,72,23,0,0,0,0,
- 1,0,90,39,241,254,64,23,0,0,0,0,
- 255,255,27,36,238,254,104,23,0,0,0,0,
- 1,0,123,39,235,254,96,23,0,0,0,0,
- 255,255,28,36,232,254,136,23,0,0,0,0,
- 1,0,156,39,229,254,128,23,0,0,0,0,
- 255,255,29,36,226,254,168,23,0,0,0,0,
- 1,0,189,39,223,254,160,23,0,0,0,0,
- 255,255,30,36,220,254,200,23,0,0,0,0,
- 1,0,222,39,217,254,192,23,0,0,0,0,
- 255,255,31,36,214,254,232,23,0,0,0,0,
- 1,0,255,39,211,254,224,23,0,0,0,0,
- 0,131,24,60,0,1,24,39,0,32,1,60,
- 37,192,1,3,0,96,8,64,0,0,0,0,
- 1,0,1,60,37,64,1,1,0,96,136,64,
- 33,16,0,0,165,165,3,60,165,165,99,52,
- 0,128,1,60,0,0,35,172,0,128,9,60,
- 0,0,41,141,0,0,0,0,0,96,10,64,
- 0,0,0,0,8,0,1,60,36,80,65,1,
- 29,0,64,21,0,0,0,0,27,0,105,20,
- 0,0,0,0,0,1,2,36,0,128,1,60,
- 33,8,34,0,0,0,32,172,64,16,2,0,
- 1,0,1,60,1,0,33,52,43,8,65,0,
- 248,255,32,20,0,0,0,0,255,255,3,36,
- 0,128,1,60,0,0,35,172,0,1,2,36,
- 0,128,3,60,33,24,98,0,0,0,99,140,
- 0,0,0,0,7,0,96,20,0,0,0,0,
- 64,16,2,0,1,0,1,60,1,0,33,52,
- 43,8,65,0,245,255,32,20,0,0,0,0,
- 0,96,128,64,0,0,0,0,84,0,2,175,
- 0,96,8,64,0,0,0,0,3,0,1,60,
- 37,64,1,1,0,96,136,64,33,16,0,0,
- 165,165,3,60,165,165,99,52,0,128,1,60,
- 0,0,35,172,0,128,9,60,0,0,41,141,
- 0,0,0,0,0,96,10,64,0,0,0,0,
- 8,0,1,60,36,80,65,1,29,0,64,21,
- 0,0,0,0,27,0,105,20,0,0,0,0,
- 0,1,2,36,0,128,1,60,33,8,34,0,
- 0,0,32,172,64,16,2,0,1,0,1,60,
- 1,0,33,52,43,8,65,0,248,255,32,20,
- 0,0,0,0,255,255,3,36,0,128,1,60,
- 0,0,35,172,0,1,2,36,0,128,3,60,
- 33,24,98,0,0,0,99,140,0,0,0,0,
- 7,0,96,20,0,0,0,0,64,16,2,0,
- 1,0,1,60,1,0,33,52,43,8,65,0,
- 245,255,32,20,0,0,0,0,0,96,128,64,
- 0,0,0,0,88,0,2,175,88,0,9,143,
- 0,0,0,0,17,0,32,17,0,0,0,0,
- 0,0,0,0,3,0,2,60,0,0,0,0,
- 0,96,130,64,0,128,8,60,37,72,40,1,
- 0,0,0,161,4,0,0,161,8,0,0,161,
- 12,0,0,161,16,0,0,161,20,0,0,161,
- 24,0,0,161,32,0,8,37,247,255,9,21,
- 252,255,0,161,84,0,9,143,0,0,0,0,
- 17,0,32,17,0,0,0,0,0,0,0,0,
- 1,0,2,60,0,0,0,0,0,96,130,64,
- 0,128,8,60,37,72,40,1,0,0,0,161,
- 4,0,0,161,8,0,0,161,12,0,0,161,
- 16,0,0,161,20,0,0,161,24,0,0,161,
- 32,0,8,37,247,255,9,21,252,255,0,161,
- 32,0,8,60,0,96,136,64,0,104,128,64,
- 0,131,2,60,152,28,66,36,255,31,9,60,
- 255,255,41,53,36,16,73,0,0,128,9,60,
- 37,16,73,0,8,0,64,0,0,0,0,0,
- 2,131,8,60,224,210,8,37,252,255,1,36,
- 36,64,1,1,3,131,9,60,124,18,41,37,
- 252,255,1,36,36,72,33,1,0,0,10,36,
- 0,0,10,173,254,255,9,21,4,0,8,37,
- 3,131,8,60,128,18,8,37,252,255,1,36,
- 36,64,1,1,31,131,9,60,252,255,41,53,
- 252,255,1,36,36,72,33,1,237,254,10,60,
- 175,222,74,53,0,0,10,173,254,255,9,21,
- 4,0,8,37,2,131,8,60,0,212,8,37,
- 252,255,1,36,36,64,1,1,2,131,9,60,
- 252,219,41,37,252,255,1,36,36,72,33,1,
- 173,222,10,60,239,190,74,53,0,0,10,173,
- 254,255,9,21,4,0,8,37,0,4,8,60,
- 0,0,0,0,0,24,136,64,0,0,0,0,
- 2,131,29,60,0,220,189,39,0,0,30,36,
- 2,131,28,60,51,8,192,12,16,78,156,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,0,0,0,0,0,0,
- 232,255,189,39,16,0,191,175,8,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,12,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,16,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,20,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,24,133,131,143,6,0,2,36,
- 20,0,191,175,6,0,98,20,16,0,176,175,
- 7,162,3,60,228,0,99,52,1,0,2,36,
- 184,7,192,8,0,0,98,172,0,128,130,151,
- 5,162,16,60,0,1,66,52,120,63,192,12,
- 0,0,2,166,0,128,130,151,0,0,0,0,
- 255,254,66,48,0,0,2,166,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,33,16,128,0,3,0,64,4,
- 16,0,191,175,254,255,2,60,192,29,66,52,
- 0,163,4,60,96,1,132,52,0,163,1,60,
- 92,1,34,172,0,163,1,60,104,1,38,172,
- 204,63,192,12,8,0,6,36,228,63,192,12,
- 255,255,4,36,204,7,192,8,0,0,0,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,216,255,189,39,1,0,6,36,
- 3,131,2,60,143,18,66,36,240,255,3,36,
- 36,16,67,0,0,163,1,60,120,1,34,172,
- 0,163,2,60,120,1,66,140,33,56,0,0,
- 32,0,191,175,28,0,177,175,24,0,176,175,
- 16,0,160,175,0,163,1,60,116,1,34,172,
- 0,163,3,60,112,1,99,140,0,163,2,60,
- 116,1,66,140,0,163,4,60,116,1,132,140,
- 35,136,98,0,84,64,192,12,33,40,32,2,
- 13,0,64,16,0,0,0,0,1,131,4,60,
- 96,127,132,36,24,128,144,39,33,40,0,2,
- 1,131,7,60,128,127,231,36,15,63,192,12,
- 148,0,6,36,1,0,4,36,33,40,0,2,
- 188,7,192,12,148,0,6,36,2,0,33,6,
- 33,16,32,2,3,0,34,38,131,136,2,0,
- 0,163,2,60,116,1,66,140,0,0,0,0,
- 6,0,32,18,237,254,3,60,175,222,99,52,
- 0,0,67,172,255,255,49,38,253,255,32,22,
- 4,0,66,36,32,0,191,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 224,255,189,39,15,0,132,36,240,255,3,36,
- 20,0,177,175,0,163,17,60,120,1,49,142,
- 0,163,2,60,120,1,66,140,36,32,131,0,
- 33,16,68,0,0,163,1,60,120,1,34,172,
- 0,163,3,60,120,1,99,140,0,163,2,60,
- 112,1,66,140,24,0,191,175,43,16,67,0,
- 13,0,64,16,16,0,176,175,1,131,4,60,
- 96,127,132,36,24,128,144,39,33,40,0,2,
- 1,131,7,60,176,127,231,36,15,63,192,12,
- 171,0,6,36,1,0,4,36,33,40,0,2,
- 188,7,192,12,171,0,6,36,33,16,32,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 3,0,2,60,7,162,3,60,36,0,191,175,
- 32,0,176,175,0,163,1,60,92,1,32,172,
- 0,0,99,140,79,17,66,52,32,0,98,20,
- 87,0,4,60,76,0,8,60,64,75,8,53,
- 250,2,7,60,128,240,231,52,7,162,6,60,
- 152,0,198,52,67,73,3,60,67,3,99,52,
- 7,162,4,60,48,1,132,52,7,162,5,60,
- 0,1,165,52,6,0,2,36,24,133,130,175,
- 0,163,1,60,204,5,34,172,4,0,2,36,
- 50,133,130,167,2,0,2,36,48,133,130,167,
- 1,0,2,36,20,133,130,167,119,119,2,36,
- 28,133,136,175,16,133,135,175,0,0,195,172,
- 0,0,130,172,67,1,2,36,0,0,162,172,
- 109,8,192,8,31,131,4,60,240,188,132,52,
- 189,2,3,60,128,231,99,52,4,0,2,36,
- 24,133,130,175,0,163,1,60,204,5,34,172,
- 0,8,2,36,50,133,130,167,0,4,2,36,
- 48,133,130,167,0,2,2,36,20,133,130,167,
- 28,133,132,175,16,133,131,175,31,131,4,60,
- 0,240,132,52,24,133,131,143,0,131,2,60,
- 0,163,1,60,108,1,34,172,0,163,1,60,
- 112,1,36,172,1,0,99,36,32,133,131,175,
- 210,7,192,12,0,0,0,0,0,163,2,60,
- 132,1,66,140,0,128,128,167,2,0,64,20,
- 85,0,2,36,0,128,130,167,0,163,2,60,
- 136,1,66,140,0,0,0,0,5,0,64,20,
- 0,0,0,0,0,128,130,151,0,0,0,0,
- 170,0,66,52,0,128,130,167,0,128,131,151,
- 5,162,2,60,0,0,67,164,188,64,192,12,
- 1,0,16,36,2,131,4,60,0,220,132,36,
- 2,131,5,60,0,224,165,36,2,131,6,60,
- 0,226,198,36,8,0,7,36,2,131,2,60,
- 112,154,66,36,16,0,162,175,2,131,2,60,
- 144,154,66,36,20,0,162,175,2,131,2,60,
- 176,154,66,36,24,0,162,175,0,131,2,60,
- 36,30,66,36,0,163,1,60,92,1,48,172,
- 240,64,192,12,28,0,162,175,0,163,3,60,
- 124,1,99,140,40,133,128,175,2,0,98,40,
- 7,0,64,16,2,0,2,36,18,0,97,4,
- 255,255,2,36,7,0,98,16,0,0,0,0,
- 196,8,192,8,0,0,0,0,16,0,98,16,
- 0,0,0,0,196,8,192,8,0,0,0,0,
- 24,133,133,143,1,131,4,60,15,63,192,12,
- 208,127,132,36,0,163,1,60,112,25,192,12,
- 124,1,32,172,207,8,192,8,0,0,0,0,
- 211,8,192,12,0,0,0,0,207,8,192,8,
- 0,0,0,0,40,133,144,175,31,10,192,12,
- 0,0,0,0,207,8,192,8,0,0,0,0,
- 1,131,4,60,96,127,132,36,24,128,144,39,
- 33,40,0,2,32,128,135,39,15,63,192,12,
- 58,1,6,36,1,0,4,36,33,40,0,2,
- 188,7,192,12,58,1,6,36,36,0,191,143,
- 32,0,176,143,8,0,224,3,40,0,189,39,
- 192,255,189,39,56,0,191,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,180,10,192,12,32,0,176,175,
- 33,32,0,0,2,0,2,36,0,163,1,60,
- 244,57,192,12,92,1,34,172,3,0,2,36,
- 0,163,1,60,0,12,192,12,92,1,34,172,
- 1,0,4,36,4,0,2,36,0,163,1,60,
- 34,11,192,12,92,1,34,172,5,0,2,36,
- 0,163,1,60,92,1,34,172,0,163,19,60,
- 124,1,115,142,0,163,3,60,160,1,99,140,
- 1,0,98,46,80,133,130,175,0,128,2,60,
- 5,0,98,20,0,0,0,0,32,133,130,143,
- 0,0,0,0,252,8,192,8,255,255,66,36,
- 32,133,130,143,0,0,0,0,84,133,130,175,
- 130,11,192,12,0,0,0,0,33,32,64,0,
- 2,0,5,36,232,3,6,36,0,131,7,60,
- 196,37,231,36,156,11,192,12,16,0,160,175,
- 35,35,192,12,0,0,0,0,6,0,2,36,
- 0,163,1,60,84,35,192,12,92,1,34,172,
- 7,0,2,36,0,163,1,60,141,47,192,12,
- 92,1,34,172,8,0,2,36,0,163,1,60,
- 120,50,192,12,92,1,34,172,9,0,2,36,
- 0,163,1,60,92,1,34,172,0,163,2,60,
- 240,5,66,140,0,0,0,0,8,0,64,16,
- 10,0,2,36,0,163,4,60,240,5,132,140,
- 13,8,192,12,0,0,0,0,0,163,1,60,
- 244,5,34,172,10,0,2,36,0,163,1,60,
- 92,1,34,172,157,15,192,12,1,0,21,36,
- 2,131,2,60,192,246,66,36,33,160,64,0,
- 80,133,131,143,11,0,2,36,0,163,1,60,
- 92,1,34,172,100,0,2,36,0,163,1,60,
- 92,1,34,172,84,133,130,143,64,26,3,0,
- 33,136,116,0,64,18,2,0,33,144,84,0,
- 0,163,2,60,8,1,66,140,0,0,0,0,
- 1,0,66,36,0,163,1,60,8,1,34,172,
- 0,163,2,60,8,1,66,140,0,163,2,60,
- 124,1,66,140,0,0,0,0,14,0,83,16,
- 0,0,0,0,4,0,64,16,33,152,64,0,
- 80,133,128,175,76,9,192,8,0,0,0,0,
- 80,133,149,175,2,131,4,60,163,23,192,12,
- 192,246,132,36,80,133,130,143,0,0,0,0,
- 64,18,2,0,33,136,84,0,0,163,2,60,
- 0,6,66,140,0,0,0,0,3,0,64,24,
- 33,128,32,2,239,15,192,12,0,0,0,0,
- 43,16,18,2,11,0,64,16,33,32,0,2,
- 151,18,192,12,10,0,5,36,27,22,192,12,
- 33,32,0,2,142,22,192,12,33,32,0,2,
- 0,2,16,38,43,16,18,2,247,255,64,20,
- 33,32,0,2,184,11,192,12,0,0,0,0,
- 54,9,192,8,0,0,0,0,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,4,128,130,143,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 1,0,67,36,4,128,131,175,255,255,3,36,
- 4,0,67,20,255,31,4,60,0,163,1,60,
- 8,1,32,172,255,31,4,60,255,255,132,52,
- 0,163,16,60,0,163,2,60,8,1,66,140,
- 208,132,131,143,220,5,16,54,35,16,67,0,
- 0,163,1,60,16,1,34,172,2,131,2,60,
- 192,246,66,36,36,16,68,0,0,160,3,60,
- 37,16,67,0,0,163,3,60,8,1,99,140,
- 28,0,68,140,0,0,5,142,3,131,2,60,
- 20,18,66,140,208,132,131,175,36,133,132,175,
- 18,0,162,16,0,163,4,60,99,59,192,12,
- 220,5,132,52,255,0,5,60,255,0,165,52,
- 0,255,6,60,0,0,4,142,0,255,198,52,
- 0,20,4,0,2,28,4,0,37,16,67,0,
- 2,26,2,0,36,24,101,0,0,18,2,0,
- 36,16,70,0,37,24,98,0,176,133,132,175,
- 184,133,131,175,0,163,16,60,16,6,16,54,
- 0,0,3,142,3,131,2,60,68,18,66,140,
- 0,0,0,0,18,0,98,16,0,163,4,60,
- 119,59,192,12,16,6,132,52,255,0,5,60,
- 255,0,165,52,0,255,6,60,0,0,4,142,
- 0,255,198,52,0,20,4,0,2,28,4,0,
- 37,16,67,0,2,26,2,0,36,24,101,0,
- 0,18,2,0,36,16,70,0,37,24,98,0,
- 196,133,132,175,192,133,131,175,0,163,16,60,
- 224,5,16,54,0,0,3,142,3,131,2,60,
- 24,18,66,140,0,0,0,0,18,0,98,16,
- 0,163,4,60,139,59,192,12,224,5,132,52,
- 255,0,5,60,255,0,165,52,0,255,6,60,
- 0,0,4,142,0,255,198,52,0,20,4,0,
- 2,28,4,0,37,16,67,0,2,26,2,0,
- 36,24,101,0,0,18,2,0,36,16,70,0,
- 37,24,98,0,188,133,132,175,180,133,131,175,
- 44,133,131,143,0,163,2,60,144,1,66,140,
- 0,0,0,0,5,0,98,16,0,0,0,0,
- 0,163,4,60,144,1,132,140,159,59,192,12,
- 0,0,0,0,0,163,3,60,140,1,99,140,
- 3,131,2,60,64,18,66,140,0,0,0,0,
- 5,0,98,16,0,0,0,0,0,163,4,60,
- 140,1,132,140,51,60,192,12,0,0,0,0,
- 44,133,130,143,0,0,0,0,3,0,64,16,
- 0,0,0,0,116,38,192,12,0,0,0,0,
- 164,7,192,12,0,0,0,0,36,128,130,143,
- 0,0,0,0,1,0,66,36,36,128,130,175,
- 60,0,66,40,8,0,64,20,0,0,0,0,
- 3,131,2,60,24,18,66,140,36,128,128,175,
- 3,0,64,16,0,0,0,0,222,48,192,12,
- 0,0,0,0,0,163,2,60,48,1,66,140,
- 0,0,0,0,20,0,64,16,0,0,0,0,
- 0,163,1,60,48,1,32,172,0,163,1,60,
- 16,1,32,172,0,163,1,60,20,1,32,172,
- 0,163,1,60,24,1,32,172,0,163,1,60,
- 28,1,32,172,0,163,1,60,32,1,32,172,
- 0,163,1,60,36,1,32,172,0,163,1,60,
- 40,1,32,172,0,163,1,60,201,13,192,12,
- 44,1,32,172,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,216,255,189,39,
- 36,0,191,175,32,0,178,175,28,0,177,175,
- 180,10,192,12,24,0,176,175,33,32,0,0,
- 2,0,2,36,0,163,1,60,244,57,192,12,
- 92,1,34,172,3,0,2,36,0,163,1,60,
- 0,12,192,12,92,1,34,172,1,0,4,36,
- 4,0,2,36,0,163,1,60,34,11,192,12,
- 92,1,34,172,32,133,131,143,5,0,2,36,
- 0,163,1,60,92,1,34,172,80,133,128,175,
- 84,133,131,175,130,11,192,12,0,0,0,0,
- 33,32,64,0,2,0,5,36,232,3,6,36,
- 0,131,7,60,196,37,231,36,156,11,192,12,
- 16,0,160,175,0,163,2,60,240,5,66,140,
- 0,0,0,0,8,0,64,16,10,0,2,36,
- 0,163,4,60,240,5,132,140,13,8,192,12,
- 0,0,0,0,0,163,1,60,244,5,34,172,
- 10,0,2,36,0,163,1,60,92,1,34,172,
- 100,0,2,36,80,133,131,143,2,131,4,60,
- 192,246,132,36,0,163,1,60,92,1,34,172,
- 84,133,130,143,64,26,3,0,33,144,100,0,
- 64,18,2,0,33,136,68,0,0,163,2,60,
- 8,1,66,140,33,128,64,2,1,0,66,36,
- 0,163,1,60,8,1,34,172,0,163,2,60,
- 8,1,66,140,43,16,17,2,11,0,64,16,
- 33,32,0,2,151,18,192,12,10,0,5,36,
- 27,22,192,12,33,32,0,2,142,22,192,12,
- 33,32,0,2,0,2,16,38,43,16,17,2,
- 247,255,64,20,33,32,0,2,184,11,192,12,
- 0,0,0,0,91,10,192,8,0,0,0,0,
- 36,0,191,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 4,128,130,143,232,255,189,39,16,0,191,175,
- 1,0,67,36,4,128,131,175,255,255,3,36,
- 4,0,67,20,255,31,4,60,0,163,1,60,
- 8,1,32,172,255,31,4,60,0,163,2,60,
- 8,1,66,140,212,132,131,143,255,255,132,52,
- 35,16,67,0,0,163,1,60,16,1,34,172,
- 2,131,2,60,192,246,66,36,36,16,68,0,
- 0,160,3,60,37,16,67,0,0,163,3,60,
- 8,1,99,140,28,0,66,140,212,132,131,175,
- 36,133,130,175,164,7,192,12,0,0,0,0,
- 0,163,2,60,48,1,66,140,0,0,0,0,
- 20,0,64,16,0,0,0,0,0,163,1,60,
- 48,1,32,172,0,163,1,60,16,1,32,172,
- 0,163,1,60,20,1,32,172,0,163,1,60,
- 24,1,32,172,0,163,1,60,28,1,32,172,
- 0,163,1,60,32,1,32,172,0,163,1,60,
- 36,1,32,172,0,163,1,60,40,1,32,172,
- 0,163,1,60,201,13,192,12,44,1,32,172,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,224,255,189,39,24,0,191,175,
- 20,0,177,175,120,63,192,12,16,0,176,175,
- 52,0,2,36,4,162,1,60,12,0,34,160,
- 120,63,192,12,232,3,16,36,28,133,130,143,
- 0,0,0,0,27,0,80,0,2,0,0,22,
- 0,0,0,0,13,0,7,0,18,16,0,0,
- 4,162,17,60,120,63,192,12,0,0,34,162,
- 28,133,130,143,0,0,0,0,27,0,80,0,
- 2,0,0,22,0,0,0,0,13,0,7,0,
- 18,16,0,0,33,40,0,0,33,32,0,0,
- 6,162,3,60,2,18,2,0,0,0,34,162,
- 1,0,2,36,0,163,1,60,4,1,32,172,
- 0,0,98,172,2,131,1,60,33,8,36,0,
- 8,245,32,172,1,0,165,36,22,0,162,44,
- 250,255,64,20,20,0,132,36,31,131,4,60,
- 0,240,132,52,52,128,131,143,1,0,2,36,
- 68,133,128,175,48,128,130,175,64,133,128,175,
- 32,131,1,60,252,239,36,172,8,0,96,16,
- 31,131,5,60,252,239,165,52,31,131,6,60,
- 1,131,4,60,224,127,132,36,15,63,192,12,
- 0,240,198,52,52,128,128,175,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,16,0,176,175,
- 116,0,2,36,20,0,191,175,4,162,1,60,
- 12,0,34,160,130,63,192,12,33,128,128,0,
- 4,162,1,60,4,0,48,160,130,63,192,12,
- 3,130,16,0,4,162,1,60,130,63,192,12,
- 4,0,48,160,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,224,255,189,39,
- 64,0,2,36,24,0,191,175,20,0,177,175,
- 16,0,176,175,4,162,1,60,130,63,192,12,
- 12,0,34,160,4,162,17,60,4,0,49,146,
- 0,0,0,0,130,63,192,12,255,0,49,50,
- 4,162,16,60,4,0,16,146,0,0,0,0,
- 130,63,192,12,255,0,16,50,0,130,16,0,
- 37,16,17,2,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 48,128,130,143,232,255,189,39,16,0,176,175,
- 33,128,128,0,3,0,64,20,20,0,191,175,
- 180,10,192,12,0,0,0,0,5,0,0,18,
- 0,0,0,0,236,63,192,12,1,4,4,36,
- 50,11,192,8,0,0,0,0,228,63,192,12,
- 0,4,4,36,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,216,255,189,39,
- 6,162,3,60,1,0,2,36,32,0,191,175,
- 28,0,177,175,24,0,176,175,0,0,98,172,
- 0,163,2,60,4,1,66,140,33,136,224,0,
- 1,0,66,36,0,163,1,60,4,1,34,172,
- 56,128,130,143,0,163,3,60,4,1,99,140,
- 1,0,66,36,56,128,130,175,232,3,66,40,
- 21,0,64,20,255,127,3,60,68,133,130,143,
- 254,255,99,52,56,128,128,175,1,0,66,36,
- 43,24,98,0,68,133,130,175,13,0,96,16,
- 0,0,0,0,2,131,4,60,28,128,132,36,
- 60,128,144,39,33,40,0,2,2,131,7,60,
- 60,128,231,36,15,63,192,12,144,0,6,36,
- 1,0,4,36,33,40,0,2,188,7,192,12,
- 144,0,6,36,64,133,134,143,0,0,0,0,
- 14,0,192,24,33,24,0,0,2,131,5,60,
- 0,245,165,36,33,32,0,0,2,131,2,60,
- 33,16,68,0,0,245,66,140,20,0,132,36,
- 1,0,99,36,255,255,66,36,0,0,162,172,
- 42,16,102,0,247,255,64,20,20,0,165,36,
- 31,131,4,60,252,239,132,52,31,131,2,60,
- 0,0,131,140,255,255,66,52,0,0,113,172,
- 4,0,99,36,43,16,67,0,3,0,64,16,
- 0,0,0,0,31,131,3,60,0,240,99,52,
- 0,0,131,172,32,0,191,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 64,133,130,143,232,255,189,39,20,0,191,175,
- 22,0,66,40,13,0,64,20,16,0,176,175,
- 2,131,4,60,28,128,132,36,60,128,144,39,
- 33,40,0,2,2,131,7,60,84,128,231,36,
- 15,63,192,12,173,0,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,173,0,6,36,
- 64,133,130,143,0,0,0,0,1,0,67,36,
- 64,133,131,175,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,128,16,4,0,
- 33,16,68,0,16,0,163,143,128,16,2,0,
- 2,131,1,60,33,8,34,0,4,245,38,172,
- 2,131,1,60,33,8,34,0,12,245,39,172,
- 2,131,1,60,33,8,34,0,0,245,38,172,
- 2,131,1,60,33,8,34,0,8,245,37,172,
- 2,131,1,60,33,8,34,0,16,245,35,172,
- 8,0,224,3,33,16,0,1,128,16,4,0,
- 33,16,68,0,128,16,2,0,2,131,1,60,
- 33,8,34,0,8,0,224,3,8,245,32,172,
- 64,133,130,143,192,255,189,39,40,0,180,175,
- 33,160,0,0,56,0,191,175,52,0,183,175,
- 48,0,182,175,44,0,181,175,36,0,179,175,
- 32,0,178,175,28,0,177,175,48,0,64,24,
- 24,0,176,175,1,0,23,36,2,0,22,36,
- 2,131,16,60,12,245,16,38,4,0,19,38,
- 244,255,17,38,252,255,18,38,33,168,0,0,
- 0,0,67,142,0,0,0,0,7,0,119,16,
- 2,0,98,40,25,0,64,20,0,0,0,0,
- 9,0,118,16,0,0,0,0,236,11,192,8,
- 20,0,16,38,0,0,34,142,0,0,0,0,
- 17,0,64,28,0,0,0,0,230,11,192,8,
- 0,0,64,174,0,0,34,142,0,0,0,0,
- 11,0,64,28,0,0,0,0,2,131,2,60,
- 33,16,85,0,4,245,66,140,0,0,0,0,
- 0,0,34,174,0,0,100,142,0,0,2,142,
- 0,0,0,0,9,248,64,0,0,0,0,0,
- 20,0,16,38,20,0,115,38,20,0,49,38,
- 20,0,82,38,64,133,130,143,1,0,148,38,
- 42,16,130,2,218,255,64,20,20,0,181,38,
- 56,0,191,143,52,0,183,143,48,0,182,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,64,0,189,39,0,0,0,0,
- 2,131,3,60,192,246,99,36,0,2,2,36,
- 0,163,1,60,200,5,35,172,0,163,1,60,
- 208,5,34,172,0,163,2,60,124,1,66,140,
- 216,255,189,39,16,0,176,175,33,128,0,0,
- 28,0,179,175,255,255,19,36,24,0,178,175,
- 21,0,114,36,20,0,177,175,32,0,191,175,
- 1,0,66,44,80,133,130,175,139,14,192,12,
- 20,0,113,36,184,24,192,12,0,0,0,0,
- 27,67,192,12,33,32,0,2,6,0,83,20,
- 1,0,16,38,2,131,4,60,15,63,192,12,
- 112,128,132,36,126,12,192,8,1,0,2,36,
- 0,0,34,162,3,18,2,0,0,0,66,162,
- 2,0,82,38,3,0,2,42,241,255,64,20,
- 2,0,49,38,2,131,17,60,212,246,49,38,
- 33,32,32,2,33,40,0,0,255,127,6,60,
- 247,24,192,12,255,255,198,52,255,31,3,60,
- 255,255,99,52,236,255,48,38,36,0,34,38,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 0,32,3,36,236,255,32,174,2,131,1,60,
- 220,246,32,172,2,131,1,60,204,246,32,172,
- 2,131,1,60,236,246,34,172,0,0,67,164,
- 222,21,192,12,33,32,0,2,122,15,192,12,
- 33,32,0,2,242,21,192,12,33,32,0,2,
- 32,133,130,143,1,0,16,36,42,16,2,2,
- 12,0,64,16,255,31,3,60,236,1,49,38,
- 133,12,192,12,33,32,0,2,242,21,192,12,
- 33,32,32,2,32,133,130,143,1,0,16,38,
- 42,16,2,2,248,255,64,20,0,2,49,38,
- 255,31,3,60,255,255,99,52,2,131,16,60,
- 192,4,16,38,7,0,2,36,0,0,2,174,
- 56,0,2,38,36,16,67,0,0,160,3,60,
- 37,16,67,0,0,32,3,36,2,131,1,60,
- 220,4,32,172,2,131,1,60,204,4,32,172,
- 2,131,1,60,236,4,34,172,0,0,67,164,
- 2,131,2,60,212,246,66,140,2,131,3,60,
- 216,246,99,132,20,0,2,174,24,0,3,166,
- 2,131,2,60,217,4,66,144,0,0,0,0,
- 7,0,66,36,2,131,1,60,217,4,34,160,
- 112,15,192,12,33,32,0,2,33,32,0,2,
- 19,15,192,12,32,0,5,36,20,0,16,38,
- 33,32,0,2,7,0,5,36,255,127,6,60,
- 247,24,192,12,255,255,198,52,33,16,0,0,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,200,255,189,39,48,0,180,175,
- 33,160,128,0,255,31,6,60,255,255,198,52,
- 64,26,20,0,2,131,2,60,192,246,66,36,
- 40,0,178,175,33,144,98,0,255,255,132,38,
- 64,18,4,0,0,162,3,60,33,16,67,0,
- 52,0,191,175,44,0,179,175,36,0,177,175,
- 32,0,176,175,4,0,66,174,0,1,66,36,
- 8,0,66,174,0,16,2,36,4,16,130,0,
- 12,0,66,174,4,0,2,36,4,16,130,0,
- 0,160,5,60,16,0,66,174,48,0,66,38,
- 36,16,70,0,37,16,69,0,36,0,66,174,
- 64,16,4,0,33,16,68,0,128,16,2,0,
- 2,131,3,60,240,231,99,36,33,16,67,0,
- 36,16,70,0,37,16,69,0,40,0,66,174,
- 56,0,66,38,36,16,70,0,37,16,69,0,
- 0,0,84,174,44,0,66,174,32,0,64,174,
- 2,131,2,60,212,246,66,140,2,131,3,60,
- 216,246,99,132,20,0,66,174,24,0,67,166,
- 25,0,66,146,0,0,0,0,33,32,84,0,
- 2,131,2,60,0,227,66,36,36,16,70,0,
- 37,128,69,0,2,131,2,60,32,227,66,36,
- 36,16,70,0,25,0,68,162,40,133,131,143,
- 0,0,0,0,3,0,96,16,37,136,69,0,
- 255,255,130,36,25,0,66,162,12,0,68,142,
- 28,0,64,174,228,63,192,12,1,0,132,52,
- 4,0,68,142,0,0,0,0,76,67,192,12,
- 33,40,0,0,76,63,192,12,0,0,0,0,
- 76,63,192,12,0,0,0,0,255,255,2,36,
- 4,0,2,174,4,0,2,142,0,0,0,0,
- 0,0,2,174,4,0,68,142,0,0,0,0,
- 76,67,192,12,1,0,5,54,4,0,4,38,
- 33,40,0,0,255,255,6,36,211,67,192,12,
- 208,7,7,36,8,0,64,20,255,255,2,52,
- 2,131,4,60,184,128,132,36,4,0,6,142,
- 0,0,0,0,15,63,192,12,33,40,128,2,
- 255,255,2,52,48,1,34,174,4,0,68,142,
- 0,0,0,0,76,67,192,12,3,0,37,54,
- 48,1,36,38,33,40,0,0,255,255,6,52,
- 211,67,192,12,208,7,7,36,7,0,64,20,
- 0,0,0,0,2,131,4,60,8,129,132,36,
- 48,1,38,142,0,0,0,0,15,63,192,12,
- 33,40,128,2,143,63,192,12,0,0,0,0,
- 40,0,69,142,4,0,68,142,0,0,0,0,
- 76,67,192,12,2,0,165,52,44,0,81,142,
- 84,128,131,143,80,128,132,143,100,0,2,36,
- 0,0,32,166,2,0,32,166,4,0,32,174,
- 8,0,32,174,12,0,32,174,16,0,32,174,
- 24,0,32,174,20,0,32,174,28,0,32,174,
- 32,0,32,174,36,0,34,166,38,0,34,166,
- 36,0,35,166,38,0,36,166,36,0,83,142,
- 1,0,2,36,0,0,98,174,44,0,66,142,
- 0,0,0,0,4,0,98,174,40,0,67,142,
- 116,0,2,60,0,0,98,172,40,0,67,142,
- 36,0,66,142,0,0,0,0,8,0,98,172,
- 8,0,66,142,0,0,0,0,0,0,64,172,
- 0,0,98,142,0,0,0,0,10,0,64,16,
- 33,128,0,0,208,7,2,42,7,0,64,16,
- 0,0,0,0,143,63,192,12,0,0,0,0,
- 0,0,98,142,0,0,0,0,248,255,64,20,
- 1,0,16,38,0,0,98,142,0,0,0,0,
- 6,0,64,16,33,32,32,2,2,131,4,60,
- 76,129,132,36,15,63,192,12,33,40,128,2,
- 33,32,32,2,8,0,5,36,0,0,34,150,
- 8,0,6,36,0,240,66,48,0,6,66,52,
- 2,0,34,166,8,0,66,142,208,7,7,36,
- 129,67,192,12,0,0,64,172,6,0,64,20,
- 2,0,36,38,2,131,4,60,160,129,132,36,
- 15,63,192,12,33,40,128,2,2,0,36,38,
- 33,40,0,0,0,0,34,150,33,48,0,0,
- 0,240,66,48,2,0,34,166,8,0,66,142,
- 208,7,7,36,129,67,192,12,0,0,64,172,
- 4,0,64,20,0,0,0,0,2,131,4,60,
- 15,63,192,12,248,129,132,36,143,63,192,12,
- 0,0,0,0,108,0,80,142,0,128,2,52,
- 0,0,0,166,2,0,2,166,44,0,66,142,
- 0,32,5,36,4,0,80,172,44,0,67,142,
- 0,241,2,52,2,0,98,164,8,0,66,142,
- 0,32,6,36,0,0,64,172,44,0,68,142,
- 0,0,0,0,129,67,192,12,208,7,7,36,
- 12,0,64,20,0,0,0,0,44,0,66,142,
- 0,0,0,0,0,0,69,148,2,131,4,60,
- 15,63,192,12,16,130,132,36,254,255,4,36,
- 2,131,5,60,44,130,165,36,188,7,192,12,
- 1,1,6,36,108,0,80,142,2,128,2,52,
- 0,0,0,166,2,0,2,166,14,0,2,36,
- 8,0,2,162,200,0,2,36,9,0,2,162,
- 65,0,2,36,10,0,2,162,46,0,2,36,
- 11,0,2,162,87,0,2,36,12,0,0,162,
- 13,0,2,162,242,0,2,36,14,0,0,162,
- 15,0,2,162,1,0,2,36,16,0,2,162,
- 8,0,2,36,17,0,2,162,88,128,130,143,
- 0,0,0,0,6,0,64,16,64,0,2,36,
- 2,131,4,60,15,63,192,12,56,130,132,36,
- 88,128,128,175,64,0,2,36,18,0,2,162,
- 255,0,2,36,19,0,2,162,63,0,2,36,
- 20,0,0,162,21,0,2,162,44,0,66,142,
- 0,32,5,36,4,0,80,172,44,0,67,142,
- 0,33,2,36,2,0,98,164,8,0,66,142,
- 0,32,6,36,0,0,64,172,44,0,68,142,
- 0,0,0,0,129,67,192,12,208,7,7,36,
- 12,0,64,20,0,0,0,0,44,0,66,142,
- 0,0,0,0,0,0,69,148,2,131,4,60,
- 15,63,192,12,16,130,132,36,253,255,4,36,
- 2,131,5,60,44,130,165,36,188,7,192,12,
- 85,1,6,36,222,21,192,12,33,32,64,2,
- 122,15,192,12,33,32,64,2,52,0,191,143,
- 48,0,180,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 56,0,189,39,248,255,189,39,32,133,133,143,
- 0,0,0,0,50,0,160,24,33,32,0,0,
- 2,131,3,60,192,246,99,36,44,0,98,140,
- 152,0,96,172,156,0,96,172,160,0,96,172,
- 164,0,96,172,168,0,96,172,172,0,96,172,
- 176,0,96,172,180,0,96,172,184,0,96,172,
- 188,0,96,172,192,0,96,172,196,0,96,172,
- 200,0,96,172,204,0,96,172,208,0,96,172,
- 212,0,96,172,216,0,96,172,224,0,96,172,
- 232,0,96,172,236,0,96,172,240,0,96,172,
- 244,0,96,172,248,0,96,172,252,0,96,172,
- 0,1,96,172,4,1,96,172,8,1,96,172,
- 12,0,64,172,44,0,98,140,0,0,0,0,
- 16,0,64,172,44,0,98,140,0,0,0,0,
- 24,0,64,172,44,0,98,140,0,0,0,0,
- 20,0,64,172,44,0,98,140,1,0,132,36,
- 28,0,64,172,44,0,98,140,0,2,99,36,
- 32,0,64,172,42,16,133,0,210,255,64,20,
- 0,0,0,0,33,32,0,0,0,163,3,60,
- 0,1,99,52,32,0,5,36,33,16,131,0,
- 188,0,69,160,1,0,132,36,0,2,130,44,
- 251,255,64,20,0,0,0,0,8,0,224,3,
- 8,0,189,39,0,0,0,0,124,133,130,143,
- 232,255,189,39,20,0,191,175,17,0,64,20,
- 16,0,176,175,208,7,16,36,7,0,0,26,
- 0,0,0,0,143,63,192,12,255,255,16,38,
- 124,133,130,143,0,0,0,0,249,255,64,16,
- 0,0,0,0,6,0,0,22,0,0,0,0,
- 2,131,4,60,15,63,192,12,80,130,132,36,
- 45,14,192,8,33,16,0,0,220,63,192,12,
- 33,32,0,0,33,32,64,0,124,133,144,143,
- 128,133,130,143,4,0,3,142,255,255,66,36,
- 128,133,130,175,124,133,131,175,220,63,192,12,
- 0,0,0,0,33,16,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,96,133,130,143,33,40,128,0,
- 43,16,162,0,6,0,64,20,16,0,191,175,
- 100,133,130,143,0,0,0,0,43,16,162,0,
- 6,0,64,20,0,0,0,0,2,131,4,60,
- 15,63,192,12,116,130,132,36,71,14,192,8,
- 0,0,0,0,124,133,131,143,128,133,130,143,
- 124,133,133,175,1,0,66,36,4,0,163,172,
- 128,133,130,175,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,108,133,130,143,
- 232,255,189,39,20,0,191,175,17,0,64,20,
- 16,0,176,175,208,7,16,36,7,0,0,26,
- 0,0,0,0,143,63,192,12,255,255,16,38,
- 108,133,130,143,0,0,0,0,249,255,64,16,
- 0,0,0,0,6,0,0,22,0,0,0,0,
- 2,131,4,60,15,63,192,12,148,130,132,36,
- 108,14,192,8,33,16,0,0,220,63,192,12,
- 33,32,0,0,33,32,64,0,108,133,144,143,
- 120,133,130,143,0,0,3,142,255,255,66,36,
- 120,133,130,175,108,133,131,175,220,63,192,12,
- 0,0,0,0,33,16,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,104,133,130,143,33,40,128,0,
- 43,16,162,0,6,0,64,20,16,0,191,175,
- 112,133,130,143,0,0,0,0,43,16,162,0,
- 6,0,64,20,0,0,0,0,2,131,4,60,
- 15,63,192,12,184,130,132,36,135,14,192,8,
- 0,0,0,0,108,133,130,143,0,0,0,0,
- 0,0,162,172,120,133,130,143,108,133,133,175,
- 1,0,66,36,120,133,130,175,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 124,133,128,175,13,8,192,12,0,32,4,36,
- 255,31,3,60,255,255,99,52,255,1,16,36,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 96,133,130,175,0,32,66,36,100,133,130,175,
- 0,17,16,0,96,133,132,143,255,255,16,38,
- 49,14,192,12,33,32,130,0,251,255,1,6,
- 0,17,16,0,0,2,2,36,132,133,130,175,
- 108,133,128,175,13,8,192,12,18,0,4,60,
- 255,31,3,60,255,255,99,52,255,17,16,36,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 18,0,3,60,104,133,130,175,33,16,67,0,
- 112,133,130,175,0,18,16,0,104,133,132,143,
- 255,255,16,38,112,14,192,12,33,32,130,0,
- 251,255,1,6,0,18,16,0,0,18,2,36,
- 116,133,130,175,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,163,2,60,
- 168,1,66,140,216,255,189,39,28,0,177,175,
- 33,136,128,0,32,0,178,175,33,144,160,0,
- 36,0,191,175,17,0,64,16,24,0,176,175,
- 0,163,2,60,168,1,66,140,0,0,0,0,
- 42,16,82,0,12,0,64,16,128,128,18,0,
- 0,0,34,142,0,163,18,60,168,1,82,142,
- 0,0,0,0,6,0,64,20,128,128,18,0,
- 2,131,4,60,224,130,132,36,15,63,192,12,
- 33,40,64,2,128,128,18,0,33,128,18,2,
- 128,128,16,0,13,8,192,12,33,32,0,2,
- 255,31,3,60,255,255,99,52,33,32,0,0,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 112,0,34,174,112,0,35,142,33,16,80,0,
- 15,0,64,26,116,0,34,174,8,0,5,36,
- 1,0,132,36,20,0,98,36,4,0,98,172,
- 2,0,101,164,0,0,96,164,8,0,96,172,
- 14,0,96,164,12,0,96,164,33,24,64,0,
- 42,16,146,0,246,255,64,20,1,0,132,36,
- 255,255,132,36,116,0,35,142,112,0,34,142,
- 0,0,0,0,240,255,98,172,116,0,35,142,
- 0,0,0,0,218,255,98,148,0,0,0,0,
- 0,128,66,52,218,255,98,164,116,0,35,142,
- 0,0,0,0,238,255,98,148,0,0,0,0,
- 0,128,66,52,238,255,98,164,116,0,34,142,
- 112,0,35,142,216,255,66,36,120,0,35,174,
- 124,0,34,174,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,200,255,189,39,32,0,178,175,
- 33,144,128,0,0,1,2,36,48,0,191,175,
- 44,0,181,175,40,0,180,175,36,0,179,175,
- 28,0,177,175,24,0,176,175,144,0,66,174,
- 0,163,2,60,172,1,66,140,0,0,0,0,
- 17,0,64,16,33,160,160,0,0,163,2,60,
- 172,1,66,140,0,0,0,0,42,16,84,0,
- 12,0,64,16,128,128,20,0,0,0,66,142,
- 0,163,20,60,172,1,148,142,0,0,0,0,
- 6,0,64,20,128,128,20,0,2,131,4,60,
- 236,130,132,36,15,63,192,12,33,40,128,2,
- 128,128,20,0,33,128,20,2,128,128,16,0,
- 33,32,0,2,13,8,192,12,148,0,84,174,
- 255,31,3,60,255,255,99,52,33,152,0,0,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 128,0,66,174,128,0,81,142,33,16,80,0,
- 15,0,128,26,132,0,66,174,0,1,21,36,
- 20,0,48,38,4,0,48,174,75,14,192,12,
- 0,0,32,174,8,0,34,174,12,0,53,174,
- 0,0,66,142,1,0,115,38,16,0,34,162,
- 17,0,32,162,42,16,116,2,244,255,64,20,
- 33,136,0,2,132,0,67,142,128,0,66,142,
- 0,0,0,0,240,255,98,172,132,0,67,142,
- 0,0,0,0,228,255,98,140,0,0,0,0,
- 0,128,66,52,228,255,98,172,132,0,67,142,
- 0,0,0,0,248,255,98,140,0,0,0,0,
- 0,128,66,52,248,255,98,172,132,0,66,142,
- 128,0,67,142,216,255,66,36,136,0,67,174,
- 140,0,66,174,48,0,191,143,44,0,181,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 56,0,189,39,152,0,128,172,156,0,128,172,
- 160,0,128,172,164,0,128,172,168,0,128,172,
- 252,0,128,172,0,1,128,172,152,0,128,172,
- 8,0,224,3,216,0,128,172,232,255,189,39,
- 16,0,176,175,20,0,191,175,112,15,192,12,
- 33,128,128,0,33,32,0,2,192,14,192,12,
- 0,4,5,36,33,32,0,2,19,15,192,12,
- 128,2,5,36,120,0,3,142,136,0,2,142,
- 0,0,0,0,8,0,98,172,44,0,3,142,
- 120,0,2,142,0,0,0,0,8,0,98,172,
- 0,0,2,142,0,0,0,0,255,255,66,36,
- 6,0,66,44,7,0,64,16,16,0,3,36,
- 44,0,2,142,0,0,0,0,2,0,67,164,
- 8,0,2,142,0,0,0,0,0,0,64,172,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,184,255,189,39,0,32,6,36,
- 68,0,191,175,64,0,190,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,0,163,1,60,252,5,38,172,
- 13,8,192,12,0,32,4,36,255,31,4,60,
- 255,255,132,52,33,168,0,0,255,31,6,60,
- 255,255,198,52,2,131,3,60,212,247,99,36,
- 16,0,101,36,8,0,126,36,248,255,119,36,
- 33,176,96,0,36,16,68,0,0,160,3,60,
- 37,16,67,0,16,0,166,175,0,163,1,60,
- 248,5,34,172,0,163,1,60,0,6,32,172,
- 33,160,0,0,33,128,224,2,33,152,160,0,
- 33,144,192,3,33,136,192,2,32,133,130,143,
- 0,0,32,174,0,0,0,174,0,0,64,174,
- 42,16,162,2,10,0,64,16,0,0,96,174,
- 0,32,4,36,13,8,192,12,24,0,165,175,
- 16,0,166,143,0,128,3,60,36,16,70,0,
- 37,16,67,0,0,0,2,174,24,0,165,143,
- 4,0,16,38,4,0,115,38,4,0,82,38,
- 1,0,148,38,2,0,130,42,234,255,64,20,
- 4,0,49,38,0,2,165,36,0,2,222,39,
- 0,2,247,38,1,0,181,38,7,0,162,42,
- 222,255,64,20,0,2,214,38,68,0,191,143,
- 64,0,190,143,60,0,183,143,56,0,182,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,72,0,189,39,0,163,4,60,
- 0,6,132,140,0,163,3,60,8,6,99,140,
- 32,133,130,143,224,255,189,39,16,0,176,175,
- 0,163,16,60,12,6,16,142,20,0,177,175,
- 0,163,17,60,4,6,49,142,43,16,98,0,
- 42,0,64,16,24,0,191,175,2,0,2,46,
- 40,0,64,16,255,255,2,36,0,163,2,60,
- 252,5,66,140,0,0,0,0,43,16,81,0,
- 34,0,64,20,255,255,2,36,64,18,3,0,
- 2,131,3,60,192,246,99,36,33,24,67,0,
- 1,0,2,36,5,0,130,16,2,0,2,36,
- 18,0,130,16,128,16,16,0,36,16,192,8,
- 0,0,0,0,128,128,16,0,33,128,3,2,
- 12,1,4,142,0,163,5,60,248,5,165,140,
- 33,48,32,2,80,68,192,12,36,1,17,174,
- 12,1,4,142,12,1,2,142,33,40,32,2,
- 114,68,192,12,20,1,2,174,36,16,192,8,
- 0,0,0,0,33,16,67,0,20,1,64,172,
- 36,1,64,172,0,163,1,60,42,16,192,8,
- 0,6,32,172,255,255,2,36,0,163,1,60,
- 0,6,34,172,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 176,133,136,143,188,133,137,143,232,255,189,39,
- 3,0,0,21,16,0,191,175,124,0,32,17,
- 0,0,0,0,12,0,194,148,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,56,98,0,
- 255,255,227,48,221,5,98,44,36,0,64,20,
- 170,170,2,52,0,8,2,36,23,0,98,20,
- 6,8,2,36,21,0,0,17,0,0,0,0,
- 32,0,194,148,30,0,195,148,0,20,2,0,
- 37,56,67,0,36,0,195,148,0,161,2,52,
- 5,0,98,16,8,0,2,36,34,0,195,148,
- 0,0,0,0,98,0,98,20,0,0,0,0,
- 3,0,232,16,255,255,2,36,94,0,226,20,
- 0,0,0,0,226,46,192,12,14,0,6,36,
- 177,16,192,8,0,0,0,0,7,0,98,20,
- 255,255,227,48,71,0,0,17,55,129,2,52,
- 108,43,192,12,14,0,6,36,177,16,192,8,
- 0,0,0,0,162,16,192,8,55,129,2,52,
- 14,0,195,148,0,0,0,0,61,0,98,20,
- 255,255,2,52,16,0,195,144,3,0,2,36,
- 55,0,98,20,255,255,2,52,20,0,194,148,
- 0,0,0,0,0,26,2,0,2,18,2,0,
- 37,56,98,0,255,255,227,48,0,8,2,36,
- 23,0,98,20,6,8,2,36,21,0,0,17,
- 0,0,0,0,40,0,194,148,38,0,195,148,
- 0,20,2,0,37,56,67,0,44,0,195,148,
- 0,161,2,52,5,0,98,16,8,0,2,36,
- 42,0,195,148,0,0,0,0,49,0,98,20,
- 0,0,0,0,3,0,232,16,255,255,2,36,
- 45,0,226,20,0,0,0,0,226,46,192,12,
- 22,0,6,36,177,16,192,8,0,0,0,0,
- 7,0,98,20,255,255,227,48,6,0,0,17,
- 55,129,2,52,108,43,192,12,22,0,6,36,
- 177,16,192,8,0,0,0,0,55,129,2,52,
- 30,0,98,20,0,0,0,0,28,0,32,17,
- 144,15,3,36,38,0,194,148,28,0,198,140,
- 24,0,67,20,0,0,0,0,3,0,201,16,
- 0,0,0,0,20,0,192,20,0,0,0,0,
- 175,16,192,8,22,0,6,36,14,0,195,148,
- 0,0,0,0,14,0,98,20,0,0,0,0,
- 12,0,32,17,144,15,3,36,30,0,194,148,
- 20,0,198,140,8,0,67,20,0,0,0,0,
- 3,0,201,16,0,0,0,0,4,0,192,20,
- 0,0,0,0,14,0,6,36,126,49,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,128,255,189,39,
- 116,0,183,175,33,184,128,0,3,0,3,36,
- 124,0,191,175,120,0,190,175,112,0,182,175,
- 108,0,181,175,104,0,180,175,100,0,179,175,
- 96,0,178,175,92,0,177,175,88,0,176,175,
- 0,0,245,142,8,0,178,140,192,17,21,0,
- 3,131,4,60,33,32,130,0,20,13,132,140,
- 8,0,84,142,0,0,0,0,59,0,131,16,
- 5,0,130,44,57,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,104,131,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 44,133,130,143,0,0,0,0,48,0,64,16,
- 6,0,132,38,4,0,131,150,2,131,2,60,
- 68,207,66,148,0,0,0,0,6,0,98,20,
- 33,32,0,0,0,0,130,142,48,129,131,143,
- 0,0,0,0,38,16,67,0,1,0,68,44,
- 72,1,128,16,33,32,160,2,114,42,192,12,
- 33,40,128,2,45,18,192,8,33,32,64,2,
- 44,133,130,143,0,0,0,0,27,0,64,16,
- 6,0,132,38,4,0,131,150,2,131,2,60,
- 68,207,66,148,0,0,0,0,6,0,98,20,
- 33,32,0,0,0,0,130,142,48,129,131,143,
- 0,0,0,0,38,16,67,0,1,0,68,44,
- 5,0,128,16,33,32,160,2,114,42,192,12,
- 33,40,128,2,45,18,192,8,33,32,64,2,
- 6,0,132,38,0,163,6,60,140,1,198,140,
- 0,0,0,0,247,24,192,12,33,40,160,2,
- 45,18,192,8,33,32,64,2,6,0,132,38,
- 0,163,6,60,140,1,198,140,0,0,0,0,
- 247,24,192,12,33,40,160,2,203,24,192,12,
- 33,32,128,2,20,1,227,142,0,0,0,0,
- 14,0,96,16,33,240,64,0,33,32,128,2,
- 16,0,166,39,18,0,69,150,0,0,0,0,
- 9,248,96,0,33,56,192,3,6,0,64,16,
- 33,32,64,2,28,1,226,142,0,0,0,0,
- 1,0,66,36,45,18,192,8,28,1,226,174,
- 132,0,193,7,7,0,2,36,4,0,131,150,
- 2,131,2,60,68,207,66,148,0,0,0,0,
- 6,0,98,20,33,32,0,0,0,0,130,142,
- 48,129,131,143,0,0,0,0,38,16,67,0,
- 1,0,68,44,9,0,128,16,255,255,2,36,
- 44,133,130,143,0,0,0,0,251,0,64,16,
- 33,32,160,2,114,42,192,12,33,40,128,2,
- 45,18,192,8,33,32,64,2,10,0,194,23,
- 0,0,0,0,8,0,160,18,0,0,0,0,
- 36,133,130,143,0,0,0,0,8,0,64,16,
- 1,0,19,36,80,133,147,143,69,17,192,8,
- 0,0,0,0,0,1,226,142,80,133,147,143,
- 1,0,66,36,0,1,226,174,84,133,130,143,
- 0,0,0,0,35,16,83,0,255,255,66,36,
- 17,0,66,162,84,133,130,143,33,128,96,2,
- 42,16,2,2,15,0,64,16,64,18,16,0,
- 2,131,3,60,192,246,99,36,33,136,67,0,
- 5,0,21,18,0,0,0,0,247,22,192,12,
- 33,32,32,2,217,0,64,16,33,16,0,0,
- 84,133,130,143,1,0,16,38,42,16,2,2,
- 246,255,64,20,0,2,49,38,84,133,130,143,
- 33,128,96,2,42,16,2,2,55,0,64,16,
- 64,18,16,0,2,131,3,60,192,246,99,36,
- 33,152,67,0,33,136,64,0,192,177,16,0,
- 41,0,21,18,0,0,0,0,2,131,2,60,
- 33,16,81,0,216,247,66,140,0,0,0,0,
- 15,0,64,16,33,32,128,2,16,0,166,39,
- 18,0,69,150,0,0,0,0,9,248,64,0,
- 33,56,160,2,8,0,64,16,0,0,0,0,
- 2,131,2,60,33,16,81,0,224,247,66,140,
- 0,0,0,0,1,0,66,36,140,17,192,8,
- 32,1,98,174,44,133,130,143,0,0,0,0,
- 7,0,64,16,3,0,8,36,3,131,2,60,
- 33,16,86,0,20,13,66,140,0,0,0,0,
- 6,0,72,20,0,0,0,0,33,32,96,2,
- 6,23,192,12,33,40,64,2,146,17,192,8,
- 0,2,115,38,17,0,66,146,0,0,0,0,
- 255,255,66,36,17,0,66,162,17,0,66,146,
- 0,2,115,38,0,2,49,38,84,133,130,143,
- 1,0,16,38,42,16,2,2,208,255,64,20,
- 128,0,214,38,254,255,2,36,4,0,194,23,
- 33,32,224,2,33,40,64,2,47,16,192,12,
- 33,48,128,2,17,0,66,146,0,0,0,0,
- 140,0,64,16,33,32,64,2,36,18,192,8,
- 0,0,0,0,26,0,194,23,0,0,0,0,
- 36,133,130,143,0,0,0,0,11,0,64,16,
- 33,32,224,2,9,0,160,18,1,0,2,36,
- 17,0,66,162,2,131,4,60,192,246,132,36,
- 6,23,192,12,33,40,64,2,126,0,64,16,
- 33,16,0,0,33,32,224,2,33,40,64,2,
- 47,16,192,12,33,48,128,2,36,133,130,143,
- 0,0,0,0,115,0,64,16,33,32,64,2,
- 116,0,160,22,1,0,2,36,45,18,192,8,
- 0,0,0,0,87,0,213,19,64,130,30,0,
- 2,131,2,60,33,16,80,0,216,247,66,140,
- 0,0,0,0,18,0,64,16,33,32,128,2,
- 16,0,166,39,18,0,69,150,0,0,0,0,
- 9,248,64,0,33,56,160,2,11,0,64,16,
- 33,32,64,2,2,131,2,60,33,16,80,0,
- 224,247,66,140,0,0,0,0,1,0,66,36,
- 2,131,1,60,33,8,48,0,224,247,34,172,
- 45,18,192,8,17,0,128,160,36,133,130,143,
- 0,0,0,0,43,0,64,16,0,0,0,0,
- 41,0,192,19,0,0,0,0,39,0,160,18,
- 64,18,30,0,2,131,16,60,192,246,16,38,
- 33,136,80,0,247,22,192,12,33,32,32,2,
- 74,0,64,16,33,16,0,0,247,22,192,12,
- 33,32,0,2,63,0,64,16,2,0,2,36,
- 17,0,66,162,44,133,130,143,0,0,0,0,
- 7,0,64,16,192,17,30,0,3,131,3,60,
- 33,24,98,0,20,13,99,140,3,0,2,36,
- 6,0,98,20,0,0,0,0,33,32,32,2,
- 6,23,192,12,33,40,64,2,0,18,192,8,
- 0,0,0,0,17,0,66,146,0,0,0,0,
- 255,255,66,36,17,0,66,162,17,0,66,146,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,36,18,192,8,0,0,0,0,
- 44,133,130,143,0,0,0,0,7,0,64,16,
- 192,17,30,0,3,131,3,60,33,24,98,0,
- 20,13,99,140,3,0,2,36,28,0,98,20,
- 0,0,0,0,1,0,2,36,17,0,66,162,
- 64,18,30,0,2,131,4,60,192,246,132,36,
- 32,18,192,8,33,32,68,0,36,133,130,143,
- 0,0,0,0,17,0,64,16,0,0,0,0,
- 15,0,192,19,1,0,2,36,17,0,66,162,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,13,0,64,16,33,16,0,0,
- 252,0,226,142,0,0,0,0,1,0,66,36,
- 47,18,192,8,252,0,226,174,48,18,192,8,
- 33,16,0,0,17,0,64,162,33,32,64,2,
- 152,21,192,12,0,0,0,0,1,0,2,36,
- 124,0,191,143,120,0,190,143,116,0,183,143,
- 112,0,182,143,108,0,181,143,104,0,180,143,
- 100,0,179,143,96,0,178,143,92,0,177,143,
- 88,0,176,143,8,0,224,3,128,0,189,39,
- 216,255,189,39,24,0,178,175,33,144,128,0,
- 32,0,191,175,28,0,179,175,20,0,177,175,
- 16,0,176,175,8,0,177,140,0,0,66,142,
- 8,0,38,142,36,0,64,16,0,0,0,0,
- 28,0,66,142,0,0,0,0,18,0,64,20,
- 1,0,2,36,0,0,194,144,0,0,0,0,
- 1,0,66,48,13,0,64,20,1,0,2,36,
- 4,0,195,148,24,0,66,150,0,0,0,0,
- 6,0,98,20,33,32,0,0,0,0,194,140,
- 20,0,67,142,0,0,0,0,38,16,67,0,
- 1,0,68,44,10,0,128,16,1,0,2,36,
- 17,0,34,162,2,131,4,60,192,246,132,36,
- 6,23,192,12,33,40,32,2,45,0,64,16,
- 33,16,0,0,139,18,192,8,0,0,0,0,
- 17,0,32,162,152,21,192,12,33,32,32,2,
- 144,18,192,8,1,0,2,36,16,0,179,140,
- 0,0,0,0,6,0,96,26,0,0,0,0,
- 32,133,130,143,0,0,0,0,42,16,98,2,
- 15,0,64,20,1,0,2,36,2,131,4,60,
- 248,130,132,36,2,131,16,60,24,131,16,38,
- 33,40,0,2,2,131,7,60,36,131,231,36,
- 15,63,192,12,188,2,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,188,2,6,36,
- 1,0,2,36,17,0,34,162,64,18,19,0,
- 2,131,4,60,192,246,132,36,33,32,68,0,
- 6,23,192,12,33,40,32,2,6,0,64,16,
- 33,16,0,0,252,0,66,142,0,0,0,0,
- 1,0,66,36,252,0,66,174,1,0,2,36,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,72,255,189,39,164,0,181,175,
- 33,168,128,0,180,0,191,175,176,0,190,175,
- 172,0,183,175,168,0,182,175,160,0,180,175,
- 156,0,179,175,152,0,178,175,148,0,177,175,
- 144,0,176,175,88,0,165,175,120,0,160,175,
- 120,0,168,142,0,0,0,0,96,0,168,175,
- 124,0,169,142,0,0,0,0,15,2,160,24,
- 104,0,169,175,96,0,168,143,0,0,0,0,
- 0,0,4,149,0,0,0,0,0,128,130,48,
- 9,2,64,16,0,0,0,0,128,0,160,175,
- 8,0,2,141,136,0,169,142,255,255,8,36,
- 18,0,72,16,112,0,169,175,112,0,169,143,
- 0,0,0,0,0,0,35,141,4,0,40,141,
- 128,0,169,143,255,63,98,48,33,72,34,1,
- 0,128,99,48,112,0,168,175,246,255,96,16,
- 128,0,169,175,96,0,168,143,0,0,0,0,
- 8,0,2,141,128,0,169,151,0,0,0,0,
- 18,0,73,164,0,32,130,48,200,1,64,16,
- 0,0,0,0,40,133,130,143,0,0,0,0,
- 75,0,64,16,3,0,8,36,96,0,168,143,
- 0,0,0,0,8,0,16,141,0,0,162,142,
- 8,0,5,142,30,0,64,16,0,0,0,0,
- 28,0,162,142,0,0,0,0,18,0,64,20,
- 1,0,9,36,0,0,162,144,0,0,0,0,
- 1,0,66,48,13,0,64,20,0,0,0,0,
- 4,0,163,148,24,0,162,150,0,0,0,0,
- 6,0,98,20,33,32,0,0,0,0,162,140,
- 20,0,163,142,0,0,0,0,38,16,67,0,
- 1,0,68,44,6,0,128,16,1,0,9,36,
- 17,0,9,162,2,131,4,60,192,246,132,36,
- 18,19,192,8,33,40,0,2,17,0,0,162,
- 130,20,192,8,33,32,0,2,16,0,17,141,
- 0,0,0,0,6,0,32,26,0,0,0,0,
- 32,133,130,143,0,0,0,0,42,16,34,2,
- 15,0,64,20,1,0,9,36,2,131,4,60,
- 248,130,132,36,2,131,5,60,24,131,165,36,
- 2,131,7,60,36,131,231,36,15,63,192,12,
- 188,2,6,36,1,0,4,36,2,131,5,60,
- 24,131,165,36,188,7,192,12,188,2,6,36,
- 1,0,9,36,17,0,9,162,64,34,17,0,
- 2,131,8,60,192,246,8,37,33,32,136,0,
- 33,40,0,2,6,23,192,12,0,0,0,0,
- 112,1,64,16,33,16,0,0,252,0,162,142,
- 0,0,0,0,1,0,66,36,132,20,192,8,
- 252,0,162,174,0,0,182,142,96,0,169,143,
- 192,17,22,0,8,0,50,141,3,131,3,60,
- 33,24,98,0,20,13,99,140,8,0,84,142,
- 0,0,0,0,59,0,104,16,5,0,98,44,
- 57,0,64,16,128,16,3,0,2,131,1,60,
- 33,8,34,0,128,131,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,44,133,130,143,
- 0,0,0,0,48,0,64,16,6,0,132,38,
- 4,0,131,150,2,131,2,60,68,207,66,148,
- 0,0,0,0,6,0,98,20,33,32,0,0,
- 0,0,130,142,48,129,131,143,0,0,0,0,
- 38,16,67,0,1,0,68,44,67,1,128,16,
- 33,32,192,2,114,42,192,12,33,40,128,2,
- 130,20,192,8,33,32,64,2,44,133,130,143,
- 0,0,0,0,27,0,64,16,6,0,132,38,
- 4,0,131,150,2,131,2,60,68,207,66,148,
- 0,0,0,0,6,0,98,20,33,32,0,0,
- 0,0,130,142,48,129,131,143,0,0,0,0,
- 38,16,67,0,1,0,68,44,5,0,128,16,
- 33,32,192,2,114,42,192,12,33,40,128,2,
- 130,20,192,8,33,32,64,2,6,0,132,38,
- 0,163,6,60,140,1,198,140,0,0,0,0,
- 247,24,192,12,33,40,192,2,130,20,192,8,
- 33,32,64,2,6,0,132,38,0,163,6,60,
- 140,1,198,140,0,0,0,0,247,24,192,12,
- 33,40,192,2,203,24,192,12,33,32,128,2,
- 20,1,163,142,0,0,0,0,14,0,96,16,
- 33,240,64,0,33,32,128,2,16,0,166,39,
- 18,0,69,150,0,0,0,0,9,248,96,0,
- 33,56,192,3,6,0,64,16,33,32,64,2,
- 28,1,162,142,0,0,0,0,1,0,66,36,
- 130,20,192,8,28,1,162,174,132,0,193,7,
- 7,0,2,36,4,0,131,150,2,131,2,60,
- 68,207,66,148,0,0,0,0,6,0,98,20,
- 33,32,0,0,0,0,130,142,48,129,131,143,
- 0,0,0,0,38,16,67,0,1,0,68,44,
- 9,0,128,16,255,255,9,36,44,133,130,143,
- 0,0,0,0,246,0,64,16,33,32,192,2,
- 114,42,192,12,33,40,128,2,130,20,192,8,
- 33,32,64,2,10,0,201,23,0,0,0,0,
- 8,0,192,18,0,0,0,0,36,133,130,143,
- 0,0,0,0,8,0,64,16,1,0,19,36,
- 80,133,147,143,159,19,192,8,0,0,0,0,
- 0,1,162,142,80,133,147,143,1,0,66,36,
- 0,1,162,174,84,133,130,143,0,0,0,0,
- 35,16,83,0,255,255,66,36,17,0,66,162,
- 84,133,130,143,33,136,96,2,42,16,34,2,
- 15,0,64,16,64,18,17,0,2,131,8,60,
- 192,246,8,37,33,128,72,0,5,0,54,18,
- 0,0,0,0,247,22,192,12,33,32,0,2,
- 212,0,64,16,33,16,0,0,84,133,130,143,
- 1,0,49,38,42,16,34,2,246,255,64,20,
- 0,2,16,38,84,133,130,143,33,136,96,2,
- 42,16,34,2,55,0,64,16,64,18,17,0,
- 2,131,9,60,192,246,41,37,33,152,73,0,
- 33,128,64,0,192,185,17,0,41,0,54,18,
- 0,0,0,0,2,131,2,60,33,16,80,0,
- 216,247,66,140,0,0,0,0,15,0,64,16,
- 33,32,128,2,16,0,166,39,18,0,69,150,
- 0,0,0,0,9,248,64,0,33,56,192,2,
- 8,0,64,16,0,0,0,0,2,131,2,60,
- 33,16,80,0,224,247,66,140,0,0,0,0,
- 1,0,66,36,230,19,192,8,32,1,98,174,
- 44,133,130,143,0,0,0,0,7,0,64,16,
- 3,0,8,36,3,131,2,60,33,16,87,0,
- 20,13,66,140,0,0,0,0,6,0,72,20,
- 0,0,0,0,33,32,96,2,6,23,192,12,
- 33,40,64,2,236,19,192,8,0,2,115,38,
- 17,0,66,146,0,0,0,0,255,255,66,36,
- 17,0,66,162,17,0,66,146,0,2,115,38,
- 0,2,16,38,84,133,130,143,1,0,49,38,
- 42,16,34,2,208,255,64,20,128,0,247,38,
- 254,255,2,36,4,0,194,23,33,32,160,2,
- 33,40,64,2,47,16,192,12,33,48,128,2,
- 17,0,66,146,0,0,0,0,135,0,64,16,
- 33,32,64,2,22,19,192,8,0,0,0,0,
- 26,0,194,23,0,0,0,0,36,133,130,143,
- 0,0,0,0,11,0,64,16,33,32,160,2,
- 9,0,192,18,1,0,9,36,17,0,73,162,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,121,0,64,16,33,16,0,0,
- 33,32,160,2,33,40,64,2,47,16,192,12,
- 33,48,128,2,36,133,130,143,0,0,0,0,
- 110,0,64,16,33,32,64,2,111,0,192,22,
- 1,0,2,36,130,20,192,8,0,0,0,0,
- 89,0,214,19,64,130,30,0,2,131,2,60,
- 33,16,80,0,216,247,66,140,0,0,0,0,
- 18,0,64,16,33,32,128,2,16,0,166,39,
- 18,0,69,150,0,0,0,0,9,248,64,0,
- 33,56,192,2,11,0,64,16,33,32,64,2,
- 2,131,8,60,192,246,8,37,2,131,2,60,
- 33,16,80,0,224,247,66,140,33,24,8,2,
- 1,0,66,36,32,1,98,172,130,20,192,8,
- 17,0,128,160,36,133,130,143,0,0,0,0,
- 44,0,64,16,0,0,0,0,42,0,192,19,
- 0,0,0,0,40,0,192,18,64,18,30,0,
- 2,131,9,60,192,246,41,37,33,128,73,0,
- 247,22,192,12,33,32,0,2,69,0,64,16,
- 33,16,0,0,2,131,4,60,247,22,192,12,
- 192,246,132,36,57,0,64,16,2,0,2,36,
- 17,0,66,162,44,133,130,143,0,0,0,0,
- 7,0,64,16,192,17,30,0,3,131,1,60,
- 33,8,34,0,20,13,34,140,3,0,8,36,
- 6,0,72,20,0,0,0,0,33,32,0,2,
- 6,23,192,12,33,40,64,2,91,20,192,8,
- 0,0,0,0,17,0,66,146,0,0,0,0,
- 255,255,66,36,17,0,66,162,17,0,66,146,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,22,19,192,8,0,0,0,0,
- 44,133,130,143,0,0,0,0,7,0,64,16,
- 192,17,30,0,3,131,1,60,33,8,34,0,
- 20,13,34,140,3,0,9,36,22,0,73,20,
- 0,0,0,0,1,0,8,36,17,0,72,162,
- 64,34,30,0,2,131,9,60,192,246,41,37,
- 33,32,137,0,18,19,192,8,33,40,64,2,
- 36,133,130,143,0,0,0,0,10,0,64,16,
- 0,0,0,0,8,0,192,19,1,0,8,36,
- 17,0,72,162,2,131,4,60,192,246,132,36,
- 18,19,192,8,33,40,64,2,133,20,192,8,
- 33,16,0,0,17,0,64,162,33,32,64,2,
- 152,21,192,12,0,0,0,0,1,0,2,36,
- 52,0,64,16,0,0,0,0,152,0,162,142,
- 0,0,0,0,1,0,66,36,152,0,162,174,
- 156,0,162,142,168,0,163,142,1,0,66,36,
- 156,0,162,174,128,0,169,143,0,0,0,0,
- 33,24,105,0,163,20,192,8,168,0,163,174,
- 152,0,162,142,160,0,163,142,1,0,66,36,
- 1,0,99,36,152,0,162,174,160,0,163,174,
- 96,0,168,143,0,0,0,0,8,0,2,141,
- 255,255,9,36,4,0,73,16,0,0,0,0,
- 8,0,4,141,152,21,192,12,0,0,0,0,
- 120,0,168,143,112,0,169,143,1,0,8,37,
- 120,0,168,175,136,0,169,174,96,0,168,143,
- 8,128,2,52,0,0,0,165,2,0,2,165,
- 104,0,169,143,8,0,2,36,2,0,34,165,
- 4,0,40,141,96,0,169,143,104,0,168,175,
- 4,0,41,141,120,0,168,143,96,0,169,175,
- 88,0,169,143,0,0,0,0,42,16,9,1,
- 243,253,64,20,0,0,0,0,96,0,168,143,
- 44,0,163,142,120,0,168,174,104,0,169,143,
- 0,0,0,0,124,0,169,174,0,0,98,148,
- 0,0,0,0,0,16,66,48,43,0,64,16,
- 0,0,0,0,2,0,98,148,0,0,0,0,
- 39,0,64,20,0,0,0,0,0,0,2,149,
- 0,0,0,0,35,0,64,20,0,0,0,0,
- 2,0,2,149,8,0,3,36,255,255,66,48,
- 30,0,67,20,0,0,0,0,136,0,162,142,
- 0,0,0,0,12,0,66,140,0,0,0,0,
- 0,128,66,48,23,0,64,20,0,0,0,0,
- 164,0,162,142,44,0,163,142,1,0,66,36,
- 164,0,162,174,8,0,104,172,136,0,162,142,
- 0,0,0,0,8,0,2,173,44,0,163,142,
- 16,16,2,36,2,0,98,164,0,0,162,142,
- 0,0,0,0,5,0,64,20,0,0,0,0,
- 164,7,192,12,0,0,0,0,239,20,192,8,
- 0,0,0,0,8,0,162,142,0,0,0,0,
- 0,0,64,172,180,0,191,143,176,0,190,143,
- 172,0,183,143,168,0,182,143,164,0,181,143,
- 160,0,180,143,156,0,179,143,152,0,178,143,
- 148,0,177,143,144,0,176,143,8,0,224,3,
- 184,0,189,39,216,255,189,39,28,0,177,175,
- 33,136,128,0,32,0,178,175,33,144,160,0,
- 96,128,132,39,6,0,37,38,24,0,176,175,
- 104,128,144,39,36,0,191,175,31,21,192,12,
- 33,48,0,2,108,128,132,39,33,40,32,2,
- 31,21,192,12,33,48,0,2,10,0,64,26,
- 33,128,0,0,116,128,132,39,33,16,17,2,
- 12,0,69,144,0,0,0,0,15,63,192,12,
- 1,0,16,38,42,16,18,2,248,255,64,20,
- 0,0,0,0,124,128,132,39,15,63,192,12,
- 0,0,0,0,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,208,255,189,39,40,0,191,175,
- 2,0,162,144,0,0,163,144,1,0,167,144,
- 16,0,162,175,3,0,162,144,33,64,128,0,
- 20,0,162,175,4,0,162,144,2,131,4,60,
- 68,131,132,36,24,0,162,175,5,0,162,144,
- 33,40,0,1,32,0,166,175,33,48,96,0,
- 15,63,192,12,28,0,162,175,40,0,191,143,
- 48,0,189,39,8,0,224,3,0,0,0,0,
- 248,255,189,39,136,0,135,140,255,255,163,36,
- 12,0,160,16,33,48,224,0,255,255,5,36,
- 12,0,194,140,0,0,0,0,0,128,66,48,
- 8,0,64,20,33,16,0,0,255,255,99,36,
- 0,0,192,172,4,0,198,140,247,255,101,20,
- 0,0,0,0,136,0,134,172,33,16,224,0,
- 8,0,224,3,8,0,189,39,224,255,189,39,
- 16,0,176,175,33,128,160,0,28,0,191,175,
- 24,0,178,175,33,0,128,20,20,0,177,175,
- 84,133,130,143,80,133,131,143,0,0,0,0,
- 35,16,67,0,17,0,2,162,80,133,145,143,
- 84,133,130,143,0,0,0,0,42,16,34,2,
- 19,0,64,16,64,18,17,0,2,131,3,60,
- 192,246,99,36,33,144,67,0,33,32,64,2,
- 6,23,192,12,33,40,0,2,6,0,64,20,
- 0,0,0,0,17,0,2,146,0,0,0,0,
- 255,255,66,36,17,0,2,162,17,0,2,146,
- 84,133,130,143,1,0,49,38,42,16,34,2,
- 242,255,64,20,0,2,82,38,17,0,2,146,
- 144,21,192,8,0,0,0,0,36,133,130,143,
- 0,0,0,0,25,0,64,16,1,0,2,36,
- 0,0,130,140,0,0,0,0,20,0,64,16,
- 2,0,2,36,17,0,2,162,6,23,192,12,
- 33,40,0,2,19,0,64,16,33,16,0,0,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,0,2,7,0,64,20,0,0,0,0,
- 17,0,2,146,0,0,0,0,255,255,66,36,
- 17,0,2,162,17,0,2,146,0,0,0,0,
- 144,21,192,8,1,0,2,36,1,0,2,36,
- 17,0,2,162,6,23,192,12,33,40,0,2,
- 28,0,191,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 0,0,0,0,0,0,0,0,0,129,9,52,
- 16,0,130,144,2,131,3,60,192,246,99,36,
- 64,18,2,0,33,56,67,0,140,0,230,140,
- 0,1,8,36,4,0,197,140,0,0,131,140,
- 0,0,128,172,12,0,137,172,4,0,164,172,
- 12,0,200,172,33,48,160,0,216,0,226,140,
- 33,40,128,0,1,0,66,36,0,128,99,48,
- 4,0,96,20,216,0,226,172,4,0,132,140,
- 161,21,192,8,0,0,0,0,8,0,224,3,
- 140,0,230,172,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,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,0,224,3,0,0,0,0,
- 172,0,128,172,176,0,128,172,180,0,128,172,
- 184,0,128,172,188,0,128,172,192,0,128,172,
- 196,0,128,172,200,0,128,172,204,0,128,172,
- 208,0,128,172,212,0,128,172,224,0,128,172,
- 8,1,128,172,4,1,128,172,236,0,128,172,
- 240,0,128,172,232,0,128,172,244,0,128,172,
- 8,0,224,3,248,0,128,172,224,255,189,39,
- 16,0,176,175,33,128,128,0,20,0,177,175,
- 0,2,17,36,24,0,191,175,13,8,192,12,
- 0,48,4,36,255,31,3,60,255,255,99,52,
- 33,32,0,0,36,16,67,0,0,128,3,60,
- 37,40,67,0,33,24,160,0,0,128,6,52,
- 1,0,132,36,24,0,98,36,0,0,96,164,
- 2,0,102,164,4,0,98,172,33,24,64,0,
- 42,16,145,0,249,255,64,20,1,0,132,36,
- 255,255,132,36,64,16,17,0,33,16,81,0,
- 192,16,2,0,33,16,69,0,48,0,163,36,
- 236,255,69,172,108,0,3,174,104,0,3,174,
- 96,0,5,174,100,0,2,174,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,248,255,189,39,0,32,14,60,
- 4,0,177,175,7,0,17,60,0,0,176,175,
- 4,0,16,60,2,131,25,60,192,246,57,39,
- 0,1,15,36,108,0,152,140,104,0,137,140,
- 176,0,140,140,180,0,141,140,94,0,56,17,
- 0,0,0,0,4,0,43,141,0,0,0,0,
- 37,16,110,1,0,0,66,148,0,0,0,0,
- 0,128,66,48,86,0,64,16,37,16,46,1,
- 0,0,67,140,0,0,0,0,36,16,113,0,
- 76,0,80,20,0,32,98,48,41,0,64,20,
- 15,0,98,48,188,0,130,140,0,0,0,0,
- 1,0,66,36,188,0,130,172,0,8,98,48,
- 6,0,64,16,0,4,98,48,192,0,130,140,
- 0,0,0,0,1,0,66,36,192,0,130,172,
- 0,4,98,48,6,0,64,16,0,2,98,48,
- 196,0,130,140,0,0,0,0,1,0,66,36,
- 196,0,130,172,0,2,98,48,6,0,64,16,
- 0,1,98,48,200,0,130,140,0,0,0,0,
- 1,0,66,36,200,0,130,172,0,1,98,48,
- 6,0,64,16,32,0,98,48,204,0,130,140,
- 0,0,0,0,1,0,66,36,204,0,130,172,
- 32,0,98,48,6,0,64,16,15,0,98,48,
- 208,0,130,140,0,0,0,0,1,0,66,36,
- 208,0,130,172,15,0,98,48,212,0,131,140,
- 8,0,37,141,33,24,98,0,212,0,131,172,
- 17,0,162,144,1,0,140,37,255,255,66,36,
- 17,0,162,160,25,0,64,20,37,24,46,1,
- 16,0,162,144,1,0,173,37,64,18,2,0,
- 33,64,89,0,140,0,7,141,0,129,10,52,
- 4,0,230,140,0,0,163,140,0,0,160,172,
- 12,0,170,172,4,0,197,172,12,0,239,172,
- 33,56,192,0,216,0,2,141,33,48,160,0,
- 1,0,66,36,0,128,99,48,4,0,96,20,
- 216,0,2,173,4,0,165,140,114,22,192,8,
- 0,0,0,0,140,0,7,173,37,24,46,1,
- 0,128,2,60,0,0,98,172,40,22,192,8,
- 33,72,96,1,104,0,137,172,176,0,140,172,
- 180,0,141,172,4,0,177,143,0,0,176,143,
- 8,0,224,3,8,0,189,39,224,255,189,39,
- 16,0,176,175,33,128,128,0,24,0,191,175,
- 20,0,177,175,44,0,17,142,0,0,0,0,
- 0,0,34,150,0,0,0,0,0,32,66,48,
- 89,0,64,16,0,0,0,0,2,0,34,150,
- 0,0,0,0,0,1,66,48,84,0,64,20,
- 0,0,0,0,27,22,192,12,0,0,0,0,
- 104,0,4,142,0,0,0,0,2,0,130,148,
- 0,128,3,52,255,255,66,48,75,0,67,16,
- 0,0,0,0,224,0,2,142,0,0,0,0,
- 1,0,66,36,224,0,2,174,4,0,36,174,
- 0,0,128,164,4,0,130,140,0,0,0,0,
- 0,0,64,164,0,0,2,142,0,0,0,0,
- 51,0,64,16,0,33,2,36,2,0,34,150,
- 0,0,0,0,47,0,64,16,0,33,2,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,0,0,0,
- 2,0,34,150,0,0,0,0,211,255,64,20,
- 0,33,2,36,2,0,34,166,0,0,2,142,
- 0,0,0,0,5,0,64,16,0,0,0,0,
- 8,0,2,142,0,0,0,0,242,22,192,8,
- 0,0,64,172,164,7,192,12,0,0,0,0,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,108,0,133,140,
- 0,0,0,0,4,0,162,140,0,0,0,0,
- 4,0,67,140,104,0,130,140,0,0,0,0,
- 5,0,98,20,33,16,160,0,184,0,131,140,
- 33,16,0,0,1,0,99,36,184,0,131,172,
- 8,0,224,3,0,0,0,0,224,255,189,39,
- 16,0,176,175,33,128,128,0,28,0,191,175,
- 24,0,178,175,20,0,177,175,108,0,18,142,
- 8,1,6,142,44,0,17,142,4,0,66,142,
- 104,0,7,142,4,0,66,140,18,0,163,148,
- 172,0,4,142,0,0,0,0,6,0,71,20,
- 255,255,99,48,184,0,3,142,33,16,0,0,
- 1,0,99,36,157,23,192,8,184,0,3,174,
- 33,48,195,0,1,0,130,36,172,0,2,174,
- 8,1,6,174,8,0,162,140,4,1,3,142,
- 0,0,70,144,33,32,64,2,8,0,69,174,
- 12,0,64,174,1,0,194,48,2,0,64,16,
- 1,0,98,36,4,1,2,174,0,0,2,142,
- 0,0,0,0,35,0,64,20,0,0,0,0,
- 18,0,162,148,0,0,0,0,255,255,66,48,
- 12,0,66,174,0,0,34,150,0,0,0,0,
- 0,32,66,48,24,0,64,16,12,0,2,36,
- 2,0,34,150,0,0,0,0,0,1,66,48,
- 19,0,64,20,12,0,2,36,4,0,242,16,
- 0,0,0,0,27,22,192,12,33,32,0,2,
- 12,0,2,36,2,0,66,166,104,0,4,142,
- 0,0,0,0,0,0,128,164,4,0,130,140,
- 0,0,0,0,0,0,64,164,0,33,2,36,
- 4,0,36,174,164,7,192,12,2,0,34,166,
- 154,23,192,8,0,0,0,0,154,23,192,8,
- 2,0,130,164,0,0,34,150,0,0,0,0,
- 0,32,66,48,69,0,64,16,12,0,2,36,
- 4,0,242,16,0,0,0,0,27,22,192,12,
- 33,32,0,2,12,0,2,36,2,0,66,166,
- 104,0,4,142,0,0,0,0,0,0,128,164,
- 4,0,130,140,0,0,0,0,0,0,64,164,
- 4,0,36,174,2,0,34,150,0,0,0,0,
- 47,0,64,16,0,33,2,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,0,0,0,2,0,34,150,
- 0,0,0,0,211,255,64,20,0,33,2,36,
- 2,0,34,166,8,0,2,142,0,0,0,0,
- 154,23,192,8,0,0,64,172,2,0,66,166,
- 4,0,67,142,1,0,2,36,108,0,3,174,
- 28,0,191,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 216,255,189,39,20,0,177,175,33,136,128,0,
- 24,0,178,175,2,131,18,60,192,131,82,38,
- 28,0,179,175,0,1,19,36,32,0,191,175,
- 16,0,176,175,104,0,48,142,108,0,34,142,
- 0,0,0,0,4,0,2,22,0,0,0,0,
- 2,0,2,150,245,23,192,8,0,0,0,0,
- 2,0,2,150,0,0,0,0,7,0,66,48,
- 11,0,64,20,33,40,64,2,2,131,4,60,
- 160,131,132,36,2,131,7,60,252,131,231,36,
- 15,63,192,12,0,2,6,36,1,0,4,36,
- 33,40,64,2,188,7,192,12,0,2,6,36,
- 2,0,2,150,4,0,3,36,7,0,66,48,
- 40,0,67,20,0,128,2,52,8,0,3,142,
- 0,0,0,0,17,0,98,144,0,0,0,0,
- 255,255,66,36,17,0,98,160,17,0,98,144,
- 0,0,0,0,30,0,64,20,0,128,2,52,
- 180,0,34,142,33,32,96,0,1,0,66,36,
- 180,0,34,174,16,0,130,144,2,131,3,60,
- 192,246,99,36,64,18,2,0,33,56,67,0,
- 140,0,230,140,0,129,8,52,4,0,197,140,
- 0,0,131,140,0,0,128,172,12,0,136,172,
- 4,0,164,172,12,0,211,172,33,48,160,0,
- 216,0,226,140,33,40,128,0,1,0,66,36,
- 0,128,99,48,4,0,96,20,216,0,226,172,
- 4,0,132,140,223,23,192,8,0,0,0,0,
- 140,0,230,172,0,128,2,52,2,0,2,166,
- 0,0,0,166,4,0,16,142,174,23,192,8,
- 0,0,0,0,44,0,35,142,104,0,48,174,
- 0,0,98,148,0,0,0,0,0,32,66,52,
- 0,0,98,164,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,0,163,2,60,
- 0,1,66,52,0,0,66,140,2,131,3,60,
- 192,6,99,36,255,3,66,48,60,0,66,36,
- 0,128,66,52,8,0,224,3,0,0,98,172,
- 208,255,189,39,28,0,177,175,33,136,128,0,
- 32,0,178,175,33,144,160,0,24,0,176,175,
- 0,163,16,60,0,163,2,60,164,1,66,140,
- 0,1,16,54,44,0,191,175,40,0,180,175,
- 4,0,64,20,36,0,179,175,60,0,2,36,
- 0,163,1,60,164,1,34,172,0,163,2,60,
- 164,1,66,140,0,0,0,0,221,5,66,40,
- 3,0,64,20,220,5,2,36,0,163,1,60,
- 164,1,34,172,0,163,3,60,164,1,99,140,
- 255,255,2,36,21,0,98,20,0,0,0,0,
- 128,128,130,143,0,0,0,0,5,0,67,20,
- 2,0,5,36,130,11,192,12,0,0,0,0,
- 128,128,130,175,2,0,5,36,10,0,6,36,
- 128,128,132,143,0,131,7,60,8,96,231,36,
- 156,11,192,12,16,0,160,175,0,0,2,142,
- 2,131,3,60,192,6,99,36,255,3,66,48,
- 66,24,192,8,64,0,66,36,0,163,2,60,
- 164,1,66,140,2,131,3,60,192,6,99,36,
- 0,128,66,52,0,0,98,172,255,31,4,60,
- 255,255,132,52,2,131,2,60,208,6,66,36,
- 36,16,68,0,0,160,5,60,37,16,69,0,
- 2,131,3,60,176,12,99,36,2,131,1,60,
- 196,6,32,172,2,131,1,60,200,6,34,172,
- 12,0,2,36,0,0,96,164,2,131,1,60,
- 178,12,34,164,6,0,65,6,36,16,100,0,
- 37,16,69,0,2,131,1,60,180,12,34,172,
- 99,24,192,8,255,31,18,60,2,131,2,60,
- 178,12,66,148,0,0,0,0,0,128,66,52,
- 2,131,1,60,178,12,34,164,255,31,18,60,
- 255,255,82,54,2,131,2,60,192,6,66,36,
- 36,16,82,0,0,160,20,60,37,16,84,0,
- 2,131,1,60,184,12,34,172,2,131,1,60,
- 188,12,32,172,44,0,34,142,0,0,0,0,
- 0,0,66,148,2,131,19,60,176,12,115,38,
- 0,32,66,48,15,0,64,20,33,40,0,0,
- 2,131,4,60,160,131,132,36,2,131,16,60,
- 192,131,16,38,33,40,0,2,2,131,7,60,
- 24,132,231,36,15,63,192,12,71,2,6,36,
- 1,0,4,36,33,40,0,2,188,7,192,12,
- 71,2,6,36,33,40,0,0,33,48,0,0,
- 36,16,114,2,44,0,35,142,37,16,84,0,
- 4,0,98,172,44,0,36,142,208,7,7,36,
- 129,67,192,12,2,0,132,36,12,0,64,20,
- 0,0,0,0,44,0,34,142,0,0,0,0,
- 2,0,69,148,2,131,4,60,15,63,192,12,
- 56,132,132,36,255,255,4,36,2,131,5,60,
- 192,131,165,36,188,7,192,12,79,2,6,36,
- 44,0,34,142,0,33,3,36,2,0,67,164,
- 8,0,34,142,0,0,0,0,0,0,64,172,
- 44,0,191,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,232,255,189,39,
- 128,128,132,143,0,128,2,52,16,0,191,175,
- 2,131,1,60,3,0,128,4,178,12,34,164,
- 177,11,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 8,0,224,3,0,0,0,0,0,0,0,0,
- 0,0,0,0,240,255,2,52,2,131,1,60,
- 33,8,34,0,208,12,32,172,240,255,66,36,
- 251,255,65,4,0,0,0,0,2,131,2,60,
- 208,12,66,36,0,163,1,60,12,1,32,172,
- 0,163,1,60,212,5,34,172,1,0,2,60,
- 148,133,128,175,144,133,128,175,0,163,1,60,
- 8,0,224,3,216,5,34,172,0,0,136,148,
- 4,0,138,148,1,0,2,49,34,0,64,20,
- 2,0,137,148,0,25,10,0,38,24,106,0,
- 38,24,105,0,240,255,99,48,2,131,15,60,
- 208,12,239,37,33,40,111,0,68,133,142,143,
- 128,0,3,36,0,0,162,140,4,0,171,148,
- 23,0,64,16,43,16,194,1,9,0,64,16,
- 6,0,172,148,7,0,11,21,8,0,173,148,
- 5,0,44,21,0,0,0,0,3,0,77,21,
- 10,0,162,148,8,0,224,3,0,0,0,0,
- 255,255,99,36,10,0,96,16,240,255,165,36,
- 43,16,175,0,238,255,64,16,0,0,162,140,
- 248,127,229,37,248,127,165,36,218,24,192,8,
- 0,0,162,140,8,0,224,3,254,255,2,36,
- 8,0,224,3,255,255,2,36,8,0,224,3,
- 0,0,0,0,0,0,136,148,68,133,142,143,
- 1,0,2,49,53,0,64,20,2,0,137,148,
- 0,131,2,60,4,0,138,148,12,1,89,140,
- 0,25,10,0,38,24,106,0,38,24,105,0,
- 240,255,99,48,2,131,15,60,208,12,239,37,
- 33,56,111,0,128,0,3,36,0,0,248,140,
- 4,0,235,148,43,16,216,1,14,0,64,16,
- 6,0,236,148,24,0,11,21,8,0,237,148,
- 22,0,44,21,255,127,2,60,20,0,77,21,
- 255,255,66,52,43,16,2,3,2,0,64,16,
- 33,16,198,1,0,0,226,172,10,0,229,164,
- 8,0,224,3,0,0,2,36,3,0,0,23,
- 1,0,57,35,0,131,2,60,12,1,89,172,
- 33,16,198,1,0,0,226,172,10,0,229,164,
- 4,0,232,164,6,0,233,164,8,0,234,164,
- 8,0,224,3,1,0,2,36,255,255,99,36,
- 11,0,96,16,0,0,0,0,240,255,231,36,
- 43,16,239,0,221,255,64,16,0,0,248,140,
- 248,127,231,37,248,127,231,36,8,25,192,8,
- 0,0,248,140,8,0,224,3,0,0,2,36,
- 144,133,130,143,0,0,0,0,1,0,66,32,
- 144,133,130,175,8,0,224,3,255,255,2,36,
- 8,0,224,3,0,0,0,0,164,128,130,143,
- 0,0,0,0,7,0,130,20,232,255,189,39,
- 160,128,130,143,2,131,3,60,208,12,99,36,
- 0,17,2,0,108,25,192,8,33,16,67,0,
- 42,16,130,0,3,0,64,16,255,255,2,36,
- 164,128,128,175,160,128,130,175,164,128,130,143,
- 160,128,131,143,35,48,130,0,1,0,101,36,
- 0,16,162,40,25,0,64,16,0,25,5,0,
- 68,133,135,143,2,131,2,60,33,16,67,0,
- 208,12,66,140,0,0,0,0,43,16,226,0,
- 4,0,64,16,0,0,0,0,255,255,198,36,
- 6,0,192,16,0,16,162,40,1,0,165,36,
- 0,16,162,40,243,255,64,20,16,0,99,36,
- 0,16,162,40,7,0,64,16,0,25,5,0,
- 2,131,2,60,208,12,66,36,160,128,133,175,
- 164,128,132,175,108,25,192,8,33,16,98,0,
- 33,16,0,0,255,255,3,36,164,128,128,175,
- 160,128,131,175,8,0,224,3,24,0,189,39,
- 0,0,0,0,0,0,0,0,24,255,189,39,
- 228,0,191,175,224,0,190,175,220,0,183,175,
- 216,0,182,175,212,0,181,175,208,0,180,175,
- 204,0,179,175,200,0,178,175,196,0,177,175,
- 192,0,176,175,44,28,192,12,0,0,0,0,
- 176,128,132,39,15,63,192,12,1,0,17,36,
- 24,0,176,39,164,68,192,12,33,32,0,2,
- 24,0,162,131,0,0,0,0,137,25,192,8,
- 32,0,8,36,0,0,2,130,32,0,8,36,
- 253,255,72,16,1,0,16,38,255,255,16,38,
- 9,0,8,36,249,255,72,16,1,0,16,38,
- 255,255,16,38,0,0,2,146,0,0,0,0,
- 208,255,66,36,10,0,66,44,27,0,64,16,
- 33,32,0,2,33,40,0,0,212,68,192,12,
- 33,48,0,0,0,0,3,146,0,0,0,0,
- 208,255,99,36,10,0,99,44,9,0,96,16,
- 33,136,64,0,1,0,16,38,0,0,2,146,
- 0,0,0,0,208,255,66,36,10,0,66,44,
- 251,255,64,20,1,0,16,38,255,255,16,38,
- 0,0,2,130,32,0,8,36,253,255,72,16,
- 1,0,16,38,255,255,16,38,9,0,8,36,
- 249,255,72,16,1,0,16,38,255,255,16,38,
- 0,0,2,130,0,0,3,146,0,0,0,0,
- 22,0,64,16,104,0,180,39,32,0,8,36,
- 19,0,72,16,9,0,8,36,17,0,72,16,
- 32,0,5,36,9,0,4,36,208,255,98,36,
- 10,0,66,44,12,0,64,20,0,0,0,0,
- 1,0,16,38,0,0,131,162,0,0,2,130,
- 0,0,3,146,0,0,0,0,5,0,64,16,
- 1,0,148,38,3,0,69,16,0,0,0,0,
- 243,255,68,20,208,255,98,36,0,0,128,162,
- 104,0,180,39,0,0,2,130,32,0,8,36,
- 253,255,72,16,1,0,16,38,255,255,16,38,
- 9,0,8,36,249,255,72,16,1,0,16,38,
- 255,255,16,38,33,240,0,2,0,0,196,131,
- 0,0,0,0,32,69,192,12,144,0,190,175,
- 11,0,64,16,33,32,192,3,33,40,0,0,
- 212,68,192,12,33,48,0,0,33,152,64,0,
- 33,32,192,3,33,40,0,0,44,69,192,12,
- 16,0,6,36,232,25,192,8,33,144,64,0,
- 255,255,18,36,255,255,19,36,0,0,3,130,
- 0,0,2,146,0,0,0,0,17,0,96,16,
- 32,0,8,36,15,0,104,16,1,0,16,38,
- 255,255,16,38,32,0,4,36,0,22,2,0,
- 3,22,2,0,9,0,8,36,8,0,72,16,
- 0,0,0,0,1,0,16,38,0,0,3,130,
- 0,0,2,146,3,0,96,16,0,0,0,0,
- 246,255,100,20,0,22,2,0,0,0,2,130,
- 32,0,8,36,253,255,72,16,1,0,16,38,
- 255,255,16,38,9,0,8,36,249,255,72,16,
- 1,0,16,38,255,255,16,38,33,184,0,2,
- 33,32,224,2,33,40,0,0,212,68,192,12,
- 33,48,0,0,33,32,224,2,33,40,0,0,
- 16,0,6,36,44,69,192,12,33,176,64,0,
- 0,0,227,130,0,0,0,0,15,0,96,16,
- 33,168,64,0,32,0,8,36,12,0,104,16,
- 32,0,3,36,0,0,2,130,9,0,8,36,
- 8,0,72,16,0,0,0,0,1,0,16,38,
- 0,0,2,130,0,0,0,0,3,0,64,16,
- 0,0,0,0,248,255,67,20,0,0,0,0,
- 0,0,131,130,0,0,0,0,121,0,98,44,
- 244,1,64,16,128,16,3,0,2,131,1,60,
- 33,8,34,0,160,138,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,1,0,131,130,
- 104,0,2,36,26,0,98,16,105,0,98,40,
- 7,0,64,16,116,0,2,36,34,0,96,16,
- 98,0,2,36,11,0,98,16,0,0,0,0,
- 26,28,192,8,0,0,0,0,5,0,98,16,
- 119,0,8,36,27,0,104,16,33,16,32,2,
- 26,28,192,8,0,0,0,0,4,162,2,60,
- 33,144,66,2,2,0,130,130,0,0,0,0,
- 214,1,64,20,0,0,0,0,2,131,4,60,
- 108,132,132,36,0,0,70,146,82,26,192,8,
- 0,0,0,0,2,0,130,130,0,0,0,0,
- 205,1,64,20,0,0,0,0,2,131,4,60,
- 120,132,132,36,0,0,70,150,0,0,0,0,
- 15,63,192,12,33,40,64,2,125,25,192,8,
- 0,0,0,0,33,16,32,2,37,255,64,16,
- 255,255,49,38,0,0,80,142,2,131,4,60,
- 132,132,132,36,33,40,64,2,4,0,82,38,
- 15,63,192,12,33,48,0,2,33,16,32,2,
- 247,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,1,0,131,130,104,0,2,36,
- 23,0,98,16,105,0,98,40,7,0,64,16,
- 116,0,2,36,25,0,96,16,98,0,2,36,
- 11,0,98,16,0,0,0,0,26,28,192,8,
- 0,0,0,0,5,0,98,16,119,0,8,36,
- 17,0,104,16,0,0,0,0,26,28,192,8,
- 0,0,0,0,4,162,2,60,33,144,66,2,
- 2,0,130,130,0,0,0,0,158,1,64,20,
- 0,0,0,0,125,25,192,8,0,0,85,162,
- 2,0,130,130,0,0,0,0,152,1,64,20,
- 0,0,0,0,125,25,192,8,0,0,85,166,
- 125,25,192,8,0,0,85,174,0,163,16,60,
- 31,163,17,60,255,255,49,54,0,0,2,142,
- 0,0,0,0,4,0,82,20,0,0,0,0,
- 180,128,132,39,15,63,192,12,33,40,0,2,
- 4,0,16,38,43,16,48,2,246,255,64,16,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 33,16,32,2,228,254,64,16,255,255,49,38,
- 33,32,96,2,164,32,192,12,33,40,192,2,
- 33,16,32,2,251,255,64,20,255,255,49,38,
- 125,25,192,8,0,0,0,0,1,0,130,130,
- 0,0,0,0,117,1,64,20,33,32,32,2,
- 133,29,192,12,33,40,96,2,125,25,192,8,
- 0,0,0,0,33,32,96,2,33,40,32,2,
- 234,31,192,12,33,48,192,2,125,25,192,8,
- 0,0,0,0,1,0,130,130,0,0,0,0,
- 103,1,64,20,33,16,32,2,200,254,64,16,
- 255,255,49,38,33,32,96,2,33,40,192,2,
- 182,29,192,12,33,48,0,2,33,16,32,2,
- 250,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,33,32,32,2,33,40,96,2,
- 33,48,192,2,38,30,192,12,33,56,0,2,
- 125,25,192,8,0,0,0,0,5,162,2,60,
- 0,0,69,144,2,131,4,60,15,63,192,12,
- 144,132,132,36,125,25,192,8,0,0,0,0,
- 0,163,1,60,20,1,32,172,14,0,32,18,
- 33,128,0,0,164,7,192,12,1,0,16,38,
- 143,63,192,12,0,0,0,0,143,63,192,12,
- 0,0,0,0,143,63,192,12,0,0,0,0,
- 143,63,192,12,0,0,0,0,43,16,17,2,
- 244,255,64,20,0,0,0,0,184,63,192,12,
- 0,0,0,0,0,163,16,60,20,1,16,142,
- 0,0,0,0,7,0,17,22,33,40,32,2,
- 2,131,4,60,164,132,132,36,15,63,192,12,
- 33,40,32,2,125,25,192,8,0,0,0,0,
- 2,131,4,60,188,132,132,36,15,63,192,12,
- 33,48,0,2,125,25,192,8,0,0,0,0,
- 0,0,226,130,7,162,8,60,16,0,64,16,
- 33,144,72,2,33,16,32,2,134,254,64,16,
- 255,255,49,38,0,0,85,174,2,131,4,60,
- 132,132,132,36,33,40,64,2,15,63,192,12,
- 33,48,160,2,4,0,82,38,33,16,32,2,
- 247,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,33,16,32,2,119,254,64,16,
- 255,255,49,38,0,0,80,142,2,131,4,60,
- 132,132,132,36,33,40,64,2,4,0,82,38,
- 15,63,192,12,33,48,0,2,33,16,32,2,
- 247,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,7,162,16,60,64,0,17,38,
- 2,131,4,60,228,132,132,36,33,40,0,2,
- 0,0,6,142,0,0,0,0,15,63,192,12,
- 4,0,16,38,42,16,17,2,247,255,64,20,
- 7,162,8,60,128,0,16,37,176,0,17,37,
- 2,131,4,60,228,132,132,36,33,40,0,2,
- 0,0,6,142,0,0,0,0,15,63,192,12,
- 4,0,16,38,42,16,17,2,247,255,64,20,
- 7,162,8,60,192,0,16,37,240,0,17,37,
- 2,131,4,60,228,132,132,36,33,40,0,2,
- 0,0,6,142,0,0,0,0,15,63,192,12,
- 4,0,16,38,42,16,17,2,247,255,64,20,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 1,0,130,130,0,0,0,0,222,0,64,20,
- 33,16,32,2,63,254,64,16,255,255,49,38,
- 33,32,96,2,213,29,192,12,33,40,160,2,
- 33,16,32,2,251,255,64,20,255,255,49,38,
- 125,25,192,8,0,0,0,0,1,0,130,130,
- 0,0,0,0,208,0,64,20,33,16,32,2,
- 49,254,64,16,255,255,49,38,33,32,96,2,
- 161,31,192,12,33,40,192,2,33,16,32,2,
- 251,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,33,16,32,2,38,254,64,16,
- 255,255,49,38,208,32,192,12,33,32,0,0,
- 33,32,0,0,164,32,192,12,33,40,0,0,
- 40,29,192,12,0,0,0,0,133,29,192,12,
- 255,255,4,36,33,16,32,2,245,255,64,20,
- 255,255,49,38,125,25,192,8,0,0,0,0,
- 1,0,131,130,87,0,2,36,27,0,98,16,
- 88,0,98,40,7,0,64,16,114,0,2,36,
- 37,0,96,16,82,0,2,36,9,0,98,16,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 5,0,98,16,119,0,8,36,15,0,104,16,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 2,0,130,130,0,0,0,0,159,0,64,20,
- 0,0,0,0,60,65,192,12,33,32,96,2,
- 184,128,132,39,33,40,96,2,15,63,192,12,
- 33,48,64,0,125,25,192,8,0,0,0,0,
- 2,0,130,130,0,0,0,0,147,0,64,20,
- 33,32,96,2,162,65,192,12,33,40,160,2,
- 242,253,64,20,33,40,160,2,2,131,4,60,
- 8,133,132,36,15,63,192,12,33,48,96,2,
- 125,25,192,8,0,0,0,0,33,16,32,2,
- 233,253,64,16,255,255,49,38,40,29,192,12,
- 0,0,0,0,33,16,32,2,252,255,64,20,
- 255,255,49,38,125,25,192,8,0,0,0,0,
- 1,0,133,130,87,0,2,36,29,0,162,16,
- 88,0,162,40,5,0,64,16,82,0,2,36,
- 11,0,162,16,33,16,32,2,125,25,192,8,
- 0,0,0,0,114,0,2,36,5,0,162,16,
- 119,0,8,36,19,0,168,16,33,32,64,2,
- 125,25,192,8,0,0,0,0,33,16,32,2,
- 206,253,64,16,255,255,49,38,168,69,192,12,
- 33,32,64,2,184,128,132,39,33,40,64,2,
- 15,63,192,12,33,48,64,0,1,0,82,38,
- 33,16,32,2,247,255,64,20,255,255,49,38,
- 125,25,192,8,0,0,0,0,33,32,64,2,
- 29,70,192,12,33,40,160,2,189,253,64,20,
- 33,40,160,2,2,131,4,60,40,133,132,36,
- 15,63,192,12,33,48,64,2,125,25,192,8,
- 0,0,0,0,144,0,164,143,122,28,192,12,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 33,16,96,2,175,253,64,16,255,255,115,38,
- 143,63,192,12,0,0,0,0,33,16,96,2,
- 252,255,64,20,255,255,115,38,125,25,192,8,
- 0,0,0,0,33,16,32,2,165,253,64,16,
- 255,255,49,38,33,32,96,2,208,32,192,12,
- 33,40,192,2,33,16,32,2,251,255,64,20,
- 255,255,49,38,125,25,192,8,0,0,0,0,
- 1,0,130,146,0,0,0,0,159,255,66,36,
- 0,22,2,0,3,30,2,0,24,0,98,44,
- 27,0,64,16,128,16,3,0,2,131,1,60,
- 33,8,34,0,136,140,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,12,33,192,12,
- 33,32,64,2,125,25,192,8,0,0,0,0,
- 15,33,192,12,33,32,96,2,125,25,192,8,
- 0,0,0,0,18,33,192,12,33,32,96,2,
- 125,25,192,8,0,0,0,0,22,33,192,12,
- 33,32,96,2,125,25,192,8,0,0,0,0,
- 25,33,192,12,33,32,64,2,125,25,192,8,
- 0,0,0,0,33,32,64,2,7,33,192,12,
- 33,40,192,2,125,25,192,8,0,0,0,0,
- 16,0,182,175,33,32,32,2,33,40,192,3,
- 33,48,224,2,161,33,192,12,33,56,160,2,
- 125,25,192,8,0,0,0,0,33,136,0,0,
- 2,131,4,60,72,133,132,36,15,63,192,12,
- 1,0,49,38,32,0,34,46,250,255,64,20,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 2,131,4,60,92,133,132,36,15,63,192,12,
- 33,40,128,2,123,25,192,8,0,0,0,0,
- 228,0,191,143,224,0,190,143,220,0,183,143,
- 216,0,182,143,212,0,181,143,208,0,180,143,
- 204,0,179,143,200,0,178,143,196,0,177,143,
- 192,0,176,143,8,0,224,3,232,0,189,39,
- 232,255,189,39,2,131,5,60,192,154,165,36,
- 20,0,191,175,16,0,176,175,0,0,162,140,
- 0,0,0,0,9,0,64,16,33,128,160,0,
- 0,0,5,142,192,128,132,39,15,63,192,12,
- 4,0,16,38,0,0,2,142,0,0,0,0,
- 249,255,64,20,0,0,0,0,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 0,0,132,144,0,0,0,0,208,255,130,36,
- 10,0,66,44,4,0,64,16,0,22,4,0,
- 3,22,2,0,89,28,192,8,208,255,66,36,
- 159,255,130,36,6,0,66,44,4,0,64,16,
- 0,22,4,0,3,22,2,0,89,28,192,8,
- 169,255,66,36,191,255,130,36,6,0,66,44,
- 3,0,64,20,0,22,4,0,89,28,192,8,
- 255,255,2,36,3,22,2,0,201,255,66,36,
- 8,0,224,3,0,0,0,0,216,255,189,39,
- 24,0,178,175,33,144,128,0,32,0,191,175,
- 28,0,179,175,20,0,177,175,16,0,176,175,
- 0,0,81,142,0,0,0,0,65,28,192,12,
- 33,32,32,2,33,24,64,0,255,255,19,36,
- 9,0,115,16,0,129,3,0,65,28,192,12,
- 1,0,36,38,33,24,64,0,4,0,115,16,
- 2,0,34,38,0,0,66,174,115,28,192,8,
- 37,16,3,2,255,255,2,36,32,0,191,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 176,255,189,39,64,0,180,175,33,160,128,0,
- 72,0,191,175,68,0,181,175,60,0,179,175,
- 56,0,178,175,52,0,177,175,48,0,176,175,
- 0,0,130,130,0,0,0,0,53,0,64,20,
- 33,128,0,0,27,67,192,12,33,32,0,0,
- 1,0,4,36,27,67,192,12,33,128,64,0,
- 2,0,4,36,27,67,192,12,33,136,64,0,
- 33,24,64,0,255,255,2,36,5,0,2,18,
- 0,0,0,0,3,0,34,18,0,0,0,0,
- 6,0,98,20,255,255,2,52,2,131,4,60,
- 15,63,192,12,60,137,132,36,29,29,192,8,
- 0,0,0,0,5,0,2,18,0,0,0,0,
- 3,0,34,18,0,0,0,0,6,0,98,20,
- 1,0,2,50,2,131,4,60,15,63,192,12,
- 104,137,132,36,29,29,192,8,0,0,0,0,
- 6,0,64,16,255,0,5,50,2,131,4,60,
- 15,63,192,12,132,137,132,36,29,29,192,8,
- 0,0,0,0,2,131,4,60,176,137,132,36,
- 3,50,16,0,3,18,17,0,16,0,162,175,
- 255,0,98,48,20,0,162,175,3,18,3,0,
- 255,0,39,50,15,63,192,12,24,0,162,175,
- 29,29,192,8,0,0,0,0,40,0,180,175,
- 58,0,21,36,32,0,19,36,255,255,18,36,
- 32,0,177,39,40,0,162,143,0,0,0,0,
- 0,0,67,128,0,0,0,0,3,0,117,16,
- 0,0,0,0,3,0,115,20,0,0,0,0,
- 1,0,66,36,40,0,162,175,91,28,192,12,
- 40,0,164,39,33,24,64,0,75,0,114,16,
- 0,0,0,0,40,0,162,143,0,0,35,166,
- 0,0,67,128,0,0,0,0,3,0,117,16,
- 0,0,0,0,3,0,115,20,0,0,0,0,
- 1,0,66,36,40,0,162,175,91,28,192,12,
- 40,0,164,39,33,24,64,0,60,0,114,16,
- 1,0,16,38,0,0,34,150,0,26,3,0,
- 37,16,67,0,0,0,34,166,3,0,2,42,
- 220,255,64,20,2,0,49,38,32,0,165,151,
- 0,0,0,0,1,0,162,48,7,0,64,16,
- 0,0,0,0,2,131,4,60,208,137,132,36,
- 15,63,192,12,255,0,165,48,25,29,192,8,
- 0,0,0,0,36,0,162,151,0,0,0,0,
- 0,7,66,48,6,0,64,16,0,0,0,0,
- 2,131,4,60,15,63,192,12,0,138,132,36,
- 25,29,192,8,0,0,0,0,255,66,192,12,
- 33,32,0,0,1,0,4,36,34,0,165,151,
- 0,0,0,0,255,66,192,12,33,128,0,0,
- 36,0,165,151,0,0,0,0,255,66,192,12,
- 2,0,4,36,2,131,4,60,15,63,192,12,
- 32,138,132,36,2,131,4,60,80,138,132,36,
- 15,63,192,12,33,40,0,2,196,128,132,39,
- 200,128,134,39,31,21,192,12,32,0,165,39,
- 36,0,162,151,1,0,16,38,0,1,66,36,
- 36,0,162,167,8,0,2,42,7,0,64,16,
- 0,0,0,0,8,29,192,8,0,0,0,0,
- 2,131,4,60,116,138,132,36,15,63,192,12,
- 33,40,128,2,72,0,191,143,68,0,181,143,
- 64,0,180,143,60,0,179,143,56,0,178,143,
- 52,0,177,143,48,0,176,143,8,0,224,3,
- 80,0,189,39,0,0,0,0,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,0,0,
- 20,0,177,175,33,136,0,0,24,0,191,175,
- 33,32,0,2,162,65,192,12,33,40,0,0,
- 43,0,64,16,0,0,0,0,1,0,16,38,
- 64,0,2,42,249,255,64,20,33,32,0,2,
- 33,128,0,0,85,85,17,36,33,32,0,2,
- 162,65,192,12,85,85,5,36,32,0,64,16,
- 0,0,0,0,1,0,16,38,64,0,2,42,
- 249,255,64,20,33,32,0,2,33,128,0,0,
- 170,170,17,52,33,32,0,2,162,65,192,12,
- 170,170,5,52,21,0,64,16,0,0,0,0,
- 1,0,16,38,64,0,2,42,249,255,64,20,
- 33,32,0,2,33,128,0,0,255,255,17,52,
- 33,32,0,2,162,65,192,12,255,255,5,52,
- 10,0,64,16,0,0,0,0,1,0,16,38,
- 64,0,2,42,249,255,64,20,33,32,0,2,
- 2,131,4,60,15,63,192,12,240,140,132,36,
- 101,29,192,8,0,0,0,0,60,65,192,12,
- 33,32,0,2,2,131,4,60,4,141,132,36,
- 33,40,32,2,33,48,0,2,15,63,192,12,
- 33,56,64,0,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 0,0,0,0,0,0,0,0,232,255,189,39,
- 16,0,191,175,210,7,192,12,0,0,0,0,
- 139,14,192,12,0,0,0,0,180,10,192,12,
- 0,0,0,0,32,133,132,143,1,0,2,36,
- 42,16,68,0,9,0,64,16,0,2,3,36,
- 64,34,4,0,2,131,1,60,33,8,35,0,
- 196,246,32,172,0,2,99,36,42,16,100,0,
- 250,255,64,20,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 208,255,189,39,24,0,178,175,33,144,128,0,
- 32,0,180,175,33,160,160,0,44,0,191,175,
- 40,0,182,175,36,0,181,175,28,0,179,175,
- 20,0,177,175,3,0,128,26,16,0,176,175,
- 149,29,192,8,1,0,147,38,1,0,20,36,
- 32,133,147,143,255,255,82,38,255,255,2,36,
- 20,0,66,18,255,255,21,36,2,131,22,60,
- 192,246,214,38,108,29,192,12,33,128,128,2,
- 42,16,19,2,10,0,64,16,64,18,16,0,
- 33,136,86,0,242,21,192,12,33,32,32,2,
- 133,12,192,12,33,32,0,2,1,0,16,38,
- 42,16,19,2,249,255,64,20,0,2,49,38,
- 255,255,82,38,240,255,85,22,0,0,0,0,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,216,255,189,39,24,0,178,175,
- 33,144,160,0,28,0,179,175,33,152,192,0,
- 32,0,191,175,20,0,177,175,3,0,128,24,
- 16,0,176,175,195,29,192,8,1,0,145,36,
- 1,0,4,36,32,133,145,143,33,128,128,0,
- 42,16,17,2,8,0,64,16,33,32,0,2,
- 33,40,64,2,250,29,192,12,33,48,96,2,
- 1,0,16,38,42,16,17,2,250,255,64,20,
- 33,32,0,2,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,224,255,189,39,
- 24,0,191,175,20,0,177,175,3,0,128,24,
- 16,0,176,175,222,29,192,8,1,0,145,36,
- 1,0,4,36,32,133,145,143,33,128,128,0,
- 42,16,17,2,7,0,64,16,0,0,0,0,
- 237,29,192,12,33,32,0,2,1,0,16,38,
- 42,16,17,2,251,255,64,20,0,0,0,0,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,64,34,4,0,
- 2,131,2,60,192,246,66,36,33,32,130,0,
- 44,0,131,140,1,0,2,36,32,0,130,172,
- 16,0,2,36,2,0,98,164,8,0,130,140,
- 0,0,0,0,8,0,224,3,0,0,64,172,
- 208,255,189,39,33,48,128,0,64,18,6,0,
- 2,131,3,60,192,246,99,36,36,0,177,175,
- 33,136,67,0,40,0,191,175,32,0,176,175,
- 4,0,34,142,0,0,0,0,4,0,64,20,
- 33,128,160,0,1,0,4,36,133,29,192,12,
- 33,40,192,0,3,0,0,30,221,5,2,42,
- 17,30,192,8,1,0,16,36,3,0,64,20,
- 33,32,32,2,220,5,16,36,33,32,32,2,
- 208,7,5,36,108,0,131,140,12,0,2,36,
- 2,0,98,164,16,0,162,39,8,0,98,172,
- 0,128,2,54,12,0,96,172,16,0,162,175,
- 255,255,2,36,20,0,162,175,2,131,2,60,
- 0,155,66,36,98,31,192,12,24,0,162,175,
- 40,0,191,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,48,0,189,39,56,254,189,39,
- 160,1,176,175,33,128,192,0,48,1,164,175,
- 33,32,224,0,64,18,5,0,2,131,3,60,
- 192,246,99,36,33,16,67,0,56,1,162,175,
- 64,18,16,0,33,16,67,0,40,0,168,39,
- 196,1,191,175,192,1,190,175,188,1,183,175,
- 184,1,182,175,180,1,181,175,176,1,180,175,
- 172,1,179,175,168,1,178,175,164,1,177,175,
- 64,1,162,175,12,0,160,24,96,1,168,175,
- 32,133,131,143,0,0,0,0,42,16,163,0,
- 19,1,64,16,1,0,2,36,5,0,0,26,
- 42,16,3,2,15,1,64,16,1,0,2,36,
- 3,0,176,20,33,40,0,0,86,31,192,8,
- 1,0,2,36,212,68,192,12,33,48,0,0,
- 6,0,65,4,104,1,162,175,33,72,64,0,
- 35,72,9,0,104,1,169,175,87,30,192,8,
- 112,1,160,175,1,0,8,36,112,1,168,175,
- 1,0,4,36,133,29,192,12,33,40,0,0,
- 237,29,192,12,33,32,0,2,24,0,169,39,
- 56,1,168,143,255,0,2,36,80,1,169,175,
- 108,0,8,141,43,1,163,39,72,1,168,175,
- 0,0,98,160,255,255,66,36,253,255,65,4,
- 255,255,99,36,64,1,169,143,0,0,0,0,
- 120,0,41,141,64,1,168,143,128,1,169,175,
- 124,0,8,141,64,1,169,143,136,1,168,175,
- 44,0,34,141,0,0,0,0,12,0,64,172,
- 44,0,34,141,0,0,0,0,16,0,64,172,
- 44,0,34,141,120,1,160,175,32,0,64,172,
- 44,0,34,141,88,1,160,175,24,0,64,172,
- 48,1,168,143,0,0,0,0,168,0,0,25,
- 40,0,169,39,144,1,169,175,88,1,168,143,
- 0,0,0,0,255,0,2,49,4,0,86,36,
- 60,0,194,42,2,0,64,16,0,0,0,0,
- 60,0,22,36,104,1,169,143,0,0,0,0,
- 2,0,32,17,0,0,0,0,104,1,182,143,
- 56,1,164,143,72,1,168,143,12,0,2,36,
- 2,0,2,165,80,1,169,143,0,128,194,54,
- 8,0,9,173,12,0,0,173,0,0,34,173,
- 255,255,8,36,4,0,40,173,144,1,168,143,
- 0,0,0,0,8,0,40,173,88,1,168,143,
- 96,1,169,143,208,7,5,36,98,31,192,12,
- 0,0,40,173,0,128,5,52,0,128,6,52,
- 128,1,164,143,0,0,0,0,129,67,192,12,
- 2,0,7,36,13,0,64,20,0,0,0,0,
- 88,1,165,143,2,131,4,60,15,63,192,12,
- 64,141,132,36,120,1,169,143,0,0,0,0,
- 1,0,41,37,20,0,34,41,117,0,64,16,
- 120,1,169,175,32,31,192,8,0,0,0,0,
- 128,1,168,143,64,1,169,143,8,0,2,141,
- 255,255,8,36,136,0,53,141,0,0,0,0,
- 50,0,72,16,33,184,0,0,1,0,4,36,
- 4,0,18,36,4,0,3,36,0,0,190,142,
- 8,0,166,142,112,1,169,143,255,63,212,51,
- 30,0,32,17,33,184,244,2,42,16,116,0,
- 27,0,64,16,33,152,96,0,144,1,168,143,
- 0,0,0,0,33,136,72,2,33,128,102,0,
- 15,0,128,16,0,0,0,0,0,0,2,146,
- 0,0,35,146,0,0,0,0,10,0,67,16,
- 33,48,192,2,2,131,4,60,92,141,132,36,
- 88,1,165,143,16,0,163,175,0,0,2,146,
- 33,56,64,2,15,63,192,12,20,0,162,175,
- 33,32,0,0,1,0,115,38,1,0,16,38,
- 1,0,49,38,42,16,116,2,235,255,64,20,
- 1,0,82,38,33,24,0,0,4,0,181,142,
- 0,128,194,51,217,255,64,16,0,0,0,0,
- 128,1,169,143,0,0,0,0,8,0,34,141,
- 0,0,0,0,25,0,128,16,18,0,87,164,
- 9,0,246,18,33,48,192,2,2,131,4,60,
- 140,141,132,36,88,1,165,143,0,0,0,0,
- 15,63,192,12,33,56,224,2,5,31,192,8,
- 0,0,0,0,64,1,168,143,0,0,0,0,
- 136,0,2,141,96,1,169,143,8,0,70,140,
- 0,0,34,141,0,0,198,140,0,0,0,0,
- 7,0,194,16,0,0,0,0,88,1,165,143,
- 2,131,4,60,15,63,192,12,184,141,132,36,
- 64,1,168,143,0,0,0,0,136,0,4,141,
- 152,21,192,12,0,0,0,0,64,1,169,143,
- 0,0,0,0,136,0,53,173,128,1,168,143,
- 8,128,2,52,0,0,0,165,2,0,2,165,
- 8,0,0,173,12,0,0,165,136,1,169,143,
- 8,0,2,36,2,0,34,165,4,0,40,141,
- 128,1,169,143,136,1,168,175,4,0,41,141,
- 64,1,168,143,128,1,169,175,120,0,9,173,
- 136,1,169,143,0,0,0,0,124,0,9,173,
- 88,1,168,143,48,1,169,143,1,0,8,37,
- 42,16,9,1,91,255,64,20,88,1,168,175,
- 64,1,168,143,0,0,0,0,44,0,3,141,
- 0,0,0,0,12,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,12,0,101,140,
- 2,131,4,60,15,63,192,12,212,141,132,36,
- 64,1,169,143,0,0,0,0,44,0,35,141,
- 0,0,0,0,16,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,16,0,101,140,
- 2,131,4,60,15,63,192,12,240,141,132,36,
- 64,1,168,143,0,0,0,0,44,0,3,141,
- 0,0,0,0,32,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,32,0,101,140,
- 2,131,4,60,15,63,192,12,16,142,132,36,
- 64,1,169,143,0,0,0,0,44,0,35,141,
- 0,0,0,0,24,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,24,0,101,140,
- 2,131,4,60,15,63,192,12,48,142,132,36,
- 196,1,191,143,192,1,190,143,188,1,183,143,
- 184,1,182,143,180,1,181,143,176,1,180,143,
- 172,1,179,143,168,1,178,143,164,1,177,143,
- 160,1,176,143,8,0,224,3,200,1,189,39,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 24,0,191,175,20,0,177,175,44,0,4,142,
- 0,0,0,0,0,0,130,148,0,0,0,0,
- 0,32,66,48,7,0,64,20,33,136,160,0,
- 0,0,133,148,2,131,4,60,15,63,192,12,
- 80,142,132,36,156,31,192,8,3,0,2,36,
- 2,0,132,36,33,40,0,0,33,48,0,0,
- 129,67,192,12,33,56,32,2,13,0,64,16,
- 33,40,0,0,44,0,3,142,0,33,2,36,
- 2,0,98,164,8,0,2,142,33,48,0,0,
- 0,0,64,172,44,0,4,142,33,56,32,2,
- 129,67,192,12,2,0,132,36,9,0,64,20,
- 0,32,5,36,44,0,2,142,0,0,0,0,
- 2,0,69,148,2,131,4,60,15,63,192,12,
- 108,142,132,36,156,31,192,8,1,0,2,36,
- 44,0,4,142,0,32,6,36,129,67,192,12,
- 33,56,32,2,8,0,64,20,33,16,0,0,
- 44,0,2,142,0,0,0,0,0,0,69,148,
- 2,131,4,60,15,63,192,12,132,142,132,36,
- 2,0,2,36,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 224,255,189,39,24,0,178,175,33,144,160,0,
- 28,0,191,175,20,0,177,175,7,0,128,4,
- 16,0,176,175,24,133,130,143,0,0,0,0,
- 255,255,66,36,42,16,68,0,4,0,64,16,
- 33,136,128,0,24,133,130,143,33,32,0,0,
- 255,255,81,36,33,128,128,0,42,16,48,2,
- 7,0,64,20,33,32,0,2,193,31,192,12,
- 33,40,64,2,1,0,16,38,42,16,48,2,
- 251,255,64,16,33,32,0,2,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,8,0,224,3,
- 0,0,0,0,232,255,189,39,16,0,191,175,
- 236,63,192,12,1,16,4,36,85,0,2,36,
- 131,131,1,60,128,18,34,160,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 216,255,189,39,28,0,177,175,33,136,128,0,
- 32,0,178,175,33,144,160,0,212,128,132,39,
- 36,0,191,175,15,63,192,12,24,0,176,175,
- 9,0,64,26,33,128,0,0,0,0,37,146,
- 1,0,49,38,220,128,132,39,15,63,192,12,
- 1,0,16,38,42,16,18,2,249,255,64,20,
- 0,0,0,0,228,128,132,39,15,63,192,12,
- 0,0,0,0,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,48,255,189,39,33,56,128,0,
- 192,0,178,175,33,144,160,0,200,0,180,175,
- 33,160,192,0,255,255,226,36,6,0,66,44,
- 204,0,191,175,196,0,179,175,188,0,177,175,
- 2,0,64,20,184,0,176,175,1,0,7,36,
- 2,0,64,30,0,0,0,0,1,0,18,36,
- 2,0,128,30,64,18,7,0,60,0,20,36,
- 2,131,3,60,192,246,99,36,33,136,67,0,
- 4,0,34,142,0,0,0,0,4,0,64,20,
- 33,152,64,2,1,0,4,36,133,29,192,12,
- 33,40,224,0,255,31,4,60,255,255,132,52,
- 0,128,133,54,120,0,162,39,36,16,68,0,
- 0,160,3,60,37,16,67,0,104,0,165,175,
- 108,0,160,175,112,0,162,175,12,0,2,36,
- 80,0,160,167,82,0,162,167,80,0,162,39,
- 36,16,68,0,37,128,67,0,104,0,162,39,
- 36,16,68,0,232,128,132,143,37,16,67,0,
- 84,0,176,175,88,0,162,175,92,0,160,175,
- 5,0,128,16,4,0,2,36,82,0,162,167,
- 255,255,2,36,92,0,165,175,88,0,162,175,
- 44,0,34,142,0,0,0,0,0,0,66,148,
- 0,0,0,0,0,32,66,48,7,0,64,20,
- 33,40,0,0,255,255,4,36,2,131,5,60,
- 184,142,165,36,188,7,192,12,208,1,6,36,
- 33,40,0,0,44,0,34,142,33,48,0,0,
- 4,0,80,172,44,0,36,142,208,7,7,36,
- 129,67,192,12,2,0,132,36,12,0,64,20,
- 0,0,0,0,44,0,34,142,0,0,0,0,
- 2,0,69,148,2,131,4,60,15,63,192,12,
- 108,142,132,36,255,255,4,36,2,131,5,60,
- 184,142,165,36,188,7,192,12,216,1,6,36,
- 34,11,192,12,1,0,4,36,0,163,16,60,
- 4,1,16,142,0,163,2,60,4,1,66,140,
- 0,0,0,0,252,255,2,18,0,33,3,36,
- 44,0,34,142,0,0,0,0,2,0,67,164,
- 8,0,34,142,0,0,0,0,0,0,64,172,
- 0,163,16,60,4,1,16,142,44,0,36,142,
- 0,0,0,0,4,0,130,140,0,0,0,0,
- 0,0,66,148,0,0,0,0,0,128,66,48,
- 10,0,64,20,0,0,0,0,44,0,35,142,
- 0,0,0,0,4,0,98,140,0,0,0,0,
- 0,0,66,148,0,0,0,0,0,128,66,48,
- 250,255,64,16,0,0,0,0,255,255,115,38,
- 19,0,96,18,33,40,64,2,44,0,35,142,
- 0,0,0,0,4,0,98,140,0,0,0,0,
- 0,0,66,148,0,0,0,0,0,128,66,48,
- 229,255,64,16,0,0,0,0,4,0,98,140,
- 0,0,0,0,0,0,66,148,0,0,0,0,
- 0,128,66,48,250,255,64,20,0,0,0,0,
- 89,32,192,8,0,0,0,0,2,131,4,60,
- 200,142,132,36,33,48,128,2,0,163,3,60,
- 4,1,99,140,0,128,2,52,82,0,162,167,
- 35,128,112,0,15,63,192,12,33,56,0,2,
- 19,0,0,18,64,41,18,0,35,40,178,0,
- 128,40,5,0,33,40,178,0,192,40,5,0,
- 26,0,176,0,2,0,0,22,0,0,0,0,
- 13,0,7,0,255,255,1,36,4,0,1,22,
- 0,128,1,60,2,0,161,20,0,0,0,0,
- 13,0,6,0,18,40,0,0,236,128,132,39,
- 15,63,192,12,0,0,0,0,204,0,191,143,
- 200,0,180,143,196,0,179,143,192,0,178,143,
- 188,0,177,143,184,0,176,143,8,0,224,3,
- 208,0,189,39,224,255,189,39,20,0,177,175,
- 33,136,128,0,24,0,191,175,180,10,192,12,
- 16,0,176,175,34,11,192,12,1,0,4,36,
- 16,133,132,143,0,163,16,60,4,1,16,142,
- 193,63,192,12,0,0,0,0,0,163,2,60,
- 4,1,66,140,0,0,0,0,35,40,80,0,
- 73,252,162,36,99,0,66,44,4,0,64,16,
- 0,0,0,0,2,131,4,60,196,32,192,8,
- 0,143,132,36,5,0,160,20,0,0,0,0,
- 2,131,4,60,36,143,132,36,196,32,192,8,
- 33,40,0,0,2,131,4,60,76,143,132,36,
- 15,63,192,12,1,0,16,36,3,0,48,18,
- 0,0,0,0,34,11,192,12,33,32,0,0,
- 0,129,144,175,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 200,255,189,39,32,0,178,175,33,144,128,0,
- 33,48,64,2,44,0,181,175,1,131,21,60,
- 60,252,181,38,33,56,160,2,40,0,180,175,
- 2,131,20,60,144,143,148,38,36,0,179,175,
- 0,163,19,60,120,1,115,142,0,163,3,60,
- 120,1,99,140,32,131,2,60,48,0,191,175,
- 28,0,177,175,24,0,176,175,16,0,180,175,
- 33,32,96,2,35,136,67,0,84,64,192,12,
- 33,40,32,2,3,0,64,18,33,128,64,0,
- 10,0,0,22,0,0,0,0,16,0,180,175,
- 33,32,96,2,33,40,32,2,33,48,64,2,
- 244,63,192,12,33,56,160,2,33,128,2,2,
- 5,0,0,18,33,40,96,2,2,131,4,60,
- 168,143,132,36,252,32,192,8,33,40,96,2,
- 2,131,4,60,204,143,132,36,15,63,192,12,
- 33,48,177,0,48,0,191,143,44,0,181,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 56,0,189,39,0,163,1,60,232,5,36,172,
- 0,163,1,60,8,0,224,3,236,5,37,172,
- 28,129,132,175,8,0,224,3,0,0,0,0,
- 16,129,132,175,8,0,224,3,0,0,0,0,
- 15,0,132,48,20,129,132,175,8,0,224,3,
- 0,0,0,0,24,129,132,175,8,0,224,3,
- 0,0,0,0,32,129,132,175,8,0,224,3,
- 0,0,0,0,33,72,128,0,33,80,160,0,
- 33,88,192,0,7,162,4,60,48,1,132,52,
- 7,162,8,60,0,1,8,53,20,129,130,143,
- 24,129,131,143,128,48,2,0,28,129,130,143,
- 3,0,197,52,2,0,96,16,0,0,130,172,
- 67,0,197,52,16,129,130,143,0,0,0,0,
- 2,0,64,16,33,24,160,0,0,1,99,52,
- 36,129,130,143,0,0,0,0,2,0,64,16,
- 0,0,0,0,0,4,99,52,32,129,130,143,
- 0,0,3,173,3,0,64,16,7,162,5,60,
- 0,0,2,173,7,162,5,60,4,1,165,52,
- 7,162,6,60,8,1,198,52,255,0,2,60,
- 255,255,66,52,7,162,3,60,12,1,99,52,
- 7,162,4,60,16,1,132,52,36,16,66,1,
- 0,0,169,172,0,0,194,172,43,16,7,0,
- 192,16,2,0,0,0,107,172,8,0,224,3,
- 0,0,130,172,7,162,3,60,40,1,99,52,
- 3,0,2,36,0,163,1,60,20,1,32,172,
- 8,0,224,3,0,0,98,172,232,255,189,39,
- 16,0,191,175,33,24,0,0,7,162,6,60,
- 40,1,198,52,15,0,4,60,63,66,132,52,
- 0,0,197,140,0,0,0,0,16,0,162,48,
- 7,0,64,20,1,0,99,36,42,16,131,0,
- 249,255,64,16,0,0,0,0,2,131,4,60,
- 122,33,192,8,240,143,132,36,36,129,130,143,
- 0,0,0,0,3,0,64,20,33,24,0,0,
- 125,33,192,8,33,16,0,0,1,0,5,36,
- 15,0,4,60,63,66,132,52,0,163,2,60,
- 20,1,66,140,0,0,0,0,247,255,69,16,
- 1,0,99,36,42,16,131,0,249,255,64,16,
- 0,0,0,0,0,163,5,60,20,1,165,140,
- 2,131,4,60,24,144,132,36,15,63,192,12,
- 0,0,0,0,1,0,2,36,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 224,255,189,39,24,0,191,175,33,72,192,0,
- 255,31,3,60,255,255,99,52,33,64,0,0,
- 36,32,131,0,0,160,2,60,37,32,130,0,
- 36,40,163,0,16,0,32,25,37,40,162,0,
- 0,0,134,144,0,0,167,144,0,0,0,0,
- 7,0,199,16,1,0,165,36,2,131,4,60,
- 72,144,132,36,15,63,192,12,33,40,0,1,
- 157,33,192,8,1,0,2,36,1,0,8,37,
- 42,16,9,1,242,255,64,20,1,0,132,36,
- 33,16,0,0,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,0,163,2,60,
- 232,5,66,140,152,255,189,39,80,0,180,175,
- 120,0,180,143,64,0,176,175,33,128,160,0,
- 68,0,177,175,33,136,192,0,72,0,178,175,
- 33,144,224,0,100,0,191,175,96,0,190,175,
- 92,0,183,175,88,0,182,175,84,0,181,175,
- 76,0,179,175,12,0,64,16,16,0,164,175,
- 0,163,2,60,236,5,66,140,0,0,0,0,
- 7,0,64,16,0,0,0,0,0,163,2,60,
- 236,5,66,140,0,0,0,0,1,8,66,44,
- 10,0,64,20,16,0,2,60,0,163,5,60,
- 232,5,165,140,0,163,6,60,236,5,198,140,
- 2,131,4,60,15,63,192,12,124,144,132,36,
- 7,35,192,8,0,0,0,0,16,0,168,143,
- 0,0,0,0,43,16,72,0,6,0,64,16,
- 0,0,0,0,2,131,4,60,15,63,192,12,
- 172,144,132,36,7,35,192,8,0,0,0,0,
- 224,132,130,143,0,0,0,0,11,0,64,20,
- 0,0,0,0,0,163,4,60,236,5,132,140,
- 13,8,192,12,0,0,0,0,255,31,3,60,
- 255,255,99,52,36,16,67,0,0,160,3,60,
- 37,16,67,0,224,132,130,175,228,132,130,143,
- 0,0,0,0,11,0,64,20,0,0,0,0,
- 0,163,4,60,236,5,132,140,13,8,192,12,
- 0,0,0,0,255,31,3,60,255,255,99,52,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 228,132,130,175,224,132,133,143,0,163,6,60,
- 232,5,198,140,228,132,135,143,2,131,4,60,
- 15,63,192,12,208,144,132,36,16,129,133,143,
- 20,129,134,143,2,131,4,60,15,63,192,12,
- 8,145,132,36,7,162,2,60,232,0,66,52,
- 0,0,83,140,1,0,3,130,105,0,2,36,
- 7,0,98,20,251,255,2,60,1,0,2,36,
- 36,129,130,175,4,0,2,60,0,8,66,52,
- 10,34,192,8,37,152,98,2,36,129,128,175,
- 255,247,66,52,36,152,98,2,7,162,2,60,
- 232,0,66,52,0,0,83,172,0,0,5,130,
- 114,0,2,36,3,0,162,16,82,0,2,36,
- 3,0,162,20,119,0,2,36,42,34,192,8,
- 33,176,0,0,3,0,162,16,87,0,2,36,
- 3,0,162,20,108,0,2,36,42,34,192,8,
- 1,0,22,36,3,0,162,16,76,0,2,36,
- 3,0,162,20,116,0,2,36,42,34,192,8,
- 2,0,22,36,118,0,162,16,84,0,2,36,
- 116,0,162,16,0,0,0,0,2,131,4,60,
- 15,63,192,12,52,145,132,36,7,35,192,8,
- 0,0,0,0,0,0,38,130,0,0,0,0,
- 12,0,192,16,99,0,2,36,3,0,194,16,
- 67,0,2,36,4,0,194,20,33,152,0,0,
- 5,0,19,36,61,34,192,8,5,0,21,36,
- 2,131,1,60,80,155,50,160,61,34,192,8,
- 33,168,0,0,33,168,0,0,5,0,19,36,
- 2,131,1,60,80,155,32,160,16,0,168,143,
- 0,163,18,60,236,5,82,142,0,0,0,0,
- 197,0,0,17,255,255,20,37,255,255,194,38,
- 2,0,87,44,2,0,30,36,33,128,160,2,
- 42,16,112,2,73,0,64,20,0,0,0,0,
- 42,0,224,18,5,0,2,36,13,0,2,22,
- 0,0,0,0,25,0,64,26,33,136,0,0,
- 224,132,130,143,0,0,0,0,33,16,81,0,
- 0,0,81,160,1,0,49,38,42,16,50,2,
- 249,255,64,20,33,48,64,2,105,34,192,8,
- 0,0,0,0,2,131,3,60,33,24,112,0,
- 80,155,99,144,0,0,0,0,9,0,64,26,
- 33,136,0,0,224,132,130,143,0,0,0,0,
- 33,16,81,0,1,0,49,38,0,0,67,160,
- 42,16,50,2,249,255,64,20,0,0,0,0,
- 33,48,64,2,0,163,4,60,232,5,132,140,
- 224,132,133,143,0,0,0,0,28,33,192,12,
- 1,0,7,36,76,33,192,12,0,0,0,0,
- 83,33,192,12,0,0,0,0,147,0,64,20,
- 0,0,0,0,3,0,192,18,33,48,64,2,
- 22,0,222,22,0,0,0,0,0,163,4,60,
- 232,5,132,140,228,132,133,143,0,0,0,0,
- 28,33,192,12,33,56,0,0,76,33,192,12,
- 0,0,0,0,83,33,192,12,0,0,0,0,
- 131,0,64,20,0,0,0,0,8,0,222,22,
- 0,0,0,0,224,132,132,143,228,132,133,143,
- 0,0,0,0,129,33,192,12,33,48,64,2,
- 122,0,64,20,0,0,0,0,1,0,16,38,
- 42,16,112,2,185,255,64,16,0,0,0,0,
- 255,255,148,38,255,255,2,36,178,255,130,22,
- 33,128,160,2,7,35,192,8,0,0,0,0,
- 180,10,192,12,0,0,0,0,34,11,192,12,
- 1,0,4,36,0,0,34,130,0,0,0,0,
- 6,0,64,16,33,184,0,0,24,0,160,175,
- 2,131,1,60,88,155,52,164,171,34,192,8,
- 33,176,0,0,6,0,23,36,4,0,2,36,
- 24,0,160,175,2,131,1,60,88,155,34,164,
- 33,176,0,0,0,8,30,36,24,0,177,143,
- 0,0,0,0,42,16,241,2,83,0,64,20,
- 64,16,17,0,2,131,8,60,88,155,8,37,
- 33,168,72,0,0,0,178,150,0,0,0,0,
- 26,0,210,3,2,0,64,22,0,0,0,0,
- 13,0,7,0,255,255,1,36,4,0,65,22,
- 0,128,1,60,2,0,193,23,0,0,0,0,
- 13,0,6,0,18,16,0,0,16,0,168,143,
- 0,0,0,0,24,0,72,0,33,56,192,2,
- 33,128,0,0,0,163,19,60,4,1,115,142,
- 0,163,4,60,232,5,132,140,224,132,133,143,
- 18,160,0,0,0,0,0,0,0,0,0,0,
- 28,33,192,12,33,48,64,2,10,0,128,26,
- 0,0,0,0,76,33,192,12,0,0,0,0,
- 83,33,192,12,0,0,0,0,48,0,64,20,
- 1,0,16,38,42,16,20,2,248,255,64,20,
- 0,0,0,0,2,131,5,60,140,145,165,36,
- 0,163,16,60,4,1,16,142,3,0,192,18,
- 0,0,0,0,2,131,5,60,128,145,165,36,
- 2,131,4,60,96,145,132,36,15,63,192,12,
- 33,48,64,2,19,0,19,18,24,0,146,2,
- 18,24,0,0,35,16,19,2,0,0,0,0,
- 27,0,98,0,2,0,64,20,0,0,0,0,
- 13,0,7,0,18,16,0,0,2,131,4,60,
- 152,145,132,36,64,41,2,0,35,40,162,0,
- 128,40,5,0,33,40,162,0,15,63,192,12,
- 192,40,5,0,255,34,192,8,2,0,181,38,
- 2,131,4,60,168,145,132,36,15,63,192,12,
- 2,0,181,38,1,0,49,38,42,16,241,2,
- 178,255,64,16,0,0,0,0,1,0,214,38,
- 2,0,194,42,166,255,64,20,0,0,0,0,
- 100,0,191,143,96,0,190,143,92,0,183,143,
- 88,0,182,143,84,0,181,143,80,0,180,143,
- 76,0,179,143,72,0,178,143,68,0,177,143,
- 64,0,176,143,8,0,224,3,104,0,189,39,
- 0,0,0,0,43,16,134,0,0,0,164,175,
- 4,0,165,175,8,0,166,175,7,0,64,20,
- 12,0,167,175,43,16,196,0,5,0,64,20,
- 1,0,2,36,43,16,167,0,2,0,64,16,
- 43,16,229,0,255,255,2,36,8,0,224,3,
- 0,0,0,0,232,255,189,39,3,131,4,60,
- 208,12,132,36,170,0,5,36,16,0,191,175,
- 144,71,192,12,60,0,6,36,2,131,6,60,
- 112,155,198,36,2,131,2,60,212,246,66,140,
- 2,131,3,60,216,246,99,132,0,0,194,172,
- 4,0,195,164,2,131,2,60,138,155,66,148,
- 2,131,3,60,132,155,99,148,2,131,4,60,
- 134,155,132,148,2,131,5,60,136,155,165,148,
- 3,131,1,60,216,12,34,164,2,131,2,60,
- 130,155,66,148,3,131,10,60,218,12,74,37,
- 3,0,199,136,0,0,199,152,4,0,200,128,
- 5,0,201,128,3,0,71,169,0,0,71,185,
- 4,0,72,161,5,0,73,161,3,131,1,60,
- 238,12,35,164,3,131,1,60,242,12,36,164,
- 3,131,1,60,246,12,37,164,3,131,1,60,
- 240,12,34,164,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,3,131,2,60,
- 216,12,66,140,3,131,3,60,220,12,99,140,
- 3,131,1,60,208,12,34,172,3,131,1,60,
- 212,12,35,172,3,131,2,60,238,12,66,148,
- 3,131,3,60,240,12,99,148,3,131,4,60,
- 242,12,132,148,232,255,189,39,16,0,176,175,
- 3,131,1,60,234,12,35,164,24,133,131,143,
- 20,0,191,175,3,131,1,60,224,12,32,172,
- 3,131,1,60,228,12,32,172,3,131,1,60,
- 248,12,32,172,3,131,1,60,252,12,32,172,
- 3,131,1,60,8,13,32,164,3,131,1,60,
- 4,13,32,164,3,131,1,60,232,12,34,164,
- 33,16,68,0,3,131,1,60,236,12,36,164,
- 3,131,1,60,244,12,34,164,8,0,96,24,
- 1,0,16,36,150,35,192,12,33,32,0,2,
- 24,133,130,143,1,0,16,38,42,16,80,0,
- 250,255,64,16,0,0,0,0,206,35,192,12,
- 0,0,0,0,52,36,192,12,0,0,0,0,
- 1,0,2,36,3,131,1,60,0,13,34,164,
- 3,0,2,36,3,131,1,60,2,13,32,164,
- 3,131,1,60,20,13,34,172,2,131,1,60,
- 164,247,34,172,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,224,255,189,39,
- 20,0,177,175,33,136,128,0,16,0,176,175,
- 192,129,17,0,3,131,4,60,16,13,132,36,
- 33,32,4,2,187,0,5,36,24,0,191,175,
- 144,71,192,12,128,0,6,36,2,131,2,60,
- 140,155,66,148,100,0,3,36,3,131,1,60,
- 33,8,48,0,24,13,35,172,0,18,2,0,
- 37,16,34,2,3,131,1,60,33,8,48,0,
- 16,13,34,164,22,36,192,12,33,32,32,2,
- 4,0,2,36,64,138,17,0,3,131,1,60,
- 33,8,48,0,20,13,34,172,2,131,1,60,
- 33,8,49,0,164,247,34,172,3,131,1,60,
- 33,8,48,0,52,13,32,172,3,131,1,60,
- 33,8,48,0,56,13,32,172,3,131,1,60,
- 33,8,48,0,106,13,32,164,3,131,1,60,
- 33,8,48,0,110,13,32,164,3,131,1,60,
- 33,8,48,0,114,13,32,164,3,131,1,60,
- 33,8,48,0,120,13,32,172,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,24,133,130,143,216,255,189,39,
- 20,0,177,175,1,0,17,36,36,0,191,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 55,0,64,24,16,0,176,175,3,131,20,60,
- 228,12,148,38,3,131,2,60,56,13,66,36,
- 128,0,83,36,124,0,82,36,128,0,16,36,
- 0,0,130,142,0,0,0,0,6,0,34,22,
- 33,32,32,2,0,0,64,174,101,36,192,12,
- 0,0,96,174,8,36,192,8,128,0,115,38,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 244,255,134,142,248,255,135,142,20,35,192,12,
- 0,0,0,0,17,0,64,20,33,32,32,2,
- 3,131,3,60,33,24,112,0,48,13,99,148,
- 3,131,2,60,33,16,80,0,16,13,66,148,
- 0,0,0,0,8,0,98,20,0,0,0,0,
- 3,131,1,60,33,8,48,0,106,13,32,164,
- 101,36,192,12,33,32,32,2,8,36,192,8,
- 128,0,115,38,0,0,64,174,125,36,192,12,
- 0,0,96,174,128,0,115,38,128,0,82,38,
- 24,133,130,143,1,0,49,38,42,16,81,0,
- 210,255,64,16,128,0,16,38,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,192,33,4,0,3,131,2,60,
- 28,13,66,36,33,24,130,0,3,131,5,60,
- 208,12,165,140,3,131,6,60,212,12,198,140,
- 0,0,101,172,4,0,102,172,12,0,66,36,
- 3,131,3,60,224,12,99,140,33,16,130,0,
- 3,131,1,60,33,8,36,0,36,13,35,172,
- 3,131,3,60,216,12,99,140,3,131,5,60,
- 220,12,165,140,0,0,67,172,4,0,69,172,
- 3,131,2,60,33,16,68,0,16,13,66,148,
- 3,131,1,60,33,8,36,0,8,0,224,3,
- 48,13,34,164,24,133,130,143,224,255,189,39,
- 20,0,177,175,1,0,17,36,24,0,191,175,
- 38,0,64,24,16,0,176,175,128,0,16,36,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 18,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,112,0,48,13,99,148,3,131,2,60,
- 33,16,80,0,16,13,66,148,0,0,0,0,
- 9,0,98,20,0,0,0,0,3,131,2,60,
- 33,16,80,0,20,13,66,140,0,0,0,0,
- 3,0,64,16,0,0,0,0,203,36,192,12,
- 33,32,32,2,24,133,130,143,1,0,49,38,
- 42,16,81,0,221,255,64,16,128,0,16,38,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,192,41,4,0,
- 3,131,3,60,33,24,101,0,20,13,99,140,
- 4,0,2,36,16,0,98,20,240,255,189,39,
- 1,0,2,36,64,26,4,0,3,131,1,60,
- 33,8,37,0,20,13,34,172,2,131,1,60,
- 33,8,35,0,164,247,34,172,1,0,2,36,
- 3,131,1,60,33,8,37,0,110,13,34,164,
- 3,131,1,60,33,8,37,0,112,13,32,164,
- 8,0,224,3,16,0,189,39,224,255,189,39,
- 24,0,178,175,33,144,128,0,16,0,176,175,
- 192,129,18,0,28,0,191,175,20,0,177,175,
- 3,131,2,60,33,16,80,0,20,13,66,140,
- 0,0,0,0,18,0,64,16,4,0,17,36,
- 16,0,81,16,254,255,66,36,2,0,66,44,
- 4,0,64,16,64,18,18,0,161,36,192,12,
- 0,0,0,0,64,18,18,0,3,131,1,60,
- 33,8,48,0,20,13,49,172,2,131,1,60,
- 33,8,34,0,164,247,49,172,3,131,1,60,
- 33,8,48,0,110,13,32,164,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,3,131,4,60,
- 208,12,132,140,3,131,5,60,212,12,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,232,255,189,39,16,0,191,175,
- 20,35,192,12,0,0,0,0,10,0,64,20,
- 1,0,2,36,3,131,1,60,252,12,34,172,
- 1,0,2,36,3,131,1,60,4,13,34,164,
- 3,131,1,60,6,13,32,164,197,36,192,8,
- 1,0,2,36,3,131,2,60,248,12,66,140,
- 0,0,0,0,9,0,64,20,1,0,2,36,
- 72,37,192,12,0,0,0,0,1,0,2,36,
- 3,131,1,60,8,13,34,164,3,131,1,60,
- 10,13,32,164,1,0,2,36,3,131,1,60,
- 248,12,34,172,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,224,255,189,39,
- 20,0,177,175,33,136,128,0,16,0,176,175,
- 192,129,17,0,24,0,191,175,3,131,2,60,
- 33,16,80,0,114,13,66,132,0,0,0,0,
- 5,0,64,16,1,0,2,36,3,131,1,60,
- 33,8,48,0,67,37,192,8,56,13,34,172,
- 3,131,4,60,208,12,132,36,3,131,2,60,
- 64,13,66,36,33,24,2,2,3,131,1,60,
- 33,8,48,0,60,13,32,164,0,0,133,140,
- 4,0,134,140,0,0,101,172,4,0,102,172,
- 12,0,66,36,3,131,3,60,224,12,99,140,
- 33,16,2,2,3,131,1,60,33,8,48,0,
- 72,13,35,172,3,131,3,60,216,12,99,140,
- 3,131,5,60,220,12,165,140,0,0,67,172,
- 4,0,69,172,3,131,2,60,33,16,80,0,
- 16,13,66,148,3,131,1,60,33,8,48,0,
- 84,13,34,164,0,0,132,140,3,131,5,60,
- 212,12,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,5,0,64,20,0,0,0,0,
- 3,131,1,60,33,8,48,0,22,37,192,8,
- 86,13,32,164,3,131,2,60,228,12,66,140,
- 2,131,3,60,128,155,99,148,192,17,2,0,
- 3,131,1,60,33,8,34,0,108,13,34,148,
- 0,0,0,0,33,16,67,0,3,131,1,60,
- 33,8,48,0,86,13,34,164,3,131,2,60,
- 232,12,66,148,192,129,17,0,3,131,1,60,
- 33,8,48,0,88,13,34,164,3,131,2,60,
- 234,12,66,148,33,32,32,2,3,131,1,60,
- 33,8,48,0,90,13,34,164,3,131,3,60,
- 236,12,99,148,3,131,2,60,33,16,80,0,
- 52,13,66,140,3,131,5,60,60,13,165,36,
- 3,131,1,60,33,8,48,0,52,13,32,172,
- 3,131,1,60,33,8,48,0,96,13,34,172,
- 3,131,1,60,33,8,48,0,92,13,35,164,
- 3,131,2,60,252,12,66,140,3,131,1,60,
- 33,8,48,0,100,13,34,172,80,40,192,12,
- 33,40,5,2,1,0,2,36,3,131,1,60,
- 33,8,48,0,56,13,32,172,3,131,1,60,
- 33,8,48,0,114,13,34,164,3,131,1,60,
- 33,8,48,0,116,13,32,164,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,128,0,2,36,
- 3,131,4,60,228,12,132,140,3,131,5,60,
- 104,13,165,36,16,0,191,175,192,25,4,0,
- 3,131,1,60,33,8,35,0,104,13,34,164,
- 151,40,192,12,33,40,101,0,2,131,4,60,
- 15,63,192,12,12,146,132,36,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,102,37,192,12,
- 0,0,0,0,13,38,192,12,0,0,0,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,24,133,130,143,208,255,189,39,
- 24,0,178,175,33,144,0,0,28,0,179,175,
- 1,0,19,36,44,0,191,175,40,0,182,175,
- 36,0,181,175,32,0,180,175,20,0,177,175,
- 110,0,64,24,16,0,176,175,3,131,21,60,
- 216,12,181,38,3,131,22,60,16,13,214,38,
- 128,0,208,38,128,0,20,36,192,17,18,0,
- 3,131,4,60,33,32,148,0,40,13,132,140,
- 3,131,5,60,33,40,180,0,44,13,165,140,
- 0,0,166,142,3,131,7,60,220,12,231,140,
- 0,0,0,0,20,35,192,12,33,136,86,0,
- 10,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,116,0,48,13,99,148,3,131,2,60,
- 33,16,84,0,16,13,66,148,0,0,0,0,
- 74,0,98,16,0,0,0,0,4,0,2,142,
- 0,0,0,0,70,0,64,16,0,0,0,0,
- 12,0,4,142,16,0,5,142,0,0,166,142,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,61,0,65,4,0,0,0,0,
- 58,0,64,18,0,0,0,0,12,0,4,142,
- 16,0,5,142,12,0,38,142,16,0,39,142,
- 20,35,192,12,0,0,0,0,50,0,64,4,
- 0,0,0,0,12,0,4,142,16,0,5,142,
- 12,0,38,142,16,0,39,142,20,35,192,12,
- 0,0,0,0,43,0,64,20,0,0,0,0,
- 20,0,5,142,8,0,3,142,20,0,36,142,
- 8,0,34,142,33,40,163,0,33,32,130,0,
- 43,16,164,0,33,0,64,20,0,0,0,0,
- 32,0,164,20,0,0,0,0,24,0,4,142,
- 28,0,5,142,24,0,38,142,28,0,39,142,
- 20,35,192,12,0,0,0,0,23,0,64,4,
- 0,0,0,0,24,0,4,142,28,0,5,142,
- 24,0,38,142,28,0,39,142,20,35,192,12,
- 0,0,0,0,16,0,64,20,0,0,0,0,
- 32,0,4,150,32,0,35,150,0,0,0,0,
- 43,16,131,0,9,0,64,20,0,0,0,0,
- 8,0,131,20,0,0,0,0,0,0,2,150,
- 0,0,35,150,0,0,0,0,43,16,67,0,
- 2,0,64,16,0,0,0,0,33,144,96,2,
- 128,0,16,38,24,133,130,143,1,0,115,38,
- 42,16,83,0,154,255,64,16,128,0,148,38,
- 3,131,1,60,228,12,50,172,12,0,64,22,
- 192,17,18,0,3,131,2,60,216,12,66,140,
- 3,131,3,60,220,12,99,140,3,131,1,60,
- 208,12,34,172,3,131,1,60,212,12,35,172,
- 3,131,1,60,3,38,192,8,224,12,32,172,
- 3,131,3,60,33,24,98,0,28,13,99,140,
- 3,131,4,60,33,32,130,0,32,13,132,140,
- 3,131,1,60,208,12,35,172,3,131,1,60,
- 212,12,36,172,3,131,3,60,33,24,98,0,
- 36,13,99,140,3,131,1,60,33,8,34,0,
- 24,13,34,140,0,0,0,0,33,24,98,0,
- 3,131,1,60,224,12,35,172,44,0,191,143,
- 40,0,182,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,48,0,189,39,
- 24,133,130,143,208,255,189,39,36,0,181,175,
- 1,0,21,36,44,0,191,175,40,0,182,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,82,0,64,24,16,0,176,175,
- 3,131,22,60,216,12,214,38,3,131,2,60,
- 48,13,66,36,128,0,84,36,96,0,83,36,
- 124,0,82,36,120,0,81,36,128,0,16,36,
- 0,0,36,142,0,0,69,142,0,0,198,142,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,55,0,64,20,0,0,0,0,
- 0,0,131,150,0,0,98,150,0,0,0,0,
- 50,0,98,20,0,0,0,0,3,131,4,60,
- 33,32,144,0,28,13,132,140,3,131,5,60,
- 33,40,176,0,32,13,165,140,248,255,198,142,
- 3,131,7,60,212,12,231,140,20,35,192,12,
- 0,0,0,0,37,0,64,16,0,0,0,0,
- 8,0,196,142,3,131,3,60,33,24,112,0,
- 36,13,99,140,0,0,0,0,43,16,131,0,
- 29,0,64,20,0,0,0,0,27,0,131,20,
- 0,0,0,0,0,0,196,142,3,131,5,60,
- 220,12,165,140,0,0,38,142,0,0,71,142,
- 20,35,192,12,0,0,0,0,16,0,64,4,
- 0,0,0,0,0,0,196,142,3,131,5,60,
- 220,12,165,140,0,0,38,142,0,0,71,142,
- 20,35,192,12,0,0,0,0,9,0,64,20,
- 0,0,0,0,0,0,99,150,0,0,130,150,
- 0,0,0,0,43,16,67,0,3,0,64,20,
- 0,0,0,0,22,36,192,12,33,32,160,2,
- 128,0,148,38,128,0,115,38,128,0,82,38,
- 128,0,49,38,24,133,130,143,1,0,181,38,
- 42,16,85,0,185,255,64,16,128,0,16,38,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,216,255,189,39,3,131,4,60,
- 0,13,132,36,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 0,0,130,132,0,0,0,0,14,0,64,16,
- 0,0,0,0,3,131,2,60,2,13,66,148,
- 3,131,3,60,234,12,99,148,1,0,66,36,
- 3,131,1,60,2,13,34,164,255,255,66,48,
- 43,16,67,0,3,0,64,20,0,0,0,0,
- 11,39,192,12,0,0,128,164,3,131,4,60,
- 8,13,132,36,0,0,130,132,0,0,0,0,
- 14,0,64,16,0,0,0,0,3,131,2,60,
- 10,13,66,148,3,131,3,60,234,12,99,148,
- 1,0,66,36,3,131,1,60,10,13,34,164,
- 255,255,66,48,43,16,67,0,3,0,64,20,
- 0,0,0,0,24,39,192,12,0,0,128,164,
- 3,131,4,60,4,13,132,36,0,0,130,132,
- 0,0,0,0,14,0,64,16,0,0,0,0,
- 3,131,2,60,6,13,66,148,3,131,3,60,
- 244,12,99,148,1,0,66,36,3,131,1,60,
- 6,13,34,164,255,255,66,48,43,16,67,0,
- 3,0,64,20,0,0,0,0,37,39,192,12,
- 0,0,128,164,24,133,130,143,0,0,0,0,
- 78,0,64,24,1,0,17,36,3,131,2,60,
- 16,13,66,36,226,0,83,36,128,0,82,36,
- 128,0,16,36,3,131,2,60,33,16,80,0,
- 110,13,66,132,0,0,0,0,18,0,64,16,
- 0,0,0,0,3,131,2,60,33,16,80,0,
- 112,13,66,148,0,0,0,0,1,0,66,36,
- 96,0,66,166,3,131,3,60,236,12,99,148,
- 255,255,66,48,43,16,67,0,6,0,64,20,
- 0,0,0,0,3,131,1,60,33,8,48,0,
- 110,13,32,164,79,39,192,12,33,32,32,2,
- 3,131,2,60,33,16,80,0,106,13,66,132,
- 0,0,0,0,18,0,64,16,0,0,0,0,
- 3,131,2,60,33,16,80,0,108,13,66,148,
- 0,0,0,0,1,0,66,36,92,0,66,166,
- 3,131,3,60,232,12,99,148,255,255,66,48,
- 43,16,67,0,6,0,64,20,0,0,0,0,
- 3,131,1,60,33,8,48,0,106,13,32,164,
- 129,39,192,12,33,32,32,2,0,0,98,134,
- 0,0,0,0,16,0,64,16,0,0,0,0,
- 3,131,2,60,33,16,80,0,116,13,66,148,
- 0,0,0,0,1,0,66,36,100,0,66,166,
- 3,131,3,60,246,12,99,148,255,255,66,48,
- 43,16,67,0,4,0,64,20,0,0,0,0,
- 0,0,96,166,191,39,192,12,33,32,32,2,
- 128,0,115,38,128,0,82,38,24,133,130,143,
- 1,0,49,38,42,16,81,0,185,255,64,16,
- 128,0,16,38,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,232,255,189,39,
- 16,0,191,175,52,36,192,12,0,0,0,0,
- 1,0,2,36,3,131,1,60,0,13,34,164,
- 3,131,1,60,2,13,32,164,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,72,37,192,12,
- 0,0,0,0,1,0,2,36,3,131,1,60,
- 8,13,34,164,3,131,1,60,10,13,32,164,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,240,255,189,39,3,131,1,60,
- 248,12,32,172,3,131,1,60,252,12,32,172,
- 8,0,224,3,16,0,189,39,24,133,130,143,
- 224,255,189,39,20,0,177,175,1,0,17,36,
- 24,0,191,175,23,0,64,24,16,0,176,175,
- 128,0,16,36,3,131,4,60,33,32,144,0,
- 40,13,132,140,3,131,5,60,33,40,176,0,
- 44,13,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,3,0,64,20,1,0,49,38,
- 74,39,192,8,1,0,2,36,24,133,130,143,
- 0,0,0,0,42,16,81,0,236,255,64,16,
- 128,0,16,38,33,16,0,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,192,41,4,0,
- 16,0,191,175,3,131,3,60,33,24,101,0,
- 20,13,99,140,1,0,2,36,16,0,98,20,
- 2,0,2,36,64,26,4,0,3,131,1,60,
- 33,8,37,0,20,13,34,172,2,131,1,60,
- 33,8,35,0,164,247,34,172,1,0,2,36,
- 3,131,1,60,33,8,37,0,110,13,34,164,
- 3,131,1,60,33,8,37,0,125,39,192,8,
- 112,13,32,164,21,0,98,20,3,0,3,36,
- 64,18,4,0,3,131,1,60,33,8,37,0,
- 20,13,35,172,2,131,1,60,33,8,34,0,
- 164,247,35,172,3,131,2,60,33,16,69,0,
- 120,13,66,140,0,0,0,0,1,0,66,36,
- 3,131,1,60,33,8,37,0,44,39,192,12,
- 120,13,34,172,3,0,64,16,0,0,0,0,
- 161,36,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 20,0,177,175,3,131,17,60,208,12,49,38,
- 24,0,191,175,0,0,36,142,3,131,5,60,
- 212,12,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,33,32,0,2,22,36,192,12,
- 1,0,80,44,92,37,192,12,0,0,0,0,
- 206,35,192,12,0,0,0,0,33,0,0,22,
- 0,0,0,0,0,0,36,142,3,131,5,60,
- 212,12,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,22,0,64,20,0,0,0,0,
- 3,131,2,60,238,12,66,148,3,131,3,60,
- 240,12,99,148,3,131,4,60,242,12,132,148,
- 3,131,1,60,232,12,34,164,3,131,1,60,
- 234,12,35,164,3,131,1,60,161,36,192,12,
- 236,12,36,164,3,131,1,60,52,36,192,12,
- 8,13,32,164,1,0,2,36,3,131,1,60,
- 0,13,34,164,3,131,1,60,2,13,32,164,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 192,17,4,0,16,0,191,175,3,131,1,60,
- 33,8,34,0,56,13,34,140,0,0,0,0,
- 3,0,64,16,0,0,0,0,203,36,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,3,131,1,60,
- 248,12,32,172,3,131,1,60,8,0,224,3,
- 8,13,32,164,232,255,189,39,192,25,4,0,
- 1,0,2,36,16,0,191,175,3,131,1,60,
- 33,8,35,0,203,36,192,12,52,13,34,172,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,192,33,4,0,3,131,2,60,
- 28,13,66,36,33,24,130,0,4,0,166,140,
- 8,0,167,140,0,0,102,172,4,0,103,172,
- 12,0,66,36,12,0,163,140,33,16,130,0,
- 3,131,1,60,33,8,36,0,36,13,35,172,
- 16,0,163,140,20,0,166,140,0,0,67,172,
- 4,0,70,172,24,0,163,148,1,0,2,36,
- 3,131,1,60,33,8,36,0,106,13,34,164,
- 3,131,1,60,33,8,36,0,48,13,35,164,
- 26,0,162,148,3,131,1,60,33,8,36,0,
- 8,0,224,3,108,13,34,164,28,0,130,148,
- 3,131,1,60,232,12,34,164,30,0,130,148,
- 3,131,1,60,234,12,34,164,32,0,130,148,
- 3,131,1,60,236,12,34,164,40,0,130,140,
- 3,131,1,60,8,0,224,3,252,12,34,172,
- 224,255,189,39,16,0,176,175,33,128,160,0,
- 192,25,4,0,3,131,2,60,16,13,66,36,
- 20,0,177,175,33,136,98,0,24,0,191,175,
- 4,0,4,142,8,0,5,142,12,0,38,142,
- 16,0,39,142,20,35,192,12,0,0,0,0,
- 48,0,64,4,1,0,2,36,4,0,4,142,
- 8,0,5,142,12,0,38,142,16,0,39,142,
- 20,35,192,12,0,0,0,0,40,0,64,20,
- 33,16,0,0,12,0,4,142,20,0,35,142,
- 0,0,0,0,43,16,131,0,34,0,64,20,
- 1,0,2,36,32,0,131,20,33,16,0,0,
- 16,0,4,142,20,0,5,142,24,0,38,142,
- 28,0,39,142,20,35,192,12,0,0,0,0,
- 24,0,64,4,1,0,2,36,16,0,4,142,
- 20,0,5,142,24,0,38,142,28,0,39,142,
- 20,35,192,12,0,0,0,0,16,0,64,20,
- 33,16,0,0,16,0,4,142,20,0,5,142,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 6,0,64,20,1,0,2,36,24,0,3,150,
- 32,0,34,150,0,0,0,0,43,16,67,0,
- 1,0,66,56,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 44,133,130,143,216,255,189,39,20,0,177,175,
- 33,136,128,0,32,0,180,175,33,160,160,0,
- 36,0,191,175,28,0,179,175,24,0,178,175,
- 53,0,64,16,16,0,176,175,2,131,19,60,
- 192,4,115,38,33,32,96,2,54,21,192,12,
- 1,0,5,36,33,128,64,0,8,0,0,22,
- 64,26,17,0,2,131,2,60,33,16,67,0,
- 176,247,66,140,33,24,99,2,1,0,66,36,
- 143,40,192,8,240,242,98,172,8,0,4,142,
- 64,146,17,0,20,242,101,38,33,40,69,2,
- 172,41,192,12,33,48,128,2,33,24,64,0,
- 60,0,98,40,2,0,64,16,0,242,98,38,
- 60,0,3,36,33,136,66,2,33,32,32,2,
- 33,40,0,2,1,0,2,36,17,0,2,162,
- 0,128,98,52,0,0,2,174,6,23,192,12,
- 18,0,3,166,10,0,64,20,33,32,0,2,
- 2,131,2,60,33,16,82,0,172,247,66,140,
- 0,0,0,0,1,0,66,36,152,21,192,12,
- 236,0,34,174,143,40,192,8,0,0,0,0,
- 2,131,2,60,33,16,82,0,168,247,66,140,
- 0,0,0,0,1,0,66,36,232,0,34,174,
- 36,0,191,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,44,133,130,143,
- 216,255,189,39,20,0,177,175,33,136,128,0,
- 32,0,180,175,33,160,160,0,36,0,191,175,
- 28,0,179,175,24,0,178,175,53,0,64,16,
- 16,0,176,175,2,131,19,60,192,4,115,38,
- 33,32,96,2,54,21,192,12,1,0,5,36,
- 33,128,64,0,8,0,0,22,64,26,17,0,
- 2,131,2,60,33,16,67,0,176,247,66,140,
- 33,24,99,2,1,0,66,36,214,40,192,8,
- 240,242,98,172,8,0,4,142,64,146,17,0,
- 20,242,101,38,33,40,69,2,74,42,192,12,
- 33,48,128,2,33,24,64,0,60,0,98,40,
- 2,0,64,16,0,242,98,38,60,0,3,36,
- 33,136,66,2,33,32,32,2,33,40,0,2,
- 1,0,2,36,17,0,2,162,0,128,98,52,
- 0,0,2,174,6,23,192,12,18,0,3,166,
- 10,0,64,20,33,32,0,2,2,131,2,60,
- 33,16,82,0,172,247,66,140,0,0,0,0,
- 1,0,66,36,152,21,192,12,236,0,34,174,
- 214,40,192,8,0,0,0,0,2,131,2,60,
- 33,16,82,0,168,247,66,140,0,0,0,0,
- 1,0,66,36,232,0,34,174,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,216,255,189,39,24,0,178,175,
- 33,144,128,0,20,0,177,175,33,136,160,0,
- 16,0,176,175,33,128,192,0,36,0,191,175,
- 32,0,180,175,28,0,179,175,4,0,36,142,
- 8,0,37,142,160,133,134,143,2,131,7,60,
- 180,211,231,140,20,35,192,12,0,0,0,0,
- 11,0,64,20,0,0,0,0,2,131,4,60,
- 144,146,132,36,15,63,192,12,33,40,0,2,
- 100,129,132,39,108,129,134,39,31,21,192,12,
- 6,0,5,38,92,41,192,8,0,0,0,0,
- 3,131,20,60,208,12,148,38,0,0,132,142,
- 3,131,5,60,212,12,165,140,3,131,6,60,
- 216,12,198,140,3,131,7,60,220,12,231,140,
- 0,0,0,0,20,35,192,12,192,129,18,0,
- 3,131,3,60,33,24,112,0,20,13,99,140,
- 0,0,0,0,80,0,96,16,1,0,83,44,
- 33,32,64,2,11,40,192,12,33,40,32,2,
- 50,0,64,16,33,32,64,2,223,39,192,12,
- 33,40,32,2,92,37,192,12,0,0,0,0,
- 206,35,192,12,0,0,0,0,0,0,132,142,
- 3,131,5,60,212,12,165,140,3,131,6,60,
- 216,12,198,140,3,131,7,60,220,12,231,140,
- 20,35,192,12,0,0,0,0,16,0,64,16,
- 0,0,0,0,14,0,96,18,0,0,0,0,
- 3,131,2,60,248,12,66,140,3,131,1,60,
- 9,0,64,16,0,13,32,164,3,131,1,60,
- 72,37,192,12,4,13,32,164,1,0,2,36,
- 3,131,1,60,8,13,34,164,3,131,1,60,
- 10,13,32,164,3,131,2,60,228,12,66,140,
- 0,0,0,0,38,0,66,22,0,0,0,0,
- 254,39,192,12,33,32,32,2,52,36,192,12,
- 0,0,0,0,36,0,34,142,0,0,0,0,
- 30,0,64,16,0,0,0,0,206,39,192,12,
- 0,0,0,0,92,41,192,8,0,0,0,0,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 12,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,112,0,48,13,99,148,3,131,2,60,
- 33,16,80,0,16,13,66,148,0,0,0,0,
- 3,0,98,20,0,0,0,0,203,36,192,12,
- 33,32,64,2,36,0,191,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 224,255,189,39,20,0,177,175,33,136,128,0,
- 16,0,176,175,192,129,17,0,24,0,191,175,
- 3,131,2,60,33,16,80,0,20,13,66,140,
- 0,0,0,0,28,0,64,16,0,0,0,0,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 14,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,112,0,48,13,99,148,3,131,2,60,
- 33,16,80,0,16,13,66,148,0,0,0,0,
- 5,0,98,20,0,0,0,0,161,36,192,12,
- 0,0,0,0,211,39,192,12,33,32,32,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,2,18,5,0,
- 0,0,130,160,8,0,224,3,1,0,133,160,
- 2,22,5,0,0,0,130,160,2,20,5,0,
- 1,0,130,160,2,18,5,0,2,0,130,160,
- 8,0,224,3,3,0,133,160,0,0,130,144,
- 1,0,131,144,0,18,2,0,8,0,224,3,
- 37,16,98,0,0,0,130,144,1,0,131,144,
- 2,0,133,144,0,22,2,0,0,28,3,0,
- 33,16,67,0,0,42,5,0,3,0,131,144,
- 33,16,69,0,8,0,224,3,37,16,67,0,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 24,0,191,175,20,0,177,175,48,129,135,39,
- 3,0,226,136,0,0,226,152,4,0,227,128,
- 5,0,228,128,3,0,2,170,0,0,2,186,
- 4,0,3,162,5,0,4,162,3,0,162,136,
- 0,0,162,152,4,0,163,128,5,0,164,128,
- 9,0,2,170,6,0,2,186,10,0,3,162,
- 11,0,4,162,12,0,4,38,38,0,5,36,
- 144,41,192,12,33,136,192,0,14,0,4,38,
- 144,41,192,12,66,66,5,36,17,0,4,38,
- 33,40,0,0,3,0,2,36,144,41,192,12,
- 16,0,2,162,19,0,0,162,20,0,0,162,
- 40,0,34,142,0,0,0,0,43,32,2,0,
- 36,0,34,142,0,0,0,0,3,0,64,16,
- 33,24,128,0,218,41,192,8,128,0,130,52,
- 33,16,96,0,21,0,2,162,4,0,37,150,
- 0,0,0,0,144,41,192,12,22,0,4,38,
- 9,0,34,138,6,0,34,154,10,0,35,130,
- 11,0,36,130,27,0,2,170,24,0,2,186,
- 28,0,3,162,29,0,4,162,12,0,37,142,
- 0,0,0,0,148,41,192,12,30,0,4,38,
- 16,0,37,150,0,0,0,0,144,41,192,12,
- 34,0,4,38,21,0,34,138,18,0,34,154,
- 22,0,35,130,23,0,36,130,39,0,2,170,
- 36,0,2,186,40,0,3,162,41,0,4,162,
- 24,0,37,150,0,0,0,0,144,41,192,12,
- 42,0,4,38,26,0,37,150,0,0,0,0,
- 144,41,192,12,44,0,4,38,28,0,37,150,
- 0,0,0,0,144,41,192,12,46,0,4,38,
- 30,0,37,150,0,0,0,0,144,41,192,12,
- 48,0,4,38,32,0,37,150,0,0,0,0,
- 144,41,192,12,50,0,4,38,52,0,2,36,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,224,255,189,39,
- 16,0,176,175,33,128,160,0,24,0,191,175,
- 20,0,177,175,21,0,2,146,33,136,128,0,
- 1,0,66,48,40,0,34,174,22,0,2,146,
- 22,0,4,38,128,0,66,48,156,41,192,12,
- 36,0,34,174,4,0,34,166,27,0,2,138,
- 24,0,2,154,28,0,3,130,29,0,4,130,
- 9,0,34,170,6,0,34,186,10,0,35,162,
- 11,0,36,162,161,41,192,12,30,0,4,38,
- 34,0,4,38,156,41,192,12,12,0,34,174,
- 16,0,34,166,39,0,2,138,36,0,2,154,
- 40,0,3,130,41,0,4,130,21,0,34,170,
- 18,0,34,186,22,0,35,162,23,0,36,162,
- 156,41,192,12,42,0,4,38,44,0,4,38,
- 156,41,192,12,24,0,34,166,46,0,4,38,
- 156,41,192,12,26,0,34,166,48,0,4,38,
- 156,41,192,12,28,0,34,166,50,0,4,38,
- 156,41,192,12,30,0,34,166,32,0,34,166,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 16,0,176,175,33,128,128,0,20,0,191,175,
- 48,129,134,39,3,0,194,136,0,0,194,152,
- 4,0,195,128,5,0,196,128,3,0,2,170,
- 0,0,2,186,4,0,3,162,5,0,4,162,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,164,128,9,0,2,170,6,0,2,186,
- 10,0,3,162,11,0,4,162,12,0,4,38,
- 144,41,192,12,7,0,5,36,14,0,4,38,
- 144,41,192,12,66,66,5,36,17,0,4,38,
- 33,40,0,0,3,0,2,36,144,41,192,12,
- 16,0,2,162,21,0,2,36,128,0,3,36,
- 19,0,0,162,20,0,3,162,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 176,255,189,39,68,0,177,175,64,0,176,175,
- 33,128,160,0,72,0,191,175,14,0,3,146,
- 66,0,2,36,9,0,98,20,33,136,128,0,
- 15,0,2,146,0,0,0,0,6,0,67,20,
- 64,26,17,0,16,0,3,146,3,0,2,36,
- 11,0,98,16,0,0,0,0,64,26,17,0,
- 2,131,2,60,33,16,67,0,184,247,66,140,
- 0,0,0,0,1,0,66,36,2,131,1,60,
- 33,8,35,0,182,42,192,8,184,247,34,172,
- 20,0,3,146,0,0,0,0,5,0,96,16,
- 128,0,2,36,21,0,98,16,64,26,17,0,
- 179,42,192,8,0,0,0,0,16,0,164,39,
- 64,26,17,0,2,131,2,60,33,16,67,0,
- 180,247,66,140,0,0,0,0,1,0,66,36,
- 2,131,1,60,33,8,35,0,180,247,34,172,
- 17,42,192,12,33,40,0,2,33,32,32,2,
- 16,0,165,39,222,40,192,12,33,48,0,2,
- 182,42,192,8,0,0,0,0,2,131,2,60,
- 33,16,67,0,180,247,66,140,0,0,0,0,
- 1,0,66,36,2,131,1,60,33,8,35,0,
- 180,247,34,172,100,41,192,12,33,32,32,2,
- 182,42,192,8,0,0,0,0,112,129,132,39,
- 15,63,192,12,0,0,0,0,72,0,191,143,
- 68,0,177,143,64,0,176,143,8,0,224,3,
- 80,0,189,39,8,0,224,3,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,162,48,8,0,64,16,255,255,198,48,
- 67,40,5,0,64,16,5,0,33,16,68,0,
- 0,0,66,144,0,0,0,0,203,42,192,8,
- 33,48,194,0,67,40,5,0,255,255,165,36,
- 255,255,2,36,6,0,162,16,255,255,3,36,
- 0,0,130,148,2,0,132,36,255,255,165,36,
- 252,255,163,20,33,48,194,0,255,255,195,48,
- 2,20,6,0,33,48,98,0,255,255,195,48,
- 2,20,6,0,33,48,98,0,8,0,224,3,
- 255,255,194,48,208,255,189,39,16,0,176,175,
- 33,128,128,0,28,0,179,175,33,152,160,0,
- 24,0,178,175,33,144,192,0,36,0,181,175,
- 33,168,0,2,32,0,180,175,33,160,0,0,
- 40,0,191,175,20,0,177,175,12,0,3,142,
- 0,0,2,142,0,0,0,0,35,24,98,0,
- 42,16,114,0,2,0,64,16,33,136,64,2,
- 33,136,96,0,13,0,32,18,33,40,96,2,
- 35,144,81,2,8,0,2,142,0,0,4,142,
- 33,48,32,2,80,68,192,12,33,32,68,0,
- 8,0,2,142,0,0,2,142,0,0,2,142,
- 33,152,113,2,33,16,81,0,0,0,2,174,
- 0,0,2,142,0,0,0,0,4,0,64,18,
- 33,160,130,2,4,0,16,142,233,42,192,8,
- 0,0,0,0,18,0,180,166,33,16,0,2,
- 40,0,191,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,24,0,178,175,33,144,128,0,
- 2,131,4,60,192,4,132,36,36,0,165,175,
- 1,0,5,36,28,0,191,175,20,0,177,175,
- 54,21,192,12,16,0,176,175,33,136,64,0,
- 8,0,32,22,33,40,0,0,2,131,2,60,
- 176,5,66,140,0,0,0,0,1,0,66,36,
- 2,131,1,60,102,43,192,8,176,5,34,172,
- 0,1,3,36,8,0,48,142,8,0,2,36,
- 16,0,2,166,6,0,2,36,18,0,2,162,
- 4,0,2,36,14,0,3,166,19,0,2,162,
- 20,0,3,166,2,131,6,60,212,4,198,36,
- 3,0,194,136,0,0,194,152,4,0,195,132,
- 25,0,2,170,22,0,2,186,26,0,3,166,
- 2,131,1,60,195,211,34,136,176,133,130,155,
- 0,0,0,0,31,0,2,170,28,0,2,186,
- 32,0,4,38,144,71,192,12,6,0,6,36,
- 39,0,162,139,36,0,162,155,0,0,0,0,
- 41,0,2,170,38,0,2,186,132,129,133,39,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,164,128,3,0,2,170,0,0,2,186,
- 4,0,3,162,5,0,4,162,2,131,5,60,
- 212,4,165,36,3,0,162,136,0,0,162,152,
- 4,0,163,128,5,0,164,128,9,0,2,170,
- 6,0,2,186,10,0,3,162,11,0,4,162,
- 33,32,64,2,8,6,2,36,12,0,2,166,
- 60,128,2,52,0,0,34,174,60,0,2,36,
- 18,0,34,166,74,21,192,12,33,40,32,2,
- 3,0,64,20,0,0,0,0,152,21,192,12,
- 33,32,32,2,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,216,255,189,39,32,0,180,175,
- 33,160,128,0,16,0,176,175,33,128,160,0,
- 36,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,8,0,2,142,33,152,192,0,
- 33,136,83,0,6,0,35,150,0,1,4,36,
- 5,0,100,16,0,2,2,36,113,0,98,16,
- 0,0,0,0,15,44,192,8,0,0,0,0,
- 24,0,35,150,176,133,130,151,0,0,0,0,
- 139,0,98,20,0,0,0,0,26,0,35,150,
- 2,131,2,60,194,211,66,148,0,0,0,0,
- 133,0,98,20,0,0,0,0,0,0,34,150,
- 0,0,0,0,129,0,68,20,8,0,2,36,
- 2,0,35,150,0,0,0,0,125,0,98,20,
- 6,4,2,36,4,0,35,150,0,0,0,0,
- 121,0,98,20,0,0,0,0,2,131,4,60,
- 192,4,132,36,54,21,192,12,1,0,5,36,
- 33,144,64,0,8,0,64,22,0,0,0,0,
- 2,131,2,60,176,5,66,140,0,0,0,0,
- 1,0,66,36,2,131,1,60,15,44,192,8,
- 176,5,34,172,8,0,5,142,8,0,80,142,
- 9,0,162,136,6,0,162,152,10,0,163,128,
- 11,0,164,128,3,0,2,170,0,0,2,186,
- 4,0,3,162,5,0,4,162,2,131,6,60,
- 212,4,198,36,3,0,194,136,0,0,194,152,
- 4,0,195,128,5,0,196,128,9,0,2,170,
- 6,0,2,186,10,0,3,162,11,0,4,162,
- 12,0,4,38,12,0,165,36,33,128,19,2,
- 80,68,192,12,244,255,102,38,0,1,2,36,
- 0,0,2,166,8,0,2,36,2,0,2,166,
- 6,0,2,36,4,0,2,162,4,0,2,36,
- 5,0,2,162,0,2,2,36,6,0,2,166,
- 2,131,5,60,212,4,165,36,3,0,162,136,
- 0,0,162,152,4,0,163,132,11,0,2,170,
- 8,0,2,186,12,0,3,166,2,131,1,60,
- 195,211,34,136,176,133,130,155,0,0,0,0,
- 17,0,2,170,14,0,2,186,11,0,34,138,
- 8,0,34,154,12,0,35,134,21,0,2,170,
- 18,0,2,186,22,0,3,166,17,0,34,138,
- 14,0,34,154,0,0,0,0,27,0,2,170,
- 24,0,2,186,33,32,128,2,33,40,64,2,
- 60,128,2,52,0,0,66,174,60,0,2,36,
- 74,21,192,12,18,0,66,166,38,0,64,20,
- 0,0,0,0,152,21,192,12,33,32,64,2,
- 15,44,192,8,0,0,0,0,14,0,35,150,
- 196,133,130,151,0,0,0,0,29,0,98,20,
- 0,0,0,0,16,0,35,150,2,131,2,60,
- 214,211,66,148,0,0,0,0,23,0,98,20,
- 0,0,0,0,0,0,34,150,0,0,0,0,
- 19,0,68,20,8,0,2,36,2,0,35,150,
- 0,0,0,0,15,0,98,20,6,4,2,36,
- 4,0,35,150,0,0,0,0,11,0,98,20,
- 0,0,0,0,68,133,130,143,140,129,134,39,
- 11,0,35,138,8,0,35,154,12,0,36,134,
- 3,0,195,168,0,0,195,184,4,0,196,164,
- 20,0,66,36,152,129,130,175,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,192,255,189,39,80,0,169,143,
- 84,0,168,143,56,0,180,175,33,160,128,0,
- 44,0,177,175,88,0,177,143,16,0,164,39,
- 52,0,179,175,92,0,179,143,3,131,3,60,
- 32,17,99,36,40,0,176,175,33,128,192,0,
- 60,0,191,175,48,0,178,175,0,0,98,140,
- 8,0,50,142,1,0,66,36,0,0,98,172,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,170,128,3,0,66,170,0,0,66,186,
- 4,0,67,162,5,0,74,162,2,131,10,60,
- 212,4,74,37,3,0,66,137,0,0,66,153,
- 4,0,67,129,5,0,69,129,9,0,66,170,
- 6,0,66,186,10,0,67,162,11,0,69,162,
- 69,0,2,36,16,0,162,163,17,0,168,163,
- 18,0,34,150,240,132,131,143,33,48,0,0,
- 25,0,169,163,20,0,66,36,0,66,2,0,
- 255,255,66,48,2,18,2,0,37,64,2,1,
- 0,74,3,0,255,255,98,48,2,18,2,0,
- 37,72,34,1,3,131,2,60,0,17,66,140,
- 22,0,160,167,26,0,160,167,18,0,168,167,
- 176,133,136,143,1,0,99,36,240,132,131,175,
- 20,0,169,167,24,0,162,163,28,0,168,175,
- 3,0,226,136,0,0,226,152,0,0,0,0,
- 35,0,162,171,32,0,162,187,192,42,192,12,
- 20,0,5,36,39,16,2,0,26,0,162,167,
- 14,0,2,36,44,0,2,22,8,0,2,36,
- 12,0,66,166,19,0,162,139,16,0,162,155,
- 23,0,163,139,20,0,163,155,27,0,164,139,
- 24,0,164,155,31,0,165,139,28,0,165,155,
- 17,0,66,170,14,0,66,186,21,0,67,170,
- 18,0,67,186,25,0,68,170,22,0,68,186,
- 29,0,69,170,26,0,69,186,35,0,162,139,
- 32,0,162,155,0,0,0,0,33,0,66,170,
- 30,0,66,186,34,0,2,36,0,0,34,174,
- 0,0,35,142,18,0,34,150,0,0,0,0,
- 33,16,67,0,18,0,34,166,18,0,34,150,
- 0,0,0,0,60,0,66,44,68,0,64,16,
- 33,32,128,2,0,0,98,142,18,0,35,150,
- 60,0,66,36,35,16,67,0,0,0,98,174,
- 60,0,2,36,18,0,34,166,201,44,192,8,
- 33,32,128,2,164,129,133,39,3,0,162,136,
- 0,0,162,152,4,0,163,128,5,0,164,128,
- 17,0,66,170,14,0,66,186,18,0,67,162,
- 19,0,68,162,8,0,2,36,20,0,66,166,
- 19,0,162,139,16,0,162,155,23,0,163,139,
- 20,0,163,155,27,0,164,139,24,0,164,155,
- 31,0,165,139,28,0,165,155,25,0,66,170,
- 22,0,66,186,29,0,67,170,26,0,67,186,
- 33,0,68,170,30,0,68,186,37,0,69,170,
- 34,0,69,186,35,0,162,139,32,0,162,155,
- 0,0,0,0,41,0,66,170,38,0,66,186,
- 42,0,2,36,0,0,34,174,0,0,35,142,
- 18,0,34,150,0,0,0,0,33,16,67,0,
- 18,0,34,166,18,0,34,150,0,0,0,0,
- 60,0,66,44,8,0,64,16,0,0,0,0,
- 0,0,98,142,18,0,35,150,60,0,66,36,
- 35,16,67,0,0,0,98,174,60,0,2,36,
- 18,0,34,166,18,0,34,150,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 12,0,67,166,33,32,128,2,74,21,192,12,
- 33,40,32,2,8,0,64,20,33,32,32,2,
- 3,131,3,60,36,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,152,21,192,12,
- 0,0,98,172,60,0,191,143,56,0,180,143,
- 52,0,179,143,48,0,178,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,64,0,189,39,
- 176,255,189,39,56,0,180,175,112,0,180,143,
- 48,0,178,175,100,0,178,143,52,0,179,175,
- 104,0,179,143,64,0,182,175,33,176,128,0,
- 72,0,190,175,33,240,160,0,60,0,181,175,
- 33,168,224,0,68,0,183,175,108,0,183,143,
- 2,131,4,60,192,4,132,36,76,0,191,175,
- 44,0,177,175,40,0,176,175,32,0,166,175,
- 7,2,130,38,2,130,2,0,54,21,192,12,
- 33,40,0,2,33,136,64,0,8,0,32,22,
- 0,74,18,0,2,131,4,60,232,146,132,36,
- 33,40,128,2,15,63,192,12,33,48,0,2,
- 74,45,192,8,0,0,0,0,255,255,66,50,
- 2,18,2,0,37,72,34,1,0,66,19,0,
- 255,255,98,50,2,18,2,0,37,64,2,1,
- 8,0,130,38,0,58,2,0,255,255,66,48,
- 2,18,2,0,37,56,226,0,0,163,4,60,
- 220,5,132,52,4,0,5,36,4,0,34,142,
- 0,17,6,36,8,0,80,140,4,0,35,142,
- 8,0,2,36,0,0,98,172,0,0,9,166,
- 2,0,8,166,6,0,0,166,192,42,192,12,
- 4,0,7,166,33,32,160,2,4,0,5,36,
- 192,42,192,12,255,255,70,48,4,0,4,38,
- 2,0,5,36,192,42,192,12,255,255,70,48,
- 33,32,0,2,8,0,5,36,192,42,192,12,
- 255,255,70,48,33,32,224,2,33,40,128,2,
- 192,42,192,12,255,255,70,48,39,24,2,0,
- 255,255,98,48,2,0,64,20,33,40,224,2,
- 255,255,3,52,6,0,3,166,4,0,36,142,
- 0,0,0,0,220,42,192,12,33,48,128,2,
- 33,32,192,2,0,0,67,140,33,40,192,3,
- 0,128,99,52,0,0,67,172,4,0,35,142,
- 32,0,166,143,18,0,99,148,33,56,160,2,
- 18,0,35,166,96,0,170,143,17,0,3,36,
- 16,0,163,175,24,0,177,175,28,0,162,175,
- 23,44,192,12,20,0,170,175,3,131,3,60,
- 124,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,76,0,191,143,
- 72,0,190,143,68,0,183,143,64,0,182,143,
- 60,0,181,143,56,0,180,143,52,0,179,143,
- 48,0,178,143,44,0,177,143,40,0,176,143,
- 8,0,224,3,80,0,189,39,128,255,189,39,
- 116,0,183,175,33,184,128,0,112,0,182,175,
- 33,176,160,0,104,0,180,175,33,160,192,0,
- 108,0,181,175,33,168,224,0,40,0,164,39,
- 96,0,178,175,144,0,178,143,33,40,0,0,
- 100,0,179,175,148,0,179,143,16,0,6,36,
- 120,0,191,175,92,0,177,175,144,71,192,12,
- 88,0,176,175,56,0,177,39,33,32,32,2,
- 33,40,0,0,2,0,16,36,40,0,176,167,
- 2,0,162,150,0,0,0,0,42,0,162,167,
- 19,0,130,138,16,0,130,154,0,0,0,0,
- 47,0,162,171,44,0,162,187,144,71,192,12,
- 16,0,6,36,33,32,64,2,33,40,96,2,
- 40,0,166,39,33,56,32,2,56,0,176,167,
- 0,0,162,150,2,131,16,60,8,239,16,38,
- 58,0,162,167,15,0,130,138,12,0,130,154,
- 0,0,0,0,63,0,162,171,60,0,162,187,
- 242,5,2,36,84,0,162,167,72,0,162,39,
- 72,0,160,167,76,0,176,175,80,0,176,175,
- 247,71,192,12,16,0,162,175,255,255,3,36,
- 22,0,67,16,12,0,145,38,33,32,224,2,
- 6,0,197,38,35,48,150,2,0,0,163,150,
- 4,0,2,36,16,0,162,175,161,0,2,36,
- 20,0,162,175,28,0,176,175,0,18,3,0,
- 2,26,3,0,37,16,67,0,255,255,66,48,
- 24,0,162,175,80,0,162,143,76,0,163,143,
- 33,56,32,2,35,16,67,0,255,255,66,48,
- 220,44,192,12,32,0,162,175,120,0,191,143,
- 116,0,183,143,112,0,182,143,108,0,181,143,
- 104,0,180,143,100,0,179,143,96,0,178,143,
- 92,0,177,143,88,0,176,143,8,0,224,3,
- 128,0,189,39,196,133,130,143,184,255,189,39,
- 64,0,191,175,60,0,177,175,109,0,64,16,
- 56,0,176,175,255,255,3,36,106,0,67,16,
- 0,0,0,0,176,133,130,143,176,133,145,39,
- 102,0,64,16,0,0,0,0,100,0,67,16,
- 0,0,0,0,2,131,2,60,8,239,66,36,
- 44,0,162,175,48,0,162,175,242,5,2,36,
- 40,0,160,167,6,0,128,16,52,0,162,167,
- 1,0,2,36,23,0,130,16,0,0,0,0,
- 36,46,192,8,0,0,0,0,2,131,16,60,
- 160,204,16,38,156,71,192,12,33,32,0,2,
- 0,163,4,60,4,1,132,140,204,204,3,60,
- 205,204,99,52,25,0,131,0,33,40,32,2,
- 33,48,0,2,33,56,64,0,40,0,164,39,
- 16,64,0,0,194,16,8,0,0,0,0,0,
- 104,56,192,12,16,0,162,175,251,45,192,8,
- 33,24,64,0,3,131,2,60,28,18,66,148,
- 0,0,0,0,2,0,66,48,61,0,64,16,
- 0,0,0,0,2,131,16,60,160,204,16,38,
- 156,71,192,12,33,32,0,2,0,163,4,60,
- 4,1,132,140,204,204,3,60,205,204,99,52,
- 25,0,131,0,33,40,32,2,33,48,0,2,
- 33,56,64,0,40,0,164,39,16,64,0,0,
- 194,16,8,0,0,0,0,0,105,57,192,12,
- 16,0,162,175,33,24,64,0,255,255,2,36,
- 39,0,98,16,0,0,0,0,140,129,130,147,
- 0,0,0,0,1,0,66,48,7,0,64,20,
- 0,0,0,0,68,133,131,143,152,129,130,143,
- 0,0,0,0,43,16,67,0,11,0,64,16,
- 33,32,0,0,68,133,131,143,148,129,130,143,
- 0,0,0,0,6,0,98,16,33,32,0,0,
- 196,133,133,143,148,129,131,175,17,43,192,12,
- 33,32,0,0,33,32,0,0,140,129,133,39,
- 14,0,6,36,4,0,2,36,16,0,162,175,
- 162,0,2,36,20,0,162,175,24,0,162,175,
- 2,131,2,60,8,239,66,36,28,0,162,175,
- 48,0,162,143,44,0,163,143,196,133,135,39,
- 35,16,67,0,255,255,66,48,220,44,192,12,
- 32,0,162,175,64,0,191,143,60,0,177,143,
- 56,0,176,143,8,0,224,3,72,0,189,39,
- 208,255,189,39,36,0,179,175,33,152,128,0,
- 40,0,180,175,33,160,160,0,32,0,178,175,
- 24,0,176,175,33,128,224,0,44,0,191,175,
- 28,0,177,175,6,0,2,150,64,0,177,143,
- 0,0,0,0,20,0,64,16,33,144,192,0,
- 12,0,68,38,8,0,5,36,192,42,192,12,
- 0,17,6,36,4,0,4,38,2,0,5,36,
- 192,42,192,12,255,255,70,48,33,32,0,2,
- 33,40,32,2,192,42,192,12,255,255,70,48,
- 255,255,66,48,255,255,3,52,4,0,67,16,
- 0,0,0,0,3,131,3,60,111,46,192,8,
- 120,17,99,36,4,0,2,150,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 255,255,99,48,4,0,113,16,8,0,7,38,
- 3,131,3,60,111,46,192,8,120,17,99,36,
- 2,0,2,150,0,0,0,0,0,26,2,0,
- 2,18,2,0,37,24,98,0,255,255,99,48,
- 161,0,2,36,15,0,98,20,248,255,40,38,
- 33,32,96,2,33,40,128,2,3,131,3,60,
- 112,17,99,36,0,0,98,140,33,48,64,2,
- 16,0,167,175,33,56,0,2,20,0,168,175,
- 1,0,66,36,86,45,192,12,0,0,98,172,
- 115,46,192,8,0,0,0,0,3,131,3,60,
- 116,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,44,0,191,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 48,0,189,39,192,255,189,39,52,0,181,175,
- 33,168,128,0,44,0,179,175,33,152,160,0,
- 48,0,180,175,33,160,192,0,32,0,176,175,
- 33,128,224,0,33,32,0,2,33,48,0,0,
- 40,0,178,175,80,0,178,143,3,131,3,60,
- 144,16,99,36,56,0,191,175,36,0,177,175,
- 0,0,98,140,33,40,64,2,1,0,66,36,
- 192,42,192,12,0,0,98,172,255,255,66,48,
- 255,255,3,52,8,0,67,16,8,0,2,36,
- 3,131,2,60,148,16,66,140,0,0,0,0,
- 1,0,66,36,3,131,1,60,217,46,192,8,
- 148,16,34,172,0,0,3,150,0,0,0,0,
- 58,0,98,20,255,1,69,38,2,131,4,60,
- 192,4,132,36,3,131,2,60,172,16,66,140,
- 3,131,3,60,196,16,99,140,1,0,66,36,
- 1,0,99,36,3,131,1,60,172,16,34,172,
- 3,131,1,60,196,16,35,172,54,21,192,12,
- 2,42,5,0,33,136,64,0,8,0,32,22,
- 33,32,0,2,3,131,2,60,200,16,66,140,
- 0,0,0,0,1,0,66,36,3,131,1,60,
- 217,46,192,8,200,16,34,172,33,40,64,2,
- 33,48,0,0,0,0,0,162,192,42,192,12,
- 2,0,0,166,33,40,0,2,39,16,2,0,
- 2,0,162,164,4,0,36,142,0,0,0,0,
- 220,42,192,12,33,48,64,2,33,32,160,2,
- 6,0,101,38,35,48,147,2,0,0,67,140,
- 12,0,135,38,0,128,99,52,0,0,67,172,
- 1,0,3,36,18,0,50,166,16,0,163,175,
- 4,0,3,36,20,0,163,175,24,0,177,175,
- 23,44,192,12,28,0,162,175,3,131,2,60,
- 228,16,66,140,0,0,0,0,1,0,66,36,
- 3,131,1,60,228,16,34,172,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,200,255,189,39,
- 44,0,181,175,33,168,128,0,3,131,3,60,
- 4,17,99,36,48,0,191,175,40,0,180,175,
- 36,0,179,175,32,0,178,175,28,0,177,175,
- 24,0,176,175,0,0,98,140,33,136,160,0,
- 1,0,66,36,0,0,98,172,18,0,34,150,
- 0,0,0,0,255,255,84,48,243,5,130,46,
- 8,0,64,20,33,152,192,0,3,131,2,60,
- 8,17,66,140,0,0,0,0,1,0,66,36,
- 3,131,1,60,132,47,192,8,8,17,34,172,
- 2,131,18,60,18,233,82,38,33,32,64,2,
- 0,0,48,142,8,0,37,142,255,63,16,50,
- 80,68,192,12,33,48,0,2,0,0,34,142,
- 0,0,0,0,0,128,66,48,5,0,64,20,
- 33,144,80,2,4,0,49,142,0,0,0,0,
- 1,47,192,8,33,32,64,2,2,131,18,60,
- 18,233,82,38,33,128,114,2,16,0,17,38,
- 33,32,32,2,176,133,133,39,168,71,192,12,
- 4,0,6,36,9,0,64,16,33,32,32,2,
- 128,129,133,39,168,71,192,12,4,0,6,36,
- 4,0,64,16,0,0,0,0,3,131,3,60,
- 128,47,192,8,12,17,99,36,0,0,4,146,
- 64,0,2,36,240,0,131,48,4,0,98,16,
- 15,0,130,48,3,131,3,60,128,47,192,8,
- 8,17,99,36,128,136,2,0,20,0,34,42,
- 4,0,64,16,33,32,0,2,3,131,3,60,
- 128,47,192,8,8,17,99,36,33,40,32,2,
- 192,42,192,12,33,48,0,0,255,255,66,48,
- 255,255,3,52,4,0,67,16,0,0,0,0,
- 3,131,3,60,128,47,192,8,8,17,99,36,
- 6,0,2,150,0,0,0,0,63,255,66,48,
- 18,0,64,16,33,56,17,2,3,131,3,60,
- 48,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,3,131,2,60,
- 56,17,66,140,3,131,3,60,24,17,99,140,
- 1,0,66,36,1,0,99,36,3,131,1,60,
- 56,17,34,172,3,131,1,60,132,47,192,8,
- 24,17,35,172,2,0,2,150,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 255,255,99,48,35,64,113,0,35,16,242,0,
- 35,16,130,2,42,16,72,0,4,0,64,16,
- 1,0,2,36,3,131,3,60,128,47,192,8,
- 24,17,99,36,9,0,3,146,0,0,0,0,
- 5,0,98,16,17,0,2,36,15,0,98,16,
- 33,32,160,2,126,47,192,8,0,0,0,0,
- 33,32,160,2,33,40,64,2,3,131,3,60,
- 28,17,99,36,0,0,98,140,33,48,0,2,
- 16,0,168,175,1,0,66,36,123,46,192,12,
- 0,0,98,172,132,47,192,8,0,0,0,0,
- 33,40,64,2,3,131,3,60,28,17,99,36,
- 0,0,98,140,33,48,0,2,16,0,168,175,
- 1,0,66,36,41,46,192,12,0,0,98,172,
- 132,47,192,8,0,0,0,0,3,131,3,60,
- 20,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,48,0,191,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,232,255,189,39,
- 255,0,12,60,255,0,140,53,0,255,13,60,
- 0,255,173,53,16,0,176,175,3,131,16,60,
- 0,17,16,38,33,32,0,2,33,40,0,0,
- 0,163,9,60,220,5,41,141,0,163,10,60,
- 16,6,74,141,0,163,11,60,224,5,107,141,
- 20,0,191,175,0,28,9,0,2,20,9,0,
- 37,24,98,0,0,60,10,0,2,20,10,0,
- 37,56,226,0,0,68,11,0,2,20,11,0,
- 37,64,2,1,2,18,3,0,36,16,76,0,
- 0,26,3,0,36,24,109,0,37,16,67,0,
- 184,133,130,175,2,18,7,0,36,16,76,0,
- 0,58,7,0,36,56,237,0,37,16,71,0,
- 192,133,130,175,2,18,8,0,36,16,76,0,
- 0,66,8,0,36,64,13,1,37,16,72,0,
- 176,133,137,175,196,133,138,175,188,133,139,175,
- 180,133,130,175,144,71,192,12,76,0,6,36,
- 3,131,4,60,144,16,132,36,33,40,0,0,
- 32,0,2,36,0,0,2,174,10,0,2,36,
- 3,131,1,60,44,17,34,172,144,71,192,12,
- 104,0,6,36,3,131,4,60,112,17,132,36,
- 33,40,0,0,144,71,192,12,16,0,6,36,
- 3,131,4,60,80,17,132,36,33,40,0,0,
- 144,71,192,12,32,0,6,36,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 176,255,189,39,100,0,162,143,96,0,169,143,
- 72,0,182,175,33,176,128,0,48,0,176,175,
- 104,0,176,143,34,0,164,39,60,0,179,175,
- 108,0,179,143,3,131,3,60,104,17,99,36,
- 56,0,178,175,2,131,18,60,212,4,82,38,
- 52,0,177,175,33,136,192,0,68,0,181,175,
- 112,0,181,143,4,0,6,36,76,0,191,175,
- 64,0,180,175,0,66,2,0,255,255,66,48,
- 2,18,2,0,37,64,2,1,0,0,98,140,
- 8,0,116,142,1,0,66,36,0,0,98,172,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,170,128,3,0,130,170,0,0,130,186,
- 4,0,131,162,5,0,138,162,3,0,66,138,
- 0,0,66,154,4,0,67,130,5,0,69,130,
- 9,0,130,170,6,0,130,186,10,0,131,162,
- 11,0,133,162,255,255,2,52,16,0,162,167,
- 18,0,98,150,33,40,0,0,20,0,160,163,
- 21,0,160,163,30,0,66,36,0,26,2,0,
- 255,255,66,48,2,18,2,0,37,24,98,0,
- 18,0,163,167,3,0,226,136,0,0,226,152,
- 0,0,0,0,25,0,162,171,22,0,162,187,
- 3,0,34,137,0,0,34,153,4,0,35,129,
- 5,0,39,129,29,0,162,171,26,0,162,187,
- 30,0,163,163,31,0,167,163,144,71,192,12,
- 32,0,168,167,3,0,66,138,0,0,66,154,
- 4,0,67,134,41,0,162,171,38,0,162,187,
- 42,0,163,167,33,16,0,2,0,130,16,0,
- 255,255,66,48,2,18,2,0,37,128,2,2,
- 14,0,2,36,58,0,34,22,44,0,176,167,
- 18,0,162,151,0,0,0,0,12,0,130,166,
- 19,0,162,139,16,0,162,155,23,0,163,139,
- 20,0,163,155,27,0,164,139,24,0,164,155,
- 31,0,165,139,28,0,165,155,17,0,130,170,
- 14,0,130,186,21,0,131,170,18,0,131,186,
- 25,0,132,170,22,0,132,186,29,0,133,170,
- 26,0,133,186,35,0,162,139,32,0,162,155,
- 39,0,163,139,36,0,163,155,43,0,164,139,
- 40,0,164,155,44,0,165,131,33,0,130,170,
- 30,0,130,186,37,0,131,170,34,0,131,186,
- 41,0,132,170,38,0,132,186,42,0,133,162,
- 45,0,162,131,0,0,0,0,43,0,130,162,
- 44,0,2,36,0,0,98,174,0,0,99,142,
- 18,0,98,150,0,0,0,0,33,16,67,0,
- 18,0,98,166,18,0,98,150,0,0,0,0,
- 60,0,66,44,80,0,64,16,33,32,192,2,
- 0,0,162,142,18,0,99,150,60,0,66,36,
- 35,16,67,0,0,0,162,174,60,0,2,36,
- 18,0,98,166,172,48,192,8,33,32,192,2,
- 208,129,133,39,3,0,162,136,0,0,162,152,
- 4,0,163,128,5,0,164,128,17,0,130,170,
- 14,0,130,186,18,0,131,162,19,0,132,162,
- 129,55,2,36,20,0,130,166,19,0,162,139,
- 16,0,162,155,23,0,163,139,20,0,163,155,
- 27,0,164,139,24,0,164,155,31,0,165,139,
- 28,0,165,155,25,0,130,170,22,0,130,186,
- 29,0,131,170,26,0,131,186,33,0,132,170,
- 30,0,132,186,37,0,133,170,34,0,133,186,
- 35,0,162,139,32,0,162,155,39,0,163,139,
- 36,0,163,155,43,0,164,139,40,0,164,155,
- 44,0,165,131,41,0,130,170,38,0,130,186,
- 45,0,131,170,42,0,131,186,49,0,132,170,
- 46,0,132,186,50,0,133,162,45,0,162,131,
- 0,0,0,0,51,0,130,162,52,0,2,36,
- 0,0,98,174,0,0,99,142,18,0,98,150,
- 0,0,0,0,33,16,67,0,18,0,98,166,
- 18,0,98,150,0,0,0,0,60,0,66,44,
- 8,0,64,16,0,0,0,0,0,0,162,142,
- 18,0,99,150,60,0,66,36,35,16,67,0,
- 0,0,162,174,60,0,2,36,18,0,98,166,
- 18,0,98,150,0,0,0,0,0,26,2,0,
- 2,18,2,0,37,24,98,0,12,0,131,166,
- 33,32,192,2,74,21,192,12,33,40,96,2,
- 8,0,64,20,33,32,96,2,3,131,3,60,
- 108,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,152,21,192,12,0,0,98,172,
- 76,0,191,143,72,0,182,143,68,0,181,143,
- 64,0,180,143,60,0,179,143,56,0,178,143,
- 52,0,177,143,48,0,176,143,8,0,224,3,
- 80,0,189,39,33,24,0,0,5,0,7,36,
- 58,0,6,36,0,0,162,144,0,0,0,0,
- 2,17,2,0,2,131,1,60,33,8,34,0,
- 176,155,34,144,0,0,0,0,0,0,130,160,
- 0,0,162,144,1,0,132,36,15,0,66,48,
- 2,131,1,60,33,8,34,0,176,155,34,144,
- 1,0,165,36,0,0,130,160,3,0,103,16,
- 1,0,132,36,0,0,134,160,1,0,132,36,
- 1,0,99,36,6,0,98,40,233,255,64,20,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 128,255,189,39,2,101,2,36,0,2,3,36,
- 112,0,176,175,44,0,176,39,33,32,0,2,
- 33,40,0,0,48,0,6,36,120,0,191,175,
- 116,0,177,175,40,0,162,167,144,71,192,12,
- 42,0,163,167,3,131,17,60,96,18,49,38,
- 2,131,5,60,224,147,165,36,188,71,192,12,
- 33,32,32,2,18,0,64,20,33,32,0,2,
- 2,131,5,60,236,147,165,36,0,0,162,140,
- 4,0,163,140,8,0,164,140,44,0,162,175,
- 48,0,163,175,52,0,164,175,12,0,162,128,
- 0,0,0,0,56,0,162,163,2,131,5,60,
- 212,4,165,36,193,48,192,12,56,0,164,39,
- 8,49,192,8,92,0,177,39,33,40,32,2,
- 204,63,192,12,48,0,6,36,92,0,177,39,
- 33,32,32,2,33,40,0,0,144,71,192,12,
- 4,0,6,36,2,131,4,60,212,4,132,36,
- 0,0,130,140,4,0,131,132,96,0,162,175,
- 100,0,163,167,4,82,2,36,0,1,3,36,
- 236,255,132,36,2,0,5,36,102,0,162,167,
- 54,21,192,12,104,0,163,167,33,128,64,0,
- 22,0,0,18,40,0,165,39,4,0,4,142,
- 0,0,0,0,220,42,192,12,66,0,6,36,
- 33,32,0,0,0,0,67,140,132,129,133,39,
- 0,128,99,52,0,0,67,172,4,0,3,142,
- 14,0,6,36,18,0,99,148,33,56,32,2,
- 18,0,3,166,82,4,3,36,16,0,165,175,
- 20,0,163,175,24,0,163,175,28,0,176,175,
- 214,47,192,12,32,0,162,175,120,0,191,143,
- 116,0,177,143,112,0,176,143,8,0,224,3,
- 128,0,189,39,144,255,189,39,104,0,180,175,
- 33,160,128,0,100,0,179,175,33,152,160,0,
- 92,0,177,175,33,136,192,0,33,32,224,0,
- 40,0,166,39,56,0,167,39,96,0,178,175,
- 2,131,18,60,8,239,82,38,88,0,176,175,
- 128,0,176,143,242,5,2,36,84,0,162,167,
- 72,0,162,39,108,0,191,175,72,0,160,167,
- 76,0,178,175,80,0,178,175,16,0,162,175,
- 247,71,192,12,33,40,0,2,255,255,3,36,
- 37,0,67,16,255,1,5,38,2,131,4,60,
- 192,4,132,36,54,21,192,12,2,42,5,0,
- 33,128,64,0,30,0,0,18,33,40,64,2,
- 80,0,166,143,76,0,162,143,4,0,4,142,
- 35,48,194,0,220,42,192,12,255,255,198,48,
- 33,32,128,2,0,0,67,140,6,0,101,38,
- 0,128,99,52,0,0,67,172,4,0,3,142,
- 35,48,51,2,18,0,99,148,18,0,39,38,
- 18,0,3,166,28,0,40,150,22,0,35,38,
- 16,0,163,175,15,144,3,52,24,0,163,175,
- 28,0,176,175,32,0,162,175,0,18,8,0,
- 2,66,8,0,37,16,72,0,255,255,66,48,
- 214,47,192,12,20,0,162,175,108,0,191,143,
- 104,0,180,143,100,0,179,143,96,0,178,143,
- 92,0,177,143,88,0,176,143,8,0,224,3,
- 112,0,189,39,200,255,189,39,44,0,181,175,
- 33,168,128,0,28,0,177,175,33,136,160,0,
- 48,0,191,175,40,0,180,175,36,0,179,175,
- 32,0,178,175,24,0,176,175,18,0,34,150,
- 0,0,0,0,255,255,84,48,243,5,130,46,
- 4,0,64,20,33,152,192,0,3,131,3,60,
- 241,49,192,8,84,17,99,36,2,131,18,60,
- 16,233,82,38,33,32,64,2,0,0,48,142,
- 8,0,37,142,255,63,16,50,80,68,192,12,
- 33,48,0,2,0,0,34,142,0,0,0,0,
- 0,128,66,48,5,0,64,20,33,144,80,2,
- 4,0,49,142,0,0,0,0,148,49,192,8,
- 33,32,64,2,2,131,2,60,16,233,66,36,
- 33,128,98,2,6,0,17,38,33,32,32,2,
- 0,163,5,60,224,5,165,52,168,71,192,12,
- 4,0,6,36,9,0,64,16,33,32,32,2,
- 224,129,133,39,168,71,192,12,4,0,6,36,
- 5,0,64,16,10,0,17,38,3,131,3,60,
- 241,49,192,8,88,17,99,36,10,0,17,38,
- 33,32,32,2,2,131,5,60,212,4,165,36,
- 168,71,192,12,6,0,6,36,9,0,64,16,
- 33,32,32,2,228,129,133,39,168,71,192,12,
- 6,0,6,36,4,0,64,16,0,0,0,0,
- 3,131,3,60,241,49,192,8,88,17,99,36,
- 0,0,3,150,255,255,2,52,4,0,98,16,
- 30,0,7,38,3,131,3,60,241,49,192,8,
- 88,17,99,36,2,0,2,150,2,131,5,60,
- 16,233,165,36,0,26,2,0,2,18,2,0,
- 37,24,98,0,255,255,99,48,226,255,104,36,
- 35,16,229,0,35,16,130,2,42,16,72,0,
- 4,0,64,16,0,0,0,0,3,131,3,60,
- 241,49,192,8,96,17,99,36,16,0,2,150,
- 0,0,0,0,0,26,2,0,2,18,2,0,
- 37,24,98,0,255,255,99,48,15,144,2,52,
- 11,0,98,20,33,32,160,2,3,131,3,60,
- 100,17,99,36,0,0,98,140,33,48,0,2,
- 16,0,168,175,1,0,66,36,54,49,192,12,
- 0,0,98,172,245,49,192,8,0,0,0,0,
- 3,131,3,60,92,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,0,0,98,172,
- 48,0,191,143,44,0,181,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,56,0,189,39,
- 0,0,0,0,0,0,0,0,232,255,189,39,
- 16,0,191,175,13,8,192,12,0,8,4,36,
- 8,133,130,175,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,232,255,189,39,
- 45,0,128,16,16,0,191,175,240,129,133,143,
- 7,0,130,36,194,16,2,0,10,0,160,20,
- 1,0,70,36,8,133,133,143,0,133,130,39,
- 0,133,133,175,0,0,162,172,0,8,2,36,
- 240,129,133,175,2,131,1,60,20,211,32,172,
- 4,0,162,172,0,0,164,140,0,0,0,0,
- 4,0,131,140,0,0,0,0,43,16,102,0,
- 14,0,64,20,0,0,0,0,5,0,102,20,
- 35,16,102,0,0,0,130,140,0,0,0,0,
- 43,50,192,8,0,0,162,172,4,0,130,172,
- 192,16,2,0,33,32,130,0,4,0,134,172,
- 240,129,133,175,57,50,192,8,8,0,130,36,
- 240,129,130,143,0,0,0,0,4,0,130,16,
- 33,40,128,0,0,0,132,140,28,50,192,8,
- 0,0,0,0,2,131,4,60,15,63,192,12,
- 64,148,132,36,33,16,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 56,0,128,16,248,255,132,36,240,129,133,143,
- 0,0,0,0,78,50,192,8,43,16,164,0,
- 0,0,163,140,0,0,0,0,43,16,163,0,
- 5,0,64,20,43,16,164,0,12,0,64,20,
- 43,16,131,0,10,0,64,20,0,0,0,0,
- 33,40,96,0,43,16,164,0,244,255,64,16,
- 0,0,0,0,0,0,162,140,0,0,0,0,
- 43,16,130,0,239,255,64,16,0,0,0,0,
- 4,0,134,140,0,0,163,140,192,16,6,0,
- 33,16,130,0,11,0,67,20,0,0,0,0,
- 4,0,98,140,0,0,0,0,33,16,194,0,
- 4,0,130,172,0,0,162,140,0,0,0,0,
- 0,0,66,140,0,0,0,0,102,50,192,8,
- 0,0,130,172,0,0,131,172,4,0,163,140,
- 0,0,0,0,192,16,3,0,33,16,162,0,
- 9,0,68,20,0,0,0,0,4,0,130,140,
- 0,0,0,0,33,16,98,0,4,0,162,172,
- 0,0,130,140,0,0,0,0,117,50,192,8,
- 0,0,162,172,0,0,164,172,240,129,133,175,
- 8,0,224,3,0,0,0,0,232,255,189,39,
- 16,0,191,175,0,50,192,12,0,0,0,0,
- 178,45,192,12,33,32,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 1,0,3,36,5,0,195,20,255,255,2,36,
- 0,0,226,140,0,0,0,0,43,16,2,0,
- 35,16,2,0,8,0,224,3,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,224,0,
- 20,0,177,175,48,0,177,143,1,0,2,36,
- 5,0,162,20,24,0,191,175,0,0,194,140,
- 0,0,0,0,8,0,64,16,0,0,0,0,
- 11,0,2,36,33,32,0,2,33,40,32,2,
- 48,72,192,12,96,0,2,174,1,0,66,36,
- 100,0,2,174,17,0,34,146,0,0,0,0,
- 1,0,66,52,17,0,34,162,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,8,0,224,3,0,0,0,0,
- 16,0,163,143,0,0,0,0,17,0,98,144,
- 0,0,0,0,2,0,66,52,8,0,224,3,
- 17,0,98,160,8,0,224,3,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 244,129,131,151,255,0,2,36,28,0,191,175,
- 24,0,178,175,20,0,177,175,4,0,2,174,
- 60,0,0,174,1,0,98,36,244,129,130,167,
- 10,0,3,166,3,0,162,136,0,0,162,152,
- 7,0,163,136,4,0,163,152,11,0,164,136,
- 8,0,164,152,15,0,167,136,12,0,167,152,
- 15,0,2,170,12,0,2,186,19,0,3,170,
- 16,0,3,186,23,0,4,170,20,0,4,186,
- 27,0,7,170,24,0,7,186,3,0,194,136,
- 0,0,194,152,7,0,195,136,4,0,195,152,
- 11,0,196,136,8,0,196,152,15,0,197,136,
- 12,0,197,152,31,0,2,170,28,0,2,186,
- 35,0,3,170,32,0,3,186,39,0,4,170,
- 36,0,4,186,43,0,5,170,40,0,5,186,
- 80,0,2,142,76,0,3,142,0,0,0,0,
- 35,16,67,0,255,255,81,48,88,0,3,150,
- 3,0,2,36,13,0,98,16,0,0,0,0,
- 2,131,18,60,160,204,82,38,156,71,192,12,
- 33,32,64,2,7,0,81,20,33,32,64,2,
- 76,0,5,142,0,0,0,0,168,71,192,12,
- 33,48,32,2,21,0,64,16,33,16,0,0,
- 2,131,18,60,192,204,82,38,156,71,192,12,
- 33,32,64,2,7,0,81,20,33,32,64,2,
- 76,0,5,142,0,0,0,0,168,71,192,12,
- 33,48,32,2,9,0,64,16,33,16,0,0,
- 3,131,3,60,132,17,99,36,0,0,98,140,
- 1,0,4,36,1,0,66,36,178,45,192,12,
- 0,0,98,172,1,0,2,36,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,0,0,0,0,
- 0,0,0,0,224,255,189,39,20,0,177,175,
- 33,136,224,0,16,0,176,175,48,0,176,143,
- 24,0,191,175,156,71,192,12,33,32,32,2,
- 0,0,2,174,33,16,32,2,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,8,0,224,3,33,16,224,0,
- 0,0,227,140,204,204,2,60,205,204,66,52,
- 25,0,98,0,16,32,0,0,0,0,0,0,
- 0,0,0,0,8,0,224,3,194,16,4,0,
- 224,255,189,39,16,0,176,175,33,128,224,0,
- 33,32,0,2,33,40,0,0,20,0,177,175,
- 48,0,177,143,24,0,191,175,208,71,192,12,
- 16,0,6,36,2,0,64,20,35,16,80,0,
- 16,0,2,36,0,0,34,174,33,16,0,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 40,0,164,143,44,0,165,143,16,0,191,175,
- 205,59,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,40,0,164,143,44,0,165,143,
- 16,0,191,175,239,59,192,12,0,0,0,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,232,255,189,39,40,0,164,143,
- 44,0,165,143,16,0,191,175,17,60,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,8,0,224,3,
- 33,16,224,0,0,0,226,140,8,0,224,3,
- 0,0,0,0,216,255,189,39,24,0,176,175,
- 56,0,176,143,32,0,191,175,28,0,177,175,
- 36,0,2,142,1,0,3,36,20,0,81,140,
- 187,0,163,20,0,0,0,0,0,0,195,140,
- 0,0,0,0,183,0,96,16,0,0,0,0,
- 32,133,130,143,0,0,0,0,43,16,67,0,
- 178,0,64,20,255,255,104,36,64,18,8,0,
- 2,131,3,60,192,246,99,36,33,40,67,0,
- 255,255,132,36,22,0,130,44,170,0,64,16,
- 128,16,4,0,2,131,1,60,33,8,34,0,
- 144,148,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,2,0,2,36,16,0,2,162,
- 17,0,2,146,0,0,195,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,33,32,32,2,
- 17,0,3,146,4,0,2,36,16,0,2,162,
- 40,0,0,166,44,0,17,174,2,0,99,52,
- 156,71,192,12,17,0,3,162,255,255,66,48,
- 33,16,34,2,48,0,2,174,40,52,192,8,
- 52,0,0,166,17,0,3,146,2,0,2,36,
- 16,0,2,162,243,51,192,8,40,0,17,174,
- 17,0,3,146,2,0,2,36,16,0,2,162,
- 243,51,192,8,40,0,17,174,66,0,2,36,
- 13,0,0,21,16,0,2,162,24,133,132,143,
- 0,0,0,0,64,25,4,0,35,24,100,0,
- 128,17,3,0,35,16,67,0,192,16,2,0,
- 33,16,68,0,128,24,2,0,33,16,67,0,
- 178,51,192,8,192,17,2,0,152,0,2,60,
- 128,150,66,52,40,0,2,174,17,0,2,146,
- 0,0,0,0,199,51,192,8,2,0,66,52,
- 17,0,3,146,4,0,2,36,16,0,2,162,
- 20,0,162,36,44,0,2,174,26,0,162,36,
- 40,0,0,166,48,0,2,174,243,51,192,8,
- 52,0,0,166,2,0,2,36,16,0,2,162,
- 17,0,2,146,1,0,3,36,40,0,3,174,
- 2,0,66,52,40,52,192,8,17,0,2,162,
- 17,0,3,146,0,0,0,0,241,51,192,8,
- 67,0,2,36,65,0,2,36,16,0,2,162,
- 17,0,2,146,168,0,163,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,65,0,2,36,
- 16,0,2,162,156,0,162,140,0,1,164,140,
- 22,52,192,8,0,0,0,0,65,0,2,36,
- 16,0,2,162,17,0,2,146,0,1,163,140,
- 0,0,0,0,15,52,192,8,2,0,66,52,
- 65,0,2,36,16,0,2,162,17,0,2,146,
- 164,0,163,140,0,0,0,0,15,52,192,8,
- 2,0,66,52,65,0,2,36,16,0,2,162,
- 17,0,2,146,160,0,163,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,17,0,3,146,
- 65,0,2,36,16,0,2,162,40,0,0,174,
- 2,0,99,52,40,52,192,8,17,0,3,162,
- 65,0,2,36,16,0,2,162,172,0,162,140,
- 4,1,164,140,22,52,192,8,0,0,0,0,
- 65,0,2,36,16,0,2,162,17,0,2,146,
- 4,1,163,140,0,0,0,0,15,52,192,8,
- 2,0,66,52,65,0,2,36,16,0,2,162,
- 17,0,2,146,184,0,163,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,65,0,2,36,
- 16,0,2,162,17,0,2,146,188,0,163,140,
- 2,0,66,52,40,0,3,174,40,52,192,8,
- 17,0,2,162,66,0,2,36,16,0,2,162,
- 172,0,162,140,176,0,164,140,17,0,3,146,
- 35,16,68,0,2,0,99,52,40,0,2,174,
- 40,52,192,8,17,0,3,162,16,0,160,175,
- 33,32,224,0,33,40,0,2,2,131,7,60,
- 96,204,231,36,226,76,192,12,2,0,6,36,
- 40,52,192,8,0,0,0,0,33,32,224,0,
- 200,76,192,12,33,40,0,2,32,0,191,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,224,255,189,39,16,0,176,175,
- 33,128,224,0,20,0,177,175,48,0,177,143,
- 1,0,2,36,10,0,162,20,24,0,191,175,
- 0,0,198,140,0,0,0,0,6,0,192,16,
- 0,0,0,0,32,133,130,143,0,0,0,0,
- 43,16,70,0,5,0,64,16,7,0,2,36,
- 33,32,0,2,33,40,32,2,70,52,192,8,
- 11,0,2,36,7,0,130,16,33,32,0,2,
- 33,40,32,2,17,0,2,36,48,72,192,12,
- 96,0,2,174,1,0,66,36,100,0,2,174,
- 17,0,34,146,0,0,0,0,1,0,66,52,
- 17,0,34,162,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 208,255,189,39,32,0,176,175,64,0,176,143,
- 36,0,177,175,33,136,224,0,4,0,160,20,
- 40,0,191,175,1,0,2,36,106,52,192,8,
- 24,0,162,175,0,0,198,140,32,133,130,143,
- 0,0,0,0,43,16,194,0,3,0,64,16,
- 1,0,194,36,106,52,192,8,24,0,162,175,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 116,52,192,8,17,0,2,162,16,0,176,175,
- 1,0,5,36,24,0,166,39,97,51,192,12,
- 33,56,32,2,33,32,32,2,33,40,0,2,
- 1,0,6,36,253,76,192,12,24,0,167,39,
- 40,0,191,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,48,0,189,39,16,0,163,143,
- 1,0,2,36,13,0,162,20,14,0,2,36,
- 0,0,198,140,0,0,0,0,9,0,192,16,
- 0,0,0,0,32,133,130,143,0,0,0,0,
- 43,16,70,0,4,0,64,20,14,0,2,36,
- 7,0,2,36,2,0,130,16,14,0,2,36,
- 96,0,226,172,17,0,98,144,0,0,0,0,
- 2,0,66,52,8,0,224,3,17,0,98,160,
- 16,0,162,143,0,0,0,0,8,0,224,3,
- 0,0,226,172,0,0,226,140,8,0,224,3,
- 0,0,0,0,232,255,189,39,40,0,168,143,
- 1,0,2,36,61,0,162,20,16,0,191,175,
- 0,0,197,140,0,0,0,0,57,0,160,16,
- 0,0,0,0,32,133,130,143,0,0,0,0,
- 43,16,69,0,52,0,64,20,255,255,132,36,
- 5,0,130,44,49,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,232,148,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 64,0,2,36,16,0,2,161,0,163,5,60,
- 220,5,165,52,3,0,162,136,0,0,162,152,
- 0,0,0,0,43,0,2,169,40,0,2,185,
- 17,0,2,145,0,0,0,0,213,52,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 17,0,2,145,0,0,195,140,0,0,0,0,
- 198,52,192,8,2,0,66,52,64,0,2,36,
- 16,0,2,161,17,0,2,145,128,132,131,143,
- 2,0,66,52,40,0,3,173,218,52,192,8,
- 17,0,2,161,2,0,2,36,16,0,2,161,
- 17,0,2,145,0,0,0,0,211,52,192,8,
- 1,0,3,36,2,0,2,36,16,0,2,161,
- 17,0,2,145,220,5,3,36,40,0,3,173,
- 2,0,66,52,218,52,192,8,17,0,2,161,
- 33,32,224,0,200,76,192,12,33,40,0,1,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,208,255,189,39,32,0,176,175,
- 64,0,176,143,36,0,177,175,33,136,224,0,
- 4,0,160,20,40,0,191,175,1,0,2,36,
- 245,52,192,8,24,0,162,175,0,0,198,140,
- 32,133,130,143,0,0,0,0,43,16,194,0,
- 3,0,64,16,1,0,194,36,245,52,192,8,
- 24,0,162,175,17,0,2,146,0,0,0,0,
- 18,0,66,52,255,52,192,8,17,0,2,162,
- 16,0,176,175,1,0,5,36,24,0,166,39,
- 150,52,192,12,33,56,32,2,33,32,32,2,
- 33,40,0,2,1,0,6,36,253,76,192,12,
- 24,0,167,39,40,0,191,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 232,255,189,39,40,0,165,143,16,0,191,175,
- 200,76,192,12,33,32,224,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 16,0,163,143,14,0,2,36,96,0,226,172,
- 17,0,98,144,0,0,0,0,2,0,66,52,
- 8,0,224,3,17,0,98,160,224,255,189,39,
- 16,0,176,175,33,128,224,0,17,0,2,36,
- 24,0,191,175,20,0,177,175,96,0,2,174,
- 48,0,177,143,33,32,0,2,48,72,192,12,
- 33,40,32,2,1,0,66,36,100,0,2,174,
- 17,0,34,146,0,0,0,0,1,0,66,52,
- 17,0,34,162,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 16,0,163,143,0,0,0,0,17,0,98,144,
- 0,0,0,0,18,0,66,52,8,0,224,3,
- 17,0,98,160,8,0,224,3,33,16,224,0,
- 224,255,189,39,48,0,168,143,1,0,2,36,
- 114,0,162,20,24,0,191,175,0,0,195,140,
- 0,0,0,0,110,0,96,16,0,0,0,0,
- 32,133,130,143,0,0,0,0,43,16,67,0,
- 105,0,64,20,255,255,98,36,64,18,2,0,
- 2,131,3,60,192,246,99,36,33,24,67,0,
- 255,255,132,36,17,0,130,44,97,0,64,16,
- 128,16,4,0,2,131,1,60,33,8,34,0,
- 0,149,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,2,0,2,36,16,0,2,161,
- 17,0,2,145,0,0,195,140,0,0,0,0,
- 140,53,192,8,2,0,66,52,2,0,2,36,
- 16,0,2,161,44,0,99,140,17,0,2,145,
- 16,0,99,140,0,0,0,0,101,53,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 44,0,99,140,17,0,2,145,12,0,99,140,
- 2,0,66,52,17,0,2,161,173,53,192,8,
- 40,0,3,173,2,0,2,36,16,0,2,161,
- 17,0,2,145,212,0,99,140,0,0,0,0,
- 140,53,192,8,2,0,66,52,2,0,2,36,
- 16,0,2,161,17,0,2,145,192,0,99,140,
- 0,0,0,0,140,53,192,8,2,0,66,52,
- 2,0,2,36,16,0,2,161,17,0,2,145,
- 208,0,99,140,0,0,0,0,140,53,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 204,0,98,140,184,0,100,140,17,0,3,145,
- 33,16,68,0,2,0,99,52,40,0,2,173,
- 173,53,192,8,17,0,3,161,2,0,2,36,
- 16,0,2,161,17,0,2,145,196,0,99,140,
- 2,0,66,52,40,0,3,173,173,53,192,8,
- 17,0,2,161,17,0,3,145,2,0,2,36,
- 16,0,2,161,40,0,0,173,2,0,99,52,
- 173,53,192,8,17,0,3,161,2,0,2,36,
- 16,0,2,161,44,0,100,140,17,0,2,145,
- 20,0,131,140,24,0,132,140,2,0,66,52,
- 17,0,2,161,33,24,100,0,173,53,192,8,
- 40,0,3,173,16,0,160,175,33,32,224,0,
- 33,40,0,1,2,131,7,60,104,204,231,36,
- 226,76,192,12,11,0,6,36,173,53,192,8,
- 0,0,0,0,33,32,224,0,200,76,192,12,
- 33,40,0,1,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 32,0,176,175,64,0,176,143,36,0,177,175,
- 33,136,224,0,4,0,160,20,40,0,191,175,
- 1,0,2,36,200,53,192,8,24,0,162,175,
- 0,0,198,140,32,133,130,143,0,0,0,0,
- 43,16,194,0,3,0,64,16,1,0,194,36,
- 200,53,192,8,24,0,162,175,17,0,2,146,
- 0,0,0,0,18,0,66,52,210,53,192,8,
- 17,0,2,162,16,0,176,175,1,0,5,36,
- 24,0,166,39,52,53,192,12,33,56,32,2,
- 33,32,32,2,33,40,0,2,1,0,6,36,
- 253,76,192,12,24,0,167,39,40,0,191,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 48,0,189,39,0,0,226,140,8,0,224,3,
- 0,0,0,0,3,131,2,60,28,18,66,148,
- 0,0,0,0,2,0,66,48,2,0,64,16,
- 2,0,3,36,1,0,3,36,8,0,224,3,
- 33,16,96,0,232,255,189,39,40,0,164,143,
- 16,0,191,175,1,0,132,56,186,59,192,12,
- 1,0,132,44,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,16,0,163,143,
- 6,0,2,36,0,0,98,172,8,0,224,3,
- 33,16,224,0,224,255,189,39,48,0,168,143,
- 1,0,2,36,52,0,162,20,24,0,191,175,
- 0,0,197,140,0,0,0,0,48,0,160,16,
- 0,0,0,0,24,133,130,143,0,0,0,0,
- 43,16,69,0,43,0,64,20,255,255,132,36,
- 5,0,130,44,40,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,72,149,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 2,0,2,36,16,0,2,161,17,0,2,145,
- 0,0,195,140,2,0,66,52,40,0,3,173,
- 45,54,192,8,17,0,2,161,2,0,2,36,
- 16,0,2,161,0,0,194,140,17,0,3,145,
- 1,0,66,36,2,0,99,52,40,0,2,173,
- 45,54,192,8,17,0,3,161,16,0,160,175,
- 33,32,224,0,33,40,0,1,2,131,7,60,
- 148,204,231,36,226,76,192,12,2,0,6,36,
- 45,54,192,8,0,0,0,0,17,0,3,145,
- 2,0,2,36,16,0,2,161,40,0,0,173,
- 2,0,99,52,45,54,192,8,17,0,3,161,
- 33,32,224,0,200,76,192,12,33,40,0,1,
- 24,0,191,143,32,0,189,39,8,0,224,3,
- 0,0,0,0,208,255,189,39,32,0,176,175,
- 64,0,176,143,36,0,177,175,33,136,224,0,
- 4,0,160,20,40,0,191,175,1,0,2,36,
- 72,54,192,8,24,0,162,175,0,0,198,140,
- 24,133,130,143,0,0,0,0,43,16,194,0,
- 3,0,64,16,1,0,194,36,72,54,192,8,
- 24,0,162,175,17,0,2,146,0,0,0,0,
- 18,0,66,52,82,54,192,8,17,0,2,162,
- 16,0,176,175,1,0,5,36,24,0,166,39,
- 242,53,192,12,33,56,32,2,33,32,32,2,
- 33,40,0,2,1,0,6,36,253,76,192,12,
- 24,0,167,39,40,0,191,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 0,0,226,148,8,0,224,3,0,0,0,0,
- 8,0,224,3,33,16,224,0,16,0,163,143,
- 8,0,2,36,0,0,98,172,8,0,224,3,
- 33,16,224,0,224,255,189,39,16,0,176,175,
- 48,0,176,143,1,0,2,36,24,0,191,175,
- 126,0,162,20,20,0,177,175,0,0,198,140,
- 0,0,0,0,122,0,192,16,0,0,0,0,
- 24,133,130,143,0,0,0,0,43,16,70,0,
- 117,0,64,20,192,17,6,0,3,131,3,60,
- 16,13,99,36,33,136,67,0,255,255,132,36,
- 10,0,130,44,110,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,96,149,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 17,0,3,146,2,0,2,36,16,0,2,162,
- 211,54,192,8,40,0,6,174,2,0,2,36,
- 16,0,2,162,0,0,34,150,17,0,3,146,
- 0,0,0,0,143,54,192,8,2,18,2,0,
- 2,0,2,36,16,0,2,162,4,0,34,142,
- 17,0,3,146,1,0,66,36,2,0,99,52,
- 40,0,2,174,232,54,192,8,17,0,3,162,
- 2,0,2,36,16,0,2,162,4,0,34,142,
- 0,0,0,0,2,0,64,16,2,0,3,36,
- 1,0,3,36,17,0,2,146,40,0,3,174,
- 2,0,66,52,232,54,192,8,17,0,2,162,
- 2,0,2,36,16,0,2,162,17,0,2,146,
- 8,0,35,142,0,0,0,0,226,54,192,8,
- 2,0,66,52,9,50,192,12,8,0,4,36,
- 33,48,64,0,15,0,34,138,12,0,34,154,
- 19,0,35,138,16,0,35,154,3,0,194,168,
- 0,0,194,184,7,0,195,168,196,54,192,8,
- 4,0,195,184,2,0,2,36,16,0,2,162,
- 17,0,2,146,20,0,35,142,0,0,0,0,
- 226,54,192,8,2,0,66,52,9,50,192,12,
- 8,0,4,36,33,48,64,0,27,0,34,138,
- 24,0,34,154,31,0,35,138,28,0,35,154,
- 3,0,194,168,0,0,194,184,7,0,195,168,
- 4,0,195,184,0,0,194,148,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 0,0,195,164,17,0,3,146,4,0,2,36,
- 16,0,2,162,1,0,2,36,40,0,2,166,
- 8,0,194,36,44,0,6,174,48,0,2,174,
- 52,0,0,166,2,0,99,52,232,54,192,8,
- 17,0,3,162,2,0,2,36,16,0,2,162,
- 17,0,2,146,32,0,35,150,0,0,0,0,
- 226,54,192,8,2,0,66,52,2,0,2,36,
- 16,0,2,162,17,0,2,146,104,0,35,142,
- 2,0,66,52,40,0,3,174,232,54,192,8,
- 17,0,2,162,33,32,224,0,200,76,192,12,
- 33,40,0,2,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 224,255,189,39,16,0,176,175,33,128,224,0,
- 20,0,177,175,48,0,177,143,1,0,2,36,
- 10,0,162,20,24,0,191,175,0,0,198,140,
- 0,0,0,0,6,0,192,16,0,0,0,0,
- 24,133,130,143,0,0,0,0,43,16,70,0,
- 5,0,64,16,2,0,2,36,33,32,0,2,
- 33,40,32,2,13,55,192,8,11,0,2,36,
- 14,0,130,16,2,0,130,44,5,0,64,20,
- 6,0,130,44,3,0,64,16,4,0,130,44,
- 8,0,64,16,0,0,0,0,33,32,0,2,
- 33,40,32,2,17,0,2,36,48,72,192,12,
- 96,0,2,174,1,0,66,36,100,0,2,174,
- 17,0,34,146,0,0,0,0,1,0,66,52,
- 17,0,34,162,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 208,255,189,39,32,0,176,175,64,0,176,143,
- 36,0,177,175,33,136,224,0,4,0,160,20,
- 40,0,191,175,1,0,2,36,49,55,192,8,
- 24,0,162,175,0,0,198,140,24,133,130,143,
- 0,0,0,0,43,16,194,0,3,0,64,16,
- 1,0,194,36,49,55,192,8,24,0,162,175,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 59,55,192,8,17,0,2,162,16,0,176,175,
- 1,0,5,36,24,0,166,39,97,54,192,12,
- 33,56,32,2,33,32,32,2,33,40,0,2,
- 1,0,6,36,253,76,192,12,24,0,167,39,
- 40,0,191,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,48,0,189,39,232,255,189,39,
- 33,64,128,0,16,0,176,175,40,0,176,143,
- 1,0,2,36,57,0,162,20,20,0,191,175,
- 0,0,196,140,0,0,0,0,54,0,128,16,
- 14,0,2,36,24,133,130,143,0,0,0,0,
- 43,16,68,0,49,0,64,20,14,0,2,36,
- 192,17,4,0,3,131,3,60,16,13,99,36,
- 33,48,67,0,4,0,2,36,21,0,2,17,
- 5,0,2,45,5,0,64,16,2,0,2,36,
- 8,0,2,17,14,0,2,36,129,55,192,8,
- 96,0,226,172,5,0,2,36,28,0,2,17,
- 14,0,2,36,129,55,192,8,96,0,226,172,
- 0,0,195,144,0,0,0,0,0,0,195,164,
- 40,0,2,142,0,0,0,0,0,18,2,0,
- 37,24,98,0,129,55,192,8,0,0,195,164,
- 40,0,3,142,0,0,0,0,5,0,101,16,
- 2,0,2,36,7,0,98,16,14,0,2,36,
- 129,55,192,8,96,0,226,172,187,42,192,12,
- 1,0,5,36,129,55,192,8,0,0,0,0,
- 187,42,192,12,33,40,0,0,129,55,192,8,
- 0,0,0,0,40,0,2,142,0,0,0,0,
- 129,55,192,8,8,0,194,172,14,0,2,36,
- 96,0,226,172,17,0,2,146,0,0,0,0,
- 2,0,66,52,17,0,2,162,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 216,255,189,39,20,0,177,175,33,136,128,0,
- 28,0,179,175,33,152,160,0,24,0,178,175,
- 33,144,224,0,16,0,176,175,56,0,176,143,
- 1,0,2,36,46,0,98,22,32,0,191,175,
- 0,0,196,140,0,0,0,0,42,0,128,16,
- 0,0,0,0,58,25,192,12,0,0,0,0,
- 33,32,64,0,37,0,128,16,2,0,2,36,
- 11,0,34,18,3,0,34,46,5,0,64,16,
- 3,0,2,36,15,0,51,18,4,0,2,36,
- 195,55,192,8,33,32,64,2,20,0,34,18,
- 33,32,64,2,195,55,192,8,0,0,0,0,
- 2,0,2,36,16,0,2,162,17,0,2,146,
- 10,0,131,132,2,0,66,52,40,0,3,174,
- 197,55,192,8,17,0,2,162,17,0,3,146,
- 16,0,2,162,4,0,130,36,44,0,2,174,
- 10,0,130,36,40,0,0,166,48,0,2,174,
- 191,55,192,8,52,0,0,166,17,0,3,146,
- 2,0,2,36,16,0,2,162,40,0,17,174,
- 2,0,99,52,197,55,192,8,17,0,3,162,
- 33,32,64,2,200,76,192,12,33,40,0,2,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,208,255,189,39,32,0,176,175,
- 64,0,176,143,40,0,178,175,33,144,128,0,
- 36,0,177,175,33,136,224,0,3,0,160,20,
- 44,0,191,175,218,55,192,8,1,0,2,36,
- 0,0,194,140,0,0,0,0,1,0,66,36,
- 24,0,162,175,24,0,164,143,58,25,192,12,
- 0,0,0,0,6,0,64,20,33,32,64,2,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 239,55,192,8,17,0,2,162,16,0,176,175,
- 1,0,5,36,24,0,166,39,137,55,192,12,
- 33,56,32,2,33,32,32,2,33,40,0,2,
- 1,0,6,36,253,76,192,12,24,0,167,39,
- 44,0,191,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 232,255,189,39,40,0,168,143,1,0,2,36,
- 63,0,162,20,16,0,191,175,0,0,195,140,
- 0,0,0,0,59,0,96,16,0,0,0,0,
- 24,133,130,143,0,0,0,0,43,16,67,0,
- 54,0,64,20,64,18,3,0,2,131,3,60,
- 192,246,99,36,33,24,67,0,255,255,132,36,
- 5,0,130,44,47,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,136,149,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 2,0,2,36,16,0,2,161,17,0,2,145,
- 0,0,195,140,0,0,0,0,43,56,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 17,0,2,145,220,5,3,36,40,0,3,173,
- 2,0,66,52,59,56,192,8,17,0,2,161,
- 65,0,2,36,16,0,2,161,17,0,2,145,
- 156,0,99,140,0,0,0,0,43,56,192,8,
- 2,0,66,52,65,0,2,36,16,0,2,161,
- 17,0,2,145,172,0,99,140,2,0,66,52,
- 40,0,3,173,59,56,192,8,17,0,2,161,
- 65,0,2,36,16,0,2,161,156,0,98,140,
- 252,0,100,140,17,0,3,145,35,16,68,0,
- 2,0,99,52,40,0,2,173,59,56,192,8,
- 17,0,3,161,33,32,224,0,200,76,192,12,
- 33,40,0,1,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 32,0,176,175,64,0,176,143,36,0,177,175,
- 33,136,224,0,4,0,160,20,40,0,191,175,
- 1,0,2,36,86,56,192,8,24,0,162,175,
- 0,0,198,140,24,133,130,143,0,0,0,0,
- 43,16,194,0,3,0,64,16,1,0,194,36,
- 86,56,192,8,24,0,162,175,17,0,2,146,
- 0,0,0,0,18,0,66,52,96,56,192,8,
- 17,0,2,162,16,0,176,175,1,0,5,36,
- 24,0,166,39,245,55,192,12,33,56,32,2,
- 33,32,32,2,33,40,0,2,1,0,6,36,
- 253,76,192,12,24,0,167,39,40,0,191,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 48,0,189,39,0,0,0,0,0,0,0,0,
- 0,0,0,0,200,255,189,39,72,0,163,143,
- 44,0,177,175,33,136,128,0,20,0,165,175,
- 33,40,224,0,2,131,2,60,172,210,66,140,
- 152,132,135,143,33,32,0,0,48,0,191,175,
- 40,0,176,175,24,0,160,175,28,0,160,175,
- 36,0,160,175,16,0,162,175,104,77,192,12,
- 32,0,163,175,33,128,64,0,3,0,0,22,
- 33,32,0,2,143,56,192,8,33,16,0,0,
- 197,80,192,12,33,40,32,2,255,255,3,36,
- 5,0,67,20,0,0,0,0,167,83,192,12,
- 33,32,0,2,143,56,192,8,33,16,0,0,
- 167,83,192,12,33,32,0,2,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,48,0,191,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,44,0,177,175,33,136,128,0,
- 72,0,168,143,33,32,0,0,20,0,165,175,
- 33,40,224,0,2,131,3,60,172,210,99,140,
- 152,132,135,143,1,0,2,36,48,0,191,175,
- 40,0,176,175,24,0,162,175,28,0,160,175,
- 36,0,160,175,16,0,163,175,104,77,192,12,
- 32,0,168,175,33,128,64,0,3,0,0,22,
- 33,32,0,2,188,56,192,8,33,16,0,0,
- 197,80,192,12,33,40,32,2,255,255,3,36,
- 5,0,67,20,0,0,0,0,167,83,192,12,
- 33,32,0,2,188,56,192,8,33,16,0,0,
- 167,83,192,12,33,32,0,2,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,48,0,191,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,56,0,189,39,
- 176,255,189,39,44,0,177,175,108,0,177,143,
- 68,0,183,175,96,0,183,143,72,0,190,175,
- 100,0,190,143,48,0,178,175,33,144,128,0,
- 56,0,180,175,33,160,160,0,52,0,179,175,
- 33,152,192,0,40,0,176,175,33,128,224,0,
- 60,0,181,175,1,0,21,36,76,0,191,175,
- 3,0,53,18,64,0,182,175,9,57,192,8,
- 255,255,2,36,4,0,6,36,2,131,22,60,
- 48,205,214,38,160,132,132,143,104,0,165,143,
- 128,32,4,0,80,68,192,12,33,32,150,0,
- 33,32,0,0,33,40,0,2,152,132,135,143,
- 2,0,2,36,24,0,162,175,160,132,130,143,
- 2,131,3,60,172,210,99,140,33,48,96,2,
- 20,0,180,175,28,0,160,175,32,0,183,175,
- 36,0,181,175,1,0,81,36,104,77,192,12,
- 16,0,163,175,33,128,64,0,23,0,0,18,
- 33,40,0,0,16,0,190,175,33,32,0,2,
- 33,48,32,2,108,84,192,12,33,56,192,2,
- 255,255,17,36,13,0,81,16,33,32,0,2,
- 197,80,192,12,33,40,64,2,9,0,81,16,
- 0,0,0,0,167,83,192,12,33,32,0,2,
- 8,0,66,142,4,0,67,142,0,0,0,0,
- 35,16,67,0,9,57,192,8,255,255,66,48,
- 167,83,192,12,33,32,0,2,33,16,0,0,
- 76,0,191,143,72,0,190,143,68,0,183,143,
- 64,0,182,143,60,0,181,143,56,0,180,143,
- 52,0,179,143,48,0,178,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,80,0,189,39,
- 176,255,189,39,44,0,177,175,108,0,177,143,
- 68,0,183,175,96,0,183,143,72,0,190,175,
- 100,0,190,143,48,0,178,175,33,144,128,0,
- 56,0,180,175,33,160,160,0,52,0,179,175,
- 33,152,192,0,40,0,176,175,33,128,224,0,
- 60,0,181,175,1,0,21,36,76,0,191,175,
- 3,0,53,18,64,0,182,175,93,57,192,8,
- 255,255,2,36,4,0,6,36,2,131,22,60,
- 48,205,214,38,160,132,132,143,104,0,165,143,
- 128,32,4,0,80,68,192,12,33,32,150,0,
- 33,32,0,0,33,40,0,2,152,132,135,143,
- 3,0,2,36,24,0,162,175,160,132,130,143,
- 2,131,3,60,172,210,99,140,33,48,96,2,
- 20,0,180,175,28,0,160,175,32,0,183,175,
- 36,0,181,175,1,0,81,36,104,77,192,12,
- 16,0,163,175,33,128,64,0,23,0,0,18,
- 33,40,0,0,16,0,190,175,33,32,0,2,
- 33,48,32,2,108,84,192,12,33,56,192,2,
- 255,255,17,36,13,0,81,16,33,32,0,2,
- 197,80,192,12,33,40,64,2,9,0,81,16,
- 0,0,0,0,167,83,192,12,33,32,0,2,
- 8,0,66,142,4,0,67,142,0,0,0,0,
- 35,16,67,0,93,57,192,8,255,255,66,48,
- 167,83,192,12,33,32,0,2,33,16,0,0,
- 76,0,191,143,72,0,190,143,68,0,183,143,
- 64,0,182,143,60,0,181,143,56,0,180,143,
- 52,0,179,143,48,0,178,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,80,0,189,39,
- 200,255,189,39,44,0,177,175,33,136,128,0,
- 72,0,168,143,33,32,0,0,20,0,165,175,
- 33,40,224,0,2,131,3,60,172,210,99,140,
- 152,132,135,143,4,0,2,36,48,0,191,175,
- 40,0,176,175,24,0,162,175,28,0,160,175,
- 36,0,160,175,16,0,163,175,104,77,192,12,
- 32,0,168,175,33,128,64,0,3,0,0,22,
- 33,32,0,2,145,57,192,8,33,16,0,0,
- 197,80,192,12,33,40,32,2,255,255,3,36,
- 5,0,67,20,0,0,0,0,167,83,192,12,
- 33,32,0,2,145,57,192,8,33,16,0,0,
- 167,83,192,12,33,32,0,2,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,48,0,191,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,44,0,177,175,33,136,128,0,
- 72,0,163,143,33,32,0,0,20,0,165,175,
- 33,40,224,0,164,132,135,143,2,131,2,60,
- 92,205,66,36,16,0,162,175,6,0,2,36,
- 24,0,162,175,1,0,2,36,48,0,191,175,
- 40,0,176,175,28,0,162,175,36,0,160,175,
- 104,77,192,12,32,0,163,175,33,128,64,0,
- 3,0,0,22,33,32,0,2,191,57,192,8,
- 33,16,0,0,197,80,192,12,33,40,32,2,
- 255,255,3,36,5,0,67,20,0,0,0,0,
- 167,83,192,12,33,32,0,2,191,57,192,8,
- 33,16,0,0,167,83,192,12,33,32,0,2,
- 8,0,34,142,4,0,35,142,0,0,0,0,
- 35,16,67,0,255,255,66,48,48,0,191,143,
- 44,0,177,143,40,0,176,143,8,0,224,3,
- 56,0,189,39,200,255,189,39,44,0,177,175,
- 33,136,128,0,72,0,163,143,33,32,0,0,
- 20,0,165,175,33,40,224,0,164,132,135,143,
- 2,131,2,60,92,205,66,36,16,0,162,175,
- 6,0,2,36,24,0,162,175,2,0,2,36,
- 48,0,191,175,40,0,176,175,28,0,162,175,
- 36,0,160,175,104,77,192,12,32,0,163,175,
- 33,128,64,0,3,0,0,22,33,32,0,2,
- 237,57,192,8,33,16,0,0,197,80,192,12,
- 33,40,32,2,255,255,3,36,5,0,67,20,
- 0,0,0,0,167,83,192,12,33,32,0,2,
- 237,57,192,8,33,16,0,0,167,83,192,12,
- 33,32,0,2,8,0,34,142,4,0,35,142,
- 0,0,0,0,35,16,67,0,255,255,66,48,
- 48,0,191,143,44,0,177,143,40,0,176,143,
- 8,0,224,3,56,0,189,39,0,0,0,0,
- 0,0,0,0,224,255,189,39,24,0,178,175,
- 33,144,128,0,20,0,177,175,3,131,17,60,
- 0,18,49,38,16,0,176,175,33,128,0,0,
- 28,0,191,175,208,133,128,175,60,65,192,12,
- 33,32,0,2,0,0,34,166,1,0,16,38,
- 64,0,2,42,250,255,64,20,2,0,49,38,
- 3,131,3,60,18,18,99,144,255,0,2,36,
- 3,0,98,16,0,0,0,0,6,0,64,18,
- 0,163,4,60,75,59,192,12,32,0,4,36,
- 87,59,192,12,255,0,4,36,0,163,4,60,
- 220,5,132,52,176,132,133,39,168,71,192,12,
- 4,0,6,36,25,0,64,20,0,163,4,60,
- 3,131,16,60,20,18,16,38,33,32,0,2,
- 176,132,133,39,168,71,192,12,4,0,6,36,
- 3,0,64,16,0,163,4,60,7,0,64,18,
- 0,0,0,0,220,5,132,52,33,40,0,0,
- 144,71,192,12,4,0,6,36,47,58,192,8,
- 0,163,4,60,0,163,5,60,220,5,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,0,163,4,60,
- 99,59,192,12,220,5,132,52,0,163,4,60,
- 16,6,132,52,176,132,133,39,168,71,192,12,
- 4,0,6,36,25,0,64,20,0,163,4,60,
- 3,131,16,60,68,18,16,38,33,32,0,2,
- 176,132,133,39,168,71,192,12,4,0,6,36,
- 3,0,64,16,0,163,4,60,7,0,64,18,
- 0,0,0,0,16,6,132,52,33,40,0,0,
- 144,71,192,12,4,0,6,36,80,58,192,8,
- 0,163,4,60,0,163,5,60,16,6,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,0,163,4,60,
- 119,59,192,12,16,6,132,52,0,163,4,60,
- 224,5,132,52,176,132,133,39,168,71,192,12,
- 4,0,6,36,25,0,64,20,0,163,4,60,
- 3,131,16,60,24,18,16,38,33,32,0,2,
- 176,132,133,39,168,71,192,12,4,0,6,36,
- 3,0,64,16,0,163,4,60,7,0,64,18,
- 0,0,0,0,224,5,132,52,33,40,0,0,
- 144,71,192,12,4,0,6,36,113,58,192,8,
- 0,163,4,60,0,163,5,60,224,5,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,0,163,4,60,
- 139,59,192,12,224,5,132,52,3,131,3,60,
- 28,18,99,36,0,0,98,148,0,0,0,0,
- 0,128,66,48,3,0,64,20,1,0,2,36,
- 2,0,64,18,0,0,0,0,0,0,98,164,
- 0,163,2,60,144,1,66,140,0,0,0,0,
- 7,0,64,20,0,0,0,0,3,131,3,60,
- 28,18,99,36,0,0,98,148,0,0,0,0,
- 146,58,192,8,254,255,66,48,0,163,2,60,
- 144,1,66,140,0,0,0,0,7,0,64,24,
- 0,0,0,0,3,131,3,60,28,18,99,36,
- 0,0,98,148,0,0,0,0,1,0,66,52,
- 0,0,98,164,3,131,4,60,28,18,132,148,
- 0,0,0,0,159,59,192,12,1,0,132,48,
- 3,131,3,60,80,18,99,144,255,0,2,36,
- 3,0,98,16,0,0,0,0,5,0,64,18,
- 0,0,0,0,2,131,4,60,160,149,132,36,
- 205,59,192,12,14,0,5,36,3,131,3,60,
- 96,18,99,144,255,0,2,36,3,0,98,16,
- 0,0,0,0,5,0,64,18,0,0,0,0,
- 2,131,4,60,176,149,132,36,239,59,192,12,
- 11,0,5,36,3,131,3,60,112,18,99,144,
- 255,0,2,36,3,0,98,16,0,0,0,0,
- 5,0,64,18,0,0,0,0,2,131,4,60,
- 188,149,132,36,17,60,192,12,15,0,5,36,
- 0,163,2,60,140,1,66,140,0,0,0,0,
- 7,0,64,16,15,0,2,60,0,163,3,60,
- 140,1,99,140,64,66,66,52,43,16,67,0,
- 26,0,64,16,0,0,0,0,3,131,3,60,
- 64,18,99,140,255,255,2,36,3,0,98,16,
- 44,1,2,36,4,0,64,18,0,0,0,0,
- 0,163,1,60,221,58,192,8,140,1,34,172,
- 5,0,96,20,15,0,4,60,1,0,2,36,
- 0,163,1,60,221,58,192,8,140,1,34,172,
- 64,66,132,52,43,16,131,0,4,0,64,16,
- 0,0,0,0,0,163,1,60,221,58,192,8,
- 140,1,36,172,0,163,1,60,140,1,35,172,
- 0,163,4,60,140,1,132,140,51,60,192,12,
- 0,0,0,0,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,208,255,189,39,20,0,177,175,
- 33,136,128,0,36,0,181,175,33,168,160,0,
- 28,0,179,175,33,152,192,0,44,0,191,175,
- 40,0,182,175,32,0,180,175,24,0,178,175,
- 168,71,192,12,16,0,176,175,76,0,64,16,
- 0,0,0,0,3,131,22,60,0,18,214,38,
- 35,16,54,2,194,31,2,0,33,16,67,0,
- 67,144,2,0,1,0,98,38,194,31,2,0,
- 33,16,67,0,67,128,2,0,255,255,20,38,
- 64,0,130,46,14,0,64,20,64,0,66,46,
- 2,131,4,60,204,149,132,36,180,132,144,39,
- 33,40,0,2,2,131,7,60,236,149,231,36,
- 15,63,192,12,143,0,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,143,0,6,36,
- 64,0,66,46,14,0,64,20,33,32,32,2,
- 2,131,4,60,204,149,132,36,180,132,144,39,
- 33,40,0,2,2,131,7,60,20,150,231,36,
- 15,63,192,12,144,0,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,144,0,6,36,
- 33,32,32,2,33,40,160,2,80,68,192,12,
- 33,48,96,2,64,16,18,0,33,136,86,0,
- 33,128,128,2,255,255,2,36,25,0,2,18,
- 255,255,20,36,180,132,147,39,33,32,64,2,
- 208,133,130,143,1,0,82,38,1,0,66,36,
- 208,133,130,175,0,0,37,150,0,0,0,0,
- 162,65,192,12,2,0,49,38,10,0,64,20,
- 33,40,96,2,2,131,4,60,204,149,132,36,
- 188,132,135,39,15,63,192,12,159,0,6,36,
- 1,0,4,36,33,40,96,2,188,7,192,12,
- 159,0,6,36,255,255,16,38,235,255,20,22,
- 33,32,64,2,44,0,191,143,40,0,182,143,
- 36,0,181,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,48,0,189,39,224,255,189,39,
- 16,0,164,163,3,131,4,60,18,18,132,36,
- 16,0,165,39,24,0,191,175,231,58,192,12,
- 1,0,6,36,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,224,255,189,39,
- 16,0,164,163,3,131,4,60,19,18,132,36,
- 16,0,165,39,24,0,191,175,231,58,192,12,
- 1,0,6,36,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,232,255,189,39,
- 33,40,128,0,16,0,176,175,3,131,16,60,
- 20,18,16,38,33,32,0,2,20,0,191,175,
- 231,58,192,12,4,0,6,36,0,163,5,60,
- 220,5,165,52,3,0,2,138,0,0,2,154,
- 0,0,0,0,3,0,162,168,0,0,162,184,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,232,255,189,39,33,40,128,0,
- 16,0,176,175,3,131,16,60,68,18,16,38,
- 33,32,0,2,20,0,191,175,231,58,192,12,
- 4,0,6,36,0,163,5,60,16,6,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,33,40,128,0,16,0,176,175,
- 3,131,16,60,24,18,16,38,33,32,0,2,
- 20,0,191,175,231,58,192,12,4,0,6,36,
- 0,163,5,60,224,5,165,52,3,0,2,138,
- 0,0,2,154,0,0,0,0,3,0,162,168,
- 0,0,162,184,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,3,131,2,60,
- 28,18,66,148,224,255,189,39,24,0,191,175,
- 8,0,128,16,16,0,162,167,1,0,66,52,
- 16,0,162,167,1,0,2,36,44,133,130,175,
- 0,163,1,60,177,59,192,8,144,1,34,172,
- 254,255,66,48,16,0,162,167,44,133,128,175,
- 0,163,1,60,144,1,32,172,3,131,4,60,
- 28,18,132,36,16,0,165,39,231,58,192,12,
- 2,0,6,36,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,3,131,2,60,
- 28,18,66,148,224,255,189,39,24,0,191,175,
- 3,0,128,16,16,0,162,167,195,59,192,8,
- 2,0,66,52,253,255,66,48,16,0,162,167,
- 3,131,4,60,28,18,132,36,16,0,165,39,
- 231,58,192,12,2,0,6,36,24,0,191,143,
- 32,0,189,39,8,0,224,3,0,0,0,0,
- 216,255,189,39,32,0,191,175,33,56,128,0,
- 33,48,160,0,3,0,226,136,0,0,226,152,
- 7,0,227,136,4,0,227,152,11,0,228,136,
- 8,0,228,152,15,0,229,136,12,0,229,152,
- 19,0,162,171,16,0,162,187,23,0,163,171,
- 20,0,163,187,27,0,164,171,24,0,164,187,
- 31,0,165,171,28,0,165,187,16,0,194,44,
- 3,0,64,16,16,0,163,39,33,16,102,0,
- 0,0,64,160,3,131,4,60,80,18,132,36,
- 33,40,224,0,231,58,192,12,16,0,6,36,
- 32,0,191,143,40,0,189,39,8,0,224,3,
- 0,0,0,0,216,255,189,39,32,0,191,175,
- 33,56,128,0,33,48,160,0,3,0,226,136,
- 0,0,226,152,7,0,227,136,4,0,227,152,
- 11,0,228,136,8,0,228,152,15,0,229,136,
- 12,0,229,152,19,0,162,171,16,0,162,187,
- 23,0,163,171,20,0,163,187,27,0,164,171,
- 24,0,164,187,31,0,165,171,28,0,165,187,
- 16,0,194,44,3,0,64,16,16,0,163,39,
- 33,16,102,0,0,0,64,160,3,131,4,60,
- 96,18,132,36,33,40,224,0,231,58,192,12,
- 16,0,6,36,32,0,191,143,40,0,189,39,
- 8,0,224,3,0,0,0,0,216,255,189,39,
- 32,0,191,175,33,56,128,0,33,48,160,0,
- 3,0,226,136,0,0,226,152,7,0,227,136,
- 4,0,227,152,11,0,228,136,8,0,228,152,
- 15,0,229,136,12,0,229,152,19,0,162,171,
- 16,0,162,187,23,0,163,171,20,0,163,187,
- 27,0,164,171,24,0,164,187,31,0,165,171,
- 28,0,165,187,16,0,194,44,3,0,64,16,
- 16,0,163,39,33,16,102,0,0,0,64,160,
- 3,131,4,60,112,18,132,36,33,40,224,0,
- 231,58,192,12,16,0,6,36,32,0,191,143,
- 40,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,15,0,2,60,54,66,66,52,
- 24,0,164,175,246,255,132,36,43,16,68,0,
- 3,0,64,16,16,0,191,175,44,1,2,36,
- 24,0,162,175,3,131,4,60,64,18,132,36,
- 24,0,165,39,231,58,192,12,4,0,6,36,
- 24,0,162,143,0,163,1,60,140,1,34,172,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,232,255,189,39,16,0,191,175,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,232,255,189,39,16,0,191,175,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,160,255,189,39,112,0,162,143,
- 72,0,176,175,33,128,224,0,88,0,180,175,
- 33,160,0,0,84,0,179,175,33,152,192,0,
- 92,0,191,175,80,0,178,175,7,0,160,16,
- 76,0,177,175,6,0,65,4,51,0,177,39,
- 45,0,20,36,3,0,0,18,35,16,2,0,
- 255,255,16,38,51,0,177,39,51,0,160,163,
- 27,0,68,0,2,0,128,20,0,0,0,0,
- 13,0,7,0,18,24,0,0,16,16,0,0,
- 2,131,1,60,33,8,34,0,128,205,34,144,
- 255,255,49,38,2,0,0,18,0,0,34,162,
- 255,255,16,38,33,16,96,0,241,255,64,20,
- 1,0,3,36,0,22,19,0,3,22,2,0,
- 11,0,67,20,33,32,128,2,255,255,16,38,
- 255,255,2,36,7,0,2,18,0,0,0,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,33,32,128,2,
- 4,0,128,16,0,22,19,0,196,64,192,12,
- 0,0,0,0,0,22,19,0,3,22,2,0,
- 2,0,3,36,14,0,67,20,255,255,2,36,
- 255,255,16,38,11,0,2,18,255,255,18,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,18,18,0,0,0,0,156,60,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,34,130,0,0,36,146,
- 0,0,0,0,249,255,64,20,1,0,49,38,
- 255,255,49,38,0,22,19,0,3,22,2,0,
- 3,0,3,36,9,0,67,20,255,255,16,38,
- 255,255,2,36,6,0,2,18,255,255,17,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,17,22,0,0,0,0,92,0,191,143,
- 88,0,180,143,84,0,179,143,80,0,178,143,
- 76,0,177,143,72,0,176,143,8,0,224,3,
- 96,0,189,39,200,255,189,39,40,0,178,175,
- 33,144,128,0,32,0,176,175,33,128,160,0,
- 36,0,177,175,33,136,192,0,33,32,32,2,
- 48,0,191,175,156,71,192,12,44,0,179,175,
- 33,32,0,0,33,24,64,0,42,16,112,0,
- 2,0,64,16,33,152,64,2,35,32,3,2,
- 0,22,18,0,3,22,2,0,1,0,3,36,
- 11,0,67,20,33,128,128,0,255,255,16,38,
- 255,255,2,36,8,0,2,18,0,22,19,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,0,0,0,0,
- 0,22,19,0,3,22,2,0,2,0,3,36,
- 14,0,67,20,255,255,2,36,255,255,16,38,
- 11,0,2,18,255,255,18,36,196,64,192,12,
- 48,0,4,36,255,255,16,38,6,0,18,18,
- 0,0,0,0,233,60,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,34,130,0,0,36,146,0,0,0,0,
- 249,255,64,20,1,0,49,38,255,255,49,38,
- 0,22,19,0,3,22,2,0,3,0,3,36,
- 9,0,67,20,255,255,16,38,255,255,2,36,
- 6,0,2,18,255,255,17,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,17,22,
- 0,0,0,0,48,0,191,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,56,0,189,39,32,255,189,39,
- 192,0,178,175,33,144,160,0,196,0,179,175,
- 33,152,0,0,220,0,191,175,216,0,190,175,
- 212,0,183,175,208,0,182,175,204,0,181,175,
- 200,0,180,175,188,0,177,175,184,0,176,175,
- 1,0,130,128,0,0,0,0,229,1,64,16,
- 33,136,0,0,255,255,22,36,1,0,23,36,
- 2,0,30,36,1,0,149,36,0,0,162,146,
- 0,0,0,0,219,255,66,36,0,22,2,0,
- 3,30,2,0,84,0,98,44,217,1,64,16,
- 128,16,3,0,2,131,1,60,33,8,34,0,
- 80,150,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,209,61,192,8,37,0,4,36,
- 2,131,16,60,64,150,16,38,156,71,192,12,
- 33,32,0,2,59,61,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,2,130,0,0,4,146,0,0,0,0,
- 249,255,64,20,1,0,16,38,3,63,192,8,
- 1,0,162,38,0,38,18,0,209,61,192,8,
- 3,38,4,0,2,0,3,36,33,128,32,2,
- 33,40,64,2,33,160,0,0,51,0,177,39,
- 51,0,160,163,27,0,163,0,2,0,96,20,
- 0,0,0,0,13,0,7,0,18,40,0,0,
- 16,16,0,0,2,131,1,60,33,8,34,0,
- 128,205,34,144,255,255,49,38,2,0,0,18,
- 0,0,34,162,255,255,16,38,242,255,160,20,
- 0,0,0,0,10,0,119,22,0,22,20,0,
- 255,255,16,38,8,0,22,18,3,38,2,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,0,22,20,0,
- 3,38,2,0,3,0,128,16,0,0,0,0,
- 196,64,192,12,0,0,0,0,14,0,126,22,
- 0,0,0,0,255,255,16,38,11,0,22,18,
- 255,255,18,36,196,64,192,12,48,0,4,36,
- 255,255,16,38,6,0,18,18,0,0,0,0,
- 111,61,192,8,0,0,0,0,0,38,4,0,
- 196,64,192,12,3,38,4,0,0,0,34,130,
- 0,0,36,146,0,0,0,0,249,255,64,20,
- 1,0,49,38,255,255,49,38,3,0,6,36,
- 80,0,102,22,66,0,4,36,255,255,16,38,
- 77,0,22,18,255,255,17,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,17,22,
- 66,0,4,36,209,61,192,8,0,0,0,0,
- 8,0,3,36,33,128,32,2,33,40,64,2,
- 33,160,0,0,51,0,177,39,51,0,160,163,
- 27,0,163,0,2,0,96,20,0,0,0,0,
- 13,0,7,0,18,40,0,0,16,16,0,0,
- 2,131,1,60,33,8,34,0,128,205,34,144,
- 255,255,49,38,2,0,0,18,0,0,34,162,
- 255,255,16,38,242,255,160,20,0,0,0,0,
- 10,0,119,22,0,22,20,0,255,255,16,38,
- 8,0,22,18,3,38,2,0,255,255,18,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,18,22,0,22,20,0,3,38,2,0,
- 3,0,128,16,0,0,0,0,196,64,192,12,
- 0,0,0,0,14,0,126,22,0,0,0,0,
- 255,255,16,38,11,0,22,18,255,255,18,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,18,18,0,0,0,0,182,61,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,34,130,0,0,36,146,
- 0,0,0,0,249,255,64,20,1,0,49,38,
- 255,255,49,38,3,0,6,36,9,0,102,22,
- 81,0,4,36,255,255,16,38,6,0,22,18,
- 255,255,17,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,17,22,81,0,4,36,
- 196,64,192,12,0,0,0,0,3,63,192,8,
- 1,0,162,38,33,128,32,2,33,16,64,2,
- 33,160,0,0,5,0,65,6,10,0,4,36,
- 45,0,20,36,2,0,32,18,35,16,18,0,
- 255,255,48,38,51,0,177,39,51,0,160,163,
- 27,0,68,0,2,0,128,20,0,0,0,0,
- 13,0,7,0,18,24,0,0,16,16,0,0,
- 2,131,1,60,33,8,34,0,128,205,34,144,
- 255,255,49,38,2,0,0,18,0,0,34,162,
- 255,255,16,38,33,16,96,0,241,255,64,20,
- 0,0,0,0,10,0,119,22,33,32,128,2,
- 255,255,16,38,7,0,22,18,0,0,0,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,33,32,128,2,
- 3,0,128,16,0,0,0,0,196,64,192,12,
- 0,0,0,0,14,0,126,22,0,0,0,0,
- 255,255,16,38,11,0,22,18,255,255,18,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,18,18,0,0,0,0,4,62,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,34,130,0,0,36,146,
- 0,0,0,0,249,255,64,20,1,0,49,38,
- 255,255,49,38,3,0,6,36,237,0,102,22,
- 1,0,162,38,255,255,16,38,234,0,22,18,
- 255,255,17,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,17,22,1,0,162,38,
- 3,63,192,8,0,0,0,0,10,0,3,36,
- 33,128,32,2,33,40,64,2,33,160,0,0,
- 51,0,177,39,51,0,160,163,27,0,163,0,
- 2,0,96,20,0,0,0,0,13,0,7,0,
- 18,40,0,0,16,16,0,0,2,131,1,60,
- 33,8,34,0,128,205,34,144,255,255,49,38,
- 2,0,0,18,0,0,34,162,255,255,16,38,
- 242,255,160,20,0,0,0,0,10,0,119,22,
- 0,22,20,0,255,255,16,38,8,0,22,18,
- 3,38,2,0,255,255,18,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,18,22,
- 0,22,20,0,3,38,2,0,3,0,128,16,
- 0,0,0,0,196,64,192,12,0,0,0,0,
- 14,0,126,22,0,0,0,0,255,255,16,38,
- 11,0,22,18,255,255,18,36,196,64,192,12,
- 48,0,4,36,255,255,16,38,6,0,18,18,
- 0,0,0,0,75,62,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,34,130,0,0,36,146,0,0,0,0,
- 249,255,64,20,1,0,49,38,255,255,49,38,
- 3,0,6,36,166,0,102,22,1,0,162,38,
- 255,255,16,38,163,0,22,18,255,255,17,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,17,22,1,0,162,38,3,63,192,8,
- 0,0,0,0,192,132,144,39,156,71,192,12,
- 33,32,0,2,112,62,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,2,130,0,0,4,146,0,0,0,0,
- 249,255,64,20,1,0,16,38,16,0,3,36,
- 33,128,32,2,33,40,64,2,33,160,0,0,
- 51,0,177,39,51,0,160,163,27,0,163,0,
- 2,0,96,20,0,0,0,0,13,0,7,0,
- 18,40,0,0,16,16,0,0,2,131,1,60,
- 33,8,34,0,128,205,34,144,255,255,49,38,
- 2,0,0,18,0,0,34,162,255,255,16,38,
- 242,255,160,20,0,0,0,0,10,0,119,22,
- 0,22,20,0,255,255,16,38,8,0,22,18,
- 3,38,2,0,255,255,18,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,18,22,
- 0,22,20,0,3,38,2,0,3,0,128,16,
- 0,0,0,0,196,64,192,12,0,0,0,0,
- 14,0,126,22,0,0,0,0,255,255,16,38,
- 11,0,22,18,255,255,18,36,196,64,192,12,
- 48,0,4,36,255,255,16,38,6,0,18,18,
- 0,0,0,0,159,62,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,34,130,0,0,36,146,0,0,0,0,
- 249,255,64,20,1,0,49,38,255,255,49,38,
- 3,0,6,36,82,0,102,22,1,0,162,38,
- 255,255,16,38,79,0,22,18,255,255,17,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,17,22,1,0,162,38,3,63,192,8,
- 0,0,0,0,156,71,192,12,33,32,64,2,
- 33,24,64,0,42,16,113,0,2,0,64,16,
- 33,32,0,0,35,32,35,2,10,0,119,22,
- 33,128,128,0,255,255,16,38,7,0,22,18,
- 0,0,0,0,255,255,17,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,17,22,
- 0,0,0,0,14,0,126,22,0,0,0,0,
- 255,255,16,38,11,0,22,18,255,255,17,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,17,18,0,0,0,0,211,62,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,66,130,0,0,68,146,
- 0,0,0,0,249,255,64,20,1,0,82,38,
- 255,255,82,38,3,0,6,36,30,0,102,22,
- 1,0,162,38,255,255,16,38,27,0,22,18,
- 255,255,17,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,17,22,1,0,162,38,
- 3,63,192,8,0,0,0,0,253,62,192,8,
- 3,0,19,36,3,0,96,22,128,16,17,0,
- 2,0,19,36,128,16,17,0,33,16,81,0,
- 64,16,2,0,0,0,163,130,208,255,66,36,
- 2,0,96,22,33,136,67,0,1,0,19,36,
- 1,0,181,38,0,0,162,130,0,0,0,0,
- 33,254,64,20,0,0,0,0,1,0,130,36,
- 220,0,191,143,216,0,190,143,212,0,183,143,
- 208,0,182,143,204,0,181,143,200,0,180,143,
- 196,0,179,143,192,0,178,143,188,0,177,143,
- 184,0,176,143,8,0,224,3,224,0,189,39,
- 0,0,164,175,4,0,165,175,8,0,166,175,
- 12,0,167,175,200,255,189,39,59,0,162,39,
- 252,255,3,36,36,16,67,0,52,0,191,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,56,0,164,175,
- 0,0,80,140,4,0,81,36,0,0,2,130,
- 0,0,3,146,0,0,0,0,31,0,64,16,
- 37,0,20,36,69,0,19,36,252,255,18,36,
- 0,22,3,0,3,38,2,0,18,0,148,20,
- 0,0,0,0,1,0,3,130,0,0,0,0,
- 4,0,100,16,33,32,0,2,4,0,115,20,
- 3,0,34,38,33,32,0,2,56,63,192,8,
- 33,40,0,0,36,16,82,0,4,0,81,36,
- 0,0,69,140,33,32,0,2,13,61,192,12,
- 0,0,0,0,62,63,192,8,33,128,64,0,
- 196,64,192,12,1,0,16,38,0,0,2,130,
- 0,0,3,146,0,0,0,0,230,255,64,20,
- 0,22,3,0,52,0,191,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,56,0,189,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,0,0,0,0,0,0,
- 0,0,0,0,8,0,224,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,8,0,224,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,
- 8,0,224,3,0,0,0,0,33,72,224,3,
- 170,3,8,36,76,63,192,12,0,0,0,0,
- 255,255,8,33,252,255,0,21,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,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,0,32,1,
- 0,0,0,0,33,88,224,3,232,3,10,36,
- 143,63,192,12,0,0,0,0,255,255,74,33,
- 252,255,64,21,0,0,0,0,8,0,96,1,
- 0,0,0,0,250,255,132,32,130,32,4,0,
- 255,255,132,32,0,0,0,0,253,255,128,20,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 248,255,189,39,255,255,195,36,10,0,192,16,
- 33,56,160,0,255,255,6,36,0,0,162,144,
- 1,0,165,36,0,0,130,160,4,0,64,16,
- 1,0,132,36,255,255,99,36,249,255,102,20,
- 0,0,0,0,33,16,224,0,8,0,224,3,
- 8,0,189,39,0,96,2,64,0,0,0,0,
- 38,64,68,0,1,255,8,49,38,64,2,1,
- 0,96,136,64,8,0,224,3,1,255,66,48,
- 0,96,2,64,0,0,0,0,1,255,132,48,
- 39,32,128,0,36,64,68,0,0,96,136,64,
- 8,0,224,3,1,255,66,48,0,96,2,64,
- 0,0,0,0,0,255,132,48,37,64,68,0,
- 1,0,8,53,0,96,136,64,8,0,224,3,
- 1,255,66,48,176,255,189,39,64,0,182,175,
- 33,176,128,0,52,0,179,175,33,152,160,0,
- 72,0,190,175,33,240,192,0,68,0,183,175,
- 33,184,224,0,60,0,181,175,33,168,0,0,
- 56,0,180,175,33,160,0,0,76,0,191,175,
- 48,0,178,175,44,0,177,175,40,0,176,175,
- 2,131,6,60,33,48,212,0,160,205,198,144,
- 0,0,0,0,28,0,96,26,33,128,0,0,
- 33,24,192,2,33,32,118,2,0,0,102,160,
- 1,0,99,36,42,16,100,0,252,255,64,20,
- 0,0,0,0,19,0,96,26,33,128,0,0,
- 255,0,210,48,33,136,192,2,0,0,39,146,
- 0,0,0,0,9,0,242,16,0,0,0,0,
- 5,0,224,18,33,40,0,2,96,0,164,143,
- 0,0,0,0,9,248,224,2,33,48,64,2,
- 32,0,192,23,1,0,181,38,1,0,16,38,
- 42,16,19,2,241,255,64,20,1,0,49,38,
- 1,0,148,38,4,0,130,46,220,255,64,20,
- 0,0,0,0,7,0,96,26,33,128,0,0,
- 33,24,192,2,0,0,112,160,1,0,16,38,
- 42,16,19,2,252,255,64,20,1,0,99,36,
- 20,0,96,26,33,128,0,0,33,136,192,2,
- 0,0,39,146,255,0,6,50,11,0,230,16,
- 0,0,0,0,5,0,224,18,0,0,0,0,
- 96,0,164,143,0,0,0,0,9,248,224,2,
- 33,40,0,2,3,0,192,19,1,0,181,38,
- 72,64,192,8,1,0,2,36,1,0,16,38,
- 42,16,19,2,239,255,64,20,1,0,49,38,
- 33,16,160,2,76,0,191,143,72,0,190,143,
- 68,0,183,143,64,0,182,143,60,0,181,143,
- 56,0,180,143,52,0,179,143,48,0,178,143,
- 44,0,177,143,40,0,176,143,8,0,224,3,
- 80,0,189,39,160,255,189,39,88,0,190,175,
- 33,240,128,0,68,0,179,175,33,152,160,0,
- 76,0,181,175,33,168,224,0,72,0,180,175,
- 33,160,0,0,33,16,96,2,92,0,191,175,
- 84,0,183,175,80,0,182,175,64,0,178,175,
- 60,0,177,175,56,0,176,175,2,0,97,6,
- 16,0,166,175,3,0,98,38,131,152,2,0,
- 33,184,0,0,2,131,22,60,164,205,214,38,
- 0,0,210,142,0,0,0,0,7,0,96,18,
- 33,128,0,0,33,24,192,3,0,0,114,172,
- 1,0,16,38,43,16,19,2,252,255,64,20,
- 4,0,99,36,20,0,96,18,33,128,0,0,
- 33,136,192,3,0,0,39,142,0,0,0,0,
- 11,0,242,16,128,40,16,0,5,0,160,18,
- 0,0,0,0,112,0,164,143,0,0,0,0,
- 9,248,160,2,33,48,64,2,16,0,168,143,
- 0,0,0,0,34,0,0,21,1,0,148,38,
- 1,0,16,38,43,16,19,2,239,255,64,20,
- 4,0,49,38,1,0,247,38,4,0,226,46,
- 222,255,64,20,4,0,214,38,7,0,96,18,
- 33,128,0,0,33,24,192,3,0,0,112,172,
- 1,0,16,38,43,16,19,2,252,255,64,20,
- 4,0,99,36,22,0,96,18,33,128,0,0,
- 33,136,192,3,0,0,39,142,0,0,0,0,
- 13,0,240,16,128,40,16,0,5,0,160,18,
- 0,0,0,0,112,0,164,143,0,0,0,0,
- 9,248,160,2,33,48,0,2,16,0,168,143,
- 0,0,0,0,3,0,0,17,1,0,148,38,
- 174,64,192,8,1,0,2,36,1,0,16,38,
- 43,16,19,2,237,255,64,20,4,0,49,38,
- 33,16,128,2,92,0,191,143,88,0,190,143,
- 84,0,183,143,80,0,182,143,76,0,181,143,
- 72,0,180,143,68,0,179,143,64,0,178,143,
- 60,0,177,143,56,0,176,143,8,0,224,3,
- 96,0,189,39,0,0,0,0,0,0,0,0,
- 255,1,2,36,0,163,1,60,176,1,32,172,
- 0,163,1,60,180,1,32,172,0,163,1,60,
- 8,0,224,3,184,1,34,172,232,255,189,39,
- 16,0,176,175,33,128,128,0,20,0,191,175,
- 220,63,192,12,33,32,0,0,33,40,64,0,
- 0,163,3,60,180,1,99,140,0,163,2,60,
- 184,1,66,140,0,163,4,60,128,1,132,140,
- 1,0,99,36,11,0,128,20,36,24,98,0,
- 0,163,2,60,176,1,66,140,0,0,0,0,
- 6,0,98,20,0,0,0,0,0,163,2,60,
- 128,1,66,140,0,0,0,0,247,255,64,16,
- 0,0,0,0,0,163,2,60,180,1,66,140,
- 33,32,160,0,0,163,1,60,33,8,34,0,
- 188,1,48,160,0,163,1,60,220,63,192,12,
- 180,1,35,172,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,192,255,189,39,33,80,0,0,
- 80,0,185,143,84,0,184,143,88,0,175,143,
- 1,0,2,36,60,0,177,175,92,0,177,143,
- 4,112,226,0,12,0,224,24,56,0,176,175,
- 1,0,9,36,33,64,160,3,33,24,32,3,
- 0,0,98,140,4,0,99,36,1,0,74,37,
- 4,16,73,0,0,0,2,173,42,16,71,1,
- 249,255,64,20,4,0,8,37,46,0,192,25,
- 33,80,0,0,255,0,16,36,33,72,0,0,
- 0,0,145,172,0,0,160,164,34,0,224,24,
- 0,0,208,160,33,88,128,0,33,96,160,0,
- 33,104,192,0,33,64,32,3,33,24,160,3,
- 0,0,98,140,0,0,0,0,36,16,66,1,
- 19,0,64,16,0,0,0,0,0,0,2,141,
- 0,0,0,0,128,16,2,0,33,16,88,0,
- 0,0,66,140,0,0,0,0,0,0,98,173,
- 0,0,2,141,0,0,0,0,64,16,2,0,
- 33,16,79,0,0,0,66,148,0,0,0,0,
- 0,0,130,165,0,0,2,141,0,0,0,0,
- 47,65,192,8,0,0,162,161,4,0,8,37,
- 1,0,41,37,42,16,39,1,229,255,64,20,
- 4,0,99,36,1,0,198,36,2,0,165,36,
- 1,0,74,37,42,16,78,1,213,255,64,20,
- 4,0,132,36,60,0,177,143,56,0,176,143,
- 8,0,224,3,64,0,189,39,0,0,0,0,
- 0,0,0,0,0,0,0,0,216,255,189,39,
- 63,0,132,48,28,0,179,175,128,1,147,52,
- 50,133,130,151,48,133,132,151,0,128,131,151,
- 20,0,177,175,16,0,176,175,5,162,16,60,
- 32,0,191,175,24,0,178,175,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,51,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,96,65,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,51,2,33,136,0,0,16,0,16,36,
- 5,162,18,60,255,255,19,36,76,63,192,12,
- 0,0,0,0,0,128,131,151,50,133,130,151,
- 0,0,0,0,37,24,98,0,0,128,131,167,
- 76,63,192,12,0,0,67,166,8,0,0,18,
- 0,0,0,0,0,0,67,150,20,133,130,151,
- 0,0,0,0,36,16,67,0,2,0,64,16,
- 64,136,17,0,1,0,49,54,76,63,192,12,
- 255,255,16,38,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 230,255,19,22,0,0,67,166,48,133,130,151,
- 0,128,131,151,39,16,2,0,36,24,98,0,
- 5,162,2,60,0,128,131,167,0,0,67,164,
- 255,255,34,50,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,208,255,189,39,
- 36,0,181,175,33,168,160,0,32,0,180,175,
- 63,0,148,48,33,32,128,2,44,0,191,175,
- 40,0,182,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,60,65,192,12,16,0,176,175,
- 33,152,64,0,255,255,163,50,255,255,98,50,
- 3,0,98,20,48,1,22,36,245,66,192,8,
- 1,0,2,36,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,54,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,210,65,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,54,2,255,255,163,50,255,255,98,50,
- 39,16,2,0,36,24,98,0,84,0,96,16,
- 192,1,147,54,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,51,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,8,66,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,51,2,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,76,63,192,12,
- 0,0,3,166,0,128,131,151,48,133,130,151,
- 0,0,0,0,37,24,98,0,0,0,3,166,
- 0,0,4,150,20,133,130,151,0,128,131,167,
- 36,16,68,0,9,0,64,20,0,0,0,0,
- 76,63,192,12,0,0,0,0,0,0,3,150,
- 20,133,130,151,0,0,0,0,36,16,67,0,
- 249,255,64,16,0,0,0,0,48,133,130,151,
- 0,128,131,151,39,16,2,0,36,24,98,0,
- 5,162,2,60,0,128,131,167,0,0,67,164,
- 255,255,163,50,255,255,2,52,125,0,98,16,
- 64,1,147,54,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,51,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,95,66,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,51,2,33,144,160,2,0,128,16,52,
- 0,128,130,151,48,133,131,151,5,162,17,60,
- 37,16,67,0,5,162,3,60,0,128,130,167,
- 0,0,98,164,36,16,18,2,6,0,64,16,
- 0,0,0,0,0,128,131,151,20,133,130,151,
- 0,0,0,0,136,66,192,8,37,24,98,0,
- 20,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,0,128,131,167,0,0,35,166,
- 76,63,192,12,66,128,16,0,0,128,130,151,
- 50,133,131,151,0,0,0,0,37,16,67,0,
- 0,128,130,167,76,63,192,12,0,0,34,166,
- 50,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,255,255,2,50,0,128,131,167,
- 0,0,35,166,226,255,64,20,36,16,18,2,
- 5,162,16,60,50,133,130,151,48,133,132,151,
- 0,128,131,151,39,16,68,0,36,24,98,0,
- 0,128,131,167,76,63,192,12,0,0,3,166,
- 0,128,131,151,48,133,130,151,0,0,0,0,
- 37,24,98,0,0,0,3,166,0,0,4,150,
- 20,133,130,151,0,128,131,167,36,16,68,0,
- 9,0,64,20,0,0,0,0,76,63,192,12,
- 0,0,0,0,0,0,3,150,20,133,130,151,
- 0,0,0,0,36,16,67,0,249,255,64,16,
- 0,0,0,0,48,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,5,162,2,60,
- 0,128,131,167,0,0,67,164,0,1,19,36,
- 5,162,16,60,50,133,130,151,48,133,132,151,
- 0,128,131,151,39,16,68,0,36,24,98,0,
- 0,128,131,167,0,0,3,166,76,63,192,12,
- 0,1,17,36,0,128,130,151,48,133,131,151,
- 5,162,18,60,37,16,67,0,0,128,130,167,
- 0,0,2,166,36,16,113,2,6,0,64,16,
- 0,0,0,0,0,128,131,151,20,133,130,151,
- 0,0,0,0,220,66,192,8,37,24,98,0,
- 20,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,0,128,131,167,0,0,67,166,
- 76,63,192,12,66,136,17,0,0,128,130,151,
- 50,133,131,151,0,0,0,0,37,16,67,0,
- 0,128,130,167,76,63,192,12,0,0,66,166,
- 50,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,255,255,34,50,0,128,131,167,
- 0,0,67,166,226,255,64,20,36,16,113,2,
- 60,65,192,12,33,32,128,2,38,16,162,2,
- 255,255,66,48,1,0,66,44,44,0,191,143,
- 40,0,182,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,24,0,178,175,33,144,0,0,
- 64,16,4,0,16,0,176,175,33,128,68,0,
- 33,32,0,2,20,0,177,175,255,255,177,48,
- 28,0,191,175,162,65,192,12,33,40,32,2,
- 8,0,64,16,1,0,4,38,162,65,192,12,
- 33,40,32,2,4,0,64,16,2,0,4,38,
- 162,65,192,12,33,40,32,2,43,144,2,0,
- 33,16,64,2,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,216,255,189,39,64,16,4,0,
- 24,0,178,175,33,144,68,0,33,32,64,2,
- 36,0,191,175,32,0,180,175,28,0,179,175,
- 20,0,177,175,60,65,192,12,16,0,176,175,
- 1,0,84,38,33,32,128,2,60,65,192,12,
- 33,136,64,0,2,0,83,38,33,32,96,2,
- 60,65,192,12,33,128,64,0,255,255,35,50,
- 255,255,17,50,8,0,113,20,0,0,0,0,
- 255,255,66,48,3,0,34,18,33,32,96,2,
- 162,65,192,12,33,40,32,2,66,67,192,8,
- 33,16,32,2,255,255,80,48,4,0,112,16,
- 33,32,128,2,5,0,48,22,255,255,2,36,
- 33,32,64,2,162,65,192,12,33,40,0,2,
- 33,16,0,2,36,0,191,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 0,0,0,0,0,0,0,0,0,96,8,64,
- 0,0,0,0,254,255,1,36,36,72,1,1,
- 0,96,137,64,0,0,133,164,2,0,132,32,
- 2,44,5,0,0,0,133,164,0,96,136,64,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 32,0,178,175,33,144,128,0,28,0,177,175,
- 33,136,160,0,36,0,179,175,33,152,192,0,
- 40,0,180,175,33,160,224,0,44,0,191,175,
- 2,0,32,22,24,0,176,175,255,255,17,36,
- 0,0,66,142,0,0,0,0,36,16,81,0,
- 3,0,83,20,0,0,0,0,121,67,192,8,
- 1,0,2,36,11,0,128,26,33,128,0,0,
- 143,63,192,12,0,0,0,0,0,0,66,142,
- 0,0,0,0,36,16,81,0,246,255,83,16,
- 1,0,16,38,42,16,20,2,247,255,64,20,
- 0,0,0,0,33,16,0,0,44,0,191,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 48,0,189,39,208,255,189,39,32,0,178,175,
- 33,144,128,0,28,0,177,175,33,136,160,0,
- 36,0,179,175,33,152,192,0,40,0,180,175,
- 33,160,224,0,44,0,191,175,2,0,32,22,
- 24,0,176,175,255,255,17,52,0,0,66,150,
- 0,0,0,0,36,16,81,0,3,0,83,20,
- 0,0,0,0,162,67,192,8,1,0,2,36,
- 11,0,128,26,33,128,0,0,143,63,192,12,
- 0,0,0,0,0,0,66,150,0,0,0,0,
- 36,16,81,0,246,255,83,16,1,0,16,38,
- 42,16,20,2,247,255,64,20,0,0,0,0,
- 33,16,0,0,44,0,191,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 208,255,189,39,32,0,178,175,33,144,128,0,
- 28,0,177,175,33,136,160,0,36,0,179,175,
- 33,152,192,0,40,0,180,175,33,160,224,0,
- 44,0,191,175,2,0,32,22,24,0,176,175,
- 255,0,17,36,0,0,66,146,0,0,0,0,
- 36,16,81,0,3,0,83,20,0,0,0,0,
- 203,67,192,8,1,0,2,36,11,0,128,26,
- 33,128,0,0,143,63,192,12,0,0,0,0,
- 0,0,66,146,0,0,0,0,36,16,81,0,
- 246,255,83,16,1,0,16,38,42,16,20,2,
- 247,255,64,20,0,0,0,0,33,16,0,0,
- 44,0,191,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,208,255,189,39,
- 32,0,178,175,33,144,128,0,28,0,177,175,
- 33,136,160,0,36,0,179,175,33,152,192,0,
- 40,0,180,175,33,160,224,0,44,0,191,175,
- 2,0,32,22,24,0,176,175,255,255,17,36,
- 0,0,66,142,0,0,0,0,36,16,81,0,
- 3,0,83,20,0,0,0,0,244,67,192,8,
- 1,0,2,36,11,0,128,26,33,128,0,0,
- 143,63,192,12,0,0,0,0,0,0,66,142,
- 0,0,0,0,36,16,81,0,246,255,83,20,
- 1,0,16,38,42,16,20,2,247,255,64,20,
- 0,0,0,0,33,16,0,0,44,0,191,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 48,0,189,39,208,255,189,39,32,0,178,175,
- 33,144,128,0,28,0,177,175,33,136,160,0,
- 36,0,179,175,33,152,192,0,40,0,180,175,
- 33,160,224,0,44,0,191,175,2,0,32,22,
- 24,0,176,175,255,255,17,52,0,0,66,150,
- 0,0,0,0,36,16,81,0,3,0,83,20,
- 0,0,0,0,29,68,192,8,1,0,2,36,
- 11,0,128,26,33,128,0,0,143,63,192,12,
- 0,0,0,0,0,0,66,150,0,0,0,0,
- 36,16,81,0,246,255,83,20,1,0,16,38,
- 42,16,20,2,247,255,64,20,0,0,0,0,
- 33,16,0,0,44,0,191,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 208,255,189,39,32,0,178,175,33,144,128,0,
- 28,0,177,175,33,136,160,0,36,0,179,175,
- 33,152,192,0,40,0,180,175,33,160,224,0,
- 44,0,191,175,2,0,32,22,24,0,176,175,
- 255,0,17,36,0,0,66,146,0,0,0,0,
- 36,16,81,0,3,0,83,20,0,0,0,0,
- 70,68,192,8,1,0,2,36,11,0,128,26,
- 33,128,0,0,143,63,192,12,0,0,0,0,
- 0,0,66,146,0,0,0,0,36,16,81,0,
- 246,255,83,20,1,0,16,38,42,16,20,2,
- 247,255,64,20,0,0,0,0,33,16,0,0,
- 44,0,191,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,0,0,0,0,
- 0,0,0,0,248,255,189,39,255,255,195,36,
- 8,0,192,16,33,56,128,0,255,255,6,36,
- 0,0,162,144,1,0,165,36,255,255,99,36,
- 0,0,130,160,251,255,102,20,1,0,132,36,
- 33,16,224,0,8,0,224,3,8,0,189,39,
- 0,0,0,0,0,0,0,0,0,96,8,64,
- 1,0,9,60,0,96,137,64,15,0,138,48,
- 33,40,170,0,192,255,165,36,0,0,128,160,
- 16,0,128,160,32,0,128,160,251,255,160,28,
- 48,0,128,160,64,0,132,36,0,96,136,64,
- 0,0,0,0,0,0,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,1,131,2,60,
- 224,17,66,36,0,32,9,60,37,16,73,0,
- 8,0,64,0,0,0,0,0,0,96,8,64,
- 3,0,9,60,0,96,137,64,15,0,138,48,
- 33,40,170,0,192,255,165,36,0,0,128,160,
- 16,0,128,160,32,0,128,160,251,255,160,28,
- 48,0,128,160,64,0,132,36,0,96,136,64,
- 0,0,0,0,0,0,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,163,3,60,192,3,99,140,
- 0,163,2,60,188,3,66,140,0,0,0,0,
- 16,0,98,16,255,255,2,36,0,163,2,60,
- 188,3,66,140,0,163,1,60,33,8,34,0,
- 200,3,34,144,0,163,3,60,188,3,99,140,
- 0,163,4,60,196,3,132,140,0,22,2,0,
- 3,22,2,0,1,0,99,36,36,24,100,0,
- 0,163,1,60,188,3,35,172,8,0,224,3,
- 0,0,0,0,0,163,6,60,0,1,198,52,
- 10,0,9,36,255,255,8,36,13,0,7,36,
- 0,163,3,60,192,3,99,140,0,163,2,60,
- 188,3,66,140,0,0,0,0,17,0,98,16,
- 255,255,5,36,0,163,2,60,188,3,66,140,
- 0,0,0,0,33,16,70,0,200,2,66,144,
- 0,0,0,0,0,22,2,0,3,46,2,0,
- 0,163,2,60,188,3,66,140,0,163,3,60,
- 196,3,99,140,1,0,66,36,36,16,67,0,
- 0,163,1,60,188,3,34,172,11,0,169,16,
- 11,0,162,40,5,0,64,16,0,0,0,0,
- 228,255,168,16,0,0,0,0,206,68,192,8,
- 0,0,133,160,224,255,167,16,0,0,0,0,
- 206,68,192,8,0,0,133,160,208,68,192,8,
- 0,0,128,160,169,68,192,8,1,0,132,36,
- 8,0,224,3,0,0,0,0,0,0,0,0,
- 0,0,0,0,208,255,189,39,24,0,176,175,
- 33,128,128,0,36,0,179,175,33,152,160,0,
- 28,0,177,175,33,136,0,0,32,0,178,175,
- 33,144,0,2,5,0,64,22,40,0,191,175,
- 54,0,96,22,33,16,0,0,22,69,192,8,
- 0,0,32,174,0,0,67,130,0,0,0,0,
- 233,68,192,8,32,0,2,36,0,0,3,130,
- 32,0,2,36,253,255,98,16,1,0,16,38,
- 255,255,16,38,9,0,2,36,249,255,98,16,
- 1,0,16,38,255,255,16,38,0,0,3,130,
- 45,0,2,36,4,0,98,20,43,0,2,36,
- 1,0,16,38,250,68,192,8,1,0,17,36,
- 3,0,98,20,33,32,0,2,1,0,16,38,
- 33,32,0,2,44,69,192,12,16,0,165,39,
- 7,0,96,18,33,24,64,0,16,0,162,143,
- 0,0,0,0,2,0,80,20,0,0,0,0,
- 33,16,64,2,0,0,98,174,6,0,32,18,
- 0,128,2,60,43,16,67,0,5,0,64,20,
- 255,127,2,60,19,69,192,8,33,16,96,0,
- 5,0,97,4,255,127,2,60,7,0,32,18,
- 255,255,66,52,22,69,192,8,0,128,2,60,
- 33,16,96,0,2,0,32,18,0,0,0,0,
- 35,16,2,0,40,0,191,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,0,0,0,0,
- 0,0,0,0,0,0,0,0,208,255,130,36,
- 10,0,66,44,7,0,64,20,1,0,2,36,
- 191,255,130,36,6,0,66,44,3,0,64,20,
- 1,0,2,36,159,255,130,36,6,0,66,44,
- 8,0,224,3,0,0,0,0,248,255,189,39,
- 0,0,176,175,33,56,0,0,33,72,0,0,
- 33,80,0,0,33,112,0,0,5,0,128,20,
- 33,200,128,0,110,0,160,20,33,16,0,0,
- 163,69,192,8,0,0,192,173,0,0,131,128,
- 32,0,2,36,253,255,98,16,1,0,132,36,
- 255,255,132,36,9,0,2,36,249,255,98,16,
- 1,0,132,36,255,255,132,36,0,0,131,128,
- 43,0,2,36,3,0,98,20,45,0,2,36,
- 75,69,192,8,1,0,132,36,3,0,98,20,
- 0,0,0,0,1,0,132,36,1,0,14,36,
- 3,0,192,16,16,0,2,36,16,0,194,20,
- 0,0,0,0,0,0,131,128,48,0,2,36,
- 9,0,98,20,10,0,2,36,1,0,131,128,
- 88,0,2,36,3,0,98,16,120,0,2,36,
- 3,0,98,20,8,0,2,36,16,0,2,36,
- 2,0,132,36,2,0,192,20,0,0,0,0,
- 33,48,64,0,0,0,131,128,255,255,2,36,
- 27,0,70,0,2,0,192,20,0,0,0,0,
- 13,0,7,0,18,64,0,0,16,192,0,0,
- 0,0,0,0,0,0,0,0,42,0,96,16,
- 48,0,98,44,48,0,207,36,11,0,205,40,
- 87,0,204,36,55,0,203,36,5,0,64,20,
- 43,16,111,0,3,0,64,16,0,0,0,0,
- 130,69,192,8,208,255,99,36,30,0,160,21,
- 97,0,98,44,6,0,64,20,65,0,98,44,
- 43,16,108,0,3,0,64,16,65,0,98,44,
- 130,69,192,8,169,255,99,36,21,0,64,20,
- 43,16,107,0,19,0,64,16,0,0,0,0,
- 201,255,99,36,43,16,7,1,6,0,64,20,
- 1,0,9,36,6,0,232,20,24,0,230,0,
- 43,16,3,3,3,0,64,16,0,0,0,0,
- 1,0,10,36,24,0,230,0,1,0,132,36,
- 18,128,0,0,33,56,3,2,0,0,131,128,
- 0,0,0,0,220,255,96,20,48,0,98,44,
- 5,0,64,17,0,0,0,0,13,0,160,16,
- 255,255,2,36,163,69,192,8,0,0,164,172,
- 6,0,160,16,0,0,0,0,3,0,32,21,
- 0,0,0,0,160,69,192,8,0,0,185,172,
- 0,0,164,172,2,0,192,17,33,16,224,0,
- 35,16,2,0,0,0,176,143,8,0,224,3,
- 8,0,189,39,0,0,0,0,0,0,0,0,
- 200,255,189,39,16,0,176,175,7,162,16,60,
- 236,0,16,54,255,240,3,60,255,255,99,52,
- 63,0,132,48,36,0,181,175,128,1,149,52,
- 24,0,178,175,0,1,18,36,20,0,177,175,
- 7,162,17,60,236,0,49,54,44,0,183,175,
- 0,4,23,60,32,0,180,175,255,251,20,60,
- 255,255,148,54,40,0,182,175,0,1,22,60,
- 28,0,179,175,255,254,19,60,48,0,191,175,
- 0,0,2,142,0,0,0,0,36,16,67,0,
- 224,133,130,175,0,0,2,174,76,63,192,12,
- 255,255,115,54,224,133,130,143,0,2,3,60,
- 37,16,67,0,224,133,130,175,0,0,2,174,
- 36,16,85,2,5,0,64,16,0,0,0,0,
- 224,133,130,143,0,0,0,0,214,69,192,8,
- 37,16,87,0,224,133,130,143,0,0,0,0,
- 36,16,84,0,224,133,130,175,76,63,192,12,
- 0,0,34,174,224,133,130,143,0,0,0,0,
- 37,16,86,0,224,133,130,175,0,0,34,174,
- 76,63,192,12,66,144,18,0,224,133,130,143,
- 0,0,0,0,36,16,83,0,224,133,130,175,
- 0,0,34,174,255,255,66,50,230,255,64,20,
- 36,16,85,2,33,136,0,0,16,0,16,36,
- 7,162,18,60,236,0,82,54,0,1,22,60,
- 0,8,21,60,255,254,19,60,255,255,115,54,
- 255,255,20,36,76,63,192,12,0,0,0,0,
- 224,133,130,143,0,0,0,0,37,16,86,0,
- 224,133,130,175,76,63,192,12,0,0,66,174,
- 7,0,0,18,0,0,0,0,0,0,66,142,
- 0,0,0,0,36,16,85,0,2,0,64,16,
- 64,136,17,0,1,0,49,54,76,63,192,12,
- 255,255,16,38,224,133,130,143,0,0,0,0,
- 36,16,83,0,224,133,130,175,0,0,66,174,
- 232,255,20,22,7,162,4,60,236,0,132,52,
- 255,253,3,60,224,133,130,143,255,255,99,52,
- 36,16,67,0,224,133,130,175,0,0,130,172,
- 255,255,34,50,48,0,191,143,44,0,183,143,
- 40,0,182,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,48,0,190,175,33,240,160,0,
- 40,0,182,175,63,0,150,48,33,32,192,2,
- 52,0,191,175,44,0,183,175,36,0,181,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,168,69,192,12,16,0,176,175,
- 33,152,64,0,255,255,195,51,255,255,98,50,
- 3,0,98,20,7,162,16,60,131,71,192,8,
- 1,0,2,36,236,0,16,54,255,252,3,60,
- 255,255,99,52,0,1,18,36,7,162,17,60,
- 236,0,49,54,255,251,21,60,255,255,181,54,
- 0,1,23,60,255,254,20,60,224,133,130,143,
- 0,0,0,0,36,16,67,0,224,133,130,175,
- 0,0,2,174,76,63,192,12,255,255,148,54,
- 224,133,130,143,0,2,3,60,37,16,67,0,
- 224,133,130,175,0,0,2,174,48,1,66,50,
- 5,0,64,16,0,4,6,60,224,133,130,143,
- 0,0,0,0,83,70,192,8,37,16,70,0,
- 224,133,130,143,0,0,0,0,36,16,85,0,
- 224,133,130,175,76,63,192,12,0,0,34,174,
- 224,133,130,143,0,0,0,0,37,16,87,0,
- 224,133,130,175,0,0,34,174,76,63,192,12,
- 66,144,18,0,224,133,130,143,0,0,0,0,
- 36,16,84,0,224,133,130,175,0,0,34,174,
- 255,255,66,50,230,255,64,20,48,1,66,50,
- 255,255,195,51,255,255,98,50,39,16,2,0,
- 36,24,98,0,88,0,96,16,192,1,213,54,
- 7,162,16,60,236,0,16,54,255,252,3,60,
- 255,255,99,52,0,1,18,36,7,162,17,60,
- 236,0,49,54,255,251,20,60,255,255,148,54,
- 0,1,23,60,255,254,19,60,224,133,130,143,
- 0,0,0,0,36,16,67,0,224,133,130,175,
- 0,0,2,174,76,63,192,12,255,255,115,54,
- 224,133,130,143,0,2,3,60,37,16,67,0,
- 224,133,130,175,0,0,2,174,36,16,85,2,
- 5,0,64,16,0,4,6,60,224,133,130,143,
- 0,0,0,0,140,70,192,8,37,16,70,0,
- 224,133,130,143,0,0,0,0,36,16,84,0,
- 224,133,130,175,76,63,192,12,0,0,34,174,
- 224,133,130,143,0,0,0,0,37,16,87,0,
- 224,133,130,175,0,0,34,174,76,63,192,12,
- 66,144,18,0,224,133,130,143,0,0,0,0,
- 36,16,83,0,224,133,130,175,0,0,34,174,
- 255,255,66,50,230,255,64,20,36,16,85,2,
- 7,162,16,60,236,0,16,54,255,252,3,60,
- 224,133,130,143,255,255,99,52,36,16,67,0,
- 224,133,130,175,76,63,192,12,0,0,2,174,
- 224,133,130,143,0,2,3,60,37,16,67,0,
- 224,133,130,175,0,0,2,174,0,0,2,142,
- 0,8,3,60,36,16,67,0,11,0,64,20,
- 7,162,4,60,7,162,16,60,236,0,16,54,
- 0,8,17,60,76,63,192,12,0,0,0,0,
- 0,0,2,142,0,0,0,0,36,16,81,0,
- 250,255,64,16,7,162,4,60,236,0,132,52,
- 255,253,3,60,224,133,130,143,255,255,99,52,
- 36,16,67,0,224,133,130,175,0,0,130,172,
- 255,255,195,51,255,255,2,52,133,0,98,16,
- 64,1,213,54,7,162,16,60,236,0,16,54,
- 255,252,3,60,255,255,99,52,0,1,18,36,
- 7,162,17,60,236,0,49,54,255,251,20,60,
- 255,255,148,54,0,1,23,60,255,254,19,60,
- 224,133,130,143,0,0,0,0,36,16,67,0,
- 224,133,130,175,0,0,2,174,76,63,192,12,
- 255,255,115,54,224,133,130,143,0,2,3,60,
- 37,16,67,0,224,133,130,175,0,0,2,174,
- 36,16,85,2,5,0,64,16,0,4,6,60,
- 224,133,130,143,0,0,0,0,231,70,192,8,
- 37,16,70,0,224,133,130,143,0,0,0,0,
- 36,16,84,0,224,133,130,175,76,63,192,12,
- 0,0,34,174,224,133,130,143,0,0,0,0,
- 37,16,87,0,224,133,130,175,0,0,34,174,
- 76,63,192,12,66,144,18,0,224,133,130,143,
- 0,0,0,0,36,16,83,0,224,133,130,175,
- 0,0,34,174,255,255,66,50,230,255,64,20,
- 36,16,85,2,33,160,192,3,7,162,2,60,
- 236,0,66,52,0,128,17,52,7,162,16,60,
- 236,0,16,54,0,4,23,60,255,251,19,60,
- 255,255,115,54,0,1,21,60,255,254,18,60,
- 255,255,82,54,224,133,131,143,0,2,4,60,
- 37,24,100,0,224,133,131,175,0,0,67,172,
- 36,16,52,2,5,0,64,16,0,0,0,0,
- 224,133,130,143,0,0,0,0,20,71,192,8,
- 37,16,87,0,224,133,130,143,0,0,0,0,
- 36,16,83,0,224,133,130,175,76,63,192,12,
- 0,0,2,174,224,133,130,143,0,0,0,0,
- 37,16,85,0,224,133,130,175,0,0,2,174,
- 76,63,192,12,66,136,17,0,224,133,130,143,
- 0,0,0,0,36,16,82,0,224,133,130,175,
- 0,0,2,174,255,255,34,50,230,255,64,20,
- 36,16,52,2,7,162,16,60,236,0,16,54,
- 255,252,3,60,224,133,130,143,255,255,99,52,
- 36,16,67,0,224,133,130,175,76,63,192,12,
- 0,0,2,174,224,133,130,143,0,2,3,60,
- 37,16,67,0,224,133,130,175,0,0,2,174,
- 0,0,2,142,0,8,3,60,36,16,67,0,
- 11,0,64,20,7,162,4,60,7,162,16,60,
- 236,0,16,54,0,8,17,60,76,63,192,12,
- 0,0,0,0,0,0,2,142,0,0,0,0,
- 36,16,81,0,250,255,64,16,7,162,4,60,
- 236,0,132,52,255,253,3,60,224,133,130,143,
- 255,255,99,52,36,16,67,0,224,133,130,175,
- 0,0,130,172,7,162,16,60,236,0,16,54,
- 255,252,3,60,255,255,99,52,0,1,18,36,
- 7,162,17,60,236,0,49,54,0,4,23,60,
- 255,251,20,60,255,255,148,54,0,1,21,60,
- 255,254,19,60,224,133,130,143,0,0,0,0,
- 36,16,67,0,224,133,130,175,0,0,2,174,
- 76,63,192,12,255,255,115,54,224,133,130,143,
- 0,2,3,60,37,16,67,0,224,133,130,175,
- 0,0,2,174,0,1,66,50,5,0,64,16,
- 0,0,0,0,224,133,130,143,0,0,0,0,
- 108,71,192,8,37,16,87,0,224,133,130,143,
- 0,0,0,0,36,16,84,0,224,133,130,175,
- 76,63,192,12,0,0,34,174,224,133,130,143,
- 0,0,0,0,37,16,85,0,224,133,130,175,
- 0,0,34,174,76,63,192,12,66,144,18,0,
- 224,133,130,143,0,0,0,0,36,16,83,0,
- 224,133,130,175,0,0,34,174,255,255,66,50,
- 230,255,64,20,0,1,66,50,168,69,192,12,
- 33,32,192,2,38,16,194,3,255,255,66,48,
- 1,0,66,44,52,0,191,143,48,0,190,143,
- 44,0,183,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 56,0,189,39,0,0,0,0,248,255,189,39,
- 255,255,195,36,6,0,192,16,33,16,128,0,
- 255,255,6,36,0,0,133,160,255,255,99,36,
- 253,255,102,20,1,0,132,36,8,0,189,39,
- 8,0,224,3,0,0,0,0,159,71,192,8,
- 33,24,0,0,1,0,99,36,0,0,130,128,
- 0,0,0,0,252,255,64,20,1,0,132,36,
- 8,0,224,3,33,16,96,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,255,255,198,36,
- 10,0,192,16,0,0,0,0,0,0,131,128,
- 0,0,162,128,0,0,0,0,5,0,98,20,
- 0,0,0,0,1,0,132,36,255,255,198,36,
- 248,255,192,20,1,0,165,36,0,0,131,144,
- 0,0,162,144,0,0,0,0,8,0,224,3,
- 35,16,98,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,196,71,192,8,240,255,189,39,
- 0,0,163,128,3,22,2,0,8,0,67,20,
- 0,0,0,0,1,0,132,36,1,0,165,36,
- 0,0,130,128,0,0,131,144,0,0,0,0,
- 246,255,64,20,0,22,3,0,0,0,131,144,
- 0,0,162,144,0,0,0,0,35,16,98,0,
- 8,0,224,3,16,0,189,39,0,0,0,0,
- 255,255,198,36,9,0,192,4,33,16,0,0,
- 0,0,130,144,0,0,0,0,5,0,69,16,
- 33,16,128,0,255,255,198,36,250,255,193,4,
- 1,0,132,36,33,16,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,2,0,192,20,255,255,2,36,
- 1,0,2,36,8,0,224,3,0,0,226,172,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 40,0,176,143,33,32,192,0,4,0,5,142,
- 0,0,0,0,15,86,192,12,255,255,230,48,
- 3,0,64,16,255,255,2,36,243,71,192,8,
- 0,0,2,174,0,0,0,174,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 208,255,189,39,40,0,191,175,33,24,128,0,
- 64,0,162,143,32,0,160,175,36,0,162,175,
- 12,0,66,148,0,0,0,0,2,0,64,20,
- 33,32,160,0,120,5,2,36,255,255,66,48,
- 16,0,162,175,1,131,2,60,148,31,66,36,
- 20,0,162,175,1,131,2,60,128,31,66,36,
- 24,0,162,175,32,0,162,39,28,0,162,175,
- 166,85,192,12,33,40,96,0,32,0,162,143,
- 40,0,191,143,48,0,189,39,8,0,224,3,
- 0,0,0,0,0,0,0,0,88,0,131,148,
- 4,0,2,36,9,0,98,20,0,0,0,0,
- 33,72,192,8,116,0,132,36,33,16,69,0,
- 128,16,2,0,8,0,131,140,0,0,0,0,
- 46,72,192,8,33,16,67,0,104,0,132,36,
- 12,0,128,16,33,16,0,0,4,0,130,140,
- 0,0,0,0,42,16,162,0,243,255,64,20,
- 0,17,5,0,4,0,130,140,12,0,132,140,
- 0,0,0,0,247,255,128,20,35,40,162,0,
- 33,16,0,0,8,0,224,3,0,0,0,0,
- 88,0,131,148,4,0,2,36,3,0,98,20,
- 33,48,0,0,55,72,192,8,116,0,132,36,
- 104,0,132,36,8,0,130,140,0,0,0,0,
- 43,16,162,0,14,0,64,16,255,255,2,36,
- 92,72,192,8,0,0,0,0,35,24,163,0,
- 0,17,3,0,35,16,67,0,0,26,2,0,
- 33,16,67,0,0,28,2,0,33,16,67,0,
- 35,16,2,0,131,16,2,0,92,72,192,8,
- 33,16,194,0,18,0,128,16,0,0,0,0,
- 4,0,131,140,0,0,0,0,0,17,3,0,
- 33,16,67,0,128,16,2,0,8,0,131,140,
- 0,0,0,0,33,16,67,0,43,16,162,0,
- 233,255,64,20,0,0,0,0,4,0,130,140,
- 12,0,132,140,0,0,0,0,241,255,128,20,
- 33,48,194,0,255,255,2,36,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 8,0,130,36,144,0,163,140,120,132,135,39,
- 2,0,96,16,20,0,137,36,33,56,96,0,
- 0,0,72,140,4,0,68,140,132,72,192,8,
- 0,0,0,0,30,0,0,25,0,0,0,0,
- 4,0,227,140,0,0,0,0,4,0,98,140,
- 0,0,0,0,55,0,64,16,255,255,2,36,
- 0,0,135,140,0,0,98,140,0,0,0,0,
- 8,0,71,16,0,0,0,0,8,0,99,36,
- 4,0,98,140,0,0,0,0,248,255,64,20,
- 255,255,2,36,168,72,192,8,0,0,0,0,
- 0,0,130,140,0,0,0,0,4,0,34,173,
- 4,0,103,140,255,255,8,37,4,0,132,36,
- 0,0,226,148,0,0,0,0,1,0,66,48,
- 226,255,64,16,0,0,0,0,0,0,226,148,
- 0,0,0,0,64,0,66,48,27,0,64,20,
- 255,255,2,36,0,0,226,148,0,0,0,0,
- 1,0,66,48,17,0,64,16,0,0,0,0,
- 13,0,192,16,1,0,2,36,64,0,162,140,
- 0,0,0,0,9,0,64,20,1,0,2,36,
- 28,0,226,140,4,0,163,140,0,0,0,0,
- 36,16,67,0,3,0,64,20,1,0,2,36,
- 168,72,192,8,255,255,2,36,164,72,192,8,
- 0,0,34,165,0,0,32,165,8,0,40,173,
- 12,0,36,173,16,0,39,173,33,16,0,0,
- 8,0,224,3,0,0,0,0,200,255,189,39,
- 48,0,191,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,152,128,0,
- 33,128,160,0,33,144,192,0,0,0,4,142,
- 0,0,0,0,48,0,130,40,2,0,64,16,
- 8,0,113,38,48,0,4,36,0,0,36,174,
- 9,50,192,12,128,32,4,0,3,0,64,20,
- 4,0,34,174,214,72,192,8,255,255,2,36,
- 144,0,66,142,120,132,132,39,2,0,64,16,
- 0,0,0,0,33,32,64,0,16,0,160,175,
- 20,0,179,175,24,0,178,175,0,0,5,142,
- 4,0,6,142,0,0,0,0,221,72,192,12,
- 33,56,32,2,33,128,64,0,4,0,0,26,
- 0,0,0,0,0,0,34,142,214,72,192,8,
- 0,0,0,0,110,86,192,12,33,32,32,2,
- 33,16,0,2,48,0,191,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,56,0,189,39,184,255,189,39,
- 68,0,191,175,64,0,190,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,144,128,0,33,176,160,0,
- 33,136,224,0,88,0,183,143,92,0,179,143,
- 96,0,190,143,32,0,226,38,0,0,36,142,
- 0,0,0,0,42,16,130,0,22,0,64,16,
- 33,160,192,0,4,0,132,36,9,50,192,12,
- 128,32,4,0,33,128,64,0,3,0,0,22,
- 33,32,0,2,153,73,192,8,255,255,2,36,
- 0,0,38,142,4,0,37,142,0,0,0,0,
- 80,68,192,12,128,48,6,0,4,0,36,142,
- 61,50,192,12,0,0,0,0,4,0,48,174,
- 0,0,34,142,0,0,0,0,4,0,66,36,
- 0,0,34,174,0,0,66,150,0,0,0,0,
- 1,0,66,48,96,0,64,20,0,0,0,0,
- 33,0,192,30,0,0,0,0,4,0,80,142,
- 0,0,0,0,4,0,2,142,0,0,0,0,
- 108,0,64,16,128,160,23,0,1,0,242,38,
- 4,0,34,142,0,0,0,0,33,16,130,2,
- 0,0,3,142,0,0,0,0,0,0,67,172,
- 0,0,2,142,0,0,0,0,24,0,98,174,
- 16,0,178,175,20,0,179,175,24,0,190,175,
- 4,0,4,142,33,40,0,0,33,48,0,0,
- 221,72,192,12,33,56,32,2,112,0,64,20,
- 8,0,16,38,4,0,2,142,0,0,0,0,
- 234,255,64,20,33,16,0,0,153,73,192,8,
- 0,0,0,0,4,0,80,142,0,0,0,0,
- 4,0,2,142,0,0,0,0,76,0,64,16,
- 128,168,23,0,1,0,242,38,0,0,3,142,
- 0,0,132,142,0,0,0,0,43,16,100,0,
- 42,0,64,20,0,0,0,0,19,0,100,20,
- 255,255,197,38,4,0,34,142,0,0,0,0,
- 33,16,162,2,0,0,67,172,0,0,2,142,
- 0,0,0,0,24,0,98,174,16,0,178,175,
- 20,0,179,175,24,0,190,175,4,0,4,142,
- 4,0,134,38,221,72,192,12,33,56,32,2,
- 25,0,64,16,8,0,16,38,153,73,192,8,
- 0,0,0,0,0,0,130,142,0,0,0,0,
- 43,16,67,0,17,0,64,16,33,40,0,0,
- 4,0,34,142,0,0,0,0,33,16,162,2,
- 0,0,67,172,0,0,2,142,0,0,0,0,
- 24,0,98,174,16,0,178,175,20,0,179,175,
- 24,0,190,175,4,0,4,142,33,48,0,0,
- 221,72,192,12,33,56,32,2,52,0,64,20,
- 0,0,0,0,8,0,16,38,4,0,2,142,
- 0,0,0,0,205,255,64,20,33,16,0,0,
- 153,73,192,8,0,0,0,0,0,0,66,150,
- 0,0,0,0,64,0,66,48,40,0,64,20,
- 33,16,0,0,3,0,66,146,0,0,0,0,
- 1,0,66,48,11,0,64,16,33,24,64,2,
- 64,0,194,143,0,0,0,0,9,0,64,20,
- 0,0,0,0,28,0,98,140,4,0,195,143,
- 0,0,0,0,36,16,67,0,3,0,64,20,
- 0,0,0,0,153,73,192,8,33,16,0,0,
- 14,0,192,26,33,16,246,2,0,0,34,174,
- 4,0,36,142,128,128,23,0,33,32,4,2,
- 33,40,128,2,80,68,192,12,128,48,22,0,
- 28,0,118,174,4,0,34,142,0,0,0,0,
- 33,128,2,2,149,73,192,8,32,0,112,174,
- 0,0,55,174,28,0,96,174,32,0,96,174,
- 36,0,114,174,1,0,2,36,20,0,98,166,
- 1,0,2,36,68,0,191,143,64,0,190,143,
- 60,0,183,143,56,0,182,143,52,0,181,143,
- 48,0,180,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 72,0,189,39,3,0,160,28,33,16,0,0,
- 0,0,224,172,1,0,2,36,8,0,224,3,
- 0,0,0,0,208,255,189,39,44,0,191,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,144,128,0,33,136,224,0,64,0,176,143,
- 0,0,0,0,6,0,160,24,24,0,160,175,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 200,73,192,8,17,0,2,162,33,32,32,2,
- 33,40,0,2,1,0,6,36,253,76,192,12,
- 24,0,167,39,36,0,2,142,16,0,176,175,
- 8,0,66,140,33,32,64,2,1,0,5,36,
- 24,0,166,39,9,248,64,0,33,56,32,2,
- 44,0,191,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,28,0,191,175,24,0,178,175,
- 20,0,177,175,33,144,128,0,33,136,160,0,
- 31,0,81,18,16,0,176,175,4,0,80,142,
- 0,0,0,0,4,0,2,142,0,0,0,0,
- 10,0,64,16,0,0,0,0,4,0,4,142,
- 0,0,0,0,206,73,192,12,33,40,32,2,
- 8,0,16,38,4,0,2,142,0,0,0,0,
- 248,255,64,20,0,0,0,0,0,0,66,150,
- 0,0,0,0,32,0,66,48,4,0,64,16,
- 0,0,0,0,4,0,68,142,61,50,192,12,
- 0,0,0,0,0,0,66,150,0,0,0,0,
- 16,0,66,48,3,0,64,16,0,0,0,0,
- 61,50,192,12,33,32,64,2,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,120,132,131,39,
- 2,0,128,16,0,0,0,0,33,24,128,0,
- 0,0,167,140,4,0,165,140,26,74,192,8,
- 0,0,0,0,28,0,224,24,0,0,0,0,
- 4,0,99,140,0,0,0,0,4,0,98,140,
- 0,0,0,0,11,0,64,16,0,0,0,0,
- 0,0,164,140,0,0,98,140,0,0,0,0,
- 9,0,68,16,0,0,0,0,8,0,99,36,
- 4,0,98,140,0,0,0,0,248,255,64,20,
- 0,0,0,0,0,0,192,172,33,74,192,8,
- 2,0,2,36,4,0,99,140,255,255,231,36,
- 4,0,165,36,0,0,98,148,0,0,0,0,
- 1,0,66,48,228,255,64,16,0,0,0,0,
- 0,0,195,172,42,16,7,0,8,0,224,3,
- 0,0,0,0,208,255,189,39,44,0,191,175,
- 40,0,182,175,36,0,181,175,32,0,180,175,
- 28,0,179,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,168,192,0,0,0,162,140,
- 0,0,0,0,3,0,64,28,33,48,0,0,
- 220,74,192,8,5,0,2,36,120,132,147,39,
- 2,0,128,16,0,0,224,172,33,152,128,0,
- 0,0,177,140,4,0,180,140,84,74,192,8,
- 0,0,0,0,29,0,32,26,0,0,0,0,
- 4,0,102,142,0,0,0,0,4,0,194,140,
- 0,0,0,0,23,0,64,16,0,0,0,0,
- 0,0,131,142,0,0,194,140,0,0,0,0,
- 6,0,67,16,0,0,0,0,8,0,198,36,
- 4,0,194,140,0,0,0,0,248,255,64,20,
- 0,0,0,0,4,0,194,140,0,0,0,0,
- 9,0,64,16,0,0,0,0,255,255,49,38,
- 4,0,148,38,33,152,64,0,0,0,98,150,
- 0,0,0,0,1,0,66,48,227,255,64,16,
- 0,0,0,0,29,0,32,22,0,0,0,0,
- 0,0,99,150,0,0,0,0,1,0,98,48,
- 11,0,64,16,4,0,98,48,123,0,64,16,
- 3,0,2,36,0,0,162,150,0,0,0,0,
- 1,0,66,48,118,0,64,16,4,0,2,36,
- 0,0,243,172,219,74,192,8,4,0,213,172,
- 0,0,98,150,0,0,0,0,4,0,66,48,
- 110,0,64,16,3,0,2,36,0,0,162,150,
- 0,0,0,0,1,0,66,48,105,0,64,20,
- 4,0,2,36,0,0,243,172,219,74,192,8,
- 4,0,213,172,0,0,98,150,0,0,0,0,
- 1,0,66,48,97,0,64,20,2,0,2,36,
- 2,0,34,42,23,0,64,20,33,144,160,2,
- 56,0,22,36,9,50,192,12,16,0,4,36,
- 33,128,64,0,40,0,0,18,128,16,17,0,
- 33,16,84,0,252,255,66,140,0,0,0,0,
- 0,0,2,174,4,0,18,174,8,0,0,174,
- 12,0,0,174,9,50,192,12,8,0,4,36,
- 33,144,64,0,24,0,64,18,255,255,49,38,
- 0,0,86,166,2,0,34,42,236,255,64,16,
- 4,0,80,174,4,0,102,142,0,0,0,0,
- 4,0,194,140,0,0,0,0,6,0,64,16,
- 1,0,17,36,8,0,198,36,4,0,194,140,
- 0,0,0,0,252,255,64,20,1,0,49,38,
- 1,0,36,38,9,50,192,12,192,32,4,0,
- 33,128,64,0,12,0,0,22,33,32,64,2,
- 173,74,192,8,0,0,0,0,0,0,18,142,
- 0,0,0,0,61,50,192,12,33,32,0,2,
- 33,32,64,2,206,73,192,12,33,40,160,2,
- 220,74,192,8,1,0,2,36,4,0,102,142,
- 0,0,0,0,192,74,192,8,33,168,0,2,
- 4,0,194,140,0,0,0,0,14,0,64,16,
- 0,0,0,0,0,0,194,140,4,0,195,140,
- 0,0,2,174,4,0,3,174,8,0,198,36,
- 8,0,16,38,255,255,49,38,0,0,194,140,
- 0,0,131,142,0,0,0,0,43,16,67,0,
- 240,255,64,20,0,0,0,0,0,0,130,142,
- 0,0,0,0,0,0,2,174,4,0,18,174,
- 8,0,4,38,33,40,192,0,80,68,192,12,
- 192,48,17,0,4,0,102,142,4,0,117,174,
- 0,0,98,150,0,0,0,0,32,0,66,48,
- 3,0,64,16,0,0,0,0,61,50,192,12,
- 33,32,192,0,0,0,98,150,0,0,0,0,
- 32,0,66,52,0,0,98,166,33,16,0,0,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,0,0,162,140,0,0,0,0,
- 85,0,64,24,33,16,0,0,120,132,144,39,
- 2,0,128,16,0,0,0,0,33,128,128,0,
- 0,0,164,140,4,0,165,140,0,0,0,0,
- 0,0,168,140,0,0,2,150,0,0,0,0,
- 33,24,64,0,1,0,66,48,34,0,64,20,
- 33,56,0,2,32,0,128,24,8,0,98,48,
- 4,0,6,142,5,0,64,16,0,0,0,0,
- 12,0,194,140,0,0,0,0,3,0,64,16,
- 0,0,0,0,33,56,0,2,0,0,168,140,
- 0,0,195,140,0,0,162,140,0,0,0,0,
- 10,0,98,16,0,0,0,0,0,0,163,140,
- 4,0,194,140,0,0,0,0,20,0,64,16,
- 8,0,198,36,0,0,194,140,0,0,0,0,
- 249,255,67,20,0,0,0,0,255,255,132,36,
- 4,0,208,140,0,0,0,0,0,0,3,150,
- 0,0,0,0,1,0,98,48,224,255,64,16,
- 4,0,165,36,36,0,128,20,33,16,0,0,
- 0,0,2,150,0,0,0,0,2,0,66,48,
- 3,0,64,20,0,0,0,0,65,75,192,8,
- 33,16,0,0,4,0,230,140,0,0,0,0,
- 0,0,194,140,0,0,0,0,7,0,72,16,
- 0,0,0,0,8,0,198,36,0,0,194,140,
- 0,0,0,0,253,255,72,20,8,0,198,36,
- 248,255,198,36,4,0,199,140,0,0,0,0,
- 10,0,224,16,33,32,224,0,8,0,194,140,
- 12,0,195,140,0,0,194,172,4,0,195,172,
- 8,0,198,36,4,0,194,140,0,0,0,0,
- 248,255,64,20,33,32,224,0,206,73,192,12,
- 33,40,0,2,33,16,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 192,255,189,39,56,0,191,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,136,128,0,
- 33,144,160,0,33,152,192,0,33,160,224,0,
- 80,0,181,143,0,0,0,0,36,0,162,142,
- 0,0,0,0,20,0,80,140,33,32,128,2,
- 48,72,192,12,33,40,160,2,16,0,3,142,
- 0,0,0,0,16,0,163,175,20,0,180,175,
- 24,0,162,175,0,0,2,142,1,0,4,36,
- 33,40,32,2,33,48,64,2,9,248,64,0,
- 33,56,96,2,6,0,64,20,33,32,128,2,
- 17,0,162,146,0,0,0,0,1,0,66,52,
- 113,75,192,8,17,0,162,162,33,40,160,2,
- 59,77,192,12,33,48,64,0,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,192,255,189,39,
- 60,0,191,175,56,0,178,175,52,0,177,175,
- 48,0,176,175,33,136,224,0,80,0,178,143,
- 36,0,160,175,36,0,66,142,0,0,0,0,
- 20,0,67,140,2,0,80,144,0,0,0,0,
- 255,0,2,50,254,255,71,36,70,0,226,44,
- 110,0,64,16,128,16,7,0,2,131,1,60,
- 33,8,34,0,160,151,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,16,0,177,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,2,0,3,36,16,0,67,162,
- 251,75,192,8,40,0,66,174,16,0,177,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,40,0,162,175,16,0,80,162,
- 40,0,162,143,0,0,0,0,251,75,192,8,
- 40,0,66,174,32,0,162,39,16,0,162,175,
- 20,0,177,175,36,0,162,39,24,0,162,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,33,48,64,0,16,0,80,162,
- 17,0,66,146,0,0,0,0,2,0,66,52,
- 17,0,66,162,36,0,162,143,0,0,0,0,
- 43,16,2,0,40,0,66,166,44,0,70,174,
- 32,0,162,151,0,0,0,0,33,16,194,0,
- 48,0,66,174,255,75,192,8,52,0,64,166,
- 16,0,177,175,36,0,162,39,20,0,162,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,33,128,64,0,8,0,0,22,
- 33,32,32,2,16,0,160,175,33,40,64,2,
- 33,48,0,0,226,76,192,12,33,56,0,0,
- 255,75,192,8,0,0,0,0,36,0,162,143,
- 0,0,0,0,16,0,162,175,0,0,6,142,
- 4,0,7,142,0,0,0,0,226,76,192,12,
- 33,40,64,2,36,0,162,143,0,0,0,0,
- 35,0,64,16,0,0,0,0,61,50,192,12,
- 33,32,0,2,255,75,192,8,0,0,0,0,
- 5,0,2,36,251,75,192,8,16,0,66,162,
- 16,0,177,175,40,0,162,39,20,0,162,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,33,48,64,0,7,0,192,16,
- 64,0,2,36,3,0,194,136,0,0,194,152,
- 0,0,0,0,43,0,162,171,40,0,162,187,
- 64,0,2,36,16,0,66,162,40,0,162,143,
- 0,0,0,0,251,75,192,8,40,0,66,174,
- 5,0,2,36,96,0,34,174,17,0,66,146,
- 0,0,0,0,2,0,66,52,17,0,66,162,
- 60,0,191,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,64,0,189,39,
- 80,255,189,39,168,0,191,175,164,0,179,175,
- 160,0,178,175,156,0,177,175,152,0,176,175,
- 33,152,128,0,33,136,224,0,192,0,178,143,
- 0,0,0,0,36,0,66,142,0,0,0,0,
- 20,0,67,140,0,0,0,0,16,0,98,140,
- 0,0,0,0,16,0,162,175,20,0,177,175,
- 4,0,98,140,0,0,0,0,9,248,64,0,
- 24,0,167,39,33,128,64,0,6,0,0,22,
- 33,32,32,2,17,0,66,146,0,0,0,0,
- 18,0,66,52,45,76,192,8,17,0,66,162,
- 33,40,64,2,33,48,0,2,253,76,192,12,
- 24,0,167,39,16,0,178,175,33,32,96,2,
- 33,40,0,2,24,0,166,39,122,75,192,12,
- 33,56,32,2,168,0,191,143,164,0,179,143,
- 160,0,178,143,156,0,177,143,152,0,176,143,
- 8,0,224,3,176,0,189,39,192,255,189,39,
- 56,0,191,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,152,128,0,33,160,160,0,
- 33,168,192,0,33,136,224,0,80,0,178,143,
- 0,0,0,0,36,0,66,142,0,0,0,0,
- 20,0,80,140,33,32,32,2,48,72,192,12,
- 33,40,64,2,16,0,3,142,0,0,0,0,
- 16,0,163,175,20,0,177,175,24,0,162,175,
- 0,0,2,142,33,32,0,0,33,40,96,2,
- 33,48,128,2,9,248,64,0,33,56,160,2,
- 5,0,64,16,33,32,32,2,200,76,192,12,
- 33,40,64,2,95,76,192,8,0,0,0,0,
- 16,0,178,175,33,32,96,2,33,40,128,2,
- 33,48,160,2,122,75,192,12,33,56,32,2,
- 56,0,191,143,52,0,181,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,64,0,189,39,
- 192,255,189,39,56,0,191,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,152,128,0,
- 33,160,160,0,33,168,192,0,80,0,177,143,
- 0,0,0,0,36,0,34,142,0,0,0,0,
- 20,0,82,140,2,0,66,144,0,0,0,0,
- 254,255,67,36,70,0,98,44,57,0,64,16,
- 33,128,224,0,128,16,3,0,2,131,1,60,
- 33,8,34,0,184,152,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,33,32,0,2,
- 48,72,192,12,33,40,32,2,40,0,35,142,
- 0,0,0,0,16,0,163,175,20,0,176,175,
- 173,76,192,8,24,0,162,175,33,32,0,2,
- 48,72,192,12,33,40,32,2,44,0,35,142,
- 0,0,0,0,16,0,163,175,48,0,35,142,
- 44,0,36,142,0,0,0,0,35,24,100,0,
- 170,76,192,8,255,255,99,48,33,32,0,2,
- 48,72,192,12,33,40,32,2,40,0,35,142,
- 0,0,0,0,16,0,163,175,44,0,35,142,
- 0,0,0,0,171,76,192,8,20,0,163,175,
- 33,32,0,2,48,72,192,12,33,40,32,2,
- 40,0,35,38,16,0,163,175,4,0,3,36,
- 20,0,163,175,24,0,176,175,28,0,162,175,
- 12,0,66,142,33,32,96,2,33,40,128,2,
- 16,0,71,142,0,0,0,0,9,248,64,0,
- 33,48,160,2,184,76,192,8,0,0,0,0,
- 5,0,2,36,96,0,2,174,17,0,34,146,
- 0,0,0,0,2,0,66,52,17,0,34,162,
- 56,0,191,143,52,0,181,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,64,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 224,255,189,39,24,0,191,175,20,0,177,175,
- 16,0,176,175,33,128,128,0,64,0,2,142,
- 0,0,0,0,7,0,64,20,33,136,160,0,
- 2,0,2,36,48,72,192,12,96,0,2,174,
- 1,0,66,36,217,76,192,8,100,0,2,174,
- 129,0,2,36,16,0,34,162,17,0,34,146,
- 0,0,0,0,2,0,66,52,17,0,34,162,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 33,64,160,0,33,32,192,0,33,40,224,0,
- 40,0,162,143,17,0,3,145,0,0,0,0,
- 2,0,99,52,17,0,3,161,6,0,3,36,
- 4,0,64,16,16,0,3,161,40,0,4,173,
- 249,76,192,8,44,0,5,173,80,86,192,12,
- 40,0,6,37,2,0,64,16,5,0,2,36,
- 96,0,2,174,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,200,255,189,39,
- 48,0,191,175,44,0,183,175,40,0,182,175,
- 36,0,181,175,32,0,180,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,176,128,0,33,144,160,0,33,152,192,0,
- 37,0,96,18,33,184,224,0,28,0,84,38,
- 8,0,67,142,28,0,66,142,0,0,0,0,
- 35,128,98,0,42,16,83,0,23,0,64,16,
- 33,168,19,2,9,50,192,12,128,32,21,0,
- 33,136,64,0,8,0,32,22,128,128,16,0,
- 5,0,2,36,96,0,194,174,17,0,66,146,
- 0,0,0,0,2,0,66,52,48,77,192,8,
- 17,0,66,162,33,32,32,2,12,0,69,142,
- 0,0,0,0,80,68,192,12,33,48,0,2,
- 110,86,192,12,8,0,68,38,12,0,81,174,
- 33,128,48,2,4,0,144,174,4,0,132,142,
- 33,40,224,2,80,68,192,12,128,48,19,0,
- 0,0,147,174,8,0,85,174,48,0,191,143,
- 44,0,183,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 56,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,136,128,0,
- 5,0,192,24,33,128,160,0,3,0,2,36,
- 96,0,34,174,95,77,192,8,100,0,38,174,
- 19,0,195,36,19,0,98,44,9,0,64,16,
- 128,16,3,0,2,131,1,60,33,8,34,0,
- 208,153,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,89,77,192,8,2,0,6,36,
- 89,77,192,8,5,0,6,36,89,77,192,8,
- 3,0,6,36,89,77,192,8,1,0,6,36,
- 35,48,6,0,96,0,38,174,33,32,32,2,
- 48,72,192,12,33,40,0,2,1,0,66,36,
- 100,0,34,174,17,0,2,146,0,0,0,0,
- 1,0,66,52,17,0,2,162,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,200,255,189,39,52,0,191,175,
- 48,0,190,175,44,0,183,175,40,0,182,175,
- 36,0,181,175,32,0,180,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,152,128,0,33,168,160,0,33,160,192,0,
- 76,0,182,143,80,0,183,143,84,0,190,143,
- 92,0,177,143,0,0,0,0,209,83,192,12,
- 33,144,224,0,33,128,64,0,3,0,0,22,
- 4,0,2,36,168,77,192,8,33,16,0,0,
- 88,0,2,166,64,0,19,174,33,32,64,2,
- 72,0,165,143,0,0,0,0,80,86,192,12,
- 92,0,6,38,255,255,3,36,23,0,67,16,
- 0,0,0,0,3,0,194,138,0,0,194,154,
- 0,0,0,0,103,0,2,170,100,0,2,186,
- 104,0,23,174,108,0,30,174,88,0,168,143,
- 0,0,0,0,112,0,8,174,72,0,0,166,
- 76,0,20,174,255,255,162,50,33,16,130,2,
- 80,0,2,174,84,0,0,166,9,0,32,18,
- 120,0,17,174,224,83,192,12,33,32,32,2,
- 6,0,64,20,124,0,2,174,167,83,192,12,
- 33,32,0,2,168,77,192,8,33,16,0,0,
- 124,0,0,174,33,16,0,2,52,0,191,143,
- 48,0,190,143,44,0,183,143,40,0,182,143,
- 36,0,181,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,56,0,189,39,224,255,189,39,
- 28,0,191,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,144,128,0,92,0,68,142,
- 128,86,192,12,0,0,0,0,96,0,68,142,
- 0,0,0,0,128,86,192,12,33,128,64,0,
- 100,0,68,142,0,0,0,0,128,86,192,12,
- 33,136,64,0,33,128,17,2,6,0,16,38,
- 33,16,80,0,90,0,66,166,191,79,192,12,
- 104,0,68,38,255,255,67,48,90,0,68,150,
- 128,0,98,44,5,0,64,20,2,0,130,36,
- 0,1,98,44,2,0,64,20,3,0,130,36,
- 4,0,130,36,33,16,67,0,90,0,66,166,
- 80,0,66,142,76,0,67,142,90,0,80,150,
- 64,0,68,142,0,0,0,0,128,86,192,12,
- 35,136,67,0,255,255,67,48,90,0,68,150,
- 0,0,0,0,128,0,130,44,9,0,64,20,
- 0,1,130,44,4,0,64,16,0,0,0,0,
- 33,24,112,0,237,77,192,8,6,0,99,36,
- 33,24,112,0,237,77,192,8,7,0,99,36,
- 33,24,112,0,5,0,99,36,255,255,36,50,
- 128,0,130,44,5,0,64,20,1,0,130,36,
- 0,1,130,44,2,0,64,20,2,0,130,36,
- 3,0,130,36,33,16,98,0,2,0,66,166,
- 2,0,67,150,2,0,68,150,0,0,0,0,
- 128,0,130,44,6,0,64,20,1,0,99,36,
- 0,1,130,44,4,0,64,20,2,0,98,36,
- 3,78,192,8,3,0,98,36,1,0,98,36,
- 0,0,66,166,0,0,66,150,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,152,128,0,
- 171,86,192,12,92,0,100,38,104,0,100,142,
- 0,0,0,0,128,86,192,12,33,144,64,0,
- 108,0,100,142,0,0,0,0,128,86,192,12,
- 33,136,64,0,112,0,100,142,0,0,0,0,
- 153,86,192,12,33,128,64,0,10,0,82,38,
- 33,136,50,2,33,128,17,2,4,0,16,38,
- 33,16,80,0,90,0,98,166,191,79,192,12,
- 116,0,100,38,255,255,67,48,90,0,100,150,
- 128,0,98,44,5,0,64,20,2,0,130,36,
- 0,1,98,44,2,0,64,20,3,0,130,36,
- 4,0,130,36,33,16,67,0,90,0,98,166,
- 80,0,98,142,76,0,99,142,90,0,113,150,
- 64,0,100,142,0,0,0,0,128,86,192,12,
- 35,128,67,0,255,255,67,48,90,0,100,150,
- 0,0,0,0,128,0,130,44,9,0,64,20,
- 0,1,130,44,4,0,64,16,0,0,0,0,
- 33,24,113,0,74,78,192,8,6,0,99,36,
- 33,24,113,0,74,78,192,8,7,0,99,36,
- 33,24,113,0,5,0,99,36,255,255,4,50,
- 128,0,130,44,5,0,64,20,1,0,130,36,
- 0,1,130,44,2,0,64,20,2,0,130,36,
- 3,0,130,36,33,16,98,0,2,0,98,166,
- 2,0,99,150,2,0,100,150,0,0,0,0,
- 128,0,130,44,6,0,64,20,1,0,99,36,
- 0,1,130,44,4,0,64,20,2,0,112,36,
- 96,78,192,8,3,0,112,36,1,0,112,36,
- 255,255,2,50,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,208,255,189,39,
- 40,0,191,175,36,0,179,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,152,192,0,33,144,224,0,33,136,160,0,
- 16,0,4,36,32,0,5,36,1,131,6,60,
- 56,97,198,36,242,86,192,12,33,56,0,2,
- 255,255,36,50,1,131,5,60,56,97,165,36,
- 44,87,192,12,33,48,0,2,16,0,176,175,
- 2,0,4,36,33,40,0,0,1,131,7,60,
- 56,97,231,36,94,87,192,12,33,48,96,2,
- 8,0,71,142,4,0,66,142,0,0,0,0,
- 35,56,226,0,1,131,2,60,56,97,66,36,
- 16,0,162,175,20,0,176,175,4,0,4,36,
- 33,40,0,0,4,0,70,142,0,0,0,0,
- 194,87,192,12,255,255,231,48,40,0,191,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 216,255,189,39,36,0,191,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,136,160,0,88,0,4,150,160,0,5,36,
- 1,131,6,60,56,97,198,36,242,86,192,12,
- 33,56,32,2,90,0,4,150,1,131,5,60,
- 56,97,165,36,44,87,192,12,33,48,32,2,
- 16,0,177,175,6,0,4,36,33,40,0,0,
- 1,131,7,60,56,97,231,36,15,88,192,12,
- 92,0,6,38,1,131,18,60,56,97,82,38,
- 16,0,178,175,20,0,177,175,33,32,0,0,
- 64,0,5,36,100,0,6,38,194,87,192,12,
- 4,0,7,36,16,0,177,175,2,0,4,36,
- 33,40,0,0,104,0,6,142,0,0,0,0,
- 94,87,192,12,33,56,64,2,16,0,177,175,
- 2,0,4,36,33,40,0,0,108,0,6,142,
- 0,0,0,0,94,87,192,12,33,56,64,2,
- 16,0,177,175,3,0,4,36,64,0,5,36,
- 112,0,6,142,0,0,0,0,143,87,192,12,
- 33,56,64,2,116,0,4,38,7,79,192,12,
- 33,40,32,2,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,216,255,189,39,32,0,191,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,136,160,0,88,0,4,150,160,0,5,36,
- 1,131,6,60,56,97,198,36,242,86,192,12,
- 33,56,32,2,90,0,4,150,1,131,5,60,
- 56,97,165,36,44,87,192,12,33,48,32,2,
- 16,0,177,175,2,0,4,36,92,0,6,142,
- 1,131,7,60,56,97,231,36,94,87,192,12,
- 33,40,0,0,16,0,177,175,2,0,4,36,
- 96,0,6,142,1,131,7,60,56,97,231,36,
- 94,87,192,12,33,40,0,0,16,0,177,175,
- 2,0,4,36,100,0,6,142,1,131,7,60,
- 56,97,231,36,94,87,192,12,33,40,0,0,
- 104,0,4,38,7,79,192,12,33,40,32,2,
- 32,0,191,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,40,0,189,39,200,255,189,39,
- 52,0,191,175,48,0,180,175,44,0,179,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,144,128,0,33,136,160,0,16,0,4,36,
- 32,0,5,36,1,131,6,60,56,97,198,36,
- 242,86,192,12,33,56,32,2,0,0,68,150,
- 1,131,5,60,56,97,165,36,44,87,192,12,
- 33,48,32,2,155,0,64,18,0,0,0,0,
- 1,131,20,60,56,97,148,38,8,0,80,142,
- 0,0,0,0,145,0,0,18,0,0,0,0,
- 4,0,66,142,0,0,0,0,141,0,64,24,
- 33,152,0,0,16,0,4,36,32,0,5,36,
- 33,48,128,2,242,86,192,12,33,56,32,2,
- 4,0,4,150,33,40,128,2,44,87,192,12,
- 33,48,32,2,16,0,177,175,6,0,4,36,
- 33,40,0,0,8,0,6,38,15,88,192,12,
- 33,56,128,2,16,0,3,146,65,0,2,36,
- 47,0,98,16,66,0,98,40,18,0,64,16,
- 5,0,2,36,88,0,98,16,6,0,98,40,
- 7,0,64,16,2,0,2,36,30,0,98,16,
- 4,0,2,36,51,0,98,16,4,0,4,36,
- 174,79,192,8,1,0,115,38,6,0,2,36,
- 68,0,98,16,64,0,2,36,78,0,98,16,
- 33,32,0,0,174,79,192,8,1,0,115,38,
- 68,0,2,36,47,0,98,16,69,0,98,40,
- 7,0,64,16,66,0,2,36,24,0,98,16,
- 67,0,2,36,25,0,98,16,3,0,4,36,
- 174,79,192,8,1,0,115,38,131,0,98,40,
- 83,0,64,16,128,0,98,40,68,0,64,16,
- 0,0,0,0,174,79,192,8,1,0,115,38,
- 16,0,177,175,2,0,4,36,40,0,6,142,
- 1,131,7,60,56,97,231,36,94,87,192,12,
- 33,40,0,0,174,79,192,8,1,0,115,38,
- 16,0,177,175,111,79,192,8,1,0,4,36,
- 16,0,177,175,111,79,192,8,2,0,4,36,
- 16,0,177,175,40,0,6,142,1,131,7,60,
- 56,97,231,36,143,87,192,12,64,0,5,36,
- 174,79,192,8,1,0,115,38,48,0,7,142,
- 44,0,2,142,0,0,0,0,35,56,226,0,
- 16,0,180,175,20,0,177,175,134,79,192,8,
- 33,40,0,0,48,0,7,142,44,0,2,142,
- 0,0,0,0,35,56,226,0,16,0,180,175,
- 20,0,177,175,4,0,4,36,64,0,5,36,
- 44,0,6,142,0,0,0,0,194,87,192,12,
- 255,255,231,48,174,79,192,8,1,0,115,38,
- 16,0,177,175,6,0,4,36,33,40,0,0,
- 1,131,7,60,56,97,231,36,15,88,192,12,
- 40,0,6,38,174,79,192,8,1,0,115,38,
- 5,0,4,36,164,79,192,8,33,40,0,0,
- 16,0,180,175,20,0,177,175,64,0,5,36,
- 40,0,6,38,194,87,192,12,4,0,7,36,
- 174,79,192,8,1,0,115,38,16,0,4,146,
- 16,0,5,146,31,0,132,48,224,0,165,48,
- 1,131,6,60,56,97,198,36,242,86,192,12,
- 33,56,32,2,33,32,0,0,1,131,5,60,
- 56,97,165,36,44,87,192,12,33,48,32,2,
- 1,0,115,38,4,0,66,142,0,0,0,0,
- 42,16,98,2,117,255,64,20,68,0,16,38,
- 12,0,82,142,0,0,0,0,105,255,64,22,
- 0,0,0,0,52,0,191,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,52,0,191,175,48,0,182,175,
- 44,0,181,175,40,0,180,175,36,0,179,175,
- 32,0,178,175,28,0,177,175,24,0,176,175,
- 33,168,128,0,33,152,160,2,113,0,160,18,
- 33,144,0,0,4,0,22,36,8,0,112,142,
- 0,0,0,0,104,0,0,18,0,0,0,0,
- 4,0,98,142,0,0,0,0,100,0,64,24,
- 33,160,0,0,171,86,192,12,8,0,4,38,
- 255,255,67,48,128,0,98,44,5,0,64,20,
- 2,0,113,36,0,1,98,44,2,0,64,20,
- 3,0,113,36,4,0,113,36,16,0,3,146,
- 64,0,2,36,50,0,98,16,65,0,98,40,
- 16,0,64,16,68,0,2,36,34,0,118,16,
- 5,0,98,40,5,0,64,16,2,0,2,36,
- 20,0,98,16,255,255,36,50,22,80,192,8,
- 0,0,0,0,5,0,2,36,35,0,98,16,
- 6,0,2,36,29,0,98,16,255,255,36,50,
- 22,80,192,8,0,0,0,0,19,0,98,16,
- 68,0,98,40,12,0,64,20,131,0,98,40,
- 28,0,64,16,128,0,98,40,27,0,64,20,
- 255,255,36,50,22,80,192,8,18,0,0,166,
- 40,0,4,142,128,86,192,12,0,0,0,0,
- 21,80,192,8,18,0,2,166,40,0,4,142,
- 153,86,192,12,0,0,0,0,21,80,192,8,
- 18,0,2,166,48,0,2,142,44,0,3,142,
- 0,0,0,0,35,16,67,0,21,80,192,8,
- 18,0,2,166,171,86,192,12,40,0,4,38,
- 21,80,192,8,18,0,2,166,21,80,192,8,
- 18,0,0,166,18,0,22,166,255,255,36,50,
- 18,0,3,150,0,0,0,0,128,0,98,44,
- 6,0,64,20,1,0,132,36,0,1,98,44,
- 4,0,64,20,2,0,98,36,33,80,192,8,
- 3,0,98,36,1,0,98,36,33,16,130,0,
- 4,0,2,166,4,0,4,150,0,0,0,0,
- 1,0,132,36,4,0,3,150,0,0,0,0,
- 128,0,98,44,6,0,64,20,255,255,69,50,
- 0,1,98,44,4,0,64,20,2,0,162,36,
- 49,80,192,8,3,0,162,36,1,0,162,36,
- 33,144,68,0,1,0,148,38,4,0,98,142,
- 0,0,0,0,42,16,130,2,158,255,64,20,
- 68,0,16,38,12,0,115,142,0,0,0,0,
- 146,255,96,22,0,0,0,0,0,0,178,166,
- 255,255,66,50,52,0,191,143,48,0,182,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,224,255,189,39,
- 24,0,191,175,20,0,177,175,16,0,176,175,
- 33,128,128,0,171,86,192,12,8,0,4,38,
- 255,255,67,48,128,0,98,44,5,0,64,20,
- 2,0,113,36,0,1,98,44,2,0,64,20,
- 3,0,113,36,4,0,113,36,16,0,3,146,
- 64,0,2,36,52,0,98,16,65,0,98,40,
- 17,0,64,16,4,0,2,36,37,0,98,16,
- 0,0,0,0,5,0,98,40,5,0,64,16,
- 2,0,2,36,22,0,98,16,255,255,36,50,
- 145,80,192,8,0,0,0,0,5,0,2,36,
- 36,0,98,16,6,0,2,36,30,0,98,16,
- 255,255,36,50,145,80,192,8,0,0,0,0,
- 68,0,2,36,20,0,98,16,0,0,0,0,
- 68,0,98,40,12,0,64,20,131,0,98,40,
- 28,0,64,16,128,0,98,40,27,0,64,20,
- 255,255,36,50,145,80,192,8,18,0,0,166,
- 40,0,4,142,128,86,192,12,0,0,0,0,
- 144,80,192,8,18,0,2,166,40,0,4,142,
- 153,86,192,12,0,0,0,0,144,80,192,8,
- 18,0,2,166,48,0,2,142,44,0,3,142,
- 0,0,0,0,143,80,192,8,35,16,67,0,
- 171,86,192,12,40,0,4,38,144,80,192,8,
- 18,0,2,166,144,80,192,8,18,0,0,166,
- 4,0,2,36,18,0,2,166,255,255,36,50,
- 18,0,3,150,0,0,0,0,128,0,98,44,
- 6,0,64,20,1,0,132,36,0,1,98,44,
- 4,0,64,20,2,0,98,36,156,80,192,8,
- 3,0,98,36,1,0,98,36,33,16,130,0,
- 4,0,2,166,4,0,3,150,4,0,4,150,
- 0,0,0,0,128,0,130,44,6,0,64,20,
- 1,0,99,36,0,1,130,44,4,0,64,20,
- 2,0,98,36,170,80,192,8,3,0,98,36,
- 1,0,98,36,255,255,66,48,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,16,0,191,175,
- 64,0,130,140,0,0,0,0,12,0,64,20,
- 33,16,0,0,88,0,131,148,4,0,2,36,
- 5,0,98,16,0,0,0,0,180,77,192,12,
- 0,0,0,0,193,80,192,8,255,255,66,48,
- 11,78,192,12,0,0,0,0,255,255,66,48,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,128,0,
- 176,80,192,12,33,136,160,0,33,32,0,2,
- 33,40,32,2,213,80,192,12,255,255,70,48,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,224,255,189,39,
- 28,0,191,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,144,128,0,33,136,192,0,
- 255,255,34,50,41,0,64,16,33,128,160,0,
- 4,0,2,142,0,0,0,0,11,0,64,20,
- 255,255,35,50,9,50,192,12,255,255,36,50,
- 33,24,64,0,32,0,96,16,1,0,2,36,
- 0,0,2,166,4,0,3,174,8,0,3,174,
- 242,80,192,8,12,0,17,166,12,0,2,150,
- 0,0,0,0,43,16,67,0,23,0,64,20,
- 255,255,2,36,64,0,66,142,0,0,0,0,
- 19,0,64,20,255,255,2,36,33,32,0,2,
- 2,0,69,150,33,48,0,0,104,78,192,12,
- 72,0,71,38,88,0,67,150,4,0,2,36,
- 5,0,98,16,33,32,64,2,217,78,192,12,
- 33,40,0,2,8,81,192,8,33,16,0,0,
- 153,78,192,12,33,40,0,2,8,81,192,8,
- 33,16,0,0,255,255,2,36,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,0,0,0,0,
- 0,0,0,0,168,255,189,39,80,0,191,175,
- 76,0,183,175,72,0,182,175,68,0,181,175,
- 64,0,180,175,60,0,179,175,56,0,178,175,
- 52,0,177,175,48,0,176,175,33,24,128,0,
- 33,152,160,0,33,176,192,0,33,184,224,0,
- 104,0,162,143,0,0,0,0,2,0,64,20,
- 44,0,160,175,40,0,162,39,0,0,64,172,
- 24,0,164,39,33,40,96,0,156,88,192,12,
- 33,48,96,2,33,136,64,0,82,0,32,18,
- 33,16,0,0,209,83,192,12,0,0,0,0,
- 33,144,64,0,5,0,64,22,1,0,2,36,
- 183,88,192,12,33,32,32,2,124,81,192,8,
- 33,16,0,0,148,0,66,162,196,88,192,12,
- 33,32,32,2,224,0,85,48,44,0,176,39,
- 33,32,32,2,124,89,192,12,33,40,0,2,
- 33,160,64,0,33,32,32,2,198,89,192,12,
- 33,40,0,2,2,0,66,166,44,0,162,143,
- 0,0,0,0,14,0,64,20,0,0,0,0,
- 8,0,35,142,4,0,34,142,0,0,0,0,
- 35,128,98,0,2,0,66,150,0,0,0,0,
- 33,128,2,2,42,16,19,2,16,0,64,20,
- 33,32,32,2,42,16,112,2,16,0,64,16,
- 0,0,0,0,167,83,192,12,33,32,64,2,
- 183,88,192,12,33,32,32,2,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,124,81,192,8,
- 33,16,0,0,33,40,0,2,42,89,192,12,
- 33,48,0,0,255,0,162,50,255,255,131,50,
- 37,16,67,0,48,0,3,36,8,0,67,20,
- 33,32,64,2,16,0,176,175,33,40,32,2,
- 33,48,192,2,135,81,192,12,33,56,224,2,
- 117,81,192,8,33,128,64,0,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,33,128,0,0,
- 3,0,0,22,0,0,0,0,167,83,192,12,
- 33,32,64,2,183,88,192,12,33,32,32,2,
- 33,16,0,2,80,0,191,143,76,0,183,143,
- 72,0,182,143,68,0,181,143,64,0,180,143,
- 60,0,179,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,88,0,189,39,
- 176,255,189,39,76,0,191,175,72,0,182,175,
- 68,0,181,175,64,0,180,175,60,0,179,175,
- 56,0,178,175,52,0,177,175,48,0,176,175,
- 33,128,128,0,33,136,160,0,33,160,192,0,
- 33,168,224,0,96,0,182,143,24,0,160,175,
- 33,32,32,2,24,0,165,39,2,0,6,36,
- 239,90,192,12,33,56,0,0,64,0,2,174,
- 24,0,162,143,0,0,0,0,155,0,64,20,
- 0,0,0,0,64,0,2,142,0,0,0,0,
- 4,0,64,16,33,32,32,2,3,131,3,60,
- 60,82,192,8,148,17,99,36,16,0,160,175,
- 72,0,5,38,24,0,166,39,110,90,192,12,
- 4,0,7,36,24,0,162,143,0,0,0,0,
- 139,0,64,20,0,0,0,0,196,88,192,12,
- 33,32,32,2,224,0,66,48,160,0,3,36,
- 133,0,67,20,33,32,32,2,124,89,192,12,
- 24,0,165,39,33,144,64,0,33,32,32,2,
- 198,89,192,12,24,0,165,39,33,152,64,0,
- 24,0,162,143,0,0,0,0,122,0,64,20,
- 0,0,0,0,255,255,66,50,5,0,66,44,
- 118,0,64,16,0,0,0,0,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,99,50,33,16,67,0,110,0,194,22,
- 33,32,0,2,88,0,18,166,90,0,19,166,
- 33,40,128,2,178,50,192,12,33,48,160,2,
- 118,0,64,20,33,16,0,0,255,255,67,50,
- 4,0,2,36,24,0,98,16,33,32,32,2,
- 24,0,165,39,2,0,6,36,239,90,192,12,
- 33,56,0,0,92,0,2,174,33,32,32,2,
- 24,0,165,39,2,0,6,36,239,90,192,12,
- 33,56,0,0,96,0,2,174,33,32,32,2,
- 24,0,165,39,2,0,6,36,239,90,192,12,
- 33,56,0,0,100,0,2,174,24,0,162,143,
- 0,0,0,0,78,0,64,20,33,32,32,2,
- 67,82,192,8,104,0,5,38,4,0,2,36,
- 88,0,2,166,90,0,19,166,124,0,0,174,
- 16,0,160,175,92,0,5,38,24,0,166,39,
- 186,91,192,12,6,0,7,36,24,0,162,143,
- 0,0,0,0,63,0,64,20,100,0,4,38,
- 33,40,0,0,144,71,192,12,4,0,6,36,
- 32,0,160,167,40,0,160,175,36,0,160,175,
- 44,0,160,167,32,0,178,39,64,0,2,36,
- 16,0,162,175,33,32,32,2,33,40,64,2,
- 24,0,166,39,110,90,192,12,33,56,0,0,
- 24,0,162,143,0,0,0,0,5,0,64,16,
- 0,0,0,0,24,92,192,12,33,32,64,2,
- 58,82,192,8,0,0,0,0,40,0,162,143,
- 36,0,163,143,0,0,0,0,35,16,67,0,
- 255,255,70,48,5,0,194,44,2,0,64,20,
- 0,0,0,0,4,0,6,36,8,0,192,16,
- 33,32,32,2,36,0,165,143,0,0,0,0,
- 80,68,192,12,100,0,4,38,24,92,192,12,
- 32,0,164,39,33,32,32,2,24,0,165,39,
- 2,0,6,36,239,90,192,12,33,56,0,0,
- 104,0,2,174,33,32,32,2,24,0,165,39,
- 2,0,6,36,239,90,192,12,33,56,0,0,
- 108,0,2,174,33,32,32,2,24,0,165,39,
- 3,0,6,36,239,90,192,12,64,0,7,36,
- 112,0,2,174,24,0,162,143,0,0,0,0,
- 9,0,64,16,33,32,32,2,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,73,82,192,8,
- 33,16,0,0,116,0,5,38,33,48,192,2,
- 163,82,192,12,33,56,0,2,255,255,3,36,
- 248,255,67,16,33,16,0,2,76,0,191,143,
- 72,0,182,143,68,0,181,143,64,0,180,143,
- 60,0,179,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,80,0,189,39,
- 184,255,189,39,64,0,191,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,128,128,0,16,0,160,175,
- 8,0,2,142,4,0,3,142,0,0,0,0,
- 35,184,67,0,33,144,0,0,255,255,162,48,
- 45,0,64,16,33,136,0,0,3,131,19,60,
- 140,17,115,38,255,255,22,36,255,255,181,48,
- 8,0,3,142,4,0,2,142,0,0,0,0,
- 35,160,98,0,0,0,2,146,0,0,0,0,
- 128,0,66,48,32,0,64,20,33,32,0,2,
- 124,89,192,12,16,0,165,39,33,32,0,2,
- 198,89,192,12,16,0,165,39,33,40,64,0,
- 16,0,162,143,0,0,0,0,6,0,64,20,
- 33,32,0,2,255,255,165,48,251,88,192,12,
- 1,0,6,36,7,0,86,20,0,0,0,0,
- 0,0,98,142,0,0,0,0,1,0,66,36,
- 0,0,98,174,147,82,192,8,255,255,17,36,
- 8,0,2,142,4,0,3,142,0,0,0,0,
- 35,16,67,0,33,16,66,2,35,144,84,0,
- 255,255,66,50,43,16,85,0,217,255,64,20,
- 1,0,49,38,33,32,0,2,33,40,224,2,
- 251,88,192,12,33,48,0,0,33,16,32,2,
- 64,0,191,143,60,0,183,143,56,0,182,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,72,0,189,39,192,255,189,39,
- 56,0,191,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,144,128,0,33,152,160,0,
- 33,168,224,0,16,0,160,175,124,89,192,12,
- 16,0,165,39,33,32,64,2,198,89,192,12,
- 16,0,165,39,0,0,98,166,16,0,162,143,
- 0,0,0,0,28,0,64,20,0,0,0,0,
- 12,0,66,142,8,0,67,142,0,0,0,0,
- 35,16,67,0,0,0,99,150,255,255,66,48,
- 20,0,98,20,0,0,0,0,4,0,96,174,
- 0,0,101,150,0,0,0,0,83,82,192,12,
- 33,32,64,2,33,32,64,0,255,255,2,36,
- 46,0,130,16,0,0,0,0,3,0,128,20,
- 0,0,0,0,246,82,192,8,8,0,96,174,
- 224,83,192,12,4,0,100,174,10,0,64,20,
- 8,0,98,174,247,82,192,8,255,255,2,36,
- 3,131,3,60,140,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,210,82,192,8,
- 0,0,98,172,8,0,112,142,4,0,98,142,
- 0,0,0,0,23,0,64,24,33,136,0,0,
- 255,255,20,36,33,32,64,2,124,89,192,12,
- 16,0,165,39,33,32,64,2,198,89,192,12,
- 16,0,165,39,4,0,2,166,16,0,162,143,
- 0,0,0,0,233,255,64,20,33,32,64,2,
- 33,40,0,2,0,83,192,12,33,48,160,2,
- 226,255,84,16,1,0,49,38,4,0,98,142,
- 0,0,0,0,42,16,34,2,236,255,64,20,
- 68,0,16,38,33,16,0,0,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,184,255,189,39,
- 68,0,191,175,64,0,180,175,60,0,179,175,
- 56,0,178,175,52,0,177,175,48,0,176,175,
- 33,128,128,0,33,144,160,0,24,0,160,175,
- 16,0,160,175,8,0,69,38,24,0,166,39,
- 186,91,192,12,6,0,7,36,24,0,162,143,
- 0,0,0,0,103,0,64,20,0,0,0,0,
- 196,88,192,12,33,32,0,2,224,0,84,48,
- 33,32,0,2,124,89,192,12,24,0,165,39,
- 33,152,64,0,33,32,0,2,198,89,192,12,
- 24,0,165,39,33,136,64,0,24,0,162,143,
- 0,0,0,0,88,0,64,20,37,16,116,2,
- 18,0,81,166,16,0,66,162,16,0,67,146,
- 64,0,2,36,48,0,98,16,65,0,98,40,
- 16,0,64,16,4,0,2,36,31,0,98,16,
- 5,0,98,40,5,0,64,16,2,0,2,36,
- 22,0,98,16,33,32,0,2,121,83,192,8,
- 0,0,0,0,5,0,2,36,65,0,98,16,
- 6,0,2,36,27,0,98,16,33,32,0,2,
- 121,83,192,8,0,0,0,0,68,0,2,36,
- 15,0,98,16,68,0,98,40,8,0,64,20,
- 33,32,0,2,131,0,98,40,57,0,64,16,
- 128,0,98,40,51,0,64,16,0,0,0,0,
- 121,83,192,8,0,0,0,0,255,255,37,50,
- 164,90,192,12,24,0,166,39,117,83,192,8,
- 40,0,66,174,33,32,0,2,255,255,37,50,
- 40,0,70,38,19,90,192,12,24,0,167,39,
- 117,83,192,8,0,0,0,0,255,255,37,50,
- 40,0,70,38,24,91,192,12,24,0,167,39,
- 117,83,192,8,0,0,0,0,40,0,68,38,
- 33,40,0,0,144,71,192,12,4,0,6,36,
- 32,0,160,167,40,0,160,175,36,0,160,175,
- 44,0,160,167,33,32,0,2,255,255,37,50,
- 32,0,166,39,19,90,192,12,24,0,167,39,
- 40,0,162,143,36,0,163,143,0,0,0,0,
- 35,16,67,0,255,255,70,48,5,0,194,44,
- 2,0,64,20,0,0,0,0,4,0,6,36,
- 7,0,192,16,0,0,0,0,36,0,165,143,
- 0,0,0,0,80,68,192,12,40,0,68,38,
- 24,92,192,12,32,0,164,39,24,0,162,143,
- 0,0,0,0,8,0,64,16,33,16,0,0,
- 3,131,3,60,140,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,0,0,98,172,
- 255,255,2,36,68,0,191,143,64,0,180,143,
- 60,0,179,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,72,0,189,39,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 33,128,128,0,76,0,2,142,0,0,0,0,
- 3,0,64,16,0,0,0,0,24,92,192,12,
- 72,0,4,38,88,0,3,150,4,0,2,36,
- 5,0,98,20,0,0,0,0,110,86,192,12,
- 92,0,4,38,157,83,192,8,116,0,4,38,
- 13,84,192,12,104,0,4,38,120,0,4,38,
- 13,84,192,12,0,0,0,0,148,0,3,146,
- 0,0,0,0,248,83,192,12,33,32,0,2,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,5,0,0,18,
- 0,0,0,0,136,83,192,12,0,0,0,0,
- 61,50,192,12,33,32,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 224,255,189,39,24,0,191,175,20,0,177,175,
- 16,0,176,175,33,136,128,0,9,50,192,12,
- 16,0,4,36,33,128,64,0,11,0,0,18,
- 33,32,0,2,33,40,0,0,144,71,192,12,
- 16,0,6,36,224,83,192,12,33,32,32,2,
- 4,0,64,16,8,0,2,174,4,0,17,174,
- 204,83,192,8,33,16,0,2,61,50,192,12,
- 33,32,0,2,33,16,0,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,9,50,192,12,152,0,4,36,
- 33,128,64,0,4,0,0,18,33,16,0,0,
- 248,83,192,12,33,32,0,2,33,16,0,2,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,0,17,4,0,33,16,68,0,
- 128,136,2,0,11,0,32,18,16,0,176,175,
- 9,50,192,12,33,32,32,2,33,128,64,0,
- 4,0,0,18,33,32,0,2,33,40,0,0,
- 144,71,192,12,33,48,32,2,243,83,192,8,
- 33,16,0,2,33,16,0,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,33,40,0,0,
- 144,71,192,12,152,0,6,36,255,0,2,36,
- 88,0,2,166,120,5,2,36,58,0,2,166,
- 72,0,0,166,80,0,0,174,76,0,0,174,
- 84,0,0,166,148,0,0,162,149,0,0,162,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,208,255,189,39,40,0,191,175,
- 36,0,179,175,32,0,178,175,28,0,177,175,
- 24,0,176,175,33,128,128,0,31,0,0,18,
- 1,0,19,36,8,0,18,142,0,0,0,0,
- 16,0,64,18,0,0,0,0,4,0,2,142,
- 0,0,0,0,9,0,64,24,33,136,0,0,
- 59,84,192,12,33,32,64,2,1,0,49,38,
- 4,0,2,142,0,0,0,0,42,16,34,2,
- 249,255,64,20,68,0,82,38,8,0,4,142,
- 61,50,192,12,0,0,0,0,12,0,17,142,
- 4,0,96,18,0,0,0,0,33,152,0,0,
- 49,84,192,8,4,0,0,174,61,50,192,12,
- 33,32,0,2,33,128,32,2,227,255,0,22,
- 0,0,0,0,40,0,191,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 60,0,2,142,0,0,0,0,4,0,64,16,
- 0,0,0,0,9,248,64,0,0,0,0,0,
- 60,0,0,174,110,86,192,12,8,0,4,38,
- 78,84,192,12,33,32,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,16,0,191,175,16,0,131,144,
- 6,0,2,36,18,0,98,16,7,0,98,40,
- 5,0,64,16,4,0,2,36,6,0,98,16,
- 0,0,0,0,103,84,192,8,0,0,0,0,
- 68,0,2,36,11,0,98,20,0,0,0,0,
- 44,0,130,140,0,0,0,0,7,0,64,16,
- 0,0,0,0,24,92,192,12,40,0,132,36,
- 103,84,192,8,0,0,0,0,110,86,192,12,
- 40,0,132,36,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,0,0,0,0,
- 216,255,189,39,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,136,192,0,56,0,179,143,0,0,0,0,
- 20,72,192,12,33,144,224,0,33,128,64,0,
- 11,0,0,18,33,32,32,2,33,40,64,2,
- 80,86,192,12,8,0,6,38,255,255,3,36,
- 5,0,67,16,2,0,2,36,16,0,2,162,
- 40,0,19,174,133,84,192,8,33,16,0,0,
- 255,255,2,36,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,177,175,24,0,176,175,
- 33,128,128,0,96,0,5,174,100,0,6,174,
- 128,0,2,142,0,0,0,0,11,0,64,16,
- 0,0,0,0,13,84,192,12,104,0,4,38,
- 124,0,2,142,0,0,0,0,108,0,2,174,
- 128,0,2,142,0,0,0,0,112,0,2,174,
- 128,0,0,174,124,0,0,174,88,0,17,150,
- 2,0,2,36,88,0,2,166,176,80,192,12,
- 33,32,0,2,33,56,64,0,64,0,2,142,
- 0,0,0,0,35,0,64,20,255,255,35,50,
- 3,0,2,36,14,0,98,16,255,255,227,48,
- 58,0,2,150,0,0,0,0,43,16,67,0,
- 9,0,64,16,12,0,4,38,48,0,2,142,
- 28,0,5,38,52,0,7,142,0,0,0,0,
- 9,248,64,0,1,0,6,36,214,84,192,8,
- 0,0,0,0,96,0,2,142,0,0,0,0,
- 250,255,67,36,13,0,98,44,13,0,64,16,
- 128,16,3,0,2,131,1,60,33,8,34,0,
- 32,154,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,204,84,192,8,2,0,2,36,
- 204,84,192,8,3,0,2,36,5,0,2,36,
- 96,0,2,174,52,0,2,142,0,0,0,0,
- 16,0,162,175,44,0,2,142,12,0,4,38,
- 28,0,5,38,33,48,0,2,9,248,64,0,
- 255,255,231,48,32,0,191,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 224,255,189,39,28,0,191,175,24,0,176,175,
- 33,128,128,0,96,0,5,142,0,0,0,0,
- 6,0,160,16,0,0,0,0,100,0,6,142,
- 140,84,192,12,0,0,0,0,56,85,192,8,
- 0,0,0,0,176,80,192,12,33,32,0,2,
- 33,56,64,0,88,0,2,150,0,0,0,0,
- 2,0,66,44,11,0,64,16,255,255,227,48,
- 58,0,2,150,0,0,0,0,43,16,67,0,
- 6,0,64,16,33,32,0,2,1,0,5,36,
- 140,84,192,12,33,48,0,0,56,85,192,8,
- 0,0,0,0,96,0,2,142,0,0,0,0,
- 49,0,64,20,2,0,2,36,88,0,3,150,
- 3,0,2,36,33,0,98,16,4,0,98,40,
- 7,0,64,16,2,0,98,40,41,0,64,16,
- 2,0,2,36,39,0,96,4,0,0,0,0,
- 13,85,192,8,0,0,0,0,5,0,2,36,
- 34,0,98,20,2,0,2,36,3,131,3,60,
- 236,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,104,0,4,38,25,0,128,16,
- 0,0,98,172,3,131,5,60,176,17,165,36,
- 0,0,162,140,108,0,3,142,0,0,0,0,
- 33,16,67,0,0,0,162,172,12,0,132,140,
- 0,0,0,0,248,255,128,20,2,0,2,36,
- 47,85,192,8,88,0,2,166,3,131,4,60,
- 236,17,132,36,0,0,130,140,0,0,0,0,
- 1,0,66,36,0,0,130,172,200,255,130,140,
- 108,0,3,142,0,0,0,0,33,16,67,0,
- 200,255,130,172,2,0,2,36,88,0,2,166,
- 52,0,2,142,0,0,0,0,16,0,162,175,
- 44,0,2,142,12,0,4,38,28,0,5,38,
- 33,48,0,2,9,248,64,0,255,255,231,48,
- 28,0,191,143,24,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,88,0,3,150,
- 1,0,2,36,25,0,98,16,2,0,98,40,
- 5,0,64,16,3,0,2,36,7,0,96,16,
- 0,0,0,0,116,85,192,8,0,0,0,0,
- 37,0,98,16,0,0,0,0,116,85,192,8,
- 0,0,0,0,112,0,4,142,108,0,3,142,
- 0,0,0,0,34,0,96,16,0,0,0,0,
- 17,0,130,144,0,0,0,0,2,0,66,48,
- 33,0,64,16,255,255,99,36,250,255,96,20,
- 68,0,132,36,116,85,192,8,0,0,0,0,
- 112,0,4,142,108,0,3,142,0,0,0,0,
- 8,0,96,16,0,0,0,0,17,0,130,144,
- 0,0,0,0,2,0,66,48,19,0,64,16,
- 255,255,99,36,250,255,96,20,68,0,132,36,
- 118,93,192,12,33,32,0,2,241,255,64,28,
- 255,255,66,40,7,0,64,16,0,0,0,0,
- 92,85,192,8,0,0,0,0,120,94,192,12,
- 33,32,0,2,5,0,64,20,0,0,0,0,
- 219,84,192,12,33,32,0,2,167,83,192,12,
- 33,32,0,2,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 88,0,3,150,1,0,2,36,17,0,98,16,
- 2,0,98,40,5,0,64,16,3,0,2,36,
- 9,0,96,16,0,0,0,0,156,85,192,8,
- 0,0,0,0,13,0,98,16,5,0,2,36,
- 7,0,98,16,0,0,0,0,156,85,192,8,
- 0,0,0,0,60,95,192,12,33,32,0,2,
- 154,85,192,8,0,0,0,0,0,93,192,12,
- 33,32,0,2,154,85,192,8,0,0,0,0,
- 252,93,192,12,33,32,0,2,5,0,64,20,
- 0,0,0,0,60,85,192,12,33,32,0,2,
- 162,85,192,8,0,0,0,0,167,83,192,12,
- 33,32,0,2,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,192,255,189,39,
- 60,0,191,175,56,0,182,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,64,128,0,
- 33,136,192,0,33,152,224,0,84,0,182,143,
- 88,0,181,143,92,0,180,143,80,0,178,151,
- 3,131,3,60,128,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,0,0,98,172,
- 24,0,162,39,16,0,162,175,33,32,160,0,
- 16,81,192,12,33,40,0,1,33,128,64,0,
- 57,0,0,18,255,255,66,50,58,0,3,150,
- 0,0,0,0,43,16,67,0,2,0,64,16,
- 0,0,0,0,58,0,18,166,44,0,22,174,
- 48,0,21,174,52,0,20,174,24,0,162,143,
- 0,0,0,0,7,0,64,16,1,0,2,36,
- 219,84,192,12,33,32,0,2,167,83,192,12,
- 33,32,0,2,5,86,192,8,0,0,0,0,
- 88,0,3,150,0,0,0,0,16,0,98,16,
- 2,0,98,40,5,0,64,16,3,0,2,36,
- 9,0,96,16,0,0,0,0,244,85,192,8,
- 0,0,0,0,11,0,98,16,5,0,2,36,
- 31,0,98,16,0,0,0,0,244,85,192,8,
- 0,0,0,0,3,131,3,60,239,85,192,8,
- 184,17,99,36,3,131,3,60,239,85,192,8,
- 188,17,99,36,3,131,3,60,192,17,99,36,
- 0,0,98,140,0,0,0,0,1,0,66,36,
- 3,86,192,8,0,0,98,172,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,167,83,192,12,
- 33,32,0,2,33,32,32,2,33,40,96,2,
- 1,0,6,36,9,248,160,2,33,56,128,2,
- 5,86,192,8,0,0,0,0,124,85,192,12,
- 33,32,0,2,60,0,191,143,56,0,182,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 213,80,192,12,255,255,198,48,53,0,64,20,
- 255,255,2,36,3,131,3,60,144,17,99,36,
- 0,0,98,140,0,0,0,0,1,0,66,36,
- 0,0,98,172,96,0,2,142,0,0,0,0,
- 32,0,64,16,4,0,2,36,92,0,98,140,
- 0,0,0,0,1,0,66,36,92,0,98,172,
- 96,0,2,142,0,0,0,0,255,255,67,36,
- 5,0,98,44,32,0,64,16,128,16,3,0,
- 2,131,1,60,33,8,34,0,88,154,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 3,131,3,60,70,86,192,8,204,17,99,36,
- 3,131,3,60,70,86,192,8,212,17,99,36,
- 3,131,3,60,70,86,192,8,216,17,99,36,
- 3,131,3,60,70,86,192,8,208,17,99,36,
- 3,131,3,60,70,86,192,8,220,17,99,36,
- 88,0,3,150,0,0,0,0,8,0,98,20,
- 33,16,0,0,3,131,3,60,240,17,99,36,
- 0,0,98,140,0,0,0,0,1,0,66,36,
- 0,0,98,172,33,16,0,0,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 0,0,0,0,224,255,189,39,28,0,191,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,144,160,0,33,128,192,0,4,0,0,174,
- 14,0,128,16,0,0,4,174,128,136,4,0,
- 9,50,192,12,33,32,32,2,3,0,64,20,
- 4,0,2,174,104,86,192,8,255,255,2,36,
- 5,0,32,18,33,40,64,2,4,0,4,142,
- 0,0,0,0,80,68,192,12,33,48,32,2,
- 33,16,0,0,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,4,0,4,142,
- 0,0,0,0,4,0,128,16,0,0,0,0,
- 61,50,192,12,0,0,0,0,4,0,0,174,
- 0,0,0,174,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,0,0,0,0,
- 0,0,0,0,11,0,128,4,128,0,130,40,
- 20,0,64,20,1,0,3,36,255,127,2,36,
- 42,16,68,0,16,0,64,16,2,0,3,36,
- 127,0,2,60,255,255,66,52,148,86,192,8,
- 42,16,68,0,128,255,130,40,9,0,64,16,
- 1,0,3,36,0,128,130,40,6,0,64,16,
- 2,0,3,36,128,255,2,60,42,16,130,0,
- 2,0,64,20,4,0,3,36,3,0,3,36,
- 8,0,224,3,33,16,96,0,128,0,130,44,
- 14,0,64,20,1,0,2,36,255,127,2,36,
- 43,16,68,0,9,0,64,16,127,0,2,60,
- 255,255,66,52,43,16,68,0,6,0,64,16,
- 3,0,2,36,4,0,128,4,5,0,2,36,
- 169,86,192,8,4,0,2,36,2,0,2,36,
- 8,0,224,3,0,0,0,0,4,0,135,140,
- 0,0,130,140,0,0,0,0,65,0,64,16,
- 33,16,0,0,0,0,227,140,4,0,231,36,
- 128,16,3,0,33,16,67,0,192,16,2,0,
- 0,0,227,140,0,0,0,0,33,24,67,0,
- 128,0,98,44,17,0,64,20,4,0,231,36,
- 0,64,98,44,15,0,64,20,2,0,5,36,
- 31,0,2,60,255,255,66,52,43,16,67,0,
- 7,0,64,16,255,15,2,60,255,255,66,52,
- 43,16,67,0,6,0,64,20,5,0,5,36,
- 204,86,192,8,4,0,5,36,204,86,192,8,
- 3,0,5,36,1,0,5,36,2,0,6,36,
- 0,0,130,140,0,0,0,0,42,16,194,0,
- 31,0,64,16,255,255,162,48,31,0,9,60,
- 255,255,41,53,255,15,8,60,255,255,8,53,
- 0,0,132,140,0,0,227,140,4,0,231,36,
- 128,0,98,44,16,0,64,20,255,255,165,48,
- 0,64,98,44,11,0,64,20,43,16,35,1,
- 7,0,64,16,43,16,3,1,3,0,64,20,
- 0,0,0,0,236,86,192,8,4,0,165,36,
- 236,86,192,8,5,0,165,36,236,86,192,8,
- 3,0,165,36,236,86,192,8,2,0,165,36,
- 1,0,165,36,1,0,198,36,42,16,196,0,
- 232,255,64,20,255,255,162,48,8,0,224,3,
- 0,0,0,0,208,255,189,39,40,0,191,175,
- 33,72,192,0,224,0,165,48,255,255,130,48,
- 31,0,66,44,7,0,64,16,33,48,160,0,
- 37,16,133,0,16,0,162,163,33,32,224,0,
- 16,0,165,39,38,87,192,8,1,0,6,36,
- 32,0,163,39,33,40,0,0,31,0,194,52,
- 24,0,162,163,255,255,130,48,8,0,64,16,
- 25,0,168,39,127,0,130,48,0,0,98,160,
- 1,0,99,36,255,255,130,48,194,33,2,0,
- 250,255,128,20,1,0,165,36,1,0,166,36,
- 33,16,160,0,255,255,66,48,2,0,66,44,
- 13,0,64,20,255,255,165,36,255,255,4,52,
- 255,255,99,36,0,0,98,144,0,0,0,0,
- 128,0,66,52,0,0,2,161,1,0,8,37,
- 33,16,160,0,255,255,66,48,2,0,66,44,
- 246,255,64,16,33,40,164,0,255,255,98,144,
- 0,0,0,0,0,0,2,161,33,32,224,0,
- 24,0,165,39,255,255,198,48,9,248,32,1,
- 0,0,0,0,40,0,191,143,48,0,189,39,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 40,0,191,175,33,72,160,0,255,255,130,48,
- 128,0,66,44,6,0,64,16,33,64,192,0,
- 16,0,164,163,33,32,0,1,16,0,165,39,
- 88,87,192,8,1,0,6,36,24,0,167,39,
- 32,0,165,39,255,255,130,48,7,0,64,16,
- 33,24,0,0,0,0,164,160,1,0,165,36,
- 255,255,130,48,2,34,2,0,251,255,128,20,
- 1,0,99,36,128,0,98,52,0,0,226,160,
- 1,0,231,36,1,0,102,36,33,16,96,0,
- 255,255,66,48,11,0,64,16,255,255,99,36,
- 255,255,4,52,255,255,165,36,0,0,162,144,
- 0,0,0,0,0,0,226,160,1,0,231,36,
- 33,16,96,0,255,255,66,48,248,255,64,20,
- 33,24,100,0,33,32,0,1,24,0,165,39,
- 255,255,198,48,9,248,32,1,0,0,0,0,
- 40,0,191,143,48,0,189,39,8,0,224,3,
- 0,0,0,0,200,255,189,39,48,0,191,175,
- 44,0,181,175,40,0,180,175,36,0,179,175,
- 32,0,178,175,28,0,177,175,24,0,176,175,
- 33,136,160,0,33,144,192,0,33,152,224,0,
- 72,0,180,143,33,128,128,0,128,86,192,12,
- 33,32,64,2,33,168,64,0,255,255,4,50,
- 192,0,37,50,33,48,96,2,242,86,192,12,
- 33,56,128,2,255,255,176,50,33,32,0,2,
- 33,40,96,2,44,87,192,12,33,48,128,2,
- 16,0,162,39,33,24,80,0,255,255,99,36,
- 6,0,98,16,0,0,114,160,16,0,162,39,
- 3,146,18,0,255,255,99,36,253,255,98,20,
- 0,0,114,160,33,32,128,2,16,0,165,39,
- 9,248,96,2,255,255,166,50,48,0,191,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,200,255,189,39,
- 48,0,191,175,44,0,181,175,40,0,180,175,
- 36,0,179,175,32,0,178,175,28,0,177,175,
- 24,0,176,175,33,136,160,0,33,144,192,0,
- 33,160,224,0,72,0,181,143,33,128,128,0,
- 153,86,192,12,33,32,64,2,33,152,64,0,
- 255,255,4,50,192,0,37,50,33,48,128,2,
- 242,86,192,12,33,56,160,2,255,255,112,50,
- 33,32,0,2,33,40,128,2,44,87,192,12,
- 33,48,160,2,16,0,162,39,33,32,80,0,
- 9,0,0,18,255,255,99,38,255,255,5,52,
- 255,255,132,36,0,0,146,160,2,146,18,0,
- 33,16,96,0,255,255,66,48,250,255,64,20,
- 33,24,101,0,33,32,160,2,16,0,165,39,
- 9,248,128,2,255,255,102,50,48,0,191,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,152,192,0,
- 56,0,178,143,60,0,177,143,33,128,224,0,
- 255,255,132,48,192,0,165,48,33,48,64,2,
- 242,86,192,12,33,56,32,2,255,255,16,50,
- 33,32,0,2,33,40,64,2,44,87,192,12,
- 33,48,32,2,4,0,0,18,33,32,32,2,
- 33,40,96,2,9,248,64,2,33,48,0,2,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,224,255,189,39,24,0,191,175,
- 33,72,160,0,128,0,130,44,18,0,64,20,
- 33,64,192,0,0,64,130,44,13,0,64,20,
- 31,0,2,60,255,255,66,52,43,16,68,0,
- 7,0,64,16,255,15,2,60,255,255,66,52,
- 43,16,68,0,8,0,64,20,5,0,6,36,
- 250,87,192,8,4,0,6,36,250,87,192,8,
- 3,0,6,36,250,87,192,8,2,0,6,36,
- 1,0,6,36,255,255,194,48,16,0,163,39,
- 33,40,98,0,9,0,163,16,33,56,0,0,
- 16,0,163,39,255,255,165,36,127,0,130,48,
- 37,16,226,0,0,0,162,160,194,33,4,0,
- 250,255,163,20,128,0,7,36,33,32,0,1,
- 16,0,165,39,9,248,32,1,255,255,198,48,
- 24,0,191,143,32,0,189,39,8,0,224,3,
- 0,0,0,0,208,255,189,39,44,0,191,175,
- 40,0,182,175,36,0,181,175,32,0,180,175,
- 28,0,179,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,144,160,0,33,168,192,0,
- 33,160,224,0,64,0,182,143,33,136,128,0,
- 4,0,179,142,0,0,0,0,171,86,192,12,
- 33,32,160,2,33,128,64,0,255,255,36,50,
- 192,0,69,50,33,48,128,2,242,86,192,12,
- 33,56,192,2,255,255,16,50,33,32,0,2,
- 33,40,128,2,44,87,192,12,33,48,192,2,
- 23,0,0,18,33,40,128,2,0,0,98,142,
- 4,0,115,38,128,32,2,0,33,32,130,0,
- 192,32,4,0,0,0,98,142,4,0,115,38,
- 33,32,130,0,226,87,192,12,33,48,192,2,
- 63,88,192,8,2,0,16,36,0,0,100,142,
- 4,0,115,38,226,87,192,12,33,48,192,2,
- 1,0,16,38,0,0,162,142,0,0,0,0,
- 42,16,2,2,247,255,64,20,33,40,128,2,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,224,255,189,39,28,0,191,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,136,128,0,33,144,192,0,255,255,67,50,
- 12,0,34,150,0,0,0,0,43,16,67,0,
- 4,0,64,16,1,0,2,36,12,0,50,150,
- 0,0,0,0,255,255,67,50,11,0,98,16,
- 2,0,98,40,5,0,64,16,2,0,2,36,
- 50,0,96,16,255,255,80,50,137,88,192,8,
- 0,0,0,0,15,0,98,16,255,255,80,50,
- 137,88,192,8,0,0,0,0,8,0,35,142,
- 0,0,0,0,1,0,98,36,8,0,34,174,
- 0,0,162,144,0,0,0,0,0,0,98,160,
- 12,0,34,150,0,0,0,0,255,255,66,36,
- 149,88,192,8,12,0,34,166,8,0,35,142,
- 0,0,0,0,1,0,98,36,8,0,34,174,
- 0,0,162,144,0,0,0,0,0,0,98,160,
- 8,0,35,142,0,0,0,0,1,0,98,36,
- 8,0,34,174,1,0,162,144,0,0,0,0,
- 0,0,98,160,12,0,34,150,0,0,0,0,
- 254,255,66,36,149,88,192,8,12,0,34,166,
- 8,0,36,142,0,0,0,0,80,68,192,12,
- 33,48,0,2,12,0,34,150,0,0,0,0,
- 35,16,82,0,12,0,34,166,8,0,34,142,
- 0,0,0,0,33,128,2,2,8,0,48,174,
- 255,255,66,50,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,160,0,
- 10,0,128,20,33,136,192,0,9,50,192,12,
- 16,0,4,36,33,32,64,0,3,0,128,20,
- 1,0,2,36,178,88,192,8,33,16,0,0,
- 173,88,192,8,0,0,130,160,0,0,128,160,
- 4,0,144,172,8,0,144,172,33,16,17,2,
- 12,0,130,172,33,16,128,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,16,0,191,175,
- 0,0,130,144,0,0,0,0,1,0,66,48,
- 3,0,64,16,0,0,0,0,61,50,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,255,2,36,8,0,130,140,12,0,131,140,
- 0,0,0,0,43,16,67,0,7,0,64,20,
- 0,0,0,0,0,0,130,144,0,0,0,0,
- 128,0,66,52,0,0,130,160,216,88,192,8,
- 255,255,2,36,8,0,130,140,0,0,0,0,
- 0,0,66,144,8,0,224,3,0,0,0,0,
- 30,0,192,24,33,56,192,0,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,3,36,8,0,131,140,12,0,130,140,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,130,172,0,0,99,144,
- 240,88,192,8,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,3,36,0,0,130,144,0,0,0,0,
- 128,0,66,48,5,0,64,20,0,0,0,0,
- 0,0,163,160,255,255,198,36,228,255,192,28,
- 1,0,165,36,8,0,224,3,35,16,230,0,
- 1,0,2,36,15,0,194,16,2,0,194,40,
- 5,0,64,16,2,0,2,36,7,0,192,16,
- 255,255,2,36,40,89,192,8,0,0,0,0,
- 11,0,194,16,255,255,2,36,40,89,192,8,
- 0,0,0,0,4,0,130,140,0,0,0,0,
- 21,89,192,8,33,40,162,0,8,0,130,140,
- 0,0,0,0,19,89,192,8,33,40,162,0,
- 12,0,130,140,0,0,0,0,35,40,69,0,
- 4,0,130,140,0,0,0,0,43,16,162,0,
- 17,0,64,20,255,255,2,36,12,0,130,140,
- 0,0,0,0,43,16,69,0,12,0,64,20,
- 255,255,2,36,12,0,130,140,0,0,0,0,
- 43,16,162,0,5,0,64,16,0,0,0,0,
- 0,0,130,144,0,0,0,0,127,0,66,48,
- 0,0,130,160,8,0,133,172,33,16,0,0,
- 8,0,224,3,0,0,0,0,12,0,130,140,
- 4,0,131,140,0,0,0,0,35,56,67,0,
- 1,0,2,36,15,0,194,16,2,0,194,40,
- 5,0,64,16,2,0,2,36,7,0,192,16,
- 255,255,2,36,87,89,192,8,0,0,0,0,
- 12,0,194,16,255,255,2,36,87,89,192,8,
- 0,0,0,0,4,0,130,140,0,0,0,0,
- 66,89,192,8,33,16,162,0,8,0,130,140,
- 0,0,0,0,33,16,162,0,72,89,192,8,
- 12,0,130,172,12,0,130,140,0,0,0,0,
- 35,16,69,0,12,0,130,172,8,0,130,140,
- 12,0,131,140,0,0,0,0,43,16,67,0,
- 5,0,64,16,0,0,0,0,0,0,130,144,
- 0,0,0,0,85,89,192,8,127,0,66,48,
- 0,0,130,144,0,0,0,0,128,0,66,52,
- 0,0,130,160,33,16,224,0,8,0,224,3,
- 0,0,0,0,232,255,189,39,20,0,191,175,
- 16,0,176,175,12,0,128,20,33,128,160,0,
- 9,50,192,12,16,0,4,36,33,32,64,0,
- 3,0,128,20,0,0,0,0,119,89,192,8,
- 33,16,0,0,0,0,2,146,0,0,0,0,
- 108,89,192,8,1,0,66,52,0,0,2,146,
- 0,0,0,0,254,0,66,48,0,0,130,160,
- 4,0,2,142,0,0,0,0,4,0,130,172,
- 8,0,2,142,0,0,0,0,8,0,130,172,
- 12,0,2,142,0,0,0,0,12,0,130,172,
- 33,16,128,0,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,0,0,0,0,
- 0,0,130,144,0,0,0,0,128,0,66,48,
- 17,0,64,20,31,0,3,36,8,0,131,140,
- 12,0,130,140,0,0,0,0,43,16,98,0,
- 6,0,64,16,1,0,98,36,8,0,130,172,
- 0,0,98,144,0,0,0,0,145,89,192,8,
- 31,0,67,48,0,0,130,144,0,0,0,0,
- 128,0,66,52,0,0,130,160,31,0,3,36,
- 0,0,130,144,0,0,0,0,128,0,66,48,
- 4,0,64,16,1,0,2,36,0,0,162,172,
- 196,89,192,8,33,16,0,0,255,0,99,48,
- 31,0,2,36,6,0,98,16,33,16,96,0,
- 196,89,192,8,0,0,0,0,1,0,2,36,
- 195,89,192,8,0,0,162,172,33,48,0,0,
- 0,0,130,144,0,0,0,0,128,0,66,48,
- 16,0,64,20,255,0,3,36,8,0,131,140,
- 12,0,130,140,0,0,0,0,43,16,98,0,
- 5,0,64,16,1,0,98,36,8,0,130,172,
- 0,0,99,144,183,89,192,8,0,0,0,0,
- 0,0,130,144,0,0,0,0,128,0,66,52,
- 0,0,130,160,255,0,3,36,0,0,130,144,
- 0,0,0,0,128,0,66,48,228,255,64,20,
- 128,0,98,48,4,0,64,16,127,0,98,48,
- 37,16,194,0,163,89,192,8,192,49,2,0,
- 255,0,98,48,37,48,70,0,255,255,194,48,
- 8,0,224,3,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,6,36,8,0,131,140,12,0,130,140,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,130,172,0,0,102,144,
- 218,89,192,8,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,6,36,0,0,130,144,0,0,0,0,
- 128,0,66,48,13,0,64,20,1,0,2,36,
- 255,0,195,48,128,0,2,36,4,0,98,20,
- 2,0,2,36,0,0,162,172,17,90,192,8,
- 255,255,2,52,128,0,194,48,6,0,64,20,
- 33,24,0,0,17,90,192,8,255,0,194,48,
- 0,0,162,172,17,90,192,8,33,16,0,0,
- 127,0,194,48,32,0,64,16,255,255,71,36,
- 0,26,3,0,0,0,130,144,0,0,0,0,
- 128,0,66,48,16,0,64,20,255,255,102,48,
- 8,0,131,140,12,0,130,140,0,0,0,0,
- 43,16,98,0,6,0,64,16,1,0,98,36,
- 8,0,130,172,0,0,98,144,0,0,0,0,
- 7,90,192,8,37,24,194,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,195,52,0,0,130,144,0,0,0,0,
- 128,0,66,48,224,255,64,20,1,0,2,36,
- 33,16,224,0,255,0,66,48,226,255,64,20,
- 255,255,231,36,255,255,98,48,8,0,224,3,
- 0,0,0,0,216,255,189,39,36,0,191,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,152,128,0,
- 33,128,192,0,33,144,160,0,255,255,81,50,
- 33,0,32,18,33,160,224,0,255,255,2,52,
- 30,0,34,18,0,0,0,0,9,50,192,12,
- 33,32,32,2,33,24,64,0,29,0,96,16,
- 1,0,2,36,0,0,2,166,4,0,3,174,
- 8,0,3,174,12,0,18,166,33,32,96,2,
- 8,0,5,142,0,0,0,0,218,88,192,12,
- 33,48,32,2,33,24,64,0,255,255,100,48,
- 10,0,145,20,1,0,2,36,12,0,2,150,
- 0,0,0,0,35,16,67,0,12,0,2,166,
- 8,0,2,142,0,0,0,0,33,16,130,0,
- 68,90,192,8,8,0,2,174,68,90,192,8,
- 0,0,130,174,0,0,0,166,4,0,0,174,
- 8,0,0,174,12,0,0,166,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,224,255,189,39,28,0,191,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,144,128,0,33,136,160,0,33,128,192,0,
- 124,89,192,12,33,40,0,2,33,32,64,2,
- 198,89,192,12,33,40,0,2,33,40,64,0,
- 0,0,2,142,0,0,0,0,7,0,64,20,
- 33,32,64,2,255,255,165,48,33,48,32,2,
- 19,90,192,12,33,56,0,2,104,90,192,8,
- 0,0,0,0,0,0,32,166,4,0,32,174,
- 8,0,32,174,12,0,32,166,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 36,0,191,175,32,0,180,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,152,128,0,33,136,160,0,33,144,192,0,
- 56,0,176,147,0,0,0,0,196,88,192,12,
- 33,160,224,0,224,0,66,48,7,0,80,20,
- 33,32,96,2,124,89,192,12,33,40,64,2,
- 255,255,66,48,255,255,131,50,7,0,67,16,
- 33,32,96,2,0,0,66,142,0,0,0,0,
- 16,0,64,20,4,0,2,36,152,90,192,8,
- 0,0,66,174,198,89,192,12,33,40,64,2,
- 33,40,64,0,0,0,66,142,0,0,0,0,
- 7,0,64,20,33,32,96,2,255,255,165,48,
- 33,48,32,2,19,90,192,12,33,56,64,2,
- 156,90,192,8,0,0,0,0,0,0,32,166,
- 4,0,32,174,8,0,32,174,12,0,32,166,
- 36,0,191,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,33,56,0,0,
- 255,255,168,36,255,255,165,48,50,0,160,16,
- 1,0,9,36,1,0,12,36,4,0,10,36,
- 3,0,11,36,255,255,5,52,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,3,36,8,0,131,140,12,0,130,140,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,130,172,0,0,99,144,
- 193,90,192,8,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,3,36,0,0,130,144,0,0,0,0,
- 128,0,66,48,3,0,64,16,0,0,0,0,
- 218,90,192,8,0,0,204,172,11,0,32,17,
- 255,255,2,49,5,0,74,20,33,72,0,0,
- 3,0,96,16,0,0,0,0,218,90,192,8,
- 0,0,203,172,128,0,98,48,3,0,64,16,
- 0,18,7,0,255,255,7,36,0,18,7,0,
- 37,56,67,0,33,16,0,1,255,255,66,48,
- 212,255,64,20,33,64,5,1,8,0,224,3,
- 33,16,224,0,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,128,0,
- 124,89,192,12,33,136,160,0,33,32,0,2,
- 198,89,192,12,33,40,32,2,33,32,0,2,
- 255,255,69,48,164,90,192,12,33,48,32,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,144,128,0,
- 33,136,160,0,33,152,192,0,196,88,192,12,
- 33,128,224,0,224,0,66,48,255,0,16,50,
- 7,0,80,20,33,32,64,2,124,89,192,12,
- 33,40,32,2,255,255,66,48,255,255,99,50,
- 8,0,67,16,33,32,64,2,0,0,34,142,
- 0,0,0,0,2,0,64,20,4,0,2,36,
- 0,0,34,174,17,91,192,8,33,16,0,0,
- 198,89,192,12,33,40,32,2,33,32,64,2,
- 255,255,69,48,164,90,192,12,33,48,32,2,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,208,255,189,39,44,0,191,175,
- 40,0,180,175,36,0,179,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,152,192,0,33,160,224,0,0,0,96,174,
- 4,0,96,174,8,0,3,142,4,0,2,142,
- 0,0,0,0,35,24,98,0,255,255,165,48,
- 35,0,160,24,33,144,0,0,1,0,6,36,
- 0,0,2,146,0,0,0,0,128,0,66,48,
- 16,0,64,20,255,0,4,36,8,0,4,142,
- 12,0,2,142,0,0,0,0,43,16,130,0,
- 5,0,64,16,1,0,130,36,8,0,2,174,
- 0,0,132,144,64,91,192,8,0,0,0,0,
- 0,0,2,146,0,0,0,0,128,0,66,52,
- 0,0,2,162,255,0,4,36,0,0,2,146,
- 0,0,0,0,128,0,66,48,3,0,64,16,
- 128,0,130,48,150,91,192,8,0,0,134,174,
- 2,0,64,20,0,0,0,0,1,0,82,38,
- 255,255,165,36,224,255,160,28,0,0,0,0,
- 33,32,0,2,33,40,96,0,251,88,192,12,
- 33,48,0,0,68,0,64,18,1,0,81,38,
- 9,50,192,12,128,32,17,0,33,40,64,0,
- 63,0,160,16,0,0,0,0,0,0,113,174,
- 4,0,101,174,59,0,64,26,33,56,0,0,
- 1,0,8,36,33,48,0,0,0,0,2,146,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,4,36,8,0,3,142,12,0,2,142,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,2,174,0,0,100,144,
- 114,91,192,8,0,0,0,0,0,0,2,146,
- 0,0,0,0,128,0,66,52,0,0,2,162,
- 255,0,4,36,0,0,2,146,0,0,0,0,
- 128,0,66,48,3,0,64,16,192,49,6,0,
- 150,91,192,8,0,0,136,174,127,0,130,48,
- 37,48,194,0,128,0,130,48,225,255,64,20,
- 0,0,0,0,18,0,224,20,40,0,194,44,
- 4,0,64,16,80,0,194,44,0,0,160,172,
- 145,91,192,8,4,0,165,36,5,0,64,16,
- 216,255,194,36,0,0,168,172,4,0,165,36,
- 146,91,192,8,0,0,162,172,2,0,2,36,
- 0,0,162,172,4,0,165,36,176,255,194,36,
- 146,91,192,8,0,0,162,172,0,0,166,172,
- 1,0,231,36,42,16,242,0,200,255,64,20,
- 4,0,165,36,44,0,191,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,28,0,191,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,136,128,0,
- 33,144,160,0,33,128,192,0,124,89,192,12,
- 33,40,0,2,33,32,32,2,198,89,192,12,
- 33,40,0,2,33,40,64,0,0,0,2,142,
- 0,0,0,0,5,0,64,20,33,32,32,2,
- 255,255,165,48,33,48,64,2,24,91,192,12,
- 33,56,0,2,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,216,255,189,39,36,0,191,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,144,128,0,
- 33,160,160,0,33,136,192,0,56,0,176,147,
- 0,0,0,0,196,88,192,12,33,152,224,0,
- 224,0,66,48,7,0,80,20,33,32,64,2,
- 124,89,192,12,33,40,32,2,255,255,66,48,
- 255,255,99,50,7,0,67,16,33,32,64,2,
- 0,0,34,142,0,0,0,0,14,0,64,20,
- 4,0,2,36,226,91,192,8,0,0,34,174,
- 198,89,192,12,33,40,32,2,33,40,64,0,
- 0,0,34,142,0,0,0,0,5,0,64,20,
- 33,32,64,2,255,255,165,48,33,48,128,2,
- 24,91,192,12,33,56,32,2,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,0,0,0,0,0,0,0,0,
- 216,255,189,39,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,152,128,0,8,0,99,142,4,0,98,142,
- 0,0,0,0,35,128,98,0,255,255,4,50,
- 19,0,128,16,33,136,160,0,9,50,192,12,
- 0,0,0,0,33,144,64,0,3,0,64,22,
- 255,255,16,50,17,92,192,8,255,255,2,36,
- 33,32,64,2,4,0,101,142,0,0,0,0,
- 80,68,192,12,33,48,0,2,1,0,2,36,
- 0,0,34,166,4,0,50,174,33,128,80,2,
- 15,92,192,8,8,0,48,174,0,0,32,166,
- 4,0,32,174,8,0,32,174,12,0,32,166,
- 33,16,0,0,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 0,0,2,150,0,0,0,0,1,0,66,48,
- 7,0,64,16,0,0,0,0,4,0,4,142,
- 0,0,0,0,3,0,128,16,0,0,0,0,
- 61,50,192,12,0,0,0,0,0,0,0,166,
- 8,0,0,174,4,0,0,174,12,0,0,166,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,128,0,
- 8,0,163,140,4,0,162,140,0,0,0,0,
- 35,136,98,0,255,255,35,50,12,0,2,150,
- 0,0,0,0,43,16,67,0,4,0,64,16,
- 255,255,38,50,12,0,17,150,0,0,0,0,
- 255,255,38,50,6,0,192,16,255,255,34,50,
- 8,0,4,142,4,0,165,140,80,68,192,12,
- 0,0,0,0,255,255,34,50,8,0,3,142,
- 0,0,0,0,33,16,67,0,8,0,2,174,
- 12,0,2,150,0,0,0,0,35,16,81,0,
- 12,0,2,166,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 1,0,2,36,23,0,194,16,2,0,194,40,
- 5,0,64,16,2,0,2,36,7,0,192,16,
- 255,255,2,36,132,92,192,8,0,0,0,0,
- 23,0,194,16,255,255,2,36,132,92,192,8,
- 0,0,0,0,255,255,162,48,4,0,131,140,
- 0,0,0,0,33,48,67,0,8,0,130,140,
- 0,0,0,0,35,16,67,0,12,0,131,148,
- 0,0,0,0,33,16,67,0,124,92,192,8,
- 35,40,69,0,255,255,162,48,8,0,131,140,
- 0,0,0,0,33,48,67,0,12,0,130,148,
- 0,0,0,0,124,92,192,8,35,40,69,0,
- 12,0,130,148,8,0,131,140,0,0,0,0,
- 33,48,67,0,255,255,162,48,35,48,194,0,
- 4,0,130,140,0,0,0,0,43,16,194,0,
- 4,0,64,20,255,255,2,36,8,0,134,172,
- 12,0,133,164,33,16,0,0,8,0,224,3,
- 0,0,0,0,216,255,189,39,32,0,191,175,
- 28,0,179,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,128,128,0,33,152,160,0,
- 8,0,3,142,4,0,2,142,0,0,0,0,
- 35,144,98,0,255,255,66,50,12,0,3,150,
- 0,0,0,0,33,16,67,0,255,255,99,50,
- 42,16,67,0,35,0,64,16,1,0,2,36,
- 0,0,3,150,0,0,0,0,32,0,98,20,
- 255,255,2,36,9,50,192,12,255,255,100,50,
- 33,136,64,0,3,0,32,22,255,255,70,50,
- 189,92,192,8,255,255,2,36,5,0,192,16,
- 0,0,0,0,4,0,5,142,0,0,0,0,
- 80,68,192,12,33,32,32,2,0,0,2,150,
- 0,0,0,0,1,0,66,48,7,0,64,16,
- 0,0,0,0,4,0,4,142,0,0,0,0,
- 3,0,128,16,0,0,0,0,61,50,192,12,
- 0,0,0,0,4,0,17,174,255,255,66,50,
- 33,16,34,2,8,0,2,174,35,16,114,2,
- 12,0,2,166,33,16,0,0,32,0,191,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 216,255,189,39,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,128,128,0,33,136,192,0,255,255,36,50,
- 35,0,128,16,33,152,160,0,8,0,2,142,
- 4,0,3,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,12,0,3,150,0,0,0,0,
- 33,16,67,0,42,16,68,0,20,0,64,16,
- 0,0,0,0,9,50,192,12,0,0,0,0,
- 33,144,64,0,24,0,64,18,255,255,2,36,
- 0,0,2,150,0,0,0,0,1,0,66,48,
- 8,0,64,16,1,0,2,36,4,0,4,142,
- 0,0,0,0,4,0,128,16,0,0,0,0,
- 61,50,192,12,0,0,0,0,1,0,2,36,
- 0,0,2,166,4,0,18,174,4,0,4,142,
- 33,40,96,2,80,68,192,12,255,255,38,50,
- 33,32,0,2,255,255,37,50,85,92,192,12,
- 33,48,0,0,33,16,0,0,32,0,191,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 184,255,189,39,64,0,191,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,144,128,0,112,0,84,142,
- 0,0,0,0,92,0,128,18,1,0,2,36,
- 108,0,81,142,0,0,0,0,88,0,32,18,
- 0,0,0,0,96,0,87,38,136,0,66,174,
- 140,0,64,174,96,0,64,174,100,0,64,174,
- 224,83,192,12,33,32,32,2,33,168,64,0,
- 25,0,160,18,33,128,160,2,108,0,66,142,
- 0,0,0,0,124,0,66,174,128,0,84,174,
- 108,0,81,174,112,0,85,174,29,0,32,26,
- 33,152,0,0,255,255,22,36,33,32,0,2,
- 8,0,133,38,33,48,64,2,170,72,192,12,
- 1,0,7,36,10,0,86,16,33,32,64,2,
- 14,0,64,20,0,0,0,0,64,0,66,142,
- 0,0,0,0,10,0,64,20,2,0,5,36,
- 56,93,192,8,1,0,102,38,33,32,64,2,
- 5,0,5,36,33,48,0,0,140,84,192,12,
- 0,0,0,0,107,93,192,8,1,0,2,36,
- 1,0,115,38,68,0,16,38,42,16,113,2,
- 230,255,64,20,68,0,148,38,40,0,32,18,
- 33,128,160,2,17,0,2,146,0,0,0,0,
- 34,0,66,48,32,0,64,20,0,0,0,0,
- 36,0,2,142,16,0,176,175,16,0,66,140,
- 24,0,4,142,28,0,5,142,32,0,6,142,
- 0,0,0,0,9,248,64,0,33,56,64,2,
- 17,0,2,146,0,0,0,0,32,0,66,52,
- 17,0,2,162,0,0,226,142,0,0,0,0,
- 15,0,64,16,0,0,0,0,255,255,49,38,
- 15,0,32,18,68,0,16,38,17,0,3,146,
- 0,0,0,0,32,0,98,48,2,0,64,20,
- 34,0,98,52,17,0,2,162,255,255,49,38,
- 248,255,32,22,68,0,16,38,107,93,192,8,
- 33,16,0,0,255,255,49,38,218,255,32,22,
- 68,0,16,38,33,16,0,0,64,0,191,143,
- 60,0,183,143,56,0,182,143,52,0,181,143,
- 48,0,180,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 72,0,189,39,168,255,189,39,80,0,191,175,
- 76,0,183,175,72,0,182,175,68,0,181,175,
- 64,0,180,175,60,0,179,175,56,0,178,175,
- 52,0,177,175,48,0,176,175,33,144,128,0,
- 96,0,66,142,0,0,0,0,3,0,64,16,
- 33,32,0,0,240,93,192,8,255,255,2,36,
- 116,0,66,142,0,0,0,0,7,0,64,16,
- 104,0,67,38,12,0,99,140,0,0,0,0,
- 12,0,98,140,0,0,0,0,251,255,64,20,
- 0,0,0,0,8,0,116,140,0,0,0,0,
- 92,0,128,18,33,16,0,0,4,0,115,140,
- 0,0,0,0,88,0,96,18,0,0,0,0,
- 64,0,66,142,0,0,0,0,55,0,64,20,
- 0,0,0,0,33,128,128,2,52,0,96,26,
- 33,136,0,0,255,255,23,36,2,0,22,36,
- 5,0,21,36,17,0,2,146,0,0,0,0,
- 16,0,66,48,40,0,64,16,24,0,165,39,
- 8,0,3,142,28,0,2,142,0,0,0,0,
- 35,24,98,0,24,0,163,175,12,0,2,142,
- 0,0,0,0,28,0,162,175,128,24,3,0,
- 33,24,98,0,252,255,98,140,0,0,0,0,
- 1,0,66,36,252,255,98,172,12,0,0,174,
- 8,0,0,174,33,32,0,2,33,48,64,2,
- 170,72,192,12,1,0,7,36,6,0,87,16,
- 0,0,0,0,9,0,64,20,1,0,34,38,
- 96,0,86,174,196,93,192,8,100,0,66,174,
- 96,0,85,174,110,86,192,12,24,0,164,39,
- 240,93,192,8,255,255,2,36,110,86,192,12,
- 24,0,164,39,17,0,2,146,0,0,0,0,
- 12,0,66,48,17,0,2,162,1,0,4,36,
- 1,0,49,38,42,16,51,2,209,255,64,20,
- 68,0,16,38,27,0,128,16,33,128,128,2,
- 23,0,96,26,33,136,0,0,17,0,2,146,
- 0,0,0,0,34,0,66,48,14,0,64,20,
- 0,0,0,0,36,0,2,142,16,0,176,175,
- 16,0,66,140,24,0,4,142,28,0,5,142,
- 32,0,6,142,0,0,0,0,9,248,64,0,
- 33,56,64,2,17,0,2,146,0,0,0,0,
- 32,0,66,52,17,0,2,162,1,0,49,38,
- 42,16,51,2,235,255,64,20,68,0,16,38,
- 240,93,192,8,1,0,2,36,33,16,0,0,
- 80,0,191,143,76,0,183,143,72,0,182,143,
- 68,0,181,143,64,0,180,143,60,0,179,143,
- 56,0,178,143,52,0,177,143,48,0,176,143,
- 8,0,224,3,88,0,189,39,0,0,0,0,
- 200,255,189,39,48,0,191,175,44,0,179,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,144,128,0,96,0,64,174,100,0,64,174,
- 112,0,80,142,0,0,0,0,105,0,0,18,
- 33,16,0,0,108,0,81,142,0,0,0,0,
- 101,0,32,18,0,0,0,0,64,0,66,142,
- 0,0,0,0,43,0,64,20,33,32,64,2,
- 50,0,32,26,33,152,0,0,33,32,0,2,
- 33,40,64,2,96,72,192,12,1,0,6,36,
- 13,0,64,20,33,32,64,2,20,0,2,150,
- 0,0,0,0,1,0,66,48,34,0,64,16,
- 2,0,5,36,36,0,2,142,0,0,0,0,
- 3,0,66,144,0,0,0,0,2,0,66,48,
- 3,0,64,20,0,0,0,0,63,94,192,8,
- 2,0,5,36,36,0,2,142,0,0,0,0,
- 32,0,66,140,4,0,67,142,0,0,0,0,
- 36,16,67,0,16,0,64,16,33,32,64,2,
- 36,0,2,142,16,0,3,146,2,0,66,144,
- 0,0,0,0,11,0,98,20,3,0,5,36,
- 1,0,115,38,42,16,113,2,219,255,64,20,
- 68,0,16,38,69,94,192,8,96,0,83,38,
- 5,0,5,36,64,94,192,8,33,48,0,0,
- 2,0,5,36,1,0,102,38,140,84,192,12,
- 0,0,0,0,113,94,192,8,1,0,2,36,
- 96,0,83,38,112,0,80,142,0,0,0,0,
- 41,0,32,18,33,16,0,0,17,0,2,146,
- 0,0,0,0,17,0,66,48,32,0,64,20,
- 0,0,0,0,36,0,2,142,16,0,176,175,
- 4,0,66,140,24,0,4,142,28,0,5,142,
- 32,0,6,142,0,0,0,0,9,248,64,0,
- 33,56,64,2,17,0,2,146,0,0,0,0,
- 16,0,66,52,17,0,2,162,0,0,98,142,
- 0,0,0,0,15,0,64,16,0,0,0,0,
- 255,255,49,38,15,0,32,18,68,0,16,38,
- 17,0,3,146,0,0,0,0,16,0,98,48,
- 2,0,64,20,17,0,98,52,17,0,2,162,
- 255,255,49,38,248,255,32,22,68,0,16,38,
- 113,94,192,8,33,16,0,0,255,255,49,38,
- 218,255,32,22,68,0,16,38,33,16,0,0,
- 48,0,191,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 56,0,189,39,192,255,189,39,56,0,191,175,
- 52,0,183,175,48,0,182,175,44,0,181,175,
- 40,0,180,175,36,0,179,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,144,128,0,
- 112,0,84,142,0,0,0,0,171,0,128,18,
- 33,16,0,0,108,0,85,142,0,0,0,0,
- 166,0,160,18,32,0,2,36,56,0,67,146,
- 0,0,0,0,75,0,98,16,96,0,83,38,
- 33,0,98,40,5,0,64,16,64,0,2,36,
- 9,0,96,16,33,16,0,0,49,95,192,8,
- 0,0,0,0,85,0,98,16,128,0,2,36,
- 137,0,98,16,33,16,0,0,49,95,192,8,
- 0,0,0,0,33,136,160,2,8,0,32,18,
- 33,128,128,2,17,0,2,146,0,0,0,0,
- 1,0,66,48,139,0,64,16,255,255,49,38,
- 250,255,32,22,68,0,16,38,0,0,98,142,
- 0,0,0,0,136,0,64,20,33,16,0,0,
- 33,136,160,2,43,0,32,18,33,128,128,2,
- 14,0,22,36,64,0,23,36,17,0,2,146,
- 0,0,0,0,34,0,66,48,33,0,64,20,
- 0,0,0,0,36,0,2,142,16,0,176,175,
- 12,0,66,140,24,0,4,142,28,0,5,142,
- 32,0,6,142,0,0,0,0,9,248,64,0,
- 33,56,64,2,17,0,2,146,0,0,0,0,
- 32,0,66,52,17,0,2,162,0,0,98,142,
- 0,0,0,0,16,0,64,16,0,0,0,0,
- 255,255,49,38,10,0,32,18,68,0,16,38,
- 17,0,3,146,0,0,0,0,32,0,98,48,
- 2,0,64,20,192,0,98,52,17,0,2,162,
- 255,255,49,38,248,255,32,22,68,0,16,38,
- 0,0,118,174,236,94,192,8,56,0,87,162,
- 255,255,49,38,217,255,32,22,68,0,16,38,
- 32,0,2,36,56,0,66,162,0,0,98,142,
- 0,0,0,0,13,0,64,20,64,0,2,36,
- 33,136,160,2,81,0,32,18,33,128,128,2,
- 17,0,2,146,0,0,0,0,2,0,66,48,
- 74,0,64,16,255,255,49,38,250,255,32,22,
- 68,0,16,38,49,95,192,8,33,16,0,0,
- 56,0,66,162,14,0,2,36,0,0,98,174,
- 33,136,160,2,53,0,32,18,33,128,128,2,
- 2,0,23,36,15,0,22,36,17,0,2,146,
- 0,0,0,0,194,0,66,48,5,0,64,16,
- 0,0,0,0,19,0,87,16,0,0,0,0,
- 32,95,192,8,255,255,49,38,64,0,2,142,
- 0,0,0,0,34,0,64,16,0,0,0,0,
- 16,0,176,175,64,0,2,142,24,0,4,142,
- 28,0,5,142,32,0,6,142,0,0,0,0,
- 9,248,64,0,33,56,64,2,17,0,2,146,
- 0,0,0,0,30,95,192,8,64,0,66,52,
- 64,0,2,142,0,0,0,0,13,0,64,16,
- 0,0,0,0,16,0,176,175,64,0,2,142,
- 24,0,4,142,28,0,5,142,32,0,6,142,
- 0,0,0,0,9,248,64,0,33,56,64,2,
- 17,0,2,146,0,0,0,0,30,95,192,8,
- 64,0,66,52,0,0,118,174,17,0,2,146,
- 0,0,0,0,128,0,66,52,17,0,2,162,
- 255,255,49,38,208,255,32,22,68,0,16,38,
- 33,136,160,2,12,0,32,18,33,128,128,2,
- 17,0,2,146,0,0,0,0,128,0,66,48,
- 5,0,64,16,255,255,49,38,250,255,32,22,
- 68,0,16,38,49,95,192,8,33,16,0,0,
- 49,95,192,8,1,0,2,36,33,16,0,0,
- 56,0,191,143,52,0,183,143,48,0,182,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,64,0,189,39,184,255,189,39,
- 64,0,191,175,60,0,183,175,56,0,182,175,
- 52,0,181,175,48,0,180,175,44,0,179,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,160,128,0,112,0,147,142,0,0,0,0,
- 129,0,96,18,33,16,0,0,108,0,146,142,
- 0,0,0,0,125,0,64,18,96,0,151,38,
- 96,0,128,174,100,0,128,174,224,83,192,12,
- 33,32,64,2,33,168,64,0,5,0,160,22,
- 33,136,64,2,33,32,128,2,5,0,5,36,
- 123,95,192,8,33,48,0,0,36,0,64,18,
- 33,128,160,2,5,0,22,36,16,0,22,162,
- 8,0,100,142,12,0,101,142,0,0,0,0,
- 80,86,192,12,8,0,6,38,5,0,64,20,
- 0,0,0,0,255,255,49,38,68,0,115,38,
- 245,255,32,22,68,0,16,38,21,0,32,18,
- 42,16,50,2,7,0,64,16,33,128,160,2,
- 59,84,192,12,33,32,0,2,1,0,49,38,
- 42,16,50,2,251,255,64,20,68,0,16,38,
- 61,50,192,12,33,32,160,2,33,32,128,2,
- 5,0,5,36,123,95,192,8,33,48,0,0,
- 2,0,5,36,1,0,38,38,140,84,192,12,
- 0,0,0,0,203,95,192,8,1,0,2,36,
- 124,0,146,174,112,0,130,142,0,0,0,0,
- 128,0,130,174,112,0,149,174,33,128,160,2,
- 27,0,64,26,33,136,0,0,33,32,0,2,
- 33,40,128,2,96,72,192,12,1,0,6,36,
- 13,0,64,20,0,0,0,0,20,0,2,150,
- 0,0,0,0,1,0,66,48,8,0,64,16,
- 0,0,0,0,36,0,2,142,0,0,0,0,
- 3,0,66,144,0,0,0,0,1,0,66,48,
- 5,0,64,20,0,0,0,0,64,0,130,142,
- 0,0,0,0,221,255,64,16,33,32,128,2,
- 1,0,49,38,42,16,50,2,231,255,64,20,
- 68,0,16,38,40,0,64,18,33,128,160,2,
- 17,0,2,146,0,0,0,0,34,0,66,48,
- 32,0,64,20,0,0,0,0,36,0,2,142,
- 16,0,176,175,8,0,66,140,24,0,4,142,
- 28,0,5,142,32,0,6,142,0,0,0,0,
- 9,248,64,0,33,56,128,2,17,0,2,146,
- 0,0,0,0,32,0,66,52,17,0,2,162,
- 0,0,226,142,0,0,0,0,15,0,64,16,
- 0,0,0,0,255,255,82,38,15,0,64,18,
- 68,0,16,38,17,0,3,146,0,0,0,0,
- 32,0,98,48,2,0,64,20,34,0,98,52,
- 17,0,2,162,255,255,82,38,248,255,64,22,
- 68,0,16,38,203,95,192,8,33,16,0,0,
- 255,255,82,38,218,255,64,22,68,0,16,38,
- 33,16,0,0,64,0,191,143,60,0,183,143,
- 56,0,182,143,52,0,181,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,72,0,189,39,
- 0,0,0,0,0,0,0,0,37,115,58,37,
- 100,58,32,102,97,105,108,101,100,32,97,115,
- 115,101,114,116,105,111,110,32,96,37,115,39,
- 10,0,0,0,114,97,109,116,101,115,116,100,
- 119,40,98,99,46,98,99,95,104,101,97,112,
- 115,116,97,114,116,44,32,108,101,110,44,32,
- 49,44,32,48,44,32,48,41,32,61,61,32,
- 48,0,0,0,98,99,46,98,99,95,104,101,
- 97,112,101,110,100,32,60,61,32,98,99,46,
- 98,99,95,114,97,109,101,110,100,0,0,0,
- 35,32,112,111,114,116,115,58,32,37,100,10,
- 0,0,0,0,42,42,42,80,114,111,102,105,
- 108,105,110,103,32,64,32,37,120,44,32,37,
- 120,10,0,0,103,111,116,32,104,101,114,101,
- 32,99,97,117,115,101,61,37,120,32,115,116,
- 97,116,117,115,61,37,120,32,118,101,99,61,
- 37,120,10,0,37,115,58,37,100,58,32,102,
- 97,105,108,101,100,32,97,115,115,101,114,116,
- 105,111,110,32,96,37,115,39,10,0,0,0,
- 83,101,99,111,110,100,115,32,60,32,48,120,
- 55,70,70,70,102,102,102,102,0,0,0,0,
- 84,105,109,101,114,115,85,115,101,100,32,60,
- 32,78,84,73,77,69,82,83,0,0,0,0,
- 0,0,0,0,69,69,80,82,79,77,32,105,
- 115,32,98,97,100,10,0,0,80,111,114,116,
- 32,37,100,32,101,116,104,101,114,32,97,100,
- 100,114,101,115,115,58,32,37,48,50,88,58,
- 37,48,50,88,58,37,48,50,88,58,37,48,
- 50,88,58,37,48,50,88,58,37,48,50,88,
- 10,0,0,0,35,35,35,32,56,50,53,57,
- 54,32,67,104,97,110,32,37,100,58,32,115,
- 101,108,102,116,101,115,116,32,102,97,105,108,
- 101,100,32,40,37,120,41,10,0,0,0,0,
- 42,42,42,32,56,50,53,57,54,32,80,111,
- 114,116,32,37,100,58,32,115,101,108,102,116,
- 101,115,116,32,112,97,115,115,101,100,10,0,
- 56,50,53,57,54,32,80,111,114,116,32,37,
- 100,58,32,100,117,109,112,32,102,97,105,108,
- 101,100,32,40,37,120,41,10,0,0,0,0,
- 42,42,42,32,56,50,53,57,54,32,80,111,
- 114,116,32,37,100,58,32,100,117,109,112,32,
- 112,97,115,115,101,100,10,0,35,35,35,32,
- 56,50,53,57,54,32,80,111,114,116,32,37,
- 100,58,32,83,67,80,32,102,101,116,99,104,
- 32,102,97,105,108,101,100,10,0,0,0,0,
- 42,42,42,32,56,50,53,57,54,32,80,111,
- 114,116,32,37,100,58,32,83,67,80,32,102,
- 101,116,99,104,32,112,97,115,115,101,100,32,
- 37,120,32,10,0,0,0,0,35,35,35,32,
- 56,50,53,57,54,32,80,111,114,116,32,37,
- 100,58,32,66,85,83,84,73,77,69,82,83,
- 32,108,111,97,100,32,102,97,105,108,101,100,
- 10,0,0,0,42,42,42,32,56,50,53,57,
- 54,32,80,111,114,116,32,37,100,58,32,66,
- 85,83,84,73,77,69,82,83,32,108,111,97,
- 100,32,112,97,115,115,101,100,10,0,0,0,
- 35,35,35,32,65,67,75,32,100,105,100,32,
- 110,111,116,32,111,99,99,117,114,10,0,0,
- 35,35,35,32,115,116,97,116,117,115,32,115,
- 116,105,108,108,32,98,117,115,121,58,32,37,
- 120,10,0,0,101,116,104,95,105,110,105,116,
- 46,99,0,0,42,42,42,76,49,87,65,10,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,35,35,35,32,84,66,68,32,
- 98,108,111,99,107,115,32,97,114,101,110,39,
- 116,32,98,101,105,110,103,32,102,114,101,101,
- 100,10,0,0,65,116,116,101,109,112,116,32,
- 116,111,32,102,114,101,101,32,98,111,103,117,
- 115,32,84,66,68,32,37,120,10,0,0,0,
- 35,35,35,32,66,85,70,32,98,108,111,99,
- 107,115,32,97,114,101,110,39,116,32,98,101,
- 105,110,103,32,102,114,101,101,100,10,0,0,
- 65,116,116,101,109,112,116,32,116,111,32,102,
- 114,101,101,32,98,111,103,117,115,32,66,85,
- 70,32,37,120,10,0,0,0,0,0,0,0,
- 0,0,0,0,82,70,68,115,32,37,100,32,
- 10,0,0,0,82,66,68,115,32,37,100,32,
- 10,0,0,0,37,115,58,37,100,58,32,102,
- 97,105,108,101,100,32,97,115,115,101,114,116,
- 105,111,110,32,96,37,115,39,10,0,0,0,
- 101,116,104,95,114,99,118,46,99,0,0,0,
- 100,115,116,99,104,97,110,32,62,61,32,49,
- 32,38,38,32,100,115,116,99,104,97,110,32,
- 60,32,78,99,104,97,110,0,37,115,37,48,
- 50,88,58,37,48,50,88,58,37,48,50,88,
- 58,37,48,50,88,58,37,48,50,88,58,37,
- 48,50,88,37,115,0,0,0,176,72,0,131,
- 80,67,0,131,164,67,0,131,24,68,0,131,
- 80,67,0,131,0,0,0,0,4,82,0,131,
- 184,76,0,131,12,77,0,131,128,77,0,131,
- 184,76,0,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,37,115,58,37,100,58,32,102,
- 97,105,108,101,100,32,97,115,115,101,114,116,
- 105,111,110,32,96,37,115,39,10,0,0,0,
- 101,116,104,95,120,109,105,116,46,99,0,0,
- 99,98,112,45,62,110,111,112,46,99,109,100,
- 32,61,61,32,73,53,57,54,95,67,66,95,
- 67,77,68,95,78,79,80,124,73,53,57,54,
- 95,67,66,95,67,77,68,95,69,76,0,0,
- 99,98,112,45,62,110,111,112,46,99,109,100,
- 32,38,32,73,53,57,54,95,67,66,95,67,
- 77,68,0,0,112,45,62,115,99,98,112,45,
- 62,115,116,97,116,117,115,32,38,32,73,53,
- 57,54,95,83,67,66,95,67,78,65,0,0,
- 35,35,35,32,99,109,100,32,115,116,105,108,
- 108,32,98,117,115,121,58,32,37,120,10,0,
- 37,100,61,37,100,44,37,120,44,37,100,10,
- 0,0,0,0,39,37,115,39,32,37,120,32,
- 37,120,10,0,37,48,56,120,58,32,37,48,
- 50,120,10,0,37,48,56,120,58,32,37,48,
- 52,120,10,0,37,48,56,120,58,32,37,48,
- 56,120,10,0,108,105,110,107,32,115,116,97,
- 116,101,32,37,48,50,120,10,0,0,0,0,
- 42,42,42,32,103,111,116,32,37,100,32,105,
- 110,116,101,114,114,117,112,116,115,10,0,0,
- 35,35,35,32,69,120,112,101,99,116,101,100,
- 32,37,100,32,98,117,116,32,103,111,116,32,
- 37,100,32,105,110,116,101,114,114,117,112,116,
- 115,10,0,0,80,76,88,57,48,54,48,32,
- 65,100,100,114,101,115,115,32,61,32,37,88,
- 32,68,65,84,65,32,61,32,37,88,32,10,
- 0,0,0,0,42,42,42,32,87,114,105,116,
- 101,32,111,102,32,37,120,32,116,111,32,37,
- 100,32,102,97,105,108,101,100,10,0,0,0,
- 42,42,42,32,87,114,105,116,101,32,111,102,
- 32,37,120,32,116,111,32,37,120,32,102,97,
- 105,108,101,100,10,0,0,0,42,42,42,42,
- 42,42,42,42,42,42,42,42,42,42,42,42,
- 0,0,0,0,42,42,42,32,73,108,108,101,
- 103,97,108,32,99,111,109,109,97,110,100,32,
- 39,37,115,39,10,0,0,0,45,45,45,32,
- 99,111,109,109,97,110,100,115,32,109,44,116,
- 44,101,44,69,44,97,44,120,44,108,44,115,
- 44,112,32,99,97,110,32,98,101,32,112,114,
- 101,102,105,120,101,100,32,119,105,116,104,32,
- 97,32,114,101,112,101,97,116,32,99,111,117,
- 110,116,0,0,108,32,120,112,111,114,116,32,
- 114,112,111,114,116,32,91,108,101,110,93,32,
- 32,32,32,32,32,32,32,32,32,76,111,111,
- 112,98,97,99,107,32,116,101,115,116,32,102,
- 114,111,109,32,120,112,111,114,116,32,40,49,
- 45,54,41,32,116,111,32,114,112,111,114,116,
- 32,40,49,45,54,41,0,0,105,32,32,32,
- 32,32,32,32,32,32,73,110,116,101,114,114,
- 117,112,116,32,72,111,115,116,32,32,124,32,
- 32,115,32,91,112,111,114,116,93,32,91,108,
- 101,110,93,32,66,97,99,107,50,98,97,99,
- 107,32,120,109,105,116,32,99,110,116,32,112,
- 97,99,107,101,116,115,0,0,80,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,80,
- 76,88,32,57,48,54,48,32,32,32,124,32,
- 32,100,32,91,114,124,119,124,108,124,116,93,
- 32,91,118,97,108,124,39,99,39,93,32,32,
- 82,101,97,100,47,87,114,105,116,101,47,76,
- 111,111,112,47,84,105,109,101,32,68,77,65,
- 0,0,0,0,76,32,32,32,32,32,32,32,
- 32,32,82,101,97,100,32,76,105,110,107,32,
- 76,69,68,115,32,32,124,32,32,112,32,114,
- 101,103,110,111,32,91,118,97,108,93,32,32,
- 82,101,97,100,47,91,119,114,105,116,101,93,
- 32,80,76,88,32,114,101,103,105,115,116,101,
- 114,0,0,0,65,32,97,100,100,114,32,32,
- 32,32,83,101,116,32,101,116,104,101,114,32,
- 97,100,100,114,32,32,124,32,32,36,32,115,
- 99,114,105,112,116,32,32,32,32,32,32,32,
- 82,101,97,100,32,99,109,100,115,32,102,114,
- 111,109,32,102,105,108,101,32,39,115,99,114,
- 105,112,116,39,0,0,0,0,120,32,91,112,
- 111,114,116,93,32,32,84,120,32,101,116,104,
- 101,114,32,32,32,32,32,32,32,32,124,32,
- 32,82,32,91,112,111,114,116,93,32,32,32,
- 32,32,32,32,82,120,32,101,116,104,101,114,
- 32,91,111,110,32,112,111,114,116,32,49,45,
- 54,93,0,0,72,32,32,32,32,32,32,32,
- 32,32,84,111,103,103,108,101,32,70,67,67,
- 32,116,101,115,116,32,124,32,32,113,44,94,
- 68,44,94,90,32,32,32,32,32,32,32,32,
- 81,117,105,116,0,0,0,0,97,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,97,
- 108,108,32,32,32,32,32,32,32,32,124,32,
- 32,90,32,109,115,101,99,115,32,32,32,32,
- 32,32,32,32,80,97,117,115,101,32,102,111,
- 114,32,97,32,119,104,105,108,101,0,0,0,
- 69,32,32,32,32,32,32,32,32,32,84,101,
- 115,116,32,69,69,80,82,79,77,32,32,32,
- 32,32,124,32,32,83,114,32,97,100,100,114,
- 59,32,83,119,32,97,100,100,114,32,118,97,
- 108,59,32,32,82,101,97,100,47,87,114,105,
- 116,101,32,80,76,88,32,69,50,32,114,101,
- 103,0,0,0,101,32,91,112,111,114,116,93,
- 32,32,84,101,115,116,32,101,116,104,101,114,
- 110,101,116,32,32,32,124,32,32,69,114,32,
- 97,100,100,114,59,32,69,119,32,97,100,100,
- 114,32,118,97,108,59,32,32,82,101,97,100,
- 47,87,114,105,116,101,32,69,69,80,82,79,
- 77,32,114,101,103,0,0,0,116,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,116,
- 105,109,101,114,115,32,32,32,32,32,124,32,
- 32,119,91,42,93,32,97,100,100,114,32,118,
- 97,108,32,32,87,114,105,116,101,32,109,101,
- 109,111,114,121,58,32,119,98,32,119,104,44,
- 32,119,119,44,32,119,116,0,109,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,109,
- 101,109,111,114,121,32,32,32,32,32,124,32,
- 32,114,91,42,93,32,97,100,100,114,32,32,
- 32,32,32,32,82,101,97,100,32,109,101,109,
- 111,114,121,58,32,114,98,32,114,104,44,32,
- 114,119,44,32,114,116,0,0,42,42,42,32,
- 82,105,103,104,116,83,119,105,116,99,104,32,
- 68,105,97,103,110,111,115,116,105,99,115,32,
- 109,101,110,117,32,42,42,42,0,0,0,0,
- 45,45,45,32,84,104,114,101,101,32,99,111,
- 112,105,101,115,32,111,102,32,97,100,100,114,
- 101,115,115,32,100,111,32,110,111,116,32,97,
- 103,114,101,101,33,10,0,0,45,45,45,32,
- 69,116,104,101,114,32,65,100,100,114,101,115,
- 115,32,78,111,116,32,83,101,116,33,10,0,
- 45,45,45,32,69,116,104,101,114,32,65,100,
- 100,114,101,115,115,32,105,115,32,97,32,109,
- 117,108,116,105,99,97,115,116,32,97,100,100,
- 114,101,115,115,33,10,0,0,42,42,42,32,
- 37,48,50,88,37,48,50,88,37,48,50,88,
- 58,37,48,50,88,58,37,48,50,88,37,48,
- 50,88,10,0,45,45,45,32,70,105,114,115,
- 116,32,98,121,116,101,32,40,37,48,50,88,
- 41,32,105,115,32,97,32,98,114,111,97,100,
- 99,97,115,116,32,97,100,100,114,101,115,115,
- 10,0,0,0,45,45,45,32,76,97,115,116,
- 32,100,105,103,105,116,32,109,117,115,116,32,
- 98,101,32,48,32,111,114,32,56,10,0,0,
- 42,42,42,32,69,105,103,104,116,32,101,116,
- 104,101,114,110,101,116,32,97,100,100,114,101,
- 115,115,101,115,32,104,97,118,101,32,98,101,
- 101,110,32,117,115,101,100,58,10,0,0,0,
- 42,42,42,32,80,111,114,116,32,37,100,32,
- 101,116,104,101,114,110,101,116,32,97,100,100,
- 114,101,115,115,32,105,115,32,0,0,0,0,
- 45,45,45,32,66,97,100,32,101,116,104,101,
- 114,32,97,100,100,114,101,115,115,32,39,37,
- 115,39,32,115,112,101,99,105,102,105,101,100,
- 10,0,0,0,0,0,0,0,244,101,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,244,101,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,64,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,28,111,0,131,104,112,0,131,
- 104,112,0,131,132,111,0,131,152,109,0,131,
- 104,112,0,131,104,112,0,131,244,101,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 24,107,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,76,108,0,131,104,112,0,131,
- 228,108,0,131,112,110,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 28,109,0,131,104,112,0,131,48,111,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 84,109,0,131,104,112,0,131,104,112,0,131,
- 32,112,0,131,136,106,0,131,28,106,0,131,
- 104,112,0,131,104,112,0,131,52,107,0,131,
- 104,112,0,131,104,112,0,131,252,106,0,131,
- 88,111,0,131,104,112,0,131,104,112,0,131,
- 196,107,0,131,104,112,0,131,180,104,0,131,
- 168,106,0,131,92,106,0,131,104,112,0,131,
- 104,112,0,131,148,105,0,131,192,106,0,131,
- 0,0,0,0,188,111,0,131,204,111,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,252,111,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 236,111,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,220,111,0,131,
- 252,111,0,131,0,0,0,0,0,0,0,0,
- 42,42,42,32,69,69,80,82,79,77,32,80,
- 97,115,115,101,100,10,0,0,33,33,33,32,
- 69,69,80,82,79,77,32,70,97,105,108,117,
- 114,101,58,32,87,114,111,116,101,32,37,48,
- 52,120,32,97,116,32,37,100,44,32,103,111,
- 116,32,37,48,52,120,10,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,35,35,35,70,
- 114,97,109,101,32,37,100,32,100,105,100,32,
- 110,111,116,32,97,114,114,105,118,101,10,0,
- 35,35,35,32,70,114,97,109,101,32,37,100,
- 44,32,108,101,110,32,37,100,44,32,98,121,
- 116,101,32,37,100,44,32,119,97,110,116,32,
- 37,120,32,103,111,116,32,37,120,10,0,0,
- 35,35,35,70,114,97,109,101,32,37,100,32,
- 119,114,111,110,103,32,108,101,110,103,116,104,
- 32,40,119,97,110,116,32,37,100,32,103,111,
- 116,32,37,100,41,10,0,0,35,35,35,70,
- 114,97,109,101,32,37,100,58,32,103,111,116,
- 32,115,101,113,32,37,100,10,0,0,0,0,
- 35,35,35,32,37,100,32,67,82,67,32,101,
- 114,114,111,114,115,32,111,99,99,117,114,101,
- 100,10,0,0,35,35,35,32,37,100,32,65,
- 108,105,103,110,32,101,114,114,111,114,115,32,
- 111,99,99,117,114,101,100,10,0,0,0,0,
- 35,35,35,32,37,100,32,83,104,111,114,116,
- 32,101,114,114,111,114,115,32,111,99,99,117,
- 114,101,100,10,0,0,0,0,35,35,35,32,
- 37,100,32,79,118,101,114,114,117,110,32,101,
- 114,114,111,114,115,32,111,99,99,117,114,101,
- 100,10,0,0,35,35,35,32,67,85,32,115,
- 116,105,108,108,32,114,117,110,110,105,110,103,
- 58,32,37,120,10,0,0,0,35,35,35,32,
- 99,109,100,32,115,116,105,108,108,32,98,117,
- 115,121,58,32,37,120,10,0,35,35,35,32,
- 115,116,97,116,117,115,32,115,116,105,108,108,
- 32,98,117,115,121,58,32,37,120,10,0,0,
- 67,66,61,37,120,44,32,84,66,68,61,37,
- 120,44,32,66,85,70,61,37,120,10,0,0,
- 116,101,115,116,95,101,116,104,101,114,46,99,
- 0,0,0,0,37,100,32,102,114,97,109,101,
- 115,32,111,102,32,108,101,110,103,116,104,32,
- 37,100,32,115,101,110,116,32,105,110,32,37,
- 100,32,109,115,101,99,115,10,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 42,42,42,32,56,50,53,52,32,84,105,109,
- 101,114,32,48,32,79,75,44,32,99,111,117,
- 110,116,32,119,97,115,32,37,100,10,0,0,
- 42,42,42,32,56,50,53,52,32,84,105,109,
- 101,114,32,48,32,110,111,116,32,105,110,116,
- 101,114,114,117,112,116,105,110,103,32,37,100,
- 10,0,0,0,42,42,42,32,56,50,53,52,
- 32,84,105,109,101,114,32,48,32,115,112,101,
- 101,100,32,119,114,111,110,103,44,32,103,111,
- 116,32,37,100,32,115,104,111,117,108,100,32,
- 98,101,32,49,48,48,48,10,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 9,37,120,58,32,119,97,110,116,32,37,120,
- 32,103,111,116,32,37,120,10,0,0,0,0,
- 45,45,45,32,82,65,77,32,84,101,115,116,
- 32,111,102,32,37,120,32,116,111,32,37,120,
- 32,102,97,105,108,101,100,10,0,0,0,0,
- 42,42,42,32,82,65,77,32,84,101,115,116,
- 32,111,102,32,37,120,32,116,111,32,37,120,
- 32,112,97,115,115,101,100,10,0,0,0,0,
- 35,35,35,32,68,77,65,32,68,79,78,69,
- 32,110,101,118,101,114,32,111,99,99,117,114,
- 114,101,100,46,32,32,99,115,114,32,61,32,
- 37,120,10,0,35,35,35,32,72,111,115,116,
- 32,110,101,118,101,114,32,103,111,116,32,68,
- 77,65,32,105,110,116,101,114,114,117,112,116,
- 46,32,98,99,95,99,110,116,32,61,32,37,
- 100,10,0,0,35,35,35,32,68,77,65,32,
- 101,114,114,111,114,32,97,116,32,105,110,100,
- 101,120,32,37,100,58,32,119,97,110,116,101,
- 100,32,37,48,50,120,32,103,111,116,32,37,
- 48,50,120,10,0,0,0,0,35,35,35,32,
- 73,108,108,101,103,97,108,32,72,111,115,116,
- 32,97,100,100,114,32,40,61,37,120,41,32,
- 111,114,32,108,101,110,103,116,104,32,40,61,
- 37,100,41,10,0,0,0,0,35,35,35,32,
- 67,111,117,110,116,32,99,97,110,110,111,116,
- 32,98,101,32,62,32,49,48,50,52,42,49,
- 48,50,52,10,0,0,0,0,42,42,42,32,
- 108,99,108,46,66,117,102,49,32,61,32,37,
- 120,32,45,45,62,32,104,111,115,116,46,66,
- 117,102,32,61,32,37,120,32,45,45,62,32,
- 108,99,108,46,66,117,102,50,32,61,32,37,
- 120,10,0,0,42,42,42,32,62,32,68,98,
- 32,37,100,32,40,98,117,114,115,116,41,59,
- 32,62,32,68,119,32,37,100,32,40,119,97,
- 105,116,115,116,97,116,101,115,41,10,0,0,
- 35,35,35,32,83,101,99,111,110,100,32,97,
- 114,103,32,109,117,115,116,32,98,101,32,39,
- 114,39,32,111,114,32,39,119,39,32,111,114,
- 32,39,108,39,10,0,0,0,42,42,42,32,
- 68,77,65,32,37,115,32,105,110,32,37,52,
- 100,32,98,121,116,101,32,99,104,117,110,107,
- 115,58,32,0,32,32,116,111,32,104,111,115,
- 116,0,0,0,102,114,111,109,32,104,111,115,
- 116,0,0,0,37,56,100,32,98,121,116,101,
- 115,47,115,101,99,46,10,0,116,105,109,101,
- 32,116,111,111,32,115,104,111,114,116,32,116,
- 111,32,109,101,97,115,117,114,101,10,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 80,37,100,45,62,37,115,32,10,0,0,0,
- 116,114,97,110,115,109,105,116,32,112,101,110,
- 100,105,110,103,32,111,110,32,37,100,10,0,
- 116,114,97,110,115,109,105,116,32,99,111,110,
- 102,105,103,32,111,110,32,37,100,10,0,0,
- 116,114,97,110,115,109,105,116,32,116,99,110,
- 10,0,0,0,116,99,110,32,101,120,112,10,
- 0,0,0,0,102,111,114,119,97,114,100,95,
- 100,101,108,97,121,32,101,120,112,32,37,100,
- 10,0,0,0,109,101,115,115,97,103,101,95,
- 97,103,101,32,101,120,112,32,37,100,10,0,
- 104,111,108,100,32,101,120,112,32,37,100,10,
- 0,0,0,0,84,120,67,79,78,70,73,71,
- 37,100,10,0,84,120,84,67,78,37,100,10,
- 0,0,0,0,114,99,118,32,99,111,110,102,
- 105,103,32,111,110,32,37,100,10,0,0,0,
- 90,69,82,79,32,114,111,111,116,33,32,97,
- 116,32,37,120,32,0,0,0,115,117,112,101,
- 114,99,101,100,101,115,32,37,100,10,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 65,82,80,82,69,81,32,37,120,33,10,0,
- 65,82,80,82,69,80,32,37,120,33,10,0,
- 83,101,110,100,32,85,68,80,32,37,100,10,
- 0,0,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,85,68,80,32,40,37,100,32,
- 37,100,41,10,0,0,0,0,83,101,110,116,
- 32,85,68,80,32,37,100,10,0,0,0,0,
- 83,78,77,80,32,39,37,99,39,32,108,101,
- 110,32,37,100,10,0,0,0,69,110,118,111,
- 121,32,114,99,61,37,100,10,0,0,0,0,
- 71,101,110,32,116,114,97,112,32,37,100,32,
- 114,99,61,37,100,10,0,0,66,97,100,32,
- 85,68,80,32,99,104,101,99,107,115,117,109,
- 32,37,120,32,108,101,110,32,37,100,10,0,
- 66,97,100,32,85,68,80,32,108,101,110,103,
- 116,104,32,119,97,110,116,32,37,100,32,103,
- 111,116,32,37,100,10,0,0,66,97,100,32,
- 73,67,77,80,32,99,104,101,99,107,115,117,
- 109,10,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,73,67,77,80,10,0,0,0,
- 66,97,100,32,73,80,32,99,104,101,99,107,
- 115,117,109,10,0,0,0,0,84,114,117,110,
- 99,97,116,101,100,32,73,80,10,0,0,0,
- 83,69,78,84,32,73,80,88,33,10,0,0,
- 110,111,32,115,121,115,78,97,109,101,0,0,
- 114,105,103,104,116,115,119,105,116,99,104,45,
- 0,0,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,115,101,110,100,95,115,97,112,
- 10,0,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,73,80,88,10,0,0,0,0,
- 84,114,117,110,99,97,116,101,100,32,73,80,
- 88,10,0,0,0,0,0,0,0,0,0,0,
- 77,97,108,108,111,99,32,114,101,116,117,114,
- 110,115,32,78,85,76,76,33,0,0,0,0,
- 0,0,0,0,0,0,0,0,68,105,103,105,
- 32,73,110,116,108,46,32,82,105,103,104,116,
- 83,119,105,116,99,104,32,83,69,45,88,0,
- 73,110,116,101,108,32,56,50,53,57,54,0,
- 0,0,0,0,0,0,0,0,8,206,0,131,
- 36,206,0,131,92,206,0,131,112,206,0,131,
- 132,206,0,131,220,206,0,131,4,207,0,131,
- 4,207,0,131,36,207,0,131,52,207,0,131,
- 80,207,0,131,104,207,0,131,132,207,0,131,
- 160,207,0,131,188,207,0,131,188,207,0,131,
- 216,207,0,131,240,207,0,131,12,208,0,131,
- 40,208,0,131,72,208,0,131,112,208,0,131,
- 180,210,0,131,232,210,0,131,4,211,0,131,
- 36,211,0,131,60,211,0,131,0,0,0,0,
- 64,213,0,131,92,213,0,131,124,213,0,131,
- 160,213,0,131,60,214,0,131,60,214,0,131,
- 60,214,0,131,188,213,0,131,216,213,0,131,
- 244,213,0,131,28,214,0,131,168,214,0,131,
- 60,214,0,131,168,214,0,131,168,214,0,131,
- 88,214,0,131,132,214,0,131,0,0,0,0,
- 36,216,0,131,68,216,0,131,104,216,0,131,
- 140,216,0,131,140,216,0,131,0,0,0,0,
- 248,217,0,131,12,218,0,131,40,218,0,131,
- 76,218,0,131,124,218,0,131,152,218,0,131,
- 200,218,0,131,228,218,0,131,88,219,0,131,
- 116,219,0,131,64,224,0,131,92,224,0,131,
- 124,224,0,131,152,224,0,131,184,224,0,131,
- 0,0,0,0,110,111,32,115,121,115,67,111,
- 110,116,97,99,116,0,0,0,110,111,32,115,
- 121,115,78,97,109,101,0,0,110,111,32,115,
- 121,115,76,111,99,97,116,105,111,110,0,0,
- 37,115,58,37,100,58,32,102,97,105,108,101,
- 100,32,97,115,115,101,114,116,105,111,110,32,
- 96,37,115,39,10,0,0,0,110,117,109,114,
- 101,103,115,32,60,61,32,78,86,82,65,77,
- 95,78,82,69,71,83,32,38,38,32,110,117,
- 109,114,101,103,115,32,62,32,48,0,0,0,
- 102,105,114,115,116,114,101,103,32,60,32,78,
- 86,82,65,77,95,78,82,69,71,83,32,38,
- 38,32,102,105,114,115,116,114,101,103,32,62,
- 61,32,48,0,0,0,0,0,10,13,69,82,
- 82,79,82,32,45,0,0,0,0,0,0,0,
- 192,244,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,192,251,0,131,
- 8,252,0,131,8,252,0,131,200,251,0,131,
- 212,251,0,131,212,251,0,131,212,251,0,131,
- 212,251,0,131,212,251,0,131,212,251,0,131,
- 212,251,0,131,212,251,0,131,212,251,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,200,244,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 212,249,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,20,245,0,131,8,245,0,131,
- 84,247,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,244,251,0,131,
- 8,252,0,131,8,252,0,131,48,246,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 240,250,0,131,8,252,0,131,132,248,0,131,
- 8,252,0,131,8,252,0,131,160,249,0,131,
- 72,46,1,131,228,47,1,131,152,46,1,131,
- 132,47,1,131,0,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,144,47,1,131,
- 108,46,1,131,108,46,1,131,108,46,1,131,
- 152,46,1,131,152,46,1,131,228,47,1,131,
- 108,46,1,131,20,50,1,131,216,50,1,131,
- 56,50,1,131,224,50,1,131,104,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 144,50,1,131,20,50,1,131,20,50,1,131,
- 20,50,1,131,56,50,1,131,56,50,1,131,
- 216,50,1,131,20,50,1,131,124,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,88,53,1,131,64,53,1,131,
- 80,53,1,131,72,53,1,131,64,53,1,131,
- 0,0,0,0,28,83,1,131,36,83,1,131,
- 36,83,1,131,36,83,1,131,36,83,1,131,
- 28,83,1,131,44,83,1,131,44,83,1,131,
- 44,83,1,131,44,83,1,131,44,83,1,131,
- 28,83,1,131,44,83,1,131,0,0,0,0,
- 196,88,1,131,232,88,1,131,208,88,1,131,
- 220,88,1,131,244,88,1,131,0,0,0,0,
- 4,0,0,0,5,0,0,0,6,0,0,0,
- 7,0,0,0,2,0,0,0,3,0,0,0,
- 0,0,0,0,1,0,0,0,72,30,0,131,
- 72,30,0,131,216,44,0,131,0,30,0,131,
- 108,30,0,131,108,30,0,131,108,30,0,131,
- 108,30,0,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,20,137,1,131,
- 204,136,1,131,132,136,1,131,56,136,1,131,
- 236,135,1,131,172,135,1,131,120,135,1,131,
- 52,135,1,131,232,134,1,131,160,134,1,131,
- 80,134,1,131,8,134,1,131,188,133,1,131,
- 120,133,1,131,0,0,0,0,0,0,0,0,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,0,0,0,0,255,85,170,
- 0,0,0,0,4,0,8,0,16,0,32,0,
- 64,0,0,1,0,8,0,0,0,0,0,0,
- 0,0,0,0,0,4,3,2,1,0,0,0,
- 7,0,0,0,1,0,1,0,1,0,2,0,
- 20,0,15,0,1,0,0,128,128,0,0,0,
- 100,0,0,0,96,207,1,131,92,207,1,131,
- 88,207,1,131,84,207,1,131,80,207,1,131,
- 0,0,0,0,0,0,0,0,48,49,50,51,
- 52,53,54,55,56,57,65,66,67,68,69,70,
- 0,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,64,204,0,131,156,202,0,131,
- 96,148,1,131,1,0,4,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 200,155,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,124,204,0,131,156,202,0,131,
- 168,210,1,131,1,0,6,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 4,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,132,204,0,131,156,202,0,131,
- 4,1,0,163,1,0,67,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 64,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,168,204,0,131,248,204,0,131,
- 80,18,3,131,1,0,4,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 124,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,168,204,0,131,32,205,0,131,
- 96,18,3,131,1,0,4,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 184,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,168,204,0,131,72,205,0,131,
- 112,18,3,131,1,0,4,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 244,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,112,205,0,131,156,202,0,131,
- 2,0,0,0,1,0,2,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 48,157,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 220,155,1,131,2,0,0,0,24,156,1,131,
- 3,0,0,0,84,156,1,131,4,0,0,0,
- 144,156,1,131,5,0,0,0,204,156,1,131,
- 6,0,0,0,8,157,1,131,7,0,0,0,
- 68,157,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 156,202,0,131,48,211,1,131,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,172,157,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,4,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 124,148,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,6,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,220,5,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,66,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,4,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,180,208,0,131,132,205,0,131,
- 228,209,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,67,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,66,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,6,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,232,157,1,131,
- 2,0,0,0,16,158,1,131,3,0,0,0,
- 56,158,1,131,4,0,0,0,96,158,1,131,
- 5,0,0,0,136,158,1,131,6,0,0,0,
- 176,158,1,131,7,0,0,0,216,158,1,131,
- 8,0,0,0,0,159,1,131,9,0,0,0,
- 40,159,1,131,10,0,0,0,80,159,1,131,
- 11,0,0,0,120,159,1,131,12,0,0,0,
- 160,159,1,131,13,0,0,0,200,159,1,131,
- 14,0,0,0,240,159,1,131,15,0,0,0,
- 24,160,1,131,16,0,0,0,64,160,1,131,
- 17,0,0,0,104,160,1,131,18,0,0,0,
- 144,160,1,131,19,0,0,0,184,160,1,131,
- 20,0,0,0,224,160,1,131,21,0,0,0,
- 8,161,1,131,22,0,0,0,48,161,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 32,208,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,192,157,1,131,2,0,0,0,
- 40,208,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,112,205,0,131,
- 60,210,0,131,2,0,0,0,1,0,2,3,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,56,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 60,210,0,131,0,17,3,131,1,0,2,3,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,116,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,4,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,176,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,8,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,236,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,12,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,40,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,16,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,100,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,20,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,160,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,24,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,220,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,28,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,24,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,32,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,84,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,36,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,144,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,40,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,204,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 156,202,0,131,44,17,3,131,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,8,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,48,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,68,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,52,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,128,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,56,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,188,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,60,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,248,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,64,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,52,166,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,68,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,112,166,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,64,1,44,202,0,131,88,210,0,131,
- 164,202,0,131,120,211,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 88,210,0,131,164,202,0,131,120,211,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,64,1,
- 44,202,0,131,88,210,0,131,164,202,0,131,
- 120,211,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,88,210,0,131,
- 164,202,0,131,120,211,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 88,210,0,131,164,202,0,131,120,211,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 172,166,1,131,2,0,0,0,212,166,1,131,
- 3,0,0,0,252,166,1,131,4,0,0,0,
- 36,167,1,131,5,0,0,0,76,167,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 56,208,1,131,0,0,0,0,0,0,0,0,
- 1,0,64,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,64,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,1,
- 84,212,0,131,16,212,0,131,164,202,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,64,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,6,1,84,212,0,131,16,212,0,131,
- 164,202,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,180,167,1,131,
- 2,0,0,0,220,167,1,131,3,0,0,0,
- 4,168,1,131,4,0,0,0,44,168,1,131,
- 5,0,0,0,84,168,1,131,6,0,0,0,
- 124,168,1,131,7,0,0,0,164,168,1,131,
- 8,0,0,0,204,168,1,131,9,0,0,0,
- 244,168,1,131,10,0,0,0,28,169,1,131,
- 11,0,0,0,68,169,1,131,12,0,0,0,
- 108,169,1,131,13,0,0,0,148,169,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 72,208,1,131,0,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,4,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,64,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,60,170,1,131,
- 2,0,0,0,100,170,1,131,3,0,0,0,
- 140,170,1,131,4,0,0,0,180,170,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 88,208,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,72,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,20,171,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,76,162,1,131,2,0,0,0,
- 136,162,1,131,3,0,0,0,196,162,1,131,
- 4,0,0,0,0,163,1,131,5,0,0,0,
- 60,163,1,131,6,0,0,0,120,163,1,131,
- 7,0,0,0,180,163,1,131,8,0,0,0,
- 240,163,1,131,9,0,0,0,44,164,1,131,
- 10,0,0,0,104,164,1,131,11,0,0,0,
- 164,164,1,131,12,0,0,0,224,164,1,131,
- 13,0,0,0,28,165,1,131,14,0,0,0,
- 88,165,1,131,15,0,0,0,148,165,1,131,
- 16,0,0,0,208,165,1,131,17,0,0,0,
- 12,166,1,131,18,0,0,0,72,166,1,131,
- 19,0,0,0,132,166,1,131,20,0,0,0,
- 64,208,1,131,21,0,0,0,80,208,1,131,
- 22,0,0,0,96,208,1,131,23,0,0,0,
- 40,171,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,144,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,16,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,148,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,76,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,152,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,136,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,156,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,196,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,160,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,0,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,164,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,60,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,168,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,120,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,172,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,180,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,176,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,240,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,180,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,44,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,184,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,104,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,188,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,164,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,192,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,224,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,196,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,28,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,200,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,88,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,204,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,148,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,208,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,208,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,212,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,12,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,216,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,72,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,220,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,132,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,224,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,192,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,228,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,252,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,232,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,56,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,236,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,116,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,240,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,176,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,244,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,236,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,36,172,1,131,2,0,0,0,
- 96,172,1,131,3,0,0,0,156,172,1,131,
- 4,0,0,0,216,172,1,131,5,0,0,0,
- 20,173,1,131,6,0,0,0,80,173,1,131,
- 7,0,0,0,140,173,1,131,8,0,0,0,
- 200,173,1,131,9,0,0,0,4,174,1,131,
- 10,0,0,0,64,174,1,131,11,0,0,0,
- 124,174,1,131,12,0,0,0,184,174,1,131,
- 13,0,0,0,244,174,1,131,14,0,0,0,
- 48,175,1,131,15,0,0,0,108,175,1,131,
- 16,0,0,0,168,175,1,131,17,0,0,0,
- 228,175,1,131,18,0,0,0,32,176,1,131,
- 19,0,0,0,92,176,1,131,20,0,0,0,
- 152,176,1,131,21,0,0,0,212,176,1,131,
- 22,0,0,0,16,177,1,131,23,0,0,0,
- 76,177,1,131,24,0,0,0,136,177,1,131,
- 25,0,0,0,196,177,1,131,26,0,0,0,
- 0,178,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,112,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,0,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,116,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,60,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,120,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,120,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,124,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,180,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,200,212,0,131,
- 156,202,0,131,220,5,0,163,1,0,64,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,240,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,112,205,0,131,
- 156,202,0,131,161,0,0,0,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,44,180,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,4,180,1,131,2,0,0,0,
- 64,180,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,120,208,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,20,179,1,131,
- 2,0,0,0,80,179,1,131,3,0,0,0,
- 140,179,1,131,4,0,0,0,200,179,1,131,
- 5,0,0,0,128,208,1,131,0,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,6,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,192,180,1,131,2,0,0,0,
- 232,180,1,131,3,0,0,0,16,181,1,131,
- 4,0,0,0,56,181,1,131,5,0,0,0,
- 96,181,1,131,6,0,0,0,136,181,1,131,
- 7,0,0,0,176,181,1,131,8,0,0,0,
- 216,181,1,131,9,0,0,0,0,182,1,131,
- 10,0,0,0,40,182,1,131,11,0,0,0,
- 80,182,1,131,13,0,0,0,120,182,1,131,
- 16,0,0,0,160,182,1,131,17,0,0,0,
- 200,182,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,144,208,1,131,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,0,0,0,
- 160,208,1,131,2,0,0,0,168,208,1,131,
- 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,0,0,0,184,208,1,131,2,0,0,0,
- 192,208,1,131,0,0,0,0,0,0,0,0,
- 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,0,0,0,208,208,1,131,2,0,0,0,
- 216,208,1,131,3,0,0,0,224,208,1,131,
- 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,0,0,0,240,208,1,131,2,0,0,0,
- 248,208,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 8,209,1,131,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,0,0,0,24,209,1,131,
- 2,0,0,0,32,209,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,48,209,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,64,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,232,208,1,131,
- 2,0,0,0,0,209,1,131,3,0,0,0,
- 16,209,1,131,4,0,0,0,40,209,1,131,
- 5,0,0,0,56,209,1,131,6,0,0,0,
- 72,209,1,131,0,0,0,0,0,0,0,0,
- 2,0,0,0,152,208,1,131,6,0,0,0,
- 176,208,1,131,7,0,0,0,200,208,1,131,
- 8,0,0,0,80,209,1,131,0,0,0,0,
- 0,0,0,0,7,0,0,0,88,209,1,131,
- 0,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 128,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 8,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 144,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 68,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 148,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 128,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 132,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 188,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 136,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 248,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 140,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 52,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 156,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 112,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 160,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 172,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 164,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 232,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 168,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 36,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 172,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 96,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 176,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 156,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 180,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 216,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 184,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 20,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 188,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 80,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 192,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 140,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 196,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 200,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 200,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 4,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 204,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 64,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 208,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 124,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 212,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 184,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 220,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 244,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 224,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 48,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 228,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 108,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 232,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 168,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 236,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 228,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 240,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 32,191,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,104,215,0,131,140,215,0,131,
- 0,0,0,0,1,0,2,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 92,191,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 28,185,1,131,2,0,0,0,88,185,1,131,
- 3,0,0,0,148,185,1,131,4,0,0,0,
- 208,185,1,131,5,0,0,0,12,186,1,131,
- 6,0,0,0,72,186,1,131,8,0,0,0,
- 132,186,1,131,9,0,0,0,192,186,1,131,
- 10,0,0,0,252,186,1,131,11,0,0,0,
- 56,187,1,131,12,0,0,0,116,187,1,131,
- 13,0,0,0,176,187,1,131,14,0,0,0,
- 236,187,1,131,15,0,0,0,40,188,1,131,
- 16,0,0,0,100,188,1,131,17,0,0,0,
- 160,188,1,131,18,0,0,0,220,188,1,131,
- 19,0,0,0,24,189,1,131,20,0,0,0,
- 84,189,1,131,21,0,0,0,144,189,1,131,
- 22,0,0,0,204,189,1,131,24,0,0,0,
- 8,190,1,131,25,0,0,0,68,190,1,131,
- 26,0,0,0,128,190,1,131,27,0,0,0,
- 188,190,1,131,28,0,0,0,248,190,1,131,
- 29,0,0,0,52,191,1,131,30,0,0,0,
- 112,191,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,180,215,0,131,
- 156,202,0,131,218,12,3,131,1,0,4,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,128,192,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 156,202,0,131,40,211,1,131,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,188,192,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,112,205,0,131,
- 156,202,0,131,2,0,0,0,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,248,192,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,200,215,0,131,
- 164,202,0,131,196,216,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 200,215,0,131,164,202,0,131,196,216,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,6,1,
- 44,202,0,131,200,215,0,131,164,202,0,131,
- 196,216,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,200,215,0,131,
- 164,202,0,131,196,216,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 200,215,0,131,164,202,0,131,196,216,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 52,193,1,131,2,0,0,0,92,193,1,131,
- 3,0,0,0,132,193,1,131,4,0,0,0,
- 172,193,1,131,5,0,0,0,212,193,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 112,209,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,148,192,1,131,2,0,0,0,
- 208,192,1,131,3,0,0,0,12,193,1,131,
- 4,0,0,0,120,209,1,131,0,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 112,205,0,131,156,202,0,131,3,0,0,0,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,100,194,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,216,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,160,194,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 104,217,0,131,156,202,0,131,0,0,0,0,
- 1,0,67,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,220,194,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 104,217,0,131,156,202,0,131,0,0,0,0,
- 1,0,65,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,24,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 112,217,0,131,156,202,0,131,216,12,3,131,
- 1,0,4,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,84,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 120,205,0,131,156,202,0,131,224,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,144,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 120,205,0,131,156,202,0,131,228,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,204,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,232,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,8,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,234,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,68,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,246,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,128,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,236,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,188,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,238,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,248,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,240,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,52,197,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,242,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,112,197,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,180,219,0,131,
- 132,217,0,131,164,202,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 180,219,0,131,132,217,0,131,0,221,0,131,
- 104,220,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,180,219,0,131,132,217,0,131,
- 164,202,0,131,104,220,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,180,219,0,131,
- 132,217,0,131,0,221,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 180,219,0,131,132,217,0,131,0,221,0,131,
- 104,220,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,4,1,180,219,0,131,132,217,0,131,
- 164,202,0,131,104,220,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,180,219,0,131,
- 132,217,0,131,164,202,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,4,1,
- 180,219,0,131,132,217,0,131,164,202,0,131,
- 104,220,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,4,1,180,219,0,131,132,217,0,131,
- 164,202,0,131,104,220,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,219,0,131,
- 132,217,0,131,164,202,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 172,197,1,131,2,0,0,0,212,197,1,131,
- 3,0,0,0,252,197,1,131,4,0,0,0,
- 36,198,1,131,5,0,0,0,76,198,1,131,
- 6,0,0,0,116,198,1,131,7,0,0,0,
- 156,198,1,131,8,0,0,0,196,198,1,131,
- 9,0,0,0,236,198,1,131,10,0,0,0,
- 20,199,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,136,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,120,194,1,131,
- 2,0,0,0,180,194,1,131,3,0,0,0,
- 240,194,1,131,4,0,0,0,44,195,1,131,
- 5,0,0,0,104,195,1,131,6,0,0,0,
- 164,195,1,131,7,0,0,0,224,195,1,131,
- 8,0,0,0,28,196,1,131,9,0,0,0,
- 88,196,1,131,10,0,0,0,148,196,1,131,
- 11,0,0,0,208,196,1,131,12,0,0,0,
- 12,197,1,131,13,0,0,0,72,197,1,131,
- 14,0,0,0,132,197,1,131,15,0,0,0,
- 144,209,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,76,210,0,131,156,202,0,131,
- 160,211,1,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 44,200,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,120,205,0,131,60,210,0,131,
- 140,1,0,163,1,0,2,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 104,200,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,4,1,
- 44,202,0,131,36,222,0,131,164,202,0,131,
- 48,223,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,36,222,0,131,
- 164,202,0,131,48,223,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 36,222,0,131,164,202,0,131,48,223,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 164,200,1,131,2,0,0,0,204,200,1,131,
- 3,0,0,0,244,200,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,168,209,1,131,
- 0,0,0,0,0,0,0,0,1,0,2,1,
- 44,202,0,131,212,223,0,131,164,202,0,131,
- 252,224,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,212,223,0,131,
- 164,202,0,131,252,224,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 212,223,0,131,164,202,0,131,252,224,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,212,223,0,131,164,202,0,131,
- 252,224,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,212,223,0,131,
- 164,202,0,131,252,224,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,76,201,1,131,
- 2,0,0,0,116,201,1,131,3,0,0,0,
- 156,201,1,131,4,0,0,0,196,201,1,131,
- 5,0,0,0,236,201,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,184,209,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 64,200,1,131,2,0,0,0,124,200,1,131,
- 3,0,0,0,176,209,1,131,4,0,0,0,
- 192,209,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,128,209,1,131,2,0,0,0,
- 152,209,1,131,3,0,0,0,160,209,1,131,
- 4,0,0,0,200,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,24,208,1,131,
- 2,0,0,0,48,208,1,131,4,0,0,0,
- 104,208,1,131,5,0,0,0,112,208,1,131,
- 7,0,0,0,136,208,1,131,10,0,0,0,
- 96,209,1,131,11,0,0,0,104,209,1,131,
- 17,0,0,0,208,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,216,209,1,131,
- 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,0,0,0,240,209,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,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,0,0,0,8,210,1,131,
- 2,0,0,0,16,210,1,131,3,0,0,0,
- 24,210,1,131,4,0,0,0,32,210,1,131,
- 5,0,0,0,40,210,1,131,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,0,0,0,
- 56,210,1,131,2,0,0,0,64,210,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 72,210,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 48,210,1,131,2,0,0,0,80,210,1,131,
- 3,0,0,0,88,210,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,16,208,1,131,
- 2,0,0,0,224,209,1,131,3,0,0,0,
- 232,209,1,131,4,0,0,0,248,209,1,131,
- 5,0,0,0,0,210,1,131,6,0,0,0,
- 96,210,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,104,210,1,131,0,0,0,0,
- 0,0,0,0,6,0,0,0,112,210,1,131,
- 0,0,0,0,0,0,0,0,3,0,0,0,
- 120,210,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,128,210,1,131,0,0,0,0,
- 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,0,0,0,3,0,0,0,6,0,0,0,
- 1,0,0,0,2,0,0,0,1,0,0,0,
- 10,0,0,0,7,0,0,0,8,0,0,0,
- 2,0,0,0,2,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,112,117,98,108,
- 105,99,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,112,114,105,118,97,116,101,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 83,78,77,80,95,116,114,97,112,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 3,0,0,0,6,0,0,0,1,0,0,0,
- 4,0,0,0,1,0,0,0,76,1,0,0,
- 5,0,0,0,1,0,0,0,1,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 3,0,0,0,6,0,0,0,1,0,0,0,
- 2,0,0,0,1,0,0,0,2,0,0,0,
- 2,0,0,0,1,0,0,0,1,0,0,0,
- 0,0,0,0,1,0,0,0,3,0,0,0,
- 6,0,0,0,1,0,0,0,2,0,0,0,
- 1,0,0,0,17,0,0,0,0,0,0,0,
- 0,0,0,0,48,49,50,51,52,53,54,55,
- 56,57,65,66,67,68,69,70,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 255,85,170,0,255,255,255,255,85,85,85,85,
- 170,170,170,170,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,64,40,35,41,
- 32,67,111,112,121,114,105,103,104,116,32,40,
- 99,41,32,49,57,56,54,32,45,32,49,57,
- 57,53,32,32,69,112,105,108,111,103,117,101,
- 32,84,101,99,104,110,111,108,111,103,121,32,
- 67,111,114,112,111,114,97,116,105,111,110,10,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,255,255,255,255,
- 72,10,0,0,78,10,0,0,83,10,0,0,
- 69,10,0,0,109,97,105,110,46,99,0,0,
- 48,0,0,0,55,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 0,0,0,0,116,105,109,101,114,46,99,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 100,0,0,0,100,0,0,0,1,0,0,0,
- 0,0,0,0,115,114,99,32,0,0,0,0,
- 32,0,0,0,100,115,116,32,0,0,0,0,
- 32,37,48,50,88,0,0,0,10,0,0,0,
- 255,255,255,255,48,48,48,48,48,48,0,0,
- 48,48,48,48,48,49,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,255,255,255,255,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 62,32,0,0,37,120,10,0,37,120,58,9,
- 37,120,10,0,37,115,10,0,0,0,0,0,
- 10,0,0,0,0,0,0,0,0,0,0,0,
- 68,85,77,80,10,0,0,0,37,48,50,120,
- 32,0,0,0,10,0,0,0,0,0,0,0,
- 37,100,32,112,112,115,10,0,0,0,0,0,
- 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,0,0,0,0,0,0,0,1,0,0,0,
- 119,119,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,128,194,0,
- 0,0,0,0,1,128,194,0,0,16,0,0,
- 66,76,75,0,70,87,68,0,76,82,78,0,
- 76,73,83,0,68,73,83,0,72,69,76,76,
- 79,10,0,0,116,99,32,101,120,112,10,0,
- 102,114,111,109,32,0,0,0,10,0,0,0,
- 87,101,105,114,100,0,0,0,0,0,0,0,
- 0,0,0,0,255,255,255,255,255,255,255,255,
- 255,255,0,0,255,255,255,255,255,255,0,0,
- 0,0,0,0,0,0,0,0,80,65,68,37,
- 100,10,0,0,170,170,3,0,0,0,0,0,
- 83,69,78,84,33,10,0,0,85,68,80,10,
- 0,0,0,0,73,67,77,80,10,0,0,0,
- 69,67,72,79,10,0,0,0,73,80,10,0,
- 170,170,3,0,0,0,0,0,73,80,88,33,
- 10,0,0,0,0,0,0,0,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,192,155,1,131,0,0,0,0,
- 108,157,1,131,0,0,0,0,88,161,1,131,
- 0,0,0,0,16,162,1,131,0,0,0,0,
- 32,162,1,131,0,0,0,0,116,167,1,131,
- 0,0,0,0,164,167,1,131,0,0,0,0,
- 188,169,1,131,0,0,0,0,44,170,1,131,
- 0,0,0,0,220,170,1,131,0,0,0,0,
- 4,171,1,131,0,0,0,0,80,171,1,131,
- 0,0,0,0,40,178,1,131,0,0,0,0,
- 104,180,1,131,0,0,0,0,128,180,1,131,
- 0,0,0,0,144,180,1,131,0,0,0,0,
- 240,182,1,131,0,0,0,0,104,183,1,131,
- 0,0,0,0,120,183,1,131,0,0,0,0,
- 128,183,1,131,0,0,0,0,136,183,1,131,
- 0,0,0,0,160,183,1,131,0,0,0,0,
- 168,183,1,131,0,0,0,0,176,183,1,131,
- 0,0,0,0,200,183,1,131,0,0,0,0,
- 208,183,1,131,0,0,0,0,216,183,1,131,
- 0,0,0,0,224,183,1,131,0,0,0,0,
- 0,184,1,131,0,0,0,0,8,184,1,131,
- 0,0,0,0,16,184,1,131,0,0,0,0,
- 40,184,1,131,0,0,0,0,48,184,1,131,
- 0,0,0,0,64,184,1,131,0,0,0,0,
- 72,184,1,131,0,0,0,0,80,184,1,131,
- 0,0,0,0,104,184,1,131,0,0,0,0,
- 112,184,1,131,0,0,0,0,128,184,1,131,
- 0,0,0,0,136,184,1,131,0,0,0,0,
- 152,184,1,131,0,0,0,0,208,184,1,131,
- 0,0,0,0,248,184,1,131,0,0,0,0,
- 152,191,1,131,0,0,0,0,252,193,1,131,
- 0,0,0,0,44,194,1,131,0,0,0,0,
- 60,194,1,131,0,0,0,0,60,199,1,131,
- 0,0,0,0,148,199,1,131,0,0,0,0,
- 164,199,1,131,0,0,0,0,36,200,1,131,
- 0,0,0,0,28,201,1,131,0,0,0,0,
- 60,201,1,131,0,0,0,0,20,202,1,131,
- 0,0,0,0,68,202,1,131,0,0,0,0,
- 84,202,1,131,0,0,0,0,124,202,1,131,
- 0,0,0,0,164,202,1,131,0,0,0,0,
- 236,202,1,131,0,0,0,0,252,202,1,131,
- 0,0,0,0,4,203,1,131,0,0,0,0,
- 12,203,1,131,0,0,0,0,28,203,1,131,
- 0,0,0,0,36,203,1,131,0,0,0,0,
- 44,203,1,131,0,0,0,0,52,203,1,131,
- 0,0,0,0,60,203,1,131,0,0,0,0,
- 68,203,1,131,0,0,0,0,76,203,1,131,
- 0,0,0,0,124,203,1,131,0,0,0,0,
- 132,203,1,131,0,0,0,0,140,203,1,131,
- 0,0,0,0,164,203,1,131,0,0,0,0,
- 180,203,1,131,0,0,0,0,188,203,1,131,
- 0,0,0,0,220,203,1,131,0,0,0,0,
- 20,204,1,131,0,0,0,0,36,204,1,131,
- 0,0,0,0,52,204,1,131,0,0,0,0,
- 68,204,1,131,255,255,255,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 10,0,0,0,10,0,0,0,0,205,1,131,
- 10,0,0,0,7,0,0,0,0,0,0,0,
- 0,0,0,0,255,255,255,255,110,118,114,97,
- 109,46,99,0,114,99,0,0,48,120,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0
- } ;
-static const int dgrs_ncode = 119520 ;
diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h
deleted file mode 100644
index ac9217ad2138..000000000000
--- a/drivers/net/dgrs_i82596.h
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * i82596 ethernet controller bits and structures (little endian)
- *
- * $Id: i82596.h,v 1.8 1996/09/03 11:19:03 rick Exp $
- */
-
-/************************************************************************/
-/* */
-/* PORT commands (p. 4-20). The least significant nibble is one */
-/* of these commands, the rest of the command is a memory address */
-/* aligned on a 16 byte boundary. Note that port commands must */
-/* be written to the PORT address and the PORT address+2 with two */
-/* halfword writes. Write the LSH first to PORT, then the MSH to */
-/* PORT+2. Blame Intel. */
-/* */
-/************************************************************************/
-#define I596_PORT_RESET 0x0 /* Reset. Wait 5 SysClks & 10 TxClks */
-#define I596_PORT_SELFTEST 0x1 /* Do a selftest */
-#define I596_PORT_SCP_ADDR 0x2 /* Set new SCP address */
-#define I596_PORT_DUMP 0x3 /* Dump internal data structures */
-
-/*
- * I596_ST: Selftest results (p. 4-21)
- */
-typedef volatile struct
-{
- ulong signature; /* ROM checksum */
- ulong result; /* Selftest results: non-zero is a failure */
-} I596_ST;
-
-#define I596_ST_SELFTEST_FAIL 0x1000 /* Selftest Failed */
-#define I596_ST_DIAGNOSE_FAIL 0x0020 /* Diagnose Failed */
-#define I596_ST_BUSTIMER_FAIL 0x0010 /* Bus Timer Failed */
-#define I596_ST_REGISTER_FAIL 0x0008 /* Register Failed */
-#define I596_ST_ROM_FAIL 0x0004 /* ROM Failed */
-
-/*
- * I596_DUMP: Dump results
- */
-typedef volatile struct
-{
- ulong dump[77];
-} I596_DUMP;
-
-/************************************************************************/
-/* */
-/* I596_TBD: Transmit Buffer Descriptor (p. 4-59) */
-/* */
-/************************************************************************/
-typedef volatile struct _I596_TBD
-{
- ulong count;
- vol struct _I596_TBD *next;
- uchar *buf;
- ushort unused1;
- ushort unused2;
-} I596_TBD;
-
-#define I596_TBD_NOLINK ((I596_TBD *) 0xffffffff)
-#define I596_TBD_EOF 0x8000
-#define I596_TBD_COUNT_MASK 0x3fff
-
-/************************************************************************/
-/* */
-/* I596_TFD: Transmit Frame Descriptor (p. 4-56) */
-/* a.k.a. I596_CB_XMIT */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- I596_TBD *tbdp;
- ulong count; /* for speed */
-
- /* Application defined data follows structure... */
-
-#if 0 /* We don't use these intel defined ones */
- uchar addr[6];
- ushort len;
- uchar data[1];
-#else
- ulong dstchan;/* Used by multi-NIC mode */
-#endif
-} I596_TFD;
-
-#define I596_TFD_NOCRC 0x0010 /* cmd: No CRC insertion */
-#define I596_TFD_FLEX 0x0008 /* cmd: Flexible mode */
-
-/************************************************************************/
-/* */
-/* I596_RBD: Receive Buffer Descriptor (p. 4-84) */
-/* */
-/************************************************************************/
-typedef volatile struct _I596_RBD
-{
-#ifdef INTEL_RETENTIVE
- ushort count; /* Length of data in buf */
- ushort offset;
-#else
- ulong count; /* Length of data in buf */
-#endif
- vol struct _I596_RBD *next; /* Next buffer descriptor in list */
- uchar *buf; /* Data buffer */
-#ifdef INTEL_RETENTIVE
- ushort size; /* Size of buf (constant) */
- ushort zero;
-#else
- ulong size; /* Size of buf (constant) */
-#endif
-
- /* Application defined data follows structure... */
-
- uchar chan;
- uchar refcnt;
- ushort len;
-} I596_RBD;
-
-#define I596_RBD_NOLINK ((I596_RBD *) 0xffffffff)
-#define I596_RBD_EOF 0x8000 /* This is last buffer in a frame */
-#define I596_RBD_F 0x4000 /* The actual count is valid */
-
-#define I596_RBD_EL 0x8000 /* Last buffer in list */
-
-/************************************************************************/
-/* */
-/* I596_RFD: Receive Frame Descriptor (p. 4-79) */
-/* */
-/************************************************************************/
-typedef volatile struct _I596_RFD
-{
- ushort status;
- ushort cmd;
- vol struct _I596_RFD *next;
- vol struct _I596_RBD *rbdp;
- ushort count; /* Len of data in RFD: always 0 */
- ushort size; /* Size of RFD buffer: always 0 */
-
- /* Application defined data follows structure... */
-
-# if 0 /* We don't use these intel defined ones */
- uchar addr[6];
- ushort len;
- uchar data[1];
-# else
- ulong dstchan;/* Used by multi-nic mode */
-# endif
-} I596_RFD;
-
-#define I596_RFD_C 0x8000 /* status: frame complete */
-#define I596_RFD_B 0x4000 /* status: frame busy or waiting */
-#define I596_RFD_OK 0x2000 /* status: frame OK */
-#define I596_RFD_ERR_LENGTH 0x1000 /* status: length error */
-#define I596_RFD_ERR_CRC 0x0800 /* status: CRC error */
-#define I596_RFD_ERR_ALIGN 0x0400 /* status: alignment error */
-#define I596_RFD_ERR_NOBUFS 0x0200 /* status: resource error */
-#define I596_RFD_ERR_DMA 0x0100 /* status: DMA error */
-#define I596_RFD_ERR_SHORT 0x0080 /* status: too short error */
-#define I596_RFD_NOMATCH 0x0002 /* status: IA was not matched */
-#define I596_RFD_COLLISION 0x0001 /* status: collision during receive */
-
-#define I596_RFD_EL 0x8000 /* cmd: end of RFD list */
-#define I596_RFD_FLEX 0x0008 /* cmd: Flexible mode */
-#define I596_RFD_EOF 0x8000 /* count: last buffer in the frame */
-#define I596_RFD_F 0x4000 /* count: The actual count is valid */
-
-/************************************************************************/
-/* */
-/* Commands */
-/* */
-/************************************************************************/
-
- /* values for cmd halfword in all the structs below */
-#define I596_CB_CMD 0x07 /* CB COMMANDS */
-#define I596_CB_CMD_NOP 0
-#define I596_CB_CMD_IA 1
-#define I596_CB_CMD_CONF 2
-#define I596_CB_CMD_MCAST 3
-#define I596_CB_CMD_XMIT 4
-#define I596_CB_CMD_TDR 5
-#define I596_CB_CMD_DUMP 6
-#define I596_CB_CMD_DIAG 7
-
-#define I596_CB_CMD_EL 0x8000 /* CB is last in linked list */
-#define I596_CB_CMD_S 0x4000 /* Suspend after execution */
-#define I596_CB_CMD_I 0x2000 /* cause interrupt */
-
- /* values for the status halfword in all the struct below */
-#define I596_CB_STATUS 0xF000 /* All four status bits */
-#define I596_CB_STATUS_C 0x8000 /* Command complete */
-#define I596_CB_STATUS_B 0x4000 /* Command busy executing */
-#define I596_CB_STATUS_C_OR_B 0xC000 /* Command complete or busy */
-#define I596_CB_STATUS_OK 0x2000 /* Command complete, no errors */
-#define I596_CB_STATUS_A 0x1000 /* Command busy executing */
-
-#define I596_CB_NOLINK ((I596_CB *) 0xffffffff)
-
-/*
- * I596_CB_NOP: NOP Command (p. 4-34)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
-} I596_CB_NOP;
-
-/*
- * Same as above, but command and status in one ulong for speed
- */
-typedef volatile struct
-{
- ulong csr;
- union _I596_CB *next;
-} I596_CB_FAST;
-#define FASTs(X) (X)
-#define FASTc(X) ((X)<<16)
-
-/*
- * I596_CB_IA: Individual (MAC) Address Command (p. 4-35)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- uchar addr[6];
-} I596_CB_IA;
-
-/*
- * I596_CB_CONF: Configure Command (p. 4-37)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- uchar conf[14];
-} I596_CB_CONF;
-
-#define I596_CONF0_P 0x80 /* Enable RBD Prefetch Bit */
-#define I596_CONF0_COUNT 14 /* Count of configuration bytes */
-
-#define I596_CONF1_MON_OFF 0xC0 /* Monitor mode: Monitor off */
-#define I596_CONF1_MON_ON 0x80 /* Monitor mode: Monitor on */
-#define I596_CONF1_TxFIFO(W) (W) /* TxFIFO trigger, in words */
-
-#define I596_CONF2_SAVEBF 0x80 /* Save bad frames */
-
-#define I596_CONF3_ADDRLEN(B) (B) /* Address length */
-#define I596_CONF3_NOSRCINSERT 0x08 /* Do not insert source address */
-#define I596_CONF3_PREAMBLE8 0x20 /* 8 byte preamble */
-#define I596_CONF3_LOOPOFF 0x00 /* Loopback: Off */
-#define I596_CONF3_LOOPINT 0x40 /* Loopback: internal */
-#define I596_CONF3_LOOPEXT 0xC0 /* Loopback: external */
-
-#define I596_CONF4_LINPRI(ST) (ST) /* Linear priority: slot times */
-#define I596_CONF4_EXPPRI(ST) (ST) /* Exponential priority: slot times */
-#define I596_CONF4_IEEE_BOM 0 /* IEEE 802.3 backoff method */
-
-#define I596_CONF5_IFS(X) (X) /* Interframe spacing in clocks */
-
-#define I596_CONF6_ST_LOW(X) (X&255) /* Slot time, low byte */
-
-#define I596_CONF7_ST_HI(X) (X>>8) /* Slot time, high bits */
-#define I596_CONF7_RETRY(X) (X<<4) /* Max retry number */
-
-#define I596_CONF8_PROMISC 0x01 /* Rcv all frames */
-#define I596_CONF8_NOBROAD 0x02
-#define I596_CONF8_MANCHESTER 0x04
-#define I596_CONF8_TxNOCRS 0x08
-#define I596_CONF8_NOCRC 0x10
-#define I596_CONF8_CRC_CCITT 0x20
-#define I596_CONF8_BITSTUFFING 0x40
-#define I596_CONF8_PADDING 0x80
-
-#define I596_CONF9_CSFILTER(X) (X)
-#define I596_CONF9_CSINT(X) 0x08
-#define I596_CONF9_CDFILTER(X) (X<<4)
-#define I596_CONF9_CDINT(X) 0x80
-
-#define I596_CONF10_MINLEN(X) (X) /* Minimum frame length */
-
-#define I596_CONF11_PRECRS_ 0x01 /* Preamble before carrier sense */
-#define I596_CONF11_LNGFLD_ 0x02 /* Padding in End of Carrier */
-#define I596_CONF11_CRCINM_ 0x04 /* CRC in memory */
-#define I596_CONF11_AUTOTX 0x08 /* Auto retransmit */
-#define I596_CONF11_CSBSAC_ 0x10 /* Collision detect by src addr cmp. */
-#define I596_CONF11_MCALL_ 0x20 /* Multicast all */
-
-#define I596_CONF13_RESERVED 0x3f /* Reserved: must be ones */
-#define I596_CONF13_MULTIA 0x40 /* Enable multiple addr. reception */
-#define I596_CONF13_DISBOF 0x80 /* Disable backoff algorithm */
-/*
- * I596_CB_MCAST: Multicast-Setup Command (p. 4-54)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- ushort count; /* Number of 6-byte addrs that follow */
- uchar addr[6][1];
-} I596_CB_MCAST;
-
-/*
- * I596_CB_XMIT: Transmit Command (p. 4-56)
- */
-typedef I596_TFD I596_CB_XMIT;
-
-#define I596_CB_XMIT_NOCRC 0x0010 /* cmd: No CRC insertion */
-#define I596_CB_XMIT_FLEX 0x0008 /* cmd: Flexible memory mode */
-
-#define I596_CB_XMIT_ERR_LATE 0x0800 /* status: error: late collision */
-#define I596_CB_XMIT_ERR_NOCRS 0x0400 /* status: error: no carriers sense */
-#define I596_CB_XMIT_ERR_NOCTS 0x0200 /* status: error: loss of CTS */
-#define I596_CB_XMIT_ERR_UNDER 0x0100 /* status: error: DMA underrun */
-#define I596_CB_XMIT_ERR_MAXCOL 0x0020 /* status: error: maximum collisions */
-#define I596_CB_XMIT_COLLISIONS 0x000f /* status: number of collisions */
-
-/*
- * I596_CB_TDR: Time Domain Reflectometry Command (p. 4-63)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- ushort time;
-} I596_CB_TDR;
-
-/*
- * I596_CB_DUMP: Dump Command (p. 4-65)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- uchar *buf;
-} I596_CB_DUMP;
-
-/*
- * I596_CB_DIAG: Diagnose Command (p. 4-77)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
-} I596_CB_DIAG;
-
-/*
- * I596_CB: Command Block
- */
-typedef union _I596_CB
-{
- I596_CB_NOP nop;
- I596_CB_IA ia;
- I596_CB_CONF conf;
- I596_CB_MCAST mcast;
- I596_CB_XMIT xmit;
- I596_CB_TDR tdr;
- I596_CB_DUMP dump;
- I596_CB_DIAG diag;
-
- /* command and status in one ulong for speed... */
- I596_CB_FAST fast;
-} I596_CB;
-
-/************************************************************************/
-/* */
-/* I596_SCB: System Configuration Block (p. 4-26) */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- volatile ushort status; /* Status word */
- volatile ushort cmd; /* Command word */
- I596_CB *cbp;
- I596_RFD *rfdp;
- ulong crc_errs;
- ulong align_errs;
- ulong resource_errs;
- ulong overrun_errs;
- ulong rcvcdt_errs;
- ulong short_errs;
- ushort toff;
- ushort ton;
-} I596_SCB;
-
- /* cmd halfword values */
-#define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */
-#define I596_SCB_ACK_CX 0x8000 /* Ack command completion */
-#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */
-#define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */
-#define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */
-#define I596_SCB_ACK_ALL 0xF000 /* Ack everything */
-
-#define I596_SCB_CUC 0x0700 /* COMMAND UNIT COMMANDS */
-#define I596_SCB_CUC_NOP 0x0000 /* No operation */
-#define I596_SCB_CUC_START 0x0100 /* Start execution of first CB */
-#define I596_SCB_CUC_RESUME 0x0200 /* Resume execution */
-#define I596_SCB_CUC_SUSPEND 0x0300 /* Suspend after current CB */
-#define I596_SCB_CUC_ABORT 0x0400 /* Abort current CB immediately */
-#define I596_SCB_CUC_LOAD 0x0500 /* Load Bus throttle timers */
-#define I596_SCB_CUC_LOADIMM 0x0600 /* Load Bus throttle timers, now */
-
-#define I596_SCB_RUC 0x0070 /* RECEIVE UNIT COMMANDS */
-#define I596_SCB_RUC_NOP 0x0000 /* No operation */
-#define I596_SCB_RUC_START 0x0010 /* Start reception */
-#define I596_SCB_RUC_RESUME 0x0020 /* Resume reception */
-#define I596_SCB_RUC_SUSPEND 0x0030 /* Suspend reception */
-#define I596_SCB_RUC_ABORT 0x0040 /* Abort reception */
-
-#define I596_SCB_RESET 0x0080 /* Hard reset chip */
-
- /* status halfword values */
-#define I596_SCB_STAT 0xF000 /* STATUS */
-#define I596_SCB_CX 0x8000 /* command completion */
-#define I596_SCB_FR 0x4000 /* received frame */
-#define I596_SCB_CNA 0x2000 /* command unit not active */
-#define I596_SCB_RNR 0x1000 /* rcv unit not ready */
-
-#define I596_SCB_CUS 0x0700 /* COMMAND UNIT STATUS */
-#define I596_SCB_CUS_IDLE 0x0000 /* Idle */
-#define I596_SCB_CUS_SUSPENDED 0x0100 /* Suspended */
-#define I596_SCB_CUS_ACTIVE 0x0200 /* Active */
-
-#define I596_SCB_RUS 0x00F0 /* RECEIVE UNIT STATUS */
-#define I596_SCB_RUS_IDLE 0x0000 /* Idle */
-#define I596_SCB_RUS_SUSPENDED 0x0010 /* Suspended */
-#define I596_SCB_RUS_NORES 0x0020 /* No Resources */
-#define I596_SCB_RUS_READY 0x0040 /* Ready */
-#define I596_SCB_RUS_NORBDS 0x0080 /* No more RBDs modifier */
-
-#define I596_SCB_LOADED 0x0008 /* Bus timers loaded */
-
-/************************************************************************/
-/* */
-/* I596_ISCP: Intermediate System Configuration Ptr (p 4-26) */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- ulong busy; /* Set to 1; I596 clears it when scbp is read */
- I596_SCB *scbp;
-} I596_ISCP;
-
-/************************************************************************/
-/* */
-/* I596_SCP: System Configuration Pointer (p. 4-23) */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- ulong sysbus;
- ulong dummy;
- I596_ISCP *iscpp;
-} I596_SCP;
-
- /* .sysbus values */
-#define I596_SCP_RESERVED 0x400000 /* Reserved bits must be set */
-#define I596_SCP_INTLOW 0x200000 /* Intr. Polarity active low */
-#define I596_SCP_INTHIGH 0 /* Intr. Polarity active high */
-#define I596_SCP_LOCKDIS 0x100000 /* Lock Function disabled */
-#define I596_SCP_LOCKEN 0 /* Lock Function enabled */
-#define I596_SCP_ETHROTTLE 0x080000 /* External Bus Throttle */
-#define I596_SCP_ITHROTTLE 0 /* Internal Bus Throttle */
-#define I596_SCP_LINEAR 0x040000 /* Linear Mode */
-#define I596_SCP_SEGMENTED 0x020000 /* Segmented Mode */
-#define I596_SCP_82586 0x000000 /* 82586 Mode */
diff --git a/drivers/net/dgrs_plx9060.h b/drivers/net/dgrs_plx9060.h
deleted file mode 100644
index 6888ae0d0ce0..000000000000
--- a/drivers/net/dgrs_plx9060.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * PLX 9060 PCI Interface chip
- */
-
-/*
- * PCI configuration registers, same offset on local and PCI sides,
- * but on PCI side, must use PCI BIOS calls to read/write.
- */
-#define PCI_PLXREGS_BASE_ADDR 0x10
-
-#define PCI_PLXREGS_IO_ADDR 0x14
-
-#define PCI_SPACE0_BASE_ADDR 0x18
-
-#define PCI_ROM_BASE_ADDR 0x30
-# define PCI_ROM_ENABLED 0x00000001
-
-#define PCI_INT_LINE 0x3C
-
-/*
- * Registers accessible directly from PCI and local side.
- * Offset is from PCI side. Add PLX_LCL_OFFSET for local address.
- */
-#define PLX_LCL_OFFSET 0x80 /* Offset of regs from local side */
-
-/*
- * Local Configuration Registers
- */
-#define PLX_SPACE0_RANGE 0x00 /* Range for PCI to Lcl Addr Space 0 */
-#define PLX_SPACE0_BASE_ADDR 0x04 /* Lcl Base address remap */
-
-#define PLX_ROM_RANGE 0x10 /* Range for expansion ROM (DMA) */
-#define PLX_ROM_BASE_ADDR 0x14 /* Lcl base address remap for ROM */
-
-#define PLX_BUS_REGION 0x18 /* Bus Region Descriptors */
-
-/*
- * Shared Run Time Registers
- */
-#define PLX_MBOX0 0x40
-#define PLX_MBOX1 0x44
-#define PLX_MBOX2 0x48
-#define PLX_MBOX3 0x4C
-#define PLX_MBOX4 0x50
-#define PLX_MBOX5 0x54
-#define PLX_MBOX6 0x58
-#define PLX_MBOX7 0x5C
-
-#define PLX_PCI2LCL_DOORBELL 0x60
-
-#define PLX_LCL2PCI_DOORBELL 0x64
-
-#define PLX_INT_CSR 0x68 /* Interrupt Control/Status */
-# define PLX_LSERR_ENABLE 0x00000001
-# define PLX_LSERR_PE 0x00000002
-# define PLX_SERR 0x00000004
-# undef PLX_UNUSED /* 0x00000008 */
-# undef PLX_UNUSED /* 0x00000010 */
-# undef PLX_UNUSED /* 0x00000020 */
-# undef PLX_UNUSED /* 0x00000040 */
-# undef PLX_UNUSED /* 0x00000080 */
-# define PLX_PCI_IE 0x00000100
-# define PLX_PCI_DOORBELL_IE 0x00000200
-# define PLX_PCI_ABORT_IE 0x00000400
-# define PLX_PCI_LOCAL_IE 0x00000800
-# define PLX_RETRY_ABORT_ENABLE 0x00001000
-# define PLX_PCI_DOORBELL_INT 0x00002000
-# define PLX_PCI_ABORT_INT 0x00004000
-# define PLX_PCI_LOCAL_INT 0x00008000
-# define PLX_LCL_IE 0x00010000
-# define PLX_LCL_DOORBELL_IE 0x00020000
-# define PLX_LCL_DMA0_IE 0x00040000
-# define PLX_LCL_DMA1_IE 0x00080000
-# define PLX_LCL_DOORBELL_INT 0x00100000
-# define PLX_LCL_DMA0_INT 0x00200000
-# define PLX_LCL_DMA1_INT 0x00400000
-# define PLX_LCL_BIST_INT 0x00800000
-# define PLX_BM_DIRECT_ 0x01000000
-# define PLX_BM_DMA0_ 0x02000000
-# define PLX_BM_DMA1_ 0x04000000
-# define PLX_BM_ABORT_ 0x08000000
-# undef PLX_UNUSED /* 0x10000000 */
-# undef PLX_UNUSED /* 0x20000000 */
-# undef PLX_UNUSED /* 0x40000000 */
-# undef PLX_UNUSED /* 0x80000000 */
-
-#define PLX_MISC_CSR 0x6c /* EEPROM,PCI,User,Init Control/Status*/
-# define PLX_USEROUT 0x00010000
-# define PLX_USERIN 0x00020000
-# define PLX_EECK 0x01000000
-# define PLX_EECS 0x02000000
-# define PLX_EEWD 0x04000000
-# define PLX_EERD 0x08000000
-
-/*
- * DMA registers. Offset is from local side
- */
-#define PLX_DMA0_MODE 0x100
-# define PLX_DMA_MODE_WIDTH32 0x00000003
-# define PLX_DMA_MODE_WAITSTATES(X) ((X)<<2)
-# define PLX_DMA_MODE_NOREADY 0x00000000
-# define PLX_DMA_MODE_READY 0x00000040
-# define PLX_DMA_MODE_NOBTERM 0x00000000
-# define PLX_DMA_MODE_BTERM 0x00000080
-# define PLX_DMA_MODE_NOBURST 0x00000000
-# define PLX_DMA_MODE_BURST 0x00000100
-# define PLX_DMA_MODE_NOCHAIN 0x00000000
-# define PLX_DMA_MODE_CHAIN 0x00000200
-# define PLX_DMA_MODE_DONE_IE 0x00000400
-# define PLX_DMA_MODE_ADDR_HOLD 0x00000800
-
-#define PLX_DMA0_PCI_ADDR 0x104
- /* non-chaining mode PCI address */
-
-#define PLX_DMA0_LCL_ADDR 0x108
- /* non-chaining mode local address */
-
-#define PLX_DMA0_SIZE 0x10C
- /* non-chaining mode length */
-
-#define PLX_DMA0_DESCRIPTOR 0x110
-# define PLX_DMA_DESC_EOC 0x00000002
-# define PLX_DMA_DESC_TC_IE 0x00000004
-# define PLX_DMA_DESC_TO_HOST 0x00000008
-# define PLX_DMA_DESC_TO_BOARD 0x00000000
-# define PLX_DMA_DESC_NEXTADDR 0xFFFFfff0
-
-#define PLX_DMA1_MODE 0x114
-#define PLX_DMA1_PCI_ADDR 0x118
-#define PLX_DMA1_LCL_ADDR 0x11C
-#define PLX_DMA1_SIZE 0x110
-#define PLX_DMA1_DESCRIPTOR 0x124
-
-#define PLX_DMA_CSR 0x128
-# define PLX_DMA_CSR_0_ENABLE 0x00000001
-# define PLX_DMA_CSR_0_START 0x00000002
-# define PLX_DMA_CSR_0_ABORT 0x00000004
-# define PLX_DMA_CSR_0_CLR_INTR 0x00000008
-# define PLX_DMA_CSR_0_DONE 0x00000010
-# define PLX_DMA_CSR_1_ENABLE 0x00000100
-# define PLX_DMA_CSR_1_START 0x00000200
-# define PLX_DMA_CSR_1_ABORT 0x00000400
-# define PLX_DMA_CSR_1_CLR_INTR 0x00000800
-# define PLX_DMA_CSR_1_DONE 0x00001000
-
-#define PLX_DMA_ARB0 0x12C
-# define PLX_DMA_ARB0_LATENCY_T 0x000000FF
-# define PLX_DMA_ARB0_PAUSE_T 0x0000FF00
-# define PLX_DMA_ARB0_LATENCY_EN 0x00010000
-# define PLX_DMA_ARB0_PAUSE_EN 0x00020000
-# define PLX_DMA_ARB0_BREQ_EN 0x00040000
-# define PLX_DMA_ARB0_PRI 0x00180000
-# define PLX_DMA_ARB0_PRI_ROUND 0x00000000
-# define PLX_DMA_ARB0_PRI_0 0x00080000
-# define PLX_DMA_ARB0_PRI_1 0x00100000
-
-#define PLX_DMA_ARB1 0x130
- /* Chan 0: FIFO DEPTH=16 */
-# define PLX_DMA_ARB1_0_P2L_LW_TRIG(X) ( ((X)&15) << 0 )
-# define PLX_DMA_ARB1_0_L2P_LR_TRIG(X) ( ((X)&15) << 4 )
-# define PLX_DMA_ARB1_0_L2P_PW_TRIG(X) ( ((X)&15) << 8 )
-# define PLX_DMA_ARB1_0_P2L_PR_TRIG(X) ( ((X)&15) << 12 )
- /* Chan 1: FIFO DEPTH=8 */
-# define PLX_DMA_ARB1_1_P2L_LW_TRIG(X) ( ((X)& 7) << 16 )
-# define PLX_DMA_ARB1_1_L2P_LR_TRIG(X) ( ((X)& 7) << 20 )
-# define PLX_DMA_ARB1_1_L2P_PW_TRIG(X) ( ((X)& 7) << 24 )
-# define PLX_DMA_ARB1_1_P2L_PR_TRIG(X) ( ((X)& 7) << 28 )
-
-typedef struct _dmachain
-{
- ulong pciaddr;
- ulong lcladdr;
- ulong len;
- ulong next;
-} DMACHAIN;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 04e3710c9082..5066beb2e7bc 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -10,9 +10,9 @@
(at your option) any later version.
*/
-#define DRV_NAME "D-Link DL2000-based linux driver"
-#define DRV_VERSION "v1.18"
-#define DRV_RELDATE "2006/06/27"
+#define DRV_NAME "DL2000/TC902x-based linux driver"
+#define DRV_VERSION "v1.19"
+#define DRV_RELDATE "2007/08/12"
#include "dl2k.h"
#include <linux/dma-mapping.h>
@@ -97,6 +97,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
static int version_printed;
void *ring_space;
dma_addr_t ring_dma;
+ DECLARE_MAC_BUF(mac);
if (!version_printed++)
printk ("%s", version);
@@ -116,7 +117,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto err_out_res;
}
- SET_MODULE_OWNER (dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#ifdef MEM_MAPPING
@@ -257,10 +257,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
card_idx++;
- printk (KERN_INFO "%s: %s, %02x:%02x:%02x:%02x:%02x:%02x, IRQ %d\n",
- dev->name, np->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], irq);
+ printk (KERN_INFO "%s: %s, %s, IRQ %d\n",
+ dev->name, np->name, print_mac(mac, dev->dev_addr), irq);
if (tx_coalesce > 1)
printk(KERN_INFO "tx_coalesce:\t%d packets\n",
tx_coalesce);
@@ -292,7 +290,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
return err;
}
-int
+static int
find_miiphy (struct net_device *dev)
{
int i, phy_found = 0;
@@ -316,7 +314,7 @@ find_miiphy (struct net_device *dev)
return 0;
}
-int
+static int
parse_eeprom (struct net_device *dev)
{
int i, j;
@@ -339,17 +337,24 @@ parse_eeprom (struct net_device *dev)
#ifdef MEM_MAPPING
ioaddr = dev->base_addr;
#endif
- /* Check CRC */
- crc = ~ether_crc_le (256 - 4, sromdata);
- if (psrom->crc != crc) {
- printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
- return -1;
+ if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) { /* D-Link Only */
+ /* Check CRC */
+ crc = ~ether_crc_le (256 - 4, sromdata);
+ if (psrom->crc != crc) {
+ printk (KERN_ERR "%s: EEPROM data CRC error.\n",
+ dev->name);
+ return -1;
+ }
}
/* Set MAC address */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = psrom->mac_addr[i];
+ if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
+ return 0;
+ }
+
/* Parse Software Information Block */
i = 0x30;
psib = (u8 *) sromdata;
@@ -1091,7 +1096,7 @@ clear_stats (struct net_device *dev)
}
-int
+static int
change_mtu (struct net_device *dev, int new_mtu)
{
struct netdev_private *np = netdev_priv(dev);
@@ -1326,7 +1331,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
#define EEP_BUSY 0x8000
/* Read the EEPROM word */
/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
-int
+static int
read_eeprom (long ioaddr, int eep_addr)
{
int i = 1000;
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index e443065a452e..5b801775f42d 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -692,6 +692,7 @@ struct netdev_private {
static const struct pci_device_id rio_pci_tbl[] = {
{0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+ {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
{ }
};
MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index c3de81bf090a..27ac010900ab 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -148,7 +148,6 @@ typedef struct board_info {
struct resource *irq_res;
struct timer_list timer;
- struct net_device_stats stats;
unsigned char srom[128];
spinlock_t lock;
@@ -166,8 +165,6 @@ static int dm9000_stop(struct net_device *);
static void dm9000_timer(unsigned long);
static void dm9000_init_dm9000(struct net_device *);
-static struct net_device_stats *dm9000_get_stats(struct net_device *);
-
static irqreturn_t dm9000_interrupt(int, void *);
static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
@@ -416,7 +413,6 @@ dm9000_probe(struct platform_device *pdev)
return -ENOMEM;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
PRINTK2("dm9000_probe()");
@@ -559,7 +555,6 @@ dm9000_probe(struct platform_device *pdev)
ndev->tx_timeout = &dm9000_timeout;
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
ndev->stop = &dm9000_stop;
- ndev->get_stats = &dm9000_get_stats;
ndev->set_multicast_list = &dm9000_hash_table;
#ifdef CONFIG_NET_POLL_CONTROLLER
ndev->poll_controller = &dm9000_poll_controller;
@@ -600,11 +595,10 @@ dm9000_probe(struct platform_device *pdev)
ret = register_netdev(ndev);
if (ret == 0) {
- printk("%s: dm9000 at %p,%p IRQ %d MAC: ",
- ndev->name, db->io_addr, db->io_data, ndev->irq);
- for (i = 0; i < 5; i++)
- printk("%02x:", ndev->dev_addr[i]);
- printk("%02x\n", ndev->dev_addr[5]);
+ DECLARE_MAC_BUF(mac);
+ printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n",
+ ndev->name, db->io_addr, db->io_data, ndev->irq,
+ print_mac(mac, ndev->dev_addr));
}
return 0;
@@ -700,6 +694,7 @@ dm9000_init_dm9000(struct net_device *dev)
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ unsigned long flags;
board_info_t *db = (board_info_t *) dev->priv;
PRINTK3("dm9000_start_xmit\n");
@@ -707,23 +702,17 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (db->tx_pkt_cnt > 1)
return 1;
- netif_stop_queue(dev);
-
- /* Disable all interrupts */
- iow(db, DM9000_IMR, IMR_PAR);
+ spin_lock_irqsave(&db->lock, flags);
/* Move data to DM9000 TX RAM */
writeb(DM9000_MWCMD, db->io_addr);
(db->outblk)(db->io_data, skb->data, skb->len);
- db->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
+ db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
- if (db->tx_pkt_cnt == 0) {
-
- /* First Packet */
- db->tx_pkt_cnt++;
-
+ if (db->tx_pkt_cnt == 1) {
/* Set TX length to DM9000 */
iow(db, DM9000_TXPLL, skb->len & 0xff);
iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
@@ -732,23 +721,17 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
dev->trans_start = jiffies; /* save the time stamp */
-
} else {
/* Second packet */
- db->tx_pkt_cnt++;
db->queue_pkt_len = skb->len;
+ netif_stop_queue(dev);
}
+ spin_unlock_irqrestore(&db->lock, flags);
+
/* free this SKB */
dev_kfree_skb(skb);
- /* Re-enable resource check */
- if (db->tx_pkt_cnt == 1)
- netif_wake_queue(dev);
-
- /* Re-enable interrupt */
- iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
-
return 0;
}
@@ -802,7 +785,7 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db)
if (tx_status & (NSR_TX2END | NSR_TX1END)) {
/* One packet sent complete */
db->tx_pkt_cnt--;
- db->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Queue packet check & send */
if (db->tx_pkt_cnt > 0) {
@@ -864,17 +847,6 @@ dm9000_interrupt(int irq, void *dev_id)
}
/*
- * Get statistics from driver.
- */
-static struct net_device_stats *
-dm9000_get_stats(struct net_device *dev)
-{
- board_info_t *db = (board_info_t *) dev->priv;
- return &db->stats;
-}
-
-
-/*
* A periodic timer routine
* Dynamic media sense, allocated Rx buffer...
*/
@@ -951,15 +923,15 @@ dm9000_rx(struct net_device *dev)
GoodPacket = false;
if (rxhdr.RxStatus & 0x100) {
PRINTK1("fifo error\n");
- db->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
if (rxhdr.RxStatus & 0x200) {
PRINTK1("crc error\n");
- db->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
if (rxhdr.RxStatus & 0x8000) {
PRINTK1("length error\n");
- db->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
}
@@ -972,12 +944,12 @@ dm9000_rx(struct net_device *dev)
/* Read received packet from RX SRAM */
(db->inblk)(db->io_data, rdptr, RxLen);
- db->stats.rx_bytes += RxLen;
+ dev->stats.rx_bytes += RxLen;
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- db->stats.rx_packets++;
+ dev->stats.rx_packets++;
} else {
/* need to dump the packet's data */
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 756a6bcb038d..84e14f397d9a 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -71,7 +71,6 @@ static void dummy_setup(struct net_device *dev)
dev->change_mtu = NULL;
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
- SET_MODULE_OWNER(dev);
random_ether_addr(dev->dev_addr);
}
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 6b6401e9304e..64f35e20fd48 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -539,6 +539,7 @@ struct nic {
struct csr __iomem *csr;
enum scb_cmd_lo cuc_cmd;
unsigned int cbs_avail;
+ struct napi_struct napi;
struct cb *cbs;
struct cb *cb_to_use;
struct cb *cb_to_send;
@@ -557,7 +558,6 @@ struct nic {
enum mac mac;
enum phy phy;
struct params params;
- struct net_device_stats net_stats;
struct timer_list watchdog;
struct timer_list blink_timer;
struct mii_if_info mii;
@@ -1482,7 +1482,8 @@ static void e100_set_multicast_list(struct net_device *netdev)
static void e100_update_stats(struct nic *nic)
{
- struct net_device_stats *ns = &nic->net_stats;
+ struct net_device *dev = nic->netdev;
+ struct net_device_stats *ns = &dev->stats;
struct stats *s = &nic->mem->stats;
u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :
@@ -1604,7 +1605,8 @@ static void e100_watchdog(unsigned long data)
else
nic->flags &= ~ich_10h_workaround;
- mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
+ mod_timer(&nic->watchdog,
+ round_jiffies(jiffies + E100_WATCHDOG_PERIOD));
}
static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
@@ -1659,6 +1661,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static int e100_tx_clean(struct nic *nic)
{
+ struct net_device *dev = nic->netdev;
struct cb *cb;
int tx_cleaned = 0;
@@ -1673,8 +1676,8 @@ static int e100_tx_clean(struct nic *nic)
cb->status);
if(likely(cb->skb != NULL)) {
- nic->net_stats.tx_packets++;
- nic->net_stats.tx_bytes += cb->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += cb->skb->len;
pci_unmap_single(nic->pdev,
le32_to_cpu(cb->u.tcb.tbd.buf_addr),
@@ -1805,6 +1808,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
static int e100_rx_indicate(struct nic *nic, struct rx *rx,
unsigned int *work_done, unsigned int work_to_do)
{
+ struct net_device *dev = nic->netdev;
struct sk_buff *skb = rx->skb;
struct rfd *rfd = (struct rfd *)skb->data;
u16 rfd_status, actual_size;
@@ -1849,8 +1853,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
nic->rx_over_length_errors++;
dev_kfree_skb_any(skb);
} else {
- nic->net_stats.rx_packets++;
- nic->net_stats.rx_bytes += actual_size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += actual_size;
nic->netdev->last_rx = jiffies;
netif_receive_skb(skb);
if(work_done)
@@ -1974,35 +1978,31 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
if(stat_ack & stat_ack_rnr)
nic->ru_running = RU_SUSPENDED;
- if(likely(netif_rx_schedule_prep(netdev))) {
+ if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) {
e100_disable_irq(nic);
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &nic->napi);
}
return IRQ_HANDLED;
}
-static int e100_poll(struct net_device *netdev, int *budget)
+static int e100_poll(struct napi_struct *napi, int budget)
{
- struct nic *nic = netdev_priv(netdev);
- unsigned int work_to_do = min(netdev->quota, *budget);
+ struct nic *nic = container_of(napi, struct nic, napi);
+ struct net_device *netdev = nic->netdev;
unsigned int work_done = 0;
int tx_cleaned;
- e100_rx_clean(nic, &work_done, work_to_do);
+ e100_rx_clean(nic, &work_done, budget);
tx_cleaned = e100_tx_clean(nic);
/* If no Rx and Tx cleanup work was done, exit polling mode. */
if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
e100_enable_irq(nic);
- return 0;
}
- *budget -= work_done;
- netdev->quota -= work_done;
-
- return 1;
+ return work_done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2017,12 +2017,6 @@ static void e100_netpoll(struct net_device *netdev)
}
#endif
-static struct net_device_stats *e100_get_stats(struct net_device *netdev)
-{
- struct nic *nic = netdev_priv(netdev);
- return &nic->net_stats;
-}
-
static int e100_set_mac_address(struct net_device *netdev, void *p)
{
struct nic *nic = netdev_priv(netdev);
@@ -2071,7 +2065,7 @@ static int e100_up(struct nic *nic)
nic->netdev->name, nic->netdev)))
goto err_no_irq;
netif_wake_queue(nic->netdev);
- netif_poll_enable(nic->netdev);
+ napi_enable(&nic->napi);
/* enable ints _after_ enabling poll, preventing a race between
* disable ints+schedule */
e100_enable_irq(nic);
@@ -2089,7 +2083,7 @@ err_rx_clean_list:
static void e100_down(struct nic *nic)
{
/* wait here for poll to complete */
- netif_poll_disable(nic->netdev);
+ napi_disable(&nic->napi);
netif_stop_queue(nic->netdev);
e100_hw_reset(nic);
free_irq(nic->pdev->irq, nic->netdev);
@@ -2380,11 +2374,6 @@ static const char e100_gstrings_test[][ETH_GSTRING_LEN] = {
};
#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN
-static int e100_diag_test_count(struct net_device *netdev)
-{
- return E100_TEST_LEN;
-}
-
static void e100_diag_test(struct net_device *netdev,
struct ethtool_test *test, u64 *data)
{
@@ -2447,9 +2436,16 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
#define E100_NET_STATS_LEN 21
#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
-static int e100_get_stats_count(struct net_device *netdev)
+static int e100_get_sset_count(struct net_device *netdev, int sset)
{
- return E100_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return E100_TEST_LEN;
+ case ETH_SS_STATS:
+ return E100_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void e100_get_ethtool_stats(struct net_device *netdev,
@@ -2459,7 +2455,7 @@ static void e100_get_ethtool_stats(struct net_device *netdev,
int i;
for(i = 0; i < E100_NET_STATS_LEN; i++)
- data[i] = ((unsigned long *)&nic->net_stats)[i];
+ data[i] = ((unsigned long *)&netdev->stats)[i];
data[i++] = nic->tx_deferred;
data[i++] = nic->tx_single_collisions;
@@ -2500,13 +2496,11 @@ static const struct ethtool_ops e100_ethtool_ops = {
.set_eeprom = e100_set_eeprom,
.get_ringparam = e100_get_ringparam,
.set_ringparam = e100_set_ringparam,
- .self_test_count = e100_diag_test_count,
.self_test = e100_diag_test,
.get_strings = e100_get_strings,
.phys_id = e100_phys_id,
- .get_stats_count = e100_get_stats_count,
.get_ethtool_stats = e100_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_sset_count = e100_get_sset_count,
};
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
@@ -2555,6 +2549,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct nic *nic;
int err;
+ DECLARE_MAC_BUF(mac);
if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
if(((1 << debug) - 1) & NETIF_MSG_PROBE)
@@ -2565,7 +2560,6 @@ static int __devinit e100_probe(struct pci_dev *pdev,
netdev->open = e100_open;
netdev->stop = e100_close;
netdev->hard_start_xmit = e100_xmit_frame;
- netdev->get_stats = e100_get_stats;
netdev->set_multicast_list = e100_set_multicast_list;
netdev->set_mac_address = e100_set_mac_address;
netdev->change_mtu = e100_change_mtu;
@@ -2573,14 +2567,13 @@ static int __devinit e100_probe(struct pci_dev *pdev,
SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
netdev->tx_timeout = e100_tx_timeout;
netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
- netdev->poll = e100_poll;
- netdev->weight = E100_NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = e100_netpoll;
#endif
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
nic = netdev_priv(netdev);
+ netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT);
nic->netdev = netdev;
nic->pdev = pdev;
nic->msg_enable = (1 << debug) - 1;
@@ -2608,7 +2601,6 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_free_res;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
if (use_io)
@@ -2689,11 +2681,9 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_free;
}
- DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
- "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
- (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
- netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
- netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+ DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n",
+ (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
+ pdev->irq, print_mac(mac, netdev->dev_addr));
return 0;
@@ -2734,7 +2724,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
struct nic *nic = netdev_priv(netdev);
if (netif_running(netdev))
- netif_poll_disable(nic->netdev);
+ napi_disable(&nic->napi);
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
netif_device_detach(netdev);
@@ -2780,7 +2770,7 @@ static void e100_shutdown(struct pci_dev *pdev)
struct nic *nic = netdev_priv(netdev);
if (netif_running(netdev))
- netif_poll_disable(nic->netdev);
+ napi_disable(&nic->napi);
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
@@ -2805,12 +2795,13 @@ static void e100_shutdown(struct pci_dev *pdev)
static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
/* Similar to calling e100_down(), but avoids adpater I/O. */
netdev->stop(netdev);
/* Detach; put netif into state similar to hotplug unplug. */
- netif_poll_enable(netdev);
+ napi_enable(&nic->napi);
netif_device_detach(netdev);
pci_disable_device(pdev);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 16a6edfeba41..781ed9968489 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -300,6 +300,7 @@ struct e1000_adapter {
int cleaned_count);
struct e1000_rx_ring *rx_ring; /* One per active queue */
#ifdef CONFIG_E1000_NAPI
+ struct napi_struct napi;
struct net_device *polling_netdev; /* One per active queue */
#endif
int num_tx_queues;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index bb08375b5f13..6c9a643426f5 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -106,8 +106,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
};
#define E1000_QUEUE_STATS_LEN 0
-#define E1000_GLOBAL_STATS_LEN \
- sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN)
static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
"Register test (offline)", "Eeprom test (offline)",
@@ -619,8 +618,6 @@ e1000_get_drvinfo(struct net_device *netdev,
strncpy(drvinfo->fw_version, firmware_version, 32);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
- drvinfo->n_stats = E1000_STATS_LEN;
- drvinfo->testinfo_len = E1000_TEST_LEN;
drvinfo->regdump_len = e1000_get_regs_len(netdev);
drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
}
@@ -1612,9 +1609,16 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
}
static int
-e1000_diag_test_count(struct net_device *netdev)
+e1000_get_sset_count(struct net_device *netdev, int sset)
{
- return E1000_TEST_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return E1000_TEST_LEN;
+ case ETH_SS_STATS:
+ return E1000_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
extern void e1000_power_up_phy(struct e1000_adapter *);
@@ -1706,6 +1710,7 @@ static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wol
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546GB_QUAD_COPPER:
case E1000_DEV_ID_82546GB_PCIE:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
/* these don't support WoL at all */
wol->supported = 0;
break;
@@ -1723,7 +1728,9 @@ static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wol
retval = 0;
break;
case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
/* quad port adapters only support WoL on port A */
if (!adapter->quad_port_a) {
@@ -1896,12 +1903,6 @@ e1000_nway_reset(struct net_device *netdev)
return 0;
}
-static int
-e1000_get_stats_count(struct net_device *netdev)
-{
- return E1000_STATS_LEN;
-}
-
static void
e1000_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
@@ -1963,17 +1964,13 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_rx_csum = e1000_set_rx_csum,
.get_tx_csum = e1000_get_tx_csum,
.set_tx_csum = e1000_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = e1000_set_tso,
- .self_test_count = e1000_diag_test_count,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
.phys_id = e1000_phys_id,
- .get_stats_count = e1000_get_stats_count,
.get_ethtool_stats = e1000_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_sset_count = e1000_get_sset_count,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 9be44699300b..8fa0fe4009d5 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -384,7 +384,11 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82571EB_COPPER:
case E1000_DEV_ID_82571EB_FIBER:
case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES_DUAL:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
hw->mac_type = e1000_82571;
break;
@@ -485,6 +489,8 @@ e1000_set_media_type(struct e1000_hw *hw)
case E1000_DEV_ID_82545GM_SERDES:
case E1000_DEV_ID_82546GB_SERDES:
case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES_DUAL:
+ case E1000_DEV_ID_82571EB_SERDES_QUAD:
case E1000_DEV_ID_82572EI_SERDES:
case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
hw->media_type = e1000_media_type_internal_serdes;
@@ -865,10 +871,6 @@ e1000_init_hw(struct e1000_hw *hw)
uint32_t ctrl;
uint32_t i;
int32_t ret_val;
- uint16_t pcix_cmd_word;
- uint16_t pcix_stat_hi_word;
- uint16_t cmd_mmrbc;
- uint16_t stat_mmrbc;
uint32_t mta_size;
uint32_t reg_data;
uint32_t ctrl_ext;
@@ -958,24 +960,9 @@ e1000_init_hw(struct e1000_hw *hw)
break;
default:
/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
- if (hw->bus_type == e1000_bus_type_pcix) {
- e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
- e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
- &pcix_stat_hi_word);
- cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
- PCIX_COMMAND_MMRBC_SHIFT;
- stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
- PCIX_STATUS_HI_MMRBC_SHIFT;
- if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
- stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
- if (cmd_mmrbc > stat_mmrbc) {
- pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
- pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
- e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
- &pcix_cmd_word);
- }
- }
- break;
+ if (hw->bus_type == e1000_bus_type_pcix && e1000_pcix_get_mmrbc(hw) > 2048)
+ e1000_pcix_set_mmrbc(hw, 2048);
+ break;
}
/* More time needed for PHY to initialize */
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index bd000b802ee7..a2a86c54a75c 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -424,6 +424,8 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw);
void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value);
+void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc);
+int e1000_pcix_get_mmrbc(struct e1000_hw *hw);
/* Port I/O is only supported on 82544 and newer */
void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value);
int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
@@ -475,7 +477,11 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
#define E1000_DEV_ID_82571EB_FIBER 0x105F
#define E1000_DEV_ID_82571EB_SERDES 0x1060
#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
#define E1000_DEV_ID_82572EI_COPPER 0x107D
#define E1000_DEV_ID_82572EI_FIBER 0x107E
#define E1000_DEV_ID_82572EI_SERDES 0x107F
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index f48b659e0c2b..047263830e6a 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -100,6 +100,7 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x1099),
INTEL_E1000_ETHERNET_DEVICE(0x109A),
INTEL_E1000_ETHERNET_DEVICE(0x10A4),
+ INTEL_E1000_ETHERNET_DEVICE(0x10A5),
INTEL_E1000_ETHERNET_DEVICE(0x10B5),
INTEL_E1000_ETHERNET_DEVICE(0x10B9),
INTEL_E1000_ETHERNET_DEVICE(0x10BA),
@@ -107,6 +108,9 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x10BC),
INTEL_E1000_ETHERNET_DEVICE(0x10C4),
INTEL_E1000_ETHERNET_DEVICE(0x10C5),
+ INTEL_E1000_ETHERNET_DEVICE(0x10D5),
+ INTEL_E1000_ETHERNET_DEVICE(0x10D9),
+ INTEL_E1000_ETHERNET_DEVICE(0x10DA),
/* required last entry */
{0,}
};
@@ -162,7 +166,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data);
static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
struct e1000_tx_ring *tx_ring);
#ifdef CONFIG_E1000_NAPI
-static int e1000_clean(struct net_device *poll_dev, int *budget);
+static int e1000_clean(struct napi_struct *napi, int budget);
static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
@@ -541,7 +545,7 @@ int e1000_up(struct e1000_adapter *adapter)
clear_bit(__E1000_DOWN, &adapter->flags);
#ifdef CONFIG_E1000_NAPI
- netif_poll_enable(adapter->netdev);
+ napi_enable(&adapter->napi);
#endif
e1000_irq_enable(adapter);
@@ -630,7 +634,7 @@ e1000_down(struct e1000_adapter *adapter)
set_bit(__E1000_DOWN, &adapter->flags);
#ifdef CONFIG_E1000_NAPI
- netif_poll_disable(netdev);
+ napi_disable(&adapter->napi);
#endif
e1000_irq_disable(adapter);
@@ -868,6 +872,8 @@ e1000_probe(struct pci_dev *pdev,
int i, err, pci_using_dac;
uint16_t eeprom_data = 0;
uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
+ DECLARE_MAC_BUF(mac);
+
if ((err = pci_enable_device(pdev)))
return err;
@@ -893,7 +899,6 @@ e1000_probe(struct pci_dev *pdev,
if (!netdev)
goto err_alloc_etherdev;
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
@@ -932,8 +937,7 @@ e1000_probe(struct pci_dev *pdev,
netdev->tx_timeout = &e1000_tx_timeout;
netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_E1000_NAPI
- netdev->poll = &e1000_clean;
- netdev->weight = 64;
+ netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
#endif
netdev->vlan_rx_register = e1000_vlan_rx_register;
netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
@@ -1096,7 +1100,9 @@ e1000_probe(struct pci_dev *pdev,
break;
case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+ case E1000_DEV_ID_82571PT_QUAD_COPPER:
/* if quad port adapter, disable WoL on all but port A */
if (global_quad_port_a != 0)
adapter->eeprom_wol = 0;
@@ -1128,8 +1134,7 @@ e1000_probe(struct pci_dev *pdev,
"32-bit"));
}
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", netdev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk("%s\n", print_mac(mac, netdev->dev_addr));
/* reset the hardware with the new settings */
e1000_reset(adapter);
@@ -1145,9 +1150,6 @@ e1000_probe(struct pci_dev *pdev,
/* tell the stack to leave us alone until e1000_open() is called */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
-#ifdef CONFIG_E1000_NAPI
- netif_poll_disable(netdev);
-#endif
strcpy(netdev->name, "eth%d");
if ((err = register_netdev(netdev)))
@@ -1216,12 +1218,13 @@ e1000_remove(struct pci_dev *pdev)
* would have already happened in close and is redundant. */
e1000_release_hw_control(adapter);
- unregister_netdev(netdev);
#ifdef CONFIG_E1000_NAPI
for (i = 0; i < adapter->num_rx_queues; i++)
dev_put(&adapter->polling_netdev[i]);
#endif
+ unregister_netdev(netdev);
+
if (!e1000_check_phy_reset_block(&adapter->hw))
e1000_phy_hw_reset(&adapter->hw);
@@ -1319,8 +1322,6 @@ e1000_sw_init(struct e1000_adapter *adapter)
#ifdef CONFIG_E1000_NAPI
for (i = 0; i < adapter->num_rx_queues; i++) {
adapter->polling_netdev[i].priv = adapter;
- adapter->polling_netdev[i].poll = &e1000_clean;
- adapter->polling_netdev[i].weight = 64;
dev_hold(&adapter->polling_netdev[i]);
set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
}
@@ -1437,7 +1438,7 @@ e1000_open(struct net_device *netdev)
clear_bit(__E1000_DOWN, &adapter->flags);
#ifdef CONFIG_E1000_NAPI
- netif_poll_enable(netdev);
+ napi_enable(&adapter->napi);
#endif
e1000_irq_enable(adapter);
@@ -3260,14 +3261,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
unsigned int tx_flags = 0;
- unsigned int len = skb->len;
+ unsigned int len = skb->len - skb->data_len;
unsigned long flags;
- unsigned int nr_frags = 0;
- unsigned int mss = 0;
+ unsigned int nr_frags;
+ unsigned int mss;
int count = 0;
int tso;
unsigned int f;
- len -= skb->data_len;
/* This goes back to the question of how to logically map a tx queue
* to a flow. Right now, performance is impacted slightly negatively
@@ -3301,7 +3301,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
* points to just header, pull a few bytes of payload from
* frags into skb->data */
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) {
+ if (skb->data_len && hdr_len == len) {
switch (adapter->hw.mac_type) {
unsigned int pull_size;
case e1000_82544:
@@ -3780,12 +3780,12 @@ e1000_intr_msi(int irq, void *data)
}
#ifdef CONFIG_E1000_NAPI
- if (likely(netif_rx_schedule_prep(netdev))) {
+ if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
} else
e1000_irq_enable(adapter);
#else
@@ -3865,12 +3865,12 @@ e1000_intr(int irq, void *data)
E1000_WRITE_REG(hw, IMC, ~0);
E1000_WRITE_FLUSH(hw);
}
- if (likely(netif_rx_schedule_prep(netdev))) {
+ if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
} else
/* this really should not happen! if it does it is basically a
* bug, but not a hard error, so enable ints and continue */
@@ -3918,10 +3918,10 @@ e1000_intr(int irq, void *data)
**/
static int
-e1000_clean(struct net_device *poll_dev, int *budget)
+e1000_clean(struct napi_struct *napi, int budget)
{
- struct e1000_adapter *adapter;
- int work_to_do = min(*budget, poll_dev->quota);
+ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+ struct net_device *poll_dev = adapter->netdev;
int tx_cleaned = 0, work_done = 0;
/* Must NOT use netdev_priv macro here. */
@@ -3942,23 +3942,19 @@ e1000_clean(struct net_device *poll_dev, int *budget)
}
adapter->clean_rx(adapter, &adapter->rx_ring[0],
- &work_done, work_to_do);
-
- *budget -= work_done;
- poll_dev->quota -= work_done;
+ &work_done, budget);
/* If no Tx and not enough Rx work done, exit the polling mode */
- if ((!tx_cleaned && (work_done == 0)) ||
+ if ((!tx_cleaned && (work_done < budget)) ||
!netif_running(poll_dev)) {
quit_polling:
if (likely(adapter->itr_setting & 3))
e1000_set_itr(adapter);
- netif_rx_complete(poll_dev);
+ netif_rx_complete(poll_dev, napi);
e1000_irq_enable(adapter);
- return 0;
}
- return 1;
+ return work_done;
}
#endif
@@ -4906,6 +4902,20 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
pci_write_config_word(adapter->pdev, reg, *value);
}
+int
+e1000_pcix_get_mmrbc(struct e1000_hw *hw)
+{
+ struct e1000_adapter *adapter = hw->back;
+ return pcix_get_mmrbc(adapter->pdev);
+}
+
+void
+e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc)
+{
+ struct e1000_adapter *adapter = hw->back;
+ pcix_set_mmrbc(adapter->pdev, mmrbc);
+}
+
int32_t
e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
{
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
new file mode 100644
index 000000000000..cf70522fc851
--- /dev/null
+++ b/drivers/net/e1000e/82571.c
@@ -0,0 +1,1351 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller (Copper)
+ * 82572EI Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller
+ * 82573V Gigabit Ethernet Controller (Copper)
+ * 82573E Gigabit Ethernet Controller (Copper)
+ * 82573L Gigabit Ethernet Controller
+ */
+
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data);
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
+static s32 e1000_setup_link_82571(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+
+/**
+ * e1000_init_phy_params_82571 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+
+ if (hw->media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ return 0;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ phy->type = e1000_phy_igp_2;
+ break;
+ case e1000_82573:
+ phy->type = e1000_phy_m88;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ /* This can only be done after all function pointers are setup. */
+ ret_val = e1000_get_phy_id_82571(hw);
+
+ /* Verify phy id */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ if (phy->id != IGP01E1000_I_PHY_ID)
+ return -E1000_ERR_PHY;
+ break;
+ case e1000_82573:
+ if (phy->id != M88E1111_I_PHY_ID)
+ return -E1000_ERR_PHY;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_nvm_params_82571 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u16 size;
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+ if (((eecd >> 15) & 0x3) == 0x3) {
+ nvm->type = e1000_nvm_flash_hw;
+ nvm->word_size = 2048;
+ /* Autonomous Flash update bit must be cleared due
+ * to Flash update issue.
+ */
+ eecd &= ~E1000_EECD_AUPDEN;
+ ew32(EECD, eecd);
+ break;
+ }
+ /* Fall Through */
+ default:
+ nvm->type = e1000_nvm_eeprom_spi;
+ size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ /* Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+ nvm->word_size = 1 << size;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_mac_params_82571 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_mac_operations *func = &mac->ops;
+
+ /* Set media type */
+ switch (adapter->pdev->device) {
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ hw->media_type = e1000_media_type_fiber;
+ break;
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82572EI_SERDES:
+ hw->media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ hw->media_type = e1000_media_type_copper;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+
+ /* check for link */
+ switch (hw->media_type) {
+ case e1000_media_type_copper:
+ func->setup_physical_interface = e1000_setup_copper_link_82571;
+ func->check_for_link = e1000e_check_for_copper_link;
+ func->get_link_up_info = e1000e_get_speed_and_duplex_copper;
+ break;
+ case e1000_media_type_fiber:
+ func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
+ func->check_for_link = e1000e_check_for_fiber_link;
+ func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
+ break;
+ case e1000_media_type_internal_serdes:
+ func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
+ func->check_for_link = e1000e_check_for_serdes_link;
+ func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
+ break;
+ default:
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ return 0;
+}
+
+static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ static int global_quad_port_a; /* global port a indication */
+ struct pci_dev *pdev = adapter->pdev;
+ u16 eeprom_data = 0;
+ int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
+ s32 rc;
+
+ rc = e1000_init_mac_params_82571(adapter);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_nvm_params_82571(hw);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_phy_params_82571(hw);
+ if (rc)
+ return rc;
+
+ /* tag quad port adapters first, it's used below */
+ switch (pdev->device) {
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+ adapter->flags |= FLAG_IS_QUAD_PORT;
+ /* mark the first port */
+ if (global_quad_port_a == 0)
+ adapter->flags |= FLAG_IS_QUAD_PORT_A;
+ /* Reset for multiple quad port adapters */
+ global_quad_port_a++;
+ if (global_quad_port_a == 4)
+ global_quad_port_a = 0;
+ break;
+ default:
+ break;
+ }
+
+ switch (adapter->hw.mac.type) {
+ case e1000_82571:
+ /* these dual ports don't have WoL on port B at all */
+ if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
+ (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
+ (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
+ (is_port_b))
+ adapter->flags &= ~FLAG_HAS_WOL;
+ /* quad ports only support WoL on port A */
+ if (adapter->flags & FLAG_IS_QUAD_PORT &&
+ (!adapter->flags & FLAG_IS_QUAD_PORT_A))
+ adapter->flags &= ~FLAG_HAS_WOL;
+ break;
+
+ case e1000_82573:
+ if (pdev->device == E1000_DEV_ID_82573L) {
+ e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
+ &eeprom_data);
+ if (eeprom_data & NVM_WORD1A_ASPM_MASK)
+ adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* The 82571 firmware may still be configuring the PHY.
+ * In this case, we cannot access the PHY until the
+ * configuration is done. So we explicitly set the
+ * PHY ID. */
+ phy->id = IGP01E1000_I_PHY_ID;
+ break;
+ case e1000_82573:
+ return e1000e_get_phy_id(hw);
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ u32 swsm;
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (er32(SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000e_put_hw_semaphore(hw);
+ hw_dbg(hw, "Driver can't access the NVM\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_put_hw_semaphore_82571 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ u32 swsm;
+
+ swsm = er32(SWSM);
+
+ swsm &= ~E1000_SWSM_SWESMBI;
+
+ ew32(SWSM, swsm);
+}
+
+/**
+ * e1000_acquire_nvm_82571 - Request for access to the EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ * Then for non-82573 hardware, set the EEPROM access request bit and wait
+ * for EEPROM access grant bit. If the access grant bit is not set, release
+ * hardware semaphore.
+ **/
+static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = e1000_get_hw_semaphore_82571(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->mac.type != e1000_82573)
+ ret_val = e1000e_acquire_nvm(hw);
+
+ if (ret_val)
+ e1000_put_hw_semaphore_82571(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_82571 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+static void e1000_release_nvm_82571(struct e1000_hw *hw)
+{
+ e1000e_release_nvm(hw);
+ e1000_put_hw_semaphore_82571(hw);
+}
+
+/**
+ * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ * If e1000e_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likley contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 ret_val;
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+ ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ ret_val = e1000e_write_nvm_spi(hw, offset, words, data);
+ break;
+ default:
+ ret_val = -E1000_ERR_NVM;
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_82571 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ u32 eecd;
+ s32 ret_val;
+ u16 i;
+
+ ret_val = e1000e_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* If our nvm is an EEPROM, then we're done
+ * otherwise, commit the checksum to the flash NVM. */
+ if (hw->nvm.type != e1000_nvm_flash_hw)
+ return ret_val;
+
+ /* Check for pending operations. */
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msleep(1);
+ if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES)
+ return -E1000_ERR_NVM;
+
+ /* Reset the firmware if using STM opcode. */
+ if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+ /* The enabling of and the actual reset must be done
+ * in two write cycles.
+ */
+ ew32(HICR, E1000_HICR_FW_RESET_ENABLE);
+ e1e_flush();
+ ew32(HICR, E1000_HICR_FW_RESET);
+ }
+
+ /* Commit the write to flash */
+ eecd = er32(EECD) | E1000_EECD_FLUPD;
+ ew32(EECD, eecd);
+
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msleep(1);
+ if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES)
+ return -E1000_ERR_NVM;
+
+ return 0;
+}
+
+/**
+ * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ if (hw->nvm.type == e1000_nvm_flash_hw)
+ e1000_fix_nvm_checksum_82571(hw);
+
+ return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * After checking for invalid values, poll the EEPROM to ensure the previous
+ * command has completed before trying to write the next word. After write
+ * poll for completion.
+ *
+ * If e1000e_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likley contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i;
+ u32 eewr = 0;
+ s32 ret_val = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+ ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+ E1000_NVM_RW_REG_START;
+
+ ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+
+ ew32(EEWR, eewr);
+
+ ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_cfg_done_82571 - Poll for configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Reads the management control register for the config done bit to be set.
+ **/
+static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
+{
+ s32 timeout = PHY_CFG_TIMEOUT;
+
+ while (timeout) {
+ if (er32(EEMNGCTL) &
+ E1000_NVM_CFG_DONE_PORT_0)
+ break;
+ msleep(1);
+ timeout--;
+ }
+ if (!timeout) {
+ hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When activating LPLU
+ * this function also disables smart speed and vice versa. LPLU will not be
+ * activated unless the device autonegotiation advertisement meets standards
+ * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function
+ * pointer entry point only called by PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (active) {
+ data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+ if (ret_val)
+ return ret_val;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_reset_hw_82571 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state. This is a
+ * function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ u32 extcnf_ctrl;
+ u32 ctrl_ext;
+ u32 icr;
+ s32 ret_val;
+ u16 i = 0;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000e_disable_pcie_master(hw);
+ if (ret_val)
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+ hw_dbg(hw, "Masking off all interrupts\n");
+ ew32(IMC, 0xffffffff);
+
+ ew32(RCTL, 0);
+ ew32(TCTL, E1000_TCTL_PSP);
+ e1e_flush();
+
+ msleep(10);
+
+ /* Must acquire the MDIO ownership before MAC reset.
+ * Ownership defaults to firmware after a reset. */
+ if (hw->mac.type == e1000_82573) {
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ do {
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ msleep(2);
+ i++;
+ } while (i < MDIO_OWNERSHIP_TIMEOUT);
+ }
+
+ ctrl = er32(CTRL);
+
+ hw_dbg(hw, "Issuing a global reset to MAC\n");
+ ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+ if (hw->nvm.type == e1000_nvm_flash_hw) {
+ udelay(10);
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ ew32(CTRL_EXT, ctrl_ext);
+ e1e_flush();
+ }
+
+ ret_val = e1000e_get_auto_rd_done(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ return ret_val;
+
+ /* Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+ * Need to wait for Phy configuration completion before accessing
+ * NVM and Phy.
+ */
+ if (hw->mac.type == e1000_82573)
+ msleep(25);
+
+ /* Clear any pending interrupt events. */
+ ew32(IMC, 0xffffffff);
+ icr = er32(ICR);
+
+ return 0;
+}
+
+/**
+ * e1000_init_hw_82571 - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 reg_data;
+ s32 ret_val;
+ u16 i;
+ u16 rar_count = mac->rar_entry_count;
+
+ e1000_initialize_hw_bits_82571(hw);
+
+ /* Initialize identification LED */
+ ret_val = e1000e_id_led_init(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error initializing identification LED\n");
+ return ret_val;
+ }
+
+ /* Disabling VLAN filtering */
+ hw_dbg(hw, "Initializing the IEEE VLAN\n");
+ e1000e_clear_vfta(hw);
+
+ /* Setup the receive address. */
+ /* If, however, a locally administered address was assigned to the
+ * 82571, we must reserve a RAR for it to work around an issue where
+ * resetting one port will reload the MAC on the other port.
+ */
+ if (e1000e_get_laa_state_82571(hw))
+ rar_count--;
+ e1000e_init_rx_addrs(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg(hw, "Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = e1000_setup_link_82571(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = er32(TXDCTL);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL, reg_data);
+
+ /* ...for both queues. */
+ if (mac->type != e1000_82573) {
+ reg_data = er32(TXDCTL1);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL1, reg_data);
+ } else {
+ e1000e_enable_tx_pkt_filtering(hw);
+ reg_data = er32(GCR);
+ reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ ew32(GCR, reg_data);
+ }
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_82571(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+ u32 reg;
+
+ /* Transmit Descriptor Control 0 */
+ reg = er32(TXDCTL);
+ reg |= (1 << 22);
+ ew32(TXDCTL, reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = er32(TXDCTL1);
+ reg |= (1 << 22);
+ ew32(TXDCTL1, reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = er32(TARC0);
+ reg &= ~(0xF << 27); /* 30:27 */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+ break;
+ default:
+ break;
+ }
+ ew32(TARC0, reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = er32(TARC1);
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg &= ~((1 << 29) | (1 << 30));
+ reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+ if (er32(TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ ew32(TARC1, reg);
+ break;
+ default:
+ break;
+ }
+
+ /* Device Control */
+ if (hw->mac.type == e1000_82573) {
+ reg = er32(CTRL);
+ reg &= ~(1 << 29);
+ ew32(CTRL, reg);
+ }
+
+ /* Extended Device Control */
+ if (hw->mac.type == e1000_82573) {
+ reg = er32(CTRL_EXT);
+ reg &= ~(1 << 23);
+ reg |= (1 << 22);
+ ew32(CTRL_EXT, reg);
+ }
+}
+
+/**
+ * e1000e_clear_vfta - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+void e1000e_clear_vfta(struct e1000_hw *hw)
+{
+ u32 offset;
+ u32 vfta_value = 0;
+ u32 vfta_offset = 0;
+ u32 vfta_bit_in_reg = 0;
+
+ if (hw->mac.type == e1000_82573) {
+ if (hw->mng_cookie.vlan_id != 0) {
+ /* The VFTA is a 4096b bit-field, each identifying
+ * a single VLAN ID. The following operations
+ * determine which 32b entry (i.e. offset) into the
+ * array we want to set the VLAN ID (i.e. bit) of
+ * the manageability unit.
+ */
+ vfta_offset = (hw->mng_cookie.vlan_id >>
+ E1000_VFTA_ENTRY_SHIFT) &
+ E1000_VFTA_ENTRY_MASK;
+ vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+ E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+ }
+ }
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ /* If the offset we want to clear is the same offset of the
+ * manageability VLAN ID, then clear all bits except that of
+ * the manageability unit.
+ */
+ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
+ e1e_flush();
+ }
+}
+
+/**
+ * e1000_mc_addr_list_update_82571 - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @rar_used_count: the first RAR register free to program
+ * @rar_count: total number of supported Receive Address Registers
+ *
+ * Updates the Receive Address Registers and Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ * The parameter rar_count will usually be hw->mac.rar_entry_count
+ * unless there are workarounds that change this.
+ **/
+static void e1000_mc_addr_list_update_82571(struct e1000_hw *hw,
+ u8 *mc_addr_list,
+ u32 mc_addr_count,
+ u32 rar_used_count,
+ u32 rar_count)
+{
+ if (e1000e_get_laa_state_82571(hw))
+ rar_count--;
+
+ e1000e_mc_addr_list_update_generic(hw, mc_addr_list, mc_addr_count,
+ rar_used_count, rar_count);
+}
+
+/**
+ * e1000_setup_link_82571 - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_82571(struct e1000_hw *hw)
+{
+ /* 82573 does not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ if (hw->mac.type == e1000_82573)
+ hw->mac.fc = e1000_fc_full;
+
+ return e1000e_setup_link(hw);
+}
+
+/**
+ * e1000_setup_copper_link_82571 - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ **/
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ u32 led_ctrl;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+ ret_val = e1000e_copper_link_setup_m88(hw);
+ break;
+ case e1000_phy_igp_2:
+ ret_val = e1000e_copper_link_setup_igp(hw);
+ /* Setup activity LED */
+ led_ctrl = er32(LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ ew32(LEDCTL, led_ctrl);
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000e_setup_copper_link(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes links.
+ * Upon successful setup, poll for link.
+ **/
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* If SerDes loopback mode is entered, there is no form
+ * of reset to take the adapter out of that mode. So we
+ * have to explicitly take the adapter out of loopback
+ * mode. This prevents drivers from twidling their thumbs
+ * if another tool failed to take it out of loopback mode.
+ */
+ ew32(SCTL,
+ E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+ break;
+ default:
+ break;
+ }
+
+ return e1000e_setup_fiber_serdes_link(hw);
+}
+
+/**
+ * e1000_valid_led_default_82571 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (hw->mac.type == e1000_82573 &&
+ *data == ID_LED_RESERVED_F746)
+ *data = ID_LED_DEFAULT_82573;
+ else if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+
+ return 0;
+}
+
+/**
+ * e1000e_get_laa_state_82571 - Get locally administered address state
+ * @hw: pointer to the HW structure
+ *
+ * Retrieve and return the current locally administed address state.
+ **/
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
+{
+ if (hw->mac.type != e1000_82571)
+ return 0;
+
+ return hw->dev_spec.e82571.laa_is_present;
+}
+
+/**
+ * e1000e_set_laa_state_82571 - Set locally administered address state
+ * @hw: pointer to the HW structure
+ * @state: enable/disable locally administered address
+ *
+ * Enable/Disable the current locally administed address state.
+ **/
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
+{
+ if (hw->mac.type != e1000_82571)
+ return;
+
+ hw->dev_spec.e82571.laa_is_present = state;
+
+ /* If workaround is activated... */
+ if (state)
+ /* Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed, the actual LAA is in one of the RARs and no
+ * incoming packets directed to this port are dropped.
+ * Eventually the LAA will be in RAR[0] and RAR[14].
+ */
+ e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1);
+}
+
+/**
+ * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Verifies that the EEPROM has completed the update. After updating the
+ * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If
+ * the checksum fix is not implemented, we need to set the bit and update
+ * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect,
+ * we need to return bad checksum.
+ **/
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ s32 ret_val;
+ u16 data;
+
+ if (nvm->type != e1000_nvm_flash_hw)
+ return 0;
+
+ /* Check bit 4 of word 10h. If it is 0, firmware is done updating
+ * 10h-12h. Checksum may need to be fixed.
+ */
+ ret_val = e1000_read_nvm(hw, 0x10, 1, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(data & 0x10)) {
+ /* Read 0x23 and check bit 15. This bit is a 1
+ * when the checksum has already been fixed. If
+ * the checksum is still wrong and this bit is a
+ * 1, we need to return bad checksum. Otherwise,
+ * we need to set this bit to a 1 and update the
+ * checksum.
+ */
+ ret_val = e1000_read_nvm(hw, 0x23, 1, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(data & 0x8000)) {
+ data |= 0x8000;
+ ret_val = e1000_write_nvm(hw, 0x23, 1, &data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_update_nvm_checksum(hw);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ e1000e_clear_hw_cntrs_base(hw);
+
+ temp = er32(PRC64);
+ temp = er32(PRC127);
+ temp = er32(PRC255);
+ temp = er32(PRC511);
+ temp = er32(PRC1023);
+ temp = er32(PRC1522);
+ temp = er32(PTC64);
+ temp = er32(PTC127);
+ temp = er32(PTC255);
+ temp = er32(PTC511);
+ temp = er32(PTC1023);
+ temp = er32(PTC1522);
+
+ temp = er32(ALGNERRC);
+ temp = er32(RXERRC);
+ temp = er32(TNCRS);
+ temp = er32(CEXTERR);
+ temp = er32(TSCTC);
+ temp = er32(TSCTFC);
+
+ temp = er32(MGTPRC);
+ temp = er32(MGTPDC);
+ temp = er32(MGTPTC);
+
+ temp = er32(IAC);
+ temp = er32(ICRXOC);
+
+ temp = er32(ICRXPTC);
+ temp = er32(ICRXATC);
+ temp = er32(ICTXPTC);
+ temp = er32(ICTXATC);
+ temp = er32(ICTXQEC);
+ temp = er32(ICTXQMTC);
+ temp = er32(ICRXDMTC);
+}
+
+static struct e1000_mac_operations e82571_mac_ops = {
+ .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+ /* .check_for_link: media type dependent */
+ .cleanup_led = e1000e_cleanup_led_generic,
+ .clear_hw_cntrs = e1000_clear_hw_cntrs_82571,
+ .get_bus_info = e1000e_get_bus_info_pcie,
+ /* .get_link_up_info: media type dependent */
+ .led_on = e1000e_led_on_generic,
+ .led_off = e1000e_led_off_generic,
+ .mc_addr_list_update = e1000_mc_addr_list_update_82571,
+ .reset_hw = e1000_reset_hw_82571,
+ .init_hw = e1000_init_hw_82571,
+ .setup_link = e1000_setup_link_82571,
+ /* .setup_physical_interface: media type dependent */
+};
+
+static struct e1000_phy_operations e82_phy_ops_igp = {
+ .acquire_phy = e1000_get_hw_semaphore_82571,
+ .check_reset_block = e1000e_check_reset_block_generic,
+ .commit_phy = NULL,
+ .force_speed_duplex = e1000e_phy_force_speed_duplex_igp,
+ .get_cfg_done = e1000_get_cfg_done_82571,
+ .get_cable_length = e1000e_get_cable_length_igp_2,
+ .get_phy_info = e1000e_get_phy_info_igp,
+ .read_phy_reg = e1000e_read_phy_reg_igp,
+ .release_phy = e1000_put_hw_semaphore_82571,
+ .reset_phy = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_phy_reg = e1000e_write_phy_reg_igp,
+};
+
+static struct e1000_phy_operations e82_phy_ops_m88 = {
+ .acquire_phy = e1000_get_hw_semaphore_82571,
+ .check_reset_block = e1000e_check_reset_block_generic,
+ .commit_phy = e1000e_phy_sw_reset,
+ .force_speed_duplex = e1000e_phy_force_speed_duplex_m88,
+ .get_cfg_done = e1000e_get_cfg_done,
+ .get_cable_length = e1000e_get_cable_length_m88,
+ .get_phy_info = e1000e_get_phy_info_m88,
+ .read_phy_reg = e1000e_read_phy_reg_m88,
+ .release_phy = e1000_put_hw_semaphore_82571,
+ .reset_phy = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_phy_reg = e1000e_write_phy_reg_m88,
+};
+
+static struct e1000_nvm_operations e82571_nvm_ops = {
+ .acquire_nvm = e1000_acquire_nvm_82571,
+ .read_nvm = e1000e_read_nvm_spi,
+ .release_nvm = e1000_release_nvm_82571,
+ .update_nvm = e1000_update_nvm_checksum_82571,
+ .valid_led_default = e1000_valid_led_default_82571,
+ .validate_nvm = e1000_validate_nvm_checksum_82571,
+ .write_nvm = e1000_write_nvm_82571,
+};
+
+static struct e1000_nvm_operations e82573_nvm_ops = {
+ .acquire_nvm = e1000_acquire_nvm_82571,
+ .read_nvm = e1000e_read_nvm_eerd,
+ .release_nvm = e1000_release_nvm_82571,
+ .update_nvm = e1000_update_nvm_checksum_82571,
+ .valid_led_default = e1000_valid_led_default_82571,
+ .validate_nvm = e1000_validate_nvm_checksum_82571,
+ .write_nvm = e1000_write_nvm_82571,
+};
+
+struct e1000_info e1000_82571_info = {
+ .mac = e1000_82571,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_HAS_SMART_POWER_DOWN
+ | FLAG_RESET_OVERWRITES_LAA /* errata */
+ | FLAG_TARC_SPEED_MODE_BIT /* errata */
+ | FLAG_APME_CHECK_PORT_B,
+ .pba = 38,
+ .get_invariants = e1000_get_invariants_82571,
+ .mac_ops = &e82571_mac_ops,
+ .phy_ops = &e82_phy_ops_igp,
+ .nvm_ops = &e82571_nvm_ops,
+};
+
+struct e1000_info e1000_82572_info = {
+ .mac = e1000_82572,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_TARC_SPEED_MODE_BIT, /* errata */
+ .pba = 38,
+ .get_invariants = e1000_get_invariants_82571,
+ .mac_ops = &e82571_mac_ops,
+ .phy_ops = &e82_phy_ops_igp,
+ .nvm_ops = &e82571_nvm_ops,
+};
+
+struct e1000_info e1000_82573_info = {
+ .mac = e1000_82573,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_HAS_SMART_POWER_DOWN
+ | FLAG_HAS_AMT
+ | FLAG_HAS_ASPM
+ | FLAG_HAS_ERT
+ | FLAG_HAS_SWSM_ON_LOAD,
+ .pba = 20,
+ .get_invariants = e1000_get_invariants_82571,
+ .mac_ops = &e82571_mac_ops,
+ .phy_ops = &e82_phy_ops_m88,
+ .nvm_ops = &e82573_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile
new file mode 100644
index 000000000000..650f866e7ac2
--- /dev/null
+++ b/drivers/net/e1000e/Makefile
@@ -0,0 +1,37 @@
+################################################################################
+#
+# Intel PRO/1000 Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) PRO/1000 ethernet driver
+#
+
+obj-$(CONFIG_E1000E) += e1000e.o
+
+e1000e-objs := 82571.o ich8lan.o es2lan.o \
+ lib.o phy.o param.o ethtool.o netdev.o
+
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
new file mode 100644
index 000000000000..b32ed45b4b34
--- /dev/null
+++ b/drivers/net/e1000e/defines.h
@@ -0,0 +1,739 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
+#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
+#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
+#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
+#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+
+#define E1000_RXDEXT_STATERR_CE 0x01000000
+#define E1000_RXDEXT_STATERR_SE 0x02000000
+#define E1000_RXDEXT_STATERR_SEQ 0x04000000
+#define E1000_RXDEXT_STATERR_CXE 0x10000000
+#define E1000_RXDEXT_STATERR_RXE 0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+ E1000_RXDEXT_STATERR_CE | \
+ E1000_RXDEXT_STATERR_SE | \
+ E1000_RXDEXT_STATERR_SEQ | \
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address
+ * filtering */
+#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host
+ * memory */
+
+/* Receive Control */
+#define E1000_RCTL_EN 0x00000002 /* enable */
+#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
+#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */
+#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */
+#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
+#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
+#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
+#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
+#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
+#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ * E1000_PSRCTL_BSIZE0_MASK) |
+ * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ * E1000_PSRCTL_BSIZE1_MASK) |
+ * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ * E1000_PSRCTL_BSIZE2_MASK) |
+ * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ * E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256], default=256
+ * value1 = [1024..64512], default=4096
+ * value2 = [0..64512], default=4096
+ * value3 = [0..64512], default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM 0x1
+#define E1000_SWFW_PHY0_SM 0x2
+#define E1000_SWFW_PHY1_SM 0x4
+
+/* Device Control */
+#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
+#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
+#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
+#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
+#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
+#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_RST 0x04000000 /* Global reset */
+#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+
+/* Device Status */
+#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL 0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL)
+#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+
+#define E1000_LEDCTL_MODE_LED_ON 0xE
+#define E1000_LEDCTL_MODE_LED_OFF 0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+
+/* Transmit Control */
+#define E1000_TCTL_EN 0x00000002 /* enable tx */
+#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
+#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
+#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
+#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
+
+/* Transmit Arbitration Count */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+
+/* Header split receive */
+#define E1000_RFCTL_EXTEN 0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD 15
+#define E1000_CT_SHIFT 4
+#define E1000_COLLISION_DISTANCE 63
+#define E1000_COLD_SHIFT 12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK 0x000003FF
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT 10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT 20
+
+#define MAX_JUMBO_FRAME_SIZE 0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16
+
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+
+/* PBA constants */
+#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */
+#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
+
+#define E1000_PBS_16K E1000_PBA_16K
+
+#define IFS_MAX 80
+#define IFS_MIN 40
+#define IFS_RATIO 4
+#define IFS_STEP 10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
+#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+ still to be processed. */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+
+/* 802.1q VLAN Packet Size */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/* Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots. However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 15
+#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+
+/* Error Codes */
+#define E1000_ERR_NVM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET 9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET 12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT 50
+#define COPPER_LINK_UP_LIMIT 10
+#define PHY_AUTO_NEG_LIMIT 45
+#define PHY_FORCE_LIMIT 20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT 800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT 10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT 10
+
+/* Flow Control */
+#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
+#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */
+#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
+#define E1000_RXCW_C 0x20000000 /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP 0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004
+#define E1000_GCR_TXD_NO_SNOOP 0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \
+ E1000_GCR_RXDSCW_NO_SNOOP | \
+ E1000_GCR_RXDSCR_NO_SNOOP | \
+ E1000_GCR_TXD_NO_SNOOP | \
+ E1000_GCR_TXDSCW_NO_SNOOP | \
+ E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+
+/* Autoneg Expansion Register */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+
+/* NVM Control */
+#define E1000_EECD_SK 0x00000001 /* NVM Clock */
+#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI 0x00000004 /* NVM Data In */
+#define E1000_EECD_DO 0x00000008 /* NVM Data Out */
+#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */
+#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* NVM Addressing bits based on type
+ * (0-small, 1-large) */
+#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+
+#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */
+#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START 1 /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES 2000
+
+/* NVM Word Offsets */
+#define NVM_ID_LED_SETTINGS 0x0004
+#define NVM_INIT_CONTROL2_REG 0x000F
+#define NVM_INIT_CONTROL3_PORT_B 0x0014
+#define NVM_INIT_3GIO_3 0x001A
+#define NVM_INIT_CONTROL3_PORT_A 0x0024
+#define NVM_CFG 0x0012
+#define NVM_CHECKSUM_REG 0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK 0x3000
+#define NVM_WORD0F_PAUSE 0x1000
+#define NVM_WORD0F_ASM_DIR 0x2000
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK 0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM 0xBABA
+
+/* PBA (printed board assembly) number words */
+#define NVM_PBA_OFFSET_0 8
+#define NVM_PBA_OFFSET_1 9
+
+#define NVM_WORD_SIZE_BASE_SHIFT 6
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI 0x01
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2 0x1
+#define ID_LED_DEF1_ON2 0x2
+#define ID_LED_DEF1_OFF2 0x3
+#define ID_LED_ON1_DEF2 0x4
+#define ID_LED_ON1_ON2 0x5
+#define ID_LED_ON1_OFF2 0x6
+#define ID_LED_OFF1_DEF2 0x7
+#define ID_LED_OFF1_ON2 0x8
+#define ID_LED_OFF1_OFF2 0x9
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER 0x0E
+#define PCIE_LINK_STATUS 0x12
+
+#define PCI_HEADER_TYPE_MULTIFUNC 0x80
+#define PCIE_LINK_WIDTH_MASK 0x3F0
+#define PCIE_LINK_WIDTH_SHIFT 4
+
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define GG82563_E_PHY_ID 0x01410CA0
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
+ * 100BASE-TX/10BASE-T:
+ * MDI Mode
+ */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
+ */
+ /* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+ /* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+ * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT 5
+#define GG82563_REG(page, reg) \
+ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG 30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL \
+ GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_PAGE_SELECT \
+ GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2 \
+ GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT \
+ GG82563_REG(0, 29) /* Alternate Page Select */
+
+#define GG82563_PHY_MAC_SPEC_CTRL \
+ GG82563_REG(2, 21) /* MAC Specific Control Register */
+
+#define GG82563_PHY_DSP_DISTANCE \
+ GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL \
+ GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PWR_MGMT_CTRL \
+ GG82563_REG(193, 20) /* Power Management Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_INBAND_CTRL \
+ GG82563_REG(194, 18) /* Inband Control */
+
+/* MDI Control */
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE 0x04000000
+#define E1000_MDIC_OP_READ 0x08000000
+#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_ERROR 0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_POLL_TIMEOUT 640
+
+#endif /* _E1000_DEFINES_H_ */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
new file mode 100644
index 000000000000..d2499bb07c13
--- /dev/null
+++ b/drivers/net/e1000e/e1000.h
@@ -0,0 +1,514 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+
+#include "hw.h"
+
+struct e1000_info;
+
+#define ndev_printk(level, netdev, format, arg...) \
+ printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \
+ (netdev)->name, ## arg)
+
+#ifdef DEBUG
+#define ndev_dbg(netdev, format, arg...) \
+ ndev_printk(KERN_DEBUG , netdev, format, ## arg)
+#else
+#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0)
+#endif
+
+#define ndev_err(netdev, format, arg...) \
+ ndev_printk(KERN_ERR , netdev, format, ## arg)
+#define ndev_info(netdev, format, arg...) \
+ ndev_printk(KERN_INFO , netdev, format, ## arg)
+#define ndev_warn(netdev, format, arg...) \
+ ndev_printk(KERN_WARNING , netdev, format, ## arg)
+#define ndev_notice(netdev, format, arg...) \
+ ndev_printk(KERN_NOTICE , netdev, format, ## arg)
+
+
+/* TX/RX descriptor defines */
+#define E1000_DEFAULT_TXD 256
+#define E1000_MAX_TXD 4096
+#define E1000_MIN_TXD 80
+
+#define E1000_DEFAULT_RXD 256
+#define E1000_MAX_RXD 4096
+#define E1000_MIN_RXD 80
+
+/* Early Receive defines */
+#define E1000_ERT_2048 0x100
+
+#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+
+#define AUTO_ALL_MODES 0
+#define E1000_EEPROM_APME 0x0400
+
+#define E1000_MNG_VLAN_NONE (-1)
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
+
+enum e1000_boards {
+ board_82571,
+ board_82572,
+ board_82573,
+ board_80003es2lan,
+ board_ich8lan,
+ board_ich9lan,
+};
+
+struct e1000_queue_stats {
+ u64 packets;
+ u64 bytes;
+};
+
+struct e1000_ps_page {
+ struct page *page;
+ u64 dma; /* must be u64 - written to hw */
+};
+
+/*
+ * wrappers around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct e1000_buffer {
+ dma_addr_t dma;
+ struct sk_buff *skb;
+ union {
+ /* TX */
+ struct {
+ unsigned long time_stamp;
+ u16 length;
+ u16 next_to_watch;
+ };
+ /* RX */
+ struct page *page;
+ };
+
+};
+
+struct e1000_ring {
+ void *desc; /* pointer to ring memory */
+ dma_addr_t dma; /* phys address of ring */
+ unsigned int size; /* length of ring in bytes */
+ unsigned int count; /* number of desc. in ring */
+
+ u16 next_to_use;
+ u16 next_to_clean;
+
+ u16 head;
+ u16 tail;
+
+ /* array of buffer information structs */
+ struct e1000_buffer *buffer_info;
+
+ /* arrays of page information for packet split */
+ struct e1000_ps_page *ps_pages;
+ struct sk_buff *rx_skb_top;
+
+ struct e1000_queue_stats stats;
+};
+
+/* board specific private data structure */
+struct e1000_adapter {
+ struct timer_list watchdog_timer;
+ struct timer_list phy_info_timer;
+ struct timer_list blink_timer;
+
+ struct work_struct reset_task;
+ struct work_struct watchdog_task;
+
+ const struct e1000_info *ei;
+
+ struct vlan_group *vlgrp;
+ u32 bd_number;
+ u32 rx_buffer_len;
+ u16 mng_vlan_id;
+ u16 link_speed;
+ u16 link_duplex;
+
+ spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
+
+ /* this is still needed for 82571 and above */
+ atomic_t irq_sem;
+
+ /* track device up/down/testing state */
+ unsigned long state;
+
+ /* Interrupt Throttle Rate */
+ u32 itr;
+ u32 itr_setting;
+ u16 tx_itr;
+ u16 rx_itr;
+
+ /*
+ * TX
+ */
+ struct e1000_ring *tx_ring /* One per active queue */
+ ____cacheline_aligned_in_smp;
+
+ struct napi_struct napi;
+
+ unsigned long tx_queue_len;
+ unsigned int restart_queue;
+ u32 txd_cmd;
+
+ bool detect_tx_hung;
+ u8 tx_timeout_factor;
+
+ u32 tx_int_delay;
+ u32 tx_abs_int_delay;
+
+ unsigned int total_tx_bytes;
+ unsigned int total_tx_packets;
+ unsigned int total_rx_bytes;
+ unsigned int total_rx_packets;
+
+ /* TX stats */
+ u64 tpt_old;
+ u64 colc_old;
+ u64 gotcl_old;
+ u32 gotcl;
+ u32 tx_timeout_count;
+ u32 tx_fifo_head;
+ u32 tx_head_addr;
+ u32 tx_fifo_size;
+ u32 tx_dma_failed;
+
+ /*
+ * RX
+ */
+ bool (*clean_rx) (struct e1000_adapter *adapter,
+ int *work_done, int work_to_do)
+ ____cacheline_aligned_in_smp;
+ void (*alloc_rx_buf) (struct e1000_adapter *adapter,
+ int cleaned_count);
+ struct e1000_ring *rx_ring;
+
+ u32 rx_int_delay;
+ u32 rx_abs_int_delay;
+
+ /* RX stats */
+ u64 hw_csum_err;
+ u64 hw_csum_good;
+ u64 rx_hdr_split;
+ u64 gorcl_old;
+ u32 gorcl;
+ u32 alloc_rx_buff_failed;
+ u32 rx_dma_failed;
+
+ unsigned int rx_ps_pages;
+ u16 rx_ps_bsize0;
+
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ spinlock_t stats_lock; /* prevent concurrent stats updates */
+
+ /* structs defined in e1000_hw.h */
+ struct e1000_hw hw;
+
+ struct e1000_hw_stats stats;
+ struct e1000_phy_info phy_info;
+ struct e1000_phy_stats phy_stats;
+
+ struct e1000_ring test_tx_ring;
+ struct e1000_ring test_rx_ring;
+ u32 test_icr;
+
+ u32 msg_enable;
+
+ u32 eeprom_wol;
+ u32 wol;
+ u32 pba;
+
+ u8 fc_autoneg;
+
+ unsigned long led_status;
+
+ unsigned int flags;
+};
+
+struct e1000_info {
+ enum e1000_mac_type mac;
+ unsigned int flags;
+ u32 pba;
+ s32 (*get_invariants)(struct e1000_adapter *);
+ struct e1000_mac_operations *mac_ops;
+ struct e1000_phy_operations *phy_ops;
+ struct e1000_nvm_operations *nvm_ops;
+};
+
+/* hardware capability, feature, and workaround flags */
+#define FLAG_HAS_AMT (1 << 0)
+#define FLAG_HAS_FLASH (1 << 1)
+#define FLAG_HAS_HW_VLAN_FILTER (1 << 2)
+#define FLAG_HAS_WOL (1 << 3)
+#define FLAG_HAS_ERT (1 << 4)
+#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_HAS_ASPM (1 << 8)
+#define FLAG_HAS_STATS_ICR_ICT (1 << 9)
+#define FLAG_HAS_STATS_PTC_PRC (1 << 10)
+#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
+#define FLAG_IS_QUAD_PORT_A (1 << 12)
+#define FLAG_IS_QUAD_PORT (1 << 13)
+#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14)
+#define FLAG_APME_IN_WUC (1 << 15)
+#define FLAG_APME_IN_CTRL3 (1 << 16)
+#define FLAG_APME_CHECK_PORT_B (1 << 17)
+#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18)
+#define FLAG_NO_WAKE_UCAST (1 << 19)
+#define FLAG_MNG_PT_ENABLED (1 << 20)
+#define FLAG_RESET_OVERWRITES_LAA (1 << 21)
+#define FLAG_TARC_SPEED_MODE_BIT (1 << 22)
+#define FLAG_TARC_SET_BIT_ZERO (1 << 23)
+#define FLAG_RX_NEEDS_RESTART (1 << 24)
+#define FLAG_LSC_GIG_SPEED_DROP (1 << 25)
+#define FLAG_SMART_POWER_DOWN (1 << 26)
+#define FLAG_MSI_ENABLED (1 << 27)
+#define FLAG_RX_CSUM_ENABLED (1 << 28)
+#define FLAG_TSO_FORCE (1 << 29)
+
+#define E1000_RX_DESC_PS(R, i) \
+ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
+
+enum e1000_state_t {
+ __E1000_TESTING,
+ __E1000_RESETTING,
+ __E1000_DOWN
+};
+
+enum latency_range {
+ lowest_latency = 0,
+ low_latency = 1,
+ bulk_latency = 2,
+ latency_invalid = 255
+};
+
+extern char e1000e_driver_name[];
+extern const char e1000e_driver_version[];
+
+extern void e1000e_check_options(struct e1000_adapter *adapter);
+extern void e1000e_set_ethtool_ops(struct net_device *netdev);
+
+extern int e1000e_up(struct e1000_adapter *adapter);
+extern void e1000e_down(struct e1000_adapter *adapter);
+extern void e1000e_reinit_locked(struct e1000_adapter *adapter);
+extern void e1000e_reset(struct e1000_adapter *adapter);
+extern void e1000e_power_up_phy(struct e1000_adapter *adapter);
+extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter);
+extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
+extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
+extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
+extern void e1000e_update_stats(struct e1000_adapter *adapter);
+
+extern unsigned int copybreak;
+
+extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
+
+extern struct e1000_info e1000_82571_info;
+extern struct e1000_info e1000_82572_info;
+extern struct e1000_info e1000_82573_info;
+extern struct e1000_info e1000_ich8_info;
+extern struct e1000_info e1000_ich9_info;
+extern struct e1000_info e1000_es2_info;
+
+extern s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num);
+
+extern s32 e1000e_commit_phy(struct e1000_hw *hw);
+
+extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+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 s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
+extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
+extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
+extern s32 e1000e_id_led_init(struct e1000_hw *hw);
+extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+extern s32 e1000e_setup_link(struct e1000_hw *hw);
+extern void e1000e_clear_vfta(struct e1000_hw *hw);
+extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+extern void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count,
+ u32 rar_used_count, u32 rar_count);
+extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
+extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+extern void e1000e_config_collision_dist(struct e1000_hw *hw);
+extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
+extern s32 e1000e_blink_led(struct e1000_hw *hw);
+extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+extern void e1000e_reset_adaptive(struct e1000_hw *hw);
+extern void e1000e_update_adaptive(struct e1000_hw *hw);
+
+extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_id(struct e1000_hw *hw);
+extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
+extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
+extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
+extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
+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 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);
+extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success);
+extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+extern s32 e1000e_check_downshift(struct e1000_hw *hw);
+
+static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ return hw->phy.ops.reset_phy(hw);
+}
+
+static inline s32 e1000_check_reset_block(struct e1000_hw *hw)
+{
+ return hw->phy.ops.check_reset_block(hw);
+}
+
+static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return hw->phy.ops.read_phy_reg(hw, offset, data);
+}
+
+static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return hw->phy.ops.write_phy_reg(hw, offset, data);
+}
+
+static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
+{
+ return hw->phy.ops.get_cable_length(hw);
+}
+
+extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
+extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+extern s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+extern void e1000e_release_nvm(struct e1000_hw *hw);
+extern void e1000e_reload_nvm(struct e1000_hw *hw);
+extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
+
+static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
+{
+ return hw->nvm.ops.validate_nvm(hw);
+}
+
+static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
+{
+ return hw->nvm.ops.update_nvm(hw);
+}
+
+static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ return hw->nvm.ops.read_nvm(hw, offset, words, data);
+}
+
+static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ return hw->nvm.ops.write_nvm(hw, offset, words, data);
+}
+
+static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
+{
+ return hw->phy.ops.get_phy_info(hw);
+}
+
+extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
+extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
+
+static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
+{
+ return readl(hw->hw_addr + reg);
+}
+
+static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+ writel(val, hw->hw_addr + reg);
+}
+
+#endif /* _E1000_H_ */
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
new file mode 100644
index 000000000000..88657adf965f
--- /dev/null
+++ b/drivers/net/e1000e/es2lan.c
@@ -0,0 +1,1232 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+ * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disab. */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000
+ /* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M
+ 1 = 50-80M
+ 2 = 80-110M
+ 3 = 110-140M
+ 4 = >140M */
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
+ /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */
+
+/* A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const u16 e1000_gg82563_cable_length_table[] =
+ { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
+
+/**
+ * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+
+ if (hw->media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ return 0;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+ phy->type = e1000_phy_gg82563;
+
+ /* This can only be done after all function pointers are setup. */
+ ret_val = e1000e_get_phy_id(hw);
+
+ /* Verify phy id */
+ if (phy->id != GG82563_E_PHY_ID)
+ return -E1000_ERR_PHY;
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u16 size;
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ nvm->type = e1000_nvm_eeprom_spi;
+
+ size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+
+ /* Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+ nvm->word_size = 1 << size;
+
+ return 0;
+}
+
+/**
+ * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_mac_operations *func = &mac->ops;
+
+ /* Set media type */
+ switch (adapter->pdev->device) {
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ hw->media_type = e1000_media_type_copper;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+
+ /* check for link */
+ switch (hw->media_type) {
+ case e1000_media_type_copper:
+ func->setup_physical_interface = e1000_setup_copper_link_80003es2lan;
+ func->check_for_link = e1000e_check_for_copper_link;
+ break;
+ case e1000_media_type_fiber:
+ func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
+ func->check_for_link = e1000e_check_for_fiber_link;
+ break;
+ case e1000_media_type_internal_serdes:
+ func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
+ func->check_for_link = e1000e_check_for_serdes_link;
+ break;
+ default:
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ return 0;
+}
+
+static s32 e1000_get_invariants_80003es2lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ s32 rc;
+
+ rc = e1000_init_mac_params_80003es2lan(adapter);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_nvm_params_80003es2lan(hw);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_phy_params_80003es2lan(hw);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+/**
+ * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to acquire access rights to the correct PHY. This is a
+ * function pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+ u16 mask;
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+
+ return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_release_phy_80003es2lan - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY. This is a
+ * function pointer entry point called by the api module.
+ **/
+static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+ u16 mask;
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the semaphore to access the EEPROM. This is a function
+ * pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000e_acquire_nvm(hw);
+
+ if (ret_val)
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Release the semaphore used to access the EEPROM. This is a
+ * function pointer entry point called by the api module.
+ **/
+static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ e1000e_release_nvm(hw);
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+ u32 swmask = mask;
+ u32 fwmask = mask << 16;
+ s32 i = 0;
+ s32 timeout = 200;
+
+ while (i < timeout) {
+ if (e1000e_get_hw_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ swfw_sync = er32(SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /* Firmware currently using resource (fwmask)
+ * or other software thread using resource (swmask) */
+ e1000e_put_hw_semaphore(hw);
+ mdelay(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ hw_dbg(hw,
+ "Driver can't access resource, SW_FW_SYNC timeout.\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+
+ swfw_sync |= swmask;
+ ew32(SW_FW_SYNC, swfw_sync);
+
+ e1000e_put_hw_semaphore(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+
+ while (e1000e_get_hw_semaphore(hw) != 0);
+ /* Empty */
+
+ swfw_sync = er32(SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ ew32(SW_FW_SYNC, swfw_sync);
+
+ e1000e_put_hw_semaphore(hw);
+}
+
+/**
+ * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: pointer to the data returned from the operation
+ *
+ * Read the GG82563 PHY register. This is a function pointer entry
+ * point called by the api module.
+ **/
+static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ u32 offset, u16 *data)
+{
+ s32 ret_val;
+ u32 page_select;
+ u16 temp;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+ page_select = GG82563_PHY_PAGE_SELECT;
+ else
+ /* Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+
+ temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
+ if (ret_val)
+ return ret_val;
+
+ /* The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ udelay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+
+ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ ret_val = -E1000_ERR_PHY;
+ return ret_val;
+ }
+
+ udelay(200);
+
+ ret_val = e1000e_read_phy_reg_m88(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ udelay(200);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: value to write to the register
+ *
+ * Write to the GG82563 PHY register. This is a function pointer entry
+ * point called by the api module.
+ **/
+static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ u32 offset, u16 data)
+{
+ s32 ret_val;
+ u32 page_select;
+ u16 temp;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+ page_select = GG82563_PHY_PAGE_SELECT;
+ else
+ /* Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+
+ temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
+ if (ret_val)
+ return ret_val;
+
+
+ /* The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ udelay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+
+ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp)
+ return -E1000_ERR_PHY;
+
+ udelay(200);
+
+ ret_val = e1000e_write_phy_reg_m88(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ udelay(200);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_80003es2lan - Write to ESB2 NVM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @words: number of words to write
+ * @data: buffer of data to write to the NVM
+ *
+ * Write "words" of data to the ESB2 NVM. This is a function
+ * pointer entry point called by the api module.
+ **/
+static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ return e1000e_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
+ * @hw: pointer to the HW structure
+ *
+ * Wait a specific amount of time for manageability processes to complete.
+ * This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+ s32 timeout = PHY_CFG_TIMEOUT;
+ u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+ if (hw->bus.func == 1)
+ mask = E1000_NVM_CFG_DONE_PORT_1;
+
+ while (timeout) {
+ if (er32(EEMNGCTL) & mask)
+ break;
+ msleep(1);
+ timeout--;
+ }
+ if (!timeout) {
+ hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ * @hw: pointer to the HW structure
+ *
+ * Force the speed and duplex settings onto the PHY. This is a
+ * function pointer entry point called by the phy module.
+ **/
+static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data);
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ /* Reset the phy to commit changes. */
+ phy_data |= MII_CR_RESET;
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+
+ if (hw->phy.wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link "
+ "on GG82563 phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ /* We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = e1000e_phy_reset_dsp(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Resetting the phy means we need to verify the TX_CLK corresponds
+ * to the link speed. 10Mbps -> 2.5MHz, else 25MHz.
+ */
+ phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+ if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+ phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+ else
+ phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+ /* In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_80003es2lan - Set approximate cable length
+ * @hw: pointer to the HW structure
+ *
+ * Find the approximate cable length as measured by the GG82563 PHY.
+ * This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ u16 index;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+ phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+ phy->max_cable_length = e1000_gg82563_cable_length_table[index+5];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+ return 0;
+}
+
+/**
+ * e1000_get_link_up_info_80003es2lan - Report speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to speed buffer
+ * @duplex: pointer to duplex buffer
+ *
+ * Retrieve the current speed and duplex configuration.
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+ u16 *duplex)
+{
+ s32 ret_val;
+
+ if (hw->media_type == e1000_media_type_copper) {
+ ret_val = e1000e_get_speed_and_duplex_copper(hw,
+ speed,
+ duplex);
+ if (ret_val)
+ return ret_val;
+ if (*speed == SPEED_1000)
+ ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+ else
+ ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw,
+ *duplex);
+ } else {
+ ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
+ speed,
+ duplex);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_80003es2lan - Reset the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Perform a global reset to the ESB2 controller.
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ u32 icr;
+ s32 ret_val;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000e_disable_pcie_master(hw);
+ if (ret_val)
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+ hw_dbg(hw, "Masking off all interrupts\n");
+ ew32(IMC, 0xffffffff);
+
+ ew32(RCTL, 0);
+ ew32(TCTL, E1000_TCTL_PSP);
+ e1e_flush();
+
+ msleep(10);
+
+ ctrl = er32(CTRL);
+
+ hw_dbg(hw, "Issuing a global reset to MAC\n");
+ ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+ ret_val = e1000e_get_auto_rd_done(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ return ret_val;
+
+ /* Clear any pending interrupt events. */
+ ew32(IMC, 0xffffffff);
+ icr = er32(ICR);
+
+ return 0;
+}
+
+/**
+ * e1000_init_hw_80003es2lan - Initialize the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 reg_data;
+ s32 ret_val;
+ u16 i;
+
+ e1000_initialize_hw_bits_80003es2lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = e1000e_id_led_init(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error initializing identification LED\n");
+ return ret_val;
+ }
+
+ /* Disabling VLAN filtering */
+ hw_dbg(hw, "Initializing the IEEE VLAN\n");
+ e1000e_clear_vfta(hw);
+
+ /* Setup the receive address. */
+ e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg(hw, "Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = e1000e_setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = er32(TXDCTL);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL, reg_data);
+
+ /* ...for both queues. */
+ reg_data = er32(TXDCTL1);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL1, reg_data);
+
+ /* Enable retransmit on late collisions */
+ reg_data = er32(TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ ew32(TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = er32(TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+ ew32(TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = er32(TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ ew32(TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_80003es2lan(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+ u32 reg;
+
+ /* Transmit Descriptor Control 0 */
+ reg = er32(TXDCTL);
+ reg |= (1 << 22);
+ ew32(TXDCTL, reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = er32(TXDCTL1);
+ reg |= (1 << 22);
+ ew32(TXDCTL1, reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = er32(TARC0);
+ reg &= ~(0xF << 27); /* 30:27 */
+ if (hw->media_type != e1000_media_type_copper)
+ reg &= ~(1 << 20);
+ ew32(TARC0, reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = er32(TARC1);
+ if (er32(TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ ew32(TARC1, reg);
+}
+
+/**
+ * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ * @hw: pointer to the HW structure
+ *
+ * Setup some GG82563 PHY registers for obtaining link
+ **/
+static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u32 ctrl_ext;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+ data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+ ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ data);
+ if (ret_val)
+ return ret_val;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (phy->mdix) {
+ case 1:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ if (phy->disable_polarity_correction)
+ data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+ ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000e_commit_phy(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ /* Bypass RX and TX FIFO's */
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data);
+ if (ret_val)
+ return ret_val;
+
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ ew32(CTRL_EXT, ctrl_ext);
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (!e1000e_check_mng_mode(hw)) {
+ /* Enable Electrical Idle on the PHY */
+ data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= GG82563_ICR_DIS_PADDING;
+ ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ return 0;
+}
+
+/**
+ * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Essentially a wrapper for setting up all things "copper" related.
+ * This is a function pointer entry point called by the mac module.
+ **/
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+ u16 reg_data;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ /* Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000e_setup_copper_link(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ * @hw: pointer to the HW structure
+ * @duplex: current duplex setting
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * 10/100 operation.
+ **/
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
+{
+ s32 ret_val;
+ u32 tipg;
+ u16 reg_data;
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = er32(TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+ ew32(TIPG, tipg);
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return 0;
+}
+
+/**
+ * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ * @hw: pointer to the HW structure
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * gigabit operation.
+ **/
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 reg_data;
+ u32 tipg;
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = er32(TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ ew32(TIPG, tipg);
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ e1000e_clear_hw_cntrs_base(hw);
+
+ temp = er32(PRC64);
+ temp = er32(PRC127);
+ temp = er32(PRC255);
+ temp = er32(PRC511);
+ temp = er32(PRC1023);
+ temp = er32(PRC1522);
+ temp = er32(PTC64);
+ temp = er32(PTC127);
+ temp = er32(PTC255);
+ temp = er32(PTC511);
+ temp = er32(PTC1023);
+ temp = er32(PTC1522);
+
+ temp = er32(ALGNERRC);
+ temp = er32(RXERRC);
+ temp = er32(TNCRS);
+ temp = er32(CEXTERR);
+ temp = er32(TSCTC);
+ temp = er32(TSCTFC);
+
+ temp = er32(MGTPRC);
+ temp = er32(MGTPDC);
+ temp = er32(MGTPTC);
+
+ temp = er32(IAC);
+ temp = er32(ICRXOC);
+
+ temp = er32(ICRXPTC);
+ temp = er32(ICRXATC);
+ temp = er32(ICTXPTC);
+ temp = er32(ICTXATC);
+ temp = er32(ICTXQEC);
+ temp = er32(ICTXQMTC);
+ temp = er32(ICRXDMTC);
+}
+
+static struct e1000_mac_operations es2_mac_ops = {
+ .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+ /* check_for_link dependent on media type */
+ .cleanup_led = e1000e_cleanup_led_generic,
+ .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan,
+ .get_bus_info = e1000e_get_bus_info_pcie,
+ .get_link_up_info = e1000_get_link_up_info_80003es2lan,
+ .led_on = e1000e_led_on_generic,
+ .led_off = e1000e_led_off_generic,
+ .mc_addr_list_update = e1000e_mc_addr_list_update_generic,
+ .reset_hw = e1000_reset_hw_80003es2lan,
+ .init_hw = e1000_init_hw_80003es2lan,
+ .setup_link = e1000e_setup_link,
+ /* setup_physical_interface dependent on media type */
+};
+
+static struct e1000_phy_operations es2_phy_ops = {
+ .acquire_phy = e1000_acquire_phy_80003es2lan,
+ .check_reset_block = e1000e_check_reset_block_generic,
+ .commit_phy = e1000e_phy_sw_reset,
+ .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan,
+ .get_cfg_done = e1000_get_cfg_done_80003es2lan,
+ .get_cable_length = e1000_get_cable_length_80003es2lan,
+ .get_phy_info = e1000e_get_phy_info_m88,
+ .read_phy_reg = e1000_read_phy_reg_gg82563_80003es2lan,
+ .release_phy = e1000_release_phy_80003es2lan,
+ .reset_phy = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = NULL,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_phy_reg = e1000_write_phy_reg_gg82563_80003es2lan,
+};
+
+static struct e1000_nvm_operations es2_nvm_ops = {
+ .acquire_nvm = e1000_acquire_nvm_80003es2lan,
+ .read_nvm = e1000e_read_nvm_eerd,
+ .release_nvm = e1000_release_nvm_80003es2lan,
+ .update_nvm = e1000e_update_nvm_checksum_generic,
+ .valid_led_default = e1000e_valid_led_default,
+ .validate_nvm = e1000e_validate_nvm_checksum_generic,
+ .write_nvm = e1000_write_nvm_80003es2lan,
+};
+
+struct e1000_info e1000_es2_info = {
+ .mac = e1000_80003es2lan,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_RX_NEEDS_RESTART /* errata */
+ | FLAG_TARC_SET_BIT_ZERO /* errata */
+ | FLAG_APME_CHECK_PORT_B
+ | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+ | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
+ .pba = 38,
+ .get_invariants = e1000_get_invariants_80003es2lan,
+ .mac_ops = &es2_mac_ops,
+ .phy_ops = &es2_phy_ops,
+ .nvm_ops = &es2_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
new file mode 100644
index 000000000000..b7a7e2ae5e13
--- /dev/null
+++ b/drivers/net/e1000e/ethtool.c
@@ -0,0 +1,1780 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for e1000 */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "e1000.h"
+
+struct e1000_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+static const struct e1000_stats e1000_gstrings_stats[] = {
+ { "rx_packets", E1000_STAT(stats.gprc) },
+ { "tx_packets", E1000_STAT(stats.gptc) },
+ { "rx_bytes", E1000_STAT(stats.gorcl) },
+ { "tx_bytes", E1000_STAT(stats.gotcl) },
+ { "rx_broadcast", E1000_STAT(stats.bprc) },
+ { "tx_broadcast", E1000_STAT(stats.bptc) },
+ { "rx_multicast", E1000_STAT(stats.mprc) },
+ { "tx_multicast", E1000_STAT(stats.mptc) },
+ { "rx_errors", E1000_STAT(net_stats.rx_errors) },
+ { "tx_errors", E1000_STAT(net_stats.tx_errors) },
+ { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+ { "multicast", E1000_STAT(stats.mprc) },
+ { "collisions", E1000_STAT(stats.colc) },
+ { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
+ { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+ { "rx_crc_errors", E1000_STAT(stats.crcerrs) },
+ { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
+ { "rx_missed_errors", E1000_STAT(stats.mpc) },
+ { "tx_aborted_errors", E1000_STAT(stats.ecol) },
+ { "tx_carrier_errors", E1000_STAT(stats.tncrs) },
+ { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_window_errors", E1000_STAT(stats.latecol) },
+ { "tx_abort_late_coll", E1000_STAT(stats.latecol) },
+ { "tx_deferred_ok", E1000_STAT(stats.dc) },
+ { "tx_single_coll_ok", E1000_STAT(stats.scc) },
+ { "tx_multi_coll_ok", E1000_STAT(stats.mcc) },
+ { "tx_timeout_count", E1000_STAT(tx_timeout_count) },
+ { "tx_restart_queue", E1000_STAT(restart_queue) },
+ { "rx_long_length_errors", E1000_STAT(stats.roc) },
+ { "rx_short_length_errors", E1000_STAT(stats.ruc) },
+ { "rx_align_errors", E1000_STAT(stats.algnerrc) },
+ { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) },
+ { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) },
+ { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) },
+ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
+ { "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
+ { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
+ { "rx_long_byte_count", E1000_STAT(stats.gorcl) },
+ { "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
+ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
+ { "rx_header_split", E1000_STAT(rx_hdr_split) },
+ { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) },
+ { "tx_smbus", E1000_STAT(stats.mgptc) },
+ { "rx_smbus", E1000_STAT(stats.mgprc) },
+ { "dropped_smbus", E1000_STAT(stats.mgpdc) },
+ { "rx_dma_failed", E1000_STAT(rx_dma_failed) },
+ { "tx_dma_failed", E1000_STAT(tx_dma_failed) },
+};
+
+#define E1000_GLOBAL_STATS_LEN \
+ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN)
+static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register test (offline)", "Eeprom test (offline)",
+ "Interrupt test (offline)", "Loopback test (offline)",
+ "Link test (on/offline)"
+};
+#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
+
+static int e1000_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (hw->media_type == e1000_media_type_copper) {
+
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP);
+ if (hw->phy.type == e1000_phy_ife)
+ ecmd->supported &= ~SUPPORTED_1000baseT_Full;
+ ecmd->advertising = ADVERTISED_TP;
+
+ if (hw->mac.autoneg == 1) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ /* the e1000 autoneg seems to match ethtool nicely */
+ ecmd->advertising |= hw->phy.autoneg_advertised;
+ }
+
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = hw->phy.addr;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ } else {
+ ecmd->supported = (SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg);
+
+ ecmd->advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg);
+
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL;
+ }
+
+ if (er32(STATUS) & E1000_STATUS_LU) {
+
+ adapter->hw.mac.ops.get_link_up_info(hw, &adapter->link_speed,
+ &adapter->link_duplex);
+ ecmd->speed = adapter->link_speed;
+
+ /* unfortunately FULL_DUPLEX != DUPLEX_FULL
+ * and HALF_DUPLEX != DUPLEX_HALF */
+
+ if (adapter->link_duplex == FULL_DUPLEX)
+ ecmd->duplex = DUPLEX_FULL;
+ else
+ ecmd->duplex = DUPLEX_HALF;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+
+ ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) ||
+ hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ return 0;
+}
+
+static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
+{
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+
+ mac->autoneg = 0;
+
+ /* Fiber NICs only allow 1000 gbps Full duplex */
+ if ((adapter->hw.media_type == e1000_media_type_fiber) &&
+ spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+ ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
+ "configuration\n");
+ return -EINVAL;
+ }
+
+ switch (spddplx) {
+ case SPEED_10 + DUPLEX_HALF:
+ mac->forced_speed_duplex = ADVERTISE_10_HALF;
+ break;
+ case SPEED_10 + DUPLEX_FULL:
+ mac->forced_speed_duplex = ADVERTISE_10_FULL;
+ break;
+ case SPEED_100 + DUPLEX_HALF:
+ mac->forced_speed_duplex = ADVERTISE_100_HALF;
+ break;
+ case SPEED_100 + DUPLEX_FULL:
+ mac->forced_speed_duplex = ADVERTISE_100_FULL;
+ break;
+ case SPEED_1000 + DUPLEX_FULL:
+ mac->autoneg = 1;
+ adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
+ break;
+ case SPEED_1000 + DUPLEX_HALF: /* not supported */
+ default:
+ ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
+ "configuration\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int e1000_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* When SoL/IDER sessions are active, autoneg/speed/duplex
+ * cannot be changed */
+ if (e1000_check_reset_block(hw)) {
+ ndev_err(netdev, "Cannot change link "
+ "characteristics when SoL/IDER is active.\n");
+ return -EINVAL;
+ }
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ hw->mac.autoneg = 1;
+ if (hw->media_type == e1000_media_type_fiber)
+ hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg;
+ else
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
+ ecmd->advertising = hw->phy.autoneg_advertised;
+ } else {
+ if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return -EINVAL;
+ }
+ }
+
+ /* reset the link */
+
+ if (netif_running(adapter->netdev)) {
+ e1000e_down(adapter);
+ e1000e_up(adapter);
+ } else {
+ e1000e_reset(adapter);
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return 0;
+}
+
+static void e1000_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ pause->autoneg =
+ (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+ if (hw->mac.fc == e1000_fc_rx_pause) {
+ pause->rx_pause = 1;
+ } else if (hw->mac.fc == e1000_fc_tx_pause) {
+ pause->tx_pause = 1;
+ } else if (hw->mac.fc == e1000_fc_full) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+}
+
+static int e1000_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ int retval = 0;
+
+ adapter->fc_autoneg = pause->autoneg;
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (pause->rx_pause && pause->tx_pause)
+ hw->mac.fc = e1000_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->mac.fc = e1000_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->mac.fc = e1000_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->mac.fc = e1000_fc_none;
+
+ hw->mac.original_fc = hw->mac.fc;
+
+ if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+ hw->mac.fc = e1000_fc_default;
+ if (netif_running(adapter->netdev)) {
+ e1000e_down(adapter);
+ e1000e_up(adapter);
+ } else {
+ e1000e_reset(adapter);
+ }
+ } else {
+ retval = ((hw->media_type == e1000_media_type_fiber) ?
+ hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw));
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return retval;
+}
+
+static u32 e1000_get_rx_csum(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ return (adapter->flags & FLAG_RX_CSUM_ENABLED);
+}
+
+static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (data)
+ adapter->flags |= FLAG_RX_CSUM_ENABLED;
+ else
+ adapter->flags &= ~FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+ return 0;
+}
+
+static u32 e1000_get_tx_csum(struct net_device *netdev)
+{
+ return ((netdev->features & NETIF_F_HW_CSUM) != 0);
+}
+
+static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
+{
+ if (data)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+
+ return 0;
+}
+
+static int e1000_set_tso(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (data) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ }
+
+ ndev_info(netdev, "TSO is %s\n",
+ data ? "Enabled" : "Disabled");
+ adapter->flags |= FLAG_TSO_FORCE;
+ return 0;
+}
+
+static u32 e1000_get_msglevel(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ return adapter->msg_enable;
+}
+
+static void e1000_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ adapter->msg_enable = data;
+}
+
+static int e1000_get_regs_len(struct net_device *netdev)
+{
+#define E1000_REGS_LEN 32 /* overestimate */
+ return E1000_REGS_LEN * sizeof(u32);
+}
+
+static void e1000_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 *regs_buff = p;
+ u16 phy_data;
+ u8 revision_id;
+
+ memset(p, 0, E1000_REGS_LEN * sizeof(u32));
+
+ pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);
+
+ regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device;
+
+ regs_buff[0] = er32(CTRL);
+ regs_buff[1] = er32(STATUS);
+
+ regs_buff[2] = er32(RCTL);
+ regs_buff[3] = er32(RDLEN);
+ regs_buff[4] = er32(RDH);
+ regs_buff[5] = er32(RDT);
+ regs_buff[6] = er32(RDTR);
+
+ regs_buff[7] = er32(TCTL);
+ regs_buff[8] = er32(TDLEN);
+ regs_buff[9] = er32(TDH);
+ regs_buff[10] = er32(TDT);
+ regs_buff[11] = er32(TIDV);
+
+ regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
+ if (hw->phy.type == e1000_phy_m88) {
+ e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ regs_buff[13] = (u32)phy_data; /* cable length */
+ regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ regs_buff[17] = (u32)phy_data; /* extended 10bt distance */
+ regs_buff[18] = regs_buff[13]; /* cable polarity */
+ regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[20] = regs_buff[17]; /* polarity correction */
+ /* phy receive errors */
+ regs_buff[22] = adapter->phy_stats.receive_errors;
+ regs_buff[23] = regs_buff[13]; /* mdix mode */
+ }
+ regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */
+ e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+ regs_buff[24] = (u32)phy_data; /* phy local receiver status */
+ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
+}
+
+static int e1000_get_eeprom_len(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ return adapter->hw.nvm.word_size * 2;
+}
+
+static int e1000_get_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ int first_word;
+ int last_word;
+ int ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EINVAL;
+
+ eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16);
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+ eeprom_buff = kmalloc(sizeof(u16) *
+ (last_word - first_word + 1), GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+ ret_val = e1000_read_nvm(hw, first_word,
+ last_word - first_word + 1,
+ eeprom_buff);
+ } else {
+ 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)
+ break;
+ }
+ }
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < last_word - first_word + 1; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+ kfree(eeprom_buff);
+
+ return ret_val;
+}
+
+static int e1000_set_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ void *ptr;
+ int max_len;
+ int first_word;
+ int last_word;
+ int ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EOPNOTSUPP;
+
+ if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
+ return -EFAULT;
+
+ max_len = hw->nvm.word_size * 2;
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+ eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ ptr = (void *)eeprom_buff;
+
+ if (eeprom->offset & 1) {
+ /* need read/modify/write of first changed EEPROM word */
+ /* only the second byte of the word is being modified */
+ ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]);
+ ptr++;
+ }
+ if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0))
+ /* need read/modify/write of last changed EEPROM word */
+ /* only the first byte of the word is being modified */
+ ret_val = e1000_read_nvm(hw, last_word, 1,
+ &eeprom_buff[last_word - first_word]);
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < last_word - first_word + 1; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(ptr, bytes, eeprom->len);
+
+ for (i = 0; i < last_word - first_word + 1; i++)
+ eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
+ ret_val = e1000_write_nvm(hw, first_word,
+ last_word - first_word + 1, eeprom_buff);
+
+ /* Update the checksum over the first part of the EEPROM if needed
+ * and flush shadow RAM for 82573 controllers */
+ if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
+ (hw->mac.type == e1000_82573)))
+ e1000e_update_nvm_checksum(hw);
+
+ kfree(eeprom_buff);
+ return ret_val;
+}
+
+static void e1000_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ char firmware_version[32];
+ u16 eeprom_data;
+
+ strncpy(drvinfo->driver, e1000e_driver_name, 32);
+ strncpy(drvinfo->version, e1000e_driver_version, 32);
+
+ /* EEPROM image version # is reported as firmware version # for
+ * PCI-E controllers */
+ e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data);
+ sprintf(firmware_version, "%d.%d-%d",
+ (eeprom_data & 0xF000) >> 12,
+ (eeprom_data & 0x0FF0) >> 4,
+ eeprom_data & 0x000F);
+
+ strncpy(drvinfo->fw_version, firmware_version, 32);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ drvinfo->regdump_len = e1000_get_regs_len(netdev);
+ drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
+}
+
+static void e1000_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+
+ ring->rx_max_pending = E1000_MAX_RXD;
+ ring->tx_max_pending = E1000_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rx_ring->count;
+ ring->tx_pending = tx_ring->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int e1000_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_ring *tx_ring, *tx_old;
+ struct e1000_ring *rx_ring, *rx_old;
+ int err;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (netif_running(adapter->netdev))
+ e1000e_down(adapter);
+
+ tx_old = adapter->tx_ring;
+ rx_old = adapter->rx_ring;
+
+ err = -ENOMEM;
+ tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!tx_ring)
+ goto err_alloc_tx;
+
+ rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!rx_ring)
+ goto err_alloc_rx;
+
+ adapter->tx_ring = tx_ring;
+ adapter->rx_ring = rx_ring;
+
+ rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD);
+ rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD));
+ rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD);
+ tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD));
+ tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ if (netif_running(adapter->netdev)) {
+ /* Try to get new resources before deleting old */
+ err = e1000e_setup_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+ err = e1000e_setup_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ /* save the new, restore the old in order to free it,
+ * then restore the new back again */
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ e1000e_free_rx_resources(adapter);
+ e1000e_free_tx_resources(adapter);
+ kfree(tx_old);
+ kfree(rx_old);
+ adapter->rx_ring = rx_ring;
+ adapter->tx_ring = tx_ring;
+ err = e1000e_up(adapter);
+ if (err)
+ goto err_setup;
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return 0;
+err_setup_tx:
+ e1000e_free_rx_resources(adapter);
+err_setup_rx:
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ kfree(rx_ring);
+err_alloc_rx:
+ kfree(tx_ring);
+err_alloc_tx:
+ e1000e_up(adapter);
+err_setup:
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return err;
+}
+
+#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W)
+#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable) \
+{ \
+ u32 _pat; \
+ u32 _value; \
+ u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+ for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) { \
+ E1000_WRITE_REG_ARRAY(hw, reg, offset, \
+ (_test[_pat] & writeable)); \
+ _value = E1000_READ_REG_ARRAY(hw, reg, offset); \
+ if (_value != (_test[_pat] & writeable & mask)) { \
+ ndev_err(netdev, "pattern test reg %04X " \
+ "failed: got 0x%08X expected 0x%08X\n", \
+ reg + offset, \
+ value, (_test[_pat] & writeable & mask)); \
+ *data = reg; \
+ return 1; \
+ } \
+ } \
+}
+
+#define REG_SET_AND_CHECK(R, M, W) \
+{ \
+ u32 _value; \
+ __ew32(hw, R, W & M); \
+ _value = __er32(hw, R); \
+ if ((W & M) != (_value & M)) { \
+ ndev_err(netdev, "set/check reg %04X test failed: " \
+ "got 0x%08X expected 0x%08X\n", R, (_value & M), \
+ (W & M)); \
+ *data = R; \
+ return 1; \
+ } \
+}
+
+static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct net_device *netdev = adapter->netdev;
+ u32 value;
+ u32 before;
+ u32 after;
+ u32 i;
+ u32 toggle;
+
+ /* The status register is Read Only, so a write should fail.
+ * Some bits that get toggled are ignored.
+ */
+ switch (mac->type) {
+ /* there are several bits on newer hardware that are r/w */
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_80003es2lan:
+ toggle = 0x7FFFF3FF;
+ break;
+ case e1000_82573:
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ toggle = 0x7FFFF033;
+ break;
+ default:
+ toggle = 0xFFFFF833;
+ break;
+ }
+
+ before = er32(STATUS);
+ value = (er32(STATUS) & toggle);
+ ew32(STATUS, toggle);
+ after = er32(STATUS) & toggle;
+ if (value != after) {
+ ndev_err(netdev, "failed STATUS register test got: "
+ "0x%08X expected: 0x%08X\n", after, value);
+ *data = 1;
+ return 1;
+ }
+ /* restore previous status */
+ ew32(STATUS, before);
+
+ if ((mac->type != e1000_ich8lan) &&
+ (mac->type != e1000_ich9lan)) {
+ REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF);
+ }
+
+ REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF);
+ REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8);
+ REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
+ REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF);
+
+ REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000);
+
+ before = (((mac->type == e1000_ich8lan) ||
+ (mac->type == e1000_ich9lan)) ? 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))
+ REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
+ for (i = 0; i < mac->rar_entry_count; i++)
+ REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
+ 0x8003FFFF, 0xFFFFFFFF);
+
+ for (i = 0; i < mac->mta_reg_count; i++)
+ REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
+
+ *data = 0;
+ return 0;
+}
+
+static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
+{
+ u16 temp;
+ u16 checksum = 0;
+ u16 i;
+
+ *data = 0;
+ /* Read and add up the contents of the EEPROM */
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) {
+ *data = 1;
+ break;
+ }
+ checksum += temp;
+ }
+
+ /* If Checksum is not Correct return error else test passed */
+ if ((checksum != (u16) NVM_SUM) && !(*data))
+ *data = 2;
+
+ return *data;
+}
+
+static irqreturn_t e1000_test_intr(int irq, void *data)
+{
+ struct net_device *netdev = (struct net_device *) data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ adapter->test_icr |= er32(ICR);
+
+ return IRQ_HANDLED;
+}
+
+static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 mask;
+ u32 shared_int = 1;
+ u32 irq = adapter->pdev->irq;
+ int i;
+
+ *data = 0;
+
+ /* NOTE: we don't test MSI interrupts here, yet */
+ /* Hook up test interrupt handler just for this test */
+ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
+ netdev)) {
+ shared_int = 0;
+ } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+ netdev->name, netdev)) {
+ *data = 1;
+ return -1;
+ }
+ ndev_info(netdev, "testing %s interrupt\n",
+ (shared_int ? "shared" : "unshared"));
+
+ /* Disable all the interrupts */
+ ew32(IMC, 0xFFFFFFFF);
+ msleep(10);
+
+ /* Test each interrupt */
+ for (i = 0; i < 10; i++) {
+
+ if (((adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich9lan)) && i == 8)
+ continue;
+
+ /* Interrupt to test */
+ mask = 1 << i;
+
+ if (!shared_int) {
+ /* Disable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ ew32(IMC, mask);
+ ew32(ICS, mask);
+ msleep(10);
+
+ if (adapter->test_icr & mask) {
+ *data = 3;
+ break;
+ }
+ }
+
+ /* Enable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was not posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ ew32(IMS, mask);
+ ew32(ICS, mask);
+ msleep(10);
+
+ if (!(adapter->test_icr & mask)) {
+ *data = 4;
+ break;
+ }
+
+ if (!shared_int) {
+ /* Disable the other interrupts to be reported in
+ * the cause register and then force the other
+ * interrupts and see if any get posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ ew32(IMC, ~mask & 0x00007FFF);
+ ew32(ICS, ~mask & 0x00007FFF);
+ msleep(10);
+
+ if (adapter->test_icr) {
+ *data = 5;
+ break;
+ }
+ }
+ }
+
+ /* Disable all the interrupts */
+ ew32(IMC, 0xFFFFFFFF);
+ msleep(10);
+
+ /* Unhook test interrupt handler */
+ free_irq(irq, netdev);
+
+ return *data;
+}
+
+static void e1000_free_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+ struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ int i;
+
+ if (tx_ring->desc && tx_ring->buffer_info) {
+ for (i = 0; i < tx_ring->count; i++) {
+ if (tx_ring->buffer_info[i].dma)
+ pci_unmap_single(pdev,
+ tx_ring->buffer_info[i].dma,
+ tx_ring->buffer_info[i].length,
+ PCI_DMA_TODEVICE);
+ if (tx_ring->buffer_info[i].skb)
+ dev_kfree_skb(tx_ring->buffer_info[i].skb);
+ }
+ }
+
+ if (rx_ring->desc && rx_ring->buffer_info) {
+ for (i = 0; i < rx_ring->count; i++) {
+ if (rx_ring->buffer_info[i].dma)
+ pci_unmap_single(pdev,
+ rx_ring->buffer_info[i].dma,
+ 2048, PCI_DMA_FROMDEVICE);
+ if (rx_ring->buffer_info[i].skb)
+ dev_kfree_skb(rx_ring->buffer_info[i].skb);
+ }
+ }
+
+ if (tx_ring->desc) {
+ dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+ tx_ring->dma);
+ tx_ring->desc = NULL;
+ }
+ if (rx_ring->desc) {
+ dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+ rx_ring->dma);
+ rx_ring->desc = NULL;
+ }
+
+ kfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
+ kfree(rx_ring->buffer_info);
+ rx_ring->buffer_info = NULL;
+}
+
+static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+ struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
+ int size;
+ int i;
+ int ret_val;
+
+ /* Setup Tx descriptor ring and Tx buffers */
+
+ if (!tx_ring->count)
+ tx_ring->count = E1000_DEFAULT_TXD;
+
+ size = tx_ring->count * sizeof(struct e1000_buffer);
+ tx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
+ if (!tx_ring->buffer_info) {
+ ret_val = 1;
+ goto err_nomem;
+ }
+ memset(tx_ring->buffer_info, 0, size);
+
+ tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+ tx_ring->size = ALIGN(tx_ring->size, 4096);
+ tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+ &tx_ring->dma, GFP_KERNEL);
+ if (!tx_ring->desc) {
+ ret_val = 2;
+ goto err_nomem;
+ }
+ memset(tx_ring->desc, 0, tx_ring->size);
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ ew32(TDBAL,
+ ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+ ew32(TDBAH, ((u64) tx_ring->dma >> 32));
+ ew32(TDLEN,
+ tx_ring->count * sizeof(struct e1000_tx_desc));
+ ew32(TDH, 0);
+ ew32(TDT, 0);
+ ew32(TCTL,
+ E1000_TCTL_PSP | E1000_TCTL_EN |
+ E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+ E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+ for (i = 0; i < tx_ring->count; i++) {
+ struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+ struct sk_buff *skb;
+ unsigned int skb_size = 1024;
+
+ skb = alloc_skb(skb_size, GFP_KERNEL);
+ if (!skb) {
+ ret_val = 3;
+ goto err_nomem;
+ }
+ skb_put(skb, skb_size);
+ tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[i].length = skb->len;
+ tx_ring->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) {
+ ret_val = 4;
+ goto err_nomem;
+ }
+ tx_desc->buffer_addr = cpu_to_le64(
+ tx_ring->buffer_info[i].dma);
+ tx_desc->lower.data = cpu_to_le32(skb->len);
+ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
+ E1000_TXD_CMD_IFCS |
+ E1000_TXD_CMD_RPS);
+ tx_desc->upper.data = 0;
+ }
+
+ /* Setup Rx descriptor ring and Rx buffers */
+
+ if (!rx_ring->count)
+ rx_ring->count = E1000_DEFAULT_RXD;
+
+ size = rx_ring->count * sizeof(struct e1000_buffer);
+ rx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
+ if (!rx_ring->buffer_info) {
+ ret_val = 5;
+ goto err_nomem;
+ }
+ memset(rx_ring->buffer_info, 0, size);
+
+ rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+ rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+ &rx_ring->dma, GFP_KERNEL);
+ if (!rx_ring->desc) {
+ ret_val = 6;
+ goto err_nomem;
+ }
+ memset(rx_ring->desc, 0, rx_ring->size);
+ rx_ring->next_to_use = 0;
+ rx_ring->next_to_clean = 0;
+
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
+ ew32(RDBAH, ((u64) rx_ring->dma >> 32));
+ ew32(RDLEN, rx_ring->size);
+ ew32(RDH, 0);
+ ew32(RDT, 0);
+ rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ ew32(RCTL, rctl);
+
+ for (i = 0; i < rx_ring->count; i++) {
+ struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+ struct sk_buff *skb;
+
+ skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL);
+ if (!skb) {
+ ret_val = 7;
+ goto err_nomem;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ rx_ring->buffer_info[i].skb = skb;
+ rx_ring->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, 2048,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) {
+ ret_val = 8;
+ goto err_nomem;
+ }
+ rx_desc->buffer_addr =
+ cpu_to_le64(rx_ring->buffer_info[i].dma);
+ memset(skb->data, 0x00, skb->len);
+ }
+
+ return 0;
+
+err_nomem:
+ e1000_free_desc_rings(adapter);
+ return ret_val;
+}
+
+static void e1000_phy_disable_receiver(struct e1000_adapter *adapter)
+{
+ /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+ e1e_wphy(&adapter->hw, 29, 0x001F);
+ e1e_wphy(&adapter->hw, 30, 0x8FFC);
+ e1e_wphy(&adapter->hw, 29, 0x001A);
+ e1e_wphy(&adapter->hw, 30, 0x8FF0);
+}
+
+static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl_reg = 0;
+ u32 stat_reg = 0;
+
+ adapter->hw.mac.autoneg = 0;
+
+ if (adapter->hw.phy.type == e1000_phy_m88) {
+ /* Auto-MDI/MDIX Off */
+ e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+ /* reset to update Auto-MDI/MDIX */
+ e1e_wphy(hw, PHY_CONTROL, 0x9140);
+ /* autoneg off */
+ e1e_wphy(hw, PHY_CONTROL, 0x8140);
+ } else if (adapter->hw.phy.type == e1000_phy_gg82563)
+ e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
+
+ ctrl_reg = er32(CTRL);
+
+ if (adapter->hw.phy.type == e1000_phy_ife) {
+ /* force 100, set loopback */
+ e1e_wphy(hw, PHY_CONTROL, 0x6100);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 |/* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ } else {
+ /* force 1000, set loopback */
+ e1e_wphy(hw, PHY_CONTROL, 0x4140);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = er32(CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ }
+
+ if (adapter->hw.media_type == e1000_media_type_copper &&
+ adapter->hw.phy.type == e1000_phy_m88) {
+ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+ } else {
+ /* Set the ILOS bit on the fiber Nic if half duplex link is
+ * detected. */
+ stat_reg = er32(STATUS);
+ if ((stat_reg & E1000_STATUS_FD) == 0)
+ ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+ }
+
+ ew32(CTRL, ctrl_reg);
+
+ /* Disable the receiver on the PHY so when a cable is plugged in, the
+ * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+ */
+ if (adapter->hw.phy.type == e1000_phy_m88)
+ e1000_phy_disable_receiver(adapter);
+
+ udelay(500);
+
+ return 0;
+}
+
+static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl = er32(CTRL);
+ int link = 0;
+
+ /* special requirements for 82571/82572 fiber adapters */
+
+ /* jump through hoops to make sure link is up because serdes
+ * link is hardwired up */
+ ctrl |= E1000_CTRL_SLU;
+ ew32(CTRL, ctrl);
+
+ /* disable autoneg */
+ ctrl = er32(TXCW);
+ ctrl &= ~(1 << 31);
+ ew32(TXCW, ctrl);
+
+ link = (er32(STATUS) & E1000_STATUS_LU);
+
+ if (!link) {
+ /* set invert loss of signal */
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_ILOS;
+ ew32(CTRL, ctrl);
+ }
+
+ /* special write to serdes control register to enable SerDes analog
+ * loopback */
+#define E1000_SERDES_LB_ON 0x410
+ ew32(SCTL, E1000_SERDES_LB_ON);
+ msleep(10);
+
+ return 0;
+}
+
+/* only call this for fiber/serdes connections to es2lan */
+static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrlext = er32(CTRL_EXT);
+ u32 ctrl = er32(CTRL);
+
+ /* save CTRL_EXT to restore later, reuse an empty variable (unused
+ on mac_type 80003es2lan) */
+ adapter->tx_fifo_head = ctrlext;
+
+ /* clear the serdes mode bits, putting the device into mac loopback */
+ ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
+ ew32(CTRL_EXT, ctrlext);
+
+ /* force speed to 1000/FD, link up */
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX |
+ E1000_CTRL_SPD_1000 | E1000_CTRL_FD);
+ ew32(CTRL, ctrl);
+
+ /* set mac loopback */
+ ctrl = er32(RCTL);
+ ctrl |= E1000_RCTL_LBM_MAC;
+ ew32(RCTL, ctrl);
+
+ /* set testing mode parameters (no need to reset later) */
+#define KMRNCTRLSTA_OPMODE (0x1F << 16)
+#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582
+ ew32(KMRNCTRLSTA,
+ (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));
+
+ return 0;
+}
+
+static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
+
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes) {
+ switch (hw->mac.type) {
+ case e1000_80003es2lan:
+ return e1000_set_es2lan_mac_loopback(adapter);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ return e1000_set_82571_fiber_loopback(adapter);
+ break;
+ default:
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_LBM_TCVR;
+ ew32(RCTL, rctl);
+ return 0;
+ }
+ } else if (hw->media_type == e1000_media_type_copper) {
+ return e1000_integrated_phy_loopback(adapter);
+ }
+
+ return 7;
+}
+
+static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
+ u16 phy_reg;
+
+ rctl = er32(RCTL);
+ rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+ ew32(RCTL, rctl);
+
+ switch (hw->mac.type) {
+ case e1000_80003es2lan:
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes) {
+ /* restore CTRL_EXT, stealing space from tx_fifo_head */
+ ew32(CTRL_EXT,
+ adapter->tx_fifo_head);
+ adapter->tx_fifo_head = 0;
+ }
+ /* fall through */
+ case e1000_82571:
+ case e1000_82572:
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes) {
+#define E1000_SERDES_LB_OFF 0x400
+ ew32(SCTL, E1000_SERDES_LB_OFF);
+ msleep(10);
+ break;
+ }
+ /* Fall Through */
+ default:
+ hw->mac.autoneg = 1;
+ if (hw->phy.type == e1000_phy_gg82563)
+ e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180);
+ e1e_rphy(hw, PHY_CONTROL, &phy_reg);
+ if (phy_reg & MII_CR_LOOPBACK) {
+ phy_reg &= ~MII_CR_LOOPBACK;
+ e1e_wphy(hw, PHY_CONTROL, phy_reg);
+ e1000e_commit_phy(hw);
+ }
+ break;
+ }
+}
+
+static void e1000_create_lbtest_frame(struct sk_buff *skb,
+ unsigned int frame_size)
+{
+ memset(skb->data, 0xFF, frame_size);
+ frame_size &= ~1;
+ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+ memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+ memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int e1000_check_lbtest_frame(struct sk_buff *skb,
+ unsigned int frame_size)
+{
+ frame_size &= ~1;
+ if (*(skb->data + 3) == 0xFF)
+ if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+ (*(skb->data + frame_size / 2 + 12) == 0xAF))
+ return 0;
+ return 13;
+}
+
+static int e1000_run_loopback_test(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+ struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_hw *hw = &adapter->hw;
+ int i, j, k, l;
+ int lc;
+ int good_cnt;
+ int ret_val = 0;
+ unsigned long time;
+
+ ew32(RDT, rx_ring->count - 1);
+
+ /* Calculate the loop count based on the largest descriptor ring
+ * The idea is to wrap the largest ring a number of times using 64
+ * send/receive pairs during each loop
+ */
+
+ if (rx_ring->count <= tx_ring->count)
+ lc = ((tx_ring->count / 64) * 2) + 1;
+ else
+ lc = ((rx_ring->count / 64) * 2) + 1;
+
+ k = 0;
+ l = 0;
+ for (j = 0; j <= lc; j++) { /* loop count loop */
+ for (i = 0; i < 64; i++) { /* send the packets */
+ e1000_create_lbtest_frame(
+ tx_ring->buffer_info[i].skb, 1024);
+ pci_dma_sync_single_for_device(pdev,
+ tx_ring->buffer_info[k].dma,
+ tx_ring->buffer_info[k].length,
+ PCI_DMA_TODEVICE);
+ k++;
+ if (k == tx_ring->count)
+ k = 0;
+ }
+ ew32(TDT, k);
+ msleep(200);
+ time = jiffies; /* set the start time for the receive */
+ good_cnt = 0;
+ do { /* receive the sent packets */
+ pci_dma_sync_single_for_cpu(pdev,
+ rx_ring->buffer_info[l].dma, 2048,
+ PCI_DMA_FROMDEVICE);
+
+ ret_val = e1000_check_lbtest_frame(
+ rx_ring->buffer_info[l].skb, 1024);
+ if (!ret_val)
+ good_cnt++;
+ l++;
+ if (l == rx_ring->count)
+ l = 0;
+ /* time + 20 msecs (200 msecs on 2.4) is more than
+ * enough time to complete the receives, if it's
+ * exceeded, break and error off
+ */
+ } while ((good_cnt < 64) && !time_after(jiffies, time + 20));
+ if (good_cnt != 64) {
+ ret_val = 13; /* ret_val is the same as mis-compare */
+ break;
+ }
+ if (jiffies >= (time + 2)) {
+ ret_val = 14; /* error code for time out error */
+ break;
+ }
+ } /* end loop count loop */
+ return ret_val;
+}
+
+static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data)
+{
+ /* PHY loopback cannot be performed if SoL/IDER
+ * sessions are active */
+ if (e1000_check_reset_block(&adapter->hw)) {
+ ndev_err(adapter->netdev, "Cannot do PHY loopback test "
+ "when SoL/IDER is active.\n");
+ *data = 0;
+ goto out;
+ }
+
+ *data = e1000_setup_desc_rings(adapter);
+ if (data)
+ goto out;
+
+ *data = e1000_setup_loopback_test(adapter);
+ if (data)
+ goto err_loopback;
+
+ *data = e1000_run_loopback_test(adapter);
+ e1000_loopback_cleanup(adapter);
+
+err_loopback:
+ e1000_free_desc_rings(adapter);
+out:
+ return *data;
+}
+
+static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ *data = 0;
+ if (hw->media_type == e1000_media_type_internal_serdes) {
+ int i = 0;
+ hw->mac.serdes_has_link = 0;
+
+ /* On some blade server designs, link establishment
+ * could take as long as 2-3 minutes */
+ do {
+ hw->mac.ops.check_for_link(hw);
+ if (hw->mac.serdes_has_link)
+ return *data;
+ msleep(20);
+ } while (i++ < 3750);
+
+ *data = 1;
+ } else {
+ hw->mac.ops.check_for_link(hw);
+ if (hw->mac.autoneg)
+ msleep(4000);
+
+ if (!(er32(STATUS) &
+ E1000_STATUS_LU))
+ *data = 1;
+ }
+ return *data;
+}
+
+static int e1000e_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_TEST:
+ return E1000_TEST_LEN;
+ case ETH_SS_STATS:
+ return E1000_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void e1000_diag_test(struct net_device *netdev,
+ struct ethtool_test *eth_test, u64 *data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ u16 autoneg_advertised;
+ u8 forced_speed_duplex;
+ u8 autoneg;
+ bool if_running = netif_running(netdev);
+
+ set_bit(__E1000_TESTING, &adapter->state);
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ /* Offline tests */
+
+ /* save speed, duplex, autoneg settings */
+ autoneg_advertised = adapter->hw.phy.autoneg_advertised;
+ forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
+ autoneg = adapter->hw.mac.autoneg;
+
+ ndev_info(netdev, "offline testing starting\n");
+
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result */
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ if (if_running)
+ /* indicate we're in test mode */
+ dev_close(netdev);
+ else
+ e1000e_reset(adapter);
+
+ if (e1000_reg_test(adapter, &data[0]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000e_reset(adapter);
+ if (e1000_eeprom_test(adapter, &data[1]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000e_reset(adapter);
+ if (e1000_intr_test(adapter, &data[2]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000e_reset(adapter);
+ /* make sure the phy is powered up */
+ e1000e_power_up_phy(adapter);
+ if (e1000_loopback_test(adapter, &data[3]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* restore speed, duplex, autoneg settings */
+ adapter->hw.phy.autoneg_advertised = autoneg_advertised;
+ adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
+ adapter->hw.mac.autoneg = autoneg;
+
+ /* force this routine to wait until autoneg complete/timeout */
+ adapter->hw.phy.wait_for_link = 1;
+ e1000e_reset(adapter);
+ adapter->hw.phy.wait_for_link = 0;
+
+ clear_bit(__E1000_TESTING, &adapter->state);
+ if (if_running)
+ dev_open(netdev);
+ } else {
+ ndev_info(netdev, "online testing starting\n");
+ /* Online tests */
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* Online tests aren't run; pass by default */
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+
+ clear_bit(__E1000_TESTING, &adapter->state);
+ }
+ msleep_interruptible(4 * 1000);
+}
+
+static void e1000_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ if (!(adapter->flags & FLAG_HAS_WOL))
+ return;
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST |
+ WAKE_BCAST | WAKE_MAGIC;
+
+ /* apply any specific unsupported masks here */
+ if (adapter->flags & FLAG_NO_WAKE_UCAST) {
+ wol->supported &= ~WAKE_UCAST;
+
+ if (adapter->wol & E1000_WUFC_EX)
+ ndev_err(netdev, "Interface does not support "
+ "directed (unicast) frame wake-up packets\n");
+ }
+
+ if (adapter->wol & E1000_WUFC_EX)
+ wol->wolopts |= WAKE_UCAST;
+ if (adapter->wol & E1000_WUFC_MC)
+ wol->wolopts |= WAKE_MCAST;
+ if (adapter->wol & E1000_WUFC_BC)
+ wol->wolopts |= WAKE_BCAST;
+ if (adapter->wol & E1000_WUFC_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+static int e1000_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+
+ if (!(adapter->flags & FLAG_HAS_WOL))
+ return wol->wolopts ? -EOPNOTSUPP : 0;
+
+ /* these settings will always override what we currently have */
+ adapter->wol = 0;
+
+ if (wol->wolopts & WAKE_UCAST)
+ adapter->wol |= E1000_WUFC_EX;
+ if (wol->wolopts & WAKE_MCAST)
+ adapter->wol |= E1000_WUFC_MC;
+ if (wol->wolopts & WAKE_BCAST)
+ adapter->wol |= E1000_WUFC_BC;
+ if (wol->wolopts & WAKE_MAGIC)
+ adapter->wol |= E1000_WUFC_MAG;
+
+ return 0;
+}
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define E1000_ID_INTERVAL (HZ/4)
+
+/* bit defines for adapter->led_status */
+#define E1000_LED_ON 0
+
+static void e1000_led_blink_callback(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+ if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
+ adapter->hw.mac.ops.led_off(&adapter->hw);
+ else
+ adapter->hw.mac.ops.led_on(&adapter->hw);
+
+ mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
+}
+
+static int e1000_phys_id(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+ data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+ if (adapter->hw.phy.type == e1000_phy_ife) {
+ if (!adapter->blink_timer.function) {
+ init_timer(&adapter->blink_timer);
+ adapter->blink_timer.function =
+ e1000_led_blink_callback;
+ adapter->blink_timer.data = (unsigned long) adapter;
+ }
+ mod_timer(&adapter->blink_timer, jiffies);
+ msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ e1e_wphy(&adapter->hw,
+ IFE_PHY_SPECIAL_CONTROL_LED, 0);
+ } else {
+ e1000e_blink_led(&adapter->hw);
+ msleep_interruptible(data * 1000);
+ }
+
+ adapter->hw.mac.ops.led_off(&adapter->hw);
+ clear_bit(E1000_LED_ON, &adapter->led_status);
+ adapter->hw.mac.ops.cleanup_led(&adapter->hw);
+
+ return 0;
+}
+
+static int e1000_nway_reset(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ return 0;
+}
+
+static void e1000_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ int i;
+
+ e1000e_update_stats(adapter);
+ for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+ char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
+ data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+}
+
+static void e1000_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(data, *e1000_gstrings_test,
+ E1000_TEST_LEN*ETH_GSTRING_LEN);
+ break;
+ case ETH_SS_STATS:
+ for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, e1000_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static const struct ethtool_ops e1000_ethtool_ops = {
+ .get_settings = e1000_get_settings,
+ .set_settings = e1000_set_settings,
+ .get_drvinfo = e1000_get_drvinfo,
+ .get_regs_len = e1000_get_regs_len,
+ .get_regs = e1000_get_regs,
+ .get_wol = e1000_get_wol,
+ .set_wol = e1000_set_wol,
+ .get_msglevel = e1000_get_msglevel,
+ .set_msglevel = e1000_set_msglevel,
+ .nway_reset = e1000_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_eeprom_len = e1000_get_eeprom_len,
+ .get_eeprom = e1000_get_eeprom,
+ .set_eeprom = e1000_set_eeprom,
+ .get_ringparam = e1000_get_ringparam,
+ .set_ringparam = e1000_set_ringparam,
+ .get_pauseparam = e1000_get_pauseparam,
+ .set_pauseparam = e1000_set_pauseparam,
+ .get_rx_csum = e1000_get_rx_csum,
+ .set_rx_csum = e1000_set_rx_csum,
+ .get_tx_csum = e1000_get_tx_csum,
+ .set_tx_csum = e1000_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = e1000_set_tso,
+ .self_test = e1000_diag_test,
+ .get_strings = e1000_get_strings,
+ .phys_id = e1000_phys_id,
+ .get_ethtool_stats = e1000_get_ethtool_stats,
+ .get_sset_count = e1000e_get_sset_count,
+};
+
+void e1000e_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
+}
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
new file mode 100644
index 000000000000..aa82f1afb7fb
--- /dev/null
+++ b/drivers/net/e1000e/hw.h
@@ -0,0 +1,864 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <linux/types.h>
+
+struct e1000_hw;
+struct e1000_adapter;
+
+#include "defines.h"
+
+#define er32(reg) __er32(hw, E1000_##reg)
+#define ew32(reg,val) __ew32(hw, E1000_##reg, (val))
+#define e1e_flush() er32(STATUS)
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+ (writel((value), ((a)->hw_addr + reg + ((offset) << 2))))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+ (readl((a)->hw_addr + reg + ((offset) << 2)))
+
+enum e1e_registers {
+ E1000_CTRL = 0x00000, /* Device Control - RW */
+ E1000_STATUS = 0x00008, /* Device Status - RO */
+ E1000_EECD = 0x00010, /* EEPROM/Flash Control - RW */
+ E1000_EERD = 0x00014, /* EEPROM Read - RW */
+ E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */
+ E1000_FLA = 0x0001C, /* Flash Access - RW */
+ E1000_MDIC = 0x00020, /* MDI Control - RW */
+ E1000_SCTL = 0x00024, /* SerDes Control - RW */
+ E1000_FCAL = 0x00028, /* Flow Control Address Low - RW */
+ E1000_FCAH = 0x0002C, /* Flow Control Address High -RW */
+ E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */
+ E1000_FCT = 0x00030, /* Flow Control Type - RW */
+ E1000_VET = 0x00038, /* VLAN Ether Type - RW */
+ E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */
+ E1000_ITR = 0x000C4, /* Interrupt Throttling Rate - RW */
+ E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */
+ E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */
+ E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */
+ E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */
+ E1000_RCTL = 0x00100, /* RX Control - RW */
+ E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */
+ E1000_TXCW = 0x00178, /* TX Configuration Word - RW */
+ E1000_RXCW = 0x00180, /* RX Configuration Word - RO */
+ E1000_TCTL = 0x00400, /* TX Control - RW */
+ E1000_TCTL_EXT = 0x00404, /* Extended TX Control - RW */
+ E1000_TIPG = 0x00410, /* TX Inter-packet gap -RW */
+ E1000_AIT = 0x00458, /* Adaptive Interframe Spacing Throttle - RW */
+ E1000_LEDCTL = 0x00E00, /* LED Control - RW */
+ E1000_EXTCNF_CTRL = 0x00F00, /* Extended Configuration Control */
+ E1000_EXTCNF_SIZE = 0x00F08, /* Extended Configuration Size */
+ E1000_PHY_CTRL = 0x00F10, /* PHY Control Register in CSR */
+ E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */
+ E1000_PBS = 0x01008, /* Packet Buffer Size */
+ E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
+ E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */
+ E1000_FLOP = 0x0103C, /* FLASH Opcode Register */
+ E1000_ERT = 0x02008, /* Early Rx Threshold - RW */
+ E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */
+ E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */
+ E1000_PSRCTL = 0x02170, /* Packet Split Receive Control - RW */
+ E1000_RDBAL = 0x02800, /* RX Descriptor Base Address Low - RW */
+ E1000_RDBAH = 0x02804, /* RX Descriptor Base Address High - RW */
+ E1000_RDLEN = 0x02808, /* RX Descriptor Length - RW */
+ E1000_RDH = 0x02810, /* RX Descriptor Head - RW */
+ E1000_RDT = 0x02818, /* RX Descriptor Tail - RW */
+ E1000_RDTR = 0x02820, /* RX Delay Timer - RW */
+ E1000_RADV = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+
+/* Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ *
+ */
+#define E1000_RDBAL_REG(_n) (E1000_RDBAL + (_n << 8))
+ E1000_KABGTXD = 0x03004, /* AFE Band Gap Transmit Ref Data */
+ E1000_TDBAL = 0x03800, /* TX Descriptor Base Address Low - RW */
+ E1000_TDBAH = 0x03804, /* TX Descriptor Base Address High - RW */
+ E1000_TDLEN = 0x03808, /* TX Descriptor Length - RW */
+ E1000_TDH = 0x03810, /* TX Descriptor Head - RW */
+ E1000_TDT = 0x03818, /* TX Descriptor Tail - RW */
+ E1000_TIDV = 0x03820, /* TX Interrupt Delay Value - RW */
+ E1000_TXDCTL = 0x03828, /* TX Descriptor Control - RW */
+ E1000_TADV = 0x0382C, /* TX Interrupt Absolute Delay Val - RW */
+ E1000_TARC0 = 0x03840, /* TX Arbitration Count (0) */
+ E1000_TXDCTL1 = 0x03928, /* TX Descriptor Control (1) - RW */
+ E1000_TARC1 = 0x03940, /* TX Arbitration Count (1) */
+ E1000_CRCERRS = 0x04000, /* CRC Error Count - R/clr */
+ E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */
+ E1000_SYMERRS = 0x04008, /* Symbol Error Count - R/clr */
+ E1000_RXERRC = 0x0400C, /* Receive Error Count - R/clr */
+ E1000_MPC = 0x04010, /* Missed Packet Count - R/clr */
+ E1000_SCC = 0x04014, /* Single Collision Count - R/clr */
+ E1000_ECOL = 0x04018, /* Excessive Collision Count - R/clr */
+ E1000_MCC = 0x0401C, /* Multiple Collision Count - R/clr */
+ E1000_LATECOL = 0x04020, /* Late Collision Count - R/clr */
+ E1000_COLC = 0x04028, /* Collision Count - R/clr */
+ E1000_DC = 0x04030, /* Defer Count - R/clr */
+ E1000_TNCRS = 0x04034, /* TX-No CRS - R/clr */
+ E1000_SEC = 0x04038, /* Sequence Error Count - R/clr */
+ E1000_CEXTERR = 0x0403C, /* Carrier Extension Error Count - R/clr */
+ E1000_RLEC = 0x04040, /* Receive Length Error Count - R/clr */
+ E1000_XONRXC = 0x04048, /* XON RX Count - R/clr */
+ E1000_XONTXC = 0x0404C, /* XON TX Count - R/clr */
+ E1000_XOFFRXC = 0x04050, /* XOFF RX Count - R/clr */
+ E1000_XOFFTXC = 0x04054, /* XOFF TX Count - R/clr */
+ E1000_FCRUC = 0x04058, /* Flow Control RX Unsupported Count- R/clr */
+ E1000_PRC64 = 0x0405C, /* Packets RX (64 bytes) - R/clr */
+ E1000_PRC127 = 0x04060, /* Packets RX (65-127 bytes) - R/clr */
+ E1000_PRC255 = 0x04064, /* Packets RX (128-255 bytes) - R/clr */
+ E1000_PRC511 = 0x04068, /* Packets RX (255-511 bytes) - R/clr */
+ E1000_PRC1023 = 0x0406C, /* Packets RX (512-1023 bytes) - R/clr */
+ E1000_PRC1522 = 0x04070, /* Packets RX (1024-1522 bytes) - R/clr */
+ E1000_GPRC = 0x04074, /* Good Packets RX Count - R/clr */
+ E1000_BPRC = 0x04078, /* Broadcast Packets RX Count - R/clr */
+ E1000_MPRC = 0x0407C, /* Multicast Packets RX Count - R/clr */
+ E1000_GPTC = 0x04080, /* Good Packets TX Count - R/clr */
+ E1000_GORCL = 0x04088, /* Good Octets RX Count Low - R/clr */
+ E1000_GORCH = 0x0408C, /* Good Octets RX Count High - R/clr */
+ E1000_GOTCL = 0x04090, /* Good Octets TX Count Low - R/clr */
+ E1000_GOTCH = 0x04094, /* Good Octets TX Count High - R/clr */
+ E1000_RNBC = 0x040A0, /* RX No Buffers Count - R/clr */
+ E1000_RUC = 0x040A4, /* RX Undersize Count - R/clr */
+ E1000_RFC = 0x040A8, /* RX Fragment Count - R/clr */
+ E1000_ROC = 0x040AC, /* RX Oversize Count - R/clr */
+ E1000_RJC = 0x040B0, /* RX Jabber Count - R/clr */
+ E1000_MGTPRC = 0x040B4, /* Management Packets RX Count - R/clr */
+ E1000_MGTPDC = 0x040B8, /* Management Packets Dropped Count - R/clr */
+ E1000_MGTPTC = 0x040BC, /* Management Packets TX Count - R/clr */
+ E1000_TORL = 0x040C0, /* Total Octets RX Low - R/clr */
+ E1000_TORH = 0x040C4, /* Total Octets RX High - R/clr */
+ E1000_TOTL = 0x040C8, /* Total Octets TX Low - R/clr */
+ E1000_TOTH = 0x040CC, /* Total Octets TX High - R/clr */
+ E1000_TPR = 0x040D0, /* Total Packets RX - R/clr */
+ E1000_TPT = 0x040D4, /* Total Packets TX - R/clr */
+ E1000_PTC64 = 0x040D8, /* Packets TX (64 bytes) - R/clr */
+ E1000_PTC127 = 0x040DC, /* Packets TX (65-127 bytes) - R/clr */
+ E1000_PTC255 = 0x040E0, /* Packets TX (128-255 bytes) - R/clr */
+ E1000_PTC511 = 0x040E4, /* Packets TX (256-511 bytes) - R/clr */
+ E1000_PTC1023 = 0x040E8, /* Packets TX (512-1023 bytes) - R/clr */
+ E1000_PTC1522 = 0x040EC, /* Packets TX (1024-1522 Bytes) - R/clr */
+ E1000_MPTC = 0x040F0, /* Multicast Packets TX Count - R/clr */
+ E1000_BPTC = 0x040F4, /* Broadcast Packets TX Count - R/clr */
+ E1000_TSCTC = 0x040F8, /* TCP Segmentation Context TX - R/clr */
+ E1000_TSCTFC = 0x040FC, /* TCP Segmentation Context TX Fail - R/clr */
+ E1000_IAC = 0x04100, /* Interrupt Assertion Count */
+ E1000_ICRXPTC = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */
+ E1000_ICRXATC = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */
+ E1000_ICTXPTC = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */
+ E1000_ICTXATC = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */
+ E1000_ICTXQEC = 0x04118, /* Irq Cause Tx Queue Empty Count */
+ E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
+ E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
+ E1000_ICRXOC = 0x04124, /* Irq Cause Receiver Overrun Count */
+ E1000_RXCSUM = 0x05000, /* RX Checksum Control - RW */
+ E1000_RFCTL = 0x05008, /* Receive Filter Control*/
+ E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */
+ E1000_RA = 0x05400, /* Receive Address - RW Array */
+ E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */
+ E1000_WUC = 0x05800, /* Wakeup Control - RW */
+ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */
+ E1000_WUS = 0x05810, /* Wakeup Status - RO */
+ E1000_MANC = 0x05820, /* Management Control - RW */
+ E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */
+ E1000_HOST_IF = 0x08800, /* Host Interface */
+
+ E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
+ E1000_MANC2H = 0x05860, /* Management Control To Host - RW */
+ E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
+ E1000_GCR = 0x05B00, /* PCI-Ex Control */
+ E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */
+ E1000_SWSM = 0x05B50, /* SW Semaphore */
+ E1000_FWSM = 0x05B54, /* FW Semaphore */
+ E1000_HICR = 0x08F00, /* Host Inteface Control */
+};
+
+/* RSS registers */
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
+#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 IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX 0x0008
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK 0x7F
+#define IGP02E1000_AGC_RANGE 15
+
+/* manage.c */
+#define E1000_VFTA_ENTRY_SHIFT 5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+#define E1000_HICR_EN 0x01 /* Enable bit - RO */
+#define E1000_HICR_C 0x02 /* Driver sets this bit when done
+ * to put command in RAM */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET 0x80
+
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+
+/* nvm.c */
+#define E1000_STM_OPCODE 0xDB00
+
+#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED 0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
+#define IFE_PSC_FORCE_POLARITY 0x0020
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE 0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
+
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
+#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_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_FUNC_1 1
+
+enum e1000_mac_type {
+ e1000_82571,
+ e1000_82572,
+ e1000_82573,
+ e1000_80003es2lan,
+ e1000_ich8lan,
+ e1000_ich9lan,
+};
+
+enum e1000_media_type {
+ e1000_media_type_unknown = 0,
+ e1000_media_type_copper = 1,
+ e1000_media_type_fiber = 2,
+ e1000_media_type_internal_serdes = 3,
+ e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+ e1000_nvm_unknown = 0,
+ e1000_nvm_none,
+ e1000_nvm_eeprom_spi,
+ e1000_nvm_flash_hw,
+ e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+ e1000_nvm_override_none = 0,
+ e1000_nvm_override_spi_small,
+ e1000_nvm_override_spi_large
+};
+
+enum e1000_phy_type {
+ e1000_phy_unknown = 0,
+ e1000_phy_none,
+ e1000_phy_m88,
+ e1000_phy_igp,
+ e1000_phy_igp_2,
+ e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
+};
+
+enum e1000_bus_width {
+ e1000_bus_width_unknown = 0,
+ e1000_bus_width_pcie_x1,
+ e1000_bus_width_pcie_x2,
+ e1000_bus_width_pcie_x4 = 4,
+ e1000_bus_width_32,
+ e1000_bus_width_64,
+ e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity{
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+ e1000_fc_none = 0,
+ e1000_fc_rx_pause,
+ e1000_fc_tx_pause,
+ e1000_fc_full,
+ e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+ e1000_ms_hw_default = 0,
+ e1000_ms_force_master,
+ e1000_ms_force_slave,
+ e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+ e1000_smart_speed_default = 0,
+ e1000_smart_speed_on,
+ e1000_smart_speed_off
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ u16 length; /* Length of data DMAed into data buffer */
+ u16 csum; /* Packet checksum */
+ u8 status; /* Descriptor status */
+ u8 errors; /* Descriptor Errors */
+ u16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+ struct {
+ u64 buffer_addr;
+ u64 reserved;
+ } read;
+ struct {
+ struct {
+ u32 mrq; /* Multiple Rx Queues */
+ union {
+ u32 rss; /* RSS Hash */
+ struct {
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ u32 status_error; /* ext status/error */
+ u16 length;
+ u16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+ struct {
+ /* one buffer for protocol header(s), three data buffers */
+ u64 buffer_addr[MAX_PS_BUFFERS];
+ } read;
+ struct {
+ struct {
+ u32 mrq; /* Multiple Rx Queues */
+ union {
+ u32 rss; /* RSS Hash */
+ struct {
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ u32 status_error; /* ext status/error */
+ u16 length0; /* length of buffer 0 */
+ u16 vlan; /* VLAN tag */
+ } middle;
+ struct {
+ u16 header_status;
+ u16 length[3]; /* length of buffers 1-3 */
+ } upper;
+ u64 reserved;
+ } wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ u32 data;
+ struct {
+ u16 length; /* Data buffer length */
+ u8 cso; /* Checksum offset */
+ u8 cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 css; /* Checksum start */
+ u16 special;
+ } fields;
+ } upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+ union {
+ u32 ip_config;
+ struct {
+ u8 ipcss; /* IP checksum start */
+ u8 ipcso; /* IP checksum offset */
+ u16 ipcse; /* IP checksum end */
+ } ip_fields;
+ } lower_setup;
+ union {
+ u32 tcp_config;
+ struct {
+ u8 tucss; /* TCP checksum start */
+ u8 tucso; /* TCP checksum offset */
+ u16 tucse; /* TCP checksum end */
+ } tcp_fields;
+ } upper_setup;
+ u32 cmd_and_length;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 hdr_len; /* Header length */
+ u16 mss; /* Maximum segment size */
+ } fields;
+ } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+ u64 buffer_addr; /* Address of the descriptor's buffer address */
+ union {
+ u32 data;
+ struct {
+ u16 length; /* Data buffer length */
+ u8 typ_len_ext;
+ u8 cmd;
+ } flags;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 popts; /* Packet Options */
+ u16 special; /* */
+ } fields;
+ } upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+ u64 crcerrs;
+ u64 algnerrc;
+ u64 symerrs;
+ u64 rxerrc;
+ u64 mpc;
+ u64 scc;
+ u64 ecol;
+ u64 mcc;
+ u64 latecol;
+ u64 colc;
+ u64 dc;
+ u64 tncrs;
+ u64 sec;
+ u64 cexterr;
+ u64 rlec;
+ u64 xonrxc;
+ u64 xontxc;
+ u64 xoffrxc;
+ u64 xofftxc;
+ u64 fcruc;
+ u64 prc64;
+ u64 prc127;
+ u64 prc255;
+ u64 prc511;
+ u64 prc1023;
+ u64 prc1522;
+ u64 gprc;
+ u64 bprc;
+ u64 mprc;
+ u64 gptc;
+ u64 gorcl;
+ u64 gorch;
+ u64 gotcl;
+ u64 gotch;
+ u64 rnbc;
+ u64 ruc;
+ u64 rfc;
+ u64 roc;
+ u64 rjc;
+ u64 mgprc;
+ u64 mgpdc;
+ u64 mgptc;
+ u64 torl;
+ u64 torh;
+ u64 totl;
+ u64 toth;
+ u64 tpr;
+ u64 tpt;
+ u64 ptc64;
+ u64 ptc127;
+ u64 ptc255;
+ u64 ptc511;
+ u64 ptc1023;
+ u64 ptc1522;
+ u64 mptc;
+ u64 bptc;
+ u64 tsctc;
+ u64 tsctfc;
+ u64 iac;
+ u64 icrxptc;
+ u64 icrxatc;
+ u64 ictxptc;
+ u64 ictxatc;
+ u64 ictxqec;
+ u64 ictxqmtc;
+ u64 icrxdmtc;
+ u64 icrxoc;
+};
+
+struct e1000_phy_stats {
+ u32 idle_errors;
+ u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+ u32 signature;
+ u8 status;
+ u8 reserved0;
+ u16 vlan_id;
+ u32 reserved1;
+ u16 reserved2;
+ u8 reserved3;
+ u8 checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+ u8 command_id;
+ u8 command_length;
+ u8 command_options;
+ u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH 252
+struct e1000_host_command_info {
+ struct e1000_host_command_header command_header;
+ u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+ u8 command_id;
+ u8 checksum;
+ u16 reserved1;
+ u16 reserved2;
+ u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+ struct e1000_host_mng_command_header command_header;
+ u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+/* Function pointers and static data for the MAC. */
+struct e1000_mac_operations {
+ u32 mng_mode_enab;
+
+ s32 (*check_for_link)(struct e1000_hw *);
+ s32 (*cleanup_led)(struct e1000_hw *);
+ void (*clear_hw_cntrs)(struct e1000_hw *);
+ s32 (*get_bus_info)(struct e1000_hw *);
+ s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+ s32 (*led_on)(struct e1000_hw *);
+ s32 (*led_off)(struct e1000_hw *);
+ void (*mc_addr_list_update)(struct e1000_hw *, u8 *, u32, u32,
+ u32);
+ s32 (*reset_hw)(struct e1000_hw *);
+ s32 (*init_hw)(struct e1000_hw *);
+ s32 (*setup_link)(struct e1000_hw *);
+ s32 (*setup_physical_interface)(struct e1000_hw *);
+};
+
+/* Function pointers for the PHY. */
+struct e1000_phy_operations {
+ s32 (*acquire_phy)(struct e1000_hw *);
+ s32 (*check_reset_block)(struct e1000_hw *);
+ s32 (*commit_phy)(struct e1000_hw *);
+ s32 (*force_speed_duplex)(struct e1000_hw *);
+ s32 (*get_cfg_done)(struct e1000_hw *hw);
+ s32 (*get_cable_length)(struct e1000_hw *);
+ s32 (*get_phy_info)(struct e1000_hw *);
+ s32 (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
+ void (*release_phy)(struct e1000_hw *);
+ s32 (*reset_phy)(struct e1000_hw *);
+ s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
+ s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
+ s32 (*write_phy_reg)(struct e1000_hw *, u32, u16);
+};
+
+/* Function pointers for the NVM. */
+struct e1000_nvm_operations {
+ s32 (*acquire_nvm)(struct e1000_hw *);
+ s32 (*read_nvm)(struct e1000_hw *, u16, u16, u16 *);
+ void (*release_nvm)(struct e1000_hw *);
+ s32 (*update_nvm)(struct e1000_hw *);
+ s32 (*valid_led_default)(struct e1000_hw *, u16 *);
+ s32 (*validate_nvm)(struct e1000_hw *);
+ s32 (*write_nvm)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+ struct e1000_mac_operations ops;
+
+ u8 addr[6];
+ u8 perm_addr[6];
+
+ enum e1000_mac_type type;
+ enum e1000_fc_mode fc;
+ enum e1000_fc_mode original_fc;
+
+ u32 collision_delta;
+ u32 ledctl_default;
+ u32 ledctl_mode1;
+ u32 ledctl_mode2;
+ u32 max_frame_size;
+ u32 mc_filter_type;
+ u32 min_frame_size;
+ u32 tx_packet_delta;
+ u32 txcw;
+
+ u16 current_ifs_val;
+ u16 ifs_max_val;
+ u16 ifs_min_val;
+ u16 ifs_ratio;
+ u16 ifs_step_size;
+ u16 mta_reg_count;
+ u16 rar_entry_count;
+ u16 fc_high_water;
+ u16 fc_low_water;
+ u16 fc_pause_time;
+
+ u8 forced_speed_duplex;
+
+ bool arc_subsystem_valid;
+ bool autoneg;
+ bool autoneg_failed;
+ bool get_link_status;
+ bool in_ifs_mode;
+ bool serdes_has_link;
+ bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+ struct e1000_phy_operations ops;
+
+ enum e1000_phy_type type;
+
+ enum e1000_1000t_rx_status local_rx;
+ enum e1000_1000t_rx_status remote_rx;
+ enum e1000_ms_type ms_type;
+ enum e1000_ms_type original_ms_type;
+ enum e1000_rev_polarity cable_polarity;
+ enum e1000_smart_speed smart_speed;
+
+ u32 addr;
+ u32 id;
+ u32 reset_delay_us; /* in usec */
+ u32 revision;
+
+ u16 autoneg_advertised;
+ u16 autoneg_mask;
+ u16 cable_length;
+ u16 max_cable_length;
+ u16 min_cable_length;
+
+ u8 mdix;
+
+ bool disable_polarity_correction;
+ bool is_mdix;
+ bool polarity_correction;
+ bool speed_downgraded;
+ bool wait_for_link;
+};
+
+struct e1000_nvm_info {
+ struct e1000_nvm_operations ops;
+
+ enum e1000_nvm_type type;
+ enum e1000_nvm_override override;
+
+ u32 flash_bank_size;
+ u32 flash_base_addr;
+
+ u16 word_size;
+ u16 delay_usec;
+ u16 address_bits;
+ u16 opcode_bits;
+ u16 page_size;
+};
+
+struct e1000_bus_info {
+ enum e1000_bus_width width;
+
+ u16 func;
+};
+
+struct e1000_dev_spec_82571 {
+ bool laa_is_present;
+};
+
+struct e1000_shadow_ram {
+ u16 value;
+ bool modified;
+};
+
+#define E1000_ICH8_SHADOW_RAM_WORDS 2048
+
+struct e1000_dev_spec_ich8lan {
+ bool kmrn_lock_loss_workaround_enabled;
+ struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
+};
+
+struct e1000_hw {
+ struct e1000_adapter *adapter;
+
+ u8 __iomem *hw_addr;
+ u8 __iomem *flash_address;
+
+ struct e1000_mac_info mac;
+ struct e1000_phy_info phy;
+ struct e1000_nvm_info nvm;
+ struct e1000_bus_info bus;
+ struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+ union {
+ struct e1000_dev_spec_82571 e82571;
+ struct e1000_dev_spec_ich8lan ich8lan;
+ } dev_spec;
+
+ enum e1000_media_type media_type;
+};
+
+#ifdef DEBUG
+#define hw_dbg(hw, format, arg...) \
+ printk(KERN_DEBUG, "%s: " format, e1000e_get_hw_dev_name(hw), ##arg);
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct e1000_hw *hw, const char *format, ...)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
new file mode 100644
index 000000000000..8f8139de1f48
--- /dev/null
+++ b/drivers/net/e1000e/ich8lan.c
@@ -0,0 +1,2225 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 82562G-2 10/100 Network Connection
+ * 82562GT 10/100 Network Connection
+ * 82562GT-2 10/100 Network Connection
+ * 82562V 10/100 Network Connection
+ * 82562V-2 10/100 Network Connection
+ * 82566DC-2 Gigabit Network Connection
+ * 82566DC Gigabit Network Connection
+ * 82566DM-2 Gigabit Network Connection
+ * 82566DM Gigabit Network Connection
+ * 82566MC Gigabit Network Connection
+ * 82566MM Gigabit Network Connection
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+
+#define ICH_FLASH_READ_COMMAND_TIMEOUT 500
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT 10
+
+#define ICH_CYCLE_READ 0
+#define ICH_CYCLE_WRITE 2
+#define ICH_CYCLE_ERASE 3
+
+#define FLASH_GFPREG_BASE_MASK 0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT 12
+
+#define ICH_FLASH_SEG_SIZE_256 256
+#define ICH_FLASH_SEG_SIZE_4K 4096
+#define ICH_FLASH_SEG_SIZE_8K 8192
+#define ICH_FLASH_SEG_SIZE_64K 65536
+
+
+#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
+
+#define E1000_ICH_MNG_IAMT_MODE 0x2
+
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_OFF2 << 8) | \
+ (ID_LED_DEF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC000
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
+
+#define E1000_FEXTNVM_SW_CONFIG 1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
+
+#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES 7
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+ ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+ struct ich8_hsfsts {
+ u16 flcdone :1; /* bit 0 Flash Cycle Done */
+ u16 flcerr :1; /* bit 1 Flash Cycle Error */
+ u16 dael :1; /* bit 2 Direct Access error Log */
+ u16 berasesz :2; /* bit 4:3 Sector Erase Size */
+ u16 flcinprog :1; /* bit 5 flash cycle in Progress */
+ u16 reserved1 :2; /* bit 13:6 Reserved */
+ u16 reserved2 :6; /* bit 13:6 Reserved */
+ u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+ u16 flockdn :1; /* bit 15 Flash Config Lock-Down */
+ } hsf_status;
+ u16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+ struct ich8_hsflctl {
+ u16 flcgo :1; /* 0 Flash Cycle Go */
+ u16 flcycle :2; /* 2:1 Flash Cycle */
+ u16 reserved :5; /* 7:3 Reserved */
+ u16 fldbcount :2; /* 9:8 Flash Data Byte Count */
+ u16 flockdn :6; /* 15:10 Reserved */
+ } hsf_ctrl;
+ u16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+ struct ich8_flracc {
+ u32 grra :8; /* 0:7 GbE region Read Access */
+ u32 grwa :8; /* 8:15 GbE region Write Access */
+ u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */
+ u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */
+ } hsf_flregacc;
+ u16 regval;
+};
+
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ u32 offset, u8 byte);
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+ u16 *data);
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 size, u16 *data);
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+
+static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
+{
+ return readw(hw->flash_address + reg);
+}
+
+static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg)
+{
+ return readl(hw->flash_address + reg);
+}
+
+static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val)
+{
+ writew(val, hw->flash_address + reg);
+}
+
+static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+ writel(val, hw->flash_address + reg);
+}
+
+#define er16flash(reg) __er16flash(hw, (reg))
+#define er32flash(reg) __er32flash(hw, (reg))
+#define ew16flash(reg,val) __ew16flash(hw, (reg), (val))
+#define ew32flash(reg,val) __ew32flash(hw, (reg), (val))
+
+/**
+ * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 i = 0;
+
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->id = 0;
+ while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
+ (i++ < 100)) {
+ msleep(1);
+ ret_val = e1000e_get_phy_id(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Verify phy id */
+ switch (phy->id) {
+ case IGP03E1000_E_PHY_ID:
+ phy->type = e1000_phy_igp_3;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy->type = e1000_phy_ife;
+ phy->autoneg_mask = E1000_ALL_NOT_GIG;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific NVM parameters and function
+ * pointers.
+ **/
+static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 gfpreg;
+ u32 sector_base_addr;
+ u32 sector_end_addr;
+ u16 i;
+
+ /* Can't read flash registers if the register set isn't mapped.
+ */
+ if (!hw->flash_address) {
+ hw_dbg(hw, "ERROR: Flash registers not mapped\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ nvm->type = e1000_nvm_flash_sw;
+
+ gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+ /* sector_X_addr is a "sector"-aligned address (4096 bytes)
+ * Add 1 to sector_end_addr since this sector is included in
+ * the overall size. */
+ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+ /* flash_base_addr is byte-aligned */
+ nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+ /* find total size of the NVM, then cut in half since the total
+ * size represents two separate NVM banks. */
+ nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT;
+ nvm->flash_bank_size /= 2;
+ /* Adjust to word count */
+ nvm->flash_bank_size /= sizeof(u16);
+
+ nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
+
+ /* Clear shadow ram */
+ for (i = 0; i < nvm->word_size; i++) {
+ dev_spec->shadow_ram[i].modified = 0;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_mac_params_ich8lan - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific MAC parameters and function
+ * pointers.
+ **/
+static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+
+ /* Set media type function pointer */
+ hw->media_type = e1000_media_type_copper;
+
+ /* Set mta register count */
+ mac->mta_reg_count = 32;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+ if (mac->type == e1000_ich8lan)
+ mac->rar_entry_count--;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid = 1;
+
+ /* Enable PCS Lock-loss workaround for ICH8 */
+ if (mac->type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1);
+
+ return 0;
+}
+
+static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ s32 rc;
+
+ rc = e1000_init_mac_params_ich8lan(adapter);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_nvm_params_ich8lan(hw);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_phy_params_ich8lan(hw);
+ if (rc)
+ return rc;
+
+ if ((adapter->hw.mac.type == e1000_ich8lan) &&
+ (adapter->hw.phy.type == e1000_phy_igp_3))
+ adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+
+ return 0;
+}
+
+/**
+ * e1000_acquire_swflag_ich8lan - Acquire software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the software control flag for performing NVM and PHY
+ * operations. This is a function pointer entry point only called by
+ * read/write routines for the PHY and NVM parts.
+ **/
+static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+ u32 timeout = PHY_CFG_TIMEOUT;
+
+ while (timeout) {
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+ mdelay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_release_swflag_ich8lan - Release software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Releases the software control flag for performing NVM and PHY operations.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+}
+
+/**
+ * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Checks if firmware is blocking the reset of the PHY.
+ * This is a function pointer entry point only called by
+ * reset routines.
+ **/
+static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+ u32 fwsm;
+
+ fwsm = er32(FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
+ * @hw: pointer to the HW structure
+ *
+ * Forces the speed and duplex settings of the PHY.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ bool link;
+
+ if (phy->type != e1000_phy_ife) {
+ ret_val = e1000e_phy_force_speed_duplex_igp(hw);
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &data);
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+ if (ret_val)
+ return ret_val;
+
+ /* Disable MDI-X support for 10/100 */
+ ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IFE_PMC_AUTO_MDIX;
+ data &= ~IFE_PMC_FORCE_MDIX;
+
+ ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "IFE PMC: %X\n", data);
+
+ udelay(1);
+
+ if (phy->wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link)
+ hw_dbg(hw, "Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i;
+ u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
+ s32 ret_val;
+ u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+ u16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+ ret_val = e1000e_phy_hw_reset_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Initialize the PHY from the NVM on ICH platforms. This
+ * is needed due to an issue where the NVM configuration is
+ * not properly autoloaded after power transitions.
+ * Therefore, after each PHY reset, we will load the
+ * configuration data out of the NVM manually.
+ */
+ if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
+ struct e1000_adapter *adapter = hw->adapter;
+
+ /* Check if SW needs configure the PHY */
+ if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+ (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M))
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+ else
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+
+ data = er32(FEXTNVM);
+ if (!(data & sw_cfg_mask))
+ return 0;
+
+ /* Wait for basic configuration completes before proceeding*/
+ do {
+ data = er32(STATUS);
+ data &= E1000_STATUS_LAN_INIT_DONE;
+ udelay(100);
+ } while ((!data) && --loop);
+
+ /* If basic configuration is incomplete before the above loop
+ * count reaches 0, loading the configuration from NVM will
+ * leave the PHY in a bad state possibly resulting in no link.
+ */
+ if (loop == 0) {
+ hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
+ }
+
+ /* Clear the Init Done bit for the next init event */
+ data = er32(STATUS);
+ data &= ~E1000_STATUS_LAN_INIT_DONE;
+ ew32(STATUS, data);
+
+ /* Make sure HW does not configure LCD from PHY
+ * extended configuration before SW configuration */
+ data = er32(EXTCNF_CTRL);
+ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+ return 0;
+
+ cnf_size = er32(EXTCNF_SIZE);
+ cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+ cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+ if (!cnf_size)
+ return 0;
+
+ cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+ cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+ /* Configure LCD from extended configuration
+ * region. */
+
+ /* cnf_base_addr is in DWORD */
+ word_addr = (u16)(cnf_base_addr << 1);
+
+ for (i = 0; i < cnf_size; i++) {
+ ret_val = e1000_read_nvm(hw,
+ (word_addr + i * 2),
+ 1,
+ &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_nvm(hw,
+ (word_addr + i * 2 + 1),
+ 1,
+ &reg_addr);
+ if (ret_val)
+ return ret_val;
+
+ /* Save off the PHY page for future writes. */
+ if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+ phy_page = reg_data;
+ continue;
+ }
+
+ reg_addr |= phy_page;
+
+ ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
+ * @hw: pointer to the HW structure
+ *
+ * Populates "phy" structure with various feature states.
+ * This function is only called by other family-specific
+ * routines.
+ **/
+static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ bool link;
+
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ hw_dbg(hw, "Phy info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+ phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
+
+ if (phy->polarity_correction) {
+ ret_val = e1000_check_polarity_ife_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Polarity is forced */
+ phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+ }
+
+ ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+
+ phy->is_mdix = (data & IFE_PMC_MDIX_STATUS);
+
+ /* The following parameters are undefined for 10/100 operation. */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+ return 0;
+}
+
+/**
+ * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
+ * @hw: pointer to the HW structure
+ *
+ * Wrapper for calling the get_phy_info routines for the appropriate phy type.
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
+{
+ switch (hw->phy.type) {
+ case e1000_phy_ife:
+ return e1000_get_phy_info_ife_ich8lan(hw);
+ break;
+ case e1000_phy_igp_3:
+ return e1000e_get_phy_info_igp(hw);
+ break;
+ default:
+ break;
+ }
+
+ return -E1000_ERR_PHY_TYPE;
+}
+
+/**
+ * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
+ * @hw: pointer to the HW structure
+ *
+ * Polarity is determined on the polarity reveral feature being enabled.
+ * This function is only called by other family-specific
+ * routines.
+ **/
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, offset, mask;
+
+ /* Polarity is determined based on the reversal feature
+ * being enabled.
+ */
+ if (phy->polarity_correction) {
+ offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+ mask = IFE_PESC_POLARITY_REVERSED;
+ } else {
+ offset = IFE_PHY_SPECIAL_CONTROL;
+ mask = IFE_PSC_FORCE_POLARITY;
+ }
+
+ ret_val = e1e_rphy(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->cable_polarity = (phy_data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 phy_ctrl;
+ s32 ret_val = 0;
+ u16 data;
+
+ if (phy->type != e1000_phy_igp_3)
+ return ret_val;
+
+ phy_ctrl = er32(PHY_CTRL);
+
+ if (active) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers */
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D3 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 phy_ctrl;
+ s32 ret_val;
+ u16 data;
+
+ phy_ctrl = er32(PHY_CTRL);
+
+ if (!active) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers */
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_read_nvm_ich8lan - Read word(s) from the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to read.
+ * @words: Size of data to read in words
+ * @data: Pointer to the word(s) to read at offset.
+ *
+ * Reads a word(s) from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 act_offset;
+ s32 ret_val;
+ u16 i, word;
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Start with the bank offset, then add the relative offset. */
+ act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
+ ? nvm->flash_bank_size
+ : 0;
+ act_offset += offset;
+
+ for (i = 0; i < words; i++) {
+ if ((dev_spec->shadow_ram) &&
+ (dev_spec->shadow_ram[offset+i].modified)) {
+ data[i] = dev_spec->shadow_ram[offset+i].value;
+ } else {
+ ret_val = e1000_read_flash_word_ich8lan(hw,
+ act_offset + i,
+ &word);
+ if (ret_val)
+ break;
+ data[i] = word;
+ }
+ }
+
+ e1000_release_swflag_ich8lan(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_init_ich8lan - Initialize flash
+ * @hw: pointer to the HW structure
+ *
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ **/
+static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+ union ich8_hws_flash_status hsfsts;
+ s32 ret_val = -E1000_ERR_NVM;
+ s32 i = 0;
+
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+ /* Check if the flash descriptor is valid */
+ if (hsfsts.hsf_status.fldesvalid == 0) {
+ hw_dbg(hw, "Flash descriptor invalid. "
+ "SW Sequencing must be used.");
+ return -E1000_ERR_NVM;
+ }
+
+ /* Clear FCERR and DAEL in hw status by writing 1 */
+ hsfsts.hsf_status.flcerr = 1;
+ hsfsts.hsf_status.dael = 1;
+
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+ /* Either we should have a hardware SPI cycle in progress
+ * bit to check against, in order to start a new cycle or
+ * FDONE bit should be changed in the hardware so that it
+ * is 1 after harware reset, which can then be used as an
+ * indication whether a cycle is in progress or has been
+ * completed.
+ */
+
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ /* There is no cycle running at present,
+ * so we can start a cycle */
+ /* Begin by setting Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+ ret_val = 0;
+ } else {
+ /* otherwise poll for sometime so the current
+ * cycle has a chance to end before giving up. */
+ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+ hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ ret_val = 0;
+ break;
+ }
+ udelay(1);
+ }
+ if (ret_val == 0) {
+ /* Successful in waiting for previous cycle to timeout,
+ * now set the Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+ } else {
+ hw_dbg(hw, "Flash controller busy, cannot get access");
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ * @hw: pointer to the HW structure
+ * @timeout: maximum time to wait for completion
+ *
+ * This function starts a flash cycle and waits for its completion.
+ **/
+static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
+{
+ union ich8_hws_flash_ctrl hsflctl;
+ union ich8_hws_flash_status hsfsts;
+ s32 ret_val = -E1000_ERR_NVM;
+ u32 i = 0;
+
+ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcgo = 1;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ /* wait till FDONE bit is set to 1 */
+ do {
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcdone == 1)
+ break;
+ udelay(1);
+ } while (i++ < timeout);
+
+ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+ return 0;
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_word_ich8lan - Read word from flash
+ * @hw: pointer to the HW structure
+ * @offset: offset to data location
+ * @data: pointer to the location for storing the data
+ *
+ * Reads the flash word at offset into data. Offset is converted
+ * to bytes before read.
+ **/
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+ u16 *data)
+{
+ /* Must convert offset into bytes. */
+ offset <<= 1;
+
+ return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
+}
+
+/**
+ * e1000_read_flash_data_ich8lan - Read byte or word from NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte or word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: Pointer to the word to store the value read.
+ *
+ * Reads a byte or word from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 size, u16 *data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ u32 flash_data = 0;
+ s32 ret_val = -E1000_ERR_NVM;
+ u8 count = 0;
+
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != 0)
+ break;
+
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+ /* Check if FCERR is set to 1, if set to 1, clear it
+ * and try the whole sequence a few more times, else
+ * read in (shift in) the Flash Data0, the order is
+ * least significant byte first msb to lsb */
+ if (ret_val == 0) {
+ flash_data = er32flash(ICH_FLASH_FDATA0);
+ if (size == 1) {
+ *data = (u8)(flash_data & 0x000000FF);
+ } else if (size == 2) {
+ *data = (u16)(flash_data & 0x0000FFFF);
+ }
+ break;
+ } else {
+ /* If we've gotten here, then things are probably
+ * completely hosed, but if the error condition is
+ * detected, it won't hurt to give it another try...
+ * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ hw_dbg(hw, "Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_ich8lan - Write word(s) to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to write.
+ * @words: Size of data to write in words
+ * @data: Pointer to the word(s) to write at offset.
+ *
+ * Writes a byte or word to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ s32 ret_val;
+ u16 i;
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ for (i = 0; i < words; i++) {
+ dev_spec->shadow_ram[offset+i].modified = 1;
+ dev_spec->shadow_ram[offset+i].value = data[i];
+ }
+
+ e1000_release_swflag_ich8lan(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ * @hw: pointer to the HW structure
+ *
+ * The NVM checksum is updated by calling the generic update_nvm_checksum,
+ * which writes the checksum to the shadow ram. The changes in the shadow
+ * ram are then committed to the EEPROM by processing each bank at a time
+ * checking for the modified bit and writing only the pending changes.
+ * After a succesful commit, the shadow ram is cleared and is ready for
+ * future writes.
+ **/
+static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 i, act_offset, new_bank_offset, old_bank_offset;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1000e_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ return ret_val;;
+
+ if (nvm->type != e1000_nvm_flash_sw)
+ return ret_val;;
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return ret_val;;
+
+ /* We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written */
+ if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
+ new_bank_offset = nvm->flash_bank_size;
+ old_bank_offset = 0;
+ e1000_erase_flash_bank_ich8lan(hw, 1);
+ } else {
+ old_bank_offset = nvm->flash_bank_size;
+ new_bank_offset = 0;
+ e1000_erase_flash_bank_ich8lan(hw, 0);
+ }
+
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+ /* Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM */
+ if (dev_spec->shadow_ram[i].modified) {
+ data = dev_spec->shadow_ram[i].value;
+ } else {
+ e1000_read_flash_word_ich8lan(hw,
+ i + old_bank_offset,
+ &data);
+ }
+
+ /* If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress */
+ if (i == E1000_ICH_NVM_SIG_WORD)
+ data |= E1000_ICH_NVM_SIG_MASK;
+
+ /* Convert offset to bytes. */
+ act_offset = (i + new_bank_offset) << 1;
+
+ udelay(100);
+ /* Write the bytes to the new bank. */
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset,
+ (u8)data);
+ if (ret_val)
+ break;
+
+ udelay(100);
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset + 1,
+ (u8)(data >> 8));
+ if (ret_val)
+ break;
+ }
+
+ /* Don't bother writing the segment valid bits if sector
+ * programming failed. */
+ if (ret_val) {
+ hw_dbg(hw, "Flash commit failed.\n");
+ e1000_release_swflag_ich8lan(hw);
+ return ret_val;
+ }
+
+ /* Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b */
+ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+ e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+ data &= 0xBFFF;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset * 2 + 1,
+ (u8)(data >> 8));
+ if (ret_val) {
+ e1000_release_swflag_ich8lan(hw);
+ return ret_val;
+ }
+
+ /* And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase */
+ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+ if (ret_val) {
+ e1000_release_swflag_ich8lan(hw);
+ return ret_val;
+ }
+
+ /* Great! Everything worked, we can now clear the cached entries. */
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+ dev_spec->shadow_ram[i].modified = 0;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+ e1000_release_swflag_ich8lan(hw);
+
+ /* Reload the EEPROM, or else modifications will not appear
+ * until after the next adapter reset.
+ */
+ e1000e_reload_nvm(hw);
+ msleep(10);
+
+ return ret_val;
+}
+
+/**
+ * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ * If the bit is 0, that the EEPROM had been modified, but the checksum was not
+ * calculated, in which case we need to calculate the checksum and set bit 6.
+ **/
+static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 data;
+
+ /* Read 0x19 and check bit 6. If this bit is 0, the checksum
+ * needs to be fixed. This bit is an indication that the NVM
+ * was prepared by OEM software and did not calculate the
+ * checksum...a likely scenario.
+ */
+ ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
+ if (ret_val)
+ return ret_val;
+
+ if ((data & 0x40) == 0) {
+ data |= 0x40;
+ ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_update_nvm_checksum(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ * e1000_write_flash_data_ich8lan - Writes bytes to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte/word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: The byte(s) to write to the NVM.
+ *
+ * Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 size, u16 data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ u32 flash_data = 0;
+ s32 ret_val;
+ u8 count = 0;
+
+ if (size < 1 || size > 2 || data > size * 0xff ||
+ offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val)
+ break;
+
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size -1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+ if (size == 1)
+ flash_data = (u32)data & 0x00FF;
+ else
+ flash_data = (u32)data;
+
+ ew32flash(ICH_FLASH_FDATA0, flash_data);
+
+ /* check if FCERR is set to 1 , if set to 1, clear it
+ * and try the whole sequence a few more times else done */
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+ if (!ret_val)
+ break;
+
+ /* If we're here, then things are most likely
+ * completely hosed, but if the error condition
+ * is detected, it won't hurt to give it another
+ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* Repeat for some time before giving up. */
+ continue;
+ if (hsfsts.hsf_status.flcdone == 0) {
+ hw_dbg(hw, "Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_flash_byte_ich8lan - Write a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The index of the byte to read.
+ * @data: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 data)
+{
+ u16 word = (u16)data;
+
+ return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to write.
+ * @byte: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ * Goes through a retry algorithm before giving up.
+ **/
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ u32 offset, u8 byte)
+{
+ s32 ret_val;
+ u16 program_retries;
+
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (!ret_val)
+ return ret_val;
+
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset);
+ udelay(100);
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (!ret_val)
+ break;
+ }
+ if (program_retries == 100)
+ return -E1000_ERR_NVM;
+
+ return 0;
+}
+
+/**
+ * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ * @hw: pointer to the HW structure
+ * @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ * Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ * bank N is 4096 * N + flash_reg_addr.
+ **/
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ /* bank size is in 16bit words - adjust to bytes */
+ u32 flash_bank_size = nvm->flash_bank_size * 2;
+ s32 ret_val;
+ s32 count = 0;
+ s32 iteration;
+ s32 sector_size;
+ s32 j;
+
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+ /* Determine HW Sector size: Read BERASE bits of hw flash status
+ * register */
+ /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector
+ * can be calculated as = bank * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+ * as = bank * 4096
+ * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+ * (ich9 only, otherwise error condition)
+ * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+ */
+ switch (hsfsts.hsf_status.berasesz) {
+ case 0:
+ /* Hw sector size 256 */
+ sector_size = ICH_FLASH_SEG_SIZE_256;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+ break;
+ case 1:
+ sector_size = ICH_FLASH_SEG_SIZE_4K;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+ break;
+ case 2:
+ if (hw->mac.type == e1000_ich9lan) {
+ sector_size = ICH_FLASH_SEG_SIZE_8K;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
+ } else {
+ return -E1000_ERR_NVM;
+ }
+ break;
+ case 3:
+ sector_size = ICH_FLASH_SEG_SIZE_64K;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+ break;
+ default:
+ return -E1000_ERR_NVM;
+ }
+
+ /* Start with the base address, then add the sector offset. */
+ flash_linear_addr = hw->nvm.flash_base_addr;
+ flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
+
+ for (j = 0; j < iteration ; j++) {
+ do {
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Write a value 11 (block Erase) in Flash
+ * Cycle field in hw flash control */
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of an index within the
+ * block into Flash Linear address field in Flash
+ * Address.
+ */
+ flash_linear_addr += (j * sector_size);
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+ if (ret_val == 0)
+ break;
+
+ /* Check if FCERR is set to 1. If 1,
+ * clear it and try the whole sequence
+ * a few more times else Done */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* repeat for some time before
+ * giving up */
+ continue;
+ else if (hsfsts.hsf_status.flcdone == 0)
+ return ret_val;
+ } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_valid_led_default_ich8lan - Set the default LED settings
+ * @hw: pointer to the HW structure
+ * @data: Pointer to the LED settings
+ *
+ * Reads the LED default settings from the NVM to data. If the NVM LED
+ * settings is all 0's or F's, set the LED default to a valid LED default
+ * setting.
+ **/
+static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT_ICH8LAN;
+
+ return 0;
+}
+
+/**
+ * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
+ * @hw: pointer to the HW structure
+ *
+ * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ * register, so the the bus width is hard coded.
+ **/
+static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ s32 ret_val;
+
+ ret_val = e1000e_get_bus_info_pcie(hw);
+
+ /* ICH devices are "PCI Express"-ish. They have
+ * a configuration space, but do not contain
+ * PCI Express Capability registers, so bus width
+ * must be hardcoded.
+ */
+ if (bus->width == e1000_bus_width_unknown)
+ bus->width = e1000_bus_width_pcie_x1;
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_ich8lan - Reset the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Does a full reset of the hardware which includes a reset of the PHY and
+ * MAC.
+ **/
+static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+ u32 ctrl, icr, kab;
+ s32 ret_val;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000e_disable_pcie_master(hw);
+ if (ret_val) {
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+ }
+
+ hw_dbg(hw, "Masking off all interrupts\n");
+ ew32(IMC, 0xffffffff);
+
+ /* Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC
+ * with the global reset.
+ */
+ ew32(RCTL, 0);
+ ew32(TCTL, E1000_TCTL_PSP);
+ e1e_flush();
+
+ msleep(10);
+
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+ if (hw->mac.type == e1000_ich8lan) {
+ /* Set Tx and Rx buffer allocation to 8k apiece. */
+ ew32(PBA, E1000_PBA_8K);
+ /* Set Packet Buffer Size to 16k. */
+ ew32(PBS, E1000_PBS_16K);
+ }
+
+ ctrl = er32(CTRL);
+
+ if (!e1000_check_reset_block(hw)) {
+ /* PHY HW reset requires MAC CORE reset at the same
+ * time to make sure the interface between MAC and the
+ * external PHY is reset.
+ */
+ ctrl |= E1000_CTRL_PHY_RST;
+ }
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ hw_dbg(hw, "Issuing a global reset to ich8lan");
+ ew32(CTRL, (ctrl | E1000_CTRL_RST));
+ msleep(20);
+
+ ret_val = e1000e_get_auto_rd_done(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ hw_dbg(hw, "Auto Read Done did not complete\n");
+ }
+
+ ew32(IMC, 0xffffffff);
+ icr = er32(ICR);
+
+ kab = er32(KABGTXD);
+ kab |= E1000_KABGTXD_BGSQLBIAS;
+ ew32(KABGTXD, kab);
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_ich8lan - Initialize the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Prepares the hardware for transmit and receive by doing the following:
+ * - initialize hardware bits
+ * - initialize LED identification
+ * - setup receive address registers
+ * - setup flow control
+ * - setup transmit discriptors
+ * - clear statistics
+ **/
+static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 ctrl_ext, txdctl, snoop;
+ s32 ret_val;
+ u16 i;
+
+ e1000_initialize_hw_bits_ich8lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = e1000e_id_led_init(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error initializing identification LED\n");
+ return ret_val;
+ }
+
+ /* Setup the receive address. */
+ e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg(hw, "Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = e1000_setup_link_ich8lan(hw);
+
+ /* Set the transmit descriptor write-back policy for both queues */
+ txdctl = er32(TXDCTL);
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ ew32(TXDCTL, txdctl);
+ txdctl = er32(TXDCTL1);
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ ew32(TXDCTL1, txdctl);
+
+ /* ICH8 has opposite polarity of no_snoop bits.
+ * By default, we should use snoop behavior. */
+ if (mac->type == e1000_ich8lan)
+ snoop = PCIE_ICH8_SNOOP_ALL;
+ else
+ snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
+ e1000e_set_pcie_no_snoop(hw, snoop);
+
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ ew32(CTRL_EXT, ctrl_ext);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_ich8lan(hw);
+
+ return 0;
+}
+/**
+ * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ * @hw: pointer to the HW structure
+ *
+ * Sets/Clears required hardware bits necessary for correctly setting up the
+ * hardware for transmit and receive.
+ **/
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+ u32 reg;
+
+ /* Extended Device Control */
+ reg = er32(CTRL_EXT);
+ reg |= (1 << 22);
+ ew32(CTRL_EXT, reg);
+
+ /* Transmit Descriptor Control 0 */
+ reg = er32(TXDCTL);
+ reg |= (1 << 22);
+ ew32(TXDCTL, reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = er32(TXDCTL1);
+ reg |= (1 << 22);
+ ew32(TXDCTL1, reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = er32(TARC0);
+ if (hw->mac.type == e1000_ich8lan)
+ reg |= (1 << 28) | (1 << 29);
+ reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+ ew32(TARC0, reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = er32(TARC1);
+ if (er32(TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ reg |= (1 << 24) | (1 << 26) | (1 << 30);
+ ew32(TARC1, reg);
+
+ /* Device Status */
+ if (hw->mac.type == e1000_ich8lan) {
+ reg = er32(STATUS);
+ reg &= ~(1 << 31);
+ ew32(STATUS, reg);
+ }
+}
+
+/**
+ * e1000_setup_link_ich8lan - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+
+ if (e1000_check_reset_block(hw))
+ return 0;
+
+ /* ICH parts do not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ if (mac->fc == e1000_fc_default)
+ mac->fc = e1000_fc_full;
+
+ mac->original_fc = mac->fc;
+
+ hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
+
+ /* Continue to configure the copper link. */
+ ret_val = e1000_setup_copper_link_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ ew32(FCTTV, mac->fc_pause_time);
+
+ return e1000e_set_fc_watermarks(hw);
+}
+
+/**
+ * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ * @hw: pointer to the HW structure
+ *
+ * Configures the kumeran interface to the PHY to wait the appropriate time
+ * when polling the PHY, then call the generic setup_copper_link to finish
+ * configuring the copper link.
+ **/
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+ u16 reg_data;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ /* Set the mac to wait the maximum time between each iteration
+ * and increase the max iterations when polling the phy;
+ * this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->phy.type == e1000_phy_igp_3) {
+ ret_val = e1000e_copper_link_setup_igp(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return e1000e_setup_copper_link(hw);
+}
+
+/**
+ * e1000_get_link_up_info_ich8lan - Get current link speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to store current link speed
+ * @duplex: pointer to store the current link duplex
+ *
+ * Calls the generic get_speed_and_duplex to retreive the current link
+ * information and then calls the Kumeran lock loss workaround for links at
+ * gigabit speeds.
+ **/
+static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
+ u16 *duplex)
+{
+ s32 ret_val;
+
+ ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
+ if (ret_val)
+ return ret_val;
+
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3) &&
+ (*speed == SPEED_1000)) {
+ ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ * @hw: pointer to the HW structure
+ *
+ * Work-around for 82566 Kumeran PCS lock loss:
+ * On link status change (i.e. PCI reset, speed change) and link is up and
+ * speed is gigabit-
+ * 0) if workaround is optionally disabled do nothing
+ * 1) wait 1ms for Kumeran link to come up
+ * 2) check Kumeran Diagnostic register PCS lock loss bit
+ * 3) if not set the link is locked (all is good), otherwise...
+ * 4) reset the PHY
+ * 5) repeat up to 10 times
+ * Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 phy_ctrl;
+ s32 ret_val;
+ u16 i, data;
+ bool link;
+
+ if (!dev_spec->kmrn_lock_loss_workaround_enabled)
+ return 0;
+
+ /* Make sure link is up before proceeding. If not just return.
+ * Attempting this while link is negotiating fouled up link
+ * stability */
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (!link)
+ return 0;
+
+ for (i = 0; i < 10; i++) {
+ /* read once to clear */
+ ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ return ret_val;
+ /* and again to get new status */
+ ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* check for PCS lock */
+ if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
+ return 0;
+
+ /* Issue PHY reset */
+ e1000_phy_hw_reset(hw);
+ mdelay(5);
+ }
+ /* Disable GigE link negotiation */
+ phy_ctrl = er32(PHY_CTRL);
+ phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* Call gig speed drop workaround on Giga disable before accessing
+ * any PHY registers */
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* unable to acquire PCS lock */
+ return -E1000_ERR_PHY;
+}
+
+/**
+ * e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state
+ * @hw: pointer to the HW structure
+ * @state: boolean value used to set the current Kumaran workaround state
+ *
+ * If ICH8, set the current Kumeran workaround state (enabled - TRUE
+ * /disabled - FALSE).
+ **/
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ bool state)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+
+ if (hw->mac.type != e1000_ich8lan) {
+ hw_dbg(hw, "Workaround applies to ICH8 only.\n");
+ return;
+ }
+
+ dev_spec->kmrn_lock_loss_workaround_enabled = state;
+}
+
+/**
+ * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ * @hw: pointer to the HW structure
+ *
+ * Workaround for 82566 power-down on D3 entry:
+ * 1) disable gigabit link
+ * 2) write VR power-down enable
+ * 3) read it back
+ * Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+ u32 reg;
+ u16 data;
+ u8 retry = 0;
+
+ if (hw->phy.type != e1000_phy_igp_3)
+ return;
+
+ /* Try the workaround twice (if needed) */
+ do {
+ /* Disable link */
+ reg = er32(PHY_CTRL);
+ reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ ew32(PHY_CTRL, reg);
+
+ /* Call gig speed drop workaround on Giga disable before
+ * accessing any PHY registers */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* Write VR power-down enable */
+ e1e_rphy(hw, IGP3_VR_CTRL, &data);
+ data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+ /* Read it back and test */
+ e1e_rphy(hw, IGP3_VR_CTRL, &data);
+ data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+ break;
+
+ /* Issue PHY reset and repeat at most one more time */
+ reg = er32(CTRL);
+ ew32(CTRL, reg | E1000_CTRL_PHY_RST);
+ retry++;
+ } while (retry);
+}
+
+/**
+ * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ * @hw: pointer to the HW structure
+ *
+ * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ * LPLU, Giga disable, MDIC PHY reset):
+ * 1) Set Kumeran Near-end loopback
+ * 2) Clear Kumeran Near-end loopback
+ * Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 reg_data;
+
+ if ((hw->mac.type != e1000_ich8lan) ||
+ (hw->phy.type != e1000_phy_igp_3))
+ return;
+
+ ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ &reg_data);
+ if (ret_val)
+ return;
+ reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+ if (ret_val)
+ return;
+ reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+}
+
+/**
+ * e1000_cleanup_led_ich8lan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ **/
+static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+ if (hw->phy.type == e1000_phy_ife)
+ return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
+
+ ew32(LEDCTL, hw->mac.ledctl_default);
+ return 0;
+}
+
+/**
+ * e1000_led_on_ich8lan - Turn LED's on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LED's.
+ **/
+static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
+{
+ if (hw->phy.type == e1000_phy_ife)
+ return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+
+ ew32(LEDCTL, hw->mac.ledctl_mode2);
+ return 0;
+}
+
+/**
+ * e1000_led_off_ich8lan - Turn LED's off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LED's.
+ **/
+static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
+{
+ if (hw->phy.type == e1000_phy_ife)
+ return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+
+ ew32(LEDCTL, hw->mac.ledctl_mode1);
+ return 0;
+}
+
+/**
+ * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears hardware counters specific to the silicon family and calls
+ * clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ e1000e_clear_hw_cntrs_base(hw);
+
+ temp = er32(ALGNERRC);
+ temp = er32(RXERRC);
+ temp = er32(TNCRS);
+ temp = er32(CEXTERR);
+ temp = er32(TSCTC);
+ temp = er32(TSCTFC);
+
+ temp = er32(MGTPRC);
+ temp = er32(MGTPDC);
+ temp = er32(MGTPTC);
+
+ temp = er32(IAC);
+ temp = er32(ICRXOC);
+
+}
+
+static struct e1000_mac_operations ich8_mac_ops = {
+ .mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+ .check_for_link = e1000e_check_for_copper_link,
+ .cleanup_led = e1000_cleanup_led_ich8lan,
+ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan,
+ .get_bus_info = e1000_get_bus_info_ich8lan,
+ .get_link_up_info = e1000_get_link_up_info_ich8lan,
+ .led_on = e1000_led_on_ich8lan,
+ .led_off = e1000_led_off_ich8lan,
+ .mc_addr_list_update = e1000e_mc_addr_list_update_generic,
+ .reset_hw = e1000_reset_hw_ich8lan,
+ .init_hw = e1000_init_hw_ich8lan,
+ .setup_link = e1000_setup_link_ich8lan,
+ .setup_physical_interface= e1000_setup_copper_link_ich8lan,
+};
+
+static struct e1000_phy_operations ich8_phy_ops = {
+ .acquire_phy = e1000_acquire_swflag_ich8lan,
+ .check_reset_block = e1000_check_reset_block_ich8lan,
+ .commit_phy = NULL,
+ .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan,
+ .get_cfg_done = e1000e_get_cfg_done,
+ .get_cable_length = e1000e_get_cable_length_igp_2,
+ .get_phy_info = e1000_get_phy_info_ich8lan,
+ .read_phy_reg = e1000e_read_phy_reg_igp,
+ .release_phy = e1000_release_swflag_ich8lan,
+ .reset_phy = e1000_phy_hw_reset_ich8lan,
+ .set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan,
+ .set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan,
+ .write_phy_reg = e1000e_write_phy_reg_igp,
+};
+
+static struct e1000_nvm_operations ich8_nvm_ops = {
+ .acquire_nvm = e1000_acquire_swflag_ich8lan,
+ .read_nvm = e1000_read_nvm_ich8lan,
+ .release_nvm = e1000_release_swflag_ich8lan,
+ .update_nvm = e1000_update_nvm_checksum_ich8lan,
+ .valid_led_default = e1000_valid_led_default_ich8lan,
+ .validate_nvm = e1000_validate_nvm_checksum_ich8lan,
+ .write_nvm = e1000_write_nvm_ich8lan,
+};
+
+struct e1000_info e1000_ich8_info = {
+ .mac = e1000_ich8lan,
+ .flags = FLAG_HAS_WOL
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_FLASH
+ | FLAG_APME_IN_WUC,
+ .pba = 8,
+ .get_invariants = e1000_get_invariants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &ich8_nvm_ops,
+};
+
+struct e1000_info e1000_ich9_info = {
+ .mac = e1000_ich9lan,
+ .flags = FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_WOL
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_ERT
+ | FLAG_HAS_FLASH
+ | FLAG_APME_IN_WUC,
+ .pba = 10,
+ .get_invariants = e1000_get_invariants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &ich8_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
new file mode 100644
index 000000000000..0bdeca30c75f
--- /dev/null
+++ b/drivers/net/e1000e/lib.c
@@ -0,0 +1,2493 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+enum e1000_mng_mode {
+ e1000_mng_mode_none = 0,
+ e1000_mng_mode_asf,
+ e1000_mng_mode_pt,
+ e1000_mng_mode_ipmi,
+ e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG 0x20000000
+
+#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management
+ * Technology signature */
+
+/**
+ * e1000e_get_bus_info_pcie - Get PCIe bus information
+ * @hw: pointer to the HW structure
+ *
+ * Determines and stores the system bus information for a particular
+ * network interface. The following bus information is determined and stored:
+ * bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ struct e1000_adapter *adapter = hw->adapter;
+ u32 status;
+ u16 pcie_link_status, pci_header_type, cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset) {
+ bus->width = e1000_bus_width_unknown;
+ } else {
+ pci_read_config_word(adapter->pdev,
+ cap_offset + PCIE_LINK_STATUS,
+ &pcie_link_status);
+ bus->width = (enum e1000_bus_width)((pcie_link_status &
+ PCIE_LINK_WIDTH_MASK) >>
+ PCIE_LINK_WIDTH_SHIFT);
+ }
+
+ pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER,
+ &pci_header_type);
+ if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+ status = er32(STATUS);
+ bus->func = (status & E1000_STATUS_FUNC_MASK)
+ >> E1000_STATUS_FUNC_SHIFT;
+ } else {
+ bus->func = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_write_vfta - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: register offset in VLAN filter table
+ * @value: register value written to VLAN filter table
+ *
+ * Writes value at the given offset in the register array which stores
+ * the VLAN filter table.
+ **/
+void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+ e1e_flush();
+}
+
+/**
+ * e1000e_init_rx_addrs - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+ u32 i;
+
+ /* Setup the receive address */
+ hw_dbg(hw, "Programming MAC Address into RAR[0]\n");
+
+ e1000e_rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0);
+ e1e_flush();
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0);
+ e1e_flush();
+ }
+}
+
+/**
+ * e1000e_rar_set - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr.
+ **/
+void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+ u32 rar_low, rar_high;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((u32) addr[0] |
+ ((u32) addr[1] << 8) |
+ ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+ rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+ rar_high |= E1000_RAH_AV;
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
+}
+
+/**
+ * e1000_mta_set - Set multicast filter table address
+ * @hw: pointer to the HW structure
+ * @hash_value: determines the MTA register and bit to set
+ *
+ * The multicast table address is a register array of 32-bit registers.
+ * The hash_value is used to determine what register the bit is in, the
+ * current value is read, the new bit is OR'd in and the new value is
+ * written back into the register.
+ **/
+static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+ u32 hash_bit, hash_reg, mta;
+
+ /* The MTA is a register array of 32-bit registers. It is
+ * treated like an array of (32*mta_reg_count) bits. We want to
+ * set bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The (hw->mac.mta_reg_count - 1) serves as a
+ * mask to bits 31:5 of the hash value which gives us the
+ * register we're modifying. The hash bit within that register
+ * is determined by the lower 5 bits of the hash value.
+ */
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+ mta |= (1 << hash_bit);
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+ e1e_flush();
+}
+
+/**
+ * e1000_hash_mc_addr - Generate a multicast hash value
+ * @hw: pointer to the HW structure
+ * @mc_addr: pointer to a multicast address
+ *
+ * Generates a multicast address hash value which is used to determine
+ * the multicast filter table array address and new table value. See
+ * e1000_mta_set_generic()
+ **/
+static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+ u32 hash_value, hash_mask;
+ u8 bit_shift = 0;
+
+ /* Register count multiplied by bits per register */
+ hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+ /* For a mc_filter_type of 0, bit_shift is the number of left-shifts
+ * where 0xFF would still fall within the hash mask. */
+ while (hash_mask >> bit_shift != 0xFF)
+ bit_shift++;
+
+ /* The portion of the address that is used for the hash table
+ * is determined by the mc_filter_type setting.
+ * The algorithm is such that there is a total of 8 bits of shifting.
+ * The bit_shift for a mc_filter_type of 0 represents the number of
+ * left-shifts where the MSB of mc_addr[5] would still fall within
+ * the hash_mask. Case 0 does this exactly. Since there are a total
+ * of 8 bits of shifting, then mc_addr[4] will shift right the
+ * remaining number of bits. Thus 8 - bit_shift. The rest of the
+ * cases are a variation of this algorithm...essentially raising the
+ * number of bits to shift mc_addr[5] left, while still keeping the
+ * 8-bit shifting total.
+ */
+ /* For example, given the following Destination MAC Address and an
+ * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+ * we can see that the bit_shift for case 0 is 4. These are the hash
+ * values resulting from each mc_filter_type...
+ * [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ *
+ * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+ * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+ * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+ * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+ */
+ switch (hw->mac.mc_filter_type) {
+ default:
+ case 0:
+ break;
+ case 1:
+ bit_shift += 1;
+ break;
+ case 2:
+ bit_shift += 2;
+ break;
+ case 3:
+ bit_shift += 4;
+ break;
+ }
+
+ hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+ (((u16) mc_addr[5]) << bit_shift)));
+
+ return hash_value;
+}
+
+/**
+ * e1000e_mc_addr_list_update_generic - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @rar_used_count: the first RAR register free to program
+ * @rar_count: total number of supported Receive Address Registers
+ *
+ * Updates the Receive Address Registers and Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ * The parameter rar_count will usually be hw->mac.rar_entry_count
+ * unless there are workarounds that change this.
+ **/
+void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count,
+ u32 rar_used_count, u32 rar_count)
+{
+ u32 hash_value;
+ u32 i;
+
+ /* Load the first set of multicast addresses into the exact
+ * filters (RAR). If there are not enough to fill the RAR
+ * array, clear the filters.
+ */
+ for (i = rar_used_count; i < rar_count; i++) {
+ if (mc_addr_count) {
+ e1000e_rar_set(hw, mc_addr_list, i);
+ mc_addr_count--;
+ mc_addr_list += ETH_ALEN;
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
+ e1e_flush();
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
+ e1e_flush();
+ }
+ }
+
+ /* Clear the old settings from the MTA */
+ hw_dbg(hw, "Clearing MTA\n");
+ for (i = 0; i < hw->mac.mta_reg_count; i++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+ e1e_flush();
+ }
+
+ /* Load any remaining multicast addresses into the hash table. */
+ for (; mc_addr_count > 0; mc_addr_count--) {
+ hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
+ hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
+ e1000_mta_set(hw, hash_value);
+ mc_addr_list += ETH_ALEN;
+ }
+}
+
+/**
+ * e1000e_clear_hw_cntrs_base - Clear base hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ temp = er32(CRCERRS);
+ temp = er32(SYMERRS);
+ temp = er32(MPC);
+ temp = er32(SCC);
+ temp = er32(ECOL);
+ temp = er32(MCC);
+ temp = er32(LATECOL);
+ temp = er32(COLC);
+ temp = er32(DC);
+ temp = er32(SEC);
+ temp = er32(RLEC);
+ temp = er32(XONRXC);
+ temp = er32(XONTXC);
+ temp = er32(XOFFRXC);
+ temp = er32(XOFFTXC);
+ temp = er32(FCRUC);
+ temp = er32(GPRC);
+ temp = er32(BPRC);
+ temp = er32(MPRC);
+ temp = er32(GPTC);
+ temp = er32(GORCL);
+ temp = er32(GORCH);
+ temp = er32(GOTCL);
+ temp = er32(GOTCH);
+ temp = er32(RNBC);
+ temp = er32(RUC);
+ temp = er32(RFC);
+ temp = er32(ROC);
+ temp = er32(RJC);
+ temp = er32(TORL);
+ temp = er32(TORH);
+ temp = er32(TOTL);
+ temp = er32(TOTH);
+ temp = er32(TPR);
+ temp = er32(TPT);
+ temp = er32(MPTC);
+ temp = er32(BPTC);
+}
+
+/**
+ * e1000e_check_for_copper_link - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ **/
+s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ bool link;
+
+ /* We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status)
+ return 0;
+
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link)
+ return ret_val; /* No link detected */
+
+ mac->get_link_status = 0;
+
+ /* Check if there was DownShift, must be checked
+ * immediately after link-up */
+ e1000e_check_downshift(hw);
+
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -E1000_ERR_CONFIG;
+ return ret_val;
+ }
+
+ /* Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ e1000e_config_collision_dist(hw);
+
+ /* Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error configuring flow control\n");
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_check_for_fiber_link - Check for link (Fiber)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 rxcw;
+ u32 ctrl;
+ u32 status;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ status = er32(STATUS);
+ rxcw = er32(RXCW);
+
+ /* If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), the cable is plugged in (we have signal),
+ * and our link partner is not trying to auto-negotiate with us (we
+ * are receiving idles or data), we need to force link up. We also
+ * need to give auto-negotiation time to complete, in case the cable
+ * was just plugged in. The autoneg_failed flag does this.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ return 0;
+ }
+ hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = er32(CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ ew32(CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error configuring flow control\n");
+ return ret_val;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /* If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
+ ew32(TXCW, mac->txcw);
+ ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_check_for_serdes_link - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 rxcw;
+ u32 ctrl;
+ u32 status;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ status = er32(STATUS);
+ rxcw = er32(RXCW);
+
+ /* If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), and our link partner is not trying to
+ * auto-negotiate with us (we are receiving idles or data),
+ * we need to force link up. We also need to give auto-negotiation
+ * time to complete.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ return 0;
+ }
+ hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = er32(CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ ew32(CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error configuring flow control\n");
+ return ret_val;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /* If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
+ ew32(TXCW, mac->txcw);
+ ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = 1;
+ } else if (!(E1000_TXCW_ANE & er32(TXCW))) {
+ /* If we force link for non-auto-negotiation switch, check
+ * link status based on MAC synchronization for internal
+ * serdes media type.
+ */
+ /* SYNCH bit and IV bit are sticky. */
+ udelay(10);
+ if (E1000_RXCW_SYNCH & er32(RXCW)) {
+ if (!(rxcw & E1000_RXCW_IV)) {
+ mac->serdes_has_link = 1;
+ hw_dbg(hw, "SERDES: Link is up.\n");
+ }
+ } else {
+ mac->serdes_has_link = 0;
+ hw_dbg(hw, "SERDES: Link is down.\n");
+ }
+ }
+
+ if (E1000_TXCW_ANE & er32(TXCW)) {
+ status = er32(STATUS);
+ mac->serdes_has_link = (status & E1000_STATUS_LU);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_set_default_fc_generic - Set flow control default values
+ * @hw: pointer to the HW structure
+ *
+ * Read the EEPROM for the default values for flow control and store the
+ * values.
+ **/
+static s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ u16 nvm_data;
+
+ if (mac->fc != e1000_fc_default)
+ return 0;
+
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+ mac->fc = e1000_fc_none;
+ else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+ NVM_WORD0F_ASM_DIR)
+ mac->fc = e1000_fc_tx_pause;
+ else
+ mac->fc = e1000_fc_full;
+
+ return 0;
+}
+
+/**
+ * e1000e_setup_link - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+s32 e1000e_setup_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+
+ /* In the case of the phy reset being blocked, we already have a link.
+ * We do not need to set it up again.
+ */
+ if (e1000_check_reset_block(hw))
+ return 0;
+
+ /*
+ * If flow control is set to default, set flow control based on
+ * the EEPROM flow control settings.
+ */
+ if (mac->fc == e1000_fc_default) {
+ ret_val = e1000_set_default_fc_generic(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ mac->original_fc = mac->fc;
+
+ hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
+
+ /* Call the necessary media_type subroutine to configure the link. */
+ ret_val = mac->ops.setup_physical_interface(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ hw_dbg(hw, "Initializing the Flow Control address, type and timer regs\n");
+ ew32(FCT, FLOW_CONTROL_TYPE);
+ ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+ ew32(FCTTV, mac->fc_pause_time);
+
+ return e1000e_set_fc_watermarks(hw);
+}
+
+/**
+ * e1000_commit_fc_settings_generic - Configure flow control
+ * @hw: pointer to the HW structure
+ *
+ * Write the flow control settings to the Transmit Config Word Register (TXCW)
+ * base on the flow control settings in e1000_mac_info.
+ **/
+static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 txcw;
+
+ /* Check for a software override of the flow control settings, and
+ * setup the device accordingly. If auto-negotiation is enabled, then
+ * software will have to set the "PAUSE" bits to the correct value in
+ * the Transmit Config Word Register (TXCW) and re-start auto-
+ * negotiation. However, if auto-negotiation is disabled, then
+ * software will have to manually configure the two flow control enable
+ * bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames,
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we
+ * do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (mac->fc) {
+ case e1000_fc_none:
+ /* Flow control completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled and TX Flow control is disabled
+ * by a software over-ride. Since there really isn't a way to
+ * advertise that we are capable of RX Pause ONLY, we will
+ * advertise that we support both symmetric and asymmetric RX
+ * PAUSE. Later, we will disable the adapter's ability to send
+ * PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is disabled,
+ * by a software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ ew32(TXCW, txcw);
+ mac->txcw = txcw;
+
+ return 0;
+}
+
+/**
+ * e1000_poll_fiber_serdes_link_generic - Poll for link up
+ * @hw: pointer to the HW structure
+ *
+ * Polls for link up by reading the status register, if link fails to come
+ * up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 i, status;
+ s32 ret_val;
+
+ /* If we have a signal (the cable is plugged in, or assumed true for
+ * serdes media) then poll for a "Link-Up" indication in the Device
+ * Status Register. Time-out if a link isn't seen in 500 milliseconds
+ * seconds (Auto-negotiation should complete in less than 500
+ * milliseconds even if the other end is doing it in SW).
+ */
+ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+ msleep(10);
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU)
+ break;
+ }
+ if (i == FIBER_LINK_UP_LIMIT) {
+ hw_dbg(hw, "Never got a valid link from auto-neg!!!\n");
+ mac->autoneg_failed = 1;
+ /* AutoNeg failed to achieve a link, so we'll call
+ * mac->check_for_link. This routine will force the
+ * link up if we detect a signal. This will allow us to
+ * communicate with non-autonegotiating link partners.
+ */
+ ret_val = mac->ops.check_for_link(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error while checking for link\n");
+ return ret_val;
+ }
+ mac->autoneg_failed = 0;
+ } else {
+ mac->autoneg_failed = 0;
+ hw_dbg(hw, "Valid Link Found\n");
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes
+ * links. Upon successful setup, poll for link.
+ **/
+s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+
+ /* Take the link out of reset */
+ ctrl &= ~E1000_CTRL_LRST;
+
+ e1000e_config_collision_dist(hw);
+
+ ret_val = e1000_commit_fc_settings_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Since auto-negotiation is enabled, take the link out of reset (the
+ * link will be in reset, because we previously reset the chip). This
+ * will restart auto-negotiation. If auto-negotiation is successful
+ * then the link-up status bit will be set and the flow control enable
+ * bits (RFCE and TFCE) will be set according to their negotiated value.
+ */
+ hw_dbg(hw, "Auto-negotiation enabled\n");
+
+ ew32(CTRL, ctrl);
+ e1e_flush();
+ msleep(1);
+
+ /* For these adapters, the SW defineable pin 1 is set when the optics
+ * detect a signal. If we have a signal, then poll for a "Link-Up"
+ * indication.
+ */
+ if (hw->media_type == e1000_media_type_internal_serdes ||
+ (er32(CTRL) & E1000_CTRL_SWDPIN1)) {
+ ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+ } else {
+ hw_dbg(hw, "No signal detected\n");
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_config_collision_dist - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+void e1000e_config_collision_dist(struct e1000_hw *hw)
+{
+ u32 tctl;
+
+ tctl = er32(TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ ew32(TCTL, tctl);
+ e1e_flush();
+}
+
+/**
+ * e1000e_set_fc_watermarks - Set flow control high/low watermarks
+ * @hw: pointer to the HW structure
+ *
+ * Sets the flow control high/low threshold (watermark) registers. If
+ * flow control XON frame transmission is enabled, then set XON frame
+ * tansmission as well.
+ **/
+s32 e1000e_set_fc_watermarks(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 fcrtl = 0, fcrth = 0;
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames is not enabled, then these
+ * registers will be set to 0.
+ */
+ if (mac->fc & e1000_fc_tx_pause) {
+ /* We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ fcrtl = mac->fc_low_water;
+ fcrtl |= E1000_FCRTL_XONE;
+ fcrth = mac->fc_high_water;
+ }
+ ew32(FCRTL, fcrtl);
+ ew32(FCRTH, fcrth);
+
+ return 0;
+}
+
+/**
+ * e1000e_force_mac_fc - Force the MAC's flow control settings
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
+ * device control register to reflect the adapter settings. TFCE and RFCE
+ * need to be explicitly set by software when a copper PHY is used because
+ * autonegotiation is managed by the PHY rather than the MAC. Software must
+ * also configure these bits when link is forced on a fiber connection.
+ **/
+s32 e1000e_force_mac_fc(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 ctrl;
+
+ ctrl = er32(CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "mac->fc" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+ hw_dbg(hw, "mac->fc = %u\n", mac->fc);
+
+ switch (mac->fc) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ew32(CTRL, ctrl);
+
+ return 0;
+}
+
+/**
+ * e1000e_config_fc_after_link_up - Configures flow control after link
+ * @hw: pointer to the HW structure
+ *
+ * Checks the status of auto-negotiation after link up to ensure that the
+ * speed and duplex were not forced. If the link needed to be forced, then
+ * flow control needs to be forced also. If auto-negotiation is enabled
+ * and did not fail, then we configure flow control based on our link
+ * partner.
+ **/
+s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val = 0;
+ u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+ u16 speed, duplex;
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if (mac->autoneg_failed) {
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes)
+ ret_val = e1000e_force_mac_fc(hw);
+ } else {
+ if (hw->media_type == e1000_media_type_copper)
+ ret_val = e1000e_force_mac_fc(hw);
+ }
+
+ if (ret_val) {
+ hw_dbg(hw, "Error forcing flow control settings\n");
+ return ret_val;
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ return ret_val;
+
+ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ hw_dbg(hw, "Copper PHY and Auto Neg "
+ "has not completed.\n");
+ return ret_val;
+ }
+
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (Address 4) and the Auto_Negotiation Base
+ * Page Ability Register (Address 5) to determine how
+ * flow control was negotiated.
+ */
+ ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
+ if (ret_val)
+ return ret_val;
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | E1000_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if (mac->original_fc == e1000_fc_full) {
+ mac->fc = e1000_fc_full;
+ hw_dbg(hw, "Flow Control = FULL.\r\n");
+ } else {
+ mac->fc = e1000_fc_rx_pause;
+ hw_dbg(hw, "Flow Control = "
+ "RX PAUSE frames only.\r\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ *
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ mac->fc = e1000_fc_tx_pause;
+ hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ mac->fc = e1000_fc_rx_pause;
+ hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if ((mac->original_fc == e1000_fc_none) ||
+ (mac->original_fc == e1000_fc_tx_pause)) {
+ mac->fc = e1000_fc_none;
+ hw_dbg(hw, "Flow Control = NONE.\r\n");
+ } else {
+ mac->fc = e1000_fc_rx_pause;
+ hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+ if (ret_val) {
+ hw_dbg(hw, "Error getting link speed and duplex\n");
+ return ret_val;
+ }
+
+ if (duplex == HALF_DUPLEX)
+ mac->fc = e1000_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000e_force_mac_fc(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Read the status register for the current speed/duplex and store the current
+ * speed and duplex for copper connections.
+ **/
+s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+ u32 status;
+
+ status = er32(STATUS);
+ if (status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ hw_dbg(hw, "1000 Mbs, ");
+ } else if (status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ hw_dbg(hw, "100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ hw_dbg(hw, "10 Mbs, ");
+ }
+
+ if (status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ hw_dbg(hw, "Full Duplex\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ hw_dbg(hw, "Half Duplex\n");
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Sets the speed and duplex to gigabit full duplex (the only possible option)
+ * for fiber/serdes links.
+ **/
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+
+ return 0;
+}
+
+/**
+ * e1000e_get_hw_semaphore - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
+{
+ u32 swsm;
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+
+ /* Get the SW semaphore */
+ while (i < timeout) {
+ swsm = er32(SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ udelay(50);
+ i++;
+ }
+
+ if (i == timeout) {
+ hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_NVM;
+ }
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (er32(SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000e_put_hw_semaphore(hw);
+ hw_dbg(hw, "Driver can't access the NVM\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_put_hw_semaphore - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000e_put_hw_semaphore(struct e1000_hw *hw)
+{
+ u32 swsm;
+
+ swsm = er32(SWSM);
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ ew32(SWSM, swsm);
+}
+
+/**
+ * e1000e_get_auto_rd_done - Check for auto read completion
+ * @hw: pointer to the HW structure
+ *
+ * Check EEPROM for Auto Read done bit.
+ **/
+s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
+{
+ s32 i = 0;
+
+ while (i < AUTO_READ_DONE_TIMEOUT) {
+ if (er32(EECD) & E1000_EECD_AUTO_RD)
+ break;
+ msleep(1);
+ i++;
+ }
+
+ if (i == AUTO_READ_DONE_TIMEOUT) {
+ hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_valid_led_default - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+
+ return 0;
+}
+
+/**
+ * e1000e_id_led_init -
+ * @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000e_id_led_init(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ const u32 ledctl_mask = 0x000000FF;
+ const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+ const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+ u16 data, i, temp;
+ const u16 led_mask = 0x0F;
+
+ ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+ if (ret_val)
+ return ret_val;
+
+ mac->ledctl_default = er32(LEDCTL);
+ mac->ledctl_mode1 = mac->ledctl_default;
+ mac->ledctl_mode2 = mac->ledctl_default;
+
+ for (i = 0; i < 4; i++) {
+ temp = (data >> (i << 2)) & led_mask;
+ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_cleanup_led_generic - Set LED config to default operation
+ * @hw: pointer to the HW structure
+ *
+ * Remove the current LED configuration and set the LED configuration
+ * to the default value, saved from the EEPROM.
+ **/
+s32 e1000e_cleanup_led_generic(struct e1000_hw *hw)
+{
+ ew32(LEDCTL, hw->mac.ledctl_default);
+ return 0;
+}
+
+/**
+ * e1000e_blink_led - Blink LED
+ * @hw: pointer to the HW structure
+ *
+ * Blink the led's which are set to be on.
+ **/
+s32 e1000e_blink_led(struct e1000_hw *hw)
+{
+ u32 ledctl_blink = 0;
+ u32 i;
+
+ if (hw->media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /* set the blink bit for each LED that's "on" (0x0E)
+ * in ledctl_mode2 */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+ (i * 8));
+ }
+
+ ew32(LEDCTL, ledctl_blink);
+
+ return 0;
+}
+
+/**
+ * e1000e_led_on_generic - Turn LED on
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED on.
+ **/
+s32 e1000e_led_on_generic(struct e1000_hw *hw)
+{
+ u32 ctrl;
+
+ switch (hw->media_type) {
+ case e1000_media_type_fiber:
+ ctrl = er32(CTRL);
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ ew32(CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ ew32(LEDCTL, hw->mac.ledctl_mode2);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_led_off_generic - Turn LED off
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED off.
+ **/
+s32 e1000e_led_off_generic(struct e1000_hw *hw)
+{
+ u32 ctrl;
+
+ switch (hw->media_type) {
+ case e1000_media_type_fiber:
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ ew32(CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ ew32(LEDCTL, hw->mac.ledctl_mode1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_set_pcie_no_snoop - Set PCI-express capabilities
+ * @hw: pointer to the HW structure
+ * @no_snoop: bitmap of snoop events
+ *
+ * Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
+{
+ u32 gcr;
+
+ if (no_snoop) {
+ gcr = er32(GCR);
+ gcr &= ~(PCIE_NO_SNOOP_ALL);
+ gcr |= no_snoop;
+ ew32(GCR, gcr);
+ }
+}
+
+/**
+ * e1000e_disable_pcie_master - Disables PCI-express master access
+ * @hw: pointer to the HW structure
+ *
+ * Returns 0 if successful, else returns -10
+ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ * the master requests to be disabled.
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests.
+ **/
+s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 timeout = MASTER_DISABLE_TIMEOUT;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+ ew32(CTRL, ctrl);
+
+ while (timeout) {
+ if (!(er32(STATUS) &
+ E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ udelay(100);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "Master requests are pending.\n");
+ return -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_reset_adaptive - Reset Adaptive Interframe Spacing
+ * @hw: pointer to the HW structure
+ *
+ * Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000e_reset_adaptive(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ mac->current_ifs_val = 0;
+ mac->ifs_min_val = IFS_MIN;
+ mac->ifs_max_val = IFS_MAX;
+ mac->ifs_step_size = IFS_STEP;
+ mac->ifs_ratio = IFS_RATIO;
+
+ mac->in_ifs_mode = 0;
+ ew32(AIT, 0);
+}
+
+/**
+ * e1000e_update_adaptive - Update Adaptive Interframe Spacing
+ * @hw: pointer to the HW structure
+ *
+ * Update the Adaptive Interframe Spacing Throttle value based on the
+ * time between transmitted packets and time between collisions.
+ **/
+void e1000e_update_adaptive(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+ if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+ mac->in_ifs_mode = 1;
+ if (mac->current_ifs_val < mac->ifs_max_val) {
+ if (!mac->current_ifs_val)
+ mac->current_ifs_val = mac->ifs_min_val;
+ else
+ mac->current_ifs_val +=
+ mac->ifs_step_size;
+ ew32(AIT,
+ mac->current_ifs_val);
+ }
+ }
+ } else {
+ if (mac->in_ifs_mode &&
+ (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+ mac->current_ifs_val = 0;
+ mac->in_ifs_mode = 0;
+ ew32(AIT, 0);
+ }
+ }
+}
+
+/**
+ * e1000_raise_eec_clk - Raise EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+ *eecd = *eecd | E1000_EECD_SK;
+ ew32(EECD, *eecd);
+ e1e_flush();
+ udelay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_lower_eec_clk - Lower EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+ *eecd = *eecd & ~E1000_EECD_SK;
+ ew32(EECD, *eecd);
+ e1e_flush();
+ udelay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ * @hw: pointer to the HW structure
+ * @data: data to send to the EEPROM
+ * @count: number of bits to shift out
+ *
+ * We need to shift 'count' bits out to the EEPROM. So, the value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u32 mask;
+
+ mask = 0x01 << (count - 1);
+ if (nvm->type == e1000_nvm_eeprom_spi)
+ eecd |= E1000_EECD_DO;
+
+ do {
+ eecd &= ~E1000_EECD_DI;
+
+ if (data & mask)
+ eecd |= E1000_EECD_DI;
+
+ ew32(EECD, eecd);
+ e1e_flush();
+
+ udelay(nvm->delay_usec);
+
+ e1000_raise_eec_clk(hw, &eecd);
+ e1000_lower_eec_clk(hw, &eecd);
+
+ mask >>= 1;
+ } while (mask);
+
+ eecd &= ~E1000_EECD_DI;
+ ew32(EECD, eecd);
+}
+
+/**
+ * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ * @hw: pointer to the HW structure
+ * @count: number of bits to shift in
+ *
+ * In order to read a register from the EEPROM, we need to shift 'count' bits
+ * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+ * the EEPROM (setting the SK bit), and then reading the value of the data out
+ * "DO" bit. During this "shifting in" process the data in "DI" bit should
+ * always be clear.
+ **/
+static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+ u32 eecd;
+ u32 i;
+ u16 data;
+
+ eecd = er32(EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for (i = 0; i < count; i++) {
+ data <<= 1;
+ e1000_raise_eec_clk(hw, &eecd);
+
+ eecd = er32(EECD);
+
+ eecd &= ~E1000_EECD_DI;
+ if (eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_eec_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/**
+ * e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ * @hw: pointer to the HW structure
+ * @ee_reg: EEPROM flag for polling
+ *
+ * Polls the EEPROM status bit for either read or write completion based
+ * upon the value of 'ee_reg'.
+ **/
+s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+ u32 attempts = 100000;
+ u32 i, reg = 0;
+
+ for (i = 0; i < attempts; i++) {
+ if (ee_reg == E1000_NVM_POLL_READ)
+ reg = er32(EERD);
+ else
+ reg = er32(EEWR);
+
+ if (reg & E1000_NVM_RW_REG_DONE)
+ return 0;
+
+ udelay(5);
+ }
+
+ return -E1000_ERR_NVM;
+}
+
+/**
+ * e1000e_acquire_nvm - Generic request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 e1000e_acquire_nvm(struct e1000_hw *hw)
+{
+ u32 eecd = er32(EECD);
+ s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+
+ ew32(EECD, eecd | E1000_EECD_REQ);
+ eecd = er32(EECD);
+
+ while (timeout) {
+ if (eecd & E1000_EECD_GNT)
+ break;
+ udelay(5);
+ eecd = er32(EECD);
+ timeout--;
+ }
+
+ if (!timeout) {
+ eecd &= ~E1000_EECD_REQ;
+ ew32(EECD, eecd);
+ hw_dbg(hw, "Could not acquire NVM grant\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_standby_nvm - Return EEPROM to standby state
+ * @hw: pointer to the HW structure
+ *
+ * Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ ew32(EECD, eecd);
+ e1e_flush();
+ udelay(nvm->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ ew32(EECD, eecd);
+ e1e_flush();
+ udelay(nvm->delay_usec);
+ }
+}
+
+/**
+ * e1000_stop_nvm - Terminate EEPROM command
+ * @hw: pointer to the HW structure
+ *
+ * Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void e1000_stop_nvm(struct e1000_hw *hw)
+{
+ u32 eecd;
+
+ eecd = er32(EECD);
+ if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+ /* Pull CS high */
+ eecd |= E1000_EECD_CS;
+ e1000_lower_eec_clk(hw, &eecd);
+ }
+}
+
+/**
+ * e1000e_release_nvm - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000e_release_nvm(struct e1000_hw *hw)
+{
+ u32 eecd;
+
+ e1000_stop_nvm(hw);
+
+ eecd = er32(EECD);
+ eecd &= ~E1000_EECD_REQ;
+ ew32(EECD, eecd);
+}
+
+/**
+ * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ * @hw: pointer to the HW structure
+ *
+ * Setups the EEPROM for reading and writing.
+ **/
+static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u16 timeout = 0;
+ u8 spi_stat_reg;
+
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ ew32(EECD, eecd);
+ udelay(1);
+ timeout = NVM_MAX_RETRY_SPI;
+
+ /* Read "Status Register" repeatedly until the LSB is cleared.
+ * The EEPROM will signal that the command has been completed
+ * by clearing bit 0 of the internal status register. If it's
+ * not cleared within 'timeout', then error out. */
+ while (timeout) {
+ e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+ hw->nvm.opcode_bits);
+ spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
+ if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+ break;
+
+ udelay(5);
+ e1000_standby_nvm(hw);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "SPI NVM Status error\n");
+ return -E1000_ERR_NVM;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_read_nvm_spi - Read EEPROM's using SPI
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i = 0;
+ s32 ret_val;
+ u16 word_in;
+ u8 read_opcode = NVM_READ_OPCODE_SPI;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = nvm->ops.acquire_nvm(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val) {
+ nvm->ops.release_nvm(hw);
+ return ret_val;
+ }
+
+ e1000_standby_nvm(hw);
+
+ if ((nvm->address_bits == 8) && (offset >= 128))
+ read_opcode |= NVM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
+
+ /* Read the data. SPI NVMs increment the address with each byte
+ * read and will roll over if reading beyond the end. This allows
+ * us to read the whole NVM from any offset */
+ for (i = 0; i < words; i++) {
+ word_in = e1000_shift_in_eec_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+
+ nvm->ops.release_nvm(hw);
+ return 0;
+}
+
+/**
+ * e1000e_read_nvm_eerd - Reads EEPROM using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i, eerd = 0;
+ s32 ret_val = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+ E1000_NVM_RW_REG_START;
+
+ ew32(EERD, eerd);
+ ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+ if (ret_val)
+ break;
+
+ data[i] = (er32(EERD) >>
+ E1000_NVM_RW_REG_DATA);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_nvm_spi - Write to EEPROM using SPI
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * Writes data to EEPROM at offset using SPI interface.
+ *
+ * If e1000e_update_nvm_checksum is not called after this function , the
+ * EEPROM will most likley contain an invalid checksum.
+ **/
+s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ s32 ret_val;
+ u16 widx = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = nvm->ops.acquire_nvm(hw);
+ if (ret_val)
+ return ret_val;
+
+ msleep(10);
+
+ while (widx < words) {
+ u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val) {
+ nvm->ops.release_nvm(hw);
+ return ret_val;
+ }
+
+ e1000_standby_nvm(hw);
+
+ /* Send the WRITE ENABLE command (8 bit opcode) */
+ e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+ nvm->opcode_bits);
+
+ e1000_standby_nvm(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the
+ * opcode */
+ if ((nvm->address_bits == 8) && (offset >= 128))
+ write_opcode |= NVM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+ nvm->address_bits);
+
+ /* Loop to allow for up to whole page write of eeprom */
+ while (widx < words) {
+ u16 word_out = data[widx];
+ word_out = (word_out >> 8) | (word_out << 8);
+ e1000_shift_out_eec_bits(hw, word_out, 16);
+ widx++;
+
+ if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+ e1000_standby_nvm(hw);
+ break;
+ }
+ }
+ }
+
+ msleep(10);
+ return 0;
+}
+
+/**
+ * e1000e_read_mac_addr - Read device MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the device MAC address from the EEPROM and stores the value.
+ * Since devices with two ports use the same EEPROM, we increment the
+ * last bit in the MAC address for the second port.
+ **/
+s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 offset, nvm_data, i;
+
+ for (i = 0; i < ETH_ALEN; i += 2) {
+ offset = i >> 1;
+ ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+ hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+ }
+
+ /* Flip last bit of mac address if we're on second port */
+ if (hw->bus.func == E1000_FUNC_1)
+ hw->mac.perm_addr[5] ^= 1;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+ return 0;
+}
+
+/**
+ * e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 checksum = 0;
+ u16 i, nvm_data;
+
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ checksum += nvm_data;
+ }
+
+ if (checksum != (u16) NVM_SUM) {
+ hw_dbg(hw, "NVM Checksum Invalid\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_update_nvm_checksum_generic - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 checksum = 0;
+ u16 i, nvm_data;
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error while updating checksum.\n");
+ return ret_val;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (u16) NVM_SUM - checksum;
+ ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
+ if (ret_val)
+ hw_dbg(hw, "NVM Write Error while updating checksum.\n");
+
+ return ret_val;
+}
+
+/**
+ * e1000e_reload_nvm - Reloads EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ * extended control register.
+ **/
+void e1000e_reload_nvm(struct e1000_hw *hw)
+{
+ u32 ctrl_ext;
+
+ udelay(10);
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ ew32(CTRL_EXT, ctrl_ext);
+ e1e_flush();
+}
+
+/**
+ * e1000_calculate_checksum - Calculate checksum for buffer
+ * @buffer: pointer to EEPROM
+ * @length: size of EEPROM to calculate a checksum for
+ *
+ * Calculates the checksum for some buffer on a specified length. The
+ * checksum calculated is returned.
+ **/
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
+{
+ u32 i;
+ u8 sum = 0;
+
+ if (!buffer)
+ return 0;
+
+ for (i = 0; i < length; i++)
+ sum += buffer[i];
+
+ return (u8) (0 - sum);
+}
+
+/**
+ * e1000_mng_enable_host_if - Checks host interface is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed. It busy waits
+ * in case of previous command is not completed.
+ **/
+static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
+{
+ u32 hicr;
+ u8 i;
+
+ /* Check that the host interface is enabled. */
+ hicr = er32(HICR);
+ if ((hicr & E1000_HICR_EN) == 0) {
+ hw_dbg(hw, "E1000_HOST_EN bit disabled.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+ /* check the previous command is completed */
+ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+ hicr = er32(HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ mdelay(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ hw_dbg(hw, "Previous command timeout failed .\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_check_mng_mode - check managament mode
+ * @hw: pointer to the HW structure
+ *
+ * Reads the firmware semaphore register and returns true (>0) if
+ * manageability is enabled, else false (0).
+ **/
+bool e1000e_check_mng_mode(struct e1000_hw *hw)
+{
+ u32 fwsm = er32(FWSM);
+
+ return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
+}
+
+/**
+ * e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX
+ * @hw: pointer to the HW structure
+ *
+ * Enables packet filtering on transmit packets if manageability is enabled
+ * and host interface is enabled.
+ **/
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+ struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+ u32 *buffer = (u32 *)&hw->mng_cookie;
+ u32 offset;
+ s32 ret_val, hdr_csum, csum;
+ u8 i, len;
+
+ /* No manageability, no filtering */
+ if (!e1000e_check_mng_mode(hw)) {
+ hw->mac.tx_pkt_filtering = 0;
+ return 0;
+ }
+
+ /* If we can't read from the host interface for whatever
+ * reason, disable filtering.
+ */
+ ret_val = e1000_mng_enable_host_if(hw);
+ if (ret_val != 0) {
+ hw->mac.tx_pkt_filtering = 0;
+ return ret_val;
+ }
+
+ /* Read in the header. Length and offset are in dwords. */
+ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+ offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+ for (i = 0; i < len; i++)
+ *(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i);
+ hdr_csum = hdr->checksum;
+ hdr->checksum = 0;
+ csum = e1000_calculate_checksum((u8 *)hdr,
+ E1000_MNG_DHCP_COOKIE_LENGTH);
+ /* If either the checksums or signature don't match, then
+ * the cookie area isn't considered valid, in which case we
+ * take the safe route of assuming Tx filtering is enabled.
+ */
+ if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
+ hw->mac.tx_pkt_filtering = 1;
+ return 1;
+ }
+
+ /* Cookie area is valid, make the final check for filtering. */
+ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
+ hw->mac.tx_pkt_filtering = 0;
+ return 0;
+ }
+
+ hw->mac.tx_pkt_filtering = 1;
+ return 1;
+}
+
+/**
+ * e1000_mng_write_cmd_header - Writes manageability command header
+ * @hw: pointer to the HW structure
+ * @hdr: pointer to the host interface command header
+ *
+ * Writes the command header after does the checksum calculation.
+ **/
+static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr)
+{
+ u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+ /* Write the whole command header structure with new checksum. */
+
+ hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
+
+ length >>= 2;
+ /* Write the relevant command block into the ram area. */
+ for (i = 0; i < length; i++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i,
+ *((u32 *) hdr + i));
+ e1e_flush();
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_mng_host_if_write - Writes to the manageability host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface buffer
+ * @length: size of the buffer
+ * @offset: location in the buffer to write to
+ * @sum: sum of the data (not checksum)
+ *
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient
+ * way. Also fills up the sum of the buffer in *buffer parameter.
+ **/
+static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer,
+ u16 length, u16 offset, u8 *sum)
+{
+ u8 *tmp;
+ u8 *bufptr = buffer;
+ u32 data = 0;
+ u16 remaining, i, j, prev_bytes;
+
+ /* sum = only sum of the data and it is not checksum */
+
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
+ return -E1000_ERR_PARAM;
+
+ tmp = (u8 *)&data;
+ prev_bytes = offset & 0x3;
+ offset >>= 2;
+
+ if (prev_bytes) {
+ data = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset);
+ for (j = prev_bytes; j < sizeof(u32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset, data);
+ length -= j - prev_bytes;
+ offset++;
+ }
+
+ remaining = length & 0x3;
+ length -= remaining;
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /* The device driver writes the relevant command block into the
+ * ram area. */
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < sizeof(u32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
+ }
+ if (remaining) {
+ for (j = 0; j < sizeof(u32); j++) {
+ if (j < remaining)
+ *(tmp + j) = *bufptr++;
+ else
+ *(tmp + j) = 0;
+
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
+{
+ struct e1000_host_mng_command_header hdr;
+ s32 ret_val;
+ u32 hicr;
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ /* Enable the host interface */
+ ret_val = e1000_mng_enable_host_if(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Populate the host interface with the contents of "buffer". */
+ ret_val = e1000_mng_host_if_write(hw, buffer, length,
+ sizeof(hdr), &(hdr.checksum));
+ if (ret_val)
+ return ret_val;
+
+ /* Write the manageability command header */
+ ret_val = e1000_mng_write_cmd_header(hw, &hdr);
+ if (ret_val)
+ return ret_val;
+
+ /* Tell the ARC a new command is pending. */
+ hicr = er32(HICR);
+ ew32(HICR, hicr | E1000_HICR_C);
+
+ return 0;
+}
+
+/**
+ * e1000e_enable_mng_pass_thru - Enable processing of ARP's
+ * @hw: pointer to the HW structure
+ *
+ * Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+ u32 manc;
+ u32 fwsm, factps;
+ bool ret_val = 0;
+
+ manc = er32(MANC);
+
+ if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+ !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+ return ret_val;
+
+ if (hw->mac.arc_subsystem_valid) {
+ fwsm = er32(FWSM);
+ factps = er32(FACTPS);
+
+ if (!(factps & E1000_FACTPS_MNGCG) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+ ret_val = 1;
+ return ret_val;
+ }
+ } else {
+ if ((manc & E1000_MANC_SMBUS_EN) &&
+ !(manc & E1000_MANC_ASF_EN)) {
+ ret_val = 1;
+ return ret_val;
+ }
+ }
+
+ return ret_val;
+}
+
+s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num)
+{
+ s32 ret_val;
+ u16 nvm_data;
+
+ ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num = (u32)(nvm_data << 16);
+
+ ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num |= nvm_data;
+
+ return 0;
+}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
new file mode 100644
index 000000000000..033e124d1c1f
--- /dev/null
+++ b/drivers/net/e1000e/netdev.c
@@ -0,0 +1,4438 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+
+#include "e1000.h"
+
+#define DRV_VERSION "0.2.0"
+char e1000e_driver_name[] = "e1000e";
+const char e1000e_driver_version[] = DRV_VERSION;
+
+static const struct e1000_info *e1000_info_tbl[] = {
+ [board_82571] = &e1000_82571_info,
+ [board_82572] = &e1000_82572_info,
+ [board_82573] = &e1000_82573_info,
+ [board_80003es2lan] = &e1000_es2_info,
+ [board_ich8lan] = &e1000_ich8_info,
+ [board_ich9lan] = &e1000_ich9_info,
+};
+
+#ifdef DEBUG
+/**
+ * e1000_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *e1000e_get_hw_dev_name(struct e1000_hw *hw)
+{
+ return hw->adapter->netdev->name;
+}
+#endif
+
+/**
+ * e1000_desc_unused - calculate if we have unused descriptors
+ **/
+static int e1000_desc_unused(struct e1000_ring *ring)
+{
+ if (ring->next_to_clean > ring->next_to_use)
+ return ring->next_to_clean - ring->next_to_use - 1;
+
+ return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ **/
+static void e1000_receive_skb(struct e1000_adapter *adapter,
+ struct net_device *netdev,
+ struct sk_buff *skb,
+ u8 status, u16 vlan)
+{
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+ le16_to_cpu(vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
+ else
+ netif_receive_skb(skb);
+
+ netdev->last_rx = jiffies;
+}
+
+/**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @status_err: receive descriptor status and error fields
+ * @csum: receive descriptor csum field
+ * @sk_buff: socket buffer with received data
+ **/
+static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
+ u32 csum, struct sk_buff *skb)
+{
+ u16 status = (u16)status_err;
+ u8 errors = (u8)(status_err >> 24);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Ignore Checksum bit is set */
+ if (status & E1000_RXD_STAT_IXSM)
+ return;
+ /* TCP/UDP checksum error bit is set */
+ if (errors & E1000_RXD_ERR_TCPE) {
+ /* let the stack verify checksum errors */
+ adapter->hw_csum_err++;
+ return;
+ }
+
+ /* TCP/UDP Checksum has not been calculated */
+ if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)))
+ return;
+
+ /* It must be a TCP or UDP packet with a valid checksum */
+ if (status & E1000_RXD_STAT_TCPCS) {
+ /* TCP checksum is good */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ /* IP fragment with UDP payload */
+ /* Hardware complements the payload checksum, so we undo it
+ * and then put the value in host order for further stack use.
+ */
+ csum = ntohl(csum ^ 0xFFFF);
+ skb->csum = csum;
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+ adapter->hw_csum_good++;
+}
+
+/**
+ * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
+ * @adapter: address of board private structure
+ **/
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+ int cleaned_count)
+{
+ 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;
+ struct e1000_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = adapter->rx_buffer_len + 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 map_skb;
+ }
+
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (!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;
+map_skb:
+ buffer_info->dma = pci_map_single(pdev, skb->data,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&pdev->dev, "RX DMA map failed\n");
+ adapter->rx_dma_failed++;
+ break;
+ }
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+ if (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_alloc_rx_buffers_ps - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+ int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ union e1000_rx_desc_packet_split *rx_desc;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info;
+ struct e1000_ps_page *ps_page;
+ struct sk_buff *skb;
+ unsigned int i, j;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+
+ for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+ ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS)
+ + j];
+ if (j < adapter->rx_ps_pages) {
+ if (!ps_page->page) {
+ ps_page->page = alloc_page(GFP_ATOMIC);
+ if (!ps_page->page) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+ }
+ ps_page->dma = pci_map_page(pdev,
+ ps_page->page,
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(
+ ps_page->dma)) {
+ dev_err(&adapter->pdev->dev,
+ "RX DMA page map failed\n");
+ adapter->rx_dma_failed++;
+ goto no_buffers;
+ }
+ }
+ /*
+ * Refresh the desc even if buffer_addrs
+ * didn't change because each write-back
+ * erases this info.
+ */
+ rx_desc->read.buffer_addr[j+1] =
+ cpu_to_le64(ps_page->dma);
+ } else {
+ rx_desc->read.buffer_addr[j+1] = ~0;
+ }
+ }
+
+ skb = netdev_alloc_skb(netdev,
+ adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+
+ if (!skb) {
+ 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;
+ buffer_info->dma = pci_map_single(pdev, skb->data,
+ adapter->rx_ps_bsize0,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&pdev->dev, "RX DMA map failed\n");
+ adapter->rx_dma_failed++;
+ /* cleanup skb */
+ dev_kfree_skb_any(skb);
+ buffer_info->skb = NULL;
+ break;
+ }
+
+ rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+no_buffers:
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+
+ if (!(i--))
+ 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();
+ /* Hardware increments by 16 bytes, but packet split
+ * descriptors are 32 bytes...so we increment tail
+ * twice as much.
+ */
+ writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+ }
+}
+
+/**
+ * e1000_alloc_rx_buffers_jumbo - Replace used jumbo receive buffers
+ *
+ * @adapter: address of board private structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+static void e1000_alloc_rx_buffers_jumbo(struct e1000_adapter *adapter,
+ int cleaned_count)
+{
+ 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;
+ 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 (!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 (!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);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&adapter->pdev->dev, "RX DMA page map failed\n");
+ adapter->rx_dma_failed++;
+ break;
+ }
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+ if (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
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_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 = 0;
+ 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;
+
+ prefetch(skb->data - NET_IP_ALIGN);
+
+ 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 = 1;
+ cleaned_count++;
+ pci_unmap_single(pdev,
+ buffer_info->dma,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ length = le16_to_cpu(rx_desc->length);
+
+ /* !EOP means multiple descriptors were used to store a single
+ * packet, also make sure the frame isn't just CRC only */
+ if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) {
+ /* All receives must fit into a single buffer */
+ ndev_dbg(netdev, "%s: Receive packet consumed "
+ "multiple buffers\n", netdev->name);
+ /* recycle */
+ buffer_info->skb = skb;
+ goto next_desc;
+ }
+
+ if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+ /* recycle */
+ buffer_info->skb = skb;
+ goto next_desc;
+ }
+
+ /* adjust length to remove Ethernet CRC */
+ length -= 4;
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += length;
+ total_rx_packets++;
+
+ /* code added for copybreak, this should improve
+ * performance for small packets with large amounts
+ * of reassembly being done in the stack */
+ if (length < copybreak) {
+ struct sk_buff *new_skb =
+ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ if (new_skb) {
+ skb_reserve(new_skb, NET_IP_ALIGN);
+ memcpy(new_skb->data - NET_IP_ALIGN,
+ skb->data - NET_IP_ALIGN,
+ length + NET_IP_ALIGN);
+ /* save the skb in buffer_info as good */
+ buffer_info->skb = skb;
+ skb = new_skb;
+ }
+ /* else just continue with the old one */
+ }
+ /* end copybreak code */
+ skb_put(skb, length);
+
+ /* Receive Checksum Offload */
+ e1000_rx_checksum(adapter,
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
+
+ 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 (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_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ return cleaned;
+}
+
+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;
+}
+
+static void e1000_put_txbuf(struct e1000_adapter *adapter,
+ struct e1000_buffer *buffer_info)
+{
+ if (buffer_info->dma) {
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+}
+
+static void e1000_print_tx_hang(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ unsigned int i = tx_ring->next_to_clean;
+ unsigned int eop = tx_ring->buffer_info[i].next_to_watch;
+ struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop);
+ struct net_device *netdev = adapter->netdev;
+
+ /* detected Tx unit hang */
+ ndev_err(netdev,
+ "Detected Tx Unit Hang:\n"
+ " TDH <%x>\n"
+ " TDT <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "buffer_info[next_to_clean]:\n"
+ " time_stamp <%lx>\n"
+ " next_to_watch <%x>\n"
+ " jiffies <%lx>\n"
+ " next_to_watch.status <%x>\n",
+ readl(adapter->hw.hw_addr + tx_ring->head),
+ readl(adapter->hw.hw_addr + tx_ring->tail),
+ tx_ring->next_to_use,
+ tx_ring->next_to_clean,
+ tx_ring->buffer_info[eop].time_stamp,
+ eop,
+ jiffies,
+ eop_desc->upper.fields.status);
+}
+
+/**
+ * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @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_tx_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc, *eop_desc;
+ struct e1000_buffer *buffer_info;
+ unsigned int i, eop;
+ unsigned int count = 0;
+ bool cleaned = 0;
+ unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+
+ i = tx_ring->next_to_clean;
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
+
+ while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ for (cleaned = 0; !cleaned; ) {
+ tx_desc = E1000_TX_DESC(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
+ cleaned = (i == eop);
+
+ if (cleaned) {
+ struct sk_buff *skb = buffer_info->skb;
+ unsigned int segs, bytecount;
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
+ total_tx_packets += segs;
+ total_tx_bytes += bytecount;
+ }
+
+ e1000_put_txbuf(adapter, buffer_info);
+ tx_desc->upper.data = 0;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
+#define E1000_TX_WEIGHT 64
+ /* weight of a sort for tx, to avoid endless transmit cleanup */
+ if (count++ == E1000_TX_WEIGHT)
+ break;
+ }
+
+ tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+ if (cleaned && netif_carrier_ok(netdev) &&
+ e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+
+ if (netif_queue_stopped(netdev) &&
+ !(test_bit(__E1000_DOWN, &adapter->state))) {
+ netif_wake_queue(netdev);
+ ++adapter->restart_queue;
+ }
+ }
+
+ if (adapter->detect_tx_hung) {
+ /* Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of i */
+ adapter->detect_tx_hung = 0;
+ if (tx_ring->buffer_info[eop].dma &&
+ time_after(jiffies, tx_ring->buffer_info[eop].time_stamp
+ + (adapter->tx_timeout_factor * HZ))
+ && !(er32(STATUS) &
+ E1000_STATUS_TXOFF)) {
+ e1000_print_tx_hang(adapter);
+ netif_stop_queue(netdev);
+ }
+ }
+ adapter->total_tx_bytes += total_tx_bytes;
+ adapter->total_tx_packets += total_tx_packets;
+ return cleaned;
+}
+
+/**
+ * e1000_clean_rx_irq_jumbo - 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_rx_irq_jumbo(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 = 0;
+ 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 = 1;
+ 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 ((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);
+
+ pskb_trim(skb, skb->len - 4);
+
+ /* 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_pull_tail 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 (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_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ return cleaned;
+}
+
+/**
+ * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split
+ * @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_rx_irq_ps(struct e1000_adapter *adapter,
+ int *work_done, int work_to_do)
+{
+ union e1000_rx_desc_packet_split *rx_desc, *next_rxd;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ struct e1000_ps_page *ps_page;
+ struct sk_buff *skb;
+ unsigned int i, j;
+ u32 length, staterr;
+ int cleaned_count = 0;
+ bool cleaned = 0;
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (staterr & E1000_RXD_STAT_DD) {
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+ skb = buffer_info->skb;
+
+ /* in the packet split case this is header only */
+ prefetch(skb->data - NET_IP_ALIGN);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ next_rxd = E1000_RX_DESC_PS(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = 1;
+ cleaned_count++;
+ pci_unmap_single(pdev, buffer_info->dma,
+ adapter->rx_ps_bsize0,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ if (!(staterr & E1000_RXD_STAT_EOP)) {
+ ndev_dbg(netdev, "%s: Packet Split buffers didn't pick "
+ "up the full packet\n", netdev->name);
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ length = le16_to_cpu(rx_desc->wb.middle.length0);
+
+ if (!length) {
+ ndev_dbg(netdev, "%s: Last part of the packet spanning"
+ " multiple descriptors\n", netdev->name);
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ /* Good Receive */
+ skb_put(skb, length);
+
+ {
+ /* this looks ugly, but it seems compiler issues make it
+ more efficient than reusing j */
+ int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]);
+
+ /* page alloc/put takes too long and effects small packet
+ * throughput, so unsplit small packets and save the alloc/put*/
+ if (l1 && (l1 <= copybreak) &&
+ ((length + l1) <= adapter->rx_ps_bsize0)) {
+ u8 *vaddr;
+
+ ps_page = &rx_ring->ps_pages[i * PS_PAGE_BUFFERS];
+
+ /* there is no documentation about how to call
+ * kmap_atomic, so we can't hold the mapping
+ * very long */
+ pci_dma_sync_single_for_cpu(pdev, ps_page->dma,
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ);
+ memcpy(skb_tail_pointer(skb), vaddr, l1);
+ kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
+ pci_dma_sync_single_for_device(pdev, ps_page->dma,
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ /* remove the CRC */
+ l1 -= 4;
+ skb_put(skb, l1);
+ goto copydone;
+ } /* if */
+ }
+
+ for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+ length = le16_to_cpu(rx_desc->wb.upper.length[j]);
+ if (!length)
+ break;
+
+ ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + j];
+ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ ps_page->dma = 0;
+ skb_fill_page_desc(skb, j, ps_page->page, 0, length);
+ ps_page->page = NULL;
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+ }
+
+ /* strip the ethernet crc, problem is we're using pages now so
+ * this whole operation can get a little cpu intensive */
+ pskb_trim(skb, skb->len - 4);
+
+copydone:
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ e1000_rx_checksum(adapter, staterr, le16_to_cpu(
+ rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
+
+ if (rx_desc->wb.upper.header_status &
+ cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
+ adapter->rx_hdr_split++;
+
+ e1000_receive_skb(adapter, netdev, skb,
+ staterr, rx_desc->wb.middle.vlan);
+
+next_desc:
+ rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
+ buffer_info->skb = NULL;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (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;
+
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+ }
+ 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_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ return cleaned;
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ **/
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info;
+ struct e1000_ps_page *ps_page;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i, j;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ if (adapter->clean_rx == e1000_clean_rx_irq)
+ pci_unmap_single(pdev, buffer_info->dma,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ else if (adapter->clean_rx == e1000_clean_rx_irq_jumbo)
+ 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,
+ PCI_DMA_FROMDEVICE);
+ 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;
+ }
+
+ for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+ ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS)
+ + j];
+ if (!ps_page->page)
+ break;
+ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ ps_page->dma = 0;
+ put_page(ps_page->page);
+ ps_page->page = NULL;
+ }
+ }
+
+ /* there also may be some cached data from a chained receive */
+ if (rx_ring->rx_skb_top) {
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ }
+
+ size = sizeof(struct e1000_buffer) * rx_ring->count;
+ memset(rx_ring->buffer_info, 0, size);
+ size = sizeof(struct e1000_ps_page)
+ * (rx_ring->count * PS_PAGE_BUFFERS);
+ memset(rx_ring->ps_pages, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ writel(0, adapter->hw.hw_addr + rx_ring->head);
+ writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * e1000_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr_msi(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 icr = er32(ICR);
+
+ /* read ICR disables interrupts using IAM, so keep up with our
+ * enable/disable accounting */
+ atomic_inc(&adapter->irq_sem);
+
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->mac.get_link_status = 1;
+ /* ICH8 workaround-- Call gig speed drop workaround on cable
+ * disconnect (LSC) before accessing any PHY registers */
+ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+ (!(er32(STATUS) & E1000_STATUS_LU)))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* 80003ES2LAN workaround-- For packet buffer work-around on
+ * link down event; disable receives here in the ISR and reset
+ * adapter in watchdog */
+ if (netif_carrier_ok(netdev) &&
+ adapter->flags & FLAG_RX_NEEDS_RESTART) {
+ /* disable receives */
+ u32 rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ }
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ adapter->total_tx_bytes = 0;
+ adapter->total_tx_packets = 0;
+ adapter->total_rx_bytes = 0;
+ adapter->total_rx_packets = 0;
+ __netif_rx_schedule(netdev, &adapter->napi);
+ } else {
+ atomic_dec(&adapter->irq_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ u32 rctl, icr = er32(ICR);
+ if (!icr)
+ return IRQ_NONE; /* Not our interrupt */
+
+ /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+ * not set, then the adapter didn't send an interrupt */
+ if (!(icr & E1000_ICR_INT_ASSERTED))
+ return IRQ_NONE;
+
+ /* Interrupt Auto-Mask...upon reading ICR,
+ * interrupts are masked. No need for the
+ * IMC write, but it does mean we should
+ * account for it ASAP. */
+ atomic_inc(&adapter->irq_sem);
+
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->mac.get_link_status = 1;
+ /* ICH8 workaround-- Call gig speed drop workaround on cable
+ * disconnect (LSC) before accessing any PHY registers */
+ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+ (!(er32(STATUS) & E1000_STATUS_LU)))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* 80003ES2LAN workaround--
+ * For packet buffer work-around on link down event;
+ * disable receives here in the ISR and
+ * reset adapter in watchdog
+ */
+ if (netif_carrier_ok(netdev) &&
+ (adapter->flags & FLAG_RX_NEEDS_RESTART)) {
+ /* disable receives */
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ }
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ adapter->total_tx_bytes = 0;
+ adapter->total_tx_packets = 0;
+ adapter->total_rx_bytes = 0;
+ adapter->total_rx_packets = 0;
+ __netif_rx_schedule(netdev, &adapter->napi);
+ } else {
+ atomic_dec(&adapter->irq_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int e1000_request_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ void (*handler) = &e1000_intr;
+ int irq_flags = IRQF_SHARED;
+ int err;
+
+ err = pci_enable_msi(adapter->pdev);
+ if (err) {
+ ndev_warn(netdev,
+ "Unable to allocate MSI interrupt Error: %d\n", err);
+ } else {
+ adapter->flags |= FLAG_MSI_ENABLED;
+ handler = &e1000_intr_msi;
+ irq_flags = 0;
+ }
+
+ err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
+ netdev);
+ if (err) {
+ if (adapter->flags & FLAG_MSI_ENABLED)
+ pci_disable_msi(adapter->pdev);
+ ndev_err(netdev,
+ "Unable to allocate interrupt Error: %d\n", err);
+ }
+
+ return err;
+}
+
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ free_irq(adapter->pdev->irq, netdev);
+ if (adapter->flags & FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~FLAG_MSI_ENABLED;
+ }
+}
+
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ **/
+static void e1000_irq_disable(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ atomic_inc(&adapter->irq_sem);
+ ew32(IMC, ~0);
+ e1e_flush();
+ synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ **/
+static void e1000_irq_enable(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (atomic_dec_and_test(&adapter->irq_sem)) {
+ ew32(IMS, IMS_ENABLE_MASK);
+ e1e_flush();
+ }
+}
+
+/**
+ * e1000_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded. For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is open.
+ **/
+static void e1000_get_hw_control(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl_ext;
+ u32 swsm;
+
+ /* Let firmware know the driver has taken over */
+ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
+ } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+ ctrl_ext = er32(CTRL_EXT);
+ ew32(CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+ }
+}
+
+/**
+ * e1000_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded. For AMT version (only with 82573) i
+ * of the f/w this means that the network i/f is closed.
+ *
+ **/
+static void e1000_release_hw_control(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl_ext;
+ u32 swsm;
+
+ /* Let firmware taken over control of h/w */
+ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD);
+ } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+ ctrl_ext = er32(CTRL_EXT);
+ ew32(CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+ }
+}
+
+static void e1000_release_manageability(struct e1000_adapter *adapter)
+{
+ if (adapter->flags & FLAG_MNG_PT_ENABLED) {
+ struct e1000_hw *hw = &adapter->hw;
+
+ u32 manc = er32(MANC);
+
+ /* re-enable hardware interception of ARP */
+ manc |= E1000_MANC_ARP_EN;
+ manc &= ~E1000_MANC_EN_MNG2HOST;
+
+ /* don't explicitly have to mess with MANC2H since
+ * MANC has an enable disable that gates MANC2H */
+ ew32(MANC, manc);
+ }
+}
+
+/**
+ * @e1000_alloc_ring - allocate memory for a ring structure
+ **/
+static int e1000_alloc_ring_dma(struct e1000_adapter *adapter,
+ struct e1000_ring *ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
+ GFP_KERNEL);
+ if (!ring->desc)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * e1000e_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+int e1000e_setup_tx_resources(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ int err = -ENOMEM, size;
+
+ size = sizeof(struct e1000_buffer) * tx_ring->count;
+ tx_ring->buffer_info = vmalloc(size);
+ if (!tx_ring->buffer_info)
+ goto err;
+ memset(tx_ring->buffer_info, 0, size);
+
+ /* round up to nearest 4K */
+ tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+ tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+ err = e1000_alloc_ring_dma(adapter, tx_ring);
+ if (err)
+ goto err;
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+ spin_lock_init(&adapter->tx_queue_lock);
+
+ return 0;
+err:
+ vfree(tx_ring->buffer_info);
+ ndev_err(adapter->netdev,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return err;
+}
+
+/**
+ * e1000e_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int e1000e_setup_rx_resources(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ int size, desc_len, err = -ENOMEM;
+
+ size = sizeof(struct e1000_buffer) * rx_ring->count;
+ rx_ring->buffer_info = vmalloc(size);
+ if (!rx_ring->buffer_info)
+ goto err;
+ memset(rx_ring->buffer_info, 0, size);
+
+ rx_ring->ps_pages = kcalloc(rx_ring->count * PS_PAGE_BUFFERS,
+ sizeof(struct e1000_ps_page),
+ GFP_KERNEL);
+ if (!rx_ring->ps_pages)
+ goto err;
+
+ desc_len = sizeof(union e1000_rx_desc_packet_split);
+
+ /* Round up to nearest 4K */
+ rx_ring->size = rx_ring->count * desc_len;
+ rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+ err = e1000_alloc_ring_dma(adapter, rx_ring);
+ if (err)
+ goto err;
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+ rx_ring->rx_skb_top = NULL;
+
+ return 0;
+err:
+ vfree(rx_ring->buffer_info);
+ kfree(rx_ring->ps_pages);
+ ndev_err(adapter->netdev,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return err;
+}
+
+/**
+ * e1000_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ **/
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_buffer *buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ for (i = 0; i < tx_ring->count; i++) {
+ buffer_info = &tx_ring->buffer_info[i];
+ e1000_put_txbuf(adapter, buffer_info);
+ }
+
+ size = sizeof(struct e1000_buffer) * tx_ring->count;
+ memset(tx_ring->buffer_info, 0, size);
+
+ memset(tx_ring->desc, 0, tx_ring->size);
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ writel(0, adapter->hw.hw_addr + tx_ring->head);
+ writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * e1000e_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+void e1000e_free_tx_resources(struct e1000_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+
+ e1000_clean_tx_ring(adapter);
+
+ vfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
+
+ dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+ tx_ring->dma);
+ tx_ring->desc = NULL;
+}
+
+/**
+ * e1000e_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+void e1000e_free_rx_resources(struct e1000_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+
+ e1000_clean_rx_ring(adapter);
+
+ vfree(rx_ring->buffer_info);
+ rx_ring->buffer_info = NULL;
+
+ kfree(rx_ring->ps_pages);
+ rx_ring->ps_pages = NULL;
+
+ dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+ rx_ring->dma);
+ rx_ring->desc = NULL;
+}
+
+/**
+ * e1000_update_itr - update the dynamic ITR value based on statistics
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt. The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern. Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ * this functionality is controlled by the InterruptThrottleRate module
+ * parameter (see e1000_param.c)
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ **/
+static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
+ u16 itr_setting, int packets,
+ int bytes)
+{
+ unsigned int retval = itr_setting;
+
+ if (packets == 0)
+ goto update_itr_done;
+
+ switch (itr_setting) {
+ case lowest_latency:
+ /* handle TSO and jumbo frames */
+ if (bytes/packets > 8000)
+ retval = bulk_latency;
+ else if ((packets < 5) && (bytes > 512)) {
+ retval = low_latency;
+ }
+ break;
+ case low_latency: /* 50 usec aka 20000 ints/s */
+ if (bytes > 10000) {
+ /* this if handles the TSO accounting */
+ if (bytes/packets > 8000) {
+ retval = bulk_latency;
+ } else if ((packets < 10) || ((bytes/packets) > 1200)) {
+ retval = bulk_latency;
+ } else if ((packets > 35)) {
+ retval = lowest_latency;
+ }
+ } else if (bytes/packets > 2000) {
+ retval = bulk_latency;
+ } else if (packets <= 2 && bytes < 512) {
+ retval = lowest_latency;
+ }
+ break;
+ case bulk_latency: /* 250 usec aka 4000 ints/s */
+ if (bytes > 25000) {
+ if (packets > 35) {
+ retval = low_latency;
+ }
+ } else if (bytes < 6000) {
+ retval = low_latency;
+ }
+ break;
+ }
+
+update_itr_done:
+ return retval;
+}
+
+static void e1000_set_itr(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u16 current_itr;
+ u32 new_itr = adapter->itr;
+
+ /* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+ if (adapter->link_speed != SPEED_1000) {
+ current_itr = 0;
+ new_itr = 4000;
+ goto set_itr_now;
+ }
+
+ adapter->tx_itr = e1000_update_itr(adapter,
+ adapter->tx_itr,
+ adapter->total_tx_packets,
+ adapter->total_tx_bytes);
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
+ adapter->tx_itr = low_latency;
+
+ adapter->rx_itr = e1000_update_itr(adapter,
+ adapter->rx_itr,
+ adapter->total_rx_packets,
+ adapter->total_rx_bytes);
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+ adapter->rx_itr = low_latency;
+
+ current_itr = max(adapter->rx_itr, adapter->tx_itr);
+
+ switch (current_itr) {
+ /* counts and packets in update_itr are dependent on these numbers */
+ case lowest_latency:
+ new_itr = 70000;
+ break;
+ case low_latency:
+ new_itr = 20000; /* aka hwitr = ~200 */
+ break;
+ case bulk_latency:
+ new_itr = 4000;
+ break;
+ default:
+ break;
+ }
+
+set_itr_now:
+ if (new_itr != adapter->itr) {
+ /* this attempts to bias the interrupt rate towards Bulk
+ * by adding intermediate steps when interrupt rate is
+ * increasing */
+ new_itr = new_itr > adapter->itr ?
+ min(adapter->itr + (new_itr >> 2), new_itr) :
+ new_itr;
+ adapter->itr = new_itr;
+ ew32(ITR, 1000000000 / (new_itr * 256));
+ }
+}
+
+/**
+ * e1000_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int e1000_clean(struct napi_struct *napi, int budget)
+{
+ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+ struct net_device *poll_dev = adapter->netdev;
+ int tx_cleaned = 0, work_done = 0;
+
+ /* Must NOT use netdev_priv macro here. */
+ adapter = poll_dev->priv;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(poll_dev))
+ goto quit_polling;
+
+ /* e1000_clean is called per-cpu. This lock protects
+ * tx_ring from being cleaned by multiple cpus
+ * simultaneously. A failure obtaining the lock means
+ * tx_ring is currently being cleaned anyway. */
+ if (spin_trylock(&adapter->tx_queue_lock)) {
+ tx_cleaned = e1000_clean_tx_irq(adapter);
+ spin_unlock(&adapter->tx_queue_lock);
+ }
+
+ adapter->clean_rx(adapter, &work_done, budget);
+
+ /* If no Tx and not enough Rx work done, exit the polling mode */
+ if ((!tx_cleaned && (work_done < budget)) ||
+ !netif_running(poll_dev)) {
+quit_polling:
+ if (adapter->itr_setting & 3)
+ e1000_set_itr(adapter);
+ netif_rx_complete(poll_dev, napi);
+ e1000_irq_enable(adapter);
+ }
+
+ return work_done;
+}
+
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 vfta, index;
+
+ /* don't update vlan cookie if already programmed */
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+ (vid == adapter->mng_vlan_id))
+ return;
+ /* add VID to filter table */
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
+ vfta |= (1 << (vid & 0x1F));
+ e1000e_write_vfta(hw, index, vfta);
+}
+
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 vfta, index;
+
+ e1000_irq_disable(adapter);
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
+ e1000_irq_enable(adapter);
+
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+ (vid == adapter->mng_vlan_id)) {
+ /* release control to f/w */
+ e1000_release_hw_control(adapter);
+ return;
+ }
+
+ /* remove VID from filter table */
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
+ vfta &= ~(1 << (vid & 0x1F));
+ e1000e_write_vfta(hw, index, vfta);
+}
+
+static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 vid = adapter->hw.mng_cookie.vlan_id;
+ u16 old_vid = adapter->mng_vlan_id;
+
+ if (!adapter->vlgrp)
+ return;
+
+ if (!vlan_group_get_device(adapter->vlgrp, vid)) {
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+ if (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+ e1000_vlan_rx_add_vid(netdev, vid);
+ adapter->mng_vlan_id = vid;
+ }
+
+ if ((old_vid != (u16)E1000_MNG_VLAN_NONE) &&
+ (vid != old_vid) &&
+ !vlan_group_get_device(adapter->vlgrp, old_vid))
+ e1000_vlan_rx_kill_vid(netdev, old_vid);
+ } else {
+ adapter->mng_vlan_id = vid;
+ }
+}
+
+
+static void e1000_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl, rctl;
+
+ e1000_irq_disable(adapter);
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_VME;
+ ew32(CTRL, ctrl);
+
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+ /* enable VLAN receive filtering */
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_VFE;
+ rctl &= ~E1000_RCTL_CFIEN;
+ ew32(RCTL, rctl);
+ e1000_update_mng_vlan(adapter);
+ }
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl = er32(CTRL);
+ ctrl &= ~E1000_CTRL_VME;
+ ew32(CTRL, ctrl);
+
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+ /* disable VLAN filtering */
+ rctl = er32(RCTL);
+ rctl &= ~E1000_RCTL_VFE;
+ ew32(RCTL, rctl);
+ if (adapter->mng_vlan_id !=
+ (u16)E1000_MNG_VLAN_NONE) {
+ e1000_vlan_rx_kill_vid(netdev,
+ adapter->mng_vlan_id);
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+ }
+ }
+ }
+
+ e1000_irq_enable(adapter);
+}
+
+static void e1000_restore_vlan(struct e1000_adapter *adapter)
+{
+ u16 vid;
+
+ e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+ if (!adapter->vlgrp)
+ return;
+
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
+ continue;
+ e1000_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+}
+
+static void e1000_init_manageability(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 manc, manc2h;
+
+ if (!(adapter->flags & FLAG_MNG_PT_ENABLED))
+ return;
+
+ manc = er32(MANC);
+
+ /* disable hardware interception of ARP */
+ manc &= ~(E1000_MANC_ARP_EN);
+
+ /* enable receiving management packets to the host. this will probably
+ * generate destination unreachable messages from the host OS, but
+ * the packets will be handled on SMBUS */
+ manc |= E1000_MANC_EN_MNG2HOST;
+ manc2h = er32(MANC2H);
+#define E1000_MNG2HOST_PORT_623 (1 << 5)
+#define E1000_MNG2HOST_PORT_664 (1 << 6)
+ manc2h |= E1000_MNG2HOST_PORT_623;
+ manc2h |= E1000_MNG2HOST_PORT_664;
+ ew32(MANC2H, manc2h);
+ ew32(MANC, manc);
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void e1000_configure_tx(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ u64 tdba;
+ u32 tdlen, tctl, tipg, tarc;
+ u32 ipgr1, ipgr2;
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ tdba = tx_ring->dma;
+ tdlen = tx_ring->count * sizeof(struct e1000_tx_desc);
+ ew32(TDBAL, (tdba & DMA_32BIT_MASK));
+ ew32(TDBAH, (tdba >> 32));
+ ew32(TDLEN, tdlen);
+ ew32(TDH, 0);
+ ew32(TDT, 0);
+ tx_ring->head = E1000_TDH;
+ tx_ring->tail = E1000_TDT;
+
+ /* Set the default values for the Tx Inter Packet Gap timer */
+ tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */
+ ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */
+ ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */
+
+ if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN)
+ ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */
+
+ tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+ tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
+ ew32(TIPG, tipg);
+
+ /* Set the Tx Interrupt Delay register */
+ ew32(TIDV, adapter->tx_int_delay);
+ /* tx irq moderation */
+ ew32(TADV, adapter->tx_abs_int_delay);
+
+ /* Program the Transmit Control Register */
+ tctl = er32(TCTL);
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+ if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
+ tarc = er32(TARC0);
+ /* set the speed mode bit, we'll clear it if we're not at
+ * gigabit link later */
+#define SPEED_MODE_BIT (1 << 21)
+ tarc |= SPEED_MODE_BIT;
+ ew32(TARC0, tarc);
+ }
+
+ /* errata: program both queues to unweighted RR */
+ if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
+ tarc = er32(TARC0);
+ tarc |= 1;
+ ew32(TARC0, tarc);
+ tarc = er32(TARC1);
+ tarc |= 1;
+ ew32(TARC1, tarc);
+ }
+
+ e1000e_config_collision_dist(hw);
+
+ /* Setup Transmit Descriptor Settings for eop descriptor */
+ adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
+
+ /* only set IDE if we are delaying interrupts using the timers */
+ if (adapter->tx_int_delay)
+ adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+
+ /* enable Report Status bit */
+ adapter->txd_cmd |= E1000_TXD_CMD_RS;
+
+ ew32(TCTL, tctl);
+
+ adapter->tx_queue_len = adapter->netdev->tx_queue_len;
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+static void e1000_setup_rctl(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl, rfctl;
+ u32 psrctl = 0;
+ u32 pages = 0;
+
+ /* Program MC offset vector base */
+ rctl = er32(RCTL);
+ rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+ /* Do not Store bad packets */
+ rctl &= ~E1000_RCTL_SBP;
+
+ /* Enable Long Packet receive */
+ if (adapter->netdev->mtu <= ETH_DATA_LEN)
+ rctl &= ~E1000_RCTL_LPE;
+ else
+ rctl |= E1000_RCTL_LPE;
+
+ /* Setup buffer sizes */
+ rctl &= ~E1000_RCTL_SZ_4096;
+ rctl |= E1000_RCTL_BSEX;
+ switch (adapter->rx_buffer_len) {
+ case 256:
+ rctl |= E1000_RCTL_SZ_256;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 512:
+ rctl |= E1000_RCTL_SZ_512;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 1024:
+ rctl |= E1000_RCTL_SZ_1024;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 2048:
+ default:
+ rctl |= E1000_RCTL_SZ_2048;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 4096:
+ rctl |= E1000_RCTL_SZ_4096;
+ break;
+ case 8192:
+ rctl |= E1000_RCTL_SZ_8192;
+ break;
+ case 16384:
+ rctl |= E1000_RCTL_SZ_16384;
+ break;
+ }
+
+ /*
+ * 82571 and greater support packet-split where the protocol
+ * header is placed in skb->data and the packet data is
+ * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
+ * In the case of a non-split, skb->data is linearly filled,
+ * followed by the page buffers. Therefore, skb->data is
+ * sized to hold the largest protocol header.
+ *
+ * allocations using alloc_page take too long for regular MTU
+ * so only enable packet split for jumbo frames
+ *
+ * Using pages when the page size is greater than 16k wastes
+ * 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))
+ adapter->rx_ps_pages = pages;
+
+ if (adapter->rx_ps_pages) {
+ /* Configure extra packet-split registers */
+ rfctl = er32(RFCTL);
+ rfctl |= E1000_RFCTL_EXTEN;
+ /* disable packet split support for IPv6 extension headers,
+ * because some malformed IPv6 headers can hang the RX */
+ rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
+ E1000_RFCTL_NEW_IPV6_EXT_DIS);
+
+ ew32(RFCTL, rfctl);
+
+ /* disable the stripping of CRC because it breaks
+ * BMC firmware connected over SMBUS */
+ rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */;
+
+ psrctl |= adapter->rx_ps_bsize0 >>
+ E1000_PSRCTL_BSIZE0_SHIFT;
+
+ switch (adapter->rx_ps_pages) {
+ case 3:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE3_SHIFT;
+ case 2:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE2_SHIFT;
+ case 1:
+ psrctl |= PAGE_SIZE >>
+ E1000_PSRCTL_BSIZE1_SHIFT;
+ break;
+ }
+
+ ew32(PSRCTL, psrctl);
+ }
+
+ ew32(RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void e1000_configure_rx(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ u64 rdba;
+ u32 rdlen, rctl, rxcsum, ctrl_ext;
+
+ if (adapter->rx_ps_pages) {
+ /* this is a 32 byte descriptor */
+ rdlen = rx_ring->count *
+ 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 + VLAN_HLEN + 4) {
+ rdlen = rx_ring->count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_rx_irq_jumbo;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers_jumbo;
+ } else {
+ rdlen = rx_ring->count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ }
+
+ /* disable receives while setting up the descriptors */
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ e1e_flush();
+ msleep(10);
+
+ /* set the Receive Delay Timer Register */
+ ew32(RDTR, adapter->rx_int_delay);
+
+ /* irq moderation */
+ ew32(RADV, adapter->rx_abs_int_delay);
+ if (adapter->itr_setting != 0)
+ ew32(ITR,
+ 1000000000 / (adapter->itr * 256));
+
+ ctrl_ext = er32(CTRL_EXT);
+ /* Reset delay timers after every interrupt */
+ ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+ /* Auto-Mask interrupts upon ICR access */
+ ctrl_ext |= E1000_CTRL_EXT_IAME;
+ ew32(IAM, 0xffffffff);
+ ew32(CTRL_EXT, ctrl_ext);
+ e1e_flush();
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ rdba = rx_ring->dma;
+ ew32(RDBAL, (rdba & DMA_32BIT_MASK));
+ ew32(RDBAH, (rdba >> 32));
+ ew32(RDLEN, rdlen);
+ ew32(RDH, 0);
+ ew32(RDT, 0);
+ rx_ring->head = E1000_RDH;
+ rx_ring->tail = E1000_RDT;
+
+ /* Enable Receive Checksum Offload for TCP and UDP */
+ rxcsum = er32(RXCSUM);
+ if (adapter->flags & FLAG_RX_CSUM_ENABLED) {
+ rxcsum |= E1000_RXCSUM_TUOFL;
+
+ /* IPv4 payload checksum for UDP fragments must be
+ * used in conjunction with packet-split. */
+ if (adapter->rx_ps_pages)
+ rxcsum |= E1000_RXCSUM_IPPCSE;
+ } else {
+ rxcsum &= ~E1000_RXCSUM_TUOFL;
+ /* no need to clear IPPCSE as it defaults to 0 */
+ }
+ ew32(RXCSUM, rxcsum);
+
+ /* Enable early receives on supported devices, only takes effect when
+ * packet size is equal or larger than the specified value (in 8 byte
+ * 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);
+
+ /* Enable Receives */
+ ew32(RCTL, rctl);
+}
+
+/**
+ * e1000_mc_addr_list_update - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @rar_used_count: the first RAR register free to program
+ * @rar_count: total number of supported Receive Address Registers
+ *
+ * Updates the Receive Address Registers and Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ * The parameter rar_count will usually be hw->mac.rar_entry_count
+ * unless there are workarounds that change this. Currently no func pointer
+ * exists and all implementations are handled in the generic version of this
+ * function.
+ **/
+static void e1000_mc_addr_list_update(struct e1000_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, u32 rar_used_count,
+ u32 rar_count)
+{
+ hw->mac.ops.mc_addr_list_update(hw, mc_addr_list, mc_addr_count,
+ rar_used_count, rar_count);
+}
+
+/**
+ * e1000_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void e1000_set_multi(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+ struct dev_mc_list *mc_ptr;
+ u8 *mta_list;
+ u32 rctl;
+ int i;
+
+ /* Check for Promiscuous and All Multicast modes */
+
+ rctl = er32(RCTL);
+
+ if (netdev->flags & IFF_PROMISC) {
+ rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ } else if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= E1000_RCTL_MPE;
+ rctl &= ~E1000_RCTL_UPE;
+ } else {
+ rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+ }
+
+ ew32(RCTL, rctl);
+
+ if (netdev->mc_count) {
+ mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!mta_list)
+ return;
+
+ /* prepare a packed array of only addresses. */
+ mc_ptr = netdev->mc_list;
+
+ for (i = 0; i < netdev->mc_count; i++) {
+ if (!mc_ptr)
+ break;
+ memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr,
+ ETH_ALEN);
+ mc_ptr = mc_ptr->next;
+ }
+
+ e1000_mc_addr_list_update(hw, mta_list, i, 1,
+ mac->rar_entry_count);
+ kfree(mta_list);
+ } else {
+ /*
+ * if we're called from probe, we might not have
+ * anything to do here, so clear out the list
+ */
+ e1000_mc_addr_list_update(hw, NULL, 0, 1,
+ mac->rar_entry_count);
+ }
+}
+
+/**
+ * e1000_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
+ **/
+static void e1000_configure(struct e1000_adapter *adapter)
+{
+ e1000_set_multi(adapter->netdev);
+
+ e1000_restore_vlan(adapter);
+ e1000_init_manageability(adapter);
+
+ e1000_configure_tx(adapter);
+ e1000_setup_rctl(adapter);
+ e1000_configure_rx(adapter);
+ adapter->alloc_rx_buf(adapter,
+ e1000_desc_unused(adapter->rx_ring));
+}
+
+/**
+ * e1000e_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000e_reset ***
+ **/
+void e1000e_power_up_phy(struct e1000_adapter *adapter)
+{
+ u16 mii_reg = 0;
+
+ /* Just clear the power down bit to wake the phy back up */
+ if (adapter->hw.media_type == e1000_media_type_copper) {
+ /* according to the manual, the phy will retain its
+ * settings across a power-down/up cycle */
+ e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg);
+ }
+
+ adapter->hw.mac.ops.setup_link(&adapter->hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down the PHY
+ *
+ * Power down the PHY so no link is implied when interface is down
+ * The PHY cannot be powered down is management or WoL is active
+ */
+static void e1000_power_down_phy(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u16 mii_reg;
+
+ /* WoL is enabled */
+ if (!adapter->wol)
+ return;
+
+ /* non-copper PHY? */
+ if (adapter->hw.media_type != e1000_media_type_copper)
+ return;
+
+ /* reset is blocked because of a SoL/IDER session */
+ if (e1000e_check_mng_mode(hw) ||
+ e1000_check_reset_block(hw))
+ return;
+
+ /* managebility (AMT) is enabled */
+ if (er32(MANC) & E1000_MANC_SMBUS_EN)
+ return;
+
+ /* power down the PHY */
+ e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ e1e_wphy(hw, PHY_CONTROL, mii_reg);
+ mdelay(1);
+}
+
+/**
+ * e1000e_reset - bring the hardware into a known good state
+ *
+ * This function boots the hardware and enables some settings that
+ * require a configuration cycle of the hardware - those cannot be
+ * set/changed during runtime. After reset the device needs to be
+ * properly configured for rx, tx etc.
+ */
+void e1000e_reset(struct e1000_adapter *adapter)
+{
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 tx_space, min_tx_space, min_rx_space;
+ u16 hwm;
+
+ if (mac->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) {
+ /* To maintain wire speed transmits, the Tx FIFO should be
+ * large enough to accommodate two full transmit packets,
+ * rounded up to the next 1KB and expressed in KB. Likewise,
+ * the Rx FIFO should be large enough to accommodate at least
+ * one full receive packet and is similarly rounded up and
+ * expressed in KB. */
+ adapter->pba = er32(PBA);
+ /* upper 16 bits has Tx packet buffer allocation size in KB */
+ tx_space = adapter->pba >> 16;
+ /* lower 16 bits has Rx packet buffer allocation size in KB */
+ adapter->pba &= 0xffff;
+ /* the tx fifo also stores 16 bytes of information about the tx
+ * but don't include ethernet FCS because hardware appends it */
+ min_tx_space = (mac->max_frame_size +
+ sizeof(struct e1000_tx_desc) -
+ ETH_FCS_LEN) * 2;
+ min_tx_space = ALIGN(min_tx_space, 1024);
+ min_tx_space >>= 10;
+ /* software strips receive CRC, so leave room for it */
+ min_rx_space = mac->max_frame_size;
+ min_rx_space = ALIGN(min_rx_space, 1024);
+ min_rx_space >>= 10;
+
+ /* If current Tx allocation is less than the min Tx FIFO size,
+ * and the min Tx FIFO size is less than the current Rx FIFO
+ * allocation, take space away from current Rx allocation */
+ if (tx_space < min_tx_space &&
+ ((min_tx_space - tx_space) < adapter->pba)) {
+ adapter->pba -= - (min_tx_space - tx_space);
+
+ /* if short on rx space, rx wins and must trump tx
+ * adjustment or use Early Receive if available */
+ if ((adapter->pba < min_rx_space) &&
+ (!(adapter->flags & FLAG_HAS_ERT)))
+ /* ERT enabled in e1000_configure_rx */
+ adapter->pba = min_rx_space;
+ }
+ }
+
+ ew32(PBA, adapter->pba);
+
+ /* flow control settings */
+ /* The high water mark must be low enough to fit one full frame
+ * (or the size used for early receive) above it in the Rx FIFO.
+ * Set it to the lower of:
+ * - 90% of the Rx FIFO size, and
+ * - the full Rx FIFO size minus the early receive size (for parts
+ * with ERT support assuming ERT set to E1000_ERT_2048), or
+ * - the full Rx FIFO size minus one full frame */
+ if (adapter->flags & FLAG_HAS_ERT)
+ hwm = min(((adapter->pba << 10) * 9 / 10),
+ ((adapter->pba << 10) - (E1000_ERT_2048 << 3)));
+ else
+ hwm = min(((adapter->pba << 10) * 9 / 10),
+ ((adapter->pba << 10) - mac->max_frame_size));
+
+ mac->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
+ mac->fc_low_water = mac->fc_high_water - 8;
+
+ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
+ mac->fc_pause_time = 0xFFFF;
+ else
+ mac->fc_pause_time = E1000_FC_PAUSE_TIME;
+ mac->fc = mac->original_fc;
+
+ /* Allow time for pending master requests to run */
+ mac->ops.reset_hw(hw);
+ ew32(WUC, 0);
+
+ if (mac->ops.init_hw(hw))
+ ndev_err(adapter->netdev, "Hardware Error\n");
+
+ e1000_update_mng_vlan(adapter);
+
+ /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
+ ew32(VET, ETH_P_8021Q);
+
+ e1000e_reset_adaptive(hw);
+ e1000_get_phy_info(hw);
+
+ if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) {
+ u16 phy_data = 0;
+ /* speed up time to link by disabling smart power down, ignore
+ * the return value of this function because there is nothing
+ * different we would do if it failed */
+ e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+ phy_data &= ~IGP02E1000_PM_SPD;
+ e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+ }
+
+ e1000_release_manageability(adapter);
+}
+
+int e1000e_up(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* hardware has been reset, we need to reload some things */
+ e1000_configure(adapter);
+
+ clear_bit(__E1000_DOWN, &adapter->state);
+
+ napi_enable(&adapter->napi);
+ e1000_irq_enable(adapter);
+
+ /* fire a link change interrupt to start the watchdog */
+ ew32(ICS, E1000_ICS_LSC);
+ return 0;
+}
+
+void e1000e_down(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 tctl, rctl;
+
+ /* signal that we're down so the interrupt handler does not
+ * reschedule our watchdog timer */
+ set_bit(__E1000_DOWN, &adapter->state);
+
+ /* disable receives in the hardware */
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ /* flush and sleep below */
+
+ netif_stop_queue(netdev);
+
+ /* disable transmits in the hardware */
+ tctl = er32(TCTL);
+ tctl &= ~E1000_TCTL_EN;
+ ew32(TCTL, tctl);
+ /* flush both disables and wait for them to finish */
+ e1e_flush();
+ msleep(10);
+
+ napi_disable(&adapter->napi);
+ e1000_irq_disable(adapter);
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_info_timer);
+
+ netdev->tx_queue_len = adapter->tx_queue_len;
+ netif_carrier_off(netdev);
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+
+ e1000e_reset(adapter);
+ e1000_clean_tx_ring(adapter);
+ e1000_clean_rx_ring(adapter);
+
+ /*
+ * TODO: for power management, we could drop the link and
+ * pci_disable_device here.
+ */
+}
+
+void e1000e_reinit_locked(struct e1000_adapter *adapter)
+{
+ might_sleep();
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+ e1000e_down(adapter);
+ e1000e_up(adapter);
+ clear_bit(__E1000_RESETTING, &adapter->state);
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+
+ adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN;
+ adapter->rx_ps_bsize0 = 128;
+ hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+ adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!adapter->tx_ring)
+ goto err;
+
+ adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!adapter->rx_ring)
+ goto err;
+
+ spin_lock_init(&adapter->tx_queue_lock);
+
+ /* Explicitly disable IRQ since the NIC can be in any state. */
+ atomic_set(&adapter->irq_sem, 0);
+ e1000_irq_disable(adapter);
+
+ spin_lock_init(&adapter->stats_lock);
+
+ set_bit(__E1000_DOWN, &adapter->state);
+ return 0;
+
+err:
+ ndev_err(netdev, "Unable to allocate memory for queues\n");
+ kfree(adapter->rx_ring);
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+}
+
+/**
+ * e1000_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int e1000_open(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ int err;
+
+ /* disallow open during test */
+ if (test_bit(__E1000_TESTING, &adapter->state))
+ return -EBUSY;
+
+ /* allocate transmit descriptors */
+ err = e1000e_setup_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ /* allocate receive descriptors */
+ err = e1000e_setup_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+
+ e1000e_power_up_phy(adapter);
+
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
+ e1000_update_mng_vlan(adapter);
+
+ /* If AMT is enabled, let the firmware know that the network
+ * interface is now open */
+ if ((adapter->flags & FLAG_HAS_AMT) &&
+ e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+ /* before we allocate an interrupt, we must be ready to handle it.
+ * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
+ * as soon as we call pci_request_irq, so we have to setup our
+ * clean_rx handler before we do so. */
+ e1000_configure(adapter);
+
+ err = e1000_request_irq(adapter);
+ if (err)
+ goto err_req_irq;
+
+ /* From here on the code is the same as e1000e_up() */
+ clear_bit(__E1000_DOWN, &adapter->state);
+
+ napi_enable(&adapter->napi);
+
+ e1000_irq_enable(adapter);
+
+ /* fire a link status change interrupt to start the watchdog */
+ ew32(ICS, E1000_ICS_LSC);
+
+ return 0;
+
+err_req_irq:
+ e1000_release_hw_control(adapter);
+ e1000_power_down_phy(adapter);
+ e1000e_free_rx_resources(adapter);
+err_setup_rx:
+ e1000e_free_tx_resources(adapter);
+err_setup_tx:
+ e1000e_reset(adapter);
+
+ return err;
+}
+
+/**
+ * e1000_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int e1000_close(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+ e1000e_down(adapter);
+ e1000_power_down_phy(adapter);
+ e1000_free_irq(adapter);
+
+ e1000e_free_tx_resources(adapter);
+ e1000e_free_rx_resources(adapter);
+
+ /* kill manageability vlan ID if supported, but not if a vlan with
+ * the same ID is registered on the host OS (let 8021q kill it) */
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+ !(adapter->vlgrp &&
+ vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
+ e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+
+ /* If AMT is enabled, let the firmware know that the network
+ * interface is now closed */
+ if ((adapter->flags & FLAG_HAS_AMT) &&
+ e1000e_check_mng_mode(&adapter->hw))
+ e1000_release_hw_control(adapter);
+
+ return 0;
+}
+/**
+ * e1000_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int e1000_set_mac(struct net_device *netdev, void *p)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+ e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+ if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) {
+ /* activate the work around */
+ e1000e_set_laa_state_82571(&adapter->hw, 1);
+
+ /* Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed (in e1000_watchdog), the actual LAA is in one
+ * of the RARs and no incoming packets directed to this port
+ * are dropped. Eventually the LAA will be in RAR[0] and
+ * RAR[14] */
+ e1000e_rar_set(&adapter->hw,
+ adapter->hw.mac.addr,
+ adapter->hw.mac.rar_entry_count - 1);
+ }
+
+ return 0;
+}
+
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy */
+static void e1000_update_phy_info(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+ e1000_get_phy_info(&adapter->hw);
+}
+
+/**
+ * e1000e_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+void e1000e_update_stats(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long irq_flags;
+ u16 phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+ /*
+ * Prevent stats update while adapter is being reset, or if the pci
+ * connection is down.
+ */
+ if (adapter->link_speed == 0)
+ return;
+ if (pci_channel_offline(pdev))
+ return;
+
+ spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+
+ /* these counters are modified from e1000_adjust_tbi_stats,
+ * called from the interrupt context, so they must only
+ * be written while holding adapter->stats_lock
+ */
+
+ adapter->stats.crcerrs += er32(CRCERRS);
+ adapter->stats.gprc += er32(GPRC);
+ adapter->stats.gorcl += er32(GORCL);
+ adapter->stats.gorch += er32(GORCH);
+ adapter->stats.bprc += er32(BPRC);
+ adapter->stats.mprc += er32(MPRC);
+ adapter->stats.roc += er32(ROC);
+
+ if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
+ adapter->stats.prc64 += er32(PRC64);
+ adapter->stats.prc127 += er32(PRC127);
+ adapter->stats.prc255 += er32(PRC255);
+ adapter->stats.prc511 += er32(PRC511);
+ adapter->stats.prc1023 += er32(PRC1023);
+ adapter->stats.prc1522 += er32(PRC1522);
+ adapter->stats.symerrs += er32(SYMERRS);
+ adapter->stats.sec += er32(SEC);
+ }
+
+ adapter->stats.mpc += er32(MPC);
+ adapter->stats.scc += er32(SCC);
+ adapter->stats.ecol += er32(ECOL);
+ adapter->stats.mcc += er32(MCC);
+ adapter->stats.latecol += er32(LATECOL);
+ adapter->stats.dc += er32(DC);
+ adapter->stats.rlec += er32(RLEC);
+ adapter->stats.xonrxc += er32(XONRXC);
+ adapter->stats.xontxc += er32(XONTXC);
+ adapter->stats.xoffrxc += er32(XOFFRXC);
+ adapter->stats.xofftxc += er32(XOFFTXC);
+ adapter->stats.fcruc += er32(FCRUC);
+ adapter->stats.gptc += er32(GPTC);
+ adapter->stats.gotcl += er32(GOTCL);
+ adapter->stats.gotch += er32(GOTCH);
+ adapter->stats.rnbc += er32(RNBC);
+ adapter->stats.ruc += er32(RUC);
+ adapter->stats.rfc += er32(RFC);
+ adapter->stats.rjc += er32(RJC);
+ adapter->stats.torl += er32(TORL);
+ adapter->stats.torh += er32(TORH);
+ adapter->stats.totl += er32(TOTL);
+ adapter->stats.toth += er32(TOTH);
+ adapter->stats.tpr += er32(TPR);
+
+ if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
+ adapter->stats.ptc64 += er32(PTC64);
+ adapter->stats.ptc127 += er32(PTC127);
+ adapter->stats.ptc255 += er32(PTC255);
+ adapter->stats.ptc511 += er32(PTC511);
+ adapter->stats.ptc1023 += er32(PTC1023);
+ adapter->stats.ptc1522 += er32(PTC1522);
+ }
+
+ adapter->stats.mptc += er32(MPTC);
+ adapter->stats.bptc += er32(BPTC);
+
+ /* used for adaptive IFS */
+
+ hw->mac.tx_packet_delta = er32(TPT);
+ adapter->stats.tpt += hw->mac.tx_packet_delta;
+ hw->mac.collision_delta = er32(COLC);
+ adapter->stats.colc += hw->mac.collision_delta;
+
+ adapter->stats.algnerrc += er32(ALGNERRC);
+ adapter->stats.rxerrc += er32(RXERRC);
+ adapter->stats.tncrs += er32(TNCRS);
+ adapter->stats.cexterr += er32(CEXTERR);
+ adapter->stats.tsctc += er32(TSCTC);
+ adapter->stats.tsctfc += er32(TSCTFC);
+
+ adapter->stats.iac += er32(IAC);
+
+ if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) {
+ adapter->stats.icrxoc += er32(ICRXOC);
+ adapter->stats.icrxptc += er32(ICRXPTC);
+ adapter->stats.icrxatc += er32(ICRXATC);
+ adapter->stats.ictxptc += er32(ICTXPTC);
+ adapter->stats.ictxatc += er32(ICTXATC);
+ adapter->stats.ictxqec += er32(ICTXQEC);
+ adapter->stats.ictxqmtc += er32(ICTXQMTC);
+ adapter->stats.icrxdmtc += er32(ICRXDMTC);
+ }
+
+ /* Fill out the OS statistics structure */
+ adapter->net_stats.rx_packets = adapter->stats.gprc;
+ adapter->net_stats.tx_packets = adapter->stats.gptc;
+ adapter->net_stats.rx_bytes = adapter->stats.gorcl;
+ adapter->net_stats.tx_bytes = adapter->stats.gotcl;
+ adapter->net_stats.multicast = adapter->stats.mprc;
+ adapter->net_stats.collisions = adapter->stats.colc;
+
+ /* Rx Errors */
+
+ /* RLEC on some newer hardware can be incorrect so build
+ * our own version based on RUC and ROC */
+ adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+ adapter->stats.crcerrs + adapter->stats.algnerrc +
+ adapter->stats.ruc + adapter->stats.roc +
+ adapter->stats.cexterr;
+ adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+ adapter->stats.roc;
+ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+ adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+ adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+ /* Tx Errors */
+ adapter->net_stats.tx_errors = adapter->stats.ecol +
+ adapter->stats.latecol;
+ adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+ adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+ adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+ /* Tx Dropped needs to be maintained elsewhere */
+
+ /* Phy Stats */
+ if (hw->media_type == e1000_media_type_copper) {
+ if ((adapter->link_speed == SPEED_1000) &&
+ (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) {
+ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+ adapter->phy_stats.idle_errors += phy_tmp;
+ }
+ }
+
+ /* Management Stats */
+ adapter->stats.mgptc += er32(MGTPTC);
+ adapter->stats.mgprc += er32(MGTPRC);
+ adapter->stats.mgpdc += er32(MGTPDC);
+
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+}
+
+static void e1000_print_link_info(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl = er32(CTRL);
+
+ ndev_info(netdev,
+ "Link is Up %d Mbps %s, Flow Control: %s\n",
+ adapter->link_speed,
+ (adapter->link_duplex == FULL_DUPLEX) ?
+ "Full Duplex" : "Half Duplex",
+ ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
+ "RX/TX" :
+ ((ctrl & E1000_CTRL_RFCE) ? "RX" :
+ ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+}
+
+/**
+ * e1000_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void e1000_watchdog(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+ /* Do the rest outside of interrupt context */
+ schedule_work(&adapter->watchdog_task);
+
+ /* TODO: make this use queue_delayed_work() */
+}
+
+static void e1000_watchdog_task(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter, watchdog_task);
+
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 link, tctl;
+ s32 ret_val;
+ int tx_pending = 0;
+
+ if ((netif_carrier_ok(netdev)) &&
+ (er32(STATUS) & E1000_STATUS_LU))
+ goto link_up;
+
+ ret_val = mac->ops.check_for_link(hw);
+ if ((ret_val == E1000_ERR_PHY) &&
+ (adapter->hw.phy.type == e1000_phy_igp_3) &&
+ (er32(CTRL) &
+ E1000_PHY_CTRL_GBE_DISABLE)) {
+ /* See e1000_kmrn_lock_loss_workaround_ich8lan() */
+ ndev_info(netdev,
+ "Gigabit has been disabled, downgrading speed\n");
+ }
+
+ if ((e1000e_enable_tx_pkt_filtering(hw)) &&
+ (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id))
+ e1000_update_mng_vlan(adapter);
+
+ if ((adapter->hw.media_type == e1000_media_type_internal_serdes) &&
+ !(er32(TXCW) & E1000_TXCW_ANE))
+ link = adapter->hw.mac.serdes_has_link;
+ else
+ link = er32(STATUS) & E1000_STATUS_LU;
+
+ if (link) {
+ if (!netif_carrier_ok(netdev)) {
+ bool txb2b = 1;
+ mac->ops.get_link_up_info(&adapter->hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+ e1000_print_link_info(adapter);
+ /* tweak tx_queue_len according to speed/duplex
+ * and adjust the timeout factor */
+ netdev->tx_queue_len = adapter->tx_queue_len;
+ adapter->tx_timeout_factor = 1;
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ txb2b = 0;
+ netdev->tx_queue_len = 10;
+ adapter->tx_timeout_factor = 14;
+ break;
+ case SPEED_100:
+ txb2b = 0;
+ netdev->tx_queue_len = 100;
+ /* maybe add some timeout factor ? */
+ break;
+ }
+
+ /* workaround: re-program speed mode bit after
+ * link-up event */
+ if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) &&
+ !txb2b) {
+ u32 tarc0;
+ tarc0 = er32(TARC0);
+ tarc0 &= ~SPEED_MODE_BIT;
+ ew32(TARC0, tarc0);
+ }
+
+ /* disable TSO for pcie and 10/100 speeds, to avoid
+ * some hardware issues */
+ if (!(adapter->flags & FLAG_TSO_FORCE)) {
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ case SPEED_100:
+ ndev_info(netdev,
+ "10/100 speed: disabling TSO\n");
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ break;
+ case SPEED_1000:
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ break;
+ default:
+ /* oops */
+ break;
+ }
+ }
+
+ /* enable transmits in the hardware, need to do this
+ * after setting TARC0 */
+ tctl = er32(TCTL);
+ tctl |= E1000_TCTL_EN;
+ ew32(TCTL, tctl);
+
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->phy_info_timer,
+ round_jiffies(jiffies + 2 * HZ));
+ } else {
+ /* make sure the receive unit is started */
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART) {
+ u32 rctl = er32(RCTL);
+ ew32(RCTL, rctl |
+ E1000_RCTL_EN);
+ }
+ }
+ } else {
+ if (netif_carrier_ok(netdev)) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+ ndev_info(netdev, "Link is Down\n");
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->phy_info_timer,
+ round_jiffies(jiffies + 2 * HZ));
+
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART)
+ schedule_work(&adapter->reset_task);
+ }
+ }
+
+link_up:
+ e1000e_update_stats(adapter);
+
+ mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
+ adapter->tpt_old = adapter->stats.tpt;
+ mac->collision_delta = adapter->stats.colc - adapter->colc_old;
+ adapter->colc_old = adapter->stats.colc;
+
+ adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
+ adapter->gorcl_old = adapter->stats.gorcl;
+ adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
+ adapter->gotcl_old = adapter->stats.gotcl;
+
+ e1000e_update_adaptive(&adapter->hw);
+
+ if (!netif_carrier_ok(netdev)) {
+ tx_pending = (e1000_desc_unused(tx_ring) + 1 <
+ tx_ring->count);
+ if (tx_pending) {
+ /* We've lost link, so the controller stops DMA,
+ * but we've got queued Tx work that's never going
+ * to get done, so reset controller to flush Tx.
+ * (Do the reset outside of interrupt context). */
+ adapter->tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+ }
+ }
+
+ /* Cause software interrupt to ensure rx ring is cleaned */
+ ew32(ICS, E1000_ICS_RXDMT0);
+
+ /* Force detection of hung controller every watchdog period */
+ adapter->detect_tx_hung = 1;
+
+ /* With 82571 controllers, LAA may be overwritten due to controller
+ * reset from the other port. Set the appropriate LAA in RAR[0] */
+ if (e1000e_get_laa_state_82571(hw))
+ e1000e_rar_set(hw, adapter->hw.mac.addr, 0);
+
+ /* Reset the timer */
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 2 * HZ));
+}
+
+#define E1000_TX_FLAGS_CSUM 0x00000001
+#define E1000_TX_FLAGS_VLAN 0x00000002
+#define E1000_TX_FLAGS_TSO 0x00000004
+#define E1000_TX_FLAGS_IPV4 0x00000008
+#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT 16
+
+static int e1000_tso(struct e1000_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_context_desc *context_desc;
+ struct e1000_buffer *buffer_info;
+ unsigned int i;
+ u32 cmd_length = 0;
+ u16 ipcse = 0, tucse, mss;
+ u8 ipcss, ipcso, tucss, tucso, hdr_len;
+ int err;
+
+ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+ return err;
+ }
+
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ mss = skb_shinfo(skb)->gso_size;
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+ iph->tot_len = 0;
+ iph->check = 0;
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ cmd_length = E1000_TXD_CMD_IP;
+ ipcse = skb_transport_offset(skb) - 1;
+ } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
+ ipcse = 0;
+ }
+ ipcss = skb_network_offset(skb);
+ ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data;
+ tucss = skb_transport_offset(skb);
+ tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
+ tucse = 0;
+
+ cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
+ E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
+
+ i = tx_ring->next_to_use;
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
+
+ context_desc->lower_setup.ip_fields.ipcss = ipcss;
+ context_desc->lower_setup.ip_fields.ipcso = ipcso;
+ context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
+ context_desc->upper_setup.tcp_fields.tucss = tucss;
+ context_desc->upper_setup.tcp_fields.tucso = tucso;
+ context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
+ context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
+ context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
+ context_desc->cmd_and_length = cpu_to_le32(cmd_length);
+
+ buffer_info->time_stamp = jiffies;
+ buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_context_desc *context_desc;
+ struct e1000_buffer *buffer_info;
+ unsigned int i;
+ u8 css;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ css = skb_transport_offset(skb);
+
+ i = tx_ring->next_to_use;
+ buffer_info = &tx_ring->buffer_info[i];
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+
+ context_desc->lower_setup.ip_config = 0;
+ context_desc->upper_setup.tcp_fields.tucss = css;
+ context_desc->upper_setup.tcp_fields.tucso =
+ css + skb->csum_offset;
+ context_desc->upper_setup.tcp_fields.tucse = 0;
+ context_desc->tcp_seg_setup.data = 0;
+ context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
+
+ buffer_info->time_stamp = jiffies;
+ buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+#define E1000_MAX_PER_TXD 8192
+#define E1000_MAX_TXD_PWR 12
+
+static int e1000_tx_map(struct e1000_adapter *adapter,
+ struct sk_buff *skb, unsigned int first,
+ unsigned int max_per_txd, unsigned int nr_frags,
+ unsigned int mss)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_buffer *buffer_info;
+ unsigned int len = skb->len - skb->data_len;
+ unsigned int offset = 0, size, count = 0, i;
+ unsigned int f;
+
+ i = tx_ring->next_to_use;
+
+ while (len) {
+ buffer_info = &tx_ring->buffer_info[i];
+ size = min(len, max_per_txd);
+
+ /* Workaround for premature desc write-backs
+ * in TSO mode. Append 4-byte sentinel desc */
+ if (mss && !nr_frags && size == len && size > 8)
+ size -= 4;
+
+ buffer_info->length = size;
+ /* set time_stamp *before* dma to help avoid a possible race */
+ buffer_info->time_stamp = jiffies;
+ buffer_info->dma =
+ pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+ adapter->tx_dma_failed++;
+ return -1;
+ }
+ buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ len = frag->size;
+ offset = frag->page_offset;
+
+ while (len) {
+ buffer_info = &tx_ring->buffer_info[i];
+ size = min(len, max_per_txd);
+ /* Workaround for premature desc write-backs
+ * in TSO mode. Append 4-byte sentinel desc */
+ if (mss && f == (nr_frags-1) && size == len && size > 8)
+ size -= 4;
+
+ buffer_info->length = size;
+ buffer_info->time_stamp = jiffies;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev,
+ frag->page,
+ offset,
+ size,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&adapter->pdev->dev,
+ "TX DMA page map failed\n");
+ adapter->tx_dma_failed++;
+ return -1;
+ }
+
+ buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+ }
+
+ if (i == 0)
+ i = tx_ring->count - 1;
+ else
+ i--;
+
+ tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[first].next_to_watch = i;
+
+ return count;
+}
+
+static void e1000_tx_queue(struct e1000_adapter *adapter,
+ int tx_flags, int count)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc = NULL;
+ struct e1000_buffer *buffer_info;
+ u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
+ unsigned int i;
+
+ if (tx_flags & E1000_TX_FLAGS_TSO) {
+ txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
+ E1000_TXD_CMD_TSE;
+ txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+
+ if (tx_flags & E1000_TX_FLAGS_IPV4)
+ txd_upper |= E1000_TXD_POPTS_IXSM << 8;
+ }
+
+ if (tx_flags & E1000_TX_FLAGS_CSUM) {
+ txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+ }
+
+ if (tx_flags & E1000_TX_FLAGS_VLAN) {
+ txd_lower |= E1000_TXD_CMD_VLE;
+ txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+ }
+
+ i = tx_ring->next_to_use;
+
+ while (count--) {
+ buffer_info = &tx_ring->buffer_info[i];
+ tx_desc = E1000_TX_DESC(*tx_ring, i);
+ tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ tx_desc->lower.data =
+ cpu_to_le32(txd_lower | buffer_info->length);
+ tx_desc->upper.data = cpu_to_le32(txd_upper);
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+
+ tx_ring->next_to_use = i;
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+ /* we need this if more than one processor can write to our tail
+ * at a time, it synchronizes IO on IA64/Altix systems */
+ mmiowb();
+}
+
+#define MINIMUM_DHCP_PACKET_SIZE 282
+static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u16 length, offset;
+
+ if (vlan_tx_tag_present(skb)) {
+ if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id)
+ && (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
+ return 0;
+ }
+
+ if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
+ return 0;
+
+ if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP))
+ return 0;
+
+ {
+ const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14);
+ struct udphdr *udp;
+
+ if (ip->protocol != IPPROTO_UDP)
+ return 0;
+
+ udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
+ if (ntohs(udp->dest) != 67)
+ return 0;
+
+ offset = (u8 *)udp + 8 - skb->data;
+ length = skb->len - offset;
+ return e1000e_mng_write_dhcp_info(hw, (u8 *)udp + 8, length);
+ }
+
+ return 0;
+}
+
+static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ netif_stop_queue(netdev);
+ /* Herbert's original patch had:
+ * smp_mb__after_netif_stop_queue();
+ * but since that doesn't exist yet, just open code it. */
+ smp_mb();
+
+ /* We need to check again in a case another CPU has just
+ * made room available. */
+ if (e1000_desc_unused(adapter->tx_ring) < size)
+ return -EBUSY;
+
+ /* A reprieve! */
+ netif_start_queue(netdev);
+ ++adapter->restart_queue;
+ return 0;
+}
+
+static int e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (e1000_desc_unused(adapter->tx_ring) >= size)
+ return 0;
+ return __e1000_maybe_stop_tx(netdev, size);
+}
+
+#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
+static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ unsigned int first;
+ unsigned int max_per_txd = E1000_MAX_PER_TXD;
+ unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
+ unsigned int tx_flags = 0;
+ unsigned int len = skb->len - skb->data_len;
+ unsigned long irq_flags;
+ unsigned int nr_frags;
+ unsigned int mss;
+ int count = 0;
+ int tso;
+ unsigned int f;
+
+ if (test_bit(__E1000_DOWN, &adapter->state)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (skb->len <= 0) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ mss = skb_shinfo(skb)->gso_size;
+ /* The controller does a simple calculation to
+ * make sure there is enough room in the FIFO before
+ * initiating the DMA for each buffer. The calc is:
+ * 4 = ceil(buffer len/mss). To make sure we don't
+ * overrun the FIFO, adjust the max buffer len if mss
+ * drops. */
+ if (mss) {
+ u8 hdr_len;
+ max_per_txd = min(mss << 2, max_per_txd);
+ max_txd_pwr = fls(max_per_txd) - 1;
+
+ /* TSO Workaround for 82571/2/3 Controllers -- if skb->data
+ * points to just header, pull a few bytes of payload from
+ * frags into skb->data */
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ if (skb->data_len && (hdr_len == len)) {
+ unsigned int pull_size;
+
+ pull_size = min((unsigned int)4, skb->data_len);
+ if (!__pskb_pull_tail(skb, pull_size)) {
+ ndev_err(netdev,
+ "__pskb_pull_tail failed.\n");
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ len = skb->len - skb->data_len;
+ }
+ }
+
+ /* reserve a descriptor for the offload context */
+ if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
+ count++;
+ count++;
+
+ count += TXD_USE_COUNT(len, max_txd_pwr);
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ for (f = 0; f < nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+ max_txd_pwr);
+
+ if (adapter->hw.mac.tx_pkt_filtering)
+ e1000_transfer_dhcp_info(adapter, skb);
+
+ if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags))
+ /* Collision - tell upper layer to requeue */
+ return NETDEV_TX_LOCKED;
+
+ /* need: count + 2 desc gap to keep tail from touching
+ * head, otherwise try next time */
+ if (e1000_maybe_stop_tx(netdev, count + 2)) {
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= E1000_TX_FLAGS_VLAN;
+ tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+ }
+
+ first = tx_ring->next_to_use;
+
+ tso = e1000_tso(adapter, skb);
+ if (tso < 0) {
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_OK;
+ }
+
+ if (tso)
+ tx_flags |= E1000_TX_FLAGS_TSO;
+ else if (e1000_tx_csum(adapter, skb))
+ tx_flags |= E1000_TX_FLAGS_CSUM;
+
+ /* Old method was to assume IPv4 packet by default if TSO was enabled.
+ * 82571 hardware supports TSO capabilities for IPv6 as well...
+ * no longer assume, we must. */
+ if (skb->protocol == htons(ETH_P_IP))
+ tx_flags |= E1000_TX_FLAGS_IPV4;
+
+ count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss);
+ if (count < 0) {
+ /* handle pci_map_single() error in e1000_tx_map */
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_OK;
+ }
+
+ e1000_tx_queue(adapter, tx_flags, count);
+
+ netdev->trans_start = jiffies;
+
+ /* Make sure there is space in the ring for the next send. */
+ e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
+
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * e1000_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void e1000_tx_timeout(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /* Do the reset outside of interrupt context */
+ adapter->tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+}
+
+static void e1000_reset_task(struct work_struct *work)
+{
+ struct e1000_adapter *adapter;
+ adapter = container_of(work, struct e1000_adapter, reset_task);
+
+ e1000e_reinit_locked(adapter);
+}
+
+/**
+ * e1000_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /* only return the current stats */
+ return &adapter->net_stats;
+}
+
+/**
+ * e1000_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+ ndev_err(netdev, "Invalid MTU setting\n");
+ return -EINVAL;
+ }
+
+ /* Jumbo frame size limits */
+ if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
+ if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+ ndev_err(netdev, "Jumbo Frames not supported.\n");
+ return -EINVAL;
+ }
+ if (adapter->hw.phy.type == e1000_phy_ife) {
+ ndev_err(netdev, "Jumbo Frames not supported.\n");
+ return -EINVAL;
+ }
+ }
+
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
+ if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+ ndev_err(netdev, "MTU > 9216 not supported.\n");
+ return -EINVAL;
+ }
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+ /* e1000e_down has a dependency on max_frame_size */
+ adapter->hw.mac.max_frame_size = max_frame;
+ if (netif_running(netdev))
+ e1000e_down(adapter);
+
+ /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+ * means we reserve 2 more, this pushes us to allocate from the next
+ * larger slab size.
+ * i.e. RXBUFFER_2048 --> size-4096 slab
+ * however with the new *_jumbo* routines, jumbo receives will use
+ * fragmented skbs */
+
+ if (max_frame <= 256)
+ adapter->rx_buffer_len = 256;
+ else if (max_frame <= 512)
+ adapter->rx_buffer_len = 512;
+ else if (max_frame <= 1024)
+ adapter->rx_buffer_len = 1024;
+ else if (max_frame <= 2048)
+ adapter->rx_buffer_len = 2048;
+ else
+ adapter->rx_buffer_len = 4096;
+
+ /* adjust allocation if LPE protects us, and we aren't using SBP */
+ if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
+ (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
+ adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
+ + ETH_FCS_LEN ;
+
+ ndev_info(netdev, "changing MTU from %d to %d\n",
+ netdev->mtu, new_mtu);
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev))
+ e1000e_up(adapter);
+ else
+ e1000e_reset(adapter);
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+
+ return 0;
+}
+
+static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
+ int cmd)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+ unsigned long irq_flags;
+
+ if (adapter->hw.media_type != e1000_media_type_copper)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = adapter->hw.phy.addr;
+ break;
+ case SIOCGMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+ if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F,
+ &data->val_out)) {
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+ return -EIO;
+ }
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+ break;
+ case SIOCSMIIREG:
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return e1000_mii_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl, ctrl_ext, rctl, status;
+ u32 wufc = adapter->wol;
+ int retval = 0;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+ e1000e_down(adapter);
+ e1000_free_irq(adapter);
+ }
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU)
+ wufc &= ~E1000_WUFC_LNKC;
+
+ if (wufc) {
+ e1000_setup_rctl(adapter);
+ e1000_set_multi(netdev);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+ if (wufc & E1000_WUFC_MC) {
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_MPE;
+ ew32(RCTL, rctl);
+ }
+
+ ctrl = er32(CTRL);
+ /* advertise wake from D3Cold */
+ #define E1000_CTRL_ADVD3WUC 0x00100000
+ /* phy power management enable */
+ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+ ctrl |= E1000_CTRL_ADVD3WUC |
+ E1000_CTRL_EN_PHY_PWR_MGMT;
+ ew32(CTRL, ctrl);
+
+ if (adapter->hw.media_type == e1000_media_type_fiber ||
+ adapter->hw.media_type == e1000_media_type_internal_serdes) {
+ /* keep the laser running in D3 */
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+ ew32(CTRL_EXT, ctrl_ext);
+ }
+
+ /* Allow time for pending master requests to run */
+ e1000e_disable_pcie_master(&adapter->hw);
+
+ ew32(WUC, E1000_WUC_PME_EN);
+ ew32(WUFC, wufc);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ } else {
+ ew32(WUC, 0);
+ ew32(WUFC, 0);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+ }
+
+ e1000_release_manageability(adapter);
+
+ /* make sure adapter isn't asleep if manageability is enabled */
+ if (adapter->flags & FLAG_MNG_PT_ENABLED) {
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ }
+
+ if (adapter->hw.phy.type == e1000_phy_igp_3)
+ e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant. */
+ e1000_release_hw_control(adapter);
+
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int e1000_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Cannot enable PCI device from suspend\n");
+ return err;
+ }
+
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ if (netif_running(netdev)) {
+ err = e1000_request_irq(adapter);
+ if (err)
+ return err;
+ }
+
+ e1000e_power_up_phy(adapter);
+ e1000e_reset(adapter);
+ ew32(WUS, ~0);
+
+ e1000_init_manageability(adapter);
+
+ if (netif_running(netdev))
+ e1000e_up(adapter);
+
+ netif_device_attach(netdev);
+
+ /* If the controller has AMT, do not set DRV_LOAD until the interface
+ * is up. For all other cases, let the f/w know that the h/w is now
+ * under the control of the driver. */
+ if (!(adapter->flags & FLAG_HAS_AMT) || !e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+ return 0;
+}
+#endif
+
+static void e1000_shutdown(struct pci_dev *pdev)
+{
+ e1000_suspend(pdev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void e1000_netpoll(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ disable_irq(adapter->pdev->irq);
+ e1000_intr(adapter->pdev->irq, netdev);
+
+ e1000_clean_tx_irq(adapter);
+
+ enable_irq(adapter->pdev->irq);
+}
+#endif
+
+/**
+ * e1000_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ e1000e_down(adapter);
+ pci_disable_device(pdev);
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e1000_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev,
+ "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ e1000e_reset(adapter);
+ ew32(WUS, ~0);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e1000_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the e1000_resume routine.
+ */
+static void e1000_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ e1000_init_manageability(adapter);
+
+ if (netif_running(netdev)) {
+ if (e1000e_up(adapter)) {
+ dev_err(&pdev->dev,
+ "can't bring device back up after reset\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+
+ /* If the controller has AMT, do not set DRV_LOAD until the interface
+ * is up. For all other cases, let the f/w know that the h/w is now
+ * under the control of the driver. */
+ if (!(adapter->flags & FLAG_HAS_AMT) ||
+ !e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+}
+
+static void e1000_print_device_info(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ u32 part_num;
+
+ /* print bus type/speed/width info */
+ ndev_info(netdev, "(PCI Express:2.5GB/s:%s) "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ /* bus width */
+ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
+ "Width x1"),
+ /* MAC address */
+ netdev->dev_addr[0], netdev->dev_addr[1],
+ netdev->dev_addr[2], netdev->dev_addr[3],
+ netdev->dev_addr[4], netdev->dev_addr[5]);
+ ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n",
+ (hw->phy.type == e1000_phy_ife)
+ ? "10/100" : "1000");
+ e1000e_read_part_num(hw, &part_num);
+ ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type,
+ (part_num >> 8), (part_num & 0xff));
+}
+
+/**
+ * e1000_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in e1000_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * e1000_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit e1000_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct e1000_adapter *adapter;
+ struct e1000_hw *hw;
+ const struct e1000_info *ei = e1000_info_tbl[ent->driver_data];
+ unsigned long mmio_start, mmio_len;
+ unsigned long flash_start, flash_len;
+
+ static int cards_found;
+ int i, err, pci_using_dac;
+ u16 eeprom_data = 0;
+ u16 eeprom_apme_mask = E1000_EEPROM_APME;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_using_dac = 0;
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (!err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (!err)
+ pci_using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev,
+ DMA_32BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "No usable DMA "
+ "configuration, aborting\n");
+ goto err_dma;
+ }
+ }
+ }
+
+ err = pci_request_regions(pdev, e1000e_driver_name);
+ if (err)
+ goto err_pci_reg;
+
+ pci_set_master(pdev);
+
+ err = -ENOMEM;
+ netdev = alloc_etherdev(sizeof(struct e1000_adapter));
+ if (!netdev)
+ goto err_alloc_etherdev;
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ hw = &adapter->hw;
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->ei = ei;
+ adapter->pba = ei->pba;
+ adapter->flags = ei->flags;
+ adapter->hw.adapter = adapter;
+ adapter->hw.mac.type = ei->mac;
+ adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+
+ err = -EIO;
+ adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+ if (!adapter->hw.hw_addr)
+ goto err_ioremap;
+
+ if ((adapter->flags & FLAG_HAS_FLASH) &&
+ (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+ flash_start = pci_resource_start(pdev, 1);
+ flash_len = pci_resource_len(pdev, 1);
+ adapter->hw.flash_address = ioremap(flash_start, flash_len);
+ if (!adapter->hw.flash_address)
+ goto err_flashmap;
+ }
+
+ /* construct the net_device struct */
+ netdev->open = &e1000_open;
+ netdev->stop = &e1000_close;
+ netdev->hard_start_xmit = &e1000_xmit_frame;
+ netdev->get_stats = &e1000_get_stats;
+ netdev->set_multicast_list = &e1000_set_multi;
+ netdev->set_mac_address = &e1000_set_mac;
+ netdev->change_mtu = &e1000_change_mtu;
+ netdev->do_ioctl = &e1000_ioctl;
+ e1000e_set_ethtool_ops(netdev);
+ netdev->tx_timeout = &e1000_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
+ netdev->vlan_rx_register = e1000_vlan_rx_register;
+ netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = e1000_netpoll;
+#endif
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+
+ adapter->bd_number = cards_found++;
+
+ /* setup adapter struct */
+ err = e1000_sw_init(adapter);
+ if (err)
+ goto err_sw_init;
+
+ err = -EIO;
+
+ memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
+ memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
+ memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
+
+ err = ei->get_invariants(adapter);
+ if (err)
+ goto err_hw_init;
+
+ hw->mac.ops.get_bus_info(&adapter->hw);
+
+ adapter->hw.phy.wait_for_link = 0;
+
+ /* Copper options */
+ if (adapter->hw.media_type == e1000_media_type_copper) {
+ adapter->hw.phy.mdix = AUTO_ALL_MODES;
+ adapter->hw.phy.disable_polarity_correction = 0;
+ adapter->hw.phy.ms_type = e1000_ms_hw_default;
+ }
+
+ if (e1000_check_reset_block(&adapter->hw))
+ ndev_info(netdev,
+ "PHY reset is blocked due to SOL/IDER session.\n");
+
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX;
+
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
+ netdev->features |= NETIF_F_HW_VLAN_FILTER;
+
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ /* We should not be using LLTX anymore, but we are still TX faster with
+ * it. */
+ netdev->features |= NETIF_F_LLTX;
+
+ if (e1000e_enable_mng_pass_thru(&adapter->hw))
+ adapter->flags |= FLAG_MNG_PT_ENABLED;
+
+ /* before reading the NVM, reset the controller to
+ * put the device in a known good starting state */
+ adapter->hw.mac.ops.reset_hw(&adapter->hw);
+
+ /*
+ * systems with ASPM and others may see the checksum fail on the first
+ * attempt. Let's give it a few tries
+ */
+ for (i = 0;; i++) {
+ if (e1000_validate_nvm_checksum(&adapter->hw) >= 0)
+ break;
+ if (i == 2) {
+ ndev_err(netdev, "The NVM Checksum Is Not Valid\n");
+ err = -EIO;
+ goto err_eeprom;
+ }
+ }
+
+ /* copy the MAC address out of the NVM */
+ if (e1000e_read_mac_addr(&adapter->hw))
+ ndev_err(netdev, "NVM Read Error while reading MAC address\n");
+
+ memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ ndev_err(netdev, "Invalid MAC Address: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netdev->perm_addr[0], netdev->perm_addr[1],
+ netdev->perm_addr[2], netdev->perm_addr[3],
+ netdev->perm_addr[4], netdev->perm_addr[5]);
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &e1000_watchdog;
+ adapter->watchdog_timer.data = (unsigned long) adapter;
+
+ init_timer(&adapter->phy_info_timer);
+ adapter->phy_info_timer.function = &e1000_update_phy_info;
+ adapter->phy_info_timer.data = (unsigned long) adapter;
+
+ INIT_WORK(&adapter->reset_task, e1000_reset_task);
+ INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
+
+ e1000e_check_options(adapter);
+
+ /* Initialize link parameters. User can change them with ethtool */
+ adapter->hw.mac.autoneg = 1;
+ adapter->fc_autoneg = 1;
+ adapter->hw.mac.original_fc = e1000_fc_default;
+ adapter->hw.mac.fc = e1000_fc_default;
+ adapter->hw.phy.autoneg_advertised = 0x2f;
+
+ /* ring size defaults */
+ adapter->rx_ring->count = 256;
+ adapter->tx_ring->count = 256;
+
+ /*
+ * Initial Wake on LAN setting - If APM wake is enabled in
+ * the EEPROM, enable the ACPI Magic Packet filter
+ */
+ if (adapter->flags & FLAG_APME_IN_WUC) {
+ /* APME bit in EEPROM is mapped to WUC.APME */
+ eeprom_data = er32(WUC);
+ eeprom_apme_mask = E1000_WUC_APME;
+ } else if (adapter->flags & FLAG_APME_IN_CTRL3) {
+ if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
+ (adapter->hw.bus.func == 1))
+ e1000_read_nvm(&adapter->hw,
+ NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+ else
+ e1000_read_nvm(&adapter->hw,
+ NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+ }
+
+ /* fetch WoL from EEPROM */
+ if (eeprom_data & eeprom_apme_mask)
+ adapter->eeprom_wol |= E1000_WUFC_MAG;
+
+ /*
+ * now that we have the eeprom settings, apply the special cases
+ * where the eeprom may be wrong or the board simply won't support
+ * wake on lan on a particular port
+ */
+ if (!(adapter->flags & FLAG_HAS_WOL))
+ adapter->eeprom_wol = 0;
+
+ /* initialize the wol settings based on the eeprom settings */
+ adapter->wol = adapter->eeprom_wol;
+
+ /* reset the hardware with the new settings */
+ e1000e_reset(adapter);
+
+ /* If the controller has AMT, do not set DRV_LOAD until the interface
+ * is up. For all other cases, let the f/w know that the h/w is now
+ * under the control of the driver. */
+ if (!(adapter->flags & FLAG_HAS_AMT) ||
+ !e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+ /* tell the stack to leave us alone until e1000_open() is called */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ strcpy(netdev->name, "eth%d");
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
+ e1000_print_device_info(adapter);
+
+ return 0;
+
+err_register:
+err_hw_init:
+ e1000_release_hw_control(adapter);
+err_eeprom:
+ if (!e1000_check_reset_block(&adapter->hw))
+ e1000_phy_hw_reset(&adapter->hw);
+
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+
+err_flashmap:
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+err_sw_init:
+ iounmap(adapter->hw.hw_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * e1000_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * e1000_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit e1000_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /* flush_scheduled work may reschedule our watchdog task, so
+ * explicitly disable watchdog tasks from being rescheduled */
+ set_bit(__E1000_DOWN, &adapter->state);
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_info_timer);
+
+ flush_scheduled_work();
+
+ e1000_release_manageability(adapter);
+
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant. */
+ e1000_release_hw_control(adapter);
+
+ unregister_netdev(netdev);
+
+ if (!e1000_check_reset_block(&adapter->hw))
+ e1000_phy_hw_reset(&adapter->hw);
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+
+ iounmap(adapter->hw.hw_addr);
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+ pci_release_regions(pdev);
+
+ free_netdev(netdev);
+
+ pci_disable_device(pdev);
+}
+
+/* PCI Error Recovery (ERS) */
+static struct pci_error_handlers e1000_err_handler = {
+ .error_detected = e1000_io_error_detected,
+ .slot_reset = e1000_io_slot_reset,
+ .resume = e1000_io_resume,
+};
+
+static struct pci_device_id e1000_pci_tbl[] = {
+ /*
+ * Support for 82571/2/3, es2lan and ich8 will be phased in
+ * stepwise.
+
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan },
+ */
+
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan },
+ { 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 },
+
+ { } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+
+/* PCI Device API Driver */
+static struct pci_driver e1000_driver = {
+ .name = e1000e_driver_name,
+ .id_table = e1000_pci_tbl,
+ .probe = e1000_probe,
+ .remove = __devexit_p(e1000_remove),
+#ifdef CONFIG_PM
+ /* Power Managment Hooks */
+ .suspend = e1000_suspend,
+ .resume = e1000_resume,
+#endif
+ .shutdown = e1000_shutdown,
+ .err_handler = &e1000_err_handler
+};
+
+/**
+ * e1000_init_module - Driver Registration Routine
+ *
+ * e1000_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init e1000_init_module(void)
+{
+ int ret;
+ printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n",
+ e1000e_driver_name, e1000e_driver_version);
+ printk(KERN_INFO "%s: Copyright (c) 1999-2007 Intel Corporation.\n",
+ e1000e_driver_name);
+ ret = pci_register_driver(&e1000_driver);
+
+ return ret;
+}
+module_init(e1000_init_module);
+
+/**
+ * e1000_exit_module - Driver Exit Cleanup Routine
+ *
+ * e1000_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit e1000_exit_module(void)
+{
+ pci_unregister_driver(&e1000_driver);
+}
+module_exit(e1000_exit_module);
+
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+/* e1000_main.c */
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
new file mode 100644
index 000000000000..e4e655efb23c
--- /dev/null
+++ b/drivers/net/e1000e/param.c
@@ -0,0 +1,382 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+
+#include "e1000.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define E1000_MAX_NIC 32
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+#define COPYBREAK_DEFAULT 256
+unsigned int copybreak = COPYBREAK_DEFAULT;
+module_param(copybreak, uint, 0644);
+MODULE_PARM_DESC(copybreak,
+ "Maximum size of packet that is copied to a new buffer on receive");
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+#define E1000_PARAM(X, desc) \
+ static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
+ static int num_##X; \
+ module_param_array_named(X, X, int, &num_##X, 0); \
+ MODULE_PARM_DESC(X, desc);
+
+
+/* Transmit Interrupt Delay in units of 1.024 microseconds
+ * Tx interrupt delay needs to typically be set to something non zero
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
+#define DEFAULT_TIDV 8
+#define MAX_TXDELAY 0xFFFF
+#define MIN_TXDELAY 0
+
+/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
+#define DEFAULT_TADV 32
+#define MAX_TXABSDELAY 0xFFFF
+#define MIN_TXABSDELAY 0
+
+/* Receive Interrupt Delay in units of 1.024 microseconds
+ * hardware will likely hang if you set this to anything but zero.
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
+#define DEFAULT_RDTR 0
+#define MAX_RXDELAY 0xFFFF
+#define MIN_RXDELAY 0
+
+/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+#define DEFAULT_RADV 8
+#define MAX_RXABSDELAY 0xFFFF
+#define MIN_RXABSDELAY 0
+
+/* Interrupt Throttle Rate (interrupts/sec)
+ *
+ * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
+ */
+E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+#define DEFAULT_ITR 3
+#define MAX_ITR 100000
+#define MIN_ITR 100
+
+/* Enable Smart Power Down of the PHY
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 0 (disabled)
+ */
+E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
+
+/* Enable Kumeran Lock Loss workaround
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+
+struct e1000_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct e1000_opt_list { int i; char *str; } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit e1000_validate_option(int *value,
+ struct e1000_option *opt,
+ struct e1000_adapter *adapter)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ ndev_info(adapter->netdev, "%s Enabled\n", opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ ndev_info(adapter->netdev, "%s Disabled\n", opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ ndev_info(adapter->netdev,
+ "%s set to %i\n", opt->name, *value);
+ return 0;
+ }
+ break;
+ case list_option: {
+ int i;
+ struct e1000_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ ndev_info(adapter->netdev, "%s\n",
+ ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ BUG();
+ }
+
+ ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n",
+ opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/**
+ * e1000e_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ **/
+void __devinit e1000e_check_options(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ int bd = adapter->bd_number;
+
+ if (bd >= E1000_MAX_NIC) {
+ ndev_notice(netdev,
+ "Warning: no configuration for board #%i\n", bd);
+ ndev_notice(netdev, "Using defaults for all values\n");
+ }
+
+ { /* Transmit Interrupt Delay */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Transmit Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_TIDV),
+ .def = DEFAULT_TIDV,
+ .arg = { .r = { .min = MIN_TXDELAY,
+ .max = MAX_TXDELAY } }
+ };
+
+ if (num_TxIntDelay > bd) {
+ adapter->tx_int_delay = TxIntDelay[bd];
+ e1000_validate_option(&adapter->tx_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->tx_int_delay = opt.def;
+ }
+ }
+ { /* Transmit Absolute Interrupt Delay */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Transmit Absolute Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_TADV),
+ .def = DEFAULT_TADV,
+ .arg = { .r = { .min = MIN_TXABSDELAY,
+ .max = MAX_TXABSDELAY } }
+ };
+
+ if (num_TxAbsIntDelay > bd) {
+ adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+ e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->tx_abs_int_delay = opt.def;
+ }
+ }
+ { /* Receive Interrupt Delay */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Receive Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_RDTR),
+ .def = DEFAULT_RDTR,
+ .arg = { .r = { .min = MIN_RXDELAY,
+ .max = MAX_RXDELAY } }
+ };
+
+ /* modify min and default if 82573 for slow ping w/a,
+ * a value greater than 8 needs to be set for RDTR */
+ if (adapter->flags & FLAG_HAS_ASPM) {
+ opt.def = 32;
+ opt.arg.r.min = 8;
+ }
+
+ if (num_RxIntDelay > bd) {
+ adapter->rx_int_delay = RxIntDelay[bd];
+ e1000_validate_option(&adapter->rx_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->rx_int_delay = opt.def;
+ }
+ }
+ { /* Receive Absolute Interrupt Delay */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Receive Absolute Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_RADV),
+ .def = DEFAULT_RADV,
+ .arg = { .r = { .min = MIN_RXABSDELAY,
+ .max = MAX_RXABSDELAY } }
+ };
+
+ if (num_RxAbsIntDelay > bd) {
+ adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+ e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->rx_abs_int_delay = opt.def;
+ }
+ }
+ { /* Interrupt Throttling Rate */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Interrupt Throttling Rate (ints/sec)",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_ITR),
+ .def = DEFAULT_ITR,
+ .arg = { .r = { .min = MIN_ITR,
+ .max = MAX_ITR } }
+ };
+
+ if (num_InterruptThrottleRate > bd) {
+ adapter->itr = InterruptThrottleRate[bd];
+ switch (adapter->itr) {
+ case 0:
+ ndev_info(netdev, "%s turned off\n",
+ opt.name);
+ break;
+ case 1:
+ ndev_info(netdev,
+ "%s set to dynamic mode\n",
+ opt.name);
+ adapter->itr_setting = adapter->itr;
+ adapter->itr = 20000;
+ break;
+ case 3:
+ ndev_info(netdev,
+ "%s set to dynamic conservative mode\n",
+ opt.name);
+ adapter->itr_setting = adapter->itr;
+ adapter->itr = 20000;
+ break;
+ default:
+ e1000_validate_option(&adapter->itr, &opt,
+ adapter);
+ /*
+ * save the setting, because the dynamic bits
+ * change itr. clear the lower two bits
+ * because they are used as control
+ */
+ adapter->itr_setting = adapter->itr & ~3;
+ break;
+ }
+ } else {
+ adapter->itr_setting = opt.def;
+ adapter->itr = 20000;
+ }
+ }
+ { /* Smart Power Down */
+ struct e1000_option opt = {
+ .type = enable_option,
+ .name = "PHY Smart Power Down",
+ .err = "defaulting to Disabled",
+ .def = OPTION_DISABLED
+ };
+
+ if (num_SmartPowerDownEnable > bd) {
+ int spd = SmartPowerDownEnable[bd];
+ e1000_validate_option(&spd, &opt, adapter);
+ if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN)
+ && spd)
+ adapter->flags |= FLAG_SMART_POWER_DOWN;
+ }
+ }
+ { /* Kumeran Lock Loss Workaround */
+ struct e1000_option opt = {
+ .type = enable_option,
+ .name = "Kumeran Lock Loss Workaround",
+ .err = "defaulting to Enabled",
+ .def = OPTION_ENABLED
+ };
+
+ if (num_KumeranLockLoss > bd) {
+ int kmrn_lock_loss = KumeranLockLoss[bd];
+ e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+ kmrn_lock_loss);
+ } else {
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+ opt.def);
+ }
+ }
+}
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
new file mode 100644
index 000000000000..793231810ae0
--- /dev/null
+++ b/drivers/net/e1000e/phy.c
@@ -0,0 +1,1773 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/delay.h>
+
+#include "e1000.h"
+
+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);
+
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+ { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+
+static const u16 e1000_igp_2_cable_length_table[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3,
+ 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22,
+ 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40,
+ 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61,
+ 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82,
+ 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95,
+ 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121,
+ 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_igp_2_cable_length_table) / \
+ sizeof(e1000_igp_2_cable_length_table[0]))
+
+/**
+ * e1000e_check_reset_block_generic - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Read the PHY management control register and check whether a PHY reset
+ * is blocked. If a reset is not blocked return 0, otherwise
+ * return E1000_BLK_PHY_RESET (12).
+ **/
+s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
+{
+ u32 manc;
+
+ manc = er32(MANC);
+
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : 0;
+}
+
+/**
+ * e1000e_get_phy_id - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+s32 e1000e_get_phy_id(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_id;
+
+ ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ return ret_val;
+
+ phy->id = (u32)(phy_id << 16);
+ udelay(20);
+ ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ return ret_val;
+
+ phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+ return 0;
+}
+
+/**
+ * e1000e_phy_reset_dsp - Reset PHY DSP
+ * @hw: pointer to the HW structure
+ *
+ * Reset the digital signal processor.
+ **/
+s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+ if (ret_val)
+ return ret_val;
+
+ return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
+}
+
+/**
+ * e1000_read_phy_reg_mdic - Read MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control regsiter in the PHY at offset and stores the
+ * information read to data.
+ **/
+static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i, mdic = 0;
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /* Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ ew32(MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < 64; i++) {
+ udelay(50);
+ mdic = er32(MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ hw_dbg(hw, "MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ hw_dbg(hw, "MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *data = (u16) mdic;
+
+ return 0;
+}
+
+/**
+ * e1000_write_phy_reg_mdic - Write MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ **/
+static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i, mdic = 0;
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /* Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = (((u32)data) |
+ (offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ ew32(MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+ udelay(5);
+ mdic = er32(MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ hw_dbg(hw, "MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_read_phy_reg_m88 - Read m88 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_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_phy_reg_m88 - Write m88 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_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_read_phy_reg_igp - Read igp 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_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
+ if (ret_val) {
+ hw->phy.ops.release_phy(hw);
+ return ret_val;
+ }
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_phy_reg_igp - Write igp 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_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
+ if (ret_val) {
+ hw->phy.ops.release_phy(hw);
+ return ret_val;
+ }
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_read_kmrn_reg - Read kumeran 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
+ * using the kumeran interface. The information retrieved is stored in data.
+ * Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ u32 kmrnctrlsta;
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+ udelay(2);
+
+ kmrnctrlsta = er32(KMRNCTRLSTA);
+ *data = (u16)kmrnctrlsta;
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_kmrn_reg - Write kumeran 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 write the data to PHY register
+ * at the offset using the kumeran interface. Release any acquired semaphores
+ * before exiting.
+ **/
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ u32 kmrnctrlsta;
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | data;
+ ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+ udelay(2);
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock
+ * and downshift values are set also.
+ **/
+s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (phy->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if (phy->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+ ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (phy->revision < 4) {
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((phy->revision == 2) &&
+ (phy->id == M88E1111_I_PHY_ID)) {
+ /* 82573L PHY - set the downshift counter to 5x. */
+ phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ }
+ ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Commit the changes. */
+ ret_val = e1000e_commit_phy(hw);
+ if (ret_val)
+ hw_dbg(hw, "Error committing the PHY changes\n");
+
+ return ret_val;
+}
+
+/**
+ * e1000e_copper_link_setup_igp - Setup igp PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ * igp PHY's.
+ **/
+s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error resetting the PHY.\n");
+ return ret_val;
+ }
+
+ /* Wait 15ms for MAC to configure PHY from NVM settings. */
+ msleep(15);
+
+ /* disable lplu d0 during driver init */
+ ret_val = e1000_set_d0_lplu_state(hw, 0);
+ if (ret_val) {
+ hw_dbg(hw, "Error Disabling LPLU D0\n");
+ return ret_val;
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (phy->mdix) {
+ case 1:
+ data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ /* set auto-master slave resolution settings */
+ if (hw->mac.autoneg) {
+ /* when autonegotiation advertisement is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default. */
+ if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+
+ /* Set auto Master/Slave resolution process */
+ ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~CR_1000T_MS_ENABLE;
+ ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+ ((data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) :
+ e1000_ms_auto;
+
+ switch (phy->ms_type) {
+ case e1000_ms_force_master:
+ data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ data |= CR_1000T_MS_ENABLE;
+ data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MII auto-neg advertisement register and/or the 1000T control
+ * register and if the PHY is already setup for auto-negotiation, then
+ * return successful. Otherwise, setup advertisement and flow control to
+ * the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 mii_autoneg_adv_reg;
+ u16 mii_1000t_ctrl_reg = 0;
+
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+ NWAY_AR_100TX_HD_CAPS |
+ NWAY_AR_10T_FD_CAPS |
+ NWAY_AR_10T_HD_CAPS);
+ mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+ hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+ hw_dbg(hw, "Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+ hw_dbg(hw, "Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+ hw_dbg(hw, "Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+ hw_dbg(hw, "Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+ hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n");
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+ hw_dbg(hw, "Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+ * negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->mac.fc) {
+ case e1000_fc_none:
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+ /* Since there really isn't a way to advertise that we are
+ * capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later
+ * (in e1000e_config_fc_after_link_up) we will disable the
+ * hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ return ret_val;
+ }
+
+ ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Performs initial bounds checking on autoneg advertisement parameter, then
+ * configure to advertise the full capability. Setup the PHY to autoneg
+ * and restart the negotiation process between the link partner. If
+ * wait_for_link, then wait for autoneg to complete before exiting.
+ **/
+static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_ctrl;
+
+ /* Perform some bounds checking on the autoneg advertisement
+ * parameter.
+ */
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (phy->autoneg_advertised == 0)
+ phy->autoneg_advertised = phy->autoneg_mask;
+
+ hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+ hw_dbg(hw, "Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if (phy->wait_for_link) {
+ ret_val = e1000_wait_autoneg(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error while waiting for "
+ "autoneg to complete\n");
+ return ret_val;
+ }
+ }
+
+ hw->mac.get_link_status = 1;
+
+ return ret_val;
+}
+
+/**
+ * e1000e_setup_copper_link - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex. Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called. If link is
+ * not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_setup_copper_link(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ bool link;
+
+ if (hw->mac.autoneg) {
+ /* Setup autoneg and flow control advertisement and perform
+ * autonegotiation. */
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* PHY will be set to 10H, 10F, 100H or 100F
+ * depending on user settings. */
+ hw_dbg(hw, "Forcing Speed and Duplex\n");
+ ret_val = e1000_phy_force_speed_duplex(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error Forcing Speed and Duplex\n");
+ return ret_val;
+ }
+ }
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ ret_val = e1000e_phy_has_link_generic(hw,
+ COPPER_LINK_UP_LIMIT,
+ 10,
+ &link);
+ if (ret_val)
+ return ret_val;
+
+ if (link) {
+ hw_dbg(hw, "Valid link established!!!\n");
+ e1000e_config_collision_dist(hw);
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ } else {
+ hw_dbg(hw, "Unable to establish link!!!\n");
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Waits for link and returns
+ * successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "IGP PSCR: %X\n", phy_data);
+
+ udelay(1);
+
+ if (phy->wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link on IGP phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link)
+ hw_dbg(hw, "Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Resets the PHY to commit the
+ * changes. If time expires while waiting for link up, we reset the DSP.
+ * After reset, TX_CLK and CRS on TX must be set. Return successful upon
+ * successful completion, else return corresponding error code.
+ **/
+s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data);
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ /* Reset the phy to commit changes. */
+ phy_data |= MII_CR_RESET;
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+
+ if (phy->wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ /* We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_phy_reset_dsp(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Resetting the phy means we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock from
+ * the reset value of 2.5MHz.
+ */
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ * @hw: pointer to the HW structure
+ * @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ * Forces speed and duplex on the PHY by doing the following: disable flow
+ * control, force speed/duplex on the MAC, disable auto speed detection,
+ * disable auto-negotiation, configure duplex, configure speed, configure
+ * the collision distance, write configuration to CTRL register. The
+ * caller must write to the PHY_CONTROL register for these settings to
+ * take affect.
+ **/
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 ctrl;
+
+ /* Turn off flow control when forcing speed/duplex */
+ mac->fc = e1000_fc_none;
+
+ /* Force speed/duplex on the mac */
+ ctrl = er32(CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~E1000_CTRL_SPD_SEL;
+
+ /* Disable Auto Speed Detection */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Disable autoneg on the phy */
+ *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Forcing Full or Half Duplex? */
+ if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+ ctrl &= ~E1000_CTRL_FD;
+ *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+ hw_dbg(hw, "Half Duplex\n");
+ } else {
+ ctrl |= E1000_CTRL_FD;
+ *phy_ctrl |= MII_CR_FULL_DUPLEX;
+ hw_dbg(hw, "Full Duplex\n");
+ }
+
+ /* Forcing 10mb or 100mb? */
+ if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+ ctrl |= E1000_CTRL_SPD_100;
+ *phy_ctrl |= MII_CR_SPEED_100;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ hw_dbg(hw, "Forcing 100mb\n");
+ } else {
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ *phy_ctrl |= MII_CR_SPEED_10;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ hw_dbg(hw, "Forcing 10mb\n");
+ }
+
+ e1000e_config_collision_dist(hw);
+
+ ew32(CTRL, ctrl);
+}
+
+/**
+ * e1000e_set_d3_lplu_state - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: boolean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is true, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained.
+ **/
+s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (!active) {
+ data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = e1e_wphy(hw,
+ IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ return ret_val;
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+ if (ret_val)
+ return ret_val;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_check_downshift - Checks whether a downshift in speed occured
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * A downshift is detected by querying the PHY link health.
+ **/
+s32 e1000e_check_downshift(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, offset, mask;
+
+ switch (phy->type) {
+ case e1000_phy_m88:
+ case e1000_phy_gg82563:
+ offset = M88E1000_PHY_SPEC_STATUS;
+ mask = M88E1000_PSSR_DOWNSHIFT;
+ break;
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ offset = IGP01E1000_PHY_LINK_HEALTH;
+ mask = IGP01E1000_PLHR_SS_DOWNGRADE;
+ break;
+ default:
+ /* speed downshift not supported */
+ phy->speed_downgraded = 0;
+ return 0;
+ }
+
+ ret_val = e1e_rphy(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->speed_downgraded = (phy_data & mask);
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_m88 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ **/
+static s32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_igp - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY port status register, and the
+ * current speed (since there is no polarity at 100Mbps).
+ **/
+static s32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data, offset, mask;
+
+ /* Polarity is determined based on the speed of
+ * our connection. */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ offset = IGP01E1000_PHY_PCS_INIT_REG;
+ mask = IGP01E1000_PHY_POLARITY_MASK;
+ } else {
+ /* This really only applies to 10Mbps since
+ * there is no polarity for 100Mbps (always 0).
+ */
+ offset = IGP01E1000_PHY_PORT_STATUS;
+ mask = IGP01E1000_PSSR_POLARITY_REVERSED;
+ }
+
+ ret_val = e1e_rphy(hw, offset, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_wait_autoneg - Wait for auto-neg compeletion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for auto-negotiation to complete or for the auto-negotiation time
+ * limit to expire, which ever happens first.
+ **/
+static s32 e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+ u16 i, phy_status;
+
+ /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+ for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_AUTONEG_COMPLETE)
+ break;
+ msleep(100);
+ }
+
+ /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+ * has completed.
+ */
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_has_link_generic - Polls PHY for link
+ * @hw: pointer to the HW structure
+ * @iterations: number of times to poll for link
+ * @usec_interval: delay between polling attempts
+ * @success: pointer to whether polling was successful or not
+ *
+ * Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success)
+{
+ s32 ret_val = 0;
+ u16 i, phy_status;
+
+ for (i = 0; i < iterations; i++) {
+ /* Some PHYs require the PHY_STATUS register to be read
+ * twice due to the link bit being sticky. No harm doing
+ * it across the board.
+ */
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_LINK_STATUS)
+ break;
+ if (usec_interval >= 1000)
+ mdelay(usec_interval/1000);
+ else
+ udelay(usec_interval);
+ }
+
+ *success = (i < iterations);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_cable_length_m88 - Determine cable length for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY specific status register to retrieve the cable length
+ * information. The cable length is determined by averaging the minimum and
+ * maximum values to get the "average" cable length. The m88 PHY has four
+ * possible cable length values, which are:
+ * Register Value Cable Length
+ * 0 < 50 meters
+ * 1 50 - 80 meters
+ * 2 80 - 110 meters
+ * 3 110 - 140 meters
+ * 4 > 140 meters
+ **/
+s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, index;
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ phy->min_cable_length = e1000_m88_cable_length_table[index];
+ phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ * @hw: pointer to the HW structure
+ *
+ * The automatic gain control (agc) normalizes the amplitude of the
+ * received signal, adjusting for the attenuation produced by the
+ * cable. By reading the AGC registers, which reperesent the
+ * cobination of course and fine gain value, the value can be put
+ * into a lookup table to obtain the approximate cable length
+ * for each channel.
+ **/
+s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, i, agc_value = 0;
+ u16 cur_agc_index, max_agc_index = 0;
+ u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+ u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+ {IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D};
+
+ /* Read the AGC registers for all channels */
+ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Getting bits 15:9, which represent the combination of
+ * course and fine gain values. The result is a number
+ * that can be put into the lookup table to obtain the
+ * approximate cable length. */
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
+
+ /* Array index bound check. */
+ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+ (cur_agc_index == 0))
+ return -E1000_ERR_PHY;
+
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc_index] >
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ min_agc_index = cur_agc_index;
+ if (e1000_igp_2_cable_length_table[max_agc_index] <
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ max_agc_index = cur_agc_index;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+ }
+
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+ e1000_igp_2_cable_length_table[max_agc_index]);
+ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+ /* Calculate cable length with the error range of +/- 10 meters. */
+ phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_phy_info_m88 - Retrieve PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Valid for only copper links. Read the PHY status register (sticky read)
+ * to verify that link is up. Read the PHY special control register to
+ * determine the polarity and 10base-T extended distance. Read the PHY
+ * special status register to determine MDI/MDIx and current speed. If
+ * speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ if (hw->media_type != e1000_media_type_copper) {
+ hw_dbg(hw, "Phy info is only valid for copper media\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ hw_dbg(hw, "Phy info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy->polarity_correction = (phy_data &
+ M88E1000_PSCR_POLARITY_REVERSAL);
+
+ ret_val = e1000_check_polarity_m88(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX);
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ ret_val = e1000_get_cable_length(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ /* Set values to "undefined" */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_phy_info_igp - Retrieve igp PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ bool link;
+
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ hw_dbg(hw, "Phy info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ phy->polarity_correction = 1;
+
+ ret_val = e1000_check_polarity_igp(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ phy->is_mdix = (data & IGP01E1000_PSSR_MDIX);
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ ret_val = e1000_get_cable_length(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_sw_reset - PHY software reset
+ * @hw: pointer to the HW structure
+ *
+ * Does a software reset of the PHY by reading the PHY control register and
+ * setting/write the control register reset bit to the PHY.
+ **/
+s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_ctrl;
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl |= MII_CR_RESET;
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_hw_reset_generic - PHY hardware reset
+ * @hw: pointer to the HW structure
+ *
+ * Verify the reset block is not blocking us from resetting. Acquire
+ * semaphore (if necessary) and read/set/write the device control reset
+ * bit in the PHY. Wait the appropriate delay time for the device to
+ * reset and relase the semaphore (if necessary).
+ **/
+s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u32 ctrl;
+
+ ret_val = e1000_check_reset_block(hw);
+ if (ret_val)
+ return 0;
+
+ ret_val = phy->ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ ctrl = er32(CTRL);
+ ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
+ e1e_flush();
+
+ udelay(phy->reset_delay_us);
+
+ ew32(CTRL, ctrl);
+ e1e_flush();
+
+ udelay(150);
+
+ phy->ops.release_phy(hw);
+
+ return e1000_get_phy_cfg_done(hw);
+}
+
+/**
+ * e1000e_get_cfg_done - Generic configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Generic function to wait 10 milli-seconds for configuration to complete
+ * and return success.
+ **/
+s32 e1000e_get_cfg_done(struct e1000_hw *hw)
+{
+ mdelay(10);
+ return 0;
+}
+
+/* Internal function pointers */
+
+/**
+ * e1000_get_phy_cfg_done - Generic PHY configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Return success if silicon family did not implement a family specific
+ * get_cfg_done function.
+ **/
+static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.get_cfg_done)
+ return hw->phy.ops.get_cfg_done(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
+ * @hw: pointer to the HW structure
+ *
+ * When the silicon family has not implemented a forced speed/duplex
+ * function for the PHY, simply return 0.
+ **/
+static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.force_speed_duplex)
+ return hw->phy.ops.force_speed_duplex(hw);
+
+ return 0;
+}
+
+/**
+ * e1000e_get_phy_type_from_id - Get PHY type from id
+ * @phy_id: phy_id read from the phy
+ *
+ * Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
+{
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ switch (phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1000_E_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+ phy_type = e1000_phy_igp_2;
+ break;
+ case GG82563_E_PHY_ID:
+ phy_type = e1000_phy_gg82563;
+ break;
+ case IGP03E1000_E_PHY_ID:
+ phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy_type = e1000_phy_ife;
+ break;
+ default:
+ phy_type = e1000_phy_unknown;
+ break;
+ }
+ return phy_type;
+}
+
+/**
+ * e1000e_commit_phy - Soft PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Performs a soft PHY reset on those that apply. This is a function pointer
+ * entry point called by drivers.
+ **/
+s32 e1000e_commit_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.commit_phy)
+ return hw->phy.ops.commit_phy(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_set_d0_lplu_state - Sets low power link up state for D0
+ * @hw: pointer to the HW structure
+ * @active: boolean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D0
+ * and SmartSpeed is disabled when active is true, else clear lplu for D0
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained. This is a function pointer entry point called by drivers.
+ **/
+static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
+{
+ if (hw->phy.ops.set_d0_lplu_state)
+ return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+ return 0;
+}
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index b2b0a96218ca..6390f51ea6fb 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -124,8 +124,6 @@ static int __init do_e2100_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return e21_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 47680237f783..83bda6ccde98 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -192,7 +192,6 @@ static unsigned int net_debug = NET_DEBUG;
/* Information that need to be kept for each board. */
struct eepro_local {
- struct net_device_stats stats;
unsigned rx_start;
unsigned tx_start; /* start of the transmit chain */
int tx_last; /* pointer to last packet in the transmit chain */
@@ -315,7 +314,6 @@ static irqreturn_t eepro_interrupt(int irq, void *dev_id);
static void eepro_rx(struct net_device *dev);
static void eepro_transmit_interrupt(struct net_device *dev);
static int eepro_close(struct net_device *dev);
-static struct net_device_stats *eepro_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void eepro_tx_timeout (struct net_device *dev);
@@ -514,7 +512,7 @@ buffer (transmit-buffer = 32K - receive-buffer).
/* a complete sel reset */
#define eepro_complete_selreset(ioaddr) { \
- lp->stats.tx_errors++;\
+ dev->stats.tx_errors++;\
eepro_sel_reset(ioaddr);\
lp->tx_end = \
lp->xmt_lower_limit;\
@@ -537,8 +535,6 @@ static int __init do_eepro_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
#ifdef PnPWakeup
/* XXXX for multiple cards should this only be run once? */
@@ -594,8 +590,6 @@ struct net_device * __init eepro_probe(int unit)
if (!dev)
return ERR_PTR(-ENODEV);
- SET_MODULE_OWNER(dev);
-
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
@@ -696,6 +690,7 @@ static void __init eepro_print_info (struct net_device *dev)
struct eepro_local * lp = netdev_priv(dev);
int i;
const char * ifmap[] = {"AUI", "10Base2", "10BaseT"};
+ DECLARE_MAC_BUF(mac);
i = inb(dev->base_addr + ID_REG);
printk(KERN_DEBUG " id: %#x ",i);
@@ -717,10 +712,10 @@ static void __init eepro_print_info (struct net_device *dev)
case LAN595:
printk("%s: Intel 82595-based lan card at %#x,",
dev->name, (unsigned)dev->base_addr);
+ break;
}
- for (i=0; i < 6; i++)
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+ printk(" %s", print_mac(mac, dev->dev_addr));
if (net_debug > 3)
printk(KERN_DEBUG ", %dK RCV buffer",
@@ -860,7 +855,6 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
dev->open = eepro_open;
dev->stop = eepro_close;
dev->hard_start_xmit = eepro_send_packet;
- dev->get_stats = eepro_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->tx_timeout = eepro_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1158,9 +1152,9 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
if (hardware_send_packet(dev, buf, length))
/* we won't wake queue here because we're out of space */
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
else {
- lp->stats.tx_bytes+=skb->len;
+ dev->stats.tx_bytes+=skb->len;
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
@@ -1170,7 +1164,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
- /* lp->stats.tx_aborted_errors++; */
+ /* dev->stats.tx_aborted_errors++; */
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
@@ -1277,16 +1271,6 @@ static int eepro_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *
-eepro_get_stats(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
*/
static void
@@ -1579,12 +1563,12 @@ eepro_rx(struct net_device *dev)
/* Malloc up new buffer. */
struct sk_buff *skb;
- lp->stats.rx_bytes+=rcv_size;
+ dev->stats.rx_bytes+=rcv_size;
rcv_size &= 0x3fff;
skb = dev_alloc_skb(rcv_size+5);
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
lp->rx_start = rcv_next_frame;
outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
@@ -1606,28 +1590,28 @@ eepro_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++;
}
else { /* Not sure will ever reach here,
I set the 595 to discard bad received frames */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rcv_status & 0x0100)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
else if (rcv_status & 0x0400)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
else if (rcv_status & 0x0800)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
}
if (rcv_status & 0x1000)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
lp->rx_start = rcv_next_frame;
@@ -1670,11 +1654,11 @@ eepro_transmit_interrupt(struct net_device *dev)
netif_wake_queue (dev);
if (xmt_status & TX_OK)
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (xmt_status & 0x0400) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
printk(KERN_DEBUG "%s: carrier error\n",
dev->name);
printk(KERN_DEBUG "%s: XMT status = %#x\n",
@@ -1688,11 +1672,11 @@ eepro_transmit_interrupt(struct net_device *dev)
}
}
if (xmt_status & 0x000f) {
- lp->stats.collisions += (xmt_status & 0x000f);
+ dev->stats.collisions += (xmt_status & 0x000f);
}
if ((xmt_status & 0x0040) == 0x0) {
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
}
}
}
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 3c54014acece..1548a80f917d 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -622,6 +622,7 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
int size;
void *tx_ring_space;
dma_addr_t tx_ring_dma;
+ DECLARE_MAC_BUF(mac);
size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats);
tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma);
@@ -635,7 +636,6 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
return -1;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (dev->mem_start > 0)
@@ -706,12 +706,8 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
else
product = pci_name(pdev);
- printk(KERN_INFO "%s: %s, ", dev->name, product);
-
- for (i = 0; i < 5; i++)
- printk("%2.2X:", dev->dev_addr[i]);
- printk("%2.2X, ", dev->dev_addr[i]);
- printk("IRQ %d.\n", pdev->irq);
+ printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product,
+ print_mac(mac, dev->dev_addr), pdev->irq);
sp = netdev_priv(dev);
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 7934ea37f944..9c85e50014b4 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -135,7 +135,6 @@
struct net_local
{
- struct net_device_stats stats;
unsigned long last_tx; /* jiffies when last transmit started */
unsigned long init_time; /* jiffies when eexp_hw_init586 called */
unsigned short rx_first; /* first rx buf, same as RX_BUF_START */
@@ -247,7 +246,6 @@ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
static int eexp_open(struct net_device *dev);
static int eexp_close(struct net_device *dev);
static void eexp_timeout(struct net_device *dev);
-static struct net_device_stats *eexp_stats(struct net_device *dev);
static int eexp_xmit(struct sk_buff *buf, struct net_device *dev);
static irqreturn_t eexp_irq(int irq, void *dev_addr);
@@ -341,8 +339,6 @@ static int __init do_express_probe(struct net_device *dev)
int dev_irq = dev->irq;
int err;
- SET_MODULE_OWNER(dev);
-
dev->if_port = 0xff; /* not set */
#ifdef CONFIG_MCA_LEGACY
@@ -535,17 +531,6 @@ static int eexp_close(struct net_device *dev)
}
/*
- * Return interface stats
- */
-
-static struct net_device_stats *eexp_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
-/*
* This gets called when a higher level thinks we are broken. Check that
* nothing has become jammed in the CU.
*/
@@ -648,7 +633,7 @@ static void eexp_timeout(struct net_device *dev)
printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
(SCB_complete(status)?"lost interrupt":
"board on fire"));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
lp->last_tx = jiffies;
if (!SCB_complete(status)) {
scb_command(dev, SCB_CUabort);
@@ -696,7 +681,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
{
unsigned short *data = (unsigned short *)buf->data;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_bytes += length;
eexp_hw_tx_pio(dev,data,length);
}
@@ -845,7 +830,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info)
outw(rbd+8, ioaddr+READ_PTR);
printk("[%04x]\n", inw(ioaddr+DATAPORT));
#endif
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
#if 1
eexp_hw_rxinit(dev);
#else
@@ -954,17 +939,17 @@ static void eexp_hw_rx_pio(struct net_device *dev)
}
else if (!FD_OK(status))
{
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (FD_CRC(status))
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (FD_Align(status))
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (FD_Resrc(status))
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (FD_DMA(status))
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (FD_Short(status))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
else
{
@@ -974,7 +959,7 @@ static void eexp_hw_rx_pio(struct net_device *dev)
if (skb == NULL)
{
printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb, 2);
@@ -983,8 +968,8 @@ static void eexp_hw_rx_pio(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
outw(rx_block, ioaddr+WRITE_PTR);
outw(0, ioaddr+DATAPORT);
@@ -1055,7 +1040,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
outw(0xFFFF, ioaddr+SIGNAL_CA);
}
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
lp->last_tx = jiffies;
}
@@ -1182,7 +1167,6 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
dev->open = eexp_open;
dev->stop = eexp_close;
dev->hard_start_xmit = eexp_xmit;
- dev->get_stats = eexp_stats;
dev->set_multicast_list = &eexp_set_multicast;
dev->tx_timeout = eexp_timeout;
dev->watchdog_timeo = 2*HZ;
@@ -1265,35 +1249,35 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
else
{
lp->last_tx_restart = 0;
- lp->stats.collisions += Stat_NoColl(status);
+ dev->stats.collisions += Stat_NoColl(status);
if (!Stat_OK(status))
{
char *whatsup = NULL;
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (Stat_Abort(status))
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (Stat_TNoCar(status)) {
whatsup = "aborted, no carrier";
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (Stat_TNoCTS(status)) {
whatsup = "aborted, lost CTS";
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (Stat_TNoDMA(status)) {
whatsup = "FIFO underran";
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
}
if (Stat_TXColl(status)) {
whatsup = "aborted, too many collisions";
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
if (whatsup)
printk(KERN_INFO "%s: transmit %s\n",
dev->name, whatsup);
}
else
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
lp->tx_reap = tx_block = TX_BUF_START;
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 6628fa622e2c..ac21526b6de8 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -33,19 +33,20 @@
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
#include <asm/ibmebus.h>
#include <asm/abs_addr.h>
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0070"
+#define DRV_VERSION "EHEA_0078"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
#define DLPAR_MEM_ADD 2
#define DLPAR_MEM_REM 4
-#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM)
+#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD)
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -58,6 +59,7 @@
#define EHEA_SMALL_QUEUES
#define EHEA_NUM_TX_QP 1
+#define EHEA_LRO_MAX_AGGR 64
#ifdef EHEA_SMALL_QUEUES
#define EHEA_MAX_CQE_COUNT 1023
@@ -84,6 +86,8 @@
#define EHEA_RQ2_PKT_SIZE 1522
#define EHEA_L_PKT_SIZE 256 /* low latency */
+#define MAX_LRO_DESCRIPTORS 8
+
/* Send completion signaling */
/* Protection Domain Identifier */
@@ -351,6 +355,7 @@ struct ehea_q_skb_arr {
* Port resources
*/
struct ehea_port_res {
+ struct napi_struct napi;
struct port_stats p_stats;
struct ehea_mr send_mr; /* send memory region */
struct ehea_mr recv_mr; /* receive memory region */
@@ -362,7 +367,6 @@ struct ehea_port_res {
struct ehea_cq *send_cq;
struct ehea_cq *recv_cq;
struct ehea_eq *eq;
- struct net_device *d_netdev;
struct ehea_q_skb_arr rq1_skba;
struct ehea_q_skb_arr rq2_skba;
struct ehea_q_skb_arr rq3_skba;
@@ -376,6 +380,8 @@ struct ehea_port_res {
u64 tx_packets;
u64 rx_packets;
u32 poll_counter;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS];
};
@@ -385,7 +391,6 @@ struct ehea_adapter {
struct ibmebus_dev *ebus_dev;
struct ehea_port *port[EHEA_MAX_PORTS];
struct ehea_eq *neq; /* notification event queue */
- struct workqueue_struct *ehea_wq;
struct tasklet_struct neq_tasklet;
struct ehea_mr mr;
u32 pd; /* protection domain */
@@ -402,6 +407,8 @@ struct ehea_mc_list {
#define EHEA_PORT_UP 1
#define EHEA_PORT_DOWN 0
+#define EHEA_PHY_LINK_UP 1
+#define EHEA_PHY_LINK_DOWN 0
#define EHEA_MAX_PORT_RES 16
struct ehea_port {
struct ehea_adapter *adapter; /* adapter that owns this port */
@@ -427,6 +434,8 @@ struct ehea_port {
u32 msg_enable;
u32 sig_comp_iv;
u32 state;
+ u32 lro_max_aggr;
+ u8 phy_link;
u8 full_duplex;
u8 autoneg;
u8 num_def_qps;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index decec8cfe96b..679f40ee9572 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -183,6 +183,9 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"PR5 free_swqes"},
{"PR6 free_swqes"},
{"PR7 free_swqes"},
+ {"LRO aggregated"},
+ {"LRO flushed"},
+ {"LRO no_desc"},
};
static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -193,9 +196,14 @@ static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static int ehea_get_stats_count(struct net_device *dev)
+static int ehea_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(ehea_ethtool_stats_keys);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ehea_ethtool_stats_keys);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void ehea_get_ethtool_stats(struct net_device *dev,
@@ -204,7 +212,7 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
int i, k, tmp;
struct ehea_port *port = netdev_priv(dev);
- for (i = 0; i < ehea_get_stats_count(dev); i++)
+ for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)
data[i] = 0;
i = 0;
@@ -239,6 +247,18 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
for (k = 0; k < 8; k++)
data[i++] = atomic_read(&port->port_res[k].swqe_avail);
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].lro_mgr.stats.aggregated;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].lro_mgr.stats.flushed;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].lro_mgr.stats.no_desc;
+ data[i++] = tmp;
+
}
const struct ethtool_ops ehea_ethtool_ops = {
@@ -247,12 +267,9 @@ const struct ethtool_ops ehea_ethtool_ops = {
.get_msglevel = ehea_get_msglevel,
.set_msglevel = ehea_set_msglevel,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_strings = ehea_get_strings,
- .get_stats_count = ehea_get_stats_count,
+ .get_sset_count = ehea_get_sset_count,
.get_ethtool_stats = ehea_get_ethtool_stats,
.get_rx_csum = ehea_get_rx_csum,
.set_settings = ehea_set_settings,
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 1d1571cf322e..2ba57e6ace4d 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -52,18 +52,26 @@ static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
static int use_mcs = 0;
+static int use_lro = 0;
+static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
static int num_tx_qps = EHEA_NUM_TX_QP;
+static int prop_carrier_state = 0;
module_param(msg_level, int, 0);
module_param(rq1_entries, int, 0);
module_param(rq2_entries, int, 0);
module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
+module_param(prop_carrier_state, int, 0);
module_param(use_mcs, int, 0);
+module_param(use_lro, int, 0);
+module_param(lro_max_aggr, int, 0);
module_param(num_tx_qps, int, 0);
MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
MODULE_PARM_DESC(msg_level, "msg_level");
+MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
+ "port to stack. 1:yes, 0:no. Default = 0 ");
MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
"[2^x - 1], x = [6..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
@@ -76,14 +84,19 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
"[2^x - 1], x = [6..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
-MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
+MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 ");
+
+MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
+ __MODULE_STRING(EHEA_LRO_MAX_AGGR));
+MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
+ "Default = 0");
static int port_name_cnt = 0;
static LIST_HEAD(adapter_list);
u64 ehea_driver_flags = 0;
-struct workqueue_struct *ehea_driver_wq;
struct work_struct ehea_rereg_mr_task;
+struct semaphore dlpar_mem_lock;
static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
const struct of_device_id *id);
@@ -164,16 +177,24 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
struct net_device *dev = pr->port->netdev;
int max_index_mask = pr->rq1_skba.len - 1;
+ int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes;
+ int adder = 0;
int i;
- if (!nr_of_wqes)
+ pr->rq1_skba.os_skbs = 0;
+
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+ pr->rq1_skba.index = index;
+ pr->rq1_skba.os_skbs = fill_wqes;
return;
+ }
- for (i = 0; i < nr_of_wqes; i++) {
+ for (i = 0; i < fill_wqes; i++) {
if (!skb_arr_rq1[index]) {
skb_arr_rq1[index] = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb_arr_rq1[index]) {
+ pr->rq1_skba.os_skbs = fill_wqes - i;
ehea_error("%s: no mem for skb/%d wqes filled",
dev->name, i);
break;
@@ -181,9 +202,14 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
}
index--;
index &= max_index_mask;
+ adder++;
}
+
+ if (adder == 0)
+ return;
+
/* Ring doorbell */
- ehea_update_rq1a(pr->qp, i);
+ ehea_update_rq1a(pr->qp, adder);
}
static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
@@ -217,16 +243,21 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
struct sk_buff **skb_arr = q_skba->arr;
struct ehea_rwqe *rwqe;
int i, index, max_index_mask, fill_wqes;
+ int adder = 0;
int ret = 0;
fill_wqes = q_skba->os_skbs + num_wqes;
+ q_skba->os_skbs = 0;
- if (!fill_wqes)
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+ q_skba->os_skbs = fill_wqes;
return ret;
+ }
index = q_skba->index;
max_index_mask = q_skba->len - 1;
for (i = 0; i < fill_wqes; i++) {
+ u64 tmp_addr;
struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
if (!skb) {
ehea_error("%s: no mem for skb/%d wqes filled",
@@ -238,30 +269,37 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
skb_reserve(skb, NET_IP_ALIGN);
skb_arr[index] = skb;
+ tmp_addr = ehea_map_vaddr(skb->data);
+ if (tmp_addr == -1) {
+ dev_kfree_skb(skb);
+ q_skba->os_skbs = fill_wqes - i;
+ ret = 0;
+ break;
+ }
rwqe = ehea_get_next_rwqe(qp, rq_nr);
rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
| EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
- rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+ rwqe->sg_list[0].vaddr = tmp_addr;
rwqe->sg_list[0].len = packet_size;
rwqe->data_segments = 1;
index++;
index &= max_index_mask;
-
- if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
- goto out;
+ adder++;
}
q_skba->index = index;
+ if (adder == 0)
+ goto out;
/* Ring doorbell */
iosync();
if (rq_nr == 2)
- ehea_update_rq2a(pr->qp, i);
+ ehea_update_rq2a(pr->qp, adder);
else
- ehea_update_rq3a(pr->qp, i);
+ ehea_update_rq3a(pr->qp, adder);
out:
return ret;
}
@@ -382,16 +420,70 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
ehea_error("Critical receive error. Resetting port.");
- queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task);
+ schedule_work(&pr->port->reset_task);
return 1;
}
return 0;
}
-static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
- struct ehea_port_res *pr,
- int *budget)
+static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
+ void **tcph, u64 *hdr_flags, void *priv)
+{
+ struct ehea_cqe *cqe = priv;
+ unsigned int ip_len;
+ struct iphdr *iph;
+
+ /* non tcp/udp packets */
+ if (!cqe->header_length)
+ return -1;
+
+ /* non tcp packet */
+ 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);
+
+ /* check if ip header and tcp header are complete */
+ if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+ return -1;
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *iphdr = iph;
+
+ return 0;
+}
+
+static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
+ struct sk_buff *skb)
+{
+ int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+ && pr->port->vgrp;
+
+ if (use_lro) {
+ if (vlan_extracted)
+ lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb,
+ pr->port->vgrp,
+ cqe->vlan_tag,
+ cqe);
+ else
+ lro_receive_skb(&pr->lro_mgr, skb, cqe);
+ } else {
+ if (vlan_extracted)
+ vlan_hwaccel_receive_skb(skb, pr->port->vgrp,
+ cqe->vlan_tag);
+ else
+ netif_receive_skb(skb);
+ }
+}
+
+static int ehea_proc_rwqes(struct net_device *dev,
+ struct ehea_port_res *pr,
+ int budget)
{
struct ehea_port *port = pr->port;
struct ehea_qp *qp = pr->qp;
@@ -404,18 +496,16 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
int skb_arr_rq2_len = pr->rq2_skba.len;
int skb_arr_rq3_len = pr->rq3_skba.len;
int processed, processed_rq1, processed_rq2, processed_rq3;
- int wqe_index, last_wqe_index, rq, my_quota, port_reset;
+ int wqe_index, last_wqe_index, rq, port_reset;
processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
last_wqe_index = 0;
- my_quota = min(*budget, dev->quota);
cqe = ehea_poll_rq1(qp, &wqe_index);
- while ((my_quota > 0) && cqe) {
+ while ((processed < budget) && cqe) {
ehea_inc_rq1(qp);
processed_rq1++;
processed++;
- my_quota--;
if (netif_msg_rx_status(port))
ehea_dump(cqe, sizeof(*cqe), "CQE");
@@ -430,14 +520,14 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
if (netif_msg_rx_err(port))
ehea_error("LL rq1: skb=NULL");
- skb = netdev_alloc_skb(port->netdev,
+ skb = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb)
break;
}
skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
cqe->num_bytes_transfered - 4);
- ehea_fill_skb(port->netdev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe);
} else if (rq == 2) { /* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
skb_arr_rq2_len, cqe);
@@ -446,7 +536,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
ehea_error("rq2: skb=NULL");
break;
}
- ehea_fill_skb(port->netdev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe);
processed_rq2++;
} else { /* RQ3 */
skb = get_skb_by_index(skb_arr_rq3,
@@ -456,16 +546,12 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
ehea_error("rq3: skb=NULL");
break;
}
- ehea_fill_skb(port->netdev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe);
processed_rq3++;
}
- if ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
- && port->vgrp)
- vlan_hwaccel_receive_skb(skb, port->vgrp,
- cqe->vlan_tag);
- else
- netif_receive_skb(skb);
+ ehea_proc_skb(pr, cqe, skb);
+ dev->last_rx = jiffies;
} else {
pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -476,16 +562,16 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
}
cqe = ehea_poll_rq1(qp, &wqe_index);
}
+ if (use_lro)
+ lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
- *budget -= processed;
ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
ehea_refill_rq2(pr, processed_rq2);
ehea_refill_rq3(pr, processed_rq3);
- cqe = ehea_poll_rq1(qp, &wqe_index);
- return cqe;
+ return processed;
}
static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
@@ -509,8 +595,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
ehea_error("Send Completion Error: Resetting port");
if (netif_msg_tx_err(pr->port))
ehea_dump(cqe, sizeof(*cqe), "Send CQE");
- queue_work(pr->port->adapter->ehea_wq,
- &pr->port->reset_task);
+ schedule_work(&pr->port->reset_task);
break;
}
@@ -548,22 +633,27 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
}
#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+#define EHEA_POLL_MAX_CQES 65535
-static int ehea_poll(struct net_device *dev, int *budget)
+static int ehea_poll(struct napi_struct *napi, int budget)
{
- struct ehea_port_res *pr = dev->priv;
+ struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi);
+ struct net_device *dev = pr->port->netdev;
struct ehea_cqe *cqe;
struct ehea_cqe *cqe_skb = NULL;
int force_irq, wqe_index;
-
- cqe = ehea_poll_rq1(pr->qp, &wqe_index);
- cqe_skb = ehea_poll_cq(pr->send_cq);
+ int rx = 0;
force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+ cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+
+ if (!force_irq)
+ rx += ehea_proc_rwqes(dev, pr, budget - rx);
- if ((!cqe && !cqe_skb) || force_irq) {
+ while ((rx != budget) || force_irq) {
pr->poll_counter = 0;
- netif_rx_complete(dev);
+ force_irq = 0;
+ netif_rx_complete(dev, napi);
ehea_reset_cq_ep(pr->recv_cq);
ehea_reset_cq_ep(pr->send_cq);
ehea_reset_cq_n1(pr->recv_cq);
@@ -572,26 +662,35 @@ static int ehea_poll(struct net_device *dev, int *budget)
cqe_skb = ehea_poll_cq(pr->send_cq);
if (!cqe && !cqe_skb)
- return 0;
+ return rx;
- if (!netif_rx_reschedule(dev, dev->quota))
- return 0;
+ if (!netif_rx_reschedule(dev, napi))
+ return rx;
+
+ cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+ rx += ehea_proc_rwqes(dev, pr, budget - rx);
}
- cqe = ehea_proc_rwqes(dev, pr, budget);
- cqe_skb = ehea_proc_cqes(pr, 300);
+ pr->poll_counter++;
+ return rx;
+}
- if (cqe || cqe_skb)
- pr->poll_counter++;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ehea_netpoll(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ int i;
- return 1;
+ for (i = 0; i < port->num_def_qps; i++)
+ netif_rx_schedule(dev, &port->port_res[i].napi);
}
+#endif
static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
- netif_rx_schedule(pr->d_netdev);
+ netif_rx_schedule(pr->port->netdev, &pr->napi);
return IRQ_HANDLED;
}
@@ -615,7 +714,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
eqe = ehea_poll_eq(port->qp_eq);
}
- queue_work(port->adapter->ehea_wq, &port->reset_task);
+ schedule_work(&port->reset_task);
return IRQ_HANDLED;
}
@@ -795,7 +894,9 @@ int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
ehea_error("Failed setting port speed");
}
}
- netif_carrier_on(port->netdev);
+ if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP))
+ netif_carrier_on(port->netdev);
+
kfree(cb4);
out:
return ret;
@@ -850,13 +951,19 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
+ port->phy_link = EHEA_PHY_LINK_UP;
if (netif_msg_link(port))
ehea_info("%s: Physical port up",
port->netdev->name);
+ if (prop_carrier_state)
+ netif_carrier_on(port->netdev);
} else {
+ port->phy_link = EHEA_PHY_LINK_DOWN;
if (netif_msg_link(port))
ehea_info("%s: Physical port down",
port->netdev->name);
+ if (prop_carrier_state)
+ netif_carrier_off(port->netdev);
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
@@ -1205,14 +1312,16 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
kfree(init_attr);
- pr->d_netdev = alloc_netdev(0, "", ether_setup);
- if (!pr->d_netdev)
- goto out_free;
- pr->d_netdev->priv = pr;
- pr->d_netdev->weight = 64;
- pr->d_netdev->poll = ehea_poll;
- set_bit(__LINK_STATE_START, &pr->d_netdev->state);
- strcpy(pr->d_netdev->name, port->netdev->name);
+ netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64);
+
+ pr->lro_mgr.max_aggr = pr->port->lro_max_aggr;
+ pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
+ pr->lro_mgr.lro_arr = pr->lro_desc;
+ pr->lro_mgr.get_skb_header = get_skb_hdr;
+ pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+ pr->lro_mgr.dev = port->netdev;
+ pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+ pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
ret = 0;
goto out;
@@ -1235,8 +1344,6 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
{
int ret, i;
- free_netdev(pr->d_netdev);
-
ret = ehea_destroy_qp(pr->qp);
if (!ret) {
@@ -1307,7 +1414,6 @@ static void write_swqe2_TSO(struct sk_buff *skb,
u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
int skb_data_size = skb->len - skb->data_len;
int headersize;
- u64 tmp_addr;
/* Packet is TCP with TSO enabled */
swqe->tx_control |= EHEA_SWQE_TSO;
@@ -1328,9 +1434,8 @@ static void write_swqe2_TSO(struct sk_buff *skb,
/* set sg1entry data */
sg1entry->l_key = lkey;
sg1entry->len = skb_data_size - headersize;
-
- tmp_addr = (u64)(skb->data + headersize);
- sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
+ sg1entry->vaddr =
+ ehea_map_vaddr(skb->data + headersize);
swqe->descriptors++;
}
} else
@@ -1343,7 +1448,6 @@ static void write_swqe2_nonTSO(struct sk_buff *skb,
int skb_data_size = skb->len - skb->data_len;
u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
- u64 tmp_addr;
/* Packet is any nonTSO type
*
@@ -1360,8 +1464,8 @@ static void write_swqe2_nonTSO(struct sk_buff *skb,
/* copy sg1entry data */
sg1entry->l_key = lkey;
sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
- tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
- sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
+ sg1entry->vaddr =
+ ehea_map_vaddr(skb->data + SWQE2_MAX_IMM);
swqe->descriptors++;
}
} else {
@@ -1376,7 +1480,6 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
struct ehea_vsgentry *sg_list, *sg1entry, *sgentry;
skb_frag_t *frag;
int nfrags, sg1entry_contains_frag_data, i;
- u64 tmp_addr;
nfrags = skb_shinfo(skb)->nr_frags;
sg1entry = &swqe->u.immdata_desc.sg_entry;
@@ -1398,9 +1501,9 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
/* copy sg1entry data */
sg1entry->l_key = lkey;
sg1entry->len = frag->size;
- tmp_addr = (u64)(page_address(frag->page)
- + frag->page_offset);
- sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
+ sg1entry->vaddr =
+ ehea_map_vaddr(page_address(frag->page)
+ + frag->page_offset);
swqe->descriptors++;
sg1entry_contains_frag_data = 1;
}
@@ -1412,10 +1515,9 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
sgentry->l_key = lkey;
sgentry->len = frag->size;
-
- tmp_addr = (u64)(page_address(frag->page)
- + frag->page_offset);
- sgentry->vaddr = ehea_map_vaddr(tmp_addr);
+ sgentry->vaddr =
+ ehea_map_vaddr(page_address(frag->page)
+ + frag->page_offset);
swqe->descriptors++;
}
}
@@ -1433,7 +1535,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
port->logical_port_id,
reg_type, port->mac_addr, 0, hcallid);
if (hret != H_SUCCESS) {
- ehea_error("reg_dereg_bcmc failed (tagged)");
+ ehea_error("%sregistering bc address failed (tagged)",
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
goto out_herr;
}
@@ -1444,7 +1547,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
port->logical_port_id,
reg_type, port->mac_addr, 0, hcallid);
if (hret != H_SUCCESS) {
- ehea_error("reg_dereg_bcmc failed (vlan)");
+ ehea_error("%sregistering bc address failed (vlan)",
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
}
out_herr:
@@ -1887,11 +1991,12 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
ehea_dump(swqe, 512, "swqe");
}
- if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
- goto out;
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+ netif_stop_queue(dev);
+ swqe->tx_control |= EHEA_SWQE_PURGE;
+ }
ehea_post_swqe(pr->qp, swqe);
- pr->tx_packets++;
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
spin_lock_irqsave(&pr->netif_queue, flags);
@@ -1904,7 +2009,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev->trans_start = jiffies;
spin_unlock(&pr->xmit_lock);
-out:
+
return NETDEV_TX_OK;
}
@@ -2144,24 +2249,18 @@ static int ehea_clean_all_portres(struct ehea_port *port)
return ret;
}
-static void ehea_remove_adapter_mr (struct ehea_adapter *adapter)
+static void ehea_remove_adapter_mr(struct ehea_adapter *adapter)
{
- int i;
-
- for (i=0; i < EHEA_MAX_PORTS; i++)
- if (adapter->port[i])
- return;
+ if (adapter->active_ports)
+ return;
ehea_rem_mr(&adapter->mr);
}
-static int ehea_add_adapter_mr (struct ehea_adapter *adapter)
+static int ehea_add_adapter_mr(struct ehea_adapter *adapter)
{
- int i;
-
- for (i=0; i < EHEA_MAX_PORTS; i++)
- if (adapter->port[i])
- return 0;
+ if (adapter->active_ports)
+ return 0;
return ehea_reg_kernel_mr(adapter, &adapter->mr);
}
@@ -2170,7 +2269,6 @@ static int ehea_up(struct net_device *dev)
{
int ret, i;
struct ehea_port *port = netdev_priv(dev);
- u64 mac_addr = 0;
if (port->state == EHEA_PORT_UP)
return 0;
@@ -2189,18 +2287,10 @@ static int ehea_up(struct net_device *dev)
goto out_clean_pr;
}
- ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
- if (ret) {
- ret = -EIO;
- ehea_error("out_clean_pr");
- goto out_clean_pr;
- }
- mac_addr = (*(u64*)dev->dev_addr) >> 16;
-
ret = ehea_reg_interrupts(dev);
if (ret) {
- ehea_error("out_dereg_bc");
- goto out_dereg_bc;
+ ehea_error("reg_interrupts failed. ret:%d", ret);
+ goto out_clean_pr;
}
for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
@@ -2226,9 +2316,6 @@ static int ehea_up(struct net_device *dev)
out_free_irqs:
ehea_free_interrupts(dev);
-out_dereg_bc:
- ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
-
out_clean_pr:
ehea_clean_all_portres(port);
out:
@@ -2238,6 +2325,22 @@ out:
return ret;
}
+static void port_napi_disable(struct ehea_port *port)
+{
+ int i;
+
+ for (i = 0; i < port->num_def_qps; i++)
+ napi_disable(&port->port_res[i].napi);
+}
+
+static void port_napi_enable(struct ehea_port *port)
+{
+ int i;
+
+ for (i = 0; i < port->num_def_qps; i++)
+ napi_enable(&port->port_res[i].napi);
+}
+
static int ehea_open(struct net_device *dev)
{
int ret;
@@ -2249,8 +2352,10 @@ static int ehea_open(struct net_device *dev)
ehea_info("enabling port %s", dev->name);
ret = ehea_up(dev);
- if (!ret)
+ if (!ret) {
+ port_napi_enable(port);
netif_start_queue(dev);
+ }
up(&port->port_lock);
@@ -2259,7 +2364,7 @@ static int ehea_open(struct net_device *dev)
static int ehea_down(struct net_device *dev)
{
- int ret, i;
+ int ret;
struct ehea_port *port = netdev_priv(dev);
if (port->state == EHEA_PORT_DOWN)
@@ -2268,12 +2373,8 @@ static int ehea_down(struct net_device *dev)
ehea_drop_multicast_list(dev);
ehea_free_interrupts(dev);
- for (i = 0; i < port->num_def_qps; i++)
- while (test_bit(__LINK_STATE_RX_SCHED,
- &port->port_res[i].d_netdev->state))
- msleep(1);
+ port_napi_disable(port);
- ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
port->state = EHEA_PORT_DOWN;
ret = ehea_clean_all_portres(port);
@@ -2292,7 +2393,7 @@ static int ehea_stop(struct net_device *dev)
if (netif_msg_ifdown(port))
ehea_info("disabling port %s", dev->name);
- flush_workqueue(port->adapter->ehea_wq);
+ flush_scheduled_work();
down(&port->port_lock);
netif_stop_queue(dev);
ret = ehea_down(dev);
@@ -2300,6 +2401,192 @@ static int ehea_stop(struct net_device *dev)
return ret;
}
+void ehea_purge_sq(struct ehea_qp *orig_qp)
+{
+ struct ehea_qp qp = *orig_qp;
+ struct ehea_qp_init_attr *init_attr = &qp.init_attr;
+ struct ehea_swqe *swqe;
+ int wqe_index;
+ int i;
+
+ for (i = 0; i < init_attr->act_nr_send_wqes; i++) {
+ swqe = ehea_get_swqe(&qp, &wqe_index);
+ swqe->tx_control |= EHEA_SWQE_PURGE;
+ }
+}
+
+int ehea_stop_qps(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ struct hcp_modify_qp_cb0* cb0;
+ int ret = -EIO;
+ int dret;
+ int i;
+ u64 hret;
+ u64 dummy64 = 0;
+ u16 dummy16 = 0;
+
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!cb0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ struct ehea_port_res *pr = &port->port_res[i];
+ struct ehea_qp *qp = pr->qp;
+
+ /* Purge send queue */
+ ehea_purge_sq(qp);
+
+ /* Disable queue pair */
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (1)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
+ cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED;
+
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
+ 1), cb0, &dummy64,
+ &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (1)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (2)");
+ goto out;
+ }
+
+ /* deregister shared memory regions */
+ dret = ehea_rem_smrs(pr);
+ if (dret) {
+ ehea_error("unreg shared memory region failed");
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ kfree(cb0);
+
+ return ret;
+}
+
+void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr)
+{
+ struct ehea_qp qp = *orig_qp;
+ struct ehea_qp_init_attr *init_attr = &qp.init_attr;
+ struct ehea_rwqe *rwqe;
+ struct sk_buff **skba_rq2 = pr->rq2_skba.arr;
+ struct sk_buff **skba_rq3 = pr->rq3_skba.arr;
+ struct sk_buff *skb;
+ u32 lkey = pr->recv_mr.lkey;
+
+
+ int i;
+ int index;
+
+ for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) {
+ rwqe = ehea_get_next_rwqe(&qp, 2);
+ rwqe->sg_list[0].l_key = lkey;
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
+ skb = skba_rq2[index];
+ if (skb)
+ rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+ }
+
+ for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) {
+ rwqe = ehea_get_next_rwqe(&qp, 3);
+ rwqe->sg_list[0].l_key = lkey;
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
+ skb = skba_rq3[index];
+ if (skb)
+ rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+ }
+}
+
+int ehea_restart_qps(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ int ret = 0;
+ int i;
+
+ struct hcp_modify_qp_cb0* cb0;
+ u64 hret;
+ u64 dummy64 = 0;
+ u16 dummy16 = 0;
+
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!cb0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ struct ehea_port_res *pr = &port->port_res[i];
+ struct ehea_qp *qp = pr->qp;
+
+ ret = ehea_gen_smrs(pr);
+ if (ret) {
+ ehea_error("creation of shared memory regions failed");
+ goto out;
+ }
+
+ ehea_update_rqs(qp, pr);
+
+ /* Enable queue pair */
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (1)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
+ cb0->qp_ctl_reg |= H_QP_CR_ENABLED;
+
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
+ 1), cb0, &dummy64,
+ &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (1)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (2)");
+ goto out;
+ }
+
+ /* refill entire queue */
+ ehea_refill_rq1(pr, pr->rq1_skba.index, 0);
+ ehea_refill_rq2(pr, 0);
+ ehea_refill_rq3(pr, 0);
+ }
+out:
+ kfree(cb0);
+
+ return ret;
+}
+
static void ehea_reset_port(struct work_struct *work)
{
int ret;
@@ -2310,7 +2597,8 @@ static void ehea_reset_port(struct work_struct *work)
port->resets++;
down(&port->port_lock);
netif_stop_queue(dev);
- netif_poll_disable(dev);
+
+ port_napi_disable(port);
ehea_down(dev);
@@ -2318,10 +2606,13 @@ static void ehea_reset_port(struct work_struct *work)
if (ret)
goto out;
+ ehea_set_multicast_list(dev);
+
if (netif_msg_timer(port))
ehea_info("Device %s resetted successfully", dev->name);
- netif_poll_enable(dev);
+ port_napi_enable(port);
+
netif_wake_queue(dev);
out:
up(&port->port_lock);
@@ -2333,6 +2624,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
int ret, i;
struct ehea_adapter *adapter;
+ down(&dlpar_mem_lock);
ehea_info("LPAR memory enlarged - re-initializing driver");
list_for_each_entry(adapter, &adapter_list, list)
@@ -2345,12 +2637,14 @@ static void ehea_rereg_mrs(struct work_struct *work)
struct net_device *dev = port->netdev;
if (dev->flags & IFF_UP) {
- ehea_info("stopping %s",
- dev->name);
down(&port->port_lock);
netif_stop_queue(dev);
- netif_poll_disable(dev);
- ehea_down(dev);
+ ret = ehea_stop_qps(dev);
+ if (ret) {
+ up(&port->port_lock);
+ goto out;
+ }
+ port_napi_disable(port);
up(&port->port_lock);
}
}
@@ -2366,10 +2660,11 @@ static void ehea_rereg_mrs(struct work_struct *work)
}
ehea_destroy_busmap();
-
ret = ehea_create_busmap();
- if (ret)
+ if (ret) {
+ ehea_error("creating ehea busmap failed");
goto out;
+ }
clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
@@ -2391,21 +2686,18 @@ static void ehea_rereg_mrs(struct work_struct *work)
struct net_device *dev = port->netdev;
if (dev->flags & IFF_UP) {
- ehea_info("restarting %s",
- dev->name);
down(&port->port_lock);
-
- ret = ehea_up(dev);
- if (!ret) {
- netif_poll_enable(dev);
+ port_napi_enable(port);
+ ret = ehea_restart_qps(dev);
+ if (!ret)
netif_wake_queue(dev);
- }
-
up(&port->port_lock);
}
}
}
}
+ up(&dlpar_mem_lock);
+ ehea_info("re-initializing driver complete");
out:
return;
}
@@ -2414,8 +2706,9 @@ static void ehea_tx_watchdog(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
- if (netif_carrier_ok(dev))
- queue_work(port->adapter->ehea_wq, &port->reset_task);
+ if (netif_carrier_ok(dev) &&
+ !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
+ schedule_work(&port->reset_task);
}
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
@@ -2493,7 +2786,7 @@ static ssize_t ehea_show_port_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
- return sprintf(buf, "0x%X", port->logical_port_id);
+ return sprintf(buf, "%d", port->logical_port_id);
}
static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
@@ -2630,13 +2923,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
SET_NETDEV_DEV(dev, port_dev);
/* initialize net_device structure */
- SET_MODULE_OWNER(dev);
-
memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
dev->open = ehea_open;
- dev->poll = ehea_poll;
- dev->weight = 64;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = ehea_netpoll;
+#endif
dev->stop = ehea_stop;
dev->hard_start_xmit = ehea_start_xmit;
dev->get_stats = ehea_get_stats;
@@ -2655,14 +2947,22 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
INIT_WORK(&port->reset_task, ehea_reset_port);
+ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+ if (ret) {
+ ret = -EIO;
+ goto out_unreg_port;
+ }
+
ehea_set_ethtool_ops(dev);
ret = register_netdev(dev);
if (ret) {
ehea_error("register_netdev failed. ret=%d", ret);
- goto out_unreg_port;
+ goto out_dereg_bc;
}
+ port->lro_max_aggr = lro_max_aggr;
+
ret = ehea_get_jumboframe_status(port, &jumbo);
if (ret)
ehea_error("failed determining jumbo frame status for %s",
@@ -2675,6 +2975,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
return port;
+out_dereg_bc:
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
out_unreg_port:
ehea_unregister_port(port);
@@ -2694,6 +2997,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
{
unregister_netdev(port->netdev);
ehea_unregister_port(port);
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
kfree(port->mc_list);
free_netdev(port->netdev);
port->adapter->active_ports--;
@@ -2771,7 +3075,7 @@ static ssize_t ehea_probe_port(struct device *dev,
u32 logical_port_id;
- sscanf(buf, "%X", &logical_port_id);
+ sscanf(buf, "%d", &logical_port_id);
port = ehea_get_port(adapter, logical_port_id);
@@ -2824,7 +3128,7 @@ static ssize_t ehea_remove_port(struct device *dev,
int i;
u32 logical_port_id;
- sscanf(buf, "%X", &logical_port_id);
+ sscanf(buf, "%d", &logical_port_id);
port = ehea_get_port(adapter, logical_port_id);
@@ -2937,15 +3241,9 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
goto out_kill_eq;
}
- adapter->ehea_wq = create_workqueue("ehea_wq");
- if (!adapter->ehea_wq) {
- ret = -EIO;
- goto out_free_irq;
- }
-
ret = ehea_create_device_sysfs(dev);
if (ret)
- goto out_kill_wq;
+ goto out_free_irq;
ret = ehea_setup_ports(adapter);
if (ret) {
@@ -2959,9 +3257,6 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
out_rem_dev_sysfs:
ehea_remove_device_sysfs(dev);
-out_kill_wq:
- destroy_workqueue(adapter->ehea_wq);
-
out_free_irq:
ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
@@ -2987,7 +3282,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev)
ehea_remove_device_sysfs(dev);
- destroy_workqueue(adapter->ehea_wq);
+ flush_scheduled_work();
ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
tasklet_kill(&adapter->neq_tasklet);
@@ -3045,9 +3340,9 @@ int __init ehea_module_init(void)
printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
DRV_VERSION);
- ehea_driver_wq = create_workqueue("ehea_driver_wq");
INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
+ sema_init(&dlpar_mem_lock, 1);
ret = check_module_parm();
if (ret)
@@ -3078,6 +3373,7 @@ out:
static void __exit ehea_module_exit(void)
{
+ flush_scheduled_work();
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver);
ehea_destroy_busmap();
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 89b63531ff26..faa191d23b86 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -126,6 +126,7 @@ struct hcp_modify_qp_cb0 {
#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */
#define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */
#define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */
+#define H_QP_CR_RES_STATE 0x0000007F00000000ULL /* Resultant state */
struct hcp_modify_qp_cb1 {
u32 qpn; /* 00 */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index a36fa6c23fdf..83b76432b41a 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -34,7 +34,6 @@
struct ehea_busmap ehea_bmap = { 0, 0, NULL };
extern u64 ehea_driver_flags;
-extern struct workqueue_struct *ehea_driver_wq;
extern struct work_struct ehea_rereg_mr_task;
@@ -235,6 +234,8 @@ int ehea_destroy_cq(struct ehea_cq *cq)
if (!cq)
return 0;
+ hcp_epas_dtor(&cq->epas);
+
if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
ehea_error_data(cq->adapter, cq->fw_handle);
hret = ehea_destroy_cq_res(cq, FORCE_FREE);
@@ -361,6 +362,8 @@ int ehea_destroy_eq(struct ehea_eq *eq)
if (!eq)
return 0;
+ hcp_epas_dtor(&eq->epas);
+
if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
ehea_error_data(eq->adapter, eq->fw_handle);
hret = ehea_destroy_eq_res(eq, FORCE_FREE);
@@ -541,6 +544,8 @@ int ehea_destroy_qp(struct ehea_qp *qp)
if (!qp)
return 0;
+ hcp_epas_dtor(&qp->epas);
+
if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
ehea_error_data(qp->adapter, qp->fw_handle);
hret = ehea_destroy_qp_res(qp, FORCE_FREE);
@@ -557,8 +562,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
int ehea_create_busmap( void )
{
u64 vaddr = EHEA_BUSMAP_START;
- unsigned long abs_max_pfn = 0;
- unsigned long sec_max_pfn;
+ unsigned long high_section_index = 0;
int i;
/*
@@ -568,14 +572,10 @@ int ehea_create_busmap( void )
ehea_bmap.valid_sections = 0;
for (i = 0; i < NR_MEM_SECTIONS; i++)
- if (valid_section_nr(i)) {
- sec_max_pfn = section_nr_to_pfn(i);
- if (sec_max_pfn > abs_max_pfn)
- abs_max_pfn = sec_max_pfn;
- ehea_bmap.valid_sections++;
- }
+ if (valid_section_nr(i))
+ high_section_index = i;
- ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1;
+ ehea_bmap.entries = high_section_index + 1;
ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
if (!ehea_bmap.vaddr)
@@ -587,6 +587,7 @@ int ehea_create_busmap( void )
if (pfn_valid(pfn)) {
ehea_bmap.vaddr[i] = vaddr;
vaddr += EHEA_SECTSIZE;
+ ehea_bmap.valid_sections++;
} else
ehea_bmap.vaddr[i] = 0;
}
@@ -616,7 +617,7 @@ u64 ehea_map_vaddr(void *caddr)
if (unlikely(mapped_addr == -1))
if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
- queue_work(ehea_driver_wq, &ehea_rereg_mr_task);
+ schedule_work(&ehea_rereg_mr_task);
return mapped_addr;
}
@@ -631,7 +632,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
- pt = kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL);
+ pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!pt) {
ehea_error("no mem");
ret = -ENOMEM;
@@ -654,8 +655,8 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
void *sectbase = __va(i << SECTION_SIZE_BITS);
unsigned long k = 0;
- for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE);
- j++) {
+ 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);
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index b71f8452a5e3..562de0ebdd85 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -39,7 +39,7 @@
#define EHEA_PAGESHIFT 12
#define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT)
#define EHEA_SECTSIZE (1UL << 24)
-#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT)
+#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT)
#if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
#error eHEA module can't work if kernel sectionsize < ehea sectionsize
@@ -145,7 +145,7 @@ struct ehea_rwqe {
#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
#define EHEA_CQE_TYPE_RQ 0x60
-#define EHEA_CQE_STAT_ERR_MASK 0x721F
+#define EHEA_CQE_STAT_ERR_MASK 0x720F
#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
#define EHEA_CQE_STAT_ERR_TCP 0x4000
#define EHEA_CQE_STAT_ERR_IP 0x2000
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 119778401e48..ecdd3fc8d70c 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -262,6 +262,7 @@ struct epic_private {
/* Ring pointers. */
spinlock_t lock; /* Group with Tx control cache line. */
spinlock_t napi_lock;
+ struct napi_struct napi;
unsigned int reschedule_in_poll;
unsigned int cur_tx, dirty_tx;
@@ -294,7 +295,7 @@ static void epic_tx_timeout(struct net_device *dev);
static void epic_init_ring(struct net_device *dev);
static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int epic_rx(struct net_device *dev, int budget);
-static int epic_poll(struct net_device *dev, int *budget);
+static int epic_poll(struct napi_struct *napi, int budget);
static irqreturn_t epic_interrupt(int irq, void *dev_instance);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
@@ -316,6 +317,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
int i, ret, option = 0, duplex = 0;
void *ring_space;
dma_addr_t ring_dma;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -351,7 +353,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev_err(&pdev->dev, "no memory for eth device\n");
goto err_out_free_res;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#ifdef USE_IO_OPS
@@ -487,18 +488,15 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
dev->tx_timeout = &epic_tx_timeout;
- dev->poll = epic_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &ep->napi, epic_poll, 64);
ret = register_netdev(dev);
if (ret < 0)
goto err_out_unmap_rx;
- printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x.\n", dev->dev_addr[i]);
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+ dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq,
+ print_mac(mac, dev->dev_addr));
out:
return ret;
@@ -660,8 +658,11 @@ static int epic_open(struct net_device *dev)
/* Soft reset the chip. */
outl(0x4001, ioaddr + GENCTL);
- if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev)))
+ napi_enable(&ep->napi);
+ if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) {
+ napi_disable(&ep->napi);
return retval;
+ }
epic_init_ring(dev);
@@ -1103,9 +1104,9 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance)
if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
spin_lock(&ep->napi_lock);
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &ep->napi)) {
epic_napi_irq_off(dev, ep);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &ep->napi);
} else
ep->reschedule_in_poll++;
spin_unlock(&ep->napi_lock);
@@ -1257,26 +1258,22 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
outw(RxQueued, ioaddr + COMMAND);
}
-static int epic_poll(struct net_device *dev, int *budget)
+static int epic_poll(struct napi_struct *napi, int budget)
{
- struct epic_private *ep = dev->priv;
- int work_done = 0, orig_budget;
+ struct epic_private *ep = container_of(napi, struct epic_private, napi);
+ struct net_device *dev = ep->mii.dev;
+ int work_done = 0;
long ioaddr = dev->base_addr;
- orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
-
rx_action:
epic_tx(dev, ep);
- work_done += epic_rx(dev, *budget);
+ work_done += epic_rx(dev, budget);
epic_rx_err(dev, ep);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (netif_running(dev) && (work_done < orig_budget)) {
+ if (netif_running(dev) && (work_done < budget)) {
unsigned long flags;
int more;
@@ -1286,7 +1283,7 @@ rx_action:
more = ep->reschedule_in_poll;
if (!more) {
- __netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
outl(EpicNapiEvent, ioaddr + INTSTAT);
epic_napi_irq_on(dev, ep);
} else
@@ -1298,7 +1295,7 @@ rx_action:
goto rx_action;
}
- return (work_done >= orig_budget);
+ return work_done;
}
static int epic_close(struct net_device *dev)
@@ -1309,6 +1306,7 @@ static int epic_close(struct net_device *dev)
int i;
netif_stop_queue(dev);
+ napi_disable(&ep->napi);
if (debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
@@ -1495,8 +1493,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
.begin = ethtool_begin,
.complete = ethtool_complete
};
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index a93700e5661a..18f1364d3d5b 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -116,6 +116,7 @@
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/netdevice.h>
+#include <net/net_namespace.h>
#include <linux/if.h>
#include <linux/if_arp.h>
@@ -127,7 +128,6 @@ static int eql_open(struct net_device *dev);
static int eql_close(struct net_device *dev);
static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *eql_get_stats(struct net_device *dev);
#define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE)
#define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER)
@@ -166,8 +166,6 @@ static void __init eql_setup(struct net_device *dev)
{
equalizer_t *eql = netdev_priv(dev);
- SET_MODULE_OWNER(dev);
-
init_timer(&eql->timer);
eql->timer.data = (unsigned long) eql;
eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL;
@@ -181,7 +179,6 @@ static void __init eql_setup(struct net_device *dev)
dev->stop = eql_close;
dev->do_ioctl = eql_ioctl;
dev->hard_start_xmit = eql_slave_xmit;
- dev->get_stats = eql_get_stats;
/*
* Now we undo some of the things that eth_setup does
@@ -338,9 +335,9 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
skb->priority = 1;
slave->bytes_queued += skb->len;
dev_queue_xmit(skb);
- eql->stats.tx_packets++;
+ dev->stats.tx_packets++;
} else {
- eql->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
}
@@ -349,12 +346,6 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats * eql_get_stats(struct net_device *dev)
-{
- equalizer_t *eql = netdev_priv(dev);
- return &eql->stats;
-}
-
/*
* Private ioctl functions
*/
@@ -391,7 +382,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave)
slave_t *duplicate_slave = NULL;
duplicate_slave = __eql_find_slave_dev(queue, slave->dev);
- if (duplicate_slave != 0)
+ if (duplicate_slave)
eql_kill_one_slave(queue, duplicate_slave);
list_add(&slave->list, &queue->all_slaves);
@@ -412,7 +403,7 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t __user *
if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(srq.slave_name);
+ slave_dev = dev_get_by_name(&init_net, srq.slave_name);
if (slave_dev) {
if ((master_dev->flags & IFF_UP) == IFF_UP) {
/* slave is not a master & not already a slave: */
@@ -460,7 +451,7 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t __use
if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(srq.slave_name);
+ slave_dev = dev_get_by_name(&init_net, srq.slave_name);
ret = -EINVAL;
if (slave_dev) {
spin_lock_bh(&eql->queue.lock);
@@ -493,7 +484,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(sc.slave_name);
+ slave_dev = dev_get_by_name(&init_net, sc.slave_name);
if (!slave_dev)
return -ENODEV;
@@ -528,7 +519,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(sc.slave_name);
+ slave_dev = dev_get_by_name(&init_net, sc.slave_name);
if (!slave_dev)
return -ENODEV;
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 822e5bfd1a71..deefa51b8c31 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -130,8 +130,6 @@ static int __init do_es_probe(struct net_device *dev)
int irq = dev->irq;
int mem_start = dev->mem_start;
- SET_MODULE_OWNER(dev);
-
if (ioaddr > 0x1ff) /* Check a single specified location. */
return es_probe1(dev, ioaddr);
else if (ioaddr > 0) /* Don't probe at all. */
@@ -181,6 +179,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
{
int i, retval;
unsigned long eisa_id;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
return -ENODEV;
@@ -192,7 +191,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
#endif
-
/* Check the EISA ID of the card. */
eisa_id = inl(ioaddr + ES_ID_PORT);
if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
@@ -200,21 +198,21 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
goto out;
}
+ for (i = 0; i < ETHER_ADDR_LEN ; i++)
+ dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
+
/* Check the Racal vendor ID as well. */
- if (inb(ioaddr + ES_SA_PROM + 0) != ES_ADDR0
- || inb(ioaddr + ES_SA_PROM + 1) != ES_ADDR1
- || inb(ioaddr + ES_SA_PROM + 2) != ES_ADDR2 ) {
- printk("es3210.c: card not found");
- for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", inb(ioaddr + ES_SA_PROM + i));
- printk(" (invalid prefix).\n");
+ if (dev->dev_addr[0] != ES_ADDR0 ||
+ dev->dev_addr[1] != ES_ADDR1 ||
+ dev->dev_addr[2] != ES_ADDR2) {
+ printk("es3210.c: card not found %s (invalid_prefix).\n",
+ print_mac(mac, dev->dev_addr));
retval = -ENODEV;
goto out;
}
- printk("es3210.c: ES3210 rev. %ld at %#x, node", eisa_id>>24, ioaddr);
- for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i)));
+ printk("es3210.c: ES3210 rev. %ld at %#x, node %s",
+ eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr));
/* Snarf the interrupt now. */
if (dev->irq == 0) {
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 04abf59e5007..243fc6b354b5 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -380,7 +380,6 @@ static unsigned int eth16i_debug = ETH16I_DEBUG;
/* Information for each board */
struct eth16i_local {
- struct net_device_stats stats;
unsigned char tx_started;
unsigned char tx_buf_busy;
unsigned short tx_queue; /* Number of packets in transmit buffer */
@@ -426,8 +425,6 @@ static int eth16i_set_irq(struct net_device *dev);
static ushort eth16i_parse_mediatype(const char* s);
#endif
-static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
-
static char cardname[] __initdata = "ICL EtherTeam 16i/32";
static int __init do_eth16i_probe(struct net_device *dev)
@@ -436,8 +433,6 @@ static int __init do_eth16i_probe(struct net_device *dev)
int ioaddr;
int base_addr = dev->base_addr;
- SET_MODULE_OWNER(dev);
-
if(eth16i_debug > 4)
printk(KERN_DEBUG "Probing started for %s\n", cardname);
@@ -559,7 +554,6 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
dev->open = eth16i_open;
dev->stop = eth16i_close;
dev->hard_start_xmit = eth16i_tx;
- dev->get_stats = eth16i_get_stats;
dev->set_multicast_list = eth16i_multicast;
dev->tx_timeout = eth16i_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1047,7 +1041,7 @@ static void eth16i_timeout(struct net_device *dev)
printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
eth16i_reset(dev);
dev->trans_start = jiffies;
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
@@ -1132,7 +1126,6 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
static void eth16i_rx(struct net_device *dev)
{
- struct eth16i_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int boguscount = MAX_RX_LOOP;
@@ -1151,16 +1144,16 @@ static void eth16i_rx(struct net_device *dev)
inb(ioaddr + RECEIVE_MODE_REG), status);
if( !(status & PKT_GOOD) ) {
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
eth16i_reset(dev);
return;
}
else {
eth16i_skip_packet(dev);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
}
else { /* Ok so now we should have a good packet */
@@ -1171,7 +1164,7 @@ static void eth16i_rx(struct net_device *dev)
printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
dev->name, pkt_len);
eth16i_skip_packet(dev);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -1214,8 +1207,8 @@ static void eth16i_rx(struct net_device *dev)
}
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
} /* else */
@@ -1252,32 +1245,32 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
if( status & 0x7f00 ) {
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if(status & (BUS_RD_ERR << 8) )
printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
- if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++;
- if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++;
- if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++;
- if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;
+ if(status & (SHORT_PKT_ERR << 8) ) dev->stats.rx_length_errors++;
+ if(status & (ALIGN_ERR << 8) ) dev->stats.rx_frame_errors++;
+ if(status & (CRC_ERR << 8) ) dev->stats.rx_crc_errors++;
+ if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++;
}
if( status & 0x001a) {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
- if(status & CR_LOST) lp->stats.tx_carrier_errors++;
- if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
+ if(status & CR_LOST) dev->stats.tx_carrier_errors++;
+ if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++;
#if 0
if(status & COLLISION) {
- lp->stats.collisions +=
+ dev->stats.collisions +=
((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
}
#endif
if(status & COLLISIONS_16) {
if(lp->col_16 < MAX_COL_16) {
lp->col_16++;
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* Resume transmitting, skip failed packet */
outb(0x02, ioaddr + COL_16_REG);
}
@@ -1290,8 +1283,8 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
if( status & 0x00ff ) { /* Let's check the transmit status reg */
if(status & TX_DONE) { /* The transmit has been done */
- lp->stats.tx_packets = lp->tx_buffered_packets;
- lp->stats.tx_bytes += lp->tx_buffered_bytes;
+ dev->stats.tx_packets = lp->tx_buffered_packets;
+ dev->stats.tx_bytes += lp->tx_buffered_bytes;
lp->col_16 = 0;
if(lp->tx_queue) { /* Is there still packets ? */
@@ -1371,12 +1364,6 @@ static void eth16i_multicast(struct net_device *dev)
}
}
-static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
{
unsigned char data;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index cb0792c187ba..593a120e31b2 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -275,7 +275,6 @@ struct ewrk3_private {
u_long shmem_base; /* Shared memory start address */
void __iomem *shmem;
u_long shmem_length; /* Shared memory window length */
- struct net_device_stats stats; /* Public stats */
struct ewrk3_stats pktStats; /* Private stats counters */
u_char irq_mask; /* Adapter IRQ mask bits */
u_char mPage; /* Maximum 2kB Page number */
@@ -302,7 +301,6 @@ static int ewrk3_open(struct net_device *dev);
static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
static int ewrk3_close(struct net_device *dev);
-static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops ethtool_ops_203;
@@ -356,7 +354,6 @@ struct net_device * __init ewrk3_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
if (err)
@@ -399,6 +396,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
u_long mem_start, shmem_length;
u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
+ DECLARE_MAC_BUF(mac);
/*
** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
@@ -463,10 +461,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
if (lemac != LeMAC2)
DevicePresent(iobase); /* need after EWRK3_INIT */
status = get_hw_addr(dev, eeprom_image, lemac);
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x,\n", dev->dev_addr[i]);
+ printk("%s\n", print_mac(mac, dev->dev_addr));
if (status) {
printk(" which has an EEPROM CRC error.\n");
@@ -612,7 +607,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
dev->open = ewrk3_open;
dev->hard_start_xmit = ewrk3_queue_pkt;
dev->stop = ewrk3_close;
- dev->get_stats = ewrk3_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->do_ioctl = ewrk3_ioctl;
if (lp->adapter_name[4] == '3')
@@ -632,7 +626,7 @@ static int ewrk3_open(struct net_device *dev)
{
struct ewrk3_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
- int i, status = 0;
+ int status = 0;
u_char icr, csr;
/*
@@ -652,12 +646,10 @@ static int ewrk3_open(struct net_device *dev)
ewrk3_init(dev);
if (ewrk3_debug > 1) {
+ DECLARE_MAC_BUF(mac);
printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
- printk(" physical address: ");
- for (i = 0; i < 5; i++) {
- printk("%2.2x:", (u_char) dev->dev_addr[i]);
- }
- printk("%2.2x\n", (u_char) dev->dev_addr[i]);
+ printk(" physical address: %s\n",
+ print_mac(mac, dev->dev_addr));
if (lp->shmem_length == 0) {
printk(" no shared memory, I/O only mode\n");
} else {
@@ -864,7 +856,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
ENABLE_IRQs;
spin_unlock_irq (&lp->hw_lock);
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
@@ -981,13 +973,13 @@ static int ewrk3_rx(struct net_device *dev)
}
if (!(rx_status & R_ROK)) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
+ dev->stats.rx_errors++; /* Update the error stats. */
if (rx_status & R_DBE)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status & R_CRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_status & R_PLL)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
} else {
struct sk_buff *skb;
@@ -1038,11 +1030,11 @@ static int ewrk3_rx(struct net_device *dev)
** Update stats
*/
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
} else {
printk("%s: Insufficient memory; nuking packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
+ dev->stats.rx_dropped++; /* Really, deferred. */
break;
}
}
@@ -1072,11 +1064,11 @@ static int ewrk3_tx(struct net_device *dev)
while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */
if (tx_status & T_VSTS) { /* The status is valid */
if (tx_status & T_TXE) {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status & T_NCL)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & T_LCL)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tx_status & T_CTU) {
if ((tx_status & T_COLL) ^ T_XUR) {
lp->pktStats.tx_underruns++;
@@ -1085,13 +1077,13 @@ static int ewrk3_tx(struct net_device *dev)
}
} else if (tx_status & T_COLL) {
if ((tx_status & T_COLL) ^ T_XCOLL) {
- lp->stats.collisions++;
+ dev->stats.collisions++;
} else {
lp->pktStats.excessive_collisions++;
}
}
} else {
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
}
}
@@ -1134,14 +1126,6 @@ static int ewrk3_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *ewrk3_get_stats(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
-
- /* Null body since there is no framing error counter */
- return &lp->stats;
-}
-
/*
** Set or clear the multicast filter for this adapter.
*/
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index ff9f177d7157..43f7647ff246 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -486,6 +486,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
#else
int bar = 1;
#endif
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -527,7 +528,6 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_out_unmap;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* read ethernet id */
@@ -665,11 +665,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (err)
goto err_out_free_tx;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
return 0;
@@ -1892,8 +1890,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
};
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 03023dd17829..2b5782056dda 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -47,6 +47,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
@@ -98,8 +99,6 @@ static unsigned char fec_mac_default[] = {
#define FEC_FLASHMAC 0xf0006006
#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
#define FEC_FLASHMAC 0xf0006000
-#elif defined (CONFIG_MTD_KeyTechnology)
-#define FEC_FLASHMAC 0xffe04000
#elif defined(CONFIG_CANCam)
#define FEC_FLASHMAC 0xf0020000
#elif defined (CONFIG_M5272C3)
@@ -191,6 +190,8 @@ struct fec_enet_private {
/* Hardware registers of the FEC device */
volatile fec_t *hwp;
+ struct net_device *netdev;
+
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
unsigned char *tx_bounce[TX_RING_SIZE];
struct sk_buff* tx_skbuff[TX_RING_SIZE];
@@ -203,7 +204,6 @@ struct fec_enet_private {
cbd_t *tx_bd_base;
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
- struct net_device_stats stats;
uint tx_full;
spinlock_t lock;
@@ -233,7 +233,6 @@ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
-static struct net_device_stats *fec_enet_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void fec_restart(struct net_device *dev, int duplex);
static void fec_stop(struct net_device *dev);
@@ -358,7 +357,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
fep->tx_skbuff[fep->skb_cur] = skb;
- fep->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
/* Push the data cache so the CPM does not get stale memory
@@ -408,7 +407,7 @@ fec_timeout(struct net_device *dev)
struct fec_enet_private *fep = netdev_priv(dev);
printk("%s: transmit timed out.\n", dev->name);
- fep->stats.tx_errors++;
+ dev->stats.tx_errors++;
#ifndef final_version
{
int i;
@@ -510,19 +509,19 @@ fec_enet_tx(struct net_device *dev)
if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN |
BD_ENET_TX_CSL)) {
- fep->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & BD_ENET_TX_HB) /* No heartbeat */
- fep->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (status & BD_ENET_TX_LC) /* Late collision */
- fep->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (status & BD_ENET_TX_RL) /* Retrans limit */
- fep->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & BD_ENET_TX_UN) /* Underrun */
- fep->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (status & BD_ENET_TX_CSL) /* Carrier lost */
- fep->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
} else {
- fep->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
#ifndef final_version
@@ -533,7 +532,7 @@ fec_enet_tx(struct net_device *dev)
* but we eventually sent the packet OK.
*/
if (status & BD_ENET_TX_DEF)
- fep->stats.collisions++;
+ dev->stats.collisions++;
/* Free the sk buffer associated with this last transmit.
*/
@@ -606,17 +605,17 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
/* Check for errors. */
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
BD_ENET_RX_CR | BD_ENET_RX_OV)) {
- fep->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
/* Frame too long or too short. */
- fep->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
if (status & BD_ENET_RX_NO) /* Frame alignment */
- fep->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & BD_ENET_RX_CR) /* CRC Error */
- fep->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & BD_ENET_RX_OV) /* FIFO overrun */
- fep->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
/* Report late collisions as a frame error.
@@ -624,16 +623,16 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
* have in the buffer. So, just drop this frame on the floor.
*/
if (status & BD_ENET_RX_CL) {
- fep->stats.rx_errors++;
- fep->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
goto rx_processing_done;
}
/* Process the incoming frame.
*/
- fep->stats.rx_packets++;
+ dev->stats.rx_packets++;
pkt_len = bdp->cbd_datlen;
- fep->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
data = (__u8*)__va(bdp->cbd_bufaddr);
/* This does 16 byte alignment, exactly what we need.
@@ -645,7 +644,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- fep->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
skb_put(skb,pkt_len-4); /* Make room */
skb_copy_to_linear_data(skb, data, pkt_len-4);
@@ -1269,7 +1268,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
*icrp = 0x00000ddd;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = (*icrp & 0x70777777) | 0x0d000000;
+ *icrp = 0x0d000000;
}
static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
@@ -1331,7 +1330,7 @@ static void __inline__ fec_disable_phy_intr(void)
{
volatile unsigned long *icrp;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = (*icrp & 0x70777777) | 0x08000000;
+ *icrp = 0x08000000;
}
static void __inline__ fec_phy_ack_intr(void)
@@ -1339,7 +1338,7 @@ static void __inline__ fec_phy_ack_intr(void)
volatile unsigned long *icrp;
/* Acknowledge the interrupt */
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = (*icrp & 0x77777777) | 0x08000000;
+ *icrp = 0x0d000000;
}
static void __inline__ fec_localhw_setup(void)
@@ -1426,6 +1425,29 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
*gpio_pehlpar = 0xc0;
}
#endif
+
+#if defined(CONFIG_M527x)
+ /* Set up gpio outputs for MII lines */
+ {
+ volatile u8 *gpio_par_fec;
+ volatile u16 *gpio_par_feci2c;
+
+ gpio_par_feci2c = (volatile u16 *)(MCF_IPSBAR + 0x100082);
+ /* Set up gpio outputs for FEC0 MII lines */
+ gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100078);
+
+ *gpio_par_feci2c |= 0x0f00;
+ *gpio_par_fec |= 0xc0;
+
+#if defined(CONFIG_FEC2)
+ /* Set up gpio outputs for FEC1 MII lines */
+ gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100079);
+
+ *gpio_par_feci2c |= 0x00a0;
+ *gpio_par_fec |= 0xc0;
+#endif /* CONFIG_FEC2 */
+ }
+#endif /* CONFIG_M527x */
}
static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
@@ -1940,9 +1962,10 @@ static void mii_display_status(struct net_device *dev)
printk(".\n");
}
-static void mii_display_config(struct net_device *dev)
+static void mii_display_config(struct work_struct *work)
{
- struct fec_enet_private *fep = netdev_priv(dev);
+ struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
+ struct net_device *dev = fep->netdev;
uint status = fep->phy_status;
/*
@@ -1976,9 +1999,10 @@ static void mii_display_config(struct net_device *dev)
fep->sequence_done = 1;
}
-static void mii_relink(struct net_device *dev)
+static void mii_relink(struct work_struct *work)
{
- struct fec_enet_private *fep = netdev_priv(dev);
+ struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
+ struct net_device *dev = fep->netdev;
int duplex;
/*
@@ -2022,7 +2046,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev)
return;
fep->mii_phy_task_queued = 1;
- INIT_WORK(&fep->phy_task, (void*)mii_relink, dev);
+ INIT_WORK(&fep->phy_task, mii_relink);
schedule_work(&fep->phy_task);
}
@@ -2035,7 +2059,7 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev)
return;
fep->mii_phy_task_queued = 1;
- INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev);
+ INIT_WORK(&fep->phy_task, mii_display_config);
schedule_work(&fep->phy_task);
}
@@ -2194,13 +2218,6 @@ fec_enet_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
-{
- struct fec_enet_private *fep = netdev_priv(dev);
-
- return &fep->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
* Skeleton taken from sunlance driver.
* The CPM Ethernet implementation allows Multicast as well as individual
@@ -2330,6 +2347,7 @@ int __init fec_enet_init(struct net_device *dev)
fep->index = index;
fep->hwp = fecp;
+ fep->netdev = dev;
/* Whack a reset. We should wait for this.
*/
@@ -2435,7 +2453,6 @@ int __init fec_enet_init(struct net_device *dev)
dev->tx_timeout = fec_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->stop = fec_enet_close;
- dev->get_stats = fec_enet_get_stats;
dev->set_multicast_list = set_multicast_list;
for (i=0; i<NMII-1; i++)
@@ -2618,6 +2635,7 @@ static int __init fec_enet_module_init(void)
{
struct net_device *dev;
int i, j, err;
+ DECLARE_MAC_BUF(mac);
printk("FEC ENET Version 0.2\n");
@@ -2636,10 +2654,8 @@ static int __init fec_enet_module_init(void)
return -EIO;
}
- printk("%s: ethernet ", dev->name);
- for (j = 0; (j < 5); j++)
- printk("%02x:", dev->dev_addr[j]);
- printk("%02x\n", dev->dev_addr[5]);
+ printk("%s: ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
return 0;
}
diff --git a/drivers/net/fec_8xx/fec_8xx.h b/drivers/net/fec_8xx/fec_8xx.h
index 5af60b0f9208..f3b1c6fbba8b 100644
--- a/drivers/net/fec_8xx/fec_8xx.h
+++ b/drivers/net/fec_8xx/fec_8xx.h
@@ -105,6 +105,8 @@ struct fec;
struct fec_enet_private {
spinlock_t lock; /* during all ops except TX pckt processing */
spinlock_t tx_lock; /* during fec_start_xmit and fec_tx */
+ struct net_device *dev;
+ struct napi_struct napi;
int fecno;
struct fec *fecp;
const struct fec_platform_info *fpi;
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index e5502af5b8e2..8d2904fa5789 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -465,9 +465,9 @@ void fec_stop(struct net_device *dev)
}
/* common receive function */
-static int fec_enet_rx_common(struct net_device *dev, int *budget)
+static int fec_enet_rx_common(struct fec_enet_private *ep,
+ struct net_device *dev, int budget)
{
- struct fec_enet_private *fep = netdev_priv(dev);
fec_t *fecp = fep->fecp;
const struct fec_platform_info *fpi = fep->fpi;
cbd_t *bdp;
@@ -475,11 +475,8 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget)
int received = 0;
__u16 pkt_len, sc;
int curidx;
- int rx_work_limit;
if (fpi->use_napi) {
- rx_work_limit = min(dev->quota, *budget);
-
if (!netif_running(dev))
return 0;
}
@@ -530,11 +527,6 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget)
BUG_ON(skbn == NULL);
} else {
-
- /* napi, got packet but no quota */
- if (fpi->use_napi && --rx_work_limit < 0)
- break;
-
skb = fep->rx_skbuff[curidx];
BUG_ON(skb == NULL);
@@ -599,25 +591,24 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget)
* able to keep up at the expense of system resources.
*/
FW(fecp, r_des_active, 0x01000000);
+
+ if (received >= budget)
+ break;
+
}
fep->cur_rx = bdp;
if (fpi->use_napi) {
- dev->quota -= received;
- *budget -= received;
-
- if (rx_work_limit < 0)
- return 1; /* not done */
+ if (received < budget) {
+ netif_rx_complete(dev, &fep->napi);
- /* done */
- netif_rx_complete(dev);
-
- /* enable RX interrupt bits */
- FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
+ /* enable RX interrupt bits */
+ FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
+ }
}
- return 0;
+ return received;
}
static void fec_enet_tx(struct net_device *dev)
@@ -743,12 +734,12 @@ fec_enet_interrupt(int irq, void *dev_id)
if ((int_events & FEC_ENET_RXF) != 0) {
if (!fpi->use_napi)
- fec_enet_rx_common(dev, NULL);
+ fec_enet_rx_common(fep, dev, ~0);
else {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &fep->napi)) {
/* disable rx interrupts */
FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &fep->napi);
} else {
printk(KERN_ERR DRV_MODULE_NAME
": %s driver bug! interrupt while in poll!\n",
@@ -893,10 +884,13 @@ static int fec_enet_open(struct net_device *dev)
const struct fec_platform_info *fpi = fep->fpi;
unsigned long flags;
+ napi_enable(&fep->napi);
+
/* Install our interrupt handler. */
if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 0) {
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate FEC IRQ!", dev->name);
+ napi_disable(&fep->napi);
return -EINVAL;
}
@@ -907,6 +901,7 @@ static int fec_enet_open(struct net_device *dev)
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate PHY IRQ!", dev->name);
free_irq(fpi->fec_irq, dev);
+ napi_disable(&fep->napi);
return -EINVAL;
}
@@ -932,6 +927,7 @@ static int fec_enet_close(struct net_device *dev)
unsigned long flags;
netif_stop_queue(dev);
+ napi_disable(&fep->napi);
netif_carrier_off(dev);
if (fpi->use_mdio)
@@ -955,9 +951,12 @@ static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
return &fep->stats;
}
-static int fec_enet_poll(struct net_device *dev, int *budget)
+static int fec_enet_poll(struct napi_struct *napi, int budget)
{
- return fec_enet_rx_common(dev, budget);
+ struct fec_enet_private *fep = container_of(napi, struct fec_enet_private, napi);
+ struct net_device *dev = fep->dev;
+
+ return fec_enet_rx_common(fep, dev, budget);
}
/*************************************************************************/
@@ -1042,9 +1041,7 @@ static const struct ethtool_ops fec_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = fec_get_msglevel,
.set_msglevel = fec_set_msglevel,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_regs = fec_get_regs,
};
@@ -1104,9 +1101,9 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi,
err = -ENOMEM;
goto err;
}
- SET_MODULE_OWNER(dev);
fep = netdev_priv(dev);
+ fep->dev = dev;
/* partial reset of FEC */
fec_whack_reset(fecp);
@@ -1172,10 +1169,9 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi,
dev->get_stats = fec_enet_get_stats;
dev->set_multicast_list = fec_set_multicast_list;
dev->set_mac_address = fec_set_mac_address;
- if (fpi->use_napi) {
- dev->poll = fec_enet_poll;
- dev->weight = fpi->napi_weight;
- }
+ netif_napi_add(dev, &fec->napi,
+ fec_enet_poll, fpi->napi_weight);
+
dev->ethtool_ops = &fec_ethtool_ops;
dev->do_ioctl = fec_ioctl;
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index b3fa0d6a159c..e8e10a02d202 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -308,12 +308,11 @@ int fec_mii_phy_id_detect(struct net_device *dev)
return -1;
}
- for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
- i++, phy++)
+ for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
if (phy->id == (phy_hwid >> 4) || phy->id == 0)
break;
- if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {
+ if (i >= ARRAY_SIZE(phy_info)) {
printk(KERN_ERR DRV_MODULE_NAME
": %s PHY id 0x%08x is not supported!\n",
dev->name, phy_hwid);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 136827f8dc2e..dae30b731342 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -159,6 +159,8 @@
#define dprintk(x...) do { } while (0)
#endif
+#define TX_WORK_PER_LOOP 64
+#define RX_WORK_PER_LOOP 64
/*
* Hardware access:
@@ -178,6 +180,7 @@
#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */
#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */
#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */
+#define DEV_HAS_CORRECT_MACADDR 0x4000 /* device supports correct mac address order */
enum {
NvRegIrqStatus = 0x000,
@@ -551,7 +554,7 @@ union ring_type {
#define PHY_OUI_MARVELL 0x5043
#define PHY_OUI_CICADA 0x03f1
#define PHY_OUI_VITESSE 0x01c1
-#define PHY_OUI_REALTEK 0x01c1
+#define PHY_OUI_REALTEK 0x0732
#define PHYID1_OUI_MASK 0x03ff
#define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00
@@ -744,6 +747,9 @@ struct nv_skb_map {
struct fe_priv {
spinlock_t lock;
+ struct net_device *dev;
+ struct napi_struct napi;
+
/* General data:
* Locking: spin_lock(&np->lock); */
struct net_device_stats stats;
@@ -1585,9 +1591,10 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
/* Just reschedule NAPI rx processing */
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
}
#else
static void nv_do_rx_refill(unsigned long data)
@@ -2996,7 +3003,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
/* Disable furthur receive irq's */
spin_lock(&np->lock);
@@ -3009,7 +3016,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- if (nv_rx_process(dev, dev->weight)) {
+ if (nv_rx_process(dev, RX_WORK_PER_LOOP)) {
if (unlikely(nv_alloc_rx(dev))) {
spin_lock(&np->lock);
if (!np->in_shutdown)
@@ -3067,8 +3074,8 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
np->nic_poll_irq = np->irqmask;
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
spin_unlock(&np->lock);
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
break;
}
@@ -3078,8 +3085,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
return IRQ_RETVAL(i);
}
-#define TX_WORK_PER_LOOP 64
-#define RX_WORK_PER_LOOP 64
/**
* All _optimized functions are used to help increase performance
* (reduce CPU and increase throughput). They use descripter version 3,
@@ -3113,7 +3118,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
/* Disable furthur receive irq's */
spin_lock(&np->lock);
@@ -3126,7 +3131,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
if (unlikely(nv_alloc_rx_optimized(dev))) {
spin_lock(&np->lock);
if (!np->in_shutdown)
@@ -3185,8 +3190,8 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
np->nic_poll_irq = np->irqmask;
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
spin_unlock(&np->lock);
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
break;
}
@@ -3232,8 +3237,8 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
np->nic_poll_irq |= NVREG_IRQ_TX_ALL;
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
spin_unlock_irqrestore(&np->lock, flags);
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
break;
}
@@ -3244,19 +3249,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
}
#ifdef CONFIG_FORCEDETH_NAPI
-static int nv_napi_poll(struct net_device *dev, int *budget)
+static int nv_napi_poll(struct napi_struct *napi, int budget)
{
- int pkts, limit = min(*budget, dev->quota);
- struct fe_priv *np = netdev_priv(dev);
+ struct fe_priv *np = container_of(napi, struct fe_priv, napi);
+ struct net_device *dev = np->dev;
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
- int retcode;
+ int pkts, retcode;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- pkts = nv_rx_process(dev, limit);
+ pkts = nv_rx_process(dev, budget);
retcode = nv_alloc_rx(dev);
} else {
- pkts = nv_rx_process_optimized(dev, limit);
+ pkts = nv_rx_process_optimized(dev, budget);
retcode = nv_alloc_rx_optimized(dev);
}
@@ -3267,13 +3272,12 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
spin_unlock_irqrestore(&np->lock, flags);
}
- if (pkts < limit) {
- /* all done, no more packets present */
- netif_rx_complete(dev);
-
+ if (pkts < budget) {
/* re-enable receive interrupts */
spin_lock_irqsave(&np->lock, flags);
+ __netif_rx_complete(dev, napi);
+
np->irqmask |= NVREG_IRQ_RX_ALL;
if (np->msi_flags & NV_MSI_X_ENABLED)
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -3281,13 +3285,8 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
writel(np->irqmask, base + NvRegIrqMask);
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
- } else {
- /* used up our quantum, so reschedule */
- dev->quota -= pkts;
- *budget -= pkts;
- return 1;
}
+ return pkts;
}
#endif
@@ -3295,6 +3294,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
static irqreturn_t nv_nic_irq_rx(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
@@ -3302,7 +3302,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
if (events) {
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
/* disable receive interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
pci_push(base);
@@ -3328,7 +3328,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
if (!(events & np->irqmask))
break;
- if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
if (unlikely(nv_alloc_rx_optimized(dev))) {
spin_lock_irqsave(&np->lock, flags);
if (!np->in_shutdown)
@@ -3347,8 +3347,8 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
np->nic_poll_irq |= NVREG_IRQ_RX_ALL;
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
spin_unlock_irqrestore(&np->lock, flags);
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
break;
}
}
@@ -3420,8 +3420,8 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
np->nic_poll_irq |= NVREG_IRQ_OTHER;
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
- printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
spin_unlock_irqrestore(&np->lock, flags);
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
break;
}
@@ -4333,16 +4333,26 @@ static int nv_set_sg(struct net_device *dev, u32 data)
return -EOPNOTSUPP;
}
-static int nv_get_stats_count(struct net_device *dev)
+static int nv_get_sset_count(struct net_device *dev, int sset)
{
struct fe_priv *np = netdev_priv(dev);
- if (np->driver_data & DEV_HAS_STATISTICS_V1)
- return NV_DEV_STATISTICS_V1_COUNT;
- else if (np->driver_data & DEV_HAS_STATISTICS_V2)
- return NV_DEV_STATISTICS_V2_COUNT;
- else
- return 0;
+ switch (sset) {
+ case ETH_SS_TEST:
+ if (np->driver_data & DEV_HAS_TEST_EXTENDED)
+ return NV_TEST_COUNT_EXTENDED;
+ else
+ return NV_TEST_COUNT_BASE;
+ case ETH_SS_STATS:
+ if (np->driver_data & DEV_HAS_STATISTICS_V1)
+ return NV_DEV_STATISTICS_V1_COUNT;
+ else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+ return NV_DEV_STATISTICS_V2_COUNT;
+ else
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer)
@@ -4352,17 +4362,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e
/* update stats */
nv_do_stats_poll((unsigned long)dev);
- memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64));
-}
-
-static int nv_self_test_count(struct net_device *dev)
-{
- struct fe_priv *np = netdev_priv(dev);
-
- if (np->driver_data & DEV_HAS_TEST_EXTENDED)
- return NV_TEST_COUNT_EXTENDED;
- else
- return NV_TEST_COUNT_BASE;
+ memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
}
static int nv_link_test(struct net_device *dev)
@@ -4609,7 +4609,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int result;
- memset(buffer, 0, nv_self_test_count(dev)*sizeof(u64));
+ memset(buffer, 0, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(u64));
if (!nv_link_test(dev)) {
test->flags |= ETH_TEST_FL_FAILED;
@@ -4619,7 +4619,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (netif_running(dev)) {
netif_stop_queue(dev);
- netif_poll_disable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_disable(&np->napi);
+#endif
netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
@@ -4678,7 +4680,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_enable(&np->napi);
+#endif
nv_enable_hw_interrupts(dev, np->irqmask);
}
}
@@ -4688,10 +4692,10 @@ static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer)
{
switch (stringset) {
case ETH_SS_STATS:
- memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str));
+ memcpy(buffer, &nv_estats_str, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(struct nv_ethtool_str));
break;
case ETH_SS_TEST:
- memcpy(buffer, &nv_etests_str, nv_self_test_count(dev)*sizeof(struct nv_ethtool_str));
+ memcpy(buffer, &nv_etests_str, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(struct nv_ethtool_str));
break;
}
}
@@ -4706,8 +4710,6 @@ static const struct ethtool_ops ops = {
.get_regs_len = nv_get_regs_len,
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
- .get_perm_addr = ethtool_op_get_perm_addr,
- .get_tso = ethtool_op_get_tso,
.set_tso = nv_set_tso,
.get_ringparam = nv_get_ringparam,
.set_ringparam = nv_set_ringparam,
@@ -4715,14 +4717,11 @@ static const struct ethtool_ops ops = {
.set_pauseparam = nv_set_pauseparam,
.get_rx_csum = nv_get_rx_csum,
.set_rx_csum = nv_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = nv_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = nv_set_sg,
.get_strings = nv_get_strings,
- .get_stats_count = nv_get_stats_count,
.get_ethtool_stats = nv_get_ethtool_stats,
- .self_test_count = nv_self_test_count,
+ .get_sset_count = nv_get_sset_count,
.self_test = nv_self_test,
};
@@ -4911,12 +4910,14 @@ static int nv_open(struct net_device *dev)
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_enable(&np->napi);
+#endif
if (ret) {
netif_carrier_on(dev);
} else {
- printk("%s: no link during initialization.\n", dev->name);
+ printk(KERN_INFO "%s: no link during initialization.\n", dev->name);
netif_carrier_off(dev);
}
if (oom)
@@ -4942,7 +4943,9 @@ static int nv_close(struct net_device *dev)
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
spin_unlock_irq(&np->lock);
- netif_poll_disable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_disable(&np->napi);
+#endif
synchronize_irq(dev->irq);
del_timer_sync(&np->oom_kick);
@@ -4987,6 +4990,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
u32 powerstate, txreg;
u32 phystate_orig = 0, phystate;
int phyinitialized = 0;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -4994,9 +4998,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out;
np = netdev_priv(dev);
+ np->dev = dev;
np->pci_dev = pci_dev;
spin_lock_init(&np->lock);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pci_dev->dev);
init_timer(&np->oom_kick);
@@ -5137,12 +5141,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_unmap;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
- np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+ np->rx_skb = kcalloc(np->rx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
+ np->tx_skb = kcalloc(np->tx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
if (!np->rx_skb || !np->tx_skb)
goto out_freering;
- memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
- memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
dev->open = nv_open;
dev->stop = nv_close;
@@ -5157,9 +5159,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
- dev->weight = RX_WORK_PER_LOOP;
#ifdef CONFIG_FORCEDETH_NAPI
- dev->poll = nv_napi_poll;
+ netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
#endif
SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
@@ -5174,7 +5175,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
/* check the workaround bit for correct mac address order */
txreg = readl(base + NvRegTransmitPoll);
- if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+ if ((txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) ||
+ (id->driver_data & DEV_HAS_CORRECT_MACADDR)) {
/* mac address is already in correct order */
dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
@@ -5203,10 +5205,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
* Bad mac address. At least one bios sets the mac address
* to 01:23:45:67:89:ab
*/
- printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n",
- pci_name(pci_dev),
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_ERR "%s: Invalid Mac address detected: %s\n",
+ pci_name(pci_dev), print_mac(mac, dev->dev_addr));
printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n");
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x00;
@@ -5214,9 +5214,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
get_random_bytes(&dev->dev_addr[3], 3);
}
- dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev),
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ dprintk(KERN_DEBUG "%s: MAC Address %s\n",
+ pci_name(pci_dev), print_mac(mac, dev->dev_addr));
/* set mac address */
nv_copy_mac_to_hw(dev);
@@ -5502,51 +5501,67 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ },
+ { /* MCP73 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ },
+ { /* MCP73 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ },
+ { /* MCP73 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+ },
+ { /* MCP73 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{0,},
};
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index e27ee210b605..2765e49e07df 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -11,6 +11,7 @@ config FS_ENET_HAS_SCC
config FS_ENET_HAS_FCC
bool "Chip has an FCC usable for ethernet"
depends on FS_ENET && CPM2
+ select MDIO_BITBANG
default y
config FS_ENET_HAS_FEC
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a4a2a0ea43d3..04c6faec88d2 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1,17 +1,17 @@
/*
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
* and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -39,28 +39,35 @@
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
-
-#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
+#endif
MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
MODULE_DESCRIPTION("Freescale Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
-int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
+static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
module_param(fs_enet_debug, int, 0);
MODULE_PARM_DESC(fs_enet_debug,
"Freescale bitmapped debugging message enable value");
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void fs_enet_netpoll(struct net_device *dev);
+#endif
static void fs_set_multicast_list(struct net_device *dev)
{
@@ -69,19 +76,25 @@ static void fs_set_multicast_list(struct net_device *dev)
(*fep->ops->set_multicast_list)(dev);
}
+static void skb_align(struct sk_buff *skb, int align)
+{
+ int off = ((unsigned long)skb->data) & (align - 1);
+
+ if (off)
+ skb_reserve(skb, align - off);
+}
+
/* NAPI receive function */
-static int fs_enet_rx_napi(struct net_device *dev, int *budget)
+static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
{
- struct fs_enet_private *fep = netdev_priv(dev);
+ struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi);
+ struct net_device *dev = to_net_dev(fep->dev);
const struct fs_platform_info *fpi = fep->fpi;
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb, *skbn, *skbt;
int received = 0;
u16 pkt_len, sc;
int curidx;
- int rx_work_limit = 0; /* pacify gcc */
-
- rx_work_limit = min(dev->quota, *budget);
if (!netif_running(dev))
return 0;
@@ -96,7 +109,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
(*fep->ops->napi_clear_rx_event)(dev);
while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {
-
curidx = bdp - fep->rx_bd_base;
/*
@@ -109,7 +121,7 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
dev->name);
/*
- * Check for errors.
+ * Check for errors.
*/
if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -136,11 +148,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
skbn = skb;
} else {
-
- /* napi, got packet but no quota */
- if (--rx_work_limit < 0)
- break;
-
skb = fep->rx_skbuff[curidx];
dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp),
@@ -166,9 +173,13 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
skb = skbn;
skbn = skbt;
}
- } else
+ } else {
skbn = dev_alloc_skb(ENET_RX_FRSIZE);
+ if (skbn)
+ skb_align(skbn, ENET_RX_ALIGN);
+ }
+
if (skbn != NULL) {
skb_put(skb, pkt_len); /* Make room */
skb->protocol = eth_type_trans(skb, dev);
@@ -191,7 +202,7 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
/*
- * Update BD pointer to next entry.
+ * Update BD pointer to next entry.
*/
if ((sc & BD_ENET_RX_WRAP) == 0)
bdp++;
@@ -199,22 +210,19 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
bdp = fep->rx_bd_base;
(*fep->ops->rx_bd_done)(dev);
+
+ if (received >= budget)
+ break;
}
fep->cur_rx = bdp;
- dev->quota -= received;
- *budget -= received;
-
- if (rx_work_limit < 0)
- return 1; /* not done */
-
- /* done */
- netif_rx_complete(dev);
-
- (*fep->ops->napi_enable_rx)(dev);
-
- return 0;
+ if (received >= budget) {
+ /* done */
+ netif_rx_complete(dev, napi);
+ (*fep->ops->napi_enable_rx)(dev);
+ }
+ return received;
}
/* non NAPI receive function */
@@ -222,7 +230,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb, *skbn, *skbt;
int received = 0;
u16 pkt_len, sc;
@@ -247,7 +255,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
dev->name);
/*
- * Check for errors.
+ * Check for errors.
*/
if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -300,9 +308,13 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
skb = skbn;
skbn = skbt;
}
- } else
+ } else {
skbn = dev_alloc_skb(ENET_RX_FRSIZE);
+ if (skbn)
+ skb_align(skbn, ENET_RX_ALIGN);
+ }
+
if (skbn != NULL) {
skb_put(skb, pkt_len); /* Make room */
skb->protocol = eth_type_trans(skb, dev);
@@ -325,7 +337,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
/*
- * Update BD pointer to next entry.
+ * Update BD pointer to next entry.
*/
if ((sc & BD_ENET_RX_WRAP) == 0)
bdp++;
@@ -343,17 +355,16 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
static void fs_enet_tx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb;
int dirtyidx, do_wake, do_restart;
u16 sc;
- spin_lock(&fep->lock);
+ spin_lock(&fep->tx_lock);
bdp = fep->dirty_tx;
do_wake = do_restart = 0;
while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) {
-
dirtyidx = bdp - fep->tx_bd_base;
if (fep->tx_free == fep->tx_ring)
@@ -362,7 +373,7 @@ static void fs_enet_tx(struct net_device *dev)
skb = fep->tx_skbuff[dirtyidx];
/*
- * Check for errors.
+ * Check for errors.
*/
if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) {
@@ -402,13 +413,13 @@ static void fs_enet_tx(struct net_device *dev)
skb->len, DMA_TO_DEVICE);
/*
- * Free the sk buffer associated with this last transmit.
+ * Free the sk buffer associated with this last transmit.
*/
dev_kfree_skb_irq(skb);
fep->tx_skbuff[dirtyidx] = NULL;
/*
- * Update pointer to next buffer descriptor to be transmitted.
+ * Update pointer to next buffer descriptor to be transmitted.
*/
if ((sc & BD_ENET_TX_WRAP) == 0)
bdp++;
@@ -428,7 +439,7 @@ static void fs_enet_tx(struct net_device *dev)
if (do_restart)
(*fep->ops->tx_restart)(dev);
- spin_unlock(&fep->lock);
+ spin_unlock(&fep->tx_lock);
if (do_wake)
netif_wake_queue(dev);
@@ -454,7 +465,6 @@ fs_enet_interrupt(int irq, void *dev_id)
nr = 0;
while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) {
-
nr++;
int_clr_events = int_events;
@@ -470,7 +480,7 @@ fs_enet_interrupt(int irq, void *dev_id)
if (!fpi->use_napi)
fs_enet_rx_non_napi(dev);
else {
- napi_ok = netif_rx_schedule_prep(dev);
+ napi_ok = napi_schedule_prep(&fep->napi);
(*fep->ops->napi_disable_rx)(dev);
(*fep->ops->clear_int_events)(dev, fep->ev_napi_rx);
@@ -478,7 +488,7 @@ fs_enet_interrupt(int irq, void *dev_id)
/* NOTE: it is possible for FCCs in NAPI mode */
/* to submit a spurious interrupt while in poll */
if (napi_ok)
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &fep->napi);
}
}
@@ -493,7 +503,7 @@ fs_enet_interrupt(int irq, void *dev_id)
void fs_init_bds(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb;
int i;
@@ -504,7 +514,7 @@ void fs_init_bds(struct net_device *dev)
fep->cur_rx = fep->rx_bd_base;
/*
- * Initialize the receive buffer descriptors.
+ * Initialize the receive buffer descriptors.
*/
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
skb = dev_alloc_skb(ENET_RX_FRSIZE);
@@ -514,6 +524,7 @@ void fs_init_bds(struct net_device *dev)
dev->name);
break;
}
+ skb_align(skb, ENET_RX_ALIGN);
fep->rx_skbuff[i] = skb;
CBDW_BUFADDR(bdp,
dma_map_single(fep->dev, skb->data,
@@ -524,7 +535,7 @@ void fs_init_bds(struct net_device *dev)
((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP));
}
/*
- * if we failed, fillup remainder
+ * if we failed, fillup remainder
*/
for (; i < fep->rx_ring; i++, bdp++) {
fep->rx_skbuff[i] = NULL;
@@ -532,7 +543,7 @@ void fs_init_bds(struct net_device *dev)
}
/*
- * ...and the same for transmit.
+ * ...and the same for transmit.
*/
for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
fep->tx_skbuff[i] = NULL;
@@ -546,11 +557,11 @@ void fs_cleanup_bds(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
struct sk_buff *skb;
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
int i;
/*
- * Reset SKB transmit buffers.
+ * Reset SKB transmit buffers.
*/
for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
if ((skb = fep->tx_skbuff[i]) == NULL)
@@ -565,7 +576,7 @@ void fs_cleanup_bds(struct net_device *dev)
}
/*
- * Reset SKB receive buffers
+ * Reset SKB receive buffers
*/
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
if ((skb = fep->rx_skbuff[i]) == NULL)
@@ -587,7 +598,7 @@ void fs_cleanup_bds(struct net_device *dev)
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
int curidx;
u16 sc;
unsigned long flags;
@@ -595,7 +606,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&fep->tx_lock, flags);
/*
- * Fill in a Tx ring entry
+ * Fill in a Tx ring entry
*/
bdp = fep->cur_tx;
@@ -614,19 +625,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
curidx = bdp - fep->tx_bd_base;
/*
- * Clear all of the status flags.
+ * Clear all of the status flags.
*/
CBDC_SC(bdp, BD_ENET_TX_STATS);
/*
- * Save skb pointer.
+ * Save skb pointer.
*/
fep->tx_skbuff[curidx] = skb;
fep->stats.tx_bytes += skb->len;
/*
- * Push the data cache so the CPM does not get stale memory data.
+ * Push the data cache so the CPM does not get stale memory data.
*/
CBDW_BUFADDR(bdp, dma_map_single(fep->dev,
skb->data, skb->len, DMA_TO_DEVICE));
@@ -635,7 +646,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
/*
- * If this was the last BD in the ring, start at the beginning again.
+ * If this was the last BD in the ring, start at the beginning again.
*/
if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
fep->cur_tx++;
@@ -710,45 +721,43 @@ static void fs_timeout(struct net_device *dev)
*-----------------------------------------------------------------------------*/
static void generic_adjust_link(struct net_device *dev)
{
- struct fs_enet_private *fep = netdev_priv(dev);
- struct phy_device *phydev = fep->phydev;
- int new_state = 0;
-
- if (phydev->link) {
-
- /* adjust to duplex mode */
- if (phydev->duplex != fep->oldduplex){
- new_state = 1;
- fep->oldduplex = phydev->duplex;
- }
-
- if (phydev->speed != fep->oldspeed) {
- new_state = 1;
- fep->oldspeed = phydev->speed;
- }
-
- if (!fep->oldlink) {
- new_state = 1;
- fep->oldlink = 1;
- netif_schedule(dev);
- netif_carrier_on(dev);
- netif_start_queue(dev);
- }
-
- if (new_state)
- fep->ops->restart(dev);
-
- } else if (fep->oldlink) {
- new_state = 1;
- fep->oldlink = 0;
- fep->oldspeed = 0;
- fep->oldduplex = -1;
- netif_carrier_off(dev);
- netif_stop_queue(dev);
- }
-
- if (new_state && netif_msg_link(fep))
- phy_print_status(phydev);
+ struct fs_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev = fep->phydev;
+ int new_state = 0;
+
+ if (phydev->link) {
+ /* adjust to duplex mode */
+ if (phydev->duplex != fep->oldduplex) {
+ new_state = 1;
+ fep->oldduplex = phydev->duplex;
+ }
+
+ if (phydev->speed != fep->oldspeed) {
+ new_state = 1;
+ fep->oldspeed = phydev->speed;
+ }
+
+ if (!fep->oldlink) {
+ new_state = 1;
+ fep->oldlink = 1;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ if (new_state)
+ fep->ops->restart(dev);
+ } else if (fep->oldlink) {
+ new_state = 1;
+ fep->oldlink = 0;
+ fep->oldspeed = 0;
+ fep->oldduplex = -1;
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ }
+
+ if (new_state && netif_msg_link(fep))
+ phy_print_status(phydev);
}
@@ -792,25 +801,28 @@ static int fs_init_phy(struct net_device *dev)
return 0;
}
-
static int fs_enet_open(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
int r;
int err;
+ napi_enable(&fep->napi);
+
/* Install our interrupt handler. */
r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate FS_ENET IRQ!", dev->name);
+ napi_disable(&fep->napi);
return -EINVAL;
}
err = fs_init_phy(dev);
- if(err)
+ if(err) {
+ napi_disable(&fep->napi);
return err;
-
+ }
phy_start(fep->phydev);
return 0;
@@ -823,10 +835,13 @@ static int fs_enet_close(struct net_device *dev)
netif_stop_queue(dev);
netif_carrier_off(dev);
+ napi_disable(&fep->napi);
phy_stop(fep->phydev);
spin_lock_irqsave(&fep->lock, flags);
+ spin_lock(&fep->tx_lock);
(*fep->ops->stop)(dev);
+ spin_unlock(&fep->tx_lock);
spin_unlock_irqrestore(&fep->lock, flags);
/* release any irqs */
@@ -915,9 +930,7 @@ static const struct ethtool_ops fs_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = fs_get_msglevel,
.set_msglevel = fs_set_msglevel,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_regs = fs_get_regs,
};
@@ -941,6 +954,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
extern int fs_mii_connect(struct net_device *dev);
extern void fs_mii_disconnect(struct net_device *dev);
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static struct net_device *fs_init_instance(struct device *dev,
struct fs_platform_info *fpi)
{
@@ -961,10 +975,8 @@ static struct net_device *fs_init_instance(struct device *dev,
err = -ENOMEM;
goto err;
}
- SET_MODULE_OWNER(ndev);
fep = netdev_priv(ndev);
- memset(fep, 0, privsize); /* clear everything */
fep->dev = dev;
dev_set_drvdata(dev, ndev);
@@ -978,7 +990,7 @@ static struct net_device *fs_init_instance(struct device *dev,
#endif
#ifdef CONFIG_FS_ENET_HAS_SCC
- if (fs_get_scc_index(fpi->fs_no) >=0 )
+ if (fs_get_scc_index(fpi->fs_no) >=0)
fep->ops = &fs_scc_ops;
#endif
@@ -1013,13 +1025,13 @@ static struct net_device *fs_init_instance(struct device *dev,
spin_lock_init(&fep->tx_lock);
/*
- * Set the Ethernet address.
+ * Set the Ethernet address.
*/
for (i = 0; i < 6; i++)
ndev->dev_addr[i] = fpi->macaddr[i];
-
+
r = (*fep->ops->allocate_bd)(ndev);
-
+
if (fep->ring_base == NULL) {
printk(KERN_ERR DRV_MODULE_NAME
": %s buffer descriptor alloc failed (%d).\n", ndev->name, r);
@@ -1038,7 +1050,7 @@ static struct net_device *fs_init_instance(struct device *dev,
fep->rx_ring = fpi->rx_ring;
/*
- * The FEC Ethernet specific entries in the device structure.
+ * The FEC Ethernet specific entries in the device structure.
*/
ndev->open = fs_enet_open;
ndev->hard_start_xmit = fs_enet_start_xmit;
@@ -1047,10 +1059,14 @@ static struct net_device *fs_init_instance(struct device *dev,
ndev->stop = fs_enet_close;
ndev->get_stats = fs_enet_get_stats;
ndev->set_multicast_list = fs_set_multicast_list;
- if (fpi->use_napi) {
- ndev->poll = fs_enet_rx_napi;
- ndev->weight = fpi->napi_weight;
- }
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ ndev->poll_controller = fs_enet_netpoll;
+#endif
+
+ netif_napi_add(ndev, &fep->napi,
+ fs_enet_rx_napi, fpi->napi_weight);
+
ndev->ethtool_ops = &fs_ethtool_ops;
ndev->do_ioctl = fs_ioctl;
@@ -1069,9 +1085,8 @@ static struct net_device *fs_init_instance(struct device *dev,
return ndev;
- err:
+err:
if (ndev != NULL) {
-
if (registered)
unregister_netdev(ndev);
@@ -1106,7 +1121,7 @@ static int fs_cleanup_instance(struct net_device *ndev)
unregister_netdev(ndev);
dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
- fep->ring_base, fep->ring_mem_addr);
+ (void __force *)fep->ring_base, fep->ring_mem_addr);
/* reset it */
(*fep->ops->cleanup_data)(ndev);
@@ -1121,43 +1136,259 @@ static int fs_cleanup_instance(struct net_device *ndev)
return 0;
}
+#endif
/**************************************************************************************/
/* handy pointer to the immap */
-void *fs_enet_immap = NULL;
+void __iomem *fs_enet_immap = NULL;
static int setup_immap(void)
{
- phys_addr_t paddr = 0;
- unsigned long size = 0;
-
#ifdef CONFIG_CPM1
- paddr = IMAP_ADDR;
- size = 0x10000; /* map 64K */
+ fs_enet_immap = ioremap(IMAP_ADDR, 0x4000);
+ WARN_ON(!fs_enet_immap);
+#elif defined(CONFIG_CPM2)
+ fs_enet_immap = cpm2_immr;
#endif
-#ifdef CONFIG_CPM2
- paddr = CPM_MAP_ADDR;
- size = 0x40000; /* map 256 K */
-#endif
- fs_enet_immap = ioremap(paddr, size);
- if (fs_enet_immap == NULL)
- return -EBADF; /* XXX ahem; maybe just BUG_ON? */
-
return 0;
}
static void cleanup_immap(void)
{
- if (fs_enet_immap != NULL) {
- iounmap(fs_enet_immap);
- fs_enet_immap = NULL;
- }
+#if defined(CONFIG_CPM1)
+ iounmap(fs_enet_immap);
+#endif
}
/**************************************************************************************/
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit find_phy(struct device_node *np,
+ struct fs_platform_info *fpi)
+{
+ struct device_node *phynode, *mdionode;
+ struct resource res;
+ int ret = 0, len;
+
+ const u32 *data = of_get_property(np, "phy-handle", &len);
+ if (!data || len != 4)
+ return -EINVAL;
+
+ phynode = of_find_node_by_phandle(*data);
+ if (!phynode)
+ return -EINVAL;
+
+ mdionode = of_get_parent(phynode);
+ if (!mdionode)
+ goto out_put_phy;
+
+ ret = of_address_to_resource(mdionode, 0, &res);
+ if (ret)
+ goto out_put_mdio;
+
+ data = of_get_property(phynode, "reg", &len);
+ if (!data || len != 4)
+ goto out_put_mdio;
+
+ snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data);
+
+out_put_mdio:
+ of_node_put(mdionode);
+out_put_phy:
+ of_node_put(phynode);
+ return ret;
+}
+
+#ifdef CONFIG_FS_ENET_HAS_FEC
+#define IS_FEC(match) ((match)->data == &fs_fec_ops)
+#else
+#define IS_FEC(match) 0
+#endif
+
+static int __devinit fs_enet_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct net_device *ndev;
+ struct fs_enet_private *fep;
+ struct fs_platform_info *fpi;
+ const u32 *data;
+ const u8 *mac_addr;
+ int privsize, len, ret = -ENODEV;
+
+ fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
+ if (!fpi)
+ return -ENOMEM;
+
+ if (!IS_FEC(match)) {
+ data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+ if (!data || len != 4)
+ goto out_free_fpi;
+
+ fpi->cp_command = *data;
+ }
+
+ fpi->rx_ring = 32;
+ fpi->tx_ring = 32;
+ fpi->rx_copybreak = 240;
+ fpi->use_napi = 0;
+ fpi->napi_weight = 17;
+
+ ret = find_phy(ofdev->node, fpi);
+ if (ret)
+ goto out_free_fpi;
+
+ privsize = sizeof(*fep) +
+ sizeof(struct sk_buff **) *
+ (fpi->rx_ring + fpi->tx_ring);
+
+ ndev = alloc_etherdev(privsize);
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto out_free_fpi;
+ }
+
+ SET_MODULE_OWNER(ndev);
+ dev_set_drvdata(&ofdev->dev, ndev);
+
+ fep = netdev_priv(ndev);
+ fep->dev = &ofdev->dev;
+ fep->fpi = fpi;
+ fep->ops = match->data;
+
+ ret = fep->ops->setup_data(ndev);
+ if (ret)
+ goto out_free_dev;
+
+ fep->rx_skbuff = (struct sk_buff **)&fep[1];
+ fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+
+ spin_lock_init(&fep->lock);
+ spin_lock_init(&fep->tx_lock);
+
+ mac_addr = of_get_mac_address(ofdev->node);
+ if (mac_addr)
+ memcpy(ndev->dev_addr, mac_addr, 6);
+
+ ret = fep->ops->allocate_bd(ndev);
+ if (ret)
+ goto out_cleanup_data;
+
+ fep->rx_bd_base = fep->ring_base;
+ fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;
+
+ fep->tx_ring = fpi->tx_ring;
+ fep->rx_ring = fpi->rx_ring;
+
+ ndev->open = fs_enet_open;
+ ndev->hard_start_xmit = fs_enet_start_xmit;
+ ndev->tx_timeout = fs_timeout;
+ ndev->watchdog_timeo = 2 * HZ;
+ ndev->stop = fs_enet_close;
+ ndev->get_stats = fs_enet_get_stats;
+ ndev->set_multicast_list = fs_set_multicast_list;
+ if (fpi->use_napi) {
+ ndev->poll = fs_enet_rx_napi;
+ ndev->weight = fpi->napi_weight;
+ }
+ ndev->ethtool_ops = &fs_ethtool_ops;
+ ndev->do_ioctl = fs_ioctl;
+
+ init_timer(&fep->phy_timer_list);
+
+ netif_carrier_off(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto out_free_bd;
+
+ printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ return 0;
+
+out_free_bd:
+ fep->ops->free_bd(ndev);
+out_cleanup_data:
+ fep->ops->cleanup_data(ndev);
+out_free_dev:
+ free_netdev(ndev);
+ dev_set_drvdata(&ofdev->dev, NULL);
+out_free_fpi:
+ kfree(fpi);
+ return ret;
+}
+
+static int fs_enet_remove(struct of_device *ofdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct fs_enet_private *fep = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ fep->ops->free_bd(ndev);
+ fep->ops->cleanup_data(ndev);
+ dev_set_drvdata(fep->dev, NULL);
+
+ free_netdev(ndev);
+ return 0;
+}
+
+static struct of_device_id fs_enet_match[] = {
+#ifdef CONFIG_FS_ENET_HAS_SCC
+ {
+ .compatible = "fsl,cpm1-scc-enet",
+ .data = (void *)&fs_scc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FCC
+ {
+ .compatible = "fsl,cpm2-fcc-enet",
+ .data = (void *)&fs_fcc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FEC
+ {
+ .compatible = "fsl,pq1-fec-enet",
+ .data = (void *)&fs_fec_ops,
+ },
+#endif
+ {}
+};
+
+static struct of_platform_driver fs_enet_driver = {
+ .name = "fs_enet",
+ .match_table = fs_enet_match,
+ .probe = fs_enet_probe,
+ .remove = fs_enet_remove,
+};
+
+static int __init fs_init(void)
+{
+ int r = setup_immap();
+ if (r != 0)
+ return r;
+
+ r = of_register_platform_driver(&fs_enet_driver);
+ if (r != 0)
+ goto out;
+
+ return 0;
+
+out:
+ cleanup_immap();
+ return r;
+}
+
+static void __exit fs_cleanup(void)
+{
+ of_unregister_platform_driver(&fs_enet_driver);
+ cleanup_immap();
+}
+#else
static int __devinit fs_enet_probe(struct device *dev)
{
struct net_device *ndev;
@@ -1262,7 +1493,6 @@ static int __init fs_init(void)
err:
cleanup_immap();
return r;
-
}
static void __exit fs_cleanup(void)
@@ -1272,6 +1502,16 @@ static void __exit fs_cleanup(void)
driver_unregister(&fs_enet_scc_driver);
cleanup_immap();
}
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void fs_enet_netpoll(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ fs_enet_interrupt(dev->irq, dev, NULL);
+ enable_irq(dev->irq);
+}
+#endif
/**************************************************************************************/
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 569be225cd05..baf6477165af 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -15,8 +15,8 @@
#include <asm/commproc.h>
struct fec_info {
- fec_t* fecp;
- u32 mii_speed;
+ fec_t __iomem *fecp;
+ u32 mii_speed;
};
#endif
@@ -24,19 +24,6 @@ struct fec_info {
#include <asm/cpm2.h>
#endif
-/* This is used to operate with pins.
- Note that the actual port size may
- be different; cpm(s) handle it OK */
-struct bb_info {
- u8 mdio_dat_msk;
- u8 mdio_dir_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dat;
- int delay;
-};
-
/* hw driver ops */
struct fs_ops {
int (*setup_data)(struct net_device *dev);
@@ -82,60 +69,26 @@ struct phy_info {
/* Must be a multiple of 32 (to cover both FEC & FCC) */
#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31)
/* This is needed so that invalidate_xxx wont invalidate too much */
-#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE)
-
-struct fs_enet_mii_bus {
- struct list_head list;
- spinlock_t mii_lock;
- const struct fs_mii_bus_info *bus_info;
- int refs;
- u32 usage_map;
-
- int (*mii_read)(struct fs_enet_mii_bus *bus,
- int phy_id, int location);
-
- void (*mii_write)(struct fs_enet_mii_bus *bus,
- int phy_id, int location, int value);
-
- union {
- struct {
- unsigned int mii_speed;
- void *fecp;
- } fec;
-
- struct {
- /* note that the actual port size may */
- /* be different; cpm(s) handle it OK */
- u8 mdio_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dir;
- u8 *mdc_dat;
- } bitbang;
-
- struct {
- u16 lpa;
- } fixed;
- };
-};
+#define ENET_RX_ALIGN 16
+#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)
struct fs_enet_private {
+ struct napi_struct napi;
struct device *dev; /* pointer back to the device (must be initialized first) */
spinlock_t lock; /* during all ops except TX pckt processing */
spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */
- const struct fs_platform_info *fpi;
+ struct fs_platform_info *fpi;
const struct fs_ops *ops;
int rx_ring, tx_ring;
dma_addr_t ring_mem_addr;
- void *ring_base;
+ void __iomem *ring_base;
struct sk_buff **rx_skbuff;
struct sk_buff **tx_skbuff;
- cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */
- cbd_t *tx_bd_base;
- cbd_t *dirty_tx; /* ring entries to be free()ed. */
- cbd_t *cur_rx;
- cbd_t *cur_tx;
+ cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */
+ cbd_t __iomem *tx_bd_base;
+ cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */
+ cbd_t __iomem *cur_rx;
+ cbd_t __iomem *cur_tx;
int tx_free;
struct net_device_stats stats;
struct timer_list phy_timer_list;
@@ -143,7 +96,6 @@ struct fs_enet_private {
u32 msg_enable;
struct mii_if_info mii_if;
unsigned int last_mii_status;
- struct fs_enet_mii_bus *mii_bus;
int interrupt;
struct phy_device *phydev;
@@ -161,23 +113,23 @@ struct fs_enet_private {
union {
struct {
int idx; /* FEC1 = 0, FEC2 = 1 */
- void *fecp; /* hw registers */
+ void __iomem *fecp; /* hw registers */
u32 hthi, htlo; /* state for multicast */
} fec;
struct {
int idx; /* FCC1-3 = 0-2 */
- void *fccp; /* hw registers */
- void *ep; /* parameter ram */
- void *fcccp; /* hw registers cont. */
- void *mem; /* FCC DPRAM */
+ void __iomem *fccp; /* hw registers */
+ void __iomem *ep; /* parameter ram */
+ void __iomem *fcccp; /* hw registers cont. */
+ void __iomem *mem; /* FCC DPRAM */
u32 gaddrh, gaddrl; /* group address */
} fcc;
struct {
int idx; /* FEC1 = 0, FEC2 = 1 */
- void *sccp; /* hw registers */
- void *ep; /* parameter ram */
+ void __iomem *sccp; /* hw registers */
+ void __iomem *ep; /* parameter ram */
u32 hthi, htlo; /* state for multicast */
} scc;
@@ -185,9 +137,10 @@ struct fs_enet_private {
};
/***************************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
int fs_enet_mdio_bb_init(void);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
int fs_enet_mdio_fec_init(void);
+#endif
void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev);
@@ -247,7 +200,7 @@ extern const struct fs_ops fs_scc_ops;
/*******************************************************************/
/* handy pointer to the immap */
-extern void *fs_enet_immap;
+extern void __iomem *fs_enet_immap;
/*******************************************************************/
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 5603121132cd..da4efbca646e 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -1,14 +1,14 @@
/*
* FCC driver for Motorola MPC82xx (PQ2).
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
- * 2005 (c) MontaVista Software, Inc.
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -42,34 +42,29 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_device.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
/* FCC access macros */
-#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x)
-#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x)
-#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x)
-#define __fcc_in32(addr) in_be32((unsigned *)addr)
-#define __fcc_in16(addr) in_be16((unsigned short *)addr)
-#define __fcc_in8(addr) in_8((unsigned char *)addr)
-
-/* parameter space */
-
/* write, read, set bits, clear bits */
-#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v))
-#define R32(_p, _m) __fcc_in32(&(_p)->_m)
+#define W32(_p, _m, _v) out_be32(&(_p)->_m, (_v))
+#define R32(_p, _m) in_be32(&(_p)->_m)
#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v))
#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v))
-#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v))
-#define R16(_p, _m) __fcc_in16(&(_p)->_m)
+#define W16(_p, _m, _v) out_be16(&(_p)->_m, (_v))
+#define R16(_p, _m) in_be16(&(_p)->_m)
#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v))
#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v))
-#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v))
-#define R8(_p, _m) __fcc_in8(&(_p)->_m)
+#define W8(_p, _m, _v) out_8(&(_p)->_m, (_v))
+#define R8(_p, _m) in_8(&(_p)->_m)
#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v))
#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v))
@@ -83,34 +78,62 @@
#define MAX_CR_CMD_LOOPS 10000
-static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
const struct fs_platform_info *fpi = fep->fpi;
-
- cpm2_map_t *immap = fs_enet_immap;
- cpm_cpm2_t *cpmp = &immap->im_cpm;
- u32 v;
int i;
- /* Currently I don't know what feature call will look like. But
- I guess there'd be something like do_cpm_cmd() which will require page & sblock */
- v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);
- W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
+ return 0;
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
-
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+ struct fs_platform_info *fpi = fep->fpi;
+ int ret = -EINVAL;
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ goto out;
+
+ fep->fcc.fccp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ goto out;
+
+ fep->fcc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->fcc.ep)
+ goto out_fccp;
+
+ fep->fcc.fcccp = of_iomap(ofdev->node, 2);
+ if (!fep->fcc.fcccp)
+ goto out_ep;
+
+ fep->fcc.mem = (void __iomem *)cpm2_immr;
+ fpi->dpram_offset = cpm_dpalloc(128, 8);
+ if (IS_ERR_VALUE(fpi->dpram_offset)) {
+ ret = fpi->dpram_offset;
+ goto out_fcccp;
+ }
+
+ return 0;
+
+out_fcccp:
+ iounmap(fep->fcc.fcccp);
+out_ep:
+ iounmap(fep->fcc.ep);
+out_fccp:
+ iounmap(fep->fcc.fccp);
+out:
+ return ret;
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -121,33 +144,33 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Attach the memory for the FCC Parameter RAM */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
- fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1);
+ fep->fcc.ep = ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.ep == NULL)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
- fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1);
+ fep->fcc.fccp = ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.fccp == NULL)
return -EINVAL;
if (fep->fpi->fcc_regs_c) {
-
- fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+ fep->fcc.fcccp = (void __iomem *)fep->fpi->fcc_regs_c;
} else {
r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"fcc_regs_c");
- fep->fcc.fcccp = (void *)ioremap(r->start,
+ fep->fcc.fcccp = ioremap(r->start,
r->end - r->start + 1);
}
if (fep->fcc.fcccp == NULL)
return -EINVAL;
- fep->fcc.mem = (void *)fep->fpi->mem_offset;
+ fep->fcc.mem = (void __iomem *)fep->fpi->mem_offset;
if (fep->fcc.mem == NULL)
return -EINVAL;
return 0;
+#endif
}
#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB)
@@ -158,11 +181,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
+
+ fpi->cp_command = (fpi->cp_page << 26) |
+ (fpi->cp_block << 21) |
+ (12 << 6);
fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
return -EINVAL;
+#endif
if (do_pd_setup(fep) != 0)
return -EINVAL;
@@ -180,7 +209,7 @@ static int allocate_bd(struct net_device *dev)
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fep->ring_base = dma_alloc_coherent(fep->dev,
+ fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev,
(fpi->tx_ring + fpi->rx_ring) *
sizeof(cbd_t), &fep->ring_mem_addr,
GFP_KERNEL);
@@ -198,7 +227,7 @@ static void free_bd(struct net_device *dev)
if (fep->ring_base)
dma_free_coherent(fep->dev,
(fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
- fep->ring_base, fep->ring_mem_addr);
+ (void __force *)fep->ring_base, fep->ring_mem_addr);
}
static void cleanup_data(struct net_device *dev)
@@ -209,7 +238,7 @@ static void cleanup_data(struct net_device *dev)
static void set_promiscuous_mode(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
S32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
}
@@ -217,7 +246,7 @@ static void set_promiscuous_mode(struct net_device *dev)
static void set_multicast_start(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
W32(ep, fen_gaddrh, 0);
W32(ep, fen_gaddrl, 0);
@@ -226,7 +255,7 @@ static void set_multicast_start(struct net_device *dev)
static void set_multicast_one(struct net_device *dev, const u8 *mac)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
u16 taddrh, taddrm, taddrl;
taddrh = ((u16)mac[5] << 8) | mac[4];
@@ -236,14 +265,14 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
W16(ep, fen_taddrh, taddrh);
W16(ep, fen_taddrm, taddrm);
W16(ep, fen_taddrl, taddrl);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+ fcc_cr_cmd(fep, CPM_CR_SET_GADDR);
}
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
/* clear promiscuous always */
C32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
@@ -278,12 +307,14 @@ static void restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fcc_t *fccp = fep->fcc.fccp;
- fcc_c_t *fcccp = fep->fcc.fcccp;
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
+ fcc_c_t __iomem *fcccp = fep->fcc.fcccp;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
u16 paddrh, paddrm, paddrl;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
u16 mem_addr;
+#endif
const unsigned char *mac;
int i;
@@ -291,7 +322,7 @@ static void restart(struct net_device *dev)
/* clear everything (slow & steady does it) */
for (i = 0; i < sizeof(*ep); i++)
- __fcc_out8((char *)ep + i, 0);
+ out_8((u8 __iomem *)ep + i, 0);
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -315,14 +346,22 @@ static void restart(struct net_device *dev)
* this area.
*/
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset);
+ W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32);
+
+ W16(ep, fen_padptr, fpi->dpram_offset + 64);
+#else
mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */
W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff));
W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff));
+
W16(ep, fen_padptr, mem_addr + 64);
+#endif
/* fill with special symbol... */
- memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
+ memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
W32(ep, fen_genfcc.fcc_rbptr, 0);
W32(ep, fen_genfcc.fcc_tbptr, 0);
@@ -407,7 +446,7 @@ static void restart(struct net_device *dev)
S8(fcccp, fcc_gfemr, 0x20);
}
- fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+ fcc_cr_cmd(fep, CPM_CR_INIT_TRX);
/* clear events */
W16(fccp, fcc_fcce, 0xffff);
@@ -438,7 +477,7 @@ static void restart(struct net_device *dev)
static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
/* stop ethernet */
C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
@@ -465,7 +504,7 @@ static void post_free_irq(struct net_device *dev, int irq)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK);
}
@@ -473,7 +512,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
}
@@ -481,7 +520,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
}
@@ -494,15 +533,15 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
- S32(fccp, fcc_ftodr, 0x80);
+ S16(fccp, fcc_ftodr, 0x8000);
}
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
return (u32)R16(fccp, fcc_fcce);
}
@@ -510,7 +549,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
W16(fccp, fcc_fcce, int_events & 0xffff);
}
@@ -521,47 +560,46 @@ static void ev_error(struct net_device *dev, u32 int_events)
": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
}
-int get_regs(struct net_device *dev, void *p, int *sizep)
+static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+ if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1)
return -EINVAL;
memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
p = (char *)p + sizeof(fcc_t);
- memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
- p = (char *)p + sizeof(fcc_c_t);
-
memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+ p = (char *)p + sizeof(fcc_enet_t);
+ memcpy_fromio(p, fep->fcc.fcccp, 1);
return 0;
}
-int get_regs_len(struct net_device *dev)
+static int get_regs_len(struct net_device *dev)
{
- return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+ return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1;
}
/* Some transmit errors cause the transmitter to shut
* down. We now issue a restart transmit. Since the
* errors close the BD and update the pointers, the restart
* _should_ pick up without having to reset any of our
- * pointers either. Also, To workaround 8260 device erratum
+ * pointers either. Also, To workaround 8260 device erratum
* CPM37, we must disable and then re-enable the transmitter
* following a Late Collision, Underrun, or Retry Limit error.
*/
-void tx_restart(struct net_device *dev)
+static void tx_restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
udelay(10);
S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+ fcc_cr_cmd(fep, CPM_CR_RESTART_TX);
}
/*************************************************************************/
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 04b4f80a1cde..c1fee48517e3 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -1,14 +1,14 @@
/*
* Freescale Ethernet controllers
*
- * Copyright (c) 2005 Intracom S.A.
+ * Copyright (c) 2005 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
- * 2005 (c) MontaVista Software, Inc.
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_device.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -79,7 +83,7 @@
*/
#define FEC_RESET_DELAY 50
-static int whack_reset(fec_t * fecp)
+static int whack_reset(fec_t __iomem *fecp)
{
int i;
@@ -95,9 +99,22 @@ static int whack_reset(fec_t * fecp)
static int do_pd_setup(struct fs_enet_private *fep)
{
- struct platform_device *pdev = to_platform_device(fep->dev);
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->fec.fecp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ return -EINVAL;
+
+ return 0;
+#else
+ struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
-
+
/* Fill out IRQ field */
fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
if (fep->interrupt < 0)
@@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
return 0;
-
+#endif
}
#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB)
@@ -141,8 +158,8 @@ static int allocate_bd(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
-
- fep->ring_base = dma_alloc_coherent(fep->dev,
+
+ fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev,
(fpi->tx_ring + fpi->rx_ring) *
sizeof(cbd_t), &fep->ring_mem_addr,
GFP_KERNEL);
@@ -160,7 +177,7 @@ static void free_bd(struct net_device *dev)
if(fep->ring_base)
dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring)
* sizeof(cbd_t),
- fep->ring_base,
+ (void __force *)fep->ring_base,
fep->ring_mem_addr);
}
@@ -172,7 +189,7 @@ static void cleanup_data(struct net_device *dev)
static void set_promiscuous_mode(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
}
@@ -220,7 +237,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
/* if all multi or too many multicasts; just enable all */
if ((dev->flags & IFF_ALLMULTI) != 0 ||
@@ -254,7 +271,7 @@ static void restart(struct net_device *dev)
u32 cptr;
#endif
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
const struct fs_platform_info *fpi = fep->fpi;
dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
int r;
@@ -280,13 +297,13 @@ static void restart(struct net_device *dev)
FW(fecp, addr_high, addrlo);
/*
- * Reset all multicast.
+ * Reset all multicast.
*/
FW(fecp, hash_table_high, fep->fec.hthi);
FW(fecp, hash_table_low, fep->fec.htlo);
/*
- * Set maximum receive buffer size.
+ * Set maximum receive buffer size.
*/
FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
FW(fecp, r_hash, PKT_MAXBUF_SIZE);
@@ -296,7 +313,7 @@ static void restart(struct net_device *dev)
tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
/*
- * Set receive and transmit descriptor base.
+ * Set receive and transmit descriptor base.
*/
FW(fecp, r_des_start, rx_bd_base_phys);
FW(fecp, x_des_start, tx_bd_base_phys);
@@ -304,7 +321,7 @@ static void restart(struct net_device *dev)
fs_init_bds(dev);
/*
- * Enable big endian and don't care about SDMA FC.
+ * Enable big endian and don't care about SDMA FC.
*/
FW(fecp, fun_code, 0x78000000);
@@ -366,13 +383,13 @@ static void restart(struct net_device *dev)
}
/*
- * Enable interrupts we wish to service.
+ * Enable interrupts we wish to service.
*/
FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB |
FEC_ENET_RXF | FEC_ENET_RXB);
/*
- * And last, enable the transmit and receive processing.
+ * And last, enable the transmit and receive processing.
*/
FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
FW(fecp, r_des_active, 0x01000000);
@@ -382,7 +399,7 @@ static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
struct fec_info* feci= fep->phydev->bus->priv;
@@ -401,7 +418,7 @@ static void stop(struct net_device *dev)
": %s FEC timeout on graceful transmit stop\n",
dev->name);
/*
- * Disable FEC. Let only MII interrupts.
+ * Disable FEC. Let only MII interrupts.
*/
FW(fecp, imask, 0);
FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN);
@@ -444,7 +461,7 @@ static void post_free_irq(struct net_device *dev, int irq)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
}
@@ -452,7 +469,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -460,7 +477,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -468,7 +485,7 @@ static void napi_disable_rx(struct net_device *dev)
static void rx_bd_done(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, r_des_active, 0x01000000);
}
@@ -476,7 +493,7 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, x_des_active, 0x01000000);
}
@@ -484,7 +501,7 @@ static void tx_kickstart(struct net_device *dev)
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
return FR(fecp, ievent) & FR(fecp, imask);
}
@@ -492,7 +509,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, int_events);
}
@@ -503,7 +520,7 @@ static void ev_error(struct net_device *dev, u32 int_events)
": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);
}
-int get_regs(struct net_device *dev, void *p, int *sizep)
+static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -515,12 +532,12 @@ int get_regs(struct net_device *dev, void *p, int *sizep)
return 0;
}
-int get_regs_len(struct net_device *dev)
+static int get_regs_len(struct net_device *dev)
{
return sizeof(fec_t);
}
-void tx_restart(struct net_device *dev)
+static void tx_restart(struct net_device *dev)
{
/* nothing */
}
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 7540966687ec..03134f47a4eb 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -1,14 +1,14 @@
/*
* Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx.
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
@@ -82,34 +86,45 @@
#define SCC_MAX_MULTICAST_ADDRS 64
/*
- * Delay to wait for SCC reset command to complete (in us)
+ * Delay to wait for SCC reset command to complete (in us)
*/
#define SCC_RESET_DELAY 50
#define MAX_CR_CMD_LOOPS 10000
static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
- cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;
- u32 v, ch;
- int i = 0;
+ const struct fs_platform_info *fpi = fep->fpi;
+ int i;
- ch = fep->scc.idx << 2;
- v = mk_cr_cmd(ch, op);
- W16(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
+ return 0;
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->scc.sccp = of_iomap(ofdev->node, 0);
+ if (!fep->scc.sccp)
+ return -EINVAL;
+
+ fep->scc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->scc.ep) {
+ iounmap(fep->scc.sccp);
+ return -EINVAL;
+ }
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -129,6 +144,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
if (fep->scc.ep == NULL)
return -EINVAL;
+#endif
return 0;
}
@@ -141,12 +157,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
fep->scc.idx = fs_get_scc_index(fpi->fs_no);
- if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */
+ if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */
return -EINVAL;
+ fpi->cp_command = fep->fcc.idx << 6;
+#endif
+
do_pd_setup(fep);
fep->scc.hthi = 0;
@@ -154,7 +175,7 @@ static int setup_data(struct net_device *dev)
fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;
fep->ev_rx = SCC_RX_EVENT;
- fep->ev_tx = SCC_TX_EVENT;
+ fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE;
fep->ev_err = SCC_ERR_EVENT_MSK;
return 0;
@@ -170,7 +191,8 @@ static int allocate_bd(struct net_device *dev)
if (IS_ERR_VALUE(fep->ring_mem_addr))
return -ENOMEM;
- fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);
+ fep->ring_base = (void __iomem __force*)
+ cpm_dpram_addr(fep->ring_mem_addr);
return 0;
}
@@ -189,9 +211,9 @@ static void cleanup_data(struct net_device *dev)
}
static void set_promiscuous_mode(struct net_device *dev)
-{
+{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
S16(sccp, scc_psmr, SCC_PSMR_PRO);
}
@@ -199,7 +221,7 @@ static void set_promiscuous_mode(struct net_device *dev)
static void set_multicast_start(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_enet_t *ep = fep->scc.ep;
+ scc_enet_t __iomem *ep = fep->scc.ep;
W16(ep, sen_gaddr1, 0);
W16(ep, sen_gaddr2, 0);
@@ -210,7 +232,7 @@ static void set_multicast_start(struct net_device *dev)
static void set_multicast_one(struct net_device *dev, const u8 * mac)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_enet_t *ep = fep->scc.ep;
+ scc_enet_t __iomem *ep = fep->scc.ep;
u16 taddrh, taddrm, taddrl;
taddrh = ((u16) mac[5] << 8) | mac[4];
@@ -226,8 +248,8 @@ static void set_multicast_one(struct net_device *dev, const u8 * mac)
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
- scc_enet_t *ep = fep->scc.ep;
+ scc_t __iomem *sccp = fep->scc.sccp;
+ scc_enet_t __iomem *ep = fep->scc.ep;
/* clear promiscuous always */
C16(sccp, scc_psmr, SCC_PSMR_PRO);
@@ -264,8 +286,8 @@ static void set_multicast_list(struct net_device *dev)
static void restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
- scc_enet_t *ep = fep->scc.ep;
+ scc_t __iomem *sccp = fep->scc.sccp;
+ scc_enet_t __iomem *ep = fep->scc.ep;
const struct fs_platform_info *fpi = fep->fpi;
u16 paddrh, paddrm, paddrl;
const unsigned char *mac;
@@ -275,7 +297,7 @@ static void restart(struct net_device *dev)
/* clear everything (slow & steady does it) */
for (i = 0; i < sizeof(*ep); i++)
- __fs_out8((char *)ep + i, 0);
+ __fs_out8((u8 __iomem *)ep + i, 0);
/* point to bds */
W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr);
@@ -323,7 +345,7 @@ static void restart(struct net_device *dev)
W16(ep, sen_iaddr3, 0);
W16(ep, sen_iaddr4, 0);
- /* set address
+ /* set address
*/
mac = dev->dev_addr;
paddrh = ((u16) mac[5] << 8) | mac[4];
@@ -345,7 +367,7 @@ static void restart(struct net_device *dev)
W16(sccp, scc_scce, 0xffff);
- /* Enable interrupts we wish to service.
+ /* Enable interrupts we wish to service.
*/
W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
@@ -373,10 +395,10 @@ static void restart(struct net_device *dev)
S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
-static void stop(struct net_device *dev)
+static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
int i;
for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++)
@@ -420,7 +442,7 @@ static void post_free_irq(struct net_device *dev, int irq)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK);
}
@@ -428,7 +450,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
}
@@ -436,7 +458,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
}
@@ -454,7 +476,7 @@ static void tx_kickstart(struct net_device *dev)
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
return (u32) R16(sccp, scc_scce);
}
@@ -462,7 +484,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
W16(sccp, scc_scce, int_events & 0xffff);
}
@@ -477,20 +499,20 @@ static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t))
+ if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *))
return -EINVAL;
memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t));
p = (char *)p + sizeof(scc_t);
- memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t));
+ memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *));
return 0;
}
static int get_regs_len(struct net_device *dev)
{
- return sizeof(scc_t) + sizeof(scc_enet_t);
+ return sizeof(scc_t) + sizeof(scc_enet_t __iomem *);
}
static void tx_restart(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index d3840108ffbd..b8e4a736a130 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -1,314 +1,288 @@
/*
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
-
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
#include <linux/platform_device.h>
+#include <linux/mdio-bitbang.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
#include "fs_enet.h"
-static int bitbang_prep_bit(u8 **datp, u8 *mskp,
- struct fs_mii_bit *mii_bit)
-{
- void *dat;
- int adv;
- u8 msk;
-
- dat = (void*) mii_bit->offset;
-
- adv = mii_bit->bit >> 3;
- dat = (char *)dat + adv;
-
- msk = 1 << (7 - (mii_bit->bit & 7));
-
- *datp = dat;
- *mskp = msk;
-
- return 0;
-}
+struct bb_info {
+ struct mdiobb_ctrl ctrl;
+ __be32 __iomem *dir;
+ __be32 __iomem *dat;
+ u32 mdio_msk;
+ u32 mdc_msk;
+};
-static inline void bb_set(u8 *p, u8 m)
+/* FIXME: If any other users of GPIO crop up, then these will have to
+ * have some sort of global synchronization to avoid races with other
+ * pins on the same port. The ideal solution would probably be to
+ * bind the ports to a GPIO driver, and have this be a client of it.
+ */
+static inline void bb_set(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) | m);
+ out_be32(p, in_be32(p) | m);
}
-static inline void bb_clr(u8 *p, u8 m)
+static inline void bb_clr(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) & ~m);
+ out_be32(p, in_be32(p) & ~m);
}
-static inline int bb_read(u8 *p, u8 m)
+static inline int bb_read(u32 __iomem *p, u32 m)
{
- return (in_8(p) & m) != 0;
+ return (in_be32(p) & m) != 0;
}
-static inline void mdio_active(struct bb_info *bitbang)
+static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
{
- bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
-}
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
-static inline void mdio_tristate(struct bb_info *bitbang )
-{
- bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
+ if (dir)
+ bb_set(bitbang->dir, bitbang->mdio_msk);
+ else
+ bb_clr(bitbang->dir, bitbang->mdio_msk);
+
+ /* Read back to flush the write. */
+ in_be32(bitbang->dir);
}
-static inline int mdio_read(struct bb_info *bitbang )
+static inline int mdio_read(struct mdiobb_ctrl *ctrl)
{
- return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+ return bb_read(bitbang->dat, bitbang->mdio_msk);
}
-static inline void mdio(struct bb_info *bitbang , int what)
+static inline void mdio(struct mdiobb_ctrl *ctrl, int what)
{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
if (what)
- bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_set(bitbang->dat, bitbang->mdio_msk);
else
- bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_clr(bitbang->dat, bitbang->mdio_msk);
+
+ /* Read back to flush the write. */
+ in_be32(bitbang->dat);
}
-static inline void mdc(struct bb_info *bitbang , int what)
+static inline void mdc(struct mdiobb_ctrl *ctrl, int what)
{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
if (what)
- bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_set(bitbang->dat, bitbang->mdc_msk);
else
- bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_clr(bitbang->dat, bitbang->mdc_msk);
+
+ /* Read back to flush the write. */
+ in_be32(bitbang->dat);
}
-static inline void mii_delay(struct bb_info *bitbang )
+static struct mdiobb_ops bb_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = mdc,
+ .set_mdio_dir = mdio_dir,
+ .set_mdio_data = mdio,
+ .get_mdio_data = mdio_read,
+};
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
{
- udelay(bitbang->delay);
+ struct resource res;
+ const u32 *data;
+ int mdio_pin, mdc_pin, len;
+ struct bb_info *bitbang = bus->priv;
+
+ int ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+
+ if (res.end - res.start < 13)
+ return -ENODEV;
+
+ /* This should really encode the pin number as well, but all
+ * we get is an int, and the odds of multiple bitbang mdio buses
+ * is low enough that it's not worth going too crazy.
+ */
+ bus->id = res.start;
+
+ data = of_get_property(np, "fsl,mdio-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdio_pin = *data;
+
+ data = of_get_property(np, "fsl,mdc-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdc_pin = *data;
+
+ bitbang->dir = ioremap(res.start, res.end - res.start + 1);
+ if (!bitbang->dir)
+ return -ENOMEM;
+
+ bitbang->dat = bitbang->dir + 4;
+ bitbang->mdio_msk = 1 << (31 - mdio_pin);
+ bitbang->mdc_msk = 1 << (31 - mdc_pin);
+
+ return 0;
}
-/* Utility to send the preamble, address, and register (common to read and write). */
-static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg)
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
{
- int j;
-
- /*
- * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
- * The IEEE spec says this is a PHY optional requirement. The AMD
- * 79C874 requires one after power up and one after a MII communications
- * error. This means that we are doing more preambles than we need,
- * but it is safer and will be much more robust.
- */
+ const u32 *data;
+ int len, id, irq;
- mdio_active(bitbang);
- mdio(bitbang, 1);
- for (j = 0; j < 32; j++) {
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- }
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
- /* send the start bit (01) and the read opcode (10) or write (10) */
- mdc(bitbang, 0);
- mdio(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, read);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, !read);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
-
- /* send the PHY address */
- for (j = 0; j < 5; j++) {
- mdc(bitbang, 0);
- mdio(bitbang, (addr & 0x10) != 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- addr <<= 1;
- }
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
- /* send the register address */
- for (j = 0; j < 5; j++) {
- mdc(bitbang, 0);
- mdio(bitbang, (reg & 0x10) != 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- reg <<= 1;
- }
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
}
-static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location)
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- u16 rdreg;
- int ret, j;
- u8 addr = phy_id & 0xff;
- u8 reg = location & 0xff;
- struct bb_info* bitbang = bus->priv;
-
- bitbang_pre(bitbang, 1, addr, reg);
-
- /* tri-state our MDIO I/O pin so we can read */
- mdc(bitbang, 0);
- mdio_tristate(bitbang);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
-
- /* check the turnaround bit: the PHY should be driving it to zero */
- if (mdio_read(bitbang) != 0) {
- /* PHY didn't drive TA low */
- for (j = 0; j < 32; j++) {
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- }
- ret = -1;
+ struct device_node *np = NULL;
+ struct mii_bus *new_bus;
+ struct bb_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ if (!bitbang)
goto out;
- }
- mdc(bitbang, 0);
- mii_delay(bitbang);
-
- /* read 16 bits of register data, MSB first */
- rdreg = 0;
- for (j = 0; j < 16; j++) {
- mdc(bitbang, 1);
- mii_delay(bitbang);
- rdreg <<= 1;
- rdreg |= mdio_read(bitbang);
- mdc(bitbang, 0);
- mii_delay(bitbang);
- }
+ bitbang->ctrl.ops = &bb_ops;
+
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+ if (!new_bus)
+ goto out_free_priv;
+
+ new_bus->name = "CPM2 Bitbanged MII",
+
+ ret = fs_mii_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bus;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
+ return 0;
- ret = rdreg;
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(bitbang->dir);
+out_free_bus:
+ kfree(new_bus);
+out_free_priv:
+ free_mdio_bitbang(new_bus);
out:
return ret;
}
-static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+static int fs_enet_mdio_remove(struct of_device *ofdev)
{
- int j;
- struct bb_info* bitbang = bus->priv;
-
- u8 addr = phy_id & 0xff;
- u8 reg = location & 0xff;
- u16 value = val & 0xffff;
-
- bitbang_pre(bitbang, 0, addr, reg);
-
- /* send the turnaround (10) */
- mdc(bitbang, 0);
- mdio(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
-
- /* write 16 bits of register data, MSB first */
- for (j = 0; j < 16; j++) {
- mdc(bitbang, 0);
- mdio(bitbang, (value & 0x8000) != 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- value <<= 1;
- }
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct bb_info *bitbang = bus->priv;
- /*
- * Tri-state the MDIO line.
- */
- mdio_tristate(bitbang);
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- return 0;
-}
+ mdiobus_unregister(bus);
+ free_mdio_bitbang(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(bitbang->dir);
+ kfree(bitbang);
+ kfree(bus);
-static int fs_enet_mii_bb_reset(struct mii_bus *bus)
-{
- /*nothing here - dunno how to reset it*/
return 0;
}
-static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
-{
- int r;
+static struct of_device_id fs_enet_mdio_bb_match[] = {
+ {
+ .compatible = "fsl,cpm2-mdio-bitbang",
+ },
+ {},
+};
- bitbang->delay = fmpi->delay;
+static struct of_platform_driver fs_enet_bb_mdio_driver = {
+ .name = "fsl-bb-mdio",
+ .match_table = fs_enet_mdio_bb_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
- r = bitbang_prep_bit(&bitbang->mdio_dir,
- &bitbang->mdio_dir_msk,
- &fmpi->mdio_dir);
- if (r != 0)
- return r;
+static int fs_enet_mdio_bb_init(void)
+{
+ return of_register_platform_driver(&fs_enet_bb_mdio_driver);
+}
- r = bitbang_prep_bit(&bitbang->mdio_dat,
- &bitbang->mdio_dat_msk,
- &fmpi->mdio_dat);
- if (r != 0)
- return r;
+static void fs_enet_mdio_bb_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
+}
- r = bitbang_prep_bit(&bitbang->mdc_dat,
- &bitbang->mdc_msk,
- &fmpi->mdc_dat);
- if (r != 0)
- return r;
+module_init(fs_enet_mdio_bb_init);
+module_exit(fs_enet_mdio_bb_exit);
+#else
+static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
+ struct fs_mii_bb_platform_info *fmpi)
+{
+ bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
+ bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
+ bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
+ bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
return 0;
}
-
static int __devinit fs_enet_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -320,20 +294,19 @@ static int __devinit fs_enet_mdio_probe(struct device *dev)
if (NULL == dev)
return -EINVAL;
- new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
- if (NULL == new_bus)
+ if (NULL == bitbang)
return -ENOMEM;
- bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ bitbang->ctrl.ops = &bb_ops;
- if (NULL == bitbang)
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+
+ if (NULL == new_bus)
return -ENOMEM;
new_bus->name = "BB MII Bus",
- new_bus->read = &fs_enet_mii_bb_read,
- new_bus->write = &fs_enet_mii_bb_write,
- new_bus->reset = &fs_enet_mii_bb_reset,
new_bus->id = pdev->id;
new_bus->phy_mask = ~0x9;
@@ -365,13 +338,12 @@ static int __devinit fs_enet_mdio_probe(struct device *dev)
return 0;
bus_register_fail:
+ free_mdio_bitbang(new_bus);
kfree(bitbang);
- kfree(new_bus);
return err;
}
-
static int fs_enet_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
@@ -380,9 +352,7 @@ static int fs_enet_mdio_remove(struct device *dev)
dev_set_drvdata(dev, NULL);
- iounmap((void *) (&bus->priv));
- bus->priv = NULL;
- kfree(bus);
+ free_mdio_bitbang(bus);
return 0;
}
@@ -403,4 +373,4 @@ void fs_enet_mdio_bb_exit(void)
{
driver_unregister(&fs_enet_bb_mdio_driver);
}
-
+#endif
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 0a563a83016f..a89cf15090b8 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -47,6 +51,7 @@
#define FEC_MII_LOOPS 10000
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static int match_has_phy (struct device *dev, void* data)
{
struct platform_device* pdev = container_of(dev, struct platform_device, dev);
@@ -65,7 +70,7 @@ static int match_has_phy (struct device *dev, void* data)
static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi)
{
struct resource *r;
- fec_t *fecp;
+ fec_t __iomem *fecp;
char* name = "fsl-cpm-fec";
/* we need fec in order to be useful */
@@ -80,7 +85,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info
r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs");
- fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t));
+ fec->fecp = fecp = ioremap(r->start,sizeof(fec_t));
fec->mii_speed = fmpi->mii_speed;
setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
@@ -90,11 +95,12 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info
return 0;
}
+#endif
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
struct fec_info* fec = bus->priv;
- fec_t *fecp = fec->fecp;
+ fec_t __iomem *fecp = fec->fecp;
int i, ret = -1;
if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
@@ -113,13 +119,12 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
}
return ret;
-
}
static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
struct fec_info* fec = bus->priv;
- fec_t *fecp = fec->fecp;
+ fec_t __iomem *fecp = fec->fecp;
int i;
/* this must never happen */
@@ -146,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
return 0;
}
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct resource res;
+ struct mii_bus *new_bus;
+ struct fec_info *fec;
+ int ret = -ENOMEM, i;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!new_bus)
+ goto out;
+
+ fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+ if (!fec)
+ goto out_mii;
+
+ new_bus->priv = fec;
+ new_bus->name = "FEC MII Bus";
+ new_bus->read = &fs_enet_fec_mii_read;
+ new_bus->write = &fs_enet_fec_mii_write;
+ new_bus->reset = &fs_enet_fec_mii_reset;
+
+ ret = of_address_to_resource(ofdev->node, 0, &res);
+ if (ret)
+ return ret;
+
+ new_bus->id = res.start;
+
+ fec->fecp = ioremap(res.start, res.end - res.start + 1);
+ if (!fec->fecp)
+ goto out_fec;
+
+ fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+
+ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+ setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
+ FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
+ out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(fec->fecp);
+out_fec:
+ kfree(fec);
+out_mii:
+ kfree(new_bus);
+out:
+ return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct fec_info *fec = bus->priv;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(fec->fecp);
+ kfree(fec);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id fs_enet_mdio_fec_match[] = {
+ {
+ .compatible = "fsl,pq1-fec-mdio",
+ },
+ {},
+};
+
+static struct of_platform_driver fs_enet_fec_mdio_driver = {
+ .name = "fsl-fec-mdio",
+ .match_table = fs_enet_mdio_fec_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+static int fs_enet_mdio_fec_init(void)
+{
+ return of_register_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+static void fs_enet_mdio_fec_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+module_init(fs_enet_mdio_fec_init);
+module_exit(fs_enet_mdio_fec_exit);
+#else
static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -236,4 +376,4 @@ void fs_enet_mdio_fec_exit(void)
{
driver_unregister(&fs_enet_fec_mdio_driver);
}
-
+#endif
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index d7a1a58de766..0db5e6fabe73 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -116,7 +116,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
static int gfar_close(struct net_device *dev);
struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
-static struct net_device_stats *gfar_get_stats(struct net_device *dev);
static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -134,7 +133,7 @@ static void gfar_configure_serdes(struct net_device *dev);
extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget);
+static int gfar_poll(struct napi_struct *napi, int budget);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
static void gfar_netpoll(struct net_device *dev);
@@ -171,6 +170,7 @@ static int gfar_probe(struct platform_device *pdev)
struct resource *r;
int idx;
int err = 0;
+ DECLARE_MAC_BUF(mac);
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
@@ -188,6 +188,7 @@ static int gfar_probe(struct platform_device *pdev)
return -ENOMEM;
priv = netdev_priv(dev);
+ priv->dev = dev;
/* Set the info in the priv to the current info */
priv->einfo = einfo;
@@ -253,7 +254,6 @@ static int gfar_probe(struct platform_device *pdev)
/* Set the dev->base_addr to the gfar reg region */
dev->base_addr = (unsigned long) (priv->regs);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Fill in the dev structure */
@@ -261,15 +261,11 @@ static int gfar_probe(struct platform_device *pdev)
dev->hard_start_xmit = gfar_start_xmit;
dev->tx_timeout = gfar_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_GFAR_NAPI
- dev->poll = gfar_poll;
- dev->weight = GFAR_DEV_WEIGHT;
-#endif
+ netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = gfar_netpoll;
#endif
dev->stop = gfar_close;
- dev->get_stats = gfar_get_stats;
dev->change_mtu = gfar_change_mtu;
dev->mtu = 1500;
dev->set_multicast_list = gfar_set_multi;
@@ -361,10 +357,8 @@ static int gfar_probe(struct platform_device *pdev)
gfar_init_sysfs(dev);
/* Print out the device info */
- printk(KERN_INFO DEVICE_NAME, dev->name);
- for (idx = 0; idx < 6; idx++)
- printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
- printk("\n");
+ printk(KERN_INFO DEVICE_NAME "%s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
/* Even more device info helps when determining which kernel */
/* provided which set of benchmarks. */
@@ -420,8 +414,18 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
if (ecntrl & ECNTRL_REDUCED_MODE) {
if (ecntrl & ECNTRL_REDUCED_MII_MODE)
return PHY_INTERFACE_MODE_RMII;
- else
+ else {
+ phy_interface_t interface = priv->einfo->interface;
+
+ /*
+ * This isn't autodetected right now, so it must
+ * be set by the device tree or platform code.
+ */
+ if (interface == PHY_INTERFACE_MODE_RGMII_ID)
+ return PHY_INTERFACE_MODE_RGMII_ID;
+
return PHY_INTERFACE_MODE_RGMII;
+ }
}
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
@@ -929,6 +933,8 @@ static int gfar_enet_open(struct net_device *dev)
{
int err;
+ napi_enable(&priv->napi);
+
/* Initialize a bunch of registers */
init_registers(dev);
@@ -936,10 +942,14 @@ static int gfar_enet_open(struct net_device *dev)
err = init_phy(dev);
- if(err)
+ if(err) {
+ napi_disable(&priv->napi);
return err;
+ }
err = startup_gfar(dev);
+ if (err)
+ napi_disable(&priv->napi);
netif_start_queue(dev);
@@ -1000,7 +1010,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
/* Update transmit stats */
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Lock priv now */
spin_lock_irqsave(&priv->txlock, flags);
@@ -1073,7 +1083,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (txbdp == priv->dirty_tx) {
netif_stop_queue(dev);
- priv->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
}
/* Update the current txbd to the next one */
@@ -1092,6 +1102,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int gfar_close(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+
+ napi_disable(&priv->napi);
+
stop_gfar(dev);
/* Disconnect from the PHY */
@@ -1103,14 +1116,6 @@ static int gfar_close(struct net_device *dev)
return 0;
}
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats * gfar_get_stats(struct net_device *dev)
-{
- struct gfar_private *priv = netdev_priv(dev);
-
- return &(priv->stats);
-}
-
/* Changes the mac address if the controller is not running. */
int gfar_set_mac_address(struct net_device *dev)
{
@@ -1222,7 +1227,7 @@ static void gfar_timeout(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (dev->flags & IFF_UP) {
stop_gfar(dev);
@@ -1252,12 +1257,12 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0))
break;
- priv->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Deferred means some collisions occurred during transmit, */
/* but we eventually sent the packet. */
if (bdp->status & TXBD_DEF)
- priv->stats.collisions++;
+ dev->stats.collisions++;
/* Free the sk buffer associated with this TxBD */
dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
@@ -1308,7 +1313,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
return NULL;
alignamount = RXBUF_ALIGNMENT -
- (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
+ (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
/* We need the data buffer to be aligned properly. We will reserve
* as many bytes as needed to align the data properly
@@ -1329,7 +1334,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
static inline void count_errors(unsigned short status, struct gfar_private *priv)
{
- struct net_device_stats *stats = &priv->stats;
+ struct net_device_stats *stats = &dev->stats;
struct gfar_extra_stats *estats = &priv->extra_stats;
/* If the packet was truncated, none of the other errors
@@ -1380,12 +1385,12 @@ irqreturn_t gfar_receive(int irq, void *dev_id)
/* support NAPI */
#ifdef CONFIG_GFAR_NAPI
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &priv->napi)) {
tempval = gfar_read(&priv->regs->imask);
tempval &= IMASK_RX_DISABLED;
gfar_write(&priv->regs->imask, tempval);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &priv->napi);
} else {
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
@@ -1454,7 +1459,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
if (NULL == skb) {
if (netif_msg_rx_err(priv))
printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
} else {
int ret;
@@ -1512,7 +1517,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
(RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET
| RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) {
/* Increment the number of packets */
- priv->stats.rx_packets++;
+ dev->stats.rx_packets++;
howmany++;
/* Remove the FCS from the packet length */
@@ -1520,7 +1525,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
gfar_process_frame(dev, skb, pkt_len);
- priv->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
} else {
count_errors(bdp->status, priv);
@@ -1559,23 +1564,16 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
}
#ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget)
+static int gfar_poll(struct napi_struct *napi, int budget)
{
+ struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
+ struct net_device *dev = priv->dev;
int howmany;
- struct gfar_private *priv = netdev_priv(dev);
- int rx_work_limit = *budget;
-
- if (rx_work_limit > dev->quota)
- rx_work_limit = dev->quota;
- howmany = gfar_clean_rx_ring(dev, rx_work_limit);
+ howmany = gfar_clean_rx_ring(dev, budget);
- dev->quota -= howmany;
- rx_work_limit -= howmany;
- *budget -= howmany;
-
- if (rx_work_limit > 0) {
- netif_rx_complete(dev);
+ if (howmany < budget) {
+ netif_rx_complete(dev, napi);
/* Clear the halt bit in RSTAT */
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
@@ -1591,8 +1589,7 @@ static int gfar_poll(struct net_device *dev, int *budget)
gfar_write(&priv->regs->rxic, 0);
}
- /* Return 1 if there's more work to do */
- return (rx_work_limit > 0) ? 0 : 1;
+ return howmany;
}
#endif
@@ -1908,17 +1905,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
/* Update the error counters */
if (events & IEVENT_TXE) {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (events & IEVENT_LC)
- priv->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (events & IEVENT_CRL)
- priv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
if (netif_msg_tx_err(priv))
printk(KERN_DEBUG "%s: TX FIFO underrun, "
"packet dropped.\n", dev->name);
- priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
/* Reactivate the Tx Queues */
@@ -1928,7 +1925,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
}
if (events & IEVENT_BSY) {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
priv->extra_stats.rx_bsy++;
gfar_receive(irq, dev_id);
@@ -1943,7 +1940,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
dev->name, gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
priv->extra_stats.rx_babr++;
if (netif_msg_rx_err(priv))
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index d8e779c102fa..c16cc8b946a9 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -45,7 +45,6 @@
#include <linux/crc32.h>
#include <linux/workqueue.h>
#include <linux/ethtool.h>
-#include <linux/netdevice.h>
#include <linux/fsl_devices.h>
#include "gianfar_mii.h"
@@ -691,6 +690,9 @@ struct gfar_private {
/* RX Locked fields */
spinlock_t rxlock;
+ struct net_device *dev;
+ struct napi_struct napi;
+
/* skb array and index */
struct sk_buff ** rx_skbuff;
u16 skb_currx;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 7b411c1514db..6007147cc1e9 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/crc32.h>
#include <asm/types.h>
-#include <asm/uaccess.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/phy.h>
@@ -153,15 +152,19 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
buf[i] = extra[i];
}
-/* Returns the number of stats (and their corresponding strings) */
-static int gfar_stats_count(struct net_device *dev)
+static int gfar_sset_count(struct net_device *dev, int sset)
{
struct gfar_private *priv = netdev_priv(dev);
- if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
- return GFAR_STATS_LEN;
- else
- return GFAR_EXTRA_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ return GFAR_STATS_LEN;
+ else
+ return GFAR_EXTRA_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
/* Fills in the drvinfo structure with some basic info */
@@ -172,8 +175,6 @@ static void gfar_gdrvinfo(struct net_device *dev, struct
strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
- drvinfo->n_stats = GFAR_STATS_LEN;
- drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
drvinfo->eedump_len = 0;
}
@@ -576,7 +577,7 @@ const struct ethtool_ops gfar_ethtool_ops = {
.get_ringparam = gfar_gringparam,
.set_ringparam = gfar_sringparam,
.get_strings = gfar_gstrings,
- .get_stats_count = gfar_stats_count,
+ .get_sset_count = gfar_sset_count,
.get_ethtool_stats = gfar_fill_stats,
.get_rx_csum = gfar_get_rx_csum,
.get_tx_csum = gfar_get_tx_csum,
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index ac3596f45dd8..100bf410bf5f 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -245,7 +245,7 @@ int __init gfar_mdio_init(void)
return driver_register(&gianfar_mdio_driver);
}
-void __exit gfar_mdio_exit(void)
+void gfar_mdio_exit(void)
{
driver_unregister(&gianfar_mdio_driver);
}
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index 5d3400469514..b373091c7031 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -42,5 +42,5 @@ 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 __init gfar_mdio_init(void);
-void __exit gfar_mdio_exit(void);
+void gfar_mdio_exit(void);
#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 15254dc7876a..ed407c85708f 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -580,6 +580,7 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
void *ring_space;
dma_addr_t ring_dma;
int ret = -ENOMEM;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -613,7 +614,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
if (!dev)
goto err_out_iounmap;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#ifdef TX_CHECKSUM
@@ -742,12 +742,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
goto err_out_unmap_rx;
}
- printk(KERN_INFO "%s: %s type %x at %p, ",
+ printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n",
dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev),
- ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ ioaddr, print_mac(mac, dev->dev_addr), irq);
i = readb(ioaddr + PCIClkMeas);
printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "
"%2.2x, LPA %4.4x.\n",
@@ -1020,7 +1017,7 @@ static inline int hamachi_tx(struct net_device *dev)
break;
/* Free the original skb. */
skb = hmp->tx_skbuff[entry];
- if (skb != 0) {
+ if (skb) {
pci_unmap_single(hmp->pci_dev,
hmp->tx_ring[entry].addr, skb->len,
PCI_DMA_TODEVICE);
@@ -1072,7 +1069,6 @@ static void hamachi_tx_timeout(struct net_device *dev)
" resetting...\n", dev->name, (int)readw(ioaddr + TxStatus));
{
- int i;
printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 760d04a671f9..ecd156def039 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -288,7 +288,8 @@ static int sp_close(struct net_device *dev)
/* Return the frame type ID */
static int sp_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
#ifdef CONFIG_INET
if (type != htons(ETH_P_AX25))
@@ -323,6 +324,11 @@ static int sp_rebuild_header(struct sk_buff *skb)
#endif
}
+static const struct header_ops sp_header_ops = {
+ .create = sp_header,
+ .rebuild = sp_rebuild_header,
+};
+
static void sp_setup(struct net_device *dev)
{
/* Finish setting up the DEVICE info. */
@@ -331,22 +337,21 @@ static void sp_setup(struct net_device *dev)
dev->open = sp_open_dev;
dev->destructor = free_netdev;
dev->stop = sp_close;
- dev->hard_header = sp_header;
+
dev->get_stats = sp_get_stats;
dev->set_mac_address = sp_set_mac_address;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
+ dev->header_ops = &sp_header_ops;
+
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
- dev->rebuild_header = sp_rebuild_header;
dev->tx_timeout = NULL;
/* Only activated in AX.25 mode */
memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
- SET_MODULE_OWNER(dev);
-
dev->flags = 0;
}
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 84aa2117c0ee..1a5a75acf73e 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -320,7 +320,7 @@ static int eppconfig(struct baycom_state *bc)
sprintf(portarg, "%ld", bc->pdev->port->base);
printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
- return call_usermodehelper(eppconfig_path, argv, envp, 1);
+ return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
}
/* ---------------------------------------------------------------------- */
@@ -1159,8 +1159,7 @@ static void baycom_probe(struct net_device *dev)
/* Fill in the fields of the device structure */
bc->skb = NULL;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = baycom_set_mac_address;
dev->type = ARPHRD_AX25; /* AF_AX25 device */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 656f2789c9ba..5ddf8b0c34f9 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -64,7 +64,7 @@
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
-#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
@@ -83,6 +83,7 @@
#include <net/ip.h>
#include <net/arp.h>
+#include <net/net_namespace.h>
#include <linux/bpqether.h>
@@ -94,7 +95,6 @@ static char bpq_eth_addr[6];
static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
static int bpq_device_event(struct notifier_block *, unsigned long, void *);
-static const char *bpq_print_ethaddr(const unsigned char *);
static struct packet_type bpq_packet_type = {
.type = __constant_htons(ETH_P_BPQ),
@@ -172,6 +172,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
struct ethhdr *eth;
struct bpqdev *bpq;
+ if (dev->nd_net != &init_net)
+ goto drop;
+
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
@@ -283,7 +286,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
skb->protocol = ax25_type_trans(skb, dev);
skb_reset_network_header(skb);
- dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
+ dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
bpq->stats.tx_packets++;
bpq->stats.tx_bytes+=skb->len;
@@ -379,16 +382,6 @@ static int bpq_close(struct net_device *dev)
/*
* Proc filesystem
*/
-static const char * bpq_print_ethaddr(const unsigned char *e)
-{
- static char buf[18];
-
- sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- e[0], e[1], e[2], e[3], e[4], e[5]);
-
- return buf;
-}
-
static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
{
int i = 1;
@@ -413,12 +406,12 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++*pos;
if (v == SEQ_START_TOKEN)
- p = bpq_devices.next;
+ p = rcu_dereference(bpq_devices.next);
else
- p = ((struct bpqdev *)v)->bpq_list.next;
+ p = rcu_dereference(((struct bpqdev *)v)->bpq_list.next);
return (p == &bpq_devices) ? NULL
- : rcu_dereference(list_entry(p, struct bpqdev, bpq_list));
+ : list_entry(p, struct bpqdev, bpq_list);
}
static void bpq_seq_stop(struct seq_file *seq, void *v)
@@ -434,14 +427,16 @@ static int bpq_seq_show(struct seq_file *seq, void *v)
"dev ether destination accept from\n");
else {
const struct bpqdev *bpqdev = v;
+ DECLARE_MAC_BUF(mac);
seq_printf(seq, "%-5s %-10s %s ",
bpqdev->axdev->name, bpqdev->ethdev->name,
- bpq_print_ethaddr(bpqdev->dest_addr));
+ print_mac(mac, bpqdev->dest_addr));
- seq_printf(seq, "%s\n",
- (bpqdev->acpt_addr[0] & 0x01) ? "*"
- : bpq_print_ethaddr(bpqdev->acpt_addr));
+ if (is_multicast_ether_addr(bpqdev->acpt_addr))
+ seq_printf(seq, "*\n");
+ else
+ seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr));
}
return 0;
@@ -488,8 +483,7 @@ static void bpq_setup(struct net_device *dev)
dev->flags = 0;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
#endif
dev->type = ARPHRD_AX25;
@@ -559,6 +553,9 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
{
struct net_device *dev = (struct net_device *)ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
@@ -594,7 +591,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
static int __init bpq_init_driver(void)
{
#ifdef CONFIG_PROC_FS
- if (!proc_net_fops_create("bpqether", S_IRUGO, &bpq_info_fops)) {
+ if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) {
printk(KERN_ERR
"bpq: cannot create /proc/net/bpqether entry.\n");
return -ENOENT;
@@ -618,7 +615,7 @@ static void __exit bpq_cleanup_driver(void)
unregister_netdevice_notifier(&bpq_dev_notifier);
- proc_net_remove("bpqether");
+ proc_net_remove(&init_net, "bpqether");
rtnl_lock();
while (!list_empty(&bpq_devices)) {
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 3be8c5047599..bc02e4694804 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -453,8 +453,8 @@ static int __init setup_adapter(int card_base, int type, int n)
int scc_base = card_base + hw[type].scc_offset;
char *chipnames[] = CHIPNAMES;
- /* Allocate memory */
- info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
+ /* Initialize what is necessary for write_scc and write_scc_data */
+ info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
if (!info) {
printk(KERN_ERR "dmascc: "
"could not allocate memory for %s at %#3x\n",
@@ -462,8 +462,6 @@ static int __init setup_adapter(int card_base, int type, int n)
goto out;
}
- /* Initialize what is necessary for write_scc and write_scc_data */
- memset(info, 0, sizeof(struct scc_info));
info->dev[0] = alloc_netdev(0, "", dev_setup);
if (!info->dev[0]) {
@@ -583,8 +581,7 @@ static int __init setup_adapter(int card_base, int type, int n)
dev->do_ioctl = scc_ioctl;
dev->hard_start_xmit = scc_send_packet;
dev->get_stats = scc_get_stats;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = scc_set_mac_address;
}
if (register_netdev(info->dev[0])) {
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index b33adc6a340b..ae9629fa6882 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -682,8 +682,7 @@ static void hdlcdrv_setup(struct net_device *dev)
s->skb = NULL;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = hdlcdrv_set_mac_address;
dev->type = ARPHRD_AX25; /* AF_AX25 device */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d08fbc396648..9e43c47691ca 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -578,8 +578,9 @@ static int ax_open_dev(struct net_device *dev)
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
/* Return the frame type ID */
-static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+static int ax_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
#ifdef CONFIG_INET
if (type != htons(ETH_P_AX25))
@@ -670,6 +671,11 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev)
return &ax->stats;
}
+static const struct header_ops ax_header_ops = {
+ .create = ax_header,
+ .rebuild = ax_rebuild_header,
+};
+
static void ax_setup(struct net_device *dev)
{
/* Finish setting up the DEVICE info. */
@@ -683,8 +689,8 @@ static void ax_setup(struct net_device *dev)
dev->addr_len = 0;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
- dev->hard_header = ax_header;
- dev->rebuild_header = ax_rebuild_header;
+ dev->header_ops = &ax_header_ops;
+
memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 6fdaad5a4577..353d13e543ce 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -174,6 +174,7 @@
#include <linux/seq_file.h>
#include <linux/bitops.h>
+#include <net/net_namespace.h>
#include <net/ax25.h>
#include <asm/irq.h>
@@ -1550,8 +1551,8 @@ static void scc_net_setup(struct net_device *dev)
dev->stop = scc_net_close;
dev->hard_start_xmit = scc_net_tx;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
+
dev->set_mac_address = scc_net_set_mac_address;
dev->get_stats = scc_net_get_stats;
dev->do_ioctl = scc_net_ioctl;
@@ -2114,7 +2115,7 @@ static int __init scc_init_driver (void)
}
rtnl_unlock();
- proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops);
+ proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops);
return 0;
}
@@ -2169,7 +2170,7 @@ static void __exit scc_cleanup_driver(void)
if (Vector_Latch)
release_region(Vector_Latch, 1);
- proc_net_remove("z8530drv");
+ proc_net_remove(&init_net, "z8530drv");
}
MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 467559debfd6..1c942862a3f4 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -65,6 +65,7 @@
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <net/net_namespace.h>
#include <asm/uaccess.h>
#include <linux/init.h>
@@ -1096,8 +1097,7 @@ static void yam_setup(struct net_device *dev)
skb_queue_head_init(&yp->send_queue);
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = yam_set_mac_address;
@@ -1142,7 +1142,7 @@ static int __init yam_init_driver(void)
yam_timer.expires = jiffies + HZ / 100;
add_timer(&yam_timer);
- proc_net_fops_create("yam", S_IRUGO, &yam_info_fops);
+ proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops);
return 0;
error:
while (--i >= 0) {
@@ -1174,7 +1174,7 @@ static void __exit yam_cleanup_driver(void)
kfree(p);
}
- proc_net_remove("yam");
+ proc_net_remove(&init_net, "yam");
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 99a36cc3f8df..c2c4f49d7578 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -122,8 +122,6 @@ static int __init do_hpp_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return hpp_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -168,6 +166,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
const char name[] = "HP-PC-LAN+";
int mem_start;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -182,7 +181,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
if (ei_debug && version_printed++ == 0)
printk(version);
- printk("%s: %s at %#3x,", dev->name, name, ioaddr);
+ printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
/* Retrieve and checksum the station address. */
outw(MAC_Page, ioaddr + HP_PAGING);
@@ -191,10 +190,11 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
unsigned char inval = inb(ioaddr + 8 + i);
dev->dev_addr[i] = inval;
checksum += inval;
- printk(" %2.2x", inval);
}
checksum += inb(ioaddr + 14);
+ printk("%s", print_mac(mac, dev->dev_addr));
+
if (checksum != 0xff) {
printk(" bad checksum %2.2x.\n", checksum);
retval = -ENODEV;
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 635b13c2e2aa..c649a8019beb 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -86,8 +86,6 @@ static int __init do_hp_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return hp_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -129,6 +127,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
int i, retval, board_id, wordmode;
const char *name;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -160,7 +159,9 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+
+ printk(" %s", print_mac(mac, dev->dev_addr));
/* Snarf the interrupt now. Someday this could be moved to open(). */
if (dev->irq < 2) {
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 8caa591c5649..e4fde17e2841 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -404,8 +404,6 @@ struct net_device * __init hp100_probe(int unit)
if (!dev)
return ERR_PTR(-ENODEV);
- SET_MODULE_OWNER(dev);
-
#ifdef HP100_DEBUG_B
hp100_outw(0x4200, TRACE);
printk("hp100: %s: probe\n", dev->name);
@@ -2095,9 +2093,9 @@ static void hp100_set_multicast_list(struct net_device *dev)
addrs = dmi->dmi_addr;
if ((*addrs & 0x01) == 0x01) { /* multicast address? */
#ifdef HP100_DEBUG
- printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ",
- dev->name, addrs[0], addrs[1], addrs[2],
- addrs[3], addrs[4], addrs[5]);
+ DECLARE_MAC_BUF(mac);
+ printk("hp100: %s: multicast = %s, ",
+ dev->name, print_mac(mac, addrs));
#endif
for (j = idx = 0; j < 6; j++) {
idx ^= *addrs++ & 0x3f;
@@ -2843,7 +2841,6 @@ static int __init hp100_eisa_probe (struct device *gendev)
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &edev->dev);
err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL);
@@ -2896,7 +2893,6 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
goto out0;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
@@ -2993,7 +2989,6 @@ static int __init hp100_isa_init(void)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
err = hp100_isa_probe(dev, hp100_port[i]);
if (!err)
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
index c991cb82ff22..be6e5bc7c881 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/hplance.c
@@ -141,7 +141,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
dev->poll_controller = lance_poll;
#endif
dev->hard_start_xmit = &lance_start_xmit;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0;
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index f970bfbb9db2..b96cf2dcb109 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -103,6 +103,7 @@ static int __devinit hydra_init(struct zorro_dev *z)
int start_page, stop_page;
int j;
int err;
+ DECLARE_MAC_BUF(mac);
static u32 hydra_offsets[16] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
@@ -112,7 +113,6 @@ static int __devinit hydra_init(struct zorro_dev *z)
dev = ____alloc_ei_netdev(0);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
for(j = 0; j < ETHER_ADDR_LEN; j++)
dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j));
@@ -163,10 +163,8 @@ static int __devinit hydra_init(struct zorro_dev *z)
zorro_set_drvdata(z, dev);
printk(KERN_INFO "%s: Hydra at 0x%08lx, address "
- "%02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
- dev->name, z->resource.start, dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5]);
+ "%s (hydra.c " HYDRA_VERSION ")\n",
+ dev->name, z->resource.start, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/ibm_emac/Kconfig b/drivers/net/ibm_emac/Kconfig
new file mode 100644
index 000000000000..f61c48047dc0
--- /dev/null
+++ b/drivers/net/ibm_emac/Kconfig
@@ -0,0 +1,70 @@
+config IBM_EMAC
+ tristate "PowerPC 4xx on-chip Ethernet support"
+ depends on 4xx && !PPC_MERGE
+ help
+ This driver supports the PowerPC 4xx EMAC family of on-chip
+ Ethernet controllers.
+
+config IBM_EMAC_RXB
+ int "Number of receive buffers"
+ depends on IBM_EMAC
+ default "128"
+
+config IBM_EMAC_TXB
+ int "Number of transmit buffers"
+ depends on IBM_EMAC
+ default "64"
+
+config IBM_EMAC_POLL_WEIGHT
+ int "MAL NAPI polling weight"
+ depends on IBM_EMAC
+ default "32"
+
+config IBM_EMAC_RX_COPY_THRESHOLD
+ int "RX skb copy threshold (bytes)"
+ depends on IBM_EMAC
+ default "256"
+
+config IBM_EMAC_RX_SKB_HEADROOM
+ int "Additional RX skb headroom (bytes)"
+ depends on IBM_EMAC
+ default "0"
+ help
+ Additional receive skb headroom. Note, that driver
+ will always reserve at least 2 bytes to make IP header
+ aligned, so usually there is no need to add any additional
+ headroom.
+
+ If unsure, set to 0.
+
+config IBM_EMAC_PHY_RX_CLK_FIX
+ bool "PHY Rx clock workaround"
+ depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
+ help
+ Enable this if EMAC attached to a PHY which doesn't generate
+ RX clock if there is no link, if this is the case, you will
+ see "TX disable timeout" or "RX disable timeout" in the system
+ log.
+
+ If unsure, say N.
+
+config IBM_EMAC_DEBUG
+ bool "Debugging"
+ depends on IBM_EMAC
+ default n
+
+config IBM_EMAC_ZMII
+ bool
+ depends on IBM_EMAC && (NP405H || NP405L || 44x)
+ default y
+
+config IBM_EMAC_RGMII
+ bool
+ depends on IBM_EMAC && 440GX
+ default y
+
+config IBM_EMAC_TAH
+ bool
+ depends on IBM_EMAC && 440GX
+ default y
+
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index f752e5fc65ba..73664f226f32 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -353,10 +353,9 @@ static void emac_hash_mc(struct ocp_enet_private *dev)
for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
int bit;
- DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
- dev->def->index,
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+ DECLARE_MAC_BUF(mac);
+ DBG2("%d: mc %s" NL,
+ dev->def->index, print_mac(mac, dmi->dmi_addr));
bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
@@ -1843,9 +1842,14 @@ static int emac_ethtool_nway_reset(struct net_device *ndev)
return res;
}
-static int emac_ethtool_get_stats_count(struct net_device *ndev)
+static int emac_get_sset_count(struct net_device *ndev, int sset)
{
- return EMAC_ETHTOOL_STATS_COUNT;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return EMAC_ETHTOOL_STATS_COUNT;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
@@ -1876,7 +1880,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
strcpy(info->version, DRV_VERSION);
info->fw_version[0] = '\0';
sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index);
- info->n_stats = emac_ethtool_get_stats_count(ndev);
info->regdump_len = emac_ethtool_get_regs_len(ndev);
}
@@ -1896,12 +1899,10 @@ static const struct ethtool_ops emac_ethtool_ops = {
.get_rx_csum = emac_ethtool_get_rx_csum,
.get_strings = emac_ethtool_get_strings,
- .get_stats_count = emac_ethtool_get_stats_count,
+ .get_sset_count = emac_get_sset_count,
.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
};
static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1942,6 +1943,7 @@ static int __init emac_probe(struct ocp_device *ocpdev)
struct ocp_device *maldev;
struct ocp_enet_private *dev;
int err, i;
+ DECLARE_MAC_BUF(mac);
DBG("%d: probe" NL, ocpdev->def->index);
@@ -1962,7 +1964,6 @@ static int __init emac_probe(struct ocp_device *ocpdev)
dev->ndev = ndev;
dev->ldev = &ocpdev->dev;
dev->def = ocpdev->def;
- SET_MODULE_OWNER(ndev);
/* Find MAL device we are connected to */
maldev =
@@ -2191,10 +2192,8 @@ static int __init emac_probe(struct ocp_device *ocpdev)
ocp_set_drvdata(ocpdev, dev);
- printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- ndev->name, dev->def->index,
- ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
- ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+ printk("%s: emac%d, MAC %s\n",
+ ndev->name, dev->def->index, print_mac(mac, ndev->dev_addr));
if (dev->phy.address >= 0)
printk("%s: found %s PHY (0x%02x)\n", ndev->name,
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c
index 92f970d402df..1f70906cfb98 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.c
+++ b/drivers/net/ibm_emac/ibm_emac_debug.c
@@ -132,7 +132,7 @@ void emac_dbg_register(int idx, struct ocp_enet_private *dev)
{
unsigned long flags;
- if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) {
+ if (idx >= ARRAY_SIZE(__emacs)) {
printk(KERN_WARNING
"invalid index %d when registering EMAC for debugging\n",
idx);
@@ -148,7 +148,7 @@ void mal_dbg_register(int idx, struct ibm_ocp_mal *mal)
{
unsigned long flags;
- if (idx >= sizeof(__mals) / sizeof(__mals[0])) {
+ if (idx >= ARRAY_SIZE(__mals)) {
printk(KERN_WARNING
"invalid index %d when registering MAL for debugging\n",
idx);
@@ -167,11 +167,11 @@ void emac_dbg_dump_all(void)
local_irq_save(flags);
- for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE(__mals); ++i)
if (__mals[i])
emac_mal_dump(__mals[i]);
- for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
if (__emacs[i])
emac_mac_dump(i, __emacs[i]);
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index cabd9846a5ee..4e49e8c4f871 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -207,10 +207,10 @@ static irqreturn_t mal_serr(int irq, void *dev_instance)
static inline void mal_schedule_poll(struct ibm_ocp_mal *mal)
{
- if (likely(netif_rx_schedule_prep(&mal->poll_dev))) {
+ if (likely(napi_schedule_prep(&mal->napi))) {
MAL_DBG2("%d: schedule_poll" NL, mal->def->index);
mal_disable_eob_irq(mal);
- __netif_rx_schedule(&mal->poll_dev);
+ __napi_schedule(&mal->napi);
} else
MAL_DBG2("%d: already in poll" NL, mal->def->index);
}
@@ -273,11 +273,11 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static int mal_poll(struct net_device *ndev, int *budget)
+static int mal_poll(struct napi_struct *napi, int budget)
{
- struct ibm_ocp_mal *mal = ndev->priv;
+ struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi);
struct list_head *l;
- int rx_work_limit = min(ndev->quota, *budget), received = 0, done;
+ int received = 0;
MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget,
rx_work_limit);
@@ -295,38 +295,34 @@ static int mal_poll(struct net_device *ndev, int *budget)
list_for_each(l, &mal->poll_list) {
struct mal_commac *mc =
list_entry(l, struct mal_commac, poll_list);
- int n = mc->ops->poll_rx(mc->dev, rx_work_limit);
+ int n = mc->ops->poll_rx(mc->dev, budget);
if (n) {
received += n;
- rx_work_limit -= n;
- if (rx_work_limit <= 0) {
- done = 0;
+ budget -= n;
+ if (budget <= 0)
goto more_work; // XXX What if this is the last one ?
- }
}
}
/* We need to disable IRQs to protect from RXDE IRQ here */
local_irq_disable();
- __netif_rx_complete(ndev);
+ __napi_complete(napi);
mal_enable_eob_irq(mal);
local_irq_enable();
- done = 1;
-
/* Check for "rotting" packet(s) */
list_for_each(l, &mal->poll_list) {
struct mal_commac *mc =
list_entry(l, struct mal_commac, poll_list);
if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) {
MAL_DBG2("%d: rotting packet" NL, mal->def->index);
- if (netif_rx_reschedule(ndev, received))
+ if (napi_reschedule(napi))
mal_disable_eob_irq(mal);
else
MAL_DBG2("%d: already in poll list" NL,
mal->def->index);
- if (rx_work_limit > 0)
+ if (budget > 0)
goto again;
else
goto more_work;
@@ -335,12 +331,8 @@ static int mal_poll(struct net_device *ndev, int *budget)
}
more_work:
- ndev->quota -= received;
- *budget -= received;
-
- MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget,
- done ? 0 : 1);
- return done ? 0 : 1;
+ MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received);
+ return received;
}
static void mal_reset(struct ibm_ocp_mal *mal)
@@ -425,11 +417,8 @@ static int __init mal_probe(struct ocp_device *ocpdev)
mal->def = ocpdev->def;
INIT_LIST_HEAD(&mal->poll_list);
- set_bit(__LINK_STATE_START, &mal->poll_dev.state);
- mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
- mal->poll_dev.poll = mal_poll;
- mal->poll_dev.priv = mal;
- atomic_set(&mal->poll_dev.refcnt, 1);
+ mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
+ mal->napi.poll = mal_poll;
INIT_LIST_HEAD(&mal->list);
@@ -520,11 +509,8 @@ static void __exit mal_remove(struct ocp_device *ocpdev)
MAL_DBG("%d: remove" NL, mal->def->index);
- /* Syncronize with scheduled polling,
- stolen from net/core/dev.c:dev_close()
- */
- clear_bit(__LINK_STATE_START, &mal->poll_dev.state);
- netif_poll_disable(&mal->poll_dev);
+ /* Synchronize with scheduled polling */
+ napi_disable(&mal->napi);
if (!list_empty(&mal->list)) {
/* This is *very* bad */
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index 64bc338acc6c..8f54d621994d 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -195,7 +195,7 @@ struct ibm_ocp_mal {
dcr_host_t dcrhost;
struct list_head poll_list;
- struct net_device poll_dev;
+ struct napi_struct napi;
struct list_head list;
u32 tx_chan_mask;
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig
new file mode 100644
index 000000000000..0d3e7380bad0
--- /dev/null
+++ b/drivers/net/ibm_newemac/Kconfig
@@ -0,0 +1,63 @@
+config IBM_NEW_EMAC
+ tristate "IBM EMAC Ethernet support"
+ depends on PPC_DCR && PPC_MERGE
+ help
+ This driver supports the IBM EMAC family of Ethernet controllers
+ typically found on 4xx embedded PowerPC chips, but also on the
+ Axon southbridge for Cell.
+
+config IBM_NEW_EMAC_RXB
+ int "Number of receive buffers"
+ depends on IBM_NEW_EMAC
+ default "128"
+
+config IBM_NEW_EMAC_TXB
+ int "Number of transmit buffers"
+ depends on IBM_NEW_EMAC
+ default "64"
+
+config IBM_NEW_EMAC_POLL_WEIGHT
+ int "MAL NAPI polling weight"
+ depends on IBM_NEW_EMAC
+ default "32"
+
+config IBM_NEW_EMAC_RX_COPY_THRESHOLD
+ int "RX skb copy threshold (bytes)"
+ depends on IBM_NEW_EMAC
+ default "256"
+
+config IBM_NEW_EMAC_RX_SKB_HEADROOM
+ int "Additional RX skb headroom (bytes)"
+ depends on IBM_NEW_EMAC
+ default "0"
+ help
+ Additional receive skb headroom. Note, that driver
+ will always reserve at least 2 bytes to make IP header
+ aligned, so usually there is no need to add any additional
+ headroom.
+
+ If unsure, set to 0.
+
+config IBM_NEW_EMAC_DEBUG
+ bool "Debugging"
+ depends on IBM_NEW_EMAC
+ default n
+
+# The options below has to be select'ed by the respective
+# processor types or platforms
+
+config IBM_NEW_EMAC_ZMII
+ bool
+ default n
+
+config IBM_NEW_EMAC_RGMII
+ bool
+ default n
+
+config IBM_NEW_EMAC_TAH
+ bool
+ default n
+
+config IBM_NEW_EMAC_EMAC4
+ bool
+ default n
diff --git a/drivers/net/ibm_newemac/Makefile b/drivers/net/ibm_newemac/Makefile
new file mode 100644
index 000000000000..0b5c99512762
--- /dev/null
+++ b/drivers/net/ibm_newemac/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the PowerPC 4xx on-chip ethernet driver
+#
+
+obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac.o
+
+ibm_newemac-y := mal.o core.o phy.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_ZMII) += zmii.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_RGMII) += rgmii.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_TAH) += tah.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_DEBUG) += debug.o
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
new file mode 100644
index 000000000000..8ea500961871
--- /dev/null
+++ b/drivers/net/ibm_newemac/core.c
@@ -0,0 +1,2906 @@
+/*
+ * drivers/net/ibm_newemac/core.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Armin Kuster <akuster@mvista.com>
+ * Johnnie Peters <jpeters@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include "core.h"
+
+/*
+ * Lack of dma_unmap_???? calls is intentional.
+ *
+ * API-correct usage requires additional support state information to be
+ * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to
+ * EMAC design (e.g. TX buffer passed from network stack can be split into
+ * several BDs, dma_map_single/dma_map_page can be used to map particular BD),
+ * maintaining such information will add additional overhead.
+ * Current DMA API implementation for 4xx processors only ensures cache coherency
+ * and dma_unmap_???? routines are empty and are likely to stay this way.
+ * I decided to omit dma_unmap_??? calls because I don't want to add additional
+ * complexity just for the sake of following some abstract API, when it doesn't
+ * add any real benefit to the driver. I understand that this decision maybe
+ * controversial, but I really tried to make code API-correct and efficient
+ * at the same time and didn't come up with code I liked :(. --ebs
+ */
+
+#define DRV_NAME "emac"
+#define DRV_VERSION "3.54"
+#define DRV_DESC "PPC 4xx OCP EMAC driver"
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR
+ ("Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>");
+MODULE_LICENSE("GPL");
+
+/*
+ * PPC64 doesn't (yet) have a cacheable_memcpy
+ */
+#ifdef CONFIG_PPC64
+#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n))
+#endif
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4)
+
+/* If packet size is less than this number, we allocate small skb and copy packet
+ * contents into it instead of just sending original big skb up
+ */
+#define EMAC_RX_COPY_THRESH CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD
+
+/* Since multiple EMACs share MDIO lines in various ways, we need
+ * to avoid re-using the same PHY ID in cases where the arch didn't
+ * setup precise phy_map entries
+ *
+ * XXX This is something that needs to be reworked as we can have multiple
+ * EMAC "sets" (multiple ASICs containing several EMACs) though we can
+ * probably require in that case to have explicit PHY IDs in the device-tree
+ */
+static u32 busy_phy_map;
+static DEFINE_MUTEX(emac_phy_map_lock);
+
+/* This is the wait queue used to wait on any event related to probe, that
+ * is discovery of MALs, other EMACs, ZMII/RGMIIs, etc...
+ */
+static DECLARE_WAIT_QUEUE_HEAD(emac_probe_wait);
+
+/* Having stable interface names is a doomed idea. However, it would be nice
+ * if we didn't have completely random interface names at boot too :-) It's
+ * just a matter of making everybody's life easier. Since we are doing
+ * threaded probing, it's a bit harder though. The base idea here is that
+ * we make up a list of all emacs in the device-tree before we register the
+ * driver. Every emac will then wait for the previous one in the list to
+ * initialize before itself. We should also keep that list ordered by
+ * cell_index.
+ * That list is only 4 entries long, meaning that additional EMACs don't
+ * get ordering guarantees unless EMAC_BOOT_LIST_SIZE is increased.
+ */
+
+#define EMAC_BOOT_LIST_SIZE 4
+static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE];
+
+/* How long should I wait for dependent devices ? */
+#define EMAC_PROBE_DEP_TIMEOUT (HZ * 5)
+
+/* I don't want to litter system log with timeout errors
+ * when we have brain-damaged PHY.
+ */
+static inline void emac_report_timeout_error(struct emac_instance *dev,
+ const char *error)
+{
+ if (net_ratelimit())
+ printk(KERN_ERR "%s: %s\n", dev->ndev->name, error);
+}
+
+/* PHY polling intervals */
+#define PHY_POLL_LINK_ON HZ
+#define PHY_POLL_LINK_OFF (HZ / 5)
+
+/* Graceful stop timeouts in us.
+ * We should allow up to 1 frame time (full-duplex, ignoring collisions)
+ */
+#define STOP_TIMEOUT_10 1230
+#define STOP_TIMEOUT_100 124
+#define STOP_TIMEOUT_1000 13
+#define STOP_TIMEOUT_1000_JUMBO 73
+
+/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */
+static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
+ "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum",
+ "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom",
+ "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu",
+ "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet",
+ "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error",
+ "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range",
+ "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun",
+ "rx_bad_packet", "rx_runt_packet", "rx_short_event",
+ "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long",
+ "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors",
+ "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral",
+ "tx_bd_excessive_collisions", "tx_bd_late_collision",
+ "tx_bd_multple_collisions", "tx_bd_single_collision",
+ "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe",
+ "tx_errors"
+};
+
+static irqreturn_t emac_irq(int irq, void *dev_instance);
+static void emac_clean_tx_ring(struct emac_instance *dev);
+static void __emac_set_multicast_list(struct emac_instance *dev);
+
+static inline int emac_phy_supports_gige(int phy_mode)
+{
+ return phy_mode == PHY_MODE_GMII ||
+ phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+static inline int emac_phy_gpcs(int phy_mode)
+{
+ return phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+static inline void emac_tx_enable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "tx_enable" NL);
+
+ r = in_be32(&p->mr0);
+ if (!(r & EMAC_MR0_TXE))
+ out_be32(&p->mr0, r | EMAC_MR0_TXE);
+}
+
+static void emac_tx_disable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "tx_disable" NL);
+
+ r = in_be32(&p->mr0);
+ if (r & EMAC_MR0_TXE) {
+ int n = dev->stop_timeout;
+ out_be32(&p->mr0, r & ~EMAC_MR0_TXE);
+ while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) {
+ udelay(1);
+ --n;
+ }
+ if (unlikely(!n))
+ emac_report_timeout_error(dev, "TX disable timeout");
+ }
+}
+
+static void emac_rx_enable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ if (unlikely(test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags)))
+ goto out;
+
+ DBG(dev, "rx_enable" NL);
+
+ r = in_be32(&p->mr0);
+ if (!(r & EMAC_MR0_RXE)) {
+ if (unlikely(!(r & EMAC_MR0_RXI))) {
+ /* Wait if previous async disable is still in progress */
+ int n = dev->stop_timeout;
+ while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+ udelay(1);
+ --n;
+ }
+ if (unlikely(!n))
+ emac_report_timeout_error(dev,
+ "RX disable timeout");
+ }
+ out_be32(&p->mr0, r | EMAC_MR0_RXE);
+ }
+ out:
+ ;
+}
+
+static void emac_rx_disable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "rx_disable" NL);
+
+ r = in_be32(&p->mr0);
+ if (r & EMAC_MR0_RXE) {
+ int n = dev->stop_timeout;
+ out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
+ while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+ udelay(1);
+ --n;
+ }
+ if (unlikely(!n))
+ emac_report_timeout_error(dev, "RX disable timeout");
+ }
+}
+
+static inline void emac_netif_stop(struct emac_instance *dev)
+{
+ netif_tx_lock_bh(dev->ndev);
+ dev->no_mcast = 1;
+ netif_tx_unlock_bh(dev->ndev);
+ dev->ndev->trans_start = jiffies; /* prevent tx timeout */
+ mal_poll_disable(dev->mal, &dev->commac);
+ netif_tx_disable(dev->ndev);
+}
+
+static inline void emac_netif_start(struct emac_instance *dev)
+{
+ netif_tx_lock_bh(dev->ndev);
+ dev->no_mcast = 0;
+ if (dev->mcast_pending && netif_running(dev->ndev))
+ __emac_set_multicast_list(dev);
+ netif_tx_unlock_bh(dev->ndev);
+
+ netif_wake_queue(dev->ndev);
+
+ /* NOTE: unconditional netif_wake_queue is only appropriate
+ * so long as all callers are assured to have free tx slots
+ * (taken from tg3... though the case where that is wrong is
+ * not terribly harmful)
+ */
+ mal_poll_enable(dev->mal, &dev->commac);
+}
+
+static inline void emac_rx_disable_async(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "rx_disable_async" NL);
+
+ r = in_be32(&p->mr0);
+ if (r & EMAC_MR0_RXE)
+ out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
+}
+
+static int emac_reset(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ int n = 20;
+
+ DBG(dev, "reset" NL);
+
+ if (!dev->reset_failed) {
+ /* 40x erratum suggests stopping RX channel before reset,
+ * we stop TX as well
+ */
+ emac_rx_disable(dev);
+ emac_tx_disable(dev);
+ }
+
+ out_be32(&p->mr0, EMAC_MR0_SRST);
+ while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
+ --n;
+
+ if (n) {
+ dev->reset_failed = 0;
+ return 0;
+ } else {
+ emac_report_timeout_error(dev, "reset timeout");
+ dev->reset_failed = 1;
+ return -ETIMEDOUT;
+ }
+}
+
+static void emac_hash_mc(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u16 gaht[4] = { 0 };
+ struct dev_mc_list *dmi;
+
+ DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count);
+
+ for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
+ int bit;
+ DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
+ dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+ dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+
+ bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
+ gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
+ }
+ out_be32(&p->gaht1, gaht[0]);
+ out_be32(&p->gaht2, gaht[1]);
+ out_be32(&p->gaht3, gaht[2]);
+ out_be32(&p->gaht4, gaht[3]);
+}
+
+static inline u32 emac_iff2rmr(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ u32 r;
+
+ r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE;
+
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r |= EMAC4_RMR_BASE;
+ else
+ r |= EMAC_RMR_BASE;
+
+ if (ndev->flags & IFF_PROMISC)
+ r |= EMAC_RMR_PME;
+ else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32)
+ r |= EMAC_RMR_PMME;
+ else if (ndev->mc_count > 0)
+ r |= EMAC_RMR_MAE;
+
+ return r;
+}
+
+static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+ u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC_MR1_TR0_MULT;
+
+ DBG2(dev, "__emac_calc_base_mr1" NL);
+
+ switch(tx_size) {
+ case 2048:
+ ret |= EMAC_MR1_TFS_2K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, tx_size);
+ }
+
+ switch(rx_size) {
+ case 16384:
+ ret |= EMAC_MR1_RFS_16K;
+ break;
+ case 4096:
+ ret |= EMAC_MR1_RFS_4K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, rx_size);
+ }
+
+ return ret;
+}
+
+static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+ u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR |
+ EMAC4_MR1_OBCI(dev->opb_bus_freq);
+
+ DBG2(dev, "__emac4_calc_base_mr1" NL);
+
+ switch(tx_size) {
+ case 4096:
+ ret |= EMAC4_MR1_TFS_4K;
+ break;
+ case 2048:
+ ret |= EMAC4_MR1_TFS_2K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, tx_size);
+ }
+
+ switch(rx_size) {
+ case 16384:
+ ret |= EMAC4_MR1_RFS_16K;
+ break;
+ case 4096:
+ ret |= EMAC4_MR1_RFS_4K;
+ break;
+ case 2048:
+ ret |= EMAC4_MR1_RFS_2K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, rx_size);
+ }
+
+ return ret;
+}
+
+static u32 emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+ return emac_has_feature(dev, EMAC_FTR_EMAC4) ?
+ __emac4_calc_base_mr1(dev, tx_size, rx_size) :
+ __emac_calc_base_mr1(dev, tx_size, rx_size);
+}
+
+static inline u32 emac_calc_trtr(struct emac_instance *dev, unsigned int size)
+{
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ return ((size >> 6) - 1) << EMAC_TRTR_SHIFT_EMAC4;
+ else
+ return ((size >> 6) - 1) << EMAC_TRTR_SHIFT;
+}
+
+static inline u32 emac_calc_rwmr(struct emac_instance *dev,
+ unsigned int low, unsigned int high)
+{
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ return (low << 22) | ( (high & 0x3ff) << 6);
+ else
+ return (low << 23) | ( (high & 0x1ff) << 7);
+}
+
+static int emac_configure(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ struct net_device *ndev = dev->ndev;
+ int tx_size, rx_size;
+ u32 r, mr1 = 0;
+
+ DBG(dev, "configure" NL);
+
+ if (emac_reset(dev) < 0)
+ return -ETIMEDOUT;
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ tah_reset(dev->tah_dev);
+
+ DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n",
+ dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
+
+ /* Default fifo sizes */
+ tx_size = dev->tx_fifo_size;
+ rx_size = dev->rx_fifo_size;
+
+ /* Check for full duplex */
+ if (dev->phy.duplex == DUPLEX_FULL)
+ mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
+
+ /* Adjust fifo sizes, mr1 and timeouts based on link speed */
+ dev->stop_timeout = STOP_TIMEOUT_10;
+ switch (dev->phy.speed) {
+ case SPEED_1000:
+ if (emac_phy_gpcs(dev->phy.mode)) {
+ mr1 |= EMAC_MR1_MF_1000GPCS |
+ EMAC_MR1_MF_IPPA(dev->phy.address);
+
+ /* Put some arbitrary OUI, Manuf & Rev IDs so we can
+ * identify this GPCS PHY later.
+ */
+ out_be32(&p->ipcr, 0xdeadbeef);
+ } else
+ mr1 |= EMAC_MR1_MF_1000;
+
+ /* Extended fifo sizes */
+ tx_size = dev->tx_fifo_size_gige;
+ rx_size = dev->rx_fifo_size_gige;
+
+ if (dev->ndev->mtu > ETH_DATA_LEN) {
+ mr1 |= EMAC_MR1_JPSM;
+ dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
+ } else
+ dev->stop_timeout = STOP_TIMEOUT_1000;
+ break;
+ case SPEED_100:
+ mr1 |= EMAC_MR1_MF_100;
+ dev->stop_timeout = STOP_TIMEOUT_100;
+ break;
+ default: /* make gcc happy */
+ break;
+ }
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port,
+ dev->phy.speed);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed);
+
+ /* on 40x erratum forces us to NOT use integrated flow control,
+ * let's hope it works on 44x ;)
+ */
+ if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x) &&
+ dev->phy.duplex == DUPLEX_FULL) {
+ if (dev->phy.pause)
+ mr1 |= EMAC_MR1_EIFC | EMAC_MR1_APP;
+ else if (dev->phy.asym_pause)
+ mr1 |= EMAC_MR1_APP;
+ }
+
+ /* Add base settings & fifo sizes & program MR1 */
+ mr1 |= emac_calc_base_mr1(dev, tx_size, rx_size);
+ out_be32(&p->mr1, mr1);
+
+ /* Set individual MAC address */
+ out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]);
+ out_be32(&p->ialr, (ndev->dev_addr[2] << 24) |
+ (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) |
+ ndev->dev_addr[5]);
+
+ /* VLAN Tag Protocol ID */
+ out_be32(&p->vtpid, 0x8100);
+
+ /* Receive mode register */
+ r = emac_iff2rmr(ndev);
+ if (r & EMAC_RMR_MAE)
+ emac_hash_mc(dev);
+ out_be32(&p->rmr, r);
+
+ /* FIFOs thresholds */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r = EMAC4_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,
+ tx_size / 2 / dev->fifo_entry_size);
+ else
+ r = EMAC_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,
+ tx_size / 2 / dev->fifo_entry_size);
+ out_be32(&p->tmr1, r);
+ out_be32(&p->trtr, emac_calc_trtr(dev, tx_size / 2));
+
+ /* PAUSE frame is sent when RX FIFO reaches its high-water mark,
+ there should be still enough space in FIFO to allow the our link
+ partner time to process this frame and also time to send PAUSE
+ frame itself.
+
+ Here is the worst case scenario for the RX FIFO "headroom"
+ (from "The Switch Book") (100Mbps, without preamble, inter-frame gap):
+
+ 1) One maximum-length frame on TX 1522 bytes
+ 2) One PAUSE frame time 64 bytes
+ 3) PAUSE frame decode time allowance 64 bytes
+ 4) One maximum-length frame on RX 1522 bytes
+ 5) Round-trip propagation delay of the link (100Mb) 15 bytes
+ ----------
+ 3187 bytes
+
+ I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes)
+ low-water mark to RX_FIFO_SIZE / 8 (512 bytes)
+ */
+ r = emac_calc_rwmr(dev, rx_size / 8 / dev->fifo_entry_size,
+ rx_size / 4 / dev->fifo_entry_size);
+ out_be32(&p->rwmr, r);
+
+ /* Set PAUSE timer to the maximum */
+ out_be32(&p->ptr, 0xffff);
+
+ /* IRQ sources */
+ r = EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE |
+ EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE |
+ EMAC_ISR_IRE | EMAC_ISR_TE;
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r |= EMAC4_ISR_TXPE | EMAC4_ISR_RXPE /* | EMAC4_ISR_TXUE |
+ EMAC4_ISR_RXOE | */;
+ out_be32(&p->iser, r);
+
+ /* We need to take GPCS PHY out of isolate mode after EMAC reset */
+ if (emac_phy_gpcs(dev->phy.mode))
+ emac_mii_reset_phy(&dev->phy);
+
+ return 0;
+}
+
+static void emac_reinitialize(struct emac_instance *dev)
+{
+ DBG(dev, "reinitialize" NL);
+
+ emac_netif_stop(dev);
+ if (!emac_configure(dev)) {
+ emac_tx_enable(dev);
+ emac_rx_enable(dev);
+ }
+ emac_netif_start(dev);
+}
+
+static void emac_full_tx_reset(struct emac_instance *dev)
+{
+ DBG(dev, "full_tx_reset" NL);
+
+ emac_tx_disable(dev);
+ mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);
+ emac_clean_tx_ring(dev);
+ dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0;
+
+ emac_configure(dev);
+
+ mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);
+ emac_tx_enable(dev);
+ emac_rx_enable(dev);
+}
+
+static void emac_reset_work(struct work_struct *work)
+{
+ struct emac_instance *dev = container_of(work, struct emac_instance, reset_work);
+
+ DBG(dev, "reset_work" NL);
+
+ mutex_lock(&dev->link_lock);
+ emac_netif_stop(dev);
+ emac_full_tx_reset(dev);
+ emac_netif_start(dev);
+ mutex_unlock(&dev->link_lock);
+}
+
+static void emac_tx_timeout(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ DBG(dev, "tx_timeout" NL);
+
+ schedule_work(&dev->reset_work);
+}
+
+
+static inline int emac_phy_done(struct emac_instance *dev, u32 stacr)
+{
+ int done = !!(stacr & EMAC_STACR_OC);
+
+ if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+ done = !done;
+
+ return done;
+};
+
+static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r = 0;
+ int n, err = -ETIMEDOUT;
+
+ mutex_lock(&dev->mdio_lock);
+
+ DBG2(dev, "mdio_read(%02x,%02x)" NL, id, reg);
+
+ /* Enable proper MDIO port */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+
+ /* Wait for management interface to become idle */
+ n = 10;
+ while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait idle\n");
+ goto bail;
+ }
+ }
+
+ /* Issue read command */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r = EMAC4_STACR_BASE(dev->opb_bus_freq);
+ else
+ r = EMAC_STACR_BASE(dev->opb_bus_freq);
+ if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+ r |= EMAC_STACR_OC;
+ if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+ r |= EMACX_STACR_STAC_READ;
+ else
+ r |= EMAC_STACR_STAC_READ;
+ r |= (reg & EMAC_STACR_PRA_MASK)
+ | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT);
+ out_be32(&p->stacr, r);
+
+ /* Wait for read to complete */
+ n = 100;
+ while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait complete\n");
+ goto bail;
+ }
+ }
+
+ if (unlikely(r & EMAC_STACR_PHYE)) {
+ DBG(dev, "mdio_read(%02x, %02x) failed" NL, id, reg);
+ err = -EREMOTEIO;
+ goto bail;
+ }
+
+ r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK);
+
+ DBG2(dev, "mdio_read -> %04x" NL, r);
+ err = 0;
+ bail:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_put_mdio(dev->zmii_dev, dev->zmii_port);
+ mutex_unlock(&dev->mdio_lock);
+
+ return err == 0 ? r : err;
+}
+
+static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
+ u16 val)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r = 0;
+ int n, err = -ETIMEDOUT;
+
+ mutex_lock(&dev->mdio_lock);
+
+ DBG2(dev, "mdio_write(%02x,%02x,%04x)" NL, id, reg, val);
+
+ /* Enable proper MDIO port */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+
+ /* Wait for management interface to be idle */
+ n = 10;
+ while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait idle\n");
+ goto bail;
+ }
+ }
+
+ /* Issue write command */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r = EMAC4_STACR_BASE(dev->opb_bus_freq);
+ else
+ r = EMAC_STACR_BASE(dev->opb_bus_freq);
+ if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+ r |= EMAC_STACR_OC;
+ if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+ r |= EMACX_STACR_STAC_WRITE;
+ else
+ r |= EMAC_STACR_STAC_WRITE;
+ r |= (reg & EMAC_STACR_PRA_MASK) |
+ ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) |
+ (val << EMAC_STACR_PHYD_SHIFT);
+ out_be32(&p->stacr, r);
+
+ /* Wait for write to complete */
+ n = 100;
+ while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait complete\n");
+ goto bail;
+ }
+ }
+ err = 0;
+ bail:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_put_mdio(dev->zmii_dev, dev->zmii_port);
+ mutex_unlock(&dev->mdio_lock);
+}
+
+static int emac_mdio_read(struct net_device *ndev, int id, int reg)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int res;
+
+ res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
+ (u8) id, (u8) reg);
+ return res;
+}
+
+static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
+ (u8) id, (u8) reg, (u16) val);
+}
+
+/* Tx lock BH */
+static void __emac_set_multicast_list(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 rmr = emac_iff2rmr(dev->ndev);
+
+ DBG(dev, "__multicast %08x" NL, rmr);
+
+ /* I decided to relax register access rules here to avoid
+ * full EMAC reset.
+ *
+ * There is a real problem with EMAC4 core if we use MWSW_001 bit
+ * in MR1 register and do a full EMAC reset.
+ * One TX BD status update is delayed and, after EMAC reset, it
+ * never happens, resulting in TX hung (it'll be recovered by TX
+ * timeout handler eventually, but this is just gross).
+ * So we either have to do full TX reset or try to cheat here :)
+ *
+ * The only required change is to RX mode register, so I *think* all
+ * we need is just to stop RX channel. This seems to work on all
+ * tested SoCs. --ebs
+ *
+ * If we need the full reset, we might just trigger the workqueue
+ * and do it async... a bit nasty but should work --BenH
+ */
+ dev->mcast_pending = 0;
+ emac_rx_disable(dev);
+ if (rmr & EMAC_RMR_MAE)
+ emac_hash_mc(dev);
+ out_be32(&p->rmr, rmr);
+ emac_rx_enable(dev);
+}
+
+/* Tx lock BH */
+static void emac_set_multicast_list(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ DBG(dev, "multicast" NL);
+
+ BUG_ON(!netif_running(dev->ndev));
+
+ if (dev->no_mcast) {
+ dev->mcast_pending = 1;
+ return;
+ }
+ __emac_set_multicast_list(dev);
+}
+
+static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
+{
+ int rx_sync_size = emac_rx_sync_size(new_mtu);
+ int rx_skb_size = emac_rx_skb_size(new_mtu);
+ int i, ret = 0;
+
+ mutex_lock(&dev->link_lock);
+ emac_netif_stop(dev);
+ emac_rx_disable(dev);
+ mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);
+
+ if (dev->rx_sg_skb) {
+ ++dev->estats.rx_dropped_resize;
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ }
+
+ /* Make a first pass over RX ring and mark BDs ready, dropping
+ * non-processed packets on the way. We need this as a separate pass
+ * to simplify error recovery in the case of allocation failure later.
+ */
+ for (i = 0; i < NUM_RX_BUFF; ++i) {
+ if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST)
+ ++dev->estats.rx_dropped_resize;
+
+ dev->rx_desc[i].data_len = 0;
+ dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY |
+ (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+ }
+
+ /* Reallocate RX ring only if bigger skb buffers are required */
+ if (rx_skb_size <= dev->rx_skb_size)
+ goto skip;
+
+ /* Second pass, allocate new skbs */
+ for (i = 0; i < NUM_RX_BUFF; ++i) {
+ struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto oom;
+ }
+
+ BUG_ON(!dev->rx_skb[i]);
+ dev_kfree_skb(dev->rx_skb[i]);
+
+ skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);
+ dev->rx_desc[i].data_ptr =
+ dma_map_single(&dev->ofdev->dev, skb->data - 2, rx_sync_size,
+ DMA_FROM_DEVICE) + 2;
+ dev->rx_skb[i] = skb;
+ }
+ skip:
+ /* Check if we need to change "Jumbo" bit in MR1 */
+ if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) {
+ /* This is to prevent starting RX channel in emac_rx_enable() */
+ set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+
+ dev->ndev->mtu = new_mtu;
+ emac_full_tx_reset(dev);
+ }
+
+ mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu));
+ oom:
+ /* Restart RX */
+ clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+ dev->rx_slot = 0;
+ mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+ emac_rx_enable(dev);
+ emac_netif_start(dev);
+ mutex_unlock(&dev->link_lock);
+
+ return ret;
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int ret = 0;
+
+ if (new_mtu < EMAC_MIN_MTU || new_mtu > dev->max_mtu)
+ return -EINVAL;
+
+ DBG(dev, "change_mtu(%d)" NL, new_mtu);
+
+ if (netif_running(ndev)) {
+ /* Check if we really need to reinitalize RX ring */
+ if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu))
+ ret = emac_resize_rx_ring(dev, new_mtu);
+ }
+
+ if (!ret) {
+ ndev->mtu = new_mtu;
+ dev->rx_skb_size = emac_rx_skb_size(new_mtu);
+ dev->rx_sync_size = emac_rx_sync_size(new_mtu);
+ }
+
+ return ret;
+}
+
+static void emac_clean_tx_ring(struct emac_instance *dev)
+{
+ int i;
+
+ for (i = 0; i < NUM_TX_BUFF; ++i) {
+ if (dev->tx_skb[i]) {
+ dev_kfree_skb(dev->tx_skb[i]);
+ dev->tx_skb[i] = NULL;
+ if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY)
+ ++dev->estats.tx_dropped;
+ }
+ dev->tx_desc[i].ctrl = 0;
+ dev->tx_desc[i].data_ptr = 0;
+ }
+}
+
+static void emac_clean_rx_ring(struct emac_instance *dev)
+{
+ int i;
+
+ for (i = 0; i < NUM_RX_BUFF; ++i)
+ if (dev->rx_skb[i]) {
+ dev->rx_desc[i].ctrl = 0;
+ dev_kfree_skb(dev->rx_skb[i]);
+ dev->rx_skb[i] = NULL;
+ dev->rx_desc[i].data_ptr = 0;
+ }
+
+ if (dev->rx_sg_skb) {
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ }
+}
+
+static inline int emac_alloc_rx_skb(struct emac_instance *dev, int slot,
+ gfp_t flags)
+{
+ struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ dev->rx_skb[slot] = skb;
+ dev->rx_desc[slot].data_len = 0;
+
+ skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);
+ dev->rx_desc[slot].data_ptr =
+ dma_map_single(&dev->ofdev->dev, skb->data - 2, dev->rx_sync_size,
+ DMA_FROM_DEVICE) + 2;
+ wmb();
+ dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+ (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+
+ return 0;
+}
+
+static void emac_print_link_status(struct emac_instance *dev)
+{
+ if (netif_carrier_ok(dev->ndev))
+ printk(KERN_INFO "%s: link is up, %d %s%s\n",
+ dev->ndev->name, dev->phy.speed,
+ dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX",
+ dev->phy.pause ? ", pause enabled" :
+ dev->phy.asym_pause ? ", asymmetric pause enabled" : "");
+ else
+ printk(KERN_INFO "%s: link is down\n", dev->ndev->name);
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_open(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int err, i;
+
+ DBG(dev, "open" NL);
+
+ /* Setup error IRQ handler */
+ err = request_irq(dev->emac_irq, emac_irq, 0, "EMAC", dev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to request IRQ %d\n",
+ ndev->name, dev->emac_irq);
+ return err;
+ }
+
+ /* Allocate RX ring */
+ for (i = 0; i < NUM_RX_BUFF; ++i)
+ if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) {
+ printk(KERN_ERR "%s: failed to allocate RX ring\n",
+ ndev->name);
+ goto oom;
+ }
+
+ dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = 0;
+ clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+ dev->rx_sg_skb = NULL;
+
+ mutex_lock(&dev->link_lock);
+
+ /* XXX Start PHY polling now. Shouldn't wr do like sungem instead and
+ * always poll the PHY even when the iface is down ? That would allow
+ * things like laptop-net to work. --BenH
+ */
+ if (dev->phy.address >= 0) {
+ int link_poll_interval;
+ if (dev->phy.def->ops->poll_link(&dev->phy)) {
+ dev->phy.def->ops->read_link(&dev->phy);
+ netif_carrier_on(dev->ndev);
+ link_poll_interval = PHY_POLL_LINK_ON;
+ } else {
+ netif_carrier_off(dev->ndev);
+ link_poll_interval = PHY_POLL_LINK_OFF;
+ }
+ dev->link_polling = 1;
+ wmb();
+ schedule_delayed_work(&dev->link_work, link_poll_interval);
+ emac_print_link_status(dev);
+ } else
+ netif_carrier_on(dev->ndev);
+
+ emac_configure(dev);
+ mal_poll_add(dev->mal, &dev->commac);
+ mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);
+ mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu));
+ mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+ emac_tx_enable(dev);
+ emac_rx_enable(dev);
+ emac_netif_start(dev);
+
+ mutex_unlock(&dev->link_lock);
+
+ return 0;
+ oom:
+ emac_clean_rx_ring(dev);
+ free_irq(dev->emac_irq, dev);
+
+ return -ENOMEM;
+}
+
+/* BHs disabled */
+#if 0
+static int emac_link_differs(struct emac_instance *dev)
+{
+ u32 r = in_be32(&dev->emacp->mr1);
+
+ int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF;
+ int speed, pause, asym_pause;
+
+ if (r & EMAC_MR1_MF_1000)
+ speed = SPEED_1000;
+ else if (r & EMAC_MR1_MF_100)
+ speed = SPEED_100;
+ else
+ speed = SPEED_10;
+
+ switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) {
+ case (EMAC_MR1_EIFC | EMAC_MR1_APP):
+ pause = 1;
+ asym_pause = 0;
+ break;
+ case EMAC_MR1_APP:
+ pause = 0;
+ asym_pause = 1;
+ break;
+ default:
+ pause = asym_pause = 0;
+ }
+ return speed != dev->phy.speed || duplex != dev->phy.duplex ||
+ pause != dev->phy.pause || asym_pause != dev->phy.asym_pause;
+}
+#endif
+
+static void emac_link_timer(struct work_struct *work)
+{
+ struct emac_instance *dev =
+ container_of((struct delayed_work *)work,
+ struct emac_instance, link_work);
+ int link_poll_interval;
+
+ mutex_lock(&dev->link_lock);
+
+ DBG2(dev, "link timer" NL);
+
+ if (dev->phy.def->ops->poll_link(&dev->phy)) {
+ if (!netif_carrier_ok(dev->ndev)) {
+ /* Get new link parameters */
+ dev->phy.def->ops->read_link(&dev->phy);
+
+ netif_carrier_on(dev->ndev);
+ emac_netif_stop(dev);
+ emac_full_tx_reset(dev);
+ emac_netif_start(dev);
+ emac_print_link_status(dev);
+ }
+ link_poll_interval = PHY_POLL_LINK_ON;
+ } else {
+ if (netif_carrier_ok(dev->ndev)) {
+ emac_reinitialize(dev);
+ netif_carrier_off(dev->ndev);
+ netif_tx_disable(dev->ndev);
+ emac_print_link_status(dev);
+ }
+ link_poll_interval = PHY_POLL_LINK_OFF;
+ }
+ schedule_delayed_work(&dev->link_work, link_poll_interval);
+
+ mutex_unlock(&dev->link_lock);
+}
+
+static void emac_force_link_update(struct emac_instance *dev)
+{
+ netif_carrier_off(dev->ndev);
+ if (dev->link_polling) {
+ cancel_rearming_delayed_work(&dev->link_work);
+ if (dev->link_polling)
+ schedule_delayed_work(&dev->link_work, PHY_POLL_LINK_OFF);
+ }
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_close(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ DBG(dev, "close" NL);
+
+ if (dev->phy.address >= 0)
+ cancel_rearming_delayed_work(&dev->link_work);
+
+ emac_netif_stop(dev);
+ flush_scheduled_work();
+
+ emac_rx_disable(dev);
+ emac_tx_disable(dev);
+ mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);
+ mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);
+ mal_poll_del(dev->mal, &dev->commac);
+
+ emac_clean_tx_ring(dev);
+ emac_clean_rx_ring(dev);
+
+ free_irq(dev->emac_irq, dev);
+
+ return 0;
+}
+
+static inline u16 emac_tx_csum(struct emac_instance *dev,
+ struct sk_buff *skb)
+{
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH &&
+ skb->ip_summed == CHECKSUM_PARTIAL)) {
+ ++dev->stats.tx_packets_csum;
+ return EMAC_TX_CTRL_TAH_CSUM;
+ }
+ return 0;
+}
+
+static inline int emac_xmit_finish(struct emac_instance *dev, int len)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ struct net_device *ndev = dev->ndev;
+
+ /* Send the packet out. If the if makes a significant perf
+ * difference, then we can store the TMR0 value in "dev"
+ * instead
+ */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ out_be32(&p->tmr0, EMAC4_TMR0_XMIT);
+ else
+ out_be32(&p->tmr0, EMAC_TMR0_XMIT);
+
+ if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) {
+ netif_stop_queue(ndev);
+ DBG2(dev, "stopped TX queue" NL);
+ }
+
+ ndev->trans_start = jiffies;
+ ++dev->stats.tx_packets;
+ dev->stats.tx_bytes += len;
+
+ return 0;
+}
+
+/* Tx lock BH */
+static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ unsigned int len = skb->len;
+ int slot;
+
+ u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
+ MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb);
+
+ slot = dev->tx_slot++;
+ if (dev->tx_slot == NUM_TX_BUFF) {
+ dev->tx_slot = 0;
+ ctrl |= MAL_TX_CTRL_WRAP;
+ }
+
+ DBG2(dev, "xmit(%u) %d" NL, len, slot);
+
+ dev->tx_skb[slot] = skb;
+ dev->tx_desc[slot].data_ptr = dma_map_single(&dev->ofdev->dev,
+ skb->data, len,
+ DMA_TO_DEVICE);
+ dev->tx_desc[slot].data_len = (u16) len;
+ wmb();
+ dev->tx_desc[slot].ctrl = ctrl;
+
+ return emac_xmit_finish(dev, len);
+}
+
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+static inline int emac_xmit_split(struct emac_instance *dev, int slot,
+ u32 pd, int len, int last, u16 base_ctrl)
+{
+ while (1) {
+ u16 ctrl = base_ctrl;
+ int chunk = min(len, MAL_MAX_TX_SIZE);
+ len -= chunk;
+
+ slot = (slot + 1) % NUM_TX_BUFF;
+
+ if (last && !len)
+ ctrl |= MAL_TX_CTRL_LAST;
+ if (slot == NUM_TX_BUFF - 1)
+ ctrl |= MAL_TX_CTRL_WRAP;
+
+ dev->tx_skb[slot] = NULL;
+ dev->tx_desc[slot].data_ptr = pd;
+ dev->tx_desc[slot].data_len = (u16) chunk;
+ dev->tx_desc[slot].ctrl = ctrl;
+ ++dev->tx_cnt;
+
+ if (!len)
+ break;
+
+ pd += chunk;
+ }
+ return slot;
+}
+
+/* Tx lock BH disabled (SG version for TAH equipped EMACs) */
+static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int len = skb->len, chunk;
+ int slot, i;
+ u16 ctrl;
+ u32 pd;
+
+ /* This is common "fast" path */
+ if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE))
+ return emac_start_xmit(skb, ndev);
+
+ len -= skb->data_len;
+
+ /* Note, this is only an *estimation*, we can still run out of empty
+ * slots because of the additional fragmentation into
+ * MAL_MAX_TX_SIZE-sized chunks
+ */
+ if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF))
+ goto stop_queue;
+
+ ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
+ emac_tx_csum(dev, skb);
+ slot = dev->tx_slot;
+
+ /* skb data */
+ dev->tx_skb[slot] = NULL;
+ chunk = min(len, MAL_MAX_TX_SIZE);
+ dev->tx_desc[slot].data_ptr = pd =
+ dma_map_single(&dev->ofdev->dev, skb->data, len, DMA_TO_DEVICE);
+ dev->tx_desc[slot].data_len = (u16) chunk;
+ len -= chunk;
+ if (unlikely(len))
+ slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags,
+ ctrl);
+ /* skb fragments */
+ for (i = 0; i < nr_frags; ++i) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ len = frag->size;
+
+ if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF))
+ goto undo_frame;
+
+ pd = dma_map_page(&dev->ofdev->dev, frag->page, frag->page_offset, len,
+ DMA_TO_DEVICE);
+
+ slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1,
+ ctrl);
+ }
+
+ DBG2(dev, "xmit_sg(%u) %d - %d" NL, skb->len, dev->tx_slot, slot);
+
+ /* Attach skb to the last slot so we don't release it too early */
+ dev->tx_skb[slot] = skb;
+
+ /* Send the packet out */
+ if (dev->tx_slot == NUM_TX_BUFF - 1)
+ ctrl |= MAL_TX_CTRL_WRAP;
+ wmb();
+ dev->tx_desc[dev->tx_slot].ctrl = ctrl;
+ dev->tx_slot = (slot + 1) % NUM_TX_BUFF;
+
+ return emac_xmit_finish(dev, skb->len);
+
+ undo_frame:
+ /* Well, too bad. Our previous estimation was overly optimistic.
+ * Undo everything.
+ */
+ while (slot != dev->tx_slot) {
+ dev->tx_desc[slot].ctrl = 0;
+ --dev->tx_cnt;
+ if (--slot < 0)
+ slot = NUM_TX_BUFF - 1;
+ }
+ ++dev->estats.tx_undo;
+
+ stop_queue:
+ netif_stop_queue(ndev);
+ DBG2(dev, "stopped TX queue" NL);
+ return 1;
+}
+#else
+# define emac_start_xmit_sg emac_start_xmit
+#endif /* !defined(CONFIG_IBM_NEW_EMAC_TAH) */
+
+/* Tx lock BHs */
+static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl)
+{
+ struct emac_error_stats *st = &dev->estats;
+
+ DBG(dev, "BD TX error %04x" NL, ctrl);
+
+ ++st->tx_bd_errors;
+ if (ctrl & EMAC_TX_ST_BFCS)
+ ++st->tx_bd_bad_fcs;
+ if (ctrl & EMAC_TX_ST_LCS)
+ ++st->tx_bd_carrier_loss;
+ if (ctrl & EMAC_TX_ST_ED)
+ ++st->tx_bd_excessive_deferral;
+ if (ctrl & EMAC_TX_ST_EC)
+ ++st->tx_bd_excessive_collisions;
+ if (ctrl & EMAC_TX_ST_LC)
+ ++st->tx_bd_late_collision;
+ if (ctrl & EMAC_TX_ST_MC)
+ ++st->tx_bd_multple_collisions;
+ if (ctrl & EMAC_TX_ST_SC)
+ ++st->tx_bd_single_collision;
+ if (ctrl & EMAC_TX_ST_UR)
+ ++st->tx_bd_underrun;
+ if (ctrl & EMAC_TX_ST_SQE)
+ ++st->tx_bd_sqe;
+}
+
+static void emac_poll_tx(void *param)
+{
+ struct emac_instance *dev = param;
+ u32 bad_mask;
+
+ DBG2(dev, "poll_tx, %d %d" NL, dev->tx_cnt, dev->ack_slot);
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ bad_mask = EMAC_IS_BAD_TX_TAH;
+ else
+ bad_mask = EMAC_IS_BAD_TX;
+
+ netif_tx_lock_bh(dev->ndev);
+ if (dev->tx_cnt) {
+ u16 ctrl;
+ int slot = dev->ack_slot, n = 0;
+ again:
+ ctrl = dev->tx_desc[slot].ctrl;
+ if (!(ctrl & MAL_TX_CTRL_READY)) {
+ struct sk_buff *skb = dev->tx_skb[slot];
+ ++n;
+
+ if (skb) {
+ dev_kfree_skb(skb);
+ dev->tx_skb[slot] = NULL;
+ }
+ slot = (slot + 1) % NUM_TX_BUFF;
+
+ if (unlikely(ctrl & bad_mask))
+ emac_parse_tx_error(dev, ctrl);
+
+ if (--dev->tx_cnt)
+ goto again;
+ }
+ if (n) {
+ dev->ack_slot = slot;
+ if (netif_queue_stopped(dev->ndev) &&
+ dev->tx_cnt < EMAC_TX_WAKEUP_THRESH)
+ netif_wake_queue(dev->ndev);
+
+ DBG2(dev, "tx %d pkts" NL, n);
+ }
+ }
+ netif_tx_unlock_bh(dev->ndev);
+}
+
+static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot,
+ int len)
+{
+ struct sk_buff *skb = dev->rx_skb[slot];
+
+ DBG2(dev, "recycle %d %d" NL, slot, len);
+
+ if (len)
+ dma_map_single(&dev->ofdev->dev, skb->data - 2,
+ EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE);
+
+ dev->rx_desc[slot].data_len = 0;
+ wmb();
+ dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+ (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+}
+
+static void emac_parse_rx_error(struct emac_instance *dev, u16 ctrl)
+{
+ struct emac_error_stats *st = &dev->estats;
+
+ DBG(dev, "BD RX error %04x" NL, ctrl);
+
+ ++st->rx_bd_errors;
+ if (ctrl & EMAC_RX_ST_OE)
+ ++st->rx_bd_overrun;
+ if (ctrl & EMAC_RX_ST_BP)
+ ++st->rx_bd_bad_packet;
+ if (ctrl & EMAC_RX_ST_RP)
+ ++st->rx_bd_runt_packet;
+ if (ctrl & EMAC_RX_ST_SE)
+ ++st->rx_bd_short_event;
+ if (ctrl & EMAC_RX_ST_AE)
+ ++st->rx_bd_alignment_error;
+ if (ctrl & EMAC_RX_ST_BFCS)
+ ++st->rx_bd_bad_fcs;
+ if (ctrl & EMAC_RX_ST_PTL)
+ ++st->rx_bd_packet_too_long;
+ if (ctrl & EMAC_RX_ST_ORE)
+ ++st->rx_bd_out_of_range;
+ if (ctrl & EMAC_RX_ST_IRE)
+ ++st->rx_bd_in_range;
+}
+
+static inline void emac_rx_csum(struct emac_instance *dev,
+ struct sk_buff *skb, u16 ctrl)
+{
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ if (!ctrl && dev->tah_dev) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ ++dev->stats.rx_packets_csum;
+ }
+#endif
+}
+
+static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
+{
+ if (likely(dev->rx_sg_skb != NULL)) {
+ int len = dev->rx_desc[slot].data_len;
+ int tot_len = dev->rx_sg_skb->len + len;
+
+ if (unlikely(tot_len + 2 > dev->rx_skb_size)) {
+ ++dev->estats.rx_dropped_mtu;
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ } else {
+ cacheable_memcpy(dev->rx_sg_skb->tail,
+ dev->rx_skb[slot]->data, len);
+ skb_put(dev->rx_sg_skb, len);
+ emac_recycle_rx_skb(dev, slot, len);
+ return 0;
+ }
+ }
+ emac_recycle_rx_skb(dev, slot, 0);
+ return -1;
+}
+
+/* NAPI poll context */
+static int emac_poll_rx(void *param, int budget)
+{
+ struct emac_instance *dev = param;
+ int slot = dev->rx_slot, received = 0;
+
+ DBG2(dev, "poll_rx(%d)" NL, budget);
+
+ again:
+ while (budget > 0) {
+ int len;
+ struct sk_buff *skb;
+ u16 ctrl = dev->rx_desc[slot].ctrl;
+
+ if (ctrl & MAL_RX_CTRL_EMPTY)
+ break;
+
+ skb = dev->rx_skb[slot];
+ mb();
+ len = dev->rx_desc[slot].data_len;
+
+ if (unlikely(!MAL_IS_SINGLE_RX(ctrl)))
+ goto sg;
+
+ ctrl &= EMAC_BAD_RX_MASK;
+ if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) {
+ emac_parse_rx_error(dev, ctrl);
+ ++dev->estats.rx_dropped_error;
+ emac_recycle_rx_skb(dev, slot, 0);
+ len = 0;
+ goto next;
+ }
+
+ if (len && len < EMAC_RX_COPY_THRESH) {
+ struct sk_buff *copy_skb =
+ alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC);
+ if (unlikely(!copy_skb))
+ goto oom;
+
+ skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2);
+ cacheable_memcpy(copy_skb->data - 2, skb->data - 2,
+ len + 2);
+ emac_recycle_rx_skb(dev, slot, len);
+ skb = copy_skb;
+ } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC)))
+ goto oom;
+
+ skb_put(skb, len);
+ push_packet:
+ skb->dev = dev->ndev;
+ skb->protocol = eth_type_trans(skb, dev->ndev);
+ emac_rx_csum(dev, skb, ctrl);
+
+ if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
+ ++dev->estats.rx_dropped_stack;
+ next:
+ ++dev->stats.rx_packets;
+ skip:
+ dev->stats.rx_bytes += len;
+ slot = (slot + 1) % NUM_RX_BUFF;
+ --budget;
+ ++received;
+ continue;
+ sg:
+ if (ctrl & MAL_RX_CTRL_FIRST) {
+ BUG_ON(dev->rx_sg_skb);
+ if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) {
+ DBG(dev, "rx OOM %d" NL, slot);
+ ++dev->estats.rx_dropped_oom;
+ emac_recycle_rx_skb(dev, slot, 0);
+ } else {
+ dev->rx_sg_skb = skb;
+ skb_put(skb, len);
+ }
+ } else if (!emac_rx_sg_append(dev, slot) &&
+ (ctrl & MAL_RX_CTRL_LAST)) {
+
+ skb = dev->rx_sg_skb;
+ dev->rx_sg_skb = NULL;
+
+ ctrl &= EMAC_BAD_RX_MASK;
+ if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) {
+ emac_parse_rx_error(dev, ctrl);
+ ++dev->estats.rx_dropped_error;
+ dev_kfree_skb(skb);
+ len = 0;
+ } else
+ goto push_packet;
+ }
+ goto skip;
+ oom:
+ DBG(dev, "rx OOM %d" NL, slot);
+ /* Drop the packet and recycle skb */
+ ++dev->estats.rx_dropped_oom;
+ emac_recycle_rx_skb(dev, slot, 0);
+ goto next;
+ }
+
+ if (received) {
+ DBG2(dev, "rx %d BDs" NL, received);
+ dev->rx_slot = slot;
+ }
+
+ if (unlikely(budget && test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) {
+ mb();
+ if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) {
+ DBG2(dev, "rx restart" NL);
+ received = 0;
+ goto again;
+ }
+
+ if (dev->rx_sg_skb) {
+ DBG2(dev, "dropping partial rx packet" NL);
+ ++dev->estats.rx_dropped_error;
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ }
+
+ clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+ mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+ emac_rx_enable(dev);
+ dev->rx_slot = 0;
+ }
+ return received;
+}
+
+/* NAPI poll context */
+static int emac_peek_rx(void *param)
+{
+ struct emac_instance *dev = param;
+
+ return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY);
+}
+
+/* NAPI poll context */
+static int emac_peek_rx_sg(void *param)
+{
+ struct emac_instance *dev = param;
+
+ int slot = dev->rx_slot;
+ while (1) {
+ u16 ctrl = dev->rx_desc[slot].ctrl;
+ if (ctrl & MAL_RX_CTRL_EMPTY)
+ return 0;
+ else if (ctrl & MAL_RX_CTRL_LAST)
+ return 1;
+
+ slot = (slot + 1) % NUM_RX_BUFF;
+
+ /* I'm just being paranoid here :) */
+ if (unlikely(slot == dev->rx_slot))
+ return 0;
+ }
+}
+
+/* Hard IRQ */
+static void emac_rxde(void *param)
+{
+ struct emac_instance *dev = param;
+
+ ++dev->estats.rx_stopped;
+ emac_rx_disable_async(dev);
+}
+
+/* Hard IRQ */
+static irqreturn_t emac_irq(int irq, void *dev_instance)
+{
+ struct emac_instance *dev = dev_instance;
+ struct emac_regs __iomem *p = dev->emacp;
+ struct emac_error_stats *st = &dev->estats;
+ u32 isr;
+
+ spin_lock(&dev->lock);
+
+ isr = in_be32(&p->isr);
+ out_be32(&p->isr, isr);
+
+ DBG(dev, "isr = %08x" NL, isr);
+
+ if (isr & EMAC4_ISR_TXPE)
+ ++st->tx_parity;
+ if (isr & EMAC4_ISR_RXPE)
+ ++st->rx_parity;
+ if (isr & EMAC4_ISR_TXUE)
+ ++st->tx_underrun;
+ if (isr & EMAC4_ISR_RXOE)
+ ++st->rx_fifo_overrun;
+ if (isr & EMAC_ISR_OVR)
+ ++st->rx_overrun;
+ if (isr & EMAC_ISR_BP)
+ ++st->rx_bad_packet;
+ if (isr & EMAC_ISR_RP)
+ ++st->rx_runt_packet;
+ if (isr & EMAC_ISR_SE)
+ ++st->rx_short_event;
+ if (isr & EMAC_ISR_ALE)
+ ++st->rx_alignment_error;
+ if (isr & EMAC_ISR_BFCS)
+ ++st->rx_bad_fcs;
+ if (isr & EMAC_ISR_PTLE)
+ ++st->rx_packet_too_long;
+ if (isr & EMAC_ISR_ORE)
+ ++st->rx_out_of_range;
+ if (isr & EMAC_ISR_IRE)
+ ++st->rx_in_range;
+ if (isr & EMAC_ISR_SQE)
+ ++st->tx_sqe;
+ if (isr & EMAC_ISR_TE)
+ ++st->tx_errors;
+
+ spin_unlock(&dev->lock);
+
+ return IRQ_HANDLED;
+}
+
+static struct net_device_stats *emac_stats(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ struct emac_stats *st = &dev->stats;
+ struct emac_error_stats *est = &dev->estats;
+ struct net_device_stats *nst = &dev->nstats;
+ unsigned long flags;
+
+ DBG2(dev, "stats" NL);
+
+ /* Compute "legacy" statistics */
+ spin_lock_irqsave(&dev->lock, flags);
+ nst->rx_packets = (unsigned long)st->rx_packets;
+ nst->rx_bytes = (unsigned long)st->rx_bytes;
+ nst->tx_packets = (unsigned long)st->tx_packets;
+ nst->tx_bytes = (unsigned long)st->tx_bytes;
+ nst->rx_dropped = (unsigned long)(est->rx_dropped_oom +
+ est->rx_dropped_error +
+ est->rx_dropped_resize +
+ est->rx_dropped_mtu);
+ nst->tx_dropped = (unsigned long)est->tx_dropped;
+
+ nst->rx_errors = (unsigned long)est->rx_bd_errors;
+ nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun +
+ est->rx_fifo_overrun +
+ est->rx_overrun);
+ nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error +
+ est->rx_alignment_error);
+ nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs +
+ est->rx_bad_fcs);
+ nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet +
+ est->rx_bd_short_event +
+ est->rx_bd_packet_too_long +
+ est->rx_bd_out_of_range +
+ est->rx_bd_in_range +
+ est->rx_runt_packet +
+ est->rx_short_event +
+ est->rx_packet_too_long +
+ est->rx_out_of_range +
+ est->rx_in_range);
+
+ nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors);
+ nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun +
+ est->tx_underrun);
+ nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss;
+ nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral +
+ est->tx_bd_excessive_collisions +
+ est->tx_bd_late_collision +
+ est->tx_bd_multple_collisions);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return nst;
+}
+
+static struct mal_commac_ops emac_commac_ops = {
+ .poll_tx = &emac_poll_tx,
+ .poll_rx = &emac_poll_rx,
+ .peek_rx = &emac_peek_rx,
+ .rxde = &emac_rxde,
+};
+
+static struct mal_commac_ops emac_commac_sg_ops = {
+ .poll_tx = &emac_poll_tx,
+ .poll_rx = &emac_poll_rx,
+ .peek_rx = &emac_peek_rx_sg,
+ .rxde = &emac_rxde,
+};
+
+/* Ethtool support */
+static int emac_ethtool_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ cmd->supported = dev->phy.features;
+ cmd->port = PORT_MII;
+ cmd->phy_address = dev->phy.address;
+ cmd->transceiver =
+ dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL;
+
+ mutex_lock(&dev->link_lock);
+ cmd->advertising = dev->phy.advertising;
+ cmd->autoneg = dev->phy.autoneg;
+ cmd->speed = dev->phy.speed;
+ cmd->duplex = dev->phy.duplex;
+ mutex_unlock(&dev->link_lock);
+
+ return 0;
+}
+
+static int emac_ethtool_set_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ u32 f = dev->phy.features;
+
+ DBG(dev, "set_settings(%d, %d, %d, 0x%08x)" NL,
+ cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising);
+
+ /* Basic sanity checks */
+ if (dev->phy.address < 0)
+ return -EOPNOTSUPP;
+ if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+ return -EINVAL;
+ if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_DISABLE) {
+ switch (cmd->speed) {
+ case SPEED_10:
+ if (cmd->duplex == DUPLEX_HALF
+ && !(f & SUPPORTED_10baseT_Half))
+ return -EINVAL;
+ if (cmd->duplex == DUPLEX_FULL
+ && !(f & SUPPORTED_10baseT_Full))
+ return -EINVAL;
+ break;
+ case SPEED_100:
+ if (cmd->duplex == DUPLEX_HALF
+ && !(f & SUPPORTED_100baseT_Half))
+ return -EINVAL;
+ if (cmd->duplex == DUPLEX_FULL
+ && !(f & SUPPORTED_100baseT_Full))
+ return -EINVAL;
+ break;
+ case SPEED_1000:
+ if (cmd->duplex == DUPLEX_HALF
+ && !(f & SUPPORTED_1000baseT_Half))
+ return -EINVAL;
+ if (cmd->duplex == DUPLEX_FULL
+ && !(f & SUPPORTED_1000baseT_Full))
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->link_lock);
+ dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed,
+ cmd->duplex);
+ mutex_unlock(&dev->link_lock);
+
+ } else {
+ if (!(f & SUPPORTED_Autoneg))
+ return -EINVAL;
+
+ mutex_lock(&dev->link_lock);
+ dev->phy.def->ops->setup_aneg(&dev->phy,
+ (cmd->advertising & f) |
+ (dev->phy.advertising &
+ (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause)));
+ mutex_unlock(&dev->link_lock);
+ }
+ emac_force_link_update(dev);
+
+ return 0;
+}
+
+static void emac_ethtool_get_ringparam(struct net_device *ndev,
+ struct ethtool_ringparam *rp)
+{
+ rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF;
+ rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF;
+}
+
+static void emac_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pp)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ mutex_lock(&dev->link_lock);
+ if ((dev->phy.features & SUPPORTED_Autoneg) &&
+ (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause)))
+ pp->autoneg = 1;
+
+ if (dev->phy.duplex == DUPLEX_FULL) {
+ if (dev->phy.pause)
+ pp->rx_pause = pp->tx_pause = 1;
+ else if (dev->phy.asym_pause)
+ pp->tx_pause = 1;
+ }
+ mutex_unlock(&dev->link_lock);
+}
+
+static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ return dev->tah_dev != 0;
+}
+
+static int emac_get_regs_len(struct emac_instance *dev)
+{
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ EMAC4_ETHTOOL_REGS_SIZE;
+ else
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ EMAC_ETHTOOL_REGS_SIZE;
+}
+
+static int emac_ethtool_get_regs_len(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int size;
+
+ size = sizeof(struct emac_ethtool_regs_hdr) +
+ emac_get_regs_len(dev) + mal_get_regs_len(dev->mal);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ size += zmii_get_regs_len(dev->zmii_dev);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ size += rgmii_get_regs_len(dev->rgmii_dev);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ size += tah_get_regs_len(dev->tah_dev);
+
+ return size;
+}
+
+static void *emac_dump_regs(struct emac_instance *dev, void *buf)
+{
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+
+ hdr->index = dev->cell_index;
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
+ hdr->version = EMAC4_ETHTOOL_REGS_VER;
+ memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE);
+ return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE);
+ } else {
+ hdr->version = EMAC_ETHTOOL_REGS_VER;
+ memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE);
+ return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE);
+ }
+}
+
+static void emac_ethtool_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *buf)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ struct emac_ethtool_regs_hdr *hdr = buf;
+
+ hdr->components = 0;
+ buf = hdr + 1;
+
+ buf = mal_dump_regs(dev->mal, buf);
+ buf = emac_dump_regs(dev, buf);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) {
+ hdr->components |= EMAC_ETHTOOL_REGS_ZMII;
+ buf = zmii_dump_regs(dev->zmii_dev, buf);
+ }
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {
+ hdr->components |= EMAC_ETHTOOL_REGS_RGMII;
+ buf = rgmii_dump_regs(dev->rgmii_dev, buf);
+ }
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) {
+ hdr->components |= EMAC_ETHTOOL_REGS_TAH;
+ buf = tah_dump_regs(dev->tah_dev, buf);
+ }
+}
+
+static int emac_ethtool_nway_reset(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int res = 0;
+
+ DBG(dev, "nway_reset" NL);
+
+ if (dev->phy.address < 0)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&dev->link_lock);
+ if (!dev->phy.autoneg) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising);
+ out:
+ mutex_unlock(&dev->link_lock);
+ emac_force_link_update(dev);
+ return res;
+}
+
+static int emac_ethtool_get_stats_count(struct net_device *ndev)
+{
+ return EMAC_ETHTOOL_STATS_COUNT;
+}
+
+static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
+ u8 * buf)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys));
+}
+
+static void emac_ethtool_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *estats,
+ u64 * tmp_stats)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ memcpy(tmp_stats, &dev->stats, sizeof(dev->stats));
+ tmp_stats += sizeof(dev->stats) / sizeof(u64);
+ memcpy(tmp_stats, &dev->estats, sizeof(dev->estats));
+}
+
+static void emac_ethtool_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ strcpy(info->driver, "ibm_emac");
+ strcpy(info->version, DRV_VERSION);
+ info->fw_version[0] = '\0';
+ sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
+ dev->cell_index, dev->ofdev->node->full_name);
+ info->n_stats = emac_ethtool_get_stats_count(ndev);
+ info->regdump_len = emac_ethtool_get_regs_len(ndev);
+}
+
+static const struct ethtool_ops emac_ethtool_ops = {
+ .get_settings = emac_ethtool_get_settings,
+ .set_settings = emac_ethtool_set_settings,
+ .get_drvinfo = emac_ethtool_get_drvinfo,
+
+ .get_regs_len = emac_ethtool_get_regs_len,
+ .get_regs = emac_ethtool_get_regs,
+
+ .nway_reset = emac_ethtool_nway_reset,
+
+ .get_ringparam = emac_ethtool_get_ringparam,
+ .get_pauseparam = emac_ethtool_get_pauseparam,
+
+ .get_rx_csum = emac_ethtool_get_rx_csum,
+
+ .get_strings = emac_ethtool_get_strings,
+ .get_stats_count = emac_ethtool_get_stats_count,
+ .get_ethtool_stats = emac_ethtool_get_ethtool_stats,
+
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+};
+
+static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ uint16_t *data = (uint16_t *) & rq->ifr_ifru;
+
+ DBG(dev, "ioctl %08x" NL, cmd);
+
+ if (dev->phy.address < 0)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCDEVPRIVATE:
+ data[0] = dev->phy.address;
+ /* Fall through */
+ case SIOCGMIIREG:
+ case SIOCDEVPRIVATE + 1:
+ data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]);
+ return 0;
+
+ case SIOCSMIIREG:
+ case SIOCDEVPRIVATE + 2:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ emac_mdio_write(ndev, dev->phy.address, data[1], data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+struct emac_depentry {
+ u32 phandle;
+ struct device_node *node;
+ struct of_device *ofdev;
+ void *drvdata;
+};
+
+#define EMAC_DEP_MAL_IDX 0
+#define EMAC_DEP_ZMII_IDX 1
+#define EMAC_DEP_RGMII_IDX 2
+#define EMAC_DEP_TAH_IDX 3
+#define EMAC_DEP_MDIO_IDX 4
+#define EMAC_DEP_PREV_IDX 5
+#define EMAC_DEP_COUNT 6
+
+static int __devinit emac_check_deps(struct emac_instance *dev,
+ struct emac_depentry *deps)
+{
+ int i, there = 0;
+ struct device_node *np;
+
+ for (i = 0; i < EMAC_DEP_COUNT; i++) {
+ /* no dependency on that item, allright */
+ if (deps[i].phandle == 0) {
+ there++;
+ continue;
+ }
+ /* special case for blist as the dependency might go away */
+ if (i == EMAC_DEP_PREV_IDX) {
+ np = *(dev->blist - 1);
+ if (np == NULL) {
+ deps[i].phandle = 0;
+ there++;
+ continue;
+ }
+ if (deps[i].node == NULL)
+ deps[i].node = of_node_get(np);
+ }
+ if (deps[i].node == NULL)
+ deps[i].node = of_find_node_by_phandle(deps[i].phandle);
+ if (deps[i].node == NULL)
+ continue;
+ if (deps[i].ofdev == NULL)
+ deps[i].ofdev = of_find_device_by_node(deps[i].node);
+ if (deps[i].ofdev == NULL)
+ continue;
+ if (deps[i].drvdata == NULL)
+ deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev);
+ if (deps[i].drvdata != NULL)
+ there++;
+ }
+ return (there == EMAC_DEP_COUNT);
+}
+
+static void emac_put_deps(struct emac_instance *dev)
+{
+ if (dev->mal_dev)
+ of_dev_put(dev->mal_dev);
+ if (dev->zmii_dev)
+ of_dev_put(dev->zmii_dev);
+ if (dev->rgmii_dev)
+ of_dev_put(dev->rgmii_dev);
+ if (dev->mdio_dev)
+ of_dev_put(dev->mdio_dev);
+ if (dev->tah_dev)
+ of_dev_put(dev->tah_dev);
+}
+
+static int __devinit emac_of_bus_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ /* We are only intereted in device addition */
+ if (action == BUS_NOTIFY_BOUND_DRIVER)
+ wake_up_all(&emac_probe_wait);
+ return 0;
+}
+
+static struct notifier_block emac_of_bus_notifier = {
+ .notifier_call = emac_of_bus_notify
+};
+
+static int __devinit emac_wait_deps(struct emac_instance *dev)
+{
+ struct emac_depentry deps[EMAC_DEP_COUNT];
+ int i, err;
+
+ memset(&deps, 0, sizeof(deps));
+
+ deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph;
+ deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph;
+ deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph;
+ if (dev->tah_ph)
+ deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph;
+ if (dev->mdio_ph)
+ deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph;
+ if (dev->blist && dev->blist > emac_boot_list)
+ deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu;
+ bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+ wait_event_timeout(emac_probe_wait,
+ emac_check_deps(dev, deps),
+ EMAC_PROBE_DEP_TIMEOUT);
+ bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+ err = emac_check_deps(dev, deps) ? 0 : -ENODEV;
+ for (i = 0; i < EMAC_DEP_COUNT; i++) {
+ if (deps[i].node)
+ of_node_put(deps[i].node);
+ if (err && deps[i].ofdev)
+ of_dev_put(deps[i].ofdev);
+ }
+ if (err == 0) {
+ dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev;
+ dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev;
+ dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev;
+ dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev;
+ dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev;
+ }
+ if (deps[EMAC_DEP_PREV_IDX].ofdev)
+ of_dev_put(deps[EMAC_DEP_PREV_IDX].ofdev);
+ return err;
+}
+
+static int __devinit emac_read_uint_prop(struct device_node *np, const char *name,
+ u32 *val, int fatal)
+{
+ int len;
+ const u32 *prop = of_get_property(np, name, &len);
+ if (prop == NULL || len < sizeof(u32)) {
+ if (fatal)
+ printk(KERN_ERR "%s: missing %s property\n",
+ np->full_name, name);
+ return -ENODEV;
+ }
+ *val = *prop;
+ return 0;
+}
+
+static int __devinit emac_init_phy(struct emac_instance *dev)
+{
+ struct device_node *np = dev->ofdev->node;
+ struct net_device *ndev = dev->ndev;
+ u32 phy_map, adv;
+ int i;
+
+ dev->phy.dev = ndev;
+ dev->phy.mode = dev->phy_mode;
+
+ /* PHY-less configuration.
+ * XXX I probably should move these settings to the dev tree
+ */
+ if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) {
+ emac_reset(dev);
+
+ /* PHY-less configuration.
+ * XXX I probably should move these settings to the dev tree
+ */
+ dev->phy.address = -1;
+ dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
+ dev->phy.pause = 1;
+
+ return 0;
+ }
+
+ mutex_lock(&emac_phy_map_lock);
+ phy_map = dev->phy_map | busy_phy_map;
+
+ DBG(dev, "PHY maps %08x %08x" NL, dev->phy_map, busy_phy_map);
+
+ dev->phy.mdio_read = emac_mdio_read;
+ dev->phy.mdio_write = emac_mdio_write;
+
+ /* Configure EMAC with defaults so we can at least use MDIO
+ * This is needed mostly for 440GX
+ */
+ if (emac_phy_gpcs(dev->phy.mode)) {
+ /* XXX
+ * Make GPCS PHY address equal to EMAC index.
+ * We probably should take into account busy_phy_map
+ * and/or phy_map here.
+ *
+ * Note that the busy_phy_map is currently global
+ * while it should probably be per-ASIC...
+ */
+ dev->phy.address = dev->cell_index;
+ }
+
+ emac_configure(dev);
+
+ if (dev->phy_address != 0xffffffff)
+ phy_map = ~(1 << dev->phy_address);
+
+ for (i = 0; i < 0x20; phy_map >>= 1, ++i)
+ if (!(phy_map & 1)) {
+ int r;
+ busy_phy_map |= 1 << i;
+
+ /* Quick check if there is a PHY at the address */
+ r = emac_mdio_read(dev->ndev, i, MII_BMCR);
+ if (r == 0xffff || r < 0)
+ continue;
+ if (!emac_mii_phy_probe(&dev->phy, i))
+ break;
+ }
+ mutex_unlock(&emac_phy_map_lock);
+ if (i == 0x20) {
+ printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);
+ return -ENXIO;
+ }
+
+ /* Init PHY */
+ if (dev->phy.def->ops->init)
+ dev->phy.def->ops->init(&dev->phy);
+
+ /* Disable any PHY features not supported by the platform */
+ dev->phy.def->features &= ~dev->phy_feat_exc;
+
+ /* Setup initial link parameters */
+ if (dev->phy.features & SUPPORTED_Autoneg) {
+ adv = dev->phy.features;
+ if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x))
+ adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+ /* Restart autonegotiation */
+ dev->phy.def->ops->setup_aneg(&dev->phy, adv);
+ } else {
+ u32 f = dev->phy.def->features;
+ int speed = SPEED_10, fd = DUPLEX_HALF;
+
+ /* Select highest supported speed/duplex */
+ if (f & SUPPORTED_1000baseT_Full) {
+ speed = SPEED_1000;
+ fd = DUPLEX_FULL;
+ } else if (f & SUPPORTED_1000baseT_Half)
+ speed = SPEED_1000;
+ else if (f & SUPPORTED_100baseT_Full) {
+ speed = SPEED_100;
+ fd = DUPLEX_FULL;
+ } else if (f & SUPPORTED_100baseT_Half)
+ speed = SPEED_100;
+ else if (f & SUPPORTED_10baseT_Full)
+ fd = DUPLEX_FULL;
+
+ /* Force link parameters */
+ dev->phy.def->ops->setup_forced(&dev->phy, speed, fd);
+ }
+ return 0;
+}
+
+static int __devinit emac_init_config(struct emac_instance *dev)
+{
+ struct device_node *np = dev->ofdev->node;
+ const void *p;
+ unsigned int plen;
+ const char *pm, *phy_modes[] = {
+ [PHY_MODE_NA] = "",
+ [PHY_MODE_MII] = "mii",
+ [PHY_MODE_RMII] = "rmii",
+ [PHY_MODE_SMII] = "smii",
+ [PHY_MODE_RGMII] = "rgmii",
+ [PHY_MODE_TBI] = "tbi",
+ [PHY_MODE_GMII] = "gmii",
+ [PHY_MODE_RTBI] = "rtbi",
+ [PHY_MODE_SGMII] = "sgmii",
+ };
+
+ /* Read config from device-tree */
+ if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "mal-tx-channel", &dev->mal_tx_chan, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "mal-rx-channel", &dev->mal_rx_chan, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "cell-index", &dev->cell_index, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "max-frame-size", &dev->max_mtu, 0))
+ dev->max_mtu = 1500;
+ if (emac_read_uint_prop(np, "rx-fifo-size", &dev->rx_fifo_size, 0))
+ dev->rx_fifo_size = 2048;
+ if (emac_read_uint_prop(np, "tx-fifo-size", &dev->tx_fifo_size, 0))
+ dev->tx_fifo_size = 2048;
+ if (emac_read_uint_prop(np, "rx-fifo-size-gige", &dev->rx_fifo_size_gige, 0))
+ dev->rx_fifo_size_gige = dev->rx_fifo_size;
+ if (emac_read_uint_prop(np, "tx-fifo-size-gige", &dev->tx_fifo_size_gige, 0))
+ dev->tx_fifo_size_gige = dev->tx_fifo_size;
+ if (emac_read_uint_prop(np, "phy-address", &dev->phy_address, 0))
+ dev->phy_address = 0xffffffff;
+ if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
+ dev->phy_map = 0xffffffff;
+ if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
+ dev->tah_ph = 0;
+ if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0))
+ dev->tah_ph = 0;
+ if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0))
+ dev->mdio_ph = 0;
+ if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0))
+ dev->zmii_ph = 0;;
+ if (emac_read_uint_prop(np, "zmii-channel", &dev->zmii_port, 0))
+ dev->zmii_port = 0xffffffff;;
+ if (emac_read_uint_prop(np, "rgmii-device", &dev->rgmii_ph, 0))
+ dev->rgmii_ph = 0;;
+ if (emac_read_uint_prop(np, "rgmii-channel", &dev->rgmii_port, 0))
+ dev->rgmii_port = 0xffffffff;;
+ if (emac_read_uint_prop(np, "fifo-entry-size", &dev->fifo_entry_size, 0))
+ dev->fifo_entry_size = 16;
+ if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0))
+ dev->mal_burst_size = 256;
+
+ /* PHY mode needs some decoding */
+ dev->phy_mode = PHY_MODE_NA;
+ pm = of_get_property(np, "phy-mode", &plen);
+ if (pm != NULL) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
+ if (!strcasecmp(pm, phy_modes[i])) {
+ dev->phy_mode = i;
+ break;
+ }
+ }
+
+ /* Backward compat with non-final DT */
+ if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) {
+ u32 nmode = *(const u32 *)pm;
+ if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII)
+ dev->phy_mode = nmode;
+ }
+
+ /* Check EMAC version */
+ if (of_device_is_compatible(np, "ibm,emac4"))
+ dev->features |= EMAC_FTR_EMAC4;
+ if (of_device_is_compatible(np, "ibm,emac-axon")
+ || of_device_is_compatible(np, "ibm,emac-440epx"))
+ dev->features |= EMAC_FTR_HAS_AXON_STACR
+ | EMAC_FTR_STACR_OC_INVERT;
+ if (of_device_is_compatible(np, "ibm,emac-440spe"))
+ dev->features |= EMAC_FTR_STACR_OC_INVERT;
+
+ /* Fixup some feature bits based on the device tree and verify
+ * we have support for them compiled in
+ */
+ if (dev->tah_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ dev->features |= EMAC_FTR_HAS_TAH;
+#else
+ printk(KERN_ERR "%s: TAH support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
+ if (dev->zmii_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+ dev->features |= EMAC_FTR_HAS_ZMII;
+#else
+ printk(KERN_ERR "%s: ZMII support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
+ if (dev->rgmii_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+ dev->features |= EMAC_FTR_HAS_RGMII;
+#else
+ printk(KERN_ERR "%s: RGMII support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
+ /* Read MAC-address */
+ p = of_get_property(np, "local-mac-address", NULL);
+ if (p == NULL) {
+ printk(KERN_ERR "%s: Can't find local-mac-address property\n",
+ np->full_name);
+ return -ENXIO;
+ }
+ memcpy(dev->ndev->dev_addr, p, 6);
+
+ DBG(dev, "features : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE);
+ DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige);
+ DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige);
+ DBG(dev, "max_mtu : %d\n", dev->max_mtu);
+ DBG(dev, "OPB freq : %d\n", dev->opb_bus_freq);
+
+ return 0;
+}
+
+static int __devinit emac_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct net_device *ndev;
+ struct emac_instance *dev;
+ struct device_node *np = ofdev->node;
+ struct device_node **blist = NULL;
+ int err, i;
+
+ /* Find ourselves in the bootlist if we are there */
+ for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
+ if (emac_boot_list[i] == np)
+ blist = &emac_boot_list[i];
+
+ /* Allocate our net_device structure */
+ err = -ENOMEM;
+ ndev = alloc_etherdev(sizeof(struct emac_instance));
+ if (!ndev) {
+ printk(KERN_ERR "%s: could not allocate ethernet device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+ dev = netdev_priv(ndev);
+ dev->ndev = ndev;
+ dev->ofdev = ofdev;
+ dev->blist = blist;
+ SET_NETDEV_DEV(ndev, &ofdev->dev);
+
+ /* Initialize some embedded data structures */
+ mutex_init(&dev->mdio_lock);
+ mutex_init(&dev->link_lock);
+ spin_lock_init(&dev->lock);
+ INIT_WORK(&dev->reset_work, emac_reset_work);
+
+ /* Init various config data based on device-tree */
+ err = emac_init_config(dev);
+ if (err != 0)
+ goto err_free;
+
+ /* Get interrupts. EMAC irq is mandatory, WOL irq is optional */
+ dev->emac_irq = irq_of_parse_and_map(np, 0);
+ dev->wol_irq = irq_of_parse_and_map(np, 1);
+ if (dev->emac_irq == NO_IRQ) {
+ printk(KERN_ERR "%s: Can't map main interrupt\n", np->full_name);
+ goto err_free;
+ }
+ ndev->irq = dev->emac_irq;
+
+ /* Map EMAC regs */
+ if (of_address_to_resource(np, 0, &dev->rsrc_regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_irq_unmap;
+ }
+ // TODO : request_mem_region
+ dev->emacp = ioremap(dev->rsrc_regs.start, sizeof(struct emac_regs));
+ if (dev->emacp == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ err = -ENOMEM;
+ goto err_irq_unmap;
+ }
+
+ /* Wait for dependent devices */
+ err = emac_wait_deps(dev);
+ if (err) {
+ printk(KERN_ERR
+ "%s: Timeout waiting for dependent devices\n",
+ np->full_name);
+ /* display more info about what's missing ? */
+ goto err_reg_unmap;
+ }
+ dev->mal = dev_get_drvdata(&dev->mal_dev->dev);
+ if (dev->mdio_dev != NULL)
+ dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev);
+
+ /* Register with MAL */
+ dev->commac.ops = &emac_commac_ops;
+ dev->commac.dev = dev;
+ dev->commac.tx_chan_mask = MAL_CHAN_MASK(dev->mal_tx_chan);
+ dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan);
+ err = mal_register_commac(dev->mal, &dev->commac);
+ if (err) {
+ printk(KERN_ERR "%s: failed to register with mal %s!\n",
+ np->full_name, dev->mal_dev->node->full_name);
+ goto err_rel_deps;
+ }
+ dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);
+ dev->rx_sync_size = emac_rx_sync_size(ndev->mtu);
+
+ /* Get pointers to BD rings */
+ dev->tx_desc =
+ dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, dev->mal_tx_chan);
+ dev->rx_desc =
+ dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, dev->mal_rx_chan);
+
+ DBG(dev, "tx_desc %p" NL, dev->tx_desc);
+ DBG(dev, "rx_desc %p" NL, dev->rx_desc);
+
+ /* Clean rings */
+ memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));
+ memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));
+
+ /* Attach to ZMII, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&
+ (err = zmii_attach(dev->zmii_dev, dev->zmii_port, &dev->phy_mode)) != 0)
+ goto err_unreg_commac;
+
+ /* Attach to RGMII, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII) &&
+ (err = rgmii_attach(dev->rgmii_dev, dev->rgmii_port, dev->phy_mode)) != 0)
+ goto err_detach_zmii;
+
+ /* Attach to TAH, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) &&
+ (err = tah_attach(dev->tah_dev, dev->tah_port)) != 0)
+ goto err_detach_rgmii;
+
+ /* Set some link defaults before we can find out real parameters */
+ dev->phy.speed = SPEED_100;
+ dev->phy.duplex = DUPLEX_FULL;
+ dev->phy.autoneg = AUTONEG_DISABLE;
+ dev->phy.pause = dev->phy.asym_pause = 0;
+ dev->stop_timeout = STOP_TIMEOUT_100;
+ INIT_DELAYED_WORK(&dev->link_work, emac_link_timer);
+
+ /* Find PHY if any */
+ err = emac_init_phy(dev);
+ if (err != 0)
+ goto err_detach_tah;
+
+ /* Fill in the driver function table */
+ ndev->open = &emac_open;
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ if (dev->tah_dev) {
+ ndev->hard_start_xmit = &emac_start_xmit_sg;
+ ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ } else
+#endif
+ ndev->hard_start_xmit = &emac_start_xmit;
+ ndev->tx_timeout = &emac_tx_timeout;
+ ndev->watchdog_timeo = 5 * HZ;
+ ndev->stop = &emac_close;
+ ndev->get_stats = &emac_stats;
+ ndev->set_multicast_list = &emac_set_multicast_list;
+ ndev->do_ioctl = &emac_ioctl;
+ if (emac_phy_supports_gige(dev->phy_mode)) {
+ ndev->change_mtu = &emac_change_mtu;
+ dev->commac.ops = &emac_commac_sg_ops;
+ }
+ SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
+
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+
+ err = register_netdev(ndev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to register net device (%d)!\n",
+ np->full_name, err);
+ goto err_detach_tah;
+ }
+
+ /* Set our drvdata last as we don't want them visible until we are
+ * fully initialized
+ */
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ /* There's a new kid in town ! Let's tell everybody */
+ wake_up_all(&emac_probe_wait);
+
+
+ printk(KERN_INFO
+ "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name, dev->cell_index, np->full_name,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ if (dev->phy.address >= 0)
+ printk("%s: found %s PHY (0x%02x)\n", ndev->name,
+ dev->phy.def->name, dev->phy.address);
+
+ emac_dbg_register(dev);
+
+ /* Life is good */
+ return 0;
+
+ /* I have a bad feeling about this ... */
+
+ err_detach_tah:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ tah_detach(dev->tah_dev, dev->tah_port);
+ err_detach_rgmii:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
+ err_detach_zmii:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_detach(dev->zmii_dev, dev->zmii_port);
+ err_unreg_commac:
+ mal_unregister_commac(dev->mal, &dev->commac);
+ err_rel_deps:
+ emac_put_deps(dev);
+ err_reg_unmap:
+ iounmap(dev->emacp);
+ err_irq_unmap:
+ if (dev->wol_irq != NO_IRQ)
+ irq_dispose_mapping(dev->wol_irq);
+ if (dev->emac_irq != NO_IRQ)
+ irq_dispose_mapping(dev->emac_irq);
+ err_free:
+ kfree(ndev);
+ err_gone:
+ /* if we were on the bootlist, remove us as we won't show up and
+ * wake up all waiters to notify them in case they were waiting
+ * on us
+ */
+ if (blist) {
+ *blist = NULL;
+ wake_up_all(&emac_probe_wait);
+ }
+ return err;
+}
+
+static int __devexit emac_remove(struct of_device *ofdev)
+{
+ struct emac_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ DBG(dev, "remove" NL);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ unregister_netdev(dev->ndev);
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ tah_detach(dev->tah_dev, dev->tah_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_detach(dev->zmii_dev, dev->zmii_port);
+
+ mal_unregister_commac(dev->mal, &dev->commac);
+ emac_put_deps(dev);
+
+ emac_dbg_unregister(dev);
+ iounmap(dev->emacp);
+
+ if (dev->wol_irq != NO_IRQ)
+ irq_dispose_mapping(dev->wol_irq);
+ if (dev->emac_irq != NO_IRQ)
+ irq_dispose_mapping(dev->emac_irq);
+
+ kfree(dev->ndev);
+
+ return 0;
+}
+
+/* XXX Features in here should be replaced by properties... */
+static struct of_device_id emac_match[] =
+{
+ {
+ .type = "network",
+ .compatible = "ibm,emac",
+ },
+ {
+ .type = "network",
+ .compatible = "ibm,emac4",
+ },
+ {},
+};
+
+static struct of_platform_driver emac_driver = {
+ .name = "emac",
+ .match_table = emac_match,
+
+ .probe = emac_probe,
+ .remove = emac_remove,
+};
+
+static void __init emac_make_bootlist(void)
+{
+ struct device_node *np = NULL;
+ int j, max, i = 0, k;
+ int cell_indices[EMAC_BOOT_LIST_SIZE];
+
+ /* Collect EMACs */
+ while((np = of_find_all_nodes(np)) != NULL) {
+ const u32 *idx;
+
+ if (of_match_node(emac_match, np) == NULL)
+ continue;
+ if (of_get_property(np, "unused", NULL))
+ continue;
+ idx = of_get_property(np, "cell-index", NULL);
+ if (idx == NULL)
+ continue;
+ cell_indices[i] = *idx;
+ emac_boot_list[i++] = of_node_get(np);
+ if (i >= EMAC_BOOT_LIST_SIZE) {
+ of_node_put(np);
+ break;
+ }
+ }
+ max = i;
+
+ /* Bubble sort them (doh, what a creative algorithm :-) */
+ for (i = 0; max > 1 && (i < (max - 1)); i++)
+ for (j = i; j < max; j++) {
+ if (cell_indices[i] > cell_indices[j]) {
+ np = emac_boot_list[i];
+ emac_boot_list[i] = emac_boot_list[j];
+ emac_boot_list[j] = np;
+ k = cell_indices[i];
+ cell_indices[i] = cell_indices[j];
+ cell_indices[j] = k;
+ }
+ }
+}
+
+static int __init emac_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n");
+
+ /* Init debug stuff */
+ emac_init_debug();
+
+ /* Build EMAC boot list */
+ emac_make_bootlist();
+
+ /* Init submodules */
+ rc = mal_init();
+ if (rc)
+ goto err;
+ rc = zmii_init();
+ if (rc)
+ goto err_mal;
+ rc = rgmii_init();
+ if (rc)
+ goto err_zmii;
+ rc = tah_init();
+ if (rc)
+ goto err_rgmii;
+ rc = of_register_platform_driver(&emac_driver);
+ if (rc)
+ goto err_tah;
+
+ return 0;
+
+ err_tah:
+ tah_exit();
+ err_rgmii:
+ rgmii_exit();
+ err_zmii:
+ zmii_exit();
+ err_mal:
+ mal_exit();
+ err:
+ return rc;
+}
+
+static void __exit emac_exit(void)
+{
+ int i;
+
+ of_unregister_platform_driver(&emac_driver);
+
+ tah_exit();
+ rgmii_exit();
+ zmii_exit();
+ mal_exit();
+ emac_fini_debug();
+
+ /* Destroy EMAC boot list */
+ for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
+ if (emac_boot_list[i])
+ of_node_put(emac_boot_list[i]);
+}
+
+module_init(emac_init);
+module_exit(emac_exit);
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
new file mode 100644
index 000000000000..4011803117ca
--- /dev/null
+++ b/drivers/net/ibm_newemac/core.h
@@ -0,0 +1,355 @@
+/*
+ * drivers/net/ibm_newemac/core.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Johnnie Peters <jpeters@mvista.com>
+ * Copyright 2000, 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_CORE_H
+#define __IBM_NEWEMAC_CORE_H
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/dcr.h>
+
+#include "emac.h"
+#include "phy.h"
+#include "zmii.h"
+#include "rgmii.h"
+#include "mal.h"
+#include "tah.h"
+#include "debug.h"
+
+#define NUM_TX_BUFF CONFIG_IBM_NEW_EMAC_TXB
+#define NUM_RX_BUFF CONFIG_IBM_NEW_EMAC_RXB
+
+/* Simple sanity check */
+#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256
+#error Invalid number of buffer descriptors (greater than 256)
+#endif
+
+#define EMAC_MIN_MTU 46
+
+/* Maximum L2 header length (VLAN tagged, no FCS) */
+#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4)
+
+/* RX BD size for the given MTU */
+static inline int emac_rx_size(int mtu)
+{
+ if (mtu > ETH_DATA_LEN)
+ return MAL_MAX_RX_SIZE;
+ else
+ return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD);
+}
+
+#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment())
+
+#define EMAC_RX_SKB_HEADROOM \
+ EMAC_DMA_ALIGN(CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM)
+
+/* Size of RX skb for the given MTU */
+static inline int emac_rx_skb_size(int mtu)
+{
+ int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));
+ return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM;
+}
+
+/* RX DMA sync size */
+static inline int emac_rx_sync_size(int mtu)
+{
+ return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2);
+}
+
+/* Driver statistcs is split into two parts to make it more cache friendly:
+ * - normal statistics (packet count, etc)
+ * - error statistics
+ *
+ * When statistics is requested by ethtool, these parts are concatenated,
+ * normal one goes first.
+ *
+ * Please, keep these structures in sync with emac_stats_keys.
+ */
+
+/* Normal TX/RX Statistics */
+struct emac_stats {
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ u64 rx_packets_csum;
+ u64 tx_packets_csum;
+};
+
+/* Error statistics */
+struct emac_error_stats {
+ u64 tx_undo;
+
+ /* Software RX Errors */
+ u64 rx_dropped_stack;
+ u64 rx_dropped_oom;
+ u64 rx_dropped_error;
+ u64 rx_dropped_resize;
+ u64 rx_dropped_mtu;
+ u64 rx_stopped;
+ /* BD reported RX errors */
+ u64 rx_bd_errors;
+ u64 rx_bd_overrun;
+ u64 rx_bd_bad_packet;
+ u64 rx_bd_runt_packet;
+ u64 rx_bd_short_event;
+ u64 rx_bd_alignment_error;
+ u64 rx_bd_bad_fcs;
+ u64 rx_bd_packet_too_long;
+ u64 rx_bd_out_of_range;
+ u64 rx_bd_in_range;
+ /* EMAC IRQ reported RX errors */
+ u64 rx_parity;
+ u64 rx_fifo_overrun;
+ u64 rx_overrun;
+ u64 rx_bad_packet;
+ u64 rx_runt_packet;
+ u64 rx_short_event;
+ u64 rx_alignment_error;
+ u64 rx_bad_fcs;
+ u64 rx_packet_too_long;
+ u64 rx_out_of_range;
+ u64 rx_in_range;
+
+ /* Software TX Errors */
+ u64 tx_dropped;
+ /* BD reported TX errors */
+ u64 tx_bd_errors;
+ u64 tx_bd_bad_fcs;
+ u64 tx_bd_carrier_loss;
+ u64 tx_bd_excessive_deferral;
+ u64 tx_bd_excessive_collisions;
+ u64 tx_bd_late_collision;
+ u64 tx_bd_multple_collisions;
+ u64 tx_bd_single_collision;
+ u64 tx_bd_underrun;
+ u64 tx_bd_sqe;
+ /* EMAC IRQ reported TX errors */
+ u64 tx_parity;
+ u64 tx_underrun;
+ u64 tx_sqe;
+ u64 tx_errors;
+};
+
+#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct emac_stats) + \
+ sizeof(struct emac_error_stats)) \
+ / sizeof(u64))
+
+struct emac_instance {
+ struct net_device *ndev;
+ struct resource rsrc_regs;
+ struct emac_regs __iomem *emacp;
+ struct of_device *ofdev;
+ struct device_node **blist; /* bootlist entry */
+
+ /* MAL linkage */
+ u32 mal_ph;
+ struct of_device *mal_dev;
+ u32 mal_rx_chan;
+ u32 mal_tx_chan;
+ struct mal_instance *mal;
+ struct mal_commac commac;
+
+ /* PHY infos */
+ u32 phy_mode;
+ u32 phy_map;
+ u32 phy_address;
+ u32 phy_feat_exc;
+ struct mii_phy phy;
+ struct mutex link_lock;
+ struct delayed_work link_work;
+ int link_polling;
+
+ /* Shared MDIO if any */
+ u32 mdio_ph;
+ struct of_device *mdio_dev;
+ struct emac_instance *mdio_instance;
+ struct mutex mdio_lock;
+
+ /* ZMII infos if any */
+ u32 zmii_ph;
+ u32 zmii_port;
+ struct of_device *zmii_dev;
+
+ /* RGMII infos if any */
+ u32 rgmii_ph;
+ u32 rgmii_port;
+ struct of_device *rgmii_dev;
+
+ /* TAH infos if any */
+ u32 tah_ph;
+ u32 tah_port;
+ struct of_device *tah_dev;
+
+ /* IRQs */
+ int wol_irq;
+ int emac_irq;
+
+ /* OPB bus frequency in Mhz */
+ u32 opb_bus_freq;
+
+ /* Cell index within an ASIC (for clk mgmnt) */
+ u32 cell_index;
+
+ /* Max supported MTU */
+ u32 max_mtu;
+
+ /* Feature bits (from probe table) */
+ unsigned int features;
+
+ /* Tx and Rx fifo sizes & other infos in bytes */
+ u32 tx_fifo_size;
+ u32 tx_fifo_size_gige;
+ u32 rx_fifo_size;
+ u32 rx_fifo_size_gige;
+ u32 fifo_entry_size;
+ u32 mal_burst_size; /* move to MAL ? */
+
+ /* Descriptor management
+ */
+ struct mal_descriptor *tx_desc;
+ int tx_cnt;
+ int tx_slot;
+ int ack_slot;
+
+ struct mal_descriptor *rx_desc;
+ int rx_slot;
+ struct sk_buff *rx_sg_skb; /* 1 */
+ int rx_skb_size;
+ int rx_sync_size;
+
+ struct sk_buff *tx_skb[NUM_TX_BUFF];
+ struct sk_buff *rx_skb[NUM_RX_BUFF];
+
+ /* Stats
+ */
+ struct emac_error_stats estats;
+ struct net_device_stats nstats;
+ struct emac_stats stats;
+
+ /* Misc
+ */
+ int reset_failed;
+ int stop_timeout; /* in us */
+ int no_mcast;
+ int mcast_pending;
+ struct work_struct reset_work;
+ spinlock_t lock;
+};
+
+/*
+ * Features of various EMAC implementations
+ */
+
+/*
+ * No flow control on 40x according to the original driver
+ */
+#define EMAC_FTR_NO_FLOW_CONTROL_40x 0x00000001
+/*
+ * Cell is an EMAC4
+ */
+#define EMAC_FTR_EMAC4 0x00000002
+/*
+ * For the 440SPe, AMCC inexplicably changed the polarity of
+ * the "operation complete" bit in the MII control register.
+ */
+#define EMAC_FTR_STACR_OC_INVERT 0x00000004
+/*
+ * Set if we have a TAH.
+ */
+#define EMAC_FTR_HAS_TAH 0x00000008
+/*
+ * Set if we have a ZMII.
+ */
+#define EMAC_FTR_HAS_ZMII 0x00000010
+/*
+ * Set if we have a RGMII.
+ */
+#define EMAC_FTR_HAS_RGMII 0x00000020
+/*
+ * Set if we have axon-type STACR
+ */
+#define EMAC_FTR_HAS_AXON_STACR 0x00000040
+
+
+/* Right now, we don't quite handle the always/possible masks on the
+ * most optimal way as we don't have a way to say something like
+ * always EMAC4. Patches welcome.
+ */
+enum {
+ EMAC_FTRS_ALWAYS = 0,
+
+ EMAC_FTRS_POSSIBLE =
+#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
+ EMAC_FTR_EMAC4 | EMAC_FTR_HAS_AXON_STACR |
+ EMAC_FTR_STACR_OC_INVERT |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ EMAC_FTR_HAS_TAH |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+ EMAC_FTR_HAS_ZMII |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+ EMAC_FTR_HAS_RGMII |
+#endif
+ 0,
+};
+
+static inline int emac_has_feature(struct emac_instance *dev,
+ unsigned long feature)
+{
+ return (EMAC_FTRS_ALWAYS & feature) ||
+ (EMAC_FTRS_POSSIBLE & dev->features & feature);
+}
+
+
+/* Ethtool get_regs complex data.
+ * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
+ * when available.
+ *
+ * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr,
+ * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers.
+ * Each register component is preceded with emac_ethtool_regs_subhdr.
+ * Order of the optional headers follows their relative bit posititions
+ * in emac_ethtool_regs_hdr.components
+ */
+#define EMAC_ETHTOOL_REGS_ZMII 0x00000001
+#define EMAC_ETHTOOL_REGS_RGMII 0x00000002
+#define EMAC_ETHTOOL_REGS_TAH 0x00000004
+
+struct emac_ethtool_regs_hdr {
+ u32 components;
+};
+
+struct emac_ethtool_regs_subhdr {
+ u32 version;
+ u32 index;
+};
+
+#endif /* __IBM_NEWEMAC_CORE_H */
diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ibm_newemac/debug.c
new file mode 100644
index 000000000000..170524ee0f19
--- /dev/null
+++ b/drivers/net/ibm_newemac/debug.c
@@ -0,0 +1,238 @@
+/*
+ * drivers/net/ibm_newemac/debug.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/sysrq.h>
+#include <asm/io.h>
+
+#include "core.h"
+
+static spinlock_t emac_dbg_lock = SPIN_LOCK_UNLOCKED;
+
+static void emac_desc_dump(struct emac_instance *p)
+{
+ int i;
+ printk("** EMAC %s TX BDs **\n"
+ " tx_cnt = %d tx_slot = %d ack_slot = %d\n",
+ p->ofdev->node->full_name,
+ p->tx_cnt, p->tx_slot, p->ack_slot);
+ for (i = 0; i < NUM_TX_BUFF / 2; ++i)
+ printk
+ ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
+ i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ',
+ p->tx_desc[i].ctrl, p->tx_desc[i].data_len,
+ NUM_TX_BUFF / 2 + i,
+ p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr,
+ p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ',
+ p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl,
+ p->tx_desc[NUM_TX_BUFF / 2 + i].data_len);
+
+ printk("** EMAC %s RX BDs **\n"
+ " rx_slot = %d flags = 0x%lx rx_skb_size = %d rx_sync_size = %d\n"
+ " rx_sg_skb = 0x%p\n",
+ p->ofdev->node->full_name,
+ p->rx_slot, p->commac.flags, p->rx_skb_size,
+ p->rx_sync_size, p->rx_sg_skb);
+ for (i = 0; i < NUM_RX_BUFF / 2; ++i)
+ printk
+ ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
+ i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ',
+ p->rx_desc[i].ctrl, p->rx_desc[i].data_len,
+ NUM_RX_BUFF / 2 + i,
+ p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr,
+ p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ',
+ p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl,
+ p->rx_desc[NUM_RX_BUFF / 2 + i].data_len);
+}
+
+static void emac_mac_dump(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+
+ printk("** EMAC %s registers **\n"
+ "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
+ "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
+ "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n"
+ "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x "
+ "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n"
+ "LSA = %04x%08x IPGVR = 0x%04x\n"
+ "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
+ "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n",
+ dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1),
+ in_be32(&p->tmr0), in_be32(&p->tmr1),
+ in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
+ in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
+ in_be32(&p->vtci),
+ in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3),
+ in_be32(&p->iaht4),
+ in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3),
+ in_be32(&p->gaht4),
+ in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr),
+ in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr),
+ in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr)
+ );
+
+ emac_desc_dump(dev);
+}
+
+static void emac_mal_dump(struct mal_instance *mal)
+{
+ int i;
+
+ printk("** MAL %s Registers **\n"
+ "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
+ "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
+ "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
+ mal->ofdev->node->full_name,
+ get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR),
+ get_mal_dcrn(mal, MAL_IER),
+ get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR),
+ get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR),
+ get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR),
+ get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR)
+ );
+
+ printk("TX|");
+ for (i = 0; i < mal->num_tx_chans; ++i) {
+ if (i && !(i % 4))
+ printk("\n ");
+ printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i)));
+ }
+ printk("\nRX|");
+ for (i = 0; i < mal->num_rx_chans; ++i) {
+ if (i && !(i % 4))
+ printk("\n ");
+ printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i)));
+ }
+ printk("\n ");
+ for (i = 0; i < mal->num_rx_chans; ++i) {
+ u32 r = get_mal_dcrn(mal, MAL_RCBS(i));
+ if (i && !(i % 3))
+ printk("\n ");
+ printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16);
+ }
+ printk("\n");
+}
+
+static struct emac_instance *__emacs[4];
+static struct mal_instance *__mals[1];
+
+void emac_dbg_register(struct emac_instance *dev)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__emacs); i++)
+ if (__emacs[i] == NULL) {
+ __emacs[i] = dev;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void emac_dbg_unregister(struct emac_instance *dev)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__emacs); i++)
+ if (__emacs[i] == dev) {
+ __emacs[i] = NULL;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void mal_dbg_register(struct mal_instance *mal)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__mals); i++)
+ if (__mals[i] == NULL) {
+ __mals[i] = mal;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void mal_dbg_unregister(struct mal_instance *mal)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__mals); i++)
+ if (__mals[i] == mal) {
+ __mals[i] = NULL;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void emac_dbg_dump_all(void)
+{
+ unsigned int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(__mals); ++i)
+ if (__mals[i])
+ emac_mal_dump(__mals[i]);
+
+ for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
+ if (__emacs[i])
+ emac_mac_dump(__emacs[i]);
+
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+static void emac_sysrq_handler(int key, struct tty_struct *tty)
+{
+ emac_dbg_dump_all();
+}
+
+static struct sysrq_key_op emac_sysrq_op = {
+ .handler = emac_sysrq_handler,
+ .help_msg = "emaC",
+ .action_msg = "Show EMAC(s) status",
+};
+
+int __init emac_init_debug(void)
+{
+ return register_sysrq_key('c', &emac_sysrq_op);
+}
+
+void __exit emac_fini_debug(void)
+{
+ unregister_sysrq_key('c', &emac_sysrq_op);
+}
+
+#else
+int __init emac_init_debug(void)
+{
+ return 0;
+}
+void __exit emac_fini_debug(void)
+{
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
diff --git a/drivers/net/ibm_newemac/debug.h b/drivers/net/ibm_newemac/debug.h
new file mode 100644
index 000000000000..1dd2dcbc157f
--- /dev/null
+++ b/drivers/net/ibm_newemac/debug.h
@@ -0,0 +1,78 @@
+/*
+ * drivers/net/ibm_newemac/debug.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_DEBUG_H
+#define __IBM_NEWEMAC_DEBUG_H
+
+#include <linux/init.h>
+
+#include "core.h"
+
+#if defined(CONFIG_IBM_NEW_EMAC_DEBUG)
+
+struct emac_instance;
+struct mal_instance;
+
+extern void emac_dbg_register(struct emac_instance *dev);
+extern void emac_dbg_unregister(struct emac_instance *dev);
+extern void mal_dbg_register(struct mal_instance *mal);
+extern void mal_dbg_unregister(struct mal_instance *mal);
+extern int emac_init_debug(void) __init;
+extern void emac_fini_debug(void) __exit;
+extern void emac_dbg_dump_all(void);
+
+# define DBG_LEVEL 1
+
+#else
+
+# define emac_dbg_register(x) do { } while(0)
+# define emac_dbg_unregister(x) do { } while(0)
+# define mal_dbg_register(x) do { } while(0)
+# define mal_dbg_unregister(x) do { } while(0)
+# define emac_init_debug() do { } while(0)
+# define emac_fini_debug() do { } while(0)
+# define emac_dbg_dump_all() do { } while(0)
+
+# define DBG_LEVEL 0
+
+#endif
+
+#define EMAC_DBG(dev, name, fmt, arg...) \
+ printk(KERN_DEBUG #name "%s: " fmt, dev->ofdev->node->full_name, ## arg)
+
+#if DBG_LEVEL > 0
+# define DBG(d,f,x...) EMAC_DBG(d, emac, f, ##x)
+# define MAL_DBG(d,f,x...) EMAC_DBG(d, mal, f, ##x)
+# define ZMII_DBG(d,f,x...) EMAC_DBG(d, zmii, f, ##x)
+# define RGMII_DBG(d,f,x...) EMAC_DBG(d, rgmii, f, ##x)
+# define NL "\n"
+#else
+# define DBG(f,x...) ((void)0)
+# define MAL_DBG(d,f,x...) ((void)0)
+# define ZMII_DBG(d,f,x...) ((void)0)
+# define RGMII_DBG(d,f,x...) ((void)0)
+#endif
+#if DBG_LEVEL > 1
+# define DBG2(d,f,x...) DBG(d,f, ##x)
+# define MAL_DBG2(d,f,x...) MAL_DBG(d,f, ##x)
+# define ZMII_DBG2(d,f,x...) ZMII_DBG(d,f, ##x)
+# define RGMII_DBG2(d,f,x...) RGMII_DBG(d,f, ##x)
+#else
+# define DBG2(f,x...) ((void)0)
+# define MAL_DBG2(d,f,x...) ((void)0)
+# define ZMII_DBG2(d,f,x...) ((void)0)
+# define RGMII_DBG2(d,f,x...) ((void)0)
+#endif
+
+#endif /* __IBM_NEWEMAC_DEBUG_H */
diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h
new file mode 100644
index 000000000000..bef92efeeadc
--- /dev/null
+++ b/drivers/net/ibm_newemac/emac.h
@@ -0,0 +1,268 @@
+/*
+ * drivers/net/ibm_newemac/emac.h
+ *
+ * Register definitions for PowerPC 4xx on-chip ethernet contoller
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2002-2004 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_H
+#define __IBM_NEWEMAC_H
+
+#include <linux/types.h>
+
+/* EMAC registers Write Access rules */
+struct emac_regs {
+ u32 mr0; /* special */
+ u32 mr1; /* Reset */
+ u32 tmr0; /* special */
+ u32 tmr1; /* special */
+ u32 rmr; /* Reset */
+ u32 isr; /* Always */
+ u32 iser; /* Reset */
+ u32 iahr; /* Reset, R, T */
+ u32 ialr; /* Reset, R, T */
+ u32 vtpid; /* Reset, R, T */
+ u32 vtci; /* Reset, R, T */
+ u32 ptr; /* Reset, T */
+ u32 iaht1; /* Reset, R */
+ u32 iaht2; /* Reset, R */
+ u32 iaht3; /* Reset, R */
+ u32 iaht4; /* Reset, R */
+ u32 gaht1; /* Reset, R */
+ u32 gaht2; /* Reset, R */
+ u32 gaht3; /* Reset, R */
+ u32 gaht4; /* Reset, R */
+ u32 lsah;
+ u32 lsal;
+ u32 ipgvr; /* Reset, T */
+ u32 stacr; /* special */
+ u32 trtr; /* special */
+ u32 rwmr; /* Reset */
+ u32 octx;
+ u32 ocrx;
+ u32 ipcr;
+};
+
+/*
+ * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
+ */
+#define PHY_MODE_NA 0
+#define PHY_MODE_MII 1
+#define PHY_MODE_RMII 2
+#define PHY_MODE_SMII 3
+#define PHY_MODE_RGMII 4
+#define PHY_MODE_TBI 5
+#define PHY_MODE_GMII 6
+#define PHY_MODE_RTBI 7
+#define PHY_MODE_SGMII 8
+
+
+#define EMAC_ETHTOOL_REGS_VER 0
+#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32))
+#define EMAC4_ETHTOOL_REGS_VER 1
+#define EMAC4_ETHTOOL_REGS_SIZE sizeof(struct emac_regs)
+
+/* EMACx_MR0 */
+#define EMAC_MR0_RXI 0x80000000
+#define EMAC_MR0_TXI 0x40000000
+#define EMAC_MR0_SRST 0x20000000
+#define EMAC_MR0_TXE 0x10000000
+#define EMAC_MR0_RXE 0x08000000
+#define EMAC_MR0_WKE 0x04000000
+
+/* EMACx_MR1 */
+#define EMAC_MR1_FDE 0x80000000
+#define EMAC_MR1_ILE 0x40000000
+#define EMAC_MR1_VLE 0x20000000
+#define EMAC_MR1_EIFC 0x10000000
+#define EMAC_MR1_APP 0x08000000
+#define EMAC_MR1_IST 0x01000000
+
+#define EMAC_MR1_MF_MASK 0x00c00000
+#define EMAC_MR1_MF_10 0x00000000
+#define EMAC_MR1_MF_100 0x00400000
+#define EMAC_MR1_MF_1000 0x00800000
+#define EMAC_MR1_MF_1000GPCS 0x00c00000
+#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6)
+
+#define EMAC_MR1_RFS_4K 0x00300000
+#define EMAC_MR1_RFS_16K 0x00000000
+#define EMAC_MR1_TFS_2K 0x00080000
+#define EMAC_MR1_TR0_MULT 0x00008000
+#define EMAC_MR1_JPSM 0x00000000
+#define EMAC_MR1_MWSW_001 0x00000000
+#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
+
+
+#define EMAC4_MR1_RFS_2K 0x00100000
+#define EMAC4_MR1_RFS_4K 0x00180000
+#define EMAC4_MR1_RFS_16K 0x00280000
+#define EMAC4_MR1_TFS_2K 0x00020000
+#define EMAC4_MR1_TFS_4K 0x00030000
+#define EMAC4_MR1_TR 0x00008000
+#define EMAC4_MR1_MWSW_001 0x00001000
+#define EMAC4_MR1_JPSM 0x00000800
+#define EMAC4_MR1_OBCI_MASK 0x00000038
+#define EMAC4_MR1_OBCI_50 0x00000000
+#define EMAC4_MR1_OBCI_66 0x00000008
+#define EMAC4_MR1_OBCI_83 0x00000010
+#define EMAC4_MR1_OBCI_100 0x00000018
+#define EMAC4_MR1_OBCI_100P 0x00000020
+#define EMAC4_MR1_OBCI(freq) ((freq) <= 50 ? EMAC4_MR1_OBCI_50 : \
+ (freq) <= 66 ? EMAC4_MR1_OBCI_66 : \
+ (freq) <= 83 ? EMAC4_MR1_OBCI_83 : \
+ (freq) <= 100 ? EMAC4_MR1_OBCI_100 : \
+ EMAC4_MR1_OBCI_100P)
+
+/* EMACx_TMR0 */
+#define EMAC_TMR0_GNP 0x80000000
+#define EMAC_TMR0_DEFAULT 0x00000000
+#define EMAC4_TMR0_TFAE_2_32 0x00000001
+#define EMAC4_TMR0_TFAE_4_64 0x00000002
+#define EMAC4_TMR0_TFAE_8_128 0x00000003
+#define EMAC4_TMR0_TFAE_16_256 0x00000004
+#define EMAC4_TMR0_TFAE_32_512 0x00000005
+#define EMAC4_TMR0_TFAE_64_1024 0x00000006
+#define EMAC4_TMR0_TFAE_128_2048 0x00000007
+#define EMAC4_TMR0_DEFAULT EMAC4_TMR0_TFAE_2_32
+#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT)
+#define EMAC4_TMR0_XMIT (EMAC_TMR0_GNP | EMAC4_TMR0_DEFAULT)
+
+/* EMACx_TMR1 */
+
+#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16))
+#define EMAC4_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14))
+
+/* EMACx_RMR */
+#define EMAC_RMR_SP 0x80000000
+#define EMAC_RMR_SFCS 0x40000000
+#define EMAC_RMR_RRP 0x20000000
+#define EMAC_RMR_RFP 0x10000000
+#define EMAC_RMR_ROP 0x08000000
+#define EMAC_RMR_RPIR 0x04000000
+#define EMAC_RMR_PPP 0x02000000
+#define EMAC_RMR_PME 0x01000000
+#define EMAC_RMR_PMME 0x00800000
+#define EMAC_RMR_IAE 0x00400000
+#define EMAC_RMR_MIAE 0x00200000
+#define EMAC_RMR_BAE 0x00100000
+#define EMAC_RMR_MAE 0x00080000
+#define EMAC_RMR_BASE 0x00000000
+#define EMAC4_RMR_RFAF_2_32 0x00000001
+#define EMAC4_RMR_RFAF_4_64 0x00000002
+#define EMAC4_RMR_RFAF_8_128 0x00000003
+#define EMAC4_RMR_RFAF_16_256 0x00000004
+#define EMAC4_RMR_RFAF_32_512 0x00000005
+#define EMAC4_RMR_RFAF_64_1024 0x00000006
+#define EMAC4_RMR_RFAF_128_2048 0x00000007
+#define EMAC4_RMR_BASE EMAC4_RMR_RFAF_128_2048
+
+/* EMACx_ISR & EMACx_ISER */
+#define EMAC4_ISR_TXPE 0x20000000
+#define EMAC4_ISR_RXPE 0x10000000
+#define EMAC4_ISR_TXUE 0x08000000
+#define EMAC4_ISR_RXOE 0x04000000
+#define EMAC_ISR_OVR 0x02000000
+#define EMAC_ISR_PP 0x01000000
+#define EMAC_ISR_BP 0x00800000
+#define EMAC_ISR_RP 0x00400000
+#define EMAC_ISR_SE 0x00200000
+#define EMAC_ISR_ALE 0x00100000
+#define EMAC_ISR_BFCS 0x00080000
+#define EMAC_ISR_PTLE 0x00040000
+#define EMAC_ISR_ORE 0x00020000
+#define EMAC_ISR_IRE 0x00010000
+#define EMAC_ISR_SQE 0x00000080
+#define EMAC_ISR_TE 0x00000040
+#define EMAC_ISR_MOS 0x00000002
+#define EMAC_ISR_MOF 0x00000001
+
+/* EMACx_STACR */
+#define EMAC_STACR_PHYD_MASK 0xffff
+#define EMAC_STACR_PHYD_SHIFT 16
+#define EMAC_STACR_OC 0x00008000
+#define EMAC_STACR_PHYE 0x00004000
+#define EMAC_STACR_STAC_MASK 0x00003000
+#define EMAC_STACR_STAC_READ 0x00001000
+#define EMAC_STACR_STAC_WRITE 0x00002000
+#define EMAC_STACR_OPBC_MASK 0x00000C00
+#define EMAC_STACR_OPBC_50 0x00000000
+#define EMAC_STACR_OPBC_66 0x00000400
+#define EMAC_STACR_OPBC_83 0x00000800
+#define EMAC_STACR_OPBC_100 0x00000C00
+#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \
+ (freq) <= 66 ? EMAC_STACR_OPBC_66 : \
+ (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100)
+#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb)
+#define EMAC4_STACR_BASE(opb) 0x00000000
+#define EMAC_STACR_PCDA_MASK 0x1f
+#define EMAC_STACR_PCDA_SHIFT 5
+#define EMAC_STACR_PRA_MASK 0x1f
+#define EMACX_STACR_STAC_MASK 0x00003800
+#define EMACX_STACR_STAC_READ 0x00001000
+#define EMACX_STACR_STAC_WRITE 0x00000800
+#define EMACX_STACR_STAC_IND_ADDR 0x00002000
+#define EMACX_STACR_STAC_IND_READ 0x00003800
+#define EMACX_STACR_STAC_IND_READINC 0x00003000
+#define EMACX_STACR_STAC_IND_WRITE 0x00002800
+
+
+/* EMACx_TRTR */
+#define EMAC_TRTR_SHIFT_EMAC4 27
+#define EMAC_TRTR_SHIFT 24
+
+/* EMAC specific TX descriptor control fields (write access) */
+#define EMAC_TX_CTRL_GFCS 0x0200
+#define EMAC_TX_CTRL_GP 0x0100
+#define EMAC_TX_CTRL_ISA 0x0080
+#define EMAC_TX_CTRL_RSA 0x0040
+#define EMAC_TX_CTRL_IVT 0x0020
+#define EMAC_TX_CTRL_RVT 0x0010
+#define EMAC_TX_CTRL_TAH_CSUM 0x000e
+
+/* EMAC specific TX descriptor status fields (read access) */
+#define EMAC_TX_ST_BFCS 0x0200
+#define EMAC_TX_ST_LCS 0x0080
+#define EMAC_TX_ST_ED 0x0040
+#define EMAC_TX_ST_EC 0x0020
+#define EMAC_TX_ST_LC 0x0010
+#define EMAC_TX_ST_MC 0x0008
+#define EMAC_TX_ST_SC 0x0004
+#define EMAC_TX_ST_UR 0x0002
+#define EMAC_TX_ST_SQE 0x0001
+#define EMAC_IS_BAD_TX (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
+ EMAC_TX_ST_EC | EMAC_TX_ST_LC | \
+ EMAC_TX_ST_MC | EMAC_TX_ST_UR)
+#define EMAC_IS_BAD_TX_TAH (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
+ EMAC_TX_ST_EC | EMAC_TX_ST_LC)
+
+/* EMAC specific RX descriptor status fields (read access) */
+#define EMAC_RX_ST_OE 0x0200
+#define EMAC_RX_ST_PP 0x0100
+#define EMAC_RX_ST_BP 0x0080
+#define EMAC_RX_ST_RP 0x0040
+#define EMAC_RX_ST_SE 0x0020
+#define EMAC_RX_ST_AE 0x0010
+#define EMAC_RX_ST_BFCS 0x0008
+#define EMAC_RX_ST_PTL 0x0004
+#define EMAC_RX_ST_ORE 0x0002
+#define EMAC_RX_ST_IRE 0x0001
+#define EMAC_RX_TAH_BAD_CSUM 0x0003
+#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \
+ EMAC_RX_ST_RP | EMAC_RX_ST_SE | \
+ EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \
+ EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \
+ EMAC_RX_ST_IRE )
+#endif /* __IBM_NEWEMAC_H */
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
new file mode 100644
index 000000000000..58854117b1a9
--- /dev/null
+++ b/drivers/net/ibm_newemac/mal.c
@@ -0,0 +1,711 @@
+/*
+ * drivers/net/ibm_newemac/mal.c
+ *
+ * Memory Access Layer (MAL) support
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ * David Gibson <hermes@gibson.dropbear.id.au>,
+ *
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "core.h"
+
+static int mal_count;
+
+int __devinit mal_register_commac(struct mal_instance *mal,
+ struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "reg(%08x, %08x)" NL,
+ commac->tx_chan_mask, commac->rx_chan_mask);
+
+ /* Don't let multiple commacs claim the same channel(s) */
+ if ((mal->tx_chan_mask & commac->tx_chan_mask) ||
+ (mal->rx_chan_mask & commac->rx_chan_mask)) {
+ spin_unlock_irqrestore(&mal->lock, flags);
+ printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n",
+ mal->index);
+ return -EBUSY;
+ }
+
+ mal->tx_chan_mask |= commac->tx_chan_mask;
+ mal->rx_chan_mask |= commac->rx_chan_mask;
+ list_add(&commac->list, &mal->list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+
+ return 0;
+}
+
+void __devexit mal_unregister_commac(struct mal_instance *mal,
+ struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "unreg(%08x, %08x)" NL,
+ commac->tx_chan_mask, commac->rx_chan_mask);
+
+ mal->tx_chan_mask &= ~commac->tx_chan_mask;
+ mal->rx_chan_mask &= ~commac->rx_chan_mask;
+ list_del_init(&commac->list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size)
+{
+ BUG_ON(channel < 0 || channel >= mal->num_rx_chans ||
+ size > MAL_MAX_RX_SIZE);
+
+ MAL_DBG(mal, "set_rbcs(%d, %lu)" NL, channel, size);
+
+ if (size & 0xf) {
+ printk(KERN_WARNING
+ "mal%d: incorrect RX size %lu for the channel %d\n",
+ mal->index, size, channel);
+ return -EINVAL;
+ }
+
+ set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4);
+ return 0;
+}
+
+int mal_tx_bd_offset(struct mal_instance *mal, int channel)
+{
+ BUG_ON(channel < 0 || channel >= mal->num_tx_chans);
+
+ return channel * NUM_TX_BUFF;
+}
+
+int mal_rx_bd_offset(struct mal_instance *mal, int channel)
+{
+ BUG_ON(channel < 0 || channel >= mal->num_rx_chans);
+ return mal->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF;
+}
+
+void mal_enable_tx_channel(struct mal_instance *mal, int channel)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "enable_tx(%d)" NL, channel);
+
+ set_mal_dcrn(mal, MAL_TXCASR,
+ get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel));
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_disable_tx_channel(struct mal_instance *mal, int channel)
+{
+ set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel));
+
+ MAL_DBG(mal, "disable_tx(%d)" NL, channel);
+}
+
+void mal_enable_rx_channel(struct mal_instance *mal, int channel)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "enable_rx(%d)" NL, channel);
+
+ set_mal_dcrn(mal, MAL_RXCASR,
+ get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel));
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_disable_rx_channel(struct mal_instance *mal, int channel)
+{
+ set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel));
+
+ MAL_DBG(mal, "disable_rx(%d)" NL, channel);
+}
+
+void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "poll_add(%p)" NL, commac);
+
+ /* starts disabled */
+ set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags);
+
+ list_add_tail(&commac->poll_list, &mal->poll_list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "poll_del(%p)" NL, commac);
+
+ list_del(&commac->poll_list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+/* synchronized by mal_poll() */
+static inline void mal_enable_eob_irq(struct mal_instance *mal)
+{
+ MAL_DBG2(mal, "enable_irq" NL);
+
+ // XXX might want to cache MAL_CFG as the DCR read can be slooooow
+ set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE);
+}
+
+/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */
+static inline void mal_disable_eob_irq(struct mal_instance *mal)
+{
+ // XXX might want to cache MAL_CFG as the DCR read can be slooooow
+ set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE);
+
+ MAL_DBG2(mal, "disable_irq" NL);
+}
+
+static irqreturn_t mal_serr(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 esr = get_mal_dcrn(mal, MAL_ESR);
+
+ /* Clear the error status register */
+ set_mal_dcrn(mal, MAL_ESR, esr);
+
+ MAL_DBG(mal, "SERR %08x" NL, esr);
+
+ if (esr & MAL_ESR_EVB) {
+ if (esr & MAL_ESR_DE) {
+ /* We ignore Descriptor error,
+ * TXDE or RXDE interrupt will be generated anyway.
+ */
+ return IRQ_HANDLED;
+ }
+
+ if (esr & MAL_ESR_PEIN) {
+ /* PLB error, it's probably buggy hardware or
+ * incorrect physical address in BD (i.e. bug)
+ */
+ if (net_ratelimit())
+ printk(KERN_ERR
+ "mal%d: system error, "
+ "PLB (ESR = 0x%08x)\n",
+ mal->index, esr);
+ return IRQ_HANDLED;
+ }
+
+ /* OPB error, it's probably buggy hardware or incorrect
+ * EBC setup
+ */
+ if (net_ratelimit())
+ printk(KERN_ERR
+ "mal%d: system error, OPB (ESR = 0x%08x)\n",
+ mal->index, esr);
+ }
+ return IRQ_HANDLED;
+}
+
+static inline void mal_schedule_poll(struct mal_instance *mal)
+{
+ if (likely(napi_schedule_prep(&mal->napi))) {
+ MAL_DBG2(mal, "schedule_poll" NL);
+ mal_disable_eob_irq(mal);
+ __napi_schedule(&mal->napi);
+ } else
+ MAL_DBG2(mal, "already in poll" NL);
+}
+
+static irqreturn_t mal_txeob(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 r = get_mal_dcrn(mal, MAL_TXEOBISR);
+
+ MAL_DBG2(mal, "txeob %08x" NL, r);
+
+ mal_schedule_poll(mal);
+ set_mal_dcrn(mal, MAL_TXEOBISR, r);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_rxeob(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 r = get_mal_dcrn(mal, MAL_RXEOBISR);
+
+ MAL_DBG2(mal, "rxeob %08x" NL, r);
+
+ mal_schedule_poll(mal);
+ set_mal_dcrn(mal, MAL_RXEOBISR, r);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_txde(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
+ set_mal_dcrn(mal, MAL_TXDEIR, deir);
+
+ MAL_DBG(mal, "txde %08x" NL, deir);
+
+ if (net_ratelimit())
+ printk(KERN_ERR
+ "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n",
+ mal->index, deir);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_rxde(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+ struct list_head *l;
+
+ u32 deir = get_mal_dcrn(mal, MAL_RXDEIR);
+
+ MAL_DBG(mal, "rxde %08x" NL, deir);
+
+ list_for_each(l, &mal->list) {
+ struct mal_commac *mc = list_entry(l, struct mal_commac, list);
+ if (deir & mc->rx_chan_mask) {
+ set_bit(MAL_COMMAC_RX_STOPPED, &mc->flags);
+ mc->ops->rxde(mc->dev);
+ }
+ }
+
+ mal_schedule_poll(mal);
+ set_mal_dcrn(mal, MAL_RXDEIR, deir);
+
+ return IRQ_HANDLED;
+}
+
+void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac)
+{
+ /* Spinlock-type semantics: only one caller disable poll at a time */
+ while (test_and_set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags))
+ msleep(1);
+
+ /* Synchronize with the MAL NAPI poller. */
+ napi_disable(&mal->napi);
+}
+
+void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac)
+{
+ smp_wmb();
+ clear_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags);
+
+ // XXX might want to kick a poll now...
+}
+
+static int mal_poll(struct napi_struct *napi, int budget)
+{
+ struct mal_instance *mal = container_of(napi, struct mal_instance, napi);
+ struct list_head *l;
+ int received = 0;
+ unsigned long flags;
+
+ MAL_DBG2(mal, "poll(%d) %d ->" NL, *budget,
+ rx_work_limit);
+ again:
+ /* Process TX skbs */
+ list_for_each(l, &mal->poll_list) {
+ struct mal_commac *mc =
+ list_entry(l, struct mal_commac, poll_list);
+ mc->ops->poll_tx(mc->dev);
+ }
+
+ /* Process RX skbs.
+ *
+ * We _might_ need something more smart here to enforce polling
+ * fairness.
+ */
+ list_for_each(l, &mal->poll_list) {
+ struct mal_commac *mc =
+ list_entry(l, struct mal_commac, poll_list);
+ int n;
+ if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
+ continue;
+ n = mc->ops->poll_rx(mc->dev, budget);
+ if (n) {
+ received += n;
+ budget -= n;
+ if (budget <= 0)
+ goto more_work; // XXX What if this is the last one ?
+ }
+ }
+
+ /* We need to disable IRQs to protect from RXDE IRQ here */
+ spin_lock_irqsave(&mal->lock, flags);
+ __napi_complete(napi);
+ mal_enable_eob_irq(mal);
+ spin_unlock_irqrestore(&mal->lock, flags);
+
+ /* Check for "rotting" packet(s) */
+ list_for_each(l, &mal->poll_list) {
+ struct mal_commac *mc =
+ list_entry(l, struct mal_commac, poll_list);
+ if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
+ continue;
+ if (unlikely(mc->ops->peek_rx(mc->dev) ||
+ test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) {
+ MAL_DBG2(mal, "rotting packet" NL);
+ if (napi_reschedule(napi))
+ mal_disable_eob_irq(mal);
+ else
+ MAL_DBG2(mal, "already in poll list" NL);
+
+ if (budget > 0)
+ goto again;
+ else
+ goto more_work;
+ }
+ mc->ops->poll_tx(mc->dev);
+ }
+
+ more_work:
+ MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received);
+ return received;
+}
+
+static void mal_reset(struct mal_instance *mal)
+{
+ int n = 10;
+
+ MAL_DBG(mal, "reset" NL);
+
+ set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR);
+
+ /* Wait for reset to complete (1 system clock) */
+ while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n)
+ --n;
+
+ if (unlikely(!n))
+ printk(KERN_ERR "mal%d: reset timeout\n", mal->index);
+}
+
+int mal_get_regs_len(struct mal_instance *mal)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct mal_regs);
+}
+
+void *mal_dump_regs(struct mal_instance *mal, void *buf)
+{
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct mal_regs *regs = (struct mal_regs *)(hdr + 1);
+ int i;
+
+ hdr->version = mal->version;
+ hdr->index = mal->index;
+
+ regs->tx_count = mal->num_tx_chans;
+ regs->rx_count = mal->num_rx_chans;
+
+ regs->cfg = get_mal_dcrn(mal, MAL_CFG);
+ regs->esr = get_mal_dcrn(mal, MAL_ESR);
+ regs->ier = get_mal_dcrn(mal, MAL_IER);
+ regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR);
+ regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR);
+ regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR);
+ regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR);
+ regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR);
+ regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR);
+ regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR);
+ regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR);
+
+ for (i = 0; i < regs->tx_count; ++i)
+ regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i));
+
+ for (i = 0; i < regs->rx_count; ++i) {
+ regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i));
+ regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i));
+ }
+ return regs + 1;
+}
+
+static int __devinit mal_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct mal_instance *mal;
+ int err = 0, i, bd_size;
+ int index = mal_count++;
+ const u32 *prop;
+ u32 cfg;
+
+ mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
+ if (!mal) {
+ printk(KERN_ERR
+ "mal%d: out of memory allocating MAL structure!\n",
+ index);
+ return -ENOMEM;
+ }
+ mal->index = index;
+ mal->ofdev = ofdev;
+ mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1;
+
+ MAL_DBG(mal, "probe" NL);
+
+ prop = of_get_property(ofdev->node, "num-tx-chans", NULL);
+ if (prop == NULL) {
+ printk(KERN_ERR
+ "mal%d: can't find MAL num-tx-chans property!\n",
+ index);
+ err = -ENODEV;
+ goto fail;
+ }
+ mal->num_tx_chans = prop[0];
+
+ prop = of_get_property(ofdev->node, "num-rx-chans", NULL);
+ if (prop == NULL) {
+ printk(KERN_ERR
+ "mal%d: can't find MAL num-rx-chans property!\n",
+ index);
+ err = -ENODEV;
+ goto fail;
+ }
+ mal->num_rx_chans = prop[0];
+
+ mal->dcr_base = dcr_resource_start(ofdev->node, 0);
+ if (mal->dcr_base == 0) {
+ printk(KERN_ERR
+ "mal%d: can't find DCR resource!\n", index);
+ err = -ENODEV;
+ goto fail;
+ }
+ mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100);
+ if (!DCR_MAP_OK(mal->dcr_host)) {
+ printk(KERN_ERR
+ "mal%d: failed to map DCRs !\n", index);
+ err = -ENODEV;
+ goto fail;
+ }
+
+ mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
+ mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
+ mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);
+ mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
+ mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+ if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||
+ mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ ||
+ mal->rxde_irq == NO_IRQ) {
+ printk(KERN_ERR
+ "mal%d: failed to map interrupts !\n", index);
+ err = -ENODEV;
+ goto fail_unmap;
+ }
+
+ INIT_LIST_HEAD(&mal->poll_list);
+ mal->napi.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT;
+ mal->napi.poll = mal_poll;
+ INIT_LIST_HEAD(&mal->list);
+ spin_lock_init(&mal->lock);
+
+ /* Load power-on reset defaults */
+ mal_reset(mal);
+
+ /* Set the MAL configuration register */
+ cfg = (mal->version == 2) ? MAL2_CFG_DEFAULT : MAL1_CFG_DEFAULT;
+ cfg |= MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA;
+
+ /* Current Axon is not happy with priority being non-0, it can
+ * deadlock, fix it up here
+ */
+ if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon"))
+ cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10);
+
+ /* Apply configuration */
+ set_mal_dcrn(mal, MAL_CFG, cfg);
+
+ /* Allocate space for BD rings */
+ BUG_ON(mal->num_tx_chans <= 0 || mal->num_tx_chans > 32);
+ BUG_ON(mal->num_rx_chans <= 0 || mal->num_rx_chans > 32);
+
+ bd_size = sizeof(struct mal_descriptor) *
+ (NUM_TX_BUFF * mal->num_tx_chans +
+ NUM_RX_BUFF * mal->num_rx_chans);
+ mal->bd_virt =
+ dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
+ GFP_KERNEL);
+ if (mal->bd_virt == NULL) {
+ printk(KERN_ERR
+ "mal%d: out of memory allocating RX/TX descriptors!\n",
+ index);
+ err = -ENOMEM;
+ goto fail_unmap;
+ }
+ memset(mal->bd_virt, 0, bd_size);
+
+ for (i = 0; i < mal->num_tx_chans; ++i)
+ set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +
+ sizeof(struct mal_descriptor) *
+ mal_tx_bd_offset(mal, i));
+
+ for (i = 0; i < mal->num_rx_chans; ++i)
+ set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma +
+ sizeof(struct mal_descriptor) *
+ mal_rx_bd_offset(mal, i));
+
+ err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal);
+ if (err)
+ goto fail2;
+ err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal);
+ if (err)
+ goto fail3;
+ err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
+ if (err)
+ goto fail4;
+ err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
+ if (err)
+ goto fail5;
+ err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
+ if (err)
+ goto fail6;
+
+ /* Enable all MAL SERR interrupt sources */
+ if (mal->version == 2)
+ set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS);
+ else
+ set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS);
+
+ /* Enable EOB interrupt */
+ mal_enable_eob_irq(mal);
+
+ printk(KERN_INFO
+ "MAL v%d %s, %d TX channels, %d RX channels\n",
+ mal->version, ofdev->node->full_name,
+ mal->num_tx_chans, mal->num_rx_chans);
+
+ /* Advertise this instance to the rest of the world */
+ wmb();
+ dev_set_drvdata(&ofdev->dev, mal);
+
+ mal_dbg_register(mal);
+
+ return 0;
+
+ fail6:
+ free_irq(mal->rxde_irq, mal);
+ fail5:
+ free_irq(mal->txeob_irq, mal);
+ fail4:
+ free_irq(mal->txde_irq, mal);
+ fail3:
+ free_irq(mal->serr_irq, mal);
+ fail2:
+ dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
+ fail_unmap:
+ dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100);
+ fail:
+ kfree(mal);
+
+ return err;
+}
+
+static int __devexit mal_remove(struct of_device *ofdev)
+{
+ struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);
+
+ MAL_DBG(mal, "remove" NL);
+
+ /* Synchronize with scheduled polling */
+ napi_disable(&mal->napi);
+
+ if (!list_empty(&mal->list)) {
+ /* This is *very* bad */
+ printk(KERN_EMERG
+ "mal%d: commac list is not empty on remove!\n",
+ mal->index);
+ WARN_ON(1);
+ }
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ free_irq(mal->serr_irq, mal);
+ free_irq(mal->txde_irq, mal);
+ free_irq(mal->txeob_irq, mal);
+ free_irq(mal->rxde_irq, mal);
+ free_irq(mal->rxeob_irq, mal);
+
+ mal_reset(mal);
+
+ mal_dbg_unregister(mal);
+
+ dma_free_coherent(&ofdev->dev,
+ sizeof(struct mal_descriptor) *
+ (NUM_TX_BUFF * mal->num_tx_chans +
+ NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt,
+ mal->bd_dma);
+ kfree(mal);
+
+ return 0;
+}
+
+static struct of_device_id mal_platform_match[] =
+{
+ {
+ .compatible = "ibm,mcmal",
+ },
+ {
+ .compatible = "ibm,mcmal2",
+ },
+ /* Backward compat */
+ {
+ .type = "mcmal-dma",
+ .compatible = "ibm,mcmal",
+ },
+ {
+ .type = "mcmal-dma",
+ .compatible = "ibm,mcmal2",
+ },
+ {},
+};
+
+static struct of_platform_driver mal_of_driver = {
+ .name = "mcmal",
+ .match_table = mal_platform_match,
+
+ .probe = mal_probe,
+ .remove = mal_remove,
+};
+
+int __init mal_init(void)
+{
+ return of_register_platform_driver(&mal_of_driver);
+}
+
+void mal_exit(void)
+{
+ of_unregister_platform_driver(&mal_of_driver);
+}
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
new file mode 100644
index 000000000000..cb1a16d589fe
--- /dev/null
+++ b/drivers/net/ibm_newemac/mal.h
@@ -0,0 +1,276 @@
+/*
+ * drivers/net/ibm_newemac/mal.h
+ *
+ * Memory Access Layer (MAL) support
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_MAL_H
+#define __IBM_NEWEMAC_MAL_H
+
+/*
+ * There are some variations on the MAL, we express them in this driver as
+ * MAL Version 1 and 2 though that doesn't match any IBM terminology.
+ *
+ * We call MAL 1 the version in 405GP, 405GPR, 405EP, 440EP, 440GR and
+ * NP405H.
+ *
+ * We call MAL 2 the version in 440GP, 440GX, 440SP, 440SPE and Axon
+ *
+ * The driver expects a "version" property in the emac node containing
+ * a number 1 or 2. New device-trees for EMAC capable platforms are thus
+ * required to include that when porting to arch/powerpc.
+ */
+
+/* MALx DCR registers */
+#define MAL_CFG 0x00
+#define MAL_CFG_SR 0x80000000
+#define MAL_CFG_PLBB 0x00004000
+#define MAL_CFG_OPBBL 0x00000080
+#define MAL_CFG_EOPIE 0x00000004
+#define MAL_CFG_LEA 0x00000002
+#define MAL_CFG_SD 0x00000001
+
+/* MAL V1 CFG bits */
+#define MAL1_CFG_PLBP_MASK 0x00c00000
+#define MAL1_CFG_PLBP_10 0x00800000
+#define MAL1_CFG_GA 0x00200000
+#define MAL1_CFG_OA 0x00100000
+#define MAL1_CFG_PLBLE 0x00080000
+#define MAL1_CFG_PLBT_MASK 0x00078000
+#define MAL1_CFG_DEFAULT (MAL1_CFG_PLBP_10 | MAL1_CFG_PLBT_MASK)
+
+/* MAL V2 CFG bits */
+#define MAL2_CFG_RPP_MASK 0x00c00000
+#define MAL2_CFG_RPP_10 0x00800000
+#define MAL2_CFG_RMBS_MASK 0x00300000
+#define MAL2_CFG_WPP_MASK 0x000c0000
+#define MAL2_CFG_WPP_10 0x00080000
+#define MAL2_CFG_WMBS_MASK 0x00030000
+#define MAL2_CFG_PLBLE 0x00008000
+#define MAL2_CFG_DEFAULT (MAL2_CFG_RMBS_MASK | MAL2_CFG_WMBS_MASK | \
+ MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10)
+
+#define MAL_ESR 0x01
+#define MAL_ESR_EVB 0x80000000
+#define MAL_ESR_CIDT 0x40000000
+#define MAL_ESR_CID_MASK 0x3e000000
+#define MAL_ESR_CID_SHIFT 25
+#define MAL_ESR_DE 0x00100000
+#define MAL_ESR_OTE 0x00040000
+#define MAL_ESR_OSE 0x00020000
+#define MAL_ESR_PEIN 0x00010000
+#define MAL_ESR_DEI 0x00000010
+#define MAL_ESR_OTEI 0x00000004
+#define MAL_ESR_OSEI 0x00000002
+#define MAL_ESR_PBEI 0x00000001
+
+/* MAL V1 ESR bits */
+#define MAL1_ESR_ONE 0x00080000
+#define MAL1_ESR_ONEI 0x00000008
+
+/* MAL V2 ESR bits */
+#define MAL2_ESR_PTE 0x00800000
+#define MAL2_ESR_PRE 0x00400000
+#define MAL2_ESR_PWE 0x00200000
+#define MAL2_ESR_PTEI 0x00000080
+#define MAL2_ESR_PREI 0x00000040
+#define MAL2_ESR_PWEI 0x00000020
+
+
+#define MAL_IER 0x02
+#define MAL_IER_DE 0x00000010
+#define MAL_IER_OTE 0x00000004
+#define MAL_IER_OE 0x00000002
+#define MAL_IER_PE 0x00000001
+/* MAL V1 IER bits */
+#define MAL1_IER_NWE 0x00000008
+#define MAL1_IER_SOC_EVENTS MAL1_IER_NWE
+#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \
+ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+
+/* MAL V2 IER bits */
+#define MAL2_IER_PT 0x00000080
+#define MAL2_IER_PRE 0x00000040
+#define MAL2_IER_PWE 0x00000020
+#define MAL2_IER_SOC_EVENTS (MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE)
+#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \
+ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+
+
+#define MAL_TXCASR 0x04
+#define MAL_TXCARR 0x05
+#define MAL_TXEOBISR 0x06
+#define MAL_TXDEIR 0x07
+#define MAL_RXCASR 0x10
+#define MAL_RXCARR 0x11
+#define MAL_RXEOBISR 0x12
+#define MAL_RXDEIR 0x13
+#define MAL_TXCTPR(n) ((n) + 0x20)
+#define MAL_RXCTPR(n) ((n) + 0x40)
+#define MAL_RCBS(n) ((n) + 0x60)
+
+/* In reality MAL can handle TX buffers up to 4095 bytes long,
+ * but this isn't a good round number :) --ebs
+ */
+#define MAL_MAX_TX_SIZE 4080
+#define MAL_MAX_RX_SIZE 4080
+
+static inline int mal_rx_size(int len)
+{
+ len = (len + 0xf) & ~0xf;
+ return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len;
+}
+
+static inline int mal_tx_chunks(int len)
+{
+ return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE;
+}
+
+#define MAL_CHAN_MASK(n) (0x80000000 >> (n))
+
+/* MAL Buffer Descriptor structure */
+struct mal_descriptor {
+ u16 ctrl; /* MAL / Commac status control bits */
+ u16 data_len; /* Max length is 4K-1 (12 bits) */
+ u32 data_ptr; /* pointer to actual data buffer */
+};
+
+/* the following defines are for the MadMAL status and control registers. */
+/* MADMAL transmit and receive status/control bits */
+#define MAL_RX_CTRL_EMPTY 0x8000
+#define MAL_RX_CTRL_WRAP 0x4000
+#define MAL_RX_CTRL_CM 0x2000
+#define MAL_RX_CTRL_LAST 0x1000
+#define MAL_RX_CTRL_FIRST 0x0800
+#define MAL_RX_CTRL_INTR 0x0400
+#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST)
+#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE)
+
+#define MAL_TX_CTRL_READY 0x8000
+#define MAL_TX_CTRL_WRAP 0x4000
+#define MAL_TX_CTRL_CM 0x2000
+#define MAL_TX_CTRL_LAST 0x1000
+#define MAL_TX_CTRL_INTR 0x0400
+
+struct mal_commac_ops {
+ void (*poll_tx) (void *dev);
+ int (*poll_rx) (void *dev, int budget);
+ int (*peek_rx) (void *dev);
+ void (*rxde) (void *dev);
+};
+
+struct mal_commac {
+ struct mal_commac_ops *ops;
+ void *dev;
+ struct list_head poll_list;
+ long flags;
+#define MAL_COMMAC_RX_STOPPED 0
+#define MAL_COMMAC_POLL_DISABLED 1
+ u32 tx_chan_mask;
+ u32 rx_chan_mask;
+ struct list_head list;
+};
+
+struct mal_instance {
+ int version;
+ int dcr_base;
+ dcr_host_t dcr_host;
+
+ int num_tx_chans; /* Number of TX channels */
+ int num_rx_chans; /* Number of RX channels */
+ int txeob_irq; /* TX End Of Buffer IRQ */
+ int rxeob_irq; /* RX End Of Buffer IRQ */
+ int txde_irq; /* TX Descriptor Error IRQ */
+ int rxde_irq; /* RX Descriptor Error IRQ */
+ int serr_irq; /* MAL System Error IRQ */
+
+ struct list_head poll_list;
+ struct napi_struct napi;
+
+ struct list_head list;
+ u32 tx_chan_mask;
+ u32 rx_chan_mask;
+
+ dma_addr_t bd_dma;
+ struct mal_descriptor *bd_virt;
+
+ struct of_device *ofdev;
+ int index;
+ spinlock_t lock;
+};
+
+static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
+{
+ return dcr_read(mal->dcr_host, mal->dcr_base + reg);
+}
+
+static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
+{
+ dcr_write(mal->dcr_host, mal->dcr_base + reg, val);
+}
+
+/* Register MAL devices */
+int mal_init(void);
+void mal_exit(void);
+
+int mal_register_commac(struct mal_instance *mal,
+ struct mal_commac *commac);
+void mal_unregister_commac(struct mal_instance *mal,
+ struct mal_commac *commac);
+int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size);
+
+/* Returns BD ring offset for a particular channel
+ (in 'struct mal_descriptor' elements)
+*/
+int mal_tx_bd_offset(struct mal_instance *mal, int channel);
+int mal_rx_bd_offset(struct mal_instance *mal, int channel);
+
+void mal_enable_tx_channel(struct mal_instance *mal, int channel);
+void mal_disable_tx_channel(struct mal_instance *mal, int channel);
+void mal_enable_rx_channel(struct mal_instance *mal, int channel);
+void mal_disable_rx_channel(struct mal_instance *mal, int channel);
+
+void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac);
+void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac);
+
+/* Add/remove EMAC to/from MAL polling list */
+void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac);
+void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac);
+
+/* Ethtool MAL registers */
+struct mal_regs {
+ u32 tx_count;
+ u32 rx_count;
+
+ u32 cfg;
+ u32 esr;
+ u32 ier;
+ u32 tx_casr;
+ u32 tx_carr;
+ u32 tx_eobisr;
+ u32 tx_deir;
+ u32 rx_casr;
+ u32 rx_carr;
+ u32 rx_eobisr;
+ u32 rx_deir;
+ u32 tx_ctpr[32];
+ u32 rx_ctpr[32];
+ u32 rcbs[32];
+};
+
+int mal_get_regs_len(struct mal_instance *mal);
+void *mal_dump_regs(struct mal_instance *mal, void *buf);
+
+#endif /* __IBM_NEWEMAC_MAL_H */
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c
new file mode 100644
index 000000000000..aa1f0ddf1e3e
--- /dev/null
+++ b/drivers/net/ibm_newemac/phy.c
@@ -0,0 +1,373 @@
+/*
+ * drivers/net/ibm_newemac/phy.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
+ * Borrowed from sungem_phy.c, though I only kept the generic MII
+ * driver for now.
+ *
+ * This file should be shared with other drivers or eventually
+ * merged as the "low level" part of miilib
+ *
+ * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "emac.h"
+#include "phy.h"
+
+static inline int phy_read(struct mii_phy *phy, int reg)
+{
+ return phy->mdio_read(phy->dev, phy->address, reg);
+}
+
+static inline void phy_write(struct mii_phy *phy, int reg, int val)
+{
+ phy->mdio_write(phy->dev, phy->address, reg, val);
+}
+
+int emac_mii_reset_phy(struct mii_phy *phy)
+{
+ int val;
+ int limit = 10000;
+
+ val = phy_read(phy, MII_BMCR);
+ val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
+ val |= BMCR_RESET;
+ phy_write(phy, MII_BMCR, val);
+
+ udelay(300);
+
+ while (limit--) {
+ val = phy_read(phy, MII_BMCR);
+ if (val >= 0 && (val & BMCR_RESET) == 0)
+ break;
+ udelay(10);
+ }
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
+
+ return limit <= 0;
+}
+
+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ int ctl, adv;
+
+ phy->autoneg = AUTONEG_ENABLE;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = phy->asym_pause = 0;
+ phy->advertising = advertise;
+
+ ctl = phy_read(phy, MII_BMCR);
+ if (ctl < 0)
+ return ctl;
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+
+ /* First clear the PHY */
+ phy_write(phy, MII_BMCR, ctl);
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, MII_ADVERTISE);
+ if (adv < 0)
+ return adv;
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ if (phy->features &
+ (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
+ adv = phy_read(phy, MII_CTRL1000);
+ if (adv < 0)
+ return adv;
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if (advertise & ADVERTISED_1000baseT_Full)
+ adv |= ADVERTISE_1000FULL;
+ if (advertise & ADVERTISED_1000baseT_Half)
+ adv |= ADVERTISE_1000HALF;
+ phy_write(phy, MII_CTRL1000, adv);
+ }
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ int ctl;
+
+ phy->autoneg = AUTONEG_DISABLE;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = phy->asym_pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ if (ctl < 0)
+ return ctl;
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+
+ /* First clear the PHY */
+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+ /* Select speed & duplex */
+ switch (speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ ctl |= BMCR_SPEED100;
+ break;
+ case SPEED_1000:
+ ctl |= BMCR_SPEED1000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (fd == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+ int status;
+
+ /* Clear latched value with dummy read */
+ phy_read(phy, MII_BMSR);
+ status = phy_read(phy, MII_BMSR);
+ if (status < 0 || (status & BMSR_LSTATUS) == 0)
+ return 0;
+ if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
+ return 0;
+ return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+ if (phy->autoneg == AUTONEG_ENABLE) {
+ int glpa = 0;
+ int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
+ if (lpa < 0)
+ return lpa;
+
+ if (phy->features &
+ (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
+ int adv = phy_read(phy, MII_CTRL1000);
+ glpa = phy_read(phy, MII_STAT1000);
+
+ if (glpa < 0 || adv < 0)
+ return adv;
+
+ glpa &= adv << 2;
+ }
+
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = phy->asym_pause = 0;
+
+ if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
+ phy->speed = SPEED_1000;
+ if (glpa & LPA_1000FULL)
+ phy->duplex = DUPLEX_FULL;
+ } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phy->speed = SPEED_100;
+ if (lpa & LPA_100FULL)
+ phy->duplex = DUPLEX_FULL;
+ } else if (lpa & LPA_10FULL)
+ phy->duplex = DUPLEX_FULL;
+
+ if (phy->duplex == DUPLEX_FULL) {
+ phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+ phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+ }
+ } else {
+ int bmcr = phy_read(phy, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phy->duplex = DUPLEX_FULL;
+ else
+ phy->duplex = DUPLEX_HALF;
+ if (bmcr & BMCR_SPEED1000)
+ phy->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phy->speed = SPEED_100;
+ else
+ phy->speed = SPEED_10;
+
+ phy->pause = phy->asym_pause = 0;
+ }
+ return 0;
+}
+
+/* Generic implementation for most 10/100/1000 PHYs */
+static struct mii_phy_ops generic_phy_ops = {
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def genmii_phy_def = {
+ .phy_id = 0x00000000,
+ .phy_id_mask = 0x00000000,
+ .name = "Generic MII",
+ .ops = &generic_phy_ops
+};
+
+/* CIS8201 */
+#define MII_CIS8201_10BTCSR 0x16
+#define TENBTCSR_ECHO_DISABLE 0x2000
+#define MII_CIS8201_EPCR 0x17
+#define EPCR_MODE_MASK 0x3000
+#define EPCR_GMII_MODE 0x0000
+#define EPCR_RGMII_MODE 0x1000
+#define EPCR_TBI_MODE 0x2000
+#define EPCR_RTBI_MODE 0x3000
+#define MII_CIS8201_ACSR 0x1c
+#define ACSR_PIN_PRIO_SELECT 0x0004
+
+static int cis8201_init(struct mii_phy *phy)
+{
+ int epcr;
+
+ epcr = phy_read(phy, MII_CIS8201_EPCR);
+ if (epcr < 0)
+ return epcr;
+
+ epcr &= ~EPCR_MODE_MASK;
+
+ switch (phy->mode) {
+ case PHY_MODE_TBI:
+ epcr |= EPCR_TBI_MODE;
+ break;
+ case PHY_MODE_RTBI:
+ epcr |= EPCR_RTBI_MODE;
+ break;
+ case PHY_MODE_GMII:
+ epcr |= EPCR_GMII_MODE;
+ break;
+ case PHY_MODE_RGMII:
+ default:
+ epcr |= EPCR_RGMII_MODE;
+ }
+
+ phy_write(phy, MII_CIS8201_EPCR, epcr);
+
+ /* MII regs override strap pins */
+ phy_write(phy, MII_CIS8201_ACSR,
+ phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
+
+ /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
+ phy_write(phy, MII_CIS8201_10BTCSR,
+ phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
+
+ return 0;
+}
+
+static struct mii_phy_ops cis8201_phy_ops = {
+ .init = cis8201_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def cis8201_phy_def = {
+ .phy_id = 0x000fc410,
+ .phy_id_mask = 0x000ffff0,
+ .name = "CIS8201 Gigabit Ethernet",
+ .ops = &cis8201_phy_ops
+};
+
+static struct mii_phy_def *mii_phy_table[] = {
+ &cis8201_phy_def,
+ &genmii_phy_def,
+ NULL
+};
+
+int emac_mii_phy_probe(struct mii_phy *phy, int address)
+{
+ struct mii_phy_def *def;
+ int i;
+ u32 id;
+
+ phy->autoneg = AUTONEG_DISABLE;
+ phy->advertising = 0;
+ phy->address = address;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = phy->asym_pause = 0;
+
+ /* Take PHY out of isolate mode and reset it. */
+ if (emac_mii_reset_phy(phy))
+ return -ENODEV;
+
+ /* Read ID and find matching entry */
+ id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
+ for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
+ if ((id & def->phy_id_mask) == def->phy_id)
+ break;
+ /* Should never be NULL (we have a generic entry), but... */
+ if (!def)
+ return -ENODEV;
+
+ phy->def = def;
+
+ /* Determine PHY features if needed */
+ phy->features = def->features;
+ if (!phy->features) {
+ u16 bmsr = phy_read(phy, MII_BMSR);
+ if (bmsr & BMSR_ANEGCAPABLE)
+ phy->features |= SUPPORTED_Autoneg;
+ if (bmsr & BMSR_10HALF)
+ phy->features |= SUPPORTED_10baseT_Half;
+ if (bmsr & BMSR_10FULL)
+ phy->features |= SUPPORTED_10baseT_Full;
+ if (bmsr & BMSR_100HALF)
+ phy->features |= SUPPORTED_100baseT_Half;
+ if (bmsr & BMSR_100FULL)
+ phy->features |= SUPPORTED_100baseT_Full;
+ if (bmsr & BMSR_ESTATEN) {
+ u16 esr = phy_read(phy, MII_ESTATUS);
+ if (esr & ESTATUS_1000_TFULL)
+ phy->features |= SUPPORTED_1000baseT_Full;
+ if (esr & ESTATUS_1000_THALF)
+ phy->features |= SUPPORTED_1000baseT_Half;
+ }
+ phy->features |= SUPPORTED_MII;
+ }
+
+ /* Setup default advertising */
+ phy->advertising = phy->features;
+
+ return 0;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h
new file mode 100644
index 000000000000..6feca26afedb
--- /dev/null
+++ b/drivers/net/ibm_newemac/phy.h
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/ibm_newemac/phy.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, PHY support
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * February 2003
+ *
+ * Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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 file basically duplicates sungem_phy.{c,h} with different PHYs
+ * supported. I'm looking into merging that in a single mii layer more
+ * flexible than mii.c
+ */
+
+#ifndef __IBM_NEWEMAC_PHY_H
+#define __IBM_NEWEMAC_PHY_H
+
+struct mii_phy;
+
+/* Operations supported by any kind of PHY */
+struct mii_phy_ops {
+ int (*init) (struct mii_phy * phy);
+ int (*suspend) (struct mii_phy * phy, int wol_options);
+ int (*setup_aneg) (struct mii_phy * phy, u32 advertise);
+ int (*setup_forced) (struct mii_phy * phy, int speed, int fd);
+ int (*poll_link) (struct mii_phy * phy);
+ int (*read_link) (struct mii_phy * phy);
+};
+
+/* Structure used to statically define an mii/gii based PHY */
+struct mii_phy_def {
+ u32 phy_id; /* Concatenated ID1 << 16 | ID2 */
+ u32 phy_id_mask; /* Significant bits */
+ u32 features; /* Ethtool SUPPORTED_* defines or
+ 0 for autodetect */
+ int magic_aneg; /* Autoneg does all speed test for us */
+ const char *name;
+ const struct mii_phy_ops *ops;
+};
+
+/* An instance of a PHY, partially borrowed from mii_if_info */
+struct mii_phy {
+ struct mii_phy_def *def;
+ u32 advertising; /* Ethtool ADVERTISED_* defines */
+ u32 features; /* Copied from mii_phy_def.features
+ or determined automaticaly */
+ int address; /* PHY address */
+ int mode; /* PHY mode */
+
+ /* 1: autoneg enabled, 0: disabled */
+ int autoneg;
+
+ /* forced speed & duplex (no autoneg)
+ * partner speed & duplex & pause (autoneg)
+ */
+ int speed;
+ int duplex;
+ int pause;
+ int asym_pause;
+
+ /* Provided by host chip */
+ struct net_device *dev;
+ int (*mdio_read) (struct net_device * dev, int addr, int reg);
+ void (*mdio_write) (struct net_device * dev, int addr, int reg,
+ int val);
+};
+
+/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
+ * filled, the remaining fields will be filled on return
+ */
+int emac_mii_phy_probe(struct mii_phy *phy, int address);
+int emac_mii_reset_phy(struct mii_phy *phy);
+
+#endif /* __IBM_NEWEMAC_PHY_H */
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
new file mode 100644
index 000000000000..bcd7fc639c40
--- /dev/null
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -0,0 +1,323 @@
+/*
+ * drivers/net/ibm_newemac/rgmii.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+
+#include "emac.h"
+#include "debug.h"
+
+// XXX FIXME: Axon seems to support a subset of the RGMII, we
+// thus need to take that into account and possibly change some
+// of the bit settings below that don't seem to quite match the
+// AXON spec
+
+/* RGMIIx_FER */
+#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4))
+#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4))
+#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4))
+#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4))
+#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4))
+
+/* RGMIIx_SSR */
+#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8))
+#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8))
+#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8))
+
+/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
+static inline int rgmii_valid_mode(int phy_mode)
+{
+ return phy_mode == PHY_MODE_GMII ||
+ phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+static inline const char *rgmii_mode_name(int mode)
+{
+ switch (mode) {
+ case PHY_MODE_RGMII:
+ return "RGMII";
+ case PHY_MODE_TBI:
+ return "TBI";
+ case PHY_MODE_GMII:
+ return "GMII";
+ case PHY_MODE_RTBI:
+ return "RTBI";
+ default:
+ BUG();
+ }
+}
+
+static inline u32 rgmii_mode_mask(int mode, int input)
+{
+ switch (mode) {
+ case PHY_MODE_RGMII:
+ return RGMII_FER_RGMII(input);
+ case PHY_MODE_TBI:
+ return RGMII_FER_TBI(input);
+ case PHY_MODE_GMII:
+ return RGMII_FER_GMII(input);
+ case PHY_MODE_RTBI:
+ return RGMII_FER_RTBI(input);
+ default:
+ BUG();
+ }
+}
+
+int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs *p = dev->base;
+
+ RGMII_DBG(dev, "attach(%d)" NL, input);
+
+ /* Check if we need to attach to a RGMII */
+ if (input < 0 || !rgmii_valid_mode(mode)) {
+ printk(KERN_ERR "%s: unsupported settings !\n",
+ ofdev->node->full_name);
+ return -ENODEV;
+ }
+
+ mutex_lock(&dev->lock);
+
+ /* Enable this input */
+ out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
+
+ printk(KERN_NOTICE "%s: input %d in %s mode\n",
+ ofdev->node->full_name, input, rgmii_mode_name(mode));
+
+ ++dev->users;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs *p = dev->base;
+ u32 ssr;
+
+ mutex_lock(&dev->lock);
+
+ ssr = in_be32(&p->ssr) & ~RGMII_SSR_MASK(input);
+
+ RGMII_DBG(dev, "speed(%d, %d)" NL, input, speed);
+
+ if (speed == SPEED_1000)
+ ssr |= RGMII_SSR_1000(input);
+ else if (speed == SPEED_100)
+ ssr |= RGMII_SSR_100(input);
+
+ out_be32(&p->ssr, ssr);
+
+ mutex_unlock(&dev->lock);
+}
+
+void rgmii_get_mdio(struct of_device *ofdev, int input)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs *p = dev->base;
+ u32 fer;
+
+ RGMII_DBG2(dev, "get_mdio(%d)" NL, input);
+
+ if (dev->type != RGMII_AXON)
+ return;
+
+ mutex_lock(&dev->lock);
+
+ fer = in_be32(&p->fer);
+ fer |= 0x00080000u >> input;
+ out_be32(&p->fer, fer);
+ (void)in_be32(&p->fer);
+
+ DBG2(dev, " fer = 0x%08x\n", fer);
+}
+
+void rgmii_put_mdio(struct of_device *ofdev, int input)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs *p = dev->base;
+ u32 fer;
+
+ RGMII_DBG2(dev, "put_mdio(%d)" NL, input);
+
+ if (dev->type != RGMII_AXON)
+ return;
+
+ fer = in_be32(&p->fer);
+ fer &= ~(0x00080000u >> input);
+ out_be32(&p->fer, fer);
+ (void)in_be32(&p->fer);
+
+ DBG2(dev, " fer = 0x%08x\n", fer);
+
+ mutex_unlock(&dev->lock);
+}
+
+void __devexit rgmii_detach(struct of_device *ofdev, int input)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs *p = dev->base;
+
+ mutex_lock(&dev->lock);
+
+ BUG_ON(!dev || dev->users == 0);
+
+ RGMII_DBG(dev, "detach(%d)" NL, input);
+
+ /* Disable this input */
+ out_be32(&p->fer, in_be32(&p->fer) & ~RGMII_FER_MASK(input));
+
+ --dev->users;
+
+ mutex_unlock(&dev->lock);
+}
+
+int rgmii_get_regs_len(struct of_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct rgmii_regs);
+}
+
+void *rgmii_dump_regs(struct of_device *ofdev, void *buf)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * rgmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs));
+ return regs + 1;
+}
+
+
+static int __devinit rgmii_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct rgmii_instance *dev;
+ struct resource regs;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: could not allocate RGMII device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+
+ mutex_init(&dev->lock);
+ dev->ofdev = ofdev;
+
+ rc = -ENXIO;
+ if (of_address_to_resource(np, 0, &regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ rc = -ENOMEM;
+ dev->base = (struct rgmii_regs *)ioremap(regs.start,
+ sizeof(struct rgmii_regs));
+ if (dev->base == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ /* Check for RGMII type */
+ if (device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+ dev->type = RGMII_AXON;
+ else
+ dev->type = RGMII_STANDARD;
+
+ DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n",
+ in_be32(&dev->base->fer), in_be32(&dev->base->ssr));
+
+ /* Disable all inputs by default */
+ out_be32(&dev->base->fer, 0);
+
+ printk(KERN_INFO
+ "RGMII %s %s initialized\n",
+ dev->type == RGMII_STANDARD ? "standard" : "axon",
+ ofdev->node->full_name);
+
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int __devexit rgmii_remove(struct of_device *ofdev)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id rgmii_match[] =
+{
+ {
+ .type = "rgmii-interface",
+ .compatible = "ibm,rgmii",
+ },
+ {
+ .type = "emac-rgmii",
+ },
+ {},
+};
+
+static struct of_platform_driver rgmii_driver = {
+ .name = "emac-rgmii",
+ .match_table = rgmii_match,
+
+ .probe = rgmii_probe,
+ .remove = rgmii_remove,
+};
+
+int __init rgmii_init(void)
+{
+ return of_register_platform_driver(&rgmii_driver);
+}
+
+void rgmii_exit(void)
+{
+ of_unregister_platform_driver(&rgmii_driver);
+}
diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ibm_newemac/rgmii.h
new file mode 100644
index 000000000000..57806833121e
--- /dev/null
+++ b/drivers/net/ibm_newemac/rgmii.h
@@ -0,0 +1,76 @@
+/*
+ * drivers/net/ibm_newemac/rgmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+ * Based on ocp_zmii.h/ibm_emac_zmii.h
+ * Armin Kuster akuster@mvista.com
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __IBM_NEWEMAC_RGMII_H
+#define __IBM_NEWEMAC_RGMII_H
+
+/* RGMII bridge type */
+#define RGMII_STANDARD 0
+#define RGMII_AXON 1
+
+/* RGMII bridge */
+struct rgmii_regs {
+ u32 fer; /* Function enable register */
+ u32 ssr; /* Speed select register */
+};
+
+/* RGMII device */
+struct rgmii_instance {
+ struct rgmii_regs __iomem *base;
+
+ /* Type of RGMII bridge */
+ int type;
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* number of EMACs using this RGMII bridge */
+ int users;
+
+ /* OF device instance */
+ struct of_device *ofdev;
+};
+
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+
+extern int rgmii_init(void);
+extern void rgmii_exit(void);
+extern int rgmii_attach(struct of_device *ofdev, int input, int mode);
+extern void rgmii_detach(struct of_device *ofdev, int input);
+extern void rgmii_get_mdio(struct of_device *ofdev, int input);
+extern void rgmii_put_mdio(struct of_device *ofdev, int input);
+extern void rgmii_set_speed(struct of_device *ofdev, int input, int speed);
+extern int rgmii_get_regs_len(struct of_device *ofdev);
+extern void *rgmii_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+
+# define rgmii_init() 0
+# define rgmii_exit() do { } while(0)
+# define rgmii_attach(x,y,z) (-ENXIO)
+# define rgmii_detach(x,y) do { } while(0)
+# define rgmii_get_mdio(o,i) do { } while (0)
+# define rgmii_put_mdio(o,i) do { } while (0)
+# define rgmii_set_speed(x,y,z) do { } while(0)
+# define rgmii_get_regs_len(x) 0
+# define rgmii_dump_regs(x,buf) (buf)
+#endif /* !CONFIG_IBM_NEW_EMAC_RGMII */
+
+#endif /* __IBM_NEWEMAC_RGMII_H */
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
new file mode 100644
index 000000000000..e05c7e81efb6
--- /dev/null
+++ b/drivers/net/ibm_newemac/tah.c
@@ -0,0 +1,173 @@
+/*
+ * drivers/net/ibm_newemac/tah.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <asm/io.h>
+
+#include "emac.h"
+#include "core.h"
+
+int __devinit tah_attach(struct of_device *ofdev, int channel)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ mutex_lock(&dev->lock);
+ /* Reset has been done at probe() time... nothing else to do for now */
+ ++dev->users;
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void __devexit tah_detach(struct of_device *ofdev, int channel)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ mutex_lock(&dev->lock);
+ --dev->users;
+ mutex_unlock(&dev->lock);
+}
+
+void tah_reset(struct of_device *ofdev)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_regs *p = dev->base;
+ int n;
+
+ /* Reset TAH */
+ out_be32(&p->mr, TAH_MR_SR);
+ n = 100;
+ while ((in_be32(&p->mr) & TAH_MR_SR) && n)
+ --n;
+
+ if (unlikely(!n))
+ printk(KERN_ERR "%s: reset timeout\n", ofdev->node->full_name);
+
+ /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
+ out_be32(&p->mr,
+ TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |
+ TAH_MR_DIG);
+}
+
+int tah_get_regs_len(struct of_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct tah_regs);
+}
+
+void *tah_dump_regs(struct of_device *ofdev, void *buf)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * zmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->base, sizeof(struct tah_regs));
+ return regs + 1;
+}
+
+static int __devinit tah_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct tah_instance *dev;
+ struct resource regs;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: could not allocate TAH device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+
+ mutex_init(&dev->lock);
+ dev->ofdev = ofdev;
+
+ rc = -ENXIO;
+ if (of_address_to_resource(np, 0, &regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ rc = -ENOMEM;
+ dev->base = (struct tah_regs *)ioremap(regs.start,
+ sizeof(struct tah_regs));
+ if (dev->base == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
+ tah_reset(ofdev);
+
+ printk(KERN_INFO
+ "TAH %s initialized\n", ofdev->node->full_name);
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int __devexit tah_remove(struct of_device *ofdev)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id tah_match[] =
+{
+ {
+ .type = "tah",
+ },
+ {},
+};
+
+static struct of_platform_driver tah_driver = {
+ .name = "emac-tah",
+ .match_table = tah_match,
+
+ .probe = tah_probe,
+ .remove = tah_remove,
+};
+
+int __init tah_init(void)
+{
+ return of_register_platform_driver(&tah_driver);
+}
+
+void tah_exit(void)
+{
+ of_unregister_platform_driver(&tah_driver);
+}
diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ibm_newemac/tah.h
new file mode 100644
index 000000000000..bc41853b6e26
--- /dev/null
+++ b/drivers/net/ibm_newemac/tah.h
@@ -0,0 +1,90 @@
+/*
+ * drivers/net/ibm_newemac/tah.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __IBM_NEWEMAC_TAH_H
+#define __IBM_NEWEMAC_TAH_H
+
+/* TAH */
+struct tah_regs {
+ u32 revid;
+ u32 pad[3];
+ u32 mr;
+ u32 ssr0;
+ u32 ssr1;
+ u32 ssr2;
+ u32 ssr3;
+ u32 ssr4;
+ u32 ssr5;
+ u32 tsr;
+};
+
+
+/* TAH device */
+struct tah_instance {
+ struct tah_regs __iomem *base;
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* number of EMACs using this TAH */
+ int users;
+
+ /* OF device instance */
+ struct of_device *ofdev;
+};
+
+
+/* TAH engine */
+#define TAH_MR_CVR 0x80000000
+#define TAH_MR_SR 0x40000000
+#define TAH_MR_ST_256 0x01000000
+#define TAH_MR_ST_512 0x02000000
+#define TAH_MR_ST_768 0x03000000
+#define TAH_MR_ST_1024 0x04000000
+#define TAH_MR_ST_1280 0x05000000
+#define TAH_MR_ST_1536 0x06000000
+#define TAH_MR_TFS_16KB 0x00000000
+#define TAH_MR_TFS_2KB 0x00200000
+#define TAH_MR_TFS_4KB 0x00400000
+#define TAH_MR_TFS_6KB 0x00600000
+#define TAH_MR_TFS_8KB 0x00800000
+#define TAH_MR_TFS_10KB 0x00a00000
+#define TAH_MR_DTFP 0x00100000
+#define TAH_MR_DIG 0x00080000
+
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+
+extern int tah_init(void);
+extern void tah_exit(void);
+extern int tah_attach(struct of_device *ofdev, int channel);
+extern void tah_detach(struct of_device *ofdev, int channel);
+extern void tah_reset(struct of_device *ofdev);
+extern int tah_get_regs_len(struct of_device *ofdev);
+extern void *tah_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+
+# define tah_init() 0
+# define tah_exit() do { } while(0)
+# define tah_attach(x,y) (-ENXIO)
+# define tah_detach(x,y) do { } while(0)
+# define tah_reset(x) do { } while(0)
+# define tah_get_regs_len(x) 0
+# define tah_dump_regs(x,buf) (buf)
+
+#endif /* !CONFIG_IBM_NEW_EMAC_TAH */
+
+#endif /* __IBM_NEWEMAC_TAH_H */
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
new file mode 100644
index 000000000000..d06312901848
--- /dev/null
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -0,0 +1,322 @@
+/*
+ * drivers/net/ibm_newemac/zmii.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+
+#include "emac.h"
+#include "core.h"
+
+/* ZMIIx_FER */
+#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4))
+#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \
+ ZMII_FER_MDI(2) | ZMII_FER_MDI(3))
+
+#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4))
+#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4))
+#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4))
+
+/* ZMIIx_SSR */
+#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4))
+#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4))
+#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4))
+
+/* ZMII only supports MII, RMII and SMII
+ * we also support autodetection for backward compatibility
+ */
+static inline int zmii_valid_mode(int mode)
+{
+ return mode == PHY_MODE_MII ||
+ mode == PHY_MODE_RMII ||
+ mode == PHY_MODE_SMII ||
+ mode == PHY_MODE_NA;
+}
+
+static inline const char *zmii_mode_name(int mode)
+{
+ switch (mode) {
+ case PHY_MODE_MII:
+ return "MII";
+ case PHY_MODE_RMII:
+ return "RMII";
+ case PHY_MODE_SMII:
+ return "SMII";
+ default:
+ BUG();
+ }
+}
+
+static inline u32 zmii_mode_mask(int mode, int input)
+{
+ switch (mode) {
+ case PHY_MODE_MII:
+ return ZMII_FER_MII(input);
+ case PHY_MODE_RMII:
+ return ZMII_FER_RMII(input);
+ case PHY_MODE_SMII:
+ return ZMII_FER_SMII(input);
+ default:
+ return 0;
+ }
+}
+
+int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_regs *p = dev->base;
+
+ ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
+
+ if (!zmii_valid_mode(*mode))
+ /* Probably an EMAC connected to RGMII,
+ * but it still may need ZMII for MDIO so
+ * we don't fail here.
+ */
+ return 0;
+
+ mutex_lock(&dev->lock);
+
+ /* Autodetect ZMII mode if not specified.
+ * This is only for backward compatibility with the old driver.
+ * Please, always specify PHY mode in your board port to avoid
+ * any surprises.
+ */
+ if (dev->mode == PHY_MODE_NA) {
+ if (*mode == PHY_MODE_NA) {
+ u32 r = dev->fer_save;
+
+ ZMII_DBG(dev, "autodetecting mode, FER = 0x%08x" NL, r);
+
+ if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1)))
+ dev->mode = PHY_MODE_MII;
+ else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1)))
+ dev->mode = PHY_MODE_RMII;
+ else
+ dev->mode = PHY_MODE_SMII;
+ } else
+ dev->mode = *mode;
+
+ printk(KERN_NOTICE "%s: bridge in %s mode\n",
+ ofdev->node->full_name, zmii_mode_name(dev->mode));
+ } else {
+ /* All inputs must use the same mode */
+ if (*mode != PHY_MODE_NA && *mode != dev->mode) {
+ printk(KERN_ERR
+ "%s: invalid mode %d specified for input %d\n",
+ ofdev->node->full_name, *mode, input);
+ mutex_unlock(&dev->lock);
+ return -EINVAL;
+ }
+ }
+
+ /* Report back correct PHY mode,
+ * it may be used during PHY initialization.
+ */
+ *mode = dev->mode;
+
+ /* Enable this input */
+ out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input));
+ ++dev->users;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void zmii_get_mdio(struct of_device *ofdev, int input)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ u32 fer;
+
+ ZMII_DBG2(dev, "get_mdio(%d)" NL, input);
+
+ mutex_lock(&dev->lock);
+
+ fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL;
+ out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));
+}
+
+void zmii_put_mdio(struct of_device *ofdev, int input)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ ZMII_DBG2(dev, "put_mdio(%d)" NL, input);
+ mutex_unlock(&dev->lock);
+}
+
+
+void zmii_set_speed(struct of_device *ofdev, int input, int speed)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ u32 ssr;
+
+ mutex_lock(&dev->lock);
+
+ ssr = in_be32(&dev->base->ssr);
+
+ ZMII_DBG(dev, "speed(%d, %d)" NL, input, speed);
+
+ if (speed == SPEED_100)
+ ssr |= ZMII_SSR_SP(input);
+ else
+ ssr &= ~ZMII_SSR_SP(input);
+
+ out_be32(&dev->base->ssr, ssr);
+
+ mutex_unlock(&dev->lock);
+}
+
+void __devexit zmii_detach(struct of_device *ofdev, int input)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ BUG_ON(!dev || dev->users == 0);
+
+ mutex_lock(&dev->lock);
+
+ ZMII_DBG(dev, "detach(%d)" NL, input);
+
+ /* Disable this input */
+ out_be32(&dev->base->fer,
+ in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input));
+
+ --dev->users;
+
+ mutex_unlock(&dev->lock);
+}
+
+int zmii_get_regs_len(struct of_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct zmii_regs);
+}
+
+void *zmii_dump_regs(struct of_device *ofdev, void *buf)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * zmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs));
+ return regs + 1;
+}
+
+static int __devinit zmii_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct zmii_instance *dev;
+ struct resource regs;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: could not allocate ZMII device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+
+ mutex_init(&dev->lock);
+ dev->ofdev = ofdev;
+ dev->mode = PHY_MODE_NA;
+
+ rc = -ENXIO;
+ if (of_address_to_resource(np, 0, &regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ rc = -ENOMEM;
+ dev->base = (struct zmii_regs *)ioremap(regs.start,
+ sizeof(struct zmii_regs));
+ if (dev->base == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ /* We may need FER value for autodetection later */
+ dev->fer_save = in_be32(&dev->base->fer);
+
+ /* Disable all inputs by default */
+ out_be32(&dev->base->fer, 0);
+
+ printk(KERN_INFO
+ "ZMII %s initialized\n", ofdev->node->full_name);
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int __devexit zmii_remove(struct of_device *ofdev)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id zmii_match[] =
+{
+ {
+ .compatible = "ibm,zmii",
+ },
+ /* For backward compat with old DT */
+ {
+ .type = "emac-zmii",
+ },
+ {},
+};
+
+static struct of_platform_driver zmii_driver = {
+ .name = "emac-zmii",
+ .match_table = zmii_match,
+
+ .probe = zmii_probe,
+ .remove = zmii_remove,
+};
+
+int __init zmii_init(void)
+{
+ return of_register_platform_driver(&zmii_driver);
+}
+
+void zmii_exit(void)
+{
+ of_unregister_platform_driver(&zmii_driver);
+}
diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ibm_newemac/zmii.h
new file mode 100644
index 000000000000..82a9968b1f74
--- /dev/null
+++ b/drivers/net/ibm_newemac/zmii.h
@@ -0,0 +1,73 @@
+/*
+ * drivers/net/ibm_newemac/zmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_ZMII_H
+#define __IBM_NEWEMAC_ZMII_H
+
+/* ZMII bridge registers */
+struct zmii_regs {
+ u32 fer; /* Function enable reg */
+ u32 ssr; /* Speed select reg */
+ u32 smiirs; /* SMII status reg */
+};
+
+/* ZMII device */
+struct zmii_instance {
+ struct zmii_regs __iomem *base;
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* subset of PHY_MODE_XXXX */
+ int mode;
+
+ /* number of EMACs using this ZMII bridge */
+ int users;
+
+ /* FER value left by firmware */
+ u32 fer_save;
+
+ /* OF device instance */
+ struct of_device *ofdev;
+};
+
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+
+extern int zmii_init(void);
+extern void zmii_exit(void);
+extern int zmii_attach(struct of_device *ofdev, int input, int *mode);
+extern void zmii_detach(struct of_device *ofdev, int input);
+extern void zmii_get_mdio(struct of_device *ofdev, int input);
+extern void zmii_put_mdio(struct of_device *ofdev, int input);
+extern void zmii_set_speed(struct of_device *ofdev, int input, int speed);
+extern int zmii_get_regs_len(struct of_device *ocpdev);
+extern void *zmii_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+# define zmii_init() 0
+# define zmii_exit() do { } while(0)
+# define zmii_attach(x,y,z) (-ENXIO)
+# define zmii_detach(x,y) do { } while(0)
+# define zmii_get_mdio(x,y) do { } while(0)
+# define zmii_put_mdio(x,y) do { } while(0)
+# define zmii_set_speed(x,y,z) do { } while(0)
+# define zmii_get_regs_len(x) 0
+# define zmii_dump_regs(x,buf) (buf)
+#endif /* !CONFIG_IBM_NEW_EMAC_ZMII */
+
+#endif /* __IBM_NEWEMAC_ZMII_H */
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index fe85d6fcba33..91d83aca6bc7 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -591,7 +591,7 @@ static void irqrx_handler(struct net_device *dev)
skb = dev_alloc_skb(rda.length + 2);
if (skb == NULL)
- priv->stat.rx_dropped++;
+ dev->stats.rx_dropped++;
else {
/* copy out data */
@@ -606,8 +606,8 @@ static void irqrx_handler(struct net_device *dev)
/* bookkeeping */
dev->last_rx = jiffies;
- priv->stat.rx_packets++;
- priv->stat.rx_bytes += rda.length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += rda.length;
/* pass to the upper layers */
netif_rx(skb);
@@ -617,11 +617,11 @@ static void irqrx_handler(struct net_device *dev)
/* otherwise check error status bits and increase statistics */
else {
- priv->stat.rx_errors++;
+ dev->stats.rx_errors++;
if (rda.status & RCREG_FAER)
- priv->stat.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rda.status & RCREG_CRCR)
- priv->stat.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
/* descriptor processed, will become new last descriptor in queue */
@@ -656,8 +656,8 @@ static void irqtx_handler(struct net_device *dev)
memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
/* update statistics */
- priv->stat.tx_packets++;
- priv->stat.tx_bytes += tda.length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += tda.length;
/* update our pointers */
priv->txused[priv->currtxdescr] = 0;
@@ -680,15 +680,15 @@ static void irqtxerr_handler(struct net_device *dev)
memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
/* update statistics */
- priv->stat.tx_errors++;
+ dev->stats.tx_errors++;
if (tda.status & (TCREG_NCRS | TCREG_CRSL))
- priv->stat.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tda.status & TCREG_EXC)
- priv->stat.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tda.status & TCREG_OWC)
- priv->stat.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tda.status & TCREG_FU)
- priv->stat.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
/* update our pointers */
priv->txused[priv->currtxdescr] = 0;
@@ -824,7 +824,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
if (priv->txusedcnt >= TXBUFCNT) {
retval = -EIO;
- priv->stat.tx_dropped++;
+ dev->stats.tx_dropped++;
goto tx_done;
}
@@ -876,14 +876,6 @@ tx_done:
return retval;
}
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *ibmlana_stats(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- return &priv->stat;
-}
-
/* switch receiver mode. */
static void ibmlana_set_multicast_list(struct net_device *dev)
@@ -906,8 +898,7 @@ static int ibmlana_probe(struct net_device *dev)
int base = 0, irq = 0, iobase = 0, memlen = 0;
ibmlana_priv *priv;
ibmlana_medium medium;
-
- SET_MODULE_OWNER(dev);
+ DECLARE_MAC_BUF(mac);
/* can't work without an MCA bus ;-) */
if (MCA_bus == 0)
@@ -980,7 +971,6 @@ static int ibmlana_probe(struct net_device *dev)
dev->stop = ibmlana_close;
dev->hard_start_xmit = ibmlana_tx;
dev->do_ioctl = NULL;
- dev->get_stats = ibmlana_stats;
dev->set_multicast_list = ibmlana_set_multicast_list;
dev->flags |= IFF_MULTICAST;
@@ -992,11 +982,10 @@ static int ibmlana_probe(struct net_device *dev)
/* print config */
printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+ "MAC address %s.\n",
dev->name, priv->realirq, dev->base_addr,
dev->mem_start, dev->mem_end - 1,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ print_mac(mac, dev->dev_addr));
printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
/* reset board */
diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h
index 6b58bab9e308..aa3ddbdee4bb 100644
--- a/drivers/net/ibmlana.h
+++ b/drivers/net/ibmlana.h
@@ -26,7 +26,6 @@ typedef enum {
typedef struct {
unsigned int slot; /* MCA-Slot-# */
- struct net_device_stats stat; /* packet statistics */
int realirq; /* memorizes actual IRQ, even when
currently not allocated */
ibmlana_medium medium; /* physical cannector */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index d96eb7229548..7d7758f3ad8c 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -28,7 +28,6 @@
/**************************************************************************/
/*
TODO:
- - remove frag processing code - no longer needed
- add support for sysfs
- possibly remove procfs support
*/
@@ -47,6 +46,9 @@
#include <linux/mm.h>
#include <linux/ethtool.h>
#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/net_namespace.h>
#include <asm/semaphore.h>
#include <asm/hvcall.h>
#include <asm/atomic.h>
@@ -83,9 +85,8 @@
static int ibmveth_open(struct net_device *dev);
static int ibmveth_close(struct net_device *dev);
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int ibmveth_poll(struct net_device *dev, int *budget);
+static int ibmveth_poll(struct napi_struct *napi, int budget);
static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ibmveth_get_stats(struct net_device *dev);
static void ibmveth_set_multicast_list(struct net_device *dev);
static int ibmveth_change_mtu(struct net_device *dev, int new_mtu);
static void ibmveth_proc_register_driver(void);
@@ -97,7 +98,7 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
static struct kobj_type ktype_veth_pool;
#ifdef CONFIG_PROC_FS
-#define IBMVETH_PROC_DIR "net/ibmveth"
+#define IBMVETH_PROC_DIR "ibmveth"
static struct proc_dir_entry *ibmveth_proc_dir;
#endif
@@ -110,20 +111,49 @@ MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(ibmveth_driver_version);
+struct ibmveth_stat {
+ char name[ETH_GSTRING_LEN];
+ int offset;
+};
+
+#define IBMVETH_STAT_OFF(stat) offsetof(struct ibmveth_adapter, stat)
+#define IBMVETH_GET_STAT(a, off) *((u64 *)(((unsigned long)(a)) + off))
+
+struct ibmveth_stat ibmveth_stats[] = {
+ { "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) },
+ { "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) },
+ { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) },
+ { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) },
+ { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) },
+ { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
+ { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
+ { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
+};
+
/* simple methods of getting data from the current rxq entry */
+static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter)
+{
+ return adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off;
+}
+
+static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter)
+{
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT;
+}
+
static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].toggle == adapter->rx_queue.toggle);
+ return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle);
}
static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].valid);
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID);
}
static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].offset);
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK);
}
static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
@@ -131,6 +161,11 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
}
+static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
+{
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD);
+}
+
/* setup the initial settings for a buffer pool */
static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
{
@@ -228,9 +263,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
correlator = ((u64)pool->index << 32) | index;
*(u64*)skb->data = correlator;
- desc.desc = 0;
- desc.fields.valid = 1;
- desc.fields.length = pool->buff_size;
+ desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size;
desc.fields.address = dma_addr;
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
@@ -371,9 +404,8 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
return;
}
- desc.desc = 0;
- desc.fields.valid = 1;
- desc.fields.length = adapter->rx_buff_pool[pool].buff_size;
+ desc.fields.flags_len = IBMVETH_BUF_VALID |
+ adapter->rx_buff_pool[pool].buff_size;
desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index];
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
@@ -480,6 +512,8 @@ static int ibmveth_open(struct net_device *netdev)
ibmveth_debug_printk("open starting\n");
+ napi_enable(&adapter->napi);
+
for(i = 0; i<IbmVethNumBufferPools; i++)
rxq_entries += adapter->rx_buff_pool[i].size;
@@ -489,6 +523,7 @@ static int ibmveth_open(struct net_device *netdev)
if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM;
}
@@ -498,6 +533,7 @@ static int ibmveth_open(struct net_device *netdev)
if(!adapter->rx_queue.queue_addr) {
ibmveth_error_printk("unable to allocate rx queue pages\n");
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM;
}
@@ -514,6 +550,7 @@ static int ibmveth_open(struct net_device *netdev)
(dma_mapping_error(adapter->rx_queue.queue_dma))) {
ibmveth_error_printk("unable to map filter or buffer list pages\n");
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM;
}
@@ -524,9 +561,7 @@ static int ibmveth_open(struct net_device *netdev)
memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
mac_address = mac_address >> 16;
- rxq_desc.desc = 0;
- rxq_desc.fields.valid = 1;
- rxq_desc.fields.length = adapter->rx_queue.queue_len;
+ rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len;
rxq_desc.fields.address = adapter->rx_queue.queue_dma;
ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr);
@@ -545,6 +580,7 @@ static int ibmveth_open(struct net_device *netdev)
rxq_desc.desc,
mac_address);
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENONET;
}
@@ -555,6 +591,7 @@ static int ibmveth_open(struct net_device *netdev)
ibmveth_error_printk("unable to alloc pool\n");
adapter->rx_buff_pool[i].active = 0;
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM ;
}
}
@@ -567,6 +604,7 @@ static int ibmveth_open(struct net_device *netdev)
} while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return rc;
}
@@ -587,6 +625,8 @@ static int ibmveth_close(struct net_device *netdev)
ibmveth_debug_printk("close starting\n");
+ napi_disable(&adapter->napi);
+
if (!adapter->pool_config)
netif_stop_queue(netdev);
@@ -634,12 +674,164 @@ static u32 netdev_get_link(struct net_device *dev) {
return 1;
}
+static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data)
+ adapter->rx_csum = 1;
+ else {
+ /*
+ * Since the ibmveth firmware interface does not have the concept of
+ * separate tx/rx checksum offload enable, if rx checksum is disabled
+ * we also have to disable tx checksum offload. Once we disable rx
+ * checksum offload, we are no longer allowed to send tx buffers that
+ * are not properly checksummed.
+ */
+ adapter->rx_csum = 0;
+ dev->features &= ~NETIF_F_IP_CSUM;
+ }
+}
+
+static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data) {
+ dev->features |= NETIF_F_IP_CSUM;
+ adapter->rx_csum = 1;
+ } else
+ dev->features &= ~NETIF_F_IP_CSUM;
+}
+
+static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
+ void (*done) (struct net_device *, u32))
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ u64 set_attr, clr_attr, ret_attr;
+ long ret;
+ int rc1 = 0, rc2 = 0;
+ int restart = 0;
+
+ if (netif_running(dev)) {
+ restart = 1;
+ adapter->pool_config = 1;
+ ibmveth_close(dev);
+ adapter->pool_config = 0;
+ }
+
+ set_attr = 0;
+ clr_attr = 0;
+
+ if (data)
+ set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+ else
+ clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+
+ ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr);
+
+ if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
+ !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
+ (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
+ ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
+ set_attr, &ret_attr);
+
+ if (ret != H_SUCCESS) {
+ rc1 = -EIO;
+ ibmveth_error_printk("unable to change checksum offload settings."
+ " %d rc=%ld\n", data, ret);
+
+ ret = h_illan_attributes(adapter->vdev->unit_address,
+ set_attr, clr_attr, &ret_attr);
+ } else
+ done(dev, data);
+ } else {
+ rc1 = -EIO;
+ ibmveth_error_printk("unable to change checksum offload settings."
+ " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr);
+ }
+
+ if (restart)
+ rc2 = ibmveth_open(dev);
+
+ return rc1 ? rc1 : rc2;
+}
+
+static int ibmveth_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum))
+ return 0;
+
+ return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags);
+}
+
+static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ int rc = 0;
+
+ if (data && (dev->features & NETIF_F_IP_CSUM))
+ return 0;
+ if (!data && !(dev->features & NETIF_F_IP_CSUM))
+ return 0;
+
+ if (data && !adapter->rx_csum)
+ rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags);
+ else
+ ibmveth_set_tx_csum_flags(dev, data);
+
+ return rc;
+}
+
+static u32 ibmveth_get_rx_csum(struct net_device *dev)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ return adapter->rx_csum;
+}
+
+static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++, data += ETH_GSTRING_LEN)
+ memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN);
+}
+
+static int ibmveth_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ibmveth_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void ibmveth_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++)
+ data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset);
+}
+
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.get_link = netdev_get_link,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ibmveth_set_tx_csum,
+ .get_rx_csum = ibmveth_get_rx_csum,
+ .set_rx_csum = ibmveth_set_rx_csum,
+ .get_strings = ibmveth_get_strings,
+ .get_sset_count = ibmveth_get_sset_count,
+ .get_ethtool_stats = ibmveth_get_ethtool_stats,
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -652,9 +844,8 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev->priv;
- union ibmveth_buf_desc desc[IbmVethMaxSendFrags];
+ union ibmveth_buf_desc desc;
unsigned long lpar_rc;
- int nfrags = 0, curfrag;
unsigned long correlator;
unsigned long flags;
unsigned int retry_count;
@@ -664,83 +855,48 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
unsigned int tx_send_failed = 0;
unsigned int tx_map_failed = 0;
+ desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len;
+ desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
- if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL &&
+ ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
+ ibmveth_error_printk("tx: failed to checksum packet\n");
tx_dropped++;
goto out;
}
- memset(&desc, 0, sizeof(desc));
-
- /* nfrags = number of frags after the initial fragment */
- nfrags = skb_shinfo(skb)->nr_frags;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
- if(nfrags)
- adapter->tx_multidesc_send++;
+ desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
- /* map the initial fragment */
- desc[0].fields.length = nfrags ? skb->len - skb->data_len : skb->len;
- desc[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
- desc[0].fields.length, DMA_TO_DEVICE);
- desc[0].fields.valid = 1;
+ /* Need to zero out the checksum */
+ buf[0] = 0;
+ buf[1] = 0;
+ }
- if(dma_mapping_error(desc[0].fields.address)) {
- ibmveth_error_printk("tx: unable to map initial fragment\n");
+ if (dma_mapping_error(desc.fields.address)) {
+ ibmveth_error_printk("tx: unable to map xmit buffer\n");
tx_map_failed++;
tx_dropped++;
goto out;
}
- curfrag = nfrags;
-
- /* map fragments past the initial portion if there are any */
- while(curfrag--) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[curfrag];
- desc[curfrag+1].fields.address
- = dma_map_single(&adapter->vdev->dev,
- page_address(frag->page) + frag->page_offset,
- frag->size, DMA_TO_DEVICE);
- desc[curfrag+1].fields.length = frag->size;
- desc[curfrag+1].fields.valid = 1;
-
- if(dma_mapping_error(desc[curfrag+1].fields.address)) {
- ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
- tx_map_failed++;
- tx_dropped++;
- /* Free all the mappings we just created */
- while(curfrag < nfrags) {
- dma_unmap_single(&adapter->vdev->dev,
- desc[curfrag+1].fields.address,
- desc[curfrag+1].fields.length,
- DMA_TO_DEVICE);
- curfrag++;
- }
- goto out;
- }
- }
-
/* send the frame. Arbitrarily set retrycount to 1024 */
correlator = 0;
retry_count = 1024;
do {
lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
- desc[0].desc,
- desc[1].desc,
- desc[2].desc,
- desc[3].desc,
- desc[4].desc,
- desc[5].desc,
- correlator,
- &correlator);
+ desc.desc, 0, 0, 0, 0, 0,
+ correlator, &correlator);
} while ((lpar_rc == H_BUSY) && (retry_count--));
if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
- int i;
ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
- for(i = 0; i < 6; i++) {
- ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i,
- desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address);
- }
+ ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n",
+ (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0,
+ skb->len, desc.fields.address);
tx_send_failed++;
tx_dropped++;
} else {
@@ -749,16 +905,13 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
}
- do {
- dma_unmap_single(&adapter->vdev->dev,
- desc[nfrags].fields.address,
- desc[nfrags].fields.length, DMA_TO_DEVICE);
- } while(--nfrags >= 0);
+ dma_unmap_single(&adapter->vdev->dev, desc.fields.address,
+ skb->len, DMA_TO_DEVICE);
out: spin_lock_irqsave(&adapter->stats_lock, flags);
- adapter->stats.tx_dropped += tx_dropped;
- adapter->stats.tx_bytes += tx_bytes;
- adapter->stats.tx_packets += tx_packets;
+ netdev->stats.tx_dropped += tx_dropped;
+ netdev->stats.tx_bytes += tx_bytes;
+ netdev->stats.tx_packets += tx_packets;
adapter->tx_send_failed += tx_send_failed;
adapter->tx_map_failed += tx_map_failed;
spin_unlock_irqrestore(&adapter->stats_lock, flags);
@@ -767,80 +920,72 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags);
return 0;
}
-static int ibmveth_poll(struct net_device *netdev, int *budget)
+static int ibmveth_poll(struct napi_struct *napi, int budget)
{
- struct ibmveth_adapter *adapter = netdev->priv;
- int max_frames_to_process = netdev->quota;
+ struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
int frames_processed = 0;
- int more_work = 1;
unsigned long lpar_rc;
restart_poll:
do {
- struct net_device *netdev = adapter->netdev;
+ struct sk_buff *skb;
- if(ibmveth_rxq_pending_buffer(adapter)) {
- struct sk_buff *skb;
+ if (!ibmveth_rxq_pending_buffer(adapter))
+ break;
- rmb();
+ rmb();
+ if (!ibmveth_rxq_buffer_valid(adapter)) {
+ wmb(); /* suggested by larson1 */
+ adapter->rx_invalid_buffer++;
+ ibmveth_debug_printk("recycling invalid buffer\n");
+ ibmveth_rxq_recycle_buffer(adapter);
+ } else {
+ int length = ibmveth_rxq_frame_length(adapter);
+ int offset = ibmveth_rxq_frame_offset(adapter);
+ int csum_good = ibmveth_rxq_csum_good(adapter);
- if(!ibmveth_rxq_buffer_valid(adapter)) {
- wmb(); /* suggested by larson1 */
- adapter->rx_invalid_buffer++;
- ibmveth_debug_printk("recycling invalid buffer\n");
- ibmveth_rxq_recycle_buffer(adapter);
- } else {
- int length = ibmveth_rxq_frame_length(adapter);
- int offset = ibmveth_rxq_frame_offset(adapter);
- skb = ibmveth_rxq_get_buffer(adapter);
+ skb = ibmveth_rxq_get_buffer(adapter);
+ if (csum_good)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
- ibmveth_rxq_harvest_buffer(adapter);
+ ibmveth_rxq_harvest_buffer(adapter);
- skb_reserve(skb, offset);
- skb_put(skb, length);
- skb->protocol = eth_type_trans(skb, netdev);
+ skb_reserve(skb, offset);
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, netdev);
- netif_receive_skb(skb); /* send it up */
+ netif_receive_skb(skb); /* send it up */
- adapter->stats.rx_packets++;
- adapter->stats.rx_bytes += length;
- frames_processed++;
- netdev->last_rx = jiffies;
- }
- } else {
- more_work = 0;
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += length;
+ frames_processed++;
+ netdev->last_rx = jiffies;
}
- } while(more_work && (frames_processed < max_frames_to_process));
+ } while (frames_processed < budget);
ibmveth_replenish_task(adapter);
- if(more_work) {
- /* more work to do - return that we are not done yet */
- netdev->quota -= frames_processed;
- *budget -= frames_processed;
- return 1;
- }
-
- /* we think we are done - reenable interrupts, then check once more to make sure we are done */
- lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE);
+ if (frames_processed < budget) {
+ /* We think we are done - reenable interrupts,
+ * then check once more to make sure we are done.
+ */
+ lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+ VIO_IRQ_ENABLE);
- ibmveth_assert(lpar_rc == H_SUCCESS);
+ ibmveth_assert(lpar_rc == H_SUCCESS);
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
- if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed))
- {
- lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
- ibmveth_assert(lpar_rc == H_SUCCESS);
- more_work = 1;
- goto restart_poll;
+ if (ibmveth_rxq_pending_buffer(adapter) &&
+ netif_rx_reschedule(netdev, napi)) {
+ lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+ VIO_IRQ_DISABLE);
+ goto restart_poll;
+ }
}
- netdev->quota -= frames_processed;
- *budget -= frames_processed;
-
- /* we really are done */
- return 0;
+ return frames_processed;
}
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
@@ -849,20 +994,15 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
struct ibmveth_adapter *adapter = netdev->priv;
unsigned long lpar_rc;
- if(netif_rx_schedule_prep(netdev)) {
- lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+ VIO_IRQ_DISABLE);
ibmveth_assert(lpar_rc == H_SUCCESS);
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
}
return IRQ_HANDLED;
}
-static struct net_device_stats *ibmveth_get_stats(struct net_device *dev)
-{
- struct ibmveth_adapter *adapter = dev->priv;
- return &adapter->stats;
-}
-
static void ibmveth_set_multicast_list(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev->priv;
@@ -962,8 +1102,10 @@ static void ibmveth_poll_controller(struct net_device *dev)
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
int rc, i;
+ long ret;
struct net_device *netdev;
- struct ibmveth_adapter *adapter = NULL;
+ struct ibmveth_adapter *adapter;
+ u64 set_attr, ret_attr;
unsigned char *mac_addr_p;
unsigned int *mcastFilterSize_p;
@@ -994,10 +1136,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
if(!netdev)
return -ENOMEM;
- SET_MODULE_OWNER(netdev);
-
adapter = netdev->priv;
- memset(adapter, 0, sizeof(adapter));
dev->dev.driver_data = netdev;
adapter->vdev = dev;
@@ -1005,6 +1144,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
adapter->mcastFilterSize= *mcastFilterSize_p;
adapter->pool_config = 0;
+ netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
+
/* Some older boxes running PHYP non-natively have an OF that
returns a 8-byte local-mac-address field (and the first
2 bytes have to be ignored) while newer boxes' OF return
@@ -1021,11 +1162,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
netdev->irq = dev->irq;
netdev->open = ibmveth_open;
- netdev->poll = ibmveth_poll;
- netdev->weight = 16;
netdev->stop = ibmveth_close;
netdev->hard_start_xmit = ibmveth_start_xmit;
- netdev->get_stats = ibmveth_get_stats;
netdev->set_multicast_list = ibmveth_set_multicast_list;
netdev->do_ioctl = ibmveth_ioctl;
netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1045,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
pool_count[i], pool_size[i],
pool_active[i]);
kobj->parent = &dev->dev.kobj;
- sprintf(kobj->name, "pool%d", i);
+ kobject_set_name(kobj, "pool%d", i);
kobj->ktype = &ktype_veth_pool;
kobject_register(kobj);
}
@@ -1058,6 +1196,22 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
ibmveth_debug_printk("registering netdev...\n");
+ ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr);
+
+ if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
+ !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
+ (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
+ set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+
+ ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr);
+
+ if (ret == H_SUCCESS) {
+ adapter->rx_csum = 1;
+ netdev->features |= NETIF_F_IP_CSUM;
+ } else
+ ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr);
+ }
+
rc = register_netdev(netdev);
if(rc) {
@@ -1093,15 +1247,14 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
#ifdef CONFIG_PROC_FS
static void ibmveth_proc_register_driver(void)
{
- ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, NULL);
+ ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net);
if (ibmveth_proc_dir) {
- SET_MODULE_OWNER(ibmveth_proc_dir);
}
}
static void ibmveth_proc_unregister_driver(void)
{
- remove_proc_entry(IBMVETH_PROC_DIR, NULL);
+ remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net);
}
static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos)
@@ -1128,22 +1281,16 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v)
struct ibmveth_adapter *adapter = seq->private;
char *current_mac = ((char*) &adapter->netdev->dev_addr);
char *firmware_mac = ((char*) &adapter->mac_addr) ;
+ DECLARE_MAC_BUF(mac);
seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address);
- seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
- current_mac[0], current_mac[1], current_mac[2],
- current_mac[3], current_mac[4], current_mac[5]);
- seq_printf(seq, "Firmware MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
- firmware_mac[0], firmware_mac[1], firmware_mac[2],
- firmware_mac[3], firmware_mac[4], firmware_mac[5]);
+ seq_printf(seq, "Current MAC: %s\n", print_mac(mac, current_mac));
+ seq_printf(seq, "Firmware MAC: %s\n", print_mac(mac, firmware_mac));
seq_printf(seq, "\nAdapter Statistics:\n");
- seq_printf(seq, " TX: skbuffs linearized: %ld\n", adapter->tx_linearized);
- seq_printf(seq, " multi-descriptor sends: %ld\n", adapter->tx_multidesc_send);
- seq_printf(seq, " skb_linearize failures: %ld\n", adapter->tx_linearize_failed);
- seq_printf(seq, " vio_map_single failres: %ld\n", adapter->tx_map_failed);
+ seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed);
seq_printf(seq, " send failures: %ld\n", adapter->tx_send_failed);
seq_printf(seq, " RX: replenish task cycles: %ld\n", adapter->replenish_task_cycles);
seq_printf(seq, " alloc_skb_failures: %ld\n", adapter->replenish_no_mem);
@@ -1196,7 +1343,6 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
} else {
entry->data = (void *) adapter;
entry->proc_fops = &ibmveth_proc_fops;
- SET_MODULE_OWNER(entry);
}
}
return;
@@ -1280,24 +1426,28 @@ const char * buf, size_t count)
int i;
/* Make sure there is a buffer pool with buffers that
can hold a packet of the size of the MTU */
- for(i = 0; i<IbmVethNumBufferPools; i++) {
+ for (i = 0; i < IbmVethNumBufferPools; i++) {
if (pool == &adapter->rx_buff_pool[i])
continue;
if (!adapter->rx_buff_pool[i].active)
continue;
- if (mtu < adapter->rx_buff_pool[i].buff_size) {
- pool->active = 0;
- h_free_logical_lan_buffer(adapter->
- vdev->
- unit_address,
- pool->
- buff_size);
- }
+ if (mtu <= adapter->rx_buff_pool[i].buff_size)
+ break;
}
- if (pool->active) {
+
+ if (i == IbmVethNumBufferPools) {
ibmveth_error_printk("no active pool >= MTU\n");
return -EPERM;
}
+
+ pool->active = 0;
+ if (netif_running(netdev)) {
+ adapter->pool_config = 1;
+ ibmveth_close(netdev);
+ adapter->pool_config = 0;
+ if ((rc = ibmveth_open(netdev)))
+ return rc;
+ }
}
} else if (attr == &veth_num_attr) {
if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT)
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index bb69ccae8ace..41f61cd18852 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -25,8 +25,6 @@
#ifndef _IBMVETH_H
#define _IBMVETH_H
-#define IbmVethMaxSendFrags 6
-
/* constants for H_MULTICAST_CTRL */
#define IbmVethMcastReceptionModifyBit 0x80000UL
#define IbmVethMcastReceptionEnableBit 0x20000UL
@@ -41,6 +39,12 @@
#define IbmVethMcastRemoveFilter 0x2UL
#define IbmVethMcastClearFilterTable 0x3UL
+#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000ULL
+#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00ULL
+#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004ULL
+#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002ULL
+#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001ULL
+
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
@@ -67,15 +71,27 @@ static inline long h_send_logical_lan(unsigned long unit_address,
return rc;
}
+static inline long h_illan_attributes(unsigned long unit_address,
+ unsigned long reset_mask, unsigned long set_mask,
+ unsigned long *ret_attributes)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address,
+ reset_mask, set_mask);
+
+ *ret_attributes = retbuf[0];
+
+ return rc;
+}
+
#define h_multicast_ctrl(ua, cmd, mac) \
plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
#define h_change_logical_lan_mac(ua, mac) \
plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac)
-#define h_free_logical_lan_buffer(ua, bufsize) \
- plpar_hcall_norets(H_FREE_LOGICAL_LAN_BUFFER, ua, bufsize)
-
#define IbmVethNumBufferPools 5
#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */
#define IBMVETH_MAX_MTU 68
@@ -115,6 +131,7 @@ struct ibmveth_rx_q {
struct ibmveth_adapter {
struct vio_dev *vdev;
struct net_device *netdev;
+ struct napi_struct napi;
struct net_device_stats stats;
unsigned int mcastFilterSize;
unsigned long mac_addr;
@@ -125,6 +142,7 @@ struct ibmveth_adapter {
struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
struct ibmveth_rx_q rx_queue;
int pool_config;
+ int rx_csum;
/* adapter specific stats */
u64 replenish_task_cycles;
@@ -133,20 +151,19 @@ struct ibmveth_adapter {
u64 replenish_add_buff_success;
u64 rx_invalid_buffer;
u64 rx_no_buffer;
- u64 tx_multidesc_send;
- u64 tx_linearized;
- u64 tx_linearize_failed;
u64 tx_map_failed;
u64 tx_send_failed;
spinlock_t stats_lock;
};
struct ibmveth_buf_desc_fields {
- u32 valid : 1;
- u32 toggle : 1;
- u32 reserved : 6;
- u32 length : 24;
- u32 address;
+ u32 flags_len;
+#define IBMVETH_BUF_VALID 0x80000000
+#define IBMVETH_BUF_TOGGLE 0x40000000
+#define IBMVETH_BUF_NO_CSUM 0x02000000
+#define IBMVETH_BUF_CSUM_GOOD 0x01000000
+#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF
+ u32 address;
};
union ibmveth_buf_desc {
@@ -155,12 +172,16 @@ union ibmveth_buf_desc {
};
struct ibmveth_rx_q_entry {
- u16 toggle : 1;
- u16 valid : 1;
- u16 reserved : 14;
- u16 offset;
- u32 length;
- u64 correlator;
+ u32 flags_off;
+#define IBMVETH_RXQ_TOGGLE 0x80000000
+#define IBMVETH_RXQ_TOGGLE_SHIFT 31
+#define IBMVETH_RXQ_VALID 0x40000000
+#define IBMVETH_RXQ_NO_CSUM 0x02000000
+#define IBMVETH_RXQ_CSUM_GOOD 0x01000000
+#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF
+
+ u32 length;
+ u64 correlator;
};
#endif /* _IBMVETH_H */
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index f5c3598e59af..15949d3df17e 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -34,12 +34,12 @@
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <net/pkt_sched.h>
+#include <net/net_namespace.h>
#define TX_TIMEOUT (2*HZ)
#define TX_Q_LIMIT 32
struct ifb_private {
- struct net_device_stats stats;
struct tasklet_struct ifb_tasklet;
int tasklet_pending;
/* mostly debug stats leave in for now */
@@ -60,7 +60,6 @@ static int numifbs = 2;
static void ri_tasklet(unsigned long dev);
static int ifb_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ifb_get_stats(struct net_device *dev);
static int ifb_open(struct net_device *dev);
static int ifb_close(struct net_device *dev);
@@ -69,7 +68,7 @@ static void ri_tasklet(unsigned long dev)
struct net_device *_dev = (struct net_device *)dev;
struct ifb_private *dp = netdev_priv(_dev);
- struct net_device_stats *stats = &dp->stats;
+ struct net_device_stats *stats = &_dev->stats;
struct sk_buff *skb;
dp->st_task_enter++;
@@ -97,7 +96,7 @@ static void ri_tasklet(unsigned long dev)
stats->tx_packets++;
stats->tx_bytes +=skb->len;
- skb->dev = __dev_get_by_index(skb->iif);
+ skb->dev = __dev_get_by_index(&init_net, skb->iif);
if (!skb->dev) {
dev_kfree_skb(skb);
stats->tx_dropped++;
@@ -139,7 +138,6 @@ resched:
static void ifb_setup(struct net_device *dev)
{
/* Initialize the device structure. */
- dev->get_stats = ifb_get_stats;
dev->hard_start_xmit = ifb_xmit;
dev->open = &ifb_open;
dev->stop = &ifb_close;
@@ -151,14 +149,13 @@ static void ifb_setup(struct net_device *dev)
dev->change_mtu = NULL;
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
- SET_MODULE_OWNER(dev);
random_ether_addr(dev->dev_addr);
}
static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
- struct net_device_stats *stats = &dp->stats;
+ struct net_device_stats *stats = &dev->stats;
int ret = 0;
u32 from = G_TC_FROM(skb->tc_verd);
@@ -185,19 +182,6 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
return ret;
}
-static struct net_device_stats *ifb_get_stats(struct net_device *dev)
-{
- struct ifb_private *dp = netdev_priv(dev);
- struct net_device_stats *stats = &dp->stats;
-
- pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
- dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
- dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr,
- dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch);
-
- return stats;
-}
-
static int ifb_close(struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 3ca1e8ece548..373f72cdbe8e 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -5,7 +5,7 @@
*
* Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
*
- * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle
* Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
*
* References:
@@ -48,6 +48,7 @@
#ifdef CONFIG_SERIAL_8250
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
#endif
#include <linux/netdevice.h>
@@ -61,12 +62,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/sn/types.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/sn0/hubni.h>
-#include <asm/sn/sn0/hubio.h>
-#include <asm/sn/klconfig.h>
#include <asm/sn/ioc3.h>
-#include <asm/sn/sn0/ip27.h>
#include <asm/pci/bridge.h>
/*
@@ -94,6 +90,9 @@ struct ioc3_private {
u32 emcr, ehar_h, ehar_l;
spinlock_t ioc3_lock;
struct mii_if_info mii;
+ unsigned long flags;
+#define IOC3_FLAG_RX_CHECKSUMS 1
+
struct pci_dev *pdev;
/* Members used by autonegotiation */
@@ -444,18 +443,12 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
*/
static void ioc3_get_eaddr(struct ioc3_private *ip)
{
- int i;
-
+ DECLARE_MAC_BUF(mac);
ioc3_get_eaddr_nic(ip);
- printk("Ethernet address is ");
- for (i = 0; i < 6; i++) {
- printk("%02x", priv_netdev(ip)->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk(".\n");
+ printk("Ethernet address is %s.\n",
+ print_mac(mac, priv_netdev(ip)->dev_addr));
}
static void __ioc3_set_mac_address(struct net_device *dev)
@@ -520,8 +513,6 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
return &ip->stats;
}
-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
-
static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
{
struct ethhdr *eh = eth_hdr(skb);
@@ -589,7 +580,6 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
if (csum == 0xffff)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
-#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */
static inline void ioc3_rx(struct ioc3_private *ip)
{
@@ -624,9 +614,9 @@ static inline void ioc3_rx(struct ioc3_private *ip)
goto next;
}
-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
- ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len);
-#endif
+ if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS))
+ ioc3_tcpudp_checksum(skb,
+ w0 & ERXBUF_IPCKSUM_MASK, len);
netif_rx(skb);
@@ -1151,13 +1141,41 @@ static int ioc3_is_menet(struct pci_dev *pdev)
* Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
* around ioc3 oddities in this respect.
*
- * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
+ * The IOC3 serials use a 22MHz clock rate with an additional divider which
+ * can be programmed in the SCR register if the DLAB bit is set.
+ *
+ * Register to interrupt zero because we share the interrupt with
+ * the serial driver which we don't properly support yet.
+ *
+ * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been
+ * registered.
*/
+static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
+{
+#define COSMISC_CONSTANT 6
+
+ struct uart_port port = {
+ .irq = 0,
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
+
+ .membase = (unsigned char __iomem *) uart,
+ .mapbase = (unsigned long) uart,
+ };
+ unsigned char lcr;
+
+ lcr = uart->iu_lcr;
+ uart->iu_lcr = lcr | UART_LCR_DLAB;
+ uart->iu_scr = COSMISC_CONSTANT,
+ uart->iu_lcr = lcr;
+ uart->iu_lcr;
+ serial8250_register_port(&port);
+}
static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
{
- struct uart_port port;
-
/*
* We need to recognice and treat the fourth MENET serial as it
* does not have an SuperIO chip attached to it, therefore attempting
@@ -1171,24 +1189,35 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
return;
/*
- * Register to interrupt zero because we share the interrupt with
- * the serial driver which we don't properly support yet.
- *
- * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
- * been registered.
+ * Switch IOC3 to PIO mode. It probably already was but let's be
+ * paranoid
*/
- memset(&port, 0, sizeof(port));
- port.irq = 0;
- port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- port.iotype = UPIO_MEM;
- port.regshift = 0;
- port.uartclk = 22000000 / 3;
-
- port.membase = (unsigned char *) &ioc3->sregs.uarta;
- serial8250_register_port(&port);
-
- port.membase = (unsigned char *) &ioc3->sregs.uartb;
- serial8250_register_port(&port);
+ ioc3->gpcr_s = GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL;
+ ioc3->gpcr_s;
+ ioc3->gppr_6 = 0;
+ ioc3->gppr_6;
+ ioc3->gppr_7 = 0;
+ ioc3->gppr_7;
+ ioc3->sscr_a = ioc3->sscr_a & ~SSCR_DMA_EN;
+ ioc3->sscr_a;
+ ioc3->sscr_b = ioc3->sscr_b & ~SSCR_DMA_EN;
+ ioc3->sscr_b;
+ /* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */
+ ioc3->sio_iec &= ~ (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL |
+ SIO_IR_SA_RX_HIGH | SIO_IR_SA_RX_TIMER |
+ SIO_IR_SA_DELTA_DCD | SIO_IR_SA_DELTA_CTS |
+ SIO_IR_SA_TX_EXPLICIT | SIO_IR_SA_MEMERR);
+ ioc3->sio_iec |= SIO_IR_SA_INT;
+ ioc3->sscr_a = 0;
+ ioc3->sio_iec &= ~ (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL |
+ SIO_IR_SB_RX_HIGH | SIO_IR_SB_RX_TIMER |
+ SIO_IR_SB_DELTA_DCD | SIO_IR_SB_DELTA_CTS |
+ SIO_IR_SB_TX_EXPLICIT | SIO_IR_SB_MEMERR);
+ ioc3->sio_iec |= SIO_IR_SB_INT;
+ ioc3->sscr_b = 0;
+
+ ioc3_8250_register(&ioc3->sregs.uarta);
+ ioc3_8250_register(&ioc3->sregs.uartb);
}
#endif
@@ -1238,7 +1267,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto out_free;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
ip = netdev_priv(dev);
@@ -1298,9 +1326,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->set_multicast_list = ioc3_set_multicast_list;
dev->set_mac_address = ioc3_set_mac_address;
dev->ethtool_ops = &ioc3_ethtool_ops;
-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
dev->features = NETIF_F_IP_CSUM;
-#endif
sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
@@ -1390,7 +1416,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
uint32_t w0 = 0;
int produce;
-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
/*
* IOC3 has a fairly simple minded checksumming hardware which simply
* adds up the 1's complement checksum for the entire packet and
@@ -1438,7 +1463,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
}
-#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */
spin_lock_irq(&ip->ioc3_lock);
@@ -1593,12 +1617,37 @@ static u32 ioc3_get_link(struct net_device *dev)
return rc;
}
+static u32 ioc3_get_rx_csum(struct net_device *dev)
+{
+ struct ioc3_private *ip = netdev_priv(dev);
+
+ return ip->flags & IOC3_FLAG_RX_CHECKSUMS;
+}
+
+static int ioc3_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct ioc3_private *ip = netdev_priv(dev);
+
+ spin_lock_bh(&ip->ioc3_lock);
+ if (data)
+ ip->flags |= IOC3_FLAG_RX_CHECKSUMS;
+ else
+ ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS;
+ spin_unlock_bh(&ip->ioc3_lock);
+
+ return 0;
+}
+
static const struct ethtool_ops ioc3_ethtool_ops = {
.get_drvinfo = ioc3_get_drvinfo,
.get_settings = ioc3_get_settings,
.set_settings = ioc3_set_settings,
.nway_reset = ioc3_nway_reset,
.get_link = ioc3_get_link,
+ .get_rx_csum = ioc3_get_rx_csum,
+ .set_rx_csum = ioc3_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum
};
static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
new file mode 100644
index 000000000000..59898ce54dcf
--- /dev/null
+++ b/drivers/net/ipg.c
@@ -0,0 +1,2332 @@
+/*
+ * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
+ *
+ * Copyright (C) 2003, 2007 IC Plus Corp
+ *
+ * Original Author:
+ *
+ * Craig Rich
+ * Sundance Technology, Inc.
+ * www.sundanceti.com
+ * craig_rich@sundanceti.com
+ *
+ * Current Maintainer:
+ *
+ * Sorbica Shieh.
+ * http://www.icplus.com.tw
+ * sorbica@icplus.com.tw
+ *
+ * Jesse Huang
+ * http://www.icplus.com.tw
+ * jesse@icplus.com.tw
+ */
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/mutex.h>
+
+#include <asm/div64.h>
+
+#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
+#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
+#define IPG_RESET_MASK \
+ (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
+ IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
+ IPG_AC_AUTO_INIT)
+
+#define ipg_w32(val32,reg) iowrite32((val32), ioaddr + (reg))
+#define ipg_w16(val16,reg) iowrite16((val16), ioaddr + (reg))
+#define ipg_w8(val8,reg) iowrite8((val8), ioaddr + (reg))
+
+#define ipg_r32(reg) ioread32(ioaddr + (reg))
+#define ipg_r16(reg) ioread16(ioaddr + (reg))
+#define ipg_r8(reg) ioread8(ioaddr + (reg))
+
+#define JUMBO_FRAME_4k_ONLY
+enum {
+ netdev_io_size = 128
+};
+
+#include "ipg.h"
+#define DRV_NAME "ipg"
+
+MODULE_AUTHOR("IC Plus Corp. 2003");
+MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver "
+ DrvVer);
+MODULE_LICENSE("GPL");
+
+static const char *ipg_brand_name[] = {
+ "IC PLUS IP1000 1000/100/10 based NIC",
+ "Sundance Technology ST2021 based NIC",
+ "Tamarack Microelectronics TC9020/9021 based NIC",
+ "Tamarack Microelectronics TC9020/9021 based NIC",
+ "D-Link NIC",
+ "D-Link NIC IP1000A"
+};
+
+static struct pci_device_id ipg_pci_tbl[] __devinitdata = {
+ { PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
+ { PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
+ { PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
+ { PCI_VDEVICE(DLINK, 0x9021), 3 },
+ { PCI_VDEVICE(DLINK, 0x4000), 4 },
+ { PCI_VDEVICE(DLINK, 0x4020), 5 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
+
+static inline void __iomem *ipg_ioaddr(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ return sp->ioaddr;
+}
+
+#ifdef IPG_DEBUG
+static void ipg_dump_rfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+ u32 offset;
+
+ IPG_DEBUG_MSG("_dump_rfdlist\n");
+
+ printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current);
+ printk(KERN_INFO "rx_dirty = %2.2x\n", sp->rx_dirty);
+ printk(KERN_INFO "RFDList start address = %16.16lx\n",
+ (unsigned long) sp->rxd_map);
+ printk(KERN_INFO "RFDListPtr register = %8.8x%8.8x\n",
+ ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
+
+ for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+ offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
+ printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i,
+ offset, (unsigned long) sp->rxd[i].next_desc);
+ offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
+ printk(KERN_INFO "%2.2x %4.4x RFS = %16.16lx\n", i,
+ offset, (unsigned long) sp->rxd[i].rfs);
+ offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
+ printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
+ offset, (unsigned long) sp->rxd[i].frag_info);
+ }
+}
+
+static void ipg_dump_tfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+ u32 offset;
+
+ IPG_DEBUG_MSG("_dump_tfdlist\n");
+
+ printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current);
+ printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
+ printk(KERN_INFO "TFDList start address = %16.16lx\n",
+ (unsigned long) sp->txd_map);
+ printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n",
+ ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
+ printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
+ offset, (unsigned long) sp->txd[i].next_desc);
+
+ offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
+ printk(KERN_INFO "%2.2x %4.4x TFC = %16.16lx\n", i,
+ offset, (unsigned long) sp->txd[i].tfc);
+ offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
+ printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
+ offset, (unsigned long) sp->txd[i].frag_info);
+ }
+}
+#endif
+
+static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
+{
+ ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
+ ndelay(IPG_PC_PHYCTRLWAIT_NS);
+}
+
+static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
+{
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
+}
+
+static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+ phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
+
+ ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
+}
+
+static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+ ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
+ phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
+}
+
+static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity)
+{
+ u16 bit_data;
+
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
+
+ bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
+
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
+
+ return bit_data;
+}
+
+/*
+ * Read a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ /*
+ * The GMII mangement frame structure for a read is as follows:
+ *
+ * |Preamble|st|op|phyad|regad|ta| data |idle|
+ * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
+ *
+ * <32 1s> = 32 consecutive logic 1 values
+ * A = bit of Physical Layer device address (MSB first)
+ * R = bit of register address (MSB first)
+ * z = High impedance state
+ * D = bit of read data (MSB first)
+ *
+ * Transmission order is 'Preamble' field first, bits transmitted
+ * left to right (first to last).
+ */
+ struct {
+ u32 field;
+ unsigned int len;
+ } p[] = {
+ { GMII_PREAMBLE, 32 }, /* Preamble */
+ { GMII_ST, 2 }, /* ST */
+ { GMII_READ, 2 }, /* OP */
+ { phy_id, 5 }, /* PHYAD */
+ { phy_reg, 5 }, /* REGAD */
+ { 0x0000, 2 }, /* TA */
+ { 0x0000, 16 }, /* DATA */
+ { 0x0000, 1 } /* IDLE */
+ };
+ unsigned int i, j;
+ u8 polarity, data;
+
+ polarity = ipg_r8(PHY_CTRL);
+ polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+ /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+ for (j = 0; j < 5; j++) {
+ for (i = 0; i < p[j].len; i++) {
+ /* For each variable length field, the MSB must be
+ * transmitted first. Rotate through the field bits,
+ * starting with the MSB, and move each bit into the
+ * the 1st (2^1) bit position (this is the bit position
+ * corresponding to the MgmtData bit of the PhyCtrl
+ * register for the IPG).
+ *
+ * Example: ST = 01;
+ *
+ * First write a '0' to bit 1 of the PhyCtrl
+ * register, then write a '1' to bit 1 of the
+ * PhyCtrl register.
+ *
+ * To do this, right shift the MSB of ST by the value:
+ * [field length - 1 - #ST bits already written]
+ * then left shift this result by 1.
+ */
+ data = (p[j].field >> (p[j].len - 1 - i)) << 1;
+ data &= IPG_PC_MGMTDATA;
+ data |= polarity | IPG_PC_MGMTDIR;
+
+ ipg_drive_phy_ctl_low_high(ioaddr, data);
+ }
+ }
+
+ send_three_state(ioaddr, polarity);
+
+ read_phy_bit(ioaddr, polarity);
+
+ /*
+ * For a read cycle, the bits for the next two fields (TA and
+ * DATA) are driven by the PHY (the IPG reads these bits).
+ */
+ for (i = 0; i < p[6].len; i++) {
+ p[6].field |=
+ (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
+ }
+
+ send_three_state(ioaddr, polarity);
+ send_three_state(ioaddr, polarity);
+ send_three_state(ioaddr, polarity);
+ send_end(ioaddr, polarity);
+
+ /* Return the value of the DATA field. */
+ return p[6].field;
+}
+
+/*
+ * Write to a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ /*
+ * The GMII mangement frame structure for a read is as follows:
+ *
+ * |Preamble|st|op|phyad|regad|ta| data |idle|
+ * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
+ *
+ * <32 1s> = 32 consecutive logic 1 values
+ * A = bit of Physical Layer device address (MSB first)
+ * R = bit of register address (MSB first)
+ * z = High impedance state
+ * D = bit of write data (MSB first)
+ *
+ * Transmission order is 'Preamble' field first, bits transmitted
+ * left to right (first to last).
+ */
+ struct {
+ u32 field;
+ unsigned int len;
+ } p[] = {
+ { GMII_PREAMBLE, 32 }, /* Preamble */
+ { GMII_ST, 2 }, /* ST */
+ { GMII_WRITE, 2 }, /* OP */
+ { phy_id, 5 }, /* PHYAD */
+ { phy_reg, 5 }, /* REGAD */
+ { 0x0002, 2 }, /* TA */
+ { val & 0xffff, 16 }, /* DATA */
+ { 0x0000, 1 } /* IDLE */
+ };
+ unsigned int i, j;
+ u8 polarity, data;
+
+ polarity = ipg_r8(PHY_CTRL);
+ polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+ /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+ for (j = 0; j < 7; j++) {
+ for (i = 0; i < p[j].len; i++) {
+ /* For each variable length field, the MSB must be
+ * transmitted first. Rotate through the field bits,
+ * starting with the MSB, and move each bit into the
+ * the 1st (2^1) bit position (this is the bit position
+ * corresponding to the MgmtData bit of the PhyCtrl
+ * register for the IPG).
+ *
+ * Example: ST = 01;
+ *
+ * First write a '0' to bit 1 of the PhyCtrl
+ * register, then write a '1' to bit 1 of the
+ * PhyCtrl register.
+ *
+ * To do this, right shift the MSB of ST by the value:
+ * [field length - 1 - #ST bits already written]
+ * then left shift this result by 1.
+ */
+ data = (p[j].field >> (p[j].len - 1 - i)) << 1;
+ data &= IPG_PC_MGMTDATA;
+ data |= polarity | IPG_PC_MGMTDIR;
+
+ ipg_drive_phy_ctl_low_high(ioaddr, data);
+ }
+ }
+
+ /* The last cycle is a tri-state, so read from the PHY. */
+ for (j = 7; j < 8; j++) {
+ for (i = 0; i < p[j].len; i++) {
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
+
+ p[j].field |= ((ipg_r8(PHY_CTRL) &
+ IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i);
+
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
+ }
+ }
+}
+
+/* Set LED_Mode JES20040127EEPROM */
+static void ipg_set_led_mode(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ u32 mode;
+
+ mode = ipg_r32(ASIC_CTRL);
+ mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
+
+ if ((sp->LED_Mode & 0x03) > 1)
+ mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */
+
+ if ((sp->LED_Mode & 0x01) == 1)
+ mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */
+
+ if ((sp->LED_Mode & 0x08) == 8)
+ mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */
+
+ ipg_w32(mode, ASIC_CTRL);
+}
+
+/* Set PHYSet JES20040127EEPROM */
+static void ipg_set_phy_set(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ int physet;
+
+ physet = ipg_r8(PHY_SET);
+ physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
+ physet |= ((sp->LED_Mode & 0x70) >> 4);
+ ipg_w8(physet, PHY_SET);
+}
+
+static int ipg_reset(struct net_device *dev, u32 resetflags)
+{
+ /* Assert functional resets via the IPG AsicCtrl
+ * register as specified by the 'resetflags' input
+ * parameter.
+ */
+ void __iomem *ioaddr = ipg_ioaddr(dev); //JES20040127EEPROM:
+ unsigned int timeout_count = 0;
+
+ IPG_DEBUG_MSG("_reset\n");
+
+ ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
+
+ /* Delay added to account for problem with 10Mbps reset. */
+ mdelay(IPG_AC_RESETWAIT);
+
+ while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
+ mdelay(IPG_AC_RESETWAIT);
+ if (++timeout_count > IPG_AC_RESET_TIMEOUT)
+ return -ETIME;
+ }
+ /* Set LED Mode in Asic Control JES20040127EEPROM */
+ ipg_set_led_mode(dev);
+
+ /* Set PHYSet Register Value JES20040127EEPROM */
+ ipg_set_phy_set(dev);
+ return 0;
+}
+
+/* Find the GMII PHY address. */
+static int ipg_find_phyaddr(struct net_device *dev)
+{
+ unsigned int phyaddr, i;
+
+ for (i = 0; i < 32; i++) {
+ u32 status;
+
+ /* Search for the correct PHY address among 32 possible. */
+ phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32;
+
+ /* 10/22/03 Grace change verify from GMII_PHY_STATUS to
+ GMII_PHY_ID1
+ */
+
+ status = mdio_read(dev, phyaddr, MII_BMSR);
+
+ if ((status != 0xFFFF) && (status != 0))
+ return phyaddr;
+ }
+
+ return 0x1f;
+}
+
+/*
+ * Configure IPG based on result of IEEE 802.3 PHY
+ * auto-negotiation.
+ */
+static int ipg_config_autoneg(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int txflowcontrol;
+ unsigned int rxflowcontrol;
+ unsigned int fullduplex;
+ unsigned int gig;
+ u32 mac_ctrl_val;
+ u32 asicctrl;
+ u8 phyctrl;
+
+ IPG_DEBUG_MSG("_config_autoneg\n");
+
+ asicctrl = ipg_r32(ASIC_CTRL);
+ phyctrl = ipg_r8(PHY_CTRL);
+ mac_ctrl_val = ipg_r32(MAC_CTRL);
+
+ /* Set flags for use in resolving auto-negotation, assuming
+ * non-1000Mbps, half duplex, no flow control.
+ */
+ fullduplex = 0;
+ txflowcontrol = 0;
+ rxflowcontrol = 0;
+ gig = 0;
+
+ /* To accomodate a problem in 10Mbps operation,
+ * set a global flag if PHY running in 10Mbps mode.
+ */
+ sp->tenmbpsmode = 0;
+
+ printk(KERN_INFO "%s: Link speed = ", dev->name);
+
+ /* Determine actual speed of operation. */
+ switch (phyctrl & IPG_PC_LINK_SPEED) {
+ case IPG_PC_LINK_SPEED_10MBPS:
+ printk("10Mbps.\n");
+ printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n",
+ dev->name);
+ sp->tenmbpsmode = 1;
+ break;
+ case IPG_PC_LINK_SPEED_100MBPS:
+ printk("100Mbps.\n");
+ break;
+ case IPG_PC_LINK_SPEED_1000MBPS:
+ printk("1000Mbps.\n");
+ gig = 1;
+ break;
+ default:
+ printk("undefined!\n");
+ return 0;
+ }
+
+ if (phyctrl & IPG_PC_DUPLEX_STATUS) {
+ fullduplex = 1;
+ txflowcontrol = 1;
+ rxflowcontrol = 1;
+ }
+
+ /* Configure full duplex, and flow control. */
+ if (fullduplex == 1) {
+ /* Configure IPG for full duplex operation. */
+ printk(KERN_INFO "%s: setting full duplex, ", dev->name);
+
+ mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
+
+ if (txflowcontrol == 1) {
+ printk("TX flow control");
+ mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
+ } else {
+ printk("no TX flow control");
+ mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
+ }
+
+ if (rxflowcontrol == 1) {
+ printk(", RX flow control.");
+ mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ } else {
+ printk(", no RX flow control.");
+ mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ }
+
+ printk("\n");
+ } else {
+ /* Configure IPG for half duplex operation. */
+ printk(KERN_INFO "%s: setting half duplex, "
+ "no TX flow control, no RX flow control.\n", dev->name);
+
+ mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD &
+ ~IPG_MC_TX_FLOW_CONTROL_ENABLE &
+ ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ }
+ ipg_w32(mac_ctrl_val, MAC_CTRL);
+ return 0;
+}
+
+/* Determine and configure multicast operation and set
+ * receive mode for IPG.
+ */
+static void ipg_nic_set_multicast_list(struct net_device *dev)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ struct dev_mc_list *mc_list_ptr;
+ unsigned int hashindex;
+ u32 hashtable[2];
+ u8 receivemode;
+
+ IPG_DEBUG_MSG("_nic_set_multicast_list\n");
+
+ receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST;
+
+ if (dev->flags & IFF_PROMISC) {
+ /* NIC to be configured in promiscuous mode. */
+ receivemode = IPG_RM_RECEIVEALLFRAMES;
+ } else if ((dev->flags & IFF_ALLMULTI) ||
+ (dev->flags & IFF_MULTICAST &
+ (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) {
+ /* NIC to be configured to receive all multicast
+ * frames. */
+ receivemode |= IPG_RM_RECEIVEMULTICAST;
+ } else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) {
+ /* NIC to be configured to receive selected
+ * multicast addresses. */
+ receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
+ }
+
+ /* Calculate the bits to set for the 64 bit, IPG HASHTABLE.
+ * The IPG applies a cyclic-redundancy-check (the same CRC
+ * used to calculate the frame data FCS) to the destination
+ * address all incoming multicast frames whose destination
+ * address has the multicast bit set. The least significant
+ * 6 bits of the CRC result are used as an addressing index
+ * into the hash table. If the value of the bit addressed by
+ * this index is a 1, the frame is passed to the host system.
+ */
+
+ /* Clear hashtable. */
+ hashtable[0] = 0x00000000;
+ hashtable[1] = 0x00000000;
+
+ /* Cycle through all multicast addresses to filter. */
+ for (mc_list_ptr = dev->mc_list;
+ mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) {
+ /* Calculate CRC result for each multicast address. */
+ hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
+ ETH_ALEN);
+
+ /* Use only the least significant 6 bits. */
+ hashindex = hashindex & 0x3F;
+
+ /* Within "hashtable", set bit number "hashindex"
+ * to a logic 1.
+ */
+ set_bit(hashindex, (void *)hashtable);
+ }
+
+ /* Write the value of the hashtable, to the 4, 16 bit
+ * HASHTABLE IPG registers.
+ */
+ ipg_w32(hashtable[0], HASHTABLE_0);
+ ipg_w32(hashtable[1], HASHTABLE_1);
+
+ ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE);
+
+ IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE));
+}
+
+static int ipg_io_config(struct net_device *dev)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ u32 origmacctrl;
+ u32 restoremacctrl;
+
+ IPG_DEBUG_MSG("_io_config\n");
+
+ origmacctrl = ipg_r32(MAC_CTRL);
+
+ restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE;
+
+ /* Based on compilation option, determine if FCS is to be
+ * stripped on receive frames by IPG.
+ */
+ if (!IPG_STRIP_FCS_ON_RX)
+ restoremacctrl |= IPG_MC_RCV_FCS;
+
+ /* Determine if transmitter and/or receiver are
+ * enabled so we may restore MACCTRL correctly.
+ */
+ if (origmacctrl & IPG_MC_TX_ENABLED)
+ restoremacctrl |= IPG_MC_TX_ENABLE;
+
+ if (origmacctrl & IPG_MC_RX_ENABLED)
+ restoremacctrl |= IPG_MC_RX_ENABLE;
+
+ /* Transmitter and receiver must be disabled before setting
+ * IFSSelect.
+ */
+ ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+
+ /* Now that transmitter and receiver are disabled, write
+ * to IFSSelect.
+ */
+ ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL);
+
+ /* Set RECEIVEMODE register. */
+ ipg_nic_set_multicast_list(dev);
+
+ ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE);
+
+ ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD);
+ ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH);
+ ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH);
+ ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD);
+ ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH);
+ ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH);
+ ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE |
+ IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED |
+ IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT |
+ IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE);
+ ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH);
+ ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH);
+
+ /* IPG multi-frag frame bug workaround.
+ * Per silicon revision B3 eratta.
+ */
+ ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL);
+
+ /* IPG TX poll now bug workaround.
+ * Per silicon revision B3 eratta.
+ */
+ ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL);
+
+ /* IPG RX poll now bug workaround.
+ * Per silicon revision B3 eratta.
+ */
+ ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL);
+
+ /* Now restore MACCTRL to original setting. */
+ ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL);
+
+ /* Disable unused RMON statistics. */
+ ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK);
+
+ /* Disable unused MIB statistics. */
+ ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD |
+ IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES |
+ IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES |
+ IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK |
+ IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS |
+ IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK);
+
+ return 0;
+}
+
+/*
+ * Create a receive buffer within system memory and update
+ * NIC private structure appropriately.
+ */
+static int ipg_get_rxbuff(struct net_device *dev, int entry)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ struct ipg_rx *rxfd = sp->rxd + entry;
+ struct sk_buff *skb;
+ u64 rxfragsize;
+
+ IPG_DEBUG_MSG("_get_rxbuff\n");
+
+ skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN);
+ if (!skb) {
+ sp->RxBuff[entry] = NULL;
+ return -ENOMEM;
+ }
+
+ /* Adjust the data start location within the buffer to
+ * align IP address field to a 16 byte boundary.
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ /* Associate the receive buffer with the IPG NIC. */
+ skb->dev = dev;
+
+ /* Save the address of the sk_buff structure. */
+ sp->RxBuff[entry] = skb;
+
+ rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+
+ /* Set the RFD fragment length. */
+ rxfragsize = IPG_RXFRAG_SIZE;
+ rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN);
+
+ return 0;
+}
+
+static int init_rfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_init_rfdlist\n");
+
+ for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+ struct ipg_rx *rxfd = sp->rxd + i;
+
+ if (sp->RxBuff[i]) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+ sp->RxBuff[i] = NULL;
+ }
+
+ /* Clear out the RFS field. */
+ rxfd->rfs = 0x0000000000000000;
+
+ if (ipg_get_rxbuff(dev, i) < 0) {
+ /*
+ * A receive buffer was not ready, break the
+ * RFD list here.
+ */
+ IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n");
+
+ /* Just in case we cannot allocate a single RFD.
+ * Should not occur.
+ */
+ if (i == 0) {
+ printk(KERN_ERR "%s: No memory available"
+ " for RFD list.\n", dev->name);
+ return -ENOMEM;
+ }
+ }
+
+ rxfd->next_desc = cpu_to_le64(sp->rxd_map +
+ sizeof(struct ipg_rx)*(i + 1));
+ }
+ sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map);
+
+ sp->rx_current = 0;
+ sp->rx_dirty = 0;
+
+ /* Write the location of the RFDList to the IPG. */
+ ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0);
+ ipg_w32(0x00000000, RFD_LIST_PTR_1);
+
+ return 0;
+}
+
+static void init_tfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_init_tfdlist\n");
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ struct ipg_tx *txfd = sp->txd + i;
+
+ txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+ if (sp->TxBuff[i]) {
+ IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+ sp->TxBuff[i] = NULL;
+ }
+
+ txfd->next_desc = cpu_to_le64(sp->txd_map +
+ sizeof(struct ipg_tx)*(i + 1));
+ }
+ sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map);
+
+ sp->tx_current = 0;
+ sp->tx_dirty = 0;
+
+ /* Write the location of the TFDList to the IPG. */
+ IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n",
+ (u32) sp->txd_map);
+ ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
+ ipg_w32(0x00000000, TFD_LIST_PTR_1);
+
+ sp->ResetCurrentTFD = 1;
+}
+
+/*
+ * Free all transmit buffers which have already been transfered
+ * via DMA to the IPG.
+ */
+static void ipg_nic_txfree(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int curr;
+ u64 txd_map;
+ unsigned int released, pending;
+
+ txd_map = (u64)sp->txd_map;
+ curr = ipg_r32(TFD_LIST_PTR_0) -
+ do_div(txd_map, sizeof(struct ipg_tx)) - 1;
+
+ IPG_DEBUG_MSG("_nic_txfree\n");
+
+ pending = sp->tx_current - sp->tx_dirty;
+
+ for (released = 0; released < pending; released++) {
+ unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
+ struct sk_buff *skb = sp->TxBuff[dirty];
+ struct ipg_tx *txfd = sp->txd + dirty;
+
+ IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc);
+
+ /* Look at each TFD's TFC field beginning
+ * at the last freed TFD up to the current TFD.
+ * If the TFDDone bit is set, free the associated
+ * buffer.
+ */
+ if (dirty == curr)
+ break;
+
+ /* Setup TFDDONE for compatible issue. */
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE);
+
+ /* Free the transmit buffer. */
+ if (skb) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+ skb->len, PCI_DMA_TODEVICE);
+
+ IPG_DEV_KFREE_SKB(skb);
+
+ sp->TxBuff[dirty] = NULL;
+ }
+ }
+
+ sp->tx_dirty += released;
+
+ if (netif_queue_stopped(dev) &&
+ (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) {
+ netif_wake_queue(dev);
+ }
+}
+
+static void ipg_tx_timeout(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+
+ ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK |
+ IPG_AC_FIFO);
+
+ spin_lock_irq(&sp->lock);
+
+ /* Re-configure after DMA reset. */
+ if (ipg_io_config(dev) < 0) {
+ printk(KERN_INFO "%s: Error during re-configuration.\n",
+ dev->name);
+ }
+
+ init_tfdlist(dev);
+
+ spin_unlock_irq(&sp->lock);
+
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK,
+ MAC_CTRL);
+}
+
+/*
+ * For TxComplete interrupts, free all transmit
+ * buffers which have already been transfered via DMA
+ * to the IPG.
+ */
+static void ipg_nic_txcleanup(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_nic_txcleanup\n");
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ /* Reading the TXSTATUS register clears the
+ * TX_COMPLETE interrupt.
+ */
+ u32 txstatusdword = ipg_r32(TX_STATUS);
+
+ IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword);
+
+ /* Check for Transmit errors. Error bits only valid if
+ * TX_COMPLETE bit in the TXSTATUS register is a 1.
+ */
+ if (!(txstatusdword & IPG_TS_TX_COMPLETE))
+ break;
+
+ /* If in 10Mbps mode, indicate transmit is ready. */
+ if (sp->tenmbpsmode) {
+ netif_wake_queue(dev);
+ }
+
+ /* Transmit error, increment stat counters. */
+ if (txstatusdword & IPG_TS_TX_ERROR) {
+ IPG_DEBUG_MSG("Transmit error.\n");
+ sp->stats.tx_errors++;
+ }
+
+ /* Late collision, re-enable transmitter. */
+ if (txstatusdword & IPG_TS_LATE_COLLISION) {
+ IPG_DEBUG_MSG("Late collision on transmit.\n");
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+ }
+
+ /* Maximum collisions, re-enable transmitter. */
+ if (txstatusdword & IPG_TS_TX_MAX_COLL) {
+ IPG_DEBUG_MSG("Maximum collisions on transmit.\n");
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+ }
+
+ /* Transmit underrun, reset and re-enable
+ * transmitter.
+ */
+ if (txstatusdword & IPG_TS_TX_UNDERRUN) {
+ IPG_DEBUG_MSG("Transmitter underrun.\n");
+ sp->stats.tx_fifo_errors++;
+ ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
+ IPG_AC_NETWORK | IPG_AC_FIFO);
+
+ /* Re-configure after DMA reset. */
+ if (ipg_io_config(dev) < 0) {
+ printk(KERN_INFO
+ "%s: Error during re-configuration.\n",
+ dev->name);
+ }
+ init_tfdlist(dev);
+
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+ }
+ }
+
+ ipg_nic_txfree(dev);
+}
+
+/* Provides statistical information about the IPG NIC. */
+struct net_device_stats *ipg_nic_get_stats(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ u16 temp1;
+ u16 temp2;
+
+ IPG_DEBUG_MSG("_nic_get_stats\n");
+
+ /* Check to see if the NIC has been initialized via nic_open,
+ * before trying to read statistic registers.
+ */
+ if (!test_bit(__LINK_STATE_START, &dev->state))
+ return &sp->stats;
+
+ sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK);
+ sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK);
+ sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK);
+ sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK);
+ temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS);
+ sp->stats.rx_errors += temp1;
+ sp->stats.rx_missed_errors += temp1;
+ temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) +
+ ipg_r32(IPG_LATECOLLISIONS);
+ temp2 = ipg_r16(IPG_CARRIERSENSEERRORS);
+ sp->stats.collisions += temp1;
+ sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS);
+ sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) +
+ ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2;
+ sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK);
+
+ /* detailed tx_errors */
+ sp->stats.tx_carrier_errors += temp2;
+
+ /* detailed rx_errors */
+ sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) +
+ ipg_r16(IPG_FRAMETOOLONGERRRORS);
+ sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS);
+
+ /* Unutilized IPG statistic registers. */
+ ipg_r32(IPG_MCSTFRAMESRCVDOK);
+
+ return &sp->stats;
+}
+
+/* Restore used receive buffers. */
+static int ipg_nic_rxrestore(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ const unsigned int curr = sp->rx_current;
+ unsigned int dirty = sp->rx_dirty;
+
+ IPG_DEBUG_MSG("_nic_rxrestore\n");
+
+ for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) {
+ unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
+
+ /* rx_copybreak may poke hole here and there. */
+ if (sp->RxBuff[entry])
+ continue;
+
+ /* Generate a new receive buffer to replace the
+ * current buffer (which will be released by the
+ * Linux system).
+ */
+ if (ipg_get_rxbuff(dev, entry) < 0) {
+ IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n");
+
+ break;
+ }
+
+ /* Reset the RFS field. */
+ sp->rxd[entry].rfs = 0x0000000000000000;
+ }
+ sp->rx_dirty = dirty;
+
+ return 0;
+}
+
+#ifdef JUMBO_FRAME
+
+/* use jumboindex and jumbosize to control jumbo frame status
+ initial status is jumboindex=-1 and jumbosize=0
+ 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
+ 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
+ 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
+ previous receiving and need to continue dumping the current one
+*/
+enum {
+ NormalPacket,
+ ErrorPacket
+};
+
+enum {
+ Frame_NoStart_NoEnd = 0,
+ Frame_WithStart = 1,
+ Frame_WithEnd = 10,
+ Frame_WithStart_WithEnd = 11
+};
+
+inline void ipg_nic_rx_free_skb(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+
+ if (sp->RxBuff[entry]) {
+ struct ipg_rx *rxfd = sp->rxd + entry;
+
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+ sp->RxBuff[entry] = NULL;
+ }
+}
+
+inline int ipg_nic_rx_check_frame_type(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
+ int type = Frame_NoStart_NoEnd;
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
+ type += Frame_WithStart;
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
+ type += Frame_WithEnd;
+ return type;
+}
+
+inline int ipg_nic_rx_check_error(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+ struct ipg_rx *rxfd = sp->rxd + entry;
+
+ if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
+ (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+ IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+ IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
+ IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+ (unsigned long) rxfd->rfs);
+
+ /* Increment general receive error statistic. */
+ sp->stats.rx_errors++;
+
+ /* Increment detailed receive error statistics. */
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
+ IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+
+ sp->stats.rx_fifo_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
+ IPG_DEBUG_MSG("RX runt occured.\n");
+ sp->stats.rx_length_errors++;
+ }
+
+ /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME,
+ * error count handled by a IPG statistic register.
+ */
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
+ IPG_DEBUG_MSG("RX alignment error occured.\n");
+ sp->stats.rx_frame_errors++;
+ }
+
+ /* Do nothing for IPG_RFS_RXFCSERROR, error count
+ * handled by a IPG statistic register.
+ */
+
+ /* Free the memory associated with the RX
+ * buffer since it is erroneous and we will
+ * not pass it to higher layer processes.
+ */
+ if (sp->RxBuff[entry]) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+ IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+ sp->RxBuff[entry] = NULL;
+ }
+ return ErrorPacket;
+ }
+ return NormalPacket;
+}
+
+static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+ struct sk_buff *skb;
+ int framelen;
+
+ if (jumbo->FoundStart) {
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+ }
+
+ // 1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) != NormalPacket)
+ return;
+
+ skb = sp->RxBuff[entry];
+ if (!skb)
+ return;
+
+ // accept this frame and send to upper layer
+ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+ if (framelen > IPG_RXFRAG_SIZE)
+ framelen = IPG_RXFRAG_SIZE;
+
+ skb_put(skb, framelen);
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_NONE;
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ sp->RxBuff[entry] = NULL;
+}
+
+static void ipg_nic_rx_with_start(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+ struct pci_dev *pdev = sp->pdev;
+ struct sk_buff *skb;
+
+ // 1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) != NormalPacket)
+ return;
+
+ // accept this frame and send to upper layer
+ skb = sp->RxBuff[entry];
+ if (!skb)
+ return;
+
+ if (jumbo->FoundStart)
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+
+ pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+ skb_put(skb, IPG_RXFRAG_SIZE);
+
+ jumbo->FoundStart = 1;
+ jumbo->CurrentSize = IPG_RXFRAG_SIZE;
+ jumbo->skb = skb;
+
+ sp->RxBuff[entry] = NULL;
+ dev->last_rx = jiffies;
+}
+
+static void ipg_nic_rx_with_end(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+
+ //1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+ struct sk_buff *skb = sp->RxBuff[entry];
+
+ if (!skb)
+ return;
+
+ if (jumbo->FoundStart) {
+ int framelen, endframelen;
+
+ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+ endframeLen = framelen - jumbo->CurrentSize;
+ /*
+ if (framelen > IPG_RXFRAG_SIZE)
+ framelen=IPG_RXFRAG_SIZE;
+ */
+ if (framelen > IPG_RXSUPPORT_SIZE)
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ else {
+ memcpy(skb_put(jumbo->skb, endframeLen),
+ skb->data, endframeLen);
+
+ jumbo->skb->protocol =
+ eth_type_trans(jumbo->skb, dev);
+
+ jumbo->skb->ip_summed = CHECKSUM_NONE;
+ netif_rx(jumbo->skb);
+ }
+ }
+
+ dev->last_rx = jiffies;
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+
+ ipg_nic_rx_free_skb(dev);
+ } else {
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+ }
+}
+
+static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+
+ //1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+ struct sk_buff *skb = sp->RxBuff[entry];
+
+ if (skb) {
+ if (jumbo->FoundStart) {
+ jumbo->CurrentSize += IPG_RXFRAG_SIZE;
+ if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) {
+ memcpy(skb_put(jumbo->skb,
+ IPG_RXFRAG_SIZE),
+ skb->data, IPG_RXFRAG_SIZE);
+ }
+ }
+ dev->last_rx = jiffies;
+ ipg_nic_rx_free_skb(dev);
+ }
+ } else {
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+ }
+}
+
+static int ipg_nic_rx(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int curr = sp->rx_current;
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_nic_rx\n");
+
+ for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+ unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+ struct ipg_rx *rxfd = sp->rxd + entry;
+
+ if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE)))
+ break;
+
+ switch (ipg_nic_rx_check_frame_type(dev)) {
+ case Frame_WithStart_WithEnd:
+ ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+ break;
+ case Frame_WithStart:
+ ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+ break;
+ case Frame_WithEnd:
+ ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+ break;
+ case Frame_NoStart_NoEnd:
+ ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+ break;
+ }
+ }
+
+ sp->rx_current = curr;
+
+ if (i == IPG_MAXRFDPROCESS_COUNT) {
+ /* There are more RFDs to process, however the
+ * allocated amount of RFD processing time has
+ * expired. Assert Interrupt Requested to make
+ * sure we come back to process the remaining RFDs.
+ */
+ ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+ }
+
+ ipg_nic_rxrestore(dev);
+
+ return 0;
+}
+
+#else
+static int ipg_nic_rx(struct net_device *dev)
+{
+ /* Transfer received Ethernet frames to higher network layers. */
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int curr = sp->rx_current;
+ void __iomem *ioaddr = sp->ioaddr;
+ struct ipg_rx *rxfd;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_nic_rx\n");
+
+#define __RFS_MASK \
+ cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND)
+
+ for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+ unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+ struct sk_buff *skb = sp->RxBuff[entry];
+ unsigned int framelen;
+
+ rxfd = sp->rxd + entry;
+
+ if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb)
+ break;
+
+ /* Get received frame length. */
+ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+ /* Check for jumbo frame arrival with too small
+ * RXFRAG_SIZE.
+ */
+ if (framelen > IPG_RXFRAG_SIZE) {
+ IPG_DEBUG_MSG
+ ("RFS FrameLen > allocated fragment size.\n");
+
+ framelen = IPG_RXFRAG_SIZE;
+ }
+
+ if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs &
+ (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+ IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+ IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) {
+
+ IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+ (unsigned long int) rxfd->rfs);
+
+ /* Increment general receive error statistic. */
+ sp->stats.rx_errors++;
+
+ /* Increment detailed receive error statistics. */
+ if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) {
+ IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+ sp->stats.rx_fifo_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) {
+ IPG_DEBUG_MSG("RX runt occured.\n");
+ sp->stats.rx_length_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ;
+ /* Do nothing, error count handled by a IPG
+ * statistic register.
+ */
+
+ if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) {
+ IPG_DEBUG_MSG("RX alignment error occured.\n");
+ sp->stats.rx_frame_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ;
+ /* Do nothing, error count handled by a IPG
+ * statistic register.
+ */
+
+ /* Free the memory associated with the RX
+ * buffer since it is erroneous and we will
+ * not pass it to higher layer processes.
+ */
+ if (skb) {
+ u64 info = rxfd->frag_info;
+
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+ IPG_DEV_KFREE_SKB(skb);
+ }
+ } else {
+
+ /* Adjust the new buffer length to accomodate the size
+ * of the received frame.
+ */
+ skb_put(skb, framelen);
+
+ /* Set the buffer's protocol field to Ethernet. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* If the frame contains an IP/TCP/UDP frame,
+ * determine if upper layer must check IP/TCP/UDP
+ * checksums.
+ *
+ * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM
+ * VERIFICATION FOR SILICON REVISIONS B3
+ * AND EARLIER!
+ *
+ if ((le64_to_cpu(rxfd->rfs &
+ (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED |
+ IPG_RFS_IPDETECTED))) &&
+ !(le64_to_cpu(rxfd->rfs &
+ (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR |
+ IPG_RFS_IPERROR)))) {
+ * Indicate IP checksums were performed
+ * by the IPG.
+ *
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else
+ */
+ {
+ /* The IPG encountered an error with (or
+ * there were no) IP/TCP/UDP checksums.
+ * This may or may not indicate an invalid
+ * IP/TCP/UDP frame was received. Let the
+ * upper layer decide.
+ */
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
+ /* Hand off frame for higher layer processing.
+ * The function netif_rx() releases the sk_buff
+ * when processing completes.
+ */
+ netif_rx(skb);
+
+ /* Record frame receive time (jiffies = Linux
+ * kernel current time stamp).
+ */
+ dev->last_rx = jiffies;
+ }
+
+ /* Assure RX buffer is not reused by IPG. */
+ sp->RxBuff[entry] = NULL;
+ }
+
+ /*
+ * If there are more RFDs to proces and the allocated amount of RFD
+ * processing time has expired, assert Interrupt Requested to make
+ * sure we come back to process the remaining RFDs.
+ */
+ if (i == IPG_MAXRFDPROCESS_COUNT)
+ ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+
+#ifdef IPG_DEBUG
+ /* Check if the RFD list contained no receive frame data. */
+ if (!i)
+ sp->EmptyRFDListCount++;
+#endif
+ while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) &&
+ !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) &&
+ (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) {
+ unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
+
+ rxfd = sp->rxd + entry;
+
+ IPG_DEBUG_MSG("Frame requires multiple RFDs.\n");
+
+ /* An unexpected event, additional code needed to handle
+ * properly. So for the time being, just disregard the
+ * frame.
+ */
+
+ /* Free the memory associated with the RX
+ * buffer since it is erroneous and we will
+ * not pass it to higher layer processes.
+ */
+ if (sp->RxBuff[entry]) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+ }
+
+ /* Assure RX buffer is not reused by IPG. */
+ sp->RxBuff[entry] = NULL;
+ }
+
+ sp->rx_current = curr;
+
+ /* Check to see if there are a minimum number of used
+ * RFDs before restoring any (should improve performance.)
+ */
+ if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE)
+ ipg_nic_rxrestore(dev);
+
+ return 0;
+}
+#endif
+
+static void ipg_reset_after_host_error(struct work_struct *work)
+{
+ struct ipg_nic_private *sp =
+ container_of(work, struct ipg_nic_private, task.work);
+ struct net_device *dev = sp->dev;
+
+ IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL));
+
+ /*
+ * Acknowledge HostError interrupt by resetting
+ * IPG DMA and HOST.
+ */
+ ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+ init_rfdlist(dev);
+ init_tfdlist(dev);
+
+ if (ipg_io_config(dev) < 0) {
+ printk(KERN_INFO "%s: Cannot recover from PCI error.\n",
+ dev->name);
+ schedule_delayed_work(&sp->task, HZ);
+ }
+}
+
+static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
+{
+ struct net_device *dev = dev_inst;
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int handled = 0;
+ u16 status;
+
+ IPG_DEBUG_MSG("_interrupt_handler\n");
+
+#ifdef JUMBO_FRAME
+ ipg_nic_rxrestore(dev);
+#endif
+ /* Get interrupt source information, and acknowledge
+ * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
+ * IntRequested, MacControlFrame, LinkEvent) interrupts
+ * if issued. Also, all IPG interrupts are disabled by
+ * reading IntStatusAck.
+ */
+ status = ipg_r16(INT_STATUS_ACK);
+
+ IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status);
+
+ /* Shared IRQ of remove event. */
+ if (!(status & IPG_IS_RSVD_MASK))
+ goto out_enable;
+
+ handled = 1;
+
+ if (unlikely(!netif_running(dev)))
+ goto out;
+
+ spin_lock(&sp->lock);
+
+ /* If RFDListEnd interrupt, restore all used RFDs. */
+ if (status & IPG_IS_RFD_LIST_END) {
+ IPG_DEBUG_MSG("RFDListEnd Interrupt.\n");
+
+ /* The RFD list end indicates an RFD was encountered
+ * with a 0 NextPtr, or with an RFDDone bit set to 1
+ * (indicating the RFD is not read for use by the
+ * IPG.) Try to restore all RFDs.
+ */
+ ipg_nic_rxrestore(dev);
+
+#ifdef IPG_DEBUG
+ /* Increment the RFDlistendCount counter. */
+ sp->RFDlistendCount++;
+#endif
+ }
+
+ /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or
+ * IntRequested interrupt, process received frames. */
+ if ((status & IPG_IS_RX_DMA_PRIORITY) ||
+ (status & IPG_IS_RFD_LIST_END) ||
+ (status & IPG_IS_RX_DMA_COMPLETE) ||
+ (status & IPG_IS_INT_REQUESTED)) {
+#ifdef IPG_DEBUG
+ /* Increment the RFD list checked counter if interrupted
+ * only to check the RFD list. */
+ if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END |
+ IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) &
+ (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE |
+ IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE |
+ IPG_IS_UPDATE_STATS)))
+ sp->RFDListCheckedCount++;
+#endif
+
+ ipg_nic_rx(dev);
+ }
+
+ /* If TxDMAComplete interrupt, free used TFDs. */
+ if (status & IPG_IS_TX_DMA_COMPLETE)
+ ipg_nic_txfree(dev);
+
+ /* TxComplete interrupts indicate one of numerous actions.
+ * Determine what action to take based on TXSTATUS register.
+ */
+ if (status & IPG_IS_TX_COMPLETE)
+ ipg_nic_txcleanup(dev);
+
+ /* If UpdateStats interrupt, update Linux Ethernet statistics */
+ if (status & IPG_IS_UPDATE_STATS)
+ ipg_nic_get_stats(dev);
+
+ /* If HostError interrupt, reset IPG. */
+ if (status & IPG_IS_HOST_ERROR) {
+ IPG_DDEBUG_MSG("HostError Interrupt\n");
+
+ schedule_delayed_work(&sp->task, 0);
+ }
+
+ /* If LinkEvent interrupt, resolve autonegotiation. */
+ if (status & IPG_IS_LINK_EVENT) {
+ if (ipg_config_autoneg(dev) < 0)
+ printk(KERN_INFO "%s: Auto-negotiation error.\n",
+ dev->name);
+ }
+
+ /* If MACCtrlFrame interrupt, do nothing. */
+ if (status & IPG_IS_MAC_CTRL_FRAME)
+ IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n");
+
+ /* If RxComplete interrupt, do nothing. */
+ if (status & IPG_IS_RX_COMPLETE)
+ IPG_DEBUG_MSG("RxComplete interrupt.\n");
+
+ /* If RxEarly interrupt, do nothing. */
+ if (status & IPG_IS_RX_EARLY)
+ IPG_DEBUG_MSG("RxEarly interrupt.\n");
+
+out_enable:
+ /* Re-enable IPG interrupts. */
+ ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
+ IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
+ IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
+
+ spin_unlock(&sp->lock);
+out:
+ return IRQ_RETVAL(handled);
+}
+
+static void ipg_rx_clear(struct ipg_nic_private *sp)
+{
+ unsigned int i;
+
+ for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+ if (sp->RxBuff[i]) {
+ struct ipg_rx *rxfd = sp->rxd + i;
+
+ IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+ sp->RxBuff[i] = NULL;
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ }
+ }
+}
+
+static void ipg_tx_clear(struct ipg_nic_private *sp)
+{
+ unsigned int i;
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ if (sp->TxBuff[i]) {
+ struct ipg_tx *txfd = sp->txd + i;
+
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+ sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
+
+ IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+
+ sp->TxBuff[i] = NULL;
+ }
+ }
+}
+
+static int ipg_nic_open(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ struct pci_dev *pdev = sp->pdev;
+ int rc;
+
+ IPG_DEBUG_MSG("_nic_open\n");
+
+ sp->rx_buf_sz = IPG_RXSUPPORT_SIZE;
+
+ /* Check for interrupt line conflicts, and request interrupt
+ * line for IPG.
+ *
+ * IMPORTANT: Disable IPG interrupts prior to registering
+ * IRQ.
+ */
+ ipg_w16(0x0000, INT_ENABLE);
+
+ /* Register the interrupt line to be used by the IPG within
+ * the Linux system.
+ */
+ rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED,
+ dev->name, dev);
+ if (rc < 0) {
+ printk(KERN_INFO "%s: Error when requesting interrupt.\n",
+ dev->name);
+ goto out;
+ }
+
+ dev->irq = pdev->irq;
+
+ rc = -ENOMEM;
+
+ sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES,
+ &sp->rxd_map, GFP_KERNEL);
+ if (!sp->rxd)
+ goto err_free_irq_0;
+
+ sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES,
+ &sp->txd_map, GFP_KERNEL);
+ if (!sp->txd)
+ goto err_free_rx_1;
+
+ rc = init_rfdlist(dev);
+ if (rc < 0) {
+ printk(KERN_INFO "%s: Error during configuration.\n",
+ dev->name);
+ goto err_free_tx_2;
+ }
+
+ init_tfdlist(dev);
+
+ rc = ipg_io_config(dev);
+ if (rc < 0) {
+ printk(KERN_INFO "%s: Error during configuration.\n",
+ dev->name);
+ goto err_release_tfdlist_3;
+ }
+
+ /* Resolve autonegotiation. */
+ if (ipg_config_autoneg(dev) < 0)
+ printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name);
+
+#ifdef JUMBO_FRAME
+ /* initialize JUMBO Frame control variable */
+ sp->Jumbo.FoundStart = 0;
+ sp->Jumbo.CurrentSize = 0;
+ sp->Jumbo.skb = 0;
+ dev->mtu = IPG_TXFRAG_SIZE;
+#endif
+
+ /* Enable transmit and receive operation of the IPG. */
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+
+ netif_start_queue(dev);
+out:
+ return rc;
+
+err_release_tfdlist_3:
+ ipg_tx_clear(sp);
+ ipg_rx_clear(sp);
+err_free_tx_2:
+ dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+err_free_rx_1:
+ dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+err_free_irq_0:
+ free_irq(pdev->irq, dev);
+ goto out;
+}
+
+static int ipg_nic_stop(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ struct pci_dev *pdev = sp->pdev;
+
+ IPG_DEBUG_MSG("_nic_stop\n");
+
+ netif_stop_queue(dev);
+
+ IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount);
+ IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount);
+ IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount);
+ IPG_DUMPTFDLIST(dev);
+
+ do {
+ (void) ipg_r16(INT_STATUS_ACK);
+
+ ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+ synchronize_irq(pdev->irq);
+ } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);
+
+ ipg_rx_clear(sp);
+
+ ipg_tx_clear(sp);
+
+ pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+ pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+
+ free_irq(pdev->irq, dev);
+
+ return 0;
+}
+
+static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;
+ unsigned long flags;
+ struct ipg_tx *txfd;
+
+ IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");
+
+ /* If in 10Mbps mode, stop the transmit queue so
+ * no more transmit frames are accepted.
+ */
+ if (sp->tenmbpsmode)
+ netif_stop_queue(dev);
+
+ if (sp->ResetCurrentTFD) {
+ sp->ResetCurrentTFD = 0;
+ entry = 0;
+ }
+
+ txfd = sp->txd + entry;
+
+ sp->TxBuff[entry] = skb;
+
+ /* Clear all TFC fields, except TFDDONE. */
+ txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+ /* Specify the TFC field within the TFD. */
+ txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |
+ (IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) |
+ (IPG_TFC_FRAGCOUNT & (1 << 24)));
+
+ /* Request TxComplete interrupts at an interval defined
+ * by the constant IPG_FRAMESBETWEENTXCOMPLETES.
+ * Request TxComplete interrupt for every frame
+ * if in 10Mbps mode to accomodate problem with 10Mbps
+ * processing.
+ */
+ if (sp->tenmbpsmode)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
+ else if (!((sp->tx_current - sp->tx_dirty + 1) >
+ IPG_FRAMESBETWEENTXDMACOMPLETES)) {
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
+ }
+ /* Based on compilation option, determine if FCS is to be
+ * appended to transmit frame by IPG.
+ */
+ if (!(IPG_APPEND_FCS_ON_TX))
+ txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);
+
+ /* Based on compilation option, determine if IP, TCP and/or
+ * UDP checksums are to be added to transmit frame by IPG.
+ */
+ if (IPG_ADD_IPCHECKSUM_ON_TX)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);
+
+ if (IPG_ADD_TCPCHECKSUM_ON_TX)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);
+
+ if (IPG_ADD_UDPCHECKSUM_ON_TX)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);
+
+ /* Based on compilation option, determine if VLAN tag info is to be
+ * inserted into transmit frame by IPG.
+ */
+ if (IPG_INSERT_MANUAL_VLAN_TAG) {
+ txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |
+ ((u64) IPG_MANUAL_VLAN_VID << 32) |
+ ((u64) IPG_MANUAL_VLAN_CFI << 44) |
+ ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));
+ }
+
+ /* The fragment start location within system memory is defined
+ * by the sk_buff structure's data field. The physical address
+ * of this location within the system's virtual memory space
+ * is determined using the IPG_HOST2BUS_MAP function.
+ */
+ txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+ skb->len, PCI_DMA_TODEVICE));
+
+ /* The length of the fragment within system memory is defined by
+ * the sk_buff structure's len field.
+ */
+ txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &
+ ((u64) (skb->len & 0xffff) << 48));
+
+ /* Clear the TFDDone bit last to indicate the TFD is ready
+ * for transfer to the IPG.
+ */
+ txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);
+
+ spin_lock_irqsave(&sp->lock, flags);
+
+ sp->tx_current++;
+
+ mmiowb();
+
+ ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
+
+ if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
+ netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&sp->lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+static void ipg_set_phy_default_param(unsigned char rev,
+ struct net_device *dev, int phy_address)
+{
+ unsigned short length;
+ unsigned char revision;
+ unsigned short *phy_param;
+ unsigned short address, value;
+
+ phy_param = &DefaultPhyParam[0];
+ length = *phy_param & 0x00FF;
+ revision = (unsigned char)((*phy_param) >> 8);
+ phy_param++;
+ while (length != 0) {
+ if (rev == revision) {
+ while (length > 1) {
+ address = *phy_param;
+ value = *(phy_param + 1);
+ phy_param += 2;
+ mdio_write(dev, phy_address, address, value);
+ length -= 4;
+ }
+ break;
+ } else {
+ phy_param += length / 2;
+ length = *phy_param & 0x00FF;
+ revision = (unsigned char)((*phy_param) >> 8);
+ phy_param++;
+ }
+ }
+}
+
+/* JES20040127EEPROM */
+static int read_eeprom(struct net_device *dev, int eep_addr)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ unsigned int i;
+ int ret = 0;
+ u16 value;
+
+ value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);
+ ipg_w16(value, EEPROM_CTRL);
+
+ for (i = 0; i < 1000; i++) {
+ u16 data;
+
+ mdelay(10);
+ data = ipg_r16(EEPROM_CTRL);
+ if (!(data & IPG_EC_EEPROM_BUSY)) {
+ ret = ipg_r16(EEPROM_DATA);
+ break;
+ }
+ }
+ return ret;
+}
+
+static void ipg_init_mii(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ struct mii_if_info *mii_if = &sp->mii_if;
+ int phyaddr;
+
+ mii_if->dev = dev;
+ mii_if->mdio_read = mdio_read;
+ mii_if->mdio_write = mdio_write;
+ mii_if->phy_id_mask = 0x1f;
+ mii_if->reg_num_mask = 0x1f;
+
+ mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);
+
+ if (phyaddr != 0x1f) {
+ u16 mii_phyctrl, mii_1000cr;
+ u8 revisionid = 0;
+
+ mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000);
+ mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |
+ GMII_PHY_1000BASETCONTROL_PreferMaster;
+ mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);
+
+ mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);
+
+ /* Set default phyparam */
+ pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);
+ ipg_set_phy_default_param(revisionid, dev, phyaddr);
+
+ /* Reset PHY */
+ mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;
+ mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);
+
+ }
+}
+
+static int ipg_hw_init(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+ int rc;
+
+ /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
+ /* Read LED Mode Configuration from EEPROM */
+ sp->LED_Mode = read_eeprom(dev, 6);
+
+ /* Reset all functions within the IPG. Do not assert
+ * RST_OUT as not compatible with some PHYs.
+ */
+ rc = ipg_reset(dev, IPG_RESET_MASK);
+ if (rc < 0)
+ goto out;
+
+ ipg_init_mii(dev);
+
+ /* Read MAC Address from EEPROM */
+ for (i = 0; i < 3; i++)
+ sp->station_addr[i] = read_eeprom(dev, 16 + i);
+
+ for (i = 0; i < 3; i++)
+ ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);
+
+ /* Set station address in ethernet_device structure. */
+ dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff;
+ dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;
+ dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff;
+ dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;
+ dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff;
+ dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;
+out:
+ return rc;
+}
+
+static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu)
+{
+ /* Function to accomodate changes to Maximum Transfer Unit
+ * (or MTU) of IPG NIC. Cannot use default function since
+ * the default will not allow for MTU > 1500 bytes.
+ */
+
+ IPG_DEBUG_MSG("_nic_change_mtu\n");
+
+ /* Check that the new MTU value is between 68 (14 byte header, 46
+ * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which
+ * corresponds to the MAXFRAMESIZE register in the IPG.
+ */
+ if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE))
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = mii_ethtool_gset(&sp->mii_if, cmd);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = mii_ethtool_sset(&sp->mii_if, cmd);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static int ipg_nway_reset(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = mii_nway_restart(&sp->mii_if);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static struct ethtool_ops ipg_ethtool_ops = {
+ .get_settings = ipg_get_settings,
+ .set_settings = ipg_set_settings,
+ .nway_reset = ipg_nway_reset,
+};
+
+static void ipg_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct ipg_nic_private *sp = netdev_priv(dev);
+
+ IPG_DEBUG_MSG("_remove\n");
+
+ /* Un-register Ethernet device. */
+ unregister_netdev(dev);
+
+ pci_iounmap(pdev, sp->ioaddr);
+
+ pci_release_regions(pdev);
+
+ free_netdev(dev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static int __devinit ipg_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned int i = id->driver_data;
+ struct ipg_nic_private *sp;
+ struct net_device *dev;
+ void __iomem *ioaddr;
+ int rc;
+
+ rc = pci_enable_device(pdev);
+ if (rc < 0)
+ goto out;
+
+ printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
+
+ pci_set_master(pdev);
+
+ rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+ if (rc < 0) {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc < 0) {
+ printk(KERN_ERR "%s: DMA config failed.\n",
+ pci_name(pdev));
+ goto err_disable_0;
+ }
+ }
+
+ /*
+ * Initialize net device.
+ */
+ dev = alloc_etherdev(sizeof(struct ipg_nic_private));
+ if (!dev) {
+ printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev));
+ rc = -ENOMEM;
+ goto err_disable_0;
+ }
+
+ sp = netdev_priv(dev);
+ spin_lock_init(&sp->lock);
+ mutex_init(&sp->mii_mutex);
+
+ /* Declare IPG NIC functions for Ethernet device methods.
+ */
+ dev->open = &ipg_nic_open;
+ dev->stop = &ipg_nic_stop;
+ dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
+ dev->get_stats = &ipg_nic_get_stats;
+ dev->set_multicast_list = &ipg_nic_set_multicast_list;
+ dev->do_ioctl = ipg_ioctl;
+ dev->tx_timeout = ipg_tx_timeout;
+ dev->change_mtu = &ipg_nic_change_mtu;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops);
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_free_dev_1;
+
+ ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
+ if (!ioaddr) {
+ printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev));
+ rc = -EIO;
+ goto err_release_regions_2;
+ }
+
+ /* Save the pointer to the PCI device information. */
+ sp->ioaddr = ioaddr;
+ sp->pdev = pdev;
+ sp->dev = dev;
+
+ INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);
+
+ pci_set_drvdata(pdev, dev);
+
+ rc = ipg_hw_init(dev);
+ if (rc < 0)
+ goto err_unmap_3;
+
+ rc = register_netdev(dev);
+ if (rc < 0)
+ goto err_unmap_3;
+
+ printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name);
+out:
+ return rc;
+
+err_unmap_3:
+ pci_iounmap(pdev, ioaddr);
+err_release_regions_2:
+ pci_release_regions(pdev);
+err_free_dev_1:
+ free_netdev(dev);
+err_disable_0:
+ pci_disable_device(pdev);
+ goto out;
+}
+
+static struct pci_driver ipg_pci_driver = {
+ .name = IPG_DRIVER_NAME,
+ .id_table = ipg_pci_tbl,
+ .probe = ipg_probe,
+ .remove = __devexit_p(ipg_remove),
+};
+
+static int __init ipg_init_module(void)
+{
+ return pci_register_driver(&ipg_pci_driver);
+}
+
+static void __exit ipg_exit_module(void)
+{
+ pci_unregister_driver(&ipg_pci_driver);
+}
+
+module_init(ipg_init_module);
+module_exit(ipg_exit_module);
diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h
new file mode 100644
index 000000000000..1952d0dfd314
--- /dev/null
+++ b/drivers/net/ipg.h
@@ -0,0 +1,856 @@
+/*
+ *
+ * ipg.h
+ *
+ * Include file for Gigabit Ethernet device driver for Network
+ * Interface Cards (NICs) utilizing the Tamarack Microelectronics
+ * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
+ * Controller.
+ *
+ * Craig Rich
+ * Sundance Technology, Inc.
+ * 1485 Saratoga Avenue
+ * Suite 200
+ * San Jose, CA 95129
+ * 408 873 4117
+ * www.sundanceti.com
+ * craig_rich@sundanceti.com
+ */
+#ifndef __LINUX_IPG_H
+#define __LINUX_IPG_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/version.h>
+#include <asm/bitops.h>
+/*#include <asm/spinlock.h>*/
+
+#define DrvVer "2.09d"
+
+#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb)
+
+/*
+ * Constants
+ */
+
+/* GMII based PHY IDs */
+#define NS 0x2000
+#define MARVELL 0x0141
+#define ICPLUS_PHY 0x243
+
+/* NIC Physical Layer Device MII register fields. */
+#define MII_PHY_SELECTOR_IEEE8023 0x0001
+#define MII_PHY_TECHABILITYFIELD 0x1FE0
+
+/* GMII_PHY_1000 need to set to prefer master */
+#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400
+
+/* NIC Physical Layer Device GMII constants. */
+#define GMII_PREAMBLE 0xFFFFFFFF
+#define GMII_ST 0x1
+#define GMII_READ 0x2
+#define GMII_WRITE 0x1
+#define GMII_TA_READ_MASK 0x1
+#define GMII_TA_WRITE 0x2
+
+/* I/O register offsets. */
+enum ipg_regs {
+ DMA_CTRL = 0x00,
+ RX_DMA_STATUS = 0x08, // Unused + reserved
+ TFD_LIST_PTR_0 = 0x10,
+ TFD_LIST_PTR_1 = 0x14,
+ TX_DMA_BURST_THRESH = 0x18,
+ TX_DMA_URGENT_THRESH = 0x19,
+ TX_DMA_POLL_PERIOD = 0x1a,
+ RFD_LIST_PTR_0 = 0x1c,
+ RFD_LIST_PTR_1 = 0x20,
+ RX_DMA_BURST_THRESH = 0x24,
+ RX_DMA_URGENT_THRESH = 0x25,
+ RX_DMA_POLL_PERIOD = 0x26,
+ DEBUG_CTRL = 0x2c,
+ ASIC_CTRL = 0x30,
+ FIFO_CTRL = 0x38, // Unused
+ FLOW_OFF_THRESH = 0x3c,
+ FLOW_ON_THRESH = 0x3e,
+ EEPROM_DATA = 0x48,
+ EEPROM_CTRL = 0x4a,
+ EXPROM_ADDR = 0x4c, // Unused
+ EXPROM_DATA = 0x50, // Unused
+ WAKE_EVENT = 0x51, // Unused
+ COUNTDOWN = 0x54, // Unused
+ INT_STATUS_ACK = 0x5a,
+ INT_ENABLE = 0x5c,
+ INT_STATUS = 0x5e, // Unused
+ TX_STATUS = 0x60,
+ MAC_CTRL = 0x6c,
+ VLAN_TAG = 0x70, // Unused
+ PHY_SET = 0x75, // JES20040127EEPROM
+ PHY_CTRL = 0x76,
+ STATION_ADDRESS_0 = 0x78,
+ STATION_ADDRESS_1 = 0x7a,
+ STATION_ADDRESS_2 = 0x7c,
+ MAX_FRAME_SIZE = 0x86,
+ RECEIVE_MODE = 0x88,
+ HASHTABLE_0 = 0x8c,
+ HASHTABLE_1 = 0x90,
+ RMON_STATISTICS_MASK = 0x98,
+ STATISTICS_MASK = 0x9c,
+ RX_JUMBO_FRAMES = 0xbc, // Unused
+ TCP_CHECKSUM_ERRORS = 0xc0, // Unused
+ IP_CHECKSUM_ERRORS = 0xc2, // Unused
+ UDP_CHECKSUM_ERRORS = 0xc4, // Unused
+ TX_JUMBO_FRAMES = 0xf4 // Unused
+};
+
+/* Ethernet MIB statistic register offsets. */
+#define IPG_OCTETRCVOK 0xA8
+#define IPG_MCSTOCTETRCVDOK 0xAC
+#define IPG_BCSTOCTETRCVOK 0xB0
+#define IPG_FRAMESRCVDOK 0xB4
+#define IPG_MCSTFRAMESRCVDOK 0xB8
+#define IPG_BCSTFRAMESRCVDOK 0xBE
+#define IPG_MACCONTROLFRAMESRCVD 0xC6
+#define IPG_FRAMETOOLONGERRRORS 0xC8
+#define IPG_INRANGELENGTHERRORS 0xCA
+#define IPG_FRAMECHECKSEQERRORS 0xCC
+#define IPG_FRAMESLOSTRXERRORS 0xCE
+#define IPG_OCTETXMTOK 0xD0
+#define IPG_MCSTOCTETXMTOK 0xD4
+#define IPG_BCSTOCTETXMTOK 0xD8
+#define IPG_FRAMESXMTDOK 0xDC
+#define IPG_MCSTFRAMESXMTDOK 0xE0
+#define IPG_FRAMESWDEFERREDXMT 0xE4
+#define IPG_LATECOLLISIONS 0xE8
+#define IPG_MULTICOLFRAMES 0xEC
+#define IPG_SINGLECOLFRAMES 0xF0
+#define IPG_BCSTFRAMESXMTDOK 0xF6
+#define IPG_CARRIERSENSEERRORS 0xF8
+#define IPG_MACCONTROLFRAMESXMTDOK 0xFA
+#define IPG_FRAMESABORTXSCOLLS 0xFC
+#define IPG_FRAMESWEXDEFERRAL 0xFE
+
+/* RMON statistic register offsets. */
+#define IPG_ETHERSTATSCOLLISIONS 0x100
+#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104
+#define IPG_ETHERSTATSPKTSTRANSMIT 0x108
+#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C
+#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110
+#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114
+#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118
+#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C
+#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120
+#define IPG_ETHERSTATSCRCALIGNERRORS 0x124
+#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128
+#define IPG_ETHERSTATSFRAGMENTS 0x12C
+#define IPG_ETHERSTATSJABBERS 0x130
+#define IPG_ETHERSTATSOCTETS 0x134
+#define IPG_ETHERSTATSPKTS 0x138
+#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C
+#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140
+#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144
+#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148
+#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C
+#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150
+
+/* RMON statistic register equivalents. */
+#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0
+#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6
+#define IPG_ETHERSTATSMULTICASTPKTS 0xB8
+#define IPG_ETHERSTATSBROADCASTPKTS 0xBE
+#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8
+#define IPG_ETHERSTATSDROPEVENTS 0xCE
+
+/* Serial EEPROM offsets */
+#define IPG_EEPROM_CONFIGPARAM 0x00
+#define IPG_EEPROM_ASICCTRL 0x01
+#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02
+#define IPG_EEPROM_SUBSYSTEMID 0x03
+#define IPG_EEPROM_STATIONADDRESS0 0x10
+#define IPG_EEPROM_STATIONADDRESS1 0x11
+#define IPG_EEPROM_STATIONADDRESS2 0x12
+
+/* Register & data structure bit masks */
+
+/* PCI register masks. */
+
+/* IOBaseAddress */
+#define IPG_PIB_RSVD_MASK 0xFFFFFE01
+#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00
+#define IPG_PIB_IOBASEADDRIND 0x00000001
+
+/* MemBaseAddress */
+#define IPG_PMB_RSVD_MASK 0xFFFFFE07
+#define IPG_PMB_MEMBASEADDRIND 0x00000001
+#define IPG_PMB_MEMMAPTYPE 0x00000006
+#define IPG_PMB_MEMMAPTYPE0 0x00000002
+#define IPG_PMB_MEMMAPTYPE1 0x00000004
+#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00
+
+/* ConfigStatus */
+#define IPG_CS_RSVD_MASK 0xFFB0
+#define IPG_CS_CAPABILITIES 0x0010
+#define IPG_CS_66MHZCAPABLE 0x0020
+#define IPG_CS_FASTBACK2BACK 0x0080
+#define IPG_CS_DATAPARITYREPORTED 0x0100
+#define IPG_CS_DEVSELTIMING 0x0600
+#define IPG_CS_SIGNALEDTARGETABORT 0x0800
+#define IPG_CS_RECEIVEDTARGETABORT 0x1000
+#define IPG_CS_RECEIVEDMASTERABORT 0x2000
+#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000
+#define IPG_CS_DETECTEDPARITYERROR 0x8000
+
+/* TFD data structure masks. */
+
+/* TFDList, TFC */
+#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFF
+#define IPG_TFC_FRAMEID 0x000000000000FFFF
+#define IPG_TFC_WORDALIGN 0x0000000000030000
+#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000
+#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000
+#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000
+#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000
+#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000
+#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000
+#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000
+#define IPG_TFC_TXINDICATE 0x0000000000400000
+#define IPG_TFC_TXDMAINDICATE 0x0000000000800000
+#define IPG_TFC_FRAGCOUNT 0x000000000F000000
+#define IPG_TFC_VLANTAGINSERT 0x0000000010000000
+#define IPG_TFC_TFDDONE 0x0000000080000000
+#define IPG_TFC_VID 0x00000FFF00000000
+#define IPG_TFC_CFI 0x0000100000000000
+#define IPG_TFC_USERPRIORITY 0x0000E00000000000
+
+/* TFDList, FragInfo */
+#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFF
+#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFF
+#define IPG_TFI_FRAGLEN 0xFFFF000000000000LL
+
+/* RFD data structure masks. */
+
+/* RFDList, RFS */
+#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFF
+#define IPG_RFS_RXFRAMELEN 0x000000000000FFFF
+#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000
+#define IPG_RFS_RXRUNTFRAME 0x0000000000020000
+#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000
+#define IPG_RFS_RXFCSERROR 0x0000000000080000
+#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000
+#define IPG_RFS_RXLENGTHERROR 0x0000000000200000
+#define IPG_RFS_VLANDETECTED 0x0000000000400000
+#define IPG_RFS_TCPDETECTED 0x0000000000800000
+#define IPG_RFS_TCPERROR 0x0000000001000000
+#define IPG_RFS_UDPDETECTED 0x0000000002000000
+#define IPG_RFS_UDPERROR 0x0000000004000000
+#define IPG_RFS_IPDETECTED 0x0000000008000000
+#define IPG_RFS_IPERROR 0x0000000010000000
+#define IPG_RFS_FRAMESTART 0x0000000020000000
+#define IPG_RFS_FRAMEEND 0x0000000040000000
+#define IPG_RFS_RFDDONE 0x0000000080000000
+#define IPG_RFS_TCI 0x0000FFFF00000000
+
+/* RFDList, FragInfo */
+#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFF
+#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFF
+#define IPG_RFI_FRAGLEN 0xFFFF000000000000LL
+
+/* I/O Register masks. */
+
+/* RMON Statistics Mask */
+#define IPG_RZ_ALL 0x0FFFFFFF
+
+/* Statistics Mask */
+#define IPG_SM_ALL 0x0FFFFFFF
+#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001
+#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002
+#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004
+#define IPG_SM_RXJUMBOFRAMES 0x00000008
+#define IPG_SM_TCPCHECKSUMERRORS 0x00000010
+#define IPG_SM_IPCHECKSUMERRORS 0x00000020
+#define IPG_SM_UDPCHECKSUMERRORS 0x00000040
+#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080
+#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100
+#define IPG_SM_INRANGELENGTHERRORS 0x00000200
+#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400
+#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800
+#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000
+#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000
+#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000
+#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000
+#define IPG_SM_LATECOLLISIONS 0x00010000
+#define IPG_SM_MULTICOLFRAMES 0x00020000
+#define IPG_SM_SINGLECOLFRAMES 0x00040000
+#define IPG_SM_TXJUMBOFRAMES 0x00080000
+#define IPG_SM_CARRIERSENSEERRORS 0x00100000
+#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000
+#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000
+#define IPG_SM_FRAMESWEXDEFERAL 0x00800000
+
+/* Countdown */
+#define IPG_CD_RSVD_MASK 0x0700FFFF
+#define IPG_CD_COUNT 0x0000FFFF
+#define IPG_CD_COUNTDOWNSPEED 0x01000000
+#define IPG_CD_COUNTDOWNMODE 0x02000000
+#define IPG_CD_COUNTINTENABLED 0x04000000
+
+/* TxDMABurstThresh */
+#define IPG_TB_RSVD_MASK 0xFF
+
+/* TxDMAUrgentThresh */
+#define IPG_TU_RSVD_MASK 0xFF
+
+/* TxDMAPollPeriod */
+#define IPG_TP_RSVD_MASK 0xFF
+
+/* RxDMAUrgentThresh */
+#define IPG_RU_RSVD_MASK 0xFF
+
+/* RxDMAPollPeriod */
+#define IPG_RP_RSVD_MASK 0xFF
+
+/* ReceiveMode */
+#define IPG_RM_RSVD_MASK 0x3F
+#define IPG_RM_RECEIVEUNICAST 0x01
+#define IPG_RM_RECEIVEMULTICAST 0x02
+#define IPG_RM_RECEIVEBROADCAST 0x04
+#define IPG_RM_RECEIVEALLFRAMES 0x08
+#define IPG_RM_RECEIVEMULTICASTHASH 0x10
+#define IPG_RM_RECEIVEIPMULTICAST 0x20
+
+/* PhySet JES20040127EEPROM*/
+#define IPG_PS_MEM_LENB9B 0x01
+#define IPG_PS_MEM_LEN9 0x02
+#define IPG_PS_NON_COMPDET 0x04
+
+/* PhyCtrl */
+#define IPG_PC_RSVD_MASK 0xFF
+#define IPG_PC_MGMTCLK_LO 0x00
+#define IPG_PC_MGMTCLK_HI 0x01
+#define IPG_PC_MGMTCLK 0x01
+#define IPG_PC_MGMTDATA 0x02
+#define IPG_PC_MGMTDIR 0x04
+#define IPG_PC_DUPLEX_POLARITY 0x08
+#define IPG_PC_DUPLEX_STATUS 0x10
+#define IPG_PC_LINK_POLARITY 0x20
+#define IPG_PC_LINK_SPEED 0xC0
+#define IPG_PC_LINK_SPEED_10MBPS 0x40
+#define IPG_PC_LINK_SPEED_100MBPS 0x80
+#define IPG_PC_LINK_SPEED_1000MBPS 0xC0
+
+/* DMACtrl */
+#define IPG_DC_RSVD_MASK 0xC07D9818
+#define IPG_DC_RX_DMA_COMPLETE 0x00000008
+#define IPG_DC_RX_DMA_POLL_NOW 0x00000010
+#define IPG_DC_TX_DMA_COMPLETE 0x00000800
+#define IPG_DC_TX_DMA_POLL_NOW 0x00001000
+#define IPG_DC_TX_DMA_IN_PROG 0x00008000
+#define IPG_DC_RX_EARLY_DISABLE 0x00010000
+#define IPG_DC_MWI_DISABLE 0x00040000
+#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000
+#define IPG_DC_TX_BURST_LIMIT 0x00700000
+#define IPG_DC_TARGET_ABORT 0x40000000
+#define IPG_DC_MASTER_ABORT 0x80000000
+
+/* ASICCtrl */
+#define IPG_AC_RSVD_MASK 0x07FFEFF2
+#define IPG_AC_EXP_ROM_SIZE 0x00000002
+#define IPG_AC_PHY_SPEED10 0x00000010
+#define IPG_AC_PHY_SPEED100 0x00000020
+#define IPG_AC_PHY_SPEED1000 0x00000040
+#define IPG_AC_PHY_MEDIA 0x00000080
+#define IPG_AC_FORCED_CFG 0x00000700
+#define IPG_AC_D3RESETDISABLE 0x00000800
+#define IPG_AC_SPEED_UP_MODE 0x00002000
+#define IPG_AC_LED_MODE 0x00004000
+#define IPG_AC_RST_OUT_POLARITY 0x00008000
+#define IPG_AC_GLOBAL_RESET 0x00010000
+#define IPG_AC_RX_RESET 0x00020000
+#define IPG_AC_TX_RESET 0x00040000
+#define IPG_AC_DMA 0x00080000
+#define IPG_AC_FIFO 0x00100000
+#define IPG_AC_NETWORK 0x00200000
+#define IPG_AC_HOST 0x00400000
+#define IPG_AC_AUTO_INIT 0x00800000
+#define IPG_AC_RST_OUT 0x01000000
+#define IPG_AC_INT_REQUEST 0x02000000
+#define IPG_AC_RESET_BUSY 0x04000000
+#define IPG_AC_LED_SPEED 0x08000000 //JES20040127EEPROM
+#define IPG_AC_LED_MODE_BIT_1 0x20000000 //JES20040127EEPROM
+
+/* EepromCtrl */
+#define IPG_EC_RSVD_MASK 0x83FF
+#define IPG_EC_EEPROM_ADDR 0x00FF
+#define IPG_EC_EEPROM_OPCODE 0x0300
+#define IPG_EC_EEPROM_SUBCOMMAD 0x0000
+#define IPG_EC_EEPROM_WRITEOPCODE 0x0100
+#define IPG_EC_EEPROM_READOPCODE 0x0200
+#define IPG_EC_EEPROM_ERASEOPCODE 0x0300
+#define IPG_EC_EEPROM_BUSY 0x8000
+
+/* FIFOCtrl */
+#define IPG_FC_RSVD_MASK 0xC001
+#define IPG_FC_RAM_TEST_MODE 0x0001
+#define IPG_FC_TRANSMITTING 0x4000
+#define IPG_FC_RECEIVING 0x8000
+
+/* TxStatus */
+#define IPG_TS_RSVD_MASK 0xFFFF00DD
+#define IPG_TS_TX_ERROR 0x00000001
+#define IPG_TS_LATE_COLLISION 0x00000004
+#define IPG_TS_TX_MAX_COLL 0x00000008
+#define IPG_TS_TX_UNDERRUN 0x00000010
+#define IPG_TS_TX_IND_REQD 0x00000040
+#define IPG_TS_TX_COMPLETE 0x00000080
+#define IPG_TS_TX_FRAMEID 0xFFFF0000
+
+/* WakeEvent */
+#define IPG_WE_WAKE_PKT_ENABLE 0x01
+#define IPG_WE_MAGIC_PKT_ENABLE 0x02
+#define IPG_WE_LINK_EVT_ENABLE 0x04
+#define IPG_WE_WAKE_POLARITY 0x08
+#define IPG_WE_WAKE_PKT_EVT 0x10
+#define IPG_WE_MAGIC_PKT_EVT 0x20
+#define IPG_WE_LINK_EVT 0x40
+#define IPG_WE_WOL_ENABLE 0x80
+
+/* IntEnable */
+#define IPG_IE_RSVD_MASK 0x1FFE
+#define IPG_IE_HOST_ERROR 0x0002
+#define IPG_IE_TX_COMPLETE 0x0004
+#define IPG_IE_MAC_CTRL_FRAME 0x0008
+#define IPG_IE_RX_COMPLETE 0x0010
+#define IPG_IE_RX_EARLY 0x0020
+#define IPG_IE_INT_REQUESTED 0x0040
+#define IPG_IE_UPDATE_STATS 0x0080
+#define IPG_IE_LINK_EVENT 0x0100
+#define IPG_IE_TX_DMA_COMPLETE 0x0200
+#define IPG_IE_RX_DMA_COMPLETE 0x0400
+#define IPG_IE_RFD_LIST_END 0x0800
+#define IPG_IE_RX_DMA_PRIORITY 0x1000
+
+/* IntStatus */
+#define IPG_IS_RSVD_MASK 0x1FFF
+#define IPG_IS_INTERRUPT_STATUS 0x0001
+#define IPG_IS_HOST_ERROR 0x0002
+#define IPG_IS_TX_COMPLETE 0x0004
+#define IPG_IS_MAC_CTRL_FRAME 0x0008
+#define IPG_IS_RX_COMPLETE 0x0010
+#define IPG_IS_RX_EARLY 0x0020
+#define IPG_IS_INT_REQUESTED 0x0040
+#define IPG_IS_UPDATE_STATS 0x0080
+#define IPG_IS_LINK_EVENT 0x0100
+#define IPG_IS_TX_DMA_COMPLETE 0x0200
+#define IPG_IS_RX_DMA_COMPLETE 0x0400
+#define IPG_IS_RFD_LIST_END 0x0800
+#define IPG_IS_RX_DMA_PRIORITY 0x1000
+
+/* MACCtrl */
+#define IPG_MC_RSVD_MASK 0x7FE33FA3
+#define IPG_MC_IFS_SELECT 0x00000003
+#define IPG_MC_IFS_4352BIT 0x00000003
+#define IPG_MC_IFS_1792BIT 0x00000002
+#define IPG_MC_IFS_1024BIT 0x00000001
+#define IPG_MC_IFS_96BIT 0x00000000
+#define IPG_MC_DUPLEX_SELECT 0x00000020
+#define IPG_MC_DUPLEX_SELECT_FD 0x00000020
+#define IPG_MC_DUPLEX_SELECT_HD 0x00000000
+#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080
+#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100
+#define IPG_MC_RCV_FCS 0x00000200
+#define IPG_MC_FIFO_LOOPBACK 0x00000400
+#define IPG_MC_MAC_LOOPBACK 0x00000800
+#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000
+#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000
+#define IPG_MC_COLLISION_DETECT 0x00010000
+#define IPG_MC_CARRIER_SENSE 0x00020000
+#define IPG_MC_STATISTICS_ENABLE 0x00200000
+#define IPG_MC_STATISTICS_DISABLE 0x00400000
+#define IPG_MC_STATISTICS_ENABLED 0x00800000
+#define IPG_MC_TX_ENABLE 0x01000000
+#define IPG_MC_TX_DISABLE 0x02000000
+#define IPG_MC_TX_ENABLED 0x04000000
+#define IPG_MC_RX_ENABLE 0x08000000
+#define IPG_MC_RX_DISABLE 0x10000000
+#define IPG_MC_RX_ENABLED 0x20000000
+#define IPG_MC_PAUSED 0x40000000
+
+/*
+ * Tune
+ */
+
+/* Miscellaneous Constants. */
+#define TRUE 1
+#define FALSE 0
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
+#define IPG_APPEND_FCS_ON_TX TRUE
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
+#define IPG_STRIP_FCS_ON_RX TRUE
+
+/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
+ * Ethernet errors.
+ */
+#define IPG_DROP_ON_RX_ETH_ERRORS TRUE
+
+/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
+ * (via TFC).
+ */
+#define IPG_INSERT_MANUAL_VLAN_TAG FALSE
+
+/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
+#define IPG_ADD_IPCHECKSUM_ON_TX FALSE
+
+/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define IPG_ADD_TCPCHECKSUM_ON_TX FALSE
+
+/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define IPG_ADD_UDPCHECKSUM_ON_TX FALSE
+
+/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
+ * constants as desired.
+ */
+#define IPG_MANUAL_VLAN_VID 0xABC
+#define IPG_MANUAL_VLAN_CFI 0x1
+#define IPG_MANUAL_VLAN_USERPRIORITY 0x5
+
+#define IPG_IO_REG_RANGE 0xFF
+#define IPG_MEM_REG_RANGE 0x154
+#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet"
+#define IPG_NIC_PHY_ADDRESS 0x01
+#define IPG_DMALIST_ALIGN_PAD 0x07
+#define IPG_MULTICAST_HASHTABLE_SIZE 0x40
+
+/* Number of miliseconds to wait after issuing a software reset.
+ * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
+ */
+#define IPG_AC_RESETWAIT 0x05
+
+/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */
+#define IPG_AC_RESET_TIMEOUT 0x0A
+
+/* Minimum number of nanoseconds used to toggle MDC clock during
+ * MII/GMII register access.
+ */
+#define IPG_PC_PHYCTRLWAIT_NS 200
+
+#define IPG_TFDLIST_LENGTH 0x100
+
+/* Number of frames between TxDMAComplete interrupt.
+ * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH
+ */
+#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1
+
+#ifdef JUMBO_FRAME
+
+# ifdef JUMBO_FRAME_SIZE_2K
+# define JUMBO_FRAME_SIZE 2048
+# define __IPG_RXFRAG_SIZE 2048
+# else
+# ifdef JUMBO_FRAME_SIZE_3K
+# define JUMBO_FRAME_SIZE 3072
+# define __IPG_RXFRAG_SIZE 3072
+# else
+# ifdef JUMBO_FRAME_SIZE_4K
+# define JUMBO_FRAME_SIZE 4096
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_5K
+# define JUMBO_FRAME_SIZE 5120
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_6K
+# define JUMBO_FRAME_SIZE 6144
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_7K
+# define JUMBO_FRAME_SIZE 7168
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_8K
+# define JUMBO_FRAME_SIZE 8192
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_9K
+# define JUMBO_FRAME_SIZE 9216
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_10K
+# define JUMBO_FRAME_SIZE 10240
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# define JUMBO_FRAME_SIZE 4096
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash
+#define IPG_TXFRAG_SIZE JUMBO_FRAME_SIZE
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//4088=4096-8
+#define IPG_RXFRAG_SIZE __IPG_RXFRAG_SIZE
+#define IPG_RXSUPPORT_SIZE IPG_MAX_RXFRAME_SIZE
+#else
+#define IPG_RXFRAG_SIZE 0x0600
+#define IPG_RXSUPPORT_SIZE IPG_RXFRAG_SIZE
+#endif
+
+/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */
+#ifdef JUMBO_FRAME
+#define IPG_MAX_RXFRAME_SIZE JUMBO_FRAME_SIZE
+#else
+#define IPG_MAX_RXFRAME_SIZE 0x0600
+#endif
+
+#define IPG_RFDLIST_LENGTH 0x100
+
+/* Maximum number of RFDs to process per interrupt.
+ * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH
+ */
+#define IPG_MAXRFDPROCESS_COUNT 0x80
+
+/* Minimum margin between last freed RFD, and current RFD.
+ * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH
+ */
+#define IPG_MINUSEDRFDSTOFREE 0x80
+
+/* specify the jumbo frame maximum size
+ * per unit is 0x600 (the RxBuffer size that one RFD can carry)
+ */
+#define MAX_JUMBOSIZE 0x8 // max is 12K
+
+/* Key register values loaded at driver start up. */
+
+/* TXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value Time
+ * ---------------------
+ * 0x00-0x01 320ns
+ * 0x03 ~1us
+ * 0x1F ~10us
+ * 0xFF ~82us
+ */
+#define IPG_TXDMAPOLLPERIOD_VALUE 0x26
+
+/* TxDMAUrgentThresh specifies the minimum amount of
+ * data in the transmit FIFO before asserting an
+ * urgent transmit DMA request.
+ *
+ * Value Min TxFIFO occupied space before urgent TX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04 128 bytes (1024 bits)
+ * 0x27 1248 bytes (~10000 bits)
+ * 0x30 1536 bytes (12288 bits)
+ * 0xFF 8192 bytes (65535 bits)
+ */
+#define IPG_TXDMAURGENTTHRESH_VALUE 0x04
+
+/* TxDMABurstThresh specifies the minimum amount of
+ * free space in the transmit FIFO before asserting an
+ * transmit DMA request.
+ *
+ * Value Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08 256 bytes
+ * 0x30 1536 bytes
+ * 0xFF 8192 bytes
+ */
+#define IPG_TXDMABURSTTHRESH_VALUE 0x30
+
+/* RXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value Time
+ * ---------------------
+ * 0x00-0x01 320ns
+ * 0x03 ~1us
+ * 0x1F ~10us
+ * 0xFF ~82us
+ */
+#define IPG_RXDMAPOLLPERIOD_VALUE 0x01
+
+/* RxDMAUrgentThresh specifies the minimum amount of
+ * free space within the receive FIFO before asserting
+ * a urgent receive DMA request.
+ *
+ * Value Min RxFIFO free space before urgent RX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04 128 bytes (1024 bits)
+ * 0x27 1248 bytes (~10000 bits)
+ * 0x30 1536 bytes (12288 bits)
+ * 0xFF 8192 bytes (65535 bits)
+ */
+#define IPG_RXDMAURGENTTHRESH_VALUE 0x30
+
+/* RxDMABurstThresh specifies the minimum amount of
+ * occupied space within the receive FIFO before asserting
+ * a receive DMA request.
+ *
+ * Value Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08 256 bytes
+ * 0x30 1536 bytes
+ * 0xFF 8192 bytes
+ */
+#define IPG_RXDMABURSTTHRESH_VALUE 0x30
+
+/* FlowOnThresh specifies the maximum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * maximum pause time transmitted.
+ *
+ * Value Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000 0 bytes
+ * 0x0740 29,696 bytes
+ * 0x07FF 32,752 bytes
+ */
+#define IPG_FLOWONTHRESH_VALUE 0x0740
+
+/* FlowOffThresh specifies the minimum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * zero pause time is transmitted.
+ *
+ * Value Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000 0 bytes
+ * 0x00BF 3056 bytes
+ * 0x07FF 32,752 bytes
+ */
+#define IPG_FLOWOFFTHRESH_VALUE 0x00BF
+
+/*
+ * Miscellaneous macros.
+ */
+
+/* Marco for printing debug statements.
+# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */
+#ifdef IPG_DEBUG
+# define IPG_DEBUG_MSG(args...)
+# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args)
+# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
+# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
+#else
+# define IPG_DEBUG_MSG(args...)
+# define IPG_DDEBUG_MSG(args...)
+# define IPG_DUMPRFDLIST(args)
+# define IPG_DUMPTFDLIST(args)
+#endif
+
+/*
+ * End miscellaneous macros.
+ */
+
+/* Transmit Frame Descriptor. The IPG supports 15 fragments,
+ * however Linux requires only a single fragment. Note, each
+ * TFD field is 64 bits wide.
+ */
+struct ipg_tx {
+ u64 next_desc;
+ u64 tfc;
+ u64 frag_info;
+};
+
+/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
+ */
+struct ipg_rx {
+ u64 next_desc;
+ u64 rfs;
+ u64 frag_info;
+};
+
+struct SJumbo {
+ int FoundStart;
+ int CurrentSize;
+ struct sk_buff *skb;
+};
+/* Structure of IPG NIC specific data. */
+struct ipg_nic_private {
+ void __iomem *ioaddr;
+ struct ipg_tx *txd;
+ struct ipg_rx *rxd;
+ dma_addr_t txd_map;
+ dma_addr_t rxd_map;
+ struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH];
+ struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH];
+ unsigned int tx_current;
+ unsigned int tx_dirty;
+ unsigned int rx_current;
+ unsigned int rx_dirty;
+// Add by Grace 2005/05/19
+#ifdef JUMBO_FRAME
+ struct SJumbo Jumbo;
+#endif
+ unsigned int rx_buf_sz;
+ struct pci_dev *pdev;
+ struct net_device *dev;
+ struct net_device_stats stats;
+ spinlock_t lock;
+ int tenmbpsmode;
+
+ /*Jesse20040128EEPROM_VALUE */
+ u16 LED_Mode;
+ u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */
+
+ struct mutex mii_mutex;
+ struct mii_if_info mii_if;
+ int ResetCurrentTFD;
+#ifdef IPG_DEBUG
+ int RFDlistendCount;
+ int RFDListCheckedCount;
+ int EmptyRFDListCount;
+#endif
+ struct delayed_work task;
+};
+
+//variable record -- index by leading revision/length
+//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
+unsigned short DefaultPhyParam[] = {
+ // 11/12/03 IP1000A v1-3 rev=0x40
+ /*--------------------------------------------------------------------------
+ (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
+ 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
+ 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700,
+ --------------------------------------------------------------------------*/
+ // 12/17/03 IP1000A v1-4 rev=0x40
+ (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+ 0x0000,
+ 30, 0x005e, 9, 0x0700,
+ // 01/09/04 IP1000A v1-5 rev=0x41
+ (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+ 0x0000,
+ 30, 0x005e, 9, 0x0700,
+ 0x0000
+};
+
+#endif /* __LINUX_IPG_H */
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 829da9a1d113..65806956728a 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -155,6 +155,41 @@ config KINGSUN_DONGLE
To compile it as a module, choose M here: the module will be called
kingsun-sir.
+config EP7211_DONGLE
+ tristate "EP7211 I/R support"
+ depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+ help
+ Say Y here if you want to build support for the Cirrus logic
+ EP7211 chipset's infrared module.
+
+config KSDAZZLE_DONGLE
+ tristate "KingSun Dazzle IrDA-USB dongle (EXPERIMENTAL)"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the KingSun Dazzle
+ IrDA-USB bridge device driver.
+
+ This USB bridge does not conform to the IrDA-USB device class
+ specification, and therefore needs its own specific driver. This
+ dongle supports SIR speeds only (9600 through 115200 bps).
+
+ To compile it as a module, choose M here: the module will be called
+ ksdazzle-sir.
+
+config KS959_DONGLE
+ tristate "KingSun KS-959 IrDA-USB dongle (EXPERIMENTAL)"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the KingSun KS-959
+ IrDA-USB bridge device driver.
+
+ This USB bridge does not conform to the IrDA-USB device class
+ specification, and therefore needs its own specific driver. This
+ dongle supports SIR speeds only (9600 through 57600 bps).
+
+ To compile it as a module, choose M here: the module will be called
+ ks959-sir.
+
comment "Old SIR device drivers"
config IRPORT_SIR
@@ -355,7 +390,7 @@ config WINBOND_FIR
config TOSHIBA_FIR
tristate "Toshiba Type-O IR Port"
- depends on IRDA && PCI && !64BIT
+ depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
help
Say Y here if you want to build support for the Toshiba Type-O IR
and Donau oboe chipsets. These chipsets are used by the Toshiba
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 233a2f923730..fefbb5909081 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -45,7 +45,10 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
+obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
+obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o
+obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c
index 9715ab5572e9..ccf6ec548a64 100644
--- a/drivers/net/irda/actisys-sir.c
+++ b/drivers/net/irda/actisys-sir.c
@@ -67,7 +67,7 @@ static int actisys_reset(struct sir_dev *);
/* Note : the 220L doesn't support 38400, but we will fix that below */
static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
-#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0]))
+#define MAX_SPEEDS ARRAY_SIZE(baud_rates)
static struct dongle_driver act220l = {
.owner = THIS_MODULE,
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index f9c889c0dd07..9f584521304a 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -360,10 +360,6 @@ static int ali_ircc_open(int i, chipio_t *info)
self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
self->tx_fifo.tail = self->tx_buff.head;
-
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
-
/* Override the network functions we need to use */
dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
dev->open = ali_ircc_net_open;
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 3ca47bf6dfec..3e5eca1aa987 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1660,7 +1660,6 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
}
#endif
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pci_dev->dev);
dev->hard_start_xmit = toshoboe_hard_xmit;
dev->open = toshoboe_net_open;
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
new file mode 100644
index 000000000000..831572429bb9
--- /dev/null
+++ b/drivers/net/irda/ep7211-sir.c
@@ -0,0 +1,89 @@
+/*
+ * IR port driver for the Cirrus Logic EP7211 processor.
+ *
+ * Copyright 2001, Blue Mug Inc. All rights reserved.
+ * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "sir-dev.h"
+
+#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000 /* 1 ms */
+
+static int ep7211_open(struct sir_dev *dev);
+static int ep7211_close(struct sir_dev *dev);
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed);
+static int ep7211_reset(struct sir_dev *dev);
+
+static struct dongle_driver ep7211 = {
+ .owner = THIS_MODULE,
+ .driver_name = "EP7211 IR driver",
+ .type = IRDA_EP7211_DONGLE,
+ .open = ep7211_open,
+ .close = ep7211_close,
+ .reset = ep7211_reset,
+ .set_speed = ep7211_change_speed,
+};
+
+static int __init ep7211_sir_init(void)
+{
+ return irda_register_dongle(&ep7211);
+}
+
+static void __exit ep7211_sir_cleanup(void)
+{
+ irda_unregister_dongle(&ep7211);
+}
+
+static int ep7211_open(struct sir_dev *dev)
+{
+ unsigned int syscon;
+
+ /* Turn on the SIR encoder. */
+ syscon = clps_readl(SYSCON1);
+ syscon |= SYSCON1_SIREN;
+ clps_writel(syscon, SYSCON1);
+
+ return 0;
+}
+
+static int ep7211_close(struct sir_dev *dev)
+{
+ unsigned int syscon;
+
+ /* Turn off the SIR encoder. */
+ syscon = clps_readl(SYSCON1);
+ syscon &= ~SYSCON1_SIREN;
+ clps_writel(syscon, SYSCON1);
+
+ return 0;
+}
+
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed)
+{
+ return 0;
+}
+
+static int ep7211_reset(struct sir_dev *dev)
+{
+ return 0;
+}
+
+MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
+MODULE_DESCRIPTION("EP7211 IR dongle driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
+
+module_init(ep7211_sir_init);
+module_exit(ep7211_sir_cleanup);
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 0ac240ca905b..c6355c00fd7a 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1561,10 +1561,9 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interf
struct irda_class_desc *desc;
int ret;
- desc = kmalloc(sizeof (*desc), GFP_KERNEL);
- if (desc == NULL)
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
return NULL;
- memset(desc, 0, sizeof(*desc));
/* USB-IrDA class spec 1.0:
* 6.1.3: Standard "Get Descriptor" Device Request is not
@@ -1617,7 +1616,7 @@ static int irda_usb_probe(struct usb_interface *intf,
{
struct net_device *net;
struct usb_device *dev = interface_to_usbdev(intf);
- struct irda_usb_cb *self = NULL;
+ struct irda_usb_cb *self;
struct usb_host_interface *interface;
struct irda_class_desc *irda_desc;
int ret = -ENOMEM;
@@ -1636,7 +1635,6 @@ static int irda_usb_probe(struct usb_interface *intf,
if (!net)
goto err_out;
- SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
self = net->priv;
self->netdev = net;
@@ -1655,7 +1653,7 @@ static int irda_usb_probe(struct usb_interface *intf,
self->header_length = USB_IRDA_HEADER;
}
- self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *),
+ self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *),
GFP_KERNEL);
for (i = 0; i < self->max_rx_urb; i++) {
@@ -1715,7 +1713,7 @@ static int irda_usb_probe(struct usb_interface *intf,
/* Find IrDA class descriptor */
irda_desc = irda_usb_find_class_desc(intf);
ret = -ENODEV;
- if (irda_desc == NULL)
+ if (!irda_desc)
goto err_out_3;
if (self->needspatch) {
@@ -1738,15 +1736,13 @@ static int irda_usb_probe(struct usb_interface *intf,
/* Don't change this buffer size and allocation without doing
* some heavy and complete testing. Don't ask why :-(
* Jean II */
- self->speed_buff = kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
- if (self->speed_buff == NULL)
+ self->speed_buff = kzalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
+ if (!self->speed_buff)
goto err_out_3;
- memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);
-
self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length,
GFP_KERNEL);
- if (self->tx_buff == NULL)
+ if (!self->tx_buff)
goto err_out_4;
ret = irda_usb_open(self);
@@ -1767,12 +1763,11 @@ static int irda_usb_probe(struct usb_interface *intf,
/* replace IrDA class descriptor with what patched device is now reporting */
irda_desc = irda_usb_find_class_desc (self->usbintf);
- if (irda_desc == NULL) {
+ if (!irda_desc) {
ret = -ENODEV;
goto err_out_6;
}
- if (self->irda_desc)
- kfree (self->irda_desc);
+ kfree(self->irda_desc);
self->irda_desc = irda_desc;
irda_usb_init_qos(self);
}
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 3078c419cb02..c79caa5d3d71 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -164,20 +164,17 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
/* Allocate memory if needed */
if (self->tx_buff.truesize > 0) {
- self->tx_buff.head = kmalloc(self->tx_buff.truesize,
+ self->tx_buff.head = kzalloc(self->tx_buff.truesize,
GFP_KERNEL);
if (self->tx_buff.head == NULL) {
IRDA_ERROR("%s(), can't allocate memory for "
"transmit buffer!\n", __FUNCTION__);
goto err_out4;
}
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
}
self->tx_buff.data = self->tx_buff.head;
self->netdev = dev;
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
/* May be overridden by piggyback drivers */
self->interrupt = irport_interrupt;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index ad1857364d51..6f5f697ec9f8 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -505,10 +505,9 @@ static int irtty_open(struct tty_struct *tty)
}
/* allocate private device info block */
- priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
goto out_put;
- memset(priv, 0, sizeof(*priv));
priv->magic = IRTTY_MAGIC;
priv->tty = tty;
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index bdd5c979bead..648e54b3f00e 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -66,7 +66,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/device.h>
@@ -488,7 +487,6 @@ static int kingsun_probe(struct usb_interface *intf,
if(!net)
goto err_out1;
- SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
kingsun = netdev_priv(net);
kingsun->irlap = NULL;
@@ -509,12 +507,12 @@ static int kingsun_probe(struct usb_interface *intf,
spin_lock_init(&kingsun->lock);
/* Allocate input buffer */
- kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
+ kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL);
if (!kingsun->in_buf)
goto free_mem;
/* Allocate output buffer */
- kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
+ kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
if (!kingsun->out_buf)
goto free_mem;
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
new file mode 100644
index 000000000000..8c257a51341a
--- /dev/null
+++ b/drivers/net/irda/ks959-sir.c
@@ -0,0 +1,938 @@
+/*****************************************************************************
+*
+* Filename: ks959-sir.c
+* Version: 0.1.2
+* Description: Irda KingSun KS-959 USB Dongle
+* Status: Experimental
+* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
+* with help from Domen Puncer <domen@coderock.org>
+*
+* Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-17) understanding of how the Kingsun
+ * KS-959 dongle is supposed to work. This information was deduced by
+ * reverse-engineering and examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
+ * invaluable help in cracking the obfuscation and padding required for this
+ * dongle.
+ *
+ * General: This dongle exposes one interface with one interrupt IN endpoint.
+ * However, the interrupt endpoint is NOT used at all for this dongle. Instead,
+ * this dongle uses control transfers for everything, including sending and
+ * receiving the IrDA frame data. Apparently the interrupt endpoint is just a
+ * dummy to ensure the dongle has a valid interface to present to the PC.And I
+ * thought the DonShine dongle was weird... In addition, this dongle uses
+ * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent
+ * and received, from the dongle. I call it obfuscation because the XOR keying
+ * and padding required to produce an USB traffic acceptable for the dongle can
+ * not be explained by any other technical requirement.
+ *
+ * Transmission: To transmit an IrDA frame, the driver must prepare a control
+ * URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue <length of valid data before padding, little endian>
+ * wIndex 0x0000
+ * wLength <length of padded data>
+ * The payload packet must be manually wrapped and escaped (as in stir4200.c),
+ * then padded and obfuscated before being sent. Both padding and obfuscation
+ * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
+ * designer/programmer of the dongle used his name as a source for the
+ * obfuscation. WTF?!
+ * Apparently the dongle cannot handle payloads larger than 256 bytes. The
+ * driver has to perform fragmentation in order to send anything larger than
+ * this limit.
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with control URBs and the following as a setup packet:
+ * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x01
+ * wValue 0x0200
+ * wIndex 0x0000
+ * wLength 0x0800 (size of available buffer)
+ * If there is data to be read, it will be returned as the response payload.
+ * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
+ * it, the driver must XOR every byte, in sequence, with a value that starts at
+ * 1 and is incremented with each byte processed, and then with 0x55. The value
+ * incremented with each byte processed overflows as an unsigned char. The
+ * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped
+ * as in stir4200.c The incremented value is NOT reset with each frame, but is
+ * kept across the entire session with the dongle. Also, the dongle inserts an
+ * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
+ * must be skipped.
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue 0x0200
+ * wIndex 0x0001
+ * wLength 0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ * __u32 baudSpeed;
+ * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
+ * unsigned int : 1;
+ * unsigned int stopBits : 1;
+ * unsigned int parityEnable : 1;
+ * unsigned int parityType : 1;
+ * unsigned int : 1;
+ * unsigned int reset : 1;
+ * unsigned char reserved[3]; // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 57600 bps. Although the
+ * package announces support for up to 4MBps, tests with a Sony Ericcson K300
+ * phone show corruption when receiving large frames at 115200 bps, the highest
+ * speed announced by the phone. However, transmission at 115200 bps is OK. Go
+ * figure. Since I don't know whether the phone or the dongle is at fault, max
+ * announced speed is 57600 bps until someone produces a device that can run
+ * at higher speeds with this dongle.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KS959_VENDOR_ID 0x07d0
+#define KS959_PRODUCT_ID 0x4959
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+ /* KingSun Co,Ltd IrDA/USB Bridge */
+ {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */
+#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
+#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */
+
+struct ks959_speedparams {
+ __le32 baudrate; /* baud rate, little endian */
+ __u8 flags;
+ __u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE 0x00
+#define KS_PAR_EVEN 0x10
+#define KS_PAR_ODD 0x30
+#define KS_RESET 0x80
+
+struct ks959_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+
+ struct usb_ctrlrequest *tx_setuprequest;
+ struct urb *tx_urb;
+ __u8 *tx_buf_clear;
+ unsigned int tx_buf_clear_used;
+ unsigned int tx_buf_clear_sent;
+ __u8 *tx_buf_xored;
+
+ struct usb_ctrlrequest *rx_setuprequest;
+ struct urb *rx_urb;
+ __u8 *rx_buf;
+ __u8 rx_variable_xormask;
+ iobuff_t rx_unwrap_buff;
+ struct timeval rx_time;
+
+ struct usb_ctrlrequest *speed_setuprequest;
+ struct urb *speed_urb;
+ struct ks959_speedparams speedparams;
+ unsigned int new_speed;
+
+ spinlock_t lock;
+ int receiving;
+};
+
+/* Procedure to perform the obfuscation/padding expected by the dongle
+ *
+ * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit
+ * len_cleartext (IN) Length of the cleartext version of IrDA frame
+ * buf_xoredtext (OUT) Obfuscated version of frame built by proc
+ * len_maxbuf (OUT) Maximum space available at buf_xoredtext
+ *
+ * (return) length of obfuscated frame with padding
+ *
+ * If not enough space (as indicated by len_maxbuf vs. required padding),
+ * zero is returned
+ *
+ * The value of lookup_string is actually a required portion of the algorithm.
+ * Seems the designer of the dongle wanted to state who exactly is responsible
+ * for implementing obfuscation. Send your best (or other) wishes to him ]:-)
+ */
+static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext,
+ unsigned int len_cleartext,
+ __u8 * buf_xoredtext,
+ unsigned int len_maxbuf)
+{
+ unsigned int len_xoredtext;
+
+ /* Calculate required length with padding, check for necessary space */
+ len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
+ if (len_xoredtext <= len_maxbuf) {
+ static const __u8 lookup_string[] = "wangshuofei19710";
+ __u8 xor_mask;
+
+ /* Unlike the WinXP driver, we *do* clear out the padding */
+ memset(buf_xoredtext, 0, len_xoredtext);
+
+ xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
+
+ while (len_cleartext-- > 0) {
+ *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
+ }
+ } else {
+ len_xoredtext = 0;
+ }
+ return len_xoredtext;
+}
+
+/* Callback transmission routine */
+static void ks959_speed_irq(struct urb *urb)
+{
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ks959_speed_irq: urb asynchronously failed - %d",
+ urb->status);
+ }
+}
+
+/* Send a control request to change speed of the dongle */
+static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed)
+{
+ static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
+ 57600, 115200, 576000, 1152000, 4000000, 0
+ };
+ int err;
+ unsigned int i;
+
+ if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+ return -ENOMEM;
+
+ /* Check that requested speed is among the supported ones */
+ for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
+ if (supported_speeds[i] == 0)
+ return -EOPNOTSUPP;
+
+ memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
+ kingsun->speedparams.baudrate = cpu_to_le32(speed);
+ kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+ /* speed_setuprequest pre-filled in ks959_probe */
+ usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->speed_setuprequest,
+ &(kingsun->speedparams),
+ sizeof(struct ks959_speedparams), ks959_speed_irq,
+ kingsun);
+ kingsun->speed_urb->status = 0;
+ err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+ return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ks959_send_irq(struct urb *urb);
+static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
+{
+ unsigned int padlen;
+ unsigned int wraplen;
+ int ret;
+
+ /* Check whether current plaintext can produce a padded buffer that fits
+ within the range handled by the dongle */
+ wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
+ if (wraplen > kingsun->tx_buf_clear_used)
+ wraplen = kingsun->tx_buf_clear_used;
+
+ /* Perform dongle obfuscation. Also remove the portion of the frame that
+ was just obfuscated and will now be sent to the dongle. */
+ padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
+ kingsun->tx_buf_xored,
+ KINGSUN_SND_PACKET_SIZE);
+
+ /* Calculate how much data can be transmitted in this urb */
+ kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
+ kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
+ /* Rest of the fields were filled in ks959_probe */
+ usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->tx_setuprequest,
+ kingsun->tx_buf_xored, padlen,
+ ks959_send_irq, kingsun);
+ kingsun->tx_urb->status = 0;
+ ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+ /* Remember how much data was sent, in order to update at callback */
+ kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+ return ret;
+}
+
+/* Callback transmission routine */
+static void ks959_send_irq(struct urb *urb)
+{
+ struct ks959_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
+ int ret = 0;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ err("ks959_send_irq: Network not running!");
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ks959_send_irq: urb asynchronously failed - %d",
+ urb->status);
+ return;
+ }
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* Update data remaining to be sent */
+ if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+ memmove(kingsun->tx_buf_clear,
+ kingsun->tx_buf_clear +
+ kingsun->tx_buf_clear_sent,
+ kingsun->tx_buf_clear_used -
+ kingsun->tx_buf_clear_sent);
+ }
+ kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+ kingsun->tx_buf_clear_sent = 0;
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* There is more data to be sent */
+ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+ err("ks959_send_irq: failed tx_urb submit: %d",
+ ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ }
+ } else {
+ /* All data sent, send next speed && wake network queue */
+ if (kingsun->new_speed != -1 &&
+ cpu_to_le32(kingsun->new_speed) !=
+ kingsun->speedparams.baudrate)
+ ks959_change_speed(kingsun, kingsun->new_speed);
+
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ks959_cb *kingsun;
+ unsigned int wraplen;
+ int ret = 0;
+
+ if (skb == NULL || netdev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ /* the IRDA wrapping routines don't deal with non linear skb */
+ SKB_LINEAR_ASSERT(skb);
+
+ kingsun = netdev_priv(netdev);
+
+ spin_lock(&kingsun->lock);
+ kingsun->new_speed = irda_get_next_speed(skb);
+
+ /* Append data to the end of whatever data remains to be transmitted */
+ wraplen =
+ async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+ kingsun->tx_buf_clear_used = wraplen;
+
+ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+ err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ } else {
+ kingsun->stats.tx_packets++;
+ kingsun->stats.tx_bytes += skb->len;
+
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock(&kingsun->lock);
+
+ return ret;
+}
+
+/* Receive callback function */
+static void ks959_rcv_irq(struct urb *urb)
+{
+ struct ks959_cb *kingsun = urb->context;
+ int ret;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ kingsun->receiving = 0;
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("kingsun_rcv_irq: urb asynchronously failed - %d",
+ urb->status);
+ kingsun->receiving = 0;
+ return;
+ }
+
+ if (urb->actual_length > 0) {
+ __u8 *bytes = urb->transfer_buffer;
+ unsigned int i;
+
+ for (i = 0; i < urb->actual_length; i++) {
+ /* De-obfuscation implemented here: variable portion of
+ xormask is incremented, and then used with the encoded
+ byte for the XOR. The result of the operation is used
+ to unwrap the SIR frame. */
+ kingsun->rx_variable_xormask++;
+ bytes[i] =
+ bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
+
+ /* rx_variable_xormask doubles as an index counter so we
+ can skip the byte at 0xff (wrapped around to 0).
+ */
+ if (kingsun->rx_variable_xormask != 0) {
+ async_unwrap_char(kingsun->netdev,
+ &kingsun->stats,
+ &kingsun->rx_unwrap_buff,
+ bytes[i]);
+ }
+ }
+ kingsun->netdev->last_rx = jiffies;
+ do_gettimeofday(&kingsun->rx_time);
+ kingsun->receiving =
+ (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+ }
+
+ /* This urb has already been filled in kingsun_net_open. Setup
+ packet must be re-filled, but it is assumed that urb keeps the
+ pointer to the initial setup packet, as well as the payload buffer.
+ Setup packet is already pre-filled at ks959_probe.
+ */
+ urb->status = 0;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ks959_net_open(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ int err = -ENOMEM;
+ char hwname[16];
+
+ /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+ kingsun->receiving = 0;
+
+ /* Initialize for SIR to copy data directly into skb. */
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+ kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!kingsun->rx_unwrap_buff.skb)
+ goto free_mem;
+
+ skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+ kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+ do_gettimeofday(&kingsun->rx_time);
+
+ kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->rx_urb)
+ goto free_mem;
+
+ kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->tx_urb)
+ goto free_mem;
+
+ kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->speed_urb)
+ goto free_mem;
+
+ /* Initialize speed for dongle */
+ kingsun->new_speed = 9600;
+ err = ks959_change_speed(kingsun, 9600);
+ if (err < 0)
+ goto free_mem;
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ */
+ sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+ kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+ if (!kingsun->irlap) {
+ err("ks959-sir: irlap_open failed");
+ goto free_mem;
+ }
+
+ /* Start reception. Setup request already pre-filled in ks959_probe */
+ usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
+ usb_rcvctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->rx_setuprequest,
+ kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
+ ks959_rcv_irq, kingsun);
+ kingsun->rx_urb->status = 0;
+ err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ if (err) {
+ err("ks959-sir: first urb-submit failed: %d", err);
+ goto close_irlap;
+ }
+
+ netif_start_queue(netdev);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs allocated and ready to fill
+ - max rx packet known (in max_rx)
+ - unwrap state machine initialized, in state outside of any frame
+ - receive request in progress
+ - IrLAP layer started, about to hand over packets to send
+ */
+
+ return 0;
+
+ close_irlap:
+ irlap_close(kingsun->irlap);
+ free_mem:
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ if (kingsun->rx_unwrap_buff.skb) {
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ }
+ return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
+ */
+static int ks959_net_close(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->receiving = 0;
+
+ /* Stop and remove instance of IrLAP */
+ if (kingsun->irlap)
+ irlap_close(kingsun->irlap);
+
+ kingsun->irlap = NULL;
+
+ return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *)rq;
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the device is still there */
+ if (netif_device_present(kingsun->netdev))
+ return ks959_change_speed(kingsun, irq->ifr_baudrate);
+ break;
+
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the IrDA stack is still there */
+ if (netif_running(kingsun->netdev))
+ irda_device_set_media_busy(kingsun->netdev, TRUE);
+ break;
+
+ case SIOCGRECEIVING:
+ /* Only approximately true */
+ irq->ifr_receiving = kingsun->receiving;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ks959_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct ks959_cb *kingsun = NULL;
+ struct net_device *net = NULL;
+ int ret = -ENOMEM;
+
+ /* Allocate network device container. */
+ net = alloc_irdadev(sizeof(*kingsun));
+ if (!net)
+ goto err_out1;
+
+ SET_NETDEV_DEV(net, &intf->dev);
+ kingsun = netdev_priv(net);
+ kingsun->netdev = net;
+ kingsun->usbdev = dev;
+ kingsun->irlap = NULL;
+ kingsun->tx_setuprequest = NULL;
+ kingsun->tx_urb = NULL;
+ kingsun->tx_buf_clear = NULL;
+ kingsun->tx_buf_xored = NULL;
+ kingsun->tx_buf_clear_used = 0;
+ kingsun->tx_buf_clear_sent = 0;
+
+ kingsun->rx_setuprequest = NULL;
+ kingsun->rx_urb = NULL;
+ kingsun->rx_buf = NULL;
+ kingsun->rx_variable_xormask = 0;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->receiving = 0;
+ spin_lock_init(&kingsun->lock);
+
+ kingsun->speed_setuprequest = NULL;
+ kingsun->speed_urb = NULL;
+ kingsun->speedparams.baudrate = 0;
+
+ /* Allocate input buffer */
+ kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->rx_buf)
+ goto free_mem;
+
+ /* Allocate input setup packet */
+ kingsun->rx_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->rx_setuprequest)
+ goto free_mem;
+ kingsun->rx_setuprequest->bRequestType =
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
+ kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->rx_setuprequest->wIndex = 0;
+ kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
+
+ /* Allocate output buffer */
+ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_clear)
+ goto free_mem;
+ kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_xored)
+ goto free_mem;
+
+ /* Allocate and initialize output setup packet */
+ kingsun->tx_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->tx_setuprequest)
+ goto free_mem;
+ kingsun->tx_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->tx_setuprequest->wValue = 0;
+ kingsun->tx_setuprequest->wIndex = 0;
+ kingsun->tx_setuprequest->wLength = 0;
+
+ /* Allocate and initialize speed setup packet */
+ kingsun->speed_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->speed_setuprequest)
+ goto free_mem;
+ kingsun->speed_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+ kingsun->speed_setuprequest->wLength =
+ cpu_to_le16(sizeof(struct ks959_speedparams));
+
+ printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
+ "Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&kingsun->qos);
+
+ /* Baud rates known to be supported. Please uncomment if devices (other
+ than a SonyEriccson K300 phone) can be shown to support higher speed
+ with this dongle.
+ */
+ kingsun->qos.baud_rate.bits =
+ IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
+ kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+ irda_qos_bits_to_value(&kingsun->qos);
+
+ /* Override the network functions we need to use */
+ net->hard_start_xmit = ks959_hard_xmit;
+ net->open = ks959_net_open;
+ net->stop = ks959_net_close;
+ net->get_stats = ks959_net_get_stats;
+ net->do_ioctl = ks959_net_ioctl;
+
+ ret = register_netdev(net);
+ if (ret != 0)
+ goto free_mem;
+
+ info("IrDA: Registered KingSun KS-959 device %s", net->name);
+
+ usb_set_intfdata(intf, kingsun);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - setup requests pre-filled
+ - urbs not allocated, set to NULL
+ - max rx packet known (is KINGSUN_FIFO_SIZE)
+ - unwrap state machine (partially) initialized, but skb == NULL
+ */
+
+ return 0;
+
+ free_mem:
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_setuprequest);
+ kfree(kingsun->tx_buf_xored);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_setuprequest);
+ kfree(kingsun->rx_buf);
+ free_netdev(net);
+ err_out1:
+ return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ks959_disconnect(struct usb_interface *intf)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ if (!kingsun)
+ return;
+
+ unregister_netdev(kingsun->netdev);
+
+ /* Mop up receive && transmit urb's */
+ if (kingsun->speed_urb != NULL) {
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ }
+ if (kingsun->tx_urb != NULL) {
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ }
+ if (kingsun->rx_urb != NULL) {
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ }
+
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_setuprequest);
+ kfree(kingsun->tx_buf_xored);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_setuprequest);
+ kfree(kingsun->rx_buf);
+ free_netdev(kingsun->netdev);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ netif_device_detach(kingsun->netdev);
+ if (kingsun->speed_urb != NULL)
+ usb_kill_urb(kingsun->speed_urb);
+ if (kingsun->tx_urb != NULL)
+ usb_kill_urb(kingsun->tx_urb);
+ if (kingsun->rx_urb != NULL)
+ usb_kill_urb(kingsun->rx_urb);
+ return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ks959_resume(struct usb_interface *intf)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ if (kingsun->rx_urb != NULL) {
+ /* Setup request already filled in ks959_probe */
+ usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ }
+ netif_device_attach(kingsun->netdev);
+
+ return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+ .name = "ks959-sir",
+ .probe = ks959_probe,
+ .disconnect = ks959_disconnect,
+ .id_table = dongles,
+#ifdef CONFIG_PM
+ .suspend = ks959_suspend,
+ .resume = ks959_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ks959_init(void)
+{
+ return usb_register(&irda_driver);
+}
+
+module_init(ks959_init);
+
+/*
+ * Module removal
+ */
+static void __exit ks959_cleanup(void)
+{
+ /* Deregister the driver and remove all pending instances */
+ usb_deregister(&irda_driver);
+}
+
+module_exit(ks959_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
new file mode 100644
index 000000000000..d01a28593ce2
--- /dev/null
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -0,0 +1,832 @@
+/*****************************************************************************
+*
+* Filename: ksdazzle.c
+* Version: 0.1.2
+* Description: Irda KingSun Dazzle USB Dongle
+* Status: Experimental
+* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
+*
+* Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-26) understanding of how the Kingsun
+ * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This
+ * information was deduced by examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * General: This dongle exposes one interface with two interrupt endpoints, one
+ * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine
+ * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and
+ * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir.
+ *
+ * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then
+ * split it into multiple segments of up to 7 bytes each, and transmit each in
+ * sequence. It seems that sending a single big block (like kingsun-sir does)
+ * won't work with this dongle. Each segment needs to be prefixed with a value
+ * equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload
+ * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9,
+ * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the
+ * payload, not considered by the prefix, are ignored (set to 0 by this
+ * implementation).
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned
+ * in payloads from 0 to 8 bytes long. When concatenated, these payloads form
+ * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue 0x0200
+ * wIndex 0x0001
+ * wLength 0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ * __u32 baudSpeed;
+ * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
+ * unsigned int : 1;
+ * unsigned int stopBits : 1;
+ * unsigned int parityEnable : 1;
+ * unsigned int parityType : 1;
+ * unsigned int : 1;
+ * unsigned int reset : 1;
+ * unsigned char reserved[3]; // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 115200 bps.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KSDAZZLE_VENDOR_ID 0x07d0
+#define KSDAZZLE_PRODUCT_ID 0x4100
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+ /* KingSun Co,Ltd IrDA/USB Bridge */
+ {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
+#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */
+
+struct ksdazzle_speedparams {
+ __le32 baudrate; /* baud rate, little endian */
+ __u8 flags;
+ __u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE 0x00
+#define KS_PAR_EVEN 0x10
+#define KS_PAR_ODD 0x30
+#define KS_RESET 0x80
+
+#define KINGSUN_EP_IN 0
+#define KINGSUN_EP_OUT 1
+
+struct ksdazzle_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+
+ struct urb *tx_urb;
+ __u8 *tx_buf_clear;
+ unsigned int tx_buf_clear_used;
+ unsigned int tx_buf_clear_sent;
+ __u8 tx_payload[8];
+
+ struct urb *rx_urb;
+ __u8 *rx_buf;
+ iobuff_t rx_unwrap_buff;
+
+ struct usb_ctrlrequest *speed_setuprequest;
+ struct urb *speed_urb;
+ struct ksdazzle_speedparams speedparams;
+ unsigned int new_speed;
+
+ __u8 ep_in;
+ __u8 ep_out;
+
+ spinlock_t lock;
+ int receiving;
+};
+
+/* Callback transmission routine */
+static void ksdazzle_speed_irq(struct urb *urb)
+{
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ksdazzle_speed_irq: urb asynchronously failed - %d",
+ urb->status);
+ }
+}
+
+/* Send a control request to change speed of the dongle */
+static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed)
+{
+ static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
+ 57600, 115200, 576000, 1152000, 4000000, 0
+ };
+ int err;
+ unsigned int i;
+
+ if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+ return -ENOMEM;
+
+ /* Check that requested speed is among the supported ones */
+ for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
+ if (supported_speeds[i] == 0)
+ return -EOPNOTSUPP;
+
+ memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams));
+ kingsun->speedparams.baudrate = cpu_to_le32(speed);
+ kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+ /* speed_setuprequest pre-filled in ksdazzle_probe */
+ usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->speed_setuprequest,
+ &(kingsun->speedparams),
+ sizeof(struct ksdazzle_speedparams),
+ ksdazzle_speed_irq, kingsun);
+ kingsun->speed_urb->status = 0;
+ err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+ return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ksdazzle_send_irq(struct urb *urb);
+static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun)
+{
+ unsigned int wraplen;
+ int ret;
+
+ /* We can send at most 7 bytes of payload at a time */
+ wraplen = 7;
+ if (wraplen > kingsun->tx_buf_clear_used)
+ wraplen = kingsun->tx_buf_clear_used;
+
+ /* Prepare payload prefix with used length */
+ memset(kingsun->tx_payload, 0, 8);
+ kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen;
+ memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen);
+
+ usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+ usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+ kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1);
+ kingsun->tx_urb->status = 0;
+ ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+ /* Remember how much data was sent, in order to update at callback */
+ kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+ return ret;
+}
+
+/* Callback transmission routine */
+static void ksdazzle_send_irq(struct urb *urb)
+{
+ struct ksdazzle_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
+ int ret = 0;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ err("ksdazzle_send_irq: Network not running!");
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ksdazzle_send_irq: urb asynchronously failed - %d",
+ urb->status);
+ return;
+ }
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* Update data remaining to be sent */
+ if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+ memmove(kingsun->tx_buf_clear,
+ kingsun->tx_buf_clear +
+ kingsun->tx_buf_clear_sent,
+ kingsun->tx_buf_clear_used -
+ kingsun->tx_buf_clear_sent);
+ }
+ kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+ kingsun->tx_buf_clear_sent = 0;
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* There is more data to be sent */
+ if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
+ err("ksdazzle_send_irq: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ }
+ } else {
+ /* All data sent, send next speed && wake network queue */
+ if (kingsun->new_speed != -1 &&
+ cpu_to_le32(kingsun->new_speed) !=
+ kingsun->speedparams.baudrate)
+ ksdazzle_change_speed(kingsun,
+ kingsun->new_speed);
+
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ksdazzle_cb *kingsun;
+ unsigned int wraplen;
+ int ret = 0;
+
+ if (skb == NULL || netdev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ /* the IRDA wrapping routines don't deal with non linear skb */
+ SKB_LINEAR_ASSERT(skb);
+
+ kingsun = netdev_priv(netdev);
+
+ spin_lock(&kingsun->lock);
+ kingsun->new_speed = irda_get_next_speed(skb);
+
+ /* Append data to the end of whatever data remains to be transmitted */
+ wraplen =
+ async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+ kingsun->tx_buf_clear_used = wraplen;
+
+ if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
+ err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ } else {
+ kingsun->stats.tx_packets++;
+ kingsun->stats.tx_bytes += skb->len;
+
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock(&kingsun->lock);
+
+ return ret;
+}
+
+/* Receive callback function */
+static void ksdazzle_rcv_irq(struct urb *urb)
+{
+ struct ksdazzle_cb *kingsun = urb->context;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ kingsun->receiving = 0;
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ksdazzle_rcv_irq: urb asynchronously failed - %d",
+ urb->status);
+ kingsun->receiving = 0;
+ return;
+ }
+
+ if (urb->actual_length > 0) {
+ __u8 *bytes = urb->transfer_buffer;
+ unsigned int i;
+
+ for (i = 0; i < urb->actual_length; i++) {
+ async_unwrap_char(kingsun->netdev, &kingsun->stats,
+ &kingsun->rx_unwrap_buff, bytes[i]);
+ }
+ kingsun->netdev->last_rx = jiffies;
+ kingsun->receiving =
+ (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+ }
+
+ /* This urb has already been filled in ksdazzle_net_open. It is assumed that
+ urb keeps the pointer to the payload buffer.
+ */
+ urb->status = 0;
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function ksdazzle_net_open (dev)
+ *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ksdazzle_net_open(struct net_device *netdev)
+{
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+ int err = -ENOMEM;
+ char hwname[16];
+
+ /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */
+ kingsun->receiving = 0;
+
+ /* Initialize for SIR to copy data directly into skb. */
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+ kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!kingsun->rx_unwrap_buff.skb)
+ goto free_mem;
+
+ skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+ kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+
+ kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->rx_urb)
+ goto free_mem;
+
+ kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->tx_urb)
+ goto free_mem;
+
+ kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->speed_urb)
+ goto free_mem;
+
+ /* Initialize speed for dongle */
+ kingsun->new_speed = 9600;
+ err = ksdazzle_change_speed(kingsun, 9600);
+ if (err < 0)
+ goto free_mem;
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ */
+ sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+ kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+ if (!kingsun->irlap) {
+ err("ksdazzle-sir: irlap_open failed");
+ goto free_mem;
+ }
+
+ /* Start reception. */
+ usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+ usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+ kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq,
+ kingsun, 1);
+ kingsun->rx_urb->status = 0;
+ err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ if (err) {
+ err("ksdazzle-sir: first urb-submit failed: %d", err);
+ goto close_irlap;
+ }
+
+ netif_start_queue(netdev);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs allocated and ready to fill
+ - max rx packet known (in max_rx)
+ - unwrap state machine initialized, in state outside of any frame
+ - receive request in progress
+ - IrLAP layer started, about to hand over packets to send
+ */
+
+ return 0;
+
+ close_irlap:
+ irlap_close(kingsun->irlap);
+ free_mem:
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ if (kingsun->rx_unwrap_buff.skb) {
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ }
+ return err;
+}
+
+/*
+ * Function ksdazzle_net_close (dev)
+ *
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
+ */
+static int ksdazzle_net_close(struct net_device *netdev)
+{
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->receiving = 0;
+
+ /* Stop and remove instance of IrLAP */
+ irlap_close(kingsun->irlap);
+
+ kingsun->irlap = NULL;
+
+ return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+ int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *)rq;
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the device is still there */
+ if (netif_device_present(kingsun->netdev))
+ return ksdazzle_change_speed(kingsun,
+ irq->ifr_baudrate);
+ break;
+
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the IrDA stack is still there */
+ if (netif_running(kingsun->netdev))
+ irda_device_set_media_busy(kingsun->netdev, TRUE);
+ break;
+
+ case SIOCGRECEIVING:
+ /* Only approximately true */
+ irq->ifr_receiving = kingsun->receiving;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ksdazzle_net_get_stats(struct net_device
+ *netdev)
+{
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+ return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ksdazzle_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct ksdazzle_cb *kingsun = NULL;
+ struct net_device *net = NULL;
+ int ret = -ENOMEM;
+ int pipe, maxp_in, maxp_out;
+ __u8 ep_in;
+ __u8 ep_out;
+
+ /* Check that there really are two interrupt endpoints. Check based on the
+ one in drivers/usb/input/usbmouse.c
+ */
+ interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints != 2) {
+ err("ksdazzle: expected 2 endpoints, found %d",
+ interface->desc.bNumEndpoints);
+ return -ENODEV;
+ }
+ endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+ if (!usb_endpoint_is_int_in(endpoint)) {
+ err("ksdazzle: endpoint 0 is not interrupt IN");
+ return -ENODEV;
+ }
+
+ ep_in = endpoint->bEndpointAddress;
+ pipe = usb_rcvintpipe(dev, ep_in);
+ maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ if (maxp_in > 255 || maxp_in <= 1) {
+ err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in);
+ return -ENODEV;
+ }
+
+ endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+ if (!usb_endpoint_is_int_out(endpoint)) {
+ err("ksdazzle: endpoint 1 is not interrupt OUT");
+ return -ENODEV;
+ }
+
+ ep_out = endpoint->bEndpointAddress;
+ pipe = usb_sndintpipe(dev, ep_out);
+ maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ /* Allocate network device container. */
+ net = alloc_irdadev(sizeof(*kingsun));
+ if (!net)
+ goto err_out1;
+
+ SET_NETDEV_DEV(net, &intf->dev);
+ kingsun = netdev_priv(net);
+ kingsun->netdev = net;
+ kingsun->usbdev = dev;
+ kingsun->ep_in = ep_in;
+ kingsun->ep_out = ep_out;
+ kingsun->irlap = NULL;
+ kingsun->tx_urb = NULL;
+ kingsun->tx_buf_clear = NULL;
+ kingsun->tx_buf_clear_used = 0;
+ kingsun->tx_buf_clear_sent = 0;
+
+ kingsun->rx_urb = NULL;
+ kingsun->rx_buf = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->receiving = 0;
+ spin_lock_init(&kingsun->lock);
+
+ kingsun->speed_setuprequest = NULL;
+ kingsun->speed_urb = NULL;
+ kingsun->speedparams.baudrate = 0;
+
+ /* Allocate input buffer */
+ kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL);
+ if (!kingsun->rx_buf)
+ goto free_mem;
+
+ /* Allocate output buffer */
+ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_clear)
+ goto free_mem;
+
+ /* Allocate and initialize speed setup packet */
+ kingsun->speed_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->speed_setuprequest)
+ goto free_mem;
+ kingsun->speed_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+ kingsun->speed_setuprequest->wLength =
+ cpu_to_le16(sizeof(struct ksdazzle_speedparams));
+
+ printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, "
+ "Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&kingsun->qos);
+
+ /* Baud rates known to be supported. Please uncomment if devices (other
+ than a SonyEriccson K300 phone) can be shown to support higher speeds
+ with this dongle.
+ */
+ kingsun->qos.baud_rate.bits =
+ IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
+ kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+ irda_qos_bits_to_value(&kingsun->qos);
+
+ /* Override the network functions we need to use */
+ net->hard_start_xmit = ksdazzle_hard_xmit;
+ net->open = ksdazzle_net_open;
+ net->stop = ksdazzle_net_close;
+ net->get_stats = ksdazzle_net_get_stats;
+ net->do_ioctl = ksdazzle_net_ioctl;
+
+ ret = register_netdev(net);
+ if (ret != 0)
+ goto free_mem;
+
+ info("IrDA: Registered KingSun/Dazzle device %s", net->name);
+
+ usb_set_intfdata(intf, kingsun);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - setup requests pre-filled
+ - urbs not allocated, set to NULL
+ - max rx packet known (is KINGSUN_FIFO_SIZE)
+ - unwrap state machine (partially) initialized, but skb == NULL
+ */
+
+ return 0;
+
+ free_mem:
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_buf);
+ free_netdev(net);
+ err_out1:
+ return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ksdazzle_disconnect(struct usb_interface *intf)
+{
+ struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+ if (!kingsun)
+ return;
+
+ unregister_netdev(kingsun->netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_buf);
+ free_netdev(kingsun->netdev);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+ netif_device_detach(kingsun->netdev);
+ if (kingsun->speed_urb != NULL)
+ usb_kill_urb(kingsun->speed_urb);
+ if (kingsun->tx_urb != NULL)
+ usb_kill_urb(kingsun->tx_urb);
+ if (kingsun->rx_urb != NULL)
+ usb_kill_urb(kingsun->rx_urb);
+ return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ksdazzle_resume(struct usb_interface *intf)
+{
+ struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+ if (kingsun->rx_urb != NULL) {
+ /* Setup request already filled in ksdazzle_probe */
+ usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ }
+ netif_device_attach(kingsun->netdev);
+
+ return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+ .name = "ksdazzle-sir",
+ .probe = ksdazzle_probe,
+ .disconnect = ksdazzle_disconnect,
+ .id_table = dongles,
+#ifdef CONFIG_PM
+ .suspend = ksdazzle_suspend,
+ .resume = ksdazzle_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ksdazzle_init(void)
+{
+ return usb_register(&irda_driver);
+}
+
+module_init(ksdazzle_init);
+
+/*
+ * Module removal
+ */
+static void __exit ksdazzle_cleanup(void)
+{
+ /* Deregister the driver and remove all pending instances */
+ usb_deregister(&irda_driver);
+}
+
+module_exit(ksdazzle_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 0de867288a47..0b769192d4ce 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -50,7 +50,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/device.h>
@@ -465,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((u32 *)(buf+new_len)))) {
+ if(fcs != le32_to_cpu(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++;
@@ -899,8 +898,6 @@ static int mcs_probe(struct usb_interface *intf,
IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
- /* what is it realy for? */
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &intf->dev);
ret = usb_reset_configuration(udev);
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index d96c89751a71..12b9378c587f 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -437,7 +437,6 @@ static int __init nsc_ircc_open(chipio_t *info)
self->tx_fifo.tail = self->tx_buff.head;
/* Override the network functions we need to use */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
dev->open = nsc_ircc_net_open;
dev->stop = nsc_ircc_net_close;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 9d6c8f391b2d..6078e03de9a8 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -414,7 +414,7 @@ EXPORT_SYMBOL(sirdev_raw_read);
int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
{
int ret = -ENXIO;
- if (dev->drv->set_dtr_rts != 0)
+ if (dev->drv->set_dtr_rts)
ret = dev->drv->set_dtr_rts(dev, dtr, rts);
return ret;
}
@@ -913,8 +913,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n
dev->drv = drv;
dev->netdev = ndev;
- SET_MODULE_OWNER(ndev);
-
/* Override the network functions we need to use */
ndev->hard_start_xmit = sirdev_hard_xmit;
ndev->open = sirdev_open;
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 36ab98386be0..7e7b5828214a 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");
static int smsc_nopnp = 1;
module_param_named(nopnp, smsc_nopnp, bool, 0);
-MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true");
#define DMA_INVAL 255
static int ircc_dma = DMA_INVAL;
@@ -519,8 +519,6 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
goto err_out1;
}
- SET_MODULE_OWNER(dev);
-
dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
#if SMSC_IRCC2_C_NET_TIMEOUT
dev->tx_timeout = smsc_ircc_timeout;
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 755aa444a4dd..042bc2f0417d 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -332,7 +332,7 @@ static void fir_eof(struct stir_cb *stir)
}
fcs = ~(crc32_le(~0, rx_buff->data, len));
- if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) {
+ if (fcs != le32_to_cpu(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++;
@@ -1034,7 +1034,6 @@ static int stir_probe(struct usb_interface *intf,
if(!net)
goto err_out1;
- SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
stir = netdev_priv(net);
stir->netdev = net;
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index ff5358574d0a..126ec7c8680e 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -429,9 +429,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
self->tx_fifo.tail = self->tx_buff.head;
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
-
/* Override the network functions we need to use */
dev->hard_start_xmit = via_ircc_hard_xmit_sir;
dev->open = via_ircc_net_open;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 0538ca9ce058..acd082a96a4f 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1584,8 +1584,6 @@ static int vlsi_irda_init(struct net_device *ndev)
vlsi_irda_dev_t *idev = ndev->priv;
struct pci_dev *pdev = idev->pdev;
- SET_MODULE_OWNER(ndev);
-
ndev->irq = pdev->irq;
ndev->base_addr = pci_resource_start(pdev,0);
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index ca12a6096419..c8b9c74eea52 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -537,10 +537,10 @@ calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect)
*/
struct ring_descr_hw {
- volatile u16 rd_count; /* tx/rx count [11:0] */
- u16 reserved;
+ volatile __le16 rd_count; /* tx/rx count [11:0] */
+ __le16 reserved;
union {
- u32 addr; /* [23:0] of the buffer's busaddress */
+ __le32 addr; /* [23:0] of the buffer's busaddress */
struct {
u8 addr_res[3];
volatile u8 status; /* descriptor status */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 5182e800cc18..9fd2451b0fb2 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -232,9 +232,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
self->rx_buff.data = self->rx_buff.head;
self->netdev = dev;
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
-
/* Override the network functions we need to use */
dev->hard_start_xmit = w83977af_hard_xmit;
dev->open = w83977af_net_open;
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index 0343f12d2ffb..d6ff26af37b3 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -133,8 +133,6 @@ static int __init do_netcard_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return netcard_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -194,6 +192,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
static unsigned version_printed;
int i;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
/* Grab the region so that no one else tries to probe our ioports. */
if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname))
@@ -219,7 +218,9 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+
+ printk("%s", print_mac(mac, dev->dev_addr));
err = -EAGAIN;
#ifdef jumpered_interrupts
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 347d50cd77d4..97bd9dc2e52e 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -196,7 +196,6 @@ struct veth_lpar_connection {
struct veth_port {
struct device *dev;
- struct net_device_stats stats;
u64 mac_addr;
HvLpIndexMap lpar_map;
@@ -822,10 +821,9 @@ static int veth_init_connection(u8 rlp)
|| ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
return 0;
- cnx = kmalloc(sizeof(*cnx), GFP_KERNEL);
+ cnx = kzalloc(sizeof(*cnx), GFP_KERNEL);
if (! cnx)
return -ENOMEM;
- memset(cnx, 0, sizeof(*cnx));
cnx->remote_lp = rlp;
spin_lock_init(&cnx->lock);
@@ -852,14 +850,13 @@ static int veth_init_connection(u8 rlp)
if (rc != 0)
return rc;
- msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
+ msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
if (! msgs) {
veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
return -ENOMEM;
}
cnx->msgs = msgs;
- memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
for (i = 0; i < VETH_NUMBUFFERS; i++) {
msgs[i].token = i;
@@ -938,9 +935,6 @@ static void veth_release_connection(struct kobject *kobj)
static int veth_open(struct net_device *dev)
{
- struct veth_port *port = (struct veth_port *) dev->priv;
-
- memset(&port->stats, 0, sizeof (port->stats));
netif_start_queue(dev);
return 0;
}
@@ -951,13 +945,6 @@ static int veth_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *veth_get_stats(struct net_device *dev)
-{
- struct veth_port *port = (struct veth_port *) dev->priv;
-
- return &port->stats;
-}
-
static int veth_change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU))
@@ -1086,7 +1073,6 @@ static struct net_device * __init veth_probe_one(int vlan,
dev->open = veth_open;
dev->hard_start_xmit = veth_start_xmit;
dev->stop = veth_close;
- dev->get_stats = veth_get_stats;
dev->change_mtu = veth_change_mtu;
dev->set_mac_address = NULL;
dev->set_multicast_list = veth_set_multicast_list;
@@ -1185,7 +1171,6 @@ static void veth_transmit_to_many(struct sk_buff *skb,
HvLpIndexMap lpmask,
struct net_device *dev)
{
- struct veth_port *port = (struct veth_port *) dev->priv;
int i, success, error;
success = error = 0;
@@ -1201,11 +1186,11 @@ static void veth_transmit_to_many(struct sk_buff *skb,
}
if (error)
- port->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (success) {
- port->stats.tx_packets++;
- port->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
}
}
@@ -1543,8 +1528,8 @@ static void veth_receive(struct veth_lpar_connection *cnx,
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb); /* send it up */
- port->stats.rx_packets++;
- port->stats.rx_bytes += length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
} while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG);
/* Ack it */
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 3569d5b03388..1eee8894c732 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -184,6 +184,7 @@ struct ixgb_adapter {
boolean_t rx_csum;
/* OS defined structs */
+ struct napi_struct napi;
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index 52c99d01d568..e8eb0fd6c576 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -411,7 +411,7 @@ ixgb_write_eeprom(struct ixgb_hw *hw, uint16_t offset, uint16_t data)
ixgb_cleanup_eeprom(hw);
/* clear the init_ctrl_reg_1 to signify that the cache is invalidated */
- ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+ ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
return;
}
@@ -476,19 +476,19 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
uint16_t ee_data;
ee_data = ixgb_read_eeprom(hw, i);
checksum += ee_data;
- hw->eeprom[i] = le16_to_cpu(ee_data);
+ hw->eeprom[i] = cpu_to_le16(ee_data);
}
if (checksum != (uint16_t) EEPROM_SUM) {
DEBUGOUT("ixgb_ee: Checksum invalid.\n");
/* clear the init_ctrl_reg_1 to signify that the cache is
* invalidated */
- ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+ ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
return (FALSE);
}
- if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK))
- != le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) {
+ if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
+ != cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
DEBUGOUT("ixgb_ee: Signature invalid.\n");
return(FALSE);
}
@@ -511,8 +511,8 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
- if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK))
- == le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) {
+ if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
+ == cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
return (TRUE);
} else {
return ixgb_get_eeprom_data(hw);
@@ -528,7 +528,7 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw)
* Returns:
* Word at indexed offset in eeprom, if valid, 0 otherwise.
******************************************************************************/
-uint16_t
+__le16
ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index)
{
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
index ef236b935c15..7908bf3005ed 100644
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ixgb/ixgb_ee.h
@@ -76,22 +76,22 @@
/* EEPROM structure */
struct ixgb_ee_map_type {
uint8_t mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS];
- uint16_t compatibility;
- uint16_t reserved1[4];
- uint32_t pba_number;
- uint16_t init_ctrl_reg_1;
- uint16_t subsystem_id;
- uint16_t subvendor_id;
- uint16_t device_id;
- uint16_t vendor_id;
- uint16_t init_ctrl_reg_2;
- uint16_t oem_reserved[16];
- uint16_t swdpins_reg;
- uint16_t circuit_ctrl_reg;
+ __le16 compatibility;
+ __le16 reserved1[4];
+ __le32 pba_number;
+ __le16 init_ctrl_reg_1;
+ __le16 subsystem_id;
+ __le16 subvendor_id;
+ __le16 device_id;
+ __le16 vendor_id;
+ __le16 init_ctrl_reg_2;
+ __le16 oem_reserved[16];
+ __le16 swdpins_reg;
+ __le16 circuit_ctrl_reg;
uint8_t d3_power;
uint8_t d0_power;
- uint16_t reserved2[28];
- uint16_t checksum;
+ __le16 reserved2[28];
+ __le16 checksum;
};
/* EEPROM Functions */
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index afde84868bea..fddd5844168d 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -94,8 +94,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)}
};
-#define IXGB_STATS_LEN \
- sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats)
+#define IXGB_STATS_LEN ARRAY_SIZE(ixgb_gstrings_stats)
static int
ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
@@ -423,7 +422,7 @@ ixgb_get_eeprom(struct net_device *netdev,
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
- uint16_t *eeprom_buff;
+ __le16 *eeprom_buff;
int i, max_len, first_word, last_word;
int ret_val = 0;
@@ -447,7 +446,7 @@ ixgb_get_eeprom(struct net_device *netdev,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
- eeprom_buff = kmalloc(sizeof(uint16_t) *
+ eeprom_buff = kmalloc(sizeof(__le16) *
(last_word - first_word + 1), GFP_KERNEL);
if(!eeprom_buff)
return -ENOMEM;
@@ -660,9 +659,14 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data)
}
static int
-ixgb_get_stats_count(struct net_device *netdev)
+ixgb_get_sset_count(struct net_device *netdev, int sset)
{
- return IXGB_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return IXGB_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -714,17 +718,14 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_rx_csum = ixgb_set_rx_csum,
.get_tx_csum = ixgb_get_tx_csum,
.set_tx_csum = ixgb_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_msglevel = ixgb_get_msglevel,
.set_msglevel = ixgb_set_msglevel,
- .get_tso = ethtool_op_get_tso,
.set_tso = ixgb_set_tso,
.get_strings = ixgb_get_strings,
.phys_id = ixgb_phys_id,
- .get_stats_count = ixgb_get_stats_count,
+ .get_sset_count = ixgb_get_sset_count,
.get_ethtool_stats = ixgb_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
void ixgb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index 40ef5ca88717..af5643324ee3 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -711,7 +711,7 @@ struct ixgb_hw {
uint32_t bar2;
uint32_t bar3;
uint16_t pci_cmd_word; /* PCI command register id from PCI configuration space */
- uint16_t eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */
+ __le16 eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */
unsigned long io_base; /* Our I/O mapped location */
uint32_t lastLFC;
uint32_t lastRFC;
@@ -809,7 +809,7 @@ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr);
uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw);
boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw);
-uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
+__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
/* Everything else */
void ixgb_led_on(struct ixgb_hw *hw);
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 991c8833e23c..d444de58ba34 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -97,7 +97,7 @@ static irqreturn_t ixgb_intr(int irq, void *data);
static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
#ifdef CONFIG_IXGB_NAPI
-static int ixgb_clean(struct net_device *netdev, int *budget);
+static int ixgb_clean(struct napi_struct *napi, int budget);
static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter,
int *work_done, int work_to_do);
#else
@@ -288,7 +288,7 @@ ixgb_up(struct ixgb_adapter *adapter)
mod_timer(&adapter->watchdog_timer, jiffies);
#ifdef CONFIG_IXGB_NAPI
- netif_poll_enable(netdev);
+ napi_enable(&adapter->napi);
#endif
ixgb_irq_enable(adapter);
@@ -309,7 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
if(kill_watchdog)
del_timer_sync(&adapter->watchdog_timer);
#ifdef CONFIG_IXGB_NAPI
- netif_poll_disable(netdev);
+ napi_disable(&adapter->napi);
#endif
adapter->link_speed = 0;
adapter->link_duplex = 0;
@@ -382,7 +382,6 @@ ixgb_probe(struct pci_dev *pdev,
goto err_alloc_etherdev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
@@ -421,8 +420,7 @@ ixgb_probe(struct pci_dev *pdev,
netdev->tx_timeout = &ixgb_tx_timeout;
netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_IXGB_NAPI
- netdev->poll = &ixgb_clean;
- netdev->weight = 64;
+ netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64);
#endif
netdev->vlan_rx_register = ixgb_vlan_rx_register;
netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid;
@@ -1746,7 +1744,7 @@ ixgb_intr(int irq, void *data)
}
#ifdef CONFIG_IXGB_NAPI
- if(netif_rx_schedule_prep(netdev)) {
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
/* Disable interrupts and register for poll. The flush
of the posted write is intentionally left out.
@@ -1754,7 +1752,7 @@ ixgb_intr(int irq, void *data)
atomic_inc(&adapter->irq_sem);
IXGB_WRITE_REG(&adapter->hw, IMC, ~0);
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
}
#else
/* yes, that is actually a & and it is meant to make sure that
@@ -1776,27 +1774,23 @@ ixgb_intr(int irq, void *data)
**/
static int
-ixgb_clean(struct net_device *netdev, int *budget)
+ixgb_clean(struct napi_struct *napi, int budget)
{
- struct ixgb_adapter *adapter = netdev_priv(netdev);
- int work_to_do = min(*budget, netdev->quota);
+ struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
int tx_cleaned;
int work_done = 0;
tx_cleaned = ixgb_clean_tx_irq(adapter);
- ixgb_clean_rx_irq(adapter, &work_done, work_to_do);
-
- *budget -= work_done;
- netdev->quota -= work_done;
+ ixgb_clean_rx_irq(adapter, &work_done, budget);
/* if no Tx and not enough Rx work done, exit the polling mode */
if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
ixgb_irq_enable(adapter);
- return 0;
}
- return 1;
+ return work_done;
}
#endif
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
new file mode 100644
index 000000000000..ccd83d9f579e
--- /dev/null
+++ b/drivers/net/ixgbe/Makefile
@@ -0,0 +1,36 @@
+################################################################################
+#
+# Intel 10 Gigabit PCI Express Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 10GbE PCI Express ethernet driver
+#
+
+obj-$(CONFIG_IXGBE) += ixgbe.o
+
+ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
+ ixgbe_82598.o ixgbe_phy.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
new file mode 100644
index 000000000000..c160a7d91e21
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -0,0 +1,259 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_H_
+#define _IXGBE_H_
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+
+
+#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args)
+
+#define PFX "ixgbe: "
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+ ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
+ printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
+ __FUNCTION__ , ## args)))
+
+/* TX/RX descriptor defines */
+#define IXGBE_DEFAULT_TXD 1024
+#define IXGBE_MAX_TXD 4096
+#define IXGBE_MIN_TXD 64
+
+#define IXGBE_DEFAULT_RXD 1024
+#define IXGBE_MAX_RXD 4096
+#define IXGBE_MIN_RXD 64
+
+#define IXGBE_DEFAULT_RXQ 1
+#define IXGBE_MAX_RXQ 1
+#define IXGBE_MIN_RXQ 1
+
+#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */
+#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */
+#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */
+#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */
+
+/* flow control */
+#define IXGBE_DEFAULT_FCRTL 0x10000
+#define IXGBE_MIN_FCRTL 0
+#define IXGBE_MAX_FCRTL 0x7FF80
+#define IXGBE_DEFAULT_FCRTH 0x20000
+#define IXGBE_MIN_FCRTH 0
+#define IXGBE_MAX_FCRTH 0x7FFF0
+#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */
+#define IXGBE_MIN_FCPAUSE 0
+#define IXGBE_MAX_FCPAUSE 0xFFFF
+
+/* Supported Rx Buffer Sizes */
+#define IXGBE_RXBUFFER_64 64 /* Used for packet split */
+#define IXGBE_RXBUFFER_128 128 /* Used for packet split */
+#define IXGBE_RXBUFFER_256 256 /* Used for packet split */
+#define IXGBE_RXBUFFER_2048 2048
+
+#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
+
+/* How many Tx Descriptors do we need to call netif_wake_queue? */
+#define IXGBE_TX_QUEUE_WAKE 16
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+
+#define IXGBE_TX_FLAGS_CSUM (u32)(1)
+#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1)
+#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2)
+#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3)
+#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct ixgbe_tx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned long time_stamp;
+ u16 length;
+ u16 next_to_watch;
+};
+
+struct ixgbe_rx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ struct page *page;
+ dma_addr_t page_dma;
+};
+
+struct ixgbe_queue_stats {
+ u64 packets;
+ u64 bytes;
+};
+
+struct ixgbe_ring {
+ struct ixgbe_adapter *adapter; /* backlink */
+ void *desc; /* descriptor ring memory */
+ dma_addr_t dma; /* phys. address of descriptor ring */
+ unsigned int size; /* length in bytes */
+ unsigned int count; /* amount of descriptors */
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+
+ union {
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ struct ixgbe_rx_buffer *rx_buffer_info;
+ };
+
+ u16 head;
+ u16 tail;
+
+ /* To protect race between sender and clean_tx_irq */
+ spinlock_t tx_lock;
+
+ struct ixgbe_queue_stats stats;
+
+ u32 eims_value;
+ u16 itr_register;
+
+ char name[IFNAMSIZ + 5];
+ u16 work_limit; /* max work per interrupt */
+};
+
+/* Helper macros to switch between ints/sec and what the register uses.
+ * And yes, it's the same math going both ways.
+ */
+#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
+ ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0)
+#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+
+#define IXGBE_DESC_UNUSED(R) \
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IXGBE_RX_DESC_ADV(R, i) \
+ (&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+#define IXGBE_TX_DESC_ADV(R, i) \
+ (&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
+#define IXGBE_TX_CTXTDESC_ADV(R, i) \
+ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
+
+#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
+
+/* board specific private data structure */
+struct ixgbe_adapter {
+ struct timer_list watchdog_timer;
+ struct vlan_group *vlgrp;
+ u16 bd_number;
+ u16 rx_buf_len;
+ atomic_t irq_sem;
+ struct work_struct reset_task;
+
+ /* TX */
+ struct ixgbe_ring *tx_ring; /* One per active queue */
+ struct napi_struct napi;
+ u64 restart_queue;
+ u64 lsc_int;
+ u64 hw_tso_ctxt;
+ u64 hw_tso6_ctxt;
+ u32 tx_timeout_count;
+ bool detect_tx_hung;
+
+ /* RX */
+ struct ixgbe_ring *rx_ring; /* One per active queue */
+ u64 hw_csum_tx_good;
+ u64 hw_csum_rx_error;
+ u64 hw_csum_rx_good;
+ u64 non_eop_descs;
+ int num_tx_queues;
+ int num_rx_queues;
+ struct msix_entry *msix_entries;
+
+ u64 rx_hdr_split;
+ u32 alloc_rx_page_failed;
+ u32 alloc_rx_buff_failed;
+
+ u32 flags;
+#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1)
+#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1)
+#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2)
+#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3)
+#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4)
+
+ /* Interrupt Throttle Rate */
+ u32 rx_eitr;
+ u32 tx_eitr;
+
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+
+ /* structs defined in ixgbe_hw.h */
+ struct ixgbe_hw hw;
+ u16 msg_enable;
+ struct ixgbe_hw_stats stats;
+ char lsc_name[IFNAMSIZ + 5];
+
+ unsigned long state;
+ u64 tx_busy;
+};
+
+enum ixbge_state_t {
+ __IXGBE_TESTING,
+ __IXGBE_RESETTING,
+ __IXGBE_DOWN
+};
+
+enum ixgbe_boards {
+ board_82598AF,
+ board_82598EB,
+ board_82598AT,
+};
+
+extern struct ixgbe_info ixgbe_82598AF_info;
+extern struct ixgbe_info ixgbe_82598EB_info;
+extern struct ixgbe_info ixgbe_82598AT_info;
+
+extern char ixgbe_driver_name[];
+extern char ixgbe_driver_version[];
+
+extern int ixgbe_up(struct ixgbe_adapter *adapter);
+extern void ixgbe_down(struct ixgbe_adapter *adapter);
+extern void ixgbe_reset(struct ixgbe_adapter *adapter);
+extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
+extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
+extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rxdr);
+extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *txdr);
+
+#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
new file mode 100644
index 000000000000..00ee20125ca9
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -0,0 +1,589 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+#define IXGBE_82598_MAX_TX_QUEUES 32
+#define IXGBE_82598_MAX_RX_QUEUES 64
+#define IXGBE_82598_RAR_ENTRIES 16
+
+static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *autoneg);
+static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
+ u32 *speed, bool *autoneg);
+static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up);
+static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete);
+static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up);
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete);
+static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw);
+
+
+static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
+{
+ hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES;
+ hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES;
+ hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
+
+ return 0;
+}
+
+/**
+ * ixgbe_get_link_settings_82598 - Determines default link settings
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: boolean auto-negotiation value
+ *
+ * Determines the default link settings by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *autoneg)
+{
+ s32 status = 0;
+ s32 autoc_reg;
+
+ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+ if (hw->mac.link_settings_loaded) {
+ autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
+ autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
+ autoc_reg |= hw->mac.link_attach_type;
+ autoc_reg |= hw->mac.link_mode_select;
+ }
+
+ switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) {
+ case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = false;
+ break;
+
+ case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ *autoneg = false;
+ break;
+
+ case IXGBE_AUTOC_LMS_1G_AN:
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = true;
+ break;
+
+ case IXGBE_AUTOC_LMS_KX4_AN:
+ case IXGBE_AUTOC_LMS_KX4_AN_1G_AN:
+ *speed = IXGBE_LINK_SPEED_UNKNOWN;
+ if (autoc_reg & IXGBE_AUTOC_KX4_SUPP)
+ *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (autoc_reg & IXGBE_AUTOC_KX_SUPP)
+ *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = true;
+ break;
+
+ default:
+ status = IXGBE_ERR_LINK_SETUP;
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_get_copper_link_settings_82598 - Determines default link settings
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: boolean auto-negotiation value
+ *
+ * Determines the default link settings by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
+ u32 *speed, bool *autoneg)
+{
+ s32 status = IXGBE_ERR_LINK_SETUP;
+ u16 speed_ability;
+
+ *speed = 0;
+ *autoneg = true;
+
+ status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &speed_ability);
+
+ if (status == 0) {
+ if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
+ *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
+ *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_get_media_type_82598 - Determines media type
+ * @hw: pointer to hardware structure
+ *
+ * Returns the media type (fiber, copper, backplane)
+ **/
+static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
+{
+ enum ixgbe_media_type media_type;
+
+ /* Media type for I82598 is based on device ID */
+ switch (hw->device_id) {
+ case IXGBE_DEV_ID_82598AF_DUAL_PORT:
+ case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
+ case IXGBE_DEV_ID_82598EB_CX4:
+ media_type = ixgbe_media_type_fiber;
+ break;
+ case IXGBE_DEV_ID_82598AT_DUAL_PORT:
+ media_type = ixgbe_media_type_copper;
+ break;
+ default:
+ media_type = ixgbe_media_type_unknown;
+ break;
+ }
+
+ return media_type;
+}
+
+/**
+ * ixgbe_setup_mac_link_82598 - Configures MAC link settings
+ * @hw: pointer to hardware structure
+ *
+ * Configures link settings based on values in the ixgbe_hw struct.
+ * Restarts the link. Performs autonegotiation if needed.
+ **/
+static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
+{
+ u32 autoc_reg;
+ u32 links_reg;
+ u32 i;
+ s32 status = 0;
+
+ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+ if (hw->mac.link_settings_loaded) {
+ autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
+ autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
+ autoc_reg |= hw->mac.link_attach_type;
+ autoc_reg |= hw->mac.link_mode_select;
+
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+ msleep(50);
+ }
+
+ /* Restart link */
+ autoc_reg |= IXGBE_AUTOC_AN_RESTART;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+ /* Only poll for autoneg to complete if specified to do so */
+ if (hw->phy.autoneg_wait_to_complete) {
+ if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN ||
+ hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
+ links_reg = 0; /* Just in case Autoneg time = 0 */
+ for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
+ links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+ if (links_reg & IXGBE_LINKS_KX_AN_COMP)
+ break;
+ msleep(100);
+ }
+ if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
+ status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+ hw_dbg(hw,
+ "Autonegotiation did not complete.\n");
+ }
+ }
+ }
+
+ /*
+ * We want to save off the original Flow Control configuration just in
+ * case we get disconnected and then reconnected into a different hub
+ * or switch with different Flow Control capabilities.
+ */
+ hw->fc.type = hw->fc.original_type;
+ ixgbe_setup_fc(hw, 0);
+
+ /* Add delay to filter out noises during initial link setup */
+ msleep(50);
+
+ return status;
+}
+
+/**
+ * ixgbe_check_mac_link_82598 - Get link/speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true is link is up, false otherwise
+ *
+ * Reads the links register to determine if link is up and the current speed
+ **/
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up)
+{
+ u32 links_reg;
+
+ links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+
+ if (links_reg & IXGBE_LINKS_UP)
+ *link_up = true;
+ else
+ *link_up = false;
+
+ if (links_reg & IXGBE_LINKS_SPEED)
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ else
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if auto-negotiation enabled
+ * @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ * Set the link speed in the AUTOC register and restarts link.
+ **/
+static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
+ u32 speed, bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ s32 status = 0;
+
+ /* If speed is 10G, then check for CX4 or XAUI. */
+ if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
+ (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4)))
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
+ else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg))
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
+ else if (autoneg) {
+ /* BX mode - Autonegotiate 1G */
+ if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD))
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN;
+ else /* KX/KX4 mode */
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN;
+ } else {
+ status = IXGBE_ERR_LINK_SETUP;
+ }
+
+ if (status == 0) {
+ hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete;
+
+ hw->mac.link_settings_loaded = true;
+ /*
+ * Setup and restart the link based on the new values in
+ * ixgbe_hw This will write the AUTOC register based on the new
+ * stored values
+ */
+ hw->phy.ops.setup(hw);
+ }
+
+ return status;
+}
+
+
+/**
+ * ixgbe_setup_copper_link_82598 - Setup copper link settings
+ * @hw: pointer to hardware structure
+ *
+ * Configures link settings based on values in the ixgbe_hw struct.
+ * Restarts the link. Performs autonegotiation if needed. Restart
+ * phy and wait for autonegotiate to finish. Then synchronize the
+ * MAC and PHY.
+ **/
+static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u32 speed = 0;
+ bool link_up = false;
+
+ /* Set up MAC */
+ hw->phy.ops.setup(hw);
+
+ /* Restart autonegotiation on PHY */
+ status = hw->phy.ops.setup(hw);
+
+ /* Synchronize MAC to PHY speed */
+ if (status == 0)
+ status = hw->phy.ops.check(hw, &speed, &link_up);
+
+ return status;
+}
+
+/**
+ * ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true if link is up, false otherwise
+ *
+ * Reads the mac link, phy link, and synchronizes the MAC to PHY.
+ **/
+static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up)
+{
+ s32 status;
+ u32 phy_speed = 0;
+ bool phy_link = false;
+
+ /* This is the speed and link the MAC is set at */
+ hw->phy.ops.check(hw, speed, link_up);
+
+ /*
+ * Check current speed and link status of the PHY register.
+ * This is a vendor specific register and may have to
+ * be changed for other copper PHYs.
+ */
+ status = hw->phy.ops.check(hw, &phy_speed, &phy_link);
+
+ if ((status == 0) && (phy_link)) {
+ /*
+ * Check current link status of the MACs link's register
+ * matches that of the speed in the PHY register
+ */
+ if (*speed != phy_speed) {
+ /*
+ * The copper PHY requires 82598 attach type to be XAUI
+ * for 10G and BX for 1G
+ */
+ hw->mac.link_attach_type =
+ (IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX);
+
+ /* Synchronize the MAC speed to the PHY speed */
+ status = hw->phy.ops.setup_speed(hw, phy_speed, false,
+ false);
+ if (status == 0)
+ hw->phy.ops.check(hw, speed, link_up);
+ else
+ status = IXGBE_ERR_LINK_SETUP;
+ }
+ } else {
+ *link_up = phy_link;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if autonegotiation enabled
+ * @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ * Sets the link speed in the AUTOC register in the MAC and restarts link.
+ **/
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ s32 status;
+ bool link_up = 0;
+
+ /* Setup the PHY according to input speed */
+ status = hw->phy.ops.setup_speed(hw, speed, autoneg,
+ autoneg_wait_to_complete);
+
+ /* Synchronize MAC to PHY speed */
+ if (status == 0)
+ status = hw->phy.ops.check(hw, &speed, &link_up);
+
+ return status;
+}
+
+/**
+ * ixgbe_reset_hw_82598 - Performs hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by reseting the transmit and receive units, masks and
+ * clears all interrupts, performing a PHY reset, and performing a link (MAC)
+ * reset.
+ **/
+static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
+{
+ s32 status = 0;
+ u32 ctrl;
+ u32 gheccr;
+ u32 i;
+ u32 autoc;
+ u8 analog_val;
+
+ /* Call adapter stop to disable tx/rx and clear interrupts */
+ ixgbe_stop_adapter(hw);
+
+ /*
+ * Power up the Atlas TX lanes if they are currently powered down.
+ * Atlas TX lanes are powered down for MAC loopback tests, but
+ * they are not automatically restored on reset.
+ */
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+ if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) {
+ /* Enable TX Atlas so packets can be transmitted again */
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val);
+
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val);
+
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val);
+
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val);
+ }
+
+ /* Reset PHY */
+ ixgbe_reset_phy(hw);
+
+ /*
+ * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+ * access and verify no pending requests before reset
+ */
+ if (ixgbe_disable_pcie_master(hw) != 0) {
+ status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+ }
+
+ /*
+ * Issue global reset to the MAC. This needs to be a SW reset.
+ * If link reset is used, it might reset the MAC when mng is using it
+ */
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* Poll for reset bit to self-clear indicating reset is complete */
+ for (i = 0; i < 10; i++) {
+ udelay(1);
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ if (!(ctrl & IXGBE_CTRL_RST))
+ break;
+ }
+ if (ctrl & IXGBE_CTRL_RST) {
+ status = IXGBE_ERR_RESET_FAILED;
+ hw_dbg(hw, "Reset polling failed to complete.\n");
+ }
+
+ msleep(50);
+
+ gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR);
+ gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6));
+ IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr);
+
+ /*
+ * AUTOC register which stores link settings gets cleared
+ * and reloaded from EEPROM after reset. We need to restore
+ * our stored value from init in case SW changed the attach
+ * type or speed. If this is the first time and link settings
+ * have not been stored, store default settings from AUTOC.
+ */
+ autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ if (hw->mac.link_settings_loaded) {
+ autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE);
+ autoc &= ~(IXGBE_AUTOC_LMS_MASK);
+ autoc |= hw->mac.link_attach_type;
+ autoc |= hw->mac.link_mode_select;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+ } else {
+ hw->mac.link_attach_type =
+ (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
+ hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK);
+ hw->mac.link_settings_loaded = true;
+ }
+
+ /* Store the permanent mac address */
+ ixgbe_get_mac_addr(hw, hw->mac.perm_addr);
+
+ return status;
+}
+
+static struct ixgbe_mac_operations mac_ops_82598 = {
+ .reset = &ixgbe_reset_hw_82598,
+ .get_media_type = &ixgbe_get_media_type_82598,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598EB = {
+ .setup = &ixgbe_setup_copper_link_82598,
+ .check = &ixgbe_check_copper_link_82598,
+ .setup_speed = &ixgbe_setup_copper_link_speed_82598,
+ .get_settings = &ixgbe_get_copper_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598EB_info = {
+ .mac = ixgbe_mac_82598EB,
+ .get_invariants = &ixgbe_get_invariants_82598,
+ .mac_ops = &mac_ops_82598,
+ .phy_ops = &phy_ops_82598EB,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598AT = {
+ .setup = &ixgbe_setup_tnx_phy_link,
+ .check = &ixgbe_check_tnx_phy_link,
+ .setup_speed = &ixgbe_setup_tnx_phy_link_speed,
+ .get_settings = &ixgbe_get_copper_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598AT_info = {
+ .mac = ixgbe_mac_82598EB,
+ .get_invariants = &ixgbe_get_invariants_82598,
+ .mac_ops = &mac_ops_82598,
+ .phy_ops = &phy_ops_82598AT,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598AF = {
+ .setup = &ixgbe_setup_mac_link_82598,
+ .check = &ixgbe_check_mac_link_82598,
+ .setup_speed = &ixgbe_setup_mac_link_speed_82598,
+ .get_settings = &ixgbe_get_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598AF_info = {
+ .mac = ixgbe_mac_82598EB,
+ .get_invariants = &ixgbe_get_invariants_82598,
+ .mac_ops = &mac_ops_82598,
+ .phy_ops = &phy_ops_82598AF,
+};
+
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
new file mode 100644
index 000000000000..512e3b22ed08
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -0,0 +1,1175 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw);
+
+static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw);
+static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw);
+static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw);
+static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
+
+static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw);
+static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw);
+static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
+static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr);
+
+/**
+ * ixgbe_start_hw - Prepare hardware for TX/RX
+ * @hw: pointer to hardware structure
+ *
+ * Starts the hardware by filling the bus info structure and media type, clears
+ * all on chip counters, initializes receive address registers, multicast
+ * table, VLAN filter table, calls routine to set up link and flow control
+ * settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+s32 ixgbe_start_hw(struct ixgbe_hw *hw)
+{
+ u32 ctrl_ext;
+
+ /* Set the media type */
+ hw->phy.media_type = hw->mac.ops.get_media_type(hw);
+
+ /* Identify the PHY */
+ ixgbe_identify_phy(hw);
+
+ /*
+ * Store MAC address from RAR0, clear receive address registers, and
+ * clear the multicast table
+ */
+ ixgbe_init_rx_addrs(hw);
+
+ /* Clear the VLAN filter table */
+ ixgbe_clear_vfta(hw);
+
+ /* Set up link */
+ hw->phy.ops.setup(hw);
+
+ /* Clear statistics registers */
+ ixgbe_clear_hw_cntrs(hw);
+
+ /* Set No Snoop Disable */
+ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+ ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+ /* Clear adapter stopped flag */
+ hw->adapter_stopped = false;
+
+ return 0;
+}
+
+/**
+ * ixgbe_init_hw - Generic hardware initialization
+ * @hw: pointer to hardware structure
+ *
+ * Initialize the hardware by reseting the hardware, filling the bus info
+ * structure and media type, clears all on chip counters, initializes receive
+ * address registers, multicast table, VLAN filter table, calls routine to set
+ * up link and flow control settings, and leaves transmit and receive units
+ * disabled and uninitialized
+ **/
+s32 ixgbe_init_hw(struct ixgbe_hw *hw)
+{
+ /* Reset the hardware */
+ hw->mac.ops.reset(hw);
+
+ /* Start the HW */
+ ixgbe_start_hw(hw);
+
+ return 0;
+}
+
+/**
+ * ixgbe_clear_hw_cntrs - Generic clear hardware counters
+ * @hw: pointer to hardware structure
+ *
+ * Clears all hardware statistics counters by reading them from the hardware
+ * Statistics counters are clear on read.
+ **/
+static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw)
+{
+ u16 i = 0;
+
+ IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+ IXGBE_READ_REG(hw, IXGBE_ILLERRC);
+ IXGBE_READ_REG(hw, IXGBE_ERRBC);
+ IXGBE_READ_REG(hw, IXGBE_MSPDC);
+ for (i = 0; i < 8; i++)
+ IXGBE_READ_REG(hw, IXGBE_MPC(i));
+
+ IXGBE_READ_REG(hw, IXGBE_MLFC);
+ IXGBE_READ_REG(hw, IXGBE_MRFC);
+ IXGBE_READ_REG(hw, IXGBE_RLEC);
+ IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+ IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+ IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+ IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+
+ for (i = 0; i < 8; i++) {
+ IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
+ IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
+ IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
+ IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
+ }
+
+ IXGBE_READ_REG(hw, IXGBE_PRC64);
+ IXGBE_READ_REG(hw, IXGBE_PRC127);
+ IXGBE_READ_REG(hw, IXGBE_PRC255);
+ IXGBE_READ_REG(hw, IXGBE_PRC511);
+ IXGBE_READ_REG(hw, IXGBE_PRC1023);
+ IXGBE_READ_REG(hw, IXGBE_PRC1522);
+ IXGBE_READ_REG(hw, IXGBE_GPRC);
+ IXGBE_READ_REG(hw, IXGBE_BPRC);
+ IXGBE_READ_REG(hw, IXGBE_MPRC);
+ IXGBE_READ_REG(hw, IXGBE_GPTC);
+ IXGBE_READ_REG(hw, IXGBE_GORCL);
+ IXGBE_READ_REG(hw, IXGBE_GORCH);
+ IXGBE_READ_REG(hw, IXGBE_GOTCL);
+ IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ for (i = 0; i < 8; i++)
+ IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+ IXGBE_READ_REG(hw, IXGBE_RUC);
+ IXGBE_READ_REG(hw, IXGBE_RFC);
+ IXGBE_READ_REG(hw, IXGBE_ROC);
+ IXGBE_READ_REG(hw, IXGBE_RJC);
+ IXGBE_READ_REG(hw, IXGBE_MNGPRC);
+ IXGBE_READ_REG(hw, IXGBE_MNGPDC);
+ IXGBE_READ_REG(hw, IXGBE_MNGPTC);
+ IXGBE_READ_REG(hw, IXGBE_TORL);
+ IXGBE_READ_REG(hw, IXGBE_TORH);
+ IXGBE_READ_REG(hw, IXGBE_TPR);
+ IXGBE_READ_REG(hw, IXGBE_TPT);
+ IXGBE_READ_REG(hw, IXGBE_PTC64);
+ IXGBE_READ_REG(hw, IXGBE_PTC127);
+ IXGBE_READ_REG(hw, IXGBE_PTC255);
+ IXGBE_READ_REG(hw, IXGBE_PTC511);
+ IXGBE_READ_REG(hw, IXGBE_PTC1023);
+ IXGBE_READ_REG(hw, IXGBE_PTC1522);
+ IXGBE_READ_REG(hw, IXGBE_MPTC);
+ IXGBE_READ_REG(hw, IXGBE_BPTC);
+ for (i = 0; i < 16; i++) {
+ IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+ IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+ IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+ IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_get_mac_addr - Generic get MAC address
+ * @hw: pointer to hardware structure
+ * @mac_addr: Adapter MAC address
+ *
+ * Reads the adapter's MAC address from first Receive Address Register (RAR0)
+ * A reset of the adapter must be performed prior to calling this function
+ * in order for the MAC address to have been loaded from the EEPROM into RAR0
+ **/
+s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr)
+{
+ u32 rar_high;
+ u32 rar_low;
+ u16 i;
+
+ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0));
+ rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0));
+
+ for (i = 0; i < 4; i++)
+ mac_addr[i] = (u8)(rar_low >> (i*8));
+
+ for (i = 0; i < 2; i++)
+ mac_addr[i+4] = (u8)(rar_high >> (i*8));
+
+ return 0;
+}
+
+s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num)
+{
+ s32 ret_val;
+ u16 data;
+
+ ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num = (u32)(data << 16);
+
+ ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num |= data;
+
+ return 0;
+}
+
+/**
+ * ixgbe_stop_adapter - Generic stop TX/RX units
+ * @hw: pointer to hardware structure
+ *
+ * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
+ * disables transmit and receive units. The adapter_stopped flag is used by
+ * the shared code and drivers to determine if the adapter is in a stopped
+ * state and should not touch the hardware.
+ **/
+s32 ixgbe_stop_adapter(struct ixgbe_hw *hw)
+{
+ u32 number_of_queues;
+ u32 reg_val;
+ u16 i;
+
+ /*
+ * Set the adapter_stopped flag so other driver functions stop touching
+ * the hardware
+ */
+ hw->adapter_stopped = true;
+
+ /* Disable the receive unit */
+ reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ reg_val &= ~(IXGBE_RXCTRL_RXEN);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
+ msleep(2);
+
+ /* Clear interrupt mask to stop from interrupts being generated */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
+
+ /* Clear any pending interrupts */
+ IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ /* Disable the transmit unit. Each queue must be disabled. */
+ number_of_queues = hw->mac.num_tx_queues;
+ for (i = 0; i < number_of_queues; i++) {
+ reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+ if (reg_val & IXGBE_TXDCTL_ENABLE) {
+ reg_val &= ~IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_led_on - Turns on the software controllable LEDs.
+ * @hw: pointer to hardware structure
+ * @index: led number to turn on
+ **/
+s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index)
+{
+ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+ /* To turn on the LED, set mode to ON. */
+ led_reg &= ~IXGBE_LED_MODE_MASK(index);
+ led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index);
+ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+
+ return 0;
+}
+
+/**
+ * ixgbe_led_off - Turns off the software controllable LEDs.
+ * @hw: pointer to hardware structure
+ * @index: led number to turn off
+ **/
+s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index)
+{
+ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+ /* To turn off the LED, set mode to OFF. */
+ led_reg &= ~IXGBE_LED_MODE_MASK(index);
+ led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index);
+ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+
+ return 0;
+}
+
+
+/**
+ * ixgbe_init_eeprom - Initialize EEPROM params
+ * @hw: pointer to hardware structure
+ *
+ * Initializes the EEPROM parameters ixgbe_eeprom_info within the
+ * ixgbe_hw struct in order to set up EEPROM access.
+ **/
+s32 ixgbe_init_eeprom(struct ixgbe_hw *hw)
+{
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ u32 eec;
+ u16 eeprom_size;
+
+ if (eeprom->type == ixgbe_eeprom_uninitialized) {
+ eeprom->type = ixgbe_eeprom_none;
+
+ /*
+ * Check for EEPROM present first.
+ * If not present leave as none
+ */
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ if (eec & IXGBE_EEC_PRES) {
+ eeprom->type = ixgbe_eeprom_spi;
+
+ /*
+ * SPI EEPROM is assumed here. This code would need to
+ * change if a future EEPROM is not SPI.
+ */
+ eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
+ IXGBE_EEC_SIZE_SHIFT);
+ eeprom->word_size = 1 << (eeprom_size +
+ IXGBE_EEPROM_WORD_SIZE_SHIFT);
+ }
+
+ if (eec & IXGBE_EEC_ADDR_SIZE)
+ eeprom->address_bits = 16;
+ else
+ eeprom->address_bits = 8;
+ hw_dbg(hw, "Eeprom params: type = %d, size = %d, address bits: "
+ "%d\n", eeprom->type, eeprom->word_size,
+ eeprom->address_bits);
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_read_eeprom - Read EEPROM word using EERD
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data)
+{
+ u32 eerd;
+ s32 status;
+
+ eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) +
+ IXGBE_EEPROM_READ_REG_START;
+
+ IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
+ status = ixgbe_poll_eeprom_eerd_done(hw);
+
+ if (status == 0)
+ *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
+ IXGBE_EEPROM_READ_REG_DATA);
+ else
+ hw_dbg(hw, "Eeprom read timed out\n");
+
+ return status;
+}
+
+/**
+ * ixgbe_poll_eeprom_eerd_done - Poll EERD status
+ * @hw: pointer to hardware structure
+ *
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ **/
+static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw)
+{
+ u32 i;
+ u32 reg;
+ s32 status = IXGBE_ERR_EEPROM;
+
+ for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) {
+ reg = IXGBE_READ_REG(hw, IXGBE_EERD);
+ if (reg & IXGBE_EEPROM_READ_REG_DONE) {
+ status = 0;
+ break;
+ }
+ udelay(5);
+ }
+ return status;
+}
+
+/**
+ * ixgbe_get_eeprom_semaphore - Get hardware semaphore
+ * @hw: pointer to hardware structure
+ *
+ * Sets the hardware semaphores so EEPROM access can occur for bit-bang method
+ **/
+static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_ERR_EEPROM;
+ u32 timeout;
+ u32 i;
+ u32 swsm;
+
+ /* Set timeout value based on size of EEPROM */
+ timeout = hw->eeprom.word_size + 1;
+
+ /* Get SMBI software semaphore between device drivers first */
+ for (i = 0; i < timeout; i++) {
+ /*
+ * If the SMBI bit is 0 when we read it, then the bit will be
+ * set and we have the semaphore
+ */
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ if (!(swsm & IXGBE_SWSM_SMBI)) {
+ status = 0;
+ break;
+ }
+ msleep(1);
+ }
+
+ /* Now get the semaphore between SW/FW through the SWESMBI bit */
+ if (status == 0) {
+ for (i = 0; i < timeout; i++) {
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+
+ /* Set the SW EEPROM semaphore bit to request access */
+ swsm |= IXGBE_SWSM_SWESMBI;
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+
+ /*
+ * If we set the bit successfully then we got the
+ * semaphore.
+ */
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ if (swsm & IXGBE_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ /*
+ * Release semaphores and return error if SW EEPROM semaphore
+ * was not granted because we don't have access to the EEPROM
+ */
+ if (i >= timeout) {
+ hw_dbg(hw, "Driver can't access the Eeprom - Semaphore "
+ "not granted.\n");
+ ixgbe_release_eeprom_semaphore(hw);
+ status = IXGBE_ERR_EEPROM;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_release_eeprom_semaphore - Release hardware semaphore
+ * @hw: pointer to hardware structure
+ *
+ * This function clears hardware semaphore bits.
+ **/
+static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw)
+{
+ u32 swsm;
+
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+
+ /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */
+ swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI);
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+}
+
+/**
+ * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ **/
+static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw)
+{
+ u16 i;
+ u16 j;
+ u16 checksum = 0;
+ u16 length = 0;
+ u16 pointer = 0;
+ u16 word = 0;
+
+ /* Include 0x0-0x3F in the checksum */
+ for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) {
+ if (ixgbe_read_eeprom(hw, i, &word) != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ break;
+ }
+ checksum += word;
+ }
+
+ /* Include all data from pointers except for the fw pointer */
+ for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
+ ixgbe_read_eeprom(hw, i, &pointer);
+
+ /* Make sure the pointer seems valid */
+ if (pointer != 0xFFFF && pointer != 0) {
+ ixgbe_read_eeprom(hw, pointer, &length);
+
+ if (length != 0xFFFF && length != 0) {
+ for (j = pointer+1; j <= pointer+length; j++) {
+ ixgbe_read_eeprom(hw, j, &word);
+ checksum += word;
+ }
+ }
+ }
+ }
+
+ checksum = (u16)IXGBE_EEPROM_SUM - checksum;
+
+ return checksum;
+}
+
+/**
+ * ixgbe_validate_eeprom_checksum - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum_val: calculated checksum
+ *
+ * Performs checksum calculation and validates the EEPROM checksum. If the
+ * caller does not need checksum_val, the value can be NULL.
+ **/
+s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val)
+{
+ s32 status;
+ u16 checksum;
+ u16 read_checksum = 0;
+
+ /*
+ * Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ status = ixgbe_read_eeprom(hw, 0, &checksum);
+
+ if (status == 0) {
+ checksum = ixgbe_calc_eeprom_checksum(hw);
+
+ ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum);
+
+ /*
+ * Verify read checksum from EEPROM is the same as
+ * calculated checksum
+ */
+ if (read_checksum != checksum)
+ status = IXGBE_ERR_EEPROM_CHECKSUM;
+
+ /* If the user cares, return the calculated checksum */
+ if (checksum_val)
+ *checksum_val = checksum;
+ } else {
+ hw_dbg(hw, "EEPROM read failed\n");
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_validate_mac_addr - Validate MAC address
+ * @mac_addr: pointer to MAC address.
+ *
+ * Tests a MAC address to ensure it is a valid Individual Address
+ **/
+s32 ixgbe_validate_mac_addr(u8 *mac_addr)
+{
+ s32 status = 0;
+
+ /* Make sure it is not a multicast address */
+ if (IXGBE_IS_MULTICAST(mac_addr))
+ status = IXGBE_ERR_INVALID_MAC_ADDR;
+ /* Not a broadcast address */
+ else if (IXGBE_IS_BROADCAST(mac_addr))
+ status = IXGBE_ERR_INVALID_MAC_ADDR;
+ /* Reject the zero address */
+ else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 &&
+ mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0)
+ status = IXGBE_ERR_INVALID_MAC_ADDR;
+
+ return status;
+}
+
+/**
+ * ixgbe_set_rar - Set RX address register
+ * @hw: pointer to hardware structure
+ * @addr: Address to put into receive address register
+ * @index: Receive address register to write
+ * @vind: Vind to set RAR to
+ * @enable_addr: set flag that address is active
+ *
+ * Puts an ethernet address into a receive address register.
+ **/
+s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
+ u32 enable_addr)
+{
+ u32 rar_low, rar_high;
+
+ /*
+ * HW expects these in little endian so we reverse the byte order from
+ * network order (big endian) to little endian
+ */
+ rar_low = ((u32)addr[0] |
+ ((u32)addr[1] << 8) |
+ ((u32)addr[2] << 16) |
+ ((u32)addr[3] << 24));
+
+ rar_high = ((u32)addr[4] |
+ ((u32)addr[5] << 8) |
+ ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK));
+
+ if (enable_addr != 0)
+ rar_high |= IXGBE_RAH_AV;
+
+ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low);
+ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+
+ return 0;
+}
+
+/**
+ * ixgbe_init_rx_addrs - Initializes receive address filters.
+ * @hw: pointer to hardware structure
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ **/
+static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw)
+{
+ u32 i;
+ u32 rar_entries = hw->mac.num_rx_addrs;
+
+ /*
+ * If the current mac address is valid, assume it is a software override
+ * to the permanent address.
+ * Otherwise, use the permanent address from the eeprom.
+ */
+ if (ixgbe_validate_mac_addr(hw->mac.addr) ==
+ IXGBE_ERR_INVALID_MAC_ADDR) {
+ /* Get the MAC address from the RAR0 for later reference */
+ ixgbe_get_mac_addr(hw, hw->mac.addr);
+
+ hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ",
+ hw->mac.addr[0], hw->mac.addr[1],
+ hw->mac.addr[2]);
+ hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
+ hw->mac.addr[4], hw->mac.addr[5]);
+ } else {
+ /* Setup the receive address. */
+ hw_dbg(hw, "Overriding MAC Address in RAR[0]\n");
+ hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ",
+ hw->mac.addr[0], hw->mac.addr[1],
+ hw->mac.addr[2]);
+ hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
+ hw->mac.addr[4], hw->mac.addr[5]);
+
+ ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+ }
+
+ hw->addr_ctrl.rar_used_count = 1;
+
+ /* Zero out the other receive addresses. */
+ hw_dbg(hw, "Clearing RAR[1-15]\n");
+ for (i = 1; i < rar_entries; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+ }
+
+ /* Clear the MTA */
+ hw->addr_ctrl.mc_addr_in_rar_count = 0;
+ hw->addr_ctrl.mta_in_use = 0;
+ IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type);
+
+ hw_dbg(hw, " Clearing MTA\n");
+ for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
+
+ return 0;
+}
+
+/**
+ * ixgbe_mta_vector - Determines bit-vector in multicast table to set
+ * @hw: pointer to hardware structure
+ * @mc_addr: the multicast address
+ *
+ * Extracts the 12 bits, from a multicast address, to determine which
+ * bit-vector to set in the multicast table. The hardware uses 12 bits, from
+ * incoming rx multicast addresses, to determine the bit-vector to check in
+ * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
+ * by the MO field of the MCSTCTRL. The MO field is set during initalization
+ * to mc_filter_type.
+ **/
+static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 vector = 0;
+
+ switch (hw->mac.mc_filter_type) {
+ case 0: /* use bits [47:36] of the address */
+ vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
+ break;
+ case 1: /* use bits [46:35] of the address */
+ vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
+ break;
+ case 2: /* use bits [45:34] of the address */
+ vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
+ break;
+ case 3: /* use bits [43:32] of the address */
+ vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
+ break;
+ default: /* Invalid mc_filter_type */
+ hw_dbg(hw, "MC filter type param set incorrectly\n");
+ break;
+ }
+
+ /* vector can only be 12-bits or boundary will be exceeded */
+ vector &= 0xFFF;
+ return vector;
+}
+
+/**
+ * ixgbe_set_mta - Set bit-vector in multicast table
+ * @hw: pointer to hardware structure
+ * @hash_value: Multicast address hash value
+ *
+ * Sets the bit-vector in the multicast table.
+ **/
+static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 vector;
+ u32 vector_bit;
+ u32 vector_reg;
+ u32 mta_reg;
+
+ hw->addr_ctrl.mta_in_use++;
+
+ vector = ixgbe_mta_vector(hw, mc_addr);
+ hw_dbg(hw, " bit-vector = 0x%03X\n", vector);
+
+ /*
+ * The MTA is a register array of 128 32-bit registers. It is treated
+ * like an array of 4096 bits. We want to set bit
+ * BitArray[vector_value]. So we figure out what register the bit is
+ * in, read it, OR in the new bit, then write back the new value. The
+ * register is determined by the upper 7 bits of the vector value and
+ * the bit within that register are determined by the lower 5 bits of
+ * the value.
+ */
+ vector_reg = (vector >> 5) & 0x7F;
+ vector_bit = vector & 0x1F;
+ mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg));
+ mta_reg |= (1 << vector_bit);
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
+}
+
+/**
+ * ixgbe_add_mc_addr - Adds a multicast address.
+ * @hw: pointer to hardware structure
+ * @mc_addr: new multicast address
+ *
+ * Adds it to unused receive address register or to the multicast table.
+ **/
+static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 rar_entries = hw->mac.num_rx_addrs;
+
+ hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
+ mc_addr[0], mc_addr[1], mc_addr[2],
+ mc_addr[3], mc_addr[4], mc_addr[5]);
+
+ /*
+ * Place this multicast address in the RAR if there is room,
+ * else put it in the MTA
+ */
+ if (hw->addr_ctrl.rar_used_count < rar_entries) {
+ ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count,
+ mc_addr, 0, IXGBE_RAH_AV);
+ hw_dbg(hw, "Added a multicast address to RAR[%d]\n",
+ hw->addr_ctrl.rar_used_count);
+ hw->addr_ctrl.rar_used_count++;
+ hw->addr_ctrl.mc_addr_in_rar_count++;
+ } else {
+ ixgbe_set_mta(hw, mc_addr);
+ }
+
+ hw_dbg(hw, "ixgbe_add_mc_addr Complete\n");
+}
+
+/**
+ * ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses
+ * @hw: pointer to hardware structure
+ * @mc_addr_list: the list of new multicast addresses
+ * @mc_addr_count: number of addresses
+ * @pad: number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the MC addrs from receive
+ * address registers and the multicast table. Uses unsed receive address
+ * registers for the first multicast addresses, and hashes the rest into the
+ * multicast table.
+ **/
+s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, u32 pad)
+{
+ u32 i;
+ u32 rar_entries = hw->mac.num_rx_addrs;
+
+ /*
+ * Set the new number of MC addresses that we are being requested to
+ * use.
+ */
+ hw->addr_ctrl.num_mc_addrs = mc_addr_count;
+ hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count;
+ hw->addr_ctrl.mc_addr_in_rar_count = 0;
+ hw->addr_ctrl.mta_in_use = 0;
+
+ /* Zero out the other receive addresses. */
+ hw_dbg(hw, "Clearing RAR[1-15]\n");
+ for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+ }
+
+ /* Clear the MTA */
+ hw_dbg(hw, " Clearing MTA\n");
+ for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
+
+ /* Add the new addresses */
+ for (i = 0; i < mc_addr_count; i++) {
+ hw_dbg(hw, " Adding the multicast addresses:\n");
+ ixgbe_add_mc_addr(hw, mc_addr_list +
+ (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad)));
+ }
+
+ /* Enable mta */
+ if (hw->addr_ctrl.mta_in_use > 0)
+ IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL,
+ IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type);
+
+ hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n");
+ return 0;
+}
+
+/**
+ * ixgbe_clear_vfta - Clear VLAN filter table
+ * @hw: pointer to hardware structure
+ *
+ * Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw)
+{
+ u32 offset;
+ u32 vlanbyte;
+
+ for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+
+ for (vlanbyte = 0; vlanbyte < 4; vlanbyte++)
+ for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
+ IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset),
+ 0);
+
+ return 0;
+}
+
+/**
+ * ixgbe_set_vfta - Set VLAN filter table
+ * @hw: pointer to hardware structure
+ * @vlan: VLAN id to write to VLAN filter
+ * @vind: VMDq output index that maps queue to VLAN id in VFTA
+ * @vlan_on: boolean flag to turn on/off VLAN in VFTA
+ *
+ * Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+ bool vlan_on)
+{
+ u32 VftaIndex;
+ u32 BitOffset;
+ u32 VftaReg;
+ u32 VftaByte;
+
+ /* Determine 32-bit word position in array */
+ VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */
+
+ /* Determine the location of the (VMD) queue index */
+ VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */
+ BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */
+
+ /* Set the nibble for VMD queue index */
+ VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex));
+ VftaReg &= (~(0x0F << BitOffset));
+ VftaReg |= (vind << BitOffset);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg);
+
+ /* Determine the location of the bit for this VLAN id */
+ BitOffset = vlan & 0x1F; /* lower five bits */
+
+ VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex));
+ if (vlan_on)
+ /* Turn on this VLAN id */
+ VftaReg |= (1 << BitOffset);
+ else
+ /* Turn off this VLAN id */
+ VftaReg &= ~(1 << BitOffset);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_fc - Configure flow control settings
+ * @hw: pointer to hardware structure
+ * @packetbuf_num: packet buffer number (0-7)
+ *
+ * Configures the flow control settings based on SW configuration.
+ * This function is used for 802.3x flow control configuration only.
+ **/
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
+{
+ u32 frctl_reg;
+ u32 rmcs_reg;
+
+ if (packetbuf_num < 0 || packetbuf_num > 7)
+ hw_dbg(hw, "Invalid packet buffer number [%d], expected range"
+ "is 0-7\n", packetbuf_num);
+
+ frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
+
+ rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
+ rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X);
+
+ /*
+ * We want to save off the original Flow Control configuration just in
+ * case we get disconnected and then reconnected into a different hub
+ * or switch with different Flow Control capabilities.
+ */
+ hw->fc.type = hw->fc.original_type;
+
+ /*
+ * The possible values of the "flow_control" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames but not
+ * send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do not
+ * support receiving pause frames)
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: Invalid.
+ */
+ switch (hw->fc.type) {
+ case ixgbe_fc_none:
+ break;
+ case ixgbe_fc_rx_pause:
+ /*
+ * RX Flow control is enabled,
+ * and TX Flow control is disabled.
+ */
+ frctl_reg |= IXGBE_FCTRL_RFCE;
+ break;
+ case ixgbe_fc_tx_pause:
+ /*
+ * TX Flow control is enabled, and RX Flow control is disabled,
+ * by a software over-ride.
+ */
+ rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+ break;
+ case ixgbe_fc_full:
+ /*
+ * Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ frctl_reg |= IXGBE_FCTRL_RFCE;
+ rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+ break;
+ default:
+ /* We should never get here. The value should be 0-3. */
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ break;
+ }
+
+ /* Enable 802.3x based flow control settings. */
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg);
+ IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
+
+ /*
+ * We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ if (hw->fc.type & ixgbe_fc_tx_pause) {
+ if (hw->fc.send_xon) {
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+ (hw->fc.low_water | IXGBE_FCRTL_XONE));
+ } else {
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+ hw->fc.low_water);
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
+ (hw->fc.high_water)|IXGBE_FCRTH_FCEN);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time);
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));
+
+ return 0;
+}
+
+/**
+ * ixgbe_disable_pcie_master - Disable PCI-express master access
+ * @hw: pointer to hardware structure
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable
+ * bit hasn't caused the master requests to be disabled, else 0
+ * is returned signifying master requests disabled.
+ **/
+s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
+{
+ u32 ctrl;
+ s32 i;
+ s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ ctrl |= IXGBE_CTRL_GIO_DIS;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+
+ for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) {
+ status = 0;
+ break;
+ }
+ udelay(100);
+ }
+
+ return status;
+}
+
+
+/**
+ * ixgbe_acquire_swfw_sync - Aquire SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify wich semaphore to acquire
+ *
+ * Aquires the SWFW semaphore throught the GSSR register for the specified
+ * function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask)
+{
+ u32 gssr;
+ u32 swmask = mask;
+ u32 fwmask = mask << 5;
+ s32 timeout = 200;
+
+ while (timeout) {
+ if (ixgbe_get_eeprom_semaphore(hw))
+ return -IXGBE_ERR_SWFW_SYNC;
+
+ gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
+ if (!(gssr & (fwmask | swmask)))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask) or other software
+ * thread currently using resource (swmask)
+ */
+ ixgbe_release_eeprom_semaphore(hw);
+ msleep(5);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "Driver can't access resource, GSSR timeout.\n");
+ return -IXGBE_ERR_SWFW_SYNC;
+ }
+
+ gssr |= swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+
+ ixgbe_release_eeprom_semaphore(hw);
+ return 0;
+}
+
+/**
+ * ixgbe_release_swfw_sync - Release SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify wich semaphore to release
+ *
+ * Releases the SWFW semaphore throught the GSSR register for the specified
+ * function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
+{
+ u32 gssr;
+ u32 swmask = mask;
+
+ ixgbe_get_eeprom_semaphore(hw);
+
+ gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
+ gssr &= ~swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+
+ ixgbe_release_eeprom_semaphore(hw);
+}
+
+/**
+ * ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register
+ * @hw: pointer to hardware structure
+ * @reg: analog register to read
+ * @val: read value
+ *
+ * Performs write operation to analog register specified.
+ **/
+s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val)
+{
+ u32 atlas_ctl;
+
+ IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL,
+ IXGBE_ATLASCTL_WRITE_CMD | (reg << 8));
+ IXGBE_WRITE_FLUSH(hw);
+ udelay(10);
+ atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+ *val = (u8)atlas_ctl;
+
+ return 0;
+}
+
+/**
+ * ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register
+ * @hw: pointer to hardware structure
+ * @reg: atlas register to write
+ * @val: value to write
+ *
+ * Performs write operation to Atlas analog register specified.
+ **/
+s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val)
+{
+ u32 atlas_ctl;
+
+ atlas_ctl = (reg << 8) | val;
+ IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl);
+ IXGBE_WRITE_FLUSH(hw);
+ udelay(10);
+
+ return 0;
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
new file mode 100644
index 000000000000..de6ddd5d04ad
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_COMMON_H_
+#define _IXGBE_COMMON_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_init_hw(struct ixgbe_hw *hw);
+s32 ixgbe_start_hw(struct ixgbe_hw *hw);
+s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr);
+s32 ixgbe_stop_adapter(struct ixgbe_hw *hw);
+s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num);
+
+s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index);
+
+s32 ixgbe_init_eeprom(struct ixgbe_hw *hw);
+s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val);
+
+s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
+ u32 enable_addr);
+s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, u32 pad);
+s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on);
+s32 ixgbe_validate_mac_addr(u8 *mac_addr);
+
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num);
+
+s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
+
+s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val);
+s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val);
+
+#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+
+#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
+
+#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
+ writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
+
+#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
+ readl((a)->hw_addr + (reg) + ((offset) << 2)))
+
+#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
+
+#ifdef DEBUG
+#define hw_dbg(hw, format, arg...) \
+printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg);
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct ixgbe_hw *hw, const char *format, ...)
+{
+ return 0;
+}
+#endif
+
+#endif /* IXGBE_COMMON */
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
new file mode 100644
index 000000000000..a4e576a0c543
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -0,0 +1,948 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for ixgbe */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include "ixgbe.h"
+
+
+#define IXGBE_ALL_RAR_ENTRIES 16
+
+struct ixgbe_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \
+ offsetof(struct ixgbe_adapter, m)
+static struct ixgbe_stats ixgbe_gstrings_stats[] = {
+ {"rx_packets", IXGBE_STAT(net_stats.rx_packets)},
+ {"tx_packets", IXGBE_STAT(net_stats.tx_packets)},
+ {"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)},
+ {"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)},
+ {"lsc_int", IXGBE_STAT(lsc_int)},
+ {"tx_busy", IXGBE_STAT(tx_busy)},
+ {"non_eop_descs", IXGBE_STAT(non_eop_descs)},
+ {"rx_errors", IXGBE_STAT(net_stats.rx_errors)},
+ {"tx_errors", IXGBE_STAT(net_stats.tx_errors)},
+ {"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)},
+ {"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)},
+ {"multicast", IXGBE_STAT(net_stats.multicast)},
+ {"broadcast", IXGBE_STAT(stats.bprc)},
+ {"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
+ {"collisions", IXGBE_STAT(net_stats.collisions)},
+ {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)},
+ {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)},
+ {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)},
+ {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)},
+ {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)},
+ {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)},
+ {"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)},
+ {"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)},
+ {"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)},
+ {"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
+ {"tx_restart_queue", IXGBE_STAT(restart_queue)},
+ {"rx_long_length_errors", IXGBE_STAT(stats.roc)},
+ {"rx_short_length_errors", IXGBE_STAT(stats.ruc)},
+ {"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)},
+ {"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)},
+ {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)},
+ {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)},
+ {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)},
+ {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)},
+ {"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)},
+ {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)},
+ {"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)},
+ {"rx_header_split", IXGBE_STAT(rx_hdr_split)},
+ {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
+ {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
+};
+
+#define IXGBE_QUEUE_STATS_LEN \
+ ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
+ ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
+ (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
+#define IXGBE_GLOBAL_STATS_LEN \
+ sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats)
+#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+
+static int ixgbe_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+ ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL;
+
+ if (netif_carrier_ok(adapter->netdev)) {
+ ecmd->speed = SPEED_10000;
+ ecmd->duplex = DUPLEX_FULL;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+
+ ecmd->autoneg = AUTONEG_DISABLE;
+ return 0;
+}
+
+static int ixgbe_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if (ecmd->autoneg == AUTONEG_ENABLE ||
+ ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
+ return -EINVAL;
+
+ if (netif_running(adapter->netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_reset(adapter);
+ ixgbe_up(adapter);
+ } else {
+ ixgbe_reset(adapter);
+ }
+
+ return 0;
+}
+
+static void ixgbe_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ pause->autoneg = AUTONEG_DISABLE;
+
+ if (hw->fc.type == ixgbe_fc_rx_pause) {
+ pause->rx_pause = 1;
+ } else if (hw->fc.type == ixgbe_fc_tx_pause) {
+ pause->tx_pause = 1;
+ } else if (hw->fc.type == ixgbe_fc_full) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+}
+
+static int ixgbe_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ if (pause->autoneg == AUTONEG_ENABLE)
+ return -EINVAL;
+
+ if (pause->rx_pause && pause->tx_pause)
+ hw->fc.type = ixgbe_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->fc.type = ixgbe_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->fc.type = ixgbe_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->fc.type = ixgbe_fc_none;
+
+ hw->fc.original_type = hw->fc.type;
+
+ if (netif_running(adapter->netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ } else {
+ ixgbe_reset(adapter);
+ }
+
+ return 0;
+}
+
+static u32 ixgbe_get_rx_csum(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED);
+}
+
+static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ if (data)
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ } else {
+ ixgbe_reset(adapter);
+ }
+
+ return 0;
+}
+
+static u32 ixgbe_get_tx_csum(struct net_device *netdev)
+{
+ return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
+{
+ if (data)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+
+ return 0;
+}
+
+static int ixgbe_set_tso(struct net_device *netdev, u32 data)
+{
+
+ if (data) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ }
+ return 0;
+}
+
+static u32 ixgbe_get_msglevel(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ return adapter->msg_enable;
+}
+
+static void ixgbe_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ adapter->msg_enable = data;
+}
+
+static int ixgbe_get_regs_len(struct net_device *netdev)
+{
+#define IXGBE_REGS_LEN 1128
+ return IXGBE_REGS_LEN * sizeof(u32);
+}
+
+#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_
+
+static void ixgbe_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 *regs_buff = p;
+ u8 i;
+
+ memset(p, 0, IXGBE_REGS_LEN * sizeof(u32));
+
+ regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+
+ /* General Registers */
+ regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS);
+ regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+ regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP);
+ regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP);
+ regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+ regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER);
+ regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER);
+
+ /* NVM Register */
+ regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC);
+ regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD);
+ regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA);
+ regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL);
+ regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA);
+ regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL);
+ regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA);
+ regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT);
+ regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP);
+ regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC);
+
+ /* Interrupt */
+ regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR);
+ regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS);
+ regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS);
+ regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC);
+ regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC);
+ regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM);
+ regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0));
+ regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0));
+ regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT);
+ regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA);
+ regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL);
+ regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE);
+
+ /* Flow Control */
+ regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP);
+ regs_buff[31] = IXGBE_READ_REG(hw, IXGBE_FCTTV(0));
+ regs_buff[32] = IXGBE_READ_REG(hw, IXGBE_FCTTV(1));
+ regs_buff[33] = IXGBE_READ_REG(hw, IXGBE_FCTTV(2));
+ regs_buff[34] = IXGBE_READ_REG(hw, IXGBE_FCTTV(3));
+ for (i = 0; i < 8; i++)
+ regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
+ regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV);
+ regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS);
+
+ /* Receive DMA */
+ for (i = 0; i < 64; i++)
+ regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+ for (i = 0; i < 16; i++)
+ regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
+ for (i = 0; i < 16; i++)
+ regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
+ regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+ regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN);
+
+ /* Receive */
+ regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL);
+ for (i = 0; i < 16; i++)
+ regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i));
+ for (i = 0; i < 16; i++)
+ regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i));
+ regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE);
+ regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL);
+ regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC);
+ regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i));
+ regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP);
+
+ /* Transmit */
+ for (i = 0; i < 32; i++)
+ regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i));
+ regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL);
+ for (i = 0; i < 16; i++)
+ regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
+ regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG);
+ for (i = 0; i < 8; i++)
+ regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i));
+ regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP);
+
+ /* Wake Up */
+ regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC);
+ regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC);
+ regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS);
+ regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV);
+ regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT);
+ regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT);
+ regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL);
+ regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
+ regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT);
+
+ /* DCE */
+ regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);
+ regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
+ regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS);
+ regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR);
+ for (i = 0; i < 8; i++)
+ regs_buff[833 + i] = IXGBE_READ_REG(hw, IXGBE_RT2CR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[841 + i] = IXGBE_READ_REG(hw, IXGBE_RT2SR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[849 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[857 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[865 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[873 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i));
+
+ /* Statistics */
+ regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs);
+ regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc);
+ regs_buff[883] = IXGBE_GET_STAT(adapter, errbc);
+ regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc);
+ for (i = 0; i < 8; i++)
+ regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]);
+ regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc);
+ regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc);
+ regs_buff[895] = IXGBE_GET_STAT(adapter, rlec);
+ regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc);
+ regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc);
+ regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc);
+ regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc);
+ for (i = 0; i < 8; i++)
+ regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]);
+ for (i = 0; i < 8; i++)
+ regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]);
+ for (i = 0; i < 8; i++)
+ regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]);
+ for (i = 0; i < 8; i++)
+ regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]);
+ regs_buff[932] = IXGBE_GET_STAT(adapter, prc64);
+ regs_buff[933] = IXGBE_GET_STAT(adapter, prc127);
+ regs_buff[934] = IXGBE_GET_STAT(adapter, prc255);
+ regs_buff[935] = IXGBE_GET_STAT(adapter, prc511);
+ regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023);
+ regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522);
+ regs_buff[938] = IXGBE_GET_STAT(adapter, gprc);
+ regs_buff[939] = IXGBE_GET_STAT(adapter, bprc);
+ regs_buff[940] = IXGBE_GET_STAT(adapter, mprc);
+ regs_buff[941] = IXGBE_GET_STAT(adapter, gptc);
+ regs_buff[942] = IXGBE_GET_STAT(adapter, gorc);
+ regs_buff[944] = IXGBE_GET_STAT(adapter, gotc);
+ for (i = 0; i < 8; i++)
+ regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]);
+ regs_buff[954] = IXGBE_GET_STAT(adapter, ruc);
+ regs_buff[955] = IXGBE_GET_STAT(adapter, rfc);
+ regs_buff[956] = IXGBE_GET_STAT(adapter, roc);
+ regs_buff[957] = IXGBE_GET_STAT(adapter, rjc);
+ regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc);
+ regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc);
+ regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc);
+ regs_buff[961] = IXGBE_GET_STAT(adapter, tor);
+ regs_buff[963] = IXGBE_GET_STAT(adapter, tpr);
+ regs_buff[964] = IXGBE_GET_STAT(adapter, tpt);
+ regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64);
+ regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127);
+ regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255);
+ regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511);
+ regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023);
+ regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522);
+ regs_buff[971] = IXGBE_GET_STAT(adapter, mptc);
+ regs_buff[972] = IXGBE_GET_STAT(adapter, bptc);
+ regs_buff[973] = IXGBE_GET_STAT(adapter, xec);
+ for (i = 0; i < 16; i++)
+ regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]);
+ for (i = 0; i < 16; i++)
+ regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]);
+ for (i = 0; i < 16; i++)
+ regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]);
+ for (i = 0; i < 16; i++)
+ regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]);
+
+ /* MAC */
+ regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG);
+ regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
+ regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
+ regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0);
+ regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1);
+ regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
+ regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
+ regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP);
+ regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP);
+ regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1);
+ regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP);
+ regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA);
+ regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE);
+ regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD);
+ regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS);
+ regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA);
+ regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+ regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD);
+ regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD);
+ regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG);
+ regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1);
+ regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2);
+ regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS);
+ regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC);
+ regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS);
+ regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS);
+ regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+ regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3);
+ regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1);
+ regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2);
+ regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+
+ /* Diagnostic */
+ regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
+ regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN);
+ regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0);
+ regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1);
+ regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2);
+ regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3);
+ regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE);
+ regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
+ regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN);
+ regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0);
+ regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1);
+ regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2);
+ regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3);
+ regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE);
+ regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL);
+ regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0);
+ regs_buff[1103] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA1);
+ regs_buff[1104] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA2);
+ regs_buff[1105] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA3);
+ regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL);
+ regs_buff[1107] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA0);
+ regs_buff[1108] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA1);
+ regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2);
+ regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3);
+ for (i = 0; i < 8; i++)
+ regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
+ regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL);
+ regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1);
+ regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2);
+ regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1);
+ regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2);
+ regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS);
+ regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL);
+ regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC);
+ regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC);
+}
+
+static int ixgbe_get_eeprom_len(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ return adapter->hw.eeprom.word_size * 2;
+}
+
+static int ixgbe_get_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ int first_word, last_word, eeprom_len;
+ int ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EINVAL;
+
+ eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+ eeprom_len = last_word - first_word + 1;
+
+ eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ for (i = 0; i < eeprom_len; i++) {
+ if ((ret_val = ixgbe_read_eeprom(hw, first_word + i,
+ &eeprom_buff[i])))
+ break;
+ }
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < eeprom_len; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+ kfree(eeprom_buff);
+
+ return ret_val;
+}
+
+static void ixgbe_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ strncpy(drvinfo->driver, ixgbe_driver_name, 32);
+ strncpy(drvinfo->version, ixgbe_driver_version, 32);
+ strncpy(drvinfo->fw_version, "N/A", 32);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ drvinfo->n_stats = IXGBE_STATS_LEN;
+ drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
+}
+
+static void ixgbe_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_ring *tx_ring = adapter->tx_ring;
+ struct ixgbe_ring *rx_ring = adapter->rx_ring;
+
+ ring->rx_max_pending = IXGBE_MAX_RXD;
+ ring->tx_max_pending = IXGBE_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rx_ring->count;
+ ring->tx_pending = tx_ring->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int ixgbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_tx_buffer *old_buf;
+ struct ixgbe_rx_buffer *old_rx_buf;
+ void *old_desc;
+ int i, err;
+ u32 new_rx_count, new_tx_count, old_size;
+ dma_addr_t old_dma;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
+ new_rx_count = max(ring->rx_pending, (u32)IXGBE_MIN_RXD);
+ new_rx_count = min(new_rx_count, (u32)IXGBE_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ new_tx_count = max(ring->tx_pending, (u32)IXGBE_MIN_TXD);
+ new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ if ((new_tx_count == adapter->tx_ring->count) &&
+ (new_rx_count == adapter->rx_ring->count)) {
+ /* nothing to do */
+ return 0;
+ }
+
+ if (netif_running(adapter->netdev))
+ ixgbe_down(adapter);
+
+ /*
+ * We can't just free everything and then setup again,
+ * because the ISRs in MSI-X mode get passed pointers
+ * to the tx and rx ring structs.
+ */
+ if (new_tx_count != adapter->tx_ring->count) {
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ /* Save existing descriptor ring */
+ old_buf = adapter->tx_ring[i].tx_buffer_info;
+ old_desc = adapter->tx_ring[i].desc;
+ old_size = adapter->tx_ring[i].size;
+ old_dma = adapter->tx_ring[i].dma;
+ /* Try to allocate a new one */
+ adapter->tx_ring[i].tx_buffer_info = NULL;
+ adapter->tx_ring[i].desc = NULL;
+ adapter->tx_ring[i].count = new_tx_count;
+ err = ixgbe_setup_tx_resources(adapter,
+ &adapter->tx_ring[i]);
+ if (err) {
+ /* Restore the old one so at least
+ the adapter still works, even if
+ we failed the request */
+ adapter->tx_ring[i].tx_buffer_info = old_buf;
+ adapter->tx_ring[i].desc = old_desc;
+ adapter->tx_ring[i].size = old_size;
+ adapter->tx_ring[i].dma = old_dma;
+ goto err_setup;
+ }
+ /* Free the old buffer manually */
+ vfree(old_buf);
+ pci_free_consistent(adapter->pdev, old_size,
+ old_desc, old_dma);
+ }
+ }
+
+ if (new_rx_count != adapter->rx_ring->count) {
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+
+ old_rx_buf = adapter->rx_ring[i].rx_buffer_info;
+ old_desc = adapter->rx_ring[i].desc;
+ old_size = adapter->rx_ring[i].size;
+ old_dma = adapter->rx_ring[i].dma;
+
+ adapter->rx_ring[i].rx_buffer_info = NULL;
+ adapter->rx_ring[i].desc = NULL;
+ adapter->rx_ring[i].dma = 0;
+ adapter->rx_ring[i].count = new_rx_count;
+ err = ixgbe_setup_rx_resources(adapter,
+ &adapter->rx_ring[i]);
+ if (err) {
+ adapter->rx_ring[i].rx_buffer_info = old_rx_buf;
+ adapter->rx_ring[i].desc = old_desc;
+ adapter->rx_ring[i].size = old_size;
+ adapter->rx_ring[i].dma = old_dma;
+ goto err_setup;
+ }
+
+ vfree(old_rx_buf);
+ pci_free_consistent(adapter->pdev, old_size, old_desc,
+ old_dma);
+ }
+ }
+
+ err = 0;
+err_setup:
+ if (netif_running(adapter->netdev))
+ ixgbe_up(adapter);
+
+ return err;
+}
+
+static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return IXGBE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void ixgbe_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u64 *queue_stat;
+ int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
+ int j, k;
+ int i;
+
+ ixgbe_update_stats(adapter);
+ for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+ char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset;
+ data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ for (j = 0; j < adapter->num_tx_queues; j++) {
+ queue_stat = (u64 *)&adapter->tx_ring[j].stats;
+ for (k = 0; k < stat_count; k++)
+ data[i + k] = queue_stat[k];
+ i += k;
+ }
+ for (j = 0; j < adapter->num_rx_queues; j++) {
+ queue_stat = (u64 *)&adapter->rx_ring[j].stats;
+ for (k = 0; k < stat_count; k++)
+ data[i + k] = queue_stat[k];
+ i += k;
+ }
+}
+
+static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, ixgbe_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ sprintf(p, "tx_queue_%u_packets", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "tx_queue_%u_bytes", i);
+ p += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ sprintf(p, "rx_queue_%u_packets", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "rx_queue_%u_bytes", i);
+ p += ETH_GSTRING_LEN;
+ }
+/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
+ break;
+ }
+}
+
+
+static void ixgbe_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ return;
+}
+
+static int ixgbe_nway_reset(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_reset(adapter);
+ ixgbe_up(adapter);
+ }
+
+ return 0;
+}
+
+static int ixgbe_phys_id(struct net_device *netdev, u32 data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL);
+ u32 i;
+
+ if (!data || data > 300)
+ data = 300;
+
+ for (i = 0; i < (data * 1000); i += 400) {
+ ixgbe_led_on(&adapter->hw, IXGBE_LED_ON);
+ msleep_interruptible(200);
+ ixgbe_led_off(&adapter->hw, IXGBE_LED_ON);
+ msleep_interruptible(200);
+ }
+
+ /* Restore LED settings */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg);
+
+ return 0;
+}
+
+static int ixgbe_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->rx_eitr == 0)
+ ec->rx_coalesce_usecs = 0;
+ else
+ ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr;
+
+ if (adapter->tx_eitr == 0)
+ ec->tx_coalesce_usecs = 0;
+ else
+ ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr;
+
+ ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit;
+ return 0;
+}
+
+static int ixgbe_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
+ ((ec->rx_coalesce_usecs > 0) &&
+ (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
+ return -EINVAL;
+ if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
+ ((ec->tx_coalesce_usecs > 0) &&
+ (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
+ return -EINVAL;
+
+ /* convert to rate of irq's per second */
+ if (ec->rx_coalesce_usecs == 0)
+ adapter->rx_eitr = 0;
+ else
+ adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs);
+
+ if (ec->tx_coalesce_usecs == 0)
+ adapter->tx_eitr = 0;
+ else
+ adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs);
+
+ if (ec->tx_max_coalesced_frames_irq)
+ adapter->tx_ring[0].work_limit =
+ ec->tx_max_coalesced_frames_irq;
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ }
+
+ return 0;
+}
+
+
+static struct ethtool_ops ixgbe_ethtool_ops = {
+ .get_settings = ixgbe_get_settings,
+ .set_settings = ixgbe_set_settings,
+ .get_drvinfo = ixgbe_get_drvinfo,
+ .get_regs_len = ixgbe_get_regs_len,
+ .get_regs = ixgbe_get_regs,
+ .get_wol = ixgbe_get_wol,
+ .nway_reset = ixgbe_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_eeprom_len = ixgbe_get_eeprom_len,
+ .get_eeprom = ixgbe_get_eeprom,
+ .get_ringparam = ixgbe_get_ringparam,
+ .set_ringparam = ixgbe_set_ringparam,
+ .get_pauseparam = ixgbe_get_pauseparam,
+ .set_pauseparam = ixgbe_set_pauseparam,
+ .get_rx_csum = ixgbe_get_rx_csum,
+ .set_rx_csum = ixgbe_set_rx_csum,
+ .get_tx_csum = ixgbe_get_tx_csum,
+ .set_tx_csum = ixgbe_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_msglevel = ixgbe_get_msglevel,
+ .set_msglevel = ixgbe_set_msglevel,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ixgbe_set_tso,
+ .get_strings = ixgbe_get_strings,
+ .phys_id = ixgbe_phys_id,
+ .get_sset_count = ixgbe_get_sset_count,
+ .get_ethtool_stats = ixgbe_get_ethtool_stats,
+ .get_coalesce = ixgbe_get_coalesce,
+ .set_coalesce = ixgbe_set_coalesce,
+};
+
+void ixgbe_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
+}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
new file mode 100644
index 000000000000..b75f1c6efc42
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -0,0 +1,2872 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include "ixgbe.h"
+#include "ixgbe_common.h"
+
+char ixgbe_driver_name[] = "ixgbe";
+static char ixgbe_driver_string[] =
+ "Intel(R) 10 Gigabit PCI Express Network Driver";
+
+#define DRV_VERSION "1.1.18"
+char ixgbe_driver_version[] = DRV_VERSION;
+static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation.";
+
+static const struct ixgbe_info *ixgbe_info_tbl[] = {
+ [board_82598AF] = &ixgbe_82598AF_info,
+ [board_82598EB] = &ixgbe_82598EB_info,
+ [board_82598AT] = &ixgbe_82598AT_info,
+};
+
+/* ixgbe_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ * Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id ixgbe_pci_tbl[] = {
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
+ board_82598AF },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
+ board_82598AF },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT),
+ board_82598AT },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
+ board_82598EB },
+
+ /* required last entry */
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+
+#ifdef DEBUG
+/**
+ * ixgbe_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+{
+ struct ixgbe_adapter *adapter = hw->back;
+ struct net_device *netdev = adapter->netdev;
+ return netdev->name;
+}
+#endif
+
+static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry,
+ u8 msix_vector)
+{
+ u32 ivar, index;
+
+ msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+ index = (int_alloc_entry >> 2) & 0x1F;
+ ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index));
+ ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3)));
+ ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3)));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
+}
+
+static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
+ struct ixgbe_tx_buffer
+ *tx_buffer_info)
+{
+ if (tx_buffer_info->dma) {
+ pci_unmap_page(adapter->pdev,
+ tx_buffer_info->dma,
+ tx_buffer_info->length, PCI_DMA_TODEVICE);
+ tx_buffer_info->dma = 0;
+ }
+ if (tx_buffer_info->skb) {
+ dev_kfree_skb_any(tx_buffer_info->skb);
+ tx_buffer_info->skb = NULL;
+ }
+ /* tx_buffer_info must be completely set up in the transmit path */
+}
+
+static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ unsigned int eop,
+ union ixgbe_adv_tx_desc *eop_desc)
+{
+ /* Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of i */
+ adapter->detect_tx_hung = false;
+ if (tx_ring->tx_buffer_info[eop].dma &&
+ time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
+ !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) {
+ /* detected Tx unit hang */
+ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
+ " TDH <%x>\n"
+ " TDT <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " next_to_watch <%x>\n"
+ " jiffies <%lx>\n"
+ " next_to_watch.status <%x>\n",
+ readl(adapter->hw.hw_addr + tx_ring->head),
+ readl(adapter->hw.hw_addr + tx_ring->tail),
+ tx_ring->next_to_use,
+ tx_ring->next_to_clean,
+ tx_ring->tx_buffer_info[eop].time_stamp,
+ eop, jiffies, eop_desc->wb.status);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ **/
+static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ struct net_device *netdev = adapter->netdev;
+ union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ unsigned int i, eop;
+ bool cleaned = false;
+ int count = 0;
+
+ i = tx_ring->next_to_clean;
+ eop = tx_ring->tx_buffer_info[i].next_to_watch;
+ eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+ while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
+ for (cleaned = false; !cleaned;) {
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ cleaned = (i == eop);
+
+ tx_ring->stats.bytes += tx_buffer_info->length;
+ ixgbe_unmap_and_free_tx_resource(adapter,
+ tx_buffer_info);
+ tx_desc->wb.status = 0;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_ring->stats.packets++;
+
+ eop = tx_ring->tx_buffer_info[i].next_to_watch;
+ eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+
+ /* weight of a sort for tx, avoid endless transmit cleanup */
+ if (count++ >= tx_ring->work_limit)
+ break;
+ }
+
+ tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+ spin_lock(&tx_ring->tx_lock);
+
+ if (cleaned && netif_carrier_ok(netdev) &&
+ (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) &&
+ !test_bit(__IXGBE_DOWN, &adapter->state))
+ netif_wake_queue(netdev);
+
+ spin_unlock(&tx_ring->tx_lock);
+
+ if (adapter->detect_tx_hung)
+ if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
+ netif_stop_queue(netdev);
+
+ if (count >= tx_ring->work_limit)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
+
+ return cleaned;
+}
+
+/**
+ * ixgbe_receive_skb - Send a completed packet up the stack
+ * @adapter: board private structure
+ * @skb: packet to send up
+ * @is_vlan: packet has a VLAN tag
+ * @tag: VLAN tag from descriptor
+ **/
+static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
+ struct sk_buff *skb, bool is_vlan,
+ u16 tag)
+{
+ if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
+ if (adapter->vlgrp && is_vlan)
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
+ else
+ netif_receive_skb(skb);
+ } else {
+
+ if (adapter->vlgrp && is_vlan)
+ vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+ else
+ netif_rx(skb);
+ }
+}
+
+static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
+ u32 status_err,
+ struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Ignore Checksum bit is set */
+ if ((status_err & IXGBE_RXD_STAT_IXSM) ||
+ !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+ return;
+ /* TCP/UDP checksum error bit is set */
+ if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) {
+ /* let the stack verify checksum errors */
+ adapter->hw_csum_rx_error++;
+ return;
+ }
+ /* It must be a TCP or UDP packet with a valid checksum */
+ if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_rx_good++;
+}
+
+/**
+ * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbe_rx_buffer *rx_buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
+ while (cleaned_count--) {
+ rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+
+ if (!rx_buffer_info->page &&
+ (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+ rx_buffer_info->page = alloc_page(GFP_ATOMIC);
+ if (!rx_buffer_info->page) {
+ adapter->alloc_rx_page_failed++;
+ goto no_buffers;
+ }
+ rx_buffer_info->page_dma =
+ pci_map_page(pdev, rx_buffer_info->page,
+ 0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ }
+
+ if (!rx_buffer_info->skb) {
+ skb = netdev_alloc_skb(netdev, bufsz);
+
+ if (!skb) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+ }
+
+ /*
+ * Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ rx_buffer_info->skb = skb;
+ rx_buffer_info->dma = pci_map_single(pdev, skb->data,
+ bufsz,
+ PCI_DMA_FROMDEVICE);
+ }
+ /* Refresh the desc even if buffer_addrs didn't change because
+ * each write-back erases this info. */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ rx_desc->read.pkt_addr =
+ cpu_to_le64(rx_buffer_info->page_dma);
+ rx_desc->read.hdr_addr =
+ cpu_to_le64(rx_buffer_info->dma);
+ } else {
+ rx_desc->read.pkt_addr =
+ cpu_to_le64(rx_buffer_info->dma);
+ }
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ }
+no_buffers:
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+ if (i-- == 0)
+ i = (rx_ring->count - 1);
+
+ /*
+ * 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);
+ }
+}
+
+static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
+ struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
+ struct sk_buff *skb;
+ unsigned int i;
+ u32 upper_len, len, staterr;
+ u16 hdr_info, vlan_tag;
+ bool is_vlan, cleaned = false;
+ int cleaned_count = 0;
+
+ i = rx_ring->next_to_clean;
+ upper_len = 0;
+ rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ is_vlan = (staterr & IXGBE_RXD_STAT_VP);
+ vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+
+ while (staterr & IXGBE_RXD_STAT_DD) {
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ hdr_info =
+ le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info);
+ len =
+ ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+ IXGBE_RXDADV_HDRBUFLEN_SHIFT);
+ if (hdr_info & IXGBE_RXDADV_SPH)
+ adapter->rx_hdr_split++;
+ if (len > IXGBE_RX_HDR_SIZE)
+ len = IXGBE_RX_HDR_SIZE;
+ upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+ } else
+ len = le16_to_cpu(rx_desc->wb.upper.length);
+
+ cleaned = true;
+ skb = rx_buffer_info->skb;
+ prefetch(skb->data - NET_IP_ALIGN);
+ rx_buffer_info->skb = NULL;
+
+ if (len && !skb_shinfo(skb)->nr_frags) {
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ adapter->rx_buf_len + NET_IP_ALIGN,
+ PCI_DMA_FROMDEVICE);
+ skb_put(skb, len);
+ }
+
+ if (upper_len) {
+ pci_unmap_page(pdev, rx_buffer_info->page_dma,
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+ rx_buffer_info->page, 0, upper_len);
+ rx_buffer_info->page = NULL;
+
+ skb->len += upper_len;
+ skb->data_len += upper_len;
+ skb->truesize += upper_len;
+ }
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ next_buffer = &rx_ring->rx_buffer_info[i];
+
+ next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ prefetch(next_rxd);
+
+ cleaned_count++;
+ if (staterr & IXGBE_RXD_STAT_EOP) {
+ rx_ring->stats.packets++;
+ rx_ring->stats.bytes += skb->len;
+ } else {
+ rx_buffer_info->skb = next_buffer->skb;
+ rx_buffer_info->dma = next_buffer->dma;
+ next_buffer->skb = skb;
+ adapter->non_eop_descs++;
+ goto next_desc;
+ }
+
+ if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) {
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ ixgbe_rx_checksum(adapter, staterr, skb);
+ skb->protocol = eth_type_trans(skb, netdev);
+ ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
+ netdev->last_rx = jiffies;
+
+next_desc:
+ rx_desc->wb.upper.status_error = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) {
+ ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ rx_buffer_info = next_buffer;
+
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ is_vlan = (staterr & IXGBE_RXD_STAT_VP);
+ vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+ }
+
+ rx_ring->next_to_clean = i;
+ cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
+
+ if (cleaned_count)
+ ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+
+ return cleaned;
+}
+
+#define IXGBE_MAX_INTR 10
+/**
+ * ixgbe_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure
+ *
+ * ixgbe_configure_msix sets up the hardware to properly generate MSI-X
+ * interrupts.
+ **/
+static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
+{
+ int i, vector = 0;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i),
+ IXGBE_MSIX_VECTOR(vector));
+ writel(EITR_INTS_PER_SEC_TO_REG(adapter->tx_eitr),
+ adapter->hw.hw_addr + adapter->tx_ring[i].itr_register);
+ vector++;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i),
+ IXGBE_MSIX_VECTOR(vector));
+ writel(EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr),
+ adapter->hw.hw_addr + adapter->rx_ring[i].itr_register);
+ vector++;
+ }
+
+ vector = adapter->num_tx_queues + adapter->num_rx_queues;
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX,
+ IXGBE_MSIX_VECTOR(vector));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950);
+}
+
+static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ if (eicr & IXGBE_EICR_LSC) {
+ adapter->lsc_int++;
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ }
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
+{
+ struct ixgbe_ring *txr = data;
+ struct ixgbe_adapter *adapter = txr->adapter;
+
+ ixgbe_clean_tx_irq(adapter, txr);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
+{
+ struct ixgbe_ring *rxr = data;
+ struct ixgbe_adapter *adapter = rxr->adapter;
+
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims_value);
+ netif_rx_schedule(adapter->netdev, &adapter->napi);
+ return IRQ_HANDLED;
+}
+
+static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
+{
+ struct ixgbe_adapter *adapter = container_of(napi,
+ struct ixgbe_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
+ int work_done = 0;
+ struct ixgbe_ring *rxr = adapter->rx_ring;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(netdev))
+ goto quit_polling;
+
+ ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget);
+
+ /* If no Tx and not enough Rx work done, exit the polling mode */
+ if ((work_done < budget) || !netif_running(netdev)) {
+quit_polling:
+ netif_rx_complete(netdev, napi);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+ rxr->eims_value);
+ }
+
+ return work_done;
+}
+
+/**
+ * ixgbe_setup_msix - Initialize MSI-X interrupts
+ *
+ * ixgbe_setup_msix allocates MSI-X vectors and requests
+ * interrutps from the kernel.
+ **/
+static int ixgbe_setup_msix(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i, int_vector = 0, err = 0;
+ int max_msix_count;
+
+ /* +1 for the LSC interrupt */
+ max_msix_count = adapter->num_rx_queues + adapter->num_tx_queues + 1;
+ adapter->msix_entries = kcalloc(max_msix_count,
+ sizeof(struct msix_entry), GFP_KERNEL);
+ if (!adapter->msix_entries)
+ return -ENOMEM;
+
+ for (i = 0; i < max_msix_count; i++)
+ adapter->msix_entries[i].entry = i;
+
+ err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+ max_msix_count);
+ if (err)
+ goto out;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ sprintf(adapter->tx_ring[i].name, "%s-tx%d", netdev->name, i);
+ err = request_irq(adapter->msix_entries[int_vector].vector,
+ &ixgbe_msix_clean_tx,
+ 0,
+ adapter->tx_ring[i].name,
+ &(adapter->tx_ring[i]));
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "request_irq failed for MSIX interrupt "
+ "Error: %d\n", err);
+ goto release_irqs;
+ }
+ adapter->tx_ring[i].eims_value =
+ (1 << IXGBE_MSIX_VECTOR(int_vector));
+ adapter->tx_ring[i].itr_register = IXGBE_EITR(int_vector);
+ int_vector++;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ if (strlen(netdev->name) < (IFNAMSIZ - 5))
+ sprintf(adapter->rx_ring[i].name,
+ "%s-rx%d", netdev->name, i);
+ else
+ memcpy(adapter->rx_ring[i].name,
+ netdev->name, IFNAMSIZ);
+ err = request_irq(adapter->msix_entries[int_vector].vector,
+ &ixgbe_msix_clean_rx, 0,
+ adapter->rx_ring[i].name,
+ &(adapter->rx_ring[i]));
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "request_irq failed for MSIX interrupt "
+ "Error: %d\n", err);
+ goto release_irqs;
+ }
+
+ adapter->rx_ring[i].eims_value =
+ (1 << IXGBE_MSIX_VECTOR(int_vector));
+ adapter->rx_ring[i].itr_register = IXGBE_EITR(int_vector);
+ int_vector++;
+ }
+
+ sprintf(adapter->lsc_name, "%s-lsc", netdev->name);
+ err = request_irq(adapter->msix_entries[int_vector].vector,
+ &ixgbe_msix_lsc, 0, adapter->lsc_name, netdev);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "request_irq for msix_lsc failed: %d\n", err);
+ goto release_irqs;
+ }
+
+ /* FIXME: implement netif_napi_remove() instead */
+ adapter->napi.poll = ixgbe_clean_rxonly;
+ adapter->flags |= IXGBE_FLAG_MSIX_ENABLED;
+ return 0;
+
+release_irqs:
+ int_vector--;
+ for (; int_vector >= adapter->num_tx_queues; int_vector--)
+ free_irq(adapter->msix_entries[int_vector].vector,
+ &(adapter->rx_ring[int_vector -
+ adapter->num_tx_queues]));
+
+ for (; int_vector >= 0; int_vector--)
+ free_irq(adapter->msix_entries[int_vector].vector,
+ &(adapter->tx_ring[int_vector]));
+out:
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+ return err;
+}
+
+/**
+ * ixgbe_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ **/
+static irqreturn_t ixgbe_intr(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 eicr;
+
+ eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ if (!eicr)
+ return IRQ_NONE; /* Not our interrupt */
+
+ if (eicr & IXGBE_EICR_LSC) {
+ adapter->lsc_int++;
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ }
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ /* Disable interrupts and register for poll. The flush of the
+ * posted write is intentionally left out. */
+ atomic_inc(&adapter->irq_sem);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+ __netif_rx_schedule(netdev, &adapter->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ixgbe_request_irq - initialize interrupts
+ * @adapter: board private structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues)
+{
+ struct net_device *netdev = adapter->netdev;
+ int flags, err;
+ irqreturn_t(*handler) (int, void *) = &ixgbe_intr;
+
+ flags = IRQF_SHARED;
+
+ err = ixgbe_setup_msix(adapter);
+ if (!err)
+ goto request_done;
+
+ /*
+ * if we can't do MSI-X, fall through and try MSI
+ * No need to reallocate memory since we're decreasing the number of
+ * queues. We just won't use the other ones, also it is freed correctly
+ * on ixgbe_remove.
+ */
+ *num_rx_queues = 1;
+
+ /* do MSI */
+ err = pci_enable_msi(adapter->pdev);
+ if (!err) {
+ adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
+ flags &= ~IRQF_SHARED;
+ handler = &ixgbe_intr;
+ }
+
+ err = request_irq(adapter->pdev->irq, handler, flags,
+ netdev->name, netdev);
+ if (err)
+ DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);
+
+request_done:
+ return err;
+}
+
+static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ free_irq(adapter->msix_entries[i].vector,
+ &(adapter->tx_ring[i]));
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ free_irq(adapter->msix_entries[i +
+ adapter->num_tx_queues].vector,
+ &(adapter->rx_ring[i]));
+ i = adapter->num_rx_queues + adapter->num_tx_queues;
+ free_irq(adapter->msix_entries[i].vector, netdev);
+ pci_disable_msix(adapter->pdev);
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+ return;
+ }
+
+ free_irq(adapter->pdev->irq, netdev);
+ if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
+ }
+}
+
+/**
+ * ixgbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
+{
+ atomic_inc(&adapter->irq_sem);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * ixgbe_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
+{
+ if (atomic_dec_and_test(&adapter->irq_sem)) {
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
+ (IXGBE_EIMS_ENABLE_MASK &
+ ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+ IXGBE_EIMS_ENABLE_MASK);
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ }
+}
+
+/**
+ * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts
+ *
+ **/
+static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
+{
+ int i;
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ if (adapter->rx_eitr)
+ IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
+ EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr));
+
+ /* for re-triggering the interrupt in non-NAPI mode */
+ adapter->rx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0));
+ adapter->tx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0));
+
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0);
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), i);
+}
+
+/**
+ * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+{
+ u64 tdba;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 i, tdlen;
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ tdba = adapter->tx_ring[i].dma;
+ tdlen = adapter->tx_ring[i].count *
+ sizeof(union ixgbe_adv_tx_desc);
+ IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & DMA_32BIT_MASK));
+ IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), tdlen);
+ IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0);
+ adapter->tx_ring[i].head = IXGBE_TDH(i);
+ adapter->tx_ring[i].tail = IXGBE_TDT(i);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_TIPG, IXGBE_TIPG_FIBER_DEFAULT);
+}
+
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
+/**
+ * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+{
+ u64 rdba;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ u32 rdlen, rxctrl, rxcsum;
+ u32 random[10];
+ u32 reta, mrqc;
+ int i;
+ u32 fctrl, hlreg0;
+ u32 srrctl;
+ u32 pages;
+
+ /* Decide whether to use packet split mode or not */
+ if (netdev->mtu > ETH_DATA_LEN)
+ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+
+ /* Set the RX buffer length according to the mode */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ adapter->rx_buf_len = IXGBE_RX_HDR_SIZE;
+ } else {
+ if (netdev->mtu <= ETH_DATA_LEN)
+ adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+ else
+ adapter->rx_buf_len = ALIGN(max_frame, 1024);
+ }
+
+ fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+ fctrl |= IXGBE_FCTRL_BAM;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
+
+ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ if (adapter->netdev->mtu <= ETH_DATA_LEN)
+ hlreg0 &= ~IXGBE_HLREG0_JUMBOEN;
+ else
+ hlreg0 |= IXGBE_HLREG0_JUMBOEN;
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
+
+ pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+
+ srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0));
+ srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
+ srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+ srrctl |= ((IXGBE_RX_HDR_SIZE <<
+ IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+ IXGBE_SRRCTL_BSIZEHDR_MASK);
+ } else {
+ srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+ if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
+ srrctl |=
+ IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ else
+ srrctl |=
+ adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ }
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl);
+
+ rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
+ /* disable receives while setting up the descriptors */
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rdba = adapter->rx_ring[i].dma;
+ IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK));
+ IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen);
+ IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0);
+ adapter->rx_ring[i].head = IXGBE_RDH(i);
+ adapter->rx_ring[i].tail = IXGBE_RDT(i);
+ }
+
+ if (adapter->num_rx_queues > 1) {
+ /* Random 40bytes used as random key in RSS hash function */
+ get_random_bytes(&random[0], 40);
+
+ switch (adapter->num_rx_queues) {
+ case 8:
+ case 4:
+ /* Bits [3:0] in each byte refers the Rx queue no */
+ reta = 0x00010203;
+ break;
+ case 2:
+ reta = 0x00010001;
+ break;
+ default:
+ reta = 0x00000000;
+ break;
+ }
+
+ /* Fill out redirection table */
+ for (i = 0; i < 32; i++) {
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, reta);
+ if (adapter->num_rx_queues > 4) {
+ i++;
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i,
+ 0x04050607);
+ }
+ }
+
+ /* Fill out hash function seeds */
+ for (i = 0; i < 10; i++)
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, random[i]);
+
+ mrqc = IXGBE_MRQC_RSSEN
+ /* Perform hash on these packet types */
+ | IXGBE_MRQC_RSS_FIELD_IPV4
+ | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_EX
+ | IXGBE_MRQC_RSS_FIELD_IPV6
+ | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
+ IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+
+ /* Multiqueue and packet checksumming are mutually exclusive. */
+ rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ rxcsum |= IXGBE_RXCSUM_PCSD;
+ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+ } else {
+ /* Enable Receive Checksum Offload for TCP and UDP */
+ rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ if (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) {
+ /* Enable IPv4 payload checksum for UDP fragments
+ * Must be used in conjunction with packet-split. */
+ rxcsum |= IXGBE_RXCSUM_IPPCSE;
+ } else {
+ /* don't need to clear IPPCSE as it defaults to 0 */
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+ }
+ /* Enable Receives */
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+}
+
+static void ixgbe_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 ctrl;
+
+ ixgbe_irq_disable(adapter);
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+ ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+ ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+ }
+
+ ixgbe_irq_enable(adapter);
+}
+
+static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ /* add VID to filter table */
+ ixgbe_set_vfta(&adapter->hw, vid, 0, true);
+}
+
+static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ ixgbe_irq_disable(adapter);
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
+ ixgbe_irq_enable(adapter);
+
+ /* remove VID from filter table */
+ ixgbe_set_vfta(&adapter->hw, vid, 0, false);
+}
+
+static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
+{
+ ixgbe_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+ if (adapter->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
+ continue;
+ ixgbe_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+ }
+}
+
+/**
+ * ixgbe_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void ixgbe_set_multi(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct dev_mc_list *mc_ptr;
+ u8 *mta_list;
+ u32 fctrl;
+ int i;
+
+ /* Check for Promiscuous and All Multicast modes */
+
+ fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+
+ if (netdev->flags & IFF_PROMISC) {
+ fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ } else if (netdev->flags & IFF_ALLMULTI) {
+ fctrl |= IXGBE_FCTRL_MPE;
+ fctrl &= ~IXGBE_FCTRL_UPE;
+ } else {
+ fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+
+ if (netdev->mc_count) {
+ mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC);
+ if (!mta_list)
+ return;
+
+ /* Shared function expects packed array of only addresses. */
+ mc_ptr = netdev->mc_list;
+
+ for (i = 0; i < netdev->mc_count; i++) {
+ if (!mc_ptr)
+ break;
+ memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr,
+ ETH_ALEN);
+ mc_ptr = mc_ptr->next;
+ }
+
+ ixgbe_update_mc_addr_list(hw, mta_list, i, 0);
+ kfree(mta_list);
+ } else {
+ ixgbe_update_mc_addr_list(hw, NULL, 0, 0);
+ }
+
+}
+
+static void ixgbe_configure(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+
+ ixgbe_set_multi(netdev);
+
+ ixgbe_restore_vlan(adapter);
+
+ ixgbe_configure_tx(adapter);
+ ixgbe_configure_rx(adapter);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
+ (adapter->rx_ring[i].count - 1));
+}
+
+static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+ u32 gpie = 0;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 txdctl, rxdctl, mhadd;
+ int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED |
+ IXGBE_FLAG_MSI_ENABLED)) {
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME |
+ IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
+ } else {
+ /* MSI only */
+ gpie = (IXGBE_GPIE_EIAME |
+ IXGBE_GPIE_PBA_SUPPORT);
+ }
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_GPIE, gpie);
+ gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE);
+ }
+
+ mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
+
+ if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
+ mhadd &= ~IXGBE_MHADD_MFS_MASK;
+ mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
+
+ IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
+ }
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ txdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(i));
+ txdctl |= IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(i), txdctl);
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rxdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(i));
+ rxdctl |= IXGBE_RXDCTL_ENABLE;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl);
+ }
+ /* enable all receives */
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl);
+
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ ixgbe_configure_msix(adapter);
+ else
+ ixgbe_configure_msi_and_legacy(adapter);
+
+ clear_bit(__IXGBE_DOWN, &adapter->state);
+ napi_enable(&adapter->napi);
+ ixgbe_irq_enable(adapter);
+
+ /* bring the link up in the watchdog, this could race with our first
+ * link up interrupt but shouldn't be a problem */
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ return 0;
+}
+
+int ixgbe_up(struct ixgbe_adapter *adapter)
+{
+ /* hardware has been reset, we need to reload some things */
+ ixgbe_configure(adapter);
+
+ return ixgbe_up_complete(adapter);
+}
+
+void ixgbe_reset(struct ixgbe_adapter *adapter)
+{
+ if (ixgbe_init_hw(&adapter->hw))
+ DPRINTK(PROBE, ERR, "Hardware Error\n");
+
+ /* reprogram the RAR[0] in case user changed it. */
+ ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+
+}
+
+#ifdef CONFIG_PM
+static int ixgbe_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 err, num_rx_queues = adapter->num_rx_queues;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \
+ "suspend\n");
+ return err;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ if (netif_running(netdev)) {
+ err = ixgbe_request_irq(adapter, &num_rx_queues);
+ if (err)
+ return err;
+ }
+
+ ixgbe_reset(adapter);
+
+ if (netif_running(netdev))
+ ixgbe_up(adapter);
+
+ netif_device_attach(netdev);
+
+ return 0;
+}
+#endif
+
+/**
+ * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Rx ring sk_buffs */
+
+ for (i = 0; i < rx_ring->count; i++) {
+ struct ixgbe_rx_buffer *rx_buffer_info;
+
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ if (rx_buffer_info->dma) {
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ adapter->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->dma = 0;
+ }
+ if (rx_buffer_info->skb) {
+ dev_kfree_skb(rx_buffer_info->skb);
+ rx_buffer_info->skb = NULL;
+ }
+ if (!rx_buffer_info->page)
+ continue;
+ pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+
+ put_page(rx_buffer_info->page);
+ rx_buffer_info->page = NULL;
+ }
+
+ size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
+ memset(rx_ring->rx_buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ writel(0, adapter->hw.hw_addr + rx_ring->head);
+ writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * ixgbe_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Tx ring sk_buffs */
+
+ for (i = 0; i < tx_ring->count; i++) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+ }
+
+ size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
+ memset(tx_ring->tx_buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(tx_ring->desc, 0, tx_ring->size);
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ writel(0, adapter->hw.hw_addr + tx_ring->head);
+ writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * ixgbe_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * ixgbe_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+void ixgbe_down(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u32 rxctrl;
+
+ /* signal that we are down to the interrupt handler */
+ set_bit(__IXGBE_DOWN, &adapter->state);
+
+ /* disable receives */
+ rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL,
+ rxctrl & ~IXGBE_RXCTRL_RXEN);
+
+ netif_tx_disable(netdev);
+
+ /* disable transmits in the hardware */
+
+ /* flush both disables */
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ msleep(10);
+
+ ixgbe_irq_disable(adapter);
+
+ napi_disable(&adapter->napi);
+ del_timer_sync(&adapter->watchdog_timer);
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ ixgbe_reset(adapter);
+ ixgbe_clean_all_tx_rings(adapter);
+ ixgbe_clean_all_rx_rings(adapter);
+
+}
+
+static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+#ifdef CONFIG_PM
+ int retval = 0;
+#endif
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_free_irq(adapter);
+ }
+
+#ifdef CONFIG_PM
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+#endif
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static void ixgbe_shutdown(struct pci_dev *pdev)
+{
+ ixgbe_suspend(pdev, PMSG_SUSPEND);
+}
+
+/**
+ * ixgbe_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int ixgbe_clean(struct napi_struct *napi, int budget)
+{
+ struct ixgbe_adapter *adapter = container_of(napi,
+ struct ixgbe_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
+ int tx_cleaned = 0, work_done = 0;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(adapter->netdev))
+ goto quit_polling;
+
+ /* In non-MSIX case, there is no multi-Tx/Rx queue */
+ tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
+ ixgbe_clean_rx_irq(adapter, &adapter->rx_ring[0], &work_done,
+ budget);
+
+ /* If no Tx and not enough Rx work done, exit the polling mode */
+ if ((!tx_cleaned && (work_done < budget)) ||
+ !netif_running(adapter->netdev)) {
+quit_polling:
+ netif_rx_complete(netdev, napi);
+ ixgbe_irq_enable(adapter);
+ }
+
+ return work_done;
+}
+
+/**
+ * ixgbe_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void ixgbe_tx_timeout(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->reset_task);
+}
+
+static void ixgbe_reset_task(struct work_struct *work)
+{
+ struct ixgbe_adapter *adapter;
+ adapter = container_of(work, struct ixgbe_adapter, reset_task);
+
+ adapter->tx_timeout_count++;
+
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+}
+
+/**
+ * ixgbe_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time. The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct ixgbe_ring), GFP_KERNEL);
+ if (!adapter->tx_ring)
+ return -ENOMEM;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD;
+
+ adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct ixgbe_ring), GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ adapter->rx_ring[i].adapter = adapter;
+ adapter->rx_ring[i].itr_register = IXGBE_EITR(i);
+ adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD;
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * ixgbe_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* default flow control settings */
+ hw->fc.original_type = ixgbe_fc_full;
+ hw->fc.type = ixgbe_fc_full;
+
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
+ if (hw->mac.ops.reset(hw)) {
+ dev_err(&pdev->dev, "HW Init failed\n");
+ return -EIO;
+ }
+ if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true,
+ false)) {
+ dev_err(&pdev->dev, "Link Speed setup failed\n");
+ return -EIO;
+ }
+
+ /* initialize eeprom parameters */
+ if (ixgbe_init_eeprom(hw)) {
+ dev_err(&pdev->dev, "EEPROM initialization failed\n");
+ return -EIO;
+ }
+
+ /* Set the default values */
+ adapter->num_rx_queues = IXGBE_DEFAULT_RXQ;
+ adapter->num_tx_queues = 1;
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ if (ixgbe_alloc_queues(adapter)) {
+ dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+
+ atomic_set(&adapter->irq_sem, 1);
+ set_bit(__IXGBE_DOWN, &adapter->state);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @txdr: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *txdr)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+
+ size = sizeof(struct ixgbe_tx_buffer) * txdr->count;
+ txdr->tx_buffer_info = vmalloc(size);
+ if (!txdr->tx_buffer_info) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return -ENOMEM;
+ }
+ memset(txdr->tx_buffer_info, 0, size);
+
+ /* round up to nearest 4K */
+ txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc);
+ txdr->size = ALIGN(txdr->size, 4096);
+
+ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+ if (!txdr->desc) {
+ vfree(txdr->tx_buffer_info);
+ DPRINTK(PROBE, ERR,
+ "Memory allocation failed for the tx desc ring\n");
+ return -ENOMEM;
+ }
+
+ txdr->adapter = adapter;
+ txdr->next_to_use = 0;
+ txdr->next_to_clean = 0;
+ txdr->work_limit = txdr->count;
+ spin_lock_init(&txdr->tx_lock);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rxdr: rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rxdr)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int size, desc_len;
+
+ size = sizeof(struct ixgbe_rx_buffer) * rxdr->count;
+ rxdr->rx_buffer_info = vmalloc(size);
+ if (!rxdr->rx_buffer_info) {
+ DPRINTK(PROBE, ERR,
+ "vmalloc allocation failed for the rx desc ring\n");
+ return -ENOMEM;
+ }
+ memset(rxdr->rx_buffer_info, 0, size);
+
+ desc_len = sizeof(union ixgbe_adv_rx_desc);
+
+ /* Round up to nearest 4K */
+ rxdr->size = rxdr->count * desc_len;
+ rxdr->size = ALIGN(rxdr->size, 4096);
+
+ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+
+ if (!rxdr->desc) {
+ DPRINTK(PROBE, ERR,
+ "Memory allocation failed for the rx desc ring\n");
+ vfree(rxdr->rx_buffer_info);
+ return -ENOMEM;
+ }
+
+ rxdr->next_to_clean = 0;
+ rxdr->next_to_use = 0;
+ rxdr->adapter = adapter;
+
+ return 0;
+}
+
+/**
+ * ixgbe_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ixgbe_clean_tx_ring(adapter, tx_ring);
+
+ vfree(tx_ring->tx_buffer_info);
+ tx_ring->tx_buffer_info = NULL;
+
+ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+ tx_ring->desc = NULL;
+}
+
+/**
+ * ixgbe_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * ixgbe_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ixgbe_clean_rx_ring(adapter, rx_ring);
+
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+
+ pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+ rx_ring->desc = NULL;
+}
+
+/**
+ * ixgbe_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbe_setup_all_tx_resources - wrapper to allocate Tx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Tx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ixgbe_setup_all_rx_resources - wrapper to allocate Rx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Rx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ixgbe_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) ||
+ (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
+ return -EINVAL;
+
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int ixgbe_open(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int err;
+ u32 ctrl_ext;
+ u32 num_rx_queues = adapter->num_rx_queues;
+
+ /* Let firmware know the driver has taken over */
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+ ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+
+try_intr_reinit:
+ /* allocate transmit descriptors */
+ err = ixgbe_setup_all_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+ num_rx_queues = 1;
+ adapter->num_rx_queues = num_rx_queues;
+ }
+
+ /* allocate receive descriptors */
+ err = ixgbe_setup_all_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+
+ ixgbe_configure(adapter);
+
+ err = ixgbe_request_irq(adapter, &num_rx_queues);
+ if (err)
+ goto err_req_irq;
+
+ /* ixgbe_request might have reduced num_rx_queues */
+ if (num_rx_queues < adapter->num_rx_queues) {
+ /* We didn't get MSI-X, so we need to release everything,
+ * set our Rx queue count to num_rx_queues, and redo the
+ * whole init process.
+ */
+ ixgbe_free_irq(adapter);
+ if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
+ }
+ ixgbe_free_all_rx_resources(adapter);
+ ixgbe_free_all_tx_resources(adapter);
+ adapter->num_rx_queues = num_rx_queues;
+
+ /* Reset the hardware, and start over. */
+ ixgbe_reset(adapter);
+
+ goto try_intr_reinit;
+ }
+
+ err = ixgbe_up_complete(adapter);
+ if (err)
+ goto err_up;
+
+ return 0;
+
+err_up:
+ ixgbe_free_irq(adapter);
+err_req_irq:
+ ixgbe_free_all_rx_resources(adapter);
+err_setup_rx:
+ ixgbe_free_all_tx_resources(adapter);
+err_setup_tx:
+ ixgbe_reset(adapter);
+
+ return err;
+}
+
+/**
+ * ixgbe_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int ixgbe_close(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 ctrl_ext;
+
+ ixgbe_down(adapter);
+ ixgbe_free_irq(adapter);
+
+ ixgbe_free_all_tx_resources(adapter);
+ ixgbe_free_all_rx_resources(adapter);
+
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+ ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+
+ return 0;
+}
+
+/**
+ * ixgbe_update_stats - Update the board statistics counters.
+ * @adapter: board private structure
+ **/
+void ixgbe_update_stats(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 good_rx, missed_rx, bprc;
+
+ adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+ good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC);
+ missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7));
+ adapter->stats.gprc += (good_rx - missed_rx);
+
+ adapter->stats.mpc[0] += missed_rx;
+ adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+ bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
+ adapter->stats.bprc += bprc;
+ adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
+ adapter->stats.mprc -= bprc;
+ adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
+ adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
+ adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
+ adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
+ adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
+ adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
+ adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
+
+ adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
+ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+ adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+ adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+ adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+ adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+ adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
+ adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0));
+ adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+ adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
+ adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
+ adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+ adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
+ adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+ adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
+ adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
+ adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
+ adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
+ adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
+ adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+ adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
+
+ /* Fill out the OS statistics structure */
+ adapter->net_stats.rx_packets = adapter->stats.gprc;
+ adapter->net_stats.tx_packets = adapter->stats.gptc;
+ adapter->net_stats.rx_bytes = adapter->stats.gorc;
+ adapter->net_stats.tx_bytes = adapter->stats.gotc;
+ adapter->net_stats.multicast = adapter->stats.mprc;
+
+ /* Rx Errors */
+ adapter->net_stats.rx_errors = adapter->stats.crcerrs +
+ adapter->stats.rlec;
+ adapter->net_stats.rx_dropped = 0;
+ adapter->net_stats.rx_length_errors = adapter->stats.rlec;
+ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+ adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0];
+
+}
+
+/**
+ * ixgbe_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void ixgbe_watchdog(unsigned long data)
+{
+ struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+ struct net_device *netdev = adapter->netdev;
+ bool link_up;
+ u32 link_speed = 0;
+
+ adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up);
+
+ if (link_up) {
+ if (!netif_carrier_ok(netdev)) {
+ u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+ u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS);
+#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
+#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
+ DPRINTK(LINK, INFO, "NIC Link is Up %s, "
+ "Flow Control: %s\n",
+ (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+ "10 Gbps" :
+ (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+ "1 Gpbs" : "unknown speed")),
+ ((FLOW_RX && FLOW_TX) ? "RX/TX" :
+ (FLOW_RX ? "RX" :
+ (FLOW_TX ? "TX" : "None"))));
+
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ } else {
+ /* Force detection of hung controller */
+ adapter->detect_tx_hung = true;
+ }
+ } else {
+ if (netif_carrier_ok(netdev)) {
+ DPRINTK(LINK, INFO, "NIC Link is Down\n");
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ }
+
+ ixgbe_update_stats(adapter);
+
+ /* Reset the timer */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 2 * HZ));
+}
+
+#define IXGBE_MAX_TXD_PWR 14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+ (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
+
+static int ixgbe_tso(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+ u32 tx_flags, u8 *hdr_len)
+{
+ struct ixgbe_adv_tx_context_desc *context_desc;
+ unsigned int i;
+ int err;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+ u32 mss_l4len_idx = 0, l4len;
+ *hdr_len = 0;
+
+ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+ return err;
+ }
+ l4len = tcp_hdrlen(skb);
+ *hdr_len += l4len;
+
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+ iph->tot_len = 0;
+ iph->check = 0;
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ adapter->hw_tso_ctxt++;
+ } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
+ adapter->hw_tso6_ctxt++;
+ }
+
+ i = tx_ring->next_to_use;
+
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+ /* VLAN MACLEN IPLEN */
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ vlan_macip_lens |=
+ (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+ vlan_macip_lens |= ((skb_network_offset(skb)) <<
+ IXGBE_ADVTXD_MACLEN_SHIFT);
+ *hdr_len += skb_network_offset(skb);
+ vlan_macip_lens |=
+ (skb_transport_header(skb) - skb_network_header(skb));
+ *hdr_len +=
+ (skb_transport_header(skb) - skb_network_header(skb));
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+
+ /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+ type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+ IXGBE_ADVTXD_DTYP_CTXT);
+
+ if (skb->protocol == ntohs(ETH_P_IP))
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+
+ /* MSS L4LEN IDX */
+ mss_l4len_idx |=
+ (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT);
+ mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT);
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return true;
+ }
+ return false;
+}
+
+static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags)
+{
+ struct ixgbe_adv_tx_context_desc *context_desc;
+ unsigned int i;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL ||
+ (tx_flags & IXGBE_TX_FLAGS_VLAN)) {
+ i = tx_ring->next_to_use;
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ vlan_macip_lens |=
+ (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+ vlan_macip_lens |= (skb_network_offset(skb) <<
+ IXGBE_ADVTXD_MACLEN_SHIFT);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ vlan_macip_lens |= (skb_transport_header(skb) -
+ skb_network_header(skb));
+
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+
+ type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+ IXGBE_ADVTXD_DTYP_CTXT);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb->protocol == ntohs(ETH_P_IP))
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+
+ if (skb->sk->sk_protocol == IPPROTO_TCP)
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ }
+
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+ context_desc->mss_l4len_idx = 0;
+
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+ adapter->hw_csum_tx_good++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return true;
+ }
+ return false;
+}
+
+static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb, unsigned int first)
+{
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ unsigned int len = skb->len;
+ unsigned int offset = 0, size, count = 0, i;
+ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ unsigned int f;
+
+ len -= skb->data_len;
+
+ i = tx_ring->next_to_use;
+
+ while (len) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
+
+ tx_buffer_info->length = size;
+ tx_buffer_info->dma = pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size, PCI_DMA_TODEVICE);
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ len = frag->size;
+ offset = frag->page_offset;
+
+ while (len) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
+
+ tx_buffer_info->length = size;
+ tx_buffer_info->dma = pci_map_page(adapter->pdev,
+ frag->page,
+ offset,
+ size, PCI_DMA_TODEVICE);
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+ }
+ if (i == 0)
+ i = tx_ring->count - 1;
+ else
+ i = i - 1;
+ tx_ring->tx_buffer_info[i].skb = skb;
+ tx_ring->tx_buffer_info[first].next_to_watch = i;
+
+ return count;
+}
+
+static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ int tx_flags, int count, u32 paylen, u8 hdr_len)
+{
+ union ixgbe_adv_tx_desc *tx_desc = NULL;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ u32 olinfo_status = 0, cmd_type_len = 0;
+ unsigned int i;
+ u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS;
+
+ cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
+
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
+
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE;
+
+ if (tx_flags & IXGBE_TX_FLAGS_TSO) {
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
+
+ olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ if (tx_flags & IXGBE_TX_FLAGS_IPV4)
+ olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ } else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
+ olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
+ i = tx_ring->next_to_use;
+ while (count--) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
+ tx_desc->read.cmd_type_len =
+ cpu_to_le32(cmd_type_len | tx_buffer_info->length);
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+
+ tx_ring->next_to_use = i;
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_ring *tx_ring;
+ unsigned int len = skb->len;
+ unsigned int first;
+ unsigned int tx_flags = 0;
+ unsigned long flags = 0;
+ u8 hdr_len;
+ int tso;
+ unsigned int mss = 0;
+ int count = 0;
+ unsigned int f;
+ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ len -= skb->data_len;
+
+ tx_ring = adapter->tx_ring;
+
+ if (skb->len <= 0) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+ mss = skb_shinfo(skb)->gso_size;
+
+ if (mss)
+ count++;
+ else if (skb->ip_summed == CHECKSUM_PARTIAL)
+ count++;
+
+ count += TXD_USE_COUNT(len);
+ for (f = 0; f < nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+
+ spin_lock_irqsave(&tx_ring->tx_lock, flags);
+ if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) {
+ adapter->tx_busy++;
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= IXGBE_TX_FLAGS_VLAN;
+ tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
+ }
+
+ if (skb->protocol == ntohs(ETH_P_IP))
+ tx_flags |= IXGBE_TX_FLAGS_IPV4;
+ first = tx_ring->next_to_use;
+ tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+ if (tso < 0) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (tso)
+ tx_flags |= IXGBE_TX_FLAGS_TSO;
+ else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+ (skb->ip_summed == CHECKSUM_PARTIAL))
+ tx_flags |= IXGBE_TX_FLAGS_CSUM;
+
+ ixgbe_tx_queue(adapter, tx_ring, tx_flags,
+ ixgbe_tx_map(adapter, tx_ring, skb, first),
+ skb->len, hdr_len);
+
+ netdev->trans_start = jiffies;
+
+ spin_lock_irqsave(&tx_ring->tx_lock, flags);
+ /* Make sure there is space in the ring for the next send. */
+ if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED)
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * ixgbe_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ /* only return the current stats */
+ return &adapter->net_stats;
+}
+
+/**
+ * ixgbe_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_set_mac(struct net_device *netdev, void *p)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+ ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ixgbe_netpoll(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ disable_irq(adapter->pdev->irq);
+ adapter->flags |= IXGBE_FLAG_IN_NETPOLL;
+ ixgbe_intr(adapter->pdev->irq, netdev);
+ adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL;
+ enable_irq(adapter->pdev->irq);
+}
+#endif
+
+/**
+ * ixgbe_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ixgbe_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * ixgbe_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit ixgbe_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct ixgbe_adapter *adapter = NULL;
+ struct ixgbe_hw *hw;
+ const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
+ unsigned long mmio_start, mmio_len;
+ static int cards_found;
+ int i, err, pci_using_dac;
+ u16 link_status, link_speed, link_width;
+ u32 part_num;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
+ !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "No usable DMA "
+ "configuration, aborting\n");
+ goto err_dma;
+ }
+ }
+ pci_using_dac = 0;
+ }
+
+ err = pci_request_regions(pdev, ixgbe_driver_name);
+ if (err) {
+ dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err);
+ goto err_pci_reg;
+ }
+
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct ixgbe_adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ hw = &adapter->hw;
+ hw->back = adapter;
+ adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+
+ hw->hw_addr = ioremap(mmio_start, mmio_len);
+ if (!hw->hw_addr) {
+ err = -EIO;
+ goto err_ioremap;
+ }
+
+ for (i = 1; i <= 5; i++) {
+ if (pci_resource_len(pdev, i) == 0)
+ continue;
+ }
+
+ netdev->open = &ixgbe_open;
+ netdev->stop = &ixgbe_close;
+ netdev->hard_start_xmit = &ixgbe_xmit_frame;
+ netdev->get_stats = &ixgbe_get_stats;
+ netdev->set_multicast_list = &ixgbe_set_multi;
+ netdev->set_mac_address = &ixgbe_set_mac;
+ netdev->change_mtu = &ixgbe_change_mtu;
+ ixgbe_set_ethtool_ops(netdev);
+ netdev->tx_timeout = &ixgbe_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netif_napi_add(netdev, &adapter->napi, ixgbe_clean, 64);
+ netdev->vlan_rx_register = ixgbe_vlan_rx_register;
+ netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = ixgbe_netpoll;
+#endif
+ strcpy(netdev->name, pci_name(pdev));
+
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+
+ adapter->bd_number = cards_found;
+
+ /* PCI config space info */
+ hw->vendor_id = pdev->vendor;
+ hw->device_id = pdev->device;
+ hw->revision_id = pdev->revision;
+ hw->subsystem_vendor_id = pdev->subsystem_vendor;
+ hw->subsystem_device_id = pdev->subsystem_device;
+
+ /* Setup hw api */
+ memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
+ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
+
+ err = ii->get_invariants(hw);
+ if (err)
+ goto err_hw_init;
+
+ /* setup the private structure */
+ err = ixgbe_sw_init(adapter);
+ if (err)
+ goto err_sw_init;
+
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ netdev->features |= NETIF_F_TSO;
+
+ netdev->features |= NETIF_F_TSO6;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+
+ /* make sure the EEPROM is good */
+ if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
+ dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
+
+ if (ixgbe_validate_mac_addr(netdev->dev_addr)) {
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &ixgbe_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+
+ INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
+
+ /* initialize default flow control settings */
+ hw->fc.original_type = ixgbe_fc_full;
+ hw->fc.type = ixgbe_fc_full;
+ hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
+ hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
+ hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
+
+ /* Interrupt Throttle Rate */
+ adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS);
+ adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS);
+
+ /* print bus type/speed/width info */
+ pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status);
+ link_speed = link_status & IXGBE_PCI_LINK_SPEED;
+ link_width = link_status & IXGBE_PCI_LINK_WIDTH;
+ dev_info(&pdev->dev, "(PCI Express:%s:%s) "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
+ (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
+ "Unknown"),
+ ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
+ (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
+ (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
+ (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
+ "Unknown"),
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+ ixgbe_read_part_num(hw, &part_num);
+ dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type,
+ (part_num >> 8), (part_num & 0xff));
+
+ /* reset the hardware with the new settings */
+ ixgbe_start_hw(hw);
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ strcpy(netdev->name, "eth%d");
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
+
+ dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
+ cards_found++;
+ return 0;
+
+err_register:
+err_hw_init:
+err_sw_init:
+err_eeprom:
+ iounmap(hw->hw_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * ixgbe_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ixgbe_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit ixgbe_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ set_bit(__IXGBE_DOWN, &adapter->state);
+ del_timer_sync(&adapter->watchdog_timer);
+
+ flush_scheduled_work();
+
+ unregister_netdev(netdev);
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+
+ iounmap(adapter->hw.hw_addr);
+ pci_release_regions(pdev);
+
+ free_netdev(netdev);
+
+ pci_disable_device(pdev);
+}
+
+/**
+ * ixgbe_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev->priv;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ ixgbe_down(adapter);
+ pci_disable_device(pdev);
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * ixgbe_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev->priv;
+
+ if (pci_enable_device(pdev)) {
+ DPRINTK(PROBE, ERR,
+ "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ ixgbe_reset(adapter);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * ixgbe_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void ixgbe_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev->priv;
+
+ if (netif_running(netdev)) {
+ if (ixgbe_up(adapter)) {
+ DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+
+}
+
+static struct pci_error_handlers ixgbe_err_handler = {
+ .error_detected = ixgbe_io_error_detected,
+ .slot_reset = ixgbe_io_slot_reset,
+ .resume = ixgbe_io_resume,
+};
+
+static struct pci_driver ixgbe_driver = {
+ .name = ixgbe_driver_name,
+ .id_table = ixgbe_pci_tbl,
+ .probe = ixgbe_probe,
+ .remove = __devexit_p(ixgbe_remove),
+#ifdef CONFIG_PM
+ .suspend = ixgbe_suspend,
+ .resume = ixgbe_resume,
+#endif
+ .shutdown = ixgbe_shutdown,
+ .err_handler = &ixgbe_err_handler
+};
+
+/**
+ * ixgbe_init_module - Driver Registration Routine
+ *
+ * ixgbe_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init ixgbe_init_module(void)
+{
+ int ret;
+ printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name,
+ ixgbe_driver_string, ixgbe_driver_version);
+
+ printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
+
+ ret = pci_register_driver(&ixgbe_driver);
+ return ret;
+}
+module_init(ixgbe_init_module);
+
+/**
+ * ixgbe_exit_module - Driver Exit Cleanup Routine
+ *
+ * ixgbe_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit ixgbe_exit_module(void)
+{
+ pci_unregister_driver(&ixgbe_driver);
+}
+module_exit(ixgbe_exit_module);
+
+/* ixgbe_main.c */
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
new file mode 100644
index 000000000000..8002931ae823
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -0,0 +1,494 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
+static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
+static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 phy_data);
+
+/**
+ * ixgbe_identify_phy - Get physical layer module
+ * @hw: pointer to hardware structure
+ *
+ * Determines the physical layer module found on the current adapter.
+ **/
+s32 ixgbe_identify_phy(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+ u32 phy_addr;
+
+ for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
+ if (ixgbe_validate_phy_addr(hw, phy_addr)) {
+ hw->phy.addr = phy_addr;
+ ixgbe_get_phy_id(hw);
+ hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
+ status = 0;
+ break;
+ }
+ }
+ return status;
+}
+
+/**
+ * ixgbe_validate_phy_addr - Determines phy address is valid
+ * @hw: pointer to hardware structure
+ *
+ **/
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
+{
+ u16 phy_id = 0;
+ bool valid = false;
+
+ hw->phy.addr = phy_addr;
+ ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_PHY_ID_HIGH,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &phy_id);
+
+ if (phy_id != 0xFFFF && phy_id != 0x0)
+ valid = true;
+
+ return valid;
+}
+
+/**
+ * ixgbe_get_phy_id - Get the phy type
+ * @hw: pointer to hardware structure
+ *
+ **/
+static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
+{
+ u32 status;
+ u16 phy_id_high = 0;
+ u16 phy_id_low = 0;
+
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_PHY_ID_HIGH,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &phy_id_high);
+
+ if (status == 0) {
+ hw->phy.id = (u32)(phy_id_high << 16);
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_PHY_ID_LOW,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &phy_id_low);
+ hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
+ hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_get_phy_type_from_id - Get the phy type
+ * @hw: pointer to hardware structure
+ *
+ **/
+static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
+{
+ enum ixgbe_phy_type phy_type;
+
+ switch (phy_id) {
+ case TN1010_PHY_ID:
+ phy_type = ixgbe_phy_tn;
+ break;
+ case QT2022_PHY_ID:
+ phy_type = ixgbe_phy_qt;
+ break;
+ default:
+ phy_type = ixgbe_phy_unknown;
+ break;
+ }
+
+ return phy_type;
+}
+
+/**
+ * ixgbe_reset_phy - Performs a PHY reset
+ * @hw: pointer to hardware structure
+ **/
+s32 ixgbe_reset_phy(struct ixgbe_hw *hw)
+{
+ /*
+ * Perform soft PHY reset to the PHY_XS.
+ * This will cause a soft reset to the PHY
+ */
+ return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+ IXGBE_MDIO_PHY_XS_DEV_TYPE,
+ IXGBE_MDIO_PHY_XS_RESET);
+}
+
+/**
+ * ixgbe_read_phy_reg - Reads a value from a specified PHY register
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit address of PHY register to read
+ * @phy_data: Pointer to read data from PHY register
+ **/
+s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 *phy_data)
+{
+ u32 command;
+ u32 i;
+ u32 timeout = 10;
+ u32 data;
+ s32 status = 0;
+ u16 gssr;
+
+ if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+ gssr = IXGBE_GSSR_PHY1_SM;
+ else
+ gssr = IXGBE_GSSR_PHY0_SM;
+
+ if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
+ status = IXGBE_ERR_SWFW_SYNC;
+
+ if (status == 0) {
+ /* Setup and write the address cycle command */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle completed.
+ * The MDI Command bit will clear when the operation is
+ * complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+ break;
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+ hw_dbg(hw, "PHY address command did not complete.\n");
+ status = IXGBE_ERR_PHY;
+ }
+
+ if (status == 0) {
+ /*
+ * Address cycle complete, setup and write the read
+ * command
+ */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle
+ * completed. The MDI Command bit will clear when the
+ * operation is complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+ break;
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+ hw_dbg(hw,
+ "PHY read command didn't complete\n");
+ status = IXGBE_ERR_PHY;
+ } else {
+ /*
+ * Read operation is complete. Get the data
+ * from MSRWD
+ */
+ data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+ data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
+ *phy_data = (u16)(data);
+ }
+ }
+
+ ixgbe_release_swfw_sync(hw, gssr);
+ }
+ return status;
+}
+
+/**
+ * ixgbe_write_phy_reg - Writes a value to specified PHY register
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit PHY register to write
+ * @device_type: 5 bit device type
+ * @phy_data: Data to write to the PHY register
+ **/
+static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 phy_data)
+{
+ u32 command;
+ u32 i;
+ u32 timeout = 10;
+ s32 status = 0;
+ u16 gssr;
+
+ if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+ gssr = IXGBE_GSSR_PHY1_SM;
+ else
+ gssr = IXGBE_GSSR_PHY0_SM;
+
+ if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
+ status = IXGBE_ERR_SWFW_SYNC;
+
+ if (status == 0) {
+ /* Put the data in the MDI single read and write data register*/
+ IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
+
+ /* Setup and write the address cycle command */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle completed.
+ * The MDI Command bit will clear when the operation is
+ * complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
+ hw_dbg(hw, "PHY address cmd didn't complete\n");
+ break;
+ }
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+ status = IXGBE_ERR_PHY;
+
+ if (status == 0) {
+ /*
+ * Address cycle complete, setup and write the write
+ * command
+ */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle
+ * completed. The MDI Command bit will clear when the
+ * operation is complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
+ hw_dbg(hw, "PHY write command did not "
+ "complete.\n");
+ break;
+ }
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+ status = IXGBE_ERR_PHY;
+ }
+
+ ixgbe_release_swfw_sync(hw, gssr);
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_tnx_phy_link - Set and restart autoneg
+ * @hw: pointer to hardware structure
+ *
+ * Restart autonegotiation and PHY and waits for completion.
+ **/
+s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_NOT_IMPLEMENTED;
+ u32 time_out;
+ u32 max_time_out = 10;
+ u16 autoneg_speed_selection_register = 0x10;
+ u16 autoneg_restart_mask = 0x0200;
+ u16 autoneg_complete_mask = 0x0020;
+ u16 autoneg_reg = 0;
+
+ /*
+ * Set advertisement settings in PHY based on autoneg_advertised
+ * settings. If autoneg_advertised = 0, then advertise default values
+ * txn devices cannot be "forced" to a autoneg 10G and fail. But can
+ * for a 1G.
+ */
+ ixgbe_read_phy_reg(hw,
+ autoneg_speed_selection_register,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
+ autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
+ else
+ autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
+
+ ixgbe_write_phy_reg(hw,
+ autoneg_speed_selection_register,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ autoneg_reg);
+
+
+ /* Restart PHY autonegotiation and wait for completion */
+ ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_AUTO_NEG_CONTROL,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ autoneg_reg |= autoneg_restart_mask;
+
+ ixgbe_write_phy_reg(hw,
+ IXGBE_MDIO_AUTO_NEG_CONTROL,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ autoneg_reg);
+
+ /* Wait for autonegotiation to finish */
+ for (time_out = 0; time_out < max_time_out; time_out++) {
+ udelay(10);
+ /* Restart PHY autonegotiation and wait for completion */
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ autoneg_reg &= autoneg_complete_mask;
+ if (autoneg_reg == autoneg_complete_mask) {
+ status = 0;
+ break;
+ }
+ }
+
+ if (time_out == max_time_out)
+ status = IXGBE_ERR_LINK_SETUP;
+
+ return status;
+}
+
+/**
+ * ixgbe_check_tnx_phy_link - Determine link and speed status
+ * @hw: pointer to hardware structure
+ *
+ * Reads the VS1 register to determine if link is up and the current speed for
+ * the PHY.
+ **/
+s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up)
+{
+ s32 status = 0;
+ u32 time_out;
+ u32 max_time_out = 10;
+ u16 phy_link = 0;
+ u16 phy_speed = 0;
+ u16 phy_data = 0;
+
+ /* Initialize speed and link to default case */
+ *link_up = false;
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+
+ /*
+ * Check current speed and link status of the PHY register.
+ * This is a vendor specific register and may have to
+ * be changed for other copper PHYs.
+ */
+ for (time_out = 0; time_out < max_time_out; time_out++) {
+ udelay(10);
+ if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
+ *link_up = true;
+ if (phy_speed ==
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ break;
+ } else {
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &phy_data);
+ phy_link = phy_data &
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
+ phy_speed = phy_data &
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if autonegotiation enabled
+ **/
+s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ /*
+ * Clear autoneg_advertised and set new values based on input link
+ * speed.
+ */
+ hw->phy.autoneg_advertised = 0;
+
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+
+ /* Setup link based on the new speed settings */
+ ixgbe_setup_tnx_phy_link(hw);
+
+ return 0;
+}
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
new file mode 100644
index 000000000000..199e8f670f3a
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_PHY_H_
+#define _IXGBE_PHY_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw);
+s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw);
+s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
+s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
+ bool autoneg_wait_to_complete);
+s32 ixgbe_identify_phy(struct ixgbe_hw *hw);
+s32 ixgbe_reset_phy(struct ixgbe_hw *hw);
+s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 *phy_data);
+
+/* PHY specific */
+s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw);
+s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
+s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
+ bool autoneg_wait_to_complete);
+
+#endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
new file mode 100644
index 000000000000..fdcde16a2a99
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -0,0 +1,1332 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_TYPE_H_
+#define _IXGBE_TYPE_H_
+
+#include <linux/types.h>
+
+/* Vendor ID */
+#define IXGBE_INTEL_VENDOR_ID 0x8086
+
+/* Device IDs */
+#define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6
+#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
+#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10C8
+#define IXGBE_DEV_ID_82598EB_CX4 0x10DD
+
+/* General Registers */
+#define IXGBE_CTRL 0x00000
+#define IXGBE_STATUS 0x00008
+#define IXGBE_CTRL_EXT 0x00018
+#define IXGBE_ESDP 0x00020
+#define IXGBE_EODSDP 0x00028
+#define IXGBE_LEDCTL 0x00200
+#define IXGBE_FRTIMER 0x00048
+#define IXGBE_TCPTIMER 0x0004C
+
+/* NVM Registers */
+#define IXGBE_EEC 0x10010
+#define IXGBE_EERD 0x10014
+#define IXGBE_FLA 0x1001C
+#define IXGBE_EEMNGCTL 0x10110
+#define IXGBE_EEMNGDATA 0x10114
+#define IXGBE_FLMNGCTL 0x10118
+#define IXGBE_FLMNGDATA 0x1011C
+#define IXGBE_FLMNGCNT 0x10120
+#define IXGBE_FLOP 0x1013C
+#define IXGBE_GRC 0x10200
+
+/* Interrupt Registers */
+#define IXGBE_EICR 0x00800
+#define IXGBE_EICS 0x00808
+#define IXGBE_EIMS 0x00880
+#define IXGBE_EIMC 0x00888
+#define IXGBE_EIAC 0x00810
+#define IXGBE_EIAM 0x00890
+#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */
+#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */
+#define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */
+#define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */
+#define IXGBE_PBACL 0x11068
+#define IXGBE_GPIE 0x00898
+
+/* Flow Control Registers */
+#define IXGBE_PFCTOP 0x03008
+#define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */
+#define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */
+#define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */
+#define IXGBE_FCRTV 0x032A0
+#define IXGBE_TFCS 0x0CE00
+
+/* Receive DMA Registers */
+#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/
+#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40))
+#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40))
+#define IXGBE_RDH(_i) (0x01010 + ((_i) * 0x40))
+#define IXGBE_RDT(_i) (0x01018 + ((_i) * 0x40))
+#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40))
+#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40))
+#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4))
+ /* array of 16 (0x02100-0x0213C) */
+#define IXGBE_DCA_RXCTRL(_i) (0x02200 + ((_i) * 4))
+ /* array of 16 (0x02200-0x0223C) */
+#define IXGBE_RDRXCTL 0x02F00
+#define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4))
+ /* 8 of these 0x03C00 - 0x03C1C */
+#define IXGBE_RXCTRL 0x03000
+#define IXGBE_DROPEN 0x03D04
+#define IXGBE_RXPBSIZE_SHIFT 10
+
+/* Receive Registers */
+#define IXGBE_RXCSUM 0x05000
+#define IXGBE_RFCTL 0x05008
+#define IXGBE_MTA(_i) (0x05200 + ((_i) * 4))
+ /* Multicast Table Array - 128 entries */
+#define IXGBE_RAL(_i) (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */
+#define IXGBE_RAH(_i) (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */
+#define IXGBE_PSRTYPE 0x05480
+ /* 0x5480-0x54BC Packet split receive type */
+#define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4))
+ /* array of 4096 1-bit vlan filters */
+#define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4))
+ /*array of 4096 4-bit vlan vmdq indicies */
+#define IXGBE_FCTRL 0x05080
+#define IXGBE_VLNCTRL 0x05088
+#define IXGBE_MCSTCTRL 0x05090
+#define IXGBE_MRQC 0x05818
+#define IXGBE_VMD_CTL 0x0581C
+#define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_IMIRVP 0x05AC0
+#define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */
+#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */
+
+/* Transmit DMA registers */
+#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/
+#define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40))
+#define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40))
+#define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40))
+#define IXGBE_TDT(_i) (0x06018 + ((_i) * 0x40))
+#define IXGBE_TXDCTL(_i) (0x06028 + ((_i) * 0x40))
+#define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40))
+#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40))
+#define IXGBE_DTXCTL 0x07E00
+#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4))
+ /* there are 16 of these (0-15) */
+#define IXGBE_TIPG 0x0CB00
+#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04))
+ /* there are 8 of these */
+#define IXGBE_MNGTXMAP 0x0CD10
+#define IXGBE_TIPG_FIBER_DEFAULT 3
+#define IXGBE_TXPBSIZE_SHIFT 10
+
+/* Wake up registers */
+#define IXGBE_WUC 0x05800
+#define IXGBE_WUFC 0x05808
+#define IXGBE_WUS 0x05810
+#define IXGBE_IPAV 0x05838
+#define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */
+#define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */
+#define IXGBE_WUPL 0x05900
+#define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */
+#define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */
+
+/* Music registers */
+#define IXGBE_RMCS 0x03D00
+#define IXGBE_DPMCS 0x07F40
+#define IXGBE_PDPMCS 0x0CD00
+#define IXGBE_RUPPBMR 0x050A0
+#define IXGBE_RT2CR(_i) (0x03C20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RT2SR(_i) (0x03C40 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TDTQ2TCCR(_i) (0x0602C + ((_i) * 0x40)) /* 8 of these (0-7) */
+#define IXGBE_TDTQ2TCSR(_i) (0x0622C + ((_i) * 0x40)) /* 8 of these (0-7) */
+#define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */
+
+/* Stats registers */
+#define IXGBE_CRCERRS 0x04000
+#define IXGBE_ILLERRC 0x04004
+#define IXGBE_ERRBC 0x04008
+#define IXGBE_MSPDC 0x04010
+#define IXGBE_MPC(_i) (0x03FA0 + ((_i) * 4)) /* 8 of these 3FA0-3FBC*/
+#define IXGBE_MLFC 0x04034
+#define IXGBE_MRFC 0x04038
+#define IXGBE_RLEC 0x04040
+#define IXGBE_LXONTXC 0x03F60
+#define IXGBE_LXONRXC 0x0CF60
+#define IXGBE_LXOFFTXC 0x03F68
+#define IXGBE_LXOFFRXC 0x0CF68
+#define IXGBE_PXONTXC(_i) (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/
+#define IXGBE_PXONRXC(_i) (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/
+#define IXGBE_PXOFFTXC(_i) (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/
+#define IXGBE_PXOFFRXC(_i) (0x0CF20 + ((_i) * 4)) /* 8 of these CF20-CF3C*/
+#define IXGBE_PRC64 0x0405C
+#define IXGBE_PRC127 0x04060
+#define IXGBE_PRC255 0x04064
+#define IXGBE_PRC511 0x04068
+#define IXGBE_PRC1023 0x0406C
+#define IXGBE_PRC1522 0x04070
+#define IXGBE_GPRC 0x04074
+#define IXGBE_BPRC 0x04078
+#define IXGBE_MPRC 0x0407C
+#define IXGBE_GPTC 0x04080
+#define IXGBE_GORCL 0x04088
+#define IXGBE_GORCH 0x0408C
+#define IXGBE_GOTCL 0x04090
+#define IXGBE_GOTCH 0x04094
+#define IXGBE_RNBC(_i) (0x03FC0 + ((_i) * 4)) /* 8 of these 3FC0-3FDC*/
+#define IXGBE_RUC 0x040A4
+#define IXGBE_RFC 0x040A8
+#define IXGBE_ROC 0x040AC
+#define IXGBE_RJC 0x040B0
+#define IXGBE_MNGPRC 0x040B4
+#define IXGBE_MNGPDC 0x040B8
+#define IXGBE_MNGPTC 0x0CF90
+#define IXGBE_TORL 0x040C0
+#define IXGBE_TORH 0x040C4
+#define IXGBE_TPR 0x040D0
+#define IXGBE_TPT 0x040D4
+#define IXGBE_PTC64 0x040D8
+#define IXGBE_PTC127 0x040DC
+#define IXGBE_PTC255 0x040E0
+#define IXGBE_PTC511 0x040E4
+#define IXGBE_PTC1023 0x040E8
+#define IXGBE_PTC1522 0x040EC
+#define IXGBE_MPTC 0x040F0
+#define IXGBE_BPTC 0x040F4
+#define IXGBE_XEC 0x04120
+
+#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */
+#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */
+
+#define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */
+
+/* Management */
+#define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MFUTP(_i) (0x05030 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MANC 0x05820
+#define IXGBE_MFVAL 0x05824
+#define IXGBE_MANC2H 0x05860
+#define IXGBE_MDEF(_i) (0x05890 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MIPAF 0x058B0
+#define IXGBE_MMAL(_i) (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */
+#define IXGBE_MMAH(_i) (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */
+#define IXGBE_FTFT 0x09400 /* 0x9400-0x97FC */
+
+/* ARC Subsystem registers */
+#define IXGBE_HICR 0x15F00
+#define IXGBE_FWSTS 0x15F0C
+#define IXGBE_HSMC0R 0x15F04
+#define IXGBE_HSMC1R 0x15F08
+#define IXGBE_SWSR 0x15F10
+#define IXGBE_HFDR 0x15FE8
+#define IXGBE_FLEX_MNG 0x15800 /* 0x15800 - 0x15EFC */
+
+/* PCI-E registers */
+#define IXGBE_GCR 0x11000
+#define IXGBE_GTV 0x11004
+#define IXGBE_FUNCTAG 0x11008
+#define IXGBE_GLT 0x1100C
+#define IXGBE_GSCL_1 0x11010
+#define IXGBE_GSCL_2 0x11014
+#define IXGBE_GSCL_3 0x11018
+#define IXGBE_GSCL_4 0x1101C
+#define IXGBE_GSCN_0 0x11020
+#define IXGBE_GSCN_1 0x11024
+#define IXGBE_GSCN_2 0x11028
+#define IXGBE_GSCN_3 0x1102C
+#define IXGBE_FACTPS 0x10150
+#define IXGBE_PCIEANACTL 0x11040
+#define IXGBE_SWSM 0x10140
+#define IXGBE_FWSM 0x10148
+#define IXGBE_GSSR 0x10160
+#define IXGBE_MREVID 0x11064
+#define IXGBE_DCA_ID 0x11070
+#define IXGBE_DCA_CTRL 0x11074
+
+/* Diagnostic Registers */
+#define IXGBE_RDSTATCTL 0x02C20
+#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */
+#define IXGBE_RDHMPN 0x02F08
+#define IXGBE_RIC_DW0 0x02F10
+#define IXGBE_RIC_DW1 0x02F14
+#define IXGBE_RIC_DW2 0x02F18
+#define IXGBE_RIC_DW3 0x02F1C
+#define IXGBE_RDPROBE 0x02F20
+#define IXGBE_TDSTATCTL 0x07C20
+#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */
+#define IXGBE_TDHMPN 0x07F08
+#define IXGBE_TIC_DW0 0x07F10
+#define IXGBE_TIC_DW1 0x07F14
+#define IXGBE_TIC_DW2 0x07F18
+#define IXGBE_TIC_DW3 0x07F1C
+#define IXGBE_TDPROBE 0x07F20
+#define IXGBE_TXBUFCTRL 0x0C600
+#define IXGBE_TXBUFDATA0 0x0C610
+#define IXGBE_TXBUFDATA1 0x0C614
+#define IXGBE_TXBUFDATA2 0x0C618
+#define IXGBE_TXBUFDATA3 0x0C61C
+#define IXGBE_RXBUFCTRL 0x03600
+#define IXGBE_RXBUFDATA0 0x03610
+#define IXGBE_RXBUFDATA1 0x03614
+#define IXGBE_RXBUFDATA2 0x03618
+#define IXGBE_RXBUFDATA3 0x0361C
+#define IXGBE_PCIE_DIAG(_i) (0x11090 + ((_i) * 4)) /* 8 of these */
+#define IXGBE_RFVAL 0x050A4
+#define IXGBE_MDFTC1 0x042B8
+#define IXGBE_MDFTC2 0x042C0
+#define IXGBE_MDFTFIFO1 0x042C4
+#define IXGBE_MDFTFIFO2 0x042C8
+#define IXGBE_MDFTS 0x042CC
+#define IXGBE_RXDATAWRPTR(_i) (0x03700 + ((_i) * 4)) /* 8 of these 3700-370C*/
+#define IXGBE_RXDESCWRPTR(_i) (0x03710 + ((_i) * 4)) /* 8 of these 3710-371C*/
+#define IXGBE_RXDATARDPTR(_i) (0x03720 + ((_i) * 4)) /* 8 of these 3720-372C*/
+#define IXGBE_RXDESCRDPTR(_i) (0x03730 + ((_i) * 4)) /* 8 of these 3730-373C*/
+#define IXGBE_TXDATAWRPTR(_i) (0x0C700 + ((_i) * 4)) /* 8 of these C700-C70C*/
+#define IXGBE_TXDESCWRPTR(_i) (0x0C710 + ((_i) * 4)) /* 8 of these C710-C71C*/
+#define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/
+#define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/
+#define IXGBE_PCIEECCCTL 0x1106C
+#define IXGBE_PBTXECC 0x0C300
+#define IXGBE_PBRXECC 0x03300
+#define IXGBE_GHECCR 0x110B0
+
+/* MAC Registers */
+#define IXGBE_PCS1GCFIG 0x04200
+#define IXGBE_PCS1GLCTL 0x04208
+#define IXGBE_PCS1GLSTA 0x0420C
+#define IXGBE_PCS1GDBG0 0x04210
+#define IXGBE_PCS1GDBG1 0x04214
+#define IXGBE_PCS1GANA 0x04218
+#define IXGBE_PCS1GANLP 0x0421C
+#define IXGBE_PCS1GANNP 0x04220
+#define IXGBE_PCS1GANLPNP 0x04224
+#define IXGBE_HLREG0 0x04240
+#define IXGBE_HLREG1 0x04244
+#define IXGBE_PAP 0x04248
+#define IXGBE_MACA 0x0424C
+#define IXGBE_APAE 0x04250
+#define IXGBE_ARD 0x04254
+#define IXGBE_AIS 0x04258
+#define IXGBE_MSCA 0x0425C
+#define IXGBE_MSRWD 0x04260
+#define IXGBE_MLADD 0x04264
+#define IXGBE_MHADD 0x04268
+#define IXGBE_TREG 0x0426C
+#define IXGBE_PCSS1 0x04288
+#define IXGBE_PCSS2 0x0428C
+#define IXGBE_XPCSS 0x04290
+#define IXGBE_SERDESC 0x04298
+#define IXGBE_MACS 0x0429C
+#define IXGBE_AUTOC 0x042A0
+#define IXGBE_LINKS 0x042A4
+#define IXGBE_AUTOC2 0x042A8
+#define IXGBE_AUTOC3 0x042AC
+#define IXGBE_ANLP1 0x042B0
+#define IXGBE_ANLP2 0x042B4
+#define IXGBE_ATLASCTL 0x04800
+
+/* RSCCTL Bit Masks */
+#define IXGBE_RSCCTL_RSCEN 0x01
+#define IXGBE_RSCCTL_MAXDESC_1 0x00
+#define IXGBE_RSCCTL_MAXDESC_4 0x04
+#define IXGBE_RSCCTL_MAXDESC_8 0x08
+#define IXGBE_RSCCTL_MAXDESC_16 0x0C
+
+/* CTRL Bit Masks */
+#define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */
+#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */
+#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */
+
+/* FACTPS */
+#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */
+
+/* MHADD Bit Masks */
+#define IXGBE_MHADD_MFS_MASK 0xFFFF0000
+#define IXGBE_MHADD_MFS_SHIFT 16
+
+/* Extended Device Control */
+#define IXGBE_CTRL_EXT_NS_DIS 0x00010000 /* No Snoop disable */
+#define IXGBE_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+
+/* Direct Cache Access (DCA) definitions */
+#define IXGBE_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */
+#define IXGBE_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
+
+#define IXGBE_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
+#define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
+
+#define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
+#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
+#define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
+
+#define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */
+#define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */
+
+/* MSCA Bit Masks */
+#define IXGBE_MSCA_NP_ADDR_MASK 0x0000FFFF /* MDI Address (new protocol) */
+#define IXGBE_MSCA_NP_ADDR_SHIFT 0
+#define IXGBE_MSCA_DEV_TYPE_MASK 0x001F0000 /* Device Type (new protocol) */
+#define IXGBE_MSCA_DEV_TYPE_SHIFT 16 /* Register Address (old protocol */
+#define IXGBE_MSCA_PHY_ADDR_MASK 0x03E00000 /* PHY Address mask */
+#define IXGBE_MSCA_PHY_ADDR_SHIFT 21 /* PHY Address shift*/
+#define IXGBE_MSCA_OP_CODE_MASK 0x0C000000 /* OP CODE mask */
+#define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */
+#define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */
+#define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */
+#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */
+#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/
+#define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */
+#define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */
+#define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */
+#define IXGBE_MSCA_OLD_PROTOCOL 0x10000000 /* ST CODE 01 (old protocol) */
+#define IXGBE_MSCA_MDI_COMMAND 0x40000000 /* Initiate MDI command */
+#define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */
+
+/* MSRWD bit masks */
+#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF
+#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0
+#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000
+#define IXGBE_MSRWD_READ_DATA_SHIFT 16
+
+/* Atlas registers */
+#define IXGBE_ATLAS_PDN_LPBK 0x24
+#define IXGBE_ATLAS_PDN_10G 0xB
+#define IXGBE_ATLAS_PDN_1G 0xC
+#define IXGBE_ATLAS_PDN_AN 0xD
+
+/* Atlas bit masks */
+#define IXGBE_ATLASCTL_WRITE_CMD 0x00010000
+#define IXGBE_ATLAS_PDN_TX_REG_EN 0x10
+#define IXGBE_ATLAS_PDN_TX_10G_QL_ALL 0xF0
+#define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0
+#define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0
+
+/* Device Type definitions for new protocol MDIO commands */
+#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1
+#define IXGBE_MDIO_PCS_DEV_TYPE 0x3
+#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4
+#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */
+
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS 0x0010 /* 0 - 10G, 1 - 1G */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010
+
+#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */
+#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */
+#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */
+#define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */
+#define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/
+#define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/
+#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Abilty Reg */
+#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */
+#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */
+
+#define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0
+#define IXGBE_MAX_PHY_ADDR 32
+
+/* PHY IDs*/
+#define TN1010_PHY_ID 0x00A19410
+#define QT2022_PHY_ID 0x0043A400
+
+/* General purpose Interrupt Enable */
+#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */
+#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */
+#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */
+#define IXGBE_GPIE_EIAME 0x40000000
+#define IXGBE_GPIE_PBA_SUPPORT 0x80000000
+
+/* Transmit Flow Control status */
+#define IXGBE_TFCS_TXOFF 0x00000001
+#define IXGBE_TFCS_TXOFF0 0x00000100
+#define IXGBE_TFCS_TXOFF1 0x00000200
+#define IXGBE_TFCS_TXOFF2 0x00000400
+#define IXGBE_TFCS_TXOFF3 0x00000800
+#define IXGBE_TFCS_TXOFF4 0x00001000
+#define IXGBE_TFCS_TXOFF5 0x00002000
+#define IXGBE_TFCS_TXOFF6 0x00004000
+#define IXGBE_TFCS_TXOFF7 0x00008000
+
+/* TCP Timer */
+#define IXGBE_TCPTIMER_KS 0x00000100
+#define IXGBE_TCPTIMER_COUNT_ENABLE 0x00000200
+#define IXGBE_TCPTIMER_COUNT_FINISH 0x00000400
+#define IXGBE_TCPTIMER_LOOP 0x00000800
+#define IXGBE_TCPTIMER_DURATION_MASK 0x000000FF
+
+/* HLREG0 Bit Masks */
+#define IXGBE_HLREG0_TXCRCEN 0x00000001 /* bit 0 */
+#define IXGBE_HLREG0_RXCRCSTRP 0x00000002 /* bit 1 */
+#define IXGBE_HLREG0_JUMBOEN 0x00000004 /* bit 2 */
+#define IXGBE_HLREG0_TXPADEN 0x00000400 /* bit 10 */
+#define IXGBE_HLREG0_TXPAUSEEN 0x00001000 /* bit 12 */
+#define IXGBE_HLREG0_RXPAUSEEN 0x00004000 /* bit 14 */
+#define IXGBE_HLREG0_LPBK 0x00008000 /* bit 15 */
+#define IXGBE_HLREG0_MDCSPD 0x00010000 /* bit 16 */
+#define IXGBE_HLREG0_CONTMDC 0x00020000 /* bit 17 */
+#define IXGBE_HLREG0_CTRLFLTR 0x00040000 /* bit 18 */
+#define IXGBE_HLREG0_PREPEND 0x00F00000 /* bits 20-23 */
+#define IXGBE_HLREG0_PRIPAUSEEN 0x01000000 /* bit 24 */
+#define IXGBE_HLREG0_RXPAUSERECDA 0x06000000 /* bits 25-26 */
+#define IXGBE_HLREG0_RXLNGTHERREN 0x08000000 /* bit 27 */
+#define IXGBE_HLREG0_RXPADSTRIPEN 0x10000000 /* bit 28 */
+
+/* VMD_CTL bitmasks */
+#define IXGBE_VMD_CTL_VMDQ_EN 0x00000001
+#define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002
+
+/* RDHMPN and TDHMPN bitmasks */
+#define IXGBE_RDHMPN_RDICADDR 0x007FF800
+#define IXGBE_RDHMPN_RDICRDREQ 0x00800000
+#define IXGBE_RDHMPN_RDICADDR_SHIFT 11
+#define IXGBE_TDHMPN_TDICADDR 0x003FF800
+#define IXGBE_TDHMPN_TDICRDREQ 0x00800000
+#define IXGBE_TDHMPN_TDICADDR_SHIFT 11
+
+/* Receive Checksum Control */
+#define IXGBE_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+#define IXGBE_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+
+/* FCRTL Bit Masks */
+#define IXGBE_FCRTL_XONE 0x80000000 /* bit 31, XON enable */
+#define IXGBE_FCRTH_FCEN 0x80000000 /* Rx Flow control enable */
+
+/* PAP bit masks*/
+#define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */
+
+/* RMCS Bit Masks */
+#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recylce Mode enable */
+/* Receive Arbitration Control: 0 Round Robin, 1 DFP */
+#define IXGBE_RMCS_RAC 0x00000004
+#define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */
+#define IXGBE_RMCS_TFCE_802_3X 0x00000008 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */
+
+/* Interrupt register bitmasks */
+
+/* Extended Interrupt Cause Read */
+#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */
+#define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */
+#define IXGBE_EICR_MNG 0x00400000 /* Managability Event Interrupt */
+#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */
+#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */
+#define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */
+#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
+
+/* Extended Interrupt Cause Set */
+#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */
+#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */
+#define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+/* Extended Interrupt Mask Set */
+#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */
+#define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+/* Extended Interrupt Mask Clear */
+#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */
+#define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+#define IXGBE_EIMS_ENABLE_MASK (\
+ IXGBE_EIMS_RTX_QUEUE | \
+ IXGBE_EIMS_LSC | \
+ IXGBE_EIMS_TCP_TIMER | \
+ IXGBE_EIMS_OTHER)
+
+/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */
+#define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */
+#define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */
+#define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
+#define IXGBE_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */
+#define IXGBE_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */
+#define IXGBE_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */
+#define IXGBE_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */
+#define IXGBE_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */
+#define IXGBE_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */
+#define IXGBE_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of control bits */
+
+/* Interrupt clear mask */
+#define IXGBE_IRQ_CLEAR_MASK 0xFFFFFFFF
+
+/* Interrupt Vector Allocation Registers */
+#define IXGBE_IVAR_REG_NUM 25
+#define IXGBE_IVAR_TXRX_ENTRY 96
+#define IXGBE_IVAR_RX_ENTRY 64
+#define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i))
+#define IXGBE_IVAR_TX_QUEUE(_i) (64 + (_i))
+#define IXGBE_IVAR_TX_ENTRY 32
+
+#define IXGBE_IVAR_TCP_TIMER_INDEX 96 /* 0 based index */
+#define IXGBE_IVAR_OTHER_CAUSES_INDEX 97 /* 0 based index */
+
+#define IXGBE_MSIX_VECTOR(_i) (0 + (_i))
+
+#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */
+
+/* VLAN Control Bit Masks */
+#define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */
+#define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */
+#define IXGBE_VLNCTRL_CFIEN 0x20000000 /* bit 29 */
+#define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */
+#define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */
+
+#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */
+
+/* STATUS Bit Masks */
+#define IXGBE_STATUS_LAN_ID 0x0000000C /* LAN ID */
+#define IXGBE_STATUS_GIO 0x00080000 /* GIO Master Enable Status */
+
+#define IXGBE_STATUS_LAN_ID_0 0x00000000 /* LAN ID 0 */
+#define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */
+
+/* ESDP Bit Masks */
+#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */
+#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */
+#define IXGBE_ESDP_SDP4_DIR 0x00000004 /* SDP4 IO direction */
+#define IXGBE_ESDP_SDP5_DIR 0x00000008 /* SDP5 IO direction */
+
+/* LEDCTL Bit Masks */
+#define IXGBE_LED_IVRT_BASE 0x00000040
+#define IXGBE_LED_BLINK_BASE 0x00000080
+#define IXGBE_LED_MODE_MASK_BASE 0x0000000F
+#define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i)))
+#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i))
+#define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i)
+#define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i)
+#define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i)
+
+/* LED modes */
+#define IXGBE_LED_LINK_UP 0x0
+#define IXGBE_LED_LINK_10G 0x1
+#define IXGBE_LED_MAC 0x2
+#define IXGBE_LED_FILTER 0x3
+#define IXGBE_LED_LINK_ACTIVE 0x4
+#define IXGBE_LED_LINK_1G 0x5
+#define IXGBE_LED_ON 0xE
+#define IXGBE_LED_OFF 0xF
+
+/* AUTOC Bit Masks */
+#define IXGBE_AUTOC_KX4_SUPP 0x80000000
+#define IXGBE_AUTOC_KX_SUPP 0x40000000
+#define IXGBE_AUTOC_PAUSE 0x30000000
+#define IXGBE_AUTOC_RF 0x08000000
+#define IXGBE_AUTOC_PD_TMR 0x06000000
+#define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000
+#define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000
+#define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000
+#define IXGBE_AUTOC_AN_RESTART 0x00001000
+#define IXGBE_AUTOC_FLU 0x00000001
+#define IXGBE_AUTOC_LMS_SHIFT 13
+#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+
+#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200
+#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180
+#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7
+#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9
+#define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_10G_KX4 (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_10G_CX4 (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_BX (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_KX (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+
+/* LINKS Bit Masks */
+#define IXGBE_LINKS_KX_AN_COMP 0x80000000
+#define IXGBE_LINKS_UP 0x40000000
+#define IXGBE_LINKS_SPEED 0x20000000
+#define IXGBE_LINKS_MODE 0x18000000
+#define IXGBE_LINKS_RX_MODE 0x06000000
+#define IXGBE_LINKS_TX_MODE 0x01800000
+#define IXGBE_LINKS_XGXS_EN 0x00400000
+#define IXGBE_LINKS_PCS_1G_EN 0x00200000
+#define IXGBE_LINKS_1G_AN_EN 0x00100000
+#define IXGBE_LINKS_KX_AN_IDLE 0x00080000
+#define IXGBE_LINKS_1G_SYNC 0x00040000
+#define IXGBE_LINKS_10G_ALIGN 0x00020000
+#define IXGBE_LINKS_10G_LANE_SYNC 0x00017000
+#define IXGBE_LINKS_TL_FAULT 0x00001000
+#define IXGBE_LINKS_SIGNAL 0x00000F00
+
+#define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+
+/* SW Semaphore Register bitmasks */
+#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+
+/* GSSR definitions */
+#define IXGBE_GSSR_EEP_SM 0x0001
+#define IXGBE_GSSR_PHY0_SM 0x0002
+#define IXGBE_GSSR_PHY1_SM 0x0004
+#define IXGBE_GSSR_MAC_CSR_SM 0x0008
+#define IXGBE_GSSR_FLASH_SM 0x0010
+
+/* EEC Register */
+#define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */
+#define IXGBE_EEC_CS 0x00000002 /* EEPROM Chip Select */
+#define IXGBE_EEC_DI 0x00000004 /* EEPROM Data In */
+#define IXGBE_EEC_DO 0x00000008 /* EEPROM Data Out */
+#define IXGBE_EEC_FWE_MASK 0x00000030 /* FLASH Write Enable */
+#define IXGBE_EEC_FWE_DIS 0x00000010 /* Disable FLASH writes */
+#define IXGBE_EEC_FWE_EN 0x00000020 /* Enable FLASH writes */
+#define IXGBE_EEC_FWE_SHIFT 4
+#define IXGBE_EEC_REQ 0x00000040 /* EEPROM Access Request */
+#define IXGBE_EEC_GNT 0x00000080 /* EEPROM Access Grant */
+#define IXGBE_EEC_PRES 0x00000100 /* EEPROM Present */
+#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */
+/* EEPROM Addressing bits based on type (0-small, 1-large) */
+#define IXGBE_EEC_ADDR_SIZE 0x00000400
+#define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */
+
+#define IXGBE_EEC_SIZE_SHIFT 11
+#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6
+#define IXGBE_EEPROM_OPCODE_BITS 8
+
+/* Checksum and EEPROM pointers */
+#define IXGBE_EEPROM_CHECKSUM 0x3F
+#define IXGBE_EEPROM_SUM 0xBABA
+#define IXGBE_PCIE_ANALOG_PTR 0x03
+#define IXGBE_ATLAS0_CONFIG_PTR 0x04
+#define IXGBE_ATLAS1_CONFIG_PTR 0x05
+#define IXGBE_PCIE_GENERAL_PTR 0x06
+#define IXGBE_PCIE_CONFIG0_PTR 0x07
+#define IXGBE_PCIE_CONFIG1_PTR 0x08
+#define IXGBE_CORE0_PTR 0x09
+#define IXGBE_CORE1_PTR 0x0A
+#define IXGBE_MAC0_PTR 0x0B
+#define IXGBE_MAC1_PTR 0x0C
+#define IXGBE_CSR0_CONFIG_PTR 0x0D
+#define IXGBE_CSR1_CONFIG_PTR 0x0E
+#define IXGBE_FW_PTR 0x0F
+#define IXGBE_PBANUM0_PTR 0x15
+#define IXGBE_PBANUM1_PTR 0x16
+
+/* EEPROM Commands - SPI */
+#define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */
+#define IXGBE_EEPROM_STATUS_RDY_SPI 0x01
+#define IXGBE_EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
+#define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
+#define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */
+#define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */
+/* EEPROM reset Write Enbale latch */
+#define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04
+#define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */
+#define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */
+#define IXGBE_EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */
+#define IXGBE_EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */
+#define IXGBE_EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */
+
+/* EEPROM Read Register */
+#define IXGBE_EEPROM_READ_REG_DATA 16 /* data offset in EEPROM read reg */
+#define IXGBE_EEPROM_READ_REG_DONE 2 /* Offset to READ done bit */
+#define IXGBE_EEPROM_READ_REG_START 1 /* First bit to start operation */
+#define IXGBE_EEPROM_READ_ADDR_SHIFT 2 /* Shift to the address bits */
+
+#define IXGBE_ETH_LENGTH_OF_ADDRESS 6
+
+#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
+#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+
+#ifndef IXGBE_EERD_ATTEMPTS
+/* Number of 5 microseconds we wait for EERD read to complete */
+#define IXGBE_EERD_ATTEMPTS 100000
+#endif
+
+/* PCI Bus Info */
+#define IXGBE_PCI_LINK_STATUS 0xB2
+#define IXGBE_PCI_LINK_WIDTH 0x3F0
+#define IXGBE_PCI_LINK_WIDTH_1 0x10
+#define IXGBE_PCI_LINK_WIDTH_2 0x20
+#define IXGBE_PCI_LINK_WIDTH_4 0x40
+#define IXGBE_PCI_LINK_WIDTH_8 0x80
+#define IXGBE_PCI_LINK_SPEED 0xF
+#define IXGBE_PCI_LINK_SPEED_2500 0x1
+#define IXGBE_PCI_LINK_SPEED_5000 0x2
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
+
+/* PHY Types */
+#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0
+
+/* Check whether address is multicast. This is little-endian specific check.*/
+#define IXGBE_IS_MULTICAST(Address) \
+ (bool)(((u8 *)(Address))[0] & ((u8)0x01))
+
+/* Check whether an address is broadcast. */
+#define IXGBE_IS_BROADCAST(Address) \
+ ((((u8 *)(Address))[0] == ((u8)0xff)) && \
+ (((u8 *)(Address))[1] == ((u8)0xff)))
+
+/* RAH */
+#define IXGBE_RAH_VIND_MASK 0x003C0000
+#define IXGBE_RAH_VIND_SHIFT 18
+#define IXGBE_RAH_AV 0x80000000
+
+/* Filters */
+#define IXGBE_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
+#define IXGBE_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Header split receive */
+#define IXGBE_RFCTL_ISCSI_DIS 0x00000001
+#define IXGBE_RFCTL_ISCSI_DWC_MASK 0x0000003E
+#define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1
+#define IXGBE_RFCTL_NFSW_DIS 0x00000040
+#define IXGBE_RFCTL_NFSR_DIS 0x00000080
+#define IXGBE_RFCTL_NFS_VER_MASK 0x00000300
+#define IXGBE_RFCTL_NFS_VER_SHIFT 8
+#define IXGBE_RFCTL_NFS_VER_2 0
+#define IXGBE_RFCTL_NFS_VER_3 1
+#define IXGBE_RFCTL_NFS_VER_4 2
+#define IXGBE_RFCTL_IPV6_DIS 0x00000400
+#define IXGBE_RFCTL_IPV6_XSUM_DIS 0x00000800
+#define IXGBE_RFCTL_IPFRSP_DIS 0x00004000
+#define IXGBE_RFCTL_IPV6_EX_DIS 0x00010000
+#define IXGBE_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+
+/* Transmit Config masks */
+#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */
+/* Enable short packet padding to 64 bytes */
+#define IXGBE_TX_PAD_ENABLE 0x00000400
+#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */
+/* This allows for 16K packets + 4k for vlan */
+#define IXGBE_MAX_FRAME_SZ 0x40040000
+
+#define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */
+#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */
+
+/* Receive Config masks */
+#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */
+#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */
+#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */
+
+#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
+#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
+#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */
+#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */
+#define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */
+#define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */
+/* Receive Priority Flow Control Enbale */
+#define IXGBE_FCTRL_RPFCE 0x00004000
+#define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */
+
+/* Multiple Receive Queue Control */
+#define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */
+#define IXGBE_MRQC_RSS_FIELD_MASK 0xFFFF0000
+#define IXGBE_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define IXGBE_MRQC_RSS_FIELD_IPV4 0x00020000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 0x00040000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX 0x00080000
+#define IXGBE_MRQC_RSS_FIELD_IPV6 0x00100000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
+#define IXGBE_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000
+
+#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */
+#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+
+/* Receive Descriptor bit definitions */
+#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */
+#define IXGBE_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
+#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */
+#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */
+#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */
+#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
+#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */
+#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */
+#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */
+#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */
+#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */
+#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */
+#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */
+#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */
+#define IXGBE_RXDADV_HBO 0x00800000
+#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */
+#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */
+#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */
+#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */
+#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */
+#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */
+#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */
+#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define IXGBE_RXD_PRI_SHIFT 13
+#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define IXGBE_RXD_CFI_SHIFT 12
+
+/* SRRCTL bit definitions */
+#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */
+#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00
+#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+
+#define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000
+#define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
+
+#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F
+#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0
+#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0
+#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5
+#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000
+#define IXGBE_RXDADV_SPH 0x8000
+
+/* RSS Hash results */
+#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000
+#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001
+#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002
+#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003
+#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004
+#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005
+#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
+#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007
+#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008
+#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
+
+/* RSS Packet Types as indicated in the receive descriptor. */
+#define IXGBE_RXDADV_PKTTYPE_NONE 0x00000000
+#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPv4 hdr + extensions */
+#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPv6 hdr + extensions */
+#define IXGBE_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */
+
+/* Masks to determine if packets should be dropped due to frame errors */
+#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\
+ IXGBE_RXD_ERR_CE | \
+ IXGBE_RXD_ERR_LE | \
+ IXGBE_RXD_ERR_PE | \
+ IXGBE_RXD_ERR_OSE | \
+ IXGBE_RXD_ERR_USE)
+
+#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\
+ IXGBE_RXDADV_ERR_CE | \
+ IXGBE_RXDADV_ERR_LE | \
+ IXGBE_RXDADV_ERR_PE | \
+ IXGBE_RXDADV_ERR_OSE | \
+ IXGBE_RXDADV_ERR_USE)
+
+/* Multicast bit mask */
+#define IXGBE_MCSTCTRL_MFE 0x4
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8
+#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024
+
+/* Vlan-specific macros */
+#define IXGBE_RX_DESC_SPECIAL_VLAN_MASK 0x0FFF /* VLAN ID in lower 12 bits */
+#define IXGBE_RX_DESC_SPECIAL_PRI_MASK 0xE000 /* Priority in upper 3 bits */
+#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */
+#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
+
+/* Transmit Descriptor - Legacy */
+struct ixgbe_legacy_tx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ u32 data;
+ struct {
+ u16 length; /* Data buffer length */
+ u8 cso; /* Checksum offset */
+ u8 cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 css; /* Checksum start */
+ u16 vlan;
+ } fields;
+ } upper;
+};
+
+/* Transmit Descriptor - Advanced */
+union ixgbe_adv_tx_desc {
+ struct {
+ u64 buffer_addr; /* Address of descriptor's data buf */
+ u32 cmd_type_len;
+ u32 olinfo_status;
+ } read;
+ struct {
+ u64 rsvd; /* Reserved */
+ u32 nxtseq_seed;
+ u32 status;
+ } wb;
+};
+
+/* Receive Descriptor - Legacy */
+struct ixgbe_legacy_rx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ u16 length; /* Length of data DMAed into data buffer */
+ u16 csum; /* Packet checksum */
+ u8 status; /* Descriptor status */
+ u8 errors; /* Descriptor Errors */
+ u16 vlan;
+};
+
+/* Receive Descriptor - Advanced */
+union ixgbe_adv_rx_desc {
+ struct {
+ u64 pkt_addr; /* Packet buffer address */
+ u64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ struct {
+ u16 pkt_info; /* RSS type, Packet type */
+ u16 hdr_info; /* Split Header, header len */
+ } lo_dword;
+ union {
+ u32 rss; /* RSS Hash */
+ struct {
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ u32 status_error; /* ext status/error */
+ u16 length; /* Packet length */
+ u16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+/* Context descriptors */
+struct ixgbe_adv_tx_context_desc {
+ u32 vlan_macip_lens;
+ u32 seqnum_seed;
+ u32 type_tucmd_mlhl;
+ u32 mss_l4len_idx;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */
+#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */
+#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */
+#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */
+#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */
+#define IXGBE_ADVTXD_DCMD_RDMA 0x04000000 /* RDMA */
+#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */
+#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */
+#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */
+#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */
+#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */
+#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */
+#define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */
+#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
+#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */
+#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
+ IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
+ IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_EOM 0x00000400 /* Enable L bit-RDMA DDP hdr */
+#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
+#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */
+#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
+#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */
+#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
+#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */
+#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
+#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */
+#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
+#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
+
+/* Link speed */
+#define IXGBE_LINK_SPEED_UNKNOWN 0
+#define IXGBE_LINK_SPEED_100_FULL 0x0008
+#define IXGBE_LINK_SPEED_1GB_FULL 0x0020
+#define IXGBE_LINK_SPEED_10GB_FULL 0x0080
+
+
+enum ixgbe_eeprom_type {
+ ixgbe_eeprom_uninitialized = 0,
+ ixgbe_eeprom_spi,
+ ixgbe_eeprom_none /* No NVM support */
+};
+
+enum ixgbe_mac_type {
+ ixgbe_mac_unknown = 0,
+ ixgbe_mac_82598EB,
+ ixgbe_num_macs
+};
+
+enum ixgbe_phy_type {
+ ixgbe_phy_unknown = 0,
+ ixgbe_phy_tn,
+ ixgbe_phy_qt,
+ ixgbe_phy_xaui
+};
+
+enum ixgbe_media_type {
+ ixgbe_media_type_unknown = 0,
+ ixgbe_media_type_fiber,
+ ixgbe_media_type_copper,
+ ixgbe_media_type_backplane
+};
+
+/* Flow Control Settings */
+enum ixgbe_fc_type {
+ ixgbe_fc_none = 0,
+ ixgbe_fc_rx_pause,
+ ixgbe_fc_tx_pause,
+ ixgbe_fc_full,
+ ixgbe_fc_default
+};
+
+struct ixgbe_addr_filter_info {
+ u32 num_mc_addrs;
+ u32 rar_used_count;
+ u32 mc_addr_in_rar_count;
+ u32 mta_in_use;
+};
+
+/* Flow control parameters */
+struct ixgbe_fc_info {
+ u32 high_water; /* Flow Control High-water */
+ u32 low_water; /* Flow Control Low-water */
+ u16 pause_time; /* Flow Control Pause timer */
+ bool send_xon; /* Flow control send XON */
+ bool strict_ieee; /* Strict IEEE mode */
+ enum ixgbe_fc_type type; /* Type of flow control */
+ enum ixgbe_fc_type original_type;
+};
+
+/* Statistics counters collected by the MAC */
+struct ixgbe_hw_stats {
+ u64 crcerrs;
+ u64 illerrc;
+ u64 errbc;
+ u64 mspdc;
+ u64 mpctotal;
+ u64 mpc[8];
+ u64 mlfc;
+ u64 mrfc;
+ u64 rlec;
+ u64 lxontxc;
+ u64 lxonrxc;
+ u64 lxofftxc;
+ u64 lxoffrxc;
+ u64 pxontxc[8];
+ u64 pxonrxc[8];
+ u64 pxofftxc[8];
+ u64 pxoffrxc[8];
+ u64 prc64;
+ u64 prc127;
+ u64 prc255;
+ u64 prc511;
+ u64 prc1023;
+ u64 prc1522;
+ u64 gprc;
+ u64 bprc;
+ u64 mprc;
+ u64 gptc;
+ u64 gorc;
+ u64 gotc;
+ u64 rnbc[8];
+ u64 ruc;
+ u64 rfc;
+ u64 roc;
+ u64 rjc;
+ u64 mngprc;
+ u64 mngpdc;
+ u64 mngptc;
+ u64 tor;
+ u64 tpr;
+ u64 tpt;
+ u64 ptc64;
+ u64 ptc127;
+ u64 ptc255;
+ u64 ptc511;
+ u64 ptc1023;
+ u64 ptc1522;
+ u64 mptc;
+ u64 bptc;
+ u64 xec;
+ u64 rqsmr[16];
+ u64 tqsmr[8];
+ u64 qprc[16];
+ u64 qptc[16];
+ u64 qbrc[16];
+ u64 qbtc[16];
+};
+
+/* forward declaration */
+struct ixgbe_hw;
+
+struct ixgbe_mac_operations {
+ s32 (*reset)(struct ixgbe_hw *);
+ enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+};
+
+struct ixgbe_phy_operations {
+ s32 (*setup)(struct ixgbe_hw *);
+ s32 (*check)(struct ixgbe_hw *, u32 *, bool *);
+ s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool);
+ s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *);
+};
+
+struct ixgbe_mac_info {
+ struct ixgbe_mac_operations ops;
+ enum ixgbe_mac_type type;
+ u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+ u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+ s32 mc_filter_type;
+ u32 num_rx_queues;
+ u32 num_tx_queues;
+ u32 num_rx_addrs;
+ u32 link_attach_type;
+ u32 link_mode_select;
+ bool link_settings_loaded;
+};
+
+
+struct ixgbe_eeprom_info {
+ enum ixgbe_eeprom_type type;
+ u16 word_size;
+ u16 address_bits;
+};
+
+struct ixgbe_phy_info {
+ struct ixgbe_phy_operations ops;
+
+ enum ixgbe_phy_type type;
+ u32 addr;
+ u32 id;
+ u32 revision;
+ enum ixgbe_media_type media_type;
+ u32 autoneg_advertised;
+ bool autoneg_wait_to_complete;
+};
+
+struct ixgbe_info {
+ enum ixgbe_mac_type mac;
+ s32 (*get_invariants)(struct ixgbe_hw *);
+ struct ixgbe_mac_operations *mac_ops;
+ struct ixgbe_phy_operations *phy_ops;
+};
+
+struct ixgbe_hw {
+ u8 __iomem *hw_addr;
+ void *back;
+ struct ixgbe_mac_info mac;
+ struct ixgbe_addr_filter_info addr_ctrl;
+ struct ixgbe_fc_info fc;
+ struct ixgbe_phy_info phy;
+ struct ixgbe_eeprom_info eeprom;
+ u16 device_id;
+ u16 vendor_id;
+ u16 subsystem_device_id;
+ u16 subsystem_vendor_id;
+ u8 revision_id;
+ bool adapter_stopped;
+};
+
+/* Error Codes */
+#define IXGBE_ERR_EEPROM -1
+#define IXGBE_ERR_EEPROM_CHECKSUM -2
+#define IXGBE_ERR_PHY -3
+#define IXGBE_ERR_CONFIG -4
+#define IXGBE_ERR_PARAM -5
+#define IXGBE_ERR_MAC_TYPE -6
+#define IXGBE_ERR_UNKNOWN_PHY -7
+#define IXGBE_ERR_LINK_SETUP -8
+#define IXGBE_ERR_ADAPTER_STOPPED -9
+#define IXGBE_ERR_INVALID_MAC_ADDR -10
+#define IXGBE_ERR_DEVICE_NOT_SUPPORTED -11
+#define IXGBE_ERR_MASTER_REQUESTS_PENDING -12
+#define IXGBE_ERR_INVALID_LINK_SETTINGS -13
+#define IXGBE_ERR_AUTONEG_NOT_COMPLETE -14
+#define IXGBE_ERR_RESET_FAILED -15
+#define IXGBE_ERR_SWFW_SYNC -16
+#define IXGBE_ERR_PHY_ADDR_INVALID -17
+#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF
+
+#endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c
index d3f4235c585d..b02a981c87a8 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ixp2000/enp2611.c
@@ -210,7 +210,6 @@ static int __init enp2611_init_module(void)
return -ENOMEM;
}
- SET_MODULE_OWNER(nds[i]);
nds[i]->get_stats = enp2611_get_stats;
pm3386_init_port(i);
pm3386_get_mac(i, nds[i]->dev_addr);
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index d9ce1aef148a..6c0dd49149d0 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -74,9 +74,9 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
}
-static int ixpdev_rx(struct net_device *dev, int *budget)
+static int ixpdev_rx(struct net_device *dev, int processed, int budget)
{
- while (*budget > 0) {
+ while (processed < budget) {
struct ixpdev_rx_desc *desc;
struct sk_buff *skb;
void *buf;
@@ -122,29 +122,34 @@ static int ixpdev_rx(struct net_device *dev, int *budget)
err:
ixp2000_reg_write(RING_RX_PENDING, _desc);
- dev->quota--;
- (*budget)--;
+ processed++;
}
- return 1;
+ return processed;
}
/* dev always points to nds[0]. */
-static int ixpdev_poll(struct net_device *dev, int *budget)
+static int ixpdev_poll(struct napi_struct *napi, int budget)
{
+ struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi);
+ struct net_device *dev = ip->dev;
+ int rx;
+
/* @@@ Have to stop polling when nds[0] is administratively
* downed while we are polling. */
+ rx = 0;
do {
ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
- if (ixpdev_rx(dev, budget))
- return 1;
+ rx = ixpdev_rx(dev, rx, budget);
+ if (rx >= budget)
+ break;
} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
- return 0;
+ return rx;
}
static void ixpdev_tx_complete(void)
@@ -199,9 +204,12 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
* Any of the eight receive units signaled RX?
*/
if (status & 0x00ff) {
+ struct net_device *dev = nds[0];
+ struct ixpdev_priv *ip = netdev_priv(dev);
+
ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
- if (likely(__netif_rx_schedule_prep(nds[0]))) {
- __netif_rx_schedule(nds[0]);
+ if (likely(napi_schedule_prep(&ip->napi))) {
+ __netif_rx_schedule(dev, &ip->napi);
} else {
printk(KERN_CRIT "ixp2000: irq while polling!!\n");
}
@@ -232,11 +240,13 @@ static int ixpdev_open(struct net_device *dev)
struct ixpdev_priv *ip = netdev_priv(dev);
int err;
+ napi_enable(&ip->napi);
if (!nds_open++) {
err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
IRQF_SHARED, "ixp2000_eth", nds);
if (err) {
nds_open--;
+ napi_disable(&ip->napi);
return err;
}
@@ -254,6 +264,7 @@ static int ixpdev_close(struct net_device *dev)
struct ixpdev_priv *ip = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&ip->napi);
set_port_admin_status(ip->channel, 0);
if (!--nds_open) {
@@ -274,7 +285,6 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
return NULL;
dev->hard_start_xmit = ixpdev_xmit;
- dev->poll = ixpdev_poll;
dev->open = ixpdev_open;
dev->stop = ixpdev_close;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -282,9 +292,10 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
#endif
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->weight = 64;
ip = netdev_priv(dev);
+ ip->dev = dev;
+ netif_napi_add(dev, &ip->napi, ixpdev_poll, 64);
ip->channel = channel;
ip->tx_queue_entries = 0;
diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ixp2000/ixpdev.h
index bd686cb63058..391ece623243 100644
--- a/drivers/net/ixp2000/ixpdev.h
+++ b/drivers/net/ixp2000/ixpdev.h
@@ -14,6 +14,8 @@
struct ixpdev_priv
{
+ struct net_device *dev;
+ struct napi_struct napi;
int channel;
int tx_queue_entries;
};
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 75f6f441e876..d3825c8ee994 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -45,7 +45,6 @@
#include <asm/jazzdma.h>
static char jazz_sonic_string[] = "jazzsonic";
-static struct platform_device *jazz_sonic_device;
#define SONIC_MEM_SIZE 0x100
@@ -70,14 +69,6 @@ static unsigned int sonic_debug = 1;
#endif
/*
- * Base address and interrupt of the SONIC controller on JAZZ boards
- */
-static struct {
- unsigned int port;
- unsigned int irq;
-} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
-
-/*
* We cannot use station (ethernet) address prefixes to detect the
* sonic controller since these are board manufacturer depended.
* So we check for known Silicon Revision IDs instead.
@@ -215,13 +206,13 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
+ struct resource *res;
int err = 0;
int i;
+ DECLARE_MAC_BUF(mac);
- /*
- * Don't probe if we're not running on a Jazz board.
- */
- if (mips_machgroup != MACH_GROUP_JAZZ)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
return -ENODEV;
dev = alloc_etherdev(sizeof(struct sonic_local));
@@ -231,37 +222,20 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
- SET_MODULE_OWNER(dev);
netdev_boot_setup_check(dev);
- if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
- err = sonic_probe1(dev);
- } else if (dev->base_addr != 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (i = 0; sonic_portlist[i].port; i++) {
- dev->base_addr = sonic_portlist[i].port;
- dev->irq = sonic_portlist[i].irq;
- if (sonic_probe1(dev) == 0)
- break;
- }
- if (!sonic_portlist[i].port)
- err = -ENODEV;
- }
+ dev->base_addr = res->start;
+ dev->irq = platform_get_irq(pdev, 0);
+ err = sonic_probe1(dev);
if (err)
goto out;
err = register_netdev(dev);
if (err)
goto out1;
- printk("%s: MAC ", dev->name);
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk(" IRQ %d\n", dev->irq);
+ printk("%s: MAC %s IRQ %d\n",
+ dev->name, print_mac(mac, dev->dev_addr), dev->irq);
return 0;
@@ -303,38 +277,12 @@ static struct platform_driver jazz_sonic_driver = {
static int __init jazz_sonic_init_module(void)
{
- int err;
-
- if ((err = platform_driver_register(&jazz_sonic_driver))) {
- printk(KERN_ERR "Driver registration failed\n");
- return err;
- }
-
- jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0);
- if (!jazz_sonic_device)
- goto out_unregister;
-
- if (platform_device_add(jazz_sonic_device)) {
- platform_device_put(jazz_sonic_device);
- jazz_sonic_device = NULL;
- }
-
- return 0;
-
-out_unregister:
- platform_driver_unregister(&jazz_sonic_driver);
-
- return -ENOMEM;
+ return platform_driver_register(&jazz_sonic_driver);
}
static void __exit jazz_sonic_cleanup_module(void)
{
platform_driver_unregister(&jazz_sonic_driver);
-
- if (jazz_sonic_device) {
- platform_device_unregister(jazz_sonic_device);
- jazz_sonic_device = NULL;
- }
}
module_init(jazz_sonic_init_module);
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index a2f37e52b928..977ed3401bb3 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -466,6 +466,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
unsigned long flags;
int err = -ENOMEM;
void __iomem *bios;
+ DECLARE_MAC_BUF(mac);
/* First we look for special cases.
Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
@@ -521,23 +522,22 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
/* We can't allocate dev->priv from alloc_etherdev() because it must
a ISA DMA-able region. */
- SET_MODULE_OWNER(dev);
chipname = chip_table[lance_version].name;
- printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+ printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr);
/* There is a 16 byte station address PROM at the base address.
The first six bytes are the station address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+ printk("%s", print_mac(mac, dev->dev_addr));
dev->base_addr = ioaddr;
/* Make certain the data structures used by the LANCE are aligned and DMAble. */
- lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+ lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
if(lp==NULL)
return -ENODEV;
if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
- memset(lp, 0, sizeof(*lp));
dev->priv = lp;
lp->name = chipname;
lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c
new file mode 100644
index 000000000000..abce2ee8430a
--- /dev/null
+++ b/drivers/net/lguest_net.c
@@ -0,0 +1,555 @@
+/*D:500
+ * The Guest network driver.
+ *
+ * This is very simple a virtual network driver, and our last Guest driver.
+ * The only trick is that it can talk directly to multiple other recipients
+ * (ie. other Guests on the same network). It can also be used with only the
+ * Host on the network.
+ :*/
+
+/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+//#define DEBUG
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/mm_types.h>
+#include <linux/io.h>
+#include <linux/lguest_bus.h>
+
+#define SHARED_SIZE PAGE_SIZE
+#define MAX_LANS 4
+#define NUM_SKBS 8
+
+/*M:011 Network code master Jeff Garzik points out numerous shortcomings in
+ * this driver if it aspires to greatness.
+ *
+ * Firstly, it doesn't use "NAPI": the networking's New API, and is poorer for
+ * it. As he says "NAPI means system-wide load leveling, across multiple
+ * network interfaces. Lack of NAPI can mean competition at higher loads."
+ *
+ * He also points out that we don't implement set_mac_address, so users cannot
+ * change the devices hardware address. When I asked why one would want to:
+ * "Bonding, and situations where you /do/ want the MAC address to "leak" out
+ * of the host onto the wider net."
+ *
+ * Finally, he would like module unloading: "It is not unrealistic to think of
+ * [un|re|]loading the net support module in an lguest guest. And, adding
+ * module support makes the programmer more responsible, because they now have
+ * to learn to clean up after themselves. Any driver that cannot clean up
+ * after itself is an incomplete driver in my book."
+ :*/
+
+/*D:530 The "struct lguestnet_info" contains all the information we need to
+ * know about the network device. */
+struct lguestnet_info
+{
+ /* The mapped device page(s) (an array of "struct lguest_net"). */
+ struct lguest_net *peer;
+ /* The physical address of the device page(s) */
+ unsigned long peer_phys;
+ /* The size of the device page(s). */
+ unsigned long mapsize;
+
+ /* The lguest_device I come from */
+ struct lguest_device *lgdev;
+
+ /* My peerid (ie. my slot in the array). */
+ unsigned int me;
+
+ /* Receive queue: the network packets waiting to be filled. */
+ struct sk_buff *skb[NUM_SKBS];
+ struct lguest_dma dma[NUM_SKBS];
+};
+/*:*/
+
+/* How many bytes left in this page. */
+static unsigned int rest_of_page(void *data)
+{
+ return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
+}
+
+/*D:570 Each peer (ie. Guest or Host) on the network binds their receive
+ * buffers to a different key: we simply use the physical address of the
+ * device's memory page plus the peer number. The Host insists that all keys
+ * be a multiple of 4, so we multiply the peer number by 4. */
+static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum)
+{
+ return info->peer_phys + 4 * peernum;
+}
+
+/* This is the routine which sets up a "struct lguest_dma" to point to a
+ * network packet, similar to req_to_dma() in lguest_blk.c. The structure of a
+ * "struct sk_buff" has grown complex over the years: it consists of a "head"
+ * linear section pointed to by "skb->data", and possibly an array of
+ * "fragments" in the case of a non-linear packet.
+ *
+ * Our receive buffers don't use fragments at all but outgoing skbs might, so
+ * we handle it. */
+static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen,
+ struct lguest_dma *dma)
+{
+ unsigned int i, seg;
+
+ /* First, we put the linear region into the "struct lguest_dma". Each
+ * entry can't go over a page boundary, so even though all our packets
+ * are 1514 bytes or less, we might need to use two entries here: */
+ for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) {
+ dma->addr[seg] = virt_to_phys(skb->data + i);
+ dma->len[seg] = min((unsigned)(headlen - i),
+ rest_of_page(skb->data + i));
+ }
+
+ /* Now we handle the fragments: at least they're guaranteed not to go
+ * over a page. skb_shinfo(skb) returns a pointer to the structure
+ * which tells us about the number of fragments and the fragment
+ * array. */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) {
+ const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ /* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */
+ if (seg == LGUEST_MAX_DMA_SECTIONS) {
+ /* We will end up sending a truncated packet should
+ * this ever happen. Plus, a cool log message! */
+ printk("Woah dude! Megapacket!\n");
+ break;
+ }
+ dma->addr[seg] = page_to_phys(f->page) + f->page_offset;
+ dma->len[seg] = f->size;
+ }
+
+ /* If after all that we didn't use the entire "struct lguest_dma"
+ * array, we terminate it with a 0 length. */
+ if (seg < LGUEST_MAX_DMA_SECTIONS)
+ dma->len[seg] = 0;
+}
+
+/*
+ * Packet transmission.
+ *
+ * Our packet transmission is a little unusual. A real network card would just
+ * send out the packet and leave the receivers to decide if they're interested.
+ * Instead, we look through the network device memory page and see if any of
+ * the ethernet addresses match the packet destination, and if so we send it to
+ * that Guest.
+ *
+ * This is made a little more complicated in two cases. The first case is
+ * broadcast packets: for that we send the packet to all Guests on the network,
+ * one at a time. The second case is "promiscuous" mode, where a Guest wants
+ * to see all the packets on the network. We need a way for the Guest to tell
+ * us it wants to see all packets, so it sets the "multicast" bit on its
+ * published MAC address, which is never valid in a real ethernet address.
+ */
+#define PROMISC_BIT 0x01
+
+/* This is the callback which is summoned whenever the network device's
+ * multicast or promiscuous state changes. If the card is in promiscuous mode,
+ * we advertise that in our ethernet address in the device's memory. We do the
+ * same if Linux wants any or all multicast traffic. */
+static void lguestnet_set_multicast(struct net_device *dev)
+{
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count)
+ info->peer[info->me].mac[0] |= PROMISC_BIT;
+ else
+ info->peer[info->me].mac[0] &= ~PROMISC_BIT;
+}
+
+/* A simple test function to see if a peer wants to see all packets.*/
+static int promisc(struct lguestnet_info *info, unsigned int peer)
+{
+ return info->peer[peer].mac[0] & PROMISC_BIT;
+}
+
+/* Another simple function to see if a peer's advertised ethernet address
+ * matches a packet's destination ethernet address. */
+static int mac_eq(const unsigned char mac[ETH_ALEN],
+ struct lguestnet_info *info, unsigned int peer)
+{
+ /* Ignore multicast bit, which peer turns on to mean promisc. */
+ if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0])
+ return 0;
+ return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0;
+}
+
+/* This is the function which actually sends a packet once we've decided a
+ * peer wants it: */
+static void transfer_packet(struct net_device *dev,
+ struct sk_buff *skb,
+ unsigned int peernum)
+{
+ struct lguestnet_info *info = netdev_priv(dev);
+ struct lguest_dma dma;
+
+ /* We use our handy "struct lguest_dma" packing function to prepare
+ * the skb for sending. */
+ skb_to_dma(skb, skb_headlen(skb), &dma);
+ pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len);
+
+ /* This is the actual send call which copies the packet. */
+ lguest_send_dma(peer_key(info, peernum), &dma);
+
+ /* Check that the entire packet was transmitted. If not, it could mean
+ * that the other Guest registered a short receive buffer, but this
+ * driver should never do that. More likely, the peer is dead. */
+ if (dma.used_len != skb->len) {
+ dev->stats.tx_carrier_errors++;
+ pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n",
+ peernum, dma.used_len, skb->len,
+ (void *)dma.addr[0], dma.len[0]);
+ } else {
+ /* On success we update the stats. */
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ }
+}
+
+/* Another helper function to tell is if a slot in the device memory is unused.
+ * Since we always set the Local Assignment bit in the ethernet address, the
+ * first byte can never be 0. */
+static int unused_peer(const struct lguest_net peer[], unsigned int num)
+{
+ return peer[num].mac[0] == 0;
+}
+
+/* Finally, here is the routine which handles an outgoing packet. It's called
+ * "start_xmit" for traditional reasons. */
+static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int i;
+ int broadcast;
+ struct lguestnet_info *info = netdev_priv(dev);
+ /* Extract the destination ethernet address from the packet. */
+ const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
+ DECLARE_MAC_BUF(mac);
+
+ pr_debug("%s: xmit %s\n", dev->name, print_mac(mac, dest));
+
+ /* If it's a multicast packet, we broadcast to everyone. That's not
+ * very efficient, but there are very few applications which actually
+ * use multicast, which is a shame really.
+ *
+ * As etherdevice.h points out: "By definition the broadcast address is
+ * also a multicast address." So we don't have to test for broadcast
+ * packets separately. */
+ broadcast = is_multicast_ether_addr(dest);
+
+ /* Look through all the published ethernet addresses to see if we
+ * should send this packet. */
+ for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) {
+ /* We don't send to ourselves (we actually can't SEND_DMA to
+ * ourselves anyway), and don't send to unused slots.*/
+ if (i == info->me || unused_peer(info->peer, i))
+ continue;
+
+ /* If it's broadcast we send it. If they want every packet we
+ * send it. If the destination matches their address we send
+ * it. Otherwise we go to the next peer. */
+ if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i))
+ continue;
+
+ pr_debug("lguestnet %s: sending from %i to %i\n",
+ dev->name, info->me, i);
+ /* Our routine which actually does the transfer. */
+ transfer_packet(dev, skb, i);
+ }
+
+ /* An xmit routine is expected to dispose of the packet, so we do. */
+ dev_kfree_skb(skb);
+
+ /* As per kernel convention, 0 means success. This is why I love
+ * networking: even if we never sent to anyone, that's still
+ * success! */
+ return 0;
+}
+
+/*D:560
+ * Packet receiving.
+ *
+ * First, here's a helper routine which fills one of our array of receive
+ * buffers: */
+static int fill_slot(struct net_device *dev, unsigned int slot)
+{
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ /* We can receive ETH_DATA_LEN (1500) byte packets, plus a standard
+ * ethernet header of ETH_HLEN (14) bytes. */
+ info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN);
+ if (!info->skb[slot]) {
+ printk("%s: could not fill slot %i\n", dev->name, slot);
+ return -ENOMEM;
+ }
+
+ /* skb_to_dma() is a helper which sets up the "struct lguest_dma" to
+ * point to the data in the skb: we also use it for sending out a
+ * packet. */
+ skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]);
+
+ /* This is a Write Memory Barrier: it ensures that the entry in the
+ * receive buffer array is written *before* we set the "used_len" entry
+ * to 0. If the Host were looking at the receive buffer array from a
+ * different CPU, it could potentially see "used_len = 0" and not see
+ * the updated receive buffer information. This would be a horribly
+ * nasty bug, so make sure the compiler and CPU know this has to happen
+ * first. */
+ wmb();
+ /* Writing 0 to "used_len" tells the Host it can use this receive
+ * buffer now. */
+ info->dma[slot].used_len = 0;
+ return 0;
+}
+
+/* This is the actual receive routine. When we receive an interrupt from the
+ * Host to tell us a packet has been delivered, we arrive here: */
+static irqreturn_t lguestnet_rcv(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct lguestnet_info *info = netdev_priv(dev);
+ unsigned int i, done = 0;
+
+ /* Look through our entire receive array for an entry which has data
+ * in it. */
+ for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+ unsigned int length;
+ struct sk_buff *skb;
+
+ length = info->dma[i].used_len;
+ if (length == 0)
+ continue;
+
+ /* We've found one! Remember the skb (we grabbed the length
+ * above), and immediately refill the slot we've taken it
+ * from. */
+ done++;
+ skb = info->skb[i];
+ fill_slot(dev, i);
+
+ /* This shouldn't happen: micropackets could be sent by a
+ * badly-behaved Guest on the network, but the Host will never
+ * stuff more data in the buffer than the buffer length. */
+ if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) {
+ pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n",
+ dev->name, length);
+ dev_kfree_skb(skb);
+ continue;
+ }
+
+ /* skb_put(), what a great function! I've ranted about this
+ * function before (http://lkml.org/lkml/1999/9/26/24). You
+ * call it after you've added data to the end of an skb (in
+ * this case, it was the Host which wrote the data). */
+ skb_put(skb, length);
+
+ /* The ethernet header contains a protocol field: we use the
+ * standard helper to extract it, and place the result in
+ * skb->protocol. The helper also sets up skb->pkt_type and
+ * eats up the ethernet header from the front of the packet. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* If this device doesn't need checksums for sending, we also
+ * don't need to check the packets when they come in. */
+ if (dev->features & NETIF_F_NO_CSUM)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ /* As a last resort for debugging the driver or the lguest I/O
+ * subsystem, you can uncomment the "#define DEBUG" at the top
+ * of this file, which turns all the pr_debug() into printk()
+ * and floods the logs. */
+ pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+ ntohs(skb->protocol), skb->len, skb->pkt_type);
+
+ /* Update the packet and byte counts (visible from ifconfig,
+ * and good for debugging). */
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+
+ /* Hand our fresh network packet into the stack's "network
+ * interface receive" routine. That will free the packet
+ * itself when it's finished. */
+ netif_rx(skb);
+ }
+
+ /* If we found any packets, we assume the interrupt was for us. */
+ return done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*D:550 This is where we start: when the device is brought up by dhcpd or
+ * ifconfig. At this point we advertise our MAC address to the rest of the
+ * network, and register receive buffers ready for incoming packets. */
+static int lguestnet_open(struct net_device *dev)
+{
+ int i;
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ /* Copy our MAC address into the device page, so others on the network
+ * can find us. */
+ memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN);
+
+ /* We might already be in promisc mode (dev->flags & IFF_PROMISC). Our
+ * set_multicast callback handles this already, so we call it now. */
+ lguestnet_set_multicast(dev);
+
+ /* Allocate packets and put them into our "struct lguest_dma" array.
+ * If we fail to allocate all the packets we could still limp along,
+ * but it's a sign of real stress so we should probably give up now. */
+ for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+ if (fill_slot(dev, i) != 0)
+ goto cleanup;
+ }
+
+ /* Finally we tell the Host where our array of "struct lguest_dma"
+ * receive buffers is, binding it to the key corresponding to the
+ * device's physical memory plus our peerid. */
+ if (lguest_bind_dma(peer_key(info,info->me), info->dma,
+ NUM_SKBS, lgdev_irq(info->lgdev)) != 0)
+ goto cleanup;
+ return 0;
+
+cleanup:
+ while (--i >= 0)
+ dev_kfree_skb(info->skb[i]);
+ return -ENOMEM;
+}
+/*:*/
+
+/* The close routine is called when the device is no longer in use: we clean up
+ * elegantly. */
+static int lguestnet_close(struct net_device *dev)
+{
+ unsigned int i;
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ /* Clear all trace of our existence out of the device memory by setting
+ * the slot which held our MAC address to 0 (unused). */
+ memset(&info->peer[info->me], 0, sizeof(info->peer[info->me]));
+
+ /* Unregister our array of receive buffers */
+ lguest_unbind_dma(peer_key(info, info->me), info->dma);
+ for (i = 0; i < ARRAY_SIZE(info->dma); i++)
+ dev_kfree_skb(info->skb[i]);
+ return 0;
+}
+
+/*D:510 The network device probe function is basically a standard ethernet
+ * device setup. It reads the "struct lguest_device_desc" and sets the "struct
+ * net_device". Oh, the line-by-line excitement! Let's skip over it. :*/
+static int lguestnet_probe(struct lguest_device *lgdev)
+{
+ int err, irqf = IRQF_SHARED;
+ struct net_device *dev;
+ struct lguestnet_info *info;
+ struct lguest_device_desc *desc = &lguest_devices[lgdev->index];
+
+ pr_debug("lguest_net: probing for device %i\n", lgdev->index);
+
+ dev = alloc_etherdev(sizeof(struct lguestnet_info));
+ if (!dev)
+ return -ENOMEM;
+
+ /* Ethernet defaults with some changes */
+ ether_setup(dev);
+ dev->set_mac_address = NULL;
+
+ dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */
+ dev->dev_addr[1] = 0x00;
+ memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2);
+ dev->dev_addr[4] = 0x00;
+ dev->dev_addr[5] = 0x00;
+
+ dev->open = lguestnet_open;
+ dev->stop = lguestnet_close;
+ dev->hard_start_xmit = lguestnet_start_xmit;
+
+ /* We don't actually support multicast yet, but turning on/off
+ * promisc also calls dev->set_multicast_list. */
+ dev->set_multicast_list = lguestnet_set_multicast;
+ SET_NETDEV_DEV(dev, &lgdev->dev);
+
+ /* The network code complains if you have "scatter-gather" capability
+ * if you don't also handle checksums (it seem that would be
+ * "illogical"). So we use a lie of omission and don't tell it that we
+ * can handle scattered packets unless we also don't want checksums,
+ * even though to us they're completely independent. */
+ if (desc->features & LGUEST_NET_F_NOCSUM)
+ dev->features = NETIF_F_SG|NETIF_F_NO_CSUM;
+
+ info = netdev_priv(dev);
+ info->mapsize = PAGE_SIZE * desc->num_pages;
+ info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT);
+ info->lgdev = lgdev;
+ info->peer = lguest_map(info->peer_phys, desc->num_pages);
+ if (!info->peer) {
+ err = -ENOMEM;
+ goto free;
+ }
+
+ /* This stores our peerid (upper bits reserved for future). */
+ info->me = (desc->features & (info->mapsize-1));
+
+ err = register_netdev(dev);
+ if (err) {
+ pr_debug("lguestnet: registering device failed\n");
+ goto unmap;
+ }
+
+ if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+ irqf |= IRQF_SAMPLE_RANDOM;
+ if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet",
+ dev) != 0) {
+ pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev));
+ goto unregister;
+ }
+
+ pr_debug("lguestnet: registered device %s\n", dev->name);
+ /* Finally, we put the "struct net_device" in the generic "struct
+ * lguest_device"s private pointer. Again, it's not necessary, but
+ * makes sure the cool kernel kids don't tease us. */
+ lgdev->private = dev;
+ return 0;
+
+unregister:
+ unregister_netdev(dev);
+unmap:
+ lguest_unmap(info->peer);
+free:
+ free_netdev(dev);
+ return err;
+}
+
+static struct lguest_driver lguestnet_drv = {
+ .name = "lguestnet",
+ .owner = THIS_MODULE,
+ .device_type = LGUEST_DEVICE_T_NET,
+ .probe = lguestnet_probe,
+};
+
+static __init int lguestnet_init(void)
+{
+ return register_lguest_driver(&lguestnet_drv);
+}
+module_init(lguestnet_init);
+
+MODULE_DESCRIPTION("Lguest network driver");
+MODULE_LICENSE("GPL");
+
+/*D:580
+ * This is the last of the Drivers, and with this we have covered the many and
+ * wonderous and fine (and boring) details of the Guest.
+ *
+ * "make Launcher" beckons, where we answer questions like "Where do Guests
+ * come from?", and "What do you do when someone asks for optimization?"
+ */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 5884f5bd04a4..ffaa14f2cd01 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -322,7 +322,6 @@ struct i596_private {
struct i596_cmd *cmd_head;
int cmd_backlog;
u32 last_cmd;
- struct net_device_stats stats;
int next_tx_cmd;
int options;
spinlock_t lock; /* serialize access to chip */
@@ -352,7 +351,6 @@ static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void i596_tx_timeout (struct net_device *dev);
static void print_eth(unsigned char *buf, char *str);
@@ -725,7 +723,7 @@ memory_squeeze:
printk(KERN_ERR
"%s: i596_rx Memory squeeze, dropping packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
if (!rx_in_place) {
/* 16 byte align the data fields */
@@ -742,28 +740,28 @@ memory_squeeze:
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
} else {
DEB(DEB_ERRORS, printk(KERN_DEBUG
"%s: Error, rfd.stat = 0x%04x\n",
dev->name, rfd->stat));
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rfd->stat & SWAP16(0x0100))
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (rfd->stat & SWAP16(0x8000))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rfd->stat & SWAP16(0x0001))
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rfd->stat & SWAP16(0x0002))
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rfd->stat & SWAP16(0x0004))
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rfd->stat & SWAP16(0x0008))
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rfd->stat & SWAP16(0x0010))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
/* Clear the buffer descriptor count and EOF + F flags */
@@ -821,8 +819,8 @@ static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private
dev_kfree_skb(skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
ptr->v_next = NULL;
ptr->b_next = I596_NULL;
@@ -951,10 +949,10 @@ static void i596_tx_timeout (struct net_device *dev)
"%s: transmit timed out, status resetting.\n",
dev->name));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
/* Shutdown and restart */
i596_reset (dev, lp);
@@ -964,7 +962,7 @@ static void i596_tx_timeout (struct net_device *dev)
lp->dma->scb.command = SWAP16(CUC_START | RX_START);
DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
ca (dev);
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies;
@@ -999,7 +997,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
DEB(DEB_ERRORS, printk(KERN_DEBUG
"%s: xmit ring full, dropping packet.\n",
dev->name));
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
} else {
@@ -1025,8 +1023,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
i596_add_cmd(dev, &tx_cmd->cmd);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
}
netif_start_queue(dev);
@@ -1036,15 +1034,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void print_eth(unsigned char *add, char *str)
{
- int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
- printk(KERN_DEBUG "i596 0x%p, ", add);
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i + 6]);
- printk(" -->");
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i]);
- printk(" %02X%02X, %s\n", add[12], add[13], str);
+ printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
+ add, print_mac(mac, add + 6), print_mac(mac2, add),
+ add[12], add[13], str);
}
static int __devinit i82596_probe(struct net_device *dev)
@@ -1076,7 +1071,6 @@ static int __devinit i82596_probe(struct net_device *dev)
dev->open = i596_open;
dev->stop = i596_close;
dev->hard_start_xmit = i596_start_xmit;
- dev->get_stats = i596_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->tx_timeout = i596_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1197,17 +1191,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
DEB(DEB_TXADDR,
print_eth(skb->data, "tx-done"));
} else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (ptr->status & SWAP16(0x0020))
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (!(ptr->status & SWAP16(0x0040)))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (ptr->status & SWAP16(0x0400))
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (ptr->status & SWAP16(0x0800))
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (ptr->status & SWAP16(0x1000))
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
dma_unmap_single(dev->dev.parent,
tx_cmd->dma_addr,
@@ -1292,8 +1286,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
"%s: i596 interrupt receive unit inactive, status 0x%x\n",
dev->name, status));
ack_cmd |= RX_START;
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
rebuild_rx_bufs(dev);
}
}
@@ -1346,13 +1340,6 @@ static int i596_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *i596_get_stats(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
*/
@@ -1362,6 +1349,7 @@ static void set_multicast_list(struct net_device *dev)
struct i596_private *lp = netdev_priv(dev);
struct i596_dma *dma = lp->dma;
int config = 0, cnt;
+ DECLARE_MAC_BUF(mac);
DEB(DEB_MULTI,
printk(KERN_DEBUG
@@ -1425,8 +1413,8 @@ static void set_multicast_list(struct net_device *dev)
if (i596_debug > 1)
DEB(DEB_MULTI,
printk(KERN_DEBUG
- "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]));
+ "%s: Adding address %s\n",
+ dev->name, print_mac(mac, cp)));
}
DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
i596_add_cmd(dev, &cmd->cmd);
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index 5c86e737f954..c429a5002dd6 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -143,6 +143,52 @@ static void __NS8390_init(struct net_device *dev, int startp);
* annoying the transmit function is called bh atomic. That places
* restrictions on the user context callers as disable_irq won't save
* them.
+ *
+ * Additional explanation of problems with locking by Alan Cox:
+ *
+ * "The author (me) didn't use spin_lock_irqsave because the slowness of the
+ * card means that approach caused horrible problems like losing serial data
+ * at 38400 baud on some chips. Rememeber many 8390 nics on PCI were ISA
+ * chips with FPGA front ends.
+ *
+ * Ok the logic behind the 8390 is very simple:
+ *
+ * Things to know
+ * - IRQ delivery is asynchronous to the PCI bus
+ * - Blocking the local CPU IRQ via spin locks was too slow
+ * - The chip has register windows needing locking work
+ *
+ * So the path was once (I say once as people appear to have changed it
+ * in the mean time and it now looks rather bogus if the changes to use
+ * disable_irq_nosync_irqsave are disabling the local IRQ)
+ *
+ *
+ * Take the page lock
+ * Mask the IRQ on chip
+ * Disable the IRQ (but not mask locally- someone seems to have
+ * broken this with the lock validator stuff)
+ * [This must be _nosync as the page lock may otherwise
+ * deadlock us]
+ * Drop the page lock and turn IRQs back on
+ *
+ * At this point an existing IRQ may still be running but we can't
+ * get a new one
+ *
+ * Take the lock (so we know the IRQ has terminated) but don't mask
+ * the IRQs on the processor
+ * Set irqlock [for debug]
+ *
+ * Transmit (slow as ****)
+ *
+ * re-enable the IRQ
+ *
+ *
+ * We have to use disable_irq because otherwise you will get delayed
+ * interrupts on the APIC bus deadlocking the transmit path.
+ *
+ * Quite hairy but the chip simply wasn't designed for SMP and you can't
+ * even ACK an interrupt without risking corrupting other parallel
+ * activities on the chip." [lkml, 25 Jul 2007]
*/
@@ -219,15 +265,6 @@ static void ei_tx_timeout(struct net_device *dev)
int txsr, isr, tickssofar = jiffies - dev->trans_start;
unsigned long flags;
-#if defined(CONFIG_M32R) && defined(CONFIG_SMP)
- unsigned long icucr;
-
- local_irq_save(flags);
- icucr = inl(M32R_ICU_CR1_PORTL);
- icucr |= M32R_ICUCR_ISMOD11;
- outl(icucr, M32R_ICU_CR1_PORTL);
- local_irq_restore(flags);
-#endif
ei_local->stat.tx_errors++;
spin_lock_irqsave(&ei_local->page_lock, flags);
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 0a08d0c4e7b4..b36989097883 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -111,8 +111,6 @@ static int __init do_lne390_probe(struct net_device *dev)
int mem_start = dev->mem_start;
int ret;
- SET_MODULE_OWNER(dev);
-
if (ioaddr > 0x1ff) { /* Check a single specified location. */
if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -171,6 +169,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
{
int i, revision, ret;
unsigned long eisa_id;
+ DECLARE_MAC_BUF(mac);
if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
@@ -202,10 +201,12 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
}
#endif
- printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000);
for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i)));
- printk(".\nlne390.c: ");
+ dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
+ printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n",
+ 0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr));
+
+ printk("lne390.c: ");
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
if (dev->irq == 0) {
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 6ba6ed2b480a..be25aa33971c 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -57,12 +57,12 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
+#include <net/net_namespace.h>
struct pcpu_lstats {
unsigned long packets;
unsigned long bytes;
};
-static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
@@ -134,7 +134,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
*/
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct pcpu_lstats *lb_stats;
+ struct pcpu_lstats *pcpu_lstats, *lb_stats;
skb_orphan(skb);
@@ -154,8 +154,9 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
dev->last_rx = jiffies;
- /* it's OK to use __get_cpu_var() because BHs are off */
- lb_stats = &__get_cpu_var(pcpu_lstats);
+ /* it's OK to use per_cpu_ptr() because BHs are off */
+ pcpu_lstats = netdev_priv(dev);
+ lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
lb_stats->bytes += skb->len;
lb_stats->packets++;
@@ -166,15 +167,17 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
static struct net_device_stats *get_stats(struct net_device *dev)
{
+ const struct pcpu_lstats *pcpu_lstats;
struct net_device_stats *stats = &dev->stats;
unsigned long bytes = 0;
unsigned long packets = 0;
int i;
+ pcpu_lstats = netdev_priv(dev);
for_each_possible_cpu(i) {
const struct pcpu_lstats *lb_stats;
- lb_stats = &per_cpu(pcpu_lstats, i);
+ lb_stats = per_cpu_ptr(pcpu_lstats, i);
bytes += lb_stats->bytes;
packets += lb_stats->packets;
}
@@ -192,46 +195,107 @@ static u32 always_on(struct net_device *dev)
static const struct ethtool_ops loopback_ethtool_ops = {
.get_link = always_on,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_tx_csum = always_on,
.get_sg = always_on,
.get_rx_csum = always_on,
};
+static int loopback_dev_init(struct net_device *dev)
+{
+ struct pcpu_lstats *lstats;
+
+ lstats = alloc_percpu(struct pcpu_lstats);
+ if (!lstats)
+ return -ENOMEM;
+
+ dev->priv = lstats;
+ return 0;
+}
+
+static void loopback_dev_free(struct net_device *dev)
+{
+ struct pcpu_lstats *lstats = netdev_priv(dev);
+
+ free_percpu(lstats);
+ free_netdev(dev);
+}
+
/*
- * The loopback device is special. There is only one instance and
- * it is statically allocated. Don't do this for other devices.
+ * The loopback device is special. There is only one instance
+ * per network namespace.
*/
-struct net_device loopback_dev = {
- .name = "lo",
- .get_stats = &get_stats,
- .mtu = (16 * 1024) + 20 + 20 + 12,
- .hard_start_xmit = loopback_xmit,
- .hard_header = eth_header,
- .hard_header_cache = eth_header_cache,
- .header_cache_update = eth_header_cache_update,
- .hard_header_len = ETH_HLEN, /* 14 */
- .addr_len = ETH_ALEN, /* 6 */
- .tx_queue_len = 0,
- .type = ARPHRD_LOOPBACK, /* 0x0001*/
- .rebuild_header = eth_rebuild_header,
- .flags = IFF_LOOPBACK,
- .features = NETIF_F_SG | NETIF_F_FRAGLIST
+static void loopback_setup(struct net_device *dev)
+{
+ dev->get_stats = &get_stats;
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_start_xmit = loopback_xmit;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
+ dev->flags = IFF_LOOPBACK;
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
#ifdef LOOPBACK_TSO
- | NETIF_F_TSO
+ | NETIF_F_TSO
#endif
- | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
- | NETIF_F_LLTX,
- .ethtool_ops = &loopback_ethtool_ops,
-};
+ | NETIF_F_NO_CSUM
+ | NETIF_F_HIGHDMA
+ | NETIF_F_LLTX
+ | NETIF_F_NETNS_LOCAL,
+ dev->ethtool_ops = &loopback_ethtool_ops;
+ dev->header_ops = &eth_header_ops;
+ dev->init = loopback_dev_init;
+ dev->destructor = loopback_dev_free;
+}
/* Setup and register the loopback device. */
-static int __init loopback_init(void)
+static __net_init int loopback_net_init(struct net *net)
{
- return register_netdev(&loopback_dev);
+ struct net_device *dev;
+ int err;
+
+ err = -ENOMEM;
+ dev = alloc_netdev(0, "lo", loopback_setup);
+ if (!dev)
+ goto out;
+
+ dev->nd_net = net;
+ err = register_netdev(dev);
+ if (err)
+ goto out_free_netdev;
+
+ err = 0;
+ net->loopback_dev = dev;
+
+out:
+ if (err)
+ panic("loopback: Failed to register netdevice: %d\n", err);
+ return err;
+
+out_free_netdev:
+ free_netdev(dev);
+ goto out;
+}
+
+static __net_exit void loopback_net_exit(struct net *net)
+{
+ struct net_device *dev = net->loopback_dev;
+
+ unregister_netdev(dev);
+}
+
+static struct pernet_operations __net_initdata loopback_net_ops = {
+ .init = loopback_net_init,
+ .exit = loopback_net_exit,
};
-module_init(loopback_init);
+static int __init loopback_init(void)
+{
+ return register_pernet_device(&loopback_net_ops);
+}
-EXPORT_SYMBOL(loopback_dev);
+/* Loopback is special. It should be initialized before any other network
+ * device and network subsystem.
+ */
+fs_initcall(loopback_init);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 5fc18da1873d..c5095ecd8b11 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -350,7 +350,6 @@ struct i596_private { /* aligned to a 16-byte boundary */
struct i596_cmd *cmd_head;
int cmd_backlog;
unsigned long last_cmd;
- struct net_device_stats stats;
spinlock_t cmd_lock;
};
@@ -381,7 +380,6 @@ static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void print_eth(char *);
static void set_multicast_list(struct net_device *dev);
@@ -515,8 +513,6 @@ CLEAR_INT(void) {
outb(0, IOADDR+8);
}
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
#if 0
/* selftest or dump */
static void
@@ -532,7 +528,7 @@ i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
mdelay(30); /* random, unmotivated */
printk("lp486e i82596 %s result:\n", cmdname);
- for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+ for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
;
for (i = 0; i < m; i++) {
printk(" %04x", lp->dump.dump[i]);
@@ -672,7 +668,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp,
if (skb == NULL) {
printk ("%s: i596_rx Memory squeeze, "
"dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return 1;
}
@@ -681,27 +677,27 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp,
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
} else {
#if 0
printk("Frame reception error status %04x\n",
rfd->stat);
#endif
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rfd->stat & RFD_COLLISION)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (rfd->stat & RFD_SHORT_FRAME_ERR)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rfd->stat & RFD_DMA_ERR)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rfd->stat & RFD_NOBUFS_ERR)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rfd->stat & RFD_ALIGN_ERR)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rfd->stat & RFD_CRC_ERR)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rfd->stat & RFD_LENGTH_ERR)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
rfd->stat = rfd->count = 0;
return 0;
@@ -757,8 +753,8 @@ i596_cleanup_cmd(struct net_device *dev) {
dev_kfree_skb_any(tx_cmd_tbd->skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
cmd->pa_next = I596_NULL;
kfree((unsigned char *)tx_cmd);
@@ -869,7 +865,6 @@ static int i596_open(struct net_device *dev)
}
static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
- struct i596_private *lp = dev->priv;
struct tx_cmd *tx_cmd;
short length;
@@ -886,7 +881,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
if (tx_cmd == NULL) {
printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb (skb);
} else {
struct i596_tbd *tx_cmd_tbd;
@@ -909,7 +904,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
return 0;
@@ -922,10 +917,10 @@ i596_tx_timeout (struct net_device *dev) {
/* Transmitter timeout, serious problems. */
printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
printk ("Resetting board.\n");
/* Shutdown and restart */
@@ -935,7 +930,7 @@ i596_tx_timeout (struct net_device *dev) {
printk ("Kicking board.\n");
lp->scb.command = (CUC_START | RX_START);
CA();
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
netif_wake_queue(dev);
}
@@ -1023,7 +1018,6 @@ static int __init lp486e_probe(struct net_device *dev) {
dev->open = &i596_open;
dev->stop = &i596_close;
dev->hard_start_xmit = &i596_start_xmit;
- dev->get_stats = &i596_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->watchdog_timeo = 5*HZ;
dev->tx_timeout = i596_tx_timeout;
@@ -1080,20 +1074,20 @@ i596_handle_CU_completion(struct net_device *dev,
if (i596_debug)
print_eth(pa_to_va(tx_cmd_tbd->pa_data));
} else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (i596_debug)
printk("transmission failure:%04x\n",
cmd->status);
if (cmd->status & 0x0020)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (!(cmd->status & 0x0040))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (cmd->status & 0x0400)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (cmd->status & 0x0800)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (cmd->status & 0x1000)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
dev_kfree_skb_irq(tx_cmd_tbd->skb);
@@ -1244,12 +1238,6 @@ static int i596_close(struct net_device *dev) {
return 0;
}
-static struct net_device_stats * i596_get_stats(struct net_device *dev) {
- struct i596_private *lp = dev->priv;
-
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
*/
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 90b0c3ed4bb6..9e700749bb31 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -313,8 +313,6 @@ struct net_device * __init mac8390_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
/* Have we seen it already? */
if (slots & (1<<ndev->board->slot))
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 26a3b45a4a34..30854f094965 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -181,6 +181,7 @@ struct net_device * __init mac89x0_probe(int unit)
unsigned long ioaddr;
unsigned short sig;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct net_local));
if (!dev)
@@ -191,8 +192,6 @@ struct net_device * __init mac89x0_probe(int unit)
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
-
if (once_is_enough)
goto out;
once_is_enough = 1;
@@ -274,13 +273,11 @@ struct net_device * __init mac89x0_probe(int unit)
}
dev->irq = SLOT2IRQ(slot);
- printk(" IRQ %d ADDR ", dev->irq);
- /* print the ethernet address. */
- for (i = 0; i < ETH_ALEN; i++)
- printk("%2.2x%s", dev->dev_addr[i],
- ((i < ETH_ALEN-1) ? ":" : ""));
- printk("\n");
+ /* print the IRQ and ethernet address. */
+
+ printk(" IRQ %d ADDR %s\n",
+ dev->irq, print_mac(mac, dev->dev_addr));
dev->open = net_open;
dev->stop = net_close;
@@ -608,7 +605,7 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
MODULE_LICENSE("GPL");
-int
+int __init
init_module(void)
{
net_debug = debug;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index a4bb0264180a..047ea7be4850 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -470,47 +470,41 @@ static int macb_rx(struct macb *bp, int budget)
return received;
}
-static int macb_poll(struct net_device *dev, int *budget)
+static int macb_poll(struct napi_struct *napi, int budget)
{
- struct macb *bp = netdev_priv(dev);
- int orig_budget, work_done, retval = 0;
+ struct macb *bp = container_of(napi, struct macb, napi);
+ struct net_device *dev = bp->dev;
+ int work_done;
u32 status;
status = macb_readl(bp, RSR);
macb_writel(bp, RSR, status);
+ work_done = 0;
if (!status) {
/*
* This may happen if an interrupt was pending before
* this function was called last time, and no packets
* have been received since.
*/
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
goto out;
}
dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n",
- (unsigned long)status, *budget);
+ (unsigned long)status, budget);
if (!(status & MACB_BIT(REC))) {
dev_warn(&bp->pdev->dev,
"No RX buffers complete, status = %02lx\n",
(unsigned long)status);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
goto out;
}
- orig_budget = *budget;
- if (orig_budget > dev->quota)
- orig_budget = dev->quota;
-
- work_done = macb_rx(bp, orig_budget);
- if (work_done < orig_budget) {
- netif_rx_complete(dev);
- retval = 0;
- } else {
- retval = 1;
- }
+ work_done = macb_rx(bp, budget);
+ if (work_done < budget)
+ netif_rx_complete(dev, napi);
/*
* We've done what we can to clean the buffers. Make sure we
@@ -521,7 +515,7 @@ out:
/* TODO: Handle errors */
- return retval;
+ return work_done;
}
static irqreturn_t macb_interrupt(int irq, void *dev_id)
@@ -545,7 +539,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
}
if (status & MACB_RX_INT_FLAGS) {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
/*
* There's no point taking any more interrupts
* until we have processed the buffers
@@ -553,7 +547,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
dev_dbg(&bp->pdev->dev,
"scheduling RX softirq\n");
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
}
}
@@ -937,6 +931,8 @@ static int macb_open(struct net_device *dev)
return err;
}
+ napi_enable(&bp->napi);
+
macb_init_rings(bp);
macb_init_hw(bp);
@@ -954,6 +950,7 @@ static int macb_close(struct net_device *dev)
unsigned long flags;
netif_stop_queue(dev);
+ napi_disable(&bp->napi);
if (bp->phy_dev)
phy_stop(bp->phy_dev);
@@ -1074,6 +1071,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
unsigned long pclk_hz;
u32 config;
int err = -ENXIO;
+ DECLARE_MAC_BUF(mac);
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -1088,7 +1086,6 @@ static int __devinit macb_probe(struct platform_device *pdev)
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* TODO: Actually, we have some interesting features... */
@@ -1146,8 +1143,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->get_stats = macb_get_stats;
dev->set_multicast_list = macb_set_rx_mode;
dev->do_ioctl = macb_ioctl;
- dev->poll = macb_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &bp->napi, macb_poll, 64);
dev->ethtool_ops = &macb_ethtool_ops;
dev->base_addr = regs->start;
@@ -1195,10 +1191,9 @@ static int __devinit macb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
- "(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+ "(%s)\n",
dev->name, dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ print_mac(mac, dev->dev_addr));
phydev = bp->phy_dev;
printk(KERN_INFO "%s: attached PHY driver [%s] "
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 4e3283ebd97c..57b85acf0d16 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -374,6 +374,7 @@ struct macb {
struct clk *pclk;
struct clk *hclk;
struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
struct macb_stats hw_stats;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 52b9332810c5..95ebe72f320f 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -57,7 +57,6 @@ struct mace_data {
unsigned char tx_fullup;
unsigned char tx_active;
unsigned char tx_bad_runt;
- struct net_device_stats stats;
struct timer_list tx_timeout;
int timeout_active;
int port_aaui;
@@ -78,7 +77,6 @@ struct mace_data {
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static void mace_reset(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
@@ -103,6 +101,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
struct mace_data *mp;
const unsigned char *addr;
int j, rev, rc = -EBUSY;
+ DECLARE_MAC_BUF(mac);
if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
@@ -143,7 +142,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
rc = -ENOMEM;
goto err_release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
mp = dev->priv;
@@ -189,7 +187,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
- memset(&mp->stats, 0, sizeof(mp->stats));
memset((char *) mp->tx_cmds, 0,
(NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
init_timer(&mp->tx_timeout);
@@ -214,7 +211,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
dev->open = mace_open;
dev->stop = mace_close;
dev->hard_start_xmit = mace_xmit_start;
- dev->get_stats = mace_stats;
dev->set_multicast_list = mace_set_multicast;
dev->set_mac_address = mace_set_address;
@@ -245,11 +241,9 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
goto err_free_rx_irq;
}
- printk(KERN_INFO "%s: MACE at", dev->name);
- for (j = 0; j < 6; ++j) {
- printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
- }
- printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff);
+ printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n",
+ dev->name, print_mac(mac, dev->dev_addr),
+ mp->chipid >> 8, mp->chipid & 0xff);
return 0;
@@ -585,13 +579,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *mace_stats(struct net_device *dev)
-{
- struct mace_data *p = (struct mace_data *) dev->priv;
-
- return &p->stats;
-}
-
static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -645,19 +632,19 @@ static void mace_set_multicast(struct net_device *dev)
spin_unlock_irqrestore(&mp->lock, flags);
}
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev)
{
volatile struct mace __iomem *mb = mp->mace;
static int mace_babbles, mace_jabbers;
if (intr & MPCO)
- mp->stats.rx_missed_errors += 256;
- mp->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */
+ dev->stats.rx_missed_errors += 256;
+ dev->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */
if (intr & RNTPCO)
- mp->stats.rx_length_errors += 256;
- mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
+ dev->stats.rx_length_errors += 256;
+ dev->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
if (intr & CERR)
- ++mp->stats.tx_heartbeat_errors;
+ ++dev->stats.tx_heartbeat_errors;
if (intr & BABBLE)
if (mace_babbles++ < 4)
printk(KERN_DEBUG "mace: babbling transmitter\n");
@@ -681,7 +668,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
spin_lock_irqsave(&mp->lock, flags);
intr = in_8(&mb->ir); /* read interrupt register */
in_8(&mb->xmtrc); /* get retries */
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(mp, intr, dev);
i = mp->tx_empty;
while (in_8(&mb->pr) & XMTSV) {
@@ -694,7 +681,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
*/
intr = in_8(&mb->ir);
if (intr != 0)
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(mp, intr, dev);
if (mp->tx_bad_runt) {
fs = in_8(&mb->xmtfs);
mp->tx_bad_runt = 0;
@@ -768,14 +755,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
}
/* Update stats */
if (fs & (UFLO|LCOL|LCAR|RTRY)) {
- ++mp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (fs & LCAR)
- ++mp->stats.tx_carrier_errors;
+ ++dev->stats.tx_carrier_errors;
if (fs & (UFLO|LCOL|RTRY))
- ++mp->stats.tx_aborted_errors;
+ ++dev->stats.tx_aborted_errors;
} else {
- mp->stats.tx_bytes += mp->tx_bufs[i]->len;
- ++mp->stats.tx_packets;
+ dev->stats.tx_bytes += mp->tx_bufs[i]->len;
+ ++dev->stats.tx_packets;
}
dev_kfree_skb_irq(mp->tx_bufs[i]);
--mp->tx_active;
@@ -829,7 +816,7 @@ static void mace_tx_timeout(unsigned long data)
goto out;
/* update various counters */
- mace_handle_misc_intrs(mp, in_8(&mb->ir));
+ mace_handle_misc_intrs(mp, in_8(&mb->ir), dev);
cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
@@ -849,7 +836,7 @@ static void mace_tx_timeout(unsigned long data)
/* fix up the transmit side */
i = mp->tx_empty;
mp->tx_active = 0;
- ++mp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (mp->tx_bad_runt) {
mp->tx_bad_runt = 0;
} else if (i != mp->tx_fill) {
@@ -917,18 +904,18 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
/* got a packet, have a look at it */
skb = mp->rx_bufs[i];
if (skb == 0) {
- ++mp->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
} else if (nb > 8) {
data = skb->data;
frame_status = (data[nb-3] << 8) + data[nb-4];
if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
- ++mp->stats.rx_errors;
+ ++dev->stats.rx_errors;
if (frame_status & RS_OFLO)
- ++mp->stats.rx_over_errors;
+ ++dev->stats.rx_over_errors;
if (frame_status & RS_FRAMERR)
- ++mp->stats.rx_frame_errors;
+ ++dev->stats.rx_frame_errors;
if (frame_status & RS_FCSERR)
- ++mp->stats.rx_crc_errors;
+ ++dev->stats.rx_crc_errors;
} else {
/* Mace feature AUTO_STRIP_RCV is on by default, dropping the
* FCS on frames with 802.3 headers. This means that Ethernet
@@ -940,15 +927,15 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
nb -= 8;
skb_put(skb, nb);
skb->protocol = eth_type_trans(skb, dev);
- mp->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
mp->rx_bufs[i] = NULL;
- ++mp->stats.rx_packets;
+ ++dev->stats.rx_packets;
}
} else {
- ++mp->stats.rx_errors;
- ++mp->stats.rx_length_errors;
+ ++dev->stats.rx_errors;
+ ++dev->stats.rx_length_errors;
}
/* advance to next */
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 9a343b965975..6589239b79ee 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -65,7 +65,6 @@ struct mace_data {
unsigned char *rx_ring;
dma_addr_t rx_ring_phys;
int dma_intr;
- struct net_device_stats stats;
int rx_slot, rx_tail;
int tx_slot, tx_sloti, tx_count;
int chipid;
@@ -92,7 +91,6 @@ struct mace_frame {
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
static void mace_reset(struct net_device *dev);
@@ -196,6 +194,7 @@ static int __devinit mace_probe(struct platform_device *pdev)
unsigned char checksum = 0;
static int found = 0;
int err;
+ DECLARE_MAC_BUF(mac);
if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
return -ENODEV;
@@ -210,7 +209,6 @@ static int __devinit mace_probe(struct platform_device *pdev)
mp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
- SET_MODULE_OWNER(dev);
dev->base_addr = (u32)MACE_BASE;
mp->mace = (volatile struct mace *) MACE_BASE;
@@ -243,20 +241,16 @@ static int __devinit mace_probe(struct platform_device *pdev)
return -ENODEV;
}
- memset(&mp->stats, 0, sizeof(mp->stats));
-
dev->open = mace_open;
dev->stop = mace_close;
dev->hard_start_xmit = mace_xmit_start;
dev->tx_timeout = mace_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->get_stats = mace_stats;
dev->set_multicast_list = mace_set_multicast;
dev->set_mac_address = mace_set_address;
- printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]);
- for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]);
- printk("\n");
+ printk(KERN_INFO "%s: 68K MACE, hardware address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
err = register_netdev(dev);
if (!err)
@@ -473,8 +467,8 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
mp->tx_count--;
local_irq_restore(flags);
- mp->stats.tx_packets++;
- mp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
/* We need to copy into our xmit buffer to take care of alignment and caching issues */
skb_copy_from_linear_data(skb, mp->tx_ring, skb->len);
@@ -493,12 +487,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-static struct net_device_stats *mace_stats(struct net_device *dev)
-{
- struct mace_data *mp = netdev_priv(dev);
- return &mp->stats;
-}
-
static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = netdev_priv(dev);
@@ -556,13 +544,13 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
static int mace_babbles, mace_jabbers;
if (intr & MPCO)
- mp->stats.rx_missed_errors += 256;
- mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+ dev->stats.rx_missed_errors += 256;
+ dev->stats.rx_missed_errors += mb->mpc; /* reading clears it */
if (intr & RNTPCO)
- mp->stats.rx_length_errors += 256;
- mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+ dev->stats.rx_length_errors += 256;
+ dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */
if (intr & CERR)
- ++mp->stats.tx_heartbeat_errors;
+ ++dev->stats.tx_heartbeat_errors;
if (intr & BABBLE)
if (mace_babbles++ < 4)
printk(KERN_DEBUG "macmace: babbling transmitter\n");
@@ -601,14 +589,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
}
/* Update stats */
if (fs & (UFLO|LCOL|LCAR|RTRY)) {
- ++mp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (fs & LCAR)
- ++mp->stats.tx_carrier_errors;
+ ++dev->stats.tx_carrier_errors;
else if (fs & (UFLO|LCOL|RTRY)) {
- ++mp->stats.tx_aborted_errors;
+ ++dev->stats.tx_aborted_errors;
if (mb->xmtfs & UFLO) {
printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
- mp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
mace_txdma_reset(dev);
}
}
@@ -662,23 +650,23 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
unsigned int frame_status = mf->rcvsts;
if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
- mp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (frame_status & RS_OFLO) {
printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
- mp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
if (frame_status & RS_CLSN)
- mp->stats.collisions++;
+ dev->stats.collisions++;
if (frame_status & RS_FRAMERR)
- mp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (frame_status & RS_FCSERR)
- mp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
} else {
unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
skb = dev_alloc_skb(frame_length + 2);
if (!skb) {
- mp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
skb_reserve(skb, 2);
@@ -687,8 +675,8 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- mp->stats.rx_packets++;
- mp->stats.rx_bytes += frame_length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += frame_length;
}
}
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index e9ecdbf352ae..b267161418ea 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -223,6 +223,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
struct sonic_local *lp = netdev_priv(dev);
const int prom_addr = ONBOARD_SONIC_PROM_BASE;
int i;
+ DECLARE_MAC_BUF(mac);
/* On NuBus boards we can sometimes look in the ROM resources.
No such luck for comm-slot/onboard. */
@@ -266,13 +267,8 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
- printk(KERN_INFO "HW Address from CAM 15: ");
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk("\n");
+ printk(KERN_INFO "HW Address from CAM 15: %s\n",
+ print_mac(mac, dev->dev_addr));
} else return 0;
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
@@ -567,7 +563,7 @@ static int __init mac_sonic_probe(struct platform_device *pdev)
struct net_device *dev;
struct sonic_local *lp;
int err;
- int i;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct sonic_local));
if (!dev)
@@ -576,7 +572,6 @@ static int __init mac_sonic_probe(struct platform_device *pdev)
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
- SET_MODULE_OWNER(dev);
/* This will catch fatal stuff like -ENOMEM as well as success */
err = mac_onboard_sonic_probe(dev);
@@ -592,13 +587,8 @@ found:
if (err)
goto out;
- printk("%s: MAC ", dev->name);
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk(" IRQ %d\n", dev->irq);
+ printk("%s: MAC %s IRQ %d\n",
+ dev->name, print_mac(mac, dev->dev_addr), dev->irq);
return 0;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index dc74d006e01f..b7c81c874f7a 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -164,16 +164,25 @@ static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
const struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
- return lowerdev->hard_header(skb, lowerdev, type, daddr,
- saddr ? : dev->dev_addr, len);
+ return dev_hard_header(skb, lowerdev, type, daddr,
+ saddr ? : dev->dev_addr, len);
}
+static const struct header_ops macvlan_hard_header_ops = {
+ .create = macvlan_hard_header,
+ .rebuild = eth_rebuild_header,
+ .parse = eth_header_parse,
+ .rebuild = eth_rebuild_header,
+ .cache = eth_header_cache,
+ .cache_update = eth_header_cache_update,
+};
+
static int macvlan_open(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
@@ -282,10 +291,6 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
static const struct ethtool_ops macvlan_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_rx_csum = macvlan_ethtool_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_sg = ethtool_op_get_sg,
.get_drvinfo = macvlan_ethtool_get_drvinfo,
};
@@ -299,9 +304,9 @@ static void macvlan_setup(struct net_device *dev)
dev->change_mtu = macvlan_change_mtu;
dev->change_rx_flags = macvlan_change_rx_flags;
dev->set_multicast_list = macvlan_set_multicast_list;
- dev->hard_header = macvlan_hard_header;
dev->hard_start_xmit = macvlan_hard_start_xmit;
dev->destructor = free_netdev;
+ dev->header_ops = &macvlan_hard_header_ops,
dev->ethtool_ops = &macvlan_ethtool_ops;
dev->tx_queue_len = 0;
}
@@ -376,7 +381,7 @@ static int macvlan_newlink(struct net_device *dev,
if (!tb[IFLA_LINK])
return -EINVAL;
- lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+ lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK]));
if (lowerdev == NULL)
return -ENODEV;
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 92b403bf38b0..e25dbab67363 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -66,7 +66,6 @@ module_param(timeout, int, 0);
* packets in and out, so there is place for a packet
*/
struct meth_private {
- struct net_device_stats stats;
/* in-memory copy of MAC Control register */
unsigned long mac_ctrl;
/* in-memory copy of DMA Control register */
@@ -96,11 +95,11 @@ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
static inline void load_eaddr(struct net_device *dev)
{
int i;
- DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- (int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF,
- (int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
+ DECLARE_MAC_BUF(mac);
+
for (i = 0; i < 6; i++)
dev->dev_addr[i] = o2meth_eaddr[i];
+ DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr));
mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16;
}
@@ -401,15 +400,15 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n",
dev->name, priv->rx_write,
priv->rx_ring[priv->rx_write]->status.raw);
- priv->stats.rx_errors++;
- priv->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
skb = priv->rx_skbs[priv->rx_write];
} else {
- skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC | GFP_DMA);
+ skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC);
if (!skb) {
/* Ouch! No memory! Drop packet on the floor */
DPRINTK("No mem: dropping packet\n");
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
skb = priv->rx_skbs[priv->rx_write];
} else {
struct sk_buff *skb_c = priv->rx_skbs[priv->rx_write];
@@ -421,13 +420,13 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
priv->rx_skbs[priv->rx_write] = skb;
skb_c->protocol = eth_type_trans(skb_c, dev);
dev->last_rx = jiffies;
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
netif_rx(skb_c);
}
}
} else {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
skb=priv->rx_skbs[priv->rx_write];
#if MFE_DEBUG>0
printk(KERN_WARNING "meth: RX error: status=0x%016lx\n",status);
@@ -490,10 +489,10 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status)
#endif
if (status & METH_TX_ST_DONE) {
if (status & METH_TX_ST_SUCCESS){
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
} else {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
#if MFE_DEBUG>=1
DPRINTK("TX error: status=%016lx <",status);
if(status & METH_TX_ST_SUCCESS)
@@ -734,7 +733,7 @@ static void meth_tx_timeout(struct net_device *dev)
/* Try to reset the interface. */
meth_reset(dev);
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Clear all rings */
meth_free_tx_ring(priv);
@@ -773,12 +772,6 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/*
* Return statistics to the caller
*/
-static struct net_device_stats *meth_stats(struct net_device *dev)
-{
- struct meth_private *priv = netdev_priv(dev);
- return &priv->stats;
-}
-
/*
* The init function.
*/
@@ -796,7 +789,6 @@ static int __init meth_probe(struct platform_device *pdev)
dev->stop = meth_release;
dev->hard_start_xmit = meth_tx;
dev->do_ioctl = meth_ioctl;
- dev->get_stats = meth_stats;
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = meth_tx_timeout;
dev->watchdog_timeo = timeout;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 9853c74f6bbf..d593175ab6f0 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/mips-boards/simint.h>
@@ -22,10 +21,6 @@
#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field))
-struct mipsnet_priv {
- struct net_device_stats stats;
-};
-
static char mipsnet_string[] = "mipsnet";
/*
@@ -50,7 +45,6 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
{
int count_to_go = skb->len;
char *buf_ptr = skb->data;
- struct mipsnet_priv *mp = netdev_priv(dev);
pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n",
dev->name, __FUNCTION__, skb->len);
@@ -64,8 +58,8 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
}
- mp->stats.tx_packets++;
- mp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
return skb->len;
}
@@ -88,10 +82,9 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
{
struct sk_buff *skb;
size_t len = count;
- struct mipsnet_priv *mp = netdev_priv(dev);
if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
- mp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return -ENOMEM;
}
@@ -106,8 +99,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
dev->name, __FUNCTION__);
netif_rx(skb);
- mp->stats.rx_packets++;
- mp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
return count;
}
@@ -204,13 +197,6 @@ static int mipsnet_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *mipsnet_get_stats(struct net_device *dev)
-{
- struct mipsnet_priv *mp = netdev_priv(dev);
-
- return &mp->stats;
-}
-
static void mipsnet_set_mclist(struct net_device *dev)
{
// we don't do anything
@@ -222,7 +208,7 @@ static int __init mipsnet_probe(struct device *dev)
struct net_device *netdev;
int err;
- netdev = alloc_etherdev(sizeof(struct mipsnet_priv));
+ netdev = alloc_etherdev(0);
if (!netdev) {
err = -ENOMEM;
goto out;
@@ -233,7 +219,6 @@ static int __init mipsnet_probe(struct device *dev)
netdev->open = mipsnet_open;
netdev->stop = mipsnet_close;
netdev->hard_start_xmit = mipsnet_xmit;
- netdev->get_stats = mipsnet_get_stats;
netdev->set_multicast_list = mipsnet_set_mclist;
/*
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index 1bb088aeaf71..6b32ec94b3a8 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -30,41 +30,133 @@
* SOFTWARE.
*/
+#include <linux/workqueue.h>
+
#include "mlx4.h"
-void mlx4_handle_catas_err(struct mlx4_dev *dev)
+enum {
+ MLX4_CATAS_POLL_INTERVAL = 5 * HZ,
+};
+
+static DEFINE_SPINLOCK(catas_lock);
+
+static LIST_HEAD(catas_list);
+static struct workqueue_struct *catas_wq;
+static struct work_struct catas_work;
+
+static int internal_err_reset = 1;
+module_param(internal_err_reset, int, 0644);
+MODULE_PARM_DESC(internal_err_reset,
+ "Reset device on internal errors if non-zero (default 1)");
+
+static void dump_err_buf(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int i;
- mlx4_err(dev, "Catastrophic error detected:\n");
+ mlx4_err(dev, "Internal error detected:\n");
for (i = 0; i < priv->fw.catas_size; ++i)
mlx4_err(dev, " buf[%02x]: %08x\n",
i, swab32(readl(priv->catas_err.map + i)));
+}
- mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+static void poll_catas(unsigned long dev_ptr)
+{
+ struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ if (readl(priv->catas_err.map)) {
+ dump_err_buf(dev);
+
+ mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+
+ if (internal_err_reset) {
+ spin_lock(&catas_lock);
+ list_add(&priv->catas_err.list, &catas_list);
+ spin_unlock(&catas_lock);
+
+ queue_work(catas_wq, &catas_work);
+ }
+ } else
+ mod_timer(&priv->catas_err.timer,
+ round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
}
-void mlx4_map_catas_buf(struct mlx4_dev *dev)
+static void catas_reset(struct work_struct *work)
+{
+ struct mlx4_priv *priv, *tmppriv;
+ struct mlx4_dev *dev;
+
+ LIST_HEAD(tlist);
+ int ret;
+
+ spin_lock_irq(&catas_lock);
+ list_splice_init(&catas_list, &tlist);
+ spin_unlock_irq(&catas_lock);
+
+ list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
+ ret = mlx4_restart_one(priv->dev.pdev);
+ dev = &priv->dev;
+ if (ret)
+ mlx4_err(dev, "Reset failed (%d)\n", ret);
+ else
+ mlx4_dbg(dev, "Reset succeeded\n");
+ }
+}
+
+void mlx4_start_catas_poll(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
unsigned long addr;
+ INIT_LIST_HEAD(&priv->catas_err.list);
+ init_timer(&priv->catas_err.timer);
+ priv->catas_err.map = NULL;
+
addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
priv->fw.catas_offset;
priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
- if (!priv->catas_err.map)
- mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n",
+ if (!priv->catas_err.map) {
+ mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n",
addr);
+ return;
+ }
+ priv->catas_err.timer.data = (unsigned long) dev;
+ priv->catas_err.timer.function = poll_catas;
+ priv->catas_err.timer.expires =
+ round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL);
+ add_timer(&priv->catas_err.timer);
}
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev)
+void mlx4_stop_catas_poll(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
+ del_timer_sync(&priv->catas_err.timer);
+
if (priv->catas_err.map)
iounmap(priv->catas_err.map);
+
+ spin_lock_irq(&catas_lock);
+ list_del(&priv->catas_err.list);
+ spin_unlock_irq(&catas_lock);
+}
+
+int __init mlx4_catas_init(void)
+{
+ INIT_WORK(&catas_work, catas_reset);
+
+ catas_wq = create_singlethread_workqueue("mlx4_err");
+ if (!catas_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx4_catas_cleanup(void)
+{
+ destroy_workqueue(catas_wq);
}
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index c1f81a993f5d..db49051b97b1 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -95,7 +95,7 @@ enum {
};
enum {
- GO_BIT_TIMEOUT = 10000
+ GO_BIT_TIMEOUT_MSECS = 10000
};
struct mlx4_cmd_context {
@@ -155,7 +155,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
end = jiffies;
if (event)
- end += HZ * 10;
+ end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
while (cmd_pending(dev)) {
if (time_after_eq(jiffies, end))
@@ -184,6 +184,13 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
(event ? (1 << HCR_E_BIT) : 0) |
(op_modifier << HCR_OPMOD_SHIFT) |
op), hcr + 6);
+
+ /*
+ * Make sure that our HCR writes don't get mixed in with
+ * writes from another CPU starting a FW command.
+ */
+ mmiowb();
+
cmd->toggle = cmd->toggle ^ 1;
ret = 0;
@@ -246,8 +253,6 @@ void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
context->result = mlx4_status_to_errno(status);
context->out_param = out_param;
- context->token += priv->cmd.token_mask + 1;
-
complete(&context->done);
}
@@ -264,6 +269,7 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
spin_lock(&cmd->context_lock);
BUG_ON(cmd->free_head < 0);
context = &cmd->context[cmd->free_head];
+ context->token += cmd->token_mask + 1;
cmd->free_head = context->next;
spin_unlock(&cmd->context_lock);
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 39253d0c1590..d4441fee3d80 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -231,7 +231,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
}
EXPORT_SYMBOL_GPL(mlx4_cq_free);
-int __devinit mlx4_init_cq_table(struct mlx4_dev *dev)
+int mlx4_init_cq_table(struct mlx4_dev *dev)
{
struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
int err;
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 27a82cecd693..9c36c2034030 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -89,14 +89,12 @@ struct mlx4_eq_context {
(1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \
(1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
(1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \
- (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR) | \
(1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \
(1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \
(1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \
(1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \
(1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \
(1ull << MLX4_EVENT_TYPE_CMD))
-#define MLX4_CATAS_EVENT_MASK (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)
struct mlx4_eqe {
u8 reserved1;
@@ -264,7 +262,7 @@ static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr)
writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
return IRQ_RETVAL(work);
@@ -281,14 +279,6 @@ static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
return IRQ_HANDLED;
}
-static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr)
-{
- mlx4_handle_catas_err(dev_ptr);
-
- /* MSI-X vectors always belong to us */
- return IRQ_HANDLED;
-}
-
static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
int eq_num)
{
@@ -310,8 +300,7 @@ static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
MLX4_CMD_TIME_CLASS_A);
}
-static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev,
- struct mlx4_eq *eq)
+static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int index;
@@ -333,8 +322,8 @@ static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev,
return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
}
-static int __devinit mlx4_create_eq(struct mlx4_dev *dev, int nent,
- u8 intr, struct mlx4_eq *eq)
+static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
+ u8 intr, struct mlx4_eq *eq)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cmd_mailbox *mailbox;
@@ -490,14 +479,12 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
if (eq_table->have_irq)
free_irq(dev->pdev->irq, dev);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
if (eq_table->eq[i].have_irq)
free_irq(eq_table->eq[i].irq, eq_table->eq + i);
- if (eq_table->eq[MLX4_EQ_CATAS].have_irq)
- free_irq(eq_table->eq[MLX4_EQ_CATAS].irq, dev);
}
-static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
+static int mlx4_map_clr_int(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -518,7 +505,7 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
iounmap(priv->clr_base);
}
-int __devinit mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
+int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int ret;
@@ -560,7 +547,7 @@ void mlx4_unmap_eq_icm(struct mlx4_dev *dev)
__free_page(priv->eq_table.icm_page);
}
-int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
+int mlx4_init_eq_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
@@ -598,32 +585,19 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
if (dev->flags & MLX4_FLAG_MSI_X) {
static const char *eq_name[] = {
[MLX4_EQ_COMP] = DRV_NAME " (comp)",
- [MLX4_EQ_ASYNC] = DRV_NAME " (async)",
- [MLX4_EQ_CATAS] = DRV_NAME " (catas)"
+ [MLX4_EQ_ASYNC] = DRV_NAME " (async)"
};
- err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS,
- &priv->eq_table.eq[MLX4_EQ_CATAS]);
- if (err)
- goto err_out_async;
-
- for (i = 0; i < MLX4_EQ_CATAS; ++i) {
+ for (i = 0; i < MLX4_NUM_EQ; ++i) {
err = request_irq(priv->eq_table.eq[i].irq,
mlx4_msi_x_interrupt,
0, eq_name[i], priv->eq_table.eq + i);
if (err)
- goto err_out_catas;
+ goto err_out_async;
priv->eq_table.eq[i].have_irq = 1;
}
- err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq,
- mlx4_catas_interrupt, 0,
- eq_name[MLX4_EQ_CATAS], dev);
- if (err)
- goto err_out_catas;
-
- priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1;
} else {
err = request_irq(dev->pdev->irq, mlx4_interrupt,
IRQF_SHARED, DRV_NAME, dev);
@@ -639,22 +613,11 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
eq_set_ci(&priv->eq_table.eq[i], 1);
- if (dev->flags & MLX4_FLAG_MSI_X) {
- err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0,
- priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
- if (err)
- mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n",
- priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err);
- }
-
return 0;
-err_out_catas:
- mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
-
err_out_async:
mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
@@ -675,19 +638,13 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
int i;
- if (dev->flags & MLX4_FLAG_MSI_X)
- mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1,
- priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-
mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
mlx4_free_irqs(dev);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
mlx4_free_eq(dev, &priv->eq_table.eq[i]);
- if (dev->flags & MLX4_FLAG_MSI_X)
- mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
mlx4_unmap_clr_int(dev);
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index c45cbe43a0c4..6471d33afb7d 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -76,7 +76,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
[ 0] = "RC transport",
[ 1] = "UC transport",
[ 2] = "UD transport",
- [ 3] = "SRC transport",
+ [ 3] = "XRC transport",
[ 4] = "reliable multicast",
[ 5] = "FCoIB support",
[ 6] = "SRQ support",
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c
index b7a4aa8476fb..4b3c109d5eae 100644
--- a/drivers/net/mlx4/icm.c
+++ b/drivers/net/mlx4/icm.c
@@ -34,6 +34,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
+#include <linux/scatterlist.h>
#include <linux/mlx4/cmd.h>
@@ -50,19 +51,41 @@ enum {
MLX4_TABLE_CHUNK_SIZE = 1 << 18
};
-void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm)
+static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk)
{
- struct mlx4_icm_chunk *chunk, *tmp;
int i;
- list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
- if (chunk->nsg > 0)
- pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
- PCI_DMA_BIDIRECTIONAL);
+ if (chunk->nsg > 0)
+ pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
+ PCI_DMA_BIDIRECTIONAL);
+
+ for (i = 0; i < chunk->npages; ++i)
+ __free_pages(chunk->mem[i].page,
+ get_order(chunk->mem[i].length));
+}
+
+static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk)
+{
+ int i;
+
+ for (i = 0; i < chunk->npages; ++i)
+ dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
+ lowmem_page_address(chunk->mem[i].page),
+ sg_dma_address(&chunk->mem[i]));
+}
+
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent)
+{
+ struct mlx4_icm_chunk *chunk, *tmp;
- for (i = 0; i < chunk->npages; ++i)
- __free_pages(chunk->mem[i].page,
- get_order(chunk->mem[i].length));
+ if (!icm)
+ return;
+
+ list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
+ if (coherent)
+ mlx4_free_icm_coherent(dev, chunk);
+ else
+ mlx4_free_icm_pages(dev, chunk);
kfree(chunk);
}
@@ -70,16 +93,45 @@ void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm)
kfree(icm);
}
+static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
+{
+ mem->page = alloc_pages(gfp_mask, order);
+ if (!mem->page)
+ return -ENOMEM;
+
+ mem->length = PAGE_SIZE << order;
+ mem->offset = 0;
+ return 0;
+}
+
+static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem,
+ int order, gfp_t gfp_mask)
+{
+ void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order,
+ &sg_dma_address(mem), gfp_mask);
+ if (!buf)
+ return -ENOMEM;
+
+ sg_set_buf(mem, buf, PAGE_SIZE << order);
+ BUG_ON(mem->offset);
+ sg_dma_len(mem) = PAGE_SIZE << order;
+ return 0;
+}
+
struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
- gfp_t gfp_mask)
+ gfp_t gfp_mask, int coherent)
{
struct mlx4_icm *icm;
struct mlx4_icm_chunk *chunk = NULL;
int cur_order;
+ int ret;
+
+ /* We use sg_set_buf for coherent allocs, which assumes low memory */
+ BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
if (!icm)
- return icm;
+ return NULL;
icm->refcount = 0;
INIT_LIST_HEAD(&icm->chunk_list);
@@ -101,12 +153,20 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
while (1 << cur_order > npages)
--cur_order;
- chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order);
- if (chunk->mem[chunk->npages].page) {
- chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order;
- chunk->mem[chunk->npages].offset = 0;
+ if (coherent)
+ ret = mlx4_alloc_icm_coherent(&dev->pdev->dev,
+ &chunk->mem[chunk->npages],
+ cur_order, gfp_mask);
+ else
+ ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages],
+ cur_order, gfp_mask);
+
+ if (!ret) {
+ ++chunk->npages;
- if (++chunk->npages == MLX4_ICM_CHUNK_LEN) {
+ if (coherent)
+ ++chunk->nsg;
+ else if (chunk->npages == MLX4_ICM_CHUNK_LEN) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
@@ -125,7 +185,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
}
}
- if (chunk) {
+ if (!coherent && chunk) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
@@ -137,7 +197,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
return icm;
fail:
- mlx4_free_icm(dev, icm);
+ mlx4_free_icm(dev, icm, coherent);
return NULL;
}
@@ -202,7 +262,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
(table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
- __GFP_NOWARN);
+ __GFP_NOWARN, table->coherent);
if (!table->icm[i]) {
ret = -ENOMEM;
goto out;
@@ -210,7 +270,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
if (mlx4_MAP_ICM(dev, table->icm[i], table->virt +
(u64) i * MLX4_TABLE_CHUNK_SIZE)) {
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
ret = -ENOMEM;
goto out;
@@ -234,16 +294,16 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
if (--table->icm[i]->refcount == 0) {
mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
}
mutex_unlock(&table->mutex);
}
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj)
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle)
{
- int idx, offset, i;
+ int idx, offset, dma_offset, i;
struct mlx4_icm_chunk *chunk;
struct mlx4_icm *icm;
struct page *page = NULL;
@@ -253,15 +313,26 @@ void *mlx4_table_find(struct mlx4_icm_table *table, int obj)
mutex_lock(&table->mutex);
- idx = obj & (table->num_obj - 1);
- icm = table->icm[idx / (MLX4_TABLE_CHUNK_SIZE / table->obj_size)];
- offset = idx % (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+ idx = (obj & (table->num_obj - 1)) * table->obj_size;
+ icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE];
+ dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE;
if (!icm)
goto out;
list_for_each_entry(chunk, &icm->chunk_list, list) {
for (i = 0; i < chunk->npages; ++i) {
+ if (dma_handle && dma_offset >= 0) {
+ if (sg_dma_len(&chunk->mem[i]) > dma_offset)
+ *dma_handle = sg_dma_address(&chunk->mem[i]) +
+ dma_offset;
+ dma_offset -= sg_dma_len(&chunk->mem[i]);
+ }
+ /*
+ * DMA mapping can merge pages but not split them,
+ * so if we found the page, dma_handle has already
+ * been assigned to.
+ */
if (chunk->mem[i].length > offset) {
page = chunk->mem[i].page;
goto out;
@@ -309,7 +380,7 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
u64 virt, int obj_size, int nobj, int reserved,
- int use_lowmem)
+ int use_lowmem, int use_coherent)
{
int obj_per_chunk;
int num_icm;
@@ -327,6 +398,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
table->num_obj = nobj;
table->obj_size = obj_size;
table->lowmem = use_lowmem;
+ table->coherent = use_coherent;
mutex_init(&table->mutex);
for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
@@ -336,11 +408,11 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
(use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
- __GFP_NOWARN);
+ __GFP_NOWARN, use_coherent);
if (!table->icm[i])
goto err;
if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) {
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], use_coherent);
table->icm[i] = NULL;
goto err;
}
@@ -359,7 +431,7 @@ err:
if (table->icm[i]) {
mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE,
MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], use_coherent);
}
return -ENOMEM;
@@ -373,7 +445,7 @@ void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table)
if (table->icm[i]) {
mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], table->coherent);
}
kfree(table->icm);
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h
index bea223d879a5..6c44edf35847 100644
--- a/drivers/net/mlx4/icm.h
+++ b/drivers/net/mlx4/icm.h
@@ -67,8 +67,9 @@ struct mlx4_icm_iter {
struct mlx4_dev;
-struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, gfp_t gfp_mask);
-void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm);
+struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
+ gfp_t gfp_mask, int coherent);
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent);
int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
@@ -78,11 +79,11 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
int start, int end);
int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
u64 virt, int obj_size, int nobj, int reserved,
- int use_lowmem);
+ int use_lowmem, int use_coherent);
void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj);
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle);
int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
int start, int end);
void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c
index 9ae951bf6aa6..be5d9e90ccf2 100644
--- a/drivers/net/mlx4/intf.c
+++ b/drivers/net/mlx4/intf.c
@@ -142,6 +142,7 @@ int mlx4_register_device(struct mlx4_dev *dev)
mlx4_add_device(intf, priv);
mutex_unlock(&intf_mutex);
+ mlx4_start_catas_poll(dev);
return 0;
}
@@ -151,6 +152,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_interface *intf;
+ mlx4_stop_catas_poll(dev);
mutex_lock(&intf_mutex);
list_for_each_entry(intf, &intf_list, list)
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index a4f2e0475a71..e029b8afbd37 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
#ifdef CONFIG_PCI_MSI
-static int msi_x;
+static int msi_x = 1;
module_param(msi_x, int, 0444);
MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
@@ -78,14 +78,14 @@ static const char mlx4_version[] __devinitdata =
static struct mlx4_profile default_profile = {
.num_qp = 1 << 16,
.num_srq = 1 << 16,
- .rdmarc_per_qp = 4,
+ .rdmarc_per_qp = 1 << 4,
.num_cq = 1 << 16,
.num_mcg = 1 << 13,
.num_mpt = 1 << 17,
.num_mtt = 1 << 20,
};
-static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
{
int err;
int i;
@@ -149,7 +149,8 @@ static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev
dev->caps.max_cqes = dev_cap->max_cq_sz - 1;
dev->caps.reserved_cqs = dev_cap->reserved_cqs;
dev->caps.reserved_eqs = dev_cap->reserved_eqs;
- dev->caps.reserved_mtts = dev_cap->reserved_mtts;
+ dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts,
+ MLX4_MTT_ENTRY_PER_SEG);
dev->caps.reserved_mrws = dev_cap->reserved_mrws;
dev->caps.reserved_uars = dev_cap->reserved_uars;
dev->caps.reserved_pds = dev_cap->reserved_pds;
@@ -168,7 +169,7 @@ static int __devinit mlx4_load_fw(struct mlx4_dev *dev)
int err;
priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
+ GFP_HIGHUSER | __GFP_NOWARN, 0);
if (!priv->fw.fw_icm) {
mlx4_err(dev, "Couldn't allocate FW area, aborting.\n");
return -ENOMEM;
@@ -192,7 +193,7 @@ err_unmap_fa:
mlx4_UNMAP_FA(dev);
err_free:
- mlx4_free_icm(dev, priv->fw.fw_icm);
+ mlx4_free_icm(dev, priv->fw.fw_icm, 0);
return err;
}
@@ -207,7 +208,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_QP *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err)
goto err;
@@ -216,7 +217,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_SRQ *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_srqs,
- dev->caps.reserved_srqs, 0);
+ dev->caps.reserved_srqs, 0, 0);
if (err)
goto err_qp;
@@ -225,7 +226,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_CQ *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_cqs,
- dev->caps.reserved_cqs, 0);
+ dev->caps.reserved_cqs, 0, 0);
if (err)
goto err_srq;
@@ -236,7 +237,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
cmpt_entry_sz,
roundup_pow_of_two(MLX4_NUM_EQ +
dev->caps.reserved_eqs),
- MLX4_NUM_EQ + dev->caps.reserved_eqs, 0);
+ MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0);
if (err)
goto err_cq;
@@ -255,10 +256,8 @@ err:
return err;
}
-static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
- struct mlx4_dev_cap *dev_cap,
- struct mlx4_init_hca_param *init_hca,
- u64 icm_size)
+static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
+ struct mlx4_init_hca_param *init_hca, u64 icm_size)
{
struct mlx4_priv *priv = mlx4_priv(dev);
u64 aux_pages;
@@ -275,7 +274,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
(unsigned long long) aux_pages << 2);
priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
+ GFP_HIGHUSER | __GFP_NOWARN, 0);
if (!priv->fw.aux_icm) {
mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n");
return -ENOMEM;
@@ -299,11 +298,22 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
goto err_unmap_cmpt;
}
+ /*
+ * Reserved MTT entries must be aligned up to a cacheline
+ * boundary, since the FW will write to them, while the driver
+ * writes to all other MTT entries. (The variable
+ * dev->caps.mtt_entry_sz below is really the MTT segment
+ * size, not the raw entry size)
+ */
+ dev->caps.reserved_mtts =
+ ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz,
+ dma_get_cache_alignment()) / dev->caps.mtt_entry_sz;
+
err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table,
init_hca->mtt_base,
dev->caps.mtt_entry_sz,
dev->caps.num_mtt_segs,
- dev->caps.reserved_mtts, 1);
+ dev->caps.reserved_mtts, 1, 0);
if (err) {
mlx4_err(dev, "Failed to map MTT context memory, aborting.\n");
goto err_unmap_eq;
@@ -313,7 +323,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->dmpt_base,
dev_cap->dmpt_entry_sz,
dev->caps.num_mpts,
- dev->caps.reserved_mrws, 1);
+ dev->caps.reserved_mrws, 1, 1);
if (err) {
mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n");
goto err_unmap_mtt;
@@ -323,7 +333,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->qpc_base,
dev_cap->qpc_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map QP context memory, aborting.\n");
goto err_unmap_dmpt;
@@ -333,7 +343,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->auxc_base,
dev_cap->aux_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n");
goto err_unmap_qp;
@@ -343,7 +353,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->altc_base,
dev_cap->altc_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n");
goto err_unmap_auxc;
@@ -353,7 +363,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->rdmarc_base,
dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n");
goto err_unmap_altc;
@@ -363,7 +373,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->cqc_base,
dev_cap->cqc_entry_sz,
dev->caps.num_cqs,
- dev->caps.reserved_cqs, 0);
+ dev->caps.reserved_cqs, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map CQ context memory, aborting.\n");
goto err_unmap_rdmarc;
@@ -373,7 +383,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->srqc_base,
dev_cap->srq_entry_sz,
dev->caps.num_srqs,
- dev->caps.reserved_srqs, 0);
+ dev->caps.reserved_srqs, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n");
goto err_unmap_cq;
@@ -388,7 +398,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->mc_base, MLX4_MGM_ENTRY_SIZE,
dev->caps.num_mgms + dev->caps.num_amgms,
dev->caps.num_mgms + dev->caps.num_amgms,
- 0);
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map MCG context memory, aborting.\n");
goto err_unmap_srq;
@@ -433,7 +443,7 @@ err_unmap_aux:
mlx4_UNMAP_ICM_AUX(dev);
err_free_aux:
- mlx4_free_icm(dev, priv->fw.aux_icm);
+ mlx4_free_icm(dev, priv->fw.aux_icm, 0);
return err;
}
@@ -458,7 +468,7 @@ static void mlx4_free_icms(struct mlx4_dev *dev)
mlx4_unmap_eq_icm(dev);
mlx4_UNMAP_ICM_AUX(dev);
- mlx4_free_icm(dev, priv->fw.aux_icm);
+ mlx4_free_icm(dev, priv->fw.aux_icm, 0);
}
static void mlx4_close_hca(struct mlx4_dev *dev)
@@ -466,10 +476,10 @@ static void mlx4_close_hca(struct mlx4_dev *dev)
mlx4_CLOSE_HCA(dev, 0);
mlx4_free_icms(dev);
mlx4_UNMAP_FA(dev);
- mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm);
+ mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0);
}
-static int __devinit mlx4_init_hca(struct mlx4_dev *dev)
+static int mlx4_init_hca(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_adapter adapter;
@@ -524,8 +534,8 @@ static int __devinit mlx4_init_hca(struct mlx4_dev *dev)
}
priv->eq_table.inta_pin = adapter.inta_pin;
- priv->rev_id = adapter.revision_id;
- memcpy(priv->board_id, adapter.board_id, sizeof priv->board_id);
+ dev->rev_id = adapter.revision_id;
+ memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
return 0;
@@ -537,12 +547,12 @@ err_free_icm:
err_stop_fw:
mlx4_UNMAP_FA(dev);
- mlx4_free_icm(dev, priv->fw.fw_icm);
+ mlx4_free_icm(dev, priv->fw.fw_icm, 0);
return err;
}
-static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
+static int mlx4_setup_hca(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
@@ -583,13 +593,11 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
goto err_pd_table_free;
}
- mlx4_map_catas_buf(dev);
-
err = mlx4_init_eq_table(dev);
if (err) {
mlx4_err(dev, "Failed to initialize "
"event queue table, aborting.\n");
- goto err_catas_buf;
+ goto err_mr_table_free;
}
err = mlx4_cmd_use_events(dev);
@@ -601,13 +609,17 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
err = mlx4_NOP(dev);
if (err) {
- mlx4_err(dev, "NOP command failed to generate interrupt "
- "(IRQ %d), aborting.\n",
- priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
- if (dev->flags & MLX4_FLAG_MSI_X)
- mlx4_err(dev, "Try again with MSI-X disabled.\n");
- else
+ if (dev->flags & MLX4_FLAG_MSI_X) {
+ mlx4_warn(dev, "NOP command failed to generate MSI-X "
+ "interrupt IRQ %d).\n",
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
+ mlx4_warn(dev, "Trying again without MSI-X.\n");
+ } else {
+ mlx4_err(dev, "NOP command failed to generate interrupt "
+ "(IRQ %d), aborting.\n",
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+ }
goto err_cmd_poll;
}
@@ -659,8 +671,7 @@ err_cmd_poll:
err_eq_table_free:
mlx4_cleanup_eq_table(dev);
-err_catas_buf:
- mlx4_unmap_catas_buf(dev);
+err_mr_table_free:
mlx4_cleanup_mr_table(dev);
err_pd_table_free:
@@ -708,19 +719,12 @@ no_msi:
priv->eq_table.eq[i].irq = dev->pdev->irq;
}
-static int __devinit mlx4_init_one(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- static int mlx4_version_printed;
struct mlx4_priv *priv;
struct mlx4_dev *dev;
int err;
- if (!mlx4_version_printed) {
- printk(KERN_INFO "%s", mlx4_version);
- ++mlx4_version_printed;
- }
-
printk(KERN_INFO PFX "Initializing %s\n",
pci_name(pdev));
@@ -806,8 +810,6 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev,
goto err_free_dev;
}
- mlx4_enable_msi_x(dev);
-
if (mlx4_cmd_init(dev)) {
mlx4_err(dev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
@@ -817,7 +819,15 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev,
if (err)
goto err_cmd;
+ mlx4_enable_msi_x(dev);
+
err = mlx4_setup_hca(dev);
+ if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) {
+ dev->flags &= ~MLX4_FLAG_MSI_X;
+ pci_disable_msix(pdev);
+ err = mlx4_setup_hca(dev);
+ }
+
if (err)
goto err_close;
@@ -836,23 +846,20 @@ err_cleanup:
mlx4_cleanup_cq_table(dev);
mlx4_cmd_use_polling(dev);
mlx4_cleanup_eq_table(dev);
-
- mlx4_unmap_catas_buf(dev);
-
mlx4_cleanup_mr_table(dev);
mlx4_cleanup_pd_table(dev);
mlx4_cleanup_uar_table(dev);
err_close:
+ if (dev->flags & MLX4_FLAG_MSI_X)
+ pci_disable_msix(pdev);
+
mlx4_close_hca(dev);
err_cmd:
mlx4_cmd_cleanup(dev);
err_free_dev:
- if (dev->flags & MLX4_FLAG_MSI_X)
- pci_disable_msix(pdev);
-
kfree(priv);
err_release_bar2:
@@ -867,7 +874,20 @@ err_disable_pdev:
return err;
}
-static void __devexit mlx4_remove_one(struct pci_dev *pdev)
+static int __devinit mlx4_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static int mlx4_version_printed;
+
+ if (!mlx4_version_printed) {
+ printk(KERN_INFO "%s", mlx4_version);
+ ++mlx4_version_printed;
+ }
+
+ return mlx4_init_one(pdev, id);
+}
+
+static void mlx4_remove_one(struct pci_dev *pdev)
{
struct mlx4_dev *dev = pci_get_drvdata(pdev);
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -885,9 +905,6 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
mlx4_cleanup_cq_table(dev);
mlx4_cmd_use_polling(dev);
mlx4_cleanup_eq_table(dev);
-
- mlx4_unmap_catas_buf(dev);
-
mlx4_cleanup_mr_table(dev);
mlx4_cleanup_pd_table(dev);
@@ -908,6 +925,12 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
}
}
+int mlx4_restart_one(struct pci_dev *pdev)
+{
+ mlx4_remove_one(pdev);
+ return __mlx4_init_one(pdev, NULL);
+}
+
static struct pci_device_id mlx4_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
{ PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
@@ -930,6 +953,10 @@ static int __init mlx4_init(void)
{
int ret;
+ ret = mlx4_catas_init();
+ if (ret)
+ return ret;
+
ret = pci_register_driver(&mlx4_driver);
return ret < 0 ? ret : 0;
}
@@ -937,6 +964,7 @@ static int __init mlx4_init(void)
static void __exit mlx4_cleanup(void)
{
pci_unregister_driver(&mlx4_driver);
+ mlx4_catas_cleanup();
}
module_init(mlx4_init);
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index 672024a0ee71..a99e7729d333 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -359,7 +359,7 @@ out:
}
EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
-int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev)
+int mlx4_init_mcg_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index d9c91a71fc87..53a1cdddfc13 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -39,6 +39,7 @@
#include <linux/mutex.h>
#include <linux/radix-tree.h>
+#include <linux/timer.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/doorbell.h>
@@ -55,11 +56,7 @@ enum {
};
enum {
- MLX4_BOARD_ID_LEN = 64
-};
-
-enum {
- MLX4_MGM_ENTRY_SIZE = 0x40,
+ MLX4_MGM_ENTRY_SIZE = 0x100,
MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2),
MLX4_MTT_ENTRY_PER_SEG = 8
};
@@ -67,7 +64,6 @@ enum {
enum {
MLX4_EQ_ASYNC,
MLX4_EQ_COMP,
- MLX4_EQ_CATAS,
MLX4_NUM_EQ
};
@@ -133,6 +129,7 @@ struct mlx4_icm_table {
int num_obj;
int obj_size;
int lowmem;
+ int coherent;
struct mutex mutex;
struct mlx4_icm **icm;
};
@@ -248,7 +245,8 @@ struct mlx4_mcg_table {
struct mlx4_catas_err {
u32 __iomem *map;
- int size;
+ struct timer_list timer;
+ struct list_head list;
};
struct mlx4_priv {
@@ -276,9 +274,6 @@ struct mlx4_priv {
struct mlx4_uar driver_uar;
void __iomem *kar;
-
- u32 rev_id;
- char board_id[MLX4_BOARD_ID_LEN];
};
static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
@@ -311,9 +306,11 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
-void mlx4_map_catas_buf(struct mlx4_dev *dev);
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev);
-
+void mlx4_start_catas_poll(struct mlx4_dev *dev);
+void mlx4_stop_catas_poll(struct mlx4_dev *dev);
+int mlx4_catas_init(void);
+void mlx4_catas_cleanup(void);
+int mlx4_restart_one(struct pci_dev *pdev);
int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_device(struct mlx4_dev *dev);
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index d0808fa3ec82..0c05a10bae3b 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -68,6 +68,9 @@ struct mlx4_mpt_entry {
#define MLX4_MTT_FLAG_PRESENT 1
+#define MLX4_MPT_STATUS_SW 0xF0
+#define MLX4_MPT_STATUS_HW 0x00
+
static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order)
{
int o;
@@ -255,10 +258,8 @@ int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
int err;
index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap);
- if (index == -1) {
- err = -ENOMEM;
- goto err;
- }
+ if (index == -1)
+ return -ENOMEM;
mr->iova = iova;
mr->size = size;
@@ -269,15 +270,8 @@ int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
if (err)
- goto err_index;
-
- return 0;
-
-err_index:
- mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
+ mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
-err:
- kfree(mr);
return err;
}
EXPORT_SYMBOL_GPL(mlx4_mr_alloc);
@@ -358,58 +352,57 @@ err_table:
}
EXPORT_SYMBOL_GPL(mlx4_mr_enable);
-static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
- int num_mtt)
+static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+ int start_index, int npages, u64 *page_list)
{
- return mlx4_cmd(dev, mailbox->dma, num_mtt, 0, MLX4_CMD_WRITE_MTT,
- MLX4_CMD_TIME_CLASS_B);
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ __be64 *mtts;
+ dma_addr_t dma_handle;
+ int i;
+ int s = start_index * sizeof (u64);
+
+ /* All MTTs must fit in the same page */
+ if (start_index / (PAGE_SIZE / sizeof (u64)) !=
+ (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64)))
+ return -EINVAL;
+
+ if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1))
+ return -EINVAL;
+
+ mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg +
+ s / dev->caps.mtt_entry_sz, &dma_handle);
+ if (!mtts)
+ return -ENOMEM;
+
+ for (i = 0; i < npages; ++i)
+ mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+
+ dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE);
+
+ return 0;
}
int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int start_index, int npages, u64 *page_list)
{
- struct mlx4_cmd_mailbox *mailbox;
- __be64 *mtt_entry;
- int i;
- int err = 0;
+ int chunk;
+ int err;
if (mtt->order < 0)
return -EINVAL;
- mailbox = mlx4_alloc_cmd_mailbox(dev);
- if (IS_ERR(mailbox))
- return PTR_ERR(mailbox);
-
- mtt_entry = mailbox->buf;
-
while (npages > 0) {
- mtt_entry[0] = cpu_to_be64(mlx4_mtt_addr(dev, mtt) + start_index * 8);
- mtt_entry[1] = 0;
-
- for (i = 0; i < npages && i < MLX4_MAILBOX_SIZE / 8 - 2; ++i)
- mtt_entry[i + 2] = cpu_to_be64(page_list[i] |
- MLX4_MTT_FLAG_PRESENT);
-
- /*
- * If we have an odd number of entries to write, add
- * one more dummy entry for firmware efficiency.
- */
- if (i & 1)
- mtt_entry[i + 2] = 0;
-
- err = mlx4_WRITE_MTT(dev, mailbox, (i + 1) & ~1);
+ chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
+ err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list);
if (err)
- goto out;
+ return err;
- npages -= i;
- start_index += i;
- page_list += i;
+ npages -= chunk;
+ start_index += chunk;
+ page_list += chunk;
}
-out:
- mlx4_free_cmd_mailbox(dev, mailbox);
-
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(mlx4_write_mtt);
@@ -437,7 +430,7 @@ int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
}
EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt);
-int __devinit mlx4_init_mr_table(struct mlx4_dev *dev)
+int mlx4_init_mr_table(struct mlx4_dev *dev)
{
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
int err;
@@ -453,7 +446,7 @@ int __devinit mlx4_init_mr_table(struct mlx4_dev *dev)
goto err_buddy;
if (dev->caps.reserved_mtts) {
- if (mlx4_alloc_mtt_range(dev, ilog2(dev->caps.reserved_mtts)) == -1) {
+ if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) {
mlx4_warn(dev, "MTT table of order %d is too small.\n",
mr_table->mtt_buddy.max_order);
err = -ENOMEM;
@@ -479,3 +472,165 @@ void mlx4_cleanup_mr_table(struct mlx4_dev *dev)
mlx4_buddy_cleanup(&mr_table->mtt_buddy);
mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
}
+
+static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list,
+ int npages, u64 iova)
+{
+ int i, page_mask;
+
+ if (npages > fmr->max_pages)
+ return -EINVAL;
+
+ page_mask = (1 << fmr->page_shift) - 1;
+
+ /* We are getting page lists, so va must be page aligned. */
+ if (iova & page_mask)
+ return -EINVAL;
+
+ /* Trust the user not to pass misaligned data in page_list */
+ if (0)
+ for (i = 0; i < npages; ++i) {
+ if (page_list[i] & ~page_mask)
+ return -EINVAL;
+ }
+
+ if (fmr->maps >= fmr->max_maps)
+ return -EINVAL;
+
+ return 0;
+}
+
+int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list,
+ int npages, u64 iova, u32 *lkey, u32 *rkey)
+{
+ u32 key;
+ int i, err;
+
+ err = mlx4_check_fmr(fmr, page_list, npages, iova);
+ if (err)
+ return err;
+
+ ++fmr->maps;
+
+ key = key_to_hw_index(fmr->mr.key);
+ key += dev->caps.num_mpts;
+ *lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
+
+ *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
+
+ /* Make sure MPT status is visible before writing MTT entries */
+ wmb();
+
+ for (i = 0; i < npages; ++i)
+ fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+
+ dma_sync_single(&dev->pdev->dev, fmr->dma_handle,
+ npages * sizeof(u64), DMA_TO_DEVICE);
+
+ fmr->mpt->key = cpu_to_be32(key);
+ fmr->mpt->lkey = cpu_to_be32(key);
+ fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift));
+ fmr->mpt->start = cpu_to_be64(iova);
+
+ /* Make MTT entries are visible before setting MPT status */
+ wmb();
+
+ *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW;
+
+ /* Make sure MPT status is visible before consumer can use FMR */
+ wmb();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr);
+
+int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages,
+ int max_maps, u8 page_shift, struct mlx4_fmr *fmr)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ u64 mtt_seg;
+ int err = -ENOMEM;
+
+ if (page_shift < 12 || page_shift >= 32)
+ return -EINVAL;
+
+ /* All MTTs must fit in the same page */
+ if (max_pages * sizeof *fmr->mtts > PAGE_SIZE)
+ return -EINVAL;
+
+ fmr->page_shift = page_shift;
+ fmr->max_pages = max_pages;
+ fmr->max_maps = max_maps;
+ fmr->maps = 0;
+
+ err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages,
+ page_shift, &fmr->mr);
+ if (err)
+ return err;
+
+ mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz;
+
+ fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table,
+ fmr->mr.mtt.first_seg,
+ &fmr->dma_handle);
+ if (!fmr->mtts) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table,
+ key_to_hw_index(fmr->mr.key), NULL);
+ if (!fmr->mpt) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ return 0;
+
+err_free:
+ mlx4_mr_free(dev, &fmr->mr);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_alloc);
+
+int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
+{
+ return mlx4_mr_enable(dev, &fmr->mr);
+}
+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;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_unmap);
+
+int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
+{
+ if (fmr->maps)
+ return -EBUSY;
+
+ fmr->mr.enabled = 0;
+ mlx4_mr_free(dev, &fmr->mr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_free);
+
+int mlx4_SYNC_TPT(struct mlx4_dev *dev)
+{
+ return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000);
+}
+EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT);
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
index 23dea1ee7750..3a93c5f0f7ab 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/mlx4/pd.c
@@ -57,7 +57,7 @@ void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn)
}
EXPORT_SYMBOL_GPL(mlx4_pd_free);
-int __devinit mlx4_init_pd_table(struct mlx4_dev *dev)
+int mlx4_init_pd_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 19b48c71cf7f..cc4b1be18219 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -240,7 +240,8 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
- mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
+ if (qp->qpn < dev->caps.sqp_start + 8)
+ mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
}
EXPORT_SYMBOL_GPL(mlx4_qp_free);
@@ -250,7 +251,7 @@ static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn)
MLX4_CMD_TIME_CLASS_B);
}
-int __devinit mlx4_init_qp_table(struct mlx4_dev *dev)
+int mlx4_init_qp_table(struct mlx4_dev *dev)
{
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
int err;
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c
index e4dfd4b11a4a..e199715fabd0 100644
--- a/drivers/net/mlx4/reset.c
+++ b/drivers/net/mlx4/reset.c
@@ -119,6 +119,9 @@ int mlx4_reset(struct mlx4_dev *dev)
writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);
iounmap(reset);
+ /* Docs say to wait one second before accessing device */
+ msleep(1000);
+
end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;
do {
if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) &&
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index b061c86d6839..d23f46d692ef 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -227,7 +227,7 @@ int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_waterm
err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
if (err)
goto err_out;
- *limit_watermark = srq_context->limit_watermark;
+ *limit_watermark = be16_to_cpu(srq_context->limit_watermark);
err_out:
mlx4_free_cmd_mailbox(dev, mailbox);
@@ -235,7 +235,7 @@ err_out:
}
EXPORT_SYMBOL_GPL(mlx4_srq_query);
-int __devinit mlx4_init_srq_table(struct mlx4_dev *dev)
+int mlx4_init_srq_table(struct mlx4_dev *dev)
{
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
int err;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 1799eee88db7..b33d21f4efff 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -63,10 +63,9 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num);
static int mv643xx_eth_open(struct net_device *);
static int mv643xx_eth_stop(struct net_device *);
static int mv643xx_eth_change_mtu(struct net_device *, int);
-static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *);
static void eth_port_init_mac_tables(unsigned int eth_port_num);
#ifdef MV643XX_NAPI
-static int mv643xx_poll(struct net_device *dev, int *budget);
+static int mv643xx_poll(struct napi_struct *napi, int budget);
#endif
static int ethernet_phy_get(unsigned int eth_port_num);
static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
@@ -341,7 +340,7 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force)
if (cmd_sts & ETH_ERROR_SUMMARY) {
printk("%s: Error in TX\n", dev->name);
- mp->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
spin_unlock_irqrestore(&mp->lock, flags);
@@ -388,7 +387,7 @@ static void mv643xx_eth_free_all_tx_descs(struct net_device *dev)
static int mv643xx_eth_receive_queue(struct net_device *dev, int budget)
{
struct mv643xx_private *mp = netdev_priv(dev);
- struct net_device_stats *stats = &mp->stats;
+ struct net_device_stats *stats = &dev->stats;
unsigned int received_packets = 0;
struct sk_buff *skb;
struct pkt_info pkt_info;
@@ -534,7 +533,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
}
/* PHY status changed */
- if (eth_int_cause_ext & ETH_INT_CAUSE_PHY) {
+ if (eth_int_cause_ext & (ETH_INT_CAUSE_PHY | ETH_INT_CAUSE_STATE)) {
struct ethtool_cmd cmd;
if (mii_link_ok(&mp->mii)) {
@@ -562,7 +561,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
/* wait for previous write to complete */
mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &mp->napi);
}
#else
if (eth_int_cause & ETH_INT_CAUSE_RX)
@@ -785,6 +784,7 @@ static int mv643xx_eth_open(struct net_device *dev)
unsigned int port_num = mp->port_num;
unsigned int size;
int err;
+ DECLARE_MAC_BUF(mac);
/* Clear any pending ethernet port interrupts */
mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
@@ -880,6 +880,10 @@ static int mv643xx_eth_open(struct net_device *dev)
mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */
+#ifdef MV643XX_NAPI
+ napi_enable(&mp->napi);
+#endif
+
eth_port_start(dev);
/* Interrupt Coalescing */
@@ -982,7 +986,7 @@ static int mv643xx_eth_stop(struct net_device *dev)
mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
#ifdef MV643XX_NAPI
- netif_poll_disable(dev);
+ napi_disable(&mp->napi);
#endif
netif_carrier_off(dev);
netif_stop_queue(dev);
@@ -992,10 +996,6 @@ static int mv643xx_eth_stop(struct net_device *dev)
mv643xx_eth_free_tx_rings(dev);
mv643xx_eth_free_rx_rings(dev);
-#ifdef MV643XX_NAPI
- netif_poll_enable(dev);
-#endif
-
free_irq(dev->irq, dev);
return 0;
@@ -1007,11 +1007,12 @@ static int mv643xx_eth_stop(struct net_device *dev)
*
* This function is used in case of NAPI
*/
-static int mv643xx_poll(struct net_device *dev, int *budget)
+static int mv643xx_poll(struct napi_struct *napi, int budget)
{
- struct mv643xx_private *mp = netdev_priv(dev);
- int done = 1, orig_budget, work_done;
+ struct mv643xx_private *mp = container_of(napi, struct mv643xx_private, napi);
+ struct net_device *dev = mp->dev;
unsigned int port_num = mp->port_num;
+ int work_done;
#ifdef MV643XX_TX_FAST_REFILL
if (++mp->tx_clean_threshold > 5) {
@@ -1020,27 +1021,20 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
}
#endif
+ work_done = 0;
if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))
- != (u32) mp->rx_used_desc_q) {
- orig_budget = *budget;
- if (orig_budget > dev->quota)
- orig_budget = dev->quota;
- work_done = mv643xx_eth_receive_queue(dev, orig_budget);
- *budget -= work_done;
- dev->quota -= work_done;
- if (work_done >= orig_budget)
- done = 0;
- }
+ != (u32) mp->rx_used_desc_q)
+ work_done = mv643xx_eth_receive_queue(dev, budget);
- if (done) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
ETH_INT_UNMASK_ALL);
}
- return done ? 0 : 1;
+ return work_done;
}
#endif
@@ -1198,7 +1192,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mv643xx_private *mp = netdev_priv(dev);
- struct net_device_stats *stats = &mp->stats;
+ struct net_device_stats *stats = &dev->stats;
unsigned long flags;
BUG_ON(netif_queue_stopped(dev));
@@ -1222,7 +1216,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&mp->lock, flags);
eth_tx_submit_descs_for_skb(mp, skb);
- stats->tx_bytes = skb->len;
+ stats->tx_bytes += skb->len;
stats->tx_packets++;
dev->trans_start = jiffies;
@@ -1234,23 +1228,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0; /* success */
}
-/*
- * mv643xx_eth_get_stats
- *
- * Returns a pointer to the interface statistics.
- *
- * Input : dev - a pointer to the required interface
- *
- * Output : a pointer to the interface's statistics
- */
-
-static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
-{
- struct mv643xx_private *mp = netdev_priv(dev);
-
- return &mp->stats;
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void mv643xx_netpoll(struct net_device *netdev)
{
@@ -1333,6 +1310,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
mp = netdev_priv(dev);
+ mp->dev = dev;
+#ifdef MV643XX_NAPI
+ netif_napi_add(dev, &mp->napi, mv643xx_poll, 64);
+#endif
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
BUG_ON(!res);
@@ -1341,23 +1322,17 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev->open = mv643xx_eth_open;
dev->stop = mv643xx_eth_stop;
dev->hard_start_xmit = mv643xx_eth_start_xmit;
- dev->get_stats = mv643xx_eth_get_stats;
dev->set_mac_address = mv643xx_eth_set_mac_address;
dev->set_multicast_list = mv643xx_eth_set_rx_mode;
/* No need to Tx Timeout */
dev->tx_timeout = mv643xx_eth_tx_timeout;
-#ifdef MV643XX_NAPI
- dev->poll = mv643xx_poll;
- dev->weight = 64;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = mv643xx_netpoll;
#endif
dev->watchdog_timeo = 2 * HZ;
- dev->tx_queue_len = mp->tx_ring_size;
dev->base_addr = 0;
dev->change_mtu = mv643xx_eth_change_mtu;
dev->do_ioctl = mv643xx_eth_do_ioctl;
@@ -1432,7 +1407,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mv643xx_eth_update_pscr(dev, &cmd);
mv643xx_set_settings(dev, &cmd);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_netdev(dev);
if (err)
@@ -1440,8 +1414,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
p = dev->dev_addr;
printk(KERN_NOTICE
- "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]);
+ "%s: port %d with MAC address %s\n",
+ dev->name, port_num, print_mac(mac, p));
if (dev->features & NETIF_F_SG)
printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name);
@@ -2688,8 +2662,7 @@ static const struct mv643xx_stats mv643xx_gstrings_stats[] = {
{ "late_collision", MV643XX_STAT(mib_counters.late_collision) },
};
-#define MV643XX_STATS_LEN \
- sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats)
+#define MV643XX_STATS_LEN ARRAY_SIZE(mv643xx_gstrings_stats)
static void mv643xx_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
@@ -2701,9 +2674,14 @@ static void mv643xx_get_drvinfo(struct net_device *netdev,
drvinfo->n_stats = MV643XX_STATS_LEN;
}
-static int mv643xx_get_stats_count(struct net_device *netdev)
+static int mv643xx_get_sset_count(struct net_device *netdev, int sset)
{
- return MV643XX_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MV643XX_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void mv643xx_get_ethtool_stats(struct net_device *netdev,
@@ -2763,13 +2741,9 @@ static const struct ethtool_ops mv643xx_ethtool_ops = {
.set_settings = mv643xx_set_settings,
.get_drvinfo = mv643xx_get_drvinfo,
.get_link = mv643xx_eth_get_link,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_stats_count = mv643xx_get_stats_count,
.get_ethtool_stats = mv643xx_get_ethtool_stats,
.get_strings = mv643xx_get_strings,
- .get_stats_count = mv643xx_get_stats_count,
- .get_ethtool_stats = mv643xx_get_ethtool_stats,
.nway_reset = mv643xx_eth_nway_restart,
};
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 82f8c0cbfb64..be669eb23788 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -64,7 +64,9 @@
#define ETH_INT_CAUSE_TX_ERROR (ETH_TX_QUEUES_ENABLED << 8)
#define ETH_INT_CAUSE_TX (ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR)
#define ETH_INT_CAUSE_PHY 0x00010000
-#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY)
+#define ETH_INT_CAUSE_STATE 0x00100000
+#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY | \
+ ETH_INT_CAUSE_STATE)
#define ETH_INT_MASK_ALL 0x00000000
#define ETH_INT_MASK_ALL_EXT 0x00000000
@@ -318,6 +320,8 @@ struct mv643xx_private {
struct work_struct tx_timeout_task;
+ struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
struct mv643xx_mib_counters mib_counters;
spinlock_t lock;
diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c
index e246d00bba6d..86c9c06433cb 100644
--- a/drivers/net/mvme147.c
+++ b/drivers/net/mvme147.c
@@ -67,6 +67,7 @@ struct net_device * __init mvme147lance_probe(int unit)
u_long *addr;
u_long address;
int err;
+ DECLARE_MAC_BUF(mac);
if (!MACH_IS_MVME147 || called)
return ERR_PTR(-ENODEV);
@@ -79,8 +80,6 @@ struct net_device * __init mvme147lance_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
/* Fill the dev fields */
dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
dev->open = &m147lance_open;
@@ -103,12 +102,10 @@ struct net_device * __init mvme147lance_probe(int unit)
address=address>>8;
dev->dev_addr[3]=address&0xff;
- printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, dev->base_addr, MVME147_LANCE_IRQ,
- dev->dev_addr[0],
- dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5]);
+ printk("%s: MVME147 at 0x%08lx, irq %d, "
+ "Hardware Address %s\n",
+ dev->name, dev->base_addr, MVME147_LANCE_IRQ,
+ print_mac(mac, dev->dev_addr));
lp = (struct m147lance_private *)dev->priv;
lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index deca65330b0f..e8afa101433e 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -48,6 +48,7 @@
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
#include <linux/ip.h>
#include <linux/inet.h>
#include <linux/in.h>
@@ -62,6 +63,8 @@
#include <linux/io.h>
#include <linux/log2.h>
#include <net/checksum.h>
+#include <net/ip.h>
+#include <net/tcp.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/processor.h>
@@ -72,7 +75,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.3.1-1.248"
+#define MYRI10GE_VERSION_STR "1.3.2-1.269"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -89,6 +92,8 @@ MODULE_LICENSE("Dual BSD/GPL");
#define MYRI10GE_EEPROM_STRINGS_SIZE 256
#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
+#define MYRI10GE_MAX_LRO_DESCRIPTORS 8
+#define MYRI10GE_LRO_MAX_PKTS 64
#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
@@ -151,6 +156,8 @@ struct myri10ge_rx_done {
dma_addr_t bus;
int cnt;
int idx;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
};
struct myri10ge_priv {
@@ -163,6 +170,7 @@ struct myri10ge_priv {
int small_bytes;
int big_bytes;
struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
u8 __iomem *sram;
int sram_size;
@@ -191,6 +199,7 @@ struct myri10ge_priv {
struct timer_list watchdog_timer;
int watchdog_tx_done;
int watchdog_tx_req;
+ int watchdog_pause;
int watchdog_resets;
int tx_linearized;
int pause;
@@ -276,6 +285,14 @@ static int myri10ge_debug = -1; /* defaults above */
module_param(myri10ge_debug, int, 0);
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");
+
+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");
+
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");
@@ -1019,6 +1036,15 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
remainder -= MYRI10GE_ALLOC_SIZE;
}
+ if (mgp->csum_flag && myri10ge_lro) {
+ 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,
+ len, len, (void *)(unsigned long)csum, csum);
+ return 1;
+ }
+
hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
/* allocate an skb to attach the page(s) to. */
@@ -1099,7 +1125,7 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
}
}
-static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
+static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
{
struct myri10ge_rx_done *rx_done = &mgp->rx_done;
unsigned long rx_bytes = 0;
@@ -1108,10 +1134,11 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
int idx = rx_done->idx;
int cnt = rx_done->cnt;
+ int work_done = 0;
u16 length;
__wsum checksum;
- while (rx_done->entry[idx].length != 0 && *limit != 0) {
+ while (rx_done->entry[idx].length != 0 && work_done++ < budget) {
length = ntohs(rx_done->entry[idx].length);
rx_done->entry[idx].length = 0;
checksum = csum_unfold(rx_done->entry[idx].checksum);
@@ -1127,16 +1154,15 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
rx_bytes += rx_ok * (unsigned long)length;
cnt++;
idx = cnt & (myri10ge_max_intr_slots - 1);
-
- /* limit potential for livelock by only handling a
- * limited number of frames. */
- (*limit)--;
}
rx_done->idx = idx;
rx_done->cnt = cnt;
mgp->stats.rx_packets += rx_packets;
mgp->stats.rx_bytes += rx_bytes;
+ 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,
@@ -1144,6 +1170,7 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
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);
+ return work_done;
}
static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
@@ -1188,26 +1215,21 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
}
}
-static int myri10ge_poll(struct net_device *netdev, int *budget)
+static int myri10ge_poll(struct napi_struct *napi, int budget)
{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
+ struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi);
+ struct net_device *netdev = mgp->dev;
struct myri10ge_rx_done *rx_done = &mgp->rx_done;
- int limit, orig_limit, work_done;
+ int work_done;
/* process as many rx events as NAPI will allow */
- limit = min(*budget, netdev->quota);
- orig_limit = limit;
- myri10ge_clean_rx_done(mgp, &limit);
- work_done = orig_limit - limit;
- *budget -= work_done;
- netdev->quota -= work_done;
+ work_done = myri10ge_clean_rx_done(mgp, budget);
if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
put_be32(htonl(3), mgp->irq_claim);
- return 0;
}
- return 1;
+ return work_done;
}
static irqreturn_t myri10ge_intr(int irq, void *arg)
@@ -1225,7 +1247,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);
+ netif_rx_schedule(mgp->dev, &mgp->napi);
if (!mgp->msi_enabled) {
put_be32(0, mgp->irq_deassert);
@@ -1378,7 +1400,8 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"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"
+ "dropped_no_big_buffer", "LRO aggregated", "LRO flushed",
+ "LRO avg aggr", "LRO no_desc"
};
#define MYRI10GE_NET_STATS_LEN 21
@@ -1395,9 +1418,14 @@ myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
}
}
-static int myri10ge_get_stats_count(struct net_device *netdev)
+static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
{
- return MYRI10GE_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MYRI10GE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -1444,6 +1472,14 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
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;
+ else
+ data[i++] = 0;
+ data[i++] = mgp->rx_done.lro_mgr.stats.no_desc;
}
static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1468,15 +1504,12 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_ringparam = myri10ge_get_ringparam,
.get_rx_csum = myri10ge_get_rx_csum,
.set_rx_csum = myri10ge_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_link = ethtool_op_get_link,
.get_strings = myri10ge_get_strings,
- .get_stats_count = myri10ge_get_stats_count,
+ .get_sset_count = myri10ge_get_sset_count,
.get_ethtool_stats = myri10ge_get_ethtool_stats,
.set_msglevel = myri10ge_set_msglevel,
.get_msglevel = myri10ge_get_msglevel
@@ -1717,10 +1750,69 @@ static void myri10ge_free_irq(struct myri10ge_priv *mgp)
pci_disable_msi(pdev);
}
+static int
+myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr,
+ u64 * hdr_flags, void *priv)
+{
+ struct ethhdr *eh;
+ struct vlan_ethhdr *veh;
+ struct iphdr *iph;
+ u8 *va = page_address(frag->page) + frag->page_offset;
+ unsigned long ll_hlen;
+ __wsum csum = (__wsum) (unsigned long)priv;
+
+ /* find the mac header, aborting if not IPv4 */
+
+ eh = (struct ethhdr *)va;
+ *mac_hdr = eh;
+ ll_hlen = ETH_HLEN;
+ if (eh->h_proto != htons(ETH_P_IP)) {
+ if (eh->h_proto == htons(ETH_P_8021Q)) {
+ veh = (struct vlan_ethhdr *)va;
+ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+ return -1;
+
+ ll_hlen += VLAN_HLEN;
+
+ /*
+ * HW checksum starts ETH_HLEN bytes into
+ * frame, so we must subtract off the VLAN
+ * header's checksum before csum can be used
+ */
+ csum = csum_sub(csum, csum_partial(va + ETH_HLEN,
+ VLAN_HLEN, 0));
+ } else {
+ return -1;
+ }
+ }
+ *hdr_flags = LRO_IPV4;
+
+ iph = (struct iphdr *)(va + ll_hlen);
+ *ip_hdr = iph;
+ if (iph->protocol != IPPROTO_TCP)
+ return -1;
+ *hdr_flags |= LRO_TCP;
+ *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
+
+ /* verify the IP checksum */
+ if (unlikely(ip_fast_csum((u8 *) iph, iph->ihl)))
+ return -1;
+
+ /* verify the checksum */
+ if (unlikely(csum_tcpudp_magic(iph->saddr, iph->daddr,
+ ntohs(iph->tot_len) - (iph->ihl << 2),
+ IPPROTO_TCP, csum)))
+ return -1;
+
+ return 0;
+}
+
static int myri10ge_open(struct net_device *dev)
{
struct myri10ge_priv *mgp;
struct myri10ge_cmd cmd;
+ struct net_lro_mgr *lro_mgr;
int status, big_pow2;
mgp = netdev_priv(dev);
@@ -1852,7 +1944,19 @@ static int myri10ge_open(struct net_device *dev)
mgp->link_state = htonl(~0U);
mgp->rdma_tags_available = 15;
- netif_poll_enable(mgp->dev); /* must happen prior to any irq */
+ lro_mgr = &mgp->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->get_frag_header = myri10ge_get_frag_header;
+ lro_mgr->max_aggr = myri10ge_lro_max_pkts;
+ 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 */
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
if (status) {
@@ -1896,7 +2000,7 @@ static int myri10ge_close(struct net_device *dev)
del_timer_sync(&mgp->watchdog_timer);
mgp->running = MYRI10GE_ETH_STOPPING;
- netif_poll_disable(mgp->dev);
+ napi_disable(&mgp->napi);
netif_carrier_off(dev);
netif_stop_queue(dev);
old_down_cnt = mgp->down_cnt;
@@ -2296,6 +2400,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
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,
@@ -2343,14 +2448,8 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
printk(KERN_ERR "myri10ge: %s: Failed "
"MXGEFW_JOIN_MULTICAST_GROUP, error status:"
"%d\t", dev->name, err);
- printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- ((unsigned char *)&mc_list->dmi_addr)[0],
- ((unsigned char *)&mc_list->dmi_addr)[1],
- ((unsigned char *)&mc_list->dmi_addr)[2],
- ((unsigned char *)&mc_list->dmi_addr)[3],
- ((unsigned char *)&mc_list->dmi_addr)[4],
- ((unsigned char *)&mc_list->dmi_addr)[5]
- );
+ printk(KERN_ERR "MAC %s\n",
+ print_mac(mac, mc_list->dmi_addr));
goto abort;
}
}
@@ -2513,26 +2612,20 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
{
struct pci_dev *pdev = mgp->pdev;
struct device *dev = &pdev->dev;
- int cap, status;
- u16 val;
+ int status;
mgp->tx.boundary = 4096;
/*
* Verify the max read request size was set to 4KB
* before trying the test with 4KB.
*/
- cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (cap < 64) {
- dev_err(dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
- goto abort;
- }
- status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
- if (status != 0) {
+ status = pcie_get_readrq(pdev);
+ if (status < 0) {
dev_err(dev, "Couldn't read max read req size: %d\n", status);
goto abort;
}
- if ((val & (5 << 12)) != (5 << 12)) {
- dev_warn(dev, "Max Read Request size != 4096 (0x%x)\n", val);
+ if (status != 4096) {
+ dev_warn(dev, "Max Read Request size != 4096 (%d)\n", status);
mgp->tx.boundary = 2048;
}
/*
@@ -2800,6 +2893,7 @@ static void myri10ge_watchdog(struct work_struct *work)
static void myri10ge_watchdog_timer(unsigned long arg)
{
struct myri10ge_priv *mgp;
+ u32 rx_pause_cnt;
mgp = (struct myri10ge_priv *)arg;
@@ -2816,19 +2910,28 @@ static void myri10ge_watchdog_timer(unsigned long arg)
myri10ge_fill_thresh)
mgp->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)
+ mgp->watchdog_tx_req != mgp->watchdog_tx_done) {
/* nic seems like it might be stuck.. */
- schedule_work(&mgp->watchdog_work);
- else
- /* rearm timer */
- mod_timer(&mgp->watchdog_timer,
- jiffies + myri10ge_watchdog_timeout * HZ);
-
+ if (rx_pause_cnt != mgp->watchdog_pause) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "myri10ge %s:"
+ "TX paused, check link partner\n",
+ mgp->dev->name);
+ } else {
+ schedule_work(&mgp->watchdog_work);
+ return;
+ }
+ }
+ /* 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;
+ mgp->watchdog_pause = rx_pause_cnt;
}
static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2839,9 +2942,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
size_t bytes;
int i;
int status = -ENXIO;
- int cap;
int dac_enabled;
- u16 val;
netdev = alloc_etherdev(sizeof(*mgp));
if (netdev == NULL) {
@@ -2852,8 +2953,9 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_NETDEV_DEV(netdev, &pdev->dev);
mgp = netdev_priv(netdev);
- memset(mgp, 0, sizeof(*mgp));
mgp->dev = netdev;
+ netif_napi_add(netdev, &mgp->napi,
+ myri10ge_poll, myri10ge_napi_weight);
mgp->pdev = pdev;
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
@@ -2873,19 +2975,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
= pci_find_capability(pdev, PCI_CAP_ID_VNDR);
/* Set our max read request to 4KB */
- cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (cap < 64) {
- dev_err(&pdev->dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
- goto abort_with_netdev;
- }
- status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
- if (status != 0) {
- dev_err(&pdev->dev, "Error %d reading PCI_EXP_DEVCTL\n",
- status);
- goto abort_with_netdev;
- }
- val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);
- status = pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, val);
+ status = pcie_set_readrq(pdev, 4096);
if (status != 0) {
dev_err(&pdev->dev, "Error %d writing PCI_EXP_DEVCTL\n",
status);
@@ -2990,8 +3080,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
if (dac_enabled)
netdev->features |= NETIF_F_HIGHDMA;
- netdev->poll = myri10ge_poll;
- netdev->weight = myri10ge_napi_weight;
/* make sure we can get an irq, and that MSI can be
* setup (if available). Also ensure netdev->irq
@@ -3103,9 +3191,12 @@ static void myri10ge_remove(struct pci_dev *pdev)
}
#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008
+#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009
static struct pci_device_id myri10ge_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
+ {PCI_DEVICE
+ (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)},
{0},
};
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 13444da93273..8d29319cc5cb 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -311,12 +311,12 @@ static void myri_is_not_so_happy(struct myri_eth *mp)
#ifdef DEBUG_HEADER
static void dump_ehdr(struct ethhdr *ehdr)
{
- printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"
- "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",
- ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],
- ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],
- ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],
- ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ printk("ehdr[h_dst(%s)"
+ "h_source(%s)"
+ "h_proto(%04x)]\n",
+ print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source),
ehdr->h_proto);
}
@@ -325,13 +325,7 @@ static void dump_ehdr_and_myripad(unsigned char *stuff)
struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2);
printk("pad[%02x:%02x]", stuff[0], stuff[1]);
- printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"
- "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",
- ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],
- ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],
- ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],
- ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],
- ehdr->h_proto);
+ dump_ehdr(ehdr);
}
#endif
@@ -353,7 +347,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
dev_kfree_skb(skb);
mp->tx_skbs[entry] = NULL;
- mp->enet_stats.tx_packets++;
+ dev->stats.tx_packets++;
entry = NEXT_TX(entry);
}
mp->tx_old = entry;
@@ -434,20 +428,20 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
DRX(("ERROR["));
- mp->enet_stats.rx_errors++;
+ dev->stats.rx_errors++;
if (len < (ETH_HLEN + MYRI_PAD_LEN)) {
DRX(("BAD_LENGTH] "));
- mp->enet_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
DRX(("NO_PADDING] "));
- mp->enet_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
}
/* Return it to the LANAI. */
drop_it:
drops++;
DRX(("DROP "));
- mp->enet_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
sbus_dma_sync_single_for_device(mp->myri_sdev,
sbus_readl(&rxd->myri_scatters[0].addr),
RX_ALLOC_SIZE,
@@ -527,8 +521,8 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
netif_rx(skb);
dev->last_rx = jiffies;
- mp->enet_stats.rx_packets++;
- mp->enet_stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
next:
DRX(("NEXT\n"));
entry = NEXT_RX(entry);
@@ -596,7 +590,7 @@ static void myri_tx_timeout(struct net_device *dev)
printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
- mp->enet_stats.tx_errors++;
+ dev->stats.tx_errors++;
myri_init(mp, 0);
netif_wake_queue(dev);
}
@@ -682,8 +676,9 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp)
*/
-static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+static int myri_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN);
@@ -765,18 +760,18 @@ static int myri_rebuild_header(struct sk_buff *skb)
return 0;
}
-int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int myri_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
{
unsigned short type = hh->hh_type;
unsigned char *pad;
struct ethhdr *eth;
- struct net_device *dev = neigh->dev;
+ const struct net_device *dev = neigh->dev;
pad = ((unsigned char *) hh->hh_data) +
HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN);
eth = (struct ethhdr *) (pad + MYRI_PAD_LEN);
- if (type == __constant_htons(ETH_P_802_3))
+ if (type == htons(ETH_P_802_3))
return -1;
/* Refill MyriNet padding identifiers, this is just being anal. */
@@ -792,7 +787,9 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
/* Called by Address Resolution module to notify changes in address. */
-void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+void myri_header_cache_update(struct hh_cache *hh,
+ const struct net_device *dev,
+ const unsigned char * haddr)
{
memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
haddr, dev->addr_len);
@@ -806,9 +803,6 @@ static int myri_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static struct net_device_stats *myri_get_stats(struct net_device *dev)
-{ return &(((struct myri_eth *)dev->priv)->enet_stats); }
-
static void myri_set_multicast(struct net_device *dev)
{
/* Do nothing, all MyriCOM nodes transmit multicast frames
@@ -890,6 +884,13 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
+static const struct header_ops myri_header_ops = {
+ .create = myri_header,
+ .rebuild = myri_rebuild_header,
+ .cache = myri_header_cache,
+ .cache_update = myri_header_cache_update,
+};
+
static int __devinit myri_ether_init(struct sbus_dev *sdev)
{
static int num;
@@ -898,6 +899,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
struct myri_eth *mp;
unsigned char prop_buf[32];
int i;
+ DECLARE_MAC_BUF(mac);
DET(("myri_ether_init(%p,%d):\n", sdev, num));
dev = alloc_etherdev(sizeof(struct myri_eth));
@@ -908,7 +910,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
if (version_printed++ == 0)
printk(version);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
mp = (struct myri_eth *) dev->priv;
@@ -1061,7 +1062,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
dev->hard_start_xmit = &myri_start_xmit;
dev->tx_timeout = &myri_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &myri_get_stats;
dev->set_multicast_list = &myri_set_multicast;
dev->irq = sdev->irqs[0];
@@ -1075,11 +1075,9 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
dev->mtu = MYRINET_MTU;
dev->change_mtu = myri_change_mtu;
- dev->hard_header = myri_header;
- dev->rebuild_header = myri_rebuild_header;
+ dev->header_ops = &myri_header_ops;
+
dev->hard_header_len = (ETH_HLEN + MYRI_PAD_LEN);
- dev->hard_header_cache = myri_header_cache;
- dev->header_cache_update= myri_header_cache_update;
/* Load code onto the LANai. */
DET(("Loading LANAI firmware\n"));
@@ -1094,12 +1092,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
num++;
- printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ printk("%s: MyriCOM MyriNET Ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 2f69ef7cdccb..5d93fcc95d55 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -280,7 +280,6 @@ struct myri_eth {
void __iomem *lregs; /* Quick ptr to LANAI regs. */
struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */
struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */
- struct net_device_stats enet_stats; /* Interface stats. */
/* These are less frequently accessed. */
void __iomem *regs; /* MyriCOM register space. */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 6bb48ba80964..527f9dcc7f69 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -108,7 +108,7 @@ static int full_duplex[MAX_UNITS];
#define TX_TIMEOUT (2*HZ)
#define NATSEMI_HW_TIMEOUT 400
-#define NATSEMI_TIMER_FREQ 3*HZ
+#define NATSEMI_TIMER_FREQ 5*HZ
#define NATSEMI_PG0_NREGS 64
#define NATSEMI_RFDR_NREGS 8
#define NATSEMI_PG1_NREGS 4
@@ -560,6 +560,8 @@ struct netdev_private {
/* address of a sent-in-place packet/buffer, for later free() */
struct sk_buff *tx_skbuff[TX_RING_SIZE];
dma_addr_t tx_dma[TX_RING_SIZE];
+ struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
/* Media monitoring timer */
struct timer_list timer;
@@ -636,7 +638,7 @@ static void init_registers(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t intr_handler(int irq, void *dev_instance);
static void netdev_error(struct net_device *dev, int intr_status);
-static int natsemi_poll(struct net_device *dev, int *budget);
+static int natsemi_poll(struct napi_struct *napi, int budget);
static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
static void netdev_tx_done(struct net_device *dev);
static int natsemi_change_mtu(struct net_device *dev, int new_mtu);
@@ -803,6 +805,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
const int pcibar = 1; /* PCI base address register */
int prev_eedata;
u32 tmp;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -835,7 +838,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof (struct netdev_private));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
i = pci_request_regions(pdev, DRV_NAME);
@@ -861,6 +863,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev->irq = irq;
np = netdev_priv(dev);
+ netif_napi_add(dev, &np->napi, natsemi_poll, 64);
np->pci_dev = pdev;
pci_set_drvdata(pdev, dev);
@@ -931,8 +934,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev->do_ioctl = &netdev_ioctl;
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->poll = natsemi_poll;
- dev->weight = 64;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &natsemi_poll_controller;
@@ -958,12 +959,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
goto err_create_file;
if (netif_msg_drv(np)) {
- printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ",
- dev->name, natsemi_pci_info[chip_idx].name, iostart,
- pci_name(np->pci_dev));
- for (i = 0; i < ETH_ALEN-1; i++)
- printk("%02x:", dev->dev_addr[i]);
- printk("%02x, IRQ %d", dev->dev_addr[i], irq);
+ printk(KERN_INFO "natsemi %s: %s at %#08lx "
+ "(%s), %s, IRQ %d",
+ dev->name, natsemi_pci_info[chip_idx].name, iostart,
+ pci_name(np->pci_dev), print_mac(mac, dev->dev_addr), irq);
if (dev->if_port == PORT_TP)
printk(", port TP.\n");
else if (np->ignore_phy)
@@ -1554,6 +1553,8 @@ static int netdev_open(struct net_device *dev)
free_irq(dev->irq, dev);
return i;
}
+ napi_enable(&np->napi);
+
init_ring(dev);
spin_lock_irq(&np->lock);
init_registers(dev);
@@ -1614,7 +1615,7 @@ static void do_cable_magic(struct net_device *dev)
* (these values all come from National)
*/
if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
- struct netdev_private *np = netdev_priv(dev);
+ np = netdev_priv(dev);
/* the bug has been triggered - fix the coefficient */
writew(TSTDAT_FIXED, ioaddr + TSTDAT);
@@ -1797,7 +1798,7 @@ static void netdev_timer(unsigned long data)
struct net_device *dev = (struct net_device *)data;
struct netdev_private *np = netdev_priv(dev);
void __iomem * ioaddr = ns_ioaddr(dev);
- int next_tick = 5*HZ;
+ int next_tick = NATSEMI_TIMER_FREQ;
if (netif_msg_timer(np)) {
/* DO NOT read the IntrStatus register,
@@ -2200,10 +2201,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &np->napi)) {
/* Disable interrupts and register for poll */
natsemi_irq_disable(dev);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &np->napi);
} else
printk(KERN_WARNING
"%s: Ignoring interrupt, status %#08x, mask %#08x.\n",
@@ -2216,12 +2217,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
/* This is the NAPI poll routine. As well as the standard RX handling
* it also handles all other interrupts that the chip might raise.
*/
-static int natsemi_poll(struct net_device *dev, int *budget)
+static int natsemi_poll(struct napi_struct *napi, int budget)
{
- struct netdev_private *np = netdev_priv(dev);
+ struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+ struct net_device *dev = np->dev;
void __iomem * ioaddr = ns_ioaddr(dev);
-
- int work_to_do = min(*budget, dev->quota);
int work_done = 0;
do {
@@ -2236,7 +2236,7 @@ static int natsemi_poll(struct net_device *dev, int *budget)
if (np->intr_status &
(IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
IntrRxErr | IntrRxOverrun)) {
- netdev_rx(dev, &work_done, work_to_do);
+ netdev_rx(dev, &work_done, budget);
}
if (np->intr_status &
@@ -2250,16 +2250,13 @@ static int natsemi_poll(struct net_device *dev, int *budget)
if (np->intr_status & IntrAbnormalSummary)
netdev_error(dev, np->intr_status);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done >= work_to_do)
- return 1;
+ if (work_done >= budget)
+ return work_done;
np->intr_status = readl(ioaddr + IntrStatus);
} while (np->intr_status);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
/* Reenable interrupts providing nothing is trying to shut
* the chip down. */
@@ -2268,7 +2265,7 @@ static int natsemi_poll(struct net_device *dev, int *budget)
natsemi_irq_enable(dev);
spin_unlock(&np->lock);
- return 0;
+ return work_done;
}
/* This routine is logically part of the interrupt handler, but separated
@@ -2438,13 +2435,16 @@ static void netdev_error(struct net_device *dev, int intr_status)
dev->name);
}
np->stats.rx_fifo_errors++;
+ np->stats.rx_errors++;
}
/* Hmmmmm, it's not clear how to recover from PCI faults. */
if (intr_status & IntrPCIErr) {
printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
intr_status & IntrPCIErr);
np->stats.tx_fifo_errors++;
+ np->stats.tx_errors++;
np->stats.rx_fifo_errors++;
+ np->stats.rx_errors++;
}
spin_unlock(&np->lock);
}
@@ -2502,8 +2502,8 @@ static void __set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
- mc_filter[i/8] |= (1 << (i & 0x07));
+ int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
+ mc_filter[b/8] |= (1 << (b & 0x07));
}
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptMulticast | AcceptMyPhys;
@@ -3155,6 +3155,8 @@ static int netdev_close(struct net_device *dev)
dev->name, np->cur_tx, np->dirty_tx,
np->cur_rx, np->dirty_rx);
+ napi_disable(&np->napi);
+
/*
* FIXME: what if someone tries to close a device
* that is suspended?
@@ -3250,7 +3252,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev)
* disable_irq() to enforce synchronization.
* * natsemi_poll: checks before reenabling interrupts. suspend
* sets hands_off, disables interrupts and then waits with
- * netif_poll_disable().
+ * napi_disable().
*
* Interrupts must be disabled, otherwise hands_off can cause irq storms.
*/
@@ -3276,7 +3278,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state)
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
- netif_poll_disable(dev);
+ napi_disable(&np->napi);
/* Update the error counts. */
__get_stats(dev);
@@ -3317,6 +3319,8 @@ static int natsemi_resume (struct pci_dev *pdev)
pci_enable_device(pdev);
/* pci_power_on(pdev); */
+ napi_enable(&np->napi);
+
natsemi_reset(dev);
init_ring(dev);
disable_irq(dev->irq);
@@ -3330,7 +3334,6 @@ static int natsemi_resume (struct pci_dev *pdev)
mod_timer(&np->timer, jiffies + 1*HZ);
}
netif_device_attach(dev);
- netif_poll_enable(dev);
out:
rtnl_unlock();
return 0;
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index 38fd525f0f13..368f2560856d 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -149,8 +149,6 @@ static int __init do_ne_probe(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
- SET_MODULE_OWNER(dev);
-
/* First check any supplied i/o locations. User knows best. <cough> */
if (base_addr > 0x1ff) /* Check a single specified location. */
return ne_probe1(dev, base_addr);
@@ -206,6 +204,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
static unsigned version_printed;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
unsigned char bus_width;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -259,7 +258,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -298,12 +297,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
- }
+ printk(" %s\n", print_mac(mac, dev->dev_addr));
- printk("\n%s: %s found at %#x, using IRQ %d.\n",
+ printk("%s: %s found at %#x, using IRQ %d.\n",
dev->name, name, ioaddr, dev->irq);
ei_status.name = name;
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index c9f74bf5f491..874d291cbaed 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -191,8 +191,6 @@ static int __init do_ne_probe(struct net_device *dev)
int orig_irq = dev->irq;
#endif
- SET_MODULE_OWNER(dev);
-
/* First check any supplied i/o locations. User knows best. <cough> */
if (base_addr > 0x1ff) /* Check a single specified location. */
return ne_probe1(dev, base_addr);
@@ -293,6 +291,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
int neX000, ctron, copam, bad_card;
int reg0, ret;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -377,7 +376,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -505,16 +504,14 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
for (i = 0 ; i < ETHER_ADDR_LEN ; i++) {
dev->dev_addr[i] = SA_prom[i]
= inb_p(ioaddr + EN1_PHYS_SHIFT(i));
- printk(" %2.2x", SA_prom[i]);
}
#else
for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
dev->dev_addr[i] = SA_prom[i];
}
#endif
- printk("\n");
+ printk("%s\n", print_mac(mac, dev->dev_addr));
ei_status.name = name;
ei_status.tx_start_page = start_page;
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 089b5bb702fc..f4cd8c7e81ba 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -251,8 +251,6 @@ static int __init do_ne2_probe(struct net_device *dev)
int i;
int adapter_found = 0;
- SET_MODULE_OWNER(dev);
-
/* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
@@ -304,6 +302,7 @@ out:
static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
{
int len=0;
+ DECLARE_MAC_BUF(mac);
len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" );
len += sprintf(buf+len, "Driver written by Wim Dumon ");
@@ -314,12 +313,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
len += sprintf(buf+len, "Based on the original NE2000 drivers\n" );
len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr);
len += sprintf(buf+len, "IRQ : %d\n", dev->irq);
-
-#define HW_ADDR(i) dev->dev_addr[i]
- len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
- HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
- HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) );
-#undef HW_ADDR
+ len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr));
return len;
}
@@ -332,6 +326,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
const char *name = "NE/2";
int start_page, stop_page;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -432,7 +427,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, base_addr +
program_seq[i].offset);
@@ -471,12 +466,12 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
dev->base_addr = base_addr;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
- }
- printk("\n%s: %s found at %#x, using IRQ %d.\n",
+ printk(" %s\n", print_mac(mac, dev->dev_addr));
+
+ printk("%s: %s found at %#x, using IRQ %d.\n",
dev->name, name, base_addr, dev->irq);
mca_set_adapter_procfn(slot, (MCA_ProcFn) ne2_procinfo, dev);
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index cfdeaf7aa163..b569c90da4ba 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -212,6 +212,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
static unsigned int fnd_cnt;
long ioaddr;
int flags = pci_clone_list[chip_idx].flags;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -265,7 +266,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
dev_err(&pdev->dev, "cannot allocate ethernet device\n");
goto err_out_free_res;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Reset card. Who knows what dain-bramaged state it was left in. */
@@ -308,7 +308,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
{0x00, EN0_RSARHI},
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -366,12 +366,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
if (i)
goto err_out_free_netdev;
- printk("%s: %s found at %#lx, IRQ %d, ",
- dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
- for(i = 0; i < 6; i++) {
- printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
+ for(i = 0; i < 6; i++)
dev->dev_addr[i] = SA_prom[i];
- }
+ printk("%s: %s found at %#lx, IRQ %d, %s.\n",
+ dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
+ print_mac(mac, dev->dev_addr));
+
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return 0;
@@ -636,9 +636,6 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev,
static const struct ethtool_ops ne2k_pci_ethtool_ops = {
.get_drvinfo = ne2k_pci_get_drvinfo,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 1a6fed76d4cc..425043a88db9 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -99,6 +99,7 @@ static int __init ne3210_eisa_probe (struct device *device)
int i, retval, port_index;
struct eisa_device *edev = to_eisa_device (device);
struct net_device *dev;
+ DECLARE_MAC_BUF(mac);
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (!(dev = alloc_ei_netdev ())) {
@@ -106,7 +107,6 @@ static int __init ne3210_eisa_probe (struct device *device)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, device);
device->driver_data = dev;
ioaddr = edev->base_addr;
@@ -128,17 +128,15 @@ static int __init ne3210_eisa_probe (struct device *device)
inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
#endif
-
port_index = inb(ioaddr + NE3210_CFG2) >> 6;
- printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:",
- edev->slot, ifmap[port_index]);
for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
-
+ dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
+ printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n",
+ edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr));
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
- printk(".\nne3210.c: using IRQ %d, ", dev->irq);
+ printk("ne3210.c: using IRQ %d, ", dev->irq);
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (retval) {
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 69233f6aa05c..5ffbb8891647 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -35,95 +35,780 @@
****************************************************************/
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/console.h>
-#include <linux/tty_driver.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
-#include <linux/sysrq.h>
-#include <linux/smp.h>
#include <linux/netpoll.h>
+#include <linux/inet.h>
+#include <linux/configfs.h>
MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
MODULE_DESCRIPTION("Console driver for network interfaces");
MODULE_LICENSE("GPL");
-static char config[256];
-module_param_string(netconsole, config, 256, 0);
+#define MAX_PARAM_LENGTH 256
+#define MAX_PRINT_CHUNK 1000
+
+static char config[MAX_PARAM_LENGTH];
+module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
-static struct netpoll np = {
- .name = "netconsole",
- .dev_name = "eth0",
- .local_port = 6665,
- .remote_port = 6666,
- .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+#ifndef MODULE
+static int __init option_setup(char *opt)
+{
+ strlcpy(config, opt, MAX_PARAM_LENGTH);
+ return 1;
+}
+__setup("netconsole=", option_setup);
+#endif /* MODULE */
+
+/* Linked list of all configured targets */
+static LIST_HEAD(target_list);
+
+/* This needs to be a spinlock because write_msg() cannot sleep */
+static DEFINE_SPINLOCK(target_list_lock);
+
+/**
+ * struct netconsole_target - Represents a configured netconsole target.
+ * @list: Links this target into the target_list.
+ * @item: Links us into the configfs subsystem hierarchy.
+ * @enabled: On / off knob to enable / disable target.
+ * Visible from userspace (read-write).
+ * We maintain a strict 1:1 correspondence between this and
+ * whether the corresponding netpoll is active or inactive.
+ * Also, other parameters of a target may be modified at
+ * runtime only when it is disabled (enabled == 0).
+ * @np: The netpoll structure for this target.
+ * Contains the other userspace visible parameters:
+ * dev_name (read-write)
+ * local_port (read-write)
+ * remote_port (read-write)
+ * local_ip (read-write)
+ * remote_ip (read-write)
+ * local_mac (read-only)
+ * remote_mac (read-write)
+ */
+struct netconsole_target {
+ struct list_head list;
+#ifdef CONFIG_NETCONSOLE_DYNAMIC
+ struct config_item item;
+#endif
+ int enabled;
+ struct netpoll np;
};
-static int configured = 0;
-#define MAX_PRINT_CHUNK 1000
+#ifdef CONFIG_NETCONSOLE_DYNAMIC
-static void write_msg(struct console *con, const char *msg, unsigned int len)
+static struct configfs_subsystem netconsole_subsys;
+
+static int __init dynamic_netconsole_init(void)
{
- int frag, left;
- unsigned long flags;
+ config_group_init(&netconsole_subsys.su_group);
+ mutex_init(&netconsole_subsys.su_mutex);
+ return configfs_register_subsystem(&netconsole_subsys);
+}
- if (!np.dev)
- return;
+static void __exit dynamic_netconsole_exit(void)
+{
+ configfs_unregister_subsystem(&netconsole_subsys);
+}
+
+/*
+ * Targets that were created by parsing the boot/module option string
+ * do not exist in the configfs hierarchy (and have NULL names) and will
+ * never go away, so make these a no-op for them.
+ */
+static void netconsole_target_get(struct netconsole_target *nt)
+{
+ if (config_item_name(&nt->item))
+ config_item_get(&nt->item);
+}
+
+static void netconsole_target_put(struct netconsole_target *nt)
+{
+ if (config_item_name(&nt->item))
+ config_item_put(&nt->item);
+}
+
+#else /* !CONFIG_NETCONSOLE_DYNAMIC */
+
+static int __init dynamic_netconsole_init(void)
+{
+ return 0;
+}
- local_irq_save(flags);
+static void __exit dynamic_netconsole_exit(void)
+{
+}
- for(left = len; left; ) {
- frag = min(left, MAX_PRINT_CHUNK);
- netpoll_send_udp(&np, msg, frag);
- msg += frag;
- left -= frag;
+/*
+ * No danger of targets going away from under us when dynamic
+ * reconfigurability is off.
+ */
+static void netconsole_target_get(struct netconsole_target *nt)
+{
+}
+
+static void netconsole_target_put(struct netconsole_target *nt)
+{
+}
+
+#endif /* CONFIG_NETCONSOLE_DYNAMIC */
+
+/* Allocate new target (from boot/module param) and setup netpoll for it */
+static struct netconsole_target *alloc_param_target(char *target_config)
+{
+ int err = -ENOMEM;
+ struct netconsole_target *nt;
+
+ /*
+ * Allocate and initialize with defaults.
+ * Note that these targets get their config_item fields zeroed-out.
+ */
+ nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+ if (!nt) {
+ printk(KERN_ERR "netconsole: failed to allocate memory\n");
+ goto fail;
}
- local_irq_restore(flags);
+ nt->np.name = "netconsole";
+ strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
+ nt->np.local_port = 6665;
+ nt->np.remote_port = 6666;
+ memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+
+ /* Parse parameters and setup netpoll */
+ err = netpoll_parse_options(&nt->np, target_config);
+ if (err)
+ goto fail;
+
+ err = netpoll_setup(&nt->np);
+ if (err)
+ goto fail;
+
+ nt->enabled = 1;
+
+ return nt;
+
+fail:
+ kfree(nt);
+ return ERR_PTR(err);
}
-static struct console netconsole = {
- .name = "netcon",
- .flags = CON_ENABLED | CON_PRINTBUFFER,
- .write = write_msg
+/* Cleanup netpoll for given target (from boot/module param) and free it */
+static void free_param_target(struct netconsole_target *nt)
+{
+ netpoll_cleanup(&nt->np);
+ kfree(nt);
+}
+
+#ifdef CONFIG_NETCONSOLE_DYNAMIC
+
+/*
+ * Our subsystem hierarchy is:
+ *
+ * /sys/kernel/config/netconsole/
+ * |
+ * <target>/
+ * | enabled
+ * | dev_name
+ * | local_port
+ * | remote_port
+ * | local_ip
+ * | remote_ip
+ * | local_mac
+ * | remote_mac
+ * |
+ * <target>/...
+ */
+
+struct netconsole_target_attr {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct netconsole_target *nt,
+ char *buf);
+ ssize_t (*store)(struct netconsole_target *nt,
+ const char *buf,
+ size_t count);
};
-static int option_setup(char *opt)
+static struct netconsole_target *to_target(struct config_item *item)
{
- configured = !netpoll_parse_options(&np, opt);
- return 1;
+ return item ?
+ container_of(item, struct netconsole_target, item) :
+ NULL;
}
-__setup("netconsole=", option_setup);
+/*
+ * Wrapper over simple_strtol (base 10) with sanity and range checking.
+ * We return (signed) long only because we may want to return errors.
+ * Do not use this to convert numbers that are allowed to be negative.
+ */
+static long strtol10_check_range(const char *cp, long min, long max)
+{
+ long ret;
+ char *p = (char *) cp;
+
+ WARN_ON(min < 0);
+ WARN_ON(max < min);
+
+ ret = simple_strtol(p, &p, 10);
+
+ if (*p && (*p != '\n')) {
+ printk(KERN_ERR "netconsole: invalid input\n");
+ return -EINVAL;
+ }
+ if ((ret < min) || (ret > max)) {
+ printk(KERN_ERR "netconsole: input %ld must be between "
+ "%ld and %ld\n", ret, min, max);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*
+ * Attribute operations for netconsole_target.
+ */
+
+static ssize_t show_enabled(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled);
+}
+
+static ssize_t show_dev_name(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name);
+}
+
+static ssize_t show_local_port(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port);
+}
+
+static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port);
+}
+
+static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+ HIPQUAD(nt->np.local_ip));
+}
+
+static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+ HIPQUAD(nt->np.remote_ip));
+}
+
+static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
+{
+ DECLARE_MAC_BUF(mac);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ print_mac(mac, nt->np.local_mac));
+}
+
+static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
+{
+ DECLARE_MAC_BUF(mac);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ print_mac(mac, nt->np.remote_mac));
+}
-static int init_netconsole(void)
+/*
+ * This one is special -- targets created through the configfs interface
+ * are not enabled (and the corresponding netpoll activated) by default.
+ * The user is expected to set the desired parameters first (which
+ * would enable him to dynamically add new netpoll targets for new
+ * network interfaces as and when they come up).
+ */
+static ssize_t store_enabled(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
{
int err;
+ long enabled;
+
+ enabled = strtol10_check_range(buf, 0, 1);
+ if (enabled < 0)
+ return enabled;
+
+ if (enabled) { /* 1 */
+
+ /*
+ * Skip netpoll_parse_options() -- all the attributes are
+ * already configured via configfs. Just print them out.
+ */
+ netpoll_print_options(&nt->np);
+
+ err = netpoll_setup(&nt->np);
+ if (err)
+ return err;
+
+ printk(KERN_INFO "netconsole: network logging started\n");
+
+ } else { /* 0 */
+ netpoll_cleanup(&nt->np);
+ }
+
+ nt->enabled = enabled;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_dev_name(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ size_t len;
+
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
+
+ /* Get rid of possible trailing newline from echo(1) */
+ len = strnlen(nt->np.dev_name, IFNAMSIZ);
+ if (nt->np.dev_name[len - 1] == '\n')
+ nt->np.dev_name[len - 1] = '\0';
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_local_port(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ long local_port;
+#define __U16_MAX ((__u16) ~0U)
+
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ local_port = strtol10_check_range(buf, 0, __U16_MAX);
+ if (local_port < 0)
+ return local_port;
+
+ nt->np.local_port = local_port;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_remote_port(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ long remote_port;
+#define __U16_MAX ((__u16) ~0U)
+
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ remote_port = strtol10_check_range(buf, 0, __U16_MAX);
+ if (remote_port < 0)
+ return remote_port;
+
+ nt->np.remote_port = remote_port;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_local_ip(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ nt->np.local_ip = ntohl(in_aton(buf));
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_remote_ip(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ nt->np.remote_ip = ntohl(in_aton(buf));
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_remote_mac(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ u8 remote_mac[ETH_ALEN];
+ char *p = (char *) buf;
+ int i;
- if(strlen(config))
- option_setup(config);
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
- if(!configured) {
- printk("netconsole: not configured, aborting\n");
- return 0;
+ for (i = 0; i < ETH_ALEN - 1; i++) {
+ remote_mac[i] = simple_strtoul(p, &p, 16);
+ if (*p != ':')
+ goto invalid;
+ p++;
}
+ remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16);
+ if (*p && (*p != '\n'))
+ goto invalid;
+
+ memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+
+ return strnlen(buf, count);
+
+invalid:
+ printk(KERN_ERR "netconsole: invalid input\n");
+ return -EINVAL;
+}
+
+/*
+ * Attribute definitions for netconsole_target.
+ */
+
+#define NETCONSOLE_TARGET_ATTR_RO(_name) \
+static struct netconsole_target_attr netconsole_target_##_name = \
+ __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)
- err = netpoll_setup(&np);
+#define NETCONSOLE_TARGET_ATTR_RW(_name) \
+static struct netconsole_target_attr netconsole_target_##_name = \
+ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)
+
+NETCONSOLE_TARGET_ATTR_RW(enabled);
+NETCONSOLE_TARGET_ATTR_RW(dev_name);
+NETCONSOLE_TARGET_ATTR_RW(local_port);
+NETCONSOLE_TARGET_ATTR_RW(remote_port);
+NETCONSOLE_TARGET_ATTR_RW(local_ip);
+NETCONSOLE_TARGET_ATTR_RW(remote_ip);
+NETCONSOLE_TARGET_ATTR_RO(local_mac);
+NETCONSOLE_TARGET_ATTR_RW(remote_mac);
+
+static struct configfs_attribute *netconsole_target_attrs[] = {
+ &netconsole_target_enabled.attr,
+ &netconsole_target_dev_name.attr,
+ &netconsole_target_local_port.attr,
+ &netconsole_target_remote_port.attr,
+ &netconsole_target_local_ip.attr,
+ &netconsole_target_remote_ip.attr,
+ &netconsole_target_local_mac.attr,
+ &netconsole_target_remote_mac.attr,
+ NULL,
+};
+
+/*
+ * Item operations and type for netconsole_target.
+ */
+
+static void netconsole_target_release(struct config_item *item)
+{
+ kfree(to_target(item));
+}
+
+static ssize_t netconsole_target_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *buf)
+{
+ ssize_t ret = -EINVAL;
+ struct netconsole_target *nt = to_target(item);
+ struct netconsole_target_attr *na =
+ container_of(attr, struct netconsole_target_attr, attr);
+
+ if (na->show)
+ ret = na->show(nt, buf);
+
+ return ret;
+}
+
+static ssize_t netconsole_target_attr_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret = -EINVAL;
+ struct netconsole_target *nt = to_target(item);
+ struct netconsole_target_attr *na =
+ container_of(attr, struct netconsole_target_attr, attr);
+
+ if (na->store)
+ ret = na->store(nt, buf, count);
+
+ return ret;
+}
+
+static struct configfs_item_operations netconsole_target_item_ops = {
+ .release = netconsole_target_release,
+ .show_attribute = netconsole_target_attr_show,
+ .store_attribute = netconsole_target_attr_store,
+};
+
+static struct config_item_type netconsole_target_type = {
+ .ct_attrs = netconsole_target_attrs,
+ .ct_item_ops = &netconsole_target_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/*
+ * Group operations and type for netconsole_subsys.
+ */
+
+static struct config_item *make_netconsole_target(struct config_group *group,
+ const char *name)
+{
+ unsigned long flags;
+ struct netconsole_target *nt;
+
+ /*
+ * Allocate and initialize with defaults.
+ * Target is disabled at creation (enabled == 0).
+ */
+ nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+ if (!nt) {
+ printk(KERN_ERR "netconsole: failed to allocate memory\n");
+ return NULL;
+ }
+
+ nt->np.name = "netconsole";
+ strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
+ nt->np.local_port = 6665;
+ nt->np.remote_port = 6666;
+ memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+
+ /* Initialize the config_item member */
+ config_item_init_type_name(&nt->item, name, &netconsole_target_type);
+
+ /* Adding, but it is disabled */
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_add(&nt->list, &target_list);
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+ return &nt->item;
+}
+
+static void drop_netconsole_target(struct config_group *group,
+ struct config_item *item)
+{
+ unsigned long flags;
+ struct netconsole_target *nt = to_target(item);
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_del(&nt->list);
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+ /*
+ * The target may have never been enabled, or was manually disabled
+ * before being removed so netpoll may have already been cleaned up.
+ */
+ if (nt->enabled)
+ netpoll_cleanup(&nt->np);
+
+ config_item_put(&nt->item);
+}
+
+static struct configfs_group_operations netconsole_subsys_group_ops = {
+ .make_item = make_netconsole_target,
+ .drop_item = drop_netconsole_target,
+};
+
+static struct config_item_type netconsole_subsys_type = {
+ .ct_group_ops = &netconsole_subsys_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* The netconsole configfs subsystem */
+static struct configfs_subsystem netconsole_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "netconsole",
+ .ci_type = &netconsole_subsys_type,
+ },
+ },
+};
+
+#endif /* CONFIG_NETCONSOLE_DYNAMIC */
+
+/* Handle network interface device notifications */
+static int netconsole_netdev_event(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ unsigned long flags;
+ struct netconsole_target *nt;
+ struct net_device *dev = ptr;
+
+ if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME))
+ goto done;
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_for_each_entry(nt, &target_list, list) {
+ netconsole_target_get(nt);
+ if (nt->np.dev == dev) {
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN);
+ break;
+
+ case NETDEV_CHANGENAME:
+ strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
+ break;
+ }
+ }
+ netconsole_target_put(nt);
+ }
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block netconsole_netdev_notifier = {
+ .notifier_call = netconsole_netdev_event,
+};
+
+static void write_msg(struct console *con, const char *msg, unsigned int len)
+{
+ int frag, left;
+ unsigned long flags;
+ struct netconsole_target *nt;
+ const char *tmp;
+
+ /* Avoid taking lock and disabling interrupts unnecessarily */
+ if (list_empty(&target_list))
+ return;
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_for_each_entry(nt, &target_list, list) {
+ netconsole_target_get(nt);
+ if (nt->enabled && netif_running(nt->np.dev)) {
+ /*
+ * We nest this inside the for-each-target loop above
+ * so that we're able to get as much logging out to
+ * at least one target if we die inside here, instead
+ * of unnecessarily keeping all targets in lock-step.
+ */
+ tmp = msg;
+ for (left = len; left;) {
+ frag = min(left, MAX_PRINT_CHUNK);
+ netpoll_send_udp(&nt->np, tmp, frag);
+ tmp += frag;
+ left -= frag;
+ }
+ }
+ netconsole_target_put(nt);
+ }
+ spin_unlock_irqrestore(&target_list_lock, flags);
+}
+
+static struct console netconsole = {
+ .name = "netcon",
+ .flags = CON_ENABLED | CON_PRINTBUFFER,
+ .write = write_msg,
+};
+
+static int __init init_netconsole(void)
+{
+ int err;
+ struct netconsole_target *nt, *tmp;
+ unsigned long flags;
+ char *target_config;
+ char *input = config;
+
+ if (strnlen(input, MAX_PARAM_LENGTH)) {
+ while ((target_config = strsep(&input, ";"))) {
+ nt = alloc_param_target(target_config);
+ if (IS_ERR(nt)) {
+ err = PTR_ERR(nt);
+ goto fail;
+ }
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_add(&nt->list, &target_list);
+ spin_unlock_irqrestore(&target_list_lock, flags);
+ }
+ }
+
+ err = register_netdevice_notifier(&netconsole_netdev_notifier);
+ if (err)
+ goto fail;
+
+ err = dynamic_netconsole_init();
if (err)
- return err;
+ goto undonotifier;
register_console(&netconsole);
printk(KERN_INFO "netconsole: network logging started\n");
- return 0;
+
+ return err;
+
+undonotifier:
+ unregister_netdevice_notifier(&netconsole_netdev_notifier);
+
+fail:
+ printk(KERN_ERR "netconsole: cleaning up\n");
+
+ /*
+ * Remove all targets and destroy them (only targets created
+ * from the boot/module option exist here). Skipping the list
+ * lock is safe here, and netpoll_cleanup() will sleep.
+ */
+ list_for_each_entry_safe(nt, tmp, &target_list, list) {
+ list_del(&nt->list);
+ free_param_target(nt);
+ }
+
+ return err;
}
-static void cleanup_netconsole(void)
+static void __exit cleanup_netconsole(void)
{
+ struct netconsole_target *nt, *tmp;
+
unregister_console(&netconsole);
- netpoll_cleanup(&np);
+ dynamic_netconsole_exit();
+ unregister_netdevice_notifier(&netconsole_netdev_notifier);
+
+ /*
+ * Targets created via configfs pin references on our module
+ * and would first be rmdir(2)'ed from userspace. We reach
+ * here only when they are already destroyed, and only those
+ * created from the boot/module option are left, so remove and
+ * destroy them. Skipping the list lock is safe here, and
+ * netpoll_cleanup() will sleep.
+ */
+ list_for_each_entry_safe(nt, tmp, &target_list, list) {
+ list_del(&nt->list);
+ free_param_target(nt);
+ }
}
module_init(init_netconsole);
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 2b8da0a54998..eb0aff787dfd 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -97,7 +97,6 @@
struct netx_eth_priv {
void __iomem *sram_base, *xpec_base, *xmac_base;
int id;
- struct net_device_stats stats;
struct mii_if_info mii;
u32 msg_enable;
struct xc *xc;
@@ -129,8 +128,8 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
FIFO_PTR_FRAMELEN(len));
ndev->trans_start = jiffies;
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
netif_stop_queue(ndev);
spin_unlock_irq(&priv->lock);
@@ -156,7 +155,7 @@ static void netx_eth_receive(struct net_device *ndev)
if (unlikely(skb == NULL)) {
printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
ndev->name);
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -170,8 +169,8 @@ static void netx_eth_receive(struct net_device *ndev)
ndev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, ndev);
netif_rx(skb);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
static irqreturn_t
@@ -210,12 +209,6 @@ netx_eth_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev)
-{
- struct netx_eth_priv *priv = netdev_priv(ndev);
- return &priv->stats;
-}
-
static int netx_eth_open(struct net_device *ndev)
{
struct netx_eth_priv *priv = netdev_priv(ndev);
@@ -323,7 +316,6 @@ static int netx_eth_enable(struct net_device *ndev)
ndev->hard_start_xmit = netx_eth_hard_start_xmit;
ndev->tx_timeout = netx_eth_timeout;
ndev->watchdog_timeo = msecs_to_jiffies(5000);
- ndev->get_stats = netx_eth_query_statistics;
ndev->set_multicast_list = netx_eth_set_multicast_list;
priv->msg_enable = NETIF_MSG_LINK;
@@ -390,7 +382,6 @@ static int netx_eth_drv_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto exit;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
platform_set_drvdata(pdev, ndev);
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 325269d8ae38..fbc2553275dc 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -880,6 +880,7 @@ struct netxen_adapter {
struct netxen_adapter *master;
struct net_device *netdev;
struct pci_dev *pdev;
+ struct napi_struct napi;
struct net_device_stats net_stats;
unsigned char mac_addr[ETH_ALEN];
int mtu;
@@ -918,7 +919,7 @@ struct netxen_adapter {
u16 link_duplex;
u16 state;
u16 link_autoneg;
- int rcsum;
+ int rx_csum;
int status;
spinlock_t stats_lock;
@@ -1118,7 +1119,7 @@ static const struct netxen_brdinfo netxen_boards[] = {
{NETXEN_BRDTYPE_P2_SB31_2G, 2, "Dual Gb"},
};
-#define NUM_SUPPORTED_BOARDS (sizeof(netxen_boards)/sizeof(struct netxen_brdinfo))
+#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards)
static inline void get_brd_port_by_type(u32 type, int *ports)
{
@@ -1179,8 +1180,7 @@ dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter)
NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4))
printk(KERN_ERR "failed to read dma watchdog status\n");
- return ((netxen_get_dma_watchdog_enabled(ctrl) == 0) &&
- (netxen_get_dma_watchdog_disabled(ctrl) == 0));
+ return (netxen_get_dma_watchdog_enabled(ctrl) == 0);
}
static inline int
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 0175f6c353f6..cfb847b0cae3 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -115,8 +115,6 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
- drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
- drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
}
@@ -518,17 +516,17 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
ring->rx_jumbo_pending = 0;
for (i = 0; i < MAX_RCV_CTX; ++i) {
ring->rx_pending += adapter->recv_ctx[i].
- rcv_desc[RCV_DESC_NORMAL_CTXID].rcv_pending;
+ rcv_desc[RCV_DESC_NORMAL_CTXID].max_rx_desc_count;
ring->rx_jumbo_pending += adapter->recv_ctx[i].
- rcv_desc[RCV_DESC_JUMBO_CTXID].rcv_pending;
+ rcv_desc[RCV_DESC_JUMBO_CTXID].max_rx_desc_count;
}
+ ring->tx_pending = adapter->max_tx_desc_count;
- ring->rx_max_pending = adapter->max_rx_desc_count;
- ring->tx_max_pending = adapter->max_tx_desc_count;
- ring->rx_jumbo_max_pending = adapter->max_jumbo_rx_desc_count;
+ ring->rx_max_pending = MAX_RCV_DESCRIPTORS;
+ ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS;
ring->rx_mini_max_pending = 0;
ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static void
@@ -672,9 +670,16 @@ static int netxen_nic_reg_test(struct net_device *dev)
return 0;
}
-static int netxen_nic_diag_test_count(struct net_device *dev)
+static int netxen_get_sset_count(struct net_device *dev, int sset)
{
- return NETXEN_NIC_TEST_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return NETXEN_NIC_TEST_LEN;
+ case ETH_SS_STATS:
+ return NETXEN_NIC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -709,11 +714,6 @@ netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-static int netxen_nic_get_stats_count(struct net_device *dev)
-{
- return NETXEN_NIC_STATS_LEN;
-}
-
static void
netxen_nic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
@@ -731,6 +731,19 @@ netxen_nic_get_ethtool_stats(struct net_device *dev,
}
}
+static u32 netxen_nic_get_rx_csum(struct net_device *dev)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ return adapter->rx_csum;
+}
+
+static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ adapter->rx_csum = !!data;
+ return 0;
+}
+
struct ethtool_ops netxen_nic_ethtool_ops = {
.get_settings = netxen_nic_get_settings,
.set_settings = netxen_nic_set_settings,
@@ -744,16 +757,13 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_ringparam = netxen_nic_get_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
- .self_test_count = netxen_nic_diag_test_count,
.self_test = netxen_nic_diag_test,
.get_strings = netxen_nic_get_strings,
- .get_stats_count = netxen_nic_get_stats_count,
.get_ethtool_stats = netxen_nic_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_sset_count = netxen_get_sset_count,
+ .get_rx_csum = netxen_nic_get_rx_csum,
+ .set_rx_csum = netxen_nic_set_rx_csum,
};
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index 3276866b17e2..d72f8f8fcb50 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -649,9 +649,11 @@ enum {
#define PCIX_INT_VECTOR (0x10100)
#define PCIX_INT_MASK (0x10104)
-#define PCIX_MN_WINDOW (0x10200)
+#define PCIX_MN_WINDOW_F0 (0x10200)
+#define PCIX_MN_WINDOW(_f) (PCIX_MN_WINDOW_F0 + (0x20 * (_f)))
#define PCIX_MS_WINDOW (0x10204)
-#define PCIX_SN_WINDOW (0x10208)
+#define PCIX_SN_WINDOW_F0 (0x10208)
+#define PCIX_SN_WINDOW(_f) (PCIX_SN_WINDOW_F0 + (0x20 * (_f)))
#define PCIX_CRB_WINDOW (0x10210)
#define PCIX_CRB_WINDOW_F0 (0x10210)
#define PCIX_CRB_WINDOW_F1 (0x10230)
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index aac15421bd1e..2c19b8df98fa 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -569,7 +569,7 @@ int netxen_is_flash_supported(struct netxen_adapter *adapter)
/* if the flash size less than 4Mb, make huge war cry and die */
for (j = 1; j < 4; j++) {
addr = j * NETXEN_NIC_WINDOW_MARGIN;
- for (i = 0; i < (sizeof(locs) / sizeof(locs[0])); i++) {
+ for (i = 0; i < ARRAY_SIZE(locs); i++) {
if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0
&& netxen_rom_fast_read(adapter, (addr + locs[i]),
&val02) == 0) {
@@ -904,11 +904,11 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter,
ddr_mn_window = window;
writel(window, PCI_OFFSET_SECOND_RANGE(adapter,
NETXEN_PCIX_PH_REG
- (PCIX_MN_WINDOW)));
+ (PCIX_MN_WINDOW(adapter->ahw.pci_func))));
/* MUST make sure window is set before we forge on... */
readl(PCI_OFFSET_SECOND_RANGE(adapter,
NETXEN_PCIX_PH_REG
- (PCIX_MN_WINDOW)));
+ (PCIX_MN_WINDOW(adapter->ahw.pci_func))));
}
addr -= (window * NETXEN_WINDOW_ONE);
addr += NETXEN_PCI_DDR_NET;
@@ -929,11 +929,11 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter,
writel((window << 22),
PCI_OFFSET_SECOND_RANGE(adapter,
NETXEN_PCIX_PH_REG
- (PCIX_SN_WINDOW)));
+ (PCIX_SN_WINDOW(adapter->ahw.pci_func))));
/* MUST make sure window is set before we forge on... */
readl(PCI_OFFSET_SECOND_RANGE(adapter,
NETXEN_PCIX_PH_REG
- (PCIX_SN_WINDOW)));
+ (PCIX_SN_WINDOW(adapter->ahw.pci_func))));
}
addr -= (window * 0x400000);
addr += NETXEN_PCI_QDR_NET;
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 1811bcb8c380..37589265297e 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1118,10 +1118,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
skb = (struct sk_buff *)buffer->skb;
- if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
+ if (likely(adapter->rx_csum &&
+ netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
skb->dev = netdev;
if (desc_ctx == RCV_DESC_LRO_CTXID) {
/* True length was only available on the last pkt */
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index b703ccfe040b..2a1d6d7ec351 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,14 +39,13 @@
#include "netxen_nic_phan_reg.h"
#include <linux/dma-mapping.h>
-#include <linux/vmalloc.h>
#include <net/ip.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
-char netxen_nic_driver_name[] = "netxen-nic";
+char netxen_nic_driver_name[] = "netxen_nic";
static char netxen_nic_driver_string[] = "NetXen Network Driver version "
NETXEN_NIC_LINUX_VERSIONID;
@@ -68,7 +67,7 @@ static void netxen_tx_timeout(struct net_device *netdev);
static void netxen_tx_timeout_task(struct work_struct *work);
static void netxen_watchdog(unsigned long);
static int netxen_handle_int(struct netxen_adapter *, struct net_device *);
-static int netxen_nic_poll(struct net_device *dev, int *budget);
+static int netxen_nic_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller(struct net_device *netdev);
#endif
@@ -286,6 +285,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int valid_mac = 0;
u32 val;
int pci_func_id = PCI_FUNC(pdev->devfn);
+ DECLARE_MAC_BUF(mac);
printk(KERN_INFO "%s \n", netxen_nic_driver_string);
@@ -326,16 +326,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_res;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
adapter = netdev->priv;
- memset(adapter, 0 , sizeof(struct netxen_adapter));
adapter->ahw.pdev = pdev;
adapter->ahw.pci_func = pci_func_id;
spin_lock_init(&adapter->tx_lock);
- spin_lock_init(&adapter->lock);
/* remap phys address */
mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -403,12 +400,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->netdev = netdev;
adapter->pdev = pdev;
+ netif_napi_add(netdev, &adapter->napi,
+ netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+
/* this will be read from FW later */
adapter->intr_scheme = -1;
/* This will be reset for mezz cards */
adapter->portnum = pci_func_id;
adapter->status &= ~NETXEN_NETDEV_STATUS;
+ adapter->rx_csum = 1;
netdev->open = netxen_nic_open;
netdev->stop = netxen_nic_close;
@@ -423,8 +424,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_nic_change_mtu(netdev, netdev->mtu);
SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
- netdev->poll = netxen_nic_poll;
- netdev->weight = NETXEN_NETDEV_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = netxen_nic_poll_controller;
#endif
@@ -576,15 +575,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(netdev->perm_addr, netdev->dev_addr,
netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr)) {
- printk(KERN_ERR "%s: Bad MAC address "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- netxen_nic_driver_name,
- netdev->dev_addr[0],
- netdev->dev_addr[1],
- netdev->dev_addr[2],
- netdev->dev_addr[3],
- netdev->dev_addr[4],
- netdev->dev_addr[5]);
+ printk(KERN_ERR "%s: Bad MAC address %s.\n",
+ netxen_nic_driver_name,
+ print_mac(mac, netdev->dev_addr));
} else {
if (adapter->macaddr_set)
adapter->macaddr_set(adapter,
@@ -747,9 +740,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_nic_disable_int(adapter);
- if (adapter->irq)
- free_irq(adapter->irq, adapter);
-
if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
init_firmware_done++;
netxen_free_hw_resources(adapter);
@@ -773,28 +763,22 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
}
}
- if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
- pci_disable_msi(pdev);
-
vfree(adapter->cmd_buf_arr);
- pci_disable_device(pdev);
-
if (adapter->portnum == 0) {
if (init_firmware_done) {
- dma_watchdog_shutdown_request(adapter);
- msleep(100);
i = 100;
- while ((dma_watchdog_shutdown_poll_result(adapter) != 1) && i) {
- printk(KERN_INFO "dma_watchdog_shutdown_poll still in progress\n");
+ do {
+ if (dma_watchdog_shutdown_request(adapter) == 1)
+ break;
msleep(100);
- i--;
- }
+ if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+ break;
+ } while (--i);
- if (i == 0) {
- printk(KERN_ERR "dma_watchdog_shutdown_request failed\n");
- return;
- }
+ if (i == 0)
+ printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+ netdev->name);
/* clear the register for future unloads/loads */
writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
@@ -803,11 +787,9 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
/* leave the hw in the same state as reboot */
writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- if (netxen_pinit_from_rom(adapter, 0))
- return;
+ netxen_pinit_from_rom(adapter, 0);
msleep(1);
- if (netxen_load_firmware(adapter))
- return;
+ netxen_load_firmware(adapter);
netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
}
@@ -816,30 +798,36 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
printk(KERN_INFO "State: 0x%0x\n",
readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
- dma_watchdog_shutdown_request(adapter);
- msleep(100);
i = 100;
- while ((dma_watchdog_shutdown_poll_result(adapter) != 1) && i) {
- printk(KERN_INFO "dma_watchdog_shutdown_poll still in progress\n");
+ do {
+ if (dma_watchdog_shutdown_request(adapter) == 1)
+ break;
msleep(100);
- i--;
- }
+ if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+ break;
+ } while (--i);
if (i) {
netxen_free_adapter_offload(adapter);
} else {
- printk(KERN_ERR "failed to dma shutdown\n");
- return;
+ printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+ netdev->name);
}
-
}
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
+
+ if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+ pci_disable_msi(pdev);
+
iounmap(adapter->ahw.db_base);
iounmap(adapter->ahw.pci_base0);
iounmap(adapter->ahw.pci_base1);
iounmap(adapter->ahw.pci_base2);
pci_release_regions(pdev);
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
@@ -891,19 +879,22 @@ static int netxen_nic_open(struct net_device *netdev)
if (!adapter->driver_mismatch)
mod_timer(&adapter->watchdog_timer, jiffies);
+ napi_enable(&adapter->napi);
+
netxen_nic_enable_int(adapter);
/* Done here again so that even if phantom sw overwrote it,
* we set it */
- if (adapter->macaddr_set)
- adapter->macaddr_set(adapter, netdev->dev_addr);
if (adapter->init_port
&& adapter->init_port(adapter, adapter->portnum) != 0) {
del_timer_sync(&adapter->watchdog_timer);
printk(KERN_ERR "%s: Failed to initialize port %d\n",
netxen_nic_driver_name, adapter->portnum);
+ napi_disable(&adapter->napi);
return -EIO;
}
+ if (adapter->macaddr_set)
+ adapter->macaddr_set(adapter, netdev->dev_addr);
netxen_nic_set_link_parameters(adapter);
@@ -929,6 +920,9 @@ static int netxen_nic_close(struct net_device *netdev)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
+ napi_disable(&adapter->napi);
+
+ netxen_nic_disable_int(adapter);
cmd_buff = adapter->cmd_buf_arr;
for (i = 0; i < adapter->max_tx_desc_count; i++) {
@@ -1226,15 +1220,12 @@ static void netxen_tx_timeout_task(struct work_struct *work)
{
struct netxen_adapter *adapter =
container_of(work, struct netxen_adapter, tx_timeout_task);
- unsigned long flags;
printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
netxen_nic_driver_name, adapter->netdev->name);
- spin_lock_irqsave(&adapter->lock, flags);
netxen_nic_close(adapter->netdev);
netxen_nic_open(adapter->netdev);
- spin_unlock_irqrestore(&adapter->lock, flags);
adapter->netdev->trans_start = jiffies;
netif_wake_queue(adapter->netdev);
}
@@ -1243,34 +1234,18 @@ static int
netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
{
u32 ret = 0;
- u32 our_int = 0;
DPRINTK(INFO, "Entered handle ISR\n");
adapter->stats.ints++;
- if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
- our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
- /* not our interrupt */
- if ((our_int & (0x80 << adapter->portnum)) == 0)
- return ret;
- }
-
netxen_nic_disable_int(adapter);
- if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
- /* claim interrupt */
- if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
- writel(our_int & ~((u32)(0x80 << adapter->portnum)),
- NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
- }
- }
-
if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
- if (netif_rx_schedule_prep(netdev)) {
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
/*
* Interrupts are already disabled.
*/
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
} else {
static unsigned int intcount = 0;
if ((++intcount & 0xfff) == 0xfff)
@@ -1298,6 +1273,7 @@ irqreturn_t netxen_intr(int irq, void *data)
{
struct netxen_adapter *adapter;
struct net_device *netdev;
+ u32 our_int = 0;
if (unlikely(!irq)) {
return IRQ_NONE; /* Not our interrupt */
@@ -1305,21 +1281,35 @@ irqreturn_t netxen_intr(int irq, void *data)
adapter = (struct netxen_adapter *)data;
netdev = adapter->netdev;
- /* process our status queue (for all 4 ports) */
+
+ if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+ our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+ /* not our interrupt */
+ if ((our_int & (0x80 << adapter->portnum)) == 0)
+ return IRQ_NONE;
+ }
+
+ if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
+ /* claim interrupt */
+ if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+ writel(our_int & ~((u32)(0x80 << adapter->portnum)),
+ NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+ }
+ }
+
if (netif_running(netdev))
netxen_handle_int(adapter, netdev);
return IRQ_HANDLED;
}
-static int netxen_nic_poll(struct net_device *netdev, int *budget)
+static int netxen_nic_poll(struct napi_struct *napi, int budget)
{
- struct netxen_adapter *adapter = netdev_priv(netdev);
- int work_to_do = min(*budget, netdev->quota);
+ struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
int done = 1;
int ctx;
- int this_work_done;
- int work_done = 0;
+ int work_done;
DPRINTK(INFO, "polling for %d descriptors\n", *budget);
@@ -1337,16 +1327,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
* packets are on one context, it gets only half of the quota,
* and ends up not processing it.
*/
- this_work_done = netxen_process_rcv_ring(adapter, ctx,
- work_to_do /
- MAX_RCV_CTX);
- work_done += this_work_done;
+ work_done += netxen_process_rcv_ring(adapter, ctx,
+ budget / MAX_RCV_CTX);
}
- netdev->quota -= work_done;
- *budget -= work_done;
-
- if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0)
+ if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0)
done = 0;
if (netxen_process_cmd_ring((unsigned long)adapter) == 0)
@@ -1355,11 +1340,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
DPRINTK(INFO, "new work_done: %d work_to_do: %d\n",
work_done, work_to_do);
if (done) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
netxen_nic_enable_int(adapter);
}
- return !done;
+ return work_done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 05e0577a0e10..5b9e1b300fab 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -603,6 +603,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
int phy = physical_port[adapter->portnum];
unsigned char mac_addr[6];
int i;
+ DECLARE_MAC_BUF(mac);
for (i = 0; i < 10; i++) {
temp[0] = temp[1] = 0;
@@ -627,15 +628,10 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
if (i == 10) {
printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
netxen_nic_driver_name, adapter->netdev->name);
- printk(KERN_ERR "MAC address set: "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
-
- printk(KERN_ERR "MAC address get: "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- mac_addr[0],
- mac_addr[1],
- mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+ printk(KERN_ERR "MAC address set: %s.\n",
+ print_mac(mac, addr));
+ printk(KERN_ERR "MAC address get: %s.\n",
+ print_mac(mac, mac_addr));
}
return 0;
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 3d5b4232f65f..14a768fbce2e 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -89,7 +89,6 @@ static unsigned int ports[] __initdata =
/* Information that needs to be kept for each board. */
struct ni5010_local {
- struct net_device_stats stats;
int o_pkt_size;
spinlock_t lock;
};
@@ -103,7 +102,6 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
static void ni5010_rx(struct net_device *dev);
static void ni5010_timeout(struct net_device *dev);
static int ni5010_close(struct net_device *dev);
-static struct net_device_stats *ni5010_get_stats(struct net_device *dev);
static void ni5010_set_multicast_list(struct net_device *dev);
static void reset_receiver(struct net_device *dev);
@@ -135,8 +133,6 @@ struct net_device * __init ni5010_probe(int unit)
PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = ni5010_probe1(dev, io);
} else if (io != 0) { /* Don't probe at all. */
@@ -207,6 +203,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
unsigned int data = 0;
int boguscount = 40;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
dev->base_addr = ioaddr;
dev->irq = irq;
@@ -272,8 +269,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
for (i=0; i<6; i++) {
outw(i, IE_GP);
- printk("%2.2x ", dev->dev_addr[i] = inb(IE_SAPROM));
+ dev->dev_addr[i] = inb(IE_SAPROM);
}
+ printk("%s ", print_mac(mac, dev->dev_addr));
PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
@@ -336,7 +334,6 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
dev->open = ni5010_open;
dev->stop = ni5010_close;
dev->hard_start_xmit = ni5010_send_packet;
- dev->get_stats = ni5010_get_stats;
dev->set_multicast_list = ni5010_set_multicast_list;
dev->tx_timeout = ni5010_timeout;
dev->watchdog_timeo = HZ/20;
@@ -534,11 +531,11 @@ static void ni5010_rx(struct net_device *dev)
if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
- lp->stats.rx_errors++;
- if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++;
- if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++;
- if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++;
- if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
+ if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
+ if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
+ if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
outb(0xff, EDLC_RCLR); /* Clear the interrupt */
return;
}
@@ -549,8 +546,8 @@ static void ni5010_rx(struct net_device *dev)
if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
dev->name, i_pkt_size));
- lp->stats.rx_errors++;
- lp->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
return;
}
@@ -558,7 +555,7 @@ static void ni5010_rx(struct net_device *dev)
skb = dev_alloc_skb(i_pkt_size + 3);
if (skb == NULL) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -575,8 +572,8 @@ static void ni5010_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += i_pkt_size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += i_pkt_size;
PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
dev->name, i_pkt_size));
@@ -604,14 +601,14 @@ static int process_xmt_interrupt(struct net_device *dev)
/* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
outb(MM_EN_XMT | MM_MUX, IE_MMODE);
outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
- lp->stats.collisions++;
+ dev->stats.collisions++;
return 1;
}
/* FIXME: handle other xmt error conditions */
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += lp->o_pkt_size;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += lp->o_pkt_size;
netif_wake_queue(dev);
PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
@@ -640,24 +637,6 @@ static int ni5010_close(struct net_device *dev)
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
-{
- struct ni5010_local *lp = netdev_priv(dev);
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name));
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
-
- /* cli(); */
- /* Update the statistics from the device registers. */
- /* We do this in the interrupt handler */
- /* sti(); */
-
- return &lp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
@@ -670,14 +649,10 @@ static void ni5010_set_multicast_list(struct net_device *dev)
PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
- if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) {
+ if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) {
dev->flags |= IFF_PROMISC;
outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
- } else if (dev->mc_list) {
- /* Sorry, multicast not supported */
- PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name));
- outb(RMD_BROADCAST, EDLC_RMODE);
} else {
PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 5e7999db2096..6b3384a24f07 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -382,8 +382,6 @@ struct net_device * __init ni52_probe(int unit)
memend = dev->mem_end;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = ni52_probe1(dev, io);
} else if (io > 0) { /* Don't probe at all. */
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 4ef5fe345191..097685245112 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -550,7 +550,6 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
}
dev->base_addr = ioaddr;
- SET_MODULE_OWNER(dev);
dev->open = ni65_open;
dev->stop = ni65_close;
dev->hard_start_xmit = ni65_send_packet;
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
new file mode 100644
index 000000000000..43bfe7e6b6f5
--- /dev/null
+++ b/drivers/net/niu.c
@@ -0,0 +1,7939 @@
+/* niu.c: Neptune ethernet driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/mii.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/ipv6.h>
+#include <linux/log2.h>
+#include <linux/jiffies.h>
+#include <linux/crc32.h>
+
+#include <linux/io.h>
+
+#ifdef CONFIG_SPARC64
+#include <linux/of_device.h>
+#endif
+
+#include "niu.h"
+
+#define DRV_MODULE_NAME "niu"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "0.5"
+#define DRV_MODULE_RELDATE "October 5, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("NIU ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+#ifndef DMA_44BIT_MASK
+#define DMA_44BIT_MASK 0x00000fffffffffffULL
+#endif
+
+#ifndef readq
+static u64 readq(void __iomem *reg)
+{
+ return (((u64)readl(reg + 0x4UL) << 32) |
+ (u64)readl(reg));
+}
+
+static void writeq(u64 val, void __iomem *reg)
+{
+ writel(val & 0xffffffff, reg);
+ writel(val >> 32, reg + 0x4UL);
+}
+#endif
+
+static struct pci_device_id niu_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, niu_pci_tbl);
+
+#define NIU_TX_TIMEOUT (5 * HZ)
+
+#define nr64(reg) readq(np->regs + (reg))
+#define nw64(reg, val) writeq((val), np->regs + (reg))
+
+#define nr64_mac(reg) readq(np->mac_regs + (reg))
+#define nw64_mac(reg, val) writeq((val), np->mac_regs + (reg))
+
+#define nr64_ipp(reg) readq(np->regs + np->ipp_off + (reg))
+#define nw64_ipp(reg, val) writeq((val), np->regs + np->ipp_off + (reg))
+
+#define nr64_pcs(reg) readq(np->regs + np->pcs_off + (reg))
+#define nw64_pcs(reg, val) writeq((val), np->regs + np->pcs_off + (reg))
+
+#define nr64_xpcs(reg) readq(np->regs + np->xpcs_off + (reg))
+#define nw64_xpcs(reg, val) writeq((val), np->regs + np->xpcs_off + (reg))
+
+#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+static int niu_debug;
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "NIU debug level");
+
+#define niudbg(TYPE, f, a...) \
+do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+ printk(KERN_DEBUG PFX f, ## a); \
+} while (0)
+
+#define niuinfo(TYPE, f, a...) \
+do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+ printk(KERN_INFO PFX f, ## a); \
+} while (0)
+
+#define niuwarn(TYPE, f, a...) \
+do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+ printk(KERN_WARNING PFX f, ## a); \
+} while (0)
+
+#define niu_lock_parent(np, flags) \
+ spin_lock_irqsave(&np->parent->lock, flags)
+#define niu_unlock_parent(np, flags) \
+ spin_unlock_irqrestore(&np->parent->lock, flags)
+
+static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay)
+{
+ while (--limit >= 0) {
+ u64 val = nr64_mac(reg);
+
+ if (!(val & bits))
+ break;
+ udelay(delay);
+ }
+ if (limit < 0)
+ return -ENODEV;
+ return 0;
+}
+
+static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay,
+ const char *reg_name)
+{
+ int err;
+
+ nw64_mac(reg, bits);
+ err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay);
+ if (err)
+ dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+ "would not clear, val[%llx]\n",
+ np->dev->name, (unsigned long long) bits, reg_name,
+ (unsigned long long) nr64_mac(reg));
+ return err;
+}
+
+#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay)
+{
+ while (--limit >= 0) {
+ u64 val = nr64_ipp(reg);
+
+ if (!(val & bits))
+ break;
+ udelay(delay);
+ }
+ if (limit < 0)
+ return -ENODEV;
+ return 0;
+}
+
+static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay,
+ const char *reg_name)
+{
+ int err;
+ u64 val;
+
+ val = nr64_ipp(reg);
+ val |= bits;
+ nw64_ipp(reg, val);
+
+ err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay);
+ if (err)
+ dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+ "would not clear, val[%llx]\n",
+ np->dev->name, (unsigned long long) bits, reg_name,
+ (unsigned long long) nr64_ipp(reg));
+ return err;
+}
+
+#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static int __niu_wait_bits_clear(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay)
+{
+ while (--limit >= 0) {
+ u64 val = nr64(reg);
+
+ if (!(val & bits))
+ break;
+ udelay(delay);
+ }
+ if (limit < 0)
+ return -ENODEV;
+ return 0;
+}
+
+#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \
+})
+
+static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay,
+ const char *reg_name)
+{
+ int err;
+
+ nw64(reg, bits);
+ err = __niu_wait_bits_clear(np, reg, bits, limit, delay);
+ if (err)
+ dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+ "would not clear, val[%llx]\n",
+ np->dev->name, (unsigned long long) bits, reg_name,
+ (unsigned long long) nr64(reg));
+ return err;
+}
+
+#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on)
+{
+ u64 val = (u64) lp->timer;
+
+ if (on)
+ val |= LDG_IMGMT_ARM;
+
+ nw64(LDG_IMGMT(lp->ldg_num), val);
+}
+
+static int niu_ldn_irq_enable(struct niu *np, int ldn, int on)
+{
+ unsigned long mask_reg, bits;
+ u64 val;
+
+ if (ldn < 0 || ldn > LDN_MAX)
+ return -EINVAL;
+
+ if (ldn < 64) {
+ mask_reg = LD_IM0(ldn);
+ bits = LD_IM0_MASK;
+ } else {
+ mask_reg = LD_IM1(ldn - 64);
+ bits = LD_IM1_MASK;
+ }
+
+ val = nr64(mask_reg);
+ if (on)
+ val &= ~bits;
+ else
+ val |= bits;
+ nw64(mask_reg, val);
+
+ return 0;
+}
+
+static int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on)
+{
+ struct niu_parent *parent = np->parent;
+ int i;
+
+ for (i = 0; i <= LDN_MAX; i++) {
+ int err;
+
+ if (parent->ldg_map[i] != lp->ldg_num)
+ continue;
+
+ err = niu_ldn_irq_enable(np, i, on);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int niu_enable_interrupts(struct niu *np, int on)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+ int err;
+
+ err = niu_enable_ldn_in_ldg(np, lp, on);
+ if (err)
+ return err;
+ }
+ for (i = 0; i < np->num_ldg; i++)
+ niu_ldg_rearm(np, &np->ldg[i], on);
+
+ return 0;
+}
+
+static u32 phy_encode(u32 type, int port)
+{
+ return (type << (port * 2));
+}
+
+static u32 phy_decode(u32 val, int port)
+{
+ return (val >> (port * 2)) & PORT_TYPE_MASK;
+}
+
+static int mdio_wait(struct niu *np)
+{
+ int limit = 1000;
+ u64 val;
+
+ while (--limit > 0) {
+ val = nr64(MIF_FRAME_OUTPUT);
+ if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1)
+ return val & MIF_FRAME_OUTPUT_DATA;
+
+ udelay(10);
+ }
+
+ return -ENODEV;
+}
+
+static int mdio_read(struct niu *np, int port, int dev, int reg)
+{
+ int err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev));
+ return mdio_wait(np);
+}
+
+static int mdio_write(struct niu *np, int port, int dev, int reg, int data)
+{
+ int err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int mii_read(struct niu *np, int port, int reg)
+{
+ nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg));
+ return mdio_wait(np);
+}
+
+static int mii_write(struct niu *np, int port, int reg, int data)
+{
+ int err;
+
+ nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_TX_CFG_L(channel),
+ val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_TX_CFG_H(channel),
+ val >> 16);
+ return err;
+}
+
+static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_RX_CFG_L(channel),
+ val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_RX_CFG_H(channel),
+ val >> 16);
+ return err;
+}
+
+/* Mode is always 10G fiber. */
+static int serdes_init_niu(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u32 tx_cfg, rx_cfg;
+ unsigned long i;
+
+ tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);
+ rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
+ PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
+ PLL_RX_CFG_EQ_LP_ADAPTIVE);
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
+
+ mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_TEST_CFG_L, test_cfg);
+
+ tx_cfg |= PLL_TX_CFG_ENTEST;
+ rx_cfg |= PLL_RX_CFG_ENTEST;
+ }
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ int err = esr2_set_tx_cfg(np, i, tx_cfg);
+ if (err)
+ return err;
+ }
+
+ for (i = 0; i < 4; i++) {
+ int err = esr2_set_rx_cfg(np, i, rx_cfg);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val)
+{
+ int err;
+
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan));
+ if (err >= 0) {
+ *val = (err & 0xffff);
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_CTRL_H(chan));
+ if (err >= 0)
+ *val |= ((err & 0xffff) << 16);
+ err = 0;
+ }
+ return err;
+}
+
+static int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val)
+{
+ int err;
+
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_L(chan));
+ if (err >= 0) {
+ *val = (err & 0xffff);
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_H(chan));
+ if (err >= 0) {
+ *val |= ((err & 0xffff) << 16);
+ err = 0;
+ }
+ }
+ return err;
+}
+
+static int esr_read_reset(struct niu *np, u32 *val)
+{
+ int err;
+
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_L);
+ if (err >= 0) {
+ *val = (err & 0xffff);
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_H);
+ if (err >= 0) {
+ *val |= ((err & 0xffff) << 16);
+ err = 0;
+ }
+ }
+ return err;
+}
+
+static int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_CTRL_L(chan), val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_CTRL_H(chan), (val >> 16));
+ return err;
+}
+
+static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_L(chan), val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_H(chan), (val >> 16));
+ return err;
+}
+
+static int esr_reset(struct niu *np)
+{
+ u32 reset;
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_L, 0x0000);
+ if (err)
+ return err;
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_H, 0xffff);
+ if (err)
+ return err;
+ udelay(200);
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_L, 0xffff);
+ if (err)
+ return err;
+ udelay(200);
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_H, 0x0000);
+ if (err)
+ return err;
+ udelay(200);
+
+ err = esr_read_reset(np, &reset);
+ if (err)
+ return err;
+ if (reset != 0) {
+ dev_err(np->device, PFX "Port %u ESR_RESET "
+ "did not clear [%08x]\n",
+ np->port, reset);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int serdes_init_10g(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ unsigned long ctrl_reg, test_cfg_reg, i;
+ u64 ctrl_val, test_cfg_val, sig, mask, val;
+ int err;
+
+ switch (np->port) {
+ case 0:
+ ctrl_reg = ENET_SERDES_0_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_0_TEST_CFG;
+ break;
+ case 1:
+ ctrl_reg = ENET_SERDES_1_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_1_TEST_CFG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
+ ENET_SERDES_CTRL_SDET_1 |
+ ENET_SERDES_CTRL_SDET_2 |
+ ENET_SERDES_CTRL_SDET_3 |
+ (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
+ test_cfg_val = 0;
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_0_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_1_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_2_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_3_SHIFT));
+ }
+
+ nw64(ctrl_reg, ctrl_val);
+ nw64(test_cfg_reg, test_cfg_val);
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ u32 rxtx_ctrl, glue0;
+
+ err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_read_glue0(np, i, &glue0);
+ if (err)
+ return err;
+
+ rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
+ rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
+ (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
+
+ glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
+ ESR_GLUE_CTRL0_THCNT |
+ ESR_GLUE_CTRL0_BLTIME);
+ glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
+ (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
+ (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
+ (BLTIME_300_CYCLES <<
+ ESR_GLUE_CTRL0_BLTIME_SHIFT));
+
+ err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_write_glue0(np, i, glue0);
+ if (err)
+ return err;
+ }
+
+ err = esr_reset(np);
+ if (err)
+ return err;
+
+ sig = nr64(ESR_INT_SIGNALS);
+ switch (np->port) {
+ case 0:
+ mask = ESR_INT_SIGNALS_P0_BITS;
+ val = (ESR_INT_SRDY0_P0 |
+ ESR_INT_DET0_P0 |
+ ESR_INT_XSRDY_P0 |
+ ESR_INT_XDP_P0_CH3 |
+ ESR_INT_XDP_P0_CH2 |
+ ESR_INT_XDP_P0_CH1 |
+ ESR_INT_XDP_P0_CH0);
+ break;
+
+ case 1:
+ mask = ESR_INT_SIGNALS_P1_BITS;
+ val = (ESR_INT_SRDY0_P1 |
+ ESR_INT_DET0_P1 |
+ ESR_INT_XSRDY_P1 |
+ ESR_INT_XDP_P1_CH3 |
+ ESR_INT_XDP_P1_CH2 |
+ ESR_INT_XDP_P1_CH1 |
+ ESR_INT_XDP_P1_CH0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((sig & mask) != val) {
+ dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
+ "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int serdes_init_1g(struct niu *np)
+{
+ u64 val;
+
+ val = nr64(ENET_SERDES_1_PLL_CFG);
+ val &= ~ENET_SERDES_PLL_FBDIV2;
+ switch (np->port) {
+ case 0:
+ val |= ENET_SERDES_PLL_HRATE0;
+ break;
+ case 1:
+ val |= ENET_SERDES_PLL_HRATE1;
+ break;
+ case 2:
+ val |= ENET_SERDES_PLL_HRATE2;
+ break;
+ case 3:
+ val |= ENET_SERDES_PLL_HRATE3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ nw64(ENET_SERDES_1_PLL_CFG, val);
+
+ return 0;
+}
+
+static int bcm8704_reset(struct niu *np)
+{
+ int err, limit;
+
+ err = mdio_read(np, np->phy_addr,
+ BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+ if (err < 0)
+ return err;
+ err |= BMCR_RESET;
+ err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ MII_BMCR, err);
+ if (err)
+ return err;
+
+ limit = 1000;
+ while (--limit >= 0) {
+ err = mdio_read(np, np->phy_addr,
+ BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+ if (err < 0)
+ return err;
+ if (!(err & BMCR_RESET))
+ break;
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u PHY will not reset "
+ "(bmcr=%04x)\n", np->port, (err & 0xffff));
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/* When written, certain PHY registers need to be read back twice
+ * in order for the bits to settle properly.
+ */
+static int bcm8704_user_dev3_readback(struct niu *np, int reg)
+{
+ int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
+ if (err < 0)
+ return err;
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int bcm8704_init_user_dev3(struct niu *np)
+{
+ int err;
+
+ err = mdio_write(np, np->phy_addr,
+ BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL,
+ (USER_CONTROL_OPTXRST_LVL |
+ USER_CONTROL_OPBIASFLT_LVL |
+ USER_CONTROL_OBTMPFLT_LVL |
+ USER_CONTROL_OPPRFLT_LVL |
+ USER_CONTROL_OPTXFLT_LVL |
+ USER_CONTROL_OPRXLOS_LVL |
+ USER_CONTROL_OPRXFLT_LVL |
+ USER_CONTROL_OPTXON_LVL |
+ (0x3f << USER_CONTROL_RES1_SHIFT)));
+ if (err)
+ return err;
+
+ err = mdio_write(np, np->phy_addr,
+ BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL,
+ (USER_PMD_TX_CTL_XFP_CLKEN |
+ (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) |
+ (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) |
+ USER_PMD_TX_CTL_TSCK_LPWREN));
+ if (err)
+ return err;
+
+ err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL);
+ if (err)
+ return err;
+ err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL);
+ if (err)
+ return err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_OPT_DIGITAL_CTRL);
+ if (err < 0)
+ return err;
+ err &= ~USER_ODIG_CTRL_GPIOS;
+ err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT);
+ err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_OPT_DIGITAL_CTRL, err);
+ if (err)
+ return err;
+
+ mdelay(1000);
+
+ return 0;
+}
+
+static int xcvr_init_10g(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u16 analog_stat0, tx_alarm_status;
+ int err;
+ u64 val;
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_LED_POLARITY;
+ val |= XMAC_CONFIG_FORCE_LED_ON;
+ nw64_mac(XMAC_CONFIG, val);
+
+ /* XXX shared resource, lock parent XXX */
+ val = nr64(MIF_CONFIG);
+ val |= MIF_CONFIG_INDIRECT_MODE;
+ nw64(MIF_CONFIG, val);
+
+ err = bcm8704_reset(np);
+ if (err)
+ return err;
+
+ err = bcm8704_init_user_dev3(np);
+ if (err)
+ return err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ MII_BMCR);
+ if (err < 0)
+ return err;
+ err &= ~BMCR_LOOPBACK;
+
+ if (lp->loopback_mode == LOOPBACK_MAC)
+ err |= BMCR_LOOPBACK;
+
+ err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ MII_BMCR, err);
+ if (err)
+ return err;
+
+#if 1
+ err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+ MII_STAT1000);
+ if (err < 0)
+ return err;
+ pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n",
+ np->port, err);
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20);
+ if (err < 0)
+ return err;
+ pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n",
+ np->port, err);
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ MII_NWAYTEST);
+ if (err < 0)
+ return err;
+ pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n",
+ np->port, err);
+#endif
+
+ /* XXX dig this out it might not be so useful XXX */
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_ANALOG_STATUS0);
+ if (err < 0)
+ return err;
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_ANALOG_STATUS0);
+ if (err < 0)
+ return err;
+ analog_stat0 = err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_TX_ALARM_STATUS);
+ if (err < 0)
+ return err;
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_TX_ALARM_STATUS);
+ if (err < 0)
+ return err;
+ tx_alarm_status = err;
+
+ if (analog_stat0 != 0x03fc) {
+ if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) {
+ pr_info(PFX "Port %u cable not connected "
+ "or bad cable.\n", np->port);
+ } else if (analog_stat0 == 0x639c) {
+ pr_info(PFX "Port %u optical module is bad "
+ "or missing.\n", np->port);
+ }
+ }
+
+ return 0;
+}
+
+static int mii_reset(struct niu *np)
+{
+ int limit, err;
+
+ err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET);
+ if (err)
+ return err;
+
+ limit = 1000;
+ while (--limit >= 0) {
+ udelay(500);
+ err = mii_read(np, np->phy_addr, MII_BMCR);
+ if (err < 0)
+ return err;
+ if (!(err & BMCR_RESET))
+ break;
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u MII would not reset, "
+ "bmcr[%04x]\n", np->port, err);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int mii_init_common(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u16 bmcr, bmsr, adv, estat;
+ int err;
+
+ err = mii_reset(np);
+ if (err)
+ return err;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ return err;
+ bmsr = err;
+
+ estat = 0;
+ if (bmsr & BMSR_ESTATEN) {
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ return err;
+ estat = err;
+ }
+
+ bmcr = 0;
+ err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+ if (err)
+ return err;
+
+ if (lp->loopback_mode == LOOPBACK_MAC) {
+ bmcr |= BMCR_LOOPBACK;
+ if (lp->active_speed == SPEED_1000)
+ bmcr |= BMCR_SPEED1000;
+ if (lp->active_duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+ }
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ u16 aux;
+
+ aux = (BCM5464R_AUX_CTL_EXT_LB |
+ BCM5464R_AUX_CTL_WRITE_1);
+ err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux);
+ if (err)
+ return err;
+ }
+
+ /* XXX configurable XXX */
+ /* XXX for now don't advertise half-duplex or asym pause... XXX */
+ adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
+ if (bmsr & BMSR_10FULL)
+ adv |= ADVERTISE_10FULL;
+ if (bmsr & BMSR_100FULL)
+ adv |= ADVERTISE_100FULL;
+ err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv);
+ if (err)
+ return err;
+
+ if (bmsr & BMSR_ESTATEN) {
+ u16 ctrl1000 = 0;
+
+ if (estat & ESTATUS_1000_TFULL)
+ ctrl1000 |= ADVERTISE_1000FULL;
+ err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000);
+ if (err)
+ return err;
+ }
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+ err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+ if (err)
+ return err;
+
+ err = mii_read(np, np->phy_addr, MII_BMCR);
+ if (err < 0)
+ return err;
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ return err;
+#if 0
+ pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
+ np->port, bmcr, bmsr);
+#endif
+
+ return 0;
+}
+
+static int xcvr_init_1g(struct niu *np)
+{
+ u64 val;
+
+ /* XXX shared resource, lock parent XXX */
+ val = nr64(MIF_CONFIG);
+ val &= ~MIF_CONFIG_INDIRECT_MODE;
+ nw64(MIF_CONFIG, val);
+
+ return mii_init_common(np);
+}
+
+static int niu_xcvr_init(struct niu *np)
+{
+ const struct niu_phy_ops *ops = np->phy_ops;
+ int err;
+
+ err = 0;
+ if (ops->xcvr_init)
+ err = ops->xcvr_init(np);
+
+ return err;
+}
+
+static int niu_serdes_init(struct niu *np)
+{
+ const struct niu_phy_ops *ops = np->phy_ops;
+ int err;
+
+ err = 0;
+ if (ops->serdes_init)
+ err = ops->serdes_init(np);
+
+ return err;
+}
+
+static void niu_init_xif(struct niu *);
+
+static int niu_link_status_common(struct niu *np, int link_up)
+{
+ struct niu_link_config *lp = &np->link_config;
+ struct net_device *dev = np->dev;
+ unsigned long flags;
+
+ if (!netif_carrier_ok(dev) && link_up) {
+ niuinfo(LINK, "%s: Link is up at %s, %s duplex\n",
+ dev->name,
+ (lp->active_speed == SPEED_10000 ?
+ "10Gb/sec" :
+ (lp->active_speed == SPEED_1000 ?
+ "1Gb/sec" :
+ (lp->active_speed == SPEED_100 ?
+ "100Mbit/sec" : "10Mbit/sec"))),
+ (lp->active_duplex == DUPLEX_FULL ?
+ "full" : "half"));
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_init_xif(np);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ netif_carrier_on(dev);
+ } else if (netif_carrier_ok(dev) && !link_up) {
+ niuwarn(LINK, "%s: Link is down\n", dev->name);
+ netif_carrier_off(dev);
+ }
+
+ return 0;
+}
+
+static int link_status_10g(struct niu *np, int *link_up_p)
+{
+ unsigned long flags;
+ int err, link_up;
+
+ link_up = 0;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = -EINVAL;
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ goto out;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+ BCM8704_PMD_RCV_SIGDET);
+ if (err < 0)
+ goto out;
+ if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
+ err = 0;
+ goto out;
+ }
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ BCM8704_PCS_10G_R_STATUS);
+ if (err < 0)
+ goto out;
+ if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {
+ err = 0;
+ goto out;
+ }
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ BCM8704_PHYXS_XGXS_LANE_STAT);
+ if (err < 0)
+ goto out;
+
+ if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |
+ PHYXS_XGXS_LANE_STAT_MAGIC |
+ PHYXS_XGXS_LANE_STAT_LANE3 |
+ PHYXS_XGXS_LANE_STAT_LANE2 |
+ PHYXS_XGXS_LANE_STAT_LANE1 |
+ PHYXS_XGXS_LANE_STAT_LANE0)) {
+ err = 0;
+ goto out;
+ }
+
+ link_up = 1;
+ np->link_config.active_speed = SPEED_10000;
+ np->link_config.active_duplex = DUPLEX_FULL;
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return err;
+}
+
+static int link_status_1g(struct niu *np, int *link_up_p)
+{
+ u16 current_speed, bmsr;
+ unsigned long flags;
+ u8 current_duplex;
+ int err, link_up;
+
+ link_up = 0;
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = -EINVAL;
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ goto out;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ goto out;
+
+ bmsr = err;
+ if (bmsr & BMSR_LSTATUS) {
+ u16 adv, lpa, common, estat;
+
+ err = mii_read(np, np->phy_addr, MII_ADVERTISE);
+ if (err < 0)
+ goto out;
+ adv = err;
+
+ err = mii_read(np, np->phy_addr, MII_LPA);
+ if (err < 0)
+ goto out;
+ lpa = err;
+
+ common = adv & lpa;
+
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ goto out;
+ estat = err;
+
+ link_up = 1;
+ if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
+ current_speed = SPEED_1000;
+ if (estat & ESTATUS_1000_TFULL)
+ current_duplex = DUPLEX_FULL;
+ else
+ current_duplex = DUPLEX_HALF;
+ } else {
+ if (common & ADVERTISE_100BASE4) {
+ current_speed = SPEED_100;
+ current_duplex = DUPLEX_HALF;
+ } else if (common & ADVERTISE_100FULL) {
+ current_speed = SPEED_100;
+ current_duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISE_100HALF) {
+ current_speed = SPEED_100;
+ current_duplex = DUPLEX_HALF;
+ } else if (common & ADVERTISE_10FULL) {
+ current_speed = SPEED_10;
+ current_duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISE_10HALF) {
+ current_speed = SPEED_10;
+ current_duplex = DUPLEX_HALF;
+ } else
+ link_up = 0;
+ }
+ }
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return err;
+}
+
+static int niu_link_status(struct niu *np, int *link_up_p)
+{
+ const struct niu_phy_ops *ops = np->phy_ops;
+ int err;
+
+ err = 0;
+ if (ops->link_status)
+ err = ops->link_status(np, link_up_p);
+
+ return err;
+}
+
+static void niu_timer(unsigned long __opaque)
+{
+ struct niu *np = (struct niu *) __opaque;
+ unsigned long off;
+ int err, link_up;
+
+ err = niu_link_status(np, &link_up);
+ if (!err)
+ niu_link_status_common(np, link_up);
+
+ if (netif_carrier_ok(np->dev))
+ off = 5 * HZ;
+ else
+ off = 1 * HZ;
+ np->timer.expires = jiffies + off;
+
+ add_timer(&np->timer);
+}
+
+static const struct niu_phy_ops phy_ops_10g_fiber_niu = {
+ .serdes_init = serdes_init_niu,
+ .xcvr_init = xcvr_init_10g,
+ .link_status = link_status_10g,
+};
+
+static const struct niu_phy_ops phy_ops_10g_fiber = {
+ .serdes_init = serdes_init_10g,
+ .xcvr_init = xcvr_init_10g,
+ .link_status = link_status_10g,
+};
+
+static const struct niu_phy_ops phy_ops_10g_copper = {
+ .serdes_init = serdes_init_10g,
+ .link_status = link_status_10g, /* XXX */
+};
+
+static const struct niu_phy_ops phy_ops_1g_fiber = {
+ .serdes_init = serdes_init_1g,
+ .xcvr_init = xcvr_init_1g,
+ .link_status = link_status_1g,
+};
+
+static const struct niu_phy_ops phy_ops_1g_copper = {
+ .xcvr_init = xcvr_init_1g,
+ .link_status = link_status_1g,
+};
+
+struct niu_phy_template {
+ const struct niu_phy_ops *ops;
+ u32 phy_addr_base;
+};
+
+static const struct niu_phy_template phy_template_niu = {
+ .ops = &phy_ops_10g_fiber_niu,
+ .phy_addr_base = 16,
+};
+
+static const struct niu_phy_template phy_template_10g_fiber = {
+ .ops = &phy_ops_10g_fiber,
+ .phy_addr_base = 8,
+};
+
+static const struct niu_phy_template phy_template_10g_copper = {
+ .ops = &phy_ops_10g_copper,
+ .phy_addr_base = 10,
+};
+
+static const struct niu_phy_template phy_template_1g_fiber = {
+ .ops = &phy_ops_1g_fiber,
+ .phy_addr_base = 0,
+};
+
+static const struct niu_phy_template phy_template_1g_copper = {
+ .ops = &phy_ops_1g_copper,
+ .phy_addr_base = 0,
+};
+
+static int niu_determine_phy_disposition(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ u8 plat_type = parent->plat_type;
+ const struct niu_phy_template *tp;
+ u32 phy_addr_off = 0;
+
+ if (plat_type == PLAT_TYPE_NIU) {
+ tp = &phy_template_niu;
+ phy_addr_off += np->port;
+ } else {
+ switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+ case 0:
+ /* 1G copper */
+ tp = &phy_template_1g_copper;
+ if (plat_type == PLAT_TYPE_VF_P0)
+ phy_addr_off = 10;
+ else if (plat_type == PLAT_TYPE_VF_P1)
+ phy_addr_off = 26;
+
+ phy_addr_off += (np->port ^ 0x3);
+ break;
+
+ case NIU_FLAGS_10G:
+ /* 10G copper */
+ tp = &phy_template_1g_copper;
+ break;
+
+ case NIU_FLAGS_FIBER:
+ /* 1G fiber */
+ tp = &phy_template_1g_fiber;
+ break;
+
+ case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+ /* 10G fiber */
+ tp = &phy_template_10g_fiber;
+ if (plat_type == PLAT_TYPE_VF_P0 ||
+ plat_type == PLAT_TYPE_VF_P1)
+ phy_addr_off = 8;
+ phy_addr_off += np->port;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ np->phy_ops = tp->ops;
+ np->phy_addr = tp->phy_addr_base + phy_addr_off;
+
+ return 0;
+}
+
+static int niu_init_link(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ int err, ignore;
+
+ if (parent->plat_type == PLAT_TYPE_NIU) {
+ err = niu_xcvr_init(np);
+ if (err)
+ return err;
+ msleep(200);
+ }
+ err = niu_serdes_init(np);
+ if (err)
+ return err;
+ msleep(200);
+ err = niu_xcvr_init(np);
+ if (!err)
+ niu_link_status(np, &ignore);
+ return 0;
+}
+
+static void niu_set_primary_mac(struct niu *np, unsigned char *addr)
+{
+ u16 reg0 = addr[4] << 8 | addr[5];
+ u16 reg1 = addr[2] << 8 | addr[3];
+ u16 reg2 = addr[0] << 8 | addr[1];
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ nw64_mac(XMAC_ADDR0, reg0);
+ nw64_mac(XMAC_ADDR1, reg1);
+ nw64_mac(XMAC_ADDR2, reg2);
+ } else {
+ nw64_mac(BMAC_ADDR0, reg0);
+ nw64_mac(BMAC_ADDR1, reg1);
+ nw64_mac(BMAC_ADDR2, reg2);
+ }
+}
+
+static int niu_num_alt_addr(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return XMAC_NUM_ALT_ADDR;
+ else
+ return BMAC_NUM_ALT_ADDR;
+}
+
+static int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr)
+{
+ u16 reg0 = addr[4] << 8 | addr[5];
+ u16 reg1 = addr[2] << 8 | addr[3];
+ u16 reg2 = addr[0] << 8 | addr[1];
+
+ if (index >= niu_num_alt_addr(np))
+ return -EINVAL;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ nw64_mac(XMAC_ALT_ADDR0(index), reg0);
+ nw64_mac(XMAC_ALT_ADDR1(index), reg1);
+ nw64_mac(XMAC_ALT_ADDR2(index), reg2);
+ } else {
+ nw64_mac(BMAC_ALT_ADDR0(index), reg0);
+ nw64_mac(BMAC_ALT_ADDR1(index), reg1);
+ nw64_mac(BMAC_ALT_ADDR2(index), reg2);
+ }
+
+ return 0;
+}
+
+static int niu_enable_alt_mac(struct niu *np, int index, int on)
+{
+ unsigned long reg;
+ u64 val, mask;
+
+ if (index >= niu_num_alt_addr(np))
+ return -EINVAL;
+
+ if (np->flags & NIU_FLAGS_XMAC)
+ reg = XMAC_ADDR_CMPEN;
+ else
+ reg = BMAC_ADDR_CMPEN;
+
+ mask = 1 << index;
+
+ val = nr64_mac(reg);
+ if (on)
+ val |= mask;
+ else
+ val &= ~mask;
+ nw64_mac(reg, val);
+
+ return 0;
+}
+
+static void __set_rdc_table_num_hw(struct niu *np, unsigned long reg,
+ int num, int mac_pref)
+{
+ u64 val = nr64_mac(reg);
+ val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR);
+ val |= num;
+ if (mac_pref)
+ val |= HOST_INFO_MPR;
+ nw64_mac(reg, val);
+}
+
+static int __set_rdc_table_num(struct niu *np,
+ int xmac_index, int bmac_index,
+ int rdc_table_num, int mac_pref)
+{
+ unsigned long reg;
+
+ if (rdc_table_num & ~HOST_INFO_MACRDCTBLN)
+ return -EINVAL;
+ if (np->flags & NIU_FLAGS_XMAC)
+ reg = XMAC_HOST_INFO(xmac_index);
+ else
+ reg = BMAC_HOST_INFO(bmac_index);
+ __set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref);
+ return 0;
+}
+
+static int niu_set_primary_mac_rdc_table(struct niu *np, int table_num,
+ int mac_pref)
+{
+ return __set_rdc_table_num(np, 17, 0, table_num, mac_pref);
+}
+
+static int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num,
+ int mac_pref)
+{
+ return __set_rdc_table_num(np, 16, 8, table_num, mac_pref);
+}
+
+static int niu_set_alt_mac_rdc_table(struct niu *np, int idx,
+ int table_num, int mac_pref)
+{
+ if (idx >= niu_num_alt_addr(np))
+ return -EINVAL;
+ return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref);
+}
+
+static u64 vlan_entry_set_parity(u64 reg_val)
+{
+ u64 port01_mask;
+ u64 port23_mask;
+
+ port01_mask = 0x00ff;
+ port23_mask = 0xff00;
+
+ if (hweight64(reg_val & port01_mask) & 1)
+ reg_val |= ENET_VLAN_TBL_PARITY0;
+ else
+ reg_val &= ~ENET_VLAN_TBL_PARITY0;
+
+ if (hweight64(reg_val & port23_mask) & 1)
+ reg_val |= ENET_VLAN_TBL_PARITY1;
+ else
+ reg_val &= ~ENET_VLAN_TBL_PARITY1;
+
+ return reg_val;
+}
+
+static void vlan_tbl_write(struct niu *np, unsigned long index,
+ int port, int vpr, int rdc_table)
+{
+ u64 reg_val = nr64(ENET_VLAN_TBL(index));
+
+ reg_val &= ~((ENET_VLAN_TBL_VPR |
+ ENET_VLAN_TBL_VLANRDCTBLN) <<
+ ENET_VLAN_TBL_SHIFT(port));
+ if (vpr)
+ reg_val |= (ENET_VLAN_TBL_VPR <<
+ ENET_VLAN_TBL_SHIFT(port));
+ reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port));
+
+ reg_val = vlan_entry_set_parity(reg_val);
+
+ nw64(ENET_VLAN_TBL(index), reg_val);
+}
+
+static void vlan_tbl_clear(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++)
+ nw64(ENET_VLAN_TBL(i), 0);
+}
+
+static int tcam_wait_bit(struct niu *np, u64 bit)
+{
+ int limit = 1000;
+
+ while (--limit > 0) {
+ if (nr64(TCAM_CTL) & bit)
+ break;
+ udelay(1);
+ }
+ if (limit < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int tcam_flush(struct niu *np, int index)
+{
+ nw64(TCAM_KEY_0, 0x00);
+ nw64(TCAM_KEY_MASK_0, 0xff);
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
+
+ return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+#if 0
+static int tcam_read(struct niu *np, int index,
+ u64 *key, u64 *mask)
+{
+ int err;
+
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_READ | index));
+ err = tcam_wait_bit(np, TCAM_CTL_STAT);
+ if (!err) {
+ key[0] = nr64(TCAM_KEY_0);
+ key[1] = nr64(TCAM_KEY_1);
+ key[2] = nr64(TCAM_KEY_2);
+ key[3] = nr64(TCAM_KEY_3);
+ mask[0] = nr64(TCAM_KEY_MASK_0);
+ mask[1] = nr64(TCAM_KEY_MASK_1);
+ mask[2] = nr64(TCAM_KEY_MASK_2);
+ mask[3] = nr64(TCAM_KEY_MASK_3);
+ }
+ return err;
+}
+#endif
+
+static int tcam_write(struct niu *np, int index,
+ u64 *key, u64 *mask)
+{
+ nw64(TCAM_KEY_0, key[0]);
+ nw64(TCAM_KEY_1, key[1]);
+ nw64(TCAM_KEY_2, key[2]);
+ nw64(TCAM_KEY_3, key[3]);
+ nw64(TCAM_KEY_MASK_0, mask[0]);
+ nw64(TCAM_KEY_MASK_1, mask[1]);
+ nw64(TCAM_KEY_MASK_2, mask[2]);
+ nw64(TCAM_KEY_MASK_3, mask[3]);
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
+
+ return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+#if 0
+static int tcam_assoc_read(struct niu *np, int index, u64 *data)
+{
+ int err;
+
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_READ | index));
+ err = tcam_wait_bit(np, TCAM_CTL_STAT);
+ if (!err)
+ *data = nr64(TCAM_KEY_1);
+
+ return err;
+}
+#endif
+
+static int tcam_assoc_write(struct niu *np, int index, u64 assoc_data)
+{
+ nw64(TCAM_KEY_1, assoc_data);
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_WRITE | index));
+
+ return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+static void tcam_enable(struct niu *np, int on)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ if (on)
+ val &= ~FFLP_CFG_1_TCAM_DIS;
+ else
+ val |= FFLP_CFG_1_TCAM_DIS;
+ nw64(FFLP_CFG_1, val);
+}
+
+static void tcam_set_lat_and_ratio(struct niu *np, u64 latency, u64 ratio)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ val &= ~(FFLP_CFG_1_FFLPINITDONE |
+ FFLP_CFG_1_CAMLAT |
+ FFLP_CFG_1_CAMRATIO);
+ val |= (latency << FFLP_CFG_1_CAMLAT_SHIFT);
+ val |= (ratio << FFLP_CFG_1_CAMRATIO_SHIFT);
+ nw64(FFLP_CFG_1, val);
+
+ val = nr64(FFLP_CFG_1);
+ val |= FFLP_CFG_1_FFLPINITDONE;
+ nw64(FFLP_CFG_1, val);
+}
+
+static int tcam_user_eth_class_enable(struct niu *np, unsigned long class,
+ int on)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_ETHERTYPE1 ||
+ class > CLASS_CODE_ETHERTYPE2)
+ return -EINVAL;
+
+ reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
+ val = nr64(reg);
+ if (on)
+ val |= L2_CLS_VLD;
+ else
+ val &= ~L2_CLS_VLD;
+ nw64(reg, val);
+
+ return 0;
+}
+
+#if 0
+static int tcam_user_eth_class_set(struct niu *np, unsigned long class,
+ u64 ether_type)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_ETHERTYPE1 ||
+ class > CLASS_CODE_ETHERTYPE2 ||
+ (ether_type & ~(u64)0xffff) != 0)
+ return -EINVAL;
+
+ reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
+ val = nr64(reg);
+ val &= ~L2_CLS_ETYPE;
+ val |= (ether_type << L2_CLS_ETYPE_SHIFT);
+ nw64(reg, val);
+
+ return 0;
+}
+#endif
+
+static int tcam_user_ip_class_enable(struct niu *np, unsigned long class,
+ int on)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_USER_PROG1 ||
+ class > CLASS_CODE_USER_PROG4)
+ return -EINVAL;
+
+ reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
+ val = nr64(reg);
+ if (on)
+ val |= L3_CLS_VALID;
+ else
+ val &= ~L3_CLS_VALID;
+ nw64(reg, val);
+
+ return 0;
+}
+
+#if 0
+static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
+ int ipv6, u64 protocol_id,
+ u64 tos_mask, u64 tos_val)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_USER_PROG1 ||
+ class > CLASS_CODE_USER_PROG4 ||
+ (protocol_id & ~(u64)0xff) != 0 ||
+ (tos_mask & ~(u64)0xff) != 0 ||
+ (tos_val & ~(u64)0xff) != 0)
+ return -EINVAL;
+
+ reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
+ val = nr64(reg);
+ val &= ~(L3_CLS_IPVER | L3_CLS_PID |
+ L3_CLS_TOSMASK | L3_CLS_TOS);
+ if (ipv6)
+ val |= L3_CLS_IPVER;
+ val |= (protocol_id << L3_CLS_PID_SHIFT);
+ val |= (tos_mask << L3_CLS_TOSMASK_SHIFT);
+ val |= (tos_val << L3_CLS_TOS_SHIFT);
+ nw64(reg, val);
+
+ return 0;
+}
+#endif
+
+static int tcam_early_init(struct niu *np)
+{
+ unsigned long i;
+ int err;
+
+ tcam_enable(np, 0);
+ tcam_set_lat_and_ratio(np,
+ DEFAULT_TCAM_LATENCY,
+ DEFAULT_TCAM_ACCESS_RATIO);
+ for (i = CLASS_CODE_ETHERTYPE1; i <= CLASS_CODE_ETHERTYPE2; i++) {
+ err = tcam_user_eth_class_enable(np, i, 0);
+ if (err)
+ return err;
+ }
+ for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_USER_PROG4; i++) {
+ err = tcam_user_ip_class_enable(np, i, 0);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int tcam_flush_all(struct niu *np)
+{
+ unsigned long i;
+
+ for (i = 0; i < np->parent->tcam_num_entries; i++) {
+ int err = tcam_flush(np, i);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static u64 hash_addr_regval(unsigned long index, unsigned long num_entries)
+{
+ return ((u64)index | (num_entries == 1 ?
+ HASH_TBL_ADDR_AUTOINC : 0));
+}
+
+#if 0
+static int hash_read(struct niu *np, unsigned long partition,
+ unsigned long index, unsigned long num_entries,
+ u64 *data)
+{
+ u64 val = hash_addr_regval(index, num_entries);
+ unsigned long i;
+
+ if (partition >= FCRAM_NUM_PARTITIONS ||
+ index + num_entries > FCRAM_SIZE)
+ return -EINVAL;
+
+ nw64(HASH_TBL_ADDR(partition), val);
+ for (i = 0; i < num_entries; i++)
+ data[i] = nr64(HASH_TBL_DATA(partition));
+
+ return 0;
+}
+#endif
+
+static int hash_write(struct niu *np, unsigned long partition,
+ unsigned long index, unsigned long num_entries,
+ u64 *data)
+{
+ u64 val = hash_addr_regval(index, num_entries);
+ unsigned long i;
+
+ if (partition >= FCRAM_NUM_PARTITIONS ||
+ index + (num_entries * 8) > FCRAM_SIZE)
+ return -EINVAL;
+
+ nw64(HASH_TBL_ADDR(partition), val);
+ for (i = 0; i < num_entries; i++)
+ nw64(HASH_TBL_DATA(partition), data[i]);
+
+ return 0;
+}
+
+static void fflp_reset(struct niu *np)
+{
+ u64 val;
+
+ nw64(FFLP_CFG_1, FFLP_CFG_1_PIO_FIO_RST);
+ udelay(10);
+ nw64(FFLP_CFG_1, 0);
+
+ val = FFLP_CFG_1_FCRAMOUTDR_NORMAL | FFLP_CFG_1_FFLPINITDONE;
+ nw64(FFLP_CFG_1, val);
+}
+
+static void fflp_set_timings(struct niu *np)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ val &= ~FFLP_CFG_1_FFLPINITDONE;
+ val |= (DEFAULT_FCRAMRATIO << FFLP_CFG_1_FCRAMRATIO_SHIFT);
+ nw64(FFLP_CFG_1, val);
+
+ val = nr64(FFLP_CFG_1);
+ val |= FFLP_CFG_1_FFLPINITDONE;
+ nw64(FFLP_CFG_1, val);
+
+ val = nr64(FCRAM_REF_TMR);
+ val &= ~(FCRAM_REF_TMR_MAX | FCRAM_REF_TMR_MIN);
+ val |= (DEFAULT_FCRAM_REFRESH_MAX << FCRAM_REF_TMR_MAX_SHIFT);
+ val |= (DEFAULT_FCRAM_REFRESH_MIN << FCRAM_REF_TMR_MIN_SHIFT);
+ nw64(FCRAM_REF_TMR, val);
+}
+
+static int fflp_set_partition(struct niu *np, u64 partition,
+ u64 mask, u64 base, int enable)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (partition >= FCRAM_NUM_PARTITIONS ||
+ (mask & ~(u64)0x1f) != 0 ||
+ (base & ~(u64)0x1f) != 0)
+ return -EINVAL;
+
+ reg = FLW_PRT_SEL(partition);
+
+ val = nr64(reg);
+ val &= ~(FLW_PRT_SEL_EXT | FLW_PRT_SEL_MASK | FLW_PRT_SEL_BASE);
+ val |= (mask << FLW_PRT_SEL_MASK_SHIFT);
+ val |= (base << FLW_PRT_SEL_BASE_SHIFT);
+ if (enable)
+ val |= FLW_PRT_SEL_EXT;
+ nw64(reg, val);
+
+ return 0;
+}
+
+static int fflp_disable_all_partitions(struct niu *np)
+{
+ unsigned long i;
+
+ for (i = 0; i < FCRAM_NUM_PARTITIONS; i++) {
+ int err = fflp_set_partition(np, 0, 0, 0, 0);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static void fflp_llcsnap_enable(struct niu *np, int on)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ if (on)
+ val |= FFLP_CFG_1_LLCSNAP;
+ else
+ val &= ~FFLP_CFG_1_LLCSNAP;
+ nw64(FFLP_CFG_1, val);
+}
+
+static void fflp_errors_enable(struct niu *np, int on)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ if (on)
+ val &= ~FFLP_CFG_1_ERRORDIS;
+ else
+ val |= FFLP_CFG_1_ERRORDIS;
+ nw64(FFLP_CFG_1, val);
+}
+
+static int fflp_hash_clear(struct niu *np)
+{
+ struct fcram_hash_ipv4 ent;
+ unsigned long i;
+
+ /* IPV4 hash entry with valid bit clear, rest is don't care. */
+ memset(&ent, 0, sizeof(ent));
+ ent.header = HASH_HEADER_EXT;
+
+ for (i = 0; i < FCRAM_SIZE; i += sizeof(ent)) {
+ int err = hash_write(np, 0, i, 1, (u64 *) &ent);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int fflp_early_init(struct niu *np)
+{
+ struct niu_parent *parent;
+ unsigned long flags;
+ int err;
+
+ niu_lock_parent(np, flags);
+
+ parent = np->parent;
+ err = 0;
+ if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) {
+ niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n",
+ np->port);
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ fflp_reset(np);
+ fflp_set_timings(np);
+ err = fflp_disable_all_partitions(np);
+ if (err) {
+ niudbg(PROBE, "fflp_disable_all_partitions "
+ "failed, err=%d\n", err);
+ goto out;
+ }
+ }
+
+ err = tcam_early_init(np);
+ if (err) {
+ niudbg(PROBE, "tcam_early_init failed, err=%d\n",
+ err);
+ goto out;
+ }
+ fflp_llcsnap_enable(np, 1);
+ fflp_errors_enable(np, 0);
+ nw64(H1POLY, 0);
+ nw64(H2POLY, 0);
+
+ err = tcam_flush_all(np);
+ if (err) {
+ niudbg(PROBE, "tcam_flush_all failed, err=%d\n",
+ err);
+ goto out;
+ }
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ err = fflp_hash_clear(np);
+ if (err) {
+ niudbg(PROBE, "fflp_hash_clear failed, "
+ "err=%d\n", err);
+ goto out;
+ }
+ }
+
+ vlan_tbl_clear(np);
+
+ niudbg(PROBE, "fflp_early_init: Success\n");
+ parent->flags |= PARENT_FLGS_CLS_HWINIT;
+ }
+out:
+ niu_unlock_parent(np, flags);
+ return err;
+}
+
+static int niu_set_flow_key(struct niu *np, unsigned long class_code, u64 key)
+{
+ if (class_code < CLASS_CODE_USER_PROG1 ||
+ class_code > CLASS_CODE_SCTP_IPV6)
+ return -EINVAL;
+
+ nw64(FLOW_KEY(class_code - CLASS_CODE_USER_PROG1), key);
+ return 0;
+}
+
+static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key)
+{
+ if (class_code < CLASS_CODE_USER_PROG1 ||
+ class_code > CLASS_CODE_SCTP_IPV6)
+ return -EINVAL;
+
+ nw64(TCAM_KEY(class_code - CLASS_CODE_USER_PROG1), key);
+ return 0;
+}
+
+static void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
+ u32 offset, u32 size)
+{
+ int i = skb_shinfo(skb)->nr_frags;
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ frag->page = page;
+ frag->page_offset = offset;
+ frag->size = size;
+
+ skb->len += size;
+ skb->data_len += size;
+ skb->truesize += size;
+
+ skb_shinfo(skb)->nr_frags = i + 1;
+}
+
+static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a)
+{
+ a >>= PAGE_SHIFT;
+ a ^= (a >> ilog2(MAX_RBR_RING_SIZE));
+
+ return (a & (MAX_RBR_RING_SIZE - 1));
+}
+
+static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr,
+ struct page ***link)
+{
+ unsigned int h = niu_hash_rxaddr(rp, addr);
+ struct page *p, **pp;
+
+ addr &= PAGE_MASK;
+ pp = &rp->rxhash[h];
+ for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) {
+ if (p->index == addr) {
+ *link = pp;
+ break;
+ }
+ }
+
+ return p;
+}
+
+static void niu_hash_page(struct rx_ring_info *rp, struct page *page, u64 base)
+{
+ unsigned int h = niu_hash_rxaddr(rp, base);
+
+ page->index = base;
+ page->mapping = (struct address_space *) rp->rxhash[h];
+ rp->rxhash[h] = page;
+}
+
+static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,
+ gfp_t mask, int start_index)
+{
+ struct page *page;
+ u64 addr;
+ int i;
+
+ page = alloc_page(mask);
+ if (!page)
+ return -ENOMEM;
+
+ addr = np->ops->map_page(np->device, page, 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+
+ niu_hash_page(rp, page, addr);
+ if (rp->rbr_blocks_per_page > 1)
+ atomic_add(rp->rbr_blocks_per_page - 1,
+ &compound_head(page)->_count);
+
+ for (i = 0; i < rp->rbr_blocks_per_page; i++) {
+ __le32 *rbr = &rp->rbr[start_index + i];
+
+ *rbr = cpu_to_le32(addr >> RBR_DESCR_ADDR_SHIFT);
+ addr += rp->rbr_block_size;
+ }
+
+ return 0;
+}
+
+static void niu_rbr_refill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
+{
+ int index = rp->rbr_index;
+
+ rp->rbr_pending++;
+ if ((rp->rbr_pending % rp->rbr_blocks_per_page) == 0) {
+ int err = niu_rbr_add_page(np, rp, mask, index);
+
+ if (unlikely(err)) {
+ rp->rbr_pending--;
+ return;
+ }
+
+ rp->rbr_index += rp->rbr_blocks_per_page;
+ BUG_ON(rp->rbr_index > rp->rbr_table_size);
+ if (rp->rbr_index == rp->rbr_table_size)
+ rp->rbr_index = 0;
+
+ if (rp->rbr_pending >= rp->rbr_kick_thresh) {
+ nw64(RBR_KICK(rp->rx_channel), rp->rbr_pending);
+ rp->rbr_pending = 0;
+ }
+ }
+}
+
+static int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp)
+{
+ unsigned int index = rp->rcr_index;
+ int num_rcr = 0;
+
+ rp->rx_dropped++;
+ while (1) {
+ struct page *page, **link;
+ u64 addr, val;
+ u32 rcr_size;
+
+ num_rcr++;
+
+ val = le64_to_cpup(&rp->rcr[index]);
+ addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
+ RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
+ page = niu_find_rxpage(rp, addr, &link);
+
+ rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
+ RCR_ENTRY_PKTBUFSZ_SHIFT];
+ if ((page->index + PAGE_SIZE) - rcr_size == addr) {
+ *link = (struct page *) page->mapping;
+ np->ops->unmap_page(np->device, page->index,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ page->index = 0;
+ page->mapping = NULL;
+ __free_page(page);
+ rp->rbr_refill_pending++;
+ }
+
+ index = NEXT_RCR(rp, index);
+ if (!(val & RCR_ENTRY_MULTI))
+ break;
+
+ }
+ rp->rcr_index = index;
+
+ return num_rcr;
+}
+
+static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp)
+{
+ unsigned int index = rp->rcr_index;
+ struct sk_buff *skb;
+ int len, num_rcr;
+
+ skb = netdev_alloc_skb(np->dev, RX_SKB_ALLOC_SIZE);
+ if (unlikely(!skb))
+ return niu_rx_pkt_ignore(np, rp);
+
+ num_rcr = 0;
+ while (1) {
+ struct page *page, **link;
+ u32 rcr_size, append_size;
+ u64 addr, val, off;
+
+ num_rcr++;
+
+ val = le64_to_cpup(&rp->rcr[index]);
+
+ len = (val & RCR_ENTRY_L2_LEN) >>
+ RCR_ENTRY_L2_LEN_SHIFT;
+ len -= ETH_FCS_LEN;
+
+ addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
+ RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
+ page = niu_find_rxpage(rp, addr, &link);
+
+ rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
+ RCR_ENTRY_PKTBUFSZ_SHIFT];
+
+ off = addr & ~PAGE_MASK;
+ append_size = rcr_size;
+ if (num_rcr == 1) {
+ int ptype;
+
+ off += 2;
+ append_size -= 2;
+
+ ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT);
+ if ((ptype == RCR_PKT_TYPE_TCP ||
+ ptype == RCR_PKT_TYPE_UDP) &&
+ !(val & (RCR_ENTRY_NOPORT |
+ RCR_ENTRY_ERROR)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ if (!(val & RCR_ENTRY_MULTI))
+ append_size = len - skb->len;
+
+ niu_rx_skb_append(skb, page, off, append_size);
+ if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
+ *link = (struct page *) page->mapping;
+ np->ops->unmap_page(np->device, page->index,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ page->index = 0;
+ page->mapping = NULL;
+ rp->rbr_refill_pending++;
+ } else
+ get_page(page);
+
+ index = NEXT_RCR(rp, index);
+ if (!(val & RCR_ENTRY_MULTI))
+ break;
+
+ }
+ rp->rcr_index = index;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ __pskb_pull_tail(skb, min(len, NIU_RXPULL_MAX));
+
+ rp->rx_packets++;
+ rp->rx_bytes += skb->len;
+
+ skb->protocol = eth_type_trans(skb, np->dev);
+ netif_receive_skb(skb);
+
+ return num_rcr;
+}
+
+static int niu_rbr_fill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
+{
+ int blocks_per_page = rp->rbr_blocks_per_page;
+ int err, index = rp->rbr_index;
+
+ err = 0;
+ while (index < (rp->rbr_table_size - blocks_per_page)) {
+ err = niu_rbr_add_page(np, rp, mask, index);
+ if (err)
+ break;
+
+ index += blocks_per_page;
+ }
+
+ rp->rbr_index = index;
+ return err;
+}
+
+static void niu_rbr_free(struct niu *np, struct rx_ring_info *rp)
+{
+ int i;
+
+ for (i = 0; i < MAX_RBR_RING_SIZE; i++) {
+ struct page *page;
+
+ page = rp->rxhash[i];
+ while (page) {
+ struct page *next = (struct page *) page->mapping;
+ u64 base = page->index;
+
+ np->ops->unmap_page(np->device, base, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ page->index = 0;
+ page->mapping = NULL;
+
+ __free_page(page);
+
+ page = next;
+ }
+ }
+
+ for (i = 0; i < rp->rbr_table_size; i++)
+ rp->rbr[i] = cpu_to_le32(0);
+ rp->rbr_index = 0;
+}
+
+static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx)
+{
+ struct tx_buff_info *tb = &rp->tx_buffs[idx];
+ struct sk_buff *skb = tb->skb;
+ struct tx_pkt_hdr *tp;
+ u64 tx_flags;
+ int i, len;
+
+ tp = (struct tx_pkt_hdr *) skb->data;
+ tx_flags = le64_to_cpup(&tp->flags);
+
+ rp->tx_packets++;
+ rp->tx_bytes += (((tx_flags & TXHDR_LEN) >> TXHDR_LEN_SHIFT) -
+ ((tx_flags & TXHDR_PAD) / 2));
+
+ len = skb_headlen(skb);
+ np->ops->unmap_single(np->device, tb->mapping,
+ len, DMA_TO_DEVICE);
+
+ if (le64_to_cpu(rp->descr[idx]) & TX_DESC_MARK)
+ rp->mark_pending--;
+
+ tb->skb = NULL;
+ do {
+ idx = NEXT_TX(rp, idx);
+ len -= MAX_TX_DESC_LEN;
+ } while (len > 0);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ tb = &rp->tx_buffs[idx];
+ BUG_ON(tb->skb != NULL);
+ np->ops->unmap_page(np->device, tb->mapping,
+ skb_shinfo(skb)->frags[i].size,
+ DMA_TO_DEVICE);
+ idx = NEXT_TX(rp, idx);
+ }
+
+ dev_kfree_skb(skb);
+
+ return idx;
+}
+
+#define NIU_TX_WAKEUP_THRESH(rp) ((rp)->pending / 4)
+
+static void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
+{
+ u16 pkt_cnt, tmp;
+ int cons;
+ u64 cs;
+
+ cs = rp->tx_cs;
+ if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK))))
+ goto out;
+
+ tmp = pkt_cnt = (cs & TX_CS_PKT_CNT) >> TX_CS_PKT_CNT_SHIFT;
+ pkt_cnt = (pkt_cnt - rp->last_pkt_cnt) &
+ (TX_CS_PKT_CNT >> TX_CS_PKT_CNT_SHIFT);
+
+ rp->last_pkt_cnt = tmp;
+
+ cons = rp->cons;
+
+ niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n",
+ np->dev->name, pkt_cnt, cons);
+
+ while (pkt_cnt--)
+ cons = release_tx_packet(np, rp, cons);
+
+ rp->cons = cons;
+ smp_mb();
+
+out:
+ if (unlikely(netif_queue_stopped(np->dev) &&
+ (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) {
+ netif_tx_lock(np->dev);
+ if (netif_queue_stopped(np->dev) &&
+ (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))
+ netif_wake_queue(np->dev);
+ netif_tx_unlock(np->dev);
+ }
+}
+
+static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
+{
+ int qlen, rcr_done = 0, work_done = 0;
+ struct rxdma_mailbox *mbox = rp->mbox;
+ u64 stat;
+
+#if 1
+ stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
+ qlen = nr64(RCRSTAT_A(rp->rx_channel)) & RCRSTAT_A_QLEN;
+#else
+ stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
+ qlen = (le64_to_cpup(&mbox->rcrstat_a) & RCRSTAT_A_QLEN);
+#endif
+ mbox->rx_dma_ctl_stat = 0;
+ mbox->rcrstat_a = 0;
+
+ niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n",
+ np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen);
+
+ rcr_done = work_done = 0;
+ qlen = min(qlen, budget);
+ while (work_done < qlen) {
+ rcr_done += niu_process_rx_pkt(np, rp);
+ work_done++;
+ }
+
+ if (rp->rbr_refill_pending >= rp->rbr_kick_thresh) {
+ unsigned int i;
+
+ for (i = 0; i < rp->rbr_refill_pending; i++)
+ niu_rbr_refill(np, rp, GFP_ATOMIC);
+ rp->rbr_refill_pending = 0;
+ }
+
+ stat = (RX_DMA_CTL_STAT_MEX |
+ ((u64)work_done << RX_DMA_CTL_STAT_PKTREAD_SHIFT) |
+ ((u64)rcr_done << RX_DMA_CTL_STAT_PTRREAD_SHIFT));
+
+ nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat);
+
+ return work_done;
+}
+
+static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget)
+{
+ u64 v0 = lp->v0;
+ u32 tx_vec = (v0 >> 32);
+ u32 rx_vec = (v0 & 0xffffffff);
+ int i, work_done = 0;
+
+ niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n",
+ np->dev->name, (unsigned long long) v0);
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+ if (tx_vec & (1 << rp->tx_channel))
+ niu_tx_work(np, rp);
+ nw64(LD_IM0(LDN_TXDMA(rp->tx_channel)), 0);
+ }
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ if (rx_vec & (1 << rp->rx_channel)) {
+ int this_work_done;
+
+ this_work_done = niu_rx_work(np, rp,
+ budget);
+
+ budget -= this_work_done;
+ work_done += this_work_done;
+ }
+ nw64(LD_IM0(LDN_RXDMA(rp->rx_channel)), 0);
+ }
+
+ return work_done;
+}
+
+static int niu_poll(struct napi_struct *napi, int budget)
+{
+ struct niu_ldg *lp = container_of(napi, struct niu_ldg, napi);
+ struct niu *np = lp->np;
+ int work_done;
+
+ work_done = niu_poll_core(np, lp, budget);
+
+ if (work_done < budget) {
+ netif_rx_complete(np->dev, napi);
+ niu_ldg_rearm(np, lp, 1);
+ }
+ return work_done;
+}
+
+static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp,
+ u64 stat)
+{
+ dev_err(np->device, PFX "%s: RX channel %u errors ( ",
+ np->dev->name, rp->rx_channel);
+
+ if (stat & RX_DMA_CTL_STAT_RBR_TMOUT)
+ printk("RBR_TMOUT ");
+ if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR)
+ printk("RSP_CNT ");
+ if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS)
+ printk("BYTE_EN_BUS ");
+ if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR)
+ printk("RSP_DAT ");
+ if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR)
+ printk("RCR_ACK ");
+ if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR)
+ printk("RCR_SHA_PAR ");
+ if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR)
+ printk("RBR_PRE_PAR ");
+ if (stat & RX_DMA_CTL_STAT_CONFIG_ERR)
+ printk("CONFIG ");
+ if (stat & RX_DMA_CTL_STAT_RCRINCON)
+ printk("RCRINCON ");
+ if (stat & RX_DMA_CTL_STAT_RCRFULL)
+ printk("RCRFULL ");
+ if (stat & RX_DMA_CTL_STAT_RBRFULL)
+ printk("RBRFULL ");
+ if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE)
+ printk("RBRLOGPAGE ");
+ if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE)
+ printk("CFIGLOGPAGE ");
+ if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR)
+ printk("DC_FIDO ");
+
+ printk(")\n");
+}
+
+static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
+{
+ u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
+ int err = 0;
+
+ dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
+ np->dev->name, rp->rx_channel, (unsigned long long) stat);
+
+ niu_log_rxchan_errors(np, rp, stat);
+
+ if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL |
+ RX_DMA_CTL_STAT_PORT_FATAL))
+ err = -EINVAL;
+
+ nw64(RX_DMA_CTL_STAT(rp->rx_channel),
+ stat & RX_DMA_CTL_WRITE_CLEAR_ERRS);
+
+ return err;
+}
+
+static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp,
+ u64 cs)
+{
+ dev_err(np->device, PFX "%s: TX channel %u errors ( ",
+ np->dev->name, rp->tx_channel);
+
+ if (cs & TX_CS_MBOX_ERR)
+ printk("MBOX ");
+ if (cs & TX_CS_PKT_SIZE_ERR)
+ printk("PKT_SIZE ");
+ if (cs & TX_CS_TX_RING_OFLOW)
+ printk("TX_RING_OFLOW ");
+ if (cs & TX_CS_PREF_BUF_PAR_ERR)
+ printk("PREF_BUF_PAR ");
+ if (cs & TX_CS_NACK_PREF)
+ printk("NACK_PREF ");
+ if (cs & TX_CS_NACK_PKT_RD)
+ printk("NACK_PKT_RD ");
+ if (cs & TX_CS_CONF_PART_ERR)
+ printk("CONF_PART ");
+ if (cs & TX_CS_PKT_PRT_ERR)
+ printk("PKT_PTR ");
+
+ printk(")\n");
+}
+
+static int niu_tx_error(struct niu *np, struct tx_ring_info *rp)
+{
+ u64 cs, logh, logl;
+
+ cs = nr64(TX_CS(rp->tx_channel));
+ logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel));
+ logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel));
+
+ dev_err(np->device, PFX "%s: TX channel %u error, "
+ "cs[%llx] logh[%llx] logl[%llx]\n",
+ np->dev->name, rp->tx_channel,
+ (unsigned long long) cs,
+ (unsigned long long) logh,
+ (unsigned long long) logl);
+
+ niu_log_txchan_errors(np, rp, cs);
+
+ return -ENODEV;
+}
+
+static int niu_mif_interrupt(struct niu *np)
+{
+ u64 mif_status = nr64(MIF_STATUS);
+ int phy_mdint = 0;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ u64 xrxmac_stat = nr64_mac(XRXMAC_STATUS);
+
+ if (xrxmac_stat & XRXMAC_STATUS_PHY_MDINT)
+ phy_mdint = 1;
+ }
+
+ dev_err(np->device, PFX "%s: MIF interrupt, "
+ "stat[%llx] phy_mdint(%d)\n",
+ np->dev->name, (unsigned long long) mif_status, phy_mdint);
+
+ return -ENODEV;
+}
+
+static void niu_xmac_interrupt(struct niu *np)
+{
+ struct niu_xmac_stats *mp = &np->mac_stats.xmac;
+ u64 val;
+
+ val = nr64_mac(XTXMAC_STATUS);
+ if (val & XTXMAC_STATUS_FRAME_CNT_EXP)
+ mp->tx_frames += TXMAC_FRM_CNT_COUNT;
+ if (val & XTXMAC_STATUS_BYTE_CNT_EXP)
+ mp->tx_bytes += TXMAC_BYTE_CNT_COUNT;
+ if (val & XTXMAC_STATUS_TXFIFO_XFR_ERR)
+ mp->tx_fifo_errors++;
+ if (val & XTXMAC_STATUS_TXMAC_OFLOW)
+ mp->tx_overflow_errors++;
+ if (val & XTXMAC_STATUS_MAX_PSIZE_ERR)
+ mp->tx_max_pkt_size_errors++;
+ if (val & XTXMAC_STATUS_TXMAC_UFLOW)
+ mp->tx_underflow_errors++;
+
+ val = nr64_mac(XRXMAC_STATUS);
+ if (val & XRXMAC_STATUS_LCL_FLT_STATUS)
+ mp->rx_local_faults++;
+ if (val & XRXMAC_STATUS_RFLT_DET)
+ mp->rx_remote_faults++;
+ if (val & XRXMAC_STATUS_LFLT_CNT_EXP)
+ mp->rx_link_faults += LINK_FAULT_CNT_COUNT;
+ if (val & XRXMAC_STATUS_ALIGNERR_CNT_EXP)
+ mp->rx_align_errors += RXMAC_ALIGN_ERR_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXFRAG_CNT_EXP)
+ mp->rx_frags += RXMAC_FRAG_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXMULTF_CNT_EXP)
+ mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
+ mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
+ mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP)
+ mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP)
+ mp->rx_hist_cnt2 += RXMAC_HIST_CNT2_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST3_CNT_EXP)
+ mp->rx_hist_cnt3 += RXMAC_HIST_CNT3_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST4_CNT_EXP)
+ mp->rx_hist_cnt4 += RXMAC_HIST_CNT4_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST5_CNT_EXP)
+ mp->rx_hist_cnt5 += RXMAC_HIST_CNT5_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST6_CNT_EXP)
+ mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP)
+ mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT;
+ if (val & XRXMAC_STAT_MSK_RXOCTET_CNT_EXP)
+ mp->rx_octets += RXMAC_BT_CNT_COUNT;
+ if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP)
+ mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT;
+ if (val & XRXMAC_STATUS_LENERR_CNT_EXP)
+ mp->rx_len_errors += RXMAC_MPSZER_CNT_COUNT;
+ if (val & XRXMAC_STATUS_CRCERR_CNT_EXP)
+ mp->rx_crc_errors += RXMAC_CRC_ER_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXUFLOW)
+ mp->rx_underflows++;
+ if (val & XRXMAC_STATUS_RXOFLOW)
+ mp->rx_overflows++;
+
+ val = nr64_mac(XMAC_FC_STAT);
+ if (val & XMAC_FC_STAT_TX_MAC_NPAUSE)
+ mp->pause_off_state++;
+ if (val & XMAC_FC_STAT_TX_MAC_PAUSE)
+ mp->pause_on_state++;
+ if (val & XMAC_FC_STAT_RX_MAC_RPAUSE)
+ mp->pause_received++;
+}
+
+static void niu_bmac_interrupt(struct niu *np)
+{
+ struct niu_bmac_stats *mp = &np->mac_stats.bmac;
+ u64 val;
+
+ val = nr64_mac(BTXMAC_STATUS);
+ if (val & BTXMAC_STATUS_UNDERRUN)
+ mp->tx_underflow_errors++;
+ if (val & BTXMAC_STATUS_MAX_PKT_ERR)
+ mp->tx_max_pkt_size_errors++;
+ if (val & BTXMAC_STATUS_BYTE_CNT_EXP)
+ mp->tx_bytes += BTXMAC_BYTE_CNT_COUNT;
+ if (val & BTXMAC_STATUS_FRAME_CNT_EXP)
+ mp->tx_frames += BTXMAC_FRM_CNT_COUNT;
+
+ val = nr64_mac(BRXMAC_STATUS);
+ if (val & BRXMAC_STATUS_OVERFLOW)
+ mp->rx_overflows++;
+ if (val & BRXMAC_STATUS_FRAME_CNT_EXP)
+ mp->rx_frames += BRXMAC_FRAME_CNT_COUNT;
+ if (val & BRXMAC_STATUS_ALIGN_ERR_EXP)
+ mp->rx_align_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
+ if (val & BRXMAC_STATUS_CRC_ERR_EXP)
+ mp->rx_crc_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
+ if (val & BRXMAC_STATUS_LEN_ERR_EXP)
+ mp->rx_len_errors += BRXMAC_CODE_VIOL_ERR_CNT_COUNT;
+
+ val = nr64_mac(BMAC_CTRL_STATUS);
+ if (val & BMAC_CTRL_STATUS_NOPAUSE)
+ mp->pause_off_state++;
+ if (val & BMAC_CTRL_STATUS_PAUSE)
+ mp->pause_on_state++;
+ if (val & BMAC_CTRL_STATUS_PAUSE_RECV)
+ mp->pause_received++;
+}
+
+static int niu_mac_interrupt(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_xmac_interrupt(np);
+ else
+ niu_bmac_interrupt(np);
+
+ return 0;
+}
+
+static void niu_log_device_error(struct niu *np, u64 stat)
+{
+ dev_err(np->device, PFX "%s: Core device errors ( ",
+ np->dev->name);
+
+ if (stat & SYS_ERR_MASK_META2)
+ printk("META2 ");
+ if (stat & SYS_ERR_MASK_META1)
+ printk("META1 ");
+ if (stat & SYS_ERR_MASK_PEU)
+ printk("PEU ");
+ if (stat & SYS_ERR_MASK_TXC)
+ printk("TXC ");
+ if (stat & SYS_ERR_MASK_RDMC)
+ printk("RDMC ");
+ if (stat & SYS_ERR_MASK_TDMC)
+ printk("TDMC ");
+ if (stat & SYS_ERR_MASK_ZCP)
+ printk("ZCP ");
+ if (stat & SYS_ERR_MASK_FFLP)
+ printk("FFLP ");
+ if (stat & SYS_ERR_MASK_IPP)
+ printk("IPP ");
+ if (stat & SYS_ERR_MASK_MAC)
+ printk("MAC ");
+ if (stat & SYS_ERR_MASK_SMX)
+ printk("SMX ");
+
+ printk(")\n");
+}
+
+static int niu_device_error(struct niu *np)
+{
+ u64 stat = nr64(SYS_ERR_STAT);
+
+ dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n",
+ np->dev->name, (unsigned long long) stat);
+
+ niu_log_device_error(np, stat);
+
+ return -ENODEV;
+}
+
+static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
+{
+ u64 v0 = lp->v0;
+ u64 v1 = lp->v1;
+ u64 v2 = lp->v2;
+ int i, err = 0;
+
+ if (v1 & 0x00000000ffffffffULL) {
+ u32 rx_vec = (v1 & 0xffffffff);
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ if (rx_vec & (1 << rp->rx_channel)) {
+ int r = niu_rx_error(np, rp);
+ if (r)
+ err = r;
+ }
+ }
+ }
+ if (v1 & 0x7fffffff00000000ULL) {
+ u32 tx_vec = (v1 >> 32) & 0x7fffffff;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ if (tx_vec & (1 << rp->tx_channel)) {
+ int r = niu_tx_error(np, rp);
+ if (r)
+ err = r;
+ }
+ }
+ }
+ if ((v0 | v1) & 0x8000000000000000ULL) {
+ int r = niu_mif_interrupt(np);
+ if (r)
+ err = r;
+ }
+ if (v2) {
+ if (v2 & 0x01ef) {
+ int r = niu_mac_interrupt(np);
+ if (r)
+ err = r;
+ }
+ if (v2 & 0x0210) {
+ int r = niu_device_error(np);
+ if (r)
+ err = r;
+ }
+ }
+
+ if (err)
+ niu_enable_interrupts(np, 0);
+
+ return -EINVAL;
+}
+
+static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
+ int ldn)
+{
+ struct rxdma_mailbox *mbox = rp->mbox;
+ u64 stat_write, stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
+
+ stat_write = (RX_DMA_CTL_STAT_RCRTHRES |
+ RX_DMA_CTL_STAT_RCRTO);
+ nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write);
+
+ niudbg(INTR, "%s: rxchan_intr stat[%llx]\n",
+ np->dev->name, (unsigned long long) stat);
+}
+
+static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp,
+ int ldn)
+{
+ rp->tx_cs = nr64(TX_CS(rp->tx_channel));
+
+ niudbg(INTR, "%s: txchan_intr cs[%llx]\n",
+ np->dev->name, (unsigned long long) rp->tx_cs);
+}
+
+static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0)
+{
+ struct niu_parent *parent = np->parent;
+ u32 rx_vec, tx_vec;
+ int i;
+
+ tx_vec = (v0 >> 32);
+ rx_vec = (v0 & 0xffffffff);
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+ int ldn = LDN_RXDMA(rp->rx_channel);
+
+ if (parent->ldg_map[ldn] != ldg)
+ continue;
+
+ nw64(LD_IM0(ldn), LD_IM0_MASK);
+ if (rx_vec & (1 << rp->rx_channel))
+ niu_rxchan_intr(np, rp, ldn);
+ }
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+ int ldn = LDN_TXDMA(rp->tx_channel);
+
+ if (parent->ldg_map[ldn] != ldg)
+ continue;
+
+ nw64(LD_IM0(ldn), LD_IM0_MASK);
+ if (tx_vec & (1 << rp->tx_channel))
+ niu_txchan_intr(np, rp, ldn);
+ }
+}
+
+static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp,
+ u64 v0, u64 v1, u64 v2)
+{
+ if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) {
+ lp->v0 = v0;
+ lp->v1 = v1;
+ lp->v2 = v2;
+ __niu_fastpath_interrupt(np, lp->ldg_num, v0);
+ __netif_rx_schedule(np->dev, &lp->napi);
+ }
+}
+
+static irqreturn_t niu_interrupt(int irq, void *dev_id)
+{
+ struct niu_ldg *lp = dev_id;
+ struct niu *np = lp->np;
+ int ldg = lp->ldg_num;
+ unsigned long flags;
+ u64 v0, v1, v2;
+
+ if (netif_msg_intr(np))
+ printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ",
+ lp, ldg);
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ v0 = nr64(LDSV0(ldg));
+ v1 = nr64(LDSV1(ldg));
+ v2 = nr64(LDSV2(ldg));
+
+ if (netif_msg_intr(np))
+ printk("v0[%llx] v1[%llx] v2[%llx]\n",
+ (unsigned long long) v0,
+ (unsigned long long) v1,
+ (unsigned long long) v2);
+
+ if (unlikely(!v0 && !v1 && !v2)) {
+ spin_unlock_irqrestore(&np->lock, flags);
+ return IRQ_NONE;
+ }
+
+ if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) {
+ int err = niu_slowpath_interrupt(np, lp);
+ if (err)
+ goto out;
+ }
+ if (likely(v0 & ~((u64)1 << LDN_MIF)))
+ niu_schedule_napi(np, lp, v0, v1, v2);
+ else
+ niu_ldg_rearm(np, lp, 1);
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void niu_free_rx_ring_info(struct niu *np, struct rx_ring_info *rp)
+{
+ if (rp->mbox) {
+ np->ops->free_coherent(np->device,
+ sizeof(struct rxdma_mailbox),
+ rp->mbox, rp->mbox_dma);
+ rp->mbox = NULL;
+ }
+ if (rp->rcr) {
+ np->ops->free_coherent(np->device,
+ MAX_RCR_RING_SIZE * sizeof(__le64),
+ rp->rcr, rp->rcr_dma);
+ rp->rcr = NULL;
+ rp->rcr_table_size = 0;
+ rp->rcr_index = 0;
+ }
+ if (rp->rbr) {
+ niu_rbr_free(np, rp);
+
+ np->ops->free_coherent(np->device,
+ MAX_RBR_RING_SIZE * sizeof(__le32),
+ rp->rbr, rp->rbr_dma);
+ rp->rbr = NULL;
+ rp->rbr_table_size = 0;
+ rp->rbr_index = 0;
+ }
+ kfree(rp->rxhash);
+ rp->rxhash = NULL;
+}
+
+static void niu_free_tx_ring_info(struct niu *np, struct tx_ring_info *rp)
+{
+ if (rp->mbox) {
+ np->ops->free_coherent(np->device,
+ sizeof(struct txdma_mailbox),
+ rp->mbox, rp->mbox_dma);
+ rp->mbox = NULL;
+ }
+ if (rp->descr) {
+ int i;
+
+ for (i = 0; i < MAX_TX_RING_SIZE; i++) {
+ if (rp->tx_buffs[i].skb)
+ (void) release_tx_packet(np, rp, i);
+ }
+
+ np->ops->free_coherent(np->device,
+ MAX_TX_RING_SIZE * sizeof(__le64),
+ rp->descr, rp->descr_dma);
+ rp->descr = NULL;
+ rp->pending = 0;
+ rp->prod = 0;
+ rp->cons = 0;
+ rp->wrap_bit = 0;
+ }
+}
+
+static void niu_free_channels(struct niu *np)
+{
+ int i;
+
+ if (np->rx_rings) {
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ niu_free_rx_ring_info(np, rp);
+ }
+ kfree(np->rx_rings);
+ np->rx_rings = NULL;
+ np->num_rx_rings = 0;
+ }
+
+ if (np->tx_rings) {
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ niu_free_tx_ring_info(np, rp);
+ }
+ kfree(np->tx_rings);
+ np->tx_rings = NULL;
+ np->num_tx_rings = 0;
+ }
+}
+
+static int niu_alloc_rx_ring_info(struct niu *np,
+ struct rx_ring_info *rp)
+{
+ BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64);
+
+ rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *),
+ GFP_KERNEL);
+ if (!rp->rxhash)
+ return -ENOMEM;
+
+ rp->mbox = np->ops->alloc_coherent(np->device,
+ sizeof(struct rxdma_mailbox),
+ &rp->mbox_dma, GFP_KERNEL);
+ if (!rp->mbox)
+ return -ENOMEM;
+ if ((unsigned long)rp->mbox & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "RXDMA mailbox %p\n", np->dev->name, rp->mbox);
+ return -EINVAL;
+ }
+
+ rp->rcr = np->ops->alloc_coherent(np->device,
+ MAX_RCR_RING_SIZE * sizeof(__le64),
+ &rp->rcr_dma, GFP_KERNEL);
+ if (!rp->rcr)
+ return -ENOMEM;
+ if ((unsigned long)rp->rcr & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "RXDMA RCR table %p\n", np->dev->name, rp->rcr);
+ return -EINVAL;
+ }
+ rp->rcr_table_size = MAX_RCR_RING_SIZE;
+ rp->rcr_index = 0;
+
+ rp->rbr = np->ops->alloc_coherent(np->device,
+ MAX_RBR_RING_SIZE * sizeof(__le32),
+ &rp->rbr_dma, GFP_KERNEL);
+ if (!rp->rbr)
+ return -ENOMEM;
+ if ((unsigned long)rp->rbr & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "RXDMA RBR table %p\n", np->dev->name, rp->rbr);
+ return -EINVAL;
+ }
+ rp->rbr_table_size = MAX_RBR_RING_SIZE;
+ rp->rbr_index = 0;
+ rp->rbr_pending = 0;
+
+ return 0;
+}
+
+static void niu_set_max_burst(struct niu *np, struct tx_ring_info *rp)
+{
+ int mtu = np->dev->mtu;
+
+ /* These values are recommended by the HW designers for fair
+ * utilization of DRR amongst the rings.
+ */
+ rp->max_burst = mtu + 32;
+ if (rp->max_burst > 4096)
+ rp->max_burst = 4096;
+}
+
+static int niu_alloc_tx_ring_info(struct niu *np,
+ struct tx_ring_info *rp)
+{
+ BUILD_BUG_ON(sizeof(struct txdma_mailbox) != 64);
+
+ rp->mbox = np->ops->alloc_coherent(np->device,
+ sizeof(struct txdma_mailbox),
+ &rp->mbox_dma, GFP_KERNEL);
+ if (!rp->mbox)
+ return -ENOMEM;
+ if ((unsigned long)rp->mbox & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "TXDMA mailbox %p\n", np->dev->name, rp->mbox);
+ return -EINVAL;
+ }
+
+ rp->descr = np->ops->alloc_coherent(np->device,
+ MAX_TX_RING_SIZE * sizeof(__le64),
+ &rp->descr_dma, GFP_KERNEL);
+ if (!rp->descr)
+ return -ENOMEM;
+ if ((unsigned long)rp->descr & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "TXDMA descr table %p\n", np->dev->name, rp->descr);
+ return -EINVAL;
+ }
+
+ rp->pending = MAX_TX_RING_SIZE;
+ rp->prod = 0;
+ rp->cons = 0;
+ rp->wrap_bit = 0;
+
+ /* XXX make these configurable... XXX */
+ rp->mark_freq = rp->pending / 4;
+
+ niu_set_max_burst(np, rp);
+
+ return 0;
+}
+
+static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
+{
+ u16 bs;
+
+ switch (PAGE_SIZE) {
+ case 4 * 1024:
+ case 8 * 1024:
+ case 16 * 1024:
+ case 32 * 1024:
+ rp->rbr_block_size = PAGE_SIZE;
+ rp->rbr_blocks_per_page = 1;
+ break;
+
+ default:
+ if (PAGE_SIZE % (32 * 1024) == 0)
+ bs = 32 * 1024;
+ else if (PAGE_SIZE % (16 * 1024) == 0)
+ bs = 16 * 1024;
+ else if (PAGE_SIZE % (8 * 1024) == 0)
+ bs = 8 * 1024;
+ else if (PAGE_SIZE % (4 * 1024) == 0)
+ bs = 4 * 1024;
+ else
+ BUG();
+ rp->rbr_block_size = bs;
+ rp->rbr_blocks_per_page = PAGE_SIZE / bs;
+ }
+
+ rp->rbr_sizes[0] = 256;
+ rp->rbr_sizes[1] = 1024;
+ if (np->dev->mtu > ETH_DATA_LEN) {
+ switch (PAGE_SIZE) {
+ case 4 * 1024:
+ rp->rbr_sizes[2] = 4096;
+ break;
+
+ default:
+ rp->rbr_sizes[2] = 8192;
+ break;
+ }
+ } else {
+ rp->rbr_sizes[2] = 2048;
+ }
+ rp->rbr_sizes[3] = rp->rbr_block_size;
+}
+
+static int niu_alloc_channels(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ int first_rx_channel, first_tx_channel;
+ int i, port, err;
+
+ port = np->port;
+ first_rx_channel = first_tx_channel = 0;
+ for (i = 0; i < port; i++) {
+ first_rx_channel += parent->rxchan_per_port[i];
+ first_tx_channel += parent->txchan_per_port[i];
+ }
+
+ np->num_rx_rings = parent->rxchan_per_port[port];
+ np->num_tx_rings = parent->txchan_per_port[port];
+
+ np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info),
+ GFP_KERNEL);
+ err = -ENOMEM;
+ if (!np->rx_rings)
+ goto out_err;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ rp->np = np;
+ rp->rx_channel = first_rx_channel + i;
+
+ err = niu_alloc_rx_ring_info(np, rp);
+ if (err)
+ goto out_err;
+
+ niu_size_rbr(np, rp);
+
+ /* XXX better defaults, configurable, etc... XXX */
+ rp->nonsyn_window = 64;
+ rp->nonsyn_threshold = rp->rcr_table_size - 64;
+ rp->syn_window = 64;
+ rp->syn_threshold = rp->rcr_table_size - 64;
+ rp->rcr_pkt_threshold = 16;
+ rp->rcr_timeout = 8;
+ rp->rbr_kick_thresh = RBR_REFILL_MIN;
+ if (rp->rbr_kick_thresh < rp->rbr_blocks_per_page)
+ rp->rbr_kick_thresh = rp->rbr_blocks_per_page;
+
+ err = niu_rbr_fill(np, rp, GFP_KERNEL);
+ if (err)
+ return err;
+ }
+
+ np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info),
+ GFP_KERNEL);
+ err = -ENOMEM;
+ if (!np->tx_rings)
+ goto out_err;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ rp->np = np;
+ rp->tx_channel = first_tx_channel + i;
+
+ err = niu_alloc_tx_ring_info(np, rp);
+ if (err)
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ niu_free_channels(np);
+ return err;
+}
+
+static int niu_tx_cs_sng_poll(struct niu *np, int channel)
+{
+ int limit = 1000;
+
+ while (--limit > 0) {
+ u64 val = nr64(TX_CS(channel));
+ if (val & TX_CS_SNG_STATE)
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int niu_tx_channel_stop(struct niu *np, int channel)
+{
+ u64 val = nr64(TX_CS(channel));
+
+ val |= TX_CS_STOP_N_GO;
+ nw64(TX_CS(channel), val);
+
+ return niu_tx_cs_sng_poll(np, channel);
+}
+
+static int niu_tx_cs_reset_poll(struct niu *np, int channel)
+{
+ int limit = 1000;
+
+ while (--limit > 0) {
+ u64 val = nr64(TX_CS(channel));
+ if (!(val & TX_CS_RST))
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int niu_tx_channel_reset(struct niu *np, int channel)
+{
+ u64 val = nr64(TX_CS(channel));
+ int err;
+
+ val |= TX_CS_RST;
+ nw64(TX_CS(channel), val);
+
+ err = niu_tx_cs_reset_poll(np, channel);
+ if (!err)
+ nw64(TX_RING_KICK(channel), 0);
+
+ return err;
+}
+
+static int niu_tx_channel_lpage_init(struct niu *np, int channel)
+{
+ u64 val;
+
+ nw64(TX_LOG_MASK1(channel), 0);
+ nw64(TX_LOG_VAL1(channel), 0);
+ nw64(TX_LOG_MASK2(channel), 0);
+ nw64(TX_LOG_VAL2(channel), 0);
+ nw64(TX_LOG_PAGE_RELO1(channel), 0);
+ nw64(TX_LOG_PAGE_RELO2(channel), 0);
+ nw64(TX_LOG_PAGE_HDL(channel), 0);
+
+ val = (u64)np->port << TX_LOG_PAGE_VLD_FUNC_SHIFT;
+ val |= (TX_LOG_PAGE_VLD_PAGE0 | TX_LOG_PAGE_VLD_PAGE1);
+ nw64(TX_LOG_PAGE_VLD(channel), val);
+
+ /* XXX TXDMA 32bit mode? XXX */
+
+ return 0;
+}
+
+static void niu_txc_enable_port(struct niu *np, int on)
+{
+ unsigned long flags;
+ u64 val, mask;
+
+ niu_lock_parent(np, flags);
+ val = nr64(TXC_CONTROL);
+ mask = (u64)1 << np->port;
+ if (on) {
+ val |= TXC_CONTROL_ENABLE | mask;
+ } else {
+ val &= ~mask;
+ if ((val & ~TXC_CONTROL_ENABLE) == 0)
+ val &= ~TXC_CONTROL_ENABLE;
+ }
+ nw64(TXC_CONTROL, val);
+ niu_unlock_parent(np, flags);
+}
+
+static void niu_txc_set_imask(struct niu *np, u64 imask)
+{
+ unsigned long flags;
+ u64 val;
+
+ niu_lock_parent(np, flags);
+ val = nr64(TXC_INT_MASK);
+ val &= ~TXC_INT_MASK_VAL(np->port);
+ val |= (imask << TXC_INT_MASK_VAL_SHIFT(np->port));
+ niu_unlock_parent(np, flags);
+}
+
+static void niu_txc_port_dma_enable(struct niu *np, int on)
+{
+ u64 val = 0;
+
+ if (on) {
+ int i;
+
+ for (i = 0; i < np->num_tx_rings; i++)
+ val |= (1 << np->tx_rings[i].tx_channel);
+ }
+ nw64(TXC_PORT_DMA(np->port), val);
+}
+
+static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+ int err, channel = rp->tx_channel;
+ u64 val, ring_len;
+
+ err = niu_tx_channel_stop(np, channel);
+ if (err)
+ return err;
+
+ err = niu_tx_channel_reset(np, channel);
+ if (err)
+ return err;
+
+ err = niu_tx_channel_lpage_init(np, channel);
+ if (err)
+ return err;
+
+ nw64(TXC_DMA_MAX(channel), rp->max_burst);
+ nw64(TX_ENT_MSK(channel), 0);
+
+ if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE |
+ TX_RNG_CFIG_STADDR)) {
+ dev_err(np->device, PFX "%s: TX ring channel %d "
+ "DMA addr (%llx) is not aligned.\n",
+ np->dev->name, channel,
+ (unsigned long long) rp->descr_dma);
+ return -EINVAL;
+ }
+
+ /* The length field in TX_RNG_CFIG is measured in 64-byte
+ * blocks. rp->pending is the number of TX descriptors in
+ * our ring, 8 bytes each, thus we divide by 8 bytes more
+ * to get the proper value the chip wants.
+ */
+ ring_len = (rp->pending / 8);
+
+ val = ((ring_len << TX_RNG_CFIG_LEN_SHIFT) |
+ rp->descr_dma);
+ nw64(TX_RNG_CFIG(channel), val);
+
+ if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) ||
+ ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) {
+ dev_err(np->device, PFX "%s: TX ring channel %d "
+ "MBOX addr (%llx) is has illegal bits.\n",
+ np->dev->name, channel,
+ (unsigned long long) rp->mbox_dma);
+ return -EINVAL;
+ }
+ nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32);
+ nw64(TXDMA_MBL(channel), rp->mbox_dma & TXDMA_MBL_MBADDR);
+
+ nw64(TX_CS(channel), 0);
+
+ rp->last_pkt_cnt = 0;
+
+ return 0;
+}
+
+static void niu_init_rdc_groups(struct niu *np)
+{
+ struct niu_rdc_tables *tp = &np->parent->rdc_group_cfg[np->port];
+ int i, first_table_num = tp->first_table_num;
+
+ for (i = 0; i < tp->num_tables; i++) {
+ struct rdc_table *tbl = &tp->tables[i];
+ int this_table = first_table_num + i;
+ int slot;
+
+ for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++)
+ nw64(RDC_TBL(this_table, slot),
+ tbl->rxdma_channel[slot]);
+ }
+
+ nw64(DEF_RDC(np->port), np->parent->rdc_default[np->port]);
+}
+
+static void niu_init_drr_weight(struct niu *np)
+{
+ int type = phy_decode(np->parent->port_phy, np->port);
+ u64 val;
+
+ switch (type) {
+ case PORT_TYPE_10G:
+ val = PT_DRR_WEIGHT_DEFAULT_10G;
+ break;
+
+ case PORT_TYPE_1G:
+ default:
+ val = PT_DRR_WEIGHT_DEFAULT_1G;
+ break;
+ }
+ nw64(PT_DRR_WT(np->port), val);
+}
+
+static int niu_init_hostinfo(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+ int i, err, num_alt = niu_num_alt_addr(np);
+ int first_rdc_table = tp->first_table_num;
+
+ err = niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+ if (err)
+ return err;
+
+ err = niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+ if (err)
+ return err;
+
+ for (i = 0; i < num_alt; i++) {
+ err = niu_set_alt_mac_rdc_table(np, i, first_rdc_table, 1);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int niu_rx_channel_reset(struct niu *np, int channel)
+{
+ return niu_set_and_wait_clear(np, RXDMA_CFIG1(channel),
+ RXDMA_CFIG1_RST, 1000, 10,
+ "RXDMA_CFIG1");
+}
+
+static int niu_rx_channel_lpage_init(struct niu *np, int channel)
+{
+ u64 val;
+
+ nw64(RX_LOG_MASK1(channel), 0);
+ nw64(RX_LOG_VAL1(channel), 0);
+ nw64(RX_LOG_MASK2(channel), 0);
+ nw64(RX_LOG_VAL2(channel), 0);
+ nw64(RX_LOG_PAGE_RELO1(channel), 0);
+ nw64(RX_LOG_PAGE_RELO2(channel), 0);
+ nw64(RX_LOG_PAGE_HDL(channel), 0);
+
+ val = (u64)np->port << RX_LOG_PAGE_VLD_FUNC_SHIFT;
+ val |= (RX_LOG_PAGE_VLD_PAGE0 | RX_LOG_PAGE_VLD_PAGE1);
+ nw64(RX_LOG_PAGE_VLD(channel), val);
+
+ return 0;
+}
+
+static void niu_rx_channel_wred_init(struct niu *np, struct rx_ring_info *rp)
+{
+ u64 val;
+
+ val = (((u64)rp->nonsyn_window << RDC_RED_PARA_WIN_SHIFT) |
+ ((u64)rp->nonsyn_threshold << RDC_RED_PARA_THRE_SHIFT) |
+ ((u64)rp->syn_window << RDC_RED_PARA_WIN_SYN_SHIFT) |
+ ((u64)rp->syn_threshold << RDC_RED_PARA_THRE_SYN_SHIFT));
+ nw64(RDC_RED_PARA(rp->rx_channel), val);
+}
+
+static int niu_compute_rbr_cfig_b(struct rx_ring_info *rp, u64 *ret)
+{
+ u64 val = 0;
+
+ switch (rp->rbr_block_size) {
+ case 4 * 1024:
+ val |= (RBR_BLKSIZE_4K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ case 8 * 1024:
+ val |= (RBR_BLKSIZE_8K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ case 16 * 1024:
+ val |= (RBR_BLKSIZE_16K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ case 32 * 1024:
+ val |= (RBR_BLKSIZE_32K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+ val |= RBR_CFIG_B_VLD2;
+ switch (rp->rbr_sizes[2]) {
+ case 2 * 1024:
+ val |= (RBR_BUFSZ2_2K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+ case 4 * 1024:
+ val |= (RBR_BUFSZ2_4K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+ case 8 * 1024:
+ val |= (RBR_BUFSZ2_8K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+ case 16 * 1024:
+ val |= (RBR_BUFSZ2_16K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ val |= RBR_CFIG_B_VLD1;
+ switch (rp->rbr_sizes[1]) {
+ case 1 * 1024:
+ val |= (RBR_BUFSZ1_1K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+ case 2 * 1024:
+ val |= (RBR_BUFSZ1_2K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+ case 4 * 1024:
+ val |= (RBR_BUFSZ1_4K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+ case 8 * 1024:
+ val |= (RBR_BUFSZ1_8K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ val |= RBR_CFIG_B_VLD0;
+ switch (rp->rbr_sizes[0]) {
+ case 256:
+ val |= (RBR_BUFSZ0_256 << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+ case 512:
+ val |= (RBR_BUFSZ0_512 << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+ case 1 * 1024:
+ val |= (RBR_BUFSZ0_1K << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+ case 2 * 1024:
+ val |= (RBR_BUFSZ0_2K << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *ret = val;
+ return 0;
+}
+
+static int niu_enable_rx_channel(struct niu *np, int channel, int on)
+{
+ u64 val = nr64(RXDMA_CFIG1(channel));
+ int limit;
+
+ if (on)
+ val |= RXDMA_CFIG1_EN;
+ else
+ val &= ~RXDMA_CFIG1_EN;
+ nw64(RXDMA_CFIG1(channel), val);
+
+ limit = 1000;
+ while (--limit > 0) {
+ if (nr64(RXDMA_CFIG1(channel)) & RXDMA_CFIG1_QST)
+ break;
+ udelay(10);
+ }
+ if (limit <= 0)
+ return -ENODEV;
+ return 0;
+}
+
+static int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+ int err, channel = rp->rx_channel;
+ u64 val;
+
+ err = niu_rx_channel_reset(np, channel);
+ if (err)
+ return err;
+
+ err = niu_rx_channel_lpage_init(np, channel);
+ if (err)
+ return err;
+
+ niu_rx_channel_wred_init(np, rp);
+
+ nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_RBR_EMPTY);
+ nw64(RX_DMA_CTL_STAT(channel),
+ (RX_DMA_CTL_STAT_MEX |
+ RX_DMA_CTL_STAT_RCRTHRES |
+ RX_DMA_CTL_STAT_RCRTO |
+ RX_DMA_CTL_STAT_RBR_EMPTY));
+ nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32);
+ nw64(RXDMA_CFIG2(channel), (rp->mbox_dma & 0x00000000ffffffc0));
+ nw64(RBR_CFIG_A(channel),
+ ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) |
+ (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR)));
+ err = niu_compute_rbr_cfig_b(rp, &val);
+ if (err)
+ return err;
+ nw64(RBR_CFIG_B(channel), val);
+ nw64(RCRCFIG_A(channel),
+ ((u64)rp->rcr_table_size << RCRCFIG_A_LEN_SHIFT) |
+ (rp->rcr_dma & (RCRCFIG_A_STADDR_BASE | RCRCFIG_A_STADDR)));
+ nw64(RCRCFIG_B(channel),
+ ((u64)rp->rcr_pkt_threshold << RCRCFIG_B_PTHRES_SHIFT) |
+ RCRCFIG_B_ENTOUT |
+ ((u64)rp->rcr_timeout << RCRCFIG_B_TIMEOUT_SHIFT));
+
+ err = niu_enable_rx_channel(np, channel, 1);
+ if (err)
+ return err;
+
+ nw64(RBR_KICK(channel), rp->rbr_index);
+
+ val = nr64(RX_DMA_CTL_STAT(channel));
+ val |= RX_DMA_CTL_STAT_RBR_EMPTY;
+ nw64(RX_DMA_CTL_STAT(channel), val);
+
+ return 0;
+}
+
+static int niu_init_rx_channels(struct niu *np)
+{
+ unsigned long flags;
+ u64 seed = jiffies_64;
+ int err, i;
+
+ niu_lock_parent(np, flags);
+ nw64(RX_DMA_CK_DIV, np->parent->rxdma_clock_divider);
+ nw64(RED_RAN_INIT, RED_RAN_INIT_OPMODE | (seed & RED_RAN_INIT_VAL));
+ niu_unlock_parent(np, flags);
+
+ /* XXX RXDMA 32bit mode? XXX */
+
+ niu_init_rdc_groups(np);
+ niu_init_drr_weight(np);
+
+ err = niu_init_hostinfo(np);
+ if (err)
+ return err;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ err = niu_init_one_rx_channel(np, rp);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int niu_set_ip_frag_rule(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_classifier *cp = &np->clas;
+ struct niu_tcam_entry *tp;
+ int index, err;
+
+ /* XXX fix this allocation scheme XXX */
+ index = cp->tcam_index;
+ tp = &parent->tcam[index];
+
+ /* Note that the noport bit is the same in both ipv4 and
+ * ipv6 format TCAM entries.
+ */
+ memset(tp, 0, sizeof(*tp));
+ tp->key[1] = TCAM_V4KEY1_NOPORT;
+ tp->key_mask[1] = TCAM_V4KEY1_NOPORT;
+ tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
+ ((u64)0 << TCAM_ASSOCDATA_OFFSET_SHIFT));
+ err = tcam_write(np, index, tp->key, tp->key_mask);
+ if (err)
+ return err;
+ err = tcam_assoc_write(np, index, tp->assoc_data);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int niu_init_classifier_hw(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_classifier *cp = &np->clas;
+ int i, err;
+
+ nw64(H1POLY, cp->h1_init);
+ nw64(H2POLY, cp->h2_init);
+
+ err = niu_init_hostinfo(np);
+ if (err)
+ return err;
+
+ for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) {
+ struct niu_vlan_rdc *vp = &cp->vlan_mappings[i];
+
+ vlan_tbl_write(np, i, np->port,
+ vp->vlan_pref, vp->rdc_num);
+ }
+
+ for (i = 0; i < cp->num_alt_mac_mappings; i++) {
+ struct niu_altmac_rdc *ap = &cp->alt_mac_mappings[i];
+
+ err = niu_set_alt_mac_rdc_table(np, ap->alt_mac_num,
+ ap->rdc_num, ap->mac_pref);
+ if (err)
+ return err;
+ }
+
+ for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
+ int index = i - CLASS_CODE_USER_PROG1;
+
+ err = niu_set_tcam_key(np, i, parent->tcam_key[index]);
+ if (err)
+ return err;
+ err = niu_set_flow_key(np, i, parent->flow_key[index]);
+ if (err)
+ return err;
+ }
+
+ err = niu_set_ip_frag_rule(np);
+ if (err)
+ return err;
+
+ tcam_enable(np, 1);
+
+ return 0;
+}
+
+static int niu_zcp_write(struct niu *np, int index, u64 *data)
+{
+ nw64(ZCP_RAM_DATA0, data[0]);
+ nw64(ZCP_RAM_DATA1, data[1]);
+ nw64(ZCP_RAM_DATA2, data[2]);
+ nw64(ZCP_RAM_DATA3, data[3]);
+ nw64(ZCP_RAM_DATA4, data[4]);
+ nw64(ZCP_RAM_BE, ZCP_RAM_BE_VAL);
+ nw64(ZCP_RAM_ACC,
+ (ZCP_RAM_ACC_WRITE |
+ (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
+ (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
+
+ return niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+ 1000, 100);
+}
+
+static int niu_zcp_read(struct niu *np, int index, u64 *data)
+{
+ int err;
+
+ err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+ 1000, 100);
+ if (err) {
+ dev_err(np->device, PFX "%s: ZCP read busy won't clear, "
+ "ZCP_RAM_ACC[%llx]\n", np->dev->name,
+ (unsigned long long) nr64(ZCP_RAM_ACC));
+ return err;
+ }
+
+ nw64(ZCP_RAM_ACC,
+ (ZCP_RAM_ACC_READ |
+ (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
+ (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
+
+ err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+ 1000, 100);
+ if (err) {
+ dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, "
+ "ZCP_RAM_ACC[%llx]\n", np->dev->name,
+ (unsigned long long) nr64(ZCP_RAM_ACC));
+ return err;
+ }
+
+ data[0] = nr64(ZCP_RAM_DATA0);
+ data[1] = nr64(ZCP_RAM_DATA1);
+ data[2] = nr64(ZCP_RAM_DATA2);
+ data[3] = nr64(ZCP_RAM_DATA3);
+ data[4] = nr64(ZCP_RAM_DATA4);
+
+ return 0;
+}
+
+static void niu_zcp_cfifo_reset(struct niu *np)
+{
+ u64 val = nr64(RESET_CFIFO);
+
+ val |= RESET_CFIFO_RST(np->port);
+ nw64(RESET_CFIFO, val);
+ udelay(10);
+
+ val &= ~RESET_CFIFO_RST(np->port);
+ nw64(RESET_CFIFO, val);
+}
+
+static int niu_init_zcp(struct niu *np)
+{
+ u64 data[5], rbuf[5];
+ int i, max, err;
+
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ if (np->port == 0 || np->port == 1)
+ max = ATLAS_P0_P1_CFIFO_ENTRIES;
+ else
+ max = ATLAS_P2_P3_CFIFO_ENTRIES;
+ } else
+ max = NIU_CFIFO_ENTRIES;
+
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+
+ for (i = 0; i < max; i++) {
+ err = niu_zcp_write(np, i, data);
+ if (err)
+ return err;
+ err = niu_zcp_read(np, i, rbuf);
+ if (err)
+ return err;
+ }
+
+ niu_zcp_cfifo_reset(np);
+ nw64(CFIFO_ECC(np->port), 0);
+ nw64(ZCP_INT_STAT, ZCP_INT_STAT_ALL);
+ (void) nr64(ZCP_INT_STAT);
+ nw64(ZCP_INT_MASK, ZCP_INT_MASK_ALL);
+
+ return 0;
+}
+
+static void niu_ipp_write(struct niu *np, int index, u64 *data)
+{
+ u64 val = nr64_ipp(IPP_CFIG);
+
+ nw64_ipp(IPP_CFIG, val | IPP_CFIG_DFIFO_PIO_W);
+ nw64_ipp(IPP_DFIFO_WR_PTR, index);
+ nw64_ipp(IPP_DFIFO_WR0, data[0]);
+ nw64_ipp(IPP_DFIFO_WR1, data[1]);
+ nw64_ipp(IPP_DFIFO_WR2, data[2]);
+ nw64_ipp(IPP_DFIFO_WR3, data[3]);
+ nw64_ipp(IPP_DFIFO_WR4, data[4]);
+ nw64_ipp(IPP_CFIG, val & ~IPP_CFIG_DFIFO_PIO_W);
+}
+
+static void niu_ipp_read(struct niu *np, int index, u64 *data)
+{
+ nw64_ipp(IPP_DFIFO_RD_PTR, index);
+ data[0] = nr64_ipp(IPP_DFIFO_RD0);
+ data[1] = nr64_ipp(IPP_DFIFO_RD1);
+ data[2] = nr64_ipp(IPP_DFIFO_RD2);
+ data[3] = nr64_ipp(IPP_DFIFO_RD3);
+ data[4] = nr64_ipp(IPP_DFIFO_RD4);
+}
+
+static int niu_ipp_reset(struct niu *np)
+{
+ return niu_set_and_wait_clear_ipp(np, IPP_CFIG, IPP_CFIG_SOFT_RST,
+ 1000, 100, "IPP_CFIG");
+}
+
+static int niu_init_ipp(struct niu *np)
+{
+ u64 data[5], rbuf[5], val;
+ int i, max, err;
+
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ if (np->port == 0 || np->port == 1)
+ max = ATLAS_P0_P1_DFIFO_ENTRIES;
+ else
+ max = ATLAS_P2_P3_DFIFO_ENTRIES;
+ } else
+ max = NIU_DFIFO_ENTRIES;
+
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+
+ for (i = 0; i < max; i++) {
+ niu_ipp_write(np, i, data);
+ niu_ipp_read(np, i, rbuf);
+ }
+
+ (void) nr64_ipp(IPP_INT_STAT);
+ (void) nr64_ipp(IPP_INT_STAT);
+
+ err = niu_ipp_reset(np);
+ if (err)
+ return err;
+
+ (void) nr64_ipp(IPP_PKT_DIS);
+ (void) nr64_ipp(IPP_BAD_CS_CNT);
+ (void) nr64_ipp(IPP_ECC);
+
+ (void) nr64_ipp(IPP_INT_STAT);
+
+ nw64_ipp(IPP_MSK, ~IPP_MSK_ALL);
+
+ val = nr64_ipp(IPP_CFIG);
+ val &= ~IPP_CFIG_IP_MAX_PKT;
+ val |= (IPP_CFIG_IPP_ENABLE |
+ IPP_CFIG_DFIFO_ECC_EN |
+ IPP_CFIG_DROP_BAD_CRC |
+ IPP_CFIG_CKSUM_EN |
+ (0x1ffff << IPP_CFIG_IP_MAX_PKT_SHIFT));
+ nw64_ipp(IPP_CFIG, val);
+
+ return 0;
+}
+
+static void niu_init_xif_xmac(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u64 val;
+
+ val = nr64_mac(XMAC_CONFIG);
+
+ if ((np->flags & NIU_FLAGS_10G) != 0 &&
+ (np->flags & NIU_FLAGS_FIBER) != 0) {
+ if (netif_carrier_ok(np->dev)) {
+ val |= XMAC_CONFIG_LED_POLARITY;
+ val &= ~XMAC_CONFIG_FORCE_LED_ON;
+ } else {
+ val |= XMAC_CONFIG_FORCE_LED_ON;
+ val &= ~XMAC_CONFIG_LED_POLARITY;
+ }
+ }
+
+ val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
+
+ val |= XMAC_CONFIG_TX_OUTPUT_EN;
+
+ if (lp->loopback_mode == LOOPBACK_MAC) {
+ val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
+ val |= XMAC_CONFIG_LOOPBACK;
+ } else {
+ val &= ~XMAC_CONFIG_LOOPBACK;
+ }
+
+ if (np->flags & NIU_FLAGS_10G) {
+ val &= ~XMAC_CONFIG_LFS_DISABLE;
+ } else {
+ val |= XMAC_CONFIG_LFS_DISABLE;
+ if (!(np->flags & NIU_FLAGS_FIBER))
+ val |= XMAC_CONFIG_1G_PCS_BYPASS;
+ else
+ val &= ~XMAC_CONFIG_1G_PCS_BYPASS;
+ }
+
+ val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
+
+ if (lp->active_speed == SPEED_100)
+ val |= XMAC_CONFIG_SEL_CLK_25MHZ;
+ else
+ val &= ~XMAC_CONFIG_SEL_CLK_25MHZ;
+
+ nw64_mac(XMAC_CONFIG, val);
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_MODE_MASK;
+ if (np->flags & NIU_FLAGS_10G) {
+ val |= XMAC_CONFIG_MODE_XGMII;
+ } else {
+ if (lp->active_speed == SPEED_100)
+ val |= XMAC_CONFIG_MODE_MII;
+ else
+ val |= XMAC_CONFIG_MODE_GMII;
+ }
+
+ nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_init_xif_bmac(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u64 val;
+
+ val = BMAC_XIF_CONFIG_TX_OUTPUT_EN;
+
+ if (lp->loopback_mode == LOOPBACK_MAC)
+ val |= BMAC_XIF_CONFIG_MII_LOOPBACK;
+ else
+ val &= ~BMAC_XIF_CONFIG_MII_LOOPBACK;
+
+ if (lp->active_speed == SPEED_1000)
+ val |= BMAC_XIF_CONFIG_GMII_MODE;
+ else
+ val &= ~BMAC_XIF_CONFIG_GMII_MODE;
+
+ val &= ~(BMAC_XIF_CONFIG_LINK_LED |
+ BMAC_XIF_CONFIG_LED_POLARITY);
+
+ if (!(np->flags & NIU_FLAGS_10G) &&
+ !(np->flags & NIU_FLAGS_FIBER) &&
+ lp->active_speed == SPEED_100)
+ val |= BMAC_XIF_CONFIG_25MHZ_CLOCK;
+ else
+ val &= ~BMAC_XIF_CONFIG_25MHZ_CLOCK;
+
+ nw64_mac(BMAC_XIF_CONFIG, val);
+}
+
+static void niu_init_xif(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_init_xif_xmac(np);
+ else
+ niu_init_xif_bmac(np);
+}
+
+static void niu_pcs_mii_reset(struct niu *np)
+{
+ u64 val = nr64_pcs(PCS_MII_CTL);
+ val |= PCS_MII_CTL_RST;
+ nw64_pcs(PCS_MII_CTL, val);
+}
+
+static void niu_xpcs_reset(struct niu *np)
+{
+ u64 val = nr64_xpcs(XPCS_CONTROL1);
+ val |= XPCS_CONTROL1_RESET;
+ nw64_xpcs(XPCS_CONTROL1, val);
+}
+
+static int niu_init_pcs(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u64 val;
+
+ switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+ case NIU_FLAGS_FIBER:
+ /* 1G fiber */
+ nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
+ nw64_pcs(PCS_DPATH_MODE, 0);
+ niu_pcs_mii_reset(np);
+ break;
+
+ case NIU_FLAGS_10G:
+ case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+ if (!(np->flags & NIU_FLAGS_XMAC))
+ return -EINVAL;
+
+ /* 10G copper or fiber */
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
+ nw64_mac(XMAC_CONFIG, val);
+
+ niu_xpcs_reset(np);
+
+ val = nr64_xpcs(XPCS_CONTROL1);
+ if (lp->loopback_mode == LOOPBACK_PHY)
+ val |= XPCS_CONTROL1_LOOPBACK;
+ else
+ val &= ~XPCS_CONTROL1_LOOPBACK;
+ nw64_xpcs(XPCS_CONTROL1, val);
+
+ nw64_xpcs(XPCS_DESKEW_ERR_CNT, 0);
+ (void) nr64_xpcs(XPCS_SYMERR_CNT01);
+ (void) nr64_xpcs(XPCS_SYMERR_CNT23);
+ break;
+
+ case 0:
+ /* 1G copper */
+ nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII);
+ niu_pcs_mii_reset(np);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int niu_reset_tx_xmac(struct niu *np)
+{
+ return niu_set_and_wait_clear_mac(np, XTXMAC_SW_RST,
+ (XTXMAC_SW_RST_REG_RS |
+ XTXMAC_SW_RST_SOFT_RST),
+ 1000, 100, "XTXMAC_SW_RST");
+}
+
+static int niu_reset_tx_bmac(struct niu *np)
+{
+ int limit;
+
+ nw64_mac(BTXMAC_SW_RST, BTXMAC_SW_RST_RESET);
+ limit = 1000;
+ while (--limit >= 0) {
+ if (!(nr64_mac(BTXMAC_SW_RST) & BTXMAC_SW_RST_RESET))
+ break;
+ udelay(100);
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u TX BMAC would not reset, "
+ "BTXMAC_SW_RST[%llx]\n",
+ np->port,
+ (unsigned long long) nr64_mac(BTXMAC_SW_RST));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int niu_reset_tx_mac(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return niu_reset_tx_xmac(np);
+ else
+ return niu_reset_tx_bmac(np);
+}
+
+static void niu_init_tx_xmac(struct niu *np, u64 min, u64 max)
+{
+ u64 val;
+
+ val = nr64_mac(XMAC_MIN);
+ val &= ~(XMAC_MIN_TX_MIN_PKT_SIZE |
+ XMAC_MIN_RX_MIN_PKT_SIZE);
+ val |= (min << XMAC_MIN_RX_MIN_PKT_SIZE_SHFT);
+ val |= (min << XMAC_MIN_TX_MIN_PKT_SIZE_SHFT);
+ nw64_mac(XMAC_MIN, val);
+
+ nw64_mac(XMAC_MAX, max);
+
+ nw64_mac(XTXMAC_STAT_MSK, ~(u64)0);
+
+ val = nr64_mac(XMAC_IPG);
+ if (np->flags & NIU_FLAGS_10G) {
+ val &= ~XMAC_IPG_IPG_XGMII;
+ val |= (IPG_12_15_XGMII << XMAC_IPG_IPG_XGMII_SHIFT);
+ } else {
+ val &= ~XMAC_IPG_IPG_MII_GMII;
+ val |= (IPG_12_MII_GMII << XMAC_IPG_IPG_MII_GMII_SHIFT);
+ }
+ nw64_mac(XMAC_IPG, val);
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~(XMAC_CONFIG_ALWAYS_NO_CRC |
+ XMAC_CONFIG_STRETCH_MODE |
+ XMAC_CONFIG_VAR_MIN_IPG_EN |
+ XMAC_CONFIG_TX_ENABLE);
+ nw64_mac(XMAC_CONFIG, val);
+
+ nw64_mac(TXMAC_FRM_CNT, 0);
+ nw64_mac(TXMAC_BYTE_CNT, 0);
+}
+
+static void niu_init_tx_bmac(struct niu *np, u64 min, u64 max)
+{
+ u64 val;
+
+ nw64_mac(BMAC_MIN_FRAME, min);
+ nw64_mac(BMAC_MAX_FRAME, max);
+
+ nw64_mac(BTXMAC_STATUS_MASK, ~(u64)0);
+ nw64_mac(BMAC_CTRL_TYPE, 0x8808);
+ nw64_mac(BMAC_PREAMBLE_SIZE, 7);
+
+ val = nr64_mac(BTXMAC_CONFIG);
+ val &= ~(BTXMAC_CONFIG_FCS_DISABLE |
+ BTXMAC_CONFIG_ENABLE);
+ nw64_mac(BTXMAC_CONFIG, val);
+}
+
+static void niu_init_tx_mac(struct niu *np)
+{
+ u64 min, max;
+
+ min = 64;
+ if (np->dev->mtu > ETH_DATA_LEN)
+ max = 9216;
+ else
+ max = 1522;
+
+ /* The XMAC_MIN register only accepts values for TX min which
+ * have the low 3 bits cleared.
+ */
+ BUILD_BUG_ON(min & 0x7);
+
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_init_tx_xmac(np, min, max);
+ else
+ niu_init_tx_bmac(np, min, max);
+}
+
+static int niu_reset_rx_xmac(struct niu *np)
+{
+ int limit;
+
+ nw64_mac(XRXMAC_SW_RST,
+ XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST);
+ limit = 1000;
+ while (--limit >= 0) {
+ if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS |
+ XRXMAC_SW_RST_SOFT_RST)))
+ break;
+ udelay(100);
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u RX XMAC would not reset, "
+ "XRXMAC_SW_RST[%llx]\n",
+ np->port,
+ (unsigned long long) nr64_mac(XRXMAC_SW_RST));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int niu_reset_rx_bmac(struct niu *np)
+{
+ int limit;
+
+ nw64_mac(BRXMAC_SW_RST, BRXMAC_SW_RST_RESET);
+ limit = 1000;
+ while (--limit >= 0) {
+ if (!(nr64_mac(BRXMAC_SW_RST) & BRXMAC_SW_RST_RESET))
+ break;
+ udelay(100);
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u RX BMAC would not reset, "
+ "BRXMAC_SW_RST[%llx]\n",
+ np->port,
+ (unsigned long long) nr64_mac(BRXMAC_SW_RST));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int niu_reset_rx_mac(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return niu_reset_rx_xmac(np);
+ else
+ return niu_reset_rx_bmac(np);
+}
+
+static void niu_init_rx_xmac(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+ int first_rdc_table = tp->first_table_num;
+ unsigned long i;
+ u64 val;
+
+ nw64_mac(XMAC_ADD_FILT0, 0);
+ nw64_mac(XMAC_ADD_FILT1, 0);
+ nw64_mac(XMAC_ADD_FILT2, 0);
+ nw64_mac(XMAC_ADD_FILT12_MASK, 0);
+ nw64_mac(XMAC_ADD_FILT00_MASK, 0);
+ for (i = 0; i < MAC_NUM_HASH; i++)
+ nw64_mac(XMAC_HASH_TBL(i), 0);
+ nw64_mac(XRXMAC_STAT_MSK, ~(u64)0);
+ niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+ niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~(XMAC_CONFIG_RX_MAC_ENABLE |
+ XMAC_CONFIG_PROMISCUOUS |
+ XMAC_CONFIG_PROMISC_GROUP |
+ XMAC_CONFIG_ERR_CHK_DIS |
+ XMAC_CONFIG_RX_CRC_CHK_DIS |
+ XMAC_CONFIG_RESERVED_MULTICAST |
+ XMAC_CONFIG_RX_CODEV_CHK_DIS |
+ XMAC_CONFIG_ADDR_FILTER_EN |
+ XMAC_CONFIG_RCV_PAUSE_ENABLE |
+ XMAC_CONFIG_STRIP_CRC |
+ XMAC_CONFIG_PASS_FLOW_CTRL |
+ XMAC_CONFIG_MAC2IPP_PKT_CNT_EN);
+ val |= (XMAC_CONFIG_HASH_FILTER_EN);
+ nw64_mac(XMAC_CONFIG, val);
+
+ nw64_mac(RXMAC_BT_CNT, 0);
+ nw64_mac(RXMAC_BC_FRM_CNT, 0);
+ nw64_mac(RXMAC_MC_FRM_CNT, 0);
+ nw64_mac(RXMAC_FRAG_CNT, 0);
+ nw64_mac(RXMAC_HIST_CNT1, 0);
+ nw64_mac(RXMAC_HIST_CNT2, 0);
+ nw64_mac(RXMAC_HIST_CNT3, 0);
+ nw64_mac(RXMAC_HIST_CNT4, 0);
+ nw64_mac(RXMAC_HIST_CNT5, 0);
+ nw64_mac(RXMAC_HIST_CNT6, 0);
+ nw64_mac(RXMAC_HIST_CNT7, 0);
+ nw64_mac(RXMAC_MPSZER_CNT, 0);
+ nw64_mac(RXMAC_CRC_ER_CNT, 0);
+ nw64_mac(RXMAC_CD_VIO_CNT, 0);
+ nw64_mac(LINK_FAULT_CNT, 0);
+}
+
+static void niu_init_rx_bmac(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+ int first_rdc_table = tp->first_table_num;
+ unsigned long i;
+ u64 val;
+
+ nw64_mac(BMAC_ADD_FILT0, 0);
+ nw64_mac(BMAC_ADD_FILT1, 0);
+ nw64_mac(BMAC_ADD_FILT2, 0);
+ nw64_mac(BMAC_ADD_FILT12_MASK, 0);
+ nw64_mac(BMAC_ADD_FILT00_MASK, 0);
+ for (i = 0; i < MAC_NUM_HASH; i++)
+ nw64_mac(BMAC_HASH_TBL(i), 0);
+ niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+ niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+ nw64_mac(BRXMAC_STATUS_MASK, ~(u64)0);
+
+ val = nr64_mac(BRXMAC_CONFIG);
+ val &= ~(BRXMAC_CONFIG_ENABLE |
+ BRXMAC_CONFIG_STRIP_PAD |
+ BRXMAC_CONFIG_STRIP_FCS |
+ BRXMAC_CONFIG_PROMISC |
+ BRXMAC_CONFIG_PROMISC_GRP |
+ BRXMAC_CONFIG_ADDR_FILT_EN |
+ BRXMAC_CONFIG_DISCARD_DIS);
+ val |= (BRXMAC_CONFIG_HASH_FILT_EN);
+ nw64_mac(BRXMAC_CONFIG, val);
+
+ val = nr64_mac(BMAC_ADDR_CMPEN);
+ val |= BMAC_ADDR_CMPEN_EN0;
+ nw64_mac(BMAC_ADDR_CMPEN, val);
+}
+
+static void niu_init_rx_mac(struct niu *np)
+{
+ niu_set_primary_mac(np, np->dev->dev_addr);
+
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_init_rx_xmac(np);
+ else
+ niu_init_rx_bmac(np);
+}
+
+static void niu_enable_tx_xmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(XMAC_CONFIG);
+
+ if (on)
+ val |= XMAC_CONFIG_TX_ENABLE;
+ else
+ val &= ~XMAC_CONFIG_TX_ENABLE;
+ nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_enable_tx_bmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(BTXMAC_CONFIG);
+
+ if (on)
+ val |= BTXMAC_CONFIG_ENABLE;
+ else
+ val &= ~BTXMAC_CONFIG_ENABLE;
+ nw64_mac(BTXMAC_CONFIG, val);
+}
+
+static void niu_enable_tx_mac(struct niu *np, int on)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_enable_tx_xmac(np, on);
+ else
+ niu_enable_tx_bmac(np, on);
+}
+
+static void niu_enable_rx_xmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(XMAC_CONFIG);
+
+ val &= ~(XMAC_CONFIG_HASH_FILTER_EN |
+ XMAC_CONFIG_PROMISCUOUS);
+
+ if (np->flags & NIU_FLAGS_MCAST)
+ val |= XMAC_CONFIG_HASH_FILTER_EN;
+ if (np->flags & NIU_FLAGS_PROMISC)
+ val |= XMAC_CONFIG_PROMISCUOUS;
+
+ if (on)
+ val |= XMAC_CONFIG_RX_MAC_ENABLE;
+ else
+ val &= ~XMAC_CONFIG_RX_MAC_ENABLE;
+ nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_enable_rx_bmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(BRXMAC_CONFIG);
+
+ val &= ~(BRXMAC_CONFIG_HASH_FILT_EN |
+ BRXMAC_CONFIG_PROMISC);
+
+ if (np->flags & NIU_FLAGS_MCAST)
+ val |= BRXMAC_CONFIG_HASH_FILT_EN;
+ if (np->flags & NIU_FLAGS_PROMISC)
+ val |= BRXMAC_CONFIG_PROMISC;
+
+ if (on)
+ val |= BRXMAC_CONFIG_ENABLE;
+ else
+ val &= ~BRXMAC_CONFIG_ENABLE;
+ nw64_mac(BRXMAC_CONFIG, val);
+}
+
+static void niu_enable_rx_mac(struct niu *np, int on)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_enable_rx_xmac(np, on);
+ else
+ niu_enable_rx_bmac(np, on);
+}
+
+static int niu_init_mac(struct niu *np)
+{
+ int err;
+
+ niu_init_xif(np);
+ err = niu_init_pcs(np);
+ if (err)
+ return err;
+
+ err = niu_reset_tx_mac(np);
+ if (err)
+ return err;
+ niu_init_tx_mac(np);
+ err = niu_reset_rx_mac(np);
+ if (err)
+ return err;
+ niu_init_rx_mac(np);
+
+ /* This looks hookey but the RX MAC reset we just did will
+ * undo some of the state we setup in niu_init_tx_mac() so we
+ * have to call it again. In particular, the RX MAC reset will
+ * set the XMAC_MAX register back to it's default value.
+ */
+ niu_init_tx_mac(np);
+ niu_enable_tx_mac(np, 1);
+
+ niu_enable_rx_mac(np, 1);
+
+ return 0;
+}
+
+static void niu_stop_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+ (void) niu_tx_channel_stop(np, rp->tx_channel);
+}
+
+static void niu_stop_tx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ niu_stop_one_tx_channel(np, rp);
+ }
+}
+
+static void niu_reset_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+ (void) niu_tx_channel_reset(np, rp->tx_channel);
+}
+
+static void niu_reset_tx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ niu_reset_one_tx_channel(np, rp);
+ }
+}
+
+static void niu_stop_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+ (void) niu_enable_rx_channel(np, rp->rx_channel, 0);
+}
+
+static void niu_stop_rx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ niu_stop_one_rx_channel(np, rp);
+ }
+}
+
+static void niu_reset_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+ int channel = rp->rx_channel;
+
+ (void) niu_rx_channel_reset(np, channel);
+ nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_ALL);
+ nw64(RX_DMA_CTL_STAT(channel), 0);
+ (void) niu_enable_rx_channel(np, channel, 0);
+}
+
+static void niu_reset_rx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ niu_reset_one_rx_channel(np, rp);
+ }
+}
+
+static void niu_disable_ipp(struct niu *np)
+{
+ u64 rd, wr, val;
+ int limit;
+
+ rd = nr64_ipp(IPP_DFIFO_RD_PTR);
+ wr = nr64_ipp(IPP_DFIFO_WR_PTR);
+ limit = 100;
+ while (--limit >= 0 && (rd != wr)) {
+ rd = nr64_ipp(IPP_DFIFO_RD_PTR);
+ wr = nr64_ipp(IPP_DFIFO_WR_PTR);
+ }
+ if (limit < 0 &&
+ (rd != 0 && wr != 1)) {
+ dev_err(np->device, PFX "%s: IPP would not quiesce, "
+ "rd_ptr[%llx] wr_ptr[%llx]\n",
+ np->dev->name,
+ (unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR),
+ (unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR));
+ }
+
+ val = nr64_ipp(IPP_CFIG);
+ val &= ~(IPP_CFIG_IPP_ENABLE |
+ IPP_CFIG_DFIFO_ECC_EN |
+ IPP_CFIG_DROP_BAD_CRC |
+ IPP_CFIG_CKSUM_EN);
+ nw64_ipp(IPP_CFIG, val);
+
+ (void) niu_ipp_reset(np);
+}
+
+static int niu_init_hw(struct niu *np)
+{
+ int i, err;
+
+ niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name);
+ niu_txc_enable_port(np, 1);
+ niu_txc_port_dma_enable(np, 1);
+ niu_txc_set_imask(np, 0);
+
+ niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name);
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ err = niu_init_one_tx_channel(np, rp);
+ if (err)
+ return err;
+ }
+
+ niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name);
+ err = niu_init_rx_channels(np);
+ if (err)
+ goto out_uninit_tx_channels;
+
+ niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name);
+ err = niu_init_classifier_hw(np);
+ if (err)
+ goto out_uninit_rx_channels;
+
+ niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name);
+ err = niu_init_zcp(np);
+ if (err)
+ goto out_uninit_rx_channels;
+
+ niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name);
+ err = niu_init_ipp(np);
+ if (err)
+ goto out_uninit_rx_channels;
+
+ niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name);
+ err = niu_init_mac(np);
+ if (err)
+ goto out_uninit_ipp;
+
+ return 0;
+
+out_uninit_ipp:
+ niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name);
+ niu_disable_ipp(np);
+
+out_uninit_rx_channels:
+ niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name);
+ niu_stop_rx_channels(np);
+ niu_reset_rx_channels(np);
+
+out_uninit_tx_channels:
+ niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name);
+ niu_stop_tx_channels(np);
+ niu_reset_tx_channels(np);
+
+ return err;
+}
+
+static void niu_stop_hw(struct niu *np)
+{
+ niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name);
+ niu_enable_interrupts(np, 0);
+
+ niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name);
+ niu_enable_rx_mac(np, 0);
+
+ niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name);
+ niu_disable_ipp(np);
+
+ niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name);
+ niu_stop_tx_channels(np);
+
+ niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name);
+ niu_stop_rx_channels(np);
+
+ niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name);
+ niu_reset_tx_channels(np);
+
+ niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name);
+ niu_reset_rx_channels(np);
+}
+
+static int niu_request_irq(struct niu *np)
+{
+ int i, j, err;
+
+ err = 0;
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+
+ err = request_irq(lp->irq, niu_interrupt,
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ np->dev->name, lp);
+ if (err)
+ goto out_free_irqs;
+
+ }
+
+ return 0;
+
+out_free_irqs:
+ for (j = 0; j < i; j++) {
+ struct niu_ldg *lp = &np->ldg[j];
+
+ free_irq(lp->irq, lp);
+ }
+ return err;
+}
+
+static void niu_free_irq(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+
+ free_irq(lp->irq, lp);
+ }
+}
+
+static void niu_enable_napi(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++)
+ napi_enable(&np->ldg[i].napi);
+}
+
+static void niu_disable_napi(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++)
+ napi_disable(&np->ldg[i].napi);
+}
+
+static int niu_open(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ int err;
+
+ netif_carrier_off(dev);
+
+ err = niu_alloc_channels(np);
+ if (err)
+ goto out_err;
+
+ err = niu_enable_interrupts(np, 0);
+ if (err)
+ goto out_free_channels;
+
+ err = niu_request_irq(np);
+ if (err)
+ goto out_free_channels;
+
+ niu_enable_napi(np);
+
+ spin_lock_irq(&np->lock);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ init_timer(&np->timer);
+ np->timer.expires = jiffies + HZ;
+ np->timer.data = (unsigned long) np;
+ np->timer.function = niu_timer;
+
+ err = niu_enable_interrupts(np, 1);
+ if (err)
+ niu_stop_hw(np);
+ }
+
+ spin_unlock_irq(&np->lock);
+
+ if (err) {
+ niu_disable_napi(np);
+ goto out_free_irq;
+ }
+
+ netif_start_queue(dev);
+
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ netif_carrier_on(dev);
+
+ add_timer(&np->timer);
+
+ return 0;
+
+out_free_irq:
+ niu_free_irq(np);
+
+out_free_channels:
+ niu_free_channels(np);
+
+out_err:
+ return err;
+}
+
+static void niu_full_shutdown(struct niu *np, struct net_device *dev)
+{
+ cancel_work_sync(&np->reset_task);
+
+ niu_disable_napi(np);
+ netif_stop_queue(dev);
+
+ del_timer_sync(&np->timer);
+
+ spin_lock_irq(&np->lock);
+
+ niu_stop_hw(np);
+
+ spin_unlock_irq(&np->lock);
+}
+
+static int niu_close(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ niu_full_shutdown(np, dev);
+
+ niu_free_irq(np);
+
+ niu_free_channels(np);
+
+ return 0;
+}
+
+static void niu_sync_xmac_stats(struct niu *np)
+{
+ struct niu_xmac_stats *mp = &np->mac_stats.xmac;
+
+ mp->tx_frames += nr64_mac(TXMAC_FRM_CNT);
+ mp->tx_bytes += nr64_mac(TXMAC_BYTE_CNT);
+
+ mp->rx_link_faults += nr64_mac(LINK_FAULT_CNT);
+ mp->rx_align_errors += nr64_mac(RXMAC_ALIGN_ERR_CNT);
+ mp->rx_frags += nr64_mac(RXMAC_FRAG_CNT);
+ mp->rx_mcasts += nr64_mac(RXMAC_MC_FRM_CNT);
+ mp->rx_bcasts += nr64_mac(RXMAC_BC_FRM_CNT);
+ mp->rx_hist_cnt1 += nr64_mac(RXMAC_HIST_CNT1);
+ mp->rx_hist_cnt2 += nr64_mac(RXMAC_HIST_CNT2);
+ mp->rx_hist_cnt3 += nr64_mac(RXMAC_HIST_CNT3);
+ mp->rx_hist_cnt4 += nr64_mac(RXMAC_HIST_CNT4);
+ mp->rx_hist_cnt5 += nr64_mac(RXMAC_HIST_CNT5);
+ mp->rx_hist_cnt6 += nr64_mac(RXMAC_HIST_CNT6);
+ mp->rx_hist_cnt7 += nr64_mac(RXMAC_HIST_CNT7);
+ mp->rx_octets += nr64_mac(RXMAC_BT_CNT);
+ mp->rx_code_violations += nr64_mac(RXMAC_CD_VIO_CNT);
+ mp->rx_len_errors += nr64_mac(RXMAC_MPSZER_CNT);
+ mp->rx_crc_errors += nr64_mac(RXMAC_CRC_ER_CNT);
+}
+
+static void niu_sync_bmac_stats(struct niu *np)
+{
+ struct niu_bmac_stats *mp = &np->mac_stats.bmac;
+
+ mp->tx_bytes += nr64_mac(BTXMAC_BYTE_CNT);
+ mp->tx_frames += nr64_mac(BTXMAC_FRM_CNT);
+
+ mp->rx_frames += nr64_mac(BRXMAC_FRAME_CNT);
+ mp->rx_align_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
+ mp->rx_crc_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
+ mp->rx_len_errors += nr64_mac(BRXMAC_CODE_VIOL_ERR_CNT);
+}
+
+static void niu_sync_mac_stats(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_sync_xmac_stats(np);
+ else
+ niu_sync_bmac_stats(np);
+}
+
+static void niu_get_rx_stats(struct niu *np)
+{
+ unsigned long pkts, dropped, errors, bytes;
+ int i;
+
+ pkts = dropped = errors = bytes = 0;
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ pkts += rp->rx_packets;
+ bytes += rp->rx_bytes;
+ dropped += rp->rx_dropped;
+ errors += rp->rx_errors;
+ }
+ np->net_stats.rx_packets = pkts;
+ np->net_stats.rx_bytes = bytes;
+ np->net_stats.rx_dropped = dropped;
+ np->net_stats.rx_errors = errors;
+}
+
+static void niu_get_tx_stats(struct niu *np)
+{
+ unsigned long pkts, errors, bytes;
+ int i;
+
+ pkts = errors = bytes = 0;
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ pkts += rp->tx_packets;
+ bytes += rp->tx_bytes;
+ errors += rp->tx_errors;
+ }
+ np->net_stats.tx_packets = pkts;
+ np->net_stats.tx_bytes = bytes;
+ np->net_stats.tx_errors = errors;
+}
+
+static struct net_device_stats *niu_get_stats(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ niu_get_rx_stats(np);
+ niu_get_tx_stats(np);
+
+ return &np->net_stats;
+}
+
+static void niu_load_hash_xmac(struct niu *np, u16 *hash)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ nw64_mac(XMAC_HASH_TBL(i), hash[i]);
+}
+
+static void niu_load_hash_bmac(struct niu *np, u16 *hash)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ nw64_mac(BMAC_HASH_TBL(i), hash[i]);
+}
+
+static void niu_load_hash(struct niu *np, u16 *hash)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_load_hash_xmac(np, hash);
+ else
+ niu_load_hash_bmac(np, hash);
+}
+
+static void niu_set_rx_mode(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ int i, alt_cnt, err;
+ struct dev_addr_list *addr;
+ unsigned long flags;
+ u16 hash[16] = { 0, };
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_enable_rx_mac(np, 0);
+
+ np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC);
+ if (dev->flags & IFF_PROMISC)
+ np->flags |= NIU_FLAGS_PROMISC;
+ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0))
+ np->flags |= NIU_FLAGS_MCAST;
+
+ alt_cnt = dev->uc_count;
+ if (alt_cnt > niu_num_alt_addr(np)) {
+ alt_cnt = 0;
+ np->flags |= NIU_FLAGS_PROMISC;
+ }
+
+ if (alt_cnt) {
+ int index = 0;
+
+ for (addr = dev->uc_list; addr; addr = addr->next) {
+ err = niu_set_alt_mac(np, index,
+ addr->da_addr);
+ if (err)
+ printk(KERN_WARNING PFX "%s: Error %d "
+ "adding alt mac %d\n",
+ dev->name, err, index);
+ err = niu_enable_alt_mac(np, index, 1);
+ if (err)
+ printk(KERN_WARNING PFX "%s: Error %d "
+ "enabling alt mac %d\n",
+ dev->name, err, index);
+
+ index++;
+ }
+ } else {
+ for (i = 0; i < niu_num_alt_addr(np); i++) {
+ err = niu_enable_alt_mac(np, i, 0);
+ if (err)
+ printk(KERN_WARNING PFX "%s: Error %d "
+ "disabling alt mac %d\n",
+ dev->name, err, i);
+ }
+ }
+ if (dev->flags & IFF_ALLMULTI) {
+ for (i = 0; i < 16; i++)
+ hash[i] = 0xffff;
+ } else if (dev->mc_count > 0) {
+ for (addr = dev->mc_list; addr; addr = addr->next) {
+ u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr);
+
+ crc >>= 24;
+ hash[crc >> 4] |= (1 << (15 - (crc & 0xf)));
+ }
+ }
+
+ if (np->flags & NIU_FLAGS_MCAST)
+ niu_load_hash(np, hash);
+
+ niu_enable_rx_mac(np, 1);
+ spin_unlock_irqrestore(&np->lock, flags);
+}
+
+static int niu_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct niu *np = netdev_priv(dev);
+ struct sockaddr *addr = p;
+ unsigned long flags;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+ if (!netif_running(dev))
+ return 0;
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_enable_rx_mac(np, 0);
+ niu_set_primary_mac(np, dev->dev_addr);
+ niu_enable_rx_mac(np, 1);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return 0;
+}
+
+static int niu_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+static void niu_netif_stop(struct niu *np)
+{
+ np->dev->trans_start = jiffies; /* prevent tx timeout */
+
+ niu_disable_napi(np);
+
+ netif_tx_disable(np->dev);
+}
+
+static void niu_netif_start(struct niu *np)
+{
+ /* NOTE: unconditional netif_wake_queue is only appropriate
+ * so long as all callers are assured to have free tx slots
+ * (such as after niu_init_hw).
+ */
+ netif_wake_queue(np->dev);
+
+ niu_enable_napi(np);
+
+ niu_enable_interrupts(np, 1);
+}
+
+static void niu_reset_task(struct work_struct *work)
+{
+ struct niu *np = container_of(work, struct niu, reset_task);
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&np->lock, flags);
+ if (!netif_running(np->dev)) {
+ spin_unlock_irqrestore(&np->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ del_timer_sync(&np->timer);
+
+ niu_netif_stop(np);
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ niu_stop_hw(np);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ np->timer.expires = jiffies + HZ;
+ add_timer(&np->timer);
+ niu_netif_start(np);
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+}
+
+static void niu_tx_timeout(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ dev_err(np->device, PFX "%s: Transmit timed out, resetting\n",
+ dev->name);
+
+ schedule_work(&np->reset_task);
+}
+
+static void niu_set_txd(struct tx_ring_info *rp, int index,
+ u64 mapping, u64 len, u64 mark,
+ u64 n_frags)
+{
+ __le64 *desc = &rp->descr[index];
+
+ *desc = cpu_to_le64(mark |
+ (n_frags << TX_DESC_NUM_PTR_SHIFT) |
+ (len << TX_DESC_TR_LEN_SHIFT) |
+ (mapping & TX_DESC_SAD));
+}
+
+static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr,
+ u64 pad_bytes, u64 len)
+{
+ u16 eth_proto, eth_proto_inner;
+ u64 csum_bits, l3off, ihl, ret;
+ u8 ip_proto;
+ int ipv6;
+
+ eth_proto = be16_to_cpu(ehdr->h_proto);
+ eth_proto_inner = eth_proto;
+ if (eth_proto == ETH_P_8021Q) {
+ struct vlan_ethhdr *vp = (struct vlan_ethhdr *) ehdr;
+ __be16 val = vp->h_vlan_encapsulated_proto;
+
+ eth_proto_inner = be16_to_cpu(val);
+ }
+
+ ipv6 = ihl = 0;
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ ip_proto = ip_hdr(skb)->protocol;
+ ihl = ip_hdr(skb)->ihl;
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ ip_proto = ipv6_hdr(skb)->nexthdr;
+ ihl = (40 >> 2);
+ ipv6 = 1;
+ break;
+ default:
+ ip_proto = ihl = 0;
+ break;
+ }
+
+ csum_bits = TXHDR_CSUM_NONE;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u64 start, stuff;
+
+ csum_bits = (ip_proto == IPPROTO_TCP ?
+ TXHDR_CSUM_TCP :
+ (ip_proto == IPPROTO_UDP ?
+ TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP));
+
+ start = skb_transport_offset(skb) -
+ (pad_bytes + sizeof(struct tx_pkt_hdr));
+ stuff = start + skb->csum_offset;
+
+ csum_bits |= (start / 2) << TXHDR_L4START_SHIFT;
+ csum_bits |= (stuff / 2) << TXHDR_L4STUFF_SHIFT;
+ }
+
+ l3off = skb_network_offset(skb) -
+ (pad_bytes + sizeof(struct tx_pkt_hdr));
+
+ ret = (((pad_bytes / 2) << TXHDR_PAD_SHIFT) |
+ (len << TXHDR_LEN_SHIFT) |
+ ((l3off / 2) << TXHDR_L3START_SHIFT) |
+ (ihl << TXHDR_IHL_SHIFT) |
+ ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) |
+ ((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) |
+ (ipv6 ? TXHDR_IP_VER : 0) |
+ csum_bits);
+
+ return ret;
+}
+
+static struct tx_ring_info *tx_ring_select(struct niu *np, struct sk_buff *skb)
+{
+ return &np->tx_rings[0];
+}
+
+static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ unsigned long align, headroom;
+ struct tx_ring_info *rp;
+ struct tx_pkt_hdr *tp;
+ unsigned int len, nfg;
+ struct ethhdr *ehdr;
+ int prod, i, tlen;
+ u64 mapping, mrk;
+
+ rp = tx_ring_select(np, skb);
+
+ if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+ netif_stop_queue(dev);
+ dev_err(np->device, PFX "%s: BUG! Tx ring full when "
+ "queue awake!\n", dev->name);
+ rp->tx_errors++;
+ return NETDEV_TX_BUSY;
+ }
+
+ if (skb->len < ETH_ZLEN) {
+ unsigned int pad_bytes = ETH_ZLEN - skb->len;
+
+ if (skb_pad(skb, pad_bytes))
+ goto out;
+ skb_put(skb, pad_bytes);
+ }
+
+ len = sizeof(struct tx_pkt_hdr) + 15;
+ if (skb_headroom(skb) < len) {
+ struct sk_buff *skb_new;
+
+ skb_new = skb_realloc_headroom(skb, len);
+ if (!skb_new) {
+ rp->tx_errors++;
+ goto out_drop;
+ }
+ kfree_skb(skb);
+ skb = skb_new;
+ }
+
+ align = ((unsigned long) skb->data & (16 - 1));
+ headroom = align + sizeof(struct tx_pkt_hdr);
+
+ ehdr = (struct ethhdr *) skb->data;
+ tp = (struct tx_pkt_hdr *) skb_push(skb, headroom);
+
+ len = skb->len - sizeof(struct tx_pkt_hdr);
+ tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len));
+ tp->resv = 0;
+
+ len = skb_headlen(skb);
+ mapping = np->ops->map_single(np->device, skb->data,
+ len, DMA_TO_DEVICE);
+
+ prod = rp->prod;
+
+ rp->tx_buffs[prod].skb = skb;
+ rp->tx_buffs[prod].mapping = mapping;
+
+ mrk = TX_DESC_SOP;
+ if (++rp->mark_counter == rp->mark_freq) {
+ rp->mark_counter = 0;
+ mrk |= TX_DESC_MARK;
+ rp->mark_pending++;
+ }
+
+ tlen = len;
+ nfg = skb_shinfo(skb)->nr_frags;
+ while (tlen > 0) {
+ tlen -= MAX_TX_DESC_LEN;
+ nfg++;
+ }
+
+ while (len > 0) {
+ unsigned int this_len = len;
+
+ if (this_len > MAX_TX_DESC_LEN)
+ this_len = MAX_TX_DESC_LEN;
+
+ niu_set_txd(rp, prod, mapping, this_len, mrk, nfg);
+ mrk = nfg = 0;
+
+ prod = NEXT_TX(rp, prod);
+ mapping += this_len;
+ len -= this_len;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ len = frag->size;
+ mapping = np->ops->map_page(np->device, frag->page,
+ frag->page_offset, len,
+ DMA_TO_DEVICE);
+
+ rp->tx_buffs[prod].skb = NULL;
+ rp->tx_buffs[prod].mapping = mapping;
+
+ niu_set_txd(rp, prod, mapping, len, 0, 0);
+
+ prod = NEXT_TX(rp, prod);
+ }
+
+ if (prod < rp->prod)
+ rp->wrap_bit ^= TX_RING_KICK_WRAP;
+ rp->prod = prod;
+
+ nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3));
+
+ if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) {
+ netif_stop_queue(dev);
+ if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))
+ netif_wake_queue(dev);
+ }
+
+ dev->trans_start = jiffies;
+
+out:
+ return NETDEV_TX_OK;
+
+out_drop:
+ rp->tx_errors++;
+ kfree_skb(skb);
+ goto out;
+}
+
+static int niu_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct niu *np = netdev_priv(dev);
+ int err, orig_jumbo, new_jumbo;
+
+ if (new_mtu < 68 || new_mtu > NIU_MAX_MTU)
+ return -EINVAL;
+
+ orig_jumbo = (dev->mtu > ETH_DATA_LEN);
+ new_jumbo = (new_mtu > ETH_DATA_LEN);
+
+ dev->mtu = new_mtu;
+
+ if (!netif_running(dev) ||
+ (orig_jumbo == new_jumbo))
+ return 0;
+
+ niu_full_shutdown(np, dev);
+
+ niu_free_channels(np);
+
+ niu_enable_napi(np);
+
+ err = niu_alloc_channels(np);
+ if (err)
+ return err;
+
+ spin_lock_irq(&np->lock);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ init_timer(&np->timer);
+ np->timer.expires = jiffies + HZ;
+ np->timer.data = (unsigned long) np;
+ np->timer.function = niu_timer;
+
+ err = niu_enable_interrupts(np, 1);
+ if (err)
+ niu_stop_hw(np);
+ }
+
+ spin_unlock_irq(&np->lock);
+
+ if (!err) {
+ netif_start_queue(dev);
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ netif_carrier_on(dev);
+
+ add_timer(&np->timer);
+ }
+
+ return err;
+}
+
+static void niu_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct niu *np = netdev_priv(dev);
+ struct niu_vpd *vpd = &np->vpd;
+
+ strcpy(info->driver, DRV_MODULE_NAME);
+ strcpy(info->version, DRV_MODULE_VERSION);
+ sprintf(info->fw_version, "%d.%d",
+ vpd->fcode_major, vpd->fcode_minor);
+ if (np->parent->plat_type != PLAT_TYPE_NIU)
+ strcpy(info->bus_info, pci_name(np->pdev));
+}
+
+static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct niu *np = netdev_priv(dev);
+ struct niu_link_config *lp;
+
+ lp = &np->link_config;
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->phy_address = np->phy_addr;
+ cmd->supported = lp->supported;
+ cmd->advertising = lp->advertising;
+ cmd->autoneg = lp->autoneg;
+ cmd->speed = lp->active_speed;
+ cmd->duplex = lp->active_duplex;
+
+ return 0;
+}
+
+static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ return -EINVAL;
+}
+
+static u32 niu_get_msglevel(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ return np->msg_enable;
+}
+
+static void niu_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct niu *np = netdev_priv(dev);
+ np->msg_enable = value;
+}
+
+static int niu_get_eeprom_len(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ return np->eeprom_len;
+}
+
+static int niu_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct niu *np = netdev_priv(dev);
+ u32 offset, len, val;
+
+ offset = eeprom->offset;
+ len = eeprom->len;
+
+ if (offset + len < offset)
+ return -EINVAL;
+ if (offset >= np->eeprom_len)
+ return -EINVAL;
+ if (offset + len > np->eeprom_len)
+ len = eeprom->len = np->eeprom_len - offset;
+
+ if (offset & 3) {
+ u32 b_offset, b_count;
+
+ b_offset = offset & 3;
+ b_count = 4 - b_offset;
+ if (b_count > len)
+ b_count = len;
+
+ val = nr64(ESPC_NCR((offset - b_offset) / 4));
+ memcpy(data, ((char *)&val) + b_offset, b_count);
+ data += b_count;
+ len -= b_count;
+ offset += b_count;
+ }
+ while (len >= 4) {
+ val = nr64(ESPC_NCR(offset / 4));
+ memcpy(data, &val, 4);
+ data += 4;
+ len -= 4;
+ offset += 4;
+ }
+ if (len) {
+ val = nr64(ESPC_NCR(offset / 4));
+ memcpy(data, &val, len);
+ }
+ return 0;
+}
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_xmac_stat_keys[] = {
+ { "tx_frames" },
+ { "tx_bytes" },
+ { "tx_fifo_errors" },
+ { "tx_overflow_errors" },
+ { "tx_max_pkt_size_errors" },
+ { "tx_underflow_errors" },
+ { "rx_local_faults" },
+ { "rx_remote_faults" },
+ { "rx_link_faults" },
+ { "rx_align_errors" },
+ { "rx_frags" },
+ { "rx_mcasts" },
+ { "rx_bcasts" },
+ { "rx_hist_cnt1" },
+ { "rx_hist_cnt2" },
+ { "rx_hist_cnt3" },
+ { "rx_hist_cnt4" },
+ { "rx_hist_cnt5" },
+ { "rx_hist_cnt6" },
+ { "rx_hist_cnt7" },
+ { "rx_octets" },
+ { "rx_code_violations" },
+ { "rx_len_errors" },
+ { "rx_crc_errors" },
+ { "rx_underflows" },
+ { "rx_overflows" },
+ { "pause_off_state" },
+ { "pause_on_state" },
+ { "pause_received" },
+};
+
+#define NUM_XMAC_STAT_KEYS ARRAY_SIZE(niu_xmac_stat_keys)
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_bmac_stat_keys[] = {
+ { "tx_underflow_errors" },
+ { "tx_max_pkt_size_errors" },
+ { "tx_bytes" },
+ { "tx_frames" },
+ { "rx_overflows" },
+ { "rx_frames" },
+ { "rx_align_errors" },
+ { "rx_crc_errors" },
+ { "rx_len_errors" },
+ { "pause_off_state" },
+ { "pause_on_state" },
+ { "pause_received" },
+};
+
+#define NUM_BMAC_STAT_KEYS ARRAY_SIZE(niu_bmac_stat_keys)
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_rxchan_stat_keys[] = {
+ { "rx_channel" },
+ { "rx_packets" },
+ { "rx_bytes" },
+ { "rx_dropped" },
+ { "rx_errors" },
+};
+
+#define NUM_RXCHAN_STAT_KEYS ARRAY_SIZE(niu_rxchan_stat_keys)
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_txchan_stat_keys[] = {
+ { "tx_channel" },
+ { "tx_packets" },
+ { "tx_bytes" },
+ { "tx_errors" },
+};
+
+#define NUM_TXCHAN_STAT_KEYS ARRAY_SIZE(niu_txchan_stat_keys)
+
+static void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ struct niu *np = netdev_priv(dev);
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ memcpy(data, niu_xmac_stat_keys,
+ sizeof(niu_xmac_stat_keys));
+ data += sizeof(niu_xmac_stat_keys);
+ } else {
+ memcpy(data, niu_bmac_stat_keys,
+ sizeof(niu_bmac_stat_keys));
+ data += sizeof(niu_bmac_stat_keys);
+ }
+ for (i = 0; i < np->num_rx_rings; i++) {
+ memcpy(data, niu_rxchan_stat_keys,
+ sizeof(niu_rxchan_stat_keys));
+ data += sizeof(niu_rxchan_stat_keys);
+ }
+ for (i = 0; i < np->num_tx_rings; i++) {
+ memcpy(data, niu_txchan_stat_keys,
+ sizeof(niu_txchan_stat_keys));
+ data += sizeof(niu_txchan_stat_keys);
+ }
+}
+
+static int niu_get_stats_count(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ return ((np->flags & NIU_FLAGS_XMAC ?
+ NUM_XMAC_STAT_KEYS :
+ NUM_BMAC_STAT_KEYS) +
+ (np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) +
+ (np->num_tx_rings * NUM_TXCHAN_STAT_KEYS));
+}
+
+static void niu_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct niu *np = netdev_priv(dev);
+ int i;
+
+ niu_sync_mac_stats(np);
+ if (np->flags & NIU_FLAGS_XMAC) {
+ memcpy(data, &np->mac_stats.xmac,
+ sizeof(struct niu_xmac_stats));
+ data += (sizeof(struct niu_xmac_stats) / sizeof(u64));
+ } else {
+ memcpy(data, &np->mac_stats.bmac,
+ sizeof(struct niu_bmac_stats));
+ data += (sizeof(struct niu_bmac_stats) / sizeof(u64));
+ }
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ data[0] = rp->rx_channel;
+ data[1] = rp->rx_packets;
+ data[2] = rp->rx_bytes;
+ data[3] = rp->rx_dropped;
+ data[4] = rp->rx_errors;
+ data += 5;
+ }
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ data[0] = rp->tx_channel;
+ data[1] = rp->tx_packets;
+ data[2] = rp->tx_bytes;
+ data[3] = rp->tx_errors;
+ data += 4;
+ }
+}
+
+static u64 niu_led_state_save(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return nr64_mac(XMAC_CONFIG);
+ else
+ return nr64_mac(BMAC_XIF_CONFIG);
+}
+
+static void niu_led_state_restore(struct niu *np, u64 val)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ nw64_mac(XMAC_CONFIG, val);
+ else
+ nw64_mac(BMAC_XIF_CONFIG, val);
+}
+
+static void niu_force_led(struct niu *np, int on)
+{
+ u64 val, reg, bit;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ reg = XMAC_CONFIG;
+ bit = XMAC_CONFIG_FORCE_LED_ON;
+ } else {
+ reg = BMAC_XIF_CONFIG;
+ bit = BMAC_XIF_CONFIG_LINK_LED;
+ }
+
+ val = nr64_mac(reg);
+ if (on)
+ val |= bit;
+ else
+ val &= ~bit;
+ nw64_mac(reg, val);
+}
+
+static int niu_phys_id(struct net_device *dev, u32 data)
+{
+ struct niu *np = netdev_priv(dev);
+ u64 orig_led_state;
+ int i;
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+
+ if (data == 0)
+ data = 2;
+
+ orig_led_state = niu_led_state_save(np);
+ for (i = 0; i < (data * 2); i++) {
+ int on = ((i % 2) == 0);
+
+ niu_force_led(np, on);
+
+ if (msleep_interruptible(500))
+ break;
+ }
+ niu_led_state_restore(np, orig_led_state);
+
+ return 0;
+}
+
+static const struct ethtool_ops niu_ethtool_ops = {
+ .get_drvinfo = niu_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = niu_get_msglevel,
+ .set_msglevel = niu_set_msglevel,
+ .get_eeprom_len = niu_get_eeprom_len,
+ .get_eeprom = niu_get_eeprom,
+ .get_settings = niu_get_settings,
+ .set_settings = niu_set_settings,
+ .get_strings = niu_get_strings,
+ .get_stats_count = niu_get_stats_count,
+ .get_ethtool_stats = niu_get_ethtool_stats,
+ .phys_id = niu_phys_id,
+};
+
+static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
+ int ldg, int ldn)
+{
+ if (ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX)
+ return -EINVAL;
+ if (ldn < 0 || ldn > LDN_MAX)
+ return -EINVAL;
+
+ parent->ldg_map[ldn] = ldg;
+
+ if (np->parent->plat_type == PLAT_TYPE_NIU) {
+ /* On N2 NIU, the ldn-->ldg assignments are setup and fixed by
+ * the firmware, and we're not supposed to change them.
+ * Validate the mapping, because if it's wrong we probably
+ * won't get any interrupts and that's painful to debug.
+ */
+ if (nr64(LDG_NUM(ldn)) != ldg) {
+ dev_err(np->device, PFX "Port %u, mis-matched "
+ "LDG assignment "
+ "for ldn %d, should be %d is %llu\n",
+ np->port, ldn, ldg,
+ (unsigned long long) nr64(LDG_NUM(ldn)));
+ return -EINVAL;
+ }
+ } else
+ nw64(LDG_NUM(ldn), ldg);
+
+ return 0;
+}
+
+static int niu_set_ldg_timer_res(struct niu *np, int res)
+{
+ if (res < 0 || res > LDG_TIMER_RES_VAL)
+ return -EINVAL;
+
+
+ nw64(LDG_TIMER_RES, res);
+
+ return 0;
+}
+
+static int niu_set_ldg_sid(struct niu *np, int ldg, int func, int vector)
+{
+ if ((ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) ||
+ (func < 0 || func > 3) ||
+ (vector < 0 || vector > 0x1f))
+ return -EINVAL;
+
+ nw64(SID(ldg), (func << SID_FUNC_SHIFT) | vector);
+
+ return 0;
+}
+
+static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr)
+{
+ u64 frame, frame_base = (ESPC_PIO_STAT_READ_START |
+ (addr << ESPC_PIO_STAT_ADDR_SHIFT));
+ int limit;
+
+ if (addr > (ESPC_PIO_STAT_ADDR >> ESPC_PIO_STAT_ADDR_SHIFT))
+ return -EINVAL;
+
+ frame = frame_base;
+ nw64(ESPC_PIO_STAT, frame);
+ limit = 64;
+ do {
+ udelay(5);
+ frame = nr64(ESPC_PIO_STAT);
+ if (frame & ESPC_PIO_STAT_READ_END)
+ break;
+ } while (limit--);
+ if (!(frame & ESPC_PIO_STAT_READ_END)) {
+ dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+ (unsigned long long) frame);
+ return -ENODEV;
+ }
+
+ frame = frame_base;
+ nw64(ESPC_PIO_STAT, frame);
+ limit = 64;
+ do {
+ udelay(5);
+ frame = nr64(ESPC_PIO_STAT);
+ if (frame & ESPC_PIO_STAT_READ_END)
+ break;
+ } while (limit--);
+ if (!(frame & ESPC_PIO_STAT_READ_END)) {
+ dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+ (unsigned long long) frame);
+ return -ENODEV;
+ }
+
+ frame = nr64(ESPC_PIO_STAT);
+ return (frame & ESPC_PIO_STAT_DATA) >> ESPC_PIO_STAT_DATA_SHIFT;
+}
+
+static int __devinit niu_pci_eeprom_read16(struct niu *np, u32 off)
+{
+ int err = niu_pci_eeprom_read(np, off);
+ u16 val;
+
+ if (err < 0)
+ return err;
+ val = (err << 8);
+ err = niu_pci_eeprom_read(np, off + 1);
+ if (err < 0)
+ return err;
+ val |= (err & 0xff);
+
+ return val;
+}
+
+static int __devinit niu_pci_eeprom_read16_swp(struct niu *np, u32 off)
+{
+ int err = niu_pci_eeprom_read(np, off);
+ u16 val;
+
+ if (err < 0)
+ return err;
+
+ val = (err & 0xff);
+ err = niu_pci_eeprom_read(np, off + 1);
+ if (err < 0)
+ return err;
+
+ val |= (err & 0xff) << 8;
+
+ return val;
+}
+
+static int __devinit niu_pci_vpd_get_propname(struct niu *np,
+ u32 off,
+ char *namebuf,
+ int namebuf_len)
+{
+ int i;
+
+ for (i = 0; i < namebuf_len; i++) {
+ int err = niu_pci_eeprom_read(np, off + i);
+ if (err < 0)
+ return err;
+ *namebuf++ = err;
+ if (!err)
+ break;
+ }
+ if (i >= namebuf_len)
+ return -EINVAL;
+
+ return i + 1;
+}
+
+static void __devinit niu_vpd_parse_version(struct niu *np)
+{
+ struct niu_vpd *vpd = &np->vpd;
+ int len = strlen(vpd->version) + 1;
+ const char *s = vpd->version;
+ int i;
+
+ for (i = 0; i < len - 5; i++) {
+ if (!strncmp(s + i, "FCode ", 5))
+ break;
+ }
+ if (i >= len - 5)
+ return;
+
+ s += i + 5;
+ sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor);
+
+ niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n",
+ vpd->fcode_major, vpd->fcode_minor);
+ if (vpd->fcode_major > NIU_VPD_MIN_MAJOR ||
+ (vpd->fcode_major == NIU_VPD_MIN_MAJOR &&
+ vpd->fcode_minor >= NIU_VPD_MIN_MINOR))
+ np->flags |= NIU_FLAGS_VPD_VALID;
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static int __devinit niu_pci_vpd_scan_props(struct niu *np,
+ u32 start, u32 end)
+{
+ unsigned int found_mask = 0;
+#define FOUND_MASK_MODEL 0x00000001
+#define FOUND_MASK_BMODEL 0x00000002
+#define FOUND_MASK_VERS 0x00000004
+#define FOUND_MASK_MAC 0x00000008
+#define FOUND_MASK_NMAC 0x00000010
+#define FOUND_MASK_PHY 0x00000020
+#define FOUND_MASK_ALL 0x0000003f
+
+ niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n",
+ start, end);
+ while (start < end) {
+ int len, err, instance, type, prop_len;
+ char namebuf[64];
+ u8 *prop_buf;
+ int max_len;
+
+ if (found_mask == FOUND_MASK_ALL) {
+ niu_vpd_parse_version(np);
+ return 1;
+ }
+
+ err = niu_pci_eeprom_read(np, start + 2);
+ if (err < 0)
+ return err;
+ len = err;
+ start += 3;
+
+ instance = niu_pci_eeprom_read(np, start);
+ type = niu_pci_eeprom_read(np, start + 3);
+ prop_len = niu_pci_eeprom_read(np, start + 4);
+ err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
+ if (err < 0)
+ return err;
+
+ prop_buf = NULL;
+ max_len = 0;
+ if (!strcmp(namebuf, "model")) {
+ prop_buf = np->vpd.model;
+ max_len = NIU_VPD_MODEL_MAX;
+ found_mask |= FOUND_MASK_MODEL;
+ } else if (!strcmp(namebuf, "board-model")) {
+ prop_buf = np->vpd.board_model;
+ max_len = NIU_VPD_BD_MODEL_MAX;
+ found_mask |= FOUND_MASK_BMODEL;
+ } else if (!strcmp(namebuf, "version")) {
+ prop_buf = np->vpd.version;
+ max_len = NIU_VPD_VERSION_MAX;
+ found_mask |= FOUND_MASK_VERS;
+ } else if (!strcmp(namebuf, "local-mac-address")) {
+ prop_buf = np->vpd.local_mac;
+ max_len = ETH_ALEN;
+ found_mask |= FOUND_MASK_MAC;
+ } else if (!strcmp(namebuf, "num-mac-addresses")) {
+ prop_buf = &np->vpd.mac_num;
+ max_len = 1;
+ found_mask |= FOUND_MASK_NMAC;
+ } else if (!strcmp(namebuf, "phy-type")) {
+ prop_buf = np->vpd.phy_type;
+ max_len = NIU_VPD_PHY_TYPE_MAX;
+ found_mask |= FOUND_MASK_PHY;
+ }
+
+ if (max_len && prop_len > max_len) {
+ dev_err(np->device, PFX "Property '%s' length (%d) is "
+ "too long.\n", namebuf, prop_len);
+ return -EINVAL;
+ }
+
+ if (prop_buf) {
+ u32 off = start + 5 + err;
+ int i;
+
+ niudbg(PROBE, "VPD_SCAN: Reading in property [%s] "
+ "len[%d]\n", namebuf, prop_len);
+ for (i = 0; i < prop_len; i++)
+ *prop_buf++ = niu_pci_eeprom_read(np, off + i);
+ }
+
+ start += len;
+ }
+
+ return 0;
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static void __devinit niu_pci_vpd_fetch(struct niu *np, u32 start)
+{
+ u32 offset;
+ int err;
+
+ err = niu_pci_eeprom_read16_swp(np, start + 1);
+ if (err < 0)
+ return;
+
+ offset = err + 3;
+
+ while (start + offset < ESPC_EEPROM_SIZE) {
+ u32 here = start + offset;
+ u32 end;
+
+ err = niu_pci_eeprom_read(np, here);
+ if (err != 0x90)
+ return;
+
+ err = niu_pci_eeprom_read16_swp(np, here + 1);
+ if (err < 0)
+ return;
+
+ here = start + offset + 3;
+ end = start + offset + err;
+
+ offset += err;
+
+ err = niu_pci_vpd_scan_props(np, here, end);
+ if (err < 0 || err == 1)
+ return;
+ }
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static u32 __devinit niu_pci_vpd_offset(struct niu *np)
+{
+ u32 start = 0, end = ESPC_EEPROM_SIZE, ret;
+ int err;
+
+ while (start < end) {
+ ret = start;
+
+ /* ROM header signature? */
+ err = niu_pci_eeprom_read16(np, start + 0);
+ if (err != 0x55aa)
+ return 0;
+
+ /* Apply offset to PCI data structure. */
+ err = niu_pci_eeprom_read16(np, start + 23);
+ if (err < 0)
+ return 0;
+ start += err;
+
+ /* Check for "PCIR" signature. */
+ err = niu_pci_eeprom_read16(np, start + 0);
+ if (err != 0x5043)
+ return 0;
+ err = niu_pci_eeprom_read16(np, start + 2);
+ if (err != 0x4952)
+ return 0;
+
+ /* Check for OBP image type. */
+ err = niu_pci_eeprom_read(np, start + 20);
+ if (err < 0)
+ return 0;
+ if (err != 0x01) {
+ err = niu_pci_eeprom_read(np, ret + 2);
+ if (err < 0)
+ return 0;
+
+ start = ret + (err * 512);
+ continue;
+ }
+
+ err = niu_pci_eeprom_read16_swp(np, start + 8);
+ if (err < 0)
+ return err;
+ ret += err;
+
+ err = niu_pci_eeprom_read(np, ret + 0);
+ if (err != 0x82)
+ return 0;
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devinit niu_phy_type_prop_decode(struct niu *np,
+ const char *phy_prop)
+{
+ if (!strcmp(phy_prop, "mif")) {
+ /* 1G copper, MII */
+ np->flags &= ~(NIU_FLAGS_FIBER |
+ NIU_FLAGS_10G);
+ np->mac_xcvr = MAC_XCVR_MII;
+ } else if (!strcmp(phy_prop, "xgf")) {
+ /* 10G fiber, XPCS */
+ np->flags |= (NIU_FLAGS_10G |
+ NIU_FLAGS_FIBER);
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ } else if (!strcmp(phy_prop, "pcs")) {
+ /* 1G fiber, PCS */
+ np->flags &= ~NIU_FLAGS_10G;
+ np->flags |= NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_PCS;
+ } else if (!strcmp(phy_prop, "xgc")) {
+ /* 10G copper, XPCS */
+ np->flags |= NIU_FLAGS_10G;
+ np->flags &= ~NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void __devinit niu_pci_vpd_validate(struct niu *np)
+{
+ struct net_device *dev = np->dev;
+ struct niu_vpd *vpd = &np->vpd;
+ u8 val8;
+
+ if (!is_valid_ether_addr(&vpd->local_mac[0])) {
+ dev_err(np->device, PFX "VPD MAC invalid, "
+ "falling back to SPROM.\n");
+
+ np->flags &= ~NIU_FLAGS_VPD_VALID;
+ return;
+ }
+
+ if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+ dev_err(np->device, PFX "Illegal phy string [%s].\n",
+ np->vpd.phy_type);
+ dev_err(np->device, PFX "Falling back to SPROM.\n");
+ np->flags &= ~NIU_FLAGS_VPD_VALID;
+ return;
+ }
+
+ memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
+
+ val8 = dev->perm_addr[5];
+ dev->perm_addr[5] += np->port;
+ if (dev->perm_addr[5] < val8)
+ dev->perm_addr[4]++;
+
+ memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+}
+
+static int __devinit niu_pci_probe_sprom(struct niu *np)
+{
+ struct net_device *dev = np->dev;
+ int len, i;
+ u64 val, sum;
+ u8 val8;
+
+ val = (nr64(ESPC_VER_IMGSZ) & ESPC_VER_IMGSZ_IMGSZ);
+ val >>= ESPC_VER_IMGSZ_IMGSZ_SHIFT;
+ len = val / 4;
+
+ np->eeprom_len = len;
+
+ niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val);
+
+ sum = 0;
+ for (i = 0; i < len; i++) {
+ val = nr64(ESPC_NCR(i));
+ sum += (val >> 0) & 0xff;
+ sum += (val >> 8) & 0xff;
+ sum += (val >> 16) & 0xff;
+ sum += (val >> 24) & 0xff;
+ }
+ niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff));
+ if ((sum & 0xff) != 0xab) {
+ dev_err(np->device, PFX "Bad SPROM checksum "
+ "(%x, should be 0xab)\n", (int) (sum & 0xff));
+ return -EINVAL;
+ }
+
+ val = nr64(ESPC_PHY_TYPE);
+ switch (np->port) {
+ case 0:
+ val = (val & ESPC_PHY_TYPE_PORT0) >>
+ ESPC_PHY_TYPE_PORT0_SHIFT;
+ break;
+ case 1:
+ val = (val & ESPC_PHY_TYPE_PORT1) >>
+ ESPC_PHY_TYPE_PORT1_SHIFT;
+ break;
+ case 2:
+ val = (val & ESPC_PHY_TYPE_PORT2) >>
+ ESPC_PHY_TYPE_PORT2_SHIFT;
+ break;
+ case 3:
+ val = (val & ESPC_PHY_TYPE_PORT3) >>
+ ESPC_PHY_TYPE_PORT3_SHIFT;
+ break;
+ default:
+ dev_err(np->device, PFX "Bogus port number %u\n",
+ np->port);
+ return -EINVAL;
+ }
+ niudbg(PROBE, "SPROM: PHY type %llx\n", (unsigned long long) val);
+
+ switch (val) {
+ case ESPC_PHY_TYPE_1G_COPPER:
+ /* 1G copper, MII */
+ np->flags &= ~(NIU_FLAGS_FIBER |
+ NIU_FLAGS_10G);
+ np->mac_xcvr = MAC_XCVR_MII;
+ break;
+
+ case ESPC_PHY_TYPE_1G_FIBER:
+ /* 1G fiber, PCS */
+ np->flags &= ~NIU_FLAGS_10G;
+ np->flags |= NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_PCS;
+ break;
+
+ case ESPC_PHY_TYPE_10G_COPPER:
+ /* 10G copper, XPCS */
+ np->flags |= NIU_FLAGS_10G;
+ np->flags &= ~NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ break;
+
+ case ESPC_PHY_TYPE_10G_FIBER:
+ /* 10G fiber, XPCS */
+ np->flags |= (NIU_FLAGS_10G |
+ NIU_FLAGS_FIBER);
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ break;
+
+ default:
+ dev_err(np->device, PFX "Bogus SPROM phy type %llu\n",
+ (unsigned long long) val);
+ return -EINVAL;
+ }
+
+ val = nr64(ESPC_MAC_ADDR0);
+ niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n",
+ (unsigned long long) val);
+ dev->perm_addr[0] = (val >> 0) & 0xff;
+ dev->perm_addr[1] = (val >> 8) & 0xff;
+ dev->perm_addr[2] = (val >> 16) & 0xff;
+ dev->perm_addr[3] = (val >> 24) & 0xff;
+
+ val = nr64(ESPC_MAC_ADDR1);
+ niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n",
+ (unsigned long long) val);
+ dev->perm_addr[4] = (val >> 0) & 0xff;
+ dev->perm_addr[5] = (val >> 8) & 0xff;
+
+ if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+ dev_err(np->device, PFX "SPROM MAC address invalid\n");
+ dev_err(np->device, PFX "[ \n");
+ for (i = 0; i < 6; i++)
+ printk("%02x ", dev->perm_addr[i]);
+ printk("]\n");
+ return -EINVAL;
+ }
+
+ val8 = dev->perm_addr[5];
+ dev->perm_addr[5] += np->port;
+ if (dev->perm_addr[5] < val8)
+ dev->perm_addr[4]++;
+
+ memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+
+ val = nr64(ESPC_MOD_STR_LEN);
+ niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n",
+ (unsigned long long) val);
+ if (val > 8 * 4)
+ return -EINVAL;
+
+ for (i = 0; i < val; i += 4) {
+ u64 tmp = nr64(ESPC_NCR(5 + (i / 4)));
+
+ np->vpd.model[i + 3] = (tmp >> 0) & 0xff;
+ np->vpd.model[i + 2] = (tmp >> 8) & 0xff;
+ np->vpd.model[i + 1] = (tmp >> 16) & 0xff;
+ np->vpd.model[i + 0] = (tmp >> 24) & 0xff;
+ }
+ np->vpd.model[val] = '\0';
+
+ val = nr64(ESPC_BD_MOD_STR_LEN);
+ niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n",
+ (unsigned long long) val);
+ if (val > 4 * 4)
+ return -EINVAL;
+
+ for (i = 0; i < val; i += 4) {
+ u64 tmp = nr64(ESPC_NCR(14 + (i / 4)));
+
+ np->vpd.board_model[i + 3] = (tmp >> 0) & 0xff;
+ np->vpd.board_model[i + 2] = (tmp >> 8) & 0xff;
+ np->vpd.board_model[i + 1] = (tmp >> 16) & 0xff;
+ np->vpd.board_model[i + 0] = (tmp >> 24) & 0xff;
+ }
+ np->vpd.board_model[val] = '\0';
+
+ np->vpd.mac_num =
+ nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL;
+ niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n",
+ np->vpd.mac_num);
+
+ return 0;
+}
+
+static int __devinit niu_get_and_validate_port(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+
+ if (np->port <= 1)
+ np->flags |= NIU_FLAGS_XMAC;
+
+ if (!parent->num_ports) {
+ if (parent->plat_type == PLAT_TYPE_NIU) {
+ parent->num_ports = 2;
+ } else {
+ parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
+ ESPC_NUM_PORTS_MACS_VAL;
+
+ if (!parent->num_ports)
+ parent->num_ports = 4;
+ }
+ }
+
+ niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n",
+ np->port, parent->num_ports);
+ if (np->port >= parent->num_ports)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int __devinit phy_record(struct niu_parent *parent,
+ struct phy_probe_info *p,
+ int dev_id_1, int dev_id_2, u8 phy_port,
+ int type)
+{
+ u32 id = (dev_id_1 << 16) | dev_id_2;
+ u8 idx;
+
+ if (dev_id_1 < 0 || dev_id_2 < 0)
+ return 0;
+ if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
+ if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704)
+ return 0;
+ } else {
+ if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
+ return 0;
+ }
+
+ pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n",
+ parent->index, id,
+ (type == PHY_TYPE_PMA_PMD ?
+ "PMA/PMD" :
+ (type == PHY_TYPE_PCS ?
+ "PCS" : "MII")),
+ phy_port);
+
+ if (p->cur[type] >= NIU_MAX_PORTS) {
+ printk(KERN_ERR PFX "Too many PHY ports.\n");
+ return -EINVAL;
+ }
+ idx = p->cur[type];
+ p->phy_id[type][idx] = id;
+ p->phy_port[type][idx] = phy_port;
+ p->cur[type] = idx + 1;
+ return 0;
+}
+
+static int __devinit port_has_10g(struct phy_probe_info *p, int port)
+{
+ int i;
+
+ for (i = 0; i < p->cur[PHY_TYPE_PMA_PMD]; i++) {
+ if (p->phy_port[PHY_TYPE_PMA_PMD][i] == port)
+ return 1;
+ }
+ for (i = 0; i < p->cur[PHY_TYPE_PCS]; i++) {
+ if (p->phy_port[PHY_TYPE_PCS][i] == port)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int __devinit count_10g_ports(struct phy_probe_info *p, int *lowest)
+{
+ int port, cnt;
+
+ cnt = 0;
+ *lowest = 32;
+ for (port = 8; port < 32; port++) {
+ if (port_has_10g(p, port)) {
+ if (!cnt)
+ *lowest = port;
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+static int __devinit count_1g_ports(struct phy_probe_info *p, int *lowest)
+{
+ *lowest = 32;
+ if (p->cur[PHY_TYPE_MII])
+ *lowest = p->phy_port[PHY_TYPE_MII][0];
+
+ return p->cur[PHY_TYPE_MII];
+}
+
+static void __devinit niu_n2_divide_channels(struct niu_parent *parent)
+{
+ int num_ports = parent->num_ports;
+ int i;
+
+ for (i = 0; i < num_ports; i++) {
+ parent->rxchan_per_port[i] = (16 / num_ports);
+ parent->txchan_per_port[i] = (16 / num_ports);
+
+ pr_info(PFX "niu%d: Port %u [%u RX chans] "
+ "[%u TX chans]\n",
+ parent->index, i,
+ parent->rxchan_per_port[i],
+ parent->txchan_per_port[i]);
+ }
+}
+
+static void __devinit niu_divide_channels(struct niu_parent *parent,
+ int num_10g, int num_1g)
+{
+ int num_ports = parent->num_ports;
+ int rx_chans_per_10g, rx_chans_per_1g;
+ int tx_chans_per_10g, tx_chans_per_1g;
+ int i, tot_rx, tot_tx;
+
+ if (!num_10g || !num_1g) {
+ rx_chans_per_10g = rx_chans_per_1g =
+ (NIU_NUM_RXCHAN / num_ports);
+ tx_chans_per_10g = tx_chans_per_1g =
+ (NIU_NUM_TXCHAN / num_ports);
+ } else {
+ rx_chans_per_1g = NIU_NUM_RXCHAN / 8;
+ rx_chans_per_10g = (NIU_NUM_RXCHAN -
+ (rx_chans_per_1g * num_1g)) /
+ num_10g;
+
+ tx_chans_per_1g = NIU_NUM_TXCHAN / 6;
+ tx_chans_per_10g = (NIU_NUM_TXCHAN -
+ (tx_chans_per_1g * num_1g)) /
+ num_10g;
+ }
+
+ tot_rx = tot_tx = 0;
+ for (i = 0; i < num_ports; i++) {
+ int type = phy_decode(parent->port_phy, i);
+
+ if (type == PORT_TYPE_10G) {
+ parent->rxchan_per_port[i] = rx_chans_per_10g;
+ parent->txchan_per_port[i] = tx_chans_per_10g;
+ } else {
+ parent->rxchan_per_port[i] = rx_chans_per_1g;
+ parent->txchan_per_port[i] = tx_chans_per_1g;
+ }
+ pr_info(PFX "niu%d: Port %u [%u RX chans] "
+ "[%u TX chans]\n",
+ parent->index, i,
+ parent->rxchan_per_port[i],
+ parent->txchan_per_port[i]);
+ tot_rx += parent->rxchan_per_port[i];
+ tot_tx += parent->txchan_per_port[i];
+ }
+
+ if (tot_rx > NIU_NUM_RXCHAN) {
+ printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), "
+ "resetting to one per port.\n",
+ parent->index, tot_rx);
+ for (i = 0; i < num_ports; i++)
+ parent->rxchan_per_port[i] = 1;
+ }
+ if (tot_tx > NIU_NUM_TXCHAN) {
+ printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), "
+ "resetting to one per port.\n",
+ parent->index, tot_tx);
+ for (i = 0; i < num_ports; i++)
+ parent->txchan_per_port[i] = 1;
+ }
+ if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) {
+ printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, "
+ "RX[%d] TX[%d]\n",
+ parent->index, tot_rx, tot_tx);
+ }
+}
+
+static void __devinit niu_divide_rdc_groups(struct niu_parent *parent,
+ int num_10g, int num_1g)
+{
+ int i, num_ports = parent->num_ports;
+ int rdc_group, rdc_groups_per_port;
+ int rdc_channel_base;
+
+ rdc_group = 0;
+ rdc_groups_per_port = NIU_NUM_RDC_TABLES / num_ports;
+
+ rdc_channel_base = 0;
+
+ for (i = 0; i < num_ports; i++) {
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[i];
+ int grp, num_channels = parent->rxchan_per_port[i];
+ int this_channel_offset;
+
+ tp->first_table_num = rdc_group;
+ tp->num_tables = rdc_groups_per_port;
+ this_channel_offset = 0;
+ for (grp = 0; grp < tp->num_tables; grp++) {
+ struct rdc_table *rt = &tp->tables[grp];
+ int slot;
+
+ pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ",
+ parent->index, i, tp->first_table_num + grp);
+ for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) {
+ rt->rxdma_channel[slot] =
+ rdc_channel_base + this_channel_offset;
+
+ printk("%d ", rt->rxdma_channel[slot]);
+
+ if (++this_channel_offset == num_channels)
+ this_channel_offset = 0;
+ }
+ printk("]\n");
+ }
+
+ parent->rdc_default[i] = rdc_channel_base;
+
+ rdc_channel_base += num_channels;
+ rdc_group += rdc_groups_per_port;
+ }
+}
+
+static int __devinit fill_phy_probe_info(struct niu *np,
+ struct niu_parent *parent,
+ struct phy_probe_info *info)
+{
+ unsigned long flags;
+ int port, err;
+
+ memset(info, 0, sizeof(*info));
+
+ /* Port 0 to 7 are reserved for onboard Serdes, probe the rest. */
+ niu_lock_parent(np, flags);
+ err = 0;
+ for (port = 8; port < 32; port++) {
+ int dev_id_1, dev_id_2;
+
+ dev_id_1 = mdio_read(np, port,
+ NIU_PMA_PMD_DEV_ADDR, MII_PHYSID1);
+ dev_id_2 = mdio_read(np, port,
+ NIU_PMA_PMD_DEV_ADDR, MII_PHYSID2);
+ err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+ PHY_TYPE_PMA_PMD);
+ if (err)
+ break;
+ dev_id_1 = mdio_read(np, port,
+ NIU_PCS_DEV_ADDR, MII_PHYSID1);
+ dev_id_2 = mdio_read(np, port,
+ NIU_PCS_DEV_ADDR, MII_PHYSID2);
+ err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+ PHY_TYPE_PCS);
+ if (err)
+ break;
+ dev_id_1 = mii_read(np, port, MII_PHYSID1);
+ dev_id_2 = mii_read(np, port, MII_PHYSID2);
+ err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+ PHY_TYPE_MII);
+ if (err)
+ break;
+ }
+ niu_unlock_parent(np, flags);
+
+ return err;
+}
+
+static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
+{
+ struct phy_probe_info *info = &parent->phy_probe_info;
+ int lowest_10g, lowest_1g;
+ int num_10g, num_1g;
+ u32 val;
+ int err;
+
+ err = fill_phy_probe_info(np, parent, info);
+ if (err)
+ return err;
+
+ num_10g = count_10g_ports(info, &lowest_10g);
+ num_1g = count_1g_ports(info, &lowest_1g);
+
+ switch ((num_10g << 4) | num_1g) {
+ case 0x24:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ /* fallthru */
+ case 0x22:
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_10G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ case 0x20:
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_10G, 1));
+ break;
+
+ case 0x10:
+ val = phy_encode(PORT_TYPE_10G, np->port);
+ break;
+
+ case 0x14:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ /* fallthru */
+ case 0x13:
+ if ((lowest_10g & 0x7) == 0)
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ else
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_10G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ case 0x04:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Unsupported port config "
+ "10G[%d] 1G[%d]\n",
+ num_10g, num_1g);
+ return -EINVAL;
+ }
+
+ parent->port_phy = val;
+
+ if (parent->plat_type == PLAT_TYPE_NIU)
+ niu_n2_divide_channels(parent);
+ else
+ niu_divide_channels(parent, num_10g, num_1g);
+
+ niu_divide_rdc_groups(parent, num_10g, num_1g);
+
+ return 0;
+
+unknown_vg_1g_port:
+ printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n",
+ lowest_1g);
+ return -EINVAL;
+}
+
+static int __devinit niu_probe_ports(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ int err, i;
+
+ niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n",
+ parent->port_phy);
+
+ if (parent->port_phy == PORT_PHY_UNKNOWN) {
+ err = walk_phys(np, parent);
+ if (err)
+ return err;
+
+ niu_set_ldg_timer_res(np, 2);
+ for (i = 0; i <= LDN_MAX; i++)
+ niu_ldn_irq_enable(np, i, 0);
+ }
+
+ if (parent->port_phy == PORT_PHY_INVALID)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int __devinit niu_classifier_swstate_init(struct niu *np)
+{
+ struct niu_classifier *cp = &np->clas;
+
+ niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n",
+ np->parent->tcam_num_entries);
+
+ cp->tcam_index = (u16) np->port;
+ cp->h1_init = 0xffffffff;
+ cp->h2_init = 0xffff;
+
+ return fflp_early_init(np);
+}
+
+static void __devinit niu_link_config_init(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+
+ lp->advertising = (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_Autoneg);
+ lp->speed = lp->active_speed = SPEED_INVALID;
+ lp->duplex = lp->active_duplex = DUPLEX_INVALID;
+#if 0
+ lp->loopback_mode = LOOPBACK_MAC;
+ lp->active_speed = SPEED_10000;
+ lp->active_duplex = DUPLEX_FULL;
+#else
+ lp->loopback_mode = LOOPBACK_DISABLED;
+#endif
+}
+
+static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np)
+{
+ switch (np->port) {
+ case 0:
+ np->mac_regs = np->regs + XMAC_PORT0_OFF;
+ np->ipp_off = 0x00000;
+ np->pcs_off = 0x04000;
+ np->xpcs_off = 0x02000;
+ break;
+
+ case 1:
+ np->mac_regs = np->regs + XMAC_PORT1_OFF;
+ np->ipp_off = 0x08000;
+ np->pcs_off = 0x0a000;
+ np->xpcs_off = 0x08000;
+ break;
+
+ case 2:
+ np->mac_regs = np->regs + BMAC_PORT2_OFF;
+ np->ipp_off = 0x04000;
+ np->pcs_off = 0x0e000;
+ np->xpcs_off = ~0UL;
+ break;
+
+ case 3:
+ np->mac_regs = np->regs + BMAC_PORT3_OFF;
+ np->ipp_off = 0x0c000;
+ np->pcs_off = 0x12000;
+ np->xpcs_off = ~0UL;
+ break;
+
+ default:
+ dev_err(np->device, PFX "Port %u is invalid, cannot "
+ "compute MAC block offset.\n", np->port);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __devinit niu_try_msix(struct niu *np, u8 *ldg_num_map)
+{
+ struct msix_entry msi_vec[NIU_NUM_LDG];
+ struct niu_parent *parent = np->parent;
+ struct pci_dev *pdev = np->pdev;
+ int i, num_irqs, err;
+ u8 first_ldg;
+
+ first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port;
+ for (i = 0; i < (NIU_NUM_LDG / parent->num_ports); i++)
+ ldg_num_map[i] = first_ldg + i;
+
+ num_irqs = (parent->rxchan_per_port[np->port] +
+ parent->txchan_per_port[np->port] +
+ (np->port == 0 ? 3 : 1));
+ BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports));
+
+retry:
+ for (i = 0; i < num_irqs; i++) {
+ msi_vec[i].vector = 0;
+ msi_vec[i].entry = i;
+ }
+
+ err = pci_enable_msix(pdev, msi_vec, num_irqs);
+ if (err < 0) {
+ np->flags &= ~NIU_FLAGS_MSIX;
+ return;
+ }
+ if (err > 0) {
+ num_irqs = err;
+ goto retry;
+ }
+
+ np->flags |= NIU_FLAGS_MSIX;
+ for (i = 0; i < num_irqs; i++)
+ np->ldg[i].irq = msi_vec[i].vector;
+ np->num_ldg = num_irqs;
+}
+
+static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
+{
+#ifdef CONFIG_SPARC64
+ struct of_device *op = np->op;
+ const u32 *int_prop;
+ int i;
+
+ int_prop = of_get_property(op->node, "interrupts", NULL);
+ if (!int_prop)
+ return -ENODEV;
+
+ for (i = 0; i < op->num_irqs; i++) {
+ ldg_num_map[i] = int_prop[i];
+ np->ldg[i].irq = op->irqs[i];
+ }
+
+ np->num_ldg = op->num_irqs;
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
+static int __devinit niu_ldg_init(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ u8 ldg_num_map[NIU_NUM_LDG];
+ int first_chan, num_chan;
+ int i, err, ldg_rotor;
+ u8 port;
+
+ np->num_ldg = 1;
+ np->ldg[0].irq = np->dev->irq;
+ if (parent->plat_type == PLAT_TYPE_NIU) {
+ err = niu_n2_irq_init(np, ldg_num_map);
+ if (err)
+ return err;
+ } else
+ niu_try_msix(np, ldg_num_map);
+
+ port = np->port;
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+
+ netif_napi_add(np->dev, &lp->napi, niu_poll, 64);
+
+ lp->np = np;
+ lp->ldg_num = ldg_num_map[i];
+ lp->timer = 2; /* XXX */
+
+ /* On N2 NIU the firmware has setup the SID mappings so they go
+ * to the correct values that will route the LDG to the proper
+ * interrupt in the NCU interrupt table.
+ */
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ err = niu_set_ldg_sid(np, lp->ldg_num, port, i);
+ if (err)
+ return err;
+ }
+ }
+
+ /* We adopt the LDG assignment ordering used by the N2 NIU
+ * 'interrupt' properties because that simplifies a lot of
+ * things. This ordering is:
+ *
+ * MAC
+ * MIF (if port zero)
+ * SYSERR (if port zero)
+ * RX channels
+ * TX channels
+ */
+
+ ldg_rotor = 0;
+
+ err = niu_ldg_assign_ldn(np, parent, ldg_num_map[ldg_rotor],
+ LDN_MAC(port));
+ if (err)
+ return err;
+
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+
+ if (port == 0) {
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_MIF);
+ if (err)
+ return err;
+
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_DEVICE_ERROR);
+ if (err)
+ return err;
+
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+
+ }
+
+ first_chan = 0;
+ for (i = 0; i < port; i++)
+ first_chan += parent->rxchan_per_port[port];
+ num_chan = parent->rxchan_per_port[port];
+
+ for (i = first_chan; i < (first_chan + num_chan); i++) {
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_RXDMA(i));
+ if (err)
+ return err;
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+ }
+
+ first_chan = 0;
+ for (i = 0; i < port; i++)
+ first_chan += parent->txchan_per_port[port];
+ num_chan = parent->txchan_per_port[port];
+ for (i = first_chan; i < (first_chan + num_chan); i++) {
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_TXDMA(i));
+ if (err)
+ return err;
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+ }
+
+ return 0;
+}
+
+static void __devexit niu_ldg_free(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_MSIX)
+ pci_disable_msix(np->pdev);
+}
+
+static int __devinit niu_get_of_props(struct niu *np)
+{
+#ifdef CONFIG_SPARC64
+ struct net_device *dev = np->dev;
+ struct device_node *dp;
+ const char *phy_type;
+ const u8 *mac_addr;
+ int prop_len;
+
+ if (np->parent->plat_type == PLAT_TYPE_NIU)
+ dp = np->op->node;
+ else
+ dp = pci_device_to_OF_node(np->pdev);
+
+ phy_type = of_get_property(dp, "phy-type", &prop_len);
+ if (!phy_type) {
+ dev_err(np->device, PFX "%s: OF node lacks "
+ "phy-type property\n",
+ dp->full_name);
+ return -EINVAL;
+ }
+
+ if (!strcmp(phy_type, "none"))
+ return -ENODEV;
+
+ strcpy(np->vpd.phy_type, phy_type);
+
+ if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+ dev_err(np->device, PFX "%s: Illegal phy string [%s].\n",
+ dp->full_name, np->vpd.phy_type);
+ return -EINVAL;
+ }
+
+ mac_addr = of_get_property(dp, "local-mac-address", &prop_len);
+ if (!mac_addr) {
+ dev_err(np->device, PFX "%s: OF node lacks "
+ "local-mac-address property\n",
+ dp->full_name);
+ return -EINVAL;
+ }
+ if (prop_len != dev->addr_len) {
+ dev_err(np->device, PFX "%s: OF MAC address prop len (%d) "
+ "is wrong.\n",
+ dp->full_name, prop_len);
+ }
+ memcpy(dev->perm_addr, mac_addr, dev->addr_len);
+ if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+ int i;
+
+ dev_err(np->device, PFX "%s: OF MAC address is invalid\n",
+ dp->full_name);
+ dev_err(np->device, PFX "%s: [ \n",
+ dp->full_name);
+ for (i = 0; i < 6; i++)
+ printk("%02x ", dev->perm_addr[i]);
+ printk("]\n");
+ return -EINVAL;
+ }
+
+ memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
+static int __devinit niu_get_invariants(struct niu *np)
+{
+ int err, have_props;
+ u32 offset;
+
+ err = niu_get_of_props(np);
+ if (err == -ENODEV)
+ return err;
+
+ have_props = !err;
+
+ err = niu_get_and_validate_port(np);
+ if (err)
+ return err;
+
+ err = niu_init_mac_ipp_pcs_base(np);
+ if (err)
+ return err;
+
+ if (!have_props) {
+ if (np->parent->plat_type == PLAT_TYPE_NIU)
+ return -EINVAL;
+
+ nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE);
+ offset = niu_pci_vpd_offset(np);
+ niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n",
+ offset);
+ if (offset)
+ niu_pci_vpd_fetch(np, offset);
+ nw64(ESPC_PIO_EN, 0);
+
+ if (np->flags & NIU_FLAGS_VPD_VALID)
+ niu_pci_vpd_validate(np);
+
+ if (!(np->flags & NIU_FLAGS_VPD_VALID)) {
+ err = niu_pci_probe_sprom(np);
+ if (err)
+ return err;
+ }
+ }
+
+ err = niu_probe_ports(np);
+ if (err)
+ return err;
+
+ niu_ldg_init(np);
+
+ niu_classifier_swstate_init(np);
+ niu_link_config_init(np);
+
+ err = niu_determine_phy_disposition(np);
+ if (!err)
+ err = niu_init_link(np);
+
+ return err;
+}
+
+static LIST_HEAD(niu_parent_list);
+static DEFINE_MUTEX(niu_parent_lock);
+static int niu_parent_index;
+
+static ssize_t show_port_phy(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+ u32 port_phy = p->port_phy;
+ char *orig_buf = buf;
+ int i;
+
+ if (port_phy == PORT_PHY_UNKNOWN ||
+ port_phy == PORT_PHY_INVALID)
+ return 0;
+
+ for (i = 0; i < p->num_ports; i++) {
+ const char *type_str;
+ int type;
+
+ type = phy_decode(port_phy, i);
+ if (type == PORT_TYPE_10G)
+ type_str = "10G";
+ else
+ type_str = "1G";
+ buf += sprintf(buf,
+ (i == 0) ? "%s" : " %s",
+ type_str);
+ }
+ buf += sprintf(buf, "\n");
+ return buf - orig_buf;
+}
+
+static ssize_t show_plat_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+ const char *type_str;
+
+ switch (p->plat_type) {
+ case PLAT_TYPE_ATLAS:
+ type_str = "atlas";
+ break;
+ case PLAT_TYPE_NIU:
+ type_str = "niu";
+ break;
+ case PLAT_TYPE_VF_P0:
+ type_str = "vf_p0";
+ break;
+ case PLAT_TYPE_VF_P1:
+ type_str = "vf_p1";
+ break;
+ default:
+ type_str = "unknown";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", type_str);
+}
+
+static ssize_t __show_chan_per_port(struct device *dev,
+ struct device_attribute *attr, char *buf,
+ int rx)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+ char *orig_buf = buf;
+ u8 *arr;
+ int i;
+
+ arr = (rx ? p->rxchan_per_port : p->txchan_per_port);
+
+ for (i = 0; i < p->num_ports; i++) {
+ buf += sprintf(buf,
+ (i == 0) ? "%d" : " %d",
+ arr[i]);
+ }
+ buf += sprintf(buf, "\n");
+
+ return buf - orig_buf;
+}
+
+static ssize_t show_rxchan_per_port(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return __show_chan_per_port(dev, attr, buf, 1);
+}
+
+static ssize_t show_txchan_per_port(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return __show_chan_per_port(dev, attr, buf, 1);
+}
+
+static ssize_t show_num_ports(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+
+ return sprintf(buf, "%d\n", p->num_ports);
+}
+
+static struct device_attribute niu_parent_attributes[] = {
+ __ATTR(port_phy, S_IRUGO, show_port_phy, NULL),
+ __ATTR(plat_type, S_IRUGO, show_plat_type, NULL),
+ __ATTR(rxchan_per_port, S_IRUGO, show_rxchan_per_port, NULL),
+ __ATTR(txchan_per_port, S_IRUGO, show_txchan_per_port, NULL),
+ __ATTR(num_ports, S_IRUGO, show_num_ports, NULL),
+ {}
+};
+
+static struct niu_parent * __devinit niu_new_parent(struct niu *np,
+ union niu_parent_id *id,
+ u8 ptype)
+{
+ struct platform_device *plat_dev;
+ struct niu_parent *p;
+ int i;
+
+ niudbg(PROBE, "niu_new_parent: Creating new parent.\n");
+
+ plat_dev = platform_device_register_simple("niu", niu_parent_index,
+ NULL, 0);
+ if (!plat_dev)
+ return NULL;
+
+ for (i = 0; attr_name(niu_parent_attributes[i]); i++) {
+ int err = device_create_file(&plat_dev->dev,
+ &niu_parent_attributes[i]);
+ if (err)
+ goto fail_unregister;
+ }
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ goto fail_unregister;
+
+ p->index = niu_parent_index++;
+
+ plat_dev->dev.platform_data = p;
+ p->plat_dev = plat_dev;
+
+ memcpy(&p->id, id, sizeof(*id));
+ p->plat_type = ptype;
+ INIT_LIST_HEAD(&p->list);
+ atomic_set(&p->refcnt, 0);
+ list_add(&p->list, &niu_parent_list);
+ spin_lock_init(&p->lock);
+
+ p->rxdma_clock_divider = 7500;
+
+ p->tcam_num_entries = NIU_PCI_TCAM_ENTRIES;
+ if (p->plat_type == PLAT_TYPE_NIU)
+ p->tcam_num_entries = NIU_NONPCI_TCAM_ENTRIES;
+
+ for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
+ int index = i - CLASS_CODE_USER_PROG1;
+
+ p->tcam_key[index] = TCAM_KEY_TSEL;
+ p->flow_key[index] = (FLOW_KEY_IPSA |
+ FLOW_KEY_IPDA |
+ FLOW_KEY_PROTO |
+ (FLOW_KEY_L4_BYTE12 <<
+ FLOW_KEY_L4_0_SHIFT) |
+ (FLOW_KEY_L4_BYTE12 <<
+ FLOW_KEY_L4_1_SHIFT));
+ }
+
+ for (i = 0; i < LDN_MAX + 1; i++)
+ p->ldg_map[i] = LDG_INVALID;
+
+ return p;
+
+fail_unregister:
+ platform_device_unregister(plat_dev);
+ return NULL;
+}
+
+static struct niu_parent * __devinit niu_get_parent(struct niu *np,
+ union niu_parent_id *id,
+ u8 ptype)
+{
+ struct niu_parent *p, *tmp;
+ int port = np->port;
+
+ niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n",
+ ptype, port);
+
+ mutex_lock(&niu_parent_lock);
+ p = NULL;
+ list_for_each_entry(tmp, &niu_parent_list, list) {
+ if (!memcmp(id, &tmp->id, sizeof(*id))) {
+ p = tmp;
+ break;
+ }
+ }
+ if (!p)
+ p = niu_new_parent(np, id, ptype);
+
+ if (p) {
+ char port_name[6];
+ int err;
+
+ sprintf(port_name, "port%d", port);
+ err = sysfs_create_link(&p->plat_dev->dev.kobj,
+ &np->device->kobj,
+ port_name);
+ if (!err) {
+ p->ports[port] = np;
+ atomic_inc(&p->refcnt);
+ }
+ }
+ mutex_unlock(&niu_parent_lock);
+
+ return p;
+}
+
+static void niu_put_parent(struct niu *np)
+{
+ struct niu_parent *p = np->parent;
+ u8 port = np->port;
+ char port_name[6];
+
+ BUG_ON(!p || p->ports[port] != np);
+
+ niudbg(PROBE, "niu_put_parent: port[%u]\n", port);
+
+ sprintf(port_name, "port%d", port);
+
+ mutex_lock(&niu_parent_lock);
+
+ sysfs_remove_link(&p->plat_dev->dev.kobj, port_name);
+
+ p->ports[port] = NULL;
+ np->parent = NULL;
+
+ if (atomic_dec_and_test(&p->refcnt)) {
+ list_del(&p->list);
+ platform_device_unregister(p->plat_dev);
+ }
+
+ mutex_unlock(&niu_parent_lock);
+}
+
+static void *niu_pci_alloc_coherent(struct device *dev, size_t size,
+ u64 *handle, gfp_t flag)
+{
+ dma_addr_t dh;
+ void *ret;
+
+ ret = dma_alloc_coherent(dev, size, &dh, flag);
+ if (ret)
+ *handle = dh;
+ return ret;
+}
+
+static void niu_pci_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, u64 handle)
+{
+ dma_free_coherent(dev, size, cpu_addr, handle);
+}
+
+static u64 niu_pci_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ return dma_map_page(dev, page, offset, size, direction);
+}
+
+static void niu_pci_unmap_page(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction)
+{
+ return dma_unmap_page(dev, dma_address, size, direction);
+}
+
+static u64 niu_pci_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return dma_map_single(dev, cpu_addr, size, direction);
+}
+
+static void niu_pci_unmap_single(struct device *dev, u64 dma_address,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ dma_unmap_single(dev, dma_address, size, direction);
+}
+
+static const struct niu_ops niu_pci_ops = {
+ .alloc_coherent = niu_pci_alloc_coherent,
+ .free_coherent = niu_pci_free_coherent,
+ .map_page = niu_pci_map_page,
+ .unmap_page = niu_pci_unmap_page,
+ .map_single = niu_pci_map_single,
+ .unmap_single = niu_pci_unmap_single,
+};
+
+static void __devinit niu_driver_version(void)
+{
+ static int niu_version_printed;
+
+ if (niu_version_printed++ == 0)
+ pr_info("%s", version);
+}
+
+static struct net_device * __devinit niu_alloc_and_init(
+ struct device *gen_dev, struct pci_dev *pdev,
+ struct of_device *op, const struct niu_ops *ops,
+ u8 port)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct niu));
+ struct niu *np;
+
+ if (!dev) {
+ dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n");
+ return NULL;
+ }
+
+ SET_NETDEV_DEV(dev, gen_dev);
+
+ np = netdev_priv(dev);
+ np->dev = dev;
+ np->pdev = pdev;
+ np->op = op;
+ np->device = gen_dev;
+ np->ops = ops;
+
+ np->msg_enable = niu_debug;
+
+ spin_lock_init(&np->lock);
+ INIT_WORK(&np->reset_task, niu_reset_task);
+
+ np->port = port;
+
+ return dev;
+}
+
+static void __devinit niu_assign_netdev_ops(struct net_device *dev)
+{
+ dev->open = niu_open;
+ dev->stop = niu_close;
+ dev->get_stats = niu_get_stats;
+ dev->set_multicast_list = niu_set_rx_mode;
+ dev->set_mac_address = niu_set_mac_addr;
+ dev->do_ioctl = niu_ioctl;
+ dev->tx_timeout = niu_tx_timeout;
+ dev->hard_start_xmit = niu_start_xmit;
+ dev->ethtool_ops = &niu_ethtool_ops;
+ dev->watchdog_timeo = NIU_TX_TIMEOUT;
+ dev->change_mtu = niu_change_mtu;
+}
+
+static void __devinit niu_device_announce(struct niu *np)
+{
+ struct net_device *dev = np->dev;
+ int i;
+
+ pr_info("%s: NIU Ethernet ", dev->name);
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i],
+ i == 5 ? '\n' : ':');
+
+ pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
+ dev->name,
+ (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
+ (np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
+ (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"),
+ (np->mac_xcvr == MAC_XCVR_MII ? "MII" :
+ (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
+ np->vpd.phy_type);
+}
+
+static int __devinit niu_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ unsigned long niureg_base, niureg_len;
+ union niu_parent_id parent_id;
+ struct net_device *dev;
+ struct niu *np;
+ int err, pos;
+ u64 dma_mask;
+ u16 val16;
+
+ niu_driver_version();
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Cannot enable PCI device, "
+ "aborting.\n");
+ return err;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+ dev_err(&pdev->dev, PFX "Cannot find proper PCI device "
+ "base addresses, aborting.\n");
+ err = -ENODEV;
+ goto err_out_disable_pdev;
+ }
+
+ err = pci_request_regions(pdev, DRV_MODULE_NAME);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, "
+ "aborting.\n");
+ goto err_out_disable_pdev;
+ }
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (pos <= 0) {
+ dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
+ "aborting.\n");
+ goto err_out_free_res;
+ }
+
+ dev = niu_alloc_and_init(&pdev->dev, pdev, NULL,
+ &niu_pci_ops, PCI_FUNC(pdev->devfn));
+ if (!dev) {
+ err = -ENOMEM;
+ goto err_out_free_res;
+ }
+ np = netdev_priv(dev);
+
+ memset(&parent_id, 0, sizeof(parent_id));
+ parent_id.pci.domain = pci_domain_nr(pdev->bus);
+ parent_id.pci.bus = pdev->bus->number;
+ parent_id.pci.device = PCI_SLOT(pdev->devfn);
+
+ np->parent = niu_get_parent(np, &parent_id,
+ PLAT_TYPE_ATLAS);
+ if (!np->parent) {
+ err = -ENOMEM;
+ goto err_out_free_dev;
+ }
+
+ pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
+ val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
+ val16 |= (PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE |
+ PCI_EXP_DEVCTL_RELAX_EN);
+ pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
+
+ dma_mask = DMA_44BIT_MASK;
+ err = pci_set_dma_mask(pdev, dma_mask);
+ if (!err) {
+ dev->features |= NETIF_F_HIGHDMA;
+ err = pci_set_consistent_dma_mask(pdev, dma_mask);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Unable to obtain 44 bit "
+ "DMA for consistent allocations, "
+ "aborting.\n");
+ goto err_out_release_parent;
+ }
+ }
+ if (err || dma_mask == DMA_32BIT_MASK) {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, PFX "No usable DMA configuration, "
+ "aborting.\n");
+ goto err_out_release_parent;
+ }
+ }
+
+ dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+
+ niureg_base = pci_resource_start(pdev, 0);
+ niureg_len = pci_resource_len(pdev, 0);
+
+ np->regs = ioremap_nocache(niureg_base, niureg_len);
+ if (!np->regs) {
+ dev_err(&pdev->dev, PFX "Cannot map device registers, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_release_parent;
+ }
+
+ pci_set_master(pdev);
+ pci_save_state(pdev);
+
+ dev->irq = pdev->irq;
+
+ niu_assign_netdev_ops(dev);
+
+ err = niu_get_invariants(np);
+ if (err) {
+ if (err != -ENODEV)
+ dev_err(&pdev->dev, PFX "Problem fetching invariants "
+ "of chip, aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ niu_device_announce(np);
+
+ return 0;
+
+err_out_iounmap:
+ if (np->regs) {
+ iounmap(np->regs);
+ np->regs = NULL;
+ }
+
+err_out_release_parent:
+ niu_put_parent(np);
+
+err_out_free_dev:
+ free_netdev(dev);
+
+err_out_free_res:
+ pci_release_regions(pdev);
+
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+static void __devexit niu_pci_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (dev) {
+ struct niu *np = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ if (np->regs) {
+ iounmap(np->regs);
+ np->regs = NULL;
+ }
+
+ niu_ldg_free(np);
+
+ niu_put_parent(np);
+
+ free_netdev(dev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+static int niu_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct niu *np = netdev_priv(dev);
+ unsigned long flags;
+
+ if (!netif_running(dev))
+ return 0;
+
+ flush_scheduled_work();
+ niu_netif_stop(np);
+
+ del_timer_sync(&np->timer);
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_enable_interrupts(np, 0);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ netif_device_detach(dev);
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_stop_hw(np);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ pci_save_state(pdev);
+
+ return 0;
+}
+
+static int niu_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct niu *np = netdev_priv(dev);
+ unsigned long flags;
+ int err;
+
+ if (!netif_running(dev))
+ return 0;
+
+ pci_restore_state(pdev);
+
+ netif_device_attach(dev);
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ np->timer.expires = jiffies + HZ;
+ add_timer(&np->timer);
+ niu_netif_start(np);
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return err;
+}
+
+static struct pci_driver niu_pci_driver = {
+ .name = DRV_MODULE_NAME,
+ .id_table = niu_pci_tbl,
+ .probe = niu_pci_init_one,
+ .remove = __devexit_p(niu_pci_remove_one),
+ .suspend = niu_suspend,
+ .resume = niu_resume,
+};
+
+#ifdef CONFIG_SPARC64
+static void *niu_phys_alloc_coherent(struct device *dev, size_t size,
+ u64 *dma_addr, gfp_t flag)
+{
+ unsigned long order = get_order(size);
+ unsigned long page = __get_free_pages(flag, order);
+
+ if (page == 0UL)
+ return NULL;
+ memset((char *)page, 0, PAGE_SIZE << order);
+ *dma_addr = __pa(page);
+
+ return (void *) page;
+}
+
+static void niu_phys_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, u64 handle)
+{
+ unsigned long order = get_order(size);
+
+ free_pages((unsigned long) cpu_addr, order);
+}
+
+static u64 niu_phys_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ return page_to_phys(page) + offset;
+}
+
+static void niu_phys_unmap_page(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction)
+{
+ /* Nothing to do. */
+}
+
+static u64 niu_phys_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return __pa(cpu_addr);
+}
+
+static void niu_phys_unmap_single(struct device *dev, u64 dma_address,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ /* Nothing to do. */
+}
+
+static const struct niu_ops niu_phys_ops = {
+ .alloc_coherent = niu_phys_alloc_coherent,
+ .free_coherent = niu_phys_free_coherent,
+ .map_page = niu_phys_map_page,
+ .unmap_page = niu_phys_unmap_page,
+ .map_single = niu_phys_map_single,
+ .unmap_single = niu_phys_unmap_single,
+};
+
+static unsigned long res_size(struct resource *r)
+{
+ return r->end - r->start + 1UL;
+}
+
+static int __devinit niu_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ union niu_parent_id parent_id;
+ struct net_device *dev;
+ struct niu *np;
+ const u32 *reg;
+ int err;
+
+ niu_driver_version();
+
+ reg = of_get_property(op->node, "reg", NULL);
+ if (!reg) {
+ dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n",
+ op->node->full_name);
+ return -ENODEV;
+ }
+
+ dev = niu_alloc_and_init(&op->dev, NULL, op,
+ &niu_phys_ops, reg[0] & 0x1);
+ if (!dev) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ np = netdev_priv(dev);
+
+ memset(&parent_id, 0, sizeof(parent_id));
+ parent_id.of = of_get_parent(op->node);
+
+ np->parent = niu_get_parent(np, &parent_id,
+ PLAT_TYPE_NIU);
+ if (!np->parent) {
+ err = -ENOMEM;
+ goto err_out_free_dev;
+ }
+
+ dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+
+ np->regs = of_ioremap(&op->resource[1], 0,
+ res_size(&op->resource[1]),
+ "niu regs");
+ if (!np->regs) {
+ dev_err(&op->dev, PFX "Cannot map device registers, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_release_parent;
+ }
+
+ np->vir_regs_1 = of_ioremap(&op->resource[2], 0,
+ res_size(&op->resource[2]),
+ "niu vregs-1");
+ if (!np->vir_regs_1) {
+ dev_err(&op->dev, PFX "Cannot map device vir registers 1, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ np->vir_regs_2 = of_ioremap(&op->resource[3], 0,
+ res_size(&op->resource[3]),
+ "niu vregs-2");
+ if (!np->vir_regs_2) {
+ dev_err(&op->dev, PFX "Cannot map device vir registers 2, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ niu_assign_netdev_ops(dev);
+
+ err = niu_get_invariants(np);
+ if (err) {
+ if (err != -ENODEV)
+ dev_err(&op->dev, PFX "Problem fetching invariants "
+ "of chip, aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&op->dev, PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ dev_set_drvdata(&op->dev, dev);
+
+ niu_device_announce(np);
+
+ return 0;
+
+err_out_iounmap:
+ if (np->vir_regs_1) {
+ of_iounmap(&op->resource[2], np->vir_regs_1,
+ res_size(&op->resource[2]));
+ np->vir_regs_1 = NULL;
+ }
+
+ if (np->vir_regs_2) {
+ of_iounmap(&op->resource[3], np->vir_regs_2,
+ res_size(&op->resource[3]));
+ np->vir_regs_2 = NULL;
+ }
+
+ if (np->regs) {
+ of_iounmap(&op->resource[1], np->regs,
+ res_size(&op->resource[1]));
+ np->regs = NULL;
+ }
+
+err_out_release_parent:
+ niu_put_parent(np);
+
+err_out_free_dev:
+ free_netdev(dev);
+
+err_out:
+ return err;
+}
+
+static int __devexit niu_of_remove(struct of_device *op)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ if (dev) {
+ struct niu *np = netdev_priv(dev);
+
+ unregister_netdev(dev);
+
+ if (np->vir_regs_1) {
+ of_iounmap(&op->resource[2], np->vir_regs_1,
+ res_size(&op->resource[2]));
+ np->vir_regs_1 = NULL;
+ }
+
+ if (np->vir_regs_2) {
+ of_iounmap(&op->resource[3], np->vir_regs_2,
+ res_size(&op->resource[3]));
+ np->vir_regs_2 = NULL;
+ }
+
+ if (np->regs) {
+ of_iounmap(&op->resource[1], np->regs,
+ res_size(&op->resource[1]));
+ np->regs = NULL;
+ }
+
+ niu_ldg_free(np);
+
+ niu_put_parent(np);
+
+ free_netdev(dev);
+ dev_set_drvdata(&op->dev, NULL);
+ }
+ return 0;
+}
+
+static struct of_device_id niu_match[] = {
+ {
+ .name = "network",
+ .compatible = "SUNW,niusl",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, niu_match);
+
+static struct of_platform_driver niu_of_driver = {
+ .name = "niu",
+ .match_table = niu_match,
+ .probe = niu_of_probe,
+ .remove = __devexit_p(niu_of_remove),
+};
+
+#endif /* CONFIG_SPARC64 */
+
+static int __init niu_init(void)
+{
+ int err = 0;
+
+ BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) ||
+ ((PAGE_SIZE > 32 * 1024) &&
+ ((PAGE_SIZE % (32 * 1024)) != 0 &&
+ (PAGE_SIZE % (16 * 1024)) != 0 &&
+ (PAGE_SIZE % (8 * 1024)) != 0 &&
+ (PAGE_SIZE % (4 * 1024)) != 0)));
+
+ niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
+
+#ifdef CONFIG_SPARC64
+ err = of_register_driver(&niu_of_driver, &of_bus_type);
+#endif
+
+ if (!err) {
+ err = pci_register_driver(&niu_pci_driver);
+#ifdef CONFIG_SPARC64
+ if (err)
+ of_unregister_driver(&niu_of_driver);
+#endif
+ }
+
+ return err;
+}
+
+static void __exit niu_exit(void)
+{
+ pci_unregister_driver(&niu_pci_driver);
+#ifdef CONFIG_SPARC64
+ of_unregister_driver(&niu_of_driver);
+#endif
+}
+
+module_init(niu_init);
+module_exit(niu_exit);
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
new file mode 100644
index 000000000000..10e3f111b6d5
--- /dev/null
+++ b/drivers/net/niu.h
@@ -0,0 +1,3222 @@
+/* niu.h: Definitions for Neptune ethernet driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _NIU_H
+#define _NIU_H
+
+#define PIO 0x000000UL
+#define FZC_PIO 0x080000UL
+#define FZC_MAC 0x180000UL
+#define FZC_IPP 0x280000UL
+#define FFLP 0x300000UL
+#define FZC_FFLP 0x380000UL
+#define PIO_VADDR 0x400000UL
+#define ZCP 0x500000UL
+#define FZC_ZCP 0x580000UL
+#define DMC 0x600000UL
+#define FZC_DMC 0x680000UL
+#define TXC 0x700000UL
+#define FZC_TXC 0x780000UL
+#define PIO_LDSV 0x800000UL
+#define PIO_PIO_LDGIM 0x900000UL
+#define PIO_IMASK0 0xa00000UL
+#define PIO_IMASK1 0xb00000UL
+#define FZC_PROM 0xc80000UL
+#define FZC_PIM 0xd80000UL
+
+#define LDSV0(LDG) (PIO_LDSV + 0x00000UL + (LDG) * 0x2000UL)
+#define LDSV1(LDG) (PIO_LDSV + 0x00008UL + (LDG) * 0x2000UL)
+#define LDSV2(LDG) (PIO_LDSV + 0x00010UL + (LDG) * 0x2000UL)
+
+#define LDG_IMGMT(LDG) (PIO_LDSV + 0x00018UL + (LDG) * 0x2000UL)
+#define LDG_IMGMT_ARM 0x0000000080000000ULL
+#define LDG_IMGMT_TIMER 0x000000000000003fULL
+
+#define LD_IM0(IDX) (PIO_IMASK0 + 0x00000UL + (IDX) * 0x2000UL)
+#define LD_IM0_MASK 0x0000000000000003ULL
+
+#define LD_IM1(IDX) (PIO_IMASK1 + 0x00000UL + (IDX) * 0x2000UL)
+#define LD_IM1_MASK 0x0000000000000003ULL
+
+#define LDG_TIMER_RES (FZC_PIO + 0x00008UL)
+#define LDG_TIMER_RES_VAL 0x00000000000fffffULL
+
+#define DIRTY_TID_CTL (FZC_PIO + 0x00010UL)
+#define DIRTY_TID_CTL_NPTHRED 0x00000000003f0000ULL
+#define DIRTY_TID_CTL_RDTHRED 0x00000000000003f0ULL
+#define DIRTY_TID_CTL_DTIDCLR 0x0000000000000002ULL
+#define DIRTY_TID_CTL_DTIDENAB 0x0000000000000001ULL
+
+#define DIRTY_TID_STAT (FZC_PIO + 0x00018UL)
+#define DIRTY_TID_STAT_NPWSTAT 0x0000000000003f00ULL
+#define DIRTY_TID_STAT_RDSTAT 0x000000000000003fULL
+
+#define RST_CTL (FZC_PIO + 0x00038UL)
+#define RST_CTL_MAC_RST3 0x0000000000400000ULL
+#define RST_CTL_MAC_RST2 0x0000000000200000ULL
+#define RST_CTL_MAC_RST1 0x0000000000100000ULL
+#define RST_CTL_MAC_RST0 0x0000000000080000ULL
+#define RST_CTL_ACK_TO_EN 0x0000000000000800ULL
+#define RST_CTL_ACK_TO_VAL 0x00000000000007feULL
+
+#define SMX_CFIG_DAT (FZC_PIO + 0x00040UL)
+#define SMX_CFIG_DAT_RAS_DET 0x0000000080000000ULL
+#define SMX_CFIG_DAT_RAS_INJ 0x0000000040000000ULL
+#define SMX_CFIG_DAT_XACT_TO 0x000000000fffffffULL
+
+#define SMX_INT_STAT (FZC_PIO + 0x00048UL)
+#define SMX_INT_STAT_STAT 0x00000000ffffffffULL
+
+#define SMX_CTL (FZC_PIO + 0x00050UL)
+#define SMX_CTL_CTL 0x00000000ffffffffULL
+
+#define SMX_DBG_VEC (FZC_PIO + 0x00058UL)
+#define SMX_DBG_VEC_VEC 0x00000000ffffffffULL
+
+#define PIO_DBG_SEL (FZC_PIO + 0x00060UL)
+#define PIO_DBG_SEL_SEL 0x000000000000003fULL
+
+#define PIO_TRAIN_VEC (FZC_PIO + 0x00068UL)
+#define PIO_TRAIN_VEC_VEC 0x00000000ffffffffULL
+
+#define PIO_ARB_CTL (FZC_PIO + 0x00070UL)
+#define PIO_ARB_CTL_CTL 0x00000000ffffffffULL
+
+#define PIO_ARB_DBG_VEC (FZC_PIO + 0x00078UL)
+#define PIO_ARB_DBG_VEC_VEC 0x00000000ffffffffULL
+
+#define SYS_ERR_MASK (FZC_PIO + 0x00090UL)
+#define SYS_ERR_MASK_META2 0x0000000000000400ULL
+#define SYS_ERR_MASK_META1 0x0000000000000200ULL
+#define SYS_ERR_MASK_PEU 0x0000000000000100ULL
+#define SYS_ERR_MASK_TXC 0x0000000000000080ULL
+#define SYS_ERR_MASK_RDMC 0x0000000000000040ULL
+#define SYS_ERR_MASK_TDMC 0x0000000000000020ULL
+#define SYS_ERR_MASK_ZCP 0x0000000000000010ULL
+#define SYS_ERR_MASK_FFLP 0x0000000000000008ULL
+#define SYS_ERR_MASK_IPP 0x0000000000000004ULL
+#define SYS_ERR_MASK_MAC 0x0000000000000002ULL
+#define SYS_ERR_MASK_SMX 0x0000000000000001ULL
+
+#define SYS_ERR_STAT (FZC_PIO + 0x00098UL)
+#define SYS_ERR_STAT_META2 0x0000000000000400ULL
+#define SYS_ERR_STAT_META1 0x0000000000000200ULL
+#define SYS_ERR_STAT_PEU 0x0000000000000100ULL
+#define SYS_ERR_STAT_TXC 0x0000000000000080ULL
+#define SYS_ERR_STAT_RDMC 0x0000000000000040ULL
+#define SYS_ERR_STAT_TDMC 0x0000000000000020ULL
+#define SYS_ERR_STAT_ZCP 0x0000000000000010ULL
+#define SYS_ERR_STAT_FFLP 0x0000000000000008ULL
+#define SYS_ERR_STAT_IPP 0x0000000000000004ULL
+#define SYS_ERR_STAT_MAC 0x0000000000000002ULL
+#define SYS_ERR_STAT_SMX 0x0000000000000001ULL
+
+#define SID(LDG) (FZC_PIO + 0x10200UL + (LDG) * 8UL)
+#define SID_FUNC 0x0000000000000060ULL
+#define SID_FUNC_SHIFT 5
+#define SID_VECTOR 0x000000000000001fULL
+#define SID_VECTOR_SHIFT 0
+
+#define LDG_NUM(LDN) (FZC_PIO + 0x20000UL + (LDN) * 8UL)
+
+#define XMAC_PORT0_OFF (FZC_MAC + 0x000000)
+#define XMAC_PORT1_OFF (FZC_MAC + 0x006000)
+#define BMAC_PORT2_OFF (FZC_MAC + 0x00c000)
+#define BMAC_PORT3_OFF (FZC_MAC + 0x010000)
+
+/* XMAC registers, offset from np->mac_regs */
+
+#define XTXMAC_SW_RST 0x00000UL
+#define XTXMAC_SW_RST_REG_RS 0x0000000000000002ULL
+#define XTXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL
+
+#define XRXMAC_SW_RST 0x00008UL
+#define XRXMAC_SW_RST_REG_RS 0x0000000000000002ULL
+#define XRXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL
+
+#define XTXMAC_STATUS 0x00020UL
+#define XTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL
+#define XTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL
+#define XTXMAC_STATUS_TXFIFO_XFR_ERR 0x0000000000000010ULL
+#define XTXMAC_STATUS_TXMAC_OFLOW 0x0000000000000008ULL
+#define XTXMAC_STATUS_MAX_PSIZE_ERR 0x0000000000000004ULL
+#define XTXMAC_STATUS_TXMAC_UFLOW 0x0000000000000002ULL
+#define XTXMAC_STATUS_FRAME_XMITED 0x0000000000000001ULL
+
+#define XRXMAC_STATUS 0x00028UL
+#define XRXMAC_STATUS_RXHIST7_CNT_EXP 0x0000000000100000ULL
+#define XRXMAC_STATUS_LCL_FLT_STATUS 0x0000000000080000ULL
+#define XRXMAC_STATUS_RFLT_DET 0x0000000000040000ULL
+#define XRXMAC_STATUS_LFLT_CNT_EXP 0x0000000000020000ULL
+#define XRXMAC_STATUS_PHY_MDINT 0x0000000000010000ULL
+#define XRXMAC_STATUS_ALIGNERR_CNT_EXP 0x0000000000010000ULL
+#define XRXMAC_STATUS_RXFRAG_CNT_EXP 0x0000000000008000ULL
+#define XRXMAC_STATUS_RXMULTF_CNT_EXP 0x0000000000004000ULL
+#define XRXMAC_STATUS_RXBCAST_CNT_EXP 0x0000000000002000ULL
+#define XRXMAC_STATUS_RXHIST6_CNT_EXP 0x0000000000001000ULL
+#define XRXMAC_STATUS_RXHIST5_CNT_EXP 0x0000000000000800ULL
+#define XRXMAC_STATUS_RXHIST4_CNT_EXP 0x0000000000000400ULL
+#define XRXMAC_STATUS_RXHIST3_CNT_EXP 0x0000000000000200ULL
+#define XRXMAC_STATUS_RXHIST2_CNT_EXP 0x0000000000000100ULL
+#define XRXMAC_STATUS_RXHIST1_CNT_EXP 0x0000000000000080ULL
+#define XRXMAC_STATUS_RXOCTET_CNT_EXP 0x0000000000000040ULL
+#define XRXMAC_STATUS_CVIOLERR_CNT_EXP 0x0000000000000020ULL
+#define XRXMAC_STATUS_LENERR_CNT_EXP 0x0000000000000010ULL
+#define XRXMAC_STATUS_CRCERR_CNT_EXP 0x0000000000000008ULL
+#define XRXMAC_STATUS_RXUFLOW 0x0000000000000004ULL
+#define XRXMAC_STATUS_RXOFLOW 0x0000000000000002ULL
+#define XRXMAC_STATUS_FRAME_RCVD 0x0000000000000001ULL
+
+#define XMAC_FC_STAT 0x00030UL
+#define XMAC_FC_STAT_RX_RCV_PAUSE_TIME 0x00000000ffff0000ULL
+#define XMAC_FC_STAT_TX_MAC_NPAUSE 0x0000000000000004ULL
+#define XMAC_FC_STAT_TX_MAC_PAUSE 0x0000000000000002ULL
+#define XMAC_FC_STAT_RX_MAC_RPAUSE 0x0000000000000001ULL
+
+#define XTXMAC_STAT_MSK 0x00040UL
+#define XTXMAC_STAT_MSK_FRAME_CNT_EXP 0x0000000000000800ULL
+#define XTXMAC_STAT_MSK_BYTE_CNT_EXP 0x0000000000000400ULL
+#define XTXMAC_STAT_MSK_TXFIFO_XFR_ERR 0x0000000000000010ULL
+#define XTXMAC_STAT_MSK_TXMAC_OFLOW 0x0000000000000008ULL
+#define XTXMAC_STAT_MSK_MAX_PSIZE_ERR 0x0000000000000004ULL
+#define XTXMAC_STAT_MSK_TXMAC_UFLOW 0x0000000000000002ULL
+#define XTXMAC_STAT_MSK_FRAME_XMITED 0x0000000000000001ULL
+
+#define XRXMAC_STAT_MSK 0x00048UL
+#define XRXMAC_STAT_MSK_LCL_FLT_STAT_MSK 0x0000000000080000ULL
+#define XRXMAC_STAT_MSK_RFLT_DET 0x0000000000040000ULL
+#define XRXMAC_STAT_MSK_LFLT_CNT_EXP 0x0000000000020000ULL
+#define XRXMAC_STAT_MSK_PHY_MDINT 0x0000000000010000ULL
+#define XRXMAC_STAT_MSK_RXFRAG_CNT_EXP 0x0000000000008000ULL
+#define XRXMAC_STAT_MSK_RXMULTF_CNT_EXP 0x0000000000004000ULL
+#define XRXMAC_STAT_MSK_RXBCAST_CNT_EXP 0x0000000000002000ULL
+#define XRXMAC_STAT_MSK_RXHIST6_CNT_EXP 0x0000000000001000ULL
+#define XRXMAC_STAT_MSK_RXHIST5_CNT_EXP 0x0000000000000800ULL
+#define XRXMAC_STAT_MSK_RXHIST4_CNT_EXP 0x0000000000000400ULL
+#define XRXMAC_STAT_MSK_RXHIST3_CNT_EXP 0x0000000000000200ULL
+#define XRXMAC_STAT_MSK_RXHIST2_CNT_EXP 0x0000000000000100ULL
+#define XRXMAC_STAT_MSK_RXHIST1_CNT_EXP 0x0000000000000080ULL
+#define XRXMAC_STAT_MSK_RXOCTET_CNT_EXP 0x0000000000000040ULL
+#define XRXMAC_STAT_MSK_CVIOLERR_CNT_EXP 0x0000000000000020ULL
+#define XRXMAC_STAT_MSK_LENERR_CNT_EXP 0x0000000000000010ULL
+#define XRXMAC_STAT_MSK_CRCERR_CNT_EXP 0x0000000000000008ULL
+#define XRXMAC_STAT_MSK_RXUFLOW_CNT_EXP 0x0000000000000004ULL
+#define XRXMAC_STAT_MSK_RXOFLOW_CNT_EXP 0x0000000000000002ULL
+#define XRXMAC_STAT_MSK_FRAME_RCVD 0x0000000000000001ULL
+
+#define XMAC_FC_MSK 0x00050UL
+#define XMAC_FC_MSK_TX_MAC_NPAUSE 0x0000000000000004ULL
+#define XMAC_FC_MSK_TX_MAC_PAUSE 0x0000000000000002ULL
+#define XMAC_FC_MSK_RX_MAC_RPAUSE 0x0000000000000001ULL
+
+#define XMAC_CONFIG 0x00060UL
+#define XMAC_CONFIG_SEL_CLK_25MHZ 0x0000000080000000ULL
+#define XMAC_CONFIG_1G_PCS_BYPASS 0x0000000040000000ULL
+#define XMAC_CONFIG_10G_XPCS_BYPASS 0x0000000020000000ULL
+#define XMAC_CONFIG_MODE_MASK 0x0000000018000000ULL
+#define XMAC_CONFIG_MODE_XGMII 0x0000000000000000ULL
+#define XMAC_CONFIG_MODE_GMII 0x0000000008000000ULL
+#define XMAC_CONFIG_MODE_MII 0x0000000010000000ULL
+#define XMAC_CONFIG_LFS_DISABLE 0x0000000004000000ULL
+#define XMAC_CONFIG_LOOPBACK 0x0000000002000000ULL
+#define XMAC_CONFIG_TX_OUTPUT_EN 0x0000000001000000ULL
+#define XMAC_CONFIG_SEL_POR_CLK_SRC 0x0000000000800000ULL
+#define XMAC_CONFIG_LED_POLARITY 0x0000000000400000ULL
+#define XMAC_CONFIG_FORCE_LED_ON 0x0000000000200000ULL
+#define XMAC_CONFIG_PASS_FLOW_CTRL 0x0000000000100000ULL
+#define XMAC_CONFIG_RCV_PAUSE_ENABLE 0x0000000000080000ULL
+#define XMAC_CONFIG_MAC2IPP_PKT_CNT_EN 0x0000000000040000ULL
+#define XMAC_CONFIG_STRIP_CRC 0x0000000000020000ULL
+#define XMAC_CONFIG_ADDR_FILTER_EN 0x0000000000010000ULL
+#define XMAC_CONFIG_HASH_FILTER_EN 0x0000000000008000ULL
+#define XMAC_CONFIG_RX_CODEV_CHK_DIS 0x0000000000004000ULL
+#define XMAC_CONFIG_RESERVED_MULTICAST 0x0000000000002000ULL
+#define XMAC_CONFIG_RX_CRC_CHK_DIS 0x0000000000001000ULL
+#define XMAC_CONFIG_ERR_CHK_DIS 0x0000000000000800ULL
+#define XMAC_CONFIG_PROMISC_GROUP 0x0000000000000400ULL
+#define XMAC_CONFIG_PROMISCUOUS 0x0000000000000200ULL
+#define XMAC_CONFIG_RX_MAC_ENABLE 0x0000000000000100ULL
+#define XMAC_CONFIG_WARNING_MSG_EN 0x0000000000000080ULL
+#define XMAC_CONFIG_ALWAYS_NO_CRC 0x0000000000000008ULL
+#define XMAC_CONFIG_VAR_MIN_IPG_EN 0x0000000000000004ULL
+#define XMAC_CONFIG_STRETCH_MODE 0x0000000000000002ULL
+#define XMAC_CONFIG_TX_ENABLE 0x0000000000000001ULL
+
+#define XMAC_IPG 0x00080UL
+#define XMAC_IPG_STRETCH_CONST 0x0000000000e00000ULL
+#define XMAC_IPG_STRETCH_CONST_SHIFT 21
+#define XMAC_IPG_STRETCH_RATIO 0x00000000001f0000ULL
+#define XMAC_IPG_STRETCH_RATIO_SHIFT 16
+#define XMAC_IPG_IPG_MII_GMII 0x000000000000ff00ULL
+#define XMAC_IPG_IPG_MII_GMII_SHIFT 8
+#define XMAC_IPG_IPG_XGMII 0x0000000000000007ULL
+#define XMAC_IPG_IPG_XGMII_SHIFT 0
+
+#define IPG_12_15_XGMII 3
+#define IPG_16_19_XGMII 4
+#define IPG_20_23_XGMII 5
+#define IPG_12_MII_GMII 10
+#define IPG_13_MII_GMII 11
+#define IPG_14_MII_GMII 12
+#define IPG_15_MII_GMII 13
+#define IPG_16_MII_GMII 14
+
+#define XMAC_MIN 0x00088UL
+#define XMAC_MIN_RX_MIN_PKT_SIZE 0x000000003ff00000ULL
+#define XMAC_MIN_RX_MIN_PKT_SIZE_SHFT 20
+#define XMAC_MIN_SLOT_TIME 0x000000000003fc00ULL
+#define XMAC_MIN_SLOT_TIME_SHFT 10
+#define XMAC_MIN_TX_MIN_PKT_SIZE 0x00000000000003ffULL
+#define XMAC_MIN_TX_MIN_PKT_SIZE_SHFT 0
+
+#define XMAC_MAX 0x00090UL
+#define XMAC_MAX_FRAME_SIZE 0x0000000000003fffULL
+#define XMAC_MAX_FRAME_SIZE_SHFT 0
+
+#define XMAC_ADDR0 0x000a0UL
+#define XMAC_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define XMAC_ADDR1 0x000a8UL
+#define XMAC_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define XMAC_ADDR2 0x000b0UL
+#define XMAC_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define XMAC_ADDR_CMPEN 0x00208UL
+#define XMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL
+#define XMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL
+#define XMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL
+#define XMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL
+#define XMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL
+#define XMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL
+#define XMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL
+#define XMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL
+#define XMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL
+#define XMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL
+#define XMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL
+#define XMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL
+#define XMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL
+#define XMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL
+#define XMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL
+#define XMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL
+
+#define XMAC_NUM_ALT_ADDR 16
+
+#define XMAC_ALT_ADDR0(NUM) (0x00218UL + (NUM)*0x18UL)
+#define XMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define XMAC_ALT_ADDR1(NUM) (0x00220UL + (NUM)*0x18UL)
+#define XMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define XMAC_ALT_ADDR2(NUM) (0x00228UL + (NUM)*0x18UL)
+#define XMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT0 0x00818UL
+#define XMAC_ADD_FILT0_FILT0 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT1 0x00820UL
+#define XMAC_ADD_FILT1_FILT1 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT2 0x00828UL
+#define XMAC_ADD_FILT2_FILT2 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT12_MASK 0x00830UL
+#define XMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL
+
+#define XMAC_ADD_FILT00_MASK 0x00838UL
+#define XMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL
+
+#define XMAC_HASH_TBL(NUM) (0x00840UL + (NUM) * 0x8UL)
+#define XMAC_HASH_TBL_VAL 0x000000000000ffffULL
+
+#define XMAC_NUM_HOST_INFO 20
+
+#define XMAC_HOST_INFO(NUM) (0x00900UL + (NUM) * 0x8UL)
+
+#define XMAC_PA_DATA0 0x00b80UL
+#define XMAC_PA_DATA0_VAL 0x00000000ffffffffULL
+
+#define XMAC_PA_DATA1 0x00b88UL
+#define XMAC_PA_DATA1_VAL 0x00000000ffffffffULL
+
+#define XMAC_DEBUG_SEL 0x00b90UL
+#define XMAC_DEBUG_SEL_XMAC 0x0000000000000078ULL
+#define XMAC_DEBUG_SEL_MAC 0x0000000000000007ULL
+
+#define XMAC_TRAIN_VEC 0x00b98UL
+#define XMAC_TRAIN_VEC_VAL 0x00000000ffffffffULL
+
+#define RXMAC_BT_CNT 0x00100UL
+#define RXMAC_BT_CNT_COUNT 0x00000000ffffffffULL
+
+#define RXMAC_BC_FRM_CNT 0x00108UL
+#define RXMAC_BC_FRM_CNT_COUNT 0x00000000001fffffULL
+
+#define RXMAC_MC_FRM_CNT 0x00110UL
+#define RXMAC_MC_FRM_CNT_COUNT 0x00000000001fffffULL
+
+#define RXMAC_FRAG_CNT 0x00118UL
+#define RXMAC_FRAG_CNT_COUNT 0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT1 0x00120UL
+#define RXMAC_HIST_CNT1_COUNT 0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT2 0x00128UL
+#define RXMAC_HIST_CNT2_COUNT 0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT3 0x00130UL
+#define RXMAC_HIST_CNT3_COUNT 0x00000000000fffffULL
+
+#define RXMAC_HIST_CNT4 0x00138UL
+#define RXMAC_HIST_CNT4_COUNT 0x000000000007ffffULL
+
+#define RXMAC_HIST_CNT5 0x00140UL
+#define RXMAC_HIST_CNT5_COUNT 0x000000000003ffffULL
+
+#define RXMAC_HIST_CNT6 0x00148UL
+#define RXMAC_HIST_CNT6_COUNT 0x000000000000ffffULL
+
+#define RXMAC_MPSZER_CNT 0x00150UL
+#define RXMAC_MPSZER_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_CRC_ER_CNT 0x00158UL
+#define RXMAC_CRC_ER_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_CD_VIO_CNT 0x00160UL
+#define RXMAC_CD_VIO_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_ALIGN_ERR_CNT 0x00168UL
+#define RXMAC_ALIGN_ERR_CNT_COUNT 0x00000000000000ffULL
+
+#define TXMAC_FRM_CNT 0x00170UL
+#define TXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL
+
+#define TXMAC_BYTE_CNT 0x00178UL
+#define TXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL
+
+#define LINK_FAULT_CNT 0x00180UL
+#define LINK_FAULT_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_HIST_CNT7 0x00188UL
+#define RXMAC_HIST_CNT7_COUNT 0x0000000007ffffffULL
+
+#define XMAC_SM_REG 0x001a8UL
+#define XMAC_SM_REG_STATE 0x00000000ffffffffULL
+
+#define XMAC_INTER1 0x001b0UL
+#define XMAC_INTERN1_SIGNALS1 0x00000000ffffffffULL
+
+#define XMAC_INTER2 0x001b8UL
+#define XMAC_INTERN2_SIGNALS2 0x00000000ffffffffULL
+
+/* BMAC registers, offset from np->mac_regs */
+
+#define BTXMAC_SW_RST 0x00000UL
+#define BTXMAC_SW_RST_RESET 0x0000000000000001ULL
+
+#define BRXMAC_SW_RST 0x00008UL
+#define BRXMAC_SW_RST_RESET 0x0000000000000001ULL
+
+#define BMAC_SEND_PAUSE 0x00010UL
+#define BMAC_SEND_PAUSE_SEND 0x0000000000010000ULL
+#define BMAC_SEND_PAUSE_TIME 0x000000000000ffffULL
+
+#define BTXMAC_STATUS 0x00020UL
+#define BTXMAC_STATUS_XMIT 0x0000000000000001ULL
+#define BTXMAC_STATUS_UNDERRUN 0x0000000000000002ULL
+#define BTXMAC_STATUS_MAX_PKT_ERR 0x0000000000000004ULL
+#define BTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL
+#define BTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL
+
+#define BRXMAC_STATUS 0x00028UL
+#define BRXMAC_STATUS_RX_PKT 0x0000000000000001ULL
+#define BRXMAC_STATUS_OVERFLOW 0x0000000000000002ULL
+#define BRXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000004ULL
+#define BRXMAC_STATUS_ALIGN_ERR_EXP 0x0000000000000008ULL
+#define BRXMAC_STATUS_CRC_ERR_EXP 0x0000000000000010ULL
+#define BRXMAC_STATUS_LEN_ERR_EXP 0x0000000000000020ULL
+
+#define BMAC_CTRL_STATUS 0x00030UL
+#define BMAC_CTRL_STATUS_PAUSE_RECV 0x0000000000000001ULL
+#define BMAC_CTRL_STATUS_PAUSE 0x0000000000000002ULL
+#define BMAC_CTRL_STATUS_NOPAUSE 0x0000000000000004ULL
+#define BMAC_CTRL_STATUS_TIME 0x00000000ffff0000ULL
+#define BMAC_CTRL_STATUS_TIME_SHIFT 16
+
+#define BTXMAC_STATUS_MASK 0x00040UL
+#define BRXMAC_STATUS_MASK 0x00048UL
+#define BMAC_CTRL_STATUS_MASK 0x00050UL
+
+#define BTXMAC_CONFIG 0x00060UL
+#define BTXMAC_CONFIG_ENABLE 0x0000000000000001ULL
+#define BTXMAC_CONFIG_FCS_DISABLE 0x0000000000000002ULL
+
+#define BRXMAC_CONFIG 0x00068UL
+#define BRXMAC_CONFIG_DISCARD_DIS 0x0000000000000080ULL
+#define BRXMAC_CONFIG_ADDR_FILT_EN 0x0000000000000040ULL
+#define BRXMAC_CONFIG_HASH_FILT_EN 0x0000000000000020ULL
+#define BRXMAC_CONFIG_PROMISC_GRP 0x0000000000000010ULL
+#define BRXMAC_CONFIG_PROMISC 0x0000000000000008ULL
+#define BRXMAC_CONFIG_STRIP_FCS 0x0000000000000004ULL
+#define BRXMAC_CONFIG_STRIP_PAD 0x0000000000000002ULL
+#define BRXMAC_CONFIG_ENABLE 0x0000000000000001ULL
+
+#define BMAC_CTRL_CONFIG 0x00070UL
+#define BMAC_CTRL_CONFIG_TX_PAUSE_EN 0x0000000000000001ULL
+#define BMAC_CTRL_CONFIG_RX_PAUSE_EN 0x0000000000000002ULL
+#define BMAC_CTRL_CONFIG_PASS_CTRL 0x0000000000000004ULL
+
+#define BMAC_XIF_CONFIG 0x00078UL
+#define BMAC_XIF_CONFIG_TX_OUTPUT_EN 0x0000000000000001ULL
+#define BMAC_XIF_CONFIG_MII_LOOPBACK 0x0000000000000002ULL
+#define BMAC_XIF_CONFIG_GMII_MODE 0x0000000000000008ULL
+#define BMAC_XIF_CONFIG_LINK_LED 0x0000000000000020ULL
+#define BMAC_XIF_CONFIG_LED_POLARITY 0x0000000000000040ULL
+#define BMAC_XIF_CONFIG_25MHZ_CLOCK 0x0000000000000080ULL
+
+#define BMAC_MIN_FRAME 0x000a0UL
+#define BMAC_MIN_FRAME_VAL 0x00000000000003ffULL
+
+#define BMAC_MAX_FRAME 0x000a8UL
+#define BMAC_MAX_FRAME_MAX_BURST 0x000000003fff0000ULL
+#define BMAC_MAX_FRAME_MAX_BURST_SHIFT 16
+#define BMAC_MAX_FRAME_MAX_FRAME 0x0000000000003fffULL
+#define BMAC_MAX_FRAME_MAX_FRAME_SHIFT 0
+
+#define BMAC_PREAMBLE_SIZE 0x000b0UL
+#define BMAC_PREAMBLE_SIZE_VAL 0x00000000000003ffULL
+
+#define BMAC_CTRL_TYPE 0x000c8UL
+
+#define BMAC_ADDR0 0x00100UL
+#define BMAC_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define BMAC_ADDR1 0x00108UL
+#define BMAC_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define BMAC_ADDR2 0x00110UL
+#define BMAC_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define BMAC_NUM_ALT_ADDR 7
+
+#define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL)
+#define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define BMAC_ALT_ADDR1(NUM) (0x00120UL + (NUM)*0x18UL)
+#define BMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define BMAC_ALT_ADDR2(NUM) (0x00128UL + (NUM)*0x18UL)
+#define BMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define BMAC_FC_ADDR0 0x00268UL
+#define BMAC_FC_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define BMAC_FC_ADDR1 0x00270UL
+#define BMAC_FC_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define BMAC_FC_ADDR2 0x00278UL
+#define BMAC_FC_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT0 0x00298UL
+#define BMAC_ADD_FILT0_FILT0 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT1 0x002a0UL
+#define BMAC_ADD_FILT1_FILT1 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT2 0x002a8UL
+#define BMAC_ADD_FILT2_FILT2 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT12_MASK 0x002b0UL
+#define BMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL
+
+#define BMAC_ADD_FILT00_MASK 0x002b8UL
+#define BMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL
+
+#define BMAC_HASH_TBL(NUM) (0x002c0UL + (NUM) * 0x8UL)
+#define BMAC_HASH_TBL_VAL 0x000000000000ffffULL
+
+#define BRXMAC_FRAME_CNT 0x00370
+#define BRXMAC_FRAME_CNT_COUNT 0x000000000000ffffULL
+
+#define BRXMAC_MAX_LEN_ERR_CNT 0x00378
+
+#define BRXMAC_ALIGN_ERR_CNT 0x00380
+#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL
+
+#define BRXMAC_CRC_ERR_CNT 0x00388
+#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL
+
+#define BRXMAC_CODE_VIOL_ERR_CNT 0x00390
+#define BRXMAC_CODE_VIOL_ERR_CNT_COUNT 0x000000000000ffffULL
+
+#define BMAC_STATE_MACHINE 0x003a0
+
+#define BMAC_ADDR_CMPEN 0x003f8UL
+#define BMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL
+#define BMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL
+#define BMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL
+#define BMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL
+#define BMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL
+#define BMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL
+#define BMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL
+#define BMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL
+#define BMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL
+#define BMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL
+#define BMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL
+#define BMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL
+#define BMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL
+#define BMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL
+#define BMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL
+#define BMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL
+
+#define BMAC_NUM_HOST_INFO 9
+
+#define BMAC_HOST_INFO(NUM) (0x00400UL + (NUM) * 0x8UL)
+
+#define BTXMAC_BYTE_CNT 0x00448UL
+#define BTXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL
+
+#define BTXMAC_FRM_CNT 0x00450UL
+#define BTXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL
+
+#define BRXMAC_BYTE_CNT 0x00458UL
+#define BRXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL
+
+#define HOST_INFO_MPR 0x0000000000000100ULL
+#define HOST_INFO_MACRDCTBLN 0x0000000000000007ULL
+
+/* XPCS registers, offset from np->regs + np->xpcs_off */
+
+#define XPCS_CONTROL1 (FZC_MAC + 0x00000UL)
+#define XPCS_CONTROL1_RESET 0x0000000000008000ULL
+#define XPCS_CONTROL1_LOOPBACK 0x0000000000004000ULL
+#define XPCS_CONTROL1_SPEED_SELECT3 0x0000000000002000ULL
+#define XPCS_CONTROL1_CSR_LOW_PWR 0x0000000000000800ULL
+#define XPCS_CONTROL1_CSR_SPEED1 0x0000000000000040ULL
+#define XPCS_CONTROL1_CSR_SPEED0 0x000000000000003cULL
+
+#define XPCS_STATUS1 (FZC_MAC + 0x00008UL)
+#define XPCS_STATUS1_CSR_FAULT 0x0000000000000080ULL
+#define XPCS_STATUS1_CSR_RXLNK_STAT 0x0000000000000004ULL
+#define XPCS_STATUS1_CSR_LPWR_ABLE 0x0000000000000002ULL
+
+#define XPCS_DEVICE_IDENTIFIER (FZC_MAC + 0x00010UL)
+#define XPCS_DEVICE_IDENTIFIER_VAL 0x00000000ffffffffULL
+
+#define XPCS_SPEED_ABILITY (FZC_MAC + 0x00018UL)
+#define XPCS_SPEED_ABILITY_10GIG 0x0000000000000001ULL
+
+#define XPCS_DEV_IN_PKG (FZC_MAC + 0x00020UL)
+#define XPCS_DEV_IN_PKG_CSR_VEND2 0x0000000080000000ULL
+#define XPCS_DEV_IN_PKG_CSR_VEND1 0x0000000040000000ULL
+#define XPCS_DEV_IN_PKG_DTE_XS 0x0000000000000020ULL
+#define XPCS_DEV_IN_PKG_PHY_XS 0x0000000000000010ULL
+#define XPCS_DEV_IN_PKG_PCS 0x0000000000000008ULL
+#define XPCS_DEV_IN_PKG_WIS 0x0000000000000004ULL
+#define XPCS_DEV_IN_PKG_PMD_PMA 0x0000000000000002ULL
+#define XPCS_DEV_IN_PKG_CLS22 0x0000000000000001ULL
+
+#define XPCS_CONTROL2 (FZC_MAC + 0x00028UL)
+#define XPCS_CONTROL2_CSR_PSC_SEL 0x0000000000000003ULL
+
+#define XPCS_STATUS2 (FZC_MAC + 0x00030UL)
+#define XPCS_STATUS2_CSR_DEV_PRES 0x000000000000c000ULL
+#define XPCS_STATUS2_CSR_TX_FAULT 0x0000000000000800ULL
+#define XPCS_STATUS2_CSR_RCV_FAULT 0x0000000000000400ULL
+#define XPCS_STATUS2_TEN_GBASE_W 0x0000000000000004ULL
+#define XPCS_STATUS2_TEN_GBASE_X 0x0000000000000002ULL
+#define XPCS_STATUS2_TEN_GBASE_R 0x0000000000000001ULL
+
+#define XPCS_PKG_ID (FZC_MAC + 0x00038UL)
+#define XPCS_PKG_ID_VAL 0x00000000ffffffffULL
+
+#define XPCS_STATUS(IDX) (FZC_MAC + 0x00040UL)
+#define XPCS_STATUS_CSR_LANE_ALIGN 0x0000000000001000ULL
+#define XPCS_STATUS_CSR_PATTEST_CAP 0x0000000000000800ULL
+#define XPCS_STATUS_CSR_LANE3_SYNC 0x0000000000000008ULL
+#define XPCS_STATUS_CSR_LANE2_SYNC 0x0000000000000004ULL
+#define XPCS_STATUS_CSR_LANE1_SYNC 0x0000000000000002ULL
+#define XPCS_STATUS_CSR_LANE0_SYNC 0x0000000000000001ULL
+
+#define XPCS_TEST_CONTROL (FZC_MAC + 0x00048UL)
+#define XPCS_TEST_CONTROL_TXTST_EN 0x0000000000000004ULL
+#define XPCS_TEST_CONTROL_TPAT_SEL 0x0000000000000003ULL
+
+#define XPCS_CFG_VENDOR1 (FZC_MAC + 0x00050UL)
+#define XPCS_CFG_VENDOR1_DBG_IOTST 0x0000000000000080ULL
+#define XPCS_CFG_VENDOR1_DBG_SEL 0x0000000000000078ULL
+#define XPCS_CFG_VENDOR1_BYPASS_DET 0x0000000000000004ULL
+#define XPCS_CFG_VENDOR1_TXBUF_EN 0x0000000000000002ULL
+#define XPCS_CFG_VENDOR1_XPCS_EN 0x0000000000000001ULL
+
+#define XPCS_DIAG_VENDOR2 (FZC_MAC + 0x00058UL)
+#define XPCS_DIAG_VENDOR2_SSM_LANE3 0x0000000001e00000ULL
+#define XPCS_DIAG_VENDOR2_SSM_LANE2 0x00000000001e0000ULL
+#define XPCS_DIAG_VENDOR2_SSM_LANE1 0x000000000001e000ULL
+#define XPCS_DIAG_VENDOR2_SSM_LANE0 0x0000000000001e00ULL
+#define XPCS_DIAG_VENDOR2_EBUF_SM 0x00000000000001feULL
+#define XPCS_DIAG_VENDOR2_RCV_SM 0x0000000000000001ULL
+
+#define XPCS_MASK1 (FZC_MAC + 0x00060UL)
+#define XPCS_MASK1_FAULT_MASK 0x0000000000000080ULL
+#define XPCS_MASK1_RXALIGN_STAT_MSK 0x0000000000000004ULL
+
+#define XPCS_PKT_COUNT (FZC_MAC + 0x00068UL)
+#define XPCS_PKT_COUNT_TX 0x00000000ffff0000ULL
+#define XPCS_PKT_COUNT_RX 0x000000000000ffffULL
+
+#define XPCS_TX_SM (FZC_MAC + 0x00070UL)
+#define XPCS_TX_SM_VAL 0x000000000000000fULL
+
+#define XPCS_DESKEW_ERR_CNT (FZC_MAC + 0x00078UL)
+#define XPCS_DESKEW_ERR_CNT_VAL 0x00000000000000ffULL
+
+#define XPCS_SYMERR_CNT01 (FZC_MAC + 0x00080UL)
+#define XPCS_SYMERR_CNT01_LANE1 0x00000000ffff0000ULL
+#define XPCS_SYMERR_CNT01_LANE0 0x000000000000ffffULL
+
+#define XPCS_SYMERR_CNT23 (FZC_MAC + 0x00088UL)
+#define XPCS_SYMERR_CNT23_LANE3 0x00000000ffff0000ULL
+#define XPCS_SYMERR_CNT23_LANE2 0x000000000000ffffULL
+
+#define XPCS_TRAINING_VECTOR (FZC_MAC + 0x00090UL)
+#define XPCS_TRAINING_VECTOR_VAL 0x00000000ffffffffULL
+
+/* PCS registers, offset from np->regs + np->pcs_off */
+
+#define PCS_MII_CTL (FZC_MAC + 0x00000UL)
+#define PCS_MII_CTL_RST 0x0000000000008000ULL
+#define PCS_MII_CTL_10_100_SPEED 0x0000000000002000ULL
+#define PCS_MII_AUTONEG_EN 0x0000000000001000ULL
+#define PCS_MII_PWR_DOWN 0x0000000000000800ULL
+#define PCS_MII_ISOLATE 0x0000000000000400ULL
+#define PCS_MII_AUTONEG_RESTART 0x0000000000000200ULL
+#define PCS_MII_DUPLEX 0x0000000000000100ULL
+#define PCS_MII_COLL_TEST 0x0000000000000080ULL
+#define PCS_MII_1000MB_SPEED 0x0000000000000040ULL
+
+#define PCS_MII_STAT (FZC_MAC + 0x00008UL)
+#define PCS_MII_STAT_EXT_STATUS 0x0000000000000100ULL
+#define PCS_MII_STAT_AUTONEG_DONE 0x0000000000000020ULL
+#define PCS_MII_STAT_REMOTE_FAULT 0x0000000000000010ULL
+#define PCS_MII_STAT_AUTONEG_ABLE 0x0000000000000008ULL
+#define PCS_MII_STAT_LINK_STATUS 0x0000000000000004ULL
+#define PCS_MII_STAT_JABBER_DET 0x0000000000000002ULL
+#define PCS_MII_STAT_EXT_CAP 0x0000000000000001ULL
+
+#define PCS_MII_ADV (FZC_MAC + 0x00010UL)
+#define PCS_MII_ADV_NEXT_PAGE 0x0000000000008000ULL
+#define PCS_MII_ADV_ACK 0x0000000000004000ULL
+#define PCS_MII_ADV_REMOTE_FAULT 0x0000000000003000ULL
+#define PCS_MII_ADV_ASM_DIR 0x0000000000000100ULL
+#define PCS_MII_ADV_PAUSE 0x0000000000000080ULL
+#define PCS_MII_ADV_HALF_DUPLEX 0x0000000000000040ULL
+#define PCS_MII_ADV_FULL_DUPLEX 0x0000000000000020ULL
+
+#define PCS_MII_PARTNER (FZC_MAC + 0x00018UL)
+#define PCS_MII_PARTNER_NEXT_PAGE 0x0000000000008000ULL
+#define PCS_MII_PARTNER_ACK 0x0000000000004000ULL
+#define PCS_MII_PARTNER_REMOTE_FAULT 0x0000000000002000ULL
+#define PCS_MII_PARTNER_PAUSE 0x0000000000000180ULL
+#define PCS_MII_PARTNER_HALF_DUPLEX 0x0000000000000040ULL
+#define PCS_MII_PARTNER_FULL_DUPLEX 0x0000000000000020ULL
+
+#define PCS_CONF (FZC_MAC + 0x00020UL)
+#define PCS_CONF_MASK 0x0000000000000040ULL
+#define PCS_CONF_10MS_TMR_OVERRIDE 0x0000000000000020ULL
+#define PCS_CONF_JITTER_STUDY 0x0000000000000018ULL
+#define PCS_CONF_SIGDET_ACTIVE_LOW 0x0000000000000004ULL
+#define PCS_CONF_SIGDET_OVERRIDE 0x0000000000000002ULL
+#define PCS_CONF_ENABLE 0x0000000000000001ULL
+
+#define PCS_STATE (FZC_MAC + 0x00028UL)
+#define PCS_STATE_D_PARTNER_FAIL 0x0000000020000000ULL
+#define PCS_STATE_D_WAIT_C_CODES_ACK 0x0000000010000000ULL
+#define PCS_STATE_D_SYNC_LOSS 0x0000000008000000ULL
+#define PCS_STATE_D_NO_GOOD_C_CODES 0x0000000004000000ULL
+#define PCS_STATE_D_SERDES 0x0000000002000000ULL
+#define PCS_STATE_D_BREAKLINK_C_CODES 0x0000000001000000ULL
+#define PCS_STATE_L_SIGDET 0x0000000000400000ULL
+#define PCS_STATE_L_SYNC_LOSS 0x0000000000200000ULL
+#define PCS_STATE_L_C_CODES 0x0000000000100000ULL
+#define PCS_STATE_LINK_CFG_STATE 0x000000000001e000ULL
+#define PCS_STATE_SEQ_DET_STATE 0x0000000000001800ULL
+#define PCS_STATE_WORD_SYNC_STATE 0x0000000000000700ULL
+#define PCS_STATE_NO_IDLE 0x000000000000000fULL
+
+#define PCS_INTERRUPT (FZC_MAC + 0x00030UL)
+#define PCS_INTERRUPT_LSTATUS 0x0000000000000004ULL
+
+#define PCS_DPATH_MODE (FZC_MAC + 0x000a0UL)
+#define PCS_DPATH_MODE_PCS 0x0000000000000000ULL
+#define PCS_DPATH_MODE_MII 0x0000000000000002ULL
+#define PCS_DPATH_MODE_LINKUP_F_ENAB 0x0000000000000001ULL
+
+#define PCS_PKT_CNT (FZC_MAC + 0x000c0UL)
+#define PCS_PKT_CNT_RX 0x0000000007ff0000ULL
+#define PCS_PKT_CNT_TX 0x00000000000007ffULL
+
+#define MIF_BB_MDC (FZC_MAC + 0x16000UL)
+#define MIF_BB_MDC_CLK 0x0000000000000001ULL
+
+#define MIF_BB_MDO (FZC_MAC + 0x16008UL)
+#define MIF_BB_MDO_DAT 0x0000000000000001ULL
+
+#define MIF_BB_MDO_EN (FZC_MAC + 0x16010UL)
+#define MIF_BB_MDO_EN_VAL 0x0000000000000001ULL
+
+#define MIF_FRAME_OUTPUT (FZC_MAC + 0x16018UL)
+#define MIF_FRAME_OUTPUT_ST 0x00000000c0000000ULL
+#define MIF_FRAME_OUTPUT_ST_SHIFT 30
+#define MIF_FRAME_OUTPUT_OP_ADDR 0x0000000000000000ULL
+#define MIF_FRAME_OUTPUT_OP_WRITE 0x0000000010000000ULL
+#define MIF_FRAME_OUTPUT_OP_READ_INC 0x0000000020000000ULL
+#define MIF_FRAME_OUTPUT_OP_READ 0x0000000030000000ULL
+#define MIF_FRAME_OUTPUT_OP_SHIFT 28
+#define MIF_FRAME_OUTPUT_PORT 0x000000000f800000ULL
+#define MIF_FRAME_OUTPUT_PORT_SHIFT 23
+#define MIF_FRAME_OUTPUT_REG 0x00000000007c0000ULL
+#define MIF_FRAME_OUTPUT_REG_SHIFT 18
+#define MIF_FRAME_OUTPUT_TA 0x0000000000030000ULL
+#define MIF_FRAME_OUTPUT_TA_SHIFT 16
+#define MIF_FRAME_OUTPUT_DATA 0x000000000000ffffULL
+#define MIF_FRAME_OUTPUT_DATA_SHIFT 0
+
+#define MDIO_ADDR_OP(port, dev, reg) \
+ ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ MIF_FRAME_OUTPUT_OP_ADDR | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+ (reg << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MDIO_READ_OP(port, dev) \
+ ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ MIF_FRAME_OUTPUT_OP_READ | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT))
+
+#define MDIO_WRITE_OP(port, dev, data) \
+ ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ MIF_FRAME_OUTPUT_OP_WRITE | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+ (data << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MII_READ_OP(port, reg) \
+ ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ (2 << MIF_FRAME_OUTPUT_OP_SHIFT) | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT))
+
+#define MII_WRITE_OP(port, reg, data) \
+ ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ (1 << MIF_FRAME_OUTPUT_OP_SHIFT) | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+ (data << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MIF_CONFIG (FZC_MAC + 0x16020UL)
+#define MIF_CONFIG_ATCA_GE 0x0000000000010000ULL
+#define MIF_CONFIG_INDIRECT_MODE 0x0000000000008000ULL
+#define MIF_CONFIG_POLL_PRT_PHYADDR 0x0000000000003c00ULL
+#define MIF_CONFIG_POLL_DEV_REG_ADDR 0x00000000000003e0ULL
+#define MIF_CONFIG_BB_MODE 0x0000000000000010ULL
+#define MIF_CONFIG_POLL_EN 0x0000000000000008ULL
+#define MIF_CONFIG_BB_SER_SEL 0x0000000000000006ULL
+#define MIF_CONFIG_MANUAL_MODE 0x0000000000000001ULL
+
+#define MIF_POLL_STATUS (FZC_MAC + 0x16028UL)
+#define MIF_POLL_STATUS_DATA 0x00000000ffff0000ULL
+#define MIF_POLL_STATUS_STAT 0x000000000000ffffULL
+
+#define MIF_POLL_MASK (FZC_MAC + 0x16030UL)
+#define MIF_POLL_MASK_VAL 0x000000000000ffffULL
+
+#define MIF_SM (FZC_MAC + 0x16038UL)
+#define MIF_SM_PORT_ADDR 0x00000000001f0000ULL
+#define MIF_SM_MDI_1 0x0000000000004000ULL
+#define MIF_SM_MDI_0 0x0000000000002400ULL
+#define MIF_SM_MDCLK 0x0000000000001000ULL
+#define MIF_SM_MDO_EN 0x0000000000000800ULL
+#define MIF_SM_MDO 0x0000000000000400ULL
+#define MIF_SM_MDI 0x0000000000000200ULL
+#define MIF_SM_CTL 0x00000000000001c0ULL
+#define MIF_SM_EX 0x000000000000003fULL
+
+#define MIF_STATUS (FZC_MAC + 0x16040UL)
+#define MIF_STATUS_MDINT1 0x0000000000000020ULL
+#define MIF_STATUS_MDINT0 0x0000000000000010ULL
+
+#define MIF_MASK (FZC_MAC + 0x16048UL)
+#define MIF_MASK_MDINT1 0x0000000000000020ULL
+#define MIF_MASK_MDINT0 0x0000000000000010ULL
+#define MIF_MASK_PEU_ERR 0x0000000000000008ULL
+#define MIF_MASK_YC 0x0000000000000004ULL
+#define MIF_MASK_XGE_ERR0 0x0000000000000002ULL
+#define MIF_MASK_MIF_INIT_DONE 0x0000000000000001ULL
+
+#define ENET_SERDES_RESET (FZC_MAC + 0x14000UL)
+#define ENET_SERDES_RESET_1 0x0000000000000002ULL
+#define ENET_SERDES_RESET_0 0x0000000000000001ULL
+
+#define ENET_SERDES_CFG (FZC_MAC + 0x14008UL)
+#define ENET_SERDES_BE_LOOPBACK 0x0000000000000002ULL
+#define ENET_SERDES_CFG_FORCE_RDY 0x0000000000000001ULL
+
+#define ENET_SERDES_0_PLL_CFG (FZC_MAC + 0x14010UL)
+#define ENET_SERDES_PLL_FBDIV0 0x0000000000000001ULL
+#define ENET_SERDES_PLL_FBDIV1 0x0000000000000002ULL
+#define ENET_SERDES_PLL_FBDIV2 0x0000000000000004ULL
+#define ENET_SERDES_PLL_HRATE0 0x0000000000000008ULL
+#define ENET_SERDES_PLL_HRATE1 0x0000000000000010ULL
+#define ENET_SERDES_PLL_HRATE2 0x0000000000000020ULL
+#define ENET_SERDES_PLL_HRATE3 0x0000000000000040ULL
+
+#define ENET_SERDES_0_CTRL_CFG (FZC_MAC + 0x14018UL)
+#define ENET_SERDES_CTRL_SDET_0 0x0000000000000001ULL
+#define ENET_SERDES_CTRL_SDET_1 0x0000000000000002ULL
+#define ENET_SERDES_CTRL_SDET_2 0x0000000000000004ULL
+#define ENET_SERDES_CTRL_SDET_3 0x0000000000000008ULL
+#define ENET_SERDES_CTRL_EMPH_0 0x0000000000000070ULL
+#define ENET_SERDES_CTRL_EMPH_0_SHIFT 4
+#define ENET_SERDES_CTRL_EMPH_1 0x0000000000000380ULL
+#define ENET_SERDES_CTRL_EMPH_1_SHIFT 7
+#define ENET_SERDES_CTRL_EMPH_2 0x0000000000001c00ULL
+#define ENET_SERDES_CTRL_EMPH_2_SHIFT 10
+#define ENET_SERDES_CTRL_EMPH_3 0x000000000000e000ULL
+#define ENET_SERDES_CTRL_EMPH_3_SHIFT 13
+#define ENET_SERDES_CTRL_LADJ_0 0x0000000000070000ULL
+#define ENET_SERDES_CTRL_LADJ_0_SHIFT 16
+#define ENET_SERDES_CTRL_LADJ_1 0x0000000000380000ULL
+#define ENET_SERDES_CTRL_LADJ_1_SHIFT 19
+#define ENET_SERDES_CTRL_LADJ_2 0x0000000001c00000ULL
+#define ENET_SERDES_CTRL_LADJ_2_SHIFT 22
+#define ENET_SERDES_CTRL_LADJ_3 0x000000000e000000ULL
+#define ENET_SERDES_CTRL_LADJ_3_SHIFT 25
+#define ENET_SERDES_CTRL_RXITERM_0 0x0000000010000000ULL
+#define ENET_SERDES_CTRL_RXITERM_1 0x0000000020000000ULL
+#define ENET_SERDES_CTRL_RXITERM_2 0x0000000040000000ULL
+#define ENET_SERDES_CTRL_RXITERM_3 0x0000000080000000ULL
+
+#define ENET_SERDES_0_TEST_CFG (FZC_MAC + 0x14020UL)
+#define ENET_SERDES_TEST_MD_0 0x0000000000000003ULL
+#define ENET_SERDES_TEST_MD_0_SHIFT 0
+#define ENET_SERDES_TEST_MD_1 0x000000000000000cULL
+#define ENET_SERDES_TEST_MD_1_SHIFT 2
+#define ENET_SERDES_TEST_MD_2 0x0000000000000030ULL
+#define ENET_SERDES_TEST_MD_2_SHIFT 4
+#define ENET_SERDES_TEST_MD_3 0x00000000000000c0ULL
+#define ENET_SERDES_TEST_MD_3_SHIFT 6
+
+#define ENET_TEST_MD_NO_LOOPBACK 0x0
+#define ENET_TEST_MD_EWRAP 0x1
+#define ENET_TEST_MD_PAD_LOOPBACK 0x2
+#define ENET_TEST_MD_REV_LOOPBACK 0x3
+
+#define ENET_SERDES_1_PLL_CFG (FZC_MAC + 0x14028UL)
+#define ENET_SERDES_1_CTRL_CFG (FZC_MAC + 0x14030UL)
+#define ENET_SERDES_1_TEST_CFG (FZC_MAC + 0x14038UL)
+
+#define ENET_RGMII_CFG_REG (FZC_MAC + 0x14040UL)
+
+#define ESR_INT_SIGNALS (FZC_MAC + 0x14800UL)
+#define ESR_INT_SIGNALS_ALL 0x00000000ffffffffULL
+#define ESR_INT_SIGNALS_P0_BITS 0x0000000033e0000fULL
+#define ESR_INT_SIGNALS_P1_BITS 0x000000000c1f00f0ULL
+#define ESR_INT_SRDY0_P0 0x0000000020000000ULL
+#define ESR_INT_DET0_P0 0x0000000010000000ULL
+#define ESR_INT_SRDY0_P1 0x0000000008000000ULL
+#define ESR_INT_DET0_P1 0x0000000004000000ULL
+#define ESR_INT_XSRDY_P0 0x0000000002000000ULL
+#define ESR_INT_XDP_P0_CH3 0x0000000001000000ULL
+#define ESR_INT_XDP_P0_CH2 0x0000000000800000ULL
+#define ESR_INT_XDP_P0_CH1 0x0000000000400000ULL
+#define ESR_INT_XDP_P0_CH0 0x0000000000200000ULL
+#define ESR_INT_XSRDY_P1 0x0000000000100000ULL
+#define ESR_INT_XDP_P1_CH3 0x0000000000080000ULL
+#define ESR_INT_XDP_P1_CH2 0x0000000000040000ULL
+#define ESR_INT_XDP_P1_CH1 0x0000000000020000ULL
+#define ESR_INT_XDP_P1_CH0 0x0000000000010000ULL
+#define ESR_INT_SLOSS_P1_CH3 0x0000000000000080ULL
+#define ESR_INT_SLOSS_P1_CH2 0x0000000000000040ULL
+#define ESR_INT_SLOSS_P1_CH1 0x0000000000000020ULL
+#define ESR_INT_SLOSS_P1_CH0 0x0000000000000010ULL
+#define ESR_INT_SLOSS_P0_CH3 0x0000000000000008ULL
+#define ESR_INT_SLOSS_P0_CH2 0x0000000000000004ULL
+#define ESR_INT_SLOSS_P0_CH1 0x0000000000000002ULL
+#define ESR_INT_SLOSS_P0_CH0 0x0000000000000001ULL
+
+#define ESR_DEBUG_SEL (FZC_MAC + 0x14808UL)
+#define ESR_DEBUG_SEL_VAL 0x000000000000003fULL
+
+/* SerDes registers behind MIF */
+#define NIU_ESR_DEV_ADDR 0x1e
+#define ESR_BASE 0x0000
+
+#define ESR_RXTX_COMM_CTRL_L (ESR_BASE + 0x0000)
+#define ESR_RXTX_COMM_CTRL_H (ESR_BASE + 0x0001)
+
+#define ESR_RXTX_RESET_CTRL_L (ESR_BASE + 0x0002)
+#define ESR_RXTX_RESET_CTRL_H (ESR_BASE + 0x0003)
+
+#define ESR_RX_POWER_CTRL_L (ESR_BASE + 0x0004)
+#define ESR_RX_POWER_CTRL_H (ESR_BASE + 0x0005)
+
+#define ESR_TX_POWER_CTRL_L (ESR_BASE + 0x0006)
+#define ESR_TX_POWER_CTRL_H (ESR_BASE + 0x0007)
+
+#define ESR_MISC_POWER_CTRL_L (ESR_BASE + 0x0008)
+#define ESR_MISC_POWER_CTRL_H (ESR_BASE + 0x0009)
+
+#define ESR_RXTX_CTRL_L(CHAN) (ESR_BASE + 0x0080 + (CHAN) * 0x10)
+#define ESR_RXTX_CTRL_H(CHAN) (ESR_BASE + 0x0081 + (CHAN) * 0x10)
+#define ESR_RXTX_CTRL_BIASCNTL 0x80000000
+#define ESR_RXTX_CTRL_RESV1 0x7c000000
+#define ESR_RXTX_CTRL_TDENFIFO 0x02000000
+#define ESR_RXTX_CTRL_TDWS20 0x01000000
+#define ESR_RXTX_CTRL_VMUXLO 0x00c00000
+#define ESR_RXTX_CTRL_VMUXLO_SHIFT 22
+#define ESR_RXTX_CTRL_VPULSELO 0x00300000
+#define ESR_RXTX_CTRL_VPULSELO_SHIFT 20
+#define ESR_RXTX_CTRL_RESV2 0x000f0000
+#define ESR_RXTX_CTRL_RESV3 0x0000c000
+#define ESR_RXTX_CTRL_RXPRESWIN 0x00003000
+#define ESR_RXTX_CTRL_RXPRESWIN_SHIFT 12
+#define ESR_RXTX_CTRL_RESV4 0x00000800
+#define ESR_RXTX_CTRL_RISEFALL 0x00000700
+#define ESR_RXTX_CTRL_RISEFALL_SHIFT 8
+#define ESR_RXTX_CTRL_RESV5 0x000000fe
+#define ESR_RXTX_CTRL_ENSTRETCH 0x00000001
+
+#define ESR_RXTX_TUNING_L(CHAN) (ESR_BASE + 0x0082 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING_H(CHAN) (ESR_BASE + 0x0083 + (CHAN) * 0x10)
+
+#define ESR_RX_SYNCCHAR_L(CHAN) (ESR_BASE + 0x0084 + (CHAN) * 0x10)
+#define ESR_RX_SYNCCHAR_H(CHAN) (ESR_BASE + 0x0085 + (CHAN) * 0x10)
+
+#define ESR_RXTX_TEST_L(CHAN) (ESR_BASE + 0x0086 + (CHAN) * 0x10)
+#define ESR_RXTX_TEST_H(CHAN) (ESR_BASE + 0x0087 + (CHAN) * 0x10)
+
+#define ESR_GLUE_CTRL0_L(CHAN) (ESR_BASE + 0x0088 + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL0_H(CHAN) (ESR_BASE + 0x0089 + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL0_RESV1 0xf8000000
+#define ESR_GLUE_CTRL0_BLTIME 0x07000000
+#define ESR_GLUE_CTRL0_BLTIME_SHIFT 24
+#define ESR_GLUE_CTRL0_RESV2 0x00ff0000
+#define ESR_GLUE_CTRL0_RXLOS_TEST 0x00008000
+#define ESR_GLUE_CTRL0_RESV3 0x00004000
+#define ESR_GLUE_CTRL0_RXLOSENAB 0x00002000
+#define ESR_GLUE_CTRL0_FASTRESYNC 0x00001000
+#define ESR_GLUE_CTRL0_SRATE 0x00000f00
+#define ESR_GLUE_CTRL0_SRATE_SHIFT 8
+#define ESR_GLUE_CTRL0_THCNT 0x000000ff
+#define ESR_GLUE_CTRL0_THCNT_SHIFT 0
+
+#define BLTIME_64_CYCLES 0
+#define BLTIME_128_CYCLES 1
+#define BLTIME_256_CYCLES 2
+#define BLTIME_300_CYCLES 3
+#define BLTIME_384_CYCLES 4
+#define BLTIME_512_CYCLES 5
+#define BLTIME_1024_CYCLES 6
+#define BLTIME_2048_CYCLES 7
+
+#define ESR_GLUE_CTRL1_L(CHAN) (ESR_BASE + 0x008a + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL1_H(CHAN) (ESR_BASE + 0x008b + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING1_L(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING1_H(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING2_L(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING2_H(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING3_L(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING3_H(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10)
+
+#define NIU_ESR2_DEV_ADDR 0x1e
+#define ESR2_BASE 0x8000
+
+#define ESR2_TI_PLL_CFG_L (ESR2_BASE + 0x000)
+#define ESR2_TI_PLL_CFG_H (ESR2_BASE + 0x001)
+#define PLL_CFG_STD 0x00000c00
+#define PLL_CFG_STD_SHIFT 10
+#define PLL_CFG_LD 0x00000300
+#define PLL_CFG_LD_SHIFT 8
+#define PLL_CFG_MPY 0x0000001e
+#define PLL_CFG_MPY_SHIFT 1
+#define PLL_CFG_ENPLL 0x00000001
+
+#define ESR2_TI_PLL_STS_L (ESR2_BASE + 0x002)
+#define ESR2_TI_PLL_STS_H (ESR2_BASE + 0x003)
+#define PLL_STS_LOCK 0x00000001
+
+#define ESR2_TI_PLL_TEST_CFG_L (ESR2_BASE + 0x004)
+#define ESR2_TI_PLL_TEST_CFG_H (ESR2_BASE + 0x005)
+#define PLL_TEST_INVPATT 0x00004000
+#define PLL_TEST_RATE 0x00003000
+#define PLL_TEST_RATE_SHIFT 12
+#define PLL_TEST_CFG_ENBSAC 0x00000400
+#define PLL_TEST_CFG_ENBSRX 0x00000200
+#define PLL_TEST_CFG_ENBSTX 0x00000100
+#define PLL_TEST_CFG_LOOPBACK_PAD 0x00000040
+#define PLL_TEST_CFG_LOOPBACK_CML_DIS 0x00000080
+#define PLL_TEST_CFG_LOOPBACK_CML_EN 0x000000c0
+#define PLL_TEST_CFG_CLKBYP 0x00000030
+#define PLL_TEST_CFG_CLKBYP_SHIFT 4
+#define PLL_TEST_CFG_EN_RXPATT 0x00000008
+#define PLL_TEST_CFG_EN_TXPATT 0x00000004
+#define PLL_TEST_CFG_TPATT 0x00000003
+#define PLL_TEST_CFG_TPATT_SHIFT 0
+
+#define ESR2_TI_PLL_TX_CFG_L(CHAN) (ESR2_BASE + 0x100 + (CHAN) * 4)
+#define ESR2_TI_PLL_TX_CFG_H(CHAN) (ESR2_BASE + 0x101 + (CHAN) * 4)
+#define PLL_TX_CFG_RDTCT 0x00600000
+#define PLL_TX_CFG_RDTCT_SHIFT 21
+#define PLL_TX_CFG_ENIDL 0x00100000
+#define PLL_TX_CFG_BSTX 0x00020000
+#define PLL_TX_CFG_ENFTP 0x00010000
+#define PLL_TX_CFG_DE 0x0000f000
+#define PLL_TX_CFG_DE_SHIFT 12
+#define PLL_TX_CFG_SWING_125MV 0x00000000
+#define PLL_TX_CFG_SWING_250MV 0x00000200
+#define PLL_TX_CFG_SWING_500MV 0x00000400
+#define PLL_TX_CFG_SWING_625MV 0x00000600
+#define PLL_TX_CFG_SWING_750MV 0x00000800
+#define PLL_TX_CFG_SWING_1000MV 0x00000a00
+#define PLL_TX_CFG_SWING_1250MV 0x00000c00
+#define PLL_TX_CFG_SWING_1375MV 0x00000e00
+#define PLL_TX_CFG_CM 0x00000100
+#define PLL_TX_CFG_INVPAIR 0x00000080
+#define PLL_TX_CFG_RATE 0x00000060
+#define PLL_TX_CFG_RATE_SHIFT 5
+#define PLL_TX_CFG_BUSWIDTH 0x0000001c
+#define PLL_TX_CFG_BUSWIDTH_SHIFT 2
+#define PLL_TX_CFG_ENTEST 0x00000002
+#define PLL_TX_CFG_ENTX 0x00000001
+
+#define ESR2_TI_PLL_TX_STS_L(CHAN) (ESR2_BASE + 0x102 + (CHAN) * 4)
+#define ESR2_TI_PLL_TX_STS_H(CHAN) (ESR2_BASE + 0x103 + (CHAN) * 4)
+#define PLL_TX_STS_RDTCTIP 0x00000002
+#define PLL_TX_STS_TESTFAIL 0x00000001
+
+#define ESR2_TI_PLL_RX_CFG_L(CHAN) (ESR2_BASE + 0x120 + (CHAN) * 4)
+#define ESR2_TI_PLL_RX_CFG_H(CHAN) (ESR2_BASE + 0x121 + (CHAN) * 4)
+#define PLL_RX_CFG_BSINRXN 0x02000000
+#define PLL_RX_CFG_BSINRXP 0x01000000
+#define PLL_RX_CFG_EQ_MAX_LF 0x00000000
+#define PLL_RX_CFG_EQ_LP_ADAPTIVE 0x00080000
+#define PLL_RX_CFG_EQ_LP_1084MHZ 0x00400000
+#define PLL_RX_CFG_EQ_LP_805MHZ 0x00480000
+#define PLL_RX_CFG_EQ_LP_573MHZ 0x00500000
+#define PLL_RX_CFG_EQ_LP_402MHZ 0x00580000
+#define PLL_RX_CFG_EQ_LP_304MHZ 0x00600000
+#define PLL_RX_CFG_EQ_LP_216MHZ 0x00680000
+#define PLL_RX_CFG_EQ_LP_156MHZ 0x00700000
+#define PLL_RX_CFG_EQ_LP_135MHZ 0x00780000
+#define PLL_RX_CFG_EQ_SHIFT 19
+#define PLL_RX_CFG_CDR 0x00070000
+#define PLL_RX_CFG_CDR_SHIFT 16
+#define PLL_RX_CFG_LOS_DIS 0x00000000
+#define PLL_RX_CFG_LOS_HTHRESH 0x00004000
+#define PLL_RX_CFG_LOS_LTHRESH 0x00008000
+#define PLL_RX_CFG_ALIGN_DIS 0x00000000
+#define PLL_RX_CFG_ALIGN_ENA 0x00001000
+#define PLL_RX_CFG_ALIGN_JOG 0x00002000
+#define PLL_RX_CFG_TERM_VDDT 0x00000000
+#define PLL_RX_CFG_TERM_0P8VDDT 0x00000100
+#define PLL_RX_CFG_TERM_FLOAT 0x00000300
+#define PLL_RX_CFG_INVPAIR 0x00000080
+#define PLL_RX_CFG_RATE 0x00000060
+#define PLL_RX_CFG_RATE_SHIFT 5
+#define PLL_RX_CFG_BUSWIDTH 0x0000001c
+#define PLL_RX_CFG_BUSWIDTH_SHIFT 2
+#define PLL_RX_CFG_ENTEST 0x00000002
+#define PLL_RX_CFG_ENRX 0x00000001
+
+#define ESR2_TI_PLL_RX_STS_L(CHAN) (ESR2_BASE + 0x122 + (CHAN) * 4)
+#define ESR2_TI_PLL_RX_STS_H(CHAN) (ESR2_BASE + 0x123 + (CHAN) * 4)
+#define PLL_RX_STS_CRCIDTCT 0x00000200
+#define PLL_RX_STS_CWDTCT 0x00000100
+#define PLL_RX_STS_BSRXN 0x00000020
+#define PLL_RX_STS_BSRXP 0x00000010
+#define PLL_RX_STS_LOSDTCT 0x00000008
+#define PLL_RX_STS_ODDCG 0x00000004
+#define PLL_RX_STS_SYNC 0x00000002
+#define PLL_RX_STS_TESTFAIL 0x00000001
+
+#define ENET_VLAN_TBL(IDX) (FZC_FFLP + 0x00000UL + (IDX) * 8UL)
+#define ENET_VLAN_TBL_PARITY1 0x0000000000020000ULL
+#define ENET_VLAN_TBL_PARITY0 0x0000000000010000ULL
+#define ENET_VLAN_TBL_VPR 0x0000000000000008ULL
+#define ENET_VLAN_TBL_VLANRDCTBLN 0x0000000000000007ULL
+#define ENET_VLAN_TBL_SHIFT(PORT) ((PORT) * 4)
+
+#define ENET_VLAN_TBL_NUM_ENTRIES 4096
+
+#define FFLP_VLAN_PAR_ERR (FZC_FFLP + 0x0800UL)
+#define FFLP_VLAN_PAR_ERR_ERR 0x0000000080000000ULL
+#define FFLP_VLAN_PAR_ERR_M_ERR 0x0000000040000000ULL
+#define FFLP_VLAN_PAR_ERR_ADDR 0x000000003ffc0000ULL
+#define FFLP_VLAN_PAR_ERR_DATA 0x000000000003ffffULL
+
+#define L2_CLS(IDX) (FZC_FFLP + 0x20000UL + (IDX) * 8UL)
+#define L2_CLS_VLD 0x0000000000010000ULL
+#define L2_CLS_ETYPE 0x000000000000ffffULL
+#define L2_CLS_ETYPE_SHIFT 0
+
+#define L3_CLS(IDX) (FZC_FFLP + 0x20010UL + (IDX) * 8UL)
+#define L3_CLS_VALID 0x0000000002000000ULL
+#define L3_CLS_IPVER 0x0000000001000000ULL
+#define L3_CLS_PID 0x0000000000ff0000ULL
+#define L3_CLS_PID_SHIFT 16
+#define L3_CLS_TOSMASK 0x000000000000ff00ULL
+#define L3_CLS_TOSMASK_SHIFT 8
+#define L3_CLS_TOS 0x00000000000000ffULL
+#define L3_CLS_TOS_SHIFT 0
+
+#define TCAM_KEY(IDX) (FZC_FFLP + 0x20030UL + (IDX) * 8UL)
+#define TCAM_KEY_DISC 0x0000000000000008ULL
+#define TCAM_KEY_TSEL 0x0000000000000004ULL
+#define TCAM_KEY_IPADDR 0x0000000000000001ULL
+
+#define TCAM_KEY_0 (FZC_FFLP + 0x20090UL)
+#define TCAM_KEY_0_KEY 0x00000000000000ffULL /* bits 192-199 */
+
+#define TCAM_KEY_1 (FZC_FFLP + 0x20098UL)
+#define TCAM_KEY_1_KEY 0xffffffffffffffffULL /* bits 128-191 */
+
+#define TCAM_KEY_2 (FZC_FFLP + 0x200a0UL)
+#define TCAM_KEY_2_KEY 0xffffffffffffffffULL /* bits 64-127 */
+
+#define TCAM_KEY_3 (FZC_FFLP + 0x200a8UL)
+#define TCAM_KEY_3_KEY 0xffffffffffffffffULL /* bits 0-63 */
+
+#define TCAM_KEY_MASK_0 (FZC_FFLP + 0x200b0UL)
+#define TCAM_KEY_MASK_0_KEY_SEL 0x00000000000000ffULL /* bits 192-199 */
+
+#define TCAM_KEY_MASK_1 (FZC_FFLP + 0x200b8UL)
+#define TCAM_KEY_MASK_1_KEY_SEL 0xffffffffffffffffULL /* bits 128-191 */
+
+#define TCAM_KEY_MASK_2 (FZC_FFLP + 0x200c0UL)
+#define TCAM_KEY_MASK_2_KEY_SEL 0xffffffffffffffffULL /* bits 64-127 */
+
+#define TCAM_KEY_MASK_3 (FZC_FFLP + 0x200c8UL)
+#define TCAM_KEY_MASK_3_KEY_SEL 0xffffffffffffffffULL /* bits 0-63 */
+
+#define TCAM_CTL (FZC_FFLP + 0x200d0UL)
+#define TCAM_CTL_RWC 0x00000000001c0000ULL
+#define TCAM_CTL_RWC_TCAM_WRITE 0x0000000000000000ULL
+#define TCAM_CTL_RWC_TCAM_READ 0x0000000000040000ULL
+#define TCAM_CTL_RWC_TCAM_COMPARE 0x0000000000080000ULL
+#define TCAM_CTL_RWC_RAM_WRITE 0x0000000000100000ULL
+#define TCAM_CTL_RWC_RAM_READ 0x0000000000140000ULL
+#define TCAM_CTL_STAT 0x0000000000020000ULL
+#define TCAM_CTL_MATCH 0x0000000000010000ULL
+#define TCAM_CTL_LOC 0x00000000000003ffULL
+
+#define TCAM_ERR (FZC_FFLP + 0x200d8UL)
+#define TCAM_ERR_ERR 0x0000000080000000ULL
+#define TCAM_ERR_P_ECC 0x0000000040000000ULL
+#define TCAM_ERR_MULT 0x0000000020000000ULL
+#define TCAM_ERR_ADDR 0x0000000000ff0000ULL
+#define TCAM_ERR_SYNDROME 0x000000000000ffffULL
+
+#define HASH_LOOKUP_ERR_LOG1 (FZC_FFLP + 0x200e0UL)
+#define HASH_LOOKUP_ERR_LOG1_ERR 0x0000000000000008ULL
+#define HASH_LOOKUP_ERR_LOG1_MULT_LK 0x0000000000000004ULL
+#define HASH_LOOKUP_ERR_LOG1_CU 0x0000000000000002ULL
+#define HASH_LOOKUP_ERR_LOG1_MULT_BIT 0x0000000000000001ULL
+
+#define HASH_LOOKUP_ERR_LOG2 (FZC_FFLP + 0x200e8UL)
+#define HASH_LOOKUP_ERR_LOG2_H1 0x000000007ffff800ULL
+#define HASH_LOOKUP_ERR_LOG2_SUBAREA 0x0000000000000700ULL
+#define HASH_LOOKUP_ERR_LOG2_SYNDROME 0x00000000000000ffULL
+
+#define FFLP_CFG_1 (FZC_FFLP + 0x20100UL)
+#define FFLP_CFG_1_TCAM_DIS 0x0000000004000000ULL
+#define FFLP_CFG_1_PIO_DBG_SEL 0x0000000003800000ULL
+#define FFLP_CFG_1_PIO_FIO_RST 0x0000000000400000ULL
+#define FFLP_CFG_1_PIO_FIO_LAT 0x0000000000300000ULL
+#define FFLP_CFG_1_CAMLAT 0x00000000000f0000ULL
+#define FFLP_CFG_1_CAMLAT_SHIFT 16
+#define FFLP_CFG_1_CAMRATIO 0x000000000000f000ULL
+#define FFLP_CFG_1_CAMRATIO_SHIFT 12
+#define FFLP_CFG_1_FCRAMRATIO 0x0000000000000f00ULL
+#define FFLP_CFG_1_FCRAMRATIO_SHIFT 8
+#define FFLP_CFG_1_FCRAMOUTDR_MASK 0x00000000000000f0ULL
+#define FFLP_CFG_1_FCRAMOUTDR_NORMAL 0x0000000000000000ULL
+#define FFLP_CFG_1_FCRAMOUTDR_STRONG 0x0000000000000050ULL
+#define FFLP_CFG_1_FCRAMOUTDR_WEAK 0x00000000000000a0ULL
+#define FFLP_CFG_1_FCRAMQS 0x0000000000000008ULL
+#define FFLP_CFG_1_ERRORDIS 0x0000000000000004ULL
+#define FFLP_CFG_1_FFLPINITDONE 0x0000000000000002ULL
+#define FFLP_CFG_1_LLCSNAP 0x0000000000000001ULL
+
+#define DEFAULT_FCRAMRATIO 10
+
+#define DEFAULT_TCAM_LATENCY 4
+#define DEFAULT_TCAM_ACCESS_RATIO 10
+
+#define TCP_CFLAG_MSK (FZC_FFLP + 0x20108UL)
+#define TCP_CFLAG_MSK_MASK 0x0000000000000fffULL
+
+#define FCRAM_REF_TMR (FZC_FFLP + 0x20110UL)
+#define FCRAM_REF_TMR_MAX 0x00000000ffff0000ULL
+#define FCRAM_REF_TMR_MAX_SHIFT 16
+#define FCRAM_REF_TMR_MIN 0x000000000000ffffULL
+#define FCRAM_REF_TMR_MIN_SHIFT 0
+
+#define DEFAULT_FCRAM_REFRESH_MAX 512
+#define DEFAULT_FCRAM_REFRESH_MIN 512
+
+#define FCRAM_FIO_ADDR (FZC_FFLP + 0x20118UL)
+#define FCRAM_FIO_ADDR_ADDR 0x00000000000000ffULL
+
+#define FCRAM_FIO_DAT (FZC_FFLP + 0x20120UL)
+#define FCRAM_FIO_DAT_DATA 0x000000000000ffffULL
+
+#define FCRAM_ERR_TST0 (FZC_FFLP + 0x20128UL)
+#define FCRAM_ERR_TST0_SYND 0x00000000000000ffULL
+
+#define FCRAM_ERR_TST1 (FZC_FFLP + 0x20130UL)
+#define FCRAM_ERR_TST1_DAT 0x00000000ffffffffULL
+
+#define FCRAM_ERR_TST2 (FZC_FFLP + 0x20138UL)
+#define FCRAM_ERR_TST2_DAT 0x00000000ffffffffULL
+
+#define FFLP_ERR_MASK (FZC_FFLP + 0x20140UL)
+#define FFLP_ERR_MASK_HSH_TBL_DAT 0x00000000000007f8ULL
+#define FFLP_ERR_MASK_HSH_TBL_LKUP 0x0000000000000004ULL
+#define FFLP_ERR_MASK_TCAM 0x0000000000000002ULL
+#define FFLP_ERR_MASK_VLAN 0x0000000000000001ULL
+
+#define FFLP_DBG_TRAIN_VCT (FZC_FFLP + 0x20148UL)
+#define FFLP_DBG_TRAIN_VCT_VECTOR 0x00000000ffffffffULL
+
+#define FCRAM_PHY_RD_LAT (FZC_FFLP + 0x20150UL)
+#define FCRAM_PHY_RD_LAT_LAT 0x00000000000000ffULL
+
+/* Ethernet TCAM format */
+#define TCAM_ETHKEY0_RESV1 0xffffffffffffff00ULL
+#define TCAM_ETHKEY0_CLASS_CODE 0x00000000000000f8ULL
+#define TCAM_ETHKEY0_CLASS_CODE_SHIFT 3
+#define TCAM_ETHKEY0_RESV2 0x0000000000000007ULL
+#define TCAM_ETHKEY1_FRAME_BYTE0_7(NUM) (0xff << ((7 - NUM) * 8))
+#define TCAM_ETHKEY2_FRAME_BYTE8 0xff00000000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE8_SHIFT 56
+#define TCAM_ETHKEY2_FRAME_BYTE9 0x00ff000000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE9_SHIFT 48
+#define TCAM_ETHKEY2_FRAME_BYTE10 0x0000ff0000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE10_SHIFT 40
+#define TCAM_ETHKEY2_FRAME_RESV 0x000000ffffffffffULL
+#define TCAM_ETHKEY3_FRAME_RESV 0xffffffffffffffffULL
+
+/* IPV4 TCAM format */
+#define TCAM_V4KEY0_RESV1 0xffffffffffffff00ULL
+#define TCAM_V4KEY0_CLASS_CODE 0x00000000000000f8ULL
+#define TCAM_V4KEY0_CLASS_CODE_SHIFT 3
+#define TCAM_V4KEY0_RESV2 0x0000000000000007ULL
+#define TCAM_V4KEY1_L2RDCNUM 0xf800000000000000ULL
+#define TCAM_V4KEY1_L2RDCNUM_SHIFT 59
+#define TCAM_V4KEY1_NOPORT 0x0400000000000000ULL
+#define TCAM_V4KEY1_RESV 0x03ffffffffffffffULL
+#define TCAM_V4KEY2_RESV 0xffff000000000000ULL
+#define TCAM_V4KEY2_TOS 0x0000ff0000000000ULL
+#define TCAM_V4KEY2_TOS_SHIFT 40
+#define TCAM_V4KEY2_PROTO 0x000000ff00000000ULL
+#define TCAM_V4KEY2_PROTO_SHIFT 32
+#define TCAM_V4KEY2_PORT_SPI 0x00000000ffffffffULL
+#define TCAM_V4KEY2_PORT_SPI_SHIFT 0
+#define TCAM_V4KEY3_SADDR 0xffffffff00000000ULL
+#define TCAM_V4KEY3_SADDR_SHIFT 32
+#define TCAM_V4KEY3_DADDR 0x00000000ffffffffULL
+#define TCAM_V4KEY3_DADDR_SHIFT 0
+
+/* IPV6 TCAM format */
+#define TCAM_V6KEY0_RESV1 0xffffffffffffff00ULL
+#define TCAM_V6KEY0_CLASS_CODE 0x00000000000000f8ULL
+#define TCAM_V6KEY0_CLASS_CODE_SHIFT 3
+#define TCAM_V6KEY0_RESV2 0x0000000000000007ULL
+#define TCAM_V6KEY1_L2RDCNUM 0xf800000000000000ULL
+#define TCAM_V6KEY1_L2RDCNUM_SHIFT 59
+#define TCAM_V6KEY1_NOPORT 0x0400000000000000ULL
+#define TCAM_V6KEY1_RESV 0x03ff000000000000ULL
+#define TCAM_V6KEY1_TOS 0x0000ff0000000000ULL
+#define TCAM_V6KEY1_TOS_SHIFT 40
+#define TCAM_V6KEY1_NEXT_HDR 0x000000ff00000000ULL
+#define TCAM_V6KEY1_NEXT_HDR_SHIFT 32
+#define TCAM_V6KEY1_PORT_SPI 0x00000000ffffffffULL
+#define TCAM_V6KEY1_PORT_SPI_SHIFT 0
+#define TCAM_V6KEY2_ADDR_HIGH 0xffffffffffffffffULL
+#define TCAM_V6KEY3_ADDR_LOW 0xffffffffffffffffULL
+
+#define TCAM_ASSOCDATA_SYNDROME 0x000003fffc000000ULL
+#define TCAM_ASSOCDATA_SYNDROME_SHIFT 26
+#define TCAM_ASSOCDATA_ZFID 0x0000000003ffc000ULL
+#define TCAM_ASSOCDATA_ZFID_SHIFT 14
+#define TCAM_ASSOCDATA_V4_ECC_OK 0x0000000000002000ULL
+#define TCAM_ASSOCDATA_DISC 0x0000000000001000ULL
+#define TCAM_ASSOCDATA_TRES_MASK 0x0000000000000c00ULL
+#define TCAM_ASSOCDATA_TRES_USE_L2RDC 0x0000000000000000ULL
+#define TCAM_ASSOCDATA_TRES_USE_OFFSET 0x0000000000000400ULL
+#define TCAM_ASSOCDATA_TRES_OVR_RDC 0x0000000000000800ULL
+#define TCAM_ASSOCDATA_TRES_OVR_RDC_OFF 0x0000000000000c00ULL
+#define TCAM_ASSOCDATA_RDCTBL 0x0000000000000380ULL
+#define TCAM_ASSOCDATA_RDCTBL_SHIFT 7
+#define TCAM_ASSOCDATA_OFFSET 0x000000000000007cULL
+#define TCAM_ASSOCDATA_OFFSET_SHIFT 2
+#define TCAM_ASSOCDATA_ZFVLD 0x0000000000000002ULL
+#define TCAM_ASSOCDATA_AGE 0x0000000000000001ULL
+
+#define FLOW_KEY(IDX) (FZC_FFLP + 0x40000UL + (IDX) * 8UL)
+#define FLOW_KEY_PORT 0x0000000000000200ULL
+#define FLOW_KEY_L2DA 0x0000000000000100ULL
+#define FLOW_KEY_VLAN 0x0000000000000080ULL
+#define FLOW_KEY_IPSA 0x0000000000000040ULL
+#define FLOW_KEY_IPDA 0x0000000000000020ULL
+#define FLOW_KEY_PROTO 0x0000000000000010ULL
+#define FLOW_KEY_L4_0 0x000000000000000cULL
+#define FLOW_KEY_L4_0_SHIFT 2
+#define FLOW_KEY_L4_1 0x0000000000000003ULL
+#define FLOW_KEY_L4_1_SHIFT 0
+
+#define FLOW_KEY_L4_NONE 0x0
+#define FLOW_KEY_L4_RESV 0x1
+#define FLOW_KEY_L4_BYTE12 0x2
+#define FLOW_KEY_L4_BYTE56 0x3
+
+#define H1POLY (FZC_FFLP + 0x40060UL)
+#define H1POLY_INITVAL 0x00000000ffffffffULL
+
+#define H2POLY (FZC_FFLP + 0x40068UL)
+#define H2POLY_INITVAL 0x000000000000ffffULL
+
+#define FLW_PRT_SEL(IDX) (FZC_FFLP + 0x40070UL + (IDX) * 8UL)
+#define FLW_PRT_SEL_EXT 0x0000000000010000ULL
+#define FLW_PRT_SEL_MASK 0x0000000000001f00ULL
+#define FLW_PRT_SEL_MASK_SHIFT 8
+#define FLW_PRT_SEL_BASE 0x000000000000001fULL
+#define FLW_PRT_SEL_BASE_SHIFT 0
+
+#define HASH_TBL_ADDR(IDX) (FFLP + 0x00000UL + (IDX) * 8192UL)
+#define HASH_TBL_ADDR_AUTOINC 0x0000000000800000ULL
+#define HASH_TBL_ADDR_ADDR 0x00000000007fffffULL
+
+#define HASH_TBL_DATA(IDX) (FFLP + 0x00008UL + (IDX) * 8192UL)
+#define HASH_TBL_DATA_DATA 0xffffffffffffffffULL
+
+/* FCRAM hash table entries are up to 8 64-bit words in size.
+ * The layout of each entry is determined by the settings in the
+ * first word, which is the header.
+ *
+ * The indexing is controllable per partition (there is one partition
+ * per RDC group, thus a total of eight) using the BASE and MASK fields
+ * of FLW_PRT_SEL above.
+ */
+#define FCRAM_SIZE 0x800000
+#define FCRAM_NUM_PARTITIONS 8
+
+/* Generic HASH entry header, used for all non-optimized formats. */
+#define HASH_HEADER_FMT 0x8000000000000000ULL
+#define HASH_HEADER_EXT 0x4000000000000000ULL
+#define HASH_HEADER_VALID 0x2000000000000000ULL
+#define HASH_HEADER_RESVD 0x1000000000000000ULL
+#define HASH_HEADER_L2_DADDR 0x0ffffffffffff000ULL
+#define HASH_HEADER_L2_DADDR_SHIFT 12
+#define HASH_HEADER_VLAN 0x0000000000000fffULL
+#define HASH_HEADER_VLAN_SHIFT 0
+
+/* Optimized format, just a header with a special layout defined below.
+ * Set FMT and EXT both to zero to indicate this layout is being used.
+ */
+#define HASH_OPT_HEADER_FMT 0x8000000000000000ULL
+#define HASH_OPT_HEADER_EXT 0x4000000000000000ULL
+#define HASH_OPT_HEADER_VALID 0x2000000000000000ULL
+#define HASH_OPT_HEADER_RDCOFF 0x1f00000000000000ULL
+#define HASH_OPT_HEADER_RDCOFF_SHIFT 56
+#define HASH_OPT_HEADER_HASH2 0x00ffff0000000000ULL
+#define HASH_OPT_HEADER_HASH2_SHIFT 40
+#define HASH_OPT_HEADER_RESVD 0x000000ff00000000ULL
+#define HASH_OPT_HEADER_USERINFO 0x00000000ffffffffULL
+#define HASH_OPT_HEADER_USERINFO_SHIFT 0
+
+/* Port and protocol word used for ipv4 and ipv6 layouts. */
+#define HASH_PORT_DPORT 0xffff000000000000ULL
+#define HASH_PORT_DPORT_SHIFT 48
+#define HASH_PORT_SPORT 0x0000ffff00000000ULL
+#define HASH_PORT_SPORT_SHIFT 32
+#define HASH_PORT_PROTO 0x00000000ff000000ULL
+#define HASH_PORT_PROTO_SHIFT 24
+#define HASH_PORT_PORT_OFF 0x0000000000c00000ULL
+#define HASH_PORT_PORT_OFF_SHIFT 22
+#define HASH_PORT_PORT_RESV 0x00000000003fffffULL
+
+/* Action word used for ipv4 and ipv6 layouts. */
+#define HASH_ACTION_RESV1 0xe000000000000000ULL
+#define HASH_ACTION_RDCOFF 0x1f00000000000000ULL
+#define HASH_ACTION_RDCOFF_SHIFT 56
+#define HASH_ACTION_ZFVALID 0x0080000000000000ULL
+#define HASH_ACTION_RESV2 0x0070000000000000ULL
+#define HASH_ACTION_ZFID 0x000fff0000000000ULL
+#define HASH_ACTION_ZFID_SHIFT 40
+#define HASH_ACTION_RESV3 0x000000ff00000000ULL
+#define HASH_ACTION_USERINFO 0x00000000ffffffffULL
+#define HASH_ACTION_USERINFO_SHIFT 0
+
+/* IPV4 address word. Addresses are in network endian. */
+#define HASH_IP4ADDR_SADDR 0xffffffff00000000ULL
+#define HASH_IP4ADDR_SADDR_SHIFT 32
+#define HASH_IP4ADDR_DADDR 0x00000000ffffffffULL
+#define HASH_IP4ADDR_DADDR_SHIFT 0
+
+/* IPV6 address layout is 4 words, first two are saddr, next two
+ * are daddr. Addresses are in network endian.
+ */
+
+struct fcram_hash_opt {
+ u64 header;
+};
+
+/* EXT=1, FMT=0 */
+struct fcram_hash_ipv4 {
+ u64 header;
+ u64 addrs;
+ u64 ports;
+ u64 action;
+};
+
+/* EXT=1, FMT=1 */
+struct fcram_hash_ipv6 {
+ u64 header;
+ u64 addrs[4];
+ u64 ports;
+ u64 action;
+};
+
+#define HASH_TBL_DATA_LOG(IDX) (FFLP + 0x00010UL + (IDX) * 8192UL)
+#define HASH_TBL_DATA_LOG_ERR 0x0000000080000000ULL
+#define HASH_TBL_DATA_LOG_ADDR 0x000000007fffff00ULL
+#define HASH_TBL_DATA_LOG_SYNDROME 0x00000000000000ffULL
+
+#define RX_DMA_CK_DIV (FZC_DMC + 0x00000UL)
+#define RX_DMA_CK_DIV_CNT 0x000000000000ffffULL
+
+#define DEF_RDC(IDX) (FZC_DMC + 0x00008UL + (IDX) * 0x8UL)
+#define DEF_RDC_VAL 0x000000000000001fULL
+
+#define PT_DRR_WT(IDX) (FZC_DMC + 0x00028UL + (IDX) * 0x8UL)
+#define PT_DRR_WT_VAL 0x000000000000ffffULL
+
+#define PT_DRR_WEIGHT_DEFAULT_10G 0x0400
+#define PT_DRR_WEIGHT_DEFAULT_1G 0x0066
+
+#define PT_USE(IDX) (FZC_DMC + 0x00048UL + (IDX) * 0x8UL)
+#define PT_USE_CNT 0x00000000000fffffULL
+
+#define RED_RAN_INIT (FZC_DMC + 0x00068UL)
+#define RED_RAN_INIT_OPMODE 0x0000000000010000ULL
+#define RED_RAN_INIT_VAL 0x000000000000ffffULL
+
+#define RX_ADDR_MD (FZC_DMC + 0x00070UL)
+#define RX_ADDR_MD_DBG_PT_MUX_SEL 0x000000000000000cULL
+#define RX_ADDR_MD_RAM_ACC 0x0000000000000002ULL
+#define RX_ADDR_MD_MODE32 0x0000000000000001ULL
+
+#define RDMC_PRE_PAR_ERR (FZC_DMC + 0x00078UL)
+#define RDMC_PRE_PAR_ERR_ERR 0x0000000000008000ULL
+#define RDMC_PRE_PAR_ERR_MERR 0x0000000000004000ULL
+#define RDMC_PRE_PAR_ERR_ADDR 0x00000000000000ffULL
+
+#define RDMC_SHA_PAR_ERR (FZC_DMC + 0x00080UL)
+#define RDMC_SHA_PAR_ERR_ERR 0x0000000000008000ULL
+#define RDMC_SHA_PAR_ERR_MERR 0x0000000000004000ULL
+#define RDMC_SHA_PAR_ERR_ADDR 0x00000000000000ffULL
+
+#define RDMC_MEM_ADDR (FZC_DMC + 0x00088UL)
+#define RDMC_MEM_ADDR_PRE_SHAD 0x0000000000000100ULL
+#define RDMC_MEM_ADDR_ADDR 0x00000000000000ffULL
+
+#define RDMC_MEM_DAT0 (FZC_DMC + 0x00090UL)
+#define RDMC_MEM_DAT0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define RDMC_MEM_DAT1 (FZC_DMC + 0x00098UL)
+#define RDMC_MEM_DAT1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define RDMC_MEM_DAT2 (FZC_DMC + 0x000a0UL)
+#define RDMC_MEM_DAT2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define RDMC_MEM_DAT3 (FZC_DMC + 0x000a8UL)
+#define RDMC_MEM_DAT3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define RDMC_MEM_DAT4 (FZC_DMC + 0x000b0UL)
+#define RDMC_MEM_DAT4_DATA 0x00000000000fffffULL /* bits 147:128 */
+
+#define RX_CTL_DAT_FIFO_STAT (FZC_DMC + 0x000b8UL)
+#define RX_CTL_DAT_FIFO_STAT_ID_MISMATCH 0x0000000000000100ULL
+#define RX_CTL_DAT_FIFO_STAT_ZCP_EOP_ERR 0x00000000000000f0ULL
+#define RX_CTL_DAT_FIFO_STAT_IPP_EOP_ERR 0x000000000000000fULL
+
+#define RX_CTL_DAT_FIFO_MASK (FZC_DMC + 0x000c0UL)
+#define RX_CTL_DAT_FIFO_MASK_ID_MISMATCH 0x0000000000000100ULL
+#define RX_CTL_DAT_FIFO_MASK_ZCP_EOP_ERR 0x00000000000000f0ULL
+#define RX_CTL_DAT_FIFO_MASK_IPP_EOP_ERR 0x000000000000000fULL
+
+#define RDMC_TRAINING_VECTOR (FZC_DMC + 0x000c8UL)
+#define RDMC_TRAINING_VECTOR_TRAINING_VECTOR 0x00000000ffffffffULL
+
+#define RX_CTL_DAT_FIFO_STAT_DBG (FZC_DMC + 0x000d0UL)
+#define RX_CTL_DAT_FIFO_STAT_DBG_ID_MISMATCH 0x0000000000000100ULL
+#define RX_CTL_DAT_FIFO_STAT_DBG_ZCP_EOP_ERR 0x00000000000000f0ULL
+#define RX_CTL_DAT_FIFO_STAT_DBG_IPP_EOP_ERR 0x000000000000000fULL
+
+#define RDC_TBL(TBL,SLOT) (FZC_ZCP + 0x10000UL + \
+ (TBL) * (8UL * 16UL) + \
+ (SLOT) * 8UL)
+#define RDC_TBL_RDC 0x000000000000000fULL
+
+#define RX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x20000UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL
+#define RX_LOG_PAGE_VLD_FUNC_SHIFT 2
+#define RX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL
+#define RX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL
+
+#define RX_LOG_MASK1(IDX) (FZC_DMC + 0x20008UL + (IDX) * 0x40UL)
+#define RX_LOG_MASK1_MASK 0x00000000ffffffffULL
+
+#define RX_LOG_VAL1(IDX) (FZC_DMC + 0x20010UL + (IDX) * 0x40UL)
+#define RX_LOG_VAL1_VALUE 0x00000000ffffffffULL
+
+#define RX_LOG_MASK2(IDX) (FZC_DMC + 0x20018UL + (IDX) * 0x40UL)
+#define RX_LOG_MASK2_MASK 0x00000000ffffffffULL
+
+#define RX_LOG_VAL2(IDX) (FZC_DMC + 0x20020UL + (IDX) * 0x40UL)
+#define RX_LOG_VAL2_VALUE 0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x20028UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x20030UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x20038UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL
+
+#define TX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x40000UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL
+#define TX_LOG_PAGE_VLD_FUNC_SHIFT 2
+#define TX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL
+#define TX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL
+
+#define TX_LOG_MASK1(IDX) (FZC_DMC + 0x40008UL + (IDX) * 0x200UL)
+#define TX_LOG_MASK1_MASK 0x00000000ffffffffULL
+
+#define TX_LOG_VAL1(IDX) (FZC_DMC + 0x40010UL + (IDX) * 0x200UL)
+#define TX_LOG_VAL1_VALUE 0x00000000ffffffffULL
+
+#define TX_LOG_MASK2(IDX) (FZC_DMC + 0x40018UL + (IDX) * 0x200UL)
+#define TX_LOG_MASK2_MASK 0x00000000ffffffffULL
+
+#define TX_LOG_VAL2(IDX) (FZC_DMC + 0x40020UL + (IDX) * 0x200UL)
+#define TX_LOG_VAL2_VALUE 0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x40028UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x40030UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x40038UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL
+
+#define TX_ADDR_MD (FZC_DMC + 0x45000UL)
+#define TX_ADDR_MD_MODE32 0x0000000000000001ULL
+
+#define RDC_RED_PARA(IDX) (FZC_DMC + 0x30000UL + (IDX) * 0x40UL)
+#define RDC_RED_PARA_THRE_SYN 0x00000000fff00000ULL
+#define RDC_RED_PARA_THRE_SYN_SHIFT 20
+#define RDC_RED_PARA_WIN_SYN 0x00000000000f0000ULL
+#define RDC_RED_PARA_WIN_SYN_SHIFT 16
+#define RDC_RED_PARA_THRE 0x000000000000fff0ULL
+#define RDC_RED_PARA_THRE_SHIFT 4
+#define RDC_RED_PARA_WIN 0x000000000000000fULL
+#define RDC_RED_PARA_WIN_SHIFT 0
+
+#define RED_DIS_CNT(IDX) (FZC_DMC + 0x30008UL + (IDX) * 0x40UL)
+#define RED_DIS_CNT_OFLOW 0x0000000000010000ULL
+#define RED_DIS_CNT_COUNT 0x000000000000ffffULL
+
+#define IPP_CFIG (FZC_IPP + 0x00000UL)
+#define IPP_CFIG_SOFT_RST 0x0000000080000000ULL
+#define IPP_CFIG_IP_MAX_PKT 0x0000000001ffff00ULL
+#define IPP_CFIG_IP_MAX_PKT_SHIFT 8
+#define IPP_CFIG_FFLP_CS_PIO_W 0x0000000000000080ULL
+#define IPP_CFIG_PFIFO_PIO_W 0x0000000000000040ULL
+#define IPP_CFIG_DFIFO_PIO_W 0x0000000000000020ULL
+#define IPP_CFIG_CKSUM_EN 0x0000000000000010ULL
+#define IPP_CFIG_DROP_BAD_CRC 0x0000000000000008ULL
+#define IPP_CFIG_DFIFO_ECC_EN 0x0000000000000004ULL
+#define IPP_CFIG_DEBUG_BUS_OUT_EN 0x0000000000000002ULL
+#define IPP_CFIG_IPP_ENABLE 0x0000000000000001ULL
+
+#define IPP_PKT_DIS (FZC_IPP + 0x00020UL)
+#define IPP_PKT_DIS_COUNT 0x0000000000003fffULL
+
+#define IPP_BAD_CS_CNT (FZC_IPP + 0x00028UL)
+#define IPP_BAD_CS_CNT_COUNT 0x0000000000003fffULL
+
+#define IPP_ECC (FZC_IPP + 0x00030UL)
+#define IPP_ECC_COUNT 0x00000000000000ffULL
+
+#define IPP_INT_STAT (FZC_IPP + 0x00040UL)
+#define IPP_INT_STAT_SOP_MISS 0x0000000080000000ULL
+#define IPP_INT_STAT_EOP_MISS 0x0000000040000000ULL
+#define IPP_INT_STAT_DFIFO_UE 0x0000000030000000ULL
+#define IPP_INT_STAT_DFIFO_CE 0x000000000c000000ULL
+#define IPP_INT_STAT_DFIFO_ECC 0x0000000003000000ULL
+#define IPP_INT_STAT_DFIFO_ECC_IDX 0x00000000007ff000ULL
+#define IPP_INT_STAT_PFIFO_PERR 0x0000000000000800ULL
+#define IPP_INT_STAT_ECC_ERR_MAX 0x0000000000000400ULL
+#define IPP_INT_STAT_PFIFO_ERR_IDX 0x00000000000003f0ULL
+#define IPP_INT_STAT_PFIFO_OVER 0x0000000000000008ULL
+#define IPP_INT_STAT_PFIFO_UND 0x0000000000000004ULL
+#define IPP_INT_STAT_BAD_CS_MX 0x0000000000000002ULL
+#define IPP_INT_STAT_PKT_DIS_MX 0x0000000000000001ULL
+#define IPP_INT_STAT_ALL 0x00000000ff7fffffULL
+
+#define IPP_MSK (FZC_IPP + 0x00048UL)
+#define IPP_MSK_ECC_ERR_MX 0x0000000000000080ULL
+#define IPP_MSK_DFIFO_EOP_SOP 0x0000000000000040ULL
+#define IPP_MSK_DFIFO_UC 0x0000000000000020ULL
+#define IPP_MSK_PFIFO_PAR 0x0000000000000010ULL
+#define IPP_MSK_PFIFO_OVER 0x0000000000000008ULL
+#define IPP_MSK_PFIFO_UND 0x0000000000000004ULL
+#define IPP_MSK_BAD_CS 0x0000000000000002ULL
+#define IPP_MSK_PKT_DIS_CNT 0x0000000000000001ULL
+#define IPP_MSK_ALL 0x00000000000000ffULL
+
+#define IPP_PFIFO_RD0 (FZC_IPP + 0x00060UL)
+#define IPP_PFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_PFIFO_RD1 (FZC_IPP + 0x00068UL)
+#define IPP_PFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_PFIFO_RD2 (FZC_IPP + 0x00070UL)
+#define IPP_PFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_PFIFO_RD3 (FZC_IPP + 0x00078UL)
+#define IPP_PFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_PFIFO_RD4 (FZC_IPP + 0x00080UL)
+#define IPP_PFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_PFIFO_WR0 (FZC_IPP + 0x00088UL)
+#define IPP_PFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_PFIFO_WR1 (FZC_IPP + 0x00090UL)
+#define IPP_PFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_PFIFO_WR2 (FZC_IPP + 0x00098UL)
+#define IPP_PFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_PFIFO_WR3 (FZC_IPP + 0x000a0UL)
+#define IPP_PFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_PFIFO_WR4 (FZC_IPP + 0x000a8UL)
+#define IPP_PFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_PFIFO_RD_PTR (FZC_IPP + 0x000b0UL)
+#define IPP_PFIFO_RD_PTR_PTR 0x000000000000003fULL
+
+#define IPP_PFIFO_WR_PTR (FZC_IPP + 0x000b8UL)
+#define IPP_PFIFO_WR_PTR_PTR 0x000000000000007fULL
+
+#define IPP_DFIFO_RD0 (FZC_IPP + 0x000c0UL)
+#define IPP_DFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_DFIFO_RD1 (FZC_IPP + 0x000c8UL)
+#define IPP_DFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_DFIFO_RD2 (FZC_IPP + 0x000d0UL)
+#define IPP_DFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_DFIFO_RD3 (FZC_IPP + 0x000d8UL)
+#define IPP_DFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_DFIFO_RD4 (FZC_IPP + 0x000e0UL)
+#define IPP_DFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_DFIFO_WR0 (FZC_IPP + 0x000e8UL)
+#define IPP_DFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_DFIFO_WR1 (FZC_IPP + 0x000f0UL)
+#define IPP_DFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_DFIFO_WR2 (FZC_IPP + 0x000f8UL)
+#define IPP_DFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_DFIFO_WR3 (FZC_IPP + 0x00100UL)
+#define IPP_DFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_DFIFO_WR4 (FZC_IPP + 0x00108UL)
+#define IPP_DFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_DFIFO_RD_PTR (FZC_IPP + 0x00110UL)
+#define IPP_DFIFO_RD_PTR_PTR 0x0000000000000fffULL
+
+#define IPP_DFIFO_WR_PTR (FZC_IPP + 0x00118UL)
+#define IPP_DFIFO_WR_PTR_PTR 0x0000000000000fffULL
+
+#define IPP_SM (FZC_IPP + 0x00120UL)
+#define IPP_SM_SM 0x00000000ffffffffULL
+
+#define IPP_CS_STAT (FZC_IPP + 0x00128UL)
+#define IPP_CS_STAT_BCYC_CNT 0x00000000ff000000ULL
+#define IPP_CS_STAT_IP_LEN 0x0000000000fff000ULL
+#define IPP_CS_STAT_CS_FAIL 0x0000000000000800ULL
+#define IPP_CS_STAT_TERM 0x0000000000000400ULL
+#define IPP_CS_STAT_BAD_NUM 0x0000000000000200ULL
+#define IPP_CS_STAT_CS_STATE 0x00000000000001ffULL
+
+#define IPP_FFLP_CS_INFO (FZC_IPP + 0x00130UL)
+#define IPP_FFLP_CS_INFO_PKT_ID 0x0000000000003c00ULL
+#define IPP_FFLP_CS_INFO_L4_PROTO 0x0000000000000300ULL
+#define IPP_FFLP_CS_INFO_V4_HD_LEN 0x00000000000000f0ULL
+#define IPP_FFLP_CS_INFO_L3_VER 0x000000000000000cULL
+#define IPP_FFLP_CS_INFO_L2_OP 0x0000000000000003ULL
+
+#define IPP_DBG_SEL (FZC_IPP + 0x00138UL)
+#define IPP_DBG_SEL_SEL 0x000000000000000fULL
+
+#define IPP_DFIFO_ECC_SYND (FZC_IPP + 0x00140UL)
+#define IPP_DFIFO_ECC_SYND_SYND 0x000000000000ffffULL
+
+#define IPP_DFIFO_EOP_RD_PTR (FZC_IPP + 0x00148UL)
+#define IPP_DFIFO_EOP_RD_PTR_PTR 0x0000000000000fffULL
+
+#define IPP_ECC_CTL (FZC_IPP + 0x00150UL)
+#define IPP_ECC_CTL_DIS_DBL 0x0000000080000000ULL
+#define IPP_ECC_CTL_COR_DBL 0x0000000000020000ULL
+#define IPP_ECC_CTL_COR_SNG 0x0000000000010000ULL
+#define IPP_ECC_CTL_COR_ALL 0x0000000000000400ULL
+#define IPP_ECC_CTL_COR_1 0x0000000000000100ULL
+#define IPP_ECC_CTL_COR_LST 0x0000000000000004ULL
+#define IPP_ECC_CTL_COR_SND 0x0000000000000002ULL
+#define IPP_ECC_CTL_COR_FSR 0x0000000000000001ULL
+
+#define NIU_DFIFO_ENTRIES 1024
+#define ATLAS_P0_P1_DFIFO_ENTRIES 2048
+#define ATLAS_P2_P3_DFIFO_ENTRIES 1024
+
+#define ZCP_CFIG (FZC_ZCP + 0x00000UL)
+#define ZCP_CFIG_ZCP_32BIT_MODE 0x0000000001000000ULL
+#define ZCP_CFIG_ZCP_DEBUG_SEL 0x0000000000ff0000ULL
+#define ZCP_CFIG_DMA_TH 0x000000000000ffe0ULL
+#define ZCP_CFIG_ECC_CHK_DIS 0x0000000000000010ULL
+#define ZCP_CFIG_PAR_CHK_DIS 0x0000000000000008ULL
+#define ZCP_CFIG_DIS_BUFF_RSP_IF 0x0000000000000004ULL
+#define ZCP_CFIG_DIS_BUFF_REQ_IF 0x0000000000000002ULL
+#define ZCP_CFIG_ZC_ENABLE 0x0000000000000001ULL
+
+#define ZCP_INT_STAT (FZC_ZCP + 0x00008UL)
+#define ZCP_INT_STAT_RRFIFO_UNDERRUN 0x0000000000008000ULL
+#define ZCP_INT_STAT_RRFIFO_OVERRUN 0x0000000000004000ULL
+#define ZCP_INT_STAT_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL
+#define ZCP_INT_STAT_BUFFER_OVERFLOW 0x0000000000000800ULL
+#define ZCP_INT_STAT_STAT_TBL_PERR 0x0000000000000400ULL
+#define ZCP_INT_STAT_DYN_TBL_PERR 0x0000000000000200ULL
+#define ZCP_INT_STAT_BUF_TBL_PERR 0x0000000000000100ULL
+#define ZCP_INT_STAT_TT_PROGRAM_ERR 0x0000000000000080ULL
+#define ZCP_INT_STAT_RSP_TT_INDEX_ERR 0x0000000000000040ULL
+#define ZCP_INT_STAT_SLV_TT_INDEX_ERR 0x0000000000000020ULL
+#define ZCP_INT_STAT_ZCP_TT_INDEX_ERR 0x0000000000000010ULL
+#define ZCP_INT_STAT_CFIFO_ECC3 0x0000000000000008ULL
+#define ZCP_INT_STAT_CFIFO_ECC2 0x0000000000000004ULL
+#define ZCP_INT_STAT_CFIFO_ECC1 0x0000000000000002ULL
+#define ZCP_INT_STAT_CFIFO_ECC0 0x0000000000000001ULL
+#define ZCP_INT_STAT_ALL 0x000000000000ffffULL
+
+#define ZCP_INT_MASK (FZC_ZCP + 0x00010UL)
+#define ZCP_INT_MASK_RRFIFO_UNDERRUN 0x0000000000008000ULL
+#define ZCP_INT_MASK_RRFIFO_OVERRUN 0x0000000000004000ULL
+#define ZCP_INT_MASK_LOJ 0x0000000000002000ULL
+#define ZCP_INT_MASK_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL
+#define ZCP_INT_MASK_BUFFER_OVERFLOW 0x0000000000000800ULL
+#define ZCP_INT_MASK_STAT_TBL_PERR 0x0000000000000400ULL
+#define ZCP_INT_MASK_DYN_TBL_PERR 0x0000000000000200ULL
+#define ZCP_INT_MASK_BUF_TBL_PERR 0x0000000000000100ULL
+#define ZCP_INT_MASK_TT_PROGRAM_ERR 0x0000000000000080ULL
+#define ZCP_INT_MASK_RSP_TT_INDEX_ERR 0x0000000000000040ULL
+#define ZCP_INT_MASK_SLV_TT_INDEX_ERR 0x0000000000000020ULL
+#define ZCP_INT_MASK_ZCP_TT_INDEX_ERR 0x0000000000000010ULL
+#define ZCP_INT_MASK_CFIFO_ECC3 0x0000000000000008ULL
+#define ZCP_INT_MASK_CFIFO_ECC2 0x0000000000000004ULL
+#define ZCP_INT_MASK_CFIFO_ECC1 0x0000000000000002ULL
+#define ZCP_INT_MASK_CFIFO_ECC0 0x0000000000000001ULL
+#define ZCP_INT_MASK_ALL 0x000000000000ffffULL
+
+#define BAM4BUF (FZC_ZCP + 0x00018UL)
+#define BAM4BUF_LOJ 0x0000000080000000ULL
+#define BAM4BUF_EN_CK 0x0000000040000000ULL
+#define BAM4BUF_IDX_END0 0x000000003ff00000ULL
+#define BAM4BUF_IDX_ST0 0x00000000000ffc00ULL
+#define BAM4BUF_OFFSET0 0x00000000000003ffULL
+
+#define BAM8BUF (FZC_ZCP + 0x00020UL)
+#define BAM8BUF_LOJ 0x0000000080000000ULL
+#define BAM8BUF_EN_CK 0x0000000040000000ULL
+#define BAM8BUF_IDX_END1 0x000000003ff00000ULL
+#define BAM8BUF_IDX_ST1 0x00000000000ffc00ULL
+#define BAM8BUF_OFFSET1 0x00000000000003ffULL
+
+#define BAM16BUF (FZC_ZCP + 0x00028UL)
+#define BAM16BUF_LOJ 0x0000000080000000ULL
+#define BAM16BUF_EN_CK 0x0000000040000000ULL
+#define BAM16BUF_IDX_END2 0x000000003ff00000ULL
+#define BAM16BUF_IDX_ST2 0x00000000000ffc00ULL
+#define BAM16BUF_OFFSET2 0x00000000000003ffULL
+
+#define BAM32BUF (FZC_ZCP + 0x00030UL)
+#define BAM32BUF_LOJ 0x0000000080000000ULL
+#define BAM32BUF_EN_CK 0x0000000040000000ULL
+#define BAM32BUF_IDX_END3 0x000000003ff00000ULL
+#define BAM32BUF_IDX_ST3 0x00000000000ffc00ULL
+#define BAM32BUF_OFFSET3 0x00000000000003ffULL
+
+#define DST4BUF (FZC_ZCP + 0x00038UL)
+#define DST4BUF_DS_OFFSET0 0x00000000000003ffULL
+
+#define DST8BUF (FZC_ZCP + 0x00040UL)
+#define DST8BUF_DS_OFFSET1 0x00000000000003ffULL
+
+#define DST16BUF (FZC_ZCP + 0x00048UL)
+#define DST16BUF_DS_OFFSET2 0x00000000000003ffULL
+
+#define DST32BUF (FZC_ZCP + 0x00050UL)
+#define DST32BUF_DS_OFFSET3 0x00000000000003ffULL
+
+#define ZCP_RAM_DATA0 (FZC_ZCP + 0x00058UL)
+#define ZCP_RAM_DATA0_DAT0 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA1 (FZC_ZCP + 0x00060UL)
+#define ZCP_RAM_DAT10_DAT1 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA2 (FZC_ZCP + 0x00068UL)
+#define ZCP_RAM_DATA2_DAT2 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA3 (FZC_ZCP + 0x00070UL)
+#define ZCP_RAM_DATA3_DAT3 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA4 (FZC_ZCP + 0x00078UL)
+#define ZCP_RAM_DATA4_DAT4 0x00000000000000ffULL
+
+#define ZCP_RAM_BE (FZC_ZCP + 0x00080UL)
+#define ZCP_RAM_BE_VAL 0x000000000001ffffULL
+
+#define ZCP_RAM_ACC (FZC_ZCP + 0x00088UL)
+#define ZCP_RAM_ACC_BUSY 0x0000000080000000ULL
+#define ZCP_RAM_ACC_READ 0x0000000040000000ULL
+#define ZCP_RAM_ACC_WRITE 0x0000000000000000ULL
+#define ZCP_RAM_ACC_LOJ 0x0000000020000000ULL
+#define ZCP_RAM_ACC_ZFCID 0x000000001ffe0000ULL
+#define ZCP_RAM_ACC_ZFCID_SHIFT 17
+#define ZCP_RAM_ACC_RAM_SEL 0x000000000001f000ULL
+#define ZCP_RAM_ACC_RAM_SEL_SHIFT 12
+#define ZCP_RAM_ACC_CFIFOADDR 0x0000000000000fffULL
+#define ZCP_RAM_ACC_CFIFOADDR_SHIFT 0
+
+#define ZCP_RAM_SEL_BAM(INDEX) (0x00 + (INDEX))
+#define ZCP_RAM_SEL_TT_STATIC 0x08
+#define ZCP_RAM_SEL_TT_DYNAMIC 0x09
+#define ZCP_RAM_SEL_CFIFO(PORT) (0x10 + (PORT))
+
+#define NIU_CFIFO_ENTRIES 1024
+#define ATLAS_P0_P1_CFIFO_ENTRIES 2048
+#define ATLAS_P2_P3_CFIFO_ENTRIES 1024
+
+#define CHK_BIT_DATA (FZC_ZCP + 0x00090UL)
+#define CHK_BIT_DATA_DATA 0x000000000000ffffULL
+
+#define RESET_CFIFO (FZC_ZCP + 0x00098UL)
+#define RESET_CFIFO_RST(PORT) (0x1 << (PORT))
+
+#define CFIFO_ECC(PORT) (FZC_ZCP + 0x000a0UL + (PORT) * 8UL)
+#define CFIFO_ECC_DIS_DBLBIT_ERR 0x0000000080000000ULL
+#define CFIFO_ECC_DBLBIT_ERR 0x0000000000020000ULL
+#define CFIFO_ECC_SINGLEBIT_ERR 0x0000000000010000ULL
+#define CFIFO_ECC_ALL_PKT 0x0000000000000400ULL
+#define CFIFO_ECC_LAST_LINE 0x0000000000000004ULL
+#define CFIFO_ECC_2ND_LINE 0x0000000000000002ULL
+#define CFIFO_ECC_1ST_LINE 0x0000000000000001ULL
+
+#define ZCP_TRAINING_VECTOR (FZC_ZCP + 0x000c0UL)
+#define ZCP_TRAINING_VECTOR_VECTOR 0x00000000ffffffffULL
+
+#define ZCP_STATE_MACHINE (FZC_ZCP + 0x000c8UL)
+#define ZCP_STATE_MACHINE_SM 0x00000000ffffffffULL
+
+/* Same bits as ZCP_INT_STAT */
+#define ZCP_INT_STAT_TEST (FZC_ZCP + 0x00108UL)
+
+#define RXDMA_CFIG1(IDX) (DMC + 0x00000UL + (IDX) * 0x200UL)
+#define RXDMA_CFIG1_EN 0x0000000080000000ULL
+#define RXDMA_CFIG1_RST 0x0000000040000000ULL
+#define RXDMA_CFIG1_QST 0x0000000020000000ULL
+#define RXDMA_CFIG1_MBADDR_H 0x0000000000000fffULL /* mboxaddr 43:32 */
+
+#define RXDMA_CFIG2(IDX) (DMC + 0x00008UL + (IDX) * 0x200UL)
+#define RXDMA_CFIG2_MBADDR_L 0x00000000ffffffc0ULL /* mboxaddr 31:6 */
+#define RXDMA_CFIG2_OFFSET 0x0000000000000006ULL
+#define RXDMA_CFIG2_OFFSET_SHIFT 1
+#define RXDMA_CFIG2_FULL_HDR 0x0000000000000001ULL
+
+#define RBR_CFIG_A(IDX) (DMC + 0x00010UL + (IDX) * 0x200UL)
+#define RBR_CFIG_A_LEN 0xffff000000000000ULL
+#define RBR_CFIG_A_LEN_SHIFT 48
+#define RBR_CFIG_A_STADDR_BASE 0x00000ffffffc0000ULL
+#define RBR_CFIG_A_STADDR 0x000000000003ffc0ULL
+
+#define RBR_CFIG_B(IDX) (DMC + 0x00018UL + (IDX) * 0x200UL)
+#define RBR_CFIG_B_BLKSIZE 0x0000000003000000ULL
+#define RBR_CFIG_B_BLKSIZE_SHIFT 24
+#define RBR_CFIG_B_VLD2 0x0000000000800000ULL
+#define RBR_CFIG_B_BUFSZ2 0x0000000000030000ULL
+#define RBR_CFIG_B_BUFSZ2_SHIFT 16
+#define RBR_CFIG_B_VLD1 0x0000000000008000ULL
+#define RBR_CFIG_B_BUFSZ1 0x0000000000000300ULL
+#define RBR_CFIG_B_BUFSZ1_SHIFT 8
+#define RBR_CFIG_B_VLD0 0x0000000000000080ULL
+#define RBR_CFIG_B_BUFSZ0 0x0000000000000003ULL
+#define RBR_CFIG_B_BUFSZ0_SHIFT 0
+
+#define RBR_BLKSIZE_4K 0x0
+#define RBR_BLKSIZE_8K 0x1
+#define RBR_BLKSIZE_16K 0x2
+#define RBR_BLKSIZE_32K 0x3
+#define RBR_BUFSZ2_2K 0x0
+#define RBR_BUFSZ2_4K 0x1
+#define RBR_BUFSZ2_8K 0x2
+#define RBR_BUFSZ2_16K 0x3
+#define RBR_BUFSZ1_1K 0x0
+#define RBR_BUFSZ1_2K 0x1
+#define RBR_BUFSZ1_4K 0x2
+#define RBR_BUFSZ1_8K 0x3
+#define RBR_BUFSZ0_256 0x0
+#define RBR_BUFSZ0_512 0x1
+#define RBR_BUFSZ0_1K 0x2
+#define RBR_BUFSZ0_2K 0x3
+
+#define RBR_KICK(IDX) (DMC + 0x00020UL + (IDX) * 0x200UL)
+#define RBR_KICK_BKADD 0x000000000000ffffULL
+
+#define RBR_STAT(IDX) (DMC + 0x00028UL + (IDX) * 0x200UL)
+#define RBR_STAT_QLEN 0x000000000000ffffULL
+
+#define RBR_HDH(IDX) (DMC + 0x00030UL + (IDX) * 0x200UL)
+#define RBR_HDH_HEAD_H 0x0000000000000fffULL
+
+#define RBR_HDL(IDX) (DMC + 0x00038UL + (IDX) * 0x200UL)
+#define RBR_HDL_HEAD_L 0x00000000fffffffcULL
+
+#define RCRCFIG_A(IDX) (DMC + 0x00040UL + (IDX) * 0x200UL)
+#define RCRCFIG_A_LEN 0xffff000000000000ULL
+#define RCRCFIG_A_LEN_SHIFT 48
+#define RCRCFIG_A_STADDR_BASE 0x00000ffffff80000ULL
+#define RCRCFIG_A_STADDR 0x000000000007ffc0ULL
+
+#define RCRCFIG_B(IDX) (DMC + 0x00048UL + (IDX) * 0x200UL)
+#define RCRCFIG_B_PTHRES 0x00000000ffff0000ULL
+#define RCRCFIG_B_PTHRES_SHIFT 16
+#define RCRCFIG_B_ENTOUT 0x0000000000008000ULL
+#define RCRCFIG_B_TIMEOUT 0x000000000000003fULL
+#define RCRCFIG_B_TIMEOUT_SHIFT 0
+
+#define RCRSTAT_A(IDX) (DMC + 0x00050UL + (IDX) * 0x200UL)
+#define RCRSTAT_A_QLEN 0x000000000000ffffULL
+
+#define RCRSTAT_B(IDX) (DMC + 0x00058UL + (IDX) * 0x200UL)
+#define RCRSTAT_B_TIPTR_H 0x0000000000000fffULL
+
+#define RCRSTAT_C(IDX) (DMC + 0x00060UL + (IDX) * 0x200UL)
+#define RCRSTAT_C_TIPTR_L 0x00000000fffffff8ULL
+
+#define RX_DMA_CTL_STAT(IDX) (DMC + 0x00070UL + (IDX) * 0x200UL)
+#define RX_DMA_CTL_STAT_RBR_TMOUT 0x0020000000000000ULL
+#define RX_DMA_CTL_STAT_RSP_CNT_ERR 0x0010000000000000ULL
+#define RX_DMA_CTL_STAT_BYTE_EN_BUS 0x0008000000000000ULL
+#define RX_DMA_CTL_STAT_RSP_DAT_ERR 0x0004000000000000ULL
+#define RX_DMA_CTL_STAT_RCR_ACK_ERR 0x0002000000000000ULL
+#define RX_DMA_CTL_STAT_DC_FIFO_ERR 0x0001000000000000ULL
+#define RX_DMA_CTL_STAT_MEX 0x0000800000000000ULL
+#define RX_DMA_CTL_STAT_RCRTHRES 0x0000400000000000ULL
+#define RX_DMA_CTL_STAT_RCRTO 0x0000200000000000ULL
+#define RX_DMA_CTL_STAT_RCR_SHA_PAR 0x0000100000000000ULL
+#define RX_DMA_CTL_STAT_RBR_PRE_PAR 0x0000080000000000ULL
+#define RX_DMA_CTL_STAT_PORT_DROP_PKT 0x0000040000000000ULL
+#define RX_DMA_CTL_STAT_WRED_DROP 0x0000020000000000ULL
+#define RX_DMA_CTL_STAT_RBR_PRE_EMTY 0x0000010000000000ULL
+#define RX_DMA_CTL_STAT_RCRSHADOW_FULL 0x0000008000000000ULL
+#define RX_DMA_CTL_STAT_CONFIG_ERR 0x0000004000000000ULL
+#define RX_DMA_CTL_STAT_RCRINCON 0x0000002000000000ULL
+#define RX_DMA_CTL_STAT_RCRFULL 0x0000001000000000ULL
+#define RX_DMA_CTL_STAT_RBR_EMPTY 0x0000000800000000ULL
+#define RX_DMA_CTL_STAT_RBRFULL 0x0000000400000000ULL
+#define RX_DMA_CTL_STAT_RBRLOGPAGE 0x0000000200000000ULL
+#define RX_DMA_CTL_STAT_CFIGLOGPAGE 0x0000000100000000ULL
+#define RX_DMA_CTL_STAT_PTRREAD 0x00000000ffff0000ULL
+#define RX_DMA_CTL_STAT_PTRREAD_SHIFT 16
+#define RX_DMA_CTL_STAT_PKTREAD 0x000000000000ffffULL
+#define RX_DMA_CTL_STAT_PKTREAD_SHIFT 0
+
+#define RX_DMA_CTL_STAT_CHAN_FATAL (RX_DMA_CTL_STAT_RBR_TMOUT | \
+ RX_DMA_CTL_STAT_RSP_CNT_ERR | \
+ RX_DMA_CTL_STAT_BYTE_EN_BUS | \
+ RX_DMA_CTL_STAT_RSP_DAT_ERR | \
+ RX_DMA_CTL_STAT_RCR_ACK_ERR | \
+ RX_DMA_CTL_STAT_RCR_SHA_PAR | \
+ RX_DMA_CTL_STAT_RBR_PRE_PAR | \
+ RX_DMA_CTL_STAT_CONFIG_ERR | \
+ RX_DMA_CTL_STAT_RCRINCON | \
+ RX_DMA_CTL_STAT_RCRFULL | \
+ RX_DMA_CTL_STAT_RBRFULL | \
+ RX_DMA_CTL_STAT_RBRLOGPAGE | \
+ RX_DMA_CTL_STAT_CFIGLOGPAGE)
+
+#define RX_DMA_CTL_STAT_PORT_FATAL (RX_DMA_CTL_STAT_DC_FIFO_ERR)
+
+#define RX_DMA_CTL_WRITE_CLEAR_ERRS (RX_DMA_CTL_STAT_RBR_EMPTY | \
+ RX_DMA_CTL_STAT_RCRSHADOW_FULL | \
+ RX_DMA_CTL_STAT_RBR_PRE_EMTY | \
+ RX_DMA_CTL_STAT_WRED_DROP | \
+ RX_DMA_CTL_STAT_PORT_DROP_PKT | \
+ RX_DMA_CTL_STAT_RCRTO | \
+ RX_DMA_CTL_STAT_RCRTHRES | \
+ RX_DMA_CTL_STAT_DC_FIFO_ERR)
+
+#define RCR_FLSH(IDX) (DMC + 0x00078UL + (IDX) * 0x200UL)
+#define RCR_FLSH_FLSH 0x0000000000000001ULL
+
+#define RXMISC(IDX) (DMC + 0x00090UL + (IDX) * 0x200UL)
+#define RXMISC_OFLOW 0x0000000000010000ULL
+#define RXMISC_COUNT 0x000000000000ffffULL
+
+#define RX_DMA_CTL_STAT_DBG(IDX) (DMC + 0x00098UL + (IDX) * 0x200UL)
+#define RX_DMA_CTL_STAT_DBG_RBR_TMOUT 0x0020000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RSP_CNT_ERR 0x0010000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_BYTE_EN_BUS 0x0008000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RSP_DAT_ERR 0x0004000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCR_ACK_ERR 0x0002000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_DC_FIFO_ERR 0x0001000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_MEX 0x0000800000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRTHRES 0x0000400000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRTO 0x0000200000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCR_SHA_PAR 0x0000100000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBR_PRE_PAR 0x0000080000000000ULL
+#define RX_DMA_CTL_STAT_DBG_PORT_DROP_PKT 0x0000040000000000ULL
+#define RX_DMA_CTL_STAT_DBG_WRED_DROP 0x0000020000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBR_PRE_EMTY 0x0000010000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRSHADOW_FULL 0x0000008000000000ULL
+#define RX_DMA_CTL_STAT_DBG_CONFIG_ERR 0x0000004000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRINCON 0x0000002000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRFULL 0x0000001000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBR_EMPTY 0x0000000800000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBRFULL 0x0000000400000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBRLOGPAGE 0x0000000200000000ULL
+#define RX_DMA_CTL_STAT_DBG_CFIGLOGPAGE 0x0000000100000000ULL
+#define RX_DMA_CTL_STAT_DBG_PTRREAD 0x00000000ffff0000ULL
+#define RX_DMA_CTL_STAT_DBG_PKTREAD 0x000000000000ffffULL
+
+#define RX_DMA_ENT_MSK(IDX) (DMC + 0x00068UL + (IDX) * 0x200UL)
+#define RX_DMA_ENT_MSK_RBR_TMOUT 0x0000000000200000ULL
+#define RX_DMA_ENT_MSK_RSP_CNT_ERR 0x0000000000100000ULL
+#define RX_DMA_ENT_MSK_BYTE_EN_BUS 0x0000000000080000ULL
+#define RX_DMA_ENT_MSK_RSP_DAT_ERR 0x0000000000040000ULL
+#define RX_DMA_ENT_MSK_RCR_ACK_ERR 0x0000000000020000ULL
+#define RX_DMA_ENT_MSK_DC_FIFO_ERR 0x0000000000010000ULL
+#define RX_DMA_ENT_MSK_RCRTHRES 0x0000000000004000ULL
+#define RX_DMA_ENT_MSK_RCRTO 0x0000000000002000ULL
+#define RX_DMA_ENT_MSK_RCR_SHA_PAR 0x0000000000001000ULL
+#define RX_DMA_ENT_MSK_RBR_PRE_PAR 0x0000000000000800ULL
+#define RX_DMA_ENT_MSK_PORT_DROP_PKT 0x0000000000000400ULL
+#define RX_DMA_ENT_MSK_WRED_DROP 0x0000000000000200ULL
+#define RX_DMA_ENT_MSK_RBR_PRE_EMTY 0x0000000000000100ULL
+#define RX_DMA_ENT_MSK_RCR_SHADOW_FULL 0x0000000000000080ULL
+#define RX_DMA_ENT_MSK_CONFIG_ERR 0x0000000000000040ULL
+#define RX_DMA_ENT_MSK_RCRINCON 0x0000000000000020ULL
+#define RX_DMA_ENT_MSK_RCRFULL 0x0000000000000010ULL
+#define RX_DMA_ENT_MSK_RBR_EMPTY 0x0000000000000008ULL
+#define RX_DMA_ENT_MSK_RBRFULL 0x0000000000000004ULL
+#define RX_DMA_ENT_MSK_RBRLOGPAGE 0x0000000000000002ULL
+#define RX_DMA_ENT_MSK_CFIGLOGPAGE 0x0000000000000001ULL
+#define RX_DMA_ENT_MSK_ALL 0x00000000003f7fffULL
+
+#define TX_RNG_CFIG(IDX) (DMC + 0x40000UL + (IDX) * 0x200UL)
+#define TX_RNG_CFIG_LEN 0x1fff000000000000ULL
+#define TX_RNG_CFIG_LEN_SHIFT 48
+#define TX_RNG_CFIG_STADDR_BASE 0x00000ffffff80000ULL
+#define TX_RNG_CFIG_STADDR 0x000000000007ffc0ULL
+
+#define TX_RING_HDL(IDX) (DMC + 0x40010UL + (IDX) * 0x200UL)
+#define TX_RING_HDL_WRAP 0x0000000000080000ULL
+#define TX_RING_HDL_HEAD 0x000000000007fff8ULL
+#define TX_RING_HDL_HEAD_SHIFT 3
+
+#define TX_RING_KICK(IDX) (DMC + 0x40018UL + (IDX) * 0x200UL)
+#define TX_RING_KICK_WRAP 0x0000000000080000ULL
+#define TX_RING_KICK_TAIL 0x000000000007fff8ULL
+
+#define TX_ENT_MSK(IDX) (DMC + 0x40020UL + (IDX) * 0x200UL)
+#define TX_ENT_MSK_MK 0x0000000000008000ULL
+#define TX_ENT_MSK_MBOX_ERR 0x0000000000000080ULL
+#define TX_ENT_MSK_PKT_SIZE_ERR 0x0000000000000040ULL
+#define TX_ENT_MSK_TX_RING_OFLOW 0x0000000000000020ULL
+#define TX_ENT_MSK_PREF_BUF_ECC_ERR 0x0000000000000010ULL
+#define TX_ENT_MSK_NACK_PREF 0x0000000000000008ULL
+#define TX_ENT_MSK_NACK_PKT_RD 0x0000000000000004ULL
+#define TX_ENT_MSK_CONF_PART_ERR 0x0000000000000002ULL
+#define TX_ENT_MSK_PKT_PRT_ERR 0x0000000000000001ULL
+
+#define TX_CS(IDX) (DMC + 0x40028UL + (IDX)*0x200UL)
+#define TX_CS_PKT_CNT 0x0fff000000000000ULL
+#define TX_CS_PKT_CNT_SHIFT 48
+#define TX_CS_LASTMARK 0x00000fff00000000ULL
+#define TX_CS_LASTMARK_SHIFT 32
+#define TX_CS_RST 0x0000000080000000ULL
+#define TX_CS_RST_STATE 0x0000000040000000ULL
+#define TX_CS_MB 0x0000000020000000ULL
+#define TX_CS_STOP_N_GO 0x0000000010000000ULL
+#define TX_CS_SNG_STATE 0x0000000008000000ULL
+#define TX_CS_MK 0x0000000000008000ULL
+#define TX_CS_MMK 0x0000000000004000ULL
+#define TX_CS_MBOX_ERR 0x0000000000000080ULL
+#define TX_CS_PKT_SIZE_ERR 0x0000000000000040ULL
+#define TX_CS_TX_RING_OFLOW 0x0000000000000020ULL
+#define TX_CS_PREF_BUF_PAR_ERR 0x0000000000000010ULL
+#define TX_CS_NACK_PREF 0x0000000000000008ULL
+#define TX_CS_NACK_PKT_RD 0x0000000000000004ULL
+#define TX_CS_CONF_PART_ERR 0x0000000000000002ULL
+#define TX_CS_PKT_PRT_ERR 0x0000000000000001ULL
+
+#define TXDMA_MBH(IDX) (DMC + 0x40030UL + (IDX) * 0x200UL)
+#define TXDMA_MBH_MBADDR 0x0000000000000fffULL
+
+#define TXDMA_MBL(IDX) (DMC + 0x40038UL + (IDX) * 0x200UL)
+#define TXDMA_MBL_MBADDR 0x00000000ffffffc0ULL
+
+#define TX_DMA_PRE_ST(IDX) (DMC + 0x40040UL + (IDX) * 0x200UL)
+#define TX_DMA_PRE_ST_SHADOW_HD 0x000000000007ffffULL
+
+#define TX_RNG_ERR_LOGH(IDX) (DMC + 0x40048UL + (IDX) * 0x200UL)
+#define TX_RNG_ERR_LOGH_ERR 0x0000000080000000ULL
+#define TX_RNG_ERR_LOGH_MERR 0x0000000040000000ULL
+#define TX_RNG_ERR_LOGH_ERRCODE 0x0000000038000000ULL
+#define TX_RNG_ERR_LOGH_ERRADDR 0x0000000000000fffULL
+
+#define TX_RNG_ERR_LOGL(IDX) (DMC + 0x40050UL + (IDX) * 0x200UL)
+#define TX_RNG_ERR_LOGL_ERRADDR 0x00000000ffffffffULL
+
+#define TDMC_INTR_DBG(IDX) (DMC + 0x40060UL + (IDX) * 0x200UL)
+#define TDMC_INTR_DBG_MK 0x0000000000008000ULL
+#define TDMC_INTR_DBG_MBOX_ERR 0x0000000000000080ULL
+#define TDMC_INTR_DBG_PKT_SIZE_ERR 0x0000000000000040ULL
+#define TDMC_INTR_DBG_TX_RING_OFLOW 0x0000000000000020ULL
+#define TDMC_INTR_DBG_PREF_BUF_PAR_ERR 0x0000000000000010ULL
+#define TDMC_INTR_DBG_NACK_PREF 0x0000000000000008ULL
+#define TDMC_INTR_DBG_NACK_PKT_RD 0x0000000000000004ULL
+#define TDMC_INTR_DBG_CONF_PART_ERR 0x0000000000000002ULL
+#define TDMC_INTR_DBG_PKT_PART_ERR 0x0000000000000001ULL
+
+#define TX_CS_DBG(IDX) (DMC + 0x40068UL + (IDX) * 0x200UL)
+#define TX_CS_DBG_PKT_CNT 0x0fff000000000000ULL
+
+#define TDMC_INJ_PAR_ERR(IDX) (DMC + 0x45040UL + (IDX) * 0x200UL)
+#define TDMC_INJ_PAR_ERR_VAL 0x000000000000ffffULL
+
+#define TDMC_DBG_SEL(IDX) (DMC + 0x45080UL + (IDX) * 0x200UL)
+#define TDMC_DBG_SEL_DBG_SEL 0x000000000000003fULL
+
+#define TDMC_TRAINING_VECTOR(IDX) (DMC + 0x45088UL + (IDX) * 0x200UL)
+#define TDMC_TRAINING_VECTOR_VEC 0x00000000ffffffffULL
+
+#define TXC_DMA_MAX(CHAN) (FZC_TXC + 0x00000UL + (CHAN)*0x1000UL)
+#define TXC_DMA_MAX_LEN(CHAN) (FZC_TXC + 0x00008UL + (CHAN)*0x1000UL)
+
+#define TXC_CONTROL (FZC_TXC + 0x20000UL)
+#define TXC_CONTROL_ENABLE 0x0000000000000010ULL
+#define TXC_CONTROL_PORT_ENABLE(X) (1 << (X))
+
+#define TXC_TRAINING_VEC (FZC_TXC + 0x20008UL)
+#define TXC_TRAINING_VEC_MASK 0x00000000ffffffffULL
+
+#define TXC_DEBUG (FZC_TXC + 0x20010UL)
+#define TXC_DEBUG_SELECT 0x000000000000003fULL
+
+#define TXC_MAX_REORDER (FZC_TXC + 0x20018UL)
+#define TXC_MAX_REORDER_PORT3 0x000000000f000000ULL
+#define TXC_MAX_REORDER_PORT2 0x00000000000f0000ULL
+#define TXC_MAX_REORDER_PORT1 0x0000000000000f00ULL
+#define TXC_MAX_REORDER_PORT0 0x000000000000000fULL
+
+#define TXC_PORT_CTL(PORT) (FZC_TXC + 0x20020UL + (PORT)*0x100UL)
+#define TXC_PORT_CTL_CLR_ALL_STAT 0x0000000000000001ULL
+
+#define TXC_PKT_STUFFED(PORT) (FZC_TXC + 0x20030UL + (PORT)*0x100UL)
+#define TXC_PKT_STUFFED_PP_REORDER 0x00000000ffff0000ULL
+#define TXC_PKT_STUFFED_PP_PACKETASSY 0x000000000000ffffULL
+
+#define TXC_PKT_XMIT(PORT) (FZC_TXC + 0x20038UL + (PORT)*0x100UL)
+#define TXC_PKT_XMIT_BYTES 0x00000000ffff0000ULL
+#define TXC_PKT_XMIT_PKTS 0x000000000000ffffULL
+
+#define TXC_ROECC_CTL(PORT) (FZC_TXC + 0x20040UL + (PORT)*0x100UL)
+#define TXC_ROECC_CTL_DISABLE_UE 0x0000000080000000ULL
+#define TXC_ROECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL
+#define TXC_ROECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL
+#define TXC_ROECC_CTL_ALL_PKTS 0x0000000000000400ULL
+#define TXC_ROECC_CTL_ALT_PKTS 0x0000000000000200ULL
+#define TXC_ROECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL
+#define TXC_ROECC_CTL_LST_PKT_LINE 0x0000000000000004ULL
+#define TXC_ROECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL
+#define TXC_ROECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL
+
+#define TXC_ROECC_ST(PORT) (FZC_TXC + 0x20048UL + (PORT)*0x100UL)
+#define TXC_ROECC_CLR_ST 0x0000000080000000ULL
+#define TXC_ROECC_CE 0x0000000000020000ULL
+#define TXC_ROECC_UE 0x0000000000010000ULL
+#define TXC_ROECC_ST_ECC_ADDR 0x00000000000003ffULL
+
+#define TXC_RO_DATA0(PORT) (FZC_TXC + 0x20050UL + (PORT)*0x100UL)
+#define TXC_RO_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */
+
+#define TXC_RO_DATA1(PORT) (FZC_TXC + 0x20058UL + (PORT)*0x100UL)
+#define TXC_RO_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */
+
+#define TXC_RO_DATA2(PORT) (FZC_TXC + 0x20060UL + (PORT)*0x100UL)
+#define TXC_RO_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */
+
+#define TXC_RO_DATA3(PORT) (FZC_TXC + 0x20068UL + (PORT)*0x100UL)
+#define TXC_RO_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */
+
+#define TXC_RO_DATA4(PORT) (FZC_TXC + 0x20070UL + (PORT)*0x100UL)
+#define TXC_RO_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */
+
+#define TXC_SFECC_CTL(PORT) (FZC_TXC + 0x20078UL + (PORT)*0x100UL)
+#define TXC_SFECC_CTL_DISABLE_UE 0x0000000080000000ULL
+#define TXC_SFECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL
+#define TXC_SFECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL
+#define TXC_SFECC_CTL_ALL_PKTS 0x0000000000000400ULL
+#define TXC_SFECC_CTL_ALT_PKTS 0x0000000000000200ULL
+#define TXC_SFECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL
+#define TXC_SFECC_CTL_LST_PKT_LINE 0x0000000000000004ULL
+#define TXC_SFECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL
+#define TXC_SFECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL
+
+#define TXC_SFECC_ST(PORT) (FZC_TXC + 0x20080UL + (PORT)*0x100UL)
+#define TXC_SFECC_ST_CLR_ST 0x0000000080000000ULL
+#define TXC_SFECC_ST_CE 0x0000000000020000ULL
+#define TXC_SFECC_ST_UE 0x0000000000010000ULL
+#define TXC_SFECC_ST_ECC_ADDR 0x00000000000003ffULL
+
+#define TXC_SF_DATA0(PORT) (FZC_TXC + 0x20088UL + (PORT)*0x100UL)
+#define TXC_SF_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */
+
+#define TXC_SF_DATA1(PORT) (FZC_TXC + 0x20090UL + (PORT)*0x100UL)
+#define TXC_SF_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */
+
+#define TXC_SF_DATA2(PORT) (FZC_TXC + 0x20098UL + (PORT)*0x100UL)
+#define TXC_SF_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */
+
+#define TXC_SF_DATA3(PORT) (FZC_TXC + 0x200a0UL + (PORT)*0x100UL)
+#define TXC_SF_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */
+
+#define TXC_SF_DATA4(PORT) (FZC_TXC + 0x200a8UL + (PORT)*0x100UL)
+#define TXC_SF_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */
+
+#define TXC_RO_TIDS(PORT) (FZC_TXC + 0x200b0UL + (PORT)*0x100UL)
+#define TXC_RO_TIDS_IN_USE 0x00000000ffffffffULL
+
+#define TXC_RO_STATE0(PORT) (FZC_TXC + 0x200b8UL + (PORT)*0x100UL)
+#define TXC_RO_STATE0_DUPLICATE_TID 0x00000000ffffffffULL
+
+#define TXC_RO_STATE1(PORT) (FZC_TXC + 0x200c0UL + (PORT)*0x100UL)
+#define TXC_RO_STATE1_UNUSED_TID 0x00000000ffffffffULL
+
+#define TXC_RO_STATE2(PORT) (FZC_TXC + 0x200c8UL + (PORT)*0x100UL)
+#define TXC_RO_STATE2_TRANS_TIMEOUT 0x00000000ffffffffULL
+
+#define TXC_RO_STATE3(PORT) (FZC_TXC + 0x200d0UL + (PORT)*0x100UL)
+#define TXC_RO_STATE3_ENAB_SPC_WMARK 0x0000000080000000ULL
+#define TXC_RO_STATE3_RO_SPC_WMARK 0x000000007fe00000ULL
+#define TXC_RO_STATE3_ROFIFO_SPC_AVAIL 0x00000000001ff800ULL
+#define TXC_RO_STATE3_ENAB_RO_WMARK 0x0000000000000100ULL
+#define TXC_RO_STATE3_HIGH_RO_USED 0x00000000000000f0ULL
+#define TXC_RO_STATE3_NUM_RO_USED 0x000000000000000fULL
+
+#define TXC_RO_CTL(PORT) (FZC_TXC + 0x200d8UL + (PORT)*0x100UL)
+#define TXC_RO_CTL_CLR_FAIL_STATE 0x0000000080000000ULL
+#define TXC_RO_CTL_RO_ADDR 0x000000000f000000ULL
+#define TXC_RO_CTL_ADDR_FAILED 0x0000000000400000ULL
+#define TXC_RO_CTL_DMA_FAILED 0x0000000000200000ULL
+#define TXC_RO_CTL_LEN_FAILED 0x0000000000100000ULL
+#define TXC_RO_CTL_CAPT_ADDR_FAILED 0x0000000000040000ULL
+#define TXC_RO_CTL_CAPT_DMA_FAILED 0x0000000000020000ULL
+#define TXC_RO_CTL_CAPT_LEN_FAILED 0x0000000000010000ULL
+#define TXC_RO_CTL_RO_STATE_RD_DONE 0x0000000000000080ULL
+#define TXC_RO_CTL_RO_STATE_WR_DONE 0x0000000000000040ULL
+#define TXC_RO_CTL_RO_STATE_RD 0x0000000000000020ULL
+#define TXC_RO_CTL_RO_STATE_WR 0x0000000000000010ULL
+#define TXC_RO_CTL_RO_STATE_ADDR 0x000000000000000fULL
+
+#define TXC_RO_ST_DATA0(PORT) (FZC_TXC + 0x200e0UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA0_DATA0 0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA1(PORT) (FZC_TXC + 0x200e8UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA1_DATA1 0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA2(PORT) (FZC_TXC + 0x200f0UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA2_DATA2 0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA3(PORT) (FZC_TXC + 0x200f8UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA3_DATA3 0x00000000ffffffffULL
+
+#define TXC_PORT_PACKET_REQ(PORT) (FZC_TXC + 0x20100UL + (PORT)*0x100UL)
+#define TXC_PORT_PACKET_REQ_GATHER_REQ 0x00000000f0000000ULL
+#define TXC_PORT_PACKET_REQ_PKT_REQ 0x000000000fff0000ULL
+#define TXC_PORT_PACKET_REQ_PERR_ABRT 0x000000000000ffffULL
+
+ /* bits are same as TXC_INT_STAT */
+#define TXC_INT_STAT_DBG (FZC_TXC + 0x20420UL)
+
+#define TXC_INT_STAT (FZC_TXC + 0x20428UL)
+#define TXC_INT_STAT_VAL_SHIFT(PORT) ((PORT) * 8)
+#define TXC_INT_STAT_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_SF_CE(PORT) (0x01 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_SF_UE(PORT) (0x02 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_RO_CE(PORT) (0x04 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_RO_UE(PORT) (0x08 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_REORDER_ERR(PORT) (0x10 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_PKTASM_DEAD(PORT) (0x20 << TXC_INT_STAT_VAL_SHIFT(PORT))
+
+#define TXC_INT_MASK (FZC_TXC + 0x20430UL)
+#define TXC_INT_MASK_VAL_SHIFT(PORT) ((PORT) * 8)
+#define TXC_INT_MASK_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT))
+
+#define TXC_INT_MASK_SF_CE 0x01
+#define TXC_INT_MASK_SF_UE 0x02
+#define TXC_INT_MASK_RO_CE 0x04
+#define TXC_INT_MASK_RO_UE 0x08
+#define TXC_INT_MASK_REORDER_ERR 0x10
+#define TXC_INT_MASK_PKTASM_DEAD 0x20
+#define TXC_INT_MASK_ALL 0x3f
+
+#define TXC_PORT_DMA(IDX) (FZC_TXC + 0x20028UL + (IDX)*0x100UL)
+
+#define ESPC_PIO_EN (FZC_PROM + 0x40000UL)
+#define ESPC_PIO_EN_ENABLE 0x0000000000000001ULL
+
+#define ESPC_PIO_STAT (FZC_PROM + 0x40008UL)
+#define ESPC_PIO_STAT_READ_START 0x0000000080000000ULL
+#define ESPC_PIO_STAT_READ_END 0x0000000040000000ULL
+#define ESPC_PIO_STAT_WRITE_INIT 0x0000000020000000ULL
+#define ESPC_PIO_STAT_WRITE_END 0x0000000010000000ULL
+#define ESPC_PIO_STAT_ADDR 0x0000000003ffff00ULL
+#define ESPC_PIO_STAT_ADDR_SHIFT 8
+#define ESPC_PIO_STAT_DATA 0x00000000000000ffULL
+#define ESPC_PIO_STAT_DATA_SHIFT 0
+
+#define ESPC_NCR(IDX) (FZC_PROM + 0x40020UL + (IDX)*0x8UL)
+#define ESPC_NCR_VAL 0x00000000ffffffffULL
+
+#define ESPC_MAC_ADDR0 ESPC_NCR(0)
+#define ESPC_MAC_ADDR1 ESPC_NCR(1)
+#define ESPC_NUM_PORTS_MACS ESPC_NCR(2)
+#define ESPC_NUM_PORTS_MACS_VAL 0x00000000000000ffULL
+#define ESPC_MOD_STR_LEN ESPC_NCR(4)
+#define ESPC_MOD_STR_1 ESPC_NCR(5)
+#define ESPC_MOD_STR_2 ESPC_NCR(6)
+#define ESPC_MOD_STR_3 ESPC_NCR(7)
+#define ESPC_MOD_STR_4 ESPC_NCR(8)
+#define ESPC_MOD_STR_5 ESPC_NCR(9)
+#define ESPC_MOD_STR_6 ESPC_NCR(10)
+#define ESPC_MOD_STR_7 ESPC_NCR(11)
+#define ESPC_MOD_STR_8 ESPC_NCR(12)
+#define ESPC_BD_MOD_STR_LEN ESPC_NCR(13)
+#define ESPC_BD_MOD_STR_1 ESPC_NCR(14)
+#define ESPC_BD_MOD_STR_2 ESPC_NCR(15)
+#define ESPC_BD_MOD_STR_3 ESPC_NCR(16)
+#define ESPC_BD_MOD_STR_4 ESPC_NCR(17)
+
+#define ESPC_PHY_TYPE ESPC_NCR(18)
+#define ESPC_PHY_TYPE_PORT0 0x00000000ff000000ULL
+#define ESPC_PHY_TYPE_PORT0_SHIFT 24
+#define ESPC_PHY_TYPE_PORT1 0x0000000000ff0000ULL
+#define ESPC_PHY_TYPE_PORT1_SHIFT 16
+#define ESPC_PHY_TYPE_PORT2 0x000000000000ff00ULL
+#define ESPC_PHY_TYPE_PORT2_SHIFT 8
+#define ESPC_PHY_TYPE_PORT3 0x00000000000000ffULL
+#define ESPC_PHY_TYPE_PORT3_SHIFT 0
+
+#define ESPC_PHY_TYPE_1G_COPPER 3
+#define ESPC_PHY_TYPE_1G_FIBER 2
+#define ESPC_PHY_TYPE_10G_COPPER 1
+#define ESPC_PHY_TYPE_10G_FIBER 0
+
+#define ESPC_MAX_FM_SZ ESPC_NCR(19)
+
+#define ESPC_INTR_NUM ESPC_NCR(20)
+#define ESPC_INTR_NUM_PORT0 0x00000000ff000000ULL
+#define ESPC_INTR_NUM_PORT1 0x0000000000ff0000ULL
+#define ESPC_INTR_NUM_PORT2 0x000000000000ff00ULL
+#define ESPC_INTR_NUM_PORT3 0x00000000000000ffULL
+
+#define ESPC_VER_IMGSZ ESPC_NCR(21)
+#define ESPC_VER_IMGSZ_IMGSZ 0x00000000ffff0000ULL
+#define ESPC_VER_IMGSZ_IMGSZ_SHIFT 16
+#define ESPC_VER_IMGSZ_VER 0x000000000000ffffULL
+#define ESPC_VER_IMGSZ_VER_SHIFT 0
+
+#define ESPC_CHKSUM ESPC_NCR(22)
+#define ESPC_CHKSUM_SUM 0x00000000000000ffULL
+
+#define ESPC_EEPROM_SIZE 0x100000
+
+#define CLASS_CODE_UNRECOG 0x00
+#define CLASS_CODE_DUMMY1 0x01
+#define CLASS_CODE_ETHERTYPE1 0x02
+#define CLASS_CODE_ETHERTYPE2 0x03
+#define CLASS_CODE_USER_PROG1 0x04
+#define CLASS_CODE_USER_PROG2 0x05
+#define CLASS_CODE_USER_PROG3 0x06
+#define CLASS_CODE_USER_PROG4 0x07
+#define CLASS_CODE_TCP_IPV4 0x08
+#define CLASS_CODE_UDP_IPV4 0x09
+#define CLASS_CODE_AH_ESP_IPV4 0x0a
+#define CLASS_CODE_SCTP_IPV4 0x0b
+#define CLASS_CODE_TCP_IPV6 0x0c
+#define CLASS_CODE_UDP_IPV6 0x0d
+#define CLASS_CODE_AH_ESP_IPV6 0x0e
+#define CLASS_CODE_SCTP_IPV6 0x0f
+#define CLASS_CODE_ARP 0x10
+#define CLASS_CODE_RARP 0x11
+#define CLASS_CODE_DUMMY2 0x12
+#define CLASS_CODE_DUMMY3 0x13
+#define CLASS_CODE_DUMMY4 0x14
+#define CLASS_CODE_DUMMY5 0x15
+#define CLASS_CODE_DUMMY6 0x16
+#define CLASS_CODE_DUMMY7 0x17
+#define CLASS_CODE_DUMMY8 0x18
+#define CLASS_CODE_DUMMY9 0x19
+#define CLASS_CODE_DUMMY10 0x1a
+#define CLASS_CODE_DUMMY11 0x1b
+#define CLASS_CODE_DUMMY12 0x1c
+#define CLASS_CODE_DUMMY13 0x1d
+#define CLASS_CODE_DUMMY14 0x1e
+#define CLASS_CODE_DUMMY15 0x1f
+
+/* Logical devices and device groups */
+#define LDN_RXDMA(CHAN) (0 + (CHAN))
+#define LDN_RESV1(OFF) (16 + (OFF))
+#define LDN_TXDMA(CHAN) (32 + (CHAN))
+#define LDN_RESV2(OFF) (56 + (OFF))
+#define LDN_MIF 63
+#define LDN_MAC(PORT) (64 + (PORT))
+#define LDN_DEVICE_ERROR 68
+#define LDN_MAX LDN_DEVICE_ERROR
+
+#define NIU_LDG_MIN 0
+#define NIU_LDG_MAX 63
+#define NIU_NUM_LDG 64
+#define LDG_INVALID 0xff
+
+/* PHY stuff */
+#define NIU_PMA_PMD_DEV_ADDR 1
+#define NIU_PCS_DEV_ADDR 3
+
+#define NIU_PHY_ID_MASK 0xfffff0f0
+#define NIU_PHY_ID_BCM8704 0x00206030
+#define NIU_PHY_ID_BCM5464R 0x002060b0
+
+#define BCM8704_PMA_PMD_DEV_ADDR 1
+#define BCM8704_PCS_DEV_ADDR 2
+#define BCM8704_USER_DEV3_ADDR 3
+#define BCM8704_PHYXS_DEV_ADDR 4
+#define BCM8704_USER_DEV4_ADDR 4
+
+#define BCM8704_PMD_RCV_SIGDET 0x000a
+#define PMD_RCV_SIGDET_LANE3 0x0010
+#define PMD_RCV_SIGDET_LANE2 0x0008
+#define PMD_RCV_SIGDET_LANE1 0x0004
+#define PMD_RCV_SIGDET_LANE0 0x0002
+#define PMD_RCV_SIGDET_GLOBAL 0x0001
+
+#define BCM8704_PCS_10G_R_STATUS 0x0020
+#define PCS_10G_R_STATUS_LINKSTAT 0x1000
+#define PCS_10G_R_STATUS_PRBS31_ABLE 0x0004
+#define PCS_10G_R_STATUS_HI_BER 0x0002
+#define PCS_10G_R_STATUS_BLK_LOCK 0x0001
+
+#define BCM8704_USER_CONTROL 0xc800
+#define USER_CONTROL_OPTXENB_LVL 0x8000
+#define USER_CONTROL_OPTXRST_LVL 0x4000
+#define USER_CONTROL_OPBIASFLT_LVL 0x2000
+#define USER_CONTROL_OBTMPFLT_LVL 0x1000
+#define USER_CONTROL_OPPRFLT_LVL 0x0800
+#define USER_CONTROL_OPTXFLT_LVL 0x0400
+#define USER_CONTROL_OPRXLOS_LVL 0x0200
+#define USER_CONTROL_OPRXFLT_LVL 0x0100
+#define USER_CONTROL_OPTXON_LVL 0x0080
+#define USER_CONTROL_RES1 0x007f
+#define USER_CONTROL_RES1_SHIFT 0
+
+#define BCM8704_USER_ANALOG_CLK 0xc801
+#define BCM8704_USER_PMD_RX_CONTROL 0xc802
+
+#define BCM8704_USER_PMD_TX_CONTROL 0xc803
+#define USER_PMD_TX_CTL_RES1 0xfe00
+#define USER_PMD_TX_CTL_XFP_CLKEN 0x0100
+#define USER_PMD_TX_CTL_TX_DAC_TXD 0x00c0
+#define USER_PMD_TX_CTL_TX_DAC_TXD_SH 6
+#define USER_PMD_TX_CTL_TX_DAC_TXCK 0x0030
+#define USER_PMD_TX_CTL_TX_DAC_TXCK_SH 4
+#define USER_PMD_TX_CTL_TSD_LPWREN 0x0008
+#define USER_PMD_TX_CTL_TSCK_LPWREN 0x0004
+#define USER_PMD_TX_CTL_CMU_LPWREN 0x0002
+#define USER_PMD_TX_CTL_SFIFORST 0x0001
+
+#define BCM8704_USER_ANALOG_STATUS0 0xc804
+#define BCM8704_USER_OPT_DIGITAL_CTRL 0xc808
+#define BCM8704_USER_TX_ALARM_STATUS 0x9004
+
+#define USER_ODIG_CTRL_FMODE 0x8000
+#define USER_ODIG_CTRL_TX_PDOWN 0x4000
+#define USER_ODIG_CTRL_RX_PDOWN 0x2000
+#define USER_ODIG_CTRL_EFILT_EN 0x1000
+#define USER_ODIG_CTRL_OPT_RST 0x0800
+#define USER_ODIG_CTRL_PCS_TIB 0x0400
+#define USER_ODIG_CTRL_PCS_RI 0x0200
+#define USER_ODIG_CTRL_RESV1 0x0180
+#define USER_ODIG_CTRL_GPIOS 0x0060
+#define USER_ODIG_CTRL_GPIOS_SHIFT 5
+#define USER_ODIG_CTRL_RESV2 0x0010
+#define USER_ODIG_CTRL_LB_ERR_DIS 0x0008
+#define USER_ODIG_CTRL_RESV3 0x0006
+#define USER_ODIG_CTRL_TXONOFF_PD_DIS 0x0001
+
+#define BCM8704_PHYXS_XGXS_LANE_STAT 0x0018
+#define PHYXS_XGXS_LANE_STAT_ALINGED 0x1000
+#define PHYXS_XGXS_LANE_STAT_PATTEST 0x0800
+#define PHYXS_XGXS_LANE_STAT_MAGIC 0x0400
+#define PHYXS_XGXS_LANE_STAT_LANE3 0x0008
+#define PHYXS_XGXS_LANE_STAT_LANE2 0x0004
+#define PHYXS_XGXS_LANE_STAT_LANE1 0x0002
+#define PHYXS_XGXS_LANE_STAT_LANE0 0x0001
+
+#define BCM5464R_AUX_CTL 24
+#define BCM5464R_AUX_CTL_EXT_LB 0x8000
+#define BCM5464R_AUX_CTL_EXT_PLEN 0x4000
+#define BCM5464R_AUX_CTL_ER1000 0x3000
+#define BCM5464R_AUX_CTL_ER1000_SHIFT 12
+#define BCM5464R_AUX_CTL_RESV1 0x0800
+#define BCM5464R_AUX_CTL_WRITE_1 0x0400
+#define BCM5464R_AUX_CTL_RESV2 0x0300
+#define BCM5464R_AUX_CTL_PRESP_DIS 0x0080
+#define BCM5464R_AUX_CTL_RESV3 0x0040
+#define BCM5464R_AUX_CTL_ER100 0x0030
+#define BCM5464R_AUX_CTL_ER100_SHIFT 4
+#define BCM5464R_AUX_CTL_DIAG_MODE 0x0008
+#define BCM5464R_AUX_CTL_SR_SEL 0x0007
+#define BCM5464R_AUX_CTL_SR_SEL_SHIFT 0
+
+#define BCM5464R_CTRL1000_AS_MASTER 0x0800
+#define BCM5464R_CTRL1000_ENABLE_AS_MASTER 0x1000
+
+#define RCR_ENTRY_MULTI 0x8000000000000000ULL
+#define RCR_ENTRY_PKT_TYPE 0x6000000000000000ULL
+#define RCR_ENTRY_PKT_TYPE_SHIFT 61
+#define RCR_ENTRY_ZERO_COPY 0x1000000000000000ULL
+#define RCR_ENTRY_NOPORT 0x0800000000000000ULL
+#define RCR_ENTRY_PROMISC 0x0400000000000000ULL
+#define RCR_ENTRY_ERROR 0x0380000000000000ULL
+#define RCR_ENTRY_DCF_ERR 0x0040000000000000ULL
+#define RCR_ENTRY_L2_LEN 0x003fff0000000000ULL
+#define RCR_ENTRY_L2_LEN_SHIFT 40
+#define RCR_ENTRY_PKTBUFSZ 0x000000c000000000ULL
+#define RCR_ENTRY_PKTBUFSZ_SHIFT 38
+#define RCR_ENTRY_PKT_BUF_ADDR 0x0000003fffffffffULL /* bits 43:6 */
+#define RCR_ENTRY_PKT_BUF_ADDR_SHIFT 6
+
+#define RCR_PKT_TYPE_OTHER 0x0
+#define RCR_PKT_TYPE_TCP 0x1
+#define RCR_PKT_TYPE_UDP 0x2
+#define RCR_PKT_TYPE_SCTP 0x3
+
+#define NIU_RXPULL_MAX ETH_HLEN
+
+struct rx_pkt_hdr0 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 inputport:2,
+ maccheck:1,
+ class:4;
+ u8 vlan:1,
+ llcsnap:1,
+ noport:1,
+ badip:1,
+ tcamhit:1,
+ tres:2,
+ tzfvld:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 class:4,
+ maccheck:1,
+ inputport:2;
+ u8 tzfvld:1,
+ tres:2,
+ tcamhit:1,
+ badip:1,
+ noport:1,
+ llcsnap:1,
+ vlan:1;
+#endif
+};
+
+struct rx_pkt_hdr1 {
+ u8 hwrsvd1;
+ u8 tcammatch;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 hwrsvd2:2,
+ hashit:1,
+ exact:1,
+ hzfvld:1,
+ hashsidx:3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 hashsidx:3,
+ hzfvld:1,
+ exact:1,
+ hashit:1,
+ hwrsvd2:2;
+#endif
+ u8 zcrsvd;
+
+ /* Bits 11:8 of zero copy flow ID. */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 hwrsvd3:4, zflowid0:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 zflowid0:4, hwrsvd3:4;
+#endif
+
+ /* Bits 7:0 of zero copy flow ID. */
+ u8 zflowid1;
+
+ /* Bits 15:8 of hash value, H2. */
+ u8 hashval2_0;
+
+ /* Bits 7:0 of hash value, H2. */
+ u8 hashval2_1;
+
+ /* Bits 19:16 of hash value, H1. */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 hwrsvd4:4, hashval1_0:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 hashval1_0:4, hwrsvd4:4;
+#endif
+
+ /* Bits 15:8 of hash value, H1. */
+ u8 hashval1_1;
+
+ /* Bits 7:0 of hash value, H1. */
+ u8 hashval1_2;
+
+ u8 usrdata_0; /* Bits 39:32 of user data. */
+ u8 usrdata_1; /* Bits 31:24 of user data. */
+ u8 usrdata_2; /* Bits 23:16 of user data. */
+ u8 usrdata_3; /* Bits 15:8 of user data. */
+ u8 usrdata_4; /* Bits 7:0 of user data. */
+};
+
+struct tx_dma_mbox {
+ u64 tx_dma_pre_st;
+ u64 tx_cs;
+ u64 tx_ring_kick;
+ u64 tx_ring_hdl;
+ u64 resv1;
+ u32 tx_rng_err_logl;
+ u32 tx_rng_err_logh;
+ u64 resv2;
+ u64 resv3;
+};
+
+struct tx_pkt_hdr {
+ __le64 flags;
+#define TXHDR_PAD 0x0000000000000007ULL
+#define TXHDR_PAD_SHIFT 0
+#define TXHDR_LEN 0x000000003fff0000ULL
+#define TXHDR_LEN_SHIFT 16
+#define TXHDR_L4STUFF 0x0000003f00000000ULL
+#define TXHDR_L4STUFF_SHIFT 32
+#define TXHDR_L4START 0x00003f0000000000ULL
+#define TXHDR_L4START_SHIFT 40
+#define TXHDR_L3START 0x000f000000000000ULL
+#define TXHDR_L3START_SHIFT 48
+#define TXHDR_IHL 0x00f0000000000000ULL
+#define TXHDR_IHL_SHIFT 52
+#define TXHDR_VLAN 0x0100000000000000ULL
+#define TXHDR_LLC 0x0200000000000000ULL
+#define TXHDR_IP_VER 0x2000000000000000ULL
+#define TXHDR_CSUM_NONE 0x0000000000000000ULL
+#define TXHDR_CSUM_TCP 0x4000000000000000ULL
+#define TXHDR_CSUM_UDP 0x8000000000000000ULL
+#define TXHDR_CSUM_SCTP 0xc000000000000000ULL
+ __le64 resv;
+};
+
+#define TX_DESC_SOP 0x8000000000000000ULL
+#define TX_DESC_MARK 0x4000000000000000ULL
+#define TX_DESC_NUM_PTR 0x3c00000000000000ULL
+#define TX_DESC_NUM_PTR_SHIFT 58
+#define TX_DESC_TR_LEN 0x01fff00000000000ULL
+#define TX_DESC_TR_LEN_SHIFT 44
+#define TX_DESC_SAD 0x00000fffffffffffULL
+#define TX_DESC_SAD_SHIFT 0
+
+struct tx_buff_info {
+ struct sk_buff *skb;
+ u64 mapping;
+};
+
+struct txdma_mailbox {
+ __le64 tx_dma_pre_st;
+ __le64 tx_cs;
+ __le64 tx_ring_kick;
+ __le64 tx_ring_hdl;
+ __le64 resv1;
+ __le32 tx_rng_err_logl;
+ __le32 tx_rng_err_logh;
+ __le64 resv2[2];
+} __attribute__((aligned(64)));
+
+#define MAX_TX_RING_SIZE 256
+#define MAX_TX_DESC_LEN 4076
+
+struct tx_ring_info {
+ struct tx_buff_info tx_buffs[MAX_TX_RING_SIZE];
+ struct niu *np;
+ u64 tx_cs;
+ int pending;
+ int prod;
+ int cons;
+ int wrap_bit;
+ u16 last_pkt_cnt;
+ u16 tx_channel;
+ u16 mark_counter;
+ u16 mark_freq;
+ u16 mark_pending;
+ u16 __pad;
+ struct txdma_mailbox *mbox;
+ __le64 *descr;
+
+ u64 tx_packets;
+ u64 tx_bytes;
+ u64 tx_errors;
+
+ u64 mbox_dma;
+ u64 descr_dma;
+ int max_burst;
+};
+
+#define NEXT_TX(tp, index) \
+ (((index) + 1) < (tp)->pending ? ((index) + 1) : 0)
+
+static inline u32 niu_tx_avail(struct tx_ring_info *tp)
+{
+ return (tp->pending -
+ ((tp->prod - tp->cons) & (MAX_TX_RING_SIZE - 1)));
+}
+
+struct rxdma_mailbox {
+ __le64 rx_dma_ctl_stat;
+ __le64 rbr_stat;
+ __le32 rbr_hdl;
+ __le32 rbr_hdh;
+ __le64 resv1;
+ __le32 rcrstat_c;
+ __le32 rcrstat_b;
+ __le64 rcrstat_a;
+ __le64 resv2[2];
+} __attribute__((aligned(64)));
+
+#define MAX_RBR_RING_SIZE 128
+#define MAX_RCR_RING_SIZE (MAX_RBR_RING_SIZE * 2)
+
+#define RBR_REFILL_MIN 16
+
+#define RX_SKB_ALLOC_SIZE 128 + NET_IP_ALIGN
+
+struct rx_ring_info {
+ struct niu *np;
+ int rx_channel;
+ u16 rbr_block_size;
+ u16 rbr_blocks_per_page;
+ u16 rbr_sizes[4];
+ unsigned int rcr_index;
+ unsigned int rcr_table_size;
+ unsigned int rbr_index;
+ unsigned int rbr_pending;
+ unsigned int rbr_refill_pending;
+ unsigned int rbr_kick_thresh;
+ unsigned int rbr_table_size;
+ struct page **rxhash;
+ struct rxdma_mailbox *mbox;
+ __le64 *rcr;
+ __le32 *rbr;
+#define RBR_DESCR_ADDR_SHIFT 12
+
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_dropped;
+ u64 rx_errors;
+
+ u64 mbox_dma;
+ u64 rcr_dma;
+ u64 rbr_dma;
+
+ /* WRED */
+ int nonsyn_window;
+ int nonsyn_threshold;
+ int syn_window;
+ int syn_threshold;
+
+ /* interrupt mitigation */
+ int rcr_pkt_threshold;
+ int rcr_timeout;
+};
+
+#define NEXT_RCR(rp, index) \
+ (((index) + 1) < (rp)->rcr_table_size ? ((index) + 1) : 0)
+#define NEXT_RBR(rp, index) \
+ (((index) + 1) < (rp)->rbr_table_size ? ((index) + 1) : 0)
+
+#define NIU_MAX_PORTS 4
+#define NIU_NUM_RXCHAN 16
+#define NIU_NUM_TXCHAN 24
+#define MAC_NUM_HASH 16
+
+#define NIU_MAX_MTU 9216
+
+#define NIU_VPD_MIN_MAJOR 3
+#define NIU_VPD_MIN_MINOR 4
+
+#define NIU_VPD_MODEL_MAX 32
+#define NIU_VPD_BD_MODEL_MAX 16
+#define NIU_VPD_VERSION_MAX 64
+#define NIU_VPD_PHY_TYPE_MAX 8
+
+struct niu_vpd {
+ char model[NIU_VPD_MODEL_MAX];
+ char board_model[NIU_VPD_BD_MODEL_MAX];
+ char version[NIU_VPD_VERSION_MAX];
+ char phy_type[NIU_VPD_PHY_TYPE_MAX];
+ u8 mac_num;
+ u8 __pad;
+ u8 local_mac[6];
+ int fcode_major;
+ int fcode_minor;
+};
+
+struct niu_altmac_rdc {
+ u8 alt_mac_num;
+ u8 rdc_num;
+ u8 mac_pref;
+};
+
+struct niu_vlan_rdc {
+ u8 rdc_num;
+ u8 vlan_pref;
+};
+
+struct niu_classifier {
+ struct niu_altmac_rdc alt_mac_mappings[16];
+ struct niu_vlan_rdc vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES];
+
+ u16 tcam_index;
+ u16 num_alt_mac_mappings;
+
+ u32 h1_init;
+ u16 h2_init;
+};
+
+#define NIU_NUM_RDC_TABLES 8
+#define NIU_RDC_TABLE_SLOTS 16
+
+struct rdc_table {
+ u8 rxdma_channel[NIU_RDC_TABLE_SLOTS];
+};
+
+struct niu_rdc_tables {
+ struct rdc_table tables[NIU_NUM_RDC_TABLES];
+ int first_table_num;
+ int num_tables;
+};
+
+#define PHY_TYPE_PMA_PMD 0
+#define PHY_TYPE_PCS 1
+#define PHY_TYPE_MII 2
+#define PHY_TYPE_MAX 3
+
+struct phy_probe_info {
+ u32 phy_id[PHY_TYPE_MAX][NIU_MAX_PORTS];
+ u8 phy_port[PHY_TYPE_MAX][NIU_MAX_PORTS];
+ u8 cur[PHY_TYPE_MAX];
+
+ struct device_attribute phy_port_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+ struct device_attribute phy_type_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+ struct device_attribute phy_id_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+};
+
+struct niu_tcam_entry {
+ u64 key[4];
+ u64 key_mask[4];
+ u64 assoc_data;
+};
+
+struct device_node;
+union niu_parent_id {
+ struct {
+ int domain;
+ int bus;
+ int device;
+ } pci;
+ struct device_node *of;
+};
+
+struct niu;
+struct niu_parent {
+ struct platform_device *plat_dev;
+ int index;
+
+ union niu_parent_id id;
+
+ struct niu *ports[NIU_MAX_PORTS];
+
+ atomic_t refcnt;
+ struct list_head list;
+
+ spinlock_t lock;
+
+ u32 flags;
+#define PARENT_FLGS_CLS_HWINIT 0x00000001
+
+ u32 port_phy;
+#define PORT_PHY_UNKNOWN 0x00000000
+#define PORT_PHY_INVALID 0xffffffff
+#define PORT_TYPE_10G 0x01
+#define PORT_TYPE_1G 0x02
+#define PORT_TYPE_MASK 0x03
+
+ u8 rxchan_per_port[NIU_MAX_PORTS];
+ u8 txchan_per_port[NIU_MAX_PORTS];
+
+ struct niu_rdc_tables rdc_group_cfg[NIU_MAX_PORTS];
+ u8 rdc_default[NIU_MAX_PORTS];
+
+ u8 ldg_map[LDN_MAX + 1];
+
+ u8 plat_type;
+#define PLAT_TYPE_INVALID 0x00
+#define PLAT_TYPE_ATLAS 0x01
+#define PLAT_TYPE_NIU 0x02
+#define PLAT_TYPE_VF_P0 0x03
+#define PLAT_TYPE_VF_P1 0x04
+
+ u8 num_ports;
+
+ u16 tcam_num_entries;
+#define NIU_PCI_TCAM_ENTRIES 256
+#define NIU_NONPCI_TCAM_ENTRIES 128
+#define NIU_TCAM_ENTRIES_MAX 256
+
+ int rxdma_clock_divider;
+
+ struct phy_probe_info phy_probe_info;
+
+ struct niu_tcam_entry tcam[NIU_TCAM_ENTRIES_MAX];
+ u64 l2_cls[2];
+ u64 l3_cls[4];
+ u64 tcam_key[12];
+ u64 flow_key[12];
+};
+
+struct niu_ops {
+ void *(*alloc_coherent)(struct device *dev, size_t size,
+ u64 *handle, gfp_t flag);
+ void (*free_coherent)(struct device *dev, size_t size,
+ void *cpu_addr, u64 handle);
+ u64 (*map_page)(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+ void (*unmap_page)(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction);
+ u64 (*map_single)(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction);
+ void (*unmap_single)(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction);
+};
+
+struct niu_link_config {
+ /* Describes what we're trying to get. */
+ u32 advertising;
+ u32 supported;
+ u16 speed;
+ u8 duplex;
+ u8 autoneg;
+
+ /* Describes what we actually have. */
+ u16 active_speed;
+ u8 active_duplex;
+#define SPEED_INVALID 0xffff
+#define DUPLEX_INVALID 0xff
+#define AUTONEG_INVALID 0xff
+
+ u8 loopback_mode;
+#define LOOPBACK_DISABLED 0x00
+#define LOOPBACK_PHY 0x01
+#define LOOPBACK_MAC 0x02
+};
+
+struct niu_ldg {
+ struct napi_struct napi;
+ struct niu *np;
+ u8 ldg_num;
+ u8 timer;
+ u64 v0, v1, v2;
+ unsigned int irq;
+};
+
+struct niu_xmac_stats {
+ u64 tx_frames;
+ u64 tx_bytes;
+ u64 tx_fifo_errors;
+ u64 tx_overflow_errors;
+ u64 tx_max_pkt_size_errors;
+ u64 tx_underflow_errors;
+
+ u64 rx_local_faults;
+ u64 rx_remote_faults;
+ u64 rx_link_faults;
+ u64 rx_align_errors;
+ u64 rx_frags;
+ u64 rx_mcasts;
+ u64 rx_bcasts;
+ u64 rx_hist_cnt1;
+ u64 rx_hist_cnt2;
+ u64 rx_hist_cnt3;
+ u64 rx_hist_cnt4;
+ u64 rx_hist_cnt5;
+ u64 rx_hist_cnt6;
+ u64 rx_hist_cnt7;
+ u64 rx_octets;
+ u64 rx_code_violations;
+ u64 rx_len_errors;
+ u64 rx_crc_errors;
+ u64 rx_underflows;
+ u64 rx_overflows;
+
+ u64 pause_off_state;
+ u64 pause_on_state;
+ u64 pause_received;
+};
+
+struct niu_bmac_stats {
+ u64 tx_underflow_errors;
+ u64 tx_max_pkt_size_errors;
+ u64 tx_bytes;
+ u64 tx_frames;
+
+ u64 rx_overflows;
+ u64 rx_frames;
+ u64 rx_align_errors;
+ u64 rx_crc_errors;
+ u64 rx_len_errors;
+
+ u64 pause_off_state;
+ u64 pause_on_state;
+ u64 pause_received;
+};
+
+union niu_mac_stats {
+ struct niu_xmac_stats xmac;
+ struct niu_bmac_stats bmac;
+};
+
+struct niu_phy_ops {
+ int (*serdes_init)(struct niu *np);
+ int (*xcvr_init)(struct niu *np);
+ int (*link_status)(struct niu *np, int *);
+};
+
+struct of_device;
+struct niu {
+ void __iomem *regs;
+ struct net_device *dev;
+ struct pci_dev *pdev;
+ struct device *device;
+ struct niu_parent *parent;
+
+ u32 flags;
+#define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */
+#define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */
+#define NIU_FLAGS_PROMISC 0x00100000 /* PROMISC enabled */
+#define NIU_FLAGS_VPD_VALID 0x00080000 /* VPD has valid version */
+#define NIU_FLAGS_10G 0x00040000 /* 0=1G 1=10G */
+#define NIU_FLAGS_FIBER 0x00020000 /* 0=COPPER 1=FIBER */
+#define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */
+
+ u32 msg_enable;
+
+ /* Protects hw programming, and ring state. */
+ spinlock_t lock;
+
+ const struct niu_ops *ops;
+ struct net_device_stats net_stats;
+ union niu_mac_stats mac_stats;
+
+ struct rx_ring_info *rx_rings;
+ struct tx_ring_info *tx_rings;
+ int num_rx_rings;
+ int num_tx_rings;
+
+ struct niu_ldg ldg[NIU_NUM_LDG];
+ int num_ldg;
+
+ void __iomem *mac_regs;
+ unsigned long ipp_off;
+ unsigned long pcs_off;
+ unsigned long xpcs_off;
+
+ struct timer_list timer;
+ const struct niu_phy_ops *phy_ops;
+ int phy_addr;
+
+ struct niu_link_config link_config;
+
+ struct work_struct reset_task;
+
+ u8 port;
+ u8 mac_xcvr;
+#define MAC_XCVR_MII 1
+#define MAC_XCVR_PCS 2
+#define MAC_XCVR_XPCS 3
+
+ struct niu_classifier clas;
+
+ struct niu_vpd vpd;
+ u32 eeprom_len;
+
+ struct of_device *op;
+ void __iomem *vir_regs_1;
+ void __iomem *vir_regs_2;
+};
+
+#endif /* _NIU_H */
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 104aab3c957f..ea71f6d82661 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1,4 +1,4 @@
-#define VERSION "0.22"
+#define VERSION "0.23"
/* ns83820.c by Benjamin LaHaise with contributions.
*
* Questions/comments/discussion to linux-ns83820@kvack.org.
@@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
return &dev->stats;
}
+/* Let ethtool retrieve info */
+static int ns83820_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct ns83820 *dev = PRIV(ndev);
+ u32 cfg, tanar, tbicr;
+ int have_optical = 0;
+ int fullduplex = 0;
+
+ /*
+ * Here's the list of available ethtool commands from other drivers:
+ * cmd->advertising =
+ * cmd->speed =
+ * cmd->duplex =
+ * cmd->port = 0;
+ * cmd->phy_address =
+ * cmd->transceiver = 0;
+ * cmd->autoneg =
+ * cmd->maxtxpkt = 0;
+ * cmd->maxrxpkt = 0;
+ */
+
+ /* read current configuration */
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+ tanar = readl(dev->base + TANAR);
+ tbicr = readl(dev->base + TBICR);
+
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ /* we have an optical interface */
+ have_optical = 1;
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+
+ } else {
+ /* We have copper */
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+ }
+
+ cmd->supported = SUPPORTED_Autoneg;
+
+ /* we have optical interface */
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ cmd->supported |= SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ } /* TODO: else copper related support */
+
+ cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
+ switch (cfg / CFG_SPDSTS0 & 3) {
+ case 2:
+ cmd->speed = SPEED_1000;
+ break;
+ case 1:
+ cmd->speed = SPEED_100;
+ break;
+ default:
+ cmd->speed = SPEED_10;
+ break;
+ }
+ cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
+ return 0;
+}
+
+/* Let ethool change settings*/
+static int ns83820_set_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct ns83820 *dev = PRIV(ndev);
+ u32 cfg, tanar;
+ int have_optical = 0;
+ int fullduplex = 0;
+
+ /* read current configuration */
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+ tanar = readl(dev->base + TANAR);
+
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ /* we have optical */
+ have_optical = 1;
+ fullduplex = (tanar & TANAR_FULL_DUP);
+
+ } else {
+ /* we have copper */
+ fullduplex = cfg & CFG_DUPSTS;
+ }
+
+ spin_lock_irq(&dev->misc_lock);
+ spin_lock(&dev->tx_lock);
+
+ /* Set duplex */
+ if (cmd->duplex != fullduplex) {
+ if (have_optical) {
+ /*set full duplex*/
+ if (cmd->duplex == DUPLEX_FULL) {
+ /* force full duplex */
+ writel(readl(dev->base + TXCFG)
+ | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+ dev->base + TXCFG);
+ writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+ dev->base + RXCFG);
+ /* Light up full duplex LED */
+ writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
+ dev->base + GPIOR);
+ } else {
+ /*TODO: set half duplex */
+ }
+
+ } else {
+ /*we have copper*/
+ /* TODO: Set duplex for copper cards */
+ }
+ printk(KERN_INFO "%s: Duplex set via ethtool\n",
+ ndev->name);
+ }
+
+ /* Set autonegotiation */
+ if (1) {
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ /* restart auto negotiation */
+ writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+ dev->base + TBICR);
+ writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
+ dev->linkstate = LINK_AUTONEGOTIATE;
+
+ printk(KERN_INFO "%s: autoneg enabled via ethtool\n",
+ ndev->name);
+ } else {
+ /* disable auto negotiation */
+ writel(0x00000000, dev->base + TBICR);
+ }
+
+ printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name,
+ cmd->autoneg ? "ENABLED" : "DISABLED");
+ }
+
+ phy_intr(ndev);
+ spin_unlock(&dev->tx_lock);
+ spin_unlock_irq(&dev->misc_lock);
+
+ return 0;
+}
+/* end ethtool get/set support -df */
+
static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
{
struct ns83820 *dev = PRIV(ndev);
@@ -1263,8 +1406,10 @@ static u32 ns83820_get_link(struct net_device *ndev)
}
static const struct ethtool_ops ops = {
- .get_drvinfo = ns83820_get_drvinfo,
- .get_link = ns83820_get_link
+ .get_settings = ns83820_get_settings,
+ .set_settings = ns83820_set_settings,
+ .get_drvinfo = ns83820_get_drvinfo,
+ .get_link = ns83820_get_link
};
/* this function is called in irq context from the ISR */
@@ -1582,7 +1727,7 @@ static void ns83820_set_multicast(struct net_device *ndev)
else
and_mask &= ~(RFCR_AAU | RFCR_AAM);
- if (ndev->flags & IFF_ALLMULTI)
+ if (ndev->flags & IFF_ALLMULTI || ndev->mc_count)
or_mask |= RFCR_AAM;
else
and_mask &= ~RFCR_AAM;
@@ -1817,6 +1962,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
long addr;
int err;
int using_dac = 0;
+ DECLARE_MAC_BUF(mac);
/* See if we can set the dma mask early on; failure is fatal. */
if (sizeof(dma_addr_t) == 8 &&
@@ -1843,7 +1989,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
spin_lock_init(&dev->misc_lock);
dev->pci_dev = pci_dev;
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pci_dev->dev);
INIT_WORK(&dev->tq_refill, queue_refill);
@@ -2082,13 +2227,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
ndev->features |= NETIF_F_HIGHDMA;
}
- printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n",
+ printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n",
ndev->name,
(unsigned)readl(dev->base + SRR) >> 8,
(unsigned)readl(dev->base + SRR) & 0xff,
- ndev->dev_addr[0], ndev->dev_addr[1],
- ndev->dev_addr[2], ndev->dev_addr[3],
- ndev->dev_addr[4], ndev->dev_addr[5],
+ print_mac(mac, ndev->dev_addr),
addr, pci_dev->irq,
(ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg"
);
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 0b3066a6fe40..9f9a421c99b3 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -34,24 +34,29 @@
#include <net/checksum.h>
#include <asm/irq.h>
+#include <asm/firmware.h>
#include "pasemi_mac.h"
+/* We have our own align, since ppc64 in general has it at 0 because
+ * of design flaws in some of the server bridge chips. However, for
+ * PWRficient doing the unaligned copies is more expensive than doing
+ * unaligned DMA, so make sure the data is aligned instead.
+ */
+#define LOCAL_SKB_ALIGN 2
/* TODO list
*
- * - Get rid of pci_{read,write}_config(), map registers with ioremap
- * for performance
- * - PHY support
* - Multicast support
* - Large MTU support
- * - Other performance improvements
+ * - SW LRO
+ * - Multiqueue RX/TX
*/
/* Must be a power of two */
-#define RX_RING_SIZE 512
-#define TX_RING_SIZE 512
+#define RX_RING_SIZE 4096
+#define TX_RING_SIZE 4096
#define DEFAULT_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -63,12 +68,16 @@
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
-#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
-#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
-#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
-#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define TX_RING(mac, num) ((mac)->tx->ring[(num) & (TX_RING_SIZE-1)])
+#define TX_RING_INFO(mac, num) ((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)])
+#define RX_RING(mac, num) ((mac)->rx->ring[(num) & (RX_RING_SIZE-1)])
+#define RX_RING_INFO(mac, num) ((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)])
#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+#define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \
+ & ((ring)->size - 1))
+#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring))
+
#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
MODULE_LICENSE("GPL");
@@ -81,6 +90,43 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value");
static struct pasdma_status *dma_status;
+static int translation_enabled(void)
+{
+#if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)
+ return 1;
+#else
+ return firmware_has_feature(FW_FEATURE_LPAR);
+#endif
+}
+
+static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg,
+ unsigned int val)
+{
+ out_le32(mac->iob_regs+reg, val);
+}
+
+static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg)
+{
+ return in_le32(mac->regs+reg);
+}
+
+static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg,
+ unsigned int val)
+{
+ out_le32(mac->regs+reg, val);
+}
+
+static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg)
+{
+ return in_le32(mac->dma_regs+reg);
+}
+
+static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg,
+ unsigned int val)
+{
+ out_le32(mac->dma_regs+reg, val);
+}
+
static int pasemi_get_mac_addr(struct pasemi_mac *mac)
{
struct pci_dev *pdev = mac->pdev;
@@ -128,11 +174,36 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
return 0;
}
+static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
+ struct sk_buff *skb,
+ dma_addr_t *dmas)
+{
+ int f;
+ int nfrags = skb_shinfo(skb)->nr_frags;
+
+ pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+
+ for (f = 0; f < nfrags; f++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
+
+ pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size,
+ PCI_DMA_TODEVICE);
+ }
+ dev_kfree_skb_irq(skb);
+
+ /* Freed descriptor slot + main SKB ptr + nfrags additional ptrs,
+ * aligned up to a power of 2
+ */
+ return (nfrags + 3) & ~1;
+}
+
static int pasemi_mac_setup_rx_resources(struct net_device *dev)
{
struct pasemi_mac_rxring *ring;
struct pasemi_mac *mac = netdev_priv(dev);
int chan_id = mac->dma_rxch;
+ unsigned int cfg;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -141,22 +212,22 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
spin_lock_init(&ring->lock);
- ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ ring->size = RX_RING_SIZE;
+ ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
RX_RING_SIZE, GFP_KERNEL);
- if (!ring->desc_info)
- goto out_desc_info;
+ if (!ring->ring_info)
+ goto out_ring_info;
/* Allocate descriptors */
- ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
- RX_RING_SIZE *
- sizeof(struct pas_dma_xct_descr),
+ ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(u64),
&ring->dma, GFP_KERNEL);
- if (!ring->desc)
- goto out_desc;
+ if (!ring->ring)
+ goto out_ring_desc;
- memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+ memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64));
ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
RX_RING_SIZE * sizeof(u64),
@@ -166,22 +237,34 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
- PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+ write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+ write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id),
+ PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+ PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+ cfg = PAS_DMA_RXCHAN_CFG_HBU(2);
+
+ if (translation_enabled())
+ cfg |= PAS_DMA_RXCHAN_CFG_CTR;
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
- PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
- PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg);
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
- PAS_DMA_RXCHAN_CFG_HBU(1));
+ write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if),
+ PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
- PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+ write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if),
+ PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) |
+ PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
- PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
- PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+ cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 |
+ PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
+ PAS_DMA_RXINT_CFG_HEN;
+
+ if (translation_enabled())
+ cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR;
+
+ write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg);
ring->next_to_fill = 0;
ring->next_to_clean = 0;
@@ -194,11 +277,11 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
out_buffers:
dma_free_coherent(&mac->dma_pdev->dev,
- RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
- mac->rx->desc, mac->rx->dma);
-out_desc:
- kfree(ring->desc_info);
-out_desc_info:
+ RX_RING_SIZE * sizeof(u64),
+ mac->rx->ring, mac->rx->dma);
+out_ring_desc:
+ kfree(ring->ring_info);
+out_ring_info:
kfree(ring);
out_ring:
return -ENOMEM;
@@ -211,6 +294,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
u32 val;
int chan_id = mac->dma_txch;
struct pasemi_mac_txring *ring;
+ unsigned int cfg;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
@@ -218,35 +302,39 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
spin_lock_init(&ring->lock);
- ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ ring->size = TX_RING_SIZE;
+ ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
TX_RING_SIZE, GFP_KERNEL);
- if (!ring->desc_info)
- goto out_desc_info;
+ if (!ring->ring_info)
+ goto out_ring_info;
/* Allocate descriptors */
- ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
- TX_RING_SIZE *
- sizeof(struct pas_dma_xct_descr),
+ ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE * sizeof(u64),
&ring->dma, GFP_KERNEL);
- if (!ring->desc)
- goto out_desc;
+ if (!ring->ring)
+ goto out_ring_desc;
- memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+ memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
- PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+ write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id),
+ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
- val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3);
+
+ write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val);
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+ cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE |
+ PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+ PAS_DMA_TXCHAN_CFG_UP |
+ PAS_DMA_TXCHAN_CFG_WT(2);
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
- PAS_DMA_TXCHAN_CFG_TY_IFACE |
- PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
- PAS_DMA_TXCHAN_CFG_UP |
- PAS_DMA_TXCHAN_CFG_WT(2));
+ if (translation_enabled())
+ cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR;
- ring->next_to_use = 0;
+ write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg);
+
+ ring->next_to_fill = 0;
ring->next_to_clean = 0;
snprintf(ring->irq_name, sizeof(ring->irq_name),
@@ -255,9 +343,9 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
return 0;
-out_desc:
- kfree(ring->desc_info);
-out_desc_info:
+out_ring_desc:
+ kfree(ring->ring_info);
+out_ring_info:
kfree(ring);
out_ring:
return -ENOMEM;
@@ -266,33 +354,37 @@ out_ring:
static void pasemi_mac_free_tx_resources(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
- unsigned int i;
+ unsigned int i, j;
struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- info = &TX_DESC_INFO(mac, i);
- dp = &TX_DESC(mac, i);
- if (info->dma) {
- if (info->skb) {
- pci_unmap_single(mac->dma_pdev,
- info->dma,
- info->skb->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_any(info->skb);
- }
- info->dma = 0;
- info->skb = NULL;
- dp->mactx = 0;
- dp->ptr = 0;
- }
+ dma_addr_t dmas[MAX_SKB_FRAGS+1];
+ int freed;
+ int start, limit;
+
+ start = mac->tx->next_to_clean;
+ limit = mac->tx->next_to_fill;
+
+ /* Compensate for when fill has wrapped and clean has not */
+ if (start > limit)
+ limit += TX_RING_SIZE;
+
+ for (i = start; i < limit; i += freed) {
+ info = &TX_RING_INFO(mac, i+1);
+ if (info->dma && info->skb) {
+ for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
+ dmas[j] = TX_RING_INFO(mac, i+1+j).dma;
+ freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas);
+ } else
+ freed = 2;
}
+ for (i = 0; i < TX_RING_SIZE; i++)
+ TX_RING(mac, i) = 0;
+
dma_free_coherent(&mac->dma_pdev->dev,
- TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
- mac->tx->desc, mac->tx->dma);
+ TX_RING_SIZE * sizeof(u64),
+ mac->tx->ring, mac->tx->dma);
- kfree(mac->tx->desc_info);
+ kfree(mac->tx->ring_info);
kfree(mac->tx);
mac->tx = NULL;
}
@@ -302,72 +394,66 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev)
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int i;
struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
for (i = 0; i < RX_RING_SIZE; i++) {
- info = &RX_DESC_INFO(mac, i);
- dp = &RX_DESC(mac, i);
- if (info->skb) {
- if (info->dma) {
- pci_unmap_single(mac->dma_pdev,
- info->dma,
- info->skb->len,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb_any(info->skb);
- }
- info->dma = 0;
- info->skb = NULL;
- dp->macrx = 0;
- dp->ptr = 0;
+ info = &RX_RING_INFO(mac, i);
+ if (info->skb && info->dma) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(info->skb);
}
+ info->dma = 0;
+ info->skb = NULL;
}
+ for (i = 0; i < RX_RING_SIZE; i++)
+ RX_RING(mac, i) = 0;
+
dma_free_coherent(&mac->dma_pdev->dev,
- RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
- mac->rx->desc, mac->rx->dma);
+ RX_RING_SIZE * sizeof(u64),
+ mac->rx->ring, mac->rx->dma);
dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
mac->rx->buffers, mac->rx->buf_dma);
- kfree(mac->rx->desc_info);
+ kfree(mac->rx->ring_info);
kfree(mac->rx);
mac->rx = NULL;
}
-static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
{
struct pasemi_mac *mac = netdev_priv(dev);
- unsigned int i;
- int start = mac->rx->next_to_fill;
- unsigned int limit, count;
-
- limit = (mac->rx->next_to_clean + RX_RING_SIZE -
- mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
-
- /* Check to see if we're doing first-time setup */
- if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
- limit = RX_RING_SIZE;
+ int fill, count;
if (limit <= 0)
return;
- i = start;
- for (count = limit; count; count--) {
- struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
- u64 *buff = &RX_BUFF(mac, i);
+ fill = mac->rx->next_to_fill;
+ for (count = 0; count < limit; count++) {
+ struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
+ u64 *buff = &RX_BUFF(mac, fill);
struct sk_buff *skb;
dma_addr_t dma;
+ /* Entry in use? */
+ WARN_ON(*buff);
+
/* skb might still be in there for recycle on short receives */
if (info->skb)
skb = info->skb;
- else
+ else {
skb = dev_alloc_skb(BUF_SIZE);
+ skb_reserve(skb, LOCAL_SKB_ALIGN);
+ }
if (unlikely(!skb))
break;
- dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+ dma = pci_map_single(mac->dma_pdev, skb->data,
+ BUF_SIZE - LOCAL_SKB_ALIGN,
PCI_DMA_FROMDEVICE);
if (unlikely(dma_mapping_error(dma))) {
@@ -378,19 +464,15 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
info->skb = skb;
info->dma = dma;
*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
- i++;
+ fill++;
}
wmb();
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
- limit - count);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_INCR(mac->dma_if),
- limit - count);
+ write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count);
- mac->rx->next_to_fill += limit - count;
+ mac->rx->next_to_fill = (mac->rx->next_to_fill + count) &
+ (RX_RING_SIZE - 1);
}
static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
@@ -404,9 +486,7 @@ static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC;
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch),
- reg);
+ write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
}
static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
@@ -418,69 +498,96 @@ static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
+ write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
}
+static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx)
+{
+ unsigned int rcmdsta, ccmdsta;
+
+ if (!netif_msg_rx_err(mac))
+ return;
+
+ rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+
+ printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n",
+ macrx, *mac->rx_status);
+
+ printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
+ rcmdsta, ccmdsta);
+}
+
+static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx)
+{
+ unsigned int cmdsta;
+
+ if (!netif_msg_tx_err(mac))
+ return;
+
+ cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+
+ printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\
+ "tx status 0x%016lx\n", mactx, *mac->tx_status);
+
+ printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
+}
+
static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
{
unsigned int n;
int count;
- struct pas_dma_xct_descr *dp;
struct pasemi_mac_buffer *info;
struct sk_buff *skb;
- unsigned int i, len;
+ unsigned int len;
u64 macrx;
dma_addr_t dma;
+ int buf_index;
+ u64 eval;
spin_lock(&mac->rx->lock);
n = mac->rx->next_to_clean;
- for (count = limit; count; count--) {
+ prefetch(RX_RING(mac, n));
- rmb();
+ for (count = 0; count < limit; count++) {
+ macrx = RX_RING(mac, n);
- dp = &RX_DESC(mac, n);
- macrx = dp->macrx;
+ if ((macrx & XCT_MACRX_E) ||
+ (*mac->rx_status & PAS_STATUS_ERROR))
+ pasemi_mac_rx_error(mac, macrx);
if (!(macrx & XCT_MACRX_O))
break;
-
info = NULL;
- /* We have to scan for our skb since there's no way
- * to back-map them from the descriptor, and if we
- * have several receive channels then they might not
- * show up in the same order as they were put on the
- * interface ring.
- */
+ BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
- dma = (dp->ptr & XCT_PTR_ADDR_M);
- for (i = n; i < (n + RX_RING_SIZE); i++) {
- info = &RX_DESC_INFO(mac, i);
- if (info->dma == dma)
- break;
- }
+ eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >>
+ XCT_RXRES_8B_EVAL_S;
+ buf_index = eval-1;
+
+ dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M);
+ info = &RX_RING_INFO(mac, buf_index);
skb = info->skb;
- info->dma = 0;
- pci_unmap_single(mac->dma_pdev, dma, skb->len,
- PCI_DMA_FROMDEVICE);
+ prefetch(skb);
+ prefetch(&skb->data_len);
len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
if (len < 256) {
- struct sk_buff *new_skb =
- netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN);
+ struct sk_buff *new_skb;
+
+ new_skb = netdev_alloc_skb(mac->netdev,
+ len + LOCAL_SKB_ALIGN);
if (new_skb) {
- skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data - NET_IP_ALIGN,
- skb->data - NET_IP_ALIGN,
- len + NET_IP_ALIGN);
+ skb_reserve(new_skb, LOCAL_SKB_ALIGN);
+ memcpy(new_skb->data, skb->data, len);
/* save the skb in buffer_info as good */
skb = new_skb;
}
@@ -488,73 +595,131 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
} else
info->skb = NULL;
- skb_put(skb, len);
+ pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE);
- skb->protocol = eth_type_trans(skb, mac->netdev);
+ info->dma = 0;
+
+ skb_put(skb, len);
- if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
- skb->ip_summed = CHECKSUM_COMPLETE;
+ if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
XCT_MACRX_CSUM_S;
} else
skb->ip_summed = CHECKSUM_NONE;
- mac->stats.rx_bytes += len;
- mac->stats.rx_packets++;
+ mac->netdev->stats.rx_bytes += len;
+ mac->netdev->stats.rx_packets++;
+ skb->protocol = eth_type_trans(skb, mac->netdev);
netif_receive_skb(skb);
- dp->ptr = 0;
- dp->macrx = 0;
+ RX_RING(mac, n) = 0;
+ RX_RING(mac, n+1) = 0;
+
+ /* Need to zero it out since hardware doesn't, since the
+ * replenish loop uses it to tell when it's done.
+ */
+ RX_BUFF(mac, buf_index) = 0;
+
+ n += 4;
+ }
- n++;
+ if (n > RX_RING_SIZE) {
+ /* Errata 5971 workaround: L2 target of headers */
+ write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
+ n &= (RX_RING_SIZE-1);
}
- mac->rx->next_to_clean += limit - count;
- pasemi_mac_replenish_rx_ring(mac->netdev);
+ mac->rx->next_to_clean = n;
+
+ /* Increase is in number of 16-byte entries, and since each descriptor
+ * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
+ * count*2.
+ */
+ write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1);
+
+ pasemi_mac_replenish_rx_ring(mac->netdev, count);
spin_unlock(&mac->rx->lock);
return count;
}
+/* Can't make this too large or we blow the kernel stack limits */
+#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS)
+
static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
{
- int i;
- struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
- int start, count;
- int flags;
-
+ int i, j;
+ unsigned int start, descr_count, buf_count, batch_limit;
+ unsigned int ring_limit;
+ unsigned int total_count;
+ unsigned long flags;
+ struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
+ dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
+
+ total_count = 0;
+ batch_limit = TX_CLEAN_BATCHSIZE;
+restart:
spin_lock_irqsave(&mac->tx->lock, flags);
start = mac->tx->next_to_clean;
- count = 0;
+ ring_limit = mac->tx->next_to_fill;
- for (i = start; i < mac->tx->next_to_use; i++) {
- dp = &TX_DESC(mac, i);
- if (!dp || (dp->mactx & XCT_MACTX_O))
+ /* Compensate for when fill has wrapped but clean has not */
+ if (start > ring_limit)
+ ring_limit += TX_RING_SIZE;
+
+ buf_count = 0;
+ descr_count = 0;
+
+ for (i = start;
+ descr_count < batch_limit && i < ring_limit;
+ i += buf_count) {
+ u64 mactx = TX_RING(mac, i);
+ struct sk_buff *skb;
+
+ if ((mactx & XCT_MACTX_E) ||
+ (*mac->tx_status & PAS_STATUS_ERROR))
+ pasemi_mac_tx_error(mac, mactx);
+
+ if (unlikely(mactx & XCT_MACTX_O))
+ /* Not yet transmitted */
break;
- count++;
+ skb = TX_RING_INFO(mac, i+1).skb;
+ skbs[descr_count] = skb;
- info = &TX_DESC_INFO(mac, i);
+ buf_count = 2 + skb_shinfo(skb)->nr_frags;
+ for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++)
+ dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma;
- pci_unmap_single(mac->dma_pdev, info->dma,
- info->skb->len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(info->skb);
+ TX_RING(mac, i) = 0;
+ TX_RING(mac, i+1) = 0;
- info->skb = NULL;
- info->dma = 0;
- dp->mactx = 0;
- dp->ptr = 0;
+ /* Since we always fill with an even number of entries, make
+ * sure we skip any unused one at the end as well.
+ */
+ if (buf_count & 1)
+ buf_count++;
+ descr_count++;
}
- mac->tx->next_to_clean += count;
- spin_unlock_irqrestore(&mac->tx->lock, flags);
+ mac->tx->next_to_clean = i & (TX_RING_SIZE-1);
+ spin_unlock_irqrestore(&mac->tx->lock, flags);
netif_wake_queue(mac->netdev);
- return count;
+ for (i = 0; i < descr_count; i++)
+ pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]);
+
+ total_count += descr_count;
+
+ /* If the batch was full, try to clean more */
+ if (descr_count == batch_limit)
+ goto restart;
+
+ return total_count;
}
@@ -567,15 +732,10 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
return IRQ_NONE;
- if (*mac->rx_status & PAS_STATUS_ERROR)
- printk("rx_status reported error\n");
-
/* Don't reset packet count so it won't fire again but clear
* all others.
*/
- pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), &reg);
-
reg = 0;
if (*mac->rx_status & PAS_STATUS_SOFT)
reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
@@ -584,11 +744,9 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
if (*mac->rx_status & PAS_STATUS_TIMER)
reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
- netif_rx_schedule(dev);
-
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+ netif_rx_schedule(dev, &mac->napi);
+ write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
return IRQ_HANDLED;
}
@@ -613,9 +771,7 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
if (*mac->tx_status & PAS_STATUS_ERROR)
reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
- reg);
+ write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
return IRQ_HANDLED;
}
@@ -641,7 +797,7 @@ static void pasemi_adjust_link(struct net_device *dev)
} else
netif_carrier_on(dev);
- pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+ flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
PAS_MAC_CFG_PCFG_TSR_M);
@@ -673,7 +829,7 @@ static void pasemi_adjust_link(struct net_device *dev)
mac->link = mac->phydev->link;
if (new_flags != flags)
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags);
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, new_flags);
if (msg && netif_msg_link(mac))
printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n",
@@ -736,39 +892,30 @@ static int pasemi_mac_open(struct net_device *dev)
int ret;
/* enable rx section */
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
- PAS_DMA_COM_RXCMD_EN);
+ write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN);
/* enable tx section */
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
- PAS_DMA_COM_TXCMD_EN);
+ write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+ write_mac_reg(mac, PAS_MAC_CFG_TXP, flags);
- flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
- PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
-
- flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
-
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
- PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
+ write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
- PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
+ write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
+ PAS_IOB_DMA_TXCH_CFG_CNTTH(128));
/* Clear out any residual packet count state from firmware */
pasemi_mac_restart_rx_intr(mac);
pasemi_mac_restart_tx_intr(mac);
/* 0xffffff is max value, about 16ms */
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
- PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
-
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+ write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
ret = pasemi_mac_setup_rx_resources(dev);
if (ret)
@@ -778,27 +925,48 @@ static int pasemi_mac_open(struct net_device *dev)
if (ret)
goto out_tx_resources;
- pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
- PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
- PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+ write_mac_reg(mac, PAS_MAC_IPC_CHNL,
+ PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+ PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
/* enable rx if */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- PAS_DMA_RXINT_RCMDSTA_EN);
+ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_EN |
+ PAS_DMA_RXINT_RCMDSTA_DROPS_M |
+ PAS_DMA_RXINT_RCMDSTA_BP |
+ PAS_DMA_RXINT_RCMDSTA_OO |
+ PAS_DMA_RXINT_RCMDSTA_BT);
/* enable rx channel */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
- PAS_DMA_RXCHAN_CCMDSTA_EN |
- PAS_DMA_RXCHAN_CCMDSTA_DU);
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_EN |
+ PAS_DMA_RXCHAN_CCMDSTA_DU |
+ PAS_DMA_RXCHAN_CCMDSTA_OD |
+ PAS_DMA_RXCHAN_CCMDSTA_FD |
+ PAS_DMA_RXCHAN_CCMDSTA_DT);
/* enable tx channel */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
- PAS_DMA_TXCHAN_TCMDSTA_EN);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_EN |
+ PAS_DMA_TXCHAN_TCMDSTA_SZ |
+ PAS_DMA_TXCHAN_TCMDSTA_DB |
+ PAS_DMA_TXCHAN_TCMDSTA_DE |
+ PAS_DMA_TXCHAN_TCMDSTA_DA);
+
+ pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
+
+ write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1);
- pasemi_mac_replenish_rx_ring(dev);
+ flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+ PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+ if (mac->type == MAC_TYPE_GMAC)
+ flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+ else
+ flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G;
+
+ /* Enable interface in MAC */
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
ret = pasemi_mac_phy_init(dev);
/* Some configs don't have PHYs (XAUI etc), so don't complain about
@@ -808,7 +976,7 @@ static int pasemi_mac_open(struct net_device *dev)
dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret);
netif_start_queue(dev);
- netif_poll_enable(dev);
+ napi_enable(&mac->napi);
/* Interrupts are a bit different for our DMA controller: While
* it's got one a regular PCI device header, the interrupt there
@@ -845,7 +1013,7 @@ static int pasemi_mac_open(struct net_device *dev)
out_rx_int:
free_irq(mac->tx_irq, dev);
out_tx_int:
- netif_poll_disable(dev);
+ napi_disable(&mac->napi);
netif_stop_queue(dev);
pasemi_mac_free_tx_resources(dev);
out_tx_resources:
@@ -860,7 +1028,7 @@ out_rx_resources:
static int pasemi_mac_close(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
- unsigned int stat;
+ unsigned int sta;
int retries;
if (mac->phydev) {
@@ -869,68 +1037,74 @@ static int pasemi_mac_close(struct net_device *dev)
}
netif_stop_queue(dev);
+ napi_disable(&mac->napi);
+
+ sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |
+ PAS_DMA_RXINT_RCMDSTA_OO |
+ PAS_DMA_RXINT_RCMDSTA_BT))
+ printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);
+
+ sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+ if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |
+ PAS_DMA_RXCHAN_CCMDSTA_OD |
+ PAS_DMA_RXCHAN_CCMDSTA_FD |
+ PAS_DMA_RXCHAN_CCMDSTA_DT))
+ printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);
+
+ sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+ if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ |
+ PAS_DMA_TXCHAN_TCMDSTA_DB |
+ PAS_DMA_TXCHAN_TCMDSTA_DE |
+ PAS_DMA_TXCHAN_TCMDSTA_DA))
+ printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);
/* Clean out any pending buffers */
pasemi_mac_clean_tx(mac);
pasemi_mac_clean_rx(mac, RX_RING_SIZE);
/* Disable interface */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
- PAS_DMA_TXCHAN_TCMDSTA_ST);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- PAS_DMA_RXINT_RCMDSTA_ST);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
- PAS_DMA_RXCHAN_CCMDSTA_ST);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST);
+ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST);
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST);
for (retries = 0; retries < MAX_RETRIES; retries++) {
- pci_read_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
- &stat);
- if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+ sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+ if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
break;
cond_resched();
}
- if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
for (retries = 0; retries < MAX_RETRIES; retries++) {
- pci_read_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
- &stat);
- if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+ sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+ if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
break;
cond_resched();
}
- if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
for (retries = 0; retries < MAX_RETRIES; retries++) {
- pci_read_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- &stat);
- if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT))
+ sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
break;
cond_resched();
}
- if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+ if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
/* Then, disable the channel. This must be done separately from
* stopping, since you can't disable when active.
*/
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
free_irq(mac->tx_irq, dev);
free_irq(mac->rx_irq, dev);
@@ -946,11 +1120,11 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
struct pasemi_mac_txring *txring;
- struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
- u64 dflags;
- dma_addr_t map;
- int flags;
+ u64 dflags, mactx;
+ dma_addr_t map[MAX_SKB_FRAGS+1];
+ unsigned int map_size[MAX_SKB_FRAGS+1];
+ unsigned long flags;
+ int i, nfrags;
dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
@@ -971,71 +1145,87 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
}
}
- map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ nfrags = skb_shinfo(skb)->nr_frags;
- if (dma_mapping_error(map))
- return NETDEV_TX_BUSY;
+ map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+ map_size[0] = skb_headlen(skb);
+ if (dma_mapping_error(map[0]))
+ goto out_err_nolock;
+
+ for (i = 0; i < nfrags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ map[i+1] = pci_map_page(mac->dma_pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ map_size[i+1] = frag->size;
+ if (dma_mapping_error(map[i+1])) {
+ nfrags = i;
+ goto out_err_nolock;
+ }
+ }
+
+ mactx = dflags | XCT_MACTX_LLEN(skb->len);
txring = mac->tx;
spin_lock_irqsave(&txring->lock, flags);
- if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
- spin_unlock_irqrestore(&txring->lock, flags);
- pasemi_mac_clean_tx(mac);
- pasemi_mac_restart_tx_intr(mac);
- spin_lock_irqsave(&txring->lock, flags);
-
- if (txring->next_to_clean - txring->next_to_use ==
- TX_RING_SIZE) {
- /* Still no room -- stop the queue and wait for tx
- * intr when there's room.
- */
- netif_stop_queue(dev);
- goto out_err;
- }
+ /* Avoid stepping on the same cache line that the DMA controller
+ * is currently about to send, so leave at least 8 words available.
+ * Total free space needed is mactx + fragments + 8
+ */
+ if (RING_AVAIL(txring) < nfrags + 10) {
+ /* no room -- stop the queue and wait for tx intr */
+ netif_stop_queue(dev);
+ goto out_err;
}
+ TX_RING(mac, txring->next_to_fill) = mactx;
+ txring->next_to_fill++;
+ TX_RING_INFO(mac, txring->next_to_fill).skb = skb;
+ for (i = 0; i <= nfrags; i++) {
+ TX_RING(mac, txring->next_to_fill+i) =
+ XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
+ TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i];
+ }
- dp = &TX_DESC(mac, txring->next_to_use);
- info = &TX_DESC_INFO(mac, txring->next_to_use);
+ /* We have to add an even number of 8-byte entries to the ring
+ * even if the last one is unused. That means always an odd number
+ * of pointers + one mactx descriptor.
+ */
+ if (nfrags & 1)
+ nfrags++;
- dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
- dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
- info->dma = map;
- info->skb = skb;
+ txring->next_to_fill = (txring->next_to_fill + nfrags + 1) &
+ (TX_RING_SIZE-1);
- txring->next_to_use++;
- mac->stats.tx_packets++;
- mac->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
spin_unlock_irqrestore(&txring->lock, flags);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1);
return NETDEV_TX_OK;
out_err:
spin_unlock_irqrestore(&txring->lock, flags);
- pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
- return NETDEV_TX_BUSY;
-}
+out_err_nolock:
+ while (nfrags--)
+ pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags],
+ PCI_DMA_TODEVICE);
-static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
-{
- struct pasemi_mac *mac = netdev_priv(dev);
-
- return &mac->stats;
+ return NETDEV_TX_BUSY;
}
-
static void pasemi_mac_set_rx_mode(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int flags;
- pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+ flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
/* Set promiscuous */
if (dev->flags & IFF_PROMISC)
@@ -1043,30 +1233,92 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev)
else
flags &= ~PAS_MAC_CFG_PCFG_PR;
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
}
-static int pasemi_mac_poll(struct net_device *dev, int *budget)
+static int pasemi_mac_poll(struct napi_struct *napi, int budget)
{
- int pkts, limit = min(*budget, dev->quota);
- struct pasemi_mac *mac = netdev_priv(dev);
-
- pkts = pasemi_mac_clean_rx(mac, limit);
-
- dev->quota -= pkts;
- *budget -= pkts;
+ struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi);
+ struct net_device *dev = mac->netdev;
+ int pkts;
- if (pkts < limit) {
+ pasemi_mac_clean_tx(mac);
+ pkts = pasemi_mac_clean_rx(mac, budget);
+ if (pkts < budget) {
/* all done, no more packets present */
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
pasemi_mac_restart_rx_intr(mac);
- return 0;
- } else {
- /* used up our quantum, so reschedule */
- return 1;
}
+ return pkts;
+}
+
+static void __iomem * __devinit map_onedev(struct pci_dev *p, int index)
+{
+ struct device_node *dn;
+ void __iomem *ret;
+
+ dn = pci_device_to_OF_node(p);
+ if (!dn)
+ goto fallback;
+
+ ret = of_iomap(dn, index);
+ if (!ret)
+ goto fallback;
+
+ return ret;
+fallback:
+ /* This is hardcoded and ugly, but we have some firmware versions
+ * that don't provide the register space in the device tree. Luckily
+ * they are at well-known locations so we can just do the math here.
+ */
+ return ioremap(0xe0000000 + (p->devfn << 12), 0x2000);
+}
+
+static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac)
+{
+ struct resource res;
+ struct device_node *dn;
+ int err;
+
+ mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+ if (!mac->dma_pdev) {
+ dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
+ return -ENODEV;
+ }
+
+ mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+ if (!mac->iob_pdev) {
+ dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");
+ return -ENODEV;
+ }
+
+ mac->regs = map_onedev(mac->pdev, 0);
+ mac->dma_regs = map_onedev(mac->dma_pdev, 0);
+ mac->iob_regs = map_onedev(mac->iob_pdev, 0);
+
+ if (!mac->regs || !mac->dma_regs || !mac->iob_regs) {
+ dev_err(&mac->pdev->dev, "Can't map registers\n");
+ return -ENODEV;
+ }
+
+ /* The dma status structure is located in the I/O bridge, and
+ * is cache coherent.
+ */
+ if (!dma_status) {
+ dn = pci_device_to_OF_node(mac->iob_pdev);
+ if (dn)
+ err = of_address_to_resource(dn, 1, &res);
+ if (!dn || err) {
+ /* Fallback for old firmware */
+ res.start = 0xfd800000;
+ res.end = res.start + 0x1000;
+ }
+ dma_status = __ioremap(res.start, res.end-res.start, 0);
+ }
+
+ return 0;
}
static int __devinit
@@ -1076,6 +1328,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *dev;
struct pasemi_mac *mac;
int err;
+ DECLARE_MAC_BUF(mac_buf);
err = pci_enable_device(pdev);
if (err)
@@ -1089,7 +1342,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_disable_device;
}
- SET_MODULE_OWNER(dev);
pci_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1097,21 +1349,10 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mac->pdev = pdev;
mac->netdev = dev;
- mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
- if (!mac->dma_pdev) {
- dev_err(&pdev->dev, "Can't find DMA Controller\n");
- err = -ENODEV;
- goto out_free_netdev;
- }
+ netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);
- mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
-
- if (!mac->iob_pdev) {
- dev_err(&pdev->dev, "Can't find I/O Bridge\n");
- err = -ENODEV;
- goto out_put_dma_pdev;
- }
+ dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG;
/* These should come out of the device tree eventually */
mac->dma_txch = index;
@@ -1148,18 +1389,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->open = pasemi_mac_open;
dev->stop = pasemi_mac_close;
dev->hard_start_xmit = pasemi_mac_start_tx;
- dev->get_stats = pasemi_mac_get_stats;
dev->set_multicast_list = pasemi_mac_set_rx_mode;
- dev->weight = 64;
- dev->poll = pasemi_mac_poll;
- dev->features = NETIF_F_HW_CSUM;
- /* The dma status structure is located in the I/O bridge, and
- * is cache coherent.
- */
- if (!dma_status)
- /* XXXOJN This should come from the device tree */
- dma_status = __ioremap(0xfd800000, 0x1000, 0);
+ err = pasemi_mac_map_regs(mac);
+ if (err)
+ goto out;
mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
@@ -1175,21 +1409,27 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
err);
goto out;
- } else
+ } else if netif_msg_probe(mac)
printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
- "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ "hw addr %s\n",
dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
mac->dma_if, mac->dma_txch, mac->dma_rxch,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ print_mac(mac_buf, dev->dev_addr));
return err;
out:
- pci_dev_put(mac->iob_pdev);
-out_put_dma_pdev:
- pci_dev_put(mac->dma_pdev);
-out_free_netdev:
+ if (mac->iob_pdev)
+ pci_dev_put(mac->iob_pdev);
+ if (mac->dma_pdev)
+ pci_dev_put(mac->dma_pdev);
+ if (mac->dma_regs)
+ iounmap(mac->dma_regs);
+ if (mac->iob_regs)
+ iounmap(mac->iob_regs);
+ if (mac->regs)
+ iounmap(mac->regs);
+
free_netdev(dev);
out_disable_device:
pci_disable_device(pdev);
@@ -1213,6 +1453,10 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
pci_dev_put(mac->dma_pdev);
pci_dev_put(mac->iob_pdev);
+ iounmap(mac->regs);
+ iounmap(mac->dma_regs);
+ iounmap(mac->iob_regs);
+
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
}
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index c29ee159c33d..60368df72634 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -28,35 +28,38 @@
struct pasemi_mac_txring {
spinlock_t lock;
- struct pas_dma_xct_descr *desc;
+ u64 *ring;
dma_addr_t dma;
unsigned int size;
- unsigned int next_to_use;
+ unsigned int next_to_fill;
unsigned int next_to_clean;
- struct pasemi_mac_buffer *desc_info;
+ struct pasemi_mac_buffer *ring_info;
char irq_name[10]; /* "eth%d tx" */
};
struct pasemi_mac_rxring {
spinlock_t lock;
- struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */
+ u64 *ring; /* RX channel descriptor ring */
dma_addr_t dma;
u64 *buffers; /* RX interface buffer ring */
dma_addr_t buf_dma;
unsigned int size;
unsigned int next_to_fill;
unsigned int next_to_clean;
- struct pasemi_mac_buffer *desc_info;
+ struct pasemi_mac_buffer *ring_info;
char irq_name[10]; /* "eth%d rx" */
};
struct pasemi_mac {
struct net_device *netdev;
+ void __iomem *regs;
+ void __iomem *dma_regs;
+ void __iomem *iob_regs;
struct pci_dev *pdev;
struct pci_dev *dma_pdev;
struct pci_dev *iob_pdev;
struct phy_device *phydev;
- struct net_device_stats stats;
+ struct napi_struct napi;
/* Pointer to the cacheable per-channel status registers */
u64 *rx_status;
@@ -85,7 +88,7 @@ struct pasemi_mac {
char phy_id[BUS_ID_SIZE];
};
-/* Software status descriptor (desc_info) */
+/* Software status descriptor (ring_info) */
struct pasemi_mac_buffer {
struct sk_buff *skb;
dma_addr_t dma;
@@ -98,20 +101,7 @@ struct pasdma_status {
u64 tx_sta[20];
};
-/* descriptor structure */
-struct pas_dma_xct_descr {
- union {
- u64 mactx;
- u64 macrx;
- };
- union {
- u64 ptr;
- u64 rxb;
- };
-};
-
/* MAC CFG register offsets */
-
enum {
PAS_MAC_CFG_PCFG = 0x80,
PAS_MAC_CFG_TXP = 0x98,
@@ -215,6 +205,20 @@ enum {
#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000
#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000
#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17
+#define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_CFG_RBP 0x80000000
+#define PAS_DMA_RXINT_CFG_ITRR 0x40000000
+#define PAS_DMA_RXINT_CFG_DHL_M 0x07000000
+#define PAS_DMA_RXINT_CFG_DHL_S 24
+#define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
+ PAS_DMA_RXINT_CFG_DHL_M)
+#define PAS_DMA_RXINT_CFG_ITR 0x00400000
+#define PAS_DMA_RXINT_CFG_LW 0x00200000
+#define PAS_DMA_RXINT_CFG_L2 0x00100000
+#define PAS_DMA_RXINT_CFG_HEN 0x00080000
+#define PAS_DMA_RXINT_CFG_WIF 0x00000002
+#define PAS_DMA_RXINT_CFG_WIL 0x00000001
+
#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE)
#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff
#define PAS_DMA_RXINT_INCR_INCR_S 0
@@ -241,6 +245,10 @@ enum {
#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */
#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */
#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_TXCHAN_TCMDSTA_SZ 0x00000800
+#define PAS_DMA_TXCHAN_TCMDSTA_DB 0x00000400
+#define PAS_DMA_TXCHAN_TCMDSTA_DE 0x00000200
+#define PAS_DMA_TXCHAN_TCMDSTA_DA 0x00000100
#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */
#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
@@ -251,9 +259,11 @@ enum {
#define PAS_DMA_TXCHAN_CFG_WT_S 6
#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
PAS_DMA_TXCHAN_CFG_WT_M)
-#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
-#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_TRD 0x00010000 /* translate data */
+#define PAS_DMA_TXCHAN_CFG_TRR 0x00008000 /* translate rings */
#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */
+#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
@@ -283,7 +293,11 @@ enum {
#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */
#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */
#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000
+#define PAS_DMA_RXCHAN_CCMDSTA_OD 0x00002000
+#define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000
+#define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800
#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CFG_CTR 0x00000400
#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380
#define PAS_DMA_RXCHAN_CFG_HBU_S 7
#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
@@ -317,6 +331,12 @@ enum {
#define PAS_STATUS_SOFT 0x4000000000000000ull
#define PAS_STATUS_INT 0x8000000000000000ull
+#define PAS_IOB_COM_PKTHDRCNT 0x120
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M 0x0fff0000
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S 16
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M 0x00000fff
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S 0
+
#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4)
#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff
#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0
@@ -412,10 +432,9 @@ enum {
/* Receive descriptor fields */
#define XCT_MACRX_T 0x8000000000000000ull
#define XCT_MACRX_ST 0x4000000000000000ull
-#define XCT_MACRX_NORES 0x0000000000000000ull
-#define XCT_MACRX_8BRES 0x1000000000000000ull
-#define XCT_MACRX_24BRES 0x2000000000000000ull
-#define XCT_MACRX_40BRES 0x3000000000000000ull
+#define XCT_MACRX_RR_M 0x3000000000000000ull
+#define XCT_MACRX_RR_NORES 0x0000000000000000ull
+#define XCT_MACRX_RR_8BRES 0x1000000000000000ull
#define XCT_MACRX_O 0x0400000000000000ull
#define XCT_MACRX_E 0x0200000000000000ull
#define XCT_MACRX_FF 0x0100000000000000ull
@@ -463,6 +482,17 @@ enum {
#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \
XCT_PTR_ADDR_M)
+/* Receive interface 8byte result fields */
+#define XCT_RXRES_8B_L4O_M 0xff00000000000000ull
+#define XCT_RXRES_8B_L4O_S 56
+#define XCT_RXRES_8B_RULE_M 0x00ffff0000000000ull
+#define XCT_RXRES_8B_RULE_S 40
+#define XCT_RXRES_8B_EVAL_M 0x000000ffff000000ull
+#define XCT_RXRES_8B_EVAL_S 24
+#define XCT_RXRES_8B_HTYPE_M 0x0000000000f00000ull
+#define XCT_RXRES_8B_HASH_M 0x00000000000fffffull
+#define XCT_RXRES_8B_HASH_S 0
+
/* Receive interface buffer fields */
#define XCT_RXB_LEN_M 0x0ffff00000000000ull
#define XCT_RXB_LEN_S 44
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 3cdbe118200b..ed402e00e730 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -457,7 +457,6 @@ struct netdrv_private {
void *mmio_addr;
int drv_flags;
struct pci_dev *pci_dev;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
unsigned char *rx_ring;
unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
@@ -505,7 +504,6 @@ static int netdrv_start_xmit (struct sk_buff *skb,
static irqreturn_t netdrv_interrupt (int irq, void *dev_instance);
static int netdrv_close (struct net_device *dev);
static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
static void netdrv_set_rx_mode (struct net_device *dev);
static void netdrv_hw_start (struct net_device *dev);
@@ -604,7 +602,6 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
DPRINTK ("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = dev->priv;
@@ -740,6 +737,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
int i, addr_len, option;
void *ioaddr = NULL;
static int board_idx = -1;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -776,7 +774,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
dev->open = netdrv_open;
dev->hard_start_xmit = netdrv_start_xmit;
dev->stop = netdrv_close;
- dev->get_stats = netdrv_get_stats;
dev->set_multicast_list = netdrv_set_rx_mode;
dev->do_ioctl = netdrv_ioctl;
dev->tx_timeout = netdrv_tx_timeout;
@@ -800,15 +797,11 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
tp->phys[0] = 32;
- printk (KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
+ printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
@@ -1277,7 +1270,7 @@ static void netdrv_tx_clear (struct netdrv_private *tp)
if (rp->skb) {
dev_kfree_skb (rp->skb);
rp->skb = NULL;
- tp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
}
}
}
@@ -1390,25 +1383,25 @@ static void netdrv_tx_interrupt (struct net_device *dev,
/* There was an major error, log it. */
DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
dev->name, txstatus);
- tp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (txstatus & TxAborted) {
- tp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
NETDRV_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
}
if (txstatus & TxCarrierLost)
- tp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (txstatus & TxOutOfWindow)
- tp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
} else {
if (txstatus & TxUnderrun) {
/* Add 64 to the Tx FIFO threshold. */
if (tp->tx_flag < 0x00300000)
tp->tx_flag += 0x00020000;
- tp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
}
- tp->stats.collisions += (txstatus >> 24) & 15;
- tp->stats.tx_bytes += txstatus & 0x7ff;
- tp->stats.tx_packets++;
+ dev->stats.collisions += (txstatus >> 24) & 15;
+ dev->stats.tx_bytes += txstatus & 0x7ff;
+ dev->stats.tx_packets++;
}
/* Free the original skb. */
@@ -1461,13 +1454,13 @@ static void netdrv_rx_err (u32 rx_status, struct net_device *dev,
dev->name, rx_status);
/* A.C.: The chip hangs here. */
}
- tp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_status & (RxBadSymbol | RxBadAlign))
- tp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status & (RxRunt | RxTooLong))
- tp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_status & RxCRCErr)
- tp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
/* Reset the receiver, based on RealTek recommendation. (Bug?) */
tp->cur_rx = 0;
@@ -1573,13 +1566,13 @@ static void netdrv_rx_interrupt (struct net_device *dev,
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
- tp->stats.rx_bytes += pkt_size;
- tp->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_size;
+ dev->stats.rx_packets++;
} else {
printk (KERN_WARNING
"%s: Memory squeeze, dropping packet.\n",
dev->name);
- tp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
@@ -1608,7 +1601,7 @@ static void netdrv_weird_interrupt (struct net_device *dev,
assert (ioaddr != NULL);
/* Update the error count. */
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+ dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
NETDRV_W32 (RxMissed, 0);
if ((status & RxUnderrun) && link_changed &&
@@ -1629,14 +1622,14 @@ static void netdrv_weird_interrupt (struct net_device *dev,
/* XXX along with netdrv_rx_err, are we double-counting errors? */
if (status &
(RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
- tp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & (PCSTimeout))
- tp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & (RxUnderrun | RxFIFOOver))
- tp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (status & RxOverflow) {
- tp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN;
NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16);
}
@@ -1740,7 +1733,7 @@ static int netdrv_close (struct net_device *dev)
NETDRV_W16 (IntrMask, 0x0000);
/* Update the error counts. */
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+ dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
NETDRV_W32 (RxMissed, 0);
spin_unlock_irqrestore (&tp->lock, flags);
@@ -1807,31 +1800,6 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-
-static struct net_device_stats *netdrv_get_stats (struct net_device *dev)
-{
- struct netdrv_private *tp = dev->priv;
- void *ioaddr = tp->mmio_addr;
-
- DPRINTK ("ENTER\n");
-
- assert (tp != NULL);
-
- if (netif_running(dev)) {
- unsigned long flags;
-
- spin_lock_irqsave (&tp->lock, flags);
-
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
- NETDRV_W32 (RxMissed, 0);
-
- spin_unlock_irqrestore (&tp->lock, flags);
- }
-
- DPRINTK ("EXIT\n");
- return &tp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
@@ -1909,7 +1877,7 @@ static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));
/* Update the error counts. */
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+ dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
NETDRV_W32 (RxMissed, 0);
spin_unlock_irqrestore (&tp->lock, flags);
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 2b395ee21f75..73dcbb7296da 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -343,6 +343,7 @@ static int tc574_config(struct pcmcia_device *link)
u16 *phys_addr;
char *cardname;
union wn3_config config;
+ DECLARE_MAC_BUF(mac);
phys_addr = (u16 *)dev->dev_addr;
@@ -458,10 +459,10 @@ static int tc574_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
- printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
- dev->name, cardname, dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
+ printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
+ "hw_addr %s.\n",
+ dev->name, cardname, dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
8 << config.u.ram_size, ram_split[config.u.ram_split],
config.u.autoselect ? "autoselect " : "");
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 503f2685fb73..32076ca6a9e1 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -197,7 +197,6 @@ static int tc589_probe(struct pcmcia_device *link)
link->conf.ConfigIndex = 1;
/* The EL3-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &el3_start_xmit;
dev->set_config = &el3_config;
dev->get_stats = &el3_get_stats;
@@ -256,6 +255,7 @@ static int tc589_config(struct pcmcia_device *link)
int last_fn, last_ret, i, j, multi = 0, fifo;
kio_addr_t ioaddr;
char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "3c589_config(0x%p)\n", link);
@@ -331,11 +331,10 @@ static int tc589_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
- printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ",
- dev->name, (multi ? "562" : "589"), dev->base_addr,
- dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, "
+ "hw_addr %s\n",
+ dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n",
(fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
if_names[dev->if_port]);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 50dff1b81d34..a95a2cae6b23 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -232,7 +232,7 @@ static int get_prom(struct pcmcia_device *link)
axnet_reset_8390(dev);
mdelay(10);
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
for (i = 0; i < 6; i += 2) {
@@ -292,6 +292,7 @@ static int axnet_config(struct pcmcia_device *link)
cisparse_t parse;
int i, j, last_ret, last_fn;
u_short buf[64];
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "axnet_config(0x%p)\n", link);
@@ -403,11 +404,11 @@ static int axnet_config(struct pcmcia_device *link)
strcpy(info->node.dev_name, dev->name);
- printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+ printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, "
+ "hw_addr %s\n",
dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
- dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
if (info->phy_id != -1) {
DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j);
} else {
@@ -771,6 +772,7 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202),
+ PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090),
PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
@@ -1728,9 +1730,6 @@ static void axdev_setup(struct net_device *dev)
if (ei_debug > 1)
printk(version_8390);
- SET_MODULE_OWNER(dev);
-
-
ei_local = (struct ei_device *)netdev_priv(dev);
spin_lock_init(&ei_local->page_lock);
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 0d1c7a41c9c6..ea9414c4d900 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -147,7 +147,7 @@ static int com20020_probe(struct pcmcia_device *p_dev)
DEBUG(0, "com20020_attach()\n");
/* Create new network device */
- info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
+ info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
if (!info)
goto fail_alloc_info;
@@ -155,7 +155,6 @@ static int com20020_probe(struct pcmcia_device *p_dev)
if (!dev)
goto fail_alloc_dev;
- memset(info, 0, sizeof(struct com20020_dev_t));
lp = dev->priv;
lp->timeout = timeout;
lp->backplane = backplane;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 85d5f2ca4bb5..62844677c784 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -259,7 +259,6 @@ static int fmvj18x_probe(struct pcmcia_device *link)
link->conf.IntType = INT_MEMORY_AND_IO;
/* The FMVJ18x specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &fjn_start_xmit;
dev->set_config = &fjn_config;
dev->get_stats = &fjn_get_stats;
@@ -347,6 +346,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
cardtype_t cardtype;
char *card_name = "unknown";
u_char *node_id;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "fmvj18x_config(0x%p)\n", link);
@@ -534,11 +534,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
/* print current configuration */
- printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ",
+ printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, "
+ "hw_addr %s\n",
dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
- dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 4ecb8ca5a992..4eafa4f42cff 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -146,9 +146,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
DEBUG(0, "ibmtr_attach()\n");
/* Create new token-ring device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) return -ENOMEM;
- memset(info,0,sizeof(*info));
dev = alloc_trdev(sizeof(struct tok_info));
if (!dev) {
kfree(info);
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 73da611fd536..a355a93b908b 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -474,7 +474,6 @@ static int nmclan_probe(struct pcmcia_device *link)
lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &mace_start_xmit;
dev->set_config = &mace_config;
dev->get_stats = &mace_get_stats;
@@ -659,6 +658,7 @@ static int nmclan_config(struct pcmcia_device *link)
u_char buf[64];
int i, last_ret, last_fn;
kio_addr_t ioaddr;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "nmclan_config(0x%p)\n", link);
@@ -717,10 +717,10 @@ static int nmclan_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
- printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
- dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port,"
+ " hw_addr %s\n",
+ dev->name, dev->base_addr, dev->irq, if_names[dev->if_port],
+ print_mac(mac, dev->dev_addr));
return 0;
cs_failed:
@@ -996,7 +996,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
mace_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr;
int status;
int IntrCnt = MACE_MAX_IR_ITERATIONS;
@@ -1006,6 +1006,8 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
return IRQ_NONE;
}
+ ioaddr = dev->base_addr;
+
if (lp->tx_irq_disabled) {
printk(
(lp->tx_irq_disabled?
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 63de89e93b70..9d45e9696e16 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -38,7 +38,7 @@
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
-#include <../drivers/net/8390.h>
+#include "../8390.h"
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
@@ -207,7 +207,7 @@ static hw_info_t hw_info[] = {
{ /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
};
-#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
+#define NR_INFO ARRAY_SIZE(hw_info)
static hw_info_t default_info = { 0, 0, 0, 0, 0 };
static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
@@ -259,7 +259,6 @@ static int pcnet_probe(struct pcmcia_device *link)
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
- SET_MODULE_OWNER(dev);
dev->open = &pcnet_open;
dev->stop = &pcnet_close;
dev->set_config = &set_config;
@@ -375,7 +374,7 @@ static hw_info_t *get_prom(struct pcmcia_device *link)
pcnet_reset_8390(dev);
mdelay(10);
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
for (i = 0; i < 32; i++)
@@ -522,6 +521,7 @@ static int pcnet_config(struct pcmcia_device *link)
int has_shmem = 0;
u_short buf[64];
hw_info_t *hw_info;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "pcnet_config(0x%p)\n", link);
@@ -671,9 +671,7 @@ static int pcnet_config(struct pcmcia_device *link)
printk (" mem %#5lx,", dev->mem_start);
if (info->flags & HAS_MISC_REG)
printk(" %s xcvr,", if_names[dev->if_port]);
- printk(" hw_addr ");
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr));
return 0;
cs_failed:
@@ -1664,6 +1662,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
+ PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97),
PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 7912dbd14251..58d716fd17cf 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -336,7 +336,6 @@ static int smc91c92_probe(struct pcmcia_device *link)
link->conf.IntType = INT_MEMORY_AND_IO;
/* The SMC91c92-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &smc_start_xmit;
dev->get_stats = &smc_get_stats;
dev->set_config = &s9k_config;
@@ -963,6 +962,7 @@ static int smc91c92_config(struct pcmcia_device *link)
int i, j, rev;
kio_addr_t ioaddr;
u_long mir;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "smc91c92_config(0x%p)\n", link);
@@ -1075,10 +1075,9 @@ static int smc91c92_config(struct pcmcia_device *link)
strcpy(smc->node.dev_name, dev->name);
printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
- "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
- dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ "hw_addr %s\n",
+ dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
if (rev > 0) {
if (mir & 0x3ff)
@@ -1368,6 +1367,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
kio_addr_t ioaddr = dev->base_addr;
u_short num_pages;
short time_out, ir;
+ unsigned long flags;
netif_stop_queue(dev);
@@ -1395,6 +1395,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* A packet is now waiting. */
smc->packets_waiting++;
+ spin_lock_irqsave(&smc->lock, flags);
SMC_SELECT_BANK(2); /* Paranoia, we should always be in window 2 */
/* need MC_RESET to keep the memory consistent. errata? */
@@ -1411,6 +1412,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Acknowledge the interrupt, send the packet. */
outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
smc_hardware_send_packet(dev); /* Send the packet now.. */
+ spin_unlock_irqrestore(&smc->lock, flags);
return 0;
}
}
@@ -1418,6 +1420,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Otherwise defer until the Tx-space-allocated interrupt. */
DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
+ spin_unlock_irqrestore(&smc->lock, flags);
return 0;
}
@@ -1523,6 +1526,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
irq, ioaddr);
+ spin_lock(&smc->lock);
smc->watchdog = 0;
saved_bank = inw(ioaddr + BANK_SELECT);
if ((saved_bank & 0xff00) != 0x3300) {
@@ -1620,6 +1624,7 @@ irq_done:
readb(smc->base+MEGAHERTZ_ISR);
}
#endif
+ spin_unlock(&smc->lock);
return IRQ_RETVAL(handled);
}
@@ -1902,6 +1907,9 @@ static void media_check(u_long arg)
kio_addr_t ioaddr = dev->base_addr;
u_short i, media, saved_bank;
u_short link;
+ unsigned long flags;
+
+ spin_lock_irqsave(&smc->lock, flags);
saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1934,6 +1942,7 @@ static void media_check(u_long arg)
smc->media.expires = jiffies + HZ/100;
add_timer(&smc->media);
SMC_SELECT_BANK(saved_bank);
+ spin_unlock_irqrestore(&smc->lock, flags);
return;
}
@@ -2007,6 +2016,7 @@ reschedule:
smc->media.expires = jiffies + HZ;
add_timer(&smc->media);
SMC_SELECT_BANK(saved_bank);
+ spin_unlock_irqrestore(&smc->lock, flags);
}
static int smc_link_ok(struct net_device *dev)
@@ -2094,14 +2104,14 @@ static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
u16 saved_bank = inw(ioaddr + BANK_SELECT);
int ret;
- SMC_SELECT_BANK(3);
spin_lock_irq(&smc->lock);
+ SMC_SELECT_BANK(3);
if (smc->cfg & CFG_MII_SELECT)
ret = mii_ethtool_gset(&smc->mii_if, ecmd);
else
ret = smc_netdev_get_ecmd(dev, ecmd);
- spin_unlock_irq(&smc->lock);
SMC_SELECT_BANK(saved_bank);
+ spin_unlock_irq(&smc->lock);
return ret;
}
@@ -2112,14 +2122,14 @@ static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
u16 saved_bank = inw(ioaddr + BANK_SELECT);
int ret;
- SMC_SELECT_BANK(3);
spin_lock_irq(&smc->lock);
+ SMC_SELECT_BANK(3);
if (smc->cfg & CFG_MII_SELECT)
ret = mii_ethtool_sset(&smc->mii_if, ecmd);
else
ret = smc_netdev_set_ecmd(dev, ecmd);
- spin_unlock_irq(&smc->lock);
SMC_SELECT_BANK(saved_bank);
+ spin_unlock_irq(&smc->lock);
return ret;
}
@@ -2130,11 +2140,11 @@ static u32 smc_get_link(struct net_device *dev)
u16 saved_bank = inw(ioaddr + BANK_SELECT);
u32 ret;
- SMC_SELECT_BANK(3);
spin_lock_irq(&smc->lock);
+ SMC_SELECT_BANK(3);
ret = smc_link_ok(dev);
- spin_unlock_irq(&smc->lock);
SMC_SELECT_BANK(saved_bank);
+ spin_unlock_irq(&smc->lock);
return ret;
}
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 258d6f396186..c3b69602e275 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -580,7 +580,6 @@ xirc2ps_probe(struct pcmcia_device *link)
link->irq.Instance = dev;
/* Fill in card specific entries */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &do_start_xmit;
dev->set_config = &do_config;
dev->get_stats = &do_get_stats;
@@ -732,6 +731,7 @@ xirc2ps_config(struct pcmcia_device * link)
u_char buf[64];
cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ DECLARE_MAC_BUF(mac);
local->dingo_ccr = NULL;
@@ -1033,11 +1033,9 @@ xirc2ps_config(struct pcmcia_device * link)
strcpy(local->node.dev_name, dev->name);
/* give some infos about the hardware */
- printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr",
- dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq);
- for (i = 0; i < 6; i++)
- printk("%c%02X", i?':':' ', dev->dev_addr[i]);
- printk("\n");
+ printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n",
+ dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq,
+ print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 465485a3fbc6..5f994b5beda1 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -23,11 +23,11 @@
#define DRV_NAME "pcnet32"
#ifdef CONFIG_PCNET32_NAPI
-#define DRV_VERSION "1.33-NAPI"
+#define DRV_VERSION "1.34-NAPI"
#else
-#define DRV_VERSION "1.33"
+#define DRV_VERSION "1.34"
#endif
-#define DRV_RELDATE "27.Jun.2006"
+#define DRV_RELDATE "14.Aug.2007"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -210,31 +210,31 @@ static int homepna[MAX_UNITS];
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
- u32 base;
- s16 buf_length; /* two`s complement of length */
- s16 status;
- u32 msg_length;
- u32 reserved;
+ __le32 base;
+ __le16 buf_length; /* two`s complement of length */
+ __le16 status;
+ __le32 msg_length;
+ __le32 reserved;
};
struct pcnet32_tx_head {
- u32 base;
- s16 length; /* two`s complement of length */
- s16 status;
- u32 misc;
- u32 reserved;
+ __le32 base;
+ __le16 length; /* two`s complement of length */
+ __le16 status;
+ __le32 misc;
+ __le32 reserved;
};
/* The PCNET32 32-Bit initialization block, described in databook. */
struct pcnet32_init_block {
- u16 mode;
- u16 tlen_rlen;
+ __le16 mode;
+ __le16 tlen_rlen;
u8 phys_addr[6];
- u16 reserved;
- u32 filter[2];
+ __le16 reserved;
+ __le32 filter[2];
/* Receive and transmit ring base, along with extra bits. */
- u32 rx_ring;
- u32 tx_ring;
+ __le32 rx_ring;
+ __le32 tx_ring;
};
/* PCnet32 access functions */
@@ -280,6 +280,8 @@ struct pcnet32_private {
unsigned int dirty_rx, /* ring entries to be freed. */
dirty_tx;
+ struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
char tx_full;
char phycount; /* number of phys found */
@@ -440,15 +442,21 @@ static struct pcnet32_access pcnet32_dwio = {
static void pcnet32_netif_stop(struct net_device *dev)
{
+ struct pcnet32_private *lp = netdev_priv(dev);
dev->trans_start = jiffies;
- netif_poll_disable(dev);
+#ifdef CONFIG_PCNET32_NAPI
+ napi_disable(&lp->napi);
+#endif
netif_tx_disable(dev);
}
static void pcnet32_netif_start(struct net_device *dev)
{
+ struct pcnet32_private *lp = netdev_priv(dev);
netif_wake_queue(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_PCNET32_NAPI
+ napi_enable(&lp->napi);
+#endif
}
/*
@@ -602,9 +610,9 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
new_dma_addr_list[new] =
pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
- new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
- new_rx_ring[new].status = le16_to_cpu(0x8000);
+ new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = cpu_to_le16(0x8000);
}
/* and free any unneeded buffers */
for (; new < lp->rx_ring_size; new++) {
@@ -816,7 +824,7 @@ static int pcnet32_set_ringparam(struct net_device *dev,
if ((1 << i) != lp->rx_ring_size)
pcnet32_realloc_rx_ring(dev, lp, i);
- dev->weight = lp->rx_ring_size / 2;
+ lp->napi.weight = lp->rx_ring_size / 2;
if (netif_running(dev)) {
pcnet32_netif_start(dev);
@@ -839,9 +847,14 @@ static void pcnet32_get_strings(struct net_device *dev, u32 stringset,
memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test));
}
-static int pcnet32_self_test_count(struct net_device *dev)
+static int pcnet32_get_sset_count(struct net_device *dev, int sset)
{
- return PCNET32_TEST_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return PCNET32_TEST_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void pcnet32_ethtool_test(struct net_device *dev,
@@ -875,7 +888,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
int x, i; /* counters */
int numbuffs = 4; /* number of TX/RX buffers and descs */
u16 status = 0x8300; /* TX ring status */
- u16 teststatus; /* test of ring status */
+ __le16 teststatus; /* test of ring status */
int rc; /* return code */
int size; /* size of packets */
unsigned char *packet; /* source packet data */
@@ -922,7 +935,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
packet = skb->data;
skb_put(skb, size); /* create space for data */
lp->tx_skbuff[x] = skb;
- lp->tx_ring[x].length = le16_to_cpu(-skb->len);
+ lp->tx_ring[x].length = cpu_to_le16(-skb->len);
lp->tx_ring[x].misc = 0;
/* put DA and SA into the skb */
@@ -942,10 +955,9 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
lp->tx_dma_addr[x] =
pci_map_single(lp->pci_dev, skb->data, skb->len,
PCI_DMA_TODEVICE);
- lp->tx_ring[x].base =
- (u32) le32_to_cpu(lp->tx_dma_addr[x]);
+ lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
wmb(); /* Make sure owner changes after all others are visible */
- lp->tx_ring[x].status = le16_to_cpu(status);
+ lp->tx_ring[x].status = cpu_to_le16(status);
}
}
@@ -956,7 +968,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
x = a->read_csr(ioaddr, CSR15) & 0xfffc;
lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
- teststatus = le16_to_cpu(0x8000);
+ teststatus = cpu_to_le16(0x8000);
lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
@@ -1086,6 +1098,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
mod_timer(&lp->blink_timer, jiffies);
set_current_state(TASK_INTERRUPTIBLE);
+ /* AV: the limit here makes no sense whatsoever */
if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)))
data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ);
@@ -1211,7 +1224,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
newskb->data,
PKT_BUF_SZ - 2,
PCI_DMA_FROMDEVICE);
- rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
+ rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]);
rx_in_place = 1;
} else
skb = NULL;
@@ -1255,7 +1268,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
return;
}
-static int pcnet32_rx(struct net_device *dev, int quota)
+static int pcnet32_rx(struct net_device *dev, int budget)
{
struct pcnet32_private *lp = netdev_priv(dev);
int entry = lp->cur_rx & lp->rx_mod_mask;
@@ -1263,16 +1276,16 @@ static int pcnet32_rx(struct net_device *dev, int quota)
int npackets = 0;
/* If we own the next entry, it's a new packet. Send it up. */
- while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
+ while (npackets < budget && (short)le16_to_cpu(rxp->status) >= 0) {
pcnet32_rx_entry(dev, lp, rxp, entry);
npackets += 1;
/*
* The docs say that the buffer length isn't touched, but Andrew
* Boyd of QNX reports that some revs of the 79C965 clear it.
*/
- rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
wmb(); /* Make sure owner changes after others are visible */
- rxp->status = le16_to_cpu(0x8000);
+ rxp->status = cpu_to_le16(0x8000);
entry = (++lp->cur_rx) & lp->rx_mod_mask;
rxp = &lp->rx_ring[entry];
}
@@ -1379,15 +1392,16 @@ static int pcnet32_tx(struct net_device *dev)
}
#ifdef CONFIG_PCNET32_NAPI
-static int pcnet32_poll(struct net_device *dev, int *budget)
+static int pcnet32_poll(struct napi_struct *napi, int budget)
{
- struct pcnet32_private *lp = netdev_priv(dev);
- int quota = min(dev->quota, *budget);
+ struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi);
+ struct net_device *dev = lp->dev;
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
+ int work_done;
u16 val;
- quota = pcnet32_rx(dev, quota);
+ work_done = pcnet32_rx(dev, budget);
spin_lock_irqsave(&lp->lock, flags);
if (pcnet32_tx(dev)) {
@@ -1399,28 +1413,22 @@ static int pcnet32_poll(struct net_device *dev, int *budget)
}
spin_unlock_irqrestore(&lp->lock, flags);
- *budget -= quota;
- dev->quota -= quota;
-
- if (dev->quota == 0) {
- return 1;
- }
-
- netif_rx_complete(dev);
-
- spin_lock_irqsave(&lp->lock, flags);
+ if (work_done < budget) {
+ spin_lock_irqsave(&lp->lock, flags);
- /* clear interrupt masks */
- val = lp->a.read_csr(ioaddr, CSR3);
- val &= 0x00ff;
- lp->a.write_csr(ioaddr, CSR3, val);
+ __netif_rx_complete(dev, napi);
- /* Set interrupt enable. */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
- mmiowb();
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* clear interrupt masks */
+ val = lp->a.read_csr(ioaddr, CSR3);
+ val &= 0x00ff;
+ lp->a.write_csr(ioaddr, CSR3, val);
- return 0;
+ /* Set interrupt enable. */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+ mmiowb();
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+ return work_done;
}
#endif
@@ -1506,16 +1514,12 @@ static const struct ethtool_ops pcnet32_ethtool_ops = {
.get_link = pcnet32_get_link,
.get_ringparam = pcnet32_get_ringparam,
.set_ringparam = pcnet32_set_ringparam,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.get_strings = pcnet32_get_strings,
- .self_test_count = pcnet32_self_test_count,
.self_test = pcnet32_ethtool_test,
.phys_id = pcnet32_phys_id,
.get_regs_len = pcnet32_get_regs_len,
.get_regs = pcnet32_get_regs,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_sset_count = pcnet32_get_sset_count,
};
/* only probes for non-PCI devices, the rest are handled by
@@ -1816,9 +1820,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
lp->pci_dev = pdev;
+ lp->dev = dev;
+
spin_lock_init(&lp->lock);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
lp->name = chipname;
lp->shared_irq = shared;
@@ -1844,6 +1849,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
lp->mii_if.mdio_read = mdio_read;
lp->mii_if.mdio_write = mdio_write;
+#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]))
lp->options |= PCNET32_PORT_FD;
@@ -1866,15 +1875,15 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
&& dev->dev_addr[2] == 0x75)
lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
- lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
+ lp->init_block->mode = cpu_to_le16(0x0003); /* Disable Rx and Tx. */
lp->init_block->tlen_rlen =
- le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
+ cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
lp->init_block->phys_addr[i] = dev->dev_addr[i];
lp->init_block->filter[0] = 0x00000000;
lp->init_block->filter[1] = 0x00000000;
- lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr);
/* switch pcnet32 to 32bit mode */
a->write_bcr(ioaddr, 20, 2);
@@ -1954,10 +1963,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
- dev->weight = lp->rx_ring_size / 2;
-#ifdef CONFIG_PCNET32_NAPI
- dev->poll = pcnet32_poll;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -2269,7 +2274,7 @@ static int pcnet32_open(struct net_device *dev)
#endif
lp->init_block->mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
pcnet32_load_multicast(dev);
if (pcnet32_init_ring(dev)) {
@@ -2277,6 +2282,10 @@ 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));
lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
@@ -2392,10 +2401,10 @@ static int pcnet32_init_ring(struct net_device *dev)
lp->rx_dma_addr[i] =
pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- lp->rx_ring[i].base = (u32) le32_to_cpu(lp->rx_dma_addr[i]);
- lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]);
+ lp->rx_ring[i].buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
wmb(); /* Make sure owner changes after all others are visible */
- lp->rx_ring[i].status = le16_to_cpu(0x8000);
+ lp->rx_ring[i].status = cpu_to_le16(0x8000);
}
/* The Tx buffer address is filled in as needed, but we do need to clear
* the upper ownership bit. */
@@ -2407,11 +2416,11 @@ static int pcnet32_init_ring(struct net_device *dev)
}
lp->init_block->tlen_rlen =
- le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
+ cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
lp->init_block->phys_addr[i] = dev->dev_addr[i];
- lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr);
wmb(); /* Make sure all changes are visible */
return 0;
}
@@ -2520,16 +2529,16 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Caution: the write order is important here, set the status
* with the "ownership" bits last. */
- lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+ lp->tx_ring[entry].length = cpu_to_le16(-skb->len);
lp->tx_ring[entry].misc = 0x00000000;
lp->tx_skbuff[entry] = skb;
lp->tx_dma_addr[entry] =
pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
- lp->tx_ring[entry].base = (u32) le32_to_cpu(lp->tx_dma_addr[entry]);
+ lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
wmb(); /* Make sure owner changes after all others are visible */
- lp->tx_ring[entry].status = le16_to_cpu(status);
+ lp->tx_ring[entry].status = cpu_to_le16(status);
lp->cur_tx++;
lp->stats.tx_bytes += skb->len;
@@ -2600,18 +2609,18 @@ pcnet32_interrupt(int irq, void *dev_id)
/* unlike for the lance, there is no restart needed */
}
#ifdef CONFIG_PCNET32_NAPI
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &lp->napi)) {
u16 val;
/* set interrupt masks */
val = lp->a.read_csr(ioaddr, CSR3);
val |= 0x5f00;
lp->a.write_csr(ioaddr, CSR3, val);
mmiowb();
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &lp->napi);
break;
}
#else
- pcnet32_rx(dev, dev->weight);
+ pcnet32_rx(dev, lp->napi.weight);
if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
@@ -2646,6 +2655,9 @@ 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);
@@ -2697,7 +2709,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
{
struct pcnet32_private *lp = netdev_priv(dev);
volatile struct pcnet32_init_block *ib = lp->init_block;
- volatile u16 *mcast_table = (u16 *) & ib->filter;
+ volatile __le16 *mcast_table = (__le16 *)ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
unsigned long ioaddr = dev->base_addr;
char *addrs;
@@ -2706,8 +2718,8 @@ static void pcnet32_load_multicast(struct net_device *dev)
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI) {
- ib->filter[0] = 0xffffffff;
- ib->filter[1] = 0xffffffff;
+ ib->filter[0] = cpu_to_le32(~0U);
+ ib->filter[1] = cpu_to_le32(~0U);
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
@@ -2729,9 +2741,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
crc = ether_crc_le(6, addrs);
crc = crc >> 26;
- mcast_table[crc >> 4] =
- le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
- (1 << (crc & 0xf)));
+ mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
}
for (i = 0; i < 4; i++)
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
@@ -2757,12 +2767,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
dev->name);
lp->init_block->mode =
- le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
+ cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block->mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
@@ -2944,6 +2954,33 @@ static void pcnet32_watchdog(struct net_device *dev)
mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
}
+static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (netif_running(dev)) {
+ netif_device_detach(dev);
+ pcnet32_close(dev);
+ }
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int pcnet32_pm_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (netif_running(dev)) {
+ pcnet32_open(dev);
+ netif_device_attach(dev);
+ }
+ return 0;
+}
+
static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -2967,6 +3004,8 @@ static struct pci_driver pcnet32_driver = {
.probe = pcnet32_probe_pci,
.remove = __devexit_p(pcnet32_remove_one),
.id_table = pcnet32_pci_tbl,
+ .suspend = pcnet32_pm_suspend,
+ .resume = pcnet32_pm_resume,
};
/* An additional parameter that may be passed in... */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index dd09011c7ee5..54b2ba996640 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -76,4 +76,27 @@ config FIXED_MII_100_FDX
bool "Emulation for 100M Fdx fixed PHY behavior"
depends on FIXED_PHY
+config FIXED_MII_1000_FDX
+ bool "Emulation for 1000M Fdx fixed PHY behavior"
+ depends on FIXED_PHY
+
+config FIXED_MII_AMNT
+ int "Number of emulated PHYs to allocate "
+ depends on FIXED_PHY
+ default "1"
+ ---help---
+ Sometimes it is required to have several independent emulated
+ PHYs on the bus (in case of multi-eth but phy-less HW for instance).
+ This control will have specified number allocated for each fixed
+ PHY type enabled.
+
+config MDIO_BITBANG
+ tristate "Support for bitbanged MDIO buses"
+ help
+ This module implements the MDIO bus protocol in software,
+ for use by low level drivers that export the ability to
+ drive the relevant pins.
+
+ If in doubt, say N.
+
endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 8885650647ff..3d6cc7b67a80 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
+obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index bb966911a137..56191822fa26 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -30,53 +30,31 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
-#define MII_REGS_NUM 7
-
-/*
- The idea is to emulate normal phy behavior by responding with
- pre-defined values to mii BMCR read, so that read_status hook could
- take all the needed info.
-*/
-
-struct fixed_phy_status {
- u8 link;
- u16 speed;
- u8 duplex;
-};
-
-/*-----------------------------------------------------------------------------
- * Private information hoder for mii_bus
- *-----------------------------------------------------------------------------*/
-struct fixed_info {
- u16 *regs;
- u8 regs_num;
- struct fixed_phy_status phy_status;
- struct phy_device *phydev; /* pointer to the container */
- /* link & speed cb */
- int(*link_update)(struct net_device*, struct fixed_phy_status*);
-
-};
+/* we need to track the allocated pointers in order to free them on exit */
+static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];
/*-----------------------------------------------------------------------------
* If something weird is required to be done with link/speed,
* network driver is able to assign a function to implement this.
* May be useful for PHY's that need to be software-driven.
*-----------------------------------------------------------------------------*/
-int fixed_mdio_set_link_update(struct phy_device* phydev,
- int(*link_update)(struct net_device*, struct fixed_phy_status*))
+int fixed_mdio_set_link_update(struct phy_device *phydev,
+ int (*link_update) (struct net_device *,
+ struct fixed_phy_status *))
{
struct fixed_info *fixed;
- if(link_update == NULL)
+ if (link_update == NULL)
return -EINVAL;
- if(phydev) {
- if(phydev->bus) {
+ if (phydev) {
+ if (phydev->bus) {
fixed = phydev->bus->priv;
fixed->link_update = link_update;
return 0;
@@ -84,54 +62,64 @@ int fixed_mdio_set_link_update(struct phy_device* phydev,
}
return -EINVAL;
}
+
EXPORT_SYMBOL(fixed_mdio_set_link_update);
+struct fixed_info *fixed_mdio_get_phydev (int phydev_ind)
+{
+ if (phydev_ind >= MAX_PHY_AMNT)
+ return NULL;
+ return fixed_phy_ptrs[phydev_ind];
+}
+
+EXPORT_SYMBOL(fixed_mdio_get_phydev);
+
/*-----------------------------------------------------------------------------
* This is used for updating internal mii regs from the status
*-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
+#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
static int fixed_mdio_update_regs(struct fixed_info *fixed)
{
u16 *regs = fixed->regs;
u16 bmsr = 0;
u16 bmcr = 0;
- if(!regs) {
+ if (!regs) {
printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
return -EINVAL;
}
- if(fixed->phy_status.link)
+ if (fixed->phy_status.link)
bmsr |= BMSR_LSTATUS;
- if(fixed->phy_status.duplex) {
+ if (fixed->phy_status.duplex) {
bmcr |= BMCR_FULLDPLX;
- switch ( fixed->phy_status.speed ) {
+ switch (fixed->phy_status.speed) {
case 100:
bmsr |= BMSR_100FULL;
bmcr |= BMCR_SPEED100;
- break;
+ break;
case 10:
bmsr |= BMSR_10FULL;
- break;
+ break;
}
} else {
- switch ( fixed->phy_status.speed ) {
+ switch (fixed->phy_status.speed) {
case 100:
bmsr |= BMSR_100HALF;
bmcr |= BMCR_SPEED100;
- break;
+ break;
case 10:
bmsr |= BMSR_100HALF;
- break;
+ break;
}
}
- regs[MII_BMCR] = bmcr;
- regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/
+ regs[MII_BMCR] = bmcr;
+ regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */
return 0;
}
@@ -141,29 +129,30 @@ static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
struct fixed_info *fixed = bus->priv;
/* if user has registered link update callback, use it */
- if(fixed->phydev)
- if(fixed->phydev->attached_dev) {
- if(fixed->link_update) {
+ if (fixed->phydev)
+ if (fixed->phydev->attached_dev) {
+ if (fixed->link_update) {
fixed->link_update(fixed->phydev->attached_dev,
- &fixed->phy_status);
+ &fixed->phy_status);
fixed_mdio_update_regs(fixed);
}
- }
+ }
if ((unsigned int)location >= fixed->regs_num)
return -1;
return fixed->regs[location];
}
-static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,
+ u16 val)
{
- /* do nothing for now*/
+ /* do nothing for now */
return 0;
}
static int fixed_mii_reset(struct mii_bus *bus)
{
- /*nothing here - no way/need to reset it*/
+ /*nothing here - no way/need to reset it */
return 0;
}
#endif
@@ -171,8 +160,8 @@ static int fixed_mii_reset(struct mii_bus *bus)
static int fixed_config_aneg(struct phy_device *phydev)
{
/* :TODO:03/13/2006 09:45:37 PM::
- The full autoneg funcionality can be emulated,
- but no need to have anything here for now
+ The full autoneg funcionality can be emulated,
+ but no need to have anything here for now
*/
return 0;
}
@@ -182,59 +171,79 @@ static int fixed_config_aneg(struct phy_device *phydev)
* match will never return true...
*-----------------------------------------------------------------------------*/
static struct phy_driver fixed_mdio_driver = {
- .name = "Fixed PHY",
- .features = PHY_BASIC_FEATURES,
- .config_aneg = fixed_config_aneg,
- .read_status = genphy_read_status,
- .driver = { .owner = THIS_MODULE,},
+ .name = "Fixed PHY",
+#ifdef CONFIG_FIXED_MII_1000_FDX
+ .features = PHY_GBIT_FEATURES,
+#else
+ .features = PHY_BASIC_FEATURES,
+#endif
+ .config_aneg = fixed_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE, },
};
+static void fixed_mdio_release(struct device *dev)
+{
+ struct phy_device *phydev = container_of(dev, struct phy_device, dev);
+ struct mii_bus *bus = phydev->bus;
+ struct fixed_info *fixed = bus->priv;
+
+ kfree(phydev);
+ kfree(bus->dev);
+ kfree(bus);
+ kfree(fixed->regs);
+ kfree(fixed);
+}
+
/*-----------------------------------------------------------------------------
* This func is used to create all the necessary stuff, bind
* the fixed phy driver and register all it on the mdio_bus_type.
- * speed is either 10 or 100, duplex is boolean.
+ * speed is either 10 or 100 or 1000, duplex is boolean.
* number is used to create multiple fixed PHYs, so that several devices can
* utilize them simultaneously.
+ *
+ * The device on mdio bus will look like [bus_id]:[phy_id],
+ * bus_id = number
+ * phy_id = speed+duplex.
*-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
-static int fixed_mdio_register_device(int number, int speed, int duplex)
+#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
+struct fixed_info *fixed_mdio_register_device(
+ int bus_id, int speed, int duplex, u8 phy_id)
{
struct mii_bus *new_bus;
struct fixed_info *fixed;
struct phy_device *phydev;
- int err = 0;
+ int err;
- struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
- if (NULL == dev)
- return -ENOMEM;
+ if (dev == NULL)
+ goto err_dev_alloc;
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
- if (NULL == new_bus) {
- kfree(dev);
- return -ENOMEM;
- }
+ if (new_bus == NULL)
+ goto err_bus_alloc;
+
fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
- if (NULL == fixed) {
- kfree(dev);
- kfree(new_bus);
- return -ENOMEM;
- }
+ if (fixed == NULL)
+ goto err_fixed_alloc;
+
+ fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);
+ if (NULL == fixed->regs)
+ goto err_fixed_regs_alloc;
- fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL);
fixed->regs_num = MII_REGS_NUM;
fixed->phy_status.speed = speed;
fixed->phy_status.duplex = duplex;
fixed->phy_status.link = 1;
- new_bus->name = "Fixed MII Bus",
- new_bus->read = &fixed_mii_read,
- new_bus->write = &fixed_mii_write,
- new_bus->reset = &fixed_mii_reset,
-
- /*set up workspace*/
+ new_bus->name = "Fixed MII Bus";
+ new_bus->read = &fixed_mii_read;
+ new_bus->write = &fixed_mii_write;
+ new_bus->reset = &fixed_mii_reset;
+ /*set up workspace */
fixed_mdio_update_regs(fixed);
new_bus->priv = fixed;
@@ -243,119 +252,110 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
/* create phy_device and register it on the mdio bus */
phydev = phy_device_create(new_bus, 0, 0);
+ if (phydev == NULL)
+ goto err_phy_dev_create;
/*
- Put the phydev pointer into the fixed pack so that bus read/write code could
- be able to access for instance attached netdev. Well it doesn't have to do
- so, only in case of utilizing user-specified link-update...
+ * Put the phydev pointer into the fixed pack so that bus read/write
+ * code could be able to access for instance attached netdev. Well it
+ * doesn't have to do so, only in case of utilizing user-specified
+ * link-update...
*/
- fixed->phydev = phydev;
- if(NULL == phydev) {
- err = -ENOMEM;
- goto device_create_fail;
- }
+ fixed->phydev = phydev;
+ phydev->speed = speed;
+ phydev->duplex = duplex;
phydev->irq = PHY_IGNORE_INTERRUPT;
phydev->dev.bus = &mdio_bus_type;
- if(number)
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- "fixed_%d@%d:%d", number, speed, duplex);
- else
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- "fixed@%d:%d", speed, duplex);
- phydev->bus = new_bus;
+ snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
+ PHY_ID_FMT, bus_id, phy_id);
- err = device_register(&phydev->dev);
- if(err) {
- printk(KERN_ERR "Phy %s failed to register\n",
- phydev->dev.bus_id);
- goto bus_register_fail;
- }
+ phydev->bus = new_bus;
- /*
- the mdio bus has phy_id match... In order not to do it
- artificially, we are binding the driver here by hand;
- it will be the same for all the fixed phys anyway.
- */
phydev->dev.driver = &fixed_mdio_driver.driver;
-
+ phydev->dev.release = fixed_mdio_release;
err = phydev->dev.driver->probe(&phydev->dev);
- if(err < 0) {
- printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
- goto probe_fail;
+ if (err < 0) {
+ printk(KERN_ERR "Phy %s: problems with fixed driver\n",
+ phydev->dev.bus_id);
+ goto err_out;
}
+ err = device_register(&phydev->dev);
+ if (err) {
+ printk(KERN_ERR "Phy %s failed to register\n",
+ phydev->dev.bus_id);
+ goto err_out;
+ }
+ //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX
+ return fixed;
- err = device_bind_driver(&phydev->dev);
- if (err)
- goto probe_fail;
-
- return 0;
-
-probe_fail:
- device_unregister(&phydev->dev);
-bus_register_fail:
+err_out:
kfree(phydev);
-device_create_fail:
- kfree(dev);
- kfree(new_bus);
+err_phy_dev_create:
+ kfree(fixed->regs);
+err_fixed_regs_alloc:
kfree(fixed);
+err_fixed_alloc:
+ kfree(new_bus);
+err_bus_alloc:
+ kfree(dev);
+err_dev_alloc:
+
+ return NULL;
- return err;
}
#endif
-
MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
MODULE_AUTHOR("Vitaly Bordug");
MODULE_LICENSE("GPL");
static int __init fixed_init(void)
{
-#if 0
- int ret;
- int duplex = 0;
-#endif
-
- /* register on the bus... Not expected to be matched with anything there... */
+ int cnt = 0;
+ int i;
+/* register on the bus... Not expected to be matched
+ * with anything there...
+ *
+ */
phy_driver_register(&fixed_mdio_driver);
- /* So let the fun begin...
- We will create several mdio devices here, and will bound the upper
- driver to them.
-
- Then the external software can lookup the phy bus by searching
- fixed@speed:duplex, e.g. fixed@100:1, to be connected to the
- virtual 100M Fdx phy.
-
- In case several virtual PHYs required, the bus_id will be in form
- fixed_<num>@<speed>:<duplex>, which make it able even to define
- driver-specific link control callback, if for instance PHY is completely
- SW-driven.
-
- */
-
-#ifdef CONFIG_FIXED_MII_DUPLEX
-#if 0
- duplex = 1;
-#endif
+/* We will create several mdio devices here, and will bound the upper
+ * driver to them.
+ *
+ * Then the external software can lookup the phy bus by searching
+ * for 0:101, to be connected to the virtual 100M Fdx phy.
+ *
+ * In case several virtual PHYs required, the bus_id will be in form
+ * [num]:[duplex]+[speed], which make it able even to define
+ * driver-specific link control callback, if for instance PHY is
+ * completely SW-driven.
+ */
+ for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {
+#ifdef CONFIG_FIXED_MII_1000_FDX
+ fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);
#endif
-
#ifdef CONFIG_FIXED_MII_100_FDX
- fixed_mdio_register_device(0, 100, 1);
+ fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);
#endif
-
#ifdef CONFIG_FIXED_MII_10_FDX
- fixed_mdio_register_device(0, 10, 1);
+ fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);
#endif
+ }
+
return 0;
}
static void __exit fixed_exit(void)
{
+ int i;
+
phy_driver_unregister(&fixed_mdio_driver);
- /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */
+ for (i=0; i < MAX_PHY_AMNT; i++)
+ if ( fixed_phy_ptrs[i] )
+ device_unregister(&fixed_phy_ptrs[i]->phydev->dev);
}
module_init(fixed_init);
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
new file mode 100644
index 000000000000..8cd243d92af3
--- /dev/null
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -0,0 +1,187 @@
+/*
+ * Bitbanged MDIO support.
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ * Copyright (c) 2007 Freescale Semiconductor
+ *
+ * Based on CPM2 MDIO code which is:
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ * by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#define MDIO_READ 1
+#define MDIO_WRITE 0
+
+#define MDIO_SETUP_TIME 10
+#define MDIO_HOLD_TIME 10
+
+/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY
+ * is done twice per period.
+ */
+#define MDIO_DELAY 250
+
+/* The PHY may take up to 300 ns to produce data, plus some margin
+ * for error.
+ */
+#define MDIO_READ_DELAY 350
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val)
+{
+ const struct mdiobb_ops *ops = ctrl->ops;
+
+ ops->set_mdio_data(ctrl, val);
+ ndelay(MDIO_DELAY);
+ ops->set_mdc(ctrl, 1);
+ ndelay(MDIO_DELAY);
+ ops->set_mdc(ctrl, 0);
+}
+
+/* MDIO must already be configured as input. */
+static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl)
+{
+ const struct mdiobb_ops *ops = ctrl->ops;
+
+ ndelay(MDIO_DELAY);
+ ops->set_mdc(ctrl, 1);
+ ndelay(MDIO_READ_DELAY);
+ ops->set_mdc(ctrl, 0);
+
+ return ops->get_mdio_data(ctrl);
+}
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits)
+{
+ int i;
+
+ for (i = bits - 1; i >= 0; i--)
+ mdiobb_send_bit(ctrl, (val >> i) & 1);
+}
+
+/* MDIO must already be configured as input. */
+static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
+{
+ int i;
+ u16 ret = 0;
+
+ for (i = bits - 1; i >= 0; i--) {
+ ret <<= 1;
+ ret |= mdiobb_get_bit(ctrl);
+ }
+
+ return ret;
+}
+
+/* Utility to send the preamble, address, and
+ * register (common to read and write).
+ */
+static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg)
+{
+ const struct mdiobb_ops *ops = ctrl->ops;
+ int i;
+
+ ops->set_mdio_dir(ctrl, 1);
+
+ /*
+ * Send a 32 bit preamble ('1's) with an extra '1' bit for good
+ * measure. The IEEE spec says this is a PHY optional
+ * requirement. The AMD 79C874 requires one after power up and
+ * one after a MII communications error. This means that we are
+ * doing more preambles than we need, but it is safer and will be
+ * much more robust.
+ */
+
+ for (i = 0; i < 32; i++)
+ mdiobb_send_bit(ctrl, 1);
+
+ /* send the start bit (01) and the read opcode (10) or write (10) */
+ mdiobb_send_bit(ctrl, 0);
+ mdiobb_send_bit(ctrl, 1);
+ mdiobb_send_bit(ctrl, read);
+ mdiobb_send_bit(ctrl, !read);
+
+ mdiobb_send_num(ctrl, phy, 5);
+ mdiobb_send_num(ctrl, reg, 5);
+}
+
+
+static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct mdiobb_ctrl *ctrl = bus->priv;
+ int ret, i;
+
+ mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+ ctrl->ops->set_mdio_dir(ctrl, 0);
+
+ /* check the turnaround bit: the PHY should be driving it to zero */
+ if (mdiobb_get_bit(ctrl) != 0) {
+ /* PHY didn't drive TA low -- flush any bits it
+ * may be trying to send.
+ */
+ for (i = 0; i < 32; i++)
+ mdiobb_get_bit(ctrl);
+
+ return 0xffff;
+ }
+
+ ret = mdiobb_get_num(ctrl, 16);
+ mdiobb_get_bit(ctrl);
+ return ret;
+}
+
+static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+ struct mdiobb_ctrl *ctrl = bus->priv;
+
+ mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+
+ /* send the turnaround (10) */
+ mdiobb_send_bit(ctrl, 1);
+ mdiobb_send_bit(ctrl, 0);
+
+ mdiobb_send_num(ctrl, val, 16);
+
+ ctrl->ops->set_mdio_dir(ctrl, 0);
+ mdiobb_get_bit(ctrl);
+ return 0;
+}
+
+struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
+{
+ struct mii_bus *bus;
+
+ bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ __module_get(ctrl->ops->owner);
+
+ bus->read = mdiobb_read;
+ bus->write = mdiobb_write;
+ bus->priv = ctrl;
+
+ return bus;
+}
+
+void free_mdio_bitbang(struct mii_bus *bus)
+{
+ struct mdiobb_ctrl *ctrl = bus->priv;
+
+ module_put(ctrl->ops->owner);
+ kfree(bus);
+}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f71dab347667..9bc11773705b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -7,7 +7,7 @@
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
- * Copyright (c) 2006 Maciej W. Rozycki
+ * Copyright (c) 2006, 2007 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -204,7 +205,7 @@ static const struct phy_setting settings[] = {
},
};
-#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
+#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
/**
* phy_find_setting - find a PHY settings array entry that matches speed & duplex
@@ -261,7 +262,7 @@ void phy_sanitize_settings(struct phy_device *phydev)
/* Sanitize settings based on PHY capabilities */
if ((features & SUPPORTED_Autoneg) == 0)
- phydev->autoneg = 0;
+ phydev->autoneg = AUTONEG_DISABLE;
idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
features);
@@ -374,7 +375,7 @@ int phy_mii_ioctl(struct phy_device *phydev,
if (mii_data->phy_id == phydev->addr) {
switch(mii_data->reg_num) {
case MII_BMCR:
- if (val & (BMCR_RESET|BMCR_ANENABLE))
+ if ((val & (BMCR_RESET|BMCR_ANENABLE)) == 0)
phydev->autoneg = AUTONEG_DISABLE;
else
phydev->autoneg = AUTONEG_ENABLE;
@@ -409,6 +410,7 @@ int phy_mii_ioctl(struct phy_device *phydev,
return 0;
}
+EXPORT_SYMBOL(phy_mii_ioctl);
/**
* phy_start_aneg - start auto-negotiation for this PHY device
@@ -423,7 +425,7 @@ int phy_start_aneg(struct phy_device *phydev)
{
int err;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (AUTONEG_DISABLE == phydev->autoneg)
phy_sanitize_settings(phydev);
@@ -444,7 +446,7 @@ int phy_start_aneg(struct phy_device *phydev)
}
out_unlock:
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
return err;
}
EXPORT_SYMBOL(phy_start_aneg);
@@ -489,10 +491,10 @@ void phy_stop_machine(struct phy_device *phydev)
{
del_timer_sync(&phydev->phy_timer);
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (phydev->state > PHY_UP)
phydev->state = PHY_UP;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
phydev->adjust_state = NULL;
}
@@ -536,9 +538,9 @@ static void phy_force_reduction(struct phy_device *phydev)
*/
void phy_error(struct phy_device *phydev)
{
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
phydev->state = PHY_HALTED;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
}
/**
@@ -561,6 +563,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
* queue will write the PHY to disable and clear the
* interrupt, and then reenable the irq line. */
disable_irq_nosync(irq);
+ atomic_inc(&phydev->irq_disable);
schedule_work(&phydev->phy_queue);
@@ -631,6 +634,7 @@ int phy_start_interrupts(struct phy_device *phydev)
INIT_WORK(&phydev->phy_queue, phy_change);
+ atomic_set(&phydev->irq_disable, 0);
if (request_irq(phydev->irq, phy_interrupt,
IRQF_SHARED,
"phy_interrupt",
@@ -661,13 +665,22 @@ int phy_stop_interrupts(struct phy_device *phydev)
if (err)
phy_error(phydev);
+ free_irq(phydev->irq, phydev);
+
/*
- * Finish any pending work; we might have been scheduled to be called
- * from keventd ourselves, but cancel_work_sync() handles that.
+ * Cannot call flush_scheduled_work() here as desired because
+ * of rtnl_lock(), but we do not really care about what would
+ * be done, except from enable_irq(), so cancel any work
+ * possibly pending and take care of the matter below.
*/
cancel_work_sync(&phydev->phy_queue);
-
- free_irq(phydev->irq, phydev);
+ /*
+ * If work indeed has been cancelled, disable_irq() will have
+ * been left unbalanced from phy_interrupt() and enable_irq()
+ * has to be called so that other devices on the line work.
+ */
+ while (atomic_dec_return(&phydev->irq_disable) >= 0)
+ enable_irq(phydev->irq);
return err;
}
@@ -689,11 +702,12 @@ static void phy_change(struct work_struct *work)
if (err)
goto phy_err;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
phydev->state = PHY_CHANGELINK;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
+ atomic_dec(&phydev->irq_disable);
enable_irq(phydev->irq);
/* Reenable interrupts */
@@ -707,6 +721,7 @@ static void phy_change(struct work_struct *work)
irq_enable_err:
disable_irq(phydev->irq);
+ atomic_inc(&phydev->irq_disable);
phy_err:
phy_error(phydev);
}
@@ -717,13 +732,11 @@ phy_err:
*/
void phy_stop(struct phy_device *phydev)
{
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (PHY_HALTED == phydev->state)
goto out_unlock;
- phydev->state = PHY_HALTED;
-
if (phydev->irq != PHY_POLL) {
/* Disable PHY Interrupts */
phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
@@ -732,8 +745,10 @@ void phy_stop(struct phy_device *phydev)
phy_clear_interrupt(phydev);
}
+ phydev->state = PHY_HALTED;
+
out_unlock:
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
/*
* Cannot call flush_scheduled_work() here as desired because
@@ -755,7 +770,7 @@ out_unlock:
*/
void phy_start(struct phy_device *phydev)
{
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
switch (phydev->state) {
case PHY_STARTING:
@@ -769,7 +784,7 @@ void phy_start(struct phy_device *phydev)
default:
break;
}
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
}
EXPORT_SYMBOL(phy_stop);
EXPORT_SYMBOL(phy_start);
@@ -781,7 +796,7 @@ static void phy_timer(unsigned long data)
int needs_aneg = 0;
int err = 0;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (phydev->adjust_state)
phydev->adjust_state(phydev->attached_dev);
@@ -947,7 +962,7 @@ static void phy_timer(unsigned long data)
break;
}
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
if (needs_aneg)
err = phy_start_aneg(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index a8b74cdab1ea..c0461217b108 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -364,7 +364,7 @@ EXPORT_SYMBOL(genphy_config_advert);
*/
int genphy_setup_forced(struct phy_device *phydev)
{
- int ctl = BMCR_RESET;
+ int ctl = 0;
phydev->pause = phydev->asym_pause = 0;
@@ -644,7 +644,7 @@ static int phy_probe(struct device *dev)
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
phydev->irq = PHY_POLL;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
/* Start out supporting everything. Eventually,
* a controller will attach, and may modify one
@@ -658,7 +658,7 @@ static int phy_probe(struct device *dev)
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
return err;
@@ -670,9 +670,9 @@ static int phy_remove(struct device *dev)
phydev = to_phy_device(dev);
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
phydev->state = PHY_DOWN;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
if (phydev->drv->remove)
phydev->drv->remove(phydev);
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 596222b260d6..8874497b6bbf 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -21,6 +21,10 @@
/* Vitesse Extended Control Register 1 */
#define MII_VSC8244_EXT_CON1 0x17
#define MII_VSC8244_EXTCON1_INIT 0x0000
+#define MII_VSC8244_EXTCON1_TX_SKEW_MASK 0x0c00
+#define MII_VSC8244_EXTCON1_RX_SKEW_MASK 0x0300
+#define MII_VSC8244_EXTCON1_TX_SKEW 0x0800
+#define MII_VSC8244_EXTCON1_RX_SKEW 0x0200
/* Vitesse Interrupt Mask Register */
#define MII_VSC8244_IMASK 0x19
@@ -39,7 +43,7 @@
/* Vitesse Auxiliary Control/Status Register */
#define MII_VSC8244_AUX_CONSTAT 0x1c
-#define MII_VSC8244_AUXCONSTAT_INIT 0x0004
+#define MII_VSC8244_AUXCONSTAT_INIT 0x0000
#define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020
#define MII_VSC8244_AUXCONSTAT_SPEED 0x0018
#define MII_VSC8244_AUXCONSTAT_GBIT 0x0010
@@ -51,6 +55,7 @@ MODULE_LICENSE("GPL");
static int vsc824x_config_init(struct phy_device *phydev)
{
+ int extcon;
int err;
err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
@@ -58,14 +63,34 @@ static int vsc824x_config_init(struct phy_device *phydev)
if (err < 0)
return err;
- err = phy_write(phydev, MII_VSC8244_EXT_CON1,
- MII_VSC8244_EXTCON1_INIT);
+ extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
+
+ if (extcon < 0)
+ return err;
+
+ extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
+ MII_VSC8244_EXTCON1_RX_SKEW_MASK);
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
+ MII_VSC8244_EXTCON1_RX_SKEW);
+
+ err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
+
return err;
}
static int vsc824x_ack_interrupt(struct phy_device *phydev)
{
- int err = phy_read(phydev, MII_VSC8244_ISTAT);
+ int err = 0;
+
+ /*
+ * Don't bother to ACK the interrupts if interrupts
+ * are disabled. The 824x cannot clear the interrupts
+ * if they are disabled.
+ */
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_read(phydev, MII_VSC8244_ISTAT);
return (err < 0) ? err : 0;
}
@@ -77,8 +102,19 @@ static int vsc824x_config_intr(struct phy_device *phydev)
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_VSC8244_IMASK,
MII_VSC8244_IMASK_MASK);
- else
+ else {
+ /*
+ * The Vitesse PHY cannot clear the interrupt
+ * once it has disabled them, so we clear them first
+ */
+ err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+ if (err < 0)
+ return err;
+
err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+ }
+
return err;
}
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 8754cf3356b0..b5e9981d1060 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -148,13 +148,12 @@ static void plip_interrupt(int irq, void *dev_id);
/* Functions for DEV methods */
static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len);
-static int plip_hard_header_cache(struct neighbour *neigh,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len);
+static int plip_hard_header_cache(const struct neighbour *neigh,
struct hh_cache *hh);
static int plip_open(struct net_device *dev);
static int plip_close(struct net_device *dev);
-static struct net_device_stats *plip_get_stats(struct net_device *dev);
static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int plip_preempt(void *handle);
static void plip_wakeup(void *handle);
@@ -206,7 +205,6 @@ struct plip_local {
};
struct net_local {
- struct net_device_stats enet_stats;
struct net_device *dev;
struct work_struct immediate;
struct delayed_work deferred;
@@ -221,11 +219,6 @@ struct net_local {
int is_deferred;
int port_owner;
int should_relinquish;
- int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len);
- int (*orig_hard_header_cache)(struct neighbour *neigh,
- struct hh_cache *hh);
spinlock_t lock;
atomic_t kill_timer;
struct semaphore killed_timer_sem;
@@ -267,6 +260,11 @@ static inline unsigned char read_status (struct net_device *dev)
return port->ops->read_status (port);
}
+static const struct header_ops plip_header_ops = {
+ .create = plip_hard_header,
+ .cache = plip_hard_header_cache,
+};
+
/* Entry point of PLIP driver.
Probe the hardware, and register/initialize the driver.
@@ -285,19 +283,13 @@ plip_init_netdev(struct net_device *dev)
dev->hard_start_xmit = plip_tx_packet;
dev->open = plip_open;
dev->stop = plip_close;
- dev->get_stats = plip_get_stats;
dev->do_ioctl = plip_ioctl;
- dev->header_cache_update = NULL;
+
dev->tx_queue_len = 10;
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
memset(dev->dev_addr, 0xfc, ETH_ALEN);
- /* Set the private structure */
- nl->orig_hard_header = dev->hard_header;
- dev->hard_header = plip_hard_header;
-
- nl->orig_hard_header_cache = dev->hard_header_cache;
- dev->hard_header_cache = plip_hard_header_cache;
+ dev->header_ops = &plip_header_ops;
nl->port_owner = 0;
@@ -430,8 +422,8 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
dev->name, snd->state, c0);
} else
error = HS_TIMEOUT;
- nl->enet_stats.tx_errors++;
- nl->enet_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
} else if (nl->connection == PLIP_CN_RECEIVE) {
if (rcv->state == PLIP_PK_TRIGGER) {
/* Transmission was interrupted. */
@@ -448,7 +440,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",
dev->name, rcv->state, c0);
}
- nl->enet_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
rcv->state = PLIP_PK_DONE;
if (rcv->skb) {
@@ -661,7 +653,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
&rcv->nibble, &rcv->data))
return TIMEOUT;
if (rcv->data != rcv->checksum) {
- nl->enet_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (net_debug)
printk(KERN_DEBUG "%s: checksum error\n", dev->name);
return ERROR;
@@ -673,8 +665,8 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
rcv->skb->protocol=plip_type_trans(rcv->skb, dev);
netif_rx(rcv->skb);
dev->last_rx = jiffies;
- nl->enet_stats.rx_bytes += rcv->length.h;
- nl->enet_stats.rx_packets++;
+ dev->stats.rx_bytes += rcv->length.h;
+ dev->stats.rx_packets++;
rcv->skb = NULL;
if (net_debug > 2)
printk(KERN_DEBUG "%s: receive end\n", dev->name);
@@ -776,7 +768,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
if (nl->connection == PLIP_CN_RECEIVE) {
spin_unlock_irq(&nl->lock);
/* Interrupted. */
- nl->enet_stats.collisions++;
+ dev->stats.collisions++;
return OK;
}
c0 = read_status(dev);
@@ -792,7 +784,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
{enable,disable}_irq *counts*
them. -- AV */
ENABLE(dev->irq);
- nl->enet_stats.collisions++;
+ dev->stats.collisions++;
return OK;
}
disable_parport_interrupts (dev);
@@ -840,9 +832,9 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
&snd->nibble, snd->checksum))
return TIMEOUT;
- nl->enet_stats.tx_bytes += snd->skb->len;
+ dev->stats.tx_bytes += snd->skb->len;
dev_kfree_skb(snd->skb);
- nl->enet_stats.tx_packets++;
+ dev->stats.tx_packets++;
snd->state = PLIP_PK_DONE;
case PLIP_PK_DONE:
@@ -996,14 +988,14 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
}
static void
-plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
+plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
{
- struct in_device *in_dev;
+ const struct in_device *in_dev = dev->ip_ptr;
- if ((in_dev=dev->ip_ptr) != NULL) {
+ if (in_dev) {
/* Any address will do - we take the first */
- struct in_ifaddr *ifa=in_dev->ifa_list;
- if (ifa != NULL) {
+ const struct in_ifaddr *ifa = in_dev->ifa_list;
+ if (ifa) {
memcpy(eth->h_source, dev->dev_addr, 6);
memset(eth->h_dest, 0xfc, 2);
memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
@@ -1013,26 +1005,25 @@ plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
static int
plip_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
- struct net_local *nl = netdev_priv(dev);
int ret;
- if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
+ ret = eth_header(skb, dev, type, daddr, saddr, len);
+ if (ret >= 0)
plip_rewrite_address (dev, (struct ethhdr *)skb->data);
return ret;
}
-int plip_hard_header_cache(struct neighbour *neigh,
+int plip_hard_header_cache(const struct neighbour *neigh,
struct hh_cache *hh)
{
- struct net_local *nl = neigh->dev->priv;
int ret;
- if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
- {
+ ret = eth_header_cache(neigh, hh);
+ if (ret == 0) {
struct ethhdr *eth;
eth = (struct ethhdr*)(((u8*)hh->hh_data) +
@@ -1199,15 +1190,6 @@ plip_wakeup(void *handle)
return;
}
-static struct net_device_stats *
-plip_get_stats(struct net_device *dev)
-{
- struct net_local *nl = netdev_priv(dev);
- struct net_device_stats *r = &nl->enet_stats;
-
- return r;
-}
-
static int
plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
@@ -1278,7 +1260,6 @@ static void plip_attach (struct parport *port)
strcpy(dev->name, name);
- SET_MODULE_OWNER(dev);
dev->irq = port->irq;
dev->base_addr = port->base;
if (port->irq == -1) {
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index caabbc408c34..27f5b904f48e 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -159,12 +159,11 @@ ppp_asynctty_open(struct tty_struct *tty)
int err;
err = -ENOMEM;
- ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+ ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (ap == 0)
goto out;
/* initialize the asyncppp structure */
- memset(ap, 0, sizeof(*ap));
ap->tty = tty;
ap->mru = PPP_MRU;
spin_lock_init(&ap->xmit_lock);
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 72c8d6628f58..eb98b661efba 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -121,12 +121,11 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
return NULL;
- state = kmalloc(sizeof(*state),
+ state = kzalloc(sizeof(*state),
GFP_KERNEL);
if (state == NULL)
return NULL;
- memset (state, 0, sizeof (struct ppp_deflate_state));
state->strm.next_in = NULL;
state->w_size = w_size;
state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
@@ -341,11 +340,10 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len)
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
return NULL;
- state = kmalloc(sizeof(*state), GFP_KERNEL);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
return NULL;
- memset (state, 0, sizeof (struct ppp_deflate_state));
state->w_size = w_size;
state->strm.next_out = NULL;
state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 3ef0092dc09c..4b49d0e8c7eb 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -899,17 +899,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Put the 2-byte PPP protocol number on the front,
making sure there is room for the address and control fields. */
- if (skb_headroom(skb) < PPP_HDRLEN) {
- struct sk_buff *ns;
-
- ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC);
- if (ns == 0)
- goto outf;
- skb_reserve(ns, dev->hard_header_len);
- skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len);
- kfree_skb(skb);
- skb = ns;
- }
+ if (skb_cow_head(skb, PPP_HDRLEN))
+ goto outf;
+
pp = skb_push(skb, 2);
proto = npindex_to_proto[npi];
pp[0] = proto >> 8;
@@ -1533,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
- if (skb->len >= 2) {
+ if (pskb_may_pull(skb, 2)) {
#ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP)
@@ -1585,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err;
- if (skb_tailroom(skb) < 124) {
+ if (skb_tailroom(skb) < 124 || skb_cloned(skb)) {
/* copy to a new sk_buff with more tailroom */
ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) {
@@ -1656,23 +1648,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* check if the packet passes the pass and active filters */
/* the filter instructions are constructed assuming
a four-byte PPP header on each packet */
- *skb_push(skb, 2) = 0;
- if (ppp->pass_filter
- && sk_run_filter(skb, ppp->pass_filter,
- ppp->pass_len) == 0) {
- if (ppp->debug & 1)
- printk(KERN_DEBUG "PPP: inbound frame not passed\n");
- kfree_skb(skb);
- return;
- }
- if (!(ppp->active_filter
- && sk_run_filter(skb, ppp->active_filter,
- ppp->active_len) == 0))
- ppp->last_recv = jiffies;
- skb_pull(skb, 2);
-#else
- ppp->last_recv = jiffies;
+ if (ppp->pass_filter || ppp->active_filter) {
+ if (skb_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto err;
+
+ *skb_push(skb, 2) = 0;
+ if (ppp->pass_filter
+ && sk_run_filter(skb, ppp->pass_filter,
+ ppp->pass_len) == 0) {
+ if (ppp->debug & 1)
+ printk(KERN_DEBUG "PPP: inbound frame "
+ "not passed\n");
+ kfree_skb(skb);
+ return;
+ }
+ if (!(ppp->active_filter
+ && sk_run_filter(skb, ppp->active_filter,
+ ppp->active_len) == 0))
+ ppp->last_recv = jiffies;
+ __skb_pull(skb, 2);
+ } else
#endif /* CONFIG_PPP_FILTER */
+ ppp->last_recv = jiffies;
if ((ppp->dev->flags & IFF_UP) == 0
|| ppp->npmode[npi] != NPMODE_PASS) {
@@ -1726,7 +1724,7 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
}
/* the decompressor still expects the A/C bytes in the hdr */
len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2,
- skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN);
+ skb->len + 2, ns->data, obuff_size);
if (len < 0) {
/* Pass the compressed frame to pppd as an
error indication. */
@@ -1770,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
struct channel *ch;
int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
- if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
+ if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
goto err; /* no good, throw it away */
/* Decode sequence number and begin/end bits */
@@ -2684,8 +2682,7 @@ static void __exit ppp_cleanup(void)
if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
printk(KERN_ERR "PPP: removing module but units remain!\n");
cardmap_destroy(&all_ppp_units);
- if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
- printk(KERN_ERR "PPP: failed to unregister PPP device\n");
+ unregister_chrdev(PPP_MAJOR, "ppp");
device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
class_destroy(ppp_class);
}
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index d5bdd2574659..c0b6d19d1457 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -136,7 +136,7 @@ struct ppp_mppe_state {
* Key Derivation, from RFC 3078, RFC 3079.
* Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
*/
-static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
+static void get_new_key_from_sha(struct ppp_mppe_state * state)
{
struct hash_desc desc;
struct scatterlist sg[4];
@@ -153,8 +153,6 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I
desc.flags = 0;
crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);
-
- memcpy(InterimKey, state->sha1_digest, state->keylen);
}
/*
@@ -163,21 +161,21 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I
*/
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{
- unsigned char InterimKey[MPPE_MAX_KEY_LEN];
struct scatterlist sg_in[1], sg_out[1];
struct blkcipher_desc desc = { .tfm = state->arc4 };
- get_new_key_from_sha(state, InterimKey);
+ get_new_key_from_sha(state);
if (!initial_key) {
- crypto_blkcipher_setkey(state->arc4, InterimKey, state->keylen);
- setup_sg(sg_in, InterimKey, state->keylen);
+ crypto_blkcipher_setkey(state->arc4, state->sha1_digest,
+ state->keylen);
+ setup_sg(sg_in, state->sha1_digest, state->keylen);
setup_sg(sg_out, state->session_key, state->keylen);
if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
state->keylen) != 0) {
printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
}
} else {
- memcpy(state->session_key, InterimKey, state->keylen);
+ memcpy(state->session_key, state->sha1_digest, state->keylen);
}
if (state->keylen == 8) {
/* See RFC 3078 */
@@ -200,11 +198,10 @@ static void *mppe_alloc(unsigned char *options, int optlen)
|| options[0] != CI_MPPE || options[1] != CILEN_MPPE)
goto out;
- state = kmalloc(sizeof(*state), GFP_KERNEL);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
goto out;
- memset(state, 0, sizeof(*state));
state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(state->arc4)) {
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 5918fab38349..ce64032a465a 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -207,13 +207,12 @@ ppp_sync_open(struct tty_struct *tty)
struct syncppp *ap;
int err;
- ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+ ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
if (ap == 0)
goto out;
/* initialize the syncppp structure */
- memset(ap, 0, sizeof(*ap));
ap->tty = tty;
ap->mru = PPP_MRU;
spin_lock_init(&ap->xmit_lock);
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 6f98834e6ace..8936ed3469cf 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -78,6 +78,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <net/net_namespace.h>
#include <net/sock.h>
#include <asm/uaccess.h>
@@ -102,25 +103,30 @@ static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b)
(memcmp(a->remote, b->remote, ETH_ALEN) == 0));
}
-static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr)
+static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr)
{
return (a->sid == sid &&
(memcmp(a->remote,addr,ETH_ALEN) == 0));
}
-static int hash_item(unsigned long sid, unsigned char *addr)
+#if 8%PPPOE_HASH_BITS
+#error 8 must be a multiple of PPPOE_HASH_BITS
+#endif
+
+static int hash_item(__be16 sid, unsigned char *addr)
{
- char hash = 0;
- int i, j;
+ unsigned char hash = 0;
+ unsigned int i;
- for (i = 0; i < ETH_ALEN ; ++i) {
- for (j = 0; j < 8/PPPOE_HASH_BITS ; ++j) {
- hash ^= addr[i] >> ( j * PPPOE_HASH_BITS );
- }
+ for (i = 0 ; i < ETH_ALEN ; i++) {
+ hash ^= addr[i];
+ }
+ for (i = 0 ; i < sizeof(sid_t)*8 ; i += 8 ){
+ hash ^= (__force __u32)sid>>i;
+ }
+ for (i = 8 ; (i>>=1) >= PPPOE_HASH_BITS ; ) {
+ hash ^= hash>>i;
}
-
- for (i = 0; i < (sizeof(unsigned long)*8) / PPPOE_HASH_BITS ; ++i)
- hash ^= sid >> (i*PPPOE_HASH_BITS);
return hash & ( PPPOE_HASH_SIZE - 1 );
}
@@ -133,7 +139,7 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE];
* Set/get/delete/rehash items (internal versions)
*
**********************************************************************/
-static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex)
+static struct pppox_sock *__get_item(__be16 sid, unsigned char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
struct pppox_sock *ret;
@@ -165,7 +171,7 @@ static int __set_item(struct pppox_sock *po)
return 0;
}
-static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex)
+static struct pppox_sock *__delete_item(__be16 sid, char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
struct pppox_sock *ret, **src;
@@ -191,7 +197,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifind
* Set/get/delete/rehash items
*
**********************************************************************/
-static inline struct pppox_sock *get_item(unsigned long sid,
+static inline struct pppox_sock *get_item(__be16 sid,
unsigned char *addr, int ifindex)
{
struct pppox_sock *po;
@@ -210,7 +216,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
struct net_device *dev;
int ifindex;
- dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+ dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);
if(!dev)
return NULL;
ifindex = dev->ifindex;
@@ -218,7 +224,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex);
}
-static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex)
+static inline struct pppox_sock *delete_item(__be16 sid, char *addr, int ifindex)
{
struct pppox_sock *ret;
@@ -295,6 +301,9 @@ static int pppoe_device_event(struct notifier_block *this,
{
struct net_device *dev = (struct net_device *) ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
/* Only look at sockets that are using this specific device. */
switch (event) {
case NETDEV_CHANGEMTU:
@@ -380,15 +389,18 @@ static int pppoe_rcv(struct sk_buff *skb,
struct pppoe_hdr *ph;
struct pppox_sock *po;
- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
- goto drop;
-
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
+ if (dev->nd_net != &init_net)
+ goto drop;
+
+ if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ goto drop;
+
ph = pppoe_hdr(skb);
- po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+ po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po != NULL)
return sk_receive_skb(sk_pppox(po), skb, 0);
drop:
@@ -412,6 +424,9 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
struct pppoe_hdr *ph;
struct pppox_sock *po;
+ if (dev->nd_net != &init_net)
+ goto abort;
+
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto abort;
@@ -422,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
if (ph->code != PADT_CODE)
goto abort;
- po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+ po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po) {
struct sock *sk = sk_pppox(po);
@@ -471,12 +486,12 @@ static struct proto pppoe_sk_proto = {
* Initialize a new struct sock.
*
**********************************************************************/
-static int pppoe_create(struct socket *sock)
+static int pppoe_create(struct net *net, struct socket *sock)
{
int error = -ENOMEM;
struct sock *sk;
- sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1);
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1);
if (!sk)
goto out;
@@ -588,7 +603,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Don't re-bind if sid==0 */
if (sp->sa_addr.pppoe.sid != 0) {
- dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+ dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);
error = -ENODEV;
if (!dev)
@@ -664,8 +679,8 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
{
struct sock *sk = sock->sk;
struct pppox_sock *po = pppox_sk(sk);
- int val = 0;
- int err = 0;
+ int val;
+ int err;
switch (cmd) {
case PPPIOCGMRU:
@@ -754,8 +769,9 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
err = 0;
break;
- default:;
- };
+ default:
+ err = -ENOTTY;
+ }
return err;
}
@@ -773,6 +789,7 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
struct net_device *dev;
char *start;
+ lock_sock(sk);
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
error = -ENOTCONN;
goto end;
@@ -783,8 +800,6 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
hdr.code = 0;
hdr.sid = po->num;
- lock_sock(sk);
-
dev = po->pppoe_dev;
error = -EMSGSIZE;
@@ -819,8 +834,8 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
}
error = total_len;
- dev->hard_header(skb, dev, ETH_P_PPP_SES,
- po->pppoe_pa.remote, NULL, total_len);
+ dev_hard_header(skb, dev, ETH_P_PPP_SES,
+ po->pppoe_pa.remote, NULL, total_len);
memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
@@ -843,71 +858,44 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
{
struct pppox_sock *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev;
- struct pppoe_hdr hdr;
struct pppoe_hdr *ph;
- int headroom = skb_headroom(skb);
int data_len = skb->len;
- struct sk_buff *skb2;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
- hdr.ver = 1;
- hdr.type = 1;
- hdr.code = 0;
- hdr.sid = po->num;
- hdr.length = htons(skb->len);
-
if (!dev)
goto abort;
- /* Copy the skb if there is no space for the header. */
- if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) {
- skb2 = dev_alloc_skb(32+skb->len +
- sizeof(struct pppoe_hdr) +
- dev->hard_header_len);
-
- if (skb2 == NULL)
- goto abort;
-
- skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
- skb_copy_from_linear_data(skb, skb_put(skb2, skb->len),
- skb->len);
- } else {
- /* Make a clone so as to not disturb the original skb,
- * give dev_queue_xmit something it can free.
- */
- skb2 = skb_clone(skb, GFP_ATOMIC);
-
- if (skb2 == NULL)
- goto abort;
- }
-
- ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr));
- memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
- skb2->protocol = __constant_htons(ETH_P_PPP_SES);
+ /* Copy the data if there is no space for the header or if it's
+ * read-only.
+ */
+ if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
+ goto abort;
- skb_reset_network_header(skb2);
+ __skb_push(skb, sizeof(*ph));
+ skb_reset_network_header(skb);
- skb2->dev = dev;
+ ph = pppoe_hdr(skb);
+ ph->ver = 1;
+ ph->type = 1;
+ ph->code = 0;
+ ph->sid = po->num;
+ ph->length = htons(data_len);
- dev->hard_header(skb2, dev, ETH_P_PPP_SES,
- po->pppoe_pa.remote, NULL, data_len);
+ skb->protocol = __constant_htons(ETH_P_PPP_SES);
+ skb->dev = dev;
- /* We're transmitting skb2, and assuming that dev_queue_xmit
- * will free it. The generic ppp layer however, is expecting
- * that we give back 'skb' (not 'skb2') in case of failure,
- * but free it in case of success.
- */
+ dev_hard_header(skb, dev, ETH_P_PPP_SES,
+ po->pppoe_pa.remote, NULL, data_len);
- if (dev_queue_xmit(skb2) < 0)
- goto abort;
+ dev_queue_xmit(skb);
- kfree_skb(skb);
return 1;
abort:
- return 0;
+ kfree_skb(skb);
+ return 1;
}
@@ -967,6 +955,7 @@ static int pppoe_seq_show(struct seq_file *seq, void *v)
{
struct pppox_sock *po;
char *dev_name;
+ DECLARE_MAC_BUF(mac);
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "Id Address Device\n");
@@ -976,11 +965,8 @@ static int pppoe_seq_show(struct seq_file *seq, void *v)
po = v;
dev_name = po->pppoe_pa.dev;
- seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",
- po->pppoe_pa.sid,
- po->pppoe_pa.remote[0], po->pppoe_pa.remote[1],
- po->pppoe_pa.remote[2], po->pppoe_pa.remote[3],
- po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name);
+ seq_printf(seq, "%08X %s %8s\n",
+ po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name);
out:
return 0;
}
@@ -1064,7 +1050,7 @@ static int __init pppoe_proc_init(void)
{
struct proc_dir_entry *p;
- p = create_proc_entry("net/pppoe", S_IRUGO, NULL);
+ p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net);
if (!p)
return -ENOMEM;
@@ -1135,7 +1121,7 @@ static void __exit pppoe_exit(void)
dev_remove_pack(&pppoes_ptype);
dev_remove_pack(&pppoed_ptype);
unregister_netdevice_notifier(&pppoe_notifier);
- remove_proc_entry("net/pppoe", NULL);
+ remove_proc_entry("pppoe", init_net.proc_net);
proto_unregister(&pppoe_sk_proto);
}
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 5891a0fbdc8b..921d4ef6d14b 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -91,6 +91,7 @@
#include <linux/hash.h>
#include <linux/sort.h>
#include <linux/proc_fs.h>
+#include <net/net_namespace.h>
#include <net/dst.h>
#include <net/ip.h>
#include <net/udp.h>
@@ -491,44 +492,46 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
u16 hdrflags;
u16 tunnel_id, session_id;
int length;
- struct udphdr *uh;
+ int offset;
tunnel = pppol2tp_sock_to_tunnel(sock);
if (tunnel == NULL)
goto error;
+ /* UDP always verifies the packet length. */
+ __skb_pull(skb, sizeof(struct udphdr));
+
/* Short packet? */
- if (skb->len < sizeof(struct udphdr)) {
+ if (!pskb_may_pull(skb, 12)) {
PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
"%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
goto error;
}
/* Point to L2TP header */
- ptr = skb->data + sizeof(struct udphdr);
+ ptr = skb->data;
/* Get L2TP header flags */
hdrflags = ntohs(*(__be16*)ptr);
/* Trace packet contents, if enabled */
if (tunnel->debug & PPPOL2TP_MSG_DATA) {
+ length = min(16u, skb->len);
+ if (!pskb_may_pull(skb, length))
+ goto error;
+
printk(KERN_DEBUG "%s: recv: ", tunnel->name);
- for (length = 0; length < 16; length++)
- printk(" %02X", ptr[length]);
+ offset = 0;
+ do {
+ printk(" %02X", ptr[offset]);
+ } while (++offset < length);
+
printk("\n");
}
/* Get length of L2TP packet */
- uh = (struct udphdr *) skb_transport_header(skb);
- length = ntohs(uh->len) - sizeof(struct udphdr);
-
- /* Too short? */
- if (length < 12) {
- PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
- "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length);
- goto error;
- }
+ length = skb->len;
/* If type is control packet, it is handled by userspace. */
if (hdrflags & L2TP_HDRFLAG_T) {
@@ -606,7 +609,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
"%s: recv data has no seq numbers when required. "
"Discarding\n", session->name);
session->stats.rx_seq_discards++;
- session->stats.rx_errors++;
goto discard;
}
@@ -625,7 +627,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
"%s: recv data has no seq numbers when required. "
"Discarding\n", session->name);
session->stats.rx_seq_discards++;
- session->stats.rx_errors++;
goto discard;
}
@@ -634,10 +635,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
}
/* If offset bit set, skip it. */
- if (hdrflags & L2TP_HDRFLAG_O)
- ptr += 2 + ntohs(*(__be16 *) ptr);
+ if (hdrflags & L2TP_HDRFLAG_O) {
+ offset = ntohs(*(__be16 *)ptr);
+ skb->transport_header += 2 + offset;
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2))
+ goto discard;
+ }
- skb_pull(skb, ptr - skb->data);
+ __skb_pull(skb, skb_transport_offset(skb));
/* Skip PPP header, if present. In testing, Microsoft L2TP clients
* don't send the PPP header (PPP header compression enabled), but
@@ -673,7 +678,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
*/
if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
session->stats.rx_seq_discards++;
- session->stats.rx_errors++;
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: oos pkt %hu len %d discarded, "
"waiting for %hu, reorder_q_len=%d\n",
@@ -698,6 +702,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
return 0;
discard:
+ session->stats.rx_errors++;
kfree_skb(skb);
sock_put(session->sock);
@@ -824,6 +829,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
struct pppol2tp_session *session;
struct pppol2tp_tunnel *tunnel;
struct udphdr *uh;
+ unsigned int len;
error = -ENOTCONN;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -912,14 +918,15 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
}
/* Queue the packet to IP for output */
+ len = skb->len;
error = ip_queue_xmit(skb, 1);
/* Update stats */
if (error >= 0) {
tunnel->stats.tx_packets++;
- tunnel->stats.tx_bytes += skb->len;
+ tunnel->stats.tx_bytes += len;
session->stats.tx_packets++;
- session->stats.tx_bytes += skb->len;
+ session->stats.tx_bytes += len;
} else {
tunnel->stats.tx_errors++;
session->stats.tx_errors++;
@@ -956,8 +963,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
int data_len = skb->len;
struct inet_sock *inet;
__wsum csum = 0;
- struct sk_buff *skb2 = NULL;
struct udphdr *uh;
+ unsigned int len;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
@@ -986,41 +993,30 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
*/
headroom = NET_SKB_PAD + sizeof(struct iphdr) +
sizeof(struct udphdr) + hdr_len + sizeof(ppph);
- if (skb_headroom(skb) < headroom) {
- skb2 = skb_realloc_headroom(skb, headroom);
- if (skb2 == NULL)
- goto abort;
- } else
- skb2 = skb;
-
- /* Check that the socket has room */
- if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf)
- skb_set_owner_w(skb2, sk_tun);
- else
- goto discard;
+ if (skb_cow_head(skb, headroom))
+ goto abort;
/* Setup PPP header */
- skb_push(skb2, sizeof(ppph));
- skb2->data[0] = ppph[0];
- skb2->data[1] = ppph[1];
+ __skb_push(skb, sizeof(ppph));
+ skb->data[0] = ppph[0];
+ skb->data[1] = ppph[1];
/* Setup L2TP header */
- skb_push(skb2, hdr_len);
- pppol2tp_build_l2tp_header(session, skb2->data);
+ pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
/* Setup UDP header */
inet = inet_sk(sk_tun);
- skb_push(skb2, sizeof(struct udphdr));
- skb_reset_transport_header(skb2);
- uh = (struct udphdr *) skb2->data;
+ __skb_push(skb, sizeof(*uh));
+ skb_reset_transport_header(skb);
+ uh = udp_hdr(skb);
uh->source = inet->sport;
uh->dest = inet->dport;
uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len);
uh->check = 0;
- /* Calculate UDP checksum if configured to do so */
+ /* *BROKEN* Calculate UDP checksum if configured to do so */
if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT)
- csum = udp_csum_outgoing(sk_tun, skb2);
+ csum = udp_csum_outgoing(sk_tun, skb);
/* Debug */
if (session->send_seq)
@@ -1033,7 +1029,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
if (session->debug & PPPOL2TP_MSG_DATA) {
int i;
- unsigned char *datap = skb2->data;
+ unsigned char *datap = skb->data;
printk(KERN_DEBUG "%s: xmit:", session->name);
for (i = 0; i < data_len; i++) {
@@ -1046,34 +1042,36 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
printk("\n");
}
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+ IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+ IPSKB_REROUTED);
+ nf_reset(skb);
+
/* Get routing info from the tunnel socket */
- skb2->dst = sk_dst_get(sk_tun);
+ dst_release(skb->dst);
+ skb->dst = sk_dst_get(sk_tun);
/* Queue the packet to IP for output */
- rc = ip_queue_xmit(skb2, 1);
+ len = skb->len;
+ rc = ip_queue_xmit(skb, 1);
/* Update stats */
if (rc >= 0) {
tunnel->stats.tx_packets++;
- tunnel->stats.tx_bytes += skb2->len;
+ tunnel->stats.tx_bytes += len;
session->stats.tx_packets++;
- session->stats.tx_bytes += skb2->len;
+ session->stats.tx_bytes += len;
} else {
tunnel->stats.tx_errors++;
session->stats.tx_errors++;
}
- /* Free the original skb */
- kfree_skb(skb);
-
return 1;
-discard:
- /* Free the new skb. Caller will free original skb. */
- if (skb2 != skb)
- kfree_skb(skb2);
abort:
- return 0;
+ /* Free the original skb */
+ kfree_skb(skb);
+ return 1;
}
/*****************************************************************************
@@ -1316,12 +1314,14 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
goto err;
}
+ sk = sock->sk;
+
/* Quick sanity checks */
- err = -ESOCKTNOSUPPORT;
- if (sock->type != SOCK_DGRAM) {
+ err = -EPROTONOSUPPORT;
+ if (sk->sk_protocol != IPPROTO_UDP) {
PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
- "tunl %hu: fd %d wrong type, got %d, expected %d\n",
- tunnel_id, fd, sock->type, SOCK_DGRAM);
+ "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
+ tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
goto err;
}
err = -EAFNOSUPPORT;
@@ -1333,7 +1333,6 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
}
err = -ENOTCONN;
- sk = sock->sk;
/* Check if this socket has already been prepped */
tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data;
@@ -1412,12 +1411,12 @@ static struct proto pppol2tp_sk_proto = {
/* socket() handler. Initialize a new struct sock.
*/
-static int pppol2tp_create(struct socket *sock)
+static int pppol2tp_create(struct net *net, struct socket *sock)
{
int error = -ENOMEM;
struct sock *sk;
- sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
if (!sk)
goto out;
@@ -2044,7 +2043,7 @@ end:
*/
static int pppol2tp_tunnel_getsockopt(struct sock *sk,
struct pppol2tp_tunnel *tunnel,
- int optname, int __user *val)
+ int optname, int *val)
{
int err = 0;
@@ -2067,7 +2066,7 @@ static int pppol2tp_tunnel_getsockopt(struct sock *sk,
*/
static int pppol2tp_session_getsockopt(struct sock *sk,
struct pppol2tp_session *session,
- int optname, int __user *val)
+ int optname, int *val)
{
int err = 0;
@@ -2446,7 +2445,7 @@ static int __init pppol2tp_init(void)
goto out_unregister_pppol2tp_proto;
#ifdef CONFIG_PROC_FS
- pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net);
+ pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net);
if (!pppol2tp_proc) {
err = -ENOMEM;
goto out_unregister_pppox_proto;
@@ -2471,7 +2470,7 @@ static void __exit pppol2tp_exit(void)
unregister_pppox_proto(PX_PROTO_OL2TP);
#ifdef CONFIG_PROC_FS
- remove_proc_entry("pppol2tp", proc_net);
+ remove_proc_entry("pppol2tp", init_net.proc_net);
#endif
proto_unregister(&pppol2tp_sk_proto);
}
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index f3e47d0c2b3c..c6898c1fc54d 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -73,7 +73,7 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
struct pppox_sock *po = pppox_sk(sk);
- int rc = 0;
+ int rc;
lock_sock(sk);
@@ -94,12 +94,9 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}
default:
- if (pppox_protos[sk->sk_protocol]->ioctl)
- rc = pppox_protos[sk->sk_protocol]->ioctl(sock, cmd,
- arg);
-
- break;
- };
+ rc = pppox_protos[sk->sk_protocol]->ioctl ?
+ pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY;
+ }
release_sock(sk);
return rc;
@@ -107,10 +104,13 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL(pppox_ioctl);
-static int pppox_create(struct socket *sock, int protocol)
+static int pppox_create(struct net *net, struct socket *sock, int protocol)
{
int rc = -EPROTOTYPE;
+ if (net != &init_net)
+ return -EAFNOSUPPORT;
+
if (protocol < 0 || protocol > PX_MAX_PROTO)
goto out;
@@ -126,7 +126,7 @@ static int pppox_create(struct socket *sock, int protocol)
!try_module_get(pppox_protos[protocol]->owner))
goto out;
- rc = pppox_protos[protocol]->create(sock);
+ rc = pppox_protos[protocol]->create(net, sock);
module_put(pppox_protos[protocol]->owner);
out:
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 08d25066f051..0a42bf517465 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -290,7 +290,8 @@ static void gelic_net_release_rx_chain(struct gelic_net_card *card)
descr->buf_addr = 0;
dev_kfree_skb_any(descr->skb);
descr->skb = NULL;
- descr->dmac_cmd_status = GELIC_NET_DESCR_NOT_IN_USE;
+ gelic_net_set_descr_status(descr,
+ GELIC_NET_DESCR_NOT_IN_USE);
}
descr = descr->next;
} while (descr != card->rx_chain.head);
@@ -350,19 +351,13 @@ static int gelic_net_alloc_rx_skbs(struct gelic_net_card *card)
static void gelic_net_release_tx_descr(struct gelic_net_card *card,
struct gelic_net_descr *descr)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = descr->skb;
+ BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)));
- if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) {
- /* 2nd descriptor */
- skb = descr->skb;
- dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
- DMA_TO_DEVICE);
- dev_kfree_skb_any(skb);
- } else {
- dma_unmap_single(ctodev(card), descr->buf_addr,
- descr->buf_size, DMA_TO_DEVICE);
- }
+ dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
descr->buf_addr = 0;
descr->buf_size = 0;
@@ -374,7 +369,7 @@ static void gelic_net_release_tx_descr(struct gelic_net_card *card,
descr->skb = NULL;
/* set descr status */
- descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE;
+ gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
}
/**
@@ -403,23 +398,26 @@ static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop)
"%s: forcing end of tx descriptor " \
"with status %x\n",
__func__, status);
- card->netdev_stats.tx_dropped++;
+ card->netdev->stats.tx_dropped++;
break;
case GELIC_NET_DESCR_COMPLETE:
- card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes +=
- tx_chain->tail->skb->len;
+ if (tx_chain->tail->skb) {
+ card->netdev->stats.tx_packets++;
+ card->netdev->stats.tx_bytes +=
+ tx_chain->tail->skb->len;
+ }
break;
case GELIC_NET_DESCR_CARDOWNED:
/* pending tx request */
default:
/* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */
- goto out;
+ if (!stop)
+ goto out;
}
gelic_net_release_tx_descr(card, tx_chain->tail);
- release = 1;
+ release ++;
}
out:
if (!stop && release)
@@ -552,7 +550,7 @@ static int gelic_net_stop(struct net_device *netdev)
{
struct gelic_net_card *card = netdev_priv(netdev);
- netif_poll_disable(netdev);
+ napi_disable(&card->napi);
netif_stop_queue(netdev);
/* turn off DMA, force end */
@@ -589,13 +587,10 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card)
{
if (!card->tx_chain.head)
return NULL;
- /* see if we can two consecutive free descrs */
+ /* see if the next descriptor is free */
if (card->tx_chain.tail != card->tx_chain.head->next &&
gelic_net_get_descr_status(card->tx_chain.head) ==
- GELIC_NET_DESCR_NOT_IN_USE &&
- card->tx_chain.tail != card->tx_chain.head->next->next &&
- gelic_net_get_descr_status(card->tx_chain.head->next) ==
- GELIC_NET_DESCR_NOT_IN_USE )
+ GELIC_NET_DESCR_NOT_IN_USE)
return card->tx_chain.head;
else
return NULL;
@@ -606,44 +601,66 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card)
* gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
* @descr: descriptor structure to fill out
* @skb: packet to consider
- * @middle: middle of frame
*
* fills out the command and status field of the descriptor structure,
* depending on hardware checksum settings. This function assumes a wmb()
* has executed before.
*/
static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr,
- struct sk_buff *skb, int middle)
+ struct sk_buff *skb)
{
- u32 eofr;
-
- if (middle)
- eofr = 0;
- else
- eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME;
-
if (skb->ip_summed != CHECKSUM_PARTIAL)
- descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+ descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
else {
/* is packet ip?
* if yes: tcp? udp? */
if (skb->protocol == htons(ETH_P_IP)) {
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
descr->dmac_cmd_status =
- GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr;
+ GELIC_NET_DMAC_CMDSTAT_TCPCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+
else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
descr->dmac_cmd_status =
- GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr;
+ GELIC_NET_DMAC_CMDSTAT_UDPCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
else /*
* the stack should checksum non-tcp and non-udp
* packets on his own: NETIF_F_IP_CSUM
*/
descr->dmac_cmd_status =
- GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+ GELIC_NET_DMAC_CMDSTAT_NOCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
}
}
}
+static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
+ unsigned short tag)
+{
+ struct vlan_ethhdr *veth;
+ static unsigned int c;
+
+ if (skb_headroom(skb) < VLAN_HLEN) {
+ struct sk_buff *sk_tmp = skb;
+ pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c);
+ skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
+ if (!skb)
+ return NULL;
+ dev_kfree_skb_any(sk_tmp);
+ }
+ veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
+
+ /* Move the mac addresses to the top of buffer */
+ memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+
+ veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
+ veth->h_vlan_TCI = htons(tag);
+
+ return skb;
+}
+
/**
* gelic_net_prepare_tx_descr_v - get dma address of skb_data
* @card: card structure
@@ -657,66 +674,35 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
struct gelic_net_descr *descr,
struct sk_buff *skb)
{
- dma_addr_t buf[2];
- unsigned int vlan_len;
+ dma_addr_t buf;
- if (skb->len < GELIC_NET_VLAN_POS)
- return -EINVAL;
-
- memcpy(&descr->vlan, skb->data, GELIC_NET_VLAN_POS);
if (card->vlan_index != -1) {
- descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
- descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
- vlan_len = GELIC_NET_VLAN_POS + VLAN_HLEN; /* VLAN_HLEN=4 */
- } else
- vlan_len = GELIC_NET_VLAN_POS; /* no vlan tag */
-
- /* first descr */
- buf[0] = dma_map_single(ctodev(card), &descr->vlan,
- vlan_len, DMA_TO_DEVICE);
-
- if (!buf[0]) {
- dev_err(ctodev(card),
- "dma map 1 failed (%p, %i). Dropping packet\n",
- skb->data, vlan_len);
- return -ENOMEM;
+ struct sk_buff *skb_tmp;
+ skb_tmp = gelic_put_vlan_tag(skb,
+ card->vlan_id[card->vlan_index]);
+ if (!skb_tmp)
+ return -ENOMEM;
+ skb = skb_tmp;
}
- descr->buf_addr = buf[0];
- descr->buf_size = vlan_len;
- descr->skb = skb; /* not used */
- descr->data_status = 0;
- gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
-
- /* second descr */
- card->tx_chain.head = card->tx_chain.head->next;
- descr->next_descr_addr = descr->next->bus_addr;
- descr = descr->next;
- if (gelic_net_get_descr_status(descr) != GELIC_NET_DESCR_NOT_IN_USE)
- /* XXX will be removed */
- dev_err(ctodev(card), "descr is not free!\n");
+ buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
- buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS,
- skb->len - GELIC_NET_VLAN_POS,
- DMA_TO_DEVICE);
-
- if (!buf[1]) {
+ if (!buf) {
dev_err(ctodev(card),
"dma map 2 failed (%p, %i). Dropping packet\n",
- skb->data + GELIC_NET_VLAN_POS,
- skb->len - GELIC_NET_VLAN_POS);
- dma_unmap_single(ctodev(card), buf[0], vlan_len,
- DMA_TO_DEVICE);
+ skb->data, skb->len);
return -ENOMEM;
}
- descr->buf_addr = buf[1];
- descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
+ descr->buf_addr = buf;
+ descr->buf_size = skb->len;
descr->skb = skb;
descr->data_status = 0;
descr->next_descr_addr = 0; /* terminate hw descr */
- gelic_net_set_txdescr_cmdstat(descr, skb, 0);
+ gelic_net_set_txdescr_cmdstat(descr, skb);
+ /* bump free descriptor pointer */
+ card->tx_chain.head = descr->next;
return 0;
}
@@ -729,26 +715,18 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
static int gelic_net_kick_txdma(struct gelic_net_card *card,
struct gelic_net_descr *descr)
{
- int status = -ENXIO;
- int count = 10;
+ int status = 0;
if (card->tx_dma_progress)
return 0;
if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) {
card->tx_dma_progress = 1;
- /* sometimes we need retry here */
- while (count--) {
- status = lv1_net_start_tx_dma(bus_id(card),
- dev_id(card),
- descr->bus_addr, 0);
- if (!status)
- break;
- }
- if (!count)
+ status = lv1_net_start_tx_dma(bus_id(card), dev_id(card),
+ descr->bus_addr, 0);
+ if (status)
dev_info(ctodev(card), "lv1_net_start_txdma failed," \
- "status=%d %#lx\n",
- status, card->irq_status);
+ "status=%d\n", status);
}
return status;
}
@@ -763,47 +741,62 @@ static int gelic_net_kick_txdma(struct gelic_net_card *card,
static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct gelic_net_card *card = netdev_priv(netdev);
- struct gelic_net_descr *descr = NULL;
+ struct gelic_net_descr *descr;
int result;
unsigned long flags;
spin_lock_irqsave(&card->tx_dma_lock, flags);
gelic_net_release_tx_chain(card, 0);
- if (!skb)
- goto kick;
+
descr = gelic_net_get_next_tx_descr(card);
if (!descr) {
+ /*
+ * no more descriptors free
+ */
netif_stop_queue(netdev);
spin_unlock_irqrestore(&card->tx_dma_lock, flags);
return NETDEV_TX_BUSY;
}
- result = gelic_net_prepare_tx_descr_v(card, descr, skb);
-
- if (result)
- goto error;
-
- card->tx_chain.head = card->tx_chain.head->next;
- if (descr->prev)
- descr->prev->next_descr_addr = descr->bus_addr;
-kick:
+ result = gelic_net_prepare_tx_descr_v(card, descr, skb);
+ if (result) {
+ /*
+ * DMA map failed. As chanses are that failure
+ * would continue, just release skb and return
+ */
+ card->netdev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&card->tx_dma_lock, flags);
+ return NETDEV_TX_OK;
+ }
+ /*
+ * link this prepared descriptor to previous one
+ * to achieve high performance
+ */
+ descr->prev->next_descr_addr = descr->bus_addr;
/*
* as hardware descriptor is modified in the above lines,
* ensure that the hardware sees it
*/
wmb();
- if (gelic_net_kick_txdma(card, card->tx_chain.tail))
- goto error;
+ if (gelic_net_kick_txdma(card, descr)) {
+ /*
+ * kick failed.
+ * release descriptors which were just prepared
+ */
+ card->netdev->stats.tx_dropped++;
+ gelic_net_release_tx_descr(card, descr);
+ gelic_net_release_tx_descr(card, descr->next);
+ card->tx_chain.tail = descr->next->next;
+ dev_info(ctodev(card), "%s: kick failure\n", __func__);
+ } else {
+ /* OK, DMA started/reserved */
+ netdev->trans_start = jiffies;
+ }
- netdev->trans_start = jiffies;
spin_unlock_irqrestore(&card->tx_dma_lock, flags);
return NETDEV_TX_OK;
-
-error:
- card->netdev_stats.tx_dropped++;
- spin_unlock_irqrestore(&card->tx_dma_lock, flags);
- return NETDEV_TX_LOCKED;
}
/**
@@ -854,8 +847,8 @@ static void gelic_net_pass_skb_up(struct gelic_net_descr *descr,
skb->ip_summed = CHECKSUM_NONE;
/* update netdevice statistics */
- card->netdev_stats.rx_packets++;
- card->netdev_stats.rx_bytes += skb->len;
+ card->netdev->stats.rx_packets++;
+ card->netdev->stats.rx_bytes += skb->len;
/* pass skb up to stack */
netif_receive_skb(skb);
@@ -895,38 +888,67 @@ static int gelic_net_decode_one_descr(struct gelic_net_card *card)
(status == GELIC_NET_DESCR_FORCE_END)) {
dev_info(ctodev(card), "dropping RX descriptor with state %x\n",
status);
- card->netdev_stats.rx_dropped++;
+ card->netdev->stats.rx_dropped++;
goto refill;
}
- if ((status != GELIC_NET_DESCR_COMPLETE) &&
- (status != GELIC_NET_DESCR_FRAME_END)) {
+ if (status == GELIC_NET_DESCR_BUFFER_FULL) {
+ /*
+ * Buffer full would occur if and only if
+ * the frame length was longer than the size of this
+ * descriptor's buffer. If the frame length was equal
+ * to or shorter than buffer'size, FRAME_END condition
+ * would occur.
+ * Anyway this frame was longer than the MTU,
+ * just drop it.
+ */
+ dev_info(ctodev(card), "overlength frame\n");
+ goto refill;
+ }
+ /*
+ * descriptoers any other than FRAME_END here should
+ * be treated as error.
+ */
+ if (status != GELIC_NET_DESCR_FRAME_END) {
dev_dbg(ctodev(card), "RX descriptor with state %x\n",
status);
goto refill;
}
/* ok, we've got a packet in descr */
- gelic_net_pass_skb_up(descr, card); /* 1: skb_up sccess */
-
+ gelic_net_pass_skb_up(descr, card);
refill:
- descr->next_descr_addr = 0; /* unlink the descr */
+ /*
+ * So that always DMAC can see the end
+ * of the descriptor chain to avoid
+ * from unwanted DMAC overrun.
+ */
+ descr->next_descr_addr = 0;
/* change the descriptor state: */
gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
- /* refill one desc
- * FIXME: this can fail, but for now, just leave this
- * descriptor without skb
+ /*
+ * this call can fail, but for now, just leave this
+ * decriptor without skb
*/
gelic_net_prepare_rx_descr(card, descr);
+
chain->head = descr;
chain->tail = descr->next;
+
+ /*
+ * Set this descriptor the end of the chain.
+ */
descr->prev->next_descr_addr = descr->bus_addr;
+ /*
+ * If dmac chain was met, DMAC stopped.
+ * thus re-enable it
+ */
if (dmac_chain_ended) {
- gelic_net_enable_rxdmac(card);
- dev_dbg(ctodev(card), "reenable rx dma\n");
+ card->rx_dma_restart_required = 1;
+ dev_dbg(ctodev(card), "reenable rx dma scheduled\n");
}
return 1;
@@ -941,47 +963,25 @@ refill:
* if the quota is exceeded, but the driver has still packets.
*
*/
-static int gelic_net_poll(struct net_device *netdev, int *budget)
+static int gelic_net_poll(struct napi_struct *napi, int budget)
{
- struct gelic_net_card *card = netdev_priv(netdev);
- int packets_to_do, packets_done = 0;
- int no_more_packets = 0;
-
- packets_to_do = min(*budget, netdev->quota);
+ struct gelic_net_card *card = container_of(napi, struct gelic_net_card, napi);
+ struct net_device *netdev = card->netdev;
+ int packets_done = 0;
- while (packets_to_do) {
- if (gelic_net_decode_one_descr(card)) {
- packets_done++;
- packets_to_do--;
- } else {
- /* no more packets for the stack */
- no_more_packets = 1;
+ while (packets_done < budget) {
+ if (!gelic_net_decode_one_descr(card))
break;
- }
- }
- netdev->quota -= packets_done;
- *budget -= packets_done;
- if (no_more_packets) {
- netif_rx_complete(netdev);
- gelic_net_rx_irq_on(card);
- return 0;
- } else
- return 1;
-}
-/**
- * gelic_net_get_stats - get interface statistics
- * @netdev: interface device structure
- *
- * returns the interface statistics residing in the gelic_net_card struct
- */
-static struct net_device_stats *gelic_net_get_stats(struct net_device *netdev)
-{
- struct gelic_net_card *card = netdev_priv(netdev);
+ packets_done++;
+ }
- return &card->netdev_stats;
+ if (packets_done < budget) {
+ netif_rx_complete(netdev, napi);
+ gelic_net_rx_irq_on(card);
+ }
+ return packets_done;
}
-
/**
* gelic_net_change_mtu - changes the MTU of an interface
* @netdev: interface device structure
@@ -1016,17 +1016,23 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr)
if (!status)
return IRQ_NONE;
+ if (card->rx_dma_restart_required) {
+ card->rx_dma_restart_required = 0;
+ gelic_net_enable_rxdmac(card);
+ }
+
if (status & GELIC_NET_RXINT) {
gelic_net_rx_irq_off(card);
- netif_rx_schedule(netdev);
+ netif_rx_schedule(netdev, &card->napi);
}
if (status & GELIC_NET_TXINT) {
spin_lock_irqsave(&card->tx_dma_lock, flags);
card->tx_dma_progress = 0;
+ gelic_net_release_tx_chain(card, 0);
+ /* kick outstanding tx descriptor if any */
+ gelic_net_kick_txdma(card, card->tx_chain.tail);
spin_unlock_irqrestore(&card->tx_dma_lock, flags);
- /* start pending DMA */
- gelic_net_xmit(NULL, netdev);
}
return IRQ_HANDLED;
}
@@ -1068,7 +1074,7 @@ static int gelic_net_open_device(struct gelic_net_card *card)
}
result = request_irq(card->netdev->irq, gelic_net_interrupt,
- IRQF_DISABLED, "gelic network", card->netdev);
+ IRQF_DISABLED, card->netdev->name, card->netdev);
if (result) {
dev_info(ctodev(card), "%s:%d: request_irq failed (%d)\n",
@@ -1107,7 +1113,7 @@ static int gelic_net_open(struct net_device *netdev)
card->descr, GELIC_NET_TX_DESCRIPTORS))
goto alloc_tx_failed;
if (gelic_net_init_chain(card, &card->rx_chain,
- card->descr + GELIC_NET_RX_DESCRIPTORS,
+ card->descr + GELIC_NET_TX_DESCRIPTORS,
GELIC_NET_RX_DESCRIPTORS))
goto alloc_rx_failed;
@@ -1121,6 +1127,8 @@ static int gelic_net_open(struct net_device *netdev)
if (gelic_net_alloc_rx_skbs(card))
goto alloc_skbs_failed;
+ napi_enable(&card->napi);
+
card->tx_dma_progress = 0;
card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT;
@@ -1129,7 +1137,6 @@ static int gelic_net_open(struct net_device *netdev)
netif_start_queue(netdev);
netif_carrier_on(netdev);
- netif_poll_enable(netdev);
return 0;
@@ -1141,7 +1148,6 @@ alloc_tx_failed:
return -ENOMEM;
}
-#ifdef GELIC_NET_ETHTOOL
static void gelic_net_get_drvinfo (struct net_device *netdev,
struct ethtool_drvinfo *info)
{
@@ -1261,7 +1267,6 @@ static struct ethtool_ops gelic_net_ethtool_ops = {
.get_rx_csum = gelic_net_get_rx_csum,
.set_rx_csum = gelic_net_set_rx_csum,
};
-#endif
/**
* gelic_net_tx_timeout_task - task scheduled by the watchdog timeout
@@ -1320,18 +1325,12 @@ static void gelic_net_setup_netdev_ops(struct net_device *netdev)
netdev->open = &gelic_net_open;
netdev->stop = &gelic_net_stop;
netdev->hard_start_xmit = &gelic_net_xmit;
- netdev->get_stats = &gelic_net_get_stats;
netdev->set_multicast_list = &gelic_net_set_multi;
netdev->change_mtu = &gelic_net_change_mtu;
/* tx watchdog */
netdev->tx_timeout = &gelic_net_tx_timeout;
netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
- /* NAPI */
- netdev->poll = &gelic_net_poll;
- netdev->weight = GELIC_NET_NAPI_WEIGHT;
-#ifdef GELIC_NET_ETHTOOL
netdev->ethtool_ops = &gelic_net_ethtool_ops;
-#endif
}
/**
@@ -1349,8 +1348,8 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
unsigned int i;
int status;
u64 v1, v2;
+ DECLARE_MAC_BUF(mac);
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &card->dev->core);
spin_lock_init(&card->tx_dma_lock);
@@ -1358,6 +1357,9 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
gelic_net_setup_netdev_ops(netdev);
+ netif_napi_add(netdev, &card->napi,
+ gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+
netdev->features = NETIF_F_IP_CSUM;
status = lv1_net_control(bus_id(card), dev_id(card),
@@ -1372,10 +1374,8 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
v1 <<= 16;
memcpy(addr.sa_data, &v1, ETH_ALEN);
memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN);
- dev_info(ctodev(card), "MAC addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->dev_addr[0], netdev->dev_addr[1],
- netdev->dev_addr[2], netdev->dev_addr[3],
- netdev->dev_addr[4], netdev->dev_addr[5]);
+ dev_info(ctodev(card), "MAC addr %s\n",
+ print_mac(mac, netdev->dev_addr));
card->vlan_index = -1; /* no vlan */
for (i = 0; i < GELIC_NET_VLAN_MAX; i++) {
@@ -1398,8 +1398,11 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1);
}
}
- if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1])
+
+ if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) {
card->vlan_index = GELIC_NET_VLAN_WIRED - 1;
+ netdev->hard_header_len += VLAN_HLEN;
+ }
status = register_netdev(netdev);
if (status) {
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h
index 5e1c28654e16..968560269a3b 100644
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ps3_gelic_net.h
@@ -28,21 +28,12 @@
#ifndef _GELIC_NET_H
#define _GELIC_NET_H
-#define GELIC_NET_DRV_NAME "Gelic Network Driver"
-#define GELIC_NET_DRV_VERSION "1.0"
-
-#define GELIC_NET_ETHTOOL /* use ethtool */
-
-/* ioctl */
-#define GELIC_NET_GET_MODE (SIOCDEVPRIVATE + 0)
-#define GELIC_NET_SET_MODE (SIOCDEVPRIVATE + 1)
-
/* descriptors */
#define GELIC_NET_RX_DESCRIPTORS 128 /* num of descriptors */
#define GELIC_NET_TX_DESCRIPTORS 128 /* num of descriptors */
-#define GELIC_NET_MAX_MTU 2308
-#define GELIC_NET_MIN_MTU 64
+#define GELIC_NET_MAX_MTU VLAN_ETH_FRAME_LEN
+#define GELIC_NET_MIN_MTU VLAN_ETH_ZLEN
#define GELIC_NET_RXBUF_ALIGN 128
#define GELIC_NET_RX_CSUM_DEFAULT 1 /* hw chksum */
#define GELIC_NET_WATCHDOG_TIMEOUT 5*HZ
@@ -90,7 +81,8 @@ enum gelic_net_int1_status {
*/
#define GELIC_NET_RXVLNPKT 0x00200000 /* VLAN packet */
/* bit 20..16 reserved */
-#define GELIC_NET_RXRECNUM 0x0000ff00 /* reception receipt number */
+#define GELIC_NET_RXRRECNUM 0x0000ff00 /* reception receipt number */
+#define GELIC_NET_RXRRECNUM_SHIFT 8
/* bit 7..0 reserved */
#define GELIC_NET_TXDESC_TAIL 0
@@ -133,19 +125,19 @@ enum gelic_net_int1_status {
* interrupt status */
#define GELIC_NET_DMAC_CMDSTAT_CHAIN_END 0x00000002 /* RXDCEIS:DMA stopped */
-#define GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE 0xb0000000
#define GELIC_NET_DESCR_IND_PROC_SHIFT 28
#define GELIC_NET_DESCR_IND_PROC_MASKO 0x0fffffff
enum gelic_net_descr_status {
- GELIC_NET_DESCR_COMPLETE = 0x00, /* used in rx and tx */
+ GELIC_NET_DESCR_COMPLETE = 0x00, /* used in tx */
+ GELIC_NET_DESCR_BUFFER_FULL = 0x00, /* used in rx */
GELIC_NET_DESCR_RESPONSE_ERROR = 0x01, /* used in rx and tx */
GELIC_NET_DESCR_PROTECTION_ERROR = 0x02, /* used in rx and tx */
GELIC_NET_DESCR_FRAME_END = 0x04, /* used in rx */
GELIC_NET_DESCR_FORCE_END = 0x05, /* used in rx and tx */
GELIC_NET_DESCR_CARDOWNED = 0x0a, /* used in rx and tx */
- GELIC_NET_DESCR_NOT_IN_USE /* any other value */
+ GELIC_NET_DESCR_NOT_IN_USE = 0x0b /* any other value */
};
/* for lv1_net_control */
#define GELIC_NET_GET_MAC_ADDRESS 0x0000000000000001
@@ -202,6 +194,7 @@ struct gelic_net_descr_chain {
struct gelic_net_card {
struct net_device *netdev;
+ struct napi_struct napi;
/*
* hypervisor requires irq_status should be
* 8 bytes aligned, but u64 member is
@@ -216,10 +209,10 @@ struct gelic_net_card {
struct gelic_net_descr_chain tx_chain;
struct gelic_net_descr_chain rx_chain;
+ int rx_dma_restart_required;
/* gurad dmac descriptor chain*/
spinlock_t chain_lock;
- struct net_device_stats netdev_stats;
int rx_csum;
/* guard tx_dma_progress */
spinlock_t tx_dma_lock;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 8be8be451ada..30adf726743c 100755..100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -31,7 +31,6 @@
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
@@ -82,7 +81,7 @@ typedef enum {
} PHY_DEVICE_et;
typedef struct {
- PHY_DEVICE_et phyDevice;
+ PHY_DEVICE_et phyDevice;
u32 phyIdOUI;
u16 phyIdModel;
char *name;
@@ -331,7 +330,7 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
@@ -885,14 +884,14 @@ static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev)
u16 reg;
/* Enable Auto-negotiation sense */
- ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
+ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
PHYAddr[qdev->mac_index]);
reg |= PETBI_TBI_AUTO_SENSE;
- ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
+ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
- PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
@@ -946,7 +945,7 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
/* Write new PHYAD w/bit 5 set */
ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
- /*
+ /*
* Disable diagnostic mode bit 2 = 0
* Power up device bit 11 = 0
* Link up (on) and activity (blink)
@@ -956,18 +955,18 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
}
-static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
u16 phyIdReg0, u16 phyIdReg1)
{
PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
- u32 oui;
+ u32 oui;
u16 model;
- int i;
+ int i;
if (phyIdReg0 == 0xffff) {
return result;
}
-
+
if (phyIdReg1 == 0xffff) {
return result;
}
@@ -985,7 +984,7 @@ static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
printk(KERN_INFO "%s: Phy: %s\n",
qdev->ndev->name, PHY_DEVICES[i].name);
-
+
break;
}
}
@@ -1034,7 +1033,7 @@ static int ql_is_full_dup(struct ql3_adapter *qdev)
{
if (ql_mii_read_reg(qdev, 0x1A, &reg))
return 0;
-
+
return ((reg & 0x0080) && (reg & 0x1000)) != 0;
}
case PHY_VITESSE_VSC8211:
@@ -1083,19 +1082,19 @@ static int PHY_Setup(struct ql3_adapter *qdev)
/* Check if we have a Agere PHY */
if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
- /* Determine which MII address we should be using
+ /* Determine which MII address we should be using
determined by the index of the card */
if (qdev->mac_index == 0) {
miiAddr = MII_AGERE_ADDR_1;
} else {
miiAddr = MII_AGERE_ADDR_2;
}
-
+
err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
if(err != 0) {
printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
qdev->ndev->name);
- return err;
+ return err;
}
err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
@@ -1104,9 +1103,9 @@ static int PHY_Setup(struct ql3_adapter *qdev)
qdev->ndev->name);
return err;
}
-
+
/* We need to remember to initialize the Agere PHY */
- agereAddrChangeNeeded = true;
+ agereAddrChangeNeeded = true;
}
/* Determine the particular PHY we have on board to apply
@@ -1115,7 +1114,7 @@ static int PHY_Setup(struct ql3_adapter *qdev)
if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
/* need this here so address gets changed */
- phyAgereSpecificInit(qdev, miiAddr);
+ phyAgereSpecificInit(qdev, miiAddr);
} else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
return -EIO;
@@ -1428,7 +1427,7 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
static void ql_phy_reset_ex(struct ql3_adapter *qdev)
{
- ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
PHYAddr[qdev->mac_index]);
}
@@ -1439,7 +1438,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
if(qdev->phyType == PHY_AGERE_ET1011C) {
/* turn off external loopback */
- ql_mii_write_reg(qdev, 0x13, 0x0000);
+ ql_mii_write_reg(qdev, 0x13, 0x0000);
}
if(qdev->mac_index == 0)
@@ -1453,23 +1452,23 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
portConfiguration = PORT_CONFIG_DEFAULT;
/* Set the 1000 advertisements */
- ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
+ ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
PHYAddr[qdev->mac_index]);
reg &= ~PHY_GIG_ALL_PARAMS;
- if(portConfiguration &
+ if(portConfiguration &
PORT_CONFIG_FULL_DUPLEX_ENABLED &
PORT_CONFIG_1000MB_SPEED) {
reg |= PHY_GIG_ADV_1000F;
}
-
- if(portConfiguration &
+
+ if(portConfiguration &
PORT_CONFIG_HALF_DUPLEX_ENABLED &
PORT_CONFIG_1000MB_SPEED) {
reg |= PHY_GIG_ADV_1000H;
}
- ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
+ ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
PHYAddr[qdev->mac_index]);
/* Set the 10/100 & pause negotiation advertisements */
@@ -1483,7 +1482,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
if(portConfiguration & PORT_CONFIG_100MB_SPEED)
reg |= PHY_NEG_ADV_100F;
-
+
if(portConfiguration & PORT_CONFIG_10MB_SPEED)
reg |= PHY_NEG_ADV_10F;
}
@@ -1491,22 +1490,22 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
if(portConfiguration & PORT_CONFIG_100MB_SPEED)
reg |= PHY_NEG_ADV_100H;
-
+
if(portConfiguration & PORT_CONFIG_10MB_SPEED)
reg |= PHY_NEG_ADV_10H;
}
if(portConfiguration &
PORT_CONFIG_1000MB_SPEED) {
- reg |= 1;
+ reg |= 1;
}
- ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
+ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
PHYAddr[qdev->mac_index]);
ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
-
- ql_mii_write_reg_ex(qdev, CONTROL_REG,
+
+ ql_mii_write_reg_ex(qdev, CONTROL_REG,
reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
PHYAddr[qdev->mac_index]);
}
@@ -1661,7 +1660,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
"%s: Reset in progress, skip processing link "
"state.\n", qdev->ndev->name);
- spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return;
}
@@ -1753,7 +1752,7 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
return -1;
if (qdev->device_id == QL3032_DEVICE_ID)
- ql_write_page0_reg(qdev,
+ ql_write_page0_reg(qdev,
&port_regs->macMIIMgmtControlReg, 0x0f00000);
/* Divide 125MHz clock by 28 to meet PHY timing requirements */
@@ -1866,8 +1865,6 @@ static void ql_get_drvinfo(struct net_device *ndev,
strncpy(drvinfo->version, ql3xxx_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
- drvinfo->n_stats = 0;
- drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
drvinfo->eedump_len = 0;
}
@@ -1904,7 +1901,6 @@ static void ql_get_pauseparam(struct net_device *ndev,
static const struct ethtool_ops ql3xxx_ethtool_ops = {
.get_settings = ql_get_settings,
.get_drvinfo = ql_get_drvinfo,
- .get_perm_addr = ethtool_op_get_perm_addr,
.get_link = ethtool_op_get_link,
.get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel,
@@ -1940,7 +1936,7 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
@@ -2048,14 +2044,14 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
printk(KERN_WARNING "Frame short but, frame was padded and sent.\n");
}
-
+
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
/* Check the transmit response flags for any errors */
if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
printk(KERN_ERR "Frame too short to be legal, frame not sent.\n");
- qdev->stats.tx_errors++;
+ qdev->ndev->stats.tx_errors++;
retval = -EIO;
goto frame_not_sent;
}
@@ -2063,7 +2059,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
if(tx_cb->seg_count == 0) {
printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id);
- qdev->stats.tx_errors++;
+ qdev->ndev->stats.tx_errors++;
retval = -EIO;
goto invalid_seg_count;
}
@@ -2082,8 +2078,8 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
PCI_DMA_TODEVICE);
}
}
- qdev->stats.tx_packets++;
- qdev->stats.tx_bytes += tx_cb->skb->len;
+ qdev->ndev->stats.tx_packets++;
+ qdev->ndev->stats.tx_bytes += tx_cb->skb->len;
frame_not_sent:
dev_kfree_skb_irq(tx_cb->skb);
@@ -2112,13 +2108,13 @@ static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
/*
* The difference between 3022 and 3032 for inbound completions:
- * 3022 uses two buffers per completion. The first buffer contains
- * (some) header info, the second the remainder of the headers plus
- * the data. For this chip we reserve some space at the top of the
- * receive buffer so that the header info in buffer one can be
- * prepended to the buffer two. Buffer two is the sent up while
+ * 3022 uses two buffers per completion. The first buffer contains
+ * (some) header info, the second the remainder of the headers plus
+ * the data. For this chip we reserve some space at the top of the
+ * receive buffer so that the header info in buffer one can be
+ * prepended to the buffer two. Buffer two is the sent up while
* buffer one is returned to the hardware to be reused.
- * 3032 receives all of it's data and headers in one buffer for a
+ * 3032 receives all of it's data and headers in one buffer for a
* simpler process. 3032 also supports checksum verification as
* can be seen in ql_process_macip_rx_intr().
*/
@@ -2142,8 +2138,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
lrg_buf_cb2 = ql_get_lbuf(qdev);
skb = lrg_buf_cb2->skb;
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
+ qdev->ndev->stats.rx_packets++;
+ qdev->ndev->stats.rx_bytes += length;
skb_put(skb, length);
pci_unmap_single(qdev->pdev,
@@ -2209,13 +2205,13 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
skb_push(skb2, size), size);
} else {
u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
- if (checksum &
- (IB_IP_IOCB_RSP_3032_ICE |
- IB_IP_IOCB_RSP_3032_CE)) {
+ if (checksum &
+ (IB_IP_IOCB_RSP_3032_ICE |
+ IB_IP_IOCB_RSP_3032_CE)) {
printk(KERN_ERR
"%s: Bad checksum for this %s packet, checksum = %x.\n",
__func__,
- ((checksum &
+ ((checksum &
IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
"UDP"),checksum);
} else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) ||
@@ -2227,8 +2223,8 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
skb2->protocol = eth_type_trans(skb2, qdev->ndev);
netif_receive_skb(skb2);
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += length;
ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
@@ -2249,6 +2245,13 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
qdev->rsp_consumer_index) && (work_done < work_to_do)) {
net_rsp = qdev->rsp_current;
+ rmb();
+ /*
+ * Fix 4032 chipe undocumented "feature" where bit-8 is set if the
+ * inbound completion is for a VLAN.
+ */
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ net_rsp->opcode &= 0x7f;
switch (net_rsp->opcode) {
case OPCODE_OB_MAC_IOCB_FN0:
@@ -2304,10 +2307,10 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
return work_done;
}
-static int ql_poll(struct net_device *ndev, int *budget)
+static int ql_poll(struct napi_struct *napi, int budget)
{
- struct ql3_adapter *qdev = netdev_priv(ndev);
- int work_to_do = min(*budget, ndev->quota);
+ struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi);
+ struct net_device *ndev = qdev->ndev;
int rx_cleaned = 0, tx_cleaned = 0;
unsigned long hw_flags;
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
@@ -2315,16 +2318,13 @@ static int ql_poll(struct net_device *ndev, int *budget)
if (!netif_carrier_ok(ndev))
goto quit_polling;
- ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
- *budget -= rx_cleaned;
- ndev->quota -= rx_cleaned;
+ ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget);
- if( tx_cleaned + rx_cleaned != work_to_do ||
+ if (tx_cleaned + rx_cleaned != budget ||
!netif_running(ndev)) {
quit_polling:
- netif_rx_complete(ndev);
-
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ __netif_rx_complete(ndev, napi);
ql_update_small_bufq_prod_index(qdev);
ql_update_lrg_bufq_prod_index(qdev);
writel(qdev->rsp_consumer_index,
@@ -2332,9 +2332,8 @@ quit_polling:
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
ql_enable_interrupts(qdev);
- return 0;
}
- return 1;
+ return tx_cleaned + rx_cleaned;
}
static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
@@ -2384,8 +2383,8 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
spin_unlock(&qdev->adapter_lock);
} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
ql_disable_interrupts(qdev);
- if (likely(netif_rx_schedule_prep(ndev))) {
- __netif_rx_schedule(ndev);
+ if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) {
+ __netif_rx_schedule(ndev, &qdev->napi);
}
} else {
return IRQ_NONE;
@@ -2395,12 +2394,12 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
}
/*
- * Get the total number of segments needed for the
+ * Get the total number of segments needed for the
* given number of fragments. This is necessary because
* outbound address lists (OAL) will be used when more than
- * two frags are given. Each address list has 5 addr/len
+ * two frags are given. Each address list has 5 addr/len
* pairs. The 5th pair in each AOL is used to point to
- * the next AOL if more frags are coming.
+ * the next AOL if more frags are coming.
* That is why the frags:segment count ratio is not linear.
*/
static int ql_get_seg_count(struct ql3_adapter *qdev,
@@ -2477,12 +2476,12 @@ static int ql_send_map(struct ql3_adapter *qdev,
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
return NETDEV_TX_BUSY;
}
-
+
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
@@ -2512,7 +2511,7 @@ static int ql_send_map(struct ql3_adapter *qdev,
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
qdev->ndev->name, err);
goto map_error;
}
@@ -2538,7 +2537,7 @@ static int ql_send_map(struct ql3_adapter *qdev,
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
qdev->ndev->name, err);
goto map_error;
}
@@ -2559,10 +2558,10 @@ static int ql_send_map(struct ql3_adapter *qdev,
map_error:
/* A PCI mapping failed and now we will need to back out
- * We need to traverse through the oal's and associated pages which
+ * We need to traverse through the oal's and associated pages which
* have been mapped and now we must unmap them to clean up properly
*/
-
+
seg = 1;
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal = tx_cb->oal;
@@ -2600,11 +2599,11 @@ map_error:
* The difference between 3022 and 3032 sends:
* 3022 only supports a simple single segment transmission.
* 3032 supports checksumming and scatter/gather lists (fragments).
- * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
- * in the IOCB plus a chain of outbound address lists (OAL) that
- * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
- * will used to point to an OAL when more ALP entries are required.
- * The IOCB is always the top of the chain followed by one or more
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
* OALs (when necessary).
*/
static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
@@ -2618,14 +2617,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
return NETDEV_TX_BUSY;
}
-
+
tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
if((tx_cb->seg_count = ql_get_seg_count(qdev,
(skb_shinfo(skb)->nr_frags))) == -1) {
printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
return NETDEV_TX_OK;
}
-
+
mac_iocb_ptr = tx_cb->queue_entry;
memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
@@ -2637,12 +2636,12 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
if (qdev->device_id == QL3032_DEVICE_ID &&
skb->ip_summed == CHECKSUM_PARTIAL)
ql_hw_csum_setup(skb, mac_iocb_ptr);
-
+
if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) {
printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__);
return NETDEV_TX_BUSY;
}
-
+
wmb();
qdev->req_producer_index++;
if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
@@ -2740,7 +2739,7 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
"%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name);
return -ENOMEM;
}
-
+
qdev->lrg_buf_q_alloc_virt_addr =
pci_alloc_consistent(qdev->pdev,
qdev->lrg_buf_q_alloc_size,
@@ -3556,6 +3555,7 @@ static void ql_display_dev_info(struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct pci_dev *pdev = qdev->pdev;
+ DECLARE_MAC_BUF(mac);
printk(KERN_INFO PFX
"\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
@@ -3581,10 +3581,8 @@ static void ql_display_dev_info(struct net_device *ndev)
if (netif_msg_probe(qdev))
printk(KERN_INFO PFX
- "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
- ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
- ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
- ndev->dev_addr[5]);
+ "%s: MAC address %s\n",
+ ndev->name, print_mac(mac, ndev->dev_addr));
}
static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
@@ -3611,7 +3609,7 @@ static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
del_timer_sync(&qdev->adapter_timer);
- netif_poll_disable(ndev);
+ napi_disable(&qdev->napi);
if (do_reset) {
int soft_reset;
@@ -3699,7 +3697,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
- netif_poll_enable(ndev);
+ napi_enable(&qdev->napi);
ql_enable_interrupts(qdev);
return 0;
@@ -3752,12 +3750,6 @@ static int ql3xxx_open(struct net_device *ndev)
return (ql_adapter_up(qdev));
}
-static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
-{
- struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
- return &qdev->stats;
-}
-
static void ql3xxx_set_multicast_list(struct net_device *ndev)
{
/*
@@ -4010,7 +4002,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
goto err_out_free_regions;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
pci_set_drvdata(pdev, ndev);
@@ -4048,15 +4039,13 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
ndev->open = ql3xxx_open;
ndev->hard_start_xmit = ql3xxx_send;
ndev->stop = ql3xxx_close;
- ndev->get_stats = ql3xxx_get_stats;
ndev->set_multicast_list = ql3xxx_set_multicast_list;
SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
ndev->set_mac_address = ql3xxx_set_mac_address;
ndev->tx_timeout = ql3xxx_tx_timeout;
ndev->watchdog_timeo = 5 * HZ;
- ndev->poll = &ql_poll;
- ndev->weight = 64;
+ netif_napi_add(ndev, &qdev->napi, ql_poll, 64);
ndev->irq = pdev->irq;
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index 4a832c46c274..fbcb0b949639 100755..100644
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -556,7 +556,7 @@ enum {
IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
IP_ADDR_INDEX_REG_6 = 0x0008,
IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
- IP_ADDR_INDEX_REG_E = 0x0040,
+ IP_ADDR_INDEX_REG_E = 0x0040,
};
enum {
QL3032_PORT_CONTROL_DS = 0x0001,
@@ -1112,7 +1112,7 @@ struct ql_rcv_buf_cb {
* OAL has 5 entries:
* 1 thru 4 point to frags
* fifth points to next oal.
- */
+ */
#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
struct oal_entry {
@@ -1137,7 +1137,7 @@ struct ql_tx_buf_cb {
struct ob_mac_iocb_req *queue_entry ;
int seg_count;
struct oal *oal;
- struct map_list map[MAX_SKB_FRAGS+1];
+ struct map_list map[MAX_SKB_FRAGS+1];
};
/* definitions for type field */
@@ -1175,6 +1175,8 @@ struct ql3_adapter {
struct pci_dev *pdev;
struct net_device *ndev; /* Parent NET device */
+ struct napi_struct napi;
+
/* Hardware information */
u8 chip_rev_id;
u8 pci_slot;
@@ -1281,7 +1283,6 @@ struct ql3_adapter {
u32 update_ob_opcode; /* Opcode to use for updating NCB */
u32 mb_bit_mask; /* MA Bits mask to use on transmission */
u32 numPorts;
- struct net_device_stats stats;
struct workqueue_struct *workqueue;
struct delayed_work reset_work;
struct delayed_work tx_timeout_work;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index bb6896ae3151..419c00cbe6e9 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -384,6 +384,7 @@ struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev; /* Index of PCI device */
struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats; /* statistics of net device */
spinlock_t lock; /* spin lock flag */
u32 msg_enable;
@@ -443,13 +444,13 @@ static void rtl_set_rx_mode(struct net_device *dev);
static void rtl8169_tx_timeout(struct net_device *dev);
static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
- void __iomem *);
+ void __iomem *, u32 budget);
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
static void rtl8169_down(struct net_device *dev);
static void rtl8169_rx_clear(struct rtl8169_private *tp);
#ifdef CONFIG_R8169_NAPI
-static int rtl8169_poll(struct net_device *dev, int *budget);
+static int rtl8169_poll(struct napi_struct *napi, int budget);
#endif
static const unsigned int rtl8169_rx_config =
@@ -725,6 +726,12 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ if (tp->mac_version == RTL_GIGA_MAC_VER_12) {
+ /* Vendor specific (0x1f) and reserved (0x0e) MII registers. */
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_write(ioaddr, 0x0e, 0x0000);
+ }
+
tp->phy_auto_nego_reg = auto_nego;
tp->phy_1000_ctrl_reg = giga_ctrl;
@@ -970,24 +977,29 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
};
struct rtl8169_counters {
- u64 tx_packets;
- u64 rx_packets;
- u64 tx_errors;
- u32 rx_errors;
- u16 rx_missed;
- u16 align_errors;
- u32 tx_one_collision;
- u32 tx_multi_collision;
- u64 rx_unicast;
- u64 rx_broadcast;
- u32 rx_multicast;
- u16 tx_aborted;
- u16 tx_underun;
+ __le64 tx_packets;
+ __le64 rx_packets;
+ __le64 tx_errors;
+ __le32 rx_errors;
+ __le16 rx_missed;
+ __le16 align_errors;
+ __le32 tx_one_collision;
+ __le32 tx_multi_collision;
+ __le64 rx_unicast;
+ __le64 rx_broadcast;
+ __le32 rx_multicast;
+ __le16 tx_aborted;
+ __le16 tx_underun;
};
-static int rtl8169_get_stats_count(struct net_device *dev)
+static int rtl8169_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(rtl8169_gstrings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(rtl8169_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void rtl8169_get_ethtool_stats(struct net_device *dev,
@@ -1054,19 +1066,15 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.set_msglevel = rtl8169_set_msglevel,
.get_rx_csum = rtl8169_get_rx_csum,
.set_rx_csum = rtl8169_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_regs = rtl8169_get_regs,
.get_wol = rtl8169_get_wol,
.set_wol = rtl8169_set_wol,
.get_strings = rtl8169_get_strings,
- .get_stats_count = rtl8169_get_stats_count,
+ .get_sset_count = rtl8169_get_sset_count,
.get_ethtool_stats = rtl8169_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg,
@@ -1223,7 +1231,10 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
return;
}
- /* phy config for RTL8169s mac_version C chip */
+ if ((tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_03))
+ return;
+
mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1
mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000
mdio_write(ioaddr, 24, 0x65c7); //w 24 15 0 65c7
@@ -1497,7 +1508,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->dev = dev;
@@ -1648,8 +1658,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->set_mac_address = rtl_set_mac_address;
#ifdef CONFIG_R8169_NAPI
- dev->poll = rtl8169_poll;
- dev->weight = R8169_NAPI_WEIGHT;
+ netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
#endif
#ifdef CONFIG_R8169_VLAN
@@ -1769,6 +1778,10 @@ static int rtl8169_open(struct net_device *dev)
if (retval < 0)
goto err_release_ring_2;
+#ifdef CONFIG_R8169_NAPI
+ napi_enable(&tp->napi);
+#endif
+
rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -1910,7 +1923,11 @@ static void rtl_hw_start_8169(struct net_device *dev)
rtl_set_rx_max_size(ioaddr);
- rtl_set_rx_tx_config_registers(tp);
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ rtl_set_rx_tx_config_registers(tp);
tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
@@ -1933,6 +1950,14 @@ static void rtl_hw_start_8169(struct net_device *dev)
rtl_set_rx_tx_desc_registers(tp, ioaddr);
+ if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+ }
+
RTL_W8(Cfg9346, Cfg9346_Lock);
/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
@@ -1947,8 +1972,6 @@ static void rtl_hw_start_8169(struct net_device *dev)
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16(IntrMask, tp->intr_event);
-
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
}
static void rtl_hw_start_8168(struct net_device *dev)
@@ -2064,7 +2087,9 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
if (ret < 0)
goto out;
- netif_poll_enable(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_enable(&tp->napi);
+#endif
rtl_hw_start(dev);
@@ -2256,11 +2281,15 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
synchronize_irq(dev->irq);
/* Wait for any pending NAPI task to complete */
- netif_poll_disable(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_disable(&tp->napi);
+#endif
rtl8169_irq_mask_and_ack(ioaddr);
- netif_poll_enable(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_enable(&tp->napi);
+#endif
}
static void rtl8169_reinit_task(struct work_struct *work)
@@ -2304,7 +2333,7 @@ static void rtl8169_reset_task(struct work_struct *work)
rtl8169_wait_for_quiescence(dev);
- rtl8169_rx_interrupt(dev, tp, tp->mmio_addr);
+ rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0);
rtl8169_tx_clear(tp);
if (tp->dirty_rx == tp->cur_rx) {
@@ -2562,6 +2591,15 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
(TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) {
netif_wake_queue(dev);
}
+ /*
+ * 8168 hack: TxPoll requests are lost when the Tx packets are
+ * too close. Let's kick an extra TxPoll request when a burst
+ * of start_xmit activity is detected (if it is not detected,
+ * it is slow enough). -- FR
+ */
+ smp_rmb();
+ if (tp->cur_tx != dirty_tx)
+ RTL_W8(TxPoll, NPQ);
}
}
@@ -2609,14 +2647,14 @@ out:
static int rtl8169_rx_interrupt(struct net_device *dev,
struct rtl8169_private *tp,
- void __iomem *ioaddr)
+ void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
unsigned int delta, count;
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
- rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
+ rx_left = rtl8169_rx_quota(rx_left, budget);
for (; rx_left > 0; rx_left--, cur_rx++) {
unsigned int entry = cur_rx % NUM_RX_DESC;
@@ -2761,20 +2799,22 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
rtl8169_check_link_status(dev, tp, ioaddr);
#ifdef CONFIG_R8169_NAPI
- RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
- tp->intr_mask = ~tp->napi_event;
-
- if (likely(netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
- else if (netif_msg_intr(tp)) {
- printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
- dev->name, status);
+ if (status & tp->napi_event) {
+ RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+ tp->intr_mask = ~tp->napi_event;
+
+ if (likely(netif_rx_schedule_prep(dev, &tp->napi)))
+ __netif_rx_schedule(dev, &tp->napi);
+ else if (netif_msg_intr(tp)) {
+ printk(KERN_INFO "%s: interrupt %04x in poll\n",
+ dev->name, status);
+ }
}
break;
#else
/* Rx interrupt */
if (status & (RxOK | RxOverflow | RxFIFOOver))
- rtl8169_rx_interrupt(dev, tp, ioaddr);
+ rtl8169_rx_interrupt(dev, tp, ioaddr, ~(u32)0);
/* Tx interrupt */
if (status & (TxOK | TxErr))
@@ -2797,20 +2837,18 @@ out:
}
#ifdef CONFIG_R8169_NAPI
-static int rtl8169_poll(struct net_device *dev, int *budget)
+static int rtl8169_poll(struct napi_struct *napi, int budget)
{
- unsigned int work_done, work_to_do = min(*budget, dev->quota);
- struct rtl8169_private *tp = netdev_priv(dev);
+ struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
+ struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->mmio_addr;
+ int work_done;
- work_done = rtl8169_rx_interrupt(dev, tp, ioaddr);
+ work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
rtl8169_tx_interrupt(dev, tp, ioaddr);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done < work_to_do) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
tp->intr_mask = 0xffff;
/*
* 20040426: the barrier is not strictly required but the
@@ -2822,7 +2860,7 @@ static int rtl8169_poll(struct net_device *dev, int *budget)
RTL_W16(IntrMask, tp->intr_event);
}
- return (work_done >= work_to_do);
+ return work_done;
}
#endif
@@ -2851,7 +2889,7 @@ core_down:
synchronize_irq(dev->irq);
if (!poll_locked) {
- netif_poll_disable(dev);
+ napi_disable(&tp->napi);
poll_locked++;
}
@@ -2889,8 +2927,6 @@ static int rtl8169_close(struct net_device *dev)
free_irq(dev->irq, dev);
- netif_poll_enable(dev);
-
pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
tp->RxPhyAddr);
pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index df6b73872fdb..e7fd08adbbac 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -53,7 +53,6 @@ struct rionet_private {
struct rio_mport *mport;
struct sk_buff *rx_skb[RIONET_RX_RING_SIZE];
struct sk_buff *tx_skb[RIONET_TX_RING_SIZE];
- struct net_device_stats stats;
int rx_slot;
int tx_slot;
int tx_cnt;
@@ -91,12 +90,6 @@ static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
-static struct net_device_stats *rionet_stats(struct net_device *ndev)
-{
- struct rionet_private *rnet = ndev->priv;
- return &rnet->stats;
-}
-
static int rionet_rx_clean(struct net_device *ndev)
{
int i;
@@ -120,15 +113,15 @@ static int rionet_rx_clean(struct net_device *ndev)
error = netif_rx(rnet->rx_skb[i]);
if (error == NET_RX_DROP) {
- rnet->stats.rx_dropped++;
+ ndev->stats.rx_dropped++;
} else if (error == NET_RX_BAD) {
if (netif_msg_rx_err(rnet))
printk(KERN_WARNING "%s: bad rx packet\n",
DRV_NAME);
- rnet->stats.rx_errors++;
+ ndev->stats.rx_errors++;
} else {
- rnet->stats.rx_packets++;
- rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
}
} while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot);
@@ -163,8 +156,8 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
rnet->tx_skb[rnet->tx_slot] = skb;
- rnet->stats.tx_packets++;
- rnet->stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
if (++rnet->tx_cnt == RIONET_TX_RING_SIZE)
netif_stop_queue(ndev);
@@ -439,6 +432,7 @@ static int rionet_setup_netdev(struct rio_mport *mport)
struct net_device *ndev = NULL;
struct rionet_private *rnet;
u16 device_id;
+ DECLARE_MAC_BUF(mac);
/* Allocate our net_device structure */
ndev = alloc_etherdev(sizeof(struct rionet_private));
@@ -466,13 +460,10 @@ static int rionet_setup_netdev(struct rio_mport *mport)
ndev->open = &rionet_open;
ndev->hard_start_xmit = &rionet_start_xmit;
ndev->stop = &rionet_close;
- ndev->get_stats = &rionet_stats;
ndev->mtu = RIO_MAX_MSG_SIZE - 14;
ndev->features = NETIF_F_LLTX;
SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
- SET_MODULE_OWNER(ndev);
-
spin_lock_init(&rnet->lock);
spin_lock_init(&rnet->tx_lock);
@@ -482,13 +473,12 @@ static int rionet_setup_netdev(struct rio_mport *mport)
if (rc != 0)
goto out;
- printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ printk("%s: %s %s Version %s, MAC %s\n",
ndev->name,
DRV_NAME,
DRV_DESC,
DRV_VERSION,
- ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
- ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+ print_mac(mac, ndev->dev_addr));
out:
return rc;
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 5c2e41fac6d2..19152f54ef2b 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -109,7 +109,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev,
rrpriv = netdev_priv(dev);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, "rrunner")) {
@@ -127,7 +126,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev,
dev->open = &rr_open;
dev->hard_start_xmit = &rr_start_xmit;
dev->stop = &rr_close;
- dev->get_stats = &rr_get_stats;
dev->do_ioctl = &rr_ioctl;
dev->base_addr = pci_resource_start(pdev, 0);
@@ -522,7 +520,7 @@ static int __devinit rr_init(struct net_device *dev)
struct rr_regs __iomem *regs;
struct eeprom *hw = NULL;
u32 sram_size, rev;
- int i;
+ DECLARE_MAC_BUF(mac);
rrpriv = netdev_priv(dev);
regs = rrpriv->regs;
@@ -560,11 +558,7 @@ static int __devinit rr_init(struct net_device *dev)
*(u32 *)(dev->dev_addr+2) =
htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4]));
- printk(" MAC: ");
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x\n", dev->dev_addr[i]);
+ printk(" MAC: %s\n", print_mac(mac, dev->dev_addr));
sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
printk(" SRAM size 0x%06x\n", sram_size);
@@ -809,7 +803,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_CON_REJ:
printk(KERN_WARNING "%s: Connection rejected\n",
dev->name);
- rrpriv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
break;
case E_CON_TMOUT:
printk(KERN_WARNING "%s: Connection timeout\n",
@@ -818,7 +812,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_DISC_ERR:
printk(KERN_WARNING "%s: HIPPI disconnect error\n",
dev->name);
- rrpriv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
break;
case E_INT_PRTY:
printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
@@ -834,7 +828,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_TX_LINK_DROP:
printk(KERN_WARNING "%s: Link lost during transmit\n",
dev->name);
- rrpriv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
@@ -974,7 +968,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
printk("len %x, mode %x\n", pkt_len, desc->mode);
#endif
if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){
- rrpriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto defer;
}
@@ -987,7 +981,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
skb = alloc_skb(pkt_len, GFP_ATOMIC);
if (skb == NULL){
printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len);
- rrpriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto defer;
} else {
pci_dma_sync_single_for_cpu(rrpriv->pci_dev,
@@ -1025,7 +1019,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
} else {
printk("%s: Out of memory, deferring "
"packet\n", dev->name);
- rrpriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto defer;
}
}
@@ -1034,8 +1028,8 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
netif_rx(skb); /* send it up */
dev->last_rx = jiffies;
- rrpriv->stats.rx_packets++;
- rrpriv->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
defer:
desc->mode = 0;
@@ -1103,8 +1097,8 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id)
desc = &(rrpriv->tx_ring[txcon]);
skb = rrpriv->tx_skbuff[txcon];
- rrpriv->stats.tx_packets++;
- rrpriv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
pci_unmap_single(rrpriv->pci_dev,
desc->addr.addrlo, skb->len,
@@ -1492,16 +1486,6 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
-static struct net_device_stats *rr_get_stats(struct net_device *dev)
-{
- struct rr_private *rrpriv;
-
- rrpriv = netdev_priv(dev);
-
- return(&rrpriv->stats);
-}
-
-
/*
* Read the firmware out of the EEPROM and put it into the SRAM
* (or from user space - later)
diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h
index 9f3e050c4dc6..6a79825bc8cf 100644
--- a/drivers/net/rrunner.h
+++ b/drivers/net/rrunner.h
@@ -819,7 +819,6 @@ struct rr_private
u32 tx_full;
u32 fw_rev;
volatile short fw_running;
- struct net_device_stats stats;
struct pci_dev *pci_dev;
};
@@ -834,7 +833,6 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id);
static int rr_open(struct net_device *dev);
static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int rr_close(struct net_device *dev);
-static struct net_device_stats *rr_get_stats(struct net_device *dev);
static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
unsigned long offset,
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 4cb710bbe729..aef66e2d98d2 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -220,7 +220,7 @@ struct XENA_dev_config {
u64 scheduled_int_ctrl;
#define SCHED_INT_CTRL_TIMER_EN BIT(0)
#define SCHED_INT_CTRL_ONE_SHOT BIT(1)
-#define SCHED_INT_CTRL_INT2MSI TBD
+#define SCHED_INT_CTRL_INT2MSI(val) vBIT(val,10,6)
#define SCHED_INT_PERIOD TBD
u64 txreqtimeout;
@@ -325,33 +325,66 @@ struct XENA_dev_config {
#define TXDMA_TPA_INT BIT(5)
#define TXDMA_SM_INT BIT(6)
u64 pfc_err_reg;
+#define PFC_ECC_SG_ERR BIT(7)
+#define PFC_ECC_DB_ERR BIT(15)
+#define PFC_SM_ERR_ALARM BIT(23)
+#define PFC_MISC_0_ERR BIT(31)
+#define PFC_MISC_1_ERR BIT(32)
+#define PFC_PCIX_ERR BIT(39)
u64 pfc_err_mask;
u64 pfc_err_alarm;
u64 tda_err_reg;
+#define TDA_Fn_ECC_SG_ERR vBIT(0xff,0,8)
+#define TDA_Fn_ECC_DB_ERR vBIT(0xff,8,8)
+#define TDA_SM0_ERR_ALARM BIT(22)
+#define TDA_SM1_ERR_ALARM BIT(23)
+#define TDA_PCIX_ERR BIT(39)
u64 tda_err_mask;
u64 tda_err_alarm;
u64 pcc_err_reg;
-#define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8)
+#define PCC_FB_ECC_SG_ERR vBIT(0xFF,0,8)
+#define PCC_TXB_ECC_SG_ERR vBIT(0xFF,8,8)
+#define PCC_FB_ECC_DB_ERR vBIT(0xFF,16, 8)
+#define PCC_TXB_ECC_DB_ERR vBIT(0xff,24,8)
+#define PCC_SM_ERR_ALARM vBIT(0xff,32,8)
+#define PCC_WR_ERR_ALARM vBIT(0xff,40,8)
+#define PCC_N_SERR vBIT(0xff,48,8)
+#define PCC_6_COF_OV_ERR BIT(56)
+#define PCC_7_COF_OV_ERR BIT(57)
+#define PCC_6_LSO_OV_ERR BIT(58)
+#define PCC_7_LSO_OV_ERR BIT(59)
#define PCC_ENABLE_FOUR vBIT(0x0F,0,8)
-
u64 pcc_err_mask;
u64 pcc_err_alarm;
u64 tti_err_reg;
+#define TTI_ECC_SG_ERR BIT(7)
+#define TTI_ECC_DB_ERR BIT(15)
+#define TTI_SM_ERR_ALARM BIT(23)
u64 tti_err_mask;
u64 tti_err_alarm;
u64 lso_err_reg;
+#define LSO6_SEND_OFLOW BIT(12)
+#define LSO7_SEND_OFLOW BIT(13)
+#define LSO6_ABORT BIT(14)
+#define LSO7_ABORT BIT(15)
+#define LSO6_SM_ERR_ALARM BIT(22)
+#define LSO7_SM_ERR_ALARM BIT(23)
u64 lso_err_mask;
u64 lso_err_alarm;
u64 tpa_err_reg;
+#define TPA_TX_FRM_DROP BIT(7)
+#define TPA_SM_ERR_ALARM BIT(23)
+
u64 tpa_err_mask;
u64 tpa_err_alarm;
u64 sm_err_reg;
+#define SM_SM_ERR_ALARM BIT(15)
u64 sm_err_mask;
u64 sm_err_alarm;
@@ -450,22 +483,52 @@ struct XENA_dev_config {
#define RXDMA_INT_RTI_INT_M BIT(3)
u64 rda_err_reg;
+#define RDA_RXDn_ECC_SG_ERR vBIT(0xFF,0,8)
+#define RDA_RXDn_ECC_DB_ERR vBIT(0xFF,8,8)
+#define RDA_FRM_ECC_SG_ERR BIT(23)
+#define RDA_FRM_ECC_DB_N_AERR BIT(31)
+#define RDA_SM1_ERR_ALARM BIT(38)
+#define RDA_SM0_ERR_ALARM BIT(39)
+#define RDA_MISC_ERR BIT(47)
+#define RDA_PCIX_ERR BIT(55)
+#define RDA_RXD_ECC_DB_SERR BIT(63)
u64 rda_err_mask;
u64 rda_err_alarm;
u64 rc_err_reg;
+#define RC_PRCn_ECC_SG_ERR vBIT(0xFF,0,8)
+#define RC_PRCn_ECC_DB_ERR vBIT(0xFF,8,8)
+#define RC_FTC_ECC_SG_ERR BIT(23)
+#define RC_FTC_ECC_DB_ERR BIT(31)
+#define RC_PRCn_SM_ERR_ALARM vBIT(0xFF,32,8)
+#define RC_FTC_SM_ERR_ALARM BIT(47)
+#define RC_RDA_FAIL_WR_Rn vBIT(0xFF,48,8)
u64 rc_err_mask;
u64 rc_err_alarm;
u64 prc_pcix_err_reg;
+#define PRC_PCI_AB_RD_Rn vBIT(0xFF,0,8)
+#define PRC_PCI_DP_RD_Rn vBIT(0xFF,8,8)
+#define PRC_PCI_AB_WR_Rn vBIT(0xFF,16,8)
+#define PRC_PCI_DP_WR_Rn vBIT(0xFF,24,8)
+#define PRC_PCI_AB_F_WR_Rn vBIT(0xFF,32,8)
+#define PRC_PCI_DP_F_WR_Rn vBIT(0xFF,40,8)
u64 prc_pcix_err_mask;
u64 prc_pcix_err_alarm;
u64 rpa_err_reg;
+#define RPA_ECC_SG_ERR BIT(7)
+#define RPA_ECC_DB_ERR BIT(15)
+#define RPA_FLUSH_REQUEST BIT(22)
+#define RPA_SM_ERR_ALARM BIT(23)
+#define RPA_CREDIT_ERR BIT(31)
u64 rpa_err_mask;
u64 rpa_err_alarm;
u64 rti_err_reg;
+#define RTI_ECC_SG_ERR BIT(7)
+#define RTI_ECC_DB_ERR BIT(15)
+#define RTI_SM_ERR_ALARM BIT(23)
u64 rti_err_mask;
u64 rti_err_alarm;
@@ -582,17 +645,43 @@ struct XENA_dev_config {
#define MAC_INT_STATUS_RMAC_INT BIT(1)
u64 mac_tmac_err_reg;
-#define TMAC_ERR_REG_TMAC_ECC_DB_ERR BIT(15)
-#define TMAC_ERR_REG_TMAC_TX_BUF_OVRN BIT(23)
-#define TMAC_ERR_REG_TMAC_TX_CRI_ERR BIT(31)
+#define TMAC_ECC_SG_ERR BIT(7)
+#define TMAC_ECC_DB_ERR BIT(15)
+#define TMAC_TX_BUF_OVRN BIT(23)
+#define TMAC_TX_CRI_ERR BIT(31)
+#define TMAC_TX_SM_ERR BIT(39)
+#define TMAC_DESC_ECC_SG_ERR BIT(47)
+#define TMAC_DESC_ECC_DB_ERR BIT(55)
+
u64 mac_tmac_err_mask;
u64 mac_tmac_err_alarm;
u64 mac_rmac_err_reg;
-#define RMAC_ERR_REG_RX_BUFF_OVRN BIT(0)
-#define RMAC_ERR_REG_RTS_ECC_DB_ERR BIT(14)
-#define RMAC_ERR_REG_ECC_DB_ERR BIT(15)
-#define RMAC_LINK_STATE_CHANGE_INT BIT(31)
+#define RMAC_RX_BUFF_OVRN BIT(0)
+#define RMAC_FRM_RCVD_INT BIT(1)
+#define RMAC_UNUSED_INT BIT(2)
+#define RMAC_RTS_PNUM_ECC_SG_ERR BIT(5)
+#define RMAC_RTS_DS_ECC_SG_ERR BIT(6)
+#define RMAC_RD_BUF_ECC_SG_ERR BIT(7)
+#define RMAC_RTH_MAP_ECC_SG_ERR BIT(8)
+#define RMAC_RTH_SPDM_ECC_SG_ERR BIT(9)
+#define RMAC_RTS_VID_ECC_SG_ERR BIT(10)
+#define RMAC_DA_SHADOW_ECC_SG_ERR BIT(11)
+#define RMAC_RTS_PNUM_ECC_DB_ERR BIT(13)
+#define RMAC_RTS_DS_ECC_DB_ERR BIT(14)
+#define RMAC_RD_BUF_ECC_DB_ERR BIT(15)
+#define RMAC_RTH_MAP_ECC_DB_ERR BIT(16)
+#define RMAC_RTH_SPDM_ECC_DB_ERR BIT(17)
+#define RMAC_RTS_VID_ECC_DB_ERR BIT(18)
+#define RMAC_DA_SHADOW_ECC_DB_ERR BIT(19)
+#define RMAC_LINK_STATE_CHANGE_INT BIT(31)
+#define RMAC_RX_SM_ERR BIT(39)
+#define RMAC_SINGLE_ECC_ERR (BIT(5) | BIT(6) | BIT(7) |\
+ BIT(8) | BIT(9) | BIT(10)|\
+ BIT(11))
+#define RMAC_DOUBLE_ECC_ERR (BIT(13) | BIT(14) | BIT(15) |\
+ BIT(16) | BIT(17) | BIT(18)|\
+ BIT(19))
u64 mac_rmac_err_mask;
u64 mac_rmac_err_alarm;
@@ -747,10 +836,10 @@ struct XENA_dev_config {
#define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23)
#define MC_ERR_REG_SM_ERR BIT(31)
#define MC_ERR_REG_ECC_ALL_SNG (BIT(2) | BIT(3) | BIT(4) | BIT(5) |\
- BIT(6) | BIT(7) | BIT(17) | BIT(19))
+ BIT(17) | BIT(19))
#define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\
- BIT(13) | BIT(14) | BIT(15) |\
- BIT(18) | BIT(20))
+ BIT(13) | BIT(18) | BIT(20))
+#define PLL_LOCK_N BIT(39)
u64 mc_err_mask;
u64 mc_err_alarm;
@@ -824,11 +913,17 @@ struct XENA_dev_config {
#define XGXS_INT_MASK_RXGXS BIT(1)
u64 xgxs_txgxs_err_reg;
-#define TXGXS_ECC_DB_ERR BIT(15)
+#define TXGXS_ECC_SG_ERR BIT(7)
+#define TXGXS_ECC_DB_ERR BIT(15)
+#define TXGXS_ESTORE_UFLOW BIT(31)
+#define TXGXS_TX_SM_ERR BIT(39)
+
u64 xgxs_txgxs_err_mask;
u64 xgxs_txgxs_err_alarm;
u64 xgxs_rxgxs_err_reg;
+#define RXGXS_ESTORE_OFLOW BIT(7)
+#define RXGXS_RX_SM_ERR BIT(39)
u64 xgxs_rxgxs_err_mask;
u64 xgxs_rxgxs_err_alarm;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index afef6c0c59fe..22e4054d4fcb 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -32,13 +32,13 @@
* rx_ring_sz: This defines the number of receive blocks each ring can have.
* This is also an array of size 8.
* rx_ring_mode: This defines the operation mode of all 8 rings. The valid
- * values are 1, 2 and 3.
+ * values are 1, 2.
* tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
* tx_fifo_len: This too is an array of 8. Each element defines the number of
* Tx descriptors that can be associated with each corresponding FIFO.
* intr_type: This defines the type of interrupt. The values can be 0(INTA),
- * 1(MSI), 2(MSI_X). Default value is '0(INTA)'
- * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
+ * 2(MSI_X). Default value is '2(MSI_X)'
+ * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not.
* Possible values '1' for enable '0' for disable. Default is '0'
* lro_max_pkts: This parameter defines maximum number of packets can be
* aggregated as a single large packet
@@ -84,14 +84,14 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.23.1"
+#define DRV_VERSION "2.0.26.5"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
static char s2io_driver_version[] = DRV_VERSION;
-static int rxd_size[4] = {32,48,48,64};
-static int rxd_count[4] = {127,85,85,63};
+static int rxd_size[2] = {32,48};
+static int rxd_count[2] = {127,85};
static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
@@ -130,6 +130,11 @@ static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
return 0;
}
+static inline int is_s2io_card_up(const struct s2io_nic * sp)
+{
+ return test_bit(__S2IO_STATE_CARD_UP, &sp->state);
+}
+
/* Ethtool related variables and Macros. */
static char s2io_gstrings[][ETH_GSTRING_LEN] = {
"Register test\t(offline)",
@@ -263,46 +268,71 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
{"serious_err_cnt"},
{"soft_reset_cnt"},
{"fifo_full_cnt"},
- {"ring_full_cnt"},
- ("alarm_transceiver_temp_high"),
- ("alarm_transceiver_temp_low"),
- ("alarm_laser_bias_current_high"),
- ("alarm_laser_bias_current_low"),
- ("alarm_laser_output_power_high"),
- ("alarm_laser_output_power_low"),
- ("warn_transceiver_temp_high"),
- ("warn_transceiver_temp_low"),
- ("warn_laser_bias_current_high"),
- ("warn_laser_bias_current_low"),
- ("warn_laser_output_power_high"),
- ("warn_laser_output_power_low"),
- ("lro_aggregated_pkts"),
- ("lro_flush_both_count"),
- ("lro_out_of_sequence_pkts"),
- ("lro_flush_due_to_max_pkts"),
- ("lro_avg_aggr_pkts"),
- ("mem_alloc_fail_cnt"),
- ("watchdog_timer_cnt"),
- ("mem_allocated"),
- ("mem_freed"),
- ("link_up_cnt"),
- ("link_down_cnt"),
- ("link_up_time"),
- ("link_down_time"),
- ("tx_tcode_buf_abort_cnt"),
- ("tx_tcode_desc_abort_cnt"),
- ("tx_tcode_parity_err_cnt"),
- ("tx_tcode_link_loss_cnt"),
- ("tx_tcode_list_proc_err_cnt"),
- ("rx_tcode_parity_err_cnt"),
- ("rx_tcode_abort_cnt"),
- ("rx_tcode_parity_abort_cnt"),
- ("rx_tcode_rda_fail_cnt"),
- ("rx_tcode_unkn_prot_cnt"),
- ("rx_tcode_fcs_err_cnt"),
- ("rx_tcode_buf_size_err_cnt"),
- ("rx_tcode_rxd_corrupt_cnt"),
- ("rx_tcode_unkn_err_cnt")
+ {"ring_0_full_cnt"},
+ {"ring_1_full_cnt"},
+ {"ring_2_full_cnt"},
+ {"ring_3_full_cnt"},
+ {"ring_4_full_cnt"},
+ {"ring_5_full_cnt"},
+ {"ring_6_full_cnt"},
+ {"ring_7_full_cnt"},
+ {"alarm_transceiver_temp_high"},
+ {"alarm_transceiver_temp_low"},
+ {"alarm_laser_bias_current_high"},
+ {"alarm_laser_bias_current_low"},
+ {"alarm_laser_output_power_high"},
+ {"alarm_laser_output_power_low"},
+ {"warn_transceiver_temp_high"},
+ {"warn_transceiver_temp_low"},
+ {"warn_laser_bias_current_high"},
+ {"warn_laser_bias_current_low"},
+ {"warn_laser_output_power_high"},
+ {"warn_laser_output_power_low"},
+ {"lro_aggregated_pkts"},
+ {"lro_flush_both_count"},
+ {"lro_out_of_sequence_pkts"},
+ {"lro_flush_due_to_max_pkts"},
+ {"lro_avg_aggr_pkts"},
+ {"mem_alloc_fail_cnt"},
+ {"pci_map_fail_cnt"},
+ {"watchdog_timer_cnt"},
+ {"mem_allocated"},
+ {"mem_freed"},
+ {"link_up_cnt"},
+ {"link_down_cnt"},
+ {"link_up_time"},
+ {"link_down_time"},
+ {"tx_tcode_buf_abort_cnt"},
+ {"tx_tcode_desc_abort_cnt"},
+ {"tx_tcode_parity_err_cnt"},
+ {"tx_tcode_link_loss_cnt"},
+ {"tx_tcode_list_proc_err_cnt"},
+ {"rx_tcode_parity_err_cnt"},
+ {"rx_tcode_abort_cnt"},
+ {"rx_tcode_parity_abort_cnt"},
+ {"rx_tcode_rda_fail_cnt"},
+ {"rx_tcode_unkn_prot_cnt"},
+ {"rx_tcode_fcs_err_cnt"},
+ {"rx_tcode_buf_size_err_cnt"},
+ {"rx_tcode_rxd_corrupt_cnt"},
+ {"rx_tcode_unkn_err_cnt"},
+ {"tda_err_cnt"},
+ {"pfc_err_cnt"},
+ {"pcc_err_cnt"},
+ {"tti_err_cnt"},
+ {"tpa_err_cnt"},
+ {"sm_err_cnt"},
+ {"lso_err_cnt"},
+ {"mac_tmac_err_cnt"},
+ {"mac_rmac_err_cnt"},
+ {"xgxs_txgxs_err_cnt"},
+ {"xgxs_rxgxs_err_cnt"},
+ {"rc_err_cnt"},
+ {"prc_pcix_err_cnt"},
+ {"rpa_err_cnt"},
+ {"rda_err_cnt"},
+ {"rti_err_cnt"},
+ {"mc_err_cnt"}
};
#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
@@ -325,6 +355,16 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
timer.data = (unsigned long) arg; \
mod_timer(&timer, (jiffies + exp)) \
+/* copy mac addr to def_mac_addr array */
+static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr)
+{
+ sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr);
+ sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8);
+ sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16);
+ sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24);
+ sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32);
+ sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40);
+}
/* Add the vlan */
static void s2io_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
@@ -422,14 +462,15 @@ S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
S2IO_PARM_INT(shared_splits, 0);
S2IO_PARM_INT(tmac_util_period, 5);
S2IO_PARM_INT(rmac_util_period, 5);
-S2IO_PARM_INT(bimodal, 0);
S2IO_PARM_INT(l3l4hdr_size, 128);
/* Frequency of Rx desc syncs expressed as power of 2 */
S2IO_PARM_INT(rxsync_frequency, 3);
-/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
-S2IO_PARM_INT(intr_type, 0);
+/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
+S2IO_PARM_INT(intr_type, 2);
/* Large receive offload feature */
-S2IO_PARM_INT(lro, 0);
+static unsigned int lro_enable;
+module_param_named(lro, lro_enable, uint, 0);
+
/* Max pkts to be aggregated by LRO at one time. If not specified,
* aggregation happens until we hit max IP pkt size(64K)
*/
@@ -531,7 +572,7 @@ static int init_shared_mem(struct s2io_nic *nic)
for (i = 0; i < config->tx_fifo_num; i++) {
int fifo_len = config->tx_cfg[i].fifo_len;
int list_holder_size = fifo_len * sizeof(struct list_info_hold);
- mac_control->fifos[i].list_info = kmalloc(list_holder_size,
+ mac_control->fifos[i].list_info = kzalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
DBG_PRINT(INFO_DBG,
@@ -539,7 +580,6 @@ static int init_shared_mem(struct s2io_nic *nic)
return -ENOMEM;
}
mem_allocated += list_holder_size;
- memset(mac_control->fifos[i].list_info, 0, list_holder_size);
}
for (i = 0; i < config->tx_fifo_num; i++) {
int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
@@ -670,7 +710,7 @@ static int init_shared_mem(struct s2io_nic *nic)
GFP_KERNEL);
if (!rx_blocks->rxds)
return -ENOMEM;
- mem_allocated +=
+ mem_allocated +=
(sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
for (l=0; l<rxd_count[nic->rxd_mode];l++) {
rx_blocks->rxds[l].virt_addr =
@@ -701,7 +741,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(u64) tmp_p_addr_next;
}
}
- if (nic->rxd_mode >= RXD_MODE_3A) {
+ if (nic->rxd_mode == RXD_MODE_3B) {
/*
* Allocation of Storages for buffer addresses in 2BUFF mode
* and the buffers as well.
@@ -732,7 +772,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_0_org)
return -ENOMEM;
- mem_allocated +=
+ mem_allocated +=
(BUF0_LEN + ALIGN_SIZE);
tmp = (unsigned long)ba->ba_0_org;
tmp += ALIGN_SIZE;
@@ -743,7 +783,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_1_org)
return -ENOMEM;
- mem_allocated
+ mem_allocated
+= (BUF1_LEN + ALIGN_SIZE);
tmp = (unsigned long) ba->ba_1_org;
tmp += ALIGN_SIZE;
@@ -828,7 +868,7 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control->fifos[i].
list_info[mem_blks].
list_phy_addr);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= PAGE_SIZE;
}
/* If we got a zero DMA address during allocation,
@@ -843,11 +883,11 @@ static void free_shared_mem(struct s2io_nic *nic)
dev->name);
DBG_PRINT(INIT_DBG, "Virtual address %p\n",
mac_control->zerodma_virt_addr);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= PAGE_SIZE;
}
kfree(mac_control->fifos[i].list_info);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
(nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold));
}
@@ -865,12 +905,12 @@ static void free_shared_mem(struct s2io_nic *nic)
tmp_v_addr, tmp_p_addr);
nic->mac_control.stats_info->sw_stat.mem_freed += size;
kfree(mac_control->rings[i].rx_blocks[j].rxds);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
}
}
- if (nic->rxd_mode >= RXD_MODE_3A) {
+ if (nic->rxd_mode == RXD_MODE_3B) {
/* Freeing buffer storage addresses in 2BUFF mode. */
for (i = 0; i < config->rx_ring_num; i++) {
blk_cnt = config->rx_cfg[i].num_rxd /
@@ -891,11 +931,12 @@ static void free_shared_mem(struct s2io_nic *nic)
k++;
}
kfree(mac_control->rings[i].ba[j]);
- nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) *
- (rxd_count[nic->rxd_mode] + 1));
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ (sizeof(struct buffAdd) *
+ (rxd_count[nic->rxd_mode] + 1));
}
kfree(mac_control->rings[i].ba);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
(sizeof(struct buffAdd *) * blk_cnt);
}
}
@@ -905,12 +946,12 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control->stats_mem_sz,
mac_control->stats_mem,
mac_control->stats_mem_phy);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
mac_control->stats_mem_sz;
}
if (nic->ufo_in_band_v) {
kfree(nic->ufo_in_band_v);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (ufo_size * sizeof(u64));
}
}
@@ -1455,7 +1496,7 @@ static int init_nic(struct s2io_nic *nic)
&bar0->rts_frm_len_n[i]);
}
}
-
+
/* Disable differentiated services steering logic */
for (i = 0; i < 64; i++) {
if (rts_ds_steer(nic, i, 0) == FAILURE) {
@@ -1535,90 +1576,57 @@ static int init_nic(struct s2io_nic *nic)
time++;
}
- if (nic->config.bimodal) {
- int k = 0;
- for (k = 0; k < config->rx_ring_num; k++) {
- val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
- val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
- writeq(val64, &bar0->tti_command_mem);
-
+ /* RTI Initialization */
+ if (nic->device_type == XFRAME_II_DEVICE) {
/*
- * Once the operation completes, the Strobe bit of the command
- * register will be reset. We poll for this particular condition
- * We wait for a maximum of 500ms for the operation to complete,
- * if it's not complete by then we return error.
- */
- time = 0;
- while (TRUE) {
- val64 = readq(&bar0->tti_command_mem);
- if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
- break;
- }
- if (time > 10) {
- DBG_PRINT(ERR_DBG,
- "%s: TTI init Failed\n",
- dev->name);
- return -1;
- }
- time++;
- msleep(50);
- }
- }
- } else {
-
- /* RTI Initialization */
- if (nic->device_type == XFRAME_II_DEVICE) {
- /*
- * Programmed to generate Apprx 500 Intrs per
- * second
- */
- int count = (nic->config.bus_speed * 125)/4;
- val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
- } else {
- val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
- }
- val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
- RTI_DATA1_MEM_RX_URNG_B(0x10) |
- RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
-
- writeq(val64, &bar0->rti_data1_mem);
+ * Programmed to generate Apprx 500 Intrs per
+ * second
+ */
+ int count = (nic->config.bus_speed * 125)/4;
+ val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
+ } else
+ val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
+ val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
+ RTI_DATA1_MEM_RX_URNG_B(0x10) |
+ RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
+
+ writeq(val64, &bar0->rti_data1_mem);
+
+ val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
+ RTI_DATA2_MEM_RX_UFC_B(0x2) ;
+ if (nic->config.intr_type == MSI_X)
+ val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
+ RTI_DATA2_MEM_RX_UFC_D(0x40));
+ else
+ val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
+ RTI_DATA2_MEM_RX_UFC_D(0x80));
+ writeq(val64, &bar0->rti_data2_mem);
- val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
- RTI_DATA2_MEM_RX_UFC_B(0x2) ;
- if (nic->intr_type == MSI_X)
- val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
- RTI_DATA2_MEM_RX_UFC_D(0x40));
- else
- val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
- RTI_DATA2_MEM_RX_UFC_D(0x80));
- writeq(val64, &bar0->rti_data2_mem);
+ for (i = 0; i < config->rx_ring_num; i++) {
+ val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
+ | RTI_CMD_MEM_OFFSET(i);
+ writeq(val64, &bar0->rti_command_mem);
- for (i = 0; i < config->rx_ring_num; i++) {
- val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
- | RTI_CMD_MEM_OFFSET(i);
- writeq(val64, &bar0->rti_command_mem);
+ /*
+ * Once the operation completes, the Strobe bit of the
+ * command register will be reset. We poll for this
+ * particular condition. We wait for a maximum of 500ms
+ * for the operation to complete, if it's not complete
+ * by then we return error.
+ */
+ time = 0;
+ while (TRUE) {
+ val64 = readq(&bar0->rti_command_mem);
+ if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD))
+ break;
- /*
- * Once the operation completes, the Strobe bit of the
- * command register will be reset. We poll for this
- * particular condition. We wait for a maximum of 500ms
- * for the operation to complete, if it's not complete
- * by then we return error.
- */
- time = 0;
- while (TRUE) {
- val64 = readq(&bar0->rti_command_mem);
- if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
- break;
- }
- if (time > 10) {
- DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
- dev->name);
- return -1;
- }
- time++;
- msleep(50);
+ if (time > 10) {
+ DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
+ dev->name);
+ return -1;
}
+ time++;
+ msleep(50);
}
}
@@ -1723,7 +1731,7 @@ static int init_nic(struct s2io_nic *nic)
static int s2io_link_fault_indication(struct s2io_nic *nic)
{
- if (nic->intr_type != INTA)
+ if (nic->config.intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
if (nic->device_type == XFRAME_II_DEVICE)
return LINK_UP_DOWN_INTERRUPT;
@@ -1732,6 +1740,150 @@ static int s2io_link_fault_indication(struct s2io_nic *nic)
}
/**
+ * do_s2io_write_bits - update alarm bits in alarm register
+ * @value: alarm bits
+ * @flag: interrupt status
+ * @addr: address value
+ * Description: update alarm bits in alarm register
+ * Return Value:
+ * NONE.
+ */
+static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr)
+{
+ u64 temp64;
+
+ temp64 = readq(addr);
+
+ if(flag == ENABLE_INTRS)
+ temp64 &= ~((u64) value);
+ else
+ temp64 |= ((u64) value);
+ writeq(temp64, addr);
+}
+
+static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag)
+{
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
+ register u64 gen_int_mask = 0;
+
+ if (mask & TX_DMA_INTR) {
+
+ gen_int_mask |= TXDMA_INT_M;
+
+ do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT |
+ TXDMA_PCC_INT | TXDMA_TTI_INT |
+ TXDMA_LSO_INT | TXDMA_TPA_INT |
+ TXDMA_SM_INT, flag, &bar0->txdma_int_mask);
+
+ do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM |
+ PFC_MISC_0_ERR | PFC_MISC_1_ERR |
+ PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag,
+ &bar0->pfc_err_mask);
+
+ do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
+ TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR |
+ TDA_PCIX_ERR, flag, &bar0->tda_err_mask);
+
+ do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR |
+ PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM |
+ PCC_N_SERR | PCC_6_COF_OV_ERR |
+ PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR |
+ PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR |
+ PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask);
+
+ do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR |
+ TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask);
+
+ do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT |
+ LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM |
+ LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
+ flag, &bar0->lso_err_mask);
+
+ do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP,
+ flag, &bar0->tpa_err_mask);
+
+ do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask);
+
+ }
+
+ if (mask & TX_MAC_INTR) {
+ gen_int_mask |= TXMAC_INT_M;
+ do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag,
+ &bar0->mac_int_mask);
+ do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR |
+ TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR |
+ TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
+ flag, &bar0->mac_tmac_err_mask);
+ }
+
+ if (mask & TX_XGXS_INTR) {
+ gen_int_mask |= TXXGXS_INT_M;
+ do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag,
+ &bar0->xgxs_int_mask);
+ do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR |
+ TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
+ flag, &bar0->xgxs_txgxs_err_mask);
+ }
+
+ if (mask & RX_DMA_INTR) {
+ gen_int_mask |= RXDMA_INT_M;
+ do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M |
+ RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M,
+ flag, &bar0->rxdma_int_mask);
+ do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR |
+ RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM |
+ RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR |
+ RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask);
+ do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn |
+ PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn |
+ PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag,
+ &bar0->prc_pcix_err_mask);
+ do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR |
+ RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag,
+ &bar0->rpa_err_mask);
+ do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR |
+ RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM |
+ RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR |
+ RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR,
+ flag, &bar0->rda_err_mask);
+ do_s2io_write_bits(RTI_SM_ERR_ALARM |
+ RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
+ flag, &bar0->rti_err_mask);
+ }
+
+ if (mask & RX_MAC_INTR) {
+ gen_int_mask |= RXMAC_INT_M;
+ do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag,
+ &bar0->mac_int_mask);
+ do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR |
+ RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR |
+ RMAC_DOUBLE_ECC_ERR |
+ RMAC_LINK_STATE_CHANGE_INT,
+ flag, &bar0->mac_rmac_err_mask);
+ }
+
+ if (mask & RX_XGXS_INTR)
+ {
+ gen_int_mask |= RXXGXS_INT_M;
+ do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag,
+ &bar0->xgxs_int_mask);
+ do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag,
+ &bar0->xgxs_rxgxs_err_mask);
+ }
+
+ if (mask & MC_INTR) {
+ gen_int_mask |= MC_INT_M;
+ do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask);
+ do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG |
+ MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag,
+ &bar0->mc_err_mask);
+ }
+ nic->general_int_mask = gen_int_mask;
+
+ /* Remove this line when alarm interrupts are enabled */
+ nic->general_int_mask = 0;
+}
+/**
* en_dis_able_nic_intrs - Enable or Disable the interrupts
* @nic: device private variable,
* @mask: A mask indicating which Intr block must be modified and,
@@ -1745,17 +1897,16 @@ static int s2io_link_fault_indication(struct s2io_nic *nic)
static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
- register u64 val64 = 0, temp64 = 0;
+ register u64 temp64 = 0, intr_mask = 0;
+
+ intr_mask = nic->general_int_mask;
/* Top level interrupt classification */
/* PIC Interrupts */
- if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
+ if (mask & TX_PIC_INTR) {
/* Enable PIC Intrs in the general intr mask register */
- val64 = TXPIC_INT_M;
+ intr_mask |= TXPIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/*
* If Hercules adapter enable GPIO otherwise
* disable all PCIX, Flash, MDIO, IIC and GPIO
@@ -1764,64 +1915,25 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
*/
if (s2io_link_fault_indication(nic) ==
LINK_UP_DOWN_INTERRUPT ) {
- temp64 = readq(&bar0->pic_int_mask);
- temp64 &= ~((u64) PIC_INT_GPIO);
- writeq(temp64, &bar0->pic_int_mask);
- temp64 = readq(&bar0->gpio_int_mask);
- temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
- writeq(temp64, &bar0->gpio_int_mask);
- } else {
+ do_s2io_write_bits(PIC_INT_GPIO, flag,
+ &bar0->pic_int_mask);
+ do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag,
+ &bar0->gpio_int_mask);
+ } else
writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
- }
- /*
- * No MSI Support is available presently, so TTI and
- * RTI interrupts are also disabled.
- */
} else if (flag == DISABLE_INTRS) {
/*
* Disable PIC Intrs in the general
* intr mask register
*/
writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* MAC Interrupts */
- /* Enabling/Disabling MAC interrupts */
- if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
- val64 = TXMAC_INT_M | RXMAC_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All MAC block error interrupts are disabled for now
- * TODO
- */
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MAC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
- writeq(DISABLE_ALL_INTRS,
- &bar0->mac_rmac_err_mask);
-
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
/* Tx traffic interrupts */
if (mask & TX_TRAFFIC_INTR) {
- val64 = TXTRAFFIC_INT_M;
+ intr_mask |= TXTRAFFIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/*
* Enable all the Tx side interrupts
* writing 0 Enables all 64 TX interrupt levels
@@ -1833,19 +1945,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
* register.
*/
writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
/* Rx traffic interrupts */
if (mask & RX_TRAFFIC_INTR) {
- val64 = RXTRAFFIC_INT_M;
+ intr_mask |= RXTRAFFIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/* writing 0 Enables all 8 RX interrupt levels */
writeq(0x0, &bar0->rx_traffic_mask);
} else if (flag == DISABLE_INTRS) {
@@ -1854,11 +1960,17 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
* register.
*/
writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
+
+ temp64 = readq(&bar0->general_int_mask);
+ if (flag == ENABLE_INTRS)
+ temp64 &= ~((u64) intr_mask);
+ else
+ temp64 = DISABLE_ALL_INTRS;
+ writeq(temp64, &bar0->general_int_mask);
+
+ nic->general_int_mask = readq(&bar0->general_int_mask);
}
/**
@@ -1871,7 +1983,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
int ret = 0, herc;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = readq(&bar0->adapter_status);
-
+
herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
@@ -2017,8 +2129,6 @@ static int start_nic(struct s2io_nic *nic)
&bar0->prc_rxd0_n[i]);
val64 = readq(&bar0->prc_ctrl_n[i]);
- if (nic->config.bimodal)
- val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
if (nic->rxd_mode == RXD_MODE_1)
val64 |= PRC_CTRL_RC_ENABLED;
else
@@ -2062,14 +2172,6 @@ static int start_nic(struct s2io_nic *nic)
writeq(val64, &bar0->adapter_control);
/*
- * Clearing any possible Link state change interrupts that
- * could have popped up just before Enabling the card.
- */
- val64 = readq(&bar0->mac_rmac_err_reg);
- if (val64)
- writeq(val64, &bar0->mac_rmac_err_reg);
-
- /*
* Verify if the device is ready to be enabled, if so enable
* it.
*/
@@ -2186,7 +2288,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
mac_control->fifos[i].list_info[j].list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
cnt++;
@@ -2222,9 +2324,9 @@ static void stop_nic(struct s2io_nic *nic)
config = &nic->config;
/* Disable all interrupts */
+ en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS);
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ interruptible |= TX_PIC_INTR;
en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
/* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
@@ -2233,44 +2335,6 @@ static void stop_nic(struct s2io_nic *nic)
writeq(val64, &bar0->adapter_control);
}
-static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
- sk_buff *skb)
-{
- struct net_device *dev = nic->dev;
- struct sk_buff *frag_list;
- void *tmp;
-
- /* Buffer-1 receives L3/L4 headers */
- ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
- (nic->pdev, skb->data, l3l4hdr_size + 4,
- PCI_DMA_FROMDEVICE);
-
- /* skb_shinfo(skb)->frag_list will have L4 data payload */
- skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
- if (skb_shinfo(skb)->frag_list == NULL) {
- nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
- DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
- return -ENOMEM ;
- }
- frag_list = skb_shinfo(skb)->frag_list;
- skb->truesize += frag_list->truesize;
- nic->mac_control.stats_info->sw_stat.mem_allocated
- += frag_list->truesize;
- frag_list->next = NULL;
- tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
- frag_list->data = tmp;
- skb_reset_tail_pointer(frag_list);
-
- /* Buffer-2 receives L4 data payload */
- ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
- frag_list->data, dev->mtu,
- PCI_DMA_FROMDEVICE);
- rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
- rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
-
- return SUCCESS;
-}
-
/**
* fill_rx_buffers - Allocates the Rx side skbs
* @nic: device private variable
@@ -2307,6 +2371,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
unsigned long flags;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
+ struct RxD1 *rxdp1;
+ struct RxD3 *rxdp3;
+ struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2359,7 +2426,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
(block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
}
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
- ((nic->rxd_mode >= RXD_MODE_3A) &&
+ ((nic->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & BIT(0)))) {
mac_control->rings[ring_no].rx_curr_put_info.
offset = off;
@@ -2370,10 +2437,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
if (nic->rxd_mode == RXD_MODE_1)
size += NET_IP_ALIGN;
- else if (nic->rxd_mode == RXD_MODE_3B)
- size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
else
- size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
+ size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
/* allocate skb */
skb = dev_alloc_skb(size);
@@ -2388,37 +2453,39 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
mem_alloc_fail_cnt++;
return -ENOMEM ;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+= skb->truesize;
if (nic->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);
- ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
+ rxdp1->Buffer0_ptr = pci_map_single
(nic->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
- rxdp->Control_2 =
+ if( (rxdp1->Buffer0_ptr == 0) ||
+ (rxdp1->Buffer0_ptr ==
+ DMA_ERROR_CODE))
+ goto pci_map_failed;
+
+ rxdp->Control_2 =
SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
- } else if (nic->rxd_mode >= RXD_MODE_3A) {
+ } else if (nic->rxd_mode == RXD_MODE_3B) {
/*
- * 2 or 3 buffer mode -
- * Both 2 buffer mode and 3 buffer mode provides 128
+ * 2 buffer mode -
+ * 2 buffer mode provides 128
* byte aligned receive buffers.
- *
- * 3 buffer mode provides header separation where in
- * skb->data will have L3/L4 headers where as
- * skb_shinfo(skb)->frag_list will have the L4 data
- * payload
*/
+ rxdp3 = (struct RxD3*)rxdp;
/* save buffer pointers to avoid frequent dma mapping */
- Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
- Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
+ Buffer0_ptr = rxdp3->Buffer0_ptr;
+ Buffer1_ptr = rxdp3->Buffer1_ptr;
memset(rxdp, 0, sizeof(struct RxD3));
/* restore the buffer pointers for dma sync*/
- ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
- ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+ rxdp3->Buffer0_ptr = Buffer0_ptr;
+ rxdp3->Buffer1_ptr = Buffer1_ptr;
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
@@ -2428,14 +2495,18 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
skb->data = (void *) (unsigned long)tmp;
skb_reset_tail_pointer(skb);
- if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
- ((struct RxD3*)rxdp)->Buffer0_ptr =
+ if (!(rxdp3->Buffer0_ptr))
+ rxdp3->Buffer0_ptr =
pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
else
pci_dma_sync_single_for_device(nic->pdev,
- (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
+ (dma_addr_t) rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
+ if( (rxdp3->Buffer0_ptr == 0) ||
+ (rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
+ goto pci_map_failed;
+
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
@@ -2444,33 +2515,30 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* Buffer2 will have L3/L4 header plus
* L4 payload
*/
- ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
+ rxdp3->Buffer2_ptr = pci_map_single
(nic->pdev, skb->data, dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- /* Buffer-1 will be dummy buffer. Not used */
- if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
- ((struct RxD3*)rxdp)->Buffer1_ptr =
+ if( (rxdp3->Buffer2_ptr == 0) ||
+ (rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
+ goto pci_map_failed;
+
+ rxdp3->Buffer1_ptr =
pci_map_single(nic->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,
+ 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);
- } else {
- /* 3 buffer mode */
- if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
- nic->mac_control.stats_info->sw_stat.\
- mem_freed += skb->truesize;
- dev_kfree_skb_irq(skb);
- if (first_rxdp) {
- wmb();
- first_rxdp->Control_1 |=
- RXD_OWN_XENA;
- }
- return -ENOMEM ;
- }
}
rxdp->Control_2 |= BIT(0);
}
@@ -2505,6 +2573,11 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
return SUCCESS;
+pci_map_failed:
+ stats->pci_map_fail_cnt++;
+ stats->mem_freed += skb->truesize;
+ dev_kfree_skb_irq(skb);
+ return -ENOMEM;
}
static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
@@ -2515,6 +2588,8 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
struct RxD_t *rxdp;
struct mac_info *mac_control;
struct buffAdd *ba;
+ struct RxD1 *rxdp1;
+ struct RxD3 *rxdp3;
mac_control = &sp->mac_control;
for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2526,40 +2601,30 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
continue;
}
if (sp->rxd_mode == RXD_MODE_1) {
+ rxdp1 = (struct RxD1*)rxdp;
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD1*)rxdp)->Buffer0_ptr,
- dev->mtu +
- HEADER_ETHERNET_II_802_3_SIZE
- + HEADER_802_2_SIZE +
- HEADER_SNAP_SIZE,
- PCI_DMA_FROMDEVICE);
+ rxdp1->Buffer0_ptr,
+ dev->mtu +
+ HEADER_ETHERNET_II_802_3_SIZE
+ + HEADER_802_2_SIZE +
+ HEADER_SNAP_SIZE,
+ PCI_DMA_FROMDEVICE);
memset(rxdp, 0, sizeof(struct RxD1));
} else if(sp->rxd_mode == RXD_MODE_3B) {
+ rxdp3 = (struct RxD3*)rxdp;
ba = &mac_control->rings[ring_no].
ba[blk][j];
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer0_ptr,
- BUF0_LEN,
- PCI_DMA_FROMDEVICE);
- pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer1_ptr,
- BUF1_LEN,
- PCI_DMA_FROMDEVICE);
- pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer2_ptr,
- dev->mtu + 4,
- PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(struct RxD3));
- } else {
- pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ rxdp3->Buffer0_ptr,
+ BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer1_ptr,
- l3l4hdr_size + 4,
+ rxdp3->Buffer1_ptr,
+ BUF1_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
+ rxdp3->Buffer2_ptr,
+ dev->mtu + 4,
PCI_DMA_FROMDEVICE);
memset(rxdp, 0, sizeof(struct RxD3));
}
@@ -2604,7 +2669,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
/**
* s2io_poll - Rx interrupt handler for NAPI support
- * @dev : pointer to the device structure.
+ * @napi : pointer to the napi structure.
* @budget : The number of packets that were budgeted to be processed
* during one pass through the 'Poll" function.
* Description:
@@ -2615,22 +2680,23 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed.
*/
-static int s2io_poll(struct net_device *dev, int *budget)
+static int s2io_poll(struct napi_struct *napi, int budget)
{
- struct s2io_nic *nic = dev->priv;
+ struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
+ struct net_device *dev = nic->dev;
int pkt_cnt = 0, org_pkts_to_process;
struct mac_info *mac_control;
struct config_param *config;
struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i;
- atomic_inc(&nic->isr_cnt);
+ if (!is_s2io_card_up(nic))
+ return 0;
+
mac_control = &nic->mac_control;
config = &nic->config;
- nic->pkts_to_process = *budget;
- if (nic->pkts_to_process > dev->quota)
- nic->pkts_to_process = dev->quota;
+ nic->pkts_to_process = budget;
org_pkts_to_process = nic->pkts_to_process;
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
@@ -2644,12 +2710,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
goto no_rx;
}
}
- if (!pkt_cnt)
- pkt_cnt = 1;
- dev->quota -= pkt_cnt;
- *budget -= pkt_cnt;
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
@@ -2661,13 +2723,9 @@ static int s2io_poll(struct net_device *dev, int *budget)
/* Re enable the Rx interrupts. */
writeq(0x0, &bar0->rx_traffic_mask);
readl(&bar0->rx_traffic_mask);
- atomic_dec(&nic->isr_cnt);
- return 0;
+ return pkt_cnt;
no_rx:
- dev->quota -= pkt_cnt;
- *budget -= pkt_cnt;
-
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
@@ -2675,8 +2733,7 @@ no_rx:
break;
}
}
- atomic_dec(&nic->isr_cnt);
- return 1;
+ return pkt_cnt;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2703,7 +2760,6 @@ static void s2io_netpoll(struct net_device *dev)
disable_irq(dev->irq);
- atomic_inc(&nic->isr_cnt);
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2728,7 +2784,6 @@ static void s2io_netpoll(struct net_device *dev)
break;
}
}
- atomic_dec(&nic->isr_cnt);
enable_irq(dev->irq);
return;
}
@@ -2756,14 +2811,10 @@ static void rx_intr_handler(struct ring_info *ring_data)
struct sk_buff *skb;
int pkt_cnt = 0;
int i;
+ struct RxD1* rxdp1;
+ struct RxD3* rxdp3;
spin_lock(&nic->rx_lock);
- if (atomic_read(&nic->card_state) == CARD_DOWN) {
- DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
- __FUNCTION__, dev->name);
- spin_unlock(&nic->rx_lock);
- return;
- }
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
@@ -2796,32 +2847,23 @@ static void rx_intr_handler(struct ring_info *ring_data)
return;
}
if (nic->rxd_mode == RXD_MODE_1) {
+ rxdp1 = (struct RxD1*)rxdp;
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((struct RxD1*)rxdp)->Buffer0_ptr,
- dev->mtu +
- HEADER_ETHERNET_II_802_3_SIZE +
- HEADER_802_2_SIZE +
- HEADER_SNAP_SIZE,
- PCI_DMA_FROMDEVICE);
+ rxdp1->Buffer0_ptr,
+ dev->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) {
+ rxdp3 = (struct RxD3*)rxdp;
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer0_ptr,
- BUF0_LEN, PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer2_ptr,
- dev->mtu + 4,
- PCI_DMA_FROMDEVICE);
- } else {
- pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
- PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer1_ptr,
- l3l4hdr_size + 4,
- PCI_DMA_FROMDEVICE);
+ rxdp3->Buffer0_ptr,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((struct RxD3*)rxdp)->Buffer2_ptr,
- dev->mtu, PCI_DMA_FROMDEVICE);
+ rxdp3->Buffer2_ptr,
+ dev->mtu + 4,
+ PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
rx_osm_handler(ring_data, rxdp);
@@ -3207,135 +3249,6 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
}
/**
- * alarm_intr_handler - Alarm Interrrupt handler
- * @nic: device private variable
- * Description: If the interrupt was neither because of Rx packet or Tx
- * complete, this function is called. If the interrupt was to indicate
- * a loss of link, the OSM link status handler is invoked for any other
- * alarm interrupt the block that raised the interrupt is displayed
- * and a H/W reset is issued.
- * Return Value:
- * NONE
-*/
-
-static void alarm_intr_handler(struct s2io_nic *nic)
-{
- struct net_device *dev = (struct net_device *) nic->dev;
- struct XENA_dev_config __iomem *bar0 = nic->bar0;
- register u64 val64 = 0, err_reg = 0;
- u64 cnt;
- int i;
- if (atomic_read(&nic->card_state) == CARD_DOWN)
- return;
- if (pci_channel_offline(nic->pdev))
- return;
- nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
- /* Handling the XPAK counters update */
- if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
- /* waiting for an hour */
- nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
- } else {
- s2io_updt_xpak_counter(dev);
- /* reset the count to zero */
- nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
- }
-
- /* Handling link status change error Intr */
- if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
- err_reg = readq(&bar0->mac_rmac_err_reg);
- writeq(err_reg, &bar0->mac_rmac_err_reg);
- if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
- schedule_work(&nic->set_link_task);
- }
- }
-
- /* Handling Ecc errors */
- val64 = readq(&bar0->mc_err_reg);
- writeq(val64, &bar0->mc_err_reg);
- if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
- if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
- nic->mac_control.stats_info->sw_stat.
- double_ecc_errs++;
- DBG_PRINT(INIT_DBG, "%s: Device indicates ",
- dev->name);
- DBG_PRINT(INIT_DBG, "double ECC error!!\n");
- if (nic->device_type != XFRAME_II_DEVICE) {
- /* Reset XframeI only if critical error */
- if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
- MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.
- soft_reset_cnt++;
- }
- }
- } else {
- nic->mac_control.stats_info->sw_stat.
- single_ecc_errs++;
- }
- }
-
- /* In case of a serious error, the device will be Reset. */
- val64 = readq(&bar0->serr_source);
- if (val64 & SERR_SOURCE_ANY) {
- nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
- DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
- DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
- (unsigned long long)val64);
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
- }
-
- /*
- * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
- * Error occurs, the adapter will be recycled by disabling the
- * adapter enable bit and enabling it again after the device
- * becomes Quiescent.
- */
- val64 = readq(&bar0->pcc_err_reg);
- writeq(val64, &bar0->pcc_err_reg);
- if (val64 & PCC_FB_ECC_DB_ERR) {
- u64 ac = readq(&bar0->adapter_control);
- ac &= ~(ADAPTER_CNTL_EN);
- writeq(ac, &bar0->adapter_control);
- ac = readq(&bar0->adapter_control);
- schedule_work(&nic->set_link_task);
- }
- /* Check for data parity error */
- val64 = readq(&bar0->pic_int_status);
- if (val64 & PIC_INT_GPIO) {
- val64 = readq(&bar0->gpio_int_reg);
- if (val64 & GPIO_INT_REG_DP_ERR_INT) {
- nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
- }
- }
-
- /* Check for ring full counter */
- if (nic->device_type & XFRAME_II_DEVICE) {
- val64 = readq(&bar0->ring_bump_counter1);
- for (i=0; i<4; i++) {
- cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
- cnt >>= 64 - ((i+1)*16);
- nic->mac_control.stats_info->sw_stat.ring_full_cnt
- += cnt;
- }
-
- val64 = readq(&bar0->ring_bump_counter2);
- for (i=0; i<4; i++) {
- cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
- cnt >>= 64 - ((i+1)*16);
- nic->mac_control.stats_info->sw_stat.ring_full_cnt
- += cnt;
- }
- }
-
- /* Other type of interrupts are not being handled now, TODO */
-}
-
-/**
* wait_for_cmd_complete - waits for a command to complete.
* @sp : private member of the device structure, which is a pointer to the
* s2io_nic structure.
@@ -3425,23 +3338,8 @@ static void s2io_reset(struct s2io_nic * sp)
/* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
- if (sp->device_type == XFRAME_II_DEVICE) {
- int ret;
- ret = pci_set_power_state(sp->pdev, 3);
- if (!ret)
- ret = pci_set_power_state(sp->pdev, 0);
- else {
- DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
- __FUNCTION__);
- goto old_way;
- }
- msleep(20);
- goto new_way;
- }
-old_way:
val64 = SW_RESET_ALL;
writeq(val64, &bar0->sw_reset);
-new_way:
if (strstr(sp->product_name, "CX4")) {
msleep(750);
}
@@ -3484,7 +3382,7 @@ new_way:
/* Reset device statistics maintained by OS */
memset(&sp->stats, 0, sizeof (struct net_device_stats));
-
+
up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt;
down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt;
up_time = sp->mac_control.stats_info->sw_stat.link_up_time;
@@ -3526,7 +3424,7 @@ new_way:
}
/* restore the previously assigned mac address */
- s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
+ do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
sp->device_enabled_once = FALSE;
}
@@ -3623,7 +3521,7 @@ static int s2io_set_swapper(struct s2io_nic * sp)
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
- if (sp->intr_type == INTA)
+ if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#else
@@ -3646,7 +3544,7 @@ static int s2io_set_swapper(struct s2io_nic * sp)
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
- if (sp->intr_type == INTA)
+ if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#endif
@@ -3731,56 +3629,6 @@ static void store_xmsi_data(struct s2io_nic *nic)
}
}
-int s2io_enable_msi(struct s2io_nic *nic)
-{
- struct XENA_dev_config __iomem *bar0 = nic->bar0;
- u16 msi_ctrl, msg_val;
- struct config_param *config = &nic->config;
- struct net_device *dev = nic->dev;
- u64 val64, tx_mat, rx_mat;
- int i, err;
-
- val64 = readq(&bar0->pic_control);
- val64 &= ~BIT(1);
- writeq(val64, &bar0->pic_control);
-
- err = pci_enable_msi(nic->pdev);
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
- nic->dev->name);
- return err;
- }
-
- /*
- * Enable MSI and use MSI-1 in stead of the standard MSI-0
- * for interrupt handling.
- */
- pci_read_config_word(nic->pdev, 0x4c, &msg_val);
- msg_val ^= 0x1;
- pci_write_config_word(nic->pdev, 0x4c, msg_val);
- pci_read_config_word(nic->pdev, 0x4c, &msg_val);
-
- pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
- msi_ctrl |= 0x10;
- pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
-
- /* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
- tx_mat = readq(&bar0->tx_mat0_n[0]);
- for (i=0; i<config->tx_fifo_num; i++) {
- tx_mat |= TX_MAT_SET(i, 1);
- }
- writeq(tx_mat, &bar0->tx_mat0_n[0]);
-
- rx_mat = readq(&bar0->rx_mat);
- for (i=0; i<config->rx_ring_num; i++) {
- rx_mat |= RX_MAT_SET(i, 1);
- }
- writeq(rx_mat, &bar0->rx_mat);
-
- dev->irq = nic->pdev->irq;
- return 0;
-}
-
static int s2io_enable_msi_x(struct s2io_nic *nic)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
@@ -3788,34 +3636,31 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1;
- nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
+ nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry),
GFP_KERNEL);
- if (nic->entries == NULL) {
+ if (!nic->entries) {
DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
__FUNCTION__);
nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
return -ENOMEM;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
- memset(nic->entries, 0,MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
nic->s2io_entries =
- kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
+ kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry),
GFP_KERNEL);
- if (nic->s2io_entries == NULL) {
- DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
+ if (!nic->s2io_entries) {
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
__FUNCTION__);
nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
kfree(nic->entries);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
return -ENOMEM;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
- memset(nic->s2io_entries, 0,
- MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
nic->entries[i].entry = i;
@@ -3833,27 +3678,15 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
}
writeq(tx_mat, &bar0->tx_mat0_n[0]);
- if (!nic->config.bimodal) {
- rx_mat = readq(&bar0->rx_mat);
- for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
- rx_mat |= RX_MAT_SET(j, msix_indx);
- nic->s2io_entries[msix_indx].arg
- = &nic->mac_control.rings[j];
- nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
- nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
- }
- writeq(rx_mat, &bar0->rx_mat);
- } else {
- tx_mat = readq(&bar0->tx_mat0_n[7]);
- for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
- tx_mat |= TX_MAT_SET(i, msix_indx);
- nic->s2io_entries[msix_indx].arg
- = &nic->mac_control.rings[j];
- nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
- nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
- }
- writeq(tx_mat, &bar0->tx_mat0_n[7]);
+ rx_mat = readq(&bar0->rx_mat);
+ for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) {
+ rx_mat |= RX_MAT_SET(j, msix_indx);
+ nic->s2io_entries[msix_indx].arg
+ = &nic->mac_control.rings[j];
+ nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
+ nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
}
+ writeq(rx_mat, &bar0->rx_mat);
nic->avail_msix_vectors = 0;
ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
@@ -3865,10 +3698,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
kfree(nic->entries);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
kfree(nic->s2io_entries);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
nic->entries = NULL;
nic->s2io_entries = NULL;
@@ -3889,6 +3722,59 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
return 0;
}
+/* Handle software interrupt used during MSI(X) test */
+static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
+{
+ struct s2io_nic *sp = dev_id;
+
+ sp->msi_detected = 1;
+ wake_up(&sp->msi_wait);
+
+ return IRQ_HANDLED;
+}
+
+/* Test interrupt path by forcing a a software IRQ */
+static int __devinit s2io_test_msi(struct s2io_nic *sp)
+{
+ struct pci_dev *pdev = sp->pdev;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ int err;
+ u64 val64, saved64;
+
+ err = request_irq(sp->entries[1].vector, s2io_test_intr, 0,
+ sp->name, sp);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n",
+ sp->dev->name, pci_name(pdev), pdev->irq);
+ return err;
+ }
+
+ init_waitqueue_head (&sp->msi_wait);
+ sp->msi_detected = 0;
+
+ saved64 = val64 = readq(&bar0->scheduled_int_ctrl);
+ val64 |= SCHED_INT_CTRL_ONE_SHOT;
+ val64 |= SCHED_INT_CTRL_TIMER_EN;
+ val64 |= SCHED_INT_CTRL_INT2MSI(1);
+ writeq(val64, &bar0->scheduled_int_ctrl);
+
+ wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10);
+
+ if (!sp->msi_detected) {
+ /* MSI(X) test failed, go back to INTx mode */
+ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated"
+ "using MSI(X) during test\n", sp->dev->name,
+ pci_name(pdev));
+
+ err = -EOPNOTSUPP;
+ }
+
+ free_irq(sp->entries[1].vector, sp);
+
+ writeq(saved64, &bar0->scheduled_int_ctrl);
+
+ return err;
+}
/* ********************************************************* *
* Functions defined below concern the OS part of the driver *
* ********************************************************* */
@@ -3917,6 +3803,50 @@ static int s2io_open(struct net_device *dev)
netif_carrier_off(dev);
sp->last_link_state = 0;
+ napi_enable(&sp->napi);
+
+ if (sp->config.intr_type == MSI_X) {
+ int ret = s2io_enable_msi_x(sp);
+
+ if (!ret) {
+ u16 msi_control;
+
+ ret = s2io_test_msi(sp);
+
+ /* rollback MSI-X, will re-enable during add_isr() */
+ kfree(sp->entries);
+ sp->mac_control.stats_info->sw_stat.mem_freed +=
+ (MAX_REQUESTED_MSI_X *
+ sizeof(struct msix_entry));
+ kfree(sp->s2io_entries);
+ sp->mac_control.stats_info->sw_stat.mem_freed +=
+ (MAX_REQUESTED_MSI_X *
+ sizeof(struct s2io_msix_entry));
+ sp->entries = NULL;
+ sp->s2io_entries = NULL;
+
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+ pci_disable_msix(sp->pdev);
+
+ }
+ if (ret) {
+
+ DBG_PRINT(ERR_DBG,
+ "%s: MSI-X requested but failed to enable\n",
+ dev->name);
+ sp->config.intr_type = INTA;
+ }
+ }
+
+ /* NAPI doesn't work well with MSI(X) */
+ if (sp->config.intr_type != INTA) {
+ if(sp->config.napi)
+ sp->config.napi = 0;
+ }
+
/* Initialize H/W and enable interrupts */
err = s2io_card_up(sp);
if (err) {
@@ -3925,7 +3855,7 @@ static int s2io_open(struct net_device *dev)
goto hw_init_failed;
}
- if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
+ if (do_s2io_prog_unicast(dev, dev->dev_addr) == FAILURE) {
DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
s2io_card_down(sp);
err = -ENODEV;
@@ -3936,15 +3866,16 @@ static int s2io_open(struct net_device *dev)
return 0;
hw_init_failed:
- if (sp->intr_type == MSI_X) {
+ napi_disable(&sp->napi);
+ if (sp->config.intr_type == MSI_X) {
if (sp->entries) {
kfree(sp->entries);
- sp->mac_control.stats_info->sw_stat.mem_freed
+ sp->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
}
if (sp->s2io_entries) {
kfree(sp->s2io_entries);
- sp->mac_control.stats_info->sw_stat.mem_freed
+ sp->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
}
}
@@ -3969,6 +3900,7 @@ static int s2io_close(struct net_device *dev)
struct s2io_nic *sp = dev->priv;
netif_stop_queue(dev);
+ napi_disable(&sp->napi);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
@@ -4001,6 +3933,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
struct mac_info *mac_control;
struct config_param *config;
int offload_type;
+ struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
mac_control = &sp->mac_control;
config = &sp->config;
@@ -4014,7 +3947,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_lock_irqsave(&sp->tx_lock, flags);
- if (atomic_read(&sp->card_state) == CARD_DOWN) {
+ if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
spin_unlock_irqrestore(&sp->tx_lock, flags);
@@ -4085,11 +4018,18 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Buffer_Pointer = pci_map_single(sp->pdev,
sp->ufo_in_band_v,
sizeof(u64), PCI_DMA_TODEVICE);
+ if((txdp->Buffer_Pointer == 0) ||
+ (txdp->Buffer_Pointer == DMA_ERROR_CODE))
+ goto pci_map_failed;
txdp++;
}
txdp->Buffer_Pointer = pci_map_single
(sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
+ if((txdp->Buffer_Pointer == 0) ||
+ (txdp->Buffer_Pointer == DMA_ERROR_CODE))
+ goto pci_map_failed;
+
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
if (offload_type == SKB_GSO_UDP)
@@ -4146,14 +4086,22 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&sp->tx_lock, flags);
return 0;
+pci_map_failed:
+ stats->pci_map_fail_cnt++;
+ netif_stop_queue(dev);
+ stats->mem_freed += skb->truesize;
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&sp->tx_lock, flags);
+ return 0;
}
static void
s2io_alarm_handle(unsigned long data)
{
struct s2io_nic *sp = (struct s2io_nic *)data;
+ struct net_device *dev = sp->dev;
- alarm_intr_handler(sp);
+ s2io_handle_errors(dev);
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
@@ -4186,50 +4134,17 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
return 0;
}
-static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *) dev_id;
- struct s2io_nic *sp = dev->priv;
- int i;
- struct mac_info *mac_control;
- struct config_param *config;
-
- atomic_inc(&sp->isr_cnt);
- mac_control = &sp->mac_control;
- config = &sp->config;
- DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
-
- /* If Intr is because of Rx Traffic */
- for (i = 0; i < config->rx_ring_num; i++)
- rx_intr_handler(&mac_control->rings[i]);
-
- /* If Intr is because of Tx Traffic */
- for (i = 0; i < config->tx_fifo_num; i++)
- tx_intr_handler(&mac_control->fifos[i]);
-
- /*
- * If the Rx buffer count is below the panic threshold then
- * reallocate the buffers from the interrupt handler itself,
- * else schedule a tasklet to reallocate the buffers.
- */
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
-
- atomic_dec(&sp->isr_cnt);
- return IRQ_HANDLED;
-}
-
static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
{
struct ring_info *ring = (struct ring_info *)dev_id;
struct s2io_nic *sp = ring->nic;
- atomic_inc(&sp->isr_cnt);
+ if (!is_s2io_card_up(sp))
+ return IRQ_HANDLED;
rx_intr_handler(ring);
s2io_chk_rx_buffers(sp, ring->ring_no);
- atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4238,9 +4153,10 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
struct fifo_info *fifo = (struct fifo_info *)dev_id;
struct s2io_nic *sp = fifo->nic;
- atomic_inc(&sp->isr_cnt);
+ if (!is_s2io_card_up(sp))
+ return IRQ_HANDLED;
+
tx_intr_handler(fifo);
- atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
static void s2io_txpic_intr_handle(struct s2io_nic *sp)
@@ -4305,6 +4221,292 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp)
}
/**
+ * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter
+ * @value: alarm bits
+ * @addr: address value
+ * @cnt: counter variable
+ * Description: Check for alarm and increment the counter
+ * Return Value:
+ * 1 - if alarm bit set
+ * 0 - if alarm bit is not set
+ */
+static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr,
+ unsigned long long *cnt)
+{
+ u64 val64;
+ val64 = readq(addr);
+ if ( val64 & value ) {
+ writeq(val64, addr);
+ (*cnt)++;
+ return 1;
+ }
+ return 0;
+
+}
+
+/**
+ * s2io_handle_errors - Xframe error indication handler
+ * @nic: device private variable
+ * Description: Handle alarms such as loss of link, single or
+ * double ECC errors, critical and serious errors.
+ * Return Value:
+ * NONE
+ */
+static void s2io_handle_errors(void * dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 temp64 = 0,val64=0;
+ int i = 0;
+
+ struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat;
+ struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat;
+
+ if (!is_s2io_card_up(sp))
+ return;
+
+ if (pci_channel_offline(sp->pdev))
+ return;
+
+ memset(&sw_stat->ring_full_cnt, 0,
+ sizeof(sw_stat->ring_full_cnt));
+
+ /* Handling the XPAK counters update */
+ if(stats->xpak_timer_count < 72000) {
+ /* waiting for an hour */
+ stats->xpak_timer_count++;
+ } else {
+ s2io_updt_xpak_counter(dev);
+ /* reset the count to zero */
+ stats->xpak_timer_count = 0;
+ }
+
+ /* Handling link status change error Intr */
+ if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) {
+ val64 = readq(&bar0->mac_rmac_err_reg);
+ writeq(val64, &bar0->mac_rmac_err_reg);
+ if (val64 & RMAC_LINK_STATE_CHANGE_INT)
+ schedule_work(&sp->set_link_task);
+ }
+
+ /* In case of a serious error, the device will be Reset. */
+ if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source,
+ &sw_stat->serious_err_cnt))
+ goto reset;
+
+ /* Check for data parity error */
+ if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg,
+ &sw_stat->parity_err_cnt))
+ goto reset;
+
+ /* Check for ring full counter */
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ val64 = readq(&bar0->ring_bump_counter1);
+ for (i=0; i<4; i++) {
+ temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+ temp64 >>= 64 - ((i+1)*16);
+ sw_stat->ring_full_cnt[i] += temp64;
+ }
+
+ val64 = readq(&bar0->ring_bump_counter2);
+ for (i=0; i<4; i++) {
+ temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+ temp64 >>= 64 - ((i+1)*16);
+ sw_stat->ring_full_cnt[i+4] += temp64;
+ }
+ }
+
+ val64 = readq(&bar0->txdma_int_status);
+ /*check for pfc_err*/
+ if (val64 & TXDMA_PFC_INT) {
+ if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM|
+ PFC_MISC_0_ERR | PFC_MISC_1_ERR|
+ PFC_PCIX_ERR, &bar0->pfc_err_reg,
+ &sw_stat->pfc_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg,
+ &sw_stat->pfc_err_cnt);
+ }
+
+ /*check for tda_err*/
+ if (val64 & TXDMA_TDA_INT) {
+ if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
+ TDA_SM1_ERR_ALARM, &bar0->tda_err_reg,
+ &sw_stat->tda_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR,
+ &bar0->tda_err_reg, &sw_stat->tda_err_cnt);
+ }
+ /*check for pcc_err*/
+ if (val64 & TXDMA_PCC_INT) {
+ if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM
+ | PCC_N_SERR | PCC_6_COF_OV_ERR
+ | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR
+ | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR
+ | PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg,
+ &sw_stat->pcc_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR,
+ &bar0->pcc_err_reg, &sw_stat->pcc_err_cnt);
+ }
+
+ /*check for tti_err*/
+ if (val64 & TXDMA_TTI_INT) {
+ if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg,
+ &sw_stat->tti_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR,
+ &bar0->tti_err_reg, &sw_stat->tti_err_cnt);
+ }
+
+ /*check for lso_err*/
+ if (val64 & TXDMA_LSO_INT) {
+ if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT
+ | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM,
+ &bar0->lso_err_reg, &sw_stat->lso_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
+ &bar0->lso_err_reg, &sw_stat->lso_err_cnt);
+ }
+
+ /*check for tpa_err*/
+ if (val64 & TXDMA_TPA_INT) {
+ if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg,
+ &sw_stat->tpa_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg,
+ &sw_stat->tpa_err_cnt);
+ }
+
+ /*check for sm_err*/
+ if (val64 & TXDMA_SM_INT) {
+ if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg,
+ &sw_stat->sm_err_cnt))
+ goto reset;
+ }
+
+ val64 = readq(&bar0->mac_int_status);
+ if (val64 & MAC_INT_STATUS_TMAC_INT) {
+ if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR,
+ &bar0->mac_tmac_err_reg,
+ &sw_stat->mac_tmac_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR
+ | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
+ &bar0->mac_tmac_err_reg,
+ &sw_stat->mac_tmac_err_cnt);
+ }
+
+ val64 = readq(&bar0->xgxs_int_status);
+ if (val64 & XGXS_INT_STATUS_TXGXS) {
+ if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR,
+ &bar0->xgxs_txgxs_err_reg,
+ &sw_stat->xgxs_txgxs_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
+ &bar0->xgxs_txgxs_err_reg,
+ &sw_stat->xgxs_txgxs_err_cnt);
+ }
+
+ val64 = readq(&bar0->rxdma_int_status);
+ if (val64 & RXDMA_INT_RC_INT_M) {
+ if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR
+ | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM,
+ &bar0->rc_err_reg, &sw_stat->rc_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR
+ | RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg,
+ &sw_stat->rc_err_cnt);
+ if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn
+ | PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg,
+ &sw_stat->prc_pcix_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn
+ | PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg,
+ &sw_stat->prc_pcix_err_cnt);
+ }
+
+ if (val64 & RXDMA_INT_RPA_INT_M) {
+ if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR,
+ &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR,
+ &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt);
+ }
+
+ if (val64 & RXDMA_INT_RDA_INT_M) {
+ if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR
+ | RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM
+ | RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR,
+ &bar0->rda_err_reg, &sw_stat->rda_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR
+ | RDA_MISC_ERR | RDA_PCIX_ERR,
+ &bar0->rda_err_reg, &sw_stat->rda_err_cnt);
+ }
+
+ if (val64 & RXDMA_INT_RTI_INT_M) {
+ if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg,
+ &sw_stat->rti_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
+ &bar0->rti_err_reg, &sw_stat->rti_err_cnt);
+ }
+
+ val64 = readq(&bar0->mac_int_status);
+ if (val64 & MAC_INT_STATUS_RMAC_INT) {
+ if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR,
+ &bar0->mac_rmac_err_reg,
+ &sw_stat->mac_rmac_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR|
+ RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg,
+ &sw_stat->mac_rmac_err_cnt);
+ }
+
+ val64 = readq(&bar0->xgxs_int_status);
+ if (val64 & XGXS_INT_STATUS_RXGXS) {
+ if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR,
+ &bar0->xgxs_rxgxs_err_reg,
+ &sw_stat->xgxs_rxgxs_err_cnt))
+ goto reset;
+ }
+
+ val64 = readq(&bar0->mc_int_status);
+ if(val64 & MC_INT_STATUS_MC_INT) {
+ if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg,
+ &sw_stat->mc_err_cnt))
+ goto reset;
+
+ /* Handling Ecc errors */
+ if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
+ writeq(val64, &bar0->mc_err_reg);
+ if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
+ sw_stat->double_ecc_errs++;
+ if (sp->device_type != XFRAME_II_DEVICE) {
+ /*
+ * Reset XframeI only if critical error
+ */
+ if (val64 &
+ (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+ MC_ERR_REG_MIRI_ECC_DB_ERR_1))
+ goto reset;
+ }
+ } else
+ sw_stat->single_ecc_errs++;
+ }
+ }
+ return;
+
+reset:
+ netif_stop_queue(dev);
+ schedule_work(&sp->rst_timer_task);
+ sw_stat->soft_reset_cnt++;
+ return;
+}
+
+/**
* s2io_isr - ISR handler of the device .
* @irq: the irq of the device.
* @dev_id: a void pointer to the dev structure of the NIC.
@@ -4331,7 +4533,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
if (pci_channel_offline(sp->pdev))
return IRQ_NONE;
- atomic_inc(&sp->isr_cnt);
+ if (!is_s2io_card_up(sp))
+ return IRQ_NONE;
+
mac_control = &sp->mac_control;
config = &sp->config;
@@ -4341,73 +4545,75 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
* 1. Rx of packet.
* 2. Tx complete.
* 3. Link down.
- * 4. Error in any functional blocks of the NIC.
*/
reason = readq(&bar0->general_int_status);
- if (!reason) {
- /* The interrupt was not raised by us. */
- atomic_dec(&sp->isr_cnt);
- return IRQ_NONE;
- }
- else if (unlikely(reason == S2IO_MINUS_ONE) ) {
- /* Disable device and get out */
- atomic_dec(&sp->isr_cnt);
- return IRQ_NONE;
+ if (unlikely(reason == S2IO_MINUS_ONE) ) {
+ /* Nothing much can be done. Get out */
+ return IRQ_HANDLED;
}
- if (napi) {
- if (reason & GEN_INTR_RXTRAFFIC) {
- if ( likely ( netif_rx_schedule_prep(dev)) ) {
- __netif_rx_schedule(dev);
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ if (reason & (GEN_INTR_RXTRAFFIC |
+ GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC))
+ {
+ writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
+
+ if (config->napi) {
+ if (reason & GEN_INTR_RXTRAFFIC) {
+ if (likely(netif_rx_schedule_prep(dev,
+ &sp->napi))) {
+ __netif_rx_schedule(dev, &sp->napi);
+ writeq(S2IO_MINUS_ONE,
+ &bar0->rx_traffic_mask);
+ } else
+ writeq(S2IO_MINUS_ONE,
+ &bar0->rx_traffic_int);
}
- else
+ } else {
+ /*
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit
+ * get's cleared and hence a read can be avoided.
+ */
+ if (reason & GEN_INTR_RXTRAFFIC)
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+
+ for (i = 0; i < config->rx_ring_num; i++)
+ rx_intr_handler(&mac_control->rings[i]);
}
- } else {
+
/*
- * Rx handler is called by default, without checking for the
- * cause of interrupt.
- * rx_traffic_int reg is an R1 register, writing all 1's
+ * tx_traffic_int reg is an R1 register, writing all 1's
* will ensure that the actual interrupt causing bit get's
* cleared and hence a read can be avoided.
*/
- if (reason & GEN_INTR_RXTRAFFIC)
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
- }
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
- /*
- * tx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- if (reason & GEN_INTR_TXTRAFFIC)
- writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
+ if (reason & GEN_INTR_TXPIC)
+ s2io_txpic_intr_handle(sp);
- for (i = 0; i < config->tx_fifo_num; i++)
- tx_intr_handler(&mac_control->fifos[i]);
+ /*
+ * Reallocate the buffers from the interrupt handler itself.
+ */
+ if (!config->napi) {
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
+ }
+ writeq(sp->general_int_mask, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
- if (reason & GEN_INTR_TXPIC)
- s2io_txpic_intr_handle(sp);
- /*
- * If the Rx buffer count is below the panic threshold then
- * reallocate the buffers from the interrupt handler itself,
- * else schedule a tasklet to reallocate the buffers.
- */
- if (!napi) {
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
- }
+ return IRQ_HANDLED;
- writeq(0, &bar0->general_int_mask);
- readl(&bar0->general_int_status);
+ }
+ else if (!reason) {
+ /* The interrupt was not raised by us */
+ return IRQ_NONE;
+ }
- atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4420,7 +4626,7 @@ static void s2io_updt_stats(struct s2io_nic *sp)
u64 val64;
int cnt = 0;
- if (atomic_read(&sp->card_state) == CARD_UP) {
+ if (is_s2io_card_up(sp)) {
/* Apprx 30us on a 133 MHz bus */
val64 = SET_UPDT_CLICKS(10) |
STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
@@ -4434,7 +4640,7 @@ static void s2io_updt_stats(struct s2io_nic *sp)
if (cnt == 5)
break; /* Updt failed */
} while(1);
- }
+ }
}
/**
@@ -4651,8 +4857,48 @@ static void s2io_set_multicast(struct net_device *dev)
}
}
+/* add unicast MAC address to CAM */
+static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off)
+{
+ u64 val64;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+
+ writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr),
+ &bar0->rmac_addr_data0_mem);
+
+ val64 =
+ RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
+ RMAC_ADDR_CMD_MEM_OFFSET(off);
+ writeq(val64, &bar0->rmac_addr_cmd_mem);
+
+ /* Wait till command completes */
+ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET)) {
+ DBG_PRINT(INFO_DBG, "add_mac_addr failed\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
/**
- * s2io_set_mac_addr - Programs the Xframe mac address
+ * s2io_set_mac_addr driver entry point
+ */
+static int s2io_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* store the MAC address in CAM */
+ return (do_s2io_prog_unicast(dev, dev->dev_addr));
+}
+
+/**
+ * do_s2io_prog_unicast - Programs the Xframe mac address
* @dev : pointer to the device structure.
* @addr: a uchar pointer to the new mac address which is to be set.
* Description : This procedure will program the Xframe to receive
@@ -4660,56 +4906,31 @@ static void s2io_set_multicast(struct net_device *dev)
* Return value: SUCCESS on success and an appropriate (-)ve integer
* as defined in errno.h file on failure.
*/
-
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
+static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
{
struct s2io_nic *sp = dev->priv;
- struct XENA_dev_config __iomem *bar0 = sp->bar0;
- register u64 val64, mac_addr = 0;
+ register u64 mac_addr = 0, perm_addr = 0;
int i;
- u64 old_mac_addr = 0;
/*
- * Set the new MAC address as the new unicast filter and reflect this
- * change on the device address registered with the OS. It will be
- * at offset 0.
- */
+ * Set the new MAC address as the new unicast filter and reflect this
+ * change on the device address registered with the OS. It will be
+ * at offset 0.
+ */
for (i = 0; i < ETH_ALEN; i++) {
mac_addr <<= 8;
mac_addr |= addr[i];
- old_mac_addr <<= 8;
- old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
+ perm_addr <<= 8;
+ perm_addr |= sp->def_mac_addr[0].mac_addr[i];
}
- if(0 == mac_addr)
+ /* check if the dev_addr is different than perm_addr */
+ if (mac_addr == perm_addr)
return SUCCESS;
/* Update the internal structure with this new mac address */
- if(mac_addr != old_mac_addr) {
- memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
- sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
- sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
- sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
- sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
- sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
- sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
- }
-
- writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
- &bar0->rmac_addr_data0_mem);
-
- val64 =
- RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
- RMAC_ADDR_CMD_MEM_OFFSET(0);
- writeq(val64, &bar0->rmac_addr_cmd_mem);
- /* Wait till command completes */
- if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
- DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
- return FAILURE;
- }
-
- return SUCCESS;
+ do_s2io_copy_mac_addr(sp, 0, mac_addr);
+ return (do_s2io_add_unicast(sp, mac_addr, 0));
}
/**
@@ -4757,7 +4978,9 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->port = PORT_FIBRE;
- /* info->transceiver?? TODO */
+
+ /* info->transceiver */
+ info->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(sp->dev)) {
info->speed = 10000;
@@ -4794,12 +5017,6 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
info->regdump_len = XENA_REG_SPACE;
info->eedump_len = XENA_EEPROM_SPACE;
- info->testinfo_len = S2IO_TEST_LEN;
-
- if (sp->device_type == XFRAME_I_DEVICE)
- info->n_stats = XFRAME_I_STAT_LEN;
- else
- info->n_stats = XFRAME_II_STAT_LEN;
}
/**
@@ -4927,19 +5144,17 @@ static void s2io_ethtool_gringparam(struct net_device *dev,
ering->rx_max_pending = MAX_RX_DESC_1;
else if (sp->rxd_mode == RXD_MODE_3B)
ering->rx_max_pending = MAX_RX_DESC_2;
- else if (sp->rxd_mode == RXD_MODE_3A)
- ering->rx_max_pending = MAX_RX_DESC_3;
ering->tx_max_pending = MAX_TX_DESC;
- for (i = 0 ; i < sp->config.tx_fifo_num ; i++) {
+ for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
tx_desc_count += sp->config.tx_cfg[i].fifo_len;
- }
+
DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds);
ering->tx_pending = tx_desc_count;
rx_desc_count = 0;
- for (i = 0 ; i < sp->config.rx_ring_num ; i++) {
+ for (i = 0 ; i < sp->config.rx_ring_num ; i++)
rx_desc_count += sp->config.rx_cfg[i].num_rxd;
- }
+
ering->rx_pending = rx_desc_count;
ering->rx_mini_max_pending = 0;
@@ -5695,7 +5910,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *estats,
u64 * tmp_stats)
{
- int i = 0;
+ int i = 0, k;
struct s2io_nic *sp = dev->priv;
struct stat_block *stat_info = sp->mac_control.stats_info;
@@ -5890,7 +6105,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
- tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
+ for (k = 0; k < MAX_RX_RINGS; k++)
+ tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k];
tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
@@ -5923,6 +6139,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
else
tmp_stats[i++] = 0;
tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt;
tmp_stats[i++] = stat_info->sw_stat.watchdog_timer_cnt;
tmp_stats[i++] = stat_info->sw_stat.mem_allocated;
tmp_stats[i++] = stat_info->sw_stat.mem_freed;
@@ -5946,6 +6163,23 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt;
tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt;
tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt;
}
static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -5978,9 +6212,25 @@ static int s2io_get_eeprom_len(struct net_device *dev)
return (XENA_EEPROM_SPACE);
}
-static int s2io_ethtool_self_test_count(struct net_device *dev)
+static int s2io_get_sset_count(struct net_device *dev, int sset)
{
- return (S2IO_TEST_LEN);
+ struct s2io_nic *sp = dev->priv;
+
+ switch (sset) {
+ case ETH_SS_TEST:
+ return S2IO_TEST_LEN;
+ case ETH_SS_STATS:
+ switch(sp->device_type) {
+ case XFRAME_I_DEVICE:
+ return XFRAME_I_STAT_LEN;
+ case XFRAME_II_DEVICE:
+ return XFRAME_II_STAT_LEN;
+ default:
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void s2io_ethtool_get_strings(struct net_device *dev,
@@ -6007,22 +6257,6 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
sizeof(ethtool_driver_stats_keys));
}
}
-static int s2io_ethtool_get_stats_count(struct net_device *dev)
-{
- struct s2io_nic *sp = dev->priv;
- int stat_count = 0;
- switch(sp->device_type) {
- case XFRAME_I_DEVICE:
- stat_count = XFRAME_I_STAT_LEN;
- break;
-
- case XFRAME_II_DEVICE:
- stat_count = XFRAME_II_STAT_LEN;
- break;
- }
-
- return stat_count;
-}
static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
{
@@ -6063,20 +6297,16 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_pauseparam = s2io_ethtool_setpause_data,
.get_rx_csum = s2io_ethtool_get_rx_csum,
.set_rx_csum = s2io_ethtool_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = s2io_ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = s2io_ethtool_op_get_tso,
.set_tso = s2io_ethtool_op_set_tso,
- .get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
- .self_test_count = s2io_ethtool_self_test_count,
.self_test = s2io_ethtool_test,
.get_strings = s2io_ethtool_get_strings,
.phys_id = s2io_ethtool_idnic,
- .get_stats_count = s2io_ethtool_get_stats_count,
- .get_ethtool_stats = s2io_get_ethtool_stats
+ .get_ethtool_stats = s2io_get_ethtool_stats,
+ .get_sset_count = s2io_get_sset_count,
};
/**
@@ -6199,7 +6429,7 @@ static void s2io_set_link(struct work_struct *work)
if (!netif_running(dev))
goto out_unlock;
- if (test_and_set_bit(0, &(nic->link_state))) {
+ if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) {
/* The card is being reset, no point doing anything */
goto out_unlock;
}
@@ -6237,13 +6467,10 @@ static void s2io_set_link(struct work_struct *work)
netif_stop_queue(dev);
}
}
- val64 = readq(&bar0->adapter_status);
- if (!LINK_IS_UP(val64)) {
- DBG_PRINT(ERR_DBG, "%s:", dev->name);
- DBG_PRINT(ERR_DBG, " Link down after enabling ");
- DBG_PRINT(ERR_DBG, "device \n");
- } else
- s2io_link(nic, LINK_UP);
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
+ s2io_link(nic, LINK_UP);
} else {
if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
subid)) {
@@ -6252,9 +6479,13 @@ static void s2io_set_link(struct work_struct *work)
writeq(val64, &bar0->gpio_control);
val64 = readq(&bar0->gpio_control);
}
+ /* turn off LED */
+ val64 = readq(&bar0->adapter_control);
+ val64 = val64 &(~ADAPTER_LED_ON);
+ writeq(val64, &bar0->adapter_control);
s2io_link(nic, LINK_DOWN);
}
- clear_bit(0, &(nic->link_state));
+ clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state));
out_unlock:
rtnl_unlock();
@@ -6266,9 +6497,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
u64 *temp2, int size)
{
struct net_device *dev = sp->dev;
- struct sk_buff *frag_list;
+ struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
+ struct RxD1 *rxdp1 = (struct RxD1 *)rxdp;
/* allocate skb */
if (*skb) {
DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
@@ -6277,7 +6509,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
* using same mapped address for the Rxd
* buffer pointer
*/
- ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
+ rxdp1->Buffer0_ptr = *temp0;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -6288,24 +6520,29 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
mem_alloc_fail_cnt++;
return -ENOMEM ;
}
- sp->mac_control.stats_info->sw_stat.mem_allocated
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+= (*skb)->truesize;
/* storing the mapped addr in a temp variable
* such it will be used for next rxd whose
* Host Control is NULL
*/
- ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
+ rxdp1->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, (*skb)->data,
size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
+ if( (rxdp1->Buffer0_ptr == 0) ||
+ (rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
+ goto memalloc_failed;
+ }
rxdp->Host_Control = (unsigned long) (*skb);
}
} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
+ struct RxD3 *rxdp3 = (struct RxD3 *)rxdp;
/* Two buffer Mode */
if (*skb) {
- ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
- ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
- ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+ rxdp3->Buffer2_ptr = *temp2;
+ rxdp3->Buffer0_ptr = *temp0;
+ rxdp3->Buffer1_ptr = *temp1;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -6316,75 +6553,52 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
mem_alloc_fail_cnt++;
return -ENOMEM;
}
- sp->mac_control.stats_info->sw_stat.mem_allocated
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+= (*skb)->truesize;
- ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
+ rxdp3->Buffer2_ptr = *temp2 =
pci_map_single(sp->pdev, (*skb)->data,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
+ if( (rxdp3->Buffer2_ptr == 0) ||
+ (rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
+ goto memalloc_failed;
+ }
+ rxdp3->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
+ if( (rxdp3->Buffer0_ptr == 0) ||
+ (rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
+ pci_unmap_single (sp->pdev,
+ (dma_addr_t)rxdp3->Buffer2_ptr,
+ dev->mtu + 4, PCI_DMA_FROMDEVICE);
+ goto memalloc_failed;
+ }
rxdp->Host_Control = (unsigned long) (*skb);
/* Buffer-1 will be dummy buffer not used */
- ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
+ rxdp3->Buffer1_ptr = *temp1 =
pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
- PCI_DMA_FROMDEVICE);
- }
- } else if ((rxdp->Host_Control == 0)) {
- /* Three buffer mode */
- if (*skb) {
- ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
- ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
- ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
- } else {
- *skb = dev_alloc_skb(size);
- if (!(*skb)) {
- DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(INFO_DBG, "memory to allocate ");
- DBG_PRINT(INFO_DBG, "3 buf mode SKBs\n");
- sp->mac_control.stats_info->sw_stat. \
- mem_alloc_fail_cnt++;
- return -ENOMEM;
- }
- sp->mac_control.stats_info->sw_stat.mem_allocated
- += (*skb)->truesize;
- ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
- pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
- PCI_DMA_FROMDEVICE);
- /* Buffer-1 receives L3/L4 headers */
- ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
- pci_map_single( sp->pdev, (*skb)->data,
- l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
- /*
- * skb_shinfo(skb)->frag_list will have L4
- * data payload
- */
- skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
- ALIGN_SIZE);
- if (skb_shinfo(*skb)->frag_list == NULL) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
- failed\n ", dev->name);
- sp->mac_control.stats_info->sw_stat. \
- mem_alloc_fail_cnt++;
- return -ENOMEM ;
+ if( (rxdp3->Buffer1_ptr == 0) ||
+ (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+ pci_unmap_single (sp->pdev,
+ (dma_addr_t)rxdp3->Buffer0_ptr,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
+ pci_unmap_single (sp->pdev,
+ (dma_addr_t)rxdp3->Buffer2_ptr,
+ dev->mtu + 4, PCI_DMA_FROMDEVICE);
+ goto memalloc_failed;
}
- frag_list = skb_shinfo(*skb)->frag_list;
- frag_list->next = NULL;
- sp->mac_control.stats_info->sw_stat.mem_allocated
- += frag_list->truesize;
- /*
- * Buffer-2 receives L4 data payload
- */
- ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
- pci_map_single( sp->pdev, frag_list->data,
- dev->mtu, PCI_DMA_FROMDEVICE);
}
}
return 0;
+ memalloc_failed:
+ stats->pci_map_fail_cnt++;
+ stats->mem_freed += (*skb)->truesize;
+ dev_kfree_skb(*skb);
+ return -ENOMEM;
}
+
static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
int size)
{
@@ -6395,10 +6609,6 @@ static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
- } else {
- rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
- rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
- rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
}
}
@@ -6420,8 +6630,6 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp)
size += NET_IP_ALIGN;
else if (sp->rxd_mode == RXD_MODE_3B)
size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
- else
- size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
for (i = 0; i < config->rx_ring_num; i++) {
blk_cnt = config->rx_cfg[i].num_rxd /
@@ -6431,7 +6639,7 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp)
for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
rxdp = mac_control->rings[i].
rx_blocks[j].rxds[k].virt_addr;
- if(sp->rxd_mode >= RXD_MODE_3A)
+ if(sp->rxd_mode == RXD_MODE_3B)
ba = &mac_control->rings[i].ba[j][k];
if (set_rxd_buffer_pointer(sp, rxdp, ba,
&skb,(u64 *)&temp0_64,
@@ -6458,30 +6666,18 @@ static int s2io_add_isr(struct s2io_nic * sp)
struct net_device *dev = sp->dev;
int err = 0;
- if (sp->intr_type == MSI)
- ret = s2io_enable_msi(sp);
- else if (sp->intr_type == MSI_X)
+ if (sp->config.intr_type == MSI_X)
ret = s2io_enable_msi_x(sp);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
- sp->intr_type = INTA;
+ sp->config.intr_type = INTA;
}
/* Store the values of the MSIX table in the struct s2io_nic structure */
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */
- if (sp->intr_type == MSI) {
- err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
- IRQF_SHARED, sp->name, dev);
- if (err) {
- pci_disable_msi(sp->pdev);
- DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
- dev->name);
- return -1;
- }
- }
- if (sp->intr_type == MSI_X) {
+ if (sp->config.intr_type == MSI_X) {
int i, msix_tx_cnt=0,msix_rx_cnt=0;
for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
@@ -6533,7 +6729,7 @@ static int s2io_add_isr(struct s2io_nic * sp)
printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
}
- if (sp->intr_type == INTA) {
+ if (sp->config.intr_type == INTA) {
err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
sp->name, dev);
if (err) {
@@ -6546,10 +6742,10 @@ static int s2io_add_isr(struct s2io_nic * sp)
}
static void s2io_rem_isr(struct s2io_nic * sp)
{
- int cnt = 0;
struct net_device *dev = sp->dev;
+ struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
- if (sp->intr_type == MSI_X) {
+ if (sp->config.intr_type == MSI_X) {
int i;
u16 msi_control;
@@ -6558,32 +6754,28 @@ static void s2io_rem_isr(struct s2io_nic * sp)
int vector = sp->entries[i].vector;
void *arg = sp->s2io_entries[i].arg;
+ synchronize_irq(vector);
free_irq(vector, arg);
}
+
+ kfree(sp->entries);
+ stats->mem_freed +=
+ (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ kfree(sp->s2io_entries);
+ stats->mem_freed +=
+ (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
+ sp->entries = NULL;
+ sp->s2io_entries = NULL;
+
pci_read_config_word(sp->pdev, 0x42, &msi_control);
msi_control &= 0xFFFE; /* Disable MSI */
pci_write_config_word(sp->pdev, 0x42, msi_control);
pci_disable_msix(sp->pdev);
} else {
+ synchronize_irq(sp->pdev->irq);
free_irq(sp->pdev->irq, dev);
- if (sp->intr_type == MSI) {
- u16 val;
-
- pci_disable_msi(sp->pdev);
- pci_read_config_word(sp->pdev, 0x4c, &val);
- val ^= 0x1;
- pci_write_config_word(sp->pdev, 0x4c, val);
- }
}
- /* Waiting till all Interrupt handlers are complete */
- cnt = 0;
- do {
- msleep(10);
- if (!atomic_read(&sp->isr_cnt))
- break;
- cnt++;
- } while(cnt < 5);
}
static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
@@ -6595,10 +6787,10 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
del_timer_sync(&sp->alarm_timer);
/* If s2io_set_link task is executing, wait till it completes. */
- while (test_and_set_bit(0, &(sp->link_state))) {
+ while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) {
msleep(50);
}
- atomic_set(&sp->card_state, CARD_DOWN);
+ clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
/* disable Tx and Rx traffic on the NIC */
if (do_io)
@@ -6649,7 +6841,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
free_rx_buffers(sp);
spin_unlock_irqrestore(&sp->rx_lock, flags);
- clear_bit(0, &(sp->link_state));
+ clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state));
}
static void s2io_card_down(struct s2io_nic * sp)
@@ -6720,7 +6912,7 @@ static int s2io_card_up(struct s2io_nic * sp)
/* Add interrupt service routine */
if (s2io_add_isr(sp) != 0) {
- if (sp->intr_type == MSI_X)
+ if (sp->config.intr_type == MSI_X)
s2io_rem_isr(sp);
s2io_reset(sp);
free_rx_buffers(sp);
@@ -6733,17 +6925,16 @@ static int s2io_card_up(struct s2io_nic * sp)
tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
/* Enable select interrupts */
- if (sp->intr_type != INTA)
+ en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
+ if (sp->config.intr_type != INTA)
en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
else {
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ interruptible |= TX_PIC_INTR;
en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
}
-
- atomic_set(&sp->card_state, CARD_UP);
+ set_bit(__S2IO_STATE_CARD_UP, &sp->state);
return 0;
}
@@ -6897,7 +7088,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n",
dev->name, err_mask);
sp->stats.rx_crc_errors++;
- sp->mac_control.stats_info->sw_stat.mem_freed
+ sp->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -6907,6 +7098,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
}
/* Updating statistics */
+ sp->stats.rx_packets++;
rxdp->Host_Control = 0;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
@@ -6914,7 +7106,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
sp->stats.rx_bytes += len;
skb_put(skb, len);
- } else if (sp->rxd_mode >= RXD_MODE_3A) {
+ } else if (sp->rxd_mode == RXD_MODE_3B) {
int get_block = ring_data->rx_curr_get_info.block_index;
int get_off = ring_data->rx_curr_get_info.offset;
int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
@@ -6924,18 +7116,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
struct buffAdd *ba = &ring_data->ba[get_block][get_off];
sp->stats.rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
-
- if (sp->rxd_mode == RXD_MODE_3A) {
- int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
-
- skb_put(skb, buf1_len);
- skb->len += buf2_len;
- skb->data_len += buf2_len;
- skb_put(skb_shinfo(skb)->frag_list, buf2_len);
- sp->stats.rx_bytes += buf1_len;
-
- } else
- skb_put(skb, buf2_len);
+ skb_put(skb, buf2_len);
}
if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
@@ -6956,7 +7137,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
int ret = 0;
ret = s2io_club_tcp_session(skb->data, &tcp,
- &tcp_len, &lro, rxdp, sp);
+ &tcp_len, &lro,
+ rxdp, sp);
switch (ret) {
case 3: /* Begin anew */
lro->parent = skb;
@@ -7061,13 +7243,13 @@ static void s2io_link(struct s2io_nic * sp, int link)
DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
netif_carrier_off(dev);
if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
- sp->mac_control.stats_info->sw_stat.link_up_time =
+ sp->mac_control.stats_info->sw_stat.link_up_time =
jiffies - sp->start_time;
sp->mac_control.stats_info->sw_stat.link_down_cnt++;
} else {
DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
if (sp->mac_control.stats_info->sw_stat.link_down_cnt)
- sp->mac_control.stats_info->sw_stat.link_down_time =
+ sp->mac_control.stats_info->sw_stat.link_down_time =
jiffies - sp->start_time;
sp->mac_control.stats_info->sw_stat.link_up_cnt++;
netif_carrier_on(dev);
@@ -7124,19 +7306,12 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
if (*dev_intr_type != INTA)
napi = 0;
-#ifndef CONFIG_PCI_MSI
- if (*dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
- "MSI/MSI-X. Defaulting to INTA\n");
- *dev_intr_type = INTA;
- }
-#else
- if (*dev_intr_type > MSI_X) {
+ if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
-#endif
+
if ((*dev_intr_type == MSI_X) &&
((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
(pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
@@ -7145,10 +7320,10 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
*dev_intr_type = INTA;
}
- if (rx_ring_mode > 3) {
+ if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) {
DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
- DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
- rx_ring_mode = 3;
+ DBG_PRINT(ERR_DBG, "s2io: Defaulting to 1-buffer mode\n");
+ rx_ring_mode = 1;
}
return SUCCESS;
}
@@ -7213,6 +7388,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
+ DECLARE_MAC_BUF(mac);
if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
return ret;
@@ -7240,28 +7416,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
pci_disable_device(pdev);
return -ENOMEM;
}
- if (dev_intr_type != MSI_X) {
- if (pci_request_regions(pdev, s2io_driver_name)) {
- DBG_PRINT(ERR_DBG, "Request Regions failed\n");
- pci_disable_device(pdev);
- return -ENODEV;
- }
- }
- else {
- if (!(request_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), s2io_driver_name))) {
- DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
- pci_disable_device(pdev);
- return -ENODEV;
- }
- if (!(request_mem_region(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2), s2io_driver_name))) {
- DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- pci_disable_device(pdev);
- return -ENODEV;
- }
+ if ((ret = pci_request_regions(pdev, s2io_driver_name))) {
+ DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __FUNCTION__, ret);
+ pci_disable_device(pdev);
+ return -ENODEV;
}
dev = alloc_etherdev(sizeof(struct s2io_nic));
@@ -7274,7 +7432,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
pci_set_master(pdev);
pci_set_drvdata(pdev, dev);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Private member variable initialized to s2io NIC structure */
@@ -7288,10 +7445,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->rxd_mode = RXD_MODE_1;
if (rx_ring_mode == 2)
sp->rxd_mode = RXD_MODE_3B;
- if (rx_ring_mode == 3)
- sp->rxd_mode = RXD_MODE_3A;
- sp->intr_type = dev_intr_type;
+ sp->config.intr_type = dev_intr_type;
if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
(pdev->device == PCI_DEVICE_ID_HERC_UNI))
@@ -7299,7 +7454,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
else
sp->device_type = XFRAME_I_DEVICE;
- sp->lro = lro;
+ sp->lro = lro_enable;
/* Initialize some PCI/PCI-X fields of the NIC. */
s2io_init_pci(sp);
@@ -7314,6 +7469,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mac_control = &sp->mac_control;
config = &sp->config;
+ config->napi = napi;
+
/* Tx side parameters. */
config->tx_fifo_num = tx_fifo_num;
for (i = 0; i < MAX_TX_FIFOS; i++) {
@@ -7361,9 +7518,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
for (i = 0; i < config->rx_ring_num; i++)
atomic_set(&sp->rx_bufs_left[i], 0);
- /* Initialize the number of ISRs currently running */
- atomic_set(&sp->isr_cnt, 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",
@@ -7406,6 +7560,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->get_stats = &s2io_get_stats;
dev->set_multicast_list = &s2io_set_multicast;
dev->do_ioctl = &s2io_ioctl;
+ dev->set_mac_address = &s2io_set_mac_addr;
dev->change_mtu = &s2io_change_mtu;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -7415,8 +7570,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called
*/
- dev->poll = s2io_poll;
- dev->weight = 32;
+ netif_napi_add(dev, &sp->napi, s2io_poll, 32);
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll;
@@ -7492,7 +7646,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Set the factory defined MAC address initially */
dev->addr_len = ETH_ALEN;
memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
+ memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+ /* Store the values of the MSIX table in the s2io_nic structure */
+ store_xmsi_data(sp);
/* reset Nic and bring it to known state */
s2io_reset(sp);
@@ -7500,9 +7657,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* Initialize the tasklet status and link state flags
* and the card state parameter
*/
- atomic_set(&(sp->card_state), 0);
sp->tasklet_status = 0;
- sp->link_state = 0;
+ sp->state = 0;
/* Initialize spinlocks */
spin_lock_init(&sp->tx_lock);
@@ -7538,14 +7694,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->product_name, pdev->revision);
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
s2io_driver_version);
- DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
- "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
- sp->def_mac_addr[0].mac_addr[0],
- sp->def_mac_addr[0].mac_addr[1],
- sp->def_mac_addr[0].mac_addr[2],
- sp->def_mac_addr[0].mac_addr[3],
- sp->def_mac_addr[0].mac_addr[4],
- sp->def_mac_addr[0].mac_addr[5]);
+ DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_print_pci_mode(sp);
@@ -7565,21 +7715,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
dev->name);
break;
- case RXD_MODE_3A:
- DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
- dev->name);
- break;
}
if (napi)
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
- switch(sp->intr_type) {
+ switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
break;
- case MSI:
- DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
- break;
case MSI_X:
DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
break;
@@ -7593,14 +7736,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initialize device name */
sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
- /* Initialize bimodal Interrupts */
- sp->config.bimodal = bimodal;
- if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
- sp->config.bimodal = 0;
- DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
- dev->name);
- }
-
/*
* Make Link state as off at this point, when the Link change
* interrupt comes the state will be automatically changed to
@@ -7619,14 +7754,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mem_alloc_failed:
free_shared_mem(sp);
pci_disable_device(pdev);
- if (dev_intr_type != MSI_X)
- pci_release_regions(pdev);
- else {
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- release_mem_region(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2));
- }
+ pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
@@ -7661,14 +7789,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
free_shared_mem(sp);
iounmap(sp->bar0);
iounmap(sp->bar1);
- if (sp->intr_type != MSI_X)
- pci_release_regions(pdev);
- else {
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- release_mem_region(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2));
- }
+ pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
pci_disable_device(pdev);
@@ -7680,7 +7801,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
* the module loadable parameters and initializes PCI configuration space.
*/
-int __init s2io_starter(void)
+static int __init s2io_starter(void)
{
return pci_register_driver(&s2io_driver);
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3887fe63a908..f6b45565304f 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -74,6 +74,10 @@ static int debug_level = ERR_DBG;
/* DEBUG message print. */
#define DBG_PRINT(dbg_level, args...) if(!(debug_level<dbg_level)) printk(args)
+#ifndef DMA_ERROR_CODE
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+#endif
+
/* Protocol assist features of the NIC */
#define L3_CKSUM_OK 0xFFFF
#define L4_CKSUM_OK 0xFFFF
@@ -87,7 +91,7 @@ struct swStat {
unsigned long long serious_err_cnt;
unsigned long long soft_reset_cnt;
unsigned long long fifo_full_cnt;
- unsigned long long ring_full_cnt;
+ unsigned long long ring_full_cnt[8];
/* LRO statistics */
unsigned long long clubbed_frms_cnt;
unsigned long long sending_both;
@@ -97,6 +101,7 @@ struct swStat {
unsigned long long num_aggregations;
/* Other statistics */
unsigned long long mem_alloc_fail_cnt;
+ unsigned long long pci_map_fail_cnt;
unsigned long long watchdog_timer_cnt;
unsigned long long mem_allocated;
unsigned long long mem_freed;
@@ -121,6 +126,26 @@ struct swStat {
unsigned long long rx_buf_size_err_cnt;
unsigned long long rx_rxd_corrupt_cnt;
unsigned long long rx_unkn_err_cnt;
+
+ /* Error/alarm statistics*/
+ unsigned long long tda_err_cnt;
+ unsigned long long pfc_err_cnt;
+ unsigned long long pcc_err_cnt;
+ unsigned long long tti_err_cnt;
+ unsigned long long lso_err_cnt;
+ unsigned long long tpa_err_cnt;
+ unsigned long long sm_err_cnt;
+ unsigned long long mac_tmac_err_cnt;
+ unsigned long long mac_rmac_err_cnt;
+ unsigned long long xgxs_txgxs_err_cnt;
+ unsigned long long xgxs_rxgxs_err_cnt;
+ unsigned long long rc_err_cnt;
+ unsigned long long prc_pcix_err_cnt;
+ unsigned long long rpa_err_cnt;
+ unsigned long long rda_err_cnt;
+ unsigned long long rti_err_cnt;
+ unsigned long long mc_err_cnt;
+
};
/* Xpak releated alarm and warnings */
@@ -407,6 +432,11 @@ struct config_param {
struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
u64 tx_intr_type;
+#define INTA 0
+#define MSI_X 2
+ u8 intr_type;
+ u8 napi;
+
/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
/* Rx Side */
@@ -414,7 +444,6 @@ struct config_param {
#define MAX_RX_BLOCKS_PER_RING 150
struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
- u8 bimodal; /*Flag for setting bimodal interrupts*/
#define HEADER_ETHERNET_II_802_3_SIZE 14
#define HEADER_802_2_SIZE 3
@@ -575,8 +604,7 @@ struct RxD_block {
#define SIZE_OF_BLOCK 4096
#define RXD_MODE_1 0 /* One Buffer mode */
-#define RXD_MODE_3A 1 /* Three Buffer mode */
-#define RXD_MODE_3B 2 /* Two Buffer mode */
+#define RXD_MODE_3B 1 /* Two Buffer mode */
/* Structure to hold virtual addresses of Buf0 and Buf1 in
* 2buf mode. */
@@ -773,6 +801,13 @@ struct lro {
u8 saw_ts;
};
+/* These flags represent the devices temporary state */
+enum s2io_device_state_t
+{
+ __S2IO_STATE_LINK_TASK=0,
+ __S2IO_STATE_CARD_UP
+};
+
/* Structure representing one instance of the NIC */
struct s2io_nic {
int rxd_mode;
@@ -782,6 +817,7 @@ struct s2io_nic {
*/
int pkts_to_process;
struct net_device *dev;
+ struct napi_struct napi;
struct mac_info mac_control;
struct config_param config;
struct pci_dev *pdev;
@@ -850,13 +886,11 @@ struct s2io_nic {
int task_flag;
unsigned long long start_time;
-#define CARD_DOWN 1
-#define CARD_UP 2
- atomic_t card_state;
- volatile unsigned long link_state;
struct vlan_group *vlgrp;
#define MSIX_FLG 0xA5
struct msix_entry *entries;
+ int msi_detected;
+ wait_queue_head_t msi_wait;
struct s2io_msix_entry *s2io_entries;
char desc[MAX_REQUESTED_MSI_X][25];
@@ -874,14 +908,9 @@ struct s2io_nic {
unsigned long sending_both;
u8 lro;
u16 lro_max_aggr_per_sess;
-
-#define INTA 0
-#define MSI 1
-#define MSI_X 2
- u8 intr_type;
-
+ volatile unsigned long state;
spinlock_t rx_lock;
- atomic_t isr_cnt;
+ u64 general_int_mask;
u64 *ufo_in_band_v;
#define VPD_STRING_LEN 80
u8 product_name[VPD_STRING_LEN];
@@ -1006,7 +1035,7 @@ static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
static void rx_intr_handler(struct ring_info *ring_data);
static void tx_intr_handler(struct fifo_info *fifo_data);
-static void alarm_intr_handler(struct s2io_nic *sp);
+static void s2io_handle_errors(void * dev_id);
static int s2io_starter(void);
static void s2io_closer(void);
@@ -1016,12 +1045,10 @@ static void s2io_set_multicast(struct net_device *dev);
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
static void s2io_link(struct s2io_nic * sp, int link);
static void s2io_reset(struct s2io_nic * sp);
-static int s2io_poll(struct net_device *dev, int *budget);
+static int s2io_poll(struct napi_struct *napi, int budget);
static void s2io_init_pci(struct s2io_nic * sp);
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr);
static void s2io_alarm_handle(unsigned long data);
-static int s2io_enable_msi(struct s2io_nic *nic);
-static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
static irqreturn_t
s2io_msix_ring_handle(int irq, void *dev_id);
static irqreturn_t
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index 451486b32f23..14361e885415 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -151,30 +151,30 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
printk("lp->lan_saa9730_regs->CamData = %x\n",
readl(&lp->lan_saa9730_regs->CamData));
}
- printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
- printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
- printk("lp->stats.tx_aborted_errors = %lx\n",
- lp->stats.tx_aborted_errors);
- printk("lp->stats.tx_window_errors = %lx\n",
- lp->stats.tx_window_errors);
- printk("lp->stats.tx_carrier_errors = %lx\n",
- lp->stats.tx_carrier_errors);
- printk("lp->stats.tx_fifo_errors = %lx\n",
- lp->stats.tx_fifo_errors);
- printk("lp->stats.tx_heartbeat_errors = %lx\n",
- lp->stats.tx_heartbeat_errors);
- printk("lp->stats.collisions = %lx\n", lp->stats.collisions);
-
- printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets);
- printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors);
- printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped);
- printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors);
- printk("lp->stats.rx_frame_errors = %lx\n",
- lp->stats.rx_frame_errors);
- printk("lp->stats.rx_fifo_errors = %lx\n",
- lp->stats.rx_fifo_errors);
- printk("lp->stats.rx_length_errors = %lx\n",
- lp->stats.rx_length_errors);
+ printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets);
+ printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors);
+ printk("dev->stats.tx_aborted_errors = %lx\n",
+ dev->stats.tx_aborted_errors);
+ printk("dev->stats.tx_window_errors = %lx\n",
+ dev->stats.tx_window_errors);
+ printk("dev->stats.tx_carrier_errors = %lx\n",
+ dev->stats.tx_carrier_errors);
+ printk("dev->stats.tx_fifo_errors = %lx\n",
+ dev->stats.tx_fifo_errors);
+ printk("dev->stats.tx_heartbeat_errors = %lx\n",
+ dev->stats.tx_heartbeat_errors);
+ printk("dev->stats.collisions = %lx\n", dev->stats.collisions);
+
+ printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets);
+ printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors);
+ printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped);
+ printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors);
+ printk("dev->stats.rx_frame_errors = %lx\n",
+ dev->stats.rx_frame_errors);
+ printk("dev->stats.rx_fifo_errors = %lx\n",
+ dev->stats.rx_fifo_errors);
+ printk("dev->stats.rx_length_errors = %lx\n",
+ dev->stats.rx_length_errors);
printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
@@ -605,24 +605,24 @@ static int lan_saa9730_tx(struct net_device *dev)
printk("lan_saa9730_tx: tx error = %x\n",
tx_status);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status &
(TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status &
(TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tx_status &
(TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status &
(TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (tx_status &
(TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
- lp->stats.collisions +=
+ dev->stats.collisions +=
tx_status & TX_STATUS_TX_COLL_MSK;
}
@@ -684,10 +684,10 @@ static int lan_saa9730_rx(struct net_device *dev)
printk
("%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
- lp->stats.rx_bytes += len;
- lp->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
skb_copy_to_linear_data(skb,
@@ -704,19 +704,19 @@ static int lan_saa9730_rx(struct net_device *dev)
("lan_saa9730_rx: We got an error packet = %x\n",
rx_status);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_status &
(RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_status &
(RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status &
(RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rx_status &
(RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
/* Indicate we have processed the buffer. */
@@ -853,7 +853,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev)
struct lan_saa9730_private *lp = netdev_priv(dev);
/* Transmitter timeout, serious problems */
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
printk("%s: transmit timed out, reset\n", dev->name);
/*show_saa9730_regs(lp); */
lan_saa9730_restart(lp);
@@ -886,8 +886,8 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb,
return -1;
}
- lp->stats.tx_bytes += len;
- lp->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
dev->trans_start = jiffies;
netif_wake_queue(dev);
@@ -919,14 +919,6 @@ static int lan_saa9730_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *lan_saa9730_get_stats(struct net_device
- *dev)
-{
- struct lan_saa9730_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
static void lan_saa9730_set_multicast(struct net_device *dev)
{
struct lan_saa9730_private *lp = netdev_priv(dev);
@@ -940,15 +932,14 @@ static void lan_saa9730_set_multicast(struct net_device *dev)
CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
&lp->lan_saa9730_regs->CamCtl);
} else {
- if (dev->flags & IFF_ALLMULTI) {
+ if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
/* accept all multicast packets */
- writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
- CAM_CONTROL_BROAD_ACC,
- &lp->lan_saa9730_regs->CamCtl);
- } else {
/*
* Will handle the multicast stuff later. -carstenl
*/
+ writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+ CAM_CONTROL_BROAD_ACC,
+ &lp->lan_saa9730_regs->CamCtl);
}
}
@@ -1041,7 +1032,6 @@ static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev,
dev->open = lan_saa9730_open;
dev->hard_start_xmit = lan_saa9730_start_xmit;
dev->stop = lan_saa9730_close;
- dev->get_stats = lan_saa9730_get_stats;
dev->set_multicast_list = lan_saa9730_set_multicast;
dev->tx_timeout = lan_saa9730_tx_timeout;
dev->watchdog_timeo = (HZ >> 1);
diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h
index f656f2f40bb8..010a120ea938 100644
--- a/drivers/net/saa9730.h
+++ b/drivers/net/saa9730.h
@@ -378,7 +378,6 @@ struct lan_saa9730_private {
unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6];
- struct net_device_stats stats;
spinlock_t lock;
};
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 1de3eec1a792..487f9d2ac5b4 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -76,7 +76,6 @@ struct sb1000_private {
unsigned char rx_session_id[NPIDS];
unsigned char rx_frame_id[NPIDS];
unsigned char rx_pkt_type[NPIDS];
- struct net_device_stats stats;
};
/* prototypes for Linux interface */
@@ -85,7 +84,6 @@ static int sb1000_open(struct net_device *dev);
static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t sb1000_interrupt(int irq, void *dev_id);
-static struct net_device_stats *sb1000_stats(struct net_device *dev);
static int sb1000_close(struct net_device *dev);
@@ -189,7 +187,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
*/
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (sb1000_debug > 0)
@@ -200,7 +197,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
dev->do_ioctl = sb1000_dev_ioctl;
dev->hard_start_xmit = sb1000_start_xmit;
dev->stop = sb1000_close;
- dev->get_stats = sb1000_stats;
/* hardware address is 0:0:serial_number */
dev->dev_addr[2] = serial_number >> 24 & 0xff;
@@ -740,7 +736,7 @@ sb1000_rx(struct net_device *dev)
unsigned int skbsize;
struct sk_buff *skb;
struct sb1000_private *lp = netdev_priv(dev);
- struct net_device_stats *stats = &lp->stats;
+ struct net_device_stats *stats = &dev->stats;
/* SB1000 frame constants */
const int FrameSize = FRAMESIZE;
@@ -1003,11 +999,11 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCGCMSTATS: /* get statistics */
- stats[0] = lp->stats.rx_bytes;
+ stats[0] = dev->stats.rx_bytes;
stats[1] = lp->rx_frames;
- stats[2] = lp->stats.rx_packets;
- stats[3] = lp->stats.rx_errors;
- stats[4] = lp->stats.rx_dropped;
+ stats[2] = dev->stats.rx_packets;
+ stats[3] = dev->stats.rx_errors;
+ stats[4] = dev->stats.rx_dropped;
if(copy_to_user(ifr->ifr_data, stats, sizeof(stats)))
return -EFAULT;
status = 0;
@@ -1133,12 +1129,6 @@ static irqreturn_t sb1000_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct net_device_stats *sb1000_stats(struct net_device *dev)
-{
- struct sb1000_private *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
static int sb1000_close(struct net_device *dev)
{
int i;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index e7fdcf15b5a7..7b53d658e337 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2001,2002,2003,2004 Broadcom Corporation
+ * Copyright (c) 2006, 2007 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
@@ -18,7 +19,12 @@
*
* This driver is designed for the Broadcom SiByte SOC built-in
* Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp.
+ *
+ * Updated to the driver model and the PHY abstraction layer
+ * by Maciej W. Rozycki.
*/
+
+#include <linux/bug.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -32,9 +38,15 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/bitops.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
/* This is only here until the firmware is ready. In that case,
the firmware leaves the ethernet address in the register for us. */
@@ -48,7 +60,7 @@
/* These identify the driver base version and may not be removed. */
#if 0
-static char version1[] __devinitdata =
+static char version1[] __initdata =
"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
#endif
@@ -57,8 +69,6 @@ static char version1[] __devinitdata =
#define CONFIG_SBMAC_COALESCE
-#define MAX_UNITS 4 /* More are supported, limit only on options */
-
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (2*HZ)
@@ -74,26 +84,6 @@ static int debug = 1;
module_param(debug, int, S_IRUGO);
MODULE_PARM_DESC(debug, "Debug messages");
-/* mii status msgs */
-static int noisy_mii = 1;
-module_param(noisy_mii, int, S_IRUGO);
-MODULE_PARM_DESC(noisy_mii, "MII status messages");
-
-/* Used to pass the media type, etc.
- Both 'options[]' and 'full_duplex[]' should exist for driver
- interoperability.
- The media type is usually passed in 'options[]'.
-*/
-#ifdef MODULE
-static int options[MAX_UNITS] = {-1, -1, -1, -1};
-module_param_array(options, int, NULL, S_IRUGO);
-MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS));
-
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1};
-module_param_array(full_duplex, int, NULL, S_IRUGO);
-MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
-#endif
-
#ifdef CONFIG_SBMAC_COALESCE
static int int_pktcnt_tx = 255;
module_param(int_pktcnt_tx, int, S_IRUGO);
@@ -112,6 +102,7 @@ module_param(int_timeout_rx, int, S_IRUGO);
MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#endif
+#include <asm/sibyte/board.h>
#include <asm/sibyte/sb1250.h>
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
#include <asm/sibyte/bcm1480_regs.h>
@@ -135,22 +126,43 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#error invalid SiByte MAC configuation
#endif
+#ifdef K_INT_PHY
+#define SBMAC_PHY_INT K_INT_PHY
+#else
+#define SBMAC_PHY_INT PHY_POLL
+#endif
+
/**********************************************************************
* Simple types
********************************************************************* */
+enum sbmac_speed {
+ sbmac_speed_none = 0,
+ sbmac_speed_10 = SPEED_10,
+ sbmac_speed_100 = SPEED_100,
+ sbmac_speed_1000 = SPEED_1000,
+};
-typedef enum { sbmac_speed_auto, sbmac_speed_10,
- sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
-
-typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
- sbmac_duplex_full } sbmac_duplex_t;
+enum sbmac_duplex {
+ sbmac_duplex_none = -1,
+ sbmac_duplex_half = DUPLEX_HALF,
+ sbmac_duplex_full = DUPLEX_FULL,
+};
-typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
- sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
+enum sbmac_fc {
+ sbmac_fc_none,
+ sbmac_fc_disabled,
+ sbmac_fc_frame,
+ sbmac_fc_collision,
+ sbmac_fc_carrier,
+};
-typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
- sbmac_state_broken } sbmac_state_t;
+enum sbmac_state {
+ sbmac_state_uninit,
+ sbmac_state_off,
+ sbmac_state_on,
+ sbmac_state_broken,
+};
/**********************************************************************
@@ -176,55 +188,61 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
* DMA Descriptor structure
********************************************************************* */
-typedef struct sbdmadscr_s {
+struct sbdmadscr {
uint64_t dscr_a;
uint64_t dscr_b;
-} sbdmadscr_t;
-
-typedef unsigned long paddr_t;
+};
/**********************************************************************
* DMA Controller structure
********************************************************************* */
-typedef struct sbmacdma_s {
+struct sbmacdma {
/*
* This stuff is used to identify the channel and the registers
* associated with it.
*/
-
- struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
- int sbdma_channel; /* channel number */
- int sbdma_txdir; /* direction (1=transmit) */
- int sbdma_maxdescr; /* total # of descriptors in ring */
+ struct sbmac_softc *sbdma_eth; /* back pointer to associated
+ MAC */
+ int sbdma_channel; /* channel number */
+ int sbdma_txdir; /* direction (1=transmit) */
+ int sbdma_maxdescr; /* total # of descriptors
+ in ring */
#ifdef CONFIG_SBMAC_COALESCE
- int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/
- int sbdma_int_timeout; /* # usec rx/tx interrupt */
+ int sbdma_int_pktcnt;
+ /* # descriptors rx/tx
+ before interrupt */
+ int sbdma_int_timeout;
+ /* # usec rx/tx interrupt */
#endif
-
- volatile void __iomem *sbdma_config0; /* DMA config register 0 */
- volatile void __iomem *sbdma_config1; /* DMA config register 1 */
- volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */
- volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
- volatile void __iomem *sbdma_curdscr; /* current descriptor address */
- volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
-
+ void __iomem *sbdma_config0; /* DMA config register 0 */
+ void __iomem *sbdma_config1; /* DMA config register 1 */
+ void __iomem *sbdma_dscrbase;
+ /* descriptor base address */
+ void __iomem *sbdma_dscrcnt; /* descriptor count register */
+ void __iomem *sbdma_curdscr; /* current descriptor
+ address */
+ void __iomem *sbdma_oodpktlost;
+ /* pkt drop (rx only) */
/*
* This stuff is for maintenance of the ring
*/
-
- sbdmadscr_t *sbdma_dscrtable_unaligned;
- sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
- sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
-
- struct sk_buff **sbdma_ctxtable; /* context table, one per descr */
-
- paddr_t sbdma_dscrtable_phys; /* and also the phys addr */
- sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */
- sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */
-} sbmacdma_t;
+ void *sbdma_dscrtable_unaligned;
+ struct sbdmadscr *sbdma_dscrtable;
+ /* base of descriptor table */
+ struct sbdmadscr *sbdma_dscrtable_end;
+ /* end of descriptor table */
+ struct sk_buff **sbdma_ctxtable;
+ /* context table, one
+ per descr */
+ dma_addr_t sbdma_dscrtable_phys;
+ /* and also the phys addr */
+ struct sbdmadscr *sbdma_addptr; /* next dscr for sw to add */
+ struct sbdmadscr *sbdma_remptr; /* next dscr for sw
+ to remove */
+};
/**********************************************************************
@@ -236,47 +254,43 @@ struct sbmac_softc {
/*
* Linux-specific things
*/
+ struct net_device *sbm_dev; /* pointer to linux device */
+ struct napi_struct napi;
+ struct phy_device *phy_dev; /* the associated PHY device */
+ struct mii_bus mii_bus; /* the MII bus */
+ int phy_irq[PHY_MAX_ADDR];
+ spinlock_t sbm_lock; /* spin lock */
+ int sbm_devflags; /* current device flags */
- struct net_device *sbm_dev; /* pointer to linux device */
- spinlock_t sbm_lock; /* spin lock */
- struct timer_list sbm_timer; /* for monitoring MII */
- struct net_device_stats sbm_stats;
- int sbm_devflags; /* current device flags */
-
- int sbm_phy_oldbmsr;
- int sbm_phy_oldanlpar;
- int sbm_phy_oldk1stsr;
- int sbm_phy_oldlinkstat;
- int sbm_buffersize;
-
- unsigned char sbm_phys[2];
+ int sbm_buffersize;
/*
* Controller-specific things
*/
-
- void __iomem *sbm_base; /* MAC's base address */
- sbmac_state_t sbm_state; /* current state */
-
- volatile void __iomem *sbm_macenable; /* MAC Enable Register */
- volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */
- volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */
- volatile void __iomem *sbm_framecfg; /* Frame configuration register */
- volatile void __iomem *sbm_rxfilter; /* receive filter register */
- volatile void __iomem *sbm_isr; /* Interrupt status register */
- volatile void __iomem *sbm_imr; /* Interrupt mask register */
- volatile void __iomem *sbm_mdio; /* MDIO register */
-
- sbmac_speed_t sbm_speed; /* current speed */
- sbmac_duplex_t sbm_duplex; /* current duplex */
- sbmac_fc_t sbm_fc; /* current flow control setting */
-
- unsigned char sbm_hwaddr[ETHER_ADDR_LEN];
-
- sbmacdma_t sbm_txdma; /* for now, only use channel 0 */
- sbmacdma_t sbm_rxdma;
- int rx_hw_checksum;
- int sbe_idx;
+ void __iomem *sbm_base; /* MAC's base address */
+ enum sbmac_state sbm_state; /* current state */
+
+ void __iomem *sbm_macenable; /* MAC Enable Register */
+ void __iomem *sbm_maccfg; /* MAC Config Register */
+ void __iomem *sbm_fifocfg; /* FIFO Config Register */
+ void __iomem *sbm_framecfg; /* Frame Config Register */
+ void __iomem *sbm_rxfilter; /* Receive Filter Register */
+ void __iomem *sbm_isr; /* Interrupt Status Register */
+ void __iomem *sbm_imr; /* Interrupt Mask Register */
+ void __iomem *sbm_mdio; /* MDIO Register */
+
+ enum sbmac_speed sbm_speed; /* current speed */
+ enum sbmac_duplex sbm_duplex; /* current duplex */
+ enum sbmac_fc sbm_fc; /* cur. flow control setting */
+ int sbm_pause; /* current pause setting */
+ int sbm_link; /* current link state */
+
+ unsigned char sbm_hwaddr[ETHER_ADDR_LEN];
+
+ struct sbmacdma sbm_txdma; /* only channel 0 for now */
+ struct sbmacdma sbm_rxdma;
+ int rx_hw_checksum;
+ int sbe_idx;
};
@@ -288,55 +302,58 @@ struct sbmac_softc {
* Prototypes
********************************************************************* */
-static void sbdma_initctx(sbmacdma_t *d,
- struct sbmac_softc *s,
- int chan,
- int txrx,
- int maxdescr);
-static void sbdma_channel_start(sbmacdma_t *d, int rxtx);
-static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
-static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
-static void sbdma_emptyring(sbmacdma_t *d);
-static void sbdma_fillring(sbmacdma_t *d);
-static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll);
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
+static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
+ int txrx, int maxdescr);
+static void sbdma_channel_start(struct sbmacdma *d, int rxtx);
+static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m);
+static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m);
+static void sbdma_emptyring(struct sbmacdma *d);
+static void sbdma_fillring(struct sbmacdma *d);
+static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int work_to_do, int poll);
+static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int poll);
static int sbmac_initctx(struct sbmac_softc *s);
static void sbmac_channel_start(struct sbmac_softc *s);
static void sbmac_channel_stop(struct sbmac_softc *s);
-static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
-static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *,
+ enum sbmac_state);
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff);
static uint64_t sbmac_addr2reg(unsigned char *ptr);
-static irqreturn_t sbmac_intr(int irq,void *dev_instance);
+static irqreturn_t sbmac_intr(int irq, void *dev_instance);
static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
static void sbmac_setmulti(struct sbmac_softc *sc);
-static int sbmac_init(struct net_device *dev, int idx);
-static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
-static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
+static int sbmac_init(struct platform_device *pldev, long long base);
+static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);
+static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
+ enum sbmac_fc fc);
static int sbmac_open(struct net_device *dev);
-static void sbmac_timer(unsigned long data);
static void sbmac_tx_timeout (struct net_device *dev);
-static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
static void sbmac_set_rx_mode(struct net_device *dev);
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int sbmac_close(struct net_device *dev);
-static int sbmac_poll(struct net_device *poll_dev, int *budget);
+static int sbmac_poll(struct napi_struct *napi, int budget);
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+static void sbmac_mii_poll(struct net_device *dev);
static int sbmac_mii_probe(struct net_device *dev);
-static void sbmac_mii_sync(struct sbmac_softc *s);
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx);
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
- unsigned int regval);
+static void sbmac_mii_sync(void __iomem *sbm_mdio);
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
+ int bitcnt);
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx);
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+ u16 val);
/**********************************************************************
* Globals
********************************************************************* */
-static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
+static char sbmac_string[] = "sb1250-mac";
+static char sbmac_pretty[] = "SB1250 MAC";
+
+static char sbmac_mdio_string[] = "sb1250-mac-mdio";
/**********************************************************************
@@ -348,185 +365,66 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
#define MII_COMMAND_WRITE 0x01
#define MII_COMMAND_ACK 0x02
-#define BMCR_RESET 0x8000
-#define BMCR_LOOPBACK 0x4000
-#define BMCR_SPEED0 0x2000
-#define BMCR_ANENABLE 0x1000
-#define BMCR_POWERDOWN 0x0800
-#define BMCR_ISOLATE 0x0400
-#define BMCR_RESTARTAN 0x0200
-#define BMCR_DUPLEX 0x0100
-#define BMCR_COLTEST 0x0080
-#define BMCR_SPEED1 0x0040
-#define BMCR_SPEED1000 BMCR_SPEED1
-#define BMCR_SPEED100 BMCR_SPEED0
-#define BMCR_SPEED10 0
-
-#define BMSR_100BT4 0x8000
-#define BMSR_100BT_FDX 0x4000
-#define BMSR_100BT_HDX 0x2000
-#define BMSR_10BT_FDX 0x1000
-#define BMSR_10BT_HDX 0x0800
-#define BMSR_100BT2_FDX 0x0400
-#define BMSR_100BT2_HDX 0x0200
-#define BMSR_1000BT_XSR 0x0100
-#define BMSR_PRESUP 0x0040
-#define BMSR_ANCOMPLT 0x0020
-#define BMSR_REMFAULT 0x0010
-#define BMSR_AUTONEG 0x0008
-#define BMSR_LINKSTAT 0x0004
-#define BMSR_JABDETECT 0x0002
-#define BMSR_EXTCAPAB 0x0001
-
-#define PHYIDR1 0x2000
-#define PHYIDR2 0x5C60
-
-#define ANAR_NP 0x8000
-#define ANAR_RF 0x2000
-#define ANAR_ASYPAUSE 0x0800
-#define ANAR_PAUSE 0x0400
-#define ANAR_T4 0x0200
-#define ANAR_TXFD 0x0100
-#define ANAR_TXHD 0x0080
-#define ANAR_10FD 0x0040
-#define ANAR_10HD 0x0020
-#define ANAR_PSB 0x0001
-
-#define ANLPAR_NP 0x8000
-#define ANLPAR_ACK 0x4000
-#define ANLPAR_RF 0x2000
-#define ANLPAR_ASYPAUSE 0x0800
-#define ANLPAR_PAUSE 0x0400
-#define ANLPAR_T4 0x0200
-#define ANLPAR_TXFD 0x0100
-#define ANLPAR_TXHD 0x0080
-#define ANLPAR_10FD 0x0040
-#define ANLPAR_10HD 0x0020
-#define ANLPAR_PSB 0x0001 /* 802.3 */
-
-#define ANER_PDF 0x0010
-#define ANER_LPNPABLE 0x0008
-#define ANER_NPABLE 0x0004
-#define ANER_PAGERX 0x0002
-#define ANER_LPANABLE 0x0001
-
-#define ANNPTR_NP 0x8000
-#define ANNPTR_MP 0x2000
-#define ANNPTR_ACK2 0x1000
-#define ANNPTR_TOGTX 0x0800
-#define ANNPTR_CODE 0x0008
-
-#define ANNPRR_NP 0x8000
-#define ANNPRR_MP 0x2000
-#define ANNPRR_ACK3 0x1000
-#define ANNPRR_TOGTX 0x0800
-#define ANNPRR_CODE 0x0008
-
-#define K1TCR_TESTMODE 0x0000
-#define K1TCR_MSMCE 0x1000
-#define K1TCR_MSCV 0x0800
-#define K1TCR_RPTR 0x0400
-#define K1TCR_1000BT_FDX 0x200
-#define K1TCR_1000BT_HDX 0x100
-
-#define K1STSR_MSMCFLT 0x8000
-#define K1STSR_MSCFGRES 0x4000
-#define K1STSR_LRSTAT 0x2000
-#define K1STSR_RRSTAT 0x1000
-#define K1STSR_LP1KFD 0x0800
-#define K1STSR_LP1KHD 0x0400
-#define K1STSR_LPASMDIR 0x0200
-
-#define K1SCR_1KX_FDX 0x8000
-#define K1SCR_1KX_HDX 0x4000
-#define K1SCR_1KT_FDX 0x2000
-#define K1SCR_1KT_HDX 0x1000
-
-#define STRAP_PHY1 0x0800
-#define STRAP_NCMODE 0x0400
-#define STRAP_MANMSCFG 0x0200
-#define STRAP_ANENABLE 0x0100
-#define STRAP_MSVAL 0x0080
-#define STRAP_1KHDXADV 0x0010
-#define STRAP_1KFDXADV 0x0008
-#define STRAP_100ADV 0x0004
-#define STRAP_SPEEDSEL 0x0000
-#define STRAP_SPEED100 0x0001
-
-#define PHYSUP_SPEED1000 0x10
-#define PHYSUP_SPEED100 0x08
-#define PHYSUP_SPEED10 0x00
-#define PHYSUP_LINKUP 0x04
-#define PHYSUP_FDX 0x02
-
-#define MII_BMCR 0x00 /* Basic mode control register (rw) */
-#define MII_BMSR 0x01 /* Basic mode status register (ro) */
-#define MII_PHYIDR1 0x02
-#define MII_PHYIDR2 0x03
-
-#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
-#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
-
-
#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */
#define ENABLE 1
#define DISABLE 0
/**********************************************************************
- * SBMAC_MII_SYNC(s)
+ * SBMAC_MII_SYNC(sbm_mdio)
*
* Synchronize with the MII - send a pattern of bits to the MII
* that will guarantee that it is ready to accept a command.
*
* Input parameters:
- * s - sbmac structure
+ * sbm_mdio - address of the MAC's MDIO register
*
* Return value:
* nothing
********************************************************************* */
-static void sbmac_mii_sync(struct sbmac_softc *s)
+static void sbmac_mii_sync(void __iomem *sbm_mdio)
{
int cnt;
uint64_t bits;
int mac_mdio_genc;
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
for (cnt = 0; cnt < 32; cnt++) {
- __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
}
}
/**********************************************************************
- * SBMAC_MII_SENDDATA(s,data,bitcnt)
+ * SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt)
*
* Send some bits to the MII. The bits to be sent are right-
* justified in the 'data' parameter.
*
* Input parameters:
- * s - sbmac structure
- * data - data to send
- * bitcnt - number of bits to send
+ * sbm_mdio - address of the MAC's MDIO register
+ * data - data to send
+ * bitcnt - number of bits to send
********************************************************************* */
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
+ int bitcnt)
{
int i;
uint64_t bits;
unsigned int curmask;
int mac_mdio_genc;
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
bits = M_MAC_MDIO_DIR_OUTPUT;
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
curmask = 1 << (bitcnt - 1);
@@ -534,9 +432,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
if (data & curmask)
bits |= M_MAC_MDIO_OUT;
else bits &= ~M_MAC_MDIO_OUT;
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
curmask >>= 1;
}
}
@@ -544,21 +442,22 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
/**********************************************************************
- * SBMAC_MII_READ(s,phyaddr,regidx)
- *
+ * SBMAC_MII_READ(bus, phyaddr, regidx)
* Read a PHY register.
*
* Input parameters:
- * s - sbmac structure
+ * bus - MDIO bus handle
* phyaddr - PHY's address
- * regidx = index of register to read
+ * regnum - index of register to read
*
* Return value:
- * value read, or 0 if an error occurred.
+ * value read, or 0xffff if an error occurred.
********************************************************************* */
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
{
+ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
+ void __iomem *sbm_mdio = sc->sbm_mdio;
int idx;
int error;
int regval;
@@ -568,8 +467,7 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* Synchronize ourselves so that the PHY knows the next
* thing coming down is a command
*/
-
- sbmac_mii_sync(s);
+ sbmac_mii_sync(sbm_mdio);
/*
* Send the data to the PHY. The sequence is
@@ -578,37 +476,37 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* the PHY addr (5 bits)
* the register index (5 bits)
*/
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2);
+ sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
+ sbmac_mii_senddata(sbm_mdio, regidx, 5);
- sbmac_mii_senddata(s,MII_COMMAND_START, 2);
- sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
- sbmac_mii_senddata(s,phyaddr, 5);
- sbmac_mii_senddata(s,regidx, 5);
-
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
/*
* Switch the port around without a clock transition.
*/
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
/*
* Send out a clock pulse to signal we want the status
*/
-
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+ sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
/*
* If an error occurred, the PHY will signal '1' back
*/
- error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN;
+ error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN;
/*
* Issue an 'idle' clock pulse, but keep the direction
* the same.
*/
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+ sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
regval = 0;
@@ -616,55 +514,60 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
regval <<= 1;
if (error == 0) {
- if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN)
+ if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN)
regval |= 1;
}
- __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+ sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
}
/* Switch back to output */
- __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
if (error == 0)
return regval;
- return 0;
+ return 0xffff;
}
/**********************************************************************
- * SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
+ * SBMAC_MII_WRITE(bus, phyaddr, regidx, regval)
*
* Write a value to a PHY register.
*
* Input parameters:
- * s - sbmac structure
+ * bus - MDIO bus handle
* phyaddr - PHY to use
- * regidx - register within the PHY
- * regval - data to write to register
+ * regidx - register within the PHY
+ * regval - data to write to register
*
* Return value:
- * nothing
+ * 0 for success
********************************************************************* */
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
- unsigned int regval)
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+ u16 regval)
{
+ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
+ void __iomem *sbm_mdio = sc->sbm_mdio;
int mac_mdio_genc;
- sbmac_mii_sync(s);
+ sbmac_mii_sync(sbm_mdio);
+
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2);
+ sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
+ sbmac_mii_senddata(sbm_mdio, regidx, 5);
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2);
+ sbmac_mii_senddata(sbm_mdio, regval, 16);
- sbmac_mii_senddata(s,MII_COMMAND_START,2);
- sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
- sbmac_mii_senddata(s,phyaddr, 5);
- sbmac_mii_senddata(s,regidx, 5);
- sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
- sbmac_mii_senddata(s,regval,16);
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+ return 0;
}
@@ -677,8 +580,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
* way.
*
* Input parameters:
- * d - sbmacdma_t structure (DMA channel context)
- * s - sbmac_softc structure (pointer to a MAC)
+ * d - struct sbmacdma (DMA channel context)
+ * s - struct sbmac_softc (pointer to a MAC)
* chan - channel number (0..1 right now)
* txrx - Identifies DMA_TX or DMA_RX for channel direction
* maxdescr - number of descriptors
@@ -687,11 +590,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
* nothing
********************************************************************* */
-static void sbdma_initctx(sbmacdma_t *d,
- struct sbmac_softc *s,
- int chan,
- int txrx,
- int maxdescr)
+static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
+ int txrx, int maxdescr)
{
#ifdef CONFIG_SBMAC_COALESCE
int int_pktcnt, int_timeout;
@@ -710,27 +610,27 @@ static void sbdma_initctx(sbmacdma_t *d,
s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
#endif
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)));
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR);
/*
* initialize register pointers
@@ -758,18 +658,17 @@ static void sbdma_initctx(sbmacdma_t *d,
d->sbdma_maxdescr = maxdescr;
- d->sbdma_dscrtable_unaligned =
- d->sbdma_dscrtable = (sbdmadscr_t *)
- kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
+ d->sbdma_dscrtable_unaligned = kcalloc(d->sbdma_maxdescr + 1,
+ sizeof(*d->sbdma_dscrtable),
+ GFP_KERNEL);
/*
* The descriptor table must be aligned to at least 16 bytes or the
* MAC will corrupt it.
*/
- d->sbdma_dscrtable = (sbdmadscr_t *)
- ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t));
-
- memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+ d->sbdma_dscrtable = (struct sbdmadscr *)
+ ALIGN((unsigned long)d->sbdma_dscrtable_unaligned,
+ sizeof(*d->sbdma_dscrtable));
d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
@@ -779,10 +678,8 @@ static void sbdma_initctx(sbmacdma_t *d,
* And context table
*/
- d->sbdma_ctxtable = (struct sk_buff **)
- kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL);
-
- memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
+ d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr,
+ sizeof(*d->sbdma_ctxtable), GFP_KERNEL);
#ifdef CONFIG_SBMAC_COALESCE
/*
@@ -819,7 +716,7 @@ static void sbdma_initctx(sbmacdma_t *d,
* nothing
********************************************************************* */
-static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
+static void sbdma_channel_start(struct sbmacdma *d, int rxtx)
{
/*
* Turn on the DMA channel
@@ -860,7 +757,7 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
* nothing
********************************************************************* */
-static void sbdma_channel_stop(sbmacdma_t *d)
+static void sbdma_channel_stop(struct sbmacdma *d)
{
/*
* Turn off the DMA channel
@@ -909,10 +806,10 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
********************************************************************* */
-static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
+static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
{
- sbdmadscr_t *dsc;
- sbdmadscr_t *nextdsc;
+ struct sbdmadscr *dsc;
+ struct sbdmadscr *nextdsc;
struct sk_buff *sb_new = NULL;
int pktsize = ENET_PACKET_SIZE;
@@ -953,7 +850,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
if (sb == NULL) {
sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
if (sb_new == NULL) {
- printk(KERN_INFO "%s: sk_buff allocation failed\n",
+ pr_info("%s: sk_buff allocation failed\n",
d->sbdma_eth->sbm_dev->name);
return -ENOBUFS;
}
@@ -1024,10 +921,10 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
********************************************************************* */
-static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
+static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *sb)
{
- sbdmadscr_t *dsc;
- sbdmadscr_t *nextdsc;
+ struct sbdmadscr *dsc;
+ struct sbdmadscr *nextdsc;
uint64_t phys;
uint64_t ncb;
int length;
@@ -1113,7 +1010,7 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
* nothing
********************************************************************* */
-static void sbdma_emptyring(sbmacdma_t *d)
+static void sbdma_emptyring(struct sbmacdma *d)
{
int idx;
struct sk_buff *sb;
@@ -1141,7 +1038,7 @@ static void sbdma_emptyring(sbmacdma_t *d)
* nothing
********************************************************************* */
-static void sbdma_fillring(sbmacdma_t *d)
+static void sbdma_fillring(struct sbmacdma *d)
{
int idx;
@@ -1188,12 +1085,13 @@ static void sbmac_netpoll(struct net_device *netdev)
* nothing
********************************************************************* */
-static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
- int work_to_do, int poll)
+static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int work_to_do, int poll)
{
+ struct net_device *dev = sc->sbm_dev;
int curidx;
int hwidx;
- sbdmadscr_t *dsc;
+ struct sbdmadscr *dsc;
struct sk_buff *sb;
int len;
int work_done = 0;
@@ -1203,7 +1101,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
again:
/* Check if the HW dropped any frames */
- sc->sbm_stats.rx_fifo_errors
+ dev->stats.rx_fifo_errors
+= __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
__raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
@@ -1225,8 +1123,9 @@ again:
prefetch(dsc);
prefetch(&d->sbdma_ctxtable[curidx]);
- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+ hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) /
+ sizeof(*d->sbdma_dscrtable);
/*
* If they're the same, that means we've processed all
@@ -1262,7 +1161,7 @@ again:
if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
-ENOBUFS)) {
- sc->sbm_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
/* No point in continuing at the moment */
printk(KERN_ERR "dropped packet (1)\n");
@@ -1298,13 +1197,13 @@ again:
dropped = netif_rx(sb);
if (dropped == NET_RX_DROP) {
- sc->sbm_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
goto done;
}
else {
- sc->sbm_stats.rx_bytes += len;
- sc->sbm_stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
}
}
} else {
@@ -1312,7 +1211,7 @@ again:
* Packet was mangled somehow. Just drop it and
* put it back on the receive ring.
*/
- sc->sbm_stats.rx_errors++;
+ dev->stats.rx_errors++;
sbdma_add_rcvbuffer(d,sb);
}
@@ -1350,11 +1249,13 @@ done:
* nothing
********************************************************************* */
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
+static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int poll)
{
+ struct net_device *dev = sc->sbm_dev;
int curidx;
int hwidx;
- sbdmadscr_t *dsc;
+ struct sbdmadscr *dsc;
struct sk_buff *sb;
unsigned long flags;
int packets_handled = 0;
@@ -1364,8 +1265,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
if (d->sbdma_remptr == d->sbdma_addptr)
goto end_unlock;
- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+ hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(*d->sbdma_dscrtable);
for (;;) {
/*
@@ -1402,8 +1303,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
* Stats
*/
- sc->sbm_stats.tx_bytes += sb->len;
- sc->sbm_stats.tx_packets++;
+ dev->stats.tx_bytes += sb->len;
+ dev->stats.tx_packets++;
/*
* for transmits, we just free buffers.
@@ -1468,14 +1369,6 @@ static int sbmac_initctx(struct sbmac_softc *s)
s->sbm_imr = s->sbm_base + R_MAC_INT_MASK;
s->sbm_mdio = s->sbm_base + R_MAC_MDIO;
- s->sbm_phys[0] = 1;
- s->sbm_phys[1] = 0;
-
- s->sbm_phy_oldbmsr = 0;
- s->sbm_phy_oldanlpar = 0;
- s->sbm_phy_oldk1stsr = 0;
- s->sbm_phy_oldlinkstat = 0;
-
/*
* Initialize the DMA channels. Right now, only one per MAC is used
* Note: Only do this _once_, as it allocates memory from the kernel!
@@ -1490,19 +1383,11 @@ static int sbmac_initctx(struct sbmac_softc *s)
s->sbm_state = sbmac_state_off;
- /*
- * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
- */
-
- s->sbm_speed = sbmac_speed_10;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_disabled;
-
return 0;
}
-static void sbdma_uninitctx(struct sbmacdma_s *d)
+static void sbdma_uninitctx(struct sbmacdma *d)
{
if (d->sbdma_dscrtable_unaligned) {
kfree(d->sbdma_dscrtable_unaligned);
@@ -1538,7 +1423,7 @@ static void sbmac_uninitctx(struct sbmac_softc *sc)
static void sbmac_channel_start(struct sbmac_softc *s)
{
uint64_t reg;
- volatile void __iomem *port;
+ void __iomem *port;
uint64_t cfg,fifo,framecfg;
int idx, th_value;
@@ -1801,10 +1686,10 @@ static void sbmac_channel_stop(struct sbmac_softc *s)
* Return value:
* old state
********************************************************************* */
-static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
- sbmac_state_t state)
+static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *sc,
+ enum sbmac_state state)
{
- sbmac_state_t oldstate = sc->sbm_state;
+ enum sbmac_state oldstate = sc->sbm_state;
/*
* If same as previous state, return
@@ -1939,14 +1824,14 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr)
*
* Input parameters:
* s - sbmac structure
- * speed - speed to set MAC to (see sbmac_speed_t enum)
+ * speed - speed to set MAC to (see enum sbmac_speed)
*
* Return value:
* 1 if successful
* 0 indicates invalid parameters
********************************************************************* */
-static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
+static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed)
{
uint64_t cfg;
uint64_t framecfg;
@@ -2004,8 +1889,6 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
break;
- case sbmac_speed_auto: /* XXX not implemented */
- /* fall through */
default:
return 0;
}
@@ -2028,15 +1911,16 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
*
* Input parameters:
* s - sbmac structure
- * duplex - duplex setting (see sbmac_duplex_t)
- * fc - flow control setting (see sbmac_fc_t)
+ * duplex - duplex setting (see enum sbmac_duplex)
+ * fc - flow control setting (see enum sbmac_fc)
*
* Return value:
* 1 if ok
* 0 if an invalid parameter combination was specified
********************************************************************* */
-static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
+static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
+ enum sbmac_fc fc)
{
uint64_t cfg;
@@ -2078,8 +1962,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
break;
- case sbmac_fc_auto: /* XXX not implemented */
- /* fall through */
case sbmac_fc_frame: /* not valid in half duplex */
default: /* invalid selection */
return 0;
@@ -2098,15 +1980,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
case sbmac_fc_collision: /* not valid in full duplex */
case sbmac_fc_carrier: /* not valid in full duplex */
- case sbmac_fc_auto: /* XXX not implemented */
- /* fall through */
default:
return 0;
}
break;
- case sbmac_duplex_auto:
- /* XXX not implemented */
- break;
+ default:
+ return 0;
}
/*
@@ -2154,20 +2033,13 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance)
* Transmits on channel 0
*/
- if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0))
sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
-#ifdef CONFIG_NETPOLL_TRAP
- if (netpoll_trap()) {
- if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
- __netif_schedule(dev);
- }
-#endif
- }
if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &sc->napi)) {
__raw_writeq(0, sc->sbm_imr);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &sc->napi);
/* Depend on the exit from poll to reenable intr */
}
else {
@@ -2236,7 +2108,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
static void sbmac_setmulti(struct sbmac_softc *sc)
{
uint64_t reg;
- volatile void __iomem *port;
+ void __iomem *port;
int idx;
struct dev_mc_list *mclist;
struct net_device *dev = sc->sbm_dev;
@@ -2392,7 +2264,7 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
if (new_mtu > ENET_PACKET_SIZE)
return -EINVAL;
_dev->mtu = new_mtu;
- printk(KERN_INFO "changing the mtu to %d\n", new_mtu);
+ pr_info("changing the mtu to %d\n", new_mtu);
return 0;
}
@@ -2408,19 +2280,17 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
* status
********************************************************************* */
-static int sbmac_init(struct net_device *dev, int idx)
+static int sbmac_init(struct platform_device *pldev, long long base)
{
- struct sbmac_softc *sc;
+ struct net_device *dev = pldev->dev.driver_data;
+ int idx = pldev->id;
+ struct sbmac_softc *sc = netdev_priv(dev);
unsigned char *eaddr;
uint64_t ea_reg;
int i;
int err;
+ DECLARE_MAC_BUF(mac);
- sc = netdev_priv(dev);
-
- /* Determine controller base address */
-
- sc->sbm_base = IOADDR(dev->base_addr);
sc->sbm_dev = dev;
sc->sbe_idx = idx;
@@ -2465,58 +2335,67 @@ static int sbmac_init(struct net_device *dev, int idx)
dev->open = sbmac_open;
dev->hard_start_xmit = sbmac_start_tx;
dev->stop = sbmac_close;
- dev->get_stats = sbmac_get_stats;
dev->set_multicast_list = sbmac_set_rx_mode;
dev->do_ioctl = sbmac_mii_ioctl;
dev->tx_timeout = sbmac_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->poll = sbmac_poll;
- dev->weight = 16;
+
+ netif_napi_add(dev, &sc->napi, sbmac_poll, 16);
dev->change_mtu = sb1250_change_mtu;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = sbmac_netpoll;
#endif
+ dev->irq = UNIT_INT(idx);
+
/* This is needed for PASS2 for Rx H/W checksum feature */
sbmac_set_iphdr_offset(sc);
err = register_netdev(dev);
- if (err)
- goto out_uninit;
-
- if (sc->rx_hw_checksum == ENABLE) {
- printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
- sc->sbm_dev->name);
+ if (err) {
+ printk(KERN_ERR "%s.%d: unable to register netdev\n",
+ sbmac_string, idx);
+ sbmac_uninitctx(sc);
+ return err;
}
+ pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name);
+
+ if (sc->rx_hw_checksum == ENABLE)
+ pr_info("%s: enabling TCP rcv checksum\n", dev->name);
+
/*
* Display Ethernet address (this is called during the config
* process so we need to finish off the config message that
* was being displayed)
*/
- printk(KERN_INFO
- "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->name, dev->base_addr,
- eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
-
+ pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n",
+ dev->name, base, print_mac(mac, eaddr));
- return 0;
+ sc->mii_bus.name = sbmac_mdio_string;
+ sc->mii_bus.id = idx;
+ sc->mii_bus.priv = sc;
+ sc->mii_bus.read = sbmac_mii_read;
+ sc->mii_bus.write = sbmac_mii_write;
+ sc->mii_bus.irq = sc->phy_irq;
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ sc->mii_bus.irq[i] = SBMAC_PHY_INT;
-out_uninit:
- sbmac_uninitctx(sc);
+ sc->mii_bus.dev = &pldev->dev;
+ dev_set_drvdata(&pldev->dev, &sc->mii_bus);
- return err;
+ return 0;
}
static int sbmac_open(struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
+ int err;
- if (debug > 1) {
- printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
- }
+ if (debug > 1)
+ pr_debug("%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
/*
* map/route interrupt (clear status first, in case something
@@ -2525,23 +2404,35 @@ static int sbmac_open(struct net_device *dev)
*/
__raw_readq(sc->sbm_isr);
- if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev))
- return -EBUSY;
+ err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev);
+ if (err) {
+ printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
+ dev->irq);
+ goto out_err;
+ }
/*
- * Probe phy address
+ * Probe PHY address
*/
-
- if(sbmac_mii_probe(dev) == -1) {
- printk("%s: failed to probe PHY.\n", dev->name);
- return -EINVAL;
+ err = mdiobus_register(&sc->mii_bus);
+ if (err) {
+ printk(KERN_ERR "%s: unable to register MDIO bus\n",
+ dev->name);
+ goto out_unirq;
}
+ sc->sbm_speed = sbmac_speed_none;
+ sc->sbm_duplex = sbmac_duplex_none;
+ sc->sbm_fc = sbmac_fc_none;
+ sc->sbm_pause = -1;
+ sc->sbm_link = 0;
+
/*
- * Configure default speed
+ * Attach to the PHY
*/
-
- sbmac_mii_poll(sc,noisy_mii);
+ err = sbmac_mii_probe(dev);
+ if (err)
+ goto out_unregister;
/*
* Turn on the channel
@@ -2549,200 +2440,133 @@ static int sbmac_open(struct net_device *dev)
sbmac_set_channel_state(sc,sbmac_state_on);
- /*
- * XXX Station address is in dev->dev_addr
- */
-
- if (dev->if_port == 0)
- dev->if_port = 0;
-
netif_start_queue(dev);
sbmac_set_rx_mode(dev);
- /* Set the timer to check for link beat. */
- init_timer(&sc->sbm_timer);
- sc->sbm_timer.expires = jiffies + 2 * HZ/100;
- sc->sbm_timer.data = (unsigned long)dev;
- sc->sbm_timer.function = &sbmac_timer;
- add_timer(&sc->sbm_timer);
+ phy_start(sc->phy_dev);
+
+ napi_enable(&sc->napi);
return 0;
+
+out_unregister:
+ mdiobus_unregister(&sc->mii_bus);
+
+out_unirq:
+ free_irq(dev->irq, dev);
+
+out_err:
+ return err;
}
static int sbmac_mii_probe(struct net_device *dev)
{
+ struct sbmac_softc *sc = netdev_priv(dev);
+ struct phy_device *phy_dev;
int i;
- struct sbmac_softc *s = netdev_priv(dev);
- u16 bmsr, id1, id2;
- u32 vendor, device;
-
- for (i=1; i<31; i++) {
- bmsr = sbmac_mii_read(s, i, MII_BMSR);
- if (bmsr != 0) {
- s->sbm_phys[0] = i;
- id1 = sbmac_mii_read(s, i, MII_PHYIDR1);
- id2 = sbmac_mii_read(s, i, MII_PHYIDR2);
- vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f);
- device = (id2 >> 4) & 0x3f;
-
- printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n",
- dev->name, i, vendor, device);
- return i;
- }
- }
- return -1;
-}
-
-
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
-{
- int bmsr,bmcr,k1stsr,anlpar;
- int chg;
- char buffer[100];
- char *p = buffer;
- /* Read the mode status and mode control registers. */
- bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
- bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
-
- /* get the link partner status */
- anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
-
- /* if supported, read the 1000baseT register */
- if (bmsr & BMSR_1000BT_XSR) {
- k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
- }
- else {
- k1stsr = 0;
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ phy_dev = sc->mii_bus.phy_map[i];
+ if (phy_dev)
+ break;
}
-
- chg = 0;
-
- if ((bmsr & BMSR_LINKSTAT) == 0) {
- /*
- * If link status is down, clear out old info so that when
- * it comes back up it will force us to reconfigure speed
- */
- s->sbm_phy_oldbmsr = 0;
- s->sbm_phy_oldanlpar = 0;
- s->sbm_phy_oldk1stsr = 0;
- return 0;
+ if (!phy_dev) {
+ printk(KERN_ERR "%s: no PHY found\n", dev->name);
+ return -ENXIO;
}
- if ((s->sbm_phy_oldbmsr != bmsr) ||
- (s->sbm_phy_oldanlpar != anlpar) ||
- (s->sbm_phy_oldk1stsr != k1stsr)) {
- if (debug > 1) {
- printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n",
- s->sbm_dev->name,
- s->sbm_phy_oldbmsr,bmsr,
- s->sbm_phy_oldanlpar,anlpar,
- s->sbm_phy_oldk1stsr,k1stsr);
- }
- s->sbm_phy_oldbmsr = bmsr;
- s->sbm_phy_oldanlpar = anlpar;
- s->sbm_phy_oldk1stsr = k1stsr;
- chg = 1;
+ phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0,
+ PHY_INTERFACE_MODE_GMII);
+ if (IS_ERR(phy_dev)) {
+ printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
+ return PTR_ERR(phy_dev);
}
- if (chg == 0)
- return 0;
+ /* Remove any features not supported by the controller */
+ phy_dev->supported &= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_MII |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause;
+ phy_dev->advertising = phy_dev->supported;
- p += sprintf(p,"Link speed: ");
-
- if (k1stsr & K1STSR_LP1KFD) {
- s->sbm_speed = sbmac_speed_1000;
- s->sbm_duplex = sbmac_duplex_full;
- s->sbm_fc = sbmac_fc_frame;
- p += sprintf(p,"1000BaseT FDX");
- }
- else if (k1stsr & K1STSR_LP1KHD) {
- s->sbm_speed = sbmac_speed_1000;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_disabled;
- p += sprintf(p,"1000BaseT HDX");
- }
- else if (anlpar & ANLPAR_TXFD) {
- s->sbm_speed = sbmac_speed_100;
- s->sbm_duplex = sbmac_duplex_full;
- s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
- p += sprintf(p,"100BaseT FDX");
- }
- else if (anlpar & ANLPAR_TXHD) {
- s->sbm_speed = sbmac_speed_100;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_disabled;
- p += sprintf(p,"100BaseT HDX");
- }
- else if (anlpar & ANLPAR_10FD) {
- s->sbm_speed = sbmac_speed_10;
- s->sbm_duplex = sbmac_duplex_full;
- s->sbm_fc = sbmac_fc_frame;
- p += sprintf(p,"10BaseT FDX");
- }
- else if (anlpar & ANLPAR_10HD) {
- s->sbm_speed = sbmac_speed_10;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_collision;
- p += sprintf(p,"10BaseT HDX");
- }
- else {
- p += sprintf(p,"Unknown");
- }
+ pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+ dev->name, phy_dev->drv->name,
+ phy_dev->dev.bus_id, phy_dev->irq);
- if (noisy) {
- printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
- }
+ sc->phy_dev = phy_dev;
- return 1;
+ return 0;
}
-static void sbmac_timer(unsigned long data)
+static void sbmac_mii_poll(struct net_device *dev)
{
- struct net_device *dev = (struct net_device *)data;
struct sbmac_softc *sc = netdev_priv(dev);
- int next_tick = HZ;
- int mii_status;
+ struct phy_device *phy_dev = sc->phy_dev;
+ unsigned long flags;
+ enum sbmac_fc fc;
+ int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg;
+
+ link_chg = (sc->sbm_link != phy_dev->link);
+ speed_chg = (sc->sbm_speed != phy_dev->speed);
+ duplex_chg = (sc->sbm_duplex != phy_dev->duplex);
+ pause_chg = (sc->sbm_pause != phy_dev->pause);
+
+ if (!link_chg && !speed_chg && !duplex_chg && !pause_chg)
+ return; /* Hmmm... */
+
+ if (!phy_dev->link) {
+ if (link_chg) {
+ sc->sbm_link = phy_dev->link;
+ sc->sbm_speed = sbmac_speed_none;
+ sc->sbm_duplex = sbmac_duplex_none;
+ sc->sbm_fc = sbmac_fc_disabled;
+ sc->sbm_pause = -1;
+ pr_info("%s: link unavailable\n", dev->name);
+ }
+ return;
+ }
- spin_lock_irq (&sc->sbm_lock);
+ if (phy_dev->duplex == DUPLEX_FULL) {
+ if (phy_dev->pause)
+ fc = sbmac_fc_frame;
+ else
+ fc = sbmac_fc_disabled;
+ } else
+ fc = sbmac_fc_collision;
+ fc_chg = (sc->sbm_fc != fc);
- /* make IFF_RUNNING follow the MII status bit "Link established" */
- mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
+ pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed,
+ phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H');
- if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
- sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
- if (mii_status & BMSR_LINKSTAT) {
- netif_carrier_on(dev);
- }
- else {
- netif_carrier_off(dev);
- }
- }
+ spin_lock_irqsave(&sc->sbm_lock, flags);
- /*
- * Poll the PHY to see what speed we should be running at
- */
+ sc->sbm_speed = phy_dev->speed;
+ sc->sbm_duplex = phy_dev->duplex;
+ sc->sbm_fc = fc;
+ sc->sbm_pause = phy_dev->pause;
+ sc->sbm_link = phy_dev->link;
- if (sbmac_mii_poll(sc,noisy_mii)) {
- if (sc->sbm_state != sbmac_state_off) {
- /*
- * something changed, restart the channel
- */
- if (debug > 1) {
- printk("%s: restarting channel because speed changed\n",
- sc->sbm_dev->name);
- }
- sbmac_channel_stop(sc);
- sbmac_channel_start(sc);
- }
+ if ((speed_chg || duplex_chg || fc_chg) &&
+ sc->sbm_state != sbmac_state_off) {
+ /*
+ * something changed, restart the channel
+ */
+ if (debug > 1)
+ pr_debug("%s: restarting channel "
+ "because PHY state changed\n", dev->name);
+ sbmac_channel_stop(sc);
+ sbmac_channel_start(sc);
}
- spin_unlock_irq (&sc->sbm_lock);
-
- sc->sbm_timer.expires = jiffies + next_tick;
- add_timer(&sc->sbm_timer);
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
}
@@ -2754,7 +2578,7 @@ static void sbmac_tx_timeout (struct net_device *dev)
dev->trans_start = jiffies;
- sc->sbm_stats.tx_errors++;
+ dev->stats.tx_errors++;
spin_unlock_irq (&sc->sbm_lock);
@@ -2764,22 +2588,6 @@ static void sbmac_tx_timeout (struct net_device *dev)
-static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
-{
- struct sbmac_softc *sc = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&sc->sbm_lock, flags);
-
- /* XXX update other stats here */
-
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
-
- return &sc->sbm_stats;
-}
-
-
-
static void sbmac_set_rx_mode(struct net_device *dev)
{
unsigned long flags;
@@ -2811,62 +2619,34 @@ static void sbmac_set_rx_mode(struct net_device *dev)
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct sbmac_softc *sc = netdev_priv(dev);
- u16 *data = (u16 *)&rq->ifr_ifru;
- unsigned long flags;
- int retval;
- spin_lock_irqsave(&sc->sbm_lock, flags);
- retval = 0;
-
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- data[0] = sc->sbm_phys[0] & 0x1f;
- /* Fall Through */
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
- break;
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!capable(CAP_NET_ADMIN)) {
- retval = -EPERM;
- break;
- }
- if (debug > 1) {
- printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
- data[0],data[1],data[2]);
- }
- sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
- break;
- default:
- retval = -EOPNOTSUPP;
- }
+ if (!netif_running(dev) || !sc->phy_dev)
+ return -EINVAL;
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
- return retval;
+ return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd);
}
static int sbmac_close(struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
- unsigned long flags;
- int irq;
- sbmac_set_channel_state(sc,sbmac_state_off);
+ napi_disable(&sc->napi);
- del_timer_sync(&sc->sbm_timer);
+ phy_stop(sc->phy_dev);
- spin_lock_irqsave(&sc->sbm_lock, flags);
+ sbmac_set_channel_state(sc, sbmac_state_off);
netif_stop_queue(dev);
- if (debug > 1) {
- printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
- }
+ if (debug > 1)
+ pr_debug("%s: Shutting down ethercard\n", dev->name);
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
+ phy_disconnect(sc->phy_dev);
+ sc->phy_dev = NULL;
+
+ mdiobus_unregister(&sc->mii_bus);
- irq = dev->irq;
- synchronize_irq(irq);
- free_irq(irq, dev);
+ free_irq(dev->irq, dev);
sbdma_emptyring(&(sc->sbm_txdma));
sbdma_emptyring(&(sc->sbm_rxdma));
@@ -2874,26 +2654,17 @@ static int sbmac_close(struct net_device *dev)
return 0;
}
-static int sbmac_poll(struct net_device *dev, int *budget)
+static int sbmac_poll(struct napi_struct *napi, int budget)
{
- int work_to_do;
+ struct sbmac_softc *sc = container_of(napi, struct sbmac_softc, napi);
+ struct net_device *dev = sc->sbm_dev;
int work_done;
- struct sbmac_softc *sc = netdev_priv(dev);
-
- work_to_do = min(*budget, dev->quota);
- work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1);
-
- if (work_done > work_to_do)
- printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
- sc->sbm_dev->name, *budget, dev->quota, work_done);
+ work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), budget, 1);
sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done < work_to_do) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
#ifdef CONFIG_SBMAC_COALESCE
__raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
@@ -2905,57 +2676,198 @@ static int sbmac_poll(struct net_device *dev, int *budget)
#endif
}
- return (work_done >= work_to_do);
+ return work_done;
+}
+
+
+static int __init sbmac_probe(struct platform_device *pldev)
+{
+ struct net_device *dev;
+ struct sbmac_softc *sc;
+ void __iomem *sbm_base;
+ struct resource *res;
+ u64 sbmac_orig_hwaddr;
+ int err;
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ BUG_ON(!res);
+ sbm_base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (!sbm_base) {
+ printk(KERN_ERR "%s: unable to map device registers\n",
+ pldev->dev.bus_id);
+ err = -ENOMEM;
+ goto out_out;
+ }
+
+ /*
+ * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
+ * value for us by the firmware if we're going to use this MAC.
+ * If we find a zero, skip this MAC.
+ */
+ sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
+ pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id,
+ sbmac_orig_hwaddr ? "" : "not ", (long long)res->start);
+ if (sbmac_orig_hwaddr == 0) {
+ err = 0;
+ goto out_unmap;
+ }
+
+ /*
+ * Okay, cool. Initialize this MAC.
+ */
+ dev = alloc_etherdev(sizeof(struct sbmac_softc));
+ if (!dev) {
+ printk(KERN_ERR "%s: unable to allocate etherdev\n",
+ pldev->dev.bus_id);
+ err = -ENOMEM;
+ goto out_unmap;
+ }
+
+ pldev->dev.driver_data = dev;
+ SET_NETDEV_DEV(dev, &pldev->dev);
+
+ sc = netdev_priv(dev);
+ sc->sbm_base = sbm_base;
+
+ err = sbmac_init(pldev, res->start);
+ if (err)
+ goto out_kfree;
+
+ return 0;
+
+out_kfree:
+ free_netdev(dev);
+ __raw_writeq(sbmac_orig_hwaddr, sbm_base + R_MAC_ETHERNET_ADDR);
+
+out_unmap:
+ iounmap(sbm_base);
+
+out_out:
+ return err;
+}
+
+static int __exit sbmac_remove(struct platform_device *pldev)
+{
+ struct net_device *dev = pldev->dev.driver_data;
+ struct sbmac_softc *sc = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ sbmac_uninitctx(sc);
+ iounmap(sc->sbm_base);
+ free_netdev(dev);
+
+ return 0;
}
+
+static struct platform_device **sbmac_pldev;
+static int sbmac_max_units;
+
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
-static void
-sbmac_setup_hwaddr(int chan,char *addr)
+static void __init sbmac_setup_hwaddr(int idx, char *addr)
{
+ void __iomem *sbm_base;
+ unsigned long start, end;
uint8_t eaddr[6];
uint64_t val;
- unsigned long port;
- port = A_MAC_CHANNEL_BASE(chan);
- sbmac_parse_hwaddr(addr,eaddr);
+ if (idx >= sbmac_max_units)
+ return;
+
+ start = A_MAC_CHANNEL_BASE(idx);
+ end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
+
+ sbm_base = ioremap_nocache(start, end - start + 1);
+ if (!sbm_base) {
+ printk(KERN_ERR "%s: unable to map device registers\n",
+ sbmac_string);
+ return;
+ }
+
+ sbmac_parse_hwaddr(addr, eaddr);
val = sbmac_addr2reg(eaddr);
- __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR));
- val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
+ __raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR);
+ val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
+
+ iounmap(sbm_base);
}
#endif
-static struct net_device *dev_sbmac[MAX_UNITS];
+static int __init sbmac_platform_probe_one(int idx)
+{
+ struct platform_device *pldev;
+ struct {
+ struct resource r;
+ char name[strlen(sbmac_pretty) + 4];
+ } *res;
+ int err;
+
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ printk(KERN_ERR "%s.%d: unable to allocate memory\n",
+ sbmac_string, idx);
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ /*
+ * This is the base address of the MAC.
+ */
+ snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx);
+ res->r.name = res->name;
+ res->r.flags = IORESOURCE_MEM;
+ res->r.start = A_MAC_CHANNEL_BASE(idx);
+ res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
+
+ pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1);
+ if (IS_ERR(pldev)) {
+ printk(KERN_ERR "%s.%d: unable to register platform device\n",
+ sbmac_string, idx);
+ err = PTR_ERR(pldev);
+ goto out_kfree;
+ }
+
+ if (!pldev->dev.driver) {
+ err = 0; /* No hardware at this address. */
+ goto out_unregister;
+ }
+
+ sbmac_pldev[idx] = pldev;
+ return 0;
+
+out_unregister:
+ platform_device_unregister(pldev);
+
+out_kfree:
+ kfree(res);
+
+out_err:
+ return err;
+}
-static int __init
-sbmac_init_module(void)
+static void __init sbmac_platform_probe(void)
{
- int idx;
- struct net_device *dev;
- unsigned long port;
- int chip_max_units;
+ int i;
/* Set the number of available units based on the SOC type. */
switch (soc_type) {
case K_SYS_SOC_TYPE_BCM1250:
case K_SYS_SOC_TYPE_BCM1250_ALT:
- chip_max_units = 3;
+ sbmac_max_units = 3;
break;
case K_SYS_SOC_TYPE_BCM1120:
case K_SYS_SOC_TYPE_BCM1125:
case K_SYS_SOC_TYPE_BCM1125H:
- case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
- chip_max_units = 2;
+ case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
+ sbmac_max_units = 2;
break;
case K_SYS_SOC_TYPE_BCM1x55:
case K_SYS_SOC_TYPE_BCM1x80:
- chip_max_units = 4;
+ sbmac_max_units = 4;
break;
default:
- chip_max_units = 0;
- break;
+ return; /* none */
}
- if (chip_max_units > MAX_UNITS)
- chip_max_units = MAX_UNITS;
/*
* For bringup when not using the firmware, we can pre-fill
@@ -2963,89 +2875,71 @@ sbmac_init_module(void)
* specified in this file (or maybe from the config file?)
*/
#ifdef SBMAC_ETH0_HWADDR
- if (chip_max_units > 0)
- sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+ sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR);
#endif
#ifdef SBMAC_ETH1_HWADDR
- if (chip_max_units > 1)
- sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+ sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR);
#endif
#ifdef SBMAC_ETH2_HWADDR
- if (chip_max_units > 2)
- sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+ sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR);
#endif
#ifdef SBMAC_ETH3_HWADDR
- if (chip_max_units > 3)
- sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR);
+ sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR);
#endif
+ sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev),
+ GFP_KERNEL);
+ if (!sbmac_pldev) {
+ printk(KERN_ERR "%s: unable to allocate memory\n",
+ sbmac_string);
+ return;
+ }
+
/*
* Walk through the Ethernet controllers and find
* those who have their MAC addresses set.
*/
- for (idx = 0; idx < chip_max_units; idx++) {
+ for (i = 0; i < sbmac_max_units; i++)
+ if (sbmac_platform_probe_one(i))
+ break;
+}
- /*
- * This is the base address of the MAC.
- */
- port = A_MAC_CHANNEL_BASE(idx);
+static void __exit sbmac_platform_cleanup(void)
+{
+ int i;
- /*
- * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
- * value for us by the firmware if we are going to use this MAC.
- * If we find a zero, skip this MAC.
- */
+ for (i = 0; i < sbmac_max_units; i++)
+ platform_device_unregister(sbmac_pldev[i]);
+ kfree(sbmac_pldev);
+}
- sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
- if (sbmac_orig_hwaddr[idx] == 0) {
- printk(KERN_DEBUG "sbmac: not configuring MAC at "
- "%lx\n", port);
- continue;
- }
- /*
- * Okay, cool. Initialize this MAC.
- */
+static struct platform_driver sbmac_driver = {
+ .probe = sbmac_probe,
+ .remove = __exit_p(sbmac_remove),
+ .driver = {
+ .name = sbmac_string,
+ },
+};
- dev = alloc_etherdev(sizeof(struct sbmac_softc));
- if (!dev)
- return -ENOMEM;
+static int __init sbmac_init_module(void)
+{
+ int err;
- printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
+ err = platform_driver_register(&sbmac_driver);
+ if (err)
+ return err;
- dev->irq = UNIT_INT(idx);
- dev->base_addr = port;
- dev->mem_end = 0;
- if (sbmac_init(dev, idx)) {
- port = A_MAC_CHANNEL_BASE(idx);
- __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR));
- free_netdev(dev);
- continue;
- }
- dev_sbmac[idx] = dev;
- }
- return 0;
-}
+ sbmac_platform_probe();
+ return err;
+}
-static void __exit
-sbmac_cleanup_module(void)
+static void __exit sbmac_cleanup_module(void)
{
- struct net_device *dev;
- int idx;
-
- for (idx = 0; idx < MAX_UNITS; idx++) {
- struct sbmac_softc *sc;
- dev = dev_sbmac[idx];
- if (!dev)
- continue;
-
- sc = netdev_priv(dev);
- unregister_netdev(dev);
- sbmac_uninitctx(sc);
- free_netdev(dev);
- }
+ sbmac_platform_cleanup();
+ platform_driver_unregister(&sbmac_driver);
}
module_init(sbmac_init_module);
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 5b7284c955dc..37b42394560d 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -1372,9 +1372,14 @@ static void sc92031_ethtool_get_strings(struct net_device *dev,
SILAN_STATS_NUM * ETH_GSTRING_LEN);
}
-static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset)
{
- return SILAN_STATS_NUM;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return SILAN_STATS_NUM;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
@@ -1396,14 +1401,9 @@ static struct ethtool_ops sc92031_ethtool_ops = {
.set_wol = sc92031_ethtool_set_wol,
.nway_reset = sc92031_ethtool_nway_reset,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.get_strings = sc92031_ethtool_get_strings,
- .get_stats_count = sc92031_ethtool_get_stats_count,
+ .get_sset_count = sc92031_ethtool_get_sset_count,
.get_ethtool_stats = sc92031_ethtool_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
- .get_ufo = ethtool_op_get_ufo,
};
static int __devinit sc92031_probe(struct pci_dev *pdev,
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 4bce7c4f373c..48c64fb20eec 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -67,7 +67,6 @@ static unsigned int net_debug = NET_DEBUG;
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */
long open_time; /* Useless example local info. */
};
@@ -86,7 +85,6 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
static void seeq8005_rx(struct net_device *dev);
static int seeq8005_close(struct net_device *dev);
-static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
/* Example routines you must write ;->. */
@@ -160,6 +158,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
int old_dmaar;
int old_rear;
int retval;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
return -ENODEV;
@@ -303,7 +302,8 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]);
+ dev->dev_addr[i] = SA_prom[i+6];
+ printk("%s", print_mac(mac, dev->dev_addr));
if (dev->irq == 0xff)
; /* Do nothing: a user-level program will set it. */
@@ -338,7 +338,6 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
dev->hard_start_xmit = seeq8005_send_packet;
dev->tx_timeout = seeq8005_timeout;
dev->watchdog_timeo = HZ/20;
- dev->get_stats = seeq8005_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->flags &= ~IFF_MULTICAST;
@@ -391,7 +390,6 @@ static void seeq8005_timeout(struct net_device *dev)
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
short length = skb->len;
unsigned char *buf;
@@ -407,7 +405,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
hardware_send_packet(dev, buf, length);
dev->trans_start = jiffies;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_bytes += length;
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
@@ -463,7 +461,7 @@ static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
if (status & SEEQSTAT_TX_INT) {
handled = 1;
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & SEEQSTAT_RX_INT) {
@@ -531,11 +529,11 @@ static void seeq8005_rx(struct net_device *dev)
}
if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
- lp->stats.rx_errors++;
- if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++;
- if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++;
- if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++;
- if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++;
+ dev->stats.rx_errors++;
+ if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
+ if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
+ if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
+ if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
/* skip over this packet */
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
@@ -547,7 +545,7 @@ static void seeq8005_rx(struct net_device *dev)
skb = dev_alloc_skb(pkt_len);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb, 2); /* align data on 16 byte */
@@ -567,8 +565,8 @@ static void seeq8005_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
@@ -599,15 +597,6 @@ static int seeq8005_close(struct net_device *dev)
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *seeq8005_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 384b4685e977..ff4056310356 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -75,6 +75,7 @@ struct sgiseeq_init_block { /* Note the name ;-) */
struct sgiseeq_private {
struct sgiseeq_init_block *srings;
+ dma_addr_t srings_dma;
/* Ptrs to the descriptors in uncached space. */
struct sgiseeq_rx_desc *rx_desc;
@@ -92,8 +93,6 @@ struct sgiseeq_private {
unsigned char control;
unsigned char mode;
- struct net_device_stats stats;
-
spinlock_t tx_lock;
};
@@ -266,18 +265,17 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
return 0;
}
-static inline void record_rx_errors(struct sgiseeq_private *sp,
- unsigned char status)
+static void record_rx_errors(struct net_device *dev, unsigned char status)
{
if (status & SEEQ_RSTAT_OVERF ||
status & SEEQ_RSTAT_SFRAME)
- sp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (status & SEEQ_RSTAT_CERROR)
- sp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & SEEQ_RSTAT_DERROR)
- sp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & SEEQ_RSTAT_REOF)
- sp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
static inline void rx_maybe_restart(struct sgiseeq_private *sp,
@@ -327,8 +325,8 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
netif_rx(skb);
dev->last_rx = jiffies;
- sp->stats.rx_packets++;
- sp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
} else {
/* Silently drop my own packets */
dev_kfree_skb_irq(skb);
@@ -336,10 +334,10 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
} else {
printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
dev->name);
- sp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
} else {
- record_rx_errors(sp, pkt_status);
+ record_rx_errors(dev, pkt_status);
}
/* Return the entry to the ring pool. */
@@ -391,11 +389,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) {
/* Oops, HPC detected some sort of error. */
if (status & SEEQ_TSTAT_R16)
- sp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & SEEQ_TSTAT_UFLOW)
- sp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (status & SEEQ_TSTAT_LCLS)
- sp->stats.collisions++;
+ dev->stats.collisions++;
}
/* Ack 'em... */
@@ -411,7 +409,7 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
}
break;
}
- sp->stats.tx_packets++;
+ dev->stats.tx_packets++;
sp->tx_old = NEXT_TX(sp->tx_old);
td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);
td->tdma.cntinfo |= HPCDMA_EOX;
@@ -515,7 +513,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Setup... */
skblen = skb->len;
len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
- sp->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
entry = sp->tx_new;
td = &sp->tx_desc[entry];
@@ -568,13 +566,6 @@ static void timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev)
-{
- struct sgiseeq_private *sp = netdev_priv(dev);
-
- return &sp->stats;
-}
-
static void sgiseeq_set_multicast(struct net_device *dev)
{
struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
@@ -631,6 +622,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
struct sgiseeq_private *sp;
struct net_device *dev;
int err, i;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof (struct sgiseeq_private));
if (!dev) {
@@ -643,13 +635,20 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
sp = netdev_priv(dev);
/* Make private data page aligned */
- sr = (struct sgiseeq_init_block *) get_zeroed_page(GFP_KERNEL);
+ sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings),
+ &sp->srings_dma, GFP_KERNEL);
if (!sr) {
printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_free_dev;
}
sp->srings = sr;
+ sp->rx_desc = sp->srings->rxvector;
+ sp->tx_desc = sp->srings->txvector;
+
+ /* A couple calculations now, saves many cycles later. */
+ setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
+ setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
@@ -662,19 +661,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
sp->name = sgiseeqstr;
sp->mode = SEEQ_RCMD_RBCAST;
- sp->rx_desc = (struct sgiseeq_rx_desc *)
- CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
- dma_cache_wback_inv((unsigned long)&sp->srings->rxvector,
- sizeof(sp->srings->rxvector));
- sp->tx_desc = (struct sgiseeq_tx_desc *)
- CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
- dma_cache_wback_inv((unsigned long)&sp->srings->txvector,
- sizeof(sp->srings->txvector));
-
- /* A couple calculations now, saves many cycles later. */
- setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
- setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
-
/* Setup PIO and DMA transfer timing */
sp->hregs->pconfig = 0x161;
sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
@@ -699,7 +685,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
dev->hard_start_xmit = sgiseeq_start_xmit;
dev->tx_timeout = timeout;
dev->watchdog_timeo = (200 * HZ) / 1000;
- dev->get_stats = sgiseeq_get_stats;
dev->set_multicast_list = sgiseeq_set_multicast;
dev->set_mac_address = sgiseeq_set_mac_address;
dev->irq = irq;
@@ -711,9 +696,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
goto err_out_free_page;
}
- printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: %s %s\n",
+ dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr));
return 0;
@@ -726,15 +710,18 @@ err_out:
return err;
}
-static void __exit sgiseeq_remove(struct platform_device *pdev)
+static int __exit sgiseeq_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sgiseeq_private *sp = netdev_priv(dev);
unregister_netdev(dev);
- free_page((unsigned long) sp->srings);
+ dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
+ sp->srings_dma);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
+
+ return 0;
}
static struct platform_driver sgiseeq_driver = {
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index e886e8d7cfdf..228f650250f6 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -86,6 +86,7 @@
#include <net/dst.h>
#include <net/arp.h>
+#include <net/net_namespace.h>
struct shaper_cb {
unsigned long shapeclock; /* Time it should go out */
@@ -170,7 +171,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) {
dev_kfree_skb(skb);
- shaper->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
} else
skb_queue_tail(&shaper->sendq, skb);
}
@@ -181,7 +182,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
ptr=skb_dequeue(&shaper->sendq);
dev_kfree_skb(ptr);
- shaper->stats.collisions++;
+ dev->stats.collisions++;
}
shaper_kick(shaper);
spin_unlock(&shaper->lock);
@@ -206,8 +207,8 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
shaper->dev->name,newskb->priority);
dev_queue_xmit(newskb);
- shaper->stats.tx_bytes += skb->len;
- shaper->stats.tx_packets++;
+ shaper->dev->stats.tx_bytes += skb->len;
+ shaper->dev->stats.tx_packets++;
if(sh_debug)
printk("Kicked new frame out.\n");
@@ -329,22 +330,17 @@ static int shaper_close(struct net_device *dev)
* ARP and other resolutions and not before.
*/
-static struct net_device_stats *shaper_get_stats(struct net_device *dev)
-{
- struct shaper *sh=dev->priv;
- return &sh->stats;
-}
-
static int shaper_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
+ unsigned short type,
+ const void *daddr, const void *saddr, unsigned len)
{
struct shaper *sh=dev->priv;
int v;
if(sh_debug)
printk("Shaper header\n");
- skb->dev=sh->dev;
- v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
- skb->dev=dev;
+ skb->dev = sh->dev;
+ v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len);
+ skb->dev = dev;
return v;
}
@@ -356,7 +352,7 @@ static int shaper_rebuild_header(struct sk_buff *skb)
if(sh_debug)
printk("Shaper rebuild header\n");
skb->dev=sh->dev;
- v=sh->rebuild_header(skb);
+ v = sh->dev->header_ops->rebuild(skb);
skb->dev=dev;
return v;
}
@@ -420,51 +416,17 @@ static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
#endif
+static const struct header_ops shaper_ops = {
+ .create = shaper_header,
+ .rebuild = shaper_rebuild_header,
+};
+
static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev)
{
sh->dev = dev;
- sh->hard_start_xmit=dev->hard_start_xmit;
sh->get_stats=dev->get_stats;
- if(dev->hard_header)
- {
- sh->hard_header=dev->hard_header;
- shdev->hard_header = shaper_header;
- }
- else
- shdev->hard_header = NULL;
-
- if(dev->rebuild_header)
- {
- sh->rebuild_header = dev->rebuild_header;
- shdev->rebuild_header = shaper_rebuild_header;
- }
- else
- shdev->rebuild_header = NULL;
-#if 0
- if(dev->hard_header_cache)
- {
- sh->hard_header_cache = dev->hard_header_cache;
- shdev->hard_header_cache= shaper_cache;
- }
- else
- {
- shdev->hard_header_cache= NULL;
- }
-
- if(dev->header_cache_update)
- {
- sh->header_cache_update = dev->header_cache_update;
- shdev->header_cache_update = shaper_cache_update;
- }
- else
- shdev->header_cache_update= NULL;
-#else
- shdev->header_cache_update = NULL;
- shdev->hard_header_cache = NULL;
-#endif
shdev->neigh_setup = shaper_neigh_setup_dev;
-
shdev->hard_header_len=dev->hard_header_len;
shdev->type=dev->type;
shdev->addr_len=dev->addr_len;
@@ -488,7 +450,7 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
case SHAPER_SET_DEV:
{
- struct net_device *them=__dev_get_by_name(ss->ss_name);
+ struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name);
if(them==NULL)
return -ENODEV;
if(sh->dev)
@@ -532,14 +494,11 @@ static void __init shaper_setup(struct net_device *dev)
* Set up the shaper.
*/
- SET_MODULE_OWNER(dev);
-
shaper_init_priv(dev);
dev->open = shaper_open;
dev->stop = shaper_close;
dev->hard_start_xmit = shaper_start_xmit;
- dev->get_stats = shaper_get_stats;
dev->set_multicast_list = NULL;
/*
@@ -550,12 +509,6 @@ static void __init shaper_setup(struct net_device *dev)
* Handlers for when we attach to a device.
*/
- dev->hard_header = shaper_header;
- dev->rebuild_header = shaper_rebuild_header;
-#if 0
- dev->hard_header_cache = shaper_cache;
- dev->header_cache_update= shaper_cache_update;
-#endif
dev->neigh_setup = shaper_neigh_setup_dev;
dev->do_ioctl = shaper_ioctl;
dev->hard_header_len = 0;
@@ -600,10 +553,9 @@ static int __init shaper_init(void)
return -ENODEV;
alloc_size = sizeof(*dev) * shapers;
- devs = kmalloc(alloc_size, GFP_KERNEL);
+ devs = kzalloc(alloc_size, GFP_KERNEL);
if (!devs)
return -ENOMEM;
- memset(devs, 0, alloc_size);
for (i = 0; i < shapers; i++) {
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index ec2ad9f0efa2..720088396bb9 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -47,24 +47,13 @@
#define PHY_ID_ANY 0x1f
#define MII_REG_ANY 0x1f
-#ifdef CONFIG_SIS190_NAPI
-#define NAPI_SUFFIX "-NAPI"
-#else
-#define NAPI_SUFFIX ""
-#endif
-
-#define DRV_VERSION "1.2" NAPI_SUFFIX
+#define DRV_VERSION "1.2"
#define DRV_NAME "sis190"
#define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
#define PFX DRV_NAME ": "
-#ifdef CONFIG_SIS190_NAPI
-#define sis190_rx_skb netif_receive_skb
-#define sis190_rx_quota(count, quota) min(count, quota)
-#else
#define sis190_rx_skb netif_rx
#define sis190_rx_quota(count, quota) count
-#endif
#define MAC_ADDR_LEN 6
@@ -281,7 +270,6 @@ struct sis190_private {
void __iomem *mmio_addr;
struct pci_dev *pci_dev;
struct net_device *dev;
- struct net_device_stats stats;
spinlock_t lock;
u32 rx_buf_sz;
u32 cur_rx;
@@ -580,7 +568,7 @@ static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
static int sis190_rx_interrupt(struct net_device *dev,
struct sis190_private *tp, void __iomem *ioaddr)
{
- struct net_device_stats *stats = &tp->stats;
+ struct net_device_stats *stats = &dev->stats;
u32 rx_left, cur_rx = tp->cur_rx;
u32 delta, count;
@@ -694,8 +682,8 @@ static void sis190_tx_interrupt(struct net_device *dev,
skb = tp->Tx_skbuff[entry];
- tp->stats.tx_packets++;
- tp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
tp->Tx_skbuff[entry] = NULL;
@@ -1091,7 +1079,7 @@ static void sis190_tx_clear(struct sis190_private *tp)
tp->Tx_skbuff[i] = NULL;
dev_kfree_skb(skb);
- tp->stats.tx_dropped++;
+ tp->dev->stats.tx_dropped++;
}
tp->cur_tx = tp->dirty_tx = 0;
}
@@ -1115,10 +1103,8 @@ static void sis190_down(struct net_device *dev)
synchronize_irq(dev->irq);
- if (!poll_locked) {
- netif_poll_disable(dev);
+ if (!poll_locked)
poll_locked++;
- }
synchronize_sched();
@@ -1137,8 +1123,6 @@ static int sis190_close(struct net_device *dev)
free_irq(dev->irq, dev);
- netif_poll_enable(dev);
-
pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma);
pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma);
@@ -1158,7 +1142,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len < ETH_ZLEN)) {
if (skb_padto(skb, ETH_ZLEN)) {
- tp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
goto out;
}
len = ETH_ZLEN;
@@ -1211,13 +1195,6 @@ out:
return NETDEV_TX_OK;
}
-static struct net_device_stats *sis190_get_stats(struct net_device *dev)
-{
- struct sis190_private *tp = netdev_priv(dev);
-
- return &tp->stats;
-}
-
static void sis190_free_phy(struct list_head *first_phy)
{
struct sis190_phy *cur, *next;
@@ -1436,7 +1413,6 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
goto err_out_0;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
@@ -1593,6 +1569,9 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
pci_name(pdev));
isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL);
+ if (!isa_bridge)
+ isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0966, NULL);
+
if (!isa_bridge) {
net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
pci_name(pdev));
@@ -1780,6 +1759,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
struct net_device *dev;
void __iomem *ioaddr;
int rc;
+ DECLARE_MAC_BUF(mac);
if (!printed_version) {
net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n");
@@ -1808,7 +1788,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
dev->open = sis190_open;
dev->stop = sis190_close;
dev->do_ioctl = sis190_ioctl;
- dev->get_stats = sis190_get_stats;
dev->tx_timeout = sis190_tx_timeout;
dev->watchdog_timeo = SIS190_TX_TIMEOUT;
dev->hard_start_xmit = sis190_start_xmit;
@@ -1831,12 +1810,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
goto err_remove_mii;
net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- pci_name(pdev), sis_chip_info[ent->driver_data].name,
- ioaddr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ "%s\n",
+ pci_name(pdev), sis_chip_info[ent->driver_data].name,
+ ioaddr, dev->irq, print_mac(mac, dev->dev_addr));
net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
(tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 7c6e4808399a..0857d2c88aa0 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -158,7 +158,6 @@ typedef struct _BufferDesc {
} BufferDesc;
struct sis900_private {
- struct net_device_stats stats;
struct pci_dev * pci_dev;
spinlock_t lock;
@@ -221,7 +220,6 @@ static void sis900_finish_xmit (struct net_device *net_dev);
static irqreturn_t sis900_interrupt(int irq, void *dev_instance);
static int sis900_close(struct net_device *net_dev);
static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
static u16 sis900_mcast_bitnr(u8 *addr, u8 revision);
static void set_rx_mode(struct net_device *net_dev);
static void sis900_reset(struct net_device *net_dev);
@@ -406,6 +404,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
int i, ret;
const char *card_name = card_names[pci_id->driver_data];
const char *dev_name = pci_name(pci_dev);
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -430,7 +429,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
net_dev = alloc_etherdev(sizeof(struct sis900_private));
if (!net_dev)
return -ENOMEM;
- SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pci_dev->dev);
/* We do a request_region() to register /proc/ioports info. */
@@ -467,7 +465,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
net_dev->open = &sis900_open;
net_dev->hard_start_xmit = &sis900_start_xmit;
net_dev->stop = &sis900_close;
- net_dev->get_stats = &sis900_get_stats;
net_dev->set_config = &sis900_set_config;
net_dev->set_multicast_list = &set_rx_mode;
net_dev->do_ioctl = &mii_ioctl;
@@ -537,11 +534,9 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
goto err_unmap_rx;
/* print some information about our NIC */
- printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
- card_name, ioaddr, net_dev->irq);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", (u8)net_dev->dev_addr[i]);
- printk("%2.2x.\n", net_dev->dev_addr[i]);
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+ net_dev->name, card_name, ioaddr, net_dev->irq,
+ print_mac(mac, net_dev->dev_addr));
/* Detect Wake on Lan support */
ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27;
@@ -1543,7 +1538,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
sis_priv->tx_skbuff[i] = NULL;
sis_priv->tx_ring[i].cmdsts = 0;
sis_priv->tx_ring[i].bufptr = 0;
- sis_priv->stats.tx_dropped++;
+ net_dev->stats.tx_dropped++;
}
}
sis_priv->tx_full = 0;
@@ -1740,15 +1735,15 @@ static int sis900_rx(struct net_device *net_dev)
printk(KERN_DEBUG "%s: Corrupted packet "
"received, buffer status = 0x%8.8x/%d.\n",
net_dev->name, rx_status, data_size);
- sis_priv->stats.rx_errors++;
+ net_dev->stats.rx_errors++;
if (rx_status & OVERRUN)
- sis_priv->stats.rx_over_errors++;
+ net_dev->stats.rx_over_errors++;
if (rx_status & (TOOLONG|RUNT))
- sis_priv->stats.rx_length_errors++;
+ net_dev->stats.rx_length_errors++;
if (rx_status & (RXISERR | FAERR))
- sis_priv->stats.rx_frame_errors++;
+ net_dev->stats.rx_frame_errors++;
if (rx_status & CRCERR)
- sis_priv->stats.rx_crc_errors++;
+ net_dev->stats.rx_crc_errors++;
/* reset buffer descriptor state */
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
} else {
@@ -1769,7 +1764,7 @@ static int sis900_rx(struct net_device *net_dev)
* in the rx ring
*/
skb = sis_priv->rx_skbuff[entry];
- sis_priv->stats.rx_dropped++;
+ net_dev->stats.rx_dropped++;
goto refill_rx_ring;
}
@@ -1794,10 +1789,10 @@ static int sis900_rx(struct net_device *net_dev)
/* some network statistics */
if ((rx_status & BCAST) == MCAST)
- sis_priv->stats.multicast++;
+ net_dev->stats.multicast++;
net_dev->last_rx = jiffies;
- sis_priv->stats.rx_bytes += rx_size;
- sis_priv->stats.rx_packets++;
+ net_dev->stats.rx_bytes += rx_size;
+ net_dev->stats.rx_packets++;
sis_priv->dirty_rx++;
refill_rx_ring:
sis_priv->rx_skbuff[entry] = skb;
@@ -1828,7 +1823,7 @@ refill_rx_ring:
printk(KERN_INFO "%s: Memory squeeze,"
"deferring packet.\n",
net_dev->name);
- sis_priv->stats.rx_dropped++;
+ net_dev->stats.rx_dropped++;
break;
}
sis_priv->rx_skbuff[entry] = skb;
@@ -1879,20 +1874,20 @@ static void sis900_finish_xmit (struct net_device *net_dev)
printk(KERN_DEBUG "%s: Transmit "
"error, Tx status %8.8x.\n",
net_dev->name, tx_status);
- sis_priv->stats.tx_errors++;
+ net_dev->stats.tx_errors++;
if (tx_status & UNDERRUN)
- sis_priv->stats.tx_fifo_errors++;
+ net_dev->stats.tx_fifo_errors++;
if (tx_status & ABORT)
- sis_priv->stats.tx_aborted_errors++;
+ net_dev->stats.tx_aborted_errors++;
if (tx_status & NOCARRIER)
- sis_priv->stats.tx_carrier_errors++;
+ net_dev->stats.tx_carrier_errors++;
if (tx_status & OWCOLL)
- sis_priv->stats.tx_window_errors++;
+ net_dev->stats.tx_window_errors++;
} else {
/* packet successfully transmitted */
- sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
- sis_priv->stats.tx_bytes += tx_status & DSIZE;
- sis_priv->stats.tx_packets++;
+ net_dev->stats.collisions += (tx_status & COLCNT) >> 16;
+ net_dev->stats.tx_bytes += tx_status & DSIZE;
+ net_dev->stats.tx_packets++;
}
/* Free the original skb. */
skb = sis_priv->tx_skbuff[entry];
@@ -2139,21 +2134,6 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
}
/**
- * sis900_get_stats - Get sis900 read/write statistics
- * @net_dev: the net device to get statistics for
- *
- * get tx/rx statistics for sis900
- */
-
-static struct net_device_stats *
-sis900_get_stats(struct net_device *net_dev)
-{
- struct sis900_private *sis_priv = net_dev->priv;
-
- return &sis_priv->stats;
-}
-
-/**
* sis900_set_config - Set media type by net_device.set_config
* @dev: the net device for media type change
* @map: ifmap passed by ifconfig
diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile
new file mode 100644
index 000000000000..afd900d5d730
--- /dev/null
+++ b/drivers/net/sk98lin/Makefile
@@ -0,0 +1,87 @@
+#
+# Makefile for the SysKonnect SK-98xx device driver.
+#
+
+
+#
+# Standalone driver params
+# SKPARAM += -DSK_KERNEL_24
+# SKPARAM += -DSK_KERNEL_24_26
+# SKPARAM += -DSK_KERNEL_26
+# SKPARAM += -DSK_KERNEL_22_24
+
+obj-$(CONFIG_SK98LIN) += sk98lin.o
+sk98lin-objs := \
+ skge.o \
+ skethtool.o \
+ skdim.o \
+ skaddr.o \
+ skgehwt.o \
+ skgeinit.o \
+ skgepnmi.o \
+ skgesirq.o \
+ ski2c.o \
+ sklm80.o \
+ skqueue.o \
+ skrlmt.o \
+ sktimer.o \
+ skvpd.o \
+ skxmac2.o
+
+# DBGDEF = \
+# -DDEBUG
+
+ifdef DEBUG
+DBGDEF += \
+-DSK_DEBUG_CHKMOD=0x00000000L \
+-DSK_DEBUG_CHKCAT=0x00000000L
+endif
+
+
+# **** possible debug modules for SK_DEBUG_CHKMOD *****************
+# SK_DBGMOD_MERR 0x00000001L /* general module error indication */
+# SK_DBGMOD_HWM 0x00000002L /* Hardware init module */
+# SK_DBGMOD_RLMT 0x00000004L /* RLMT module */
+# SK_DBGMOD_VPD 0x00000008L /* VPD module */
+# SK_DBGMOD_I2C 0x00000010L /* I2C module */
+# SK_DBGMOD_PNMI 0x00000020L /* PNMI module */
+# SK_DBGMOD_CSUM 0x00000040L /* CSUM module */
+# SK_DBGMOD_ADDR 0x00000080L /* ADDR module */
+# SK_DBGMOD_DRV 0x00010000L /* DRV module */
+
+# **** possible debug categories for SK_DEBUG_CHKCAT **************
+# *** common modules ***
+# SK_DBGCAT_INIT 0x00000001L module/driver initialization
+# SK_DBGCAT_CTRL 0x00000002L controlling: add/rmv MCA/MAC and other controls (IOCTL)
+# SK_DBGCAT_ERR 0x00000004L error handling paths
+# SK_DBGCAT_TX 0x00000008L transmit path
+# SK_DBGCAT_RX 0x00000010L receive path
+# SK_DBGCAT_IRQ 0x00000020L general IRQ handling
+# SK_DBGCAT_QUEUE 0x00000040L any queue management
+# SK_DBGCAT_DUMP 0x00000080L large data output e.g. hex dump
+# SK_DBGCAT_FATAL 0x00000100L large data output e.g. hex dump
+
+# *** driver (file skge.c) ***
+# SK_DBGCAT_DRV_ENTRY 0x00010000 entry points
+# SK_DBGCAT_DRV_??? 0x00020000 not used
+# SK_DBGCAT_DRV_MCA 0x00040000 multicast
+# SK_DBGCAT_DRV_TX_PROGRESS 0x00080000 tx path
+# SK_DBGCAT_DRV_RX_PROGRESS 0x00100000 rx path
+# SK_DBGCAT_DRV_PROGRESS 0x00200000 general runtime
+# SK_DBGCAT_DRV_??? 0x00400000 not used
+# SK_DBGCAT_DRV_PROM 0x00800000 promiscuous mode
+# SK_DBGCAT_DRV_TX_FRAME 0x01000000 display tx frames
+# SK_DBGCAT_DRV_ERROR 0x02000000 error conditions
+# SK_DBGCAT_DRV_INT_SRC 0x04000000 interrupts sources
+# SK_DBGCAT_DRV_EVENT 0x08000000 driver events
+
+EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM)
+
+clean:
+ rm -f core *.o *.a *.s
+
+
+
+
+
+
diff --git a/drivers/net/sk98lin/h/lm80.h b/drivers/net/sk98lin/h/lm80.h
new file mode 100644
index 000000000000..4e2dbbf78000
--- /dev/null
+++ b/drivers/net/sk98lin/h/lm80.h
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Name: lm80.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.6 $
+ * Date: $Date: 2003/05/13 17:26:52 $
+ * Purpose: Contains all defines for the LM80 Chip
+ * (National Semiconductor).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_LM80_H
+#define __INC_LM80_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * LM80 register definition
+ *
+ * All registers are 8 bit wide
+ */
+#define LM80_CFG 0x00 /* Configuration Register */
+#define LM80_ISRC_1 0x01 /* Interrupt Status Register 1 */
+#define LM80_ISRC_2 0x02 /* Interrupt Status Register 2 */
+#define LM80_IMSK_1 0x03 /* Interrupt Mask Register 1 */
+#define LM80_IMSK_2 0x04 /* Interrupt Mask Register 2 */
+#define LM80_FAN_CTRL 0x05 /* Fan Devisor/RST#/OS# Register */
+#define LM80_TEMP_CTRL 0x06 /* OS# Config, Temp Res. Reg */
+ /* 0x07 - 0x1f reserved */
+ /* current values */
+#define LM80_VT0_IN 0x20 /* current Voltage 0 value */
+#define LM80_VT1_IN 0x21 /* current Voltage 1 value */
+#define LM80_VT2_IN 0x22 /* current Voltage 2 value */
+#define LM80_VT3_IN 0x23 /* current Voltage 3 value */
+#define LM80_VT4_IN 0x24 /* current Voltage 4 value */
+#define LM80_VT5_IN 0x25 /* current Voltage 5 value */
+#define LM80_VT6_IN 0x26 /* current Voltage 6 value */
+#define LM80_TEMP_IN 0x27 /* current Temperature value */
+#define LM80_FAN1_IN 0x28 /* current Fan 1 count */
+#define LM80_FAN2_IN 0x29 /* current Fan 2 count */
+ /* limit values */
+#define LM80_VT0_HIGH_LIM 0x2a /* high limit val for Voltage 0 */
+#define LM80_VT0_LOW_LIM 0x2b /* low limit val for Voltage 0 */
+#define LM80_VT1_HIGH_LIM 0x2c /* high limit val for Voltage 1 */
+#define LM80_VT1_LOW_LIM 0x2d /* low limit val for Voltage 1 */
+#define LM80_VT2_HIGH_LIM 0x2e /* high limit val for Voltage 2 */
+#define LM80_VT2_LOW_LIM 0x2f /* low limit val for Voltage 2 */
+#define LM80_VT3_HIGH_LIM 0x30 /* high limit val for Voltage 3 */
+#define LM80_VT3_LOW_LIM 0x31 /* low limit val for Voltage 3 */
+#define LM80_VT4_HIGH_LIM 0x32 /* high limit val for Voltage 4 */
+#define LM80_VT4_LOW_LIM 0x33 /* low limit val for Voltage 4 */
+#define LM80_VT5_HIGH_LIM 0x34 /* high limit val for Voltage 5 */
+#define LM80_VT5_LOW_LIM 0x35 /* low limit val for Voltage 5 */
+#define LM80_VT6_HIGH_LIM 0x36 /* high limit val for Voltage 6 */
+#define LM80_VT6_LOW_LIM 0x37 /* low limit val for Voltage 6 */
+#define LM80_THOT_LIM_UP 0x38 /* hot temperature limit (high) */
+#define LM80_THOT_LIM_LO 0x39 /* hot temperature limit (low) */
+#define LM80_TOS_LIM_UP 0x3a /* OS temperature limit (high) */
+#define LM80_TOS_LIM_LO 0x3b /* OS temperature limit (low) */
+#define LM80_FAN1_COUNT_LIM 0x3c /* Fan 1 count limit (high) */
+#define LM80_FAN2_COUNT_LIM 0x3d /* Fan 2 count limit (low) */
+ /* 0x3e - 0x3f reserved */
+
+/*
+ * LM80 bit definitions
+ */
+
+/* LM80_CFG Configuration Register */
+#define LM80_CFG_START (1<<0) /* start monitoring operation */
+#define LM80_CFG_INT_ENA (1<<1) /* enables the INT# Interrupt output */
+#define LM80_CFG_INT_POL (1<<2) /* INT# pol: 0 act low, 1 act high */
+#define LM80_CFG_INT_CLR (1<<3) /* disables INT#/RST_OUT#/OS# outputs */
+#define LM80_CFG_RESET (1<<4) /* signals a reset */
+#define LM80_CFG_CHASS_CLR (1<<5) /* clears Chassis Intrusion (CI) pin */
+#define LM80_CFG_GPO (1<<6) /* drives the GPO# pin */
+#define LM80_CFG_INIT (1<<7) /* restore power on defaults */
+
+/* LM80_ISRC_1 Interrupt Status Register 1 */
+/* LM80_IMSK_1 Interrupt Mask Register 1 */
+#define LM80_IS_VT0 (1<<0) /* limit exceeded for Voltage 0 */
+#define LM80_IS_VT1 (1<<1) /* limit exceeded for Voltage 1 */
+#define LM80_IS_VT2 (1<<2) /* limit exceeded for Voltage 2 */
+#define LM80_IS_VT3 (1<<3) /* limit exceeded for Voltage 3 */
+#define LM80_IS_VT4 (1<<4) /* limit exceeded for Voltage 4 */
+#define LM80_IS_VT5 (1<<5) /* limit exceeded for Voltage 5 */
+#define LM80_IS_VT6 (1<<6) /* limit exceeded for Voltage 6 */
+#define LM80_IS_INT_IN (1<<7) /* state of INT_IN# */
+
+/* LM80_ISRC_2 Interrupt Status Register 2 */
+/* LM80_IMSK_2 Interrupt Mask Register 2 */
+#define LM80_IS_TEMP (1<<0) /* HOT temperature limit exceeded */
+#define LM80_IS_BTI (1<<1) /* state of BTI# pin */
+#define LM80_IS_FAN1 (1<<2) /* count limit exceeded for Fan 1 */
+#define LM80_IS_FAN2 (1<<3) /* count limit exceeded for Fan 2 */
+#define LM80_IS_CI (1<<4) /* Chassis Intrusion occured */
+#define LM80_IS_OS (1<<5) /* OS temperature limit exceeded */
+ /* bit 6 and 7 are reserved in LM80_ISRC_2 */
+#define LM80_IS_HT_IRQ_MD (1<<6) /* Hot temperature interrupt mode */
+#define LM80_IS_OT_IRQ_MD (1<<7) /* OS temperature interrupt mode */
+
+/* LM80_FAN_CTRL Fan Devisor/RST#/OS# Register */
+#define LM80_FAN1_MD_SEL (1<<0) /* Fan 1 mode select */
+#define LM80_FAN2_MD_SEL (1<<1) /* Fan 2 mode select */
+#define LM80_FAN1_PRM_CTL (3<<2) /* Fan 1 speed control */
+#define LM80_FAN2_PRM_CTL (3<<4) /* Fan 2 speed control */
+#define LM80_FAN_OS_ENA (1<<6) /* enable OS mode on RST_OUT#/OS# pins*/
+#define LM80_FAN_RST_ENA (1<<7) /* sets RST_OUT#/OS# pins in RST mode */
+
+/* LM80_TEMP_CTRL OS# Config, Temp Res. Reg */
+#define LM80_TEMP_OS_STAT (1<<0) /* mirrors the state of RST_OUT#/OS# */
+#define LM80_TEMP_OS_POL (1<<1) /* select OS# polarity */
+#define LM80_TEMP_OS_MODE (1<<2) /* selects Interrupt mode */
+#define LM80_TEMP_RES (1<<3) /* selects 9 or 11 bit temp resulution*/
+#define LM80_TEMP_LSB (0xf<<4)/* 4 LSBs of 11 bit temp data */
+#define LM80_TEMP_LSB_9 (1<<7) /* LSB of 9 bit temperature data */
+
+ /* 0x07 - 0x1f reserved */
+/* LM80_VT0_IN current Voltage 0 value */
+/* LM80_VT1_IN current Voltage 1 value */
+/* LM80_VT2_IN current Voltage 2 value */
+/* LM80_VT3_IN current Voltage 3 value */
+/* LM80_VT4_IN current Voltage 4 value */
+/* LM80_VT5_IN current Voltage 5 value */
+/* LM80_VT6_IN current Voltage 6 value */
+/* LM80_TEMP_IN current temperature value */
+/* LM80_FAN1_IN current Fan 1 count */
+/* LM80_FAN2_IN current Fan 2 count */
+/* LM80_VT0_HIGH_LIM high limit val for Voltage 0 */
+/* LM80_VT0_LOW_LIM low limit val for Voltage 0 */
+/* LM80_VT1_HIGH_LIM high limit val for Voltage 1 */
+/* LM80_VT1_LOW_LIM low limit val for Voltage 1 */
+/* LM80_VT2_HIGH_LIM high limit val for Voltage 2 */
+/* LM80_VT2_LOW_LIM low limit val for Voltage 2 */
+/* LM80_VT3_HIGH_LIM high limit val for Voltage 3 */
+/* LM80_VT3_LOW_LIM low limit val for Voltage 3 */
+/* LM80_VT4_HIGH_LIM high limit val for Voltage 4 */
+/* LM80_VT4_LOW_LIM low limit val for Voltage 4 */
+/* LM80_VT5_HIGH_LIM high limit val for Voltage 5 */
+/* LM80_VT5_LOW_LIM low limit val for Voltage 5 */
+/* LM80_VT6_HIGH_LIM high limit val for Voltage 6 */
+/* LM80_VT6_LOW_LIM low limit val for Voltage 6 */
+/* LM80_THOT_LIM_UP hot temperature limit (high) */
+/* LM80_THOT_LIM_LO hot temperature limit (low) */
+/* LM80_TOS_LIM_UP OS temperature limit (high) */
+/* LM80_TOS_LIM_LO OS temperature limit (low) */
+/* LM80_FAN1_COUNT_LIM Fan 1 count limit (high) */
+/* LM80_FAN2_COUNT_LIM Fan 2 count limit (low) */
+ /* 0x3e - 0x3f reserved */
+
+#define LM80_ADDR 0x28 /* LM80 default addr */
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_LM80_H */
diff --git a/drivers/net/sk98lin/h/skaddr.h b/drivers/net/sk98lin/h/skaddr.h
new file mode 100644
index 000000000000..423ad063d09b
--- /dev/null
+++ b/drivers/net/sk98lin/h/skaddr.h
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ * Name: skaddr.h
+ * Project: Gigabit Ethernet Adapters, ADDR-Modul
+ * Version: $Revision: 1.29 $
+ * Date: $Date: 2003/05/13 16:57:24 $
+ * Purpose: Header file for Address Management (MC, UC, Prom).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses and promiscuous mode
+ * on GEnesis adapters.
+ *
+ * Include File Hierarchy:
+ *
+ * "skdrv1st.h"
+ * ...
+ * "sktypes.h"
+ * "skqueue.h"
+ * "skaddr.h"
+ * ...
+ * "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKADDR_H
+#define __INC_SKADDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_MAC_ADDR_LEN 6 /* Length of MAC address. */
+#define SK_MAX_ADDRS 14 /* #Addrs for exact match. */
+
+/* ----- Common return values ----- */
+
+#define SK_ADDR_SUCCESS 0 /* Function returned successfully. */
+#define SK_ADDR_ILLEGAL_PORT 100 /* Port number too high. */
+#define SK_ADDR_TOO_EARLY 101 /* Function called too early. */
+
+/* ----- Clear/Add flag bits ----- */
+
+#define SK_ADDR_PERMANENT 1 /* RLMT Address */
+
+/* ----- Additional Clear flag bits ----- */
+
+#define SK_MC_SW_ONLY 2 /* Do not update HW when clearing. */
+
+/* ----- Override flag bits ----- */
+
+#define SK_ADDR_LOGICAL_ADDRESS 0
+#define SK_ADDR_VIRTUAL_ADDRESS (SK_ADDR_LOGICAL_ADDRESS) /* old */
+#define SK_ADDR_PHYSICAL_ADDRESS 1
+#define SK_ADDR_CLEAR_LOGICAL 2
+#define SK_ADDR_SET_LOGICAL 4
+
+/* ----- Override return values ----- */
+
+#define SK_ADDR_OVERRIDE_SUCCESS (SK_ADDR_SUCCESS)
+#define SK_ADDR_DUPLICATE_ADDRESS 1
+#define SK_ADDR_MULTICAST_ADDRESS 2
+
+/* ----- Partitioning of excact match table ----- */
+
+#define SK_ADDR_EXACT_MATCHES 16 /* #Exact match entries. */
+
+#define SK_ADDR_FIRST_MATCH_RLMT 1
+#define SK_ADDR_LAST_MATCH_RLMT 2
+#define SK_ADDR_FIRST_MATCH_DRV 3
+#define SK_ADDR_LAST_MATCH_DRV (SK_ADDR_EXACT_MATCHES - 1)
+
+/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */
+
+#define SK_MC_FILTERING_EXACT 0 /* Exact filtering. */
+#define SK_MC_FILTERING_INEXACT 1 /* Inexact filtering. */
+
+/* ----- Additional SkAddrMcAdd return values ----- */
+
+#define SK_MC_ILLEGAL_ADDRESS 2 /* Illegal address. */
+#define SK_MC_ILLEGAL_PORT 3 /* Illegal port (not the active one). */
+#define SK_MC_RLMT_OVERFLOW 4 /* Too many RLMT mc addresses. */
+
+/* Promiscuous mode bits ----- */
+
+#define SK_PROM_MODE_NONE 0 /* Normal receive. */
+#define SK_PROM_MODE_LLC 1 /* Receive all LLC frames. */
+#define SK_PROM_MODE_ALL_MC 2 /* Receive all multicast frames. */
+/* #define SK_PROM_MODE_NON_LLC 4 */ /* Receive all non-LLC frames. */
+
+/* Macros */
+
+#ifdef OLD_STUFF
+#ifndef SK_ADDR_EQUAL
+/*
+ * "&" instead of "&&" allows better optimization on IA-64.
+ * The replacement is safe here, as all bytes exist.
+ */
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2) ( \
+ (((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \
+ (((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \
+ (((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \
+ (((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \
+ (((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \
+ (((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]))
+#else /* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2) ( \
+ (*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \
+ (*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
+#endif /* SK_ADDR_DWORD_COMPARE */
+#endif /* SK_ADDR_EQUAL */
+#endif /* 0 */
+
+#ifndef SK_ADDR_EQUAL
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2) ( \
+ (((SK_U8 SK_FAR *)(A1))[5] == ((SK_U8 SK_FAR *)(A2))[5]) & \
+ (((SK_U8 SK_FAR *)(A1))[4] == ((SK_U8 SK_FAR *)(A2))[4]) & \
+ (((SK_U8 SK_FAR *)(A1))[3] == ((SK_U8 SK_FAR *)(A2))[3]) & \
+ (((SK_U8 SK_FAR *)(A1))[2] == ((SK_U8 SK_FAR *)(A2))[2]) & \
+ (((SK_U8 SK_FAR *)(A1))[1] == ((SK_U8 SK_FAR *)(A2))[1]) & \
+ (((SK_U8 SK_FAR *)(A1))[0] == ((SK_U8 SK_FAR *)(A2))[0]))
+#else /* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2) ( \
+ (*(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[4]) == \
+ *(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[4])) && \
+ (*(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[0]) == \
+ *(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[0])))
+#endif /* SK_ADDR_DWORD_COMPARE */
+#endif /* SK_ADDR_EQUAL */
+
+/* typedefs *******************************************************************/
+
+typedef struct s_MacAddr {
+ SK_U8 a[SK_MAC_ADDR_LEN];
+} SK_MAC_ADDR;
+
+
+/* SK_FILTER is used to ensure alignment of the filter. */
+typedef union s_InexactFilter {
+ SK_U8 Bytes[8];
+ SK_U64 Val; /* Dummy entry for alignment only. */
+} SK_FILTER64;
+
+
+typedef struct s_AddrNet SK_ADDR_NET;
+
+
+typedef struct s_AddrPort {
+
+/* ----- Public part (read-only) ----- */
+
+ SK_MAC_ADDR CurrentMacAddress; /* Current physical MAC Address. */
+ SK_MAC_ADDR PermanentMacAddress; /* Permanent physical MAC Address. */
+ int PromMode; /* Promiscuous Mode. */
+
+/* ----- Private part ----- */
+
+ SK_MAC_ADDR PreviousMacAddress; /* Prev. phys. MAC Address. */
+ SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */
+ SK_U8 Align01;
+
+ SK_U32 FirstExactMatchRlmt;
+ SK_U32 NextExactMatchRlmt;
+ SK_U32 FirstExactMatchDrv;
+ SK_U32 NextExactMatchDrv;
+ SK_MAC_ADDR Exact[SK_ADDR_EXACT_MATCHES];
+ SK_FILTER64 InexactFilter; /* For 64-bit hash register. */
+ SK_FILTER64 InexactRlmtFilter; /* For 64-bit hash register. */
+ SK_FILTER64 InexactDrvFilter; /* For 64-bit hash register. */
+} SK_ADDR_PORT;
+
+
+struct s_AddrNet {
+/* ----- Public part (read-only) ----- */
+
+ SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */
+ SK_MAC_ADDR PermanentMacAddress; /* Logical MAC Address. */
+
+/* ----- Private part ----- */
+
+ SK_U32 ActivePort; /* View of module ADDR. */
+ SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */
+ SK_U8 Align01;
+ SK_U16 Align02;
+};
+
+
+typedef struct s_Addr {
+
+/* ----- Public part (read-only) ----- */
+
+ SK_ADDR_NET Net[SK_MAX_NETS];
+ SK_ADDR_PORT Port[SK_MAX_MACS];
+
+/* ----- Private part ----- */
+} SK_ADDR;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkAddr */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern int SkAddrInit(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Level);
+
+extern int SkAddrMcClear(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 PortNumber,
+ int Flags);
+
+extern int SkAddrMcAdd(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 PortNumber,
+ SK_MAC_ADDR *pMc,
+ int Flags);
+
+extern int SkAddrMcUpdate(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 PortNumber);
+
+extern int SkAddrOverride(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 PortNumber,
+ SK_MAC_ADDR SK_FAR *pNewAddr,
+ int Flags);
+
+extern int SkAddrPromiscuousChange(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 PortNumber,
+ int NewPromMode);
+
+#ifndef SK_SLIM
+extern int SkAddrSwap(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 FromPortNumber,
+ SK_U32 ToPortNumber);
+#endif
+
+#else /* defined(SK_KR_PROTO)) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style prototypes are not yet provided.
+
+#endif /* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKADDR_H */
diff --git a/drivers/net/sk98lin/h/skcsum.h b/drivers/net/sk98lin/h/skcsum.h
new file mode 100644
index 000000000000..6e256bd9a28c
--- /dev/null
+++ b/drivers/net/sk98lin/h/skcsum.h
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Name: skcsum.h
+ * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
+ * Version: $Revision: 1.10 $
+ * Date: $Date: 2003/08/20 13:59:57 $
+ * Purpose: Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * Public header file for the "GEnesis" common module "CSUM".
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ * SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ * empty module.
+ *
+ * SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ * definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ * external.
+ *
+ * SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ * definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ * external.
+ *
+ * Include File Hierarchy:
+ *
+ * "h/skcsum.h"
+ * "h/sktypes.h"
+ * "h/skqueue.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKCSUM_H
+#define __INC_SKCSUM_H
+
+#include "h/sktypes.h"
+#include "h/skqueue.h"
+
+/* defines ********************************************************************/
+
+/*
+ * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags' if no user
+ * overwrite.
+ */
+#ifndef SKCS_OVERWRITE_PROTO /* User overwrite? */
+#define SKCS_PROTO_IP 0x1 /* IP (Internet Protocol version 4) */
+#define SKCS_PROTO_TCP 0x2 /* TCP (Transmission Control Protocol) */
+#define SKCS_PROTO_UDP 0x4 /* UDP (User Datagram Protocol) */
+
+/* Indices for protocol statistics. */
+#define SKCS_PROTO_STATS_IP 0
+#define SKCS_PROTO_STATS_UDP 1
+#define SKCS_PROTO_STATS_TCP 2
+#define SKCS_NUM_PROTOCOLS 3 /* Number of supported protocols. */
+#endif /* !SKCS_OVERWRITE_PROTO */
+
+/*
+ * Define the default SKCS_STATUS type and values if no user overwrite.
+ *
+ * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ * SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
+ * SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
+ * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ * SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum.
+ */
+#ifndef SKCS_OVERWRITE_STATUS /* User overwrite? */
+#define SKCS_STATUS int /* Define status type. */
+
+#define SKCS_STATUS_UNKNOWN_IP_VERSION 1
+#define SKCS_STATUS_IP_CSUM_ERROR 2
+#define SKCS_STATUS_IP_FRAGMENT 3
+#define SKCS_STATUS_IP_CSUM_OK 4
+#define SKCS_STATUS_TCP_CSUM_ERROR 5
+#define SKCS_STATUS_UDP_CSUM_ERROR 6
+#define SKCS_STATUS_TCP_CSUM_OK 7
+#define SKCS_STATUS_UDP_CSUM_OK 8
+/* needed for Microsoft */
+#define SKCS_STATUS_IP_CSUM_ERROR_UDP 9
+#define SKCS_STATUS_IP_CSUM_ERROR_TCP 10
+/* UDP checksum may be omitted */
+#define SKCS_STATUS_IP_CSUM_OK_NO_UDP 11
+#endif /* !SKCS_OVERWRITE_STATUS */
+
+/* Clear protocol statistics event. */
+#define SK_CSUM_EVENT_CLEAR_PROTO_STATS 1
+
+/*
+ * Add two values in one's complement.
+ *
+ * Note: One of the two input values may be "longer" than 16-bit, but then the
+ * resulting sum may be 17 bits long. In this case, add zero to the result using
+ * SKCS_OC_ADD() again.
+ *
+ * Result = Value1 + Value2
+ */
+#define SKCS_OC_ADD(Result, Value1, Value2) { \
+ unsigned long Sum; \
+ \
+ Sum = (unsigned long) (Value1) + (unsigned long) (Value2); \
+ /* Add-in any carry. */ \
+ (Result) = (Sum & 0xffff) + (Sum >> 16); \
+}
+
+/*
+ * Subtract two values in one's complement.
+ *
+ * Result = Value1 - Value2
+ */
+#define SKCS_OC_SUB(Result, Value1, Value2) \
+ SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff)
+
+/* typedefs *******************************************************************/
+
+/*
+ * SKCS_PROTO_STATS - The CSUM protocol statistics structure.
+ *
+ * There is one instance of this structure for each protocol supported.
+ */
+typedef struct s_CsProtocolStatistics {
+ SK_U64 RxOkCts; /* Receive checksum ok. */
+ SK_U64 RxUnableCts; /* Unable to verify receive checksum. */
+ SK_U64 RxErrCts; /* Receive checksum error. */
+ SK_U64 TxOkCts; /* Transmit checksum ok. */
+ SK_U64 TxUnableCts; /* Unable to calculate checksum in hw. */
+} SKCS_PROTO_STATS;
+
+/*
+ * s_Csum - The CSUM module context structure.
+ */
+typedef struct s_Csum {
+ /* Enabled receive SK_PROTO_XXX bit flags. */
+ unsigned ReceiveFlags[SK_MAX_NETS];
+#ifdef TX_CSUM
+ unsigned TransmitFlags[SK_MAX_NETS];
+#endif /* TX_CSUM */
+
+ /* The protocol statistics structure; one per supported protocol. */
+ SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS];
+} SK_CSUM;
+
+/*
+ * SKCS_PACKET_INFO - The packet information structure.
+ */
+typedef struct s_CsPacketInfo {
+ /* Bit field specifiying the desired/found protocols. */
+ unsigned ProtocolFlags;
+
+ /* Length of complete IP header, including any option fields. */
+ unsigned IpHeaderLength;
+
+ /* IP header checksum. */
+ unsigned IpHeaderChecksum;
+
+ /* TCP/UDP pseudo header checksum. */
+ unsigned PseudoHeaderChecksum;
+} SKCS_PACKET_INFO;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_CS_CALCULATE_CHECKSUM
+extern unsigned SkCsCalculateChecksum(
+ void *pData,
+ unsigned Length);
+#endif /* SK_CS_CALCULATE_CHECKSUM */
+
+extern int SkCsEvent(
+ SK_AC *pAc,
+ SK_IOC Ioc,
+ SK_U32 Event,
+ SK_EVPARA Param);
+
+extern SKCS_STATUS SkCsGetReceiveInfo(
+ SK_AC *pAc,
+ void *pIpHeader,
+ unsigned Checksum1,
+ unsigned Checksum2,
+ int NetNumber);
+
+extern void SkCsSetReceiveFlags(
+ SK_AC *pAc,
+ unsigned ReceiveFlags,
+ unsigned *pChecksum1Offset,
+ unsigned *pChecksum2Offset,
+ int NetNumber);
+
+#endif /* __INC_SKCSUM_H */
diff --git a/drivers/net/sk98lin/h/skdebug.h b/drivers/net/sk98lin/h/skdebug.h
new file mode 100644
index 000000000000..3cba171d74b2
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdebug.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Name: skdebug.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.14 $
+ * Date: $Date: 2003/05/13 17:26:00 $
+ * Purpose: SK specific DEBUG support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDEBUG_H
+#define __INC_SKDEBUG_H
+
+#ifdef DEBUG
+#ifndef SK_DBG_MSG
+#define SK_DBG_MSG(pAC,comp,cat,arg) \
+ if ( ((comp) & SK_DBG_CHKMOD(pAC)) && \
+ ((cat) & SK_DBG_CHKCAT(pAC)) ) { \
+ SK_DBG_PRINTF arg ; \
+ }
+#endif
+#else
+#define SK_DBG_MSG(pAC,comp,lev,arg)
+#endif
+
+/* PLS NOTE:
+ * =========
+ * Due to any restrictions of kernel printf routines do not use other
+ * format identifiers as: %x %d %c %s .
+ * Never use any combined format identifiers such as: %lx %ld in your
+ * printf - argument (arg) because some OS specific kernel printfs may
+ * only support some basic identifiers.
+ */
+
+/* Debug modules */
+
+#define SK_DBGMOD_MERR 0x00000001L /* general module error indication */
+#define SK_DBGMOD_HWM 0x00000002L /* Hardware init module */
+#define SK_DBGMOD_RLMT 0x00000004L /* RLMT module */
+#define SK_DBGMOD_VPD 0x00000008L /* VPD module */
+#define SK_DBGMOD_I2C 0x00000010L /* I2C module */
+#define SK_DBGMOD_PNMI 0x00000020L /* PNMI module */
+#define SK_DBGMOD_CSUM 0x00000040L /* CSUM module */
+#define SK_DBGMOD_ADDR 0x00000080L /* ADDR module */
+#define SK_DBGMOD_PECP 0x00000100L /* PECP module */
+#define SK_DBGMOD_POWM 0x00000200L /* Power Management module */
+
+/* Debug events */
+
+#define SK_DBGCAT_INIT 0x00000001L /* module/driver initialization */
+#define SK_DBGCAT_CTRL 0x00000002L /* controlling devices */
+#define SK_DBGCAT_ERR 0x00000004L /* error handling paths */
+#define SK_DBGCAT_TX 0x00000008L /* transmit path */
+#define SK_DBGCAT_RX 0x00000010L /* receive path */
+#define SK_DBGCAT_IRQ 0x00000020L /* general IRQ handling */
+#define SK_DBGCAT_QUEUE 0x00000040L /* any queue management */
+#define SK_DBGCAT_DUMP 0x00000080L /* large data output e.g. hex dump */
+#define SK_DBGCAT_FATAL 0x00000100L /* fatal error */
+
+#endif /* __INC_SKDEBUG_H */
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
new file mode 100644
index 000000000000..91b8d4f45904
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Name: skdrv1st.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.4 $
+ * Date: $Date: 2003/11/12 14:28:14 $
+ * Purpose: First header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the first include file of the driver, which includes all
+ * neccessary system header files and some of the GEnesis header files.
+ * It also defines some basic items.
+ *
+ * Include File Hierarchy:
+ *
+ * see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#define __INC_SKDRV1ST_H
+
+typedef struct s_AC SK_AC;
+
+/* Set card versions */
+#define SK_FAR
+
+/* override some default functions with optimized linux functions */
+
+#define SK_PNMI_STORE_U16(p,v) memcpy((char*)(p),(char*)&(v),2)
+#define SK_PNMI_STORE_U32(p,v) memcpy((char*)(p),(char*)&(v),4)
+#define SK_PNMI_STORE_U64(p,v) memcpy((char*)(p),(char*)&(v),8)
+#define SK_PNMI_READ_U16(p,v) memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U32(p,v) memcpy((char*)&(v),(char*)(p),4)
+#define SK_PNMI_READ_U64(p,v) memcpy((char*)&(v),(char*)(p),8)
+
+#define SK_ADDR_EQUAL(a1,a2) (!memcmp(a1,a2,6))
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+
+#define SK_CS_CALCULATE_CHECKSUM
+#ifndef CONFIG_X86_64
+#define SkCsCalculateChecksum(p,l) ((~ip_compute_csum(p, l)) & 0xffff)
+#else
+#define SkCsCalculateChecksum(p,l) ((~ip_fast_csum(p, l)) & 0xffff)
+#endif
+
+#include "h/sktypes.h"
+#include "h/skerror.h"
+#include "h/skdebug.h"
+#include "h/lm80.h"
+#include "h/xmac_ii.h"
+
+#ifdef __LITTLE_ENDIAN
+#define SK_LITTLE_ENDIAN
+#else
+#define SK_BIG_ENDIAN
+#endif
+
+#define SK_NET_DEVICE net_device
+
+
+/* we use gethrtime(), return unit: nanoseconds */
+#define SK_TICKS_PER_SEC 100
+
+#define SK_MEM_MAPPED_IO
+
+// #define SK_RLMT_SLOW_LOOKAHEAD
+
+#define SK_MAX_MACS 2
+#define SK_MAX_NETS 2
+
+#define SK_IOC char __iomem *
+
+typedef struct s_DrvRlmtMbuf SK_MBUF;
+
+#define SK_CONST64 INT64_C
+#define SK_CONSTU64 UINT64_C
+
+#define SK_MEMCPY(dest,src,size) memcpy(dest,src,size)
+#define SK_MEMCMP(s1,s2,size) memcmp(s1,s2,size)
+#define SK_MEMSET(dest,val,size) memset(dest,val,size)
+#define SK_STRLEN(pStr) strlen((char*)(pStr))
+#define SK_STRNCPY(pDest,pSrc,size) strncpy((char*)(pDest),(char*)(pSrc),size)
+#define SK_STRCMP(pStr1,pStr2) strcmp((char*)(pStr1),(char*)(pStr2))
+
+/* macros to access the adapter */
+#define SK_OUT8(b,a,v) writeb((v), ((b)+(a)))
+#define SK_OUT16(b,a,v) writew((v), ((b)+(a)))
+#define SK_OUT32(b,a,v) writel((v), ((b)+(a)))
+#define SK_IN8(b,a,pv) (*(pv) = readb((b)+(a)))
+#define SK_IN16(b,a,pv) (*(pv) = readw((b)+(a)))
+#define SK_IN32(b,a,pv) (*(pv) = readl((b)+(a)))
+
+#define int8_t char
+#define int16_t short
+#define int32_t long
+#define int64_t long long
+#define uint8_t u_char
+#define uint16_t u_short
+#define uint32_t u_long
+#define uint64_t unsigned long long
+#define t_scalar_t int
+#define t_uscalar_t unsigned int
+#define uintptr_t unsigned long
+
+#define __CONCAT__(A,B) A##B
+
+#define INT32_C(a) __CONCAT__(a,L)
+#define INT64_C(a) __CONCAT__(a,LL)
+#define UINT32_C(a) __CONCAT__(a,UL)
+#define UINT64_C(a) __CONCAT__(a,ULL)
+
+#ifdef DEBUG
+#define SK_DBG_PRINTF printk
+#ifndef SK_DEBUG_CHKMOD
+#define SK_DEBUG_CHKMOD 0
+#endif
+#ifndef SK_DEBUG_CHKCAT
+#define SK_DEBUG_CHKCAT 0
+#endif
+/* those come from the makefile */
+#define SK_DBG_CHKMOD(pAC) (SK_DEBUG_CHKMOD)
+#define SK_DBG_CHKCAT(pAC) (SK_DEBUG_CHKCAT)
+
+extern void SkDbgPrintf(const char *format,...);
+
+#define SK_DBGMOD_DRV 0x00010000
+
+/**** possible driver debug categories ********************************/
+#define SK_DBGCAT_DRV_ENTRY 0x00010000
+#define SK_DBGCAT_DRV_SAP 0x00020000
+#define SK_DBGCAT_DRV_MCA 0x00040000
+#define SK_DBGCAT_DRV_TX_PROGRESS 0x00080000
+#define SK_DBGCAT_DRV_RX_PROGRESS 0x00100000
+#define SK_DBGCAT_DRV_PROGRESS 0x00200000
+#define SK_DBGCAT_DRV_MSG 0x00400000
+#define SK_DBGCAT_DRV_PROM 0x00800000
+#define SK_DBGCAT_DRV_TX_FRAME 0x01000000
+#define SK_DBGCAT_DRV_ERROR 0x02000000
+#define SK_DBGCAT_DRV_INT_SRC 0x04000000
+#define SK_DBGCAT_DRV_EVENT 0x08000000
+
+#endif
+
+#define SK_ERR_LOG SkErrorLog
+
+extern void SkErrorLog(SK_AC*, int, int, char*);
+
+#endif
+
diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h
new file mode 100644
index 000000000000..3fa67171e832
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv2nd.h
@@ -0,0 +1,447 @@
+/******************************************************************************
+ *
+ * Name: skdrv2nd.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.10 $
+ * Date: $Date: 2003/12/11 16:04:45 $
+ * Purpose: Second header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the second include file of the driver, which includes all other
+ * neccessary files and defines all structures and constants used by the
+ * driver and the common modules.
+ *
+ * Include File Hierarchy:
+ *
+ * see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV2ND_H
+#define __INC_SKDRV2ND_H
+
+#include "h/skqueue.h"
+#include "h/skgehwt.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skgepnmi.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skaddr.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skrlmt.h"
+#include "h/skgedrv.h"
+
+
+extern SK_MBUF *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned);
+extern void SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*);
+extern SK_U64 SkOsGetTime(SK_AC*);
+extern int SkPciReadCfgDWord(SK_AC*, int, SK_U32*);
+extern int SkPciReadCfgWord(SK_AC*, int, SK_U16*);
+extern int SkPciReadCfgByte(SK_AC*, int, SK_U8*);
+extern int SkPciWriteCfgWord(SK_AC*, int, SK_U16);
+extern int SkPciWriteCfgByte(SK_AC*, int, SK_U8);
+extern int SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA);
+
+#ifdef SK_DIAG_SUPPORT
+extern int SkDrvEnterDiagMode(SK_AC *pAc);
+extern int SkDrvLeaveDiagMode(SK_AC *pAc);
+#endif
+
+struct s_DrvRlmtMbuf {
+ SK_MBUF *pNext; /* Pointer to next RLMT Mbuf. */
+ SK_U8 *pData; /* Data buffer (virtually contig.). */
+ unsigned Size; /* Data buffer size. */
+ unsigned Length; /* Length of packet (<= Size). */
+ SK_U32 PortIdx; /* Receiving/transmitting port. */
+#ifdef SK_RLMT_MBUF_PRIVATE
+ SK_RLMT_MBUF Rlmt; /* Private part for RLMT. */
+#endif /* SK_RLMT_MBUF_PRIVATE */
+ struct sk_buff *pOs; /* Pointer to message block */
+};
+
+
+/*
+ * Time macros
+ */
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t) (t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t) ((((unsigned long)t) * 100) / \
+ (SK_TICKS_PER_SEC))
+#endif
+
+/*
+ * New SkOsGetTime
+ */
+#define SkOsGetTimeCurrent(pAC, pUsec) {\
+ struct timeval t;\
+ do_gettimeofday(&t);\
+ *pUsec = ((((t.tv_sec) * 1000000L)+t.tv_usec)/10000);\
+}
+
+
+/*
+ * ioctl definitions
+ */
+#define SK_IOCTL_BASE (SIOCDEVPRIVATE)
+#define SK_IOCTL_GETMIB (SK_IOCTL_BASE + 0)
+#define SK_IOCTL_SETMIB (SK_IOCTL_BASE + 1)
+#define SK_IOCTL_PRESETMIB (SK_IOCTL_BASE + 2)
+#define SK_IOCTL_GEN (SK_IOCTL_BASE + 3)
+#define SK_IOCTL_DIAG (SK_IOCTL_BASE + 4)
+
+typedef struct s_IOCTL SK_GE_IOCTL;
+
+struct s_IOCTL {
+ char __user * pData;
+ unsigned int Len;
+};
+
+
+/*
+ * define sizes of descriptor rings in bytes
+ */
+
+#define TX_RING_SIZE (8*1024)
+#define RX_RING_SIZE (24*1024)
+
+/*
+ * Buffer size for ethernet packets
+ */
+#define ETH_BUF_SIZE 1540
+#define ETH_MAX_MTU 1514
+#define ETH_MIN_MTU 60
+#define ETH_MULTICAST_BIT 0x01
+#define SK_JUMBO_MTU 9000
+
+/*
+ * transmit priority selects the queue: LOW=asynchron, HIGH=synchron
+ */
+#define TX_PRIO_LOW 0
+#define TX_PRIO_HIGH 1
+
+/*
+ * alignment of rx/tx descriptors
+ */
+#define DESCR_ALIGN 64
+
+/*
+ * definitions for pnmi. TODO
+ */
+#define SK_DRIVER_RESET(pAC, IoC) 0
+#define SK_DRIVER_SENDEVENT(pAC, IoC) 0
+#define SK_DRIVER_SELFTEST(pAC, IoC) 0
+/* For get mtu you must add an own function */
+#define SK_DRIVER_GET_MTU(pAc,IoC,i) 0
+#define SK_DRIVER_SET_MTU(pAc,IoC,i,v) 0
+#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v) 0
+
+/*
+** Interim definition of SK_DRV_TIMER placed in this file until
+** common modules have been finalized
+*/
+#define SK_DRV_TIMER 11
+#define SK_DRV_MODERATION_TIMER 1
+#define SK_DRV_MODERATION_TIMER_LENGTH 1000000 /* 1 second */
+#define SK_DRV_RX_CLEANUP_TIMER 2
+#define SK_DRV_RX_CLEANUP_TIMER_LENGTH 1000000 /* 100 millisecs */
+
+/*
+** Definitions regarding transmitting frames
+** any calculating any checksum.
+*/
+#define C_LEN_ETHERMAC_HEADER_DEST_ADDR 6
+#define C_LEN_ETHERMAC_HEADER_SRC_ADDR 6
+#define C_LEN_ETHERMAC_HEADER_LENTYPE 2
+#define C_LEN_ETHERMAC_HEADER ( (C_LEN_ETHERMAC_HEADER_DEST_ADDR) + \
+ (C_LEN_ETHERMAC_HEADER_SRC_ADDR) + \
+ (C_LEN_ETHERMAC_HEADER_LENTYPE) )
+
+#define C_LEN_ETHERMTU_MINSIZE 46
+#define C_LEN_ETHERMTU_MAXSIZE_STD 1500
+#define C_LEN_ETHERMTU_MAXSIZE_JUMBO 9000
+
+#define C_LEN_ETHERNET_MINSIZE ( (C_LEN_ETHERMAC_HEADER) + \
+ (C_LEN_ETHERMTU_MINSIZE) )
+
+#define C_OFFSET_IPHEADER C_LEN_ETHERMAC_HEADER
+#define C_OFFSET_IPHEADER_IPPROTO 9
+#define C_OFFSET_TCPHEADER_TCPCS 16
+#define C_OFFSET_UDPHEADER_UDPCS 6
+
+#define C_OFFSET_IPPROTO ( (C_LEN_ETHERMAC_HEADER) + \
+ (C_OFFSET_IPHEADER_IPPROTO) )
+
+#define C_PROTO_ID_UDP 17 /* refer to RFC 790 or Stevens' */
+#define C_PROTO_ID_TCP 6 /* TCP/IP illustrated for details */
+
+/* TX and RX descriptors *****************************************************/
+
+typedef struct s_RxD RXD; /* the receive descriptor */
+
+struct s_RxD {
+ volatile SK_U32 RBControl; /* Receive Buffer Control */
+ SK_U32 VNextRxd; /* Next receive descriptor,low dword */
+ SK_U32 VDataLow; /* Receive buffer Addr, low dword */
+ SK_U32 VDataHigh; /* Receive buffer Addr, high dword */
+ SK_U32 FrameStat; /* Receive Frame Status word */
+ SK_U32 TimeStamp; /* Time stamp from XMAC */
+ SK_U32 TcpSums; /* TCP Sum 2 / TCP Sum 1 */
+ SK_U32 TcpSumStarts; /* TCP Sum Start 2 / TCP Sum Start 1 */
+ RXD *pNextRxd; /* Pointer to next Rxd */
+ struct sk_buff *pMBuf; /* Pointer to Linux' socket buffer */
+};
+
+typedef struct s_TxD TXD; /* the transmit descriptor */
+
+struct s_TxD {
+ volatile SK_U32 TBControl; /* Transmit Buffer Control */
+ SK_U32 VNextTxd; /* Next transmit descriptor,low dword */
+ SK_U32 VDataLow; /* Transmit Buffer Addr, low dword */
+ SK_U32 VDataHigh; /* Transmit Buffer Addr, high dword */
+ SK_U32 FrameStat; /* Transmit Frame Status Word */
+ SK_U32 TcpSumOfs; /* Reserved / TCP Sum Offset */
+ SK_U16 TcpSumSt; /* TCP Sum Start */
+ SK_U16 TcpSumWr; /* TCP Sum Write */
+ SK_U32 TcpReserved; /* not used */
+ TXD *pNextTxd; /* Pointer to next Txd */
+ struct sk_buff *pMBuf; /* Pointer to Linux' socket buffer */
+};
+
+/* Used interrupt bits in the interrupts source register *********************/
+
+#define DRIVER_IRQS ((IS_IRQ_SW) | \
+ (IS_R1_F) |(IS_R2_F) | \
+ (IS_XS1_F) |(IS_XA1_F) | \
+ (IS_XS2_F) |(IS_XA2_F))
+
+#define SPECIAL_IRQS ((IS_HW_ERR) |(IS_I2C_READY) | \
+ (IS_EXT_REG) |(IS_TIMINT) | \
+ (IS_PA_TO_RX1) |(IS_PA_TO_RX2) | \
+ (IS_PA_TO_TX1) |(IS_PA_TO_TX2) | \
+ (IS_MAC1) |(IS_LNK_SYNC_M1)| \
+ (IS_MAC2) |(IS_LNK_SYNC_M2)| \
+ (IS_R1_C) |(IS_R2_C) | \
+ (IS_XS1_C) |(IS_XA1_C) | \
+ (IS_XS2_C) |(IS_XA2_C))
+
+#define IRQ_MASK ((IS_IRQ_SW) | \
+ (IS_R1_B) |(IS_R1_F) |(IS_R2_B) |(IS_R2_F) | \
+ (IS_XS1_B) |(IS_XS1_F) |(IS_XA1_B)|(IS_XA1_F)| \
+ (IS_XS2_B) |(IS_XS2_F) |(IS_XA2_B)|(IS_XA2_F)| \
+ (IS_HW_ERR) |(IS_I2C_READY)| \
+ (IS_EXT_REG) |(IS_TIMINT) | \
+ (IS_PA_TO_RX1) |(IS_PA_TO_RX2)| \
+ (IS_PA_TO_TX1) |(IS_PA_TO_TX2)| \
+ (IS_MAC1) |(IS_MAC2) | \
+ (IS_R1_C) |(IS_R2_C) | \
+ (IS_XS1_C) |(IS_XA1_C) | \
+ (IS_XS2_C) |(IS_XA2_C))
+
+#define IRQ_HWE_MASK (IS_ERR_MSK) /* enable all HW irqs */
+
+typedef struct s_DevNet DEV_NET;
+
+struct s_DevNet {
+ int PortNr;
+ int NetNr;
+ SK_AC *pAC;
+};
+
+typedef struct s_TxPort TX_PORT;
+
+struct s_TxPort {
+ /* the transmit descriptor rings */
+ caddr_t pTxDescrRing; /* descriptor area memory */
+ SK_U64 VTxDescrRing; /* descr. area bus virt. addr. */
+ TXD *pTxdRingHead; /* Head of Tx rings */
+ TXD *pTxdRingTail; /* Tail of Tx rings */
+ TXD *pTxdRingPrev; /* descriptor sent previously */
+ int TxdRingFree; /* # of free entrys */
+ spinlock_t TxDesRingLock; /* serialize descriptor accesses */
+ SK_IOC HwAddr; /* bmu registers address */
+ int PortIndex; /* index number of port (0 or 1) */
+};
+
+typedef struct s_RxPort RX_PORT;
+
+struct s_RxPort {
+ /* the receive descriptor rings */
+ caddr_t pRxDescrRing; /* descriptor area memory */
+ SK_U64 VRxDescrRing; /* descr. area bus virt. addr. */
+ RXD *pRxdRingHead; /* Head of Rx rings */
+ RXD *pRxdRingTail; /* Tail of Rx rings */
+ RXD *pRxdRingPrev; /* descriptor given to BMU previously */
+ int RxdRingFree; /* # of free entrys */
+ int RxCsum; /* use receive checksum hardware */
+ spinlock_t RxDesRingLock; /* serialize descriptor accesses */
+ int RxFillLimit; /* limit for buffers in ring */
+ SK_IOC HwAddr; /* bmu registers address */
+ int PortIndex; /* index number of port (0 or 1) */
+};
+
+/* Definitions needed for interrupt moderation *******************************/
+
+#define IRQ_EOF_AS_TX ((IS_XA1_F) | (IS_XA2_F))
+#define IRQ_EOF_SY_TX ((IS_XS1_F) | (IS_XS2_F))
+#define IRQ_MASK_TX_ONLY ((IRQ_EOF_AS_TX)| (IRQ_EOF_SY_TX))
+#define IRQ_MASK_RX_ONLY ((IS_R1_F) | (IS_R2_F))
+#define IRQ_MASK_SP_ONLY (SPECIAL_IRQS)
+#define IRQ_MASK_TX_RX ((IRQ_MASK_TX_ONLY)| (IRQ_MASK_RX_ONLY))
+#define IRQ_MASK_SP_RX ((SPECIAL_IRQS) | (IRQ_MASK_RX_ONLY))
+#define IRQ_MASK_SP_TX ((SPECIAL_IRQS) | (IRQ_MASK_TX_ONLY))
+#define IRQ_MASK_RX_TX_SP ((SPECIAL_IRQS) | (IRQ_MASK_TX_RX))
+
+#define C_INT_MOD_NONE 1
+#define C_INT_MOD_STATIC 2
+#define C_INT_MOD_DYNAMIC 4
+
+#define C_CLK_FREQ_GENESIS 53215000 /* shorter: 53.125 MHz */
+#define C_CLK_FREQ_YUKON 78215000 /* shorter: 78.125 MHz */
+
+#define C_INTS_PER_SEC_DEFAULT 2000
+#define C_INT_MOD_ENABLE_PERCENTAGE 50 /* if higher 50% enable */
+#define C_INT_MOD_DISABLE_PERCENTAGE 50 /* if lower 50% disable */
+#define C_INT_MOD_IPS_LOWER_RANGE 30
+#define C_INT_MOD_IPS_UPPER_RANGE 40000
+
+
+typedef struct s_DynIrqModInfo DIM_INFO;
+struct s_DynIrqModInfo {
+ unsigned long PrevTimeVal;
+ unsigned int PrevSysLoad;
+ unsigned int PrevUsedTime;
+ unsigned int PrevTotalTime;
+ int PrevUsedDescrRatio;
+ int NbrProcessedDescr;
+ SK_U64 PrevPort0RxIntrCts;
+ SK_U64 PrevPort1RxIntrCts;
+ SK_U64 PrevPort0TxIntrCts;
+ SK_U64 PrevPort1TxIntrCts;
+ SK_BOOL ModJustEnabled; /* Moderation just enabled yes/no */
+
+ int MaxModIntsPerSec; /* Moderation Threshold */
+ int MaxModIntsPerSecUpperLimit; /* Upper limit for DIM */
+ int MaxModIntsPerSecLowerLimit; /* Lower limit for DIM */
+
+ long MaskIrqModeration; /* ModIrqType (eg. 'TxRx') */
+ SK_BOOL DisplayStats; /* Stats yes/no */
+ SK_BOOL AutoSizing; /* Resize DIM-timer on/off */
+ int IntModTypeSelect; /* EnableIntMod (eg. 'dynamic') */
+
+ SK_TIMER ModTimer; /* just some timer */
+};
+
+typedef struct s_PerStrm PER_STRM;
+
+#define SK_ALLOC_IRQ 0x00000001
+
+#ifdef SK_DIAG_SUPPORT
+#define DIAG_ACTIVE 1
+#define DIAG_NOTACTIVE 0
+#endif
+
+/****************************************************************************
+ * Per board structure / Adapter Context structure:
+ * Allocated within attach(9e) and freed within detach(9e).
+ * Contains all 'per device' necessary handles, flags, locks etc.:
+ */
+struct s_AC {
+ SK_GEINIT GIni; /* GE init struct */
+ SK_PNMI Pnmi; /* PNMI data struct */
+ SK_VPD vpd; /* vpd data struct */
+ SK_QUEUE Event; /* Event queue */
+ SK_HWT Hwt; /* Hardware Timer control struct */
+ SK_TIMCTRL Tim; /* Software Timer control struct */
+ SK_I2C I2c; /* I2C relevant data structure */
+ SK_ADDR Addr; /* for Address module */
+ SK_CSUM Csum; /* for checksum module */
+ SK_RLMT Rlmt; /* for rlmt module */
+ spinlock_t SlowPathLock; /* Normal IRQ lock */
+ struct timer_list BlinkTimer; /* for LED blinking */
+ int LedsOn;
+ SK_PNMI_STRUCT_DATA PnmiStruct; /* structure to get all Pnmi-Data */
+ int RlmtMode; /* link check mode to set */
+ int RlmtNets; /* Number of nets */
+
+ SK_IOC IoBase; /* register set of adapter */
+ int BoardLevel; /* level of active hw init (0-2) */
+
+ SK_U32 AllocFlag; /* flag allocation of resources */
+ struct pci_dev *PciDev; /* for access to pci config space */
+ struct SK_NET_DEVICE *dev[2]; /* pointer to device struct */
+
+ int RxBufSize; /* length of receive buffers */
+ struct net_device_stats stats; /* linux 'netstat -i' statistics */
+ int Index; /* internal board index number */
+
+ /* adapter RAM sizes for queues of active port */
+ int RxQueueSize; /* memory used for receive queue */
+ int TxSQueueSize; /* memory used for sync. tx queue */
+ int TxAQueueSize; /* memory used for async. tx queue */
+
+ int PromiscCount; /* promiscuous mode counter */
+ int AllMultiCount; /* allmulticast mode counter */
+ int MulticCount; /* number of different MC */
+ /* addresses for this board */
+ /* (may be more than HW can)*/
+
+ int HWRevision; /* Hardware revision */
+ int ActivePort; /* the active XMAC port */
+ int MaxPorts; /* number of activated ports */
+ int TxDescrPerRing; /* # of descriptors per tx ring */
+ int RxDescrPerRing; /* # of descriptors per rx ring */
+
+ caddr_t pDescrMem; /* Pointer to the descriptor area */
+ dma_addr_t pDescrMemDMA; /* PCI DMA address of area */
+
+ /* the port structures with descriptor rings */
+ TX_PORT TxPort[SK_MAX_MACS][2];
+ RX_PORT RxPort[SK_MAX_MACS];
+
+ SK_BOOL CheckQueue; /* check event queue soon */
+ SK_TIMER DrvCleanupTimer;/* to check for pending descriptors */
+ DIM_INFO DynIrqModInfo; /* all data related to DIM */
+
+ /* Only for tests */
+ int PortDown;
+ int ChipsetType; /* Chipset family type
+ * 0 == Genesis family support
+ * 1 == Yukon family support
+ */
+#ifdef SK_DIAG_SUPPORT
+ SK_U32 DiagModeActive; /* is diag active? */
+ SK_BOOL DiagFlowCtrl; /* for control purposes */
+ SK_PNMI_STRUCT_DATA PnmiBackup; /* backup structure for all Pnmi-Data */
+ SK_BOOL WasIfUp[SK_MAX_MACS]; /* for OpenClose while
+ * DIAG is busy with NIC
+ */
+#endif
+
+};
+
+
+#endif /* __INC_SKDRV2ND_H */
+
diff --git a/drivers/net/sk98lin/h/skerror.h b/drivers/net/sk98lin/h/skerror.h
new file mode 100644
index 000000000000..da062f766238
--- /dev/null
+++ b/drivers/net/sk98lin/h/skerror.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Name: skerror.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.7 $
+ * Date: $Date: 2003/05/13 17:25:13 $
+ * Purpose: SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKERROR_H_
+#define _INC_SKERROR_H_
+
+/*
+ * Define Error Classes
+ */
+#define SK_ERRCL_OTHER (0) /* Other error */
+#define SK_ERRCL_CONFIG (1L<<0) /* Configuration error */
+#define SK_ERRCL_INIT (1L<<1) /* Initialization error */
+#define SK_ERRCL_NORES (1L<<2) /* Out of Resources error */
+#define SK_ERRCL_SW (1L<<3) /* Internal Software error */
+#define SK_ERRCL_HW (1L<<4) /* Hardware Failure */
+#define SK_ERRCL_COMM (1L<<5) /* Communication error */
+
+
+/*
+ * Define Error Code Bases
+ */
+#define SK_ERRBASE_RLMT 100 /* Base Error number for RLMT */
+#define SK_ERRBASE_HWINIT 200 /* Base Error number for HWInit */
+#define SK_ERRBASE_VPD 300 /* Base Error number for VPD */
+#define SK_ERRBASE_PNMI 400 /* Base Error number for PNMI */
+#define SK_ERRBASE_CSUM 500 /* Base Error number for Checksum */
+#define SK_ERRBASE_SIRQ 600 /* Base Error number for Special IRQ */
+#define SK_ERRBASE_I2C 700 /* Base Error number for I2C module */
+#define SK_ERRBASE_QUEUE 800 /* Base Error number for Scheduler */
+#define SK_ERRBASE_ADDR 900 /* Base Error number for Address module */
+#define SK_ERRBASE_PECP 1000 /* Base Error number for PECP */
+#define SK_ERRBASE_DRV 1100 /* Base Error number for Driver */
+
+#endif /* _INC_SKERROR_H_ */
diff --git a/drivers/net/sk98lin/h/skgedrv.h b/drivers/net/sk98lin/h/skgedrv.h
new file mode 100644
index 000000000000..44fd4c3de818
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgedrv.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Name: skgedrv.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.10 $
+ * Date: $Date: 2003/07/04 12:25:01 $
+ * Purpose: Interface with the driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEDRV_H_
+#define __INC_SKGEDRV_H_
+
+/* defines ********************************************************************/
+
+/*
+ * Define the driver events.
+ * Usually the events are defined by the destination module.
+ * In case of the driver we put the definition of the events here.
+ */
+#define SK_DRV_PORT_RESET 1 /* The port needs to be reset */
+#define SK_DRV_NET_UP 2 /* The net is operational */
+#define SK_DRV_NET_DOWN 3 /* The net is down */
+#define SK_DRV_SWITCH_SOFT 4 /* Ports switch with both links connected */
+#define SK_DRV_SWITCH_HARD 5 /* Port switch due to link failure */
+#define SK_DRV_RLMT_SEND 6 /* Send a RLMT packet */
+#define SK_DRV_ADAP_FAIL 7 /* The whole adapter fails */
+#define SK_DRV_PORT_FAIL 8 /* One port fails */
+#define SK_DRV_SWITCH_INTERN 9 /* Port switch by the driver itself */
+#define SK_DRV_POWER_DOWN 10 /* Power down mode */
+#define SK_DRV_TIMER 11 /* Timer for free use */
+#ifdef SK_NO_RLMT
+#define SK_DRV_LINK_UP 12 /* Link Up event for driver */
+#define SK_DRV_LINK_DOWN 13 /* Link Down event for driver */
+#endif
+#define SK_DRV_DOWNSHIFT_DET 14 /* Downshift 4-Pair / 2-Pair (YUKON only) */
+#endif /* __INC_SKGEDRV_H_ */
diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h
new file mode 100644
index 000000000000..f6282b7956db
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehw.h
@@ -0,0 +1,2126 @@
+/******************************************************************************
+ *
+ * Name: skgehw.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.56 $
+ * Date: $Date: 2003/09/23 09:01:00 $
+ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product Family
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEHW_H
+#define __INC_SKGEHW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define BIT_31 (1UL << 31)
+#define BIT_30 (1L << 30)
+#define BIT_29 (1L << 29)
+#define BIT_28 (1L << 28)
+#define BIT_27 (1L << 27)
+#define BIT_26 (1L << 26)
+#define BIT_25 (1L << 25)
+#define BIT_24 (1L << 24)
+#define BIT_23 (1L << 23)
+#define BIT_22 (1L << 22)
+#define BIT_21 (1L << 21)
+#define BIT_20 (1L << 20)
+#define BIT_19 (1L << 19)
+#define BIT_18 (1L << 18)
+#define BIT_17 (1L << 17)
+#define BIT_16 (1L << 16)
+#define BIT_15 (1L << 15)
+#define BIT_14 (1L << 14)
+#define BIT_13 (1L << 13)
+#define BIT_12 (1L << 12)
+#define BIT_11 (1L << 11)
+#define BIT_10 (1L << 10)
+#define BIT_9 (1L << 9)
+#define BIT_8 (1L << 8)
+#define BIT_7 (1L << 7)
+#define BIT_6 (1L << 6)
+#define BIT_5 (1L << 5)
+#define BIT_4 (1L << 4)
+#define BIT_3 (1L << 3)
+#define BIT_2 (1L << 2)
+#define BIT_1 (1L << 1)
+#define BIT_0 1L
+
+#define BIT_15S (1U << 15)
+#define BIT_14S (1 << 14)
+#define BIT_13S (1 << 13)
+#define BIT_12S (1 << 12)
+#define BIT_11S (1 << 11)
+#define BIT_10S (1 << 10)
+#define BIT_9S (1 << 9)
+#define BIT_8S (1 << 8)
+#define BIT_7S (1 << 7)
+#define BIT_6S (1 << 6)
+#define BIT_5S (1 << 5)
+#define BIT_4S (1 << 4)
+#define BIT_3S (1 << 3)
+#define BIT_2S (1 << 2)
+#define BIT_1S (1 << 1)
+#define BIT_0S 1
+
+#define SHIFT31(x) ((x) << 31)
+#define SHIFT30(x) ((x) << 30)
+#define SHIFT29(x) ((x) << 29)
+#define SHIFT28(x) ((x) << 28)
+#define SHIFT27(x) ((x) << 27)
+#define SHIFT26(x) ((x) << 26)
+#define SHIFT25(x) ((x) << 25)
+#define SHIFT24(x) ((x) << 24)
+#define SHIFT23(x) ((x) << 23)
+#define SHIFT22(x) ((x) << 22)
+#define SHIFT21(x) ((x) << 21)
+#define SHIFT20(x) ((x) << 20)
+#define SHIFT19(x) ((x) << 19)
+#define SHIFT18(x) ((x) << 18)
+#define SHIFT17(x) ((x) << 17)
+#define SHIFT16(x) ((x) << 16)
+#define SHIFT15(x) ((x) << 15)
+#define SHIFT14(x) ((x) << 14)
+#define SHIFT13(x) ((x) << 13)
+#define SHIFT12(x) ((x) << 12)
+#define SHIFT11(x) ((x) << 11)
+#define SHIFT10(x) ((x) << 10)
+#define SHIFT9(x) ((x) << 9)
+#define SHIFT8(x) ((x) << 8)
+#define SHIFT7(x) ((x) << 7)
+#define SHIFT6(x) ((x) << 6)
+#define SHIFT5(x) ((x) << 5)
+#define SHIFT4(x) ((x) << 4)
+#define SHIFT3(x) ((x) << 3)
+#define SHIFT2(x) ((x) << 2)
+#define SHIFT1(x) ((x) << 1)
+#define SHIFT0(x) ((x) << 0)
+
+/*
+ * Configuration Space header
+ * Since this module is used for different OS', those may be
+ * duplicate on some of them (e.g. Linux). But to keep the
+ * common source, we have to live with this...
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */
+#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */
+#define PCI_COMMAND 0x04 /* 16 bit Command */
+#define PCI_STATUS 0x06 /* 16 bit Status */
+#define PCI_REV_ID 0x08 /* 8 bit Revision ID */
+#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */
+#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */
+#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */
+#define PCI_HEADER_T 0x0e /* 8 bit Header Type */
+#define PCI_BIST 0x0f /* 8 bit Built-in selftest */
+#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */
+#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */
+ /* Byte 0x18..0x2b: reserved */
+#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */
+#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */
+#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */
+#define PCI_CAP_PTR 0x34 /* 8 bit Capabilities Ptr */
+ /* Byte 0x35..0x3b: reserved */
+#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */
+#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */
+#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */
+#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */
+ /* Device Dependent Region */
+#define PCI_OUR_REG_1 0x40 /* 32 bit Our Register 1 */
+#define PCI_OUR_REG_2 0x44 /* 32 bit Our Register 2 */
+ /* Power Management Region */
+#define PCI_PM_CAP_ID 0x48 /* 8 bit Power Management Cap. ID */
+#define PCI_PM_NITEM 0x49 /* 8 bit Next Item Ptr */
+#define PCI_PM_CAP_REG 0x4a /* 16 bit Power Management Capabilities */
+#define PCI_PM_CTL_STS 0x4c /* 16 bit Power Manag. Control/Status */
+ /* Byte 0x4e: reserved */
+#define PCI_PM_DAT_REG 0x4f /* 8 bit Power Manag. Data Register */
+ /* VPD Region */
+#define PCI_VPD_CAP_ID 0x50 /* 8 bit VPD Cap. ID */
+#define PCI_VPD_NITEM 0x51 /* 8 bit Next Item Ptr */
+#define PCI_VPD_ADR_REG 0x52 /* 16 bit VPD Address Register */
+#define PCI_VPD_DAT_REG 0x54 /* 32 bit VPD Data Register */
+ /* Byte 0x58..0x59: reserved */
+#define PCI_SER_LD_CTRL 0x5a /* 16 bit SEEPROM Loader Ctrl (YUKON only) */
+ /* Byte 0x5c..0xff: reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ * I2C bus.
+ */
+#define I2C_ADDR_VPD 0xa0 /* I2C address for the VPD EEPROM */
+
+/*
+ * Define Bits and Values of the registers
+ */
+/* PCI_COMMAND 16 bit Command */
+ /* Bit 15..11: reserved */
+#define PCI_INT_DIS BIT_10S /* Interrupt INTx# disable (PCI 2.3) */
+#define PCI_FBTEN BIT_9S /* Fast Back-To-Back enable */
+#define PCI_SERREN BIT_8S /* SERR enable */
+#define PCI_ADSTEP BIT_7S /* Address Stepping */
+#define PCI_PERREN BIT_6S /* Parity Report Response enable */
+#define PCI_VGA_SNOOP BIT_5S /* VGA palette snoop */
+#define PCI_MWIEN BIT_4S /* Memory write an inv cycl ena */
+#define PCI_SCYCEN BIT_3S /* Special Cycle enable */
+#define PCI_BMEN BIT_2S /* Bus Master enable */
+#define PCI_MEMEN BIT_1S /* Memory Space Access enable */
+#define PCI_IOEN BIT_0S /* I/O Space Access enable */
+
+#define PCI_COMMAND_VAL (PCI_FBTEN | PCI_SERREN | PCI_PERREN | PCI_MWIEN |\
+ PCI_BMEN | PCI_MEMEN | PCI_IOEN)
+
+/* PCI_STATUS 16 bit Status */
+#define PCI_PERR BIT_15S /* Parity Error */
+#define PCI_SERR BIT_14S /* Signaled SERR */
+#define PCI_RMABORT BIT_13S /* Received Master Abort */
+#define PCI_RTABORT BIT_12S /* Received Target Abort */
+ /* Bit 11: reserved */
+#define PCI_DEVSEL (3<<9) /* Bit 10.. 9: DEVSEL Timing */
+#define PCI_DEV_FAST (0<<9) /* fast */
+#define PCI_DEV_MEDIUM (1<<9) /* medium */
+#define PCI_DEV_SLOW (2<<9) /* slow */
+#define PCI_DATAPERR BIT_8S /* DATA Parity error detected */
+#define PCI_FB2BCAP BIT_7S /* Fast Back-to-Back Capability */
+#define PCI_UDF BIT_6S /* User Defined Features */
+#define PCI_66MHZCAP BIT_5S /* 66 MHz PCI bus clock capable */
+#define PCI_NEWCAP BIT_4S /* New cap. list implemented */
+#define PCI_INT_STAT BIT_3S /* Interrupt INTx# Status (PCI 2.3) */
+ /* Bit 2.. 0: reserved */
+
+#define PCI_ERRBITS (PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
+ PCI_DATAPERR)
+
+/* PCI_CLASS_CODE 24 bit Class Code */
+/* Byte 2: Base Class (02) */
+/* Byte 1: SubClass (00) */
+/* Byte 0: Programming Interface (00) */
+
+/* PCI_CACHE_LSZ 8 bit Cache Line Size */
+/* Possible values: 0,2,4,8,16,32,64,128 */
+
+/* PCI_HEADER_T 8 bit Header Type */
+#define PCI_HD_MF_DEV BIT_7S /* 0= single, 1= multi-func dev */
+#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */
+
+/* PCI_BIST 8 bit Built-in selftest */
+/* Built-in Self test not supported (optional) */
+
+/* PCI_BASE_1ST 32 bit 1st Base address */
+#define PCI_MEMSIZE 0x4000L /* use 16 kB Memory Base */
+#define PCI_MEMBASE_MSK 0xffffc000L /* Bit 31..14: Memory Base Address */
+#define PCI_MEMSIZE_MSK 0x00003ff0L /* Bit 13.. 4: Memory Size Req. */
+#define PCI_PREFEN BIT_3 /* Prefetchable */
+#define PCI_MEM_TYP (3L<<2) /* Bit 2.. 1: Memory Type */
+#define PCI_MEM32BIT (0L<<1) /* Base addr anywhere in 32 Bit range */
+#define PCI_MEM1M (1L<<1) /* Base addr below 1 MegaByte */
+#define PCI_MEM64BIT (2L<<1) /* Base addr anywhere in 64 Bit range */
+#define PCI_MEMSPACE BIT_0 /* Memory Space Indicator */
+
+/* PCI_BASE_2ND 32 bit 2nd Base address */
+#define PCI_IOBASE 0xffffff00L /* Bit 31.. 8: I/O Base address */
+#define PCI_IOSIZE 0x000000fcL /* Bit 7.. 2: I/O Size Requirements */
+ /* Bit 1: reserved */
+#define PCI_IOSPACE BIT_0 /* I/O Space Indicator */
+
+/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */
+#define PCI_ROMBASE_MSK 0xfffe0000L /* Bit 31..17: ROM Base address */
+#define PCI_ROMBASE_SIZ (0x1cL<<14) /* Bit 16..14: Treat as Base or Size */
+#define PCI_ROMSIZE (0x38L<<11) /* Bit 13..11: ROM Size Requirements */
+ /* Bit 10.. 1: reserved */
+#define PCI_ROMEN BIT_0 /* Address Decode enable */
+
+/* Device Dependent Region */
+/* PCI_OUR_REG_1 32 bit Our Register 1 */
+ /* Bit 31..29: reserved */
+#define PCI_PHY_COMA BIT_28 /* Set PHY to Coma Mode (YUKON only) */
+#define PCI_TEST_CAL BIT_27 /* Test PCI buffer calib. (YUKON only) */
+#define PCI_EN_CAL BIT_26 /* Enable PCI buffer calib. (YUKON only) */
+#define PCI_VIO BIT_25 /* PCI I/O Voltage, 0 = 3.3V, 1 = 5V */
+#define PCI_DIS_BOOT BIT_24 /* Disable BOOT via ROM */
+#define PCI_EN_IO BIT_23 /* Mapping to I/O space */
+#define PCI_EN_FPROM BIT_22 /* Enable FLASH mapping to memory */
+ /* 1 = Map Flash to memory */
+ /* 0 = Disable addr. dec */
+#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */
+#define PCI_PAGE_16 (0L<<20) /* 16 k pages */
+#define PCI_PAGE_32K (1L<<20) /* 32 k pages */
+#define PCI_PAGE_64K (2L<<20) /* 64 k pages */
+#define PCI_PAGE_128K (3L<<20) /* 128 k pages */
+ /* Bit 19: reserved */
+#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */
+#define PCI_NOTAR BIT_15 /* No turnaround cycle */
+#define PCI_FORCE_BE BIT_14 /* Assert all BEs on MR */
+#define PCI_DIS_MRL BIT_13 /* Disable Mem Read Line */
+#define PCI_DIS_MRM BIT_12 /* Disable Mem Read Multiple */
+#define PCI_DIS_MWI BIT_11 /* Disable Mem Write & Invalidate */
+#define PCI_DISC_CLS BIT_10 /* Disc: cacheLsz bound */
+#define PCI_BURST_DIS BIT_9 /* Burst Disable */
+#define PCI_DIS_PCI_CLK BIT_8 /* Disable PCI clock driving */
+#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7.. 4: Skew Ctrl, DAS Ext */
+#define PCI_SKEW_BASE 0xfL /* Bit 3.. 0: Skew Ctrl, Base */
+
+
+/* PCI_OUR_REG_2 32 bit Our Register 2 */
+#define PCI_VPD_WR_THR (0xffL<<24) /* Bit 31..24: VPD Write Threshold */
+#define PCI_DEV_SEL (0x7fL<<17) /* Bit 23..17: EEPROM Device Select */
+#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 16..14: VPD ROM Size */
+ /* Bit 13..12: reserved */
+#define PCI_PATCH_DIR (0xfL<<8) /* Bit 11.. 8: Ext Patches dir 3..0 */
+#define PCI_PATCH_DIR_3 BIT_11
+#define PCI_PATCH_DIR_2 BIT_10
+#define PCI_PATCH_DIR_1 BIT_9
+#define PCI_PATCH_DIR_0 BIT_8
+#define PCI_EXT_PATCHS (0xfL<<4) /* Bit 7.. 4: Extended Patches 3..0 */
+#define PCI_EXT_PATCH_3 BIT_7
+#define PCI_EXT_PATCH_2 BIT_6
+#define PCI_EXT_PATCH_1 BIT_5
+#define PCI_EXT_PATCH_0 BIT_4
+#define PCI_EN_DUMMY_RD BIT_3 /* Enable Dummy Read */
+#define PCI_REV_DESC BIT_2 /* Reverse Desc. Bytes */
+ /* Bit 1: reserved */
+#define PCI_USEDATA64 BIT_0 /* Use 64Bit Data bus ext */
+
+
+/* Power Management Region */
+/* PCI_PM_CAP_REG 16 bit Power Management Capabilities */
+#define PCI_PME_SUP_MSK (0x1f<<11) /* Bit 15..11: PM Event Support Mask */
+#define PCI_PME_D3C_SUP BIT_15S /* PME from D3cold Support (if Vaux) */
+#define PCI_PME_D3H_SUP BIT_14S /* PME from D3hot Support */
+#define PCI_PME_D2_SUP BIT_13S /* PME from D2 Support */
+#define PCI_PME_D1_SUP BIT_12S /* PME from D1 Support */
+#define PCI_PME_D0_SUP BIT_11S /* PME from D0 Support */
+#define PCI_PM_D2_SUP BIT_10S /* D2 Support in 33 MHz mode */
+#define PCI_PM_D1_SUP BIT_9S /* D1 Support */
+ /* Bit 8.. 6: reserved */
+#define PCI_PM_DSI BIT_5S /* Device Specific Initialization */
+#define PCI_PM_APS BIT_4S /* Auxialiary Power Source */
+#define PCI_PME_CLOCK BIT_3S /* PM Event Clock */
+#define PCI_PM_VER_MSK 7 /* Bit 2.. 0: PM PCI Spec. version */
+
+/* PCI_PM_CTL_STS 16 bit Power Management Control/Status */
+#define PCI_PME_STATUS BIT_15S /* PME Status (YUKON only) */
+#define PCI_PM_DAT_SCL (3<<13) /* Bit 14..13: Data Reg. scaling factor */
+#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 12.. 9: PM data selector field */
+#define PCI_PME_EN BIT_8S /* Enable PME# generation (YUKON only) */
+ /* Bit 7.. 2: reserved */
+#define PCI_PM_STATE_MSK 3 /* Bit 1.. 0: Power Management State */
+
+#define PCI_PM_STATE_D0 0 /* D0: Operational (default) */
+#define PCI_PM_STATE_D1 1 /* D1: (YUKON only) */
+#define PCI_PM_STATE_D2 2 /* D2: (YUKON only) */
+#define PCI_PM_STATE_D3 3 /* D3: HOT, Power Down and Reset */
+
+/* VPD Region */
+/* PCI_VPD_ADR_REG 16 bit VPD Address Register */
+#define PCI_VPD_FLAG BIT_15S /* starts VPD rd/wr cycle */
+#define PCI_VPD_ADR_MSK 0x7fffL /* Bit 14.. 0: VPD address mask */
+
+/* Control Register File (Address Map) */
+
+/*
+ * Bank 0
+ */
+#define B0_RAP 0x0000 /* 8 bit Register Address Port */
+ /* 0x0001 - 0x0003: reserved */
+#define B0_CTST 0x0004 /* 16 bit Control/Status register */
+#define B0_LED 0x0006 /* 8 Bit LED register */
+#define B0_POWER_CTRL 0x0007 /* 8 Bit Power Control reg (YUKON only) */
+#define B0_ISRC 0x0008 /* 32 bit Interrupt Source Register */
+#define B0_IMSK 0x000c /* 32 bit Interrupt Mask Register */
+#define B0_HWE_ISRC 0x0010 /* 32 bit HW Error Interrupt Src Reg */
+#define B0_HWE_IMSK 0x0014 /* 32 bit HW Error Interrupt Mask Reg */
+#define B0_SP_ISRC 0x0018 /* 32 bit Special Interrupt Source Reg */
+ /* 0x001c: reserved */
+
+/* B0 XMAC 1 registers (GENESIS only) */
+#define B0_XM1_IMSK 0x0020 /* 16 bit r/w XMAC 1 Interrupt Mask Register*/
+ /* 0x0022 - 0x0027: reserved */
+#define B0_XM1_ISRC 0x0028 /* 16 bit ro XMAC 1 Interrupt Status Reg */
+ /* 0x002a - 0x002f: reserved */
+#define B0_XM1_PHY_ADDR 0x0030 /* 16 bit r/w XMAC 1 PHY Address Register */
+ /* 0x0032 - 0x0033: reserved */
+#define B0_XM1_PHY_DATA 0x0034 /* 16 bit r/w XMAC 1 PHY Data Register */
+ /* 0x0036 - 0x003f: reserved */
+
+/* B0 XMAC 2 registers (GENESIS only) */
+#define B0_XM2_IMSK 0x0040 /* 16 bit r/w XMAC 2 Interrupt Mask Register*/
+ /* 0x0042 - 0x0047: reserved */
+#define B0_XM2_ISRC 0x0048 /* 16 bit ro XMAC 2 Interrupt Status Reg */
+ /* 0x004a - 0x004f: reserved */
+#define B0_XM2_PHY_ADDR 0x0050 /* 16 bit r/w XMAC 2 PHY Address Register */
+ /* 0x0052 - 0x0053: reserved */
+#define B0_XM2_PHY_DATA 0x0054 /* 16 bit r/w XMAC 2 PHY Data Register */
+ /* 0x0056 - 0x005f: reserved */
+
+/* BMU Control Status Registers */
+#define B0_R1_CSR 0x0060 /* 32 bit BMU Ctrl/Stat Rx Queue 1 */
+#define B0_R2_CSR 0x0064 /* 32 bit BMU Ctrl/Stat Rx Queue 2 */
+#define B0_XS1_CSR 0x0068 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */
+#define B0_XA1_CSR 0x006c /* 32 bit BMU Ctrl/Stat Async Tx Queue 1*/
+#define B0_XS2_CSR 0x0070 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */
+#define B0_XA2_CSR 0x0074 /* 32 bit BMU Ctrl/Stat Async Tx Queue 2*/
+ /* 0x0078 - 0x007f: reserved */
+
+/*
+ * Bank 1
+ * - completely empty (this is the RAP Block window)
+ * Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ * Bank 2
+ */
+/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
+#define B2_MAC_1 0x0100 /* NA reg MAC Address 1 */
+ /* 0x0106 - 0x0107: reserved */
+#define B2_MAC_2 0x0108 /* NA reg MAC Address 2 */
+ /* 0x010e - 0x010f: reserved */
+#define B2_MAC_3 0x0110 /* NA reg MAC Address 3 */
+ /* 0x0116 - 0x0117: reserved */
+#define B2_CONN_TYP 0x0118 /* 8 bit Connector type */
+#define B2_PMD_TYP 0x0119 /* 8 bit PMD type */
+#define B2_MAC_CFG 0x011a /* 8 bit MAC Configuration / Chip Revision */
+#define B2_CHIP_ID 0x011b /* 8 bit Chip Identification Number */
+ /* Eprom registers are currently of no use */
+#define B2_E_0 0x011c /* 8 bit EPROM Byte 0 (ext. SRAM size */
+#define B2_E_1 0x011d /* 8 bit EPROM Byte 1 (PHY type) */
+#define B2_E_2 0x011e /* 8 bit EPROM Byte 2 */
+#define B2_E_3 0x011f /* 8 bit EPROM Byte 3 */
+#define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */
+#define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */
+ /* 0x0125 - 0x0127: reserved */
+#define B2_LD_CTRL 0x0128 /* 8 bit EPROM loader control register */
+#define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */
+ /* 0x012a - 0x012f: reserved */
+#define B2_TI_INI 0x0130 /* 32 bit Timer Init Value */
+#define B2_TI_VAL 0x0134 /* 32 bit Timer Value */
+#define B2_TI_CTRL 0x0138 /* 8 bit Timer Control */
+#define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */
+ /* 0x013a - 0x013f: reserved */
+#define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/
+#define B2_IRQM_VAL 0x0144 /* 32 bit IRQ Moderation Timer Value */
+#define B2_IRQM_CTRL 0x0148 /* 8 bit IRQ Moderation Timer Control */
+#define B2_IRQM_TEST 0x0149 /* 8 bit IRQ Moderation Timer Test */
+#define B2_IRQM_MSK 0x014c /* 32 bit IRQ Moderation Mask */
+#define B2_IRQM_HWE_MSK 0x0150 /* 32 bit IRQ Moderation HW Error Mask */
+ /* 0x0154 - 0x0157: reserved */
+#define B2_TST_CTRL1 0x0158 /* 8 bit Test Control Register 1 */
+#define B2_TST_CTRL2 0x0159 /* 8 bit Test Control Register 2 */
+ /* 0x015a - 0x015b: reserved */
+#define B2_GP_IO 0x015c /* 32 bit General Purpose I/O Register */
+#define B2_I2C_CTRL 0x0160 /* 32 bit I2C HW Control Register */
+#define B2_I2C_DATA 0x0164 /* 32 bit I2C HW Data Register */
+#define B2_I2C_IRQ 0x0168 /* 32 bit I2C HW IRQ Register */
+#define B2_I2C_SW 0x016c /* 32 bit I2C SW Port Register */
+
+/* Blink Source Counter (GENESIS only) */
+#define B2_BSC_INI 0x0170 /* 32 bit Blink Source Counter Init Val */
+#define B2_BSC_VAL 0x0174 /* 32 bit Blink Source Counter Value */
+#define B2_BSC_CTRL 0x0178 /* 8 bit Blink Source Counter Control */
+#define B2_BSC_STAT 0x0179 /* 8 bit Blink Source Counter Status */
+#define B2_BSC_TST 0x017a /* 16 bit Blink Source Counter Test Reg */
+ /* 0x017c - 0x017f: reserved */
+
+/*
+ * Bank 3
+ */
+/* RAM Random Registers */
+#define B3_RAM_ADDR 0x0180 /* 32 bit RAM Address, to read or write */
+#define B3_RAM_DATA_LO 0x0184 /* 32 bit RAM Data Word (low dWord) */
+#define B3_RAM_DATA_HI 0x0188 /* 32 bit RAM Data Word (high dWord) */
+ /* 0x018c - 0x018f: reserved */
+
+/* RAM Interface Registers */
+/*
+ * The HW-Spec. calls this registers Timeout Value 0..11. But this names are
+ * not usable in SW. Please notice these are NOT real timeouts, these are
+ * the number of qWords transferred continuously.
+ */
+#define B3_RI_WTO_R1 0x0190 /* 8 bit WR Timeout Queue R1 (TO0) */
+#define B3_RI_WTO_XA1 0x0191 /* 8 bit WR Timeout Queue XA1 (TO1) */
+#define B3_RI_WTO_XS1 0x0192 /* 8 bit WR Timeout Queue XS1 (TO2) */
+#define B3_RI_RTO_R1 0x0193 /* 8 bit RD Timeout Queue R1 (TO3) */
+#define B3_RI_RTO_XA1 0x0194 /* 8 bit RD Timeout Queue XA1 (TO4) */
+#define B3_RI_RTO_XS1 0x0195 /* 8 bit RD Timeout Queue XS1 (TO5) */
+#define B3_RI_WTO_R2 0x0196 /* 8 bit WR Timeout Queue R2 (TO6) */
+#define B3_RI_WTO_XA2 0x0197 /* 8 bit WR Timeout Queue XA2 (TO7) */
+#define B3_RI_WTO_XS2 0x0198 /* 8 bit WR Timeout Queue XS2 (TO8) */
+#define B3_RI_RTO_R2 0x0199 /* 8 bit RD Timeout Queue R2 (TO9) */
+#define B3_RI_RTO_XA2 0x019a /* 8 bit RD Timeout Queue XA2 (TO10)*/
+#define B3_RI_RTO_XS2 0x019b /* 8 bit RD Timeout Queue XS2 (TO11)*/
+#define B3_RI_TO_VAL 0x019c /* 8 bit Current Timeout Count Val */
+ /* 0x019d - 0x019f: reserved */
+#define B3_RI_CTRL 0x01a0 /* 16 bit RAM Interface Control Register */
+#define B3_RI_TEST 0x01a2 /* 8 bit RAM Interface Test Register */
+ /* 0x01a3 - 0x01af: reserved */
+
+/* MAC Arbiter Registers (GENESIS only) */
+/* these are the no. of qWord transferred continuously and NOT real timeouts */
+#define B3_MA_TOINI_RX1 0x01b0 /* 8 bit Timeout Init Val Rx Path MAC 1 */
+#define B3_MA_TOINI_RX2 0x01b1 /* 8 bit Timeout Init Val Rx Path MAC 2 */
+#define B3_MA_TOINI_TX1 0x01b2 /* 8 bit Timeout Init Val Tx Path MAC 1 */
+#define B3_MA_TOINI_TX2 0x01b3 /* 8 bit Timeout Init Val Tx Path MAC 2 */
+#define B3_MA_TOVAL_RX1 0x01b4 /* 8 bit Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_RX2 0x01b5 /* 8 bit Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_TX1 0x01b6 /* 8 bit Timeout Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_TX2 0x01b7 /* 8 bit Timeout Value Tx Path MAC 2 */
+#define B3_MA_TO_CTRL 0x01b8 /* 16 bit MAC Arbiter Timeout Ctrl Reg */
+#define B3_MA_TO_TEST 0x01ba /* 16 bit MAC Arbiter Timeout Test Reg */
+ /* 0x01bc - 0x01bf: reserved */
+#define B3_MA_RCINI_RX1 0x01c0 /* 8 bit Recovery Init Val Rx Path MAC 1 */
+#define B3_MA_RCINI_RX2 0x01c1 /* 8 bit Recovery Init Val Rx Path MAC 2 */
+#define B3_MA_RCINI_TX1 0x01c2 /* 8 bit Recovery Init Val Tx Path MAC 1 */
+#define B3_MA_RCINI_TX2 0x01c3 /* 8 bit Recovery Init Val Tx Path MAC 2 */
+#define B3_MA_RCVAL_RX1 0x01c4 /* 8 bit Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_RX2 0x01c5 /* 8 bit Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_TX1 0x01c6 /* 8 bit Recovery Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_TX2 0x01c7 /* 8 bit Recovery Value Tx Path MAC 2 */
+#define B3_MA_RC_CTRL 0x01c8 /* 16 bit MAC Arbiter Recovery Ctrl Reg */
+#define B3_MA_RC_TEST 0x01ca /* 16 bit MAC Arbiter Recovery Test Reg */
+ /* 0x01cc - 0x01cf: reserved */
+
+/* Packet Arbiter Registers (GENESIS only) */
+/* these are real timeouts */
+#define B3_PA_TOINI_RX1 0x01d0 /* 16 bit Timeout Init Val Rx Path MAC 1 */
+ /* 0x01d2 - 0x01d3: reserved */
+#define B3_PA_TOINI_RX2 0x01d4 /* 16 bit Timeout Init Val Rx Path MAC 2 */
+ /* 0x01d6 - 0x01d7: reserved */
+#define B3_PA_TOINI_TX1 0x01d8 /* 16 bit Timeout Init Val Tx Path MAC 1 */
+ /* 0x01da - 0x01db: reserved */
+#define B3_PA_TOINI_TX2 0x01dc /* 16 bit Timeout Init Val Tx Path MAC 2 */
+ /* 0x01de - 0x01df: reserved */
+#define B3_PA_TOVAL_RX1 0x01e0 /* 16 bit Timeout Val Rx Path MAC 1 */
+ /* 0x01e2 - 0x01e3: reserved */
+#define B3_PA_TOVAL_RX2 0x01e4 /* 16 bit Timeout Val Rx Path MAC 2 */
+ /* 0x01e6 - 0x01e7: reserved */
+#define B3_PA_TOVAL_TX1 0x01e8 /* 16 bit Timeout Val Tx Path MAC 1 */
+ /* 0x01ea - 0x01eb: reserved */
+#define B3_PA_TOVAL_TX2 0x01ec /* 16 bit Timeout Val Tx Path MAC 2 */
+ /* 0x01ee - 0x01ef: reserved */
+#define B3_PA_CTRL 0x01f0 /* 16 bit Packet Arbiter Ctrl Register */
+#define B3_PA_TEST 0x01f2 /* 16 bit Packet Arbiter Test Register */
+ /* 0x01f4 - 0x01ff: reserved */
+
+/*
+ * Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+#define TXA_ITI_INI 0x0200 /* 32 bit Tx Arb Interval Timer Init Val*/
+#define TXA_ITI_VAL 0x0204 /* 32 bit Tx Arb Interval Timer Value */
+#define TXA_LIM_INI 0x0208 /* 32 bit Tx Arb Limit Counter Init Val */
+#define TXA_LIM_VAL 0x020c /* 32 bit Tx Arb Limit Counter Value */
+#define TXA_CTRL 0x0210 /* 8 bit Tx Arbiter Control Register */
+#define TXA_TEST 0x0211 /* 8 bit Tx Arbiter Test Register */
+#define TXA_STAT 0x0212 /* 8 bit Tx Arbiter Status Register */
+ /* 0x0213 - 0x027f: reserved */
+ /* 0x0280 - 0x0292: MAC 2 */
+ /* 0x0213 - 0x027f: reserved */
+
+/*
+ * Bank 6
+ */
+/* External registers (GENESIS only) */
+#define B6_EXT_REG 0x0300
+
+/*
+ * Bank 7
+ */
+/* This is a copy of the Configuration register file (lower half) */
+#define B7_CFG_SPC 0x0380
+
+/*
+ * Bank 8 - 15
+ */
+/* Receive and Transmit Queue Registers, use Q_ADDR() to access */
+#define B8_Q_REGS 0x0400
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+#define Q_D 0x00 /* 8*32 bit Current Descriptor */
+#define Q_DA_L 0x20 /* 32 bit Current Descriptor Address Low dWord */
+#define Q_DA_H 0x24 /* 32 bit Current Descriptor Address High dWord */
+#define Q_AC_L 0x28 /* 32 bit Current Address Counter Low dWord */
+#define Q_AC_H 0x2c /* 32 bit Current Address Counter High dWord */
+#define Q_BC 0x30 /* 32 bit Current Byte Counter */
+#define Q_CSR 0x34 /* 32 bit BMU Control/Status Register */
+#define Q_F 0x38 /* 32 bit Flag Register */
+#define Q_T1 0x3c /* 32 bit Test Register 1 */
+#define Q_T1_TR 0x3c /* 8 bit Test Register 1 Transfer SM */
+#define Q_T1_WR 0x3d /* 8 bit Test Register 1 Write Descriptor SM */
+#define Q_T1_RD 0x3e /* 8 bit Test Register 1 Read Descriptor SM */
+#define Q_T1_SV 0x3f /* 8 bit Test Register 1 Supervisor SM */
+#define Q_T2 0x40 /* 32 bit Test Register 2 */
+#define Q_T3 0x44 /* 32 bit Test Register 3 */
+ /* 0x48 - 0x7f: reserved */
+
+/*
+ * Bank 16 - 23
+ */
+/* RAM Buffer Registers */
+#define B16_RAM_REGS 0x0800
+
+/* RAM Buffer Register Offsets, use RB_ADDR() to access */
+#define RB_START 0x00 /* 32 bit RAM Buffer Start Address */
+#define RB_END 0x04 /* 32 bit RAM Buffer End Address */
+#define RB_WP 0x08 /* 32 bit RAM Buffer Write Pointer */
+#define RB_RP 0x0c /* 32 bit RAM Buffer Read Pointer */
+#define RB_RX_UTPP 0x10 /* 32 bit Rx Upper Threshold, Pause Pack */
+#define RB_RX_LTPP 0x14 /* 32 bit Rx Lower Threshold, Pause Pack */
+#define RB_RX_UTHP 0x18 /* 32 bit Rx Upper Threshold, High Prio */
+#define RB_RX_LTHP 0x1c /* 32 bit Rx Lower Threshold, High Prio */
+ /* 0x10 - 0x1f: reserved at Tx RAM Buffer Registers */
+#define RB_PC 0x20 /* 32 bit RAM Buffer Packet Counter */
+#define RB_LEV 0x24 /* 32 bit RAM Buffer Level Register */
+#define RB_CTRL 0x28 /* 8 bit RAM Buffer Control Register */
+#define RB_TST1 0x29 /* 8 bit RAM Buffer Test Register 1 */
+#define RB_TST2 0x2A /* 8 bit RAM Buffer Test Register 2 */
+ /* 0x2c - 0x7f: reserved */
+
+/*
+ * Bank 24
+ */
+/*
+ * Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only)
+ * use MR_ADDR() to access
+ */
+#define RX_MFF_EA 0x0c00 /* 32 bit Receive MAC FIFO End Address */
+#define RX_MFF_WP 0x0c04 /* 32 bit Receive MAC FIFO Write Pointer */
+ /* 0x0c08 - 0x0c0b: reserved */
+#define RX_MFF_RP 0x0c0c /* 32 bit Receive MAC FIFO Read Pointer */
+#define RX_MFF_PC 0x0c10 /* 32 bit Receive MAC FIFO Packet Cnt */
+#define RX_MFF_LEV 0x0c14 /* 32 bit Receive MAC FIFO Level */
+#define RX_MFF_CTRL1 0x0c18 /* 16 bit Receive MAC FIFO Control Reg 1*/
+#define RX_MFF_STAT_TO 0x0c1a /* 8 bit Receive MAC Status Timeout */
+#define RX_MFF_TIST_TO 0x0c1b /* 8 bit Receive MAC Time Stamp Timeout */
+#define RX_MFF_CTRL2 0x0c1c /* 8 bit Receive MAC FIFO Control Reg 2*/
+#define RX_MFF_TST1 0x0c1d /* 8 bit Receive MAC FIFO Test Reg 1 */
+#define RX_MFF_TST2 0x0c1e /* 8 bit Receive MAC FIFO Test Reg 2 */
+ /* 0x0c1f: reserved */
+#define RX_LED_INI 0x0c20 /* 32 bit Receive LED Cnt Init Value */
+#define RX_LED_VAL 0x0c24 /* 32 bit Receive LED Cnt Current Value */
+#define RX_LED_CTRL 0x0c28 /* 8 bit Receive LED Cnt Control Reg */
+#define RX_LED_TST 0x0c29 /* 8 bit Receive LED Cnt Test Register */
+ /* 0x0c2a - 0x0c2f: reserved */
+#define LNK_SYNC_INI 0x0c30 /* 32 bit Link Sync Cnt Init Value */
+#define LNK_SYNC_VAL 0x0c34 /* 32 bit Link Sync Cnt Current Value */
+#define LNK_SYNC_CTRL 0x0c38 /* 8 bit Link Sync Cnt Control Register */
+#define LNK_SYNC_TST 0x0c39 /* 8 bit Link Sync Cnt Test Register */
+ /* 0x0c3a - 0x0c3b: reserved */
+#define LNK_LED_REG 0x0c3c /* 8 bit Link LED Register */
+ /* 0x0c3d - 0x0c3f: reserved */
+
+/* Receive GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define RX_GMF_EA 0x0c40 /* 32 bit Rx GMAC FIFO End Address */
+#define RX_GMF_AF_THR 0x0c44 /* 32 bit Rx GMAC FIFO Almost Full Thresh. */
+#define RX_GMF_CTRL_T 0x0c48 /* 32 bit Rx GMAC FIFO Control/Test */
+#define RX_GMF_FL_MSK 0x0c4c /* 32 bit Rx GMAC FIFO Flush Mask */
+#define RX_GMF_FL_THR 0x0c50 /* 32 bit Rx GMAC FIFO Flush Threshold */
+ /* 0x0c54 - 0x0c5f: reserved */
+#define RX_GMF_WP 0x0c60 /* 32 bit Rx GMAC FIFO Write Pointer */
+ /* 0x0c64 - 0x0c67: reserved */
+#define RX_GMF_WLEV 0x0c68 /* 32 bit Rx GMAC FIFO Write Level */
+ /* 0x0c6c - 0x0c6f: reserved */
+#define RX_GMF_RP 0x0c70 /* 32 bit Rx GMAC FIFO Read Pointer */
+ /* 0x0c74 - 0x0c77: reserved */
+#define RX_GMF_RLEV 0x0c78 /* 32 bit Rx GMAC FIFO Read Level */
+ /* 0x0c7c - 0x0c7f: reserved */
+
+/*
+ * Bank 25
+ */
+ /* 0x0c80 - 0x0cbf: MAC 2 */
+ /* 0x0cc0 - 0x0cff: reserved */
+
+/*
+ * Bank 26
+ */
+/*
+ * Transmit MAC FIFO and Transmit LED Registers (GENESIS only),
+ * use MR_ADDR() to access
+ */
+#define TX_MFF_EA 0x0d00 /* 32 bit Transmit MAC FIFO End Address */
+#define TX_MFF_WP 0x0d04 /* 32 bit Transmit MAC FIFO WR Pointer */
+#define TX_MFF_WSP 0x0d08 /* 32 bit Transmit MAC FIFO WR Shadow Ptr */
+#define TX_MFF_RP 0x0d0c /* 32 bit Transmit MAC FIFO RD Pointer */
+#define TX_MFF_PC 0x0d10 /* 32 bit Transmit MAC FIFO Packet Cnt */
+#define TX_MFF_LEV 0x0d14 /* 32 bit Transmit MAC FIFO Level */
+#define TX_MFF_CTRL1 0x0d18 /* 16 bit Transmit MAC FIFO Ctrl Reg 1 */
+#define TX_MFF_WAF 0x0d1a /* 8 bit Transmit MAC Wait after flush */
+ /* 0x0c1b: reserved */
+#define TX_MFF_CTRL2 0x0d1c /* 8 bit Transmit MAC FIFO Ctrl Reg 2 */
+#define TX_MFF_TST1 0x0d1d /* 8 bit Transmit MAC FIFO Test Reg 1 */
+#define TX_MFF_TST2 0x0d1e /* 8 bit Transmit MAC FIFO Test Reg 2 */
+ /* 0x0d1f: reserved */
+#define TX_LED_INI 0x0d20 /* 32 bit Transmit LED Cnt Init Value */
+#define TX_LED_VAL 0x0d24 /* 32 bit Transmit LED Cnt Current Val */
+#define TX_LED_CTRL 0x0d28 /* 8 bit Transmit LED Cnt Control Reg */
+#define TX_LED_TST 0x0d29 /* 8 bit Transmit LED Cnt Test Reg */
+ /* 0x0d2a - 0x0d3f: reserved */
+
+/* Transmit GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define TX_GMF_EA 0x0d40 /* 32 bit Tx GMAC FIFO End Address */
+#define TX_GMF_AE_THR 0x0d44 /* 32 bit Tx GMAC FIFO Almost Empty Thresh.*/
+#define TX_GMF_CTRL_T 0x0d48 /* 32 bit Tx GMAC FIFO Control/Test */
+ /* 0x0d4c - 0x0d5f: reserved */
+#define TX_GMF_WP 0x0d60 /* 32 bit Tx GMAC FIFO Write Pointer */
+#define TX_GMF_WSP 0x0d64 /* 32 bit Tx GMAC FIFO Write Shadow Ptr. */
+#define TX_GMF_WLEV 0x0d68 /* 32 bit Tx GMAC FIFO Write Level */
+ /* 0x0d6c - 0x0d6f: reserved */
+#define TX_GMF_RP 0x0d70 /* 32 bit Tx GMAC FIFO Read Pointer */
+#define TX_GMF_RSTP 0x0d74 /* 32 bit Tx GMAC FIFO Restart Pointer */
+#define TX_GMF_RLEV 0x0d78 /* 32 bit Tx GMAC FIFO Read Level */
+ /* 0x0d7c - 0x0d7f: reserved */
+
+/*
+ * Bank 27
+ */
+ /* 0x0d80 - 0x0dbf: MAC 2 */
+ /* 0x0daa - 0x0dff: reserved */
+
+/*
+ * Bank 28
+ */
+/* Descriptor Poll Timer Registers */
+#define B28_DPT_INI 0x0e00 /* 24 bit Descriptor Poll Timer Init Val */
+#define B28_DPT_VAL 0x0e04 /* 24 bit Descriptor Poll Timer Curr Val */
+#define B28_DPT_CTRL 0x0e08 /* 8 bit Descriptor Poll Timer Ctrl Reg */
+ /* 0x0e09: reserved */
+#define B28_DPT_TST 0x0e0a /* 8 bit Descriptor Poll Timer Test Reg */
+ /* 0x0e0b: reserved */
+
+/* Time Stamp Timer Registers (YUKON only) */
+ /* 0x0e10: reserved */
+#define GMAC_TI_ST_VAL 0x0e14 /* 32 bit Time Stamp Timer Curr Val */
+#define GMAC_TI_ST_CTRL 0x0e18 /* 8 bit Time Stamp Timer Ctrl Reg */
+ /* 0x0e19: reserved */
+#define GMAC_TI_ST_TST 0x0e1a /* 8 bit Time Stamp Timer Test Reg */
+ /* 0x0e1b - 0x0e7f: reserved */
+
+/*
+ * Bank 29
+ */
+ /* 0x0e80 - 0x0efc: reserved */
+
+/*
+ * Bank 30
+ */
+/* GMAC and GPHY Control Registers (YUKON only) */
+#define GMAC_CTRL 0x0f00 /* 32 bit GMAC Control Reg */
+#define GPHY_CTRL 0x0f04 /* 32 bit GPHY Control Reg */
+#define GMAC_IRQ_SRC 0x0f08 /* 8 bit GMAC Interrupt Source Reg */
+ /* 0x0f09 - 0x0f0b: reserved */
+#define GMAC_IRQ_MSK 0x0f0c /* 8 bit GMAC Interrupt Mask Reg */
+ /* 0x0f0d - 0x0f0f: reserved */
+#define GMAC_LINK_CTRL 0x0f10 /* 16 bit Link Control Reg */
+ /* 0x0f14 - 0x0f1f: reserved */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+#define WOL_REG_OFFS 0x20 /* HW-Bug: Address is + 0x20 against spec. */
+
+#define WOL_CTRL_STAT 0x0f20 /* 16 bit WOL Control/Status Reg */
+#define WOL_MATCH_CTL 0x0f22 /* 8 bit WOL Match Control Reg */
+#define WOL_MATCH_RES 0x0f23 /* 8 bit WOL Match Result Reg */
+#define WOL_MAC_ADDR_LO 0x0f24 /* 32 bit WOL MAC Address Low */
+#define WOL_MAC_ADDR_HI 0x0f28 /* 16 bit WOL MAC Address High */
+#define WOL_PATT_RPTR 0x0f2c /* 8 bit WOL Pattern Read Ptr */
+
+/* use this macro to access above registers */
+#define WOL_REG(Reg) ((Reg) + (pAC->GIni.GIWolOffs))
+
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+#define WOL_PATT_LEN_LO 0x0f30 /* 32 bit WOL Pattern Length 3..0 */
+#define WOL_PATT_LEN_HI 0x0f34 /* 24 bit WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+#define WOL_PATT_CNT_0 0x0f38 /* 32 bit WOL Pattern Counter 3..0 */
+#define WOL_PATT_CNT_4 0x0f3c /* 24 bit WOL Pattern Counter 6..4 */
+ /* 0x0f40 - 0x0f7f: reserved */
+
+/*
+ * Bank 31
+ */
+/* 0x0f80 - 0x0fff: reserved */
+
+/*
+ * Bank 32 - 33
+ */
+#define WOL_PATT_RAM_1 0x1000 /* WOL Pattern RAM Link 1 */
+
+/*
+ * Bank 0x22 - 0x3f
+ */
+/* 0x1100 - 0x1fff: reserved */
+
+/*
+ * Bank 0x40 - 0x4f
+ */
+#define BASE_XMAC_1 0x2000 /* XMAC 1 registers */
+
+/*
+ * Bank 0x50 - 0x5f
+ */
+
+#define BASE_GMAC_1 0x2800 /* GMAC 1 registers */
+
+/*
+ * Bank 0x60 - 0x6f
+ */
+#define BASE_XMAC_2 0x3000 /* XMAC 2 registers */
+
+/*
+ * Bank 0x70 - 0x7f
+ */
+#define BASE_GMAC_2 0x3800 /* GMAC 2 registers */
+
+/*
+ * Control Register Bit Definitions:
+ */
+/* B0_RAP 8 bit Register Address Port */
+ /* Bit 7: reserved */
+#define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0,..,6f = block 6f */
+
+/* B0_CTST 16 bit Control/Status register */
+ /* Bit 15..14: reserved */
+#define CS_CLK_RUN_HOT BIT_13S /* CLK_RUN hot m. (YUKON-Lite only) */
+#define CS_CLK_RUN_RST BIT_12S /* CLK_RUN reset (YUKON-Lite only) */
+#define CS_CLK_RUN_ENA BIT_11S /* CLK_RUN enable (YUKON-Lite only) */
+#define CS_VAUX_AVAIL BIT_10S /* VAUX available (YUKON only) */
+#define CS_BUS_CLOCK BIT_9S /* Bus Clock 0/1 = 33/66 MHz */
+#define CS_BUS_SLOT_SZ BIT_8S /* Slot Size 0/1 = 32/64 bit slot */
+#define CS_ST_SW_IRQ BIT_7S /* Set IRQ SW Request */
+#define CS_CL_SW_IRQ BIT_6S /* Clear IRQ SW Request */
+#define CS_STOP_DONE BIT_5S /* Stop Master is finished */
+#define CS_STOP_MAST BIT_4S /* Command Bit to stop the master */
+#define CS_MRST_CLR BIT_3S /* Clear Master reset */
+#define CS_MRST_SET BIT_2S /* Set Master reset */
+#define CS_RST_CLR BIT_1S /* Clear Software reset */
+#define CS_RST_SET BIT_0S /* Set Software reset */
+
+/* B0_LED 8 Bit LED register */
+ /* Bit 7.. 2: reserved */
+#define LED_STAT_ON BIT_1S /* Status LED on */
+#define LED_STAT_OFF BIT_0S /* Status LED off */
+
+/* B0_POWER_CTRL 8 Bit Power Control reg (YUKON only) */
+#define PC_VAUX_ENA BIT_7 /* Switch VAUX Enable */
+#define PC_VAUX_DIS BIT_6 /* Switch VAUX Disable */
+#define PC_VCC_ENA BIT_5 /* Switch VCC Enable */
+#define PC_VCC_DIS BIT_4 /* Switch VCC Disable */
+#define PC_VAUX_ON BIT_3 /* Switch VAUX On */
+#define PC_VAUX_OFF BIT_2 /* Switch VAUX Off */
+#define PC_VCC_ON BIT_1 /* Switch VCC On */
+#define PC_VCC_OFF BIT_0 /* Switch VCC Off */
+
+/* B0_ISRC 32 bit Interrupt Source Register */
+/* B0_IMSK 32 bit Interrupt Mask Register */
+/* B0_SP_ISRC 32 bit Special Interrupt Source Reg */
+/* B2_IRQM_MSK 32 bit IRQ Moderation Mask */
+#define IS_ALL_MSK 0xbfffffffUL /* All Interrupt bits */
+#define IS_HW_ERR BIT_31 /* Interrupt HW Error */
+ /* Bit 30: reserved */
+#define IS_PA_TO_RX1 BIT_29 /* Packet Arb Timeout Rx1 */
+#define IS_PA_TO_RX2 BIT_28 /* Packet Arb Timeout Rx2 */
+#define IS_PA_TO_TX1 BIT_27 /* Packet Arb Timeout Tx1 */
+#define IS_PA_TO_TX2 BIT_26 /* Packet Arb Timeout Tx2 */
+#define IS_I2C_READY BIT_25 /* IRQ on end of I2C Tx */
+#define IS_IRQ_SW BIT_24 /* SW forced IRQ */
+#define IS_EXT_REG BIT_23 /* IRQ from LM80 or PHY (GENESIS only) */
+ /* IRQ from PHY (YUKON only) */
+#define IS_TIMINT BIT_22 /* IRQ from Timer */
+#define IS_MAC1 BIT_21 /* IRQ from MAC 1 */
+#define IS_LNK_SYNC_M1 BIT_20 /* Link Sync Cnt wrap MAC 1 */
+#define IS_MAC2 BIT_19 /* IRQ from MAC 2 */
+#define IS_LNK_SYNC_M2 BIT_18 /* Link Sync Cnt wrap MAC 2 */
+/* Receive Queue 1 */
+#define IS_R1_B BIT_17 /* Q_R1 End of Buffer */
+#define IS_R1_F BIT_16 /* Q_R1 End of Frame */
+#define IS_R1_C BIT_15 /* Q_R1 Encoding Error */
+/* Receive Queue 2 */
+#define IS_R2_B BIT_14 /* Q_R2 End of Buffer */
+#define IS_R2_F BIT_13 /* Q_R2 End of Frame */
+#define IS_R2_C BIT_12 /* Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+#define IS_XS1_B BIT_11 /* Q_XS1 End of Buffer */
+#define IS_XS1_F BIT_10 /* Q_XS1 End of Frame */
+#define IS_XS1_C BIT_9 /* Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+#define IS_XA1_B BIT_8 /* Q_XA1 End of Buffer */
+#define IS_XA1_F BIT_7 /* Q_XA1 End of Frame */
+#define IS_XA1_C BIT_6 /* Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+#define IS_XS2_B BIT_5 /* Q_XS2 End of Buffer */
+#define IS_XS2_F BIT_4 /* Q_XS2 End of Frame */
+#define IS_XS2_C BIT_3 /* Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+#define IS_XA2_B BIT_2 /* Q_XA2 End of Buffer */
+#define IS_XA2_F BIT_1 /* Q_XA2 End of Frame */
+#define IS_XA2_C BIT_0 /* Q_XA2 Encoding Error */
+
+
+/* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */
+/* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */
+/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */
+#define IS_ERR_MSK 0x00000fffL /* All Error bits */
+ /* Bit 31..14: reserved */
+#define IS_IRQ_TIST_OV BIT_13 /* Time Stamp Timer Overflow (YUKON only) */
+#define IS_IRQ_SENSOR BIT_12 /* IRQ from Sensor (YUKON only) */
+#define IS_IRQ_MST_ERR BIT_11 /* IRQ master error detected */
+#define IS_IRQ_STAT BIT_10 /* IRQ status exception */
+#define IS_NO_STAT_M1 BIT_9 /* No Rx Status from MAC 1 */
+#define IS_NO_STAT_M2 BIT_8 /* No Rx Status from MAC 2 */
+#define IS_NO_TIST_M1 BIT_7 /* No Time Stamp from MAC 1 */
+#define IS_NO_TIST_M2 BIT_6 /* No Time Stamp from MAC 2 */
+#define IS_RAM_RD_PAR BIT_5 /* RAM Read Parity Error */
+#define IS_RAM_WR_PAR BIT_4 /* RAM Write Parity Error */
+#define IS_M1_PAR_ERR BIT_3 /* MAC 1 Parity Error */
+#define IS_M2_PAR_ERR BIT_2 /* MAC 2 Parity Error */
+#define IS_R1_PAR_ERR BIT_1 /* Queue R1 Parity Error */
+#define IS_R2_PAR_ERR BIT_0 /* Queue R2 Parity Error */
+
+/* B2_CONN_TYP 8 bit Connector type */
+/* B2_PMD_TYP 8 bit PMD type */
+/* Values of connector and PMD type comply to SysKonnect internal std */
+
+/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */
+#define CFG_CHIP_R_MSK (0xf<<4) /* Bit 7.. 4: Chip Revision */
+ /* Bit 3.. 2: reserved */
+#define CFG_DIS_M2_CLK BIT_1S /* Disable Clock for 2nd MAC */
+#define CFG_SNG_MAC BIT_0S /* MAC Config: 0=2 MACs / 1=1 MAC*/
+
+/* B2_CHIP_ID 8 bit Chip Identification Number */
+#define CHIP_ID_GENESIS 0x0a /* Chip ID for GENESIS */
+#define CHIP_ID_YUKON 0xb0 /* Chip ID for YUKON */
+#define CHIP_ID_YUKON_LITE 0xb1 /* Chip ID for YUKON-Lite (Rev. A1-A3) */
+#define CHIP_ID_YUKON_LP 0xb2 /* Chip ID for YUKON-LP */
+
+#define CHIP_REV_YU_LITE_A1 3 /* Chip Rev. for YUKON-Lite A1,A2 */
+#define CHIP_REV_YU_LITE_A3 7 /* Chip Rev. for YUKON-Lite A3 */
+
+/* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */
+#define FAR_ADDR 0x1ffffL /* Bit 16.. 0: FPROM Address mask */
+
+/* B2_LD_CTRL 8 bit EPROM loader control register */
+/* Bits are currently reserved */
+
+/* B2_LD_TEST 8 bit EPROM loader test register */
+ /* Bit 7.. 4: reserved */
+#define LD_T_ON BIT_3S /* Loader Test mode on */
+#define LD_T_OFF BIT_2S /* Loader Test mode off */
+#define LD_T_STEP BIT_1S /* Decrement FPROM addr. Counter */
+#define LD_START BIT_0S /* Start loading FPROM */
+
+/*
+ * Timer Section
+ */
+/* B2_TI_CTRL 8 bit Timer control */
+/* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */
+ /* Bit 7.. 3: reserved */
+#define TIM_START BIT_2S /* Start Timer */
+#define TIM_STOP BIT_1S /* Stop Timer */
+#define TIM_CLR_IRQ BIT_0S /* Clear Timer IRQ (!IRQM) */
+
+/* B2_TI_TEST 8 Bit Timer Test */
+/* B2_IRQM_TEST 8 bit IRQ Moderation Timer Test */
+/* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */
+ /* Bit 7.. 3: reserved */
+#define TIM_T_ON BIT_2S /* Test mode on */
+#define TIM_T_OFF BIT_1S /* Test mode off */
+#define TIM_T_STEP BIT_0S /* Test step */
+
+/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */
+/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */
+ /* Bit 31..24: reserved */
+#define DPT_MSK 0x00ffffffL /* Bit 23.. 0: Desc Poll Timer Bits */
+
+/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */
+ /* Bit 7.. 2: reserved */
+#define DPT_START BIT_1S /* Start Descriptor Poll Timer */
+#define DPT_STOP BIT_0S /* Stop Descriptor Poll Timer */
+
+/* B2_E_3 8 bit lower 4 bits used for HW self test result */
+#define B2_E3_RES_MASK 0x0f
+
+/* B2_TST_CTRL1 8 bit Test Control Register 1 */
+#define TST_FRC_DPERR_MR BIT_7S /* force DATAPERR on MST RD */
+#define TST_FRC_DPERR_MW BIT_6S /* force DATAPERR on MST WR */
+#define TST_FRC_DPERR_TR BIT_5S /* force DATAPERR on TRG RD */
+#define TST_FRC_DPERR_TW BIT_4S /* force DATAPERR on TRG WR */
+#define TST_FRC_APERR_M BIT_3S /* force ADDRPERR on MST */
+#define TST_FRC_APERR_T BIT_2S /* force ADDRPERR on TRG */
+#define TST_CFG_WRITE_ON BIT_1S /* Enable Config Reg WR */
+#define TST_CFG_WRITE_OFF BIT_0S /* Disable Config Reg WR */
+
+/* B2_TST_CTRL2 8 bit Test Control Register 2 */
+ /* Bit 7.. 4: reserved */
+ /* force the following error on the next master read/write */
+#define TST_FRC_DPERR_MR64 BIT_3S /* DataPERR RD 64 */
+#define TST_FRC_DPERR_MW64 BIT_2S /* DataPERR WR 64 */
+#define TST_FRC_APERR_1M64 BIT_1S /* AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64 BIT_0S /* AddrPERR on 2. phase */
+
+/* B2_GP_IO 32 bit General Purpose I/O Register */
+ /* Bit 31..26: reserved */
+#define GP_DIR_9 BIT_25 /* IO_9 direct, 0=In/1=Out */
+#define GP_DIR_8 BIT_24 /* IO_8 direct, 0=In/1=Out */
+#define GP_DIR_7 BIT_23 /* IO_7 direct, 0=In/1=Out */
+#define GP_DIR_6 BIT_22 /* IO_6 direct, 0=In/1=Out */
+#define GP_DIR_5 BIT_21 /* IO_5 direct, 0=In/1=Out */
+#define GP_DIR_4 BIT_20 /* IO_4 direct, 0=In/1=Out */
+#define GP_DIR_3 BIT_19 /* IO_3 direct, 0=In/1=Out */
+#define GP_DIR_2 BIT_18 /* IO_2 direct, 0=In/1=Out */
+#define GP_DIR_1 BIT_17 /* IO_1 direct, 0=In/1=Out */
+#define GP_DIR_0 BIT_16 /* IO_0 direct, 0=In/1=Out */
+ /* Bit 15..10: reserved */
+#define GP_IO_9 BIT_9 /* IO_9 pin */
+#define GP_IO_8 BIT_8 /* IO_8 pin */
+#define GP_IO_7 BIT_7 /* IO_7 pin */
+#define GP_IO_6 BIT_6 /* IO_6 pin */
+#define GP_IO_5 BIT_5 /* IO_5 pin */
+#define GP_IO_4 BIT_4 /* IO_4 pin */
+#define GP_IO_3 BIT_3 /* IO_3 pin */
+#define GP_IO_2 BIT_2 /* IO_2 pin */
+#define GP_IO_1 BIT_1 /* IO_1 pin */
+#define GP_IO_0 BIT_0 /* IO_0 pin */
+
+/* B2_I2C_CTRL 32 bit I2C HW Control Register */
+#define I2C_FLAG BIT_31 /* Start read/write if WR */
+#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be RD/WR */
+#define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */
+ /* Bit 8.. 5: reserved */
+#define I2C_BURST_LEN BIT_4 /* Burst Len, 1/4 bytes */
+#define I2C_DEV_SIZE (7<<1) /* Bit 3.. 1: I2C Device Size */
+#define I2C_025K_DEV (0<<1) /* 0: 256 Bytes or smal. */
+#define I2C_05K_DEV (1<<1) /* 1: 512 Bytes */
+#define I2C_1K_DEV (2<<1) /* 2: 1024 Bytes */
+#define I2C_2K_DEV (3<<1) /* 3: 2048 Bytes */
+#define I2C_4K_DEV (4<<1) /* 4: 4096 Bytes */
+#define I2C_8K_DEV (5<<1) /* 5: 8192 Bytes */
+#define I2C_16K_DEV (6<<1) /* 6: 16384 Bytes */
+#define I2C_32K_DEV (7<<1) /* 7: 32768 Bytes */
+#define I2C_STOP BIT_0 /* Interrupt I2C transfer */
+
+/* B2_I2C_IRQ 32 bit I2C HW IRQ Register */
+ /* Bit 31.. 1 reserved */
+#define I2C_CLR_IRQ BIT_0 /* Clear I2C IRQ */
+
+/* B2_I2C_SW 32 bit (8 bit access) I2C HW SW Port Register */
+ /* Bit 7.. 3: reserved */
+#define I2C_DATA_DIR BIT_2S /* direction of I2C_DATA */
+#define I2C_DATA BIT_1S /* I2C Data Port */
+#define I2C_CLK BIT_0S /* I2C Clock Port */
+
+/*
+ * I2C Address
+ */
+#define I2C_SENS_ADDR LM80_ADDR /* I2C Sensor Address, (Volt and Temp)*/
+
+
+/* B2_BSC_CTRL 8 bit Blink Source Counter Control */
+ /* Bit 7.. 2: reserved */
+#define BSC_START BIT_1S /* Start Blink Source Counter */
+#define BSC_STOP BIT_0S /* Stop Blink Source Counter */
+
+/* B2_BSC_STAT 8 bit Blink Source Counter Status */
+ /* Bit 7.. 1: reserved */
+#define BSC_SRC BIT_0S /* Blink Source, 0=Off / 1=On */
+
+/* B2_BSC_TST 16 bit Blink Source Counter Test Reg */
+#define BSC_T_ON BIT_2S /* Test mode on */
+#define BSC_T_OFF BIT_1S /* Test mode off */
+#define BSC_T_STEP BIT_0S /* Test step */
+
+
+/* B3_RAM_ADDR 32 bit RAM Address, to read or write */
+ /* Bit 31..19: reserved */
+#define RAM_ADR_RAN 0x0007ffffL /* Bit 18.. 0: RAM Address Range */
+
+/* RAM Interface Registers */
+/* B3_RI_CTRL 16 bit RAM Iface Control Register */
+ /* Bit 15..10: reserved */
+#define RI_CLR_RD_PERR BIT_9S /* Clear IRQ RAM Read Parity Err */
+#define RI_CLR_WR_PERR BIT_8S /* Clear IRQ RAM Write Parity Err*/
+ /* Bit 7.. 2: reserved */
+#define RI_RST_CLR BIT_1S /* Clear RAM Interface Reset */
+#define RI_RST_SET BIT_0S /* Set RAM Interface Reset */
+
+/* B3_RI_TEST 8 bit RAM Iface Test Register */
+ /* Bit 15.. 4: reserved */
+#define RI_T_EV BIT_3S /* Timeout Event occured */
+#define RI_T_ON BIT_2S /* Timeout Timer Test On */
+#define RI_T_OFF BIT_1S /* Timeout Timer Test Off */
+#define RI_T_STEP BIT_0S /* Timeout Timer Step */
+
+/* MAC Arbiter Registers */
+/* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */
+ /* Bit 15.. 4: reserved */
+#define MA_FOE_ON BIT_3S /* XMAC Fast Output Enable ON */
+#define MA_FOE_OFF BIT_2S /* XMAC Fast Output Enable OFF */
+#define MA_RST_CLR BIT_1S /* Clear MAC Arbiter Reset */
+#define MA_RST_SET BIT_0S /* Set MAC Arbiter Reset */
+
+/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */
+ /* Bit 15.. 8: reserved */
+#define MA_ENA_REC_TX2 BIT_7S /* Enable Recovery Timer TX2 */
+#define MA_DIS_REC_TX2 BIT_6S /* Disable Recovery Timer TX2 */
+#define MA_ENA_REC_TX1 BIT_5S /* Enable Recovery Timer TX1 */
+#define MA_DIS_REC_TX1 BIT_4S /* Disable Recovery Timer TX1 */
+#define MA_ENA_REC_RX2 BIT_3S /* Enable Recovery Timer RX2 */
+#define MA_DIS_REC_RX2 BIT_2S /* Disable Recovery Timer RX2 */
+#define MA_ENA_REC_RX1 BIT_1S /* Enable Recovery Timer RX1 */
+#define MA_DIS_REC_RX1 BIT_0S /* Disable Recovery Timer RX1 */
+
+/* Packet Arbiter Registers */
+/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */
+ /* Bit 15..14: reserved */
+#define PA_CLR_TO_TX2 BIT_13S /* Clear IRQ Packet Timeout TX2 */
+#define PA_CLR_TO_TX1 BIT_12S /* Clear IRQ Packet Timeout TX1 */
+#define PA_CLR_TO_RX2 BIT_11S /* Clear IRQ Packet Timeout RX2 */
+#define PA_CLR_TO_RX1 BIT_10S /* Clear IRQ Packet Timeout RX1 */
+#define PA_ENA_TO_TX2 BIT_9S /* Enable Timeout Timer TX2 */
+#define PA_DIS_TO_TX2 BIT_8S /* Disable Timeout Timer TX2 */
+#define PA_ENA_TO_TX1 BIT_7S /* Enable Timeout Timer TX1 */
+#define PA_DIS_TO_TX1 BIT_6S /* Disable Timeout Timer TX1 */
+#define PA_ENA_TO_RX2 BIT_5S /* Enable Timeout Timer RX2 */
+#define PA_DIS_TO_RX2 BIT_4S /* Disable Timeout Timer RX2 */
+#define PA_ENA_TO_RX1 BIT_3S /* Enable Timeout Timer RX1 */
+#define PA_DIS_TO_RX1 BIT_2S /* Disable Timeout Timer RX1 */
+#define PA_RST_CLR BIT_1S /* Clear MAC Arbiter Reset */
+#define PA_RST_SET BIT_0S /* Set MAC Arbiter Reset */
+
+#define PA_ENA_TO_ALL (PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+ PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+/* Rx/Tx Path related Arbiter Test Registers */
+/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */
+/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */
+/* B3_PA_TEST 16 bit Packet Arbiter Test Register */
+/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
+#define TX2_T_EV BIT_15S /* TX2 Timeout/Recv Event occured */
+#define TX2_T_ON BIT_14S /* TX2 Timeout/Recv Timer Test On */
+#define TX2_T_OFF BIT_13S /* TX2 Timeout/Recv Timer Tst Off */
+#define TX2_T_STEP BIT_12S /* TX2 Timeout/Recv Timer Step */
+#define TX1_T_EV BIT_11S /* TX1 Timeout/Recv Event occured */
+#define TX1_T_ON BIT_10S /* TX1 Timeout/Recv Timer Test On */
+#define TX1_T_OFF BIT_9S /* TX1 Timeout/Recv Timer Tst Off */
+#define TX1_T_STEP BIT_8S /* TX1 Timeout/Recv Timer Step */
+#define RX2_T_EV BIT_7S /* RX2 Timeout/Recv Event occured */
+#define RX2_T_ON BIT_6S /* RX2 Timeout/Recv Timer Test On */
+#define RX2_T_OFF BIT_5S /* RX2 Timeout/Recv Timer Tst Off */
+#define RX2_T_STEP BIT_4S /* RX2 Timeout/Recv Timer Step */
+#define RX1_T_EV BIT_3S /* RX1 Timeout/Recv Event occured */
+#define RX1_T_ON BIT_2S /* RX1 Timeout/Recv Timer Test On */
+#define RX1_T_OFF BIT_1S /* RX1 Timeout/Recv Timer Tst Off */
+#define RX1_T_STEP BIT_0S /* RX1 Timeout/Recv Timer Step */
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */
+/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */
+/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */
+/* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */
+ /* Bit 31..24: reserved */
+#define TXA_MAX_VAL 0x00ffffffUL/* Bit 23.. 0: Max TXA Timer/Cnt Val */
+
+/* TXA_CTRL 8 bit Tx Arbiter Control Register */
+#define TXA_ENA_FSYNC BIT_7S /* Enable force of sync Tx queue */
+#define TXA_DIS_FSYNC BIT_6S /* Disable force of sync Tx queue */
+#define TXA_ENA_ALLOC BIT_5S /* Enable alloc of free bandwidth */
+#define TXA_DIS_ALLOC BIT_4S /* Disable alloc of free bandwidth */
+#define TXA_START_RC BIT_3S /* Start sync Rate Control */
+#define TXA_STOP_RC BIT_2S /* Stop sync Rate Control */
+#define TXA_ENA_ARB BIT_1S /* Enable Tx Arbiter */
+#define TXA_DIS_ARB BIT_0S /* Disable Tx Arbiter */
+
+/* TXA_TEST 8 bit Tx Arbiter Test Register */
+ /* Bit 7.. 6: reserved */
+#define TXA_INT_T_ON BIT_5S /* Tx Arb Interval Timer Test On */
+#define TXA_INT_T_OFF BIT_4S /* Tx Arb Interval Timer Test Off */
+#define TXA_INT_T_STEP BIT_3S /* Tx Arb Interval Timer Step */
+#define TXA_LIM_T_ON BIT_2S /* Tx Arb Limit Timer Test On */
+#define TXA_LIM_T_OFF BIT_1S /* Tx Arb Limit Timer Test Off */
+#define TXA_LIM_T_STEP BIT_0S /* Tx Arb Limit Timer Step */
+
+/* TXA_STAT 8 bit Tx Arbiter Status Register */
+ /* Bit 7.. 1: reserved */
+#define TXA_PRIO_XS BIT_0S /* sync queue has prio to send */
+
+/* Q_BC 32 bit Current Byte Counter */
+ /* Bit 31..16: reserved */
+#define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */
+
+/* BMU Control Status Registers */
+/* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */
+/* B0_R2_CSR 32 bit BMU Ctrl/Stat Rx Queue 2 */
+/* B0_XA1_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */
+/* B0_XS1_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 1 */
+/* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */
+/* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */
+/* Q_CSR 32 bit BMU Control/Status Register */
+ /* Bit 31..25: reserved */
+#define CSR_SV_IDLE BIT_24 /* BMU SM Idle */
+ /* Bit 23..22: reserved */
+#define CSR_DESC_CLR BIT_21 /* Clear Reset for Descr */
+#define CSR_DESC_SET BIT_20 /* Set Reset for Descr */
+#define CSR_FIFO_CLR BIT_19 /* Clear Reset for FIFO */
+#define CSR_FIFO_SET BIT_18 /* Set Reset for FIFO */
+#define CSR_HPI_RUN BIT_17 /* Release HPI SM */
+#define CSR_HPI_RST BIT_16 /* Reset HPI SM to Idle */
+#define CSR_SV_RUN BIT_15 /* Release Supervisor SM */
+#define CSR_SV_RST BIT_14 /* Reset Supervisor SM */
+#define CSR_DREAD_RUN BIT_13 /* Release Descr Read SM */
+#define CSR_DREAD_RST BIT_12 /* Reset Descr Read SM */
+#define CSR_DWRITE_RUN BIT_11 /* Release Descr Write SM */
+#define CSR_DWRITE_RST BIT_10 /* Reset Descr Write SM */
+#define CSR_TRANS_RUN BIT_9 /* Release Transfer SM */
+#define CSR_TRANS_RST BIT_8 /* Reset Transfer SM */
+#define CSR_ENA_POL BIT_7 /* Enable Descr Polling */
+#define CSR_DIS_POL BIT_6 /* Disable Descr Polling */
+#define CSR_STOP BIT_5 /* Stop Rx/Tx Queue */
+#define CSR_START BIT_4 /* Start Rx/Tx Queue */
+#define CSR_IRQ_CL_P BIT_3 /* (Rx) Clear Parity IRQ */
+#define CSR_IRQ_CL_B BIT_2 /* Clear EOB IRQ */
+#define CSR_IRQ_CL_F BIT_1 /* Clear EOF IRQ */
+#define CSR_IRQ_CL_C BIT_0 /* Clear ERR IRQ */
+
+#define CSR_SET_RESET (CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+ CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+ CSR_TRANS_RST)
+#define CSR_CLR_RESET (CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+ CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\
+ CSR_TRANS_RUN)
+
+/* Q_F 32 bit Flag Register */
+ /* Bit 31..28: reserved */
+#define F_ALM_FULL BIT_27 /* Rx FIFO: almost full */
+#define F_EMPTY BIT_27 /* Tx FIFO: empty flag */
+#define F_FIFO_EOF BIT_26 /* Tag (EOF Flag) bit in FIFO */
+#define F_WM_REACHED BIT_25 /* Watermark reached */
+ /* reserved */
+#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 23..16: # of Qwords in FIFO */
+ /* Bit 15..11: reserved */
+#define F_WATER_MARK 0x0007ffL /* Bit 10.. 0: Watermark */
+
+/* Q_T1 32 bit Test Register 1 */
+/* Holds four State Machine control Bytes */
+#define SM_CTRL_SV_MSK (0xffL<<24) /* Bit 31..24: Control Supervisor SM */
+#define SM_CTRL_RD_MSK (0xffL<<16) /* Bit 23..16: Control Read Desc SM */
+#define SM_CTRL_WR_MSK (0xffL<<8) /* Bit 15.. 8: Control Write Desc SM */
+#define SM_CTRL_TR_MSK 0xffL /* Bit 7.. 0: Control Transfer SM */
+
+/* Q_T1_TR 8 bit Test Register 1 Transfer SM */
+/* Q_T1_WR 8 bit Test Register 1 Write Descriptor SM */
+/* Q_T1_RD 8 bit Test Register 1 Read Descriptor SM */
+/* Q_T1_SV 8 bit Test Register 1 Supervisor SM */
+
+/* The control status byte of each machine looks like ... */
+#define SM_STATE 0xf0 /* Bit 7.. 4: State which shall be loaded */
+#define SM_LOAD BIT_3S /* Load the SM with SM_STATE */
+#define SM_TEST_ON BIT_2S /* Switch on SM Test Mode */
+#define SM_TEST_OFF BIT_1S /* Go off the Test Mode */
+#define SM_STEP BIT_0S /* Step the State Machine */
+/* The encoding of the states is not supported by the Diagnostics Tool */
+
+/* Q_T2 32 bit Test Register 2 */
+ /* Bit 31.. 8: reserved */
+#define T2_AC_T_ON BIT_7 /* Address Counter Test Mode on */
+#define T2_AC_T_OFF BIT_6 /* Address Counter Test Mode off */
+#define T2_BC_T_ON BIT_5 /* Byte Counter Test Mode on */
+#define T2_BC_T_OFF BIT_4 /* Byte Counter Test Mode off */
+#define T2_STEP04 BIT_3 /* Inc AC/Dec BC by 4 */
+#define T2_STEP03 BIT_2 /* Inc AC/Dec BC by 3 */
+#define T2_STEP02 BIT_1 /* Inc AC/Dec BC by 2 */
+#define T2_STEP01 BIT_0 /* Inc AC/Dec BC by 1 */
+
+/* Q_T3 32 bit Test Register 3 */
+ /* Bit 31.. 7: reserved */
+#define T3_MUX_MSK (7<<4) /* Bit 6.. 4: Mux Position */
+ /* Bit 3: reserved */
+#define T3_VRAM_MSK 7 /* Bit 2.. 0: Virtual RAM Buffer Address */
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/* RB_START 32 bit RAM Buffer Start Address */
+/* RB_END 32 bit RAM Buffer End Address */
+/* RB_WP 32 bit RAM Buffer Write Pointer */
+/* RB_RP 32 bit RAM Buffer Read Pointer */
+/* RB_RX_UTPP 32 bit Rx Upper Threshold, Pause Pack */
+/* RB_RX_LTPP 32 bit Rx Lower Threshold, Pause Pack */
+/* RB_RX_UTHP 32 bit Rx Upper Threshold, High Prio */
+/* RB_RX_LTHP 32 bit Rx Lower Threshold, High Prio */
+/* RB_PC 32 bit RAM Buffer Packet Counter */
+/* RB_LEV 32 bit RAM Buffer Level Register */
+ /* Bit 31..19: reserved */
+#define RB_MSK 0x0007ffff /* Bit 18.. 0: RAM Buffer Pointer Bits */
+
+/* RB_TST2 8 bit RAM Buffer Test Register 2 */
+ /* Bit 7.. 4: reserved */
+#define RB_PC_DEC BIT_3S /* Packet Counter Decrem */
+#define RB_PC_T_ON BIT_2S /* Packet Counter Test On */
+#define RB_PC_T_OFF BIT_1S /* Packet Counter Tst Off */
+#define RB_PC_INC BIT_0S /* Packet Counter Increm */
+
+/* RB_TST1 8 bit RAM Buffer Test Register 1 */
+ /* Bit 7: reserved */
+#define RB_WP_T_ON BIT_6S /* Write Pointer Test On */
+#define RB_WP_T_OFF BIT_5S /* Write Pointer Test Off */
+#define RB_WP_INC BIT_4S /* Write Pointer Increm */
+ /* Bit 3: reserved */
+#define RB_RP_T_ON BIT_2S /* Read Pointer Test On */
+#define RB_RP_T_OFF BIT_1S /* Read Pointer Test Off */
+#define RB_RP_DEC BIT_0S /* Read Pointer Decrement */
+
+/* RB_CTRL 8 bit RAM Buffer Control Register */
+ /* Bit 7.. 6: reserved */
+#define RB_ENA_STFWD BIT_5S /* Enable Store & Forward */
+#define RB_DIS_STFWD BIT_4S /* Disable Store & Forward */
+#define RB_ENA_OP_MD BIT_3S /* Enable Operation Mode */
+#define RB_DIS_OP_MD BIT_2S /* Disable Operation Mode */
+#define RB_RST_CLR BIT_1S /* Clear RAM Buf STM Reset */
+#define RB_RST_SET BIT_0S /* Set RAM Buf STM Reset */
+
+
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
+
+/* RX_MFF_EA 32 bit Receive MAC FIFO End Address */
+/* RX_MFF_WP 32 bit Receive MAC FIFO Write Pointer */
+/* RX_MFF_RP 32 bit Receive MAC FIFO Read Pointer */
+/* RX_MFF_PC 32 bit Receive MAC FIFO Packet Counter */
+/* RX_MFF_LEV 32 bit Receive MAC FIFO Level */
+/* TX_MFF_EA 32 bit Transmit MAC FIFO End Address */
+/* TX_MFF_WP 32 bit Transmit MAC FIFO Write Pointer */
+/* TX_MFF_WSP 32 bit Transmit MAC FIFO WR Shadow Pointer */
+/* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */
+/* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */
+/* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */
+ /* Bit 31.. 6: reserved */
+#define MFF_MSK 0x007fL /* Bit 5.. 0: MAC FIFO Address/Ptr Bits */
+
+/* RX_MFF_CTRL1 16 bit Receive MAC FIFO Control Reg 1 */
+ /* Bit 15..14: reserved */
+#define MFF_ENA_RDY_PAT BIT_13S /* Enable Ready Patch */
+#define MFF_DIS_RDY_PAT BIT_12S /* Disable Ready Patch */
+#define MFF_ENA_TIM_PAT BIT_11S /* Enable Timing Patch */
+#define MFF_DIS_TIM_PAT BIT_10S /* Disable Timing Patch */
+#define MFF_ENA_ALM_FUL BIT_9S /* Enable AlmostFull Sign */
+#define MFF_DIS_ALM_FUL BIT_8S /* Disable AlmostFull Sign */
+#define MFF_ENA_PAUSE BIT_7S /* Enable Pause Signaling */
+#define MFF_DIS_PAUSE BIT_6S /* Disable Pause Signaling */
+#define MFF_ENA_FLUSH BIT_5S /* Enable Frame Flushing */
+#define MFF_DIS_FLUSH BIT_4S /* Disable Frame Flushing */
+#define MFF_ENA_TIST BIT_3S /* Enable Time Stamp Gener */
+#define MFF_DIS_TIST BIT_2S /* Disable Time Stamp Gener */
+#define MFF_CLR_INTIST BIT_1S /* Clear IRQ No Time Stamp */
+#define MFF_CLR_INSTAT BIT_0S /* Clear IRQ No Status */
+
+#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
+
+/* TX_MFF_CTRL1 16 bit Transmit MAC FIFO Control Reg 1 */
+#define MFF_CLR_PERR BIT_15S /* Clear Parity Error IRQ */
+ /* Bit 14: reserved */
+#define MFF_ENA_PKT_REC BIT_13S /* Enable Packet Recovery */
+#define MFF_DIS_PKT_REC BIT_12S /* Disable Packet Recovery */
+/* MFF_ENA_TIM_PAT (see RX_MFF_CTRL1) Bit 11: Enable Timing Patch */
+/* MFF_DIS_TIM_PAT (see RX_MFF_CTRL1) Bit 10: Disable Timing Patch */
+/* MFF_ENA_ALM_FUL (see RX_MFF_CTRL1) Bit 9: Enable Almost Full Sign */
+/* MFF_DIS_ALM_FUL (see RX_MFF_CTRL1) Bit 8: Disable Almost Full Sign */
+#define MFF_ENA_W4E BIT_7S /* Enable Wait for Empty */
+#define MFF_DIS_W4E BIT_6S /* Disable Wait for Empty */
+/* MFF_ENA_FLUSH (see RX_MFF_CTRL1) Bit 5: Enable Frame Flushing */
+/* MFF_DIS_FLUSH (see RX_MFF_CTRL1) Bit 4: Disable Frame Flushing */
+#define MFF_ENA_LOOPB BIT_3S /* Enable Loopback */
+#define MFF_DIS_LOOPB BIT_2S /* Disable Loopback */
+#define MFF_CLR_MAC_RST BIT_1S /* Clear XMAC Reset */
+#define MFF_SET_MAC_RST BIT_0S /* Set XMAC Reset */
+
+#define MFF_TX_CTRL_DEF (MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
+
+/* RX_MFF_TST2 8 bit Receive MAC FIFO Test Register 2 */
+/* TX_MFF_TST2 8 bit Transmit MAC FIFO Test Register 2 */
+ /* Bit 7: reserved */
+#define MFF_WSP_T_ON BIT_6S /* Tx: Write Shadow Ptr TestOn */
+#define MFF_WSP_T_OFF BIT_5S /* Tx: Write Shadow Ptr TstOff */
+#define MFF_WSP_INC BIT_4S /* Tx: Write Shadow Ptr Increment */
+#define MFF_PC_DEC BIT_3S /* Packet Counter Decrement */
+#define MFF_PC_T_ON BIT_2S /* Packet Counter Test On */
+#define MFF_PC_T_OFF BIT_1S /* Packet Counter Test Off */
+#define MFF_PC_INC BIT_0S /* Packet Counter Increment */
+
+/* RX_MFF_TST1 8 bit Receive MAC FIFO Test Register 1 */
+/* TX_MFF_TST1 8 bit Transmit MAC FIFO Test Register 1 */
+ /* Bit 7: reserved */
+#define MFF_WP_T_ON BIT_6S /* Write Pointer Test On */
+#define MFF_WP_T_OFF BIT_5S /* Write Pointer Test Off */
+#define MFF_WP_INC BIT_4S /* Write Pointer Increm */
+ /* Bit 3: reserved */
+#define MFF_RP_T_ON BIT_2S /* Read Pointer Test On */
+#define MFF_RP_T_OFF BIT_1S /* Read Pointer Test Off */
+#define MFF_RP_DEC BIT_0S /* Read Pointer Decrement */
+
+/* RX_MFF_CTRL2 8 bit Receive MAC FIFO Control Reg 2 */
+/* TX_MFF_CTRL2 8 bit Transmit MAC FIFO Control Reg 2 */
+ /* Bit 7..4: reserved */
+#define MFF_ENA_OP_MD BIT_3S /* Enable Operation Mode */
+#define MFF_DIS_OP_MD BIT_2S /* Disable Operation Mode */
+#define MFF_RST_CLR BIT_1S /* Clear MAC FIFO Reset */
+#define MFF_RST_SET BIT_0S /* Set MAC FIFO Reset */
+
+
+/* Link LED Counter Registers (GENESIS only) */
+
+/* RX_LED_CTRL 8 bit Receive LED Cnt Control Reg */
+/* TX_LED_CTRL 8 bit Transmit LED Cnt Control Reg */
+/* LNK_SYNC_CTRL 8 bit Link Sync Cnt Control Register */
+ /* Bit 7.. 3: reserved */
+#define LED_START BIT_2S /* Start Timer */
+#define LED_STOP BIT_1S /* Stop Timer */
+#define LED_STATE BIT_0S /* Rx/Tx: LED State, 1=LED on */
+#define LED_CLR_IRQ BIT_0S /* Lnk: Clear Link IRQ */
+
+/* RX_LED_TST 8 bit Receive LED Cnt Test Register */
+/* TX_LED_TST 8 bit Transmit LED Cnt Test Register */
+/* LNK_SYNC_TST 8 bit Link Sync Cnt Test Register */
+ /* Bit 7.. 3: reserved */
+#define LED_T_ON BIT_2S /* LED Counter Test mode On */
+#define LED_T_OFF BIT_1S /* LED Counter Test mode Off */
+#define LED_T_STEP BIT_0S /* LED Counter Step */
+
+/* LNK_LED_REG 8 bit Link LED Register */
+ /* Bit 7.. 6: reserved */
+#define LED_BLK_ON BIT_5S /* Link LED Blinking On */
+#define LED_BLK_OFF BIT_4S /* Link LED Blinking Off */
+#define LED_SYNC_ON BIT_3S /* Use Sync Wire to switch LED */
+#define LED_SYNC_OFF BIT_2S /* Disable Sync Wire Input */
+#define LED_ON BIT_1S /* switch LED on */
+#define LED_OFF BIT_0S /* switch LED off */
+
+/* Receive and Transmit GMAC FIFO Registers (YUKON only) */
+
+/* RX_GMF_EA 32 bit Rx GMAC FIFO End Address */
+/* RX_GMF_AF_THR 32 bit Rx GMAC FIFO Almost Full Thresh. */
+/* RX_GMF_WP 32 bit Rx GMAC FIFO Write Pointer */
+/* RX_GMF_WLEV 32 bit Rx GMAC FIFO Write Level */
+/* RX_GMF_RP 32 bit Rx GMAC FIFO Read Pointer */
+/* RX_GMF_RLEV 32 bit Rx GMAC FIFO Read Level */
+/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */
+/* TX_GMF_AE_THR 32 bit Tx GMAC FIFO Almost Empty Thresh.*/
+/* TX_GMF_WP 32 bit Tx GMAC FIFO Write Pointer */
+/* TX_GMF_WSP 32 bit Tx GMAC FIFO Write Shadow Ptr. */
+/* TX_GMF_WLEV 32 bit Tx GMAC FIFO Write Level */
+/* TX_GMF_RP 32 bit Tx GMAC FIFO Read Pointer */
+/* TX_GMF_RSTP 32 bit Tx GMAC FIFO Restart Pointer */
+/* TX_GMF_RLEV 32 bit Tx GMAC FIFO Read Level */
+
+/* RX_GMF_CTRL_T 32 bit Rx GMAC FIFO Control/Test */
+ /* Bits 31..15: reserved */
+#define GMF_WP_TST_ON BIT_14 /* Write Pointer Test On */
+#define GMF_WP_TST_OFF BIT_13 /* Write Pointer Test Off */
+#define GMF_WP_STEP BIT_12 /* Write Pointer Step/Increment */
+ /* Bit 11: reserved */
+#define GMF_RP_TST_ON BIT_10 /* Read Pointer Test On */
+#define GMF_RP_TST_OFF BIT_9 /* Read Pointer Test Off */
+#define GMF_RP_STEP BIT_8 /* Read Pointer Step/Increment */
+#define GMF_RX_F_FL_ON BIT_7 /* Rx FIFO Flush Mode On */
+#define GMF_RX_F_FL_OFF BIT_6 /* Rx FIFO Flush Mode Off */
+#define GMF_CLI_RX_FO BIT_5 /* Clear IRQ Rx FIFO Overrun */
+#define GMF_CLI_RX_FC BIT_4 /* Clear IRQ Rx Frame Complete */
+#define GMF_OPER_ON BIT_3 /* Operational Mode On */
+#define GMF_OPER_OFF BIT_2 /* Operational Mode Off */
+#define GMF_RST_CLR BIT_1 /* Clear GMAC FIFO Reset */
+#define GMF_RST_SET BIT_0 /* Set GMAC FIFO Reset */
+
+/* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */
+ /* Bits 31..19: reserved */
+#define GMF_WSP_TST_ON BIT_18 /* Write Shadow Pointer Test On */
+#define GMF_WSP_TST_OFF BIT_17 /* Write Shadow Pointer Test Off */
+#define GMF_WSP_STEP BIT_16 /* Write Shadow Pointer Step/Increment */
+ /* Bits 15..7: same as for RX_GMF_CTRL_T */
+#define GMF_CLI_TX_FU BIT_6 /* Clear IRQ Tx FIFO Underrun */
+#define GMF_CLI_TX_FC BIT_5 /* Clear IRQ Tx Frame Complete */
+#define GMF_CLI_TX_PE BIT_4 /* Clear IRQ Tx Parity Error */
+ /* Bits 3..0: same as for RX_GMF_CTRL_T */
+
+#define GMF_RX_CTRL_DEF (GMF_OPER_ON | GMF_RX_F_FL_ON)
+#define GMF_TX_CTRL_DEF GMF_OPER_ON
+
+#define RX_GMF_FL_THR_DEF 0x0a /* Rx GMAC FIFO Flush Threshold default */
+
+/* GMAC_TI_ST_CTRL 8 bit Time Stamp Timer Ctrl Reg (YUKON only) */
+ /* Bit 7.. 3: reserved */
+#define GMT_ST_START BIT_2S /* Start Time Stamp Timer */
+#define GMT_ST_STOP BIT_1S /* Stop Time Stamp Timer */
+#define GMT_ST_CLR_IRQ BIT_0S /* Clear Time Stamp Timer IRQ */
+
+/* GMAC_CTRL 32 bit GMAC Control Reg (YUKON only) */
+ /* Bits 31.. 8: reserved */
+#define GMC_H_BURST_ON BIT_7 /* Half Duplex Burst Mode On */
+#define GMC_H_BURST_OFF BIT_6 /* Half Duplex Burst Mode Off */
+#define GMC_F_LOOPB_ON BIT_5 /* FIFO Loopback On */
+#define GMC_F_LOOPB_OFF BIT_4 /* FIFO Loopback Off */
+#define GMC_PAUSE_ON BIT_3 /* Pause On */
+#define GMC_PAUSE_OFF BIT_2 /* Pause Off */
+#define GMC_RST_CLR BIT_1 /* Clear GMAC Reset */
+#define GMC_RST_SET BIT_0 /* Set GMAC Reset */
+
+/* GPHY_CTRL 32 bit GPHY Control Reg (YUKON only) */
+ /* Bits 31..29: reserved */
+#define GPC_SEL_BDT BIT_28 /* Select Bi-Dir. Transfer for MDC/MDIO */
+#define GPC_INT_POL_HI BIT_27 /* IRQ Polarity is Active HIGH */
+#define GPC_75_OHM BIT_26 /* Use 75 Ohm Termination instead of 50 */
+#define GPC_DIS_FC BIT_25 /* Disable Automatic Fiber/Copper Detection */
+#define GPC_DIS_SLEEP BIT_24 /* Disable Energy Detect */
+#define GPC_HWCFG_M_3 BIT_23 /* HWCFG_MODE[3] */
+#define GPC_HWCFG_M_2 BIT_22 /* HWCFG_MODE[2] */
+#define GPC_HWCFG_M_1 BIT_21 /* HWCFG_MODE[1] */
+#define GPC_HWCFG_M_0 BIT_20 /* HWCFG_MODE[0] */
+#define GPC_ANEG_0 BIT_19 /* ANEG[0] */
+#define GPC_ENA_XC BIT_18 /* Enable MDI crossover */
+#define GPC_DIS_125 BIT_17 /* Disable 125 MHz clock */
+#define GPC_ANEG_3 BIT_16 /* ANEG[3] */
+#define GPC_ANEG_2 BIT_15 /* ANEG[2] */
+#define GPC_ANEG_1 BIT_14 /* ANEG[1] */
+#define GPC_ENA_PAUSE BIT_13 /* Enable Pause (SYM_OR_REM) */
+#define GPC_PHYADDR_4 BIT_12 /* Bit 4 of Phy Addr */
+#define GPC_PHYADDR_3 BIT_11 /* Bit 3 of Phy Addr */
+#define GPC_PHYADDR_2 BIT_10 /* Bit 2 of Phy Addr */
+#define GPC_PHYADDR_1 BIT_9 /* Bit 1 of Phy Addr */
+#define GPC_PHYADDR_0 BIT_8 /* Bit 0 of Phy Addr */
+ /* Bits 7..2: reserved */
+#define GPC_RST_CLR BIT_1 /* Clear GPHY Reset */
+#define GPC_RST_SET BIT_0 /* Set GPHY Reset */
+
+#define GPC_HWCFG_GMII_COP (GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | \
+ GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_HWCFG_GMII_FIB ( GPC_HWCFG_M_2 | \
+ GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_ANEG_ADV_ALL_M (GPC_ANEG_3 | GPC_ANEG_2 | \
+ GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF 0
+#define GPC_FRC10MBIT_FULL GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL (GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF GPC_ANEG_2
+#define GPC_ADV_1000_FULL GPC_ANEG_3
+#define GPC_ADV_ALL (GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER 0
+#define GPC_FORCE_SLAVE GPC_ANEG_0
+#define GPC_PREF_MASTER GPC_ANEG_1
+#define GPC_PREF_SLAVE (GPC_ANEG_1 | GPC_ANEG_0)
+
+/* GMAC_IRQ_SRC 8 bit GMAC Interrupt Source Reg (YUKON only) */
+/* GMAC_IRQ_MSK 8 bit GMAC Interrupt Mask Reg (YUKON only) */
+#define GM_IS_TX_CO_OV BIT_5 /* Transmit Counter Overflow IRQ */
+#define GM_IS_RX_CO_OV BIT_4 /* Receive Counter Overflow IRQ */
+#define GM_IS_TX_FF_UR BIT_3 /* Transmit FIFO Underrun */
+#define GM_IS_TX_COMPL BIT_2 /* Frame Transmission Complete */
+#define GM_IS_RX_FF_OR BIT_1 /* Receive FIFO Overrun */
+#define GM_IS_RX_COMPL BIT_0 /* Frame Reception Complete */
+
+#define GMAC_DEF_MSK (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \
+ GM_IS_TX_FF_UR)
+
+/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */
+ /* Bits 15.. 2: reserved */
+#define GMLC_RST_CLR BIT_1S /* Clear GMAC Link Reset */
+#define GMLC_RST_SET BIT_0S /* Set GMAC Link Reset */
+
+
+/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */
+#define WOL_CTL_LINK_CHG_OCC BIT_15S
+#define WOL_CTL_MAGIC_PKT_OCC BIT_14S
+#define WOL_CTL_PATTERN_OCC BIT_13S
+
+#define WOL_CTL_CLEAR_RESULT BIT_12S
+
+#define WOL_CTL_ENA_PME_ON_LINK_CHG BIT_11S
+#define WOL_CTL_DIS_PME_ON_LINK_CHG BIT_10S
+#define WOL_CTL_ENA_PME_ON_MAGIC_PKT BIT_9S
+#define WOL_CTL_DIS_PME_ON_MAGIC_PKT BIT_8S
+#define WOL_CTL_ENA_PME_ON_PATTERN BIT_7S
+#define WOL_CTL_DIS_PME_ON_PATTERN BIT_6S
+
+#define WOL_CTL_ENA_LINK_CHG_UNIT BIT_5S
+#define WOL_CTL_DIS_LINK_CHG_UNIT BIT_4S
+#define WOL_CTL_ENA_MAGIC_PKT_UNIT BIT_3S
+#define WOL_CTL_DIS_MAGIC_PKT_UNIT BIT_2S
+#define WOL_CTL_ENA_PATTERN_UNIT BIT_1S
+#define WOL_CTL_DIS_PATTERN_UNIT BIT_0S
+
+#define WOL_CTL_DEFAULT \
+ (WOL_CTL_DIS_PME_ON_LINK_CHG | \
+ WOL_CTL_DIS_PME_ON_PATTERN | \
+ WOL_CTL_DIS_PME_ON_MAGIC_PKT | \
+ WOL_CTL_DIS_LINK_CHG_UNIT | \
+ WOL_CTL_DIS_PATTERN_UNIT | \
+ WOL_CTL_DIS_MAGIC_PKT_UNIT)
+
+/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x) (BIT_0 << (x))
+
+#define SK_NUM_WOL_PATTERN 7
+#define SK_PATTERN_PER_WORD 4
+#define SK_BITMASK_PATTERN 7
+#define SK_POW_PATTERN_LENGTH 128
+
+#define WOL_LENGTH_MSK 0x7f
+#define WOL_LENGTH_SHIFT 8
+
+
+/* Receive and Transmit Descriptors ******************************************/
+
+/* Transmit Descriptor struct */
+typedef struct s_HwTxd {
+ SK_U32 volatile TxCtrl; /* Transmit Buffer Control Field */
+ SK_U32 TxNext; /* Physical Address Pointer to the next TxD */
+ SK_U32 TxAdrLo; /* Physical Tx Buffer Address lower dword */
+ SK_U32 TxAdrHi; /* Physical Tx Buffer Address upper dword */
+ SK_U32 TxStat; /* Transmit Frame Status Word */
+#ifndef SK_USE_REV_DESC
+ SK_U16 TxTcpOffs; /* TCP Checksum Calculation Start Value */
+ SK_U16 TxRes1; /* 16 bit reserved field */
+ SK_U16 TxTcpWp; /* TCP Checksum Write Position */
+ SK_U16 TxTcpSp; /* TCP Checksum Calculation Start Position */
+#else /* SK_USE_REV_DESC */
+ SK_U16 TxRes1; /* 16 bit reserved field */
+ SK_U16 TxTcpOffs; /* TCP Checksum Calculation Start Value */
+ SK_U16 TxTcpSp; /* TCP Checksum Calculation Start Position */
+ SK_U16 TxTcpWp; /* TCP Checksum Write Position */
+#endif /* SK_USE_REV_DESC */
+ SK_U32 TxRes2; /* 32 bit reserved field */
+} SK_HWTXD;
+
+/* Receive Descriptor struct */
+typedef struct s_HwRxd {
+ SK_U32 volatile RxCtrl; /* Receive Buffer Control Field */
+ SK_U32 RxNext; /* Physical Address Pointer to the next RxD */
+ SK_U32 RxAdrLo; /* Physical Rx Buffer Address lower dword */
+ SK_U32 RxAdrHi; /* Physical Rx Buffer Address upper dword */
+ SK_U32 RxStat; /* Receive Frame Status Word */
+ SK_U32 RxTiSt; /* Receive Time Stamp (from XMAC on GENESIS) */
+#ifndef SK_USE_REV_DESC
+ SK_U16 RxTcpSum1; /* TCP Checksum 1 */
+ SK_U16 RxTcpSum2; /* TCP Checksum 2 */
+ SK_U16 RxTcpSp1; /* TCP Checksum Calculation Start Position 1 */
+ SK_U16 RxTcpSp2; /* TCP Checksum Calculation Start Position 2 */
+#else /* SK_USE_REV_DESC */
+ SK_U16 RxTcpSum2; /* TCP Checksum 2 */
+ SK_U16 RxTcpSum1; /* TCP Checksum 1 */
+ SK_U16 RxTcpSp2; /* TCP Checksum Calculation Start Position 2 */
+ SK_U16 RxTcpSp1; /* TCP Checksum Calculation Start Position 1 */
+#endif /* SK_USE_REV_DESC */
+} SK_HWRXD;
+
+/*
+ * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2)
+ * should set the define SK_USE_REV_DESC.
+ * Structures are 'normaly' not endianess dependent. But in
+ * this case the SK_U16 fields are bound to bit positions inside the
+ * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord.
+ * The bit positions inside a DWord are of course endianess dependent and
+ * swaps if the DWord is swapped by the hardware.
+ */
+
+
+/* Descriptor Bit Definition */
+/* TxCtrl Transmit Buffer Control Field */
+/* RxCtrl Receive Buffer Control Field */
+#define BMU_OWN BIT_31 /* OWN bit: 0=host/1=BMU */
+#define BMU_STF BIT_30 /* Start of Frame */
+#define BMU_EOF BIT_29 /* End of Frame */
+#define BMU_IRQ_EOB BIT_28 /* Req "End of Buffer" IRQ */
+#define BMU_IRQ_EOF BIT_27 /* Req "End of Frame" IRQ */
+/* TxCtrl specific bits */
+#define BMU_STFWD BIT_26 /* (Tx) Store & Forward Frame */
+#define BMU_NO_FCS BIT_25 /* (Tx) Disable MAC FCS (CRC) generation */
+#define BMU_SW BIT_24 /* (Tx) 1 bit res. for SW use */
+/* RxCtrl specific bits */
+#define BMU_DEV_0 BIT_26 /* (Rx) Transfer data to Dev0 */
+#define BMU_STAT_VAL BIT_25 /* (Rx) Rx Status Valid */
+#define BMU_TIST_VAL BIT_24 /* (Rx) Rx TimeStamp Valid */
+ /* Bit 23..16: BMU Check Opcodes */
+#define BMU_CHECK (0x55L<<16) /* Default BMU check */
+#define BMU_TCP_CHECK (0x56L<<16) /* Descr with TCP ext */
+#define BMU_UDP_CHECK (0x57L<<16) /* Descr with UDP ext (YUKON only) */
+#define BMU_BBC 0xffffL /* Bit 15.. 0: Buffer Byte Counter */
+
+/* TxStat Transmit Frame Status Word */
+/* RxStat Receive Frame Status Word */
+/*
+ *Note: TxStat is reserved for ASIC loopback mode only
+ *
+ * The Bits of the Status words are defined in xmac_ii.h
+ * (see XMR_FS bits)
+ */
+
+/* macros ********************************************************************/
+
+/* Receive and Transmit Queues */
+#define Q_R1 0x0000 /* Receive Queue 1 */
+#define Q_R2 0x0080 /* Receive Queue 2 */
+#define Q_XS1 0x0200 /* Synchronous Transmit Queue 1 */
+#define Q_XA1 0x0280 /* Asynchronous Transmit Queue 1 */
+#define Q_XS2 0x0300 /* Synchronous Transmit Queue 2 */
+#define Q_XA2 0x0380 /* Asynchronous Transmit Queue 2 */
+
+/*
+ * Macro Q_ADDR()
+ *
+ * Use this macro to access the Receive and Transmit Queue Registers.
+ *
+ * para:
+ * Queue Queue to access.
+ * Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ * Offs Queue register offset.
+ * Values: Q_D, Q_DA_L ... Q_T2, Q_T3
+ *
+ * usage SK_IN32(pAC, Q_ADDR(Q_R2, Q_BC), pVal)
+ */
+#define Q_ADDR(Queue, Offs) (B8_Q_REGS + (Queue) + (Offs))
+
+/*
+ * Macro RB_ADDR()
+ *
+ * Use this macro to access the RAM Buffer Registers.
+ *
+ * para:
+ * Queue Queue to access.
+ * Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ * Offs Queue register offset.
+ * Values: RB_START, RB_END ... RB_LEV, RB_CTRL
+ *
+ * usage SK_IN32(pAC, RB_ADDR(Q_R2, RB_RP), pVal)
+ */
+#define RB_ADDR(Queue, Offs) (B16_RAM_REGS + (Queue) + (Offs))
+
+
+/* MAC Related Registers */
+#define MAC_1 0 /* belongs to the port near the slot */
+#define MAC_2 1 /* belongs to the port far away from the slot */
+
+/*
+ * Macro MR_ADDR()
+ *
+ * Use this macro to access a MAC Related Registers inside the ASIC.
+ *
+ * para:
+ * Mac MAC to access.
+ * Values: MAC_1, MAC_2
+ * Offs MAC register offset.
+ * Values: RX_MFF_EA, RX_MFF_WP ... LNK_LED_REG,
+ * TX_MFF_EA, TX_MFF_WP ... TX_LED_TST
+ *
+ * usage SK_IN32(pAC, MR_ADDR(MAC_1, TX_MFF_EA), pVal)
+ */
+#define MR_ADDR(Mac, Offs) (((Mac) << 7) + (Offs))
+
+#ifdef SK_LITTLE_ENDIAN
+#define XM_WORD_LO 0
+#define XM_WORD_HI 1
+#else /* !SK_LITTLE_ENDIAN */
+#define XM_WORD_LO 1
+#define XM_WORD_HI 0
+#endif /* !SK_LITTLE_ENDIAN */
+
+
+/*
+ * macros to access the XMAC (GENESIS only)
+ *
+ * XM_IN16(), to read a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_OUT16(), to write a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_IN32(), to read a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_OUT32(), to write a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_INADDR(), to read a network address register (e.g. XM_SRC_CHK)
+ * XM_OUTADDR(), to write a network address register (e.g. XM_SRC_CHK)
+ * XM_INHASH(), to read the XM_HSM_CHK register
+ * XM_OUTHASH() to write the XM_HSM_CHK register
+ *
+ * para:
+ * Mac XMAC to access values: MAC_1 or MAC_2
+ * IoC I/O context needed for SK I/O macros
+ * Reg XMAC Register to read or write
+ * (p)Val Value or pointer to the value which should be read or written
+ *
+ * usage: XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value);
+ */
+
+#define XMA(Mac, Reg) \
+ ((BASE_XMAC_1 + (Mac) * (BASE_XMAC_2 - BASE_XMAC_1)) | ((Reg) << 1))
+
+#define XM_IN16(IoC, Mac, Reg, pVal) \
+ SK_IN16((IoC), XMA((Mac), (Reg)), (pVal))
+
+#define XM_OUT16(IoC, Mac, Reg, Val) \
+ SK_OUT16((IoC), XMA((Mac), (Reg)), (Val))
+
+#define XM_IN32(IoC, Mac, Reg, pVal) { \
+ SK_IN16((IoC), XMA((Mac), (Reg)), \
+ (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]); \
+ SK_IN16((IoC), XMA((Mac), (Reg+2)), \
+ (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]); \
+}
+
+#define XM_OUT32(IoC, Mac, Reg, Val) { \
+ SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL)); \
+ SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+/* Remember: we are always writing to / reading from LITTLE ENDIAN memory */
+
+#define XM_INADDR(IoC, Mac, Reg, pVal) { \
+ SK_U16 Word; \
+ SK_U8 *pByte; \
+ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \
+ SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \
+ pByte[0] = (SK_U8)(Word & 0x00ff); \
+ pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \
+ pByte[2] = (SK_U8)(Word & 0x00ff); \
+ pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \
+ pByte[4] = (SK_U8)(Word & 0x00ff); \
+ pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \
+}
+
+#define XM_OUTADDR(IoC, Mac, Reg, pVal) { \
+ SK_U8 SK_FAR *pByte; \
+ pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \
+ SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \
+ (((SK_U16)(pByte[0]) & 0x00ff) | \
+ (((SK_U16)(pByte[1]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \
+ (((SK_U16)(pByte[2]) & 0x00ff) | \
+ (((SK_U16)(pByte[3]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \
+ (((SK_U16)(pByte[4]) & 0x00ff) | \
+ (((SK_U16)(pByte[5]) << 8) & 0xff00))); \
+}
+
+#define XM_INHASH(IoC, Mac, Reg, pVal) { \
+ SK_U16 Word; \
+ SK_U8 SK_FAR *pByte; \
+ pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \
+ SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \
+ pByte[0] = (SK_U8)(Word & 0x00ff); \
+ pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \
+ pByte[2] = (SK_U8)(Word & 0x00ff); \
+ pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \
+ pByte[4] = (SK_U8)(Word & 0x00ff); \
+ pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word); \
+ pByte[6] = (SK_U8)(Word & 0x00ff); \
+ pByte[7] = (SK_U8)((Word >> 8) & 0x00ff); \
+}
+
+#define XM_OUTHASH(IoC, Mac, Reg, pVal) { \
+ SK_U8 SK_FAR *pByte; \
+ pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \
+ SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \
+ (((SK_U16)(pByte[0]) & 0x00ff)| \
+ (((SK_U16)(pByte[1]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \
+ (((SK_U16)(pByte[2]) & 0x00ff)| \
+ (((SK_U16)(pByte[3]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \
+ (((SK_U16)(pByte[4]) & 0x00ff)| \
+ (((SK_U16)(pByte[5]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16) \
+ (((SK_U16)(pByte[6]) & 0x00ff)| \
+ (((SK_U16)(pByte[7]) << 8) & 0xff00))); \
+}
+
+/*
+ * macros to access the GMAC (YUKON only)
+ *
+ * GM_IN16(), to read a 16 bit register (e.g. GM_GP_STAT)
+ * GM_OUT16(), to write a 16 bit register (e.g. GM_GP_CTRL)
+ * GM_IN32(), to read a 32 bit register (e.g. GM_)
+ * GM_OUT32(), to write a 32 bit register (e.g. GM_)
+ * GM_INADDR(), to read a network address register (e.g. GM_SRC_ADDR_1L)
+ * GM_OUTADDR(), to write a network address register (e.g. GM_SRC_ADDR_2L)
+ * GM_INHASH(), to read the GM_MC_ADDR_H1 register
+ * GM_OUTHASH() to write the GM_MC_ADDR_H1 register
+ *
+ * para:
+ * Mac GMAC to access values: MAC_1 or MAC_2
+ * IoC I/O context needed for SK I/O macros
+ * Reg GMAC Register to read or write
+ * (p)Val Value or pointer to the value which should be read or written
+ *
+ * usage: GM_OUT16(IoC, MAC_1, GM_GP_CTRL, Value);
+ */
+
+#define GMA(Mac, Reg) \
+ ((BASE_GMAC_1 + (Mac) * (BASE_GMAC_2 - BASE_GMAC_1)) | (Reg))
+
+#define GM_IN16(IoC, Mac, Reg, pVal) \
+ SK_IN16((IoC), GMA((Mac), (Reg)), (pVal))
+
+#define GM_OUT16(IoC, Mac, Reg, Val) \
+ SK_OUT16((IoC), GMA((Mac), (Reg)), (Val))
+
+#define GM_IN32(IoC, Mac, Reg, pVal) { \
+ SK_IN16((IoC), GMA((Mac), (Reg)), \
+ (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]); \
+ SK_IN16((IoC), GMA((Mac), (Reg+4)), \
+ (SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]); \
+}
+
+#define GM_OUT32(IoC, Mac, Reg, Val) { \
+ SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL)); \
+ SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+#define GM_INADDR(IoC, Mac, Reg, pVal) { \
+ SK_U16 Word; \
+ SK_U8 *pByte; \
+ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \
+ SK_IN16((IoC), GMA((Mac), (Reg)), &Word); \
+ pByte[0] = (SK_U8)(Word & 0x00ff); \
+ pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word); \
+ pByte[2] = (SK_U8)(Word & 0x00ff); \
+ pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word); \
+ pByte[4] = (SK_U8)(Word & 0x00ff); \
+ pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \
+}
+
+#define GM_OUTADDR(IoC, Mac, Reg, pVal) { \
+ SK_U8 SK_FAR *pByte; \
+ pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0]; \
+ SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16) \
+ (((SK_U16)(pByte[0]) & 0x00ff) | \
+ (((SK_U16)(pByte[1]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16) \
+ (((SK_U16)(pByte[2]) & 0x00ff) | \
+ (((SK_U16)(pByte[3]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16) \
+ (((SK_U16)(pByte[4]) & 0x00ff) | \
+ (((SK_U16)(pByte[5]) << 8) & 0xff00))); \
+}
+
+#define GM_INHASH(IoC, Mac, Reg, pVal) { \
+ SK_U16 Word; \
+ SK_U8 *pByte; \
+ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \
+ SK_IN16((IoC), GMA((Mac), (Reg)), &Word); \
+ pByte[0] = (SK_U8)(Word & 0x00ff); \
+ pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word); \
+ pByte[2] = (SK_U8)(Word & 0x00ff); \
+ pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word); \
+ pByte[4] = (SK_U8)(Word & 0x00ff); \
+ pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \
+ SK_IN16((IoC), GMA((Mac), (Reg+12)), &Word); \
+ pByte[6] = (SK_U8)(Word & 0x00ff); \
+ pByte[7] = (SK_U8)((Word >> 8) & 0x00ff); \
+}
+
+#define GM_OUTHASH(IoC, Mac, Reg, pVal) { \
+ SK_U8 *pByte; \
+ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \
+ SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16) \
+ (((SK_U16)(pByte[0]) & 0x00ff)| \
+ (((SK_U16)(pByte[1]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16) \
+ (((SK_U16)(pByte[2]) & 0x00ff)| \
+ (((SK_U16)(pByte[3]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16) \
+ (((SK_U16)(pByte[4]) & 0x00ff)| \
+ (((SK_U16)(pByte[5]) << 8) & 0xff00))); \
+ SK_OUT16((IoC), GMA((Mac), (Reg+12)), (SK_U16) \
+ (((SK_U16)(pByte[6]) & 0x00ff)| \
+ (((SK_U16)(pByte[7]) << 8) & 0xff00))); \
+}
+
+/*
+ * Different MAC Types
+ */
+#define SK_MAC_XMAC 0 /* Xaqti XMAC II */
+#define SK_MAC_GMAC 1 /* Marvell GMAC */
+
+/*
+ * Different PHY Types
+ */
+#define SK_PHY_XMAC 0 /* integrated in XMAC II */
+#define SK_PHY_BCOM 1 /* Broadcom BCM5400 */
+#define SK_PHY_LONE 2 /* Level One LXT1000 */
+#define SK_PHY_NAT 3 /* National DP83891 */
+#define SK_PHY_MARV_COPPER 4 /* Marvell 88E1011S */
+#define SK_PHY_MARV_FIBER 5 /* Marvell 88E1011S working on fiber */
+
+/*
+ * PHY addresses (bits 12..8 of PHY address reg)
+ */
+#define PHY_ADDR_XMAC (0<<8)
+#define PHY_ADDR_BCOM (1<<8)
+#define PHY_ADDR_LONE (3<<8)
+#define PHY_ADDR_NAT (0<<8)
+
+/* GPHY address (bits 15..11 of SMI control reg) */
+#define PHY_ADDR_MARV 0
+
+/*
+ * macros to access the PHY
+ *
+ * PHY_READ() read a 16 bit value from the PHY
+ * PHY_WRITE() write a 16 bit value to the PHY
+ *
+ * para:
+ * IoC I/O context needed for SK I/O macros
+ * pPort Pointer to port struct for PhyAddr
+ * Mac XMAC to access values: MAC_1 or MAC_2
+ * PhyReg PHY Register to read or write
+ * (p)Val Value or pointer to the value which should be read or
+ * written.
+ *
+ * usage: PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value);
+ * Warning: a PHY_READ on an uninitialized PHY (PHY still in reset) never
+ * comes back. This is checked in DEBUG mode.
+ */
+#ifndef DEBUG
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \
+ SK_U16 Mmu; \
+ \
+ XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \
+ XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \
+ if ((pPort)->PhyType != SK_PHY_XMAC) { \
+ do { \
+ XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \
+ } while ((Mmu & XM_MMU_PHY_RDY) == 0); \
+ XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \
+ } \
+}
+#else
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \
+ SK_U16 Mmu; \
+ int __i = 0; \
+ \
+ XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \
+ XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \
+ if ((pPort)->PhyType != SK_PHY_XMAC) { \
+ do { \
+ XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \
+ __i++; \
+ if (__i > 100000) { \
+ SK_DBG_PRINTF("*****************************\n"); \
+ SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n"); \
+ SK_DBG_PRINTF("*****************************\n"); \
+ break; \
+ } \
+ } while ((Mmu & XM_MMU_PHY_RDY) == 0); \
+ XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \
+ } \
+}
+#endif /* DEBUG */
+
+#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) { \
+ SK_U16 Mmu; \
+ \
+ if ((pPort)->PhyType != SK_PHY_XMAC) { \
+ do { \
+ XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \
+ } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \
+ } \
+ XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \
+ XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val)); \
+ if ((pPort)->PhyType != SK_PHY_XMAC) { \
+ do { \
+ XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \
+ } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \
+ } \
+}
+
+/*
+ * Macro PCI_C()
+ *
+ * Use this macro to access PCI config register from the I/O space.
+ *
+ * para:
+ * Addr PCI configuration register to access.
+ * Values: PCI_VENDOR_ID ... PCI_VPD_ADR_REG,
+ *
+ * usage SK_IN16(pAC, PCI_C(PCI_VENDOR_ID), pVal);
+ */
+#define PCI_C(Addr) (B7_CFG_SPC + (Addr)) /* PCI Config Space */
+
+/*
+ * Macro SK_HW_ADDR(Base, Addr)
+ *
+ * Calculates the effective HW address
+ *
+ * para:
+ * Base I/O or memory base address
+ * Addr Address offset
+ *
+ * usage: May be used in SK_INxx and SK_OUTxx macros
+ * #define SK_IN8(pAC, Addr, pVal) ...\
+ * *pVal = (SK_U8)inp(SK_HW_ADDR(pAC->Hw.Iop, Addr)))
+ */
+#ifdef SK_MEM_MAPPED_IO
+#define SK_HW_ADDR(Base, Addr) ((Base) + (Addr))
+#else /* SK_MEM_MAPPED_IO */
+#define SK_HW_ADDR(Base, Addr) \
+ ((Base) + (((Addr) & 0x7f) | (((Addr) >> 7 > 0) ? 0x80 : 0)))
+#endif /* SK_MEM_MAPPED_IO */
+
+#define SZ_LONG (sizeof(SK_U32))
+
+/*
+ * Macro SK_HWAC_LINK_LED()
+ *
+ * Use this macro to set the link LED mode.
+ * para:
+ * pAC Pointer to adapter context struct
+ * IoC I/O context needed for SK I/O macros
+ * Port Port number
+ * Mode Mode to set for this LED
+ */
+#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \
+ SK_OUT8(IoC, MR_ADDR(Port, LNK_LED_REG), Mode);
+
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKGEHW_H */
diff --git a/drivers/net/sk98lin/h/skgehwt.h b/drivers/net/sk98lin/h/skgehwt.h
new file mode 100644
index 000000000000..e6b0016a695c
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehwt.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ * Name: skhwt.h
+ * Project: Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version: $Revision: 1.7 $
+ * Date: $Date: 2003/09/16 12:55:08 $
+ * Purpose: Defines for the hardware timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEHWT.H contains all defines and types for the timer functions
+ */
+
+#ifndef _SKGEHWT_H_
+#define _SKGEHWT_H_
+
+/*
+ * SK Hardware Timer
+ * - needed wherever the HWT module is used
+ * - use in Adapters context name pAC->Hwt
+ */
+typedef struct s_Hwt {
+ SK_U32 TStart; /* HWT start */
+ SK_U32 TStop; /* HWT stop */
+ int TActive; /* HWT: flag : active/inactive */
+} SK_HWT;
+
+extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time);
+extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc);
+extern SK_U32 SkHwtRead(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc);
+#endif /* _SKGEHWT_H_ */
diff --git a/drivers/net/sk98lin/h/skgei2c.h b/drivers/net/sk98lin/h/skgei2c.h
new file mode 100644
index 000000000000..d9b6f6d8dfe2
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgei2c.h
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ * Name: skgei2c.h
+ * Project: Gigabit Ethernet Adapters, TWSI-Module
+ * Version: $Revision: 1.25 $
+ * Date: $Date: 2003/10/20 09:06:05 $
+ * Purpose: Special defines for TWSI
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEI2C.H contains all SK-98xx specific defines for the TWSI handling
+ */
+
+#ifndef _INC_SKGEI2C_H_
+#define _INC_SKGEI2C_H_
+
+/*
+ * Macros to access the B2_I2C_CTRL
+ */
+#define SK_I2C_CTL(IoC, flag, dev, dev_size, reg, burst) \
+ SK_OUT32(IoC, B2_I2C_CTRL,\
+ (flag ? 0x80000000UL : 0x0L) | \
+ (((SK_U32)reg << 16) & I2C_ADDR) | \
+ (((SK_U32)dev << 9) & I2C_DEV_SEL) | \
+ (dev_size & I2C_DEV_SIZE) | \
+ ((burst << 4) & I2C_BURST_LEN))
+
+#define SK_I2C_STOP(IoC) { \
+ SK_U32 I2cCtrl; \
+ SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl); \
+ SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP); \
+}
+
+#define SK_I2C_GET_CTL(IoC, pI2cCtrl) SK_IN32(IoC, B2_I2C_CTRL, pI2cCtrl)
+
+/*
+ * Macros to access the TWSI SW Registers
+ */
+#define SK_I2C_SET_BIT(IoC, SetBits) { \
+ SK_U8 OrgBits; \
+ SK_IN8(IoC, B2_I2C_SW, &OrgBits); \
+ SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SK_U8)(SetBits)); \
+}
+
+#define SK_I2C_CLR_BIT(IoC, ClrBits) { \
+ SK_U8 OrgBits; \
+ SK_IN8(IoC, B2_I2C_SW, &OrgBits); \
+ SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~((SK_U8)(ClrBits))); \
+}
+
+#define SK_I2C_GET_SW(IoC, pI2cSw) SK_IN8(IoC, B2_I2C_SW, pI2cSw)
+
+/*
+ * define the possible sensor states
+ */
+#define SK_SEN_IDLE 0 /* Idle: sensor not read */
+#define SK_SEN_VALUE 1 /* Value Read cycle */
+#define SK_SEN_VALEXT 2 /* Extended Value Read cycle */
+
+/*
+ * Conversion factor to convert read Voltage sensor to milli Volt
+ * Conversion factor to convert read Temperature sensor to 10th degree Celsius
+ */
+#define SK_LM80_VT_LSB 22 /* 22mV LSB resolution */
+#define SK_LM80_TEMP_LSB 10 /* 1 degree LSB resolution */
+#define SK_LM80_TEMPEXT_LSB 5 /* 0.5 degree LSB resolution for ext. val. */
+
+/*
+ * formula: counter = (22500*60)/(rpm * divisor * pulses/2)
+ * assuming: 6500rpm, 4 pulses, divisor 1
+ */
+#define SK_LM80_FAN_FAKTOR ((22500L*60)/(1*2))
+
+/*
+ * Define sensor management data
+ * Maximum is reached on Genesis copper dual port and Yukon-64
+ * Board specific maximum is in pAC->I2c.MaxSens
+ */
+#define SK_MAX_SENSORS 8 /* maximal no. of installed sensors */
+#define SK_MIN_SENSORS 5 /* minimal no. of installed sensors */
+
+/*
+ * To watch the state machine (SM) use the timer in two ways
+ * instead of one as hitherto
+ */
+#define SK_TIMER_WATCH_SM 0 /* Watch the SM to finish in a spec. time */
+#define SK_TIMER_NEW_GAUGING 1 /* Start a new gauging when timer expires */
+
+/*
+ * Defines for the individual thresholds
+ */
+
+/* Temperature sensor */
+#define SK_SEN_TEMP_HIGH_ERR 800 /* Temperature High Err Threshold */
+#define SK_SEN_TEMP_HIGH_WARN 700 /* Temperature High Warn Threshold */
+#define SK_SEN_TEMP_LOW_WARN 100 /* Temperature Low Warn Threshold */
+#define SK_SEN_TEMP_LOW_ERR 0 /* Temperature Low Err Threshold */
+
+/* VCC which should be 5 V */
+#define SK_SEN_PCI_5V_HIGH_ERR 5588 /* Voltage PCI High Err Threshold */
+#define SK_SEN_PCI_5V_HIGH_WARN 5346 /* Voltage PCI High Warn Threshold */
+#define SK_SEN_PCI_5V_LOW_WARN 4664 /* Voltage PCI Low Warn Threshold */
+#define SK_SEN_PCI_5V_LOW_ERR 4422 /* Voltage PCI Low Err Threshold */
+
+/*
+ * VIO may be 5 V or 3.3 V. Initialization takes two parts:
+ * 1. Initialize lowest lower limit and highest higher limit.
+ * 2. After the first value is read correct the upper or the lower limit to
+ * the appropriate C constant.
+ *
+ * Warning limits are +-5% of the exepected voltage.
+ * Error limits are +-10% of the expected voltage.
+ */
+
+/* Bug fix AF: 16.Aug.2001: Correct the init base of LM80 sensor */
+
+#define SK_SEN_PCI_IO_5V_HIGH_ERR 5566 /* + 10% V PCI-IO High Err Threshold */
+#define SK_SEN_PCI_IO_5V_HIGH_WARN 5324 /* + 5% V PCI-IO High Warn Threshold */
+ /* 5000 mVolt */
+#define SK_SEN_PCI_IO_5V_LOW_WARN 4686 /* - 5% V PCI-IO Low Warn Threshold */
+#define SK_SEN_PCI_IO_5V_LOW_ERR 4444 /* - 10% V PCI-IO Low Err Threshold */
+
+#define SK_SEN_PCI_IO_RANGE_LIMITER 4000 /* 4000 mV range delimiter */
+
+/* correction values for the second pass */
+#define SK_SEN_PCI_IO_3V3_HIGH_ERR 3850 /* + 15% V PCI-IO High Err Threshold */
+#define SK_SEN_PCI_IO_3V3_HIGH_WARN 3674 /* + 10% V PCI-IO High Warn Threshold */
+ /* 3300 mVolt */
+#define SK_SEN_PCI_IO_3V3_LOW_WARN 2926 /* - 10% V PCI-IO Low Warn Threshold */
+#define SK_SEN_PCI_IO_3V3_LOW_ERR 2772 /* - 15% V PCI-IO Low Err Threshold */
+
+/*
+ * VDD voltage
+ */
+#define SK_SEN_VDD_HIGH_ERR 3630 /* Voltage ASIC High Err Threshold */
+#define SK_SEN_VDD_HIGH_WARN 3476 /* Voltage ASIC High Warn Threshold */
+#define SK_SEN_VDD_LOW_WARN 3146 /* Voltage ASIC Low Warn Threshold */
+#define SK_SEN_VDD_LOW_ERR 2970 /* Voltage ASIC Low Err Threshold */
+
+/*
+ * PHY PLL 3V3 voltage
+ */
+#define SK_SEN_PLL_3V3_HIGH_ERR 3630 /* Voltage PMA High Err Threshold */
+#define SK_SEN_PLL_3V3_HIGH_WARN 3476 /* Voltage PMA High Warn Threshold */
+#define SK_SEN_PLL_3V3_LOW_WARN 3146 /* Voltage PMA Low Warn Threshold */
+#define SK_SEN_PLL_3V3_LOW_ERR 2970 /* Voltage PMA Low Err Threshold */
+
+/*
+ * VAUX (YUKON only)
+ */
+#define SK_SEN_VAUX_3V3_HIGH_ERR 3630 /* Voltage VAUX High Err Threshold */
+#define SK_SEN_VAUX_3V3_HIGH_WARN 3476 /* Voltage VAUX High Warn Threshold */
+#define SK_SEN_VAUX_3V3_LOW_WARN 3146 /* Voltage VAUX Low Warn Threshold */
+#define SK_SEN_VAUX_3V3_LOW_ERR 2970 /* Voltage VAUX Low Err Threshold */
+#define SK_SEN_VAUX_0V_WARN_ERR 0 /* if VAUX not present */
+#define SK_SEN_VAUX_RANGE_LIMITER 1000 /* 1000 mV range delimiter */
+
+/*
+ * PHY 2V5 voltage
+ */
+#define SK_SEN_PHY_2V5_HIGH_ERR 2750 /* Voltage PHY High Err Threshold */
+#define SK_SEN_PHY_2V5_HIGH_WARN 2640 /* Voltage PHY High Warn Threshold */
+#define SK_SEN_PHY_2V5_LOW_WARN 2376 /* Voltage PHY Low Warn Threshold */
+#define SK_SEN_PHY_2V5_LOW_ERR 2222 /* Voltage PHY Low Err Threshold */
+
+/*
+ * ASIC Core 1V5 voltage (YUKON only)
+ */
+#define SK_SEN_CORE_1V5_HIGH_ERR 1650 /* Voltage ASIC Core High Err Threshold */
+#define SK_SEN_CORE_1V5_HIGH_WARN 1575 /* Voltage ASIC Core High Warn Threshold */
+#define SK_SEN_CORE_1V5_LOW_WARN 1425 /* Voltage ASIC Core Low Warn Threshold */
+#define SK_SEN_CORE_1V5_LOW_ERR 1350 /* Voltage ASIC Core Low Err Threshold */
+
+/*
+ * FAN 1 speed
+ */
+/* assuming: 6500rpm +-15%, 4 pulses,
+ * warning at: 80 %
+ * error at: 70 %
+ * no upper limit
+ */
+#define SK_SEN_FAN_HIGH_ERR 20000 /* FAN Speed High Err Threshold */
+#define SK_SEN_FAN_HIGH_WARN 20000 /* FAN Speed High Warn Threshold */
+#define SK_SEN_FAN_LOW_WARN 5200 /* FAN Speed Low Warn Threshold */
+#define SK_SEN_FAN_LOW_ERR 4550 /* FAN Speed Low Err Threshold */
+
+/*
+ * Some Voltages need dynamic thresholds
+ */
+#define SK_SEN_DYN_INIT_NONE 0 /* No dynamic init of thresholds */
+#define SK_SEN_DYN_INIT_PCI_IO 10 /* Init PCI-IO with new thresholds */
+#define SK_SEN_DYN_INIT_VAUX 11 /* Init VAUX with new thresholds */
+
+extern int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#endif /* n_INC_SKGEI2C_H */
diff --git a/drivers/net/sk98lin/h/skgeinit.h b/drivers/net/sk98lin/h/skgeinit.h
new file mode 100644
index 000000000000..143e635ec24d
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgeinit.h
@@ -0,0 +1,797 @@
+/******************************************************************************
+ *
+ * Name: skgeinit.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.83 $
+ * Date: $Date: 2003/09/16 14:07:37 $
+ * Purpose: Structures and prototypes for the GE Init Module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEINIT_H_
+#define __INC_SKGEINIT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_TEST_VAL 0x11335577UL
+
+/* modifying Link LED behaviour (used with SkGeLinkLED()) */
+#define SK_LNK_OFF LED_OFF
+#define SK_LNK_ON (LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LNK_BLINK (LED_ON | LED_BLK_ON | LED_SYNC_ON)
+#define SK_LNK_PERM (LED_ON | LED_BLK_OFF | LED_SYNC_ON)
+#define SK_LNK_TST (LED_ON | LED_BLK_ON | LED_SYNC_OFF)
+
+/* parameter 'Mode' when calling SK_HWAC_LINK_LED() */
+#define SK_LED_OFF LED_OFF
+#define SK_LED_ACTIVE (LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LED_STANDBY (LED_ON | LED_BLK_ON | LED_SYNC_OFF)
+
+/* addressing LED Registers in SkGeXmitLED() */
+#define XMIT_LED_INI 0
+#define XMIT_LED_CNT (RX_LED_VAL - RX_LED_INI)
+#define XMIT_LED_CTRL (RX_LED_CTRL- RX_LED_INI)
+#define XMIT_LED_TST (RX_LED_TST - RX_LED_INI)
+
+/* parameter 'Mode' when calling SkGeXmitLED() */
+#define SK_LED_DIS 0
+#define SK_LED_ENA 1
+#define SK_LED_TST 2
+
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR 0x002faf08UL /* 50 ms */
+#define SK_BLK_DUR 0x01dcd650UL /* 500 ms */
+
+#define SK_DPOLL_DEF 0x00ee6b28UL /* 250 ms at 62.5 MHz */
+
+#define SK_DPOLL_MAX 0x00ffffffUL /* 268 ms at 62.5 MHz */
+ /* 215 ms at 78.12 MHz */
+
+#define SK_FACT_62 100 /* is given in percent */
+#define SK_FACT_53 85 /* on GENESIS: 53.12 MHz */
+#define SK_FACT_78 125 /* on YUKON: 78.12 MHz */
+
+/* Timeout values */
+#define SK_MAC_TO_53 72 /* MAC arbiter timeout */
+#define SK_PKT_TO_53 0x2000 /* Packet arbiter timeout */
+#define SK_PKT_TO_MAX 0xffff /* Maximum value */
+#define SK_RI_TO_53 36 /* RAM interface timeout */
+
+#define SK_PHY_ACC_TO 600000 /* PHY access timeout */
+
+/* RAM Buffer High Pause Threshold values */
+#define SK_RB_ULPP ( 8 * 1024) /* Upper Level in kB/8 */
+#define SK_RB_LLPP_S (10 * 1024) /* Lower Level for small Queues */
+#define SK_RB_LLPP_B (16 * 1024) /* Lower Level for big Queues */
+
+#ifndef SK_BMU_RX_WM
+#define SK_BMU_RX_WM 0x600 /* BMU Rx Watermark */
+#endif
+#ifndef SK_BMU_TX_WM
+#define SK_BMU_TX_WM 0x600 /* BMU Tx Watermark */
+#endif
+
+/* XMAC II Rx High Watermark */
+#define SK_XM_RX_HI_WM 0x05aa /* 1450 */
+
+/* XMAC II Tx Threshold */
+#define SK_XM_THR_REDL 0x01fb /* .. for redundant link usage */
+#define SK_XM_THR_SL 0x01fb /* .. for single link adapters */
+#define SK_XM_THR_MULL 0x01fb /* .. for multiple link usage */
+#define SK_XM_THR_JUMBO 0x03fc /* .. for jumbo frame usage */
+
+/* values for GIPortUsage */
+#define SK_RED_LINK 1 /* redundant link usage */
+#define SK_MUL_LINK 2 /* multiple link usage */
+#define SK_JUMBO_LINK 3 /* driver uses jumbo frames */
+
+/* Minimum RAM Buffer Rx Queue Size */
+#define SK_MIN_RXQ_SIZE 16 /* 16 kB */
+
+/* Minimum RAM Buffer Tx Queue Size */
+#define SK_MIN_TXQ_SIZE 16 /* 16 kB */
+
+/* Queue Size units */
+#define QZ_UNITS 0x7
+#define QZ_STEP 8
+
+/* Percentage of queue size from whole memory */
+/* 80 % for receive */
+#define RAM_QUOTA_RX 80L
+/* 0% for sync transfer */
+#define RAM_QUOTA_SYNC 0L
+/* the rest (20%) is taken for async transfer */
+
+/* Get the rounded queue size in Bytes in 8k steps */
+#define ROUND_QUEUE_SIZE(SizeInBytes) \
+ ((((unsigned long) (SizeInBytes) + (QZ_STEP*1024L)-1) / 1024) & \
+ ~(QZ_STEP-1))
+
+/* Get the rounded queue size in KBytes in 8k steps */
+#define ROUND_QUEUE_SIZE_KB(Kilobytes) \
+ ROUND_QUEUE_SIZE((Kilobytes) * 1024L)
+
+/* Types of RAM Buffer Queues */
+#define SK_RX_SRAM_Q 1 /* small receive queue */
+#define SK_RX_BRAM_Q 2 /* big receive queue */
+#define SK_TX_RAM_Q 3 /* small or big transmit queue */
+
+/* parameter 'Dir' when calling SkGeStopPort() */
+#define SK_STOP_TX 1 /* Stops the transmit path, resets the XMAC */
+#define SK_STOP_RX 2 /* Stops the receive path */
+#define SK_STOP_ALL 3 /* Stops Rx and Tx path, resets the XMAC */
+
+/* parameter 'RstMode' when calling SkGeStopPort() */
+#define SK_SOFT_RST 1 /* perform a software reset */
+#define SK_HARD_RST 2 /* perform a hardware reset */
+
+/* Init Levels */
+#define SK_INIT_DATA 0 /* Init level 0: init data structures */
+#define SK_INIT_IO 1 /* Init level 1: init with IOs */
+#define SK_INIT_RUN 2 /* Init level 2: init for run time */
+
+/* Link Mode Parameter */
+#define SK_LMODE_HALF 1 /* Half Duplex Mode */
+#define SK_LMODE_FULL 2 /* Full Duplex Mode */
+#define SK_LMODE_AUTOHALF 3 /* AutoHalf Duplex Mode */
+#define SK_LMODE_AUTOFULL 4 /* AutoFull Duplex Mode */
+#define SK_LMODE_AUTOBOTH 5 /* AutoBoth Duplex Mode */
+#define SK_LMODE_AUTOSENSE 6 /* configured mode auto sensing */
+#define SK_LMODE_INDETERMINATED 7 /* indeterminated */
+
+/* Auto-negotiation timeout in 100ms granularity */
+#define SK_AND_MAX_TO 6 /* Wait 600 msec before link comes up */
+
+/* Auto-negotiation error codes */
+#define SK_AND_OK 0 /* no error */
+#define SK_AND_OTHER 1 /* other error than below */
+#define SK_AND_DUP_CAP 2 /* Duplex capabilities error */
+
+
+/* Link Speed Capabilities */
+#define SK_LSPEED_CAP_AUTO (1<<0) /* Automatic resolution */
+#define SK_LSPEED_CAP_10MBPS (1<<1) /* 10 Mbps */
+#define SK_LSPEED_CAP_100MBPS (1<<2) /* 100 Mbps */
+#define SK_LSPEED_CAP_1000MBPS (1<<3) /* 1000 Mbps */
+#define SK_LSPEED_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Speed Parameter */
+#define SK_LSPEED_AUTO 1 /* Automatic resolution */
+#define SK_LSPEED_10MBPS 2 /* 10 Mbps */
+#define SK_LSPEED_100MBPS 3 /* 100 Mbps */
+#define SK_LSPEED_1000MBPS 4 /* 1000 Mbps */
+#define SK_LSPEED_INDETERMINATED 5 /* indeterminated */
+
+/* Link Speed Current State */
+#define SK_LSPEED_STAT_UNKNOWN 1
+#define SK_LSPEED_STAT_10MBPS 2
+#define SK_LSPEED_STAT_100MBPS 3
+#define SK_LSPEED_STAT_1000MBPS 4
+#define SK_LSPEED_STAT_INDETERMINATED 5
+
+
+/* Link Capability Parameter */
+#define SK_LMODE_CAP_HALF (1<<0) /* Half Duplex Mode */
+#define SK_LMODE_CAP_FULL (1<<1) /* Full Duplex Mode */
+#define SK_LMODE_CAP_AUTOHALF (1<<2) /* AutoHalf Duplex Mode */
+#define SK_LMODE_CAP_AUTOFULL (1<<3) /* AutoFull Duplex Mode */
+#define SK_LMODE_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Mode Current State */
+#define SK_LMODE_STAT_UNKNOWN 1 /* Unknown Duplex Mode */
+#define SK_LMODE_STAT_HALF 2 /* Half Duplex Mode */
+#define SK_LMODE_STAT_FULL 3 /* Full Duplex Mode */
+#define SK_LMODE_STAT_AUTOHALF 4 /* Half Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_AUTOFULL 5 /* Full Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_INDETERMINATED 6 /* indeterminated */
+
+/* Flow Control Mode Parameter (and capabilities) */
+#define SK_FLOW_MODE_NONE 1 /* No Flow-Control */
+#define SK_FLOW_MODE_LOC_SEND 2 /* Local station sends PAUSE */
+#define SK_FLOW_MODE_SYMMETRIC 3 /* Both stations may send PAUSE */
+#define SK_FLOW_MODE_SYM_OR_REM 4 /* Both stations may send PAUSE or
+ * just the remote station may send PAUSE
+ */
+#define SK_FLOW_MODE_INDETERMINATED 5 /* indeterminated */
+
+/* Flow Control Status Parameter */
+#define SK_FLOW_STAT_NONE 1 /* No Flow Control */
+#define SK_FLOW_STAT_REM_SEND 2 /* Remote Station sends PAUSE */
+#define SK_FLOW_STAT_LOC_SEND 3 /* Local station sends PAUSE */
+#define SK_FLOW_STAT_SYMMETRIC 4 /* Both station may send PAUSE */
+#define SK_FLOW_STAT_INDETERMINATED 5 /* indeterminated */
+
+/* Master/Slave Mode Capabilities */
+#define SK_MS_CAP_AUTO (1<<0) /* Automatic resolution */
+#define SK_MS_CAP_MASTER (1<<1) /* This station is master */
+#define SK_MS_CAP_SLAVE (1<<2) /* This station is slave */
+#define SK_MS_CAP_INDETERMINATED (1<<3) /* indeterminated */
+
+/* Set Master/Slave Mode Parameter (and capabilities) */
+#define SK_MS_MODE_AUTO 1 /* Automatic resolution */
+#define SK_MS_MODE_MASTER 2 /* This station is master */
+#define SK_MS_MODE_SLAVE 3 /* This station is slave */
+#define SK_MS_MODE_INDETERMINATED 4 /* indeterminated */
+
+/* Master/Slave Status Parameter */
+#define SK_MS_STAT_UNSET 1 /* The M/S status is not set */
+#define SK_MS_STAT_MASTER 2 /* This station is master */
+#define SK_MS_STAT_SLAVE 3 /* This station is slave */
+#define SK_MS_STAT_FAULT 4 /* M/S resolution failed */
+#define SK_MS_STAT_INDETERMINATED 5 /* indeterminated */
+
+/* parameter 'Mode' when calling SkXmSetRxCmd() */
+#define SK_STRIP_FCS_ON (1<<0) /* Enable FCS stripping of Rx frames */
+#define SK_STRIP_FCS_OFF (1<<1) /* Disable FCS stripping of Rx frames */
+#define SK_STRIP_PAD_ON (1<<2) /* Enable pad byte stripping of Rx fr */
+#define SK_STRIP_PAD_OFF (1<<3) /* Disable pad byte stripping of Rx fr */
+#define SK_LENERR_OK_ON (1<<4) /* Don't chk fr for in range len error */
+#define SK_LENERR_OK_OFF (1<<5) /* Check frames for in range len error */
+#define SK_BIG_PK_OK_ON (1<<6) /* Don't set Rx Error bit for big frames */
+#define SK_BIG_PK_OK_OFF (1<<7) /* Set Rx Error bit for big frames */
+#define SK_SELF_RX_ON (1<<8) /* Enable Rx of own packets */
+#define SK_SELF_RX_OFF (1<<9) /* Disable Rx of own packets */
+
+/* parameter 'Para' when calling SkMacSetRxTxEn() */
+#define SK_MAC_LOOPB_ON (1<<0) /* Enable MAC Loopback Mode */
+#define SK_MAC_LOOPB_OFF (1<<1) /* Disable MAC Loopback Mode */
+#define SK_PHY_LOOPB_ON (1<<2) /* Enable PHY Loopback Mode */
+#define SK_PHY_LOOPB_OFF (1<<3) /* Disable PHY Loopback Mode */
+#define SK_PHY_FULLD_ON (1<<4) /* Enable GMII Full Duplex */
+#define SK_PHY_FULLD_OFF (1<<5) /* Disable GMII Full Duplex */
+
+/* States of PState */
+#define SK_PRT_RESET 0 /* the port is reset */
+#define SK_PRT_STOP 1 /* the port is stopped (similar to SW reset) */
+#define SK_PRT_INIT 2 /* the port is initialized */
+#define SK_PRT_RUN 3 /* the port has an active link */
+
+/* PHY power down modes */
+#define PHY_PM_OPERATIONAL_MODE 0 /* PHY operational mode */
+#define PHY_PM_DEEP_SLEEP 1 /* coma mode --> minimal power */
+#define PHY_PM_IEEE_POWER_DOWN 2 /* IEEE 22.2.4.1.5 compl. power down */
+#define PHY_PM_ENERGY_DETECT 3 /* energy detect */
+#define PHY_PM_ENERGY_DETECT_PLUS 4 /* energy detect plus */
+
+/* Default receive frame limit for Workaround of XMAC Errata */
+#define SK_DEF_RX_WA_LIM SK_CONSTU64(100)
+
+/* values for GILedBlinkCtrl (LED Blink Control) */
+#define SK_ACT_LED_BLINK (1<<0) /* Active LED blinking */
+#define SK_DUP_LED_NORMAL (1<<1) /* Duplex LED normal */
+#define SK_LED_LINK100_ON (1<<2) /* Link 100M LED on */
+
+/* Link Partner Status */
+#define SK_LIPA_UNKNOWN 0 /* Link partner is in unknown state */
+#define SK_LIPA_MANUAL 1 /* Link partner is in detected manual state */
+#define SK_LIPA_AUTO 2 /* Link partner is in auto-negotiation state */
+
+/* Maximum Restarts before restart is ignored (3Com WA) */
+#define SK_MAX_LRESTART 3 /* Max. 3 times the link is restarted */
+
+/* Max. Auto-neg. timeouts before link detection in sense mode is reset */
+#define SK_MAX_ANEG_TO 10 /* Max. 10 times the sense mode is reset */
+
+/* structures *****************************************************************/
+
+/*
+ * MAC specific functions
+ */
+typedef struct s_GeMacFunc {
+ int (*pFnMacUpdateStats)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+ int (*pFnMacStatistic)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+ SK_U16 StatAddr, SK_U32 SK_FAR *pVal);
+ int (*pFnMacResetCounter)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+ int (*pFnMacOverflow)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+ SK_U16 IStatus, SK_U64 SK_FAR *pVal);
+} SK_GEMACFUNC;
+
+/*
+ * Port Structure
+ */
+typedef struct s_GePort {
+#ifndef SK_DIAG
+ SK_TIMER PWaTimer; /* Workaround Timer */
+ SK_TIMER HalfDupChkTimer;
+#endif /* SK_DIAG */
+ SK_U32 PPrevShorts; /* Previous Short Counter checking */
+ SK_U32 PPrevFcs; /* Previous FCS Error Counter checking */
+ SK_U64 PPrevRx; /* Previous RxOk Counter checking */
+ SK_U64 PRxLim; /* Previous RxOk Counter checking */
+ SK_U64 LastOctets; /* For half duplex hang check */
+ int PLinkResCt; /* Link Restart Counter */
+ int PAutoNegTimeOut;/* Auto-negotiation timeout current value */
+ int PAutoNegTOCt; /* Auto-negotiation Timeout Counter */
+ int PRxQSize; /* Port Rx Queue Size in kB */
+ int PXSQSize; /* Port Synchronous Transmit Queue Size in kB */
+ int PXAQSize; /* Port Asynchronous Transmit Queue Size in kB */
+ SK_U32 PRxQRamStart; /* Receive Queue RAM Buffer Start Address */
+ SK_U32 PRxQRamEnd; /* Receive Queue RAM Buffer End Address */
+ SK_U32 PXsQRamStart; /* Sync Tx Queue RAM Buffer Start Address */
+ SK_U32 PXsQRamEnd; /* Sync Tx Queue RAM Buffer End Address */
+ SK_U32 PXaQRamStart; /* Async Tx Queue RAM Buffer Start Address */
+ SK_U32 PXaQRamEnd; /* Async Tx Queue RAM Buffer End Address */
+ SK_U32 PRxOverCnt; /* Receive Overflow Counter */
+ int PRxQOff; /* Rx Queue Address Offset */
+ int PXsQOff; /* Synchronous Tx Queue Address Offset */
+ int PXaQOff; /* Asynchronous Tx Queue Address Offset */
+ int PhyType; /* PHY used on this port */
+ int PState; /* Port status (reset, stop, init, run) */
+ SK_U16 PhyId1; /* PHY Id1 on this port */
+ SK_U16 PhyAddr; /* MDIO/MDC PHY address */
+ SK_U16 PIsave; /* Saved Interrupt status word */
+ SK_U16 PSsave; /* Saved PHY status word */
+ SK_U16 PGmANegAdv; /* Saved GPhy AutoNegAdvertisment register */
+ SK_BOOL PHWLinkUp; /* The hardware Link is up (wiring) */
+ SK_BOOL PLinkBroken; /* Is Link broken ? */
+ SK_BOOL PCheckPar; /* Do we check for parity errors ? */
+ SK_BOOL HalfDupTimerActive;
+ SK_U8 PLinkCap; /* Link Capabilities */
+ SK_U8 PLinkModeConf; /* Link Mode configured */
+ SK_U8 PLinkMode; /* Link Mode currently used */
+ SK_U8 PLinkModeStatus;/* Link Mode Status */
+ SK_U8 PLinkSpeedCap; /* Link Speed Capabilities(10/100/1000 Mbps) */
+ SK_U8 PLinkSpeed; /* configured Link Speed (10/100/1000 Mbps) */
+ SK_U8 PLinkSpeedUsed; /* current Link Speed (10/100/1000 Mbps) */
+ SK_U8 PFlowCtrlCap; /* Flow Control Capabilities */
+ SK_U8 PFlowCtrlMode; /* Flow Control Mode */
+ SK_U8 PFlowCtrlStatus;/* Flow Control Status */
+ SK_U8 PMSCap; /* Master/Slave Capabilities */
+ SK_U8 PMSMode; /* Master/Slave Mode */
+ SK_U8 PMSStatus; /* Master/Slave Status */
+ SK_BOOL PAutoNegFail; /* Auto-negotiation fail flag */
+ SK_U8 PLipaAutoNeg; /* Auto-negotiation possible with Link Partner */
+ SK_U8 PCableLen; /* Cable Length */
+ SK_U8 PMdiPairLen[4]; /* MDI[0..3] Pair Length */
+ SK_U8 PMdiPairSts[4]; /* MDI[0..3] Pair Diagnostic Status */
+ SK_U8 PPhyPowerState; /* PHY current power state */
+ int PMacColThres; /* MAC Collision Threshold */
+ int PMacJamLen; /* MAC Jam length */
+ int PMacJamIpgVal; /* MAC Jam IPG */
+ int PMacJamIpgData; /* MAC IPG Jam to Data */
+ int PMacIpgData; /* MAC Data IPG */
+ SK_BOOL PMacLimit4; /* reset collision counter and backoff algorithm */
+} SK_GEPORT;
+
+/*
+ * Gigabit Ethernet Initialization Struct
+ * (has to be included in the adapter context)
+ */
+typedef struct s_GeInit {
+ int GIChipId; /* Chip Identification Number */
+ int GIChipRev; /* Chip Revision Number */
+ SK_U8 GIPciHwRev; /* PCI HW Revision Number */
+ SK_BOOL GIGenesis; /* Genesis adapter ? */
+ SK_BOOL GIYukon; /* YUKON-A1/Bx chip */
+ SK_BOOL GIYukonLite; /* YUKON-Lite chip */
+ SK_BOOL GICopperType; /* Copper Type adapter ? */
+ SK_BOOL GIPciSlot64; /* 64-bit PCI Slot */
+ SK_BOOL GIPciClock66; /* 66 MHz PCI Clock */
+ SK_BOOL GIVauxAvail; /* VAUX available (YUKON) */
+ SK_BOOL GIYukon32Bit; /* 32-Bit YUKON adapter */
+ SK_U16 GILedBlinkCtrl; /* LED Blink Control */
+ int GIMacsFound; /* Number of MACs found on this adapter */
+ int GIMacType; /* MAC Type used on this adapter */
+ int GIHstClkFact; /* Host Clock Factor (62.5 / HstClk * 100) */
+ int GIPortUsage; /* Driver Port Usage */
+ int GILevel; /* Initialization Level completed */
+ int GIRamSize; /* The RAM size of the adapter in kB */
+ int GIWolOffs; /* WOL Register Offset (HW-Bug in Rev. A) */
+ SK_U32 GIRamOffs; /* RAM Address Offset for addr calculation */
+ SK_U32 GIPollTimerVal; /* Descr. Poll Timer Init Val (HstClk ticks) */
+ SK_U32 GIValIrqMask; /* Value for Interrupt Mask */
+ SK_U32 GITimeStampCnt; /* Time Stamp High Counter (YUKON only) */
+ SK_GEPORT GP[SK_MAX_MACS];/* Port Dependent Information */
+ SK_GEMACFUNC GIFunc; /* MAC depedent functions */
+} SK_GEINIT;
+
+/*
+ * Error numbers and messages for skxmac2.c and skgeinit.c
+ */
+#define SKERR_HWI_E001 (SK_ERRBASE_HWINIT)
+#define SKERR_HWI_E001MSG "SkXmClrExactAddr() has got illegal parameters"
+#define SKERR_HWI_E002 (SKERR_HWI_E001+1)
+#define SKERR_HWI_E002MSG "SkGeInit(): Level 1 call missing"
+#define SKERR_HWI_E003 (SKERR_HWI_E002+1)
+#define SKERR_HWI_E003MSG "SkGeInit() called with illegal init Level"
+#define SKERR_HWI_E004 (SKERR_HWI_E003+1)
+#define SKERR_HWI_E004MSG "SkGeInitPort(): Queue Size illegal configured"
+#define SKERR_HWI_E005 (SKERR_HWI_E004+1)
+#define SKERR_HWI_E005MSG "SkGeInitPort(): cannot init running ports"
+#define SKERR_HWI_E006 (SKERR_HWI_E005+1)
+#define SKERR_HWI_E006MSG "SkGeMacInit(): PState does not match HW state"
+#define SKERR_HWI_E007 (SKERR_HWI_E006+1)
+#define SKERR_HWI_E007MSG "SkXmInitDupMd() called with invalid Dup Mode"
+#define SKERR_HWI_E008 (SKERR_HWI_E007+1)
+#define SKERR_HWI_E008MSG "SkXmSetRxCmd() called with invalid Mode"
+#define SKERR_HWI_E009 (SKERR_HWI_E008+1)
+#define SKERR_HWI_E009MSG "SkGeCfgSync() called although PXSQSize zero"
+#define SKERR_HWI_E010 (SKERR_HWI_E009+1)
+#define SKERR_HWI_E010MSG "SkGeCfgSync() called with invalid parameters"
+#define SKERR_HWI_E011 (SKERR_HWI_E010+1)
+#define SKERR_HWI_E011MSG "SkGeInitPort(): Receive Queue Size too small"
+#define SKERR_HWI_E012 (SKERR_HWI_E011+1)
+#define SKERR_HWI_E012MSG "SkGeInitPort(): invalid Queue Size specified"
+#define SKERR_HWI_E013 (SKERR_HWI_E012+1)
+#define SKERR_HWI_E013MSG "SkGeInitPort(): cfg changed for running queue"
+#define SKERR_HWI_E014 (SKERR_HWI_E013+1)
+#define SKERR_HWI_E014MSG "SkGeInitPort(): unknown GIPortUsage specified"
+#define SKERR_HWI_E015 (SKERR_HWI_E014+1)
+#define SKERR_HWI_E015MSG "Illegal Link mode parameter"
+#define SKERR_HWI_E016 (SKERR_HWI_E015+1)
+#define SKERR_HWI_E016MSG "Illegal Flow control mode parameter"
+#define SKERR_HWI_E017 (SKERR_HWI_E016+1)
+#define SKERR_HWI_E017MSG "Illegal value specified for GIPollTimerVal"
+#define SKERR_HWI_E018 (SKERR_HWI_E017+1)
+#define SKERR_HWI_E018MSG "FATAL: SkGeStopPort() does not terminate (Tx)"
+#define SKERR_HWI_E019 (SKERR_HWI_E018+1)
+#define SKERR_HWI_E019MSG "Illegal Speed parameter"
+#define SKERR_HWI_E020 (SKERR_HWI_E019+1)
+#define SKERR_HWI_E020MSG "Illegal Master/Slave parameter"
+#define SKERR_HWI_E021 (SKERR_HWI_E020+1)
+#define SKERR_HWI_E021MSG "MacUpdateStats(): cannot update statistic counter"
+#define SKERR_HWI_E022 (SKERR_HWI_E021+1)
+#define SKERR_HWI_E022MSG "MacStatistic(): illegal statistic base address"
+#define SKERR_HWI_E023 (SKERR_HWI_E022+1)
+#define SKERR_HWI_E023MSG "SkGeInitPort(): Transmit Queue Size too small"
+#define SKERR_HWI_E024 (SKERR_HWI_E023+1)
+#define SKERR_HWI_E024MSG "FATAL: SkGeStopPort() does not terminate (Rx)"
+#define SKERR_HWI_E025 (SKERR_HWI_E024+1)
+#define SKERR_HWI_E025MSG ""
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void SkGePollTxD(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL PollTxD);
+
+extern void SkGeYellowLED(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int State);
+
+extern int SkGeCfgSync(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_U32 IntTime,
+ SK_U32 LimCount,
+ int SyncMode);
+
+extern void SkGeLoadLnkSyncCnt(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_U32 CntVal);
+
+extern void SkGeStopPort(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Dir,
+ int RstMode);
+
+extern int SkGeInit(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Level);
+
+extern void SkGeDeInit(
+ SK_AC *pAC,
+ SK_IOC IoC);
+
+extern int SkGeInitPort(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkGeXmitLED(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Led,
+ int Mode);
+
+extern int SkGeInitAssignRamToQueues(
+ SK_AC *pAC,
+ int ActivePort,
+ SK_BOOL DualNet);
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacSoftRst(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacHardRst(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkXmInitMac(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkGmInitMac(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacInitPhy(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL DoLoop);
+
+extern void SkMacIrqDisable(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacFlushTxFifo(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacIrq(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern int SkMacAutoNegDone(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacAutoNegLipaPhy(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_U16 IStatus);
+
+extern int SkMacRxTxEnable(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port);
+
+extern void SkMacPromiscMode(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL Enable);
+
+extern void SkMacHashing(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL Enable);
+
+extern void SkXmPhyRead(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Addr,
+ SK_U16 SK_FAR *pVal);
+
+extern void SkXmPhyWrite(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Addr,
+ SK_U16 Val);
+
+extern void SkGmPhyRead(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Addr,
+ SK_U16 SK_FAR *pVal);
+
+extern void SkGmPhyWrite(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Addr,
+ SK_U16 Val);
+
+extern void SkXmClrExactAddr(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int StartNum,
+ int StopNum);
+
+extern void SkXmAutoNegLipaXmac(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_U16 IStatus);
+
+extern int SkXmUpdateStats(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port);
+
+extern int SkGmUpdateStats(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port);
+
+extern int SkXmMacStatistic(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port,
+ SK_U16 StatAddr,
+ SK_U32 SK_FAR *pVal);
+
+extern int SkGmMacStatistic(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port,
+ SK_U16 StatAddr,
+ SK_U32 SK_FAR *pVal);
+
+extern int SkXmResetCounter(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port);
+
+extern int SkGmResetCounter(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port);
+
+extern int SkXmOverflowStatus(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port,
+ SK_U16 IStatus,
+ SK_U64 SK_FAR *pStatus);
+
+extern int SkGmOverflowStatus(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ unsigned int Port,
+ SK_U16 MacStatus,
+ SK_U64 SK_FAR *pStatus);
+
+extern int SkGmCableDiagStatus(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL StartTest);
+
+#ifdef SK_DIAG
+extern void SkGePhyRead(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Addr,
+ SK_U16 *pVal);
+
+extern void SkGePhyWrite(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Addr,
+ SK_U16 Val);
+
+extern void SkMacSetRxCmd(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ int Mode);
+extern void SkMacCrcGener(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL Enable);
+extern void SkMacTimeStamp(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL Enable);
+extern void SkXmSendCont(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Port,
+ SK_BOOL Enable);
+#endif /* SK_DIAG */
+
+#else /* SK_KR_PROTO */
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void SkGePollTxD();
+extern void SkGeYellowLED();
+extern int SkGeCfgSync();
+extern void SkGeLoadLnkSyncCnt();
+extern void SkGeStopPort();
+extern int SkGeInit();
+extern void SkGeDeInit();
+extern int SkGeInitPort();
+extern void SkGeXmitLED();
+extern int SkGeInitAssignRamToQueues();
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable();
+extern void SkMacSoftRst();
+extern void SkMacHardRst();
+extern void SkMacInitPhy();
+extern int SkMacRxTxEnable();
+extern void SkMacPromiscMode();
+extern void SkMacHashing();
+extern void SkMacIrqDisable();
+extern void SkMacFlushTxFifo();
+extern void SkMacIrq();
+extern int SkMacAutoNegDone();
+extern void SkMacAutoNegLipaPhy();
+extern void SkXmInitMac();
+extern void SkXmPhyRead();
+extern void SkXmPhyWrite();
+extern void SkGmInitMac();
+extern void SkGmPhyRead();
+extern void SkGmPhyWrite();
+extern void SkXmClrExactAddr();
+extern void SkXmAutoNegLipaXmac();
+extern int SkXmUpdateStats();
+extern int SkGmUpdateStats();
+extern int SkXmMacStatistic();
+extern int SkGmMacStatistic();
+extern int SkXmResetCounter();
+extern int SkGmResetCounter();
+extern int SkXmOverflowStatus();
+extern int SkGmOverflowStatus();
+extern int SkGmCableDiagStatus();
+
+#ifdef SK_DIAG
+extern void SkGePhyRead();
+extern void SkGePhyWrite();
+extern void SkMacSetRxCmd();
+extern void SkMacCrcGener();
+extern void SkMacTimeStamp();
+extern void SkXmSendCont();
+#endif /* SK_DIAG */
+
+#endif /* SK_KR_PROTO */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKGEINIT_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnm2.h b/drivers/net/sk98lin/h/skgepnm2.h
new file mode 100644
index 000000000000..ddd304f1a48b
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnm2.h
@@ -0,0 +1,334 @@
+/*****************************************************************************
+ *
+ * Name: skgepnm2.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.36 $
+ * Date: $Date: 2003/05/23 12:45:13 $
+ * Purpose: Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SKGEPNM2_H_
+#define _SKGEPNM2_H_
+
+/*
+ * General definitions
+ */
+#define SK_PNMI_CHIPSET_XMAC 1 /* XMAC11800FP */
+#define SK_PNMI_CHIPSET_YUKON 2 /* YUKON */
+
+#define SK_PNMI_BUS_PCI 1 /* PCI bus*/
+
+/*
+ * Actions
+ */
+#define SK_PNMI_ACT_IDLE 1
+#define SK_PNMI_ACT_RESET 2
+#define SK_PNMI_ACT_SELFTEST 3
+#define SK_PNMI_ACT_RESETCNT 4
+
+/*
+ * VPD releated defines
+ */
+
+#define SK_PNMI_VPD_RW 1
+#define SK_PNMI_VPD_RO 2
+
+#define SK_PNMI_VPD_OK 0
+#define SK_PNMI_VPD_NOTFOUND 1
+#define SK_PNMI_VPD_CUT 2
+#define SK_PNMI_VPD_TIMEOUT 3
+#define SK_PNMI_VPD_FULL 4
+#define SK_PNMI_VPD_NOWRITE 5
+#define SK_PNMI_VPD_FATAL 6
+
+#define SK_PNMI_VPD_IGNORE 0
+#define SK_PNMI_VPD_CREATE 1
+#define SK_PNMI_VPD_DELETE 2
+
+
+/*
+ * RLMT related defines
+ */
+#define SK_PNMI_DEF_RLMT_CHG_THRES 240 /* 4 changes per minute */
+
+
+/*
+ * VCT internal status values
+ */
+#define SK_PNMI_VCT_PENDING 32
+#define SK_PNMI_VCT_TEST_DONE 64
+#define SK_PNMI_VCT_LINK 128
+
+/*
+ * Internal table definitions
+ */
+#define SK_PNMI_GET 0
+#define SK_PNMI_PRESET 1
+#define SK_PNMI_SET 2
+
+#define SK_PNMI_RO 0
+#define SK_PNMI_RW 1
+#define SK_PNMI_WO 2
+
+typedef struct s_OidTabEntry {
+ SK_U32 Id;
+ SK_U32 InstanceNo;
+ unsigned int StructSize;
+ unsigned int Offset;
+ int Access;
+ int (* Func)(SK_AC *pAc, SK_IOC pIo, int action,
+ SK_U32 Id, char* pBuf, unsigned int* pLen,
+ SK_U32 Instance, unsigned int TableIndex,
+ SK_U32 NetNumber);
+ SK_U16 Param;
+} SK_PNMI_TAB_ENTRY;
+
+
+/*
+ * Trap lengths
+ */
+#define SK_PNMI_TRAP_SIMPLE_LEN 17
+#define SK_PNMI_TRAP_SENSOR_LEN_BASE 46
+#define SK_PNMI_TRAP_RLMT_CHANGE_LEN 23
+#define SK_PNMI_TRAP_RLMT_PORT_LEN 23
+
+/*
+ * Number of MAC types supported
+ */
+#define SK_PNMI_MAC_TYPES (SK_MAC_GMAC + 1)
+
+/*
+ * MAC statistic data list (overall set for MAC types used)
+ */
+enum SK_MACSTATS {
+ SK_PNMI_HTX = 0,
+ SK_PNMI_HTX_OCTET,
+ SK_PNMI_HTX_OCTETHIGH = SK_PNMI_HTX_OCTET,
+ SK_PNMI_HTX_OCTETLOW,
+ SK_PNMI_HTX_BROADCAST,
+ SK_PNMI_HTX_MULTICAST,
+ SK_PNMI_HTX_UNICAST,
+ SK_PNMI_HTX_BURST,
+ SK_PNMI_HTX_PMACC,
+ SK_PNMI_HTX_MACC,
+ SK_PNMI_HTX_COL,
+ SK_PNMI_HTX_SINGLE_COL,
+ SK_PNMI_HTX_MULTI_COL,
+ SK_PNMI_HTX_EXCESS_COL,
+ SK_PNMI_HTX_LATE_COL,
+ SK_PNMI_HTX_DEFFERAL,
+ SK_PNMI_HTX_EXCESS_DEF,
+ SK_PNMI_HTX_UNDERRUN,
+ SK_PNMI_HTX_CARRIER,
+ SK_PNMI_HTX_UTILUNDER,
+ SK_PNMI_HTX_UTILOVER,
+ SK_PNMI_HTX_64,
+ SK_PNMI_HTX_127,
+ SK_PNMI_HTX_255,
+ SK_PNMI_HTX_511,
+ SK_PNMI_HTX_1023,
+ SK_PNMI_HTX_MAX,
+ SK_PNMI_HTX_LONGFRAMES,
+ SK_PNMI_HTX_SYNC,
+ SK_PNMI_HTX_SYNC_OCTET,
+ SK_PNMI_HTX_RESERVED,
+
+ SK_PNMI_HRX,
+ SK_PNMI_HRX_OCTET,
+ SK_PNMI_HRX_OCTETHIGH = SK_PNMI_HRX_OCTET,
+ SK_PNMI_HRX_OCTETLOW,
+ SK_PNMI_HRX_BADOCTET,
+ SK_PNMI_HRX_BADOCTETHIGH = SK_PNMI_HRX_BADOCTET,
+ SK_PNMI_HRX_BADOCTETLOW,
+ SK_PNMI_HRX_BROADCAST,
+ SK_PNMI_HRX_MULTICAST,
+ SK_PNMI_HRX_UNICAST,
+ SK_PNMI_HRX_PMACC,
+ SK_PNMI_HRX_MACC,
+ SK_PNMI_HRX_PMACC_ERR,
+ SK_PNMI_HRX_MACC_UNKWN,
+ SK_PNMI_HRX_BURST,
+ SK_PNMI_HRX_MISSED,
+ SK_PNMI_HRX_FRAMING,
+ SK_PNMI_HRX_UNDERSIZE,
+ SK_PNMI_HRX_OVERFLOW,
+ SK_PNMI_HRX_JABBER,
+ SK_PNMI_HRX_CARRIER,
+ SK_PNMI_HRX_IRLENGTH,
+ SK_PNMI_HRX_SYMBOL,
+ SK_PNMI_HRX_SHORTS,
+ SK_PNMI_HRX_RUNT,
+ SK_PNMI_HRX_TOO_LONG,
+ SK_PNMI_HRX_FCS,
+ SK_PNMI_HRX_CEXT,
+ SK_PNMI_HRX_UTILUNDER,
+ SK_PNMI_HRX_UTILOVER,
+ SK_PNMI_HRX_64,
+ SK_PNMI_HRX_127,
+ SK_PNMI_HRX_255,
+ SK_PNMI_HRX_511,
+ SK_PNMI_HRX_1023,
+ SK_PNMI_HRX_MAX,
+ SK_PNMI_HRX_LONGFRAMES,
+
+ SK_PNMI_HRX_RESERVED,
+
+ SK_PNMI_MAX_IDX /* NOTE: Ensure SK_PNMI_CNT_NO is set to this value */
+};
+
+/*
+ * MAC specific data
+ */
+typedef struct s_PnmiStatAddr {
+ SK_U16 Reg; /* MAC register containing the value */
+ SK_BOOL GetOffset; /* TRUE: Offset managed by PNMI (call GetStatVal())*/
+} SK_PNMI_STATADDR;
+
+
+/*
+ * SK_PNMI_STRUCT_DATA copy offset evaluation macros
+ */
+#define SK_PNMI_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_MAI_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_VPD_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_VPD *)0)->e))
+#define SK_PNMI_SEN_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_SENSOR *)0)->e))
+#define SK_PNMI_CHK_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_CHECKSUM *)0)->e))
+#define SK_PNMI_STA_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STAT *)0)->e))
+#define SK_PNMI_CNF_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_CONF *)0)->e))
+#define SK_PNMI_RLM_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT *)0)->e))
+#define SK_PNMI_MON_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT_MONITOR *)0)->e))
+#define SK_PNMI_TRP_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_TRAP *)0)->e))
+
+#define SK_PNMI_SET_STAT(b,s,o) {SK_U32 Val32; char *pVal; \
+ Val32 = (s); \
+ pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+ &(((SK_PNMI_STRUCT_DATA *)0)-> \
+ ReturnStatus.ErrorStatus)); \
+ SK_PNMI_STORE_U32(pVal, Val32); \
+ Val32 = (o); \
+ pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+ &(((SK_PNMI_STRUCT_DATA *)0)-> \
+ ReturnStatus.ErrorOffset)); \
+ SK_PNMI_STORE_U32(pVal, Val32);}
+
+/*
+ * Time macros
+ */
+#ifndef SK_PNMI_HUNDREDS_SEC
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t) (t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t) (((t) * 100) / (SK_TICKS_PER_SEC))
+#endif /* !SK_TICKS_PER_SEC */
+#endif /* !SK_PNMI_HUNDREDS_SEC */
+
+/*
+ * Macros to work around alignment problems
+ */
+#ifndef SK_PNMI_STORE_U16
+#define SK_PNMI_STORE_U16(p,v) {*(char *)(p) = *((char *)&(v)); \
+ *((char *)(p) + 1) = \
+ *(((char *)&(v)) + 1);}
+#endif
+
+#ifndef SK_PNMI_STORE_U32
+#define SK_PNMI_STORE_U32(p,v) {*(char *)(p) = *((char *)&(v)); \
+ *((char *)(p) + 1) = \
+ *(((char *)&(v)) + 1); \
+ *((char *)(p) + 2) = \
+ *(((char *)&(v)) + 2); \
+ *((char *)(p) + 3) = \
+ *(((char *)&(v)) + 3);}
+#endif
+
+#ifndef SK_PNMI_STORE_U64
+#define SK_PNMI_STORE_U64(p,v) {*(char *)(p) = *((char *)&(v)); \
+ *((char *)(p) + 1) = \
+ *(((char *)&(v)) + 1); \
+ *((char *)(p) + 2) = \
+ *(((char *)&(v)) + 2); \
+ *((char *)(p) + 3) = \
+ *(((char *)&(v)) + 3); \
+ *((char *)(p) + 4) = \
+ *(((char *)&(v)) + 4); \
+ *((char *)(p) + 5) = \
+ *(((char *)&(v)) + 5); \
+ *((char *)(p) + 6) = \
+ *(((char *)&(v)) + 6); \
+ *((char *)(p) + 7) = \
+ *(((char *)&(v)) + 7);}
+#endif
+
+#ifndef SK_PNMI_READ_U16
+#define SK_PNMI_READ_U16(p,v) {*((char *)&(v)) = *(char *)(p); \
+ *(((char *)&(v)) + 1) = \
+ *((char *)(p) + 1);}
+#endif
+
+#ifndef SK_PNMI_READ_U32
+#define SK_PNMI_READ_U32(p,v) {*((char *)&(v)) = *(char *)(p); \
+ *(((char *)&(v)) + 1) = \
+ *((char *)(p) + 1); \
+ *(((char *)&(v)) + 2) = \
+ *((char *)(p) + 2); \
+ *(((char *)&(v)) + 3) = \
+ *((char *)(p) + 3);}
+#endif
+
+#ifndef SK_PNMI_READ_U64
+#define SK_PNMI_READ_U64(p,v) {*((char *)&(v)) = *(char *)(p); \
+ *(((char *)&(v)) + 1) = \
+ *((char *)(p) + 1); \
+ *(((char *)&(v)) + 2) = \
+ *((char *)(p) + 2); \
+ *(((char *)&(v)) + 3) = \
+ *((char *)(p) + 3); \
+ *(((char *)&(v)) + 4) = \
+ *((char *)(p) + 4); \
+ *(((char *)&(v)) + 5) = \
+ *((char *)(p) + 5); \
+ *(((char *)&(v)) + 6) = \
+ *((char *)(p) + 6); \
+ *(((char *)&(v)) + 7) = \
+ *((char *)(p) + 7);}
+#endif
+
+/*
+ * Macros for Debug
+ */
+#ifdef DEBUG
+
+#define SK_PNMI_CHECKFLAGS(vSt) {if (pAC->Pnmi.MacUpdatedFlag > 0 || \
+ pAC->Pnmi.RlmtUpdatedFlag > 0 || \
+ pAC->Pnmi.SirqUpdatedFlag > 0) { \
+ SK_DBG_MSG(pAC, \
+ SK_DBGMOD_PNMI, \
+ SK_DBGCAT_CTRL, \
+ ("PNMI: ERR: %s MacUFlag=%d, RlmtUFlag=%d, SirqUFlag=%d\n", \
+ vSt, \
+ pAC->Pnmi.MacUpdatedFlag, \
+ pAC->Pnmi.RlmtUpdatedFlag, \
+ pAC->Pnmi.SirqUpdatedFlag))}}
+
+#else /* !DEBUG */
+
+#define SK_PNMI_CHECKFLAGS(vSt) /* Nothing */
+
+#endif /* !DEBUG */
+
+#endif /* _SKGEPNM2_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnmi.h b/drivers/net/sk98lin/h/skgepnmi.h
new file mode 100644
index 000000000000..1ed214ccb253
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnmi.h
@@ -0,0 +1,962 @@
+/*****************************************************************************
+ *
+ * Name: skgepnmi.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.62 $
+ * Date: $Date: 2003/08/15 12:31:52 $
+ * Purpose: Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _SKGEPNMI_H_
+#define _SKGEPNMI_H_
+
+/*
+ * Include dependencies
+ */
+#include "h/sktypes.h"
+#include "h/skerror.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skaddr.h"
+#include "h/skrlmt.h"
+#include "h/skvpd.h"
+
+/*
+ * Management Database Version
+ */
+#define SK_PNMI_MDB_VERSION 0x00030001 /* 3.1 */
+
+
+/*
+ * Event definitions
+ */
+#define SK_PNMI_EVT_SIRQ_OVERFLOW 1 /* Counter overflow */
+#define SK_PNMI_EVT_SEN_WAR_LOW 2 /* Lower war thres exceeded */
+#define SK_PNMI_EVT_SEN_WAR_UPP 3 /* Upper war thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_LOW 4 /* Lower err thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_UPP 5 /* Upper err thres exceeded */
+#define SK_PNMI_EVT_CHG_EST_TIMER 6 /* Timer event for RLMT Chg */
+#define SK_PNMI_EVT_UTILIZATION_TIMER 7 /* Timer event for Utiliza. */
+#define SK_PNMI_EVT_CLEAR_COUNTER 8 /* Clear statistic counters */
+#define SK_PNMI_EVT_XMAC_RESET 9 /* XMAC will be reset */
+
+#define SK_PNMI_EVT_RLMT_PORT_UP 10 /* Port came logically up */
+#define SK_PNMI_EVT_RLMT_PORT_DOWN 11 /* Port went logically down */
+#define SK_PNMI_EVT_RLMT_SEGMENTATION 13 /* Two SP root bridges found */
+#define SK_PNMI_EVT_RLMT_ACTIVE_DOWN 14 /* Port went logically down */
+#define SK_PNMI_EVT_RLMT_ACTIVE_UP 15 /* Port came logically up */
+#define SK_PNMI_EVT_RLMT_SET_NETS 16 /* 1. Parameter is number of nets
+ 1 = single net; 2 = dual net */
+#define SK_PNMI_EVT_VCT_RESET 17 /* VCT port reset timer event started with SET. */
+
+
+/*
+ * Return values
+ */
+#define SK_PNMI_ERR_OK 0
+#define SK_PNMI_ERR_GENERAL 1
+#define SK_PNMI_ERR_TOO_SHORT 2
+#define SK_PNMI_ERR_BAD_VALUE 3
+#define SK_PNMI_ERR_READ_ONLY 4
+#define SK_PNMI_ERR_UNKNOWN_OID 5
+#define SK_PNMI_ERR_UNKNOWN_INST 6
+#define SK_PNMI_ERR_UNKNOWN_NET 7
+#define SK_PNMI_ERR_NOT_SUPPORTED 10
+
+
+/*
+ * Return values of driver reset function SK_DRIVER_RESET() and
+ * driver event function SK_DRIVER_EVENT()
+ */
+#define SK_PNMI_ERR_OK 0
+#define SK_PNMI_ERR_FAIL 1
+
+
+/*
+ * Return values of driver test function SK_DRIVER_SELFTEST()
+ */
+#define SK_PNMI_TST_UNKNOWN (1 << 0)
+#define SK_PNMI_TST_TRANCEIVER (1 << 1)
+#define SK_PNMI_TST_ASIC (1 << 2)
+#define SK_PNMI_TST_SENSOR (1 << 3)
+#define SK_PNMI_TST_POWERMGMT (1 << 4)
+#define SK_PNMI_TST_PCI (1 << 5)
+#define SK_PNMI_TST_MAC (1 << 6)
+
+
+/*
+ * RLMT specific definitions
+ */
+#define SK_PNMI_RLMT_STATUS_STANDBY 1
+#define SK_PNMI_RLMT_STATUS_ACTIVE 2
+#define SK_PNMI_RLMT_STATUS_ERROR 3
+
+#define SK_PNMI_RLMT_LSTAT_PHY_DOWN 1
+#define SK_PNMI_RLMT_LSTAT_AUTONEG 2
+#define SK_PNMI_RLMT_LSTAT_LOG_DOWN 3
+#define SK_PNMI_RLMT_LSTAT_LOG_UP 4
+#define SK_PNMI_RLMT_LSTAT_INDETERMINATED 5
+
+#define SK_PNMI_RLMT_MODE_CHK_LINK (SK_RLMT_CHECK_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_RX (SK_RLMT_CHECK_LOC_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_SPT (SK_RLMT_CHECK_SEG)
+/* #define SK_PNMI_RLMT_MODE_CHK_EX */
+
+/*
+ * OID definition
+ */
+#ifndef _NDIS_ /* Check, whether NDIS already included OIDs */
+
+#define OID_GEN_XMIT_OK 0x00020101
+#define OID_GEN_RCV_OK 0x00020102
+#define OID_GEN_XMIT_ERROR 0x00020103
+#define OID_GEN_RCV_ERROR 0x00020104
+#define OID_GEN_RCV_NO_BUFFER 0x00020105
+
+/* #define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 */
+#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
+/* #define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 */
+#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
+/* #define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 */
+#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
+/* #define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 */
+#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
+/* #define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 */
+#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
+/* #define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B */
+#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
+#define OID_GEN_RCV_CRC_ERROR 0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
+
+#define OID_802_3_PERMANENT_ADDRESS 0x01010101
+#define OID_802_3_CURRENT_ADDRESS 0x01010102
+/* #define OID_802_3_MULTICAST_LIST 0x01010103 */
+/* #define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 */
+/* #define OID_802_3_MAC_OPTIONS 0x01010105 */
+
+#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION 0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
+#define OID_802_3_XMIT_DEFERRED 0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202
+#define OID_802_3_RCV_OVERRUN 0x01020203
+#define OID_802_3_XMIT_UNDERRUN 0x01020204
+#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
+
+/*
+ * PnP and PM OIDs
+ */
+#ifdef SK_POWER_MGMT
+#define OID_PNP_CAPABILITIES 0xFD010100
+#define OID_PNP_SET_POWER 0xFD010101
+#define OID_PNP_QUERY_POWER 0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
+#endif /* SK_POWER_MGMT */
+
+#endif /* _NDIS_ */
+
+#define OID_SKGE_MDB_VERSION 0xFF010100
+#define OID_SKGE_SUPPORTED_LIST 0xFF010101
+#define OID_SKGE_VPD_FREE_BYTES 0xFF010102
+#define OID_SKGE_VPD_ENTRIES_LIST 0xFF010103
+#define OID_SKGE_VPD_ENTRIES_NUMBER 0xFF010104
+#define OID_SKGE_VPD_KEY 0xFF010105
+#define OID_SKGE_VPD_VALUE 0xFF010106
+#define OID_SKGE_VPD_ACCESS 0xFF010107
+#define OID_SKGE_VPD_ACTION 0xFF010108
+
+#define OID_SKGE_PORT_NUMBER 0xFF010110
+#define OID_SKGE_DEVICE_TYPE 0xFF010111
+#define OID_SKGE_DRIVER_DESCR 0xFF010112
+#define OID_SKGE_DRIVER_VERSION 0xFF010113
+#define OID_SKGE_HW_DESCR 0xFF010114
+#define OID_SKGE_HW_VERSION 0xFF010115
+#define OID_SKGE_CHIPSET 0xFF010116
+#define OID_SKGE_ACTION 0xFF010117
+#define OID_SKGE_RESULT 0xFF010118
+#define OID_SKGE_BUS_TYPE 0xFF010119
+#define OID_SKGE_BUS_SPEED 0xFF01011A
+#define OID_SKGE_BUS_WIDTH 0xFF01011B
+/* 0xFF01011C unused */
+#define OID_SKGE_DIAG_ACTION 0xFF01011D
+#define OID_SKGE_DIAG_RESULT 0xFF01011E
+#define OID_SKGE_MTU 0xFF01011F
+#define OID_SKGE_PHYS_CUR_ADDR 0xFF010120
+#define OID_SKGE_PHYS_FAC_ADDR 0xFF010121
+#define OID_SKGE_PMD 0xFF010122
+#define OID_SKGE_CONNECTOR 0xFF010123
+#define OID_SKGE_LINK_CAP 0xFF010124
+#define OID_SKGE_LINK_MODE 0xFF010125
+#define OID_SKGE_LINK_MODE_STATUS 0xFF010126
+#define OID_SKGE_LINK_STATUS 0xFF010127
+#define OID_SKGE_FLOWCTRL_CAP 0xFF010128
+#define OID_SKGE_FLOWCTRL_MODE 0xFF010129
+#define OID_SKGE_FLOWCTRL_STATUS 0xFF01012A
+#define OID_SKGE_PHY_OPERATION_CAP 0xFF01012B
+#define OID_SKGE_PHY_OPERATION_MODE 0xFF01012C
+#define OID_SKGE_PHY_OPERATION_STATUS 0xFF01012D
+#define OID_SKGE_MULTICAST_LIST 0xFF01012E
+#define OID_SKGE_CURRENT_PACKET_FILTER 0xFF01012F
+
+#define OID_SKGE_TRAP 0xFF010130
+#define OID_SKGE_TRAP_NUMBER 0xFF010131
+
+#define OID_SKGE_RLMT_MODE 0xFF010140
+#define OID_SKGE_RLMT_PORT_NUMBER 0xFF010141
+#define OID_SKGE_RLMT_PORT_ACTIVE 0xFF010142
+#define OID_SKGE_RLMT_PORT_PREFERRED 0xFF010143
+#define OID_SKGE_INTERMEDIATE_SUPPORT 0xFF010160
+
+#define OID_SKGE_SPEED_CAP 0xFF010170
+#define OID_SKGE_SPEED_MODE 0xFF010171
+#define OID_SKGE_SPEED_STATUS 0xFF010172
+
+#define OID_SKGE_BOARDLEVEL 0xFF010180
+
+#define OID_SKGE_SENSOR_NUMBER 0xFF020100
+#define OID_SKGE_SENSOR_INDEX 0xFF020101
+#define OID_SKGE_SENSOR_DESCR 0xFF020102
+#define OID_SKGE_SENSOR_TYPE 0xFF020103
+#define OID_SKGE_SENSOR_VALUE 0xFF020104
+#define OID_SKGE_SENSOR_WAR_THRES_LOW 0xFF020105
+#define OID_SKGE_SENSOR_WAR_THRES_UPP 0xFF020106
+#define OID_SKGE_SENSOR_ERR_THRES_LOW 0xFF020107
+#define OID_SKGE_SENSOR_ERR_THRES_UPP 0xFF020108
+#define OID_SKGE_SENSOR_STATUS 0xFF020109
+#define OID_SKGE_SENSOR_WAR_CTS 0xFF02010A
+#define OID_SKGE_SENSOR_ERR_CTS 0xFF02010B
+#define OID_SKGE_SENSOR_WAR_TIME 0xFF02010C
+#define OID_SKGE_SENSOR_ERR_TIME 0xFF02010D
+
+#define OID_SKGE_CHKSM_NUMBER 0xFF020110
+#define OID_SKGE_CHKSM_RX_OK_CTS 0xFF020111
+#define OID_SKGE_CHKSM_RX_UNABLE_CTS 0xFF020112
+#define OID_SKGE_CHKSM_RX_ERR_CTS 0xFF020113
+#define OID_SKGE_CHKSM_TX_OK_CTS 0xFF020114
+#define OID_SKGE_CHKSM_TX_UNABLE_CTS 0xFF020115
+
+#define OID_SKGE_STAT_TX 0xFF020120
+#define OID_SKGE_STAT_TX_OCTETS 0xFF020121
+#define OID_SKGE_STAT_TX_BROADCAST 0xFF020122
+#define OID_SKGE_STAT_TX_MULTICAST 0xFF020123
+#define OID_SKGE_STAT_TX_UNICAST 0xFF020124
+#define OID_SKGE_STAT_TX_LONGFRAMES 0xFF020125
+#define OID_SKGE_STAT_TX_BURST 0xFF020126
+#define OID_SKGE_STAT_TX_PFLOWC 0xFF020127
+#define OID_SKGE_STAT_TX_FLOWC 0xFF020128
+#define OID_SKGE_STAT_TX_SINGLE_COL 0xFF020129
+#define OID_SKGE_STAT_TX_MULTI_COL 0xFF02012A
+#define OID_SKGE_STAT_TX_EXCESS_COL 0xFF02012B
+#define OID_SKGE_STAT_TX_LATE_COL 0xFF02012C
+#define OID_SKGE_STAT_TX_DEFFERAL 0xFF02012D
+#define OID_SKGE_STAT_TX_EXCESS_DEF 0xFF02012E
+#define OID_SKGE_STAT_TX_UNDERRUN 0xFF02012F
+#define OID_SKGE_STAT_TX_CARRIER 0xFF020130
+/* #define OID_SKGE_STAT_TX_UTIL 0xFF020131 */
+#define OID_SKGE_STAT_TX_64 0xFF020132
+#define OID_SKGE_STAT_TX_127 0xFF020133
+#define OID_SKGE_STAT_TX_255 0xFF020134
+#define OID_SKGE_STAT_TX_511 0xFF020135
+#define OID_SKGE_STAT_TX_1023 0xFF020136
+#define OID_SKGE_STAT_TX_MAX 0xFF020137
+#define OID_SKGE_STAT_TX_SYNC 0xFF020138
+#define OID_SKGE_STAT_TX_SYNC_OCTETS 0xFF020139
+#define OID_SKGE_STAT_RX 0xFF02013A
+#define OID_SKGE_STAT_RX_OCTETS 0xFF02013B
+#define OID_SKGE_STAT_RX_BROADCAST 0xFF02013C
+#define OID_SKGE_STAT_RX_MULTICAST 0xFF02013D
+#define OID_SKGE_STAT_RX_UNICAST 0xFF02013E
+#define OID_SKGE_STAT_RX_PFLOWC 0xFF02013F
+#define OID_SKGE_STAT_RX_FLOWC 0xFF020140
+#define OID_SKGE_STAT_RX_PFLOWC_ERR 0xFF020141
+#define OID_SKGE_STAT_RX_FLOWC_UNKWN 0xFF020142
+#define OID_SKGE_STAT_RX_BURST 0xFF020143
+#define OID_SKGE_STAT_RX_MISSED 0xFF020144
+#define OID_SKGE_STAT_RX_FRAMING 0xFF020145
+#define OID_SKGE_STAT_RX_OVERFLOW 0xFF020146
+#define OID_SKGE_STAT_RX_JABBER 0xFF020147
+#define OID_SKGE_STAT_RX_CARRIER 0xFF020148
+#define OID_SKGE_STAT_RX_IR_LENGTH 0xFF020149
+#define OID_SKGE_STAT_RX_SYMBOL 0xFF02014A
+#define OID_SKGE_STAT_RX_SHORTS 0xFF02014B
+#define OID_SKGE_STAT_RX_RUNT 0xFF02014C
+#define OID_SKGE_STAT_RX_CEXT 0xFF02014D
+#define OID_SKGE_STAT_RX_TOO_LONG 0xFF02014E
+#define OID_SKGE_STAT_RX_FCS 0xFF02014F
+/* #define OID_SKGE_STAT_RX_UTIL 0xFF020150 */
+#define OID_SKGE_STAT_RX_64 0xFF020151
+#define OID_SKGE_STAT_RX_127 0xFF020152
+#define OID_SKGE_STAT_RX_255 0xFF020153
+#define OID_SKGE_STAT_RX_511 0xFF020154
+#define OID_SKGE_STAT_RX_1023 0xFF020155
+#define OID_SKGE_STAT_RX_MAX 0xFF020156
+#define OID_SKGE_STAT_RX_LONGFRAMES 0xFF020157
+
+#define OID_SKGE_RLMT_CHANGE_CTS 0xFF020160
+#define OID_SKGE_RLMT_CHANGE_TIME 0xFF020161
+#define OID_SKGE_RLMT_CHANGE_ESTIM 0xFF020162
+#define OID_SKGE_RLMT_CHANGE_THRES 0xFF020163
+
+#define OID_SKGE_RLMT_PORT_INDEX 0xFF020164
+#define OID_SKGE_RLMT_STATUS 0xFF020165
+#define OID_SKGE_RLMT_TX_HELLO_CTS 0xFF020166
+#define OID_SKGE_RLMT_RX_HELLO_CTS 0xFF020167
+#define OID_SKGE_RLMT_TX_SP_REQ_CTS 0xFF020168
+#define OID_SKGE_RLMT_RX_SP_CTS 0xFF020169
+
+#define OID_SKGE_RLMT_MONITOR_NUMBER 0xFF010150
+#define OID_SKGE_RLMT_MONITOR_INDEX 0xFF010151
+#define OID_SKGE_RLMT_MONITOR_ADDR 0xFF010152
+#define OID_SKGE_RLMT_MONITOR_ERRS 0xFF010153
+#define OID_SKGE_RLMT_MONITOR_TIMESTAMP 0xFF010154
+#define OID_SKGE_RLMT_MONITOR_ADMIN 0xFF010155
+
+#define OID_SKGE_TX_SW_QUEUE_LEN 0xFF020170
+#define OID_SKGE_TX_SW_QUEUE_MAX 0xFF020171
+#define OID_SKGE_TX_RETRY 0xFF020172
+#define OID_SKGE_RX_INTR_CTS 0xFF020173
+#define OID_SKGE_TX_INTR_CTS 0xFF020174
+#define OID_SKGE_RX_NO_BUF_CTS 0xFF020175
+#define OID_SKGE_TX_NO_BUF_CTS 0xFF020176
+#define OID_SKGE_TX_USED_DESCR_NO 0xFF020177
+#define OID_SKGE_RX_DELIVERED_CTS 0xFF020178
+#define OID_SKGE_RX_OCTETS_DELIV_CTS 0xFF020179
+#define OID_SKGE_RX_HW_ERROR_CTS 0xFF02017A
+#define OID_SKGE_TX_HW_ERROR_CTS 0xFF02017B
+#define OID_SKGE_IN_ERRORS_CTS 0xFF02017C
+#define OID_SKGE_OUT_ERROR_CTS 0xFF02017D
+#define OID_SKGE_ERR_RECOVERY_CTS 0xFF02017E
+#define OID_SKGE_SYSUPTIME 0xFF02017F
+
+#define OID_SKGE_ALL_DATA 0xFF020190
+
+/* Defines for VCT. */
+#define OID_SKGE_VCT_GET 0xFF020200
+#define OID_SKGE_VCT_SET 0xFF020201
+#define OID_SKGE_VCT_STATUS 0xFF020202
+
+#ifdef SK_DIAG_SUPPORT
+/* Defines for driver DIAG mode. */
+#define OID_SKGE_DIAG_MODE 0xFF020204
+#endif /* SK_DIAG_SUPPORT */
+
+/* New OIDs */
+#define OID_SKGE_DRIVER_RELDATE 0xFF020210
+#define OID_SKGE_DRIVER_FILENAME 0xFF020211
+#define OID_SKGE_CHIPID 0xFF020212
+#define OID_SKGE_RAMSIZE 0xFF020213
+#define OID_SKGE_VAUXAVAIL 0xFF020214
+#define OID_SKGE_PHY_TYPE 0xFF020215
+#define OID_SKGE_PHY_LP_MODE 0xFF020216
+
+/* VCT struct to store a backup copy of VCT data after a port reset. */
+typedef struct s_PnmiVct {
+ SK_U8 VctStatus;
+ SK_U8 PCableLen;
+ SK_U32 PMdiPairLen[4];
+ SK_U8 PMdiPairSts[4];
+} SK_PNMI_VCT;
+
+
+/* VCT status values (to be given to CPA via OID_SKGE_VCT_STATUS). */
+#define SK_PNMI_VCT_NONE 0
+#define SK_PNMI_VCT_OLD_VCT_DATA 1
+#define SK_PNMI_VCT_NEW_VCT_DATA 2
+#define SK_PNMI_VCT_OLD_DSP_DATA 4
+#define SK_PNMI_VCT_NEW_DSP_DATA 8
+#define SK_PNMI_VCT_RUNNING 16
+
+
+/* VCT cable test status. */
+#define SK_PNMI_VCT_NORMAL_CABLE 0
+#define SK_PNMI_VCT_SHORT_CABLE 1
+#define SK_PNMI_VCT_OPEN_CABLE 2
+#define SK_PNMI_VCT_TEST_FAIL 3
+#define SK_PNMI_VCT_IMPEDANCE_MISMATCH 4
+
+#define OID_SKGE_TRAP_SEN_WAR_LOW 500
+#define OID_SKGE_TRAP_SEN_WAR_UPP 501
+#define OID_SKGE_TRAP_SEN_ERR_LOW 502
+#define OID_SKGE_TRAP_SEN_ERR_UPP 503
+#define OID_SKGE_TRAP_RLMT_CHANGE_THRES 520
+#define OID_SKGE_TRAP_RLMT_CHANGE_PORT 521
+#define OID_SKGE_TRAP_RLMT_PORT_DOWN 522
+#define OID_SKGE_TRAP_RLMT_PORT_UP 523
+#define OID_SKGE_TRAP_RLMT_SEGMENTATION 524
+
+#ifdef SK_DIAG_SUPPORT
+/* Defines for driver DIAG mode. */
+#define SK_DIAG_ATTACHED 2
+#define SK_DIAG_RUNNING 1
+#define SK_DIAG_IDLE 0
+#endif /* SK_DIAG_SUPPORT */
+
+/*
+ * Generic PNMI IOCTL subcommand definitions.
+ */
+#define SK_GET_SINGLE_VAR 1
+#define SK_SET_SINGLE_VAR 2
+#define SK_PRESET_SINGLE_VAR 3
+#define SK_GET_FULL_MIB 4
+#define SK_SET_FULL_MIB 5
+#define SK_PRESET_FULL_MIB 6
+
+
+/*
+ * Define error numbers and messages for syslog
+ */
+#define SK_PNMI_ERR001 (SK_ERRBASE_PNMI + 1)
+#define SK_PNMI_ERR001MSG "SkPnmiGetStruct: Unknown OID"
+#define SK_PNMI_ERR002 (SK_ERRBASE_PNMI + 2)
+#define SK_PNMI_ERR002MSG "SkPnmiGetStruct: Cannot read VPD keys"
+#define SK_PNMI_ERR003 (SK_ERRBASE_PNMI + 3)
+#define SK_PNMI_ERR003MSG "OidStruct: Called with wrong OID"
+#define SK_PNMI_ERR004 (SK_ERRBASE_PNMI + 4)
+#define SK_PNMI_ERR004MSG "OidStruct: Called with wrong action"
+#define SK_PNMI_ERR005 (SK_ERRBASE_PNMI + 5)
+#define SK_PNMI_ERR005MSG "Perform: Cannot reset driver"
+#define SK_PNMI_ERR006 (SK_ERRBASE_PNMI + 6)
+#define SK_PNMI_ERR006MSG "Perform: Unknown OID action command"
+#define SK_PNMI_ERR007 (SK_ERRBASE_PNMI + 7)
+#define SK_PNMI_ERR007MSG "General: Driver description not initialized"
+#define SK_PNMI_ERR008 (SK_ERRBASE_PNMI + 8)
+#define SK_PNMI_ERR008MSG "Addr: Tried to get unknown OID"
+#define SK_PNMI_ERR009 (SK_ERRBASE_PNMI + 9)
+#define SK_PNMI_ERR009MSG "Addr: Unknown OID"
+#define SK_PNMI_ERR010 (SK_ERRBASE_PNMI + 10)
+#define SK_PNMI_ERR010MSG "CsumStat: Unknown OID"
+#define SK_PNMI_ERR011 (SK_ERRBASE_PNMI + 11)
+#define SK_PNMI_ERR011MSG "SensorStat: Sensor descr string too long"
+#define SK_PNMI_ERR012 (SK_ERRBASE_PNMI + 12)
+#define SK_PNMI_ERR012MSG "SensorStat: Unknown OID"
+#define SK_PNMI_ERR013 (SK_ERRBASE_PNMI + 13)
+#define SK_PNMI_ERR013MSG ""
+#define SK_PNMI_ERR014 (SK_ERRBASE_PNMI + 14)
+#define SK_PNMI_ERR014MSG "Vpd: Cannot read VPD keys"
+#define SK_PNMI_ERR015 (SK_ERRBASE_PNMI + 15)
+#define SK_PNMI_ERR015MSG "Vpd: Internal array for VPD keys to small"
+#define SK_PNMI_ERR016 (SK_ERRBASE_PNMI + 16)
+#define SK_PNMI_ERR016MSG "Vpd: Key string too long"
+#define SK_PNMI_ERR017 (SK_ERRBASE_PNMI + 17)
+#define SK_PNMI_ERR017MSG "Vpd: Invalid VPD status pointer"
+#define SK_PNMI_ERR018 (SK_ERRBASE_PNMI + 18)
+#define SK_PNMI_ERR018MSG "Vpd: VPD data not valid"
+#define SK_PNMI_ERR019 (SK_ERRBASE_PNMI + 19)
+#define SK_PNMI_ERR019MSG "Vpd: VPD entries list string too long"
+#define SK_PNMI_ERR021 (SK_ERRBASE_PNMI + 21)
+#define SK_PNMI_ERR021MSG "Vpd: VPD data string too long"
+#define SK_PNMI_ERR022 (SK_ERRBASE_PNMI + 22)
+#define SK_PNMI_ERR022MSG "Vpd: VPD data string too long should be errored before"
+#define SK_PNMI_ERR023 (SK_ERRBASE_PNMI + 23)
+#define SK_PNMI_ERR023MSG "Vpd: Unknown OID in get action"
+#define SK_PNMI_ERR024 (SK_ERRBASE_PNMI + 24)
+#define SK_PNMI_ERR024MSG "Vpd: Unknown OID in preset/set action"
+#define SK_PNMI_ERR025 (SK_ERRBASE_PNMI + 25)
+#define SK_PNMI_ERR025MSG "Vpd: Cannot write VPD after modify entry"
+#define SK_PNMI_ERR026 (SK_ERRBASE_PNMI + 26)
+#define SK_PNMI_ERR026MSG "Vpd: Cannot update VPD"
+#define SK_PNMI_ERR027 (SK_ERRBASE_PNMI + 27)
+#define SK_PNMI_ERR027MSG "Vpd: Cannot delete VPD entry"
+#define SK_PNMI_ERR028 (SK_ERRBASE_PNMI + 28)
+#define SK_PNMI_ERR028MSG "Vpd: Cannot update VPD after delete entry"
+#define SK_PNMI_ERR029 (SK_ERRBASE_PNMI + 29)
+#define SK_PNMI_ERR029MSG "General: Driver description string too long"
+#define SK_PNMI_ERR030 (SK_ERRBASE_PNMI + 30)
+#define SK_PNMI_ERR030MSG "General: Driver version not initialized"
+#define SK_PNMI_ERR031 (SK_ERRBASE_PNMI + 31)
+#define SK_PNMI_ERR031MSG "General: Driver version string too long"
+#define SK_PNMI_ERR032 (SK_ERRBASE_PNMI + 32)
+#define SK_PNMI_ERR032MSG "General: Cannot read VPD Name for HW descr"
+#define SK_PNMI_ERR033 (SK_ERRBASE_PNMI + 33)
+#define SK_PNMI_ERR033MSG "General: HW description string too long"
+#define SK_PNMI_ERR034 (SK_ERRBASE_PNMI + 34)
+#define SK_PNMI_ERR034MSG "General: Unknown OID"
+#define SK_PNMI_ERR035 (SK_ERRBASE_PNMI + 35)
+#define SK_PNMI_ERR035MSG "Rlmt: Unknown OID"
+#define SK_PNMI_ERR036 (SK_ERRBASE_PNMI + 36)
+#define SK_PNMI_ERR036MSG ""
+#define SK_PNMI_ERR037 (SK_ERRBASE_PNMI + 37)
+#define SK_PNMI_ERR037MSG "Rlmt: SK_RLMT_MODE_CHANGE event return not 0"
+#define SK_PNMI_ERR038 (SK_ERRBASE_PNMI + 38)
+#define SK_PNMI_ERR038MSG "Rlmt: SK_RLMT_PREFPORT_CHANGE event return not 0"
+#define SK_PNMI_ERR039 (SK_ERRBASE_PNMI + 39)
+#define SK_PNMI_ERR039MSG "RlmtStat: Unknown OID"
+#define SK_PNMI_ERR040 (SK_ERRBASE_PNMI + 40)
+#define SK_PNMI_ERR040MSG "PowerManagement: Unknown OID"
+#define SK_PNMI_ERR041 (SK_ERRBASE_PNMI + 41)
+#define SK_PNMI_ERR041MSG "MacPrivateConf: Unknown OID"
+#define SK_PNMI_ERR042 (SK_ERRBASE_PNMI + 42)
+#define SK_PNMI_ERR042MSG "MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
+#define SK_PNMI_ERR043 (SK_ERRBASE_PNMI + 43)
+#define SK_PNMI_ERR043MSG "MacPrivateConf: SK_HWEV_SET_LMODE returned not 0"
+#define SK_PNMI_ERR044 (SK_ERRBASE_PNMI + 44)
+#define SK_PNMI_ERR044MSG "MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0"
+#define SK_PNMI_ERR045 (SK_ERRBASE_PNMI + 45)
+#define SK_PNMI_ERR045MSG "MacPrivateConf: SK_HWEV_SET_SPEED returned not 0"
+#define SK_PNMI_ERR046 (SK_ERRBASE_PNMI + 46)
+#define SK_PNMI_ERR046MSG "Monitor: Unknown OID"
+#define SK_PNMI_ERR047 (SK_ERRBASE_PNMI + 47)
+#define SK_PNMI_ERR047MSG "SirqUpdate: Event function returns not 0"
+#define SK_PNMI_ERR048 (SK_ERRBASE_PNMI + 48)
+#define SK_PNMI_ERR048MSG "RlmtUpdate: Event function returns not 0"
+#define SK_PNMI_ERR049 (SK_ERRBASE_PNMI + 49)
+#define SK_PNMI_ERR049MSG "SkPnmiInit: Invalid size of 'CounterOffset' struct!!"
+#define SK_PNMI_ERR050 (SK_ERRBASE_PNMI + 50)
+#define SK_PNMI_ERR050MSG "SkPnmiInit: Invalid size of 'StatAddr' table!!"
+#define SK_PNMI_ERR051 (SK_ERRBASE_PNMI + 51)
+#define SK_PNMI_ERR051MSG "SkPnmiEvent: Port switch suspicious"
+#define SK_PNMI_ERR052 (SK_ERRBASE_PNMI + 52)
+#define SK_PNMI_ERR052MSG ""
+#define SK_PNMI_ERR053 (SK_ERRBASE_PNMI + 53)
+#define SK_PNMI_ERR053MSG "General: Driver release date not initialized"
+#define SK_PNMI_ERR054 (SK_ERRBASE_PNMI + 54)
+#define SK_PNMI_ERR054MSG "General: Driver release date string too long"
+#define SK_PNMI_ERR055 (SK_ERRBASE_PNMI + 55)
+#define SK_PNMI_ERR055MSG "General: Driver file name not initialized"
+#define SK_PNMI_ERR056 (SK_ERRBASE_PNMI + 56)
+#define SK_PNMI_ERR056MSG "General: Driver file name string too long"
+
+/*
+ * Management counter macros called by the driver
+ */
+#define SK_PNMI_SET_DRIVER_DESCR(pAC,v) ((pAC)->Pnmi.pDriverDescription = \
+ (char *)(v))
+
+#define SK_PNMI_SET_DRIVER_VER(pAC,v) ((pAC)->Pnmi.pDriverVersion = \
+ (char *)(v))
+
+#define SK_PNMI_SET_DRIVER_RELDATE(pAC,v) ((pAC)->Pnmi.pDriverReleaseDate = \
+ (char *)(v))
+
+#define SK_PNMI_SET_DRIVER_FILENAME(pAC,v) ((pAC)->Pnmi.pDriverFileName = \
+ (char *)(v))
+
+#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \
+ { \
+ (pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \
+ if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \
+ (pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \
+ } \
+ }
+#define SK_PNMI_CNT_TX_RETRY(pAC,p) (((pAC)->Pnmi.Port[p].TxRetryCts)++)
+#define SK_PNMI_CNT_RX_INTR(pAC,p) (((pAC)->Pnmi.Port[p].RxIntrCts)++)
+#define SK_PNMI_CNT_TX_INTR(pAC,p) (((pAC)->Pnmi.Port[p].TxIntrCts)++)
+#define SK_PNMI_CNT_NO_RX_BUF(pAC,p) (((pAC)->Pnmi.Port[p].RxNoBufCts)++)
+#define SK_PNMI_CNT_NO_TX_BUF(pAC,p) (((pAC)->Pnmi.Port[p].TxNoBufCts)++)
+#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \
+ ((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v));
+#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \
+ { \
+ ((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \
+ (pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \
+ }
+#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p) (((pAC)->Pnmi.Port[p].ErrRecoveryCts)++);
+
+#define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \
+ { \
+ if ((p) < SK_MAX_MACS) { \
+ ((pAC)->Pnmi.Port[p].StatSyncCts)++; \
+ (pAC)->Pnmi.Port[p].StatSyncOctetsCts += (SK_U64)(v); \
+ } \
+ }
+
+#define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \
+ { \
+ if ((p) < SK_MAX_MACS) { \
+ ((pAC)->Pnmi.Port[p].StatRxLongFrameCts++); \
+ } \
+ }
+
+#define SK_PNMI_CNT_RX_FRAMETOOLONG(pAC,p) \
+ { \
+ if ((p) < SK_MAX_MACS) { \
+ ((pAC)->Pnmi.Port[p].StatRxFrameTooLongCts++); \
+ } \
+ }
+
+#define SK_PNMI_CNT_RX_PMACC_ERR(pAC,p) \
+ { \
+ if ((p) < SK_MAX_MACS) { \
+ ((pAC)->Pnmi.Port[p].StatRxPMaccErr++); \
+ } \
+ }
+
+/*
+ * Conversion Macros
+ */
+#define SK_PNMI_PORT_INST2LOG(i) ((unsigned int)(i) - 1)
+#define SK_PNMI_PORT_LOG2INST(l) ((unsigned int)(l) + 1)
+#define SK_PNMI_PORT_PHYS2LOG(p) ((unsigned int)(p) + 1)
+#define SK_PNMI_PORT_LOG2PHYS(pAC,l) ((unsigned int)(l) - 1)
+#define SK_PNMI_PORT_PHYS2INST(pAC,p) \
+ (pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2))
+#define SK_PNMI_PORT_INST2PHYS(pAC,i) ((unsigned int)(i) - 2)
+
+/*
+ * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct
+ */
+#define SK_PNMI_VPD_KEY_SIZE 5
+#define SK_PNMI_VPD_BUFSIZE (VPD_SIZE)
+#define SK_PNMI_VPD_ENTRIES (VPD_SIZE / 4)
+#define SK_PNMI_VPD_DATALEN 128 /* Number of data bytes */
+
+#define SK_PNMI_MULTICAST_LISTLEN 64
+#define SK_PNMI_SENSOR_ENTRIES (SK_MAX_SENSORS)
+#define SK_PNMI_CHECKSUM_ENTRIES 3
+#define SK_PNMI_MAC_ENTRIES (SK_MAX_MACS + 1)
+#define SK_PNMI_MONITOR_ENTRIES 20
+#define SK_PNMI_TRAP_ENTRIES 10
+#define SK_PNMI_TRAPLEN 128
+#define SK_PNMI_STRINGLEN1 80
+#define SK_PNMI_STRINGLEN2 25
+#define SK_PNMI_TRAP_QUEUE_LEN 512
+
+typedef struct s_PnmiVpd {
+ char VpdKey[SK_PNMI_VPD_KEY_SIZE];
+ char VpdValue[SK_PNMI_VPD_DATALEN];
+ SK_U8 VpdAccess;
+ SK_U8 VpdAction;
+} SK_PNMI_VPD;
+
+typedef struct s_PnmiSensor {
+ SK_U8 SensorIndex;
+ char SensorDescr[SK_PNMI_STRINGLEN2];
+ SK_U8 SensorType;
+ SK_U32 SensorValue;
+ SK_U32 SensorWarningThresholdLow;
+ SK_U32 SensorWarningThresholdHigh;
+ SK_U32 SensorErrorThresholdLow;
+ SK_U32 SensorErrorThresholdHigh;
+ SK_U8 SensorStatus;
+ SK_U64 SensorWarningCts;
+ SK_U64 SensorErrorCts;
+ SK_U64 SensorWarningTimestamp;
+ SK_U64 SensorErrorTimestamp;
+} SK_PNMI_SENSOR;
+
+typedef struct s_PnmiChecksum {
+ SK_U64 ChecksumRxOkCts;
+ SK_U64 ChecksumRxUnableCts;
+ SK_U64 ChecksumRxErrCts;
+ SK_U64 ChecksumTxOkCts;
+ SK_U64 ChecksumTxUnableCts;
+} SK_PNMI_CHECKSUM;
+
+typedef struct s_PnmiStat {
+ SK_U64 StatTxOkCts;
+ SK_U64 StatTxOctetsOkCts;
+ SK_U64 StatTxBroadcastOkCts;
+ SK_U64 StatTxMulticastOkCts;
+ SK_U64 StatTxUnicastOkCts;
+ SK_U64 StatTxLongFramesCts;
+ SK_U64 StatTxBurstCts;
+ SK_U64 StatTxPauseMacCtrlCts;
+ SK_U64 StatTxMacCtrlCts;
+ SK_U64 StatTxSingleCollisionCts;
+ SK_U64 StatTxMultipleCollisionCts;
+ SK_U64 StatTxExcessiveCollisionCts;
+ SK_U64 StatTxLateCollisionCts;
+ SK_U64 StatTxDeferralCts;
+ SK_U64 StatTxExcessiveDeferralCts;
+ SK_U64 StatTxFifoUnderrunCts;
+ SK_U64 StatTxCarrierCts;
+ SK_U64 Dummy1; /* StatTxUtilization */
+ SK_U64 StatTx64Cts;
+ SK_U64 StatTx127Cts;
+ SK_U64 StatTx255Cts;
+ SK_U64 StatTx511Cts;
+ SK_U64 StatTx1023Cts;
+ SK_U64 StatTxMaxCts;
+ SK_U64 StatTxSyncCts;
+ SK_U64 StatTxSyncOctetsCts;
+ SK_U64 StatRxOkCts;
+ SK_U64 StatRxOctetsOkCts;
+ SK_U64 StatRxBroadcastOkCts;
+ SK_U64 StatRxMulticastOkCts;
+ SK_U64 StatRxUnicastOkCts;
+ SK_U64 StatRxLongFramesCts;
+ SK_U64 StatRxPauseMacCtrlCts;
+ SK_U64 StatRxMacCtrlCts;
+ SK_U64 StatRxPauseMacCtrlErrorCts;
+ SK_U64 StatRxMacCtrlUnknownCts;
+ SK_U64 StatRxBurstCts;
+ SK_U64 StatRxMissedCts;
+ SK_U64 StatRxFramingCts;
+ SK_U64 StatRxFifoOverflowCts;
+ SK_U64 StatRxJabberCts;
+ SK_U64 StatRxCarrierCts;
+ SK_U64 StatRxIRLengthCts;
+ SK_U64 StatRxSymbolCts;
+ SK_U64 StatRxShortsCts;
+ SK_U64 StatRxRuntCts;
+ SK_U64 StatRxCextCts;
+ SK_U64 StatRxTooLongCts;
+ SK_U64 StatRxFcsCts;
+ SK_U64 Dummy2; /* StatRxUtilization */
+ SK_U64 StatRx64Cts;
+ SK_U64 StatRx127Cts;
+ SK_U64 StatRx255Cts;
+ SK_U64 StatRx511Cts;
+ SK_U64 StatRx1023Cts;
+ SK_U64 StatRxMaxCts;
+} SK_PNMI_STAT;
+
+typedef struct s_PnmiConf {
+ char ConfMacCurrentAddr[6];
+ char ConfMacFactoryAddr[6];
+ SK_U8 ConfPMD;
+ SK_U8 ConfConnector;
+ SK_U32 ConfPhyType;
+ SK_U32 ConfPhyMode;
+ SK_U8 ConfLinkCapability;
+ SK_U8 ConfLinkMode;
+ SK_U8 ConfLinkModeStatus;
+ SK_U8 ConfLinkStatus;
+ SK_U8 ConfFlowCtrlCapability;
+ SK_U8 ConfFlowCtrlMode;
+ SK_U8 ConfFlowCtrlStatus;
+ SK_U8 ConfPhyOperationCapability;
+ SK_U8 ConfPhyOperationMode;
+ SK_U8 ConfPhyOperationStatus;
+ SK_U8 ConfSpeedCapability;
+ SK_U8 ConfSpeedMode;
+ SK_U8 ConfSpeedStatus;
+} SK_PNMI_CONF;
+
+typedef struct s_PnmiRlmt {
+ SK_U32 RlmtIndex;
+ SK_U32 RlmtStatus;
+ SK_U64 RlmtTxHelloCts;
+ SK_U64 RlmtRxHelloCts;
+ SK_U64 RlmtTxSpHelloReqCts;
+ SK_U64 RlmtRxSpHelloCts;
+} SK_PNMI_RLMT;
+
+typedef struct s_PnmiRlmtMonitor {
+ SK_U32 RlmtMonitorIndex;
+ char RlmtMonitorAddr[6];
+ SK_U64 RlmtMonitorErrorCts;
+ SK_U64 RlmtMonitorTimestamp;
+ SK_U8 RlmtMonitorAdmin;
+} SK_PNMI_RLMT_MONITOR;
+
+typedef struct s_PnmiRequestStatus {
+ SK_U32 ErrorStatus;
+ SK_U32 ErrorOffset;
+} SK_PNMI_REQUEST_STATUS;
+
+typedef struct s_PnmiStrucData {
+ SK_U32 MgmtDBVersion;
+ SK_PNMI_REQUEST_STATUS ReturnStatus;
+ SK_U32 VpdFreeBytes;
+ char VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE];
+ SK_U32 VpdEntriesNumber;
+ SK_PNMI_VPD Vpd[SK_PNMI_VPD_ENTRIES];
+ SK_U32 PortNumber;
+ SK_U32 DeviceType;
+ char DriverDescr[SK_PNMI_STRINGLEN1];
+ char DriverVersion[SK_PNMI_STRINGLEN2];
+ char DriverReleaseDate[SK_PNMI_STRINGLEN1];
+ char DriverFileName[SK_PNMI_STRINGLEN1];
+ char HwDescr[SK_PNMI_STRINGLEN1];
+ char HwVersion[SK_PNMI_STRINGLEN2];
+ SK_U16 Chipset;
+ SK_U32 ChipId;
+ SK_U8 VauxAvail;
+ SK_U32 RamSize;
+ SK_U32 MtuSize;
+ SK_U32 Action;
+ SK_U32 TestResult;
+ SK_U8 BusType;
+ SK_U8 BusSpeed;
+ SK_U8 BusWidth;
+ SK_U8 SensorNumber;
+ SK_PNMI_SENSOR Sensor[SK_PNMI_SENSOR_ENTRIES];
+ SK_U8 ChecksumNumber;
+ SK_PNMI_CHECKSUM Checksum[SK_PNMI_CHECKSUM_ENTRIES];
+ SK_PNMI_STAT Stat[SK_PNMI_MAC_ENTRIES];
+ SK_PNMI_CONF Conf[SK_PNMI_MAC_ENTRIES];
+ SK_U8 RlmtMode;
+ SK_U32 RlmtPortNumber;
+ SK_U8 RlmtPortActive;
+ SK_U8 RlmtPortPreferred;
+ SK_U64 RlmtChangeCts;
+ SK_U64 RlmtChangeTime;
+ SK_U64 RlmtChangeEstimate;
+ SK_U64 RlmtChangeThreshold;
+ SK_PNMI_RLMT Rlmt[SK_MAX_MACS];
+ SK_U32 RlmtMonitorNumber;
+ SK_PNMI_RLMT_MONITOR RlmtMonitor[SK_PNMI_MONITOR_ENTRIES];
+ SK_U32 TrapNumber;
+ SK_U8 Trap[SK_PNMI_TRAP_QUEUE_LEN];
+ SK_U64 TxSwQueueLen;
+ SK_U64 TxSwQueueMax;
+ SK_U64 TxRetryCts;
+ SK_U64 RxIntrCts;
+ SK_U64 TxIntrCts;
+ SK_U64 RxNoBufCts;
+ SK_U64 TxNoBufCts;
+ SK_U64 TxUsedDescrNo;
+ SK_U64 RxDeliveredCts;
+ SK_U64 RxOctetsDeliveredCts;
+ SK_U64 RxHwErrorsCts;
+ SK_U64 TxHwErrorsCts;
+ SK_U64 InErrorsCts;
+ SK_U64 OutErrorsCts;
+ SK_U64 ErrRecoveryCts;
+ SK_U64 SysUpTime;
+} SK_PNMI_STRUCT_DATA;
+
+#define SK_PNMI_STRUCT_SIZE (sizeof(SK_PNMI_STRUCT_DATA))
+#define SK_PNMI_MIN_STRUCT_SIZE ((unsigned int)(SK_UPTR)\
+ &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes))
+ /*
+ * ReturnStatus field
+ * must be located
+ * before VpdFreeBytes
+ */
+
+/*
+ * Various definitions
+ */
+#define SK_PNMI_MAX_PROTOS 3
+
+#define SK_PNMI_CNT_NO 66 /* Must have the value of the enum
+ * SK_PNMI_MAX_IDX. Define SK_PNMI_CHECK
+ * for check while init phase 1
+ */
+
+/*
+ * Estimate data structure
+ */
+typedef struct s_PnmiEstimate {
+ unsigned int EstValueIndex;
+ SK_U64 EstValue[7];
+ SK_U64 Estimate;
+ SK_TIMER EstTimer;
+} SK_PNMI_ESTIMATE;
+
+
+/*
+ * VCT timer data structure
+ */
+typedef struct s_VctTimer {
+ SK_TIMER VctTimer;
+} SK_PNMI_VCT_TIMER;
+
+
+/*
+ * PNMI specific adapter context structure
+ */
+typedef struct s_PnmiPort {
+ SK_U64 StatSyncCts;
+ SK_U64 StatSyncOctetsCts;
+ SK_U64 StatRxLongFrameCts;
+ SK_U64 StatRxFrameTooLongCts;
+ SK_U64 StatRxPMaccErr;
+ SK_U64 TxSwQueueLen;
+ SK_U64 TxSwQueueMax;
+ SK_U64 TxRetryCts;
+ SK_U64 RxIntrCts;
+ SK_U64 TxIntrCts;
+ SK_U64 RxNoBufCts;
+ SK_U64 TxNoBufCts;
+ SK_U64 TxUsedDescrNo;
+ SK_U64 RxDeliveredCts;
+ SK_U64 RxOctetsDeliveredCts;
+ SK_U64 RxHwErrorsCts;
+ SK_U64 TxHwErrorsCts;
+ SK_U64 InErrorsCts;
+ SK_U64 OutErrorsCts;
+ SK_U64 ErrRecoveryCts;
+ SK_U64 RxShortZeroMark;
+ SK_U64 CounterOffset[SK_PNMI_CNT_NO];
+ SK_U32 CounterHigh[SK_PNMI_CNT_NO];
+ SK_BOOL ActiveFlag;
+ SK_U8 Align[3];
+} SK_PNMI_PORT;
+
+
+typedef struct s_PnmiData {
+ SK_PNMI_PORT Port [SK_MAX_MACS];
+ SK_PNMI_PORT BufPort [SK_MAX_MACS]; /* 2002-09-13 pweber */
+ SK_U64 VirtualCounterOffset[SK_PNMI_CNT_NO];
+ SK_U32 TestResult;
+ char HwVersion[10];
+ SK_U16 Align01;
+
+ char *pDriverDescription;
+ char *pDriverVersion;
+ char *pDriverReleaseDate;
+ char *pDriverFileName;
+
+ int MacUpdatedFlag;
+ int RlmtUpdatedFlag;
+ int SirqUpdatedFlag;
+
+ SK_U64 RlmtChangeCts;
+ SK_U64 RlmtChangeTime;
+ SK_PNMI_ESTIMATE RlmtChangeEstimate;
+ SK_U64 RlmtChangeThreshold;
+
+ SK_U64 StartUpTime;
+ SK_U32 DeviceType;
+ char PciBusSpeed;
+ char PciBusWidth;
+ char Chipset;
+ char PMD;
+ char Connector;
+ SK_BOOL DualNetActiveFlag;
+ SK_U16 Align02;
+
+ char TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
+ unsigned int TrapBufFree;
+ unsigned int TrapQueueBeg;
+ unsigned int TrapQueueEnd;
+ unsigned int TrapBufPad;
+ unsigned int TrapUnique;
+ SK_U8 VctStatus[SK_MAX_MACS];
+ SK_PNMI_VCT VctBackup[SK_MAX_MACS];
+ SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS];
+#ifdef SK_DIAG_SUPPORT
+ SK_U32 DiagAttached;
+#endif /* SK_DIAG_SUPPORT */
+} SK_PNMI;
+
+
+/*
+ * Function prototypes
+ */
+extern int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int Level);
+extern int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf,
+ unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+extern int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event,
+ SK_EVPARA Param);
+extern int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
+ unsigned int * pLen, SK_U32 NetIndex);
+
+#endif
diff --git a/drivers/net/sk98lin/h/skgesirq.h b/drivers/net/sk98lin/h/skgesirq.h
new file mode 100644
index 000000000000..3eec6274e413
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgesirq.h
@@ -0,0 +1,110 @@
+/******************************************************************************
+ *
+ * Name: skgesirq.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.30 $
+ * Date: $Date: 2003/07/04 12:34:13 $
+ * Purpose: SK specific Gigabit Ethernet special IRQ functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKGESIRQ_H_
+#define _INC_SKGESIRQ_H_
+
+/* Define return codes of SkGePortCheckUp and CheckShort */
+#define SK_HW_PS_NONE 0 /* No action needed */
+#define SK_HW_PS_RESTART 1 /* Restart needed */
+#define SK_HW_PS_LINK 2 /* Link Up actions needed */
+
+/*
+ * Define the Event the special IRQ/INI module can handle
+ */
+#define SK_HWEV_WATIM 1 /* Timeout for WA Errata #2 XMAC */
+#define SK_HWEV_PORT_START 2 /* Port Start Event by RLMT */
+#define SK_HWEV_PORT_STOP 3 /* Port Stop Event by RLMT */
+#define SK_HWEV_CLEAR_STAT 4 /* Clear Statistics by PNMI */
+#define SK_HWEV_UPDATE_STAT 5 /* Update Statistics by PNMI */
+#define SK_HWEV_SET_LMODE 6 /* Set Link Mode by PNMI */
+#define SK_HWEV_SET_FLOWMODE 7 /* Set Flow Control Mode by PNMI */
+#define SK_HWEV_SET_ROLE 8 /* Set Master/Slave (Role) by PNMI */
+#define SK_HWEV_SET_SPEED 9 /* Set Link Speed by PNMI */
+#define SK_HWEV_HALFDUP_CHK 10 /* Half Duplex Hangup Workaround */
+
+#define SK_WA_ACT_TIME (5000000UL) /* 5 sec */
+#define SK_WA_INA_TIME (100000UL) /* 100 msec */
+
+#define SK_HALFDUP_CHK_TIME (10000UL) /* 10 msec */
+
+/*
+ * Define the error numbers and messages
+ */
+#define SKERR_SIRQ_E001 (SK_ERRBASE_SIRQ+0)
+#define SKERR_SIRQ_E001MSG "Unknown event"
+#define SKERR_SIRQ_E002 (SKERR_SIRQ_E001+1)
+#define SKERR_SIRQ_E002MSG "Packet timeout RX1"
+#define SKERR_SIRQ_E003 (SKERR_SIRQ_E002+1)
+#define SKERR_SIRQ_E003MSG "Packet timeout RX2"
+#define SKERR_SIRQ_E004 (SKERR_SIRQ_E003+1)
+#define SKERR_SIRQ_E004MSG "MAC 1 not correctly initialized"
+#define SKERR_SIRQ_E005 (SKERR_SIRQ_E004+1)
+#define SKERR_SIRQ_E005MSG "MAC 2 not correctly initialized"
+#define SKERR_SIRQ_E006 (SKERR_SIRQ_E005+1)
+#define SKERR_SIRQ_E006MSG "CHECK failure R1"
+#define SKERR_SIRQ_E007 (SKERR_SIRQ_E006+1)
+#define SKERR_SIRQ_E007MSG "CHECK failure R2"
+#define SKERR_SIRQ_E008 (SKERR_SIRQ_E007+1)
+#define SKERR_SIRQ_E008MSG "CHECK failure XS1"
+#define SKERR_SIRQ_E009 (SKERR_SIRQ_E008+1)
+#define SKERR_SIRQ_E009MSG "CHECK failure XA1"
+#define SKERR_SIRQ_E010 (SKERR_SIRQ_E009+1)
+#define SKERR_SIRQ_E010MSG "CHECK failure XS2"
+#define SKERR_SIRQ_E011 (SKERR_SIRQ_E010+1)
+#define SKERR_SIRQ_E011MSG "CHECK failure XA2"
+#define SKERR_SIRQ_E012 (SKERR_SIRQ_E011+1)
+#define SKERR_SIRQ_E012MSG "unexpected IRQ Master error"
+#define SKERR_SIRQ_E013 (SKERR_SIRQ_E012+1)
+#define SKERR_SIRQ_E013MSG "unexpected IRQ Status error"
+#define SKERR_SIRQ_E014 (SKERR_SIRQ_E013+1)
+#define SKERR_SIRQ_E014MSG "Parity error on RAM (read)"
+#define SKERR_SIRQ_E015 (SKERR_SIRQ_E014+1)
+#define SKERR_SIRQ_E015MSG "Parity error on RAM (write)"
+#define SKERR_SIRQ_E016 (SKERR_SIRQ_E015+1)
+#define SKERR_SIRQ_E016MSG "Parity error MAC 1"
+#define SKERR_SIRQ_E017 (SKERR_SIRQ_E016+1)
+#define SKERR_SIRQ_E017MSG "Parity error MAC 2"
+#define SKERR_SIRQ_E018 (SKERR_SIRQ_E017+1)
+#define SKERR_SIRQ_E018MSG "Parity error RX 1"
+#define SKERR_SIRQ_E019 (SKERR_SIRQ_E018+1)
+#define SKERR_SIRQ_E019MSG "Parity error RX 2"
+#define SKERR_SIRQ_E020 (SKERR_SIRQ_E019+1)
+#define SKERR_SIRQ_E020MSG "MAC transmit FIFO underrun"
+#define SKERR_SIRQ_E021 (SKERR_SIRQ_E020+1)
+#define SKERR_SIRQ_E021MSG "Spurious TWSI interrupt"
+#define SKERR_SIRQ_E022 (SKERR_SIRQ_E021+1)
+#define SKERR_SIRQ_E022MSG "Cable pair swap error"
+#define SKERR_SIRQ_E023 (SKERR_SIRQ_E022+1)
+#define SKERR_SIRQ_E023MSG "Auto-negotiation error"
+#define SKERR_SIRQ_E024 (SKERR_SIRQ_E023+1)
+#define SKERR_SIRQ_E024MSG "FIFO overflow error"
+#define SKERR_SIRQ_E025 (SKERR_SIRQ_E024+1)
+#define SKERR_SIRQ_E025MSG "2 Pair Downshift detected"
+
+extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
+extern int SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
+
+#endif /* _INC_SKGESIRQ_H_ */
diff --git a/drivers/net/sk98lin/h/ski2c.h b/drivers/net/sk98lin/h/ski2c.h
new file mode 100644
index 000000000000..6a63f4a15de6
--- /dev/null
+++ b/drivers/net/sk98lin/h/ski2c.h
@@ -0,0 +1,174 @@
+/******************************************************************************
+ *
+ * Name: ski2c.h
+ * Project: Gigabit Ethernet Adapters, TWSI-Module
+ * Version: $Revision: 1.35 $
+ * Date: $Date: 2003/10/20 09:06:30 $
+ * Purpose: Defines to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKI2C.H contains all I2C specific defines
+ */
+
+#ifndef _SKI2C_H_
+#define _SKI2C_H_
+
+typedef struct s_Sensor SK_SENSOR;
+
+#include "h/skgei2c.h"
+
+/*
+ * Define the I2C events.
+ */
+#define SK_I2CEV_IRQ 1 /* IRQ happened Event */
+#define SK_I2CEV_TIM 2 /* Timeout event */
+#define SK_I2CEV_CLEAR 3 /* Clear MIB Values */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+#define I2C_READ 0
+#define I2C_WRITE 1
+#define I2C_BURST 1
+#define I2C_SINGLE 0
+
+#define SKERR_I2C_E001 (SK_ERRBASE_I2C+0)
+#define SKERR_I2C_E001MSG "Sensor index unknown"
+#define SKERR_I2C_E002 (SKERR_I2C_E001+1)
+#define SKERR_I2C_E002MSG "TWSI: transfer does not complete"
+#define SKERR_I2C_E003 (SKERR_I2C_E002+1)
+#define SKERR_I2C_E003MSG "LM80: NAK on device send"
+#define SKERR_I2C_E004 (SKERR_I2C_E003+1)
+#define SKERR_I2C_E004MSG "LM80: NAK on register send"
+#define SKERR_I2C_E005 (SKERR_I2C_E004+1)
+#define SKERR_I2C_E005MSG "LM80: NAK on device (2) send"
+#define SKERR_I2C_E006 (SKERR_I2C_E005+1)
+#define SKERR_I2C_E006MSG "Unknown event"
+#define SKERR_I2C_E007 (SKERR_I2C_E006+1)
+#define SKERR_I2C_E007MSG "LM80 read out of state"
+#define SKERR_I2C_E008 (SKERR_I2C_E007+1)
+#define SKERR_I2C_E008MSG "Unexpected sensor read completed"
+#define SKERR_I2C_E009 (SKERR_I2C_E008+1)
+#define SKERR_I2C_E009MSG "WARNING: temperature sensor out of range"
+#define SKERR_I2C_E010 (SKERR_I2C_E009+1)
+#define SKERR_I2C_E010MSG "WARNING: voltage sensor out of range"
+#define SKERR_I2C_E011 (SKERR_I2C_E010+1)
+#define SKERR_I2C_E011MSG "ERROR: temperature sensor out of range"
+#define SKERR_I2C_E012 (SKERR_I2C_E011+1)
+#define SKERR_I2C_E012MSG "ERROR: voltage sensor out of range"
+#define SKERR_I2C_E013 (SKERR_I2C_E012+1)
+#define SKERR_I2C_E013MSG "ERROR: couldn't init sensor"
+#define SKERR_I2C_E014 (SKERR_I2C_E013+1)
+#define SKERR_I2C_E014MSG "WARNING: fan sensor out of range"
+#define SKERR_I2C_E015 (SKERR_I2C_E014+1)
+#define SKERR_I2C_E015MSG "ERROR: fan sensor out of range"
+#define SKERR_I2C_E016 (SKERR_I2C_E015+1)
+#define SKERR_I2C_E016MSG "TWSI: active transfer does not complete"
+
+/*
+ * Define Timeout values
+ */
+#define SK_I2C_TIM_LONG 2000000L /* 2 seconds */
+#define SK_I2C_TIM_SHORT 100000L /* 100 milliseconds */
+#define SK_I2C_TIM_WATCH 1000000L /* 1 second */
+
+/*
+ * Define trap and error log hold times
+ */
+#ifndef SK_SEN_ERR_TR_HOLD
+#define SK_SEN_ERR_TR_HOLD (4*SK_TICKS_PER_SEC)
+#endif
+#ifndef SK_SEN_ERR_LOG_HOLD
+#define SK_SEN_ERR_LOG_HOLD (60*SK_TICKS_PER_SEC)
+#endif
+#ifndef SK_SEN_WARN_TR_HOLD
+#define SK_SEN_WARN_TR_HOLD (15*SK_TICKS_PER_SEC)
+#endif
+#ifndef SK_SEN_WARN_LOG_HOLD
+#define SK_SEN_WARN_LOG_HOLD (15*60*SK_TICKS_PER_SEC)
+#endif
+
+/*
+ * Defines for SenType
+ */
+#define SK_SEN_UNKNOWN 0
+#define SK_SEN_TEMP 1
+#define SK_SEN_VOLT 2
+#define SK_SEN_FAN 3
+
+/*
+ * Define for the SenErrorFlag
+ */
+#define SK_SEN_ERR_NOT_PRESENT 0 /* Error Flag: Sensor not present */
+#define SK_SEN_ERR_OK 1 /* Error Flag: O.K. */
+#define SK_SEN_ERR_WARN 2 /* Error Flag: Warning */
+#define SK_SEN_ERR_ERR 3 /* Error Flag: Error */
+#define SK_SEN_ERR_FAULTY 4 /* Error Flag: Faulty */
+
+/*
+ * Define the Sensor struct
+ */
+struct s_Sensor {
+ char *SenDesc; /* Description */
+ int SenType; /* Voltage or Temperature */
+ SK_I32 SenValue; /* Current value of the sensor */
+ SK_I32 SenThreErrHigh; /* High error Threshhold of this sensor */
+ SK_I32 SenThreWarnHigh; /* High warning Threshhold of this sensor */
+ SK_I32 SenThreErrLow; /* Lower error Threshold of the sensor */
+ SK_I32 SenThreWarnLow; /* Lower warning Threshold of the sensor */
+ int SenErrFlag; /* Sensor indicated an error */
+ SK_BOOL SenInit; /* Is sensor initialized ? */
+ SK_U64 SenErrCts; /* Error trap counter */
+ SK_U64 SenWarnCts; /* Warning trap counter */
+ SK_U64 SenBegErrTS; /* Begin error timestamp */
+ SK_U64 SenBegWarnTS; /* Begin warning timestamp */
+ SK_U64 SenLastErrTrapTS; /* Last error trap timestamp */
+ SK_U64 SenLastErrLogTS; /* Last error log timestamp */
+ SK_U64 SenLastWarnTrapTS; /* Last warning trap timestamp */
+ SK_U64 SenLastWarnLogTS; /* Last warning log timestamp */
+ int SenState; /* Sensor State (see HW specific include) */
+ int (*SenRead)(SK_AC *pAC, SK_IOC IoC, struct s_Sensor *pSen);
+ /* Sensors read function */
+ SK_U16 SenReg; /* Register Address for this sensor */
+ SK_U8 SenDev; /* Device Selection for this sensor */
+};
+
+typedef struct s_I2c {
+ SK_SENSOR SenTable[SK_MAX_SENSORS]; /* Sensor Table */
+ int CurrSens; /* Which sensor is currently queried */
+ int MaxSens; /* Max. number of sensors */
+ int TimerMode; /* Use the timer also to watch the state machine */
+ int InitLevel; /* Initialized Level */
+#ifndef SK_DIAG
+ int DummyReads; /* Number of non-checked dummy reads */
+ SK_TIMER SenTimer; /* Sensors timer */
+#endif /* !SK_DIAG */
+} SK_I2C;
+
+extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level);
+#ifdef SK_DIAG
+extern SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg,
+ int Burst);
+#else /* !SK_DIAG */
+extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC);
+extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC);
+#endif /* !SK_DIAG */
+#endif /* n_SKI2C_H */
+
diff --git a/drivers/net/sk98lin/h/skqueue.h b/drivers/net/sk98lin/h/skqueue.h
new file mode 100644
index 000000000000..2ec40d4fdf60
--- /dev/null
+++ b/drivers/net/sk98lin/h/skqueue.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Name: skqueue.h
+ * Project: Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version: $Revision: 1.16 $
+ * Date: $Date: 2003/09/16 12:50:32 $
+ * Purpose: Defines for the Event queue
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKQUEUE.H contains all defines and types for the event queue
+ */
+
+#ifndef _SKQUEUE_H_
+#define _SKQUEUE_H_
+
+
+/*
+ * define the event classes to be served
+ */
+#define SKGE_DRV 1 /* Driver Event Class */
+#define SKGE_RLMT 2 /* RLMT Event Class */
+#define SKGE_I2C 3 /* I2C Event Class */
+#define SKGE_PNMI 4 /* PNMI Event Class */
+#define SKGE_CSUM 5 /* Checksum Event Class */
+#define SKGE_HWAC 6 /* Hardware Access Event Class */
+
+#define SKGE_SWT 9 /* Software Timer Event Class */
+#define SKGE_LACP 10 /* LACP Aggregation Event Class */
+#define SKGE_RSF 11 /* RSF Aggregation Event Class */
+#define SKGE_MARKER 12 /* MARKER Aggregation Event Class */
+#define SKGE_FD 13 /* FD Distributor Event Class */
+
+/*
+ * define event queue as circular buffer
+ */
+#define SK_MAX_EVENT 64
+
+/*
+ * Parameter union for the Para stuff
+ */
+typedef union u_EvPara {
+ void *pParaPtr; /* Parameter Pointer */
+ SK_U64 Para64; /* Parameter 64bit version */
+ SK_U32 Para32[2]; /* Parameter Array of 32bit parameters */
+} SK_EVPARA;
+
+/*
+ * Event Queue
+ * skqueue.c
+ * events are class/value pairs
+ * class is addressee, e.g. RLMT, PNMI etc.
+ * value is command, e.g. line state change, ring op change etc.
+ */
+typedef struct s_EventElem {
+ SK_U32 Class; /* Event class */
+ SK_U32 Event; /* Event value */
+ SK_EVPARA Para; /* Event parameter */
+} SK_EVENTELEM;
+
+typedef struct s_Queue {
+ SK_EVENTELEM EvQueue[SK_MAX_EVENT];
+ SK_EVENTELEM *EvPut;
+ SK_EVENTELEM *EvGet;
+} SK_QUEUE;
+
+extern void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event,
+ SK_EVPARA Para);
+extern int SkEventDispatcher(SK_AC *pAC, SK_IOC Ioc);
+
+
+/* Define Error Numbers and messages */
+#define SKERR_Q_E001 (SK_ERRBASE_QUEUE+0)
+#define SKERR_Q_E001MSG "Event queue overflow"
+#define SKERR_Q_E002 (SKERR_Q_E001+1)
+#define SKERR_Q_E002MSG "Undefined event class"
+#endif /* _SKQUEUE_H_ */
+
diff --git a/drivers/net/sk98lin/h/skrlmt.h b/drivers/net/sk98lin/h/skrlmt.h
new file mode 100644
index 000000000000..ca75dfdcf2d6
--- /dev/null
+++ b/drivers/net/sk98lin/h/skrlmt.h
@@ -0,0 +1,438 @@
+/******************************************************************************
+ *
+ * Name: skrlmt.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.37 $
+ * Date: $Date: 2003/04/15 09:43:43 $
+ * Purpose: Header file for Redundant Link ManagemenT.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the header file for Redundant Link ManagemenT.
+ *
+ * Include File Hierarchy:
+ *
+ * "skdrv1st.h"
+ * ...
+ * "sktypes.h"
+ * "skqueue.h"
+ * "skaddr.h"
+ * "skrlmt.h"
+ * ...
+ * "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKRLMT_H
+#define __INC_SKRLMT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_RLMT_NET_DOWN_TEMP 1 /* NET_DOWN due to last port down. */
+#define SK_RLMT_NET_DOWN_FINAL 2 /* NET_DOWN due to RLMT_STOP. */
+
+/* ----- Default queue sizes - must be multiples of 8 KB ----- */
+
+/* Less than 8 KB free in RX queue => pause frames. */
+#define SK_RLMT_STANDBY_QRXSIZE 128 /* Size of rx standby queue in KB. */
+#define SK_RLMT_STANDBY_QXASIZE 32 /* Size of async standby queue in KB. */
+#define SK_RLMT_STANDBY_QXSSIZE 0 /* Size of sync standby queue in KB. */
+
+#define SK_RLMT_MAX_TX_BUF_SIZE 60 /* Maximum RLMT transmit size. */
+
+/* ----- PORT states ----- */
+
+#define SK_RLMT_PS_INIT 0 /* Port state: Init. */
+#define SK_RLMT_PS_LINK_DOWN 1 /* Port state: Link down. */
+#define SK_RLMT_PS_DOWN 2 /* Port state: Port down. */
+#define SK_RLMT_PS_GOING_UP 3 /* Port state: Going up. */
+#define SK_RLMT_PS_UP 4 /* Port state: Up. */
+
+/* ----- RLMT states ----- */
+
+#define SK_RLMT_RS_INIT 0 /* RLMT state: Init. */
+#define SK_RLMT_RS_NET_DOWN 1 /* RLMT state: Net down. */
+#define SK_RLMT_RS_NET_UP 2 /* RLMT state: Net up. */
+
+/* ----- PORT events ----- */
+
+#define SK_RLMT_LINK_UP 1001 /* Link came up. */
+#define SK_RLMT_LINK_DOWN 1002 /* Link went down. */
+#define SK_RLMT_PORT_ADDR 1003 /* Port address changed. */
+
+/* ----- RLMT events ----- */
+
+#define SK_RLMT_START 2001 /* Start RLMT. */
+#define SK_RLMT_STOP 2002 /* Stop RLMT. */
+#define SK_RLMT_PACKET_RECEIVED 2003 /* Packet was received for RLMT. */
+#define SK_RLMT_STATS_CLEAR 2004 /* Clear statistics. */
+#define SK_RLMT_STATS_UPDATE 2005 /* Update statistics. */
+#define SK_RLMT_PREFPORT_CHANGE 2006 /* Change preferred port. */
+#define SK_RLMT_MODE_CHANGE 2007 /* New RlmtMode. */
+#define SK_RLMT_SET_NETS 2008 /* Number of Nets (1 or 2). */
+
+/* ----- RLMT mode bits ----- */
+
+/*
+ * CAUTION: These defines are private to RLMT.
+ * Please use the RLMT mode defines below.
+ */
+
+#define SK_RLMT_CHECK_LINK 1 /* Check Link. */
+#define SK_RLMT_CHECK_LOC_LINK 2 /* Check other link on same adapter. */
+#define SK_RLMT_CHECK_SEG 4 /* Check segmentation. */
+
+#ifndef RLMT_CHECK_REMOTE
+#define SK_RLMT_CHECK_OTHERS SK_RLMT_CHECK_LOC_LINK
+#else /* RLMT_CHECK_REMOTE */
+#define SK_RLMT_CHECK_REM_LINK 8 /* Check link(s) on other adapter(s). */
+#define SK_RLMT_MAX_REMOTE_PORTS_CHECKED 3
+#define SK_RLMT_CHECK_OTHERS \
+ (SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+#endif /* RLMT_CHECK_REMOTE */
+
+#ifndef SK_RLMT_ENABLE_TRANSPARENT
+#define SK_RLMT_TRANSPARENT 0 /* RLMT transparent - inactive. */
+#else /* SK_RLMT_ENABLE_TRANSPARENT */
+#define SK_RLMT_TRANSPARENT 128 /* RLMT transparent. */
+#endif /* SK_RLMT_ENABLE_TRANSPARENT */
+
+/* ----- RLMT modes ----- */
+
+/* Check Link State. */
+#define SK_RLMT_MODE_CLS (SK_RLMT_CHECK_LINK)
+
+/* Check Local Ports: check other links on the same adapter. */
+#define SK_RLMT_MODE_CLP (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK)
+
+/* Check Local Ports and Segmentation Status. */
+#define SK_RLMT_MODE_CLPSS \
+ (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG)
+
+#ifdef RLMT_CHECK_REMOTE
+/* Check Local and Remote Ports: check links (local or remote). */
+ Name of define TBD!
+#define SK_RLMT_MODE_CRP \
+ (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+
+/* Check Local and Remote Ports and Segmentation Status. */
+ Name of define TBD!
+#define SK_RLMT_MODE_CRPSS \
+ (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \
+ SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG)
+#endif /* RLMT_CHECK_REMOTE */
+
+/* ----- RLMT lookahead result bits ----- */
+
+#define SK_RLMT_RX_RLMT 1 /* Give packet to RLMT. */
+#define SK_RLMT_RX_PROTOCOL 2 /* Give packet to protocol. */
+
+/* Macros */
+
+#if 0
+SK_AC *pAC /* adapter context */
+SK_U32 PortNum /* receiving port */
+unsigned PktLen /* received packet's length */
+SK_BOOL IsBc /* Flag: packet is broadcast */
+unsigned *pOffset /* offs. of bytes to present to SK_RLMT_LOOKAHEAD */
+unsigned *pNumBytes /* #Bytes to present to SK_RLMT_LOOKAHEAD */
+#endif /* 0 */
+
+#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \
+ SK_AC *_pAC; \
+ SK_U32 _PortNum; \
+ _pAC = (pAC); \
+ _PortNum = (SK_U32)(PortNum); \
+ /* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \
+ _pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \
+ if (_pAC->Rlmt.RlmtOff) { \
+ *(pNumBytes) = 0; \
+ } \
+ else {\
+ if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \
+ *(pNumBytes) = 0; \
+ } \
+ else if (IsBc) { \
+ if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \
+ *(pNumBytes) = 6; \
+ *(pOffset) = 6; \
+ } \
+ else { \
+ *(pNumBytes) = 0; \
+ } \
+ } \
+ else { \
+ if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \
+ /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+ *(pNumBytes) = 0; \
+ } \
+ else { \
+ *(pNumBytes) = 6; \
+ *(pOffset) = 0; \
+ } \
+ } \
+ } \
+}
+
+#if 0
+SK_AC *pAC /* adapter context */
+SK_U32 PortNum /* receiving port */
+SK_U8 *pLaPacket, /* received packet's data (points to pOffset) */
+SK_BOOL IsBc /* Flag: packet is broadcast */
+SK_BOOL IsMc /* Flag: packet is multicast */
+unsigned *pForRlmt /* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */
+SK_RLMT_LOOKAHEAD() expects *pNumBytes from
+packet offset *pOffset (s.a.) at *pLaPacket.
+
+If you use SK_RLMT_LOOKAHEAD in a path where you already know if the packet is
+BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler
+can trash unneeded parts of the if construction.
+#endif /* 0 */
+
+#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \
+ SK_AC *_pAC; \
+ SK_U32 _PortNum; \
+ SK_U8 *_pLaPacket; \
+ _pAC = (pAC); \
+ _PortNum = (SK_U32)(PortNum); \
+ _pLaPacket = (SK_U8 *)(pLaPacket); \
+ if (IsBc) {\
+ if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \
+ _PortNum].Net->NetNumber].CurrentMacAddress.a)) { \
+ _pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \
+ _pAC->Rlmt.CheckSwitch = SK_TRUE; \
+ } \
+ /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+ } \
+ else if (IsMc) { \
+ if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \
+ _pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \
+ if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \
+ *(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \
+ } \
+ else { \
+ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+ } \
+ } \
+ else if (SK_ADDR_EQUAL(_pLaPacket, SkRlmtMcAddr.a)) { \
+ *(pForRlmt) = SK_RLMT_RX_RLMT; \
+ } \
+ else { \
+ /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+ } \
+ } \
+ else { \
+ if (SK_ADDR_EQUAL( \
+ _pLaPacket, \
+ _pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \
+ *(pForRlmt) = SK_RLMT_RX_RLMT; \
+ } \
+ else { \
+ /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+ } \
+ } \
+}
+
+#ifdef SK_RLMT_FAST_LOOKAHEAD
+Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif /* SK_RLMT_FAST_LOOKAHEAD */
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif /* SK_RLMT_SLOW_LOOKAHEAD */
+
+/* typedefs *******************************************************************/
+
+#ifdef SK_RLMT_MBUF_PRIVATE
+typedef struct s_RlmtMbuf {
+ some content
+} SK_RLMT_MBUF;
+#endif /* SK_RLMT_MBUF_PRIVATE */
+
+
+#ifdef SK_LA_INFO
+typedef struct s_Rlmt_PacketInfo {
+ unsigned PacketLength; /* Length of packet. */
+ unsigned PacketType; /* Directed/Multicast/Broadcast. */
+} SK_RLMT_PINFO;
+#endif /* SK_LA_INFO */
+
+
+typedef struct s_RootId {
+ SK_U8 Id[8]; /* Root Bridge Id. */
+} SK_RLMT_ROOT_ID;
+
+
+typedef struct s_port {
+ SK_MAC_ADDR CheckAddr;
+ SK_BOOL SuspectTx;
+} SK_PORT_CHECK;
+
+
+typedef struct s_RlmtNet SK_RLMT_NET;
+
+
+typedef struct s_RlmtPort {
+
+/* ----- Public part (read-only) ----- */
+
+ SK_U8 PortState; /* Current state of this port. */
+
+ /* For PNMI */
+ SK_BOOL LinkDown;
+ SK_BOOL PortDown;
+ SK_U8 Align01;
+
+ SK_U32 PortNumber; /* Number of port on adapter. */
+ SK_RLMT_NET * Net; /* Net port belongs to. */
+
+ SK_U64 TxHelloCts;
+ SK_U64 RxHelloCts;
+ SK_U64 TxSpHelloReqCts;
+ SK_U64 RxSpHelloCts;
+
+/* ----- Private part ----- */
+
+/* SK_U64 PacketsRx; */ /* Total packets received. */
+ SK_U32 PacketsPerTimeSlot; /* Packets rxed between TOs. */
+/* SK_U32 DataPacketsPerTimeSlot; */ /* Data packets ... */
+ SK_U32 BpduPacketsPerTimeSlot; /* BPDU packets rxed in TS. */
+ SK_U64 BcTimeStamp; /* Time of last BC receive. */
+ SK_U64 GuTimeStamp; /* Time of entering GOING_UP. */
+
+ SK_TIMER UpTimer; /* Timer struct Link/Port up. */
+ SK_TIMER DownRxTimer; /* Timer struct down rx. */
+ SK_TIMER DownTxTimer; /* Timer struct down tx. */
+
+ SK_U32 CheckingState; /* Checking State. */
+
+ SK_ADDR_PORT * AddrPort;
+
+ SK_U8 Random[4]; /* Random value. */
+ unsigned PortsChecked; /* #ports checked. */
+ unsigned PortsSuspect; /* #ports checked that are s. */
+ SK_PORT_CHECK PortCheck[1];
+/* SK_PORT_CHECK PortCheck[SK_MAX_MACS - 1]; */
+
+ SK_BOOL PortStarted; /* Port is started. */
+ SK_BOOL PortNoRx; /* NoRx for >= 1 time slot. */
+ SK_BOOL RootIdSet;
+ SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */
+} SK_RLMT_PORT;
+
+
+struct s_RlmtNet {
+
+/* ----- Public part (read-only) ----- */
+
+ SK_U32 NetNumber; /* Number of net. */
+
+ SK_RLMT_PORT * Port[SK_MAX_MACS]; /* Ports that belong to this net. */
+ SK_U32 NumPorts; /* Number of ports. */
+ SK_U32 PrefPort; /* Preferred port. */
+
+ /* For PNMI */
+
+ SK_U32 ChgBcPrio; /* Change Priority of last broadcast received */
+ SK_U32 RlmtMode; /* Check ... */
+ SK_U32 ActivePort; /* Active port. */
+ SK_U32 Preference; /* 0xFFFFFFFF: Automatic. */
+
+ SK_U8 RlmtState; /* Current RLMT state. */
+
+/* ----- Private part ----- */
+ SK_BOOL RootIdSet;
+ SK_U16 Align01;
+
+ int LinksUp; /* #Links up. */
+ int PortsUp; /* #Ports up. */
+ SK_U32 TimeoutValue; /* RLMT timeout value. */
+
+ SK_U32 CheckingState; /* Checking State. */
+ SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */
+
+ SK_TIMER LocTimer; /* Timer struct. */
+ SK_TIMER SegTimer; /* Timer struct. */
+};
+
+
+typedef struct s_Rlmt {
+
+/* ----- Public part (read-only) ----- */
+
+ SK_U32 NumNets; /* Number of nets. */
+ SK_U32 NetsStarted; /* Number of nets started. */
+ SK_RLMT_NET Net[SK_MAX_NETS]; /* Array of available nets. */
+ SK_RLMT_PORT Port[SK_MAX_MACS]; /* Array of available ports. */
+
+/* ----- Private part ----- */
+ SK_BOOL CheckSwitch;
+ SK_BOOL RlmtOff; /* set to zero if the Mac addresses
+ are equal or the second one
+ is zero */
+ SK_U16 Align01;
+
+} SK_RLMT;
+
+
+extern SK_MAC_ADDR BridgeMcAddr;
+extern SK_MAC_ADDR SkRlmtMcAddr;
+
+/* function prototypes ********************************************************/
+
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkRlmt */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern void SkRlmtInit(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int Level);
+
+extern int SkRlmtEvent(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 Event,
+ SK_EVPARA Para);
+
+#else /* defined(SK_KR_PROTO) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style function prototypes are not yet provided.
+
+#endif /* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_SKRLMT_H */
diff --git a/drivers/net/sk98lin/h/sktimer.h b/drivers/net/sk98lin/h/sktimer.h
new file mode 100644
index 000000000000..04e6d7c1ec33
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktimer.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Name: sktimer.h
+ * Project: Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version: $Revision: 1.11 $
+ * Date: $Date: 2003/09/16 12:58:18 $
+ * Purpose: Defines for the timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * SKTIMER.H contains all defines and types for the timer functions
+ */
+
+#ifndef _SKTIMER_H_
+#define _SKTIMER_H_
+
+#include "h/skqueue.h"
+
+/*
+ * SK timer
+ * - needed wherever a timer is used. Put this in your data structure
+ * wherever you want.
+ */
+typedef struct s_Timer SK_TIMER;
+
+struct s_Timer {
+ SK_TIMER *TmNext; /* linked list */
+ SK_U32 TmClass; /* Timer Event class */
+ SK_U32 TmEvent; /* Timer Event value */
+ SK_EVPARA TmPara; /* Timer Event parameter */
+ SK_U32 TmDelta; /* delta time */
+ int TmActive; /* flag: active/inactive */
+};
+
+/*
+ * Timer control struct.
+ * - use in Adapters context name pAC->Tim
+ */
+typedef struct s_TimCtrl {
+ SK_TIMER *StQueue; /* Head of Timer queue */
+} SK_TIMCTRL;
+
+extern void SkTimerInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern void SkTimerStop(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer);
+extern void SkTimerStart(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer,
+ SK_U32 Time, SK_U32 Class, SK_U32 Event, SK_EVPARA Para);
+extern void SkTimerDone(SK_AC *pAC, SK_IOC Ioc);
+#endif /* _SKTIMER_H_ */
diff --git a/drivers/net/sk98lin/h/sktypes.h b/drivers/net/sk98lin/h/sktypes.h
new file mode 100644
index 000000000000..40edc96e1055
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktypes.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Name: sktypes.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.2 $
+ * Date: $Date: 2003/10/07 08:16:51 $
+ * Purpose: Define data types for Linux
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * In this file, all data types that are needed by the common modules
+ * are mapped to Linux data types.
+ *
+ *
+ * Include File Hierarchy:
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKTYPES_H
+#define __INC_SKTYPES_H
+
+
+/* defines *******************************************************************/
+
+/*
+ * Data types with a specific size. 'I' = signed, 'U' = unsigned.
+ */
+#define SK_I8 s8
+#define SK_U8 u8
+#define SK_I16 s16
+#define SK_U16 u16
+#define SK_I32 s32
+#define SK_U32 u32
+#define SK_I64 s64
+#define SK_U64 u64
+
+#define SK_UPTR ulong /* casting pointer <-> integral */
+
+/*
+* Boolean type.
+*/
+#define SK_BOOL SK_U8
+#define SK_FALSE 0
+#define SK_TRUE (!SK_FALSE)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+#endif /* __INC_SKTYPES_H */
diff --git a/drivers/net/sk98lin/h/skversion.h b/drivers/net/sk98lin/h/skversion.h
new file mode 100644
index 000000000000..a1a7294828e5
--- /dev/null
+++ b/drivers/net/sk98lin/h/skversion.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Name: version.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.5 $
+ * Date: $Date: 2003/10/07 08:16:51 $
+ * Purpose: SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifdef lint
+static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH.";
+static const char SysKonnectBuildNumber[] =
+ "@(#)SK-BUILD: 6.23 PL: 01";
+#endif /* !defined(lint) */
+
+#define BOOT_STRING "sk98lin: Network Device Driver v6.23\n" \
+ "(C)Copyright 1999-2004 Marvell(R)."
+
+#define VER_STRING "6.23"
+#define DRIVER_FILE_NAME "sk98lin"
+#define DRIVER_REL_DATE "Feb-13-2004"
+
+
diff --git a/drivers/net/sk98lin/h/skvpd.h b/drivers/net/sk98lin/h/skvpd.h
new file mode 100644
index 000000000000..fdd9e48e8040
--- /dev/null
+++ b/drivers/net/sk98lin/h/skvpd.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Name: skvpd.h
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.15 $
+ * Date: $Date: 2003/01/13 10:39:38 $
+ * Purpose: Defines and Macros for VPD handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * skvpd.h contains Diagnostic specific defines for VPD handling
+ */
+
+#ifndef __INC_SKVPD_H_
+#define __INC_SKVPD_H_
+
+/*
+ * Define Resource Type Identifiers and VPD keywords
+ */
+#define RES_ID 0x82 /* Resource Type ID String (Product Name) */
+#define RES_VPD_R 0x90 /* start of VPD read only area */
+#define RES_VPD_W 0x91 /* start of VPD read/write area */
+#define RES_END 0x78 /* Resource Type End Tag */
+
+#ifndef VPD_NAME
+#define VPD_NAME "Name" /* Product Name, VPD name of RES_ID */
+#endif /* VPD_NAME */
+#define VPD_PN "PN" /* Adapter Part Number */
+#define VPD_EC "EC" /* Adapter Engineering Level */
+#define VPD_MN "MN" /* Manufacture ID */
+#define VPD_SN "SN" /* Serial Number */
+#define VPD_CP "CP" /* Extended Capability */
+#define VPD_RV "RV" /* Checksum and Reserved */
+#define VPD_YA "YA" /* Asset Tag Identifier */
+#define VPD_VL "VL" /* First Error Log Message (SK specific) */
+#define VPD_VF "VF" /* Second Error Log Message (SK specific) */
+#define VPD_RW "RW" /* Remaining Read / Write Area */
+
+/* 'type' values for vpd_setup_para() */
+#define VPD_RO_KEY 1 /* RO keys are "PN", "EC", "MN", "SN", "RV" */
+#define VPD_RW_KEY 2 /* RW keys are "Yx", "Vx", and "RW" */
+
+/* 'op' values for vpd_setup_para() */
+#define ADD_KEY 1 /* add the key at the pos "RV" or "RW" */
+#define OWR_KEY 2 /* overwrite key if already exists */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+
+#define VPD_DEV_ID_GENESIS 0x4300
+
+#define VPD_SIZE_YUKON 256
+#define VPD_SIZE_GENESIS 512
+#define VPD_SIZE 512
+#define VPD_READ 0x0000
+#define VPD_WRITE 0x8000
+
+#define VPD_STOP(pAC,IoC) VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG,VPD_WRITE)
+
+#define VPD_GET_RES_LEN(p) ((unsigned int) \
+ (* (SK_U8 *)&(p)[1]) |\
+ ((* (SK_U8 *)&(p)[2]) << 8))
+#define VPD_GET_VPD_LEN(p) ((unsigned int)(* (SK_U8 *)&(p)[2]))
+#define VPD_GET_VAL(p) ((char *)&(p)[3])
+
+#define VPD_MAX_LEN 50
+
+/* VPD status */
+ /* bit 7..1 reserved */
+#define VPD_VALID (1<<0) /* VPD data buffer, vpd_free_ro, */
+ /* and vpd_free_rw valid */
+
+/*
+ * VPD structs
+ */
+typedef struct s_vpd_status {
+ unsigned short Align01; /* Alignment */
+ unsigned short vpd_status; /* VPD status, description see above */
+ int vpd_free_ro; /* unused bytes in read only area */
+ int vpd_free_rw; /* bytes available in read/write area */
+} SK_VPD_STATUS;
+
+typedef struct s_vpd {
+ SK_VPD_STATUS v; /* VPD status structure */
+ char vpd_buf[VPD_SIZE]; /* VPD buffer */
+ int rom_size; /* VPD ROM Size from PCI_OUR_REG_2 */
+ int vpd_size; /* saved VPD-size */
+} SK_VPD;
+
+typedef struct s_vpd_para {
+ unsigned int p_len; /* parameter length */
+ char *p_val; /* points to the value */
+} SK_VPD_PARA;
+
+/*
+ * structure of Large Resource Type Identifiers
+ */
+
+/* was removed because of alignment problems */
+
+/*
+ * structure of VPD keywords
+ */
+typedef struct s_vpd_key {
+ char p_key[2]; /* 2 bytes ID string */
+ unsigned char p_len; /* 1 byte length */
+ char p_val; /* start of the value string */
+} SK_VPD_KEY;
+
+
+/*
+ * System specific VPD macros
+ */
+#ifndef SKDIAG
+#ifndef VPD_DO_IO
+#define VPD_OUT8(pAC,IoC,Addr,Val) (void)SkPciWriteCfgByte(pAC,Addr,Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val) (void)SkPciWriteCfgWord(pAC,Addr,Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal) (void)SkPciReadCfgByte(pAC,Addr,pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal) (void)SkPciReadCfgWord(pAC,Addr,pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal) (void)SkPciReadCfgDWord(pAC,Addr,pVal)
+#else /* VPD_DO_IO */
+#define VPD_OUT8(pAC,IoC,Addr,Val) SK_OUT8(IoC,PCI_C(Addr),Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val) SK_OUT16(IoC,PCI_C(Addr),Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal) SK_IN8(IoC,PCI_C(Addr),pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal) SK_IN16(IoC,PCI_C(Addr),pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal) SK_IN32(IoC,PCI_C(Addr),pVal)
+#endif /* VPD_DO_IO */
+#else /* SKDIAG */
+#define VPD_OUT8(pAC,Ioc,Addr,Val) { \
+ if ((pAC)->DgT.DgUseCfgCycle) \
+ SkPciWriteCfgByte(pAC,Addr,Val); \
+ else \
+ SK_OUT8(pAC,PCI_C(Addr),Val); \
+ }
+#define VPD_OUT16(pAC,Ioc,Addr,Val) { \
+ if ((pAC)->DgT.DgUseCfgCycle) \
+ SkPciWriteCfgWord(pAC,Addr,Val); \
+ else \
+ SK_OUT16(pAC,PCI_C(Addr),Val); \
+ }
+#define VPD_IN8(pAC,Ioc,Addr,pVal) { \
+ if ((pAC)->DgT.DgUseCfgCycle) \
+ SkPciReadCfgByte(pAC,Addr,pVal); \
+ else \
+ SK_IN8(pAC,PCI_C(Addr),pVal); \
+ }
+#define VPD_IN16(pAC,Ioc,Addr,pVal) { \
+ if ((pAC)->DgT.DgUseCfgCycle) \
+ SkPciReadCfgWord(pAC,Addr,pVal); \
+ else \
+ SK_IN16(pAC,PCI_C(Addr),pVal); \
+ }
+#define VPD_IN32(pAC,Ioc,Addr,pVal) { \
+ if ((pAC)->DgT.DgUseCfgCycle) \
+ SkPciReadCfgDWord(pAC,Addr,pVal); \
+ else \
+ SK_IN32(pAC,PCI_C(Addr),pVal); \
+ }
+#endif /* nSKDIAG */
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+#ifdef SKDIAG
+extern SK_U32 VpdReadDWord(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ int addr);
+#endif /* SKDIAG */
+
+extern SK_VPD_STATUS *VpdStat(
+ SK_AC *pAC,
+ SK_IOC IoC);
+
+extern int VpdKeys(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ char *buf,
+ int *len,
+ int *elements);
+
+extern int VpdRead(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ const char *key,
+ char *buf,
+ int *len);
+
+extern SK_BOOL VpdMayWrite(
+ char *key);
+
+extern int VpdWrite(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ const char *key,
+ const char *buf);
+
+extern int VpdDelete(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ char *key);
+
+extern int VpdUpdate(
+ SK_AC *pAC,
+ SK_IOC IoC);
+
+#ifdef SKDIAG
+extern int VpdReadBlock(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ char *buf,
+ int addr,
+ int len);
+
+extern int VpdWriteBlock(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ char *buf,
+ int addr,
+ int len);
+#endif /* SKDIAG */
+#else /* SK_KR_PROTO */
+extern SK_U32 VpdReadDWord();
+extern SK_VPD_STATUS *VpdStat();
+extern int VpdKeys();
+extern int VpdRead();
+extern SK_BOOL VpdMayWrite();
+extern int VpdWrite();
+extern int VpdDelete();
+extern int VpdUpdate();
+#endif /* SK_KR_PROTO */
+
+#endif /* __INC_SKVPD_H_ */
diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h
new file mode 100644
index 000000000000..7f8e6d0084c7
--- /dev/null
+++ b/drivers/net/sk98lin/h/xmac_ii.h
@@ -0,0 +1,1579 @@
+/******************************************************************************
+ *
+ * Name: xmac_ii.h
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.52 $
+ * Date: $Date: 2003/10/02 16:35:50 $
+ * Purpose: Defines and Macros for Gigabit Ethernet Controller
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_XMAC_H
+#define __INC_XMAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * XMAC II registers
+ *
+ * The XMAC registers are 16 or 32 bits wide.
+ * The XMACs host processor interface is set to 16 bit mode,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the XMAC registers
+ * XM_IN16(), XM_OUT16, XM_IN32(), XM_OUT32(), XM_INADR(), XM_OUTADR(),
+ * XM_INHASH(), and XM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note: NA reg = Network Address e.g DA, SA etc.
+ *
+ */
+#define XM_MMU_CMD 0x0000 /* 16 bit r/w MMU Command Register */
+ /* 0x0004: reserved */
+#define XM_POFF 0x0008 /* 32 bit r/w Packet Offset Register */
+#define XM_BURST 0x000c /* 32 bit r/w Burst Register for half duplex*/
+#define XM_1L_VLAN_TAG 0x0010 /* 16 bit r/w One Level VLAN Tag ID */
+#define XM_2L_VLAN_TAG 0x0014 /* 16 bit r/w Two Level VLAN Tag ID */
+ /* 0x0018 - 0x001e: reserved */
+#define XM_TX_CMD 0x0020 /* 16 bit r/w Transmit Command Register */
+#define XM_TX_RT_LIM 0x0024 /* 16 bit r/w Transmit Retry Limit Register */
+#define XM_TX_STIME 0x0028 /* 16 bit r/w Transmit Slottime Register */
+#define XM_TX_IPG 0x002c /* 16 bit r/w Transmit Inter Packet Gap */
+#define XM_RX_CMD 0x0030 /* 16 bit r/w Receive Command Register */
+#define XM_PHY_ADDR 0x0034 /* 16 bit r/w PHY Address Register */
+#define XM_PHY_DATA 0x0038 /* 16 bit r/w PHY Data Register */
+ /* 0x003c: reserved */
+#define XM_GP_PORT 0x0040 /* 32 bit r/w General Purpose Port Register */
+#define XM_IMSK 0x0044 /* 16 bit r/w Interrupt Mask Register */
+#define XM_ISRC 0x0048 /* 16 bit r/o Interrupt Status Register */
+#define XM_HW_CFG 0x004c /* 16 bit r/w Hardware Config Register */
+ /* 0x0050 - 0x005e: reserved */
+#define XM_TX_LO_WM 0x0060 /* 16 bit r/w Tx FIFO Low Water Mark */
+#define XM_TX_HI_WM 0x0062 /* 16 bit r/w Tx FIFO High Water Mark */
+#define XM_TX_THR 0x0064 /* 16 bit r/w Tx Request Threshold */
+#define XM_HT_THR 0x0066 /* 16 bit r/w Host Request Threshold */
+#define XM_PAUSE_DA 0x0068 /* NA reg r/w Pause Destination Address */
+ /* 0x006e: reserved */
+#define XM_CTL_PARA 0x0070 /* 32 bit r/w Control Parameter Register */
+#define XM_MAC_OPCODE 0x0074 /* 16 bit r/w Opcode for MAC control frames */
+#define XM_MAC_PTIME 0x0076 /* 16 bit r/w Pause time for MAC ctrl frames*/
+#define XM_TX_STAT 0x0078 /* 32 bit r/o Tx Status LIFO Register */
+
+ /* 0x0080 - 0x00fc: 16 NA reg r/w Exact Match Address Registers */
+ /* use the XM_EXM() macro to address */
+#define XM_EXM_START 0x0080 /* r/w Start Address of the EXM Regs */
+
+ /*
+ * XM_EXM(Reg)
+ *
+ * returns the XMAC address offset of specified Exact Match Addr Reg
+ *
+ * para: Reg EXM register to addr (0 .. 15)
+ *
+ * usage: XM_INADDR(IoC, MAC_1, XM_EXM(i), &val[i]);
+ */
+#define XM_EXM(Reg) (XM_EXM_START + ((Reg) << 3))
+
+#define XM_SRC_CHK 0x0100 /* NA reg r/w Source Check Address Register */
+#define XM_SA 0x0108 /* NA reg r/w Station Address Register */
+#define XM_HSM 0x0110 /* 64 bit r/w Hash Match Address Registers */
+#define XM_RX_LO_WM 0x0118 /* 16 bit r/w Receive Low Water Mark */
+#define XM_RX_HI_WM 0x011a /* 16 bit r/w Receive High Water Mark */
+#define XM_RX_THR 0x011c /* 32 bit r/w Receive Request Threshold */
+#define XM_DEV_ID 0x0120 /* 32 bit r/o Device ID Register */
+#define XM_MODE 0x0124 /* 32 bit r/w Mode Register */
+#define XM_LSA 0x0128 /* NA reg r/o Last Source Register */
+ /* 0x012e: reserved */
+#define XM_TS_READ 0x0130 /* 32 bit r/o Time Stamp Read Register */
+#define XM_TS_LOAD 0x0134 /* 32 bit r/o Time Stamp Load Value */
+ /* 0x0138 - 0x01fe: reserved */
+#define XM_STAT_CMD 0x0200 /* 16 bit r/w Statistics Command Register */
+#define XM_RX_CNT_EV 0x0204 /* 32 bit r/o Rx Counter Event Register */
+#define XM_TX_CNT_EV 0x0208 /* 32 bit r/o Tx Counter Event Register */
+#define XM_RX_EV_MSK 0x020c /* 32 bit r/w Rx Counter Event Mask */
+#define XM_TX_EV_MSK 0x0210 /* 32 bit r/w Tx Counter Event Mask */
+ /* 0x0204 - 0x027e: reserved */
+#define XM_TXF_OK 0x0280 /* 32 bit r/o Frames Transmitted OK Conuter */
+#define XM_TXO_OK_HI 0x0284 /* 32 bit r/o Octets Transmitted OK High Cnt*/
+#define XM_TXO_OK_LO 0x0288 /* 32 bit r/o Octets Transmitted OK Low Cnt */
+#define XM_TXF_BC_OK 0x028c /* 32 bit r/o Broadcast Frames Xmitted OK */
+#define XM_TXF_MC_OK 0x0290 /* 32 bit r/o Multicast Frames Xmitted OK */
+#define XM_TXF_UC_OK 0x0294 /* 32 bit r/o Unicast Frames Xmitted OK */
+#define XM_TXF_LONG 0x0298 /* 32 bit r/o Tx Long Frame Counter */
+#define XM_TXE_BURST 0x029c /* 32 bit r/o Tx Burst Event Counter */
+#define XM_TXF_MPAUSE 0x02a0 /* 32 bit r/o Tx Pause MAC Ctrl Frame Cnt */
+#define XM_TXF_MCTRL 0x02a4 /* 32 bit r/o Tx MAC Ctrl Frame Counter */
+#define XM_TXF_SNG_COL 0x02a8 /* 32 bit r/o Tx Single Collision Counter */
+#define XM_TXF_MUL_COL 0x02ac /* 32 bit r/o Tx Multiple Collision Counter */
+#define XM_TXF_ABO_COL 0x02b0 /* 32 bit r/o Tx aborted due to Exces. Col. */
+#define XM_TXF_LAT_COL 0x02b4 /* 32 bit r/o Tx Late Collision Counter */
+#define XM_TXF_DEF 0x02b8 /* 32 bit r/o Tx Deferred Frame Counter */
+#define XM_TXF_EX_DEF 0x02bc /* 32 bit r/o Tx Excessive Deferall Counter */
+#define XM_TXE_FIFO_UR 0x02c0 /* 32 bit r/o Tx FIFO Underrun Event Cnt */
+#define XM_TXE_CS_ERR 0x02c4 /* 32 bit r/o Tx Carrier Sense Error Cnt */
+#define XM_TXP_UTIL 0x02c8 /* 32 bit r/o Tx Utilization in % */
+ /* 0x02cc - 0x02ce: reserved */
+#define XM_TXF_64B 0x02d0 /* 32 bit r/o 64 Byte Tx Frame Counter */
+#define XM_TXF_127B 0x02d4 /* 32 bit r/o 65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B 0x02d8 /* 32 bit r/o 128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B 0x02dc /* 32 bit r/o 256-511 Byte Tx Frame Counter */
+#define XM_TXF_1023B 0x02e0 /* 32 bit r/o 512-1023 Byte Tx Frame Counter*/
+#define XM_TXF_MAX_SZ 0x02e4 /* 32 bit r/o 1024-MaxSize Byte Tx Frame Cnt*/
+ /* 0x02e8 - 0x02fe: reserved */
+#define XM_RXF_OK 0x0300 /* 32 bit r/o Frames Received OK */
+#define XM_RXO_OK_HI 0x0304 /* 32 bit r/o Octets Received OK High Cnt */
+#define XM_RXO_OK_LO 0x0308 /* 32 bit r/o Octets Received OK Low Counter*/
+#define XM_RXF_BC_OK 0x030c /* 32 bit r/o Broadcast Frames Received OK */
+#define XM_RXF_MC_OK 0x0310 /* 32 bit r/o Multicast Frames Received OK */
+#define XM_RXF_UC_OK 0x0314 /* 32 bit r/o Unicast Frames Received OK */
+#define XM_RXF_MPAUSE 0x0318 /* 32 bit r/o Rx Pause MAC Ctrl Frame Cnt */
+#define XM_RXF_MCTRL 0x031c /* 32 bit r/o Rx MAC Ctrl Frame Counter */
+#define XM_RXF_INV_MP 0x0320 /* 32 bit r/o Rx invalid Pause Frame Cnt */
+#define XM_RXF_INV_MOC 0x0324 /* 32 bit r/o Rx Frames with inv. MAC Opcode*/
+#define XM_RXE_BURST 0x0328 /* 32 bit r/o Rx Burst Event Counter */
+#define XM_RXE_FMISS 0x032c /* 32 bit r/o Rx Missed Frames Event Cnt */
+#define XM_RXF_FRA_ERR 0x0330 /* 32 bit r/o Rx Framing Error Counter */
+#define XM_RXE_FIFO_OV 0x0334 /* 32 bit r/o Rx FIFO overflow Event Cnt */
+#define XM_RXF_JAB_PKT 0x0338 /* 32 bit r/o Rx Jabber Packet Frame Cnt */
+#define XM_RXE_CAR_ERR 0x033c /* 32 bit r/o Rx Carrier Event Error Cnt */
+#define XM_RXF_LEN_ERR 0x0340 /* 32 bit r/o Rx in Range Length Error */
+#define XM_RXE_SYM_ERR 0x0344 /* 32 bit r/o Rx Symbol Error Counter */
+#define XM_RXE_SHT_ERR 0x0348 /* 32 bit r/o Rx Short Event Error Cnt */
+#define XM_RXE_RUNT 0x034c /* 32 bit r/o Rx Runt Event Counter */
+#define XM_RXF_LNG_ERR 0x0350 /* 32 bit r/o Rx Frame too Long Error Cnt */
+#define XM_RXF_FCS_ERR 0x0354 /* 32 bit r/o Rx Frame Check Seq. Error Cnt */
+ /* 0x0358 - 0x035a: reserved */
+#define XM_RXF_CEX_ERR 0x035c /* 32 bit r/o Rx Carrier Ext Error Frame Cnt*/
+#define XM_RXP_UTIL 0x0360 /* 32 bit r/o Rx Utilization in % */
+ /* 0x0364 - 0x0366: reserved */
+#define XM_RXF_64B 0x0368 /* 32 bit r/o 64 Byte Rx Frame Counter */
+#define XM_RXF_127B 0x036c /* 32 bit r/o 65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B 0x0370 /* 32 bit r/o 128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B 0x0374 /* 32 bit r/o 256-511 Byte Rx Frame Counter */
+#define XM_RXF_1023B 0x0378 /* 32 bit r/o 512-1023 Byte Rx Frame Counter*/
+#define XM_RXF_MAX_SZ 0x037c /* 32 bit r/o 1024-MaxSize Byte Rx Frame Cnt*/
+ /* 0x02e8 - 0x02fe: reserved */
+
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ * (sc) self clearing
+ * (ro) read only
+ */
+
+/* XM_MMU_CMD 16 bit r/w MMU Command Register */
+ /* Bit 15..13: reserved */
+#define XM_MMU_PHY_RDY (1<<12) /* Bit 12: PHY Read Ready */
+#define XM_MMU_PHY_BUSY (1<<11) /* Bit 11: PHY Busy */
+#define XM_MMU_IGN_PF (1<<10) /* Bit 10: Ignore Pause Frame */
+#define XM_MMU_MAC_LB (1<<9) /* Bit 9: Enable MAC Loopback */
+ /* Bit 8: reserved */
+#define XM_MMU_FRC_COL (1<<7) /* Bit 7: Force Collision */
+#define XM_MMU_SIM_COL (1<<6) /* Bit 6: Simulate Collision */
+#define XM_MMU_NO_PRE (1<<5) /* Bit 5: No MDIO Preamble */
+#define XM_MMU_GMII_FD (1<<4) /* Bit 4: GMII uses Full Duplex */
+#define XM_MMU_RAT_CTRL (1<<3) /* Bit 3: Enable Rate Control */
+#define XM_MMU_GMII_LOOP (1<<2) /* Bit 2: PHY is in Loopback Mode */
+#define XM_MMU_ENA_RX (1<<1) /* Bit 1: Enable Receiver */
+#define XM_MMU_ENA_TX (1<<0) /* Bit 0: Enable Transmitter */
+
+
+/* XM_TX_CMD 16 bit r/w Transmit Command Register */
+ /* Bit 15..7: reserved */
+#define XM_TX_BK2BK (1<<6) /* Bit 6: Ignor Carrier Sense (Tx Bk2Bk)*/
+#define XM_TX_ENC_BYP (1<<5) /* Bit 5: Set Encoder in Bypass Mode */
+#define XM_TX_SAM_LINE (1<<4) /* Bit 4: (sc) Start utilization calculation */
+#define XM_TX_NO_GIG_MD (1<<3) /* Bit 3: Disable Carrier Extension */
+#define XM_TX_NO_PRE (1<<2) /* Bit 2: Disable Preamble Generation */
+#define XM_TX_NO_CRC (1<<1) /* Bit 1: Disable CRC Generation */
+#define XM_TX_AUTO_PAD (1<<0) /* Bit 0: Enable Automatic Padding */
+
+
+/* XM_TX_RT_LIM 16 bit r/w Transmit Retry Limit Register */
+ /* Bit 15..5: reserved */
+#define XM_RT_LIM_MSK 0x1f /* Bit 4..0: Tx Retry Limit */
+
+
+/* XM_TX_STIME 16 bit r/w Transmit Slottime Register */
+ /* Bit 15..7: reserved */
+#define XM_STIME_MSK 0x7f /* Bit 6..0: Tx Slottime bits */
+
+
+/* XM_TX_IPG 16 bit r/w Transmit Inter Packet Gap */
+ /* Bit 15..8: reserved */
+#define XM_IPG_MSK 0xff /* Bit 7..0: IPG value bits */
+
+
+/* XM_RX_CMD 16 bit r/w Receive Command Register */
+ /* Bit 15..9: reserved */
+#define XM_RX_LENERR_OK (1<<8) /* Bit 8 don't set Rx Err bit for */
+ /* inrange error packets */
+#define XM_RX_BIG_PK_OK (1<<7) /* Bit 7 don't set Rx Err bit for */
+ /* jumbo packets */
+#define XM_RX_IPG_CAP (1<<6) /* Bit 6 repl. type field with IPG */
+#define XM_RX_TP_MD (1<<5) /* Bit 5: Enable transparent Mode */
+#define XM_RX_STRIP_FCS (1<<4) /* Bit 4: Enable FCS Stripping */
+#define XM_RX_SELF_RX (1<<3) /* Bit 3: Enable Rx of own packets */
+#define XM_RX_SAM_LINE (1<<2) /* Bit 2: (sc) Start utilization calculation */
+#define XM_RX_STRIP_PAD (1<<1) /* Bit 1: Strip pad bytes of Rx frames */
+#define XM_RX_DIS_CEXT (1<<0) /* Bit 0: Disable carrier ext. check */
+
+
+/* XM_PHY_ADDR 16 bit r/w PHY Address Register */
+ /* Bit 15..5: reserved */
+#define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */
+
+
+/* XM_GP_PORT 32 bit r/w General Purpose Port Register */
+ /* Bit 31..7: reserved */
+#define XM_GP_ANIP (1L<<6) /* Bit 6: (ro) Auto-Neg. in progress */
+#define XM_GP_FRC_INT (1L<<5) /* Bit 5: (sc) Force Interrupt */
+ /* Bit 4: reserved */
+#define XM_GP_RES_MAC (1L<<3) /* Bit 3: (sc) Reset MAC and FIFOs */
+#define XM_GP_RES_STAT (1L<<2) /* Bit 2: (sc) Reset the statistics module */
+ /* Bit 1: reserved */
+#define XM_GP_INP_ASS (1L<<0) /* Bit 0: (ro) GP Input Pin asserted */
+
+
+/* XM_IMSK 16 bit r/w Interrupt Mask Register */
+/* XM_ISRC 16 bit r/o Interrupt Status Register */
+ /* Bit 15: reserved */
+#define XM_IS_LNK_AE (1<<14) /* Bit 14: Link Asynchronous Event */
+#define XM_IS_TX_ABORT (1<<13) /* Bit 13: Transmit Abort, late Col. etc */
+#define XM_IS_FRC_INT (1<<12) /* Bit 12: Force INT bit set in GP */
+#define XM_IS_INP_ASS (1<<11) /* Bit 11: Input Asserted, GP bit 0 set */
+#define XM_IS_LIPA_RC (1<<10) /* Bit 10: Link Partner requests config */
+#define XM_IS_RX_PAGE (1<<9) /* Bit 9: Page Received */
+#define XM_IS_TX_PAGE (1<<8) /* Bit 8: Next Page Loaded for Transmit */
+#define XM_IS_AND (1<<7) /* Bit 7: Auto-Negotiation Done */
+#define XM_IS_TSC_OV (1<<6) /* Bit 6: Time Stamp Counter Overflow */
+#define XM_IS_RXC_OV (1<<5) /* Bit 5: Rx Counter Event Overflow */
+#define XM_IS_TXC_OV (1<<4) /* Bit 4: Tx Counter Event Overflow */
+#define XM_IS_RXF_OV (1<<3) /* Bit 3: Receive FIFO Overflow */
+#define XM_IS_TXF_UR (1<<2) /* Bit 2: Transmit FIFO Underrun */
+#define XM_IS_TX_COMP (1<<1) /* Bit 1: Frame Tx Complete */
+#define XM_IS_RX_COMP (1<<0) /* Bit 0: Frame Rx Complete */
+
+#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\
+ XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR))
+
+
+/* XM_HW_CFG 16 bit r/w Hardware Config Register */
+ /* Bit 15.. 4: reserved */
+#define XM_HW_GEN_EOP (1<<3) /* Bit 3: generate End of Packet pulse */
+#define XM_HW_COM4SIG (1<<2) /* Bit 2: use Comma Detect for Sig. Det.*/
+ /* Bit 1: reserved */
+#define XM_HW_GMII_MD (1<<0) /* Bit 0: GMII Interface selected */
+
+
+/* XM_TX_LO_WM 16 bit r/w Tx FIFO Low Water Mark */
+/* XM_TX_HI_WM 16 bit r/w Tx FIFO High Water Mark */
+ /* Bit 15..10 reserved */
+#define XM_TX_WM_MSK 0x01ff /* Bit 9.. 0 Tx FIFO Watermark bits */
+
+/* XM_TX_THR 16 bit r/w Tx Request Threshold */
+/* XM_HT_THR 16 bit r/w Host Request Threshold */
+/* XM_RX_THR 16 bit r/w Rx Request Threshold */
+ /* Bit 15..11 reserved */
+#define XM_THR_MSK 0x03ff /* Bit 10.. 0 Rx/Tx Request Threshold bits */
+
+
+/* XM_TX_STAT 32 bit r/o Tx Status LIFO Register */
+#define XM_ST_VALID (1UL<<31) /* Bit 31: Status Valid */
+#define XM_ST_BYTE_CNT (0x3fffL<<17) /* Bit 30..17: Tx frame Length */
+#define XM_ST_RETRY_CNT (0x1fL<<12) /* Bit 16..12: Retry Count */
+#define XM_ST_EX_COL (1L<<11) /* Bit 11: Excessive Collisions */
+#define XM_ST_EX_DEF (1L<<10) /* Bit 10: Excessive Deferral */
+#define XM_ST_BURST (1L<<9) /* Bit 9: p. xmitted in burst md*/
+#define XM_ST_DEFER (1L<<8) /* Bit 8: packet was defered */
+#define XM_ST_BC (1L<<7) /* Bit 7: Broadcast packet */
+#define XM_ST_MC (1L<<6) /* Bit 6: Multicast packet */
+#define XM_ST_UC (1L<<5) /* Bit 5: Unicast packet */
+#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occured */
+#define XM_ST_CS_ERR (1L<<3) /* Bit 3: Carrier Sense Error */
+#define XM_ST_LAT_COL (1L<<2) /* Bit 2: Late Collision Error */
+#define XM_ST_MUL_COL (1L<<1) /* Bit 1: Multiple Collisions */
+#define XM_ST_SGN_COL (1L<<0) /* Bit 0: Single Collision */
+
+/* XM_RX_LO_WM 16 bit r/w Receive Low Water Mark */
+/* XM_RX_HI_WM 16 bit r/w Receive High Water Mark */
+ /* Bit 15..11: reserved */
+#define XM_RX_WM_MSK 0x03ff /* Bit 11.. 0: Rx FIFO Watermark bits */
+
+
+/* XM_DEV_ID 32 bit r/o Device ID Register */
+#define XM_DEV_OUI (0x00ffffffUL<<8) /* Bit 31..8: Device OUI */
+#define XM_DEV_REV (0x07L << 5) /* Bit 7..5: Chip Rev Num */
+
+
+/* XM_MODE 32 bit r/w Mode Register */
+ /* Bit 31..27: reserved */
+#define XM_MD_ENA_REJ (1L<<26) /* Bit 26: Enable Frame Reject */
+#define XM_MD_SPOE_E (1L<<25) /* Bit 25: Send Pause on Edge */
+ /* extern generated */
+#define XM_MD_TX_REP (1L<<24) /* Bit 24: Transmit Repeater Mode */
+#define XM_MD_SPOFF_I (1L<<23) /* Bit 23: Send Pause on FIFO full */
+ /* intern generated */
+#define XM_MD_LE_STW (1L<<22) /* Bit 22: Rx Stat Word in Little Endian */
+#define XM_MD_TX_CONT (1L<<21) /* Bit 21: Send Continuous */
+#define XM_MD_TX_PAUSE (1L<<20) /* Bit 20: (sc) Send Pause Frame */
+#define XM_MD_ATS (1L<<19) /* Bit 19: Append Time Stamp */
+#define XM_MD_SPOL_I (1L<<18) /* Bit 18: Send Pause on Low */
+ /* intern generated */
+#define XM_MD_SPOH_I (1L<<17) /* Bit 17: Send Pause on High */
+ /* intern generated */
+#define XM_MD_CAP (1L<<16) /* Bit 16: Check Address Pair */
+#define XM_MD_ENA_HASH (1L<<15) /* Bit 15: Enable Hashing */
+#define XM_MD_CSA (1L<<14) /* Bit 14: Check Station Address */
+#define XM_MD_CAA (1L<<13) /* Bit 13: Check Address Array */
+#define XM_MD_RX_MCTRL (1L<<12) /* Bit 12: Rx MAC Control Frame */
+#define XM_MD_RX_RUNT (1L<<11) /* Bit 11: Rx Runt Frames */
+#define XM_MD_RX_IRLE (1L<<10) /* Bit 10: Rx in Range Len Err Frame */
+#define XM_MD_RX_LONG (1L<<9) /* Bit 9: Rx Long Frame */
+#define XM_MD_RX_CRCE (1L<<8) /* Bit 8: Rx CRC Error Frame */
+#define XM_MD_RX_ERR (1L<<7) /* Bit 7: Rx Error Frame */
+#define XM_MD_DIS_UC (1L<<6) /* Bit 6: Disable Rx Unicast */
+#define XM_MD_DIS_MC (1L<<5) /* Bit 5: Disable Rx Multicast */
+#define XM_MD_DIS_BC (1L<<4) /* Bit 4: Disable Rx Broadcast */
+#define XM_MD_ENA_PROM (1L<<3) /* Bit 3: Enable Promiscuous */
+#define XM_MD_ENA_BE (1L<<2) /* Bit 2: Enable Big Endian */
+#define XM_MD_FTF (1L<<1) /* Bit 1: (sc) Flush Tx FIFO */
+#define XM_MD_FRF (1L<<0) /* Bit 0: (sc) Flush Rx FIFO */
+
+#define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+ XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+
+/* XM_STAT_CMD 16 bit r/w Statistics Command Register */
+ /* Bit 16..6: reserved */
+#define XM_SC_SNP_RXC (1<<5) /* Bit 5: (sc) Snap Rx Counters */
+#define XM_SC_SNP_TXC (1<<4) /* Bit 4: (sc) Snap Tx Counters */
+#define XM_SC_CP_RXC (1<<3) /* Bit 3: Copy Rx Counters Continuously */
+#define XM_SC_CP_TXC (1<<2) /* Bit 2: Copy Tx Counters Continuously */
+#define XM_SC_CLR_RXC (1<<1) /* Bit 1: (sc) Clear Rx Counters */
+#define XM_SC_CLR_TXC (1<<0) /* Bit 0: (sc) Clear Tx Counters */
+
+
+/* XM_RX_CNT_EV 32 bit r/o Rx Counter Event Register */
+/* XM_RX_EV_MSK 32 bit r/w Rx Counter Event Mask */
+#define XMR_MAX_SZ_OV (1UL<<31) /* Bit 31: 1024-MaxSize Rx Cnt Ov*/
+#define XMR_1023B_OV (1L<<30) /* Bit 30: 512-1023Byte Rx Cnt Ov*/
+#define XMR_511B_OV (1L<<29) /* Bit 29: 256-511 Byte Rx Cnt Ov*/
+#define XMR_255B_OV (1L<<28) /* Bit 28: 128-255 Byte Rx Cnt Ov*/
+#define XMR_127B_OV (1L<<27) /* Bit 27: 65-127 Byte Rx Cnt Ov */
+#define XMR_64B_OV (1L<<26) /* Bit 26: 64 Byte Rx Cnt Ov */
+#define XMR_UTIL_OV (1L<<25) /* Bit 25: Rx Util Cnt Overflow */
+#define XMR_UTIL_UR (1L<<24) /* Bit 24: Rx Util Cnt Underrun */
+#define XMR_CEX_ERR_OV (1L<<23) /* Bit 23: CEXT Err Cnt Ov */
+ /* Bit 22: reserved */
+#define XMR_FCS_ERR_OV (1L<<21) /* Bit 21: Rx FCS Error Cnt Ov */
+#define XMR_LNG_ERR_OV (1L<<20) /* Bit 20: Rx too Long Err Cnt Ov*/
+#define XMR_RUNT_OV (1L<<19) /* Bit 19: Runt Event Cnt Ov */
+#define XMR_SHT_ERR_OV (1L<<18) /* Bit 18: Rx Short Ev Err Cnt Ov*/
+#define XMR_SYM_ERR_OV (1L<<17) /* Bit 17: Rx Sym Err Cnt Ov */
+ /* Bit 16: reserved */
+#define XMR_CAR_ERR_OV (1L<<15) /* Bit 15: Rx Carr Ev Err Cnt Ov */
+#define XMR_JAB_PKT_OV (1L<<14) /* Bit 14: Rx Jabb Packet Cnt Ov */
+#define XMR_FIFO_OV (1L<<13) /* Bit 13: Rx FIFO Ov Ev Cnt Ov */
+#define XMR_FRA_ERR_OV (1L<<12) /* Bit 12: Rx Framing Err Cnt Ov */
+#define XMR_FMISS_OV (1L<<11) /* Bit 11: Rx Missed Ev Cnt Ov */
+#define XMR_BURST (1L<<10) /* Bit 10: Rx Burst Event Cnt Ov */
+#define XMR_INV_MOC (1L<<9) /* Bit 9: Rx with inv. MAC OC Ov*/
+#define XMR_INV_MP (1L<<8) /* Bit 8: Rx inv Pause Frame Ov */
+#define XMR_MCTRL_OV (1L<<7) /* Bit 7: Rx MAC Ctrl-F Cnt Ov */
+#define XMR_MPAUSE_OV (1L<<6) /* Bit 6: Rx Pause MAC Ctrl-F Ov*/
+#define XMR_UC_OK_OV (1L<<5) /* Bit 5: Rx Unicast Frame CntOv*/
+#define XMR_MC_OK_OV (1L<<4) /* Bit 4: Rx Multicast Cnt Ov */
+#define XMR_BC_OK_OV (1L<<3) /* Bit 3: Rx Broadcast Cnt Ov */
+#define XMR_OK_LO_OV (1L<<2) /* Bit 2: Octets Rx OK Low CntOv*/
+#define XMR_OK_HI_OV (1L<<1) /* Bit 1: Octets Rx OK Hi Cnt Ov*/
+#define XMR_OK_OV (1L<<0) /* Bit 0: Frames Received Ok Ov */
+
+#define XMR_DEF_MSK (XMR_OK_LO_OV | XMR_OK_HI_OV)
+
+/* XM_TX_CNT_EV 32 bit r/o Tx Counter Event Register */
+/* XM_TX_EV_MSK 32 bit r/w Tx Counter Event Mask */
+ /* Bit 31..26: reserved */
+#define XMT_MAX_SZ_OV (1L<<25) /* Bit 25: 1024-MaxSize Tx Cnt Ov*/
+#define XMT_1023B_OV (1L<<24) /* Bit 24: 512-1023Byte Tx Cnt Ov*/
+#define XMT_511B_OV (1L<<23) /* Bit 23: 256-511 Byte Tx Cnt Ov*/
+#define XMT_255B_OV (1L<<22) /* Bit 22: 128-255 Byte Tx Cnt Ov*/
+#define XMT_127B_OV (1L<<21) /* Bit 21: 65-127 Byte Tx Cnt Ov */
+#define XMT_64B_OV (1L<<20) /* Bit 20: 64 Byte Tx Cnt Ov */
+#define XMT_UTIL_OV (1L<<19) /* Bit 19: Tx Util Cnt Overflow */
+#define XMT_UTIL_UR (1L<<18) /* Bit 18: Tx Util Cnt Underrun */
+#define XMT_CS_ERR_OV (1L<<17) /* Bit 17: Tx Carr Sen Err Cnt Ov*/
+#define XMT_FIFO_UR_OV (1L<<16) /* Bit 16: Tx FIFO Ur Ev Cnt Ov */
+#define XMT_EX_DEF_OV (1L<<15) /* Bit 15: Tx Ex Deferall Cnt Ov */
+#define XMT_DEF (1L<<14) /* Bit 14: Tx Deferred Cnt Ov */
+#define XMT_LAT_COL_OV (1L<<13) /* Bit 13: Tx Late Col Cnt Ov */
+#define XMT_ABO_COL_OV (1L<<12) /* Bit 12: Tx abo dueto Ex Col Ov*/
+#define XMT_MUL_COL_OV (1L<<11) /* Bit 11: Tx Mult Col Cnt Ov */
+#define XMT_SNG_COL (1L<<10) /* Bit 10: Tx Single Col Cnt Ov */
+#define XMT_MCTRL_OV (1L<<9) /* Bit 9: Tx MAC Ctrl Counter Ov*/
+#define XMT_MPAUSE (1L<<8) /* Bit 8: Tx Pause MAC Ctrl-F Ov*/
+#define XMT_BURST (1L<<7) /* Bit 7: Tx Burst Event Cnt Ov */
+#define XMT_LONG (1L<<6) /* Bit 6: Tx Long Frame Cnt Ov */
+#define XMT_UC_OK_OV (1L<<5) /* Bit 5: Tx Unicast Cnt Ov */
+#define XMT_MC_OK_OV (1L<<4) /* Bit 4: Tx Multicast Cnt Ov */
+#define XMT_BC_OK_OV (1L<<3) /* Bit 3: Tx Broadcast Cnt Ov */
+#define XMT_OK_LO_OV (1L<<2) /* Bit 2: Octets Tx OK Low CntOv*/
+#define XMT_OK_HI_OV (1L<<1) /* Bit 1: Octets Tx OK Hi Cnt Ov*/
+#define XMT_OK_OV (1L<<0) /* Bit 0: Frames Tx Ok Ov */
+
+#define XMT_DEF_MSK (XMT_OK_LO_OV | XMT_OK_HI_OV)
+
+/*
+ * Receive Frame Status Encoding
+ */
+#define XMR_FS_LEN (0x3fffUL<<18) /* Bit 31..18: Rx Frame Length */
+#define XMR_FS_2L_VLAN (1L<<17) /* Bit 17: tagged wh 2Lev VLAN ID*/
+#define XMR_FS_1L_VLAN (1L<<16) /* Bit 16: tagged wh 1Lev VLAN ID*/
+#define XMR_FS_BC (1L<<15) /* Bit 15: Broadcast Frame */
+#define XMR_FS_MC (1L<<14) /* Bit 14: Multicast Frame */
+#define XMR_FS_UC (1L<<13) /* Bit 13: Unicast Frame */
+ /* Bit 12: reserved */
+#define XMR_FS_BURST (1L<<11) /* Bit 11: Burst Mode */
+#define XMR_FS_CEX_ERR (1L<<10) /* Bit 10: Carrier Ext. Error */
+#define XMR_FS_802_3 (1L<<9) /* Bit 9: 802.3 Frame */
+#define XMR_FS_COL_ERR (1L<<8) /* Bit 8: Collision Error */
+#define XMR_FS_CAR_ERR (1L<<7) /* Bit 7: Carrier Event Error */
+#define XMR_FS_LEN_ERR (1L<<6) /* Bit 6: In-Range Length Error */
+#define XMR_FS_FRA_ERR (1L<<5) /* Bit 5: Framing Error */
+#define XMR_FS_RUNT (1L<<4) /* Bit 4: Runt Frame */
+#define XMR_FS_LNG_ERR (1L<<3) /* Bit 3: Giant (Jumbo) Frame */
+#define XMR_FS_FCS_ERR (1L<<2) /* Bit 2: Frame Check Sequ Err */
+#define XMR_FS_ERR (1L<<1) /* Bit 1: Frame Error */
+#define XMR_FS_MCTRL (1L<<0) /* Bit 0: MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ * XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ * XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+#define XMR_FS_ANY_ERR XMR_FS_ERR
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+#define PHY_XMAC_CTRL 0x00 /* 16 bit r/w PHY Control Register */
+#define PHY_XMAC_STAT 0x01 /* 16 bit r/w PHY Status Register */
+#define PHY_XMAC_ID0 0x02 /* 16 bit r/o PHY ID0 Register */
+#define PHY_XMAC_ID1 0x03 /* 16 bit r/o PHY ID1 Register */
+#define PHY_XMAC_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */
+#define PHY_XMAC_AUNE_LP 0x05 /* 16 bit r/o Link Partner Abi Reg */
+#define PHY_XMAC_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */
+#define PHY_XMAC_NEPG 0x07 /* 16 bit r/w Next Page Register */
+#define PHY_XMAC_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */
+ /* 0x09 - 0x0e: reserved */
+#define PHY_XMAC_EXT_STAT 0x0f /* 16 bit r/o Ext Status Register */
+#define PHY_XMAC_RES_ABI 0x10 /* 16 bit r/o PHY Resolved Ability */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_BCOM_CTRL 0x00 /* 16 bit r/w PHY Control Register */
+#define PHY_BCOM_STAT 0x01 /* 16 bit r/o PHY Status Register */
+#define PHY_BCOM_ID0 0x02 /* 16 bit r/o PHY ID0 Register */
+#define PHY_BCOM_ID1 0x03 /* 16 bit r/o PHY ID1 Register */
+#define PHY_BCOM_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */
+#define PHY_BCOM_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */
+#define PHY_BCOM_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */
+#define PHY_BCOM_NEPG 0x07 /* 16 bit r/w Next Page Register */
+#define PHY_BCOM_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */
+ /* Broadcom-specific registers */
+#define PHY_BCOM_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */
+#define PHY_BCOM_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */
+ /* 0x0b - 0x0e: reserved */
+#define PHY_BCOM_EXT_STAT 0x0f /* 16 bit r/o Extended Status Reg */
+#define PHY_BCOM_P_EXT_CTRL 0x10 /* 16 bit r/w PHY Extended Ctrl Reg */
+#define PHY_BCOM_P_EXT_STAT 0x11 /* 16 bit r/o PHY Extended Stat Reg */
+#define PHY_BCOM_RE_CTR 0x12 /* 16 bit r/w Receive Error Counter */
+#define PHY_BCOM_FC_CTR 0x13 /* 16 bit r/w False Carrier Sense Cnt */
+#define PHY_BCOM_RNO_CTR 0x14 /* 16 bit r/w Receiver NOT_OK Cnt */
+ /* 0x15 - 0x17: reserved */
+#define PHY_BCOM_AUX_CTRL 0x18 /* 16 bit r/w Auxiliary Control Reg */
+#define PHY_BCOM_AUX_STAT 0x19 /* 16 bit r/o Auxiliary Stat Summary */
+#define PHY_BCOM_INT_STAT 0x1a /* 16 bit r/o Interrupt Status Reg */
+#define PHY_BCOM_INT_MASK 0x1b /* 16 bit r/w Interrupt Mask Reg */
+ /* 0x1c: reserved */
+ /* 0x1d - 0x1f: test registers */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+#define PHY_MARV_CTRL 0x00 /* 16 bit r/w PHY Control Register */
+#define PHY_MARV_STAT 0x01 /* 16 bit r/o PHY Status Register */
+#define PHY_MARV_ID0 0x02 /* 16 bit r/o PHY ID0 Register */
+#define PHY_MARV_ID1 0x03 /* 16 bit r/o PHY ID1 Register */
+#define PHY_MARV_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */
+#define PHY_MARV_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */
+#define PHY_MARV_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */
+#define PHY_MARV_NEPG 0x07 /* 16 bit r/w Next Page Register */
+#define PHY_MARV_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */
+ /* Marvel-specific registers */
+#define PHY_MARV_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Ctrl Reg */
+#define PHY_MARV_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */
+ /* 0x0b - 0x0e: reserved */
+#define PHY_MARV_EXT_STAT 0x0f /* 16 bit r/o Extended Status Reg */
+#define PHY_MARV_PHY_CTRL 0x10 /* 16 bit r/w PHY Specific Ctrl Reg */
+#define PHY_MARV_PHY_STAT 0x11 /* 16 bit r/o PHY Specific Stat Reg */
+#define PHY_MARV_INT_MASK 0x12 /* 16 bit r/w Interrupt Mask Reg */
+#define PHY_MARV_INT_STAT 0x13 /* 16 bit r/o Interrupt Status Reg */
+#define PHY_MARV_EXT_CTRL 0x14 /* 16 bit r/w Ext. PHY Specific Ctrl */
+#define PHY_MARV_RXE_CNT 0x15 /* 16 bit r/w Receive Error Counter */
+#define PHY_MARV_EXT_ADR 0x16 /* 16 bit r/w Ext. Ad. for Cable Diag. */
+ /* 0x17: reserved */
+#define PHY_MARV_LED_CTRL 0x18 /* 16 bit r/w LED Control Reg */
+#define PHY_MARV_LED_OVER 0x19 /* 16 bit r/w Manual LED Override Reg */
+#define PHY_MARV_EXT_CTRL_2 0x1a /* 16 bit r/w Ext. PHY Specific Ctrl 2 */
+#define PHY_MARV_EXT_P_STAT 0x1b /* 16 bit r/w Ext. PHY Spec. Stat Reg */
+#define PHY_MARV_CABLE_DIAG 0x1c /* 16 bit r/o Cable Diagnostic Reg */
+ /* 0x1d - 0x1f: reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Level One-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_LONE_CTRL 0x00 /* 16 bit r/w PHY Control Register */
+#define PHY_LONE_STAT 0x01 /* 16 bit r/o PHY Status Register */
+#define PHY_LONE_ID0 0x02 /* 16 bit r/o PHY ID0 Register */
+#define PHY_LONE_ID1 0x03 /* 16 bit r/o PHY ID1 Register */
+#define PHY_LONE_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */
+#define PHY_LONE_AUNE_LP 0x05 /* 16 bit r/o Link Part Ability Reg */
+#define PHY_LONE_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */
+#define PHY_LONE_NEPG 0x07 /* 16 bit r/w Next Page Register */
+#define PHY_LONE_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner */
+ /* Level One-specific registers */
+#define PHY_LONE_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Control Reg*/
+#define PHY_LONE_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */
+ /* 0x0b -0x0e: reserved */
+#define PHY_LONE_EXT_STAT 0x0f /* 16 bit r/o Extended Status Reg */
+#define PHY_LONE_PORT_CFG 0x10 /* 16 bit r/w Port Configuration Reg*/
+#define PHY_LONE_Q_STAT 0x11 /* 16 bit r/o Quick Status Reg */
+#define PHY_LONE_INT_ENAB 0x12 /* 16 bit r/w Interrupt Enable Reg */
+#define PHY_LONE_INT_STAT 0x13 /* 16 bit r/o Interrupt Status Reg */
+#define PHY_LONE_LED_CFG 0x14 /* 16 bit r/w LED Configuration Reg */
+#define PHY_LONE_PORT_CTRL 0x15 /* 16 bit r/w Port Control Reg */
+#define PHY_LONE_CIM 0x16 /* 16 bit r/o CIM Reg */
+ /* 0x17 -0x1c: reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * National-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_NAT_CTRL 0x00 /* 16 bit r/w PHY Control Register */
+#define PHY_NAT_STAT 0x01 /* 16 bit r/w PHY Status Register */
+#define PHY_NAT_ID0 0x02 /* 16 bit r/o PHY ID0 Register */
+#define PHY_NAT_ID1 0x03 /* 16 bit r/o PHY ID1 Register */
+#define PHY_NAT_AUNE_ADV 0x04 /* 16 bit r/w Auto-Neg. Advertisement */
+#define PHY_NAT_AUNE_LP 0x05 /* 16 bit r/o Link Partner Ability Reg */
+#define PHY_NAT_AUNE_EXP 0x06 /* 16 bit r/o Auto-Neg. Expansion Reg */
+#define PHY_NAT_NEPG 0x07 /* 16 bit r/w Next Page Register */
+#define PHY_NAT_NEPG_LP 0x08 /* 16 bit r/o Next Page Link Partner Reg */
+ /* National-specific registers */
+#define PHY_NAT_1000T_CTRL 0x09 /* 16 bit r/w 1000Base-T Control Reg */
+#define PHY_NAT_1000T_STAT 0x0a /* 16 bit r/o 1000Base-T Status Reg */
+ /* 0x0b -0x0e: reserved */
+#define PHY_NAT_EXT_STAT 0x0f /* 16 bit r/o Extended Status Register */
+#define PHY_NAT_EXT_CTRL1 0x10 /* 16 bit r/o Extended Control Reg1 */
+#define PHY_NAT_Q_STAT1 0x11 /* 16 bit r/o Quick Status Reg1 */
+#define PHY_NAT_10B_OP 0x12 /* 16 bit r/o 10Base-T Operations Reg */
+#define PHY_NAT_EXT_CTRL2 0x13 /* 16 bit r/o Extended Control Reg1 */
+#define PHY_NAT_Q_STAT2 0x14 /* 16 bit r/o Quick Status Reg2 */
+ /* 0x15 -0x18: reserved */
+#define PHY_NAT_PHY_ADDR 0x19 /* 16 bit r/o PHY Address Register */
+
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * PHY bit definitions
+ * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are
+ * XMAC/Broadcom/LevelOne/National/Marvell-specific.
+ * All other are general.
+ */
+
+/***** PHY_XMAC_CTRL 16 bit r/w PHY Control Register *****/
+/***** PHY_BCOM_CTRL 16 bit r/w PHY Control Register *****/
+/***** PHY_MARV_CTRL 16 bit r/w PHY Status Register *****/
+/***** PHY_LONE_CTRL 16 bit r/w PHY Control Register *****/
+#define PHY_CT_RESET (1<<15) /* Bit 15: (sc) clear all PHY related regs */
+#define PHY_CT_LOOP (1<<14) /* Bit 14: enable Loopback over PHY */
+#define PHY_CT_SPS_LSB (1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */
+#define PHY_CT_ANE (1<<12) /* Bit 12: Auto-Negotiation Enabled */
+#define PHY_CT_PDOWN (1<<11) /* Bit 11: (BC,L1) Power Down Mode */
+#define PHY_CT_ISOL (1<<10) /* Bit 10: (BC,L1) Isolate Mode */
+#define PHY_CT_RE_CFG (1<<9) /* Bit 9: (sc) Restart Auto-Negotiation */
+#define PHY_CT_DUP_MD (1<<8) /* Bit 8: Duplex Mode */
+#define PHY_CT_COL_TST (1<<7) /* Bit 7: (BC,L1) Collision Test enabled */
+#define PHY_CT_SPS_MSB (1<<6) /* Bit 6: (BC,L1) Speed select, upper bit */
+ /* Bit 5..0: reserved */
+
+#define PHY_CT_SP1000 PHY_CT_SPS_MSB /* enable speed of 1000 Mbps */
+#define PHY_CT_SP100 PHY_CT_SPS_LSB /* enable speed of 100 Mbps */
+#define PHY_CT_SP10 (0) /* enable speed of 10 Mbps */
+
+
+/***** PHY_XMAC_STAT 16 bit r/w PHY Status Register *****/
+/***** PHY_BCOM_STAT 16 bit r/w PHY Status Register *****/
+/***** PHY_MARV_STAT 16 bit r/w PHY Status Register *****/
+/***** PHY_LONE_STAT 16 bit r/w PHY Status Register *****/
+ /* Bit 15..9: reserved */
+ /* (BC/L1) 100/10 Mbps cap bits ignored*/
+#define PHY_ST_EXT_ST (1<<8) /* Bit 8: Extended Status Present */
+ /* Bit 7: reserved */
+#define PHY_ST_PRE_SUP (1<<6) /* Bit 6: (BC/L1) preamble suppression */
+#define PHY_ST_AN_OVER (1<<5) /* Bit 5: Auto-Negotiation Over */
+#define PHY_ST_REM_FLT (1<<4) /* Bit 4: Remote Fault Condition Occured */
+#define PHY_ST_AN_CAP (1<<3) /* Bit 3: Auto-Negotiation Capability */
+#define PHY_ST_LSYNC (1<<2) /* Bit 2: Link Synchronized */
+#define PHY_ST_JAB_DET (1<<1) /* Bit 1: (BC/L1) Jabber Detected */
+#define PHY_ST_EXT_REG (1<<0) /* Bit 0: Extended Register available */
+
+
+/***** PHY_XMAC_ID1 16 bit r/o PHY ID1 Register */
+/***** PHY_BCOM_ID1 16 bit r/o PHY ID1 Register */
+/***** PHY_MARV_ID1 16 bit r/o PHY ID1 Register */
+/***** PHY_LONE_ID1 16 bit r/o PHY ID1 Register */
+#define PHY_I1_OUI_MSK (0x3f<<10) /* Bit 15..10: Organization Unique ID */
+#define PHY_I1_MOD_NUM (0x3f<<4) /* Bit 9.. 4: Model Number */
+#define PHY_I1_REV_MSK 0x0f /* Bit 3.. 0: Revision Number */
+
+/* different Broadcom PHY Ids */
+#define PHY_BCOM_ID1_A1 0x6041
+#define PHY_BCOM_ID1_B2 0x6043
+#define PHY_BCOM_ID1_C0 0x6044
+#define PHY_BCOM_ID1_C5 0x6047
+
+
+/***** PHY_XMAC_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/***** PHY_XMAC_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
+#define PHY_AN_NXT_PG (1<<15) /* Bit 15: Request Next Page */
+#define PHY_X_AN_ACK (1<<14) /* Bit 14: (ro) Acknowledge Received */
+#define PHY_X_AN_RFB (3<<12) /* Bit 13..12: Remote Fault Bits */
+ /* Bit 11.. 9: reserved */
+#define PHY_X_AN_PAUSE (3<<7) /* Bit 8.. 7: Pause Bits */
+#define PHY_X_AN_HD (1<<6) /* Bit 6: Half Duplex */
+#define PHY_X_AN_FD (1<<5) /* Bit 5: Full Duplex */
+ /* Bit 4.. 0: reserved */
+
+/***** PHY_BCOM_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/***** PHY_BCOM_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
+/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */
+ /* Bit 14: reserved */
+#define PHY_B_AN_RF (1<<13) /* Bit 13: Remote Fault */
+ /* Bit 12: reserved */
+#define PHY_B_AN_ASP (1<<11) /* Bit 11: Asymmetric Pause */
+#define PHY_B_AN_PC (1<<10) /* Bit 10: Pause Capable */
+ /* Bit 9..5: 100/10 BT cap bits ingnored */
+#define PHY_B_AN_SEL 0x1f /* Bit 4..0: Selector Field, 00001=Ethernet*/
+
+/***** PHY_LONE_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/***** PHY_LONE_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
+/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */
+ /* Bit 14: reserved */
+#define PHY_L_AN_RF (1<<13) /* Bit 13: Remote Fault */
+ /* Bit 12: reserved */
+#define PHY_L_AN_ASP (1<<11) /* Bit 11: Asymmetric Pause */
+#define PHY_L_AN_PC (1<<10) /* Bit 10: Pause Capable */
+ /* Bit 9..5: 100/10 BT cap bits ingnored */
+#define PHY_L_AN_SEL 0x1f /* Bit 4..0: Selector Field, 00001=Ethernet*/
+
+/***** PHY_NAT_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/***** PHY_NAT_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
+/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */
+ /* Bit 14: reserved */
+#define PHY_N_AN_RF (1<<13) /* Bit 13: Remote Fault */
+ /* Bit 12: reserved */
+#define PHY_N_AN_100F (1<<11) /* Bit 11: 100Base-T2 FD Support */
+#define PHY_N_AN_100H (1<<10) /* Bit 10: 100Base-T2 HD Support */
+ /* Bit 9..5: 100/10 BT cap bits ingnored */
+#define PHY_N_AN_SEL 0x1f /* Bit 4..0: Selector Field, 00001=Ethernet*/
+
+/* field type definition for PHY_x_AN_SEL */
+#define PHY_SEL_TYPE 0x01 /* 00001 = Ethernet */
+
+/***** PHY_XMAC_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/
+ /* Bit 15..4: reserved */
+#define PHY_ANE_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */
+#define PHY_ANE_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */
+#define PHY_ANE_RX_PG (1<<1) /* Bit 1: Page Received */
+ /* Bit 0: reserved */
+
+/***** PHY_BCOM_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/
+/***** PHY_LONE_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/
+/***** PHY_MARV_AUNE_EXP 16 bit r/o Auto-Negotiation Expansion Reg *****/
+ /* Bit 15..5: reserved */
+#define PHY_ANE_PAR_DF (1<<4) /* Bit 4: Parallel Detection Fault */
+/* PHY_ANE_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */
+/* PHY_ANE_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */
+/* PHY_ANE_RX_PG (see XMAC) Bit 1: Page Received */
+#define PHY_ANE_LP_CAP (1<<0) /* Bit 0: Link Partner Auto-Neg. Cap. */
+
+/***** PHY_XMAC_NEPG 16 bit r/w Next Page Register *****/
+/***** PHY_BCOM_NEPG 16 bit r/w Next Page Register *****/
+/***** PHY_LONE_NEPG 16 bit r/w Next Page Register *****/
+/***** PHY_XMAC_NEPG_LP 16 bit r/o Next Page Link Partner *****/
+/***** PHY_BCOM_NEPG_LP 16 bit r/o Next Page Link Partner *****/
+/***** PHY_LONE_NEPG_LP 16 bit r/o Next Page Link Partner *****/
+#define PHY_NP_MORE (1<<15) /* Bit 15: More, Next Pages to follow */
+#define PHY_NP_ACK1 (1<<14) /* Bit 14: (ro) Ack1, for receiving a message */
+#define PHY_NP_MSG_VAL (1<<13) /* Bit 13: Message Page valid */
+#define PHY_NP_ACK2 (1<<12) /* Bit 12: Ack2, comply with msg content */
+#define PHY_NP_TOG (1<<11) /* Bit 11: Toggle Bit, ensure sync */
+#define PHY_NP_MSG 0x07ff /* Bit 10..0: Message from/to Link Partner */
+
+/*
+ * XMAC-Specific
+ */
+/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/
+#define PHY_X_EX_FD (1<<15) /* Bit 15: Device Supports Full Duplex */
+#define PHY_X_EX_HD (1<<14) /* Bit 14: Device Supports Half Duplex */
+ /* Bit 13..0: reserved */
+
+/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/
+ /* Bit 15..9: reserved */
+#define PHY_X_RS_PAUSE (3<<7) /* Bit 8..7: selected Pause Mode */
+#define PHY_X_RS_HD (1<<6) /* Bit 6: Half Duplex Mode selected */
+#define PHY_X_RS_FD (1<<5) /* Bit 5: Full Duplex Mode selected */
+#define PHY_X_RS_ABLMIS (1<<4) /* Bit 4: duplex or pause cap mismatch */
+#define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability mismatch */
+ /* Bit 2..0: reserved */
+/*
+ * Remote Fault Bits (PHY_X_AN_RFB) encoding
+ */
+#define X_RFB_OK (0<<12) /* Bit 13..12 No errors, Link OK */
+#define X_RFB_LF (1<<12) /* Bit 13..12 Link Failure */
+#define X_RFB_OFF (2<<12) /* Bit 13..12 Offline */
+#define X_RFB_AN_ERR (3<<12) /* Bit 13..12 Auto-Negotiation Error */
+
+/*
+ * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding
+ */
+#define PHY_X_P_NO_PAUSE (0<<7) /* Bit 8..7: no Pause Mode */
+#define PHY_X_P_SYM_MD (1<<7) /* Bit 8..7: symmetric Pause Mode */
+#define PHY_X_P_ASYM_MD (2<<7) /* Bit 8..7: asymmetric Pause Mode */
+#define PHY_X_P_BOTH_MD (3<<7) /* Bit 8..7: both Pause Mode */
+
+
+/*
+ * Broadcom-Specific
+ */
+/***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
+#define PHY_B_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */
+#define PHY_B_1000C_MSE (1<<12) /* Bit 12: Master/Slave Enable */
+#define PHY_B_1000C_MSC (1<<11) /* Bit 11: M/S Configuration */
+#define PHY_B_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */
+#define PHY_B_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */
+#define PHY_B_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */
+ /* Bit 7..0: reserved */
+
+/***** PHY_BCOM_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
+/***** PHY_MARV_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
+#define PHY_B_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */
+#define PHY_B_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */
+#define PHY_B_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */
+#define PHY_B_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status */
+#define PHY_B_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */
+#define PHY_B_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */
+ /* Bit 9..8: reserved */
+#define PHY_B_1000S_IEC 0xff /* Bit 7..0: Idle Error Count */
+
+/***** PHY_BCOM_EXT_STAT 16 bit r/o Extended Status Register *****/
+#define PHY_B_ES_X_FD_CAP (1<<15) /* Bit 15: 1000Base-X FD capable */
+#define PHY_B_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */
+#define PHY_B_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */
+#define PHY_B_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */
+ /* Bit 11..0: reserved */
+
+/***** PHY_BCOM_P_EXT_CTRL 16 bit r/w PHY Extended Control Reg *****/
+#define PHY_B_PEC_MAC_PHY (1<<15) /* Bit 15: 10BIT/GMI-Interface */
+#define PHY_B_PEC_DIS_CROSS (1<<14) /* Bit 14: Disable MDI Crossover */
+#define PHY_B_PEC_TX_DIS (1<<13) /* Bit 13: Tx output Disabled */
+#define PHY_B_PEC_INT_DIS (1<<12) /* Bit 12: Interrupts Disabled */
+#define PHY_B_PEC_F_INT (1<<11) /* Bit 11: Force Interrupt */
+#define PHY_B_PEC_BY_45 (1<<10) /* Bit 10: Bypass 4B5B-Decoder */
+#define PHY_B_PEC_BY_SCR (1<<9) /* Bit 9: Bypass Scrambler */
+#define PHY_B_PEC_BY_MLT3 (1<<8) /* Bit 8: Bypass MLT3 Encoder */
+#define PHY_B_PEC_BY_RXA (1<<7) /* Bit 7: Bypass Rx Alignm. */
+#define PHY_B_PEC_RES_SCR (1<<6) /* Bit 6: Reset Scrambler */
+#define PHY_B_PEC_EN_LTR (1<<5) /* Bit 5: Ena LED Traffic Mode */
+#define PHY_B_PEC_LED_ON (1<<4) /* Bit 4: Force LED's on */
+#define PHY_B_PEC_LED_OFF (1<<3) /* Bit 3: Force LED's off */
+#define PHY_B_PEC_EX_IPG (1<<2) /* Bit 2: Extend Tx IPG Mode */
+#define PHY_B_PEC_3_LED (1<<1) /* Bit 1: Three Link LED mode */
+#define PHY_B_PEC_HIGH_LA (1<<0) /* Bit 0: GMII FIFO Elasticy */
+
+/***** PHY_BCOM_P_EXT_STAT 16 bit r/o PHY Extended Status Reg *****/
+ /* Bit 15..14: reserved */
+#define PHY_B_PES_CROSS_STAT (1<<13) /* Bit 13: MDI Crossover Status */
+#define PHY_B_PES_INT_STAT (1<<12) /* Bit 12: Interrupt Status */
+#define PHY_B_PES_RRS (1<<11) /* Bit 11: Remote Receiver Stat. */
+#define PHY_B_PES_LRS (1<<10) /* Bit 10: Local Receiver Stat. */
+#define PHY_B_PES_LOCKED (1<<9) /* Bit 9: Locked */
+#define PHY_B_PES_LS (1<<8) /* Bit 8: Link Status */
+#define PHY_B_PES_RF (1<<7) /* Bit 7: Remote Fault */
+#define PHY_B_PES_CE_ER (1<<6) /* Bit 6: Carrier Ext Error */
+#define PHY_B_PES_BAD_SSD (1<<5) /* Bit 5: Bad SSD */
+#define PHY_B_PES_BAD_ESD (1<<4) /* Bit 4: Bad ESD */
+#define PHY_B_PES_RX_ER (1<<3) /* Bit 3: Receive Error */
+#define PHY_B_PES_TX_ER (1<<2) /* Bit 2: Transmit Error */
+#define PHY_B_PES_LOCK_ER (1<<1) /* Bit 1: Lock Error */
+#define PHY_B_PES_MLT3_ER (1<<0) /* Bit 0: MLT3 code Error */
+
+/***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/
+ /* Bit 15..8: reserved */
+#define PHY_B_FC_CTR 0xff /* Bit 7..0: False Carrier Counter */
+
+/***** PHY_BCOM_RNO_CTR 16 bit r/w Receive NOT_OK Counter *****/
+#define PHY_B_RC_LOC_MSK 0xff00 /* Bit 15..8: Local Rx NOT_OK cnt */
+#define PHY_B_RC_REM_MSK 0x00ff /* Bit 7..0: Remote Rx NOT_OK cnt */
+
+/***** PHY_BCOM_AUX_CTRL 16 bit r/w Auxiliary Control Reg *****/
+#define PHY_B_AC_L_SQE (1<<15) /* Bit 15: Low Squelch */
+#define PHY_B_AC_LONG_PACK (1<<14) /* Bit 14: Rx Long Packets */
+#define PHY_B_AC_ER_CTRL (3<<12) /* Bit 13..12: Edgerate Control */
+ /* Bit 11: reserved */
+#define PHY_B_AC_TX_TST (1<<10) /* Bit 10: Tx test bit, always 1 */
+ /* Bit 9.. 8: reserved */
+#define PHY_B_AC_DIS_PRF (1<<7) /* Bit 7: dis part resp filter */
+ /* Bit 6: reserved */
+#define PHY_B_AC_DIS_PM (1<<5) /* Bit 5: dis power management */
+ /* Bit 4: reserved */
+#define PHY_B_AC_DIAG (1<<3) /* Bit 3: Diagnostic Mode */
+ /* Bit 2.. 0: reserved */
+
+/***** PHY_BCOM_AUX_STAT 16 bit r/o Auxiliary Status Reg *****/
+#define PHY_B_AS_AN_C (1<<15) /* Bit 15: AutoNeg complete */
+#define PHY_B_AS_AN_CA (1<<14) /* Bit 14: AN Complete Ack */
+#define PHY_B_AS_ANACK_D (1<<13) /* Bit 13: AN Ack Detect */
+#define PHY_B_AS_ANAB_D (1<<12) /* Bit 12: AN Ability Detect */
+#define PHY_B_AS_NPW (1<<11) /* Bit 11: AN Next Page Wait */
+#define PHY_B_AS_AN_RES_MSK (7<<8) /* Bit 10..8: AN HDC */
+#define PHY_B_AS_PDF (1<<7) /* Bit 7: Parallel Detect. Fault */
+#define PHY_B_AS_RF (1<<6) /* Bit 6: Remote Fault */
+#define PHY_B_AS_ANP_R (1<<5) /* Bit 5: AN Page Received */
+#define PHY_B_AS_LP_ANAB (1<<4) /* Bit 4: LP AN Ability */
+#define PHY_B_AS_LP_NPAB (1<<3) /* Bit 3: LP Next Page Ability */
+#define PHY_B_AS_LS (1<<2) /* Bit 2: Link Status */
+#define PHY_B_AS_PRR (1<<1) /* Bit 1: Pause Resolution-Rx */
+#define PHY_B_AS_PRT (1<<0) /* Bit 0: Pause Resolution-Tx */
+
+#define PHY_B_AS_PAUSE_MSK (PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/***** PHY_BCOM_INT_STAT 16 bit r/o Interrupt Status Reg *****/
+/***** PHY_BCOM_INT_MASK 16 bit r/w Interrupt Mask Reg *****/
+ /* Bit 15: reserved */
+#define PHY_B_IS_PSE (1<<14) /* Bit 14: Pair Swap Error */
+#define PHY_B_IS_MDXI_SC (1<<13) /* Bit 13: MDIX Status Change */
+#define PHY_B_IS_HCT (1<<12) /* Bit 12: counter above 32k */
+#define PHY_B_IS_LCT (1<<11) /* Bit 11: counter above 128 */
+#define PHY_B_IS_AN_PR (1<<10) /* Bit 10: Page Received */
+#define PHY_B_IS_NO_HDCL (1<<9) /* Bit 9: No HCD Link */
+#define PHY_B_IS_NO_HDC (1<<8) /* Bit 8: No HCD */
+#define PHY_B_IS_NEG_USHDC (1<<7) /* Bit 7: Negotiated Unsup. HCD */
+#define PHY_B_IS_SCR_S_ER (1<<6) /* Bit 6: Scrambler Sync Error */
+#define PHY_B_IS_RRS_CHANGE (1<<5) /* Bit 5: Remote Rx Stat Change */
+#define PHY_B_IS_LRS_CHANGE (1<<4) /* Bit 4: Local Rx Stat Change */
+#define PHY_B_IS_DUP_CHANGE (1<<3) /* Bit 3: Duplex Mode Change */
+#define PHY_B_IS_LSP_CHANGE (1<<2) /* Bit 2: Link Speed Change */
+#define PHY_B_IS_LST_CHANGE (1<<1) /* Bit 1: Link Status Changed */
+#define PHY_B_IS_CRC_ER (1<<0) /* Bit 0: CRC Error */
+
+#define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+#define PHY_B_P_NO_PAUSE (0<<10) /* Bit 11..10: no Pause Mode */
+#define PHY_B_P_SYM_MD (1<<10) /* Bit 11..10: symmetric Pause Mode */
+#define PHY_B_P_ASYM_MD (2<<10) /* Bit 11..10: asymmetric Pause Mode */
+#define PHY_B_P_BOTH_MD (3<<10) /* Bit 11..10: both Pause Mode */
+
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+#define PHY_B_RES_1000FD (7<<8) /* Bit 10..8: 1000Base-T Full Dup. */
+#define PHY_B_RES_1000HD (6<<8) /* Bit 10..8: 1000Base-T Half Dup. */
+/* others: 100/10: invalid for us */
+
+/*
+ * Level One-Specific
+ */
+/***** PHY_LONE_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
+#define PHY_L_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */
+#define PHY_L_1000C_MSE (1<<12) /* Bit 12: Master/Slave Enable */
+#define PHY_L_1000C_MSC (1<<11) /* Bit 11: M/S Configuration */
+#define PHY_L_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */
+#define PHY_L_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */
+#define PHY_L_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */
+ /* Bit 7..0: reserved */
+
+/***** PHY_LONE_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
+#define PHY_L_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */
+#define PHY_L_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */
+#define PHY_L_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */
+#define PHY_L_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status */
+#define PHY_L_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */
+#define PHY_L_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */
+ /* Bit 9..8: reserved */
+#define PHY_B_1000S_IEC 0xff /* Bit 7..0: Idle Error Count */
+
+/***** PHY_LONE_EXT_STAT 16 bit r/o Extended Status Register *****/
+#define PHY_L_ES_X_FD_CAP (1<<15) /* Bit 15: 1000Base-X FD capable */
+#define PHY_L_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */
+#define PHY_L_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */
+#define PHY_L_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */
+ /* Bit 11..0: reserved */
+
+/***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/
+#define PHY_L_PC_REP_MODE (1<<15) /* Bit 15: Repeater Mode */
+ /* Bit 14: reserved */
+#define PHY_L_PC_TX_DIS (1<<13) /* Bit 13: Tx output Disabled */
+#define PHY_L_PC_BY_SCR (1<<12) /* Bit 12: Bypass Scrambler */
+#define PHY_L_PC_BY_45 (1<<11) /* Bit 11: Bypass 4B5B-Decoder */
+#define PHY_L_PC_JAB_DIS (1<<10) /* Bit 10: Jabber Disabled */
+#define PHY_L_PC_SQE (1<<9) /* Bit 9: Enable Heartbeat */
+#define PHY_L_PC_TP_LOOP (1<<8) /* Bit 8: TP Loopback */
+#define PHY_L_PC_SSS (1<<7) /* Bit 7: Smart Speed Selection */
+#define PHY_L_PC_FIFO_SIZE (1<<6) /* Bit 6: FIFO Size */
+#define PHY_L_PC_PRE_EN (1<<5) /* Bit 5: Preamble Enable */
+#define PHY_L_PC_CIM (1<<4) /* Bit 4: Carrier Integrity Mon */
+#define PHY_L_PC_10_SER (1<<3) /* Bit 3: Use Serial Output */
+#define PHY_L_PC_ANISOL (1<<2) /* Bit 2: Unisolate Port */
+#define PHY_L_PC_TEN_BIT (1<<1) /* Bit 1: 10bit iface mode on */
+#define PHY_L_PC_ALTCLOCK (1<<0) /* Bit 0: (ro) ALTCLOCK Mode on */
+
+/***** PHY_LONE_Q_STAT 16 bit r/o Quick Status Reg *****/
+#define PHY_L_QS_D_RATE (3<<14) /* Bit 15..14: Data Rate */
+#define PHY_L_QS_TX_STAT (1<<13) /* Bit 13: Transmitting */
+#define PHY_L_QS_RX_STAT (1<<12) /* Bit 12: Receiving */
+#define PHY_L_QS_COL_STAT (1<<11) /* Bit 11: Collision */
+#define PHY_L_QS_L_STAT (1<<10) /* Bit 10: Link is up */
+#define PHY_L_QS_DUP_MOD (1<<9) /* Bit 9: Full/Half Duplex */
+#define PHY_L_QS_AN (1<<8) /* Bit 8: AutoNeg is On */
+#define PHY_L_QS_AN_C (1<<7) /* Bit 7: AN is Complete */
+#define PHY_L_QS_LLE (7<<4) /* Bit 6: Line Length Estim. */
+#define PHY_L_QS_PAUSE (1<<3) /* Bit 3: LP advertised Pause */
+#define PHY_L_QS_AS_PAUSE (1<<2) /* Bit 2: LP adv. asym. Pause */
+#define PHY_L_QS_ISOLATE (1<<1) /* Bit 1: CIM Isolated */
+#define PHY_L_QS_EVENT (1<<0) /* Bit 0: Event has occurred */
+
+/***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/
+/***** PHY_LONE_INT_STAT 16 bit r/o Interrupt Status Reg *****/
+ /* Bit 15..14: reserved */
+#define PHY_L_IS_AN_F (1<<13) /* Bit 13: Auto-Negotiation fault */
+ /* Bit 12: not described */
+#define PHY_L_IS_CROSS (1<<11) /* Bit 11: Crossover used */
+#define PHY_L_IS_POL (1<<10) /* Bit 10: Polarity correct. used */
+#define PHY_L_IS_SS (1<<9) /* Bit 9: Smart Speed Downgrade */
+#define PHY_L_IS_CFULL (1<<8) /* Bit 8: Counter Full */
+#define PHY_L_IS_AN_C (1<<7) /* Bit 7: AutoNeg Complete */
+#define PHY_L_IS_SPEED (1<<6) /* Bit 6: Speed Changed */
+#define PHY_L_IS_DUP (1<<5) /* Bit 5: Duplex Changed */
+#define PHY_L_IS_LS (1<<4) /* Bit 4: Link Status Changed */
+#define PHY_L_IS_ISOL (1<<3) /* Bit 3: Isolate Occured */
+#define PHY_L_IS_MDINT (1<<2) /* Bit 2: (ro) STAT: MII Int Pending */
+#define PHY_L_IS_INTEN (1<<1) /* Bit 1: ENAB: Enable IRQs */
+#define PHY_L_IS_FORCE (1<<0) /* Bit 0: ENAB: Force Interrupt */
+
+/* int. mask */
+#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
+
+/***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/
+#define PHY_L_LC_LEDC (3<<14) /* Bit 15..14: Col/Blink/On/Off */
+#define PHY_L_LC_LEDR (3<<12) /* Bit 13..12: Rx/Blink/On/Off */
+#define PHY_L_LC_LEDT (3<<10) /* Bit 11..10: Tx/Blink/On/Off */
+#define PHY_L_LC_LEDG (3<<8) /* Bit 9..8: Giga/Blink/On/Off */
+#define PHY_L_LC_LEDS (3<<6) /* Bit 7..6: 10-100/Blink/On/Off */
+#define PHY_L_LC_LEDL (3<<4) /* Bit 5..4: Link/Blink/On/Off */
+#define PHY_L_LC_LEDF (3<<2) /* Bit 3..2: Duplex/Blink/On/Off */
+#define PHY_L_LC_PSTRECH (1<<1) /* Bit 1: Strech LED Pulses */
+#define PHY_L_LC_FREQ (1<<0) /* Bit 0: 30/100 ms */
+
+/***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/
+#define PHY_L_PC_TX_TCLK (1<<15) /* Bit 15: Enable TX_TCLK */
+ /* Bit 14: reserved */
+#define PHY_L_PC_ALT_NP (1<<13) /* Bit 14: Alternate Next Page */
+#define PHY_L_PC_GMII_ALT (1<<12) /* Bit 13: Alternate GMII driver */
+ /* Bit 11: reserved */
+#define PHY_L_PC_TEN_CRS (1<<10) /* Bit 10: Extend CRS*/
+ /* Bit 9..0: not described */
+
+/***** PHY_LONE_CIM 16 bit r/o CIM Reg *****/
+#define PHY_L_CIM_ISOL (255<<8)/* Bit 15..8: Isolate Count */
+#define PHY_L_CIM_FALSE_CAR (255<<0)/* Bit 7..0: False Carrier Count */
+
+
+/*
+ * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
+ */
+#define PHY_L_P_NO_PAUSE (0<<10) /* Bit 11..10: no Pause Mode */
+#define PHY_L_P_SYM_MD (1<<10) /* Bit 11..10: symmetric Pause Mode */
+#define PHY_L_P_ASYM_MD (2<<10) /* Bit 11..10: asymmetric Pause Mode */
+#define PHY_L_P_BOTH_MD (3<<10) /* Bit 11..10: both Pause Mode */
+
+
+/*
+ * National-Specific
+ */
+/***** PHY_NAT_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
+#define PHY_N_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */
+#define PHY_N_1000C_MSE (1<<12) /* Bit 12: Master/Slave Enable */
+#define PHY_N_1000C_MSC (1<<11) /* Bit 11: M/S Configuration */
+#define PHY_N_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */
+#define PHY_N_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */
+#define PHY_N_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */
+#define PHY_N_1000C_APC (1<<7) /* Bit 7: Asymmetric Pause Cap. */
+ /* Bit 6..0: reserved */
+
+/***** PHY_NAT_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
+#define PHY_N_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */
+#define PHY_N_1000S_MSR (1<<14) /* Bit 14: Master/Slave Result */
+#define PHY_N_1000S_LRS (1<<13) /* Bit 13: Local Receiver Status */
+#define PHY_N_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status*/
+#define PHY_N_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */
+#define PHY_N_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */
+#define PHY_N_1000C_LP_APC (1<<9) /* Bit 9: LP Asym. Pause Cap. */
+ /* Bit 8: reserved */
+#define PHY_N_1000S_IEC 0xff /* Bit 7..0: Idle Error Count */
+
+/***** PHY_NAT_EXT_STAT 16 bit r/o Extended Status Register *****/
+#define PHY_N_ES_X_FD_CAP (1<<15) /* Bit 15: 1000Base-X FD capable */
+#define PHY_N_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */
+#define PHY_N_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */
+#define PHY_N_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */
+ /* Bit 11..0: reserved */
+
+/* todo: those are still missing */
+/***** PHY_NAT_EXT_CTRL1 16 bit r/o Extended Control Reg1 *****/
+/***** PHY_NAT_Q_STAT1 16 bit r/o Quick Status Reg1 *****/
+/***** PHY_NAT_10B_OP 16 bit r/o 10Base-T Operations Reg *****/
+/***** PHY_NAT_EXT_CTRL2 16 bit r/o Extended Control Reg1 *****/
+/***** PHY_NAT_Q_STAT2 16 bit r/o Quick Status Reg2 *****/
+/***** PHY_NAT_PHY_ADDR 16 bit r/o PHY Address Register *****/
+
+/*
+ * Marvell-Specific
+ */
+/***** PHY_MARV_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/***** PHY_MARV_AUNE_LP 16 bit r/w Link Part Ability Reg *****/
+#define PHY_M_AN_NXT_PG BIT_15 /* Request Next Page */
+#define PHY_M_AN_ACK BIT_14 /* (ro) Acknowledge Received */
+#define PHY_M_AN_RF BIT_13 /* Remote Fault */
+ /* Bit 12: reserved */
+#define PHY_M_AN_ASP BIT_11 /* Asymmetric Pause */
+#define PHY_M_AN_PC BIT_10 /* MAC Pause implemented */
+#define PHY_M_AN_100_FD BIT_8 /* Advertise 100Base-TX Full Duplex */
+#define PHY_M_AN_100_HD BIT_7 /* Advertise 100Base-TX Half Duplex */
+#define PHY_M_AN_10_FD BIT_6 /* Advertise 10Base-TX Full Duplex */
+#define PHY_M_AN_10_HD BIT_5 /* Advertise 10Base-TX Half Duplex */
+
+/* special defines for FIBER (88E1011S only) */
+#define PHY_M_AN_ASP_X BIT_8 /* Asymmetric Pause */
+#define PHY_M_AN_PC_X BIT_7 /* MAC Pause implemented */
+#define PHY_M_AN_1000X_AHD BIT_6 /* Advertise 10000Base-X Half Duplex */
+#define PHY_M_AN_1000X_AFD BIT_5 /* Advertise 10000Base-X Full Duplex */
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+#define PHY_M_P_NO_PAUSE_X (0<<7) /* Bit 8.. 7: no Pause Mode */
+#define PHY_M_P_SYM_MD_X (1<<7) /* Bit 8.. 7: symmetric Pause Mode */
+#define PHY_M_P_ASYM_MD_X (2<<7) /* Bit 8.. 7: asymmetric Pause Mode */
+#define PHY_M_P_BOTH_MD_X (3<<7) /* Bit 8.. 7: both Pause Mode */
+
+/***** PHY_MARV_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
+#define PHY_M_1000C_TEST (7<<13) /* Bit 15..13: Test Modes */
+#define PHY_M_1000C_MSE (1<<12) /* Bit 12: Manual Master/Slave Enable */
+#define PHY_M_1000C_MSC (1<<11) /* Bit 11: M/S Configuration (1=Master) */
+#define PHY_M_1000C_MPD (1<<10) /* Bit 10: Multi-Port Device */
+#define PHY_M_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */
+#define PHY_M_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */
+ /* Bit 7..0: reserved */
+
+/***** PHY_MARV_PHY_CTRL 16 bit r/w PHY Specific Ctrl Reg *****/
+#define PHY_M_PC_TX_FFD_MSK (3<<14) /* Bit 15..14: Tx FIFO Depth Mask */
+#define PHY_M_PC_RX_FFD_MSK (3<<12) /* Bit 13..12: Rx FIFO Depth Mask */
+#define PHY_M_PC_ASS_CRS_TX (1<<11) /* Bit 11: Assert CRS on Transmit */
+#define PHY_M_PC_FL_GOOD (1<<10) /* Bit 10: Force Link Good */
+#define PHY_M_PC_EN_DET_MSK (3<<8) /* Bit 9.. 8: Energy Detect Mask */
+#define PHY_M_PC_ENA_EXT_D (1<<7) /* Bit 7: Enable Ext. Distance (10BT) */
+#define PHY_M_PC_MDIX_MSK (3<<5) /* Bit 6.. 5: MDI/MDIX Config. Mask */
+#define PHY_M_PC_DIS_125CLK (1<<4) /* Bit 4: Disable 125 CLK */
+#define PHY_M_PC_MAC_POW_UP (1<<3) /* Bit 3: MAC Power up */
+#define PHY_M_PC_SQE_T_ENA (1<<2) /* Bit 2: SQE Test Enabled */
+#define PHY_M_PC_POL_R_DIS (1<<1) /* Bit 1: Polarity Reversal Disabled */
+#define PHY_M_PC_DIS_JABBER (1<<0) /* Bit 0: Disable Jabber */
+
+#define PHY_M_PC_EN_DET SHIFT8(2) /* Energy Detect (Mode 1) */
+#define PHY_M_PC_EN_DET_PLUS SHIFT8(3) /* Energy Detect Plus (Mode 2) */
+
+#define PHY_M_PC_MDI_XMODE(x) SHIFT5(x)
+#define PHY_M_PC_MAN_MDI 0 /* 00 = Manual MDI configuration */
+#define PHY_M_PC_MAN_MDIX 1 /* 01 = Manual MDIX configuration */
+#define PHY_M_PC_ENA_AUTO 3 /* 11 = Enable Automatic Crossover */
+
+/***** PHY_MARV_PHY_STAT 16 bit r/o PHY Specific Status Reg *****/
+#define PHY_M_PS_SPEED_MSK (3<<14) /* Bit 15..14: Speed Mask */
+#define PHY_M_PS_SPEED_1000 (1<<15) /* 10 = 1000 Mbps */
+#define PHY_M_PS_SPEED_100 (1<<14) /* 01 = 100 Mbps */
+#define PHY_M_PS_SPEED_10 0 /* 00 = 10 Mbps */
+#define PHY_M_PS_FULL_DUP (1<<13) /* Bit 13: Full Duplex */
+#define PHY_M_PS_PAGE_REC (1<<12) /* Bit 12: Page Received */
+#define PHY_M_PS_SPDUP_RES (1<<11) /* Bit 11: Speed & Duplex Resolved */
+#define PHY_M_PS_LINK_UP (1<<10) /* Bit 10: Link Up */
+#define PHY_M_PS_CABLE_MSK (3<<7) /* Bit 9.. 7: Cable Length Mask */
+#define PHY_M_PS_MDI_X_STAT (1<<6) /* Bit 6: MDI Crossover Stat (1=MDIX) */
+#define PHY_M_PS_DOWNS_STAT (1<<5) /* Bit 5: Downshift Status (1=downsh.) */
+#define PHY_M_PS_ENDET_STAT (1<<4) /* Bit 4: Energy Detect Status (1=act) */
+#define PHY_M_PS_TX_P_EN (1<<3) /* Bit 3: Tx Pause Enabled */
+#define PHY_M_PS_RX_P_EN (1<<2) /* Bit 2: Rx Pause Enabled */
+#define PHY_M_PS_POL_REV (1<<1) /* Bit 1: Polarity Reversed */
+#define PHY_M_PC_JABBER (1<<0) /* Bit 0: Jabber */
+
+#define PHY_M_PS_PAUSE_MSK (PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/***** PHY_MARV_INT_MASK 16 bit r/w Interrupt Mask Reg *****/
+/***** PHY_MARV_INT_STAT 16 bit r/o Interrupt Status Reg *****/
+#define PHY_M_IS_AN_ERROR (1<<15) /* Bit 15: Auto-Negotiation Error */
+#define PHY_M_IS_LSP_CHANGE (1<<14) /* Bit 14: Link Speed Changed */
+#define PHY_M_IS_DUP_CHANGE (1<<13) /* Bit 13: Duplex Mode Changed */
+#define PHY_M_IS_AN_PR (1<<12) /* Bit 12: Page Received */
+#define PHY_M_IS_AN_COMPL (1<<11) /* Bit 11: Auto-Negotiation Completed */
+#define PHY_M_IS_LST_CHANGE (1<<10) /* Bit 10: Link Status Changed */
+#define PHY_M_IS_SYMB_ERROR (1<<9) /* Bit 9: Symbol Error */
+#define PHY_M_IS_FALSE_CARR (1<<8) /* Bit 8: False Carrier */
+#define PHY_M_IS_FIFO_ERROR (1<<7) /* Bit 7: FIFO Overflow/Underrun Error */
+#define PHY_M_IS_MDI_CHANGE (1<<6) /* Bit 6: MDI Crossover Changed */
+#define PHY_M_IS_DOWNSH_DET (1<<5) /* Bit 5: Downshift Detected */
+#define PHY_M_IS_END_CHANGE (1<<4) /* Bit 4: Energy Detect Changed */
+ /* Bit 3..2: reserved */
+#define PHY_M_IS_POL_CHANGE (1<<1) /* Bit 1: Polarity Changed */
+#define PHY_M_IS_JABBER (1<<0) /* Bit 0: Jabber */
+
+#define PHY_M_DEF_MSK (PHY_M_IS_AN_ERROR | PHY_M_IS_AN_PR | \
+ PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR)
+
+/***** PHY_MARV_EXT_CTRL 16 bit r/w Ext. PHY Specific Ctrl *****/
+#define PHY_M_EC_M_DSC_MSK (3<<10) /* Bit 11..10: Master downshift counter */
+#define PHY_M_EC_S_DSC_MSK (3<<8) /* Bit 9.. 8: Slave downshift counter */
+#define PHY_M_EC_MAC_S_MSK (7<<4) /* Bit 6.. 4: Def. MAC interface speed */
+#define PHY_M_EC_FIB_AN_ENA (1<<3) /* Bit 3: Fiber Auto-Neg. Enable */
+
+#define PHY_M_EC_M_DSC(x) SHIFT10(x) /* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x) SHIFT8(x) /* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x) SHIFT4(x) /* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define MAC_TX_CLK_0_MHZ 2
+#define MAC_TX_CLK_2_5_MHZ 6
+#define MAC_TX_CLK_25_MHZ 7
+
+/***** PHY_MARV_LED_CTRL 16 bit r/w LED Control Reg *****/
+#define PHY_M_LEDC_DIS_LED (1<<15) /* Bit 15: Disable LED */
+#define PHY_M_LEDC_PULS_MSK (7<<12) /* Bit 14..12: Pulse Stretch Mask */
+#define PHY_M_LEDC_F_INT (1<<11) /* Bit 11: Force Interrupt */
+#define PHY_M_LEDC_BL_R_MSK (7<<8) /* Bit 10.. 8: Blink Rate Mask */
+ /* Bit 7.. 5: reserved */
+#define PHY_M_LEDC_LINK_MSK (3<<3) /* Bit 4.. 3: Link Control Mask */
+#define PHY_M_LEDC_DP_CTRL (1<<2) /* Bit 2: Duplex Control */
+#define PHY_M_LEDC_RX_CTRL (1<<1) /* Bit 1: Rx activity / Link */
+#define PHY_M_LEDC_TX_CTRL (1<<0) /* Bit 0: Tx activity / Link */
+
+#define PHY_M_LED_PULS_DUR(x) SHIFT12(x) /* Pulse Stretch Duration */
+
+#define PULS_NO_STR 0 /* no pulse stretching */
+#define PULS_21MS 1 /* 21 ms to 42 ms */
+#define PULS_42MS 2 /* 42 ms to 84 ms */
+#define PULS_84MS 3 /* 84 ms to 170 ms */
+#define PULS_170MS 4 /* 170 ms to 340 ms */
+#define PULS_340MS 5 /* 340 ms to 670 ms */
+#define PULS_670MS 6 /* 670 ms to 1.3 s */
+#define PULS_1300MS 7 /* 1.3 s to 2.7 s */
+
+#define PHY_M_LED_BLINK_RT(x) SHIFT8(x) /* Blink Rate */
+
+#define BLINK_42MS 0 /* 42 ms */
+#define BLINK_84MS 1 /* 84 ms */
+#define BLINK_170MS 2 /* 170 ms */
+#define BLINK_340MS 3 /* 340 ms */
+#define BLINK_670MS 4 /* 670 ms */
+ /* values 5 - 7: reserved */
+
+/***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/
+#define PHY_M_LED_MO_DUP(x) SHIFT10(x) /* Bit 11..10: Duplex */
+#define PHY_M_LED_MO_10(x) SHIFT8(x) /* Bit 9.. 8: Link 10 */
+#define PHY_M_LED_MO_100(x) SHIFT6(x) /* Bit 7.. 6: Link 100 */
+#define PHY_M_LED_MO_1000(x) SHIFT4(x) /* Bit 5.. 4: Link 1000 */
+#define PHY_M_LED_MO_RX(x) SHIFT2(x) /* Bit 3.. 2: Rx */
+#define PHY_M_LED_MO_TX(x) SHIFT0(x) /* Bit 1.. 0: Tx */
+
+#define MO_LED_NORM 0
+#define MO_LED_BLINK 1
+#define MO_LED_OFF 2
+#define MO_LED_ON 3
+
+/***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/
+ /* Bit 15.. 7: reserved */
+#define PHY_M_EC2_FI_IMPED (1<<6) /* Bit 6: Fiber Input Impedance */
+#define PHY_M_EC2_FO_IMPED (1<<5) /* Bit 5: Fiber Output Impedance */
+#define PHY_M_EC2_FO_M_CLK (1<<4) /* Bit 4: Fiber Mode Clock Enable */
+#define PHY_M_EC2_FO_BOOST (1<<3) /* Bit 3: Fiber Output Boost */
+#define PHY_M_EC2_FO_AM_MSK 7 /* Bit 2.. 0: Fiber Output Amplitude */
+
+/***** PHY_MARV_EXT_P_STAT 16 bit r/w Ext. PHY Specific Status *****/
+#define PHY_M_FC_AUTO_SEL (1<<15) /* Bit 15: Fiber/Copper Auto Sel. dis. */
+#define PHY_M_FC_AN_REG_ACC (1<<14) /* Bit 14: Fiber/Copper Autoneg. reg acc */
+#define PHY_M_FC_RESULUTION (1<<13) /* Bit 13: Fiber/Copper Resulution */
+#define PHY_M_SER_IF_AN_BP (1<<12) /* Bit 12: Ser IF autoneg. bypass enable */
+#define PHY_M_SER_IF_BP_ST (1<<11) /* Bit 11: Ser IF autoneg. bypass status */
+#define PHY_M_IRQ_POLARITY (1<<10) /* Bit 10: IRQ polarity */
+ /* Bit 9..4: reserved */
+#define PHY_M_UNDOC1 (1<< 7) /* undocumented bit !! */
+#define PHY_M_MODE_MASK (0xf<<0)/* Bit 3..0: copy of HWCFG MODE[3:0] */
+
+
+/***** PHY_MARV_CABLE_DIAG 16 bit r/o Cable Diagnostic Reg *****/
+#define PHY_M_CABD_ENA_TEST (1<<15) /* Bit 15: Enable Test */
+#define PHY_M_CABD_STAT_MSK (3<<13) /* Bit 14..13: Status */
+ /* Bit 12.. 8: reserved */
+#define PHY_M_CABD_DIST_MSK 0xff /* Bit 7.. 0: Distance */
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+#define CABD_STAT_NORMAL 0
+#define CABD_STAT_SHORT 1
+#define CABD_STAT_OPEN 2
+#define CABD_STAT_FAIL 3
+
+
+/*
+ * GMAC registers
+ *
+ * The GMAC registers are 16 or 32 bits wide.
+ * The GMACs host processor interface is 16 bits wide,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the GMAC registers
+ * GM_IN16(), GM_OUT16, GM_IN32(), GM_OUT32(), GM_INADR(), GM_OUTADR(),
+ * GM_INHASH(), and GM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note: NA reg = Network Address e.g DA, SA etc.
+ *
+ */
+
+/* Port Registers */
+#define GM_GP_STAT 0x0000 /* 16 bit r/o General Purpose Status */
+#define GM_GP_CTRL 0x0004 /* 16 bit r/w General Purpose Control */
+#define GM_TX_CTRL 0x0008 /* 16 bit r/w Transmit Control Reg. */
+#define GM_RX_CTRL 0x000c /* 16 bit r/w Receive Control Reg. */
+#define GM_TX_FLOW_CTRL 0x0010 /* 16 bit r/w Transmit Flow-Control */
+#define GM_TX_PARAM 0x0014 /* 16 bit r/w Transmit Parameter Reg. */
+#define GM_SERIAL_MODE 0x0018 /* 16 bit r/w Serial Mode Register */
+
+/* Source Address Registers */
+#define GM_SRC_ADDR_1L 0x001c /* 16 bit r/w Source Address 1 (low) */
+#define GM_SRC_ADDR_1M 0x0020 /* 16 bit r/w Source Address 1 (middle) */
+#define GM_SRC_ADDR_1H 0x0024 /* 16 bit r/w Source Address 1 (high) */
+#define GM_SRC_ADDR_2L 0x0028 /* 16 bit r/w Source Address 2 (low) */
+#define GM_SRC_ADDR_2M 0x002c /* 16 bit r/w Source Address 2 (middle) */
+#define GM_SRC_ADDR_2H 0x0030 /* 16 bit r/w Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+#define GM_MC_ADDR_H1 0x0034 /* 16 bit r/w Multicast Address Hash 1 */
+#define GM_MC_ADDR_H2 0x0038 /* 16 bit r/w Multicast Address Hash 2 */
+#define GM_MC_ADDR_H3 0x003c /* 16 bit r/w Multicast Address Hash 3 */
+#define GM_MC_ADDR_H4 0x0040 /* 16 bit r/w Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+#define GM_TX_IRQ_SRC 0x0044 /* 16 bit r/o Tx Overflow IRQ Source */
+#define GM_RX_IRQ_SRC 0x0048 /* 16 bit r/o Rx Overflow IRQ Source */
+#define GM_TR_IRQ_SRC 0x004c /* 16 bit r/o Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+#define GM_TX_IRQ_MSK 0x0050 /* 16 bit r/w Tx Overflow IRQ Mask */
+#define GM_RX_IRQ_MSK 0x0054 /* 16 bit r/w Rx Overflow IRQ Mask */
+#define GM_TR_IRQ_MSK 0x0058 /* 16 bit r/w Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+#define GM_SMI_CTRL 0x0080 /* 16 bit r/w SMI Control Register */
+#define GM_SMI_DATA 0x0084 /* 16 bit r/w SMI Data Register */
+#define GM_PHY_ADDR 0x0088 /* 16 bit r/w GPHY Address Register */
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE 0x0100 /* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE 44 /* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word (32 bit r/o)
+ */
+#define GM_RXF_UC_OK \
+ (GM_MIB_CNT_BASE + 0) /* Unicast Frames Received OK */
+#define GM_RXF_BC_OK \
+ (GM_MIB_CNT_BASE + 8) /* Broadcast Frames Received OK */
+#define GM_RXF_MPAUSE \
+ (GM_MIB_CNT_BASE + 16) /* Pause MAC Ctrl Frames Received */
+#define GM_RXF_MC_OK \
+ (GM_MIB_CNT_BASE + 24) /* Multicast Frames Received OK */
+#define GM_RXF_FCS_ERR \
+ (GM_MIB_CNT_BASE + 32) /* Rx Frame Check Seq. Error */
+ /* GM_MIB_CNT_BASE + 40: reserved */
+#define GM_RXO_OK_LO \
+ (GM_MIB_CNT_BASE + 48) /* Octets Received OK Low */
+#define GM_RXO_OK_HI \
+ (GM_MIB_CNT_BASE + 56) /* Octets Received OK High */
+#define GM_RXO_ERR_LO \
+ (GM_MIB_CNT_BASE + 64) /* Octets Received Invalid Low */
+#define GM_RXO_ERR_HI \
+ (GM_MIB_CNT_BASE + 72) /* Octets Received Invalid High */
+#define GM_RXF_SHT \
+ (GM_MIB_CNT_BASE + 80) /* Frames <64 Byte Received OK */
+#define GM_RXE_FRAG \
+ (GM_MIB_CNT_BASE + 88) /* Frames <64 Byte Received with FCS Err */
+#define GM_RXF_64B \
+ (GM_MIB_CNT_BASE + 96) /* 64 Byte Rx Frame */
+#define GM_RXF_127B \
+ (GM_MIB_CNT_BASE + 104) /* 65-127 Byte Rx Frame */
+#define GM_RXF_255B \
+ (GM_MIB_CNT_BASE + 112) /* 128-255 Byte Rx Frame */
+#define GM_RXF_511B \
+ (GM_MIB_CNT_BASE + 120) /* 256-511 Byte Rx Frame */
+#define GM_RXF_1023B \
+ (GM_MIB_CNT_BASE + 128) /* 512-1023 Byte Rx Frame */
+#define GM_RXF_1518B \
+ (GM_MIB_CNT_BASE + 136) /* 1024-1518 Byte Rx Frame */
+#define GM_RXF_MAX_SZ \
+ (GM_MIB_CNT_BASE + 144) /* 1519-MaxSize Byte Rx Frame */
+#define GM_RXF_LNG_ERR \
+ (GM_MIB_CNT_BASE + 152) /* Rx Frame too Long Error */
+#define GM_RXF_JAB_PKT \
+ (GM_MIB_CNT_BASE + 160) /* Rx Jabber Packet Frame */
+ /* GM_MIB_CNT_BASE + 168: reserved */
+#define GM_RXE_FIFO_OV \
+ (GM_MIB_CNT_BASE + 176) /* Rx FIFO overflow Event */
+ /* GM_MIB_CNT_BASE + 184: reserved */
+#define GM_TXF_UC_OK \
+ (GM_MIB_CNT_BASE + 192) /* Unicast Frames Xmitted OK */
+#define GM_TXF_BC_OK \
+ (GM_MIB_CNT_BASE + 200) /* Broadcast Frames Xmitted OK */
+#define GM_TXF_MPAUSE \
+ (GM_MIB_CNT_BASE + 208) /* Pause MAC Ctrl Frames Xmitted */
+#define GM_TXF_MC_OK \
+ (GM_MIB_CNT_BASE + 216) /* Multicast Frames Xmitted OK */
+#define GM_TXO_OK_LO \
+ (GM_MIB_CNT_BASE + 224) /* Octets Transmitted OK Low */
+#define GM_TXO_OK_HI \
+ (GM_MIB_CNT_BASE + 232) /* Octets Transmitted OK High */
+#define GM_TXF_64B \
+ (GM_MIB_CNT_BASE + 240) /* 64 Byte Tx Frame */
+#define GM_TXF_127B \
+ (GM_MIB_CNT_BASE + 248) /* 65-127 Byte Tx Frame */
+#define GM_TXF_255B \
+ (GM_MIB_CNT_BASE + 256) /* 128-255 Byte Tx Frame */
+#define GM_TXF_511B \
+ (GM_MIB_CNT_BASE + 264) /* 256-511 Byte Tx Frame */
+#define GM_TXF_1023B \
+ (GM_MIB_CNT_BASE + 272) /* 512-1023 Byte Tx Frame */
+#define GM_TXF_1518B \
+ (GM_MIB_CNT_BASE + 280) /* 1024-1518 Byte Tx Frame */
+#define GM_TXF_MAX_SZ \
+ (GM_MIB_CNT_BASE + 288) /* 1519-MaxSize Byte Tx Frame */
+ /* GM_MIB_CNT_BASE + 296: reserved */
+#define GM_TXF_COL \
+ (GM_MIB_CNT_BASE + 304) /* Tx Collision */
+#define GM_TXF_LAT_COL \
+ (GM_MIB_CNT_BASE + 312) /* Tx Late Collision */
+#define GM_TXF_ABO_COL \
+ (GM_MIB_CNT_BASE + 320) /* Tx aborted due to Exces. Col. */
+#define GM_TXF_MUL_COL \
+ (GM_MIB_CNT_BASE + 328) /* Tx Multiple Collision */
+#define GM_TXF_SNG_COL \
+ (GM_MIB_CNT_BASE + 336) /* Tx Single Collision */
+#define GM_TXE_FIFO_UR \
+ (GM_MIB_CNT_BASE + 344) /* Tx FIFO Underrun Event */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * GMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ * (sc) self clearing
+ * (r/o) read only
+ */
+
+/* GM_GP_STAT 16 bit r/o General Purpose Status Register */
+#define GM_GPSR_SPEED (1<<15) /* Bit 15: Port Speed (1 = 100 Mbps) */
+#define GM_GPSR_DUPLEX (1<<14) /* Bit 14: Duplex Mode (1 = Full) */
+#define GM_GPSR_FC_TX_DIS (1<<13) /* Bit 13: Tx Flow-Control Mode Disabled */
+#define GM_GPSR_LINK_UP (1<<12) /* Bit 12: Link Up Status */
+#define GM_GPSR_PAUSE (1<<11) /* Bit 11: Pause State */
+#define GM_GPSR_TX_ACTIVE (1<<10) /* Bit 10: Tx in Progress */
+#define GM_GPSR_EXC_COL (1<<9) /* Bit 9: Excessive Collisions Occured */
+#define GM_GPSR_LAT_COL (1<<8) /* Bit 8: Late Collisions Occured */
+ /* Bit 7..6: reserved */
+#define GM_GPSR_PHY_ST_CH (1<<5) /* Bit 5: PHY Status Change */
+#define GM_GPSR_GIG_SPEED (1<<4) /* Bit 4: Gigabit Speed (1 = 1000 Mbps) */
+#define GM_GPSR_PART_MODE (1<<3) /* Bit 3: Partition mode */
+#define GM_GPSR_FC_RX_DIS (1<<2) /* Bit 2: Rx Flow-Control Mode Disabled */
+#define GM_GPSR_PROM_EN (1<<1) /* Bit 1: Promiscuous Mode Enabled */
+ /* Bit 0: reserved */
+
+/* GM_GP_CTRL 16 bit r/w General Purpose Control Register */
+ /* Bit 15: reserved */
+#define GM_GPCR_PROM_ENA (1<<14) /* Bit 14: Enable Promiscuous Mode */
+#define GM_GPCR_FC_TX_DIS (1<<13) /* Bit 13: Disable Tx Flow-Control Mode */
+#define GM_GPCR_TX_ENA (1<<12) /* Bit 12: Enable Transmit */
+#define GM_GPCR_RX_ENA (1<<11) /* Bit 11: Enable Receive */
+#define GM_GPCR_BURST_ENA (1<<10) /* Bit 10: Enable Burst Mode */
+#define GM_GPCR_LOOP_ENA (1<<9) /* Bit 9: Enable MAC Loopback Mode */
+#define GM_GPCR_PART_ENA (1<<8) /* Bit 8: Enable Partition Mode */
+#define GM_GPCR_GIGS_ENA (1<<7) /* Bit 7: Gigabit Speed (1000 Mbps) */
+#define GM_GPCR_FL_PASS (1<<6) /* Bit 6: Force Link Pass */
+#define GM_GPCR_DUP_FULL (1<<5) /* Bit 5: Full Duplex Mode */
+#define GM_GPCR_FC_RX_DIS (1<<4) /* Bit 4: Disable Rx Flow-Control Mode */
+#define GM_GPCR_SPEED_100 (1<<3) /* Bit 3: Port Speed 100 Mbps */
+#define GM_GPCR_AU_DUP_DIS (1<<2) /* Bit 2: Disable Auto-Update Duplex */
+#define GM_GPCR_AU_FCT_DIS (1<<1) /* Bit 1: Disable Auto-Update Flow-C. */
+#define GM_GPCR_AU_SPD_DIS (1<<0) /* Bit 0: Disable Auto-Update Speed */
+
+#define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS |\
+ GM_GPCR_AU_SPD_DIS)
+
+/* GM_TX_CTRL 16 bit r/w Transmit Control Register */
+#define GM_TXCR_FORCE_JAM (1<<15) /* Bit 15: Force Jam / Flow-Control */
+#define GM_TXCR_CRC_DIS (1<<14) /* Bit 14: Disable insertion of CRC */
+#define GM_TXCR_PAD_DIS (1<<13) /* Bit 13: Disable padding of packets */
+#define GM_TXCR_COL_THR_MSK (7<<10) /* Bit 12..10: Collision Threshold */
+
+#define TX_COL_THR(x) (SHIFT10(x) & GM_TXCR_COL_THR_MSK)
+
+#define TX_COL_DEF 0x04
+
+/* GM_RX_CTRL 16 bit r/w Receive Control Register */
+#define GM_RXCR_UCF_ENA (1<<15) /* Bit 15: Enable Unicast filtering */
+#define GM_RXCR_MCF_ENA (1<<14) /* Bit 14: Enable Multicast filtering */
+#define GM_RXCR_CRC_DIS (1<<13) /* Bit 13: Remove 4-byte CRC */
+#define GM_RXCR_PASS_FC (1<<12) /* Bit 12: Pass FC packets to FIFO */
+
+/* GM_TX_PARAM 16 bit r/w Transmit Parameter Register */
+#define GM_TXPA_JAMLEN_MSK (0x03<<14) /* Bit 15..14: Jam Length */
+#define GM_TXPA_JAMIPG_MSK (0x1f<<9) /* Bit 13..9: Jam IPG */
+#define GM_TXPA_JAMDAT_MSK (0x1f<<4) /* Bit 8..4: IPG Jam to Data */
+ /* Bit 3..0: reserved */
+
+#define TX_JAM_LEN_VAL(x) (SHIFT14(x) & GM_TXPA_JAMLEN_MSK)
+#define TX_JAM_IPG_VAL(x) (SHIFT9(x) & GM_TXPA_JAMIPG_MSK)
+#define TX_IPG_JAM_DATA(x) (SHIFT4(x) & GM_TXPA_JAMDAT_MSK)
+
+#define TX_JAM_LEN_DEF 0x03
+#define TX_JAM_IPG_DEF 0x0b
+#define TX_IPG_JAM_DEF 0x1c
+
+/* GM_SERIAL_MODE 16 bit r/w Serial Mode Register */
+#define GM_SMOD_DATABL_MSK (0x1f<<11) /* Bit 15..11: Data Blinder (r/o) */
+#define GM_SMOD_LIMIT_4 (1<<10) /* Bit 10: 4 consecutive Tx trials */
+#define GM_SMOD_VLAN_ENA (1<<9) /* Bit 9: Enable VLAN (Max. Frame Len) */
+#define GM_SMOD_JUMBO_ENA (1<<8) /* Bit 8: Enable Jumbo (Max. Frame Len) */
+ /* Bit 7..5: reserved */
+#define GM_SMOD_IPG_MSK 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */
+
+#define DATA_BLIND_VAL(x) (SHIFT11(x) & GM_SMOD_DATABL_MSK)
+#define DATA_BLIND_DEF 0x04
+
+#define IPG_DATA_VAL(x) (x & GM_SMOD_IPG_MSK)
+#define IPG_DATA_DEF 0x1e
+
+/* GM_SMI_CTRL 16 bit r/w SMI Control Register */
+#define GM_SMI_CT_PHY_A_MSK (0x1f<<11) /* Bit 15..11: PHY Device Address */
+#define GM_SMI_CT_REG_A_MSK (0x1f<<6) /* Bit 10.. 6: PHY Register Address */
+#define GM_SMI_CT_OP_RD (1<<5) /* Bit 5: OpCode Read (0=Write)*/
+#define GM_SMI_CT_RD_VAL (1<<4) /* Bit 4: Read Valid (Read completed) */
+#define GM_SMI_CT_BUSY (1<<3) /* Bit 3: Busy (Operation in progress) */
+ /* Bit 2..0: reserved */
+
+#define GM_SMI_CT_PHY_AD(x) (SHIFT11(x) & GM_SMI_CT_PHY_A_MSK)
+#define GM_SMI_CT_REG_AD(x) (SHIFT6(x) & GM_SMI_CT_REG_A_MSK)
+
+ /* GM_PHY_ADDR 16 bit r/w GPHY Address Register */
+ /* Bit 15..6: reserved */
+#define GM_PAR_MIB_CLR (1<<5) /* Bit 5: Set MIB Clear Counter Mode */
+#define GM_PAR_MIB_TST (1<<4) /* Bit 4: MIB Load Counter (Test Mode) */
+ /* Bit 3..0: reserved */
+
+/* Receive Frame Status Encoding */
+#define GMR_FS_LEN (0xffffUL<<16) /* Bit 31..16: Rx Frame Length */
+ /* Bit 15..14: reserved */
+#define GMR_FS_VLAN (1L<<13) /* Bit 13: VLAN Packet */
+#define GMR_FS_JABBER (1L<<12) /* Bit 12: Jabber Packet */
+#define GMR_FS_UN_SIZE (1L<<11) /* Bit 11: Undersize Packet */
+#define GMR_FS_MC (1L<<10) /* Bit 10: Multicast Packet */
+#define GMR_FS_BC (1L<<9) /* Bit 9: Broadcast Packet */
+#define GMR_FS_RX_OK (1L<<8) /* Bit 8: Receive OK (Good Packet) */
+#define GMR_FS_GOOD_FC (1L<<7) /* Bit 7: Good Flow-Control Packet */
+#define GMR_FS_BAD_FC (1L<<6) /* Bit 6: Bad Flow-Control Packet */
+#define GMR_FS_MII_ERR (1L<<5) /* Bit 5: MII Error */
+#define GMR_FS_LONG_ERR (1L<<4) /* Bit 4: Too Long Packet */
+#define GMR_FS_FRAGMENT (1L<<3) /* Bit 3: Fragment */
+ /* Bit 2: reserved */
+#define GMR_FS_CRC_ERR (1L<<1) /* Bit 1: CRC Error */
+#define GMR_FS_RX_FF_OV (1L<<0) /* Bit 0: Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+#define GMR_FS_ANY_ERR (GMR_FS_CRC_ERR | \
+ GMR_FS_LONG_ERR | \
+ GMR_FS_MII_ERR | \
+ GMR_FS_BAD_FC | \
+ GMR_FS_GOOD_FC | \
+ GMR_FS_JABBER)
+
+/* Rx GMAC FIFO Flush Mask (default) */
+#define RX_FF_FL_DEF_MSK (GMR_FS_CRC_ERR | \
+ GMR_FS_RX_FF_OV | \
+ GMR_FS_MII_ERR | \
+ GMR_FS_BAD_FC | \
+ GMR_FS_GOOD_FC | \
+ GMR_FS_UN_SIZE | \
+ GMR_FS_JABBER)
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __INC_XMAC_H */
diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c
new file mode 100644
index 000000000000..6e6c56aa6d6f
--- /dev/null
+++ b/drivers/net/sk98lin/skaddr.c
@@ -0,0 +1,1788 @@
+/******************************************************************************
+ *
+ * Name: skaddr.c
+ * Project: Gigabit Ethernet Adapters, ADDR-Module
+ * Version: $Revision: 1.52 $
+ * Date: $Date: 2003/06/02 13:46:15 $
+ * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses, address override,
+ * and promiscuous mode on GEnesis and Yukon adapters.
+ *
+ * Address Layout:
+ * port address: physical MAC address
+ * 1st exact match: logical MAC address (GEnesis only)
+ * 2nd exact match: RLMT multicast (GEnesis only)
+ * exact match 3-13: OS-specific multicasts (GEnesis only)
+ *
+ * Include File Hierarchy:
+ *
+ * "skdrv1st.h"
+ * "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skaddr.c,v 1.52 2003/06/02 13:46:15 tschilli Exp $ (C) Marvell.";
+#endif /* DEBUG ||!LINT || !SK_SLIM */
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+
+#define XMAC_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */
+#define GMAC_POLY 0x04C11DB7L /* CRC16-Poly - GMAC: Little Endian */
+#define HASH_BITS 6 /* #bits in hash */
+#define SK_MC_BIT 0x01
+
+/* Error numbers and messages. */
+
+#define SKERR_ADDR_E001 (SK_ERRBASE_ADDR + 0)
+#define SKERR_ADDR_E001MSG "Bad Flags."
+#define SKERR_ADDR_E002 (SKERR_ADDR_E001 + 1)
+#define SKERR_ADDR_E002MSG "New Error."
+
+/* typedefs *******************************************************************/
+
+/* None. */
+
+/* global variables ***********************************************************/
+
+/* 64-bit hash values with all bits set. */
+
+static const SK_U16 OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+
+/* local variables ************************************************************/
+
+#ifdef DEBUG
+static int Next0[SK_MAX_MACS] = {0};
+#endif /* DEBUG */
+
+static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+ SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+ int Flags);
+static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+ SK_U32 PortNumber, int NewPromMode);
+static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+ SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+ int Flags);
+static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+ SK_U32 PortNumber, int NewPromMode);
+
+/* functions ******************************************************************/
+
+/******************************************************************************
+ *
+ * SkAddrInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ * SK_INIT_DATA
+ * ============
+ *
+ * This routine clears the multicast tables and resets promiscuous mode.
+ * Some entries are reserved for the "logical MAC address", the
+ * SK-RLMT multicast address, and the BPDU multicast address.
+ *
+ *
+ * SK_INIT_IO
+ * ==========
+ *
+ * All permanent MAC addresses are read from EPROM.
+ * If the current MAC addresses are not already set in software,
+ * they are set to the values of the permanent addresses.
+ * The current addresses are written to the corresponding MAC.
+ *
+ *
+ * SK_INIT_RUN
+ * ===========
+ *
+ * Nothing.
+ *
+ * Context:
+ * init, pageable
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ */
+int SkAddrInit(
+SK_AC *pAC, /* the adapter context */
+SK_IOC IoC, /* I/O context */
+int Level) /* initialization level */
+{
+ int j;
+ SK_U32 i;
+ SK_U8 *InAddr;
+ SK_U16 *OutAddr;
+ SK_ADDR_PORT *pAPort;
+
+ switch (Level) {
+ case SK_INIT_DATA:
+ SK_MEMSET((char *) &pAC->Addr, (SK_U8) 0,
+ (SK_U16) sizeof(SK_ADDR));
+
+ for (i = 0; i < SK_MAX_MACS; i++) {
+ pAPort = &pAC->Addr.Port[i];
+ pAPort->PromMode = SK_PROM_MODE_NONE;
+
+ pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+ pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+ pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+ pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+ }
+#ifdef xDEBUG
+ for (i = 0; i < SK_MAX_MACS; i++) {
+ if (pAC->Addr.Port[i].NextExactMatchRlmt <
+ SK_ADDR_FIRST_MATCH_RLMT) {
+ Next0[i] |= 4;
+ }
+ }
+#endif /* DEBUG */
+ /* pAC->Addr.InitDone = SK_INIT_DATA; */
+ break;
+
+ case SK_INIT_IO:
+#ifndef SK_NO_RLMT
+ for (i = 0; i < SK_MAX_NETS; i++) {
+ pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
+ }
+#endif /* !SK_NO_RLMT */
+#ifdef xDEBUG
+ for (i = 0; i < SK_MAX_MACS; i++) {
+ if (pAC->Addr.Port[i].NextExactMatchRlmt <
+ SK_ADDR_FIRST_MATCH_RLMT) {
+ Next0[i] |= 8;
+ }
+ }
+#endif /* DEBUG */
+
+ /* Read permanent logical MAC address from Control Register File. */
+ for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+ InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
+ SK_IN8(IoC, B2_MAC_1 + j, InAddr);
+ }
+
+ if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
+ /* Set the current logical MAC address to the permanent one. */
+ pAC->Addr.Net[0].CurrentMacAddress =
+ pAC->Addr.Net[0].PermanentMacAddress;
+ pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
+ }
+
+ /* Set the current logical MAC address. */
+ pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
+ pAC->Addr.Net[0].CurrentMacAddress;
+#if SK_MAX_NETS > 1
+ /* Set logical MAC address for net 2 to (log | 3). */
+ if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
+ pAC->Addr.Net[1].PermanentMacAddress =
+ pAC->Addr.Net[0].PermanentMacAddress;
+ pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
+ /* Set the current logical MAC address to the permanent one. */
+ pAC->Addr.Net[1].CurrentMacAddress =
+ pAC->Addr.Net[1].PermanentMacAddress;
+ pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
+ }
+#endif /* SK_MAX_NETS > 1 */
+
+#ifdef DEBUG
+ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+ ("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+ i,
+ pAC->Addr.Net[i].PermanentMacAddress.a[0],
+ pAC->Addr.Net[i].PermanentMacAddress.a[1],
+ pAC->Addr.Net[i].PermanentMacAddress.a[2],
+ pAC->Addr.Net[i].PermanentMacAddress.a[3],
+ pAC->Addr.Net[i].PermanentMacAddress.a[4],
+ pAC->Addr.Net[i].PermanentMacAddress.a[5]))
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+ ("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+ i,
+ pAC->Addr.Net[i].CurrentMacAddress.a[0],
+ pAC->Addr.Net[i].CurrentMacAddress.a[1],
+ pAC->Addr.Net[i].CurrentMacAddress.a[2],
+ pAC->Addr.Net[i].CurrentMacAddress.a[3],
+ pAC->Addr.Net[i].CurrentMacAddress.a[4],
+ pAC->Addr.Net[i].CurrentMacAddress.a[5]))
+ }
+#endif /* DEBUG */
+
+ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+ pAPort = &pAC->Addr.Port[i];
+
+ /* Read permanent port addresses from Control Register File. */
+ for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+ InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
+ SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
+ }
+
+ if (!pAPort->CurrentMacAddressSet) {
+ /*
+ * Set the current and previous physical MAC address
+ * of this port to its permanent MAC address.
+ */
+ pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
+ pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
+ pAPort->CurrentMacAddressSet = SK_TRUE;
+ }
+
+ /* Set port's current physical MAC address. */
+ OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+ }
+#endif /* GENESIS */
+#ifdef YUKON
+ if (!pAC->GIni.GIGenesis) {
+ GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
+ }
+#endif /* YUKON */
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+ ("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+ pAPort->PermanentMacAddress.a[0],
+ pAPort->PermanentMacAddress.a[1],
+ pAPort->PermanentMacAddress.a[2],
+ pAPort->PermanentMacAddress.a[3],
+ pAPort->PermanentMacAddress.a[4],
+ pAPort->PermanentMacAddress.a[5]))
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+ ("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+ pAPort->CurrentMacAddress.a[0],
+ pAPort->CurrentMacAddress.a[1],
+ pAPort->CurrentMacAddress.a[2],
+ pAPort->CurrentMacAddress.a[3],
+ pAPort->CurrentMacAddress.a[4],
+ pAPort->CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+ }
+ /* pAC->Addr.InitDone = SK_INIT_IO; */
+ break;
+
+ case SK_INIT_RUN:
+#ifdef xDEBUG
+ for (i = 0; i < SK_MAX_MACS; i++) {
+ if (pAC->Addr.Port[i].NextExactMatchRlmt <
+ SK_ADDR_FIRST_MATCH_RLMT) {
+ Next0[i] |= 16;
+ }
+ }
+#endif /* DEBUG */
+
+ /* pAC->Addr.InitDone = SK_INIT_RUN; */
+ break;
+
+ default: /* error */
+ break;
+ }
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrInit */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ * SkAddrMcClear - clear the multicast table
+ *
+ * Description:
+ * This routine clears the multicast table.
+ *
+ * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ * immediately.
+ *
+ * It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
+ * to the adapter in use. The real work is done there.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ * may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+int SkAddrMcClear(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Index of affected port */
+int Flags) /* permanent/non-perm, sw-only */
+{
+ int ReturnCode;
+
+ if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+
+ if (pAC->GIni.GIGenesis) {
+ ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
+ }
+ else {
+ ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
+ }
+
+ return (ReturnCode);
+
+} /* SkAddrMcClear */
+
+#endif /* !SK_SLIM */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ * SkAddrXmacMcClear - clear the multicast table
+ *
+ * Description:
+ * This routine clears the multicast table
+ * (either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ * immediately.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ * may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+static int SkAddrXmacMcClear(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Index of affected port */
+int Flags) /* permanent/non-perm, sw-only */
+{
+ int i;
+
+ if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */
+
+ /* Clear RLMT multicast addresses. */
+ pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+ }
+ else { /* not permanent => DRV */
+
+ /* Clear InexactFilter */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+ }
+
+ /* Clear DRV multicast addresses. */
+
+ pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+ }
+
+ if (!(Flags & SK_MC_SW_ONLY)) {
+ (void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+ }
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrXmacMcClear */
+
+#endif /* !SK_SLIM */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ * SkAddrGmacMcClear - clear the multicast table
+ *
+ * Description:
+ * This routine clears the multicast hashing table (InexactFilter)
+ * (either the RLMT or the driver bits) of the given port.
+ *
+ * If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ * immediately.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ * may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+static int SkAddrGmacMcClear(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Index of affected port */
+int Flags) /* permanent/non-perm, sw-only */
+{
+ int i;
+
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif /* DEBUG */
+
+ /* Clear InexactFilter */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+ }
+
+ if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */
+
+ /* Copy DRV bits to InexactFilter. */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+
+ /* Clear InexactRlmtFilter. */
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
+
+ }
+ }
+ else { /* not permanent => DRV */
+
+ /* Copy RLMT bits to InexactFilter. */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+
+ /* Clear InexactDrvFilter. */
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
+ }
+ }
+
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif /* DEBUG */
+
+ if (!(Flags & SK_MC_SW_ONLY)) {
+ (void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+ }
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrGmacMcClear */
+
+#ifndef SK_ADDR_CHEAT
+
+/******************************************************************************
+ *
+ * SkXmacMcHash - hash multicast address
+ *
+ * Description:
+ * This routine computes the hash value for a multicast address.
+ * A CRC32 algorithm is used.
+ *
+ * Notes:
+ * The code was adapted from the XaQti data sheet.
+ *
+ * Context:
+ * runtime, pageable
+ *
+ * Returns:
+ * Hash value of multicast address.
+ */
+static SK_U32 SkXmacMcHash(
+unsigned char *pMc) /* Multicast address */
+{
+ SK_U32 Idx;
+ SK_U32 Bit;
+ SK_U32 Data;
+ SK_U32 Crc;
+
+ Crc = 0xFFFFFFFFUL;
+ for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
+ Data = *pMc++;
+ for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
+ Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
+ }
+ }
+
+ return (Crc & ((1 << HASH_BITS) - 1));
+
+} /* SkXmacMcHash */
+
+
+/******************************************************************************
+ *
+ * SkGmacMcHash - hash multicast address
+ *
+ * Description:
+ * This routine computes the hash value for a multicast address.
+ * A CRC16 algorithm is used.
+ *
+ * Notes:
+ *
+ *
+ * Context:
+ * runtime, pageable
+ *
+ * Returns:
+ * Hash value of multicast address.
+ */
+static SK_U32 SkGmacMcHash(
+unsigned char *pMc) /* Multicast address */
+{
+ SK_U32 Data;
+ SK_U32 TmpData;
+ SK_U32 Crc;
+ int Byte;
+ int Bit;
+
+ Crc = 0xFFFFFFFFUL;
+ for (Byte = 0; Byte < 6; Byte++) {
+ /* Get next byte. */
+ Data = (SK_U32) pMc[Byte];
+
+ /* Change bit order in byte. */
+ TmpData = Data;
+ for (Bit = 0; Bit < 8; Bit++) {
+ if (TmpData & 1L) {
+ Data |= 1L << (7 - Bit);
+ }
+ else {
+ Data &= ~(1L << (7 - Bit));
+ }
+ TmpData >>= 1;
+ }
+
+ Crc ^= (Data << 24);
+ for (Bit = 0; Bit < 8; Bit++) {
+ if (Crc & 0x80000000) {
+ Crc = (Crc << 1) ^ GMAC_POLY;
+ }
+ else {
+ Crc <<= 1;
+ }
+ }
+ }
+
+ return (Crc & ((1 << HASH_BITS) - 1));
+
+} /* SkGmacMcHash */
+
+#endif /* !SK_ADDR_CHEAT */
+
+/******************************************************************************
+ *
+ * SkAddrMcAdd - add a multicast address to a port
+ *
+ * Description:
+ * This routine enables reception for a given address on the given port.
+ *
+ * It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
+ * adapter in use. The real work is done there.
+ *
+ * Notes:
+ * The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_DATA
+ *
+ * Returns:
+ * SK_MC_FILTERING_EXACT
+ * SK_MC_FILTERING_INEXACT
+ * SK_MC_ILLEGAL_ADDRESS
+ * SK_MC_ILLEGAL_PORT
+ * SK_MC_RLMT_OVERFLOW
+ */
+int SkAddrMcAdd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Port Number */
+SK_MAC_ADDR *pMc, /* multicast address to be added */
+int Flags) /* permanent/non-permanent */
+{
+ int ReturnCode;
+
+ if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+
+ if (pAC->GIni.GIGenesis) {
+ ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+ }
+ else {
+ ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+ }
+
+ return (ReturnCode);
+
+} /* SkAddrMcAdd */
+
+
+/******************************************************************************
+ *
+ * SkAddrXmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ * This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ * The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * The multicast bit is only checked if there are no free exact match
+ * entries.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_DATA
+ *
+ * Returns:
+ * SK_MC_FILTERING_EXACT
+ * SK_MC_FILTERING_INEXACT
+ * SK_MC_ILLEGAL_ADDRESS
+ * SK_MC_RLMT_OVERFLOW
+ */
+static int SkAddrXmacMcAdd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Port Number */
+SK_MAC_ADDR *pMc, /* multicast address to be added */
+int Flags) /* permanent/non-permanent */
+{
+ int i;
+ SK_U8 Inexact;
+#ifndef SK_ADDR_CHEAT
+ SK_U32 HashBit;
+#endif /* !defined(SK_ADDR_CHEAT) */
+
+ if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */
+#ifdef xDEBUG
+ if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
+ SK_ADDR_FIRST_MATCH_RLMT) {
+ Next0[PortNumber] |= 1;
+ return (SK_MC_RLMT_OVERFLOW);
+ }
+#endif /* DEBUG */
+
+ if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
+ SK_ADDR_LAST_MATCH_RLMT) {
+ return (SK_MC_RLMT_OVERFLOW);
+ }
+
+ /* Set a RLMT multicast address. */
+
+ pAC->Addr.Port[PortNumber].Exact[
+ pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
+
+ return (SK_MC_FILTERING_EXACT);
+ }
+
+#ifdef xDEBUG
+ if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
+ SK_ADDR_FIRST_MATCH_DRV) {
+ Next0[PortNumber] |= 2;
+ return (SK_MC_RLMT_OVERFLOW);
+ }
+#endif /* DEBUG */
+
+ if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+ /* Set exact match entry. */
+ pAC->Addr.Port[PortNumber].Exact[
+ pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
+
+ /* Clear InexactFilter */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+ }
+ }
+ else {
+ if (!(pMc->a[0] & SK_MC_BIT)) {
+ /* Hashing only possible with multicast addresses */
+ return (SK_MC_ILLEGAL_ADDRESS);
+ }
+#ifndef SK_ADDR_CHEAT
+ /* Compute hash value of address. */
+ HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
+
+ /* Add bit to InexactFilter. */
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
+ 1 << (HashBit % 8);
+#else /* SK_ADDR_CHEAT */
+ /* Set all bits in InexactFilter. */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+ }
+#endif /* SK_ADDR_CHEAT */
+ }
+
+ for (Inexact = 0, i = 0; i < 8; i++) {
+ Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+ }
+
+ if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
+ return (SK_MC_FILTERING_EXACT);
+ }
+ else {
+ return (SK_MC_FILTERING_INEXACT);
+ }
+
+} /* SkAddrXmacMcAdd */
+
+
+/******************************************************************************
+ *
+ * SkAddrGmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ * This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ * The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_DATA
+ *
+ * Returns:
+ * SK_MC_FILTERING_INEXACT
+ * SK_MC_ILLEGAL_ADDRESS
+ */
+static int SkAddrGmacMcAdd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Port Number */
+SK_MAC_ADDR *pMc, /* multicast address to be added */
+int Flags) /* permanent/non-permanent */
+{
+ int i;
+#ifndef SK_ADDR_CHEAT
+ SK_U32 HashBit;
+#endif /* !defined(SK_ADDR_CHEAT) */
+
+ if (!(pMc->a[0] & SK_MC_BIT)) {
+ /* Hashing only possible with multicast addresses */
+ return (SK_MC_ILLEGAL_ADDRESS);
+ }
+
+#ifndef SK_ADDR_CHEAT
+
+ /* Compute hash value of address. */
+ HashBit = SkGmacMcHash(&pMc->a[0]);
+
+ if (Flags & SK_ADDR_PERMANENT) { /* permanent => RLMT */
+
+ /* Add bit to InexactRlmtFilter. */
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
+ 1 << (HashBit % 8);
+
+ /* Copy bit to InexactFilter. */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+ }
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
+ pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
+#endif /* DEBUG */
+ }
+ else { /* not permanent => DRV */
+
+ /* Add bit to InexactDrvFilter. */
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
+ 1 << (HashBit % 8);
+
+ /* Copy bit to InexactFilter. */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+ }
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
+ pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
+#endif /* DEBUG */
+ }
+
+#else /* SK_ADDR_CHEAT */
+
+ /* Set all bits in InexactFilter. */
+ for (i = 0; i < 8; i++) {
+ pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+ }
+#endif /* SK_ADDR_CHEAT */
+
+ return (SK_MC_FILTERING_INEXACT);
+
+} /* SkAddrGmacMcAdd */
+
+#endif /* !SK_SLIM */
+
+/******************************************************************************
+ *
+ * SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ * This routine enables reception of the addresses contained in a local
+ * table for a given port.
+ * It also programs the port's current physical MAC address.
+ *
+ * It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
+ * to the adapter in use. The real work is done there.
+ *
+ * Notes:
+ * The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_MC_FILTERING_EXACT
+ * SK_MC_FILTERING_INEXACT
+ * SK_ADDR_ILLEGAL_PORT
+ */
+int SkAddrMcUpdate(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber) /* Port Number */
+{
+ int ReturnCode = 0;
+#if (!defined(SK_SLIM) || defined(DEBUG))
+ if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+#endif /* !SK_SLIM || DEBUG */
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+ }
+#endif /* GENESIS */
+#ifdef YUKON
+ if (!pAC->GIni.GIGenesis) {
+ ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+ }
+#endif /* YUKON */
+ return (ReturnCode);
+
+} /* SkAddrMcUpdate */
+
+
+#ifdef GENESIS
+
+/******************************************************************************
+ *
+ * SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ * This routine enables reception of the addresses contained in a local
+ * table for a given port.
+ * It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ * The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_MC_FILTERING_EXACT
+ * SK_MC_FILTERING_INEXACT
+ * SK_ADDR_ILLEGAL_PORT
+ */
+static int SkAddrXmacMcUpdate(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber) /* Port Number */
+{
+ SK_U32 i;
+ SK_U8 Inexact;
+ SK_U16 *OutAddr;
+ SK_ADDR_PORT *pAPort;
+
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
+
+ pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif /* DEBUG */
+
+ /* Start with 0 to also program the logical MAC address. */
+ for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+ /* Set exact match address i on XMAC */
+ OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+ XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+ }
+
+ /* Clear other permanent exact match addresses on XMAC */
+ if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
+
+ SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
+ SK_ADDR_LAST_MATCH_RLMT);
+ }
+
+ for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
+ OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+ XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+ }
+
+ /* Clear other non-permanent exact match addresses on XMAC */
+ if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+ SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
+ SK_ADDR_LAST_MATCH_DRV);
+ }
+
+ for (Inexact = 0, i = 0; i < 8; i++) {
+ Inexact |= pAPort->InexactFilter.Bytes[i];
+ }
+
+ if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+
+ /* Set all bits in 64-bit hash register. */
+ XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ else if (Inexact != 0) {
+
+ /* Set 64-bit hash register to InexactFilter. */
+ XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ else {
+ /* Disable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
+ }
+
+ if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+ (void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+ }
+
+ /* Set port's current physical MAC address. */
+ OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+
+ XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+
+#ifdef xDEBUG
+ for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+ SK_U8 InAddr8[6];
+ SK_U16 *InAddr;
+
+ /* Get exact match address i from port PortNumber. */
+ InAddr = (SK_U16 *) &InAddr8[0];
+
+ XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
+
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
+ "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
+ i,
+ PortNumber,
+ InAddr8[0],
+ InAddr8[1],
+ InAddr8[2],
+ InAddr8[3],
+ InAddr8[4],
+ InAddr8[5],
+ pAPort->Exact[i].a[0],
+ pAPort->Exact[i].a[1],
+ pAPort->Exact[i].a[2],
+ pAPort->Exact[i].a[3],
+ pAPort->Exact[i].a[4],
+ pAPort->Exact[i].a[5]))
+ }
+#endif /* DEBUG */
+
+ /* Determine return value. */
+ if (Inexact == 0 && pAPort->PromMode == 0) {
+ return (SK_MC_FILTERING_EXACT);
+ }
+ else {
+ return (SK_MC_FILTERING_INEXACT);
+ }
+
+} /* SkAddrXmacMcUpdate */
+
+#endif /* GENESIS */
+
+#ifdef YUKON
+
+/******************************************************************************
+ *
+ * SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ * This routine enables reception of the addresses contained in a local
+ * table for a given port.
+ * It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ * The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_MC_FILTERING_EXACT
+ * SK_MC_FILTERING_INEXACT
+ * SK_ADDR_ILLEGAL_PORT
+ */
+static int SkAddrGmacMcUpdate(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber) /* Port Number */
+{
+#ifndef SK_SLIM
+ SK_U32 i;
+ SK_U8 Inexact;
+#endif /* not SK_SLIM */
+ SK_U16 *OutAddr;
+ SK_ADDR_PORT *pAPort;
+
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
+
+ pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif /* DEBUG */
+
+#ifndef SK_SLIM
+ for (Inexact = 0, i = 0; i < 8; i++) {
+ Inexact |= pAPort->InexactFilter.Bytes[i];
+ }
+
+ /* Set 64-bit hash register to InexactFilter. */
+ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+ &pAPort->InexactFilter.Bytes[0]);
+
+ if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+
+ /* Set all bits in 64-bit hash register. */
+ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ else {
+ /* Enable Hashing. */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+
+ if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+ (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+ }
+#else /* SK_SLIM */
+
+ /* Set all bits in 64-bit hash register. */
+ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+
+ (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+
+#endif /* SK_SLIM */
+
+ /* Set port's current physical MAC address. */
+ OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+ GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+
+ /* Set port's current logical MAC address. */
+ OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
+ GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
+
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+ pAPort->Exact[0].a[0],
+ pAPort->Exact[0].a[1],
+ pAPort->Exact[0].a[2],
+ pAPort->Exact[0].a[3],
+ pAPort->Exact[0].a[4],
+ pAPort->Exact[0].a[5]))
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+ pAPort->CurrentMacAddress.a[0],
+ pAPort->CurrentMacAddress.a[1],
+ pAPort->CurrentMacAddress.a[2],
+ pAPort->CurrentMacAddress.a[3],
+ pAPort->CurrentMacAddress.a[4],
+ pAPort->CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+
+#ifndef SK_SLIM
+ /* Determine return value. */
+ if (Inexact == 0 && pAPort->PromMode == 0) {
+ return (SK_MC_FILTERING_EXACT);
+ }
+ else {
+ return (SK_MC_FILTERING_INEXACT);
+ }
+#else /* SK_SLIM */
+ return (SK_MC_FILTERING_INEXACT);
+#endif /* SK_SLIM */
+
+} /* SkAddrGmacMcUpdate */
+
+#endif /* YUKON */
+
+#ifndef SK_NO_MAO
+
+/******************************************************************************
+ *
+ * SkAddrOverride - override a port's MAC address
+ *
+ * Description:
+ * This routine overrides the MAC address of one port.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS if successful.
+ * SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
+ * SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
+ * SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
+ */
+int SkAddrOverride(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* Port Number */
+SK_MAC_ADDR SK_FAR *pNewAddr, /* new MAC address */
+int Flags) /* logical/physical MAC address */
+{
+#ifndef SK_NO_RLMT
+ SK_EVPARA Para;
+#endif /* !SK_NO_RLMT */
+ SK_U32 NetNumber;
+ SK_U32 i;
+ SK_U16 SK_FAR *OutAddr;
+
+#ifndef SK_NO_RLMT
+ NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
+#else
+ NetNumber = 0;
+#endif /* SK_NO_RLMT */
+#if (!defined(SK_SLIM) || defined(DEBUG))
+ if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+#endif /* !SK_SLIM || DEBUG */
+ if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
+ return (SK_ADDR_MULTICAST_ADDRESS);
+ }
+
+ if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
+ return (SK_ADDR_TOO_EARLY);
+ }
+
+ if (Flags & SK_ADDR_SET_LOGICAL) { /* Activate logical MAC address. */
+ /* Parameter *pNewAddr is ignored. */
+ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+ if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+ return (SK_ADDR_TOO_EARLY);
+ }
+ }
+#ifndef SK_NO_RLMT
+ /* Set PortNumber to number of net's active port. */
+ PortNumber = pAC->Rlmt.Net[NetNumber].
+ Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+ pAC->Addr.Port[PortNumber].Exact[0] =
+ pAC->Addr.Net[NetNumber].CurrentMacAddress;
+
+ /* Write address to first exact match entry of active port. */
+ (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+ }
+ else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
+ /* Deactivate logical MAC address. */
+ /* Parameter *pNewAddr is ignored. */
+ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+ if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+ return (SK_ADDR_TOO_EARLY);
+ }
+ }
+#ifndef SK_NO_RLMT
+ /* Set PortNumber to number of net's active port. */
+ PortNumber = pAC->Rlmt.Net[NetNumber].
+ Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+ for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
+ pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
+ }
+
+ /* Write address to first exact match entry of active port. */
+ (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+ }
+ else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */
+ if (SK_ADDR_EQUAL(pNewAddr->a,
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+ return (SK_ADDR_DUPLICATE_ADDRESS);
+ }
+
+ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+ if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+ return (SK_ADDR_TOO_EARLY);
+ }
+
+ if (SK_ADDR_EQUAL(pNewAddr->a,
+ pAC->Addr.Port[i].CurrentMacAddress.a)) {
+ if (i == PortNumber) {
+ return (SK_ADDR_SUCCESS);
+ }
+ else {
+ return (SK_ADDR_DUPLICATE_ADDRESS);
+ }
+ }
+ }
+
+ pAC->Addr.Port[PortNumber].PreviousMacAddress =
+ pAC->Addr.Port[PortNumber].CurrentMacAddress;
+ pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+
+ /* Change port's physical MAC address. */
+ OutAddr = (SK_U16 SK_FAR *) pNewAddr;
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+ }
+#endif /* GENESIS */
+#ifdef YUKON
+ if (!pAC->GIni.GIGenesis) {
+ GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+ }
+#endif /* YUKON */
+
+#ifndef SK_NO_RLMT
+ /* Report address change to RLMT. */
+ Para.Para32[0] = PortNumber;
+ Para.Para32[0] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+#endif /* !SK_NO_RLMT */
+ }
+ else { /* Logical MAC address. */
+ if (SK_ADDR_EQUAL(pNewAddr->a,
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+ return (SK_ADDR_SUCCESS);
+ }
+
+ for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+ if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+ return (SK_ADDR_TOO_EARLY);
+ }
+
+ if (SK_ADDR_EQUAL(pNewAddr->a,
+ pAC->Addr.Port[i].CurrentMacAddress.a)) {
+ return (SK_ADDR_DUPLICATE_ADDRESS);
+ }
+ }
+
+ /*
+ * In case that the physical and the logical MAC addresses are equal
+ * we must also change the physical MAC address here.
+ * In this case we have an adapter which initially was programmed with
+ * two identical MAC addresses.
+ */
+ if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a,
+ pAC->Addr.Port[PortNumber].Exact[0].a)) {
+
+ pAC->Addr.Port[PortNumber].PreviousMacAddress =
+ pAC->Addr.Port[PortNumber].CurrentMacAddress;
+ pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+
+#ifndef SK_NO_RLMT
+ /* Report address change to RLMT. */
+ Para.Para32[0] = PortNumber;
+ Para.Para32[0] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+#endif /* !SK_NO_RLMT */
+ }
+
+#ifndef SK_NO_RLMT
+ /* Set PortNumber to number of net's active port. */
+ PortNumber = pAC->Rlmt.Net[NetNumber].
+ Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+ pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
+ pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
+#ifdef DEBUG
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+ pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
+ pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
+ pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
+ pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
+ pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
+ pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
+
+ SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+ ("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
+ pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+
+ /* Write address to first exact match entry of active port. */
+ (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+ }
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrOverride */
+
+
+#endif /* SK_NO_MAO */
+
+/******************************************************************************
+ *
+ * SkAddrPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ * This routine manages promiscuous mode:
+ * - none
+ * - all LLC frames
+ * - all MC frames
+ *
+ * It calls either SkAddrXmacPromiscuousChange or
+ * SkAddrGmacPromiscuousChange, according to the adapter in use.
+ * The real work is done there.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+int SkAddrPromiscuousChange(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* port whose promiscuous mode changes */
+int NewPromMode) /* new promiscuous mode */
+{
+ int ReturnCode = 0;
+#if (!defined(SK_SLIM) || defined(DEBUG))
+ if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+#endif /* !SK_SLIM || DEBUG */
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ ReturnCode =
+ SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+ }
+#endif /* GENESIS */
+#ifdef YUKON
+ if (!pAC->GIni.GIGenesis) {
+ ReturnCode =
+ SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+ }
+#endif /* YUKON */
+
+ return (ReturnCode);
+
+} /* SkAddrPromiscuousChange */
+
+#ifdef GENESIS
+
+/******************************************************************************
+ *
+ * SkAddrXmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ * This routine manages promiscuous mode:
+ * - none
+ * - all LLC frames
+ * - all MC frames
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+static int SkAddrXmacPromiscuousChange(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* port whose promiscuous mode changes */
+int NewPromMode) /* new promiscuous mode */
+{
+ int i;
+ SK_BOOL InexactModeBit;
+ SK_U8 Inexact;
+ SK_U8 HwInexact;
+ SK_FILTER64 HwInexactFilter;
+ SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Register. */
+ int CurPromMode = SK_PROM_MODE_NONE;
+
+ /* Read CurPromMode from Hardware. */
+ XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+
+ if ((LoMode & XM_MD_ENA_PROM) != 0) {
+ /* Promiscuous mode! */
+ CurPromMode |= SK_PROM_MODE_LLC;
+ }
+
+ for (Inexact = 0xFF, i = 0; i < 8; i++) {
+ Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+ }
+ if (Inexact == 0xFF) {
+ CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+ }
+ else {
+ /* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
+ XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+
+ InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
+
+ /* Read 64-bit hash register from XMAC */
+ XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
+
+ for (HwInexact = 0xFF, i = 0; i < 8; i++) {
+ HwInexact &= HwInexactFilter.Bytes[i];
+ }
+
+ if (InexactModeBit && (HwInexact == 0xFF)) {
+ CurPromMode |= SK_PROM_MODE_ALL_MC;
+ }
+ }
+
+ pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+ if (NewPromMode == CurPromMode) {
+ return (SK_ADDR_SUCCESS);
+ }
+
+ if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+ !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */
+
+ /* Set all bits in 64-bit hash register. */
+ XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+ !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */
+ for (Inexact = 0, i = 0; i < 8; i++) {
+ Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+ }
+ if (Inexact == 0) {
+ /* Disable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
+ }
+ else {
+ /* Set 64-bit hash register to InexactFilter. */
+ XM_OUTHASH(IoC, PortNumber, XM_HSM,
+ &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ }
+
+ if ((NewPromMode & SK_PROM_MODE_LLC) &&
+ !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */
+ /* Set the MAC in Promiscuous Mode */
+ SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+ !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC. */
+ /* Clear Promiscuous Mode */
+ SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
+ }
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrXmacPromiscuousChange */
+
+#endif /* GENESIS */
+
+#ifdef YUKON
+
+/******************************************************************************
+ *
+ * SkAddrGmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ * This routine manages promiscuous mode:
+ * - none
+ * - all LLC frames
+ * - all MC frames
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+static int SkAddrGmacPromiscuousChange(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 PortNumber, /* port whose promiscuous mode changes */
+int NewPromMode) /* new promiscuous mode */
+{
+ SK_U16 ReceiveControl; /* GMAC Receive Control Register */
+ int CurPromMode = SK_PROM_MODE_NONE;
+
+ /* Read CurPromMode from Hardware. */
+ GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
+
+ if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
+ /* Promiscuous mode! */
+ CurPromMode |= SK_PROM_MODE_LLC;
+ }
+
+ if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
+ /* All Multicast mode! */
+ CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+ }
+
+ pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+ if (NewPromMode == CurPromMode) {
+ return (SK_ADDR_SUCCESS);
+ }
+
+ if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+ !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC */
+
+ /* Set all bits in 64-bit hash register. */
+ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+ /* Enable Hashing */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+
+ if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+ !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm. MC */
+
+ /* Set 64-bit hash register to InexactFilter. */
+ GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+ &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+ /* Enable Hashing. */
+ SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+
+ if ((NewPromMode & SK_PROM_MODE_LLC) &&
+ !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */
+
+ /* Set the MAC to Promiscuous Mode. */
+ SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
+ }
+ else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+ !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC */
+
+ /* Clear Promiscuous Mode. */
+ SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
+ }
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrGmacPromiscuousChange */
+
+#endif /* YUKON */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ * SkAddrSwap - swap address info
+ *
+ * Description:
+ * This routine swaps address info of two ports.
+ *
+ * Context:
+ * runtime, pageable
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * SK_ADDR_SUCCESS
+ * SK_ADDR_ILLEGAL_PORT
+ */
+int SkAddrSwap(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+SK_U32 FromPortNumber, /* Port1 Index */
+SK_U32 ToPortNumber) /* Port2 Index */
+{
+ int i;
+ SK_U8 Byte;
+ SK_MAC_ADDR MacAddr;
+ SK_U32 DWord;
+
+ if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+
+ if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+
+ if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
+ return (SK_ADDR_ILLEGAL_PORT);
+ }
+
+ /*
+ * Swap:
+ * - Exact Match Entries (GEnesis and Yukon)
+ * Yukon uses first entry for the logical MAC
+ * address (stored in the second GMAC register).
+ * - FirstExactMatchRlmt (GEnesis only)
+ * - NextExactMatchRlmt (GEnesis only)
+ * - FirstExactMatchDrv (GEnesis only)
+ * - NextExactMatchDrv (GEnesis only)
+ * - 64-bit filter (InexactFilter)
+ * - Promiscuous Mode
+ * of ports.
+ */
+
+ for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
+ MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
+ pAC->Addr.Port[FromPortNumber].Exact[i] =
+ pAC->Addr.Port[ToPortNumber].Exact[i];
+ pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
+ }
+
+ for (i = 0; i < 8; i++) {
+ Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
+ pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
+ pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
+ pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
+ }
+
+ i = pAC->Addr.Port[FromPortNumber].PromMode;
+ pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
+ pAC->Addr.Port[ToPortNumber].PromMode = i;
+
+ if (pAC->GIni.GIGenesis) {
+ DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
+ pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
+ pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
+ pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
+
+ DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
+ pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
+ pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
+ pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
+
+ DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
+ pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
+ pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
+ pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
+
+ DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
+ pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
+ pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
+ pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
+ }
+
+ /* CAUTION: Solution works if only ports of one adapter are in use. */
+ for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
+ Net->NetNumber].NumPorts; i++) {
+ if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+ Port[i]->PortNumber == ToPortNumber) {
+ pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+ ActivePort = i;
+ /* 20001207 RA: Was "ToPortNumber;". */
+ }
+ }
+
+ (void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+ (void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
+
+ return (SK_ADDR_SUCCESS);
+
+} /* SkAddrSwap */
+
+#endif /* !SK_SLIM */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c
new file mode 100644
index 000000000000..37ce03fb8de3
--- /dev/null
+++ b/drivers/net/sk98lin/skdim.c
@@ -0,0 +1,742 @@
+/******************************************************************************
+ *
+ * Name: skdim.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.5 $
+ * Date: $Date: 2003/11/28 12:55:40 $
+ * Purpose: All functions to maintain interrupt moderation
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage the dynamic interrupt moderation on both
+ * GEnesis and Yukon adapters.
+ *
+ * Include File Hierarchy:
+ *
+ * "skdrv1st.h"
+ * "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef lint
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect.";
+#endif
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif
+
+/*******************************************************************************
+**
+** Includes
+**
+*******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#include "h/skdrv1st.h"
+#endif
+
+#ifndef __INC_SKDRV2ND_H
+#include "h/skdrv2nd.h"
+#endif
+
+#include <linux/kernel_stat.h>
+
+/*******************************************************************************
+**
+** Defines
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Typedefs
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local function prototypes
+**
+*******************************************************************************/
+
+static unsigned int GetCurrentSystemLoad(SK_AC *pAC);
+static SK_U64 GetIsrCalls(SK_AC *pAC);
+static SK_BOOL IsIntModEnabled(SK_AC *pAC);
+static void SetCurrIntCtr(SK_AC *pAC);
+static void EnableIntMod(SK_AC *pAC);
+static void DisableIntMod(SK_AC *pAC);
+static void ResizeDimTimerDuration(SK_AC *pAC);
+static void DisplaySelectedModerationType(SK_AC *pAC);
+static void DisplaySelectedModerationMask(SK_AC *pAC);
+static void DisplayDescrRatio(SK_AC *pAC);
+
+/*******************************************************************************
+**
+** Global variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Global functions
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function : SkDimModerate
+** Description : Called in every ISR to check if moderation is to be applied
+** or not for the current number of interrupts
+** Programmer : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns : void (!)
+** Notes : -
+*******************************************************************************/
+
+void
+SkDimModerate(SK_AC *pAC) {
+ unsigned int CurrSysLoad = 0; /* expressed in percent */
+ unsigned int LoadIncrease = 0; /* expressed in percent */
+ SK_U64 ThresholdInts = 0;
+ SK_U64 IsrCallsPerSec = 0;
+
+#define M_DIMINFO pAC->DynIrqModInfo
+
+ if (!IsIntModEnabled(pAC)) {
+ if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+ CurrSysLoad = GetCurrentSystemLoad(pAC);
+ if (CurrSysLoad > 75) {
+ /*
+ ** More than 75% total system load! Enable the moderation
+ ** to shield the system against too many interrupts.
+ */
+ EnableIntMod(pAC);
+ } else if (CurrSysLoad > M_DIMINFO.PrevSysLoad) {
+ LoadIncrease = (CurrSysLoad - M_DIMINFO.PrevSysLoad);
+ if (LoadIncrease > ((M_DIMINFO.PrevSysLoad *
+ C_INT_MOD_ENABLE_PERCENTAGE) / 100)) {
+ if (CurrSysLoad > 10) {
+ /*
+ ** More than 50% increase with respect to the
+ ** previous load of the system. Most likely this
+ ** is due to our ISR-proc...
+ */
+ EnableIntMod(pAC);
+ }
+ }
+ } else {
+ /*
+ ** Neither too much system load at all nor too much increase
+ ** with respect to the previous system load. Hence, we can leave
+ ** the ISR-handling like it is without enabling moderation.
+ */
+ }
+ M_DIMINFO.PrevSysLoad = CurrSysLoad;
+ }
+ } else {
+ if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+ ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec *
+ C_INT_MOD_DISABLE_PERCENTAGE) / 100);
+ IsrCallsPerSec = GetIsrCalls(pAC);
+ if (IsrCallsPerSec <= ThresholdInts) {
+ /*
+ ** The number of interrupts within the last second is
+ ** lower than the disable_percentage of the desried
+ ** maxrate. Therefore we can disable the moderation.
+ */
+ DisableIntMod(pAC);
+ M_DIMINFO.MaxModIntsPerSec =
+ (M_DIMINFO.MaxModIntsPerSecUpperLimit +
+ M_DIMINFO.MaxModIntsPerSecLowerLimit) / 2;
+ } else {
+ /*
+ ** The number of interrupts per sec is the same as expected.
+ ** Evalulate the descriptor-ratio. If it has changed, a resize
+ ** in the moderation timer might be useful
+ */
+ if (M_DIMINFO.AutoSizing) {
+ ResizeDimTimerDuration(pAC);
+ }
+ }
+ }
+ }
+
+ /*
+ ** Some information to the log...
+ */
+ if (M_DIMINFO.DisplayStats) {
+ DisplaySelectedModerationType(pAC);
+ DisplaySelectedModerationMask(pAC);
+ DisplayDescrRatio(pAC);
+ }
+
+ M_DIMINFO.NbrProcessedDescr = 0;
+ SetCurrIntCtr(pAC);
+}
+
+/*******************************************************************************
+** Function : SkDimStartModerationTimer
+** Description : Starts the audit-timer for the dynamic interrupt moderation
+** Programmer : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns : void (!)
+** Notes : -
+*******************************************************************************/
+
+void
+SkDimStartModerationTimer(SK_AC *pAC) {
+ SK_EVPARA EventParam; /* Event struct for timer event */
+
+ SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+ EventParam.Para32[0] = SK_DRV_MODERATION_TIMER;
+ SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer,
+ SK_DRV_MODERATION_TIMER_LENGTH,
+ SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*******************************************************************************
+** Function : SkDimEnableModerationIfNeeded
+** Description : Either enables or disables moderation
+** Programmer : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns : void (!)
+** Notes : This function is called when a particular adapter is opened
+** There is no Disable function, because when all interrupts
+** might be disable, the moderation timer has no meaning at all
+******************************************************************************/
+
+void
+SkDimEnableModerationIfNeeded(SK_AC *pAC) {
+
+ if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) {
+ EnableIntMod(pAC); /* notification print in this function */
+ } else if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+ SkDimStartModerationTimer(pAC);
+ if (M_DIMINFO.DisplayStats) {
+ printk("Dynamic moderation has been enabled\n");
+ }
+ } else {
+ if (M_DIMINFO.DisplayStats) {
+ printk("No moderation has been enabled\n");
+ }
+ }
+}
+
+/*******************************************************************************
+** Function : SkDimDisplayModerationSettings
+** Description : Displays the current settings regarding interrupt moderation
+** Programmer : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns : void (!)
+** Notes : -
+*******************************************************************************/
+
+void
+SkDimDisplayModerationSettings(SK_AC *pAC) {
+ DisplaySelectedModerationType(pAC);
+ DisplaySelectedModerationMask(pAC);
+}
+
+/*******************************************************************************
+**
+** Local functions
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function : GetCurrentSystemLoad
+** Description : Retrieves the current system load of the system. This load
+** is evaluated for all processors within the system.
+** Programmer : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns : unsigned int: load expressed in percentage
+** Notes : The possible range being returned is from 0 up to 100.
+** Whereas 0 means 'no load at all' and 100 'system fully loaded'
+** It is impossible to determine what actually causes the system
+** to be in 100%, but maybe that is due to too much interrupts.
+*******************************************************************************/
+
+static unsigned int
+GetCurrentSystemLoad(SK_AC *pAC) {
+ unsigned long jif = jiffies;
+ unsigned int UserTime = 0;
+ unsigned int SystemTime = 0;
+ unsigned int NiceTime = 0;
+ unsigned int IdleTime = 0;
+ unsigned int TotalTime = 0;
+ unsigned int UsedTime = 0;
+ unsigned int SystemLoad = 0;
+
+ /* unsigned int NbrCpu = 0; */
+
+ /*
+ ** The following lines have been commented out, because
+ ** from kernel 2.5.44 onwards, the kernel-owned structure
+ **
+ ** struct kernel_stat kstat
+ **
+ ** is not marked as an exported symbol in the file
+ **
+ ** kernel/ksyms.c
+ **
+ ** As a consequence, using this driver as KLM is not possible
+ ** and any access of the structure kernel_stat via the
+ ** dedicated macros kstat_cpu(i).cpustat.xxx is to be avoided.
+ **
+ ** The kstat-information might be added again in future
+ ** versions of the 2.5.xx kernel, but for the time being,
+ ** number of interrupts will serve as indication how much
+ ** load we currently have...
+ **
+ ** for (NbrCpu = 0; NbrCpu < num_online_cpus(); NbrCpu++) {
+ ** UserTime = UserTime + kstat_cpu(NbrCpu).cpustat.user;
+ ** NiceTime = NiceTime + kstat_cpu(NbrCpu).cpustat.nice;
+ ** SystemTime = SystemTime + kstat_cpu(NbrCpu).cpustat.system;
+ ** }
+ */
+ SK_U64 ThresholdInts = 0;
+ SK_U64 IsrCallsPerSec = 0;
+
+ ThresholdInts = ((M_DIMINFO.MaxModIntsPerSec *
+ C_INT_MOD_ENABLE_PERCENTAGE) + 100);
+ IsrCallsPerSec = GetIsrCalls(pAC);
+ if (IsrCallsPerSec >= ThresholdInts) {
+ /*
+ ** We do not know how much the real CPU-load is!
+ ** Return 80% as a default in order to activate DIM
+ */
+ SystemLoad = 80;
+ return (SystemLoad);
+ }
+
+ UsedTime = UserTime + NiceTime + SystemTime;
+
+ IdleTime = jif * num_online_cpus() - UsedTime;
+ TotalTime = UsedTime + IdleTime;
+
+ SystemLoad = ( 100 * (UsedTime - M_DIMINFO.PrevUsedTime) ) /
+ (TotalTime - M_DIMINFO.PrevTotalTime);
+
+ if (M_DIMINFO.DisplayStats) {
+ printk("Current system load is: %u\n", SystemLoad);
+ }
+
+ M_DIMINFO.PrevTotalTime = TotalTime;
+ M_DIMINFO.PrevUsedTime = UsedTime;
+
+ return (SystemLoad);
+}
+
+/*******************************************************************************
+** Function : GetIsrCalls
+** Description : Depending on the selected moderation mask, this function will
+** return the number of interrupts handled in the previous time-
+** frame. This evaluated number is based on the current number
+** of interrupts stored in PNMI-context and the previous stored
+** interrupts.
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : int: the number of interrupts being executed in the last
+** timeframe
+** Notes : It makes only sense to call this function, when dynamic
+** interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetIsrCalls(SK_AC *pAC) {
+ SK_U64 RxPort0IntDiff = 0;
+ SK_U64 RxPort1IntDiff = 0;
+ SK_U64 TxPort0IntDiff = 0;
+ SK_U64 TxPort1IntDiff = 0;
+
+ if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_TX_ONLY) {
+ if (pAC->GIni.GIMacsFound == 2) {
+ TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts -
+ pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+ }
+ TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts -
+ pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+ } else if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_RX_ONLY) {
+ if (pAC->GIni.GIMacsFound == 2) {
+ RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts -
+ pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+ }
+ RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts -
+ pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+ } else {
+ if (pAC->GIni.GIMacsFound == 2) {
+ RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts -
+ pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+ TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts -
+ pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+ }
+ RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts -
+ pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+ TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts -
+ pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+ }
+
+ return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function : GetRxCalls
+** Description : This function will return the number of times a receive inter-
+** rupt was processed. This is needed to evaluate any resizing
+** factor.
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : SK_U64: the number of RX-ints being processed
+** Notes : It makes only sense to call this function, when dynamic
+** interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetRxCalls(SK_AC *pAC) {
+ SK_U64 RxPort0IntDiff = 0;
+ SK_U64 RxPort1IntDiff = 0;
+
+ if (pAC->GIni.GIMacsFound == 2) {
+ RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts -
+ pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+ }
+ RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts -
+ pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+
+ return (RxPort0IntDiff + RxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function : SetCurrIntCtr
+** Description : Will store the current number orf occured interrupts in the
+** adapter context. This is needed to evaluated the number of
+** interrupts within a current timeframe.
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : void (!)
+** Notes : -
+*******************************************************************************/
+
+static void
+SetCurrIntCtr(SK_AC *pAC) {
+ if (pAC->GIni.GIMacsFound == 2) {
+ pAC->DynIrqModInfo.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts;
+ pAC->DynIrqModInfo.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts;
+ }
+ pAC->DynIrqModInfo.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts;
+ pAC->DynIrqModInfo.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts;
+}
+
+/*******************************************************************************
+** Function : IsIntModEnabled()
+** Description : Retrieves the current value of the interrupts moderation
+** command register. Its content determines whether any
+** moderation is running or not.
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : SK_TRUE : if mod timer running
+** SK_FALSE : if no moderation is being performed
+** Notes : -
+*******************************************************************************/
+
+static SK_BOOL
+IsIntModEnabled(SK_AC *pAC) {
+ unsigned long CtrCmd;
+
+ SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd);
+ if ((CtrCmd & TIM_START) == TIM_START) {
+ return SK_TRUE;
+ } else {
+ return SK_FALSE;
+ }
+}
+
+/*******************************************************************************
+** Function : EnableIntMod()
+** Description : Enables the interrupt moderation using the values stored in
+** in the pAC->DynIntMod data structure
+** Programmer : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns : -
+** Notes : -
+*******************************************************************************/
+
+static void
+EnableIntMod(SK_AC *pAC) {
+ unsigned long ModBase;
+
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+ ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+ } else {
+ ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+ }
+
+ SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+ SK_OUT32(pAC->IoBase, B2_IRQM_MSK, pAC->DynIrqModInfo.MaskIrqModeration);
+ SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+ if (M_DIMINFO.DisplayStats) {
+ printk("Enabled interrupt moderation (%i ints/sec)\n",
+ M_DIMINFO.MaxModIntsPerSec);
+ }
+}
+
+/*******************************************************************************
+** Function : DisableIntMod()
+** Description : Disables the interrupt moderation independent of what inter-
+** rupts are running or not
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : -
+** Notes : -
+*******************************************************************************/
+
+static void
+DisableIntMod(SK_AC *pAC) {
+
+ SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP);
+ if (M_DIMINFO.DisplayStats) {
+ printk("Disabled interrupt moderation\n");
+ }
+}
+
+/*******************************************************************************
+** Function : ResizeDimTimerDuration();
+** Description : Checks the current used descriptor ratio and resizes the
+** duration timer (longer/smaller) if possible.
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : -
+** Notes : There are both maximum and minimum timer duration value.
+** This function assumes that interrupt moderation is already
+** enabled!
+*******************************************************************************/
+
+static void
+ResizeDimTimerDuration(SK_AC *pAC) {
+ SK_BOOL IncreaseTimerDuration;
+ int TotalMaxNbrDescr;
+ int UsedDescrRatio;
+ int RatioDiffAbs;
+ int RatioDiffRel;
+ int NewMaxModIntsPerSec;
+ int ModAdjValue;
+ long ModBase;
+
+ /*
+ ** Check first if we are allowed to perform any modification
+ */
+ if (IsIntModEnabled(pAC)) {
+ if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_DYNAMIC) {
+ return;
+ } else {
+ if (M_DIMINFO.ModJustEnabled) {
+ M_DIMINFO.ModJustEnabled = SK_FALSE;
+ return;
+ }
+ }
+ }
+
+ /*
+ ** If we got until here, we have to evaluate the amount of the
+ ** descriptor ratio change...
+ */
+ TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+ UsedDescrRatio = (M_DIMINFO.NbrProcessedDescr * 100) / TotalMaxNbrDescr;
+
+ if (UsedDescrRatio > M_DIMINFO.PrevUsedDescrRatio) {
+ RatioDiffAbs = (UsedDescrRatio - M_DIMINFO.PrevUsedDescrRatio);
+ RatioDiffRel = (RatioDiffAbs * 100) / UsedDescrRatio;
+ M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+ IncreaseTimerDuration = SK_FALSE; /* in other words: DECREASE */
+ } else if (UsedDescrRatio < M_DIMINFO.PrevUsedDescrRatio) {
+ RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+ RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+ M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+ IncreaseTimerDuration = SK_TRUE; /* in other words: INCREASE */
+ } else {
+ RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+ RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+ M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+ IncreaseTimerDuration = SK_TRUE; /* in other words: INCREASE */
+ }
+
+ /*
+ ** Now we can determine the change in percent
+ */
+ if ((RatioDiffRel >= 0) && (RatioDiffRel <= 5) ) {
+ ModAdjValue = 1; /* 1% change - maybe some other value in future */
+ } else if ((RatioDiffRel > 5) && (RatioDiffRel <= 10) ) {
+ ModAdjValue = 1; /* 1% change - maybe some other value in future */
+ } else if ((RatioDiffRel > 10) && (RatioDiffRel <= 15) ) {
+ ModAdjValue = 1; /* 1% change - maybe some other value in future */
+ } else {
+ ModAdjValue = 1; /* 1% change - maybe some other value in future */
+ }
+
+ if (IncreaseTimerDuration) {
+ NewMaxModIntsPerSec = M_DIMINFO.MaxModIntsPerSec +
+ (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+ } else {
+ NewMaxModIntsPerSec = M_DIMINFO.MaxModIntsPerSec -
+ (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+ }
+
+ /*
+ ** Check if we exceed boundaries...
+ */
+ if ( (NewMaxModIntsPerSec > M_DIMINFO.MaxModIntsPerSecUpperLimit) ||
+ (NewMaxModIntsPerSec < M_DIMINFO.MaxModIntsPerSecLowerLimit)) {
+ if (M_DIMINFO.DisplayStats) {
+ printk("Cannot change ModTim from %i to %i ints/sec\n",
+ M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+ }
+ return;
+ } else {
+ if (M_DIMINFO.DisplayStats) {
+ printk("Resized ModTim from %i to %i ints/sec\n",
+ M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+ }
+ }
+
+ M_DIMINFO.MaxModIntsPerSec = NewMaxModIntsPerSec;
+
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+ ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+ } else {
+ ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+ }
+
+ /*
+ ** We do not need to touch any other registers
+ */
+ SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+}
+
+/*******************************************************************************
+** Function : DisplaySelectedModerationType()
+** Description : Displays what type of moderation we have
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : void!
+** Notes : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationType(SK_AC *pAC) {
+
+ if (pAC->DynIrqModInfo.DisplayStats) {
+ if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) {
+ printk("Static int moderation runs with %i INTS/sec\n",
+ pAC->DynIrqModInfo.MaxModIntsPerSec);
+ } else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+ if (IsIntModEnabled(pAC)) {
+ printk("Dynamic int moderation runs with %i INTS/sec\n",
+ pAC->DynIrqModInfo.MaxModIntsPerSec);
+ } else {
+ printk("Dynamic int moderation currently not applied\n");
+ }
+ } else {
+ printk("No interrupt moderation selected!\n");
+ }
+ }
+}
+
+/*******************************************************************************
+** Function : DisplaySelectedModerationMask()
+** Description : Displays what interrupts are moderated
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : void!
+** Notes : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationMask(SK_AC *pAC) {
+
+ if (pAC->DynIrqModInfo.DisplayStats) {
+ if (pAC->DynIrqModInfo.IntModTypeSelect != C_INT_MOD_NONE) {
+ switch (pAC->DynIrqModInfo.MaskIrqModeration) {
+ case IRQ_MASK_TX_ONLY:
+ printk("Only Tx-interrupts are moderated\n");
+ break;
+ case IRQ_MASK_RX_ONLY:
+ printk("Only Rx-interrupts are moderated\n");
+ break;
+ case IRQ_MASK_SP_ONLY:
+ printk("Only special-interrupts are moderated\n");
+ break;
+ case IRQ_MASK_TX_RX:
+ printk("Tx- and Rx-interrupts are moderated\n");
+ break;
+ case IRQ_MASK_SP_RX:
+ printk("Special- and Rx-interrupts are moderated\n");
+ break;
+ case IRQ_MASK_SP_TX:
+ printk("Special- and Tx-interrupts are moderated\n");
+ break;
+ case IRQ_MASK_RX_TX_SP:
+ printk("All Rx-, Tx and special-interrupts are moderated\n");
+ break;
+ default:
+ printk("Don't know what is moderated\n");
+ break;
+ }
+ } else {
+ printk("No specific interrupts masked for moderation\n");
+ }
+ }
+}
+
+/*******************************************************************************
+** Function : DisplayDescrRatio
+** Description : Like the name states...
+** Programmer : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns : void!
+** Notes : -
+*******************************************************************************/
+
+static void
+DisplayDescrRatio(SK_AC *pAC) {
+ int TotalMaxNbrDescr = 0;
+
+ if (pAC->DynIrqModInfo.DisplayStats) {
+ TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+ printk("Ratio descriptors: %i/%i\n",
+ M_DIMINFO.NbrProcessedDescr, TotalMaxNbrDescr);
+ }
+}
+
+/*******************************************************************************
+**
+** End of file
+**
+*******************************************************************************/
diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
new file mode 100644
index 000000000000..5a6da8950faa
--- /dev/null
+++ b/drivers/net/sk98lin/skethtool.c
@@ -0,0 +1,627 @@
+/******************************************************************************
+ *
+ * Name: skethtool.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.7 $
+ * Date: $Date: 2004/09/29 13:32:07 $
+ * Purpose: All functions regarding ethtool handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2004 Marvell.
+ *
+ * Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet
+ * Server Adapters.
+ *
+ * Author: Ralph Roesler (rroesler@syskonnect.de)
+ * Mirko Lindner (mlindner@syskonnect.de)
+ *
+ * Address all question to: linux@syskonnect.de
+ *
+ * The technical manual for the adapters is available from SysKonnect's
+ * web pages: www.syskonnect.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.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ *****************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+#include "h/skversion.h"
+
+#include <linux/ethtool.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+
+/******************************************************************************
+ *
+ * Defines
+ *
+ *****************************************************************************/
+
+#define SUPP_COPPER_ALL (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+ SUPPORTED_1000baseT_Half| SUPPORTED_1000baseT_Full| \
+ SUPPORTED_TP)
+
+#define ADV_COPPER_ALL (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+ ADVERTISED_1000baseT_Half| ADVERTISED_1000baseT_Full| \
+ ADVERTISED_TP)
+
+#define SUPP_FIBRE_ALL (SUPPORTED_1000baseT_Full | \
+ SUPPORTED_FIBRE | \
+ SUPPORTED_Autoneg)
+
+#define ADV_FIBRE_ALL (ADVERTISED_1000baseT_Full | \
+ ADVERTISED_FIBRE | \
+ ADVERTISED_Autoneg)
+
+
+/******************************************************************************
+ *
+ * Local Functions
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * getSettings - retrieves the current settings of the selected adapter
+ *
+ * Description:
+ * The current configuration of the selected adapter is returned.
+ * This configuration involves a)speed, b)duplex and c)autoneg plus
+ * a number of other variables.
+ *
+ * Returns: always 0
+ *
+ */
+static int getSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ const DEV_NET *pNet = netdev_priv(dev);
+ int port = pNet->PortNr;
+ const SK_AC *pAC = pNet->pAC;
+ const SK_GEPORT *pPort = &pAC->GIni.GP[port];
+
+ static int DuplexAutoNegConfMap[9][3]= {
+ { -1 , -1 , -1 },
+ { 0 , -1 , -1 },
+ { SK_LMODE_HALF , DUPLEX_HALF, AUTONEG_DISABLE },
+ { SK_LMODE_FULL , DUPLEX_FULL, AUTONEG_DISABLE },
+ { SK_LMODE_AUTOHALF , DUPLEX_HALF, AUTONEG_ENABLE },
+ { SK_LMODE_AUTOFULL , DUPLEX_FULL, AUTONEG_ENABLE },
+ { SK_LMODE_AUTOBOTH , DUPLEX_FULL, AUTONEG_ENABLE },
+ { SK_LMODE_AUTOSENSE , -1 , -1 },
+ { SK_LMODE_INDETERMINATED, -1 , -1 }
+ };
+ static int SpeedConfMap[6][2] = {
+ { 0 , -1 },
+ { SK_LSPEED_AUTO , -1 },
+ { SK_LSPEED_10MBPS , SPEED_10 },
+ { SK_LSPEED_100MBPS , SPEED_100 },
+ { SK_LSPEED_1000MBPS , SPEED_1000 },
+ { SK_LSPEED_INDETERMINATED, -1 }
+ };
+ static int AdvSpeedMap[6][2] = {
+ { 0 , -1 },
+ { SK_LSPEED_AUTO , -1 },
+ { SK_LSPEED_10MBPS , ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full },
+ { SK_LSPEED_100MBPS , ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full },
+ { SK_LSPEED_1000MBPS , ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full},
+ { SK_LSPEED_INDETERMINATED, -1 }
+ };
+
+ ecmd->phy_address = port;
+ ecmd->speed = SpeedConfMap[pPort->PLinkSpeedUsed][1];
+ ecmd->duplex = DuplexAutoNegConfMap[pPort->PLinkModeStatus][1];
+ ecmd->autoneg = DuplexAutoNegConfMap[pPort->PLinkModeStatus][2];
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ if (pAC->GIni.GICopperType) {
+ ecmd->port = PORT_TP;
+ ecmd->supported = (SUPP_COPPER_ALL|SUPPORTED_Autoneg);
+ if (pAC->GIni.GIGenesis) {
+ ecmd->supported &= ~(SUPPORTED_10baseT_Half);
+ ecmd->supported &= ~(SUPPORTED_10baseT_Full);
+ ecmd->supported &= ~(SUPPORTED_100baseT_Half);
+ ecmd->supported &= ~(SUPPORTED_100baseT_Full);
+ } else {
+ if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+ ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
+ }
+#ifdef CHIP_ID_YUKON_FE
+ if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) {
+ ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
+ ecmd->supported &= ~(SUPPORTED_1000baseT_Full);
+ }
+#endif
+ }
+ if (pAC->GIni.GP[0].PLinkSpeed != SK_LSPEED_AUTO) {
+ ecmd->advertising = AdvSpeedMap[pPort->PLinkSpeed][1];
+ if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+ ecmd->advertising &= ~(SUPPORTED_1000baseT_Half);
+ }
+ } else {
+ ecmd->advertising = ecmd->supported;
+ }
+
+ if (ecmd->autoneg == AUTONEG_ENABLE)
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ } else {
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPP_FIBRE_ALL;
+ ecmd->advertising = ADV_FIBRE_ALL;
+ }
+ return 0;
+}
+
+/*
+ * MIB infrastructure uses instance value starting at 1
+ * based on board and port.
+ */
+static inline u32 pnmiInstance(const DEV_NET *pNet)
+{
+ return 1 + (pNet->pAC->RlmtNets == 2) + pNet->PortNr;
+}
+
+/*****************************************************************************
+ *
+ * setSettings - configures the settings of a selected adapter
+ *
+ * Description:
+ * Possible settings that may be altered are a)speed, b)duplex or
+ * c)autonegotiation.
+ *
+ * Returns:
+ * 0: everything fine, no error
+ * <0: the return value is the error code of the failure
+ */
+static int setSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ u32 instance;
+ char buf[4];
+ int len = 1;
+
+ if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100
+ && ecmd->speed != SPEED_1000)
+ return -EINVAL;
+
+ if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+
+ if (ecmd->autoneg == AUTONEG_DISABLE)
+ *buf = (ecmd->duplex == DUPLEX_FULL)
+ ? SK_LMODE_FULL : SK_LMODE_HALF;
+ else
+ *buf = (ecmd->duplex == DUPLEX_FULL)
+ ? SK_LMODE_AUTOFULL : SK_LMODE_AUTOHALF;
+
+ instance = pnmiInstance(pNet);
+ if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE,
+ &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
+ return -EINVAL;
+
+ switch(ecmd->speed) {
+ case SPEED_1000:
+ *buf = SK_LSPEED_1000MBPS;
+ break;
+ case SPEED_100:
+ *buf = SK_LSPEED_100MBPS;
+ break;
+ case SPEED_10:
+ *buf = SK_LSPEED_10MBPS;
+ }
+
+ if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE,
+ &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * getDriverInfo - returns generic driver and adapter information
+ *
+ * Description:
+ * Generic driver information is returned via this function, such as
+ * the name of the driver, its version and and firmware version.
+ * In addition to this, the location of the selected adapter is
+ * returned as a bus info string (e.g. '01:05.0').
+ *
+ * Returns: N/A
+ *
+ */
+static void getDriverInfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ const DEV_NET *pNet = netdev_priv(dev);
+ const SK_AC *pAC = pNet->pAC;
+ char vers[32];
+
+ snprintf(vers, sizeof(vers)-1, VER_STRING "(v%d.%d)",
+ (pAC->GIni.GIPciHwRev >> 4) & 0xf, pAC->GIni.GIPciHwRev & 0xf);
+
+ strlcpy(info->driver, DRIVER_FILE_NAME, sizeof(info->driver));
+ strcpy(info->version, vers);
+ strcpy(info->fw_version, "N/A");
+ strlcpy(info->bus_info, pci_name(pAC->PciDev), ETHTOOL_BUSINFO_LEN);
+}
+
+/*
+ * Ethtool statistics support.
+ */
+static const char StringsStats[][ETH_GSTRING_LEN] = {
+ "rx_packets", "tx_packets",
+ "rx_bytes", "tx_bytes",
+ "rx_errors", "tx_errors",
+ "rx_dropped", "tx_dropped",
+ "multicasts", "collisions",
+ "rx_length_errors", "rx_buffer_overflow_errors",
+ "rx_crc_errors", "rx_frame_errors",
+ "rx_too_short_errors", "rx_too_long_errors",
+ "rx_carrier_extension_errors", "rx_symbol_errors",
+ "rx_llc_mac_size_errors", "rx_carrier_errors",
+ "rx_jabber_errors", "rx_missed_errors",
+ "tx_abort_collision_errors", "tx_carrier_errors",
+ "tx_buffer_underrun_errors", "tx_heartbeat_errors",
+ "tx_window_errors",
+};
+
+static int getStatsCount(struct net_device *dev)
+{
+ return ARRAY_SIZE(StringsStats);
+}
+
+static void getStrings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ switch(stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *StringsStats, sizeof(StringsStats));
+ break;
+ }
+}
+
+static void getEthtoolStats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ const DEV_NET *pNet = netdev_priv(dev);
+ const SK_AC *pAC = pNet->pAC;
+ const SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct;
+
+ *data++ = pPnmiStruct->Stat[0].StatRxOkCts;
+ *data++ = pPnmiStruct->Stat[0].StatTxOkCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxOctetsOkCts;
+ *data++ = pPnmiStruct->Stat[0].StatTxOctetsOkCts;
+ *data++ = pPnmiStruct->InErrorsCts;
+ *data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts;
+ *data++ = pPnmiStruct->RxNoBufCts;
+ *data++ = pPnmiStruct->TxNoBufCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxMulticastOkCts;
+ *data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxRuntCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxFifoOverflowCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxFcsCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxFramingCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxShortsCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxTooLongCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxCextCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxSymbolCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxIRLengthCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxCarrierCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxJabberCts;
+ *data++ = pPnmiStruct->Stat[0].StatRxMissedCts;
+ *data++ = pAC->stats.tx_aborted_errors;
+ *data++ = pPnmiStruct->Stat[0].StatTxCarrierCts;
+ *data++ = pPnmiStruct->Stat[0].StatTxFifoUnderrunCts;
+ *data++ = pPnmiStruct->Stat[0].StatTxCarrierCts;
+ *data++ = pAC->stats.tx_window_errors;
+}
+
+
+/*****************************************************************************
+ *
+ * toggleLeds - Changes the LED state of an adapter
+ *
+ * Description:
+ * This function changes the current state of all LEDs of an adapter so
+ * that it can be located by a user.
+ *
+ * Returns: N/A
+ *
+ */
+static void toggleLeds(DEV_NET *pNet, int on)
+{
+ SK_AC *pAC = pNet->pAC;
+ int port = pNet->PortNr;
+ void __iomem *io = pAC->IoBase;
+
+ if (pAC->GIni.GIGenesis) {
+ SK_OUT8(io, MR_ADDR(port,LNK_LED_REG),
+ on ? SK_LNK_ON : SK_LNK_OFF);
+ SkGeYellowLED(pAC, io,
+ on ? (LED_ON >> 1) : (LED_OFF >> 1));
+ SkGeXmitLED(pAC, io, MR_ADDR(port,RX_LED_INI),
+ on ? SK_LED_TST : SK_LED_DIS);
+
+ if (pAC->GIni.GP[port].PhyType == SK_PHY_BCOM)
+ SkXmPhyWrite(pAC, io, port, PHY_BCOM_P_EXT_CTRL,
+ on ? PHY_B_PEC_LED_ON : PHY_B_PEC_LED_OFF);
+ else if (pAC->GIni.GP[port].PhyType == SK_PHY_LONE)
+ SkXmPhyWrite(pAC, io, port, PHY_LONE_LED_CFG,
+ on ? 0x0800 : PHY_L_LC_LEDT);
+ else
+ SkGeXmitLED(pAC, io, MR_ADDR(port,TX_LED_INI),
+ on ? SK_LED_TST : SK_LED_DIS);
+ } else {
+ const u16 YukLedOn = (PHY_M_LED_MO_DUP(MO_LED_ON) |
+ PHY_M_LED_MO_10(MO_LED_ON) |
+ PHY_M_LED_MO_100(MO_LED_ON) |
+ PHY_M_LED_MO_1000(MO_LED_ON) |
+ PHY_M_LED_MO_RX(MO_LED_ON));
+ const u16 YukLedOff = (PHY_M_LED_MO_DUP(MO_LED_OFF) |
+ PHY_M_LED_MO_10(MO_LED_OFF) |
+ PHY_M_LED_MO_100(MO_LED_OFF) |
+ PHY_M_LED_MO_1000(MO_LED_OFF) |
+ PHY_M_LED_MO_RX(MO_LED_OFF));
+
+
+ SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_CTRL,0);
+ SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_OVER,
+ on ? YukLedOn : YukLedOff);
+ }
+}
+
+/*****************************************************************************
+ *
+ * skGeBlinkTimer - Changes the LED state of an adapter
+ *
+ * Description:
+ * This function changes the current state of all LEDs of an adapter so
+ * that it can be located by a user. If the requested time interval for
+ * this test has elapsed, this function cleans up everything that was
+ * temporarily setup during the locate NIC test. This involves of course
+ * also closing or opening any adapter so that the initial board state
+ * is recovered.
+ *
+ * Returns: N/A
+ *
+ */
+void SkGeBlinkTimer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *) data;
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+
+ toggleLeds(pNet, pAC->LedsOn);
+
+ pAC->LedsOn = !pAC->LedsOn;
+ mod_timer(&pAC->BlinkTimer, jiffies + HZ/4);
+}
+
+/*****************************************************************************
+ *
+ * locateDevice - start the locate NIC feature of the elected adapter
+ *
+ * Description:
+ * This function is used if the user want to locate a particular NIC.
+ * All LEDs are regularly switched on and off, so the NIC can easily
+ * be identified.
+ *
+ * Returns:
+ * ==0: everything fine, no error, locateNIC test was started
+ * !=0: one locateNIC test runs already
+ *
+ */
+static int locateDevice(struct net_device *dev, u32 data)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+
+ if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+ data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+ /* start blinking */
+ pAC->LedsOn = 0;
+ mod_timer(&pAC->BlinkTimer, jiffies);
+ msleep_interruptible(data * 1000);
+ del_timer_sync(&pAC->BlinkTimer);
+ toggleLeds(pNet, 0);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * getPauseParams - retrieves the pause parameters
+ *
+ * Description:
+ * All current pause parameters of a selected adapter are placed
+ * in the passed ethtool_pauseparam structure and are returned.
+ *
+ * Returns: N/A
+ *
+ */
+static void getPauseParams(struct net_device *dev, struct ethtool_pauseparam *epause)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
+
+ epause->rx_pause = (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) ||
+ (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM);
+
+ epause->tx_pause = epause->rx_pause || (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND);
+ epause->autoneg = epause->rx_pause || epause->tx_pause;
+}
+
+/*****************************************************************************
+ *
+ * setPauseParams - configures the pause parameters of an adapter
+ *
+ * Description:
+ * This function sets the Rx or Tx pause parameters
+ *
+ * Returns:
+ * ==0: everything fine, no error
+ * !=0: the return value is the error code of the failure
+ */
+static int setPauseParams(struct net_device *dev , struct ethtool_pauseparam *epause)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
+ u32 instance = pnmiInstance(pNet);
+ struct ethtool_pauseparam old;
+ u8 oldspeed = pPort->PLinkSpeedUsed;
+ char buf[4];
+ int len = 1;
+ int ret;
+
+ /*
+ ** we have to determine the current settings to see if
+ ** the operator requested any modification of the flow
+ ** control parameters...
+ */
+ getPauseParams(dev, &old);
+
+ /*
+ ** perform modifications regarding the changes
+ ** requested by the operator
+ */
+ if (epause->autoneg != old.autoneg)
+ *buf = epause->autoneg ? SK_FLOW_MODE_NONE : SK_FLOW_MODE_SYMMETRIC;
+ else {
+ if (epause->rx_pause && epause->tx_pause)
+ *buf = SK_FLOW_MODE_SYMMETRIC;
+ else if (epause->rx_pause && !epause->tx_pause)
+ *buf = SK_FLOW_MODE_SYM_OR_REM;
+ else if (!epause->rx_pause && epause->tx_pause)
+ *buf = SK_FLOW_MODE_LOC_SEND;
+ else
+ *buf = SK_FLOW_MODE_NONE;
+ }
+
+ ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_FLOWCTRL_MODE,
+ &buf, &len, instance, pNet->NetNr);
+
+ if (ret != SK_PNMI_ERR_OK) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
+ ("ethtool (sk98lin): error changing rx/tx pause (%i)\n", ret));
+ goto err;
+ }
+
+ /*
+ ** It may be that autoneg has been disabled! Therefore
+ ** set the speed to the previously used value...
+ */
+ if (!epause->autoneg) {
+ len = 1;
+ ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE,
+ &oldspeed, &len, instance, pNet->NetNr);
+ if (ret != SK_PNMI_ERR_OK)
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
+ ("ethtool (sk98lin): error setting speed (%i)\n", ret));
+ }
+ err:
+ return ret ? -EIO : 0;
+}
+
+/* Only Yukon supports checksum offload. */
+static int setScatterGather(struct net_device *dev, u32 data)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+ return -EOPNOTSUPP;
+ return ethtool_op_set_sg(dev, data);
+}
+
+static int setTxCsum(struct net_device *dev, u32 data)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+ return -EOPNOTSUPP;
+
+ return ethtool_op_set_tx_csum(dev, data);
+}
+
+static u32 getRxCsum(struct net_device *dev)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+
+ return pAC->RxPort[pNet->PortNr].RxCsum;
+}
+
+static int setRxCsum(struct net_device *dev, u32 data)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+ return -EOPNOTSUPP;
+
+ pAC->RxPort[pNet->PortNr].RxCsum = data != 0;
+ return 0;
+}
+
+static int getRegsLen(struct net_device *dev)
+{
+ return 0x4000;
+}
+
+/*
+ * Returns copy of whole control register region
+ * Note: skip RAM address register because accessing it will
+ * cause bus hangs!
+ */
+static void getRegs(struct net_device *dev, struct ethtool_regs *regs,
+ void *p)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ const void __iomem *io = pNet->pAC->IoBase;
+
+ regs->version = 1;
+ memset(p, 0, regs->len);
+ memcpy_fromio(p, io, B3_RAM_ADDR);
+
+ memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
+ regs->len - B3_RI_WTO_R1);
+}
+
+const struct ethtool_ops SkGeEthtoolOps = {
+ .get_settings = getSettings,
+ .set_settings = setSettings,
+ .get_drvinfo = getDriverInfo,
+ .get_strings = getStrings,
+ .get_stats_count = getStatsCount,
+ .get_ethtool_stats = getEthtoolStats,
+ .phys_id = locateDevice,
+ .get_pauseparam = getPauseParams,
+ .set_pauseparam = setPauseParams,
+ .get_link = ethtool_op_get_link,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = setScatterGather,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = setTxCsum,
+ .get_rx_csum = getRxCsum,
+ .set_rx_csum = setRxCsum,
+ .get_regs = getRegs,
+ .get_regs_len = getRegsLen,
+};
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
new file mode 100644
index 000000000000..20890e44f99a
--- /dev/null
+++ b/drivers/net/sk98lin/skge.c
@@ -0,0 +1,5218 @@
+/******************************************************************************
+ *
+ * Name: skge.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.45 $
+ * Date: $Date: 2004/02/12 14:41:02 $
+ * Purpose: The main driver source module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * Driver for Marvell Yukon chipset and SysKonnect Gigabit Ethernet
+ * Server Adapters.
+ *
+ * Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and
+ * SysKonnects GEnesis Solaris driver
+ * Author: Christoph Goos (cgoos@syskonnect.de)
+ * Mirko Lindner (mlindner@syskonnect.de)
+ *
+ * Address all question to: linux@syskonnect.de
+ *
+ * The technical manual for the adapters is available from SysKonnect's
+ * web pages: www.syskonnect.com
+ * Goto "Support" and search Knowledge Base for "manual".
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Possible compiler options (#define xxx / -Dxxx):
+ *
+ * debugging can be enable by changing SK_DEBUG_CHKMOD and
+ * SK_DEBUG_CHKCAT in makefile (described there).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the main module of the Linux GE driver.
+ *
+ * All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h
+ * are part of SysKonnect's COMMON MODULES for the SK-98xx adapters.
+ * Those are used for drivers on multiple OS', so some thing may seem
+ * unnecessary complicated on Linux. Please do not try to 'clean up'
+ * them without VERY good reasons, because this will make it more
+ * difficult to keep the Linux driver in synchronisation with the
+ * other versions.
+ *
+ * Include file hierarchy:
+ *
+ * <linux/module.h>
+ *
+ * "h/skdrv1st.h"
+ * <linux/types.h>
+ * <linux/kernel.h>
+ * <linux/string.h>
+ * <linux/errno.h>
+ * <linux/ioport.h>
+ * <linux/slab.h>
+ * <linux/interrupt.h>
+ * <linux/pci.h>
+ * <linux/bitops.h>
+ * <asm/byteorder.h>
+ * <asm/io.h>
+ * <linux/netdevice.h>
+ * <linux/etherdevice.h>
+ * <linux/skbuff.h>
+ * those three depending on kernel version used:
+ * <linux/bios32.h>
+ * <linux/init.h>
+ * <asm/uaccess.h>
+ * <net/checksum.h>
+ *
+ * "h/skerror.h"
+ * "h/skdebug.h"
+ * "h/sktypes.h"
+ * "h/lm80.h"
+ * "h/xmac_ii.h"
+ *
+ * "h/skdrv2nd.h"
+ * "h/skqueue.h"
+ * "h/skgehwt.h"
+ * "h/sktimer.h"
+ * "h/ski2c.h"
+ * "h/skgepnmi.h"
+ * "h/skvpd.h"
+ * "h/skgehw.h"
+ * "h/skgeinit.h"
+ * "h/skaddr.h"
+ * "h/skgesirq.h"
+ * "h/skrlmt.h"
+ *
+ ******************************************************************************/
+
+#include "h/skversion.h"
+
+#include <linux/in.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/ip.h>
+#include <linux/mii.h>
+#include <linux/mm.h>
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/*******************************************************************************
+ *
+ * Defines
+ *
+ ******************************************************************************/
+
+/* for debuging on x86 only */
+/* #define BREAKPOINT() asm(" int $3"); */
+
+/* use the transmit hw checksum driver functionality */
+#define USE_SK_TX_CHECKSUM
+
+/* use the receive hw checksum driver functionality */
+#define USE_SK_RX_CHECKSUM
+
+/* use the scatter-gather functionality with sendfile() */
+#define SK_ZEROCOPY
+
+/* use of a transmit complete interrupt */
+#define USE_TX_COMPLETE
+
+/*
+ * threshold for copying small receive frames
+ * set to 0 to avoid copying, set to 9001 to copy all frames
+ */
+#define SK_COPY_THRESHOLD 50
+
+/* number of adapters that can be configured via command line params */
+#define SK_MAX_CARD_PARAM 16
+
+
+
+/*
+ * use those defines for a compile-in version of the driver instead
+ * of command line parameters
+ */
+// #define LINK_SPEED_A {"Auto", }
+// #define LINK_SPEED_B {"Auto", }
+// #define AUTO_NEG_A {"Sense", }
+// #define AUTO_NEG_B {"Sense", }
+// #define DUP_CAP_A {"Both", }
+// #define DUP_CAP_B {"Both", }
+// #define FLOW_CTRL_A {"SymOrRem", }
+// #define FLOW_CTRL_B {"SymOrRem", }
+// #define ROLE_A {"Auto", }
+// #define ROLE_B {"Auto", }
+// #define PREF_PORT {"A", }
+// #define CON_TYPE {"Auto", }
+// #define RLMT_MODE {"CheckLinkState", }
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
+#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
+
+
+/* Set blink mode*/
+#define OEM_CONFIG_VALUE ( SK_ACT_LED_BLINK | \
+ SK_DUP_LED_NORMAL | \
+ SK_LED_LINK100_ON)
+
+
+/* Isr return value */
+#define SkIsrRetVar irqreturn_t
+#define SkIsrRetNone IRQ_NONE
+#define SkIsrRetHandled IRQ_HANDLED
+
+
+/*******************************************************************************
+ *
+ * Local Function Prototypes
+ *
+ ******************************************************************************/
+
+static void FreeResources(struct SK_NET_DEVICE *dev);
+static int SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC);
+static SK_BOOL BoardAllocMem(SK_AC *pAC);
+static void BoardFreeMem(SK_AC *pAC);
+static void BoardInitMem(SK_AC *pAC);
+static void SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL);
+static SkIsrRetVar SkGeIsr(int irq, void *dev_id);
+static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id);
+static int SkGeOpen(struct SK_NET_DEVICE *dev);
+static int SkGeClose(struct SK_NET_DEVICE *dev);
+static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p);
+static void SkGeSetRxMode(struct SK_NET_DEVICE *dev);
+static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev);
+static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd);
+static void GetConfiguration(SK_AC*);
+static int XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
+static void FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
+static void FillRxRing(SK_AC*, RX_PORT*);
+static SK_BOOL FillRxDescriptor(SK_AC*, RX_PORT*);
+static void ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL);
+static void ClearAndStartRx(SK_AC*, int);
+static void ClearTxIrq(SK_AC*, int, int);
+static void ClearRxRing(SK_AC*, RX_PORT*);
+static void ClearTxRing(SK_AC*, TX_PORT*);
+static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu);
+static void PortReInitBmu(SK_AC*, int);
+static int SkGeIocMib(DEV_NET*, unsigned int, int);
+static int SkGeInitPCI(SK_AC *pAC);
+static void StartDrvCleanupTimer(SK_AC *pAC);
+static void StopDrvCleanupTimer(SK_AC *pAC);
+static int XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*);
+
+#ifdef SK_DIAG_SUPPORT
+static SK_U32 ParseDeviceNbrFromSlotName(const char *SlotName);
+static int SkDrvInitAdapter(SK_AC *pAC, int devNbr);
+static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr);
+#endif
+
+/*******************************************************************************
+ *
+ * Extern Function Prototypes
+ *
+ ******************************************************************************/
+extern void SkDimEnableModerationIfNeeded(SK_AC *pAC);
+extern void SkDimDisplayModerationSettings(SK_AC *pAC);
+extern void SkDimStartModerationTimer(SK_AC *pAC);
+extern void SkDimModerate(SK_AC *pAC);
+extern void SkGeBlinkTimer(unsigned long data);
+
+#ifdef DEBUG
+static void DumpMsg(struct sk_buff*, char*);
+static void DumpData(char*, int);
+static void DumpLong(char*, int);
+#endif
+
+/* global variables *********************************************************/
+static SK_BOOL DoPrintInterfaceChange = SK_TRUE;
+extern const struct ethtool_ops SkGeEthtoolOps;
+
+/* local variables **********************************************************/
+static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
+static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
+
+/*****************************************************************************
+ *
+ * SkPciWriteCfgDWord - write a 32 bit value to pci config space
+ *
+ * Description:
+ * This routine writes a 32 bit value to the pci configuration
+ * space.
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+static inline int SkPciWriteCfgDWord(
+SK_AC *pAC, /* Adapter Control structure pointer */
+int PciAddr, /* PCI register address */
+SK_U32 Val) /* pointer to store the read value */
+{
+ pci_write_config_dword(pAC->PciDev, PciAddr, Val);
+ return(0);
+} /* SkPciWriteCfgDWord */
+
+/*****************************************************************************
+ *
+ * SkGeInitPCI - Init the PCI resources
+ *
+ * Description:
+ * This function initialize the PCI resources and IO
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+static __devinit int SkGeInitPCI(SK_AC *pAC)
+{
+ struct SK_NET_DEVICE *dev = pAC->dev[0];
+ struct pci_dev *pdev = pAC->PciDev;
+ int retval;
+
+ dev->mem_start = pci_resource_start (pdev, 0);
+ pci_set_master(pdev);
+
+ retval = pci_request_regions(pdev, "sk98lin");
+ if (retval)
+ goto out;
+
+#ifdef SK_BIG_ENDIAN
+ /*
+ * On big endian machines, we use the adapter's aibility of
+ * reading the descriptors as big endian.
+ */
+ {
+ SK_U32 our2;
+ SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2);
+ our2 |= PCI_REV_DESC;
+ SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2);
+ }
+#endif
+
+ /*
+ * Remap the regs into kernel space.
+ */
+ pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000);
+ if (!pAC->IoBase) {
+ retval = -EIO;
+ goto out_release;
+ }
+
+ return 0;
+
+ out_release:
+ pci_release_regions(pdev);
+ out:
+ return retval;
+}
+
+
+/*****************************************************************************
+ *
+ * FreeResources - release resources allocated for adapter
+ *
+ * Description:
+ * This function releases the IRQ, unmaps the IO and
+ * frees the desriptor ring.
+ *
+ * Returns: N/A
+ *
+ */
+static void FreeResources(struct SK_NET_DEVICE *dev)
+{
+SK_U32 AllocFlag;
+DEV_NET *pNet;
+SK_AC *pAC;
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+ AllocFlag = pAC->AllocFlag;
+ if (pAC->PciDev) {
+ pci_release_regions(pAC->PciDev);
+ }
+ if (AllocFlag & SK_ALLOC_IRQ) {
+ free_irq(dev->irq, dev);
+ }
+ if (pAC->IoBase) {
+ iounmap(pAC->IoBase);
+ }
+ if (pAC->pDescrMem) {
+ BoardFreeMem(pAC);
+ }
+
+} /* FreeResources */
+
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
+MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
+MODULE_LICENSE("GPL");
+
+#ifdef LINK_SPEED_A
+static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef LINK_SPEED_B
+static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_A
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A;
+#else
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_A
+static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A;
+#else
+static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_A
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A;
+#else
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_A
+static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A;
+#else
+static char *Role_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_B
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B;
+#else
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_B
+static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B;
+#else
+static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_B
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B;
+#else
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_B
+static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B;
+#else
+static char *Role_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef CON_TYPE
+static char *ConType[SK_MAX_CARD_PARAM] = CON_TYPE;
+#else
+static char *ConType[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef PREF_PORT
+static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT;
+#else
+static char *PrefPort[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef RLMT_MODE
+static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE;
+#else
+static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+static int IntsPerSec[SK_MAX_CARD_PARAM];
+static char *Moderation[SK_MAX_CARD_PARAM];
+static char *ModerationMask[SK_MAX_CARD_PARAM];
+static char *AutoSizing[SK_MAX_CARD_PARAM];
+static char *Stats[SK_MAX_CARD_PARAM];
+
+module_param_array(Speed_A, charp, NULL, 0);
+module_param_array(Speed_B, charp, NULL, 0);
+module_param_array(AutoNeg_A, charp, NULL, 0);
+module_param_array(AutoNeg_B, charp, NULL, 0);
+module_param_array(DupCap_A, charp, NULL, 0);
+module_param_array(DupCap_B, charp, NULL, 0);
+module_param_array(FlowCtrl_A, charp, NULL, 0);
+module_param_array(FlowCtrl_B, charp, NULL, 0);
+module_param_array(Role_A, charp, NULL, 0);
+module_param_array(Role_B, charp, NULL, 0);
+module_param_array(ConType, charp, NULL, 0);
+module_param_array(PrefPort, charp, NULL, 0);
+module_param_array(RlmtMode, charp, NULL, 0);
+/* used for interrupt moderation */
+module_param_array(IntsPerSec, int, NULL, 0);
+module_param_array(Moderation, charp, NULL, 0);
+module_param_array(Stats, charp, NULL, 0);
+module_param_array(ModerationMask, charp, NULL, 0);
+module_param_array(AutoSizing, charp, NULL, 0);
+
+/*****************************************************************************
+ *
+ * SkGeBoardInit - do level 0 and 1 initialization
+ *
+ * Description:
+ * This function prepares the board hardware for running. The desriptor
+ * ring is set up, the IRQ is allocated and the configuration settings
+ * are examined.
+ *
+ * Returns:
+ * 0, if everything is ok
+ * !=0, on error
+ */
+static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+{
+short i;
+unsigned long Flags;
+char *DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */
+char *VerStr = VER_STRING;
+int Ret; /* return code of request_irq */
+SK_BOOL DualNet;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("IoBase: %08lX\n", (unsigned long)pAC->IoBase));
+ for (i=0; i<SK_MAX_MACS; i++) {
+ pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0];
+ pAC->TxPort[i][0].PortIndex = i;
+ pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i];
+ pAC->RxPort[i].PortIndex = i;
+ }
+
+ /* Initialize the mutexes */
+ for (i=0; i<SK_MAX_MACS; i++) {
+ spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock);
+ spin_lock_init(&pAC->RxPort[i].RxDesRingLock);
+ }
+ spin_lock_init(&pAC->SlowPathLock);
+
+ /* setup phy_id blink timer */
+ pAC->BlinkTimer.function = SkGeBlinkTimer;
+ pAC->BlinkTimer.data = (unsigned long) dev;
+ init_timer(&pAC->BlinkTimer);
+
+ /* level 0 init common modules here */
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ /* Does a RESET on board ...*/
+ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) {
+ printk("HWInit (0) failed.\n");
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ return -EIO;
+ }
+ SkI2cInit( pAC, pAC->IoBase, SK_INIT_DATA);
+ SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA);
+ SkPnmiInit( pAC, pAC->IoBase, SK_INIT_DATA);
+ SkAddrInit( pAC, pAC->IoBase, SK_INIT_DATA);
+ SkRlmtInit( pAC, pAC->IoBase, SK_INIT_DATA);
+ SkTimerInit(pAC, pAC->IoBase, SK_INIT_DATA);
+
+ pAC->BoardLevel = SK_INIT_DATA;
+ pAC->RxBufSize = ETH_BUF_SIZE;
+
+ SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString);
+ SK_PNMI_SET_DRIVER_VER(pAC, VerStr);
+
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ /* level 1 init common modules here (HW init) */
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
+ printk("sk98lin: HWInit (1) failed.\n");
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ return -EIO;
+ }
+ SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
+ SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO);
+
+ /* Set chipset type support */
+ pAC->ChipsetType = 0;
+ if ((pAC->GIni.GIChipId == CHIP_ID_YUKON) ||
+ (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE)) {
+ pAC->ChipsetType = 1;
+ }
+
+ GetConfiguration(pAC);
+ if (pAC->RlmtNets == 2) {
+ pAC->GIni.GIPortUsage = SK_MUL_LINK;
+ }
+
+ pAC->BoardLevel = SK_INIT_IO;
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ if (pAC->GIni.GIMacsFound == 2) {
+ Ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+ } else if (pAC->GIni.GIMacsFound == 1) {
+ Ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED,
+ "sk98lin", dev);
+ } else {
+ printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
+ pAC->GIni.GIMacsFound);
+ return -EIO;
+ }
+
+ if (Ret) {
+ printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n",
+ dev->irq);
+ return Ret;
+ }
+ pAC->AllocFlag |= SK_ALLOC_IRQ;
+
+ /* Alloc memory for this board (Mem for RxD/TxD) : */
+ if(!BoardAllocMem(pAC)) {
+ printk("No memory for descriptor rings.\n");
+ return -ENOMEM;
+ }
+
+ BoardInitMem(pAC);
+ /* tschilling: New common function with minimum size check. */
+ DualNet = SK_FALSE;
+ if (pAC->RlmtNets == 2) {
+ DualNet = SK_TRUE;
+ }
+
+ if (SkGeInitAssignRamToQueues(
+ pAC,
+ pAC->ActivePort,
+ DualNet)) {
+ BoardFreeMem(pAC);
+ printk("sk98lin: SkGeInitAssignRamToQueues failed.\n");
+ return -EIO;
+ }
+
+ return (0);
+} /* SkGeBoardInit */
+
+
+/*****************************************************************************
+ *
+ * BoardAllocMem - allocate the memory for the descriptor rings
+ *
+ * Description:
+ * This function allocates the memory for all descriptor rings.
+ * Each ring is aligned for the desriptor alignment and no ring
+ * has a 4 GByte boundary in it (because the upper 32 bit must
+ * be constant for all descriptiors in one rings).
+ *
+ * Returns:
+ * SK_TRUE, if all memory could be allocated
+ * SK_FALSE, if not
+ */
+static __devinit SK_BOOL BoardAllocMem(SK_AC *pAC)
+{
+caddr_t pDescrMem; /* pointer to descriptor memory area */
+size_t AllocLength; /* length of complete descriptor area */
+int i; /* loop counter */
+unsigned long BusAddr;
+
+
+ /* rings plus one for alignment (do not cross 4 GB boundary) */
+ /* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */
+#if (BITS_PER_LONG == 32)
+ AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+ AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+ + RX_RING_SIZE + 8;
+#endif
+
+ pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength,
+ &pAC->pDescrMemDMA);
+
+ if (pDescrMem == NULL) {
+ return (SK_FALSE);
+ }
+ pAC->pDescrMem = pDescrMem;
+ BusAddr = (unsigned long) pAC->pDescrMemDMA;
+
+ /* Descriptors need 8 byte alignment, and this is ensured
+ * by pci_alloc_consistent.
+ */
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+ ("TX%d/A: pDescrMem: %lX, PhysDescrMem: %lX\n",
+ i, (unsigned long) pDescrMem,
+ BusAddr));
+ pAC->TxPort[i][0].pTxDescrRing = pDescrMem;
+ pAC->TxPort[i][0].VTxDescrRing = BusAddr;
+ pDescrMem += TX_RING_SIZE;
+ BusAddr += TX_RING_SIZE;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+ ("RX%d: pDescrMem: %lX, PhysDescrMem: %lX\n",
+ i, (unsigned long) pDescrMem,
+ (unsigned long)BusAddr));
+ pAC->RxPort[i].pRxDescrRing = pDescrMem;
+ pAC->RxPort[i].VRxDescrRing = BusAddr;
+ pDescrMem += RX_RING_SIZE;
+ BusAddr += RX_RING_SIZE;
+ } /* for */
+
+ return (SK_TRUE);
+} /* BoardAllocMem */
+
+
+/****************************************************************************
+ *
+ * BoardFreeMem - reverse of BoardAllocMem
+ *
+ * Description:
+ * Free all memory allocated in BoardAllocMem: adapter context,
+ * descriptor rings, locks.
+ *
+ * Returns: N/A
+ */
+static void BoardFreeMem(
+SK_AC *pAC)
+{
+size_t AllocLength; /* length of complete descriptor area */
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("BoardFreeMem\n"));
+#if (BITS_PER_LONG == 32)
+ AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+ AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+ + RX_RING_SIZE + 8;
+#endif
+
+ pci_free_consistent(pAC->PciDev, AllocLength,
+ pAC->pDescrMem, pAC->pDescrMemDMA);
+ pAC->pDescrMem = NULL;
+} /* BoardFreeMem */
+
+
+/*****************************************************************************
+ *
+ * BoardInitMem - initiate the descriptor rings
+ *
+ * Description:
+ * This function sets the descriptor rings up in memory.
+ * The adapter is initialized with the descriptor start addresses.
+ *
+ * Returns: N/A
+ */
+static __devinit void BoardInitMem(SK_AC *pAC)
+{
+int i; /* loop counter */
+int RxDescrSize; /* the size of a rx descriptor rounded up to alignment*/
+int TxDescrSize; /* the size of a tx descriptor rounded up to alignment*/
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("BoardInitMem\n"));
+
+ RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+ pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize;
+ TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+ pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize;
+
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ SetupRing(
+ pAC,
+ pAC->TxPort[i][0].pTxDescrRing,
+ pAC->TxPort[i][0].VTxDescrRing,
+ (RXD**)&pAC->TxPort[i][0].pTxdRingHead,
+ (RXD**)&pAC->TxPort[i][0].pTxdRingTail,
+ (RXD**)&pAC->TxPort[i][0].pTxdRingPrev,
+ &pAC->TxPort[i][0].TxdRingFree,
+ SK_TRUE);
+ SetupRing(
+ pAC,
+ pAC->RxPort[i].pRxDescrRing,
+ pAC->RxPort[i].VRxDescrRing,
+ &pAC->RxPort[i].pRxdRingHead,
+ &pAC->RxPort[i].pRxdRingTail,
+ &pAC->RxPort[i].pRxdRingPrev,
+ &pAC->RxPort[i].RxdRingFree,
+ SK_FALSE);
+ }
+} /* BoardInitMem */
+
+
+/*****************************************************************************
+ *
+ * SetupRing - create one descriptor ring
+ *
+ * Description:
+ * This function creates one descriptor ring in the given memory area.
+ * The head, tail and number of free descriptors in the ring are set.
+ *
+ * Returns:
+ * none
+ */
+static void SetupRing(
+SK_AC *pAC,
+void *pMemArea, /* a pointer to the memory area for the ring */
+uintptr_t VMemArea, /* the virtual bus address of the memory area */
+RXD **ppRingHead, /* address where the head should be written */
+RXD **ppRingTail, /* address where the tail should be written */
+RXD **ppRingPrev, /* address where the tail should be written */
+int *pRingFree, /* address where the # of free descr. goes */
+SK_BOOL IsTx) /* flag: is this a tx ring */
+{
+int i; /* loop counter */
+int DescrSize; /* the size of a descriptor rounded up to alignment*/
+int DescrNum; /* number of descriptors per ring */
+RXD *pDescr; /* pointer to a descriptor (receive or transmit) */
+RXD *pNextDescr; /* pointer to the next descriptor */
+RXD *pPrevDescr; /* pointer to the previous descriptor */
+uintptr_t VNextDescr; /* the virtual bus address of the next descriptor */
+
+ if (IsTx == SK_TRUE) {
+ DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) *
+ DESCR_ALIGN;
+ DescrNum = TX_RING_SIZE / DescrSize;
+ } else {
+ DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) *
+ DESCR_ALIGN;
+ DescrNum = RX_RING_SIZE / DescrSize;
+ }
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+ ("Descriptor size: %d Descriptor Number: %d\n",
+ DescrSize,DescrNum));
+
+ pDescr = (RXD*) pMemArea;
+ pPrevDescr = NULL;
+ pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+ VNextDescr = VMemArea + DescrSize;
+ for(i=0; i<DescrNum; i++) {
+ /* set the pointers right */
+ pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
+ pDescr->pNextRxd = pNextDescr;
+ if (!IsTx) pDescr->TcpSumStarts = ETH_HLEN << 16 | ETH_HLEN;
+
+ /* advance one step */
+ pPrevDescr = pDescr;
+ pDescr = pNextDescr;
+ pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+ VNextDescr += DescrSize;
+ }
+ pPrevDescr->pNextRxd = (RXD*) pMemArea;
+ pPrevDescr->VNextRxd = VMemArea;
+ pDescr = (RXD*) pMemArea;
+ *ppRingHead = (RXD*) pMemArea;
+ *ppRingTail = *ppRingHead;
+ *ppRingPrev = pPrevDescr;
+ *pRingFree = DescrNum;
+} /* SetupRing */
+
+
+/*****************************************************************************
+ *
+ * PortReInitBmu - re-initiate the descriptor rings for one port
+ *
+ * Description:
+ * This function reinitializes the descriptor rings of one port
+ * in memory. The port must be stopped before.
+ * The HW is initialized with the descriptor start addresses.
+ *
+ * Returns:
+ * none
+ */
+static void PortReInitBmu(
+SK_AC *pAC, /* pointer to adapter context */
+int PortIndex) /* index of the port for which to re-init */
+{
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("PortReInitBmu "));
+
+ /* set address of first descriptor of ring in BMU */
+ SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_L,
+ (uint32_t)(((caddr_t)
+ (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+ pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+ pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) &
+ 0xFFFFFFFF));
+ SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_H,
+ (uint32_t)(((caddr_t)
+ (pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+ pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+ pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32));
+ SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_L,
+ (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+ pAC->RxPort[PortIndex].pRxDescrRing +
+ pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF));
+ SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_H,
+ (uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+ pAC->RxPort[PortIndex].pRxDescrRing +
+ pAC->RxPort[PortIndex].VRxDescrRing) >> 32));
+} /* PortReInitBmu */
+
+
+/****************************************************************************
+ *
+ * SkGeIsr - handle adapter interrupts
+ *
+ * Description:
+ * The interrupt routine is called when the network adapter
+ * generates an interrupt. It may also be called if another device
+ * shares this interrupt vector with the driver.
+ *
+ * Returns: N/A
+ *
+ */
+static SkIsrRetVar SkGeIsr(int irq, void *dev_id)
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET *pNet;
+SK_AC *pAC;
+SK_U32 IntSrc; /* interrupts source register contents */
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+ /*
+ * Check and process if its our interrupt
+ */
+ SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+ if (IntSrc == 0) {
+ return SkIsrRetNone;
+ }
+
+ while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+ if (IntSrc & IS_IRQ_SW) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("Software IRQ\n"));
+ }
+#endif
+ if (IntSrc & IS_R1_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF RX1 IRQ\n"));
+ ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+ SK_PNMI_CNT_RX_INTR(pAC, 0);
+ }
+ if (IntSrc & IS_R2_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF RX2 IRQ\n"));
+ ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+ SK_PNMI_CNT_RX_INTR(pAC, 1);
+ }
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+ if (IntSrc & IS_XA1_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF AS TX1 IRQ\n"));
+ SK_PNMI_CNT_TX_INTR(pAC, 0);
+ spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+ FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+ spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+ }
+ if (IntSrc & IS_XA2_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF AS TX2 IRQ\n"));
+ SK_PNMI_CNT_TX_INTR(pAC, 1);
+ spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+ FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
+ spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+ }
+#if 0 /* only if sync. queues used */
+ if (IntSrc & IS_XS1_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF SY TX1 IRQ\n"));
+ SK_PNMI_CNT_TX_INTR(pAC, 1);
+ spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+ FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+ spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+ ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+ }
+ if (IntSrc & IS_XS2_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF SY TX2 IRQ\n"));
+ SK_PNMI_CNT_TX_INTR(pAC, 1);
+ spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+ FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
+ spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+ ClearTxIrq(pAC, 1, TX_PRIO_HIGH);
+ }
+#endif
+#endif
+
+ /* do all IO at once */
+ if (IntSrc & IS_R1_F)
+ ClearAndStartRx(pAC, 0);
+ if (IntSrc & IS_R2_F)
+ ClearAndStartRx(pAC, 1);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+ if (IntSrc & IS_XA1_F)
+ ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+ if (IntSrc & IS_XA2_F)
+ ClearTxIrq(pAC, 1, TX_PRIO_LOW);
+#endif
+ SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+ } /* while (IntSrc & IRQ_MASK != 0) */
+
+ IntSrc &= pAC->GIni.GIValIrqMask;
+ if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+ ("SPECIAL IRQ DP-Cards => %x\n", IntSrc));
+ pAC->CheckQueue = SK_FALSE;
+ spin_lock(&pAC->SlowPathLock);
+ if (IntSrc & SPECIAL_IRQS)
+ SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+ SkEventDispatcher(pAC, pAC->IoBase);
+ spin_unlock(&pAC->SlowPathLock);
+ }
+ /*
+ * do it all again is case we cleared an interrupt that
+ * came in after handling the ring (OUTs may be delayed
+ * in hardware buffers, but are through after IN)
+ *
+ * rroesler: has been commented out and shifted to
+ * SkGeDrvEvent(), because it is timer
+ * guarded now
+ *
+ ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+ ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+ */
+
+ if (pAC->CheckQueue) {
+ pAC->CheckQueue = SK_FALSE;
+ spin_lock(&pAC->SlowPathLock);
+ SkEventDispatcher(pAC, pAC->IoBase);
+ spin_unlock(&pAC->SlowPathLock);
+ }
+
+ /* IRQ is processed - Enable IRQs again*/
+ SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+
+ return SkIsrRetHandled;
+} /* SkGeIsr */
+
+
+/****************************************************************************
+ *
+ * SkGeIsrOnePort - handle adapter interrupts for single port adapter
+ *
+ * Description:
+ * The interrupt routine is called when the network adapter
+ * generates an interrupt. It may also be called if another device
+ * shares this interrupt vector with the driver.
+ * This is the same as above, but handles only one port.
+ *
+ * Returns: N/A
+ *
+ */
+static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id)
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET *pNet;
+SK_AC *pAC;
+SK_U32 IntSrc; /* interrupts source register contents */
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+ /*
+ * Check and process if its our interrupt
+ */
+ SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+ if (IntSrc == 0) {
+ return SkIsrRetNone;
+ }
+
+ while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+ if (IntSrc & IS_IRQ_SW) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("Software IRQ\n"));
+ }
+#endif
+ if (IntSrc & IS_R1_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF RX1 IRQ\n"));
+ ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+ SK_PNMI_CNT_RX_INTR(pAC, 0);
+ }
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+ if (IntSrc & IS_XA1_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF AS TX1 IRQ\n"));
+ SK_PNMI_CNT_TX_INTR(pAC, 0);
+ spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+ FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+ spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+ }
+#if 0 /* only if sync. queues used */
+ if (IntSrc & IS_XS1_F) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_INT_SRC,
+ ("EOF SY TX1 IRQ\n"));
+ SK_PNMI_CNT_TX_INTR(pAC, 0);
+ spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+ FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+ spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+ ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+ }
+#endif
+#endif
+
+ /* do all IO at once */
+ if (IntSrc & IS_R1_F)
+ ClearAndStartRx(pAC, 0);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+ if (IntSrc & IS_XA1_F)
+ ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+#endif
+ SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+ } /* while (IntSrc & IRQ_MASK != 0) */
+
+ IntSrc &= pAC->GIni.GIValIrqMask;
+ if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+ ("SPECIAL IRQ SP-Cards => %x\n", IntSrc));
+ pAC->CheckQueue = SK_FALSE;
+ spin_lock(&pAC->SlowPathLock);
+ if (IntSrc & SPECIAL_IRQS)
+ SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+ SkEventDispatcher(pAC, pAC->IoBase);
+ spin_unlock(&pAC->SlowPathLock);
+ }
+ /*
+ * do it all again is case we cleared an interrupt that
+ * came in after handling the ring (OUTs may be delayed
+ * in hardware buffers, but are through after IN)
+ *
+ * rroesler: has been commented out and shifted to
+ * SkGeDrvEvent(), because it is timer
+ * guarded now
+ *
+ ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+ */
+
+ /* IRQ is processed - Enable IRQs again*/
+ SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+
+ return SkIsrRetHandled;
+} /* SkGeIsrOnePort */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/****************************************************************************
+ *
+ * SkGePollController - polling receive, for netconsole
+ *
+ * Description:
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ *
+ * Returns: N/A
+ */
+static void SkGePollController(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ SkGeIsr(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+/****************************************************************************
+ *
+ * SkGeOpen - handle start of initialized adapter
+ *
+ * Description:
+ * This function starts the initialized adapter.
+ * The board level variable is set and the adapter is
+ * brought to full functionality.
+ * The device flags are set for operation.
+ * Do all necessary level 2 initialization, enable interrupts and
+ * give start command to RLMT.
+ *
+ * Returns:
+ * 0 on success
+ * != 0 on error
+ */
+static int SkGeOpen(
+struct SK_NET_DEVICE *dev)
+{
+ DEV_NET *pNet;
+ SK_AC *pAC;
+ unsigned long Flags; /* for spin lock */
+ int i;
+ SK_EVPARA EvPara; /* an event parameter union */
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC));
+
+#ifdef SK_DIAG_SUPPORT
+ if (pAC->DiagModeActive == DIAG_ACTIVE) {
+ if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+ return (-1); /* still in use by diag; deny actions */
+ }
+ }
+#endif
+
+ /* Set blink mode */
+ if ((pAC->PciDev->vendor == 0x1186) || (pAC->PciDev->vendor == 0x11ab ))
+ pAC->GIni.GILedBlinkCtrl = OEM_CONFIG_VALUE;
+
+ if (pAC->BoardLevel == SK_INIT_DATA) {
+ /* level 1 init common modules here */
+ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
+ printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name);
+ return (-1);
+ }
+ SkI2cInit (pAC, pAC->IoBase, SK_INIT_IO);
+ SkEventInit (pAC, pAC->IoBase, SK_INIT_IO);
+ SkPnmiInit (pAC, pAC->IoBase, SK_INIT_IO);
+ SkAddrInit (pAC, pAC->IoBase, SK_INIT_IO);
+ SkRlmtInit (pAC, pAC->IoBase, SK_INIT_IO);
+ SkTimerInit (pAC, pAC->IoBase, SK_INIT_IO);
+ pAC->BoardLevel = SK_INIT_IO;
+ }
+
+ if (pAC->BoardLevel != SK_INIT_RUN) {
+ /* tschilling: Level 2 init modules here, check return value. */
+ if (SkGeInit(pAC, pAC->IoBase, SK_INIT_RUN) != 0) {
+ printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name);
+ return (-1);
+ }
+ SkI2cInit (pAC, pAC->IoBase, SK_INIT_RUN);
+ SkEventInit (pAC, pAC->IoBase, SK_INIT_RUN);
+ SkPnmiInit (pAC, pAC->IoBase, SK_INIT_RUN);
+ SkAddrInit (pAC, pAC->IoBase, SK_INIT_RUN);
+ SkRlmtInit (pAC, pAC->IoBase, SK_INIT_RUN);
+ SkTimerInit (pAC, pAC->IoBase, SK_INIT_RUN);
+ pAC->BoardLevel = SK_INIT_RUN;
+ }
+
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ /* Enable transmit descriptor polling. */
+ SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+ FillRxRing(pAC, &pAC->RxPort[i]);
+ }
+ SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+ StartDrvCleanupTimer(pAC);
+ SkDimEnableModerationIfNeeded(pAC);
+ SkDimDisplayModerationSettings(pAC);
+
+ pAC->GIni.GIValIrqMask &= IRQ_MASK;
+
+ /* enable Interrupts */
+ SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+ SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+ if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) {
+ EvPara.Para32[0] = pAC->RlmtNets;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+ EvPara);
+ EvPara.Para32[0] = pAC->RlmtMode;
+ EvPara.Para32[1] = 0;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE,
+ EvPara);
+ }
+
+ EvPara.Para32[0] = pNet->NetNr;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+ SkEventDispatcher(pAC, pAC->IoBase);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ pAC->MaxPorts++;
+
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeOpen suceeded\n"));
+
+ return (0);
+} /* SkGeOpen */
+
+
+/****************************************************************************
+ *
+ * SkGeClose - Stop initialized adapter
+ *
+ * Description:
+ * Close initialized adapter.
+ *
+ * Returns:
+ * 0 - on success
+ * error code - on error
+ */
+static int SkGeClose(
+struct SK_NET_DEVICE *dev)
+{
+ DEV_NET *pNet;
+ DEV_NET *newPtrNet;
+ SK_AC *pAC;
+
+ unsigned long Flags; /* for spin lock */
+ int i;
+ int PortIdx;
+ SK_EVPARA EvPara;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC));
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+#ifdef SK_DIAG_SUPPORT
+ if (pAC->DiagModeActive == DIAG_ACTIVE) {
+ if (pAC->DiagFlowCtrl == SK_FALSE) {
+ /*
+ ** notify that the interface which has been closed
+ ** by operator interaction must not be started up
+ ** again when the DIAG has finished.
+ */
+ newPtrNet = netdev_priv(pAC->dev[0]);
+ if (newPtrNet == pNet) {
+ pAC->WasIfUp[0] = SK_FALSE;
+ } else {
+ pAC->WasIfUp[1] = SK_FALSE;
+ }
+ return 0; /* return to system everything is fine... */
+ } else {
+ pAC->DiagFlowCtrl = SK_FALSE;
+ }
+ }
+#endif
+
+ netif_stop_queue(dev);
+
+ if (pAC->RlmtNets == 1)
+ PortIdx = pAC->ActivePort;
+ else
+ PortIdx = pNet->NetNr;
+
+ StopDrvCleanupTimer(pAC);
+
+ /*
+ * Clear multicast table, promiscuous mode ....
+ */
+ SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+ SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+ SK_PROM_MODE_NONE);
+
+ if (pAC->MaxPorts == 1) {
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ /* disable interrupts */
+ SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+ EvPara.Para32[0] = pNet->NetNr;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ SkEventDispatcher(pAC, pAC->IoBase);
+ SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+ /* stop the hardware */
+ SkGeDeInit(pAC, pAC->IoBase);
+ pAC->BoardLevel = SK_INIT_DATA;
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ } else {
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ EvPara.Para32[0] = pNet->NetNr;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ SkPnmiEvent(pAC, pAC->IoBase, SK_PNMI_EVT_XMAC_RESET, EvPara);
+ SkEventDispatcher(pAC, pAC->IoBase);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ /* Stop port */
+ spin_lock_irqsave(&pAC->TxPort[pNet->PortNr]
+ [TX_PRIO_LOW].TxDesRingLock, Flags);
+ SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr,
+ SK_STOP_ALL, SK_HARD_RST);
+ spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr]
+ [TX_PRIO_LOW].TxDesRingLock, Flags);
+ }
+
+ if (pAC->RlmtNets == 1) {
+ /* clear all descriptor rings */
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+ ClearRxRing(pAC, &pAC->RxPort[i]);
+ ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+ }
+ } else {
+ /* clear port descriptor rings */
+ ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE);
+ ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]);
+ ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]);
+ }
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeClose: done "));
+
+ SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA));
+ SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct),
+ sizeof(SK_PNMI_STRUCT_DATA));
+
+ pAC->MaxPorts--;
+
+ return (0);
+} /* SkGeClose */
+
+
+/*****************************************************************************
+ *
+ * SkGeXmit - Linux frame transmit function
+ *
+ * Description:
+ * The system calls this function to send frames onto the wire.
+ * It puts the frame in the tx descriptor ring. If the ring is
+ * full then, the 'tbusy' flag is set.
+ *
+ * Returns:
+ * 0, if everything is ok
+ * !=0, on error
+ * WARNING: returning 1 in 'tbusy' case caused system crashes (double
+ * allocated skb's) !!!
+ */
+static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev)
+{
+DEV_NET *pNet;
+SK_AC *pAC;
+int Rc; /* return code of XmitFrame */
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+ if ((!skb_shinfo(skb)->nr_frags) ||
+ (pAC->GIni.GIChipId == CHIP_ID_GENESIS)) {
+ /* Don't activate scatter-gather and hardware checksum */
+
+ if (pAC->RlmtNets == 2)
+ Rc = XmitFrame(
+ pAC,
+ &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+ skb);
+ else
+ Rc = XmitFrame(
+ pAC,
+ &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+ skb);
+ } else {
+ /* scatter-gather and hardware TCP checksumming anabled*/
+ if (pAC->RlmtNets == 2)
+ Rc = XmitFrameSG(
+ pAC,
+ &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+ skb);
+ else
+ Rc = XmitFrameSG(
+ pAC,
+ &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+ skb);
+ }
+
+ /* Transmitter out of resources? */
+ if (Rc <= 0) {
+ netif_stop_queue(dev);
+ }
+
+ /* If not taken, give buffer ownership back to the
+ * queueing layer.
+ */
+ if (Rc < 0)
+ return (1);
+
+ dev->trans_start = jiffies;
+ return (0);
+} /* SkGeXmit */
+
+
+/*****************************************************************************
+ *
+ * XmitFrame - fill one socket buffer into the transmit ring
+ *
+ * Description:
+ * This function puts a message into the transmit descriptor ring
+ * if there is a descriptors left.
+ * Linux skb's consist of only one continuous buffer.
+ * The first step locks the ring. It is held locked
+ * all time to avoid problems with SWITCH_../PORT_RESET.
+ * Then the descriptoris allocated.
+ * The second part is linking the buffer to the descriptor.
+ * At the very last, the Control field of the descriptor
+ * is made valid for the BMU and a start TX command is given
+ * if necessary.
+ *
+ * Returns:
+ * > 0 - on succes: the number of bytes in the message
+ * = 0 - on resource shortage: this frame sent or dropped, now
+ * the ring is full ( -> set tbusy)
+ * < 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrame(
+SK_AC *pAC, /* pointer to adapter context */
+TX_PORT *pTxPort, /* pointer to struct of port to send to */
+struct sk_buff *pMessage) /* pointer to send-message */
+{
+ TXD *pTxd; /* the rxd to fill */
+ TXD *pOldTxd;
+ unsigned long Flags;
+ SK_U64 PhysAddr;
+ int BytesSend = pMessage->len;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X"));
+
+ spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+ FreeTxDescriptors(pAC, pTxPort);
+#endif
+ if (pTxPort->TxdRingFree == 0) {
+ /*
+ ** no enough free descriptors in ring at the moment.
+ ** Maybe free'ing some old one help?
+ */
+ FreeTxDescriptors(pAC, pTxPort);
+ if (pTxPort->TxdRingFree == 0) {
+ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+ SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_TX_PROGRESS,
+ ("XmitFrame failed\n"));
+ /*
+ ** the desired message can not be sent
+ ** Because tbusy seems to be set, the message
+ ** should not be freed here. It will be used
+ ** by the scheduler of the ethernet handler
+ */
+ return (-1);
+ }
+ }
+
+ /*
+ ** If the passed socket buffer is of smaller MTU-size than 60,
+ ** copy everything into new buffer and fill all bytes between
+ ** the original packet end and the new packet end of 60 with 0x00.
+ ** This is to resolve faulty padding by the HW with 0xaa bytes.
+ */
+ if (BytesSend < C_LEN_ETHERNET_MINSIZE) {
+ if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) {
+ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+ return 0;
+ }
+ pMessage->len = C_LEN_ETHERNET_MINSIZE;
+ }
+
+ /*
+ ** advance head counter behind descriptor needed for this frame,
+ ** so that needed descriptor is reserved from that on. The next
+ ** action will be to add the passed buffer to the TX-descriptor
+ */
+ pTxd = pTxPort->pTxdRingHead;
+ pTxPort->pTxdRingHead = pTxd->pNextTxd;
+ pTxPort->TxdRingFree--;
+
+#ifdef SK_DUMP_TX
+ DumpMsg(pMessage, "XmitFrame");
+#endif
+
+ /*
+ ** First step is to map the data to be sent via the adapter onto
+ ** the DMA memory. Kernel 2.2 uses virt_to_bus(), but kernels 2.4
+ ** and 2.6 need to use pci_map_page() for that mapping.
+ */
+ PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+ virt_to_page(pMessage->data),
+ ((unsigned long) pMessage->data & ~PAGE_MASK),
+ pMessage->len,
+ PCI_DMA_TODEVICE);
+ pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+ pTxd->pMBuf = pMessage;
+
+ if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+ u16 hdrlen = skb_transport_offset(pMessage);
+ u16 offset = hdrlen + pMessage->csum_offset;
+
+ if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
+ (pAC->GIni.GIChipRev == 0) &&
+ (pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+ pTxd->TBControl = BMU_TCP_CHECK;
+ } else {
+ pTxd->TBControl = BMU_UDP_CHECK;
+ }
+
+ pTxd->TcpSumOfs = 0;
+ pTxd->TcpSumSt = hdrlen;
+ pTxd->TcpSumWr = offset;
+
+ pTxd->TBControl |= BMU_OWN | BMU_STF |
+ BMU_SW | BMU_EOF |
+#ifdef USE_TX_COMPLETE
+ BMU_IRQ_EOF |
+#endif
+ pMessage->len;
+ } else {
+ pTxd->TBControl = BMU_OWN | BMU_STF | BMU_CHECK |
+ BMU_SW | BMU_EOF |
+#ifdef USE_TX_COMPLETE
+ BMU_IRQ_EOF |
+#endif
+ pMessage->len;
+ }
+
+ /*
+ ** If previous descriptor already done, give TX start cmd
+ */
+ pOldTxd = xchg(&pTxPort->pTxdRingPrev, pTxd);
+ if ((pOldTxd->TBControl & BMU_OWN) == 0) {
+ SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START);
+ }
+
+ /*
+ ** after releasing the lock, the skb may immediately be free'd
+ */
+ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+ if (pTxPort->TxdRingFree != 0) {
+ return (BytesSend);
+ } else {
+ return (0);
+ }
+
+} /* XmitFrame */
+
+/*****************************************************************************
+ *
+ * XmitFrameSG - fill one socket buffer into the transmit ring
+ * (use SG and TCP/UDP hardware checksumming)
+ *
+ * Description:
+ * This function puts a message into the transmit descriptor ring
+ * if there is a descriptors left.
+ *
+ * Returns:
+ * > 0 - on succes: the number of bytes in the message
+ * = 0 - on resource shortage: this frame sent or dropped, now
+ * the ring is full ( -> set tbusy)
+ * < 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrameSG(
+SK_AC *pAC, /* pointer to adapter context */
+TX_PORT *pTxPort, /* pointer to struct of port to send to */
+struct sk_buff *pMessage) /* pointer to send-message */
+{
+
+ TXD *pTxd;
+ TXD *pTxdFst;
+ TXD *pTxdLst;
+ int CurrFrag;
+ int BytesSend;
+ skb_frag_t *sk_frag;
+ SK_U64 PhysAddr;
+ unsigned long Flags;
+ SK_U32 Control;
+
+ spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+ FreeTxDescriptors(pAC, pTxPort);
+#endif
+ if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) {
+ FreeTxDescriptors(pAC, pTxPort);
+ if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) {
+ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+ SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_TX_PROGRESS,
+ ("XmitFrameSG failed - Ring full\n"));
+ /* this message can not be sent now */
+ return(-1);
+ }
+ }
+
+ pTxd = pTxPort->pTxdRingHead;
+ pTxdFst = pTxd;
+ pTxdLst = pTxd;
+ BytesSend = 0;
+
+ /*
+ ** Map the first fragment (header) into the DMA-space
+ */
+ PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+ virt_to_page(pMessage->data),
+ ((unsigned long) pMessage->data & ~PAGE_MASK),
+ skb_headlen(pMessage),
+ PCI_DMA_TODEVICE);
+
+ pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+
+ /*
+ ** Does the HW need to evaluate checksum for TCP or UDP packets?
+ */
+ if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+ u16 hdrlen = skb_transport_offset(pMessage);
+ u16 offset = hdrlen + pMessage->csum_offset;
+
+ Control = BMU_STFWD;
+
+ /*
+ ** We have to use the opcode for tcp here, because the
+ ** opcode for udp is not working in the hardware yet
+ ** (Revision 2.0)
+ */
+ if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
+ (pAC->GIni.GIChipRev == 0) &&
+ (pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+ Control |= BMU_TCP_CHECK;
+ } else {
+ Control |= BMU_UDP_CHECK;
+ }
+
+ pTxd->TcpSumOfs = 0;
+ pTxd->TcpSumSt = hdrlen;
+ pTxd->TcpSumWr = offset;
+ } else
+ Control = BMU_CHECK | BMU_SW;
+
+ pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage);
+
+ pTxd = pTxd->pNextTxd;
+ pTxPort->TxdRingFree--;
+ BytesSend += skb_headlen(pMessage);
+
+ /*
+ ** Browse over all SG fragments and map each of them into the DMA space
+ */
+ for (CurrFrag = 0; CurrFrag < skb_shinfo(pMessage)->nr_frags; CurrFrag++) {
+ sk_frag = &skb_shinfo(pMessage)->frags[CurrFrag];
+ /*
+ ** we already have the proper value in entry
+ */
+ PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+ sk_frag->page,
+ sk_frag->page_offset,
+ sk_frag->size,
+ PCI_DMA_TODEVICE);
+
+ pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+ pTxd->pMBuf = pMessage;
+
+ pTxd->TBControl = Control | BMU_OWN | sk_frag->size;
+
+ /*
+ ** Do we have the last fragment?
+ */
+ if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags ) {
+#ifdef USE_TX_COMPLETE
+ pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF;
+#else
+ pTxd->TBControl |= BMU_EOF;
+#endif
+ pTxdFst->TBControl |= BMU_OWN | BMU_SW;
+ }
+ pTxdLst = pTxd;
+ pTxd = pTxd->pNextTxd;
+ pTxPort->TxdRingFree--;
+ BytesSend += sk_frag->size;
+ }
+
+ /*
+ ** If previous descriptor already done, give TX start cmd
+ */
+ if ((pTxPort->pTxdRingPrev->TBControl & BMU_OWN) == 0) {
+ SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START);
+ }
+
+ pTxPort->pTxdRingPrev = pTxdLst;
+ pTxPort->pTxdRingHead = pTxd;
+
+ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+
+ if (pTxPort->TxdRingFree > 0) {
+ return (BytesSend);
+ } else {
+ return (0);
+ }
+}
+
+/*****************************************************************************
+ *
+ * FreeTxDescriptors - release descriptors from the descriptor ring
+ *
+ * Description:
+ * This function releases descriptors from a transmit ring if they
+ * have been sent by the BMU.
+ * If a descriptors is sent, it can be freed and the message can
+ * be freed, too.
+ * The SOFTWARE controllable bit is used to prevent running around a
+ * completely free ring for ever. If this bit is no set in the
+ * frame (by XmitFrame), this frame has never been sent or is
+ * already freed.
+ * The Tx descriptor ring lock must be held while calling this function !!!
+ *
+ * Returns:
+ * none
+ */
+static void FreeTxDescriptors(
+SK_AC *pAC, /* pointer to the adapter context */
+TX_PORT *pTxPort) /* pointer to destination port structure */
+{
+TXD *pTxd; /* pointer to the checked descriptor */
+TXD *pNewTail; /* pointer to 'end' of the ring */
+SK_U32 Control; /* TBControl field of descriptor */
+SK_U64 PhysAddr; /* address of DMA mapping */
+
+ pNewTail = pTxPort->pTxdRingTail;
+ pTxd = pNewTail;
+ /*
+ ** loop forever; exits if BMU_SW bit not set in start frame
+ ** or BMU_OWN bit set in any frame
+ */
+ while (1) {
+ Control = pTxd->TBControl;
+ if ((Control & BMU_SW) == 0) {
+ /*
+ ** software controllable bit is set in first
+ ** fragment when given to BMU. Not set means that
+ ** this fragment was never sent or is already
+ ** freed ( -> ring completely free now).
+ */
+ pTxPort->pTxdRingTail = pTxd;
+ netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+ return;
+ }
+ if (Control & BMU_OWN) {
+ pTxPort->pTxdRingTail = pTxd;
+ if (pTxPort->TxdRingFree > 0) {
+ netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+ }
+ return;
+ }
+
+ /*
+ ** release the DMA mapping, because until not unmapped
+ ** this buffer is considered being under control of the
+ ** adapter card!
+ */
+ PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
+ PhysAddr |= (SK_U64) pTxd->VDataLow;
+ pci_unmap_page(pAC->PciDev, PhysAddr,
+ pTxd->pMBuf->len,
+ PCI_DMA_TODEVICE);
+
+ if (Control & BMU_EOF)
+ DEV_KFREE_SKB_ANY(pTxd->pMBuf); /* free message */
+
+ pTxPort->TxdRingFree++;
+ pTxd->TBControl &= ~BMU_SW;
+ pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
+ } /* while(forever) */
+} /* FreeTxDescriptors */
+
+/*****************************************************************************
+ *
+ * FillRxRing - fill the receive ring with valid descriptors
+ *
+ * Description:
+ * This function fills the receive ring descriptors with data
+ * segments and makes them valid for the BMU.
+ * The active ring is filled completely, if possible.
+ * The non-active ring is filled only partial to save memory.
+ *
+ * Description of rx ring structure:
+ * head - points to the descriptor which will be used next by the BMU
+ * tail - points to the next descriptor to give to the BMU
+ *
+ * Returns: N/A
+ */
+static void FillRxRing(
+SK_AC *pAC, /* pointer to the adapter context */
+RX_PORT *pRxPort) /* ptr to port struct for which the ring
+ should be filled */
+{
+unsigned long Flags;
+
+ spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+ while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
+ if(!FillRxDescriptor(pAC, pRxPort))
+ break;
+ }
+ spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* FillRxRing */
+
+
+/*****************************************************************************
+ *
+ * FillRxDescriptor - fill one buffer into the receive ring
+ *
+ * Description:
+ * The function allocates a new receive buffer and
+ * puts it into the next descriptor.
+ *
+ * Returns:
+ * SK_TRUE - a buffer was added to the ring
+ * SK_FALSE - a buffer could not be added
+ */
+static SK_BOOL FillRxDescriptor(
+SK_AC *pAC, /* pointer to the adapter context struct */
+RX_PORT *pRxPort) /* ptr to port struct of ring to fill */
+{
+struct sk_buff *pMsgBlock; /* pointer to a new message block */
+RXD *pRxd; /* the rxd to fill */
+SK_U16 Length; /* data fragment length */
+SK_U64 PhysAddr; /* physical address of a rx buffer */
+
+ pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC);
+ if (pMsgBlock == NULL) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_ENTRY,
+ ("%s: Allocation of rx buffer failed !\n",
+ pAC->dev[pRxPort->PortIndex]->name));
+ SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex);
+ return(SK_FALSE);
+ }
+ skb_reserve(pMsgBlock, 2); /* to align IP frames */
+ /* skb allocated ok, so add buffer */
+ pRxd = pRxPort->pRxdRingTail;
+ pRxPort->pRxdRingTail = pRxd->pNextRxd;
+ pRxPort->RxdRingFree--;
+ Length = pAC->RxBufSize;
+ PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+ virt_to_page(pMsgBlock->data),
+ ((unsigned long) pMsgBlock->data &
+ ~PAGE_MASK),
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
+
+ pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+ pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+ pRxd->pMBuf = pMsgBlock;
+ pRxd->RBControl = BMU_OWN |
+ BMU_STF |
+ BMU_IRQ_EOF |
+ BMU_TCP_CHECK |
+ Length;
+ return (SK_TRUE);
+
+} /* FillRxDescriptor */
+
+
+/*****************************************************************************
+ *
+ * ReQueueRxBuffer - fill one buffer back into the receive ring
+ *
+ * Description:
+ * Fill a given buffer back into the rx ring. The buffer
+ * has been previously allocated and aligned, and its phys.
+ * address calculated, so this is no more necessary.
+ *
+ * Returns: N/A
+ */
+static void ReQueueRxBuffer(
+SK_AC *pAC, /* pointer to the adapter context struct */
+RX_PORT *pRxPort, /* ptr to port struct of ring to fill */
+struct sk_buff *pMsg, /* pointer to the buffer */
+SK_U32 PhysHigh, /* phys address high dword */
+SK_U32 PhysLow) /* phys address low dword */
+{
+RXD *pRxd; /* the rxd to fill */
+SK_U16 Length; /* data fragment length */
+
+ pRxd = pRxPort->pRxdRingTail;
+ pRxPort->pRxdRingTail = pRxd->pNextRxd;
+ pRxPort->RxdRingFree--;
+ Length = pAC->RxBufSize;
+
+ pRxd->VDataLow = PhysLow;
+ pRxd->VDataHigh = PhysHigh;
+ pRxd->pMBuf = pMsg;
+ pRxd->RBControl = BMU_OWN |
+ BMU_STF |
+ BMU_IRQ_EOF |
+ BMU_TCP_CHECK |
+ Length;
+ return;
+} /* ReQueueRxBuffer */
+
+/*****************************************************************************
+ *
+ * ReceiveIrq - handle a receive IRQ
+ *
+ * Description:
+ * This function is called when a receive IRQ is set.
+ * It walks the receive descriptor ring and sends up all
+ * frames that are complete.
+ *
+ * Returns: N/A
+ */
+static void ReceiveIrq(
+ SK_AC *pAC, /* pointer to adapter context */
+ RX_PORT *pRxPort, /* pointer to receive port struct */
+ SK_BOOL SlowPathLock) /* indicates if SlowPathLock is needed */
+{
+RXD *pRxd; /* pointer to receive descriptors */
+SK_U32 Control; /* control field of descriptor */
+struct sk_buff *pMsg; /* pointer to message holding frame */
+struct sk_buff *pNewMsg; /* pointer to a new message for copying frame */
+int FrameLength; /* total length of received frame */
+SK_MBUF *pRlmtMbuf; /* ptr to a buffer for giving a frame to rlmt */
+SK_EVPARA EvPara; /* an event parameter union */
+unsigned long Flags; /* for spin lock */
+int PortIndex = pRxPort->PortIndex;
+unsigned int Offset;
+unsigned int NumBytes;
+unsigned int ForRlmt;
+SK_BOOL IsBc;
+SK_BOOL IsMc;
+SK_BOOL IsBadFrame; /* Bad frame */
+
+SK_U32 FrameStat;
+SK_U64 PhysAddr;
+
+rx_start:
+ /* do forever; exit if BMU_OWN found */
+ for ( pRxd = pRxPort->pRxdRingHead ;
+ pRxPort->RxdRingFree < pAC->RxDescrPerRing ;
+ pRxd = pRxd->pNextRxd,
+ pRxPort->pRxdRingHead = pRxd,
+ pRxPort->RxdRingFree ++) {
+
+ /*
+ * For a better understanding of this loop
+ * Go through every descriptor beginning at the head
+ * Please note: the ring might be completely received so the OWN bit
+ * set is not a good crirteria to leave that loop.
+ * Therefore the RingFree counter is used.
+ * On entry of this loop pRxd is a pointer to the Rxd that needs
+ * to be checked next.
+ */
+
+ Control = pRxd->RBControl;
+
+ /* check if this descriptor is ready */
+ if ((Control & BMU_OWN) != 0) {
+ /* this descriptor is not yet ready */
+ /* This is the usual end of the loop */
+ /* We don't need to start the ring again */
+ FillRxRing(pAC, pRxPort);
+ return;
+ }
+ pAC->DynIrqModInfo.NbrProcessedDescr++;
+
+ /* get length of frame and check it */
+ FrameLength = Control & BMU_BBC;
+ if (FrameLength > pAC->RxBufSize) {
+ goto rx_failed;
+ }
+
+ /* check for STF and EOF */
+ if ((Control & (BMU_STF | BMU_EOF)) != (BMU_STF | BMU_EOF)) {
+ goto rx_failed;
+ }
+
+ /* here we have a complete frame in the ring */
+ pMsg = pRxd->pMBuf;
+
+ FrameStat = pRxd->FrameStat;
+
+ /* check for frame length mismatch */
+#define XMR_FS_LEN_SHIFT 18
+#define GMR_FS_LEN_SHIFT 16
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+ if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_RX_PROGRESS,
+ ("skge: Frame length mismatch (%u/%u).\n",
+ FrameLength,
+ (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+ goto rx_failed;
+ }
+ }
+ else {
+ if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_RX_PROGRESS,
+ ("skge: Frame length mismatch (%u/%u).\n",
+ FrameLength,
+ (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+ goto rx_failed;
+ }
+ }
+
+ /* Set Rx Status */
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+ IsBc = (FrameStat & XMR_FS_BC) != 0;
+ IsMc = (FrameStat & XMR_FS_MC) != 0;
+ IsBadFrame = (FrameStat &
+ (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0;
+ } else {
+ IsBc = (FrameStat & GMR_FS_BC) != 0;
+ IsMc = (FrameStat & GMR_FS_MC) != 0;
+ IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) ||
+ ((FrameStat & GMR_FS_RX_OK) == 0));
+ }
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+ ("Received frame of length %d on port %d\n",
+ FrameLength, PortIndex));
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+ ("Number of free rx descriptors: %d\n",
+ pRxPort->RxdRingFree));
+/* DumpMsg(pMsg, "Rx"); */
+
+ if ((Control & BMU_STAT_VAL) != BMU_STAT_VAL || (IsBadFrame)) {
+#if 0
+ (FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) {
+#endif
+ /* there is a receive error in this frame */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_RX_PROGRESS,
+ ("skge: Error in received frame, dropped!\n"
+ "Control: %x\nRxStat: %x\n",
+ Control, FrameStat));
+
+ ReQueueRxBuffer(pAC, pRxPort, pMsg,
+ pRxd->VDataHigh, pRxd->VDataLow);
+
+ continue;
+ }
+
+ /*
+ * if short frame then copy data to reduce memory waste
+ */
+ if ((FrameLength < SK_COPY_THRESHOLD) &&
+ ((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) {
+ /*
+ * Short frame detected and allocation successfull
+ */
+ /* use new skb and copy data */
+ skb_reserve(pNewMsg, 2);
+ skb_put(pNewMsg, FrameLength);
+ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+ PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+ pci_dma_sync_single_for_cpu(pAC->PciDev,
+ (dma_addr_t) PhysAddr,
+ FrameLength,
+ PCI_DMA_FROMDEVICE);
+ skb_copy_to_linear_data(pNewMsg, pMsg, FrameLength);
+
+ pci_dma_sync_single_for_device(pAC->PciDev,
+ (dma_addr_t) PhysAddr,
+ FrameLength,
+ PCI_DMA_FROMDEVICE);
+ ReQueueRxBuffer(pAC, pRxPort, pMsg,
+ pRxd->VDataHigh, pRxd->VDataLow);
+
+ pMsg = pNewMsg;
+
+ }
+ else {
+ /*
+ * if large frame, or SKB allocation failed, pass
+ * the SKB directly to the networking
+ */
+
+ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+ PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+ /* release the DMA mapping */
+ pci_unmap_single(pAC->PciDev,
+ PhysAddr,
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
+
+ /* set length in message */
+ skb_put(pMsg, FrameLength);
+ } /* frame > SK_COPY_TRESHOLD */
+
+#ifdef USE_SK_RX_CHECKSUM
+ pMsg->csum = pRxd->TcpSums & 0xffff;
+ pMsg->ip_summed = CHECKSUM_COMPLETE;
+#else
+ pMsg->ip_summed = CHECKSUM_NONE;
+#endif
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V"));
+ ForRlmt = SK_RLMT_RX_PROTOCOL;
+#if 0
+ IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+#endif
+ SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
+ IsBc, &Offset, &NumBytes);
+ if (NumBytes != 0) {
+#if 0
+ IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+#endif
+ SK_RLMT_LOOKAHEAD(pAC, PortIndex,
+ &pMsg->data[Offset],
+ IsBc, IsMc, &ForRlmt);
+ }
+ if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("W"));
+ /* send up only frames from active port */
+ if ((PortIndex == pAC->ActivePort) ||
+ (pAC->RlmtNets == 2)) {
+ /* frame for upper layer */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U"));
+#ifdef xDEBUG
+ DumpMsg(pMsg, "Rx");
+#endif
+ SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
+ FrameLength, pRxPort->PortIndex);
+
+ pMsg->protocol = eth_type_trans(pMsg,
+ pAC->dev[pRxPort->PortIndex]);
+ netif_rx(pMsg);
+ pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+ }
+ else {
+ /* drop frame */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_RX_PROGRESS,
+ ("D"));
+ DEV_KFREE_SKB(pMsg);
+ }
+
+ } /* if not for rlmt */
+ else {
+ /* packet for rlmt */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
+ pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
+ pAC->IoBase, FrameLength);
+ if (pRlmtMbuf != NULL) {
+ pRlmtMbuf->pNext = NULL;
+ pRlmtMbuf->Length = FrameLength;
+ pRlmtMbuf->PortIdx = PortIndex;
+ EvPara.pParaPtr = pRlmtMbuf;
+ memcpy((char*)(pRlmtMbuf->pData),
+ (char*)(pMsg->data),
+ FrameLength);
+
+ /* SlowPathLock needed? */
+ if (SlowPathLock == SK_TRUE) {
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ SkEventQueue(pAC, SKGE_RLMT,
+ SK_RLMT_PACKET_RECEIVED,
+ EvPara);
+ pAC->CheckQueue = SK_TRUE;
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ } else {
+ SkEventQueue(pAC, SKGE_RLMT,
+ SK_RLMT_PACKET_RECEIVED,
+ EvPara);
+ pAC->CheckQueue = SK_TRUE;
+ }
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+ SK_DBGCAT_DRV_RX_PROGRESS,
+ ("Q"));
+ }
+ if ((pAC->dev[pRxPort->PortIndex]->flags &
+ (IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
+ (ForRlmt & SK_RLMT_RX_PROTOCOL) ==
+ SK_RLMT_RX_PROTOCOL) {
+ pMsg->protocol = eth_type_trans(pMsg,
+ pAC->dev[pRxPort->PortIndex]);
+ netif_rx(pMsg);
+ pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+ }
+ else {
+ DEV_KFREE_SKB(pMsg);
+ }
+
+ } /* if packet for rlmt */
+ } /* for ... scanning the RXD ring */
+
+ /* RXD ring is empty -> fill and restart */
+ FillRxRing(pAC, pRxPort);
+ /* do not start if called from Close */
+ if (pAC->BoardLevel > SK_INIT_DATA) {
+ ClearAndStartRx(pAC, PortIndex);
+ }
+ return;
+
+rx_failed:
+ /* remove error frame */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+ ("Schrottdescriptor, length: 0x%x\n", FrameLength));
+
+ /* release the DMA mapping */
+
+ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+ PhysAddr |= (SK_U64) pRxd->VDataLow;
+ pci_unmap_page(pAC->PciDev,
+ PhysAddr,
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
+ DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
+ pRxd->pMBuf = NULL;
+ pRxPort->RxdRingFree++;
+ pRxPort->pRxdRingHead = pRxd->pNextRxd;
+ goto rx_start;
+
+} /* ReceiveIrq */
+
+
+/*****************************************************************************
+ *
+ * ClearAndStartRx - give a start receive command to BMU, clear IRQ
+ *
+ * Description:
+ * This function sends a start command and a clear interrupt
+ * command for one receive queue to the BMU.
+ *
+ * Returns: N/A
+ * none
+ */
+static void ClearAndStartRx(
+SK_AC *pAC, /* pointer to the adapter context */
+int PortIndex) /* index of the receive port (XMAC) */
+{
+ SK_OUT8(pAC->IoBase,
+ RxQueueAddr[PortIndex]+Q_CSR,
+ CSR_START | CSR_IRQ_CL_F);
+} /* ClearAndStartRx */
+
+
+/*****************************************************************************
+ *
+ * ClearTxIrq - give a clear transmit IRQ command to BMU
+ *
+ * Description:
+ * This function sends a clear tx IRQ command for one
+ * transmit queue to the BMU.
+ *
+ * Returns: N/A
+ */
+static void ClearTxIrq(
+SK_AC *pAC, /* pointer to the adapter context */
+int PortIndex, /* index of the transmit port (XMAC) */
+int Prio) /* priority or normal queue */
+{
+ SK_OUT8(pAC->IoBase,
+ TxQueueAddr[PortIndex][Prio]+Q_CSR,
+ CSR_IRQ_CL_F);
+} /* ClearTxIrq */
+
+
+/*****************************************************************************
+ *
+ * ClearRxRing - remove all buffers from the receive ring
+ *
+ * Description:
+ * This function removes all receive buffers from the ring.
+ * The receive BMU must be stopped before calling this function.
+ *
+ * Returns: N/A
+ */
+static void ClearRxRing(
+SK_AC *pAC, /* pointer to adapter context */
+RX_PORT *pRxPort) /* pointer to rx port struct */
+{
+RXD *pRxd; /* pointer to the current descriptor */
+unsigned long Flags;
+SK_U64 PhysAddr;
+
+ if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
+ return;
+ }
+ spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+ pRxd = pRxPort->pRxdRingHead;
+ do {
+ if (pRxd->pMBuf != NULL) {
+
+ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+ PhysAddr |= (SK_U64) pRxd->VDataLow;
+ pci_unmap_page(pAC->PciDev,
+ PhysAddr,
+ pAC->RxBufSize - 2,
+ PCI_DMA_FROMDEVICE);
+ DEV_KFREE_SKB(pRxd->pMBuf);
+ pRxd->pMBuf = NULL;
+ }
+ pRxd->RBControl &= BMU_OWN;
+ pRxd = pRxd->pNextRxd;
+ pRxPort->RxdRingFree++;
+ } while (pRxd != pRxPort->pRxdRingTail);
+ pRxPort->pRxdRingTail = pRxPort->pRxdRingHead;
+ spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* ClearRxRing */
+
+/*****************************************************************************
+ *
+ * ClearTxRing - remove all buffers from the transmit ring
+ *
+ * Description:
+ * This function removes all transmit buffers from the ring.
+ * The transmit BMU must be stopped before calling this function
+ * and transmitting at the upper level must be disabled.
+ * The BMU own bit of all descriptors is cleared, the rest is
+ * done by calling FreeTxDescriptors.
+ *
+ * Returns: N/A
+ */
+static void ClearTxRing(
+SK_AC *pAC, /* pointer to adapter context */
+TX_PORT *pTxPort) /* pointer to tx prt struct */
+{
+TXD *pTxd; /* pointer to the current descriptor */
+int i;
+unsigned long Flags;
+
+ spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+ pTxd = pTxPort->pTxdRingHead;
+ for (i=0; i<pAC->TxDescrPerRing; i++) {
+ pTxd->TBControl &= ~BMU_OWN;
+ pTxd = pTxd->pNextTxd;
+ }
+ FreeTxDescriptors(pAC, pTxPort);
+ spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+} /* ClearTxRing */
+
+/*****************************************************************************
+ *
+ * SkGeSetMacAddr - Set the hardware MAC address
+ *
+ * Description:
+ * This function sets the MAC address used by the adapter.
+ *
+ * Returns:
+ * 0, if everything is ok
+ * !=0, on error
+ */
+static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p)
+{
+
+DEV_NET *pNet = netdev_priv(dev);
+SK_AC *pAC = pNet->pAC;
+
+struct sockaddr *addr = p;
+unsigned long Flags;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeSetMacAddr starts now...\n"));
+ if(netif_running(dev))
+ return -EBUSY;
+
+ memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+ if (pAC->RlmtNets == 2)
+ SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr,
+ (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+ else
+ SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
+ (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+
+
+
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ return 0;
+} /* SkGeSetMacAddr */
+
+
+/*****************************************************************************
+ *
+ * SkGeSetRxMode - set receive mode
+ *
+ * Description:
+ * This function sets the receive mode of an adapter. The adapter
+ * supports promiscuous mode, allmulticast mode and a number of
+ * multicast addresses. If more multicast addresses the available
+ * are selected, a hash function in the hardware is used.
+ *
+ * Returns:
+ * 0, if everything is ok
+ * !=0, on error
+ */
+static void SkGeSetRxMode(struct SK_NET_DEVICE *dev)
+{
+
+DEV_NET *pNet;
+SK_AC *pAC;
+
+struct dev_mc_list *pMcList;
+int i;
+int PortIdx;
+unsigned long Flags;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeSetRxMode starts now... "));
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+ if (pAC->RlmtNets == 1)
+ PortIdx = pAC->ActivePort;
+ else
+ PortIdx = pNet->NetNr;
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ if (dev->flags & IFF_PROMISC) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("PROMISCUOUS mode\n"));
+ SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+ SK_PROM_MODE_LLC);
+ } else if (dev->flags & IFF_ALLMULTI) {
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("ALLMULTI mode\n"));
+ SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+ SK_PROM_MODE_ALL_MC);
+ } else {
+ SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+ SK_PROM_MODE_NONE);
+ SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("Number of MC entries: %d ", dev->mc_count));
+
+ pMcList = dev->mc_list;
+ for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) {
+ SkAddrMcAdd(pAC, pAC->IoBase, PortIdx,
+ (SK_MAC_ADDR*)pMcList->dmi_addr, 0);
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA,
+ ("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pMcList->dmi_addr[0],
+ pMcList->dmi_addr[1],
+ pMcList->dmi_addr[2],
+ pMcList->dmi_addr[3],
+ pMcList->dmi_addr[4],
+ pMcList->dmi_addr[5]));
+ }
+ SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx);
+ }
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ return;
+} /* SkGeSetRxMode */
+
+
+/*****************************************************************************
+ *
+ * SkGeChangeMtu - set the MTU to another value
+ *
+ * Description:
+ * This function sets is called whenever the MTU size is changed
+ * (ifconfig mtu xxx dev ethX). If the MTU is bigger than standard
+ * ethernet MTU size, long frame support is activated.
+ *
+ * Returns:
+ * 0, if everything is ok
+ * !=0, on error
+ */
+static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu)
+{
+DEV_NET *pNet;
+struct net_device *pOtherDev;
+SK_AC *pAC;
+unsigned long Flags;
+int i;
+SK_EVPARA EvPara;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeChangeMtu starts now...\n"));
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+ if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) {
+ return -EINVAL;
+ }
+
+ if(pAC->BoardLevel != SK_INIT_RUN) {
+ return -EINVAL;
+ }
+
+#ifdef SK_DIAG_SUPPORT
+ if (pAC->DiagModeActive == DIAG_ACTIVE) {
+ if (pAC->DiagFlowCtrl == SK_FALSE) {
+ return -1; /* still in use, deny any actions of MTU */
+ } else {
+ pAC->DiagFlowCtrl = SK_FALSE;
+ }
+ }
+#endif
+
+ pOtherDev = pAC->dev[1 - pNet->NetNr];
+
+ if ( netif_running(pOtherDev) && (pOtherDev->mtu > 1500)
+ && (NewMtu <= 1500))
+ return 0;
+
+ pAC->RxBufSize = NewMtu + 32;
+ dev->mtu = NewMtu;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("New MTU: %d\n", NewMtu));
+
+ /*
+ ** Prevent any reconfiguration while changing the MTU
+ ** by disabling any interrupts
+ */
+ SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+ /*
+ ** Notify RLMT that any ports are to be stopped
+ */
+ EvPara.Para32[0] = 0;
+ EvPara.Para32[1] = -1;
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ EvPara.Para32[0] = 1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ } else {
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ }
+
+ /*
+ ** After calling the SkEventDispatcher(), RLMT is aware about
+ ** the stopped ports -> configuration can take place!
+ */
+ SkEventDispatcher(pAC, pAC->IoBase);
+
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+ netif_stop_queue(pAC->dev[i]);
+
+ }
+
+ /*
+ ** Depending on the desired MTU size change, a different number of
+ ** RX buffers need to be allocated
+ */
+ if (NewMtu > 1500) {
+ /*
+ ** Use less rx buffers
+ */
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing -
+ (pAC->RxDescrPerRing / 4);
+ } else {
+ if (i == pAC->ActivePort) {
+ pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing -
+ (pAC->RxDescrPerRing / 4);
+ } else {
+ pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing -
+ (pAC->RxDescrPerRing / 10);
+ }
+ }
+ }
+ } else {
+ /*
+ ** Use the normal amount of rx buffers
+ */
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ pAC->RxPort[i].RxFillLimit = 1;
+ } else {
+ if (i == pAC->ActivePort) {
+ pAC->RxPort[i].RxFillLimit = 1;
+ } else {
+ pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing -
+ (pAC->RxDescrPerRing / 4);
+ }
+ }
+ }
+ }
+
+ SkGeDeInit(pAC, pAC->IoBase);
+
+ /*
+ ** enable/disable hardware support for long frames
+ */
+ if (NewMtu > 1500) {
+// pAC->JumboActivated = SK_TRUE; /* is never set back !!! */
+ pAC->GIni.GIPortUsage = SK_JUMBO_LINK;
+ } else {
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ pAC->GIni.GIPortUsage = SK_MUL_LINK;
+ } else {
+ pAC->GIni.GIPortUsage = SK_RED_LINK;
+ }
+ }
+
+ SkGeInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
+ SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO);
+ SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO);
+
+ /*
+ ** tschilling:
+ ** Speed and others are set back to default in level 1 init!
+ */
+ GetConfiguration(pAC);
+
+ SkGeInit( pAC, pAC->IoBase, SK_INIT_RUN);
+ SkI2cInit( pAC, pAC->IoBase, SK_INIT_RUN);
+ SkEventInit(pAC, pAC->IoBase, SK_INIT_RUN);
+ SkPnmiInit( pAC, pAC->IoBase, SK_INIT_RUN);
+ SkAddrInit( pAC, pAC->IoBase, SK_INIT_RUN);
+ SkRlmtInit( pAC, pAC->IoBase, SK_INIT_RUN);
+ SkTimerInit(pAC, pAC->IoBase, SK_INIT_RUN);
+
+ /*
+ ** clear and reinit the rx rings here
+ */
+ for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+ ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+ ClearRxRing(pAC, &pAC->RxPort[i]);
+ FillRxRing(pAC, &pAC->RxPort[i]);
+
+ /*
+ ** Enable transmit descriptor polling
+ */
+ SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+ FillRxRing(pAC, &pAC->RxPort[i]);
+ };
+
+ SkGeYellowLED(pAC, pAC->IoBase, 1);
+ SkDimEnableModerationIfNeeded(pAC);
+ SkDimDisplayModerationSettings(pAC);
+
+ netif_start_queue(pAC->dev[pNet->PortNr]);
+ for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) {
+ spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+ }
+
+ /*
+ ** Enable Interrupts again
+ */
+ SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+ SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+ SkEventDispatcher(pAC, pAC->IoBase);
+
+ /*
+ ** Notify RLMT about the changing and restarting one (or more) ports
+ */
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ EvPara.Para32[0] = pAC->RlmtNets;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, EvPara);
+ EvPara.Para32[0] = pNet->PortNr;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+
+ if (netif_running(pOtherDev)) {
+ DEV_NET *pOtherNet = netdev_priv(pOtherDev);
+ EvPara.Para32[0] = pOtherNet->PortNr;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+ }
+ } else {
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+ }
+
+ SkEventDispatcher(pAC, pAC->IoBase);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ /*
+ ** While testing this driver with latest kernel 2.5 (2.5.70), it
+ ** seems as if upper layers have a problem to handle a successful
+ ** return value of '0'. If such a zero is returned, the complete
+ ** system hangs for several minutes (!), which is in acceptable.
+ **
+ ** Currently it is not clear, what the exact reason for this problem
+ ** is. The implemented workaround for 2.5 is to return the desired
+ ** new MTU size if all needed changes for the new MTU size where
+ ** performed. In kernels 2.2 and 2.4, a zero value is returned,
+ ** which indicates the successful change of the mtu-size.
+ */
+ return NewMtu;
+
+} /* SkGeChangeMtu */
+
+
+/*****************************************************************************
+ *
+ * SkGeStats - return ethernet device statistics
+ *
+ * Description:
+ * This function return statistic data about the ethernet device
+ * to the operating system.
+ *
+ * Returns:
+ * pointer to the statistic structure.
+ */
+static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev)
+{
+DEV_NET *pNet = netdev_priv(dev);
+SK_AC *pAC = pNet->pAC;
+SK_PNMI_STRUCT_DATA *pPnmiStruct; /* structure for all Pnmi-Data */
+SK_PNMI_STAT *pPnmiStat; /* pointer to virtual XMAC stat. data */
+SK_PNMI_CONF *pPnmiConf; /* pointer to virtual link config. */
+unsigned int Size; /* size of pnmi struct */
+unsigned long Flags; /* for spin lock */
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeStats starts now...\n"));
+ pPnmiStruct = &pAC->PnmiStruct;
+
+#ifdef SK_DIAG_SUPPORT
+ if ((pAC->DiagModeActive == DIAG_NOTACTIVE) &&
+ (pAC->BoardLevel == SK_INIT_RUN)) {
+#endif
+ SK_MEMSET(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA));
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ Size = SK_PNMI_STRUCT_SIZE;
+ SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+#ifdef SK_DIAG_SUPPORT
+ }
+#endif
+
+ pPnmiStat = &pPnmiStruct->Stat[0];
+ pPnmiConf = &pPnmiStruct->Conf[0];
+
+ pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF;
+ pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF;
+ pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
+ pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
+
+ if (dev->mtu <= 1500) {
+ pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+ } else {
+ pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts -
+ pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF);
+ }
+
+
+ if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12)
+ pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts;
+
+ pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+ pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF;
+ pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF;
+ pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF;
+ pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+
+ /* detailed rx_errors: */
+ pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF;
+ pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+ pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF;
+ pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF;
+ pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+ pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF;
+
+ /* detailed tx_errors */
+ pAC->stats.tx_aborted_errors = (SK_U32) 0;
+ pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+ pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF;
+ pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+ pAC->stats.tx_window_errors = (SK_U32) 0;
+
+ return(&pAC->stats);
+} /* SkGeStats */
+
+/*
+ * Basic MII register access
+ */
+static int SkGeMiiIoctl(struct net_device *dev,
+ struct mii_ioctl_data *data, int cmd)
+{
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ SK_IOC IoC = pAC->IoBase;
+ int Port = pNet->PortNr;
+ SK_GEPORT *pPrt = &pAC->GIni.GP[Port];
+ unsigned long Flags;
+ int err = 0;
+ int reg = data->reg_num & 0x1f;
+ SK_U16 val = data->val_in;
+
+ if (!netif_running(dev))
+ return -ENODEV; /* Phy still in reset */
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ switch(cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = pPrt->PhyAddr;
+
+ /* fallthru */
+ case SIOCGMIIREG:
+ if (pAC->GIni.GIGenesis)
+ SkXmPhyRead(pAC, IoC, Port, reg, &val);
+ else
+ SkGmPhyRead(pAC, IoC, Port, reg, &val);
+
+ data->val_out = val;
+ break;
+
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ err = -EPERM;
+
+ else if (pAC->GIni.GIGenesis)
+ SkXmPhyWrite(pAC, IoC, Port, reg, val);
+ else
+ SkGmPhyWrite(pAC, IoC, Port, reg, val);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ }
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ return err;
+}
+
+
+/*****************************************************************************
+ *
+ * SkGeIoctl - IO-control function
+ *
+ * Description:
+ * This function is called if an ioctl is issued on the device.
+ * There are three subfunction for reading, writing and test-writing
+ * the private MIB data structure (useful for SysKonnect-internal tools).
+ *
+ * Returns:
+ * 0, if everything is ok
+ * !=0, on error
+ */
+static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd)
+{
+DEV_NET *pNet;
+SK_AC *pAC;
+void *pMemBuf;
+struct pci_dev *pdev = NULL;
+SK_GE_IOCTL Ioctl;
+unsigned int Err = 0;
+int Size = 0;
+int Ret = 0;
+unsigned int Length = 0;
+int HeaderLength = sizeof(SK_U32) + sizeof(SK_U32);
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeIoctl starts now...\n"));
+
+ pNet = netdev_priv(dev);
+ pAC = pNet->pAC;
+
+ if (cmd == SIOCGMIIPHY || cmd == SIOCSMIIREG || cmd == SIOCGMIIREG)
+ return SkGeMiiIoctl(dev, if_mii(rq), cmd);
+
+ if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) {
+ return -EFAULT;
+ }
+
+ switch(cmd) {
+ case SK_IOCTL_SETMIB:
+ case SK_IOCTL_PRESETMIB:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ case SK_IOCTL_GETMIB:
+ if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData,
+ Ioctl.Len<sizeof(pAC->PnmiStruct)?
+ Ioctl.Len : sizeof(pAC->PnmiStruct))) {
+ return -EFAULT;
+ }
+ Size = SkGeIocMib(pNet, Ioctl.Len, cmd);
+ if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct,
+ Ioctl.Len<Size? Ioctl.Len : Size)) {
+ return -EFAULT;
+ }
+ Ioctl.Len = Size;
+ if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+ return -EFAULT;
+ }
+ break;
+ case SK_IOCTL_GEN:
+ if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) {
+ Length = Ioctl.Len;
+ } else {
+ Length = sizeof(pAC->PnmiStruct) + HeaderLength;
+ }
+ if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+ if(copy_from_user(pMemBuf, Ioctl.pData, Length)) {
+ Err = -EFAULT;
+ goto fault_gen;
+ }
+ if ((Ret = SkPnmiGenIoctl(pAC, pAC->IoBase, pMemBuf, &Length, 0)) < 0) {
+ Err = -EFAULT;
+ goto fault_gen;
+ }
+ if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
+ Err = -EFAULT;
+ goto fault_gen;
+ }
+ Ioctl.Len = Length;
+ if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+ Err = -EFAULT;
+ goto fault_gen;
+ }
+fault_gen:
+ kfree(pMemBuf); /* cleanup everything */
+ break;
+#ifdef SK_DIAG_SUPPORT
+ case SK_IOCTL_DIAG:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) {
+ Length = Ioctl.Len;
+ } else {
+ Length = sizeof(pAC->PnmiStruct) + HeaderLength;
+ }
+ if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) {
+ return -ENOMEM;
+ }
+ if(copy_from_user(pMemBuf, Ioctl.pData, Length)) {
+ Err = -EFAULT;
+ goto fault_diag;
+ }
+ pdev = pAC->PciDev;
+ Length = 3 * sizeof(SK_U32); /* Error, Bus and Device */
+ /*
+ ** While coding this new IOCTL interface, only a few lines of code
+ ** are to to be added. Therefore no dedicated function has been
+ ** added. If more functionality is added, a separate function
+ ** should be used...
+ */
+ * ((SK_U32 *)pMemBuf) = 0;
+ * ((SK_U32 *)pMemBuf + 1) = pdev->bus->number;
+ * ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pci_name(pdev));
+ if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
+ Err = -EFAULT;
+ goto fault_diag;
+ }
+ Ioctl.Len = Length;
+ if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+ Err = -EFAULT;
+ goto fault_diag;
+ }
+fault_diag:
+ kfree(pMemBuf); /* cleanup everything */
+ break;
+#endif
+ default:
+ Err = -EOPNOTSUPP;
+ }
+
+ return(Err);
+
+} /* SkGeIoctl */
+
+
+/*****************************************************************************
+ *
+ * SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message
+ *
+ * Description:
+ * This function reads/writes the MIB data using PNMI (Private Network
+ * Management Interface).
+ * The destination for the data must be provided with the
+ * ioctl call and is given to the driver in the form of
+ * a user space address.
+ * Copying from the user-provided data area into kernel messages
+ * and back is done by copy_from_user and copy_to_user calls in
+ * SkGeIoctl.
+ *
+ * Returns:
+ * returned size from PNMI call
+ */
+static int SkGeIocMib(
+DEV_NET *pNet, /* pointer to the adapter context */
+unsigned int Size, /* length of ioctl data */
+int mode) /* flag for set/preset */
+{
+unsigned long Flags; /* for spin lock */
+SK_AC *pAC;
+
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("SkGeIocMib starts now...\n"));
+ pAC = pNet->pAC;
+ /* access MIB */
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ switch(mode) {
+ case SK_IOCTL_GETMIB:
+ SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+ pNet->NetNr);
+ break;
+ case SK_IOCTL_PRESETMIB:
+ SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+ pNet->NetNr);
+ break;
+ case SK_IOCTL_SETMIB:
+ SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+ pNet->NetNr);
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+ ("MIB data access succeeded\n"));
+ return (Size);
+} /* SkGeIocMib */
+
+
+/*****************************************************************************
+ *
+ * GetConfiguration - read configuration information
+ *
+ * Description:
+ * This function reads per-adapter configuration information from
+ * the options provided on the command line.
+ *
+ * Returns:
+ * none
+ */
+static void GetConfiguration(
+SK_AC *pAC) /* pointer to the adapter context structure */
+{
+SK_I32 Port; /* preferred port */
+SK_BOOL AutoSet;
+SK_BOOL DupSet;
+int LinkSpeed = SK_LSPEED_AUTO; /* Link speed */
+int AutoNeg = 1; /* autoneg off (0) or on (1) */
+int DuplexCap = 0; /* 0=both,1=full,2=half */
+int FlowCtrl = SK_FLOW_MODE_SYM_OR_REM; /* FlowControl */
+int MSMode = SK_MS_MODE_AUTO; /* master/slave mode */
+
+SK_BOOL IsConTypeDefined = SK_TRUE;
+SK_BOOL IsLinkSpeedDefined = SK_TRUE;
+SK_BOOL IsFlowCtrlDefined = SK_TRUE;
+SK_BOOL IsRoleDefined = SK_TRUE;
+SK_BOOL IsModeDefined = SK_TRUE;
+/*
+ * The two parameters AutoNeg. and DuplexCap. map to one configuration
+ * parameter. The mapping is described by this table:
+ * DuplexCap -> | both | full | half |
+ * AutoNeg | | | |
+ * -----------------------------------------------------------------
+ * Off | illegal | Full | Half |
+ * -----------------------------------------------------------------
+ * On | AutoBoth | AutoFull | AutoHalf |
+ * -----------------------------------------------------------------
+ * Sense | AutoSense | AutoSense | AutoSense |
+ */
+int Capabilities[3][3] =
+ { { -1, SK_LMODE_FULL , SK_LMODE_HALF },
+ {SK_LMODE_AUTOBOTH , SK_LMODE_AUTOFULL , SK_LMODE_AUTOHALF },
+ {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} };
+
+#define DC_BOTH 0
+#define DC_FULL 1
+#define DC_HALF 2
+#define AN_OFF 0
+#define AN_ON 1
+#define AN_SENS 2
+#define M_CurrPort pAC->GIni.GP[Port]
+
+
+ /*
+ ** Set the default values first for both ports!
+ */
+ for (Port = 0; Port < SK_MAX_MACS; Port++) {
+ M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH];
+ M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+ M_CurrPort.PMSMode = SK_MS_MODE_AUTO;
+ M_CurrPort.PLinkSpeed = SK_LSPEED_AUTO;
+ }
+
+ /*
+ ** Check merged parameter ConType. If it has not been used,
+ ** verify any other parameter (e.g. AutoNeg) and use default values.
+ **
+ ** Stating both ConType and other lowlevel link parameters is also
+ ** possible. If this is the case, the passed ConType-parameter is
+ ** overwritten by the lowlevel link parameter.
+ **
+ ** The following settings are used for a merged ConType-parameter:
+ **
+ ** ConType DupCap AutoNeg FlowCtrl Role Speed
+ ** ------- ------ ------- -------- ---------- -----
+ ** Auto Both On SymOrRem Auto Auto
+ ** 100FD Full Off None <ignored> 100
+ ** 100HD Half Off None <ignored> 100
+ ** 10FD Full Off None <ignored> 10
+ ** 10HD Half Off None <ignored> 10
+ **
+ ** This ConType parameter is used for all ports of the adapter!
+ */
+ if ( (ConType != NULL) &&
+ (pAC->Index < SK_MAX_CARD_PARAM) &&
+ (ConType[pAC->Index] != NULL) ) {
+
+ /* Check chipset family */
+ if ((!pAC->ChipsetType) &&
+ (strcmp(ConType[pAC->Index],"Auto")!=0) &&
+ (strcmp(ConType[pAC->Index],"")!=0)) {
+ /* Set the speed parameter back */
+ printk("sk98lin: Illegal value \"%s\" "
+ "for ConType."
+ " Using Auto.\n",
+ ConType[pAC->Index]);
+
+ sprintf(ConType[pAC->Index], "Auto");
+ }
+
+ if (strcmp(ConType[pAC->Index],"")==0) {
+ IsConTypeDefined = SK_FALSE; /* No ConType defined */
+ } else if (strcmp(ConType[pAC->Index],"Auto")==0) {
+ for (Port = 0; Port < SK_MAX_MACS; Port++) {
+ M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH];
+ M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+ M_CurrPort.PMSMode = SK_MS_MODE_AUTO;
+ M_CurrPort.PLinkSpeed = SK_LSPEED_AUTO;
+ }
+ } else if (strcmp(ConType[pAC->Index],"100FD")==0) {
+ for (Port = 0; Port < SK_MAX_MACS; Port++) {
+ M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL];
+ M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+ M_CurrPort.PMSMode = SK_MS_MODE_AUTO;
+ M_CurrPort.PLinkSpeed = SK_LSPEED_100MBPS;
+ }
+ } else if (strcmp(ConType[pAC->Index],"100HD")==0) {
+ for (Port = 0; Port < SK_MAX_MACS; Port++) {
+ M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF];
+ M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+ M_CurrPort.PMSMode = SK_MS_MODE_AUTO;
+ M_CurrPort.PLinkSpeed = SK_LSPEED_100MBPS;
+ }
+ } else if (strcmp(ConType[pAC->Index],"10FD")==0) {
+ for (Port = 0; Port < SK_MAX_MACS; Port++) {
+ M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL];
+ M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+ M_CurrPort.PMSMode = SK_MS_MODE_AUTO;
+ M_CurrPort.PLinkSpeed = SK_LSPEED_10MBPS;
+ }
+ } else if (strcmp(ConType[pAC->Index],"10HD")==0) {
+ for (Port = 0; Port < SK_MAX_MACS; Port++) {
+ M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF];
+ M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+ M_CurrPort.PMSMode = SK_MS_MODE_AUTO;
+ M_CurrPort.PLinkSpeed = SK_LSPEED_10MBPS;
+ }
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for ConType\n",
+ ConType[pAC->Index]);
+ IsConTypeDefined = SK_FALSE; /* Wrong ConType defined */
+ }
+ } else {
+ IsConTypeDefined = SK_FALSE; /* No ConType defined */
+ }
+
+ /*
+ ** Parse any parameter settings for port A:
+ ** a) any LinkSpeed stated?
+ */
+ if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ Speed_A[pAC->Index] != NULL) {
+ if (strcmp(Speed_A[pAC->Index],"")==0) {
+ IsLinkSpeedDefined = SK_FALSE;
+ } else if (strcmp(Speed_A[pAC->Index],"Auto")==0) {
+ LinkSpeed = SK_LSPEED_AUTO;
+ } else if (strcmp(Speed_A[pAC->Index],"10")==0) {
+ LinkSpeed = SK_LSPEED_10MBPS;
+ } else if (strcmp(Speed_A[pAC->Index],"100")==0) {
+ LinkSpeed = SK_LSPEED_100MBPS;
+ } else if (strcmp(Speed_A[pAC->Index],"1000")==0) {
+ LinkSpeed = SK_LSPEED_1000MBPS;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for Speed_A\n",
+ Speed_A[pAC->Index]);
+ IsLinkSpeedDefined = SK_FALSE;
+ }
+ } else {
+ IsLinkSpeedDefined = SK_FALSE;
+ }
+
+ /*
+ ** Check speed parameter:
+ ** Only copper type adapter and GE V2 cards
+ */
+ if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) &&
+ ((LinkSpeed != SK_LSPEED_AUTO) &&
+ (LinkSpeed != SK_LSPEED_1000MBPS))) {
+ printk("sk98lin: Illegal value for Speed_A. "
+ "Not a copper card or GE V2 card\n Using "
+ "speed 1000\n");
+ LinkSpeed = SK_LSPEED_1000MBPS;
+ }
+
+ /*
+ ** Decide whether to set new config value if somethig valid has
+ ** been received.
+ */
+ if (IsLinkSpeedDefined) {
+ pAC->GIni.GP[0].PLinkSpeed = LinkSpeed;
+ }
+
+ /*
+ ** b) Any Autonegotiation and DuplexCapabilities set?
+ ** Please note that both belong together...
+ */
+ AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */
+ AutoSet = SK_FALSE;
+ if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ AutoNeg_A[pAC->Index] != NULL) {
+ AutoSet = SK_TRUE;
+ if (strcmp(AutoNeg_A[pAC->Index],"")==0) {
+ AutoSet = SK_FALSE;
+ } else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) {
+ AutoNeg = AN_ON;
+ } else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) {
+ AutoNeg = AN_OFF;
+ } else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) {
+ AutoNeg = AN_SENS;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for AutoNeg_A\n",
+ AutoNeg_A[pAC->Index]);
+ }
+ }
+
+ DuplexCap = DC_BOTH;
+ DupSet = SK_FALSE;
+ if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ DupCap_A[pAC->Index] != NULL) {
+ DupSet = SK_TRUE;
+ if (strcmp(DupCap_A[pAC->Index],"")==0) {
+ DupSet = SK_FALSE;
+ } else if (strcmp(DupCap_A[pAC->Index],"Both")==0) {
+ DuplexCap = DC_BOTH;
+ } else if (strcmp(DupCap_A[pAC->Index],"Full")==0) {
+ DuplexCap = DC_FULL;
+ } else if (strcmp(DupCap_A[pAC->Index],"Half")==0) {
+ DuplexCap = DC_HALF;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for DupCap_A\n",
+ DupCap_A[pAC->Index]);
+ }
+ }
+
+ /*
+ ** Check for illegal combinations
+ */
+ if ((LinkSpeed == SK_LSPEED_1000MBPS) &&
+ ((DuplexCap == SK_LMODE_STAT_AUTOHALF) ||
+ (DuplexCap == SK_LMODE_STAT_HALF)) &&
+ (pAC->ChipsetType)) {
+ printk("sk98lin: Half Duplex not possible with Gigabit speed!\n"
+ " Using Full Duplex.\n");
+ DuplexCap = DC_FULL;
+ }
+
+ if ( AutoSet && AutoNeg==AN_SENS && DupSet) {
+ printk("sk98lin, Port A: DuplexCapabilities"
+ " ignored using Sense mode\n");
+ }
+
+ if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+ printk("sk98lin: Port A: Illegal combination"
+ " of values AutoNeg. and DuplexCap.\n Using "
+ "Full Duplex\n");
+ DuplexCap = DC_FULL;
+ }
+
+ if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+ DuplexCap = DC_FULL;
+ }
+
+ if (!AutoSet && DupSet) {
+ printk("sk98lin: Port A: Duplex setting not"
+ " possible in\n default AutoNegotiation mode"
+ " (Sense).\n Using AutoNegotiation On\n");
+ AutoNeg = AN_ON;
+ }
+
+ /*
+ ** set the desired mode
+ */
+ if (AutoSet || DupSet) {
+ pAC->GIni.GP[0].PLinkModeConf = Capabilities[AutoNeg][DuplexCap];
+ }
+
+ /*
+ ** c) Any Flowcontrol-parameter set?
+ */
+ if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ FlowCtrl_A[pAC->Index] != NULL) {
+ if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) {
+ IsFlowCtrlDefined = SK_FALSE;
+ } else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) {
+ FlowCtrl = SK_FLOW_MODE_SYM_OR_REM;
+ } else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) {
+ FlowCtrl = SK_FLOW_MODE_SYMMETRIC;
+ } else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) {
+ FlowCtrl = SK_FLOW_MODE_LOC_SEND;
+ } else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) {
+ FlowCtrl = SK_FLOW_MODE_NONE;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for FlowCtrl_A\n",
+ FlowCtrl_A[pAC->Index]);
+ IsFlowCtrlDefined = SK_FALSE;
+ }
+ } else {
+ IsFlowCtrlDefined = SK_FALSE;
+ }
+
+ if (IsFlowCtrlDefined) {
+ if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) {
+ printk("sk98lin: Port A: FlowControl"
+ " impossible without AutoNegotiation,"
+ " disabled\n");
+ FlowCtrl = SK_FLOW_MODE_NONE;
+ }
+ pAC->GIni.GP[0].PFlowCtrlMode = FlowCtrl;
+ }
+
+ /*
+ ** d) What is with the RoleParameter?
+ */
+ if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ Role_A[pAC->Index] != NULL) {
+ if (strcmp(Role_A[pAC->Index],"")==0) {
+ IsRoleDefined = SK_FALSE;
+ } else if (strcmp(Role_A[pAC->Index],"Auto")==0) {
+ MSMode = SK_MS_MODE_AUTO;
+ } else if (strcmp(Role_A[pAC->Index],"Master")==0) {
+ MSMode = SK_MS_MODE_MASTER;
+ } else if (strcmp(Role_A[pAC->Index],"Slave")==0) {
+ MSMode = SK_MS_MODE_SLAVE;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for Role_A\n",
+ Role_A[pAC->Index]);
+ IsRoleDefined = SK_FALSE;
+ }
+ } else {
+ IsRoleDefined = SK_FALSE;
+ }
+
+ if (IsRoleDefined == SK_TRUE) {
+ pAC->GIni.GP[0].PMSMode = MSMode;
+ }
+
+
+
+ /*
+ ** Parse any parameter settings for port B:
+ ** a) any LinkSpeed stated?
+ */
+ IsConTypeDefined = SK_TRUE;
+ IsLinkSpeedDefined = SK_TRUE;
+ IsFlowCtrlDefined = SK_TRUE;
+ IsModeDefined = SK_TRUE;
+
+ if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ Speed_B[pAC->Index] != NULL) {
+ if (strcmp(Speed_B[pAC->Index],"")==0) {
+ IsLinkSpeedDefined = SK_FALSE;
+ } else if (strcmp(Speed_B[pAC->Index],"Auto")==0) {
+ LinkSpeed = SK_LSPEED_AUTO;
+ } else if (strcmp(Speed_B[pAC->Index],"10")==0) {
+ LinkSpeed = SK_LSPEED_10MBPS;
+ } else if (strcmp(Speed_B[pAC->Index],"100")==0) {
+ LinkSpeed = SK_LSPEED_100MBPS;
+ } else if (strcmp(Speed_B[pAC->Index],"1000")==0) {
+ LinkSpeed = SK_LSPEED_1000MBPS;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for Speed_B\n",
+ Speed_B[pAC->Index]);
+ IsLinkSpeedDefined = SK_FALSE;
+ }
+ } else {
+ IsLinkSpeedDefined = SK_FALSE;
+ }
+
+ /*
+ ** Check speed parameter:
+ ** Only copper type adapter and GE V2 cards
+ */
+ if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) &&
+ ((LinkSpeed != SK_LSPEED_AUTO) &&
+ (LinkSpeed != SK_LSPEED_1000MBPS))) {
+ printk("sk98lin: Illegal value for Speed_B. "
+ "Not a copper card or GE V2 card\n Using "
+ "speed 1000\n");
+ LinkSpeed = SK_LSPEED_1000MBPS;
+ }
+
+ /*
+ ** Decide whether to set new config value if somethig valid has
+ ** been received.
+ */
+ if (IsLinkSpeedDefined) {
+ pAC->GIni.GP[1].PLinkSpeed = LinkSpeed;
+ }
+
+ /*
+ ** b) Any Autonegotiation and DuplexCapabilities set?
+ ** Please note that both belong together...
+ */
+ AutoNeg = AN_SENS; /* default: do auto Sense */
+ AutoSet = SK_FALSE;
+ if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ AutoNeg_B[pAC->Index] != NULL) {
+ AutoSet = SK_TRUE;
+ if (strcmp(AutoNeg_B[pAC->Index],"")==0) {
+ AutoSet = SK_FALSE;
+ } else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) {
+ AutoNeg = AN_ON;
+ } else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) {
+ AutoNeg = AN_OFF;
+ } else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) {
+ AutoNeg = AN_SENS;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for AutoNeg_B\n",
+ AutoNeg_B[pAC->Index]);
+ }
+ }
+
+ DuplexCap = DC_BOTH;
+ DupSet = SK_FALSE;
+ if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ DupCap_B[pAC->Index] != NULL) {
+ DupSet = SK_TRUE;
+ if (strcmp(DupCap_B[pAC->Index],"")==0) {
+ DupSet = SK_FALSE;
+ } else if (strcmp(DupCap_B[pAC->Index],"Both")==0) {
+ DuplexCap = DC_BOTH;
+ } else if (strcmp(DupCap_B[pAC->Index],"Full")==0) {
+ DuplexCap = DC_FULL;
+ } else if (strcmp(DupCap_B[pAC->Index],"Half")==0) {
+ DuplexCap = DC_HALF;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for DupCap_B\n",
+ DupCap_B[pAC->Index]);
+ }
+ }
+
+
+ /*
+ ** Check for illegal combinations
+ */
+ if ((LinkSpeed == SK_LSPEED_1000MBPS) &&
+ ((DuplexCap == SK_LMODE_STAT_AUTOHALF) ||
+ (DuplexCap == SK_LMODE_STAT_HALF)) &&
+ (pAC->ChipsetType)) {
+ printk("sk98lin: Half Duplex not possible with Gigabit speed!\n"
+ " Using Full Duplex.\n");
+ DuplexCap = DC_FULL;
+ }
+
+ if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+ printk("sk98lin, Port B: DuplexCapabilities"
+ " ignored using Sense mode\n");
+ }
+
+ if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+ printk("sk98lin: Port B: Illegal combination"
+ " of values AutoNeg. and DuplexCap.\n Using "
+ "Full Duplex\n");
+ DuplexCap = DC_FULL;
+ }
+
+ if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+ DuplexCap = DC_FULL;
+ }
+
+ if (!AutoSet && DupSet) {
+ printk("sk98lin: Port B: Duplex setting not"
+ " possible in\n default AutoNegotiation mode"
+ " (Sense).\n Using AutoNegotiation On\n");
+ AutoNeg = AN_ON;
+ }
+
+ /*
+ ** set the desired mode
+ */
+ if (AutoSet || DupSet) {
+ pAC->GIni.GP[1].PLinkModeConf = Capabilities[AutoNeg][DuplexCap];
+ }
+
+ /*
+ ** c) Any FlowCtrl parameter set?
+ */
+ if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ FlowCtrl_B[pAC->Index] != NULL) {
+ if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) {
+ IsFlowCtrlDefined = SK_FALSE;
+ } else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) {
+ FlowCtrl = SK_FLOW_MODE_SYM_OR_REM;
+ } else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) {
+ FlowCtrl = SK_FLOW_MODE_SYMMETRIC;
+ } else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) {
+ FlowCtrl = SK_FLOW_MODE_LOC_SEND;
+ } else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) {
+ FlowCtrl = SK_FLOW_MODE_NONE;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for FlowCtrl_B\n",
+ FlowCtrl_B[pAC->Index]);
+ IsFlowCtrlDefined = SK_FALSE;
+ }
+ } else {
+ IsFlowCtrlDefined = SK_FALSE;
+ }
+
+ if (IsFlowCtrlDefined) {
+ if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) {
+ printk("sk98lin: Port B: FlowControl"
+ " impossible without AutoNegotiation,"
+ " disabled\n");
+ FlowCtrl = SK_FLOW_MODE_NONE;
+ }
+ pAC->GIni.GP[1].PFlowCtrlMode = FlowCtrl;
+ }
+
+ /*
+ ** d) What is the RoleParameter?
+ */
+ if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ Role_B[pAC->Index] != NULL) {
+ if (strcmp(Role_B[pAC->Index],"")==0) {
+ IsRoleDefined = SK_FALSE;
+ } else if (strcmp(Role_B[pAC->Index],"Auto")==0) {
+ MSMode = SK_MS_MODE_AUTO;
+ } else if (strcmp(Role_B[pAC->Index],"Master")==0) {
+ MSMode = SK_MS_MODE_MASTER;
+ } else if (strcmp(Role_B[pAC->Index],"Slave")==0) {
+ MSMode = SK_MS_MODE_SLAVE;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for Role_B\n",
+ Role_B[pAC->Index]);
+ IsRoleDefined = SK_FALSE;
+ }
+ } else {
+ IsRoleDefined = SK_FALSE;
+ }
+
+ if (IsRoleDefined) {
+ pAC->GIni.GP[1].PMSMode = MSMode;
+ }
+
+ /*
+ ** Evaluate settings for both ports
+ */
+ pAC->ActivePort = 0;
+ if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ PrefPort[pAC->Index] != NULL) {
+ if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */
+ pAC->ActivePort = 0;
+ pAC->Rlmt.Net[0].Preference = -1; /* auto */
+ pAC->Rlmt.Net[0].PrefPort = 0;
+ } else if (strcmp(PrefPort[pAC->Index],"A") == 0) {
+ /*
+ ** do not set ActivePort here, thus a port
+ ** switch is issued after net up.
+ */
+ Port = 0;
+ pAC->Rlmt.Net[0].Preference = Port;
+ pAC->Rlmt.Net[0].PrefPort = Port;
+ } else if (strcmp(PrefPort[pAC->Index],"B") == 0) {
+ /*
+ ** do not set ActivePort here, thus a port
+ ** switch is issued after net up.
+ */
+ if (pAC->GIni.GIMacsFound == 1) {
+ printk("sk98lin: Illegal value \"B\" for PrefPort.\n"
+ " Port B not available on single port adapters.\n");
+
+ pAC->ActivePort = 0;
+ pAC->Rlmt.Net[0].Preference = -1; /* auto */
+ pAC->Rlmt.Net[0].PrefPort = 0;
+ } else {
+ Port = 1;
+ pAC->Rlmt.Net[0].Preference = Port;
+ pAC->Rlmt.Net[0].PrefPort = Port;
+ }
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for PrefPort\n",
+ PrefPort[pAC->Index]);
+ }
+ }
+
+ pAC->RlmtNets = 1;
+
+ if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+ RlmtMode[pAC->Index] != NULL) {
+ if (strcmp(RlmtMode[pAC->Index], "") == 0) {
+ pAC->RlmtMode = 0;
+ } else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) {
+ pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+ } else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) {
+ pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+ SK_RLMT_CHECK_LOC_LINK;
+ } else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) {
+ pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+ SK_RLMT_CHECK_LOC_LINK |
+ SK_RLMT_CHECK_SEG;
+ } else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) &&
+ (pAC->GIni.GIMacsFound == 2)) {
+ pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+ pAC->RlmtNets = 2;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for"
+ " RlmtMode, using default\n",
+ RlmtMode[pAC->Index]);
+ pAC->RlmtMode = 0;
+ }
+ } else {
+ pAC->RlmtMode = 0;
+ }
+
+ /*
+ ** Check the interrupt moderation parameters
+ */
+ if (Moderation[pAC->Index] != NULL) {
+ if (strcmp(Moderation[pAC->Index], "") == 0) {
+ pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+ } else if (strcmp(Moderation[pAC->Index], "Static") == 0) {
+ pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC;
+ } else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) {
+ pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC;
+ } else if (strcmp(Moderation[pAC->Index], "None") == 0) {
+ pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+ } else {
+ printk("sk98lin: Illegal value \"%s\" for Moderation.\n"
+ " Disable interrupt moderation.\n",
+ Moderation[pAC->Index]);
+ pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+ }
+ } else {
+ pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+ }
+
+ if (Stats[pAC->Index] != NULL) {
+ if (strcmp(Stats[pAC->Index], "Yes") == 0) {
+ pAC->DynIrqModInfo.DisplayStats = SK_TRUE;
+ } else {
+ pAC->DynIrqModInfo.DisplayStats = SK_FALSE;
+ }
+ } else {
+ pAC->DynIrqModInfo.DisplayStats = SK_FALSE;
+ }
+
+ if (ModerationMask[pAC->Index] != NULL) {
+ if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY;
+ } else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY;
+ } else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY;
+ } else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX;
+ } else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX;
+ } else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+ } else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+ } else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX;
+ } else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX;
+ } else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+ } else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+ } else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+ } else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+ } else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+ } else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) {
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+ } else { /* some rubbish */
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY;
+ }
+ } else { /* operator has stated nothing */
+ pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+ }
+
+ if (AutoSizing[pAC->Index] != NULL) {
+ if (strcmp(AutoSizing[pAC->Index], "On") == 0) {
+ pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+ } else {
+ pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+ }
+ } else { /* operator has stated nothing */
+ pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+ }
+
+ if (IntsPerSec[pAC->Index] != 0) {
+ if ((IntsPerSec[pAC->Index]< C_INT_MOD_IPS_LOWER_RANGE) ||
+ (IntsPerSec[pAC->Index] > C_INT_MOD_IPS_UPPER_RANGE)) {
+ printk("sk98lin: Illegal value \"%d\" for IntsPerSec. (Range: %d - %d)\n"
+ " Using default value of %i.\n",
+ IntsPerSec[pAC->Index],
+ C_INT_MOD_IPS_LOWER_RANGE,
+ C_INT_MOD_IPS_UPPER_RANGE,
+ C_INTS_PER_SEC_DEFAULT);
+ pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT;
+ } else {
+ pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index];
+ }
+ } else {
+ pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT;
+ }
+
+ /*
+ ** Evaluate upper and lower moderation threshold
+ */
+ pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit =
+ pAC->DynIrqModInfo.MaxModIntsPerSec +
+ (pAC->DynIrqModInfo.MaxModIntsPerSec / 2);
+
+ pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit =
+ pAC->DynIrqModInfo.MaxModIntsPerSec -
+ (pAC->DynIrqModInfo.MaxModIntsPerSec / 2);
+
+ pAC->DynIrqModInfo.PrevTimeVal = jiffies; /* initial value */
+
+
+} /* GetConfiguration */
+
+
+/*****************************************************************************
+ *
+ * ProductStr - return a adapter identification string from vpd
+ *
+ * Description:
+ * This function reads the product name string from the vpd area
+ * and puts it the field pAC->DeviceString.
+ *
+ * Returns: N/A
+ */
+static inline int ProductStr(
+ SK_AC *pAC, /* pointer to adapter context */
+ char *DeviceStr, /* result string */
+ int StrLen /* length of the string */
+)
+{
+char Keyword[] = VPD_NAME; /* vpd productname identifier */
+int ReturnCode; /* return code from vpd_read */
+unsigned long Flags;
+
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, DeviceStr, &StrLen);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+ return ReturnCode;
+} /* ProductStr */
+
+/*****************************************************************************
+ *
+ * StartDrvCleanupTimer - Start timer to check for descriptors which
+ * might be placed in descriptor ring, but
+ * havent been handled up to now
+ *
+ * Description:
+ * This function requests a HW-timer fo the Yukon card. The actions to
+ * perform when this timer expires, are located in the SkDrvEvent().
+ *
+ * Returns: N/A
+ */
+static void
+StartDrvCleanupTimer(SK_AC *pAC) {
+ SK_EVPARA EventParam; /* Event struct for timer event */
+
+ SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+ EventParam.Para32[0] = SK_DRV_RX_CLEANUP_TIMER;
+ SkTimerStart(pAC, pAC->IoBase, &pAC->DrvCleanupTimer,
+ SK_DRV_RX_CLEANUP_TIMER_LENGTH,
+ SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*****************************************************************************
+ *
+ * StopDrvCleanupTimer - Stop timer to check for descriptors
+ *
+ * Description:
+ * This function requests a HW-timer fo the Yukon card. The actions to
+ * perform when this timer expires, are located in the SkDrvEvent().
+ *
+ * Returns: N/A
+ */
+static void
+StopDrvCleanupTimer(SK_AC *pAC) {
+ SkTimerStop(pAC, pAC->IoBase, &pAC->DrvCleanupTimer);
+ SK_MEMSET((char *) &pAC->DrvCleanupTimer, 0, sizeof(SK_TIMER));
+}
+
+/****************************************************************************/
+/* functions for common modules *********************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * SkDrvAllocRlmtMbuf - allocate an RLMT mbuf
+ *
+ * Description:
+ * This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure
+ * is embedded into a socket buff data area.
+ *
+ * Context:
+ * runtime
+ *
+ * Returns:
+ * NULL or pointer to Mbuf.
+ */
+SK_MBUF *SkDrvAllocRlmtMbuf(
+SK_AC *pAC, /* pointer to adapter context */
+SK_IOC IoC, /* the IO-context */
+unsigned BufferSize) /* size of the requested buffer */
+{
+SK_MBUF *pRlmtMbuf; /* pointer to a new rlmt-mbuf structure */
+struct sk_buff *pMsgBlock; /* pointer to a new message block */
+
+ pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC);
+ if (pMsgBlock == NULL) {
+ return (NULL);
+ }
+ pRlmtMbuf = (SK_MBUF*) pMsgBlock->data;
+ skb_reserve(pMsgBlock, sizeof(SK_MBUF));
+ pRlmtMbuf->pNext = NULL;
+ pRlmtMbuf->pOs = pMsgBlock;
+ pRlmtMbuf->pData = pMsgBlock->data; /* Data buffer. */
+ pRlmtMbuf->Size = BufferSize; /* Data buffer size. */
+ pRlmtMbuf->Length = 0; /* Length of packet (<= Size). */
+ return (pRlmtMbuf);
+
+} /* SkDrvAllocRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ * SkDrvFreeRlmtMbuf - free an RLMT mbuf
+ *
+ * Description:
+ * This routine frees one or more RLMT mbuf(s).
+ *
+ * Context:
+ * runtime
+ *
+ * Returns:
+ * Nothing
+ */
+void SkDrvFreeRlmtMbuf(
+SK_AC *pAC, /* pointer to adapter context */
+SK_IOC IoC, /* the IO-context */
+SK_MBUF *pMbuf) /* size of the requested buffer */
+{
+SK_MBUF *pFreeMbuf;
+SK_MBUF *pNextMbuf;
+
+ pFreeMbuf = pMbuf;
+ do {
+ pNextMbuf = pFreeMbuf->pNext;
+ DEV_KFREE_SKB_ANY(pFreeMbuf->pOs);
+ pFreeMbuf = pNextMbuf;
+ } while ( pFreeMbuf != NULL );
+} /* SkDrvFreeRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ * SkOsGetTime - provide a time value
+ *
+ * Description:
+ * This routine provides a time value. The unit is 1/HZ (defined by Linux).
+ * It is not used for absolute time, but only for time differences.
+ *
+ *
+ * Returns:
+ * Time value
+ */
+SK_U64 SkOsGetTime(SK_AC *pAC)
+{
+ SK_U64 PrivateJiffies;
+ SkOsGetTimeCurrent(pAC, &PrivateJiffies);
+ return PrivateJiffies;
+} /* SkOsGetTime */
+
+
+/*****************************************************************************
+ *
+ * SkPciReadCfgDWord - read a 32 bit value from pci config space
+ *
+ * Description:
+ * This routine reads a 32 bit value from the pci configuration
+ * space.
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+int SkPciReadCfgDWord(
+SK_AC *pAC, /* Adapter Control structure pointer */
+int PciAddr, /* PCI register address */
+SK_U32 *pVal) /* pointer to store the read value */
+{
+ pci_read_config_dword(pAC->PciDev, PciAddr, pVal);
+ return(0);
+} /* SkPciReadCfgDWord */
+
+
+/*****************************************************************************
+ *
+ * SkPciReadCfgWord - read a 16 bit value from pci config space
+ *
+ * Description:
+ * This routine reads a 16 bit value from the pci configuration
+ * space.
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+int SkPciReadCfgWord(
+SK_AC *pAC, /* Adapter Control structure pointer */
+int PciAddr, /* PCI register address */
+SK_U16 *pVal) /* pointer to store the read value */
+{
+ pci_read_config_word(pAC->PciDev, PciAddr, pVal);
+ return(0);
+} /* SkPciReadCfgWord */
+
+
+/*****************************************************************************
+ *
+ * SkPciReadCfgByte - read a 8 bit value from pci config space
+ *
+ * Description:
+ * This routine reads a 8 bit value from the pci configuration
+ * space.
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+int SkPciReadCfgByte(
+SK_AC *pAC, /* Adapter Control structure pointer */
+int PciAddr, /* PCI register address */
+SK_U8 *pVal) /* pointer to store the read value */
+{
+ pci_read_config_byte(pAC->PciDev, PciAddr, pVal);
+ return(0);
+} /* SkPciReadCfgByte */
+
+
+/*****************************************************************************
+ *
+ * SkPciWriteCfgWord - write a 16 bit value to pci config space
+ *
+ * Description:
+ * This routine writes a 16 bit value to the pci configuration
+ * space. The flag PciConfigUp indicates whether the config space
+ * is accesible or must be set up first.
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+int SkPciWriteCfgWord(
+SK_AC *pAC, /* Adapter Control structure pointer */
+int PciAddr, /* PCI register address */
+SK_U16 Val) /* pointer to store the read value */
+{
+ pci_write_config_word(pAC->PciDev, PciAddr, Val);
+ return(0);
+} /* SkPciWriteCfgWord */
+
+
+/*****************************************************************************
+ *
+ * SkPciWriteCfgWord - write a 8 bit value to pci config space
+ *
+ * Description:
+ * This routine writes a 8 bit value to the pci configuration
+ * space. The flag PciConfigUp indicates whether the config space
+ * is accesible or must be set up first.
+ *
+ * Returns:
+ * 0 - indicate everything worked ok.
+ * != 0 - error indication
+ */
+int SkPciWriteCfgByte(
+SK_AC *pAC, /* Adapter Control structure pointer */
+int PciAddr, /* PCI register address */
+SK_U8 Val) /* pointer to store the read value */
+{
+ pci_write_config_byte(pAC->PciDev, PciAddr, Val);
+ return(0);
+} /* SkPciWriteCfgByte */
+
+
+/*****************************************************************************
+ *
+ * SkDrvEvent - handle driver events
+ *
+ * Description:
+ * This function handles events from all modules directed to the driver
+ *
+ * Context:
+ * Is called under protection of slow path lock.
+ *
+ * Returns:
+ * 0 if everything ok
+ * < 0 on error
+ *
+ */
+int SkDrvEvent(
+SK_AC *pAC, /* pointer to adapter context */
+SK_IOC IoC, /* io-context */
+SK_U32 Event, /* event-id */
+SK_EVPARA Param) /* event-parameter */
+{
+SK_MBUF *pRlmtMbuf; /* pointer to a rlmt-mbuf structure */
+struct sk_buff *pMsg; /* pointer to a message block */
+int FromPort; /* the port from which we switch away */
+int ToPort; /* the port we switch to */
+SK_EVPARA NewPara; /* parameter for further events */
+int Stat;
+unsigned long Flags;
+SK_BOOL DualNet;
+
+ switch (Event) {
+ case SK_DRV_ADAP_FAIL:
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("ADAPTER FAIL EVENT\n"));
+ printk("%s: Adapter failed.\n", pAC->dev[0]->name);
+ /* disable interrupts */
+ SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+ /* cgoos */
+ break;
+ case SK_DRV_PORT_FAIL:
+ FromPort = Param.Para32[0];
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("PORT FAIL EVENT, Port: %d\n", FromPort));
+ if (FromPort == 0) {
+ printk("%s: Port A failed.\n", pAC->dev[0]->name);
+ } else {
+ printk("%s: Port B failed.\n", pAC->dev[1]->name);
+ }
+ /* cgoos */
+ break;
+ case SK_DRV_PORT_RESET: /* SK_U32 PortIdx */
+ /* action list 4 */
+ FromPort = Param.Para32[0];
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("PORT RESET EVENT, Port: %d ", FromPort));
+ NewPara.Para64 = FromPort;
+ SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+ spin_lock_irqsave(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+
+ SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
+ netif_carrier_off(pAC->dev[Param.Para32[0]]);
+ spin_unlock_irqrestore(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+
+ /* clear rx ring from received frames */
+ ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE);
+
+ ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+ spin_lock_irqsave(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+
+ /* tschilling: Handling of return value inserted. */
+ if (SkGeInitPort(pAC, IoC, FromPort)) {
+ if (FromPort == 0) {
+ printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name);
+ } else {
+ printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name);
+ }
+ }
+ SkAddrMcUpdate(pAC,IoC, FromPort);
+ PortReInitBmu(pAC, FromPort);
+ SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+ ClearAndStartRx(pAC, FromPort);
+ spin_unlock_irqrestore(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+ break;
+ case SK_DRV_NET_UP: /* SK_U32 PortIdx */
+ { struct net_device *dev = pAC->dev[Param.Para32[0]];
+ /* action list 5 */
+ FromPort = Param.Para32[0];
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("NET UP EVENT, Port: %d ", Param.Para32[0]));
+ /* Mac update */
+ SkAddrMcUpdate(pAC,IoC, FromPort);
+
+ if (DoPrintInterfaceChange) {
+ printk("%s: network connection up using"
+ " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]);
+
+ /* tschilling: Values changed according to LinkSpeedUsed. */
+ Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed;
+ if (Stat == SK_LSPEED_STAT_10MBPS) {
+ printk(" speed: 10\n");
+ } else if (Stat == SK_LSPEED_STAT_100MBPS) {
+ printk(" speed: 100\n");
+ } else if (Stat == SK_LSPEED_STAT_1000MBPS) {
+ printk(" speed: 1000\n");
+ } else {
+ printk(" speed: unknown\n");
+ }
+
+
+ Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
+ if (Stat == SK_LMODE_STAT_AUTOHALF ||
+ Stat == SK_LMODE_STAT_AUTOFULL) {
+ printk(" autonegotiation: yes\n");
+ }
+ else {
+ printk(" autonegotiation: no\n");
+ }
+ if (Stat == SK_LMODE_STAT_AUTOHALF ||
+ Stat == SK_LMODE_STAT_HALF) {
+ printk(" duplex mode: half\n");
+ }
+ else {
+ printk(" duplex mode: full\n");
+ }
+ Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus;
+ if (Stat == SK_FLOW_STAT_REM_SEND ) {
+ printk(" flowctrl: remote send\n");
+ }
+ else if (Stat == SK_FLOW_STAT_LOC_SEND ){
+ printk(" flowctrl: local send\n");
+ }
+ else if (Stat == SK_FLOW_STAT_SYMMETRIC ){
+ printk(" flowctrl: symmetric\n");
+ }
+ else {
+ printk(" flowctrl: none\n");
+ }
+
+ /* tschilling: Check against CopperType now. */
+ if ((pAC->GIni.GICopperType == SK_TRUE) &&
+ (pAC->GIni.GP[FromPort].PLinkSpeedUsed ==
+ SK_LSPEED_STAT_1000MBPS)) {
+ Stat = pAC->GIni.GP[FromPort].PMSStatus;
+ if (Stat == SK_MS_STAT_MASTER ) {
+ printk(" role: master\n");
+ }
+ else if (Stat == SK_MS_STAT_SLAVE ) {
+ printk(" role: slave\n");
+ }
+ else {
+ printk(" role: ???\n");
+ }
+ }
+
+ /*
+ Display dim (dynamic interrupt moderation)
+ informations
+ */
+ if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC)
+ printk(" irq moderation: static (%d ints/sec)\n",
+ pAC->DynIrqModInfo.MaxModIntsPerSec);
+ else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC)
+ printk(" irq moderation: dynamic (%d ints/sec)\n",
+ pAC->DynIrqModInfo.MaxModIntsPerSec);
+ else
+ printk(" irq moderation: disabled\n");
+
+
+ printk(" scatter-gather: %s\n",
+ (dev->features & NETIF_F_SG) ? "enabled" : "disabled");
+ printk(" tx-checksum: %s\n",
+ (dev->features & NETIF_F_IP_CSUM) ? "enabled" : "disabled");
+ printk(" rx-checksum: %s\n",
+ pAC->RxPort[Param.Para32[0]].RxCsum ? "enabled" : "disabled");
+
+ } else {
+ DoPrintInterfaceChange = SK_TRUE;
+ }
+
+ if ((Param.Para32[0] != pAC->ActivePort) &&
+ (pAC->RlmtNets == 1)) {
+ NewPara.Para32[0] = pAC->ActivePort;
+ NewPara.Para32[1] = Param.Para32[0];
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
+ NewPara);
+ }
+
+ /* Inform the world that link protocol is up. */
+ netif_carrier_on(dev);
+ break;
+ }
+ case SK_DRV_NET_DOWN: /* SK_U32 Reason */
+ /* action list 7 */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("NET DOWN EVENT "));
+ if (DoPrintInterfaceChange) {
+ printk("%s: network connection down\n",
+ pAC->dev[Param.Para32[1]]->name);
+ } else {
+ DoPrintInterfaceChange = SK_TRUE;
+ }
+ netif_carrier_off(pAC->dev[Param.Para32[1]]);
+ break;
+ case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("PORT SWITCH HARD "));
+ case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+ /* action list 6 */
+ printk("%s: switching to port %c\n", pAC->dev[0]->name,
+ 'A'+Param.Para32[1]);
+ case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+ FromPort = Param.Para32[0];
+ ToPort = Param.Para32[1];
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("PORT SWITCH EVENT, From: %d To: %d (Pref %d) ",
+ FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort));
+ NewPara.Para64 = FromPort;
+ SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+ NewPara.Para64 = ToPort;
+ SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+ spin_lock_irqsave(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+ spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+ SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST);
+ SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST);
+ spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+ spin_unlock_irqrestore(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+
+ ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */
+ ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */
+
+ ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+ ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]);
+ spin_lock_irqsave(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+ spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+ pAC->ActivePort = ToPort;
+#if 0
+ SetQueueSizes(pAC);
+#else
+ /* tschilling: New common function with minimum size check. */
+ DualNet = SK_FALSE;
+ if (pAC->RlmtNets == 2) {
+ DualNet = SK_TRUE;
+ }
+
+ if (SkGeInitAssignRamToQueues(
+ pAC,
+ pAC->ActivePort,
+ DualNet)) {
+ spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+ spin_unlock_irqrestore(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+ printk("SkGeInitAssignRamToQueues failed.\n");
+ break;
+ }
+#endif
+ /* tschilling: Handling of return values inserted. */
+ if (SkGeInitPort(pAC, IoC, FromPort) ||
+ SkGeInitPort(pAC, IoC, ToPort)) {
+ printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name);
+ }
+ if (Event == SK_DRV_SWITCH_SOFT) {
+ SkMacRxTxEnable(pAC, IoC, FromPort);
+ }
+ SkMacRxTxEnable(pAC, IoC, ToPort);
+ SkAddrSwap(pAC, IoC, FromPort, ToPort);
+ SkAddrMcUpdate(pAC, IoC, FromPort);
+ SkAddrMcUpdate(pAC, IoC, ToPort);
+ PortReInitBmu(pAC, FromPort);
+ PortReInitBmu(pAC, ToPort);
+ SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+ SkGePollTxD(pAC, IoC, ToPort, SK_TRUE);
+ ClearAndStartRx(pAC, FromPort);
+ ClearAndStartRx(pAC, ToPort);
+ spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+ spin_unlock_irqrestore(
+ &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+ Flags);
+ break;
+ case SK_DRV_RLMT_SEND: /* SK_MBUF *pMb */
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("RLS "));
+ pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
+ pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
+ skb_put(pMsg, pRlmtMbuf->Length);
+ if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+ pMsg) < 0)
+
+ DEV_KFREE_SKB_ANY(pMsg);
+ break;
+ case SK_DRV_TIMER:
+ if (Param.Para32[0] == SK_DRV_MODERATION_TIMER) {
+ /*
+ ** expiration of the moderation timer implies that
+ ** dynamic moderation is to be applied
+ */
+ SkDimStartModerationTimer(pAC);
+ SkDimModerate(pAC);
+ if (pAC->DynIrqModInfo.DisplayStats) {
+ SkDimDisplayModerationSettings(pAC);
+ }
+ } else if (Param.Para32[0] == SK_DRV_RX_CLEANUP_TIMER) {
+ /*
+ ** check if we need to check for descriptors which
+ ** haven't been handled the last millisecs
+ */
+ StartDrvCleanupTimer(pAC);
+ if (pAC->GIni.GIMacsFound == 2) {
+ ReceiveIrq(pAC, &pAC->RxPort[1], SK_FALSE);
+ }
+ ReceiveIrq(pAC, &pAC->RxPort[0], SK_FALSE);
+ } else {
+ printk("Expiration of unknown timer\n");
+ }
+ break;
+ default:
+ break;
+ }
+ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+ ("END EVENT "));
+
+ return (0);
+} /* SkDrvEvent */
+
+
+/*****************************************************************************
+ *
+ * SkErrorLog - log errors
+ *
+ * Description:
+ * This function logs errors to the system buffer and to the console
+ *
+ * Returns:
+ * 0 if everything ok
+ * < 0 on error
+ *
+ */
+void SkErrorLog(
+SK_AC *pAC,
+int ErrClass,
+int ErrNum,
+char *pErrorMsg)
+{
+char ClassStr[80];
+
+ switch (ErrClass) {
+ case SK_ERRCL_OTHER:
+ strcpy(ClassStr, "Other error");
+ break;
+ case SK_ERRCL_CONFIG:
+ strcpy(ClassStr, "Configuration error");
+ break;
+ case SK_ERRCL_INIT:
+ strcpy(ClassStr, "Initialization error");
+ break;
+ case SK_ERRCL_NORES:
+ strcpy(ClassStr, "Out of resources error");
+ break;
+ case SK_ERRCL_SW:
+ strcpy(ClassStr, "internal Software error");
+ break;
+ case SK_ERRCL_HW:
+ strcpy(ClassStr, "Hardware failure");
+ break;
+ case SK_ERRCL_COMM:
+ strcpy(ClassStr, "Communication error");
+ break;
+ }
+ printk(KERN_INFO "%s: -- ERROR --\n Class: %s\n"
+ " Nr: 0x%x\n Msg: %s\n", pAC->dev[0]->name,
+ ClassStr, ErrNum, pErrorMsg);
+
+} /* SkErrorLog */
+
+#ifdef SK_DIAG_SUPPORT
+
+/*****************************************************************************
+ *
+ * SkDrvEnterDiagMode - handles DIAG attach request
+ *
+ * Description:
+ * Notify the kernel to NOT access the card any longer due to DIAG
+ * Deinitialize the Card
+ *
+ * Returns:
+ * int
+ */
+int SkDrvEnterDiagMode(
+SK_AC *pAc) /* pointer to adapter context */
+{
+ DEV_NET *pNet = netdev_priv(pAc->dev[0]);
+ SK_AC *pAC = pNet->pAC;
+
+ SK_MEMCPY(&(pAc->PnmiBackup), &(pAc->PnmiStruct),
+ sizeof(SK_PNMI_STRUCT_DATA));
+
+ pAC->DiagModeActive = DIAG_ACTIVE;
+ if (pAC->BoardLevel > SK_INIT_DATA) {
+ if (netif_running(pAC->dev[0])) {
+ pAC->WasIfUp[0] = SK_TRUE;
+ pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */
+ } else {
+ pAC->WasIfUp[0] = SK_FALSE;
+ }
+ if (pNet != netdev_priv(pAC->dev[1])) {
+ pNet = netdev_priv(pAC->dev[1]);
+ if (netif_running(pAC->dev[1])) {
+ pAC->WasIfUp[1] = SK_TRUE;
+ pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvDeInitAdapter(pAC, 1); /* do SkGeClose */
+ } else {
+ pAC->WasIfUp[1] = SK_FALSE;
+ }
+ }
+ pAC->BoardLevel = SK_INIT_DATA;
+ }
+ return(0);
+}
+
+/*****************************************************************************
+ *
+ * SkDrvLeaveDiagMode - handles DIAG detach request
+ *
+ * Description:
+ * Notify the kernel to may access the card again after use by DIAG
+ * Initialize the Card
+ *
+ * Returns:
+ * int
+ */
+int SkDrvLeaveDiagMode(
+SK_AC *pAc) /* pointer to adapter control context */
+{
+ SK_MEMCPY(&(pAc->PnmiStruct), &(pAc->PnmiBackup),
+ sizeof(SK_PNMI_STRUCT_DATA));
+ pAc->DiagModeActive = DIAG_NOTACTIVE;
+ pAc->Pnmi.DiagAttached = SK_DIAG_IDLE;
+ if (pAc->WasIfUp[0] == SK_TRUE) {
+ pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvInitAdapter(pAc, 0); /* first device */
+ }
+ if (pAc->WasIfUp[1] == SK_TRUE) {
+ pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvInitAdapter(pAc, 1); /* second device */
+ }
+ return(0);
+}
+
+/*****************************************************************************
+ *
+ * ParseDeviceNbrFromSlotName - Evaluate PCI device number
+ *
+ * Description:
+ * This function parses the PCI slot name information string and will
+ * retrieve the devcie number out of it. The slot_name maintianed by
+ * linux is in the form of '02:0a.0', whereas the first two characters
+ * represent the bus number in hex (in the sample above this is
+ * pci bus 0x02) and the next two characters the device number (0x0a).
+ *
+ * Returns:
+ * SK_U32: The device number from the PCI slot name
+ */
+
+static SK_U32 ParseDeviceNbrFromSlotName(
+const char *SlotName) /* pointer to pci slot name eg. '02:0a.0' */
+{
+ char *CurrCharPos = (char *) SlotName;
+ int FirstNibble = -1;
+ int SecondNibble = -1;
+ SK_U32 Result = 0;
+
+ while (*CurrCharPos != '\0') {
+ if (*CurrCharPos == ':') {
+ while (*CurrCharPos != '.') {
+ CurrCharPos++;
+ if ( (*CurrCharPos >= '0') &&
+ (*CurrCharPos <= '9')) {
+ if (FirstNibble == -1) {
+ /* dec. value for '0' */
+ FirstNibble = *CurrCharPos - 48;
+ } else {
+ SecondNibble = *CurrCharPos - 48;
+ }
+ } else if ( (*CurrCharPos >= 'a') &&
+ (*CurrCharPos <= 'f') ) {
+ if (FirstNibble == -1) {
+ FirstNibble = *CurrCharPos - 87;
+ } else {
+ SecondNibble = *CurrCharPos - 87;
+ }
+ } else {
+ Result = 0;
+ }
+ }
+
+ Result = FirstNibble;
+ Result = Result << 4; /* first nibble is higher one */
+ Result = Result | SecondNibble;
+ }
+ CurrCharPos++; /* next character */
+ }
+ return (Result);
+}
+
+/****************************************************************************
+ *
+ * SkDrvDeInitAdapter - deinitialize adapter (this function is only
+ * called if Diag attaches to that card)
+ *
+ * Description:
+ * Close initialized adapter.
+ *
+ * Returns:
+ * 0 - on success
+ * error code - on error
+ */
+static int SkDrvDeInitAdapter(
+SK_AC *pAC, /* pointer to adapter context */
+int devNbr) /* what device is to be handled */
+{
+ struct SK_NET_DEVICE *dev;
+
+ dev = pAC->dev[devNbr];
+
+ /* On Linux 2.6 the network driver does NOT mess with reference
+ ** counts. The driver MUST be able to be unloaded at any time
+ ** due to the possibility of hotplug.
+ */
+ if (SkGeClose(dev) != 0) {
+ return (-1);
+ }
+ return (0);
+
+} /* SkDrvDeInitAdapter() */
+
+/****************************************************************************
+ *
+ * SkDrvInitAdapter - Initialize adapter (this function is only
+ * called if Diag deattaches from that card)
+ *
+ * Description:
+ * Close initialized adapter.
+ *
+ * Returns:
+ * 0 - on success
+ * error code - on error
+ */
+static int SkDrvInitAdapter(
+SK_AC *pAC, /* pointer to adapter context */
+int devNbr) /* what device is to be handled */
+{
+ struct SK_NET_DEVICE *dev;
+
+ dev = pAC->dev[devNbr];
+
+ if (SkGeOpen(dev) != 0) {
+ return (-1);
+ }
+
+ /*
+ ** Use correct MTU size and indicate to kernel TX queue can be started
+ */
+ if (SkGeChangeMtu(dev, dev->mtu) != 0) {
+ return (-1);
+ }
+ return (0);
+
+} /* SkDrvInitAdapter */
+
+#endif
+
+#ifdef DEBUG
+/****************************************************************************/
+/* "debug only" section *****************************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * DumpMsg - print a frame
+ *
+ * Description:
+ * This function prints frames to the system logfile/to the console.
+ *
+ * Returns: N/A
+ *
+ */
+static void DumpMsg(struct sk_buff *skb, char *str)
+{
+ int msglen;
+
+ if (skb == NULL) {
+ printk("DumpMsg(): NULL-Message\n");
+ return;
+ }
+
+ if (skb->data == NULL) {
+ printk("DumpMsg(): Message empty\n");
+ return;
+ }
+
+ msglen = skb->len;
+ if (msglen > 64)
+ msglen = 64;
+
+ printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
+
+ DumpData((char *)skb->data, msglen);
+
+ printk("------- End of message ---------\n");
+} /* DumpMsg */
+
+
+
+/*****************************************************************************
+ *
+ * DumpData - print a data area
+ *
+ * Description:
+ * This function prints a area of data to the system logfile/to the
+ * console.
+ *
+ * Returns: N/A
+ *
+ */
+static void DumpData(char *p, int size)
+{
+register int i;
+int haddr, addr;
+char hex_buffer[180];
+char asc_buffer[180];
+char HEXCHAR[] = "0123456789ABCDEF";
+
+ addr = 0;
+ haddr = 0;
+ hex_buffer[0] = 0;
+ asc_buffer[0] = 0;
+ for (i=0; i < size; ) {
+ if (*p >= '0' && *p <='z')
+ asc_buffer[addr] = *p;
+ else
+ asc_buffer[addr] = '.';
+ addr++;
+ asc_buffer[addr] = 0;
+ hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[*p & 0x0f];
+ haddr++;
+ hex_buffer[haddr] = ' ';
+ haddr++;
+ hex_buffer[haddr] = 0;
+ p++;
+ i++;
+ if (i%16 == 0) {
+ printk("%s %s\n", hex_buffer, asc_buffer);
+ addr = 0;
+ haddr = 0;
+ }
+ }
+} /* DumpData */
+
+
+/*****************************************************************************
+ *
+ * DumpLong - print a data area as long values
+ *
+ * Description:
+ * This function prints a area of data to the system logfile/to the
+ * console.
+ *
+ * Returns: N/A
+ *
+ */
+static void DumpLong(char *pc, int size)
+{
+register int i;
+int haddr, addr;
+char hex_buffer[180];
+char asc_buffer[180];
+char HEXCHAR[] = "0123456789ABCDEF";
+long *p;
+int l;
+
+ addr = 0;
+ haddr = 0;
+ hex_buffer[0] = 0;
+ asc_buffer[0] = 0;
+ p = (long*) pc;
+ for (i=0; i < size; ) {
+ l = (long) *p;
+ hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf];
+ haddr++;
+ hex_buffer[haddr] = HEXCHAR[l & 0x0f];
+ haddr++;
+ hex_buffer[haddr] = ' ';
+ haddr++;
+ hex_buffer[haddr] = 0;
+ p++;
+ i++;
+ if (i%8 == 0) {
+ printk("%4x %s\n", (i-8)*4, hex_buffer);
+ haddr = 0;
+ }
+ }
+ printk("------------------------\n");
+} /* DumpLong */
+
+#endif
+
+static int __devinit skge_probe_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ SK_AC *pAC;
+ DEV_NET *pNet = NULL;
+ struct net_device *dev = NULL;
+ static int boards_found = 0;
+ int error = -ENODEV;
+ int using_dac = 0;
+ char DeviceStr[80];
+
+ if (pci_enable_device(pdev))
+ goto out;
+
+ /* Configure DMA attributes. */
+ if (sizeof(dma_addr_t) > sizeof(u32) &&
+ !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+ using_dac = 1;
+ error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error < 0) {
+ printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+ "for consistent allocations\n", pci_name(pdev));
+ goto out_disable_device;
+ }
+ } else {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+ pci_name(pdev));
+ goto out_disable_device;
+ }
+ }
+
+ error = -ENOMEM;
+ dev = alloc_etherdev(sizeof(DEV_NET));
+ if (!dev) {
+ printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+ "structure!\n");
+ goto out_disable_device;
+ }
+
+ pNet = netdev_priv(dev);
+ pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
+ if (!pNet->pAC) {
+ printk(KERN_ERR "sk98lin: unable to allocate adapter "
+ "structure!\n");
+ goto out_free_netdev;
+ }
+
+ pAC = pNet->pAC;
+ pAC->PciDev = pdev;
+
+ pAC->dev[0] = dev;
+ pAC->dev[1] = dev;
+ pAC->CheckQueue = SK_FALSE;
+
+ dev->irq = pdev->irq;
+
+ error = SkGeInitPCI(pAC);
+ if (error) {
+ printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
+ goto out_free_netdev;
+ }
+
+ dev->open = &SkGeOpen;
+ dev->stop = &SkGeClose;
+ dev->hard_start_xmit = &SkGeXmit;
+ dev->get_stats = &SkGeStats;
+ dev->set_multicast_list = &SkGeSetRxMode;
+ dev->set_mac_address = &SkGeSetMacAddr;
+ dev->do_ioctl = &SkGeIoctl;
+ dev->change_mtu = &SkGeChangeMtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = &SkGePollController;
+#endif
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+ /* Use only if yukon hardware */
+ if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+ dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+ dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+ pAC->RxPort[0].RxCsum = 1;
+#endif
+ }
+
+ if (using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ pAC->Index = boards_found++;
+
+ error = SkGeBoardInit(dev, pAC);
+ if (error)
+ goto out_free_netdev;
+
+ /* Read Adapter name from VPD */
+ if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+ error = -EIO;
+ printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
+ goto out_free_resources;
+ }
+
+ /* Register net device */
+ error = register_netdev(dev);
+ if (error) {
+ printk(KERN_ERR "sk98lin: Could not register device.\n");
+ goto out_free_resources;
+ }
+
+ /* Print adapter specific string from vpd */
+ printk("%s: %s\n", dev->name, DeviceStr);
+
+ /* Print configuration settings */
+ printk(" PrefPort:%c RlmtMode:%s\n",
+ 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber,
+ (pAC->RlmtMode==0) ? "Check Link State" :
+ ((pAC->RlmtMode==1) ? "Check Link State" :
+ ((pAC->RlmtMode==3) ? "Check Local Port" :
+ ((pAC->RlmtMode==7) ? "Check Segmentation" :
+ ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
+
+ SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+ memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ pNet->PortNr = 0;
+ pNet->NetNr = 0;
+
+ boards_found++;
+
+ pci_set_drvdata(pdev, dev);
+
+ /* More then one port found */
+ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+ dev = alloc_etherdev(sizeof(DEV_NET));
+ if (!dev) {
+ printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+ "structure!\n");
+ goto single_port;
+ }
+
+ pNet = netdev_priv(dev);
+ pNet->PortNr = 1;
+ pNet->NetNr = 1;
+ pNet->pAC = pAC;
+
+ dev->open = &SkGeOpen;
+ dev->stop = &SkGeClose;
+ dev->hard_start_xmit = &SkGeXmit;
+ dev->get_stats = &SkGeStats;
+ dev->set_multicast_list = &SkGeSetRxMode;
+ dev->set_mac_address = &SkGeSetMacAddr;
+ dev->do_ioctl = &SkGeIoctl;
+ dev->change_mtu = &SkGeChangeMtu;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+ if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+ dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+ dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+ pAC->RxPort[1].RxCsum = 1;
+#endif
+ }
+
+ if (using_dac)
+ dev->features |= NETIF_F_HIGHDMA;
+
+ error = register_netdev(dev);
+ if (error) {
+ printk(KERN_ERR "sk98lin: Could not register device"
+ " for second port. (%d)\n", error);
+ free_netdev(dev);
+ goto single_port;
+ }
+
+ pAC->dev[1] = dev;
+ memcpy(&dev->dev_addr,
+ &pAC->Addr.Net[1].CurrentMacAddress, 6);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ printk("%s: %s\n", dev->name, DeviceStr);
+ printk(" PrefPort:B RlmtMode:Dual Check Link State\n");
+ }
+
+single_port:
+
+ /* Save the hardware revision */
+ pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
+ (pAC->GIni.GIPciHwRev & 0x0F);
+
+ /* Set driver globals */
+ pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME;
+ pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE;
+
+ memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
+ memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
+
+ return 0;
+
+ out_free_resources:
+ FreeResources(dev);
+ out_free_netdev:
+ free_netdev(dev);
+ out_disable_device:
+ pci_disable_device(pdev);
+ out:
+ return error;
+}
+
+static void __devexit skge_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ struct net_device *otherdev = pAC->dev[1];
+
+ unregister_netdev(dev);
+
+ SkGeYellowLED(pAC, pAC->IoBase, 0);
+
+ if (pAC->BoardLevel == SK_INIT_RUN) {
+ SK_EVPARA EvPara;
+ unsigned long Flags;
+
+ /* board is still alive */
+ spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+ EvPara.Para32[0] = 0;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ EvPara.Para32[0] = 1;
+ EvPara.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+ SkEventDispatcher(pAC, pAC->IoBase);
+ /* disable interrupts */
+ SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+ SkGeDeInit(pAC, pAC->IoBase);
+ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+ pAC->BoardLevel = SK_INIT_DATA;
+ /* We do NOT check here, if IRQ was pending, of course*/
+ }
+
+ if (pAC->BoardLevel == SK_INIT_IO) {
+ /* board is still alive */
+ SkGeDeInit(pAC, pAC->IoBase);
+ pAC->BoardLevel = SK_INIT_DATA;
+ }
+
+ FreeResources(dev);
+ free_netdev(dev);
+ if (otherdev != dev)
+ free_netdev(otherdev);
+ kfree(pAC);
+}
+
+#ifdef CONFIG_PM
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ struct net_device *otherdev = pAC->dev[1];
+
+ if (netif_running(dev)) {
+ netif_carrier_off(dev);
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvDeInitAdapter(pAC, 0); /* performs SkGeClose */
+ netif_device_detach(dev);
+ }
+ if (otherdev != dev) {
+ if (netif_running(otherdev)) {
+ netif_carrier_off(otherdev);
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvDeInitAdapter(pAC, 1); /* performs SkGeClose */
+ netif_device_detach(otherdev);
+ }
+ }
+
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ if (pAC->AllocFlag & SK_ALLOC_IRQ) {
+ free_irq(dev->irq, dev);
+ }
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int skge_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ DEV_NET *pNet = netdev_priv(dev);
+ SK_AC *pAC = pNet->pAC;
+ struct net_device *otherdev = pAC->dev[1];
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ printk(KERN_WARNING "sk98lin: unable to enable device %s "
+ "in resume\n", dev->name);
+ goto err_out;
+ }
+ pci_set_master(pdev);
+ if (pAC->GIni.GIMacsFound == 2)
+ ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+ else
+ ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
+ if (ret) {
+ printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
+ ret = -EBUSY;
+ goto err_out_disable_pdev;
+ }
+
+ netif_device_attach(dev);
+ if (netif_running(dev)) {
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvInitAdapter(pAC, 0); /* first device */
+ }
+ if (otherdev != dev) {
+ netif_device_attach(otherdev);
+ if (netif_running(otherdev)) {
+ DoPrintInterfaceChange = SK_FALSE;
+ SkDrvInitAdapter(pAC, 1); /* second device */
+ }
+ }
+
+ return 0;
+
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+err_out:
+ pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+ dev->irq = 0;
+ return ret;
+}
+#else
+#define skge_suspend NULL
+#define skge_resume NULL
+#endif
+
+static struct pci_device_id skge_pci_tbl[] = {
+#ifdef SK98LIN_ALL_DEVICES
+ { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+#ifdef GENESIS
+ /* Generic SysKonnect SK-98xx Gigabit Ethernet Server Adapter */
+ { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+ /* Generic SysKonnect SK-98xx V2.0 Gigabit Ethernet Adapter */
+ { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#ifdef SK98LIN_ALL_DEVICES
+/* DLink card does not have valid VPD so this driver gags
+ * { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ */
+ { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
+ { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
+
+static struct pci_driver skge_driver = {
+ .name = "sk98lin",
+ .id_table = skge_pci_tbl,
+ .probe = skge_probe_one,
+ .remove = __devexit_p(skge_remove_one),
+ .suspend = skge_suspend,
+ .resume = skge_resume,
+};
+
+static int __init skge_init(void)
+{
+ printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver"
+ " and is scheduled for removal\n");
+
+ return pci_register_driver(&skge_driver);
+}
+
+static void __exit skge_exit(void)
+{
+ pci_unregister_driver(&skge_driver);
+}
+
+module_init(skge_init);
+module_exit(skge_exit);
diff --git a/drivers/net/sk98lin/skgehwt.c b/drivers/net/sk98lin/skgehwt.c
new file mode 100644
index 000000000000..db670993c2df
--- /dev/null
+++ b/drivers/net/sk98lin/skgehwt.c
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Name: skgehwt.c
+ * Project: Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version: $Revision: 1.15 $
+ * Date: $Date: 2003/09/16 13:41:23 $
+ * Purpose: Hardware Timer
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skgehwt.c,v 1.15 2003/09/16 13:41:23 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h" /* Driver Specific Definitions */
+#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+ * Hardware Timer function queue management.
+ */
+intro()
+{}
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+#define SK_HWT_MAX (65000)
+
+/* correction factor */
+#define SK_HWT_FAC (1000 * (SK_U32)pAC->GIni.GIHstClkFact / 100)
+
+/*
+ * Initialize hardware timer.
+ *
+ * Must be called during init level 1.
+ */
+void SkHwtInit(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc) /* IoContext */
+{
+ pAC->Hwt.TStart = 0 ;
+ pAC->Hwt.TStop = 0 ;
+ pAC->Hwt.TActive = SK_FALSE;
+
+ SkHwtStop(pAC, Ioc);
+}
+
+/*
+ *
+ * Start hardware timer (clock ticks are 16us).
+ *
+ */
+void SkHwtStart(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc, /* IoContext */
+SK_U32 Time) /* Time in units of 16us to load the timer with. */
+{
+ SK_U32 Cnt;
+
+ if (Time > SK_HWT_MAX)
+ Time = SK_HWT_MAX;
+
+ pAC->Hwt.TStart = Time;
+ pAC->Hwt.TStop = 0L;
+
+ Cnt = Time;
+
+ /*
+ * if time < 16 us
+ * time = 16 us
+ */
+ if (!Cnt) {
+ Cnt++;
+ }
+
+ SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC);
+
+ SK_OUT16(Ioc, B2_TI_CTRL, TIM_START); /* Start timer. */
+
+ pAC->Hwt.TActive = SK_TRUE;
+}
+
+/*
+ * Stop hardware timer.
+ * and clear the timer IRQ
+ */
+void SkHwtStop(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc) /* IoContext */
+{
+ SK_OUT16(Ioc, B2_TI_CTRL, TIM_STOP);
+
+ SK_OUT16(Ioc, B2_TI_CTRL, TIM_CLR_IRQ);
+
+ pAC->Hwt.TActive = SK_FALSE;
+}
+
+
+/*
+ * Stop hardware timer and read time elapsed since last start.
+ *
+ * returns
+ * The elapsed time since last start in units of 16us.
+ *
+ */
+SK_U32 SkHwtRead(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc) /* IoContext */
+{
+ SK_U32 TRead;
+ SK_U32 IStatus;
+
+ if (pAC->Hwt.TActive) {
+
+ SkHwtStop(pAC, Ioc);
+
+ SK_IN32(Ioc, B2_TI_VAL, &TRead);
+ TRead /= SK_HWT_FAC;
+
+ SK_IN32(Ioc, B0_ISRC, &IStatus);
+
+ /* Check if timer expired (or wraped around) */
+ if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) {
+
+ SkHwtStop(pAC, Ioc);
+
+ pAC->Hwt.TStop = pAC->Hwt.TStart;
+ }
+ else {
+
+ pAC->Hwt.TStop = pAC->Hwt.TStart - TRead;
+ }
+ }
+ return(pAC->Hwt.TStop);
+}
+
+/*
+ * interrupt source= timer
+ */
+void SkHwtIsr(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc) /* IoContext */
+{
+ SkHwtStop(pAC, Ioc);
+
+ pAC->Hwt.TStop = pAC->Hwt.TStart;
+
+ SkTimerDone(pAC, Ioc);
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c
new file mode 100644
index 000000000000..67f1d6a5c15d
--- /dev/null
+++ b/drivers/net/sk98lin/skgeinit.c
@@ -0,0 +1,2005 @@
+/******************************************************************************
+ *
+ * Name: skgeinit.c
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.97 $
+ * Date: $Date: 2003/10/02 16:45:31 $
+ * Purpose: Contains functions to initialize the adapter
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skgeinit.c,v 1.97 2003/10/02 16:45:31 rschmidt Exp $ (C) Marvell.";
+#endif
+
+struct s_QOffTab {
+ int RxQOff; /* Receive Queue Address Offset */
+ int XsQOff; /* Sync Tx Queue Address Offset */
+ int XaQOff; /* Async Tx Queue Address Offset */
+};
+static struct s_QOffTab QOffTab[] = {
+ {Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2}
+};
+
+struct s_Config {
+ char ScanString[8];
+ SK_U32 Value;
+};
+
+static struct s_Config OemConfig = {
+ {'O','E','M','_','C','o','n','f'},
+#ifdef SK_OEM_CONFIG
+ OEM_CONFIG_VALUE,
+#else
+ 0,
+#endif
+};
+
+/******************************************************************************
+ *
+ * SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
+ *
+ * Description:
+ * Enable or disable the descriptor polling of the transmit descriptor
+ * ring(s) (TxD) for port 'Port'.
+ * The new configuration is *not* saved over any SkGeStopPort() and
+ * SkGeInitPort() calls.
+ *
+ * Returns:
+ * nothing
+ */
+void SkGePollTxD(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL PollTxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+ SK_GEPORT *pPrt;
+ SK_U32 DWord;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ DWord = (SK_U32)(PollTxD ? CSR_ENA_POL : CSR_DIS_POL);
+
+ if (pPrt->PXSQSize != 0) {
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
+ }
+
+ if (pPrt->PXAQSize != 0) {
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
+ }
+} /* SkGePollTxD */
+
+
+/******************************************************************************
+ *
+ * SkGeYellowLED() - Switch the yellow LED on or off.
+ *
+ * Description:
+ * Switch the yellow LED on or off.
+ *
+ * Note:
+ * This function may be called any time after SkGeInit(Level 1).
+ *
+ * Returns:
+ * nothing
+ */
+void SkGeYellowLED(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int State) /* yellow LED state, 0 = OFF, 0 != ON */
+{
+ if (State == 0) {
+ /* Switch yellow LED OFF */
+ SK_OUT8(IoC, B0_LED, LED_STAT_OFF);
+ }
+ else {
+ /* Switch yellow LED ON */
+ SK_OUT8(IoC, B0_LED, LED_STAT_ON);
+ }
+} /* SkGeYellowLED */
+
+
+#if (!defined(SK_SLIM) || defined(GENESIS))
+/******************************************************************************
+ *
+ * SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
+ *
+ * Description:
+ * The Rx or Tx LED which is specified by 'Led' will be
+ * enabled, disabled or switched on in test mode.
+ *
+ * Note:
+ * 'Led' must contain the address offset of the LEDs INI register.
+ *
+ * Usage:
+ * SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+ *
+ * Returns:
+ * nothing
+ */
+void SkGeXmitLED(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Led, /* offset to the LED Init Value register */
+int Mode) /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
+{
+ SK_U32 LedIni;
+
+ switch (Mode) {
+ case SK_LED_ENA:
+ LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+ SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni);
+ SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+ break;
+ case SK_LED_TST:
+ SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON);
+ SK_OUT32(IoC, Led + XMIT_LED_CNT, 100);
+ SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+ break;
+ case SK_LED_DIS:
+ default:
+ /*
+ * Do NOT stop the LED Timer here. The LED might be
+ * in on state. But it needs to go off.
+ */
+ SK_OUT32(IoC, Led + XMIT_LED_CNT, 0);
+ SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF);
+ break;
+ }
+
+ /*
+ * 1000BT: The Transmit LED is driven by the PHY.
+ * But the default LED configuration is used for
+ * Level One and Broadcom PHYs.
+ * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.)
+ * (In this case it has to be added here. But we will see. XXX)
+ */
+} /* SkGeXmitLED */
+#endif /* !SK_SLIM || GENESIS */
+
+
+/******************************************************************************
+ *
+ * DoCalcAddr() - Calculates the start and the end address of a queue.
+ *
+ * Description:
+ * This function calculates the start and the end address of a queue.
+ * Afterwards the 'StartVal' is incremented to the next start position.
+ * If the port is already initialized the calculated values
+ * will be checked against the configured values and an
+ * error will be returned, if they are not equal.
+ * If the port is not initialized the values will be written to
+ * *StartAdr and *EndAddr.
+ *
+ * Returns:
+ * 0: success
+ * 1: configuration error
+ */
+static int DoCalcAddr(
+SK_AC *pAC, /* adapter context */
+SK_GEPORT SK_FAR *pPrt, /* port index */
+int QuSize, /* size of the queue to configure in kB */
+SK_U32 SK_FAR *StartVal, /* start value for address calculation */
+SK_U32 SK_FAR *QuStartAddr,/* start addr to calculate */
+SK_U32 SK_FAR *QuEndAddr) /* end address to calculate */
+{
+ SK_U32 EndVal;
+ SK_U32 NextStart;
+ int Rtv;
+
+ Rtv = 0;
+ if (QuSize == 0) {
+ EndVal = *StartVal;
+ NextStart = EndVal;
+ }
+ else {
+ EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
+ NextStart = EndVal + 1;
+ }
+
+ if (pPrt->PState >= SK_PRT_INIT) {
+ if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
+ Rtv = 1;
+ }
+ }
+ else {
+ *QuStartAddr = *StartVal;
+ *QuEndAddr = EndVal;
+ }
+
+ *StartVal = NextStart;
+ return(Rtv);
+} /* DoCalcAddr */
+
+/******************************************************************************
+ *
+ * SkGeInitAssignRamToQueues() - allocate default queue sizes
+ *
+ * Description:
+ * This function assigns the memory to the different queues and ports.
+ * When DualNet is set to SK_TRUE all ports get the same amount of memory.
+ * Otherwise the first port gets most of the memory and all the
+ * other ports just the required minimum.
+ * This function can only be called when pAC->GIni.GIRamSize and
+ * pAC->GIni.GIMacsFound have been initialized, usually this happens
+ * at init level 1
+ *
+ * Returns:
+ * 0 - ok
+ * 1 - invalid input values
+ * 2 - not enough memory
+ */
+
+int SkGeInitAssignRamToQueues(
+SK_AC *pAC, /* Adapter context */
+int ActivePort, /* Active Port in RLMT mode */
+SK_BOOL DualNet) /* adapter context */
+{
+ int i;
+ int UsedKilobytes; /* memory already assigned */
+ int ActivePortKilobytes; /* memory available for active port */
+ SK_GEPORT *pGePort;
+
+ UsedKilobytes = 0;
+
+ if (ActivePort >= pAC->GIni.GIMacsFound) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+ ("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
+ ActivePort));
+ return(1);
+ }
+ if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) +
+ ((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+ ("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
+ pAC->GIni.GIRamSize));
+ return(2);
+ }
+
+ if (DualNet) {
+ /* every port gets the same amount of memory */
+ ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound;
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+ pGePort = &pAC->GIni.GP[i];
+
+ /* take away the minimum memory for active queues */
+ ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+
+ /* receive queue gets the minimum + 80% of the rest */
+ pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((
+ ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100))
+ + SK_MIN_RXQ_SIZE;
+
+ ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+ /* synchronous transmit queue */
+ pGePort->PXSQSize = 0;
+
+ /* asynchronous transmit queue */
+ pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes +
+ SK_MIN_TXQ_SIZE);
+ }
+ }
+ else {
+ /* Rlmt Mode or single link adapter */
+
+ /* Set standby queue size defaults for all standby ports */
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+ if (i != ActivePort) {
+ pGePort = &pAC->GIni.GP[i];
+
+ pGePort->PRxQSize = SK_MIN_RXQ_SIZE;
+ pGePort->PXAQSize = SK_MIN_TXQ_SIZE;
+ pGePort->PXSQSize = 0;
+
+ /* Count used RAM */
+ UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize;
+ }
+ }
+ /* what's left? */
+ ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes;
+
+ /* assign it to the active port */
+ /* first take away the minimum memory */
+ ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+ pGePort = &pAC->GIni.GP[ActivePort];
+
+ /* receive queue get's the minimum + 80% of the rest */
+ pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes *
+ (unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE;
+
+ ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+ /* synchronous transmit queue */
+ pGePort->PXSQSize = 0;
+
+ /* asynchronous transmit queue */
+ pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) +
+ SK_MIN_TXQ_SIZE;
+ }
+#ifdef VCPU
+ VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n",
+ pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize);
+#endif /* VCPU */
+
+ return(0);
+} /* SkGeInitAssignRamToQueues */
+
+/******************************************************************************
+ *
+ * SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
+ *
+ * Description:
+ * This function verifies the Queue Size Configuration specified
+ * in the variables PRxQSize, PXSQSize, and PXAQSize of all
+ * used ports.
+ * This requirements must be fullfilled to have a valid configuration:
+ * - The size of all queues must not exceed GIRamSize.
+ * - The queue sizes must be specified in units of 8 kB.
+ * - The size of Rx queues of available ports must not be
+ * smaller than 16 kB.
+ * - The size of at least one Tx queue (synch. or asynch.)
+ * of available ports must not be smaller than 16 kB
+ * when Jumbo Frames are used.
+ * - The RAM start and end addresses must not be changed
+ * for ports which are already initialized.
+ * Furthermore SkGeCheckQSize() defines the Start and End Addresses
+ * of all ports and stores them into the HWAC port structure.
+ *
+ * Returns:
+ * 0: Queue Size Configuration valid
+ * 1: Queue Size Configuration invalid
+ */
+static int SkGeCheckQSize(
+SK_AC *pAC, /* adapter context */
+int Port) /* port index */
+{
+ SK_GEPORT *pPrt;
+ int i;
+ int Rtv;
+ int Rtv2;
+ SK_U32 StartAddr;
+#ifndef SK_SLIM
+ int UsedMem; /* total memory used (max. found ports) */
+#endif
+
+ Rtv = 0;
+
+#ifndef SK_SLIM
+
+ UsedMem = 0;
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+ pPrt = &pAC->GIni.GP[i];
+
+ if ((pPrt->PRxQSize & QZ_UNITS) != 0 ||
+ (pPrt->PXSQSize & QZ_UNITS) != 0 ||
+ (pPrt->PXAQSize & QZ_UNITS) != 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+ return(1);
+ }
+
+ if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
+ return(1);
+ }
+
+ /*
+ * the size of at least one Tx queue (synch. or asynch.) has to be > 0.
+ * if Jumbo Frames are used, this size has to be >= 16 kB.
+ */
+ if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
+ (pAC->GIni.GIPortUsage == SK_JUMBO_LINK &&
+ ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
+ (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
+ return(1);
+ }
+
+ UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
+ }
+
+ if (UsedMem > pAC->GIni.GIRamSize) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+ return(1);
+ }
+#endif /* !SK_SLIM */
+
+ /* Now start address calculation */
+ StartAddr = pAC->GIni.GIRamOffs;
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+ pPrt = &pAC->GIni.GP[i];
+
+ /* Calculate/Check values for the receive queue */
+ Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
+ &pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
+ Rtv |= Rtv2;
+
+ /* Calculate/Check values for the synchronous Tx queue */
+ Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
+ &pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
+ Rtv |= Rtv2;
+
+ /* Calculate/Check values for the asynchronous Tx queue */
+ Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
+ &pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
+ Rtv |= Rtv2;
+
+ if (Rtv) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
+ return(1);
+ }
+ }
+
+ return(0);
+} /* SkGeCheckQSize */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGeInitMacArb() - Initialize the MAC Arbiter
+ *
+ * Description:
+ * This function initializes the MAC Arbiter.
+ * It must not be called if there is still an
+ * initialized or active port.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInitMacArb(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+ /* release local reset */
+ SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);
+
+ /* configure timeout values */
+ SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+ SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+ SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+ SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+ SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
+ SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
+ SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
+ SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);
+
+ /* recovery values are needed for XMAC II Rev. B2 only */
+ /* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
+
+ /*
+ * There is no start or enable button to push, therefore
+ * the MAC arbiter is configured and enabled now.
+ */
+} /* SkGeInitMacArb */
+
+
+/******************************************************************************
+ *
+ * SkGeInitPktArb() - Initialize the Packet Arbiter
+ *
+ * Description:
+ * This function initializes the Packet Arbiter.
+ * It must not be called if there is still an
+ * initialized or active port.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInitPktArb(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+ /* release local reset */
+ SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);
+
+ /* configure timeout values */
+ SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+ SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+ SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+ SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+
+ /*
+ * enable timeout timers if jumbo frames not used
+ * NOTE: the packet arbiter timeout interrupt is needed for
+ * half duplex hangup workaround
+ */
+ if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
+ if (pAC->GIni.GIMacsFound == 1) {
+ SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
+ }
+ else {
+ SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
+ }
+ }
+} /* SkGeInitPktArb */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkGeInitMacFifo() - Initialize the MAC FIFOs
+ *
+ * Description:
+ * Initialize all MAC FIFOs of the specified port
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInitMacFifo(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U16 Word;
+#ifdef VCPU
+ SK_U32 DWord;
+#endif /* VCPU */
+ /*
+ * For each FIFO:
+ * - release local reset
+ * - use default value for MAC FIFO size
+ * - setup defaults for the control register
+ * - enable the FIFO
+ */
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* Configure Rx MAC FIFO */
+ SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
+ SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
+ SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+ /* Configure Tx MAC FIFO */
+ SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
+ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+ SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+ /* Enable frame flushing if jumbo frames used */
+ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+ SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* set Rx GMAC FIFO Flush Mask */
+ SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);
+
+ Word = (SK_U16)GMF_RX_CTRL_DEF;
+
+ /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
+ if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+
+ Word &= ~GMF_RX_F_FL_ON;
+ }
+
+ /* Configure Rx MAC FIFO */
+ SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+ SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word);
+
+ /* set Rx GMAC FIFO Flush Threshold (default: 0x0a -> 56 bytes) */
+ SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+
+ /* Configure Tx MAC FIFO */
+ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+ SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF);
+
+#ifdef VCPU
+ SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord);
+ SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord);
+#endif /* VCPU */
+
+ /* set Tx GMAC FIFO Almost Empty Threshold */
+/* SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */
+ }
+#endif /* YUKON */
+
+} /* SkGeInitMacFifo */
+
+#ifdef SK_LNK_SYNC_CNT
+/******************************************************************************
+ *
+ * SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
+ *
+ * Description:
+ * This function starts the Link Sync Counter of the specified
+ * port and enables the generation of an Link Sync IRQ.
+ * The Link Sync Counter may be used to detect an active link,
+ * if autonegotiation is not used.
+ *
+ * Note:
+ * o To ensure receiving the Link Sync Event the LinkSyncCounter
+ * should be initialized BEFORE clearing the XMAC's reset!
+ * o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
+ * function.
+ *
+ * Returns:
+ * nothing
+ */
+void SkGeLoadLnkSyncCnt(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_U32 CntVal) /* Counter value */
+{
+ SK_U32 OrgIMsk;
+ SK_U32 NewIMsk;
+ SK_U32 ISrc;
+ SK_BOOL IrqPend;
+
+ /* stop counter */
+ SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP);
+
+ /*
+ * ASIC problem:
+ * Each time starting the Link Sync Counter an IRQ is generated
+ * by the adapter. See problem report entry from 21.07.98
+ *
+ * Workaround: Disable Link Sync IRQ and clear the unexpeced IRQ
+ * if no IRQ is already pending.
+ */
+ IrqPend = SK_FALSE;
+ SK_IN32(IoC, B0_ISRC, &ISrc);
+ SK_IN32(IoC, B0_IMSK, &OrgIMsk);
+ if (Port == MAC_1) {
+ NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
+ if ((ISrc & IS_LNK_SYNC_M1) != 0) {
+ IrqPend = SK_TRUE;
+ }
+ }
+ else {
+ NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
+ if ((ISrc & IS_LNK_SYNC_M2) != 0) {
+ IrqPend = SK_TRUE;
+ }
+ }
+ if (!IrqPend) {
+ SK_OUT32(IoC, B0_IMSK, NewIMsk);
+ }
+
+ /* load counter */
+ SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal);
+
+ /* start counter */
+ SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START);
+
+ if (!IrqPend) {
+ /* clear the unexpected IRQ, and restore the interrupt mask */
+ SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ);
+ SK_OUT32(IoC, B0_IMSK, OrgIMsk);
+ }
+} /* SkGeLoadLnkSyncCnt*/
+#endif /* SK_LNK_SYNC_CNT */
+
+#if defined(SK_DIAG) || defined(SK_CFG_SYNC)
+/******************************************************************************
+ *
+ * SkGeCfgSync() - Configure synchronous bandwidth for this port.
+ *
+ * Description:
+ * This function may be used to configure synchronous bandwidth
+ * to the specified port. This may be done any time after
+ * initializing the port. The configuration values are NOT saved
+ * in the HWAC port structure and will be overwritten any
+ * time when stopping and starting the port.
+ * Any values for the synchronous configuration will be ignored
+ * if the size of the synchronous queue is zero!
+ *
+ * The default configuration for the synchronous service is
+ * TXA_ENA_FSYNC. This means if the size of
+ * the synchronous queue is unequal zero but no specific
+ * synchronous bandwidth is configured, the synchronous queue
+ * will always have the 'unlimited' transmit priority!
+ *
+ * This mode will be restored if the synchronous bandwidth is
+ * deallocated ('IntTime' = 0 and 'LimCount' = 0).
+ *
+ * Returns:
+ * 0: success
+ * 1: parameter configuration error
+ * 2: try to configure quality of service although no
+ * synchronous queue is configured
+ */
+int SkGeCfgSync(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_U32 IntTime, /* Interval Timer Value in units of 8ns */
+SK_U32 LimCount, /* Number of bytes to transfer during IntTime */
+int SyncMode) /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
+{
+ int Rtv;
+
+ Rtv = 0;
+
+ /* check the parameters */
+ if (LimCount > IntTime ||
+ (LimCount == 0 && IntTime != 0) ||
+ (LimCount != 0 && IntTime == 0)) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+ return(1);
+ }
+
+ if (pAC->GIni.GP[Port].PXSQSize == 0) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
+ return(2);
+ }
+
+ /* calculate register values */
+ IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
+ LimCount = LimCount / 8;
+
+ if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+ return(1);
+ }
+
+ /*
+ * - Enable 'Force Sync' to ensure the synchronous queue
+ * has the priority while configuring the new values.
+ * - Also 'disable alloc' to ensure the settings complies
+ * to the SyncMode parameter.
+ * - Disable 'Rate Control' to configure the new values.
+ * - write IntTime and LimCount
+ * - start 'Rate Control' and disable 'Force Sync'
+ * if Interval Timer or Limit Counter not zero.
+ */
+ SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+ TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+ SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
+ SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
+
+ SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+ (SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));
+
+ if (IntTime != 0 || LimCount != 0) {
+ SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
+ }
+
+ return(0);
+} /* SkGeCfgSync */
+#endif /* SK_DIAG || SK_CFG_SYNC*/
+
+
+/******************************************************************************
+ *
+ * DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
+ *
+ * Desccription:
+ * If the queue is used, enable and initialize it.
+ * Make sure the queue is still reset, if it is not used.
+ *
+ * Returns:
+ * nothing
+ */
+static void DoInitRamQueue(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int QuIoOffs, /* Queue IO Address Offset */
+SK_U32 QuStartAddr, /* Queue Start Address */
+SK_U32 QuEndAddr, /* Queue End Address */
+int QuType) /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
+{
+ SK_U32 RxUpThresVal;
+ SK_U32 RxLoThresVal;
+
+ if (QuStartAddr != QuEndAddr) {
+ /* calculate thresholds, assume we have a big Rx queue */
+ RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
+ RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;
+
+ /* build HW address format */
+ QuStartAddr = QuStartAddr / 8;
+ QuEndAddr = QuEndAddr / 8;
+
+ /* release local reset */
+ SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR);
+
+ /* configure addresses */
+ SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr);
+ SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr);
+ SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr);
+ SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr);
+
+ switch (QuType) {
+ case SK_RX_SRAM_Q:
+ /* configure threshold for small Rx Queue */
+ RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;
+
+ /* continue with SK_RX_BRAM_Q */
+ case SK_RX_BRAM_Q:
+ /* write threshold for Rx Queue */
+
+ SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
+ SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);
+
+ /* the high priority threshold not used */
+ break;
+ case SK_TX_RAM_Q:
+ /*
+ * Do NOT use Store & Forward under normal operation due to
+ * performance optimization (GENESIS only).
+ * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
+ * or YUKON is used ((GMAC Tx FIFO is only 1 kB)
+ * we NEED Store & Forward of the RAM buffer.
+ */
+ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK ||
+ pAC->GIni.GIYukon) {
+ /* enable Store & Forward Mode for the Tx Side */
+ SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
+ }
+ break;
+ }
+
+ /* set queue operational */
+ SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD);
+ }
+ else {
+ /* ensure the queue is still disabled */
+ SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
+ }
+} /* DoInitRamQueue */
+
+
+/******************************************************************************
+ *
+ * SkGeInitRamBufs() - Initialize the RAM Buffer Queues
+ *
+ * Description:
+ * Initialize all RAM Buffer Queues of the specified port
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInitRamBufs(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ int RxQType;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) {
+ RxQType = SK_RX_SRAM_Q; /* small Rx Queue */
+ }
+ else {
+ RxQType = SK_RX_BRAM_Q; /* big Rx Queue */
+ }
+
+ DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
+ pPrt->PRxQRamEnd, RxQType);
+
+ DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
+ pPrt->PXsQRamEnd, SK_TX_RAM_Q);
+
+ DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
+ pPrt->PXaQRamEnd, SK_TX_RAM_Q);
+
+} /* SkGeInitRamBufs */
+
+
+/******************************************************************************
+ *
+ * SkGeInitRamIface() - Initialize the RAM Interface
+ *
+ * Description:
+ * This function initializes the Adapters RAM Interface.
+ *
+ * Note:
+ * This function is used in the diagnostics.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInitRamIface(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+ /* release local reset */
+ SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR);
+
+ /* configure timeout values */
+ SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
+ SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);
+
+} /* SkGeInitRamIface */
+
+
+/******************************************************************************
+ *
+ * SkGeInitBmu() - Initialize the BMU state machines
+ *
+ * Description:
+ * Initialize all BMU state machines of the specified port
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInitBmu(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U32 RxWm;
+ SK_U32 TxWm;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ RxWm = SK_BMU_RX_WM;
+ TxWm = SK_BMU_TX_WM;
+
+ if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
+ /* for better performance */
+ RxWm /= 2;
+ TxWm /= 2;
+ }
+
+ /* Rx Queue: Release all local resets and set the watermark */
+ SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
+ SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);
+
+ /*
+ * Tx Queue: Release all local resets if the queue is used !
+ * set watermark
+ */
+ if (pPrt->PXSQSize != 0) {
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
+ }
+
+ if (pPrt->PXAQSize != 0) {
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
+ }
+ /*
+ * Do NOT enable the descriptor poll timers here, because
+ * the descriptor addresses are not specified yet.
+ */
+} /* SkGeInitBmu */
+
+
+/******************************************************************************
+ *
+ * TestStopBit() - Test the stop bit of the queue
+ *
+ * Description:
+ * Stopping a queue is not as simple as it seems to be.
+ * If descriptor polling is enabled, it may happen
+ * that RX/TX stop is done and SV idle is NOT set.
+ * In this case we have to issue another stop command.
+ *
+ * Returns:
+ * The queues control status register
+ */
+static SK_U32 TestStopBit(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int QuIoOffs) /* Queue IO Address Offset */
+{
+ SK_U32 QuCsr; /* CSR contents */
+
+ SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+
+ if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
+ /* Stop Descriptor overridden by start command */
+ SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);
+
+ SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+ }
+
+ return(QuCsr);
+} /* TestStopBit */
+
+
+/******************************************************************************
+ *
+ * SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
+ *
+ * Description:
+ * After calling this function the descriptor rings and Rx and Tx
+ * queues of this port may be reconfigured.
+ *
+ * It is possible to stop the receive and transmit path separate or
+ * both together.
+ *
+ * Dir = SK_STOP_TX Stops the transmit path only and resets the MAC.
+ * The receive queue is still active and
+ * the pending Rx frames may be still transferred
+ * into the RxD.
+ * SK_STOP_RX Stop the receive path. The tansmit path
+ * has to be stopped once before.
+ * SK_STOP_ALL SK_STOP_TX + SK_STOP_RX
+ *
+ * RstMode = SK_SOFT_RST Resets the MAC. The PHY is still alive.
+ * SK_HARD_RST Resets the MAC and the PHY.
+ *
+ * Example:
+ * 1) A Link Down event was signaled for a port. Therefore the activity
+ * of this port should be stopped and a hardware reset should be issued
+ * to enable the workaround of XMAC Errata #2. But the received frames
+ * should not be discarded.
+ * ...
+ * SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
+ * (transfer all pending Rx frames)
+ * SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
+ * ...
+ *
+ * 2) An event was issued which request the driver to switch
+ * the 'virtual active' link to an other already active port
+ * as soon as possible. The frames in the receive queue of this
+ * port may be lost. But the PHY must not be reset during this
+ * event.
+ * ...
+ * SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
+ * ...
+ *
+ * Extended Description:
+ * If SK_STOP_TX is set,
+ * o disable the MAC's receive and transmitter to prevent
+ * from sending incomplete frames
+ * o stop the port's transmit queues before terminating the
+ * BMUs to prevent from performing incomplete PCI cycles
+ * on the PCI bus
+ * - The network Rx and Tx activity and PCI Tx transfer is
+ * disabled now.
+ * o reset the MAC depending on the RstMode
+ * o Stop Interval Timer and Limit Counter of Tx Arbiter,
+ * also disable Force Sync bit and Enable Alloc bit.
+ * o perform a local reset of the port's Tx path
+ * - reset the PCI FIFO of the async Tx queue
+ * - reset the PCI FIFO of the sync Tx queue
+ * - reset the RAM Buffer async Tx queue
+ * - reset the RAM Buffer sync Tx queue
+ * - reset the MAC Tx FIFO
+ * o switch Link and Tx LED off, stop the LED counters
+ *
+ * If SK_STOP_RX is set,
+ * o stop the port's receive queue
+ * - The path data transfer activity is fully stopped now.
+ * o perform a local reset of the port's Rx path
+ * - reset the PCI FIFO of the Rx queue
+ * - reset the RAM Buffer receive queue
+ * - reset the MAC Rx FIFO
+ * o switch Rx LED off, stop the LED counter
+ *
+ * If all ports are stopped,
+ * o reset the RAM Interface.
+ *
+ * Notes:
+ * o This function may be called during the driver states RESET_PORT and
+ * SWITCH_PORT.
+ */
+void SkGeStopPort(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* I/O context */
+int Port, /* port to stop (MAC_1 + n) */
+int Dir, /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
+int RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
+{
+#ifndef SK_DIAG
+ SK_EVPARA Para;
+#endif /* !SK_DIAG */
+ SK_GEPORT *pPrt;
+ SK_U32 DWord;
+ SK_U32 XsCsr;
+ SK_U32 XaCsr;
+ SK_U64 ToutStart;
+ int i;
+ int ToutCnt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if ((Dir & SK_STOP_TX) != 0) {
+ /* disable receiver and transmitter */
+ SkMacRxTxDisable(pAC, IoC, Port);
+
+ /* stop both transmit queues */
+ /*
+ * If the BMU is in the reset state CSR_STOP will terminate
+ * immediately.
+ */
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP);
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP);
+
+ ToutStart = SkOsGetTime(pAC);
+ ToutCnt = 0;
+ do {
+ /*
+ * Clear packet arbiter timeout to make sure
+ * this loop will terminate.
+ */
+ SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
+ PA_CLR_TO_TX1 : PA_CLR_TO_TX2));
+
+ /*
+ * If the transfer stucks at the MAC the STOP command will not
+ * terminate if we don't flush the XMAC's transmit FIFO !
+ */
+ SkMacFlushTxFifo(pAC, IoC, Port);
+
+ XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
+ XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
+
+ if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
+ /*
+ * Timeout of 1/18 second reached.
+ * This needs to be checked at 1/18 sec only.
+ */
+ ToutCnt++;
+ if (ToutCnt > 1) {
+ /* Might be a problem when the driver event handler
+ * calls StopPort again. XXX.
+ */
+
+ /* Fatal Error, Loop aborted */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018,
+ SKERR_HWI_E018MSG);
+#ifndef SK_DIAG
+ Para.Para64 = Port;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+#endif /* !SK_DIAG */
+ return;
+ }
+ /*
+ * Cache incoherency workaround: Assume a start command
+ * has been lost while sending the frame.
+ */
+ ToutStart = SkOsGetTime(pAC);
+
+ if ((XsCsr & CSR_STOP) != 0) {
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
+ }
+ if ((XaCsr & CSR_STOP) != 0) {
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
+ }
+ }
+
+ /*
+ * Because of the ASIC problem report entry from 21.08.1998 it is
+ * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
+ */
+ } while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE ||
+ (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+ /* Reset the MAC depending on the RstMode */
+ if (RstMode == SK_SOFT_RST) {
+ SkMacSoftRst(pAC, IoC, Port);
+ }
+ else {
+ SkMacHardRst(pAC, IoC, Port);
+ }
+
+ /* Disable Force Sync bit and Enable Alloc bit */
+ SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+ TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+ /* Stop Interval Timer and Limit Counter of Tx Arbiter */
+ SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
+ SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);
+
+ /* Perform a local reset of the port's Tx path */
+
+ /* Reset the PCI FIFO of the async Tx queue */
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
+ /* Reset the PCI FIFO of the sync Tx queue */
+ SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
+ /* Reset the RAM Buffer async Tx queue */
+ SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
+ /* Reset the RAM Buffer sync Tx queue */
+ SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);
+
+ /* Reset Tx MAC FIFO */
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* Note: MFF_RST_SET does NOT reset the XMAC ! */
+ SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
+
+ /* switch Link and Tx LED off, stop the LED counters */
+ /* Link LED is switched off by the RLMT and the Diag itself */
+ SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* Reset TX MAC FIFO */
+ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+ }
+#endif /* YUKON */
+ }
+
+ if ((Dir & SK_STOP_RX) != 0) {
+ /*
+ * The RX Stop Command will not terminate if no buffers
+ * are queued in the RxD ring. But it will always reach
+ * the Idle state. Therefore we can use this feature to
+ * stop the transfer of received packets.
+ */
+ /* stop the port's receive queue */
+ SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP);
+
+ i = 100;
+ do {
+ /*
+ * Clear packet arbiter timeout to make sure
+ * this loop will terminate
+ */
+ SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
+ PA_CLR_TO_RX1 : PA_CLR_TO_RX2));
+
+ DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);
+
+ /* timeout if i==0 (bug fix for #10748) */
+ if (--i == 0) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
+ SKERR_HWI_E024MSG);
+ break;
+ }
+ /*
+ * because of the ASIC problem report entry from 21.08.98
+ * it is required to wait until CSR_STOP is reset and
+ * CSR_SV_IDLE is set.
+ */
+ } while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+ /* The path data transfer activity is fully stopped now */
+
+ /* Perform a local reset of the port's Rx path */
+
+ /* Reset the PCI FIFO of the Rx queue */
+ SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
+ /* Reset the RAM Buffer receive queue */
+ SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);
+
+ /* Reset Rx MAC FIFO */
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
+
+ /* switch Rx LED off, stop the LED counter */
+ SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* Reset Rx MAC FIFO */
+ SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+ }
+#endif /* YUKON */
+ }
+} /* SkGeStopPort */
+
+
+/******************************************************************************
+ *
+ * SkGeInit0() - Level 0 Initialization
+ *
+ * Description:
+ * - Initialize the BMU address offsets
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInit0(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+ int i;
+ SK_GEPORT *pPrt;
+
+ for (i = 0; i < SK_MAX_MACS; i++) {
+ pPrt = &pAC->GIni.GP[i];
+
+ pPrt->PState = SK_PRT_RESET;
+ pPrt->PRxQOff = QOffTab[i].RxQOff;
+ pPrt->PXsQOff = QOffTab[i].XsQOff;
+ pPrt->PXaQOff = QOffTab[i].XaQOff;
+ pPrt->PCheckPar = SK_FALSE;
+ pPrt->PIsave = 0;
+ pPrt->PPrevShorts = 0;
+ pPrt->PLinkResCt = 0;
+ pPrt->PAutoNegTOCt = 0;
+ pPrt->PPrevRx = 0;
+ pPrt->PPrevFcs = 0;
+ pPrt->PRxLim = SK_DEF_RX_WA_LIM;
+ pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
+ pPrt->PLinkSpeedCap = (SK_U8)SK_LSPEED_CAP_1000MBPS;
+ pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_1000MBPS;
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_UNKNOWN;
+ pPrt->PLinkModeConf = (SK_U8)SK_LMODE_AUTOSENSE;
+ pPrt->PFlowCtrlMode = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
+ pPrt->PLinkCap = (SK_U8)(SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
+ SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+ pPrt->PFlowCtrlCap = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
+ pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+ pPrt->PMSCap = 0;
+ pPrt->PMSMode = (SK_U8)SK_MS_MODE_AUTO;
+ pPrt->PMSStatus = (SK_U8)SK_MS_STAT_UNSET;
+ pPrt->PLipaAutoNeg = (SK_U8)SK_LIPA_UNKNOWN;
+ pPrt->PAutoNegFail = SK_FALSE;
+ pPrt->PHWLinkUp = SK_FALSE;
+ pPrt->PLinkBroken = SK_TRUE; /* See WA code */
+ pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE;
+ pPrt->PMacColThres = TX_COL_DEF;
+ pPrt->PMacJamLen = TX_JAM_LEN_DEF;
+ pPrt->PMacJamIpgVal = TX_JAM_IPG_DEF;
+ pPrt->PMacJamIpgData = TX_IPG_JAM_DEF;
+ pPrt->PMacIpgData = IPG_DATA_DEF;
+ pPrt->PMacLimit4 = SK_FALSE;
+ }
+
+ pAC->GIni.GIPortUsage = SK_RED_LINK;
+ pAC->GIni.GILedBlinkCtrl = (SK_U16)OemConfig.Value;
+ pAC->GIni.GIValIrqMask = IS_ALL_MSK;
+
+} /* SkGeInit0*/
+
+
+/******************************************************************************
+ *
+ * SkGeInit1() - Level 1 Initialization
+ *
+ * Description:
+ * o Do a software reset.
+ * o Clear all reset bits.
+ * o Verify that the detected hardware is present.
+ * Return an error if not.
+ * o Get the hardware configuration
+ * + Read the number of MACs/Ports.
+ * + Read the RAM size.
+ * + Read the PCI Revision Id.
+ * + Find out the adapters host clock speed
+ * + Read and check the PHY type
+ *
+ * Returns:
+ * 0: success
+ * 5: Unexpected PHY type detected
+ * 6: HW self test failed
+ */
+static int SkGeInit1(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+ SK_U8 Byte;
+ SK_U16 Word;
+ SK_U16 CtrlStat;
+ SK_U32 DWord;
+ int RetVal;
+ int i;
+
+ RetVal = 0;
+
+ /* save CLK_RUN bits (YUKON-Lite) */
+ SK_IN16(IoC, B0_CTST, &CtrlStat);
+
+ /* do the SW-reset */
+ SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+
+ /* release the SW-reset */
+ SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
+
+ /* reset all error bits in the PCI STATUS register */
+ /*
+ * Note: PCI Cfg cycles cannot be used, because they are not
+ * available on some platforms after 'boot time'.
+ */
+ SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+
+ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+ /* release Master Reset */
+ SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
+
+#ifdef CLK_RUN
+ CtrlStat |= CS_CLK_RUN_ENA;
+#endif /* CLK_RUN */
+
+ /* restore CLK_RUN bits */
+ SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat &
+ (CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA)));
+
+ /* read Chip Identification Number */
+ SK_IN8(IoC, B2_CHIP_ID, &Byte);
+ pAC->GIni.GIChipId = Byte;
+
+ /* read number of MACs */
+ SK_IN8(IoC, B2_MAC_CFG, &Byte);
+ pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
+
+ /* get Chip Revision Number */
+ pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
+
+ /* get diff. PCI parameters */
+ SK_IN16(IoC, B0_CTST, &CtrlStat);
+
+ /* read the adapters RAM size */
+ SK_IN8(IoC, B2_E_0, &Byte);
+
+ pAC->GIni.GIGenesis = SK_FALSE;
+ pAC->GIni.GIYukon = SK_FALSE;
+ pAC->GIni.GIYukonLite = SK_FALSE;
+
+#ifdef GENESIS
+ if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+
+ pAC->GIni.GIGenesis = SK_TRUE;
+
+ if (Byte == (SK_U8)3) {
+ /* special case: 4 x 64k x 36, offset = 0x80000 */
+ pAC->GIni.GIRamSize = 1024;
+ pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+ }
+ else {
+ pAC->GIni.GIRamSize = (int)Byte * 512;
+ pAC->GIni.GIRamOffs = 0;
+ }
+ /* all GE adapters work with 53.125 MHz host clock */
+ pAC->GIni.GIHstClkFact = SK_FACT_53;
+
+ /* set Descr. Poll Timer Init Value to 250 ms */
+ pAC->GIni.GIPollTimerVal =
+ SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIChipId != CHIP_ID_GENESIS) {
+
+ pAC->GIni.GIYukon = SK_TRUE;
+
+ pAC->GIni.GIRamSize = (Byte == (SK_U8)0) ? 128 : (int)Byte * 4;
+
+ pAC->GIni.GIRamOffs = 0;
+
+ /* WA for chip Rev. A */
+ pAC->GIni.GIWolOffs = (pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+ pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;
+
+ /* get PM Capabilities of PCI config space */
+ SK_IN16(IoC, PCI_C(PCI_PM_CAP_REG), &Word);
+
+ /* check if VAUX is available */
+ if (((CtrlStat & CS_VAUX_AVAIL) != 0) &&
+ /* check also if PME from D3cold is set */
+ ((Word & PCI_PME_D3C_SUP) != 0)) {
+ /* set entry in GE init struct */
+ pAC->GIni.GIVauxAvail = SK_TRUE;
+ }
+
+ if (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) {
+ /* this is Rev. A1 */
+ pAC->GIni.GIYukonLite = SK_TRUE;
+ }
+ else {
+ /* save Flash-Address Register */
+ SK_IN32(IoC, B2_FAR, &DWord);
+
+ /* test Flash-Address Register */
+ SK_OUT8(IoC, B2_FAR + 3, 0xff);
+ SK_IN8(IoC, B2_FAR + 3, &Byte);
+
+ if (Byte != 0) {
+ /* this is Rev. A0 */
+ pAC->GIni.GIYukonLite = SK_TRUE;
+
+ /* restore Flash-Address Register */
+ SK_OUT32(IoC, B2_FAR, DWord);
+ }
+ }
+
+ /* switch power to VCC (WA for VAUX problem) */
+ SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA |
+ PC_VAUX_OFF | PC_VCC_ON));
+
+ /* read the Interrupt source */
+ SK_IN32(IoC, B0_ISRC, &DWord);
+
+ if ((DWord & IS_HW_ERR) != 0) {
+ /* read the HW Error Interrupt source */
+ SK_IN32(IoC, B0_HWE_ISRC, &DWord);
+
+ if ((DWord & IS_IRQ_SENSOR) != 0) {
+ /* disable HW Error IRQ */
+ pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+ }
+ }
+
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+ /* set GMAC Link Control reset */
+ SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+
+ /* clear GMAC Link Control reset */
+ SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+ }
+ /* all YU chips work with 78.125 MHz host clock */
+ pAC->GIni.GIHstClkFact = SK_FACT_78;
+
+ pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX; /* 215 ms */
+ }
+#endif /* YUKON */
+
+ /* check if 64-bit PCI Slot is present */
+ pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0);
+
+ /* check if 66 MHz PCI Clock is active */
+ pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0);
+
+ /* read PCI HW Revision Id. */
+ SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
+ pAC->GIni.GIPciHwRev = Byte;
+
+ /* read the PMD type */
+ SK_IN8(IoC, B2_PMD_TYP, &Byte);
+ pAC->GIni.GICopperType = (SK_U8)(Byte == 'T');
+
+ /* read the PHY type */
+ SK_IN8(IoC, B2_E_1, &Byte);
+
+ Byte &= 0x0f; /* the PHY type is stored in the lower nibble */
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ switch (Byte) {
+ case SK_PHY_XMAC:
+ pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC;
+ break;
+ case SK_PHY_BCOM:
+ pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
+ pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
+ SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
+ break;
+ case SK_PHY_NAT:
+ pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
+ break;
+#endif /* OTHER_PHY */
+ default:
+ /* ERROR: unexpected PHY type detected */
+ RetVal = 5;
+ break;
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ if (Byte < (SK_U8)SK_PHY_MARV_COPPER) {
+ /* if this field is not initialized */
+ Byte = (SK_U8)SK_PHY_MARV_COPPER;
+
+ pAC->GIni.GICopperType = SK_TRUE;
+ }
+
+ pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV;
+
+ if (pAC->GIni.GICopperType) {
+
+ pAC->GIni.GP[i].PLinkSpeedCap = (SK_U8)(SK_LSPEED_CAP_AUTO |
+ SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
+ SK_LSPEED_CAP_1000MBPS);
+
+ pAC->GIni.GP[i].PLinkSpeed = (SK_U8)SK_LSPEED_AUTO;
+
+ pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
+ SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
+ }
+ else {
+ Byte = (SK_U8)SK_PHY_MARV_FIBER;
+ }
+ }
+#endif /* YUKON */
+
+ pAC->GIni.GP[i].PhyType = (int)Byte;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+ ("PHY type: %d PHY addr: %04x\n", Byte,
+ pAC->GIni.GP[i].PhyAddr));
+ }
+
+ /* get MAC Type & set function pointers dependent on */
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ pAC->GIni.GIMacType = SK_MAC_XMAC;
+
+ pAC->GIni.GIFunc.pFnMacUpdateStats = SkXmUpdateStats;
+ pAC->GIni.GIFunc.pFnMacStatistic = SkXmMacStatistic;
+ pAC->GIni.GIFunc.pFnMacResetCounter = SkXmResetCounter;
+ pAC->GIni.GIFunc.pFnMacOverflow = SkXmOverflowStatus;
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ pAC->GIni.GIMacType = SK_MAC_GMAC;
+
+ pAC->GIni.GIFunc.pFnMacUpdateStats = SkGmUpdateStats;
+ pAC->GIni.GIFunc.pFnMacStatistic = SkGmMacStatistic;
+ pAC->GIni.GIFunc.pFnMacResetCounter = SkGmResetCounter;
+ pAC->GIni.GIFunc.pFnMacOverflow = SkGmOverflowStatus;
+
+#ifdef SPECIAL_HANDLING
+ if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+ /* check HW self test result */
+ SK_IN8(IoC, B2_E_3, &Byte);
+ if (Byte & B2_E3_RES_MASK) {
+ RetVal = 6;
+ }
+ }
+#endif
+ }
+#endif /* YUKON */
+
+ return(RetVal);
+} /* SkGeInit1 */
+
+
+/******************************************************************************
+ *
+ * SkGeInit2() - Level 2 Initialization
+ *
+ * Description:
+ * - start the Blink Source Counter
+ * - start the Descriptor Poll Timer
+ * - configure the MAC-Arbiter
+ * - configure the Packet-Arbiter
+ * - enable the Tx Arbiters
+ * - enable the RAM Interface Arbiter
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGeInit2(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+#ifdef GENESIS
+ SK_U32 DWord;
+#endif /* GENESIS */
+ int i;
+
+ /* start the Descriptor Poll Timer */
+ if (pAC->GIni.GIPollTimerVal != 0) {
+ if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
+ pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
+ }
+ SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
+ SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
+ }
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* start the Blink Source Counter */
+ DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+
+ SK_OUT32(IoC, B2_BSC_INI, DWord);
+ SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+
+ /*
+ * Configure the MAC Arbiter and the Packet Arbiter.
+ * They will be started once and never be stopped.
+ */
+ SkGeInitMacArb(pAC, IoC);
+
+ SkGeInitPktArb(pAC, IoC);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* start Time Stamp Timer */
+ SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
+ }
+#endif /* YUKON */
+
+ /* enable the Tx Arbiters */
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+ SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
+ }
+
+ /* enable the RAM Interface Arbiter */
+ SkGeInitRamIface(pAC, IoC);
+
+} /* SkGeInit2 */
+
+/******************************************************************************
+ *
+ * SkGeInit() - Initialize the GE Adapter with the specified level.
+ *
+ * Description:
+ * Level 0: Initialize the Module structures.
+ * Level 1: Generic Hardware Initialization. The IOP/MemBase pointer has
+ * to be set before calling this level.
+ *
+ * o Do a software reset.
+ * o Clear all reset bits.
+ * o Verify that the detected hardware is present.
+ * Return an error if not.
+ * o Get the hardware configuration
+ * + Set GIMacsFound with the number of MACs.
+ * + Store the RAM size in GIRamSize.
+ * + Save the PCI Revision ID in GIPciHwRev.
+ * o return an error
+ * if Number of MACs > SK_MAX_MACS
+ *
+ * After returning from Level 0 the adapter
+ * may be accessed with IO operations.
+ *
+ * Level 2: start the Blink Source Counter
+ *
+ * Returns:
+ * 0: success
+ * 1: Number of MACs exceeds SK_MAX_MACS (after level 1)
+ * 2: Adapter not present or not accessible
+ * 3: Illegal initialization level
+ * 4: Initialization Level 1 Call missing
+ * 5: Unexpected PHY type detected
+ * 6: HW self test failed
+ */
+int SkGeInit(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Level) /* initialization level */
+{
+ int RetVal; /* return value */
+ SK_U32 DWord;
+
+ RetVal = 0;
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+ ("SkGeInit(Level %d)\n", Level));
+
+ switch (Level) {
+ case SK_INIT_DATA:
+ /* Initialization Level 0 */
+ SkGeInit0(pAC, IoC);
+ pAC->GIni.GILevel = SK_INIT_DATA;
+ break;
+
+ case SK_INIT_IO:
+ /* Initialization Level 1 */
+ RetVal = SkGeInit1(pAC, IoC);
+ if (RetVal != 0) {
+ break;
+ }
+
+ /* check if the adapter seems to be accessible */
+ SK_OUT32(IoC, B2_IRQM_INI, SK_TEST_VAL);
+ SK_IN32(IoC, B2_IRQM_INI, &DWord);
+ SK_OUT32(IoC, B2_IRQM_INI, 0L);
+
+ if (DWord != SK_TEST_VAL) {
+ RetVal = 2;
+ break;
+ }
+
+ /* check if the number of GIMacsFound matches SK_MAX_MACS */
+ if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
+ RetVal = 1;
+ break;
+ }
+
+ /* Level 1 successfully passed */
+ pAC->GIni.GILevel = SK_INIT_IO;
+ break;
+
+ case SK_INIT_RUN:
+ /* Initialization Level 2 */
+ if (pAC->GIni.GILevel != SK_INIT_IO) {
+#ifndef SK_DIAG
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
+#endif /* !SK_DIAG */
+ RetVal = 4;
+ break;
+ }
+ SkGeInit2(pAC, IoC);
+
+ /* Level 2 successfully passed */
+ pAC->GIni.GILevel = SK_INIT_RUN;
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
+ RetVal = 3;
+ break;
+ }
+
+ return(RetVal);
+} /* SkGeInit */
+
+
+/******************************************************************************
+ *
+ * SkGeDeInit() - Deinitialize the adapter
+ *
+ * Description:
+ * All ports of the adapter will be stopped if not already done.
+ * Do a software reset and switch off all LEDs.
+ *
+ * Returns:
+ * nothing
+ */
+void SkGeDeInit(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC) /* IO context */
+{
+ int i;
+ SK_U16 Word;
+
+#if (!defined(SK_SLIM) && !defined(VCPU))
+ /* ensure I2C is ready */
+ SkI2cWaitIrq(pAC, IoC);
+#endif
+
+ /* stop all current transfer activity */
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+ if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
+ pAC->GIni.GP[i].PState != SK_PRT_RESET) {
+
+ SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
+ }
+ }
+
+ /* Reset all bits in the PCI STATUS register */
+ /*
+ * Note: PCI Cfg cycles cannot be used, because they are not
+ * available on some platforms after 'boot time'.
+ */
+ SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+
+ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+ /* do the reset, all LEDs are switched off now */
+ SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+
+ pAC->GIni.GILevel = SK_INIT_DATA;
+} /* SkGeDeInit */
+
+
+/******************************************************************************
+ *
+ * SkGeInitPort() Initialize the specified port.
+ *
+ * Description:
+ * PRxQSize, PXSQSize, and PXAQSize has to be
+ * configured for the specified port before calling this function.
+ * The descriptor rings has to be initialized too.
+ *
+ * o (Re)configure queues of the specified port.
+ * o configure the MAC of the specified port.
+ * o put ASIC and MAC(s) in operational mode.
+ * o initialize Rx/Tx and Sync LED
+ * o initialize RAM Buffers and MAC FIFOs
+ *
+ * The port is ready to connect when returning.
+ *
+ * Note:
+ * The MAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ * 0: success
+ * 1: Queue size initialization error. The configured values
+ * for PRxQSize, PXSQSize, or PXAQSize are invalid for one
+ * or more queues. The specified port was NOT initialized.
+ * An error log entry was generated.
+ * 2: The port has to be stopped before it can be initialized again.
+ */
+int SkGeInitPort(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port to configure */
+{
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (SkGeCheckQSize(pAC, Port) != 0) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
+ return(1);
+ }
+
+ if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
+ return(2);
+ }
+
+ /* configuration ok, initialize the Port now */
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* initialize Rx, Tx and Link LED */
+ /*
+ * If 1000BT Phy needs LED initialization than swap
+ * LED and XMAC initialization order
+ */
+ SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+ SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
+ /* The Link LED is initialized by RLMT or Diagnostics itself */
+
+ SkXmInitMac(pAC, IoC, Port);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ SkGmInitMac(pAC, IoC, Port);
+ }
+#endif /* YUKON */
+
+ /* do NOT initialize the Link Sync Counter */
+
+ SkGeInitMacFifo(pAC, IoC, Port);
+
+ SkGeInitRamBufs(pAC, IoC, Port);
+
+ if (pPrt->PXSQSize != 0) {
+ /* enable Force Sync bit if synchronous queue available */
+ SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
+ }
+
+ SkGeInitBmu(pAC, IoC, Port);
+
+ /* mark port as initialized */
+ pPrt->PState = SK_PRT_INIT;
+
+ return(0);
+} /* SkGeInitPort */
diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c
new file mode 100644
index 000000000000..0a6f67a7a395
--- /dev/null
+++ b/drivers/net/sk98lin/skgemib.c
@@ -0,0 +1,1075 @@
+/*****************************************************************************
+ *
+ * Name: skgemib.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.11 $
+ * Date: $Date: 2003/09/15 13:38:12 $
+ * Purpose: Private Network Management Interface Management Database
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * PRIVATE OID handler function prototypes
+ */
+PNMI_STATIC int Addr(SK_AC *pAC, SK_IOC IoC, int action,
+ SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Monitor(SK_AC *pAC, SK_IOC IoC, int action,
+ SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int* pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+
+#ifdef SK_POWER_MGMT
+PNMI_STATIC int PowerManagement(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+#endif /* SK_POWER_MGMT */
+
+#ifdef SK_DIAG_SUPPORT
+PNMI_STATIC int DiagActions(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance,
+ unsigned int TableIndex, SK_U32 NetIndex);
+#endif /* SK_DIAG_SUPPORT */
+
+
+/* defines *******************************************************************/
+#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0]))
+
+
+/* global variables **********************************************************/
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = {
+ {OID_GEN_XMIT_OK,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
+ {OID_GEN_RCV_OK,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
+ {OID_GEN_XMIT_ERROR,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, General, 0},
+ {OID_GEN_RCV_ERROR,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, General, 0},
+ {OID_GEN_RCV_NO_BUFFER,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, General, 0},
+ {OID_GEN_DIRECTED_FRAMES_XMIT,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
+ {OID_GEN_MULTICAST_FRAMES_XMIT,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
+ {OID_GEN_BROADCAST_FRAMES_XMIT,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
+ {OID_GEN_DIRECTED_FRAMES_RCV,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
+ {OID_GEN_MULTICAST_FRAMES_RCV,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
+ {OID_GEN_BROADCAST_FRAMES_RCV,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
+ {OID_GEN_RCV_CRC_ERROR,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
+ {OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, General, 0},
+ {OID_802_3_PERMANENT_ADDRESS,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, 0},
+ {OID_802_3_CURRENT_ADDRESS,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, 0},
+ {OID_802_3_RCV_ERROR_ALIGNMENT,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
+ {OID_802_3_XMIT_ONE_COLLISION,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
+ {OID_802_3_XMIT_MORE_COLLISIONS,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
+ {OID_802_3_XMIT_DEFERRED,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
+ {OID_802_3_XMIT_MAX_COLLISIONS,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
+ {OID_802_3_RCV_OVERRUN,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
+ {OID_802_3_XMIT_UNDERRUN,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
+ {OID_802_3_XMIT_TIMES_CRS_LOST,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
+ {OID_802_3_XMIT_LATE_COLLISIONS,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
+#ifdef SK_POWER_MGMT
+ {OID_PNP_CAPABILITIES,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, PowerManagement, 0},
+ {OID_PNP_SET_POWER,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_WO, PowerManagement, 0},
+ {OID_PNP_QUERY_POWER,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, PowerManagement, 0},
+ {OID_PNP_ADD_WAKE_UP_PATTERN,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_WO, PowerManagement, 0},
+ {OID_PNP_REMOVE_WAKE_UP_PATTERN,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_WO, PowerManagement, 0},
+ {OID_PNP_ENABLE_WAKE_UP,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RW, PowerManagement, 0},
+#endif /* SK_POWER_MGMT */
+#ifdef SK_DIAG_SUPPORT
+ {OID_SKGE_DIAG_MODE,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RW, DiagActions, 0},
+#endif /* SK_DIAG_SUPPORT */
+ {OID_SKGE_MDB_VERSION,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(MgmtDBVersion),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_SUPPORTED_LIST,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_ALL_DATA,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RW, OidStruct, 0},
+ {OID_SKGE_VPD_FREE_BYTES,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(VpdFreeBytes),
+ SK_PNMI_RO, Vpd, 0},
+ {OID_SKGE_VPD_ENTRIES_LIST,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(VpdEntriesList),
+ SK_PNMI_RO, Vpd, 0},
+ {OID_SKGE_VPD_ENTRIES_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(VpdEntriesNumber),
+ SK_PNMI_RO, Vpd, 0},
+ {OID_SKGE_VPD_KEY,
+ SK_PNMI_VPD_ENTRIES,
+ sizeof(SK_PNMI_VPD),
+ SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
+ SK_PNMI_RO, Vpd, 0},
+ {OID_SKGE_VPD_VALUE,
+ SK_PNMI_VPD_ENTRIES,
+ sizeof(SK_PNMI_VPD),
+ SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
+ SK_PNMI_RO, Vpd, 0},
+ {OID_SKGE_VPD_ACCESS,
+ SK_PNMI_VPD_ENTRIES,
+ sizeof(SK_PNMI_VPD),
+ SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
+ SK_PNMI_RO, Vpd, 0},
+ {OID_SKGE_VPD_ACTION,
+ SK_PNMI_VPD_ENTRIES,
+ sizeof(SK_PNMI_VPD),
+ SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
+ SK_PNMI_RW, Vpd, 0},
+ {OID_SKGE_PORT_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(PortNumber),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_DEVICE_TYPE,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(DeviceType),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_DRIVER_DESCR,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(DriverDescr),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_DRIVER_VERSION,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(DriverVersion),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_DRIVER_RELDATE,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(DriverReleaseDate),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_DRIVER_FILENAME,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(DriverFileName),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_HW_DESCR,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(HwDescr),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_HW_VERSION,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(HwVersion),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_CHIPSET,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(Chipset),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_CHIPID,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(ChipId),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RAMSIZE,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RamSize),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_VAUXAVAIL,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(VauxAvail),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_ACTION,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(Action),
+ SK_PNMI_RW, Perform, 0},
+ {OID_SKGE_RESULT,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TestResult),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_BUS_TYPE,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(BusType),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_BUS_SPEED,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(BusSpeed),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_BUS_WIDTH,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(BusWidth),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_SW_QUEUE_LEN,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxSwQueueLen),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_SW_QUEUE_MAX,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxSwQueueMax),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_RETRY,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxRetryCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RX_INTR_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RxIntrCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_INTR_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxIntrCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RX_NO_BUF_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RxNoBufCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_NO_BUF_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxNoBufCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_USED_DESCR_NO,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxUsedDescrNo),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RX_DELIVERED_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RxDeliveredCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RX_OCTETS_DELIV_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RX_HW_ERROR_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RxHwErrorsCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TX_HW_ERROR_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TxHwErrorsCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_IN_ERRORS_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(InErrorsCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_OUT_ERROR_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(OutErrorsCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_ERR_RECOVERY_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(ErrRecoveryCts),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_SYSUPTIME,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(SysUpTime),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_SENSOR_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(SensorNumber),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_SENSOR_INDEX,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_DESCR,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_TYPE,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_VALUE,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_WAR_THRES_LOW,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_WAR_THRES_UPP,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_ERR_THRES_LOW,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_ERR_THRES_UPP,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_STATUS,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_WAR_CTS,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_ERR_CTS,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_WAR_TIME,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_SENSOR_ERR_TIME,
+ SK_PNMI_SENSOR_ENTRIES,
+ sizeof(SK_PNMI_SENSOR),
+ SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
+ SK_PNMI_RO, SensorStat, 0},
+ {OID_SKGE_CHKSM_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(ChecksumNumber),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_CHKSM_RX_OK_CTS,
+ SKCS_NUM_PROTOCOLS,
+ sizeof(SK_PNMI_CHECKSUM),
+ SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
+ SK_PNMI_RO, CsumStat, 0},
+ {OID_SKGE_CHKSM_RX_UNABLE_CTS,
+ SKCS_NUM_PROTOCOLS,
+ sizeof(SK_PNMI_CHECKSUM),
+ SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
+ SK_PNMI_RO, CsumStat, 0},
+ {OID_SKGE_CHKSM_RX_ERR_CTS,
+ SKCS_NUM_PROTOCOLS,
+ sizeof(SK_PNMI_CHECKSUM),
+ SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
+ SK_PNMI_RO, CsumStat, 0},
+ {OID_SKGE_CHKSM_TX_OK_CTS,
+ SKCS_NUM_PROTOCOLS,
+ sizeof(SK_PNMI_CHECKSUM),
+ SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
+ SK_PNMI_RO, CsumStat, 0},
+ {OID_SKGE_CHKSM_TX_UNABLE_CTS,
+ SKCS_NUM_PROTOCOLS,
+ sizeof(SK_PNMI_CHECKSUM),
+ SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
+ SK_PNMI_RO, CsumStat, 0},
+ {OID_SKGE_STAT_TX,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
+ {OID_SKGE_STAT_TX_OCTETS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
+ {OID_SKGE_STAT_TX_BROADCAST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
+ {OID_SKGE_STAT_TX_MULTICAST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
+ {OID_SKGE_STAT_TX_UNICAST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
+ {OID_SKGE_STAT_TX_LONGFRAMES,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
+ {OID_SKGE_STAT_TX_BURST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
+ {OID_SKGE_STAT_TX_PFLOWC,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
+ {OID_SKGE_STAT_TX_FLOWC,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
+ {OID_SKGE_STAT_TX_SINGLE_COL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
+ {OID_SKGE_STAT_TX_MULTI_COL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
+ {OID_SKGE_STAT_TX_EXCESS_COL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
+ {OID_SKGE_STAT_TX_LATE_COL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
+ {OID_SKGE_STAT_TX_DEFFERAL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
+ {OID_SKGE_STAT_TX_EXCESS_DEF,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
+ {OID_SKGE_STAT_TX_UNDERRUN,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
+ {OID_SKGE_STAT_TX_CARRIER,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
+/* {OID_SKGE_STAT_TX_UTIL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
+ SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+ {OID_SKGE_STAT_TX_64,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
+ {OID_SKGE_STAT_TX_127,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
+ {OID_SKGE_STAT_TX_255,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
+ {OID_SKGE_STAT_TX_511,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
+ {OID_SKGE_STAT_TX_1023,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
+ {OID_SKGE_STAT_TX_MAX,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
+ {OID_SKGE_STAT_TX_SYNC,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
+ {OID_SKGE_STAT_TX_SYNC_OCTETS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
+ {OID_SKGE_STAT_RX,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
+ {OID_SKGE_STAT_RX_OCTETS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
+ {OID_SKGE_STAT_RX_BROADCAST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
+ {OID_SKGE_STAT_RX_MULTICAST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
+ {OID_SKGE_STAT_RX_UNICAST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
+ {OID_SKGE_STAT_RX_LONGFRAMES,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES},
+ {OID_SKGE_STAT_RX_PFLOWC,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
+ {OID_SKGE_STAT_RX_FLOWC,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
+ {OID_SKGE_STAT_RX_PFLOWC_ERR,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
+ {OID_SKGE_STAT_RX_FLOWC_UNKWN,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
+ {OID_SKGE_STAT_RX_BURST,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
+ {OID_SKGE_STAT_RX_MISSED,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
+ {OID_SKGE_STAT_RX_FRAMING,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
+ {OID_SKGE_STAT_RX_OVERFLOW,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
+ {OID_SKGE_STAT_RX_JABBER,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
+ {OID_SKGE_STAT_RX_CARRIER,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
+ {OID_SKGE_STAT_RX_IR_LENGTH,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
+ {OID_SKGE_STAT_RX_SYMBOL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
+ {OID_SKGE_STAT_RX_SHORTS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
+ {OID_SKGE_STAT_RX_RUNT,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
+ {OID_SKGE_STAT_RX_CEXT,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
+ {OID_SKGE_STAT_RX_TOO_LONG,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
+ {OID_SKGE_STAT_RX_FCS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
+/* {OID_SKGE_STAT_RX_UTIL,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
+ SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+ {OID_SKGE_STAT_RX_64,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
+ {OID_SKGE_STAT_RX_127,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
+ {OID_SKGE_STAT_RX_255,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
+ {OID_SKGE_STAT_RX_511,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
+ {OID_SKGE_STAT_RX_1023,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
+ {OID_SKGE_STAT_RX_MAX,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_STAT),
+ SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
+ SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
+ {OID_SKGE_PHYS_CUR_ADDR,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
+ SK_PNMI_RW, Addr, 0},
+ {OID_SKGE_PHYS_FAC_ADDR,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
+ SK_PNMI_RO, Addr, 0},
+ {OID_SKGE_PMD,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_CONNECTOR,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_PHY_TYPE,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_LINK_CAP,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_LINK_MODE,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
+ SK_PNMI_RW, MacPrivateConf, 0},
+ {OID_SKGE_LINK_MODE_STATUS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_LINK_STATUS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_FLOWCTRL_CAP,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_FLOWCTRL_MODE,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
+ SK_PNMI_RW, MacPrivateConf, 0},
+ {OID_SKGE_FLOWCTRL_STATUS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_PHY_OPERATION_CAP,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_PHY_OPERATION_MODE,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
+ SK_PNMI_RW, MacPrivateConf, 0},
+ {OID_SKGE_PHY_OPERATION_STATUS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_SPEED_CAP,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedCapability),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_SPEED_MODE,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedMode),
+ SK_PNMI_RW, MacPrivateConf, 0},
+ {OID_SKGE_SPEED_STATUS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_CONF),
+ SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedStatus),
+ SK_PNMI_RO, MacPrivateConf, 0},
+ {OID_SKGE_TRAP,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(Trap),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_TRAP_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(TrapNumber),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RLMT_MODE,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtMode),
+ SK_PNMI_RW, Rlmt, 0},
+ {OID_SKGE_RLMT_PORT_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtPortNumber),
+ SK_PNMI_RO, Rlmt, 0},
+ {OID_SKGE_RLMT_PORT_ACTIVE,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtPortActive),
+ SK_PNMI_RO, Rlmt, 0},
+ {OID_SKGE_RLMT_PORT_PREFERRED,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtPortPreferred),
+ SK_PNMI_RW, Rlmt, 0},
+ {OID_SKGE_RLMT_CHANGE_CTS,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtChangeCts),
+ SK_PNMI_RO, Rlmt, 0},
+ {OID_SKGE_RLMT_CHANGE_TIME,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtChangeTime),
+ SK_PNMI_RO, Rlmt, 0},
+ {OID_SKGE_RLMT_CHANGE_ESTIM,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtChangeEstimate),
+ SK_PNMI_RO, Rlmt, 0},
+ {OID_SKGE_RLMT_CHANGE_THRES,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtChangeThreshold),
+ SK_PNMI_RW, Rlmt, 0},
+ {OID_SKGE_RLMT_PORT_INDEX,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_RLMT),
+ SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
+ SK_PNMI_RO, RlmtStat, 0},
+ {OID_SKGE_RLMT_STATUS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_RLMT),
+ SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
+ SK_PNMI_RO, RlmtStat, 0},
+ {OID_SKGE_RLMT_TX_HELLO_CTS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_RLMT),
+ SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
+ SK_PNMI_RO, RlmtStat, 0},
+ {OID_SKGE_RLMT_RX_HELLO_CTS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_RLMT),
+ SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
+ SK_PNMI_RO, RlmtStat, 0},
+ {OID_SKGE_RLMT_TX_SP_REQ_CTS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_RLMT),
+ SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
+ SK_PNMI_RO, RlmtStat, 0},
+ {OID_SKGE_RLMT_RX_SP_CTS,
+ SK_PNMI_MAC_ENTRIES,
+ sizeof(SK_PNMI_RLMT),
+ SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
+ SK_PNMI_RO, RlmtStat, 0},
+ {OID_SKGE_RLMT_MONITOR_NUMBER,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(RlmtMonitorNumber),
+ SK_PNMI_RO, General, 0},
+ {OID_SKGE_RLMT_MONITOR_INDEX,
+ SK_PNMI_MONITOR_ENTRIES,
+ sizeof(SK_PNMI_RLMT_MONITOR),
+ SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
+ SK_PNMI_RO, Monitor, 0},
+ {OID_SKGE_RLMT_MONITOR_ADDR,
+ SK_PNMI_MONITOR_ENTRIES,
+ sizeof(SK_PNMI_RLMT_MONITOR),
+ SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
+ SK_PNMI_RO, Monitor, 0},
+ {OID_SKGE_RLMT_MONITOR_ERRS,
+ SK_PNMI_MONITOR_ENTRIES,
+ sizeof(SK_PNMI_RLMT_MONITOR),
+ SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
+ SK_PNMI_RO, Monitor, 0},
+ {OID_SKGE_RLMT_MONITOR_TIMESTAMP,
+ SK_PNMI_MONITOR_ENTRIES,
+ sizeof(SK_PNMI_RLMT_MONITOR),
+ SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
+ SK_PNMI_RO, Monitor, 0},
+ {OID_SKGE_RLMT_MONITOR_ADMIN,
+ SK_PNMI_MONITOR_ENTRIES,
+ sizeof(SK_PNMI_RLMT_MONITOR),
+ SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin),
+ SK_PNMI_RW, Monitor, 0},
+ {OID_SKGE_MTU,
+ 1,
+ 0,
+ SK_PNMI_MAI_OFF(MtuSize),
+ SK_PNMI_RW, MacPrivateConf, 0},
+ {OID_SKGE_VCT_GET,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Vct, 0},
+ {OID_SKGE_VCT_SET,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_WO, Vct, 0},
+ {OID_SKGE_VCT_STATUS,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, Vct, 0},
+ {OID_SKGE_BOARDLEVEL,
+ 0,
+ 0,
+ 0,
+ SK_PNMI_RO, General, 0},
+};
+
diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c
new file mode 100644
index 000000000000..b36dd9ac6b29
--- /dev/null
+++ b/drivers/net/sk98lin/skgepnmi.c
@@ -0,0 +1,8210 @@
+/*****************************************************************************
+ *
+ * Name: skgepnmi.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.111 $
+ * Date: $Date: 2003/09/15 13:35:35 $
+ * Purpose: Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+#ifndef _lint
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell.";
+#endif /* !_lint */
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/xmac_ii.h"
+#include "h/skdebug.h"
+#include "h/skqueue.h"
+#include "h/skgepnmi.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skdrv2nd.h"
+#include "h/skgepnm2.h"
+#ifdef SK_POWER_MGMT
+#include "h/skgepmgt.h"
+#endif
+/* defines *******************************************************************/
+
+#ifndef DEBUG
+#define PNMI_STATIC static
+#else /* DEBUG */
+#define PNMI_STATIC
+#endif /* DEBUG */
+
+/*
+ * Public Function prototypes
+ */
+int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
+int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+ unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
+int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
+ unsigned int * pLen, SK_U32 NetIndex);
+
+
+/*
+ * Private Function prototypes
+ */
+
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+ PhysPortIndex);
+PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+ PhysPortIndex);
+PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
+PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
+PNMI_STATIC SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
+ unsigned int PhysPortIndex, unsigned int StatIndex);
+PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
+ unsigned int StatIndex, SK_U32 NetIndex);
+PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
+PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
+ unsigned int *pEntries);
+PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
+ unsigned int KeyArrLen, unsigned int *pKeyNo);
+PNMI_STATIC int LookupId(SK_U32 Id);
+PNMI_STATIC int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
+ unsigned int LastMac);
+PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
+ unsigned int *pLen, SK_U32 NetIndex);
+PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
+ char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
+PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
+ unsigned int PortIndex);
+PNMI_STATIC void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
+ unsigned int SensorIndex);
+PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
+PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
+PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf,
+ unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32);
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+#include "skgemib.c"
+
+/* global variables **********************************************************/
+
+/*
+ * Overflow status register bit table and corresponding counter
+ * dependent on MAC type - the number relates to the size of overflow
+ * mask returned by the pFnMacOverflow function
+ */
+PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = {
+/* Bit0 */ { SK_PNMI_HTX, SK_PNMI_HTX_UNICAST},
+/* Bit1 */ { SK_PNMI_HTX_OCTETHIGH, SK_PNMI_HTX_BROADCAST},
+/* Bit2 */ { SK_PNMI_HTX_OCTETLOW, SK_PNMI_HTX_PMACC},
+/* Bit3 */ { SK_PNMI_HTX_BROADCAST, SK_PNMI_HTX_MULTICAST},
+/* Bit4 */ { SK_PNMI_HTX_MULTICAST, SK_PNMI_HTX_OCTETLOW},
+/* Bit5 */ { SK_PNMI_HTX_UNICAST, SK_PNMI_HTX_OCTETHIGH},
+/* Bit6 */ { SK_PNMI_HTX_LONGFRAMES, SK_PNMI_HTX_64},
+/* Bit7 */ { SK_PNMI_HTX_BURST, SK_PNMI_HTX_127},
+/* Bit8 */ { SK_PNMI_HTX_PMACC, SK_PNMI_HTX_255},
+/* Bit9 */ { SK_PNMI_HTX_MACC, SK_PNMI_HTX_511},
+/* Bit10 */ { SK_PNMI_HTX_SINGLE_COL, SK_PNMI_HTX_1023},
+/* Bit11 */ { SK_PNMI_HTX_MULTI_COL, SK_PNMI_HTX_MAX},
+/* Bit12 */ { SK_PNMI_HTX_EXCESS_COL, SK_PNMI_HTX_LONGFRAMES},
+/* Bit13 */ { SK_PNMI_HTX_LATE_COL, SK_PNMI_HTX_RESERVED},
+/* Bit14 */ { SK_PNMI_HTX_DEFFERAL, SK_PNMI_HTX_COL},
+/* Bit15 */ { SK_PNMI_HTX_EXCESS_DEF, SK_PNMI_HTX_LATE_COL},
+/* Bit16 */ { SK_PNMI_HTX_UNDERRUN, SK_PNMI_HTX_EXCESS_COL},
+/* Bit17 */ { SK_PNMI_HTX_CARRIER, SK_PNMI_HTX_MULTI_COL},
+/* Bit18 */ { SK_PNMI_HTX_UTILUNDER, SK_PNMI_HTX_SINGLE_COL},
+/* Bit19 */ { SK_PNMI_HTX_UTILOVER, SK_PNMI_HTX_UNDERRUN},
+/* Bit20 */ { SK_PNMI_HTX_64, SK_PNMI_HTX_RESERVED},
+/* Bit21 */ { SK_PNMI_HTX_127, SK_PNMI_HTX_RESERVED},
+/* Bit22 */ { SK_PNMI_HTX_255, SK_PNMI_HTX_RESERVED},
+/* Bit23 */ { SK_PNMI_HTX_511, SK_PNMI_HTX_RESERVED},
+/* Bit24 */ { SK_PNMI_HTX_1023, SK_PNMI_HTX_RESERVED},
+/* Bit25 */ { SK_PNMI_HTX_MAX, SK_PNMI_HTX_RESERVED},
+/* Bit26 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED},
+/* Bit27 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED},
+/* Bit28 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED},
+/* Bit29 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED},
+/* Bit30 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED},
+/* Bit31 */ { SK_PNMI_HTX_RESERVED, SK_PNMI_HTX_RESERVED},
+/* Bit32 */ { SK_PNMI_HRX, SK_PNMI_HRX_UNICAST},
+/* Bit33 */ { SK_PNMI_HRX_OCTETHIGH, SK_PNMI_HRX_BROADCAST},
+/* Bit34 */ { SK_PNMI_HRX_OCTETLOW, SK_PNMI_HRX_PMACC},
+/* Bit35 */ { SK_PNMI_HRX_BROADCAST, SK_PNMI_HRX_MULTICAST},
+/* Bit36 */ { SK_PNMI_HRX_MULTICAST, SK_PNMI_HRX_FCS},
+/* Bit37 */ { SK_PNMI_HRX_UNICAST, SK_PNMI_HRX_RESERVED},
+/* Bit38 */ { SK_PNMI_HRX_PMACC, SK_PNMI_HRX_OCTETLOW},
+/* Bit39 */ { SK_PNMI_HRX_MACC, SK_PNMI_HRX_OCTETHIGH},
+/* Bit40 */ { SK_PNMI_HRX_PMACC_ERR, SK_PNMI_HRX_BADOCTETLOW},
+/* Bit41 */ { SK_PNMI_HRX_MACC_UNKWN, SK_PNMI_HRX_BADOCTETHIGH},
+/* Bit42 */ { SK_PNMI_HRX_BURST, SK_PNMI_HRX_UNDERSIZE},
+/* Bit43 */ { SK_PNMI_HRX_MISSED, SK_PNMI_HRX_RUNT},
+/* Bit44 */ { SK_PNMI_HRX_FRAMING, SK_PNMI_HRX_64},
+/* Bit45 */ { SK_PNMI_HRX_OVERFLOW, SK_PNMI_HRX_127},
+/* Bit46 */ { SK_PNMI_HRX_JABBER, SK_PNMI_HRX_255},
+/* Bit47 */ { SK_PNMI_HRX_CARRIER, SK_PNMI_HRX_511},
+/* Bit48 */ { SK_PNMI_HRX_IRLENGTH, SK_PNMI_HRX_1023},
+/* Bit49 */ { SK_PNMI_HRX_SYMBOL, SK_PNMI_HRX_MAX},
+/* Bit50 */ { SK_PNMI_HRX_SHORTS, SK_PNMI_HRX_LONGFRAMES},
+/* Bit51 */ { SK_PNMI_HRX_RUNT, SK_PNMI_HRX_TOO_LONG},
+/* Bit52 */ { SK_PNMI_HRX_TOO_LONG, SK_PNMI_HRX_JABBER},
+/* Bit53 */ { SK_PNMI_HRX_FCS, SK_PNMI_HRX_RESERVED},
+/* Bit54 */ { SK_PNMI_HRX_RESERVED, SK_PNMI_HRX_OVERFLOW},
+/* Bit55 */ { SK_PNMI_HRX_CEXT, SK_PNMI_HRX_RESERVED},
+/* Bit56 */ { SK_PNMI_HRX_UTILUNDER, SK_PNMI_HRX_RESERVED},
+/* Bit57 */ { SK_PNMI_HRX_UTILOVER, SK_PNMI_HRX_RESERVED},
+/* Bit58 */ { SK_PNMI_HRX_64, SK_PNMI_HRX_RESERVED},
+/* Bit59 */ { SK_PNMI_HRX_127, SK_PNMI_HRX_RESERVED},
+/* Bit60 */ { SK_PNMI_HRX_255, SK_PNMI_HRX_RESERVED},
+/* Bit61 */ { SK_PNMI_HRX_511, SK_PNMI_HRX_RESERVED},
+/* Bit62 */ { SK_PNMI_HRX_1023, SK_PNMI_HRX_RESERVED},
+/* Bit63 */ { SK_PNMI_HRX_MAX, SK_PNMI_HRX_RESERVED}
+};
+
+/*
+ * Table for hardware register saving on resets and port switches
+ */
+PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = {
+ /* SK_PNMI_HTX */
+ {{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_OCTETHIGH */
+ {{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}},
+ /* SK_PNMI_HTX_OCTETLOW */
+ {{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}},
+ /* SK_PNMI_HTX_BROADCAST */
+ {{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}},
+ /* SK_PNMI_HTX_MULTICAST */
+ {{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}},
+ /* SK_PNMI_HTX_UNICAST */
+ {{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}},
+ /* SK_PNMI_HTX_BURST */
+ {{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_PMACC */
+ {{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}},
+ /* SK_PNMI_HTX_MACC */
+ {{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_COL */
+ {{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}},
+ /* SK_PNMI_HTX_SINGLE_COL */
+ {{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}},
+ /* SK_PNMI_HTX_MULTI_COL */
+ {{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}},
+ /* SK_PNMI_HTX_EXCESS_COL */
+ {{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}},
+ /* SK_PNMI_HTX_LATE_COL */
+ {{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}},
+ /* SK_PNMI_HTX_DEFFERAL */
+ {{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_EXCESS_DEF */
+ {{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_UNDERRUN */
+ {{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}},
+ /* SK_PNMI_HTX_CARRIER */
+ {{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_UTILUNDER */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_UTILOVER */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_64 */
+ {{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}},
+ /* SK_PNMI_HTX_127 */
+ {{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}},
+ /* SK_PNMI_HTX_255 */
+ {{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}},
+ /* SK_PNMI_HTX_511 */
+ {{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}},
+ /* SK_PNMI_HTX_1023 */
+ {{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}},
+ /* SK_PNMI_HTX_MAX */
+ {{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}},
+ /* SK_PNMI_HTX_LONGFRAMES */
+ {{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}},
+ /* SK_PNMI_HTX_SYNC */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_SYNC_OCTET */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HTX_RESERVED */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX */
+ {{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_OCTETHIGH */
+ {{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}},
+ /* SK_PNMI_HRX_OCTETLOW */
+ {{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}},
+ /* SK_PNMI_HRX_BADOCTETHIGH */
+ {{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}},
+ /* SK_PNMI_HRX_BADOCTETLOW */
+ {{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}},
+ /* SK_PNMI_HRX_BROADCAST */
+ {{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}},
+ /* SK_PNMI_HRX_MULTICAST */
+ {{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}},
+ /* SK_PNMI_HRX_UNICAST */
+ {{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}},
+ /* SK_PNMI_HRX_PMACC */
+ {{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}},
+ /* SK_PNMI_HRX_MACC */
+ {{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_PMACC_ERR */
+ {{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_MACC_UNKWN */
+ {{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_BURST */
+ {{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_MISSED */
+ {{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_FRAMING */
+ {{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_UNDERSIZE */
+ {{0, SK_FALSE}, {GM_RXF_SHT, SK_TRUE}},
+ /* SK_PNMI_HRX_OVERFLOW */
+ {{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}},
+ /* SK_PNMI_HRX_JABBER */
+ {{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}},
+ /* SK_PNMI_HRX_CARRIER */
+ {{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_IRLENGTH */
+ {{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_SYMBOL */
+ {{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_SHORTS */
+ {{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_RUNT */
+ {{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}},
+ /* SK_PNMI_HRX_TOO_LONG */
+ {{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}},
+ /* SK_PNMI_HRX_FCS */
+ {{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}},
+ /* SK_PNMI_HRX_CEXT */
+ {{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_UTILUNDER */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_UTILOVER */
+ {{0, SK_FALSE}, {0, SK_FALSE}},
+ /* SK_PNMI_HRX_64 */
+ {{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}},
+ /* SK_PNMI_HRX_127 */
+ {{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}},
+ /* SK_PNMI_HRX_255 */
+ {{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}},
+ /* SK_PNMI_HRX_511 */
+ {{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}},
+ /* SK_PNMI_HRX_1023 */
+ {{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}},
+ /* SK_PNMI_HRX_MAX */
+ {{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}},
+ /* SK_PNMI_HRX_LONGFRAMES */
+ {{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}},
+ /* SK_PNMI_HRX_RESERVED */
+ {{0, SK_FALSE}, {0, SK_FALSE}}
+};
+
+
+/*****************************************************************************
+ *
+ * Public functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * SkPnmiInit - Init function of PNMI
+ *
+ * Description:
+ * SK_INIT_DATA: Initialises the data structures
+ * SK_INIT_IO: Resets the XMAC statistics, determines the device and
+ * connector type.
+ * SK_INIT_RUN: Starts a timer event for port switch per hour
+ * calculation.
+ *
+ * Returns:
+ * Always 0
+ */
+int SkPnmiInit(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Level) /* Initialization level */
+{
+ unsigned int PortMax; /* Number of ports */
+ unsigned int PortIndex; /* Current port index in loop */
+ SK_U16 Val16; /* Multiple purpose 16 bit variable */
+ SK_U8 Val8; /* Mulitple purpose 8 bit variable */
+ SK_EVPARA EventParam; /* Event struct for timer event */
+ SK_PNMI_VCT *pVctBackupData;
+
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiInit: Called, level=%d\n", Level));
+
+ switch (Level) {
+
+ case SK_INIT_DATA:
+ SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi));
+ pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN;
+ pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+ pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES;
+ for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {
+
+ pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
+ pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+ }
+
+#ifdef SK_PNMI_CHECK
+ if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+ ("CounterOffset struct size (%d) differs from"
+ "SK_PNMI_MAX_IDX (%d)\n",
+ SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
+ }
+
+ if (SK_PNMI_MAX_IDX !=
+ (sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+ ("StatAddr table size (%d) differs from "
+ "SK_PNMI_MAX_IDX (%d)\n",
+ (sizeof(StatAddr) /
+ (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
+ SK_PNMI_MAX_IDX));
+ }
+#endif /* SK_PNMI_CHECK */
+ break;
+
+ case SK_INIT_IO:
+ /*
+ * Reset MAC counters
+ */
+ PortMax = pAC->GIni.GIMacsFound;
+
+ for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+
+ pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex);
+ }
+
+ /* Initialize DSP variables for Vct() to 0xff => Never written! */
+ for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+ pAC->GIni.GP[PortIndex].PCableLen = 0xff;
+ pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex];
+ pVctBackupData->PCableLen = 0xff;
+ }
+
+ /*
+ * Get pci bus speed
+ */
+ SK_IN16(IoC, B0_CTST, &Val16);
+ if ((Val16 & CS_BUS_CLOCK) == 0) {
+
+ pAC->Pnmi.PciBusSpeed = 33;
+ }
+ else {
+ pAC->Pnmi.PciBusSpeed = 66;
+ }
+
+ /*
+ * Get pci bus width
+ */
+ SK_IN16(IoC, B0_CTST, &Val16);
+ if ((Val16 & CS_BUS_SLOT_SZ) == 0) {
+
+ pAC->Pnmi.PciBusWidth = 32;
+ }
+ else {
+ pAC->Pnmi.PciBusWidth = 64;
+ }
+
+ /*
+ * Get chipset
+ */
+ switch (pAC->GIni.GIChipId) {
+ case CHIP_ID_GENESIS:
+ pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC;
+ break;
+
+ case CHIP_ID_YUKON:
+ pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Get PMD and DeviceType
+ */
+ SK_IN8(IoC, B2_PMD_TYP, &Val8);
+ switch (Val8) {
+ case 'S':
+ pAC->Pnmi.PMD = 3;
+ if (pAC->GIni.GIMacsFound > 1) {
+
+ pAC->Pnmi.DeviceType = 0x00020002;
+ }
+ else {
+ pAC->Pnmi.DeviceType = 0x00020001;
+ }
+ break;
+
+ case 'L':
+ pAC->Pnmi.PMD = 2;
+ if (pAC->GIni.GIMacsFound > 1) {
+
+ pAC->Pnmi.DeviceType = 0x00020004;
+ }
+ else {
+ pAC->Pnmi.DeviceType = 0x00020003;
+ }
+ break;
+
+ case 'C':
+ pAC->Pnmi.PMD = 4;
+ if (pAC->GIni.GIMacsFound > 1) {
+
+ pAC->Pnmi.DeviceType = 0x00020006;
+ }
+ else {
+ pAC->Pnmi.DeviceType = 0x00020005;
+ }
+ break;
+
+ case 'T':
+ pAC->Pnmi.PMD = 5;
+ if (pAC->GIni.GIMacsFound > 1) {
+
+ pAC->Pnmi.DeviceType = 0x00020008;
+ }
+ else {
+ pAC->Pnmi.DeviceType = 0x00020007;
+ }
+ break;
+
+ default :
+ pAC->Pnmi.PMD = 1;
+ pAC->Pnmi.DeviceType = 0;
+ break;
+ }
+
+ /*
+ * Get connector
+ */
+ SK_IN8(IoC, B2_CONN_TYP, &Val8);
+ switch (Val8) {
+ case 'C':
+ pAC->Pnmi.Connector = 2;
+ break;
+
+ case 'D':
+ pAC->Pnmi.Connector = 3;
+ break;
+
+ case 'F':
+ pAC->Pnmi.Connector = 4;
+ break;
+
+ case 'J':
+ pAC->Pnmi.Connector = 5;
+ break;
+
+ case 'V':
+ pAC->Pnmi.Connector = 6;
+ break;
+
+ default:
+ pAC->Pnmi.Connector = 1;
+ break;
+ }
+ break;
+
+ case SK_INIT_RUN:
+ /*
+ * Start timer for RLMT change counter
+ */
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+ SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+ 28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+ EventParam);
+ break;
+
+ default:
+ break; /* Nothing todo */
+ }
+
+ return (0);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetVar - Retrieves the value of a single OID
+ *
+ * Description:
+ * Calls a general sub-function for all this stuff. If the instance
+ * -1 is passed, the values of all instances are returned in an
+ * array of values.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take
+ * the data.
+ * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+static int SkPnmiGetVar(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 Id, /* Object ID that is to be processed */
+void *pBuf, /* Buffer to which the management data will be copied */
+unsigned int *pLen, /* On call: buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+ Id, *pLen, Instance, NetIndex));
+
+ return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
+ Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetVar - Presets the value of a single OID
+ *
+ * Description:
+ * Calls a general sub-function for all this stuff. The preset does
+ * the same as a set, but returns just before finally setting the
+ * new value. This is useful to check if a set might be successfull.
+ * If the instance -1 is passed, an array of values is supposed and
+ * all instances of the OID will be set.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+static int SkPnmiPreSetVar(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 Id, /* Object ID that is to be processed */
+void *pBuf, /* Buffer to which the management data will be copied */
+unsigned int *pLen, /* Total length of management data */
+SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+ Id, *pLen, Instance, NetIndex));
+
+
+ return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
+ Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetVar - Sets the value of a single OID
+ *
+ * Description:
+ * Calls a general sub-function for all this stuff. The preset does
+ * the same as a set, but returns just before finally setting the
+ * new value. This is useful to check if a set might be successfull.
+ * If the instance -1 is passed, an array of values is supposed and
+ * all instances of the OID will be set.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+int SkPnmiSetVar(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 Id, /* Object ID that is to be processed */
+void *pBuf, /* Buffer to which the management data will be copied */
+unsigned int *pLen, /* Total length of management data */
+SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+ Id, *pLen, Instance, NetIndex));
+
+ return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
+ Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ * Runs through the IdTable, queries the single OIDs and stores the
+ * returned data into the management database structure
+ * SK_PNMI_STRUCT_DATA. The offset of the OID in the structure
+ * is stored in the IdTable. The return value of the function will also
+ * be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ * minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take
+ * the data.
+ * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist
+ */
+int SkPnmiGetStruct(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+void *pBuf, /* Buffer to which the management data will be copied. */
+unsigned int *pLen, /* Length of buffer */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ unsigned int TableIndex;
+ unsigned int DstOffset;
+ unsigned int InstanceNo;
+ unsigned int InstanceCnt;
+ SK_U32 Instance;
+ unsigned int TmpLen;
+ char KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n",
+ *pLen, NetIndex));
+
+ if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+ if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+ SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+ (SK_U32)(-1));
+ }
+
+ *pLen = SK_PNMI_STRUCT_SIZE;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * Check NetIndex
+ */
+ if (NetIndex >= pAC->Rlmt.NumNets) {
+ return (SK_PNMI_ERR_UNKNOWN_NET);
+ }
+
+ /* Update statistic */
+ SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");
+
+ if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) !=
+ SK_PNMI_ERR_OK) {
+
+ SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (Ret);
+ }
+
+ if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+ SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (Ret);
+ }
+
+ if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+ SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (Ret);
+ }
+
+ /*
+ * Increment semaphores to indicate that an update was
+ * already done
+ */
+ pAC->Pnmi.MacUpdatedFlag ++;
+ pAC->Pnmi.RlmtUpdatedFlag ++;
+ pAC->Pnmi.SirqUpdatedFlag ++;
+
+ /* Get vpd keys for instance calculation */
+ Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen);
+ if (Ret != SK_PNMI_ERR_OK) {
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+ SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /* Retrieve values */
+ SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
+ for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+ InstanceNo = IdTable[TableIndex].InstanceNo;
+ for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+ InstanceCnt ++) {
+
+ DstOffset = IdTable[TableIndex].Offset +
+ (InstanceCnt - 1) *
+ IdTable[TableIndex].StructSize;
+
+ /*
+ * For the VPD the instance is not an index number
+ * but the key itself. Determin with the instance
+ * counter the VPD key to be used.
+ */
+ if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY ||
+ IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE ||
+ IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
+ IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {
+
+ SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4);
+ }
+ else {
+ Instance = (SK_U32)InstanceCnt;
+ }
+
+ TmpLen = *pLen - DstOffset;
+ Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
+ IdTable[TableIndex].Id, (char *)pBuf +
+ DstOffset, &TmpLen, Instance, TableIndex, NetIndex);
+
+ /*
+ * An unknown instance error means that we reached
+ * the last instance of that variable. Proceed with
+ * the next OID in the table and ignore the return
+ * code.
+ */
+ if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+ break;
+ }
+
+ if (Ret != SK_PNMI_ERR_OK) {
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+ SK_PNMI_SET_STAT(pBuf, Ret, DstOffset);
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (Ret);
+ }
+ }
+ }
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ *pLen = SK_PNMI_STRUCT_SIZE;
+ SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+ SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ * Calls a general sub-function for all this set stuff. The preset does
+ * the same as a set, but returns just before finally setting the
+ * new value. This is useful to check if a set might be successfull.
+ * The sub-function runs through the IdTable, checks which OIDs are able
+ * to set, and calls the handler function of the OID to perform the
+ * preset. The return value of the function will also be stored in
+ * SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ * SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ */
+int SkPnmiPreSetStruct(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+void *pBuf, /* Buffer which contains the data to be set */
+unsigned int *pLen, /* Length of buffer */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+ *pLen, NetIndex));
+
+ return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf,
+ pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ * Calls a general sub-function for all this set stuff. The return value
+ * of the function will also be stored in SK_PNMI_STRUCT_DATA if the
+ * passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ * The sub-function runs through the IdTable, checks which OIDs are able
+ * to set, and calls the handler function of the OID to perform the
+ * set. The return value of the function will also be stored in
+ * SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ * SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ */
+int SkPnmiSetStruct(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+void *pBuf, /* Buffer which contains the data to be set */
+unsigned int *pLen, /* Length of buffer */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+ *pLen, NetIndex));
+
+ return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf,
+ pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiEvent - Event handler
+ *
+ * Description:
+ * Handles the following events:
+ * SK_PNMI_EVT_SIRQ_OVERFLOW When a hardware counter overflows an
+ * interrupt will be generated which is
+ * first handled by SIRQ which generates a
+ * this event. The event increments the
+ * upper 32 bit of the 64 bit counter.
+ * SK_PNMI_EVT_SEN_XXX The event is generated by the I2C module
+ * when a sensor reports a warning or
+ * error. The event will store a trap
+ * message in the trap buffer.
+ * SK_PNMI_EVT_CHG_EST_TIMER The timer event was initiated by this
+ * module and is used to calculate the
+ * port switches per hour.
+ * SK_PNMI_EVT_CLEAR_COUNTER The event clears all counters and
+ * timestamps.
+ * SK_PNMI_EVT_XMAC_RESET The event is generated by the driver
+ * before a hard reset of the XMAC is
+ * performed. All counters will be saved
+ * and added to the hardware counter
+ * values after reset to grant continuous
+ * counter values.
+ * SK_PNMI_EVT_RLMT_PORT_UP Generated by RLMT to notify that a port
+ * went logically up. A trap message will
+ * be stored to the trap buffer.
+ * SK_PNMI_EVT_RLMT_PORT_DOWN Generated by RLMT to notify that a port
+ * went logically down. A trap message will
+ * be stored to the trap buffer.
+ * SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
+ * spanning tree root bridges were
+ * detected. A trap message will be stored
+ * to the trap buffer.
+ * SK_PNMI_EVT_RLMT_ACTIVE_DOWN Notifies PNMI that an active port went
+ * down. PNMI will not further add the
+ * statistic values to the virtual port.
+ * SK_PNMI_EVT_RLMT_ACTIVE_UP Notifies PNMI that a port went up and
+ * is now an active port. PNMI will now
+ * add the statistic data of this port to
+ * the virtual port.
+ * SK_PNMI_EVT_RLMT_SET_NETS Notifies PNMI about the net mode. The first parameter
+ * contains the number of nets. 1 means single net, 2 means
+ * dual net. The second parameter is -1
+ *
+ * Returns:
+ * Always 0
+ */
+int SkPnmiEvent(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 Event, /* Event-Id */
+SK_EVPARA Param) /* Event dependent parameter */
+{
+ unsigned int PhysPortIndex;
+ unsigned int MaxNetNumber;
+ int CounterIndex;
+ int Ret;
+ SK_U16 MacStatus;
+ SK_U64 OverflowStatus;
+ SK_U64 Mask;
+ int MacType;
+ SK_U64 Value;
+ SK_U32 Val32;
+ SK_U16 Register;
+ SK_EVPARA EventParam;
+ SK_U64 NewestValue;
+ SK_U64 OldestValue;
+ SK_U64 Delta;
+ SK_PNMI_ESTIMATE *pEst;
+ SK_U32 NetIndex;
+ SK_GEPORT *pPrt;
+ SK_PNMI_VCT *pVctBackupData;
+ SK_U32 RetCode;
+ int i;
+ SK_U32 CableLength;
+
+
+#ifdef DEBUG
+ if (Event != SK_PNMI_EVT_XMAC_RESET) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
+ (unsigned int)Event, (unsigned int)Param.Para64));
+ }
+#endif /* DEBUG */
+ SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");
+
+ MacType = pAC->GIni.GIMacType;
+
+ switch (Event) {
+
+ case SK_PNMI_EVT_SIRQ_OVERFLOW:
+ PhysPortIndex = (int)Param.Para32[0];
+ MacStatus = (SK_U16)Param.Para32[1];
+#ifdef DEBUG
+ if (PhysPortIndex >= SK_MAX_MACS) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter"
+ " wrong, PhysPortIndex=0x%x\n",
+ PhysPortIndex));
+ return (0);
+ }
+#endif /* DEBUG */
+ OverflowStatus = 0;
+
+ /*
+ * Check which source caused an overflow interrupt.
+ */
+ if ((pAC->GIni.GIFunc.pFnMacOverflow(pAC, IoC, PhysPortIndex,
+ MacStatus, &OverflowStatus) != 0) ||
+ (OverflowStatus == 0)) {
+
+ SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+ return (0);
+ }
+
+ /*
+ * Check the overflow status register and increment
+ * the upper dword of corresponding counter.
+ */
+ for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8;
+ CounterIndex ++) {
+
+ Mask = (SK_U64)1 << CounterIndex;
+ if ((OverflowStatus & Mask) == 0) {
+
+ continue;
+ }
+
+ switch (StatOvrflwBit[CounterIndex][MacType]) {
+
+ case SK_PNMI_HTX_UTILUNDER:
+ case SK_PNMI_HTX_UTILOVER:
+ if (MacType == SK_MAC_XMAC) {
+ XM_IN16(IoC, PhysPortIndex, XM_TX_CMD, &Register);
+ Register |= XM_TX_SAM_LINE;
+ XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD, Register);
+ }
+ break;
+
+ case SK_PNMI_HRX_UTILUNDER:
+ case SK_PNMI_HRX_UTILOVER:
+ if (MacType == SK_MAC_XMAC) {
+ XM_IN16(IoC, PhysPortIndex, XM_RX_CMD, &Register);
+ Register |= XM_RX_SAM_LINE;
+ XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD, Register);
+ }
+ break;
+
+ case SK_PNMI_HTX_OCTETHIGH:
+ case SK_PNMI_HTX_OCTETLOW:
+ case SK_PNMI_HTX_RESERVED:
+ case SK_PNMI_HRX_OCTETHIGH:
+ case SK_PNMI_HRX_OCTETLOW:
+ case SK_PNMI_HRX_IRLENGTH:
+ case SK_PNMI_HRX_RESERVED:
+
+ /*
+ * the following counters aren't be handled (id > 63)
+ */
+ case SK_PNMI_HTX_SYNC:
+ case SK_PNMI_HTX_SYNC_OCTET:
+ break;
+
+ case SK_PNMI_HRX_LONGFRAMES:
+ if (MacType == SK_MAC_GMAC) {
+ pAC->Pnmi.Port[PhysPortIndex].
+ CounterHigh[CounterIndex] ++;
+ }
+ break;
+
+ default:
+ pAC->Pnmi.Port[PhysPortIndex].
+ CounterHigh[CounterIndex] ++;
+ }
+ }
+ break;
+
+ case SK_PNMI_EVT_SEN_WAR_LOW:
+#ifdef DEBUG
+ if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n",
+ (unsigned int)Param.Para64));
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Store a trap message in the trap buffer and generate
+ * an event for user space applications with the
+ * SK_DRIVER_SENDEVENT macro.
+ */
+ QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW,
+ (unsigned int)Param.Para64);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+ break;
+
+ case SK_PNMI_EVT_SEN_WAR_UPP:
+#ifdef DEBUG
+ if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n",
+ (unsigned int)Param.Para64));
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Store a trap message in the trap buffer and generate
+ * an event for user space applications with the
+ * SK_DRIVER_SENDEVENT macro.
+ */
+ QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP,
+ (unsigned int)Param.Para64);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+ break;
+
+ case SK_PNMI_EVT_SEN_ERR_LOW:
+#ifdef DEBUG
+ if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n",
+ (unsigned int)Param.Para64));
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Store a trap message in the trap buffer and generate
+ * an event for user space applications with the
+ * SK_DRIVER_SENDEVENT macro.
+ */
+ QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW,
+ (unsigned int)Param.Para64);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+ break;
+
+ case SK_PNMI_EVT_SEN_ERR_UPP:
+#ifdef DEBUG
+ if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n",
+ (unsigned int)Param.Para64));
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Store a trap message in the trap buffer and generate
+ * an event for user space applications with the
+ * SK_DRIVER_SENDEVENT macro.
+ */
+ QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP,
+ (unsigned int)Param.Para64);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+ break;
+
+ case SK_PNMI_EVT_CHG_EST_TIMER:
+ /*
+ * Calculate port switch average on a per hour basis
+ * Time interval for check : 28125 ms
+ * Number of values for average : 8
+ *
+ * Be careful in changing these values, on change check
+ * - typedef of SK_PNMI_ESTIMATE (Size of EstValue
+ * array one less than value number)
+ * - Timer initialization SkTimerStart() in SkPnmiInit
+ * - Delta value below must be multiplicated with
+ * power of 2
+ *
+ */
+ pEst = &pAC->Pnmi.RlmtChangeEstimate;
+ CounterIndex = pEst->EstValueIndex + 1;
+ if (CounterIndex == 7) {
+
+ CounterIndex = 0;
+ }
+ pEst->EstValueIndex = CounterIndex;
+
+ NewestValue = pAC->Pnmi.RlmtChangeCts;
+ OldestValue = pEst->EstValue[CounterIndex];
+ pEst->EstValue[CounterIndex] = NewestValue;
+
+ /*
+ * Calculate average. Delta stores the number of
+ * port switches per 28125 * 8 = 225000 ms
+ */
+ if (NewestValue >= OldestValue) {
+
+ Delta = NewestValue - OldestValue;
+ }
+ else {
+ /* Overflow situation */
+ Delta = (SK_U64)(0 - OldestValue) + NewestValue;
+ }
+
+ /*
+ * Extrapolate delta to port switches per hour.
+ * Estimate = Delta * (3600000 / 225000)
+ * = Delta * 16
+ * = Delta << 4
+ */
+ pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4;
+
+ /*
+ * Check if threshold is exceeded. If the threshold is
+ * permanently exceeded every 28125 ms an event will be
+ * generated to remind the user of this condition.
+ */
+ if ((pAC->Pnmi.RlmtChangeThreshold != 0) &&
+ (pAC->Pnmi.RlmtChangeEstimate.Estimate >=
+ pAC->Pnmi.RlmtChangeThreshold)) {
+
+ QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+ }
+
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+ SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+ 28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+ EventParam);
+ break;
+
+ case SK_PNMI_EVT_CLEAR_COUNTER:
+ /*
+ * Param.Para32[0] contains the NetIndex (0 ..1).
+ * Param.Para32[1] is reserved, contains -1.
+ */
+ NetIndex = (SK_U32)Param.Para32[0];
+
+#ifdef DEBUG
+ if (NetIndex >= pAC->Rlmt.NumNets) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n",
+ NetIndex));
+
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Set all counters and timestamps to zero.
+ * The according NetIndex is required as a
+ * parameter of the event.
+ */
+ ResetCounter(pAC, IoC, NetIndex);
+ break;
+
+ case SK_PNMI_EVT_XMAC_RESET:
+ /*
+ * To grant continuous counter values store the current
+ * XMAC statistic values to the entries 1..n of the
+ * CounterOffset array. XMAC Errata #2
+ */
+#ifdef DEBUG
+ if ((unsigned int)Param.Para64 >= SK_MAX_MACS) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n",
+ (unsigned int)Param.Para64));
+ return (0);
+ }
+#endif
+ PhysPortIndex = (unsigned int)Param.Para64;
+
+ /*
+ * Update XMAC statistic to get fresh values
+ */
+ Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+ if (Ret != SK_PNMI_ERR_OK) {
+
+ SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+ return (0);
+ }
+ /*
+ * Increment semaphore to indicate that an update was
+ * already done
+ */
+ pAC->Pnmi.MacUpdatedFlag ++;
+
+ for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+ CounterIndex ++) {
+
+ if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+ continue;
+ }
+
+ pAC->Pnmi.Port[PhysPortIndex].CounterOffset[CounterIndex] =
+ GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+ pAC->Pnmi.Port[PhysPortIndex].CounterHigh[CounterIndex] = 0;
+ }
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ break;
+
+ case SK_PNMI_EVT_RLMT_PORT_UP:
+ PhysPortIndex = (unsigned int)Param.Para32[0];
+#ifdef DEBUG
+ if (PhysPortIndex >= SK_MAX_MACS) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter"
+ " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Store a trap message in the trap buffer and generate an event for
+ * user space applications with the SK_DRIVER_SENDEVENT macro.
+ */
+ QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+ /* Bugfix for XMAC errata (#10620)*/
+ if (MacType == SK_MAC_XMAC) {
+ /* Add incremental difference to offset (#10620)*/
+ (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ XM_RXE_SHT_ERR, &Val32);
+
+ Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+ CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+ pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] +=
+ Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark;
+ }
+
+ /* Tell VctStatus() that a link was up meanwhile. */
+ pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK;
+ break;
+
+ case SK_PNMI_EVT_RLMT_PORT_DOWN:
+ PhysPortIndex = (unsigned int)Param.Para32[0];
+
+#ifdef DEBUG
+ if (PhysPortIndex >= SK_MAX_MACS) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter"
+ " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+ return (0);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Store a trap message in the trap buffer and generate an event for
+ * user space applications with the SK_DRIVER_SENDEVENT macro.
+ */
+ QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+ /* Bugfix #10620 - get zero level for incremental difference */
+ if (MacType == SK_MAC_XMAC) {
+
+ (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ XM_RXE_SHT_ERR, &Val32);
+
+ pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark =
+ (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+ CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+ }
+ break;
+
+ case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
+ PhysPortIndex = (unsigned int)Param.Para32[0];
+ NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+ if (PhysPortIndex >= SK_MAX_MACS) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
+ PhysPortIndex));
+ }
+
+ if (NetIndex >= pAC->Rlmt.NumNets) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n",
+ NetIndex));
+ }
+#endif /* DEBUG */
+
+ /*
+ * For now, ignore event if NetIndex != 0.
+ */
+ if (Param.Para32[1] != 0) {
+
+ return (0);
+ }
+
+ /*
+ * Nothing to do if port is already inactive
+ */
+ if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ return (0);
+ }
+
+ /*
+ * Update statistic counters to calculate new offset for the virtual
+ * port and increment semaphore to indicate that an update was already
+ * done.
+ */
+ if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+ SK_PNMI_ERR_OK) {
+
+ SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+ return (0);
+ }
+ pAC->Pnmi.MacUpdatedFlag ++;
+
+ /*
+ * Calculate new counter offset for virtual port to grant continous
+ * counting on port switches. The virtual port consists of all currently
+ * active ports. The port down event indicates that a port is removed
+ * from the virtual port. Therefore add the counter value of the removed
+ * port to the CounterOffset for the virtual port to grant the same
+ * counter value.
+ */
+ for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+ CounterIndex ++) {
+
+ if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+ continue;
+ }
+
+ Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+ pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
+ }
+
+ /*
+ * Set port to inactive
+ */
+ pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE;
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ break;
+
+ case SK_PNMI_EVT_RLMT_ACTIVE_UP:
+ PhysPortIndex = (unsigned int)Param.Para32[0];
+ NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+ if (PhysPortIndex >= SK_MAX_MACS) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
+ PhysPortIndex));
+ }
+
+ if (NetIndex >= pAC->Rlmt.NumNets) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n",
+ NetIndex));
+ }
+#endif /* DEBUG */
+
+ /*
+ * For now, ignore event if NetIndex != 0.
+ */
+ if (Param.Para32[1] != 0) {
+
+ return (0);
+ }
+
+ /*
+ * Nothing to do if port is already active
+ */
+ if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ return (0);
+ }
+
+ /*
+ * Statistic maintenance
+ */
+ pAC->Pnmi.RlmtChangeCts ++;
+ pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+
+ /*
+ * Store a trap message in the trap buffer and generate an event for
+ * user space applications with the SK_DRIVER_SENDEVENT macro.
+ */
+ QueueRlmtNewMacTrap(pAC, PhysPortIndex);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+ /*
+ * Update statistic counters to calculate new offset for the virtual
+ * port and increment semaphore to indicate that an update was
+ * already done.
+ */
+ if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+ SK_PNMI_ERR_OK) {
+
+ SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+ return (0);
+ }
+ pAC->Pnmi.MacUpdatedFlag ++;
+
+ /*
+ * Calculate new counter offset for virtual port to grant continous
+ * counting on port switches. A new port is added to the virtual port.
+ * Therefore substract the counter value of the new port from the
+ * CounterOffset for the virtual port to grant the same value.
+ */
+ for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+ CounterIndex ++) {
+
+ if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+ continue;
+ }
+
+ Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+ pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
+ }
+
+ /* Set port to active */
+ pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE;
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ break;
+
+ case SK_PNMI_EVT_RLMT_SEGMENTATION:
+ /*
+ * Para.Para32[0] contains the NetIndex.
+ */
+
+ /*
+ * Store a trap message in the trap buffer and generate an event for
+ * user space applications with the SK_DRIVER_SENDEVENT macro.
+ */
+ QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
+ (void)SK_DRIVER_SENDEVENT(pAC, IoC);
+ break;
+
+ case SK_PNMI_EVT_RLMT_SET_NETS:
+ /*
+ * Param.Para32[0] contains the number of Nets.
+ * Param.Para32[1] is reserved, contains -1.
+ */
+ /*
+ * Check number of nets
+ */
+ MaxNetNumber = pAC->GIni.GIMacsFound;
+ if (((unsigned int)Param.Para32[0] < 1)
+ || ((unsigned int)Param.Para32[0] > MaxNetNumber)) {
+ return (SK_PNMI_ERR_UNKNOWN_NET);
+ }
+
+ if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */
+ pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+ }
+ else { /* dual net mode */
+ pAC->Pnmi.DualNetActiveFlag = SK_TRUE;
+ }
+ break;
+
+ case SK_PNMI_EVT_VCT_RESET:
+ PhysPortIndex = Param.Para32[0];
+ pPrt = &pAC->GIni.GP[PhysPortIndex];
+ pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+
+ if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+ RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+ if (RetCode == 2) {
+ /*
+ * VCT test is still running.
+ * Start VCT timer counter again.
+ */
+ SK_MEMSET((char *) &Param, 0, sizeof(Param));
+ Param.Para32[0] = PhysPortIndex;
+ Param.Para32[1] = -1;
+ SkTimerStart(pAC, IoC,
+ &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+ 4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param);
+ break;
+ }
+ pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+ pAC->Pnmi.VctStatus[PhysPortIndex] |=
+ (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+
+ /* Copy results for later use to PNMI struct. */
+ for (i = 0; i < 4; i++) {
+ if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+ if ((pPrt->PMdiPairLen[i] > 35) &&
+ (pPrt->PMdiPairLen[i] < 0xff)) {
+ pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+ }
+ }
+ if ((pPrt->PMdiPairLen[i] > 35) &&
+ (pPrt->PMdiPairLen[i] != 0xff)) {
+ CableLength = 1000 *
+ (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+ }
+ else {
+ CableLength = 0;
+ }
+ pVctBackupData->PMdiPairLen[i] = CableLength;
+ pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+ }
+
+ Param.Para32[0] = PhysPortIndex;
+ Param.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param);
+ SkEventDispatcher(pAC, IoC);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+ return (0);
+}
+
+
+/******************************************************************************
+ *
+ * Private functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * PnmiVar - Gets, presets, and sets single OIDs
+ *
+ * Description:
+ * Looks up the requested OID, calls the corresponding handler
+ * function, and passes the parameters with the get, preset, or
+ * set command. The function is called by SkGePnmiGetVar,
+ * SkGePnmiPreSetVar, or SkGePnmiSetVar.
+ *
+ * Returns:
+ * SK_PNMI_ERR_XXX. For details have a look at the description of the
+ * calling functions.
+ * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiVar(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* Total length of pBuf management data */
+SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int TableIndex;
+ int Ret;
+
+
+ if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_OID);
+ }
+
+ /* Check NetIndex */
+ if (NetIndex >= pAC->Rlmt.NumNets) {
+ return (SK_PNMI_ERR_UNKNOWN_NET);
+ }
+
+ SK_PNMI_CHECKFLAGS("PnmiVar: On call");
+
+ Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
+ Instance, TableIndex, NetIndex);
+
+ SK_PNMI_CHECKFLAGS("PnmiVar: On return");
+
+ return (Ret);
+}
+
+/*****************************************************************************
+ *
+ * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ * The return value of the function will also be stored in
+ * SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ * SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable,
+ * checks which OIDs are able to set, and calls the handler function of
+ * the OID to perform the set. The return value of the function will
+ * also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ * minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called
+ * by SkGePnmiPreSetStruct and SkGePnmiSetStruct.
+ *
+ * Returns:
+ * SK_PNMI_ERR_XXX. The codes are described in the calling functions.
+ * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiStruct(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* PRESET/SET action to be performed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* Length of pBuf management data buffer */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ unsigned int TableIndex;
+ unsigned int DstOffset;
+ unsigned int Len;
+ unsigned int InstanceNo;
+ unsigned int InstanceCnt;
+ SK_U32 Instance;
+ SK_U32 Id;
+
+
+ /* Check if the passed buffer has the right size */
+ if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+ /* Check if we can return the error within the buffer */
+ if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+ SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+ (SK_U32)(-1));
+ }
+
+ *pLen = SK_PNMI_STRUCT_SIZE;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /* Check NetIndex */
+ if (NetIndex >= pAC->Rlmt.NumNets) {
+ return (SK_PNMI_ERR_UNKNOWN_NET);
+ }
+
+ SK_PNMI_CHECKFLAGS("PnmiStruct: On call");
+
+ /*
+ * Update the values of RLMT and SIRQ and increment semaphores to
+ * indicate that an update was already done.
+ */
+ if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+ SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (Ret);
+ }
+
+ if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+ SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (Ret);
+ }
+
+ pAC->Pnmi.RlmtUpdatedFlag ++;
+ pAC->Pnmi.SirqUpdatedFlag ++;
+
+ /* Preset/Set values */
+ for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+ if ((IdTable[TableIndex].Access != SK_PNMI_RW) &&
+ (IdTable[TableIndex].Access != SK_PNMI_WO)) {
+
+ continue;
+ }
+
+ InstanceNo = IdTable[TableIndex].InstanceNo;
+ Id = IdTable[TableIndex].Id;
+
+ for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+ InstanceCnt ++) {
+
+ DstOffset = IdTable[TableIndex].Offset +
+ (InstanceCnt - 1) *
+ IdTable[TableIndex].StructSize;
+
+ /*
+ * Because VPD multiple instance variables are
+ * not setable we do not need to evaluate VPD
+ * instances. Have a look to VPD instance
+ * calculation in SkPnmiGetStruct().
+ */
+ Instance = (SK_U32)InstanceCnt;
+
+ /*
+ * Evaluate needed buffer length
+ */
+ Len = 0;
+ Ret = IdTable[TableIndex].Func(pAC, IoC,
+ SK_PNMI_GET, IdTable[TableIndex].Id,
+ NULL, &Len, Instance, TableIndex, NetIndex);
+
+ if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+ break;
+ }
+ if (Ret != SK_PNMI_ERR_TOO_SHORT) {
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+ SK_PNMI_SET_STAT(pBuf,
+ SK_PNMI_ERR_GENERAL, DstOffset);
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ if (Id == OID_SKGE_VPD_ACTION) {
+
+ switch (*(pBuf + DstOffset)) {
+
+ case SK_PNMI_VPD_CREATE:
+ Len = 3 + *(pBuf + DstOffset + 3);
+ break;
+
+ case SK_PNMI_VPD_DELETE:
+ Len = 3;
+ break;
+
+ default:
+ Len = 1;
+ break;
+ }
+ }
+
+ /* Call the OID handler function */
+ Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
+ IdTable[TableIndex].Id, pBuf + DstOffset,
+ &Len, Instance, TableIndex, NetIndex);
+
+ if (Ret != SK_PNMI_ERR_OK) {
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+ SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE,
+ DstOffset);
+ *pLen = SK_PNMI_MIN_STRUCT_SIZE;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ }
+ }
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+ SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * LookupId - Lookup an OID in the IdTable
+ *
+ * Description:
+ * Scans the IdTable to find the table entry of an OID.
+ *
+ * Returns:
+ * The table index or -1 if not found.
+ */
+PNMI_STATIC int LookupId(
+SK_U32 Id) /* Object identifier to be searched */
+{
+ int i;
+
+ for (i = 0; i < ID_TABLE_SIZE; i++) {
+
+ if (IdTable[i].Id == Id) {
+
+ return i;
+ }
+ }
+
+ return (-1);
+}
+
+/*****************************************************************************
+ *
+ * OidStruct - Handler of OID_SKGE_ALL_DATA
+ *
+ * Description:
+ * This OID performs a Get/Preset/SetStruct call and returns all data
+ * in a SK_PNMI_STRUCT_DATA structure.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int OidStruct(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ if (Id != OID_SKGE_ALL_DATA) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003,
+ SK_PNMI_ERR003MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * Check instance. We only handle single instance variables
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ switch (Action) {
+
+ case SK_PNMI_GET:
+ return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+ case SK_PNMI_PRESET:
+ return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+ case SK_PNMI_SET:
+ return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+ }
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+}
+
+/*****************************************************************************
+ *
+ * Perform - OID handler of OID_SKGE_ACTION
+ *
+ * Description:
+ * None.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int Perform(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ SK_U32 ActionOp;
+
+
+ /*
+ * Check instance. We only handle single instance variables
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /* Check if a get should be performed */
+ if (Action == SK_PNMI_GET) {
+
+ /* A get is easy. We always return the same value */
+ ActionOp = (SK_U32)SK_PNMI_ACT_IDLE;
+ SK_PNMI_STORE_U32(pBuf, ActionOp);
+ *pLen = sizeof(SK_U32);
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* Continue with PRESET/SET action */
+ if (*pLen > sizeof(SK_U32)) {
+
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* Check if the command is a known one */
+ SK_PNMI_READ_U32(pBuf, ActionOp);
+ if (*pLen > sizeof(SK_U32) ||
+ (ActionOp != SK_PNMI_ACT_IDLE &&
+ ActionOp != SK_PNMI_ACT_RESET &&
+ ActionOp != SK_PNMI_ACT_SELFTEST &&
+ ActionOp != SK_PNMI_ACT_RESETCNT)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* A preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ switch (ActionOp) {
+
+ case SK_PNMI_ACT_IDLE:
+ /* Nothing to do */
+ break;
+
+ case SK_PNMI_ACT_RESET:
+ /*
+ * Perform a driver reset or something that comes near
+ * to this.
+ */
+ Ret = SK_DRIVER_RESET(pAC, IoC);
+ if (Ret != 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005,
+ SK_PNMI_ERR005MSG);
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ break;
+
+ case SK_PNMI_ACT_SELFTEST:
+ /*
+ * Perform a driver selftest or something similar to this.
+ * Currently this feature is not used and will probably
+ * implemented in another way.
+ */
+ Ret = SK_DRIVER_SELFTEST(pAC, IoC);
+ pAC->Pnmi.TestResult = Ret;
+ break;
+
+ case SK_PNMI_ACT_RESETCNT:
+ /* Set all counters and timestamps to zero */
+ ResetCounter(pAC, IoC, NetIndex);
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006,
+ SK_PNMI_ERR006MSG);
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX
+ *
+ * Description:
+ * Retrieves the statistic values of the virtual port (logical
+ * index 0). Only special OIDs of NDIS are handled which consist
+ * of a 32 bit instead of a 64 bit value. The OIDs are public
+ * because perhaps some other platform can use them too.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int Mac8023Stat(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ SK_U64 StatVal;
+ SK_U32 StatVal32;
+ SK_BOOL Is64BitReq = SK_FALSE;
+
+ /*
+ * Only the active Mac is returned
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ /*
+ * Check action type
+ */
+ if (Action != SK_PNMI_GET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /* Check length */
+ switch (Id) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ if (*pLen < sizeof(SK_MAC_ADDR)) {
+
+ *pLen = sizeof(SK_MAC_ADDR);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+#ifndef SK_NDIS_64BIT_CTR
+ if (*pLen < sizeof(SK_U32)) {
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+#else /* SK_NDIS_64BIT_CTR */
+
+ /* for compatibility, at least 32bit are required for OID */
+ if (*pLen < sizeof(SK_U32)) {
+ /*
+ * but indicate handling for 64bit values,
+ * if insufficient space is provided
+ */
+ *pLen = sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+ break;
+ }
+
+ /*
+ * Update all statistics, because we retrieve virtual MAC, which
+ * consists of multiple physical statistics and increment semaphore
+ * to indicate that an update was already done.
+ */
+ Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+ if ( Ret != SK_PNMI_ERR_OK) {
+
+ *pLen = 0;
+ return (Ret);
+ }
+ pAC->Pnmi.MacUpdatedFlag ++;
+
+ /*
+ * Get value (MAC Index 0 identifies the virtual MAC)
+ */
+ switch (Id) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress);
+ *pLen = sizeof(SK_MAC_ADDR);
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+ *pLen = sizeof(SK_MAC_ADDR);
+ break;
+
+ default:
+ StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex);
+
+ /* by default 32bit values are evaluated */
+ if (!Is64BitReq) {
+ StatVal32 = (SK_U32)StatVal;
+ SK_PNMI_STORE_U32(pBuf, StatVal32);
+ *pLen = sizeof(SK_U32);
+ }
+ else {
+ SK_PNMI_STORE_U64(pBuf, StatVal);
+ *pLen = sizeof(SK_U64);
+ }
+ break;
+ }
+
+ pAC->Pnmi.MacUpdatedFlag --;
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX
+ *
+ * Description:
+ * Retrieves the MAC statistic data.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int MacPrivateStat(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int LogPortMax;
+ unsigned int LogPortIndex;
+ unsigned int PhysPortMax;
+ unsigned int Limit;
+ unsigned int Offset;
+ int MacType;
+ int Ret;
+ SK_U64 StatVal;
+
+
+
+ /* Calculate instance if wished. MAC index 0 is the virtual MAC */
+ PhysPortMax = pAC->GIni.GIMacsFound;
+ LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+ MacType = pAC->GIni.GIMacType;
+
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+ LogPortMax--;
+ }
+
+ if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+ /* Check instance range */
+ if ((Instance < 1) || (Instance > LogPortMax)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+ LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+ Limit = LogPortIndex + 1;
+ }
+
+ else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+ LogPortIndex = 0;
+ Limit = LogPortMax;
+ }
+
+ /* Check action */
+ if (Action != SK_PNMI_GET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /* Check length */
+ if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) {
+
+ *pLen = (Limit - LogPortIndex) * sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * Update MAC statistic and increment semaphore to indicate that
+ * an update was already done.
+ */
+ Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+ if (Ret != SK_PNMI_ERR_OK) {
+
+ *pLen = 0;
+ return (Ret);
+ }
+ pAC->Pnmi.MacUpdatedFlag ++;
+
+ /* Get value */
+ Offset = 0;
+ for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+ switch (Id) {
+
+/* XXX not yet implemented due to XMAC problems
+ case OID_SKGE_STAT_TX_UTIL:
+ return (SK_PNMI_ERR_GENERAL);
+*/
+/* XXX not yet implemented due to XMAC problems
+ case OID_SKGE_STAT_RX_UTIL:
+ return (SK_PNMI_ERR_GENERAL);
+*/
+ case OID_SKGE_STAT_RX:
+ if (MacType == SK_MAC_GMAC) {
+ StatVal =
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HRX_BROADCAST, NetIndex) +
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HRX_MULTICAST, NetIndex) +
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HRX_UNICAST, NetIndex) +
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HRX_UNDERSIZE, NetIndex);
+ }
+ else {
+ StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+ IdTable[TableIndex].Param, NetIndex);
+ }
+ break;
+
+ case OID_SKGE_STAT_TX:
+ if (MacType == SK_MAC_GMAC) {
+ StatVal =
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HTX_BROADCAST, NetIndex) +
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HTX_MULTICAST, NetIndex) +
+ GetStatVal(pAC, IoC, LogPortIndex,
+ SK_PNMI_HTX_UNICAST, NetIndex);
+ }
+ else {
+ StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+ IdTable[TableIndex].Param, NetIndex);
+ }
+ break;
+
+ default:
+ StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+ IdTable[TableIndex].Param, NetIndex);
+ }
+ SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+
+ Offset += sizeof(SK_U64);
+ }
+ *pLen = Offset;
+
+ pAC->Pnmi.MacUpdatedFlag --;
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR
+ *
+ * Description:
+ * Get/Presets/Sets the current and factory MAC address. The MAC
+ * address of the virtual port, which is reported to the OS, may
+ * not be changed, but the physical ones. A set to the virtual port
+ * will be ignored. No error should be reported because otherwise
+ * a multiple instance set (-1) would always fail.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int Addr(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ unsigned int LogPortMax;
+ unsigned int PhysPortMax;
+ unsigned int LogPortIndex;
+ unsigned int PhysPortIndex;
+ unsigned int Limit;
+ unsigned int Offset = 0;
+
+ /*
+ * Calculate instance if wished. MAC index 0 is the virtual
+ * MAC.
+ */
+ PhysPortMax = pAC->GIni.GIMacsFound;
+ LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+ LogPortMax--;
+ }
+
+ if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+ /* Check instance range */
+ if ((Instance < 1) || (Instance > LogPortMax)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+ LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+ Limit = LogPortIndex + 1;
+ }
+ else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+ LogPortIndex = 0;
+ Limit = LogPortMax;
+ }
+
+ /*
+ * Perform Action
+ */
+ if (Action == SK_PNMI_GET) {
+
+ /* Check length */
+ if (*pLen < (Limit - LogPortIndex) * 6) {
+
+ *pLen = (Limit - LogPortIndex) * 6;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * Get value
+ */
+ for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+ switch (Id) {
+
+ case OID_SKGE_PHYS_CUR_ADDR:
+ if (LogPortIndex == 0) {
+ CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+ }
+ else {
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+
+ CopyMac(pBuf + Offset,
+ &pAC->Addr.Port[PhysPortIndex].CurrentMacAddress);
+ }
+ Offset += 6;
+ break;
+
+ case OID_SKGE_PHYS_FAC_ADDR:
+ if (LogPortIndex == 0) {
+ CopyMac(pBuf + Offset,
+ &pAC->Addr.Net[NetIndex].PermanentMacAddress);
+ }
+ else {
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ CopyMac(pBuf + Offset,
+ &pAC->Addr.Port[PhysPortIndex].PermanentMacAddress);
+ }
+ Offset += 6;
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008,
+ SK_PNMI_ERR008MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+
+ *pLen = Offset;
+ }
+ else {
+ /*
+ * The logical MAC address may not be changed only
+ * the physical ones
+ */
+ if (Id == OID_SKGE_PHYS_FAC_ADDR) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /*
+ * Only the current address may be changed
+ */
+ if (Id != OID_SKGE_PHYS_CUR_ADDR) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009,
+ SK_PNMI_ERR009MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /* Check length */
+ if (*pLen < (Limit - LogPortIndex) * 6) {
+
+ *pLen = (Limit - LogPortIndex) * 6;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ if (*pLen > (Limit - LogPortIndex) * 6) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /*
+ * Check Action
+ */
+ if (Action == SK_PNMI_PRESET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /*
+ * Set OID_SKGE_MAC_CUR_ADDR
+ */
+ for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) {
+
+ /*
+ * A set to virtual port and set of broadcast
+ * address will be ignored
+ */
+ if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset,
+ "\xff\xff\xff\xff\xff\xff", 6) == 0) {
+
+ continue;
+ }
+
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC,
+ LogPortIndex);
+
+ Ret = SkAddrOverride(pAC, IoC, PhysPortIndex,
+ (SK_MAC_ADDR *)(pBuf + Offset),
+ (LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS :
+ SK_ADDR_PHYSICAL_ADDRESS));
+ if (Ret != SK_ADDR_OVERRIDE_SUCCESS) {
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ *pLen = Offset;
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX
+ *
+ * Description:
+ * Retrieves the statistic values of the CSUM module. The CSUM data
+ * structure must be available in the SK_AC even if the CSUM module
+ * is not included, because PNMI reads the statistic data from the
+ * CSUM part of SK_AC directly.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int CsumStat(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int Index;
+ unsigned int Limit;
+ unsigned int Offset = 0;
+ SK_U64 StatVal;
+
+
+ /*
+ * Calculate instance if wished
+ */
+ if (Instance != (SK_U32)(-1)) {
+
+ if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+ Index = (unsigned int)Instance - 1;
+ Limit = Index + 1;
+ }
+ else {
+ Index = 0;
+ Limit = SKCS_NUM_PROTOCOLS;
+ }
+
+ /*
+ * Check action
+ */
+ if (Action != SK_PNMI_GET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /* Check length */
+ if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+ *pLen = (Limit - Index) * sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * Get value
+ */
+ for (; Index < Limit; Index ++) {
+
+ switch (Id) {
+
+ case OID_SKGE_CHKSM_RX_OK_CTS:
+ StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts;
+ break;
+
+ case OID_SKGE_CHKSM_RX_UNABLE_CTS:
+ StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts;
+ break;
+
+ case OID_SKGE_CHKSM_RX_ERR_CTS:
+ StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts;
+ break;
+
+ case OID_SKGE_CHKSM_TX_OK_CTS:
+ StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts;
+ break;
+
+ case OID_SKGE_CHKSM_TX_UNABLE_CTS:
+ StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts;
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010,
+ SK_PNMI_ERR010MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+ Offset += sizeof(SK_U64);
+ }
+
+ /*
+ * Store used buffer space
+ */
+ *pLen = Offset;
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX
+ *
+ * Description:
+ * Retrieves the statistic values of the I2C module, which handles
+ * the temperature and voltage sensors.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int SensorStat(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int i;
+ unsigned int Index;
+ unsigned int Limit;
+ unsigned int Offset;
+ unsigned int Len;
+ SK_U32 Val32;
+ SK_U64 Val64;
+
+
+ /*
+ * Calculate instance if wished
+ */
+ if ((Instance != (SK_U32)(-1))) {
+
+ if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ Index = (unsigned int)Instance -1;
+ Limit = (unsigned int)Instance;
+ }
+ else {
+ Index = 0;
+ Limit = (unsigned int) pAC->I2c.MaxSens;
+ }
+
+ /*
+ * Check action
+ */
+ if (Action != SK_PNMI_GET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /* Check length */
+ switch (Id) {
+
+ case OID_SKGE_SENSOR_VALUE:
+ case OID_SKGE_SENSOR_WAR_THRES_LOW:
+ case OID_SKGE_SENSOR_WAR_THRES_UPP:
+ case OID_SKGE_SENSOR_ERR_THRES_LOW:
+ case OID_SKGE_SENSOR_ERR_THRES_UPP:
+ if (*pLen < (Limit - Index) * sizeof(SK_U32)) {
+
+ *pLen = (Limit - Index) * sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_SENSOR_DESCR:
+ for (Offset = 0, i = Index; i < Limit; i ++) {
+
+ Len = (unsigned int)
+ SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1;
+ if (Len >= SK_PNMI_STRINGLEN2) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011,
+ SK_PNMI_ERR011MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ Offset += Len;
+ }
+ if (*pLen < Offset) {
+
+ *pLen = Offset;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_SENSOR_INDEX:
+ case OID_SKGE_SENSOR_TYPE:
+ case OID_SKGE_SENSOR_STATUS:
+ if (*pLen < Limit - Index) {
+
+ *pLen = Limit - Index;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_SENSOR_WAR_CTS:
+ case OID_SKGE_SENSOR_WAR_TIME:
+ case OID_SKGE_SENSOR_ERR_CTS:
+ case OID_SKGE_SENSOR_ERR_TIME:
+ if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+ *pLen = (Limit - Index) * sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012,
+ SK_PNMI_ERR012MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+
+ }
+
+ /*
+ * Get value
+ */
+ for (Offset = 0; Index < Limit; Index ++) {
+
+ switch (Id) {
+
+ case OID_SKGE_SENSOR_INDEX:
+ *(pBuf + Offset) = (char)Index;
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SENSOR_DESCR:
+ Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc);
+ SK_MEMCPY(pBuf + Offset + 1,
+ pAC->I2c.SenTable[Index].SenDesc, Len);
+ *(pBuf + Offset) = (char)Len;
+ Offset += Len + 1;
+ break;
+
+ case OID_SKGE_SENSOR_TYPE:
+ *(pBuf + Offset) =
+ (char)pAC->I2c.SenTable[Index].SenType;
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SENSOR_VALUE:
+ Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_SENSOR_WAR_THRES_LOW:
+ Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+ SenThreWarnLow;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_SENSOR_WAR_THRES_UPP:
+ Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+ SenThreWarnHigh;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_SENSOR_ERR_THRES_LOW:
+ Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+ SenThreErrLow;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_SENSOR_ERR_THRES_UPP:
+ Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_SENSOR_STATUS:
+ *(pBuf + Offset) =
+ (char)pAC->I2c.SenTable[Index].SenErrFlag;
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SENSOR_WAR_CTS:
+ Val64 = pAC->I2c.SenTable[Index].SenWarnCts;
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_SENSOR_ERR_CTS:
+ Val64 = pAC->I2c.SenTable[Index].SenErrCts;
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_SENSOR_WAR_TIME:
+ Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+ SenBegWarnTS);
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_SENSOR_ERR_TIME:
+ Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+ SenBegErrTS);
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ default:
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+ ("SensorStat: Unknown OID should be handled before"));
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+
+ /*
+ * Store used buffer space
+ */
+ *pLen = Offset;
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Vpd - OID handler function of OID_SKGE_VPD_XXX
+ *
+ * Description:
+ * Get/preset/set of VPD data. As instance the name of a VPD key
+ * can be passed. The Instance parameter is a SK_U32 and can be
+ * used as a string buffer for the VPD key, because their maximum
+ * length is 4 byte.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int Vpd(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_VPD_STATUS *pVpdStatus;
+ unsigned int BufLen;
+ char Buf[256];
+ char KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+ char KeyStr[SK_PNMI_VPD_KEY_SIZE];
+ unsigned int KeyNo;
+ unsigned int Offset;
+ unsigned int Index;
+ unsigned int FirstIndex;
+ unsigned int LastIndex;
+ unsigned int Len;
+ int Ret;
+ SK_U32 Val32;
+
+ /*
+ * Get array of all currently stored VPD keys
+ */
+ Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &KeyNo);
+ if (Ret != SK_PNMI_ERR_OK) {
+ *pLen = 0;
+ return (Ret);
+ }
+
+ /*
+ * If instance is not -1, try to find the requested VPD key for
+ * the multiple instance variables. The other OIDs as for example
+ * OID VPD_ACTION are single instance variables and must be
+ * handled separatly.
+ */
+ FirstIndex = 0;
+ LastIndex = KeyNo;
+
+ if ((Instance != (SK_U32)(-1))) {
+
+ if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE ||
+ Id == OID_SKGE_VPD_ACCESS) {
+
+ SK_STRNCPY(KeyStr, (char *)&Instance, 4);
+ KeyStr[4] = 0;
+
+ for (Index = 0; Index < KeyNo; Index ++) {
+
+ if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+ FirstIndex = Index;
+ LastIndex = Index+1;
+ break;
+ }
+ }
+ if (Index == KeyNo) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+ }
+ else if (Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+ }
+
+ /*
+ * Get value, if a query should be performed
+ */
+ if (Action == SK_PNMI_GET) {
+
+ switch (Id) {
+
+ case OID_SKGE_VPD_FREE_BYTES:
+ /* Check length of buffer */
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ /* Get number of free bytes */
+ pVpdStatus = VpdStat(pAC, IoC);
+ if (pVpdStatus == NULL) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017,
+ SK_PNMI_ERR017MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ if ((pVpdStatus->vpd_status & VPD_VALID) == 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018,
+ SK_PNMI_ERR018MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ Val32 = (SK_U32)pVpdStatus->vpd_free_rw;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_VPD_ENTRIES_LIST:
+ /* Check length */
+ for (Len = 0, Index = 0; Index < KeyNo; Index ++) {
+
+ Len += SK_STRLEN(KeyArr[Index]) + 1;
+ }
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /* Get value */
+ *(pBuf) = (char)Len - 1;
+ for (Offset = 1, Index = 0; Index < KeyNo; Index ++) {
+
+ Len = SK_STRLEN(KeyArr[Index]);
+ SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len);
+
+ Offset += Len;
+
+ if (Index < KeyNo - 1) {
+
+ *(pBuf + Offset) = ' ';
+ Offset ++;
+ }
+ }
+ *pLen = Offset;
+ break;
+
+ case OID_SKGE_VPD_ENTRIES_NUMBER:
+ /* Check length */
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ Val32 = (SK_U32)KeyNo;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_VPD_KEY:
+ /* Check buffer length, if it is large enough */
+ for (Len = 0, Index = FirstIndex;
+ Index < LastIndex; Index ++) {
+
+ Len += SK_STRLEN(KeyArr[Index]) + 1;
+ }
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * Get the key to an intermediate buffer, because
+ * we have to prepend a length byte.
+ */
+ for (Offset = 0, Index = FirstIndex;
+ Index < LastIndex; Index ++) {
+
+ Len = SK_STRLEN(KeyArr[Index]);
+
+ *(pBuf + Offset) = (char)Len;
+ SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index],
+ Len);
+ Offset += Len + 1;
+ }
+ *pLen = Offset;
+ break;
+
+ case OID_SKGE_VPD_VALUE:
+ /* Check the buffer length if it is large enough */
+ for (Offset = 0, Index = FirstIndex;
+ Index < LastIndex; Index ++) {
+
+ BufLen = 256;
+ if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+ (int *)&BufLen) > 0 ||
+ BufLen >= SK_PNMI_VPD_DATALEN) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR021,
+ SK_PNMI_ERR021MSG);
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ Offset += BufLen + 1;
+ }
+ if (*pLen < Offset) {
+
+ *pLen = Offset;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * Get the value to an intermediate buffer, because
+ * we have to prepend a length byte.
+ */
+ for (Offset = 0, Index = FirstIndex;
+ Index < LastIndex; Index ++) {
+
+ BufLen = 256;
+ if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+ (int *)&BufLen) > 0 ||
+ BufLen >= SK_PNMI_VPD_DATALEN) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR022,
+ SK_PNMI_ERR022MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ *(pBuf + Offset) = (char)BufLen;
+ SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen);
+ Offset += BufLen + 1;
+ }
+ *pLen = Offset;
+ break;
+
+ case OID_SKGE_VPD_ACCESS:
+ if (*pLen < LastIndex - FirstIndex) {
+
+ *pLen = LastIndex - FirstIndex;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ for (Offset = 0, Index = FirstIndex;
+ Index < LastIndex; Index ++) {
+
+ if (VpdMayWrite(KeyArr[Index])) {
+
+ *(pBuf + Offset) = SK_PNMI_VPD_RW;
+ }
+ else {
+ *(pBuf + Offset) = SK_PNMI_VPD_RO;
+ }
+ Offset ++;
+ }
+ *pLen = Offset;
+ break;
+
+ case OID_SKGE_VPD_ACTION:
+ Offset = LastIndex - FirstIndex;
+ if (*pLen < Offset) {
+
+ *pLen = Offset;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ SK_MEMSET(pBuf, 0, Offset);
+ *pLen = Offset;
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023,
+ SK_PNMI_ERR023MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ else {
+ /* The only OID which can be set is VPD_ACTION */
+ if (Id != OID_SKGE_VPD_ACTION) {
+
+ if (Id == OID_SKGE_VPD_FREE_BYTES ||
+ Id == OID_SKGE_VPD_ENTRIES_LIST ||
+ Id == OID_SKGE_VPD_ENTRIES_NUMBER ||
+ Id == OID_SKGE_VPD_KEY ||
+ Id == OID_SKGE_VPD_VALUE ||
+ Id == OID_SKGE_VPD_ACCESS) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024,
+ SK_PNMI_ERR024MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * From this point we handle VPD_ACTION. Check the buffer
+ * length. It should at least have the size of one byte.
+ */
+ if (*pLen < 1) {
+
+ *pLen = 1;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ /*
+ * The first byte contains the VPD action type we should
+ * perform.
+ */
+ switch (*pBuf) {
+
+ case SK_PNMI_VPD_IGNORE:
+ /* Nothing to do */
+ break;
+
+ case SK_PNMI_VPD_CREATE:
+ /*
+ * We have to create a new VPD entry or we modify
+ * an existing one. Check first the buffer length.
+ */
+ if (*pLen < 4) {
+
+ *pLen = 4;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ KeyStr[0] = pBuf[1];
+ KeyStr[1] = pBuf[2];
+ KeyStr[2] = 0;
+
+ /*
+ * Is the entry writable or does it belong to the
+ * read-only area?
+ */
+ if (!VpdMayWrite(KeyStr)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ Offset = (int)pBuf[3] & 0xFF;
+
+ SK_MEMCPY(Buf, pBuf + 4, Offset);
+ Buf[Offset] = 0;
+
+ /* A preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* Write the new entry or modify an existing one */
+ Ret = VpdWrite(pAC, IoC, KeyStr, Buf);
+ if (Ret == SK_PNMI_VPD_NOWRITE ) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ else if (Ret != SK_PNMI_VPD_OK) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025,
+ SK_PNMI_ERR025MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * Perform an update of the VPD data. This is
+ * not mandantory, but just to be sure.
+ */
+ Ret = VpdUpdate(pAC, IoC);
+ if (Ret != SK_PNMI_VPD_OK) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026,
+ SK_PNMI_ERR026MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ break;
+
+ case SK_PNMI_VPD_DELETE:
+ /* Check if the buffer size is plausible */
+ if (*pLen < 3) {
+
+ *pLen = 3;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ if (*pLen > 3) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ KeyStr[0] = pBuf[1];
+ KeyStr[1] = pBuf[2];
+ KeyStr[2] = 0;
+
+ /* Find the passed key in the array */
+ for (Index = 0; Index < KeyNo; Index ++) {
+
+ if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+
+ break;
+ }
+ }
+ /*
+ * If we cannot find the key it is wrong, so we
+ * return an appropriate error value.
+ */
+ if (Index == KeyNo) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* Ok, you wanted it and you will get it */
+ Ret = VpdDelete(pAC, IoC, KeyStr);
+ if (Ret != SK_PNMI_VPD_OK) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027,
+ SK_PNMI_ERR027MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * Perform an update of the VPD data. This is
+ * not mandantory, but just to be sure.
+ */
+ Ret = VpdUpdate(pAC, IoC);
+ if (Ret != SK_PNMI_VPD_OK) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028,
+ SK_PNMI_ERR028MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ break;
+
+ default:
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * General - OID handler function of various single instance OIDs
+ *
+ * Description:
+ * The code is simple. No description necessary.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int General(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ unsigned int Index;
+ unsigned int Len;
+ unsigned int Offset;
+ unsigned int Val;
+ SK_U8 Val8;
+ SK_U16 Val16;
+ SK_U32 Val32;
+ SK_U64 Val64;
+ SK_U64 Val64RxHwErrs = 0;
+ SK_U64 Val64TxHwErrs = 0;
+ SK_BOOL Is64BitReq = SK_FALSE;
+ char Buf[256];
+ int MacType;
+
+ /*
+ * Check instance. We only handle single instance variables.
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ /*
+ * Check action. We only allow get requests.
+ */
+ if (Action != SK_PNMI_GET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ MacType = pAC->GIni.GIMacType;
+
+ /*
+ * Check length for the various supported OIDs
+ */
+ switch (Id) {
+
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+#ifndef SK_NDIS_64BIT_CTR
+ if (*pLen < sizeof(SK_U32)) {
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+#else /* SK_NDIS_64BIT_CTR */
+
+ /*
+ * for compatibility, at least 32bit are required for oid
+ */
+ if (*pLen < sizeof(SK_U32)) {
+ /*
+ * but indicate handling for 64bit values,
+ * if insufficient space is provided
+ */
+ *pLen = sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+
+ Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+ break;
+
+ case OID_SKGE_PORT_NUMBER:
+ case OID_SKGE_DEVICE_TYPE:
+ case OID_SKGE_RESULT:
+ case OID_SKGE_RLMT_MONITOR_NUMBER:
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ case OID_SKGE_TRAP_NUMBER:
+ case OID_SKGE_MDB_VERSION:
+ case OID_SKGE_BOARDLEVEL:
+ case OID_SKGE_CHIPID:
+ case OID_SKGE_RAMSIZE:
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_CHIPSET:
+ if (*pLen < sizeof(SK_U16)) {
+
+ *pLen = sizeof(SK_U16);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_BUS_TYPE:
+ case OID_SKGE_BUS_SPEED:
+ case OID_SKGE_BUS_WIDTH:
+ case OID_SKGE_SENSOR_NUMBER:
+ case OID_SKGE_CHKSM_NUMBER:
+ case OID_SKGE_VAUXAVAIL:
+ if (*pLen < sizeof(SK_U8)) {
+
+ *pLen = sizeof(SK_U8);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_TX_SW_QUEUE_LEN:
+ case OID_SKGE_TX_SW_QUEUE_MAX:
+ case OID_SKGE_TX_RETRY:
+ case OID_SKGE_RX_INTR_CTS:
+ case OID_SKGE_TX_INTR_CTS:
+ case OID_SKGE_RX_NO_BUF_CTS:
+ case OID_SKGE_TX_NO_BUF_CTS:
+ case OID_SKGE_TX_USED_DESCR_NO:
+ case OID_SKGE_RX_DELIVERED_CTS:
+ case OID_SKGE_RX_OCTETS_DELIV_CTS:
+ case OID_SKGE_RX_HW_ERROR_CTS:
+ case OID_SKGE_TX_HW_ERROR_CTS:
+ case OID_SKGE_IN_ERRORS_CTS:
+ case OID_SKGE_OUT_ERROR_CTS:
+ case OID_SKGE_ERR_RECOVERY_CTS:
+ case OID_SKGE_SYSUPTIME:
+ if (*pLen < sizeof(SK_U64)) {
+
+ *pLen = sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ /* Checked later */
+ break;
+ }
+
+ /* Update statistic */
+ if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+ Id == OID_SKGE_TX_HW_ERROR_CTS ||
+ Id == OID_SKGE_IN_ERRORS_CTS ||
+ Id == OID_SKGE_OUT_ERROR_CTS ||
+ Id == OID_GEN_XMIT_ERROR ||
+ Id == OID_GEN_RCV_ERROR) {
+
+ /* Force the XMAC to update its statistic counters and
+ * Increment semaphore to indicate that an update was
+ * already done.
+ */
+ Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+ if (Ret != SK_PNMI_ERR_OK) {
+
+ *pLen = 0;
+ return (Ret);
+ }
+ pAC->Pnmi.MacUpdatedFlag ++;
+
+ /*
+ * Some OIDs consist of multiple hardware counters. Those
+ * values which are contained in all of them will be added
+ * now.
+ */
+ switch (Id) {
+
+ case OID_SKGE_RX_HW_ERROR_CTS:
+ case OID_SKGE_IN_ERRORS_CTS:
+ case OID_GEN_RCV_ERROR:
+ Val64RxHwErrs =
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
+ break;
+
+ case OID_SKGE_TX_HW_ERROR_CTS:
+ case OID_SKGE_OUT_ERROR_CTS:
+ case OID_GEN_XMIT_ERROR:
+ Val64TxHwErrs =
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex) +
+ GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex);
+ break;
+ }
+ }
+
+ /*
+ * Retrieve value
+ */
+ switch (Id) {
+
+ case OID_SKGE_SUPPORTED_LIST:
+ Len = ID_TABLE_SIZE * sizeof(SK_U32);
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ for (Offset = 0, Index = 0; Offset < Len;
+ Offset += sizeof(SK_U32), Index ++) {
+
+ Val32 = (SK_U32)IdTable[Index].Id;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ }
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_BOARDLEVEL:
+ Val32 = (SK_U32)pAC->GIni.GILevel;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_PORT_NUMBER:
+ Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_DEVICE_TYPE:
+ Val32 = (SK_U32)pAC->Pnmi.DeviceType;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_DRIVER_DESCR:
+ if (pAC->Pnmi.pDriverDescription == NULL) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007,
+ SK_PNMI_ERR007MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1;
+ if (Len > SK_PNMI_STRINGLEN1) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029,
+ SK_PNMI_ERR029MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ *pBuf = (char)(Len - 1);
+ SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1);
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_DRIVER_VERSION:
+ if (pAC->Pnmi.pDriverVersion == NULL) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+ SK_PNMI_ERR030MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1;
+ if (Len > SK_PNMI_STRINGLEN1) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+ SK_PNMI_ERR031MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ *pBuf = (char)(Len - 1);
+ SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1);
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_DRIVER_RELDATE:
+ if (pAC->Pnmi.pDriverReleaseDate == NULL) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+ SK_PNMI_ERR053MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1;
+ if (Len > SK_PNMI_STRINGLEN1) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+ SK_PNMI_ERR054MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ *pBuf = (char)(Len - 1);
+ SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1);
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_DRIVER_FILENAME:
+ if (pAC->Pnmi.pDriverFileName == NULL) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+ SK_PNMI_ERR055MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1;
+ if (Len > SK_PNMI_STRINGLEN1) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+ SK_PNMI_ERR056MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ *pBuf = (char)(Len - 1);
+ SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1);
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_HW_DESCR:
+ /*
+ * The hardware description is located in the VPD. This
+ * query may move to the initialisation routine. But
+ * the VPD data is cached and therefore a call here
+ * will not make much difference.
+ */
+ Len = 256;
+ if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032,
+ SK_PNMI_ERR032MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ Len ++;
+ if (Len > SK_PNMI_STRINGLEN1) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033,
+ SK_PNMI_ERR033MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ *pBuf = (char)(Len - 1);
+ SK_MEMCPY(pBuf + 1, Buf, Len - 1);
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_HW_VERSION:
+ /* Oh, I love to do some string manipulation */
+ if (*pLen < 5) {
+
+ *pLen = 5;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ Val8 = (SK_U8)pAC->GIni.GIPciHwRev;
+ pBuf[0] = 4;
+ pBuf[1] = 'v';
+ pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F));
+ pBuf[3] = '.';
+ pBuf[4] = (char)(0x30 | (Val8 & 0x0F));
+ *pLen = 5;
+ break;
+
+ case OID_SKGE_CHIPSET:
+ Val16 = pAC->Pnmi.Chipset;
+ SK_PNMI_STORE_U16(pBuf, Val16);
+ *pLen = sizeof(SK_U16);
+ break;
+
+ case OID_SKGE_CHIPID:
+ Val32 = pAC->GIni.GIChipId;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_RAMSIZE:
+ Val32 = pAC->GIni.GIRamSize;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_VAUXAVAIL:
+ *pBuf = (char) pAC->GIni.GIVauxAvail;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_BUS_TYPE:
+ *pBuf = (char) SK_PNMI_BUS_PCI;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_BUS_SPEED:
+ *pBuf = pAC->Pnmi.PciBusSpeed;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_BUS_WIDTH:
+ *pBuf = pAC->Pnmi.PciBusWidth;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_RESULT:
+ Val32 = pAC->Pnmi.TestResult;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_SENSOR_NUMBER:
+ *pBuf = (char)pAC->I2c.MaxSens;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_CHKSM_NUMBER:
+ *pBuf = SKCS_NUM_PROTOCOLS;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_TRAP_NUMBER:
+ GetTrapQueueLen(pAC, &Len, &Val);
+ Val32 = (SK_U32)Val;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_TRAP:
+ GetTrapQueueLen(pAC, &Len, &Val);
+ if (*pLen < Len) {
+
+ *pLen = Len;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ CopyTrapQueue(pAC, pBuf);
+ *pLen = Len;
+ break;
+
+ case OID_SKGE_RLMT_MONITOR_NUMBER:
+/* XXX Not yet implemented by RLMT therefore we return zero elements */
+ Val32 = 0;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_TX_SW_QUEUE_LEN:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen +
+ pAC->Pnmi.BufPort[1].TxSwQueueLen;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].TxSwQueueLen +
+ pAC->Pnmi.Port[1].TxSwQueueLen;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+
+ case OID_SKGE_TX_SW_QUEUE_MAX:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax +
+ pAC->Pnmi.BufPort[1].TxSwQueueMax;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
+ pAC->Pnmi.Port[1].TxSwQueueMax;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_TX_RETRY:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].TxRetryCts +
+ pAC->Pnmi.BufPort[1].TxRetryCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].TxRetryCts +
+ pAC->Pnmi.Port[1].TxRetryCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RX_INTR_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].RxIntrCts +
+ pAC->Pnmi.BufPort[1].RxIntrCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].RxIntrCts +
+ pAC->Pnmi.Port[1].RxIntrCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_TX_INTR_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].TxIntrCts +
+ pAC->Pnmi.BufPort[1].TxIntrCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].TxIntrCts +
+ pAC->Pnmi.Port[1].TxIntrCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RX_NO_BUF_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts +
+ pAC->Pnmi.BufPort[1].RxNoBufCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
+ pAC->Pnmi.Port[1].RxNoBufCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_TX_NO_BUF_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts +
+ pAC->Pnmi.BufPort[1].TxNoBufCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
+ pAC->Pnmi.Port[1].TxNoBufCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_TX_USED_DESCR_NO:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo +
+ pAC->Pnmi.BufPort[1].TxUsedDescrNo;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
+ pAC->Pnmi.Port[1].TxUsedDescrNo;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RX_DELIVERED_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts +
+ pAC->Pnmi.BufPort[1].RxDeliveredCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
+ pAC->Pnmi.Port[1].RxDeliveredCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RX_OCTETS_DELIV_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts +
+ pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
+ pAC->Pnmi.Port[1].RxOctetsDeliveredCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RX_HW_ERROR_CTS:
+ SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_TX_HW_ERROR_CTS:
+ SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_IN_ERRORS_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = Val64RxHwErrs +
+ pAC->Pnmi.BufPort[0].RxNoBufCts +
+ pAC->Pnmi.BufPort[1].RxNoBufCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = Val64RxHwErrs +
+ pAC->Pnmi.Port[0].RxNoBufCts +
+ pAC->Pnmi.Port[1].RxNoBufCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_OUT_ERROR_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = Val64TxHwErrs +
+ pAC->Pnmi.BufPort[0].TxNoBufCts +
+ pAC->Pnmi.BufPort[1].TxNoBufCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = Val64TxHwErrs +
+ pAC->Pnmi.Port[0].TxNoBufCts +
+ pAC->Pnmi.Port[1].TxNoBufCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_ERR_RECOVERY_CTS:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts +
+ pAC->Pnmi.BufPort[1].ErrRecoveryCts;
+ }
+ }
+ else {
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
+ }
+ /* Single net mode */
+ else {
+ Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
+ pAC->Pnmi.Port[1].ErrRecoveryCts;
+ }
+ }
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_SYSUPTIME:
+ Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+ Val64 -= pAC->Pnmi.StartUpTime;
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_MDB_VERSION:
+ Val32 = SK_PNMI_MDB_VERSION;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+ }
+ else {
+ Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+ }
+
+ /*
+ * by default 32bit values are evaluated
+ */
+ if (!Is64BitReq) {
+ Val32 = (SK_U32)Val64;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ }
+ else {
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ }
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+ }
+ else {
+ Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+ }
+
+ /*
+ * by default 32bit values are evaluated
+ */
+ if (!Is64BitReq) {
+ Val32 = (SK_U32)Val64;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ }
+ else {
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ }
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+ }
+ else {
+ Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+ }
+
+ /*
+ * by default 32bit values are evaluated
+ */
+ if (!Is64BitReq) {
+ Val32 = (SK_U32)Val64;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ }
+ else {
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ }
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034,
+ SK_PNMI_ERR034MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+ Id == OID_SKGE_TX_HW_ERROR_CTS ||
+ Id == OID_SKGE_IN_ERRORS_CTS ||
+ Id == OID_SKGE_OUT_ERROR_CTS ||
+ Id == OID_GEN_XMIT_ERROR ||
+ Id == OID_GEN_RCV_ERROR) {
+
+ pAC->Pnmi.MacUpdatedFlag --;
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance.
+ *
+ * Description:
+ * Get/Presets/Sets the RLMT OIDs.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int Rlmt(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ int Ret;
+ unsigned int PhysPortIndex;
+ unsigned int PhysPortMax;
+ SK_EVPARA EventParam;
+ SK_U32 Val32;
+ SK_U64 Val64;
+
+
+ /*
+ * Check instance. Only single instance OIDs are allowed here.
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ /*
+ * Perform the requested action.
+ */
+ if (Action == SK_PNMI_GET) {
+
+ /*
+ * Check if the buffer length is large enough.
+ */
+
+ switch (Id) {
+
+ case OID_SKGE_RLMT_MODE:
+ case OID_SKGE_RLMT_PORT_ACTIVE:
+ case OID_SKGE_RLMT_PORT_PREFERRED:
+ if (*pLen < sizeof(SK_U8)) {
+
+ *pLen = sizeof(SK_U8);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_RLMT_PORT_NUMBER:
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_RLMT_CHANGE_CTS:
+ case OID_SKGE_RLMT_CHANGE_TIME:
+ case OID_SKGE_RLMT_CHANGE_ESTIM:
+ case OID_SKGE_RLMT_CHANGE_THRES:
+ if (*pLen < sizeof(SK_U64)) {
+
+ *pLen = sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035,
+ SK_PNMI_ERR035MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * Update RLMT statistic and increment semaphores to indicate
+ * that an update was already done. Maybe RLMT will hold its
+ * statistic always up to date some time. Then we can
+ * remove this type of call.
+ */
+ if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+ *pLen = 0;
+ return (Ret);
+ }
+ pAC->Pnmi.RlmtUpdatedFlag ++;
+
+ /*
+ * Retrieve Value
+ */
+ switch (Id) {
+
+ case OID_SKGE_RLMT_MODE:
+ *pBuf = (char)pAC->Rlmt.Net[0].RlmtMode;
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_RLMT_PORT_NUMBER:
+ Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ *pLen = sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_RLMT_PORT_ACTIVE:
+ *pBuf = 0;
+ /*
+ * If multiple ports may become active this OID
+ * doesn't make sense any more. A new variable in
+ * the port structure should be created. However,
+ * for this variable the first active port is
+ * returned.
+ */
+ PhysPortMax = pAC->GIni.GIMacsFound;
+
+ for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex);
+ break;
+ }
+ }
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_RLMT_PORT_PREFERRED:
+ *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference);
+ *pLen = sizeof(char);
+ break;
+
+ case OID_SKGE_RLMT_CHANGE_CTS:
+ Val64 = pAC->Pnmi.RlmtChangeCts;
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RLMT_CHANGE_TIME:
+ Val64 = pAC->Pnmi.RlmtChangeTime;
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RLMT_CHANGE_ESTIM:
+ Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate;
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RLMT_CHANGE_THRES:
+ Val64 = pAC->Pnmi.RlmtChangeThreshold;
+ SK_PNMI_STORE_U64(pBuf, Val64);
+ *pLen = sizeof(SK_U64);
+ break;
+
+ default:
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+ ("Rlmt: Unknown OID should be handled before"));
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ }
+ else {
+ /* Perform a preset or set */
+ switch (Id) {
+
+ case OID_SKGE_RLMT_MODE:
+ /* Check if the buffer length is plausible */
+ if (*pLen < sizeof(char)) {
+
+ *pLen = sizeof(char);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ /* Check if the value range is correct */
+ if (*pLen != sizeof(char) ||
+ (*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 ||
+ *(SK_U8 *)pBuf > 15) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_OK);
+ }
+ /* Send an event to RLMT to change the mode */
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+ EventParam.Para32[0] |= (SK_U32)(*pBuf);
+ EventParam.Para32[1] = 0;
+ if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037,
+ SK_PNMI_ERR037MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ break;
+
+ case OID_SKGE_RLMT_PORT_PREFERRED:
+ /* Check if the buffer length is plausible */
+ if (*pLen < sizeof(char)) {
+
+ *pLen = sizeof(char);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ /* Check if the value range is correct */
+ if (*pLen != sizeof(char) || *(SK_U8 *)pBuf >
+ (SK_U8)pAC->GIni.GIMacsFound) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /*
+ * Send an event to RLMT change the preferred port.
+ * A param of -1 means automatic mode. RLMT will
+ * make the decision which is the preferred port.
+ */
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+ EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
+ EventParam.Para32[1] = NetIndex;
+ if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038,
+ SK_PNMI_ERR038MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ break;
+
+ case OID_SKGE_RLMT_CHANGE_THRES:
+ /* Check if the buffer length is plausible */
+ if (*pLen < sizeof(SK_U64)) {
+
+ *pLen = sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ /*
+ * There are not many restrictions to the
+ * value range.
+ */
+ if (*pLen != sizeof(SK_U64)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ /* A preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_OK);
+ }
+ /*
+ * Store the new threshold, which will be taken
+ * on the next timer event.
+ */
+ SK_PNMI_READ_U64(pBuf, Val64);
+ pAC->Pnmi.RlmtChangeThreshold = Val64;
+ break;
+
+ default:
+ /* The other OIDs are not be able for set */
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance.
+ *
+ * Description:
+ * Performs get requests on multiple instance variables.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int RlmtStat(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int PhysPortMax;
+ unsigned int PhysPortIndex;
+ unsigned int Limit;
+ unsigned int Offset;
+ int Ret;
+ SK_U32 Val32;
+ SK_U64 Val64;
+
+ /*
+ * Calculate the port indexes from the instance.
+ */
+ PhysPortMax = pAC->GIni.GIMacsFound;
+
+ if ((Instance != (SK_U32)(-1))) {
+ /* Check instance range */
+ if ((Instance < 1) || (Instance > PhysPortMax)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ /* Single net mode */
+ PhysPortIndex = Instance - 1;
+
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ PhysPortIndex = NetIndex;
+ }
+
+ /* Both net modes */
+ Limit = PhysPortIndex + 1;
+ }
+ else {
+ /* Single net mode */
+ PhysPortIndex = 0;
+ Limit = PhysPortMax;
+
+ /* Dual net mode */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ PhysPortIndex = NetIndex;
+ Limit = PhysPortIndex + 1;
+ }
+ }
+
+ /*
+ * Currently only get requests are allowed.
+ */
+ if (Action != SK_PNMI_GET) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /*
+ * Check if the buffer length is large enough.
+ */
+ switch (Id) {
+
+ case OID_SKGE_RLMT_PORT_INDEX:
+ case OID_SKGE_RLMT_STATUS:
+ if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+
+ *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_RLMT_TX_HELLO_CTS:
+ case OID_SKGE_RLMT_RX_HELLO_CTS:
+ case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+ case OID_SKGE_RLMT_RX_SP_CTS:
+ if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) {
+
+ *pLen = (Limit - PhysPortIndex) * sizeof(SK_U64);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039,
+ SK_PNMI_ERR039MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+
+ }
+
+ /*
+ * Update statistic and increment semaphores to indicate that
+ * an update was already done.
+ */
+ if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+ *pLen = 0;
+ return (Ret);
+ }
+ pAC->Pnmi.RlmtUpdatedFlag ++;
+
+ /*
+ * Get value
+ */
+ Offset = 0;
+ for (; PhysPortIndex < Limit; PhysPortIndex ++) {
+
+ switch (Id) {
+
+ case OID_SKGE_RLMT_PORT_INDEX:
+ Val32 = PhysPortIndex;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_RLMT_STATUS:
+ if (pAC->Rlmt.Port[PhysPortIndex].PortState ==
+ SK_RLMT_PS_INIT ||
+ pAC->Rlmt.Port[PhysPortIndex].PortState ==
+ SK_RLMT_PS_DOWN) {
+
+ Val32 = SK_PNMI_RLMT_STATUS_ERROR;
+ }
+ else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ Val32 = SK_PNMI_RLMT_STATUS_ACTIVE;
+ }
+ else {
+ Val32 = SK_PNMI_RLMT_STATUS_STANDBY;
+ }
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_RLMT_TX_HELLO_CTS:
+ Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts;
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RLMT_RX_HELLO_CTS:
+ Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts;
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+ Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts;
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ case OID_SKGE_RLMT_RX_SP_CTS:
+ Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts;
+ SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+ Offset += sizeof(SK_U64);
+ break;
+
+ default:
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+ ("RlmtStat: Unknown OID should be errored before"));
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ *pLen = Offset;
+
+ pAC->Pnmi.RlmtUpdatedFlag --;
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateConf - OID handler function of OIDs concerning the configuration
+ *
+ * Description:
+ * Get/Presets/Sets the OIDs concerning the configuration.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int MacPrivateConf(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int PhysPortMax;
+ unsigned int PhysPortIndex;
+ unsigned int LogPortMax;
+ unsigned int LogPortIndex;
+ unsigned int Limit;
+ unsigned int Offset;
+ char Val8;
+ char *pBufPtr;
+ int Ret;
+ SK_EVPARA EventParam;
+ SK_U32 Val32;
+
+ /*
+ * Calculate instance if wished. MAC index 0 is the virtual MAC.
+ */
+ PhysPortMax = pAC->GIni.GIMacsFound;
+ LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+ LogPortMax--;
+ }
+
+ if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+ /* Check instance range */
+ if ((Instance < 1) || (Instance > LogPortMax)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+ LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+ Limit = LogPortIndex + 1;
+ }
+
+ else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+ LogPortIndex = 0;
+ Limit = LogPortMax;
+ }
+
+ /*
+ * Perform action
+ */
+ if (Action == SK_PNMI_GET) {
+
+ /* Check length */
+ switch (Id) {
+
+ case OID_SKGE_PMD:
+ case OID_SKGE_CONNECTOR:
+ case OID_SKGE_LINK_CAP:
+ case OID_SKGE_LINK_MODE:
+ case OID_SKGE_LINK_MODE_STATUS:
+ case OID_SKGE_LINK_STATUS:
+ case OID_SKGE_FLOWCTRL_CAP:
+ case OID_SKGE_FLOWCTRL_MODE:
+ case OID_SKGE_FLOWCTRL_STATUS:
+ case OID_SKGE_PHY_OPERATION_CAP:
+ case OID_SKGE_PHY_OPERATION_MODE:
+ case OID_SKGE_PHY_OPERATION_STATUS:
+ case OID_SKGE_SPEED_CAP:
+ case OID_SKGE_SPEED_MODE:
+ case OID_SKGE_SPEED_STATUS:
+ if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
+
+ *pLen = (Limit - LogPortIndex) * sizeof(SK_U8);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_MTU:
+ case OID_SKGE_PHY_TYPE:
+ if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) {
+
+ *pLen = (Limit - LogPortIndex) * sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
+ SK_PNMI_ERR041MSG);
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * Update statistic and increment semaphore to indicate
+ * that an update was already done.
+ */
+ if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+ *pLen = 0;
+ return (Ret);
+ }
+ pAC->Pnmi.SirqUpdatedFlag ++;
+
+ /*
+ * Get value
+ */
+ Offset = 0;
+ for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+ pBufPtr = pBuf + Offset;
+
+ switch (Id) {
+
+ case OID_SKGE_PMD:
+ *pBufPtr = pAC->Pnmi.PMD;
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_CONNECTOR:
+ *pBufPtr = pAC->Pnmi.Connector;
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_PHY_TYPE:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ continue;
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+ Val32 = pAC->GIni.GP[PhysPortIndex].PhyType;
+ SK_PNMI_STORE_U32(pBufPtr, Val32);
+ }
+ }
+ else { /* DualNetMode */
+
+ Val32 = pAC->GIni.GP[NetIndex].PhyType;
+ SK_PNMI_STORE_U32(pBufPtr, Val32);
+ }
+ Offset += sizeof(SK_U32);
+ break;
+
+ case OID_SKGE_LINK_CAP:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkCap;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PLinkCap;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_LINK_MODE:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkModeConf;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PLinkModeConf;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_LINK_MODE_STATUS:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr =
+ CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = CalculateLinkModeStatus(pAC, IoC, NetIndex);
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_LINK_STATUS:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = CalculateLinkStatus(pAC, IoC, NetIndex);
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_FLOWCTRL_CAP:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlCap;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_FLOWCTRL_MODE:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlMode;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_FLOWCTRL_STATUS:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlStatus;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_PHY_OPERATION_CAP:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSCap;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PMSCap;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_PHY_OPERATION_MODE:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSMode;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PMSMode;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_PHY_OPERATION_STATUS:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSStatus;
+ }
+ }
+ else {
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PMSStatus;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SPEED_CAP:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical ports */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedCap;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedCap;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SPEED_MODE:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeed;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeed;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SPEED_STATUS:
+ if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+ if (LogPortIndex == 0) {
+ /* Get value for virtual port */
+ VirtualConf(pAC, IoC, Id, pBufPtr);
+ }
+ else {
+ /* Get value for physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+
+ *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+ }
+ }
+ else { /* DualNetMode */
+
+ *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedUsed;
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_MTU:
+ Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
+ SK_PNMI_STORE_U32(pBufPtr, Val32);
+ Offset += sizeof(SK_U32);
+ break;
+
+ default:
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+ ("MacPrivateConf: Unknown OID should be handled before"));
+
+ pAC->Pnmi.SirqUpdatedFlag --;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ *pLen = Offset;
+ pAC->Pnmi.SirqUpdatedFlag --;
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /*
+ * From here SET or PRESET action. Check if the passed
+ * buffer length is plausible.
+ */
+ switch (Id) {
+
+ case OID_SKGE_LINK_MODE:
+ case OID_SKGE_FLOWCTRL_MODE:
+ case OID_SKGE_PHY_OPERATION_MODE:
+ case OID_SKGE_SPEED_MODE:
+ if (*pLen < Limit - LogPortIndex) {
+
+ *pLen = Limit - LogPortIndex;
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ if (*pLen != Limit - LogPortIndex) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ break;
+
+ case OID_SKGE_MTU:
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ if (*pLen != sizeof(SK_U32)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+ break;
+
+ default:
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /*
+ * Perform preset or set
+ */
+ Offset = 0;
+ for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+ switch (Id) {
+
+ case OID_SKGE_LINK_MODE:
+ /* Check the value range */
+ Val8 = *(pBuf + Offset);
+ if (Val8 == 0) {
+
+ Offset += sizeof(char);
+ break;
+ }
+ if (Val8 < SK_LMODE_HALF ||
+ (LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) ||
+ (LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ if (LogPortIndex == 0) {
+
+ /*
+ * The virtual port consists of all currently
+ * active ports. Find them and send an event
+ * with the new link mode to SIRQ.
+ */
+ for (PhysPortIndex = 0;
+ PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ if (!pAC->Pnmi.Port[PhysPortIndex].
+ ActiveFlag) {
+
+ continue;
+ }
+
+ EventParam.Para32[0] = PhysPortIndex;
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_LMODE,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR043,
+ SK_PNMI_ERR043MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ }
+ else {
+ /*
+ * Send an event with the new link mode to
+ * the SIRQ module.
+ */
+ EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR043,
+ SK_PNMI_ERR043MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_FLOWCTRL_MODE:
+ /* Check the value range */
+ Val8 = *(pBuf + Offset);
+ if (Val8 == 0) {
+
+ Offset += sizeof(char);
+ break;
+ }
+ if (Val8 < SK_FLOW_MODE_NONE ||
+ (LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) ||
+ (LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ if (LogPortIndex == 0) {
+
+ /*
+ * The virtual port consists of all currently
+ * active ports. Find them and send an event
+ * with the new flow control mode to SIRQ.
+ */
+ for (PhysPortIndex = 0;
+ PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ if (!pAC->Pnmi.Port[PhysPortIndex].
+ ActiveFlag) {
+
+ continue;
+ }
+
+ EventParam.Para32[0] = PhysPortIndex;
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_FLOWMODE,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR044,
+ SK_PNMI_ERR044MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ }
+ else {
+ /*
+ * Send an event with the new flow control
+ * mode to the SIRQ module.
+ */
+ EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_FLOWMODE, EventParam)
+ > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR044,
+ SK_PNMI_ERR044MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_PHY_OPERATION_MODE :
+ /* Check the value range */
+ Val8 = *(pBuf + Offset);
+ if (Val8 == 0) {
+ /* mode of this port remains unchanged */
+ Offset += sizeof(char);
+ break;
+ }
+ if (Val8 < SK_MS_MODE_AUTO ||
+ (LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) ||
+ (LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ if (LogPortIndex == 0) {
+
+ /*
+ * The virtual port consists of all currently
+ * active ports. Find them and send an event
+ * with new master/slave (role) mode to SIRQ.
+ */
+ for (PhysPortIndex = 0;
+ PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ if (!pAC->Pnmi.Port[PhysPortIndex].
+ ActiveFlag) {
+
+ continue;
+ }
+
+ EventParam.Para32[0] = PhysPortIndex;
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_ROLE,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR042,
+ SK_PNMI_ERR042MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ }
+ else {
+ /*
+ * Send an event with the new master/slave
+ * (role) mode to the SIRQ module.
+ */
+ EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_ROLE, EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR042,
+ SK_PNMI_ERR042MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_SPEED_MODE:
+ /* Check the value range */
+ Val8 = *(pBuf + Offset);
+ if (Val8 == 0) {
+
+ Offset += sizeof(char);
+ break;
+ }
+ if (Val8 < (SK_LSPEED_AUTO) ||
+ (LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) ||
+ (LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ if (LogPortIndex == 0) {
+
+ /*
+ * The virtual port consists of all currently
+ * active ports. Find them and send an event
+ * with the new flow control mode to SIRQ.
+ */
+ for (PhysPortIndex = 0;
+ PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ continue;
+ }
+
+ EventParam.Para32[0] = PhysPortIndex;
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_SPEED,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR045,
+ SK_PNMI_ERR045MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ }
+ else {
+ /*
+ * Send an event with the new flow control
+ * mode to the SIRQ module.
+ */
+ EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+ pAC, LogPortIndex);
+ EventParam.Para32[1] = (SK_U32)Val8;
+ if (SkGeSirqEvent(pAC, IoC,
+ SK_HWEV_SET_SPEED,
+ EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW,
+ SK_PNMI_ERR045,
+ SK_PNMI_ERR045MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ Offset += sizeof(char);
+ break;
+
+ case OID_SKGE_MTU :
+ /* Check the value range */
+ Val32 = *(SK_U32*)(pBuf + Offset);
+ if (Val32 == 0) {
+ /* mtu of this port remains unchanged */
+ Offset += sizeof(SK_U32);
+ break;
+ }
+ if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ /* The preset ends here */
+ if (Action == SK_PNMI_PRESET) {
+ return (SK_PNMI_ERR_OK);
+ }
+
+ if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ Offset += sizeof(SK_U32);
+ break;
+
+ default:
+ SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+ ("MacPrivateConf: Unknown OID should be handled before set"));
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Monitor - OID handler function for RLMT_MONITOR_XXX
+ *
+ * Description:
+ * Because RLMT currently does not support the monitoring of
+ * remote adapter cards, we return always an empty table.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_BAD_VALUE The passed value is not in the valid
+ * value range.
+ * SK_PNMI_ERR_READ_ONLY The OID is read-only and cannot be set.
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+PNMI_STATIC int Monitor(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ unsigned int Index;
+ unsigned int Limit;
+ unsigned int Offset;
+ unsigned int Entries;
+
+
+ /*
+ * Calculate instance if wished.
+ */
+ /* XXX Not yet implemented. Return always an empty table. */
+ Entries = 0;
+
+ if ((Instance != (SK_U32)(-1))) {
+
+ if ((Instance < 1) || (Instance > Entries)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ Index = (unsigned int)Instance - 1;
+ Limit = (unsigned int)Instance;
+ }
+ else {
+ Index = 0;
+ Limit = Entries;
+ }
+
+ /*
+ * Get/Set value
+ */
+ if (Action == SK_PNMI_GET) {
+
+ for (Offset=0; Index < Limit; Index ++) {
+
+ switch (Id) {
+
+ case OID_SKGE_RLMT_MONITOR_INDEX:
+ case OID_SKGE_RLMT_MONITOR_ADDR:
+ case OID_SKGE_RLMT_MONITOR_ERRS:
+ case OID_SKGE_RLMT_MONITOR_TIMESTAMP:
+ case OID_SKGE_RLMT_MONITOR_ADMIN:
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046,
+ SK_PNMI_ERR046MSG);
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+ *pLen = Offset;
+ }
+ else {
+ /* Only MONITOR_ADMIN can be set */
+ if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_READ_ONLY);
+ }
+
+ /* Check if the length is plausible */
+ if (*pLen < (Limit - Index)) {
+
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ /* Okay, we have a wide value range */
+ if (*pLen != (Limit - Index)) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+/*
+ for (Offset=0; Index < Limit; Index ++) {
+ }
+*/
+/*
+ * XXX Not yet implemented. Return always BAD_VALUE, because the table
+ * is empty.
+ */
+ *pLen = 0;
+ return (SK_PNMI_ERR_BAD_VALUE);
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * VirtualConf - Calculates the values of configuration OIDs for virtual port
+ *
+ * Description:
+ * We handle here the get of the configuration group OIDs, which are
+ * a little bit complicated. The virtual port consists of all currently
+ * active physical ports. If multiple ports are active and configured
+ * differently we get in some trouble to return a single value. So we
+ * get the value of the first active port and compare it with that of
+ * the other active ports. If they are not the same, we return a value
+ * that indicates that the state is indeterminated.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void VirtualConf(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf) /* Buffer used for the management data transfer */
+{
+ unsigned int PhysPortMax;
+ unsigned int PhysPortIndex;
+ SK_U8 Val8;
+ SK_U32 Val32;
+ SK_BOOL PortActiveFlag;
+ SK_GEPORT *pPrt;
+
+ *pBuf = 0;
+ PortActiveFlag = SK_FALSE;
+ PhysPortMax = pAC->GIni.GIMacsFound;
+
+ for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ pPrt = &pAC->GIni.GP[PhysPortIndex];
+
+ /* Check if the physical port is active */
+ if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ continue;
+ }
+
+ PortActiveFlag = SK_TRUE;
+
+ switch (Id) {
+
+ case OID_SKGE_PHY_TYPE:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+ Val32 = pPrt->PhyType;
+ SK_PNMI_STORE_U32(pBuf, Val32);
+ continue;
+ }
+
+ case OID_SKGE_LINK_CAP:
+
+ /*
+ * Different capabilities should not happen, but
+ * in the case of the cases OR them all together.
+ * From a curious point of view the virtual port
+ * is capable of all found capabilities.
+ */
+ *pBuf |= pPrt->PLinkCap;
+ break;
+
+ case OID_SKGE_LINK_MODE:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PLinkModeConf;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different link
+ * mode than the first one we return a value that
+ * indicates that the link mode is indeterminated.
+ */
+ if (*pBuf != pPrt->PLinkModeConf) {
+
+ *pBuf = SK_LMODE_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_LINK_MODE_STATUS:
+ /* Get the link mode of the physical port */
+ Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = Val8;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different link
+ * mode status than the first one we return a value
+ * that indicates that the link mode status is
+ * indeterminated.
+ */
+ if (*pBuf != Val8) {
+
+ *pBuf = SK_LMODE_STAT_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_LINK_STATUS:
+ /* Get the link status of the physical port */
+ Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = Val8;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different link
+ * status than the first one, we return a value
+ * that indicates that the link status is
+ * indeterminated.
+ */
+ if (*pBuf != Val8) {
+
+ *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_FLOWCTRL_CAP:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PFlowCtrlCap;
+ continue;
+ }
+
+ /*
+ * From a curious point of view the virtual port
+ * is capable of all found capabilities.
+ */
+ *pBuf |= pPrt->PFlowCtrlCap;
+ break;
+
+ case OID_SKGE_FLOWCTRL_MODE:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PFlowCtrlMode;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different flow
+ * control mode than the first one, we return a value
+ * that indicates that the mode is indeterminated.
+ */
+ if (*pBuf != pPrt->PFlowCtrlMode) {
+
+ *pBuf = SK_FLOW_MODE_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_FLOWCTRL_STATUS:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PFlowCtrlStatus;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different flow
+ * control status than the first one, we return a
+ * value that indicates that the status is
+ * indeterminated.
+ */
+ if (*pBuf != pPrt->PFlowCtrlStatus) {
+
+ *pBuf = SK_FLOW_STAT_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_PHY_OPERATION_CAP:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PMSCap;
+ continue;
+ }
+
+ /*
+ * From a curious point of view the virtual port
+ * is capable of all found capabilities.
+ */
+ *pBuf |= pPrt->PMSCap;
+ break;
+
+ case OID_SKGE_PHY_OPERATION_MODE:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PMSMode;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different master/
+ * slave mode than the first one, we return a value
+ * that indicates that the mode is indeterminated.
+ */
+ if (*pBuf != pPrt->PMSMode) {
+
+ *pBuf = SK_MS_MODE_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_PHY_OPERATION_STATUS:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PMSStatus;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different master/
+ * slave status than the first one, we return a
+ * value that indicates that the status is
+ * indeterminated.
+ */
+ if (*pBuf != pPrt->PMSStatus) {
+
+ *pBuf = SK_MS_STAT_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_SPEED_MODE:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PLinkSpeed;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different flow
+ * control mode than the first one, we return a value
+ * that indicates that the mode is indeterminated.
+ */
+ if (*pBuf != pPrt->PLinkSpeed) {
+
+ *pBuf = SK_LSPEED_INDETERMINATED;
+ }
+ break;
+
+ case OID_SKGE_SPEED_STATUS:
+ /* Check if it is the first active port */
+ if (*pBuf == 0) {
+
+ *pBuf = pPrt->PLinkSpeedUsed;
+ continue;
+ }
+
+ /*
+ * If we find an active port with a different flow
+ * control status than the first one, we return a
+ * value that indicates that the status is
+ * indeterminated.
+ */
+ if (*pBuf != pPrt->PLinkSpeedUsed) {
+
+ *pBuf = SK_LSPEED_STAT_INDETERMINATED;
+ }
+ break;
+ }
+ }
+
+ /*
+ * If no port is active return an indeterminated answer
+ */
+ if (!PortActiveFlag) {
+
+ switch (Id) {
+
+ case OID_SKGE_LINK_CAP:
+ *pBuf = SK_LMODE_CAP_INDETERMINATED;
+ break;
+
+ case OID_SKGE_LINK_MODE:
+ *pBuf = SK_LMODE_INDETERMINATED;
+ break;
+
+ case OID_SKGE_LINK_MODE_STATUS:
+ *pBuf = SK_LMODE_STAT_INDETERMINATED;
+ break;
+
+ case OID_SKGE_LINK_STATUS:
+ *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+ break;
+
+ case OID_SKGE_FLOWCTRL_CAP:
+ case OID_SKGE_FLOWCTRL_MODE:
+ *pBuf = SK_FLOW_MODE_INDETERMINATED;
+ break;
+
+ case OID_SKGE_FLOWCTRL_STATUS:
+ *pBuf = SK_FLOW_STAT_INDETERMINATED;
+ break;
+
+ case OID_SKGE_PHY_OPERATION_CAP:
+ *pBuf = SK_MS_CAP_INDETERMINATED;
+ break;
+
+ case OID_SKGE_PHY_OPERATION_MODE:
+ *pBuf = SK_MS_MODE_INDETERMINATED;
+ break;
+
+ case OID_SKGE_PHY_OPERATION_STATUS:
+ *pBuf = SK_MS_STAT_INDETERMINATED;
+ break;
+ case OID_SKGE_SPEED_CAP:
+ *pBuf = SK_LSPEED_CAP_INDETERMINATED;
+ break;
+
+ case OID_SKGE_SPEED_MODE:
+ *pBuf = SK_LSPEED_INDETERMINATED;
+ break;
+
+ case OID_SKGE_SPEED_STATUS:
+ *pBuf = SK_LSPEED_STAT_INDETERMINATED;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkStatus - Determins the link status of a physical port
+ *
+ * Description:
+ * Determins the link status the following way:
+ * LSTAT_PHY_DOWN: Link is down
+ * LSTAT_AUTONEG: Auto-negotiation failed
+ * LSTAT_LOG_DOWN: Link is up but RLMT did not yet put the port
+ * logically up.
+ * LSTAT_LOG_UP: RLMT marked the port as up
+ *
+ * Returns:
+ * Link status of physical port
+ */
+PNMI_STATIC SK_U8 CalculateLinkStatus(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+unsigned int PhysPortIndex) /* Physical port index */
+{
+ SK_U8 Result;
+
+ if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) {
+
+ Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN;
+ }
+ else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) {
+
+ Result = SK_PNMI_RLMT_LSTAT_AUTONEG;
+ }
+ else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) {
+
+ Result = SK_PNMI_RLMT_LSTAT_LOG_UP;
+ }
+ else {
+ Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN;
+ }
+
+ return (Result);
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkModeStatus - Determins the link mode status of a phys. port
+ *
+ * Description:
+ * The COMMON module only tells us if the mode is half or full duplex.
+ * But in the decade of auto sensing it is useful for the user to
+ * know if the mode was negotiated or forced. Therefore we have a
+ * look to the mode, which was last used by the negotiation process.
+ *
+ * Returns:
+ * The link mode status
+ */
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+unsigned int PhysPortIndex) /* Physical port index */
+{
+ SK_U8 Result;
+
+ /* Get the current mode, which can be full or half duplex */
+ Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus;
+
+ /* Check if no valid mode could be found (link is down) */
+ if (Result < SK_LMODE_STAT_HALF) {
+
+ Result = SK_LMODE_STAT_UNKNOWN;
+ }
+ else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) {
+
+ /*
+ * Auto-negotiation was used to bring up the link. Change
+ * the already found duplex status that it indicates
+ * auto-negotiation was involved.
+ */
+ if (Result == SK_LMODE_STAT_HALF) {
+
+ Result = SK_LMODE_STAT_AUTOHALF;
+ }
+ else if (Result == SK_LMODE_STAT_FULL) {
+
+ Result = SK_LMODE_STAT_AUTOFULL;
+ }
+ }
+
+ return (Result);
+}
+
+/*****************************************************************************
+ *
+ * GetVpdKeyArr - Obtain an array of VPD keys
+ *
+ * Description:
+ * Read the VPD keys and build an array of VPD keys, which are
+ * easy to access.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK Task successfully performed.
+ * SK_PNMI_ERR_GENERAL Something went wrong.
+ */
+PNMI_STATIC int GetVpdKeyArr(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+char *pKeyArr, /* Ptr KeyArray */
+unsigned int KeyArrLen, /* Length of array in bytes */
+unsigned int *pKeyNo) /* Number of keys */
+{
+ unsigned int BufKeysLen = SK_PNMI_VPD_BUFSIZE;
+ char BufKeys[SK_PNMI_VPD_BUFSIZE];
+ unsigned int StartOffset;
+ unsigned int Offset;
+ int Index;
+ int Ret;
+
+
+ SK_MEMSET(pKeyArr, 0, KeyArrLen);
+
+ /*
+ * Get VPD key list
+ */
+ Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen,
+ (int *)pKeyNo);
+ if (Ret > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014,
+ SK_PNMI_ERR014MSG);
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ /* If no keys are available return now */
+ if (*pKeyNo == 0 || BufKeysLen == 0) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+ /*
+ * If the key list is too long for us trunc it and give a
+ * errorlog notification. This case should not happen because
+ * the maximum number of keys is limited due to RAM limitations
+ */
+ if (*pKeyNo > SK_PNMI_VPD_ENTRIES) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
+ SK_PNMI_ERR015MSG);
+
+ *pKeyNo = SK_PNMI_VPD_ENTRIES;
+ }
+
+ /*
+ * Now build an array of fixed string length size and copy
+ * the keys together.
+ */
+ for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen;
+ Offset ++) {
+
+ if (BufKeys[Offset] != 0) {
+
+ continue;
+ }
+
+ if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
+ SK_PNMI_ERR016MSG);
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+ &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+
+ Index ++;
+ StartOffset = Offset + 1;
+ }
+
+ /* Last key not zero terminated? Get it anyway */
+ if (StartOffset < Offset) {
+
+ SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+ &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SirqUpdate - Let the SIRQ update its internal values
+ *
+ * Description:
+ * Just to be sure that the SIRQ module holds its internal data
+ * structures up to date, we send an update event before we make
+ * any access.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK Task successfully performed.
+ * SK_PNMI_ERR_GENERAL Something went wrong.
+ */
+PNMI_STATIC int SirqUpdate(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC) /* IO context handle */
+{
+ SK_EVPARA EventParam;
+
+
+ /* Was the module already updated during the current PNMI call? */
+ if (pAC->Pnmi.SirqUpdatedFlag > 0) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* Send an synchronuous update event to the module */
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+ if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047,
+ SK_PNMI_ERR047MSG);
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtUpdate - Let the RLMT update its internal values
+ *
+ * Description:
+ * Just to be sure that the RLMT module holds its internal data
+ * structures up to date, we send an update event before we make
+ * any access.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK Task successfully performed.
+ * SK_PNMI_ERR_GENERAL Something went wrong.
+ */
+PNMI_STATIC int RlmtUpdate(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */
+{
+ SK_EVPARA EventParam;
+
+
+ /* Was the module already updated during the current PNMI call? */
+ if (pAC->Pnmi.RlmtUpdatedFlag > 0) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* Send an synchronuous update event to the module */
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+ EventParam.Para32[0] = NetIndex;
+ EventParam.Para32[1] = (SK_U32)-1;
+ if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
+ SK_PNMI_ERR048MSG);
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacUpdate - Force the XMAC to output the current statistic
+ *
+ * Description:
+ * The XMAC holds its statistic internally. To obtain the current
+ * values we must send a command so that the statistic data will
+ * be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK Task successfully performed.
+ * SK_PNMI_ERR_GENERAL Something went wrong.
+ */
+PNMI_STATIC int MacUpdate(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+unsigned int FirstMac, /* Index of the first Mac to be updated */
+unsigned int LastMac) /* Index of the last Mac to be updated */
+{
+ unsigned int MacIndex;
+
+ /*
+ * Were the statistics already updated during the
+ * current PNMI call?
+ */
+ if (pAC->Pnmi.MacUpdatedFlag > 0) {
+
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* Send an update command to all MACs specified */
+ for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {
+
+ /*
+ * 2002-09-13 pweber: Freeze the current SW counters.
+ * (That should be done as close as
+ * possible to the update of the
+ * HW counters)
+ */
+ if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+ pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex];
+ }
+
+ /* 2002-09-13 pweber: Update the HW counter */
+ if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) {
+
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ }
+
+ return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * GetStatVal - Retrieve an XMAC statistic counter
+ *
+ * Description:
+ * Retrieves the statistic counter of a virtual or physical port. The
+ * virtual port is identified by the index 0. It consists of all
+ * currently active ports. To obtain the counter value for this port
+ * we must add the statistic counter of all active ports. To grant
+ * continuous counter values for the virtual port even when port
+ * switches occur we must additionally add a delta value, which was
+ * calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event.
+ *
+ * Returns:
+ * Requested statistic value
+ */
+PNMI_STATIC SK_U64 GetStatVal(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+unsigned int LogPortIndex, /* Index of the logical Port to be processed */
+unsigned int StatIndex, /* Index to statistic value */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */
+{
+ unsigned int PhysPortIndex;
+ unsigned int PhysPortMax;
+ SK_U64 Val = 0;
+
+
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+
+ PhysPortIndex = NetIndex;
+
+ Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+ }
+ else { /* Single Net mode */
+
+ if (LogPortIndex == 0) {
+
+ PhysPortMax = pAC->GIni.GIMacsFound;
+
+ /* Add counter of all active ports */
+ for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+ PhysPortIndex ++) {
+
+ if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+ Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+ }
+ }
+
+ /* Correct value because of port switches */
+ Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
+ }
+ else {
+ /* Get counter value of physical port */
+ PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+
+ Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+ }
+ }
+ return (Val);
+}
+
+/*****************************************************************************
+ *
+ * GetPhysStatVal - Get counter value for physical port
+ *
+ * Description:
+ * Builds a 64bit counter value. Except for the octet counters
+ * the lower 32bit are counted in hardware and the upper 32bit
+ * in software by monitoring counter overflow interrupts in the
+ * event handler. To grant continous counter values during XMAC
+ * resets (caused by a workaround) we must add a delta value.
+ * The delta was calculated in the event handler when a
+ * SK_PNMI_EVT_XMAC_RESET was received.
+ *
+ * Returns:
+ * Counter value
+ */
+PNMI_STATIC SK_U64 GetPhysStatVal(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+unsigned int PhysPortIndex, /* Index of the logical Port to be processed */
+unsigned int StatIndex) /* Index to statistic value */
+{
+ SK_U64 Val = 0;
+ SK_U32 LowVal = 0;
+ SK_U32 HighVal = 0;
+ SK_U16 Word;
+ int MacType;
+ unsigned int HelpIndex;
+ SK_GEPORT *pPrt;
+
+ SK_PNMI_PORT *pPnmiPrt;
+ SK_GEMACFUNC *pFnMac;
+
+ pPrt = &pAC->GIni.GP[PhysPortIndex];
+
+ MacType = pAC->GIni.GIMacType;
+
+ /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+ if (MacType == SK_MAC_XMAC) {
+ pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex];
+ }
+ else {
+ pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex];
+ }
+
+ pFnMac = &pAC->GIni.GIFunc;
+
+ switch (StatIndex) {
+ case SK_PNMI_HTX:
+ if (MacType == SK_MAC_GMAC) {
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[SK_PNMI_HTX_BROADCAST][MacType].Reg,
+ &LowVal);
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[SK_PNMI_HTX_MULTICAST][MacType].Reg,
+ &HighVal);
+ LowVal += HighVal;
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[SK_PNMI_HTX_UNICAST][MacType].Reg,
+ &HighVal);
+ LowVal += HighVal;
+ }
+ else {
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ }
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HRX:
+ if (MacType == SK_MAC_GMAC) {
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[SK_PNMI_HRX_BROADCAST][MacType].Reg,
+ &LowVal);
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[SK_PNMI_HRX_MULTICAST][MacType].Reg,
+ &HighVal);
+ LowVal += HighVal;
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[SK_PNMI_HRX_UNICAST][MacType].Reg,
+ &HighVal);
+ LowVal += HighVal;
+ }
+ else {
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ }
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HTX_OCTET:
+ case SK_PNMI_HRX_OCTET:
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &HighVal);
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex + 1][MacType].Reg,
+ &LowVal);
+ break;
+
+ case SK_PNMI_HTX_BURST:
+ case SK_PNMI_HTX_EXCESS_DEF:
+ case SK_PNMI_HTX_CARRIER:
+ /* Not supported by GMAC */
+ if (MacType == SK_MAC_GMAC) {
+ return (Val);
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HTX_MACC:
+ /* GMAC only supports PAUSE MAC control frames */
+ if (MacType == SK_MAC_GMAC) {
+ HelpIndex = SK_PNMI_HTX_PMACC;
+ }
+ else {
+ HelpIndex = StatIndex;
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[HelpIndex][MacType].Reg,
+ &LowVal);
+
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HTX_COL:
+ case SK_PNMI_HRX_UNDERSIZE:
+ /* Not supported by XMAC */
+ if (MacType == SK_MAC_XMAC) {
+ return (Val);
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HTX_DEFFERAL:
+ /* Not supported by GMAC */
+ if (MacType == SK_MAC_GMAC) {
+ return (Val);
+ }
+
+ /*
+ * XMAC counts frames with deferred transmission
+ * even in full-duplex mode.
+ *
+ * In full-duplex mode the counter remains constant!
+ */
+ if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) ||
+ (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL)) {
+
+ LowVal = 0;
+ HighVal = 0;
+ }
+ else {
+ /* Otherwise get contents of hardware register */
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ }
+ break;
+
+ case SK_PNMI_HRX_BADOCTET:
+ /* Not supported by XMAC */
+ if (MacType == SK_MAC_XMAC) {
+ return (Val);
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &HighVal);
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex + 1][MacType].Reg,
+ &LowVal);
+ break;
+
+ case SK_PNMI_HTX_OCTETLOW:
+ case SK_PNMI_HRX_OCTETLOW:
+ case SK_PNMI_HRX_BADOCTETLOW:
+ return (Val);
+
+ case SK_PNMI_HRX_LONGFRAMES:
+ /* For XMAC the SW counter is managed by PNMI */
+ if (MacType == SK_MAC_XMAC) {
+ return (pPnmiPrt->StatRxLongFrameCts);
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HRX_TOO_LONG:
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+ Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+ if (MacType == SK_MAC_GMAC) {
+ /* For GMAC the SW counter is additionally managed by PNMI */
+ Val += pPnmiPrt->StatRxFrameTooLongCts;
+ }
+ else {
+ /*
+ * Frames longer than IEEE 802.3 frame max size are counted
+ * by XMAC in frame_too_long counter even reception of long
+ * frames was enabled and the frame was correct.
+ * So correct the value by subtracting RxLongFrame counter.
+ */
+ Val -= pPnmiPrt->StatRxLongFrameCts;
+ }
+
+ LowVal = (SK_U32)Val;
+ HighVal = (SK_U32)(Val >> 32);
+ break;
+
+ case SK_PNMI_HRX_SHORTS:
+ /* Not supported by GMAC */
+ if (MacType == SK_MAC_GMAC) {
+ /* GM_RXE_FRAG?? */
+ return (Val);
+ }
+
+ /*
+ * XMAC counts short frame errors even if link down (#10620)
+ *
+ * If link-down the counter remains constant
+ */
+ if (pPrt->PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) {
+
+ /* Otherwise get incremental difference */
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+ Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+ Val -= pPnmiPrt->RxShortZeroMark;
+
+ LowVal = (SK_U32)Val;
+ HighVal = (SK_U32)(Val >> 32);
+ }
+ break;
+
+ case SK_PNMI_HRX_MACC:
+ case SK_PNMI_HRX_MACC_UNKWN:
+ case SK_PNMI_HRX_BURST:
+ case SK_PNMI_HRX_MISSED:
+ case SK_PNMI_HRX_FRAMING:
+ case SK_PNMI_HRX_CARRIER:
+ case SK_PNMI_HRX_IRLENGTH:
+ case SK_PNMI_HRX_SYMBOL:
+ case SK_PNMI_HRX_CEXT:
+ /* Not supported by GMAC */
+ if (MacType == SK_MAC_GMAC) {
+ return (Val);
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ case SK_PNMI_HRX_PMACC_ERR:
+ /* For GMAC the SW counter is managed by PNMI */
+ if (MacType == SK_MAC_GMAC) {
+ return (pPnmiPrt->StatRxPMaccErr);
+ }
+
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+
+ /* SW counter managed by PNMI */
+ case SK_PNMI_HTX_SYNC:
+ LowVal = (SK_U32)pPnmiPrt->StatSyncCts;
+ HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32);
+ break;
+
+ /* SW counter managed by PNMI */
+ case SK_PNMI_HTX_SYNC_OCTET:
+ LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts;
+ HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32);
+ break;
+
+ case SK_PNMI_HRX_FCS:
+ /*
+ * Broadcom filters FCS errors and counts it in
+ * Receive Error Counter register
+ */
+ if (pPrt->PhyType == SK_PHY_BCOM) {
+ /* do not read while not initialized (PHY_READ hangs!)*/
+ if (pPrt->PState != SK_PRT_RESET) {
+ SkXmPhyRead(pAC, IoC, PhysPortIndex, PHY_BCOM_RE_CTR, &Word);
+
+ LowVal = Word;
+ }
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ }
+ else {
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ }
+ break;
+
+ default:
+ (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+ StatAddr[StatIndex][MacType].Reg,
+ &LowVal);
+ HighVal = pPnmiPrt->CounterHigh[StatIndex];
+ break;
+ }
+
+ Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+ /* Correct value because of possible XMAC reset. XMAC Errata #2 */
+ Val += pPnmiPrt->CounterOffset[StatIndex];
+
+ return (Val);
+}
+
+/*****************************************************************************
+ *
+ * ResetCounter - Set all counters and timestamps to zero
+ *
+ * Description:
+ * Notifies other common modules which store statistic data to
+ * reset their counters and finally reset our own counters.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void ResetCounter(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+SK_U32 NetIndex)
+{
+ unsigned int PhysPortIndex;
+ SK_EVPARA EventParam;
+
+
+ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+
+ /* Notify sensor module */
+ SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);
+
+ /* Notify RLMT module */
+ EventParam.Para32[0] = NetIndex;
+ EventParam.Para32[1] = (SK_U32)-1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
+ EventParam.Para32[1] = 0;
+
+ /* Notify SIRQ module */
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);
+
+ /* Notify CSUM module */
+#ifdef SK_USE_CSUM
+ EventParam.Para32[0] = NetIndex;
+ EventParam.Para32[1] = (SK_U32)-1;
+ SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
+ EventParam);
+#endif /* SK_USE_CSUM */
+
+ /* Clear XMAC statistic */
+ for (PhysPortIndex = 0; PhysPortIndex <
+ (unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {
+
+ (void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex);
+
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
+ 0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+ CounterOffset, 0, sizeof(pAC->Pnmi.Port[
+ PhysPortIndex].CounterOffset));
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts,
+ 0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts));
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+ StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[
+ PhysPortIndex].StatSyncOctetsCts));
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+ StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[
+ PhysPortIndex].StatRxLongFrameCts));
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+ StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[
+ PhysPortIndex].StatRxFrameTooLongCts));
+ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+ StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[
+ PhysPortIndex].StatRxPMaccErr));
+ }
+
+ /*
+ * Clear local statistics
+ */
+ SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0,
+ sizeof(pAC->Pnmi.VirtualCounterOffset));
+ pAC->Pnmi.RlmtChangeCts = 0;
+ pAC->Pnmi.RlmtChangeTime = 0;
+ SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0,
+ sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
+ pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
+ pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
+ pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0;
+ pAC->Pnmi.Port[NetIndex].TxRetryCts = 0;
+ pAC->Pnmi.Port[NetIndex].RxIntrCts = 0;
+ pAC->Pnmi.Port[NetIndex].TxIntrCts = 0;
+ pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0;
+ pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0;
+ pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0;
+ pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0;
+ pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0;
+ pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0;
+}
+
+/*****************************************************************************
+ *
+ * GetTrapEntry - Get an entry in the trap buffer
+ *
+ * Description:
+ * The trap buffer stores various events. A user application somehow
+ * gets notified that an event occured and retrieves the trap buffer
+ * contens (or simply polls the buffer). The buffer is organized as
+ * a ring which stores the newest traps at the beginning. The oldest
+ * traps are overwritten by the newest ones. Each trap entry has a
+ * unique number, so that applications may detect new trap entries.
+ *
+ * Returns:
+ * A pointer to the trap entry
+ */
+PNMI_STATIC char* GetTrapEntry(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_U32 TrapId, /* SNMP ID of the trap */
+unsigned int Size) /* Space needed for trap entry */
+{
+ unsigned int BufPad = pAC->Pnmi.TrapBufPad;
+ unsigned int BufFree = pAC->Pnmi.TrapBufFree;
+ unsigned int Beg = pAC->Pnmi.TrapQueueBeg;
+ unsigned int End = pAC->Pnmi.TrapQueueEnd;
+ char *pBuf = &pAC->Pnmi.TrapBuf[0];
+ int Wrap;
+ unsigned int NeededSpace;
+ unsigned int EntrySize;
+ SK_U32 Val32;
+ SK_U64 Val64;
+
+
+ /* Last byte of entry will get a copy of the entry length */
+ Size ++;
+
+ /*
+ * Calculate needed buffer space */
+ if (Beg >= Size) {
+
+ NeededSpace = Size;
+ Wrap = SK_FALSE;
+ }
+ else {
+ NeededSpace = Beg + Size;
+ Wrap = SK_TRUE;
+ }
+
+ /*
+ * Check if enough buffer space is provided. Otherwise
+ * free some entries. Leave one byte space between begin
+ * and end of buffer to make it possible to detect whether
+ * the buffer is full or empty
+ */
+ while (BufFree < NeededSpace + 1) {
+
+ if (End == 0) {
+
+ End = SK_PNMI_TRAP_QUEUE_LEN;
+ }
+
+ EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1);
+ BufFree += EntrySize;
+ End -= EntrySize;
+#ifdef DEBUG
+ SK_MEMSET(pBuf + End, (char)(-1), EntrySize);
+#endif /* DEBUG */
+ if (End == BufPad) {
+#ifdef DEBUG
+ SK_MEMSET(pBuf, (char)(-1), End);
+#endif /* DEBUG */
+ BufFree += End;
+ End = 0;
+ BufPad = 0;
+ }
+ }
+
+ /*
+ * Insert new entry as first entry. Newest entries are
+ * stored at the beginning of the queue.
+ */
+ if (Wrap) {
+
+ BufPad = Beg;
+ Beg = SK_PNMI_TRAP_QUEUE_LEN - Size;
+ }
+ else {
+ Beg = Beg - Size;
+ }
+ BufFree -= NeededSpace;
+
+ /* Save the current offsets */
+ pAC->Pnmi.TrapQueueBeg = Beg;
+ pAC->Pnmi.TrapQueueEnd = End;
+ pAC->Pnmi.TrapBufPad = BufPad;
+ pAC->Pnmi.TrapBufFree = BufFree;
+
+ /* Initialize the trap entry */
+ *(pBuf + Beg + Size - 1) = (char)Size;
+ *(pBuf + Beg) = (char)Size;
+ Val32 = (pAC->Pnmi.TrapUnique) ++;
+ SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32);
+ SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId);
+ Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+ SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64);
+
+ return (pBuf + Beg);
+}
+
+/*****************************************************************************
+ *
+ * CopyTrapQueue - Copies the trap buffer for the TRAP OID
+ *
+ * Description:
+ * On a query of the TRAP OID the trap buffer contents will be
+ * copied continuously to the request buffer, which must be large
+ * enough. No length check is performed.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void CopyTrapQueue(
+SK_AC *pAC, /* Pointer to adapter context */
+char *pDstBuf) /* Buffer to which the queued traps will be copied */
+{
+ unsigned int BufPad = pAC->Pnmi.TrapBufPad;
+ unsigned int Trap = pAC->Pnmi.TrapQueueBeg;
+ unsigned int End = pAC->Pnmi.TrapQueueEnd;
+ char *pBuf = &pAC->Pnmi.TrapBuf[0];
+ unsigned int Len;
+ unsigned int DstOff = 0;
+
+
+ while (Trap != End) {
+
+ Len = (unsigned int)*(pBuf + Trap);
+
+ /*
+ * Last byte containing a copy of the length will
+ * not be copied.
+ */
+ *(pDstBuf + DstOff) = (char)(Len - 1);
+ SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2);
+ DstOff += Len - 1;
+
+ Trap += Len;
+ if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+ Trap = BufPad;
+ }
+ }
+}
+
+/*****************************************************************************
+ *
+ * GetTrapQueueLen - Get the length of the trap buffer
+ *
+ * Description:
+ * Evaluates the number of currently stored traps and the needed
+ * buffer size to retrieve them.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void GetTrapQueueLen(
+SK_AC *pAC, /* Pointer to adapter context */
+unsigned int *pLen, /* Length in Bytes of all queued traps */
+unsigned int *pEntries) /* Returns number of trapes stored in queue */
+{
+ unsigned int BufPad = pAC->Pnmi.TrapBufPad;
+ unsigned int Trap = pAC->Pnmi.TrapQueueBeg;
+ unsigned int End = pAC->Pnmi.TrapQueueEnd;
+ char *pBuf = &pAC->Pnmi.TrapBuf[0];
+ unsigned int Len;
+ unsigned int Entries = 0;
+ unsigned int TotalLen = 0;
+
+
+ while (Trap != End) {
+
+ Len = (unsigned int)*(pBuf + Trap);
+ TotalLen += Len - 1;
+ Entries ++;
+
+ Trap += Len;
+ if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+ Trap = BufPad;
+ }
+ }
+
+ *pEntries = Entries;
+ *pLen = TotalLen;
+}
+
+/*****************************************************************************
+ *
+ * QueueSimpleTrap - Store a simple trap to the trap buffer
+ *
+ * Description:
+ * A simple trap is a trap with now additional data. It consists
+ * simply of a trap code.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void QueueSimpleTrap(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_U32 TrapId) /* Type of sensor trap */
+{
+ GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN);
+}
+
+/*****************************************************************************
+ *
+ * QueueSensorTrap - Stores a sensor trap in the trap buffer
+ *
+ * Description:
+ * Gets an entry in the trap buffer and fills it with sensor related
+ * data.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void QueueSensorTrap(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_U32 TrapId, /* Type of sensor trap */
+unsigned int SensorIndex) /* Index of sensor which caused the trap */
+{
+ char *pBuf;
+ unsigned int Offset;
+ unsigned int DescrLen;
+ SK_U32 Val32;
+
+
+ /* Get trap buffer entry */
+ DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc);
+ pBuf = GetTrapEntry(pAC, TrapId,
+ SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen);
+ Offset = SK_PNMI_TRAP_SIMPLE_LEN;
+
+ /* Store additionally sensor trap related data */
+ Val32 = OID_SKGE_SENSOR_INDEX;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ *(pBuf + Offset + 4) = 4;
+ Val32 = (SK_U32)SensorIndex;
+ SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+ Offset += 9;
+
+ Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ *(pBuf + Offset + 4) = (char)DescrLen;
+ SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc,
+ DescrLen);
+ Offset += DescrLen + 5;
+
+ Val32 = OID_SKGE_SENSOR_TYPE;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ *(pBuf + Offset + 4) = 1;
+ *(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType;
+ Offset += 6;
+
+ Val32 = OID_SKGE_SENSOR_VALUE;
+ SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+ *(pBuf + Offset + 4) = 4;
+ Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue;
+ SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer
+ *
+ * Description:
+ * Nothing further to explain.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void QueueRlmtNewMacTrap(
+SK_AC *pAC, /* Pointer to adapter context */
+unsigned int ActiveMac) /* Index (0..n) of the currently active port */
+{
+ char *pBuf;
+ SK_U32 Val32;
+
+
+ pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT,
+ SK_PNMI_TRAP_RLMT_CHANGE_LEN);
+
+ Val32 = OID_SKGE_RLMT_PORT_ACTIVE;
+ SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+ *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+ *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac;
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer
+ *
+ * Description:
+ * Nothing further to explain.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void QueueRlmtPortTrap(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_U32 TrapId, /* Type of RLMT port trap */
+unsigned int PortIndex) /* Index of the port, which changed its state */
+{
+ char *pBuf;
+ SK_U32 Val32;
+
+
+ pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN);
+
+ Val32 = OID_SKGE_RLMT_PORT_INDEX;
+ SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+ *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+ *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex;
+}
+
+/*****************************************************************************
+ *
+ * CopyMac - Copies a MAC address
+ *
+ * Description:
+ * Nothing further to explain.
+ *
+ * Returns:
+ * Nothing
+ */
+PNMI_STATIC void CopyMac(
+char *pDst, /* Pointer to destination buffer */
+SK_MAC_ADDR *pMac) /* Pointer of Source */
+{
+ int i;
+
+
+ for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) {
+
+ *(pDst + i) = pMac->a[i];
+ }
+}
+
+#ifdef SK_POWER_MGMT
+/*****************************************************************************
+ *
+ * PowerManagement - OID handler function of PowerManagement OIDs
+ *
+ * Description:
+ * The code is simple. No description necessary.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+
+PNMI_STATIC int PowerManagement(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* Get/PreSet/Set action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen, /* On call: buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */
+{
+
+ SK_U32 RetCode = SK_PNMI_ERR_GENERAL;
+
+ /*
+ * Check instance. We only handle single instance variables
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+
+ /* Check length */
+ switch (Id) {
+
+ case OID_PNP_CAPABILITIES:
+ if (*pLen < sizeof(SK_PNP_CAPABILITIES)) {
+
+ *pLen = sizeof(SK_PNP_CAPABILITIES);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_PNP_SET_POWER:
+ case OID_PNP_QUERY_POWER:
+ if (*pLen < sizeof(SK_DEVICE_POWER_STATE))
+ {
+ *pLen = sizeof(SK_DEVICE_POWER_STATE);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) {
+
+ *pLen = sizeof(SK_PM_PACKET_PATTERN);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_PNP_ENABLE_WAKE_UP:
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+ }
+
+ /*
+ * Perform action
+ */
+ if (Action == SK_PNMI_GET) {
+
+ /*
+ * Get value
+ */
+ switch (Id) {
+
+ case OID_PNP_CAPABILITIES:
+ RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen);
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ /* The Windows DDK describes: An OID_PNP_QUERY_POWER requests
+ the miniport to indicate whether it can transition its NIC
+ to the low-power state.
+ A miniport driver must always return NDIS_STATUS_SUCCESS
+ to a query of OID_PNP_QUERY_POWER. */
+ *pLen = sizeof(SK_DEVICE_POWER_STATE);
+ RetCode = SK_PNMI_ERR_OK;
+ break;
+
+ /* NDIS handles these OIDs as write-only.
+ * So in case of get action the buffer with written length = 0
+ * is returned
+ */
+ case OID_PNP_SET_POWER:
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ *pLen = 0;
+ RetCode = SK_PNMI_ERR_NOT_SUPPORTED;
+ break;
+
+ case OID_PNP_ENABLE_WAKE_UP:
+ RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen);
+ break;
+
+ default:
+ RetCode = SK_PNMI_ERR_GENERAL;
+ break;
+ }
+
+ return (RetCode);
+ }
+
+
+ /*
+ * Perform preset or set
+ */
+
+ /* POWER module does not support PRESET action */
+ if (Action == SK_PNMI_PRESET) {
+ return (SK_PNMI_ERR_OK);
+ }
+
+ switch (Id) {
+ case OID_PNP_SET_POWER:
+ RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen);
+ break;
+
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen);
+ break;
+
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen);
+ break;
+
+ case OID_PNP_ENABLE_WAKE_UP:
+ RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen);
+ break;
+
+ default:
+ RetCode = SK_PNMI_ERR_READ_ONLY;
+ }
+
+ return (RetCode);
+}
+#endif /* SK_POWER_MGMT */
+
+#ifdef SK_DIAG_SUPPORT
+/*****************************************************************************
+ *
+ * DiagActions - OID handler function of Diagnostic driver
+ *
+ * Description:
+ * The code is simple. No description necessary.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+
+PNMI_STATIC int DiagActions(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+
+ SK_U32 DiagStatus;
+ SK_U32 RetCode = SK_PNMI_ERR_GENERAL;
+
+ /*
+ * Check instance. We only handle single instance variables.
+ */
+ if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ /*
+ * Check length.
+ */
+ switch (Id) {
+
+ case OID_SKGE_DIAG_MODE:
+ if (*pLen < sizeof(SK_U32)) {
+
+ *pLen = sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040, SK_PNMI_ERR040MSG);
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /* Perform action. */
+
+ /* GET value. */
+ if (Action == SK_PNMI_GET) {
+
+ switch (Id) {
+
+ case OID_SKGE_DIAG_MODE:
+ DiagStatus = pAC->Pnmi.DiagAttached;
+ SK_PNMI_STORE_U32(pBuf, DiagStatus);
+ *pLen = sizeof(SK_U32);
+ RetCode = SK_PNMI_ERR_OK;
+ break;
+
+ default:
+ *pLen = 0;
+ RetCode = SK_PNMI_ERR_GENERAL;
+ break;
+ }
+ return (RetCode);
+ }
+
+ /* From here SET or PRESET value. */
+
+ /* PRESET value is not supported. */
+ if (Action == SK_PNMI_PRESET) {
+ return (SK_PNMI_ERR_OK);
+ }
+
+ /* SET value. */
+ switch (Id) {
+ case OID_SKGE_DIAG_MODE:
+
+ /* Handle the SET. */
+ switch (*pBuf) {
+
+ /* Attach the DIAG to this adapter. */
+ case SK_DIAG_ATTACHED:
+ /* Check if we come from running */
+ if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+
+ RetCode = SkDrvLeaveDiagMode(pAC);
+
+ }
+ else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) {
+
+ RetCode = SK_PNMI_ERR_OK;
+ }
+
+ else {
+
+ RetCode = SK_PNMI_ERR_GENERAL;
+
+ }
+
+ if (RetCode == SK_PNMI_ERR_OK) {
+
+ pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED;
+ }
+ break;
+
+ /* Enter the DIAG mode in the driver. */
+ case SK_DIAG_RUNNING:
+ RetCode = SK_PNMI_ERR_OK;
+
+ /*
+ * If DiagAttached is set, we can tell the driver
+ * to enter the DIAG mode.
+ */
+ if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
+ /* If DiagMode is not active, we can enter it. */
+ if (!pAC->DiagModeActive) {
+
+ RetCode = SkDrvEnterDiagMode(pAC);
+ }
+ else {
+
+ RetCode = SK_PNMI_ERR_GENERAL;
+ }
+ }
+ else {
+
+ RetCode = SK_PNMI_ERR_GENERAL;
+ }
+
+ if (RetCode == SK_PNMI_ERR_OK) {
+
+ pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING;
+ }
+ break;
+
+ case SK_DIAG_IDLE:
+ /* Check if we come from running */
+ if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+
+ RetCode = SkDrvLeaveDiagMode(pAC);
+
+ }
+ else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
+
+ RetCode = SK_PNMI_ERR_OK;
+ }
+
+ else {
+
+ RetCode = SK_PNMI_ERR_GENERAL;
+
+ }
+
+ if (RetCode == SK_PNMI_ERR_OK) {
+
+ pAC->Pnmi.DiagAttached = SK_DIAG_IDLE;
+ }
+ break;
+
+ default:
+ RetCode = SK_PNMI_ERR_BAD_VALUE;
+ break;
+ }
+ break;
+
+ default:
+ RetCode = SK_PNMI_ERR_GENERAL;
+ }
+
+ if (RetCode == SK_PNMI_ERR_OK) {
+ *pLen = sizeof(SK_U32);
+ }
+ else {
+
+ *pLen = 0;
+ }
+ return (RetCode);
+}
+#endif /* SK_DIAG_SUPPORT */
+
+/*****************************************************************************
+ *
+ * Vct - OID handler function of OIDs
+ *
+ * Description:
+ * The code is simple. No description necessary.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was performed successfully.
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured.
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain
+ * the correct data (e.g. a 32bit value is
+ * needed, but a 16 bit value was passed).
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter).
+ * SK_PNMI_ERR_READ_ONLY Only the Get action is allowed.
+ *
+ */
+
+PNMI_STATIC int Vct(
+SK_AC *pAC, /* Pointer to adapter context */
+SK_IOC IoC, /* IO context handle */
+int Action, /* GET/PRESET/SET action */
+SK_U32 Id, /* Object ID that is to be processed */
+char *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance, /* Instance (-1,2..n) that is to be queried */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+ SK_GEPORT *pPrt;
+ SK_PNMI_VCT *pVctBackupData;
+ SK_U32 LogPortMax;
+ SK_U32 PhysPortMax;
+ SK_U32 PhysPortIndex;
+ SK_U32 Limit;
+ SK_U32 Offset;
+ SK_BOOL Link;
+ SK_U32 RetCode = SK_PNMI_ERR_GENERAL;
+ int i;
+ SK_EVPARA Para;
+ SK_U32 CableLength;
+
+ /*
+ * Calculate the port indexes from the instance.
+ */
+ PhysPortMax = pAC->GIni.GIMacsFound;
+ LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+ /* Dual net mode? */
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ LogPortMax--;
+ }
+
+ if ((Instance != (SK_U32) (-1))) {
+ /* Check instance range. */
+ if ((Instance < 2) || (Instance > LogPortMax)) {
+ *pLen = 0;
+ return (SK_PNMI_ERR_UNKNOWN_INST);
+ }
+
+ if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+ PhysPortIndex = NetIndex;
+ }
+ else {
+ PhysPortIndex = Instance - 2;
+ }
+ Limit = PhysPortIndex + 1;
+ }
+ else {
+ /*
+ * Instance == (SK_U32) (-1), get all Instances of that OID.
+ *
+ * Not implemented yet. May be used in future releases.
+ */
+ PhysPortIndex = 0;
+ Limit = PhysPortMax;
+ }
+
+ pPrt = &pAC->GIni.GP[PhysPortIndex];
+ if (pPrt->PHWLinkUp) {
+ Link = SK_TRUE;
+ }
+ else {
+ Link = SK_FALSE;
+ }
+
+ /* Check MAC type */
+ if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /* Initialize backup data pointer. */
+ pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+
+ /* Check action type */
+ if (Action == SK_PNMI_GET) {
+ /* Check length */
+ switch (Id) {
+
+ case OID_SKGE_VCT_GET:
+ if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) {
+ *pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ case OID_SKGE_VCT_STATUS:
+ if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) {
+ *pLen = (Limit - PhysPortIndex) * sizeof(SK_U8);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /* Get value */
+ Offset = 0;
+ for (; PhysPortIndex < Limit; PhysPortIndex++) {
+ switch (Id) {
+
+ case OID_SKGE_VCT_GET:
+ if ((Link == SK_FALSE) &&
+ (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) {
+ RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+ if (RetCode == 0) {
+ pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+ pAC->Pnmi.VctStatus[PhysPortIndex] |=
+ (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+
+ /* Copy results for later use to PNMI struct. */
+ for (i = 0; i < 4; i++) {
+ if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+ if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) {
+ pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+ }
+ }
+ if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) {
+ CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+ }
+ else {
+ CableLength = 0;
+ }
+ pVctBackupData->PMdiPairLen[i] = CableLength;
+ pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+ }
+
+ Para.Para32[0] = PhysPortIndex;
+ Para.Para32[1] = -1;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+ SkEventDispatcher(pAC, IoC);
+ }
+ else {
+ ; /* VCT test is running. */
+ }
+ }
+
+ /* Get all results. */
+ CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+ Offset += sizeof(SK_U8);
+ *(pBuf + Offset) = pPrt->PCableLen;
+ Offset += sizeof(SK_U8);
+ for (i = 0; i < 4; i++) {
+ SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]);
+ Offset += sizeof(SK_U32);
+ }
+ for (i = 0; i < 4; i++) {
+ *(pBuf + Offset) = pVctBackupData->PMdiPairSts[i];
+ Offset += sizeof(SK_U8);
+ }
+
+ RetCode = SK_PNMI_ERR_OK;
+ break;
+
+ case OID_SKGE_VCT_STATUS:
+ CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+ Offset += sizeof(SK_U8);
+ RetCode = SK_PNMI_ERR_OK;
+ break;
+
+ default:
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ } /* for */
+ *pLen = Offset;
+ return (RetCode);
+
+ } /* if SK_PNMI_GET */
+
+ /*
+ * From here SET or PRESET action. Check if the passed
+ * buffer length is plausible.
+ */
+
+ /* Check length */
+ switch (Id) {
+ case OID_SKGE_VCT_SET:
+ if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+ *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+ return (SK_PNMI_ERR_TOO_SHORT);
+ }
+ break;
+
+ default:
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+
+ /*
+ * Perform preset or set.
+ */
+
+ /* VCT does not support PRESET action. */
+ if (Action == SK_PNMI_PRESET) {
+ return (SK_PNMI_ERR_OK);
+ }
+
+ Offset = 0;
+ for (; PhysPortIndex < Limit; PhysPortIndex++) {
+ switch (Id) {
+ case OID_SKGE_VCT_SET: /* Start VCT test. */
+ if (Link == SK_FALSE) {
+ SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST);
+
+ RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE);
+ if (RetCode == 0) { /* RetCode: 0 => Start! */
+ pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING;
+ pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+ pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK;
+
+ /*
+ * Start VCT timer counter.
+ */
+ SK_MEMSET((char *) &Para, 0, sizeof(Para));
+ Para.Para32[0] = PhysPortIndex;
+ Para.Para32[1] = -1;
+ SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+ 4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para);
+ SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+ RetCode = SK_PNMI_ERR_OK;
+ }
+ else { /* RetCode: 2 => Running! */
+ SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+ RetCode = SK_PNMI_ERR_OK;
+ }
+ }
+ else { /* RetCode: 4 => Link! */
+ RetCode = 4;
+ SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+ RetCode = SK_PNMI_ERR_OK;
+ }
+ Offset += sizeof(SK_U32);
+ break;
+
+ default:
+ *pLen = 0;
+ return (SK_PNMI_ERR_GENERAL);
+ }
+ } /* for */
+ *pLen = Offset;
+ return (RetCode);
+
+} /* Vct */
+
+
+PNMI_STATIC void CheckVctStatus(
+SK_AC *pAC,
+SK_IOC IoC,
+char *pBuf,
+SK_U32 Offset,
+SK_U32 PhysPortIndex)
+{
+ SK_GEPORT *pPrt;
+ SK_PNMI_VCT *pVctData;
+ SK_U32 RetCode;
+
+ pPrt = &pAC->GIni.GP[PhysPortIndex];
+
+ pVctData = (SK_PNMI_VCT *) (pBuf + Offset);
+ pVctData->VctStatus = SK_PNMI_VCT_NONE;
+
+ if (!pPrt->PHWLinkUp) {
+
+ /* Was a VCT test ever made before? */
+ if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+ if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) {
+ pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+ }
+ else {
+ pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+ }
+ }
+
+ /* Check VCT test status. */
+ RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE);
+ if (RetCode == 2) { /* VCT test is running. */
+ pVctData->VctStatus |= SK_PNMI_VCT_RUNNING;
+ }
+ else { /* VCT data was copied to pAC here. Check PENDING state. */
+ if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+ pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+ }
+ }
+
+ if (pPrt->PCableLen != 0xff) { /* Old DSP value. */
+ pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA;
+ }
+ }
+ else {
+
+ /* Was a VCT test ever made before? */
+ if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+ pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+ pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+ }
+
+ /* DSP only valid in 100/1000 modes. */
+ if (pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed !=
+ SK_LSPEED_STAT_10MBPS) {
+ pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA;
+ }
+ }
+} /* CheckVctStatus */
+
+
+/*****************************************************************************
+ *
+ * SkPnmiGenIoctl - Handles new generic PNMI IOCTL, calls the needed
+ * PNMI function depending on the subcommand and
+ * returns all data belonging to the complete database
+ * or OID request.
+ *
+ * Description:
+ * Looks up the requested subcommand, calls the corresponding handler
+ * function and passes all required parameters to it.
+ * The function is called by the driver. It is needed to handle the new
+ * generic PNMI IOCTL. This IOCTL is given to the driver and contains both
+ * the OID and a subcommand to decide what kind of request has to be done.
+ *
+ * Returns:
+ * SK_PNMI_ERR_OK The request was successfully performed
+ * SK_PNMI_ERR_GENERAL A general severe internal error occured
+ * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take
+ * the data.
+ * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown
+ * SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ * exist (e.g. port instance 3 on a two port
+ * adapter.
+ */
+int SkPnmiGenIoctl(
+SK_AC *pAC, /* Pointer to adapter context struct */
+SK_IOC IoC, /* I/O context */
+void *pBuf, /* Buffer used for the management data transfer */
+unsigned int *pLen, /* Length of buffer */
+SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */
+{
+SK_I32 Mode; /* Store value of subcommand. */
+SK_U32 Oid; /* Store value of OID. */
+int ReturnCode; /* Store return value to show status of PNMI action. */
+int HeaderLength; /* Length of desired action plus OID. */
+
+ ReturnCode = SK_PNMI_ERR_GENERAL;
+
+ SK_MEMCPY(&Mode, pBuf, sizeof(SK_I32));
+ SK_MEMCPY(&Oid, (char *) pBuf + sizeof(SK_I32), sizeof(SK_U32));
+ HeaderLength = sizeof(SK_I32) + sizeof(SK_U32);
+ *pLen = *pLen - HeaderLength;
+ SK_MEMCPY((char *) pBuf + sizeof(SK_I32), (char *) pBuf + HeaderLength, *pLen);
+
+ switch(Mode) {
+ case SK_GET_SINGLE_VAR:
+ ReturnCode = SkPnmiGetVar(pAC, IoC, Oid,
+ (char *) pBuf + sizeof(SK_I32), pLen,
+ ((SK_U32) (-1)), NetIndex);
+ SK_PNMI_STORE_U32(pBuf, ReturnCode);
+ *pLen = *pLen + sizeof(SK_I32);
+ break;
+ case SK_PRESET_SINGLE_VAR:
+ ReturnCode = SkPnmiPreSetVar(pAC, IoC, Oid,
+ (char *) pBuf + sizeof(SK_I32), pLen,
+ ((SK_U32) (-1)), NetIndex);
+ SK_PNMI_STORE_U32(pBuf, ReturnCode);
+ *pLen = *pLen + sizeof(SK_I32);
+ break;
+ case SK_SET_SINGLE_VAR:
+ ReturnCode = SkPnmiSetVar(pAC, IoC, Oid,
+ (char *) pBuf + sizeof(SK_I32), pLen,
+ ((SK_U32) (-1)), NetIndex);
+ SK_PNMI_STORE_U32(pBuf, ReturnCode);
+ *pLen = *pLen + sizeof(SK_I32);
+ break;
+ case SK_GET_FULL_MIB:
+ ReturnCode = SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+ break;
+ case SK_PRESET_FULL_MIB:
+ ReturnCode = SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+ break;
+ case SK_SET_FULL_MIB:
+ ReturnCode = SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+ break;
+ default:
+ break;
+ }
+
+ return (ReturnCode);
+
+} /* SkGeIocGen */
diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c
new file mode 100644
index 000000000000..3e7aa49afd00
--- /dev/null
+++ b/drivers/net/sk98lin/skgesirq.c
@@ -0,0 +1,2229 @@
+/******************************************************************************
+ *
+ * Name: skgesirq.c
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.92 $
+ * Date: $Date: 2003/09/16 14:37:07 $
+ * Purpose: Special IRQ module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Special Interrupt handler
+ *
+ * The following abstract should show how this module is included
+ * in the driver path:
+ *
+ * In the ISR of the driver the bits for frame transmission complete and
+ * for receive complete are checked and handled by the driver itself.
+ * The bits of the slow path mask are checked after that and then the
+ * entry into the so-called "slow path" is prepared. It is an implementors
+ * decision whether this is executed directly or just scheduled by
+ * disabling the mask. In the interrupt service routine some events may be
+ * generated, so it would be a good idea to call the EventDispatcher
+ * right after this ISR.
+ *
+ * The Interrupt source register of the adapter is NOT read by this module.
+ * SO if the drivers implementor needs a while loop around the
+ * slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for
+ * each loop entered.
+ *
+ * However, the MAC Interrupt status registers are read in a while loop.
+ *
+ */
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skgesirq.c,v 1.92 2003/09/16 14:37:07 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h" /* Driver Specific Definitions */
+#ifndef SK_SLIM
+#include "h/skgepnmi.h" /* PNMI Definitions */
+#include "h/skrlmt.h" /* RLMT Definitions */
+#endif
+#include "h/skdrv2nd.h" /* Adapter Control and Driver specific Def. */
+
+/* local function prototypes */
+#ifdef GENESIS
+static int SkGePortCheckUpXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static int SkGePortCheckUpBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static void SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* GENESIS */
+#ifdef YUKON
+static int SkGePortCheckUpGmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* YUKON */
+#ifdef OTHER_PHY
+static int SkGePortCheckUpLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static int SkGePortCheckUpNat(SK_AC*, SK_IOC, int, SK_BOOL);
+static void SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* OTHER_PHY */
+
+#ifdef GENESIS
+/*
+ * array of Rx counter from XMAC which are checked
+ * in AutoSense mode to check whether a link is not able to auto-negotiate.
+ */
+static const SK_U16 SkGeRxRegs[]= {
+ XM_RXF_64B,
+ XM_RXF_127B,
+ XM_RXF_255B,
+ XM_RXF_511B,
+ XM_RXF_1023B,
+ XM_RXF_MAX_SZ
+} ;
+#endif /* GENESIS */
+
+#ifdef __C2MAN__
+/*
+ * Special IRQ function
+ *
+ * General Description:
+ *
+ */
+intro()
+{}
+#endif
+
+/******************************************************************************
+ *
+ * SkHWInitDefSense() - Default Autosensing mode initialization
+ *
+ * Description: sets the PLinkMode for HWInit
+ *
+ * Returns: N/A
+ */
+static void SkHWInitDefSense(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ pPrt->PAutoNegTimeOut = 0;
+
+ if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+ pPrt->PLinkMode = pPrt->PLinkModeConf;
+ return;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("AutoSensing: First mode %d on Port %d\n",
+ (int)SK_LMODE_AUTOFULL, Port));
+
+ pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
+
+ return;
+} /* SkHWInitDefSense */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkHWSenseGetNext() - Get Next Autosensing Mode
+ *
+ * Description: gets the appropriate next mode
+ *
+ * Note:
+ *
+ */
+static SK_U8 SkHWSenseGetNext(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ pPrt->PAutoNegTimeOut = 0;
+
+ if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
+ /* Leave all as configured */
+ return(pPrt->PLinkModeConf);
+ }
+
+ if (pPrt->PLinkMode == (SK_U8)SK_LMODE_AUTOFULL) {
+ /* Return next mode AUTOBOTH */
+ return ((SK_U8)SK_LMODE_AUTOBOTH);
+ }
+
+ /* Return default autofull */
+ return ((SK_U8)SK_LMODE_AUTOFULL);
+} /* SkHWSenseGetNext */
+
+
+/******************************************************************************
+ *
+ * SkHWSenseSetNext() - Autosensing Set next mode
+ *
+ * Description: sets the appropriate next mode
+ *
+ * Returns: N/A
+ */
+static void SkHWSenseSetNext(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_U8 NewMode) /* New Mode to be written in sense mode */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ pPrt->PAutoNegTimeOut = 0;
+
+ if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
+ return;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("AutoSensing: next mode %d on Port %d\n",
+ (int)NewMode, Port));
+
+ pPrt->PLinkMode = NewMode;
+
+ return;
+} /* SkHWSenseSetNext */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkHWLinkDown() - Link Down handling
+ *
+ * Description: handles the hardware link down signal
+ *
+ * Returns: N/A
+ */
+void SkHWLinkDown(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Disable all MAC interrupts */
+ SkMacIrqDisable(pAC, IoC, Port);
+
+ /* Disable Receiver and Transmitter */
+ SkMacRxTxDisable(pAC, IoC, Port);
+
+ /* Init default sense mode */
+ SkHWInitDefSense(pAC, IoC, Port);
+
+ if (pPrt->PHWLinkUp == SK_FALSE) {
+ return;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link down Port %d\n", Port));
+
+ /* Set Link to DOWN */
+ pPrt->PHWLinkUp = SK_FALSE;
+
+ /* Reset Port stati */
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+ pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED;
+
+ /* Re-init Phy especially when the AutoSense default is set now */
+ SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+ /* GP0: used for workaround of Rev. C Errata 2 */
+
+ /* Do NOT signal to RLMT */
+
+ /* Do NOT start the timer here */
+} /* SkHWLinkDown */
+
+
+/******************************************************************************
+ *
+ * SkHWLinkUp() - Link Up handling
+ *
+ * Description: handles the hardware link up signal
+ *
+ * Returns: N/A
+ */
+static void SkHWLinkUp(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PHWLinkUp) {
+ /* We do NOT need to proceed on active link */
+ return;
+ }
+
+ pPrt->PHWLinkUp = SK_TRUE;
+ pPrt->PAutoNegFail = SK_FALSE;
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+
+ if (pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOHALF &&
+ pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOFULL &&
+ pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOBOTH) {
+ /* Link is up and no Auto-negotiation should be done */
+
+ /* Link speed should be the configured one */
+ switch (pPrt->PLinkSpeed) {
+ case SK_LSPEED_AUTO:
+ /* default is 1000 Mbps */
+ case SK_LSPEED_1000MBPS:
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+ break;
+ case SK_LSPEED_100MBPS:
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
+ break;
+ case SK_LSPEED_10MBPS:
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
+ break;
+ }
+
+ /* Set Link Mode Status */
+ if (pPrt->PLinkMode == SK_LMODE_FULL) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_FULL;
+ }
+ else {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF;
+ }
+
+ /* No flow control without auto-negotiation */
+ pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+
+ /* enable Rx/Tx */
+ (void)SkMacRxTxEnable(pAC, IoC, Port);
+ }
+} /* SkHWLinkUp */
+
+
+/******************************************************************************
+ *
+ * SkMacParity() - MAC parity workaround
+ *
+ * Description: handles MAC parity errors correctly
+ *
+ * Returns: N/A
+ */
+static void SkMacParity(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index of the port failed */
+{
+ SK_EVPARA Para;
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ SK_U32 TxMax; /* Tx Max Size Counter */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Clear IRQ Tx Parity Error */
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
+ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T),
+ (SK_U8)((pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+ pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
+ }
+#endif /* YUKON */
+
+ if (pPrt->PCheckPar) {
+
+ if (Port == MAC_1) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
+ }
+ else {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG);
+ }
+ Para.Para64 = Port;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+
+ Para.Para32[0] = Port;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+ return;
+ }
+
+ /* Check whether frames with a size of 1k were sent */
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* Snap statistic counters */
+ (void)SkXmUpdateStats(pAC, IoC, Port);
+
+ (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ (void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
+ }
+#endif /* YUKON */
+
+ if (TxMax > 0) {
+ /* From now on check the parity */
+ pPrt->PCheckPar = SK_TRUE;
+ }
+} /* SkMacParity */
+
+
+/******************************************************************************
+ *
+ * SkGeHwErr() - Hardware Error service routine
+ *
+ * Description: handles all HW Error interrupts
+ *
+ * Returns: N/A
+ */
+static void SkGeHwErr(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+SK_U32 HwStatus) /* Interrupt status word */
+{
+ SK_EVPARA Para;
+ SK_U16 Word;
+
+ if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) {
+ /* PCI Errors occured */
+ if ((HwStatus & IS_IRQ_STAT) != 0) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG);
+ }
+ else {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG);
+ }
+
+ /* Reset all bits in the PCI STATUS register */
+ SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+
+ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+ Para.Para64 = 0;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+ }
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ if ((HwStatus & IS_NO_STAT_M1) != 0) {
+ /* Ignore it */
+ /* This situation is also indicated in the descriptor */
+ SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+ }
+
+ if ((HwStatus & IS_NO_STAT_M2) != 0) {
+ /* Ignore it */
+ /* This situation is also indicated in the descriptor */
+ SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+ }
+
+ if ((HwStatus & IS_NO_TIST_M1) != 0) {
+ /* Ignore it */
+ /* This situation is also indicated in the descriptor */
+ SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST);
+ }
+
+ if ((HwStatus & IS_NO_TIST_M2) != 0) {
+ /* Ignore it */
+ /* This situation is also indicated in the descriptor */
+ SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST);
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* This is necessary only for Rx timing measurements */
+ if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
+ /* increment Time Stamp Timer counter (high) */
+ pAC->GIni.GITimeStampCnt++;
+
+ /* Clear Time Stamp Timer IRQ */
+ SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ);
+ }
+
+ if ((HwStatus & IS_IRQ_SENSOR) != 0) {
+ /* no sensors on 32-bit Yukon */
+ if (pAC->GIni.GIYukon32Bit) {
+ /* disable HW Error IRQ */
+ pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+ }
+ }
+ }
+#endif /* YUKON */
+
+ if ((HwStatus & IS_RAM_RD_PAR) != 0) {
+ SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
+ Para.Para64 = 0;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+ }
+
+ if ((HwStatus & IS_RAM_WR_PAR) != 0) {
+ SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
+ Para.Para64 = 0;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+ }
+
+ if ((HwStatus & IS_M1_PAR_ERR) != 0) {
+ SkMacParity(pAC, IoC, MAC_1);
+ }
+
+ if ((HwStatus & IS_M2_PAR_ERR) != 0) {
+ SkMacParity(pAC, IoC, MAC_2);
+ }
+
+ if ((HwStatus & IS_R1_PAR_ERR) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P);
+
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG);
+ Para.Para64 = MAC_1;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+
+ Para.Para32[0] = MAC_1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((HwStatus & IS_R2_PAR_ERR) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P);
+
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG);
+ Para.Para64 = MAC_2;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+
+ Para.Para32[0] = MAC_2;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+} /* SkGeHwErr */
+
+
+/******************************************************************************
+ *
+ * SkGeSirqIsr() - Special Interrupt Service Routine
+ *
+ * Description: handles all non data transfer specific interrupts (slow path)
+ *
+ * Returns: N/A
+ */
+void SkGeSirqIsr(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+SK_U32 Istatus) /* Interrupt status word */
+{
+ SK_EVPARA Para;
+ SK_U32 RegVal32; /* Read register value */
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ SK_U16 PhyInt;
+ int i;
+
+ if (((Istatus & IS_HW_ERR) & pAC->GIni.GIValIrqMask) != 0) {
+ /* read the HW Error Interrupt source */
+ SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+
+ SkGeHwErr(pAC, IoC, RegVal32);
+ }
+
+ /*
+ * Packet Timeout interrupts
+ */
+ /* Check whether MACs are correctly initialized */
+ if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) &&
+ pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) {
+ /* MAC 1 was not initialized but Packet timeout occured */
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
+ SKERR_SIRQ_E004MSG);
+ }
+
+ if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) &&
+ pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) {
+ /* MAC 2 was not initialized but Packet timeout occured */
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
+ SKERR_SIRQ_E005MSG);
+ }
+
+ if ((Istatus & IS_PA_TO_RX1) != 0) {
+ /* Means network is filling us up */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
+ SKERR_SIRQ_E002MSG);
+ SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1);
+ }
+
+ if ((Istatus & IS_PA_TO_RX2) != 0) {
+ /* Means network is filling us up */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
+ SKERR_SIRQ_E003MSG);
+ SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2);
+ }
+
+ if ((Istatus & IS_PA_TO_TX1) != 0) {
+
+ pPrt = &pAC->GIni.GP[0];
+
+ /* May be a normal situation in a server with a slow network */
+ SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /*
+ * workaround: if in half duplex mode, check for Tx hangup.
+ * Read number of TX'ed bytes, wait for 10 ms, then compare
+ * the number with current value. If nothing changed, we assume
+ * that Tx is hanging and do a FIFO flush (see event routine).
+ */
+ if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+ pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+ !pPrt->HalfDupTimerActive) {
+ /*
+ * many more pack. arb. timeouts may come in between,
+ * we ignore those
+ */
+ pPrt->HalfDupTimerActive = SK_TRUE;
+ /* Snap statistic counters */
+ (void)SkXmUpdateStats(pAC, IoC, 0);
+
+ (void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_HI, &RegVal32);
+
+ pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+
+ (void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_LO, &RegVal32);
+
+ pPrt->LastOctets += RegVal32;
+
+ Para.Para32[0] = 0;
+ SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+ SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+ }
+ }
+#endif /* GENESIS */
+ }
+
+ if ((Istatus & IS_PA_TO_TX2) != 0) {
+
+ pPrt = &pAC->GIni.GP[1];
+
+ /* May be a normal situation in a server with a slow network */
+ SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2);
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* workaround: see above */
+ if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+ pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+ !pPrt->HalfDupTimerActive) {
+ pPrt->HalfDupTimerActive = SK_TRUE;
+ /* Snap statistic counters */
+ (void)SkXmUpdateStats(pAC, IoC, 1);
+
+ (void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_HI, &RegVal32);
+
+ pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+
+ (void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_LO, &RegVal32);
+
+ pPrt->LastOctets += RegVal32;
+
+ Para.Para32[0] = 1;
+ SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+ SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+ }
+ }
+#endif /* GENESIS */
+ }
+
+ /* Check interrupts of the particular queues */
+ if ((Istatus & IS_R1_C) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
+ SKERR_SIRQ_E006MSG);
+ Para.Para64 = MAC_1;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+ Para.Para32[0] = MAC_1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((Istatus & IS_R2_C) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
+ SKERR_SIRQ_E007MSG);
+ Para.Para64 = MAC_2;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+ Para.Para32[0] = MAC_2;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((Istatus & IS_XS1_C) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
+ SKERR_SIRQ_E008MSG);
+ Para.Para64 = MAC_1;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+ Para.Para32[0] = MAC_1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((Istatus & IS_XA1_C) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
+ SKERR_SIRQ_E009MSG);
+ Para.Para64 = MAC_1;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+ Para.Para32[0] = MAC_1;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((Istatus & IS_XS2_C) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
+ SKERR_SIRQ_E010MSG);
+ Para.Para64 = MAC_2;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+ Para.Para32[0] = MAC_2;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((Istatus & IS_XA2_C) != 0) {
+ /* Clear IRQ */
+ SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
+ SKERR_SIRQ_E011MSG);
+ Para.Para64 = MAC_2;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+ Para.Para32[0] = MAC_2;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ /* External reg interrupt */
+ if ((Istatus & IS_EXT_REG) != 0) {
+ /* Test IRQs from PHY */
+ for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+ pPrt = &pAC->GIni.GP[i];
+
+ if (pPrt->PState == SK_PRT_RESET) {
+ continue;
+ }
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ switch (pPrt->PhyType) {
+
+ case SK_PHY_XMAC:
+ break;
+
+ case SK_PHY_BCOM:
+ SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
+
+ if ((PhyInt & ~PHY_B_DEF_MSK) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Port %d Bcom Int: 0x%04X\n",
+ i, PhyInt));
+ SkPhyIsrBcom(pAC, IoC, i, PhyInt);
+ }
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
+
+ if ((PhyInt & PHY_L_DEF_MSK) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Port %d Lone Int: %x\n",
+ i, PhyInt));
+ SkPhyIsrLone(pAC, IoC, i, PhyInt);
+ }
+ break;
+#endif /* OTHER_PHY */
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* Read PHY Interrupt Status */
+ SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
+
+ if ((PhyInt & PHY_M_DEF_MSK) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Port %d Marv Int: 0x%04X\n",
+ i, PhyInt));
+ SkPhyIsrGmac(pAC, IoC, i, PhyInt);
+ }
+ }
+#endif /* YUKON */
+ }
+ }
+
+ /* I2C Ready interrupt */
+ if ((Istatus & IS_I2C_READY) != 0) {
+#ifdef SK_SLIM
+ SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+#else
+ SkI2cIsr(pAC, IoC);
+#endif
+ }
+
+ /* SW forced interrupt */
+ if ((Istatus & IS_IRQ_SW) != 0) {
+ /* clear the software IRQ */
+ SK_OUT8(IoC, B0_CTST, CS_CL_SW_IRQ);
+ }
+
+ if ((Istatus & IS_LNK_SYNC_M1) != 0) {
+ /*
+ * We do NOT need the Link Sync interrupt, because it shows
+ * us only a link going down.
+ */
+ /* clear interrupt */
+ SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ);
+ }
+
+ /* Check MAC after link sync counter */
+ if ((Istatus & IS_MAC1) != 0) {
+ /* IRQ from MAC 1 */
+ SkMacIrq(pAC, IoC, MAC_1);
+ }
+
+ if ((Istatus & IS_LNK_SYNC_M2) != 0) {
+ /*
+ * We do NOT need the Link Sync interrupt, because it shows
+ * us only a link going down.
+ */
+ /* clear interrupt */
+ SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ);
+ }
+
+ /* Check MAC after link sync counter */
+ if ((Istatus & IS_MAC2) != 0) {
+ /* IRQ from MAC 2 */
+ SkMacIrq(pAC, IoC, MAC_2);
+ }
+
+ /* Timer interrupt (served last) */
+ if ((Istatus & IS_TIMINT) != 0) {
+ /* check for HW Errors */
+ if (((Istatus & IS_HW_ERR) & ~pAC->GIni.GIValIrqMask) != 0) {
+ /* read the HW Error Interrupt source */
+ SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+
+ SkGeHwErr(pAC, IoC, RegVal32);
+ }
+
+ SkHwtIsr(pAC, IoC);
+ }
+
+} /* SkGeSirqIsr */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ */
+static int SkGePortCheckShorts(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port) /* Which port should be checked */
+{
+ SK_U32 Shorts; /* Short Event Counter */
+ SK_U32 CheckShorts; /* Check value for Short Event Counter */
+ SK_U64 RxCts; /* Rx Counter (packets on network) */
+ SK_U32 RxTmp; /* Rx temp. Counter */
+ SK_U32 FcsErrCts; /* FCS Error Counter */
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ int Rtv; /* Return value */
+ int i;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Default: no action */
+ Rtv = SK_HW_PS_NONE;
+
+ (void)SkXmUpdateStats(pAC, IoC, Port);
+
+ /* Extra precaution: check for short Event counter */
+ (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+
+ /*
+ * Read Rx counters (packets seen on the network and not necessarily
+ * really received.
+ */
+ RxCts = 0;
+
+ for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
+
+ (void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
+
+ RxCts += (SK_U64)RxTmp;
+ }
+
+ /* On default: check shorts against zero */
+ CheckShorts = 0;
+
+ /* Extra precaution on active links */
+ if (pPrt->PHWLinkUp) {
+ /* Reset Link Restart counter */
+ pPrt->PLinkResCt = 0;
+ pPrt->PAutoNegTOCt = 0;
+
+ /* If link is up check for 2 */
+ CheckShorts = 2;
+
+ (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts);
+
+ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+ pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
+ (pPrt->PLinkMode == SK_LMODE_HALF ||
+ pPrt->PLinkMode == SK_LMODE_FULL)) {
+ /*
+ * This is autosensing and we are in the fallback
+ * manual full/half duplex mode.
+ */
+ if (RxCts == pPrt->PPrevRx) {
+ /* Nothing received, restart link */
+ pPrt->PPrevFcs = FcsErrCts;
+ pPrt->PPrevShorts = Shorts;
+
+ return(SK_HW_PS_RESTART);
+ }
+ else {
+ pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
+ }
+ }
+
+ if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
+ (!(FcsErrCts - pPrt->PPrevFcs))) {
+ /*
+ * Note: The compare with zero above has to be done the way shown,
+ * otherwise the Linux driver will have a problem.
+ */
+ /*
+ * We received a bunch of frames or no CRC error occured on the
+ * network -> ok.
+ */
+ pPrt->PPrevRx = RxCts;
+ pPrt->PPrevFcs = FcsErrCts;
+ pPrt->PPrevShorts = Shorts;
+
+ return(SK_HW_PS_NONE);
+ }
+
+ pPrt->PPrevFcs = FcsErrCts;
+ }
+
+
+ if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Short Event Count Restart Port %d \n", Port));
+ Rtv = SK_HW_PS_RESTART;
+ }
+
+ pPrt->PPrevShorts = Shorts;
+ pPrt->PPrevRx = RxCts;
+
+ return(Rtv);
+} /* SkGePortCheckShorts */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUp() - Check if the link is up
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ * 2 Link came up
+ */
+static int SkGePortCheckUp(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port) /* Which port should be checked */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ SK_BOOL AutoNeg; /* Is Auto-negotiation used ? */
+ int Rtv; /* Return value */
+
+ Rtv = SK_HW_PS_NONE;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+ AutoNeg = SK_FALSE;
+ }
+ else {
+ AutoNeg = SK_TRUE;
+ }
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ switch (pPrt->PhyType) {
+
+ case SK_PHY_XMAC:
+ Rtv = SkGePortCheckUpXmac(pAC, IoC, Port, AutoNeg);
+ break;
+ case SK_PHY_BCOM:
+ Rtv = SkGePortCheckUpBcom(pAC, IoC, Port, AutoNeg);
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ Rtv = SkGePortCheckUpLone(pAC, IoC, Port, AutoNeg);
+ break;
+ case SK_PHY_NAT:
+ Rtv = SkGePortCheckUpNat(pAC, IoC, Port, AutoNeg);
+ break;
+#endif /* OTHER_PHY */
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ Rtv = SkGePortCheckUpGmac(pAC, IoC, Port, AutoNeg);
+ }
+#endif /* YUKON */
+
+ return(Rtv);
+} /* SkGePortCheckUp */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ * 2 Link came up
+ */
+static int SkGePortCheckUpXmac(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port, /* Which port should be checked */
+SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */
+{
+ SK_U32 Shorts; /* Short Event Counter */
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ int Done;
+ SK_U32 GpReg; /* General Purpose register value */
+ SK_U16 Isrc; /* Interrupt source register */
+ SK_U16 IsrcSum; /* Interrupt source register sum */
+ SK_U16 LpAb; /* Link Partner Ability */
+ SK_U16 ResAb; /* Resolved Ability */
+ SK_U16 ExtStat; /* Extended Status Register */
+ SK_U8 NextMode; /* Next AutoSensing Mode */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PHWLinkUp) {
+ if (pPrt->PhyType != SK_PHY_XMAC) {
+ return(SK_HW_PS_NONE);
+ }
+ else {
+ return(SkGePortCheckShorts(pAC, IoC, Port));
+ }
+ }
+
+ IsrcSum = pPrt->PIsave;
+ pPrt->PIsave = 0;
+
+ /* Now wait for each port's link */
+ if (pPrt->PLinkBroken) {
+ /* Link was broken */
+ XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+
+ if ((GpReg & XM_GP_INP_ASS) == 0) {
+ /* The Link is in sync */
+ XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+ IsrcSum |= Isrc;
+ SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+
+ if ((Isrc & XM_IS_INP_ASS) == 0) {
+ /* It has been in sync since last time */
+ /* Restart the PORT */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link in sync Restart Port %d\n", Port));
+
+ (void)SkXmUpdateStats(pAC, IoC, Port);
+
+ /* We now need to reinitialize the PrevShorts counter */
+ (void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+ pPrt->PPrevShorts = Shorts;
+
+ pPrt->PLinkBroken = SK_FALSE;
+
+ /*
+ * Link Restart Workaround:
+ * it may be possible that the other Link side
+ * restarts its link as well an we detect
+ * another LinkBroken. To prevent this
+ * happening we check for a maximum number
+ * of consecutive restart. If those happens,
+ * we do NOT restart the active link and
+ * check whether the link is now o.k.
+ */
+ pPrt->PLinkResCt++;
+
+ pPrt->PAutoNegTimeOut = 0;
+
+ if (pPrt->PLinkResCt < SK_MAX_LRESTART) {
+ return(SK_HW_PS_RESTART);
+ }
+
+ pPrt->PLinkResCt = 0;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
+ }
+ else {
+ pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum));
+
+ /* Do nothing more if link is broken */
+ return(SK_HW_PS_NONE);
+ }
+ }
+ else {
+ /* Do nothing more if link is broken */
+ return(SK_HW_PS_NONE);
+ }
+
+ }
+ else {
+ /* Link was not broken, check if it is */
+ XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+ IsrcSum |= Isrc;
+ if ((Isrc & XM_IS_INP_ASS) != 0) {
+ XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+ IsrcSum |= Isrc;
+ if ((Isrc & XM_IS_INP_ASS) != 0) {
+ XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+ IsrcSum |= Isrc;
+ if ((Isrc & XM_IS_INP_ASS) != 0) {
+ pPrt->PLinkBroken = SK_TRUE;
+ /* Re-Init Link partner Autoneg flag */
+ pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link broken Port %d\n", Port));
+
+ /* Cable removed-> reinit sense mode */
+ SkHWInitDefSense(pAC, IoC, Port);
+
+ return(SK_HW_PS_RESTART);
+ }
+ }
+ }
+ else {
+ SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
+
+ if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
+ return(SK_HW_PS_RESTART);
+ }
+ }
+ }
+
+ /*
+ * here we usually can check whether the link is in sync and
+ * auto-negotiation is done.
+ */
+ XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+ XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+ IsrcSum |= Isrc;
+
+ SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+
+ if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
+ if ((GpReg & XM_GP_INP_ASS) == 0) {
+ /* Save Auto-negotiation Done interrupt only if link is in sync */
+ pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
+ }
+#ifdef DEBUG
+ if ((pPrt->PIsave & XM_IS_AND) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg done rescheduled Port %d\n", Port));
+ }
+#endif /* DEBUG */
+ return(SK_HW_PS_NONE);
+ }
+
+ if (AutoNeg) {
+ if ((IsrcSum & XM_IS_AND) != 0) {
+ SkHWLinkUp(pAC, IoC, Port);
+ Done = SkMacAutoNegDone(pAC, IoC, Port);
+ if (Done != SK_AND_OK) {
+ /* Get PHY parameters, for debugging only */
+ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb);
+ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
+ Port, LpAb, ResAb));
+
+ /* Try next possible mode */
+ NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+ SkHWLinkDown(pAC, IoC, Port);
+ if (Done == SK_AND_DUP_CAP) {
+ /* GoTo next mode */
+ SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+ }
+
+ return(SK_HW_PS_RESTART);
+ }
+ /*
+ * Dummy Read extended status to prevent extra link down/ups
+ * (clear Page Received bit if set)
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
+
+ return(SK_HW_PS_LINK);
+ }
+
+ /* AutoNeg not done, but HW link is up. Check for timeouts */
+ pPrt->PAutoNegTimeOut++;
+ if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+ /* Increase the Timeout counter */
+ pPrt->PAutoNegTOCt++;
+
+ /* Timeout occured */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("AutoNeg timeout Port %d\n", Port));
+ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+ pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+ /* Set Link manually up */
+ SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Set manual full duplex Port %d\n", Port));
+ }
+
+ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+ pPrt->PLipaAutoNeg == SK_LIPA_AUTO &&
+ pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) {
+ /*
+ * This is rather complicated.
+ * we need to check here whether the LIPA_AUTO
+ * we saw before is false alert. We saw at one
+ * switch ( SR8800) that on boot time it sends
+ * just one auto-neg packet and does no further
+ * auto-negotiation.
+ * Solution: we restart the autosensing after
+ * a few timeouts.
+ */
+ pPrt->PAutoNegTOCt = 0;
+ pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+ SkHWInitDefSense(pAC, IoC, Port);
+ }
+
+ /* Do the restart */
+ return(SK_HW_PS_RESTART);
+ }
+ }
+ else {
+ /* Link is up and we don't need more */
+#ifdef DEBUG
+ if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("ERROR: Lipa auto detected on port %d\n", Port));
+ }
+#endif /* DEBUG */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link sync(GP), Port %d\n", Port));
+ SkHWLinkUp(pAC, IoC, Port);
+
+ /*
+ * Link sync (GP) and so assume a good connection. But if not received
+ * a bunch of frames received in a time slot (maybe broken tx cable)
+ * the port is restart.
+ */
+ return(SK_HW_PS_LINK);
+ }
+
+ return(SK_HW_PS_NONE);
+} /* SkGePortCheckUpXmac */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ * 2 Link came up
+ */
+static int SkGePortCheckUpBcom(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port, /* Which port should be checked */
+SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ int Done;
+ SK_U16 Isrc; /* Interrupt source register */
+ SK_U16 PhyStat; /* Phy Status Register */
+ SK_U16 ResAb; /* Master/Slave resolution */
+ SK_U16 Ctrl; /* Broadcom control flags */
+#ifdef DEBUG
+ SK_U16 LpAb;
+ SK_U16 ExtStat;
+#endif /* DEBUG */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Check for No HCD Link events (#10523) */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc);
+
+#ifdef xDEBUG
+ if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) ==
+ (PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) {
+
+ SK_U32 Stat1, Stat2, Stat3;
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "CheckUp1 - Stat: %x, Mask: %x",
+ (void *)Isrc,
+ (void *)Stat1);
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2);
+ Stat1 = Stat1 << 16 | Stat2;
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+ Stat3 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+ Stat2 = Stat2 << 16 | Stat3;
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "Ctrl/Stat: %x, AN Adv/LP: %x",
+ (void *)Stat1,
+ (void *)Stat2);
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+ Stat1 = Stat1 << 16 | Stat2;
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+ Stat3 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3);
+ Stat2 = Stat2 << 16 | Stat3;
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+ (void *)Stat1,
+ (void *)Stat2);
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+ Stat1 = Stat1 << 16 | Stat2;
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+ Stat3 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+ Stat2 = Stat2 << 16 | Stat3;
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+ (void *)Stat1,
+ (void *)Stat2);
+ }
+#endif /* DEBUG */
+
+ if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
+ /*
+ * Workaround BCom Errata:
+ * enable and disable loopback mode if "NO HCD" occurs.
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+ (SK_U16)(Ctrl | PHY_CT_LOOP));
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+ (SK_U16)(Ctrl & ~PHY_CT_LOOP));
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("No HCD Link event, Port %d\n", Port));
+#ifdef xDEBUG
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "No HCD link event, port %d.",
+ (void *)Port,
+ (void *)NULL);
+#endif /* DEBUG */
+ }
+
+ /* Not obsolete: link status bit is latched to 0 and autoclearing! */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+ if (pPrt->PHWLinkUp) {
+ return(SK_HW_PS_NONE);
+ }
+
+#ifdef xDEBUG
+ {
+ SK_U32 Stat1, Stat2, Stat3;
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "CheckUp1a - Stat: %x, Mask: %x",
+ (void *)Isrc,
+ (void *)Stat1);
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+ Stat1 = Stat1 << 16 | PhyStat;
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+ Stat3 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+ Stat2 = Stat2 << 16 | Stat3;
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "Ctrl/Stat: %x, AN Adv/LP: %x",
+ (void *)Stat1,
+ (void *)Stat2);
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+ Stat1 = Stat1 << 16 | Stat2;
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+ Stat3 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+ Stat2 = Stat2 << 16 | ResAb;
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+ (void *)Stat1,
+ (void *)Stat2);
+
+ Stat1 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+ Stat1 = Stat1 << 16 | Stat2;
+ Stat2 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+ Stat3 = 0;
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+ Stat2 = Stat2 << 16 | Stat3;
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+ (void *)Stat1,
+ (void *)Stat2);
+ }
+#endif /* DEBUG */
+
+ /*
+ * Here we usually can check whether the link is in sync and
+ * auto-negotiation is done.
+ */
+
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+ SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat));
+
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+
+ if ((ResAb & PHY_B_1000S_MSF) != 0) {
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Master/Slave Fault port %d\n", Port));
+
+ pPrt->PAutoNegFail = SK_TRUE;
+ pPrt->PMSStatus = SK_MS_STAT_FAULT;
+
+ return(SK_HW_PS_RESTART);
+ }
+
+ if ((PhyStat & PHY_ST_LSYNC) == 0) {
+ return(SK_HW_PS_NONE);
+ }
+
+ pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+ SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Port %d, ResAb: 0x%04X\n", Port, ResAb));
+
+ if (AutoNeg) {
+ if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+
+ SkHWLinkUp(pAC, IoC, Port);
+
+ Done = SkMacAutoNegDone(pAC, IoC, Port);
+
+ if (Done != SK_AND_OK) {
+#ifdef DEBUG
+ /* Get PHY parameters, for debugging only */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb);
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ExtStat);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+ Port, LpAb, ExtStat));
+#endif /* DEBUG */
+ return(SK_HW_PS_RESTART);
+ }
+ else {
+#ifdef xDEBUG
+ /* Dummy read ISR to prevent extra link downs/ups */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+ if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "CheckUp2 - Stat: %x",
+ (void *)ExtStat,
+ (void *)NULL);
+ }
+#endif /* DEBUG */
+ return(SK_HW_PS_LINK);
+ }
+ }
+ }
+ else { /* !AutoNeg */
+ /* Link is up and we don't need more. */
+#ifdef DEBUG
+ if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("ERROR: Lipa auto detected on port %d\n", Port));
+ }
+#endif /* DEBUG */
+
+#ifdef xDEBUG
+ /* Dummy read ISR to prevent extra link downs/ups */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+ if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+ CMSMPrintString(
+ pAC->pConfigTable,
+ MSG_TYPE_RUNTIME_INFO,
+ "CheckUp3 - Stat: %x",
+ (void *)ExtStat,
+ (void *)NULL);
+ }
+#endif /* DEBUG */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link sync(GP), Port %d\n", Port));
+ SkHWLinkUp(pAC, IoC, Port);
+
+ return(SK_HW_PS_LINK);
+ }
+
+ return(SK_HW_PS_NONE);
+} /* SkGePortCheckUpBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ * 2 Link came up
+ */
+static int SkGePortCheckUpGmac(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port, /* Which port should be checked */
+SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ int Done;
+ SK_U16 PhyIsrc; /* PHY Interrupt source */
+ SK_U16 PhyStat; /* PPY Status */
+ SK_U16 PhySpecStat;/* PHY Specific Status */
+ SK_U16 ResAb; /* Master/Slave resolution */
+ SK_EVPARA Para;
+#ifdef DEBUG
+ SK_U16 Word; /* I/O helper */
+#endif /* DEBUG */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PHWLinkUp) {
+ return(SK_HW_PS_NONE);
+ }
+
+ /* Read PHY Status */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat));
+
+ /* Read PHY Interrupt Status */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc);
+
+ if ((PhyIsrc & PHY_M_IS_AN_COMPL) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Auto-Negotiation Completed, PhyIsrc: 0x%04X\n", PhyIsrc));
+ }
+
+ if ((PhyIsrc & PHY_M_IS_LSP_CHANGE) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc));
+ }
+
+ SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+ if ((ResAb & PHY_B_1000S_MSF) != 0) {
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Master/Slave Fault port %d\n", Port));
+
+ pPrt->PAutoNegFail = SK_TRUE;
+ pPrt->PMSStatus = SK_MS_STAT_FAULT;
+
+ return(SK_HW_PS_RESTART);
+ }
+
+ /* Read PHY Specific Status */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Phy1000BT: 0x%04X, PhySpecStat: 0x%04X\n", ResAb, PhySpecStat));
+
+#ifdef DEBUG
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &Word);
+
+ if ((PhyIsrc & PHY_M_IS_AN_PR) != 0 || (Word & PHY_ANE_RX_PG) != 0 ||
+ (PhySpecStat & PHY_M_PS_PAGE_REC) != 0) {
+ /* Read PHY Next Page Link Partner */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_NEPG_LP, &Word);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Page Received, NextPage: 0x%04X\n", Word));
+ }
+#endif /* DEBUG */
+
+ if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
+ return(SK_HW_PS_NONE);
+ }
+
+ if ((PhySpecStat & PHY_M_PS_DOWNS_STAT) != 0 ||
+ (PhyIsrc & PHY_M_IS_DOWNSH_DET) != 0) {
+ /* Downshift detected */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E025, SKERR_SIRQ_E025MSG);
+
+ Para.Para64 = Port;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_DOWNSHIFT_DET, Para);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Downshift detected, PhyIsrc: 0x%04X\n", PhyIsrc));
+ }
+
+ pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+ SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+
+ pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7);
+
+ if (AutoNeg) {
+ /* Auto-Negotiation Over ? */
+ if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+
+ SkHWLinkUp(pAC, IoC, Port);
+
+ Done = SkMacAutoNegDone(pAC, IoC, Port);
+
+ if (Done != SK_AND_OK) {
+ return(SK_HW_PS_RESTART);
+ }
+
+ return(SK_HW_PS_LINK);
+ }
+ }
+ else { /* !AutoNeg */
+ /* Link is up and we don't need more */
+#ifdef DEBUG
+ if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("ERROR: Lipa auto detected on port %d\n", Port));
+ }
+#endif /* DEBUG */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link sync, Port %d\n", Port));
+ SkHWLinkUp(pAC, IoC, Port);
+
+ return(SK_HW_PS_LINK);
+ }
+
+ return(SK_HW_PS_NONE);
+} /* SkGePortCheckUpGmac */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkGePortCheckUpLone() - Check if the link is up on Level One PHY
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ * 2 Link came up
+ */
+static int SkGePortCheckUpLone(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port, /* Which port should be checked */
+SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ int Done;
+ SK_U16 Isrc; /* Interrupt source register */
+ SK_U16 LpAb; /* Link Partner Ability */
+ SK_U16 ExtStat; /* Extended Status Register */
+ SK_U16 PhyStat; /* Phy Status Register */
+ SK_U16 StatSum;
+ SK_U8 NextMode; /* Next AutoSensing Mode */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PHWLinkUp) {
+ return(SK_HW_PS_NONE);
+ }
+
+ StatSum = pPrt->PIsave;
+ pPrt->PIsave = 0;
+
+ /*
+ * here we usually can check whether the link is in sync and
+ * auto-negotiation is done.
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat);
+ StatSum |= PhyStat;
+
+ SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+
+ if ((PhyStat & PHY_ST_LSYNC) == 0) {
+ /* Save Auto-negotiation Done bit */
+ pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER);
+#ifdef DEBUG
+ if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg done rescheduled Port %d\n", Port));
+ }
+#endif /* DEBUG */
+ return(SK_HW_PS_NONE);
+ }
+
+ if (AutoNeg) {
+ if ((StatSum & PHY_ST_AN_OVER) != 0) {
+ SkHWLinkUp(pAC, IoC, Port);
+ Done = SkMacAutoNegDone(pAC, IoC, Port);
+ if (Done != SK_AND_OK) {
+ /* Get PHY parameters, for debugging only */
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb);
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ExtStat);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+ Port, LpAb, ExtStat));
+
+ /* Try next possible mode */
+ NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+ SkHWLinkDown(pAC, IoC, Port);
+ if (Done == SK_AND_DUP_CAP) {
+ /* GoTo next mode */
+ SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+ }
+
+ return(SK_HW_PS_RESTART);
+
+ }
+ else {
+ /*
+ * Dummy Read interrupt status to prevent
+ * extra link down/ups
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+ return(SK_HW_PS_LINK);
+ }
+ }
+
+ /* AutoNeg not done, but HW link is up. Check for timeouts */
+ pPrt->PAutoNegTimeOut++;
+ if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+ /* Timeout occured */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("AutoNeg timeout Port %d\n", Port));
+ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+ pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+ /* Set Link manually up */
+ SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Set manual full duplex Port %d\n", Port));
+ }
+
+ /* Do the restart */
+ return(SK_HW_PS_RESTART);
+ }
+ }
+ else {
+ /* Link is up and we don't need more */
+#ifdef DEBUG
+ if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("ERROR: Lipa auto detected on port %d\n", Port));
+ }
+#endif /* DEBUG */
+
+ /*
+ * Dummy Read interrupt status to prevent
+ * extra link down/ups
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("Link sync(GP), Port %d\n", Port));
+ SkHWLinkUp(pAC, IoC, Port);
+
+ return(SK_HW_PS_LINK);
+ }
+
+ return(SK_HW_PS_NONE);
+} /* SkGePortCheckUpLone */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpNat() - Check if the link is up on National PHY
+ *
+ * return:
+ * 0 o.k. nothing needed
+ * 1 Restart needed on this port
+ * 2 Link came up
+ */
+static int SkGePortCheckUpNat(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO Context */
+int Port, /* Which port should be checked */
+SK_BOOL AutoNeg) /* Is Auto-negotiation used ? */
+{
+ /* todo: National */
+ return(SK_HW_PS_NONE);
+} /* SkGePortCheckUpNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ * SkGeSirqEvent() - Event Service Routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+int SkGeSirqEvent(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* Io Context */
+SK_U32 Event, /* Module specific Event */
+SK_EVPARA Para) /* Event specific Parameter */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ SK_U32 Port;
+ SK_U32 Val32;
+ int PortStat;
+ SK_U8 Val8;
+#ifdef GENESIS
+ SK_U64 Octets;
+#endif /* GENESIS */
+
+ Port = Para.Para32[0];
+ pPrt = &pAC->GIni.GP[Port];
+
+ switch (Event) {
+ case SK_HWEV_WATIM:
+ if (pPrt->PState == SK_PRT_RESET) {
+
+ PortStat = SK_HW_PS_NONE;
+ }
+ else {
+ /* Check whether port came up */
+ PortStat = SkGePortCheckUp(pAC, IoC, (int)Port);
+ }
+
+ switch (PortStat) {
+ case SK_HW_PS_RESTART:
+ if (pPrt->PHWLinkUp) {
+ /* Set Link to down */
+ SkHWLinkDown(pAC, IoC, (int)Port);
+
+ /*
+ * Signal directly to RLMT to ensure correct
+ * sequence of SWITCH and RESET event.
+ */
+ SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ /* Restart needed */
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+ break;
+
+ case SK_HW_PS_LINK:
+ /* Signal to RLMT */
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para);
+ break;
+ }
+
+ /* Start again the check Timer */
+ if (pPrt->PHWLinkUp) {
+ Val32 = SK_WA_ACT_TIME;
+ }
+ else {
+ Val32 = SK_WA_INA_TIME;
+ }
+
+ /* Todo: still needed for non-XMAC PHYs??? */
+ /* Start workaround Errata #2 timer */
+ SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Val32,
+ SKGE_HWAC, SK_HWEV_WATIM, Para);
+ break;
+
+ case SK_HWEV_PORT_START:
+ if (pPrt->PHWLinkUp) {
+ /*
+ * Signal directly to RLMT to ensure correct
+ * sequence of SWITCH and RESET event.
+ */
+ SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ SkHWLinkDown(pAC, IoC, (int)Port);
+
+ /* Schedule Port RESET */
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+
+ /* Start workaround Errata #2 timer */
+ SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+ SKGE_HWAC, SK_HWEV_WATIM, Para);
+ break;
+
+ case SK_HWEV_PORT_STOP:
+ if (pPrt->PHWLinkUp) {
+ /*
+ * Signal directly to RLMT to ensure correct
+ * sequence of SWITCH and RESET event.
+ */
+ SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ /* Stop Workaround Timer */
+ SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
+
+ SkHWLinkDown(pAC, IoC, (int)Port);
+ break;
+
+ case SK_HWEV_UPDATE_STAT:
+ /* We do NOT need to update any statistics */
+ break;
+
+ case SK_HWEV_CLEAR_STAT:
+ /* We do NOT need to clear any statistics */
+ for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) {
+ pPrt->PPrevRx = 0;
+ pPrt->PPrevFcs = 0;
+ pPrt->PPrevShorts = 0;
+ }
+ break;
+
+ case SK_HWEV_SET_LMODE:
+ Val8 = (SK_U8)Para.Para32[1];
+ if (pPrt->PLinkModeConf != Val8) {
+ /* Set New link mode */
+ pPrt->PLinkModeConf = Val8;
+
+ /* Restart Port */
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+ }
+ break;
+
+ case SK_HWEV_SET_FLOWMODE:
+ Val8 = (SK_U8)Para.Para32[1];
+ if (pPrt->PFlowCtrlMode != Val8) {
+ /* Set New Flow Control mode */
+ pPrt->PFlowCtrlMode = Val8;
+
+ /* Restart Port */
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+ }
+ break;
+
+ case SK_HWEV_SET_ROLE:
+ /* not possible for fiber */
+ if (!pAC->GIni.GICopperType) {
+ break;
+ }
+ Val8 = (SK_U8)Para.Para32[1];
+ if (pPrt->PMSMode != Val8) {
+ /* Set New Role (Master/Slave) mode */
+ pPrt->PMSMode = Val8;
+
+ /* Restart Port */
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+ }
+ break;
+
+ case SK_HWEV_SET_SPEED:
+ if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+ break;
+ }
+ Val8 = (SK_U8)Para.Para32[1];
+ if (pPrt->PLinkSpeed != Val8) {
+ /* Set New Speed parameter */
+ pPrt->PLinkSpeed = Val8;
+
+ /* Restart Port */
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+ }
+ break;
+
+#ifdef GENESIS
+ case SK_HWEV_HALFDUP_CHK:
+ if (pAC->GIni.GIGenesis) {
+ /*
+ * half duplex hangup workaround.
+ * See packet arbiter timeout interrupt for description
+ */
+ pPrt->HalfDupTimerActive = SK_FALSE;
+ if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+ pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
+ /* Snap statistic counters */
+ (void)SkXmUpdateStats(pAC, IoC, Port);
+
+ (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_HI, &Val32);
+
+ Octets = (SK_U64)Val32 << 32;
+
+ (void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_LO, &Val32);
+
+ Octets += Val32;
+
+ if (pPrt->LastOctets == Octets) {
+ /* Tx hanging, a FIFO flush restarts it */
+ SkMacFlushTxFifo(pAC, IoC, Port);
+ }
+ }
+ }
+ break;
+#endif /* GENESIS */
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
+ break;
+ }
+
+ return(0);
+} /* SkGeSirqEvent */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkPhyIsrBcom() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from BCom PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrBcom(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* Io Context */
+int Port, /* Port Num = PHY Num */
+SK_U16 IStatus) /* Interrupt Status */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ SK_EVPARA Para;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if ((IStatus & PHY_B_IS_PSE) != 0) {
+ /* Incorrectable pair swap error */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
+ SKERR_SIRQ_E022MSG);
+ }
+
+ if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) {
+
+ SkHWLinkDown(pAC, IoC, Port);
+
+ Para.Para32[0] = (SK_U32)Port;
+ /* Signal to RLMT */
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+ /* Start workaround Errata #2 timer */
+ SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+ SKGE_HWAC, SK_HWEV_WATIM, Para);
+ }
+
+} /* SkPhyIsrBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkPhyIsrGmac() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from Marvell PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrGmac(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* Io Context */
+int Port, /* Port Num = PHY Num */
+SK_U16 IStatus) /* Interrupt Status */
+{
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+ SK_EVPARA Para;
+ SK_U16 Word;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) {
+
+ SkHWLinkDown(pAC, IoC, Port);
+
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &Word);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg.Adv: 0x%04X\n", Word));
+
+ /* Set Auto-negotiation advertisement */
+ if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) {
+ /* restore Asymmetric Pause bit */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV,
+ (SK_U16)(Word | PHY_M_AN_ASP));
+ }
+
+ Para.Para32[0] = (SK_U32)Port;
+ /* Signal to RLMT */
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+ if ((IStatus & PHY_M_IS_AN_ERROR) != 0) {
+ /* Auto-Negotiation Error */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG);
+ }
+
+ if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) {
+ /* FIFO Overflow/Underrun Error */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG);
+ }
+
+} /* SkPhyIsrGmac */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkPhyIsrLone() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from LONE PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrLone(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* Io Context */
+int Port, /* Port Num = PHY Num */
+SK_U16 IStatus) /* Interrupt Status */
+{
+ SK_EVPARA Para;
+
+ if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
+
+ SkHWLinkDown(pAC, IoC, Port);
+
+ Para.Para32[0] = (SK_U32)Port;
+ /* Signal to RLMT */
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+ }
+
+} /* SkPhyIsrLone */
+#endif /* OTHER_PHY */
+
+/* End of File */
diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c
new file mode 100644
index 000000000000..79bf57cb5326
--- /dev/null
+++ b/drivers/net/sk98lin/ski2c.c
@@ -0,0 +1,1296 @@
+/******************************************************************************
+ *
+ * Name: ski2c.c
+ * Project: Gigabit Ethernet Adapters, TWSI-Module
+ * Version: $Revision: 1.59 $
+ * Date: $Date: 2003/10/20 09:07:25 $
+ * Purpose: Functions to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * I2C Protocol
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: ski2c.c,v 1.59 2003/10/20 09:07:25 rschmidt Exp $ (C) Marvell. ";
+#endif
+
+#include "h/skdrv1st.h" /* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+ I2C protocol implementation.
+
+ General Description:
+
+ The I2C protocol is used for the temperature sensors and for
+ the serial EEPROM which hold the configuration.
+
+ This file covers functions that allow to read write and do
+ some bulk requests a specified I2C address.
+
+ The Genesis has 2 I2C buses. One for the EEPROM which holds
+ the VPD Data and one for temperature and voltage sensor.
+ The following picture shows the I2C buses, I2C devices and
+ their control registers.
+
+ Note: The VPD functions are in skvpd.c
+.
+. PCI Config I2C Bus for VPD Data:
+.
+. +------------+
+. | VPD EEPROM |
+. +------------+
+. |
+. | <-- I2C
+. |
+. +-----------+-----------+
+. | |
+. +-----------------+ +-----------------+
+. | PCI_VPD_ADR_REG | | PCI_VPD_DAT_REG |
+. +-----------------+ +-----------------+
+.
+.
+. I2C Bus for LM80 sensor:
+.
+. +-----------------+
+. | Temperature and |
+. | Voltage Sensor |
+. | LM80 |
+. +-----------------+
+. |
+. |
+. I2C --> |
+. |
+. +----+
+. +-------------->| OR |<--+
+. | +----+ |
+. +------+------+ |
+. | | |
+. +--------+ +--------+ +----------+
+. | B2_I2C | | B2_I2C | | B2_I2C |
+. | _CTRL | | _DATA | | _SW |
+. +--------+ +--------+ +----------+
+.
+ The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL
+ and B2_I2C_DATA registers.
+ For driver software it is recommended to use the I2C control and
+ data register, because I2C bus timing is done by the ASIC and
+ an interrupt may be received when the I2C request is completed.
+
+ Clock Rate Timing: MIN MAX generated by
+ VPD EEPROM: 50 kHz 100 kHz HW
+ LM80 over I2C Ctrl/Data reg. 50 kHz 100 kHz HW
+ LM80 over B2_I2C_SW register 0 400 kHz SW
+
+ Note: The clock generated by the hardware is dependend on the
+ PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD
+ clock is 50 kHz.
+ */
+intro()
+{}
+#endif
+
+#ifdef SK_DIAG
+/*
+ * I2C Fast Mode timing values used by the LM80.
+ * If new devices are added to the I2C bus the timing values have to be checked.
+ */
+#ifndef I2C_SLOW_TIMING
+#define T_CLK_LOW 1300L /* clock low time in ns */
+#define T_CLK_HIGH 600L /* clock high time in ns */
+#define T_DATA_IN_SETUP 100L /* data in Set-up Time */
+#define T_START_HOLD 600L /* start condition hold time */
+#define T_START_SETUP 600L /* start condition Set-up time */
+#define T_STOP_SETUP 600L /* stop condition Set-up time */
+#define T_BUS_IDLE 1300L /* time the bus must free after Tx */
+#define T_CLK_2_DATA_OUT 900L /* max. clock low to data output valid */
+#else /* I2C_SLOW_TIMING */
+/* I2C Standard Mode Timing */
+#define T_CLK_LOW 4700L /* clock low time in ns */
+#define T_CLK_HIGH 4000L /* clock high time in ns */
+#define T_DATA_IN_SETUP 250L /* data in Set-up Time */
+#define T_START_HOLD 4000L /* start condition hold time */
+#define T_START_SETUP 4700L /* start condition Set-up time */
+#define T_STOP_SETUP 4000L /* stop condition Set-up time */
+#define T_BUS_IDLE 4700L /* time the bus must free after Tx */
+#endif /* !I2C_SLOW_TIMING */
+
+#define NS2BCLK(x) (((x)*125)/10000)
+
+/*
+ * I2C Wire Operations
+ *
+ * About I2C_CLK_LOW():
+ *
+ * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting
+ * clock to low, to prevent the ASIC and the I2C data client from driving the
+ * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client
+ * send an 'ACK'). See also Concentrator Bugreport No. 10192.
+ */
+#define I2C_DATA_HIGH(IoC) SK_I2C_SET_BIT(IoC, I2C_DATA)
+#define I2C_DATA_LOW(IoC) SK_I2C_CLR_BIT(IoC, I2C_DATA)
+#define I2C_DATA_OUT(IoC) SK_I2C_SET_BIT(IoC, I2C_DATA_DIR)
+#define I2C_DATA_IN(IoC) SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA)
+#define I2C_CLK_HIGH(IoC) SK_I2C_SET_BIT(IoC, I2C_CLK)
+#define I2C_CLK_LOW(IoC) SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR)
+#define I2C_START_COND(IoC) SK_I2C_CLR_BIT(IoC, I2C_CLK)
+
+#define NS2CLKT(x) ((x*125L)/10000)
+
+/*--------------- I2C Interface Register Functions --------------- */
+
+/*
+ * sending one bit
+ */
+void SkI2cSndBit(
+SK_IOC IoC, /* I/O Context */
+SK_U8 Bit) /* Bit to send */
+{
+ I2C_DATA_OUT(IoC);
+ if (Bit) {
+ I2C_DATA_HIGH(IoC);
+ }
+ else {
+ I2C_DATA_LOW(IoC);
+ }
+ SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP));
+ I2C_CLK_HIGH(IoC);
+ SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+ I2C_CLK_LOW(IoC);
+} /* SkI2cSndBit*/
+
+
+/*
+ * Signal a start to the I2C Bus.
+ *
+ * A start is signaled when data goes to low in a high clock cycle.
+ *
+ * Ends with Clock Low.
+ *
+ * Status: not tested
+ */
+void SkI2cStart(
+SK_IOC IoC) /* I/O Context */
+{
+ /* Init data and Clock to output lines */
+ /* Set Data high */
+ I2C_DATA_OUT(IoC);
+ I2C_DATA_HIGH(IoC);
+ /* Set Clock high */
+ I2C_CLK_HIGH(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP));
+
+ /* Set Data Low */
+ I2C_DATA_LOW(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD));
+
+ /* Clock low without Data to Input */
+ I2C_START_COND(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW));
+} /* SkI2cStart */
+
+
+void SkI2cStop(
+SK_IOC IoC) /* I/O Context */
+{
+ /* Init data and Clock to output lines */
+ /* Set Data low */
+ I2C_DATA_OUT(IoC);
+ I2C_DATA_LOW(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+ /* Set Clock high */
+ I2C_CLK_HIGH(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP));
+
+ /*
+ * Set Data High: Do it by setting the Data Line to Input.
+ * Because of a pull up resistor the Data Line
+ * floods to high.
+ */
+ I2C_DATA_IN(IoC);
+
+ /*
+ * When I2C activity is stopped
+ * o DATA should be set to input and
+ * o CLOCK should be set to high!
+ */
+ SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE));
+} /* SkI2cStop */
+
+
+/*
+ * Receive just one bit via the I2C bus.
+ *
+ * Note: Clock must be set to LOW before calling this function.
+ *
+ * Returns The received bit.
+ */
+int SkI2cRcvBit(
+SK_IOC IoC) /* I/O Context */
+{
+ int Bit;
+ SK_U8 I2cSwCtrl;
+
+ /* Init data as input line */
+ I2C_DATA_IN(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+ I2C_CLK_HIGH(IoC);
+
+ SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+
+ SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+
+ Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0;
+
+ I2C_CLK_LOW(IoC);
+ SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT));
+
+ return(Bit);
+} /* SkI2cRcvBit */
+
+
+/*
+ * Receive an ACK.
+ *
+ * returns 0 If acknowledged
+ * 1 in case of an error
+ */
+int SkI2cRcvAck(
+SK_IOC IoC) /* I/O Context */
+{
+ /*
+ * Received bit must be zero.
+ */
+ return(SkI2cRcvBit(IoC) != 0);
+} /* SkI2cRcvAck */
+
+
+/*
+ * Send an NACK.
+ */
+void SkI2cSndNAck(
+SK_IOC IoC) /* I/O Context */
+{
+ /*
+ * Received bit must be zero.
+ */
+ SkI2cSndBit(IoC, 1);
+} /* SkI2cSndNAck */
+
+
+/*
+ * Send an ACK.
+ */
+void SkI2cSndAck(
+SK_IOC IoC) /* I/O Context */
+{
+ /*
+ * Received bit must be zero.
+ */
+ SkI2cSndBit(IoC, 0);
+} /* SkI2cSndAck */
+
+
+/*
+ * Send one byte to the I2C device and wait for ACK.
+ *
+ * Return acknowleged status.
+ */
+int SkI2cSndByte(
+SK_IOC IoC, /* I/O Context */
+int Byte) /* byte to send */
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (Byte & (1<<(7-i))) {
+ SkI2cSndBit(IoC, 1);
+ }
+ else {
+ SkI2cSndBit(IoC, 0);
+ }
+ }
+
+ return(SkI2cRcvAck(IoC));
+} /* SkI2cSndByte */
+
+
+/*
+ * Receive one byte and ack it.
+ *
+ * Return byte.
+ */
+int SkI2cRcvByte(
+SK_IOC IoC, /* I/O Context */
+int Last) /* Last Byte Flag */
+{
+ int i;
+ int Byte = 0;
+
+ for (i = 0; i < 8; i++) {
+ Byte <<= 1;
+ Byte |= SkI2cRcvBit(IoC);
+ }
+
+ if (Last) {
+ SkI2cSndNAck(IoC);
+ }
+ else {
+ SkI2cSndAck(IoC);
+ }
+
+ return(Byte);
+} /* SkI2cRcvByte */
+
+
+/*
+ * Start dialog and send device address
+ *
+ * Return 0 if acknowleged, 1 in case of an error
+ */
+int SkI2cSndDev(
+SK_IOC IoC, /* I/O Context */
+int Addr, /* Device Address */
+int Rw) /* Read / Write Flag */
+{
+ SkI2cStart(IoC);
+ Rw = ~Rw;
+ Rw &= I2C_WRITE;
+ return(SkI2cSndByte(IoC, (Addr<<1) | Rw));
+} /* SkI2cSndDev */
+
+#endif /* SK_DIAG */
+
+/*----------------- I2C CTRL Register Functions ----------*/
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * returns 0: success, transfer completes
+ * 1: error, transfer does not complete, I2C transfer
+ * killed, wait loop terminated.
+ */
+static int SkI2cWait(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Event) /* complete event to wait for (I2C_READ or I2C_WRITE) */
+{
+ SK_U64 StartTime;
+ SK_U64 CurrentTime;
+ SK_U32 I2cCtrl;
+
+ StartTime = SkOsGetTime(pAC);
+
+ do {
+ CurrentTime = SkOsGetTime(pAC);
+
+ if (CurrentTime - StartTime > SK_TICKS_PER_SEC / 8) {
+
+ SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG);
+#endif /* !SK_DIAG */
+ return(1);
+ }
+
+ SK_I2C_GET_CTL(IoC, &I2cCtrl);
+
+#ifdef xYUKON_DBG
+ printf("StartTime=%lu, CurrentTime=%lu\n",
+ StartTime, CurrentTime);
+ if (kbhit()) {
+ return(1);
+ }
+#endif /* YUKON_DBG */
+
+ } while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31);
+
+ return(0);
+} /* SkI2cWait */
+
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * Returns
+ * Nothing
+ */
+void SkI2cWaitIrq(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC) /* I/O Context */
+{
+ SK_SENSOR *pSen;
+ SK_U64 StartTime;
+ SK_U32 IrqSrc;
+
+ pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+
+ if (pSen->SenState == SK_SEN_IDLE) {
+ return;
+ }
+
+ StartTime = SkOsGetTime(pAC);
+
+ do {
+ if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) {
+
+ SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG);
+#endif /* !SK_DIAG */
+ return;
+ }
+
+ SK_IN32(IoC, B0_ISRC, &IrqSrc);
+
+ } while ((IrqSrc & IS_I2C_READY) == 0);
+
+ pSen->SenState = SK_SEN_IDLE;
+ return;
+} /* SkI2cWaitIrq */
+
+/*
+ * writes a single byte or 4 bytes into the I2C device
+ *
+ * returns 0: success
+ * 1: error
+ */
+static int SkI2cWrite(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 I2cData, /* I2C Data to write */
+int I2cDev, /* I2C Device Address */
+int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */
+int I2cReg, /* I2C Device Register Address */
+int I2cBurst) /* I2C Burst Flag */
+{
+ SK_OUT32(IoC, B2_I2C_DATA, I2cData);
+
+ SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cDevSize, I2cReg, I2cBurst);
+
+ return(SkI2cWait(pAC, IoC, I2C_WRITE));
+} /* SkI2cWrite*/
+
+
+#ifdef SK_DIAG
+/*
+ * reads a single byte or 4 bytes from the I2C device
+ *
+ * returns the word read
+ */
+SK_U32 SkI2cRead(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int I2cDev, /* I2C Device Address */
+int I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */
+int I2cReg, /* I2C Device Register Address */
+int I2cBurst) /* I2C Burst Flag */
+{
+ SK_U32 Data;
+
+ SK_OUT32(IoC, B2_I2C_DATA, 0);
+ SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cDevSize, I2cReg, I2cBurst);
+
+ if (SkI2cWait(pAC, IoC, I2C_READ) != 0) {
+ w_print("%s\n", SKERR_I2C_E002MSG);
+ }
+
+ SK_IN32(IoC, B2_I2C_DATA, &Data);
+
+ return(Data);
+} /* SkI2cRead */
+#endif /* SK_DIAG */
+
+
+/*
+ * read a sensor's value
+ *
+ * This function reads a sensor's value from the I2C sensor chip. The sensor
+ * is defined by its index into the sensors database in the struct pAC points
+ * to.
+ * Returns
+ * 1 if the read is completed
+ * 0 if the read must be continued (I2C Bus still allocated)
+ */
+static int SkI2cReadSensor(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_SENSOR *pSen) /* Sensor to be read */
+{
+ if (pSen->SenRead != NULL) {
+ return((*pSen->SenRead)(pAC, IoC, pSen));
+ }
+ else {
+ return(0); /* no success */
+ }
+} /* SkI2cReadSensor */
+
+/*
+ * Do the Init state 0 initialization
+ */
+static int SkI2cInit0(
+SK_AC *pAC) /* Adapter Context */
+{
+ int i;
+
+ /* Begin with first sensor */
+ pAC->I2c.CurrSens = 0;
+
+ /* Begin with timeout control for state machine */
+ pAC->I2c.TimerMode = SK_TIMER_WATCH_SM;
+
+ /* Set sensor number to zero */
+ pAC->I2c.MaxSens = 0;
+
+#ifndef SK_DIAG
+ /* Initialize Number of Dummy Reads */
+ pAC->I2c.DummyReads = SK_MAX_SENSORS;
+#endif
+
+ for (i = 0; i < SK_MAX_SENSORS; i++) {
+ pAC->I2c.SenTable[i].SenDesc = "unknown";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN;
+ pAC->I2c.SenTable[i].SenThreErrHigh = 0;
+ pAC->I2c.SenTable[i].SenThreErrLow = 0;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = 0;
+ pAC->I2c.SenTable[i].SenThreWarnLow = 0;
+ pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+ pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE;
+ pAC->I2c.SenTable[i].SenValue = 0;
+ pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT;
+ pAC->I2c.SenTable[i].SenErrCts = 0;
+ pAC->I2c.SenTable[i].SenBegErrTS = 0;
+ pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+ pAC->I2c.SenTable[i].SenRead = NULL;
+ pAC->I2c.SenTable[i].SenDev = 0;
+ }
+
+ /* Now we are "INIT data"ed */
+ pAC->I2c.InitLevel = SK_INIT_DATA;
+ return(0);
+} /* SkI2cInit0*/
+
+
+/*
+ * Do the init state 1 initialization
+ *
+ * initialize the following register of the LM80:
+ * Configuration register:
+ * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT
+ *
+ * Interrupt Mask Register 1:
+ * - all interrupts are Disabled (0xff)
+ *
+ * Interrupt Mask Register 2:
+ * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter.
+ *
+ * Fan Divisor/RST_OUT register:
+ * - Divisors set to 1 (bits 00), all others 0s.
+ *
+ * OS# Configuration/Temperature resolution Register:
+ * - all 0s
+ *
+ */
+static int SkI2cInit1(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC) /* I/O Context */
+{
+ int i;
+ SK_U8 I2cSwCtrl;
+ SK_GEPORT *pPrt; /* GIni Port struct pointer */
+
+ if (pAC->I2c.InitLevel != SK_INIT_DATA) {
+ /* ReInit not needed in I2C module */
+ return(0);
+ }
+
+ /* Set the Direction of I2C-Data Pin to IN */
+ SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA);
+ /* Check for 32-Bit Yukon with Low at I2C-Data Pin */
+ SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+
+ if ((I2cSwCtrl & I2C_DATA) == 0) {
+ /* this is a 32-Bit board */
+ pAC->GIni.GIYukon32Bit = SK_TRUE;
+ return(0);
+ }
+
+ /* Check for 64 Bit Yukon without sensors */
+ if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_CFG, 0) != 0) {
+ return(0);
+ }
+
+ (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_1, 0);
+
+ (void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_2, 0);
+
+ (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_FAN_CTRL, 0);
+
+ (void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
+
+ (void)SkI2cWrite(pAC, IoC, (SK_U32)LM80_CFG_START, LM80_ADDR, I2C_025K_DEV,
+ LM80_CFG, 0);
+
+ /*
+ * MaxSens has to be updated here, because PhyType is not
+ * set when performing Init Level 0
+ */
+ pAC->I2c.MaxSens = 5;
+
+ pPrt = &pAC->GIni.GP[0];
+
+ if (pAC->GIni.GIGenesis) {
+ if (pPrt->PhyType == SK_PHY_BCOM) {
+ if (pAC->GIni.GIMacsFound == 1) {
+ pAC->I2c.MaxSens += 1;
+ }
+ else {
+ pAC->I2c.MaxSens += 3;
+ }
+ }
+ }
+ else {
+ pAC->I2c.MaxSens += 3;
+ }
+
+ for (i = 0; i < pAC->I2c.MaxSens; i++) {
+ switch (i) {
+ case 0:
+ pAC->I2c.SenTable[i].SenDesc = "Temperature";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
+ break;
+ case 1:
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
+ break;
+ case 2:
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
+ pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO;
+ break;
+ case 3:
+ pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
+ break;
+ case 4:
+ if (pAC->GIni.GIGenesis) {
+ if (pPrt->PhyType == SK_PHY_BCOM) {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL";
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+ }
+ else {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+ }
+ }
+ else {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX";
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN;
+ if (pAC->GIni.GIVauxAvail) {
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+ }
+ else {
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR;
+ }
+ }
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
+ break;
+ case 5:
+ if (pAC->GIni.GIGenesis) {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+ }
+ else {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage Core 1V5";
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR;
+ }
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
+ break;
+ case 6:
+ if (pAC->GIni.GIGenesis) {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
+ }
+ else {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3";
+ }
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
+ break;
+ case 7:
+ if (pAC->GIni.GIGenesis) {
+ pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+ }
+ else {
+ pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+ pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+ pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+ pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+ pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+ pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+ pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN;
+ }
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
+ SKERR_I2C_E001, SKERR_I2C_E001MSG);
+ break;
+ }
+
+ pAC->I2c.SenTable[i].SenValue = 0;
+ pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+ pAC->I2c.SenTable[i].SenErrCts = 0;
+ pAC->I2c.SenTable[i].SenBegErrTS = 0;
+ pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+ pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
+ pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+ }
+
+#ifndef SK_DIAG
+ pAC->I2c.DummyReads = pAC->I2c.MaxSens;
+#endif /* !SK_DIAG */
+
+ /* Clear I2C IRQ */
+ SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+
+ /* Now we are I/O initialized */
+ pAC->I2c.InitLevel = SK_INIT_IO;
+ return(0);
+} /* SkI2cInit1 */
+
+
+/*
+ * Init level 2: Start first sensor read.
+ */
+static int SkI2cInit2(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC) /* I/O Context */
+{
+ int ReadComplete;
+ SK_SENSOR *pSen;
+
+ if (pAC->I2c.InitLevel != SK_INIT_IO) {
+ /* ReInit not needed in I2C module */
+ /* Init0 and Init2 not permitted */
+ return(0);
+ }
+
+ pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+ ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+ if (ReadComplete) {
+ SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG);
+ }
+
+ /* Now we are correctly initialized */
+ pAC->I2c.InitLevel = SK_INIT_RUN;
+
+ return(0);
+} /* SkI2cInit2*/
+
+
+/*
+ * Initialize I2C devices
+ *
+ * Get the first voltage value and discard it.
+ * Go into temperature read mode. A default pointer is not set.
+ *
+ * The things to be done depend on the init level in the parameter list:
+ * Level 0:
+ * Initialize only the data structures. Do NOT access hardware.
+ * Level 1:
+ * Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts.
+ * Level 2:
+ * Everything is possible. Interrupts may be used from now on.
+ *
+ * return:
+ * 0 = success
+ * other = error.
+ */
+int SkI2cInit(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context needed in levels 1 and 2 */
+int Level) /* Init Level */
+{
+
+ switch (Level) {
+ case SK_INIT_DATA:
+ return(SkI2cInit0(pAC));
+ case SK_INIT_IO:
+ return(SkI2cInit1(pAC, IoC));
+ case SK_INIT_RUN:
+ return(SkI2cInit2(pAC, IoC));
+ default:
+ break;
+ }
+
+ return(0);
+} /* SkI2cInit */
+
+
+#ifndef SK_DIAG
+
+/*
+ * Interrupt service function for the I2C Interface
+ *
+ * Clears the Interrupt source
+ *
+ * Reads the register and check it for sending a trap.
+ *
+ * Starts the timer if necessary.
+ */
+void SkI2cIsr(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC) /* I/O Context */
+{
+ SK_EVPARA Para;
+
+ /* Clear I2C IRQ */
+ SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+
+ Para.Para64 = 0;
+ SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para);
+} /* SkI2cIsr */
+
+
+/*
+ * Check this sensors Value against the threshold and send events.
+ */
+static void SkI2cCheckSensor(
+SK_AC *pAC, /* Adapter Context */
+SK_SENSOR *pSen)
+{
+ SK_EVPARA ParaLocal;
+ SK_BOOL TooHigh; /* Is sensor too high? */
+ SK_BOOL TooLow; /* Is sensor too low? */
+ SK_U64 CurrTime; /* Current Time */
+ SK_BOOL DoTrapSend; /* We need to send a trap */
+ SK_BOOL DoErrLog; /* We need to log the error */
+ SK_BOOL IsError; /* We need to log the error */
+
+ /* Check Dummy Reads first */
+ if (pAC->I2c.DummyReads > 0) {
+ pAC->I2c.DummyReads--;
+ return;
+ }
+
+ /* Get the current time */
+ CurrTime = SkOsGetTime(pAC);
+
+ /* Set para to the most useful setting: The current sensor. */
+ ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens;
+
+ /* Check the Value against the thresholds. First: Error Thresholds */
+ TooHigh = (pSen->SenValue > pSen->SenThreErrHigh);
+ TooLow = (pSen->SenValue < pSen->SenThreErrLow);
+
+ IsError = SK_FALSE;
+ if (TooHigh || TooLow) {
+ /* Error condition is satisfied */
+ DoTrapSend = SK_TRUE;
+ DoErrLog = SK_TRUE;
+
+ /* Now error condition is satisfied */
+ IsError = SK_TRUE;
+
+ if (pSen->SenErrFlag == SK_SEN_ERR_ERR) {
+ /* This state is the former one */
+
+ /* So check first whether we have to send a trap */
+ if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD >
+ CurrTime) {
+ /*
+ * Do NOT send the Trap. The hold back time
+ * has to run out first.
+ */
+ DoTrapSend = SK_FALSE;
+ }
+
+ /* Check now whether we have to log an Error */
+ if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD >
+ CurrTime) {
+ /*
+ * Do NOT log the error. The hold back time
+ * has to run out first.
+ */
+ DoErrLog = SK_FALSE;
+ }
+ }
+ else {
+ /* We came from a different state -> Set Begin Time Stamp */
+ pSen->SenBegErrTS = CurrTime;
+ pSen->SenErrFlag = SK_SEN_ERR_ERR;
+ }
+
+ if (DoTrapSend) {
+ /* Set current Time */
+ pSen->SenLastErrTrapTS = CurrTime;
+ pSen->SenErrCts++;
+
+ /* Queue PNMI Event */
+ SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+ SK_PNMI_EVT_SEN_ERR_UPP :
+ SK_PNMI_EVT_SEN_ERR_LOW),
+ ParaLocal);
+ }
+
+ if (DoErrLog) {
+ /* Set current Time */
+ pSen->SenLastErrLogTS = CurrTime;
+
+ if (pSen->SenType == SK_SEN_TEMP) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, SKERR_I2C_E011MSG);
+ }
+ else if (pSen->SenType == SK_SEN_VOLT) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, SKERR_I2C_E012MSG);
+ }
+ else {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, SKERR_I2C_E015MSG);
+ }
+ }
+ }
+
+ /* Check the Value against the thresholds */
+ /* 2nd: Warning thresholds */
+ TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh);
+ TooLow = (pSen->SenValue < pSen->SenThreWarnLow);
+
+ if (!IsError && (TooHigh || TooLow)) {
+ /* Error condition is satisfied */
+ DoTrapSend = SK_TRUE;
+ DoErrLog = SK_TRUE;
+
+ if (pSen->SenErrFlag == SK_SEN_ERR_WARN) {
+ /* This state is the former one */
+
+ /* So check first whether we have to send a trap */
+ if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > CurrTime) {
+ /*
+ * Do NOT send the Trap. The hold back time
+ * has to run out first.
+ */
+ DoTrapSend = SK_FALSE;
+ }
+
+ /* Check now whether we have to log an Error */
+ if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > CurrTime) {
+ /*
+ * Do NOT log the error. The hold back time
+ * has to run out first.
+ */
+ DoErrLog = SK_FALSE;
+ }
+ }
+ else {
+ /* We came from a different state -> Set Begin Time Stamp */
+ pSen->SenBegWarnTS = CurrTime;
+ pSen->SenErrFlag = SK_SEN_ERR_WARN;
+ }
+
+ if (DoTrapSend) {
+ /* Set current Time */
+ pSen->SenLastWarnTrapTS = CurrTime;
+ pSen->SenWarnCts++;
+
+ /* Queue PNMI Event */
+ SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+ SK_PNMI_EVT_SEN_WAR_UPP :
+ SK_PNMI_EVT_SEN_WAR_LOW),
+ ParaLocal);
+ }
+
+ if (DoErrLog) {
+ /* Set current Time */
+ pSen->SenLastWarnLogTS = CurrTime;
+
+ if (pSen->SenType == SK_SEN_TEMP) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG);
+ }
+ else if (pSen->SenType == SK_SEN_VOLT) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, SKERR_I2C_E010MSG);
+ }
+ else {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, SKERR_I2C_E014MSG);
+ }
+ }
+ }
+
+ /* Check for NO error at all */
+ if (!IsError && !TooHigh && !TooLow) {
+ /* Set o.k. Status if no error and no warning condition */
+ pSen->SenErrFlag = SK_SEN_ERR_OK;
+ }
+
+ /* End of check against the thresholds */
+
+ /* Bug fix AF: 16.Aug.2001: Correct the init base
+ * of LM80 sensor.
+ */
+ if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) {
+
+ pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+ if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) {
+ /* 5V PCI-IO Voltage */
+ pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN;
+ pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR;
+ }
+ else {
+ /* 3.3V PCI-IO Voltage */
+ pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN;
+ pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR;
+ }
+ }
+
+#ifdef TEST_ONLY
+ /* Dynamic thresholds also for VAUX of LM80 sensor */
+ if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) {
+
+ pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+ /* 3.3V VAUX Voltage */
+ if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) {
+ pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+ pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+ }
+ /* 0V VAUX Voltage */
+ else {
+ pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR;
+ pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR;
+ }
+ }
+
+ /*
+ * Check initialization state:
+ * The VIO Thresholds need adaption
+ */
+ if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+ pSen->SenValue > SK_SEN_WARNLOW2C &&
+ pSen->SenValue < SK_SEN_WARNHIGH2) {
+ pSen->SenThreErrLow = SK_SEN_ERRLOW2C;
+ pSen->SenThreWarnLow = SK_SEN_WARNLOW2C;
+ pSen->SenInit = SK_TRUE;
+ }
+
+ if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+ pSen->SenValue > SK_SEN_WARNLOW2 &&
+ pSen->SenValue < SK_SEN_WARNHIGH2C) {
+ pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C;
+ pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C;
+ pSen->SenInit = SK_TRUE;
+ }
+#endif
+
+ if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) {
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG);
+ }
+} /* SkI2cCheckSensor */
+
+
+/*
+ * The only Event to be served is the timeout event
+ *
+ */
+int SkI2cEvent(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Event, /* Module specific Event */
+SK_EVPARA Para) /* Event specific Parameter */
+{
+ int ReadComplete;
+ SK_SENSOR *pSen;
+ SK_U32 Time;
+ SK_EVPARA ParaLocal;
+ int i;
+
+ /* New case: no sensors */
+ if (pAC->I2c.MaxSens == 0) {
+ return(0);
+ }
+
+ switch (Event) {
+ case SK_I2CEV_IRQ:
+ pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+ ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+ if (ReadComplete) {
+ /* Check sensor against defined thresholds */
+ SkI2cCheckSensor(pAC, pSen);
+
+ /* Increment Current sensor and set appropriate Timeout */
+ pAC->I2c.CurrSens++;
+ if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) {
+ pAC->I2c.CurrSens = 0;
+ Time = SK_I2C_TIM_LONG;
+ }
+ else {
+ Time = SK_I2C_TIM_SHORT;
+ }
+
+ /* Start Timer */
+ ParaLocal.Para64 = (SK_U64)0;
+
+ pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+ SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+ SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+ }
+ else {
+ /* Start Timer */
+ ParaLocal.Para64 = (SK_U64)0;
+
+ pAC->I2c.TimerMode = SK_TIMER_WATCH_SM;
+
+ SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH,
+ SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+ }
+ break;
+ case SK_I2CEV_TIM:
+ if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) {
+
+ ParaLocal.Para64 = (SK_U64)0;
+ SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer);
+
+ pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+ ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+ if (ReadComplete) {
+ /* Check sensor against defined thresholds */
+ SkI2cCheckSensor(pAC, pSen);
+
+ /* Increment Current sensor and set appropriate Timeout */
+ pAC->I2c.CurrSens++;
+ if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+ pAC->I2c.CurrSens = 0;
+ Time = SK_I2C_TIM_LONG;
+ }
+ else {
+ Time = SK_I2C_TIM_SHORT;
+ }
+
+ /* Start Timer */
+ ParaLocal.Para64 = (SK_U64)0;
+
+ pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+ SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+ SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+ }
+ }
+ else {
+ pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+ pSen->SenErrFlag = SK_SEN_ERR_FAULTY;
+ SK_I2C_STOP(IoC);
+
+ /* Increment Current sensor and set appropriate Timeout */
+ pAC->I2c.CurrSens++;
+ if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+ pAC->I2c.CurrSens = 0;
+ Time = SK_I2C_TIM_LONG;
+ }
+ else {
+ Time = SK_I2C_TIM_SHORT;
+ }
+
+ /* Start Timer */
+ ParaLocal.Para64 = (SK_U64)0;
+
+ pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+ SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+ SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+ }
+ break;
+ case SK_I2CEV_CLEAR:
+ for (i = 0; i < SK_MAX_SENSORS; i++) {
+ pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+ pAC->I2c.SenTable[i].SenErrCts = 0;
+ pAC->I2c.SenTable[i].SenWarnCts = 0;
+ pAC->I2c.SenTable[i].SenBegErrTS = 0;
+ pAC->I2c.SenTable[i].SenBegWarnTS = 0;
+ pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0;
+ pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0;
+ pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0;
+ pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0;
+ }
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG);
+ }
+
+ return(0);
+} /* SkI2cEvent*/
+
+#endif /* !SK_DIAG */
diff --git a/drivers/net/sk98lin/sklm80.c b/drivers/net/sk98lin/sklm80.c
new file mode 100644
index 000000000000..a204f5bb55d4
--- /dev/null
+++ b/drivers/net/sk98lin/sklm80.c
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * Name: sklm80.c
+ * Project: Gigabit Ethernet Adapters, TWSI-Module
+ * Version: $Revision: 1.22 $
+ * Date: $Date: 2003/10/20 09:08:21 $
+ * Purpose: Functions to access Voltage and Temperature Sensor (LM80)
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ LM80 functions
+*/
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. ";
+#endif
+
+#include "h/skdrv1st.h" /* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
+
+#define BREAK_OR_WAIT(pAC,IoC,Event) break
+
+/*
+ * read a sensors value (LM80 specific)
+ *
+ * This function reads a sensors value from the I2C sensor chip LM80.
+ * The sensor is defined by its index into the sensors database in the struct
+ * pAC points to.
+ *
+ * Returns 1 if the read is completed
+ * 0 if the read must be continued (I2C Bus still allocated)
+ */
+int SkLm80ReadSensor(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context needed in level 1 and 2 */
+SK_SENSOR *pSen) /* Sensor to be read */
+{
+ SK_I32 Value;
+
+ switch (pSen->SenState) {
+ case SK_SEN_IDLE:
+ /* Send address to ADDR register */
+ SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0);
+
+ pSen->SenState = SK_SEN_VALUE ;
+ BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+
+ case SK_SEN_VALUE:
+ /* Read value from data register */
+ SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+
+ Value &= 0xff; /* only least significant byte is valid */
+
+ /* Do NOT check the Value against the thresholds */
+ /* Checking is done in the calling instance */
+
+ if (pSen->SenType == SK_SEN_VOLT) {
+ /* Voltage sensor */
+ pSen->SenValue = Value * SK_LM80_VT_LSB;
+ pSen->SenState = SK_SEN_IDLE ;
+ return(1);
+ }
+
+ if (pSen->SenType == SK_SEN_FAN) {
+ if (Value != 0 && Value != 0xff) {
+ /* Fan speed counter */
+ pSen->SenValue = SK_LM80_FAN_FAKTOR/Value;
+ }
+ else {
+ /* Indicate Fan error */
+ pSen->SenValue = 0;
+ }
+ pSen->SenState = SK_SEN_IDLE ;
+ return(1);
+ }
+
+ /* First: correct the value: it might be negative */
+ if ((Value & 0x80) != 0) {
+ /* Value is negative */
+ Value = Value - 256;
+ }
+
+ /* We have a temperature sensor and need to get the signed extension.
+ * For now we get the extension from the last reading, so in the normal
+ * case we won't see flickering temperatures.
+ */
+ pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
+ (pSen->SenValue % SK_LM80_TEMP_LSB);
+
+ /* Send address to ADDR register */
+ SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
+
+ pSen->SenState = SK_SEN_VALEXT ;
+ BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+
+ case SK_SEN_VALEXT:
+ /* Read value from data register */
+ SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+ Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
+
+ /* cut the LSB bit */
+ pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
+ SK_LM80_TEMP_LSB);
+
+ if (pSen->SenValue < 0) {
+ /* Value negative: The bit value must be subtracted */
+ pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+ }
+ else {
+ /* Value positive: The bit value must be added */
+ pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+ }
+
+ pSen->SenState = SK_SEN_IDLE ;
+ return(1);
+
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG);
+ return(1);
+ }
+
+ /* Not completed */
+ return(0);
+}
+
diff --git a/drivers/net/sk98lin/skqueue.c b/drivers/net/sk98lin/skqueue.c
new file mode 100644
index 000000000000..0275b4f71d9b
--- /dev/null
+++ b/drivers/net/sk98lin/skqueue.c
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Name: skqueue.c
+ * Project: Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version: $Revision: 1.20 $
+ * Date: $Date: 2003/09/16 13:44:00 $
+ * Purpose: Management of an event queue.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+ * Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skqueue.c,v 1.20 2003/09/16 13:44:00 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h" /* Driver Specific Definitions */
+#include "h/skqueue.h" /* Queue Definitions */
+#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+ Event queue management.
+
+ General Description:
+
+ */
+intro()
+{}
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ *
+ * Must be called during init level 0.
+ */
+void SkEventInit(
+SK_AC *pAC, /* Adapter context */
+SK_IOC Ioc, /* IO context */
+int Level) /* Init level */
+{
+ switch (Level) {
+ case SK_INIT_DATA:
+ pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * add event to queue
+ */
+void SkEventQueue(
+SK_AC *pAC, /* Adapters context */
+SK_U32 Class, /* Event Class */
+SK_U32 Event, /* Event to be queued */
+SK_EVPARA Para) /* Event parameter */
+{
+ pAC->Event.EvPut->Class = Class;
+ pAC->Event.EvPut->Event = Event;
+ pAC->Event.EvPut->Para = Para;
+
+ if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT])
+ pAC->Event.EvPut = pAC->Event.EvQueue;
+
+ if (pAC->Event.EvPut == pAC->Event.EvGet) {
+ SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG);
+ }
+}
+
+/*
+ * event dispatcher
+ * while event queue is not empty
+ * get event from queue
+ * send command to state machine
+ * end
+ * return error reported by individual Event function
+ * 0 if no error occured.
+ */
+int SkEventDispatcher(
+SK_AC *pAC, /* Adapters Context */
+SK_IOC Ioc) /* Io context */
+{
+ SK_EVENTELEM *pEv; /* pointer into queue */
+ SK_U32 Class;
+ int Rtv;
+
+ pEv = pAC->Event.EvGet;
+
+ PRINTF("dispatch get %x put %x\n", pEv, pAC->Event.ev_put);
+
+ while (pEv != pAC->Event.EvPut) {
+ PRINTF("dispatch Class %d Event %d\n", pEv->Class, pEv->Event);
+
+ switch (Class = pEv->Class) {
+#ifndef SK_USE_LAC_EV
+#ifndef SK_SLIM
+ case SKGE_RLMT: /* RLMT Event */
+ Rtv = SkRlmtEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+ case SKGE_I2C: /* I2C Event */
+ Rtv = SkI2cEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+ case SKGE_PNMI: /* PNMI Event */
+ Rtv = SkPnmiEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+#endif /* not SK_SLIM */
+#endif /* not SK_USE_LAC_EV */
+ case SKGE_DRV: /* Driver Event */
+ Rtv = SkDrvEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+#ifndef SK_USE_SW_TIMER
+ case SKGE_HWAC:
+ Rtv = SkGeSirqEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+#else /* !SK_USE_SW_TIMER */
+ case SKGE_SWT :
+ Rtv = SkSwtEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+#endif /* !SK_USE_SW_TIMER */
+#ifdef SK_USE_LAC_EV
+ case SKGE_LACP :
+ Rtv = SkLacpEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+ case SKGE_RSF :
+ Rtv = SkRsfEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+ case SKGE_MARKER :
+ Rtv = SkMarkerEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+ case SKGE_FD :
+ Rtv = SkFdEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+#endif /* SK_USE_LAC_EV */
+#ifdef SK_USE_CSUM
+ case SKGE_CSUM :
+ Rtv = SkCsEvent(pAC, Ioc, pEv->Event, pEv->Para);
+ break;
+#endif /* SK_USE_CSUM */
+ default :
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, SKERR_Q_E002MSG);
+ Rtv = 0;
+ }
+
+ if (Rtv != 0) {
+ return(Rtv);
+ }
+
+ if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT])
+ pEv = pAC->Event.EvQueue;
+
+ /* Renew get: it is used in queue_events to detect overruns */
+ pAC->Event.EvGet = pEv;
+ }
+
+ return(0);
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c
new file mode 100644
index 000000000000..be8d1ccddf6d
--- /dev/null
+++ b/drivers/net/sk98lin/skrlmt.c
@@ -0,0 +1,3257 @@
+/******************************************************************************
+ *
+ * Name: skrlmt.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.69 $
+ * Date: $Date: 2003/04/15 09:39:22 $
+ * Purpose: Manage links on SK-NET Adapters, esp. redundant ones.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters.
+ * It is mainly intended for adapters with more than one link.
+ * For such adapters, this module realizes Redundant Link ManagemenT (RLMT).
+ *
+ * Include File Hierarchy:
+ *
+ * "skdrv1st.h"
+ * "skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef lint
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skrlmt.c,v 1.69 2003/04/15 09:39:22 tschilli Exp $ (C) Marvell.";
+#endif /* !defined(lint) */
+
+#define __SKRLMT_C
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+#ifndef SK_HWAC_LINK_LED
+#define SK_HWAC_LINK_LED(a,b,c,d)
+#endif /* !defined(SK_HWAC_LINK_LED) */
+
+#ifndef DEBUG
+#define RLMT_STATIC static
+#else /* DEBUG */
+#define RLMT_STATIC
+
+#ifndef SK_LITTLE_ENDIAN
+/* First 32 bits */
+#define OFFS_LO32 1
+
+/* Second 32 bits */
+#define OFFS_HI32 0
+#else /* SK_LITTLE_ENDIAN */
+/* First 32 bits */
+#define OFFS_LO32 0
+
+/* Second 32 bits */
+#define OFFS_HI32 1
+#endif /* SK_LITTLE_ENDIAN */
+
+#endif /* DEBUG */
+
+/* ----- Private timeout values ----- */
+
+#define SK_RLMT_MIN_TO_VAL 125000 /* 1/8 sec. */
+#define SK_RLMT_DEF_TO_VAL 1000000 /* 1 sec. */
+#define SK_RLMT_PORTDOWN_TIM_VAL 900000 /* another 0.9 sec. */
+#define SK_RLMT_PORTSTART_TIM_VAL 100000 /* 0.1 sec. */
+#define SK_RLMT_PORTUP_TIM_VAL 2500000 /* 2.5 sec. */
+#define SK_RLMT_SEG_TO_VAL 900000000 /* 15 min. */
+
+/* Assume tick counter increment is 1 - may be set OS-dependent. */
+#ifndef SK_TICK_INCR
+#define SK_TICK_INCR SK_CONSTU64(1)
+#endif /* !defined(SK_TICK_INCR) */
+
+/*
+ * Amount that a time stamp must be later to be recognized as "substantially
+ * later". This is about 1/128 sec, but above 1 tick counter increment.
+ */
+#define SK_RLMT_BC_DELTA (1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \
+ (SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR))
+
+/* ----- Private RLMT defaults ----- */
+
+#define SK_RLMT_DEF_PREF_PORT 0 /* "Lower" port. */
+#define SK_RLMT_DEF_MODE SK_RLMT_CHECK_LINK /* Default RLMT Mode. */
+
+/* ----- Private RLMT checking states ----- */
+
+#define SK_RLMT_RCS_SEG 1 /* RLMT Check State: check seg. */
+#define SK_RLMT_RCS_START_SEG 2 /* RLMT Check State: start check seg. */
+#define SK_RLMT_RCS_SEND_SEG 4 /* RLMT Check State: send BPDU packet */
+#define SK_RLMT_RCS_REPORT_SEG 8 /* RLMT Check State: report seg. */
+
+/* ----- Private PORT checking states ----- */
+
+#define SK_RLMT_PCS_TX 1 /* Port Check State: check tx. */
+#define SK_RLMT_PCS_RX 2 /* Port Check State: check rx. */
+
+/* ----- Private PORT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_PORTSTART_TIM 1100 /* Port start timeout. */
+#define SK_RLMT_PORTUP_TIM 1101 /* Port can now go up. */
+#define SK_RLMT_PORTDOWN_RX_TIM 1102 /* Port did not receive once ... */
+#define SK_RLMT_PORTDOWN 1103 /* Port went down. */
+#define SK_RLMT_PORTDOWN_TX_TIM 1104 /* Partner did not receive ... */
+
+/* ----- Private RLMT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_TIM 2100 /* RLMT timeout. */
+#define SK_RLMT_SEG_TIM 2101 /* RLMT segmentation check timeout. */
+
+#define TO_SHORTEN(tim) ((tim) / 2)
+
+/* Error numbers and messages. */
+#define SKERR_RLMT_E001 (SK_ERRBASE_RLMT + 0)
+#define SKERR_RLMT_E001_MSG "No Packet."
+#define SKERR_RLMT_E002 (SKERR_RLMT_E001 + 1)
+#define SKERR_RLMT_E002_MSG "Short Packet."
+#define SKERR_RLMT_E003 (SKERR_RLMT_E002 + 1)
+#define SKERR_RLMT_E003_MSG "Unknown RLMT event."
+#define SKERR_RLMT_E004 (SKERR_RLMT_E003 + 1)
+#define SKERR_RLMT_E004_MSG "PortsUp incorrect."
+#define SKERR_RLMT_E005 (SKERR_RLMT_E004 + 1)
+#define SKERR_RLMT_E005_MSG \
+ "Net seems to be segmented (different root bridges are reported on the ports)."
+#define SKERR_RLMT_E006 (SKERR_RLMT_E005 + 1)
+#define SKERR_RLMT_E006_MSG "Duplicate MAC Address detected."
+#define SKERR_RLMT_E007 (SKERR_RLMT_E006 + 1)
+#define SKERR_RLMT_E007_MSG "LinksUp incorrect."
+#define SKERR_RLMT_E008 (SKERR_RLMT_E007 + 1)
+#define SKERR_RLMT_E008_MSG "Port not started but link came up."
+#define SKERR_RLMT_E009 (SKERR_RLMT_E008 + 1)
+#define SKERR_RLMT_E009_MSG "Corrected illegal setting of Preferred Port."
+#define SKERR_RLMT_E010 (SKERR_RLMT_E009 + 1)
+#define SKERR_RLMT_E010_MSG "Ignored illegal Preferred Port."
+
+/* LLC field values. */
+#define LLC_COMMAND_RESPONSE_BIT 1
+#define LLC_TEST_COMMAND 0xE3
+#define LLC_UI 0x03
+
+/* RLMT Packet fields. */
+#define SK_RLMT_DSAP 0
+#define SK_RLMT_SSAP 0
+#define SK_RLMT_CTRL (LLC_TEST_COMMAND)
+#define SK_RLMT_INDICATOR0 0x53 /* S */
+#define SK_RLMT_INDICATOR1 0x4B /* K */
+#define SK_RLMT_INDICATOR2 0x2D /* - */
+#define SK_RLMT_INDICATOR3 0x52 /* R */
+#define SK_RLMT_INDICATOR4 0x4C /* L */
+#define SK_RLMT_INDICATOR5 0x4D /* M */
+#define SK_RLMT_INDICATOR6 0x54 /* T */
+#define SK_RLMT_PACKET_VERSION 0
+
+/* RLMT SPT Flag values. */
+#define SK_RLMT_SPT_FLAG_CHANGE 0x01
+#define SK_RLMT_SPT_FLAG_CHANGE_ACK 0x80
+
+/* RLMT SPT Packet fields. */
+#define SK_RLMT_SPT_DSAP 0x42
+#define SK_RLMT_SPT_SSAP 0x42
+#define SK_RLMT_SPT_CTRL (LLC_UI)
+#define SK_RLMT_SPT_PROTOCOL_ID0 0x00
+#define SK_RLMT_SPT_PROTOCOL_ID1 0x00
+#define SK_RLMT_SPT_PROTOCOL_VERSION_ID 0x00
+#define SK_RLMT_SPT_BPDU_TYPE 0x00
+#define SK_RLMT_SPT_FLAGS 0x00 /* ?? */
+#define SK_RLMT_SPT_ROOT_ID0 0xFF /* Lowest possible priority. */
+#define SK_RLMT_SPT_ROOT_ID1 0xFF /* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define SK_RLMT_SPT_ROOT_PATH_COST0 0x00
+#define SK_RLMT_SPT_ROOT_PATH_COST1 0x00
+#define SK_RLMT_SPT_ROOT_PATH_COST2 0x00
+#define SK_RLMT_SPT_ROOT_PATH_COST3 0x00
+#define SK_RLMT_SPT_BRIDGE_ID0 0xFF /* Lowest possible priority. */
+#define SK_RLMT_SPT_BRIDGE_ID1 0xFF /* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define SK_RLMT_SPT_PORT_ID0 0xFF /* Lowest possible priority. */
+#define SK_RLMT_SPT_PORT_ID1 0xFF /* Lowest possible priority. */
+#define SK_RLMT_SPT_MSG_AGE0 0x00
+#define SK_RLMT_SPT_MSG_AGE1 0x00
+#define SK_RLMT_SPT_MAX_AGE0 0x00
+#define SK_RLMT_SPT_MAX_AGE1 0xFF
+#define SK_RLMT_SPT_HELLO_TIME0 0x00
+#define SK_RLMT_SPT_HELLO_TIME1 0xFF
+#define SK_RLMT_SPT_FWD_DELAY0 0x00
+#define SK_RLMT_SPT_FWD_DELAY1 0x40
+
+/* Size defines. */
+#define SK_RLMT_MIN_PACKET_SIZE 34
+#define SK_RLMT_MAX_PACKET_SIZE (SK_RLMT_MAX_TX_BUF_SIZE)
+#define SK_PACKET_DATA_LEN (SK_RLMT_MAX_PACKET_SIZE - \
+ SK_RLMT_MIN_PACKET_SIZE)
+
+/* ----- RLMT packet types ----- */
+#define SK_PACKET_ANNOUNCE 1 /* Port announcement. */
+#define SK_PACKET_ALIVE 2 /* Alive packet to port. */
+#define SK_PACKET_ADDR_CHANGED 3 /* Port address changed. */
+#define SK_PACKET_CHECK_TX 4 /* Check your tx line. */
+
+#ifdef SK_LITTLE_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
+ SK_U8 *_Addr = (SK_U8*)(Addr); \
+ SK_U16 _Val = (SK_U16)(Val); \
+ *_Addr++ = (SK_U8)(_Val >> 8); \
+ *_Addr = (SK_U8)(_Val & 0xFF); \
+}
+#endif /* SK_LITTLE_ENDIAN */
+
+#ifdef SK_BIG_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val))
+#endif /* SK_BIG_ENDIAN */
+
+#define AUTONEG_FAILED SK_FALSE
+#define AUTONEG_SUCCESS SK_TRUE
+
+
+/* typedefs *******************************************************************/
+
+/* RLMT packet. Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
+typedef struct s_RlmtPacket {
+ SK_U8 DstAddr[SK_MAC_ADDR_LEN];
+ SK_U8 SrcAddr[SK_MAC_ADDR_LEN];
+ SK_U8 TypeLen[2];
+ SK_U8 DSap;
+ SK_U8 SSap;
+ SK_U8 Ctrl;
+ SK_U8 Indicator[7];
+ SK_U8 RlmtPacketType[2];
+ SK_U8 Align1[2];
+ SK_U8 Random[4]; /* Random value of requesting(!) station. */
+ SK_U8 RlmtPacketVersion[2]; /* RLMT Packet version. */
+ SK_U8 Data[SK_PACKET_DATA_LEN];
+} SK_RLMT_PACKET;
+
+typedef struct s_SpTreeRlmtPacket {
+ SK_U8 DstAddr[SK_MAC_ADDR_LEN];
+ SK_U8 SrcAddr[SK_MAC_ADDR_LEN];
+ SK_U8 TypeLen[2];
+ SK_U8 DSap;
+ SK_U8 SSap;
+ SK_U8 Ctrl;
+ SK_U8 ProtocolId[2];
+ SK_U8 ProtocolVersionId;
+ SK_U8 BpduType;
+ SK_U8 Flags;
+ SK_U8 RootId[8];
+ SK_U8 RootPathCost[4];
+ SK_U8 BridgeId[8];
+ SK_U8 PortId[2];
+ SK_U8 MessageAge[2];
+ SK_U8 MaxAge[2];
+ SK_U8 HelloTime[2];
+ SK_U8 ForwardDelay[2];
+} SK_SPTREE_PACKET;
+
+/* global variables ***********************************************************/
+
+SK_MAC_ADDR SkRlmtMcAddr = {{0x01, 0x00, 0x5A, 0x52, 0x4C, 0x4D}};
+SK_MAC_ADDR BridgeMcAddr = {{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}};
+
+/* local variables ************************************************************/
+
+/* None. */
+
+/* functions ******************************************************************/
+
+RLMT_STATIC void SkRlmtCheckSwitch(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 NetIdx);
+RLMT_STATIC void SkRlmtCheckSeg(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_U32 NetIdx);
+RLMT_STATIC void SkRlmtEvtSetNets(
+ SK_AC *pAC,
+ SK_IOC IoC,
+ SK_EVPARA Para);
+
+/******************************************************************************
+ *
+ * SkRlmtInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ * SK_INIT_DATA
+ * ============
+ *
+ * This routine initializes all RLMT-related variables to a known state.
+ * The initial state is SK_RLMT_RS_INIT.
+ * All ports are initialized to SK_RLMT_PS_INIT.
+ *
+ *
+ * SK_INIT_IO
+ * ==========
+ *
+ * Nothing.
+ *
+ *
+ * SK_INIT_RUN
+ * ===========
+ *
+ * Determine the adapter's random value.
+ * Set the hw registers, the "logical MAC address", the
+ * RLMT multicast address, and eventually the BPDU multicast address.
+ *
+ * Context:
+ * init, pageable
+ *
+ * Returns:
+ * Nothing.
+ */
+void SkRlmtInit(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Level) /* Initialization Level */
+{
+ SK_U32 i, j;
+ SK_U64 Random;
+ SK_EVPARA Para;
+ SK_MAC_ADDR VirtualMacAddress;
+ SK_MAC_ADDR PhysicalAMacAddress;
+ SK_BOOL VirtualMacAddressSet;
+ SK_BOOL PhysicalAMacAddressSet;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+ ("RLMT Init level %d.\n", Level))
+
+ switch (Level) {
+ case SK_INIT_DATA: /* Initialize data structures. */
+ SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT));
+
+ for (i = 0; i < SK_MAX_MACS; i++) {
+ pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
+ pAC->Rlmt.Port[i].LinkDown = SK_TRUE;
+ pAC->Rlmt.Port[i].PortDown = SK_TRUE;
+ pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
+ pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
+ pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
+ pAC->Rlmt.Port[i].PortNumber = i;
+ pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0];
+ pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i];
+ }
+
+ pAC->Rlmt.NumNets = 1;
+ for (i = 0; i < SK_MAX_NETS; i++) {
+ pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+ pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+ pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+ pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* Automatic. */
+ /* Just assuming. */
+ pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+ pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+ pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+ pAC->Rlmt.Net[i].NetNumber = i;
+ }
+
+ pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0];
+ pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1];
+#if SK_MAX_NETS > 1
+ pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1];
+#endif /* SK_MAX_NETS > 1 */
+ break;
+
+ case SK_INIT_IO: /* GIMacsFound first available here. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+ ("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound))
+
+ pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+ /* Initialize HW registers? */
+ if (pAC->GIni.GIMacsFound == 1) {
+ Para.Para32[0] = SK_RLMT_MODE_CLS;
+ Para.Para32[1] = 0;
+ (void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
+ }
+ break;
+
+ case SK_INIT_RUN:
+ /* Ensure RLMT is set to one net. */
+ if (pAC->Rlmt.NumNets > 1) {
+ Para.Para32[0] = 1;
+ Para.Para32[1] = -1;
+ SkRlmtEvtSetNets(pAC, IoC, Para);
+ }
+
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ Random = SkOsGetTime(pAC);
+ *(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
+
+ for (j = 0; j < 4; j++) {
+ pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort->
+ CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j];
+ }
+
+ (void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+ /* Add RLMT MC address. */
+ (void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+ if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) {
+ /* Add BPDU MC address. */
+ (void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT);
+ }
+
+ (void)SkAddrMcUpdate(pAC, IoC, i);
+ }
+
+ VirtualMacAddressSet = SK_FALSE;
+ /* Read virtual MAC address from Control Register File. */
+ for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+
+ SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]);
+ VirtualMacAddressSet |= VirtualMacAddress.a[j];
+ }
+
+ PhysicalAMacAddressSet = SK_FALSE;
+ /* Read physical MAC address for MAC A from Control Register File. */
+ for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+
+ SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]);
+ PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j];
+ }
+
+ /* check if the two mac addresses contain reasonable values */
+ if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) {
+
+ pAC->Rlmt.RlmtOff = SK_TRUE;
+ }
+
+ /* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD
+ and the RLMT_LOOKAHEAD macros */
+ else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) {
+
+ pAC->Rlmt.RlmtOff = SK_TRUE;
+ }
+ else {
+ pAC->Rlmt.RlmtOff = SK_FALSE;
+ }
+ break;
+
+ default: /* error */
+ break;
+ }
+ return;
+} /* SkRlmtInit */
+
+
+/******************************************************************************
+ *
+ * SkRlmtBuildCheckChain - build the check chain
+ *
+ * Description:
+ * This routine builds the local check chain:
+ * - Each port that is up checks the next port.
+ * - The last port that is up checks the first port that is up.
+ *
+ * Notes:
+ * - Currently only local ports are considered when building the chain.
+ * - Currently the SuspectState is just reset;
+ * it would be better to save it ...
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtBuildCheckChain(
+SK_AC *pAC, /* Adapter Context */
+SK_U32 NetIdx) /* Net Number */
+{
+ SK_U32 i;
+ SK_U32 NumMacsUp;
+ SK_RLMT_PORT * FirstMacUp;
+ SK_RLMT_PORT * PrevMacUp;
+
+ FirstMacUp = NULL;
+ PrevMacUp = NULL;
+
+ if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+ for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) {
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+ }
+ return; /* Done. */
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SkRlmtBuildCheckChain.\n"))
+
+ NumMacsUp = 0;
+
+ for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0;
+ pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &=
+ ~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
+
+ /*
+ * If more than two links are detected we should consider
+ * checking at least two other ports:
+ * 1. the next port that is not LinkDown and
+ * 2. the next port that is not PortDown.
+ */
+ if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+ if (NumMacsUp == 0) {
+ FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+ }
+ else {
+ PrevMacUp->PortCheck[
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
+ pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
+ PrevMacUp->PortCheck[
+ PrevMacUp->PortsChecked].SuspectTx = SK_FALSE;
+ PrevMacUp->PortsChecked++;
+ }
+ PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+ NumMacsUp++;
+ }
+ }
+
+ if (NumMacsUp > 1) {
+ PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr =
+ FirstMacUp->AddrPort->CurrentMacAddress;
+ PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx =
+ SK_FALSE;
+ PrevMacUp->PortsChecked++;
+ }
+
+#ifdef DEBUG
+ for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Port %d checks %d other ports: %2X.\n", i,
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
+ }
+#endif /* DEBUG */
+
+ return;
+} /* SkRlmtBuildCheckChain */
+
+
+/******************************************************************************
+ *
+ * SkRlmtBuildPacket - build an RLMT packet
+ *
+ * Description:
+ * This routine sets up an RLMT packet.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF *SkRlmtBuildPacket(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 PortNumber, /* Sending port */
+SK_U16 PacketType, /* RLMT packet type */
+SK_MAC_ADDR *SrcAddr, /* Source address */
+SK_MAC_ADDR *DestAddr) /* Destination address */
+{
+ int i;
+ SK_U16 Length;
+ SK_MBUF *pMb;
+ SK_RLMT_PACKET *pPacket;
+
+#ifdef DEBUG
+ SK_U8 CheckSrc = 0;
+ SK_U8 CheckDest = 0;
+
+ for (i = 0; i < SK_MAC_ADDR_LEN; ++i) {
+ CheckSrc |= SrcAddr->a[i];
+ CheckDest |= DestAddr->a[i];
+ }
+
+ if ((CheckSrc == 0) || (CheckDest == 0)) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR,
+ ("SkRlmtBuildPacket: Invalid %s%saddr.\n",
+ (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : "")))
+ }
+#endif
+
+ if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) {
+ pPacket = (SK_RLMT_PACKET*)pMb->pData;
+ for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+ pPacket->DstAddr[i] = DestAddr->a[i];
+ pPacket->SrcAddr[i] = SrcAddr->a[i];
+ }
+ pPacket->DSap = SK_RLMT_DSAP;
+ pPacket->SSap = SK_RLMT_SSAP;
+ pPacket->Ctrl = SK_RLMT_CTRL;
+ pPacket->Indicator[0] = SK_RLMT_INDICATOR0;
+ pPacket->Indicator[1] = SK_RLMT_INDICATOR1;
+ pPacket->Indicator[2] = SK_RLMT_INDICATOR2;
+ pPacket->Indicator[3] = SK_RLMT_INDICATOR3;
+ pPacket->Indicator[4] = SK_RLMT_INDICATOR4;
+ pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
+ pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
+
+ SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]);
+
+ for (i = 0; i < 4; i++) {
+ pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i];
+ }
+
+ SK_U16_TO_NETWORK_ORDER(
+ SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]);
+
+ for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
+ pPacket->Data[i] = 0x00;
+ }
+
+ Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */
+ pMb->Length = Length;
+ pMb->PortIdx = PortNumber;
+ Length -= 14;
+ SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
+
+ if (PacketType == SK_PACKET_ALIVE) {
+ pAC->Rlmt.Port[PortNumber].TxHelloCts++;
+ }
+ }
+
+ return (pMb);
+} /* SkRlmtBuildPacket */
+
+
+/******************************************************************************
+ *
+ * SkRlmtBuildSpanningTreePacket - build spanning tree check packet
+ *
+ * Description:
+ * This routine sets up a BPDU packet for spanning tree check.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF *SkRlmtBuildSpanningTreePacket(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 PortNumber) /* Sending port */
+{
+ unsigned i;
+ SK_U16 Length;
+ SK_MBUF *pMb;
+ SK_SPTREE_PACKET *pSPacket;
+
+ if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
+ NULL) {
+ pSPacket = (SK_SPTREE_PACKET*)pMb->pData;
+ for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+ pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
+ pSPacket->SrcAddr[i] =
+ pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+ }
+ pSPacket->DSap = SK_RLMT_SPT_DSAP;
+ pSPacket->SSap = SK_RLMT_SPT_SSAP;
+ pSPacket->Ctrl = SK_RLMT_SPT_CTRL;
+
+ pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0;
+ pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1;
+ pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID;
+ pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE;
+ pSPacket->Flags = SK_RLMT_SPT_FLAGS;
+ pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0;
+ pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1;
+ pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0;
+ pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1;
+ pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2;
+ pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3;
+ pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0;
+ pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
+
+ /*
+ * Use logical MAC address as bridge ID and filter these packets
+ * on receive.
+ */
+ for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+ pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
+ pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber].
+ CurrentMacAddress.a[i];
+ }
+ pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
+ pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
+ pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0;
+ pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1;
+ pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0;
+ pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1;
+ pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0;
+ pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1;
+ pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0;
+ pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1;
+
+ Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */
+ pMb->Length = Length;
+ pMb->PortIdx = PortNumber;
+ Length -= 14;
+ SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
+
+ pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++;
+ }
+
+ return (pMb);
+} /* SkRlmtBuildSpanningTreePacket */
+
+
+/******************************************************************************
+ *
+ * SkRlmtSend - build and send check packets
+ *
+ * Description:
+ * Depending on the RLMT state and the checking state, several packets
+ * are sent through the indicated port.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing.
+ */
+RLMT_STATIC void SkRlmtSend(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 PortNumber) /* Sending port */
+{
+ unsigned j;
+ SK_EVPARA Para;
+ SK_RLMT_PORT *pRPort;
+
+ pRPort = &pAC->Rlmt.Port[PortNumber];
+ if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+ if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
+ /* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */
+ if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+ SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+ &SkRlmtMcAddr)) != NULL) {
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ }
+ }
+ else {
+ /*
+ * Send a directed RLMT packet to all ports that are
+ * checked by the indicated port.
+ */
+ for (j = 0; j < pRPort->PortsChecked; j++) {
+ if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+ SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+ &pRPort->PortCheck[j].CheckAddr)) != NULL) {
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ }
+ }
+ }
+ }
+
+ if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+ (pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) {
+ /*
+ * Send a BPDU packet to make a connected switch tell us
+ * the correct root bridge.
+ */
+ if ((Para.pParaPtr =
+ SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) {
+ pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
+ pRPort->RootIdSet = SK_FALSE;
+
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX,
+ ("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber))
+ }
+ }
+ return;
+} /* SkRlmtSend */
+
+
+/******************************************************************************
+ *
+ * SkRlmtPortReceives - check if port is (going) down and bring it up
+ *
+ * Description:
+ * This routine checks if a port who received a non-BPDU packet
+ * needs to go up or needs to be stopped going down.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing.
+ */
+RLMT_STATIC void SkRlmtPortReceives(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 PortNumber) /* Port to check */
+{
+ SK_RLMT_PORT *pRPort;
+ SK_EVPARA Para;
+
+ pRPort = &pAC->Rlmt.Port[PortNumber];
+ pRPort->PortNoRx = SK_FALSE;
+
+ if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+ !(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
+ /*
+ * Port is marked down (rx), but received a non-BPDU packet.
+ * Bring it up.
+ */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Received on PortDown.\n"))
+
+ pRPort->PortState = SK_RLMT_PS_GOING_UP;
+ pRPort->GuTimeStamp = SkOsGetTime(pAC);
+ Para.Para32[0] = PortNumber;
+ Para.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+ SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para);
+ pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+ /* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+ } /* PortDown && !SuspectTx */
+ else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Stop bringing port down.\n"))
+ SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+ pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+ /* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+ } /* PortGoingDown */
+
+ return;
+} /* SkRlmtPortReceives */
+
+
+/******************************************************************************
+ *
+ * SkRlmtPacketReceive - receive a packet for closer examination
+ *
+ * Description:
+ * This routine examines a packet more closely than SK_RLMT_LOOKAHEAD.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing.
+ */
+RLMT_STATIC void SkRlmtPacketReceive(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_MBUF *pMb) /* Received packet */
+{
+#ifdef xDEBUG
+ extern void DumpData(char *p, int size);
+#endif /* DEBUG */
+ int i;
+ unsigned j;
+ SK_U16 PacketType;
+ SK_U32 PortNumber;
+ SK_ADDR_PORT *pAPort;
+ SK_RLMT_PORT *pRPort;
+ SK_RLMT_PACKET *pRPacket;
+ SK_SPTREE_PACKET *pSPacket;
+ SK_EVPARA Para;
+
+ PortNumber = pMb->PortIdx;
+ pAPort = &pAC->Addr.Port[PortNumber];
+ pRPort = &pAC->Rlmt.Port[PortNumber];
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber))
+
+ pRPacket = (SK_RLMT_PACKET*)pMb->pData;
+ pSPacket = (SK_SPTREE_PACKET*)pRPacket;
+
+#ifdef xDEBUG
+ DumpData((char *)pRPacket, 32);
+#endif /* DEBUG */
+
+ if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
+ SkRlmtPortReceives(pAC, IoC, PortNumber);
+ }
+
+ /* Check destination address. */
+
+ if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) &&
+ !SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
+ !SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
+
+ /* Not sent to current MAC or registered MC address => Trash it. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Not for me.\n"))
+
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ return;
+ }
+ else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) {
+
+ /*
+ * Was sent by same port (may happen during port switching
+ * or in case of duplicate MAC addresses).
+ */
+
+ /*
+ * Check for duplicate address here:
+ * If Packet.Random != My.Random => DupAddr.
+ */
+ for (i = 3; i >= 0; i--) {
+ if (pRPort->Random[i] != pRPacket->Random[i]) {
+ break;
+ }
+ }
+
+ /*
+ * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply
+ * packets (they have the LLC_COMMAND_RESPONSE_BIT set in
+ * pRPacket->SSap).
+ */
+ if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
+ pRPacket->Ctrl == SK_RLMT_CTRL &&
+ pRPacket->SSap == SK_RLMT_SSAP &&
+ pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+ pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+ pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+ pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+ pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+ pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+ pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
+
+ /* Error Log entry. */
+ SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG);
+ }
+ else {
+ /* Simply trash it. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Sent by me.\n"))
+ }
+
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ return;
+ }
+
+ /* Check SuspectTx entries. */
+ if (pRPort->PortsSuspect > 0) {
+ for (j = 0; j < pRPort->PortsChecked; j++) {
+ if (pRPort->PortCheck[j].SuspectTx &&
+ SK_ADDR_EQUAL(
+ pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) {
+ pRPort->PortCheck[j].SuspectTx = SK_FALSE;
+ pRPort->PortsSuspect--;
+ break;
+ }
+ }
+ }
+
+ /* Determine type of packet. */
+ if (pRPacket->DSap == SK_RLMT_DSAP &&
+ pRPacket->Ctrl == SK_RLMT_CTRL &&
+ (pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
+ pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+ pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+ pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+ pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+ pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+ pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+ pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+
+ /* It's an RLMT packet. */
+ PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
+ pRPacket->RlmtPacketType[1]);
+
+ switch (PacketType) {
+ case SK_PACKET_ANNOUNCE: /* Not yet used. */
+#if 0
+ /* Build the check chain. */
+ SkRlmtBuildCheckChain(pAC);
+#endif /* 0 */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Announce.\n"))
+
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ break;
+
+ case SK_PACKET_ALIVE:
+ if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Alive Reply.\n"))
+
+ if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) ||
+ SK_ADDR_EQUAL(
+ pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) {
+ /* Obviously we could send something. */
+ if (pRPort->CheckingState & SK_RLMT_PCS_TX) {
+ pRPort->CheckingState &= ~SK_RLMT_PCS_TX;
+ SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+ }
+
+ if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+ !(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+ pRPort->PortState = SK_RLMT_PS_GOING_UP;
+ pRPort->GuTimeStamp = SkOsGetTime(pAC);
+
+ SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+ Para.Para32[0] = PortNumber;
+ Para.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->UpTimer,
+ SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT,
+ SK_RLMT_PORTUP_TIM, Para);
+ }
+ }
+
+ /* Mark sending port as alive? */
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ }
+ else { /* Alive Request Packet. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Alive Request.\n"))
+
+ pRPort->RxHelloCts++;
+
+ /* Answer. */
+ for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+ pRPacket->DstAddr[i] = pRPacket->SrcAddr[i];
+ pRPacket->SrcAddr[i] =
+ pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+ }
+ pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
+
+ Para.pParaPtr = pMb;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ }
+ break;
+
+ case SK_PACKET_CHECK_TX:
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Check your tx line.\n"))
+
+ /* A port checking us requests us to check our tx line. */
+ pRPort->CheckingState |= SK_RLMT_PCS_TX;
+
+ /* Start PortDownTx timer. */
+ Para.Para32[0] = PortNumber;
+ Para.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->DownTxTimer,
+ SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+ SK_RLMT_PORTDOWN_TX_TIM, Para);
+
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+ if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+ SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+ &SkRlmtMcAddr)) != NULL) {
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ }
+ break;
+
+ case SK_PACKET_ADDR_CHANGED:
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Address Change.\n"))
+
+ /* Build the check chain. */
+ SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ break;
+
+ default:
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
+
+ /* RA;:;: ??? */
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ }
+ }
+ else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
+ pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
+ (pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: BPDU Packet.\n"))
+
+ /* Spanning Tree packet. */
+ pRPort->RxSpHelloCts++;
+
+ if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt.
+ Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) {
+ /*
+ * Check segmentation if a new root bridge is set and
+ * the segmentation check is not currently running.
+ */
+ if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) &&
+ (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+ (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG)
+ != 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+ SK_RLMT_RCS_SEG) == 0) {
+ pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+ SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+ }
+
+ /* Store tree view of this port. */
+ for (i = 0; i < 8; i++) {
+ pRPort->Root.Id[i] = pSPacket->RootId[i];
+ }
+ pRPort->RootIdSet = SK_TRUE;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+ ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+ PortNumber,
+ pRPort->Root.Id[0], pRPort->Root.Id[1],
+ pRPort->Root.Id[2], pRPort->Root.Id[3],
+ pRPort->Root.Id[4], pRPort->Root.Id[5],
+ pRPort->Root.Id[6], pRPort->Root.Id[7]))
+ }
+
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+ SK_RLMT_RCS_REPORT_SEG) != 0) {
+ SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber);
+ }
+ }
+ else {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+ ("SkRlmtPacketReceive: Unknown Packet Type.\n"))
+
+ /* Unknown packet. */
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ }
+ return;
+} /* SkRlmtPacketReceive */
+
+
+/******************************************************************************
+ *
+ * SkRlmtCheckPort - check if a port works
+ *
+ * Description:
+ * This routine checks if a port whose link is up received something
+ * and if it seems to transmit successfully.
+ *
+ * # PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp
+ * # PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg
+ * # RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg
+ *
+ * if (Rx - RxBpdu == 0) { # No rx.
+ * if (state == PsUp) {
+ * PortCheckingState |= ChkRx
+ * }
+ * if (ModeCheckSeg && (Timeout ==
+ * TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) {
+ * RlmtCheckingState |= ChkSeg)
+ * PortCheckingState |= ChkSeg
+ * }
+ * NewTimeout = TO_SHORTEN(Timeout)
+ * if (NewTimeout < RLMT_MIN_TIMEOUT) {
+ * NewTimeout = RLMT_MIN_TIMEOUT
+ * PortState = PsDown
+ * ...
+ * }
+ * }
+ * else { # something was received
+ * # Set counter to 0 at LinkDown?
+ * # No - rx may be reported after LinkDown ???
+ * PortCheckingState &= ~ChkRx
+ * NewTimeout = RLMT_DEFAULT_TIMEOUT
+ * if (RxAck == 0) {
+ * possible reasons:
+ * is my tx line bad? --
+ * send RLMT multicast and report
+ * back internally? (only possible
+ * between ports on same adapter)
+ * }
+ * if (RxChk == 0) {
+ * possible reasons:
+ * - tx line of port set to check me
+ * maybe bad
+ * - no other port/adapter available or set
+ * to check me
+ * - adapter checking me has a longer
+ * timeout
+ * ??? anything that can be done here?
+ * }
+ * }
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * New timeout value.
+ */
+RLMT_STATIC SK_U32 SkRlmtCheckPort(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 PortNumber) /* Port to check */
+{
+ unsigned i;
+ SK_U32 NewTimeout;
+ SK_RLMT_PORT *pRPort;
+ SK_EVPARA Para;
+
+ pRPort = &pAC->Rlmt.Port[PortNumber];
+
+ if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
+ PortNumber, pRPort->PacketsPerTimeSlot))
+
+ /*
+ * Check segmentation if there was no receive at least twice
+ * in a row (PortNoRx is already set) and the segmentation
+ * check is not currently running.
+ */
+
+ if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+ (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+ !(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) {
+ pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+ SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
+ pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX))
+
+ if (pRPort->PortState != SK_RLMT_PS_DOWN) {
+ NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue);
+ if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
+ NewTimeout = SK_RLMT_MIN_TO_VAL;
+ }
+
+ if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+ Para.Para32[0] = PortNumber;
+ pRPort->CheckingState |= SK_RLMT_PCS_RX;
+
+ /*
+ * What shall we do if the port checked by this one receives
+ * our request frames? What's bad - our rx line or his tx line?
+ */
+ Para.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->DownRxTimer,
+ SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+ SK_RLMT_PORTDOWN_RX_TIM, Para);
+
+ for (i = 0; i < pRPort->PortsChecked; i++) {
+ if (pRPort->PortCheck[i].SuspectTx) {
+ continue;
+ }
+ pRPort->PortCheck[i].SuspectTx = SK_TRUE;
+ pRPort->PortsSuspect++;
+ if ((Para.pParaPtr =
+ SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX,
+ &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+ &pRPort->PortCheck[i].CheckAddr)) != NULL) {
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ }
+ }
+ }
+ }
+ else { /* PortDown -- or all partners suspect. */
+ NewTimeout = SK_RLMT_DEF_TO_VAL;
+ }
+ pRPort->PortNoRx = SK_TRUE;
+ }
+ else { /* A non-BPDU packet was received. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
+ PortNumber,
+ pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot,
+ pRPort->PacketsPerTimeSlot))
+
+ SkRlmtPortReceives(pAC, IoC, PortNumber);
+ if (pAC->Rlmt.CheckSwitch) {
+ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+ }
+
+ NewTimeout = SK_RLMT_DEF_TO_VAL;
+ }
+
+ return (NewTimeout);
+} /* SkRlmtCheckPort */
+
+
+/******************************************************************************
+ *
+ * SkRlmtSelectBcRx - select new active port, criteria 1 (CLP)
+ *
+ * Description:
+ * This routine selects the port that received a broadcast frame
+ * substantially later than all other ports.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * SK_BOOL
+ */
+RLMT_STATIC SK_BOOL SkRlmtSelectBcRx(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Active, /* Active port */
+SK_U32 PrefPort, /* Preferred port */
+SK_U32 *pSelect) /* New active port */
+{
+ SK_U64 BcTimeStamp;
+ SK_U32 i;
+ SK_BOOL PortFound;
+
+ BcTimeStamp = 0; /* Not totally necessary, but feeling better. */
+ PortFound = SK_FALSE;
+
+ /* Select port with the latest TimeStamp. */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n",
+ i,
+ pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx,
+ *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
+ *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
+
+ if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) {
+ if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
+ BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
+ *pSelect = i;
+ PortFound = SK_TRUE;
+ }
+ }
+ }
+
+ if (PortFound) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Port %d received the last broadcast.\n", *pSelect))
+
+ /* Look if another port's time stamp is similar. */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ if (i == *pSelect) {
+ continue;
+ }
+ if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx &&
+ (pAC->Rlmt.Port[i].BcTimeStamp >
+ BcTimeStamp - SK_RLMT_BC_DELTA ||
+ pAC->Rlmt.Port[i].BcTimeStamp +
+ SK_RLMT_BC_DELTA > BcTimeStamp)) {
+ PortFound = SK_FALSE;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Port %d received a broadcast at a similar time.\n", i))
+ break;
+ }
+ }
+ }
+
+#ifdef DEBUG
+ if (PortFound) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially "
+ "latest broadcast (%u).\n",
+ *pSelect,
+ BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
+ }
+#endif /* DEBUG */
+
+ return (PortFound);
+} /* SkRlmtSelectBcRx */
+
+
+/******************************************************************************
+ *
+ * SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP)
+ *
+ * Description:
+ * This routine selects a good port (it is PortUp && !SuspectRx).
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * SK_BOOL
+ */
+RLMT_STATIC SK_BOOL SkRlmtSelectNotSuspect(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Active, /* Active port */
+SK_U32 PrefPort, /* Preferred port */
+SK_U32 *pSelect) /* New active port */
+{
+ SK_U32 i;
+ SK_BOOL PortFound;
+
+ PortFound = SK_FALSE;
+
+ /* Select first port that is PortUp && !SuspectRx. */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ if (!pAC->Rlmt.Port[i].PortDown &&
+ !(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
+ *pSelect = i;
+ if (!pAC->Rlmt.Port[Active].PortDown &&
+ !(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) {
+ *pSelect = Active;
+ }
+ if (!pAC->Rlmt.Port[PrefPort].PortDown &&
+ !(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) {
+ *pSelect = PrefPort;
+ }
+ PortFound = SK_TRUE;
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n",
+ *pSelect))
+ break;
+ }
+ }
+ return (PortFound);
+} /* SkRlmtSelectNotSuspect */
+
+
+/******************************************************************************
+ *
+ * SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP)
+ *
+ * Description:
+ * This routine selects a port that is up.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * SK_BOOL
+ */
+RLMT_STATIC SK_BOOL SkRlmtSelectUp(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Active, /* Active port */
+SK_U32 PrefPort, /* Preferred port */
+SK_U32 *pSelect, /* New active port */
+SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */
+{
+ SK_U32 i;
+ SK_BOOL PortFound;
+
+ PortFound = SK_FALSE;
+
+ /* Select first port that is PortUp. */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
+ pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+ *pSelect = i;
+ if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP &&
+ pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+ *pSelect = Active;
+ }
+ if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP &&
+ pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+ *pSelect = PrefPort;
+ }
+ PortFound = SK_TRUE;
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect))
+ break;
+ }
+ }
+ return (PortFound);
+} /* SkRlmtSelectUp */
+
+
+/******************************************************************************
+ *
+ * SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP)
+ *
+ * Description:
+ * This routine selects the port that is going up for the longest time.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * SK_BOOL
+ */
+RLMT_STATIC SK_BOOL SkRlmtSelectGoingUp(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Active, /* Active port */
+SK_U32 PrefPort, /* Preferred port */
+SK_U32 *pSelect, /* New active port */
+SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */
+{
+ SK_U64 GuTimeStamp;
+ SK_U32 i;
+ SK_BOOL PortFound;
+
+ GuTimeStamp = 0;
+ PortFound = SK_FALSE;
+
+ /* Select port that is PortGoingUp for the longest time. */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+ pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+ GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+ *pSelect = i;
+ PortFound = SK_TRUE;
+ break;
+ }
+ }
+
+ if (!PortFound) {
+ return (SK_FALSE);
+ }
+
+ for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+ pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
+ pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+ GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+ *pSelect = i;
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect))
+ return (SK_TRUE);
+} /* SkRlmtSelectGoingUp */
+
+
+/******************************************************************************
+ *
+ * SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP)
+ *
+ * Description:
+ * This routine selects a port that is down.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * SK_BOOL
+ */
+RLMT_STATIC SK_BOOL SkRlmtSelectDown(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Active, /* Active port */
+SK_U32 PrefPort, /* Preferred port */
+SK_U32 *pSelect, /* New active port */
+SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */
+{
+ SK_U32 i;
+ SK_BOOL PortFound;
+
+ PortFound = SK_FALSE;
+
+ /* Select first port that is PortDown. */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
+ pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+ *pSelect = i;
+ if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN &&
+ pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+ *pSelect = Active;
+ }
+ if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN &&
+ pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+ *pSelect = PrefPort;
+ }
+ PortFound = SK_TRUE;
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect))
+ break;
+ }
+ }
+ return (PortFound);
+} /* SkRlmtSelectDown */
+
+
+/******************************************************************************
+ *
+ * SkRlmtCheckSwitch - select new active port and switch to it
+ *
+ * Description:
+ * This routine decides which port should be the active one and queues
+ * port switching if necessary.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing.
+ */
+RLMT_STATIC void SkRlmtCheckSwitch(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 NetIdx) /* Net index */
+{
+ SK_EVPARA Para;
+ SK_U32 Active;
+ SK_U32 PrefPort;
+ SK_U32 i;
+ SK_BOOL PortFound;
+
+ Active = pAC->Rlmt.Net[NetIdx].ActivePort; /* Index of active port. */
+ PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort; /* Index of preferred port. */
+ PortFound = SK_FALSE;
+ pAC->Rlmt.CheckSwitch = SK_FALSE;
+
+#if 0 /* RW 2001/10/18 - active port becomes always prefered one */
+ if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */
+ /* disable auto-fail back */
+ PrefPort = Active;
+ }
+#endif
+
+ if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) {
+ /* Last link went down - shut down the net. */
+ pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN;
+ Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
+ Para.Para32[1] = NetIdx;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para);
+
+ Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+ Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+ Para.Para32[1] = NetIdx;
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+ return;
+ } /* pAC->Rlmt.LinksUp == 0 */
+ else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 &&
+ pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) {
+ /* First link came up - get the net up. */
+ pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP;
+
+ /*
+ * If pAC->Rlmt.ActivePort != Para.Para32[0],
+ * the DRV switches to the port that came up.
+ */
+ for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+ if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+ if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) {
+ i = Active;
+ }
+ if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) {
+ i = PrefPort;
+ }
+ PortFound = SK_TRUE;
+ break;
+ }
+ }
+
+ if (PortFound) {
+ Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+ Para.Para32[1] = NetIdx;
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+
+ pAC->Rlmt.Net[NetIdx].ActivePort = i;
+ Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+ Para.Para32[1] = NetIdx;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
+
+ if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+ (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC,
+ pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber,
+ SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].
+ CurrentMacAddress, &SkRlmtMcAddr)) != NULL) {
+ /*
+ * Send announce packet to RLMT multicast address to force
+ * switches to learn the new location of the logical MAC address.
+ */
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ }
+ }
+ else {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG);
+ }
+
+ return;
+ } /* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */
+ else { /* Cannot be reached in dual-net mode. */
+ Para.Para32[0] = Active;
+
+ /*
+ * Preselection:
+ * If RLMT Mode != CheckLinkState
+ * select port that received a broadcast frame substantially later
+ * than all other ports
+ * else select first port that is not SuspectRx
+ * else select first port that is PortUp
+ * else select port that is PortGoingUp for the longest time
+ * else select first port that is PortDown
+ * else stop.
+ *
+ * For the preselected port:
+ * If ActivePort is equal in quality, select ActivePort.
+ *
+ * If PrefPort is equal in quality, select PrefPort.
+ *
+ * If ActivePort != SelectedPort,
+ * If old ActivePort is LinkDown,
+ * SwitchHard
+ * else
+ * SwitchSoft
+ */
+ /* check of ChgBcPrio flag added */
+ if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+ (!pAC->Rlmt.Net[0].ChgBcPrio)) {
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectBcRx(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+ }
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectNotSuspect(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+ }
+ } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+ /* with changed priority for last broadcast received */
+ if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+ (pAC->Rlmt.Net[0].ChgBcPrio)) {
+ if (!PortFound) {
+ PortFound = SkRlmtSelectNotSuspect(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+ }
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectBcRx(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+ }
+ } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectUp(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+ }
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectUp(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+ }
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectGoingUp(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+ }
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectGoingUp(
+ pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+ }
+
+ if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
+ if (!PortFound) {
+ PortFound = SkRlmtSelectDown(pAC, IoC,
+ Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+ }
+
+ if (!PortFound) {
+ PortFound = SkRlmtSelectDown(pAC, IoC,
+ Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+ }
+ } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+ if (PortFound) {
+
+ if (Para.Para32[1] != Active) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
+ pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1];
+ Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+ Port[Para.Para32[0]]->PortNumber;
+ Para.Para32[1] = pAC->Rlmt.Net[NetIdx].
+ Port[Para.Para32[1]]->PortNumber;
+ SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE);
+ if (pAC->Rlmt.Port[Active].LinkDown) {
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para);
+ }
+ else {
+ SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para);
+ }
+ Para.Para32[1] = NetIdx;
+ Para.Para32[0] =
+ pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber;
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+ Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+ Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+ if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+ (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0],
+ SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress,
+ &SkRlmtMcAddr)) != NULL) {
+ /*
+ * Send announce packet to RLMT multicast address to force
+ * switches to learn the new location of the logical
+ * MAC address.
+ */
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+ } /* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */
+ } /* Para.Para32[1] != Active */
+ } /* PortFound */
+ else {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG);
+ }
+ } /* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */
+ return;
+} /* SkRlmtCheckSwitch */
+
+
+/******************************************************************************
+ *
+ * SkRlmtCheckSeg - Report if segmentation is detected
+ *
+ * Description:
+ * This routine checks if the ports see different root bridges and reports
+ * segmentation in such a case.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing.
+ */
+RLMT_STATIC void SkRlmtCheckSeg(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 NetIdx) /* Net number */
+{
+ SK_EVPARA Para;
+ SK_RLMT_NET *pNet;
+ SK_U32 i, j;
+ SK_BOOL Equal;
+
+ pNet = &pAC->Rlmt.Net[NetIdx];
+ pNet->RootIdSet = SK_FALSE;
+ Equal = SK_TRUE;
+
+ for (i = 0; i < pNet->NumPorts; i++) {
+ if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) {
+ continue;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+ ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i,
+ pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1],
+ pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3],
+ pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5],
+ pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7]))
+
+ if (!pNet->RootIdSet) {
+ pNet->Root = pNet->Port[i]->Root;
+ pNet->RootIdSet = SK_TRUE;
+ continue;
+ }
+
+ for (j = 0; j < 8; j ++) {
+ Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j];
+ if (!Equal) {
+ break;
+ }
+ }
+
+ if (!Equal) {
+ SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG);
+ Para.Para32[0] = NetIdx;
+ Para.Para32[1] = (SK_U32)-1;
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para);
+
+ pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+
+ /* 2000-03-06 RA: New. */
+ Para.Para32[0] = NetIdx;
+ Para.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL,
+ SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+ break;
+ }
+ } /* for (i = 0; i < pNet->NumPorts; i++) */
+
+ /* 2000-03-06 RA: Moved here. */
+ /* Segmentation check not running anymore. */
+ pNet->CheckingState &= ~SK_RLMT_RCS_SEG;
+
+} /* SkRlmtCheckSeg */
+
+
+/******************************************************************************
+ *
+ * SkRlmtPortStart - initialize port variables and start port
+ *
+ * Description:
+ * This routine initializes a port's variables and issues a PORT_START
+ * to the HWAC module. This handles retries if the start fails or the
+ * link eventually goes down.
+ *
+ * Context:
+ * runtime, pageable?
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtPortStart(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 PortNumber) /* Port number */
+{
+ SK_EVPARA Para;
+
+ pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN;
+ pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE;
+ pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE;
+ pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE;
+ pAC->Rlmt.Port[PortNumber].CheckingState = 0;
+ pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+ Para.Para32[0] = PortNumber;
+ Para.Para32[1] = (SK_U32)-1;
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+} /* SkRlmtPortStart */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtPortStartTim - PORT_START_TIM
+ *
+ * Description:
+ * This routine handles PORT_START_TIM events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtPortStartTim(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */
+{
+ SK_U32 i;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n"))
+ return;
+ }
+
+ /*
+ * Used to start non-preferred ports if the preferred one
+ * does not come up.
+ * This timeout needs only be set when starting the first
+ * (preferred) port.
+ */
+ if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+ /* PORT_START failed. */
+ for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) {
+ if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) {
+ SkRlmtPortStart(pAC, IoC,
+ pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber);
+ }
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTSTART_TIMEOUT Event END.\n"))
+} /* SkRlmtEvtPortStartTim */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtLinkUp - LINK_UP
+ *
+ * Description:
+ * This routine handles LLINK_UP events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtLinkUp(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */
+{
+ SK_U32 i;
+ SK_RLMT_PORT *pRPort;
+ SK_EVPARA Para2;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0]))
+
+ pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+ if (!pRPort->PortStarted) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_LINK_UP Event EMPTY.\n"))
+ return;
+ }
+
+ if (!pRPort->LinkDown) {
+ /* RA;:;: Any better solution? */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_LINK_UP Event EMPTY.\n"))
+ return;
+ }
+
+ SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+ SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+ SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+ /* Do something if timer already fired? */
+
+ pRPort->LinkDown = SK_FALSE;
+ pRPort->PortState = SK_RLMT_PS_GOING_UP;
+ pRPort->GuTimeStamp = SkOsGetTime(pAC);
+ pRPort->BcTimeStamp = 0;
+ pRPort->Net->LinksUp++;
+ if (pRPort->Net->LinksUp == 1) {
+ SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE);
+ }
+ else {
+ SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+ }
+
+ for (i = 0; i < pRPort->Net->NumPorts; i++) {
+ if (!pRPort->Net->Port[i]->PortStarted) {
+ SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber);
+ }
+ }
+
+ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+
+ if (pRPort->Net->LinksUp >= 2) {
+ if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+ /* Build the check chain. */
+ SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+ }
+ }
+
+ /* If the first link comes up, start the periodical RLMT timeout. */
+ if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 &&
+ (pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) {
+ Para2.Para32[0] = pRPort->Net->NetNumber;
+ Para2.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer,
+ pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2);
+ }
+
+ Para2 = Para;
+ Para2.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+ SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2);
+
+ /* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */
+ if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+ (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 &&
+ (Para2.pParaPtr =
+ SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE,
+ &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr)
+ ) != NULL) {
+ /* Send "new" packet to RLMT multicast address. */
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+ }
+
+ if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) {
+ if ((Para2.pParaPtr =
+ SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) {
+ pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE;
+ pRPort->Net->CheckingState |=
+ SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+
+ Para.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer,
+ SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_LINK_UP Event END.\n"))
+} /* SkRlmtEvtLinkUp */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtPortUpTim - PORT_UP_TIM
+ *
+ * Description:
+ * This routine handles PORT_UP_TIM events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtPortUpTim(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */
+{
+ SK_RLMT_PORT *pRPort;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTUP_TIM Event EMPTY.\n"))
+ return;
+ }
+
+ pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+ if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0]))
+ return;
+ }
+
+ pRPort->PortDown = SK_FALSE;
+ pRPort->PortState = SK_RLMT_PS_UP;
+ pRPort->Net->PortsUp++;
+ if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+ if (pAC->Rlmt.NumNets <= 1) {
+ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+ }
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para);
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTUP_TIM Event END.\n"))
+} /* SkRlmtEvtPortUpTim */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtPortDownTim - PORT_DOWN_*
+ *
+ * Description:
+ * This routine handles PORT_DOWN_* events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtPortDownX(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Event, /* Event code */
+SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */
+{
+ SK_RLMT_PORT *pRPort;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n",
+ Para.Para32[0], Event))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTDOWN* Event EMPTY.\n"))
+ return;
+ }
+
+ pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+ if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM &&
+ !(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
+ return;
+ }
+
+ /* Stop port's timers. */
+ SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+ SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+ SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+ if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
+ pRPort->PortState = SK_RLMT_PS_DOWN;
+ }
+
+ if (!pRPort->PortDown) {
+ pRPort->Net->PortsUp--;
+ pRPort->PortDown = SK_TRUE;
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para);
+ }
+
+ pRPort->PacketsPerTimeSlot = 0;
+ /* pRPort->DataPacketsPerTimeSlot = 0; */
+ pRPort->BpduPacketsPerTimeSlot = 0;
+ pRPort->BcTimeStamp = 0;
+
+ /*
+ * RA;:;: To be checked:
+ * - actions at RLMT_STOP: We should not switch anymore.
+ */
+ if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+ if (Para.Para32[0] ==
+ pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) {
+ /* Active Port went down. */
+ SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
+} /* SkRlmtEvtPortDownX */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtLinkDown - LINK_DOWN
+ *
+ * Description:
+ * This routine handles LINK_DOWN events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtLinkDown(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */
+{
+ SK_RLMT_PORT *pRPort;
+
+ pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+ pRPort->Net->LinksUp--;
+ pRPort->LinkDown = SK_TRUE;
+ pRPort->PortState = SK_RLMT_PS_LINK_DOWN;
+ SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF);
+
+ if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) {
+ /* Build the check chain. */
+ SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+ }
+
+ /* Ensure that port is marked down. */
+ Para.Para32[1] = -1;
+ (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para);
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_LINK_DOWN Event END.\n"))
+} /* SkRlmtEvtLinkDown */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtPortAddr - PORT_ADDR
+ *
+ * Description:
+ * This routine handles PORT_ADDR events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtPortAddr(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */
+{
+ SK_U32 i, j;
+ SK_RLMT_PORT *pRPort;
+ SK_MAC_ADDR *pOldMacAddr;
+ SK_MAC_ADDR *pNewMacAddr;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORT_ADDR Event EMPTY.\n"))
+ return;
+ }
+
+ /* Port's physical MAC address changed. */
+ pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
+ pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+
+ /*
+ * NOTE: This is not scalable for solutions where ports are
+ * checked remotely. There, we need to send an RLMT
+ * address change packet - and how do we ensure delivery?
+ */
+ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+ pRPort = &pAC->Rlmt.Port[i];
+ for (j = 0; j < pRPort->PortsChecked; j++) {
+ if (SK_ADDR_EQUAL(
+ pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) {
+ pRPort->PortCheck[j].CheckAddr = *pNewMacAddr;
+ }
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PORT_ADDR Event END.\n"))
+} /* SkRlmtEvtPortAddr */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtStart - START
+ *
+ * Description:
+ * This routine handles START events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtStart(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */
+{
+ SK_EVPARA Para2;
+ SK_U32 PortIdx;
+ SK_U32 PortNumber;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_START Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad NetNumber %d.\n", Para.Para32[0]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_START Event EMPTY.\n"))
+ return;
+ }
+
+ if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_START Event EMPTY.\n"))
+ return;
+ }
+
+ if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("All nets should have been started.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_START Event EMPTY.\n"))
+ return;
+ }
+
+ if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >=
+ pAC->Rlmt.Net[Para.Para32[0]].NumPorts) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG);
+
+ /* Change PrefPort to internal default. */
+ Para2.Para32[0] = 0xFFFFFFFF;
+ Para2.Para32[1] = Para.Para32[0];
+ (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2);
+ }
+
+ PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort;
+ PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber;
+
+ pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0;
+ pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0;
+ pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0;
+ pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN;
+
+ /* Start preferred port. */
+ SkRlmtPortStart(pAC, IoC, PortNumber);
+
+ /* Start Timer (for first port only). */
+ Para2.Para32[0] = PortNumber;
+ Para2.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer,
+ SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2);
+
+ pAC->Rlmt.NetsStarted++;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_START Event END.\n"))
+} /* SkRlmtEvtStart */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtStop - STOP
+ *
+ * Description:
+ * This routine handles STOP events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtStop(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */
+{
+ SK_EVPARA Para2;
+ SK_U32 PortNumber;
+ SK_U32 i;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STOP Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad NetNumber %d.\n", Para.Para32[0]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STOP Event EMPTY.\n"))
+ return;
+ }
+
+ if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STOP Event EMPTY.\n"))
+ return;
+ }
+
+ if (pAC->Rlmt.NetsStarted == 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("All nets are stopped.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STOP Event EMPTY.\n"))
+ return;
+ }
+
+ /* Stop RLMT timers. */
+ SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer);
+ SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer);
+
+ /* Stop net. */
+ pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT;
+ pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE;
+ Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
+ Para2.Para32[1] = Para.Para32[0]; /* Net# */
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+
+ /* Stop ports. */
+ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+ PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+ if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) {
+ SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer);
+ SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer);
+ SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer);
+
+ pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT;
+ pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+ pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE;
+ Para2.Para32[0] = PortNumber;
+ Para2.Para32[1] = (SK_U32)-1;
+ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2);
+ }
+ }
+
+ pAC->Rlmt.NetsStarted--;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STOP Event END.\n"))
+} /* SkRlmtEvtStop */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtTim - TIM
+ *
+ * Description:
+ * This routine handles TIM events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtTim(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */
+{
+ SK_RLMT_PORT *pRPort;
+ SK_U32 Timeout;
+ SK_U32 NewTimeout;
+ SK_U32 PortNumber;
+ SK_U32 i;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_TIM Event BEGIN.\n"))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_TIM Event EMPTY.\n"))
+ return;
+ }
+
+ if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 ||
+ pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) {
+ /* Mode changed or all links down: No more link checking. */
+ return;
+ }
+
+#if 0
+ pAC->Rlmt.SwitchCheckCounter--;
+ if (pAC->Rlmt.SwitchCheckCounter == 0) {
+ pAC->Rlmt.SwitchCheckCounter;
+ }
+#endif /* 0 */
+
+ NewTimeout = SK_RLMT_DEF_TO_VAL;
+ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+ PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+ pRPort = &pAC->Rlmt.Port[PortNumber];
+ if (!pRPort->LinkDown) {
+ Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber);
+ if (Timeout < NewTimeout) {
+ NewTimeout = Timeout;
+ }
+
+ /*
+ * These counters should be set to 0 for all ports before the
+ * first frame is sent in the next loop.
+ */
+ pRPort->PacketsPerTimeSlot = 0;
+ /* pRPort->DataPacketsPerTimeSlot = 0; */
+ pRPort->BpduPacketsPerTimeSlot = 0;
+ }
+ }
+ pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout;
+
+ if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) {
+ /*
+ * If checking remote ports, also send packets if
+ * (LinksUp == 1) &&
+ * this port checks at least one (remote) port.
+ */
+
+ /*
+ * Must be new loop, as SkRlmtCheckPort can request to
+ * check segmentation when e.g. checking the last port.
+ */
+ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+ if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) {
+ SkRlmtSend(pAC, IoC,
+ pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber);
+ }
+ }
+ }
+
+ SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer,
+ pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM,
+ Para);
+
+ if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 &&
+ (pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) &&
+ (pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) {
+ SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer,
+ SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+ pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG;
+ pAC->Rlmt.Net[Para.Para32[0]].CheckingState |=
+ SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_TIM Event END.\n"))
+} /* SkRlmtEvtTim */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtSegTim - SEG_TIM
+ *
+ * Description:
+ * This routine handles SEG_TIM events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtSegTim(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */
+{
+#ifdef xDEBUG
+ int j;
+#endif /* DEBUG */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SEG_TIM Event BEGIN.\n"))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SEG_TIM Event EMPTY.\n"))
+ return;
+ }
+
+#ifdef xDEBUG
+ for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
+ SK_ADDR_PORT *pAPort;
+ SK_U32 k;
+ SK_U16 *InAddr;
+ SK_U8 InAddr8[6];
+
+ InAddr = (SK_U16 *)&InAddr8[0];
+ pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort;
+ for (k = 0; k < pAPort->NextExactMatchRlmt; k++) {
+ /* Get exact match address k from port j. */
+ XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+ XM_EXM(k), InAddr);
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n",
+ k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+ InAddr8[0], InAddr8[1], InAddr8[2],
+ InAddr8[3], InAddr8[4], InAddr8[5],
+ pAPort->Exact[k].a[0], pAPort->Exact[k].a[1],
+ pAPort->Exact[k].a[2], pAPort->Exact[k].a[3],
+ pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
+ }
+ }
+#endif /* xDEBUG */
+
+ SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SEG_TIM Event END.\n"))
+} /* SkRlmtEvtSegTim */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtPacketRx - PACKET_RECEIVED
+ *
+ * Description:
+ * This routine handles PACKET_RECEIVED events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtPacketRx(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_MBUF *pMb */
+{
+ SK_MBUF *pMb;
+ SK_MBUF *pNextMb;
+ SK_U32 NetNumber;
+
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n"))
+
+ /* Should we ignore frames during port switching? */
+
+#ifdef DEBUG
+ pMb = Para.pParaPtr;
+ if (pMb == NULL) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n"))
+ }
+ else if (pMb->pNext != NULL) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("More than one mbuf or pMb->pNext not set.\n"))
+ }
+#endif /* DEBUG */
+
+ for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
+ pNextMb = pMb->pNext;
+ pMb->pNext = NULL;
+
+ NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber;
+ if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) {
+ SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+ }
+ else {
+ SkRlmtPacketReceive(pAC, IoC, pMb);
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PACKET_RECEIVED Event END.\n"))
+} /* SkRlmtEvtPacketRx */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtStatsClear - STATS_CLEAR
+ *
+ * Description:
+ * This routine handles STATS_CLEAR events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtStatsClear(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */
+{
+ SK_U32 i;
+ SK_RLMT_PORT *pRPort;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_CLEAR Event BEGIN.\n"))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad NetNumber %d.\n", Para.Para32[0]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+ return;
+ }
+
+ /* Clear statistics for logical and physical ports. */
+ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+ pRPort =
+ &pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber];
+ pRPort->TxHelloCts = 0;
+ pRPort->RxHelloCts = 0;
+ pRPort->TxSpHelloReqCts = 0;
+ pRPort->RxSpHelloCts = 0;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_CLEAR Event END.\n"))
+} /* SkRlmtEvtStatsClear */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtStatsUpdate - STATS_UPDATE
+ *
+ * Description:
+ * This routine handles STATS_UPDATE events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtStatsUpdate(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad NetNumber %d.\n", Para.Para32[0]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+ return;
+ }
+
+ /* Update statistics - currently always up-to-date. */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_STATS_UPDATE Event END.\n"))
+} /* SkRlmtEvtStatsUpdate */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtPrefportChange - PREFPORT_CHANGE
+ *
+ * Description:
+ * This routine handles PREFPORT_CHANGE events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtPrefportChange(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 PortIndex; SK_U32 NetNumber */
+{
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0]))
+
+ if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad NetNumber %d.\n", Para.Para32[1]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+ return;
+ }
+
+ /* 0xFFFFFFFF == auto-mode. */
+ if (Para.Para32[0] == 0xFFFFFFFF) {
+ pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT;
+ }
+ else {
+ if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) {
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+ return;
+ }
+
+ pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0];
+ }
+
+ pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0];
+
+ if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+ SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]);
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_PREFPORT_CHANGE Event END.\n"))
+} /* SkRlmtEvtPrefportChange */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtSetNets - SET_NETS
+ *
+ * Description:
+ * This routine handles SET_NETS events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtSetNets(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NumNets; SK_U32 -1 */
+{
+ int i;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event BEGIN.\n"))
+
+ if (Para.Para32[1] != (SK_U32)-1) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad Parameter.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS ||
+ Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad number of nets: %d.\n", Para.Para32[0]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] == pAC->Rlmt.NumNets) { /* No change. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+ return;
+ }
+
+ /* Entering and leaving dual mode only allowed while nets are stopped. */
+ if (pAC->Rlmt.NetsStarted > 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Changing dual mode only allowed while all nets are stopped.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+ return;
+ }
+
+ if (Para.Para32[0] == 1) {
+ if (pAC->Rlmt.NumNets > 1) {
+ /* Clear logical MAC addr from second net's active port. */
+ (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+ Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL);
+ pAC->Rlmt.Net[1].NumPorts = 0;
+ }
+
+ pAC->Rlmt.NumNets = Para.Para32[0];
+ for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+ pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+ pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+ pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */
+ pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+ /* Just assuming. */
+ pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+ pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+ pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+ pAC->Rlmt.Net[i].NetNumber = i;
+ }
+
+ pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0];
+ pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("RLMT: Changed to one net with two ports.\n"))
+ }
+ else if (Para.Para32[0] == 2) {
+ pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1];
+ pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1;
+ pAC->Rlmt.Net[0].NumPorts =
+ pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts;
+
+ pAC->Rlmt.NumNets = Para.Para32[0];
+ for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+ pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+ pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+ pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */
+ pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+ /* Just assuming. */
+ pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+ pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+ pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+
+ pAC->Rlmt.Net[i].NetNumber = i;
+ }
+
+ /* Set logical MAC addr on second net's active port. */
+ (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+ Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL);
+
+ SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("RLMT: Changed to two nets with one port each.\n"))
+ }
+ else {
+ /* Not implemented for more than two nets. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SetNets not implemented for more than two nets.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event EMPTY.\n"))
+ return;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_SET_NETS Event END.\n"))
+} /* SkRlmtSetNets */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvtModeChange - MODE_CHANGE
+ *
+ * Description:
+ * This routine handles MODE_CHANGE events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * Nothing
+ */
+RLMT_STATIC void SkRlmtEvtModeChange(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_EVPARA Para) /* SK_U32 NewMode; SK_U32 NetNumber */
+{
+ SK_EVPARA Para2;
+ SK_U32 i;
+ SK_U32 PrevRlmtMode;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_MODE_CHANGE Event BEGIN.\n"))
+
+ if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Bad NetNumber %d.\n", Para.Para32[1]))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+ return;
+ }
+
+ Para.Para32[0] |= SK_RLMT_CHECK_LINK;
+
+ if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) &&
+ Para.Para32[0] != SK_RLMT_MODE_CLS) {
+ pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS;
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Forced RLMT mode to CLS on single port net.\n"))
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+ return;
+ }
+
+ /* Update RLMT mode. */
+ PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode;
+ pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0];
+
+ if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
+ (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+ /* SK_RLMT_CHECK_LOC_LINK bit changed. */
+ if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 &&
+ pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 &&
+ pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) {
+ /* 20001207 RA: Was "PortsUp == 1". */
+ Para2.Para32[0] = Para.Para32[1];
+ Para2.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer,
+ pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue,
+ SKGE_RLMT, SK_RLMT_TIM, Para2);
+ }
+ }
+
+ if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
+ (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) {
+ /* SK_RLMT_CHECK_SEG bit changed. */
+ for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) {
+ (void)SkAddrMcClear(pAC, IoC,
+ pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+ SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+ /* Add RLMT MC address. */
+ (void)SkAddrMcAdd(pAC, IoC,
+ pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+ &SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+ if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode &
+ SK_RLMT_CHECK_SEG) != 0) {
+ /* Add BPDU MC address. */
+ (void)SkAddrMcAdd(pAC, IoC,
+ pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+ &BridgeMcAddr, SK_ADDR_PERMANENT);
+
+ if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+ if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown &&
+ (Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(
+ pAC, IoC, i)) != NULL) {
+ pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet =
+ SK_FALSE;
+ SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+ }
+ }
+ }
+ (void)SkAddrMcUpdate(pAC, IoC,
+ pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber);
+ } /* for ... */
+
+ if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) {
+ Para2.Para32[0] = Para.Para32[1];
+ Para2.Para32[1] = (SK_U32)-1;
+ SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer,
+ SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2);
+ }
+ } /* SK_RLMT_CHECK_SEG bit changed. */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("SK_RLMT_MODE_CHANGE Event END.\n"))
+} /* SkRlmtEvtModeChange */
+
+
+/******************************************************************************
+ *
+ * SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *
+ * Description:
+ * This routine calls subroutines to handle PORT- and RLMT-specific events.
+ *
+ * Context:
+ * runtime, pageable?
+ * may be called after SK_INIT_IO
+ *
+ * Returns:
+ * 0
+ */
+int SkRlmtEvent(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+SK_U32 Event, /* Event code */
+SK_EVPARA Para) /* Event-specific parameter */
+{
+ switch (Event) {
+
+ /* ----- PORT events ----- */
+
+ case SK_RLMT_PORTSTART_TIM: /* From RLMT via TIME. */
+ SkRlmtEvtPortStartTim(pAC, IoC, Para);
+ break;
+ case SK_RLMT_LINK_UP: /* From SIRQ. */
+ SkRlmtEvtLinkUp(pAC, IoC, Para);
+ break;
+ case SK_RLMT_PORTUP_TIM: /* From RLMT via TIME. */
+ SkRlmtEvtPortUpTim(pAC, IoC, Para);
+ break;
+ case SK_RLMT_PORTDOWN: /* From RLMT. */
+ case SK_RLMT_PORTDOWN_RX_TIM: /* From RLMT via TIME. */
+ case SK_RLMT_PORTDOWN_TX_TIM: /* From RLMT via TIME. */
+ SkRlmtEvtPortDownX(pAC, IoC, Event, Para);
+ break;
+ case SK_RLMT_LINK_DOWN: /* From SIRQ. */
+ SkRlmtEvtLinkDown(pAC, IoC, Para);
+ break;
+ case SK_RLMT_PORT_ADDR: /* From ADDR. */
+ SkRlmtEvtPortAddr(pAC, IoC, Para);
+ break;
+
+ /* ----- RLMT events ----- */
+
+ case SK_RLMT_START: /* From DRV. */
+ SkRlmtEvtStart(pAC, IoC, Para);
+ break;
+ case SK_RLMT_STOP: /* From DRV. */
+ SkRlmtEvtStop(pAC, IoC, Para);
+ break;
+ case SK_RLMT_TIM: /* From RLMT via TIME. */
+ SkRlmtEvtTim(pAC, IoC, Para);
+ break;
+ case SK_RLMT_SEG_TIM:
+ SkRlmtEvtSegTim(pAC, IoC, Para);
+ break;
+ case SK_RLMT_PACKET_RECEIVED: /* From DRV. */
+ SkRlmtEvtPacketRx(pAC, IoC, Para);
+ break;
+ case SK_RLMT_STATS_CLEAR: /* From PNMI. */
+ SkRlmtEvtStatsClear(pAC, IoC, Para);
+ break;
+ case SK_RLMT_STATS_UPDATE: /* From PNMI. */
+ SkRlmtEvtStatsUpdate(pAC, IoC, Para);
+ break;
+ case SK_RLMT_PREFPORT_CHANGE: /* From PNMI. */
+ SkRlmtEvtPrefportChange(pAC, IoC, Para);
+ break;
+ case SK_RLMT_MODE_CHANGE: /* From PNMI. */
+ SkRlmtEvtModeChange(pAC, IoC, Para);
+ break;
+ case SK_RLMT_SET_NETS: /* From DRV. */
+ SkRlmtEvtSetNets(pAC, IoC, Para);
+ break;
+
+ /* ----- Unknown events ----- */
+
+ default: /* Create error log entry. */
+ SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+ ("Unknown RLMT Event %d.\n", Event))
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG);
+ break;
+ } /* switch() */
+
+ return (0);
+} /* SkRlmtEvent */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/drivers/net/sk98lin/sktimer.c b/drivers/net/sk98lin/sktimer.c
new file mode 100644
index 000000000000..4e462955ecd8
--- /dev/null
+++ b/drivers/net/sk98lin/sktimer.c
@@ -0,0 +1,250 @@
+/******************************************************************************
+ *
+ * Name: sktimer.c
+ * Project: Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version: $Revision: 1.14 $
+ * Date: $Date: 2003/09/16 13:46:51 $
+ * Purpose: High level timer functions.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect GmbH.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+ * Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h" /* Driver Specific Definitions */
+#include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+ Event queue management.
+
+ General Description:
+
+ */
+intro()
+{}
+#endif
+
+
+/* Forward declaration */
+static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
+
+
+/*
+ * Inits the software timer
+ *
+ * needs to be called during Init level 1.
+ */
+void SkTimerInit(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc, /* IoContext */
+int Level) /* Init Level */
+{
+ switch (Level) {
+ case SK_INIT_DATA:
+ pAC->Tim.StQueue = NULL;
+ break;
+ case SK_INIT_IO:
+ SkHwtInit(pAC, Ioc);
+ SkTimerDone(pAC, Ioc);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Stops a high level timer
+ * - If a timer is not in the queue the function returns normally, too.
+ */
+void SkTimerStop(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc, /* IoContext */
+SK_TIMER *pTimer) /* Timer Pointer to be started */
+{
+ SK_TIMER **ppTimPrev;
+ SK_TIMER *pTm;
+
+ /*
+ * remove timer from queue
+ */
+ pTimer->TmActive = SK_FALSE;
+
+ if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
+ SkHwtStop(pAC, Ioc);
+ }
+
+ for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
+ ppTimPrev = &pTm->TmNext ) {
+
+ if (pTm == pTimer) {
+ /*
+ * Timer found in queue
+ * - dequeue it and
+ * - correct delta of the next timer
+ */
+ *ppTimPrev = pTm->TmNext;
+
+ if (pTm->TmNext) {
+ /* correct delta of next timer in queue */
+ pTm->TmNext->TmDelta += pTm->TmDelta;
+ }
+ return;
+ }
+ }
+}
+
+/*
+ * Start a high level software timer
+ */
+void SkTimerStart(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc, /* IoContext */
+SK_TIMER *pTimer, /* Timer Pointer to be started */
+SK_U32 Time, /* Time value */
+SK_U32 Class, /* Event Class for this timer */
+SK_U32 Event, /* Event Value for this timer */
+SK_EVPARA Para) /* Event Parameter for this timer */
+{
+ SK_TIMER **ppTimPrev;
+ SK_TIMER *pTm;
+ SK_U32 Delta;
+
+ Time /= 16; /* input is uS, clock ticks are 16uS */
+
+ if (!Time)
+ Time = 1;
+
+ SkTimerStop(pAC, Ioc, pTimer);
+
+ pTimer->TmClass = Class;
+ pTimer->TmEvent = Event;
+ pTimer->TmPara = Para;
+ pTimer->TmActive = SK_TRUE;
+
+ if (!pAC->Tim.StQueue) {
+ /* First Timer to be started */
+ pAC->Tim.StQueue = pTimer;
+ pTimer->TmNext = NULL;
+ pTimer->TmDelta = Time;
+
+ SkHwtStart(pAC, Ioc, Time);
+
+ return;
+ }
+
+ /*
+ * timer correction
+ */
+ timer_done(pAC, Ioc, 0);
+
+ /*
+ * find position in queue
+ */
+ Delta = 0;
+ for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
+ ppTimPrev = &pTm->TmNext ) {
+
+ if (Delta + pTm->TmDelta > Time) {
+ /* Position found */
+ /* Here the timer needs to be inserted. */
+ break;
+ }
+ Delta += pTm->TmDelta;
+ }
+
+ /* insert in queue */
+ *ppTimPrev = pTimer;
+ pTimer->TmNext = pTm;
+ pTimer->TmDelta = Time - Delta;
+
+ if (pTm) {
+ /* There is a next timer
+ * -> correct its Delta value.
+ */
+ pTm->TmDelta -= pTimer->TmDelta;
+ }
+
+ /* restart with first */
+ SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
+}
+
+
+void SkTimerDone(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc) /* IoContext */
+{
+ timer_done(pAC, Ioc, 1);
+}
+
+
+static void timer_done(
+SK_AC *pAC, /* Adapters context */
+SK_IOC Ioc, /* IoContext */
+int Restart) /* Do we need to restart the Hardware timer ? */
+{
+ SK_U32 Delta;
+ SK_TIMER *pTm;
+ SK_TIMER *pTComp; /* Timer completed now now */
+ SK_TIMER **ppLast; /* Next field of Last timer to be deq */
+ int Done = 0;
+
+ Delta = SkHwtRead(pAC, Ioc);
+
+ ppLast = &pAC->Tim.StQueue;
+ pTm = pAC->Tim.StQueue;
+ while (pTm && !Done) {
+ if (Delta >= pTm->TmDelta) {
+ /* Timer ran out */
+ pTm->TmActive = SK_FALSE;
+ Delta -= pTm->TmDelta;
+ ppLast = &pTm->TmNext;
+ pTm = pTm->TmNext;
+ }
+ else {
+ /* We found the first timer that did not run out */
+ pTm->TmDelta -= Delta;
+ Delta = 0;
+ Done = 1;
+ }
+ }
+ *ppLast = NULL;
+ /*
+ * pTm points to the first Timer that did not run out.
+ * StQueue points to the first Timer that run out.
+ */
+
+ for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) {
+ SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara);
+ }
+
+ /* Set head of timer queue to the first timer that did not run out */
+ pAC->Tim.StQueue = pTm;
+
+ if (Restart && pAC->Tim.StQueue) {
+ /* Restart HW timer */
+ SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
+ }
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c
new file mode 100644
index 000000000000..1e662aaebf84
--- /dev/null
+++ b/drivers/net/sk98lin/skvpd.c
@@ -0,0 +1,1091 @@
+/******************************************************************************
+ *
+ * Name: skvpd.c
+ * Project: GEnesis, PCI Gigabit Ethernet Adapter
+ * Version: $Revision: 1.37 $
+ * Date: $Date: 2003/01/13 10:42:45 $
+ * Purpose: Shared software to read and write VPD data
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ Please refer skvpd.txt for information how to include this module
+ */
+static const char SysKonnectFileId[] =
+ "@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK";
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/skdebug.h"
+#include "h/skdrv2nd.h"
+
+/*
+ * Static functions
+ */
+#ifndef SK_KR_PROTO
+static SK_VPD_PARA *vpd_find_para(
+ SK_AC *pAC,
+ const char *key,
+ SK_VPD_PARA *p);
+#else /* SK_KR_PROTO */
+static SK_VPD_PARA *vpd_find_para();
+#endif /* SK_KR_PROTO */
+
+/*
+ * waits for a completion of a VPD transfer
+ * The VPD transfer must complete within SK_TICKS_PER_SEC/16
+ *
+ * returns 0: success, transfer completes
+ * error exit(9) with a error message
+ */
+static int VpdWait(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC, /* IO Context */
+int event) /* event to wait for (VPD_READ / VPD_write) completion*/
+{
+ SK_U64 start_time;
+ SK_U16 state;
+
+ SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD wait for %s\n", event?"Write":"Read"));
+ start_time = SkOsGetTime(pAC);
+ do {
+ if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC) {
+
+ /* Bug fix AF: Thu Mar 28 2002
+ * Do not call: VPD_STOP(pAC, IoC);
+ * A pending VPD read cycle can not be aborted by writing
+ * VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register).
+ * Although the write threshold in the OUR-register protects
+ * VPD read only space from being overwritten this does not
+ * protect a VPD read from being `converted` into a VPD write
+ * operation (on the fly). As a consequence the VPD_STOP would
+ * delete VPD read only data. In case of any problems with the
+ * I2C bus we exit the loop here. The I2C read operation can
+ * not be aborted except by a reset (->LR).
+ */
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR,
+ ("ERROR:VPD wait timeout\n"));
+ return(1);
+ }
+
+ VPD_IN16(pAC, IoC, PCI_VPD_ADR_REG, &state);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("state = %x, event %x\n",state,event));
+ } while((int)(state & PCI_VPD_FLAG) == event);
+
+ return(0);
+}
+
+#ifdef SKDIAG
+
+/*
+ * Read the dword at address 'addr' from the VPD EEPROM.
+ *
+ * Needed Time: MIN 1,3 ms MAX 2,6 ms
+ *
+ * Note: The DWord is returned in the endianess of the machine the routine
+ * is running on.
+ *
+ * Returns the data read.
+ */
+SK_U32 VpdReadDWord(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC, /* IO Context */
+int addr) /* VPD address */
+{
+ SK_U32 Rtv;
+
+ /* start VPD read */
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD read dword at 0x%x\n",addr));
+ addr &= ~VPD_WRITE; /* ensure the R/W bit is set to read */
+
+ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)addr);
+
+ /* ignore return code here */
+ (void)VpdWait(pAC, IoC, VPD_READ);
+
+ /* Don't swap here, it's a data stream of bytes */
+ Rtv = 0;
+
+ VPD_IN32(pAC, IoC, PCI_VPD_DAT_REG, &Rtv);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD read dword data = 0x%x\n",Rtv));
+ return(Rtv);
+}
+
+#endif /* SKDIAG */
+
+/*
+ * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ * or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdWriteStream(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC, /* IO Context */
+char *buf, /* data buffer */
+int Addr, /* VPD start address */
+int Len) /* number of bytes to read / to write */
+{
+ int i;
+ int j;
+ SK_U16 AdrReg;
+ int Rtv;
+ SK_U8 * pComp; /* Compare pointer */
+ SK_U8 Data; /* Input Data for Compare */
+
+ /* Init Compare Pointer */
+ pComp = (SK_U8 *) buf;
+
+ for (i = 0; i < Len; i++, buf++) {
+ if ((i%sizeof(SK_U32)) == 0) {
+ /*
+ * At the begin of each cycle read the Data Reg
+ * So it is initialized even if only a few bytes
+ * are written.
+ */
+ AdrReg = (SK_U16) Addr;
+ AdrReg &= ~VPD_WRITE; /* READ operation */
+
+ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+ /* Wait for termination */
+ Rtv = VpdWait(pAC, IoC, VPD_READ);
+ if (Rtv != 0) {
+ return(i);
+ }
+ }
+
+ /* Write current Byte */
+ VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+ *(SK_U8*)buf);
+
+ if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
+ /* New Address needs to be written to VPD_ADDR reg */
+ AdrReg = (SK_U16) Addr;
+ Addr += sizeof(SK_U32);
+ AdrReg |= VPD_WRITE; /* WRITE operation */
+
+ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+ /* Wait for termination */
+ Rtv = VpdWait(pAC, IoC, VPD_WRITE);
+ if (Rtv != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("Write Timed Out\n"));
+ return(i - (i%sizeof(SK_U32)));
+ }
+
+ /*
+ * Now re-read to verify
+ */
+ AdrReg &= ~VPD_WRITE; /* READ operation */
+
+ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+ /* Wait for termination */
+ Rtv = VpdWait(pAC, IoC, VPD_READ);
+ if (Rtv != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("Verify Timed Out\n"));
+ return(i - (i%sizeof(SK_U32)));
+ }
+
+ for (j = 0; j <= (int)(i%sizeof(SK_U32)); j++, pComp++) {
+
+ VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data);
+
+ if (Data != *pComp) {
+ /* Verify Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("WriteStream Verify Error\n"));
+ return(i - (i%sizeof(SK_U32)) + j);
+ }
+ }
+ }
+ }
+
+ return(Len);
+}
+
+
+/*
+ * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ * or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdReadStream(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC, /* IO Context */
+char *buf, /* data buffer */
+int Addr, /* VPD start address */
+int Len) /* number of bytes to read / to write */
+{
+ int i;
+ SK_U16 AdrReg;
+ int Rtv;
+
+ for (i = 0; i < Len; i++, buf++) {
+ if ((i%sizeof(SK_U32)) == 0) {
+ /* New Address needs to be written to VPD_ADDR reg */
+ AdrReg = (SK_U16) Addr;
+ Addr += sizeof(SK_U32);
+ AdrReg &= ~VPD_WRITE; /* READ operation */
+
+ VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+ /* Wait for termination */
+ Rtv = VpdWait(pAC, IoC, VPD_READ);
+ if (Rtv != 0) {
+ return(i);
+ }
+ }
+ VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+ (SK_U8 *)buf);
+ }
+
+ return(Len);
+}
+
+/*
+ * Read ore writes 'len' bytes of VPD data, starting at 'addr' from
+ * or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdTransferBlock(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC, /* IO Context */
+char *buf, /* data buffer */
+int addr, /* VPD start address */
+int len, /* number of bytes to read / to write */
+int dir) /* transfer direction may be VPD_READ or VPD_WRITE */
+{
+ int Rtv; /* Return value */
+ int vpd_rom_size;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD %s block, addr = 0x%x, len = %d\n",
+ dir ? "write" : "read", addr, len));
+
+ if (len == 0)
+ return(0);
+
+ vpd_rom_size = pAC->vpd.rom_size;
+
+ if (addr > vpd_rom_size - 4) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Address error: 0x%x, exp. < 0x%x\n",
+ addr, vpd_rom_size - 4));
+ return(0);
+ }
+
+ if (addr + len > vpd_rom_size) {
+ len = vpd_rom_size - addr;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("Warning: len was cut to %d\n", len));
+ }
+
+ if (dir == VPD_READ) {
+ Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
+ }
+ else {
+ Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
+ }
+
+ return(Rtv);
+}
+
+#ifdef SKDIAG
+
+/*
+ * Read 'len' bytes of VPD data, starting at 'addr'.
+ *
+ * Returns number of bytes read.
+ */
+int VpdReadBlock(
+SK_AC *pAC, /* pAC pointer */
+SK_IOC IoC, /* IO Context */
+char *buf, /* buffer were the data should be stored */
+int addr, /* start reading at the VPD address */
+int len) /* number of bytes to read */
+{
+ return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ));
+}
+
+/*
+ * Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'.
+ *
+ * Returns number of bytes writes.
+ */
+int VpdWriteBlock(
+SK_AC *pAC, /* pAC pointer */
+SK_IOC IoC, /* IO Context */
+char *buf, /* buffer, holds the data to write */
+int addr, /* start writing at the VPD address */
+int len) /* number of bytes to write */
+{
+ return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE));
+}
+#endif /* SKDIAG */
+
+/*
+ * (re)initialize the VPD buffer
+ *
+ * Reads the VPD data from the EEPROM into the VPD buffer.
+ * Get the remaining read only and read / write space.
+ *
+ * return 0: success
+ * 1: fatal VPD error
+ */
+static int VpdInit(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC) /* IO Context */
+{
+ SK_VPD_PARA *r, rp; /* RW or RV */
+ int i;
+ unsigned char x;
+ int vpd_size;
+ SK_U16 dev_id;
+ SK_U32 our_reg2;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, ("VpdInit .. "));
+
+ VPD_IN16(pAC, IoC, PCI_DEVICE_ID, &dev_id);
+
+ VPD_IN32(pAC, IoC, PCI_OUR_REG_2, &our_reg2);
+
+ pAC->vpd.rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+
+ /*
+ * this function might get used before the hardware is initialized
+ * therefore we cannot always trust in GIChipId
+ */
+ if (((pAC->vpd.v.vpd_status & VPD_VALID) == 0 &&
+ dev_id != VPD_DEV_ID_GENESIS) ||
+ ((pAC->vpd.v.vpd_status & VPD_VALID) != 0 &&
+ !pAC->GIni.GIGenesis)) {
+
+ /* for Yukon the VPD size is always 256 */
+ vpd_size = VPD_SIZE_YUKON;
+ }
+ else {
+ /* Genesis uses the maximum ROM size up to 512 for VPD */
+ if (pAC->vpd.rom_size > VPD_SIZE_GENESIS) {
+ vpd_size = VPD_SIZE_GENESIS;
+ }
+ else {
+ vpd_size = pAC->vpd.rom_size;
+ }
+ }
+
+ /* read the VPD data into the VPD buffer */
+ if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf, 0, vpd_size, VPD_READ)
+ != vpd_size) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("Block Read Error\n"));
+ return(1);
+ }
+
+ pAC->vpd.vpd_size = vpd_size;
+
+ /* Asus K8V Se Deluxe bugfix. Correct VPD content */
+ /* MBo April 2004 */
+ if (((unsigned char)pAC->vpd.vpd_buf[0x3f] == 0x38) &&
+ ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) &&
+ ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45)) {
+ printk("sk98lin: Asus mainboard with buggy VPD? "
+ "Correcting data.\n");
+ pAC->vpd.vpd_buf[0x40] = 0x38;
+ }
+
+
+ /* find the end tag of the RO area */
+ if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Encoding Error: RV Tag not found\n"));
+ return(1);
+ }
+
+ if (r->p_val + r->p_len > pAC->vpd.vpd_buf + vpd_size/2) {
+ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Encoding Error: Invalid VPD struct size\n"));
+ return(1);
+ }
+ pAC->vpd.v.vpd_free_ro = r->p_len - 1;
+
+ /* test the checksum */
+ for (i = 0, x = 0; (unsigned)i <= (unsigned)vpd_size/2 - r->p_len; i++) {
+ x += pAC->vpd.vpd_buf[i];
+ }
+
+ if (x != 0) {
+ /* checksum error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("VPD Checksum Error\n"));
+ return(1);
+ }
+
+ /* find and check the end tag of the RW area */
+ if (!(r = vpd_find_para(pAC, VPD_RW, &rp))) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Encoding Error: RV Tag not found\n"));
+ return(1);
+ }
+
+ if (r->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Encoding Error: Invalid VPD struct size\n"));
+ return(1);
+ }
+ pAC->vpd.v.vpd_free_rw = r->p_len;
+
+ /* everything seems to be ok */
+ if (pAC->GIni.GIChipId != 0) {
+ pAC->vpd.v.vpd_status |= VPD_VALID;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT,
+ ("done. Free RO = %d, Free RW = %d\n",
+ pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+ return(0);
+}
+
+/*
+ * find the Keyword 'key' in the VPD buffer and fills the
+ * parameter struct 'p' with it's values
+ *
+ * returns *p success
+ * 0: parameter was not found or VPD encoding error
+ */
+static SK_VPD_PARA *vpd_find_para(
+SK_AC *pAC, /* common data base */
+const char *key, /* keyword to find (e.g. "MN") */
+SK_VPD_PARA *p) /* parameter description struct */
+{
+ char *v ; /* points to VPD buffer */
+ int max; /* Maximum Number of Iterations */
+
+ v = pAC->vpd.vpd_buf;
+ max = 128;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD find para %s .. ",key));
+
+ /* check mandatory resource type ID string (Product Name) */
+ if (*v != (char)RES_ID) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Error: 0x%x missing\n", RES_ID));
+ return NULL;
+ }
+
+ if (strcmp(key, VPD_NAME) == 0) {
+ p->p_len = VPD_GET_RES_LEN(v);
+ p->p_val = VPD_GET_VAL(v);
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("found, len = %d\n", p->p_len));
+ return(p);
+ }
+
+ v += 3 + VPD_GET_RES_LEN(v) + 3;
+ for (;; ) {
+ if (SK_MEMCMP(key,v,2) == 0) {
+ p->p_len = VPD_GET_VPD_LEN(v);
+ p->p_val = VPD_GET_VAL(v);
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("found, len = %d\n",p->p_len));
+ return(p);
+ }
+
+ /* exit when reaching the "RW" Tag or the maximum of itera. */
+ max--;
+ if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
+ break;
+ }
+
+ if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+ v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */
+ }
+ else {
+ v += 3 + VPD_GET_VPD_LEN(v);
+ }
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("scanning '%c%c' len = %d\n",v[0],v[1],v[2]));
+ }
+
+#ifdef DEBUG
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("not found\n"));
+ if (max == 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Key/Len Encoding error\n"));
+ }
+#endif /* DEBUG */
+ return NULL;
+}
+
+/*
+ * Move 'n' bytes. Begin with the last byte if 'n' is > 0,
+ * Start with the last byte if n is < 0.
+ *
+ * returns nothing
+ */
+static void vpd_move_para(
+char *start, /* start of memory block */
+char *end, /* end of memory block to move */
+int n) /* number of bytes the memory block has to be moved */
+{
+ char *p;
+ int i; /* number of byte copied */
+
+ if (n == 0)
+ return;
+
+ i = (int) (end - start + 1);
+ if (n < 0) {
+ p = start + n;
+ while (i != 0) {
+ *p++ = *start++;
+ i--;
+ }
+ }
+ else {
+ p = end + n;
+ while (i != 0) {
+ *p-- = *end--;
+ i--;
+ }
+ }
+}
+
+/*
+ * setup the VPD keyword 'key' at 'ip'.
+ *
+ * returns nothing
+ */
+static void vpd_insert_key(
+const char *key, /* keyword to insert */
+const char *buf, /* buffer with the keyword value */
+int len, /* length of the value string */
+char *ip) /* inseration point */
+{
+ SK_VPD_KEY *p;
+
+ p = (SK_VPD_KEY *) ip;
+ p->p_key[0] = key[0];
+ p->p_key[1] = key[1];
+ p->p_len = (unsigned char) len;
+ SK_MEMCPY(&p->p_val,buf,len);
+}
+
+/*
+ * Setup the VPD end tag "RV" / "RW".
+ * Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
+ *
+ * returns 0: success
+ * 1: encoding error
+ */
+static int vpd_mod_endtag(
+SK_AC *pAC, /* common data base */
+char *etp) /* end pointer input position */
+{
+ SK_VPD_KEY *p;
+ unsigned char x;
+ int i;
+ int vpd_size;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
+
+ vpd_size = pAC->vpd.vpd_size;
+
+ p = (SK_VPD_KEY *) etp;
+
+ if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
+ /* something wrong here, encoding error */
+ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+ ("Encoding Error: invalid end tag\n"));
+ return(1);
+ }
+ if (etp > pAC->vpd.vpd_buf + vpd_size/2) {
+ /* create "RW" tag */
+ p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size-etp-3-1);
+ pAC->vpd.v.vpd_free_rw = (int) p->p_len;
+ i = pAC->vpd.v.vpd_free_rw;
+ etp += 3;
+ }
+ else {
+ /* create "RV" tag */
+ p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size/2-etp-3);
+ pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1;
+
+ /* setup checksum */
+ for (i = 0, x = 0; i < vpd_size/2 - p->p_len; i++) {
+ x += pAC->vpd.vpd_buf[i];
+ }
+ p->p_val = (char) 0 - x;
+ i = pAC->vpd.v.vpd_free_ro;
+ etp += 4;
+ }
+ while (i) {
+ *etp++ = 0x00;
+ i--;
+ }
+
+ return(0);
+}
+
+/*
+ * Insert a VPD keyword into the VPD buffer.
+ *
+ * The keyword 'key' is inserted at the position 'ip' in the
+ * VPD buffer.
+ * The keywords behind the input position will
+ * be moved. The VPD end tag "RV" or "RW" is generated again.
+ *
+ * returns 0: success
+ * 2: value string was cut
+ * 4: VPD full, keyword was not written
+ * 6: fatal VPD error
+ *
+ */
+static int VpdSetupPara(
+SK_AC *pAC, /* common data base */
+const char *key, /* keyword to insert */
+const char *buf, /* buffer with the keyword value */
+int len, /* length of the keyword value */
+int type, /* VPD_RO_KEY or VPD_RW_KEY */
+int op) /* operation to do: ADD_KEY or OWR_KEY */
+{
+ SK_VPD_PARA vp;
+ char *etp; /* end tag position */
+ int free; /* remaining space in selected area */
+ char *ip; /* input position inside the VPD buffer */
+ int rtv; /* return code */
+ int head; /* additional haeder bytes to move */
+ int found; /* additinoal bytes if the keyword was found */
+ int vpd_size;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("VPD setup para key = %s, val = %s\n",key,buf));
+
+ vpd_size = pAC->vpd.vpd_size;
+
+ rtv = 0;
+ ip = NULL;
+ if (type == VPD_RW_KEY) {
+ /* end tag is "RW" */
+ free = pAC->vpd.v.vpd_free_rw;
+ etp = pAC->vpd.vpd_buf + (vpd_size - free - 1 - 3);
+ }
+ else {
+ /* end tag is "RV" */
+ free = pAC->vpd.v.vpd_free_ro;
+ etp = pAC->vpd.vpd_buf + (vpd_size/2 - free - 4);
+ }
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("Free RO = %d, Free RW = %d\n",
+ pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+ head = 0;
+ found = 0;
+ if (op == OWR_KEY) {
+ if (vpd_find_para(pAC, key, &vp)) {
+ found = 3;
+ ip = vp.p_val - 3;
+ free += vp.p_len + 3;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("Overwrite Key\n"));
+ }
+ else {
+ op = ADD_KEY;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+ ("Add Key\n"));
+ }
+ }
+ if (op == ADD_KEY) {
+ ip = etp;
+ vp.p_len = 0;
+ head = 3;
+ }
+
+ if (len + 3 > free) {
+ if (free < 7) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD Buffer Overflow, keyword not written\n"));
+ return(4);
+ }
+ /* cut it again */
+ len = free - 3;
+ rtv = 2;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD Buffer Full, Keyword was cut\n"));
+ }
+
+ vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head);
+ vpd_insert_key(key, buf, len, ip);
+ if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
+ pAC->vpd.v.vpd_status &= ~VPD_VALID;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD Encoding Error\n"));
+ return(6);
+ }
+
+ return(rtv);
+}
+
+
+/*
+ * Read the contents of the VPD EEPROM and copy it to the
+ * VPD buffer if not already done.
+ *
+ * return: A pointer to the vpd_status structure. The structure contains
+ * this fields.
+ */
+SK_VPD_STATUS *VpdStat(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC) /* IO Context */
+{
+ if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+ (void)VpdInit(pAC, IoC);
+ }
+ return(&pAC->vpd.v);
+}
+
+
+/*
+ * Read the contents of the VPD EEPROM and copy it to the VPD
+ * buffer if not already done.
+ * Scan the VPD buffer for VPD keywords and create the VPD
+ * keyword list by copying the keywords to 'buf', all after
+ * each other and terminated with a '\0'.
+ *
+ * Exceptions: o The Resource Type ID String (product name) is called "Name"
+ * o The VPD end tags 'RV' and 'RW' are not listed
+ *
+ * The number of copied keywords is counted in 'elements'.
+ *
+ * returns 0: success
+ * 2: buffer overfull, one or more keywords are missing
+ * 6: fatal VPD error
+ *
+ * example values after returning:
+ *
+ * buf = "Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
+ * *len = 30
+ * *elements = 9
+ */
+int VpdKeys(
+SK_AC *pAC, /* common data base */
+SK_IOC IoC, /* IO Context */
+char *buf, /* buffer where to copy the keywords */
+int *len, /* buffer length */
+int *elements) /* number of keywords returned */
+{
+ char *v;
+ int n;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("list VPD keys .. "));
+ *elements = 0;
+ if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+ if (VpdInit(pAC, IoC) != 0) {
+ *len = 0;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD Init Error, terminated\n"));
+ return(6);
+ }
+ }
+
+ if ((signed)strlen(VPD_NAME) + 1 <= *len) {
+ v = pAC->vpd.vpd_buf;
+ strcpy(buf,VPD_NAME);
+ n = strlen(VPD_NAME) + 1;
+ buf += n;
+ *elements = 1;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+ ("'%c%c' ",v[0],v[1]));
+ }
+ else {
+ *len = 0;
+ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+ ("buffer overflow\n"));
+ return(2);
+ }
+
+ v += 3 + VPD_GET_RES_LEN(v) + 3;
+ for (;; ) {
+ /* exit when reaching the "RW" Tag */
+ if (SK_MEMCMP(VPD_RW,v,2) == 0) {
+ break;
+ }
+
+ if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+ v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */
+ continue;
+ }
+
+ if (n+3 <= *len) {
+ SK_MEMCPY(buf,v,2);
+ buf += 2;
+ *buf++ = '\0';
+ n += 3;
+ v += 3 + VPD_GET_VPD_LEN(v);
+ *elements += 1;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+ ("'%c%c' ",v[0],v[1]));
+ }
+ else {
+ *len = n;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("buffer overflow\n"));
+ return(2);
+ }
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("\n"));
+ *len = n;
+ return(0);
+}
+
+
+/*
+ * Read the contents of the VPD EEPROM and copy it to the
+ * VPD buffer if not already done. Search for the VPD keyword
+ * 'key' and copy its value to 'buf'. Add a terminating '\0'.
+ * If the value does not fit into the buffer cut it after
+ * 'len' - 1 bytes.
+ *
+ * returns 0: success
+ * 1: keyword not found
+ * 2: value string was cut
+ * 3: VPD transfer timeout
+ * 6: fatal VPD error
+ */
+int VpdRead(
+SK_AC *pAC, /* common data base */
+SK_IOC IoC, /* IO Context */
+const char *key, /* keyword to read (e.g. "MN") */
+char *buf, /* buffer where to copy the keyword value */
+int *len) /* buffer length */
+{
+ SK_VPD_PARA *p, vp;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("VPD read %s .. ", key));
+ if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+ if (VpdInit(pAC, IoC) != 0) {
+ *len = 0;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD init error\n"));
+ return(6);
+ }
+ }
+
+ if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+ if (p->p_len > (*(unsigned *)len)-1) {
+ p->p_len = *len - 1;
+ }
+ SK_MEMCPY(buf, p->p_val, p->p_len);
+ buf[p->p_len] = '\0';
+ *len = p->p_len;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+ ("%c%c%c%c.., len = %d\n",
+ buf[0],buf[1],buf[2],buf[3],*len));
+ }
+ else {
+ *len = 0;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n"));
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * Check whether a given key may be written
+ *
+ * returns
+ * SK_TRUE Yes it may be written
+ * SK_FALSE No it may be written
+ */
+SK_BOOL VpdMayWrite(
+char *key) /* keyword to write (allowed values "Yx", "Vx") */
+{
+ if ((*key != 'Y' && *key != 'V') ||
+ key[1] < '0' || key[1] > 'Z' ||
+ (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+ return(SK_FALSE);
+ }
+ return(SK_TRUE);
+}
+
+/*
+ * Read the contents of the VPD EEPROM and copy it to the VPD
+ * buffer if not already done. Insert/overwrite the keyword 'key'
+ * in the VPD buffer. Cut the keyword value if it does not fit
+ * into the VPD read / write area.
+ *
+ * returns 0: success
+ * 2: value string was cut
+ * 3: VPD transfer timeout
+ * 4: VPD full, keyword was not written
+ * 5: keyword cannot be written
+ * 6: fatal VPD error
+ */
+int VpdWrite(
+SK_AC *pAC, /* common data base */
+SK_IOC IoC, /* IO Context */
+const char *key, /* keyword to write (allowed values "Yx", "Vx") */
+const char *buf) /* buffer where the keyword value can be read from */
+{
+ int len; /* length of the keyword to write */
+ int rtv; /* return code */
+ int rtv2;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+ ("VPD write %s = %s\n",key,buf));
+
+ if ((*key != 'Y' && *key != 'V') ||
+ key[1] < '0' || key[1] > 'Z' ||
+ (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("illegal key tag, keyword not written\n"));
+ return(5);
+ }
+
+ if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+ if (VpdInit(pAC, IoC) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD init error\n"));
+ return(6);
+ }
+ }
+
+ rtv = 0;
+ len = strlen(buf);
+ if (len > VPD_MAX_LEN) {
+ /* cut it */
+ len = VPD_MAX_LEN;
+ rtv = 2;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("keyword too long, cut after %d bytes\n",VPD_MAX_LEN));
+ }
+ if ((rtv2 = VpdSetupPara(pAC, key, buf, len, VPD_RW_KEY, OWR_KEY)) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD write error\n"));
+ return(rtv2);
+ }
+
+ return(rtv);
+}
+
+/*
+ * Read the contents of the VPD EEPROM and copy it to the
+ * VPD buffer if not already done. Remove the VPD keyword
+ * 'key' from the VPD buffer.
+ * Only the keywords in the read/write area can be deleted.
+ * Keywords in the read only area cannot be deleted.
+ *
+ * returns 0: success, keyword was removed
+ * 1: keyword not found
+ * 5: keyword cannot be deleted
+ * 6: fatal VPD error
+ */
+int VpdDelete(
+SK_AC *pAC, /* common data base */
+SK_IOC IoC, /* IO Context */
+char *key) /* keyword to read (e.g. "MN") */
+{
+ SK_VPD_PARA *p, vp;
+ char *etp;
+ int vpd_size;
+
+ vpd_size = pAC->vpd.vpd_size;
+
+ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("VPD delete key %s\n",key));
+ if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+ if (VpdInit(pAC, IoC) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD init error\n"));
+ return(6);
+ }
+ }
+
+ if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+ if (p->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+ /* try to delete read only keyword */
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("cannot delete RO keyword\n"));
+ return(5);
+ }
+
+ etp = pAC->vpd.vpd_buf + (vpd_size-pAC->vpd.v.vpd_free_rw-1-3);
+
+ vpd_move_para(vp.p_val+vp.p_len, etp+2,
+ - ((int)(vp.p_len + 3)));
+ if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
+ pAC->vpd.v.vpd_status &= ~VPD_VALID;
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("VPD encoding error\n"));
+ return(6);
+ }
+ }
+ else {
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("keyword not found\n"));
+ return(1);
+ }
+
+ return(0);
+}
+
+/*
+ * If the VPD buffer contains valid data write the VPD
+ * read/write area back to the VPD EEPROM.
+ *
+ * returns 0: success
+ * 3: VPD transfer timeout
+ */
+int VpdUpdate(
+SK_AC *pAC, /* Adapters context */
+SK_IOC IoC) /* IO Context */
+{
+ int vpd_size;
+
+ vpd_size = pAC->vpd.vpd_size;
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("VPD update .. "));
+ if ((pAC->vpd.v.vpd_status & VPD_VALID) != 0) {
+ if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf + vpd_size/2,
+ vpd_size/2, vpd_size/2, VPD_WRITE) != vpd_size/2) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+ ("transfer timed out\n"));
+ return(3);
+ }
+ }
+ SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("done\n"));
+ return(0);
+}
+
diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c
new file mode 100644
index 000000000000..b4e75022a657
--- /dev/null
+++ b/drivers/net/sk98lin/skxmac2.c
@@ -0,0 +1,4160 @@
+/******************************************************************************
+ *
+ * Name: skxmac2.c
+ * Project: Gigabit Ethernet Adapters, Common Modules
+ * Version: $Revision: 1.102 $
+ * Date: $Date: 2003/10/02 16:53:58 $
+ * Purpose: Contains functions to initialize the MACs and PHYs
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * (C)Copyright 1998-2002 SysKonnect.
+ * (C)Copyright 2002-2003 Marvell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* typedefs *******************************************************************/
+
+/* BCOM PHY magic pattern list */
+typedef struct s_PhyHack {
+ int PhyReg; /* Phy register */
+ SK_U16 PhyVal; /* Value to write */
+} BCOM_HACK;
+
+/* local variables ************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+ "@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#ifdef GENESIS
+static BCOM_HACK BcomRegA1Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
+ { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
+ { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+static BCOM_HACK BcomRegC0Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
+ { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+#endif
+
+/* function prototypes ********************************************************/
+#ifdef GENESIS
+static void SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static int SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
+static int SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
+#endif /* GENESIS */
+#ifdef YUKON
+static void SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL);
+static int SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int);
+#endif /* YUKON */
+#ifdef OTHER_PHY
+static void SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static int SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
+static int SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+#endif /* OTHER_PHY */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmPhyRead() - Read from XMAC PHY register
+ *
+ * Description: reads a 16-bit word from XMAC PHY or ext. PHY
+ *
+ * Returns:
+ * nothing
+ */
+void SkXmPhyRead(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Port, /* Port Index (MAC_1 + n) */
+int PhyReg, /* Register Address (Offset) */
+SK_U16 SK_FAR *pVal) /* Pointer to Value */
+{
+ SK_U16 Mmu;
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* write the PHY register's address */
+ XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+
+ /* get the PHY register's value */
+ XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+
+ if (pPrt->PhyType != SK_PHY_XMAC) {
+ do {
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+ /* wait until 'Ready' is set */
+ } while ((Mmu & XM_MMU_PHY_RDY) == 0);
+
+ /* get the PHY register's value */
+ XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+ }
+} /* SkXmPhyRead */
+
+
+/******************************************************************************
+ *
+ * SkXmPhyWrite() - Write to XMAC PHY register
+ *
+ * Description: writes a 16-bit word to XMAC PHY or ext. PHY
+ *
+ * Returns:
+ * nothing
+ */
+void SkXmPhyWrite(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Port, /* Port Index (MAC_1 + n) */
+int PhyReg, /* Register Address (Offset) */
+SK_U16 Val) /* Value */
+{
+ SK_U16 Mmu;
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PhyType != SK_PHY_XMAC) {
+ do {
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+ /* wait until 'Busy' is cleared */
+ } while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+ }
+
+ /* write the PHY register's address */
+ XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+
+ /* write the PHY register's value */
+ XM_OUT16(IoC, Port, XM_PHY_DATA, Val);
+
+ if (pPrt->PhyType != SK_PHY_XMAC) {
+ do {
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+ /* wait until 'Busy' is cleared */
+ } while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+ }
+} /* SkXmPhyWrite */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmPhyRead() - Read from GPHY register
+ *
+ * Description: reads a 16-bit word from GPHY through MDIO
+ *
+ * Returns:
+ * nothing
+ */
+void SkGmPhyRead(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Port, /* Port Index (MAC_1 + n) */
+int PhyReg, /* Register Address (Offset) */
+SK_U16 SK_FAR *pVal) /* Pointer to Value */
+{
+ SK_U16 Ctrl;
+ SK_GEPORT *pPrt;
+#ifdef VCPU
+ u_long SimCyle;
+ u_long SimLowTime;
+
+ VCPUgetTime(&SimCyle, &SimLowTime);
+ VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n",
+ PhyReg, SimCyle, SimLowTime);
+#endif /* VCPU */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* set PHY-Register offset and 'Read' OpCode (= 1) */
+ *pVal = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) |
+ GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD);
+
+ GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal);
+
+ GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+ /* additional check for MDC/MDIO activity */
+ if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+ *pVal = 0;
+ return;
+ }
+
+ *pVal |= GM_SMI_CT_BUSY;
+
+ do {
+#ifdef VCPU
+ VCPUwaitTime(1000);
+#endif /* VCPU */
+
+ GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+ /* wait until 'ReadValid' is set */
+ } while (Ctrl == *pVal);
+
+ /* get the PHY register's value */
+ GM_IN16(IoC, Port, GM_SMI_DATA, pVal);
+
+#ifdef VCPU
+ VCPUgetTime(&SimCyle, &SimLowTime);
+ VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+ SimCyle, SimLowTime);
+#endif /* VCPU */
+
+} /* SkGmPhyRead */
+
+
+/******************************************************************************
+ *
+ * SkGmPhyWrite() - Write to GPHY register
+ *
+ * Description: writes a 16-bit word to GPHY through MDIO
+ *
+ * Returns:
+ * nothing
+ */
+void SkGmPhyWrite(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Port, /* Port Index (MAC_1 + n) */
+int PhyReg, /* Register Address (Offset) */
+SK_U16 Val) /* Value */
+{
+ SK_U16 Ctrl;
+ SK_GEPORT *pPrt;
+#ifdef VCPU
+ SK_U32 DWord;
+ u_long SimCyle;
+ u_long SimLowTime;
+
+ VCPUgetTime(&SimCyle, &SimLowTime);
+ VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n",
+ PhyReg, Val, SimCyle, SimLowTime);
+#endif /* VCPU */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* write the PHY register's value */
+ GM_OUT16(IoC, Port, GM_SMI_DATA, Val);
+
+ /* set PHY-Register offset and 'Write' OpCode (= 0) */
+ Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg);
+
+ GM_OUT16(IoC, Port, GM_SMI_CTRL, Val);
+
+ GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+ /* additional check for MDC/MDIO activity */
+ if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+ return;
+ }
+
+ Val |= GM_SMI_CT_BUSY;
+
+ do {
+#ifdef VCPU
+ /* read Timer value */
+ SK_IN32(IoC, B2_TI_VAL, &DWord);
+
+ VCPUwaitTime(1000);
+#endif /* VCPU */
+
+ GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+ /* wait until 'Busy' is cleared */
+ } while (Ctrl == Val);
+
+#ifdef VCPU
+ VCPUgetTime(&SimCyle, &SimLowTime);
+ VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+ SimCyle, SimLowTime);
+#endif /* VCPU */
+
+} /* SkGmPhyWrite */
+#endif /* YUKON */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ * SkGePhyRead() - Read from PHY register
+ *
+ * Description: calls a read PHY routine dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkGePhyRead(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Port, /* Port Index (MAC_1 + n) */
+int PhyReg, /* Register Address (Offset) */
+SK_U16 *pVal) /* Pointer to Value */
+{
+ void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal);
+
+ if (pAC->GIni.GIGenesis) {
+ r_func = SkXmPhyRead;
+ }
+ else {
+ r_func = SkGmPhyRead;
+ }
+
+ r_func(pAC, IoC, Port, PhyReg, pVal);
+} /* SkGePhyRead */
+
+
+/******************************************************************************
+ *
+ * SkGePhyWrite() - Write to PHY register
+ *
+ * Description: calls a write PHY routine dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkGePhyWrite(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* I/O Context */
+int Port, /* Port Index (MAC_1 + n) */
+int PhyReg, /* Register Address (Offset) */
+SK_U16 Val) /* Value */
+{
+ void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val);
+
+ if (pAC->GIni.GIGenesis) {
+ w_func = SkXmPhyWrite;
+ }
+ else {
+ w_func = SkGmPhyWrite;
+ }
+
+ w_func(pAC, IoC, Port, PhyReg, Val);
+} /* SkGePhyWrite */
+#endif /* SK_DIAG */
+
+
+/******************************************************************************
+ *
+ * SkMacPromiscMode() - Enable / Disable Promiscuous Mode
+ *
+ * Description:
+ * enables / disables promiscuous mode by setting Mode Register (XMAC) or
+ * Receive Control Register (GMAC) dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacPromiscMode(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL Enable) /* Enable / Disable */
+{
+#ifdef YUKON
+ SK_U16 RcReg;
+#endif
+#ifdef GENESIS
+ SK_U32 MdReg;
+#endif
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN32(IoC, Port, XM_MODE, &MdReg);
+ /* enable or disable promiscuous mode */
+ if (Enable) {
+ MdReg |= XM_MD_ENA_PROM;
+ }
+ else {
+ MdReg &= ~XM_MD_ENA_PROM;
+ }
+ /* setup Mode Register */
+ XM_OUT32(IoC, Port, XM_MODE, MdReg);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+
+ /* enable or disable unicast and multicast filtering */
+ if (Enable) {
+ RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+ }
+ else {
+ RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+ }
+ /* setup Receive Control Register */
+ GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+ }
+#endif /* YUKON */
+
+} /* SkMacPromiscMode*/
+
+
+/******************************************************************************
+ *
+ * SkMacHashing() - Enable / Disable Hashing
+ *
+ * Description:
+ * enables / disables hashing by setting Mode Register (XMAC) or
+ * Receive Control Register (GMAC) dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacHashing(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL Enable) /* Enable / Disable */
+{
+#ifdef YUKON
+ SK_U16 RcReg;
+#endif
+#ifdef GENESIS
+ SK_U32 MdReg;
+#endif
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN32(IoC, Port, XM_MODE, &MdReg);
+ /* enable or disable hashing */
+ if (Enable) {
+ MdReg |= XM_MD_ENA_HASH;
+ }
+ else {
+ MdReg &= ~XM_MD_ENA_HASH;
+ }
+ /* setup Mode Register */
+ XM_OUT32(IoC, Port, XM_MODE, MdReg);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+
+ /* enable or disable multicast filtering */
+ if (Enable) {
+ RcReg |= GM_RXCR_MCF_ENA;
+ }
+ else {
+ RcReg &= ~GM_RXCR_MCF_ENA;
+ }
+ /* setup Receive Control Register */
+ GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+ }
+#endif /* YUKON */
+
+} /* SkMacHashing*/
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ * SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register
+ *
+ * Description:
+ * The features
+ * - FCS stripping, SK_STRIP_FCS_ON/OFF
+ * - pad byte stripping, SK_STRIP_PAD_ON/OFF
+ * - don't set XMR_FS_ERR in status SK_LENERR_OK_ON/OFF
+ * for inrange length error frames
+ * - don't set XMR_FS_ERR in status SK_BIG_PK_OK_ON/OFF
+ * for frames > 1514 bytes
+ * - enable Rx of own packets SK_SELF_RX_ON/OFF
+ *
+ * for incoming packets may be enabled/disabled by this function.
+ * Additional modes may be added later.
+ * Multiple modes can be enabled/disabled at the same time.
+ * The new configuration is written to the Rx Command register immediately.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmSetRxCmd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+ SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+ SK_U16 OldRxCmd;
+ SK_U16 RxCmd;
+
+ XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd);
+
+ RxCmd = OldRxCmd;
+
+ switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+ case SK_STRIP_FCS_ON:
+ RxCmd |= XM_RX_STRIP_FCS;
+ break;
+ case SK_STRIP_FCS_OFF:
+ RxCmd &= ~XM_RX_STRIP_FCS;
+ break;
+ }
+
+ switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+ case SK_STRIP_PAD_ON:
+ RxCmd |= XM_RX_STRIP_PAD;
+ break;
+ case SK_STRIP_PAD_OFF:
+ RxCmd &= ~XM_RX_STRIP_PAD;
+ break;
+ }
+
+ switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+ case SK_LENERR_OK_ON:
+ RxCmd |= XM_RX_LENERR_OK;
+ break;
+ case SK_LENERR_OK_OFF:
+ RxCmd &= ~XM_RX_LENERR_OK;
+ break;
+ }
+
+ switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+ case SK_BIG_PK_OK_ON:
+ RxCmd |= XM_RX_BIG_PK_OK;
+ break;
+ case SK_BIG_PK_OK_OFF:
+ RxCmd &= ~XM_RX_BIG_PK_OK;
+ break;
+ }
+
+ switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) {
+ case SK_SELF_RX_ON:
+ RxCmd |= XM_RX_SELF_RX;
+ break;
+ case SK_SELF_RX_OFF:
+ RxCmd &= ~XM_RX_SELF_RX;
+ break;
+ }
+
+ /* Write the new mode to the Rx command register if required */
+ if (OldRxCmd != RxCmd) {
+ XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd);
+ }
+} /* SkXmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ * SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register
+ *
+ * Description:
+ * The features
+ * - FCS (CRC) stripping, SK_STRIP_FCS_ON/OFF
+ * - don't set GMR_FS_LONG_ERR SK_BIG_PK_OK_ON/OFF
+ * for frames > 1514 bytes
+ * - enable Rx of own packets SK_SELF_RX_ON/OFF
+ *
+ * for incoming packets may be enabled/disabled by this function.
+ * Additional modes may be added later.
+ * Multiple modes can be enabled/disabled at the same time.
+ * The new configuration is written to the Rx Command register immediately.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGmSetRxCmd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+ SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+ SK_U16 OldRxCmd;
+ SK_U16 RxCmd;
+
+ if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) {
+
+ GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd);
+
+ RxCmd = OldRxCmd;
+
+ if ((Mode & SK_STRIP_FCS_ON) != 0) {
+ RxCmd |= GM_RXCR_CRC_DIS;
+ }
+ else {
+ RxCmd &= ~GM_RXCR_CRC_DIS;
+ }
+ /* Write the new mode to the Rx control register if required */
+ if (OldRxCmd != RxCmd) {
+ GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd);
+ }
+ }
+
+ if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) {
+
+ GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd);
+
+ RxCmd = OldRxCmd;
+
+ if ((Mode & SK_BIG_PK_OK_ON) != 0) {
+ RxCmd |= GM_SMOD_JUMBO_ENA;
+ }
+ else {
+ RxCmd &= ~GM_SMOD_JUMBO_ENA;
+ }
+ /* Write the new mode to the Rx control register if required */
+ if (OldRxCmd != RxCmd) {
+ GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd);
+ }
+ }
+} /* SkGmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ * SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register
+ *
+ * Description: modifies the MAC's Rx Control reg. dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacSetRxCmd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+int Mode) /* Rx Mode */
+{
+ if (pAC->GIni.GIGenesis) {
+
+ SkXmSetRxCmd(pAC, IoC, Port, Mode);
+ }
+ else {
+
+ SkGmSetRxCmd(pAC, IoC, Port, Mode);
+ }
+
+} /* SkMacSetRxCmd */
+
+
+/******************************************************************************
+ *
+ * SkMacCrcGener() - Enable / Disable CRC Generation
+ *
+ * Description: enables / disables CRC generation dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacCrcGener(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL Enable) /* Enable / Disable */
+{
+ SK_U16 Word;
+
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN16(IoC, Port, XM_TX_CMD, &Word);
+
+ if (Enable) {
+ Word &= ~XM_TX_NO_CRC;
+ }
+ else {
+ Word |= XM_TX_NO_CRC;
+ }
+ /* setup Tx Command Register */
+ XM_OUT16(IoC, Port, XM_TX_CMD, Word);
+ }
+ else {
+
+ GM_IN16(IoC, Port, GM_TX_CTRL, &Word);
+
+ if (Enable) {
+ Word &= ~GM_TXCR_CRC_DIS;
+ }
+ else {
+ Word |= GM_TXCR_CRC_DIS;
+ }
+ /* setup Tx Control Register */
+ GM_OUT16(IoC, Port, GM_TX_CTRL, Word);
+ }
+
+} /* SkMacCrcGener*/
+
+#endif /* SK_DIAG */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *
+ * Description:
+ * All Exact Match Address registers of the XMAC 'Port' will be
+ * cleared starting with 'StartNum' up to (and including) the
+ * Exact Match address number of 'StopNum'.
+ *
+ * Returns:
+ * nothing
+ */
+void SkXmClrExactAddr(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+int StartNum, /* Begin with this Address Register Index (0..15) */
+int StopNum) /* Stop after finished with this Register Idx (0..15) */
+{
+ int i;
+ SK_U16 ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
+
+ if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
+ StartNum > StopNum) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+ return;
+ }
+
+ for (i = StartNum; i <= StopNum; i++) {
+ XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+ }
+} /* SkXmClrExactAddr */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkMacFlushTxFifo() - Flush the MAC's transmit FIFO
+ *
+ * Description:
+ * Flush the transmit FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacFlushTxFifo(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+ SK_U32 MdReg;
+
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+ XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* no way to flush the FIFO we have to issue a reset */
+ /* TBD */
+ }
+#endif /* YUKON */
+
+} /* SkMacFlushTxFifo */
+
+
+/******************************************************************************
+ *
+ * SkMacFlushRxFifo() - Flush the MAC's receive FIFO
+ *
+ * Description:
+ * Flush the receive FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ * nothing
+ */
+static void SkMacFlushRxFifo(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+ SK_U32 MdReg;
+
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+ XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* no way to flush the FIFO we have to issue a reset */
+ /* TBD */
+ }
+#endif /* YUKON */
+
+} /* SkMacFlushRxFifo */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmSoftRst() - Do a XMAC software reset
+ *
+ * Description:
+ * The PHY registers should not be destroyed during this
+ * kind of software reset. Therefore the XMAC Software Reset
+ * (XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
+ *
+ * The software reset is done by
+ * - disabling the Rx and Tx state machine,
+ * - resetting the statistics module,
+ * - clear all other significant XMAC Mode,
+ * Command, and Control Registers
+ * - clearing the Hash Register and the
+ * Exact Match Address registers, and
+ * - flushing the XMAC's Rx and Tx FIFOs.
+ *
+ * Note:
+ * Another requirement when stopping the XMAC is to
+ * avoid sending corrupted frames on the network.
+ * Disabling the Tx state machine will NOT interrupt
+ * the currently transmitted frame. But we must take care
+ * that the Tx FIFO is cleared AFTER the current frame
+ * is complete sent to the network.
+ *
+ * It takes about 12ns to send a frame with 1538 bytes.
+ * One PCI clock goes at least 15ns (66MHz). Therefore
+ * after reading XM_GP_PORT back, we are sure that the
+ * transmitter is disabled AND idle. And this means
+ * we may flush the transmit FIFO now.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmSoftRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U16 ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+
+ /* reset the statistics module */
+ XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+ /* disable all XMAC IRQs */
+ XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+
+ XM_OUT32(IoC, Port, XM_MODE, 0); /* clear Mode Reg */
+
+ XM_OUT16(IoC, Port, XM_TX_CMD, 0); /* reset TX CMD Reg */
+ XM_OUT16(IoC, Port, XM_RX_CMD, 0); /* reset RX CMD Reg */
+
+ /* disable all PHY IRQs */
+ switch (pAC->GIni.GP[Port].PhyType) {
+ case SK_PHY_BCOM:
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+ break;
+ case SK_PHY_NAT:
+ /* todo: National
+ SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+ break;
+#endif /* OTHER_PHY */
+ }
+
+ /* clear the Hash Register */
+ XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
+
+ /* clear the Exact Match Address registers */
+ SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
+
+ /* clear the Source Check Address registers */
+ XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
+
+} /* SkXmSoftRst */
+
+
+/******************************************************************************
+ *
+ * SkXmHardRst() - Do a XMAC hardware reset
+ *
+ * Description:
+ * The XMAC of the specified 'Port' and all connected devices
+ * (PHY and SERDES) will receive a reset signal on its *Reset pins.
+ * External PHYs must be reset by clearing a bit in the GPIO register
+ * (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns).
+ *
+ * ATTENTION:
+ * It is absolutely necessary to reset the SW_RST Bit first
+ * before calling this function.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmHardRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U32 Reg;
+ int i;
+ int TOut;
+ SK_U16 Word;
+
+ for (i = 0; i < 4; i++) {
+ /* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */
+ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+ TOut = 0;
+ do {
+ if (TOut++ > 10000) {
+ /*
+ * Adapter seems to be in RESET state.
+ * Registers cannot be written.
+ */
+ return;
+ }
+
+ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+
+ SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word);
+
+ } while ((Word & MFF_SET_MAC_RST) == 0);
+ }
+
+ /* For external PHYs there must be special handling */
+ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+ SK_IN32(IoC, B2_GP_IO, &Reg);
+
+ if (Port == 0) {
+ Reg |= GP_DIR_0; /* set to output */
+ Reg &= ~GP_IO_0; /* set PHY reset (active low) */
+ }
+ else {
+ Reg |= GP_DIR_2; /* set to output */
+ Reg &= ~GP_IO_2; /* set PHY reset (active low) */
+ }
+ /* reset external PHY */
+ SK_OUT32(IoC, B2_GP_IO, Reg);
+
+ /* short delay */
+ SK_IN32(IoC, B2_GP_IO, &Reg);
+ }
+} /* SkXmHardRst */
+
+
+/******************************************************************************
+ *
+ * SkXmClearRst() - Release the PHY & XMAC reset
+ *
+ * Description:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmClearRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U32 DWord;
+
+ /* clear HW reset */
+ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+ SK_IN32(IoC, B2_GP_IO, &DWord);
+
+ if (Port == 0) {
+ DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */
+ }
+ else {
+ DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */
+ }
+ /* Clear PHY reset */
+ SK_OUT32(IoC, B2_GP_IO, DWord);
+
+ /* Enable GMII interface */
+ XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
+ }
+} /* SkXmClearRst */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmSoftRst() - Do a GMAC software reset
+ *
+ * Description:
+ * The GPHY registers should not be destroyed during this
+ * kind of software reset.
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGmSoftRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U16 EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+ SK_U16 RxCtrl;
+
+ /* reset the statistics module */
+
+ /* disable all GMAC IRQs */
+ SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+
+ /* disable all PHY IRQs */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+
+ /* clear the Hash Register */
+ GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash);
+
+ /* Enable Unicast and Multicast filtering */
+ GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
+
+ GM_OUT16(IoC, Port, GM_RX_CTRL,
+ (SK_U16)(RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA));
+
+} /* SkGmSoftRst */
+
+
+/******************************************************************************
+ *
+ * SkGmHardRst() - Do a GMAC hardware reset
+ *
+ * Description:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGmHardRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U32 DWord;
+
+ /* WA code for COMA mode */
+ if (pAC->GIni.GIYukonLite &&
+ pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
+
+ SK_IN32(IoC, B2_GP_IO, &DWord);
+
+ DWord |= (GP_DIR_9 | GP_IO_9);
+
+ /* set PHY reset */
+ SK_OUT32(IoC, B2_GP_IO, DWord);
+ }
+
+ /* set GPHY Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+ /* set GMAC Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+} /* SkGmHardRst */
+
+
+/******************************************************************************
+ *
+ * SkGmClearRst() - Release the GPHY & GMAC reset
+ *
+ * Description:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGmClearRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U32 DWord;
+
+#ifdef XXX
+ /* clear GMAC Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* set GMAC Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+#endif /* XXX */
+
+ /* WA code for COMA mode */
+ if (pAC->GIni.GIYukonLite &&
+ pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
+
+ SK_IN32(IoC, B2_GP_IO, &DWord);
+
+ DWord |= GP_DIR_9; /* set to output */
+ DWord &= ~GP_IO_9; /* clear PHY reset (active high) */
+
+ /* clear PHY reset */
+ SK_OUT32(IoC, B2_GP_IO, DWord);
+ }
+
+ /* set HWCFG_MODE */
+ DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+ GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE |
+ (pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP :
+ GPC_HWCFG_GMII_FIB);
+
+ /* set GPHY Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET);
+
+ /* release GPHY Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR);
+
+#ifdef VCPU
+ VCpuWait(9000);
+#endif /* VCPU */
+
+ /* clear GMAC Control reset */
+ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+
+#ifdef VCPU
+ VCpuWait(2000);
+
+ SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord);
+
+ SK_IN32(IoC, B0_ISRC, &DWord);
+#endif /* VCPU */
+
+} /* SkGmClearRst */
+#endif /* YUKON */
+
+
+/******************************************************************************
+ *
+ * SkMacSoftRst() - Do a MAC software reset
+ *
+ * Description: calls a MAC software reset routine dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacSoftRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* disable receiver and transmitter */
+ SkMacRxTxDisable(pAC, IoC, Port);
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ SkXmSoftRst(pAC, IoC, Port);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ SkGmSoftRst(pAC, IoC, Port);
+ }
+#endif /* YUKON */
+
+ /* flush the MAC's Rx and Tx FIFOs */
+ SkMacFlushTxFifo(pAC, IoC, Port);
+
+ SkMacFlushRxFifo(pAC, IoC, Port);
+
+ pPrt->PState = SK_PRT_STOP;
+
+} /* SkMacSoftRst */
+
+
+/******************************************************************************
+ *
+ * SkMacHardRst() - Do a MAC hardware reset
+ *
+ * Description: calls a MAC hardware reset routine dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacHardRst(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ SkXmHardRst(pAC, IoC, Port);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ SkGmHardRst(pAC, IoC, Port);
+ }
+#endif /* YUKON */
+
+ pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+
+} /* SkMacHardRst */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmInitMac() - Initialize the XMAC II
+ *
+ * Description:
+ * Initialize the XMAC of the specified port.
+ * The XMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ * The XMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ * nothing
+ */
+void SkXmInitMac(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ int i;
+ SK_U16 SWord;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PState == SK_PRT_STOP) {
+ /* Port State: SK_PRT_STOP */
+ /* Verify that the reset bit is cleared */
+ SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+
+ if ((SWord & MFF_SET_MAC_RST) != 0) {
+ /* PState does not match HW state */
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+ /* Correct it */
+ pPrt->PState = SK_PRT_RESET;
+ }
+ }
+
+ if (pPrt->PState == SK_PRT_RESET) {
+
+ SkXmClearRst(pAC, IoC, Port);
+
+ if (pPrt->PhyType != SK_PHY_XMAC) {
+ /* read Id from external PHY (all have the same address) */
+ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1);
+
+ /*
+ * Optimize MDIO transfer by suppressing preamble.
+ * Must be done AFTER first access to BCOM chip.
+ */
+ XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
+
+ XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
+
+ if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) {
+ /*
+ * Workaround BCOM Errata for the C0 type.
+ * Write magic patterns to reserved registers.
+ */
+ i = 0;
+ while (BcomRegC0Hack[i].PhyReg != 0) {
+ SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg,
+ BcomRegC0Hack[i].PhyVal);
+ i++;
+ }
+ }
+ else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) {
+ /*
+ * Workaround BCOM Errata for the A1 type.
+ * Write magic patterns to reserved registers.
+ */
+ i = 0;
+ while (BcomRegA1Hack[i].PhyReg != 0) {
+ SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg,
+ BcomRegA1Hack[i].PhyVal);
+ i++;
+ }
+ }
+
+ /*
+ * Workaround BCOM Errata (#10523) for all BCom PHYs.
+ * Disable Power Management after reset.
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+ (SK_U16)(SWord | PHY_B_AC_DIS_PM));
+
+ /* PHY LED initialization is done in SkGeXmitLED() */
+ }
+
+ /* Dummy read the Interrupt source register */
+ XM_IN16(IoC, Port, XM_ISRC, &SWord);
+
+ /*
+ * The auto-negotiation process starts immediately after
+ * clearing the reset. The auto-negotiation process should be
+ * started by the SIRQ, therefore stop it here immediately.
+ */
+ SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+#ifdef TEST_ONLY
+ /* temp. code: enable signal detect */
+ /* WARNING: do not override GMII setting above */
+ XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_COM4SIG);
+#endif
+ }
+
+ /*
+ * configure the XMACs Station Address
+ * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A
+ * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
+ */
+ for (i = 0; i < 3; i++) {
+ /*
+ * The following 2 statements are together endianess
+ * independent. Remember this when changing.
+ */
+ SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+
+ XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
+ }
+
+ /* Tx Inter Packet Gap (XM_TX_IPG): use default */
+ /* Tx High Water Mark (XM_TX_HI_WM): use default */
+ /* Tx Low Water Mark (XM_TX_LO_WM): use default */
+ /* Host Request Threshold (XM_HT_THR): use default */
+ /* Rx Request Threshold (XM_RX_THR): use default */
+ /* Rx Low Water Mark (XM_RX_LO_WM): use default */
+
+ /* configure Rx High Water Mark (XM_RX_HI_WM) */
+ XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM);
+
+ /* Configure Tx Request Threshold */
+ SWord = SK_XM_THR_SL; /* for single port */
+
+ if (pAC->GIni.GIMacsFound > 1) {
+ switch (pAC->GIni.GIPortUsage) {
+ case SK_RED_LINK:
+ SWord = SK_XM_THR_REDL; /* redundant link */
+ break;
+ case SK_MUL_LINK:
+ SWord = SK_XM_THR_MULL; /* load balancing */
+ break;
+ case SK_JUMBO_LINK:
+ SWord = SK_XM_THR_JUMBO; /* jumbo frames */
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG);
+ break;
+ }
+ }
+ XM_OUT16(IoC, Port, XM_TX_THR, SWord);
+
+ /* setup register defaults for the Tx Command Register */
+ XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+ /* setup register defaults for the Rx Command Register */
+ SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+
+ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+ SWord |= XM_RX_BIG_PK_OK;
+ }
+
+ if (pPrt->PLinkMode == SK_LMODE_HALF) {
+ /*
+ * If in manual half duplex mode the other side might be in
+ * full duplex mode, so ignore if a carrier extension is not seen
+ * on frames received
+ */
+ SWord |= XM_RX_DIS_CEXT;
+ }
+
+ XM_OUT16(IoC, Port, XM_RX_CMD, SWord);
+
+ /*
+ * setup register defaults for the Mode Register
+ * - Don't strip error frames to avoid Store & Forward
+ * on the Rx side.
+ * - Enable 'Check Station Address' bit
+ * - Enable 'Check Address Array' bit
+ */
+ XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE);
+
+ /*
+ * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+ * - Enable all bits excepting 'Octets Rx OK Low CntOv'
+ * and 'Octets Rx OK Hi Cnt Ov'.
+ */
+ XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+ /*
+ * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+ * - Enable all bits excepting 'Octets Tx OK Low CntOv'
+ * and 'Octets Tx OK Hi Cnt Ov'.
+ */
+ XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK);
+
+ /*
+ * Do NOT init XMAC interrupt mask here.
+ * All interrupts remain disable until link comes up!
+ */
+
+ /*
+ * Any additional configuration changes may be done now.
+ * The last action is to enable the Rx and Tx state machine.
+ * This should be done after the auto-negotiation process
+ * has been completed successfully.
+ */
+} /* SkXmInitMac */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmInitMac() - Initialize the GMAC
+ *
+ * Description:
+ * Initialize the GMAC of the specified port.
+ * The GMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ * The GMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ * nothing
+ */
+void SkGmInitMac(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ int i;
+ SK_U16 SWord;
+ SK_U32 DWord;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PState == SK_PRT_STOP) {
+ /* Port State: SK_PRT_STOP */
+ /* Verify that the reset bit is cleared */
+ SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord);
+
+ if ((DWord & GMC_RST_SET) != 0) {
+ /* PState does not match HW state */
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+ /* Correct it */
+ pPrt->PState = SK_PRT_RESET;
+ }
+ }
+
+ if (pPrt->PState == SK_PRT_RESET) {
+
+ SkGmHardRst(pAC, IoC, Port);
+
+ SkGmClearRst(pAC, IoC, Port);
+
+ /* Auto-negotiation ? */
+ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+ /* Auto-negotiation disabled */
+
+ /* get General Purpose Control */
+ GM_IN16(IoC, Port, GM_GP_CTRL, &SWord);
+
+ /* disable auto-update for speed, duplex and flow-control */
+ SWord |= GM_GPCR_AU_ALL_DIS;
+
+ /* setup General Purpose Control Register */
+ GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+
+ SWord = GM_GPCR_AU_ALL_DIS;
+ }
+ else {
+ SWord = 0;
+ }
+
+ /* speed settings */
+ switch (pPrt->PLinkSpeed) {
+ case SK_LSPEED_AUTO:
+ case SK_LSPEED_1000MBPS:
+ SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100;
+ break;
+ case SK_LSPEED_100MBPS:
+ SWord |= GM_GPCR_SPEED_100;
+ break;
+ case SK_LSPEED_10MBPS:
+ break;
+ }
+
+ /* duplex settings */
+ if (pPrt->PLinkMode != SK_LMODE_HALF) {
+ /* set full duplex */
+ SWord |= GM_GPCR_DUP_FULL;
+ }
+
+ /* flow-control settings */
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ /* set Pause Off */
+ SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_OFF);
+ /* disable Tx & Rx flow-control */
+ SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ /* disable Rx flow-control */
+ SWord |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ case SK_FLOW_MODE_SYM_OR_REM:
+ /* enable Tx & Rx flow-control */
+ break;
+ }
+
+ /* setup General Purpose Control Register */
+ GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+
+ /* dummy read the Interrupt Source Register */
+ SK_IN16(IoC, GMAC_IRQ_SRC, &SWord);
+
+#ifndef VCPU
+ /* read Id from PHY */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1);
+
+ SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
+#endif /* VCPU */
+ }
+
+ (void)SkGmResetCounter(pAC, IoC, Port);
+
+ /* setup Transmit Control Register */
+ GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres));
+
+ /* setup Receive Control Register */
+ GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA |
+ GM_RXCR_CRC_DIS);
+
+ /* setup Transmit Flow Control Register */
+ GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff);
+
+ /* setup Transmit Parameter Register */
+#ifdef VCPU
+ GM_IN16(IoC, Port, GM_TX_PARAM, &SWord);
+#endif /* VCPU */
+
+ SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) |
+ TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) |
+ TX_IPG_JAM_DATA(pPrt->PMacJamIpgData);
+
+ GM_OUT16(IoC, Port, GM_TX_PARAM, SWord);
+
+ /* configure the Serial Mode Register */
+#ifdef VCPU
+ GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord);
+#endif /* VCPU */
+
+ SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData);
+
+ if (pPrt->PMacLimit4) {
+ /* reset of collision counter after 4 consecutive collisions */
+ SWord |= GM_SMOD_LIMIT_4;
+ }
+
+ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+ /* enable jumbo mode (Max. Frame Length = 9018) */
+ SWord |= GM_SMOD_JUMBO_ENA;
+ }
+
+ GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord);
+
+ /*
+ * configure the GMACs Station Addresses
+ * in PROM you can find our addresses at:
+ * B2_MAC_1 = xx xx xx xx xx x0 virtual address
+ * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A
+ * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort
+ */
+
+ for (i = 0; i < 3; i++) {
+ /*
+ * The following 2 statements are together endianess
+ * independent. Remember this when changing.
+ */
+ /* physical address: will be used for pause frames */
+ SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+
+#ifdef WA_DEV_16
+ /* WA for deviation #16 */
+ if (pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) {
+ /* swap the address bytes */
+ SWord = ((SWord & 0xff00) >> 8) | ((SWord & 0x00ff) << 8);
+
+ /* write to register in reversed order */
+ GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord);
+ }
+ else {
+ GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+ }
+#else
+ GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+#endif /* WA_DEV_16 */
+
+ /* virtual address: will be used for data */
+ SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord);
+
+ GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord);
+
+ /* reset Multicast filtering Hash registers 1-3 */
+ GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + 4*i, 0);
+ }
+
+ /* reset Multicast filtering Hash register 4 */
+ GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0);
+
+ /* enable interrupt mask for counter overflows */
+ GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0);
+ GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0);
+ GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0);
+
+#if defined(SK_DIAG) || defined(DEBUG)
+ /* read General Purpose Status */
+ GM_IN16(IoC, Port, GM_GP_STAT, &SWord);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("MAC Stat Reg.=0x%04X\n", SWord));
+#endif /* SK_DIAG || DEBUG */
+
+#ifdef SK_DIAG
+ c_print("MAC Stat Reg=0x%04X\n", SWord);
+#endif /* SK_DIAG */
+
+} /* SkGmInitMac */
+#endif /* YUKON */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmInitDupMd() - Initialize the XMACs Duplex Mode
+ *
+ * Description:
+ * This function initializes the XMACs Duplex Mode.
+ * It should be called after successfully finishing
+ * the Auto-negotiation Process
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmInitDupMd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ switch (pAC->GIni.GP[Port].PLinkModeStatus) {
+ case SK_LMODE_STAT_AUTOHALF:
+ case SK_LMODE_STAT_HALF:
+ /* Configuration Actions for Half Duplex Mode */
+ /*
+ * XM_BURST = default value. We are probable not quick
+ * enough at the 'XMAC' bus to burst 8kB.
+ * The XMAC stops bursting if no transmit frames
+ * are available or the burst limit is exceeded.
+ */
+ /* XM_TX_RT_LIM = default value (15) */
+ /* XM_TX_STIME = default value (0xff = 4096 bit times) */
+ break;
+ case SK_LMODE_STAT_AUTOFULL:
+ case SK_LMODE_STAT_FULL:
+ /* Configuration Actions for Full Duplex Mode */
+ /*
+ * The duplex mode is configured by the PHY,
+ * therefore it seems to be that there is nothing
+ * to do here.
+ */
+ break;
+ case SK_LMODE_STAT_UNKNOWN:
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
+ break;
+ }
+} /* SkXmInitDupMd */
+
+
+/******************************************************************************
+ *
+ * SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
+ *
+ * Description:
+ * This function initializes the Pause Mode which should
+ * be used for this port.
+ * It should be called after successfully finishing
+ * the Auto-negotiation Process
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmInitPauseMd(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U32 DWord;
+ SK_U16 Word;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+ if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
+ pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+ /* Disable Pause Frame Reception */
+ Word |= XM_MMU_IGN_PF;
+ }
+ else {
+ /*
+ * enabling pause frame reception is required for 1000BT
+ * because the XMAC is not reset if the link is going down
+ */
+ /* Enable Pause Frame Reception */
+ Word &= ~XM_MMU_IGN_PF;
+ }
+
+ XM_OUT16(IoC, Port, XM_MMU_CMD, Word);
+
+ XM_IN32(IoC, Port, XM_MODE, &DWord);
+
+ if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
+ pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+ /*
+ * Configure Pause Frame Generation
+ * Use internal and external Pause Frame Generation.
+ * Sending pause frames is edge triggered.
+ * Send a Pause frame with the maximum pause time if
+ * internal oder external FIFO full condition occurs.
+ * Send a zero pause time frame to re-start transmission.
+ */
+
+ /* XM_PAUSE_DA = '010000C28001' (default) */
+
+ /* XM_MAC_PTIME = 0xffff (maximum) */
+ /* remember this value is defined in big endian (!) */
+ XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);
+
+ /* Set Pause Mode in Mode Register */
+ DWord |= XM_PAUSE_MODE;
+
+ /* Set Pause Mode in MAC Rx FIFO */
+ SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+ }
+ else {
+ /*
+ * disable pause frame generation is required for 1000BT
+ * because the XMAC is not reset if the link is going down
+ */
+ /* Disable Pause Mode in Mode Register */
+ DWord &= ~XM_PAUSE_MODE;
+
+ /* Disable Pause Mode in MAC Rx FIFO */
+ SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+ }
+
+ XM_OUT32(IoC, Port, XM_MODE, DWord);
+} /* SkXmInitPauseMd*/
+
+
+/******************************************************************************
+ *
+ * SkXmInitPhyXmac() - Initialize the XMAC Phy registers
+ *
+ * Description: initializes all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmInitPhyXmac(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 Ctrl;
+
+ pPrt = &pAC->GIni.GP[Port];
+ Ctrl = 0;
+
+ /* Auto-negotiation ? */
+ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyXmac: no auto-negotiation Port %d\n", Port));
+ /* Set DuplexMode in Config register */
+ if (pPrt->PLinkMode == SK_LMODE_FULL) {
+ Ctrl |= PHY_CT_DUP_MD;
+ }
+
+ /*
+ * Do NOT enable Auto-negotiation here. This would hold
+ * the link down because no IDLEs are transmitted
+ */
+ }
+ else {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyXmac: with auto-negotiation Port %d\n", Port));
+ /* Set Auto-negotiation advertisement */
+
+ /* Set Full/half duplex capabilities */
+ switch (pPrt->PLinkMode) {
+ case SK_LMODE_AUTOHALF:
+ Ctrl |= PHY_X_AN_HD;
+ break;
+ case SK_LMODE_AUTOFULL:
+ Ctrl |= PHY_X_AN_FD;
+ break;
+ case SK_LMODE_AUTOBOTH:
+ Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+ SKERR_HWI_E015MSG);
+ }
+
+ /* Set Flow-control capabilities */
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ Ctrl |= PHY_X_P_NO_PAUSE;
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ Ctrl |= PHY_X_P_ASYM_MD;
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ Ctrl |= PHY_X_P_SYM_MD;
+ break;
+ case SK_FLOW_MODE_SYM_OR_REM:
+ Ctrl |= PHY_X_P_BOTH_MD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+ SKERR_HWI_E016MSG);
+ }
+
+ /* Write AutoNeg Advertisement Register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl);
+
+ /* Restart Auto-negotiation */
+ Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+ }
+
+ if (DoLoop) {
+ /* Set the Phy Loopback bit, too */
+ Ctrl |= PHY_CT_LOOP;
+ }
+
+ /* Write to the Phy control register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl);
+} /* SkXmInitPhyXmac */
+
+
+/******************************************************************************
+ *
+ * SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
+ *
+ * Description: initializes all the Broadcom Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmInitPhyBcom(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 Ctrl1;
+ SK_U16 Ctrl2;
+ SK_U16 Ctrl3;
+ SK_U16 Ctrl4;
+ SK_U16 Ctrl5;
+
+ Ctrl1 = PHY_CT_SP1000;
+ Ctrl2 = 0;
+ Ctrl3 = PHY_SEL_TYPE;
+ Ctrl4 = PHY_B_PEC_EN_LTR;
+ Ctrl5 = PHY_B_AC_TX_TST;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* manually Master/Slave ? */
+ if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+ Ctrl2 |= PHY_B_1000C_MSE;
+
+ if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+ Ctrl2 |= PHY_B_1000C_MSC;
+ }
+ }
+ /* Auto-negotiation ? */
+ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyBcom: no auto-negotiation Port %d\n", Port));
+ /* Set DuplexMode in Config register */
+ if (pPrt->PLinkMode == SK_LMODE_FULL) {
+ Ctrl1 |= PHY_CT_DUP_MD;
+ }
+
+ /* Determine Master/Slave manually if not already done */
+ if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+ Ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */
+ }
+
+ /*
+ * Do NOT enable Auto-negotiation here. This would hold
+ * the link down because no IDLES are transmitted
+ */
+ }
+ else {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyBcom: with auto-negotiation Port %d\n", Port));
+ /* Set Auto-negotiation advertisement */
+
+ /*
+ * Workaround BCOM Errata #1 for the C5 type.
+ * 1000Base-T Link Acquisition Failure in Slave Mode
+ * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+ */
+ Ctrl2 |= PHY_B_1000C_RD;
+
+ /* Set Full/half duplex capabilities */
+ switch (pPrt->PLinkMode) {
+ case SK_LMODE_AUTOHALF:
+ Ctrl2 |= PHY_B_1000C_AHD;
+ break;
+ case SK_LMODE_AUTOFULL:
+ Ctrl2 |= PHY_B_1000C_AFD;
+ break;
+ case SK_LMODE_AUTOBOTH:
+ Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+ SKERR_HWI_E015MSG);
+ }
+
+ /* Set Flow-control capabilities */
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ Ctrl3 |= PHY_B_P_NO_PAUSE;
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ Ctrl3 |= PHY_B_P_ASYM_MD;
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ Ctrl3 |= PHY_B_P_SYM_MD;
+ break;
+ case SK_FLOW_MODE_SYM_OR_REM:
+ Ctrl3 |= PHY_B_P_BOTH_MD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+ SKERR_HWI_E016MSG);
+ }
+
+ /* Restart Auto-negotiation */
+ Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+ }
+
+ /* Initialize LED register here? */
+ /* No. Please do it in SkDgXmitLed() (if required) and swap
+ init order of LEDs and XMAC. (MAl) */
+
+ /* Write 1000Base-T Control Register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+
+ /* Write AutoNeg Advertisement Register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
+
+ if (DoLoop) {
+ /* Set the Phy Loopback bit, too */
+ Ctrl1 |= PHY_CT_LOOP;
+ }
+
+ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+ /* configure FIFO to high latency for transmission of ext. packets */
+ Ctrl4 |= PHY_B_PEC_HIGH_LA;
+
+ /* configure reception of extended packets */
+ Ctrl5 |= PHY_B_AC_LONG_PACK;
+
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
+ }
+
+ /* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
+
+ /* Write to the Phy control register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Control Reg=0x%04X\n", Ctrl1));
+} /* SkXmInitPhyBcom */
+#endif /* GENESIS */
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmInitPhyMarv() - Initialize the Marvell Phy registers
+ *
+ * Description: initializes all the Marvell Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGmInitPhyMarv(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 PhyCtrl;
+ SK_U16 C1000BaseT;
+ SK_U16 AutoNegAdv;
+ SK_U16 ExtPhyCtrl;
+ SK_U16 LedCtrl;
+ SK_BOOL AutoNeg;
+#if defined(SK_DIAG) || defined(DEBUG)
+ SK_U16 PhyStat;
+ SK_U16 PhyStat1;
+ SK_U16 PhySpecStat;
+#endif /* SK_DIAG || DEBUG */
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Auto-negotiation ? */
+ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+ AutoNeg = SK_FALSE;
+ }
+ else {
+ AutoNeg = SK_TRUE;
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyMarv: Port %d, auto-negotiation %s\n",
+ Port, AutoNeg ? "ON" : "OFF"));
+
+#ifdef VCPU
+ VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n",
+ Port, DoLoop);
+#else /* VCPU */
+ if (DoLoop) {
+ /* Set 'MAC Power up'-bit, set Manual MDI configuration */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
+ PHY_M_PC_MAC_POW_UP);
+ }
+ else if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO) {
+ /* Read Ext. PHY Specific Control */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+
+ ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+ PHY_M_EC_MAC_S_MSK);
+
+ ExtPhyCtrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ) |
+ PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+ }
+
+ /* Read PHY Control */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+
+ if (!AutoNeg) {
+ /* Disable Auto-negotiation */
+ PhyCtrl &= ~PHY_CT_ANE;
+ }
+
+ PhyCtrl |= PHY_CT_RESET;
+ /* Assert software reset */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+#endif /* VCPU */
+
+ PhyCtrl = 0 /* PHY_CT_COL_TST */;
+ C1000BaseT = 0;
+ AutoNegAdv = PHY_SEL_TYPE;
+
+ /* manually Master/Slave ? */
+ if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+ /* enable Manual Master/Slave */
+ C1000BaseT |= PHY_M_1000C_MSE;
+
+ if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+ C1000BaseT |= PHY_M_1000C_MSC; /* set it to Master */
+ }
+ }
+
+ /* Auto-negotiation ? */
+ if (!AutoNeg) {
+
+ if (pPrt->PLinkMode == SK_LMODE_FULL) {
+ /* Set Full Duplex Mode */
+ PhyCtrl |= PHY_CT_DUP_MD;
+ }
+
+ /* Set Master/Slave manually if not already done */
+ if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+ C1000BaseT |= PHY_M_1000C_MSE; /* set it to Slave */
+ }
+
+ /* Set Speed */
+ switch (pPrt->PLinkSpeed) {
+ case SK_LSPEED_AUTO:
+ case SK_LSPEED_1000MBPS:
+ PhyCtrl |= PHY_CT_SP1000;
+ break;
+ case SK_LSPEED_100MBPS:
+ PhyCtrl |= PHY_CT_SP100;
+ break;
+ case SK_LSPEED_10MBPS:
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+ SKERR_HWI_E019MSG);
+ }
+
+ if (!DoLoop) {
+ PhyCtrl |= PHY_CT_RESET;
+ }
+ }
+ else {
+ /* Set Auto-negotiation advertisement */
+
+ if (pAC->GIni.GICopperType) {
+ /* Set Speed capabilities */
+ switch (pPrt->PLinkSpeed) {
+ case SK_LSPEED_AUTO:
+ C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+ AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+ PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+ break;
+ case SK_LSPEED_1000MBPS:
+ C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+ break;
+ case SK_LSPEED_100MBPS:
+ AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+ /* advertise 10Base-T also */
+ PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+ break;
+ case SK_LSPEED_10MBPS:
+ AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+ SKERR_HWI_E019MSG);
+ }
+
+ /* Set Full/half duplex capabilities */
+ switch (pPrt->PLinkMode) {
+ case SK_LMODE_AUTOHALF:
+ C1000BaseT &= ~PHY_M_1000C_AFD;
+ AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD);
+ break;
+ case SK_LMODE_AUTOFULL:
+ C1000BaseT &= ~PHY_M_1000C_AHD;
+ AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD);
+ break;
+ case SK_LMODE_AUTOBOTH:
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+ SKERR_HWI_E015MSG);
+ }
+
+ /* Set Flow-control capabilities */
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ AutoNegAdv |= PHY_B_P_NO_PAUSE;
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ AutoNegAdv |= PHY_B_P_ASYM_MD;
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ AutoNegAdv |= PHY_B_P_SYM_MD;
+ break;
+ case SK_FLOW_MODE_SYM_OR_REM:
+ AutoNegAdv |= PHY_B_P_BOTH_MD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+ SKERR_HWI_E016MSG);
+ }
+ }
+ else { /* special defines for FIBER (88E1011S only) */
+
+ /* Set Full/half duplex capabilities */
+ switch (pPrt->PLinkMode) {
+ case SK_LMODE_AUTOHALF:
+ AutoNegAdv |= PHY_M_AN_1000X_AHD;
+ break;
+ case SK_LMODE_AUTOFULL:
+ AutoNegAdv |= PHY_M_AN_1000X_AFD;
+ break;
+ case SK_LMODE_AUTOBOTH:
+ AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+ SKERR_HWI_E015MSG);
+ }
+
+ /* Set Flow-control capabilities */
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ AutoNegAdv |= PHY_M_P_NO_PAUSE_X;
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ AutoNegAdv |= PHY_M_P_ASYM_MD_X;
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ AutoNegAdv |= PHY_M_P_SYM_MD_X;
+ break;
+ case SK_FLOW_MODE_SYM_OR_REM:
+ AutoNegAdv |= PHY_M_P_BOTH_MD_X;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+ SKERR_HWI_E016MSG);
+ }
+ }
+
+ if (!DoLoop) {
+ /* Restart Auto-negotiation */
+ PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+ }
+ }
+
+#ifdef VCPU
+ /*
+ * E-mail from Gu Lin (08-03-2002):
+ */
+
+ /* Program PHY register 30 as 16'h0708 for simulation speed up */
+ SkGmPhyWrite(pAC, IoC, Port, 30, 0x0700 /* 0x0708 */);
+
+ VCpuWait(2000);
+
+#else /* VCPU */
+
+ /* Write 1000Base-T Control Register */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT));
+
+ /* Write AutoNeg Advertisement Register */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
+#endif /* VCPU */
+
+ if (DoLoop) {
+ /* Set the PHY Loopback bit */
+ PhyCtrl |= PHY_CT_LOOP;
+
+#ifdef XXX
+ /* Program PHY register 16 as 16'h0400 to force link good */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD);
+#endif /* XXX */
+
+#ifndef VCPU
+ if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) {
+ /* Write Ext. PHY Specific Control */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL,
+ (SK_U16)((pPrt->PLinkSpeed + 2) << 4));
+ }
+#endif /* VCPU */
+ }
+#ifdef TEST_ONLY
+ else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) {
+ /* Write PHY Specific Control */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
+ PHY_M_PC_EN_DET_MSK);
+ }
+#endif
+
+ /* Write to the PHY Control register */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+
+#ifdef VCPU
+ VCpuWait(2000);
+#else
+
+ LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS);
+
+ if ((pAC->GIni.GILedBlinkCtrl & SK_ACT_LED_BLINK) != 0) {
+ LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL;
+ }
+
+ if ((pAC->GIni.GILedBlinkCtrl & SK_DUP_LED_NORMAL) != 0) {
+ LedCtrl |= PHY_M_LEDC_DP_CTRL;
+ }
+
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl);
+
+ if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) {
+ /* only in forced 100 Mbps mode */
+ if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) {
+
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER,
+ PHY_M_LED_MO_100(MO_LED_ON));
+ }
+ }
+
+#ifdef SK_DIAG
+ c_print("Set PHY Ctrl=0x%04X\n", PhyCtrl);
+ c_print("Set 1000 B-T=0x%04X\n", C1000BaseT);
+ c_print("Set Auto-Neg=0x%04X\n", AutoNegAdv);
+ c_print("Set Ext Ctrl=0x%04X\n", ExtPhyCtrl);
+#endif /* SK_DIAG */
+
+#if defined(SK_DIAG) || defined(DEBUG)
+ /* Read PHY Control */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+
+ /* Read 1000Base-T Control Register */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("1000B-T Ctrl =0x%04X\n", C1000BaseT));
+
+ /* Read AutoNeg Advertisement Register */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
+
+ /* Read Ext. PHY Specific Control */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+
+ /* Read PHY Status */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Stat Reg.=0x%04X\n", PhyStat));
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Stat Reg.=0x%04X\n", PhyStat1));
+
+ /* Read PHY Specific Status */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Spec Stat=0x%04X\n", PhySpecStat));
+#endif /* SK_DIAG || DEBUG */
+
+#ifdef SK_DIAG
+ c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl);
+ c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT);
+ c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv);
+ c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl);
+ c_print("PHY Stat Reg=0x%04X\n", PhyStat);
+ c_print("PHY Stat Reg=0x%04X\n", PhyStat1);
+ c_print("PHY Spec Reg=0x%04X\n", PhySpecStat);
+#endif /* SK_DIAG */
+
+#endif /* VCPU */
+
+} /* SkGmInitPhyMarv */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkXmInitPhyLone() - Initialize the Level One Phy registers
+ *
+ * Description: initializes all the Level One Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmInitPhyLone(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 Ctrl1;
+ SK_U16 Ctrl2;
+ SK_U16 Ctrl3;
+
+ Ctrl1 = PHY_CT_SP1000;
+ Ctrl2 = 0;
+ Ctrl3 = PHY_SEL_TYPE;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* manually Master/Slave ? */
+ if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+ Ctrl2 |= PHY_L_1000C_MSE;
+
+ if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+ Ctrl2 |= PHY_L_1000C_MSC;
+ }
+ }
+ /* Auto-negotiation ? */
+ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+ /*
+ * level one spec say: "1000 Mbps: manual mode not allowed"
+ * but lets see what happens...
+ */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyLone: no auto-negotiation Port %d\n", Port));
+ /* Set DuplexMode in Config register */
+ if (pPrt->PLinkMode == SK_LMODE_FULL) {
+ Ctrl1 |= PHY_CT_DUP_MD;
+ }
+
+ /* Determine Master/Slave manually if not already done */
+ if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+ Ctrl2 |= PHY_L_1000C_MSE; /* set it to Slave */
+ }
+
+ /*
+ * Do NOT enable Auto-negotiation here. This would hold
+ * the link down because no IDLES are transmitted
+ */
+ }
+ else {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("InitPhyLone: with auto-negotiation Port %d\n", Port));
+ /* Set Auto-negotiation advertisement */
+
+ /* Set Full/half duplex capabilities */
+ switch (pPrt->PLinkMode) {
+ case SK_LMODE_AUTOHALF:
+ Ctrl2 |= PHY_L_1000C_AHD;
+ break;
+ case SK_LMODE_AUTOFULL:
+ Ctrl2 |= PHY_L_1000C_AFD;
+ break;
+ case SK_LMODE_AUTOBOTH:
+ Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+ SKERR_HWI_E015MSG);
+ }
+
+ /* Set Flow-control capabilities */
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ Ctrl3 |= PHY_L_P_NO_PAUSE;
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ Ctrl3 |= PHY_L_P_ASYM_MD;
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ Ctrl3 |= PHY_L_P_SYM_MD;
+ break;
+ case SK_FLOW_MODE_SYM_OR_REM:
+ Ctrl3 |= PHY_L_P_BOTH_MD;
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+ SKERR_HWI_E016MSG);
+ }
+
+ /* Restart Auto-negotiation */
+ Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
+ }
+
+ /* Write 1000Base-T Control Register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+
+ /* Write AutoNeg Advertisement Register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
+
+ if (DoLoop) {
+ /* Set the Phy Loopback bit, too */
+ Ctrl1 |= PHY_CT_LOOP;
+ }
+
+ /* Write to the Phy control register */
+ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Control Reg=0x%04X\n", Ctrl1));
+} /* SkXmInitPhyLone */
+
+
+/******************************************************************************
+ *
+ * SkXmInitPhyNat() - Initialize the National Phy registers
+ *
+ * Description: initializes all the National Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmInitPhyNat(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */
+{
+/* todo: National */
+} /* SkXmInitPhyNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ * SkMacInitPhy() - Initialize the PHY registers
+ *
+ * Description: calls the Init PHY routines dep. on board type
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacInitPhy(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */
+{
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ switch (pPrt->PhyType) {
+ case SK_PHY_XMAC:
+ SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
+ break;
+ case SK_PHY_BCOM:
+ SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+ break;
+ case SK_PHY_NAT:
+ SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+ break;
+#endif /* OTHER_PHY */
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ SkGmInitPhyMarv(pAC, IoC, Port, DoLoop);
+ }
+#endif /* YUKON */
+
+} /* SkMacInitPhy */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmAutoNegDoneXmac() - Auto-negotiation handling
+ *
+ * Description:
+ * This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ * SK_AND_OK o.k.
+ * SK_AND_DUP_CAP Duplex capability error happened
+ * SK_AND_OTHER Other error happened
+ */
+static int SkXmAutoNegDoneXmac(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 ResAb; /* Resolved Ability */
+ SK_U16 LPAb; /* Link Partner Ability */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegDoneXmac, Port %d\n", Port));
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Get PHY parameters */
+ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb);
+ SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+
+ if ((LPAb & PHY_X_AN_RFB) != 0) {
+ /* At least one of the remote fault bit is set */
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ return(SK_AND_OTHER);
+ }
+
+ /* Check Duplex mismatch */
+ if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+ }
+ else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+ }
+ else {
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ return(SK_AND_DUP_CAP);
+ }
+
+ /* Check PAUSE mismatch */
+ /* We are NOT using chapter 4.23 of the Xaqti manual */
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
+ pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
+ (LPAb & PHY_X_P_SYM_MD) != 0) {
+ /* Symmetric PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+ }
+ else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
+ (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
+ /* Enable PAUSE receive, disable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+ }
+ else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
+ (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
+ /* Disable PAUSE receive, enable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+ }
+ else {
+ /* PAUSE mismatch -> no PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+ }
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+
+ return(SK_AND_OK);
+} /* SkXmAutoNegDoneXmac */
+
+
+/******************************************************************************
+ *
+ * SkXmAutoNegDoneBcom() - Auto-negotiation handling
+ *
+ * Description:
+ * This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ * SK_AND_OK o.k.
+ * SK_AND_DUP_CAP Duplex capability error happened
+ * SK_AND_OTHER Other error happened
+ */
+static int SkXmAutoNegDoneBcom(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 LPAb; /* Link Partner Ability */
+ SK_U16 AuxStat; /* Auxiliary Status */
+
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+ SK_U16 ResAb; /* Resolved Ability */
+#endif /* 0 */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegDoneBcom, Port %d\n", Port));
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Get PHY parameters */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb);
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+#endif /* 0 */
+
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+
+ if ((LPAb & PHY_B_AN_RF) != 0) {
+ /* Remote fault bit is set: Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ return(SK_AND_OTHER);
+ }
+
+ /* Check Duplex mismatch */
+ if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+ }
+ else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+ }
+ else {
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ return(SK_AND_DUP_CAP);
+ }
+
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+ /* Check Master/Slave resolution */
+ if ((ResAb & PHY_B_1000S_MSF) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Master/Slave Fault Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ pPrt->PMSStatus = SK_MS_STAT_FAULT;
+ return(SK_AND_OTHER);
+ }
+
+ pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+ SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+#endif /* 0 */
+
+ /* Check PAUSE mismatch ??? */
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) {
+ /* Symmetric PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+ }
+ else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) {
+ /* Enable PAUSE receive, disable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+ }
+ else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) {
+ /* Disable PAUSE receive, enable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+ }
+ else {
+ /* PAUSE mismatch -> no PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+ }
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+
+ return(SK_AND_OK);
+} /* SkXmAutoNegDoneBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmAutoNegDoneMarv() - Auto-negotiation handling
+ *
+ * Description:
+ * This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ * SK_AND_OK o.k.
+ * SK_AND_DUP_CAP Duplex capability error happened
+ * SK_AND_OTHER Other error happened
+ */
+static int SkGmAutoNegDoneMarv(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 LPAb; /* Link Partner Ability */
+ SK_U16 ResAb; /* Resolved Ability */
+ SK_U16 AuxStat; /* Auxiliary Status */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegDoneMarv, Port %d\n", Port));
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Get PHY parameters */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb);
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Link P.Abil.=0x%04X\n", LPAb));
+
+ if ((LPAb & PHY_M_AN_RF) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ return(SK_AND_OTHER);
+ }
+
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+ /* Check Master/Slave resolution */
+ if ((ResAb & PHY_B_1000S_MSF) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Master/Slave Fault Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ pPrt->PMSStatus = SK_MS_STAT_FAULT;
+ return(SK_AND_OTHER);
+ }
+
+ pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+ (SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE;
+
+ /* Read PHY Specific Status */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat);
+
+ /* Check Speed & Duplex resolved */
+ if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+ return(SK_AND_DUP_CAP);
+ }
+
+ if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+ }
+ else {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+ }
+
+ /* Check PAUSE mismatch ??? */
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) {
+ /* Symmetric PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+ }
+ else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) {
+ /* Enable PAUSE receive, disable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+ }
+ else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) {
+ /* Disable PAUSE receive, enable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+ }
+ else {
+ /* PAUSE mismatch -> no PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+ }
+
+ /* set used link speed */
+ switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) {
+ case (unsigned)PHY_M_PS_SPEED_1000:
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+ break;
+ case PHY_M_PS_SPEED_100:
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
+ break;
+ default:
+ pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
+ }
+
+ return(SK_AND_OK);
+} /* SkGmAutoNegDoneMarv */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkXmAutoNegDoneLone() - Auto-negotiation handling
+ *
+ * Description:
+ * This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ * SK_AND_OK o.k.
+ * SK_AND_DUP_CAP Duplex capability error happened
+ * SK_AND_OTHER Other error happened
+ */
+static int SkXmAutoNegDoneLone(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 ResAb; /* Resolved Ability */
+ SK_U16 LPAb; /* Link Partner Ability */
+ SK_U16 QuickStat; /* Auxiliary Status */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegDoneLone, Port %d\n", Port));
+ pPrt = &pAC->GIni.GP[Port];
+
+ /* Get PHY parameters */
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb);
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb);
+ SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat);
+
+ if ((LPAb & PHY_L_AN_RF) != 0) {
+ /* Remote fault bit is set */
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegFail: Remote fault bit set Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ return(SK_AND_OTHER);
+ }
+
+ /* Check Duplex mismatch */
+ if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+ }
+ else {
+ pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+ }
+
+ /* Check Master/Slave resolution */
+ if ((ResAb & PHY_L_1000S_MSF) != 0) {
+ /* Error */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("Master/Slave Fault Port %d\n", Port));
+ pPrt->PAutoNegFail = SK_TRUE;
+ pPrt->PMSStatus = SK_MS_STAT_FAULT;
+ return(SK_AND_OTHER);
+ }
+ else if (ResAb & PHY_L_1000S_MSR) {
+ pPrt->PMSStatus = SK_MS_STAT_MASTER;
+ }
+ else {
+ pPrt->PMSStatus = SK_MS_STAT_SLAVE;
+ }
+
+ /* Check PAUSE mismatch */
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ /* we must manually resolve the abilities here */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+
+ switch (pPrt->PFlowCtrlMode) {
+ case SK_FLOW_MODE_NONE:
+ /* default */
+ break;
+ case SK_FLOW_MODE_LOC_SEND:
+ if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+ (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) {
+ /* Disable PAUSE receive, enable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+ }
+ break;
+ case SK_FLOW_MODE_SYMMETRIC:
+ if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
+ /* Symmetric PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+ }
+ break;
+ case SK_FLOW_MODE_SYM_OR_REM:
+ if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+ PHY_L_QS_AS_PAUSE) {
+ /* Enable PAUSE receive, disable PAUSE transmit */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+ }
+ else if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
+ /* Symmetric PAUSE */
+ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+ }
+ break;
+ default:
+ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+ SKERR_HWI_E016MSG);
+ }
+
+ return(SK_AND_OK);
+} /* SkXmAutoNegDoneLone */
+
+
+/******************************************************************************
+ *
+ * SkXmAutoNegDoneNat() - Auto-negotiation handling
+ *
+ * Description:
+ * This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ * SK_AND_OK o.k.
+ * SK_AND_DUP_CAP Duplex capability error happened
+ * SK_AND_OTHER Other error happened
+ */
+static int SkXmAutoNegDoneNat(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+/* todo: National */
+ return(SK_AND_OK);
+} /* SkXmAutoNegDoneNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ * SkMacAutoNegDone() - Auto-negotiation handling
+ *
+ * Description: calls the auto-negotiation done routines dep. on board type
+ *
+ * Returns:
+ * SK_AND_OK o.k.
+ * SK_AND_DUP_CAP Duplex capability error happened
+ * SK_AND_OTHER Other error happened
+ */
+int SkMacAutoNegDone(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ int Rtv;
+
+ Rtv = SK_AND_OK;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ switch (pPrt->PhyType) {
+
+ case SK_PHY_XMAC:
+ Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port);
+ break;
+ case SK_PHY_BCOM:
+ Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port);
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port);
+ break;
+ case SK_PHY_NAT:
+ Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port);
+ break;
+#endif /* OTHER_PHY */
+ default:
+ return(SK_AND_OTHER);
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port);
+ }
+#endif /* YUKON */
+
+ if (Rtv != SK_AND_OK) {
+ return(Rtv);
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNeg done Port %d\n", Port));
+
+ /* We checked everything and may now enable the link */
+ pPrt->PAutoNegFail = SK_FALSE;
+
+ SkMacRxTxEnable(pAC, IoC, Port);
+
+ return(SK_AND_OK);
+} /* SkMacAutoNegDone */
+
+
+/******************************************************************************
+ *
+ * SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
+ *
+ * Description: enables Rx/Tx dep. on board type
+ *
+ * Returns:
+ * 0 o.k.
+ * != 0 Error happened
+ */
+int SkMacRxTxEnable(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 Reg; /* 16-bit register value */
+ SK_U16 IntMask; /* MAC interrupt mask */
+#ifdef GENESIS
+ SK_U16 SWord;
+#endif
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (!pPrt->PHWLinkUp) {
+ /* The Hardware link is NOT up */
+ return(0);
+ }
+
+ if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
+ pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
+ pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
+ pPrt->PAutoNegFail) {
+ /* Auto-negotiation is not done or failed */
+ return(0);
+ }
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* set Duplex Mode and Pause Mode */
+ SkXmInitDupMd(pAC, IoC, Port);
+
+ SkXmInitPauseMd(pAC, IoC, Port);
+
+ /*
+ * Initialize the Interrupt Mask Register. Default IRQs are...
+ * - Link Asynchronous Event
+ * - Link Partner requests config
+ * - Auto Negotiation Done
+ * - Rx Counter Event Overflow
+ * - Tx Counter Event Overflow
+ * - Transmit FIFO Underrun
+ */
+ IntMask = XM_DEF_MSK;
+
+#ifdef DEBUG
+ /* add IRQ for Receive FIFO Overflow */
+ IntMask &= ~XM_IS_RXF_OV;
+#endif /* DEBUG */
+
+ if (pPrt->PhyType != SK_PHY_XMAC) {
+ /* disable GP0 interrupt bit */
+ IntMask |= XM_IS_INP_ASS;
+ }
+ XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+
+ /* get MMU Command Reg. */
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
+
+ if (pPrt->PhyType != SK_PHY_XMAC &&
+ (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+ pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
+ /* set to Full Duplex */
+ Reg |= XM_MMU_GMII_FD;
+ }
+
+ switch (pPrt->PhyType) {
+ case SK_PHY_BCOM:
+ /*
+ * Workaround BCOM Errata (#10523) for all BCom Phys
+ * Enable Power Management after link up
+ */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+ (SK_U16)(SWord & ~PHY_B_AC_DIS_PM));
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK,
+ (SK_U16)PHY_B_DEF_MSK);
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
+ break;
+ case SK_PHY_NAT:
+ /* todo National:
+ SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */
+ /* no interrupts possible from National ??? */
+ break;
+#endif /* OTHER_PHY */
+ }
+
+ /* enable Rx/Tx */
+ XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /*
+ * Initialize the Interrupt Mask Register. Default IRQs are...
+ * - Rx Counter Event Overflow
+ * - Tx Counter Event Overflow
+ * - Transmit FIFO Underrun
+ */
+ IntMask = GMAC_DEF_MSK;
+
+#ifdef DEBUG
+ /* add IRQ for Receive FIFO Overrun */
+ IntMask |= GM_IS_RX_FF_OR;
+#endif /* DEBUG */
+
+ SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask);
+
+ /* get General Purpose Control */
+ GM_IN16(IoC, Port, GM_GP_CTRL, &Reg);
+
+ if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+ pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) {
+ /* set to Full Duplex */
+ Reg |= GM_GPCR_DUP_FULL;
+ }
+
+ /* enable Rx/Tx */
+ GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Reg | GM_GPCR_RX_ENA |
+ GM_GPCR_TX_ENA));
+
+#ifndef VCPU
+ /* Enable all PHY interrupts */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK,
+ (SK_U16)PHY_M_DEF_MSK);
+#endif /* VCPU */
+ }
+#endif /* YUKON */
+
+ return(0);
+
+} /* SkMacRxTxEnable */
+
+
+/******************************************************************************
+ *
+ * SkMacRxTxDisable() - Disable Receiver and Transmitter
+ *
+ * Description: disables Rx/Tx dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacRxTxDisable(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U16 Word;
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+ XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+
+ /* dummy read to ensure writing */
+ XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+
+ GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+
+ GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Word & ~(GM_GPCR_RX_ENA |
+ GM_GPCR_TX_ENA)));
+
+ /* dummy read to ensure writing */
+ GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+ }
+#endif /* YUKON */
+
+} /* SkMacRxTxDisable */
+
+
+/******************************************************************************
+ *
+ * SkMacIrqDisable() - Disable IRQ from MAC
+ *
+ * Description: sets the IRQ-mask to disable IRQ dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacIrqDisable(
+SK_AC *pAC, /* Adapter Context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+#ifdef GENESIS
+ SK_U16 Word;
+#endif
+
+ pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+
+ /* disable all XMAC IRQs */
+ XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+
+ /* Disable all PHY interrupts */
+ switch (pPrt->PhyType) {
+ case SK_PHY_BCOM:
+ /* Make sure that PHY is initialized */
+ if (pPrt->PState != SK_PRT_RESET) {
+ /* NOT allowed if BCOM is in RESET state */
+ /* Workaround BCOM Errata (#10523) all BCom */
+ /* Disable Power Management if link is down */
+ SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word);
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+ (SK_U16)(Word | PHY_B_AC_DIS_PM));
+ SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+ }
+ break;
+#ifdef OTHER_PHY
+ case SK_PHY_LONE:
+ SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+ break;
+ case SK_PHY_NAT:
+ /* todo: National
+ SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+ break;
+#endif /* OTHER_PHY */
+ }
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* disable all GMAC IRQs */
+ SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+
+#ifndef VCPU
+ /* Disable all PHY interrupts */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+#endif /* VCPU */
+ }
+#endif /* YUKON */
+
+} /* SkMacIrqDisable */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ * SkXmSendCont() - Enable / Disable Send Continuous Mode
+ *
+ * Description: enable / disable Send Continuous Mode on XMAC
+ *
+ * Returns:
+ * nothing
+ */
+void SkXmSendCont(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL Enable) /* Enable / Disable */
+{
+ SK_U32 MdReg;
+
+ XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+ if (Enable) {
+ MdReg |= XM_MD_TX_CONT;
+ }
+ else {
+ MdReg &= ~XM_MD_TX_CONT;
+ }
+ /* setup Mode Register */
+ XM_OUT32(IoC, Port, XM_MODE, MdReg);
+
+} /* SkXmSendCont */
+
+
+/******************************************************************************
+ *
+ * SkMacTimeStamp() - Enable / Disable Time Stamp
+ *
+ * Description: enable / disable Time Stamp generation for Rx packets
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacTimeStamp(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL Enable) /* Enable / Disable */
+{
+ SK_U32 MdReg;
+ SK_U8 TimeCtrl;
+
+ if (pAC->GIni.GIGenesis) {
+
+ XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+ if (Enable) {
+ MdReg |= XM_MD_ATS;
+ }
+ else {
+ MdReg &= ~XM_MD_ATS;
+ }
+ /* setup Mode Register */
+ XM_OUT32(IoC, Port, XM_MODE, MdReg);
+ }
+ else {
+ if (Enable) {
+ TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ;
+ }
+ else {
+ TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ;
+ }
+ /* Start/Stop Time Stamp Timer */
+ SK_OUT8(IoC, GMAC_TI_ST_CTRL, TimeCtrl);
+ }
+
+} /* SkMacTimeStamp*/
+
+#else /* !SK_DIAG */
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg
+ *
+ * This function analyses the Interrupt status word. If any of the
+ * Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable
+ * is set true.
+ */
+void SkXmAutoNegLipaXmac(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_U16 IStatus) /* Interrupt Status word to analyse */
+{
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+ (IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04X\n",
+ Port, IStatus));
+ pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+ }
+} /* SkXmAutoNegLipaXmac */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg
+ *
+ * This function analyses the PHY status word.
+ * If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable
+ * is set true.
+ */
+void SkMacAutoNegLipaPhy(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_U16 PhyStat) /* PHY Status word to analyse */
+{
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+ (PhyStat & PHY_ST_AN_OVER) != 0) {
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04X\n",
+ Port, PhyStat));
+ pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+ }
+} /* SkMacAutoNegLipaPhy */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmIrq() - Interrupt Service Routine
+ *
+ * Description: services an Interrupt Request of the XMAC
+ *
+ * Note:
+ * With an external PHY, some interrupt bits are not meaningfull any more:
+ * - LinkAsyncEvent (bit #14) XM_IS_LNK_AE
+ * - LinkPartnerReqConfig (bit #10) XM_IS_LIPA_RC
+ * - Page Received (bit #9) XM_IS_RX_PAGE
+ * - NextPageLoadedForXmt (bit #8) XM_IS_TX_PAGE
+ * - AutoNegDone (bit #7) XM_IS_AND
+ * Also probably not valid any more is the GP0 input bit:
+ * - GPRegisterBit0set XM_IS_INP_ASS
+ *
+ * Returns:
+ * nothing
+ */
+static void SkXmIrq(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_EVPARA Para;
+ SK_U16 IStatus; /* Interrupt status read from the XMAC */
+ SK_U16 IStatus2;
+#ifdef SK_SLIM
+ SK_U64 OverflowStatus;
+#endif
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ XM_IN16(IoC, Port, XM_ISRC, &IStatus);
+
+ /* LinkPartner Auto-negable? */
+ if (pPrt->PhyType == SK_PHY_XMAC) {
+ SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+ }
+ else {
+ /* mask bits that are not used with ext. PHY */
+ IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
+ XM_IS_RX_PAGE | XM_IS_TX_PAGE |
+ XM_IS_AND | XM_IS_INP_ASS);
+ }
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("XmacIrq Port %d Isr 0x%04X\n", Port, IStatus));
+
+ if (!pPrt->PHWLinkUp) {
+ /* Spurious XMAC interrupt */
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("SkXmIrq: spurious interrupt on Port %d\n", Port));
+ return;
+ }
+
+ if ((IStatus & XM_IS_INP_ASS) != 0) {
+ /* Reread ISR Register if link is not in sync */
+ XM_IN16(IoC, Port, XM_ISRC, &IStatus2);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("SkXmIrq: Link async. Double check Port %d 0x%04X 0x%04X\n",
+ Port, IStatus, IStatus2));
+ IStatus &= ~XM_IS_INP_ASS;
+ IStatus |= IStatus2;
+ }
+
+ if ((IStatus & XM_IS_LNK_AE) != 0) {
+ /* not used, GP0 is used instead */
+ }
+
+ if ((IStatus & XM_IS_TX_ABORT) != 0) {
+ /* not used */
+ }
+
+ if ((IStatus & XM_IS_FRC_INT) != 0) {
+ /* not used, use ASIC IRQ instead if needed */
+ }
+
+ if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) {
+ SkHWLinkDown(pAC, IoC, Port);
+
+ /* Signal to RLMT */
+ Para.Para32[0] = (SK_U32)Port;
+ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+ /* Start workaround Errata #2 timer */
+ SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+ SKGE_HWAC, SK_HWEV_WATIM, Para);
+ }
+
+ if ((IStatus & XM_IS_RX_PAGE) != 0) {
+ /* not used */
+ }
+
+ if ((IStatus & XM_IS_TX_PAGE) != 0) {
+ /* not used */
+ }
+
+ if ((IStatus & XM_IS_AND) != 0) {
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("SkXmIrq: AND on link that is up Port %d\n", Port));
+ }
+
+ if ((IStatus & XM_IS_TSC_OV) != 0) {
+ /* not used */
+ }
+
+ /* Combined Tx & Rx Counter Overflow SIRQ Event */
+ if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) {
+#ifdef SK_SLIM
+ SkXmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
+#else
+ Para.Para32[0] = (SK_U32)Port;
+ Para.Para32[1] = (SK_U32)IStatus;
+ SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+#endif /* SK_SLIM */
+ }
+
+ if ((IStatus & XM_IS_RXF_OV) != 0) {
+ /* normal situation -> no effect */
+#ifdef DEBUG
+ pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+ }
+
+ if ((IStatus & XM_IS_TXF_UR) != 0) {
+ /* may NOT happen -> error log */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+ }
+
+ if ((IStatus & XM_IS_TX_COMP) != 0) {
+ /* not served here */
+ }
+
+ if ((IStatus & XM_IS_RX_COMP) != 0) {
+ /* not served here */
+ }
+} /* SkXmIrq */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmIrq() - Interrupt Service Routine
+ *
+ * Description: services an Interrupt Request of the GMAC
+ *
+ * Note:
+ *
+ * Returns:
+ * nothing
+ */
+static void SkGmIrq(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U8 IStatus; /* Interrupt status */
+#ifdef SK_SLIM
+ SK_U64 OverflowStatus;
+#else
+ SK_EVPARA Para;
+#endif
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus);
+
+#ifdef XXX
+ /* LinkPartner Auto-negable? */
+ SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus);
+#endif /* XXX */
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+ ("GmacIrq Port %d Isr 0x%04X\n", Port, IStatus));
+
+ /* Combined Tx & Rx Counter Overflow SIRQ Event */
+ if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) {
+ /* these IRQs will be cleared by reading GMACs register */
+#ifdef SK_SLIM
+ SkGmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
+#else
+ Para.Para32[0] = (SK_U32)Port;
+ Para.Para32[1] = (SK_U32)IStatus;
+ SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+#endif
+ }
+
+ if (IStatus & GM_IS_RX_FF_OR) {
+ /* clear GMAC Rx FIFO Overrun IRQ */
+ SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO);
+#ifdef DEBUG
+ pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+ }
+
+ if (IStatus & GM_IS_TX_FF_UR) {
+ /* clear GMAC Tx FIFO Underrun IRQ */
+ SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU);
+ /* may NOT happen -> error log */
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+ }
+
+ if (IStatus & GM_IS_TX_COMPL) {
+ /* not served here */
+ }
+
+ if (IStatus & GM_IS_RX_COMPL) {
+ /* not served here */
+ }
+} /* SkGmIrq */
+#endif /* YUKON */
+
+
+/******************************************************************************
+ *
+ * SkMacIrq() - Interrupt Service Routine for MAC
+ *
+ * Description: calls the Interrupt Service Routine dep. on board type
+ *
+ * Returns:
+ * nothing
+ */
+void SkMacIrq(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port) /* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+ if (pAC->GIni.GIGenesis) {
+ /* IRQ from XMAC */
+ SkXmIrq(pAC, IoC, Port);
+ }
+#endif /* GENESIS */
+
+#ifdef YUKON
+ if (pAC->GIni.GIYukon) {
+ /* IRQ from GMAC */
+ SkGmIrq(pAC, IoC, Port);
+ }
+#endif /* YUKON */
+
+} /* SkMacIrq */
+
+#endif /* !SK_DIAG */
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkXmUpdateStats() - Force the XMAC to output the current statistic
+ *
+ * Description:
+ * The XMAC holds its statistic internally. To obtain the current
+ * values a command must be sent so that the statistic data will
+ * be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkXmUpdateStats(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_GEPORT *pPrt;
+ SK_U16 StatReg;
+ int WaitIndex;
+
+ pPrt = &pAC->GIni.GP[Port];
+ WaitIndex = 0;
+
+ /* Send an update command to XMAC specified */
+ XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
+
+ /*
+ * It is an auto-clearing register. If the command bits
+ * went to zero again, the statistics are transferred.
+ * Normally the command should be executed immediately.
+ * But just to be sure we execute a loop.
+ */
+ do {
+
+ XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg);
+
+ if (++WaitIndex > 10) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG);
+
+ return(1);
+ }
+ } while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0);
+
+ return(0);
+} /* SkXmUpdateStats */
+
+
+/******************************************************************************
+ *
+ * SkXmMacStatistic() - Get XMAC counter value
+ *
+ * Description:
+ * Gets the 32bit counter value. Except for the octet counters
+ * the lower 32bit are counted in hardware and the upper 32bit
+ * must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkXmMacStatistic(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port, /* Port Index (MAC_1 + n) */
+SK_U16 StatAddr, /* MIB counter base address */
+SK_U32 SK_FAR *pVal) /* ptr to return statistic value */
+{
+ if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+
+ return(1);
+ }
+
+ XM_IN32(IoC, Port, StatAddr, pVal);
+
+ return(0);
+} /* SkXmMacStatistic */
+
+
+/******************************************************************************
+ *
+ * SkXmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ * Force the XMAC to clear its statistic counter.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkXmResetCounter(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port) /* Port Index (MAC_1 + n) */
+{
+ XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+ /* Clear two times according to Errata #3 */
+ XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+ return(0);
+} /* SkXmResetCounter */
+
+
+/******************************************************************************
+ *
+ * SkXmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ * Checks the source causing an counter overflow interrupt. On success the
+ * resulting counter overflow status is written to <pStatus>, whereas the
+ * upper dword stores the XMAC ReceiveCounterEvent register and the lower
+ * dword the XMAC TransmitCounterEvent register.
+ *
+ * Note:
+ * For XMAC the interrupt source is a self-clearing register, so the source
+ * must be checked only once. SIRQ module does another check to be sure
+ * that no interrupt get lost during process time.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkXmOverflowStatus(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port, /* Port Index (MAC_1 + n) */
+SK_U16 IStatus, /* Interupt Status from MAC */
+SK_U64 SK_FAR *pStatus) /* ptr for return overflow status value */
+{
+ SK_U64 Status; /* Overflow status */
+ SK_U32 RegVal;
+
+ Status = 0;
+
+ if ((IStatus & XM_IS_RXC_OV) != 0) {
+
+ XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal);
+ Status |= (SK_U64)RegVal << 32;
+ }
+
+ if ((IStatus & XM_IS_TXC_OV) != 0) {
+
+ XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal);
+ Status |= (SK_U64)RegVal;
+ }
+
+ *pStatus = Status;
+
+ return(0);
+} /* SkXmOverflowStatus */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGmUpdateStats() - Force the GMAC to output the current statistic
+ *
+ * Description:
+ * Empty function for GMAC. Statistic data is accessible in direct way.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkGmUpdateStats(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port) /* Port Index (MAC_1 + n) */
+{
+ return(0);
+}
+
+
+/******************************************************************************
+ *
+ * SkGmMacStatistic() - Get GMAC counter value
+ *
+ * Description:
+ * Gets the 32bit counter value. Except for the octet counters
+ * the lower 32bit are counted in hardware and the upper 32bit
+ * must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkGmMacStatistic(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port, /* Port Index (MAC_1 + n) */
+SK_U16 StatAddr, /* MIB counter base address */
+SK_U32 SK_FAR *pVal) /* ptr to return statistic value */
+{
+
+ if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) {
+
+ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr));
+ return(1);
+ }
+
+ GM_IN32(IoC, Port, StatAddr, pVal);
+
+ return(0);
+} /* SkGmMacStatistic */
+
+
+/******************************************************************************
+ *
+ * SkGmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ * Force GMAC to clear its statistic counter.
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkGmResetCounter(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port) /* Port Index (MAC_1 + n) */
+{
+ SK_U16 Reg; /* Phy Address Register */
+ SK_U16 Word;
+ int i;
+
+ GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg);
+
+ /* set MIB Clear Counter Mode */
+ GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR);
+
+ /* read all MIB Counters with Clear Mode set */
+ for (i = 0; i < GM_MIB_CNT_SIZE; i++) {
+ /* the reset is performed only when the lower 16 bits are read */
+ GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word);
+ }
+
+ /* clear MIB Clear Counter Mode */
+ GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg);
+
+ return(0);
+} /* SkGmResetCounter */
+
+
+/******************************************************************************
+ *
+ * SkGmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ * Checks the source causing an counter overflow interrupt. On success the
+ * resulting counter overflow status is written to <pStatus>, whereas the
+ * the following bit coding is used:
+ * 63:56 - unused
+ * 55:48 - TxRx interrupt register bit7:0
+ * 32:47 - Rx interrupt register
+ * 31:24 - unused
+ * 23:16 - TxRx interrupt register bit15:8
+ * 15:0 - Tx interrupt register
+ *
+ * Returns:
+ * 0: success
+ * 1: something went wrong
+ */
+int SkGmOverflowStatus(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+unsigned int Port, /* Port Index (MAC_1 + n) */
+SK_U16 IStatus, /* Interupt Status from MAC */
+SK_U64 SK_FAR *pStatus) /* ptr for return overflow status value */
+{
+ SK_U64 Status; /* Overflow status */
+ SK_U16 RegVal;
+
+ Status = 0;
+
+ if ((IStatus & GM_IS_RX_CO_OV) != 0) {
+ /* this register is self-clearing after read */
+ GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal);
+ Status |= (SK_U64)RegVal << 32;
+ }
+
+ if ((IStatus & GM_IS_TX_CO_OV) != 0) {
+ /* this register is self-clearing after read */
+ GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal);
+ Status |= (SK_U64)RegVal;
+ }
+
+ /* this register is self-clearing after read */
+ GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal);
+ /* Rx overflow interrupt register bits (LoByte)*/
+ Status |= (SK_U64)((SK_U8)RegVal) << 48;
+ /* Tx overflow interrupt register bits (HiByte)*/
+ Status |= (SK_U64)(RegVal >> 8) << 16;
+
+ *pStatus = Status;
+
+ return(0);
+} /* SkGmOverflowStatus */
+
+
+#ifndef SK_SLIM
+/******************************************************************************
+ *
+ * SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test
+ *
+ * Description:
+ * starts the cable diagnostic test if 'StartTest' is true
+ * gets the results if 'StartTest' is true
+ *
+ * NOTE: this test is meaningful only when link is down
+ *
+ * Returns:
+ * 0: success
+ * 1: no YUKON copper
+ * 2: test in progress
+ */
+int SkGmCableDiagStatus(
+SK_AC *pAC, /* adapter context */
+SK_IOC IoC, /* IO context */
+int Port, /* Port Index (MAC_1 + n) */
+SK_BOOL StartTest) /* flag for start / get result */
+{
+ int i;
+ SK_U16 RegVal;
+ SK_GEPORT *pPrt;
+
+ pPrt = &pAC->GIni.GP[Port];
+
+ if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+
+ return(1);
+ }
+
+ if (StartTest) {
+ /* only start the cable test */
+ if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) {
+ /* apply TDR workaround from Marvell */
+ SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e);
+
+ SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00);
+ SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800);
+ SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400);
+ SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000);
+ SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100);
+ }
+
+ /* set address to 0 for MDI[0] */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0);
+
+ /* Read Cable Diagnostic Reg */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+ /* start Cable Diagnostic Test */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG,
+ (SK_U16)(RegVal | PHY_M_CABD_ENA_TEST));
+
+ return(0);
+ }
+
+ /* Read Cable Diagnostic Reg */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+ ("PHY Cable Diag.=0x%04X\n", RegVal));
+
+ if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) {
+ /* test is running */
+ return(2);
+ }
+
+ /* get the test results */
+ for (i = 0; i < 4; i++) {
+ /* set address to i for MDI[i] */
+ SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i);
+
+ /* get Cable Diagnostic values */
+ SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+ pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK);
+
+ pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13);
+ }
+
+ return(0);
+} /* SkGmCableDiagStatus */
+#endif /* !SK_SLIM */
+#endif /* YUKON */
+
+/* End of file */
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 4fe624b0dd25..c77cc14b3227 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -43,25 +43,6 @@ static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
/*
* valid configuration values are:
*/
-#ifdef ISA
-const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ;
-const int opt_iops[] = {8,
- 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340};
-const int opt_dmas[] = {4, 3, 5, 6, 7} ;
-const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
- 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
-#endif
-#ifdef EISA
-const int opt_ints[] = {5, 9, 10, 11} ;
-const int opt_dmas[] = {0, 5, 6, 7} ;
-const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
- 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
-#endif
-
-#ifdef MCA
-int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */
-int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
-#endif /* MCA */
/*
* xPOS_ID:xxxx
@@ -78,17 +59,9 @@ int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
*/
#ifndef MULT_OEM
#ifndef OEM_CONCEPT
-#ifndef MCA
const u_char oem_id[] = "xPOS_ID:xxxx" ;
-#else
-const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */
-#endif
#else /* OEM_CONCEPT */
-#ifndef MCA
const u_char oem_id[] = OEM_ID ;
-#else
-const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */
-#endif /* MCA */
#endif /* OEM_CONCEPT */
#define ID_BYTE0 8
#define OEMID(smc,i) oem_id[ID_BYTE0 + i]
@@ -109,23 +82,6 @@ extern int AIX_vpdReadByte() ;
/* Prototype of a local function. */
static void smt_stop_watchdog(struct s_smc *smc);
-#ifdef MCA
-static int read_card_id() ;
-static void DisableSlotAccess() ;
-static void EnableSlotAccess() ;
-#ifdef AIX
-extern int attach_POS_addr() ;
-extern int detach_POS_addr() ;
-extern u_char read_POS() ;
-extern void write_POS() ;
-extern int AIX_vpdReadByte() ;
-#else
-#define read_POS(smc,a1,a2) ((u_char) inp(a1))
-#define write_POS(smc,a1,a2,a3) outp((a1),(a3))
-#endif
-#endif /* MCA */
-
-
/*
* FDDI card reset
*/
@@ -139,51 +95,6 @@ static void card_start(struct s_smc *smc)
smt_stop_watchdog(smc) ;
-#ifdef ISA
- outpw(CSR_A,0) ; /* reset for all chips */
- for (i = 10 ; i ; i--) /* delay for PLC's */
- (void)inpw(ISR_A) ;
- OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ;
- /* counter 2, mode 2 */
- OUT_82c54_TIMER(2,97) ; /* LSB */
- OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */
- outpw(CSR_A,CS_CRESET) ;
-#endif
-#ifdef EISA
- outpw(CSR_A,0) ; /* reset for all chips */
- for (i = 10 ; i ; i--) /* delay for PLC's */
- (void)inpw(ISR_A) ;
- outpw(CSR_A,CS_CRESET) ;
- smc->hw.led = (2<<6) ;
- outpw(CSR_A,CS_CRESET | smc->hw.led) ;
-#endif
-#ifdef MCA
- outp(ADDR(CARD_DIS),0) ; /* reset for all chips */
- for (i = 10 ; i ; i--) /* delay for PLC's */
- (void)inpw(ISR_A) ;
- outp(ADDR(CARD_EN),0) ;
- /* first I/O after reset must not be a access to FORMAC or PLC */
-
- /*
- * bus timeout (MCA)
- */
- OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ;
- /* counter 2, mode 3 */
- OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */
- OUT_82c54_TIMER(2,0) ; /* MSB */
-
- /* POS 102 indicated an activ Check Line or Buss Error monitoring */
- if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) {
- outp(ADDR(IRQ_CHCK_EN),0) ;
- }
-
- if (!((i = inpw(CSR_A)) & CS_SAS)) {
- if (!(i & CS_BYSTAT)) {
- outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
- }
- }
- outpw(LEDR_A,LED_1) ; /* yellow */
-#endif /* MCA */
#ifdef PCI
/*
* make sure no transfer activity is pending
@@ -253,15 +164,7 @@ void card_stop(struct s_smc *smc)
{
smt_stop_watchdog(smc) ;
smc->hw.mac_ring_is_up = 0 ; /* ring down */
-#ifdef ISA
- outpw(CSR_A,0) ; /* reset for all chips */
-#endif
-#ifdef EISA
- outpw(CSR_A,0) ; /* reset for all chips */
-#endif
-#ifdef MCA
- outp(ADDR(CARD_DIS),0) ; /* reset for all chips */
-#endif
+
#ifdef PCI
/*
* make sure no transfer activity is pending
@@ -284,60 +187,6 @@ void mac1_irq(struct s_smc *smc, u_short stu, u_short stl)
{
int restart_tx = 0 ;
again:
-#ifndef PCI
-#ifndef ISA
-/*
- * FORMAC+ bug modified the queue pointer if many read/write accesses happens!?
- */
- if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/
- FM_SPCEPDA0 | /* parit/coding err. a.q.0 */
- FM_SPCEPDA1 | /* parit/coding err. a.q.1 */
- FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */
- SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ;
- }
- if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/
- FM_STBURA0 | /* tx buffer underrun a.q.0 */
- FM_STBURA1 | /* tx buffer underrun a.q.1 */
- FM_STBURA2)) { /* tx buffer underrun a.q.2 */
- SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
- }
-#endif
- if ( (stu & (FM_SXMTABT | /* transmit abort */
-#ifdef SYNC
- FM_STXABRS | /* syn. tx abort */
-#endif /* SYNC */
- FM_STXABRA0)) || /* asyn. tx abort */
- (stl & (FM_SQLCKS | /* lock for syn. q. */
- FM_SQLCKA0)) ) { /* lock for asyn. q. */
- formac_tx_restart(smc) ; /* init tx */
- restart_tx = 1 ;
- stu = inpw(FM_A(FM_ST1U)) ;
- stl = inpw(FM_A(FM_ST1L)) ;
- stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
- if (stu || stl)
- goto again ;
- }
-
-#ifndef SYNC
- if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */
- FM_STEFRMA0)) { /* end of frame asyn tx */
- /* free tx_queue */
- smc->hw.n_a_send = 0 ;
- if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) {
- start_next_send(smc);
- }
- restart_tx = 1 ;
- }
-#else /* SYNC */
- if (stu & (FM_STEFRMA0 | /* end of asyn tx */
- FM_STEFRMS)) { /* end of sync tx */
- restart_tx = 1 ;
- }
-#endif /* SYNC */
- if (restart_tx)
- llc_restart_tx(smc) ;
-}
-#else /* PCI */
/*
* parity error: note encoding error is not possible in tag mode
@@ -378,7 +227,7 @@ again:
if (restart_tx)
llc_restart_tx(smc) ;
}
-#endif /* PCI */
+
/*
* interrupt source= plc1
* this function is called in nwfbisr.asm
@@ -387,10 +236,6 @@ void plc1_irq(struct s_smc *smc)
{
u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ;
-#if (defined(ISA) || defined(EISA))
- /* reset PLC Int. bits */
- outpw(PLC1_I,inpw(PLC1_I)) ;
-#endif
plc_irq(smc,PB,st) ;
}
@@ -402,10 +247,6 @@ void plc2_irq(struct s_smc *smc)
{
u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ;
-#if (defined(ISA) || defined(EISA))
- /* reset PLC Int. bits */
- outpw(PLC2_I,inpw(PLC2_I)) ;
-#endif
plc_irq(smc,PA,st) ;
}
@@ -446,43 +287,15 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
char PmdType ;
int i ;
-#if (defined(ISA) || defined(MCA))
- for (i = 0; i < 4 ;i++) { /* read mac address from board */
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inpw(PR_A(i+SA_MAC)));
- }
- for (i = 4; i < 6; i++) {
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
- }
-#endif
-#ifdef EISA
- /*
- * Note: We get trouble on an Alpha machine if we make a inpw()
- * instead of inp()
- */
- for (i = 0; i < 4 ;i++) { /* read mac address from board */
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inp(PR_A(i+SA_MAC)));
- }
- for (i = 4; i < 6; i++) {
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
- }
-#endif
#ifdef PCI
for (i = 0; i < 6; i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
bitrev8(inp(ADDR(B2_MAC_0+i)));
}
#endif
-#ifndef PCI
- ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ;
- PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ;
-#else
+
ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
PmdType = inp(ADDR(B2_PMD_TYP)) ;
-#endif
smc->y[PA].pmd_type[PMD_SK_CONN] =
smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
@@ -512,20 +325,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr)
card_start(smc) ;
read_address(smc,mac_addr) ;
-#ifndef PCI
- if (inpw(CSR_A) & CS_SAS)
-#else
if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
-#endif
smc->s.sas = SMT_SAS ; /* Single att. station */
else
smc->s.sas = SMT_DAS ; /* Dual att. station */
-#ifndef PCI
- if (inpw(CSR_A) & CS_BYSTAT)
-#else
if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
-#endif
smc->mib.fddiSMTBypassPresent = 0 ;
/* without opt. bypass */
else
@@ -538,42 +343,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr)
*/
void sm_pm_bypass_req(struct s_smc *smc, int mode)
{
-#if (defined(ISA) || defined(EISA))
- int csra_v ;
-#endif
-
DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
"BP_INSERT" : "BP_DEINSERT",0) ;
if (smc->s.sas != SMT_DAS)
return ;
-#if (defined(ISA) || defined(EISA))
-
- csra_v = inpw(CSR_A) & ~CS_BYPASS ;
-#ifdef EISA
- csra_v |= smc->hw.led ;
-#endif
-
- switch(mode) {
- case BP_INSERT :
- outpw(CSR_A,csra_v | CS_BYPASS) ;
- break ;
- case BP_DEINSERT :
- outpw(CSR_A,csra_v) ;
- break ;
- }
-#endif /* ISA / EISA */
-#ifdef MCA
- switch(mode) {
- case BP_INSERT :
- outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
- break ;
- case BP_DEINSERT :
- outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */
- break ;
- }
-#endif
#ifdef PCI
switch(mode) {
case BP_INSERT :
@@ -591,31 +366,14 @@ void sm_pm_bypass_req(struct s_smc *smc, int mode)
*/
int sm_pm_bypass_present(struct s_smc *smc)
{
-#ifndef PCI
- return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ;
-#else
return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
-#endif
}
void plc_clear_irq(struct s_smc *smc, int p)
{
SK_UNUSED(p) ;
-#if (defined(ISA) || defined(EISA))
- switch (p) {
- case PA :
- /* reset PLC Int. bits */
- outpw(PLC2_I,inpw(PLC2_I)) ;
- break ;
- case PB :
- /* reset PLC Int. bits */
- outpw(PLC1_I,inpw(PLC1_I)) ;
- break ;
- }
-#else
SK_UNUSED(smc) ;
-#endif
}
@@ -645,51 +403,6 @@ static void led_indication(struct s_smc *smc, int led_event)
phy = &smc->y[PB] ;
mib_b = phy->mib ;
-#ifdef EISA
- /* Ring up = yellow led OFF*/
- if (led_event == LED_Y_ON) {
- smc->hw.led |= CS_LED_1 ;
- }
- else if (led_event == LED_Y_OFF) {
- smc->hw.led &= ~CS_LED_1 ;
- }
- else {
- /* Link at Port A or B = green led ON */
- if (mib_a->fddiPORTPCMState == PC8_ACTIVE ||
- mib_b->fddiPORTPCMState == PC8_ACTIVE) {
- smc->hw.led |= CS_LED_0 ;
- }
- else {
- smc->hw.led &= ~CS_LED_0 ;
- }
- }
-#endif
-#ifdef MCA
- led_state = inpw(LEDR_A) ;
-
- /* Ring up = yellow led OFF*/
- if (led_event == LED_Y_ON) {
- led_state |= LED_1 ;
- }
- else if (led_event == LED_Y_OFF) {
- led_state &= ~LED_1 ;
- }
- else {
- led_state &= ~(LED_2|LED_0) ;
-
- /* Link at Port A = green led A ON */
- if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {
- led_state |= LED_2 ;
- }
-
- /* Link at Port B/S = green led B ON */
- if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
- led_state |= LED_0 ;
- }
- }
-
- outpw(LEDR_A, led_state) ;
-#endif /* MCA */
#ifdef PCI
led_state = 0 ;
@@ -824,446 +537,6 @@ int set_oi_id_def(struct s_smc *smc)
}
#endif /* MULT_OEM */
-
-#ifdef MCA
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- * exist_board
- *
- * Check if an MCA board is present in the specified slot.
- *
- * int exist_board(
- * struct s_smc *smc,
- * int slot) ;
- * In
- * smc - A pointer to the SMT Context struct.
- *
- * slot - The number of the slot to inspect.
- * Out
- * 0 = No adapter present.
- * 1 = Found FM1 adapter.
- *
- * Pseudo
- * Read MCA ID
- * for all valid OEM_IDs
- * compare with ID read
- * if equal, return 1
- * return(0
- *
- * Note
- * The smc pointer must be valid now.
- *
- * END_MANUAL_ENTRY()
- *
- ************************/
-#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff))
-int exist_board(struct s_smc *smc, int slot)
-{
-#ifdef MULT_OEM
- SK_LOC_DECL(u_char,id[2]) ;
- int idi ;
-#endif /* MULT_OEM */
-
- /* No longer valid. */
- if (smc == NULL)
- return(0) ;
-
-#ifndef MULT_OEM
- if (read_card_id(smc, slot)
- == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1)))
- return (1) ; /* Found FM adapter. */
-
-#else /* MULT_OEM */
- idi = read_card_id(smc, slot) ;
- id[0] = idi & 0xff ;
- id[1] = idi >> 8 ;
-
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-
- if (is_equal_num(&id[0],&OEMID(smc,0),2))
- return (1) ;
- }
-#endif /* MULT_OEM */
- return (0) ; /* No adapter found. */
-}
-
-/************************
- *
- * read_card_id
- *
- * Read the MCA card id from the specified slot.
- * In
- * smc - A pointer to the SMT Context struct.
- * CAVEAT: This pointer may be NULL and *must not* be used within this
- * function. It's only purpose is for drivers that need some information
- * for the inp() and outp() macros.
- *
- * slot - The number of the slot for which the card id is returned.
- * Out
- * Returns the card id read from the specified slot. If an illegal slot
- * number is specified, the function returns zero.
- *
- ************************/
-static int read_card_id(struct s_smc *smc, int slot)
-/* struct s_smc *smc ; Do not use. */
-{
- int card_id ;
-
- SK_UNUSED(smc) ; /* Make LINT happy. */
- if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */
- return (0) ; /* Illegal slot number specified. */
-
- EnableSlotAccess(smc, slot) ;
-
- card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) |
- (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ;
-
- DisableSlotAccess(smc) ;
-
- return (card_id) ;
-}
-
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- * get_board_para
- *
- * Get adapter configuration information. Fill all board specific
- * parameters within the 'smc' structure.
- *
- * int get_board_para(
- * struct s_smc *smc,
- * int slot) ;
- * In
- * smc - A pointer to the SMT Context struct, to which this function will
- * write some adapter configuration data.
- *
- * slot - The number of the slot, in which the adapter is installed.
- * Out
- * 0 = No adapter present.
- * 1 = Ok.
- * 2 = Adapter present, but card enable bit not set.
- *
- * END_MANUAL_ENTRY()
- *
- ************************/
-int get_board_para(struct s_smc *smc, int slot)
-{
- int val ;
- int i ;
-
- /* Check if adapter present & get type of adapter. */
- switch (exist_board(smc, slot)) {
- case 0: /* Adapter not present. */
- return (0) ;
- case 1: /* FM Rev. 1 */
- smc->hw.rev = FM1_REV ;
- smc->hw.VFullRead = 0x0a ;
- smc->hw.VFullWrite = 0x05 ;
- smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */
- break ;
- }
- smc->hw.slot = slot ;
-
- EnableSlotAccess(smc, slot) ;
-
- if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) {
- DisableSlotAccess(smc) ;
- return (2) ; /* Card enable bit not set. */
- }
-
- val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */
-
-#ifndef MEM_MAPPED_IO /* is defined by the operating system */
- i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */
- smc->hw.iop = (i + 1) * 0x0400 - 0x200 ;
-#endif
- i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */
- smc->hw.irq = opt_ints[i] ;
-
- /* FPROM base addr. */
- i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ;
- smc->hw.eprom = opt_eproms[i] ;
-
- DisableSlotAccess(smc) ;
-
- /* before this, the smc->hw.iop must be set !!! */
- smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ;
-
- return (1) ;
-}
-
-/* Enable access to specified MCA slot. */
-static void EnableSlotAccess(struct s_smc *smc, int slot)
-{
- SK_UNUSED(slot) ;
-
-#ifndef AIX
- SK_UNUSED(smc) ;
-
- /* System mode. */
- outp(POS_SYS_SETUP, POS_SYSTEM) ;
-
- /* Select slot. */
- outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ;
-#else
- attach_POS_addr (smc) ;
-#endif
-}
-
-/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */
-static void DisableSlotAccess(struct s_smc *smc)
-{
-#ifndef AIX
- SK_UNUSED(smc) ;
-
- outp(POS_CHANNEL_POS, 0) ;
-#else
- detach_POS_addr (smc) ;
-#endif
-}
-#endif /* MCA */
-
-#ifdef EISA
-#ifndef MEM_MAPPED_IO
-#define SADDR(slot) (((slot)<<12)&0xf000)
-#else /* MEM_MAPPED_IO */
-#define SADDR(slot) (smc->hw.iop)
-#endif /* MEM_MAPPED_IO */
-
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- * exist_board
- *
- * Check if an EISA board is present in the specified slot.
- *
- * int exist_board(
- * struct s_smc *smc,
- * int slot) ;
- * In
- * smc - A pointer to the SMT Context struct.
- *
- * slot - The number of the slot to inspect.
- * Out
- * 0 = No adapter present.
- * 1 = Found adapter.
- *
- * Pseudo
- * Read EISA ID
- * for all valid OEM_IDs
- * compare with ID read
- * if equal, return 1
- * return(0
- *
- * Note
- * The smc pointer must be valid now.
- *
- ************************/
-int exist_board(struct s_smc *smc, int slot)
-{
- int i ;
-#ifdef MULT_OEM
- SK_LOC_DECL(u_char,id[4]) ;
-#endif /* MULT_OEM */
-
- /* No longer valid. */
- if (smc == NULL)
- return(0);
-
- SK_UNUSED(slot) ;
-
-#ifndef MULT_OEM
- for (i = 0 ; i < 4 ; i++) {
- if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i))
- return(0) ;
- }
- return(1) ;
-#else /* MULT_OEM */
- for (i = 0 ; i < 4 ; i++)
- id[i] = inp(SADDR(slot)+PRA(i)) ;
-
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
-
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-
- if (is_equal_num(&id[0],&OEMID(smc,0),4))
- return (1) ;
- }
- return (0) ; /* No adapter found. */
-#endif /* MULT_OEM */
-}
-
-
-int get_board_para(struct s_smc *smc, int slot)
-{
- int i ;
-
- if (!exist_board(smc,slot))
- return(0) ;
-
- smc->hw.slot = slot ;
-#ifndef MEM_MAPPED_IO /* if defined by the operating system */
- smc->hw.iop = SADDR(slot) ;
-#endif
-
- if (!(inp(C0_A(0))&CFG_CARD_EN)) {
- return(2) ; /* CFG_CARD_EN bit not set! */
- }
-
- smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ;
- smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ;
-
- if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f)
- smc->hw.eprom = opt_eproms[i] ;
- else
- smc->hw.eprom = 0 ;
-
- smc->hw.DmaWriteExtraBytes = 8 ;
-
- return(1) ;
-}
-#endif /* EISA */
-
-#ifdef ISA
-#ifndef MULT_OEM
-const u_char sklogo[6] = SKLOGO_STR ;
-#define SIZE_SKLOGO(smc) sizeof(sklogo)
-#define SKLOGO(smc,i) sklogo[i]
-#else /* MULT_OEM */
-#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len
-#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i]
-#endif /* MULT_OEM */
-
-
-int exist_board(struct s_smc *smc, HW_PTR port)
-{
- int i ;
-#ifdef MULT_OEM
- int bytes_read ;
- u_char board_logo[15] ;
- SK_LOC_DECL(u_char,id[4]) ;
-#endif /* MULT_OEM */
-
- /* No longer valid. */
- if (smc == NULL)
- return(0);
-
- SK_UNUSED(smc) ;
-#ifndef MULT_OEM
- for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) {
- if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) {
- return(0) ;
- }
- }
-
- /* check MAC address (S&K or other) */
- for (i = 0 ; i < 3 ; i++) {
- if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i))
- return(0) ;
- }
- return(1) ;
-#else /* MULT_OEM */
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
- board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ;
- bytes_read = 1 ;
-
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-
- /* Test all read bytes with current OEM_entry */
- /* for (i=0; (i<bytes_read) && (i < SIZE_SKLOGO(smc)); i++) { */
- for (i = 0; i < bytes_read; i++) {
- if (board_logo[i] != SKLOGO(smc,i))
- break ;
- }
-
- /* If mismatch, switch to next OEM entry */
- if ((board_logo[i] != SKLOGO(smc,i)) && (i < bytes_read))
- continue ;
-
- --i ;
- while (bytes_read < SIZE_SKLOGO(smc)) {
- // inpw next byte SK_Logo
- i++ ;
- board_logo[i] = (u_char)inpw((PRA(SADDRL+i)+port)) ;
- bytes_read++ ;
- if (board_logo[i] != SKLOGO(smc,i))
- break ;
- }
-
- for (i = 0 ; i < 3 ; i++)
- id[i] = (u_char)inpw((PRA(i)+port)) ;
-
- if ((board_logo[i] == SKLOGO(smc,i))
- && (bytes_read == SIZE_SKLOGO(smc))) {
-
- if (is_equal_num(&id[0],&OEMID(smc,0),3))
- return(1);
- }
- } /* for */
- return(0) ;
-#endif /* MULT_OEM */
-}
-
-int get_board_para(struct s_smc *smc, int slot)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(slot) ;
- return(0) ; /* for ISA not supported */
-}
-#endif /* ISA */
-
-#ifdef PCI
-#ifdef USE_BIOS_FUN
-int exist_board(struct s_smc *smc, int slot)
-{
- u_short dev_id ;
- u_short ven_id ;
- int found ;
- int i ;
-
- found = FALSE ; /* make sure we returned with adatper not found*/
- /* if an empty oemids.h was included */
-
-#ifdef MULT_OEM
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-#endif
- ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ;
- dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ;
- for (i = 0; i < slot; i++) {
- if (pci_find_device(i,&smc->hw.pci_handle,
- dev_id,ven_id) != 0) {
-
- found = FALSE ;
- } else {
- found = TRUE ;
- }
- }
- if (found) {
- return(1) ; /* adapter was found */
- }
-#ifdef MULT_OEM
- }
-#endif
- return(0) ; /* adapter was not found */
-}
-#endif /* PCI */
-#endif /* USE_BIOS_FUNC */
-
void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
{
int i ;
diff --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/skfp/h/mbuf.h
index b339d1f2e0e5..f2aadcda9e7f 100644
--- a/drivers/net/skfp/h/mbuf.h
+++ b/drivers/net/skfp/h/mbuf.h
@@ -15,11 +15,7 @@
#ifndef _MBUF_
#define _MBUF_
-#ifndef PCI
-#define M_SIZE 4550
-#else
#define M_SIZE 4504
-#endif
#ifndef MAX_MBUF
#define MAX_MBUF 4
diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h
index ba347d6910f1..c1ba26c06d73 100644
--- a/drivers/net/skfp/h/skfbi.h
+++ b/drivers/net/skfp/h/skfbi.h
@@ -15,797 +15,11 @@
#ifndef _SKFBI_H_
#define _SKFBI_H_
-#ifdef SYNC
-#define exist_board_far exist_board
-#define get_board_para_far get_board_para
-#endif
-
-/*
- * physical address offset + IO-Port base address
- */
-#ifndef PCI
-#define ADDR(a) ((a)+smc->hw.iop)
-#define ADDRS(smc,a) ((a)+(smc)->hw.iop)
-#endif
-
/*
- * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)})
+ * FDDI-Fx (x := {I(SA), P(CI)})
* address calculation & function defines
*/
-#ifdef EISA
-
-/*
- * Configuration PROM: !! all 8-Bit IO's !!
- * |<- MAC-Address ->|
- * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
- * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00|
- * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
- * IO- ^ ^ ^ ^ ^
- * port 0C80 0C83 0C88 0C90 0C98
- * | \
- * | \
- * | \______________________________________________
- * EISA Expansion Board Product ID: \
- * BIT: |7 6 5 4 3 2 1 0| \
- * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ^=reserved | product numb. | revision numb |
- * MAN_Cx = compressed manufacterer code (x:=0..2)
- * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!)
- */
-
-#ifndef MULT_OEM
-#ifndef OEM_CONCEPT
-#define MAN_C0 ('S'-0x40)
-#define MAN_C1 ('K'-0x40)
-#define MAN_C2 ('D'-0x40)
-#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3))
-#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2)
-#define PROD_ID2 (u_char)(1) /* prod. nr. */
-#define PROD_ID3 (u_char)(0) /* rev. nr. */
-
-#ifndef OEM_USER_DATA
-#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata"
-#endif
-#else /* OEM_CONCEPT */
-
-/* MAN_C(0|1|2) no longer present (ra). */
-#define PROD_ID0 (u_char)OEM_PROD_ID0
-#define PROD_ID1 (u_char)OEM_PROD_ID1
-#define PROD_ID2 (u_char)OEM_PROD_ID2
-#define PROD_ID3 (u_char)OEM_PROD_ID3
-#endif /* OEM_CONCEPT */
-
-#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3
-#endif /* MULT_OEM */
-
-#define SADDRL (0) /* start address SKLOGO */
-#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */
-#define PRA_OFF (4)
-#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
-
-#define SKFDDI_PSZ 32 /* address PROM size */
-
-/*
- * address transmission from logical to physical offset address on board
- */
-#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */
-#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */
-#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */
-#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */
-#define PRA(a) (0x0c80| (a)) /* configuration PROM */
-#define C0A(a) (0x0c84| (a)) /* config. RAM */
-#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */
-#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */
-
-#define CONF C0A(0) /* config RAM (card enable bit port) */
-#define PGRA C2A(0) /* Flash page register */
-#define CDID PRA(0) /* Card ID I/O port addr. offset */
-
-
-/*
- * physical address offset + slot specific IO-Port base address
- */
-#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */
-#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */
-#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */
-#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */
-#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */
-#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */
-#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */
-#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */
-
-
-#define CSRA 0x0008 /* control/status register address (r/w) */
-#define ISRA 0x0008 /* int. source register address (upper 8Bits) */
-#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */
-#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */
-#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */
-#define RQAA 0x001c /* Request reg. (write only) */
-#define WCTA 0x001e /* word counter (r/w) */
-#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */
-#ifdef UNIX
-#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */
-#endif
-#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */
-#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */
-#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */
-#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */
-#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */
-#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */
-#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-/*
- * control/status register CSRA bits
- */
-/* write */
-#define CS_CRESET 0x01 /* Card reset (0=reset) */
-#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */
-#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */
-#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */
-#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/
-#define CS_LED_0 0x40 /* switch LED 0 */
-#define CS_LED_1 0x80 /* switch LED 1 */
-/* read */
-#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */
-#define CS_SAS 0x80 /* single attachement station (=1) */
-
-/*
- * control/status register CSFA bits (FIFO)
- */
-#define CSF_MUX0 0x01
-#define CSF_MUX1 0x02
-#define CSF_HSREQ0 0x04
-#define CSF_HSREQ1 0x08
-#define CSF_HSREQ2 0x10
-#define CSF_BUSY_DMA 0x40
-#define CSF_BUSY_FIFO 0x80
-
-/*
- * Interrupt source register ISRA (upper 8 data bits) read only & low activ.
- */
-#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/
-#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/
-#define IS_PLINT1 0x0400 /* PLC1 */
-#define IS_PLINT2 0x0800 /* PLC2 */
-#define IS_TIMINT 0x1000 /* Timer 82C54-2 */
-#define IS_TC 0x2000 /* transf. counter */
-
-#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC)
-
-/*
- * CONFIG<0> RAM (C0_A())
- */
-#define CFG_CARD_EN 0x01 /* card enable */
-
-/*
- * CONFIG<1> RAM (C1_A())
- */
-#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */
-#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */
-#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */
-#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */
-#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */
-
-/*
- * CONFIG<2> RAM (C2_A())
- */
-#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */
-#define CFG_PAGE 0xf0 /* FPROM page selection */
-
-
-#define READ_PROM(a) ((u_char)inp(a))
-#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE))
-#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN)
-
-#define MAX_PAGES 16 /* 16 pages */
-#define MAX_FADDR 0x2000 /* 8K per page */
-#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN)
-#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN)
-
-#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA)
-#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO)
-#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
-#define BUS_CHECK()
-
-#ifdef UNISYS
-/* For UNISYS use another macro with drv_usecewait function */
-#define CHECK_DMA() {u_long k = 1000000; \
- while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-#else
-#define CHECK_DMA() {u_long k = 1000000 ;\
- while (k && (DMA_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-#endif
-
-#define CHECK_FIFO() {u_long k = 1000000 ;\
- while (k && (FIFO_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
-
-#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
- while (k && (DMA_FIFO_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
-
-#define GET_ISR() ~inpw(ISR_A)
-#define CHECK_ISR() ~inpw(ISR_A)
-
-#ifndef UNIX
-#ifndef WINNT
-#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\
- (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
-#else /* WINNT */
-#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\
- (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
-#endif /* WINNT */
-#else /* UNIX */
-#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
- (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led)
-#endif
-
-#ifndef UNIX
-#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\
- (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led)
-#else
-#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
- (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led)
-#endif
-
-/* EISA DMA Controller */
-#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */
-#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */
-#define DMA_CLEAR_BYTE_POINTER_M 0x0c
-#define DMA_CLEAR_BYTE_POINTER_S 0xd8
-
-#endif /* EISA */
-
-#ifdef MCA
-
-/*
- * POS Register: !! all I/O's are 8-Bit !!
- */
-#define POS_SYS_SETUP 0x94 /* system setup register */
-#define POS_SYSTEM 0xff /* system mode */
-
-#define POS_CHANNEL_POS 0x96 /* register slot ID */
-#define POS_CHANNEL_BIT 0x08 /* mask for -"- */
-
-#define POS_BASE 0x100 /* POS base address */
-#define POS_ID_LOW POS_BASE /* card ID low */
-#define POS_ID_HIGH (POS_BASE+1) /* card ID high */
-#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */
-#define POS_103 (POS_BASE+3) /* FPROM addr, page */
-#define POS_104 (POS_BASE+4) /* I/O, IRQ */
-#define POS_105 (POS_BASE+5) /* POS_CHCK */
-#define POS_106 (POS_BASE+6) /* to read VPD */
-#define POS_107 (POS_BASE+7) /* added without function */
-
-/* FM1 card IDs */
-#define FM1_CARD_ID0 0x83
-#define FM1_CARD_ID1 0
-
-#define FM1_IBM_ID0 0x9c
-#define FM1_IBM_ID1 0x8f
-
-
-/* FM2 card IDs */
-#define FM2_CARD_ID0 0xab
-#define FM2_CARD_ID1 0
-
-#define FM2_IBM_ID0 0x7e
-#define FM2_IBM_ID1 0x8f
-
-/* Board revision. */
-#define FM1_REV 0
-#define FM2_REV 1
-
-#define MAX_SLOT 8
-
-/*
- * POS_102
- */
-#define POS_CARD_EN 0x01 /* card enable =1 */
-#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */
-#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */
-#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */
-#define POS_FAIRNESS 0x10 /* fairnes on =1 */
-/* attention: arbitration level used with bit 0 POS 105 */
-#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8
- (1,1,1)->level = 0xf */
-/*
- * POS_103
- */
-#define POS_PAGE 0x07 /* FPROM page selection */
-#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */
-#define POS_MSEL 0x70 /* memory start address for FPROM mapping */
-#define PROG_EN 0x80 /* FM1: Vpp prog on/off */
-#define POS_SDR 0x80 /* FM2: Streaming data bit */
-
-/*
- * POS_104
- */
-#define POS_IOSEL 0x3f /* selected I/O base address */
-#define POS_IRQSEL 0xc0 /* selected interrupt */
-
-/*
- * POS_105
- */
-#define POS_CHCK 0x80
-#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */
-#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */
-#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */
-#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */
-#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */
-
-#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
-#define PRA_OFF (0)
-#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
-
-/*
- * address transmission from logical to physical offset address on board
- */
-#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */
-#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */
-#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */
-#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */
-#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */
-#define CS(a) (0x0020| (a)) /* control/status */
-#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */
-#define CT(a) (0x0000|((a)<<1)) /* counter */
-
-/*
- * counter
- */
-#define ACLA CT(0) /* address counter low */
-#define ACHA CT(1) /* address counter high */
-#define BCN CT(2) /* byte counter */
-#define MUX CT(3) /* MUX-register */
-#define WCN CT(0x08) /* word counter */
-#define FFLG CT(0x09) /* FIFO Flags */
-
-/*
- * test/control register (FM2 only)
- */
-#define CNT_TST 0x018 /* Counter test control register */
-#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */
-
-/*
- * CS register (read only)
- */
-#define CSRA CS(0) /* control/status register address */
-#define CSFA CS(2) /* control/status FIFO BUSY ... */
-#define ISRA CS(4) /* first int. source register address */
-#define ISR2 CS(6) /* second int. source register address */
-#define LEDR CS(0x0c) /* LED register r/w */
-#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */
-#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */
-#define CSA CS(0x14) /* - " - POS_102 */
-#define CSM CS(0x0e) /* - " - POS_103 */
-#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */
-#define CSI CS(0x18) /* - " - POS_104 */
-#define CSS CS(0x1a) /* - " - POS_105 */
-#define CSP_06 CS(0x1c) /* - " - POS_106 */
-#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */
-#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */
-#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */
-
-#define PGRA CSM /* Flash page register */
-
-
-#define WCTA FF(0) /* word counter */
-#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-/*
- * Timer register (FM2 only)
- */
-#define RTM_CNT 0x28 /* RTM Counter */
-#define TI_DIV 0x60 /* Timer Prescaler */
-#define TI_CH1 0x62 /* Timer channel 1 counter */
-#define TI_STOP 0x64 /* Stop timer on channel 1 */
-#define TI_STRT 0x66 /* Start timer on channel 1 */
-#define TI_INI2 0x68 /* Timer: Bus master preemption */
-#define TI_CNT2 0x6a /* Timer */
-#define TI_INI3 0x6c /* Timer: Streaming data */
-#define TI_CNT3 0x6e /* Timer */
-#define WDOG_LO 0x70 /* Watchdog counter low */
-#define WDOG_HI 0x72 /* Watchdog counter high */
-#define RTM_PRE 0x74 /* restr. token prescaler */
-#define RTM_TIM 0x76 /* restr. token timer */
-
-/*
- * Recommended Timeout values (for FM2 timer only)
- */
-#define TOUT_BM_PRE 188 /* 3.76 usec */
-#define TOUT_S_DAT 374 /* 7.48 usec */
-
-/*
- * CS register (write only)
- */
-#define HSR(p) CS(0x18|(p)) /* Host request register */
-
-#define RTM_PUT 0x36 /* restr. token counter write */
-#define RTM_GET 0x28 /* - " - clear */
-#define RTM_CLEAR 0x34 /* - " - read */
-
-/*
- * BCN Bit definitions
- */
-#define BCN_BUSY 0x8000 /* DMA Busy flag */
-#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */
-#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */
-
-/*
- * WCN Bit definitions
- */
-#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */
-#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */
-
-/*
- * CNT_TST Bit definitions
- */
-#define CNT_MODE 0x01 /* Go into test mode */
-#define CNT_D32 0x02 /* 16/32 BIT test mode */
-
-/*
- * FIFO Flag FIFO Flags/Vfull register
- */
-#define FF_VFULL 0x003f /* V_full value mask */
-#define FFLG_FULL 0x2000 /* FULL flag */
-#define FFLG_A_FULL 0x1000 /* Almost full flag */
-#define FFLG_VFULL 0x0800 /* V_full Flag */
-#define FFLG_A_EMP 0x0400 /* almost empty flag */
-#define FFLG_EMP 0x0200 /* empty flag */
-#define FFLG_T_EMP 0x0100 /* totally empty flag */
-
-/*
- * WDOG Watchdog status register
- */
-#define WDOG_ALM 0x01 /* Watchdog alarm Bit */
-#define WDOG_ACT 0x02 /* Watchdog active Bit */
-
-/*
- * CS(0) CONTROLS
- */
-#define CS_CRESET 0x0001
-#define FIFO_RST 0x0002
-#define CS_IMSK 0x0004
-#define EN_IRQ_CHCK 0x0008
-#define EN_IRQ_TOKEN 0x0010
-#define EN_IRQ_TC 0x0020
-#define TOKEN_STATUS 0x0040
-#define RTM_CHANGE 0x0080
-
-#define CS_SAS 0x0100
-#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */
-#define CS_BYPASS 0x0400 /* bypass on/off indication */
-
-/*
- * CS(2) FIFOSTAT
- */
-#define HSREQ 0x0007
-#define BIGDIR 0x0008
-#define CSF_BUSY_FIFO 0x0010
-#define CSF_BUSY_DMA 0x0020
-#define SLOT_32 0x0040
-
-#define LED_0 0x0001
-#define LED_1 0x0002
-#define LED_2 0x0100
-
-#define MAX_PAGES 8 /* pages */
-#define MAX_FADDR 0x4000 /* 16K per page */
-
-/*
- * IRQ = ISRA || ISR2 ;
- *
- * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ;
- * ISR2 = IRQ_TC_EN && IS_TC ;
- *
- * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) ||
- * (IRQ_EN_TOKEN && IS_TOKEN) ;
- * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ;
- */
-/*
- * ISRA !!! activ high !!!
- */
-#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/
-#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/
-#define IS_PLINT1 0x0004 /* PLC1 */
-#define IS_PLINT2 0x0008 /* PLC2 */
-#define IS_TIMINT 0x0010 /* Timer 82C54-2 */
-#define IS_TOKEN 0x0020 /* restrictet token monitoring */
-#define IS_CHCK_L 0x0040 /* check line asserted */
-#define IS_BUSERR 0x0080 /* bus error */
-/*
- * ISR2
- */
-#define IS_TC 0x0001 /* terminal count irq */
-#define IS_SFDBKRTN 0x0002 /* selected feedback return */
-#define IS_D16 0x0004 /* DS16 */
-#define IS_D32 0x0008 /* DS32 */
-#define IS_DPEI 0x0010 /* Data Parity Indication */
-
-#define ALL_IRSR 0x00ff
-
-#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */
-#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */
-#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */
-#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */
-#define PR_A(a) ADDR(PR(a)) /* config. PROM */
-#define CS_A(a) ADDR(CS(a)) /* control/status */
-
-#define ISR1_A ADDR(ISRA) /* first int. source register address */
-#define ISR2_A ADDR(ISR2) /* second -"- */
-#define CSR_A ADDR(CSRA) /* control/status register address */
-#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */
-
-#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */
-#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */
-#define CSA_A ADDR(CSA) /* - " - POS_102 */
-#define CSI_A ADDR(CSI) /* - " - POS_104 */
-#define CSM_A ADDR(CSM) /* - " - POS_103 */
-#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */
-#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */
-
-#define WCT_A ADDR(WCTA) /* word counter (r/w) */
-#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-#define ACL_A ADDR(ACLA) /* address counter low */
-#define ACH_A ADDR(ACHA) /* address counter high */
-#define BCN_A ADDR(BCN) /* byte counter */
-#define MUX_A ADDR(MUX) /* MUX-register */
-
-#define ISR_A ADDR(ISRA) /* Interrupt Source Register */
-#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */
-#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */
-
-#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */
-#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */
-/*
- * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A)
- */
-#define HSR_A(p) ADDR(HSR(p)) /* Host request register */
-
-#define STAT_BYP 0 /* bypass station */
-#define STAT_INS 2 /* insert station */
-#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */
-
-#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */
-#define IRQ_TC_DIS CS(0x0a)
-#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */
-#define IRQ_TOKEN_DIS CS(8)
-#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */
-#define IRQ_CHCK_DIS CS(6)
-#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */
-#define IRQ_OTH_DIS CS(4)
-#define FIFO_EN CS(3) /* disable (reset), enable FIFO */
-#define FIFO_RESET CS(2)
-#define CARD_EN CS(1) /* disable (reset), enable card */
-#define CARD_DIS CS(0)
-
-#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */
-#define PAGE_RG_A ADDR(CSM) /* D<2..0> */
-#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN)
-#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS)
-
-#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\
- (~POS_PAGE)) |(int) (bank))
-#define VPP_ON() if (smc->hw.rev == FM1_REV) { \
- outpw(PAGE_RG_A, \
- (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \
- }
-#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \
- outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \
- }
-
-#define SKFDDI_PSZ 16 /* address PROM size */
-
-#define READ_PROM(a) ((u_char)inp(a))
-
-#define GET_ISR() ~inpw(ISR1_A)
-#ifndef TCI
-#define CHECK_ISR() ~inpw(ISR1_A)
-#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA)
-#else
-#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A))
-#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2))
-#endif
-
-#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA)
-#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO)
-#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
-#define BUS_CHECK() { int i ; \
- if ((i = GET_ISR()) & IS_BUSERR) \
- SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \
- if (i & IS_CHCK_L) \
- SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \
- }
-
-#define CHECK_DMA() { u_long k = 10000 ; \
- while (k && (DMA_BUSY())) { \
- k-- ; \
- BUS_CHECK() ; \
- } \
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-
-#define CHECK_FIFO() {u_long k = 1000000 ;\
- while (k && (FIFO_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
-
-#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
- while (k && (DMA_FIFO_BUSY())) { \
- k-- ;\
- BUS_CHECK() ; \
- } \
- if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
-
-#ifndef UNIX
-#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0)
-#else
-#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0)
-#endif
-
-#ifndef TCI
-#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0)
-#else
-#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\
- outp((iop)+IRQ_TC_DIS,0)
-#endif
-
-#ifndef UNIX
-#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0)
-#else
-#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0)
-#endif
-
-/*
- * Terminal count primitives
- */
-#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0)
-#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0)
-#define CHECK_TC(smc,k) {(k) = 10000 ;\
- while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; }
-
-#endif /* MCA */
-
-#ifdef ISA
-
-/*
- * address transmission from logic NPADDR6-0 to physical offset address on board
- */
-#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */
-#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/
-#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */
-#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */
-#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */
-
-#define ISRA 0x0000 /* int. source register address (read only) */
-#define ACLA 0x0000 /* address counter low address (write only) */
-#define ACHA 0x0002 /* address counter high address (write only) */
-#define TRCA 0x0004 /* transfer counter address (write only) */
-#define PGRA 0x0006 /* page register address (write only) */
-#define RQAA 0x2000 /* Request reg. (write only) */
-#define CSRA 0x3000 /* control/status register address (r/w) */
-
-/*
- * physical address offset + IO-Port base address
- */
-#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */
-#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/
-#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */
-#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */
-#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */
-
-#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */
-#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */
-#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/
-#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */
-#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */
-#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */
-#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */
-#ifdef UNIX
-#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */
-#endif
-#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */
-#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */
-
-#ifndef MULT_OEM
-#ifndef OEM_CONCEPT
-#define SKLOGO_STR "SKFDDI"
-#else /* OEM_CONCEPT */
-#define SKLOGO_STR OEM_FDDI_LOGO
-#endif /* OEM_CONCEPT */
-#endif /* MULT_OEM */
-#define SADDRL (24) /* start address SKLOGO */
-#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
-#define PRA_OFF (0)
-#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
-
-#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */
-#define NEXT_CDID ((PRA(SADDRL+1)) - CDID)
-
-#define SKFDDI_PSZ 32 /* address PROM size */
-
-#define READ_PROM(a) ((u_char)inpw(a))
-#define GET_PAGE(i) outpw(PGR_A,(int)(i))
-
-#define MAX_PAGES 16 /* 16 pages */
-#define MAX_FADDR 0x2000 /* 8K per page */
-#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)))
-#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \
- CS_VPPSW)
-
-/*
- * control/status register CSRA bits (log. addr: 0x3000)
- */
-/* write */
-#define CS_CRESET 0x01 /* Card reset (0=reset) */
-#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */
-#define CS_RESINT1 0x04 /* PLINT1 reset */
-#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */
-#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/
-#define CS_RESINT2 0x40 /* PLINT2 reset */
-/* read */
-#define CS_BUSY 0x04 /* master transfer activ (=1) */
-#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */
-#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */
-#define CS_SAS 0x80 /* single attachement station (=1) */
-
-/*
- * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ.
- */
-#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/
-#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/
-#define IS_PLINT1 0x04 /* PLC1 */
-#define IS_PLINT2 0x08 /* PLC2 */
-#define IS_TIMINT 0x10 /* Timer 82C54-2 */
-
-#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT)
-
-#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM)
-#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY)
-#define CHECK_FIFO()
-#define BUS_CHECK()
-
-/*
- * set Host Request register (wr.)
- */
-#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0)
-
-#ifndef UNIX
-#ifndef WINNT
-#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#else
-#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#endif
-#else
-#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#endif
-
-#ifndef UNIX
-#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
-#else
-#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
-#endif
-
-#define CHECK_DMA() {unsigned k = 10000 ;\
- while (k && (DMA_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-
-#define GET_ISR() ~inpw(ISR_A)
-
-#endif /* ISA */
-
/*--------------------------------------------------------------------------*/
#ifdef PCI
diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h
index 79d55ad2cd2a..ac2d7192f1ca 100644
--- a/drivers/net/skfp/h/skfbiinc.h
+++ b/drivers/net/skfp/h/skfbiinc.h
@@ -22,32 +22,6 @@
*/
#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1)
-#ifdef ISA
-#define DMA_BUSY_CHECK CSRA
-#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT)
-#define HRQR (RQAA+(RQ_RRQ<<1))
-#define HRQW (RQAA+(RQ_WA2<<1))
-#define HRQA0 (RQAA+(RQ_WA0<<1))
-#define HRQSQ (RQAA+(RQ_WSQ<<1))
-#endif
-
-#ifdef EISA
-#define DMA_BUSY_CHECK CSRA
-#define DMA_HIGH_WORD 0x0400
-#define DMA_MASK_M 0x0a
-#define DMA_MODE_M 0x0b
-#define DMA_BYTE_PTR_M 0x0c
-#define DMA_MASK_S 0x0d4
-#define DMA_MODE_S 0x0d6
-#define DMA_BYTE_PTR_S 0x0d8
-#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC)
-#endif /* EISA */
-
-#ifdef MCA
-#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
- IS_CHCK_L | IS_BUSERR)
-#endif
-
#ifdef PCI
#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h
index 22c4923241d3..626dc7263591 100644
--- a/drivers/net/skfp/h/targethw.h
+++ b/drivers/net/skfp/h/targethw.h
@@ -53,11 +53,6 @@ struct s_oem_ids {
u_char oi_sub_id[4] ; /* sub id bytes, representation as */
/* defined by hardware, */
#endif
-#ifdef ISA
- u_char oi_logo_len ; /* the length of the adapter logo */
- u_char oi_logo[6] ; /* the adapter logo */
- u_char oi_reserved1 ;
-#endif /* ISA */
} ;
#endif /* MULT_OEM */
@@ -70,43 +65,17 @@ struct s_smt_hw {
short dma ; /* DMA channel */
short irq ; /* IRQ level */
short eprom ; /* FLASH prom */
-#ifndef PCI
- short DmaWriteExtraBytes ; /* add bytes for DMA write */
-#endif
#ifndef SYNC
u_short n_a_send ; /* pending send requests */
#endif
-#if (defined(EISA) || defined(MCA) || defined(PCI))
+#if defined(PCI)
short slot ; /* slot number */
short max_slots ; /* maximum number of slots */
-#endif
-
-#if (defined(PCI) || defined(MCA))
short wdog_used ; /* TRUE if the watch dog is used */
#endif
-#ifdef MCA
- short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */
- short rev ; /* Board revision (FMx_REV). */
- short VFullRead ; /* V_full value for DMA read */
- short VFullWrite ; /* V_full value for DMA write */
-#endif
-
-#ifdef EISA
- short led ; /* LED for FE card */
-
- short dma_rmode ; /* read mode */
- short dma_wmode ; /* write mode */
- short dma_emode ; /* extend mode */
-
- /* DMA controller channel dependent io addresses */
- u_short dma_base_word_count ;
- u_short dma_base_address ;
- u_short dma_base_address_page ;
-#endif
-
#ifdef PCI
u_short pci_handle ; /* handle to access the BIOS func */
u_long is_imask ; /* int maske for the int source reg */
diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c
index e01f8a0f35c6..053151468f93 100644
--- a/drivers/net/skfp/hwt.c
+++ b/drivers/net/skfp/hwt.c
@@ -77,25 +77,10 @@ void hwt_start(struct s_smc *smc, u_long time)
*/
if (!cnt)
cnt++ ;
-#ifndef PCI
- /*
- * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0
- * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT)
- */
- OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
- OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */
- OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */
- /*
- * start timer by switching counter 0 to mode 3
- * T0 resolution 16 us (CLK0=0.16us)
- */
- OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */
- OUT_82c54_TIMER(0,100) ; /* LSB */
- OUT_82c54_TIMER(0,0) ; /* MSB */
-#else /* PCI */
+
outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */
outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */
-#endif /* PCI */
+
smc->hw.timer_activ = TRUE ;
}
@@ -115,15 +100,8 @@ void hwt_start(struct s_smc *smc, u_long time)
************************/
void hwt_stop(struct s_smc *smc)
{
-#ifndef PCI
- /* stop counter 0 by switching to mode 0 */
- OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */
- OUT_82c54_TIMER(0,0) ; /* LSB */
- OUT_82c54_TIMER(0,0) ; /* MSB */
-#else /* PCI */
outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
-#endif /* PCI */
smc->hw.timer_activ = FALSE ;
}
@@ -168,11 +146,6 @@ void hwt_init(struct s_smc *smc)
void hwt_restart(struct s_smc *smc)
{
hwt_stop(smc) ;
-#ifndef PCI
- OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
- OUT_82c54_TIMER(1,1 ) ; /* LSB */
- OUT_82c54_TIMER(1,0 ) ; /* MSB */
-#endif
}
/************************
@@ -191,21 +164,12 @@ void hwt_restart(struct s_smc *smc)
u_long hwt_read(struct s_smc *smc)
{
u_short tr ;
-#ifndef PCI
- u_short is ;
-#else
u_long is ;
-#endif
if (smc->hw.timer_activ) {
hwt_stop(smc) ;
-#ifndef PCI
- OUT_82c54_TIMER(3,1<<6) ; /* latch command */
- tr = IN_82c54_TIMER(1) & 0xff ;
- tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
-#else /* PCI */
tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
-#endif /* PCI */
+
is = GET_ISR() ;
/* Check if timer expired (or wraparound). */
if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index efc639c013fd..ea85de918233 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -575,7 +575,7 @@ void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
int sp_len ;
/*
- * skip if errror
+ * skip if error
*/
if (pcon->pc_err)
return ;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index a7ef6c8b7721..7cf9b9f35dee 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -260,9 +260,7 @@ static int skfp_init_one(struct pci_dev *pdev,
dev->set_multicast_list = &skfp_ctl_set_multicast_list;
dev->set_mac_address = &skfp_ctl_set_mac_address;
dev->do_ioctl = &skfp_ioctl;
- dev->header_cache_update = NULL; /* not supported */
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Initialize board structure with bus-specific info */
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 75afc1f07ba0..ced2c8f76be7 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -1654,7 +1654,7 @@ static const struct smt_pdef {
{ SMT_P4053, 0, SWAP_SMT_P4053 } ,
} ;
-#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0]))
+#define N_SMT_PLEN ARRAY_SIZE(smt_pdef)
int smt_check_para(struct s_smc *smc, struct smt_header *sm,
const u_short list[])
diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
index 16573aca8b62..6caf713b744c 100644
--- a/drivers/net/skfp/srf.c
+++ b/drivers/net/skfp/srf.c
@@ -43,7 +43,7 @@ static void clear_reported(struct s_smc *smc);
static void smt_send_srf(struct s_smc *smc);
static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index);
-#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0]))
+#define MAX_EVCS ARRAY_SIZE(smc->evcs)
struct evc_init {
u_char code ;
@@ -67,7 +67,7 @@ static const struct evc_init evc_inits[] = {
{ SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } ,
} ;
-#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0]))
+#define MAX_INIT_EVC ARRAY_SIZE(evc_inits)
void smt_init_evc(struct s_smc *smc)
{
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 776692946562..2aae9fe38c5a 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -410,9 +410,14 @@ static const struct skge_stat {
{ "rx_fcs_error", XM_RXF_FCS_ERR, GM_RXF_FCS_ERR },
};
-static int skge_get_stats_count(struct net_device *dev)
+static int skge_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(skge_stats);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(skge_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void skge_get_ethtool_stats(struct net_device *dev,
@@ -811,17 +816,14 @@ static const struct ethtool_ops skge_ethtool_ops = {
.set_pauseparam = skge_set_pauseparam,
.get_coalesce = skge_get_coalesce,
.set_coalesce = skge_set_coalesce,
- .get_sg = ethtool_op_get_sg,
.set_sg = skge_set_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = skge_set_tx_csum,
.get_rx_csum = skge_get_rx_csum,
.set_rx_csum = skge_set_rx_csum,
.get_strings = skge_get_strings,
.phys_id = skge_phys_id,
- .get_stats_count = skge_get_stats_count,
+ .get_sset_count = skge_get_sset_count,
.get_ethtool_stats = skge_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
/*
@@ -2529,7 +2531,7 @@ static int skge_up(struct net_device *dev)
skge_write32(hw, B0_IMSK, hw->intr_mask);
spin_unlock_irq(&hw->hw_lock);
- netif_poll_enable(dev);
+ napi_enable(&skge->napi);
return 0;
free_rx_ring:
@@ -2559,7 +2561,7 @@ static int skge_down(struct net_device *dev)
if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
del_timer_sync(&skge->link_timer);
- netif_poll_disable(dev);
+ napi_disable(&skge->napi);
netif_carrier_off(dev);
spin_lock_irq(&hw->hw_lock);
@@ -3045,14 +3047,13 @@ static void skge_tx_done(struct net_device *dev)
}
}
-static int skge_poll(struct net_device *dev, int *budget)
+static int skge_poll(struct napi_struct *napi, int to_do)
{
- struct skge_port *skge = netdev_priv(dev);
+ struct skge_port *skge = container_of(napi, struct skge_port, napi);
+ struct net_device *dev = skge->netdev;
struct skge_hw *hw = skge->hw;
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- unsigned long flags;
- int to_do = min(dev->quota, *budget);
int work_done = 0;
skge_tx_done(dev);
@@ -3083,20 +3084,16 @@ static int skge_poll(struct net_device *dev, int *budget)
wmb();
skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done >= to_do)
- return 1; /* not done */
-
- spin_lock_irqsave(&hw->hw_lock, flags);
- __netif_rx_complete(dev);
- hw->intr_mask |= napimask[skge->port];
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- skge_read32(hw, B0_IMSK);
- spin_unlock_irqrestore(&hw->hw_lock, flags);
+ if (work_done < to_do) {
+ spin_lock_irq(&hw->hw_lock);
+ __netif_rx_complete(dev, napi);
+ hw->intr_mask |= napimask[skge->port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_read32(hw, B0_IMSK);
+ spin_unlock_irq(&hw->hw_lock);
+ }
- return 0;
+ return work_done;
}
/* Parity errors seem to happen when Genesis is connected to a switch
@@ -3253,8 +3250,9 @@ static irqreturn_t skge_intr(int irq, void *dev_id)
}
if (status & (IS_XA1_F|IS_R1_F)) {
+ struct skge_port *skge = netdev_priv(hw->dev[0]);
hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
- netif_rx_schedule(hw->dev[0]);
+ netif_rx_schedule(hw->dev[0], &skge->napi);
}
if (status & IS_PA_TO_TX1)
@@ -3272,13 +3270,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id)
skge_mac_intr(hw, 0);
if (hw->dev[1]) {
+ struct skge_port *skge = netdev_priv(hw->dev[1]);
+
if (status & (IS_XA2_F|IS_R2_F)) {
hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
- netif_rx_schedule(hw->dev[1]);
+ netif_rx_schedule(hw->dev[1], &skge->napi);
}
if (status & IS_PA_TO_RX2) {
- struct skge_port *skge = netdev_priv(hw->dev[1]);
++skge->net_stats.rx_over_errors;
skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
}
@@ -3553,7 +3552,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
return NULL;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &hw->pdev->dev);
dev->open = skge_up;
dev->stop = skge_down;
@@ -3570,8 +3568,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
SET_ETHTOOL_OPS(dev, &skge_ethtool_ops);
dev->tx_timeout = skge_tx_timeout;
dev->watchdog_timeo = TX_WATCHDOG;
- dev->poll = skge_poll;
- dev->weight = NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = skge_netpoll;
#endif
@@ -3581,6 +3577,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
dev->features |= NETIF_F_HIGHDMA;
skge = netdev_priv(dev);
+ netif_napi_add(dev, &skge->napi, skge_poll, NAPI_WEIGHT);
skge->netdev = dev;
skge->hw = hw;
skge->msg_enable = netif_msg_init(debug, default_msg);
@@ -3624,12 +3621,11 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
static void __devinit skge_show_addr(struct net_device *dev)
{
const struct skge_port *skge = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
if (netif_msg_probe(skge))
- printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO PFX "%s: addr %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
static int __devinit skge_probe(struct pci_dev *pdev,
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index edd71468220c..1a57bdd1ddf1 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -1351,8 +1351,6 @@ enum {
PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */
};
-#define PHY_M_PC_MDI_XMODE(x) ((((u16)(x)<<5) & PHY_M_PC_MDIX_MSK)
-
enum {
PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */
PHY_M_PC_MAN_MDIX = 1, /* 01 = Manual MDIX configuration */
@@ -2448,6 +2446,7 @@ enum pause_status {
struct skge_port {
struct skge_hw *hw;
struct net_device *netdev;
+ struct napi_struct napi;
int port;
u32 msg_enable;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index a2f32151559e..68f728f0b600 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -31,6 +31,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/tcp.h>
@@ -51,7 +52,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.16"
+#define DRV_VERSION "1.19"
#define PFX DRV_NAME " "
/*
@@ -99,10 +100,6 @@ static int disable_msi = 0;
module_param(disable_msi, int, 0);
MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
-static int idle_timeout = 100;
-module_param(idle_timeout, int, 0);
-MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)");
-
static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */
@@ -122,12 +119,15 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, /* 88E8070 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
@@ -151,8 +151,11 @@ static const char *yukon2_name[] = {
"Extreme", /* 0xb5 */
"EC", /* 0xb6 */
"FE", /* 0xb7 */
+ "FE+", /* 0xb8 */
};
+static void sky2_set_multicast(struct net_device *dev);
+
/* Access to external PHY */
static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
{
@@ -219,25 +222,30 @@ static void sky2_power_on(struct sky2_hw *hw)
else
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+ struct pci_dev *pdev = hw->pdev;
u32 reg;
- reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+ pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
+
+ pci_read_config_dword(pdev, PCI_DEV_REG4, &reg);
/* set all bits to 0 except bits 15..12 and 8 */
reg &= P_ASPM_CONTROL_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG4, reg);
+ pci_write_config_dword(pdev, PCI_DEV_REG4, reg);
- reg = sky2_pci_read32(hw, PCI_DEV_REG5);
+ pci_read_config_dword(pdev, PCI_DEV_REG5, &reg);
/* set all bits to 0 except bits 28 & 27 */
reg &= P_CTL_TIM_VMAIN_AV_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG5, reg);
+ pci_write_config_dword(pdev, PCI_DEV_REG5, reg);
- sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+ pci_write_config_dword(pdev, PCI_CFG_REG_1, 0);
/* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
reg = sky2_read32(hw, B2_GP_IO);
reg |= GLB_GPIO_STAT_RACE_DIS;
sky2_write32(hw, B2_GP_IO, reg);
+
+ sky2_read32(hw, B2_GP_IO);
}
}
@@ -288,10 +296,10 @@ static const u16 copper_fc_adv[] = {
/* flow control to advertise bits when using 1000BaseX */
static const u16 fiber_fc_adv[] = {
- [FC_BOTH] = PHY_M_P_BOTH_MD_X,
+ [FC_NONE] = PHY_M_P_NO_PAUSE_X,
[FC_TX] = PHY_M_P_ASYM_MD_X,
[FC_RX] = PHY_M_P_SYM_MD_X,
- [FC_NONE] = PHY_M_P_NO_PAUSE_X,
+ [FC_BOTH] = PHY_M_P_BOTH_MD_X,
};
/* flow control to GMA disable bits */
@@ -308,10 +316,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
- if (sky2->autoneg == AUTONEG_ENABLE
- && !(hw->chip_id == CHIP_ID_YUKON_XL
- || hw->chip_id == CHIP_ID_YUKON_EC_U
- || hw->chip_id == CHIP_ID_YUKON_EX)) {
+ if (sky2->autoneg == AUTONEG_ENABLE &&
+ !(hw->flags & SKY2_HW_NEWER_PHY)) {
u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -331,9 +337,19 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
if (sky2_is_copper(hw)) {
- if (hw->chip_id == CHIP_ID_YUKON_FE) {
+ if (!(hw->flags & SKY2_HW_GIGABIT)) {
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
+
+ if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+ u16 spec;
+
+ /* Enable Class A driver for FE+ A0 */
+ spec = gm_phy_read(hw, port, PHY_MARV_FE_SPEC_2);
+ spec |= PHY_M_FESC_SEL_CL_A;
+ gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec);
+ }
} else {
/* disable energy detect */
ctrl &= ~PHY_M_PC_EN_DET_MSK;
@@ -343,9 +359,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* downshift on PHY 88E1112 and 88E1149 is changed */
if (sky2->autoneg == AUTONEG_ENABLE
- && (hw->chip_id == CHIP_ID_YUKON_XL
- || hw->chip_id == CHIP_ID_YUKON_EC_U
- || hw->chip_id == CHIP_ID_YUKON_EX)) {
+ && (hw->flags & SKY2_HW_NEWER_PHY)) {
/* set downshift counter to 3x and enable downshift */
ctrl &= ~PHY_M_PC_DSC_MSK;
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
@@ -361,7 +375,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
/* special setup for PHY 88E1112 Fiber */
- if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) {
+ if (hw->chip_id == CHIP_ID_YUKON_XL && (hw->flags & SKY2_HW_FIBRE_PHY)) {
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
/* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
@@ -452,7 +466,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gma_write16(hw, port, GM_GP_CTRL, reg);
- if (hw->chip_id != CHIP_ID_YUKON_FE)
+ if (hw->flags & SKY2_HW_GIGABIT)
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
@@ -476,6 +490,23 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
break;
+ case CHIP_ID_YUKON_FE_P:
+ /* Enable Link Partner Next Page */
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+ ctrl |= PHY_M_PC_ENA_LIP_NP;
+
+ /* disable Energy Detect and enable scrambler */
+ ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB);
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+ /* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */
+ ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) |
+ PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) |
+ PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED);
+
+ gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
+ break;
+
case CHIP_ID_YUKON_XL:
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
@@ -545,7 +576,13 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* set page register to 0 */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+ } else if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+ /* apply workaround for integrated resistors calibration */
+ gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17);
+ gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60);
} else if (hw->chip_id != CHIP_ID_YUKON_EX) {
+ /* no effect on Yukon-XL */
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -567,25 +604,24 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
{
+ struct pci_dev *pdev = hw->pdev;
u32 reg1;
- static const u32 phy_power[]
- = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
-
- /* looks like this XL is back asswards .. */
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- onoff = !onoff;
+ static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+ static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+ /* Turn on/off phy power saving */
if (onoff)
- /* Turn off phy power saving */
reg1 &= ~phy_power[port];
else
reg1 |= phy_power[port];
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
- sky2_pci_read32(hw, PCI_DEV_REG1);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ reg1 |= coma_mode[port];
+
+ pci_write_config_dword(pdev, PCI_DEV_REG1, reg1);
+ pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+
udelay(100);
}
@@ -653,11 +689,9 @@ static void sky2_wol_init(struct sky2_port *sky2)
sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
/* Turn on legacy PCI-Express PME mode */
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg1);
reg1 |= PCI_Y2_PME_LEGACY;
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1);
/* block receiver */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
@@ -666,25 +700,25 @@ static void sky2_wol_init(struct sky2_port *sky2)
static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
{
- if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) {
+ struct net_device *dev = hw->dev[port];
+
+ if (dev->mtu <= ETH_DATA_LEN)
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_STFW_ENA |
- (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS);
- } else {
- if (hw->dev[port]->mtu > ETH_DATA_LEN) {
- /* set Tx GMAC FIFO Almost Empty Threshold */
- sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
- (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+ TX_JUMBO_DIS | TX_STFW_ENA);
+
+ else if (hw->chip_id != CHIP_ID_YUKON_EC_U)
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_STFW_ENA | TX_JUMBO_ENA);
+ else {
+ /* set Tx GMAC FIFO Almost Empty Threshold */
+ sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+ (ECU_JUMBO_WM << 16) | ECU_AE_THR);
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_ENA | TX_STFW_DIS);
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_JUMBO_ENA | TX_STFW_DIS);
- /* Can't do offload because of lack of store/forward */
- hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG
- | NETIF_F_ALL_CSUM);
- } else
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_DIS | TX_STFW_ENA);
+ /* Can't do offload because of lack of store/forward */
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
}
}
@@ -692,11 +726,12 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 reg;
+ u32 rx_reg;
int i;
const u8 *addr = hw->dev[port]->dev_addr;
- sky2_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
- sky2_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+ sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
@@ -768,23 +803,30 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
/* Configure Rx MAC FIFO */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
- reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
- if (hw->chip_id == CHIP_ID_YUKON_EX)
- reg |= GMF_RX_OVER_ON;
+ rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+ if (hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P)
+ rx_reg |= GMF_RX_OVER_ON;
- sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
/* Flush Rx MAC FIFO on any flow control or error */
sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
/* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug */
- sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
+ reg = RX_GMF_FL_THR_DEF + 1;
+ /* Another magic mystery workaround from sk98lin */
+ if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0)
+ reg = 0x178;
+ sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg);
/* Configure Tx MAC FIFO */
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+ /* On chips without ram buffer, pause is controled by MAC level */
+ if (sky2_read8(hw, B2_E_0) == 0) {
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
@@ -867,6 +909,20 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2)
return le;
}
+static void tx_init(struct sky2_port *sky2)
+{
+ struct sky2_tx_le *le;
+
+ sky2->tx_prod = sky2->tx_cons = 0;
+ sky2->tx_tcpsum = 0;
+ sky2->tx_last_mss = 0;
+
+ le = get_tx_le(sky2);
+ le->addr = 0;
+ le->opcode = OP_ADDR64 | HW_OWNER;
+ sky2->tx_addr64 = 0;
+}
+
static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
struct sky2_tx_le *le)
{
@@ -963,19 +1019,15 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
*/
static void rx_set_checksum(struct sky2_port *sky2)
{
- struct sky2_rx_le *le;
-
- if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) {
- le = sky2_next_rx(sky2);
- le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
- le->ctrl = 0;
- le->opcode = OP_TCPSTART | HW_OWNER;
+ struct sky2_rx_le *le = sky2_next_rx(sky2);
- sky2_write32(sky2->hw,
- Q_ADDR(rxqaddr[sky2->port], Q_CSR),
- sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
- }
+ le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+ le->ctrl = 0;
+ le->opcode = OP_TCPSTART | HW_OWNER;
+ sky2_write32(sky2->hw,
+ Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+ sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
}
/*
@@ -1077,7 +1129,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
u16 port = sky2->port;
netif_tx_lock_bh(dev);
- netif_poll_disable(sky2->hw->dev[0]);
+ napi_disable(&hw->napi);
sky2->vlgrp = grp;
if (grp) {
@@ -1092,7 +1144,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
TX_VLAN_TAG_OFF);
}
- netif_poll_enable(sky2->hw->dev[0]);
+ napi_enable(&hw->napi);
netif_tx_unlock_bh(dev);
}
#endif
@@ -1171,7 +1223,8 @@ static int sky2_rx_start(struct sky2_port *sky2)
sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
- rx_set_checksum(sky2);
+ if (!(hw->flags & SKY2_HW_NEW_LE))
+ rx_set_checksum(sky2);
/* Space needed for frame data + headers rounded up */
size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
@@ -1242,7 +1295,7 @@ static int sky2_up(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
- u32 ramsize, imask;
+ u32 imask, ramsize;
int cap, err = -ENOMEM;
struct net_device *otherdev = hw->dev[sky2->port^1];
@@ -1255,9 +1308,9 @@ static int sky2_up(struct net_device *dev)
struct sky2_port *osky2 = netdev_priv(otherdev);
u16 cmd;
- cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
+ pci_read_config_word(hw->pdev, cap + PCI_X_CMD, &cmd);
cmd &= ~PCI_X_CMD_MAX_SPLIT;
- sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+ pci_write_config_word(hw->pdev, cap + PCI_X_CMD, cmd);
sky2->rx_csum = 0;
osky2->rx_csum = 0;
@@ -1280,7 +1333,8 @@ static int sky2_up(struct net_device *dev)
GFP_KERNEL);
if (!sky2->tx_ring)
goto err_out;
- sky2->tx_prod = sky2->tx_cons = 0;
+
+ tx_init(sky2);
sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES,
&sky2->rx_le_map);
@@ -1299,11 +1353,10 @@ static int sky2_up(struct net_device *dev)
/* Register is number of 4K blocks on internal RAM buffer. */
ramsize = sky2_read8(hw, B2_E_0) * 4;
- printk(KERN_INFO PFX "%s: ram buffer %dK\n", dev->name, ramsize);
-
if (ramsize > 0) {
u32 rxspace;
+ pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
if (ramsize < 16)
rxspace = ramsize / 2;
else
@@ -1331,9 +1384,13 @@ static int sky2_up(struct net_device *dev)
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
TX_RING_SIZE - 1);
+ napi_enable(&hw->napi);
+
err = sky2_rx_start(sky2);
- if (err)
+ if (err) {
+ napi_disable(&hw->napi);
goto err_out;
+ }
/* Enable interrupts from phy/mac for port */
imask = sky2_read32(hw, B0_IMSK);
@@ -1432,13 +1489,15 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Check for TCP Segmentation Offload */
mss = skb_shinfo(skb)->gso_size;
if (mss != 0) {
- if (hw->chip_id != CHIP_ID_YUKON_EX)
+
+ if (!(hw->flags & SKY2_HW_NEW_LE))
mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
if (mss != sky2->tx_last_mss) {
le = get_tx_le(sky2);
le->addr = cpu_to_le32(mss);
- if (hw->chip_id == CHIP_ID_YUKON_EX)
+
+ if (hw->flags & SKY2_HW_NEW_LE)
le->opcode = OP_MSS | HW_OWNER;
else
le->opcode = OP_LRGLEN | HW_OWNER;
@@ -1464,8 +1523,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Handle TCP checksum offload */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
/* On Yukon EX (some versions) encoding change. */
- if (hw->chip_id == CHIP_ID_YUKON_EX
- && hw->chip_rev != CHIP_REV_YU_EX_B0)
+ if (hw->flags & SKY2_HW_AUTO_TX_SUM)
ctrl |= CALSUM; /* auto checksum */
else {
const unsigned offset = skb_transport_offset(skb);
@@ -1577,8 +1635,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
printk(KERN_DEBUG "%s: tx done %u\n",
dev->name, idx);
- sky2->net_stats.tx_packets++;
- sky2->net_stats.tx_bytes += re->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += re->skb->len;
dev_kfree_skb_any(re->skb);
sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE);
@@ -1621,6 +1679,8 @@ static int sky2_down(struct net_device *dev)
/* Stop more packets from being queued */
netif_stop_queue(dev);
+ napi_disable(&hw->napi);
+
/* Disable port IRQ */
imask = sky2_read32(hw, B0_IMSK);
imask &= ~portirq_msk[port];
@@ -1701,11 +1761,15 @@ static int sky2_down(struct net_device *dev)
static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
{
- if (!sky2_is_copper(hw))
+ if (hw->flags & SKY2_HW_FIBRE_PHY)
return SPEED_1000;
- if (hw->chip_id == CHIP_ID_YUKON_FE)
- return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
+ if (!(hw->flags & SKY2_HW_GIGABIT)) {
+ if (aux & PHY_M_PS_SPEED_100)
+ return SPEED_100;
+ else
+ return SPEED_10;
+ }
switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
@@ -1738,13 +1802,13 @@ static void sky2_link_up(struct sky2_port *sky2)
netif_carrier_on(sky2->netdev);
+ mod_timer(&hw->watchdog_timer, jiffies + 1);
+
/* Turn on link LED */
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->chip_id == CHIP_ID_YUKON_XL
- || hw->chip_id == CHIP_ID_YUKON_EC_U
- || hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->flags & SKY2_HW_NEWER_PHY) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
@@ -1831,7 +1895,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
/* Since the pause result bits seem to in different positions on
* different chips. look at registers.
*/
- if (!sky2_is_copper(hw)) {
+ if (hw->flags & SKY2_HW_FIBRE_PHY) {
/* Shift for bits in fiber PHY */
advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM);
lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM);
@@ -1942,7 +2006,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
- if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE)
+ if (new_mtu > ETH_DATA_LEN &&
+ (hw->chip_id == CHIP_ID_YUKON_FE ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P))
return -EINVAL;
if (!netif_running(dev)) {
@@ -1955,11 +2021,11 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
dev->trans_start = jiffies; /* prevent tx timeout */
netif_stop_queue(dev);
- netif_poll_disable(hw->dev[0]);
+ napi_disable(&hw->napi);
synchronize_irq(hw->pdev->irq);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+ if (sky2_read8(hw, B2_E_0) == 0)
sky2_set_tx_stfwd(hw, port);
ctl = gma_read16(hw, port, GM_GP_CTRL);
@@ -1982,12 +2048,16 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
err = sky2_rx_start(sky2);
sky2_write32(hw, B0_IMSK, imask);
+ /* Unconditionally re-enable NAPI because even if we
+ * call dev_close() that will do a napi_disable().
+ */
+ napi_enable(&hw->napi);
+
if (err)
dev_close(dev);
else {
gma_write16(hw, port, GM_GP_CTRL, ctl);
- netif_poll_enable(hw->dev[0]);
netif_wake_queue(dev);
}
@@ -2087,6 +2157,13 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
struct sky2_port *sky2 = netdev_priv(dev);
struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL;
+ u16 count = (status & GMR_FS_LEN) >> 16;
+
+#ifdef SKY2_VLAN_TAG_USED
+ /* Account for vlan tag */
+ if (sky2->vlgrp && (status & GMR_FS_VLAN))
+ count -= VLAN_HLEN;
+#endif
if (unlikely(netif_msg_rx_status(sky2)))
printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
@@ -2095,15 +2172,26 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
prefetch(sky2->rx_ring + sky2->rx_next);
+ /* This chip has hardware problems that generates bogus status.
+ * So do only marginal checking and expect higher level protocols
+ * to handle crap frames.
+ */
+ if (sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0 &&
+ length != count)
+ goto okay;
+
if (status & GMR_FS_ANY_ERR)
goto error;
if (!(status & GMR_FS_RX_OK))
goto resubmit;
- if (status >> 16 != length)
- goto len_mismatch;
+ /* if length reported by DMA does not match PHY, packet was truncated */
+ if (length != count)
+ goto len_error;
+okay:
if (length < copybreak)
skb = receive_copy(sky2, re, length);
else
@@ -2113,15 +2201,19 @@ resubmit:
return skb;
-len_mismatch:
+len_error:
/* Truncation of overlength packets
causes PHY length to not match MAC length */
- ++sky2->net_stats.rx_length_errors;
+ ++dev->stats.rx_length_errors;
+ if (netif_msg_rx_err(sky2) && net_ratelimit())
+ pr_info(PFX "%s: rx length error: status %#x length %d\n",
+ dev->name, status, length);
+ goto resubmit;
error:
- ++sky2->net_stats.rx_errors;
+ ++dev->stats.rx_errors;
if (status & GMR_FS_RX_FF_OV) {
- sky2->net_stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
goto resubmit;
}
@@ -2130,11 +2222,11 @@ error:
dev->name, status, length);
if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
- sky2->net_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & GMR_FS_FRAGMENT)
- sky2->net_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & GMR_FS_CRC_ERR)
- sky2->net_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
goto resubmit;
}
@@ -2152,15 +2244,13 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
}
/* Process status response ring */
-static int sky2_status_intr(struct sky2_hw *hw, int to_do)
+static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
{
int work_done = 0;
unsigned rx[2] = { 0, 0 };
- u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
rmb();
-
- while (hw->st_idx != hwidx) {
+ do {
struct sky2_port *sky2;
struct sky2_status_le *le = hw->st_le + hw->st_idx;
unsigned port = le->css & CSS_LINK_BIT;
@@ -2181,12 +2271,12 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
++rx[port];
skb = sky2_receive(dev, length, status);
if (unlikely(!skb)) {
- sky2->net_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
/* This chip reports checksum status differently */
- if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->flags & SKY2_HW_NEW_LE) {
if (sky2->rx_csum &&
(le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
(le->css & CSS_TCPUDPCSOK))
@@ -2196,8 +2286,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}
skb->protocol = eth_type_trans(skb, dev);
- sky2->net_stats.rx_packets++;
- sky2->net_stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED
@@ -2227,8 +2317,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
if (!sky2->rx_csum)
break;
- if (hw->chip_id == CHIP_ID_YUKON_EX)
+ /* If this happens then driver assuming wrong format */
+ if (unlikely(hw->flags & SKY2_HW_NEW_LE)) {
+ if (net_ratelimit())
+ printk(KERN_NOTICE "%s: unexpected"
+ " checksum status\n",
+ dev->name);
break;
+ }
/* Both checksum counters are programmed to start at
* the same offset, so unless there is a problem they
@@ -2265,7 +2361,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
printk(KERN_WARNING PFX
"unknown status opcode 0x%x\n", le->opcode);
}
- }
+ } while (hw->st_idx != idx);
/* Fully processed status ring so clear irq */
sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
@@ -2326,7 +2422,11 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
static void sky2_hw_intr(struct sky2_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u32 status = sky2_read32(hw, B0_HWE_ISRC);
+ u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
+
+ status &= hwmsk;
if (status & Y2_IS_TIST_OV)
sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
@@ -2334,38 +2434,24 @@ static void sky2_hw_intr(struct sky2_hw *hw)
if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
u16 pci_err;
- pci_err = sky2_pci_read16(hw, PCI_STATUS);
+ pci_read_config_word(pdev, PCI_STATUS, &pci_err);
if (net_ratelimit())
- dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+ dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
pci_err);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- sky2_pci_write16(hw, PCI_STATUS,
- pci_err | PCI_STATUS_ERROR_BITS);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ pci_write_config_word(pdev, PCI_STATUS,
+ pci_err | PCI_STATUS_ERROR_BITS);
}
if (status & Y2_IS_PCI_EXP) {
/* PCI-Express uncorrectable Error occurred */
- u32 pex_err;
-
- pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
+ int pos = pci_find_aer_capability(hw->pdev);
+ u32 err;
+ pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_STATUS, &err);
if (net_ratelimit())
- dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
- pex_err);
-
- /* clear the interrupt */
- sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- sky2_pci_write32(hw, PEX_UNC_ERR_STAT,
- 0xffffffffUL);
- sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
- if (pex_err & PEX_FATAL_ERRORS) {
- u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
- hwmsk &= ~Y2_IS_PCI_EXP;
- sky2_write32(hw, B0_HWE_IMSK, hwmsk);
- }
+ dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
+ pci_cleanup_aer_uncorrect_error_status(pdev);
}
if (status & Y2_HWE_L1_MASK)
@@ -2392,12 +2478,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
gma_read16(hw, port, GM_TX_IRQ_SRC);
if (status & GM_IS_RX_FF_OR) {
- ++sky2->net_stats.rx_fifo_errors;
+ ++dev->stats.rx_fifo_errors;
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
}
if (status & GM_IS_TX_FF_UR) {
- ++sky2->net_stats.tx_fifo_errors;
+ ++dev->stats.tx_fifo_errors;
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU);
}
}
@@ -2420,25 +2506,69 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port,
sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK);
}
-/* If idle then force a fake soft NAPI poll once a second
- * to work around cases where sharing an edge triggered interrupt.
- */
-static inline void sky2_idle_start(struct sky2_hw *hw)
+static int sky2_rx_hung(struct net_device *dev)
{
- if (idle_timeout > 0)
- mod_timer(&hw->idle_timer,
- jiffies + msecs_to_jiffies(idle_timeout));
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ unsigned rxq = rxqaddr[port];
+ u32 mac_rp = sky2_read32(hw, SK_REG(port, RX_GMF_RP));
+ u8 mac_lev = sky2_read8(hw, SK_REG(port, RX_GMF_RLEV));
+ u8 fifo_rp = sky2_read8(hw, Q_ADDR(rxq, Q_RP));
+ u8 fifo_lev = sky2_read8(hw, Q_ADDR(rxq, Q_RL));
+
+ /* If idle and MAC or PCI is stuck */
+ if (sky2->check.last == dev->last_rx &&
+ ((mac_rp == sky2->check.mac_rp &&
+ mac_lev != 0 && mac_lev >= sky2->check.mac_lev) ||
+ /* Check if the PCI RX hang */
+ (fifo_rp == sky2->check.fifo_rp &&
+ fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) {
+ printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n",
+ dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp,
+ sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
+ return 1;
+ } else {
+ sky2->check.last = dev->last_rx;
+ sky2->check.mac_rp = mac_rp;
+ sky2->check.mac_lev = mac_lev;
+ sky2->check.fifo_rp = fifo_rp;
+ sky2->check.fifo_lev = fifo_lev;
+ return 0;
+ }
}
-static void sky2_idle(unsigned long arg)
+static void sky2_watchdog(unsigned long arg)
{
struct sky2_hw *hw = (struct sky2_hw *) arg;
- struct net_device *dev = hw->dev[0];
- if (__netif_rx_schedule_prep(dev))
- __netif_rx_schedule(dev);
+ /* Check for lost IRQ once a second */
+ if (sky2_read32(hw, B0_ISRC)) {
+ napi_schedule(&hw->napi);
+ } else {
+ int i, active = 0;
- mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout));
+ for (i = 0; i < hw->ports; i++) {
+ struct net_device *dev = hw->dev[i];
+ if (!netif_running(dev))
+ continue;
+ ++active;
+
+ /* For chips with Rx FIFO, check if stuck */
+ if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) &&
+ sky2_rx_hung(dev)) {
+ pr_info(PFX "%s: receiver hang detected\n",
+ dev->name);
+ schedule_work(&hw->restart_work);
+ return;
+ }
+ }
+
+ if (active == 0)
+ return;
+ }
+
+ mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ));
}
/* Hardware/software error handling */
@@ -2469,11 +2599,12 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status)
sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE);
}
-static int sky2_poll(struct net_device *dev0, int *budget)
+static int sky2_poll(struct napi_struct *napi, int work_limit)
{
- struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
- int work_done;
+ struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi);
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
+ int work_done = 0;
+ u16 idx;
if (unlikely(status & Y2_IS_ERROR))
sky2_err_intr(hw, status);
@@ -2484,13 +2615,12 @@ static int sky2_poll(struct net_device *dev0, int *budget)
if (status & Y2_IS_IRQ_PHY2)
sky2_phy_intr(hw, 1);
- work_done = sky2_status_intr(hw, min(dev0->quota, *budget));
- *budget -= work_done;
- dev0->quota -= work_done;
+ while ((idx = sky2_read16(hw, STAT_PUT_IDX)) != hw->st_idx) {
+ work_done += sky2_status_intr(hw, work_limit - work_done, idx);
- /* More work? */
- if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX))
- return 1;
+ if (work_done >= work_limit)
+ goto done;
+ }
/* Bug/Errata workaround?
* Need to kick the TX irq moderation timer.
@@ -2499,16 +2629,16 @@ static int sky2_poll(struct net_device *dev0, int *budget)
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
}
- netif_rx_complete(dev0);
-
+ napi_complete(napi);
sky2_read32(hw, B0_Y2_SP_LISR);
- return 0;
+done:
+
+ return work_done;
}
static irqreturn_t sky2_intr(int irq, void *dev_id)
{
struct sky2_hw *hw = dev_id;
- struct net_device *dev0 = hw->dev[0];
u32 status;
/* Reading this mask interrupts as side effect */
@@ -2517,8 +2647,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id)
return IRQ_NONE;
prefetch(&hw->st_le[hw->st_idx]);
- if (likely(__netif_rx_schedule_prep(dev0)))
- __netif_rx_schedule(dev0);
+
+ napi_schedule(&hw->napi);
return IRQ_HANDLED;
}
@@ -2527,25 +2657,31 @@ static irqreturn_t sky2_intr(int irq, void *dev_id)
static void sky2_netpoll(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
- struct net_device *dev0 = sky2->hw->dev[0];
- if (netif_running(dev) && __netif_rx_schedule_prep(dev0))
- __netif_rx_schedule(dev0);
+ napi_schedule(&sky2->hw->napi);
}
#endif
/* Chip internal frequency for clock calculations */
-static inline u32 sky2_mhz(const struct sky2_hw *hw)
+static u32 sky2_mhz(const struct sky2_hw *hw)
{
switch (hw->chip_id) {
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
case CHIP_ID_YUKON_EX:
- return 125; /* 125 Mhz */
+ return 125;
+
case CHIP_ID_YUKON_FE:
- return 100; /* 100 Mhz */
- default: /* YUKON_XL */
- return 156; /* 156 Mhz */
+ return 100;
+
+ case CHIP_ID_YUKON_FE_P:
+ return 50;
+
+ case CHIP_ID_YUKON_XL:
+ return 156;
+
+ default:
+ BUG();
}
}
@@ -2562,31 +2698,74 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
static int __devinit sky2_init(struct sky2_hw *hw)
{
+ int rc;
u8 t8;
- /* Enable all clocks */
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ /* Enable all clocks and check for bad PCI access */
+ rc = pci_write_config_dword(hw->pdev, PCI_DEV_REG3, 0);
+ if (rc)
+ return rc;
sky2_write8(hw, B0_CTST, CS_RST_CLR);
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
- if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
+ hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+
+ switch(hw->chip_id) {
+ case CHIP_ID_YUKON_XL:
+ hw->flags = SKY2_HW_GIGABIT
+ | SKY2_HW_NEWER_PHY;
+ if (hw->chip_rev < 3)
+ hw->flags |= SKY2_HW_FIFO_HANG_CHECK;
+
+ break;
+
+ case CHIP_ID_YUKON_EC_U:
+ hw->flags = SKY2_HW_GIGABIT
+ | SKY2_HW_NEWER_PHY
+ | SKY2_HW_ADV_POWER_CTL;
+ break;
+
+ case CHIP_ID_YUKON_EX:
+ hw->flags = SKY2_HW_GIGABIT
+ | SKY2_HW_NEWER_PHY
+ | SKY2_HW_NEW_LE
+ | SKY2_HW_ADV_POWER_CTL;
+
+ /* New transmit checksum */
+ if (hw->chip_rev != CHIP_REV_YU_EX_B0)
+ hw->flags |= SKY2_HW_AUTO_TX_SUM;
+ break;
+
+ case CHIP_ID_YUKON_EC:
+ /* This rev is really old, and requires untested workarounds */
+ if (hw->chip_rev == CHIP_REV_YU_EC_A1) {
+ dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
+ return -EOPNOTSUPP;
+ }
+ hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK;
+ break;
+
+ case CHIP_ID_YUKON_FE:
+ break;
+
+ case CHIP_ID_YUKON_FE_P:
+ hw->flags = SKY2_HW_NEWER_PHY
+ | SKY2_HW_NEW_LE
+ | SKY2_HW_AUTO_TX_SUM
+ | SKY2_HW_ADV_POWER_CTL;
+ break;
+ default:
dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
hw->chip_id);
return -EOPNOTSUPP;
}
- hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+ if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
+ hw->flags |= SKY2_HW_FIBRE_PHY;
- /* This rev is really old, and requires untested workarounds */
- if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
- dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
- yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
- hw->chip_id, hw->chip_rev);
- return -EOPNOTSUPP;
- }
- hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
hw->ports = 1;
t8 = sky2_read8(hw, B2_Y2_HW_RES);
if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
@@ -2599,8 +2778,10 @@ static int __devinit sky2_init(struct sky2_hw *hw)
static void sky2_reset(struct sky2_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u16 status;
- int i;
+ int i, cap;
+ u32 hwe_mask = Y2_HWE_ALL_MASK;
/* disable ASF */
if (hw->chip_id == CHIP_ID_YUKON_EX) {
@@ -2617,18 +2798,25 @@ static void sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, B0_CTST, CS_RST_CLR);
/* clear PCI errors, if any */
- status = sky2_pci_read16(hw, PCI_STATUS);
-
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS);
-
+ pci_read_config_word(pdev, PCI_STATUS, &status);
+ status |= PCI_STATUS_ERROR_BITS;
+ pci_write_config_word(pdev, PCI_STATUS, status);
sky2_write8(hw, B0_CTST, CS_MRST_CLR);
- /* clear any PEX errors */
- if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP))
- sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (cap) {
+ /* Check for advanced error reporting */
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+ pci_cleanup_aer_correct_error_status(pdev);
+
+ /* If error bit is stuck on ignore it */
+ if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP)
+ dev_info(&pdev->dev, "ignoring stuck error report bit\n");
+ else if (pci_enable_pcie_error_reporting(pdev))
+ hwe_mask |= Y2_IS_PCI_EXP;
+ }
sky2_power_on(hw);
@@ -2642,8 +2830,6 @@ static void sky2_reset(struct sky2_hw *hw)
| GMC_BYP_RETR_ON);
}
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
/* Clear I2C IRQ noise */
sky2_write32(hw, B2_I2C_IRQ, 1);
@@ -2682,7 +2868,7 @@ static void sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53);
}
- sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK);
+ sky2_write32(hw, B0_HWE_IMSK, hwe_mask);
for (i = 0; i < hw->ports; i++)
sky2_gmac_reset(hw, i);
@@ -2726,14 +2912,10 @@ static void sky2_restart(struct work_struct *work)
struct net_device *dev;
int i, err;
- del_timer_sync(&hw->idle_timer);
-
rtnl_lock();
sky2_write32(hw, B0_IMSK, 0);
sky2_read32(hw, B0_IMSK);
- netif_poll_disable(hw->dev[0]);
-
for (i = 0; i < hw->ports; i++) {
dev = hw->dev[i];
if (netif_running(dev))
@@ -2742,7 +2924,6 @@ static void sky2_restart(struct work_struct *work)
sky2_reset(hw);
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
- netif_poll_enable(hw->dev[0]);
for (i = 0; i < hw->ports; i++) {
dev = hw->dev[i];
@@ -2756,8 +2937,6 @@ static void sky2_restart(struct work_struct *work)
}
}
- sky2_idle_start(hw);
-
rtnl_unlock();
}
@@ -2784,7 +2963,9 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
sky2->wol = wol->wolopts;
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
+ hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P)
sky2_write32(hw, B0_CTST, sky2->wol
? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
@@ -2802,7 +2983,7 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw)
| SUPPORTED_100baseT_Full
| SUPPORTED_Autoneg | SUPPORTED_TP;
- if (hw->chip_id != CHIP_ID_YUKON_FE)
+ if (hw->flags & SKY2_HW_GIGABIT)
modes |= SUPPORTED_1000baseT_Half
| SUPPORTED_1000baseT_Full;
return modes;
@@ -2822,13 +3003,6 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->supported = sky2_supported_modes(hw);
ecmd->phy_address = PHY_ADDR_MARV;
if (sky2_is_copper(hw)) {
- ecmd->supported = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_TP;
ecmd->port = PORT_TP;
ecmd->speed = sky2->speed;
} else {
@@ -2895,8 +3069,10 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
sky2->autoneg = ecmd->autoneg;
sky2->advertising = ecmd->advertising;
- if (netif_running(dev))
+ if (netif_running(dev)) {
sky2_phy_reinit(sky2);
+ sky2_set_multicast(dev);
+ }
return 0;
}
@@ -2989,6 +3165,7 @@ static int sky2_nway_reset(struct net_device *dev)
return -EINVAL;
sky2_phy_reinit(sky2);
+ sky2_set_multicast(dev);
return 0;
}
@@ -3014,9 +3191,14 @@ static void sky2_set_msglevel(struct net_device *netdev, u32 value)
sky2->msg_enable = value;
}
-static int sky2_get_stats_count(struct net_device *dev)
+static int sky2_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(sky2_stats);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(sky2_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void sky2_get_ethtool_stats(struct net_device *dev,
@@ -3040,12 +3222,6 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-static struct net_device_stats *sky2_get_stats(struct net_device *dev)
-{
- struct sky2_port *sky2 = netdev_priv(dev);
- return &sky2->net_stats;
-}
-
static int sky2_set_mac_address(struct net_device *dev, void *p)
{
struct sky2_port *sky2 = netdev_priv(dev);
@@ -3386,20 +3562,64 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
{
const struct sky2_port *sky2 = netdev_priv(dev);
const void __iomem *io = sky2->hw->regs;
+ unsigned int b;
regs->version = 1;
- memset(p, 0, regs->len);
- memcpy_fromio(p, io, B3_RAM_ADDR);
-
- /* skip diagnostic ram region */
- memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1);
+ for (b = 0; b < 128; b++) {
+ /* This complicated switch statement is to make sure and
+ * only access regions that are unreserved.
+ * Some blocks are only valid on dual port cards.
+ * and block 3 has some special diagnostic registers that
+ * are poison.
+ */
+ switch (b) {
+ case 3:
+ /* skip diagnostic ram region */
+ memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
+ break;
- /* copy GMAC registers */
- memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000);
- if (sky2->hw->ports > 1)
- memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000);
+ /* dual port cards only */
+ case 5: /* Tx Arbiter 2 */
+ case 9: /* RX2 */
+ case 14 ... 15: /* TX2 */
+ case 17: case 19: /* Ram Buffer 2 */
+ case 22 ... 23: /* Tx Ram Buffer 2 */
+ case 25: /* Rx MAC Fifo 1 */
+ case 27: /* Tx MAC Fifo 2 */
+ case 31: /* GPHY 2 */
+ case 40 ... 47: /* Pattern Ram 2 */
+ case 52: case 54: /* TCP Segmentation 2 */
+ case 112 ... 116: /* GMAC 2 */
+ if (sky2->hw->ports == 1)
+ goto reserved;
+ /* fall through */
+ case 0: /* Control */
+ case 2: /* Mac address */
+ case 4: /* Tx Arbiter 1 */
+ case 7: /* PCI express reg */
+ case 8: /* RX1 */
+ case 12 ... 13: /* TX1 */
+ case 16: case 18:/* Rx Ram Buffer 1 */
+ case 20 ... 21: /* Tx Ram Buffer 1 */
+ case 24: /* Rx MAC Fifo 1 */
+ case 26: /* Tx MAC Fifo 1 */
+ case 28 ... 29: /* Descriptor and status unit */
+ case 30: /* GPHY 1*/
+ case 32 ... 39: /* Pattern Ram 1 */
+ case 48: case 50: /* TCP Segmentation 1 */
+ case 56 ... 60: /* PCI space */
+ case 80 ... 84: /* GMAC 1 */
+ memcpy_fromio(p, io, 128);
+ break;
+ default:
+reserved:
+ memset(p, 0, 128);
+ }
+ p += 128;
+ io += 128;
+ }
}
/* In order to do Jumbo packets on these chips, need to turn off the
@@ -3435,26 +3655,31 @@ static int sky2_get_eeprom_len(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev);
u16 reg2;
- reg2 = sky2_pci_read32(sky2->hw, PCI_DEV_REG2);
+ pci_read_config_word(sky2->hw->pdev, PCI_DEV_REG2, &reg2);
return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
}
-static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset)
+static u32 sky2_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
{
- sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+ u32 val;
+
+ pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
- while (!(sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F))
- cpu_relax();
- return sky2_pci_read32(hw, cap + PCI_VPD_DATA);
+ do {
+ pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ } while (!(offset & PCI_VPD_ADDR_F));
+
+ pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
+ return val;
}
-static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val)
+static void sky2_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
{
- sky2_pci_write32(hw, cap + PCI_VPD_DATA, val);
- sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
+ pci_write_config_word(pdev, cap + PCI_VPD_DATA, val);
+ pci_write_config_dword(pdev, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
do {
- cpu_relax();
- } while (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F);
+ pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ } while (offset & PCI_VPD_ADDR_F);
}
static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3471,7 +3696,7 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
eeprom->magic = SKY2_EEPROM_MAGIC;
while (length > 0) {
- u32 val = sky2_vpd_read(sky2->hw, cap, offset);
+ u32 val = sky2_vpd_read(sky2->hw->pdev, cap, offset);
int n = min_t(int, length, sizeof(val));
memcpy(data, &val, n);
@@ -3501,10 +3726,10 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
int n = min_t(int, length, sizeof(val));
if (n < sizeof(val))
- val = sky2_vpd_read(sky2->hw, cap, offset);
+ val = sky2_vpd_read(sky2->hw->pdev, cap, offset);
memcpy(&val, data, n);
- sky2_vpd_write(sky2->hw, cap, offset, val);
+ sky2_vpd_write(sky2->hw->pdev, cap, offset, val);
length -= n;
data += n;
@@ -3529,11 +3754,8 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.get_eeprom_len = sky2_get_eeprom_len,
.get_eeprom = sky2_get_eeprom,
.set_eeprom = sky2_set_eeprom,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = sky2_set_tx_csum,
- .get_tso = ethtool_op_get_tso,
.set_tso = sky2_set_tso,
.get_rx_csum = sky2_get_rx_csum,
.set_rx_csum = sky2_set_rx_csum,
@@ -3545,9 +3767,8 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.get_pauseparam = sky2_get_pauseparam,
.set_pauseparam = sky2_set_pauseparam,
.phys_id = sky2_phys_id,
- .get_stats_count = sky2_get_stats_count,
+ .get_sset_count = sky2_get_sset_count,
.get_ethtool_stats = sky2_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
#ifdef CONFIG_SKY2_DEBUG
@@ -3558,7 +3779,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
{
struct net_device *dev = seq->private;
const struct sky2_port *sky2 = netdev_priv(dev);
- const struct sky2_hw *hw = sky2->hw;
+ struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
unsigned idx, last;
int sop;
@@ -3571,7 +3792,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
sky2_read32(hw, B0_IMSK),
sky2_read32(hw, B0_Y2_SP_ICR));
- netif_poll_disable(hw->dev[0]);
+ napi_disable(&hw->napi);
last = sky2_read16(hw, STAT_PUT_IDX);
if (hw->st_idx == last)
@@ -3641,7 +3862,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
- netif_poll_enable(hw->dev[0]);
+ napi_enable(&hw->napi);
return 0;
}
@@ -3666,42 +3887,34 @@ static int sky2_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
+ struct sky2_port *sky2 = netdev_priv(dev);
- if (dev->open == sky2_up) {
- struct sky2_port *sky2 = netdev_priv(dev);
+ if (dev->open != sky2_up || !sky2_debug)
+ return NOTIFY_DONE;
- switch(event) {
- case NETDEV_CHANGENAME:
- if (!netif_running(dev))
- break;
- /* fallthrough */
- case NETDEV_DOWN:
- case NETDEV_GOING_DOWN:
- if (sky2->debugfs) {
- printk(KERN_DEBUG PFX "%s: remove debugfs\n",
- dev->name);
- debugfs_remove(sky2->debugfs);
- sky2->debugfs = NULL;
- }
+ switch(event) {
+ case NETDEV_CHANGENAME:
+ if (sky2->debugfs) {
+ sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
+ sky2_debug, dev->name);
+ }
+ break;
- if (event != NETDEV_CHANGENAME)
- break;
- /* fallthrough for changename */
- case NETDEV_UP:
- if (sky2_debug) {
- struct dentry *d;
- d = debugfs_create_file(dev->name, S_IRUGO,
- sky2_debug, dev,
- &sky2_debug_fops);
- if (d == NULL || IS_ERR(d))
- printk(KERN_INFO PFX
- "%s: debugfs create failed\n",
- dev->name);
- else
- sky2->debugfs = d;
- }
- break;
+ case NETDEV_GOING_DOWN:
+ if (sky2->debugfs) {
+ printk(KERN_DEBUG PFX "%s: remove debugfs\n",
+ dev->name);
+ debugfs_remove(sky2->debugfs);
+ sky2->debugfs = NULL;
}
+ break;
+
+ case NETDEV_UP:
+ sky2->debugfs = debugfs_create_file(dev->name, S_IRUGO,
+ sky2_debug, dev,
+ &sky2_debug_fops);
+ if (IS_ERR(sky2->debugfs))
+ sky2->debugfs = NULL;
}
return NOTIFY_DONE;
@@ -3752,29 +3965,20 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
return NULL;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &hw->pdev->dev);
dev->irq = hw->pdev->irq;
dev->open = sky2_up;
dev->stop = sky2_down;
dev->do_ioctl = sky2_ioctl;
dev->hard_start_xmit = sky2_xmit_frame;
- dev->get_stats = sky2_get_stats;
dev->set_multicast_list = sky2_set_multicast;
dev->set_mac_address = sky2_set_mac_address;
dev->change_mtu = sky2_change_mtu;
SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
dev->tx_timeout = sky2_tx_timeout;
dev->watchdog_timeo = TX_WATCHDOG;
- if (port == 0)
- dev->poll = sky2_poll;
- dev->weight = NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
- /* Network console (only works on port 0)
- * because netpoll makes assumptions about NAPI
- */
- if (port == 0)
- dev->poll_controller = sky2_netpoll;
+ dev->poll_controller = sky2_netpoll;
#endif
sky2 = netdev_priv(dev);
@@ -3805,8 +4009,12 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
dev->features |= NETIF_F_HIGHDMA;
#ifdef SKY2_VLAN_TAG_USED
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- dev->vlan_rx_register = sky2_vlan_rx_register;
+ /* The workaround for FE+ status conflicts with VLAN tag detection. */
+ if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) {
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->vlan_rx_register = sky2_vlan_rx_register;
+ }
#endif
/* read the mac address */
@@ -3819,12 +4027,11 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
static void __devinit sky2_show_addr(struct net_device *dev)
{
const struct sky2_port *sky2 = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
if (netif_msg_probe(sky2))
- printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO PFX "%s: addr %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
/* Handle software interrupt used during MSI test */
@@ -3837,7 +4044,7 @@ static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id)
return IRQ_NONE;
if (status & Y2_IS_IRQ_SW) {
- hw->msi = 1;
+ hw->flags |= SKY2_HW_USE_MSI;
wake_up(&hw->msi_wait);
sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
}
@@ -3865,9 +4072,9 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
sky2_read8(hw, B0_CTST);
- wait_event_timeout(hw->msi_wait, hw->msi, HZ/10);
+ wait_event_timeout(hw->msi_wait, (hw->flags & SKY2_HW_USE_MSI), HZ/10);
- if (!hw->msi) {
+ if (!(hw->flags & SKY2_HW_USE_MSI)) {
/* MSI test failed, go back to INTx mode */
dev_info(&pdev->dev, "No interrupt generated using MSI, "
"switching to INTx mode.\n");
@@ -3957,15 +4164,14 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
*/
{
u32 reg;
- reg = sky2_pci_read32(hw, PCI_DEV_REG2);
+ pci_read_config_dword(pdev,PCI_DEV_REG2, &reg);
reg &= ~PCI_REV_DESC;
- sky2_pci_write32(hw, PCI_DEV_REG2, reg);
+ pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
}
#endif
/* ring for status responses */
- hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES,
- &hw->st_dma);
+ hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma);
if (!hw->st_le)
goto err_out_iounmap;
@@ -3985,6 +4191,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
err = -ENOMEM;
goto err_out_free_pci;
}
+ netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
@@ -4000,7 +4207,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
- err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED,
+ err = request_irq(pdev->irq, sky2_intr,
+ (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED,
dev->name, hw);
if (err) {
dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
@@ -4025,24 +4233,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
sky2_show_addr(dev1);
}
- setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
+ setup_timer(&hw->watchdog_timer, sky2_watchdog, (unsigned long) hw);
INIT_WORK(&hw->restart_work, sky2_restart);
- sky2_idle_start(hw);
-
pci_set_drvdata(pdev, hw);
return 0;
err_out_unregister:
- if (hw->msi)
+ if (hw->flags & SKY2_HW_USE_MSI)
pci_disable_msi(pdev);
unregister_netdev(dev);
err_out_free_netdev:
free_netdev(dev);
err_out_free_pci:
sky2_write8(hw, B0_CTST, CS_RST_SET);
- pci_free_consistent(hw->pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
+ pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
err_out_iounmap:
iounmap(hw->regs);
err_out_free_hw:
@@ -4064,7 +4270,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
if (!hw)
return;
- del_timer_sync(&hw->idle_timer);
+ del_timer_sync(&hw->watchdog_timer);
flush_scheduled_work();
@@ -4084,7 +4290,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
sky2_read8(hw, B0_CTST);
free_irq(pdev->irq, hw);
- if (hw->msi)
+ if (hw->flags & SKY2_HW_USE_MSI)
pci_disable_msi(pdev);
pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
pci_release_regions(pdev);
@@ -4108,9 +4314,6 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
if (!hw)
return 0;
- del_timer_sync(&hw->idle_timer);
- netif_poll_disable(hw->dev[0]);
-
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
struct sky2_port *sky2 = netdev_priv(dev);
@@ -4153,8 +4356,10 @@ static int sky2_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D0, 0);
/* Re-enable all clocks */
- if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ if (hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_EC_U ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P)
+ pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
sky2_reset(hw);
@@ -4170,11 +4375,11 @@ static int sky2_resume(struct pci_dev *pdev)
dev_close(dev);
goto out;
}
+
+ sky2_set_multicast(dev);
}
}
- netif_poll_enable(hw->dev[0]);
- sky2_idle_start(hw);
return 0;
out:
dev_err(&pdev->dev, "resume failed (%d)\n", err);
@@ -4191,8 +4396,7 @@ static void sky2_shutdown(struct pci_dev *pdev)
if (!hw)
return;
- del_timer_sync(&hw->idle_timer);
- netif_poll_disable(hw->dev[0]);
+ napi_disable(&hw->napi);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index dce4d276d443..49ee264064ab 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -18,14 +18,6 @@ enum {
PCI_CFG_REG_1 = 0x94,
};
-enum {
- PEX_DEV_CAP = 0xe4,
- PEX_DEV_CTRL = 0xe8,
- PEX_DEV_STA = 0xea,
- PEX_LNK_STAT = 0xf2,
- PEX_UNC_ERR_STAT= 0x104,
-};
-
/* Yukon-2 */
enum pci_dev_reg_1 {
PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */
@@ -151,38 +143,6 @@ enum pci_cfg_reg1 {
PCI_STATUS_REC_TARGET_ABORT | \
PCI_STATUS_PARITY)
-enum pex_dev_ctrl {
- PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */
- PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */
- PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */
- PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */
- PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */
- PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */
- PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */
- PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */
- PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */
- PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */
- PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */
-};
-#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK)
-
-/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */
-enum pex_err {
- PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */
-
- PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */
-
- PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */
-
- PEX_COMP_TO = 1<<14, /* Completion Timeout */
- PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */
- PEX_POIS_TLP = 1<<12, /* Poisoned TLP */
-
- PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */
- PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P),
-};
-
-
enum csr_regs {
B0_RAP = 0x0000,
B0_CTST = 0x0004,
@@ -419,7 +379,6 @@ enum {
Y2_IS_PAR_RX2 | Y2_IS_TCP_TXS2| Y2_IS_TCP_TXA2,
Y2_HWE_ALL_MASK = Y2_IS_TIST_OV | Y2_IS_MST_ERR | Y2_IS_IRQ_STAT |
- Y2_IS_PCI_EXP |
Y2_HWE_L1_MASK | Y2_HWE_L2_MASK,
};
@@ -470,18 +429,24 @@ enum {
CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
-
+ CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */
+};
+enum yukon_ec_rev {
CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */
CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */
CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */
-
+};
+enum yukon_ec_u_rev {
CHIP_REV_YU_EC_U_A0 = 1,
CHIP_REV_YU_EC_U_A1 = 2,
CHIP_REV_YU_EC_U_B0 = 3,
-
+};
+enum yukon_fe_rev {
CHIP_REV_YU_FE_A1 = 1,
CHIP_REV_YU_FE_A2 = 2,
-
+};
+enum yukon_fe_p_rev {
+ CHIP_REV_YU_FE2_A0 = 0,
};
enum yukon_ex_rev {
CHIP_REV_YU_EX_A0 = 1,
@@ -1668,7 +1633,7 @@ enum {
/* Receive Frame Status Encoding */
enum {
- GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */
+ GMR_FS_LEN = 0x7fff<<16, /* Bit 30..16: Rx Frame Length */
GMR_FS_VLAN = 1<<13, /* VLAN Packet */
GMR_FS_JABBER = 1<<12, /* Jabber Packet */
GMR_FS_UN_SIZE = 1<<11, /* Undersize Packet */
@@ -1729,6 +1694,10 @@ enum {
GMF_RX_CTRL_DEF = GMF_OPER_ON | GMF_RX_F_FL_ON,
};
+/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */
+enum {
+ TX_DYN_WM_ENA = 3, /* Yukon-FE+ specific */
+};
/* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */
enum {
@@ -1840,6 +1809,28 @@ enum {
/* GPHY_CTRL 32 bit GPHY Control Reg (YUKON only) */
enum {
+ GPC_TX_PAUSE = 1<<30, /* Tx pause enabled (ro) */
+ GPC_RX_PAUSE = 1<<29, /* Rx pause enabled (ro) */
+ GPC_SPEED = 3<<27, /* PHY speed (ro) */
+ GPC_LINK = 1<<26, /* Link up (ro) */
+ GPC_DUPLEX = 1<<25, /* Duplex (ro) */
+ GPC_CLOCK = 1<<24, /* 125Mhz clock stable (ro) */
+
+ GPC_PDOWN = 1<<23, /* Internal regulator 2.5 power down */
+ GPC_TSTMODE = 1<<22, /* Test mode */
+ GPC_REG18 = 1<<21, /* Reg18 Power down */
+ GPC_REG12SEL = 3<<19, /* Reg12 power setting */
+ GPC_REG18SEL = 3<<17, /* Reg18 power setting */
+ GPC_SPILOCK = 1<<16, /* SPI lock (ASF) */
+
+ GPC_LEDMUX = 3<<14, /* LED Mux */
+ GPC_INTPOL = 1<<13, /* Interrupt polarity */
+ GPC_DETECT = 1<<12, /* Energy detect */
+ GPC_1000HD = 1<<11, /* Enable 1000Mbit HD */
+ GPC_SLAVE = 1<<10, /* Slave mode */
+ GPC_PAUSE = 1<<9, /* Pause enable */
+ GPC_LEDCTL = 3<<6, /* GPHY Leds */
+
GPC_RST_CLR = 1<<1, /* Clear GPHY Reset */
GPC_RST_SET = 1<<0, /* Set GPHY Reset */
};
@@ -2017,6 +2008,14 @@ struct sky2_port {
u16 rx_tag;
struct vlan_group *vlgrp;
#endif
+ struct {
+ unsigned long last;
+ u32 mac_rp;
+ u8 mac_lev;
+ u8 fifo_rp;
+ u8 fifo_lev;
+ } check;
+
dma_addr_t rx_le_map;
dma_addr_t tx_le_map;
@@ -2032,14 +2031,22 @@ struct sky2_port {
#ifdef CONFIG_SKY2_DEBUG
struct dentry *debugfs;
#endif
- struct net_device_stats net_stats;
-
};
struct sky2_hw {
void __iomem *regs;
struct pci_dev *pdev;
+ struct napi_struct napi;
struct net_device *dev[2];
+ unsigned long flags;
+#define SKY2_HW_USE_MSI 0x00000001
+#define SKY2_HW_FIBRE_PHY 0x00000002
+#define SKY2_HW_GIGABIT 0x00000004
+#define SKY2_HW_NEWER_PHY 0x00000008
+#define SKY2_HW_FIFO_HANG_CHECK 0x00000010
+#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */
+#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
+#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
u8 chip_id;
u8 chip_rev;
@@ -2050,15 +2057,14 @@ struct sky2_hw {
u32 st_idx;
dma_addr_t st_dma;
- struct timer_list idle_timer;
+ struct timer_list watchdog_timer;
struct work_struct restart_work;
- int msi;
wait_queue_head_t msi_wait;
};
static inline int sky2_is_copper(const struct sky2_hw *hw)
{
- return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P');
+ return !(hw->flags & SKY2_HW_FIBRE_PHY);
}
/* Register accessor for memory mapped device */
@@ -2121,25 +2127,4 @@ static inline void gma_set_addr(struct sky2_hw *hw, unsigned port, unsigned reg,
gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
}
-
-/* PCI config space access */
-static inline u32 sky2_pci_read32(const struct sky2_hw *hw, unsigned reg)
-{
- return sky2_read32(hw, Y2_CFG_SPC + reg);
-}
-
-static inline u16 sky2_pci_read16(const struct sky2_hw *hw, unsigned reg)
-{
- return sky2_read16(hw, Y2_CFG_SPC + reg);
-}
-
-static inline void sky2_pci_write32(struct sky2_hw *hw, unsigned reg, u32 val)
-{
- sky2_write32(hw, Y2_CFG_SPC + reg, val);
-}
-
-static inline void sky2_pci_write16(struct sky2_hw *hw, unsigned reg, u16 val)
-{
- sky2_write16(hw, Y2_CFG_SPC + reg, val);
-}
#endif
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 65bd20fac820..335b7cc80eba 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -639,8 +639,6 @@ static void sl_setup(struct net_device *dev)
dev->addr_len = 0;
dev->tx_queue_len = 10;
- SET_MODULE_OWNER(dev);
-
/* New-style flags. */
dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
}
@@ -957,7 +955,7 @@ slip_close(struct tty_struct *tty)
* STANDARD SLIP ENCAPSULATION *
************************************************************************/
-int
+static int
slip_esc(unsigned char *s, unsigned char *d, int len)
{
unsigned char *ptr = d;
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index ae1ae343beed..d6abb68e6e2f 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -196,6 +196,7 @@ static int __init ultramca_probe(struct device *gen_dev)
int tirq = 0;
int base_addr = ultra_io[ultra_found];
int irq = ultra_irq[ultra_found];
+ DECLARE_MAC_BUF(mac);
if (base_addr || irq) {
printk(KERN_INFO "Probing for SMC MCA adapter");
@@ -264,7 +265,6 @@ static int __init ultramca_probe(struct device *gen_dev)
if(!dev)
return -ENODEV;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gen_dev);
mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]);
mca_device_set_claim(mca_dev, 1);
@@ -331,10 +331,11 @@ static int __init ultramca_probe(struct device *gen_dev)
reg4 = inb(ioaddr + 4) & 0x7f;
outb(reg4, ioaddr + 4);
- printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr);
-
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s",
+ slot + 1, ioaddr, print_mac(mac, dev->dev_addr));
/* Switch from the station address to the alternate register set
* and read the useful registers there.
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index a52b22d7db65..00d6cf1af484 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -142,8 +142,6 @@ static int __init do_ultra_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &ultra_poll;
#endif
@@ -200,6 +198,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
unsigned char num_pages, irqreg, addr, piomode;
unsigned char idreg = inb(ioaddr + 7);
unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -226,10 +225,11 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ";
- printk("%s: %s at %#3x,", dev->name, model_name, ioaddr);
-
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk("%s: %s at %#3x, %s", dev->name, model_name,
+ ioaddr, print_mac(mac, dev->dev_addr));
/* Switch from the station address to the alternate register set and
read the useful registers there. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 88a30e56c64c..a5a91ace28cc 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -132,8 +132,6 @@ struct net_device * __init ultra32_probe(int unit)
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
-
irq = dev->irq;
/* EISA spec allows for up to 16 slots, but 8 is typical. */
@@ -165,6 +163,7 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
unsigned char idreg;
unsigned char reg4;
const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -205,10 +204,11 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
model_name = "SMC Ultra32";
- printk("%s: %s at 0x%X,", dev->name, model_name, ioaddr);
-
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk("%s: %s at 0x%X, %s",
+ dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr));
/* Switch from the station address to the alternate register set and
read the useful registers there. */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index db43e42bee35..7c60df46fc65 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -115,13 +115,6 @@ struct smc911x_local {
*/
struct sk_buff *pending_tx_skb;
- /*
- * these are things that the kernel wants me to keep, so users
- * can find out semi-useless statistics of how well the card is
- * performing
- */
- struct net_device_stats stats;
-
/* version/revision of the SMC911x chip */
u16 version;
u16 revision;
@@ -315,8 +308,8 @@ static void smc911x_reset(struct net_device *dev)
if (lp->pending_tx_skb != NULL) {
dev_kfree_skb (lp->pending_tx_skb);
lp->pending_tx_skb = NULL;
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
}
}
@@ -449,14 +442,14 @@ static inline void smc911x_rcv(struct net_device *dev)
pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
if (status & RX_STS_ES_) {
/* Deal with a bad packet */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & RX_STS_CRC_ERR_)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
else {
if (status & RX_STS_LEN_ERR_)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & RX_STS_MCAST_)
- lp->stats.multicast++;
+ dev->stats.multicast++;
}
/* Remove the bad packet data from the RX FIFO */
smc911x_drop_pkt(dev);
@@ -467,7 +460,7 @@ static inline void smc911x_rcv(struct net_device *dev)
if (unlikely(skb == NULL)) {
PRINTK( "%s: Low memory, rcvd packet dropped.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
smc911x_drop_pkt(dev);
return;
}
@@ -503,8 +496,8 @@ static inline void smc911x_rcv(struct net_device *dev)
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len-4;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len-4;
#endif
}
}
@@ -616,8 +609,8 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk("%s: No Tx free space %d < %d\n",
dev->name, free, skb->len);
lp->pending_tx_skb = NULL;
- lp->stats.tx_errors++;
- lp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return 0;
}
@@ -667,8 +660,8 @@ static void smc911x_tx(struct net_device *dev)
dev->name,
(SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16);
tx_status = SMC_GET_TX_STS_FIFO();
- lp->stats.tx_packets++;
- lp->stats.tx_bytes+=tx_status>>16;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes+=tx_status>>16;
DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
dev->name, (tx_status & 0xffff0000) >> 16,
tx_status & 0x0000ffff);
@@ -676,22 +669,22 @@ static void smc911x_tx(struct net_device *dev)
* full-duplex mode */
if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx &&
!(tx_status & 0x00000306))) {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
if (tx_status & TX_STS_MANY_COLL_) {
- lp->stats.collisions+=16;
- lp->stats.tx_aborted_errors++;
+ dev->stats.collisions+=16;
+ dev->stats.tx_aborted_errors++;
} else {
- lp->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
+ dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
}
/* carrier error only has meaning for half-duplex communication */
if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) &&
!lp->ctl_rfduplx) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (tx_status & TX_STS_LATE_COLL_) {
- lp->stats.collisions++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.collisions++;
+ dev->stats.tx_aborted_errors++;
}
}
}
@@ -1121,11 +1114,11 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
/* Handle various error conditions */
if (status & INT_STS_RXE_) {
SMC_ACK_INT(INT_STS_RXE_);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
if (status & INT_STS_RXDFH_INT_) {
SMC_ACK_INT(INT_STS_RXDFH_INT_);
- lp->stats.rx_dropped+=SMC_GET_RX_DROP();
+ dev->stats.rx_dropped+=SMC_GET_RX_DROP();
}
/* Undocumented interrupt-what is the right thing to do here? */
if (status & INT_STS_RXDF_INT_) {
@@ -1140,8 +1133,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
cr &= ~MAC_CR_RXEN_;
SMC_SET_MAC_CR(cr);
DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
}
SMC_ACK_INT(INT_STS_RDFL_);
}
@@ -1152,8 +1145,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
SMC_SET_MAC_CR(cr);
rx_overrun=1;
DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
}
SMC_ACK_INT(INT_STS_RDFO_);
}
@@ -1307,8 +1300,8 @@ smc911x_rx_dma_irq(int dma, void *data)
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
spin_lock_irqsave(&lp->lock, flags);
pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16;
@@ -1568,19 +1561,6 @@ static int smc911x_close(struct net_device *dev)
}
/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *smc911x_query_statistics(struct net_device *dev)
-{
- struct smc911x_local *lp = netdev_priv(dev);
- DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
-
-
- return &lp->stats;
-}
-
-/*
* Ethtool support
*/
static int
@@ -2056,7 +2036,6 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
dev->hard_start_xmit = smc911x_hard_start_xmit;
dev->tx_timeout = smc911x_timeout;
dev->watchdog_timeo = msecs_to_jiffies(watchdog);
- dev->get_stats = smc911x_query_statistics;
dev->set_multicast_list = smc911x_set_multicast_list;
dev->ethtool_ops = &smc911x_ethtool_ops;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2084,7 +2063,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
/* Grab the IRQ */
retval = request_irq(dev->irq, &smc911x_interrupt,
- IRQF_SHARED | IRQF_TRIGGER_FALLING, dev->name, dev);
+ IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev);
if (retval)
goto err_out;
@@ -2181,7 +2160,6 @@ static int smc911x_drv_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto release_1;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->dma = (unsigned char)-1;
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 962a710459fc..16a0edc078fd 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -36,6 +36,12 @@
#define SMC_USE_PXA_DMA 1
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING
+#elif CONFIG_SH_MAGIC_PANEL_R2
+ #define SMC_USE_SH_DMA 0
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
#endif
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 36c1ebadbf20..cb2698de5190 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -191,13 +191,6 @@ static struct devlist smc_devlist[] __initdata = {
/* store this information for the driver.. */
struct smc_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
- performing
- */
- struct net_device_stats stats;
-
- /*
If I have to wait until memory is available to send
a packet, I will store the skbuff here, until I get the
desired memory. Then, I'll send it out and free it.
@@ -249,12 +242,6 @@ static void smc_timeout(struct net_device *dev);
static int smc_close(struct net_device *dev);
/*
- . This routine allows the proc file system to query the driver's
- . statistics.
-*/
-static struct net_device_stats * smc_query_statistics( struct net_device *dev);
-
-/*
. Finally, a call to set promiscuous mode ( for TCPDUMP and related
. programs ) and multicast modes.
*/
@@ -514,7 +501,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
if ( lp->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
return 1;
}
@@ -744,8 +731,6 @@ struct net_device * __init smc_init(int unit)
irq = dev->irq;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = smc_probe(dev, io);
} else if (io != 0) { /* Don't probe at all. */
@@ -891,6 +876,8 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
word memory_info_register;
word memory_cfg_register;
+ DECLARE_MAC_BUF(mac);
+
/* Grab the region so that no one else tries to probe our ioports. */
if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -1046,10 +1033,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
/*
. Print the Ethernet address
*/
- printk("ADDR: ");
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i] );
- printk("%2.2x \n", dev->dev_addr[5] );
+ printk("ADDR: %s\n", print_mac(mac, dev->dev_addr));
/* set the private data to zero by default */
memset(dev->priv, 0, sizeof(struct smc_local));
@@ -1067,7 +1051,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
dev->hard_start_xmit = smc_wait_to_send_packet;
dev->tx_timeout = smc_timeout;
dev->watchdog_timeo = HZ/20;
- dev->get_stats = smc_query_statistics;
dev->set_multicast_list = smc_set_multicast_list;
return 0;
@@ -1201,7 +1184,6 @@ static void smc_timeout(struct net_device *dev)
*/
static void smc_rcv(struct net_device *dev)
{
- struct smc_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int packet_number;
word status;
@@ -1245,13 +1227,13 @@ static void smc_rcv(struct net_device *dev)
/* set multicast stats */
if ( status & RS_MULTICAST )
- lp->stats.multicast++;
+ dev->stats.multicast++;
skb = dev_alloc_skb( packet_length + 5);
if ( skb == NULL ) {
printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto done;
}
@@ -1291,16 +1273,16 @@ static void smc_rcv(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev );
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += packet_length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += packet_length;
} else {
/* error ... */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
- if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++;
+ if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++;
if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
- lp->stats.rx_length_errors++;
- if ( status & RS_BADCRC) lp->stats.rx_crc_errors++;
+ dev->stats.rx_length_errors++;
+ if ( status & RS_BADCRC) dev->stats.rx_crc_errors++;
}
done:
@@ -1348,12 +1330,12 @@ static void smc_tx( struct net_device * dev )
tx_status = inw( ioaddr + DATA_1 );
PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));
- lp->stats.tx_errors++;
- if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
+ if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
if ( tx_status & TS_LATCOL ) {
printk(KERN_DEBUG CARDNAME
": Late collision occurred on last xmit.\n");
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
}
#if 0
if ( tx_status & TS_16COL ) { ... }
@@ -1448,10 +1430,10 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
SMC_SELECT_BANK( 0 );
card_stats = inw( ioaddr + COUNTER );
/* single collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
card_stats >>= 4;
/* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
/* these are for when linux supports these statistics */
@@ -1460,7 +1442,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
": TX_BUFFER_EMPTY handled\n"));
outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
mask &= ~IM_TX_EMPTY_INT;
- lp->stats.tx_packets += lp->packets_waiting;
+ dev->stats.tx_packets += lp->packets_waiting;
lp->packets_waiting = 0;
} else if (status & IM_ALLOC_INT ) {
@@ -1479,8 +1461,8 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
PRINTK2((CARDNAME": Handoff done successfully.\n"));
} else if (status & IM_RX_OVRN_INT ) {
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
} else if (status & IM_EPH_INT ) {
PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
@@ -1523,16 +1505,6 @@ static int smc_close(struct net_device *dev)
return 0;
}
-/*------------------------------------------------------------
- . Get the current statistics.
- . This may be called with the card open or closed.
- .-------------------------------------------------------------*/
-static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
- struct smc_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/*-----------------------------------------------------------
. smc_set_multicast_list
.
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 01cc3c742c38..24e610e711e8 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -183,13 +183,6 @@ struct smc_local {
struct sk_buff *pending_tx_skb;
struct tasklet_struct tx_task;
- /*
- * these are things that the kernel wants me to keep, so users
- * can find out semi-useless statistics of how well the card is
- * performing
- */
- struct net_device_stats stats;
-
/* version/revision of the SMC91x chip */
int version;
@@ -332,8 +325,8 @@ static void smc_reset(struct net_device *dev)
/* free any pending tx skb */
if (pending_skb) {
dev_kfree_skb(pending_skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
}
/*
@@ -512,13 +505,13 @@ static inline void smc_rcv(struct net_device *dev)
}
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & RS_ALGNERR)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & (RS_TOOSHORT | RS_TOOLONG))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & RS_BADCRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
} else {
struct sk_buff *skb;
unsigned char *data;
@@ -526,7 +519,7 @@ static inline void smc_rcv(struct net_device *dev)
/* set multicast stats */
if (status & RS_MULTICAST)
- lp->stats.multicast++;
+ dev->stats.multicast++;
/*
* Actual payload is packet_len - 6 (or 5 if odd byte).
@@ -542,7 +535,7 @@ static inline void smc_rcv(struct net_device *dev)
dev->name);
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -570,8 +563,8 @@ static inline void smc_rcv(struct net_device *dev)
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += data_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += data_len;
}
}
@@ -644,8 +637,8 @@ static void smc_hardware_send_pkt(unsigned long data)
packet_no = SMC_GET_AR();
if (unlikely(packet_no & AR_FAILED)) {
printk("%s: Memory allocation failed.\n", dev->name);
- lp->stats.tx_errors++;
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_fifo_errors++;
smc_special_unlock(&lp->lock);
goto done;
}
@@ -688,8 +681,8 @@ static void smc_hardware_send_pkt(unsigned long data)
smc_special_unlock(&lp->lock);
dev->trans_start = jiffies;
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
@@ -729,8 +722,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
if (unlikely(numPages > 7)) {
printk("%s: Far too big packet error.\n", dev->name);
- lp->stats.tx_errors++;
- lp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return 0;
}
@@ -803,17 +796,17 @@ static void smc_tx(struct net_device *dev)
dev->name, tx_status, packet_no);
if (!(tx_status & ES_TX_SUC))
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status & ES_LOSTCARR)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & (ES_LATCOL | ES_16COL)) {
PRINTK("%s: %s occurred on last xmit\n", dev->name,
(tx_status & ES_LATCOL) ?
"late collision" : "too many collisions");
- lp->stats.tx_window_errors++;
- if (!(lp->stats.tx_window_errors & 63) && net_ratelimit()) {
+ dev->stats.tx_window_errors++;
+ if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) {
printk(KERN_INFO "%s: unexpectedly large number of "
"bad collisions. Please check duplex "
"setting.\n", dev->name);
@@ -1347,19 +1340,19 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
SMC_SELECT_BANK(2);
/* single collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
card_stats >>= 4;
/* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
} else if (status & IM_RX_OVRN_INT) {
DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name,
({ int eph_st; SMC_SELECT_BANK(0);
eph_st = SMC_GET_EPH_STATUS();
SMC_SELECT_BANK(2); eph_st; }) );
SMC_ACK_INT(IM_RX_OVRN_INT);
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
} else if (status & IM_EPH_INT) {
smc_eph_interrupt(dev);
} else if (status & IM_MDINT) {
@@ -1628,19 +1621,6 @@ static int smc_close(struct net_device *dev)
}
/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *smc_query_statistics(struct net_device *dev)
-{
- struct smc_local *lp = netdev_priv(dev);
-
- DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
-
- return &lp->stats;
-}
-
-/*
* Ethtool support
*/
static int
@@ -1842,9 +1822,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
{
struct smc_local *lp = netdev_priv(dev);
static int version_printed = 0;
- int i, retval;
+ int retval;
unsigned int val, revision_register;
const char *version_string;
+ DECLARE_MAC_BUF(mac);
DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
@@ -1965,7 +1946,6 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
dev->hard_start_xmit = smc_hard_start_xmit;
dev->tx_timeout = smc_timeout;
dev->watchdog_timeo = msecs_to_jiffies(watchdog);
- dev->get_stats = smc_query_statistics;
dev->set_multicast_list = smc_set_multicast_list;
dev->ethtool_ops = &smc_ethtool_ops;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2035,10 +2015,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
"set using ifconfig\n", dev->name);
} else {
/* Print the Ethernet address */
- printk("%s: Ethernet addr: ", dev->name);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x\n", dev->dev_addr[5]);
+ printk("%s: Ethernet addr: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
if (lp->phy_type == 0) {
@@ -2212,7 +2190,6 @@ static int smc_drv_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto out_release_io;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->dma = (unsigned char)-1;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index f8429449dc1e..af9e6bf59552 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -284,6 +284,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#elif defined(CONFIG_SUPERH)
#ifdef CONFIG_SOLUTION_ENGINE
+#define SMC_IRQ_FLAGS (0)
#define SMC_CAN_USE_8BIT 0
#define SMC_CAN_USE_16BIT 1
#define SMC_CAN_USE_32BIT 0
@@ -299,7 +300,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_CAN_USE_8BIT 1
#define SMC_CAN_USE_16BIT 1
-#define SMC_CAN_USE_32BIT 1
+#define SMC_CAN_USE_32BIT 0
#define SMC_inb(a, r) inb((a) + (r))
#define SMC_inw(a, r) inw((a) + (r))
@@ -310,8 +311,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#endif /* BOARDS */
-#define set_irq_type(irq, type) do {} while (0)
-
#elif defined(CONFIG_M32R)
#define SMC_CAN_USE_8BIT 0
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 590b12c7246c..fab055ffcc90 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -795,6 +795,7 @@ spider_net_set_low_watermark(struct spider_net_card *card)
static int
spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
{
+ struct net_device *dev = card->netdev;
struct spider_net_descr_chain *chain = &card->tx_chain;
struct spider_net_descr *descr;
struct spider_net_hw_descr *hwdescr;
@@ -815,8 +816,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
status = spider_net_get_descr_status(hwdescr);
switch (status) {
case SPIDER_NET_DESCR_COMPLETE:
- card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes += descr->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += descr->skb->len;
break;
case SPIDER_NET_DESCR_CARDOWNED:
@@ -835,11 +836,11 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
if (netif_msg_tx_err(card))
dev_err(&card->netdev->dev, "forcing end of tx descriptor "
"with status x%02x\n", status);
- card->netdev_stats.tx_errors++;
+ dev->stats.tx_errors++;
break;
default:
- card->netdev_stats.tx_dropped++;
+ dev->stats.tx_dropped++;
if (!brutal) {
spin_unlock_irqrestore(&chain->lock, flags);
return 1;
@@ -919,7 +920,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
spider_net_release_tx_chain(card, 0);
if (spider_net_prepare_tx_descr(card, skb) != 0) {
- card->netdev_stats.tx_dropped++;
+ netdev->stats.tx_dropped++;
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
}
@@ -979,16 +980,12 @@ static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
struct spider_net_card *card)
{
- struct spider_net_hw_descr *hwdescr= descr->hwdescr;
- struct sk_buff *skb;
- struct net_device *netdev;
- u32 data_status, data_error;
-
- data_status = hwdescr->data_status;
- data_error = hwdescr->data_error;
- netdev = card->netdev;
+ struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+ struct sk_buff *skb = descr->skb;
+ struct net_device *netdev = card->netdev;
+ u32 data_status = hwdescr->data_status;
+ u32 data_error = hwdescr->data_error;
- skb = descr->skb;
skb_put(skb, hwdescr->valid_size);
/* the card seems to add 2 bytes of junk in front
@@ -1015,8 +1012,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
}
/* update netdevice statistics */
- card->netdev_stats.rx_packets++;
- card->netdev_stats.rx_bytes += skb->len;
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += skb->len;
/* pass skb up to stack */
netif_receive_skb(skb);
@@ -1184,6 +1181,7 @@ static int spider_net_resync_tail_ptr(struct spider_net_card *card)
static int
spider_net_decode_one_descr(struct spider_net_card *card)
{
+ struct net_device *dev = card->netdev;
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
struct spider_net_hw_descr *hwdescr = descr->hwdescr;
@@ -1210,9 +1208,9 @@ spider_net_decode_one_descr(struct spider_net_card *card)
(status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
(status == SPIDER_NET_DESCR_FORCE_END) ) {
if (netif_msg_rx_err(card))
- dev_err(&card->netdev->dev,
+ dev_err(&dev->dev,
"dropping RX descriptor with state %d\n", status);
- card->netdev_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto bad_desc;
}
@@ -1278,34 +1276,26 @@ bad_desc:
* (using netif_receive_skb). If all/enough packets are up, the driver
* reenables interrupts and returns 0. If not, 1 is returned.
*/
-static int
-spider_net_poll(struct net_device *netdev, int *budget)
+static int spider_net_poll(struct napi_struct *napi, int budget)
{
- struct spider_net_card *card = netdev_priv(netdev);
- int packets_to_do, packets_done = 0;
- int no_more_packets = 0;
-
- packets_to_do = min(*budget, netdev->quota);
-
- while (packets_to_do) {
- if (spider_net_decode_one_descr(card)) {
- packets_done++;
- packets_to_do--;
- } else {
- /* no more packets for the stack */
- no_more_packets = 1;
+ struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
+ struct net_device *netdev = card->netdev;
+ int packets_done = 0;
+
+ while (packets_done < budget) {
+ if (!spider_net_decode_one_descr(card))
break;
- }
+
+ packets_done++;
}
if ((packets_done == 0) && (card->num_rx_ints != 0)) {
- no_more_packets = spider_net_resync_tail_ptr(card);
+ if (!spider_net_resync_tail_ptr(card))
+ packets_done = budget;
spider_net_resync_head_ptr(card);
}
card->num_rx_ints = 0;
- netdev->quota -= packets_done;
- *budget -= packets_done;
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
@@ -1313,28 +1303,13 @@ spider_net_poll(struct net_device *netdev, int *budget)
/* if all packets are in the stack, enable interrupts and return 0 */
/* if not, return 1 */
- if (no_more_packets) {
- netif_rx_complete(netdev);
+ if (packets_done < budget) {
+ netif_rx_complete(netdev, napi);
spider_net_rx_irq_on(card);
card->ignore_rx_ramfull = 0;
- return 0;
}
- return 1;
-}
-
-/**
- * spider_net_get_stats - get interface statistics
- * @netdev: interface device structure
- *
- * returns the interface statistics residing in the spider_net_card struct
- */
-static struct net_device_stats *
-spider_net_get_stats(struct net_device *netdev)
-{
- struct spider_net_card *card = netdev_priv(netdev);
- struct net_device_stats *stats = &card->netdev_stats;
- return stats;
+ return packets_done;
}
/**
@@ -1441,17 +1416,14 @@ static void
spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
{
u32 error_reg1, error_reg2;
- u32 mask_reg1, mask_reg2;
u32 i;
int show_error = 1;
error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
- mask_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1MSK);
- mask_reg2 = spider_net_read_reg(card,SPIDER_NET_GHIINT2MSK);
- error_reg1 &= mask_reg1;
- error_reg2 &= mask_reg2;
+ error_reg1 &= SPIDER_NET_INT1_MASK_VALUE;
+ error_reg2 &= SPIDER_NET_INT2_MASK_VALUE;
/* check GHIINT0STS ************************************/
if (status_reg)
@@ -1563,7 +1535,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
card->num_rx_ints ++;
- netif_rx_schedule(card->netdev);
+ netif_rx_schedule(card->netdev,
+ &card->napi);
}
show_error = 0;
break;
@@ -1583,7 +1556,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
card->num_rx_ints ++;
- netif_rx_schedule(card->netdev);
+ netif_rx_schedule(card->netdev,
+ &card->napi);
show_error = 0;
break;
@@ -1597,7 +1571,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
card->num_rx_ints ++;
- netif_rx_schedule(card->netdev);
+ netif_rx_schedule(card->netdev,
+ &card->napi);
show_error = 0;
break;
@@ -1679,22 +1654,21 @@ spider_net_interrupt(int irq, void *ptr)
{
struct net_device *netdev = ptr;
struct spider_net_card *card = netdev_priv(netdev);
- u32 status_reg, mask_reg;
+ u32 status_reg;
status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
- mask_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
- status_reg &= mask_reg;
+ status_reg &= SPIDER_NET_INT0_MASK_VALUE;
if (!status_reg)
return IRQ_NONE;
if (status_reg & SPIDER_NET_RXINT ) {
spider_net_rx_irq_off(card);
- netif_rx_schedule(netdev);
+ netif_rx_schedule(netdev, &card->napi);
card->num_rx_ints ++;
}
if (status_reg & SPIDER_NET_TXINT)
- netif_rx_schedule(netdev);
+ netif_rx_schedule(netdev, &card->napi);
if (status_reg & SPIDER_NET_LINKINT)
spider_net_link_reset(netdev);
@@ -2038,7 +2012,7 @@ spider_net_open(struct net_device *netdev)
netif_start_queue(netdev);
netif_carrier_on(netdev);
- netif_poll_enable(netdev);
+ napi_enable(&card->napi);
spider_net_enable_interrupts(card);
@@ -2208,7 +2182,7 @@ spider_net_stop(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- netif_poll_disable(netdev);
+ napi_disable(&card->napi);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
del_timer_sync(&card->tx_timer);
@@ -2300,7 +2274,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev)
netdev->open = &spider_net_open;
netdev->stop = &spider_net_stop;
netdev->hard_start_xmit = &spider_net_xmit;
- netdev->get_stats = &spider_net_get_stats;
netdev->set_multicast_list = &spider_net_set_multi;
netdev->set_mac_address = &spider_net_set_mac;
netdev->change_mtu = &spider_net_change_mtu;
@@ -2308,9 +2281,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev)
/* tx watchdog */
netdev->tx_timeout = &spider_net_tx_timeout;
netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
- /* NAPI */
- netdev->poll = &spider_net_poll;
- netdev->weight = SPIDER_NET_NAPI_WEIGHT;
/* HW VLAN */
#ifdef CONFIG_NET_POLL_CONTROLLER
/* poll controller */
@@ -2337,7 +2307,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
struct sockaddr addr;
const u8 *mac;
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &card->pdev->dev);
pci_set_drvdata(card->pdev, netdev);
@@ -2355,6 +2324,9 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+ netif_napi_add(netdev, &card->napi,
+ spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
+
spider_net_setup_netdev_ops(netdev);
netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index dbbdb8cee3c6..a897beee7d5d 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -466,6 +466,8 @@ struct spider_net_card {
struct pci_dev *pdev;
struct mii_phy phy;
+ struct napi_struct napi;
+
int medium;
void __iomem *regs;
@@ -485,7 +487,6 @@ struct spider_net_card {
/* for ethtool */
int msg_enable;
- struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
struct spider_net_options options;
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index d940474e024a..85691d2a0be2 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -28,8 +28,6 @@
#include "spider_net.h"
-#define SPIDER_NET_NUM_STATS 13
-
static struct {
const char str[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
@@ -147,9 +145,14 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev,
ering->rx_pending = card->rx_chain.num_desc;
}
-static int spider_net_get_stats_count(struct net_device *netdev)
+static int spider_net_get_sset_count(struct net_device *netdev, int sset)
{
- return SPIDER_NET_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ethtool_stats_keys);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void spider_net_get_ethtool_stats(struct net_device *netdev,
@@ -157,13 +160,13 @@ static void spider_net_get_ethtool_stats(struct net_device *netdev,
{
struct spider_net_card *card = netdev->priv;
- data[0] = card->netdev_stats.tx_packets;
- data[1] = card->netdev_stats.tx_bytes;
- data[2] = card->netdev_stats.rx_packets;
- data[3] = card->netdev_stats.rx_bytes;
- data[4] = card->netdev_stats.tx_errors;
- data[5] = card->netdev_stats.tx_dropped;
- data[6] = card->netdev_stats.rx_dropped;
+ data[0] = netdev->stats.tx_packets;
+ data[1] = netdev->stats.tx_bytes;
+ data[2] = netdev->stats.rx_packets;
+ data[3] = netdev->stats.rx_bytes;
+ data[4] = netdev->stats.tx_errors;
+ data[5] = netdev->stats.tx_dropped;
+ data[6] = netdev->stats.rx_dropped;
data[7] = card->spider_stats.rx_desc_error;
data[8] = card->spider_stats.tx_timeouts;
data[9] = card->spider_stats.alloc_rx_skb_error;
@@ -188,11 +191,10 @@ const struct ethtool_ops spider_net_ethtool_ops = {
.nway_reset = spider_net_ethtool_nway_reset,
.get_rx_csum = spider_net_ethtool_get_rx_csum,
.set_rx_csum = spider_net_ethtool_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
.get_ringparam = spider_net_ethtool_get_ringparam,
.get_strings = spider_net_get_strings,
- .get_stats_count = spider_net_get_stats_count,
+ .get_sset_count = spider_net_get_sset_count,
.get_ethtool_stats = spider_net_get_ethtool_stats,
};
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 8b6478663a56..bcc430bd9e49 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -155,7 +155,7 @@ static int full_duplex[MAX_UNITS] = {0, };
#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
-#define netdrv_addr_t u64
+#define netdrv_addr_t __le64
#define cpu_to_dma(x) cpu_to_le64(x)
#define dma_to_cpu(x) le64_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit
@@ -164,7 +164,7 @@ static int full_duplex[MAX_UNITS] = {0, };
#define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit
#define RX_DESC_ADDR_SIZE RxDescAddr64bit
#else /* 32-bit dma_addr_t */
-#define netdrv_addr_t u32
+#define netdrv_addr_t __le32
#define cpu_to_dma(x) cpu_to_le32(x)
#define dma_to_cpu(x) le32_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit
@@ -178,16 +178,13 @@ static int full_duplex[MAX_UNITS] = {0, };
#define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
#ifdef HAVE_NETDEV_POLL
-#define init_poll(dev) \
-do { \
- dev->poll = &netdev_poll; \
- dev->weight = max_interrupt_work; \
-} while (0)
-#define netdev_rx(dev, ioaddr) \
+#define init_poll(dev, np) \
+ netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work)
+#define netdev_rx(dev, np, ioaddr) \
do { \
u32 intr_enable; \
- if (netif_rx_schedule_prep(dev)) { \
- __netif_rx_schedule(dev); \
+ if (netif_rx_schedule_prep(dev, &np->napi)) { \
+ __netif_rx_schedule(dev, &np->napi); \
intr_enable = readl(ioaddr + IntrEnable); \
intr_enable &= ~(IntrRxDone | IntrRxEmpty); \
writel(intr_enable, ioaddr + IntrEnable); \
@@ -204,12 +201,12 @@ do { \
} while (0)
#define netdev_receive_skb(skb) netif_receive_skb(skb)
#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid)
-static int netdev_poll(struct net_device *dev, int *budget);
+static int netdev_poll(struct napi_struct *napi, int budget);
#else /* not HAVE_NETDEV_POLL */
-#define init_poll(dev)
+#define init_poll(dev, np)
#define netdev_receive_skb(skb) netif_rx(skb)
#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid)
-#define netdev_rx(dev, ioaddr) \
+#define netdev_rx(dev, np, ioaddr) \
do { \
int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \
__netdev_rx(dev, &quota);\
@@ -497,7 +494,7 @@ enum intr_ctrl_bits {
/* The Rx and Tx buffer descriptors. */
struct starfire_rx_desc {
- dma_addr_t rxaddr;
+ netdrv_addr_t rxaddr;
};
enum rx_desc_bits {
RxDescValid=1, RxDescEndRing=2,
@@ -505,25 +502,25 @@ enum rx_desc_bits {
/* Completion queue entry. */
struct short_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
+ __le32 status; /* Low 16 bits is length. */
};
struct basic_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
- u16 vlanid;
- u16 status2;
+ __le32 status; /* Low 16 bits is length. */
+ __le16 vlanid;
+ __le16 status2;
};
struct csum_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
- u16 csum; /* Partial checksum */
- u16 status2;
+ __le32 status; /* Low 16 bits is length. */
+ __le16 csum; /* Partial checksum */
+ __le16 status2;
};
struct full_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
- u16 status3;
- u16 status2;
- u16 vlanid;
- u16 csum; /* partial checksum */
- u32 timestamp;
+ __le32 status; /* Low 16 bits is length. */
+ __le16 status3;
+ __le16 status2;
+ __le16 vlanid;
+ __le16 csum; /* partial checksum */
+ __le32 timestamp;
};
/* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */
#ifdef VLAN_SUPPORT
@@ -540,15 +537,15 @@ enum rx_done_bits {
/* Type 1 Tx descriptor. */
struct starfire_tx_desc_1 {
- u32 status; /* Upper bits are status, lower 16 length. */
- u32 addr;
+ __le32 status; /* Upper bits are status, lower 16 length. */
+ __le32 addr;
};
/* Type 2 Tx descriptor. */
struct starfire_tx_desc_2 {
- u32 status; /* Upper bits are status, lower 16 length. */
- u32 reserved;
- u64 addr;
+ __le32 status; /* Upper bits are status, lower 16 length. */
+ __le32 reserved;
+ __le64 addr;
};
#ifdef ADDR_64BITS
@@ -566,9 +563,9 @@ enum tx_desc_bits {
TxRingWrap=0x04000000, TxCalTCP=0x02000000,
};
struct tx_done_desc {
- u32 status; /* timestamp, index. */
+ __le32 status; /* timestamp, index. */
#if 0
- u32 intrstatus; /* interrupt status */
+ __le32 intrstatus; /* interrupt status */
#endif
};
@@ -599,6 +596,8 @@ struct netdev_private {
struct tx_done_desc *tx_done_q;
dma_addr_t tx_done_q_dma;
unsigned int tx_done;
+ struct napi_struct napi;
+ struct net_device *dev;
struct net_device_stats stats;
struct pci_dev *pci_dev;
#ifdef VLAN_SUPPORT
@@ -695,6 +694,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
void __iomem *base;
int drv_flags, io_size;
int boguscnt;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -720,7 +720,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx);
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
irq = pdev->irq;
@@ -791,6 +790,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
dev->irq = irq;
np = netdev_priv(dev);
+ np->dev = dev;
np->base = base;
spin_lock_init(&np->lock);
pci_set_drvdata(pdev, dev);
@@ -851,7 +851,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
dev->hard_start_xmit = &start_tx;
dev->tx_timeout = tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- init_poll(dev);
+ init_poll(dev, np);
dev->stop = &netdev_close;
dev->get_stats = &get_stats;
dev->set_multicast_list = &set_rx_mode;
@@ -864,11 +864,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
if (register_netdev(dev))
goto err_out_cleardev;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, netdrv_tbl[chip_idx].name, base);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, netdrv_tbl[chip_idx].name, base,
+ print_mac(mac, dev->dev_addr), irq);
if (drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
@@ -965,7 +963,7 @@ static int netdev_open(struct net_device *dev)
dev->name, dev->irq);
/* Allocate the various queues. */
- if (np->queue_mem == 0) {
+ if (!np->queue_mem) {
tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
@@ -1038,11 +1036,11 @@ static int netdev_open(struct net_device *dev)
writew(0, ioaddr + PerfFilterTable + 4);
writew(0, ioaddr + PerfFilterTable + 8);
for (i = 1; i < 16; i++) {
- u16 *eaddrs = (u16 *)dev->dev_addr;
+ __be16 *eaddrs = (__be16 *)dev->dev_addr;
void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16;
- writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
- writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
- writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
+ writew(be16_to_cpu(eaddrs[2]), setup_frm); setup_frm += 4;
+ writew(be16_to_cpu(eaddrs[1]), setup_frm); setup_frm += 4;
+ writew(be16_to_cpu(eaddrs[0]), setup_frm); setup_frm += 8;
}
/* Initialize other registers. */
@@ -1056,6 +1054,9 @@ static int netdev_open(struct net_device *dev)
writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl);
+#ifdef HAVE_NETDEV_POLL
+ napi_enable(&np->napi);
+#endif
netif_start_queue(dev);
if (debug > 1)
@@ -1330,7 +1331,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
handled = 1;
if (intr_status & (IntrRxDone | IntrRxEmpty))
- netdev_rx(dev, ioaddr);
+ netdev_rx(dev, np, ioaddr);
/* Scavenge the skbuff list based on the Tx-done queue.
There are redundant checks here that may be cleaned up
@@ -1470,13 +1471,16 @@ static int __netdev_rx(struct net_device *dev, int *quota)
}
#ifndef final_version /* Remove after testing. */
/* You will want this info for the initial debug. */
- if (debug > 5)
- printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
- "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n",
- skb->data[0], skb->data[1], skb->data[2], skb->data[3],
- skb->data[4], skb->data[5], skb->data[6], skb->data[7],
- skb->data[8], skb->data[9], skb->data[10],
- skb->data[11], skb->data[12], skb->data[13]);
+ if (debug > 5) {
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG " Rx data %s %s"
+ " %2.2x%2.2x.\n",
+ print_mac(mac, &skb->data[0]),
+ print_mac(mac2, &skb->data[6]),
+ skb->data[12], skb->data[13]);
+ }
#endif
skb->protocol = eth_type_trans(skb, dev);
@@ -1531,36 +1535,35 @@ static int __netdev_rx(struct net_device *dev, int *quota)
#ifdef HAVE_NETDEV_POLL
-static int netdev_poll(struct net_device *dev, int *budget)
+static int netdev_poll(struct napi_struct *napi, int budget)
{
+ struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+ struct net_device *dev = np->dev;
u32 intr_status;
- struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = np->base;
- int retcode = 0, quota = dev->quota;
+ int quota = budget;
do {
writel(IntrRxDone | IntrRxEmpty, ioaddr + IntrClear);
- retcode = __netdev_rx(dev, &quota);
- *budget -= (dev->quota - quota);
- dev->quota = quota;
- if (retcode)
+ if (__netdev_rx(dev, &quota))
goto out;
intr_status = readl(ioaddr + IntrStatus);
} while (intr_status & (IntrRxDone | IntrRxEmpty));
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
intr_status = readl(ioaddr + IntrEnable);
intr_status |= IntrRxDone | IntrRxEmpty;
writel(intr_status, ioaddr + IntrEnable);
out:
if (debug > 5)
- printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", retcode);
+ printk(KERN_DEBUG " exiting netdev_poll(): %d.\n",
+ budget - quota);
/* Restart Rx engine if stopped. */
- return retcode;
+ return budget - quota;
}
#endif /* HAVE_NETDEV_POLL */
@@ -1764,26 +1767,26 @@ static void set_rx_mode(struct net_device *dev)
} else if (dev->mc_count <= 14) {
/* Use the 16 element perfect filter, skip first two entries. */
void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
- u16 *eaddrs;
+ __be16 *eaddrs;
for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
i++, mclist = mclist->next) {
- eaddrs = (u16 *)mclist->dmi_addr;
- writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
+ eaddrs = (__be16 *)mclist->dmi_addr;
+ writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8;
}
- eaddrs = (u16 *)dev->dev_addr;
+ eaddrs = (__be16 *)dev->dev_addr;
while (i++ < 16) {
- writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
+ writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8;
}
rx_mode |= AcceptBroadcast|PerfectFilter;
} else {
/* Must use a multicast hash table. */
void __iomem *filter_addr;
- u16 *eaddrs;
- u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
+ __be16 *eaddrs;
+ __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -1791,17 +1794,17 @@ static void set_rx_mode(struct net_device *dev)
/* The chip uses the upper 9 CRC bits
as index into the hash table */
int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
- __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
+ __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1];
*fptr |= cpu_to_le32(1 << (bit_nr & 31));
}
/* Clear the perfect filter list, skip first two entries. */
filter_addr = ioaddr + PerfFilterTable + 2 * 16;
- eaddrs = (u16 *)dev->dev_addr;
+ eaddrs = (__be16 *)dev->dev_addr;
for (i = 2; i < 16; i++) {
- writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
+ writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8;
}
for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++)
writew(mc_filter[i], filter_addr);
@@ -1904,6 +1907,9 @@ static int netdev_close(struct net_device *dev)
int i;
netif_stop_queue(dev);
+#ifdef HAVE_NETDEV_POLL
+ napi_disable(&np->napi);
+#endif
if (debug > 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n",
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index e6f90427160c..b65be5d70fec 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -112,7 +112,6 @@ static int __init stnic_probe(void)
dev = alloc_ei_netdev();
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_get_node_addr (stnic_eadr);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index b77ab6e8fd35..9b2a7f7bb258 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -311,7 +311,6 @@ struct net_device * __init sun3_82586_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
dev->irq = IE_IRQ;
dev->base_addr = ioaddr;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index f1548c033327..f8d46134daca 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -152,7 +152,6 @@ struct lance_private {
struct lance_memory *mem;
int new_rx, new_tx; /* The next free ring entry */
int old_tx, old_rx; /* ring entry to be processed */
- struct net_device_stats stats;
/* These two must be longs for set_bit() */
long tx_full;
long lock;
@@ -241,7 +240,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
static irqreturn_t lance_interrupt( int irq, void *dev_id);
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
static void set_multicast_list( struct net_device *dev );
/************************* End of Prototypes **************************/
@@ -274,7 +272,6 @@ struct net_device * __init sun3lance_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
if (!lance_probe(dev))
goto out;
@@ -303,6 +300,7 @@ static int __init lance_probe( struct net_device *dev)
static int did_version;
volatile unsigned short *ioaddr_probe;
unsigned short tmp1, tmp2;
+ DECLARE_MAC_BUF(mac);
#ifdef CONFIG_SUN3
ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
@@ -378,8 +376,7 @@ static int __init lance_probe( struct net_device *dev)
MEM->init.hwaddr[4] = dev->dev_addr[5];
MEM->init.hwaddr[5] = dev->dev_addr[4];
- for( i = 0; i < 6; ++i )
- printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+ printk("%s\n", print_mac(mac, dev->dev_addr));
MEM->init.mode = 0x0000;
MEM->init.filter[0] = 0x00000000;
@@ -402,15 +399,12 @@ static int __init lance_probe( struct net_device *dev)
dev->open = &lance_open;
dev->hard_start_xmit = &lance_start_xmit;
dev->stop = &lance_close;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->set_mac_address = NULL;
// KLUDGE -- REMOVE ME
set_bit(__LINK_STATE_PRESENT, &dev->state);
- memset( &lp->stats, 0, sizeof(lp->stats) );
-
return 1;
}
@@ -535,7 +529,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
* little endian mode.
*/
REGA(CSR3) = CSR3_BSWP;
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if(lance_debug >= 2) {
int i;
@@ -596,17 +590,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* Fill in a Tx ring entry */
#if 0
if (lance_debug >= 2) {
- u_char *p;
- int i;
- printk( "%s: TX pkt %d type 0x%04x from ", dev->name,
- lp->new_tx, ((u_short *)skb->data)[6]);
- for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" data at 0x%08x len %d\n", (int)skb->data,
- (int)skb->len );
+ printk( "%s: TX pkt %d type 0x%04x"
+ " from %s to %s"
+ " data at 0x%08x len %d\n",
+ dev->name, lp->new_tx, ((u_short *)skb->data)[6],
+ DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data),
+ (int)skb->data, (int)skb->len );
}
#endif
/* We're not prepared for the int until the last flags are set/reset.
@@ -635,7 +624,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
@@ -713,12 +702,12 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id)
if (head->flag & TMD1_ERR) {
int status = head->misc;
- lp->stats.tx_errors++;
- if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
+ if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
+ if (status & TMD3_LCOL) dev->stats.tx_window_errors++;
if (status & (TMD3_UFLO | TMD3_BUFF)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk("%s: Tx FIFO error\n",
dev->name);
REGA(CSR0) = CSR0_STOP;
@@ -731,9 +720,9 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id)
head->flag &= ~(TMD1_ENP | TMD1_STP);
if(head->flag & (TMD1_ONE | TMD1_MORE))
- lp->stats.collisions++;
+ dev->stats.collisions++;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
DPRINTK(3, ("cleared tx ring %d\n", old_tx));
}
old_tx = (old_tx +1) & TX_RING_MOD_MASK;
@@ -753,8 +742,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id)
lance_rx( dev );
/* Log misc errors. */
- if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
- if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & CSR0_MERR) {
DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
"status %04x.\n", dev->name, csr0 ));
@@ -800,11 +789,11 @@ static int lance_rx( struct net_device *dev )
full-sized buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & RMD1_ENP) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet.*/
- if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
- if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
- if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
- if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++; /* end of a packet.*/
+ if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
+ if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
+ if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
+ if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
head->flag &= (RMD1_ENP|RMD1_STP);
} else {
/* Malloc up new buffer, compatible with net-3. */
@@ -814,7 +803,7 @@ static int lance_rx( struct net_device *dev )
if (pkt_len < 60) {
printk( "%s: Runt packet!\n", dev->name );
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
else {
skb = dev_alloc_skb( pkt_len+2 );
@@ -822,7 +811,7 @@ static int lance_rx( struct net_device *dev )
DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
dev->name ));
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
head->msg_length = 0;
head->flag |= RMD1_OWN_CHIP;
lp->new_rx = (lp->new_rx+1) &
@@ -831,13 +820,14 @@ static int lance_rx( struct net_device *dev )
#if 0
if (lance_debug >= 3) {
- u_char *data = PKTBUF_ADDR(head), *p;
- printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]);
- for( p = &data[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
+ u_char *data = PKTBUF_ADDR(head);
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2)
+ printk("%s: RX pkt %d type 0x%04x"
+ " from %s to %s",
+ dev->name, lp->new_tx, ((u_short *)data)[6],
+ print_mac(mac, &data[6]), print_mac(mac2, data));
+
printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
"len %d at %08x\n",
data[15], data[16], data[17], data[18],
@@ -860,8 +850,8 @@ static int lance_rx( struct net_device *dev )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
}
@@ -898,14 +888,6 @@ static int lance_close( struct net_device *dev )
}
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index b3e0158def4f..fe3ac6f9ae89 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1082,12 +1082,12 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
struct bigmac *bp;
u8 bsizes, bsizes_more;
int i;
+ DECLARE_MAC_BUF(mac);
/* Get a new device struct for this interface. */
dev = alloc_etherdev(sizeof(struct bigmac));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -1227,11 +1227,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
- printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index af0c9831074c..ff98f5d597f1 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -466,8 +466,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
#else
int bar = 1;
#endif
- int phy, phy_idx = 0;
-
+ int phy, phy_end, phy_idx = 0;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -485,7 +485,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*np));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, DRV_NAME))
@@ -547,19 +546,25 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
if (i)
goto err_out_unmap_rx;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
np->phys[0] = 1; /* Default setting */
np->mii_preamble_required++;
+
/*
* It seems some phys doesn't deal well with address 0 being accessed
- * first, so leave address zero to the end of the loop (32 & 31).
+ * first
*/
- for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) {
+ if (sundance_pci_tbl[np->chip_id].device == 0x0200) {
+ phy = 0;
+ phy_end = 31;
+ } else {
+ phy = 1;
+ phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */
+ }
+ for (; phy <= phy_end && phy_idx < MII_CNT; phy++) {
int phyx = phy & 0x1f;
int mii_status = mdio_read(dev, phyx, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) {
@@ -1586,7 +1591,6 @@ static const struct ethtool_ops ethtool_ops = {
.get_link = get_link,
.get_msglevel = get_msglevel,
.set_msglevel = set_msglevel,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 432803855034..53b8344a68ef 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -19,7 +19,7 @@
*
* gem_change_mtu() and gem_set_multicast() are called with a read_lock()
* help by net/core/dev.c, thus they can't schedule. That means they can't
- * call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock
+ * call napi_disable() neither, thus force gem_poll() to keep a spinlock
* where it could have been dropped. change_mtu especially would love also to
* be able to msleep instead of horrid locked delays when resetting the HW,
* but that read_lock() makes it impossible, unless I defer it's action to
@@ -878,19 +878,20 @@ static int gem_rx(struct gem *gp, int work_to_do)
return work_done;
}
-static int gem_poll(struct net_device *dev, int *budget)
+static int gem_poll(struct napi_struct *napi, int budget)
{
- struct gem *gp = dev->priv;
+ struct gem *gp = container_of(napi, struct gem, napi);
+ struct net_device *dev = gp->dev;
unsigned long flags;
+ int work_done;
/*
* NAPI locking nightmare: See comment at head of driver
*/
spin_lock_irqsave(&gp->lock, flags);
+ work_done = 0;
do {
- int work_to_do, work_done;
-
/* Handle anomalies */
if (gp->status & GREG_STAT_ABNORMAL) {
if (gem_abnormal_irq(dev, gp, gp->status))
@@ -906,29 +907,25 @@ static int gem_poll(struct net_device *dev, int *budget)
/* Run RX thread. We don't use any locking here,
* code willing to do bad things - like cleaning the
- * rx ring - must call netif_poll_disable(), which
+ * rx ring - must call napi_disable(), which
* schedule_timeout()'s if polling is already disabled.
*/
- work_to_do = min(*budget, dev->quota);
-
- work_done = gem_rx(gp, work_to_do);
-
- *budget -= work_done;
- dev->quota -= work_done;
+ work_done += gem_rx(gp, budget);
- if (work_done >= work_to_do)
- return 1;
+ if (work_done >= budget)
+ return work_done;
spin_lock_irqsave(&gp->lock, flags);
gp->status = readl(gp->regs + GREG_STAT);
} while (gp->status & GREG_STAT_NAPI);
- __netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
gem_enable_ints(gp);
spin_unlock_irqrestore(&gp->lock, flags);
- return 0;
+
+ return work_done;
}
static irqreturn_t gem_interrupt(int irq, void *dev_id)
@@ -946,17 +943,17 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id)
spin_lock_irqsave(&gp->lock, flags);
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &gp->napi)) {
u32 gem_status = readl(gp->regs + GREG_STAT);
if (gem_status == 0) {
- netif_poll_enable(dev);
+ napi_enable(&gp->napi);
spin_unlock_irqrestore(&gp->lock, flags);
return IRQ_NONE;
}
gp->status = gem_status;
gem_disable_ints(gp);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &gp->napi);
}
spin_unlock_irqrestore(&gp->lock, flags);
@@ -2284,7 +2281,7 @@ static void gem_reset_task(struct work_struct *work)
mutex_lock(&gp->pm_mutex);
- netif_poll_disable(gp->dev);
+ napi_disable(&gp->napi);
spin_lock_irq(&gp->lock);
spin_lock(&gp->tx_lock);
@@ -2307,7 +2304,7 @@ static void gem_reset_task(struct work_struct *work)
spin_unlock(&gp->tx_lock);
spin_unlock_irq(&gp->lock);
- netif_poll_enable(gp->dev);
+ napi_enable(&gp->napi);
mutex_unlock(&gp->pm_mutex);
}
@@ -2324,6 +2321,8 @@ static int gem_open(struct net_device *dev)
if (!gp->asleep)
rc = gem_do_start(dev);
gp->opened = (rc == 0);
+ if (gp->opened)
+ napi_enable(&gp->napi);
mutex_unlock(&gp->pm_mutex);
@@ -2334,9 +2333,7 @@ static int gem_close(struct net_device *dev)
{
struct gem *gp = dev->priv;
- /* Note: we don't need to call netif_poll_disable() here because
- * our caller (dev_close) already did it for us
- */
+ napi_disable(&gp->napi);
mutex_lock(&gp->pm_mutex);
@@ -2358,7 +2355,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
mutex_lock(&gp->pm_mutex);
- netif_poll_disable(dev);
+ napi_disable(&gp->napi);
printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
dev->name,
@@ -2482,7 +2479,7 @@ static int gem_resume(struct pci_dev *pdev)
spin_unlock(&gp->tx_lock);
spin_unlock_irqrestore(&gp->lock, flags);
- netif_poll_enable(dev);
+ napi_enable(&gp->napi);
mutex_unlock(&gp->pm_mutex);
@@ -2968,7 +2965,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
unsigned long gemreg_base, gemreg_len;
struct net_device *dev;
struct gem *gp;
- int i, err, pci_using_dac;
+ int err, pci_using_dac;
+ DECLARE_MAC_BUF(mac);
if (gem_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -3026,7 +3024,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_disable_device;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
gp = dev->priv;
@@ -3121,8 +3118,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
dev->get_stats = gem_get_stats;
dev->set_multicast_list = gem_set_multicast;
dev->do_ioctl = gem_ioctl;
- dev->poll = gem_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &gp->napi, gem_poll, 64);
dev->ethtool_ops = &gem_ethtool_ops;
dev->tx_timeout = gem_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
@@ -3154,12 +3150,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
goto err_out_free_consistent;
}
- printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
- dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet "
+ "%s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1)
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 58cf87c5751e..76d760acc9e2 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -993,6 +993,7 @@ struct gem {
u32 msg_enable;
u32 status;
+ struct napi_struct napi;
struct net_device_stats net_stats;
int tx_fifo_sz;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 8b35f13318ea..120c8affe83d 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2664,6 +2664,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
struct net_device *dev;
int i, qfe_slot = -1;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
if (is_qfe) {
qp = quattro_sbus_find(sdev);
@@ -2680,7 +2681,6 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
dev = alloc_etherdev(sizeof(struct happy_meal));
if (!dev)
goto err_out;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
@@ -2851,10 +2851,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",
- dev->dev_addr[i], i == 5 ? ' ' : ':');
- printk("\n");
+ printk("%s\n", print_mac(mac, dev->dev_addr));
return 0;
@@ -2989,6 +2986,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
int i, qfe_slot = -1;
char prom_name[64];
int err;
+ DECLARE_MAC_BUF(mac);
/* Now make sure pci_dev cookie is there. */
#ifdef CONFIG_SPARC
@@ -3022,7 +3020,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
err = -ENOMEM;
if (!dev)
goto err_out;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (hme_version_printed++ == 0)
@@ -3203,10 +3200,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
- printk("\n");
+ printk("%s\n", print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 053b7cb0d944..26ade68aeabf 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -99,8 +99,7 @@ static char lancestr[] = "LANCE";
#include <asm/byteorder.h> /* Used by the checksum routines */
#include <asm/idprom.h>
#include <asm/sbus.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/auxio.h> /* For tpe-link-test? setting */
#include <asm/irq.h>
@@ -249,7 +248,6 @@ struct lance_private {
int rx_new, tx_new;
int rx_old, tx_old;
- struct net_device_stats stats;
struct sbus_dma *ledma; /* If set this points to ledma */
char tpe; /* cable-selection is TPE */
char auto_select; /* cable-selection by carrier */
@@ -520,17 +518,17 @@ static void lance_rx_dvma(struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (rd->mblength & 0xfff) - 4;
skb = dev_alloc_skb(len + 2);
@@ -538,14 +536,14 @@ static void lance_rx_dvma(struct net_device *dev)
if (skb == NULL) {
printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
lp->rx_new = RX_NEXT(entry);
return;
}
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
@@ -555,7 +553,7 @@ static void lance_rx_dvma(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++;
}
/* Return the packet to the pool */
@@ -587,12 +585,12 @@ static void lance_tx_dvma(struct net_device *dev)
if (bits & LE_T1_ERR) {
u16 status = td->misc;
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
@@ -609,7 +607,7 @@ static void lance_tx_dvma(struct net_device *dev)
* transmitter, restart the adapter.
*/
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -627,13 +625,13 @@ static void lance_tx_dvma(struct net_device *dev)
/* One collision before packet was sent. */
if (bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = TX_NEXT(j);
@@ -693,17 +691,17 @@ static void lance_rx_pio(struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (sbus_readw(&rd->mblength) & 0xfff) - 4;
skb = dev_alloc_skb(len + 2);
@@ -711,14 +709,14 @@ static void lance_rx_pio(struct net_device *dev)
if (skb == NULL) {
printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
sbus_writew(0, &rd->mblength);
sbus_writeb(LE_R1_OWN, &rd->rmd1_bits);
lp->rx_new = RX_NEXT(entry);
return;
}
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb_reserve (skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
@@ -726,7 +724,7 @@ static void lance_rx_pio(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++;
}
/* Return the packet to the pool */
@@ -758,12 +756,12 @@ static void lance_tx_pio(struct net_device *dev)
if (bits & LE_T1_ERR) {
u16 status = sbus_readw(&td->misc);
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
@@ -780,7 +778,7 @@ static void lance_tx_pio(struct net_device *dev)
* transmitter, restart the adapter.
*/
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -798,13 +796,13 @@ static void lance_tx_pio(struct net_device *dev)
/* One collision before packet was sent. */
if (bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = TX_NEXT(j);
@@ -845,10 +843,10 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id)
lp->tx(dev);
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (csr0 & LE_C0_MERR) {
if (lp->dregs) {
@@ -1128,7 +1126,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&lp->lock);
- lp->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
entry = lp->tx_new & TX_RING_MOD_MASK;
if (lp->pio_buffer) {
@@ -1171,13 +1169,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* taken from the depca driver */
static void lance_load_multicast(struct net_device *dev)
{
@@ -1326,16 +1317,17 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
struct sbus_dev *lebuffer)
{
static unsigned version_printed;
+ struct device_node *dp = sdev->ofdev.node;
struct net_device *dev;
struct lance_private *lp;
int i;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct lance_private) + 8);
if (!dev)
return -ENOMEM;
lp = netdev_priv(dev);
- memset(lp, 0, sizeof(*lp));
if (sparc_lance_debug && version_printed++ == 0)
printk (KERN_INFO "%s", version);
@@ -1389,54 +1381,46 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
lp->rx = lance_rx_dvma;
lp->tx = lance_tx_dvma;
}
- lp->busmaster_regval = prom_getintdefault(sdev->prom_node,
- "busmaster-regval",
- (LE_C3_BSWP | LE_C3_ACON |
- LE_C3_BCON));
+ lp->busmaster_regval = of_getintprop_default(dp, "busmaster-regval",
+ (LE_C3_BSWP |
+ LE_C3_ACON |
+ LE_C3_BCON));
lp->name = lancestr;
lp->ledma = ledma;
lp->burst_sizes = 0;
if (lp->ledma) {
- char prop[6];
+ struct device_node *ledma_dp = ledma->sdev->ofdev.node;
+ const char *prop;
unsigned int sbmask;
u32 csr;
/* Find burst-size property for ledma */
- lp->burst_sizes = prom_getintdefault(ledma->sdev->prom_node,
- "burst-sizes", 0);
+ lp->burst_sizes = of_getintprop_default(ledma_dp,
+ "burst-sizes", 0);
/* ledma may be capable of fast bursts, but sbus may not. */
- sbmask = prom_getintdefault(ledma->sdev->bus->prom_node,
- "burst-sizes", DMA_BURSTBITS);
+ sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+ DMA_BURSTBITS);
lp->burst_sizes &= sbmask;
/* Get the cable-selection property */
- memset(prop, 0, sizeof(prop));
- prom_getstring(ledma->sdev->prom_node, "cable-selection",
- prop, sizeof(prop));
- if (prop[0] == 0) {
- int topnd, nd;
+ prop = of_get_property(ledma_dp, "cable-selection", NULL);
+ if (!prop || prop[0] == '\0') {
+ struct device_node *nd;
- printk(KERN_INFO "SunLance: using auto-carrier-detection.\n");
+ printk(KERN_INFO "SunLance: using "
+ "auto-carrier-detection.\n");
- /* Is this found at /options .attributes in all
- * Prom versions? XXX
- */
- topnd = prom_getchild(prom_root_node);
-
- nd = prom_searchsiblings(topnd, "options");
+ nd = of_find_node_by_path("/options");
if (!nd)
goto no_link_test;
- if (!prom_node_has_property(nd, "tpe-link-test?"))
+ prop = of_get_property(nd, "tpe-link-test?", NULL);
+ if (!prop)
goto no_link_test;
- memset(prop, 0, sizeof(prop));
- prom_getstring(nd, "tpe-link-test?", prop,
- sizeof(prop));
-
if (strcmp(prop, "true")) {
printk(KERN_NOTICE "SunLance: warning: overriding option "
"'tpe-link-test?'\n");
@@ -1466,14 +1450,12 @@ no_link_test:
lp->dregs = NULL;
lp->dev = dev;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
dev->tx_timeout = &lance_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->ethtool_ops = &sparc_lance_ethtool_ops;
@@ -1497,12 +1479,8 @@ no_link_test:
dev_set_drvdata(&sdev->ofdev.dev, lp);
- printk(KERN_INFO "%s: LANCE ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ': ':');
- printk("\n");
+ printk(KERN_INFO "%s: LANCE %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 1b65ae8a1c7c..ff23c6489efd 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -260,31 +260,31 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status)
if (qe_status & CREG_STAT_EDEFER) {
printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
}
if (qe_status & CREG_STAT_CLOSS) {
printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (qe_status & CREG_STAT_ERETRIES) {
printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_LCOLL) {
printk(KERN_ERR "%s: Late transmit collision.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.collisions++;
+ dev->stats.tx_errors++;
+ dev->stats.collisions++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_FUFLOW) {
printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
mace_hwbug_workaround = 1;
}
@@ -297,104 +297,104 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status)
}
if (qe_status & CREG_STAT_CCOFLOW) {
- qep->net_stats.tx_errors += 256;
- qep->net_stats.collisions += 256;
+ dev->stats.tx_errors += 256;
+ dev->stats.collisions += 256;
}
if (qe_status & CREG_STAT_TXDERROR) {
printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_TXLERR) {
printk(KERN_ERR "%s: Transmit late error.\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_TXPERR) {
printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_TXSERR) {
printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_RCCOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.collisions += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.collisions += 256;
}
if (qe_status & CREG_STAT_RUOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_over_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_over_errors += 256;
}
if (qe_status & CREG_STAT_MCOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_missed_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_missed_errors += 256;
}
if (qe_status & CREG_STAT_RXFOFLOW) {
printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_over_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
}
if (qe_status & CREG_STAT_RLCOLL) {
printk(KERN_ERR "%s: Late receive collision.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.collisions++;
+ dev->stats.rx_errors++;
+ dev->stats.collisions++;
}
if (qe_status & CREG_STAT_FCOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_frame_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_frame_errors += 256;
}
if (qe_status & CREG_STAT_CECOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_crc_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_crc_errors += 256;
}
if (qe_status & CREG_STAT_RXDROP) {
printk(KERN_ERR "%s: Receive packet dropped.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_dropped++;
- qep->net_stats.rx_missed_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
+ dev->stats.rx_missed_errors++;
}
if (qe_status & CREG_STAT_RXSMALL) {
printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
}
if (qe_status & CREG_STAT_RXLERR) {
printk(KERN_ERR "%s: Receive late error.\n", dev->name);
- qep->net_stats.rx_errors++;
+ dev->stats.rx_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_RXPERR) {
printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_missed_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_missed_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_RXSERR) {
printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_missed_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_missed_errors++;
mace_hwbug_workaround = 1;
}
@@ -409,6 +409,7 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status)
static void qe_rx(struct sunqe *qep)
{
struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
+ struct net_device *dev = qep->dev;
struct qe_rxd *this;
struct sunqe_buffers *qbufs = qep->buffers;
__u32 qbufs_dvma = qep->buffers_dvma;
@@ -428,14 +429,14 @@ static void qe_rx(struct sunqe *qep)
/* Check for errors. */
if (len < ETH_ZLEN) {
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_length_errors++;
- qep->net_stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ dev->stats.rx_dropped++;
} else {
skb = dev_alloc_skb(len + 2);
if (skb == NULL) {
drops++;
- qep->net_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
skb_reserve(skb, 2);
skb_put(skb, len);
@@ -444,8 +445,8 @@ static void qe_rx(struct sunqe *qep)
skb->protocol = eth_type_trans(skb, qep->dev);
netif_rx(skb);
qep->dev->last_rx = jiffies;
- qep->net_stats.rx_packets++;
- qep->net_stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
}
end_rxd->rx_addr = this_qbuf_dvma;
@@ -603,8 +604,8 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL);
- qep->net_stats.tx_packets++;
- qep->net_stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
if (TX_BUFFS_AVAIL(qep) <= 0) {
/* Halt the net queue and enable tx interrupts.
@@ -622,13 +623,6 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *qe_get_stats(struct net_device *dev)
-{
- struct sunqe *qep = (struct sunqe *) dev->priv;
-
- return &qep->net_stats;
-}
-
static void qe_set_multicast(struct net_device *dev)
{
struct sunqe *qep = (struct sunqe *) dev->priv;
@@ -898,13 +892,11 @@ static int __init qec_ether_init(struct sbus_dev *sdev)
/* Stop this QE. */
qe_stop(qe);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = qe_open;
dev->stop = qe_close;
dev->hard_start_xmit = qe_start_xmit;
- dev->get_stats = qe_get_stats;
dev->set_multicast_list = qe_set_multicast;
dev->tx_timeout = qe_tx_timeout;
dev->watchdog_timeo = 5*HZ;
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index af34f36111ed..347c8ddc1592 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -342,7 +342,6 @@ struct sunqe {
__u32 buffers_dvma; /* DVMA visible address. */
struct sunqec *parent;
u8 mconfig; /* Base MACE mconfig value */
- struct net_device_stats net_stats; /* Statistical counters */
struct sbus_dev *qe_sdev; /* QE's SBUS device struct */
struct net_device *dev; /* QE's netdevice struct */
int channel; /* Who am I? */
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 8a667c13faef..ff1028a597df 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -12,6 +12,7 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
+#include <linux/mutex.h>
#include <asm/vio.h>
#include <asm/ldc.h>
@@ -458,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf)
return 0;
}
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+ struct vio_net_mcast_info *pkt = msgbuf;
+
+ if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+ printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+ "[%02x:%02x:%04x:%08x]\n",
+ port->vp->dev->name,
+ pkt->tag.type,
+ pkt->tag.stype,
+ pkt->tag.stype_env,
+ pkt->tag.sid);
+
+ return 0;
+}
+
static void maybe_tx_wakeup(struct vnet *vp)
{
struct net_device *dev = vp->dev;
@@ -497,6 +514,8 @@ static void vnet_event(void *arg, int event)
vio_link_state_change(vio, event);
spin_unlock_irqrestore(&vio->lock, flags);
+ if (event == LDC_EVENT_RESET)
+ vio_port_up(vio);
return;
}
@@ -541,7 +560,10 @@ static void vnet_event(void *arg, int event)
err = vnet_nack(port, &msgbuf);
}
} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
- err = vio_control_pkt_engine(vio, &msgbuf);
+ if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+ err = handle_mcast(port, &msgbuf);
+ else
+ err = vio_control_pkt_engine(vio, &msgbuf);
if (err)
break;
} else {
@@ -728,9 +750,122 @@ static int vnet_close(struct net_device *dev)
return 0;
}
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+ struct vnet_mcast_entry *m;
+
+ for (m = vp->mcast_list; m; m = m->next) {
+ if (!memcmp(m->addr, addr, ETH_ALEN))
+ return m;
+ }
+ return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+ struct dev_addr_list *p;
+
+ for (p = dev->mc_list; p; p = p->next) {
+ struct vnet_mcast_entry *m;
+
+ m = __vnet_mc_find(vp, p->dmi_addr);
+ if (m) {
+ m->hit = 1;
+ continue;
+ }
+
+ if (!m) {
+ m = kzalloc(sizeof(*m), GFP_ATOMIC);
+ if (!m)
+ continue;
+ memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+ m->hit = 1;
+
+ m->next = vp->mcast_list;
+ vp->mcast_list = m;
+ }
+ }
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+ struct vio_net_mcast_info info;
+ struct vnet_mcast_entry *m, **pp;
+ int n_addrs;
+
+ memset(&info, 0, sizeof(info));
+
+ info.tag.type = VIO_TYPE_CTRL;
+ info.tag.stype = VIO_SUBTYPE_INFO;
+ info.tag.stype_env = VNET_MCAST_INFO;
+ info.tag.sid = vio_send_sid(&port->vio);
+ info.set = 1;
+
+ n_addrs = 0;
+ for (m = vp->mcast_list; m; m = m->next) {
+ if (m->sent)
+ continue;
+ m->sent = 1;
+ memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+ m->addr, ETH_ALEN);
+ if (++n_addrs == VNET_NUM_MCAST) {
+ info.count = n_addrs;
+
+ (void) vio_ldc_send(&port->vio, &info,
+ sizeof(info));
+ n_addrs = 0;
+ }
+ }
+ if (n_addrs) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+ }
+
+ info.set = 0;
+
+ n_addrs = 0;
+ pp = &vp->mcast_list;
+ while ((m = *pp) != NULL) {
+ if (m->hit) {
+ m->hit = 0;
+ pp = &m->next;
+ continue;
+ }
+
+ memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+ m->addr, ETH_ALEN);
+ if (++n_addrs == VNET_NUM_MCAST) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info,
+ sizeof(info));
+ n_addrs = 0;
+ }
+
+ *pp = m->next;
+ kfree(m);
+ }
+ if (n_addrs) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+ }
+}
+
static void vnet_set_rx_mode(struct net_device *dev)
{
- /* XXX Implement multicast support XXX */
+ struct vnet *vp = netdev_priv(dev);
+ struct vnet_port *port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp->lock, flags);
+ if (!list_empty(&vp->port_list)) {
+ port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+ if (port->switch_port) {
+ __update_mc_list(vp, dev);
+ __send_mc_list(vp, port);
+ }
+ }
+ spin_unlock_irqrestore(&vp->lock, flags);
}
static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -771,7 +906,6 @@ static const struct ethtool_ops vnet_ethtool_ops = {
.get_msglevel = vnet_get_msglevel,
.set_msglevel = vnet_set_msglevel,
.get_link = ethtool_op_get_link,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static void vnet_port_free_tx_bufs(struct vnet_port *port)
@@ -875,6 +1009,115 @@ err_out:
return err;
}
+static LIST_HEAD(vnet_list);
+static DEFINE_MUTEX(vnet_list_mutex);
+
+static struct vnet * __devinit vnet_new(const u64 *local_mac)
+{
+ struct net_device *dev;
+ struct vnet *vp;
+ int err, i;
+
+ dev = alloc_etherdev(sizeof(*vp));
+ if (!dev) {
+ printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ vp = netdev_priv(dev);
+
+ spin_lock_init(&vp->lock);
+ vp->dev = dev;
+
+ INIT_LIST_HEAD(&vp->port_list);
+ for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&vp->port_hash[i]);
+ INIT_LIST_HEAD(&vp->list);
+ vp->local_mac = *local_mac;
+
+ dev->open = vnet_open;
+ dev->stop = vnet_close;
+ dev->set_multicast_list = vnet_set_rx_mode;
+ dev->set_mac_address = vnet_set_mac_addr;
+ dev->tx_timeout = vnet_tx_timeout;
+ dev->ethtool_ops = &vnet_ethtool_ops;
+ dev->watchdog_timeo = VNET_TX_TIMEOUT;
+ dev->change_mtu = vnet_change_mtu;
+ dev->hard_start_xmit = vnet_start_xmit;
+
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_dev;
+ }
+
+ printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+ list_add(&vp->list, &vnet_list);
+
+ return vp;
+
+err_out_free_dev:
+ free_netdev(dev);
+
+ return ERR_PTR(err);
+}
+
+static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
+{
+ struct vnet *iter, *vp;
+
+ mutex_lock(&vnet_list_mutex);
+ vp = NULL;
+ list_for_each_entry(iter, &vnet_list, list) {
+ if (iter->local_mac == *local_mac) {
+ vp = iter;
+ break;
+ }
+ }
+ if (!vp)
+ vp = vnet_new(local_mac);
+ mutex_unlock(&vnet_list_mutex);
+
+ return vp;
+}
+
+static const char *local_mac_prop = "local-mac-address";
+
+static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
+ u64 port_node)
+{
+ const u64 *local_mac = NULL;
+ u64 a;
+
+ mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
+ u64 target = mdesc_arc_target(hp, a);
+ const char *name;
+
+ name = mdesc_get_property(hp, target, "name", NULL);
+ if (!name || strcmp(name, "network"))
+ continue;
+
+ local_mac = mdesc_get_property(hp, target,
+ local_mac_prop, NULL);
+ if (local_mac)
+ break;
+ }
+ if (!local_mac)
+ return ERR_PTR(-ENODEV);
+
+ return vnet_find_or_create(local_mac);
+}
+
static struct ldc_channel_config vnet_ldc_cfg = {
.event = vnet_event,
.mtu = 64,
@@ -887,6 +1130,14 @@ static struct vio_driver_ops vnet_vio_ops = {
.handshake_complete = vnet_handshake_complete,
};
+static void print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
const char *remote_macaddr_prop = "remote-mac-address";
static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1150,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
const u64 *rmac;
int len, i, err, switch_port;
- vp = dev_get_drvdata(vdev->dev.parent);
- if (!vp) {
- printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
- return -ENODEV;
- }
+ print_version();
hp = mdesc_grab();
+ vp = vnet_find_parent(hp, vdev->mp);
+ if (IS_ERR(vp)) {
+ printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+ err = PTR_ERR(vp);
+ goto err_out_put_mdesc;
+ }
+
rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
err = -ENODEV;
if (!rmac) {
@@ -947,6 +1201,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
switch_port = 0;
if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
switch_port = 1;
+ port->switch_port = switch_port;
spin_lock_irqsave(&vp->lock, flags);
if (switch_port)
@@ -1013,7 +1268,7 @@ static struct vio_device_id vnet_port_match[] = {
},
{},
};
-MODULE_DEVICE_TABLE(vio, vnet_match);
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
static struct vio_driver vnet_port_driver = {
.id_table = vnet_port_match,
@@ -1025,139 +1280,14 @@ static struct vio_driver vnet_port_driver = {
}
};
-const char *local_mac_prop = "local-mac-address";
-
-static int __devinit vnet_probe(struct vio_dev *vdev,
- const struct vio_device_id *id)
-{
- static int vnet_version_printed;
- struct mdesc_handle *hp;
- struct net_device *dev;
- struct vnet *vp;
- const u64 *mac;
- int err, i, len;
-
- if (vnet_version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-
- hp = mdesc_grab();
-
- mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
- if (!mac) {
- printk(KERN_ERR PFX "vnet lacks %s property.\n",
- local_mac_prop);
- err = -ENODEV;
- goto err_out;
- }
-
- dev = alloc_etherdev(sizeof(*vp));
- if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
- err = -ENOMEM;
- goto err_out;
- }
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
-
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
- SET_NETDEV_DEV(dev, &vdev->dev);
-
- vp = netdev_priv(dev);
-
- spin_lock_init(&vp->lock);
- vp->dev = dev;
- vp->vdev = vdev;
-
- INIT_LIST_HEAD(&vp->port_list);
- for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
- INIT_HLIST_HEAD(&vp->port_hash[i]);
-
- dev->open = vnet_open;
- dev->stop = vnet_close;
- dev->set_multicast_list = vnet_set_rx_mode;
- dev->set_mac_address = vnet_set_mac_addr;
- dev->tx_timeout = vnet_tx_timeout;
- dev->ethtool_ops = &vnet_ethtool_ops;
- dev->watchdog_timeo = VNET_TX_TIMEOUT;
- dev->change_mtu = vnet_change_mtu;
- dev->hard_start_xmit = vnet_start_xmit;
-
- err = register_netdev(dev);
- if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
- goto err_out_free_dev;
- }
-
- printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
- dev_set_drvdata(&vdev->dev, vp);
-
- mdesc_release(hp);
-
- return 0;
-
-err_out_free_dev:
- free_netdev(dev);
-
-err_out:
- mdesc_release(hp);
- return err;
-}
-
-static int vnet_remove(struct vio_dev *vdev)
-{
-
- struct vnet *vp = dev_get_drvdata(&vdev->dev);
-
- if (vp) {
- /* XXX unregister port, or at least check XXX */
- unregister_netdevice(vp->dev);
- dev_set_drvdata(&vdev->dev, NULL);
- }
- return 0;
-}
-
-static struct vio_device_id vnet_match[] = {
- {
- .type = "network",
- },
- {},
-};
-MODULE_DEVICE_TABLE(vio, vnet_match);
-
-static struct vio_driver vnet_driver = {
- .id_table = vnet_match,
- .probe = vnet_probe,
- .remove = vnet_remove,
- .driver = {
- .name = "vnet",
- .owner = THIS_MODULE,
- }
-};
-
static int __init vnet_init(void)
{
- int err = vio_register_driver(&vnet_driver);
-
- if (!err) {
- err = vio_register_driver(&vnet_port_driver);
- if (err)
- vio_unregister_driver(&vnet_driver);
- }
-
- return err;
+ return vio_register_driver(&vnet_port_driver);
}
static void __exit vnet_exit(void)
{
vio_unregister_driver(&vnet_port_driver);
- vio_unregister_driver(&vnet_driver);
}
module_init(vnet_init);
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 1c887302d46d..d347a5bf24b0 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -30,6 +30,8 @@ struct vnet_port {
struct hlist_node hash;
u8 raddr[ETH_ALEN];
+ u8 switch_port;
+ u8 __pad;
struct vnet *vp;
@@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac)
return val & (VNET_PORT_HASH_MASK);
}
+struct vnet_mcast_entry {
+ u8 addr[ETH_ALEN];
+ u8 sent;
+ u8 hit;
+ struct vnet_mcast_entry *next;
+};
+
struct vnet {
/* Protects port_list and port_hash. */
spinlock_t lock;
@@ -60,11 +69,15 @@ struct vnet {
struct net_device *dev;
u32 msg_enable;
- struct vio_dev *vdev;
struct list_head port_list;
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
+
+ struct vnet_mcast_entry *mcast_list;
+
+ struct list_head list;
+ u64 local_mac;
};
#endif /* _SUNVNET_H */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 75655add3f34..a679f4310ce1 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -414,6 +414,9 @@ enum tc35815_timer_state {
struct tc35815_local {
struct pci_dev *pci_dev;
+ struct net_device *dev;
+ struct napi_struct napi;
+
/* statistics */
struct net_device_stats stats;
struct {
@@ -566,7 +569,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
#ifdef TC35815_NAPI
static int tc35815_rx(struct net_device *dev, int limit);
-static int tc35815_poll(struct net_device *dev, int *budget);
+static int tc35815_poll(struct napi_struct *napi, int budget);
#else
static void tc35815_rx(struct net_device *dev);
#endif
@@ -626,7 +629,7 @@ static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
return -ENODEV;
}
#else
-static int __devinit tc35815_read_plat_dev_addr(struct device *dev)
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
{
return -ENODEV;
}
@@ -682,9 +685,9 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
dev_err(&pdev->dev, "unable to alloc new ethernet\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
lp = dev->priv;
+ lp->dev = dev;
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device (pdev);
@@ -738,8 +741,7 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
dev->tx_timeout = tc35815_tx_timeout;
dev->watchdog_timeo = TC35815_TX_TIMEOUT;
#ifdef TC35815_NAPI
- dev->poll = tc35815_poll;
- dev->weight = NAPI_WEIGHT;
+ netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = tc35815_poll_controller;
@@ -748,8 +750,6 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
- /* dev->priv/lp zeroed and aligned in alloc_etherdev */
- lp = dev->priv;
spin_lock_init(&lp->lock);
lp->pci_dev = pdev;
lp->boardtype = ent->driver_data;
@@ -1237,6 +1237,10 @@ tc35815_open(struct net_device *dev)
return -EAGAIN;
}
+#ifdef TC35815_NAPI
+ napi_enable(&lp->napi);
+#endif
+
/* Reset the hardware here. Don't forget to set the station address. */
spin_lock_irq(&lp->lock);
tc35815_chip_init(dev);
@@ -1436,6 +1440,7 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status)
static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
+ struct tc35815_local *lp = netdev_priv(dev);
struct tc35815_regs __iomem *tr =
(struct tc35815_regs __iomem *)dev->base_addr;
#ifdef TC35815_NAPI
@@ -1444,8 +1449,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
if (!(dmactl & DMA_IntMask)) {
/* disable interrupts */
tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
- if (netif_rx_schedule_prep(dev))
- __netif_rx_schedule(dev);
+ if (netif_rx_schedule_prep(dev, &lp->napi))
+ __netif_rx_schedule(dev, &lp->napi);
else {
printk(KERN_ERR "%s: interrupt taken in poll\n",
dev->name);
@@ -1726,13 +1731,12 @@ tc35815_rx(struct net_device *dev)
}
#ifdef TC35815_NAPI
-static int
-tc35815_poll(struct net_device *dev, int *budget)
+static int tc35815_poll(struct napi_struct *napi, int budget)
{
- struct tc35815_local *lp = dev->priv;
+ struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);
+ struct net_device *dev = lp->dev;
struct tc35815_regs __iomem *tr =
(struct tc35815_regs __iomem *)dev->base_addr;
- int limit = min(*budget, dev->quota);
int received = 0, handled;
u32 status;
@@ -1744,23 +1748,19 @@ tc35815_poll(struct net_device *dev, int *budget)
handled = tc35815_do_interrupt(dev, status, limit);
if (handled >= 0) {
received += handled;
- limit -= handled;
- if (limit <= 0)
+ if (received >= budget)
break;
}
status = tc_readl(&tr->Int_Src);
} while (status);
spin_unlock(&lp->lock);
- dev->quota -= received;
- *budget -= received;
- if (limit <= 0)
- return 1;
-
- netif_rx_complete(dev);
- /* enable interrupts */
- tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
- return 0;
+ if (received < budget) {
+ netif_rx_complete(dev, napi);
+ /* enable interrupts */
+ tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+ }
+ return received;
}
#endif
@@ -1949,7 +1949,11 @@ static int
tc35815_close(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
+
netif_stop_queue(dev);
+#ifdef TC35815_NAPI
+ napi_disable(&lp->napi);
+#endif
/* Flush the Tx and disable Rx here. */
@@ -2158,10 +2162,16 @@ static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
lp->msg_enable = datum;
}
-static int tc35815_get_stats_count(struct net_device *dev)
+static int tc35815_get_sset_count(struct net_device *dev, int sset)
{
struct tc35815_local *lp = dev->priv;
- return sizeof(lp->lstats) / sizeof(int);
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ return sizeof(lp->lstats) / sizeof(int);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
@@ -2196,9 +2206,8 @@ static const struct ethtool_ops tc35815_ethtool_ops = {
.get_msglevel = tc35815_get_msglevel,
.set_msglevel = tc35815_set_msglevel,
.get_strings = tc35815_get_strings,
- .get_stats_count = tc35815_get_stats_count,
+ .get_sset_count = tc35815_get_sset_count,
.get_ethtool_stats = tc35815_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
new file mode 100644
index 000000000000..8d04654f0c59
--- /dev/null
+++ b/drivers/net/tehuti.c
@@ -0,0 +1,2506 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * ethtool interface implementation
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * RX HW/SW interaction overview
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * There are 2 types of RX communication channels betwean driver and NIC.
+ * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming
+ * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds
+ * info about buffer's location, size and ID. An ID field is used to identify a
+ * buffer when it's returned with data via RXD Fifo (see below)
+ * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is
+ * filled by HW and is readen by SW. Each descriptor holds status and ID.
+ * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data,
+ * via dma moves it into host memory, builds new RXD descriptor with same ID,
+ * pushes it into RXD Fifo and raises interrupt to indicate new RX data.
+ *
+ * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos.
+ * One holds 1.5K packets and another - 26K packets. Depending on incoming
+ * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is
+ * filled with data, HW builds new RXD descriptor for it and push it into single
+ * RXD Fifo.
+ *
+ * RX SW Data Structures
+ * ~~~~~~~~~~~~~~~~~~~~~
+ * skb db - used to keep track of all skbs owned by SW and their dma addresses.
+ * For RX case, ownership lasts from allocating new empty skb for RXF until
+ * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own
+ * skb db. Implemented as array with bitmask.
+ * fifo - keeps info about fifo's size and location, relevant HW registers,
+ * usage and skb db. Each RXD and RXF Fifo has its own fifo structure.
+ * Implemented as simple struct.
+ *
+ * RX SW Execution Flow
+ * ~~~~~~~~~~~~~~~~~~~~
+ * Upon initialization (ifconfig up) driver creates RX fifos and initializes
+ * relevant registers. At the end of init phase, driver enables interrupts.
+ * NIC sees that there is no RXF buffers and raises
+ * RD_INTR interrupt, isr fills skbs and Rx begins.
+ * Driver has two receive operation modes:
+ * NAPI - interrupt-driven mixed with polling
+ * interrupt-driven only
+ *
+ * Interrupt-driven only flow is following. When buffer is ready, HW raises
+ * interrupt and isr is called. isr collects all available packets
+ * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit.
+
+ * Rx buffer allocation note
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Driver cares to feed such amount of RxF descriptors that respective amount of
+ * RxD descriptors can not fill entire RxD fifo. The main reason is lack of
+ * overflow check in Bordeaux for RxD fifo free/used size.
+ * FIXME: this is NOT fully implemented, more work should be done
+ *
+ */
+
+#include "tehuti.h"
+#include "tehuti_fw.h"
+
+static struct pci_device_id __devinitdata bdx_pci_tbl[] = {
+ {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, bdx_pci_tbl);
+
+/* Definitions needed by ISR or NAPI functions */
+static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f);
+static void bdx_tx_cleanup(struct bdx_priv *priv);
+static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget);
+
+/* Definitions needed by FW loading */
+static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size);
+
+/* Definitions needed by hw_start */
+static int bdx_tx_init(struct bdx_priv *priv);
+static int bdx_rx_init(struct bdx_priv *priv);
+
+/* Definitions needed by bdx_close */
+static void bdx_rx_free(struct bdx_priv *priv);
+static void bdx_tx_free(struct bdx_priv *priv);
+
+/* Definitions needed by bdx_probe */
+static void bdx_ethtool_ops(struct net_device *netdev);
+
+/*************************************************************************
+ * Print Info *
+ *************************************************************************/
+
+static void print_hw_id(struct pci_dev *pdev)
+{
+ struct pci_nic *nic = pci_get_drvdata(pdev);
+ u16 pci_link_status = 0;
+ u16 pci_ctrl = 0;
+
+ pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status);
+ pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl);
+
+ printk(KERN_INFO "tehuti: %s%s\n", BDX_NIC_NAME,
+ nic->port_num == 1 ? "" : ", 2-Port");
+ printk(KERN_INFO
+ "tehuti: srom 0x%x fpga %d build %u lane# %d"
+ " max_pl 0x%x mrrs 0x%x\n",
+ readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF,
+ readl(nic->regs + FPGA_SEED),
+ GET_LINK_STATUS_LANES(pci_link_status),
+ GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl));
+}
+
+static void print_fw_id(struct pci_nic *nic)
+{
+ printk(KERN_INFO "tehuti: fw 0x%x\n", readl(nic->regs + FW_VER));
+}
+
+static void print_eth_id(struct net_device *ndev)
+{
+ printk(KERN_INFO "%s: %s, Port %c\n", ndev->name, BDX_NIC_NAME,
+ (ndev->if_port == 0) ? 'A' : 'B');
+
+}
+
+/*************************************************************************
+ * Code *
+ *************************************************************************/
+
+#define bdx_enable_interrupts(priv) \
+ do { WRITE_REG(priv, regIMR, IR_RUN); } while (0)
+#define bdx_disable_interrupts(priv) \
+ do { WRITE_REG(priv, regIMR, 0); } while (0)
+
+/* bdx_fifo_init
+ * create TX/RX descriptor fifo for host-NIC communication.
+ * 1K extra space is allocated at the end of the fifo to simplify
+ * processing of descriptors that wraps around fifo's end
+ * @priv - NIC private structure
+ * @f - fifo to initialize
+ * @fsz_type - fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB
+ * @reg_XXX - offsets of registers relative to base address
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ */
+static int
+bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type,
+ u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR)
+{
+ u16 memsz = FIFO_SIZE * (1 << fsz_type);
+
+ memset(f, 0, sizeof(struct fifo));
+ /* pci_alloc_consistent gives us 4k-aligned memory */
+ f->va = pci_alloc_consistent(priv->pdev,
+ memsz + FIFO_EXTRA_SPACE, &f->da);
+ if (!f->va) {
+ ERR("pci_alloc_consistent failed\n");
+ RET(-ENOMEM);
+ }
+ f->reg_CFG0 = reg_CFG0;
+ f->reg_CFG1 = reg_CFG1;
+ f->reg_RPTR = reg_RPTR;
+ f->reg_WPTR = reg_WPTR;
+ f->rptr = 0;
+ f->wptr = 0;
+ f->memsz = memsz;
+ f->size_mask = memsz - 1;
+ WRITE_REG(priv, reg_CFG0, (u32) ((f->da & TX_RX_CFG0_BASE) | fsz_type));
+ WRITE_REG(priv, reg_CFG1, H32_64(f->da));
+
+ RET(0);
+}
+
+/* bdx_fifo_free - free all resources used by fifo
+ * @priv - NIC private structure
+ * @f - fifo to release
+ */
+static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f)
+{
+ ENTER;
+ if (f->va) {
+ pci_free_consistent(priv->pdev,
+ f->memsz + FIFO_EXTRA_SPACE, f->va, f->da);
+ f->va = NULL;
+ }
+ RET();
+}
+
+/*
+ * bdx_link_changed - notifies OS about hw link state.
+ * @bdx_priv - hw adapter structure
+ */
+static void bdx_link_changed(struct bdx_priv *priv)
+{
+ u32 link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT;
+
+ if (!link) {
+ if (netif_carrier_ok(priv->ndev)) {
+ netif_stop_queue(priv->ndev);
+ netif_carrier_off(priv->ndev);
+ ERR("%s: Link Down\n", priv->ndev->name);
+ }
+ } else {
+ if (!netif_carrier_ok(priv->ndev)) {
+ netif_wake_queue(priv->ndev);
+ netif_carrier_on(priv->ndev);
+ ERR("%s: Link Up\n", priv->ndev->name);
+ }
+ }
+}
+
+static void bdx_isr_extra(struct bdx_priv *priv, u32 isr)
+{
+ if (isr & IR_RX_FREE_0) {
+ bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+ DBG("RX_FREE_0\n");
+ }
+
+ if (isr & IR_LNKCHG0)
+ bdx_link_changed(priv);
+
+ if (isr & IR_PCIE_LINK)
+ ERR("%s: PCI-E Link Fault\n", priv->ndev->name);
+
+ if (isr & IR_PCIE_TOUT)
+ ERR("%s: PCI-E Time Out\n", priv->ndev->name);
+
+}
+
+/* bdx_isr - Interrupt Service Routine for Bordeaux NIC
+ * @irq - interrupt number
+ * @ndev - network device
+ * @regs - CPU registers
+ *
+ * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise
+ *
+ * It reads ISR register to know interrupt reasons, and proceed them one by one.
+ * Reasons of interest are:
+ * RX_DESC - new packet has arrived and RXD fifo holds its descriptor
+ * RX_FREE - number of free Rx buffers in RXF fifo gets low
+ * TX_FREE - packet was transmited and RXF fifo holds its descriptor
+ */
+
+static irqreturn_t bdx_isr_napi(int irq, void *dev)
+{
+ struct net_device *ndev = dev;
+ struct bdx_priv *priv = ndev->priv;
+ u32 isr;
+
+ ENTER;
+ isr = (READ_REG(priv, regISR) & IR_RUN);
+ if (unlikely(!isr)) {
+ bdx_enable_interrupts(priv);
+ return IRQ_NONE; /* Not our interrupt */
+ }
+
+ if (isr & IR_EXTRA)
+ bdx_isr_extra(priv, isr);
+
+ if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) {
+ if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) {
+ __netif_rx_schedule(ndev, &priv->napi);
+ RET(IRQ_HANDLED);
+ } else {
+ /* NOTE: we get here if intr has slipped into window
+ * between these lines in bdx_poll:
+ * bdx_enable_interrupts(priv);
+ * return 0;
+ * currently intrs are disabled (since we read ISR),
+ * and we have failed to register next poll.
+ * so we read the regs to trigger chip
+ * and allow further interupts. */
+ READ_REG(priv, regTXF_WPTR_0);
+ READ_REG(priv, regRXD_WPTR_0);
+ }
+ }
+
+ bdx_enable_interrupts(priv);
+ RET(IRQ_HANDLED);
+}
+
+static int bdx_poll(struct napi_struct *napi, int budget)
+{
+ struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi);
+ struct net_device *dev = priv->ndev;
+ int work_done;
+
+ ENTER;
+ bdx_tx_cleanup(priv);
+ work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget);
+ if ((work_done < budget) ||
+ (priv->napi_stop++ >= 30)) {
+ DBG("rx poll is done. backing to isr-driven\n");
+
+ /* from time to time we exit to let NAPI layer release
+ * device lock and allow waiting tasks (eg rmmod) to advance) */
+ priv->napi_stop = 0;
+
+ netif_rx_complete(dev, napi);
+ bdx_enable_interrupts(priv);
+ }
+ return work_done;
+}
+
+/* bdx_fw_load - loads firmware to NIC
+ * @priv - NIC private structure
+ * Firmware is loaded via TXD fifo, so it must be initialized first.
+ * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC
+ * can have few of them). So all drivers use semaphore register to choose one
+ * that will actually load FW to NIC.
+ */
+
+static int bdx_fw_load(struct bdx_priv *priv)
+{
+ int master, i;
+
+ ENTER;
+ master = READ_REG(priv, regINIT_SEMAPHORE);
+ if (!READ_REG(priv, regINIT_STATUS) && master) {
+ bdx_tx_push_desc_safe(priv, s_firmLoad, sizeof(s_firmLoad));
+ mdelay(100);
+ }
+ for (i = 0; i < 200; i++) {
+ if (READ_REG(priv, regINIT_STATUS))
+ break;
+ mdelay(2);
+ }
+ if (master)
+ WRITE_REG(priv, regINIT_SEMAPHORE, 1);
+
+ if (i == 200) {
+ ERR("%s: firmware loading failed\n", priv->ndev->name);
+ DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n",
+ READ_REG(priv, regVPC),
+ READ_REG(priv, regVIC), READ_REG(priv, regINIT_STATUS), i);
+ RET(-EIO);
+ } else {
+ DBG("%s: firmware loading success\n", priv->ndev->name);
+ RET(0);
+ }
+}
+
+static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv)
+{
+ u32 val;
+
+ ENTER;
+ DBG("mac0=%x mac1=%x mac2=%x\n",
+ READ_REG(priv, regUNC_MAC0_A),
+ READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A));
+
+ val = (ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]);
+ WRITE_REG(priv, regUNC_MAC2_A, val);
+ val = (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]);
+ WRITE_REG(priv, regUNC_MAC1_A, val);
+ val = (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]);
+ WRITE_REG(priv, regUNC_MAC0_A, val);
+
+ DBG("mac0=%x mac1=%x mac2=%x\n",
+ READ_REG(priv, regUNC_MAC0_A),
+ READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A));
+ RET();
+}
+
+/* bdx_hw_start - inits registers and starts HW's Rx and Tx engines
+ * @priv - NIC private structure
+ */
+static int bdx_hw_start(struct bdx_priv *priv)
+{
+ int rc = -EIO;
+ struct net_device *ndev = priv->ndev;
+
+ ENTER;
+ bdx_link_changed(priv);
+
+ /* 10G overall max length (vlan, eth&ip header, ip payload, crc) */
+ WRITE_REG(priv, regFRM_LENGTH, 0X3FE0);
+ WRITE_REG(priv, regPAUSE_QUANT, 0x96);
+ WRITE_REG(priv, regRX_FIFO_SECTION, 0x800010);
+ WRITE_REG(priv, regTX_FIFO_SECTION, 0xE00010);
+ WRITE_REG(priv, regRX_FULLNESS, 0);
+ WRITE_REG(priv, regTX_FULLNESS, 0);
+ WRITE_REG(priv, regCTRLST,
+ regCTRLST_BASE | regCTRLST_RX_ENA | regCTRLST_TX_ENA);
+
+ WRITE_REG(priv, regVGLB, 0);
+ WRITE_REG(priv, regMAX_FRAME_A,
+ priv->rxf_fifo0.m.pktsz & MAX_FRAME_AB_VAL);
+
+ DBG("RDINTCM=%08x\n", priv->rdintcm); /*NOTE: test script uses this */
+ WRITE_REG(priv, regRDINTCM0, priv->rdintcm);
+ WRITE_REG(priv, regRDINTCM2, 0); /*cpu_to_le32(rcm.val)); */
+
+ DBG("TDINTCM=%08x\n", priv->tdintcm); /*NOTE: test script uses this */
+ WRITE_REG(priv, regTDINTCM0, priv->tdintcm); /* old val = 0x300064 */
+
+ /* Enable timer interrupt once in 2 secs. */
+ /*WRITE_REG(priv, regGTMR0, ((GTMR_SEC * 2) & GTMR_DATA)); */
+ bdx_restore_mac(priv->ndev, priv);
+
+ WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN |
+ GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB);
+
+#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED)
+ if ((rc = request_irq(priv->pdev->irq, &bdx_isr_napi, BDX_IRQ_TYPE,
+ ndev->name, ndev)))
+ goto err_irq;
+ bdx_enable_interrupts(priv);
+
+ RET(0);
+
+err_irq:
+ RET(rc);
+}
+
+static void bdx_hw_stop(struct bdx_priv *priv)
+{
+ ENTER;
+ bdx_disable_interrupts(priv);
+ free_irq(priv->pdev->irq, priv->ndev);
+
+ netif_carrier_off(priv->ndev);
+ netif_stop_queue(priv->ndev);
+
+ RET();
+}
+
+static int bdx_hw_reset_direct(void __iomem *regs)
+{
+ u32 val, i;
+ ENTER;
+
+ /* reset sequences: read, write 1, read, write 0 */
+ val = readl(regs + regCLKPLL);
+ writel((val | CLKPLL_SFTRST) + 0x8, regs + regCLKPLL);
+ udelay(50);
+ val = readl(regs + regCLKPLL);
+ writel(val & ~CLKPLL_SFTRST, regs + regCLKPLL);
+
+ /* check that the PLLs are locked and reset ended */
+ for (i = 0; i < 70; i++, mdelay(10))
+ if ((readl(regs + regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) {
+ /* do any PCI-E read transaction */
+ readl(regs + regRXD_CFG0_0);
+ return 0;
+ }
+ ERR("tehuti: HW reset failed\n");
+ return 1; /* failure */
+}
+
+static int bdx_hw_reset(struct bdx_priv *priv)
+{
+ u32 val, i;
+ ENTER;
+
+ if (priv->port == 0) {
+ /* reset sequences: read, write 1, read, write 0 */
+ val = READ_REG(priv, regCLKPLL);
+ WRITE_REG(priv, regCLKPLL, (val | CLKPLL_SFTRST) + 0x8);
+ udelay(50);
+ val = READ_REG(priv, regCLKPLL);
+ WRITE_REG(priv, regCLKPLL, val & ~CLKPLL_SFTRST);
+ }
+ /* check that the PLLs are locked and reset ended */
+ for (i = 0; i < 70; i++, mdelay(10))
+ if ((READ_REG(priv, regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) {
+ /* do any PCI-E read transaction */
+ READ_REG(priv, regRXD_CFG0_0);
+ return 0;
+ }
+ ERR("tehuti: HW reset failed\n");
+ return 1; /* failure */
+}
+
+static int bdx_sw_reset(struct bdx_priv *priv)
+{
+ int i;
+
+ ENTER;
+ /* 1. load MAC (obsolete) */
+ /* 2. disable Rx (and Tx) */
+ WRITE_REG(priv, regGMAC_RXF_A, 0);
+ mdelay(100);
+ /* 3. disable port */
+ WRITE_REG(priv, regDIS_PORT, 1);
+ /* 4. disable queue */
+ WRITE_REG(priv, regDIS_QU, 1);
+ /* 5. wait until hw is disabled */
+ for (i = 0; i < 50; i++) {
+ if (READ_REG(priv, regRST_PORT) & 1)
+ break;
+ mdelay(10);
+ }
+ if (i == 50)
+ ERR("%s: SW reset timeout. continuing anyway\n",
+ priv->ndev->name);
+
+ /* 6. disable intrs */
+ WRITE_REG(priv, regRDINTCM0, 0);
+ WRITE_REG(priv, regTDINTCM0, 0);
+ WRITE_REG(priv, regIMR, 0);
+ READ_REG(priv, regISR);
+
+ /* 7. reset queue */
+ WRITE_REG(priv, regRST_QU, 1);
+ /* 8. reset port */
+ WRITE_REG(priv, regRST_PORT, 1);
+ /* 9. zero all read and write pointers */
+ for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+ DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR);
+ for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+ WRITE_REG(priv, i, 0);
+ /* 10. unseet port disable */
+ WRITE_REG(priv, regDIS_PORT, 0);
+ /* 11. unset queue disable */
+ WRITE_REG(priv, regDIS_QU, 0);
+ /* 12. unset queue reset */
+ WRITE_REG(priv, regRST_QU, 0);
+ /* 13. unset port reset */
+ WRITE_REG(priv, regRST_PORT, 0);
+ /* 14. enable Rx */
+ /* skiped. will be done later */
+ /* 15. save MAC (obsolete) */
+ for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+ DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR);
+
+ RET(0);
+}
+
+/* bdx_reset - performs right type of reset depending on hw type */
+static int bdx_reset(struct bdx_priv *priv)
+{
+ ENTER;
+ RET((priv->pdev->device == 0x3009)
+ ? bdx_hw_reset(priv)
+ : bdx_sw_reset(priv));
+}
+
+/**
+ * bdx_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int bdx_close(struct net_device *ndev)
+{
+ struct bdx_priv *priv = NULL;
+
+ ENTER;
+ priv = ndev->priv;
+
+ napi_disable(&priv->napi);
+
+ bdx_reset(priv);
+ bdx_hw_stop(priv);
+ bdx_rx_free(priv);
+ bdx_tx_free(priv);
+ RET(0);
+}
+
+/**
+ * bdx_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int bdx_open(struct net_device *ndev)
+{
+ struct bdx_priv *priv;
+ int rc;
+
+ ENTER;
+ priv = ndev->priv;
+ bdx_reset(priv);
+ if (netif_running(ndev))
+ netif_stop_queue(priv->ndev);
+
+ if ((rc = bdx_tx_init(priv)))
+ goto err;
+
+ if ((rc = bdx_rx_init(priv)))
+ goto err;
+
+ if ((rc = bdx_fw_load(priv)))
+ goto err;
+
+ bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+
+ if ((rc = bdx_hw_start(priv)))
+ goto err;
+
+ napi_enable(&priv->napi);
+
+ print_fw_id(priv->nic);
+
+ RET(0);
+
+err:
+ bdx_close(ndev);
+ RET(rc);
+}
+
+static void __init bdx_firmware_endianess(void)
+{
+ int i;
+ for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++)
+ s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]);
+}
+
+static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ struct bdx_priv *priv = ndev->priv;
+ u32 data[3];
+ int error;
+
+ ENTER;
+
+ DBG("jiffies=%ld cmd=%d\n", jiffies, cmd);
+ if (cmd != SIOCDEVPRIVATE) {
+ error = copy_from_user(data, ifr->ifr_data, sizeof(data));
+ if (error) {
+ ERR("cant copy from user\n");
+ RET(error);
+ }
+ DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
+ }
+
+ switch (data[0]) {
+
+ case BDX_OP_READ:
+ data[2] = READ_REG(priv, data[1]);
+ DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2],
+ data[2]);
+ error = copy_to_user(ifr->ifr_data, data, sizeof(data));
+ if (error)
+ RET(error);
+ break;
+
+ case BDX_OP_WRITE:
+ WRITE_REG(priv, data[1], data[2]);
+ DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]);
+ break;
+
+ default:
+ RET(-EOPNOTSUPP);
+ }
+ return 0;
+}
+
+static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ ENTER;
+ if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))
+ RET(bdx_ioctl_priv(ndev, ifr, cmd));
+ else
+ RET(-EOPNOTSUPP);
+}
+
+/*
+ * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid
+ * by passing VLAN filter table to hardware
+ * @ndev network device
+ * @vid VLAN vid
+ * @op add or kill operation
+ */
+static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable)
+{
+ struct bdx_priv *priv = ndev->priv;
+ u32 reg, bit, val;
+
+ ENTER;
+ DBG2("vid=%d value=%d\n", (int)vid, enable);
+ if (unlikely(vid >= 4096)) {
+ ERR("tehuti: invalid VID: %u (> 4096)\n", vid);
+ RET();
+ }
+ reg = regVLAN_0 + (vid / 32) * 4;
+ bit = 1 << vid % 32;
+ val = READ_REG(priv, reg);
+ DBG2("reg=%x, val=%x, bit=%d\n", reg, val, bit);
+ if (enable)
+ val |= bit;
+ else
+ val &= ~bit;
+ DBG2("new val %x\n", val);
+ WRITE_REG(priv, reg, val);
+ RET();
+}
+
+/*
+ * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table
+ * @ndev network device
+ * @vid VLAN vid to add
+ */
+static void bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid)
+{
+ __bdx_vlan_rx_vid(ndev, vid, 1);
+}
+
+/*
+ * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table
+ * @ndev network device
+ * @vid VLAN vid to kill
+ */
+static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid)
+{
+ __bdx_vlan_rx_vid(ndev, vid, 0);
+}
+
+/*
+ * bdx_vlan_rx_register - kernel hook for adding VLAN group
+ * @ndev network device
+ * @grp VLAN group
+ */
+static void
+bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
+{
+ struct bdx_priv *priv = ndev->priv;
+
+ ENTER;
+ DBG("device='%s', group='%p'\n", ndev->name, grp);
+ priv->vlgrp = grp;
+ RET();
+}
+
+/**
+ * bdx_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int bdx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ ENTER;
+
+ if (new_mtu == ndev->mtu)
+ RET(0);
+
+ /* enforce minimum frame size */
+ if (new_mtu < ETH_ZLEN) {
+ ERR("%s: %s mtu %d is less then minimal %d\n",
+ BDX_DRV_NAME, ndev->name, new_mtu, ETH_ZLEN);
+ RET(-EINVAL);
+ }
+
+ ndev->mtu = new_mtu;
+ if (netif_running(ndev)) {
+ bdx_close(ndev);
+ bdx_open(ndev);
+ }
+ RET(0);
+}
+
+static void bdx_setmulti(struct net_device *ndev)
+{
+ struct bdx_priv *priv = ndev->priv;
+
+ u32 rxf_val =
+ GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN;
+ int i;
+
+ ENTER;
+ /* IMF - imperfect (hash) rx multicat filter */
+ /* PMF - perfect rx multicat filter */
+
+ /* FIXME: RXE(OFF) */
+ if (ndev->flags & IFF_PROMISC) {
+ rxf_val |= GMAC_RX_FILTER_PRM;
+ } else if (ndev->flags & IFF_ALLMULTI) {
+ /* set IMF to accept all multicast frmaes */
+ for (i = 0; i < MAC_MCST_HASH_NUM; i++)
+ WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0);
+ } else if (ndev->mc_count) {
+ u8 hash;
+ struct dev_mc_list *mclist;
+ u32 reg, val;
+
+ /* set IMF to deny all multicast frames */
+ for (i = 0; i < MAC_MCST_HASH_NUM; i++)
+ WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, 0);
+ /* set PMF to deny all multicast frames */
+ for (i = 0; i < MAC_MCST_NUM; i++) {
+ WRITE_REG(priv, regRX_MAC_MCST0 + i * 8, 0);
+ WRITE_REG(priv, regRX_MAC_MCST1 + i * 8, 0);
+ }
+
+ /* use PMF to accept first MAC_MCST_NUM (15) addresses */
+ /* TBD: sort addreses and write them in ascending order
+ * into RX_MAC_MCST regs. we skip this phase now and accept ALL
+ * multicast frames throu IMF */
+ mclist = ndev->mc_list;
+
+ /* accept the rest of addresses throu IMF */
+ for (; mclist; mclist = mclist->next) {
+ hash = 0;
+ for (i = 0; i < ETH_ALEN; i++)
+ hash ^= mclist->dmi_addr[i];
+ reg = regRX_MCST_HASH0 + ((hash >> 5) << 2);
+ val = READ_REG(priv, reg);
+ val |= (1 << (hash % 32));
+ WRITE_REG(priv, reg, val);
+ }
+
+ } else {
+ DBG("only own mac %d\n", ndev->mc_count);
+ rxf_val |= GMAC_RX_FILTER_AB;
+ }
+ WRITE_REG(priv, regGMAC_RXF_A, rxf_val);
+ /* enable RX */
+ /* FIXME: RXE(ON) */
+ RET();
+}
+
+static int bdx_set_mac(struct net_device *ndev, void *p)
+{
+ struct bdx_priv *priv = ndev->priv;
+ struct sockaddr *addr = p;
+
+ ENTER;
+ /*
+ if (netif_running(dev))
+ return -EBUSY
+ */
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+ bdx_restore_mac(ndev, priv);
+ RET(0);
+}
+
+static int bdx_read_mac(struct bdx_priv *priv)
+{
+ u16 macAddress[3], i;
+ ENTER;
+
+ macAddress[2] = READ_REG(priv, regUNC_MAC0_A);
+ macAddress[2] = READ_REG(priv, regUNC_MAC0_A);
+ macAddress[1] = READ_REG(priv, regUNC_MAC1_A);
+ macAddress[1] = READ_REG(priv, regUNC_MAC1_A);
+ macAddress[0] = READ_REG(priv, regUNC_MAC2_A);
+ macAddress[0] = READ_REG(priv, regUNC_MAC2_A);
+ for (i = 0; i < 3; i++) {
+ priv->ndev->dev_addr[i * 2 + 1] = macAddress[i];
+ priv->ndev->dev_addr[i * 2] = macAddress[i] >> 8;
+ }
+ RET(0);
+}
+
+static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg)
+{
+ u64 val;
+
+ val = READ_REG(priv, reg);
+ val |= ((u64) READ_REG(priv, reg + 8)) << 32;
+ return val;
+}
+
+/*Do the statistics-update work*/
+static void bdx_update_stats(struct bdx_priv *priv)
+{
+ struct bdx_stats *stats = &priv->hw_stats;
+ u64 *stats_vector = (u64 *) stats;
+ int i;
+ int addr;
+
+ /*Fill HW structure */
+ addr = 0x7200;
+ /*First 12 statistics - 0x7200 - 0x72B0 */
+ for (i = 0; i < 12; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x72C0);
+ /* 0x72C0-0x72E0 RSRV */
+ addr = 0x72F0;
+ for (; i < 16; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x7330);
+ /* 0x7330-0x7360 RSRV */
+ addr = 0x7370;
+ for (; i < 19; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x73A0);
+ /* 0x73A0-0x73B0 RSRV */
+ addr = 0x73C0;
+ for (; i < 23; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x7400);
+ BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i);
+}
+
+static struct net_device_stats *bdx_get_stats(struct net_device *ndev)
+{
+ struct bdx_priv *priv = ndev->priv;
+ struct net_device_stats *net_stat = &priv->net_stats;
+ return net_stat;
+}
+
+static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
+ u16 rxd_vlan);
+static void print_rxfd(struct rxf_desc *rxfd);
+
+/*************************************************************************
+ * Rx DB *
+ *************************************************************************/
+
+static void bdx_rxdb_destroy(struct rxdb *db)
+{
+ if (db)
+ vfree(db);
+}
+
+static struct rxdb *bdx_rxdb_create(int nelem)
+{
+ struct rxdb *db;
+ int i;
+
+ db = vmalloc(sizeof(struct rxdb)
+ + (nelem * sizeof(int))
+ + (nelem * sizeof(struct rx_map)));
+ if (likely(db != NULL)) {
+ db->stack = (int *)(db + 1);
+ db->elems = (void *)(db->stack + nelem);
+ db->nelem = nelem;
+ db->top = nelem;
+ for (i = 0; i < nelem; i++)
+ db->stack[i] = nelem - i - 1; /* to make first allocs
+ close to db struct*/
+ }
+
+ return db;
+}
+
+static inline int bdx_rxdb_alloc_elem(struct rxdb *db)
+{
+ BDX_ASSERT(db->top <= 0);
+ return db->stack[--(db->top)];
+}
+
+static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n)
+{
+ BDX_ASSERT((n < 0) || (n >= db->nelem));
+ return db->elems + n;
+}
+
+static inline int bdx_rxdb_available(struct rxdb *db)
+{
+ return db->top;
+}
+
+static inline void bdx_rxdb_free_elem(struct rxdb *db, int n)
+{
+ BDX_ASSERT((n >= db->nelem) || (n < 0));
+ db->stack[(db->top)++] = n;
+}
+
+/*************************************************************************
+ * Rx Init *
+ *************************************************************************/
+
+/* bdx_rx_init - initialize RX all related HW and SW resources
+ * @priv - NIC private structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * It creates rxf and rxd fifos, update relevant HW registers, preallocate
+ * skb for rx. It assumes that Rx is desabled in HW
+ * funcs are grouped for better cache usage
+ *
+ * RxD fifo is smaller then RxF fifo by design. Upon high load, RxD will be
+ * filled and packets will be dropped by nic without getting into host or
+ * cousing interrupt. Anyway, in that condition, host has no chance to proccess
+ * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles
+ */
+
+/* TBD: ensure proper packet size */
+
+static int bdx_rx_init(struct bdx_priv *priv)
+{
+ ENTER;
+
+ if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size,
+ regRXD_CFG0_0, regRXD_CFG1_0,
+ regRXD_RPTR_0, regRXD_WPTR_0))
+ goto err_mem;
+ if (bdx_fifo_init(priv, &priv->rxf_fifo0.m, priv->rxf_size,
+ regRXF_CFG0_0, regRXF_CFG1_0,
+ regRXF_RPTR_0, regRXF_WPTR_0))
+ goto err_mem;
+ if (!
+ (priv->rxdb =
+ bdx_rxdb_create(priv->rxf_fifo0.m.memsz /
+ sizeof(struct rxf_desc))))
+ goto err_mem;
+
+ priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN;
+ return 0;
+
+err_mem:
+ ERR("%s: %s: Rx init failed\n", BDX_DRV_NAME, priv->ndev->name);
+ return -ENOMEM;
+}
+
+/* bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo
+ * @priv - NIC private structure
+ * @f - RXF fifo
+ */
+static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
+{
+ struct rx_map *dm;
+ struct rxdb *db = priv->rxdb;
+ u16 i;
+
+ ENTER;
+ DBG("total=%d free=%d busy=%d\n", db->nelem, bdx_rxdb_available(db),
+ db->nelem - bdx_rxdb_available(db));
+ while (bdx_rxdb_available(db) > 0) {
+ i = bdx_rxdb_alloc_elem(db);
+ dm = bdx_rxdb_addr_elem(db, i);
+ dm->dma = 0;
+ }
+ for (i = 0; i < db->nelem; i++) {
+ dm = bdx_rxdb_addr_elem(db, i);
+ if (dm->dma) {
+ pci_unmap_single(priv->pdev,
+ dm->dma, f->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(dm->skb);
+ }
+ }
+}
+
+/* bdx_rx_free - release all Rx resources
+ * @priv - NIC private structure
+ * It assumes that Rx is desabled in HW
+ */
+static void bdx_rx_free(struct bdx_priv *priv)
+{
+ ENTER;
+ if (priv->rxdb) {
+ bdx_rx_free_skbs(priv, &priv->rxf_fifo0);
+ bdx_rxdb_destroy(priv->rxdb);
+ priv->rxdb = NULL;
+ }
+ bdx_fifo_free(priv, &priv->rxf_fifo0.m);
+ bdx_fifo_free(priv, &priv->rxd_fifo0.m);
+
+ RET();
+}
+
+/*************************************************************************
+ * Rx Engine *
+ *************************************************************************/
+
+/* bdx_rx_alloc_skbs - fill rxf fifo with new skbs
+ * @priv - nic's private structure
+ * @f - RXF fifo that needs skbs
+ * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo.
+ * skb's virtual and physical addresses are stored in skb db.
+ * To calculate free space, func uses cached values of RPTR and WPTR
+ * When needed, it also updates RPTR and WPTR.
+ */
+
+/* TBD: do not update WPTR if no desc were written */
+
+static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
+{
+ struct sk_buff *skb;
+ struct rxf_desc *rxfd;
+ struct rx_map *dm;
+ int dno, delta, idx;
+ struct rxdb *db = priv->rxdb;
+
+ ENTER;
+ dno = bdx_rxdb_available(db) - 1;
+ while (dno > 0) {
+ if (!(skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN))) {
+ ERR("NO MEM: dev_alloc_skb failed\n");
+ break;
+ }
+ skb->dev = priv->ndev;
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ idx = bdx_rxdb_alloc_elem(db);
+ dm = bdx_rxdb_addr_elem(db, idx);
+ dm->dma = pci_map_single(priv->pdev,
+ skb->data, f->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ dm->skb = skb;
+ rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr);
+ rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */
+ rxfd->va_lo = idx;
+ rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma));
+ rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma));
+ rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz);
+ print_rxfd(rxfd);
+
+ f->m.wptr += sizeof(struct rxf_desc);
+ delta = f->m.wptr - f->m.memsz;
+ if (unlikely(delta >= 0)) {
+ f->m.wptr = delta;
+ if (delta > 0) {
+ memcpy(f->m.va, f->m.va + f->m.memsz, delta);
+ DBG("wrapped descriptor\n");
+ }
+ }
+ dno--;
+ }
+ /*TBD: to do - delayed rxf wptr like in txd */
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+ RET();
+}
+
+static inline void
+NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan,
+ struct sk_buff *skb)
+{
+ ENTER;
+ DBG("rxdd->flags.bits.vtag=%d vlgrp=%p\n", GET_RXD_VTAG(rxd_val1),
+ priv->vlgrp);
+ if (priv->vlgrp && GET_RXD_VTAG(rxd_val1)) {
+ DBG("%s: vlan rcv vlan '%x' vtag '%x', device name '%s'\n",
+ priv->ndev->name,
+ GET_RXD_VLAN_ID(rxd_vlan),
+ GET_RXD_VTAG(rxd_val1),
+ vlan_group_get_device(priv->vlgrp,
+ GET_RXD_VLAN_ID(rxd_vlan))->name);
+ /* NAPI variant of receive functions */
+ vlan_hwaccel_receive_skb(skb, priv->vlgrp,
+ GET_RXD_VLAN_ID(rxd_vlan));
+ } else {
+ netif_receive_skb(skb);
+ }
+}
+
+static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd)
+{
+ struct rxf_desc *rxfd;
+ struct rx_map *dm;
+ struct rxf_fifo *f;
+ struct rxdb *db;
+ struct sk_buff *skb;
+ int delta;
+
+ ENTER;
+ DBG("priv=%p rxdd=%p\n", priv, rxdd);
+ f = &priv->rxf_fifo0;
+ db = priv->rxdb;
+ DBG("db=%p f=%p\n", db, f);
+ dm = bdx_rxdb_addr_elem(db, rxdd->va_lo);
+ DBG("dm=%p\n", dm);
+ skb = dm->skb;
+ rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr);
+ rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */
+ rxfd->va_lo = rxdd->va_lo;
+ rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma));
+ rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma));
+ rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz);
+ print_rxfd(rxfd);
+
+ f->m.wptr += sizeof(struct rxf_desc);
+ delta = f->m.wptr - f->m.memsz;
+ if (unlikely(delta >= 0)) {
+ f->m.wptr = delta;
+ if (delta > 0) {
+ memcpy(f->m.va, f->m.va + f->m.memsz, delta);
+ DBG("wrapped descriptor\n");
+ }
+ }
+ RET();
+}
+
+/* bdx_rx_receive - recieves full packets from RXD fifo and pass them to OS
+ * NOTE: a special treatment is given to non-continous descriptors
+ * that start near the end, wraps around and continue at the beginning. a second
+ * part is copied right after the first, and then descriptor is interpreted as
+ * normal. fifo has an extra space to allow such operations
+ * @priv - nic's private structure
+ * @f - RXF fifo that needs skbs
+ */
+
+/* TBD: replace memcpy func call by explicite inline asm */
+
+static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
+{
+ struct sk_buff *skb, *skb2;
+ struct rxd_desc *rxdd;
+ struct rx_map *dm;
+ struct rxf_fifo *rxf_fifo;
+ int tmp_len, size;
+ int done = 0;
+ int max_done = BDX_MAX_RX_DONE;
+ struct rxdb *db = NULL;
+ /* Unmarshalled descriptor - copy of descriptor in host order */
+ u32 rxd_val1;
+ u16 len;
+ u16 rxd_vlan;
+
+ ENTER;
+ max_done = budget;
+
+ priv->ndev->last_rx = jiffies;
+ f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR;
+
+ size = f->m.wptr - f->m.rptr;
+ if (size < 0)
+ size = f->m.memsz + size; /* size is negative :-) */
+
+ while (size > 0) {
+
+ rxdd = (struct rxd_desc *)(f->m.va + f->m.rptr);
+ rxd_val1 = CPU_CHIP_SWAP32(rxdd->rxd_val1);
+
+ len = CPU_CHIP_SWAP16(rxdd->len);
+
+ rxd_vlan = CPU_CHIP_SWAP16(rxdd->rxd_vlan);
+
+ print_rxdd(rxdd, rxd_val1, len, rxd_vlan);
+
+ tmp_len = GET_RXD_BC(rxd_val1) << 3;
+ BDX_ASSERT(tmp_len <= 0);
+ size -= tmp_len;
+ if (size < 0) /* test for partially arrived descriptor */
+ break;
+
+ f->m.rptr += tmp_len;
+
+ tmp_len = f->m.rptr - f->m.memsz;
+ if (unlikely(tmp_len >= 0)) {
+ f->m.rptr = tmp_len;
+ if (tmp_len > 0) {
+ DBG("wrapped desc rptr=%d tmp_len=%d\n",
+ f->m.rptr, tmp_len);
+ memcpy(f->m.va + f->m.memsz, f->m.va, tmp_len);
+ }
+ }
+
+ if (unlikely(GET_RXD_ERR(rxd_val1))) {
+ DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1));
+ priv->net_stats.rx_errors++;
+ bdx_recycle_skb(priv, rxdd);
+ continue;
+ }
+
+ rxf_fifo = &priv->rxf_fifo0;
+ db = priv->rxdb;
+ dm = bdx_rxdb_addr_elem(db, rxdd->va_lo);
+ skb = dm->skb;
+
+ if (len < BDX_COPYBREAK &&
+ (skb2 = dev_alloc_skb(len + NET_IP_ALIGN))) {
+ skb_reserve(skb2, NET_IP_ALIGN);
+ /*skb_put(skb2, len); */
+ pci_dma_sync_single_for_cpu(priv->pdev,
+ dm->dma, rxf_fifo->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb2->data, skb->data, len);
+ bdx_recycle_skb(priv, rxdd);
+ skb = skb2;
+ } else {
+ pci_unmap_single(priv->pdev,
+ dm->dma, rxf_fifo->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ bdx_rxdb_free_elem(db, rxdd->va_lo);
+ }
+
+ priv->net_stats.rx_bytes += len;
+
+ skb_put(skb, len);
+ skb->dev = priv->ndev;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->protocol = eth_type_trans(skb, priv->ndev);
+
+ /* Non-IP packets aren't checksum-offloaded */
+ if (GET_RXD_PKT_ID(rxd_val1) == 0)
+ skb->ip_summed = CHECKSUM_NONE;
+
+ NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb);
+
+ if (++done >= max_done)
+ break;
+ }
+
+ priv->net_stats.rx_packets += done;
+
+ /* FIXME: do smth to minimize pci accesses */
+ WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
+
+ bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+
+ RET(done);
+}
+
+/*************************************************************************
+ * Debug / Temprorary Code *
+ *************************************************************************/
+static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
+ u16 rxd_vlan)
+{
+ DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d "
+ "pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d "
+ "va_lo %d va_hi %d\n",
+ GET_RXD_BC(rxd_val1), GET_RXD_RXFQ(rxd_val1), GET_RXD_TO(rxd_val1),
+ GET_RXD_TYPE(rxd_val1), GET_RXD_ERR(rxd_val1),
+ GET_RXD_RXP(rxd_val1), GET_RXD_PKT_ID(rxd_val1),
+ GET_RXD_VTAG(rxd_val1), len, GET_RXD_VLAN_ID(rxd_vlan),
+ GET_RXD_CFI(rxd_vlan), GET_RXD_PRIO(rxd_vlan), rxdd->va_lo,
+ rxdd->va_hi);
+}
+
+static void print_rxfd(struct rxf_desc *rxfd)
+{
+ DBG("=== RxF desc CHIP ORDER/ENDIANESS =============\n"
+ "info 0x%x va_lo %u pa_lo 0x%x pa_hi 0x%x len 0x%x\n",
+ rxfd->info, rxfd->va_lo, rxfd->pa_lo, rxfd->pa_hi, rxfd->len);
+}
+
+/*
+ * TX HW/SW interaction overview
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * There are 2 types of TX communication channels betwean driver and NIC.
+ * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets
+ * 2) TX Data Fifo - TXD - holds descriptors of full buffers.
+ *
+ * Currently NIC supports TSO, checksuming and gather DMA
+ * UFO and IP fragmentation is on the way
+ *
+ * RX SW Data Structures
+ * ~~~~~~~~~~~~~~~~~~~~~
+ * txdb - used to keep track of all skbs owned by SW and their dma addresses.
+ * For TX case, ownership lasts from geting packet via hard_xmit and until HW
+ * acknowledges sent by TXF descriptors.
+ * Implemented as cyclic buffer.
+ * fifo - keeps info about fifo's size and location, relevant HW registers,
+ * usage and skb db. Each RXD and RXF Fifo has its own fifo structure.
+ * Implemented as simple struct.
+ *
+ * TX SW Execution Flow
+ * ~~~~~~~~~~~~~~~~~~~~
+ * OS calls driver's hard_xmit method with packet to sent.
+ * Driver creates DMA mappings, builds TXD descriptors and kicks HW
+ * by updating TXD WPTR.
+ * When packet is sent, HW write us TXF descriptor and SW frees original skb.
+ * To prevent TXD fifo overflow without reading HW registers every time,
+ * SW deploys "tx level" technique.
+ * Upon strart up, tx level is initialized to TXD fifo length.
+ * For every sent packet, SW gets its TXD descriptor sizei
+ * (from precalculated array) and substructs it from tx level.
+ * The size is also stored in txdb. When TXF ack arrives, SW fetch size of
+ * original TXD descriptor from txdb and adds it to tx level.
+ * When Tx level drops under some predefined treshhold, the driver
+ * stops the TX queue. When TX level rises above that level,
+ * the tx queue is enabled again.
+ *
+ * This technique avoids eccessive reading of RPTR and WPTR registers.
+ * As our benchmarks shows, it adds 1.5 Gbit/sec to NIS's throuput.
+ */
+
+/*************************************************************************
+ * Tx DB *
+ *************************************************************************/
+static inline int bdx_tx_db_size(struct txdb *db)
+{
+ int taken = db->wptr - db->rptr;
+ if (taken < 0)
+ taken = db->size + 1 + taken; /* (size + 1) equals memsz */
+
+ return db->size - taken;
+}
+
+/* __bdx_tx_ptr_next - helper function, increment read/write pointer + wrap
+ * @d - tx data base
+ * @ptr - read or write pointer
+ */
+static inline void __bdx_tx_db_ptr_next(struct txdb *db, struct tx_map **pptr)
+{
+ BDX_ASSERT(db == NULL || pptr == NULL); /* sanity */
+
+ BDX_ASSERT(*pptr != db->rptr && /* expect either read */
+ *pptr != db->wptr); /* or write pointer */
+
+ BDX_ASSERT(*pptr < db->start || /* pointer has to be */
+ *pptr >= db->end); /* in range */
+
+ ++*pptr;
+ if (unlikely(*pptr == db->end))
+ *pptr = db->start;
+}
+
+/* bdx_tx_db_inc_rptr - increment read pointer
+ * @d - tx data base
+ */
+static inline void bdx_tx_db_inc_rptr(struct txdb *db)
+{
+ BDX_ASSERT(db->rptr == db->wptr); /* can't read from empty db */
+ __bdx_tx_db_ptr_next(db, &db->rptr);
+}
+
+/* bdx_tx_db_inc_rptr - increment write pointer
+ * @d - tx data base
+ */
+static inline void bdx_tx_db_inc_wptr(struct txdb *db)
+{
+ __bdx_tx_db_ptr_next(db, &db->wptr);
+ BDX_ASSERT(db->rptr == db->wptr); /* we can not get empty db as
+ a result of write */
+}
+
+/* bdx_tx_db_init - creates and initializes tx db
+ * @d - tx data base
+ * @sz_type - size of tx fifo
+ * Returns 0 on success, error code otherwise
+ */
+static int bdx_tx_db_init(struct txdb *d, int sz_type)
+{
+ int memsz = FIFO_SIZE * (1 << (sz_type + 1));
+
+ d->start = vmalloc(memsz);
+ if (!d->start)
+ return -ENOMEM;
+
+ /*
+ * In order to differentiate between db is empty and db is full
+ * states at least one element should always be empty in order to
+ * avoid rptr == wptr which means db is empty
+ */
+ d->size = memsz / sizeof(struct tx_map) - 1;
+ d->end = d->start + d->size + 1; /* just after last element */
+
+ /* all dbs are created equally empty */
+ d->rptr = d->start;
+ d->wptr = d->start;
+
+ return 0;
+}
+
+/* bdx_tx_db_close - closes tx db and frees all memory
+ * @d - tx data base
+ */
+static void bdx_tx_db_close(struct txdb *d)
+{
+ BDX_ASSERT(d == NULL);
+
+ if (d->start) {
+ vfree(d->start);
+ d->start = NULL;
+ }
+}
+
+/*************************************************************************
+ * Tx Engine *
+ *************************************************************************/
+
+/* sizes of tx desc (including padding if needed) as function
+ * of skb's frag number */
+static struct {
+ u16 bytes;
+ u16 qwords; /* qword = 64 bit */
+} txd_sizes[MAX_SKB_FRAGS + 1];
+
+/* txdb_map_skb - creates and stores dma mappings for skb's data blocks
+ * @priv - NIC private structure
+ * @skb - socket buffer to map
+ *
+ * It makes dma mappings for skb's data blocks and writes them to PBL of
+ * new tx descriptor. It also stores them in the tx db, so they could be
+ * unmaped after data was sent. It is reponsibility of a caller to make
+ * sure that there is enough space in the tx db. Last element holds pointer
+ * to skb itself and marked with zero length
+ */
+static inline void
+bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb,
+ struct txd_desc *txdd)
+{
+ struct txdb *db = &priv->txdb;
+ struct pbl *pbl = &txdd->pbl[0];
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
+
+ db->wptr->len = skb->len - skb->data_len;
+ db->wptr->addr.dma = pci_map_single(priv->pdev, skb->data,
+ db->wptr->len, PCI_DMA_TODEVICE);
+ pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
+ pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma));
+ pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma));
+ DBG("=== pbl len: 0x%x ================\n", pbl->len);
+ DBG("=== pbl pa_lo: 0x%x ================\n", pbl->pa_lo);
+ DBG("=== pbl pa_hi: 0x%x ================\n", pbl->pa_hi);
+ bdx_tx_db_inc_wptr(db);
+
+ for (i = 0; i < nr_frags; i++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[i];
+ db->wptr->len = frag->size;
+ db->wptr->addr.dma =
+ pci_map_page(priv->pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+
+ pbl++;
+ pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
+ pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma));
+ pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma));
+ bdx_tx_db_inc_wptr(db);
+ }
+
+ /* add skb clean up info. */
+ db->wptr->len = -txd_sizes[nr_frags].bytes;
+ db->wptr->addr.skb = skb;
+ bdx_tx_db_inc_wptr(db);
+}
+
+/* init_txd_sizes - precalculate sizes of descriptors for skbs up to 16 frags
+ * number of frags is used as index to fetch correct descriptors size,
+ * instead of calculating it each time */
+static void __init init_txd_sizes(void)
+{
+ int i, lwords;
+
+ /* 7 - is number of lwords in txd with one phys buffer
+ * 3 - is number of lwords used for every additional phys buffer */
+ for (i = 0; i < MAX_SKB_FRAGS + 1; i++) {
+ lwords = 7 + (i * 3);
+ if (lwords & 1)
+ lwords++; /* pad it with 1 lword */
+ txd_sizes[i].qwords = lwords >> 1;
+ txd_sizes[i].bytes = lwords << 2;
+ }
+}
+
+/* bdx_tx_init - initialize all Tx related stuff.
+ * Namely, TXD and TXF fifos, database etc */
+static int bdx_tx_init(struct bdx_priv *priv)
+{
+ if (bdx_fifo_init(priv, &priv->txd_fifo0.m, priv->txd_size,
+ regTXD_CFG0_0,
+ regTXD_CFG1_0, regTXD_RPTR_0, regTXD_WPTR_0))
+ goto err_mem;
+ if (bdx_fifo_init(priv, &priv->txf_fifo0.m, priv->txf_size,
+ regTXF_CFG0_0,
+ regTXF_CFG1_0, regTXF_RPTR_0, regTXF_WPTR_0))
+ goto err_mem;
+
+ /* The TX db has to keep mappings for all packets sent (on TxD)
+ * and not yet reclaimed (on TxF) */
+ if (bdx_tx_db_init(&priv->txdb, max(priv->txd_size, priv->txf_size)))
+ goto err_mem;
+
+ priv->tx_level = BDX_MAX_TX_LEVEL;
+#ifdef BDX_DELAY_WPTR
+ priv->tx_update_mark = priv->tx_level - 1024;
+#endif
+ return 0;
+
+err_mem:
+ ERR("tehuti: %s: Tx init failed\n", priv->ndev->name);
+ return -ENOMEM;
+}
+
+/*
+ * bdx_tx_space - calculates avalable space in TX fifo
+ * @priv - NIC private structure
+ * Returns avaliable space in TX fifo in bytes
+ */
+static inline int bdx_tx_space(struct bdx_priv *priv)
+{
+ struct txd_fifo *f = &priv->txd_fifo0;
+ int fsize;
+
+ f->m.rptr = READ_REG(priv, f->m.reg_RPTR) & TXF_WPTR_WR_PTR;
+ fsize = f->m.rptr - f->m.wptr;
+ if (fsize <= 0)
+ fsize = f->m.memsz + fsize;
+ return (fsize);
+}
+
+/* bdx_tx_transmit - send packet to NIC
+ * @skb - packet to send
+ * ndev - network device assigned to NIC
+ * Return codes:
+ * o NETDEV_TX_OK everything ok.
+ * o NETDEV_TX_BUSY Cannot transmit packet, try later
+ * Usually a bug, means queue start/stop flow control is broken in
+ * the driver. Note: the driver must NOT put the skb in its DMA ring.
+ * o NETDEV_TX_LOCKED Locking failed, please retry quickly.
+ */
+static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct bdx_priv *priv = ndev->priv;
+ struct txd_fifo *f = &priv->txd_fifo0;
+ int txd_checksum = 7; /* full checksum */
+ int txd_lgsnd = 0;
+ int txd_vlan_id = 0;
+ int txd_vtag = 0;
+ int txd_mss = 0;
+
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ struct txd_desc *txdd;
+ int len;
+ unsigned long flags;
+
+ ENTER;
+ local_irq_save(flags);
+ if (!spin_trylock(&priv->tx_lock)) {
+ local_irq_restore(flags);
+ DBG("%s[%s]: TX locked, returning NETDEV_TX_LOCKED\n",
+ BDX_DRV_NAME, ndev->name);
+ return NETDEV_TX_LOCKED;
+ }
+
+ /* build tx descriptor */
+ BDX_ASSERT(f->m.wptr >= f->m.memsz); /* started with valid wptr */
+ txdd = (struct txd_desc *)(f->m.va + f->m.wptr);
+ if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL))
+ txd_checksum = 0;
+
+ if (skb_shinfo(skb)->gso_size) {
+ txd_mss = skb_shinfo(skb)->gso_size;
+ txd_lgsnd = 1;
+ DBG("skb %p skb len %d gso size = %d\n", skb, skb->len,
+ txd_mss);
+ }
+
+ if (vlan_tx_tag_present(skb)) {
+ /*Cut VLAN ID to 12 bits */
+ txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12);
+ txd_vtag = 1;
+ }
+
+ txdd->length = CPU_CHIP_SWAP16(skb->len);
+ txdd->mss = CPU_CHIP_SWAP16(txd_mss);
+ txdd->txd_val1 =
+ CPU_CHIP_SWAP32(TXD_W1_VAL
+ (txd_sizes[nr_frags].qwords, txd_checksum, txd_vtag,
+ txd_lgsnd, txd_vlan_id));
+ DBG("=== TxD desc =====================\n");
+ DBG("=== w1: 0x%x ================\n", txdd->txd_val1);
+ DBG("=== w2: mss 0x%x len 0x%x\n", txdd->mss, txdd->length);
+
+ bdx_tx_map_skb(priv, skb, txdd);
+
+ /* increment TXD write pointer. In case of
+ fifo wrapping copy reminder of the descriptor
+ to the beginning */
+ f->m.wptr += txd_sizes[nr_frags].bytes;
+ len = f->m.wptr - f->m.memsz;
+ if (unlikely(len >= 0)) {
+ f->m.wptr = len;
+ if (len > 0) {
+ BDX_ASSERT(len > f->m.memsz);
+ memcpy(f->m.va, f->m.va + f->m.memsz, len);
+ }
+ }
+ BDX_ASSERT(f->m.wptr >= f->m.memsz); /* finished with valid wptr */
+
+ priv->tx_level -= txd_sizes[nr_frags].bytes;
+ BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
+#ifdef BDX_DELAY_WPTR
+ if (priv->tx_level > priv->tx_update_mark) {
+ /* Force memory writes to complete before letting h/w
+ know there are new descriptors to fetch.
+ (might be needed on platforms like IA64)
+ wmb(); */
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+ } else {
+ if (priv->tx_noupd++ > BDX_NO_UPD_PACKETS) {
+ priv->tx_noupd = 0;
+ WRITE_REG(priv, f->m.reg_WPTR,
+ f->m.wptr & TXF_WPTR_WR_PTR);
+ }
+ }
+#else
+ /* Force memory writes to complete before letting h/w
+ know there are new descriptors to fetch.
+ (might be needed on platforms like IA64)
+ wmb(); */
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+
+#endif
+ ndev->trans_start = jiffies;
+
+ priv->net_stats.tx_packets++;
+ priv->net_stats.tx_bytes += skb->len;
+
+ if (priv->tx_level < BDX_MIN_TX_LEVEL) {
+ DBG("%s: %s: TX Q STOP level %d\n",
+ BDX_DRV_NAME, ndev->name, priv->tx_level);
+ netif_stop_queue(ndev);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ return NETDEV_TX_OK;
+}
+
+/* bdx_tx_cleanup - clean TXF fifo, run in the context of IRQ.
+ * @priv - bdx adapter
+ * It scans TXF fifo for descriptors, frees DMA mappings and reports to OS
+ * that those packets were sent
+ */
+static void bdx_tx_cleanup(struct bdx_priv *priv)
+{
+ struct txf_fifo *f = &priv->txf_fifo0;
+ struct txdb *db = &priv->txdb;
+ int tx_level = 0;
+
+ ENTER;
+ f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_MASK;
+ BDX_ASSERT(f->m.rptr >= f->m.memsz); /* started with valid rptr */
+
+ while (f->m.wptr != f->m.rptr) {
+ f->m.rptr += BDX_TXF_DESC_SZ;
+ f->m.rptr &= f->m.size_mask;
+
+ /* unmap all the fragments */
+ /* first has to come tx_maps containing dma */
+ BDX_ASSERT(db->rptr->len == 0);
+ do {
+ BDX_ASSERT(db->rptr->addr.dma == 0);
+ pci_unmap_page(priv->pdev, db->rptr->addr.dma,
+ db->rptr->len, PCI_DMA_TODEVICE);
+ bdx_tx_db_inc_rptr(db);
+ } while (db->rptr->len > 0);
+ tx_level -= db->rptr->len; /* '-' koz len is negative */
+
+ /* now should come skb pointer - free it */
+ dev_kfree_skb_irq(db->rptr->addr.skb);
+ bdx_tx_db_inc_rptr(db);
+ }
+
+ /* let h/w know which TXF descriptors were cleaned */
+ BDX_ASSERT((f->m.wptr & TXF_WPTR_WR_PTR) >= f->m.memsz);
+ WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
+
+ /* We reclaimed resources, so in case the Q is stopped by xmit callback,
+ * we resume the transmition and use tx_lock to synchronize with xmit.*/
+ spin_lock(&priv->tx_lock);
+ priv->tx_level += tx_level;
+ BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
+#ifdef BDX_DELAY_WPTR
+ if (priv->tx_noupd) {
+ priv->tx_noupd = 0;
+ WRITE_REG(priv, priv->txd_fifo0.m.reg_WPTR,
+ priv->txd_fifo0.m.wptr & TXF_WPTR_WR_PTR);
+ }
+#endif
+
+ if (unlikely(netif_queue_stopped(priv->ndev)
+ && netif_carrier_ok(priv->ndev)
+ && (priv->tx_level >= BDX_MIN_TX_LEVEL))) {
+ DBG("%s: %s: TX Q WAKE level %d\n",
+ BDX_DRV_NAME, priv->ndev->name, priv->tx_level);
+ netif_wake_queue(priv->ndev);
+ }
+ spin_unlock(&priv->tx_lock);
+}
+
+/* bdx_tx_free_skbs - frees all skbs from TXD fifo.
+ * It gets called when OS stops this dev, eg upon "ifconfig down" or rmmod
+ */
+static void bdx_tx_free_skbs(struct bdx_priv *priv)
+{
+ struct txdb *db = &priv->txdb;
+
+ ENTER;
+ while (db->rptr != db->wptr) {
+ if (likely(db->rptr->len))
+ pci_unmap_page(priv->pdev, db->rptr->addr.dma,
+ db->rptr->len, PCI_DMA_TODEVICE);
+ else
+ dev_kfree_skb(db->rptr->addr.skb);
+ bdx_tx_db_inc_rptr(db);
+ }
+ RET();
+}
+
+/* bdx_tx_free - frees all Tx resources */
+static void bdx_tx_free(struct bdx_priv *priv)
+{
+ ENTER;
+ bdx_tx_free_skbs(priv);
+ bdx_fifo_free(priv, &priv->txd_fifo0.m);
+ bdx_fifo_free(priv, &priv->txf_fifo0.m);
+ bdx_tx_db_close(&priv->txdb);
+}
+
+/* bdx_tx_push_desc - push descriptor to TxD fifo
+ * @priv - NIC private structure
+ * @data - desc's data
+ * @size - desc's size
+ *
+ * Pushes desc to TxD fifo and overlaps it if needed.
+ * NOTE: this func does not check for available space. this is responsibility
+ * of the caller. Neither does it check that data size is smaller then
+ * fifo size.
+ */
+static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size)
+{
+ struct txd_fifo *f = &priv->txd_fifo0;
+ int i = f->m.memsz - f->m.wptr;
+
+ if (size == 0)
+ return;
+
+ if (i > size) {
+ memcpy(f->m.va + f->m.wptr, data, size);
+ f->m.wptr += size;
+ } else {
+ memcpy(f->m.va + f->m.wptr, data, i);
+ f->m.wptr = size - i;
+ memcpy(f->m.va, data + i, f->m.wptr);
+ }
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+}
+
+/* bdx_tx_push_desc_safe - push descriptor to TxD fifo in a safe way
+ * @priv - NIC private structure
+ * @data - desc's data
+ * @size - desc's size
+ *
+ * NOTE: this func does check for available space and, if neccessary, waits for
+ * NIC to read existing data before writing new one.
+ */
+static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size)
+{
+ int timer = 0;
+ ENTER;
+
+ while (size > 0) {
+ /* we substruct 8 because when fifo is full rptr == wptr
+ which also means that fifo is empty, we can understand
+ the difference, but could hw do the same ??? :) */
+ int avail = bdx_tx_space(priv) - 8;
+ if (avail <= 0) {
+ if (timer++ > 300) { /* prevent endless loop */
+ DBG("timeout while writing desc to TxD fifo\n");
+ break;
+ }
+ udelay(50); /* give hw a chance to clean fifo */
+ continue;
+ }
+ avail = MIN(avail, size);
+ DBG("about to push %d bytes starting %p size %d\n", avail,
+ data, size);
+ bdx_tx_push_desc(priv, data, avail);
+ size -= avail;
+ data += avail;
+ }
+ RET();
+}
+
+/**
+ * bdx_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in bdx_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * bdx_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ *
+ * functions and their order used as explained in
+ * /usr/src/linux/Documentation/DMA-{API,mapping}.txt
+ *
+ */
+
+/* TBD: netif_msg should be checked and implemented. I disable it for now */
+static int __devinit
+bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *ndev;
+ struct bdx_priv *priv;
+ int err, pci_using_dac, port;
+ unsigned long pciaddr;
+ u32 regionSize;
+ struct pci_nic *nic;
+
+ ENTER;
+
+ nic = vmalloc(sizeof(*nic));
+ if (!nic)
+ RET(-ENOMEM);
+
+ /************** pci *****************/
+ if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */
+ RET(err); /* it's not a problem though */
+
+ if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+ !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
+ pci_using_dac = 1;
+ } else {
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
+ printk(KERN_ERR "tehuti: No usable DMA configuration"
+ ", aborting\n");
+ goto err_dma;
+ }
+ pci_using_dac = 0;
+ }
+
+ if ((err = pci_request_regions(pdev, BDX_DRV_NAME)))
+ goto err_dma;
+
+ pci_set_master(pdev);
+
+ pciaddr = pci_resource_start(pdev, 0);
+ if (!pciaddr) {
+ err = -EIO;
+ ERR("tehuti: no MMIO resource\n");
+ goto err_out_res;
+ }
+ if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) {
+ err = -EIO;
+ ERR("tehuti: MMIO resource (%x) too small\n", regionSize);
+ goto err_out_res;
+ }
+
+ nic->regs = ioremap(pciaddr, regionSize);
+ if (!nic->regs) {
+ err = -EIO;
+ ERR("tehuti: ioremap failed\n");
+ goto err_out_res;
+ }
+
+ if (pdev->irq < 2) {
+ err = -EIO;
+ ERR("tehuti: invalid irq (%d)\n", pdev->irq);
+ goto err_out_iomap;
+ }
+ pci_set_drvdata(pdev, nic);
+
+ if (pdev->device == 0x3014)
+ nic->port_num = 2;
+ else
+ nic->port_num = 1;
+
+ print_hw_id(pdev);
+
+ bdx_hw_reset_direct(nic->regs);
+
+ nic->irq_type = IRQ_INTX;
+#ifdef BDX_MSI
+ if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) {
+ if ((err = pci_enable_msi(pdev)))
+ ERR("Tehuti: Can't eneble msi. error is %d\n", err);
+ else
+ nic->irq_type = IRQ_MSI;
+ } else
+ DBG("HW does not support MSI\n");
+#endif
+
+ /************** netdev **************/
+ for (port = 0; port < nic->port_num; port++) {
+ if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) {
+ err = -ENOMEM;
+ printk(KERN_ERR "tehuti: alloc_etherdev failed\n");
+ goto err_out_iomap;
+ }
+
+ ndev->open = bdx_open;
+ ndev->stop = bdx_close;
+ ndev->hard_start_xmit = bdx_tx_transmit;
+ ndev->do_ioctl = bdx_ioctl;
+ ndev->set_multicast_list = bdx_setmulti;
+ ndev->get_stats = bdx_get_stats;
+ ndev->change_mtu = bdx_change_mtu;
+ ndev->set_mac_address = bdx_set_mac;
+ ndev->tx_queue_len = BDX_NDEV_TXQ_LEN;
+ ndev->vlan_rx_register = bdx_vlan_rx_register;
+ ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid;
+ ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid;
+
+ bdx_ethtool_ops(ndev); /* ethtool interface */
+
+ /* these fields are used for info purposes only
+ * so we can have them same for all ports of the board */
+ ndev->if_port = port;
+ ndev->base_addr = pciaddr;
+ ndev->mem_start = pciaddr;
+ ndev->mem_end = pciaddr + regionSize;
+ ndev->irq = pdev->irq;
+ ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO
+ | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER
+ /*| NETIF_F_FRAGLIST */
+ ;
+
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+
+ /************** priv ****************/
+ priv = nic->priv[port] = ndev->priv;
+
+ memset(priv, 0, sizeof(struct bdx_priv));
+ priv->pBdxRegs = nic->regs + port * 0x8000;
+ priv->port = port;
+ priv->pdev = pdev;
+ priv->ndev = ndev;
+ priv->nic = nic;
+ priv->msg_enable = BDX_DEF_MSG_ENABLE;
+
+ netif_napi_add(ndev, &priv->napi, bdx_poll, 64);
+
+ if ((readl(nic->regs + FPGA_VER) & 0xFFF) == 308) {
+ DBG("HW statistics not supported\n");
+ priv->stats_flag = 0;
+ } else {
+ priv->stats_flag = 1;
+ }
+
+ /* Initialize fifo sizes. */
+ priv->txd_size = 2;
+ priv->txf_size = 2;
+ priv->rxd_size = 2;
+ priv->rxf_size = 3;
+
+ /* Initialize the initial coalescing registers. */
+ priv->rdintcm = INT_REG_VAL(0x20, 1, 4, 12);
+ priv->tdintcm = INT_REG_VAL(0x20, 1, 0, 12);
+
+ /* ndev->xmit_lock spinlock is not used.
+ * Private priv->tx_lock is used for synchronization
+ * between transmit and TX irq cleanup. In addition
+ * set multicast list callback has to use priv->tx_lock.
+ */
+#ifdef BDX_LLTX
+ ndev->features |= NETIF_F_LLTX;
+#endif
+ spin_lock_init(&priv->tx_lock);
+
+ /*bdx_hw_reset(priv); */
+ if (bdx_read_mac(priv)) {
+ printk(KERN_ERR "tehuti: load MAC address failed\n");
+ goto err_out_iomap;
+ }
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ if ((err = register_netdev(ndev))) {
+ printk(KERN_ERR "tehuti: register_netdev failed\n");
+ goto err_out_free;
+ }
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+
+ print_eth_id(ndev);
+ }
+ RET(0);
+
+err_out_free:
+ free_netdev(ndev);
+err_out_iomap:
+ iounmap(nic->regs);
+err_out_res:
+ pci_release_regions(pdev);
+err_dma:
+ pci_disable_device(pdev);
+ vfree(nic);
+
+ RET(err);
+}
+
+/****************** Ethtool interface *********************/
+/* get strings for tests */
+static const char
+ bdx_test_names[][ETH_GSTRING_LEN] = {
+ "No tests defined"
+};
+
+/* get strings for statistics counters */
+static const char
+ bdx_stat_names[][ETH_GSTRING_LEN] = {
+ "InUCast", /* 0x7200 */
+ "InMCast", /* 0x7210 */
+ "InBCast", /* 0x7220 */
+ "InPkts", /* 0x7230 */
+ "InErrors", /* 0x7240 */
+ "InDropped", /* 0x7250 */
+ "FrameTooLong", /* 0x7260 */
+ "FrameSequenceErrors", /* 0x7270 */
+ "InVLAN", /* 0x7280 */
+ "InDroppedDFE", /* 0x7290 */
+ "InDroppedIntFull", /* 0x72A0 */
+ "InFrameAlignErrors", /* 0x72B0 */
+
+ /* 0x72C0-0x72E0 RSRV */
+
+ "OutUCast", /* 0x72F0 */
+ "OutMCast", /* 0x7300 */
+ "OutBCast", /* 0x7310 */
+ "OutPkts", /* 0x7320 */
+
+ /* 0x7330-0x7360 RSRV */
+
+ "OutVLAN", /* 0x7370 */
+ "InUCastOctects", /* 0x7380 */
+ "OutUCastOctects", /* 0x7390 */
+
+ /* 0x73A0-0x73B0 RSRV */
+
+ "InBCastOctects", /* 0x73C0 */
+ "OutBCastOctects", /* 0x73D0 */
+ "InOctects", /* 0x73E0 */
+ "OutOctects", /* 0x73F0 */
+};
+
+/*
+ * bdx_get_settings - get device-specific settings
+ * @netdev
+ * @ecmd
+ */
+static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ u32 rdintcm;
+ u32 tdintcm;
+ struct bdx_priv *priv = netdev->priv;
+
+ rdintcm = priv->rdintcm;
+ tdintcm = priv->tdintcm;
+
+ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+ ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+ ecmd->speed = SPEED_10000;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ /* PCK_TH measures in multiples of FIFO bytes
+ We translate to packets */
+ ecmd->maxtxpkt =
+ ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ);
+ ecmd->maxrxpkt =
+ ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc));
+
+ return 0;
+}
+
+/*
+ * bdx_get_drvinfo - report driver information
+ * @netdev
+ * @drvinfo
+ */
+static void
+bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct bdx_priv *priv = netdev->priv;
+
+ strncat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
+ strncat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
+ strncat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strncat(drvinfo->bus_info, pci_name(priv->pdev),
+ sizeof(drvinfo->bus_info));
+
+ drvinfo->n_stats = ((priv->stats_flag) ?
+ (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0);
+ drvinfo->testinfo_len = 0;
+ drvinfo->regdump_len = 0;
+ drvinfo->eedump_len = 0;
+}
+
+/*
+ * bdx_get_rx_csum - report whether receive checksums are turned on or off
+ * @netdev
+ */
+static u32 bdx_get_rx_csum(struct net_device *netdev)
+{
+ return 1; /* always on */
+}
+
+/*
+ * bdx_get_tx_csum - report whether transmit checksums are turned on or off
+ * @netdev
+ */
+static u32 bdx_get_tx_csum(struct net_device *netdev)
+{
+ return (netdev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+/*
+ * bdx_get_coalesce - get interrupt coalescing parameters
+ * @netdev
+ * @ecoal
+ */
+static int
+bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
+{
+ u32 rdintcm;
+ u32 tdintcm;
+ struct bdx_priv *priv = netdev->priv;
+
+ rdintcm = priv->rdintcm;
+ tdintcm = priv->tdintcm;
+
+ /* PCK_TH measures in multiples of FIFO bytes
+ We translate to packets */
+ ecoal->rx_coalesce_usecs = GET_INT_COAL(rdintcm) * INT_COAL_MULT;
+ ecoal->rx_max_coalesced_frames =
+ ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc));
+
+ ecoal->tx_coalesce_usecs = GET_INT_COAL(tdintcm) * INT_COAL_MULT;
+ ecoal->tx_max_coalesced_frames =
+ ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ);
+
+ /* adaptive parameters ignored */
+ return 0;
+}
+
+/*
+ * bdx_set_coalesce - set interrupt coalescing parameters
+ * @netdev
+ * @ecoal
+ */
+static int
+bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
+{
+ u32 rdintcm;
+ u32 tdintcm;
+ struct bdx_priv *priv = netdev->priv;
+ int rx_coal;
+ int tx_coal;
+ int rx_max_coal;
+ int tx_max_coal;
+
+ /* Check for valid input */
+ rx_coal = ecoal->rx_coalesce_usecs / INT_COAL_MULT;
+ tx_coal = ecoal->tx_coalesce_usecs / INT_COAL_MULT;
+ rx_max_coal = ecoal->rx_max_coalesced_frames;
+ tx_max_coal = ecoal->tx_max_coalesced_frames;
+
+ /* Translate from packets to multiples of FIFO bytes */
+ rx_max_coal =
+ (((rx_max_coal * sizeof(struct rxf_desc)) + PCK_TH_MULT - 1)
+ / PCK_TH_MULT);
+ tx_max_coal =
+ (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1)
+ / PCK_TH_MULT);
+
+ if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF)
+ || (rx_max_coal > 0xF) || (tx_max_coal > 0xF))
+ return -EINVAL;
+
+ rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm),
+ GET_RXF_TH(priv->rdintcm), rx_max_coal);
+ tdintcm = INT_REG_VAL(tx_coal, GET_INT_COAL_RC(priv->tdintcm), 0,
+ tx_max_coal);
+
+ priv->rdintcm = rdintcm;
+ priv->tdintcm = tdintcm;
+
+ WRITE_REG(priv, regRDINTCM0, rdintcm);
+ WRITE_REG(priv, regTDINTCM0, tdintcm);
+
+ return 0;
+}
+
+/* Convert RX fifo size to number of pending packets */
+static inline int bdx_rx_fifo_size_to_packets(int rx_size)
+{
+ return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc));
+}
+
+/* Convert TX fifo size to number of pending packets */
+static inline int bdx_tx_fifo_size_to_packets(int tx_size)
+{
+ return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ);
+}
+
+/*
+ * bdx_get_ringparam - report ring sizes
+ * @netdev
+ * @ring
+ */
+static void
+bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+ struct bdx_priv *priv = netdev->priv;
+
+ /*max_pending - the maximum-sized FIFO we allow */
+ ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3);
+ ring->tx_max_pending = bdx_tx_fifo_size_to_packets(3);
+ ring->rx_pending = bdx_rx_fifo_size_to_packets(priv->rxf_size);
+ ring->tx_pending = bdx_tx_fifo_size_to_packets(priv->txd_size);
+}
+
+/*
+ * bdx_set_ringparam - set ring sizes
+ * @netdev
+ * @ring
+ */
+static int
+bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+ struct bdx_priv *priv = netdev->priv;
+ int rx_size = 0;
+ int tx_size = 0;
+
+ for (; rx_size < 4; rx_size++) {
+ if (bdx_rx_fifo_size_to_packets(rx_size) >= ring->rx_pending)
+ break;
+ }
+ if (rx_size == 4)
+ rx_size = 3;
+
+ for (; tx_size < 4; tx_size++) {
+ if (bdx_tx_fifo_size_to_packets(tx_size) >= ring->tx_pending)
+ break;
+ }
+ if (tx_size == 4)
+ tx_size = 3;
+
+ /*Is there anything to do? */
+ if ((rx_size == priv->rxf_size)
+ && (tx_size == priv->txd_size))
+ return 0;
+
+ priv->rxf_size = rx_size;
+ if (rx_size > 1)
+ priv->rxd_size = rx_size - 1;
+ else
+ priv->rxd_size = rx_size;
+
+ priv->txf_size = priv->txd_size = tx_size;
+
+ if (netif_running(netdev)) {
+ bdx_close(netdev);
+ bdx_open(netdev);
+ }
+ return 0;
+}
+
+/*
+ * bdx_get_strings - return a set of strings that describe the requested objects
+ * @netdev
+ * @data
+ */
+static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(data, *bdx_test_names, sizeof(bdx_test_names));
+ break;
+ case ETH_SS_STATS:
+ memcpy(data, *bdx_stat_names, sizeof(bdx_stat_names));
+ break;
+ }
+}
+
+/*
+ * bdx_get_stats_count - return number of 64bit statistics counters
+ * @netdev
+ */
+static int bdx_get_stats_count(struct net_device *netdev)
+{
+ struct bdx_priv *priv = netdev->priv;
+ BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN
+ != sizeof(struct bdx_stats) / sizeof(u64));
+ return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN)
+ : 0);
+}
+
+/*
+ * bdx_get_ethtool_stats - return device's hardware L2 statistics
+ * @netdev
+ * @stats
+ * @data
+ */
+static void bdx_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct bdx_priv *priv = netdev->priv;
+
+ if (priv->stats_flag) {
+
+ /* Update stats from HW */
+ bdx_update_stats(priv);
+
+ /* Copy data to user buffer */
+ memcpy(data, &priv->hw_stats, sizeof(priv->hw_stats));
+ }
+}
+
+/*
+ * bdx_ethtool_ops - ethtool interface implementation
+ * @netdev
+ */
+static void bdx_ethtool_ops(struct net_device *netdev)
+{
+ static struct ethtool_ops bdx_ethtool_ops = {
+ .get_settings = bdx_get_settings,
+ .get_drvinfo = bdx_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = bdx_get_coalesce,
+ .set_coalesce = bdx_set_coalesce,
+ .get_ringparam = bdx_get_ringparam,
+ .set_ringparam = bdx_set_ringparam,
+ .get_rx_csum = bdx_get_rx_csum,
+ .get_tx_csum = bdx_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .get_strings = bdx_get_strings,
+ .get_stats_count = bdx_get_stats_count,
+ .get_ethtool_stats = bdx_get_ethtool_stats,
+ };
+
+ SET_ETHTOOL_OPS(netdev, &bdx_ethtool_ops);
+}
+
+/**
+ * bdx_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * bdx_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit bdx_remove(struct pci_dev *pdev)
+{
+ struct pci_nic *nic = pci_get_drvdata(pdev);
+ struct net_device *ndev;
+ int port;
+
+ for (port = 0; port < nic->port_num; port++) {
+ ndev = nic->priv[port]->ndev;
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ }
+
+ /*bdx_hw_reset_direct(nic->regs); */
+#ifdef BDX_MSI
+ if (nic->irq_type == IRQ_MSI)
+ pci_disable_msi(pdev);
+#endif
+
+ iounmap(nic->regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ vfree(nic);
+
+ RET();
+}
+
+static struct pci_driver bdx_pci_driver = {
+ .name = BDX_DRV_NAME,
+ .id_table = bdx_pci_tbl,
+ .probe = bdx_probe,
+ .remove = __devexit_p(bdx_remove),
+};
+
+/*
+ * print_driver_id - print parameters of the driver build
+ */
+static void __init print_driver_id(void)
+{
+ printk(KERN_INFO "%s: %s, %s\n", BDX_DRV_NAME, BDX_DRV_DESC,
+ BDX_DRV_VERSION);
+ printk(KERN_INFO "%s: Options: hw_csum %s\n", BDX_DRV_NAME,
+ BDX_MSI_STRING);
+}
+
+static int __init bdx_module_init(void)
+{
+ ENTER;
+ bdx_firmware_endianess();
+ init_txd_sizes();
+ print_driver_id();
+ RET(pci_register_driver(&bdx_pci_driver));
+}
+
+module_init(bdx_module_init);
+
+static void __exit bdx_module_exit(void)
+{
+ ENTER;
+ pci_unregister_driver(&bdx_pci_driver);
+ RET();
+}
+
+module_exit(bdx_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(BDX_DRV_DESC);
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
new file mode 100644
index 000000000000..efd170f451b4
--- /dev/null
+++ b/drivers/net/tehuti.h
@@ -0,0 +1,564 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _TEHUTI_H
+#define _TEHUTI_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/if_vlan.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <asm/byteorder.h>
+
+/* Compile Time Switches */
+/* start */
+#define BDX_TSO
+#define BDX_LLTX
+#define BDX_DELAY_WPTR
+/* #define BDX_MSI */
+/* end */
+
+#if !defined CONFIG_PCI_MSI
+# undef BDX_MSI
+#endif
+
+#define BDX_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK)
+
+/* ioctl ops */
+#define BDX_OP_READ 1
+#define BDX_OP_WRITE 2
+
+/* RX copy break size */
+#define BDX_COPYBREAK 257
+
+#define DRIVER_AUTHOR "Tehuti Networks(R)"
+#define BDX_DRV_DESC "Tehuti Networks(R) Network Driver"
+#define BDX_DRV_NAME "tehuti"
+#define BDX_NIC_NAME "Tehuti 10 Giga TOE SmartNIC"
+#define BDX_NIC2PORT_NAME "Tehuti 2-Port 10 Giga TOE SmartNIC"
+#define BDX_DRV_VERSION "7.29.3"
+
+#ifdef BDX_MSI
+# define BDX_MSI_STRING "msi "
+#else
+# define BDX_MSI_STRING ""
+#endif
+
+/* netdev tx queue len for Luxor. default value is, btw, 1000
+ * ifcontig eth1 txqueuelen 3000 - to change it at runtime */
+#define BDX_NDEV_TXQ_LEN 3000
+
+#define FIFO_SIZE 4096
+#define FIFO_EXTRA_SPACE 1024
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#if BITS_PER_LONG == 64
+# define H32_64(x) (u32) ((u64)(x) >> 32)
+# define L32_64(x) (u32) ((u64)(x) & 0xffffffff)
+#elif BITS_PER_LONG == 32
+# define H32_64(x) 0
+# define L32_64(x) ((u32) (x))
+#else /* BITS_PER_LONG == ?? */
+# error BITS_PER_LONG is undefined. Must be 64 or 32
+#endif /* BITS_PER_LONG */
+
+#ifdef __BIG_ENDIAN
+# define CPU_CHIP_SWAP32(x) swab32(x)
+# define CPU_CHIP_SWAP16(x) swab16(x)
+#else
+# define CPU_CHIP_SWAP32(x) (x)
+# define CPU_CHIP_SWAP16(x) (x)
+#endif
+
+#define READ_REG(pp, reg) readl(pp->pBdxRegs + reg)
+#define WRITE_REG(pp, reg, val) writel(val, pp->pBdxRegs + reg)
+
+#ifndef DMA_64BIT_MASK
+# define DMA_64BIT_MASK 0xffffffffffffffffULL
+#endif
+
+#ifndef DMA_32BIT_MASK
+# define DMA_32BIT_MASK 0x00000000ffffffffULL
+#endif
+
+#ifndef NET_IP_ALIGN
+# define NET_IP_ALIGN 2
+#endif
+
+#ifndef NETDEV_TX_OK
+# define NETDEV_TX_OK 0
+#endif
+
+#define LUXOR_MAX_PORT 2
+#define BDX_MAX_RX_DONE 150
+#define BDX_TXF_DESC_SZ 16
+#define BDX_MAX_TX_LEVEL (priv->txd_fifo0.m.memsz - 16)
+#define BDX_MIN_TX_LEVEL 256
+#define BDX_NO_UPD_PACKETS 40
+
+struct pci_nic {
+ int port_num;
+ void __iomem *regs;
+ int irq_type;
+ struct bdx_priv *priv[LUXOR_MAX_PORT];
+};
+
+enum { IRQ_INTX, IRQ_MSI, IRQ_MSIX };
+
+#define PCK_TH_MULT 128
+#define INT_COAL_MULT 2
+
+#define BITS_MASK(nbits) ((1<<nbits)-1)
+#define GET_BITS_SHIFT(x, nbits, nshift) (((x)>>nshift)&BITS_MASK(nbits))
+#define BITS_SHIFT_MASK(nbits, nshift) (BITS_MASK(nbits)<<nshift)
+#define BITS_SHIFT_VAL(x, nbits, nshift) (((x)&BITS_MASK(nbits))<<nshift)
+#define BITS_SHIFT_CLEAR(x, nbits, nshift) \
+ ((x)&(~BITS_SHIFT_MASK(nbits, nshift)))
+
+#define GET_INT_COAL(x) GET_BITS_SHIFT(x, 15, 0)
+#define GET_INT_COAL_RC(x) GET_BITS_SHIFT(x, 1, 15)
+#define GET_RXF_TH(x) GET_BITS_SHIFT(x, 4, 16)
+#define GET_PCK_TH(x) GET_BITS_SHIFT(x, 4, 20)
+
+#define INT_REG_VAL(coal, coal_rc, rxf_th, pck_th) \
+ ((coal)|((coal_rc)<<15)|((rxf_th)<<16)|((pck_th)<<20))
+
+struct fifo {
+ dma_addr_t da; /* physical address of fifo (used by HW) */
+ char *va; /* virtual address of fifo (used by SW) */
+ u32 rptr, wptr; /* cached values of RPTR and WPTR registers,
+ they're 32 bits on both 32 and 64 archs */
+ u16 reg_CFG0, reg_CFG1;
+ u16 reg_RPTR, reg_WPTR;
+ u16 memsz; /* memory size allocated for fifo */
+ u16 size_mask;
+ u16 pktsz; /* skb packet size to allocate */
+ u16 rcvno; /* number of buffers that come from this RXF */
+};
+
+struct txf_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct txd_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct rxf_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct rxd_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct rx_map {
+ u64 dma;
+ struct sk_buff *skb;
+};
+
+struct rxdb {
+ int *stack;
+ struct rx_map *elems;
+ int nelem;
+ int top;
+};
+
+union bdx_dma_addr {
+ dma_addr_t dma;
+ struct sk_buff *skb;
+};
+
+/* Entry in the db.
+ * if len == 0 addr is dma
+ * if len != 0 addr is skb */
+struct tx_map {
+ union bdx_dma_addr addr;
+ int len;
+};
+
+/* tx database - implemented as circular fifo buffer*/
+struct txdb {
+ struct tx_map *start; /* points to the first element */
+ struct tx_map *end; /* points just AFTER the last element */
+ struct tx_map *rptr; /* points to the next element to read */
+ struct tx_map *wptr; /* points to the next element to write */
+ int size; /* number of elements in the db */
+};
+
+/*Internal stats structure*/
+struct bdx_stats {
+ u64 InUCast; /* 0x7200 */
+ u64 InMCast; /* 0x7210 */
+ u64 InBCast; /* 0x7220 */
+ u64 InPkts; /* 0x7230 */
+ u64 InErrors; /* 0x7240 */
+ u64 InDropped; /* 0x7250 */
+ u64 FrameTooLong; /* 0x7260 */
+ u64 FrameSequenceErrors; /* 0x7270 */
+ u64 InVLAN; /* 0x7280 */
+ u64 InDroppedDFE; /* 0x7290 */
+ u64 InDroppedIntFull; /* 0x72A0 */
+ u64 InFrameAlignErrors; /* 0x72B0 */
+
+ /* 0x72C0-0x72E0 RSRV */
+
+ u64 OutUCast; /* 0x72F0 */
+ u64 OutMCast; /* 0x7300 */
+ u64 OutBCast; /* 0x7310 */
+ u64 OutPkts; /* 0x7320 */
+
+ /* 0x7330-0x7360 RSRV */
+
+ u64 OutVLAN; /* 0x7370 */
+ u64 InUCastOctects; /* 0x7380 */
+ u64 OutUCastOctects; /* 0x7390 */
+
+ /* 0x73A0-0x73B0 RSRV */
+
+ u64 InBCastOctects; /* 0x73C0 */
+ u64 OutBCastOctects; /* 0x73D0 */
+ u64 InOctects; /* 0x73E0 */
+ u64 OutOctects; /* 0x73F0 */
+};
+
+struct bdx_priv {
+ void __iomem *pBdxRegs;
+ struct net_device *ndev;
+
+ struct napi_struct napi;
+
+ /* RX FIFOs: 1 for data (full) descs, and 2 for free descs */
+ struct rxd_fifo rxd_fifo0;
+ struct rxf_fifo rxf_fifo0;
+ struct rxdb *rxdb; /* rx dbs to store skb pointers */
+ int napi_stop;
+ struct vlan_group *vlgrp;
+
+ /* Tx FIFOs: 1 for data desc, 1 for empty (acks) desc */
+ struct txd_fifo txd_fifo0;
+ struct txf_fifo txf_fifo0;
+
+ struct txdb txdb;
+ int tx_level;
+#ifdef BDX_DELAY_WPTR
+ int tx_update_mark;
+ int tx_noupd;
+#endif
+ spinlock_t tx_lock; /* NETIF_F_LLTX mode */
+
+ /* rarely used */
+ u8 port;
+ u32 msg_enable;
+ int stats_flag;
+ struct bdx_stats hw_stats;
+ struct net_device_stats net_stats;
+ struct pci_dev *pdev;
+
+ struct pci_nic *nic;
+
+ u8 txd_size;
+ u8 txf_size;
+ u8 rxd_size;
+ u8 rxf_size;
+ u32 rdintcm;
+ u32 tdintcm;
+};
+
+/* RX FREE descriptor - 64bit*/
+struct rxf_desc {
+ u32 info; /* Buffer Count + Info - described below */
+ u32 va_lo; /* VAdr[31:0] */
+ u32 va_hi; /* VAdr[63:32] */
+ u32 pa_lo; /* PAdr[31:0] */
+ u32 pa_hi; /* PAdr[63:32] */
+ u32 len; /* Buffer Length */
+};
+
+#define GET_RXD_BC(x) GET_BITS_SHIFT((x), 5, 0)
+#define GET_RXD_RXFQ(x) GET_BITS_SHIFT((x), 2, 8)
+#define GET_RXD_TO(x) GET_BITS_SHIFT((x), 1, 15)
+#define GET_RXD_TYPE(x) GET_BITS_SHIFT((x), 4, 16)
+#define GET_RXD_ERR(x) GET_BITS_SHIFT((x), 6, 21)
+#define GET_RXD_RXP(x) GET_BITS_SHIFT((x), 1, 27)
+#define GET_RXD_PKT_ID(x) GET_BITS_SHIFT((x), 3, 28)
+#define GET_RXD_VTAG(x) GET_BITS_SHIFT((x), 1, 31)
+#define GET_RXD_VLAN_ID(x) GET_BITS_SHIFT((x), 12, 0)
+#define GET_RXD_CFI(x) GET_BITS_SHIFT((x), 1, 12)
+#define GET_RXD_PRIO(x) GET_BITS_SHIFT((x), 3, 13)
+
+struct rxd_desc {
+ u32 rxd_val1;
+ u16 len;
+ u16 rxd_vlan;
+ u32 va_lo;
+ u32 va_hi;
+};
+
+/* PBL describes each virtual buffer to be */
+/* transmitted from the host.*/
+struct pbl {
+ u32 pa_lo;
+ u32 pa_hi;
+ u32 len;
+};
+
+/* First word for TXD descriptor. It means: type = 3 for regular Tx packet,
+ * hw_csum = 7 for ip+udp+tcp hw checksums */
+#define TXD_W1_VAL(bc, checksum, vtag, lgsnd, vlan_id) \
+ ((bc) | ((checksum)<<5) | ((vtag)<<8) | \
+ ((lgsnd)<<9) | (0x30000) | ((vlan_id)<<20))
+
+struct txd_desc {
+ u32 txd_val1;
+ u16 mss;
+ u16 length;
+ u32 va_lo;
+ u32 va_hi;
+ struct pbl pbl[0]; /* Fragments */
+} __attribute__ ((packed));
+
+/* Register region size */
+#define BDX_REGS_SIZE 0x1000
+
+/* Registers from 0x0000-0x00fc were remapped to 0x4000-0x40fc */
+#define regTXD_CFG1_0 0x4000
+#define regRXF_CFG1_0 0x4010
+#define regRXD_CFG1_0 0x4020
+#define regTXF_CFG1_0 0x4030
+#define regTXD_CFG0_0 0x4040
+#define regRXF_CFG0_0 0x4050
+#define regRXD_CFG0_0 0x4060
+#define regTXF_CFG0_0 0x4070
+#define regTXD_WPTR_0 0x4080
+#define regRXF_WPTR_0 0x4090
+#define regRXD_WPTR_0 0x40A0
+#define regTXF_WPTR_0 0x40B0
+#define regTXD_RPTR_0 0x40C0
+#define regRXF_RPTR_0 0x40D0
+#define regRXD_RPTR_0 0x40E0
+#define regTXF_RPTR_0 0x40F0
+#define regTXF_RPTR_3 0x40FC
+
+/* hardware versioning */
+#define FW_VER 0x5010
+#define SROM_VER 0x5020
+#define FPGA_VER 0x5030
+#define FPGA_SEED 0x5040
+
+/* Registers from 0x0100-0x0150 were remapped to 0x5100-0x5150 */
+#define regISR regISR0
+#define regISR0 0x5100
+
+#define regIMR regIMR0
+#define regIMR0 0x5110
+
+#define regRDINTCM0 0x5120
+#define regRDINTCM2 0x5128
+
+#define regTDINTCM0 0x5130
+
+#define regISR_MSK0 0x5140
+
+#define regINIT_SEMAPHORE 0x5170
+#define regINIT_STATUS 0x5180
+
+#define regMAC_LNK_STAT 0x0200
+#define MAC_LINK_STAT 0x4 /* Link state */
+
+#define regGMAC_RXF_A 0x1240
+
+#define regUNC_MAC0_A 0x1250
+#define regUNC_MAC1_A 0x1260
+#define regUNC_MAC2_A 0x1270
+
+#define regVLAN_0 0x1800
+
+#define regMAX_FRAME_A 0x12C0
+
+#define regRX_MAC_MCST0 0x1A80
+#define regRX_MAC_MCST1 0x1A84
+#define MAC_MCST_NUM 15
+#define regRX_MCST_HASH0 0x1A00
+#define MAC_MCST_HASH_NUM 8
+
+#define regVPC 0x2300
+#define regVIC 0x2320
+#define regVGLB 0x2340
+
+#define regCLKPLL 0x5000
+
+/*for 10G only*/
+#define regREVISION 0x6000
+#define regSCRATCH 0x6004
+#define regCTRLST 0x6008
+#define regMAC_ADDR_0 0x600C
+#define regMAC_ADDR_1 0x6010
+#define regFRM_LENGTH 0x6014
+#define regPAUSE_QUANT 0x6018
+#define regRX_FIFO_SECTION 0x601C
+#define regTX_FIFO_SECTION 0x6020
+#define regRX_FULLNESS 0x6024
+#define regTX_FULLNESS 0x6028
+#define regHASHTABLE 0x602C
+#define regMDIO_ST 0x6030
+#define regMDIO_CTL 0x6034
+#define regMDIO_DATA 0x6038
+#define regMDIO_ADDR 0x603C
+
+#define regRST_PORT 0x7000
+#define regDIS_PORT 0x7010
+#define regRST_QU 0x7020
+#define regDIS_QU 0x7030
+
+#define regCTRLST_TX_ENA 0x0001
+#define regCTRLST_RX_ENA 0x0002
+#define regCTRLST_PRM_ENA 0x0010
+#define regCTRLST_PAD_ENA 0x0020
+
+#define regCTRLST_BASE (regCTRLST_PAD_ENA|regCTRLST_PRM_ENA)
+
+#define regRX_FLT 0x1400
+
+/* TXD TXF RXF RXD CONFIG 0x0000 --- 0x007c*/
+#define TX_RX_CFG1_BASE 0xffffffff /*0-31 */
+#define TX_RX_CFG0_BASE 0xfffff000 /*31:12 */
+#define TX_RX_CFG0_RSVD 0x0ffc /*11:2 */
+#define TX_RX_CFG0_SIZE 0x0003 /*1:0 */
+
+/* TXD TXF RXF RXD WRITE 0x0080 --- 0x00BC */
+#define TXF_WPTR_WR_PTR 0x7ff8 /*14:3 */
+
+/* TXD TXF RXF RXD READ 0x00CO --- 0x00FC */
+#define TXF_RPTR_RD_PTR 0x7ff8 /*14:3 */
+
+#define TXF_WPTR_MASK 0x7ff0 /* last 4 bits are dropped
+ * size is rounded to 16 */
+
+/* regISR 0x0100 */
+/* regIMR 0x0110 */
+#define IMR_INPROG 0x80000000 /*31 */
+#define IR_LNKCHG1 0x10000000 /*28 */
+#define IR_LNKCHG0 0x08000000 /*27 */
+#define IR_GPIO 0x04000000 /*26 */
+#define IR_RFRSH 0x02000000 /*25 */
+#define IR_RSVD 0x01000000 /*24 */
+#define IR_SWI 0x00800000 /*23 */
+#define IR_RX_FREE_3 0x00400000 /*22 */
+#define IR_RX_FREE_2 0x00200000 /*21 */
+#define IR_RX_FREE_1 0x00100000 /*20 */
+#define IR_RX_FREE_0 0x00080000 /*19 */
+#define IR_TX_FREE_3 0x00040000 /*18 */
+#define IR_TX_FREE_2 0x00020000 /*17 */
+#define IR_TX_FREE_1 0x00010000 /*16 */
+#define IR_TX_FREE_0 0x00008000 /*15 */
+#define IR_RX_DESC_3 0x00004000 /*14 */
+#define IR_RX_DESC_2 0x00002000 /*13 */
+#define IR_RX_DESC_1 0x00001000 /*12 */
+#define IR_RX_DESC_0 0x00000800 /*11 */
+#define IR_PSE 0x00000400 /*10 */
+#define IR_TMR3 0x00000200 /*9 */
+#define IR_TMR2 0x00000100 /*8 */
+#define IR_TMR1 0x00000080 /*7 */
+#define IR_TMR0 0x00000040 /*6 */
+#define IR_VNT 0x00000020 /*5 */
+#define IR_RxFL 0x00000010 /*4 */
+#define IR_SDPERR 0x00000008 /*3 */
+#define IR_TR 0x00000004 /*2 */
+#define IR_PCIE_LINK 0x00000002 /*1 */
+#define IR_PCIE_TOUT 0x00000001 /*0 */
+
+#define IR_EXTRA (IR_RX_FREE_0 | IR_LNKCHG0 | IR_PSE | \
+ IR_TMR0 | IR_PCIE_LINK | IR_PCIE_TOUT)
+#define IR_RUN (IR_EXTRA | IR_RX_DESC_0 | IR_TX_FREE_0)
+#define IR_ALL 0xfdfffff7
+
+#define IR_LNKCHG0_ofst 27
+
+#define GMAC_RX_FILTER_OSEN 0x1000 /* shared OS enable */
+#define GMAC_RX_FILTER_TXFC 0x0400 /* Tx flow control */
+#define GMAC_RX_FILTER_RSV0 0x0200 /* reserved */
+#define GMAC_RX_FILTER_FDA 0x0100 /* filter out direct address */
+#define GMAC_RX_FILTER_AOF 0x0080 /* accept over run */
+#define GMAC_RX_FILTER_ACF 0x0040 /* accept control frames */
+#define GMAC_RX_FILTER_ARUNT 0x0020 /* accept under run */
+#define GMAC_RX_FILTER_ACRC 0x0010 /* accept crc error */
+#define GMAC_RX_FILTER_AM 0x0008 /* accept multicast */
+#define GMAC_RX_FILTER_AB 0x0004 /* accept broadcast */
+#define GMAC_RX_FILTER_PRM 0x0001 /* [0:1] promiscous mode */
+
+#define MAX_FRAME_AB_VAL 0x3fff /* 13:0 */
+
+#define CLKPLL_PLLLKD 0x0200 /*9 */
+#define CLKPLL_RSTEND 0x0100 /*8 */
+#define CLKPLL_SFTRST 0x0001 /*0 */
+
+#define CLKPLL_LKD (CLKPLL_PLLLKD|CLKPLL_RSTEND)
+
+/*
+ * PCI-E Device Control Register (Offset 0x88)
+ * Source: Luxor Data Sheet, 7.1.3.3.3
+ */
+#define PCI_DEV_CTRL_REG 0x88
+#define GET_DEV_CTRL_MAXPL(x) GET_BITS_SHIFT(x, 3, 5)
+#define GET_DEV_CTRL_MRRS(x) GET_BITS_SHIFT(x, 3, 12)
+
+/*
+ * PCI-E Link Status Register (Offset 0x92)
+ * Source: Luxor Data Sheet, 7.1.3.3.7
+ */
+#define PCI_LINK_STATUS_REG 0x92
+#define GET_LINK_STATUS_LANES(x) GET_BITS_SHIFT(x, 6, 4)
+
+/* Debugging Macros */
+
+#define ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
+#define DBG2(fmt, args...) \
+ printk(KERN_ERR "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+
+#define BDX_ASSERT(x) BUG_ON(x)
+
+#ifdef DEBUG
+
+#define ENTER do { \
+ printk(KERN_ERR "%s:%-5d: ENTER\n", __FUNCTION__, __LINE__); \
+} while (0)
+
+#define RET(args...) do { \
+ printk(KERN_ERR "%s:%-5d: RETURN\n", __FUNCTION__, __LINE__); \
+return args; } while (0)
+
+#define DBG(fmt, args...) \
+ printk(KERN_ERR "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+#else
+#define ENTER do { } while (0)
+#define RET(args...) return args
+#define DBG(fmt, args...) do { } while (0)
+#endif
+
+#endif /* _BDX__H */
diff --git a/drivers/net/tehuti_fw.h b/drivers/net/tehuti_fw.h
new file mode 100644
index 000000000000..2c603a8a4383
--- /dev/null
+++ b/drivers/net/tehuti_fw.h
@@ -0,0 +1,10712 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* Loading Firmware */
+/* INT_MEM Ver */
+static u32 s_firmLoad[] = {
+ 0x000f0002,
+ 0x40718000,
+ 0x0000002d,
+ 0xc0000000,
+ 0x000f0002,
+ 0x00718001,
+ 0x0000002d,
+ 0xc0800000,
+ 0x000f0002,
+ 0x00718002,
+ 0x0000002d,
+ 0xc1000000,
+ 0x000f0002,
+ 0x00718003,
+ 0x0000002d,
+ 0xc1800000,
+ 0x000f0002,
+ 0x00718004,
+ 0x0000002d,
+ 0xc2000000,
+ 0x000f0002,
+ 0x00718005,
+ 0x0000002d,
+ 0xc2800000,
+ 0x000f0002,
+ 0x00718006,
+ 0x0000002d,
+ 0xc3000000,
+ 0x000f0002,
+ 0x00718007,
+ 0x0000002d,
+ 0xc3800000,
+ 0x000f0002,
+ 0x00718008,
+ 0x0000002d,
+ 0xc4000000,
+ 0x000f0002,
+ 0x00718009,
+ 0x0000002d,
+ 0xc4800000,
+ 0x000f0002,
+ 0x0071800a,
+ 0x0000002d,
+ 0xc5000000,
+ 0x000f0002,
+ 0x0071800b,
+ 0x0000002d,
+ 0xc5800000,
+ 0x000f0002,
+ 0x0071800c,
+ 0x0000002d,
+ 0xc6000000,
+ 0x000f0002,
+ 0x0071800d,
+ 0x0000002d,
+ 0xc6800000,
+ 0x000f0002,
+ 0x0071800e,
+ 0x0000002d,
+ 0xc7000000,
+ 0x000f0002,
+ 0x0071800f,
+ 0x0000002d,
+ 0xc7800000,
+ 0x000f0002,
+ 0x00718010,
+ 0x0000002d,
+ 0xc8000000,
+ 0x000f0002,
+ 0x00718011,
+ 0x0000002d,
+ 0xc8800000,
+ 0x000f0002,
+ 0x00718012,
+ 0x0000002d,
+ 0xc9000000,
+ 0x000f0002,
+ 0x00718013,
+ 0x0000002d,
+ 0xc9800000,
+ 0x000f0002,
+ 0x00718014,
+ 0x0000002d,
+ 0xca000000,
+ 0x000f0002,
+ 0x00718015,
+ 0x0000002d,
+ 0xca800000,
+ 0x000f0002,
+ 0x00718016,
+ 0x0000002d,
+ 0xcb000000,
+ 0x000f0002,
+ 0x00718017,
+ 0x0000002d,
+ 0xcb800000,
+ 0x000f0002,
+ 0x00718018,
+ 0x0000002d,
+ 0xcc000000,
+ 0x000f0002,
+ 0x00718019,
+ 0x0000002d,
+ 0xcc800000,
+ 0x000f0002,
+ 0x0071801a,
+ 0x0000002d,
+ 0xcd000000,
+ 0x000f0002,
+ 0x0071801b,
+ 0x0000002d,
+ 0xcd800000,
+ 0x000f0002,
+ 0x0071801c,
+ 0x0000002d,
+ 0xce000000,
+ 0x000f0002,
+ 0x0071801d,
+ 0x0000002d,
+ 0xce800000,
+ 0x000f0002,
+ 0x0071801e,
+ 0x0000002d,
+ 0xcf000000,
+ 0x000f0002,
+ 0x0071801f,
+ 0x0000002d,
+ 0xcf800000,
+ 0x000f0002,
+ 0x00718020,
+ 0x0000002d,
+ 0xd0000000,
+ 0x000f0002,
+ 0x00718021,
+ 0x0000002d,
+ 0xd0800000,
+ 0x000f0002,
+ 0x00718022,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x00718023,
+ 0x0000002d,
+ 0xd1800000,
+ 0x000f0002,
+ 0x00718024,
+ 0x0000002d,
+ 0xd2000000,
+ 0x000f0002,
+ 0x00718025,
+ 0x0000002d,
+ 0xd2800000,
+ 0x000f0002,
+ 0x00718026,
+ 0x0000002d,
+ 0xd3000000,
+ 0x000f0002,
+ 0x00718027,
+ 0x0000002d,
+ 0xd3800000,
+ 0x000f0002,
+ 0x00718028,
+ 0x0000002d,
+ 0xd4000000,
+ 0x000f0002,
+ 0x00718029,
+ 0x0000002d,
+ 0xd4800000,
+ 0x000f0002,
+ 0x0071802a,
+ 0x0000002d,
+ 0xd5000000,
+ 0x000f0002,
+ 0x0071802b,
+ 0x0000002d,
+ 0xd5800000,
+ 0x000f0002,
+ 0x0071802c,
+ 0x0000002d,
+ 0xd6000000,
+ 0x000f0002,
+ 0x0071802d,
+ 0x0000002d,
+ 0xd6800000,
+ 0x000f0002,
+ 0x0071802e,
+ 0x0000002d,
+ 0xd7000000,
+ 0x000f0002,
+ 0x0071802f,
+ 0x0000002d,
+ 0xd7800000,
+ 0x000f0002,
+ 0x00718030,
+ 0x0000002d,
+ 0xd8000000,
+ 0x000f0002,
+ 0x00718031,
+ 0x0000002d,
+ 0xd8800000,
+ 0x000f0002,
+ 0x00718032,
+ 0x0000002d,
+ 0xd9000000,
+ 0x000f0002,
+ 0x00718033,
+ 0x0000002d,
+ 0xd9800000,
+ 0x000f0002,
+ 0x00718034,
+ 0x0000002d,
+ 0xda000000,
+ 0x000f0002,
+ 0x00718035,
+ 0x0000002d,
+ 0xda800000,
+ 0x000f0002,
+ 0x00718036,
+ 0x0000002d,
+ 0xdb000000,
+ 0x000f0002,
+ 0x00718037,
+ 0x0000002d,
+ 0xdb800000,
+ 0x000f0002,
+ 0x00718038,
+ 0x0000007b,
+ 0xdd608000,
+ 0x000f0002,
+ 0x00718039,
+ 0x0000002d,
+ 0xdd000000,
+ 0x000f0002,
+ 0x0071803a,
+ 0x0000002d,
+ 0xdb800000,
+ 0x000f0002,
+ 0x0071803b,
+ 0x0000002d,
+ 0xdd000000,
+ 0x000f0002,
+ 0x0071803c,
+ 0x0000002d,
+ 0xdd000000,
+ 0x000f0002,
+ 0x0071803d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718040,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718041,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718042,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718043,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718044,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718045,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718046,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718047,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718048,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718049,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718050,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718051,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718052,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718053,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718054,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718055,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718056,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718057,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718058,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718059,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718060,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718061,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718062,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718063,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718064,
+ 0x0000002d,
+ 0xdb000000,
+ 0x000f0002,
+ 0x00718065,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718066,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718067,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718068,
+ 0x0000003f,
+ 0xdd000804,
+ 0x000f0002,
+ 0x00718069,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071806a,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x0071806b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071806c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071806d,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071806e,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071806f,
+ 0x0000003f,
+ 0xdd003d04,
+ 0x000f0002,
+ 0x00718070,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718071,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718072,
+ 0x0000003f,
+ 0xdd000704,
+ 0x000f0002,
+ 0x00718073,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718074,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x00718075,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718076,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718077,
+ 0x0000003f,
+ 0xdd003704,
+ 0x000f0002,
+ 0x00718078,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718079,
+ 0x0000003f,
+ 0xdd002904,
+ 0x000f0002,
+ 0x0071807a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071807b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071807c,
+ 0x0000003f,
+ 0xdd04aa04,
+ 0x000f0002,
+ 0x0071807d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071807e,
+ 0x0000003f,
+ 0xdd002804,
+ 0x000f0002,
+ 0x0071807f,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718080,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718081,
+ 0x0000003f,
+ 0xdd003104,
+ 0x000f0002,
+ 0x00718082,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718083,
+ 0x0000003f,
+ 0xdd002b84,
+ 0x000f0002,
+ 0x00718084,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718085,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718086,
+ 0x0000003f,
+ 0xdd01e404,
+ 0x000f0002,
+ 0x00718087,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718088,
+ 0x0000003f,
+ 0xd7800084,
+ 0x000f0002,
+ 0x00718089,
+ 0x0000003f,
+ 0xd7980001,
+ 0x000f0002,
+ 0x0071808a,
+ 0x00000059,
+ 0xd78037ef,
+ 0x000f0002,
+ 0x0071808b,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071808c,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071808d,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071808e,
+ 0x0000002d,
+ 0xd7d6027f,
+ 0x000f0002,
+ 0x0071808f,
+ 0x00000018,
+ 0x17ff0081,
+ 0x000f0002,
+ 0x00718090,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718091,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718092,
+ 0x0000002d,
+ 0xd7d800b8,
+ 0x000f0002,
+ 0x00718093,
+ 0x00000018,
+ 0x17eb0081,
+ 0x000f0002,
+ 0x00718094,
+ 0x0000003f,
+ 0xdd002904,
+ 0x000f0002,
+ 0x00718095,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718096,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718097,
+ 0x0000003f,
+ 0xdd04aa84,
+ 0x000f0002,
+ 0x00718098,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718099,
+ 0x0000003f,
+ 0xdd002b04,
+ 0x000f0002,
+ 0x0071809a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071809b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071809c,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071809d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071809e,
+ 0x0000003f,
+ 0xdd002984,
+ 0x000f0002,
+ 0x0071809f,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180a0,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a1,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180a2,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a3,
+ 0x0000003f,
+ 0xdd002a04,
+ 0x000f0002,
+ 0x007180a4,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180a5,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a6,
+ 0x0000003f,
+ 0xdd009184,
+ 0x000f0002,
+ 0x007180a7,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a8,
+ 0x0000003f,
+ 0xd6801984,
+ 0x000f0002,
+ 0x007180a9,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180aa,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180ab,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180ac,
+ 0x0000003f,
+ 0xdd002b04,
+ 0x000f0002,
+ 0x007180ad,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180ae,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180af,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180b0,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180b1,
+ 0x0000003f,
+ 0xdd002a84,
+ 0x000f0002,
+ 0x007180b2,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180b3,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180b4,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180b5,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180b6,
+ 0x0000003f,
+ 0xd6800c84,
+ 0x000f0002,
+ 0x007180b7,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180b8,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180b9,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180ba,
+ 0x0000003f,
+ 0xdd002a84,
+ 0x000f0002,
+ 0x007180bb,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180bc,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180bd,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180be,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180bf,
+ 0x0000003f,
+ 0xd6800f84,
+ 0x000f0002,
+ 0x007180c0,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180c1,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180c2,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180c3,
+ 0x0000003f,
+ 0xdd002a04,
+ 0x000f0002,
+ 0x007180c4,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180c5,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180c6,
+ 0x0000003f,
+ 0xdd001184,
+ 0x000f0002,
+ 0x007180c7,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180c8,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x007180c9,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180ca,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180cb,
+ 0x0000003f,
+ 0xdd003784,
+ 0x000f0002,
+ 0x007180cc,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180cd,
+ 0x0000002d,
+ 0xd3800000,
+ 0x000f0002,
+ 0x007180ce,
+ 0x0000003f,
+ 0xd2003780,
+ 0x000f0002,
+ 0x007180cf,
+ 0x0000003f,
+ 0xd1800404,
+ 0x000f0002,
+ 0x007180d0,
+ 0x0000003f,
+ 0xd1840001,
+ 0x000f0002,
+ 0x007180d1,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d2,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d3,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d4,
+ 0x0000003f,
+ 0xd17fff84,
+ 0x000f0002,
+ 0x007180d5,
+ 0x0000003f,
+ 0xd17fff81,
+ 0x000f0002,
+ 0x007180d6,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d7,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d8,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d9,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180da,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180db,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180dc,
+ 0x0000003f,
+ 0xd6800784,
+ 0x000f0002,
+ 0x007180dd,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180de,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180df,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180e0,
+ 0x00000049,
+ 0xdd003b63,
+ 0x000f0002,
+ 0x007180e1,
+ 0x00000059,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180e2,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180e3,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180e4,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180e5,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x007180e6,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007180e7,
+ 0x00000045,
+ 0xdd003139,
+ 0x000f0002,
+ 0x007180e8,
+ 0x00000094,
+ 0x000b313b,
+ 0x000f0002,
+ 0x007180e9,
+ 0x00000094,
+ 0x0009313d,
+ 0x000f0002,
+ 0x007180ea,
+ 0x00000094,
+ 0x0007313f,
+ 0x000f0002,
+ 0x007180eb,
+ 0x00000094,
+ 0x00053b76,
+ 0x000f0002,
+ 0x007180ec,
+ 0x00000009,
+ 0xc1ed3d7a,
+ 0x000f0002,
+ 0x007180ed,
+ 0x0000003f,
+ 0xd200b780,
+ 0x000f0002,
+ 0x007180ee,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x007180ef,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180f0,
+ 0x00000069,
+ 0xdd003264,
+ 0x000f0002,
+ 0x007180f1,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180f2,
+ 0x0000003f,
+ 0xd6800784,
+ 0x000f0002,
+ 0x007180f3,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180f4,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180f5,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180f6,
+ 0x00000049,
+ 0xdd003b63,
+ 0x000f0002,
+ 0x007180f7,
+ 0x00000059,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180f8,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180f9,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180fa,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180fb,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x007180fc,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007180fd,
+ 0x00000045,
+ 0xdd00313a,
+ 0x000f0002,
+ 0x007180fe,
+ 0x00000018,
+ 0x1d2d3b76,
+ 0x000f0002,
+ 0x007180ff,
+ 0x00000045,
+ 0xdd00313c,
+ 0x000f0002,
+ 0x00718100,
+ 0x00000018,
+ 0x1d133b76,
+ 0x000f0002,
+ 0x00718101,
+ 0x00000045,
+ 0xdd00313e,
+ 0x000f0002,
+ 0x00718102,
+ 0x00000018,
+ 0x1d1b3b76,
+ 0x000f0002,
+ 0x00718103,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x00718104,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718105,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718106,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718107,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718108,
+ 0x00000009,
+ 0xc52d3d7a,
+ 0x000f0002,
+ 0x00718109,
+ 0x00000029,
+ 0xd2010064,
+ 0x000f0002,
+ 0x0071810a,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x0071810b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071810c,
+ 0x00000069,
+ 0xdd003264,
+ 0x000f0002,
+ 0x0071810d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071810e,
+ 0x00000009,
+ 0xc2293d7a,
+ 0x000f0002,
+ 0x0071810f,
+ 0x00000029,
+ 0xd2000064,
+ 0x000f0002,
+ 0x00718110,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x00718111,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718112,
+ 0x00000069,
+ 0xdd003264,
+ 0x000f0002,
+ 0x00718113,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718114,
+ 0x00000049,
+ 0xdd003b63,
+ 0x000f0002,
+ 0x00718115,
+ 0x00000059,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718116,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718117,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718118,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718119,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x0071811a,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071811b,
+ 0x00000045,
+ 0xdd00313a,
+ 0x000f0002,
+ 0x0071811c,
+ 0x00000018,
+ 0x1d0f3b76,
+ 0x000f0002,
+ 0x0071811d,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x0071811e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071811f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718120,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718121,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718122,
+ 0x00000009,
+ 0xc52d3d7a,
+ 0x000f0002,
+ 0x00718123,
+ 0x0000002d,
+ 0xd1080082,
+ 0x000f0002,
+ 0x00718124,
+ 0x00000008,
+ 0x23c33d7a,
+ 0x000f0002,
+ 0x00718125,
+ 0x00000049,
+ 0xd6003b0a,
+ 0x000f0002,
+ 0x00718126,
+ 0x0000003f,
+ 0xd3000004,
+ 0x000f0002,
+ 0x00718127,
+ 0x0000003f,
+ 0xd3040001,
+ 0x000f0002,
+ 0x00718128,
+ 0x0000002f,
+ 0xd6814085,
+ 0x000f0002,
+ 0x00718129,
+ 0x0000003f,
+ 0xd4ffff84,
+ 0x000f0002,
+ 0x0071812a,
+ 0x0000003f,
+ 0xd4800781,
+ 0x000f0002,
+ 0x0071812b,
+ 0x0000003f,
+ 0xd1ffff84,
+ 0x000f0002,
+ 0x0071812c,
+ 0x0000003f,
+ 0xd1800001,
+ 0x000f0002,
+ 0x0071812d,
+ 0x00000049,
+ 0xdd003666,
+ 0x000f0002,
+ 0x0071812e,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x0071812f,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718130,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718131,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x00718132,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718133,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718134,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718135,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x00718136,
+ 0x00000061,
+ 0xf600046c,
+ 0x000f0002,
+ 0x00718137,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718138,
+ 0x00000018,
+ 0x3d6b0081,
+ 0x000f0002,
+ 0x00718139,
+ 0x00000049,
+ 0xd600058b,
+ 0x000f0002,
+ 0x0071813a,
+ 0x0000002f,
+ 0xd6810106,
+ 0x000f0002,
+ 0x0071813b,
+ 0x0000002d,
+ 0xd2000000,
+ 0x000f0002,
+ 0x0071813c,
+ 0x00000021,
+ 0xd20000e4,
+ 0x000f0002,
+ 0x0071813d,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071813e,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071813f,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718140,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718141,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718142,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718143,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718144,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718145,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x00718146,
+ 0x00000049,
+ 0xd17a33e4,
+ 0x000f0002,
+ 0x00718147,
+ 0x0000002f,
+ 0xd1710162,
+ 0x000f0002,
+ 0x00718148,
+ 0x0000002f,
+ 0xd1610162,
+ 0x000f0002,
+ 0x00718149,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x0071814a,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071814b,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071814c,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071814d,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x0071814e,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071814f,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x00718150,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718151,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718152,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718153,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718154,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718155,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718156,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718157,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718158,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718159,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071815a,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x0071815b,
+ 0x0000002d,
+ 0xd16c07e4,
+ 0x000f0002,
+ 0x0071815c,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x0071815d,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071815e,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071815f,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718160,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718161,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718162,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x00718163,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718164,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718165,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718166,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718167,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718168,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718169,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071816a,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071816b,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x0071816c,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071816d,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x0071816e,
+ 0x00000049,
+ 0xd17833e4,
+ 0x000f0002,
+ 0x0071816f,
+ 0x0000002f,
+ 0xd1710162,
+ 0x000f0002,
+ 0x00718170,
+ 0x0000002f,
+ 0xd1610162,
+ 0x000f0002,
+ 0x00718171,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x00718172,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718173,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718174,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718175,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718176,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718177,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x00718178,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718179,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071817a,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071817b,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071817c,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071817d,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x0071817e,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071817f,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718180,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718181,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718182,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x00718183,
+ 0x0000002d,
+ 0xd16807e4,
+ 0x000f0002,
+ 0x00718184,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x00718185,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718186,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718187,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718188,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718189,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071818a,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x0071818b,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x0071818c,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071818d,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x0071818e,
+ 0x00000008,
+ 0x22790081,
+ 0x000f0002,
+ 0x0071818f,
+ 0x00000049,
+ 0xd600060c,
+ 0x000f0002,
+ 0x00718190,
+ 0x0000002f,
+ 0xd6810106,
+ 0x000f0002,
+ 0x00718191,
+ 0x0000003f,
+ 0xd4800002,
+ 0x000f0002,
+ 0x00718192,
+ 0x0000003f,
+ 0xd4800084,
+ 0x000f0002,
+ 0x00718193,
+ 0x0000003f,
+ 0xd5000102,
+ 0x000f0002,
+ 0x00718194,
+ 0x0000003f,
+ 0xd5000184,
+ 0x000f0002,
+ 0x00718195,
+ 0x0000003f,
+ 0xd5800202,
+ 0x000f0002,
+ 0x00718196,
+ 0x0000003f,
+ 0xd5800204,
+ 0x000f0002,
+ 0x00718197,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718198,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718199,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071819a,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x0071819b,
+ 0x00000069,
+ 0xd80034e9,
+ 0x000f0002,
+ 0x0071819c,
+ 0x00000069,
+ 0xd800356a,
+ 0x000f0002,
+ 0x0071819d,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x0071819e,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071819f,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x007181a0,
+ 0x00000041,
+ 0xd500356b,
+ 0x000f0002,
+ 0x007181a1,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181a2,
+ 0x00000018,
+ 0x37eb0081,
+ 0x000f0002,
+ 0x007181a3,
+ 0x00000049,
+ 0xd6003b0d,
+ 0x000f0002,
+ 0x007181a4,
+ 0x00000049,
+ 0xd6803b07,
+ 0x000f0002,
+ 0x007181a5,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x007181a6,
+ 0x00000049,
+ 0xdd003666,
+ 0x000f0002,
+ 0x007181a7,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181a8,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181a9,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181aa,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ab,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ac,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ad,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ae,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181af,
+ 0x00000061,
+ 0xf600046c,
+ 0x000f0002,
+ 0x007181b0,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181b1,
+ 0x00000018,
+ 0x37eb0081,
+ 0x000f0002,
+ 0x007181b2,
+ 0x00000049,
+ 0xd6003b0e,
+ 0x000f0002,
+ 0x007181b3,
+ 0x00000049,
+ 0xd6803b08,
+ 0x000f0002,
+ 0x007181b4,
+ 0x00000049,
+ 0xd5803b09,
+ 0x000f0002,
+ 0x007181b5,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181b6,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x007181b7,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007181b8,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x007181b9,
+ 0x00000069,
+ 0xd80035eb,
+ 0x000f0002,
+ 0x007181ba,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x007181bb,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x007181bc,
+ 0x00000041,
+ 0xd60007ec,
+ 0x000f0002,
+ 0x007181bd,
+ 0x00000041,
+ 0xd580086b,
+ 0x000f0002,
+ 0x007181be,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181bf,
+ 0x00000018,
+ 0x37ed0081,
+ 0x000f0002,
+ 0x007181c0,
+ 0x0000003f,
+ 0xd4ffff80,
+ 0x000f0002,
+ 0x007181c1,
+ 0x0000003f,
+ 0xd5020004,
+ 0x000f0002,
+ 0x007181c2,
+ 0x0000003f,
+ 0xd5180001,
+ 0x000f0002,
+ 0x007181c3,
+ 0x00000049,
+ 0xdd003b6a,
+ 0x000f0002,
+ 0x007181c4,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181c5,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181c6,
+ 0x00000021,
+ 0xd50000ea,
+ 0x000f0002,
+ 0x007181c7,
+ 0x00000049,
+ 0xdd0e3b6a,
+ 0x000f0002,
+ 0x007181c8,
+ 0x00000035,
+ 0xd104007a,
+ 0x000f0002,
+ 0x007181c9,
+ 0x00000018,
+ 0x37f50081,
+ 0x000f0002,
+ 0x007181ca,
+ 0x0000003f,
+ 0xd4ffff80,
+ 0x000f0002,
+ 0x007181cb,
+ 0x0000003f,
+ 0xd5040004,
+ 0x000f0002,
+ 0x007181cc,
+ 0x0000003f,
+ 0xd5180001,
+ 0x000f0002,
+ 0x007181cd,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181ce,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181cf,
+ 0x00000049,
+ 0xdd003b6a,
+ 0x000f0002,
+ 0x007181d0,
+ 0x00000051,
+ 0xf50000ea,
+ 0x000f0002,
+ 0x007181d1,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d2,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d3,
+ 0x00000049,
+ 0xdd0e3b6a,
+ 0x000f0002,
+ 0x007181d4,
+ 0x00000035,
+ 0xd104807a,
+ 0x000f0002,
+ 0x007181d5,
+ 0x00000018,
+ 0x37f50081,
+ 0x000f0002,
+ 0x007181d6,
+ 0x0000003f,
+ 0xc77f7f04,
+ 0x000f0002,
+ 0x007181d7,
+ 0x0000003f,
+ 0xc77f7f01,
+ 0x000f0002,
+ 0x007181d8,
+ 0x0000003f,
+ 0xd6804000,
+ 0x000f0002,
+ 0x007181d9,
+ 0x0000003f,
+ 0xd103c000,
+ 0x000f0002,
+ 0x007181da,
+ 0x00000025,
+ 0xde2000e2,
+ 0x000f0002,
+ 0x007181db,
+ 0x00000049,
+ 0xde80274e,
+ 0x000f0002,
+ 0x007181dc,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181dd,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181de,
+ 0x00000035,
+ 0xd10000e2,
+ 0x000f0002,
+ 0x007181df,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181e0,
+ 0x00000018,
+ 0x37f50081,
+ 0x000f0002,
+ 0x007181e1,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x007181e2,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181e3,
+ 0x00000069,
+ 0xdd001d3a,
+ 0x000f0002,
+ 0x007181e4,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181e5,
+ 0x0000007d,
+ 0xc760a713,
+ 0x000f0002,
+ 0x007181e6,
+ 0x00000031,
+ 0xc0800041,
+ 0x000f0002,
+ 0x007181e7,
+ 0x00000031,
+ 0xc4000048,
+ 0x000f0002,
+ 0x007181e8,
+ 0x00000031,
+ 0xc2800045,
+ 0x000f0002,
+ 0x007181e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f4,
+ 0x0000002d,
+ 0xdb000000,
+ 0x000f0002,
+ 0x007181f5,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x007181f6,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181f7,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181f8,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007181f9,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181fa,
+ 0x0000002d,
+ 0xd3800000,
+ 0x000f0002,
+ 0x007181fb,
+ 0x0000003f,
+ 0xdd000404,
+ 0x000f0002,
+ 0x007181fc,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181fd,
+ 0x00000069,
+ 0xdd000a14,
+ 0x000f0002,
+ 0x007181fe,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181ff,
+ 0x00000049,
+ 0xd1043394,
+ 0x000f0002,
+ 0x00718200,
+ 0x0000003f,
+ 0xdd000484,
+ 0x000f0002,
+ 0x00718201,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718202,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x00718203,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718204,
+ 0x0000003f,
+ 0xdd000504,
+ 0x000f0002,
+ 0x00718205,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718206,
+ 0x00000069,
+ 0xdd000a95,
+ 0x000f0002,
+ 0x00718207,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718208,
+ 0x00000049,
+ 0xd1043395,
+ 0x000f0002,
+ 0x00718209,
+ 0x0000003f,
+ 0xdd000584,
+ 0x000f0002,
+ 0x0071820a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071820b,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x0071820c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071820d,
+ 0x0000003f,
+ 0xdd000604,
+ 0x000f0002,
+ 0x0071820e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071820f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718210,
+ 0x0000003f,
+ 0xdd000084,
+ 0x000f0002,
+ 0x00718211,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718212,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718213,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718214,
+ 0x00000069,
+ 0xdd000b16,
+ 0x000f0002,
+ 0x00718215,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718216,
+ 0x0000003f,
+ 0xdd001004,
+ 0x000f0002,
+ 0x00718217,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718218,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718219,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071821a,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071821b,
+ 0x0000003f,
+ 0xdd001084,
+ 0x000f0002,
+ 0x0071821c,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071821d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071821e,
+ 0x0000003f,
+ 0xdd018004,
+ 0x000f0002,
+ 0x0071821f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718220,
+ 0x0000003f,
+ 0xdd001104,
+ 0x000f0002,
+ 0x00718221,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718222,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718223,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718224,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718225,
+ 0x0000003f,
+ 0xdd001184,
+ 0x000f0002,
+ 0x00718226,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718227,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718228,
+ 0x0000003f,
+ 0xdd160004,
+ 0x000f0002,
+ 0x00718229,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071822a,
+ 0x0000003f,
+ 0xdd001204,
+ 0x000f0002,
+ 0x0071822b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071822c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071822d,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071822e,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071822f,
+ 0x0000003f,
+ 0xdd001284,
+ 0x000f0002,
+ 0x00718230,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718231,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718232,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718233,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718234,
+ 0x0000003f,
+ 0xdd001304,
+ 0x000f0002,
+ 0x00718235,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718236,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718237,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718238,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718239,
+ 0x0000003f,
+ 0xdd001384,
+ 0x000f0002,
+ 0x0071823a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071823b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071823c,
+ 0x0000003f,
+ 0xdd050004,
+ 0x000f0002,
+ 0x0071823d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071823e,
+ 0x0000003f,
+ 0xdd002004,
+ 0x000f0002,
+ 0x0071823f,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718240,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718241,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718242,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718243,
+ 0x0000003f,
+ 0xdd002084,
+ 0x000f0002,
+ 0x00718244,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718245,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718246,
+ 0x0000003f,
+ 0xdd019004,
+ 0x000f0002,
+ 0x00718247,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718248,
+ 0x0000003f,
+ 0xdd002104,
+ 0x000f0002,
+ 0x00718249,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071824a,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071824b,
+ 0x0000003f,
+ 0xdd000084,
+ 0x000f0002,
+ 0x0071824c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071824d,
+ 0x0000003f,
+ 0xdd002184,
+ 0x000f0002,
+ 0x0071824e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071824f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718250,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718251,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718252,
+ 0x0000003f,
+ 0xdd002204,
+ 0x000f0002,
+ 0x00718253,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718254,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718255,
+ 0x0000003f,
+ 0xdd000284,
+ 0x000f0002,
+ 0x00718256,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718257,
+ 0x0000003f,
+ 0xdd002284,
+ 0x000f0002,
+ 0x00718258,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718259,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071825a,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071825b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071825c,
+ 0x0000003f,
+ 0xdd002304,
+ 0x000f0002,
+ 0x0071825d,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071825e,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071825f,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718260,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718261,
+ 0x0000003f,
+ 0xdd001804,
+ 0x000f0002,
+ 0x00718262,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718263,
+ 0x00000069,
+ 0xdd000b97,
+ 0x000f0002,
+ 0x00718264,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718265,
+ 0x00000049,
+ 0xd1043397,
+ 0x000f0002,
+ 0x00718266,
+ 0x0000003f,
+ 0xdd001884,
+ 0x000f0002,
+ 0x00718267,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718268,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x00718269,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071826a,
+ 0x0000003f,
+ 0xdd001904,
+ 0x000f0002,
+ 0x0071826b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071826c,
+ 0x00000069,
+ 0xdd000c18,
+ 0x000f0002,
+ 0x0071826d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071826e,
+ 0x00000049,
+ 0xd1043398,
+ 0x000f0002,
+ 0x0071826f,
+ 0x0000003f,
+ 0xdd001984,
+ 0x000f0002,
+ 0x00718270,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718271,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x00718272,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718273,
+ 0x0000003f,
+ 0xdd001a04,
+ 0x000f0002,
+ 0x00718274,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718275,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718276,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718277,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718278,
+ 0x0000003f,
+ 0xdd001a84,
+ 0x000f0002,
+ 0x00718279,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071827a,
+ 0x00000069,
+ 0xdd000b16,
+ 0x000f0002,
+ 0x0071827b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071827c,
+ 0x0000003f,
+ 0xdd001c04,
+ 0x000f0002,
+ 0x0071827d,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071827e,
+ 0x00000069,
+ 0xdd000c99,
+ 0x000f0002,
+ 0x0071827f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718280,
+ 0x0000003f,
+ 0xdd001c84,
+ 0x000f0002,
+ 0x00718281,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718282,
+ 0x00000069,
+ 0xdd000d1a,
+ 0x000f0002,
+ 0x00718283,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718284,
+ 0x0000003f,
+ 0xdd001d04,
+ 0x000f0002,
+ 0x00718285,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718286,
+ 0x00000069,
+ 0xdd000d9b,
+ 0x000f0002,
+ 0x00718287,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718288,
+ 0x00000049,
+ 0xd104339b,
+ 0x000f0002,
+ 0x00718289,
+ 0x0000003f,
+ 0xdd001d84,
+ 0x000f0002,
+ 0x0071828a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071828b,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x0071828c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071828d,
+ 0x0000003f,
+ 0xdd001e04,
+ 0x000f0002,
+ 0x0071828e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071828f,
+ 0x00000069,
+ 0xdd000e1c,
+ 0x000f0002,
+ 0x00718290,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718291,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718292,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718293,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718294,
+ 0x0000003f,
+ 0xdd000f04,
+ 0x000f0002,
+ 0x00718295,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718296,
+ 0x0000007d,
+ 0xc760a713,
+ 0x000f0002,
+ 0x00718297,
+ 0x00000031,
+ 0xc0800041,
+ 0x000f0002,
+ 0x00718298,
+ 0x00000031,
+ 0xc4000048,
+ 0x000f0002,
+ 0x00718299,
+ 0x00000031,
+ 0xc2800045,
+ 0x000f0002,
+ 0x0071829a,
+ 0x00000031,
+ 0xd680006d,
+/* BRDX_INIT_SDRAM */
+ 0x000f000f,
+ 0x00700064,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000040,
+ 0x00000100,
+ 0x00000400,
+ 0x00000064,
+ 0x00000054,
+ 0x00000000,
+ 0x00002400,
+ 0x00002800,
+ 0x00000400,
+ 0x00002880,
+ 0x00000180,
+ 0x00000003,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000051,
+ 0x0000017d,
+ 0x00000008,
+ 0x00000051,
+ 0x0000005d,
+ 0x00000000,
+ 0x00000009,
+ 0x00005000,
+ 0x00000000,
+ 0x00000000,
+/* BRDX_INIT */
+ 0x000f000f,
+ 0x007001f4,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000040,
+ 0x00000100,
+ 0x00000400,
+ 0x00000064,
+ 0x00000054,
+ 0x00000000,
+ 0x00002400,
+ 0x00002800,
+ 0x00000400,
+ 0x00002880,
+ 0x00000180,
+ 0x00000003,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000051,
+ 0x0000017d,
+ 0x00000008,
+ 0x00000051,
+ 0x0000005d,
+ 0x00000000,
+ 0x00000009,
+ 0x00005000,
+ 0x00000000,
+ 0x00000000,
+/* ZERO_INIT */
+ 0x000f0002,
+ 0x00700000,
+ 0x00000001,
+ 0x00000000,
+/* ZERO_INIT */
+ 0x000f0002,
+ 0x00700000,
+ 0x00000001,
+ 0x00000000,
+/* Loading operational Firmware */
+ 0x000f0002,
+ 0x00718000,
+ 0x00000025,
+ 0xdd0e0002,
+ 0x000f0002,
+ 0x00718001,
+ 0x00000004,
+ 0x01d13b76,
+ 0x000f0002,
+ 0x00718002,
+ 0x00000025,
+ 0xdd0e0082,
+ 0x000f0002,
+ 0x00718003,
+ 0x00000004,
+ 0x02893b76,
+ 0x000f0002,
+ 0x00718004,
+ 0x00000025,
+ 0xdd0e0102,
+ 0x000f0002,
+ 0x00718005,
+ 0x00000004,
+ 0x02853b76,
+ 0x000f0002,
+ 0x00718006,
+ 0x00000025,
+ 0xdd0e0182,
+ 0x000f0002,
+ 0x00718007,
+ 0x00000004,
+ 0x03fd3b76,
+ 0x000f0002,
+ 0x00718008,
+ 0x00000009,
+ 0xcf813b76,
+ 0x000f0002,
+ 0x00718009,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718010,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718011,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718012,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718013,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718014,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718015,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718016,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718017,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718018,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718019,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718020,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718021,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718022,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718023,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718024,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718025,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718026,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718027,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718028,
+ 0x00000049,
+ 0xc0003b00,
+ 0x000f0002,
+ 0x00718029,
+ 0x00000049,
+ 0xc0803b02,
+ 0x000f0002,
+ 0x0071802a,
+ 0x00000049,
+ 0xc1003b03,
+ 0x000f0002,
+ 0x0071802b,
+ 0x00000049,
+ 0xc1803b04,
+ 0x000f0002,
+ 0x0071802c,
+ 0x00000029,
+ 0xdf600076,
+ 0x000f0002,
+ 0x0071802d,
+ 0x00000049,
+ 0xdf443b7d,
+ 0x000f0002,
+ 0x0071802e,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x0071802f,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718030,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718031,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718032,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718033,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718034,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718035,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718036,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718037,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718038,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718039,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718040,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718041,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718042,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718043,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718044,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718045,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718046,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718047,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718048,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718049,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718050,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718051,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718052,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718053,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718054,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718055,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718056,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718057,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718058,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718059,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718060,
+ 0x0000003f,
+ 0xdf000003,
+ 0x000f0002,
+ 0x00718061,
+ 0x0000002d,
+ 0xdde00f81,
+ 0x000f0002,
+ 0x00718062,
+ 0x0000003f,
+ 0xdd800283,
+ 0x000f0002,
+ 0x00718063,
+ 0x0000002d,
+ 0xdd040180,
+ 0x000f0002,
+ 0x00718064,
+ 0x0000007d,
+ 0xfd150080,
+ 0x000f0002,
+ 0x00718065,
+ 0x0000007a,
+ 0x10203b76,
+ 0x000f0002,
+ 0x00718066,
+ 0x0000007a,
+ 0x30207b76,
+ 0x000f0002,
+ 0x00718067,
+ 0x00000021,
+ 0xd0240060,
+ 0x000f0002,
+ 0x00718068,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718069,
+ 0x0000003f,
+ 0xdd400281,
+ 0x000f0002,
+ 0x0071806a,
+ 0x00000079,
+ 0xdd31bb03,
+ 0x000f0002,
+ 0x0071806b,
+ 0x00000079,
+ 0xdd31fb04,
+ 0x000f0002,
+ 0x0071806c,
+ 0x00000079,
+ 0xdd31bb76,
+ 0x000f0002,
+ 0x0071806d,
+ 0x00000079,
+ 0xdd31fb76,
+ 0x000f0002,
+ 0x0071806e,
+ 0x00000079,
+ 0xfd210101,
+ 0x000f0002,
+ 0x0071806f,
+ 0x0000007d,
+ 0xfd2b4081,
+ 0x000f0002,
+ 0x00718070,
+ 0x00000040,
+ 0x3d003002,
+ 0x000f0002,
+ 0x00718071,
+ 0x00000048,
+ 0x1d003b02,
+ 0x000f0002,
+ 0x00718072,
+ 0x00000079,
+ 0xdd217b76,
+ 0x000f0002,
+ 0x00718073,
+ 0x0000002d,
+ 0xdd04057f,
+ 0x000f0002,
+ 0x00718074,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x00718075,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718076,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718077,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718078,
+ 0x00000021,
+ 0xe3371f76,
+ 0x000f0002,
+ 0x00718079,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x0071807a,
+ 0x00000079,
+ 0xdd21bb76,
+ 0x000f0002,
+ 0x0071807b,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x0071807c,
+ 0x00000079,
+ 0xdd21bb76,
+ 0x000f0002,
+ 0x0071807d,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x0071807e,
+ 0x00000079,
+ 0xdd21bb76,
+ 0x000f0002,
+ 0x0071807f,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x00718080,
+ 0x00000079,
+ 0xdd21fb76,
+ 0x000f0002,
+ 0x00718081,
+ 0x0000003f,
+ 0xdf000083,
+ 0x000f0002,
+ 0x00718082,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718083,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718084,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718085,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718086,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718087,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718088,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718089,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718090,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718091,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718092,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718093,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718094,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718095,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718096,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718097,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718098,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718099,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180a0,
+ 0x0000002d,
+ 0xd0080803,
+ 0x000f0002,
+ 0x007180a1,
+ 0x00000008,
+ 0x21b5fb76,
+ 0x000f0002,
+ 0x007180a2,
+ 0x00000079,
+ 0xdd010081,
+ 0x000f0002,
+ 0x007180a3,
+ 0x00000079,
+ 0xdd018102,
+ 0x000f0002,
+ 0x007180a4,
+ 0x0000007d,
+ 0xfd018083,
+ 0x000f0002,
+ 0x007180a5,
+ 0x00000079,
+ 0xd0903b76,
+ 0x000f0002,
+ 0x007180a6,
+ 0x00000049,
+ 0xd0583b7a,
+ 0x000f0002,
+ 0x007180a7,
+ 0x00000049,
+ 0xd2043b00,
+ 0x000f0002,
+ 0x007180a8,
+ 0x0000003d,
+ 0xdd400003,
+ 0x000f0002,
+ 0x007180a9,
+ 0x00000024,
+ 0x32000264,
+ 0x000f0002,
+ 0x007180aa,
+ 0x0000003d,
+ 0xdd7ff803,
+ 0x000f0002,
+ 0x007180ab,
+ 0x00000029,
+ 0xd020017a,
+ 0x000f0002,
+ 0x007180ac,
+ 0x00000049,
+ 0xd0a43b0e,
+ 0x000f0002,
+ 0x007180ad,
+ 0x0000002d,
+ 0xdd0442ff,
+ 0x000f0002,
+ 0x007180ae,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x007180af,
+ 0x0000002d,
+ 0xdd060082,
+ 0x000f0002,
+ 0x007180b0,
+ 0x00000038,
+ 0x300001e0,
+ 0x000f0002,
+ 0x007180b1,
+ 0x00000039,
+ 0xd0000160,
+ 0x000f0002,
+ 0x007180b2,
+ 0x00000079,
+ 0xd1b13b7c,
+ 0x000f0002,
+ 0x007180b3,
+ 0x0000002d,
+ 0xdde00fe3,
+ 0x000f0002,
+ 0x007180b4,
+ 0x00000049,
+ 0xd08030e4,
+ 0x000f0002,
+ 0x007180b5,
+ 0x00000079,
+ 0xdd317b7c,
+ 0x000f0002,
+ 0x007180b6,
+ 0x00000079,
+ 0xdd313b7c,
+ 0x000f0002,
+ 0x007180b7,
+ 0x0000007d,
+ 0xfd374082,
+ 0x000f0002,
+ 0x007180b8,
+ 0x00000008,
+ 0x017d3b76,
+ 0x000f0002,
+ 0x007180b9,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180ba,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180bb,
+ 0x00000049,
+ 0xdd000387,
+ 0x000f0002,
+ 0x007180bc,
+ 0x00000079,
+ 0xdd310408,
+ 0x000f0002,
+ 0x007180bd,
+ 0x00000079,
+ 0xdd317d7a,
+ 0x000f0002,
+ 0x007180be,
+ 0x00000049,
+ 0xd3003b7c,
+ 0x000f0002,
+ 0x007180bf,
+ 0x00000079,
+ 0xd381bb7c,
+ 0x000f0002,
+ 0x007180c0,
+ 0x0000007f,
+ 0xd101b27c,
+ 0x000f0002,
+ 0x007180c1,
+ 0x00000048,
+ 0x51003264,
+ 0x000f0002,
+ 0x007180c2,
+ 0x0000003d,
+ 0xdd400003,
+ 0x000f0002,
+ 0x007180c3,
+ 0x00000008,
+ 0x01953162,
+ 0x000f0002,
+ 0x007180c4,
+ 0x00000021,
+ 0xd3000666,
+ 0x000f0002,
+ 0x007180c5,
+ 0x00000020,
+ 0x538000e7,
+ 0x000f0002,
+ 0x007180c6,
+ 0x0000003f,
+ 0xdd000800,
+ 0x000f0002,
+ 0x007180c7,
+ 0x00000079,
+ 0xdd01b366,
+ 0x000f0002,
+ 0x007180c8,
+ 0x00000079,
+ 0xdd01b3e7,
+ 0x000f0002,
+ 0x007180c9,
+ 0x00000075,
+ 0xf1018662,
+ 0x000f0002,
+ 0x007180ca,
+ 0x00000075,
+ 0xd201b164,
+ 0x000f0002,
+ 0x007180cb,
+ 0x00000078,
+ 0x1d007b76,
+ 0x000f0002,
+ 0x007180cc,
+ 0x00000025,
+ 0xdd0001e3,
+ 0x000f0002,
+ 0x007180cd,
+ 0x00000008,
+ 0x01b13162,
+ 0x000f0002,
+ 0x007180ce,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180cf,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180d0,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180d1,
+ 0x00000021,
+ 0xe3379f63,
+ 0x000f0002,
+ 0x007180d2,
+ 0x00000049,
+ 0xd3003b7c,
+ 0x000f0002,
+ 0x007180d3,
+ 0x00000079,
+ 0xd381bb7c,
+ 0x000f0002,
+ 0x007180d4,
+ 0x0000007f,
+ 0xd101b27c,
+ 0x000f0002,
+ 0x007180d5,
+ 0x00000048,
+ 0x51003264,
+ 0x000f0002,
+ 0x007180d6,
+ 0x00000075,
+ 0xd201b164,
+ 0x000f0002,
+ 0x007180d7,
+ 0x00000078,
+ 0x1d007b76,
+ 0x000f0002,
+ 0x007180d8,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180d9,
+ 0x00000079,
+ 0xdd01c081,
+ 0x000f0002,
+ 0x007180da,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x007180db,
+ 0x0000002d,
+ 0xdd080803,
+ 0x000f0002,
+ 0x007180dc,
+ 0x00000078,
+ 0x3d01c081,
+ 0x000f0002,
+ 0x007180dd,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e8,
+ 0x00000049,
+ 0xd18e3b03,
+ 0x000f0002,
+ 0x007180e9,
+ 0x0000002f,
+ 0xd18100e3,
+ 0x000f0002,
+ 0x007180ea,
+ 0x0000003f,
+ 0xd1801803,
+ 0x000f0002,
+ 0x007180eb,
+ 0x00000049,
+ 0xd1043b03,
+ 0x000f0002,
+ 0x007180ec,
+ 0x0000003f,
+ 0xdd800203,
+ 0x000f0002,
+ 0x007180ed,
+ 0x00000049,
+ 0xd2043b02,
+ 0x000f0002,
+ 0x007180ee,
+ 0x00000049,
+ 0xd2843b00,
+ 0x000f0002,
+ 0x007180ef,
+ 0x00000025,
+ 0xdd0000e2,
+ 0x000f0002,
+ 0x007180f0,
+ 0x00000094,
+ 0x00134162,
+ 0x000f0002,
+ 0x007180f1,
+ 0x00000094,
+ 0x000b4362,
+ 0x000f0002,
+ 0x007180f2,
+ 0x00000094,
+ 0x001548e2,
+ 0x000f0002,
+ 0x007180f3,
+ 0x00000094,
+ 0x001b4962,
+ 0x000f0002,
+ 0x007180f4,
+ 0x00000094,
+ 0x002f4076,
+ 0x000f0002,
+ 0x007180f5,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x007180f6,
+ 0x0000001d,
+ 0xfd2b80e5,
+ 0x000f0002,
+ 0x007180f7,
+ 0x00000030,
+ 0x31838063,
+ 0x000f0002,
+ 0x007180f8,
+ 0x00000030,
+ 0x11828063,
+ 0x000f0002,
+ 0x007180f9,
+ 0x0000001d,
+ 0xfd2580e5,
+ 0x000f0002,
+ 0x007180fa,
+ 0x00000030,
+ 0x31830063,
+ 0x000f0002,
+ 0x007180fb,
+ 0x00000030,
+ 0x11820063,
+ 0x000f0002,
+ 0x007180fc,
+ 0x0000002f,
+ 0xd18100e3,
+ 0x000f0002,
+ 0x007180fd,
+ 0x0000001d,
+ 0xfd0980e5,
+ 0x000f0002,
+ 0x007180fe,
+ 0x00000030,
+ 0x3183d363,
+ 0x000f0002,
+ 0x007180ff,
+ 0x00000030,
+ 0x1183d263,
+ 0x000f0002,
+ 0x00718100,
+ 0x0000002f,
+ 0xd18100e3,
+ 0x000f0002,
+ 0x00718101,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718102,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718103,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718104,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718105,
+ 0x00000025,
+ 0xd2000264,
+ 0x000f0002,
+ 0x00718106,
+ 0x00000018,
+ 0x7d77fd7a,
+ 0x000f0002,
+ 0x00718107,
+ 0x00000049,
+ 0xde203b63,
+ 0x000f0002,
+ 0x00718108,
+ 0x00000049,
+ 0xde803b79,
+ 0x000f0002,
+ 0x00718109,
+ 0x00000021,
+ 0xd18000e3,
+ 0x000f0002,
+ 0x0071810a,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x0071810b,
+ 0x00000049,
+ 0xdd0031e3,
+ 0x000f0002,
+ 0x0071810c,
+ 0x00000069,
+ 0xdd0e3b78,
+ 0x000f0002,
+ 0x0071810d,
+ 0x00000061,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x0071810e,
+ 0x0000003f,
+ 0xdd000184,
+ 0x000f0002,
+ 0x0071810f,
+ 0x0000003f,
+ 0xdd000001,
+ 0x000f0002,
+ 0x00718110,
+ 0x00000035,
+ 0xdd0000fa,
+ 0x000f0002,
+ 0x00718111,
+ 0x00000018,
+ 0x3b7f3b76,
+ 0x000f0002,
+ 0x00718112,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718113,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718114,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718115,
+ 0x00000021,
+ 0xd18000e3,
+ 0x000f0002,
+ 0x00718116,
+ 0x00000069,
+ 0xdd043b79,
+ 0x000f0002,
+ 0x00718117,
+ 0x00000061,
+ 0xf18000e3,
+ 0x000f0002,
+ 0x00718118,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718119,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x0071811a,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x0071811b,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x0071811c,
+ 0x00000025,
+ 0xd2000264,
+ 0x000f0002,
+ 0x0071811d,
+ 0x00000098,
+ 0x605dbb76,
+ 0x000f0002,
+ 0x0071811e,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x0071811f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718120,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718121,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718122,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718123,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718124,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718125,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718126,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718127,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718128,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718129,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718130,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718131,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718132,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718133,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718134,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718135,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718136,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718137,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718138,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718139,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718140,
+ 0x00000049,
+ 0xd4083b01,
+ 0x000f0002,
+ 0x00718141,
+ 0x00000009,
+ 0xc28b3d7a,
+ 0x000f0002,
+ 0x00718142,
+ 0x0000003f,
+ 0xd4000380,
+ 0x000f0002,
+ 0x00718143,
+ 0x00000009,
+ 0xc28b3d7a,
+ 0x000f0002,
+ 0x00718144,
+ 0x00000049,
+ 0xd40e3b03,
+ 0x000f0002,
+ 0x00718145,
+ 0x0000003f,
+ 0xd6420000,
+ 0x000f0002,
+ 0x00718146,
+ 0x0000002f,
+ 0xd2814080,
+ 0x000f0002,
+ 0x00718147,
+ 0x0000002d,
+ 0xd2840365,
+ 0x000f0002,
+ 0x00718148,
+ 0x0000003f,
+ 0xd6800080,
+ 0x000f0002,
+ 0x00718149,
+ 0x0000003f,
+ 0xdd040004,
+ 0x000f0002,
+ 0x0071814a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071814b,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x0071814c,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x0071814d,
+ 0x00000031,
+ 0xd303d265,
+ 0x000f0002,
+ 0x0071814e,
+ 0x00000049,
+ 0xde403b66,
+ 0x000f0002,
+ 0x0071814f,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718150,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718151,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718152,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718153,
+ 0x00000049,
+ 0xd5803b7e,
+ 0x000f0002,
+ 0x00718154,
+ 0x00000021,
+ 0xde4000e6,
+ 0x000f0002,
+ 0x00718155,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718156,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718157,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718158,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718159,
+ 0x00000049,
+ 0xd5003b7e,
+ 0x000f0002,
+ 0x0071815a,
+ 0x00000079,
+ 0xdd013b76,
+ 0x000f0002,
+ 0x0071815b,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x0071815c,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x0071815d,
+ 0x00000079,
+ 0xdd01bb76,
+ 0x000f0002,
+ 0x0071815e,
+ 0x00000075,
+ 0xfd0180e8,
+ 0x000f0002,
+ 0x0071815f,
+ 0x00000094,
+ 0x00154168,
+ 0x000f0002,
+ 0x00718160,
+ 0x00000094,
+ 0x002544e8,
+ 0x000f0002,
+ 0x00718161,
+ 0x00000094,
+ 0x002341e8,
+ 0x000f0002,
+ 0x00718162,
+ 0x00000094,
+ 0x00174568,
+ 0x000f0002,
+ 0x00718163,
+ 0x00000094,
+ 0x00154268,
+ 0x000f0002,
+ 0x00718164,
+ 0x00000094,
+ 0x002742e8,
+ 0x000f0002,
+ 0x00718165,
+ 0x00000094,
+ 0x002d4368,
+ 0x000f0002,
+ 0x00718166,
+ 0x00000094,
+ 0x002d4468,
+ 0x000f0002,
+ 0x00718167,
+ 0x00000094,
+ 0x003343e8,
+ 0x000f0002,
+ 0x00718168,
+ 0x00000004,
+ 0x03973b76,
+ 0x000f0002,
+ 0x00718169,
+ 0x0000000d,
+ 0xe30dc165,
+ 0x000f0002,
+ 0x0071816a,
+ 0x00000030,
+ 0x32030076,
+ 0x000f0002,
+ 0x0071816b,
+ 0x00000030,
+ 0x12020076,
+ 0x000f0002,
+ 0x0071816c,
+ 0x0000003f,
+ 0xd4800000,
+ 0x000f0002,
+ 0x0071816d,
+ 0x0000003f,
+ 0xd1808000,
+ 0x000f0002,
+ 0x0071816e,
+ 0x0000000d,
+ 0xe33fc165,
+ 0x000f0002,
+ 0x0071816f,
+ 0x00000030,
+ 0x32046076,
+ 0x000f0002,
+ 0x00718170,
+ 0x00000030,
+ 0x12044076,
+ 0x000f0002,
+ 0x00718171,
+ 0x0000003f,
+ 0xd4828000,
+ 0x000f0002,
+ 0x00718172,
+ 0x0000003f,
+ 0xd1808000,
+ 0x000f0002,
+ 0x00718173,
+ 0x0000000d,
+ 0xe33fc165,
+ 0x000f0002,
+ 0x00718174,
+ 0x00000030,
+ 0x32042076,
+ 0x000f0002,
+ 0x00718175,
+ 0x00000030,
+ 0x12040076,
+ 0x000f0002,
+ 0x00718176,
+ 0x0000003f,
+ 0xd4820000,
+ 0x000f0002,
+ 0x00718177,
+ 0x0000000d,
+ 0xe363c165,
+ 0x000f0002,
+ 0x00718178,
+ 0x00000030,
+ 0x32032076,
+ 0x000f0002,
+ 0x00718179,
+ 0x00000030,
+ 0x12030076,
+ 0x000f0002,
+ 0x0071817a,
+ 0x0000003f,
+ 0xd4830000,
+ 0x000f0002,
+ 0x0071817b,
+ 0x00000049,
+ 0xd2803b76,
+ 0x000f0002,
+ 0x0071817c,
+ 0x0000000d,
+ 0xe30dc165,
+ 0x000f0002,
+ 0x0071817d,
+ 0x00000030,
+ 0x32038076,
+ 0x000f0002,
+ 0x0071817e,
+ 0x00000030,
+ 0x12028076,
+ 0x000f0002,
+ 0x0071817f,
+ 0x0000003f,
+ 0xd4810000,
+ 0x000f0002,
+ 0x00718180,
+ 0x0000003f,
+ 0xd6020000,
+ 0x000f0002,
+ 0x00718181,
+ 0x0000003f,
+ 0xd1810000,
+ 0x000f0002,
+ 0x00718182,
+ 0x0000000d,
+ 0xe33fc165,
+ 0x000f0002,
+ 0x00718183,
+ 0x00000030,
+ 0x32042076,
+ 0x000f0002,
+ 0x00718184,
+ 0x00000030,
+ 0x12040076,
+ 0x000f0002,
+ 0x00718185,
+ 0x0000003f,
+ 0xd4820000,
+ 0x000f0002,
+ 0x00718186,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x00718187,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x00718188,
+ 0x00000079,
+ 0xdd01bb76,
+ 0x000f0002,
+ 0x00718189,
+ 0x0000003f,
+ 0xd2001803,
+ 0x000f0002,
+ 0x0071818a,
+ 0x0000003f,
+ 0xd1810000,
+ 0x000f0002,
+ 0x0071818b,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x0071818c,
+ 0x00000098,
+ 0x80693b64,
+ 0x000f0002,
+ 0x0071818d,
+ 0x00000051,
+ 0xf20000e4,
+ 0x000f0002,
+ 0x0071818e,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x0071818f,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718190,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718191,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718192,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x00718193,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x00718194,
+ 0x00000049,
+ 0xd3c03b38,
+ 0x000f0002,
+ 0x00718195,
+ 0x00000049,
+ 0xdd003b64,
+ 0x000f0002,
+ 0x00718196,
+ 0x00000051,
+ 0xf20000e4,
+ 0x000f0002,
+ 0x00718197,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718198,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718199,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x0071819a,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x0071819b,
+ 0x00000049,
+ 0xd3a03b38,
+ 0x000f0002,
+ 0x0071819c,
+ 0x00000019,
+ 0xdd61bb76,
+ 0x000f0002,
+ 0x0071819d,
+ 0x00000049,
+ 0xdd003b67,
+ 0x000f0002,
+ 0x0071819e,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x0071819f,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x007181a0,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x007181a1,
+ 0x00000079,
+ 0xdd01bb76,
+ 0x000f0002,
+ 0x007181a2,
+ 0x0000003f,
+ 0xd2001803,
+ 0x000f0002,
+ 0x007181a3,
+ 0x0000003f,
+ 0xd1808000,
+ 0x000f0002,
+ 0x007181a4,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x007181a5,
+ 0x00000098,
+ 0x80373b64,
+ 0x000f0002,
+ 0x007181a6,
+ 0x00000051,
+ 0xf20000e4,
+ 0x000f0002,
+ 0x007181a7,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x007181a8,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007181a9,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181aa,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007181ab,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x007181ac,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x007181ad,
+ 0x00000049,
+ 0xd3803b38,
+ 0x000f0002,
+ 0x007181ae,
+ 0x00000019,
+ 0xdd6fbb76,
+ 0x000f0002,
+ 0x007181af,
+ 0x00000049,
+ 0xdd003b67,
+ 0x000f0002,
+ 0x007181b0,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x007181b1,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x007181b2,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x007181b3,
+ 0x00000079,
+ 0xdd01bb63,
+ 0x000f0002,
+ 0x007181b4,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x007181b5,
+ 0x00000098,
+ 0x80173b64,
+ 0x000f0002,
+ 0x007181b6,
+ 0x00000049,
+ 0xde403b64,
+ 0x000f0002,
+ 0x007181b7,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x007181b8,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007181b9,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181ba,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007181bb,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x007181bc,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x007181bd,
+ 0x00000021,
+ 0xd20000e4,
+ 0x000f0002,
+ 0x007181be,
+ 0x00000019,
+ 0xd3ef7b7e,
+ 0x000f0002,
+ 0x007181bf,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x007181c0,
+ 0x0000003f,
+ 0xd6800000,
+ 0x000f0002,
+ 0x007181c1,
+ 0x0000003f,
+ 0xdd040004,
+ 0x000f0002,
+ 0x007181c2,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181c3,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x007181c4,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x007181c5,
+ 0x0000003f,
+ 0xdd000000,
+ 0x000f0002,
+ 0x007181c6,
+ 0x0000002d,
+ 0xdd540180,
+ 0x000f0002,
+ 0x007181c7,
+ 0x00000079,
+ 0xf3e08076,
+ 0x000f0002,
+ 0x007181c8,
+ 0x00000049,
+ 0xd600367a,
+ 0x000f0002,
+ 0x007181c9,
+ 0x00000079,
+ 0xdd01fb76,
+ 0x000f0002,
+ 0x007181ca,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181cb,
+ 0x00000049,
+ 0xdd003b03,
+ 0x000f0002,
+ 0x007181cc,
+ 0x00000059,
+ 0xfd003b76,
+ 0x000f0002,
+ 0x007181cd,
+ 0x0000003f,
+ 0xdd801c03,
+ 0x000f0002,
+ 0x007181ce,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181cf,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d0,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d1,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x007181d2,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007181d3,
+ 0x00000031,
+ 0xd483886b,
+ 0x000f0002,
+ 0x007181d4,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x007181d5,
+ 0x00000079,
+ 0xf1819076,
+ 0x000f0002,
+ 0x007181d6,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x007181d7,
+ 0x00000098,
+ 0x8053bb76,
+ 0x000f0002,
+ 0x007181d8,
+ 0x00000019,
+ 0xdd7f7b79,
+ 0x000f0002,
+ 0x007181d9,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x007181da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fe,
+ 0x0000003f,
+ 0xdd800203,
+ 0x000f0002,
+ 0x007181ff,
+ 0x00000049,
+ 0xd1843b02,
+ 0x000f0002,
+ 0x00718200,
+ 0x00000049,
+ 0xdd003b03,
+ 0x000f0002,
+ 0x00718201,
+ 0x00000069,
+ 0xdd003b7a,
+ 0x000f0002,
+ 0x00718202,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x00718203,
+ 0x00000065,
+ 0xf1800263,
+ 0x000f0002,
+ 0x00718204,
+ 0x00000018,
+ 0x7d7d3b76,
+ 0x000f0002,
+ 0x00718205,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x00718206,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718207,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718208,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718209,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718210,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718211,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718212,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718213,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718214,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718215,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718216,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718217,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718218,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718219,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718220,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718221,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718222,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718223,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718224,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718225,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718226,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718227,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718228,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718229,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718230,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718231,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718232,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718233,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718234,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718235,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718236,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718237,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718238,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718239,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718240,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718241,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718242,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718243,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718244,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718245,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718246,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718247,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718248,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718249,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718250,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718251,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718252,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718253,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718254,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718255,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718256,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718257,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718258,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718259,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718260,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718261,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718262,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718263,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718264,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718265,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718266,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718267,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718268,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718269,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718270,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718271,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718272,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718273,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718274,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718275,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718276,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718277,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718278,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718279,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718280,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718281,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718282,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718283,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718284,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718285,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718286,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718287,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718288,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718289,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718290,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718291,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718292,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718293,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718294,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718295,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718296,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718297,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718298,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718299,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718300,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718301,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718302,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718303,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718304,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718305,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718306,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718307,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718308,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718309,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718310,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718311,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718312,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718313,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718314,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718315,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718316,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718317,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718318,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718319,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718320,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718321,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718322,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718323,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718324,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718325,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718326,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718327,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718328,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718329,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718330,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718331,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718332,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718333,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718334,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718335,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718336,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718337,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718338,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718339,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718340,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718341,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718342,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718343,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718344,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718345,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718346,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718347,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718348,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718349,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718350,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718351,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718352,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718353,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718354,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718355,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718356,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718357,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718358,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718359,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718360,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718361,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718362,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718363,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718364,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718365,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718366,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718367,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718368,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718369,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718370,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718371,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718372,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718373,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718374,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718375,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718376,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718377,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718378,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718379,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718380,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718381,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718382,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718383,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718384,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718385,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718386,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718387,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718388,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718389,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718390,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718391,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718392,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718393,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718394,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718395,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718396,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718397,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718398,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718399,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718400,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718401,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718402,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718403,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718404,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718405,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718406,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718407,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718408,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718409,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718410,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718411,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718412,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718413,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718414,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718415,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718416,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718417,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718418,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718419,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718420,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718421,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718422,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718423,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718424,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718425,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718426,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718427,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718428,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718429,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718430,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718431,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718432,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718433,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718434,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718435,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718436,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718437,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718438,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718439,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718440,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718441,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718442,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718443,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718444,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718445,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718446,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718447,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718448,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718449,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718450,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718451,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718452,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718453,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718454,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718455,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718456,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718457,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718458,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718459,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718460,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718461,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718462,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718463,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718464,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718465,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718466,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718467,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718468,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718469,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718470,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718471,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718472,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718473,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718474,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718475,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718476,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718477,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718478,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718479,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718480,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718481,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718482,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718483,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718484,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718485,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718486,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718487,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718488,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718489,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718490,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718491,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718492,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718493,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718494,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718495,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718496,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718497,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718498,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718499,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718500,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718501,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718502,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718503,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718504,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718505,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718506,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718507,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718508,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718509,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718510,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718511,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718512,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718513,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718514,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718515,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718516,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718517,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718518,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718519,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718520,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718521,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718522,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718523,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718524,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718525,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718526,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718527,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718528,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718529,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718530,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718531,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718532,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718533,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718534,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718535,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718536,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718537,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718538,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718539,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718540,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718541,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718542,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718543,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718544,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718545,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718546,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718547,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718548,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718549,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718550,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718551,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718552,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718553,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718554,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718555,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718556,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718557,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718558,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718559,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718560,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718561,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718562,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718563,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718564,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718565,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718566,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718567,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718568,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718569,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718570,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718571,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718572,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718573,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718574,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718575,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718576,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718577,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718578,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718579,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718580,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718581,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718582,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718583,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718584,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718585,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718586,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718587,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718588,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718589,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718590,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718591,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718592,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718593,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718594,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718595,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718596,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718597,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718598,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718599,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718600,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718601,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718602,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718603,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718604,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718605,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718606,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718607,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718608,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718609,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718610,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718611,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718612,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718613,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718614,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718615,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718616,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718617,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718618,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718619,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718620,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718621,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718622,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718623,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718624,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718625,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718626,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718627,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718628,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718629,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718630,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718631,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718632,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718633,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718634,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718635,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718636,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718637,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718638,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718639,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718640,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718641,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718642,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718643,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718644,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718645,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718646,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718647,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718648,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718649,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718650,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718651,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718652,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718653,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718654,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718655,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718656,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718657,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718658,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718659,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718660,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718661,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718662,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718663,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718664,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718665,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718666,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718667,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718668,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718669,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718670,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718671,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718672,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718673,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718674,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718675,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718676,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718677,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718678,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718679,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718680,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718681,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718682,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718683,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718684,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718685,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718686,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718687,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718688,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718689,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718690,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718691,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718692,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718693,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718694,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718695,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718696,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718697,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718698,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718699,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718700,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718701,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718702,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718703,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718704,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718705,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718706,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718707,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718708,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718709,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718710,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718711,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718712,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718713,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718714,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718715,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718716,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718717,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718718,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718719,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718720,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718721,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718722,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718723,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718724,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718725,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718726,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718727,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718728,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718729,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718730,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718731,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718732,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718733,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718734,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718735,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718736,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718737,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718738,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718739,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718740,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718741,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718742,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718743,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718744,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718745,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718746,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718747,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718748,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718749,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718750,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718751,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718752,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718753,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718754,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718755,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718756,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718757,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718758,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718759,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718760,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718761,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718762,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718763,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718764,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718765,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718766,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718767,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718768,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718769,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718770,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718771,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718772,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718773,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718774,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718775,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718776,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718777,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718778,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718779,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718780,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718781,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718782,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718783,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718784,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718785,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718786,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718787,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718788,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718789,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718790,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718791,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718792,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718793,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718794,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718795,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718796,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718797,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718798,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718799,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187c0,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x007187c1,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007187c2,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007187c3,
+ 0x0000003d,
+ 0xf780006f,
+/* FINISH INIT Descriptor */
+ 0x000f0002,
+ 0x807187c4,
+ 0x0000003d,
+ 0xf780006f,
+};
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 5ee14764fd74..30b1cca8144c 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.78"
-#define DRV_MODULE_RELDATE "July 11, 2007"
+#define DRV_MODULE_VERSION "3.83"
+#define DRV_MODULE_RELDATE "October 10, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -198,6 +198,10 @@ static struct pci_device_id tg3_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -312,6 +316,16 @@ static u32 tg3_read32(struct tg3 *tp, u32 off)
return (readl(tp->regs + off));
}
+static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
+{
+ writel(val, tp->aperegs + off);
+}
+
+static u32 tg3_ape_read32(struct tg3 *tp, u32 off)
+{
+ return (readl(tp->aperegs + off));
+}
+
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;
@@ -498,6 +512,73 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
+static void tg3_ape_lock_init(struct tg3 *tp)
+{
+ int i;
+
+ /* Make sure the driver hasn't any stale locks. */
+ for (i = 0; i < 8; i++)
+ tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
+ APE_LOCK_GRANT_DRIVER);
+}
+
+static int tg3_ape_lock(struct tg3 *tp, int locknum)
+{
+ int i, off;
+ int ret = 0;
+ u32 status;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return 0;
+
+ switch (locknum) {
+ case TG3_APE_LOCK_MEM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ off = 4 * locknum;
+
+ tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+
+ /* Wait for up to 1 millisecond to acquire lock. */
+ for (i = 0; i < 100; i++) {
+ status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+ if (status == APE_LOCK_GRANT_DRIVER)
+ break;
+ udelay(10);
+ }
+
+ if (status != APE_LOCK_GRANT_DRIVER) {
+ /* Revoke the lock request. */
+ tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+ APE_LOCK_GRANT_DRIVER);
+
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+static void tg3_ape_unlock(struct tg3 *tp, int locknum)
+{
+ int off;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return;
+
+ switch (locknum) {
+ case TG3_APE_LOCK_MEM:
+ break;
+ default:
+ return;
+ }
+
+ off = 4 * locknum;
+ tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+}
+
static void tg3_disable_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
@@ -574,7 +655,7 @@ static void tg3_restart_ints(struct tg3 *tp)
static inline void tg3_netif_stop(struct tg3 *tp)
{
tp->dev->trans_start = jiffies; /* prevent tx timeout */
- netif_poll_disable(tp->dev);
+ napi_disable(&tp->napi);
netif_tx_disable(tp->dev);
}
@@ -585,7 +666,7 @@ static inline void tg3_netif_start(struct tg3 *tp)
* so long as all callers are assured to have free tx slots
* (such as after tg3_init_hw)
*/
- netif_poll_enable(tp->dev);
+ napi_enable(&tp->napi);
tp->hw_status->status |= SD_STATUS_UPDATED;
tg3_enable_ints(tp);
}
@@ -595,7 +676,8 @@ static void tg3_switch_clocks(struct tg3 *tp)
u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
u32 orig_clock_ctrl;
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+ if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
return;
orig_clock_ctrl = clock_ctrl;
@@ -1400,6 +1482,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK |
CLOCK_CTRL_PWRDOWN_PLL133, 40);
} else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+ (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) {
/* do nothing */
} else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
@@ -1444,7 +1527,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}
if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
tg3_power_down_phy(tp);
tg3_frob_aux_power(tp);
@@ -3471,11 +3555,9 @@ next_pkt_nopost:
return received;
}
-static int tg3_poll(struct net_device *netdev, int *budget)
+static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
{
- struct tg3 *tp = netdev_priv(netdev);
struct tg3_hw_status *sblk = tp->hw_status;
- int done;
/* handle link change and other phy events */
if (!(tp->tg3_flags &
@@ -3493,44 +3575,59 @@ static int tg3_poll(struct net_device *netdev, int *budget)
/* run TX completion thread */
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
tg3_tx(tp);
- if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
- netif_rx_complete(netdev);
- schedule_work(&tp->reset_task);
- return 0;
- }
+ if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ return work_done;
}
/* run RX thread, within the bounds set by NAPI.
* All RX "locking" is done by ensuring outside
- * code synchronizes with dev->poll()
+ * code synchronizes with tg3->napi.poll()
*/
- if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
- int orig_budget = *budget;
- int work_done;
+ if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+ work_done += tg3_rx(tp, budget - work_done);
- if (orig_budget > netdev->quota)
- orig_budget = netdev->quota;
+ return work_done;
+}
- work_done = tg3_rx(tp, orig_budget);
+static int tg3_poll(struct napi_struct *napi, int budget)
+{
+ struct tg3 *tp = container_of(napi, struct tg3, napi);
+ int work_done = 0;
+ struct tg3_hw_status *sblk = tp->hw_status;
- *budget -= work_done;
- netdev->quota -= work_done;
- }
+ while (1) {
+ work_done = tg3_poll_work(tp, work_done, budget);
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
- tp->last_tag = sblk->status_tag;
- rmb();
- } else
- sblk->status &= ~SD_STATUS_UPDATED;
+ if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ goto tx_recovery;
+
+ if (unlikely(work_done >= budget))
+ break;
- /* if no more work, tell net stack and NIC we're done */
- done = !tg3_has_work(tp);
- if (done) {
- netif_rx_complete(netdev);
- tg3_restart_ints(tp);
+ if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+ /* tp->last_tag is used in tg3_restart_ints() below
+ * to tell the hw how much work has been processed,
+ * so we must read it before checking for more work.
+ */
+ tp->last_tag = sblk->status_tag;
+ rmb();
+ } else
+ sblk->status &= ~SD_STATUS_UPDATED;
+
+ if (likely(!tg3_has_work(tp))) {
+ netif_rx_complete(tp->dev, napi);
+ tg3_restart_ints(tp);
+ break;
+ }
}
- return (done ? 0 : 1);
+ return work_done;
+
+tx_recovery:
+ /* work_done is guaranteed to be less than budget. */
+ netif_rx_complete(tp->dev, napi);
+ schedule_work(&tp->reset_task);
+ return work_done;
}
static void tg3_irq_quiesce(struct tg3 *tp)
@@ -3577,7 +3674,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id)
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
if (likely(!tg3_irq_sync(tp)))
- netif_rx_schedule(dev); /* schedule NAPI poll */
+ netif_rx_schedule(dev, &tp->napi);
return IRQ_HANDLED;
}
@@ -3602,7 +3699,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id)
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (likely(!tg3_irq_sync(tp)))
- netif_rx_schedule(dev); /* schedule NAPI poll */
+ netif_rx_schedule(dev, &tp->napi);
return IRQ_RETVAL(1);
}
@@ -3644,7 +3741,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp))) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
- netif_rx_schedule(dev); /* schedule NAPI poll */
+ netif_rx_schedule(dev, &tp->napi);
} else {
/* No work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
@@ -3690,7 +3787,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (tg3_irq_sync(tp))
goto out;
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &tp->napi)) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
/* Update last_tag to mark that this status has been
* seen. Because interrupt may be shared, we may be
@@ -3698,7 +3795,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
* if tg3_poll() is not scheduled.
*/
tp->last_tag = sblk->status_tag;
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &tp->napi);
}
out:
return IRQ_RETVAL(handled);
@@ -3737,7 +3834,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
tg3_full_unlock(tp);
del_timer_sync(&tp->timer);
tp->irq_sync = 0;
- netif_poll_enable(tp->dev);
+ napi_enable(&tp->napi);
dev_close(tp->dev);
tg3_full_lock(tp, 0);
}
@@ -3932,7 +4029,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
/* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->poll inside of a software
+ * and TX reclaim runs via tp->napi.poll inside of a software
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
@@ -4087,7 +4184,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
/* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->poll inside of a software
+ * and TX reclaim runs via tp->napi.poll inside of a software
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
@@ -4732,6 +4829,80 @@ static void tg3_disable_nvram_access(struct tg3 *tp)
}
}
+static void tg3_ape_send_event(struct tg3 *tp, u32 event)
+{
+ int i;
+ u32 apedata;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+ if (apedata != APE_SEG_SIG_MAGIC)
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+ if (apedata != APE_FW_STATUS_READY)
+ return;
+
+ /* Wait for up to 1 millisecond for APE to service previous event. */
+ for (i = 0; i < 10; i++) {
+ if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
+ event | APE_EVENT_STATUS_EVENT_PENDING);
+
+ tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ break;
+
+ udelay(100);
+ }
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+}
+
+static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
+{
+ u32 event;
+ u32 apedata;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return;
+
+ switch (kind) {
+ case RESET_KIND_INIT:
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
+ APE_HOST_SEG_SIG_MAGIC);
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
+ APE_HOST_SEG_LEN_MAGIC);
+ apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
+ tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
+ tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
+ APE_HOST_DRIVER_ID_MAGIC);
+ tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
+ APE_HOST_BEHAV_NO_PHYLOCK);
+
+ event = APE_EVENT_STATUS_STATE_START;
+ break;
+ case RESET_KIND_SHUTDOWN:
+ event = APE_EVENT_STATUS_STATE_UNLOAD;
+ break;
+ case RESET_KIND_SUSPEND:
+ event = APE_EVENT_STATUS_STATE_SUSPEND;
+ break;
+ default:
+ return;
+ }
+
+ event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
+
+ tg3_ape_send_event(tp, event);
+}
+
/* tp->lock is held. */
static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
{
@@ -4759,6 +4930,10 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
break;
};
}
+
+ if (kind == RESET_KIND_INIT ||
+ kind == RESET_KIND_SUSPEND)
+ tg3_ape_driver_state_change(tp, kind);
}
/* tp->lock is held. */
@@ -4780,6 +4955,9 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
break;
};
}
+
+ if (kind == RESET_KIND_SHUTDOWN)
+ tg3_ape_driver_state_change(tp, kind);
}
/* tp->lock is held. */
@@ -4847,6 +5025,68 @@ static int tg3_poll_fw(struct tg3 *tp)
return 0;
}
+/* Save PCI command register before chip reset */
+static void tg3_save_pci_state(struct tg3 *tp)
+{
+ u32 val;
+
+ pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
+ tp->pci_cmd = val;
+}
+
+/* Restore PCI state after chip reset */
+static void tg3_restore_pci_state(struct tg3 *tp)
+{
+ u32 val;
+
+ /* Re-enable indirect register accesses. */
+ pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+ tp->misc_host_ctrl);
+
+ /* Set MAX PCI retry to zero. */
+ val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+ (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+ val |= PCISTATE_RETRY_SAME_DMA;
+ /* Allow reads and writes to the APE register and memory space. */
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+ PCISTATE_ALLOW_APE_SHMEM_WR;
+ pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+ pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+
+ /* Make sure PCI-X relaxed ordering bit is clear. */
+ if (tp->pcix_cap) {
+ u16 pcix_cmd;
+
+ pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ &pcix_cmd);
+ pcix_cmd &= ~PCI_X_CMD_ERO;
+ pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ pcix_cmd);
+ }
+
+ if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+
+ /* Chip reset on 5780 will reset MSI enable bit,
+ * so need to restore it.
+ */
+ if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+ u16 ctrl;
+
+ pci_read_config_word(tp->pdev,
+ tp->msi_cap + PCI_MSI_FLAGS,
+ &ctrl);
+ pci_write_config_word(tp->pdev,
+ tp->msi_cap + PCI_MSI_FLAGS,
+ ctrl | PCI_MSI_FLAGS_ENABLE);
+ val = tr32(MSGINT_MODE);
+ tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
+ }
+ }
+}
+
static void tg3_stop_fw(struct tg3 *);
/* tp->lock is held. */
@@ -4863,9 +5103,17 @@ static int tg3_chip_reset(struct tg3 *tp)
*/
tp->nvram_lock_cnt = 0;
+ /* GRC_MISC_CFG core clock reset will clear the memory
+ * enable bit in PCI register 4 and the MSI enable bit
+ * on some chips, so we save relevant registers here.
+ */
+ tg3_save_pci_state(tp);
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
tw32(GRC_FASTBOOT_PC, 0);
/*
@@ -4961,50 +5209,14 @@ static int tg3_chip_reset(struct tg3 *tp)
pci_write_config_dword(tp->pdev, 0xd8, 0xf5000);
}
- /* Re-enable indirect register accesses. */
- pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
- tp->misc_host_ctrl);
-
- /* Set MAX PCI retry to zero. */
- val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
- (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
- val |= PCISTATE_RETRY_SAME_DMA;
- pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
-
- pci_restore_state(tp->pdev);
+ tg3_restore_pci_state(tp);
tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
- /* Make sure PCI-X relaxed ordering bit is clear. */
- pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
- val &= ~PCIX_CAPS_RELAXED_ORDERING;
- pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
-
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
- u32 val;
-
- /* Chip reset on 5780 will reset MSI enable bit,
- * so need to restore it.
- */
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
- u16 ctrl;
-
- pci_read_config_word(tp->pdev,
- tp->msi_cap + PCI_MSI_FLAGS,
- &ctrl);
- pci_write_config_word(tp->pdev,
- tp->msi_cap + PCI_MSI_FLAGS,
- ctrl | PCI_MSI_FLAGS_ENABLE);
- val = tr32(MSGINT_MODE);
- tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
- }
-
+ val = 0;
+ if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
val = tr32(MEMARB_MODE);
- tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
-
- } else
- tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+ tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
tg3_stop_fw(tp);
@@ -5014,7 +5226,7 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32(GRC_MODE, tp->grc_mode);
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
- u32 val = tr32(0xc4);
+ val = tr32(0xc4);
tw32(0xc4, val | (1 << 15));
}
@@ -5043,7 +5255,7 @@ static int tg3_chip_reset(struct tg3 *tp)
if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
- u32 val = tr32(0x7c00);
+ val = tr32(0x7c00);
tw32(0x7c00, val | (1 << 25));
}
@@ -5069,7 +5281,8 @@ static int tg3_chip_reset(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
u32 val;
int i;
@@ -6126,14 +6339,22 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tg3_write_sig_legacy(tp, RESET_KIND_INIT);
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0) {
+ val = tr32(TG3_CPMU_CTRL);
+ val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
+ tw32(TG3_CPMU_CTRL, val);
+ }
+
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision. But do not set this on PCI Express
- * chips.
+ * chips and don't even touch the clocks if the CPMU is present.
*/
- if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
- tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
- tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+ if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) {
+ if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+ tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
+ tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+ }
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
@@ -6142,6 +6363,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3PCI_PCISTATE, val);
}
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ /* Allow reads and writes to the
+ * APE register and memory space.
+ */
+ val = tr32(TG3PCI_PCISTATE);
+ val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+ PCISTATE_ALLOW_APE_SHMEM_WR;
+ tw32(TG3PCI_PCISTATE, val);
+ }
+
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
/* Enable some hw fixes. */
val = tr32(TG3PCI_MSI_DATA);
@@ -6158,10 +6389,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- /* This value is determined during the probe time DMA
- * engine test, tg3_test_dma.
- */
- tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+ /* This value is determined during the probe time DMA
+ * engine test, tg3_test_dma.
+ */
+ tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ }
tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
GRC_MODE_4X_NIC_SEND_RINGS |
@@ -6395,6 +6629,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+ rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
+ RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
+ RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
+
/* If statement applies to 5705 and 5750 PCI devices only */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
@@ -6556,22 +6795,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Enable host coalescing bug fix */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787))
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
val |= (1 << 29);
tw32_f(WDMAC_MODE, val);
udelay(40);
- if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
- val = tr32(TG3PCI_X_CAPS);
+ if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ u16 pcix_cmd;
+
+ pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ &pcix_cmd);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
- val &= ~PCIX_CAPS_BURST_MASK;
- val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+ pcix_cmd &= ~PCI_X_CMD_MAX_READ;
+ pcix_cmd |= PCI_X_CMD_READ_2K;
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
- val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
- val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+ pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ);
+ pcix_cmd |= PCI_X_CMD_READ_2K;
}
- tw32(TG3PCI_X_CAPS, val);
+ pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ pcix_cmd);
}
tw32_f(RDMAC_MODE, rdmac_mode);
@@ -6580,7 +6825,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
- tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ tw32(SNDDATAC_MODE,
+ SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
+ else
+ tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
@@ -6607,7 +6858,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(100);
tp->rx_mode = RX_MODE_ENABLE;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -6737,6 +6989,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
break;
};
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ /* Write our heartbeat update interval to APE. */
+ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
+ APE_HOST_HEARTBEAT_INT_DISABLE);
+
tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
return 0;
@@ -7104,6 +7361,10 @@ static int tg3_open(struct net_device *dev)
} else if (pci_enable_msi(tp->pdev) == 0) {
u32 msi_mode;
+ /* Hardware bug - MSI won't work if INTX disabled. */
+ if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+ pci_intx(tp->pdev, 1);
+
msi_mode = tr32(MSGINT_MODE);
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
@@ -7120,6 +7381,8 @@ static int tg3_open(struct net_device *dev)
return err;
}
+ napi_enable(&tp->napi);
+
tg3_full_lock(tp, 0);
err = tg3_init_hw(tp, 1);
@@ -7147,6 +7410,7 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp);
if (err) {
+ napi_disable(&tp->napi);
free_irq(tp->pdev->irq, dev);
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
@@ -7172,6 +7436,8 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp);
+ napi_disable(&tp->napi);
+
return err;
}
@@ -7433,6 +7699,7 @@ static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
+ napi_disable(&tp->napi);
cancel_work_sync(&tp->reset_task);
netif_stop_queue(dev);
@@ -7968,7 +8235,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
buf = data;
if (b_offset || odd_len) {
buf = kmalloc(len, GFP_KERNEL);
- if (buf == 0)
+ if (!buf)
return -ENOMEM;
if (b_offset)
memcpy(buf, &start, 4);
@@ -8048,7 +8315,8 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.autoneg = cmd->autoneg;
if (cmd->autoneg == AUTONEG_ENABLE) {
- tp->link_config.advertising = cmd->advertising;
+ tp->link_config.advertising = (cmd->advertising |
+ ADVERTISED_Autoneg);
tp->link_config.speed = SPEED_INVALID;
tp->link_config.duplex = DUPLEX_INVALID;
} else {
@@ -8136,10 +8404,12 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
}
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
- if (value)
+ if (value) {
dev->features |= NETIF_F_TSO6;
- else
- dev->features &= ~NETIF_F_TSO6;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ dev->features |= NETIF_F_TSO_ECN;
+ } else
+ dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
}
return ethtool_op_set_tso(dev, value);
}
@@ -8317,7 +8587,9 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
ethtool_op_set_tx_ipv6_csum(dev, data);
else
ethtool_op_set_tx_csum(dev, data);
@@ -8325,14 +8597,16 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
return 0;
}
-static int tg3_get_stats_count (struct net_device *dev)
+static int tg3_get_sset_count (struct net_device *dev, int sset)
{
- return TG3_NUM_STATS;
-}
-
-static int tg3_get_test_count (struct net_device *dev)
-{
- return TG3_NUM_TEST;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return TG3_NUM_TEST;
+ case ETH_SS_STATS:
+ return TG3_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
@@ -8397,7 +8671,7 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
static int tg3_test_nvram(struct tg3 *tp)
{
u32 *buf, csum, magic;
- int i, j, err = 0, size;
+ int i, j, k, err = 0, size;
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
return -EIO;
@@ -8451,7 +8725,6 @@ static int tg3_test_nvram(struct tg3 *tp)
u8 data[NVRAM_SELFBOOT_DATA_SIZE];
u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
u8 *buf8 = (u8 *) buf;
- int j, k;
/* Separate the parity bits and the data bytes. */
for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
@@ -8812,7 +9085,9 @@ static int tg3_test_memory(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
mem_tbl = mem_tbl_5755;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mem_tbl = mem_tbl_5906;
@@ -9009,6 +9284,7 @@ out:
static int tg3_test_loopback(struct tg3 *tp)
{
int err = 0;
+ u32 cpmuctrl = 0;
if (!netif_running(tp->dev))
return TG3_LOOPBACK_FAILED;
@@ -9017,8 +9293,40 @@ static int tg3_test_loopback(struct tg3 *tp)
if (err)
return TG3_LOOPBACK_FAILED;
+ if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
+ int i;
+ u32 status;
+
+ tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER);
+
+ /* Wait for up to 40 microseconds to acquire lock. */
+ for (i = 0; i < 4; i++) {
+ status = tr32(TG3_CPMU_MUTEX_GNT);
+ if (status == CPMU_MUTEX_GNT_DRIVER)
+ break;
+ udelay(10);
+ }
+
+ if (status != CPMU_MUTEX_GNT_DRIVER)
+ return TG3_LOOPBACK_FAILED;
+
+ cpmuctrl = tr32(TG3_CPMU_CTRL);
+
+ /* Turn off power management based on link speed. */
+ tw32(TG3_CPMU_CTRL,
+ cpmuctrl & ~CPMU_CTRL_LINK_SPEED_MODE);
+ }
+
if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
err |= TG3_MAC_LOOPBACK_FAILED;
+
+ if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
+ tw32(TG3_CPMU_CTRL, cpmuctrl);
+
+ /* Release the mutex */
+ tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
+ }
+
if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
err |= TG3_PHY_LOOPBACK_FAILED;
@@ -9257,21 +9565,16 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.set_pauseparam = tg3_set_pauseparam,
.get_rx_csum = tg3_get_rx_csum,
.set_rx_csum = tg3_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = tg3_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
- .self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
.phys_id = tg3_phys_id,
- .get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
.get_coalesce = tg3_get_coalesce,
.set_coalesce = tg3_set_coalesce,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_sset_count = tg3_get_sset_count,
};
static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -9529,6 +9832,81 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
}
}
+static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
+{
+ u32 nvcfg1, protect = 0;
+
+ nvcfg1 = tr32(NVRAM_CFG1);
+
+ /* NVRAM protection for TPM */
+ if (nvcfg1 & (1 << 27)) {
+ tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM;
+ protect = 1;
+ }
+
+ nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK;
+ switch (nvcfg1) {
+ case FLASH_5761VENDOR_ATMEL_ADB021D:
+ case FLASH_5761VENDOR_ATMEL_ADB041D:
+ case FLASH_5761VENDOR_ATMEL_ADB081D:
+ case FLASH_5761VENDOR_ATMEL_ADB161D:
+ case FLASH_5761VENDOR_ATMEL_MDB021D:
+ case FLASH_5761VENDOR_ATMEL_MDB041D:
+ case FLASH_5761VENDOR_ATMEL_MDB081D:
+ case FLASH_5761VENDOR_ATMEL_MDB161D:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+ tp->nvram_pagesize = 256;
+ break;
+ case FLASH_5761VENDOR_ST_A_M45PE20:
+ case FLASH_5761VENDOR_ST_A_M45PE40:
+ case FLASH_5761VENDOR_ST_A_M45PE80:
+ case FLASH_5761VENDOR_ST_A_M45PE16:
+ case FLASH_5761VENDOR_ST_M_M45PE20:
+ case FLASH_5761VENDOR_ST_M_M45PE40:
+ case FLASH_5761VENDOR_ST_M_M45PE80:
+ case FLASH_5761VENDOR_ST_M_M45PE16:
+ tp->nvram_jedecnum = JEDEC_ST;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tp->nvram_pagesize = 256;
+ break;
+ }
+
+ if (protect) {
+ tp->nvram_size = tr32(NVRAM_ADDR_LOCKOUT);
+ } else {
+ switch (nvcfg1) {
+ case FLASH_5761VENDOR_ATMEL_ADB161D:
+ case FLASH_5761VENDOR_ATMEL_MDB161D:
+ case FLASH_5761VENDOR_ST_A_M45PE16:
+ case FLASH_5761VENDOR_ST_M_M45PE16:
+ tp->nvram_size = 0x100000;
+ 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;
+ 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;
+ 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;
+ break;
+ }
+ }
+}
+
static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
{
tp->nvram_jedecnum = JEDEC_ATMEL;
@@ -9568,8 +9946,11 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
tg3_get_5752_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tg3_get_5755_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
tg3_get_5787_nvram_info(tp);
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ tg3_get_5761_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tg3_get_5906_nvram_info(tp);
else
@@ -9647,6 +10028,7 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
(tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
(tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+ !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
(tp->nvram_jedecnum == JEDEC_ATMEL))
addr = ((addr / tp->nvram_pagesize) <<
@@ -9661,6 +10043,7 @@ static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr)
if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
(tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
(tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+ !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
(tp->nvram_jedecnum == JEDEC_ATMEL))
addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
@@ -9881,6 +10264,8 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
(tp->nvram_jedecnum == JEDEC_ST) &&
(nvram_cmd & NVRAM_CMD_FIRST)) {
@@ -10051,8 +10436,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
}
- if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC)
+ val = tr32(VCPU_CFGSHDW);
+ if (val & VCPU_CFGSHDW_ASPM_DBNC)
tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+ if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
+ (val & VCPU_CFGSHDW_WOL_MAGPKT))
+ tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
return;
}
@@ -10169,10 +10558,16 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
}
+ if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE)
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
!(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
+ if (tp->tg3_flags & TG3_FLAG_WOL_CAP &&
+ nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)
+ tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+
if (cfg2 & (1 << 17))
tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
@@ -10201,7 +10596,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
* firwmare access to the PHY hardware.
*/
err = 0;
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+ (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
} else {
/* Now read the physical PHY_ID from the chip and verify
@@ -10248,6 +10644,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
u32 bmsr, adv_reg, tg3_ctrl, mask;
@@ -10499,6 +10896,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pci_chip_rev_id = (misc_ctrl_reg >>
MISC_HOST_CTRL_CHIPREV_SHIFT);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+ u32 prod_id_asic_rev;
+
+ pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
+ &prod_id_asic_rev);
+ tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK;
+ }
/* Wrong chip ID in 5752 A0. This code can be removed later
* as A0 is not in production.
@@ -10618,6 +11022,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -10637,6 +11043,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -10654,6 +11062,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
@@ -10694,10 +11104,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
cacheline_sz_reg);
}
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
+ if (!tp->pcix_cap) {
+ printk(KERN_ERR PFX "Cannot find PCI-X "
+ "capability, aborting.\n");
+ return -EIO;
+ }
+ }
+
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
&pci_state_reg);
- if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
+ if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
/* If this is a 5700 BX chipset, and we are in PCI-X
@@ -10708,7 +11128,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
u32 pm_reg;
- u16 pci_cmd;
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
@@ -10716,11 +11135,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* space registers clobbered due to this bug.
* So explicitly force the chip into D0 here.
*/
- pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+ pci_read_config_dword(tp->pdev,
+ tp->pm_cap + PCI_PM_CTRL,
&pm_reg);
pm_reg &= ~PCI_PM_CTRL_STATE_MASK;
pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */;
- pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+ pci_write_config_dword(tp->pdev,
+ tp->pm_cap + PCI_PM_CTRL,
pm_reg);
/* Also, force SERR#/PERR# in PCI command. */
@@ -10818,6 +11239,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
tg3_get_eeprom_hw_cfg(tp);
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ /* Allow reads and writes to the
+ * APE register and memory space.
+ */
+ pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+ PCISTATE_ALLOW_APE_SHMEM_WR;
+ pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
+ pci_state_reg);
+ }
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
+
/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
* GPIO1 driven high will bring 5700's external PHY out of reset.
* It is also used as eeprom write protect on LOMs.
@@ -10884,7 +11319,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
@@ -11027,6 +11464,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->dev->hard_start_xmit = tg3_start_xmit;
else
@@ -11047,11 +11486,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->rx_std_max_post = 8;
- /* By default, disable wake-on-lan. User can change this
- * using ETHTOOL_SWOL.
- */
- tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
-
if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
PCIE_PWR_MGMT_L1_THRESH_MSK;
@@ -11648,8 +12082,10 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case PHY_ID_BCM5780: return "5780";
case PHY_ID_BCM5755: return "5755";
case PHY_ID_BCM5787: return "5787";
+ case PHY_ID_BCM5784: return "5784";
case PHY_ID_BCM5756: return "5722/5756";
case PHY_ID_BCM5906: return "5906";
+ case PHY_ID_BCM5761: return "5761";
case PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -11807,7 +12243,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
goto err_out_free_res;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#if TG3_VLAN_TAG_USED
@@ -11854,7 +12289,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
INIT_WORK(&tp->reset_task, tg3_reset_task);
tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len);
- if (tp->regs == 0UL) {
+ if (!tp->regs) {
printk(KERN_ERR PFX "Cannot map device registers, "
"aborting.\n");
err = -ENOMEM;
@@ -11874,9 +12309,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->set_mac_address = tg3_set_mac_addr;
dev->do_ioctl = tg3_ioctl;
dev->tx_timeout = tg3_tx_timeout;
- dev->poll = tg3_poll;
+ netif_napi_add(dev, &tp->napi, tg3_poll, 64);
dev->ethtool_ops = &tg3_ethtool_ops;
- dev->weight = 64;
dev->watchdog_timeo = TG3_TX_TIMEOUT;
dev->change_mtu = tg3_change_mtu;
dev->irq = pdev->irq;
@@ -11954,6 +12388,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
dev->features |= NETIF_F_TSO6;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ dev->features |= NETIF_F_TSO_ECN;
}
@@ -11978,7 +12414,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
*/
if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
- pci_save_state(tp->pdev);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
}
@@ -11995,7 +12430,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
dev->features |= NETIF_F_IPV6_CSUM;
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -12007,11 +12444,27 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_coal(tp);
- /* Now that we have fully setup the chip, save away a snapshot
- * of the PCI config space. We need to restore this after
- * GRC_MISC_CFG core clock resets and some resume events.
- */
- pci_save_state(tp->pdev);
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+ printk(KERN_ERR PFX "Cannot find proper PCI device "
+ "base address for APE, aborting.\n");
+ err = -ENODEV;
+ goto err_out_iounmap;
+ }
+
+ tg3reg_base = pci_resource_start(pdev, 2);
+ tg3reg_len = pci_resource_len(pdev, 2);
+
+ tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
+ if (tp->aperegs == 0UL) {
+ printk(KERN_ERR PFX "Cannot map APE registers, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ tg3_ape_lock_init(tp);
+ }
pci_set_drvdata(pdev, dev);
@@ -12019,7 +12472,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
- goto err_out_iounmap;
+ goto err_out_apeunmap;
}
printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
@@ -12052,6 +12505,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
return 0;
+err_out_apeunmap:
+ if (tp->aperegs) {
+ iounmap(tp->aperegs);
+ tp->aperegs = NULL;
+ }
+
err_out_iounmap:
if (tp->regs) {
iounmap(tp->regs);
@@ -12079,6 +12538,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
flush_scheduled_work();
unregister_netdev(dev);
+ if (tp->aperegs) {
+ iounmap(tp->aperegs);
+ tp->aperegs = NULL;
+ }
if (tp->regs) {
iounmap(tp->regs);
tp->regs = NULL;
@@ -12096,6 +12559,12 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
struct tg3 *tp = netdev_priv(dev);
int err;
+ /* PCI register 4 needs to be saved whether netif_running() or not.
+ * MSI address and data need to be saved if using MSI and
+ * netif_running().
+ */
+ pci_save_state(pdev);
+
if (!netif_running(dev))
return 0;
@@ -12115,9 +12584,6 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_full_unlock(tp);
- /* Save MSI address and data for resume. */
- pci_save_state(pdev);
-
err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
if (err) {
tg3_full_lock(tp, 0);
@@ -12145,15 +12611,20 @@ static int tg3_resume(struct pci_dev *pdev)
struct tg3 *tp = netdev_priv(dev);
int err;
+ pci_restore_state(tp->pdev);
+
if (!netif_running(dev))
return 0;
- pci_restore_state(tp->pdev);
-
err = tg3_set_power_state(tp, PCI_D0);
if (err)
return err;
+ /* Hardware bug - MSI won't work if INTX disabled. */
+ if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
+ (tp->tg3_flags2 & TG3_FLG2_USING_MSI))
+ pci_intx(tp->pdev, 1);
+
netif_device_attach(dev);
tg3_full_lock(tp, 0);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index d84e75e7365d..6dbdad2b8f88 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -57,32 +57,7 @@
#define TG3PCI_IRQ_PIN 0x0000003d
#define TG3PCI_MIN_GNT 0x0000003e
#define TG3PCI_MAX_LAT 0x0000003f
-#define TG3PCI_X_CAPS 0x00000040
-#define PCIX_CAPS_RELAXED_ORDERING 0x00020000
-#define PCIX_CAPS_SPLIT_MASK 0x00700000
-#define PCIX_CAPS_SPLIT_SHIFT 20
-#define PCIX_CAPS_BURST_MASK 0x000c0000
-#define PCIX_CAPS_BURST_SHIFT 18
-#define PCIX_CAPS_MAX_BURST_CPIOB 2
-#define TG3PCI_PM_CAP_PTR 0x00000041
-#define TG3PCI_X_COMMAND 0x00000042
-#define TG3PCI_X_STATUS 0x00000044
-#define TG3PCI_PM_CAP_ID 0x00000048
-#define TG3PCI_VPD_CAP_PTR 0x00000049
-#define TG3PCI_PM_CAPS 0x0000004a
-#define TG3PCI_PM_CTRL_STAT 0x0000004c
-#define TG3PCI_BR_SUPP_EXT 0x0000004e
-#define TG3PCI_PM_DATA 0x0000004f
-#define TG3PCI_VPD_CAP_ID 0x00000050
-#define TG3PCI_MSI_CAP_PTR 0x00000051
-#define TG3PCI_VPD_ADDR_FLAG 0x00000052
-#define VPD_ADDR_FLAG_WRITE 0x00008000
-#define TG3PCI_VPD_DATA 0x00000054
-#define TG3PCI_MSI_CAP_ID 0x00000058
-#define TG3PCI_NXT_CAP_PTR 0x00000059
-#define TG3PCI_MSI_CTRL 0x0000005a
-#define TG3PCI_MSI_ADDR_LOW 0x0000005c
-#define TG3PCI_MSI_ADDR_HIGH 0x00000060
+/* 0x40 --> 0x64 unused */
#define TG3PCI_MSI_DATA 0x00000064
/* 0x66 --> 0x68 unused */
#define TG3PCI_MISC_HOST_CTRL 0x00000068
@@ -133,6 +108,7 @@
#define CHIPREV_ID_5752_A1 0x6001
#define CHIPREV_ID_5714_A2 0x9002
#define CHIPREV_ID_5906_A1 0xc001
+#define CHIPREV_ID_5784_A0 0x5784000
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
@@ -146,6 +122,9 @@
#define ASIC_REV_5755 0x0a
#define ASIC_REV_5787 0x0b
#define ASIC_REV_5906 0x0c
+#define ASIC_REV_USE_PROD_ID_REG 0x0f
+#define ASIC_REV_5784 0x5784
+#define ASIC_REV_5761 0x5761
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -213,6 +192,8 @@
#define PCISTATE_ROM_RETRY_ENABLE 0x00000040
#define PCISTATE_FLAT_VIEW 0x00000100
#define PCISTATE_RETRY_SAME_DMA 0x00002000
+#define PCISTATE_ALLOW_APE_CTLSPC_WR 0x00010000
+#define PCISTATE_ALLOW_APE_SHMEM_WR 0x00020000
#define TG3PCI_CLOCK_CTRL 0x00000074
#define CLOCK_CTRL_CORECLK_DISABLE 0x00000200
#define CLOCK_CTRL_RXCLK_DISABLE 0x00000400
@@ -239,7 +220,9 @@
#define TG3PCI_DUAL_MAC_CTRL 0x000000b8
#define DUAL_MAC_CTRL_CH_MASK 0x00000003
#define DUAL_MAC_CTRL_ID 0x00000004
-/* 0xbc --> 0x100 unused */
+#define TG3PCI_PRODID_ASICREV 0x000000bc
+#define PROD_ID_ASIC_REV_MASK 0x0fffffff
+/* 0xc0 --> 0x100 unused */
/* 0x100 --> 0x200 unused */
@@ -683,6 +666,7 @@
#define SNDDATAC_MODE 0x00001000
#define SNDDATAC_MODE_RESET 0x00000001
#define SNDDATAC_MODE_ENABLE 0x00000002
+#define SNDDATAC_MODE_CDELAY 0x00000010
/* 0x1004 --> 0x1400 unused */
/* Send BD ring selector */
@@ -865,7 +849,20 @@
#define RCVLSC_MODE_ATTN_ENABLE 0x00000004
#define RCVLSC_STATUS 0x00003404
#define RCVLSC_STATUS_ERROR_ATTN 0x00000004
-/* 0x3408 --> 0x3800 unused */
+/* 0x3408 --> 0x3600 unused */
+
+/* CPMU registers */
+#define TG3_CPMU_CTRL 0x00003600
+#define CPMU_CTRL_LINK_IDLE_MODE 0x00000200
+#define CPMU_CTRL_LINK_AWARE_MODE 0x00000400
+#define CPMU_CTRL_LINK_SPEED_MODE 0x00004000
+/* 0x3604 --> 0x365c unused */
+
+#define TG3_CPMU_MUTEX_REQ 0x0000365c
+#define CPMU_MUTEX_REQ_DRIVER 0x00001000
+#define TG3_CPMU_MUTEX_GNT 0x00003660
+#define CPMU_MUTEX_GNT_DRIVER 0x00001000
+/* 0x3664 --> 0x3800 unused */
/* Mbuf cluster free registers */
#define MBFREE_MODE 0x00003800
@@ -1045,7 +1042,10 @@
#define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100
#define RDMAC_MODE_LNGREAD_ENAB 0x00000200
#define RDMAC_MODE_SPLIT_ENABLE 0x00000800
+#define RDMAC_MODE_BD_SBD_CRPT_ENAB 0x00000800
#define RDMAC_MODE_SPLIT_RESET 0x00001000
+#define RDMAC_MODE_MBUF_RBD_CRPT_ENAB 0x00001000
+#define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000
#define RDMAC_MODE_FIFO_SIZE_128 0x00020000
#define RDMAC_MODE_FIFO_LONG_BURST 0x00030000
#define RDMAC_STATUS 0x00004804
@@ -1151,6 +1151,8 @@
#define VCPU_STATUS_DRV_RESET 0x08000000
#define VCPU_CFGSHDW 0x00005104
+#define VCPU_CFGSHDW_WOL_ENABLE 0x00000001
+#define VCPU_CFGSHDW_WOL_MAGPKT 0x00000004
#define VCPU_CFGSHDW_ASPM_DBNC 0x00001000
/* Mailboxes */
@@ -1474,6 +1476,22 @@
#define FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ 0x03000002
#define FLASH_5787VENDOR_MICRO_EEPROM_64KHZ 0x03000000
#define FLASH_5787VENDOR_MICRO_EEPROM_376KHZ 0x02000000
+#define FLASH_5761VENDOR_ATMEL_MDB021D 0x00800003
+#define FLASH_5761VENDOR_ATMEL_MDB041D 0x00800000
+#define FLASH_5761VENDOR_ATMEL_MDB081D 0x00800002
+#define FLASH_5761VENDOR_ATMEL_MDB161D 0x00800001
+#define FLASH_5761VENDOR_ATMEL_ADB021D 0x00000003
+#define FLASH_5761VENDOR_ATMEL_ADB041D 0x00000000
+#define FLASH_5761VENDOR_ATMEL_ADB081D 0x00000002
+#define FLASH_5761VENDOR_ATMEL_ADB161D 0x00000001
+#define FLASH_5761VENDOR_ST_M_M45PE20 0x02800001
+#define FLASH_5761VENDOR_ST_M_M45PE40 0x02800000
+#define FLASH_5761VENDOR_ST_M_M45PE80 0x02800002
+#define FLASH_5761VENDOR_ST_M_M45PE16 0x02800003
+#define FLASH_5761VENDOR_ST_A_M45PE20 0x02000001
+#define FLASH_5761VENDOR_ST_A_M45PE40 0x02000000
+#define FLASH_5761VENDOR_ST_A_M45PE80 0x02000002
+#define FLASH_5761VENDOR_ST_A_M45PE16 0x02000003
#define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000
#define FLASH_5752PAGE_SIZE_256 0x00000000
#define FLASH_5752PAGE_SIZE_512 0x10000000
@@ -1504,9 +1522,11 @@
#define ACCESS_ENABLE 0x00000001
#define ACCESS_WR_ENABLE 0x00000002
#define NVRAM_WRITE1 0x00007028
-/* 0x702c --> 0x7400 unused */
+/* 0x702c unused */
+
+#define NVRAM_ADDR_LOCKOUT 0x00007030
+/* 0x7034 --> 0x7c00 unused */
-/* 0x7400 --> 0x7c00 unused */
#define PCIE_TRANSACTION_CFG 0x00007c04
#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000
#define PCIE_TRANS_CFG_LOM 0x00000020
@@ -1552,6 +1572,7 @@
#define NIC_SRAM_DATA_CFG_MINI_PCI 0x00001000
#define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000
#define NIC_SRAM_DATA_CFG_NO_GPIO2 0x00100000
+#define NIC_SRAM_DATA_CFG_APE_ENABLE 0x00200000
#define NIC_SRAM_DATA_VER 0x00000b5c
#define NIC_SRAM_DATA_VER_SHIFT 16
@@ -1680,6 +1701,47 @@
#define MII_TG3_TEST1_TRIM_EN 0x0010
#define MII_TG3_TEST1_CRC_EN 0x8000
+/* APE registers. Accessible through BAR1 */
+#define TG3_APE_EVENT 0x000c
+#define APE_EVENT_1 0x00000001
+#define TG3_APE_LOCK_REQ 0x002c
+#define APE_LOCK_REQ_DRIVER 0x00001000
+#define TG3_APE_LOCK_GRANT 0x004c
+#define APE_LOCK_GRANT_DRIVER 0x00001000
+#define TG3_APE_SEG_SIG 0x4000
+#define APE_SEG_SIG_MAGIC 0x41504521
+
+/* APE shared memory. Accessible through BAR1 */
+#define TG3_APE_FW_STATUS 0x400c
+#define APE_FW_STATUS_READY 0x00000100
+#define TG3_APE_HOST_SEG_SIG 0x4200
+#define APE_HOST_SEG_SIG_MAGIC 0x484f5354
+#define TG3_APE_HOST_SEG_LEN 0x4204
+#define APE_HOST_SEG_LEN_MAGIC 0x0000001c
+#define TG3_APE_HOST_INIT_COUNT 0x4208
+#define TG3_APE_HOST_DRIVER_ID 0x420c
+#define APE_HOST_DRIVER_ID_MAGIC 0xf0035100
+#define TG3_APE_HOST_BEHAVIOR 0x4210
+#define APE_HOST_BEHAV_NO_PHYLOCK 0x00000001
+#define TG3_APE_HOST_HEARTBEAT_INT_MS 0x4214
+#define APE_HOST_HEARTBEAT_INT_DISABLE 0
+#define APE_HOST_HEARTBEAT_INT_5SEC 5000
+#define TG3_APE_HOST_HEARTBEAT_COUNT 0x4218
+
+#define TG3_APE_EVENT_STATUS 0x4300
+
+#define APE_EVENT_STATUS_DRIVER_EVNT 0x00000010
+#define APE_EVENT_STATUS_STATE_CHNGE 0x00000500
+#define APE_EVENT_STATUS_STATE_START 0x00010000
+#define APE_EVENT_STATUS_STATE_UNLOAD 0x00020000
+#define APE_EVENT_STATUS_STATE_WOL 0x00030000
+#define APE_EVENT_STATUS_STATE_SUSPEND 0x00040000
+#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000
+
+/* APE convenience enumerations. */
+#define TG3_APE_LOCK_MEM 4
+
+
/* There are two ways to manage the TX descriptors on the tigon3.
* Either the descriptors are in host DMA'able memory, or they
* exist only in the cards on-chip SRAM. All 16 send bds are under
@@ -2155,6 +2217,7 @@ struct tg3 {
void (*write32_mbox) (struct tg3 *, u32,
u32);
void __iomem *regs;
+ void __iomem *aperegs;
struct net_device *dev;
struct pci_dev *pdev;
@@ -2176,6 +2239,7 @@ struct tg3 {
dma_addr_t tx_desc_mapping;
/* begin "rx thread" cacheline section */
+ struct napi_struct napi;
void (*write32_rx_mbox) (struct tg3 *, u32,
u32);
u32 rx_rcb_ptr;
@@ -2237,7 +2301,7 @@ struct tg3 {
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
-
+#define TG3_FLAG_CPMU_PRESENT 0x04000000
#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_SUPPORT_MSI 0x20000000
@@ -2279,6 +2343,9 @@ struct tg3 {
#define TG3_FLG2_PHY_JITTER_BUG 0x20000000
#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000
+ u32 tg3_flags3;
+#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001
+#define TG3_FLG3_ENABLE_APE 0x00000002
struct timer_list timer;
u16 timer_counter;
@@ -2309,7 +2376,7 @@ struct tg3 {
u32 pwrmgmt_thresh;
/* PCI block */
- u16 pci_chip_rev_id;
+ u32 pci_chip_rev_id;
u8 pci_cacheline_sz;
u8 pci_lat_timer;
u8 pci_hdr_type;
@@ -2317,6 +2384,7 @@ struct tg3 {
int pm_cap;
int msi_cap;
+ int pcix_cap;
/* PHY info */
u32 phy_id;
@@ -2335,6 +2403,8 @@ struct tg3 {
#define PHY_ID_BCM5755 0xbc050cc0
#define PHY_ID_BCM5787 0xbc050ce0
#define PHY_ID_BCM5756 0xbc050ed0
+#define PHY_ID_BCM5784 0xbc050fa0
+#define PHY_ID_BCM5761 0xbc050fd0
#define PHY_ID_BCM5906 0xdc00ac40
#define PHY_ID_BCM8002 0x60010140
#define PHY_ID_INVALID 0xffffffff
@@ -2345,6 +2415,7 @@ struct tg3 {
#define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */
u32 led_ctrl;
+ u32 pci_cmd;
char board_part_number[24];
char fw_ver[16];
@@ -2363,7 +2434,8 @@ struct tg3 {
(X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
(X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
- (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
+ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
+ (X) == PHY_ID_BCM8002)
struct tg3_hw_stats *hw_stats;
dma_addr_t stats_mapping;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 74eb12107e68..c99ce74a7aff 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -556,7 +556,6 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
rc = -ENOMEM;
goto err_out_regions;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
priv = netdev_priv(dev);
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 9f1b6ab9c228..7224d368b2a7 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -156,7 +156,7 @@ static void print_rx_state(struct net_device *dev) ;
static void print_tx_state(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
struct xl_tx_desc *txd ;
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
int i ;
@@ -179,7 +179,7 @@ static void print_tx_state(struct net_device *dev)
static void print_rx_state(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
struct xl_rx_desc *rxd ;
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
int i ;
@@ -213,7 +213,7 @@ static void print_rx_state(struct net_device *dev)
static u16 xl_ee_read(struct net_device *dev, int ee_addr)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
/* Wait for EEProm to not be busy */
@@ -245,7 +245,7 @@ static u16 xl_ee_read(struct net_device *dev, int ee_addr)
static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
/* Wait for EEProm to not be busy */
@@ -305,11 +305,11 @@ static int __devinit xl_probe(struct pci_dev *pdev,
pci_release_regions(pdev) ;
return -ENOMEM ;
}
- xl_priv = dev->priv ;
+ xl_priv = netdev_priv(dev);
#if XL_DEBUG
printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n",
- pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ;
+ pdev, dev, netdev_priv(dev), (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start);
#endif
dev->irq=pdev->irq;
@@ -344,7 +344,6 @@ static int __devinit xl_probe(struct pci_dev *pdev,
dev->set_multicast_list=&xl_set_rx_mode;
dev->get_stats=&xl_get_stats ;
dev->set_mac_address=&xl_set_mac_address ;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev,dev) ;
@@ -365,7 +364,7 @@ static int __devinit xl_probe(struct pci_dev *pdev,
static int __devinit xl_init(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
printk(KERN_INFO "%s \n", version);
printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n",
@@ -385,7 +384,7 @@ static int __devinit xl_init(struct net_device *dev)
static int xl_hw_reset(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
unsigned long t ;
u16 i ;
@@ -568,7 +567,7 @@ static int xl_hw_reset(struct net_device *dev)
static int xl_open(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
u8 i ;
u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */
@@ -641,14 +640,14 @@ static int xl_open(struct net_device *dev)
* Now to set up the Rx and Tx buffer structures
*/
/* These MUST be on 8 byte boundaries */
- xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ;
+ xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL);
if (xl_priv->xl_tx_ring == NULL) {
printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
dev->name);
free_irq(dev->irq,dev);
return -ENOMEM;
}
- xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ;
+ xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL);
if (xl_priv->xl_tx_ring == NULL) {
printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
dev->name);
@@ -656,8 +655,6 @@ static int xl_open(struct net_device *dev)
kfree(xl_priv->xl_tx_ring);
return -ENOMEM;
}
- memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ;
- memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ;
/* Setup Rx Ring */
for (i=0 ; i < XL_RX_RING_SIZE ; i++) {
@@ -726,7 +723,7 @@ static int xl_open(struct net_device *dev)
static int xl_open_hw(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
u16 vsoff ;
char ver_str[33];
@@ -875,7 +872,7 @@ static int xl_open_hw(struct net_device *dev)
static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
int prev_ring_loc ;
prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1);
@@ -890,7 +887,7 @@ static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on
static void xl_rx(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
struct sk_buff *skb, *skb2 ;
int frame_length = 0, copy_len = 0 ;
@@ -997,7 +994,7 @@ static void xl_rx(struct net_device *dev)
static void xl_reset(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
unsigned long t;
@@ -1020,7 +1017,7 @@ static void xl_reset(struct net_device *dev)
static void xl_freemem(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv=netdev_priv(dev);
int i ;
for (i=0;i<XL_RX_RING_SIZE;i++) {
@@ -1044,15 +1041,10 @@ static void xl_freemem(struct net_device *dev)
static irqreturn_t xl_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct xl_private *xl_priv =(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv =netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u16 intstatus, macstatus ;
- if (!dev) {
- printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ;
- return IRQ_NONE;
- }
-
intstatus = readw(xl_mmio + MMIO_INTSTATUS) ;
if (!(intstatus & 1)) /* We didn't generate the interrupt */
@@ -1171,7 +1163,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
struct xl_tx_desc *txd ;
int tx_head, tx_tail, tx_prev ;
unsigned long flags ;
@@ -1232,7 +1224,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
static void xl_dn_comp(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
struct xl_tx_desc *txd ;
@@ -1268,7 +1260,7 @@ static void xl_dn_comp(struct net_device *dev)
static int xl_close(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
unsigned long t ;
@@ -1366,7 +1358,7 @@ static int xl_close(struct net_device *dev)
static void xl_set_rx_mode(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
struct dev_mc_list *dmi ;
unsigned char dev_mc_address[4] ;
u16 options ;
@@ -1407,7 +1399,7 @@ static void xl_set_rx_mode(struct net_device *dev)
static void xl_srb_bh(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u8 srb_cmd, ret_code ;
int i ;
@@ -1476,14 +1468,14 @@ static void xl_srb_bh(struct net_device *dev)
static struct net_device_stats * xl_get_stats(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
return (struct net_device_stats *) &xl_priv->xl_stats;
}
static int xl_set_mac_address (struct net_device *dev, void *addr)
{
struct sockaddr *saddr = addr ;
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
if (netif_running(dev)) {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ;
@@ -1504,7 +1496,7 @@ static int xl_set_mac_address (struct net_device *dev, void *addr)
static void xl_arb_cmd(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u8 arb_cmd ;
u16 lan_status, lan_status_diff ;
@@ -1632,7 +1624,7 @@ static void xl_arb_cmd(struct net_device *dev)
static void xl_asb_cmd(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
if (xl_priv->asb_queued == 1)
@@ -1663,7 +1655,7 @@ static void xl_asb_cmd(struct net_device *dev)
*/
static void xl_asb_bh(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u8 ret_code ;
@@ -1691,7 +1683,7 @@ static void xl_asb_bh(struct net_device *dev)
static void xl_srb_cmd(struct net_device *dev, int srb_cmd)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
switch (srb_cmd) {
@@ -1748,7 +1740,7 @@ static void xl_srb_cmd(struct net_device *dev, int srb_cmd)
static void xl_wait_misr_flags(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
int i ;
@@ -1773,7 +1765,7 @@ static void xl_wait_misr_flags(struct net_device *dev)
static int xl_change_mtu(struct net_device *dev, int mtu)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv;
+ struct xl_private *xl_priv = netdev_priv(dev);
u16 max_mtu ;
if (xl_priv->xl_ring_speed == 4)
@@ -1795,7 +1787,7 @@ static int xl_change_mtu(struct net_device *dev, int mtu)
static void __devexit xl_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
unregister_netdev(dev);
iounmap(xl_priv->xl_mmio) ;
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 1bdd3beefbe5..124cfd4fbcf4 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -97,8 +97,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
static int versionprinted;
struct net_device *dev;
struct net_local *tp;
- int i, ret, pci_irq_line;
+ int ret, pci_irq_line;
unsigned long pci_ioaddr;
+ DECLARE_MAC_BUF(mac);
if (versionprinted++ == 0)
printk("%s", version);
@@ -116,8 +117,6 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
-
if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) {
ret = -EBUSY;
goto err_out_trdev;
@@ -147,12 +146,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
}
abyss_read_eeprom(dev);
-
- printk("%s: Ring Station Address: ", dev->name);
- printk("%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- printk(":%2.2x", dev->dev_addr[i]);
- printk("\n");
+
+ printk("%s: Ring Station Address: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
tp = netdev_priv(dev);
tp->setnselout = abyss_setnselout_pins;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 1e8958ee2d0a..e494c63bfbd9 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -116,9 +116,6 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
#define ENABLE_PAGING 1
#endif
-#define FALSE 0
-#define TRUE (!FALSE)
-
/* changes the output format of driver initialization */
#define TR_VERBOSE 0
@@ -327,7 +324,7 @@ static void ibmtr_cleanup_card(struct net_device *dev)
release_region(dev->base_addr, IBMTR_IO_EXTENT);
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
iounmap(ti->mmio);
iounmap(ti->sram_virt);
}
@@ -384,7 +381,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
void __iomem * t_mmio = NULL;
- struct tok_info *ti = dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
void __iomem *cd_chanid;
unsigned char *tchanid, ctemp;
#ifndef PCMCIA
@@ -392,6 +389,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
unsigned long timeout;
static int version_printed;
#endif
+ DECLARE_MAC_BUF(mac);
/* Query the adapter PIO base port which will return
* indication of where MMIO was placed. We also have a
@@ -705,9 +703,8 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
irq, PIOaddr, ti->mapped_ram_size / 2);
- DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ DPRINTK("Hardware address : %s\n",
+ print_mac(mac, dev->dev_addr));
if (ti->page_mask)
DPRINTK("Shared RAM paging enabled. "
"Page size: %uK Shared Ram size %dK\n",
@@ -823,7 +820,7 @@ static unsigned char __devinit get_sram_size(struct tok_info *adapt_info)
static int __devinit trdev_init(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
SET_PAGE(ti->srb_page);
ti->open_failure = NO ;
@@ -846,7 +843,7 @@ static int tok_init_card(struct net_device *dev)
unsigned long i;
PIOaddr = dev->base_addr;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
/* Special processing for first interrupt after reset */
ti->do_tok_int = FIRST_INT;
/* Reset adapter */
@@ -868,7 +865,7 @@ static int tok_init_card(struct net_device *dev)
/*****************************************************************************/
static int tok_open(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
int i;
/*the case we were left in a failure state during a previous open */
@@ -927,7 +924,7 @@ static void tok_open_adapter(unsigned long dev_addr)
struct tok_info *ti;
int i;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
SET_PAGE(ti->init_srb_page);
writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
for (i = 0; i < sizeof(struct dir_open_adapter); i++)
@@ -962,7 +959,7 @@ static void tok_open_adapter(unsigned long dev_addr)
static void open_sap(unsigned char type, struct net_device *dev)
{
int i;
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
SET_PAGE(ti->srb_page);
for (i = 0; i < sizeof(struct dlc_open_sap); i++)
@@ -986,7 +983,7 @@ static void open_sap(unsigned char type, struct net_device *dev)
static void tok_set_multicast_list(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
struct dev_mc_list *mclist;
unsigned char address[4];
@@ -1029,7 +1026,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct tok_info *ti;
unsigned long flags;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
netif_stop_queue(dev);
@@ -1051,7 +1048,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
static int tok_close(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
/* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */
/* unloading the module from memory, and then if a timer pops, ouch */
@@ -1094,7 +1091,7 @@ static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page
static void dir_open_adapter (struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
unsigned char ret_code;
__u16 err;
@@ -1179,7 +1176,7 @@ static irqreturn_t tok_interrupt(int irq, void *dev_id)
#if TR_VERBOSE
DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq);
#endif
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
if (ti->sram_phys & 1)
return IRQ_NONE; /* PCMCIA card extraction flag */
spin_lock(&(ti->lock));
@@ -1498,7 +1495,7 @@ static void initial_tok_int(struct net_device *dev)
struct tok_info *ti;
unsigned char init_status; /*BMS 12/2000*/
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
ti->do_tok_int = NOT_FIRST;
@@ -1542,7 +1539,7 @@ static void initial_tok_int(struct net_device *dev)
ti->ring_speed = init_status & 0x01 ? 16 : 4;
DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
ti->ring_speed, (unsigned int)dev->mem_start);
- ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE;
+ ti->auto_speedsave = (readb(ti->init_srb+INIT_STATUS_2_OFST) & 4) != 0;
if (ti->open_mode == MANUAL) wake_up(&ti->wait_for_reset);
else tok_open_adapter((unsigned long)dev);
@@ -1560,7 +1557,7 @@ static void initial_tok_int(struct net_device *dev)
static void tr_tx(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data;
unsigned int hdr_len;
__u32 dhb=0,dhb_base;
@@ -1674,7 +1671,7 @@ static void tr_tx(struct net_device *dev)
static void tr_rx(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
__u32 rbuffer;
void __iomem *rbuf, *rbufdata, *llc;
__u8 rbuffer_page = 0;
@@ -1742,18 +1739,20 @@ static void tr_rx(struct net_device *dev)
if (!IPv4_p) {
void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data);
-
+ u8 saddr[6];
+ u8 daddr[6];
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ int i;
+ for (i = 0 ; i < 6 ; i++)
+ saddr[i] = readb(trhhdr + SADDR_OFST + i);
+ for (i = 0 ; i < 6 ; i++)
+ daddr[i] = readb(trhhdr + DADDR_OFST + i);
DPRINTK("Probably non-IP frame received.\n");
DPRINTK("ssap: %02X dsap: %02X "
- "saddr: %02X:%02X:%02X:%02X:%02X:%02X "
- "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ "saddr: %s daddr: %$s\n",
readb(llc + SSAP_OFST), readb(llc + DSAP_OFST),
- readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1),
- readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3),
- readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5),
- readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1),
- readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3),
- readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5));
+ print_mac(mac, saddr), print_mac(mac2, daddr));
}
#endif
@@ -1846,7 +1845,7 @@ static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
void tok_rerun(unsigned long dev_addr){
struct net_device *dev = (struct net_device *)dev_addr;
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
if ( ti->open_action == RESTART){
ti->do_tok_int = FIRST_INT;
@@ -1868,7 +1867,7 @@ static void ibmtr_readlog(struct net_device *dev)
{
struct tok_info *ti;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
ti->readlog_pending = 0;
SET_PAGE(ti->srb_page);
@@ -1891,7 +1890,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev)
{
struct tok_info *toki;
- toki = (struct tok_info *) dev->priv;
+ toki = netdev_priv(dev);
return (struct net_device_stats *) &toki->tr_stats;
}
@@ -1899,7 +1898,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev)
static int ibmtr_change_mtu(struct net_device *dev, int mtu)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
return -EINVAL;
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 5d849c089a3b..47d84cd28097 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -123,6 +123,7 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <net/net_namespace.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -244,13 +245,12 @@ static int __devinit streamer_init_one(struct pci_dev *pdev,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
- streamer_priv = dev->priv;
+ streamer_priv = netdev_priv(dev);
#if STREAMER_NETWORK_MONITOR
#ifdef CONFIG_PROC_FS
if (!dev_streamer)
- create_proc_read_entry("net/streamer_tr", 0, 0,
+ create_proc_read_entry("streamer_tr", 0, init_net.proc_net,
streamer_proc_info, NULL);
streamer_priv->next = dev_streamer;
dev_streamer = streamer_priv;
@@ -404,7 +404,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev)
return;
}
- streamer_priv=dev->priv;
+ streamer_priv=netdev_priv(dev);
if (streamer_priv == NULL) {
printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n");
return;
@@ -423,7 +423,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev)
}
}
if (!dev_streamer)
- remove_proc_entry("net/streamer_tr", NULL);
+ remove_proc_entry("streamer_tr", init_net.proc_net);
}
#endif
#endif
@@ -447,8 +447,11 @@ static int streamer_reset(struct net_device *dev)
unsigned int uaa_addr;
struct sk_buff *skb = NULL;
__u16 misr;
+#if STREAMER_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
- streamer_priv = (struct streamer_private *) dev->priv;
+ streamer_priv = netdev_priv(dev);
streamer_mmio = streamer_priv->streamer_mmio;
writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
@@ -575,11 +578,8 @@ static int streamer_reset(struct net_device *dev)
dev->dev_addr[i+1]= addr & 0xff;
}
#if STREAMER_DEBUG
- printk("Adapter address: ");
- for (i = 0; i < 6; i++) {
- printk("%02x:", dev->dev_addr[i]);
- }
- printk("\n");
+ printk("Adapter address: %s\n",
+ print_mac(mac, dev->dev_addr));
#endif
}
return 0;
@@ -587,7 +587,7 @@ static int streamer_reset(struct net_device *dev)
static int streamer_open(struct net_device *dev)
{
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ struct streamer_private *streamer_priv = netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
unsigned long flags;
char open_error[255];
@@ -904,7 +904,7 @@ static int streamer_open(struct net_device *dev)
static void streamer_rx(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
struct streamer_rx_desc *rx_desc;
int rx_ring_last_received, length, frame_length, buffer_cnt = 0;
@@ -1029,7 +1029,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u16 sisr;
__u16 misr;
@@ -1152,7 +1152,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id)
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
unsigned long flags ;
@@ -1203,7 +1203,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
static int streamer_close(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
unsigned long flags;
int i;
@@ -1269,7 +1269,7 @@ static int streamer_close(struct net_device *dev)
static void streamer_set_rx_mode(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u8 options = 0;
struct dev_mc_list *dmi;
@@ -1328,7 +1328,7 @@ static void streamer_set_rx_mode(struct net_device *dev)
static void streamer_srb_bh(struct net_device *dev)
{
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ struct streamer_private *streamer_priv = netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u16 srb_word;
@@ -1493,14 +1493,14 @@ static void streamer_srb_bh(struct net_device *dev)
static struct net_device_stats *streamer_get_stats(struct net_device *dev)
{
struct streamer_private *streamer_priv;
- streamer_priv = (struct streamer_private *) dev->priv;
+ streamer_priv = netdev_priv(dev);
return (struct net_device_stats *) &streamer_priv->streamer_stats;
}
static int streamer_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *saddr = addr;
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ struct streamer_private *streamer_priv = netdev_priv(dev);
if (netif_running(dev))
{
@@ -1525,7 +1525,7 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr)
static void streamer_arb_cmd(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u8 header_len;
__u16 frame_len, buffer_len;
@@ -1539,6 +1539,7 @@ static void streamer_arb_cmd(struct net_device *dev)
#if STREAMER_NETWORK_MONITOR
struct trh_hdr *mac_hdr;
+ DECLARE_MAC_BUF(mac);
#endif
writew(streamer_priv->arb, streamer_mmio + LAPA);
@@ -1611,15 +1612,11 @@ static void streamer_arb_cmd(struct net_device *dev)
dev->name);
mac_hdr = tr_hdr(mac_frame);
printk(KERN_WARNING
- "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
- dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1],
- mac_hdr->daddr[2], mac_hdr->daddr[3],
- mac_hdr->daddr[4], mac_hdr->daddr[5]);
+ "%s: MAC Frame Dest. Addr: %s\n",
+ dev->name, print_mac(mac, mac_hdr->daddr));
printk(KERN_WARNING
- "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
- dev->name, mac_hdr->saddr[0], mac_hdr->saddr[1],
- mac_hdr->saddr[2], mac_hdr->saddr[3],
- mac_hdr->saddr[4], mac_hdr->saddr[5]);
+ "%s: MAC Frame Srce. Addr: %s\n",
+ dev->name, DEV->ADDR6(mac_hdr->saddr));
#endif
netif_rx(mac_frame);
@@ -1740,7 +1737,7 @@ drop_frame:
static void streamer_asb_bh(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
if (streamer_priv->asb_queued == 1)
@@ -1784,7 +1781,7 @@ static void streamer_asb_bh(struct net_device *dev)
static int streamer_change_mtu(struct net_device *dev, int mtu)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u16 max_mtu;
if (streamer_priv->streamer_ring_speed == 4)
@@ -1848,12 +1845,14 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset,
static int sprintf_info(char *buffer, struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
struct streamer_adapter_addr_table sat;
struct streamer_parameters_table spt;
int size = 0;
int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA);
for (i = 0; i < 14; i += 2) {
@@ -1875,37 +1874,30 @@ static int sprintf_info(char *buffer, struct net_device *dev)
size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name);
size += sprintf(buffer + size,
- "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
- dev->name, dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5], sat.node_addr[0], sat.node_addr[1],
- sat.node_addr[2], sat.node_addr[3], sat.node_addr[4],
- sat.node_addr[5], sat.func_addr[0], sat.func_addr[1],
- sat.func_addr[2], sat.func_addr[3]);
+ "%6s: %s : %s : %02x:%02x:%02x:%02x\n",
+ dev->name, print_mac(mac, dev->dev_addr),
+ print_mac(mac2, sat.node_addr),
+ sat.func_addr[0], sat.func_addr[1],
+ sat.func_addr[2], sat.func_addr[3]);
size += sprintf(buffer + size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name);
size += sprintf(buffer + size,
- "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n",
+ "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n",
dev->name, spt.phys_addr[0], spt.phys_addr[1],
spt.phys_addr[2], spt.phys_addr[3],
- spt.up_node_addr[0], spt.up_node_addr[1],
- spt.up_node_addr[2], spt.up_node_addr[3],
- spt.up_node_addr[4], spt.up_node_addr[4],
- spt.poll_addr[0], spt.poll_addr[1], spt.poll_addr[2],
- spt.poll_addr[3], spt.poll_addr[4], spt.poll_addr[5],
+ print_mac(mac, spt.up_node_addr),
+ print_mac(mac2, spt.poll_addr),
ntohs(spt.acc_priority), ntohs(spt.auth_source_class),
ntohs(spt.att_code));
size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name);
size += sprintf(buffer + size,
- "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n",
- dev->name, spt.source_addr[0], spt.source_addr[1],
- spt.source_addr[2], spt.source_addr[3],
- spt.source_addr[4], spt.source_addr[5],
+ "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n",
+ dev->name, print_mac(mac, spt.source_addr),
ntohs(spt.beacon_type), ntohs(spt.major_vector),
ntohs(spt.lan_status), ntohs(spt.local_ring),
ntohs(spt.mon_error), ntohs(spt.frame_correl));
@@ -1914,14 +1906,12 @@ static int sprintf_info(char *buffer, struct net_device *dev)
dev->name);
size += sprintf(buffer + size,
- "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n",
+ "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n",
dev->name, ntohs(spt.beacon_transmit),
- ntohs(spt.beacon_receive), spt.beacon_naun[0],
- spt.beacon_naun[1], spt.beacon_naun[2],
- spt.beacon_naun[3], spt.beacon_naun[4],
- spt.beacon_naun[5], spt.beacon_phys[0],
- spt.beacon_phys[1], spt.beacon_phys[2],
- spt.beacon_phys[3]);
+ ntohs(spt.beacon_receive),
+ print_mac(mac, spt.beacon_naun),
+ spt.beacon_phys[0], spt.beacon_phys[1],
+ spt.beacon_phys[2], spt.beacon_phys[3]);
return size;
}
#endif
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index f8f4d74f01f1..5a4151362fc0 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -151,7 +151,8 @@ static int __devinit madgemc_probe(struct device *device)
struct net_local *tp;
struct card_info *card;
struct mca_device *mdev = to_mca_device(device);
- int ret = 0, i = 0;
+ int ret = 0;
+ DECLARE_MAC_BUF(mac);
if (versionprinted++ == 0)
printk("%s", version);
@@ -168,7 +169,6 @@ static int __devinit madgemc_probe(struct device *device)
goto getout;
}
- SET_MODULE_OWNER(dev);
dev->dma = 0;
card = kmalloc(sizeof(struct card_info), GFP_KERNEL);
@@ -323,11 +323,8 @@ static int __devinit madgemc_probe(struct device *device)
mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev);
- printk("%s: Ring Station Address: ", dev->name);
- printk("%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- printk(":%2.2x", dev->dev_addr[i]);
- printk("\n");
+ printk("%s: Ring Station Address: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
if (tmsdev_init(dev, device)) {
printk("%s: unable to get memory for dev->priv.\n",
@@ -690,14 +687,14 @@ static int madgemc_close(struct net_device *dev)
static int madgemc_mcaproc(char *buf, int slot, void *d)
{
struct net_device *dev = (struct net_device *)d;
- struct net_local *tp = dev->priv;
+ struct net_local *tp = netdev_priv(dev);
struct card_info *curcard = tp->tmspriv;
int len = 0;
+ DECLARE_MAC_BUF(mac);
len += sprintf(buf+len, "-------\n");
if (curcard) {
struct net_local *tp = netdev_priv(dev);
- int i;
len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev);
len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize);
@@ -717,11 +714,8 @@ static int madgemc_mcaproc(char *buf, int slot, void *d)
}
len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair");
- len += sprintf(buf+len, "Ring Station Address: ");
- len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]);
- len += sprintf(buf+len, "\n");
+ len += sprintf(buf+len, "Ring Station Address: %s\n",
+ print_mac(mac, dev->dev_addr));
} else
len += sprintf(buf+len, "Card not configured\n");
@@ -736,7 +730,7 @@ static int __devexit madgemc_remove(struct device *device)
BUG_ON(!dev);
- tp = dev->priv;
+ tp = netdev_priv(dev);
card = tp->tmspriv;
kfree(card);
tp->tmspriv = NULL;
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 09b3cfb8e809..74c1f0f189f5 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -102,6 +102,7 @@
#include <linux/jiffies.h>
#include <net/checksum.h>
+#include <net/net_namespace.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -219,14 +220,14 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
goto op_release_dev;
}
- olympic_priv = dev->priv ;
+ olympic_priv = netdev_priv(dev) ;
spin_lock_init(&olympic_priv->olympic_lock) ;
init_waitqueue_head(&olympic_priv->srb_wait);
init_waitqueue_head(&olympic_priv->trb_wait);
#if OLYMPIC_DEBUG
- printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, dev->priv);
+ printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, netdev_priv(dev));
#endif
dev->irq=pdev->irq;
dev->base_addr=pci_resource_start(pdev, 0);
@@ -260,7 +261,6 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
dev->set_multicast_list=&olympic_set_rx_mode;
dev->get_stats=&olympic_get_stats ;
dev->set_mac_address=&olympic_set_mac_address ;
- SET_MODULE_OWNER(dev) ;
SET_NETDEV_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev,dev) ;
@@ -268,9 +268,9 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name);
if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */
char proc_name[20] ;
- strcpy(proc_name,"net/olympic_") ;
+ strcpy(proc_name,"olympic_") ;
strcat(proc_name,dev->name) ;
- create_proc_read_entry(proc_name,0,NULL,olympic_proc_info,(void *)dev) ;
+ create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ;
printk("Olympic: Network Monitor information: /proc/%s\n",proc_name);
}
return 0 ;
@@ -297,7 +297,7 @@ static int __devinit olympic_init(struct net_device *dev)
unsigned long t;
unsigned int uaa_addr;
- olympic_priv=(struct olympic_private *)dev->priv;
+ olympic_priv=netdev_priv(dev);
olympic_mmio=olympic_priv->olympic_mmio;
printk("%s \n", version);
@@ -418,14 +418,15 @@ static int __devinit olympic_init(struct net_device *dev)
writel(uaa_addr,olympic_mmio+LAPA);
adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
+ memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
+
#if OLYMPIC_DEBUG
- printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
- readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
+ {
+ DECLARE_MAC_BUF(mac);
+ printk("adapter address: %s\n", print_mac(mac, dev->dev_addr));
+ }
#endif
- memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
-
olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12));
olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14));
@@ -435,11 +436,12 @@ static int __devinit olympic_init(struct net_device *dev)
static int olympic_open(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
unsigned long flags, t;
int i, open_finished = 1 ;
u8 resp, err;
+ DECLARE_MAC_BUF(mac);
DECLARE_WAITQUEUE(wait,current) ;
@@ -567,14 +569,8 @@ static int olympic_open(struct net_device *dev)
goto out;
case 0x32:
- printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- olympic_priv->olympic_laa[0],
- olympic_priv->olympic_laa[1],
- olympic_priv->olympic_laa[2],
- olympic_priv->olympic_laa[3],
- olympic_priv->olympic_laa[4],
- olympic_priv->olympic_laa[5]) ;
+ printk(KERN_WARNING "%s: Invalid LAA: %s\n",
+ dev->name, print_mac(mac, olympic_priv->olympic_laa));
goto out;
default:
@@ -704,30 +700,26 @@ static int olympic_open(struct net_device *dev)
#endif
if (olympic_priv->olympic_network_monitor) {
- u8 __iomem *oat ;
- u8 __iomem *opt ;
- oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ;
- opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ;
-
- printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name,
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+ u8 __iomem *oat;
+ u8 __iomem *opt;
+ int i;
+ u8 addr[6];
+ DECLARE_MAC_BUF(mac);
+ oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr);
+ opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr);
+
+ for (i = 0; i < 6; i++)
+ addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i);
+ printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr));
printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name,
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
- printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name,
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
+
+ for (i = 0; i < 6; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i);
+ printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr));
}
netif_start_queue(dev);
@@ -755,7 +747,7 @@ out:
*/
static void olympic_rx(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
struct olympic_rx_status *rx_status;
struct olympic_rx_desc *rx_desc ;
@@ -897,7 +889,7 @@ static void olympic_rx(struct net_device *dev)
static void olympic_freemem(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
int i;
for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
@@ -930,7 +922,7 @@ static void olympic_freemem(struct net_device *dev)
static irqreturn_t olympic_interrupt(int irq, void *dev_id)
{
struct net_device *dev= (struct net_device *)dev_id;
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
u32 sisr;
u8 __iomem *adapter_check_area ;
@@ -1046,7 +1038,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id)
static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
unsigned long flags ;
@@ -1077,7 +1069,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
static int olympic_close(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb;
unsigned long t,flags;
@@ -1147,7 +1139,7 @@ static int olympic_close(struct net_device *dev)
static void olympic_set_rx_mode(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ;
u8 options = 0;
u8 __iomem *srb;
@@ -1215,7 +1207,7 @@ static void olympic_set_rx_mode(struct net_device *dev)
static void olympic_srb_bh(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ;
u8 __iomem *srb;
@@ -1361,14 +1353,14 @@ static void olympic_srb_bh(struct net_device *dev)
static struct net_device_stats * olympic_get_stats(struct net_device *dev)
{
struct olympic_private *olympic_priv ;
- olympic_priv=(struct olympic_private *) dev->priv;
+ olympic_priv=netdev_priv(dev);
return (struct net_device_stats *) &olympic_priv->olympic_stats;
}
static int olympic_set_mac_address (struct net_device *dev, void *addr)
{
struct sockaddr *saddr = addr ;
- struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
if (netif_running(dev)) {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ;
@@ -1389,7 +1381,7 @@ static int olympic_set_mac_address (struct net_device *dev, void *addr)
static void olympic_arb_cmd(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
u8 __iomem *arb_block, *asb_block, *srb ;
u8 header_len ;
@@ -1445,11 +1437,14 @@ static void olympic_arb_cmd(struct net_device *dev)
mac_frame->protocol = tr_type_trans(mac_frame, dev);
if (olympic_priv->olympic_network_monitor) {
- struct trh_hdr *mac_hdr ;
- printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+ struct trh_hdr *mac_hdr;
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name);
mac_hdr = tr_hdr(mac_frame);
- printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ;
- printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ;
+ printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %s\n",
+ dev->name, print_mac(mac, mac_hdr->daddr));
+ printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %s\n",
+ dev->name, print_mac(mac, mac_hdr->saddr));
}
netif_rx(mac_frame);
dev->last_rx = jiffies;
@@ -1575,7 +1570,7 @@ drop_frame:
static void olympic_asb_bh(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *arb_block, *asb_block ;
arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ;
@@ -1615,7 +1610,7 @@ static void olympic_asb_bh(struct net_device *dev)
static int olympic_change_mtu(struct net_device *dev, int mtu)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u16 max_mtu ;
if (olympic_priv->olympic_ring_speed == 4)
@@ -1637,33 +1632,31 @@ static int olympic_change_mtu(struct net_device *dev, int mtu)
static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
{
struct net_device *dev = (struct net_device *)data ;
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ;
u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ;
int size = 0 ;
int len=0;
off_t begin=0;
off_t pos=0;
-
+ u8 addr[6];
+ u8 addr2[6];
+ int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
size = sprintf(buffer,
"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name);
size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n",
dev->name);
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i);
+
+ size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n",
dev->name,
- dev->dev_addr[0],
- dev->dev_addr[1],
- dev->dev_addr[2],
- dev->dev_addr[3],
- dev->dev_addr[4],
- dev->dev_addr[5],
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
+ print_mac(mac, dev->dev_addr),
+ print_mac(mac2, addr),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
@@ -1673,25 +1666,20 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n",
dev->name) ;
-
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n",
+
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr) + i);
+ for (i = 0 ; i < 6 ; i++)
+ addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i);
+
+ size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n",
dev->name,
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
+ print_mac(mac, addr),
+ print_mac(mac2, addr2),
swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
@@ -1699,14 +1687,11 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
dev->name) ;
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n",
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i);
+ size += sprintf(buffer+size, "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n",
dev->name,
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
+ print_mac(mac, addr),
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
@@ -1717,16 +1702,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n",
dev->name) ;
- size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n",
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i);
+ size += sprintf(buffer+size, "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n",
dev->name,
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
+ print_mac(mac, addr),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
@@ -1748,13 +1730,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
static void __devexit olympic_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev) ;
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
if (olympic_priv->olympic_network_monitor) {
char proc_name[20] ;
- strcpy(proc_name,"net/olympic_") ;
+ strcpy(proc_name,"olympic_") ;
strcat(proc_name,dev->name) ;
- remove_proc_entry(proc_name,NULL);
+ remove_proc_entry(proc_name,init_net.proc_net);
}
unregister_netdev(dev) ;
iounmap(olympic_priv->olympic_mmio) ;
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index cb7dbb63c9d9..ca6b65919b3d 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -122,11 +122,11 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
static int versionprinted;
const unsigned *port;
int j,err = 0;
+ DECLARE_MAC_BUF(mac);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (dev->base_addr) /* probe specific location */
err = proteon_probe1(dev, dev->base_addr);
else {
@@ -153,11 +153,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
proteon_read_eeprom(dev);
- printk(KERN_DEBUG "proteon.c: Ring Station Address: ");
- printk("%2.2x", dev->dev_addr[0]);
- for (j = 1; j < 6; j++)
- printk(":%2.2x", dev->dev_addr[j]);
- printk("\n");
+ printk(KERN_DEBUG "proteon.c: Ring Station Address: %s\n",
+ print_mac(mac, dev->dev_addr));
tp = netdev_priv(dev);
tp->setnselout = proteon_setnselout_pins;
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 33afea31d87b..32e8d5a9f958 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -139,11 +139,11 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
static int versionprinted;
const unsigned *port;
int j, err = 0;
+ DECLARE_MAC_BUF(mac);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (dev->base_addr) /* probe specific location */
err = sk_isa_probe1(dev, dev->base_addr);
else {
@@ -170,11 +170,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
sk_isa_read_eeprom(dev);
- printk(KERN_DEBUG "skisa.c: Ring Station Address: ");
- printk("%2.2x", dev->dev_addr[0]);
- for (j = 1; j < 6; j++)
- printk(":%2.2x", dev->dev_addr[j]);
- printk("\n");
+ printk(KERN_DEBUG "skisa.c: Ring Station Address: %s\n",
+ print_mac(mac, dev->dev_addr));
tp = netdev_priv(dev);
tp->setnselout = sk_isa_setnselout_pins;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index f83bb5cb0d3d..93da3a36cde8 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3583,8 +3583,6 @@ struct net_device __init *smctr_probe(int unit)
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
-
if (unit >= 0) {
sprintf(dev->name, "tr%d", unit);
netdev_boot_setup_check(dev);
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 12bd294045a7..d5fa36d36515 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -2124,7 +2124,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
/* Get the frame size (Byte swap for Intel).
* Do this early (see workaround comment below)
*/
- Length = be16_to_cpu((unsigned short)rpl->FrameSize);
+ Length = be16_to_cpu(rpl->FrameSize);
/* Check if the Frame_Start, Frame_End and
* Frame_Complete bits are set.
@@ -2140,7 +2140,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
* Length2 is there because there have also been
* cases where the FrameSize was partially written
*/
- Length2 = be16_to_cpu((unsigned short)rpl->FrameSize);
+ Length2 = be16_to_cpu(rpl->FrameSize);
if(Length == 0 || Length != Length2)
{
diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h
index 2a16078ac3fd..7daf74e31ccd 100644
--- a/drivers/net/tokenring/tms380tr.h
+++ b/drivers/net/tokenring/tms380tr.h
@@ -476,13 +476,13 @@ typedef struct {
* bytes = 0xC000
*/
u_int32_t FunctAddr; /* High order bytes = 0xC000 */
- u_int16_t RxListSize; /* RPL size: 0 (=26), 14, 20 or
+ __be16 RxListSize; /* RPL size: 0 (=26), 14, 20 or
* 26 bytes read by the adapter.
* (Depending on the number of
* fragments/list)
*/
- u_int16_t TxListSize; /* TPL size */
- u_int16_t BufSize; /* Is automatically rounded up to the
+ __be16 TxListSize; /* TPL size */
+ __be16 BufSize; /* Is automatically rounded up to the
* nearest nK boundary.
*/
u_int16_t FullDuplex;
@@ -580,14 +580,14 @@ typedef struct {
/*--------------------- Send and Receive definitions -------------------*/
#pragma pack(1)
typedef struct {
- u_int16_t DataCount; /* Value 0, even and odd values are
+ __be16 DataCount; /* Value 0, even and odd values are
* permitted; value is unaltered most
* significant bit set: following
* fragments last fragment: most
* significant bit is not evaluated.
* (???)
*/
- u_int32_t DataAddr; /* Pointer to frame data fragment;
+ __be32 DataAddr; /* Pointer to frame data fragment;
* even or odd.
*/
} Fragment;
@@ -679,7 +679,7 @@ typedef struct {
typedef struct s_TPL TPL;
struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */
- u_int32_t NextTPLAddr; /* Pointer to next TPL in chain; if
+ __be32 NextTPLAddr; /* Pointer to next TPL in chain; if
* pointer is odd: this is the last
* TPL. Pointing to itself can cause
* problems!
@@ -689,7 +689,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */
* significant bit first! Set by the
* adapter: CSTAT_COMPLETE status.
*/
- u_int16_t FrameSize; /* Number of bytes to be transmitted
+ __be16 FrameSize; /* Number of bytes to be transmitted
* as a frame including AC/FC,
* Destination, Source, Routing field
* not including CRC, FS, End Delimiter
@@ -1020,7 +1020,7 @@ enum SKB_STAT {
#pragma pack(1)
typedef struct s_RPL RPL;
struct s_RPL { /* Receive Parameter List */
- u_int32_t NextRPLAddr; /* Pointer to next RPL in chain
+ __be32 NextRPLAddr; /* Pointer to next RPL in chain
* (normalized = physical 32 bit
* address) if pointer is odd: this
* is last RPL. Pointing to itself can
@@ -1031,7 +1031,7 @@ struct s_RPL { /* Receive Parameter List */
* adapter in lists that start or end
* a frame.
*/
- volatile u_int16_t FrameSize; /* Number of bytes received as a
+ volatile __be16 FrameSize; /* Number of bytes received as a
* frame including AC/FC, Destination,
* Source, Routing field not including
* CRC, FS (Frame Status), End Delimiter
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 3b2f00b9b7bd..1c18f782f522 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -96,10 +96,11 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
static int versionprinted;
struct net_device *dev;
struct net_local *tp;
- int i, ret;
+ int ret;
unsigned int pci_irq_line;
unsigned long pci_ioaddr;
struct card_info *cardinfo = &card_info_table[ent->driver_data];
+ DECLARE_MAC_BUF(mac);
if (versionprinted++ == 0)
printk("%s", version);
@@ -115,7 +116,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
dev = alloc_trdev(sizeof(struct net_local));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) {
ret = -EBUSY;
@@ -137,11 +137,8 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
tms_pci_read_eeprom(dev);
- printk("%s: Ring Station Address: ", dev->name);
- printk("%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- printk(":%2.2x", dev->dev_addr[i]);
- printk("\n");
+ printk("%s: Ring Station Address: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
ret = tmsdev_init(dev, &pdev->dev);
if (ret) {
@@ -149,7 +146,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
goto err_out_irq;
}
- tp = dev->priv;
+ tp = netdev_priv(dev);
tp->setnselout = tms_pci_setnselout_pins;
tp->sifreadb = tms_pci_sifreadb;
@@ -210,7 +207,7 @@ static void tms_pci_read_eeprom(struct net_device *dev)
static unsigned short tms_pci_setnselout_pins(struct net_device *dev)
{
unsigned short val = 0;
- struct net_local *tp = dev->priv;
+ struct net_local *tp = netdev_priv(dev);
struct card_info *cardinfo = tp->tmspriv;
if(tp->DataRate == SPEED_4)
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 1aabc91f6458..df10af7df7b8 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -47,7 +47,6 @@
#include <linux/rtnetlink.h>
#include <linux/timer.h>
#include <linux/platform_device.h>
-#include <linux/etherdevice.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -79,6 +78,9 @@ struct tsi108_prv_data {
void __iomem *regs; /* Base of normal regs */
void __iomem *phyregs; /* Base of register bank used for PHY access */
+ struct net_device *dev;
+ struct napi_struct napi;
+
unsigned int phy; /* Index of PHY for this interface */
unsigned int irq_num;
unsigned int id;
@@ -837,13 +839,13 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)
return done;
}
-static int tsi108_poll(struct net_device *dev, int *budget)
+static int tsi108_poll(struct napi_struct *napi, int budget)
{
- struct tsi108_prv_data *data = netdev_priv(dev);
+ struct tsi108_prv_data *data = container_of(napi, struct tsi108_prv_data, napi);
+ struct net_device *dev = data->dev;
u32 estat = TSI_READ(TSI108_EC_RXESTAT);
u32 intstat = TSI_READ(TSI108_EC_INTSTAT);
- int total_budget = min(*budget, dev->quota);
- int num_received = 0, num_filled = 0, budget_used;
+ int num_received = 0, num_filled = 0;
intstat &= TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH |
TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT;
@@ -852,7 +854,7 @@ static int tsi108_poll(struct net_device *dev, int *budget)
TSI_WRITE(TSI108_EC_INTSTAT, intstat);
if (data->rxpending || (estat & TSI108_EC_RXESTAT_Q0_DESCINT))
- num_received = tsi108_complete_rx(dev, total_budget);
+ num_received = tsi108_complete_rx(dev, budget);
/* This should normally fill no more slots than the number of
* packets received in tsi108_complete_rx(). The exception
@@ -867,7 +869,7 @@ static int tsi108_poll(struct net_device *dev, int *budget)
*/
if (data->rxfree < TSI108_RXRING_LEN)
- num_filled = tsi108_refill_rx(dev, total_budget * 2);
+ num_filled = tsi108_refill_rx(dev, budget * 2);
if (intstat & TSI108_INT_RXERROR) {
u32 err = TSI_READ(TSI108_EC_RXERR);
@@ -890,14 +892,9 @@ static int tsi108_poll(struct net_device *dev, int *budget)
spin_unlock_irq(&data->misclock);
}
- budget_used = max(num_received, num_filled / 2);
-
- *budget -= budget_used;
- dev->quota -= budget_used;
-
- if (budget_used != total_budget) {
+ if (num_received < budget) {
data->rxpending = 0;
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
TSI_WRITE(TSI108_EC_INTMASK,
TSI_READ(TSI108_EC_INTMASK)
@@ -906,14 +903,11 @@ static int tsi108_poll(struct net_device *dev, int *budget)
TSI108_INT_RXOVERRUN |
TSI108_INT_RXERROR |
TSI108_INT_RXWAIT));
-
- /* IRQs are level-triggered, so no need to re-check */
- return 0;
} else {
data->rxpending = 1;
}
- return 1;
+ return num_received;
}
static void tsi108_rx_int(struct net_device *dev)
@@ -931,7 +925,7 @@ static void tsi108_rx_int(struct net_device *dev)
* from tsi108_check_rxring().
*/
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &data->napi)) {
/* Mask, rather than ack, the receive interrupts. The ack
* will happen in tsi108_poll().
*/
@@ -942,7 +936,7 @@ static void tsi108_rx_int(struct net_device *dev)
| TSI108_INT_RXTHRESH |
TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR |
TSI108_INT_RXWAIT);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &data->napi);
} else {
if (!netif_running(dev)) {
/* This can happen if an interrupt occurs while the
@@ -1401,6 +1395,8 @@ static int tsi108_open(struct net_device *dev)
TSI_WRITE(TSI108_EC_TXQ_PTRLOW, data->txdma);
tsi108_init_phy(dev);
+ napi_enable(&data->napi);
+
setup_timer(&data->timer, tsi108_timed_checker, (unsigned long)dev);
mod_timer(&data->timer, jiffies + 1);
@@ -1425,6 +1421,7 @@ static int tsi108_close(struct net_device *dev)
struct tsi108_prv_data *data = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&data->napi);
del_timer_sync(&data->timer);
@@ -1543,6 +1540,7 @@ tsi108_init_one(struct platform_device *pdev)
struct tsi108_prv_data *data = NULL;
hw_info *einfo;
int err = 0;
+ DECLARE_MAC_BUF(mac);
einfo = pdev->dev.platform_data;
@@ -1562,6 +1560,7 @@ tsi108_init_one(struct platform_device *pdev)
printk("tsi108_eth%d: probe...\n", pdev->id);
data = netdev_priv(dev);
+ data->dev = dev;
pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n",
pdev->id, einfo->regs, einfo->phyregs,
@@ -1597,9 +1596,8 @@ tsi108_init_one(struct platform_device *pdev)
dev->set_mac_address = tsi108_set_mac;
dev->set_multicast_list = tsi108_set_rx_mode;
dev->get_stats = tsi108_get_stats;
- dev->poll = tsi108_poll;
+ netif_napi_add(dev, &data->napi, tsi108_poll, 64);
dev->do_ioctl = tsi108_do_ioctl;
- dev->weight = 64; /* 64 is more suitable for GigE interface - klai */
/* Apparently, the Linux networking code won't use scatter-gather
* if the hardware doesn't do checksums. However, it's faster
@@ -1610,7 +1608,6 @@ tsi108_init_one(struct platform_device *pdev)
*/
dev->features = NETIF_F_HIGHDMA;
- SET_MODULE_OWNER(dev);
spin_lock_init(&data->txlock);
spin_lock_init(&data->misclock);
@@ -1632,10 +1629,8 @@ tsi108_init_one(struct platform_device *pdev)
goto register_fail;
}
- printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n"
+ dev->name, print_mac(mac, dev->dev_addr));
#ifdef DEBUG
data->msg_enable = DEBUG;
dump_eth_one(dev);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index d380e0b3f05a..77d9dd7ea34f 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -264,10 +264,10 @@ struct de_srom_info_leaf {
} __attribute__((packed));
struct de_desc {
- u32 opts1;
- u32 opts2;
- u32 addr1;
- u32 addr2;
+ __le32 opts1;
+ __le32 opts2;
+ __le32 addr1;
+ __le32 addr2;
};
struct media_info {
@@ -1670,8 +1670,6 @@ static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static const struct ethtool_ops de_ethtool_ops = {
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
.get_drvinfo = de_get_drvinfo,
.get_regs_len = de_get_regs_len,
.get_settings = de_get_settings,
@@ -1773,8 +1771,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
/* download entire eeprom */
for (i = 0; i < DE_EEPROM_WORDS; i++)
- ((u16 *)ee_data)[i] =
- le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
+ ((__le16 *)ee_data)[i] =
+ cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size));
/* DEC now has a specification but early board makers
just put the address in the first EEPROM locations. */
@@ -1931,6 +1929,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
void __iomem *regs;
unsigned long pciaddr;
static int board_idx = -1;
+ DECLARE_MAC_BUF(mac);
board_idx++;
@@ -1944,7 +1943,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->open = de_open;
dev->stop = de_close;
@@ -2045,15 +2043,11 @@ static int __devinit de_init_one (struct pci_dev *pdev,
goto err_out_iomap;
/* print info about board and interface just registered */
- printk (KERN_INFO "%s: %s at 0x%lx, "
- "%02x:%02x:%02x:%02x:%02x:%02x, "
- "IRQ %d\n",
+ printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n",
dev->name,
de->de21040 ? "21040" : "21041",
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 09902891a6e6..9b9cd83fb8b6 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -482,7 +482,7 @@
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((u_short *)(a)))
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a)))
/*
** MII Information
@@ -756,10 +756,10 @@ struct de4x5_srom {
/* Multiple of 4 for DC21040 */
/* Allows 512 byte alignment */
struct de4x5_desc {
- volatile s32 status;
- u32 des1;
- u32 buf;
- u32 next;
+ volatile __le32 status;
+ __le32 des1;
+ __le32 buf;
+ __le32 next;
DESC_ALIGN
};
@@ -1088,6 +1088,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
struct de4x5_private *lp = netdev_priv(dev);
struct pci_dev *pdev = NULL;
int i, status=0;
+ DECLARE_MAC_BUF(mac);
gendev->driver_data = dev;
@@ -1123,12 +1124,8 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
dev->base_addr = iobase;
printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase);
- printk(", h/w address ");
status = get_hw_addr(dev);
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x,\n", dev->dev_addr[i]);
+ printk(", h/w address %s\n", print_mac(mac, dev->dev_addr));
if (status != 0) {
printk(" which has an Ethernet PROM CRC error.\n");
@@ -1261,7 +1258,6 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
}
/* The DE4X5-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gendev);
dev->open = &de4x5_open;
dev->hard_start_xmit = &de4x5_queue_pkt;
@@ -3946,7 +3942,7 @@ create_packet(struct net_device *dev, char *frame, int len)
static int
EISA_signature(char *name, struct device *device)
{
- int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+ int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures);
struct eisa_device *edev;
*name = '\0';
@@ -3967,7 +3963,7 @@ EISA_signature(char *name, struct device *device)
static int
PCI_signature(char *name, struct de4x5_private *lp)
{
- int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+ int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures);
if (lp->chipset == DC21040) {
strcpy(name, "DE434/5");
@@ -5073,7 +5069,7 @@ mii_get_phy(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
- int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
+ int i, j, k, n, limit=ARRAY_SIZE(phy_info);
int id;
lp->active = 0;
@@ -5469,19 +5465,16 @@ static void
de4x5_dbg_srom(struct de4x5_srom *p)
{
int i;
+ DECLARE_MAC_BUF(mac);
if (de4x5_debug & DEBUG_SROM) {
printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
printk("Sub-system ID: %04x\n", *((u_short *)p->sub_system_id));
printk("ID Block CRC: %02x\n", (u_char)(p->id_block_crc));
printk("SROM version: %02x\n", (u_char)(p->version));
- printk("# controllers: %02x\n", (u_char)(p->num_controllers));
+ printk("# controllers: %02x\n", (u_char)(p->num_controllers));
- printk("Hardware Address: ");
- for (i=0;i<ETH_ALEN-1;i++) {
- printk("%02x:", (u_char)*(p->ieee_addr+i));
- }
- printk("%02x\n", (u_char)*(p->ieee_addr+i));
+ printk("Hardware Address: %s\n", print_mac(mac, p->ieee_addr));
printk("CRC checksum: %04x\n", (u_short)(p->chksum));
for (i=0; i<64; i++) {
printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
@@ -5495,21 +5488,12 @@ static void
de4x5_dbg_rx(struct sk_buff *skb, int len)
{
int i, j;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
if (de4x5_debug & DEBUG_RX) {
- printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
- (u_char)skb->data[0],
- (u_char)skb->data[1],
- (u_char)skb->data[2],
- (u_char)skb->data[3],
- (u_char)skb->data[4],
- (u_char)skb->data[5],
- (u_char)skb->data[6],
- (u_char)skb->data[7],
- (u_char)skb->data[8],
- (u_char)skb->data[9],
- (u_char)skb->data[10],
- (u_char)skb->data[11],
+ printk("R: %s <- %s len/SAP:%02x%02x [%d]\n",
+ print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]),
(u_char)skb->data[12],
(u_char)skb->data[13],
len);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index dab74feb44bc..ca90566d5bcd 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -362,6 +362,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
struct net_device *dev;
u32 pci_pmr;
int i, err;
+ DECLARE_MAC_BUF(mac);
DMFE_DBUG(0, "dmfe_init_one()", 0);
@@ -372,7 +373,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*db));
if (dev == NULL)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -471,13 +471,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
if (err)
goto err_out_res;
- printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,",
- dev->name,
- ent->driver_data >> 16,
- pci_name(pdev));
- for (i = 0; i < 6; i++)
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- printk(", irq %d.\n", dev->irq);
+ printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, "
+ "%s, irq %d.\n",
+ dev->name,
+ ent->driver_data >> 16,
+ pci_name(pdev),
+ print_mac(mac, dev->dev_addr),
+ dev->irq);
pci_set_master(pdev);
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 53efd6694e75..365331446387 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -103,28 +103,29 @@ int tulip_refill_rx(struct net_device *dev)
void oom_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
- netif_rx_schedule(dev);
+ struct tulip_private *tp = netdev_priv(dev);
+ netif_rx_schedule(dev, &tp->napi);
}
-int tulip_poll(struct net_device *dev, int *budget)
+int tulip_poll(struct napi_struct *napi, int budget)
{
- struct tulip_private *tp = netdev_priv(dev);
+ struct tulip_private *tp = container_of(napi, struct tulip_private, napi);
+ struct net_device *dev = tp->dev;
int entry = tp->cur_rx % RX_RING_SIZE;
- int rx_work_limit = *budget;
+ int work_done = 0;
+#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
int received = 0;
+#endif
if (!netif_running(dev))
goto done;
- if (rx_work_limit > dev->quota)
- rx_work_limit = dev->quota;
-
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
/* that one buffer is needed for mit activation; or might be a
bug in the ring buffer code; check later -- JHS*/
- if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--;
+ if (budget >=RX_RING_SIZE) budget--;
#endif
if (tulip_debug > 4)
@@ -144,14 +145,13 @@ int tulip_poll(struct net_device *dev, int *budget)
while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status);
-
if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
break;
if (tulip_debug > 5)
printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
dev->name, entry, status);
- if (--rx_work_limit < 0)
+ if (work_done++ >= budget)
goto not_done;
if ((status & 0x38008300) != 0x0300) {
@@ -238,7 +238,9 @@ int tulip_poll(struct net_device *dev, int *budget)
tp->stats.rx_packets++;
tp->stats.rx_bytes += pkt_len;
}
- received++;
+#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
+ received++;
+#endif
entry = (++tp->cur_rx) % RX_RING_SIZE;
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
@@ -296,17 +298,15 @@ done:
#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
- dev->quota -= received;
- *budget -= received;
-
tulip_refill_rx(dev);
/* If RX ring is not full we are out of memory. */
- if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
+ if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+ goto oom;
/* Remove us from polling list and enable RX intr. */
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
/* The last op happens after poll completion. Which means the following:
@@ -320,28 +320,20 @@ done:
* processed irqs. But it must not result in losing events.
*/
- return 0;
+ return work_done;
not_done:
- if (!received) {
-
- received = dev->quota; /* Not to happen */
- }
- dev->quota -= received;
- *budget -= received;
-
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
tulip_refill_rx(dev);
- if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
-
- return 1;
+ if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+ goto oom;
+ return work_done;
oom: /* Executed with RX ints disabled */
-
/* Start timer, stop polling, but do not enable rx interrupts. */
mod_timer(&tp->oom_timer, jiffies+1);
@@ -350,9 +342,9 @@ done:
* before we did netif_rx_complete(). See? We would lose it. */
/* remove ourselves from the polling list */
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
- return 0;
+ return work_done;
}
#else /* CONFIG_TULIP_NAPI */
@@ -534,7 +526,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
rxd++;
/* Mask RX intrs and add the device to poll list. */
iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &tp->napi);
if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
break;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 16f26a8364f0..3f69f53d7768 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -178,18 +178,18 @@ enum tulip_busconfig_bits {
/* The Tulip Rx and Tx buffer descriptors. */
struct tulip_rx_desc {
- s32 status;
- s32 length;
- u32 buffer1;
- u32 buffer2;
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2;
};
struct tulip_tx_desc {
- s32 status;
- s32 length;
- u32 buffer1;
- u32 buffer2; /* We use only buffer 1. */
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2; /* We use only buffer 1. */
};
@@ -353,6 +353,7 @@ struct tulip_private {
int chip_id;
int revision;
int flags;
+ struct napi_struct napi;
struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
struct timer_list oom_timer; /* Out of memory timer. */
@@ -429,7 +430,7 @@ extern int tulip_rx_copybreak;
irqreturn_t tulip_interrupt(int irq, void *dev_instance);
int tulip_refill_rx(struct net_device *dev);
#ifdef CONFIG_TULIP_NAPI
-int tulip_poll(struct net_device *dev, int *budget);
+int tulip_poll(struct napi_struct *napi, int budget);
#endif
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index f87d76981ab7..ee08292bcf85 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -294,6 +294,10 @@ static void tulip_up(struct net_device *dev)
int next_tick = 3*HZ;
int i;
+#ifdef CONFIG_TULIP_NAPI
+ napi_enable(&tp->napi);
+#endif
+
/* Wake the chip from sleep/snooze mode. */
tulip_set_power_state (tp, 0, 0);
@@ -322,8 +326,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((u32 *)dev->dev_addr));
- u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4)));
+ 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)));
if (tp->chip_id == AX88140) {
iowrite32(0, ioaddr + CSR13);
iowrite32(addr_low, ioaddr + CSR14);
@@ -728,6 +732,10 @@ static void tulip_down (struct net_device *dev)
flush_scheduled_work();
+#ifdef CONFIG_TULIP_NAPI
+ napi_disable(&tp->napi);
+#endif
+
del_timer_sync (&tp->timer);
#ifdef CONFIG_TULIP_NAPI
del_timer_sync (&tp->oom_timer);
@@ -1043,12 +1051,11 @@ static void set_rx_mode(struct net_device *dev)
filterbit &= 0x3f;
mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
if (tulip_debug > 2) {
- printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
- "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name,
- mclist->dmi_addr[0], mclist->dmi_addr[1],
- mclist->dmi_addr[2], mclist->dmi_addr[3],
- mclist->dmi_addr[4], mclist->dmi_addr[5],
- ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_INFO "%s: Added filter for %s"
+ " %8.8x bit %d.\n",
+ dev->name, print_mac(mac, mclist->dmi_addr),
+ ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
}
}
if (mc_filter[0] == tp->mc_filter[0] &&
@@ -1248,6 +1255,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
const char *chip_name = tulip_tbl[chip_idx].chip_name;
unsigned int eeprom_missing = 0;
unsigned int force_csr0 = 0;
+ DECLARE_MAC_BUF(mac);
#ifndef MODULE
static int did_version; /* Already printed version info. */
@@ -1337,7 +1345,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
@@ -1436,13 +1443,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
do
value = ioread32(ioaddr + CSR9);
while (value < 0 && --boguscnt > 0);
- put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+ put_unaligned(cpu_to_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)), (u32 *)dev->dev_addr);
- put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (u16 *)(dev->dev_addr + 4));
+ 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));
for (i = 0; i < 6; i ++)
sum += dev->dev_addr[i];
} else {
@@ -1471,14 +1478,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
sa_offset = 2; /* Grrr, damn Matrox boards. */
multiport_cnt = 4;
}
-#ifdef CONFIG_DDB5477
- if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) {
- /* DDB5477 MAC address in first EEPROM locations. */
- sa_offset = 0;
- /* No media table either */
- tp->flags &= ~HAS_MEDIA_TABLE;
- }
-#endif
#ifdef CONFIG_MIPS_COBALT
if ((pdev->bus->number == 0) &&
((PCI_SLOT(pdev->devfn) == 7) ||
@@ -1614,8 +1613,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->tx_timeout = tulip_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_TULIP_NAPI
- dev->poll = tulip_poll;
- dev->weight = 16;
+ netif_napi_add(dev, &tp->napi, tulip_poll, 16);
#endif
dev->stop = tulip_close;
dev->get_stats = tulip_get_stats;
@@ -1641,8 +1639,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (eeprom_missing)
printk(" EEPROM not present,");
- for (i = 0; i < 6; i++)
- printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
+ printk(" %s", print_mac(mac, dev->dev_addr));
printk(", IRQ %d.\n", irq);
if (tp->chip_id == PNIC2)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index ca2548eb7d63..76e55612430b 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -112,13 +112,13 @@
/* Structure/enum declaration ------------------------------- */
struct tx_desc {
- u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+ __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
char *tx_buf_ptr; /* Data for us */
struct tx_desc *next_tx_desc;
} __attribute__(( aligned(32) ));
struct rx_desc {
- u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+ __le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
struct sk_buff *rx_skb_ptr; /* Data for us */
struct rx_desc *next_rx_desc;
} __attribute__(( aligned(32) ));
@@ -258,6 +258,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
struct uli526x_board_info *db; /* board information structure */
struct net_device *dev;
int i, err;
+ DECLARE_MAC_BUF(mac);
ULI526X_DBUG(0, "uli526x_init_one()", 0);
@@ -268,7 +269,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*db));
if (dev == NULL)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -344,7 +344,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
/* read 64 word srom data */
for (i = 0; i < 64; i++)
- ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+ ((__le16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
/* Set Node address */
if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0) /* SROM absent, so read MAC address from ID Table */
@@ -373,11 +373,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
if (err)
goto err_out_res;
- printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev));
-
- for (i = 0; i < 6; i++)
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- printk(", irq %d.\n", dev->irq);
+ printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n",
+ dev->name,ent->driver_data >> 16,pci_name(pdev),
+ print_mac(mac, dev->dev_addr), dev->irq);
pci_set_master(pdev);
@@ -666,11 +664,6 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
- if (!dev) {
- ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0);
- return IRQ_NONE;
- }
-
spin_lock_irqsave(&db->lock, flags);
outl(0, ioaddr + DCR7);
@@ -1110,19 +1103,15 @@ static void uli526x_timer(unsigned long data)
/*
- * Dynamic reset the ULI526X board
* Stop ULI526X board
* Free Tx/Rx allocated memory
- * Reset ULI526X board
- * Re-initialize ULI526X board
+ * Init system variable
*/
-static void uli526x_dynamic_reset(struct net_device *dev)
+static void uli526x_reset_prepare(struct net_device *dev)
{
struct uli526x_board_info *db = netdev_priv(dev);
- ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
-
/* Sopt MAC controller */
db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
update_cr6(db->cr6_data, dev->base_addr);
@@ -1141,6 +1130,22 @@ static void uli526x_dynamic_reset(struct net_device *dev)
db->link_failed = 1;
db->init=1;
db->wait_reset = 0;
+}
+
+
+/*
+ * Dynamic reset the ULI526X board
+ * Stop ULI526X board
+ * Free Tx/Rx allocated memory
+ * Reset ULI526X board
+ * Re-initialize ULI526X board
+ */
+
+static void uli526x_dynamic_reset(struct net_device *dev)
+{
+ ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
+
+ uli526x_reset_prepare(dev);
/* Re-initialize ULI526X board */
uli526x_init(dev);
@@ -1150,6 +1155,88 @@ static void uli526x_dynamic_reset(struct net_device *dev)
}
+#ifdef CONFIG_PM
+
+/*
+ * Suspend the interface.
+ */
+
+static int uli526x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ pci_power_t power_state;
+ int err;
+
+ ULI526X_DBUG(0, "uli526x_suspend", 0);
+
+ if (!netdev_priv(dev))
+ return 0;
+
+ pci_save_state(pdev);
+
+ if (!netif_running(dev))
+ return 0;
+
+ netif_device_detach(dev);
+ uli526x_reset_prepare(dev);
+
+ power_state = pci_choose_state(pdev, state);
+ pci_enable_wake(pdev, power_state, 0);
+ err = pci_set_power_state(pdev, power_state);
+ if (err) {
+ netif_device_attach(dev);
+ /* Re-initialize ULI526X board */
+ uli526x_init(dev);
+ /* Restart upper layer interface */
+ netif_wake_queue(dev);
+ }
+
+ return err;
+}
+
+/*
+ * Resume the interface.
+ */
+
+static int uli526x_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ int err;
+
+ ULI526X_DBUG(0, "uli526x_resume", 0);
+
+ if (!netdev_priv(dev))
+ return 0;
+
+ pci_restore_state(pdev);
+
+ if (!netif_running(dev))
+ return 0;
+
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err) {
+ printk(KERN_WARNING "%s: Could not put device into D0\n",
+ dev->name);
+ return err;
+ }
+
+ netif_device_attach(dev);
+ /* Re-initialize ULI526X board */
+ uli526x_init(dev);
+ /* Restart upper layer interface */
+ netif_wake_queue(dev);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+
+#define uli526x_suspend NULL
+#define uli526x_resume NULL
+
+#endif /* !CONFIG_PM */
+
+
/*
* free all allocated rx buffer
*/
@@ -1512,7 +1599,6 @@ static void uli526x_process_mode(struct uli526x_board_info *db)
case ULI526X_100MFD: phy_reg = 0x2100; break;
}
phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
- phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
}
}
}
@@ -1689,6 +1775,8 @@ static struct pci_driver uli526x_driver = {
.id_table = uli526x_pci_tbl,
.probe = uli526x_init_one,
.remove = __devexit_p(uli526x_remove_one),
+ .suspend = uli526x_suspend,
+ .resume = uli526x_resume,
};
MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw");
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 5824f6a35495..3c8e3b63be07 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -354,6 +354,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
int irq;
int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
void __iomem *ioaddr;
+ DECLARE_MAC_BUF(mac);
i = pci_enable_device(pdev);
if (i) return i;
@@ -370,7 +371,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*np));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, DRV_NAME))
@@ -381,7 +381,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
goto err_out_free_res;
for (i = 0; i < 3; i++)
- ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
+ ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i));
/* Reset the chip to erase previous misconfiguration.
No hold time required! */
@@ -434,11 +434,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
if (i)
goto err_out_cleardev;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
if (np->drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
@@ -1246,16 +1244,16 @@ static int netdev_rx(struct net_device *dev)
}
#ifndef final_version /* Remove after testing. */
/* You will want this info for the initial debug. */
- if (debug > 5)
- printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
- "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
- "%d.%d.%d.%d.\n",
- skb->data[0], skb->data[1], skb->data[2], skb->data[3],
- skb->data[4], skb->data[5], skb->data[6], skb->data[7],
- skb->data[8], skb->data[9], skb->data[10],
- skb->data[11], skb->data[12], skb->data[13],
- skb->data[14], skb->data[15], skb->data[16],
- skb->data[17]);
+ if (debug > 5) {
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG " Rx data %s %s"
+ " %2.2x%2.2x %d.%d.%d.%d.\n",
+ print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]),
+ skb->data[12], skb->data[13],
+ skb->data[14], skb->data[15], skb->data[16], skb->data[17]);
+ }
#endif
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -1452,8 +1450,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 16a54e6b8d4f..70befe33e454 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -252,7 +252,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
goto tx_buf_fail;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -271,7 +270,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
dev->hard_start_xmit = &xircom_start_xmit;
dev->stop = &xircom_close;
dev->get_stats = &xircom_get_stats;
- dev->priv = private;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &xircom_poll_controller;
#endif
@@ -1076,6 +1074,7 @@ static void read_mac_address(struct xircom_private *card)
unsigned char j, tuple, link, data_id, data_count;
unsigned long flags;
int i;
+ DECLARE_MAC_BUF(mac);
enter("read_mac_address");
@@ -1105,11 +1104,7 @@ static void read_mac_address(struct xircom_private *card)
}
}
spin_unlock_irqrestore(&card->lock, flags);
-#ifdef DEBUG
- for (i = 0; i < 6; i++)
- printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
- printk("\n");
-#endif
+ pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr));
leave("read_mac_address");
}
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index fc439f333350..c3f8e303c6c7 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -547,7 +547,6 @@ static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_devi
printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx);
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->base_addr = ioaddr;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 62b2b3005019..1f7644695976 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -62,6 +62,7 @@
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/crc32.h>
+#include <net/net_namespace.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -109,7 +110,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
/* We won't see all dropped packets individually, so overrun
* error is more appropriate. */
- tun->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
} else {
/* Single queue mode.
* Driver handles dropping of all packets itself. */
@@ -128,7 +129,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
drop:
- tun->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
kfree_skb(skb);
return 0;
}
@@ -158,23 +159,28 @@ tun_net_mclist(struct net_device *dev)
struct tun_struct *tun = netdev_priv(dev);
const struct dev_mc_list *mclist;
int i;
+ DECLARE_MAC_BUF(mac);
DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n",
dev->name, dev->mc_count);
memset(tun->chr_filter, 0, sizeof tun->chr_filter);
for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL;
i++, mclist = mclist->next) {
add_multi(tun->net_filter, mclist->dmi_addr);
- DBG(KERN_DEBUG "%s: tun_net_mclist: %x:%x:%x:%x:%x:%x\n",
- dev->name,
- mclist->dmi_addr[0], mclist->dmi_addr[1], mclist->dmi_addr[2],
- mclist->dmi_addr[3], mclist->dmi_addr[4], mclist->dmi_addr[5]);
+ DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n",
+ dev->name, print_mac(mac, mclist->dmi_addr));
}
}
-static struct net_device_stats *tun_net_stats(struct net_device *dev)
+#define MIN_MTU 68
+#define MAX_MTU 65535
+
+static int
+tun_net_change_mtu(struct net_device *dev, int new_mtu)
{
- struct tun_struct *tun = netdev_priv(dev);
- return &tun->stats;
+ if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
}
/* Initialize net device. */
@@ -188,6 +194,7 @@ static void tun_net_init(struct net_device *dev)
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->mtu = 1500;
+ dev->change_mtu = tun_net_change_mtu;
/* Zero header length */
dev->type = ARPHRD_NONE;
@@ -200,6 +207,7 @@ static void tun_net_init(struct net_device *dev)
dev->set_multicast_list = tun_net_mclist;
ether_setup(dev);
+ dev->change_mtu = tun_net_change_mtu;
/* random address already created for us by tun_set_iff, use it */
memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) );
@@ -249,14 +257,14 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
align = NET_IP_ALIGN;
if (!(skb = alloc_skb(len + align, GFP_KERNEL))) {
- tun->stats.rx_dropped++;
+ tun->dev->stats.rx_dropped++;
return -ENOMEM;
}
if (align)
skb_reserve(skb, align);
if (memcpy_fromiovec(skb_put(skb, len), iv, len)) {
- tun->stats.rx_dropped++;
+ tun->dev->stats.rx_dropped++;
kfree_skb(skb);
return -EFAULT;
}
@@ -278,8 +286,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
netif_rx_ni(skb);
tun->dev->last_rx = jiffies;
- tun->stats.rx_packets++;
- tun->stats.rx_bytes += len;
+ tun->dev->stats.rx_packets++;
+ tun->dev->stats.rx_bytes += len;
return count;
}
@@ -335,8 +343,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
skb_copy_datagram_iovec(skb, 0, iv, len);
total += len;
- tun->stats.tx_packets++;
- tun->stats.tx_bytes += len;
+ tun->dev->stats.tx_packets++;
+ tun->dev->stats.tx_bytes += len;
return total;
}
@@ -349,6 +357,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
DECLARE_WAITQUEUE(wait, current);
struct sk_buff *skb;
ssize_t len, ret = 0;
+ DECLARE_MAC_BUF(mac);
if (!tun)
return -EBADFD;
@@ -403,16 +412,14 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
(addr[0] == 0x33 && addr[1] == 0x33)) &&
((tun->if_flags & IFF_ALLMULTI) ||
(tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) {
- DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name, addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
+ DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n",
+ tun->dev->name, print_mac(mac, addr));
ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
kfree_skb(skb);
break;
} else {
- DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name, addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
+ DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n",
+ tun->dev->name, print_mac(mac, addr));
kfree_skb(skb);
continue;
}
@@ -434,11 +441,9 @@ static void tun_setup(struct net_device *dev)
tun->owner = -1;
tun->group = -1;
- SET_MODULE_OWNER(dev);
dev->open = tun_net_open;
dev->hard_start_xmit = tun_net_xmit;
dev->stop = tun_net_close;
- dev->get_stats = tun_net_stats;
dev->ethtool_ops = &tun_ethtool_ops;
dev->destructor = free_netdev;
}
@@ -475,7 +480,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
!capable(CAP_NET_ADMIN))
return -EPERM;
}
- else if (__dev_get_by_name(ifr->ifr_name))
+ else if (__dev_get_by_name(&init_net, ifr->ifr_name))
return -EINVAL;
else {
char *name;
@@ -557,6 +562,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
struct tun_struct *tun = file->private_data;
void __user* argp = (void __user*)arg;
struct ifreq ifr;
+ DECLARE_MAC_BUF(mac);
if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
if (copy_from_user(&ifr, argp, sizeof ifr))
@@ -685,22 +691,16 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
/** Add the specified group to the character device's multicast filter
* list. */
add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
- DBG(KERN_DEBUG "%s: add multi: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name,
- (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
- (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
- (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
+ DBG(KERN_DEBUG "%s: add multi: %s\n",
+ tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
return 0;
case SIOCDELMULTI:
/** Remove the specified group from the character device's multicast
* filter list. */
del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
- DBG(KERN_DEBUG "%s: del multi: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name,
- (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
- (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
- (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
+ DBG(KERN_DEBUG "%s: del multi: %s\n",
+ tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
return 0;
default:
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 03587205546e..72e5e9be7e99 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -284,6 +284,7 @@ struct typhoon {
struct basic_ring rxLoRing;
struct pci_dev * pdev;
struct net_device * dev;
+ struct napi_struct napi;
spinlock_t state_lock;
struct vlan_group * vlgrp;
struct basic_ring rxHiRing;
@@ -299,9 +300,9 @@ struct typhoon {
const char * name;
struct typhoon_shared * shared;
dma_addr_t shared_dma;
- u16 xcvr_select;
- u16 wol_events;
- u32 offload;
+ __le16 xcvr_select;
+ __le16 wol_events;
+ __le32 offload;
/* unused stuff (future use) */
int capabilities;
@@ -827,7 +828,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
first_txd->processFlags |=
TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
first_txd->processFlags |=
- cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
+ cpu_to_le32(ntohs(vlan_tx_tag_get(skb)) <<
TYPHOON_TX_PF_VLAN_TAG_SHIFT);
}
@@ -919,7 +920,7 @@ typhoon_set_rx_mode(struct net_device *dev)
struct typhoon *tp = netdev_priv(dev);
struct cmd_desc xp_cmd;
u32 mc_filter[2];
- u16 filter;
+ __le16 filter;
filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
if(dev->flags & IFF_PROMISC) {
@@ -1130,7 +1131,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct typhoon *tp = netdev_priv(dev);
struct cmd_desc xp_cmd;
- int xcvr;
+ __le16 xcvr;
int err;
err = -EINVAL;
@@ -1235,11 +1236,8 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
.set_wol = typhoon_set_wol,
.get_link = ethtool_op_get_link,
.get_rx_csum = typhoon_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_ringparam = typhoon_get_ringparam,
};
@@ -1538,7 +1536,7 @@ out_timeout:
static u32
typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
- volatile u32 * index)
+ volatile __le32 * index)
{
u32 lastRead = txRing->lastRead;
struct tx_desc *tx;
@@ -1574,7 +1572,7 @@ typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
static void
typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing,
- volatile u32 * index)
+ volatile __le32 * index)
{
u32 lastRead;
int numDesc = MAX_SKB_FRAGS + 1;
@@ -1664,8 +1662,8 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx)
}
static int
-typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
- volatile u32 * cleared, int budget)
+typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * ready,
+ volatile __le32 * cleared, int budget)
{
struct rx_desc *rx;
struct sk_buff *skb, *new_skb;
@@ -1675,7 +1673,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
u32 rxaddr;
int pkt_len;
u32 idx;
- u32 csum_bits;
+ __le32 csum_bits;
int received;
received = 0;
@@ -1759,12 +1757,12 @@ typhoon_fill_free_ring(struct typhoon *tp)
}
static int
-typhoon_poll(struct net_device *dev, int *total_budget)
+typhoon_poll(struct napi_struct *napi, int budget)
{
- struct typhoon *tp = netdev_priv(dev);
+ struct typhoon *tp = container_of(napi, struct typhoon, napi);
+ struct net_device *dev = tp->dev;
struct typhoon_indexes *indexes = tp->indexes;
- int orig_budget = *total_budget;
- int budget, work_done, done;
+ int work_done;
rmb();
if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared)
@@ -1773,30 +1771,16 @@ typhoon_poll(struct net_device *dev, int *total_budget)
if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead)
typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared);
- if(orig_budget > dev->quota)
- orig_budget = dev->quota;
-
- budget = orig_budget;
work_done = 0;
- done = 1;
if(indexes->rxHiCleared != indexes->rxHiReady) {
- work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
+ work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
&indexes->rxHiCleared, budget);
- budget -= work_done;
}
if(indexes->rxLoCleared != indexes->rxLoReady) {
work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady,
- &indexes->rxLoCleared, budget);
- }
-
- if(work_done) {
- *total_budget -= work_done;
- dev->quota -= work_done;
-
- if(work_done >= orig_budget)
- done = 0;
+ &indexes->rxLoCleared, budget - work_done);
}
if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) {
@@ -1804,14 +1788,14 @@ typhoon_poll(struct net_device *dev, int *total_budget)
typhoon_fill_free_ring(tp);
}
- if(done) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
iowrite32(TYPHOON_INTR_NONE,
tp->ioaddr + TYPHOON_REG_INTR_MASK);
typhoon_post_pci_writes(tp->ioaddr);
}
- return (done ? 0 : 1);
+ return work_done;
}
static irqreturn_t
@@ -1828,10 +1812,10 @@ typhoon_interrupt(int irq, void *dev_instance)
iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
- if(netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &tp->napi)) {
iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
typhoon_post_pci_writes(ioaddr);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &tp->napi);
} else {
printk(KERN_ERR "%s: Error, poll already scheduled\n",
dev->name);
@@ -1856,7 +1840,7 @@ typhoon_free_rx_rings(struct typhoon *tp)
}
static int
-typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events)
+typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events)
{
struct pci_dev *pdev = tp->pdev;
void __iomem *ioaddr = tp->ioaddr;
@@ -1944,8 +1928,8 @@ typhoon_start_runtime(struct typhoon *tp)
goto error_out;
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
- xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
- xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+ xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
+ xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
if(err < 0)
goto error_out;
@@ -2119,9 +2103,13 @@ typhoon_open(struct net_device *dev)
if(err < 0)
goto out_sleep;
+ napi_enable(&tp->napi);
+
err = typhoon_start_runtime(tp);
- if(err < 0)
+ if(err < 0) {
+ napi_disable(&tp->napi);
goto out_irq;
+ }
netif_start_queue(dev);
return 0;
@@ -2150,6 +2138,7 @@ typhoon_close(struct net_device *dev)
struct typhoon *tp = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&tp->napi);
if(typhoon_stop_runtime(tp, WaitSleep) < 0)
printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
@@ -2240,8 +2229,8 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
}
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
- xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
- xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+ xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
+ xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
printk(KERN_ERR "%s: unable to set mac address in suspend\n",
dev->name);
@@ -2327,8 +2316,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dma_addr_t shared_dma;
struct cmd_desc xp_cmd;
struct resp_desc xp_resp[3];
- int i;
int err = 0;
+ DECLARE_MAC_BUF(mac);
if(!did_version++)
printk(KERN_INFO "%s", version);
@@ -2340,7 +2329,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto error_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = pci_enable_device(pdev);
@@ -2477,8 +2465,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error_out_reset;
}
- *(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
- *(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+ *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
+ *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
if(!is_valid_ether_addr(dev->dev_addr)) {
printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
@@ -2521,8 +2509,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->stop = typhoon_close;
dev->set_multicast_list = typhoon_set_rx_mode;
dev->tx_timeout = typhoon_tx_timeout;
- dev->poll = typhoon_poll;
- dev->weight = 16;
+ netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
dev->watchdog_timeo = TX_TIMEOUT;
dev->get_stats = typhoon_get_stats;
dev->set_mac_address = typhoon_set_mac_address;
@@ -2545,13 +2532,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
- printk(KERN_INFO "%s: %s at %s 0x%llx, ",
+ printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n",
dev->name, typhoon_card_info[card_id].name,
use_mmio ? "MMIO" : "IO",
- (unsigned long long)pci_resource_start(pdev, use_mmio));
- for(i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x\n", dev->dev_addr[i]);
+ (unsigned long long)pci_resource_start(pdev, use_mmio),
+ print_mac(mac, dev->dev_addr));
/* xp_resp still contains the response to the READ_VERSIONS command.
* For debugging, let the user know what version he has.
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 2f14a050051b..19df20889b82 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -64,19 +64,19 @@ struct transmit_ring {
*/
struct typhoon_indexes {
/* The first four are written by the host, and read by the NIC */
- volatile u32 rxHiCleared;
- volatile u32 rxLoCleared;
- volatile u32 rxBuffReady;
- volatile u32 respCleared;
+ volatile __le32 rxHiCleared;
+ volatile __le32 rxLoCleared;
+ volatile __le32 rxBuffReady;
+ volatile __le32 respCleared;
/* The remaining are written by the NIC, and read by the host */
- volatile u32 txLoCleared;
- volatile u32 txHiCleared;
- volatile u32 rxLoReady;
- volatile u32 rxBuffCleared;
- volatile u32 cmdCleared;
- volatile u32 respReady;
- volatile u32 rxHiReady;
+ volatile __le32 txLoCleared;
+ volatile __le32 txHiCleared;
+ volatile __le32 rxLoReady;
+ volatile __u32 rxBuffCleared; /* AV: really? */
+ volatile __le32 cmdCleared;
+ volatile __le32 respReady;
+ volatile __le32 rxHiReady;
} __attribute__ ((packed));
/* The host<->Typhoon interface
@@ -100,31 +100,31 @@ struct typhoon_indexes {
* be zero.
*/
struct typhoon_interface {
- u32 ringIndex;
- u32 ringIndexHi;
- u32 txLoAddr;
- u32 txLoAddrHi;
- u32 txLoSize;
- u32 txHiAddr;
- u32 txHiAddrHi;
- u32 txHiSize;
- u32 rxLoAddr;
- u32 rxLoAddrHi;
- u32 rxLoSize;
- u32 rxBuffAddr;
- u32 rxBuffAddrHi;
- u32 rxBuffSize;
- u32 cmdAddr;
- u32 cmdAddrHi;
- u32 cmdSize;
- u32 respAddr;
- u32 respAddrHi;
- u32 respSize;
- u32 zeroAddr;
- u32 zeroAddrHi;
- u32 rxHiAddr;
- u32 rxHiAddrHi;
- u32 rxHiSize;
+ __le32 ringIndex;
+ __le32 ringIndexHi;
+ __le32 txLoAddr;
+ __le32 txLoAddrHi;
+ __le32 txLoSize;
+ __le32 txHiAddr;
+ __le32 txHiAddrHi;
+ __le32 txHiSize;
+ __le32 rxLoAddr;
+ __le32 rxLoAddrHi;
+ __le32 rxLoSize;
+ __le32 rxBuffAddr;
+ __le32 rxBuffAddrHi;
+ __le32 rxBuffSize;
+ __le32 cmdAddr;
+ __le32 cmdAddrHi;
+ __le32 cmdSize;
+ __le32 respAddr;
+ __le32 respAddrHi;
+ __le32 respSize;
+ __le32 zeroAddr;
+ __le32 zeroAddrHi;
+ __le32 rxHiAddr;
+ __le32 rxHiAddrHi;
+ __le32 rxHiSize;
} __attribute__ ((packed));
/* The Typhoon transmit/fragment descriptor
@@ -165,10 +165,10 @@ struct tx_desc {
#define TYPHOON_RX_ERROR 0x40
#define TYPHOON_DESC_VALID 0x80
u8 numDesc;
- u16 len;
+ __le16 len;
u32 addr;
u32 addrHi;
- u32 processFlags;
+ __le32 processFlags;
#define TYPHOON_TX_PF_NO_CRC __constant_cpu_to_le32(0x00000001)
#define TYPHOON_TX_PF_IP_CHKSUM __constant_cpu_to_le32(0x00000002)
#define TYPHOON_TX_PF_TCP_CHKSUM __constant_cpu_to_le32(0x00000004)
@@ -197,12 +197,12 @@ struct tx_desc {
struct tcpopt_desc {
u8 flags;
u8 numDesc;
- u16 mss_flags;
+ __le16 mss_flags;
#define TYPHOON_TSO_FIRST __constant_cpu_to_le16(0x1000)
#define TYPHOON_TSO_LAST __constant_cpu_to_le16(0x2000)
- u32 respAddrLo;
- u32 bytesTx;
- u32 status;
+ __le32 respAddrLo;
+ __le32 bytesTx;
+ __le32 status;
} __attribute__ ((packed));
/* The IPSEC Offload descriptor
@@ -216,12 +216,12 @@ struct tcpopt_desc {
struct ipsec_desc {
u8 flags;
u8 numDesc;
- u16 ipsecFlags;
+ __le16 ipsecFlags;
#define TYPHOON_IPSEC_GEN_IV __constant_cpu_to_le16(0x0000)
#define TYPHOON_IPSEC_USE_IV __constant_cpu_to_le16(0x0001)
- u32 sa1;
- u32 sa2;
- u32 reserved;
+ __le32 sa1;
+ __le32 sa2;
+ __le32 reserved;
} __attribute__ ((packed));
/* The Typhoon receive descriptor (Updated by NIC)
@@ -239,10 +239,10 @@ struct ipsec_desc {
struct rx_desc {
u8 flags;
u8 numDesc;
- u16 frameLen;
+ __le16 frameLen;
u32 addr;
u32 addrHi;
- u32 rxStatus;
+ __le32 rxStatus;
#define TYPHOON_RX_ERR_INTERNAL __constant_cpu_to_le32(0x00000000)
#define TYPHOON_RX_ERR_FIFO_UNDERRUN __constant_cpu_to_le32(0x00000001)
#define TYPHOON_RX_ERR_BAD_SSD __constant_cpu_to_le32(0x00000002)
@@ -264,10 +264,10 @@ struct rx_desc {
#define TYPHOON_RX_IP_CHK_GOOD __constant_cpu_to_le32(0x00000100)
#define TYPHOON_RX_TCP_CHK_GOOD __constant_cpu_to_le32(0x00000200)
#define TYPHOON_RX_UDP_CHK_GOOD __constant_cpu_to_le32(0x00000400)
- u16 filterResults;
+ __le16 filterResults;
#define TYPHOON_RX_FILTER_MASK __constant_cpu_to_le16(0x7fff)
#define TYPHOON_RX_FILTERED __constant_cpu_to_le16(0x8000)
- u16 ipsecResults;
+ __le16 ipsecResults;
#define TYPHOON_RX_OUTER_AH_GOOD __constant_cpu_to_le16(0x0001)
#define TYPHOON_RX_OUTER_ESP_GOOD __constant_cpu_to_le16(0x0002)
#define TYPHOON_RX_INNER_AH_GOOD __constant_cpu_to_le16(0x0004)
@@ -278,7 +278,7 @@ struct rx_desc {
#define TYPHOON_RX_INNER_ESP_FAIL __constant_cpu_to_le16(0x0080)
#define TYPHOON_RX_UNKNOWN_SA __constant_cpu_to_le16(0x0100)
#define TYPHOON_RX_ESP_FORMAT_ERR __constant_cpu_to_le16(0x0200)
- u32 vlanTag;
+ __be32 vlanTag;
} __attribute__ ((packed));
/* The Typhoon free buffer descriptor, used to give a buffer to the NIC
@@ -292,8 +292,8 @@ struct rx_desc {
* from the NIC
*/
struct rx_free {
- u32 physAddr;
- u32 physAddrHi;
+ __le32 physAddr;
+ __le32 physAddrHi;
u32 virtAddr;
u32 virtAddrHi;
} __attribute__ ((packed));
@@ -312,7 +312,7 @@ struct rx_free {
struct cmd_desc {
u8 flags;
u8 numDesc;
- u16 cmd;
+ __le16 cmd;
#define TYPHOON_CMD_TX_ENABLE __constant_cpu_to_le16(0x0001)
#define TYPHOON_CMD_TX_DISABLE __constant_cpu_to_le16(0x0002)
#define TYPHOON_CMD_RX_ENABLE __constant_cpu_to_le16(0x0003)
@@ -339,9 +339,9 @@ struct cmd_desc {
#define TYPHOON_CMD_GET_IPSEC_ENABLE __constant_cpu_to_le16(0x0067)
#define TYPHOON_CMD_GET_CMD_LVL __constant_cpu_to_le16(0x0069)
u16 seqNo;
- u16 parm1;
- u32 parm2;
- u32 parm3;
+ __le16 parm1;
+ __le32 parm2;
+ __le32 parm3;
} __attribute__ ((packed));
/* The Typhoon response descriptor, see command descriptor for details
@@ -349,11 +349,11 @@ struct cmd_desc {
struct resp_desc {
u8 flags;
u8 numDesc;
- u16 cmd;
- u16 seqNo;
- u16 parm1;
- u32 parm2;
- u32 parm3;
+ __le16 cmd;
+ __le16 seqNo;
+ __le16 parm1;
+ __le32 parm2;
+ __le32 parm3;
} __attribute__ ((packed));
#define INIT_COMMAND_NO_RESPONSE(x, command) \
@@ -386,31 +386,31 @@ struct resp_desc {
struct stats_resp {
u8 flags;
u8 numDesc;
- u16 cmd;
- u16 seqNo;
- u16 unused;
- u32 txPackets;
- u64 txBytes;
- u32 txDeferred;
- u32 txLateCollisions;
- u32 txCollisions;
- u32 txCarrierLost;
- u32 txMultipleCollisions;
- u32 txExcessiveCollisions;
- u32 txFifoUnderruns;
- u32 txMulticastTxOverflows;
- u32 txFiltered;
- u32 rxPacketsGood;
- u64 rxBytesGood;
- u32 rxFifoOverruns;
- u32 BadSSD;
- u32 rxCrcErrors;
- u32 rxOversized;
- u32 rxBroadcast;
- u32 rxMulticast;
- u32 rxOverflow;
- u32 rxFiltered;
- u32 linkStatus;
+ __le16 cmd;
+ __le16 seqNo;
+ __le16 unused;
+ __le32 txPackets;
+ __le64 txBytes;
+ __le32 txDeferred;
+ __le32 txLateCollisions;
+ __le32 txCollisions;
+ __le32 txCarrierLost;
+ __le32 txMultipleCollisions;
+ __le32 txExcessiveCollisions;
+ __le32 txFifoUnderruns;
+ __le32 txMulticastTxOverflows;
+ __le32 txFiltered;
+ __le32 rxPacketsGood;
+ __le64 rxBytesGood;
+ __le32 rxFifoOverruns;
+ __le32 BadSSD;
+ __le32 rxCrcErrors;
+ __le32 rxOversized;
+ __le32 rxBroadcast;
+ __le32 rxMulticast;
+ __le32 rxOverflow;
+ __le32 rxFiltered;
+ __le32 linkStatus;
#define TYPHOON_LINK_STAT_MASK __constant_cpu_to_le32(0x00000001)
#define TYPHOON_LINK_GOOD __constant_cpu_to_le32(0x00000001)
#define TYPHOON_LINK_BAD __constant_cpu_to_le32(0x00000000)
@@ -420,8 +420,8 @@ struct stats_resp {
#define TYPHOON_LINK_DUPLEX_MASK __constant_cpu_to_le32(0x00000004)
#define TYPHOON_LINK_FULL_DUPLEX __constant_cpu_to_le32(0x00000004)
#define TYPHOON_LINK_HALF_DUPLEX __constant_cpu_to_le32(0x00000000)
- u32 unused2;
- u32 unused3;
+ __le32 unused2;
+ __le32 unused3;
} __attribute__ ((packed));
/* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
@@ -509,17 +509,17 @@ struct sa_descriptor {
*/
struct typhoon_file_header {
u8 tag[8];
- u32 version;
- u32 numSections;
- u32 startAddr;
- u32 hmacDigest[5];
+ __le32 version;
+ __le32 numSections;
+ __le32 startAddr;
+ __le32 hmacDigest[5];
} __attribute__ ((packed));
struct typhoon_section_header {
- u32 len;
+ __le32 len;
u16 checksum;
u16 reserved;
- u32 startAddr;
+ __le32 startAddr;
} __attribute__ ((packed));
/* The Typhoon Register offsets
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index e4736a3b1b7a..d00e7d41f6a5 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -43,10 +43,6 @@
#undef DEBUG
-#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
-#define DRV_NAME "ucc_geth"
-#define DRV_VERSION "1.1"
-
#define ugeth_printk(level, format, arg...) \
printk(level format "\n", ## arg)
@@ -64,9 +60,19 @@
#else
#define ugeth_vdbg(fmt, args...) do { } while (0)
#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);
+static struct {
+ u32 msg_enable;
+} debug = { -1 };
+
+module_param_named(debug, debug.msg_enable, int, 0);
+MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 0xffff=all)");
+
static struct ucc_geth_info ugeth_primary_info = {
.uf_info = {
.bd_mem_part = MEM_PART_SYSTEM,
@@ -104,6 +110,7 @@ static struct ucc_geth_info ugeth_primary_info = {
.maxRetransmission = 0xf,
.collisionWindow = 0x37,
.receiveFlowControl = 1,
+ .transmitFlowControl = 1,
.maxGroupAddrInHash = 4,
.maxIndAddrInHash = 4,
.prel = 7,
@@ -139,7 +146,9 @@ static struct ucc_geth_info ugeth_primary_info = {
.numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1,
.largestexternallookupkeysize =
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE,
- .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE,
+ .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE |
+ UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX |
+ UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX,
.vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP,
.vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP,
.rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT,
@@ -281,7 +290,8 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
for (i = 0; i < num_entries; i++) {
if ((snum = qe_get_snum()) < 0) {
- ugeth_err("fill_init_enet_entries: Can not get SNUM.");
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("fill_init_enet_entries: Can not get SNUM.");
return snum;
}
if ((i == 0) && skip_page_for_first_entry)
@@ -291,8 +301,8 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
init_enet_offset =
qe_muram_alloc(thread_size, thread_alignment);
if (IS_ERR_VALUE(init_enet_offset)) {
- ugeth_err
- ("fill_init_enet_entries: Can not allocate DPRAM memory.");
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("fill_init_enet_entries: Can not allocate DPRAM memory.");
qe_put_snum((u8) snum);
return -ENOMEM;
}
@@ -1200,7 +1210,7 @@ static int init_inter_frame_gap_params(u8 non_btb_cs_ipg,
return 0;
}
-static int init_flow_control_params(u32 automatic_flow_control_mode,
+int init_flow_control_params(u32 automatic_flow_control_mode,
int rx_flow_control_enable,
int tx_flow_control_enable,
u16 pause_period,
@@ -1486,9 +1496,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2);
if (ret_val != 0) {
- ugeth_err
- ("%s: Preamble length must be between 3 and 7 inclusive.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: Preamble length must be between 3 and 7 inclusive.",
+ __FUNCTION__);
return ret_val;
}
@@ -1726,7 +1736,8 @@ static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode)
/* check if the UCC number is in range. */
if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
- ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
return -EINVAL;
}
@@ -1754,7 +1765,8 @@ static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode)
/* check if the UCC number is in range. */
if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
- ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
return -EINVAL;
}
@@ -2136,7 +2148,7 @@ 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,
- ((qe_bd_t *)bd)->buf,
+ ((struct qe_bd *)bd)->buf,
(in_be32((u32 *)bd) &
BD_LENGTH_MASK),
DMA_TO_DEVICE);
@@ -2306,7 +2318,9 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
(uf_info->bd_mem_part == MEM_PART_MURAM))) {
- ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: Bad memory partition value.",
+ __FUNCTION__);
return -EINVAL;
}
@@ -2315,9 +2329,10 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) ||
(ug_info->bdRingLenRx[i] %
UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) {
- ugeth_err
- ("%s: Rx BD ring length must be multiple of 4,"
- " no smaller than 8.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err
+ ("%s: Rx BD ring length must be multiple of 4, no smaller than 8.",
+ __FUNCTION__);
return -EINVAL;
}
}
@@ -2325,9 +2340,10 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
/* Tx BD lengths */
for (i = 0; i < ug_info->numQueuesTx; i++) {
if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) {
- ugeth_err
- ("%s: Tx BD ring length must be no smaller than 2.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err
+ ("%s: Tx BD ring length must be no smaller than 2.",
+ __FUNCTION__);
return -EINVAL;
}
}
@@ -2335,31 +2351,35 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
/* mrblr */
if ((uf_info->max_rx_buf_length == 0) ||
(uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) {
- ugeth_err
- ("%s: max_rx_buf_length must be non-zero multiple of 128.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err
+ ("%s: max_rx_buf_length must be non-zero multiple of 128.",
+ __FUNCTION__);
return -EINVAL;
}
/* num Tx queues */
if (ug_info->numQueuesTx > NUM_TX_QUEUES) {
- ugeth_err("%s: number of tx queues too large.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: number of tx queues too large.", __FUNCTION__);
return -EINVAL;
}
/* num Rx queues */
if (ug_info->numQueuesRx > NUM_RX_QUEUES) {
- ugeth_err("%s: number of rx queues too large.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: number of rx queues too large.", __FUNCTION__);
return -EINVAL;
}
/* l2qt */
for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) {
if (ug_info->l2qt[i] >= ug_info->numQueuesRx) {
- ugeth_err
- ("%s: VLAN priority table entry must not be"
- " larger than number of Rx queues.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err
+ ("%s: VLAN priority table entry must not be"
+ " larger than number of Rx queues.",
+ __FUNCTION__);
return -EINVAL;
}
}
@@ -2367,26 +2387,29 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
/* l3qt */
for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) {
if (ug_info->l3qt[i] >= ug_info->numQueuesRx) {
- ugeth_err
- ("%s: IP priority table entry must not be"
- " larger than number of Rx queues.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err
+ ("%s: IP priority table entry must not be"
+ " larger than number of Rx queues.",
+ __FUNCTION__);
return -EINVAL;
}
}
if (ug_info->cam && !ug_info->ecamptr) {
- ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
+ __FUNCTION__);
return -EINVAL;
}
if ((ug_info->numStationAddresses !=
UCC_GETH_NUM_OF_STATION_ADDRESSES_1)
&& ug_info->rxExtendedFiltering) {
- ugeth_err("%s: Number of station addresses greater than 1 "
- "not allowed in extended parsing mode.",
- __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: Number of station addresses greater than 1 "
+ "not allowed in extended parsing mode.",
+ __FUNCTION__);
return -EINVAL;
}
@@ -2399,7 +2422,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
/* Initialize the general fast UCC block. */
if (ucc_fast_init(uf_info, &ugeth->uccf)) {
- ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2452,7 +2476,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
numThreadsRxNumerical = 8;
break;
default:
- ugeth_err("%s: Bad number of Rx threads value.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Bad number of Rx threads value.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -EINVAL;
break;
@@ -2475,7 +2501,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
numThreadsTxNumerical = 8;
break;
default:
- ugeth_err("%s: Bad number of Tx threads value.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Bad number of Tx threads value.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -EINVAL;
break;
@@ -2507,7 +2535,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* For more details see the hardware spec. */
init_flow_control_params(ug_info->aufc,
ug_info->receiveFlowControl,
- 1,
+ ug_info->transmitFlowControl,
ug_info->pausePeriod,
ug_info->extensionField,
&uf_regs->upsmr,
@@ -2527,8 +2555,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
ug_info->backToBackInterFrameGap,
&ug_regs->ipgifg);
if (ret_val != 0) {
- ugeth_err("%s: IPGIFG initialization parameter too large.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: IPGIFG initialization parameter too large.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return ret_val;
}
@@ -2544,7 +2573,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
ug_info->collisionWindow,
&ug_regs->hafdup);
if (ret_val != 0) {
- ugeth_err("%s: Half Duplex initialization parameter too large.",
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Half Duplex initialization parameter too large.",
__FUNCTION__);
ucc_geth_memclean(ugeth);
return ret_val;
@@ -2597,9 +2627,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
tx_bd_ring_offset[j]);
}
if (!ugeth->p_tx_bd_ring[j]) {
- ugeth_err
- ("%s: Can not allocate memory for Tx bd rings.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate memory for Tx bd rings.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2632,9 +2663,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
rx_bd_ring_offset[j]);
}
if (!ugeth->p_rx_bd_ring[j]) {
- ugeth_err
- ("%s: Can not allocate memory for Rx bd rings.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate memory for Rx bd rings.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2648,8 +2680,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
GFP_KERNEL);
if (ugeth->tx_skbuff[j] == NULL) {
- ugeth_err("%s: Could not allocate tx_skbuff",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Could not allocate tx_skbuff",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2679,8 +2712,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
GFP_KERNEL);
if (ugeth->rx_skbuff[j] == NULL) {
- ugeth_err("%s: Could not allocate rx_skbuff",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Could not allocate rx_skbuff",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2711,9 +2745,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram),
UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2733,9 +2768,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
32 * (numThreadsTxNumerical == 1),
UCC_GETH_THREAD_DATA_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2761,9 +2797,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
sizeof(struct ucc_geth_send_queue_qd),
UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2804,9 +2841,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
qe_muram_alloc(sizeof(struct ucc_geth_scheduler),
UCC_GETH_SCHEDULER_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->scheduler_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_scheduler.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_scheduler.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2852,9 +2890,11 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
(struct ucc_geth_tx_firmware_statistics_pram),
UCC_GETH_TX_STATISTICS_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->tx_fw_statistics_pram_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_tx_fw_statistics_pram.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_tx_fw_statistics_pram.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2879,7 +2919,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
test = in_be16(&ugeth->p_tx_glbl_pram->temoder);
/* Function code register value to be used later */
- function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL;
+ function_code = UCC_BMR_BO_BE | UCC_BMR_GBL;
/* Required for QE */
/* function code register */
@@ -2891,9 +2931,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram),
UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2912,9 +2953,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
sizeof(struct ucc_geth_thread_data_rx),
UCC_GETH_THREAD_DATA_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2935,9 +2977,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
(struct ucc_geth_rx_firmware_statistics_pram),
UCC_GETH_RX_STATISTICS_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_rx_fw_statistics_pram.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_rx_fw_statistics_pram.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -2957,9 +3000,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+ 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_rx_irq_coalescing_tbl.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_rx_irq_coalescing_tbl.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -3025,9 +3069,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
sizeof(struct ucc_geth_rx_prefetched_bds)),
UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_bd_qs_tbl_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -3102,8 +3147,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* initialize extended filtering */
if (ug_info->rxExtendedFiltering) {
if (!ug_info->extendedFilteringChainPointer) {
- ugeth_err("%s: Null Extended Filtering Chain Pointer.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Null Extended Filtering Chain Pointer.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -EINVAL;
}
@@ -3114,9 +3160,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram),
UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_exf_glbl_param.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_exf_glbl_param.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -3161,9 +3208,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
*/
if (!(ugeth->p_init_enet_param_shadow =
kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
- ugeth_err
- ("%s: Can not allocate memory for"
- " p_UccInitEnetParamShadows.", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate memory for"
+ " p_UccInitEnetParamShadows.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -3196,8 +3244,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
&& (ug_info->largestexternallookupkeysize !=
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
- ugeth_err("%s: Invalid largest External Lookup Key Size.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Invalid largest External Lookup Key Size.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -EINVAL;
}
@@ -3222,8 +3271,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Rx needs one extra for terminator */
, size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT,
ug_info->riscRx, 1)) != 0) {
- ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return ret_val;
}
@@ -3237,8 +3287,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
sizeof(struct ucc_geth_thread_tx_pram),
UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
ug_info->riscTx, 0)) != 0) {
- ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return ret_val;
}
@@ -3246,8 +3297,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Load Rx bds with buffers */
for (i = 0; i < ug_info->numQueuesRx; i++) {
if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) {
- ugeth_err("%s: Can not fill Rx bds with buffers.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Can not fill Rx bds with buffers.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return ret_val;
}
@@ -3256,9 +3308,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Allocate InitEnet command parameter structure */
init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4);
if (IS_ERR_VALUE(init_enet_pram_offset)) {
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
- __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
+ __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
@@ -3297,14 +3350,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return 0;
}
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- return &(ugeth->stats);
-}
-
/* ucc_geth_timeout gets called when a packet has not been
* transmitted after a set amount of time.
* For now, assume that clearing out all the structures, and
@@ -3315,7 +3360,7 @@ static void ucc_geth_timeout(struct net_device *dev)
ugeth_vdbg("%s: IN", __FUNCTION__);
- ugeth->stats.tx_errors++;
+ dev->stats.tx_errors++;
ugeth_dump_regs(ugeth);
@@ -3343,7 +3388,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&ugeth->lock);
- ugeth->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Start from the next BD that should be filled */
bd = ugeth->txBd[txQ];
@@ -3428,15 +3473,16 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
if (!skb ||
(!(bd_status & (R_F | R_L))) ||
(bd_status & R_ERRORS_FATAL)) {
- ugeth_vdbg("%s, %d: ERROR!!! skb - 0x%08x",
- __FUNCTION__, __LINE__, (u32) skb);
+ if (netif_msg_rx_err(ugeth))
+ ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
+ __FUNCTION__, __LINE__, (u32) skb);
if (skb)
dev_kfree_skb_any(skb);
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
- ugeth->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
- ugeth->stats.rx_packets++;
+ dev->stats.rx_packets++;
howmany++;
/* Prep the skb for the packet */
@@ -3445,7 +3491,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, ugeth->dev);
- ugeth->stats.rx_bytes += length;
+ dev->stats.rx_bytes += length;
/* Send the packet up the stack */
#ifdef CONFIG_UGETH_NAPI
netif_receive_skb(skb);
@@ -3458,8 +3504,9 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
skb = get_new_skb(ugeth, bd);
if (!skb) {
- ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
- ugeth->stats.rx_dropped++;
+ if (netif_msg_rx_err(ugeth))
+ ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
+ dev->stats.rx_dropped++;
break;
}
@@ -3501,7 +3548,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
break;
- ugeth->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Free the sk buffer associated with this TxBD */
dev_kfree_skb_irq(ugeth->
@@ -3527,41 +3574,31 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
}
#ifdef CONFIG_UGETH_NAPI
-static int ucc_geth_poll(struct net_device *dev, int *budget)
+static int ucc_geth_poll(struct napi_struct *napi, int budget)
{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi);
+ struct net_device *dev = ugeth->dev;
struct ucc_geth_info *ug_info;
- struct ucc_fast_private *uccf;
- int howmany;
- u8 i;
- int rx_work_limit;
- register u32 uccm;
+ int howmany, i;
ug_info = ugeth->ug_info;
- rx_work_limit = *budget;
- if (rx_work_limit > dev->quota)
- rx_work_limit = dev->quota;
-
howmany = 0;
+ for (i = 0; i < ug_info->numQueuesRx; i++)
+ howmany += ucc_geth_rx(ugeth, i, budget - howmany);
- for (i = 0; i < ug_info->numQueuesRx; i++) {
- howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
- }
-
- dev->quota -= howmany;
- rx_work_limit -= howmany;
- *budget -= howmany;
+ if (howmany < budget) {
+ struct ucc_fast_private *uccf;
+ u32 uccm;
- if (rx_work_limit > 0) {
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
uccf = ugeth->uccf;
uccm = in_be32(uccf->p_uccm);
uccm |= UCCE_RX_EVENTS;
out_be32(uccf->p_uccm, uccm);
}
- return (rx_work_limit > 0) ? 0 : 1;
+ return howmany;
}
#endif /* CONFIG_UGETH_NAPI */
@@ -3596,10 +3633,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
/* check for receive events that require processing */
if (ucce & UCCE_RX_EVENTS) {
#ifdef CONFIG_UGETH_NAPI
- if (netif_rx_schedule_prep(dev)) {
- uccm &= ~UCCE_RX_EVENTS;
+ if (netif_rx_schedule_prep(dev, &ugeth->napi)) {
+ uccm &= ~UCCE_RX_EVENTS;
out_be32(uccf->p_uccm, uccm);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &ugeth->napi);
}
#else
rx_mask = UCCE_RXBF_SINGLE_MASK;
@@ -3628,10 +3665,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
/* Errors and other events */
if (ucce & UCCE_OTHER) {
if (ucce & UCCE_BSY) {
- ugeth->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
if (ucce & UCCE_TXE) {
- ugeth->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
}
@@ -3649,29 +3686,36 @@ static int ucc_geth_open(struct net_device *dev)
/* Test station address */
if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
- ugeth_err("%s: Multicast address used for station address"
- " - is this what you wanted?", __FUNCTION__);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Multicast address used for station address"
+ " - is this what you wanted?", __FUNCTION__);
return -EINVAL;
}
err = ucc_struct_init(ugeth);
if (err) {
- ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
return err;
}
+#ifdef CONFIG_UGETH_NAPI
+ napi_enable(&ugeth->napi);
+#endif
err = ucc_geth_startup(ugeth);
if (err) {
- ugeth_err("%s: Cannot configure net device, aborting.",
- dev->name);
- return err;
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot configure net device, aborting.",
+ dev->name);
+ goto out_err;
}
err = adjust_enet_interface(ugeth);
if (err) {
- ugeth_err("%s: Cannot configure net device, aborting.",
- dev->name);
- return err;
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot configure net device, aborting.",
+ dev->name);
+ goto out_err;
}
/* Set MACSTNADDR1, MACSTNADDR2 */
@@ -3687,8 +3731,9 @@ static int ucc_geth_open(struct net_device *dev)
err = init_phy(dev);
if (err) {
- ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
- return err;
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
+ goto out_err;
}
phy_start(ugeth->phydev);
@@ -3697,22 +3742,30 @@ static int ucc_geth_open(struct net_device *dev)
request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
"UCC Geth", dev);
if (err) {
- ugeth_err("%s: Cannot get IRQ for net device, aborting.",
- dev->name);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot get IRQ for net device, aborting.",
+ dev->name);
ucc_geth_stop(ugeth);
- return err;
+ goto out_err;
}
err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
if (err) {
- ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
ucc_geth_stop(ugeth);
- return err;
+ goto out_err;
}
netif_start_queue(dev);
return err;
+
+out_err:
+#ifdef CONFIG_UGETH_NAPI
+ napi_disable(&ugeth->napi);
+#endif
+ return err;
}
/* Stops the kernel queue, and halts the controller */
@@ -3722,6 +3775,10 @@ static int ucc_geth_close(struct net_device *dev)
ugeth_vdbg("%s: IN", __FUNCTION__);
+#ifdef CONFIG_UGETH_NAPI
+ napi_disable(&ugeth->napi);
+#endif
+
ucc_geth_stop(ugeth);
phy_disconnect(ugeth->phydev);
@@ -3732,8 +3789,6 @@ static int ucc_geth_close(struct net_device *dev)
return 0;
}
-const struct ethtool_ops ucc_geth_ethtool_ops = { };
-
static phy_interface_t to_phy_interface(const char *phy_connection_type)
{
if (strcasecmp(phy_connection_type, "mii") == 0)
@@ -3790,6 +3845,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
return -ENODEV;
ug_info = &ugeth_info[ucc_num];
+ if (ug_info == NULL) {
+ if (netif_msg_probe(&debug))
+ ugeth_err("%s: [%d] Missing additional data!",
+ __FUNCTION__, ucc_num);
+ return -ENODEV;
+ }
+
ug_info->uf_info.ucc_num = ucc_num;
prop = of_get_property(np, "rx-clock", NULL);
@@ -3868,15 +3930,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ug_info->mdio_bus = res.start;
- printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
- ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
- ug_info->uf_info.irq);
-
- if (ug_info == NULL) {
- ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__,
- ucc_num);
- return -ENODEV;
- }
+ if (netif_msg_probe(&debug))
+ printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
+ ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
+ ug_info->uf_info.irq);
/* Create an ethernet device instance */
dev = alloc_etherdev(sizeof(*ugeth));
@@ -3892,33 +3949,31 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
/* Set the dev->base_addr to the gfar reg region */
dev->base_addr = (unsigned long)(ug_info->uf_info.regs);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, device);
/* Fill in the dev structure */
+ uec_set_ethtool_ops(dev);
dev->open = ucc_geth_open;
dev->hard_start_xmit = ucc_geth_start_xmit;
dev->tx_timeout = ucc_geth_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_UGETH_NAPI
- dev->poll = ucc_geth_poll;
- dev->weight = UCC_GETH_DEV_WEIGHT;
+ netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
#endif /* CONFIG_UGETH_NAPI */
dev->stop = ucc_geth_close;
- dev->get_stats = ucc_geth_get_stats;
// dev->change_mtu = ucc_geth_change_mtu;
dev->mtu = 1500;
dev->set_multicast_list = ucc_geth_set_multi;
- dev->ethtool_ops = &ucc_geth_ethtool_ops;
- ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+ ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
ugeth->phy_interface = phy_interface;
ugeth->max_speed = max_speed;
err = register_netdev(dev);
if (err) {
- ugeth_err("%s: Cannot register net device, aborting.",
- dev->name);
+ if (netif_msg_probe(ugeth))
+ ugeth_err("%s: Cannot register net device, aborting.",
+ dev->name);
free_netdev(dev);
return err;
}
@@ -3972,7 +4027,8 @@ static int __init ucc_geth_init(void)
if (ret)
return ret;
- printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
+ if (netif_msg_drv(&debug))
+ printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
for (i = 0; i < 8; i++)
memcpy(&(ugeth_info[i]), &ugeth_primary_info,
sizeof(ugeth_primary_info));
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index a29e1c3ca4b7..4fb95b3af948 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -30,6 +30,10 @@
#include "ucc_geth_mii.h"
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
+#define DRV_NAME "ucc_geth"
+#define DRV_VERSION "1.1"
+
#define NUM_TX_QUEUES 8
#define NUM_RX_QUEUES 8
#define NUM_BDS_IN_PREFETCHED_BDS 4
@@ -40,6 +44,7 @@
struct ucc_geth {
struct ucc_fast uccf;
+ u8 res0[0x100 - sizeof(struct ucc_fast)];
u32 maccfg1; /* mac configuration reg. 1 */
u32 maccfg2; /* mac configuration reg. 2 */
@@ -896,6 +901,7 @@ struct ucc_geth_hardware_statistics {
#define UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX 8
#define UCC_GETH_RX_BD_RING_SIZE_MIN 8
#define UCC_GETH_TX_BD_RING_SIZE_MIN 2
+#define UCC_GETH_BD_RING_SIZE_MAX 0xffff
#define UCC_GETH_SIZE_OF_BD QE_SIZEOF_BD
@@ -1135,6 +1141,7 @@ struct ucc_geth_info {
int bro;
int ecm;
int receiveFlowControl;
+ int transmitFlowControl;
u8 maxGroupAddrInHash;
u8 maxIndAddrInHash;
u8 prel;
@@ -1178,7 +1185,7 @@ struct ucc_geth_private {
struct ucc_geth_info *ug_info;
struct ucc_fast_private *uccf;
struct net_device *dev;
- struct net_device_stats stats; /* linux network statistics */
+ struct napi_struct napi;
struct ucc_geth *ug_regs;
struct ucc_geth_init_pram *p_init_enet_param_shadow;
struct ucc_geth_exf_global_pram *p_exf_glbl_param;
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
new file mode 100644
index 000000000000..9a9622c13e2b
--- /dev/null
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Description: QE UCC Gigabit Ethernet Ethtool API Set
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ *
+ * Limitation:
+ * Can only get/set setttings of the first queue.
+ * Need to re-open the interface manually after changing some paramters.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+
+#include "ucc_geth.h"
+#include "ucc_geth_mii.h"
+
+static char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
+ "tx-64-frames",
+ "tx-65-127-frames",
+ "tx-128-255-frames",
+ "rx-64-frames",
+ "rx-65-127-frames",
+ "rx-128-255-frames",
+ "tx-bytes-ok",
+ "tx-pause-frames",
+ "tx-multicast-frames",
+ "tx-broadcast-frames",
+ "rx-frames",
+ "rx-bytes-ok",
+ "rx-bytes-all",
+ "rx-multicast-frames",
+ "rx-broadcast-frames",
+ "stats-counter-carry",
+ "stats-counter-mask",
+ "rx-dropped-frames",
+};
+
+static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
+ "tx-single-collision",
+ "tx-multiple-collision",
+ "tx-late-collsion",
+ "tx-aborted-frames",
+ "tx-lost-frames",
+ "tx-carrier-sense-errors",
+ "tx-frames-ok",
+ "tx-excessive-differ-frames",
+ "tx-256-511-frames",
+ "tx-1024-1518-frames",
+ "tx-jumbo-frames",
+};
+
+static char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
+ "rx-crc-errors",
+ "rx-alignment-errors",
+ "rx-in-range-length-errors",
+ "rx-out-of-range-length-errors",
+ "rx-too-long-frames",
+ "rx-runt",
+ "rx-very-long-event",
+ "rx-symbol-errors",
+ "rx-busy-drop-frames",
+ "reserved",
+ "reserved",
+ "rx-mismatch-drop-frames",
+ "rx-small-than-64",
+ "rx-256-511-frames",
+ "rx-512-1023-frames",
+ "rx-1024-1518-frames",
+ "rx-jumbo-frames",
+ "rx-mac-error-loss",
+ "rx-pause-frames",
+ "reserved",
+ "rx-vlan-removed",
+ "rx-vlan-replaced",
+ "rx-vlan-inserted",
+ "rx-ip-checksum-errors",
+};
+
+#define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
+#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)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ struct phy_device *phydev = ugeth->phydev;
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+
+ if (!phydev)
+ return -ENODEV;
+
+ ecmd->maxtxpkt = 1;
+ ecmd->maxrxpkt = ug_info->interruptcoalescingmaxvalue[0];
+
+ return phy_ethtool_gset(phydev, ecmd);
+}
+
+static int
+uec_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ struct phy_device *phydev = ugeth->phydev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, ecmd);
+}
+
+static void
+uec_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+
+ pause->autoneg = ugeth->phydev->autoneg;
+
+ if (ugeth->ug_info->receiveFlowControl)
+ pause->rx_pause = 1;
+ if (ugeth->ug_info->transmitFlowControl)
+ pause->tx_pause = 1;
+}
+
+static int
+uec_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ int ret = 0;
+
+ ugeth->ug_info->receiveFlowControl = pause->rx_pause;
+ ugeth->ug_info->transmitFlowControl = pause->tx_pause;
+
+ if (ugeth->phydev->autoneg) {
+ if (netif_running(netdev)) {
+ /* FIXME: automatically restart */
+ printk(KERN_INFO
+ "Please re-open the interface.\n");
+ }
+ } else {
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+
+ ret = init_flow_control_params(ug_info->aufc,
+ ug_info->receiveFlowControl,
+ ug_info->transmitFlowControl,
+ ug_info->pausePeriod,
+ ug_info->extensionField,
+ &ugeth->uccf->uf_regs->upsmr,
+ &ugeth->ug_regs->uempr,
+ &ugeth->ug_regs->maccfg1);
+ }
+
+ return ret;
+}
+
+static uint32_t
+uec_get_msglevel(struct net_device *netdev)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ return ugeth->msg_enable;
+}
+
+static void
+uec_set_msglevel(struct net_device *netdev, uint32_t data)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ ugeth->msg_enable = data;
+}
+
+static int
+uec_get_regs_len(struct net_device *netdev)
+{
+ return sizeof(struct ucc_geth);
+}
+
+static void
+uec_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ int i;
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
+ u32 *buff = p;
+
+ for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
+ buff[i] = in_be32(&ug_regs[i]);
+}
+
+static void
+uec_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+ int queue = 0;
+
+ ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+ ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+ ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+ ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+
+ ring->rx_pending = ug_info->bdRingLenRx[queue];
+ ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
+ ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
+ ring->tx_pending = ug_info->bdRingLenTx[queue];
+}
+
+static int
+uec_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+ int queue = 0, ret = 0;
+
+ if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
+ printk("%s: RxBD ring size must be no smaller than %d.\n",
+ netdev->name, UCC_GETH_RX_BD_RING_SIZE_MIN);
+ return -EINVAL;
+ }
+ if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
+ printk("%s: RxBD ring size must be multiple of %d.\n",
+ netdev->name, UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
+ return -EINVAL;
+ }
+ if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
+ printk("%s: TxBD ring size must be no smaller than %d.\n",
+ netdev->name, UCC_GETH_TX_BD_RING_SIZE_MIN);
+ return -EINVAL;
+ }
+
+ ug_info->bdRingLenRx[queue] = ring->rx_pending;
+ ug_info->bdRingLenTx[queue] = ring->tx_pending;
+
+ if (netif_running(netdev)) {
+ /* FIXME: restart automatically */
+ printk(KERN_INFO
+ "Please re-open the interface.\n");
+ }
+
+ return ret;
+}
+
+static int uec_get_sset_count(struct net_device *netdev, int sset)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ u32 stats_mode = ugeth->ug_info->statisticsMode;
+ int len = 0;
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
+ len += UEC_HW_STATS_LEN;
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
+ len += UEC_TX_FW_STATS_LEN;
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
+ len += UEC_RX_FW_STATS_LEN;
+
+ return len;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ u32 stats_mode = ugeth->ug_info->statisticsMode;
+
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
+ memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
+ ETH_GSTRING_LEN);
+ buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
+ }
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+ memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
+ ETH_GSTRING_LEN);
+ buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
+ }
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
+ memcpy(buf, tx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
+ ETH_GSTRING_LEN);
+}
+
+static void uec_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, uint64_t *data)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+ u32 stats_mode = ugeth->ug_info->statisticsMode;
+ u32 __iomem *base;
+ int i, j = 0;
+
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
+ base = (u32 __iomem *)&ugeth->ug_regs->tx64;
+ for (i = 0; i < UEC_HW_STATS_LEN; i++)
+ data[j++] = (u64)in_be32(&base[i]);
+ }
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+ base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
+ for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
+ data[j++] = (u64)in_be32(&base[i]);
+ }
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
+ base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
+ for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
+ data[j++] = (u64)in_be32(&base[i]);
+ }
+}
+
+static int uec_nway_reset(struct net_device *netdev)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(netdev);
+
+ return phy_start_aneg(ugeth->phydev);
+}
+
+/* Report driver information */
+static void
+uec_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strncpy(drvinfo->driver, DRV_NAME, 32);
+ strncpy(drvinfo->version, DRV_VERSION, 32);
+ strncpy(drvinfo->fw_version, "N/A", 32);
+ strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
+ drvinfo->eedump_len = 0;
+ drvinfo->regdump_len = uec_get_regs_len(netdev);
+}
+
+static const struct ethtool_ops uec_ethtool_ops = {
+ .get_settings = uec_get_settings,
+ .set_settings = uec_set_settings,
+ .get_drvinfo = uec_get_drvinfo,
+ .get_regs_len = uec_get_regs_len,
+ .get_regs = uec_get_regs,
+ .get_msglevel = uec_get_msglevel,
+ .set_msglevel = uec_set_msglevel,
+ .nway_reset = uec_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = uec_get_ringparam,
+ .set_ringparam = uec_set_ringparam,
+ .get_pauseparam = uec_get_pauseparam,
+ .set_pauseparam = uec_set_pauseparam,
+ .set_sg = ethtool_op_set_sg,
+ .get_sset_count = uec_get_sset_count,
+ .get_strings = uec_get_strings,
+ .get_ethtool_stats = uec_get_ethtool_stats,
+};
+
+void uec_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &uec_ethtool_ops);
+}
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index 7bcb82f50cf7..df884f0ad8e5 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -32,7 +32,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <asm/ocp.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>
@@ -54,8 +53,8 @@
#define vdbg(format, arg...) do {} while(0)
#endif
-#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
-#define DRV_NAME "fsl-uec_mdio"
+#define MII_DRV_DESC "QE UCC Ethernet Controller MII Bus"
+#define MII_DRV_NAME "fsl-uec_mdio"
/* Write value to the PHY for this device to the register at regnum, */
/* waiting until the write is done before it returns. All PHY */
@@ -261,7 +260,7 @@ static struct of_device_id uec_mdio_match[] = {
};
static struct of_platform_driver uec_mdio_driver = {
- .name = DRV_NAME,
+ .name = MII_DRV_NAME,
.probe = uec_mdio_probe,
.remove = uec_mdio_remove,
.match_table = uec_mdio_match,
@@ -272,7 +271,8 @@ int __init uec_mdio_init(void)
return of_register_platform_driver(&uec_mdio_driver);
}
-void __exit uec_mdio_exit(void)
+/* called from __init ucc_geth_init, therefore can not be __exit */
+void uec_mdio_exit(void)
{
of_unregister_platform_driver(&uec_mdio_driver);
}
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6d95cacd5284..61daa096de66 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1474,6 +1474,7 @@ static struct usb_driver asix_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
+ .supports_autosuspend = 1,
};
static int __init asix_init(void)
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 16c7a0e87850..a2de32fabc17 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -405,7 +405,7 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->ethtool_ops = &dm9601_ethtool_ops;
dev->net->hard_header_len += DM_TX_OVERHEAD;
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
- dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
+ dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD;
dev->mii.dev = dev->net;
dev->mii.mdio_read = dm9601_mdio_read;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 524dc5f5e46d..58a53a641754 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -1152,8 +1152,6 @@ err_fw:
INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
- SET_MODULE_OWNER(netdev);
-
usb_set_intfdata(intf, kaweth);
#if 0
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index a05fd97e5bc2..d1ed68a11e70 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -768,11 +768,13 @@ done:
static void write_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
- struct net_device *net = pegasus->net;
+ struct net_device *net;
if (!pegasus)
return;
+ net = pegasus->net;
+
if (!netif_device_present(net) || !netif_running(net))
return;
@@ -1295,6 +1297,7 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus_t *pegasus;
int dev_index = id - pegasus_ids;
int res = -ENOMEM;
+ DECLARE_MAC_BUF(mac);
usb_get_dev(dev);
net = alloc_etherdev(sizeof(struct pegasus));
@@ -1304,7 +1307,6 @@ static int pegasus_probe(struct usb_interface *intf,
}
pegasus = netdev_priv(net);
- memset(pegasus, 0, sizeof (struct pegasus));
pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait);
@@ -1320,7 +1322,6 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->intf = intf;
pegasus->usb = dev;
pegasus->net = net;
- SET_MODULE_OWNER(net);
net->open = pegasus_open;
net->stop = pegasus_close;
net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
@@ -1367,12 +1368,10 @@ static int pegasus_probe(struct usb_interface *intf,
queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
CARRIER_CHECK_DELAY);
- dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n",
- net->name,
- usb_dev_id[dev_index].name,
- net->dev_addr [0], net->dev_addr [1],
- net->dev_addr [2], net->dev_addr [3],
- net->dev_addr [4], net->dev_addr [5]);
+ dev_info(&intf->dev, "%s, %s, %s\n",
+ net->name,
+ usb_dev_id[dev_index].name,
+ print_mac(mac, net->dev_addr));
return 0;
out3:
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fa598f0340cf..33cbc306226c 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -905,7 +905,6 @@ static int rtl8150_probe(struct usb_interface *intf,
}
dev = netdev_priv(netdev);
- memset(dev, 0, sizeof(rtl8150_t));
dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
if (!dev->intr_buff) {
@@ -918,7 +917,6 @@ static int rtl8150_probe(struct usb_interface *intf,
dev->udev = udev;
dev->netdev = netdev;
- SET_MODULE_OWNER(netdev);
netdev->open = rtl8150_open;
netdev->stop = rtl8150_close;
netdev->do_ioctl = rtl8150_ioctl;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 37bf4f2c0a44..acd5f1c0e63a 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -590,6 +590,7 @@ static int usbnet_stop (struct net_device *net)
dev->flags = 0;
del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh);
+ usb_autopm_put_interface(dev->intf);
return 0;
}
@@ -603,9 +604,19 @@ static int usbnet_stop (struct net_device *net)
static int usbnet_open (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
- int retval = 0;
+ int retval;
struct driver_info *info = dev->driver_info;
+ if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
+ if (netif_msg_ifup (dev))
+ devinfo (dev,
+ "resumption fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ goto done_nopm;
+ }
+
// put into "known safe" state
if (info->reset && (retval = info->reset (dev)) < 0) {
if (netif_msg_ifup (dev))
@@ -659,7 +670,10 @@ static int usbnet_open (struct net_device *net)
// delay posting reads until we're fully open
tasklet_schedule (&dev->bh);
+ return retval;
done:
+ usb_autopm_put_interface(dev->intf);
+done_nopm:
return retval;
}
@@ -1120,6 +1134,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct usb_device *xdev;
int status;
const char *name;
+ DECLARE_MAC_BUF(mac);
name = udev->dev.driver->name;
info = (struct driver_info *) prod->driver_info;
@@ -1143,6 +1158,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev = netdev_priv(net);
dev->udev = xdev;
+ dev->intf = udev;
dev->driver_info = info;
dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
@@ -1158,7 +1174,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
init_timer (&dev->delay);
mutex_init (&dev->phy_mutex);
- SET_MODULE_OWNER (net);
dev->net = net;
strcpy (net->name, "usb%d");
memcpy (net->dev_addr, node_id, sizeof node_id);
@@ -1227,14 +1242,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
if (status)
goto out3;
if (netif_msg_probe (dev))
- devinfo (dev, "register '%s' at usb-%s-%s, %s, "
- "%02x:%02x:%02x:%02x:%02x:%02x",
+ devinfo (dev, "register '%s' at usb-%s-%s, %s, %s",
udev->dev.driver->name,
xdev->bus->bus_name, xdev->devpath,
dev->driver_info->description,
- net->dev_addr [0], net->dev_addr [1],
- net->dev_addr [2], net->dev_addr [3],
- net->dev_addr [4], net->dev_addr [5]);
+ print_mac(mac, net->dev_addr));
// ok, it's ready to go.
usb_set_intfdata (udev, dev);
@@ -1267,12 +1279,18 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
struct usbnet *dev = usb_get_intfdata(intf);
if (!dev->suspend_count++) {
- /* accelerate emptying of the rx and queues, to avoid
+ /*
+ * accelerate emptying of the rx and queues, to avoid
* having everything error out.
*/
netif_device_detach (dev->net);
(void) unlink_urbs (dev, &dev->rxq);
(void) unlink_urbs (dev, &dev->txq);
+ /*
+ * reattach so runtime management can use and
+ * wake the device
+ */
+ netif_device_attach (dev->net);
}
return 0;
}
@@ -1282,10 +1300,9 @@ int usbnet_resume (struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
- if (!--dev->suspend_count) {
- netif_device_attach (dev->net);
+ if (!--dev->suspend_count)
tasklet_schedule (&dev->bh);
- }
+
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_resume);
diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
index a6c5820767de..1fae4347e831 100644
--- a/drivers/net/usb/usbnet.h
+++ b/drivers/net/usb/usbnet.h
@@ -28,6 +28,7 @@
struct usbnet {
/* housekeeping */
struct usb_device *udev;
+ struct usb_interface *intf;
struct driver_info *driver_info;
const char *driver_name;
wait_queue_head_t *wait;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
new file mode 100644
index 000000000000..fdd1e034569d
--- /dev/null
+++ b/drivers/net/veth.c
@@ -0,0 +1,482 @@
+/*
+ * drivers/net/veth.c
+ *
+ * Copyright (C) 2007 OpenVZ http://openvz.org, SWsoft Inc
+ *
+ * Author: Pavel Emelianov <xemul@openvz.org>
+ * Ethtool interface from: Eric W. Biederman <ebiederm@xmission.com>
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+
+#include <net/dst.h>
+#include <net/xfrm.h>
+#include <net/veth.h>
+
+#define DRV_NAME "veth"
+#define DRV_VERSION "1.0"
+
+struct veth_net_stats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long tx_dropped;
+};
+
+struct veth_priv {
+ struct net_device *peer;
+ struct net_device *dev;
+ struct list_head list;
+ struct veth_net_stats *stats;
+ unsigned ip_summed;
+};
+
+static LIST_HEAD(veth_list);
+
+/*
+ * ethtool interface
+ */
+
+static struct {
+ const char string[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "peer_ifindex" },
+};
+
+static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = 0;
+ cmd->advertising = 0;
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+ cmd->port = PORT_TP;
+ cmd->phy_address = 0;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+}
+
+static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ switch(stringset) {
+ case ETH_SS_STATS:
+ memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+ break;
+ }
+}
+
+static int veth_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ethtool_stats_keys);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void veth_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ data[0] = priv->peer->ifindex;
+}
+
+static u32 veth_get_rx_csum(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ return priv->ip_summed == CHECKSUM_UNNECESSARY;
+}
+
+static int veth_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
+ return 0;
+}
+
+static u32 veth_get_tx_csum(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_NO_CSUM) != 0;
+}
+
+static int veth_set_tx_csum(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= NETIF_F_NO_CSUM;
+ else
+ dev->features &= ~NETIF_F_NO_CSUM;
+ return 0;
+}
+
+static struct ethtool_ops veth_ethtool_ops = {
+ .get_settings = veth_get_settings,
+ .get_drvinfo = veth_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = veth_get_rx_csum,
+ .set_rx_csum = veth_set_rx_csum,
+ .get_tx_csum = veth_get_tx_csum,
+ .set_tx_csum = veth_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_strings = veth_get_strings,
+ .get_sset_count = veth_get_sset_count,
+ .get_ethtool_stats = veth_get_ethtool_stats,
+};
+
+/*
+ * xmit
+ */
+
+static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device *rcv = NULL;
+ struct veth_priv *priv, *rcv_priv;
+ struct veth_net_stats *stats;
+ int length, cpu;
+
+ skb_orphan(skb);
+
+ priv = netdev_priv(dev);
+ rcv = priv->peer;
+ rcv_priv = netdev_priv(rcv);
+
+ cpu = smp_processor_id();
+ stats = per_cpu_ptr(priv->stats, cpu);
+
+ if (!(rcv->flags & IFF_UP))
+ goto outf;
+
+ skb->pkt_type = PACKET_HOST;
+ skb->protocol = eth_type_trans(skb, rcv);
+ if (dev->features & NETIF_F_NO_CSUM)
+ skb->ip_summed = rcv_priv->ip_summed;
+
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ skb->mark = 0;
+ secpath_reset(skb);
+ nf_reset(skb);
+
+ length = skb->len;
+
+ stats->tx_bytes += length;
+ stats->tx_packets++;
+
+ stats = per_cpu_ptr(rcv_priv->stats, cpu);
+ stats->rx_bytes += length;
+ stats->rx_packets++;
+
+ netif_rx(skb);
+ return 0;
+
+outf:
+ kfree_skb(skb);
+ stats->tx_dropped++;
+ return 0;
+}
+
+/*
+ * general routines
+ */
+
+static struct net_device_stats *veth_get_stats(struct net_device *dev)
+{
+ struct veth_priv *priv;
+ struct net_device_stats *dev_stats;
+ int cpu;
+ struct veth_net_stats *stats;
+
+ priv = netdev_priv(dev);
+ dev_stats = &dev->stats;
+
+ dev_stats->rx_packets = 0;
+ dev_stats->tx_packets = 0;
+ dev_stats->rx_bytes = 0;
+ dev_stats->tx_bytes = 0;
+ dev_stats->tx_dropped = 0;
+
+ for_each_online_cpu(cpu) {
+ stats = per_cpu_ptr(priv->stats, cpu);
+
+ dev_stats->rx_packets += stats->rx_packets;
+ dev_stats->tx_packets += stats->tx_packets;
+ dev_stats->rx_bytes += stats->rx_bytes;
+ dev_stats->tx_bytes += stats->tx_bytes;
+ dev_stats->tx_dropped += stats->tx_dropped;
+ }
+
+ return dev_stats;
+}
+
+static int veth_open(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ if (priv->peer == NULL)
+ return -ENOTCONN;
+
+ if (priv->peer->flags & IFF_UP) {
+ netif_carrier_on(dev);
+ netif_carrier_on(priv->peer);
+ }
+ return 0;
+}
+
+static int veth_close(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ if (netif_carrier_ok(dev)) {
+ priv = netdev_priv(dev);
+ netif_carrier_off(dev);
+ netif_carrier_off(priv->peer);
+ }
+ return 0;
+}
+
+static int veth_dev_init(struct net_device *dev)
+{
+ struct veth_net_stats *stats;
+ struct veth_priv *priv;
+
+ stats = alloc_percpu(struct veth_net_stats);
+ if (stats == NULL)
+ return -ENOMEM;
+
+ priv = netdev_priv(dev);
+ priv->stats = stats;
+ return 0;
+}
+
+static void veth_dev_free(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ free_percpu(priv->stats);
+ free_netdev(dev);
+}
+
+static void veth_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->hard_start_xmit = veth_xmit;
+ dev->get_stats = veth_get_stats;
+ dev->open = veth_open;
+ dev->stop = veth_close;
+ dev->ethtool_ops = &veth_ethtool_ops;
+ dev->features |= NETIF_F_LLTX;
+ dev->init = veth_dev_init;
+ dev->destructor = veth_dev_free;
+}
+
+/*
+ * netlink interface
+ */
+
+static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+ return 0;
+}
+
+static struct rtnl_link_ops veth_link_ops;
+
+static int veth_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ int err;
+ struct net_device *peer;
+ struct veth_priv *priv;
+ char ifname[IFNAMSIZ];
+ struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+
+ /*
+ * create and register peer first
+ *
+ * struct ifinfomsg is at the head of VETH_INFO_PEER, but we
+ * skip it since no info from it is useful yet
+ */
+
+ if (data != NULL && data[VETH_INFO_PEER] != NULL) {
+ struct nlattr *nla_peer;
+
+ nla_peer = data[VETH_INFO_PEER];
+ err = nla_parse(peer_tb, IFLA_MAX,
+ nla_data(nla_peer) + sizeof(struct ifinfomsg),
+ nla_len(nla_peer) - sizeof(struct ifinfomsg),
+ ifla_policy);
+ if (err < 0)
+ return err;
+
+ err = veth_validate(peer_tb, NULL);
+ if (err < 0)
+ return err;
+
+ tbp = peer_tb;
+ } else
+ tbp = tb;
+
+ if (tbp[IFLA_IFNAME])
+ nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
+ else
+ snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
+
+ peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp);
+ if (IS_ERR(peer))
+ return PTR_ERR(peer);
+
+ if (tbp[IFLA_ADDRESS] == NULL)
+ random_ether_addr(peer->dev_addr);
+
+ err = register_netdevice(peer);
+ if (err < 0)
+ goto err_register_peer;
+
+ netif_carrier_off(peer);
+
+ /*
+ * register dev last
+ *
+ * note, that since we've registered new device the dev's name
+ * should be re-allocated
+ */
+
+ if (tb[IFLA_ADDRESS] == NULL)
+ random_ether_addr(dev->dev_addr);
+
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ);
+ else
+ snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
+
+ if (strchr(dev->name, '%')) {
+ err = dev_alloc_name(dev, dev->name);
+ if (err < 0)
+ goto err_alloc_name;
+ }
+
+ err = register_netdevice(dev);
+ if (err < 0)
+ goto err_register_dev;
+
+ netif_carrier_off(dev);
+
+ /*
+ * tie the deviced together
+ */
+
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->peer = peer;
+ list_add(&priv->list, &veth_list);
+
+ priv = netdev_priv(peer);
+ priv->dev = peer;
+ priv->peer = dev;
+ INIT_LIST_HEAD(&priv->list);
+ return 0;
+
+err_register_dev:
+ /* nothing to do */
+err_alloc_name:
+ unregister_netdevice(peer);
+ return err;
+
+err_register_peer:
+ free_netdev(peer);
+ return err;
+}
+
+static void veth_dellink(struct net_device *dev)
+{
+ struct veth_priv *priv;
+ struct net_device *peer;
+
+ priv = netdev_priv(dev);
+ peer = priv->peer;
+
+ if (!list_empty(&priv->list))
+ list_del(&priv->list);
+
+ priv = netdev_priv(peer);
+ if (!list_empty(&priv->list))
+ list_del(&priv->list);
+
+ unregister_netdevice(dev);
+ unregister_netdevice(peer);
+}
+
+static const struct nla_policy veth_policy[VETH_INFO_MAX + 1];
+
+static struct rtnl_link_ops veth_link_ops = {
+ .kind = DRV_NAME,
+ .priv_size = sizeof(struct veth_priv),
+ .setup = veth_setup,
+ .validate = veth_validate,
+ .newlink = veth_newlink,
+ .dellink = veth_dellink,
+ .policy = veth_policy,
+ .maxtype = VETH_INFO_MAX,
+};
+
+/*
+ * init/fini
+ */
+
+static __init int veth_init(void)
+{
+ return rtnl_link_register(&veth_link_ops);
+}
+
+static __exit void veth_exit(void)
+{
+ struct veth_priv *priv, *next;
+
+ rtnl_lock();
+ /*
+ * cannot trust __rtnl_link_unregister() to unregister all
+ * devices, as each ->dellink call will remove two devices
+ * from the list at once.
+ */
+ list_for_each_entry_safe(priv, next, &veth_list, list)
+ veth_dellink(priv->dev);
+
+ __rtnl_link_unregister(&veth_link_ops);
+ rtnl_unlock();
+}
+
+module_init(veth_init);
+module_exit(veth_exit);
+
+MODULE_DESCRIPTION("Virtual Ethernet Tunnel");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index f51c2c138f10..07263cd93f9c 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -42,7 +42,13 @@ static int max_interrupt_work = 20;
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1518 effectively disables this feature. */
+#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
+ || defined(CONFIG_SPARC) || defined(__ia64__) \
+ || defined(__sh__) || defined(__mips__)
+static int rx_copybreak = 1518;
+#else
static int rx_copybreak;
+#endif
/* Work-around for broken BIOSes: they are unable to get the chip back out of
power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */
@@ -329,16 +335,16 @@ enum wol_bits {
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
- s32 rx_status;
- u32 desc_length; /* Chain flag, Buffer/frame length */
- u32 addr;
- u32 next_desc;
+ __le32 rx_status;
+ __le32 desc_length; /* Chain flag, Buffer/frame length */
+ __le32 addr;
+ __le32 next_desc;
};
struct tx_desc {
- s32 tx_status;
- u32 desc_length; /* Chain flag, Tx Config, Frame length */
- u32 addr;
- u32 next_desc;
+ __le32 tx_status;
+ __le32 desc_length; /* Chain flag, Tx Config, Frame length */
+ __le32 addr;
+ __le32 next_desc;
};
/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
@@ -383,6 +389,8 @@ struct rhine_private {
struct pci_dev *pdev;
long pioaddr;
+ struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
spinlock_t lock;
@@ -576,28 +584,25 @@ static void rhine_poll(struct net_device *dev)
#endif
#ifdef CONFIG_VIA_RHINE_NAPI
-static int rhine_napipoll(struct net_device *dev, int *budget)
+static int rhine_napipoll(struct napi_struct *napi, int budget)
{
- struct rhine_private *rp = netdev_priv(dev);
+ struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
+ struct net_device *dev = rp->dev;
void __iomem *ioaddr = rp->base;
- int done, limit = min(dev->quota, *budget);
+ int work_done;
- done = rhine_rx(dev, limit);
- *budget -= done;
- dev->quota -= done;
+ work_done = rhine_rx(dev, budget);
- if (done < limit) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
IntrTxDone | IntrTxError | IntrTxUnderrun |
IntrPCIErr | IntrStatsMax | IntrLinkChange,
ioaddr + IntrEnable);
- return 0;
}
- else
- return 1;
+ return work_done;
}
#endif
@@ -633,6 +638,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
#else
int bar = 0;
#endif
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -697,10 +703,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
printk(KERN_ERR "alloc_etherdev failed\n");
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
rp = netdev_priv(dev);
+ rp->dev = dev;
rp->quirks = quirks;
rp->pioaddr = pioaddr;
rp->pdev = pdev;
@@ -779,8 +785,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
dev->poll_controller = rhine_poll;
#endif
#ifdef CONFIG_VIA_RHINE_NAPI
- dev->poll = rhine_napipoll;
- dev->weight = 64;
+ netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
#endif
if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
@@ -790,18 +795,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rc)
goto err_out_unmap;
- printk(KERN_INFO "%s: VIA %s at 0x%lx, ",
+ printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n",
dev->name, name,
#ifdef USE_MMIO
- memaddr
+ memaddr,
#else
- (long)ioaddr
+ (long)ioaddr,
#endif
- );
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
+ print_mac(mac, dev->dev_addr), pdev->irq);
pci_set_drvdata(pdev, dev);
@@ -1055,7 +1056,9 @@ static void init_registers(struct net_device *dev)
rhine_set_rx_mode(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_enable(&rp->napi);
+#endif
/* Enable interrupts by setting the interrupt mask. */
iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
@@ -1190,6 +1193,10 @@ static void rhine_tx_timeout(struct net_device *dev)
/* protect against concurrent rx interrupts */
disable_irq(rp->pdev->irq);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_disable(&rp->napi);
+#endif
+
spin_lock(&rp->lock);
/* clear all descriptors */
@@ -1318,7 +1325,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
IntrPCIErr | IntrStatsMax | IntrLinkChange,
ioaddr + IntrEnable);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &rp->napi);
#else
rhine_rx(dev, RX_RING_SIZE);
#endif
@@ -1803,9 +1810,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_msglevel = netdev_set_msglevel,
.get_wol = rhine_get_wol,
.set_wol = rhine_set_wol,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1832,7 +1836,9 @@ static int rhine_close(struct net_device *dev)
spin_lock_irq(&rp->lock);
netif_stop_queue(dev);
- netif_poll_disable(dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_disable(&rp->napi);
+#endif
if (debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, "
@@ -1931,6 +1937,9 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev))
return 0;
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_disable(&rp->napi);
+#endif
netif_device_detach(dev);
pci_save_state(pdev);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index f331843d1102..4ae05799ac44 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -72,6 +72,7 @@
#include <linux/mii.h>
#include <linux/in.h>
#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
@@ -84,6 +85,163 @@
static int velocity_nics = 0;
static int msglevel = MSG_LEVEL_INFO;
+/**
+ * mac_get_cam_mask - Read a CAM mask
+ * @regs: register block for this velocity
+ * @mask: buffer to store mask
+ *
+ * Fetch the mask bits of the selected CAM and store them into the
+ * provided mask buffer.
+ */
+
+static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+ int i;
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* read mask */
+ for (i = 0; i < 8; i++)
+ *mask++ = readb(&(regs->MARCAM[i]));
+
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+}
+
+
+/**
+ * mac_set_cam_mask - Set a CAM mask
+ * @regs: register block for this velocity
+ * @mask: CAM mask to load
+ *
+ * Store a new mask into a CAM
+ */
+
+static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+ int i;
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ writeb(CAMADDR_CAMEN, &regs->CAMADDR);
+
+ for (i = 0; i < 8; i++) {
+ writeb(*mask++, &(regs->MARCAM[i]));
+ }
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+ int i;
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
+
+ for (i = 0; i < 8; i++) {
+ writeb(*mask++, &(regs->MARCAM[i]));
+ }
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+/**
+ * mac_set_cam - set CAM data
+ * @regs: register block of this velocity
+ * @idx: Cam index
+ * @addr: 2 or 6 bytes of CAM data
+ *
+ * Load an address or vlan tag into a CAM
+ */
+
+static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+{
+ int i;
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ idx &= (64 - 1);
+
+ writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+ for (i = 0; i < 6; i++) {
+ writeb(*addr++, &(regs->MARCAM[i]));
+ }
+ BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+ udelay(10);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+ const u8 *addr)
+{
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ idx &= (64 - 1);
+
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
+ writew(*((u16 *) addr), &regs->MARCAM[0]);
+
+ BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+ udelay(10);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+
+/**
+ * mac_wol_reset - reset WOL after exiting low power
+ * @regs: register block of this velocity
+ *
+ * Called after we drop out of wake on lan mode in order to
+ * reset the Wake on lan features. This function doesn't restore
+ * the rest of the logic from the result of sleep/wakeup
+ */
+
+static void mac_wol_reset(struct mac_regs __iomem * regs)
+{
+
+ /* Turn off SWPTAG right after leaving power mode */
+ BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
+ /* clear sticky bits */
+ BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+ BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
+ BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ /* disable force PME-enable */
+ writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
+ /* disable power-event config bit */
+ writew(0xFFFF, &regs->WOLCRClr);
+ /* clear power status */
+ writew(0xFFFF, &regs->WOLSRClr);
+}
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static const struct ethtool_ops velocity_ethtool_ops;
@@ -111,15 +269,6 @@ VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
#define TX_DESC_DEF 64
VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
-#define VLAN_ID_MIN 0
-#define VLAN_ID_MAX 4095
-#define VLAN_ID_DEF 0
-/* VID_setting[] is used for setting the VID of NIC.
- 0: default VID.
- 1-4094: other VIDs.
-*/
-VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
-
#define RX_THRESH_MIN 0
#define RX_THRESH_MAX 3
#define RX_THRESH_DEF 0
@@ -147,13 +296,6 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
*/
VELOCITY_PARAM(DMA_length, "DMA length");
-#define TAGGING_DEF 0
-/* enable_tagging[] is used for enabling 802.1Q VID tagging.
- 0: disable VID seeting(default).
- 1: enable VID setting.
-*/
-VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
-
#define IP_ALIG_DEF 0
/* IP_byte_align[] is used for IP header DWORD byte aligned
0: indicate the IP header won't be DWORD byte aligned.(Default) .
@@ -324,7 +466,7 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
* a pointer a static string valid while the driver is loaded.
*/
-static char __devinit *get_chip_name(enum chip_type chip_id)
+static const char __devinit *get_chip_name(enum chip_type chip_id)
{
int i;
for (i = 0; chip_info_table[i].name != NULL; i++)
@@ -442,8 +584,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
- velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
- velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
+
velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
@@ -465,6 +606,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
static void velocity_init_cam_filter(struct velocity_info *vptr)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
+ unsigned short vid;
/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -473,27 +615,52 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
/* Disable all CAMs */
memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
- mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
- mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+ mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
+ mac_set_cam_mask(regs, vptr->mCAMmask);
/* Enable first VCAM */
- if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
- /* If Tagging option is enabled and VLAN ID is not zero, then
- turn on MCFG_RTGOPT also */
- if (vptr->options.vid != 0)
- WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
-
- mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+ if (vptr->vlgrp) {
+ for (vid = 0; vid < VLAN_VID_MASK; vid++) {
+ if (vlan_group_get_device(vptr->vlgrp, vid)) {
+ /* If Tagging option is enabled and
+ VLAN ID is not zero, then
+ turn on MCFG_RTGOPT also */
+ if (vid != 0)
+ WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+
+ mac_set_vlan_cam(regs, 0, (u8 *) &vid);
+ }
+ }
vptr->vCAMmask[0] |= 1;
- mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+ mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
} else {
u16 temp = 0;
- mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+ mac_set_vlan_cam(regs, 0, (u8 *) &temp);
temp = 1;
- mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+ mac_set_vlan_cam_mask(regs, (u8 *) &temp);
}
}
+static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ spin_lock_irq(&vptr->lock);
+ velocity_init_cam_filter(vptr);
+ spin_unlock_irq(&vptr->lock);
+}
+
+static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ spin_lock_irq(&vptr->lock);
+ vlan_group_set_device(vptr->vlgrp, vid, NULL);
+ velocity_init_cam_filter(vptr);
+ spin_unlock_irq(&vptr->lock);
+}
+
+
/**
* velocity_rx_reset - handle a receive reset
* @vptr: velocity we are resetting
@@ -712,7 +879,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
/* Chain it all together */
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
vptr = netdev_priv(dev);
@@ -791,13 +957,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
dev->do_ioctl = velocity_ioctl;
dev->ethtool_ops = &velocity_ethtool_ops;
dev->change_mtu = velocity_change_mtu;
+
+ dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;
+
#ifdef VELOCITY_ZERO_COPY_SUPPORT
dev->features |= NETIF_F_SG;
#endif
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER;
- if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+ if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
dev->features |= NETIF_F_IP_CSUM;
- }
ret = register_netdev(dev);
if (ret < 0)
@@ -1071,14 +1241,12 @@ static int velocity_rx_refill(struct velocity_info *vptr)
static int velocity_init_rd_ring(struct velocity_info *vptr)
{
- int ret = -ENOMEM;
- unsigned int rsize = sizeof(struct velocity_rd_info) *
- vptr->options.numrx;
+ int ret;
- vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
- if(vptr->rd_info == NULL)
- goto out;
- memset(vptr->rd_info, 0, rsize);
+ vptr->rd_info = kcalloc(vptr->options.numrx,
+ sizeof(struct velocity_rd_info), GFP_KERNEL);
+ if (!vptr->rd_info)
+ return -ENOMEM;
vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0;
@@ -1088,7 +1256,7 @@ static int velocity_init_rd_ring(struct velocity_info *vptr)
"%s: failed to allocate RX buffer.\n", vptr->dev->name);
velocity_free_rd_ring(vptr);
}
-out:
+
return ret;
}
@@ -1142,21 +1310,19 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
dma_addr_t curr;
struct tx_desc *td;
struct velocity_td_info *td_info;
- unsigned int tsize = sizeof(struct velocity_td_info) *
- vptr->options.numtx;
/* Init the TD ring entries */
for (j = 0; j < vptr->num_txq; j++) {
curr = vptr->td_pool_dma[j];
- vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL);
- if(vptr->td_infos[j] == NULL)
- {
+ vptr->td_infos[j] = kcalloc(vptr->options.numtx,
+ sizeof(struct velocity_td_info),
+ GFP_KERNEL);
+ if (!vptr->td_infos[j]) {
while(--j >= 0)
kfree(vptr->td_infos[j]);
return -ENOMEM;
}
- memset(vptr->td_infos[j], 0, tsize);
for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
td = &(vptr->td_rings[j][i]);
@@ -1613,7 +1779,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
if (status & ISR_TXSTLI) {
struct mac_regs __iomem * regs = vptr->mac_regs;
- printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(&regs->TDIdx[0]));
+ printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
writew(TRDCSR_RUN, &regs->TDCSRClr);
netif_stop_queue(vptr->dev);
@@ -1994,8 +2160,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
td_ptr->tdesc1.CMDZ = 2;
}
- if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
- td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+ if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+ td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb);
td_ptr->tdesc1.pqinf.priority = 0;
td_ptr->tdesc1.pqinf.CFI = 0;
td_ptr->tdesc1.TCR |= TCR0_VETAG;
@@ -2121,14 +2287,14 @@ static void velocity_set_multi(struct net_device *dev)
rx_mode = (RCR_AM | RCR_AB);
} else {
int offset = MCAM_SIZE - vptr->multicast_limit;
- mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+ mac_get_cam_mask(regs, vptr->mCAMmask);
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
- mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM);
+ mac_set_cam(regs, i + offset, mclist->dmi_addr);
vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
}
- mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+ mac_set_cam_mask(regs, vptr->mCAMmask);
rx_mode = (RCR_AM | RCR_AB);
}
if (dev->mtu > 1500)
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index b9e114d36c0f..aa9179623d90 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1173,7 +1173,7 @@ enum chip_type {
struct velocity_info_tbl {
enum chip_type chip_id;
- char *name;
+ const char *name;
int txqueue;
u32 flags;
};
@@ -1194,14 +1194,6 @@ struct velocity_info_tbl {
#define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr))
#define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set))
-#define mac_hw_mibs_read(regs, MIBs) {\
- int i;\
- BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\
- for (i=0;i<HW_MIB_SIZE;i++) {\
- (MIBs)[i]=readl(&((regs)->MIBData));\
- }\
-}
-
#define mac_set_dma_length(regs, n) {\
BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\
}
@@ -1226,195 +1218,17 @@ struct velocity_info_tbl {
writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\
}
-#define mac_eeprom_reload(regs) {\
- int i=0;\
- BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\
- do {\
- udelay(10);\
- if (i++>0x1000) {\
- break;\
- }\
- }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\
-}
-
-enum velocity_cam_type {
- VELOCITY_VLAN_ID_CAM = 0,
- VELOCITY_MULTICAST_CAM
-};
-
-/**
- * mac_get_cam_mask - Read a CAM mask
- * @regs: register block for this velocity
- * @mask: buffer to store mask
- * @cam_type: CAM to fetch
- *
- * Fetch the mask bits of the selected CAM and store them into the
- * provided mask buffer.
- */
-
-static inline void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
-{
- int i;
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_VCAMSL, &regs->CAMADDR);
- else
- writeb(0, &regs->CAMADDR);
-
- /* read mask */
- for (i = 0; i < 8; i++)
- *mask++ = readb(&(regs->MARCAM[i]));
-
- /* disable CAMEN */
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+static inline void mac_eeprom_reload(struct mac_regs __iomem * regs) {
+ int i=0;
+ BYTE_REG_BITS_ON(EECSR_RELOAD,&(regs->EECSR));
+ do {
+ udelay(10);
+ if (i++>0x1000)
+ break;
+ } while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&(regs->EECSR)));
}
-/**
- * mac_set_cam_mask - Set a CAM mask
- * @regs: register block for this velocity
- * @mask: CAM mask to load
- * @cam_type: CAM to store
- *
- * Store a new mask into a CAM
- */
-
-static inline void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
-{
- int i;
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
- else
- writeb(CAMADDR_CAMEN, &regs->CAMADDR);
-
- for (i = 0; i < 8; i++) {
- writeb(*mask++, &(regs->MARCAM[i]));
- }
- /* disable CAMEN */
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- * mac_set_cam - set CAM data
- * @regs: register block of this velocity
- * @idx: Cam index
- * @addr: 2 or 6 bytes of CAM data
- * @cam_type: CAM to load
- *
- * Load an address or vlan tag into a CAM
- */
-
-static inline void mac_set_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
-{
- int i;
-
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- idx &= (64 - 1);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
- else
- writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writew(*((u16 *) addr), &regs->MARCAM[0]);
- else {
- for (i = 0; i < 6; i++) {
- writeb(*addr++, &(regs->MARCAM[i]));
- }
- }
- BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
-
- udelay(10);
-
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- * mac_get_cam - fetch CAM data
- * @regs: register block of this velocity
- * @idx: Cam index
- * @addr: buffer to hold up to 6 bytes of CAM data
- * @cam_type: CAM to load
- *
- * Load an address or vlan tag from a CAM into the buffer provided by
- * the caller. VLAN tags are 2 bytes the address cam entries are 6.
- */
-
-static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
-{
- int i;
-
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- idx &= (64 - 1);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
- else
- writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
-
- BYTE_REG_BITS_ON(CAMCR_CAMRD, &regs->CAMCR);
-
- udelay(10);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- *((u16 *) addr) = readw(&(regs->MARCAM[0]));
- else
- for (i = 0; i < 6; i++, addr++)
- *((u8 *) addr) = readb(&(regs->MARCAM[i]));
-
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- * mac_wol_reset - reset WOL after exiting low power
- * @regs: register block of this velocity
- *
- * Called after we drop out of wake on lan mode in order to
- * reset the Wake on lan features. This function doesn't restore
- * the rest of the logic from the result of sleep/wakeup
- */
-
-static inline void mac_wol_reset(struct mac_regs __iomem * regs)
-{
-
- /* Turn off SWPTAG right after leaving power mode */
- BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
- /* clear sticky bits */
- BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
- BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
- BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
- /* disable force PME-enable */
- writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
- /* disable power-event config bit */
- writew(0xFFFF, &regs->WOLCRClr);
- /* clear power status */
- writew(0xFFFF, &regs->WOLSRClr);
-}
-
-
/*
* Header for WOL definitions. Used to compute hashes
*/
@@ -1701,7 +1515,7 @@ struct velocity_opt {
int numrx; /* Number of RX descriptors */
int numtx; /* Number of TX descriptors */
enum speed_opt spd_dpx; /* Media link mode */
- int vid; /* vlan id */
+
int DMA_length; /* DMA length */
int rx_thresh; /* RX_THRESH */
int flow_cntl;
@@ -1727,6 +1541,7 @@ struct velocity_info {
dma_addr_t tx_bufs_dma;
u8 *tx_bufs;
+ struct vlan_group *vlgrp;
u8 ip_addr[4];
enum chip_type chip_id;
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 6b63b350cd52..c4c8eab8574f 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -315,12 +315,11 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
return -ENODEV;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "c101: unable to allocate memory\n");
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
card->dev = alloc_hdlcdev(card);
if (!card->dev) {
@@ -364,7 +363,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
hdlc = dev_to_hdlc(dev);
spin_lock_init(&card->lock);
- SET_MODULE_OWNER(dev);
dev->irq = irq;
dev->mem_start = winbase;
dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 9ef49ce148b2..26058b4f8f36 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -572,13 +572,11 @@ static int cosa_probe(int base, int irq, int dma)
sprintf(cosa->name, "cosa%d", cosa->num);
/* Initialize the per-channel data */
- cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,
- GFP_KERNEL);
+ cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL);
if (!cosa->chan) {
err = -ENOMEM;
goto err_out3;
}
- memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);
for (i=0; i<cosa->nchannels; i++) {
cosa->chan[i].cosa = cosa;
cosa->chan[i].num = i;
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 6e5f1c898517..a0e8611ad8e8 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -113,12 +113,10 @@ static int __init cycx_init(void)
/* Verify number of cards and allocate adapter data space */
cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
cycx_ncards = max_t(int, cycx_ncards, 1);
- cycx_card_array = kmalloc(sizeof(struct cycx_device) * cycx_ncards,
- GFP_KERNEL);
+ cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL);
if (!cycx_card_array)
goto out;
- memset(cycx_card_array, 0, sizeof(struct cycx_device) * cycx_ncards);
/* Register adapters with WAN router */
for (cnt = 0; cnt < cycx_ncards; ++cnt) {
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 016b3ff3ea5e..8a1778cf98d1 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -131,14 +131,15 @@ static int cycx_wan_update(struct wan_device *wandev),
cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
/* Network device interface */
-static int cycx_netdevice_init(struct net_device *dev),
- cycx_netdevice_open(struct net_device *dev),
- cycx_netdevice_stop(struct net_device *dev),
- cycx_netdevice_hard_header(struct sk_buff *skb,
- struct net_device *dev, u16 type,
- void *daddr, void *saddr, unsigned len),
- cycx_netdevice_rebuild_header(struct sk_buff *skb),
- cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
+static int cycx_netdevice_init(struct net_device *dev);
+static int cycx_netdevice_open(struct net_device *dev);
+static int cycx_netdevice_stop(struct net_device *dev);
+static int cycx_netdevice_hard_header(struct sk_buff *skb,
+ struct net_device *dev, u16 type,
+ const void *daddr, const void *saddr,
+ unsigned len);
+static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
+static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev);
static struct net_device_stats *
@@ -376,11 +377,10 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
}
/* allocate and initialize private data */
- chan = kmalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
+ chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
if (!chan)
return -ENOMEM;
- memset(chan, 0, sizeof(*chan));
strcpy(chan->name, conf->name);
chan->card = card;
chan->link = conf->port;
@@ -469,7 +469,14 @@ static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
return 0;
}
+
/* Network Device Interface */
+
+static const struct header_ops cycx_header_ops = {
+ .create = cycx_netdevice_hard_header,
+ .rebuild = cycx_netdevice_rebuild_header,
+};
+
/* Initialize Linux network interface.
*
* This routine is called only once for each interface, during Linux network
@@ -484,8 +491,8 @@ static int cycx_netdevice_init(struct net_device *dev)
/* Initialize device driver entry points */
dev->open = cycx_netdevice_open;
dev->stop = cycx_netdevice_stop;
- dev->hard_header = cycx_netdevice_hard_header;
- dev->rebuild_header = cycx_netdevice_rebuild_header;
+ dev->header_ops = &cycx_header_ops;
+
dev->hard_start_xmit = cycx_netdevice_hard_start_xmit;
dev->get_stats = cycx_netdevice_get_stats;
@@ -509,7 +516,6 @@ static int cycx_netdevice_init(struct net_device *dev)
/* Set transmit buffer queue length */
dev->tx_queue_len = 10;
- SET_MODULE_OWNER(dev);
/* Initialize socket buffers */
cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
@@ -556,7 +562,8 @@ static int cycx_netdevice_stop(struct net_device *dev)
* Return: media header length. */
static int cycx_netdevice_hard_header(struct sk_buff *skb,
struct net_device *dev, u16 type,
- void *daddr, void *saddr, unsigned len)
+ const void *daddr, const void *saddr,
+ unsigned len)
{
skb->protocol = type;
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 66be20c292b6..96b232446c0b 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -66,8 +66,8 @@ static void dlci_setup(struct net_device *);
*/
static int dlci_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct frhdr hdr;
struct dlci_local *dlp;
@@ -361,7 +361,7 @@ static int dlci_add(struct dlci_add *dlci)
/* validate slave device */
- slave = dev_get_by_name(dlci->devname);
+ slave = dev_get_by_name(&init_net, dlci->devname);
if (!slave)
return -ENODEV;
@@ -427,7 +427,7 @@ static int dlci_del(struct dlci_add *dlci)
int err;
/* validate slave device */
- master = __dev_get_by_name(dlci->devname);
+ master = __dev_get_by_name(&init_net, dlci->devname);
if (!master)
return(-ENODEV);
@@ -485,6 +485,10 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg)
return(err);
}
+static const struct header_ops dlci_header_ops = {
+ .create = dlci_header,
+};
+
static void dlci_setup(struct net_device *dev)
{
struct dlci_local *dlp = dev->priv;
@@ -494,7 +498,7 @@ static void dlci_setup(struct net_device *dev)
dev->stop = dlci_close;
dev->do_ioctl = dlci_dev_ioctl;
dev->hard_start_xmit = dlci_transmit;
- dev->hard_header = dlci_header;
+ dev->header_ops = &dlci_header_ops;
dev->get_stats = dlci_get_stats;
dev->change_mtu = dlci_change_mtu;
dev->destructor = free_netdev;
@@ -513,6 +517,9 @@ static int dlci_dev_event(struct notifier_block *unused,
{
struct net_device *dev = (struct net_device *) ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (event == NETDEV_UNREGISTER) {
struct dlci_local *dlp;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index dca024471455..33dc713b5301 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -890,12 +890,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
struct dscc4_dev_priv *root;
int i, ret = -ENOMEM;
- root = kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+ root = kcalloc(dev_per_card, sizeof(*root), GFP_KERNEL);
if (!root) {
printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);
goto err_out;
}
- memset(root, 0, dev_per_card*sizeof(*root));
for (i = 0; i < dev_per_card; i++) {
root[i].dev = alloc_hdlcdev(root + i);
@@ -903,12 +902,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
goto err_free_dev;
}
- ppriv = kmalloc(sizeof(*ppriv), GFP_KERNEL);
+ ppriv = kzalloc(sizeof(*ppriv), GFP_KERNEL);
if (!ppriv) {
printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
goto err_free_dev;
}
- memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
ppriv->root = root;
spin_lock_init(&ppriv->lock);
@@ -927,7 +925,6 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
d->do_ioctl = dscc4_ioctl;
d->tx_timeout = dscc4_tx_timeout;
d->watchdog_timeo = TX_TIMEOUT;
- SET_MODULE_OWNER(d);
SET_NETDEV_DEV(d, &pdev->dev);
dpriv->dev_id = i;
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 58a53b6d9b42..12dae8e24844 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2476,13 +2476,12 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Allocate driver private data */
- card = kmalloc(sizeof (struct fst_card_info), GFP_KERNEL);
+ card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
if (card == NULL) {
printk_err("FarSync card found but insufficient memory for"
" driver storage\n");
return -ENOMEM;
}
- memset(card, 0, sizeof (struct fst_card_info));
/* Try to enable the device */
if ((err = pci_enable_device(pdev)) != 0) {
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 65ad2e24caf0..d553e6f32851 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -36,6 +36,7 @@
#include <linux/rtnetlink.h>
#include <linux/notifier.h>
#include <linux/hdlc.h>
+#include <net/net_namespace.h>
static const char* version = "HDLC support module revision 1.21";
@@ -66,6 +67,12 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p, struct net_device *orig_dev)
{
struct hdlc_device_desc *desc = dev_to_desc(dev);
+
+ if (dev->nd_net != &init_net) {
+ kfree_skb(skb);
+ return 0;
+ }
+
if (desc->netif_rx)
return desc->netif_rx(skb);
@@ -102,6 +109,9 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event,
unsigned long flags;
int on;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (dev->get_stats != hdlc_get_stats)
return NOTIFY_DONE; /* not an HDLC device */
@@ -222,6 +232,8 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
+static const struct header_ops hdlc_null_ops;
+
static void hdlc_setup_dev(struct net_device *dev)
{
/* Re-init all variables changed by HDLC protocol drivers,
@@ -233,13 +245,9 @@ static void hdlc_setup_dev(struct net_device *dev)
dev->type = ARPHRD_RAWHDLC;
dev->hard_header_len = 16;
dev->addr_len = 0;
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->set_mac_address = NULL;
- dev->hard_header_cache = NULL;
- dev->header_cache_update = NULL;
+ dev->header_ops = &hdlc_null_ops;
+
dev->change_mtu = hdlc_change_mtu;
- dev->hard_header_parse = NULL;
}
static void hdlc_setup(struct net_device *dev)
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 9ec6cf2e510e..038a6e748bbf 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -74,7 +74,7 @@ static inline struct cisco_state * state(hdlc_device *hdlc)
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
- u16 type, void *daddr, void *saddr,
+ u16 type, const void *daddr, const void *saddr,
unsigned int len)
{
struct hdlc_header *data;
@@ -309,7 +309,6 @@ static void cisco_stop(struct net_device *dev)
}
-
static struct hdlc_proto proto = {
.start = cisco_start,
.stop = cisco_stop,
@@ -317,7 +316,10 @@ static struct hdlc_proto proto = {
.ioctl = cisco_ioctl,
.module = THIS_MODULE,
};
-
+
+static const struct header_ops cisco_header_ops = {
+ .create = cisco_hard_header,
+};
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
{
@@ -365,7 +367,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
memcpy(&state(hdlc)->settings, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
- dev->hard_header = cisco_hard_header;
+ dev->header_ops = &cisco_header_ops;
dev->type = ARPHRD_CISCO;
netif_dormant_on(dev);
return 0;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 15b6e07a4382..071a64cacd5c 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -212,14 +212,13 @@ static pvc_device* add_pvc(struct net_device *dev, u16 dlci)
pvc_p = &(*pvc_p)->next;
}
- pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
+ pvc = kzalloc(sizeof(pvc_device), GFP_ATOMIC);
#ifdef DEBUG_PVC
printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev);
#endif
if (!pvc)
return NULL;
- memset(pvc, 0, sizeof(pvc_device));
pvc->dlci = dlci;
pvc->frad = dev;
pvc->next = *pvc_p; /* Put it in the chain */
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 4591437dd2f3..3caeb528eace 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -73,7 +73,7 @@ static void ppp_close(struct net_device *dev)
sppp_close(dev);
sppp_detach(dev);
- dev->rebuild_header = NULL;
+
dev->change_mtu = state(hdlc)->old_change_mtu;
dev->mtu = HDLC_MAX_MTU;
dev->hard_header_len = 16;
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 9ba3e4ee6ec7..83dbc924fcb5 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -231,19 +231,16 @@ static struct sv11_device *sv11_init(int iobase, int irq)
return NULL;
}
- sv = kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+ sv = kzalloc(sizeof(struct sv11_device), GFP_KERNEL);
if(!sv)
goto fail3;
- memset(sv, 0, sizeof(*sv));
sv->if_ptr=&sv->netdev;
sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup);
if(!sv->netdev.dev)
goto fail2;
- SET_MODULE_OWNER(sv->netdev.dev);
-
dev=&sv->sync;
/*
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 6c302e9dbca2..fb37b8095231 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -91,6 +91,9 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
int len, err;
struct lapbethdev *lapbeth;
+ if (dev->nd_net != &init_net)
+ goto drop;
+
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
@@ -213,7 +216,7 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
skb->dev = dev = lapbeth->ethdev;
- dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
+ dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
dev_queue_xmit(skb);
}
@@ -326,7 +329,6 @@ static void lapbeth_setup(struct net_device *dev)
dev->hard_header_len = 3;
dev->mtu = 1000;
dev->addr_len = 0;
- SET_MODULE_OWNER(dev);
}
/*
@@ -391,6 +393,9 @@ static int lapbeth_device_event(struct notifier_block *this,
struct lapbethdev *lapbeth;
struct net_device *dev = ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index ae132c1c5459..5ea877221f46 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -883,7 +883,6 @@ static int __devinit lmc_init_one(struct pci_dev *pdev,
dev->base_addr = pci_resource_start(pdev, 0);
dev->irq = pdev->irq;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/*
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index 31e1799571ad..426c0678d983 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -111,7 +111,7 @@ void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/
* They set a few basics because they don't use sync_ppp
*/
dev->flags |= IFF_POINTOPOINT;
- dev->hard_header = NULL;
+
dev->hard_header_len = 0;
dev->addr_len = 0;
}
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 5c322dfb79f6..0a566b0daacb 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -351,12 +351,11 @@ static int __init n2_run(unsigned long io, unsigned long irq,
return -ENODEV;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "n2: unable to allocate memory\n");
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
@@ -460,7 +459,6 @@ static int __init n2_run(unsigned long io, unsigned long irq,
port->log_node = 1;
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->irq = irq;
dev->mem_start = winbase;
dev->mem_end = winbase + USE_WINDOWSIZE - 1;
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 5d8c78ee2cd9..99fee2f1d019 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -3456,7 +3456,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if ((err = pci_enable_device(pdev)) < 0)
return err;
- card = kmalloc(sizeof(pc300_t), GFP_KERNEL);
+ card = kzalloc(sizeof(pc300_t), GFP_KERNEL);
if (card == NULL) {
printk("PC300 found at RAM 0x%016llx, "
"but could not allocate card structure.\n",
@@ -3464,7 +3464,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto err_disable_dev;
}
- memset(card, 0, sizeof(pc300_t));
err = -ENODEV;
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index dfbd3b00f03b..bf1b01590429 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -334,14 +334,13 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
return i;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "pc300: unable to allocate memory\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
pci_set_drvdata(pdev, card);
if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
@@ -469,7 +468,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
port->phy_node = i;
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->irq = card->irq;
dev->mem_start = ramphys;
dev->mem_end = ramphys + ramsize - 1;
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index 7f720de2e9f0..b595b64e7538 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -312,14 +312,13 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
return i;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "pci200syn: unable to allocate memory\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
pci_set_drvdata(pdev, card);
card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
@@ -416,7 +415,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
port->phy_node = i;
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->irq = card->irq;
dev->mem_start = ramphys;
dev->mem_end = ramphys + ramsize - 1;
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 1cc18e787a65..76db40d200d8 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -54,6 +54,7 @@
#include <linux/init.h>
#include <linux/delay.h>
+#include <net/net_namespace.h>
#include <net/arp.h>
#include <asm/io.h>
@@ -215,8 +216,6 @@ static void __init sbni_devsetup(struct net_device *dev)
dev->get_stats = &sbni_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &sbni_ioctl;
-
- SET_MODULE_OWNER( dev );
}
int __init sbni_probe(int unit)
@@ -1361,7 +1360,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name ))
return -EFAULT;
- slave_dev = dev_get_by_name( slave_name );
+ slave_dev = dev_get_by_name(&init_net, slave_name );
if( !slave_dev || !(slave_dev->flags & IFF_UP) ) {
printk( KERN_ERR "%s: trying to enslave non-active "
"device %s\n", dev->name, slave_name );
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 6a485f0556f4..b39a541b2509 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -1196,10 +1196,9 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
if (read)
{
- temp = kmalloc(mem.len, GFP_KERNEL);
+ temp = kzalloc(mem.len, GFP_KERNEL);
if (!temp)
return(-ENOMEM);
- memset(temp, 0, mem.len);
sdla_read(dev, mem.addr, temp, mem.len);
if(copy_to_user(mem.data, temp, mem.len))
{
@@ -1604,7 +1603,6 @@ static void setup_sdla(struct net_device *dev)
netdev_boot_setup_check(dev);
- SET_MODULE_OWNER(dev);
dev->flags = 0;
dev->type = 0xFFFF;
dev->hard_header_len = 0;
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 131358108c5a..11276bf3149f 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -270,11 +270,10 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
return NULL;
}
- b = kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+ b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL);
if(!b)
goto fail3;
- memset(b, 0, sizeof(*b));
if (!(b->dev[0]= slvl_alloc(iobase, irq)))
goto fail2;
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 67fc67cfd452..232ecba5340f 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -51,6 +51,7 @@
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
+#include <net/net_namespace.h>
#include <net/syncppp.h>
#include <asm/byteorder.h>
@@ -358,8 +359,10 @@ done:
* Handle transmit packets.
*/
-static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
- void *daddr, void *saddr, unsigned int len)
+static int sppp_hard_header(struct sk_buff *skb,
+ struct net_device *dev, __u16 type,
+ const void *daddr, const void *saddr,
+ unsigned int len)
{
struct sppp *sp = (struct sppp *)sppp_of(dev);
struct ppp_header *h;
@@ -391,10 +394,9 @@ static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 t
return sizeof(struct ppp_header);
}
-static int sppp_rebuild_header(struct sk_buff *skb)
-{
- return 0;
-}
+static const struct header_ops sppp_header_ops = {
+ .create = sppp_hard_header,
+};
/*
* Send keepalive packets, every 10 seconds.
@@ -1097,8 +1099,8 @@ void sppp_attach(struct ppp_device *pd)
* hard_start_xmit.
*/
- dev->hard_header = sppp_hard_header;
- dev->rebuild_header = sppp_rebuild_header;
+ dev->header_ops = &sppp_header_ops;
+
dev->tx_queue_len = 10;
dev->type = ARPHRD_HDLC;
dev->addr_len = 0;
@@ -1114,8 +1116,6 @@ void sppp_attach(struct ppp_device *pd)
dev->stop = sppp_close;
#endif
dev->change_mtu = sppp_change_mtu;
- dev->hard_header_cache = NULL;
- dev->header_cache_update = NULL;
dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
}
@@ -1445,6 +1445,11 @@ static void sppp_print_bytes (u_char *p, u16 len)
static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev)
{
+ if (dev->nd_net != &init_net) {
+ kfree_skb(skb);
+ return 0;
+ }
+
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
sppp_input(dev,skb);
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index c73601574334..8e320b76ae0e 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -599,7 +599,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
}
alloc_size = sizeof(card_t) + ports * sizeof(port_t);
- card = kmalloc(alloc_size, GFP_KERNEL);
+ card = kzalloc(alloc_size, GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
pci_name(pdev));
@@ -607,7 +607,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
pci_disable_device(pdev);
return -ENOBUFS;
}
- memset(card, 0, alloc_size);
pci_set_drvdata(pdev, card);
card->pdev = pdev;
@@ -780,7 +779,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
port->dev = dev;
hdlc = dev_to_hdlc(dev);
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->tx_queue_len = 50;
dev->do_ioctl = wanxl_ioctl;
dev->open = wanxl_open;
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 1c9edd97accd..c48b1cc63fd5 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -786,14 +786,12 @@ static int __init init_x25_asy(void)
printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
"(dynamic channels, max=%d).\n", x25_asy_maxdev );
- x25_asy_devs = kmalloc(sizeof(struct net_device *)*x25_asy_maxdev,
- 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");
return -ENOMEM;
}
- memset(x25_asy_devs, 0, sizeof(struct net_device *)*x25_asy_maxdev);
return tty_register_ldisc(N_X25, &x25_ldisc);
}
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index a0326818ff2f..fa14255282af 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -93,8 +93,6 @@ static int __init do_wd_probe(struct net_device *dev)
int mem_start = dev->mem_start;
int mem_end = dev->mem_end;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) { /* Check a user specified location. */
r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
if ( r == NULL)
@@ -158,6 +156,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */
const char *model_name;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
for (i = 0; i < 8; i++)
checksum += inb(ioaddr + 8 + i);
@@ -176,9 +175,11 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
if (ei_debug && version_printed++ == 0)
printk(version);
- printk("%s: WD80x3 at %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk("%s: WD80x3 at %#3x, %s",
+ dev->name, ioaddr, print_mac(mac, dev->dev_addr));
/* The following PureData probe code was contributed by
Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ae27af0141c0..5a6fdfd0f140 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -63,11 +63,6 @@ config WAVELAN
a Radio LAN (wireless Ethernet-like Local Area Network) using the
radio frequencies 900 MHz and 2.4 GHz.
- This driver support the ISA version of the WaveLAN card. A separate
- driver for the PCMCIA (PC-card) hardware is available in David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location).
-
If you want to use an ISA WaveLAN card under Linux, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. Some more specific
@@ -280,6 +275,13 @@ config LIBERTAS_USB
---help---
A driver for Marvell Libertas 8388 USB devices.
+config LIBERTAS_CS
+ tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
+ depends on LIBERTAS && PCMCIA && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ A driver for Marvell Libertas 8385 CompactFlash devices.
+
config LIBERTAS_DEBUG
bool "Enable full debugging output in the Libertas module."
depends on LIBERTAS
@@ -379,30 +381,6 @@ config PCI_HERMES
common. Some of the built-in wireless adaptors in laptops are of
this variety.
-config ATMEL
- tristate "Atmel at76c50x chipset 802.11b support"
- depends on (PCI || PCMCIA) && WLAN_80211
- select WIRELESS_EXT
- select FW_LOADER
- select CRC32
- ---help---
- A driver 802.11b wireless cards based on the Atmel fast-vnet
- chips. This driver supports standard Linux wireless extensions.
-
- Many cards based on this chipset do not have flash memory
- and need their firmware loaded at start-up. If yours is
- one of these, you will need to provide a firmware image
- to be loaded into the card by the driver. The Atmel
- firmware package can be downloaded from
- <http://www.thekelleys.org.uk/atmel>
-
-config PCI_ATMEL
- tristate "Atmel at76c506 PCI cards"
- depends on ATMEL && PCI
- ---help---
- Enable support for PCI and mini-PCI cards containing the
- Atmel at76c506 chip.
-
config PCMCIA_HERMES
tristate "Hermes PCMCIA card support"
depends on PCMCIA && HERMES
@@ -414,12 +392,7 @@ config PCMCIA_HERMES
such as the Linksys, D-Link and Farallon Skyline. It should also
work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). You also want to check out the PCMCIA-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- You will also very likely also need the Wireless Tools in order to
+ You will very likely need the Wireless Tools in order to
configure your card and that /etc/pcmcia/wireless.opts works:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
@@ -437,6 +410,40 @@ config PCMCIA_SPECTRUM
for downloading Symbol firmware are available at
<http://sourceforge.net/projects/orinoco/>
+config ATMEL
+ tristate "Atmel at76c50x chipset 802.11b support"
+ depends on (PCI || PCMCIA) && WLAN_80211
+ select WIRELESS_EXT
+ select FW_LOADER
+ select CRC32
+ ---help---
+ A driver 802.11b wireless cards based on the Atmel fast-vnet
+ chips. This driver supports standard Linux wireless extensions.
+
+ Many cards based on this chipset do not have flash memory
+ and need their firmware loaded at start-up. If yours is
+ one of these, you will need to provide a firmware image
+ to be loaded into the card by the driver. The Atmel
+ firmware package can be downloaded from
+ <http://www.thekelleys.org.uk/atmel>
+
+config PCI_ATMEL
+ tristate "Atmel at76c506 PCI cards"
+ depends on ATMEL && PCI
+ ---help---
+ Enable support for PCI and mini-PCI cards containing the
+ Atmel at76c506 chip.
+
+config PCMCIA_ATMEL
+ tristate "Atmel at76c502/at76c504 PCMCIA cards"
+ depends on ATMEL && PCMCIA
+ select WIRELESS_EXT
+ select FW_LOADER
+ select CRC32
+ ---help---
+ Enable support for PCMCIA cards containing the
+ Atmel at76c502 and at76c504 chips.
+
config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211
@@ -457,21 +464,6 @@ config AIRO_CS
and Cisco proprietary API, so both the Linux Wireless Tools and the
Cisco Linux utilities can be used to configure the card.
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). You also want to check out the PCMCIA-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
-config PCMCIA_ATMEL
- tristate "Atmel at76c502/at76c504 PCMCIA cards"
- depends on ATMEL && PCMCIA
- select WIRELESS_EXT
- select FW_LOADER
- select CRC32
- ---help---
- Enable support for PCMCIA cards containing the
- Atmel at76c502 and at76c504 chips.
-
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
depends on EXPERIMENTAL && PCMCIA && WLAN_80211
@@ -558,8 +550,52 @@ config RTL8187
Thanks to Realtek for their support!
+config ADM8211
+ tristate "ADMtek ADM8211 support"
+ depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
+ select CRC32
+ select EEPROM_93CX6
+ ---help---
+ This driver is for ADM8211A, ADM8211B, and ADM8211C based cards.
+ These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as:
+
+ Xterasys Cardbus XN-2411b
+ Blitz NetWave Point PC
+ TrendNet 221pc
+ Belkin F5D6001
+ SMC 2635W
+ Linksys WPC11 v1
+ Fiberline FL-WL-200X
+ 3com Office Connect (3CRSHPW796)
+ Corega WLPCIB-11
+ SMC 2602W V2 EU
+ D-Link DWL-520 Revision C
+
+ However, some of these cards have been replaced with other chips
+ like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or
+ the Ralink RT2400 (SMC2635W) without a model number change.
+
+ Thanks to Infineon-ADMtek for their support of this driver.
+
+config P54_COMMON
+ tristate "Softmac Prism54 support"
+ depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL
+
+config P54_USB
+ tristate "Prism54 USB support"
+ depends on P54_COMMON && USB
+ select CRC32
+
+config P54_PCI
+ tristate "Prism54 PCI support"
+ depends on P54_COMMON && PCI
+
+source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/b43/Kconfig"
+source "drivers/net/wireless/b43legacy/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
+source "drivers/net/wireless/rt2x00/Kconfig"
endmenu
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index ef35bc6c4a22..6f32b53ee128 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -36,6 +36,8 @@ obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_BCM43XX) += bcm43xx/
+obj-$(CONFIG_B43) += b43/
+obj-$(CONFIG_B43LEGACY) += b43legacy/
obj-$(CONFIG_ZD1211RW) += zd1211rw/
# 16-bit wireless PCMCIA client drivers
@@ -43,7 +45,16 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o
-obj-$(CONFIG_LIBERTAS_USB) += libertas/
+obj-$(CONFIG_LIBERTAS) += libertas/
rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
obj-$(CONFIG_RTL8187) += rtl8187.o
+
+obj-$(CONFIG_ADM8211) += adm8211.o
+
+obj-$(CONFIG_IWLWIFI) += iwlwifi/
+obj-$(CONFIG_RT2X00) += rt2x00/
+
+obj-$(CONFIG_P54_COMMON) += p54common.o
+obj-$(CONFIG_P54_USB) += p54usb.o
+obj-$(CONFIG_P54_PCI) += p54pci.o
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
new file mode 100644
index 000000000000..5bf7913aadda
--- /dev/null
+++ b/drivers/net/wireless/adm8211.c
@@ -0,0 +1,2053 @@
+
+/*
+ * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP)
+ *
+ * Copyright (c) 2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2007, Michael Wu <flamingice@sourmilk.net>
+ * Some parts copyright (c) 2003 by David Young <dyoung@pobox.com>
+ * and used with permission.
+ *
+ * Much thanks to Infineon-ADMtek for their support of this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "adm8211.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
+MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless cards based on ADMtek ADM8211");
+MODULE_SUPPORTED_DEVICE("ADM8211");
+MODULE_LICENSE("GPL");
+
+static unsigned int tx_ring_size __read_mostly = 16;
+static unsigned int rx_ring_size __read_mostly = 16;
+
+module_param(tx_ring_size, uint, 0);
+module_param(rx_ring_size, uint, 0);
+
+static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+ /* ADMtek ADM8211 */
+ { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */
+ { PCI_DEVICE(0x1200, 0x8201) }, /* ? */
+ { PCI_DEVICE(0x1317, 0x8201) }, /* ADM8211A */
+ { PCI_DEVICE(0x1317, 0x8211) }, /* ADM8211B/C */
+ { 0 }
+};
+
+static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+ struct adm8211_priv *priv = eeprom->data;
+ u32 reg = ADM8211_CSR_READ(SPR);
+
+ eeprom->reg_data_in = reg & ADM8211_SPR_SDI;
+ eeprom->reg_data_out = reg & ADM8211_SPR_SDO;
+ eeprom->reg_data_clock = reg & ADM8211_SPR_SCLK;
+ eeprom->reg_chip_select = reg & ADM8211_SPR_SCS;
+}
+
+static void adm8211_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+ struct adm8211_priv *priv = eeprom->data;
+ u32 reg = 0x4000 | ADM8211_SPR_SRS;
+
+ if (eeprom->reg_data_in)
+ reg |= ADM8211_SPR_SDI;
+ if (eeprom->reg_data_out)
+ reg |= ADM8211_SPR_SDO;
+ if (eeprom->reg_data_clock)
+ reg |= ADM8211_SPR_SCLK;
+ if (eeprom->reg_chip_select)
+ reg |= ADM8211_SPR_SCS;
+
+ ADM8211_CSR_WRITE(SPR, reg);
+ ADM8211_CSR_READ(SPR); /* eeprom_delay */
+}
+
+static int adm8211_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int words, i;
+ struct ieee80211_chan_range chan_range;
+ u16 cr49;
+ struct eeprom_93cx6 eeprom = {
+ .data = priv,
+ .register_read = adm8211_eeprom_register_read,
+ .register_write = adm8211_eeprom_register_write
+ };
+
+ if (ADM8211_CSR_READ(CSR_TEST0) & ADM8211_CSR_TEST0_EPTYP) {
+ /* 256 * 16-bit = 512 bytes */
+ eeprom.width = PCI_EEPROM_WIDTH_93C66;
+ words = 256;
+ } else {
+ /* 64 * 16-bit = 128 bytes */
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
+ words = 64;
+ }
+
+ priv->eeprom_len = words * 2;
+ priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL);
+ if (!priv->eeprom)
+ return -ENOMEM;
+
+ eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words);
+
+ cr49 = le16_to_cpu(priv->eeprom->cr49);
+ priv->rf_type = (cr49 >> 3) & 0x7;
+ switch (priv->rf_type) {
+ case ADM8211_TYPE_INTERSIL:
+ case ADM8211_TYPE_RFMD:
+ case ADM8211_TYPE_MARVEL:
+ case ADM8211_TYPE_AIROHA:
+ case ADM8211_TYPE_ADMTEK:
+ break;
+
+ default:
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ priv->rf_type = ADM8211_TYPE_RFMD;
+ else
+ priv->rf_type = ADM8211_TYPE_AIROHA;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown RFtype %d\n",
+ pci_name(priv->pdev), (cr49 >> 3) & 0x7);
+ }
+
+ priv->bbp_type = cr49 & 0x7;
+ switch (priv->bbp_type) {
+ case ADM8211_TYPE_INTERSIL:
+ case ADM8211_TYPE_RFMD:
+ case ADM8211_TYPE_MARVEL:
+ case ADM8211_TYPE_AIROHA:
+ case ADM8211_TYPE_ADMTEK:
+ break;
+ default:
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ priv->bbp_type = ADM8211_TYPE_RFMD;
+ else
+ priv->bbp_type = ADM8211_TYPE_ADMTEK;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown BBPtype: %d\n",
+ pci_name(priv->pdev), cr49 >> 3);
+ }
+
+ if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) {
+ printk(KERN_WARNING "%s (adm8211): Invalid country code (%d)\n",
+ pci_name(priv->pdev), priv->eeprom->country_code);
+
+ chan_range = cranges[2];
+ } else
+ chan_range = cranges[priv->eeprom->country_code];
+
+ printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
+ pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
+
+ priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
+ priv->modes[0].channels = priv->channels;
+
+ memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels));
+
+ for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++)
+ if (i >= chan_range.min && i <= chan_range.max)
+ priv->channels[i - 1].flag =
+ IEEE80211_CHAN_W_SCAN |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_IBSS;
+
+ switch (priv->eeprom->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+ case ADM8211_BBP_RFMD3002:
+ case ADM8211_BBP_ADM8011:
+ priv->specific_bbptype = priv->eeprom->specific_bbptype;
+ break;
+
+ default:
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ priv->specific_bbptype = ADM8211_BBP_RFMD3000;
+ else
+ priv->specific_bbptype = ADM8211_BBP_ADM8011;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown specific BBP: %d\n",
+ pci_name(priv->pdev), priv->eeprom->specific_bbptype);
+ }
+
+ switch (priv->eeprom->specific_rftype) {
+ case ADM8211_RFMD2948:
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ case ADM8211_MAX2820:
+ case ADM8211_AL2210L:
+ priv->transceiver_type = priv->eeprom->specific_rftype;
+ break;
+
+ default:
+ if (priv->pdev->revision == ADM8211_REV_BA)
+ priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER;
+ else if (priv->pdev->revision == ADM8211_REV_CA)
+ priv->transceiver_type = ADM8211_AL2210L;
+ else if (priv->pdev->revision == ADM8211_REV_AB)
+ priv->transceiver_type = ADM8211_RFMD2948;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n",
+ pci_name(priv->pdev), priv->eeprom->specific_rftype);
+
+ break;
+ }
+
+ printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d "
+ "Transceiver=%d\n", pci_name(priv->pdev), priv->rf_type,
+ priv->bbp_type, priv->specific_bbptype, priv->transceiver_type);
+
+ return 0;
+}
+
+static inline void adm8211_write_sram(struct ieee80211_hw *dev,
+ u32 addr, u32 data)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR |
+ (priv->pdev->revision < ADM8211_REV_BA ?
+ 0 : ADM8211_WEPCTL_SEL_WEPTABLE ));
+ ADM8211_CSR_READ(WEPCTL);
+ msleep(1);
+
+ ADM8211_CSR_WRITE(WESK, data);
+ ADM8211_CSR_READ(WESK);
+ msleep(1);
+}
+
+static void adm8211_write_sram_bytes(struct ieee80211_hw *dev,
+ unsigned int addr, u8 *buf,
+ unsigned int len)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg = ADM8211_CSR_READ(WEPCTL);
+ unsigned int i;
+
+ if (priv->pdev->revision < ADM8211_REV_BA) {
+ for (i = 0; i < len; i += 2) {
+ u16 val = buf[i] | (buf[i + 1] << 8);
+ adm8211_write_sram(dev, addr + i / 2, val);
+ }
+ } else {
+ for (i = 0; i < len; i += 4) {
+ u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) |
+ (buf[i + 2] << 16) | (buf[i + 3] << 24);
+ adm8211_write_sram(dev, addr + i / 4, val);
+ }
+ }
+
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static void adm8211_clear_sram(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg = ADM8211_CSR_READ(WEPCTL);
+ unsigned int addr;
+
+ for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++)
+ adm8211_write_sram(dev, addr, 0);
+
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static int adm8211_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+
+ return 0;
+}
+
+static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct adm8211_priv *priv = dev->priv;
+ struct ieee80211_tx_queue_stats_data *data = &stats->data[0];
+
+ data->len = priv->cur_tx - priv->dirty_tx;
+ data->limit = priv->tx_ring_size - 2;
+ data->count = priv->dirty_tx;
+
+ return 0;
+}
+
+static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int dirty_tx;
+
+ spin_lock(&priv->lock);
+
+ for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
+ unsigned int entry = dirty_tx % priv->tx_ring_size;
+ u32 status = le32_to_cpu(priv->tx_ring[entry].status);
+ struct ieee80211_tx_status tx_status;
+ struct adm8211_tx_ring_info *info;
+ struct sk_buff *skb;
+
+ if (status & TDES0_CONTROL_OWN ||
+ !(status & TDES0_CONTROL_DONE))
+ break;
+
+ info = &priv->tx_buffers[entry];
+ skb = info->skb;
+
+ /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */
+
+ pci_unmap_single(priv->pdev, info->mapping,
+ info->skb->len, PCI_DMA_TODEVICE);
+
+ memset(&tx_status, 0, sizeof(tx_status));
+ skb_pull(skb, sizeof(struct adm8211_tx_hdr));
+ memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
+ memcpy(&tx_status.control, &info->tx_control,
+ sizeof(tx_status.control));
+ if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (status & TDES0_STATUS_ES)
+ tx_status.excessive_retries = 1;
+ else
+ tx_status.flags |= IEEE80211_TX_STATUS_ACK;
+ }
+ ieee80211_tx_status_irqsafe(dev, skb, &tx_status);
+
+ info->skb = NULL;
+ }
+
+ if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2)
+ ieee80211_wake_queue(dev, 0);
+
+ priv->dirty_tx = dirty_tx;
+ spin_unlock(&priv->lock);
+}
+
+
+static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int entry = priv->cur_rx % priv->rx_ring_size;
+ u32 status;
+ unsigned int pktlen;
+ struct sk_buff *skb, *newskb;
+ unsigned int limit = priv->rx_ring_size;
+ static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
+ u8 rssi, rate;
+
+ while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) {
+ if (!limit--)
+ break;
+
+ status = le32_to_cpu(priv->rx_ring[entry].status);
+ rate = (status & RDES0_STATUS_RXDR) >> 12;
+ rssi = le32_to_cpu(priv->rx_ring[entry].length) &
+ RDES1_STATUS_RSSI;
+
+ pktlen = status & RDES0_STATUS_FL;
+ if (pktlen > RX_PKT_SIZE) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: frame too long (%d)\n",
+ wiphy_name(dev->wiphy), pktlen);
+ pktlen = RX_PKT_SIZE;
+ }
+
+ if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) {
+ skb = NULL; /* old buffer will be reused */
+ /* TODO: update RX error stats */
+ /* TODO: check RDES0_STATUS_CRC*E */
+ } else if (pktlen < RX_COPY_BREAK) {
+ skb = dev_alloc_skb(pktlen);
+ if (skb) {
+ pci_dma_sync_single_for_cpu(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ pktlen, PCI_DMA_FROMDEVICE);
+ memcpy(skb_put(skb, pktlen),
+ skb_tail_pointer(priv->rx_buffers[entry].skb),
+ pktlen);
+ pci_dma_sync_single_for_device(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+ }
+ } else {
+ newskb = dev_alloc_skb(RX_PKT_SIZE);
+ if (newskb) {
+ skb = priv->rx_buffers[entry].skb;
+ skb_put(skb, pktlen);
+ pci_unmap_single(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+ priv->rx_buffers[entry].skb = newskb;
+ priv->rx_buffers[entry].mapping =
+ pci_map_single(priv->pdev,
+ skb_tail_pointer(newskb),
+ RX_PKT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ } else {
+ skb = NULL;
+ /* TODO: update rx dropped stats */
+ }
+
+ priv->rx_ring[entry].buffer1 =
+ cpu_to_le32(priv->rx_buffers[entry].mapping);
+ }
+
+ priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN |
+ RDES0_STATUS_SQL);
+ priv->rx_ring[entry].length =
+ cpu_to_le32(RX_PKT_SIZE |
+ (entry == priv->rx_ring_size - 1 ?
+ RDES1_CONTROL_RER : 0));
+
+ if (skb) {
+ struct ieee80211_rx_status rx_status = {0};
+
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ rx_status.ssi = rssi;
+ else
+ rx_status.ssi = 100 - rssi;
+
+ if (rate <= 4)
+ rx_status.rate = rate_tbl[rate];
+
+ rx_status.channel = priv->channel;
+ rx_status.freq = adm8211_channels[priv->channel - 1].freq;
+ rx_status.phymode = MODE_IEEE80211B;
+
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ }
+
+ entry = (++priv->cur_rx) % priv->rx_ring_size;
+ }
+
+ /* TODO: check LPC and update stats? */
+}
+
+
+static irqreturn_t adm8211_interrupt(int irq, void *dev_id)
+{
+#define ADM8211_INT(x) \
+do { \
+ if (unlikely(stsr & ADM8211_STSR_ ## x)) \
+ printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \
+} while (0)
+
+ struct ieee80211_hw *dev = dev_id;
+ struct adm8211_priv *priv = dev->priv;
+ u32 stsr = ADM8211_CSR_READ(STSR);
+ ADM8211_CSR_WRITE(STSR, stsr);
+ if (stsr == 0xffffffff)
+ return IRQ_HANDLED;
+
+ if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS)))
+ return IRQ_HANDLED;
+
+ if (stsr & ADM8211_STSR_RCI)
+ adm8211_interrupt_rci(dev);
+ if (stsr & ADM8211_STSR_TCI)
+ adm8211_interrupt_tci(dev);
+
+ /*ADM8211_INT(LinkOn);*/
+ /*ADM8211_INT(LinkOff);*/
+
+ ADM8211_INT(PCF);
+ ADM8211_INT(BCNTC);
+ ADM8211_INT(GPINT);
+ ADM8211_INT(ATIMTC);
+ ADM8211_INT(TSFTF);
+ ADM8211_INT(TSCZ);
+ ADM8211_INT(SQL);
+ ADM8211_INT(WEPTD);
+ ADM8211_INT(ATIME);
+ /*ADM8211_INT(TBTT);*/
+ ADM8211_INT(TEIS);
+ ADM8211_INT(FBE);
+ ADM8211_INT(REIS);
+ ADM8211_INT(GPTT);
+ ADM8211_INT(RPS);
+ ADM8211_INT(RDU);
+ ADM8211_INT(TUF);
+ /*ADM8211_INT(TRT);*/
+ /*ADM8211_INT(TLT);*/
+ /*ADM8211_INT(TDU);*/
+ ADM8211_INT(TPS);
+
+ return IRQ_HANDLED;
+
+#undef ADM8211_INT
+}
+
+#define WRITE_SYN(name,v_mask,v_shift,a_mask,a_shift,bits,prewrite,postwrite)\
+static void adm8211_rf_write_syn_ ## name (struct ieee80211_hw *dev, \
+ u16 addr, u32 value) { \
+ struct adm8211_priv *priv = dev->priv; \
+ unsigned int i; \
+ u32 reg, bitbuf; \
+ \
+ value &= v_mask; \
+ addr &= a_mask; \
+ bitbuf = (value << v_shift) | (addr << a_shift); \
+ \
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_1); \
+ ADM8211_CSR_READ(SYNRF); \
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ \
+ if (prewrite) { \
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_WRITE_SYNDATA_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ \
+ for (i = 0; i <= bits; i++) { \
+ if (bitbuf & (1 << (bits - i))) \
+ reg = ADM8211_SYNRF_WRITE_SYNDATA_1; \
+ else \
+ reg = ADM8211_SYNRF_WRITE_SYNDATA_0; \
+ \
+ ADM8211_CSR_WRITE(SYNRF, reg); \
+ ADM8211_CSR_READ(SYNRF); \
+ \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_1); \
+ ADM8211_CSR_READ(SYNRF); \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ \
+ if (postwrite == 1) { \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ if (postwrite == 2) { \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_1); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ \
+ ADM8211_CSR_WRITE(SYNRF, 0); \
+ ADM8211_CSR_READ(SYNRF); \
+}
+
+WRITE_SYN(max2820, 0x00FFF, 0, 0x0F, 12, 15, 1, 1)
+WRITE_SYN(al2210l, 0xFFFFF, 4, 0x0F, 0, 23, 1, 1)
+WRITE_SYN(rfmd2958, 0x3FFFF, 0, 0x1F, 18, 23, 0, 1)
+WRITE_SYN(rfmd2948, 0x0FFFF, 4, 0x0F, 0, 21, 0, 2)
+
+#undef WRITE_SYN
+
+static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int timeout;
+ u32 reg;
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = ADM8211_CSR_READ(BBPCTL);
+ if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD)))
+ break;
+ timeout--;
+ msleep(2);
+ }
+
+ if (timeout == 0) {
+ printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
+ " prewrite (reg=0x%08x)\n",
+ wiphy_name(dev->wiphy), addr, data, reg);
+ return -ETIMEDOUT;
+ }
+
+ switch (priv->bbp_type) {
+ case ADM8211_TYPE_INTERSIL:
+ reg = ADM8211_BBPCTL_MMISEL; /* three wire interface */
+ break;
+ case ADM8211_TYPE_RFMD:
+ reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+ (0x01 << 18);
+ break;
+ case ADM8211_TYPE_ADMTEK:
+ reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+ (0x05 << 18);
+ break;
+ }
+ reg |= ADM8211_BBPCTL_WR | (addr << 8) | data;
+
+ ADM8211_CSR_WRITE(BBPCTL, reg);
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = ADM8211_CSR_READ(BBPCTL);
+ if (!(reg & ADM8211_BBPCTL_WR))
+ break;
+ timeout--;
+ msleep(2);
+ }
+
+ if (timeout == 0) {
+ ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
+ ~ADM8211_BBPCTL_WR);
+ printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
+ " postwrite (reg=0x%08x)\n",
+ wiphy_name(dev->wiphy), addr, data, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan)
+{
+ static const u32 adm8211_rfmd2958_reg5[] =
+ {0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340,
+ 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7};
+ static const u32 adm8211_rfmd2958_reg6[] =
+ {0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000,
+ 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745};
+
+ struct adm8211_priv *priv = dev->priv;
+ u8 ant_power = priv->ant_power > 0x3F ?
+ priv->eeprom->antenna_power[chan - 1] : priv->ant_power;
+ u8 tx_power = priv->tx_power > 0x3F ?
+ priv->eeprom->tx_power[chan - 1] : priv->tx_power;
+ u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ?
+ priv->eeprom->lpf_cutoff[chan - 1] : priv->lpf_cutoff;
+ u8 lnags_thresh = priv->lnags_threshold == 0xFF ?
+ priv->eeprom->lnags_threshold[chan - 1] : priv->lnags_threshold;
+ u32 reg;
+
+ ADM8211_IDLE();
+
+ /* Program synthesizer to new channel */
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007);
+ adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033);
+
+ adm8211_rf_write_syn_rfmd2958(dev, 0x05,
+ adm8211_rfmd2958_reg5[chan - 1]);
+ adm8211_rf_write_syn_rfmd2958(dev, 0x06,
+ adm8211_rfmd2958_reg6[chan - 1]);
+ break;
+
+ case ADM8211_RFMD2948:
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF,
+ SI4126_MAIN_XINDIV2);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN,
+ SI4126_POWERDOWN_PDIB |
+ SI4126_POWERDOWN_PDRB);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV,
+ (chan == 14 ?
+ 2110 : (2033 + (chan * 5))));
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_rf_write_syn_max2820(dev, 0x3,
+ (chan == 14 ? 0x054 : (0x7 + (chan * 5))));
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_rf_write_syn_al2210l(dev, 0x0,
+ (chan == 14 ? 0x229B4 : (0x22967 + (chan * 5))));
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+ wiphy_name(dev->wiphy), priv->transceiver_type);
+ break;
+ }
+
+ /* write BBP regs */
+ if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+
+ /* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */
+ /* TODO: remove if SMC 2635W doesn't need this */
+ if (priv->transceiver_type == ADM8211_RFMD2948) {
+ reg = ADM8211_CSR_READ(GPIO);
+ reg &= 0xfffc0000;
+ reg |= ADM8211_CSR_GPIO_EN0;
+ if (chan != 14)
+ reg |= ADM8211_CSR_GPIO_O0;
+ ADM8211_CSR_WRITE(GPIO, reg);
+ }
+
+ if (priv->transceiver_type == ADM8211_RFMD2958) {
+ /* set PCNT2 */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100);
+ /* set PCNT1 P_DESIRED/MID_BIAS */
+ reg = le16_to_cpu(priv->eeprom->cr49);
+ reg >>= 13;
+ reg <<= 15;
+ reg |= ant_power << 9;
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg);
+ /* set TXRX TX_GAIN */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 |
+ (priv->pdev->revision < ADM8211_REV_CA ? tx_power : 0));
+ } else {
+ reg = ADM8211_CSR_READ(PLCPHD);
+ reg &= 0xff00ffff;
+ reg |= tx_power << 18;
+ ADM8211_CSR_WRITE(PLCPHD, reg);
+ }
+
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF |
+ ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(30);
+
+ /* RF3000 BBP */
+ if (priv->transceiver_type != ADM8211_RFMD2958)
+ adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT,
+ tx_power<<2);
+ adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff);
+ adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh);
+ adm8211_write_bbp(dev, 0x1c, priv->pdev->revision == ADM8211_REV_BA ?
+ priv->eeprom->cr28 : 0);
+ adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+
+ ADM8211_CSR_WRITE(SYNRF, 0);
+
+ /* Nothing to do for ADMtek BBP */
+ } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK)
+ printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+ wiphy_name(dev->wiphy), priv->bbp_type);
+
+ ADM8211_RESTORE();
+
+ /* update current channel for adhoc (and maybe AP mode) */
+ reg = ADM8211_CSR_READ(CAP0);
+ reg &= ~0xF;
+ reg |= chan;
+ ADM8211_CSR_WRITE(CAP0, reg);
+
+ return 0;
+}
+
+static void adm8211_update_mode(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ ADM8211_IDLE();
+
+ priv->soft_rx_crc = 0;
+ switch (priv->mode) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
+ priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
+
+ /* don't trust the error bits on rev 0x20 and up in adhoc */
+ if (priv->pdev->revision >= ADM8211_REV_BA)
+ priv->soft_rx_crc = 1;
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
+ priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
+ break;
+ }
+
+ ADM8211_RESTORE();
+}
+
+static void adm8211_hw_init_syn(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ /* comments taken from ADMtek vendor driver */
+
+ /* Reset RF2958 after power on */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000);
+ /* Initialize RF VCO Core Bias to maximum */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F);
+ /* Initialize IF PLL */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03);
+ /* Initialize IF PLL Coarse Tuning */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F);
+ /* Initialize RF PLL */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403);
+ /* Initialize RF PLL Coarse Tuning */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F);
+ /* Initialize TX gain and filter BW (R9) */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x09,
+ (priv->transceiver_type == ADM8211_RFMD2958 ?
+ 0x10050 : 0x00050));
+ /* Initialize CAL register */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E);
+ adm8211_rf_write_syn_max2820(dev, 0x2, 0x001);
+ adm8211_rf_write_syn_max2820(dev, 0x3, 0x054);
+ adm8211_rf_write_syn_max2820(dev, 0x4, 0x310);
+ adm8211_rf_write_syn_max2820(dev, 0x5, 0x000);
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C);
+ adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB);
+ adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F);
+ adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9);
+ adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280);
+ adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641);
+ adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130);
+ adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000);
+ adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F);
+ adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C);
+ adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000);
+ adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000);
+ break;
+
+ case ADM8211_RFMD2948:
+ default:
+ break;
+ }
+}
+
+static int adm8211_hw_init_bbp(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ /* write addresses */
+ if (priv->bbp_type == ADM8211_TYPE_INTERSIL) {
+ ADM8211_CSR_WRITE(MMIWA, 0x100E0C0A);
+ ADM8211_CSR_WRITE(MMIRD0, 0x00007C7E);
+ ADM8211_CSR_WRITE(MMIRD1, 0x00100000);
+ } else if (priv->bbp_type == ADM8211_TYPE_RFMD ||
+ priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+ /* check specific BBP type */
+ switch (priv->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+ case ADM8211_BBP_RFMD3002:
+ ADM8211_CSR_WRITE(MMIWA, 0x00009101);
+ ADM8211_CSR_WRITE(MMIRD0, 0x00000301);
+ break;
+
+ case ADM8211_BBP_ADM8011:
+ ADM8211_CSR_WRITE(MMIWA, 0x00008903);
+ ADM8211_CSR_WRITE(MMIRD0, 0x00001716);
+
+ reg = ADM8211_CSR_READ(BBPCTL);
+ reg &= ~ADM8211_BBPCTL_TYPE;
+ reg |= 0x5 << 18;
+ ADM8211_CSR_WRITE(BBPCTL, reg);
+ break;
+ }
+
+ switch (priv->pdev->revision) {
+ case ADM8211_REV_CA:
+ if (priv->transceiver_type == ADM8211_RFMD2958 ||
+ priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+ priv->transceiver_type == ADM8211_RFMD2948)
+ ADM8211_CSR_WRITE(SYNCTL, 0x1 << 22);
+ else if (priv->transceiver_type == ADM8211_MAX2820 ||
+ priv->transceiver_type == ADM8211_AL2210L)
+ ADM8211_CSR_WRITE(SYNCTL, 0x3 << 22);
+ break;
+
+ case ADM8211_REV_BA:
+ reg = ADM8211_CSR_READ(MMIRD1);
+ reg &= 0x0000FFFF;
+ reg |= 0x7e100000;
+ ADM8211_CSR_WRITE(MMIRD1, reg);
+ break;
+
+ case ADM8211_REV_AB:
+ case ADM8211_REV_AF:
+ default:
+ ADM8211_CSR_WRITE(MMIRD1, 0x7e100000);
+ break;
+ }
+
+ /* For RFMD */
+ ADM8211_CSR_WRITE(MACTEST, 0x800);
+ }
+
+ adm8211_hw_init_syn(dev);
+
+ /* Set RF Power control IF pin to PE1+PHYRST# */
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF |
+ ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(20);
+
+ /* write BBP regs */
+ if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+ /* RF3000 BBP */
+ /* another set:
+ * 11: c8
+ * 14: 14
+ * 15: 50 (chan 1..13; chan 14: d0)
+ * 1c: 00
+ * 1d: 84
+ */
+ adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80);
+ /* antenna selection: diversity */
+ adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80);
+ adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74);
+ adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38);
+ adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40);
+
+ if (priv->eeprom->major_version < 2) {
+ adm8211_write_bbp(dev, 0x1c, 0x00);
+ adm8211_write_bbp(dev, 0x1d, 0x80);
+ } else {
+ if (priv->pdev->revision == ADM8211_REV_BA)
+ adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28);
+ else
+ adm8211_write_bbp(dev, 0x1c, 0x00);
+
+ adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+ }
+ } else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+ /* reset baseband */
+ adm8211_write_bbp(dev, 0x00, 0xFF);
+ /* antenna selection: diversity */
+ adm8211_write_bbp(dev, 0x07, 0x0A);
+
+ /* TODO: find documentation for this */
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x09, 0x00);
+ adm8211_write_bbp(dev, 0x0a, 0x00);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x00);
+ adm8211_write_bbp(dev, 0x0f, 0xAA);
+ adm8211_write_bbp(dev, 0x10, 0x8c);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x40);
+ adm8211_write_bbp(dev, 0x20, 0x23);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x28);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x28, 0x35);
+ adm8211_write_bbp(dev, 0x2a, 0x8c);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x2d, 0x0A);
+ adm8211_write_bbp(dev, 0x29, 0x40);
+ adm8211_write_bbp(dev, 0x60, 0x08);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x09, 0x05);
+ adm8211_write_bbp(dev, 0x0a, 0x02);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x0f);
+ adm8211_write_bbp(dev, 0x0f, 0x55);
+ adm8211_write_bbp(dev, 0x10, 0x8d);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x4a);
+ adm8211_write_bbp(dev, 0x20, 0x20);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x23);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x2a, 0x8c);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x29, 0x4a);
+ adm8211_write_bbp(dev, 0x60, 0x2b);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x07, 0x05);
+ adm8211_write_bbp(dev, 0x08, 0x03);
+ adm8211_write_bbp(dev, 0x09, 0x00);
+ adm8211_write_bbp(dev, 0x0a, 0x00);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x10);
+ adm8211_write_bbp(dev, 0x0f, 0x55);
+ adm8211_write_bbp(dev, 0x10, 0x8d);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x4a);
+ adm8211_write_bbp(dev, 0x20, 0x20);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x23);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x2a, 0xaa);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x29, 0xfa);
+ adm8211_write_bbp(dev, 0x60, 0x2d);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_RFMD2948:
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: unsupported transceiver %d\n",
+ wiphy_name(dev->wiphy), priv->transceiver_type);
+ break;
+ }
+ } else
+ printk(KERN_DEBUG "%s: unsupported BBP %d\n",
+ wiphy_name(dev->wiphy), priv->bbp_type);
+
+ ADM8211_CSR_WRITE(SYNRF, 0);
+
+ /* Set RF CAL control source to MAC control */
+ reg = ADM8211_CSR_READ(SYNCTL);
+ reg |= ADM8211_SYNCTL_SELCAL;
+ ADM8211_CSR_WRITE(SYNCTL, reg);
+
+ return 0;
+}
+
+/* configures hw beacons/probe responses */
+static int adm8211_set_rate(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+ int i = 0;
+ u8 rate_buf[12] = {0};
+
+ /* write supported rates */
+ if (priv->pdev->revision != ADM8211_REV_BA) {
+ rate_buf[0] = ARRAY_SIZE(adm8211_rates);
+ for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
+ rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80;
+ } else {
+ /* workaround for rev BA specific bug */
+ rate_buf[0] = 0x04;
+ rate_buf[1] = 0x82;
+ rate_buf[2] = 0x04;
+ rate_buf[3] = 0x0b;
+ rate_buf[4] = 0x16;
+ }
+
+ adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf,
+ ARRAY_SIZE(adm8211_rates) + 1);
+
+ reg = ADM8211_CSR_READ(PLCPHD) & 0x00FFFFFF; /* keep bits 0-23 */
+ reg |= 1 << 15; /* short preamble */
+ reg |= 110 << 24;
+ ADM8211_CSR_WRITE(PLCPHD, reg);
+
+ /* MTMLT = 512 TU (max TX MSDU lifetime)
+ * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate)
+ * SRTYLIM = 224 (short retry limit, TX header value is default) */
+ ADM8211_CSR_WRITE(TXLMT, (512 << 16) | (110 << 8) | (224 << 0));
+
+ return 0;
+}
+
+static void adm8211_hw_init(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+ u8 cline;
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
+ reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
+ reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
+
+ if (!pci_set_mwi(priv->pdev)) {
+ reg |= 0x1 << 24;
+ pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline);
+
+ switch (cline) {
+ case 0x8: reg |= (0x1 << 14);
+ break;
+ case 0x16: reg |= (0x2 << 14);
+ break;
+ case 0x32: reg |= (0x3 << 14);
+ break;
+ default: reg |= (0x0 << 14);
+ break;
+ }
+ }
+
+ ADM8211_CSR_WRITE(PAR, reg);
+
+ reg = ADM8211_CSR_READ(CSR_TEST1);
+ reg &= ~(0xF << 28);
+ reg |= (1 << 28) | (1 << 31);
+ ADM8211_CSR_WRITE(CSR_TEST1, reg);
+
+ /* lose link after 4 lost beacons */
+ reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE;
+ ADM8211_CSR_WRITE(WCSR, reg);
+
+ /* Disable APM, enable receive FIFO threshold, and set drain receive
+ * threshold to store-and-forward */
+ reg = ADM8211_CSR_READ(CMDR);
+ reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT);
+ reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF;
+ ADM8211_CSR_WRITE(CMDR, reg);
+
+ adm8211_set_rate(dev);
+
+ /* 4-bit values:
+ * PWR1UP = 8 * 2 ms
+ * PWR0PAPE = 8 us or 5 us
+ * PWR1PAPE = 1 us or 3 us
+ * PWR0TRSW = 5 us
+ * PWR1TRSW = 12 us
+ * PWR0PE2 = 13 us
+ * PWR1PE2 = 1 us
+ * PWR0TXPE = 8 or 6 */
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ ADM8211_CSR_WRITE(TOFS2, 0x8815cd18);
+ else
+ ADM8211_CSR_WRITE(TOFS2, 0x8535cd16);
+
+ /* Enable store and forward for transmit */
+ priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB;
+ ADM8211_CSR_WRITE(NAR, priv->nar);
+
+ /* Reset RF */
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_RADIO);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(10);
+ ADM8211_CSR_WRITE(SYNRF, 0);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(5);
+
+ /* Set CFP Max Duration to 0x10 TU */
+ reg = ADM8211_CSR_READ(CFPP);
+ reg &= ~(0xffff << 8);
+ reg |= 0x0010 << 8;
+ ADM8211_CSR_WRITE(CFPP, reg);
+
+ /* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us
+ * TUCNT = 0x3ff - Tu counter 1024 us */
+ ADM8211_CSR_WRITE(TOFS0, (0x16 << 24) | 0x3ff);
+
+ /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us),
+ * DIFS=50 us, EIFS=100 us */
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) |
+ (50 << 9) | 100);
+ else
+ ADM8211_CSR_WRITE(IFST, (20 << 23) | (24 << 15) |
+ (50 << 9) | 100);
+
+ /* PCNT = 1 (MAC idle time awake/sleep, unit S)
+ * RMRD = 2346 * 8 + 1 us (max RX duration) */
+ ADM8211_CSR_WRITE(RMD, (1 << 16) | 18769);
+
+ /* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */
+ ADM8211_CSR_WRITE(RSPT, 0xffffff00);
+
+ /* Initialize BBP (and SYN) */
+ adm8211_hw_init_bbp(dev);
+
+ /* make sure interrupts are off */
+ ADM8211_CSR_WRITE(IER, 0);
+
+ /* ACK interrupts */
+ ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR));
+
+ /* Setup WEP (turns it off for now) */
+ reg = ADM8211_CSR_READ(MACTEST);
+ reg &= ~(7 << 20);
+ ADM8211_CSR_WRITE(MACTEST, reg);
+
+ reg = ADM8211_CSR_READ(WEPCTL);
+ reg &= ~ADM8211_WEPCTL_WEPENABLE;
+ reg |= ADM8211_WEPCTL_WEPRXBYP;
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+
+ /* Clear the missed-packet counter. */
+ ADM8211_CSR_READ(LPC);
+}
+
+static int adm8211_hw_reset(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg, tmp;
+ int timeout = 100;
+
+ /* Power-on issue */
+ /* TODO: check if this is necessary */
+ ADM8211_CSR_WRITE(FRCTL, 0);
+
+ /* Reset the chip */
+ tmp = ADM8211_CSR_READ(PAR);
+ ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR);
+
+ while ((ADM8211_CSR_READ(PAR) & ADM8211_PAR_SWR) && timeout--)
+ msleep(50);
+
+ if (timeout <= 0)
+ return -ETIMEDOUT;
+
+ ADM8211_CSR_WRITE(PAR, tmp);
+
+ if (priv->pdev->revision == ADM8211_REV_BA &&
+ (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+ priv->transceiver_type == ADM8211_RFMD2958)) {
+ reg = ADM8211_CSR_READ(CSR_TEST1);
+ reg |= (1 << 4) | (1 << 5);
+ ADM8211_CSR_WRITE(CSR_TEST1, reg);
+ } else if (priv->pdev->revision == ADM8211_REV_CA) {
+ reg = ADM8211_CSR_READ(CSR_TEST1);
+ reg &= ~((1 << 4) | (1 << 5));
+ ADM8211_CSR_WRITE(CSR_TEST1, reg);
+ }
+
+ ADM8211_CSR_WRITE(FRCTL, 0);
+
+ reg = ADM8211_CSR_READ(CSR_TEST0);
+ reg |= ADM8211_CSR_TEST0_EPRLD; /* EEPROM Recall */
+ ADM8211_CSR_WRITE(CSR_TEST0, reg);
+
+ adm8211_clear_sram(dev);
+
+ return 0;
+}
+
+static u64 adm8211_get_tsft(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 tsftl;
+ u64 tsft;
+
+ tsftl = ADM8211_CSR_READ(TSFTL);
+ tsft = ADM8211_CSR_READ(TSFTH);
+ tsft <<= 32;
+ tsft |= tsftl;
+
+ return tsft;
+}
+
+static void adm8211_set_interval(struct ieee80211_hw *dev,
+ unsigned short bi, unsigned short li)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ /* BP (beacon interval) = data->beacon_interval
+ * LI (listen interval) = data->listen_interval (in beacon intervals) */
+ reg = (bi << 16) | li;
+ ADM8211_CSR_WRITE(BPLI, reg);
+}
+
+static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ ADM8211_CSR_WRITE(BSSID0, le32_to_cpu(*(__le32 *)bssid));
+ reg = ADM8211_CSR_READ(ABDA1);
+ reg &= 0x0000ffff;
+ reg |= (bssid[4] << 16) | (bssid[5] << 24);
+ ADM8211_CSR_WRITE(ABDA1, reg);
+}
+
+static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u8 buf[36];
+
+ if (ssid_len > 32)
+ return -EINVAL;
+
+ memset(buf, 0, sizeof(buf));
+ buf[0] = ssid_len;
+ memcpy(buf + 1, ssid, ssid_len);
+ adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
+ /* TODO: configure beacon for adhoc? */
+ return 0;
+}
+
+static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ if (conf->channel != priv->channel) {
+ priv->channel = conf->channel;
+ adm8211_rf_set_channel(dev, priv->channel);
+ }
+
+ return 0;
+}
+
+static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
+ adm8211_set_bssid(dev, conf->bssid);
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ }
+
+ if (conf->ssid_len != priv->ssid_len ||
+ memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
+ adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
+ priv->ssid_len = conf->ssid_len;
+ memcpy(priv->ssid, conf->ssid, conf->ssid_len);
+ }
+
+ return 0;
+}
+
+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int bit_nr, new_flags;
+ u32 mc_filter[2];
+ int i;
+
+ new_flags = 0;
+
+ if (*total_flags & FIF_PROMISC_IN_BSS) {
+ new_flags |= FIF_PROMISC_IN_BSS;
+ priv->nar |= ADM8211_NAR_PR;
+ priv->nar &= ~ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ new_flags |= FIF_ALLMULTI;
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else {
+ priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+ }
+
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ if (priv->nar & ADM8211_NAR_PR)
+ dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ else
+ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ adm8211_set_bssid(dev, bcast);
+ else
+ adm8211_set_bssid(dev, priv->bssid);
+
+ ADM8211_RESTORE();
+
+ *total_flags = new_flags;
+}
+
+static int adm8211_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->mode = conf->type;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ADM8211_IDLE();
+
+ ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
+ ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+
+ adm8211_update_mode(dev);
+
+ ADM8211_RESTORE();
+
+ return 0;
+}
+
+static void adm8211_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+}
+
+static int adm8211_init_rings(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ struct adm8211_desc *desc = NULL;
+ struct adm8211_rx_ring_info *rx_info;
+ struct adm8211_tx_ring_info *tx_info;
+ unsigned int i;
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ desc = &priv->rx_ring[i];
+ desc->status = 0;
+ desc->length = cpu_to_le32(RX_PKT_SIZE);
+ priv->rx_buffers[i].skb = NULL;
+ }
+ /* Mark the end of RX ring; hw returns to base address after this
+ * descriptor */
+ desc->length |= cpu_to_le32(RDES1_CONTROL_RER);
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ desc = &priv->rx_ring[i];
+ rx_info = &priv->rx_buffers[i];
+
+ rx_info->skb = dev_alloc_skb(RX_PKT_SIZE);
+ if (rx_info->skb == NULL)
+ break;
+ rx_info->mapping = pci_map_single(priv->pdev,
+ skb_tail_pointer(rx_info->skb),
+ RX_PKT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ desc->buffer1 = cpu_to_le32(rx_info->mapping);
+ desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL);
+ }
+
+ /* Setup TX ring. TX buffers descriptors will be filled in as needed */
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ desc = &priv->tx_ring[i];
+ tx_info = &priv->tx_buffers[i];
+
+ tx_info->skb = NULL;
+ tx_info->mapping = 0;
+ desc->status = 0;
+ }
+ desc->length = cpu_to_le32(TDES1_CONTROL_TER);
+
+ priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0;
+ ADM8211_CSR_WRITE(RDB, priv->rx_ring_dma);
+ ADM8211_CSR_WRITE(TDBD, priv->tx_ring_dma);
+
+ return 0;
+}
+
+static void adm8211_free_rings(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ if (!priv->rx_buffers[i].skb)
+ continue;
+
+ pci_unmap_single(
+ priv->pdev,
+ priv->rx_buffers[i].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+
+ dev_kfree_skb(priv->rx_buffers[i].skb);
+ }
+
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ if (!priv->tx_buffers[i].skb)
+ continue;
+
+ pci_unmap_single(priv->pdev,
+ priv->tx_buffers[i].mapping,
+ priv->tx_buffers[i].skb->len,
+ PCI_DMA_TODEVICE);
+
+ dev_kfree_skb(priv->tx_buffers[i].skb);
+ }
+}
+
+static int adm8211_start(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ int retval;
+
+ /* Power up MAC and RF chips */
+ retval = adm8211_hw_reset(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: hardware reset failed\n",
+ wiphy_name(dev->wiphy));
+ goto fail;
+ }
+
+ retval = adm8211_init_rings(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to initialize rings\n",
+ wiphy_name(dev->wiphy));
+ goto fail;
+ }
+
+ /* Init hardware */
+ adm8211_hw_init(dev);
+ adm8211_rf_set_channel(dev, priv->channel);
+
+ retval = request_irq(priv->pdev->irq, &adm8211_interrupt,
+ IRQF_SHARED, "adm8211", dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to register IRQ handler\n",
+ wiphy_name(dev->wiphy));
+ goto fail;
+ }
+
+ ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE |
+ ADM8211_IER_RCIE | ADM8211_IER_TCIE |
+ ADM8211_IER_TDUIE | ADM8211_IER_GPTIE);
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+ adm8211_update_mode(dev);
+ ADM8211_CSR_WRITE(RDR, 0);
+
+ adm8211_set_interval(dev, 100, 10);
+ return 0;
+
+fail:
+ return retval;
+}
+
+static void adm8211_stop(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->nar = 0;
+ ADM8211_CSR_WRITE(NAR, 0);
+ ADM8211_CSR_WRITE(IER, 0);
+ ADM8211_CSR_READ(NAR);
+
+ free_irq(priv->pdev->irq, dev);
+
+ adm8211_free_rings(dev);
+}
+
+static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,
+ int plcp_signal, int short_preamble)
+{
+ /* Alternative calculation from NetBSD: */
+
+/* IEEE 802.11b durations for DSSS PHY in microseconds */
+#define IEEE80211_DUR_DS_LONG_PREAMBLE 144
+#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72
+#define IEEE80211_DUR_DS_FAST_PLCPHDR 24
+#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48
+#define IEEE80211_DUR_DS_SLOW_ACK 112
+#define IEEE80211_DUR_DS_FAST_ACK 56
+#define IEEE80211_DUR_DS_SLOW_CTS 112
+#define IEEE80211_DUR_DS_FAST_CTS 56
+#define IEEE80211_DUR_DS_SLOT 20
+#define IEEE80211_DUR_DS_SIFS 10
+
+ int remainder;
+
+ *dur = (80 * (24 + payload_len) + plcp_signal - 1)
+ / plcp_signal;
+
+ if (plcp_signal <= PLCP_SIGNAL_2M)
+ /* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */
+ *dur += 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) +
+ IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK;
+ else
+ /* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */
+ *dur += 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) +
+ IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK;
+
+ /* lengthen duration if long preamble */
+ if (!short_preamble)
+ *dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+ IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+ 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+ IEEE80211_DUR_DS_FAST_PLCPHDR);
+
+
+ *plcp = (80 * len) / plcp_signal;
+ remainder = (80 * len) % plcp_signal;
+ if (plcp_signal == PLCP_SIGNAL_11M &&
+ remainder <= 30 && remainder > 0)
+ *plcp = (*plcp | 0x8000) + 1;
+ else if (remainder)
+ (*plcp)++;
+}
+
+/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
+static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
+ u16 plcp_signal,
+ struct ieee80211_tx_control *control,
+ size_t hdrlen)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned long flags;
+ dma_addr_t mapping;
+ unsigned int entry;
+ u32 flag;
+
+ mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
+ flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+ else
+ flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+
+ if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2)
+ ieee80211_stop_queue(dev, 0);
+
+ entry = priv->cur_tx % priv->tx_ring_size;
+
+ priv->tx_buffers[entry].skb = skb;
+ priv->tx_buffers[entry].mapping = mapping;
+ memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
+ priv->tx_buffers[entry].hdrlen = hdrlen;
+ priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
+
+ if (entry == priv->tx_ring_size - 1)
+ flag |= TDES1_CONTROL_TER;
+ priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len);
+
+ /* Set TX rate (SIGNAL field in PLCP PPDU format) */
+ flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */;
+ priv->tx_ring[entry].status = cpu_to_le32(flag);
+
+ priv->cur_tx++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Trigger transmit poll */
+ ADM8211_CSR_WRITE(TDR, 0);
+}
+
+/* Put adm8211_tx_hdr on skb and transmit */
+static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct adm8211_tx_hdr *txhdr;
+ u16 fc;
+ size_t payload_len, hdrlen;
+ int plcp, dur, len, plcp_signal, short_preamble;
+ struct ieee80211_hdr *hdr;
+
+ if (control->tx_rate < 0) {
+ short_preamble = 1;
+ plcp_signal = -control->tx_rate;
+ } else {
+ short_preamble = 0;
+ plcp_signal = control->tx_rate;
+ }
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
+ hdrlen = ieee80211_get_hdrlen(fc);
+ memcpy(skb->cb, skb->data, hdrlen);
+ hdr = (struct ieee80211_hdr *)skb->cb;
+ skb_pull(skb, hdrlen);
+ payload_len = skb->len;
+
+ txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));
+ memset(txhdr, 0, sizeof(*txhdr));
+ memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN);
+ txhdr->signal = plcp_signal;
+ txhdr->frame_body_size = cpu_to_le16(payload_len);
+ txhdr->frame_control = hdr->frame_control;
+
+ len = hdrlen + payload_len + FCS_LEN;
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ len += 8;
+
+ txhdr->frag = cpu_to_le16(0x0FFF);
+ adm8211_calc_durations(&dur, &plcp, payload_len,
+ len, plcp_signal, short_preamble);
+ txhdr->plcp_frag_head_len = cpu_to_le16(plcp);
+ txhdr->plcp_frag_tail_len = cpu_to_le16(plcp);
+ txhdr->dur_frag_head = cpu_to_le16(dur);
+ txhdr->dur_frag_tail = cpu_to_le16(dur);
+
+ txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER);
+
+ if (short_preamble)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
+
+ if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
+
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
+
+ txhdr->retry_limit = control->retry_limit;
+
+ adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);
+
+ return NETDEV_TX_OK;
+}
+
+static int adm8211_alloc_rings(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int ring_size;
+
+ priv->rx_buffers = kmalloc(sizeof(*priv->rx_buffers) * priv->rx_ring_size +
+ sizeof(*priv->tx_buffers) * priv->tx_ring_size, GFP_KERNEL);
+ if (!priv->rx_buffers)
+ return -ENOMEM;
+
+ priv->tx_buffers = (void *)priv->rx_buffers +
+ sizeof(*priv->rx_buffers) * priv->rx_ring_size;
+
+ /* Allocate TX/RX descriptors */
+ ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size;
+ priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size,
+ &priv->rx_ring_dma);
+
+ if (!priv->rx_ring) {
+ kfree(priv->rx_buffers);
+ priv->rx_buffers = NULL;
+ priv->tx_buffers = NULL;
+ return -ENOMEM;
+ }
+
+ priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring +
+ priv->rx_ring_size);
+ priv->tx_ring_dma = priv->rx_ring_dma +
+ sizeof(struct adm8211_desc) * priv->rx_ring_size;
+
+ return 0;
+}
+
+static const struct ieee80211_ops adm8211_ops = {
+ .tx = adm8211_tx,
+ .start = adm8211_start,
+ .stop = adm8211_stop,
+ .add_interface = adm8211_add_interface,
+ .remove_interface = adm8211_remove_interface,
+ .config = adm8211_config,
+ .config_interface = adm8211_config_interface,
+ .configure_filter = adm8211_configure_filter,
+ .get_stats = adm8211_get_stats,
+ .get_tx_stats = adm8211_get_tx_stats,
+ .get_tsf = adm8211_get_tsft
+};
+
+static int __devinit adm8211_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct ieee80211_hw *dev;
+ struct adm8211_priv *priv;
+ unsigned long mem_addr, mem_len;
+ unsigned int io_addr, io_len;
+ int err;
+ u32 reg;
+ u8 perm_addr[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ io_addr = pci_resource_start(pdev, 0);
+ io_len = pci_resource_len(pdev, 0);
+ mem_addr = pci_resource_start(pdev, 1);
+ mem_len = pci_resource_len(pdev, 1);
+ if (io_len < 256 || mem_len < 1024) {
+ printk(KERN_ERR "%s (adm8211): Too short PCI resources\n",
+ pci_name(pdev));
+ goto err_disable_pdev;
+ }
+
+
+ /* check signature */
+ pci_read_config_dword(pdev, 0x80 /* CR32 */, &reg);
+ if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) {
+ printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n",
+ pci_name(pdev), reg);
+ goto err_disable_pdev;
+ }
+
+ err = pci_request_regions(pdev, "adm8211");
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n",
+ pci_name(pdev));
+ return err; /* someone else grabbed it? don't disable it */
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR "%s (adm8211): No suitable DMA available\n",
+ pci_name(pdev));
+ goto err_free_reg;
+ }
+
+ pci_set_master(pdev);
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), &adm8211_ops);
+ if (!dev) {
+ printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_free_reg;
+ }
+ priv = dev->priv;
+ priv->pdev = pdev;
+
+ spin_lock_init(&priv->lock);
+
+ SET_IEEE80211_DEV(dev, &pdev->dev);
+
+ pci_set_drvdata(pdev, dev);
+
+ priv->map = pci_iomap(pdev, 1, mem_len);
+ if (!priv->map)
+ priv->map = pci_iomap(pdev, 0, io_len);
+
+ if (!priv->map) {
+ printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",
+ pci_name(pdev));
+ goto err_free_dev;
+ }
+
+ priv->rx_ring_size = rx_ring_size;
+ priv->tx_ring_size = tx_ring_size;
+
+ if (adm8211_alloc_rings(dev)) {
+ printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n",
+ pci_name(pdev));
+ goto err_iounmap;
+ }
+
+ *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0));
+ *(u16 *)&perm_addr[4] =
+ le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF);
+
+ if (!is_valid_ether_addr(perm_addr)) {
+ printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n",
+ pci_name(pdev));
+ random_ether_addr(perm_addr);
+ }
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+
+ dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
+ dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+ /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+
+ dev->channel_change_time = 1000;
+ dev->max_rssi = 100; /* FIXME: find better value */
+
+ priv->modes[0].mode = MODE_IEEE80211B;
+ /* channel info filled in by adm8211_read_eeprom */
+ memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
+ priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
+ priv->modes[0].rates = priv->rates;
+
+ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
+
+ priv->retry_limit = 3;
+ priv->ant_power = 0x40;
+ priv->tx_power = 0x40;
+ priv->lpf_cutoff = 0xFF;
+ priv->lnags_threshold = 0xFF;
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+
+ /* Power-on issue. EEPROM won't read correctly without */
+ if (pdev->revision >= ADM8211_REV_BA) {
+ ADM8211_CSR_WRITE(FRCTL, 0);
+ ADM8211_CSR_READ(FRCTL);
+ ADM8211_CSR_WRITE(FRCTL, 1);
+ ADM8211_CSR_READ(FRCTL);
+ msleep(100);
+ }
+
+ err = adm8211_read_eeprom(dev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Can't alloc eeprom buffer\n",
+ pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ priv->channel = priv->modes[0].channels[0].chan;
+
+ err = ieee80211_register_hwmode(dev, &priv->modes[0]);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Can't register hwmode\n",
+ pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot register device\n",
+ pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n",
+ wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+ pdev->revision);
+
+ return 0;
+
+ err_free_desc:
+ pci_free_consistent(pdev,
+ sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size,
+ priv->rx_ring, priv->rx_ring_dma);
+ kfree(priv->rx_buffers);
+
+ err_iounmap:
+ pci_iounmap(pdev, priv->map);
+
+ err_free_dev:
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(dev);
+
+ err_free_reg:
+ pci_release_regions(pdev);
+
+ err_disable_pdev:
+ pci_disable_device(pdev);
+ return err;
+}
+
+
+static void __devexit adm8211_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+
+ priv = dev->priv;
+
+ pci_free_consistent(pdev,
+ sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size,
+ priv->rx_ring, priv->rx_ring_dma);
+
+ kfree(priv->rx_buffers);
+ kfree(priv->eeprom);
+ pci_iounmap(pdev, priv->map);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(dev);
+}
+
+
+#ifdef CONFIG_PM
+static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv = dev->priv;
+
+ if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+ ieee80211_stop_queues(dev);
+ adm8211_stop(dev);
+ }
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int adm8211_resume(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv = dev->priv;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+ adm8211_start(dev);
+ ieee80211_start_queues(dev);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table);
+
+/* TODO: implement enable_wake */
+static struct pci_driver adm8211_driver = {
+ .name = "adm8211",
+ .id_table = adm8211_pci_id_table,
+ .probe = adm8211_probe,
+ .remove = __devexit_p(adm8211_remove),
+#ifdef CONFIG_PM
+ .suspend = adm8211_suspend,
+ .resume = adm8211_resume,
+#endif /* CONFIG_PM */
+};
+
+
+
+static int __init adm8211_init(void)
+{
+ return pci_register_driver(&adm8211_driver);
+}
+
+
+static void __exit adm8211_exit(void)
+{
+ pci_unregister_driver(&adm8211_driver);
+}
+
+
+module_init(adm8211_init);
+module_exit(adm8211_exit);
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
new file mode 100644
index 000000000000..ef326fed42e4
--- /dev/null
+++ b/drivers/net/wireless/adm8211.h
@@ -0,0 +1,656 @@
+#ifndef ADM8211_H
+#define ADM8211_H
+
+/* ADM8211 Registers */
+
+/* CR32 (SIG) signature */
+#define ADM8211_SIG1 0x82011317 /* ADM8211A */
+#define ADM8211_SIG2 0x82111317 /* ADM8211B/ADM8211C */
+
+#define ADM8211_CSR_READ(r) ioread32(&priv->map->r)
+#define ADM8211_CSR_WRITE(r, val) iowrite32((val), &priv->map->r)
+
+/* CSR (Host Control and Status Registers) */
+struct adm8211_csr {
+ __le32 PAR; /* 0x00 CSR0 */
+ __le32 FRCTL; /* 0x04 CSR0A */
+ __le32 TDR; /* 0x08 CSR1 */
+ __le32 WTDP; /* 0x0C CSR1A */
+ __le32 RDR; /* 0x10 CSR2 */
+ __le32 WRDP; /* 0x14 CSR2A */
+ __le32 RDB; /* 0x18 CSR3 */
+ __le32 TDBH; /* 0x1C CSR3A */
+ __le32 TDBD; /* 0x20 CSR4 */
+ __le32 TDBP; /* 0x24 CSR4A */
+ __le32 STSR; /* 0x28 CSR5 */
+ __le32 TDBB; /* 0x2C CSR5A */
+ __le32 NAR; /* 0x30 CSR6 */
+ __le32 CSR6A; /* reserved */
+ __le32 IER; /* 0x38 CSR7 */
+ __le32 TKIPSCEP; /* 0x3C CSR7A */
+ __le32 LPC; /* 0x40 CSR8 */
+ __le32 CSR_TEST1; /* 0x44 CSR8A */
+ __le32 SPR; /* 0x48 CSR9 */
+ __le32 CSR_TEST0; /* 0x4C CSR9A */
+ __le32 WCSR; /* 0x50 CSR10 */
+ __le32 WPDR; /* 0x54 CSR10A */
+ __le32 GPTMR; /* 0x58 CSR11 */
+ __le32 GPIO; /* 0x5C CSR11A */
+ __le32 BBPCTL; /* 0x60 CSR12 */
+ __le32 SYNCTL; /* 0x64 CSR12A */
+ __le32 PLCPHD; /* 0x68 CSR13 */
+ __le32 MMIWA; /* 0x6C CSR13A */
+ __le32 MMIRD0; /* 0x70 CSR14 */
+ __le32 MMIRD1; /* 0x74 CSR14A */
+ __le32 TXBR; /* 0x78 CSR15 */
+ __le32 SYNDATA; /* 0x7C CSR15A */
+ __le32 ALCS; /* 0x80 CSR16 */
+ __le32 TOFS2; /* 0x84 CSR17 */
+ __le32 CMDR; /* 0x88 CSR18 */
+ __le32 PCIC; /* 0x8C CSR19 */
+ __le32 PMCSR; /* 0x90 CSR20 */
+ __le32 PAR0; /* 0x94 CSR21 */
+ __le32 PAR1; /* 0x98 CSR22 */
+ __le32 MAR0; /* 0x9C CSR23 */
+ __le32 MAR1; /* 0xA0 CSR24 */
+ __le32 ATIMDA0; /* 0xA4 CSR25 */
+ __le32 ABDA1; /* 0xA8 CSR26 */
+ __le32 BSSID0; /* 0xAC CSR27 */
+ __le32 TXLMT; /* 0xB0 CSR28 */
+ __le32 MIBCNT; /* 0xB4 CSR29 */
+ __le32 BCNT; /* 0xB8 CSR30 */
+ __le32 TSFTH; /* 0xBC CSR31 */
+ __le32 TSC; /* 0xC0 CSR32 */
+ __le32 SYNRF; /* 0xC4 CSR33 */
+ __le32 BPLI; /* 0xC8 CSR34 */
+ __le32 CAP0; /* 0xCC CSR35 */
+ __le32 CAP1; /* 0xD0 CSR36 */
+ __le32 RMD; /* 0xD4 CSR37 */
+ __le32 CFPP; /* 0xD8 CSR38 */
+ __le32 TOFS0; /* 0xDC CSR39 */
+ __le32 TOFS1; /* 0xE0 CSR40 */
+ __le32 IFST; /* 0xE4 CSR41 */
+ __le32 RSPT; /* 0xE8 CSR42 */
+ __le32 TSFTL; /* 0xEC CSR43 */
+ __le32 WEPCTL; /* 0xF0 CSR44 */
+ __le32 WESK; /* 0xF4 CSR45 */
+ __le32 WEPCNT; /* 0xF8 CSR46 */
+ __le32 MACTEST; /* 0xFC CSR47 */
+ __le32 FER; /* 0x100 */
+ __le32 FEMR; /* 0x104 */
+ __le32 FPSR; /* 0x108 */
+ __le32 FFER; /* 0x10C */
+} __attribute__ ((packed));
+
+/* CSR0 - PAR (PCI Address Register) */
+#define ADM8211_PAR_MWIE (1 << 24)
+#define ADM8211_PAR_MRLE (1 << 23)
+#define ADM8211_PAR_MRME (1 << 21)
+#define ADM8211_PAR_RAP ((1 << 18) | (1 << 17))
+#define ADM8211_PAR_CAL ((1 << 15) | (1 << 14))
+#define ADM8211_PAR_PBL 0x00003f00
+#define ADM8211_PAR_BLE (1 << 7)
+#define ADM8211_PAR_DSL 0x0000007c
+#define ADM8211_PAR_BAR (1 << 1)
+#define ADM8211_PAR_SWR (1 << 0)
+
+/* CSR1 - FRCTL (Frame Control Register) */
+#define ADM8211_FRCTL_PWRMGT (1 << 31)
+#define ADM8211_FRCTL_MAXPSP (1 << 27)
+#define ADM8211_FRCTL_DRVPRSP (1 << 26)
+#define ADM8211_FRCTL_DRVBCON (1 << 25)
+#define ADM8211_FRCTL_AID 0x0000ffff
+#define ADM8211_FRCTL_AID_ON 0x0000c000
+
+/* CSR5 - STSR (Status Register) */
+#define ADM8211_STSR_PCF (1 << 31)
+#define ADM8211_STSR_BCNTC (1 << 30)
+#define ADM8211_STSR_GPINT (1 << 29)
+#define ADM8211_STSR_LinkOff (1 << 28)
+#define ADM8211_STSR_ATIMTC (1 << 27)
+#define ADM8211_STSR_TSFTF (1 << 26)
+#define ADM8211_STSR_TSCZ (1 << 25)
+#define ADM8211_STSR_LinkOn (1 << 24)
+#define ADM8211_STSR_SQL (1 << 23)
+#define ADM8211_STSR_WEPTD (1 << 22)
+#define ADM8211_STSR_ATIME (1 << 21)
+#define ADM8211_STSR_TBTT (1 << 20)
+#define ADM8211_STSR_NISS (1 << 16)
+#define ADM8211_STSR_AISS (1 << 15)
+#define ADM8211_STSR_TEIS (1 << 14)
+#define ADM8211_STSR_FBE (1 << 13)
+#define ADM8211_STSR_REIS (1 << 12)
+#define ADM8211_STSR_GPTT (1 << 11)
+#define ADM8211_STSR_RPS (1 << 8)
+#define ADM8211_STSR_RDU (1 << 7)
+#define ADM8211_STSR_RCI (1 << 6)
+#define ADM8211_STSR_TUF (1 << 5)
+#define ADM8211_STSR_TRT (1 << 4)
+#define ADM8211_STSR_TLT (1 << 3)
+#define ADM8211_STSR_TDU (1 << 2)
+#define ADM8211_STSR_TPS (1 << 1)
+#define ADM8211_STSR_TCI (1 << 0)
+
+/* CSR6 - NAR (Network Access Register) */
+#define ADM8211_NAR_TXCF (1 << 31)
+#define ADM8211_NAR_HF (1 << 30)
+#define ADM8211_NAR_UTR (1 << 29)
+#define ADM8211_NAR_SQ (1 << 28)
+#define ADM8211_NAR_CFP (1 << 27)
+#define ADM8211_NAR_SF (1 << 21)
+#define ADM8211_NAR_TR ((1 << 15) | (1 << 14))
+#define ADM8211_NAR_ST (1 << 13)
+#define ADM8211_NAR_OM ((1 << 11) | (1 << 10))
+#define ADM8211_NAR_MM (1 << 7)
+#define ADM8211_NAR_PR (1 << 6)
+#define ADM8211_NAR_EA (1 << 5)
+#define ADM8211_NAR_PB (1 << 3)
+#define ADM8211_NAR_STPDMA (1 << 2)
+#define ADM8211_NAR_SR (1 << 1)
+#define ADM8211_NAR_CTX (1 << 0)
+
+#define ADM8211_IDLE() \
+do { \
+ if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) { \
+ ADM8211_CSR_WRITE(NAR, priv->nar & \
+ ~(ADM8211_NAR_SR | ADM8211_NAR_ST));\
+ ADM8211_CSR_READ(NAR); \
+ msleep(20); \
+ } \
+} while (0)
+
+#define ADM8211_IDLE_RX() \
+do { \
+ if (priv->nar & ADM8211_NAR_SR) { \
+ ADM8211_CSR_WRITE(NAR, priv->nar & ~ADM8211_NAR_SR); \
+ ADM8211_CSR_READ(NAR); \
+ mdelay(20); \
+ } \
+} while (0)
+
+#define ADM8211_RESTORE() \
+do { \
+ if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) \
+ ADM8211_CSR_WRITE(NAR, priv->nar); \
+} while (0)
+
+/* CSR7 - IER (Interrupt Enable Register) */
+#define ADM8211_IER_PCFIE (1 << 31)
+#define ADM8211_IER_BCNTCIE (1 << 30)
+#define ADM8211_IER_GPIE (1 << 29)
+#define ADM8211_IER_LinkOffIE (1 << 28)
+#define ADM8211_IER_ATIMTCIE (1 << 27)
+#define ADM8211_IER_TSFTFIE (1 << 26)
+#define ADM8211_IER_TSCZE (1 << 25)
+#define ADM8211_IER_LinkOnIE (1 << 24)
+#define ADM8211_IER_SQLIE (1 << 23)
+#define ADM8211_IER_WEPIE (1 << 22)
+#define ADM8211_IER_ATIMEIE (1 << 21)
+#define ADM8211_IER_TBTTIE (1 << 20)
+#define ADM8211_IER_NIE (1 << 16)
+#define ADM8211_IER_AIE (1 << 15)
+#define ADM8211_IER_TEIE (1 << 14)
+#define ADM8211_IER_FBEIE (1 << 13)
+#define ADM8211_IER_REIE (1 << 12)
+#define ADM8211_IER_GPTIE (1 << 11)
+#define ADM8211_IER_RSIE (1 << 8)
+#define ADM8211_IER_RUIE (1 << 7)
+#define ADM8211_IER_RCIE (1 << 6)
+#define ADM8211_IER_TUIE (1 << 5)
+#define ADM8211_IER_TRTIE (1 << 4)
+#define ADM8211_IER_TLTTIE (1 << 3)
+#define ADM8211_IER_TDUIE (1 << 2)
+#define ADM8211_IER_TPSIE (1 << 1)
+#define ADM8211_IER_TCIE (1 << 0)
+
+/* CSR9 - SPR (Serial Port Register) */
+#define ADM8211_SPR_SRS (1 << 11)
+#define ADM8211_SPR_SDO (1 << 3)
+#define ADM8211_SPR_SDI (1 << 2)
+#define ADM8211_SPR_SCLK (1 << 1)
+#define ADM8211_SPR_SCS (1 << 0)
+
+/* CSR9A - CSR_TEST0 */
+#define ADM8211_CSR_TEST0_EPNE (1 << 18)
+#define ADM8211_CSR_TEST0_EPSNM (1 << 17)
+#define ADM8211_CSR_TEST0_EPTYP (1 << 16)
+#define ADM8211_CSR_TEST0_EPRLD (1 << 15)
+
+/* CSR10 - WCSR (Wake-up Control/Status Register) */
+#define ADM8211_WCSR_CRCT (1 << 30)
+#define ADM8211_WCSR_TSFTWE (1 << 20)
+#define ADM8211_WCSR_TIMWE (1 << 19)
+#define ADM8211_WCSR_ATIMWE (1 << 18)
+#define ADM8211_WCSR_KEYWE (1 << 17)
+#define ADM8211_WCSR_MPRE (1 << 9)
+#define ADM8211_WCSR_LSOE (1 << 8)
+#define ADM8211_WCSR_KEYUP (1 << 6)
+#define ADM8211_WCSR_TSFTW (1 << 5)
+#define ADM8211_WCSR_TIMW (1 << 4)
+#define ADM8211_WCSR_ATIMW (1 << 3)
+#define ADM8211_WCSR_MPR (1 << 1)
+#define ADM8211_WCSR_LSO (1 << 0)
+
+/* CSR11A - GPIO */
+#define ADM8211_CSR_GPIO_EN5 (1 << 17)
+#define ADM8211_CSR_GPIO_EN4 (1 << 16)
+#define ADM8211_CSR_GPIO_EN3 (1 << 15)
+#define ADM8211_CSR_GPIO_EN2 (1 << 14)
+#define ADM8211_CSR_GPIO_EN1 (1 << 13)
+#define ADM8211_CSR_GPIO_EN0 (1 << 12)
+#define ADM8211_CSR_GPIO_O5 (1 << 11)
+#define ADM8211_CSR_GPIO_O4 (1 << 10)
+#define ADM8211_CSR_GPIO_O3 (1 << 9)
+#define ADM8211_CSR_GPIO_O2 (1 << 8)
+#define ADM8211_CSR_GPIO_O1 (1 << 7)
+#define ADM8211_CSR_GPIO_O0 (1 << 6)
+#define ADM8211_CSR_GPIO_IN 0x0000003f
+
+/* CSR12 - BBPCTL (BBP Control port) */
+#define ADM8211_BBPCTL_MMISEL (1 << 31)
+#define ADM8211_BBPCTL_SPICADD (0x7F << 24)
+#define ADM8211_BBPCTL_RF3000 (0x20 << 24)
+#define ADM8211_BBPCTL_TXCE (1 << 23)
+#define ADM8211_BBPCTL_RXCE (1 << 22)
+#define ADM8211_BBPCTL_CCAP (1 << 21)
+#define ADM8211_BBPCTL_TYPE 0x001c0000
+#define ADM8211_BBPCTL_WR (1 << 17)
+#define ADM8211_BBPCTL_RD (1 << 16)
+#define ADM8211_BBPCTL_ADDR 0x0000ff00
+#define ADM8211_BBPCTL_DATA 0x000000ff
+
+/* CSR12A - SYNCTL (Synthesizer Control port) */
+#define ADM8211_SYNCTL_WR (1 << 31)
+#define ADM8211_SYNCTL_RD (1 << 30)
+#define ADM8211_SYNCTL_CS0 (1 << 29)
+#define ADM8211_SYNCTL_CS1 (1 << 28)
+#define ADM8211_SYNCTL_CAL (1 << 27)
+#define ADM8211_SYNCTL_SELCAL (1 << 26)
+#define ADM8211_SYNCTL_RFtype ((1 << 24) || (1 << 23) || (1 << 22))
+#define ADM8211_SYNCTL_RFMD (1 << 22)
+#define ADM8211_SYNCTL_GENERAL (0x7 << 22)
+/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */
+
+/* CSR18 - CMDR (Command Register) */
+#define ADM8211_CMDR_PM (1 << 19)
+#define ADM8211_CMDR_APM (1 << 18)
+#define ADM8211_CMDR_RTE (1 << 4)
+#define ADM8211_CMDR_DRT ((1 << 3) | (1 << 2))
+#define ADM8211_CMDR_DRT_8DW (0x0 << 2)
+#define ADM8211_CMDR_DRT_16DW (0x1 << 2)
+#define ADM8211_CMDR_DRT_SF (0x2 << 2)
+
+/* CSR33 - SYNRF (SYNRF direct control) */
+#define ADM8211_SYNRF_SELSYN (1 << 31)
+#define ADM8211_SYNRF_SELRF (1 << 30)
+#define ADM8211_SYNRF_LERF (1 << 29)
+#define ADM8211_SYNRF_LEIF (1 << 28)
+#define ADM8211_SYNRF_SYNCLK (1 << 27)
+#define ADM8211_SYNRF_SYNDATA (1 << 26)
+#define ADM8211_SYNRF_PE1 (1 << 25)
+#define ADM8211_SYNRF_PE2 (1 << 24)
+#define ADM8211_SYNRF_PA_PE (1 << 23)
+#define ADM8211_SYNRF_TR_SW (1 << 22)
+#define ADM8211_SYNRF_TR_SWN (1 << 21)
+#define ADM8211_SYNRF_RADIO (1 << 20)
+#define ADM8211_SYNRF_CAL_EN (1 << 19)
+#define ADM8211_SYNRF_PHYRST (1 << 18)
+
+#define ADM8211_SYNRF_IF_SELECT_0 (1 << 31)
+#define ADM8211_SYNRF_IF_SELECT_1 ((1 << 31) | (1 << 28))
+#define ADM8211_SYNRF_WRITE_SYNDATA_0 (1 << 31)
+#define ADM8211_SYNRF_WRITE_SYNDATA_1 ((1 << 31) | (1 << 26))
+#define ADM8211_SYNRF_WRITE_CLOCK_0 (1 << 31)
+#define ADM8211_SYNRF_WRITE_CLOCK_1 ((1 << 31) | (1 << 27))
+
+/* CSR44 - WEPCTL (WEP Control) */
+#define ADM8211_WEPCTL_WEPENABLE (1 << 31)
+#define ADM8211_WEPCTL_WPAENABLE (1 << 30)
+#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29)
+#define ADM8211_WEPCTL_TABLE_WR (1 << 28)
+#define ADM8211_WEPCTL_TABLE_RD (1 << 27)
+#define ADM8211_WEPCTL_WEPRXBYP (1 << 25)
+#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23)
+#define ADM8211_WEPCTL_ADDR (0x000001ff)
+
+/* CSR45 - WESK (Data Entry for Share/Individual Key) */
+#define ADM8211_WESK_DATA (0x0000ffff)
+
+/* FER (Function Event Register) */
+#define ADM8211_FER_INTR_EV_ENT (1 << 15)
+
+
+/* Si4126 RF Synthesizer - Control Registers */
+#define SI4126_MAIN_CONF 0
+#define SI4126_PHASE_DET_GAIN 1
+#define SI4126_POWERDOWN 2
+#define SI4126_RF1_N_DIV 3 /* only Si4136 */
+#define SI4126_RF2_N_DIV 4
+#define SI4126_IF_N_DIV 5
+#define SI4126_RF1_R_DIV 6 /* only Si4136 */
+#define SI4126_RF2_R_DIV 7
+#define SI4126_IF_R_DIV 8
+
+/* Main Configuration */
+#define SI4126_MAIN_XINDIV2 (1 << 6)
+#define SI4126_MAIN_IFDIV ((1 << 11) | (1 << 10))
+/* Powerdown */
+#define SI4126_POWERDOWN_PDIB (1 << 1)
+#define SI4126_POWERDOWN_PDRB (1 << 0)
+
+
+/* RF3000 BBP - Control Port Registers */
+/* 0x00 - reserved */
+#define RF3000_MODEM_CTRL__RX_STATUS 0x01
+#define RF3000_CCA_CTRL 0x02
+#define RF3000_DIVERSITY__RSSI 0x03
+#define RF3000_RX_SIGNAL_FIELD 0x04
+#define RF3000_RX_LEN_MSB 0x05
+#define RF3000_RX_LEN_LSB 0x06
+#define RF3000_RX_SERVICE_FIELD 0x07
+#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11
+#define RF3000_TX_LEN_MSB 0x12
+#define RF3000_TX_LEN_LSB 0x13
+#define RF3000_LOW_GAIN_CALIB 0x14
+#define RF3000_HIGH_GAIN_CALIB 0x15
+
+/* ADM8211 revisions */
+#define ADM8211_REV_AB 0x11
+#define ADM8211_REV_AF 0x15
+#define ADM8211_REV_BA 0x20
+#define ADM8211_REV_CA 0x30
+
+struct adm8211_desc {
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2;
+};
+
+#define RDES0_STATUS_OWN (1 << 31)
+#define RDES0_STATUS_ES (1 << 30)
+#define RDES0_STATUS_SQL (1 << 29)
+#define RDES0_STATUS_DE (1 << 28)
+#define RDES0_STATUS_FS (1 << 27)
+#define RDES0_STATUS_LS (1 << 26)
+#define RDES0_STATUS_PCF (1 << 25)
+#define RDES0_STATUS_SFDE (1 << 24)
+#define RDES0_STATUS_SIGE (1 << 23)
+#define RDES0_STATUS_CRC16E (1 << 22)
+#define RDES0_STATUS_RXTOE (1 << 21)
+#define RDES0_STATUS_CRC32E (1 << 20)
+#define RDES0_STATUS_ICVE (1 << 19)
+#define RDES0_STATUS_DA1 (1 << 17)
+#define RDES0_STATUS_DA0 (1 << 16)
+#define RDES0_STATUS_RXDR ((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12))
+#define RDES0_STATUS_FL (0x00000fff)
+
+#define RDES1_CONTROL_RER (1 << 25)
+#define RDES1_CONTROL_RCH (1 << 24)
+#define RDES1_CONTROL_RBS2 (0x00fff000)
+#define RDES1_CONTROL_RBS1 (0x00000fff)
+
+#define RDES1_STATUS_RSSI (0x0000007f)
+
+
+#define TDES0_CONTROL_OWN (1 << 31)
+#define TDES0_CONTROL_DONE (1 << 30)
+#define TDES0_CONTROL_TXDR (0x0ff00000)
+
+#define TDES0_STATUS_OWN (1 << 31)
+#define TDES0_STATUS_DONE (1 << 30)
+#define TDES0_STATUS_ES (1 << 29)
+#define TDES0_STATUS_TLT (1 << 28)
+#define TDES0_STATUS_TRT (1 << 27)
+#define TDES0_STATUS_TUF (1 << 26)
+#define TDES0_STATUS_TRO (1 << 25)
+#define TDES0_STATUS_SOFBR (1 << 24)
+#define TDES0_STATUS_ACR (0x00000fff)
+
+#define TDES1_CONTROL_IC (1 << 31)
+#define TDES1_CONTROL_LS (1 << 30)
+#define TDES1_CONTROL_FS (1 << 29)
+#define TDES1_CONTROL_TER (1 << 25)
+#define TDES1_CONTROL_TCH (1 << 24)
+#define TDES1_CONTROL_RBS2 (0x00fff000)
+#define TDES1_CONTROL_RBS1 (0x00000fff)
+
+/* SRAM offsets */
+#define ADM8211_SRAM(x) (priv->pdev->revision < ADM8211_REV_BA ? \
+ ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x)
+
+#define ADM8211_SRAM_INDIV_KEY 0x0000
+#define ADM8211_SRAM_A_SHARE_KEY 0x0160
+#define ADM8211_SRAM_B_SHARE_KEY 0x00c0
+
+#define ADM8211_SRAM_A_SSID 0x0180
+#define ADM8211_SRAM_B_SSID 0x00d4
+#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID)
+
+#define ADM8211_SRAM_A_SUPP_RATE 0x0191
+#define ADM8211_SRAM_B_SUPP_RATE 0x00dd
+#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE)
+
+#define ADM8211_SRAM_A_SIZE 0x0200
+#define ADM8211_SRAM_B_SIZE 0x01c0
+#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE)
+
+struct adm8211_rx_ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+};
+
+struct adm8211_tx_ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ struct ieee80211_tx_control tx_control;
+ size_t hdrlen;
+};
+
+#define PLCP_SIGNAL_1M 0x0a
+#define PLCP_SIGNAL_2M 0x14
+#define PLCP_SIGNAL_5M5 0x37
+#define PLCP_SIGNAL_11M 0x6e
+
+struct adm8211_tx_hdr {
+ u8 da[6];
+ u8 signal; /* PLCP signal / TX rate in 100 Kbps */
+ u8 service;
+ __le16 frame_body_size;
+ __le16 frame_control;
+ __le16 plcp_frag_tail_len;
+ __le16 plcp_frag_head_len;
+ __le16 dur_frag_tail;
+ __le16 dur_frag_head;
+ u8 addr4[6];
+
+#define ADM8211_TXHDRCTL_SHORT_PREAMBLE (1 << 0)
+#define ADM8211_TXHDRCTL_MORE_FRAG (1 << 1)
+#define ADM8211_TXHDRCTL_MORE_DATA (1 << 2)
+#define ADM8211_TXHDRCTL_FRAG_NO (1 << 3) /* ? */
+#define ADM8211_TXHDRCTL_ENABLE_RTS (1 << 4)
+#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE (1 << 5)
+#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER (1 << 15) /* ? */
+ __le16 header_control;
+ __le16 frag;
+ u8 reserved_0;
+ u8 retry_limit;
+
+ u32 wep2key0;
+ u32 wep2key1;
+ u32 wep2key2;
+ u32 wep2key3;
+
+ u8 keyid;
+ u8 entry_control; // huh??
+ u16 reserved_1;
+ u32 reserved_2;
+} __attribute__ ((packed));
+
+
+#define RX_COPY_BREAK 128
+#define RX_PKT_SIZE 2500
+
+struct adm8211_eeprom {
+ __le16 signature; /* 0x00 */
+ u8 major_version; /* 0x02 */
+ u8 minor_version; /* 0x03 */
+ u8 reserved_1[4]; /* 0x04 */
+ u8 hwaddr[6]; /* 0x08 */
+ u8 reserved_2[8]; /* 0x1E */
+ __le16 cr49; /* 0x16 */
+ u8 cr03; /* 0x18 */
+ u8 cr28; /* 0x19 */
+ u8 cr29; /* 0x1A */
+ u8 country_code; /* 0x1B */
+
+/* specific bbp types */
+#define ADM8211_BBP_RFMD3000 0x00
+#define ADM8211_BBP_RFMD3002 0x01
+#define ADM8211_BBP_ADM8011 0x04
+ u8 specific_bbptype; /* 0x1C */
+ u8 specific_rftype; /* 0x1D */
+ u8 reserved_3[2]; /* 0x1E */
+ __le16 device_id; /* 0x20 */
+ __le16 vendor_id; /* 0x22 */
+ __le16 subsystem_id; /* 0x24 */
+ __le16 subsystem_vendor_id; /* 0x26 */
+ u8 maxlat; /* 0x28 */
+ u8 mingnt; /* 0x29 */
+ __le16 cis_pointer_low; /* 0x2A */
+ __le16 cis_pointer_high; /* 0x2C */
+ __le16 csr18; /* 0x2E */
+ u8 reserved_4[16]; /* 0x30 */
+ u8 d1_pwrdara; /* 0x40 */
+ u8 d0_pwrdara; /* 0x41 */
+ u8 d3_pwrdara; /* 0x42 */
+ u8 d2_pwrdara; /* 0x43 */
+ u8 antenna_power[14]; /* 0x44 */
+ __le16 cis_wordcnt; /* 0x52 */
+ u8 tx_power[14]; /* 0x54 */
+ u8 lpf_cutoff[14]; /* 0x62 */
+ u8 lnags_threshold[14]; /* 0x70 */
+ __le16 checksum; /* 0x7E */
+ u8 cis_data[0]; /* 0x80, 384 bytes */
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate adm8211_rates[] = {
+ { .rate = 10,
+ .val = 10,
+ .val2 = -10,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 20,
+ .val = 20,
+ .val2 = -20,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 55,
+ .val = 55,
+ .val2 = -55,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 110,
+ .val = 110,
+ .val2 = -110,
+ .flags = IEEE80211_RATE_CCK_2 }
+};
+
+struct ieee80211_chan_range {
+ u8 min;
+ u8 max;
+};
+
+static const struct ieee80211_channel adm8211_channels[] = {
+ { .chan = 1,
+ .freq = 2412},
+ { .chan = 2,
+ .freq = 2417},
+ { .chan = 3,
+ .freq = 2422},
+ { .chan = 4,
+ .freq = 2427},
+ { .chan = 5,
+ .freq = 2432},
+ { .chan = 6,
+ .freq = 2437},
+ { .chan = 7,
+ .freq = 2442},
+ { .chan = 8,
+ .freq = 2447},
+ { .chan = 9,
+ .freq = 2452},
+ { .chan = 10,
+ .freq = 2457},
+ { .chan = 11,
+ .freq = 2462},
+ { .chan = 12,
+ .freq = 2467},
+ { .chan = 13,
+ .freq = 2472},
+ { .chan = 14,
+ .freq = 2484},
+};
+
+struct adm8211_priv {
+ struct pci_dev *pdev;
+ spinlock_t lock;
+ struct adm8211_csr __iomem *map;
+ struct adm8211_desc *rx_ring;
+ struct adm8211_desc *tx_ring;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+ struct adm8211_rx_ring_info *rx_buffers;
+ struct adm8211_tx_ring_info *tx_buffers;
+ unsigned int rx_ring_size, tx_ring_size;
+ unsigned int cur_tx, dirty_tx, cur_rx;
+
+ struct ieee80211_low_level_stats stats;
+ struct ieee80211_hw_mode modes[1];
+ struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)];
+ struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
+ int mode;
+
+ int channel;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+
+ u8 soft_rx_crc;
+ u8 retry_limit;
+
+ u8 ant_power;
+ u8 tx_power;
+ u8 lpf_cutoff;
+ u8 lnags_threshold;
+ struct adm8211_eeprom *eeprom;
+ size_t eeprom_len;
+
+ u32 nar;
+
+#define ADM8211_TYPE_INTERSIL 0x00
+#define ADM8211_TYPE_RFMD 0x01
+#define ADM8211_TYPE_MARVEL 0x02
+#define ADM8211_TYPE_AIROHA 0x03
+#define ADM8211_TYPE_ADMTEK 0x05
+ unsigned int rf_type:3;
+ unsigned int bbp_type:3;
+
+ u8 specific_bbptype;
+ enum {
+ ADM8211_RFMD2948 = 0x0,
+ ADM8211_RFMD2958 = 0x1,
+ ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2,
+ ADM8211_MAX2820 = 0x8,
+ ADM8211_AL2210L = 0xC, /* Airoha */
+ } transceiver_type;
+};
+
+static const struct ieee80211_chan_range cranges[] = {
+ {1, 11}, /* FCC */
+ {1, 11}, /* IC */
+ {1, 13}, /* ETSI */
+ {10, 11}, /* SPAIN */
+ {10, 13}, /* FRANCE */
+ {14, 14}, /* MMK */
+ {1, 14}, /* MMK2 */
+};
+
+#endif /* ADM8211_H */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index ee1cc14db389..074055e18c5c 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -241,8 +241,8 @@ static int proc_perm = 0644;
MODULE_AUTHOR("Benjamin Reed");
MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
- cards. Direct support for ISA/PCI/MPI cards and support \
- for PCMCIA when used with airo_cs.");
+cards. Direct support for ISA/PCI/MPI cards and support \
+for PCMCIA when used with airo_cs.");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
module_param_array(io, int, NULL, 0);
@@ -2481,7 +2481,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
EXPORT_SYMBOL(stop_airo_card);
-static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
return ETH_ALEN;
@@ -2696,14 +2696,13 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
return rc;
}
+static const struct header_ops airo_header_ops = {
+ .parse = wll_header_parse,
+};
+
static void wifi_setup(struct net_device *dev)
{
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->hard_header_cache = NULL;
- dev->header_cache_update= NULL;
-
- dev->hard_header_parse = wll_header_parse;
+ dev->header_ops = &airo_header_ops;
dev->hard_start_xmit = &airo_start_xmit11;
dev->get_stats = &airo_get_stats;
dev->set_mac_address = &airo_set_mac_address;
@@ -2821,6 +2820,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
struct net_device *dev;
struct airo_info *ai;
int i, rc;
+ DECLARE_MAC_BUF(mac);
/* Create the network device object. */
dev = alloc_netdev(sizeof(*ai), "", ether_setup);
@@ -2870,7 +2870,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
dev->base_addr = port;
SET_NETDEV_DEV(dev, dmdev);
- SET_MODULE_OWNER(dev);
reset_card (dev, 1);
msleep(400);
@@ -2924,9 +2923,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
goto err_out_reg;
set_bit(FLAG_REGISTERED,&ai->flags);
- airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+ airo_print_info(dev->name, "MAC enabled %s",
+ print_mac(mac, dev->dev_addr));
/* Allocate the transmit buffers */
if (probe && !test_bit(FLAG_MPI,&ai->flags))
@@ -2983,6 +2981,7 @@ int reset_airo_card( struct net_device *dev )
{
int i;
struct airo_info *ai = dev->priv;
+ DECLARE_MAC_BUF(mac);
if (reset_card (dev, 1))
return -1;
@@ -2991,9 +2990,8 @@ int reset_airo_card( struct net_device *dev )
airo_print_err(dev->name, "MAC could not be enabled");
return -1;
}
- airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ airo_print_info(dev->name, "MAC enabled %s",
+ print_mac(mac, dev->dev_addr));
/* Allocate the transmit buffers if needed */
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
@@ -5427,6 +5425,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
int i;
char *ptr;
APListRid APList_rid;
+ DECLARE_MAC_BUF(mac);
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5450,13 +5449,8 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
// We end when we find a zero MAC
if ( !*(int*)APList_rid.ap[i] &&
!*(int*)&APList_rid.ap[i][2]) break;
- ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- (int)APList_rid.ap[i][0],
- (int)APList_rid.ap[i][1],
- (int)APList_rid.ap[i][2],
- (int)APList_rid.ap[i][3],
- (int)APList_rid.ap[i][4],
- (int)APList_rid.ap[i][5]);
+ ptr += sprintf(ptr, "%s\n",
+ print_mac(mac, APList_rid.ap[i]));
}
if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
@@ -5475,6 +5469,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
int rc;
/* If doLoseSync is not 1, we won't do a Lose Sync */
int doLoseSync = -1;
+ DECLARE_MAC_BUF(mac);
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5511,13 +5506,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
we have to add a spin lock... */
rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
while(rc == 0 && BSSList_rid.index != 0xffff) {
- ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
- (int)BSSList_rid.bssid[0],
- (int)BSSList_rid.bssid[1],
- (int)BSSList_rid.bssid[2],
- (int)BSSList_rid.bssid[3],
- (int)BSSList_rid.bssid[4],
- (int)BSSList_rid.bssid[5],
+ ptr += sprintf(ptr, "%s %*s rssi = %d",
+ print_mac(mac, BSSList_rid.bssid),
(int)BSSList_rid.ssidLen,
BSSList_rid.ssid,
(int)BSSList_rid.dBm);
@@ -7579,9 +7569,9 @@ static const iw_handler airo_private_handler[] =
static const struct iw_handler_def airo_handler_def =
{
- .num_standard = sizeof(airo_handler)/sizeof(iw_handler),
- .num_private = sizeof(airo_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(airo_handler),
+ .num_private = ARRAY_SIZE(airo_private_handler),
+ .num_private_args = ARRAY_SIZE(airo_private_args),
.standard = airo_handler,
.private = airo_private_handler,
.private_args = airo_private_args,
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 7d5b8c2cc614..6f7eb9f59223 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -197,7 +197,6 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
return -EBUSY;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
macio_set_drvdata(mdev, dev);
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index 498e8486d125..dbdfc9e39d20 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1469,10 +1469,10 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
while (dmi)
{ if (dmi->dmi_addrlen == 6)
{
+ DECLARE_MAC_BUF(mac);
if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
- printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+ printk(KERN_ERR "%s mcl %s\n",
+ dev->name, print_mac(mac, dmi->dmi_addr));
for (i = 0; i < 6; i++)
if (dmi->dmi_addr[i] != hw_dst_addr[i])
break;
@@ -1512,17 +1512,18 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
{
char immedDestAddress[6];
char immedSrcAddress[6];
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
- printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name,
- (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3],
- (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7],
- (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11],
- immedDestAddress[0], immedDestAddress[1], immedDestAddress[2],
- immedDestAddress[3], immedDestAddress[4], immedDestAddress[5],
- immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2],
- immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]);
+ printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n",
+ dev->name, print_mac(mac, skbtmp),
+ print_mac(mac2, &skbtmp[6]),
+ print_mac(mac3, immedDestAddress),
+ print_mac(mac4, immedSrcAddress));
}
skb->protocol = eth_type_trans(skb, dev);
IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
@@ -1792,8 +1793,6 @@ struct net_device * __init arlan_probe(int unit)
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
-
if (unit >= 0) {
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c
index 015abd928ab0..c6e70dbc5de8 100644
--- a/drivers/net/wireless/arlan-proc.c
+++ b/drivers/net/wireless/arlan-proc.c
@@ -435,7 +435,7 @@ static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp,
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
@@ -654,7 +654,7 @@ static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -688,7 +688,7 @@ static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -716,7 +716,7 @@ static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp
pos += sprintf(arlan_drive_info + pos, "No device found here \n");
goto final;
} else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -745,7 +745,7 @@ static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp,
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -780,7 +780,7 @@ static int arlan_configure(ctl_table * ctl, int write, struct file *filp,
}
else if (arlan_device[devnum] != NULL)
{
- priv = arlan_device[devnum]->priv;
+ priv = netdev_priv(arlan_device[devnum]);
arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF);
}
@@ -805,7 +805,7 @@ static int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp,
}
else if (arlan_device[devnum] != NULL)
{
- priv = arlan_device[devnum]->priv;
+ priv = netdev_priv(arlan_device[devnum]);
arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET);
} else
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 51a7db53afa5..059ce3f07dba 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1484,6 +1484,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
struct net_device *dev;
struct atmel_private *priv;
int rc;
+ DECLARE_MAC_BUF(mac);
/* Create the network device object. */
dev = alloc_etherdev(sizeof(*priv));
@@ -1598,12 +1599,9 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
if (!ent)
printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
- printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
- dev->name, DRIVER_MAJOR, DRIVER_MINOR,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+ printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n",
+ dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr));
- SET_MODULE_OWNER(dev);
return dev;
err_out_res:
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
new file mode 100644
index 000000000000..e3c573e56b63
--- /dev/null
+++ b/drivers/net/wireless/b43/Kconfig
@@ -0,0 +1,131 @@
+config B43
+ tristate "Broadcom 43xx wireless support (mac80211 stack)"
+ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+ select SSB
+ select FW_LOADER
+ select HW_RANDOM
+ ---help---
+ b43 is a driver for the Broadcom 43xx series wireless devices.
+
+ Check "lspci" for something like
+ "Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller"
+ to determine whether you own such a device.
+
+ This driver supports the new BCM43xx IEEE 802.11G devices, but not
+ the old IEEE 802.11B devices. Old devices are supported by
+ the b43legacy driver.
+ Note that this has nothing to do with the standard that your AccessPoint
+ supports (A, B, G or a combination).
+ IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints.
+
+ It is safe to include both b43 and b43legacy as the underlying glue
+ layer will automatically load the correct version for your device.
+
+ This driver uses V4 firmware, which must be installed separately using
+ b43-fwcutter.
+
+ This driver can be built as a module (recommended) that will be called "b43".
+ If unsure, say M.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B43_PCI_AUTOSELECT
+ bool
+ depends on B43 && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B43_PCICORE_AUTOSELECT
+ bool
+ depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B43_PCMCIA
+ bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)"
+ depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL
+ select SSB_PCMCIAHOST
+ ---help---
+ Broadcom 43xx PCMCIA device support.
+
+ Support for 16bit PCMCIA devices.
+ Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA
+ devices, but 32bit CardBUS devices. CardBUS devices are supported
+ out of the box by b43.
+
+ With this config option you can drive b43 cards in
+ CompactFlash formfactor in a PCMCIA adaptor.
+ CF b43 cards can sometimes be found in handheld PCs.
+
+ It's safe to select Y here, even if you don't have a B43 PCMCIA device.
+
+ If unsure, say N.
+
+# LED support
+config B43_LEDS
+ bool
+ depends on B43 && MAC80211_LEDS
+ default y
+
+# RFKILL support
+config B43_RFKILL
+ bool
+ depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV
+ default y
+
+config B43_DEBUG
+ bool "Broadcom 43xx debugging"
+ depends on B43
+ ---help---
+ Broadcom 43xx debugging messages.
+
+ Say Y, if you want to find out why the driver does not
+ work for you.
+
+config B43_DMA
+ bool
+ depends on B43
+config B43_PIO
+ bool
+ depends on B43
+
+choice
+ prompt "Broadcom 43xx data transfer mode"
+ depends on B43
+ default B43_DMA_AND_PIO_MODE
+
+config B43_DMA_AND_PIO_MODE
+ bool "DMA + PIO"
+ select B43_DMA
+ select B43_PIO
+ ---help---
+ Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+ data transfer modes.
+ The actually used mode is selectable through the module
+ parameter "pio". If the module parameter is pio=0, DMA is used.
+ Otherwise PIO is used. DMA is default.
+
+ If unsure, choose this option.
+
+config B43_DMA_MODE
+ bool "DMA (Direct Memory Access) only"
+ select B43_DMA
+ ---help---
+ Only include Direct Memory Access (DMA).
+ This reduces the size of the driver module, by omitting the PIO code.
+
+config B43_PIO_MODE
+ bool "PIO (Programmed I/O) only"
+ select B43_PIO
+ ---help---
+ Only include Programmed I/O (PIO).
+ This reduces the size of the driver module, by omitting the DMA code.
+ Please note that PIO transfers are slow (compared to DMA).
+
+ Also note that not all devices of the 43xx series support PIO.
+ The 4306 (Apple Airport Extreme and others) supports PIO, while
+ the 4318 is known to _not_ support PIO.
+
+ Only use PIO, if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
new file mode 100644
index 000000000000..485e59e2dfab
--- /dev/null
+++ b/drivers/net/wireless/b43/Makefile
@@ -0,0 +1,20 @@
+# b43 core
+b43-y += main.o
+b43-y += tables.o
+b43-y += phy.o
+b43-y += sysfs.o
+b43-y += xmit.o
+b43-y += lo.o
+# b43 RFKILL button support
+b43-$(CONFIG_B43_RFKILL) += rfkill.o
+# b43 LED support
+b43-$(CONFIG_B43_LEDS) += leds.o
+# b43 PCMCIA support
+b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
+# b43 debugging
+b43-$(CONFIG_B43_DEBUG) += debugfs.o
+# b43 DMA and PIO
+b43-$(CONFIG_B43_DMA) += dma.o
+b43-$(CONFIG_B43_PIO) += pio.o
+
+obj-$(CONFIG_B43) += b43.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
new file mode 100644
index 000000000000..a28ad230d63e
--- /dev/null
+++ b/drivers/net/wireless/b43/b43.h
@@ -0,0 +1,854 @@
+#ifndef B43_H_
+#define B43_H_
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/hw_random.h>
+#include <linux/ssb/ssb.h>
+#include <net/mac80211.h>
+
+#include "debugfs.h"
+#include "leds.h"
+#include "rfkill.h"
+#include "lo.h"
+#include "phy.h"
+
+#ifdef CONFIG_B43_DEBUG
+# define B43_DEBUG 1
+#else
+# define B43_DEBUG 0
+#endif
+
+#define B43_RX_MAX_SSI 60
+
+/* MMIO offsets */
+#define B43_MMIO_DMA0_REASON 0x20
+#define B43_MMIO_DMA0_IRQ_MASK 0x24
+#define B43_MMIO_DMA1_REASON 0x28
+#define B43_MMIO_DMA1_IRQ_MASK 0x2C
+#define B43_MMIO_DMA2_REASON 0x30
+#define B43_MMIO_DMA2_IRQ_MASK 0x34
+#define B43_MMIO_DMA3_REASON 0x38
+#define B43_MMIO_DMA3_IRQ_MASK 0x3C
+#define B43_MMIO_DMA4_REASON 0x40
+#define B43_MMIO_DMA4_IRQ_MASK 0x44
+#define B43_MMIO_DMA5_REASON 0x48
+#define B43_MMIO_DMA5_IRQ_MASK 0x4C
+#define B43_MMIO_MACCTL 0x120
+#define B43_MMIO_STATUS2_BITFIELD 0x124
+#define B43_MMIO_GEN_IRQ_REASON 0x128
+#define B43_MMIO_GEN_IRQ_MASK 0x12C
+#define B43_MMIO_RAM_CONTROL 0x130
+#define B43_MMIO_RAM_DATA 0x134
+#define B43_MMIO_PS_STATUS 0x140
+#define B43_MMIO_RADIO_HWENABLED_HI 0x158
+#define B43_MMIO_SHM_CONTROL 0x160
+#define B43_MMIO_SHM_DATA 0x164
+#define B43_MMIO_SHM_DATA_UNALIGNED 0x166
+#define B43_MMIO_XMITSTAT_0 0x170
+#define B43_MMIO_XMITSTAT_1 0x174
+#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
+#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+
+/* 32-bit DMA */
+#define B43_MMIO_DMA32_BASE0 0x200
+#define B43_MMIO_DMA32_BASE1 0x220
+#define B43_MMIO_DMA32_BASE2 0x240
+#define B43_MMIO_DMA32_BASE3 0x260
+#define B43_MMIO_DMA32_BASE4 0x280
+#define B43_MMIO_DMA32_BASE5 0x2A0
+/* 64-bit DMA */
+#define B43_MMIO_DMA64_BASE0 0x200
+#define B43_MMIO_DMA64_BASE1 0x240
+#define B43_MMIO_DMA64_BASE2 0x280
+#define B43_MMIO_DMA64_BASE3 0x2C0
+#define B43_MMIO_DMA64_BASE4 0x300
+#define B43_MMIO_DMA64_BASE5 0x340
+/* PIO */
+#define B43_MMIO_PIO1_BASE 0x300
+#define B43_MMIO_PIO2_BASE 0x310
+#define B43_MMIO_PIO3_BASE 0x320
+#define B43_MMIO_PIO4_BASE 0x330
+
+#define B43_MMIO_PHY_VER 0x3E0
+#define B43_MMIO_PHY_RADIO 0x3E2
+#define B43_MMIO_PHY0 0x3E6
+#define B43_MMIO_ANTENNA 0x3E8
+#define B43_MMIO_CHANNEL 0x3F0
+#define B43_MMIO_CHANNEL_EXT 0x3F4
+#define B43_MMIO_RADIO_CONTROL 0x3F6
+#define B43_MMIO_RADIO_DATA_HIGH 0x3F8
+#define B43_MMIO_RADIO_DATA_LOW 0x3FA
+#define B43_MMIO_PHY_CONTROL 0x3FC
+#define B43_MMIO_PHY_DATA 0x3FE
+#define B43_MMIO_MACFILTER_CONTROL 0x420
+#define B43_MMIO_MACFILTER_DATA 0x422
+#define B43_MMIO_RCMTA_COUNT 0x43C
+#define B43_MMIO_RADIO_HWENABLED_LO 0x49A
+#define B43_MMIO_GPIO_CONTROL 0x49C
+#define B43_MMIO_GPIO_MASK 0x49E
+#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */
+#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */
+#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
+#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
+#define B43_MMIO_RNG 0x65A
+#define B43_MMIO_POWERUP_DELAY 0x6A8
+
+/* SPROM boardflags_lo values */
+#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
+#define B43_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
+#define B43_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
+#define B43_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
+#define B43_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
+#define B43_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
+#define B43_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
+#define B43_BFL_ENETADM 0x0080 /* has ADMtek switch */
+#define B43_BFL_ENETVLAN 0x0100 /* can do vlan */
+#define B43_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
+#define B43_BFL_NOPCI 0x0400 /* leaves PCI floating */
+#define B43_BFL_FEM 0x0800 /* supports the Front End Module */
+#define B43_BFL_EXTLNA 0x1000 /* has an external LNA */
+#define B43_BFL_HGPA 0x2000 /* had high gain PA */
+#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
+#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define B43_GPIO_CONTROL 0x6c
+
+/* SHM Routing */
+enum {
+ B43_SHM_UCODE, /* Microcode memory */
+ B43_SHM_SHARED, /* Shared memory */
+ B43_SHM_SCRATCH, /* Scratch memory */
+ B43_SHM_HW, /* Internal hardware register */
+ B43_SHM_RCMTA, /* Receive match transmitter address (rev >= 5 only) */
+};
+/* SHM Routing modifiers */
+#define B43_SHM_AUTOINC_R 0x0200 /* Auto-increment address on read */
+#define B43_SHM_AUTOINC_W 0x0100 /* Auto-increment address on write */
+#define B43_SHM_AUTOINC_RW (B43_SHM_AUTOINC_R | \
+ B43_SHM_AUTOINC_W)
+
+/* Misc SHM_SHARED offsets */
+#define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
+#define B43_SHM_SH_PCTLWDPOS 0x0008
+#define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */
+#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */
+#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
+#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
+#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
+#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */
+#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
+#define B43_SHM_SH_RADAR 0x0066 /* Radar register */
+#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
+#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
+#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
+#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */
+#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
+/* SHM_SHARED TX FIFO variables */
+#define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */
+#define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */
+#define B43_SHM_SH_SIZE45 0x009C /* TX FIFO size for FIFO 4 and 5 */
+#define B43_SHM_SH_SIZE67 0x009E /* TX FIFO size for FIFO 6 and 7 */
+/* SHM_SHARED background noise */
+#define B43_SHM_SH_JSSI0 0x0088 /* Measure JSSI 0 */
+#define B43_SHM_SH_JSSI1 0x008A /* Measure JSSI 1 */
+#define B43_SHM_SH_JSSIAUX 0x008C /* Measure JSSI AUX */
+/* SHM_SHARED crypto engine */
+#define B43_SHM_SH_DEFAULTIV 0x003C /* Default IV location */
+#define B43_SHM_SH_NRRXTRANS 0x003E /* # of soft RX transmitter addresses (max 8) */
+#define B43_SHM_SH_KTP 0x0056 /* Key table pointer */
+#define B43_SHM_SH_TKIPTSCTTAK 0x0318
+#define B43_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block (v4 firmware) */
+#define B43_SHM_SH_PSM 0x05F4 /* PSM transmitter address match block (rev < 5) */
+/* SHM_SHARED WME variables */
+#define B43_SHM_SH_EDCFSTAT 0x000E /* EDCF status */
+#define B43_SHM_SH_TXFCUR 0x0030 /* TXF current index */
+#define B43_SHM_SH_EDCFQ 0x0240 /* EDCF Q info */
+/* SHM_SHARED powersave mode related */
+#define B43_SHM_SH_SLOTT 0x0010 /* Slot time */
+#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */
+#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
+/* SHM_SHARED beacon variables */
+#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
+#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
+#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
+#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
+#define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */
+#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
+#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
+/* SHM_SHARED ACK/CTS control */
+#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
+/* SHM_SHARED probe response variables */
+#define B43_SHM_SH_PRSSID 0x0160 /* Probe Response SSID */
+#define B43_SHM_SH_PRSSIDLEN 0x0048 /* Probe Response SSID length */
+#define B43_SHM_SH_PRTLEN 0x004A /* Probe Response template length */
+#define B43_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
+#define B43_SHM_SH_PRPHYCTL 0x0188 /* Probe Response PHY TX control word */
+/* SHM_SHARED rate tables */
+#define B43_SHM_SH_OFDMDIRECT 0x01C0 /* Pointer to OFDM direct map */
+#define B43_SHM_SH_OFDMBASIC 0x01E0 /* Pointer to OFDM basic rate map */
+#define B43_SHM_SH_CCKDIRECT 0x0200 /* Pointer to CCK direct map */
+#define B43_SHM_SH_CCKBASIC 0x0220 /* Pointer to CCK basic rate map */
+/* SHM_SHARED microcode soft registers */
+#define B43_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
+#define B43_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
+#define B43_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
+#define B43_SHM_SH_UCODETIME 0x0006 /* Microcode time */
+#define B43_SHM_SH_UCODESTAT 0x0040 /* Microcode debug status code */
+#define B43_SHM_SH_UCODESTAT_INVALID 0
+#define B43_SHM_SH_UCODESTAT_INIT 1
+#define B43_SHM_SH_UCODESTAT_ACTIVE 2
+#define B43_SHM_SH_UCODESTAT_SUSP 3 /* suspended */
+#define B43_SHM_SH_UCODESTAT_SLEEP 4 /* asleep (PS) */
+#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */
+#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
+#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
+
+/* SHM_SCRATCH offsets */
+#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */
+#define B43_SHM_SC_MAXCONT 0x0004 /* Maximum contention window */
+#define B43_SHM_SC_CURCONT 0x0005 /* Current contention window */
+#define B43_SHM_SC_SRLIMIT 0x0006 /* Short retry count limit */
+#define B43_SHM_SC_LRLIMIT 0x0007 /* Long retry count limit */
+#define B43_SHM_SC_DTIMC 0x0008 /* Current DTIM count */
+#define B43_SHM_SC_BTL0LEN 0x0015 /* Beacon 0 template length */
+#define B43_SHM_SC_BTL1LEN 0x0016 /* Beacon 1 template length */
+#define B43_SHM_SC_SCFB 0x0017 /* Short frame transmit count threshold for rate fallback */
+#define B43_SHM_SC_LCFB 0x0018 /* Long frame transmit count threshold for rate fallback */
+
+/* Hardware Radio Enable masks */
+#define B43_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+/* HostFlags. See b43_hf_read/write() */
+#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */
+#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
+#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */
+#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */
+#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */
+#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */
+#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */
+#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */
+#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */
+#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */
+#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */
+#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */
+#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */
+#define B43_HF_RADARW 0x00002000 /* Radar workaround */
+#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */
+#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */
+#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */
+#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */
+#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */
+#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */
+#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */
+#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */
+#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */
+#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */
+#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */
+
+/* MacFilter offsets. */
+#define B43_MACFILTER_SELF 0x0000
+#define B43_MACFILTER_BSSID 0x0003
+
+/* PowerControl */
+#define B43_PCTL_IN 0xB0
+#define B43_PCTL_OUT 0xB4
+#define B43_PCTL_OUTENABLE 0xB8
+#define B43_PCTL_XTAL_POWERUP 0x40
+#define B43_PCTL_PLL_POWERDOWN 0x80
+
+/* PowerControl Clock Modes */
+#define B43_PCTL_CLK_FAST 0x00
+#define B43_PCTL_CLK_SLOW 0x01
+#define B43_PCTL_CLK_DYNAMIC 0x02
+
+#define B43_PCTL_FORCE_SLOW 0x0800
+#define B43_PCTL_FORCE_PLL 0x1000
+#define B43_PCTL_DYN_XTAL 0x2000
+
+/* PHYVersioning */
+#define B43_PHYTYPE_A 0x00
+#define B43_PHYTYPE_B 0x01
+#define B43_PHYTYPE_G 0x02
+
+/* PHYRegisters */
+#define B43_PHY_ILT_A_CTRL 0x0072
+#define B43_PHY_ILT_A_DATA1 0x0073
+#define B43_PHY_ILT_A_DATA2 0x0074
+#define B43_PHY_G_LO_CONTROL 0x0810
+#define B43_PHY_ILT_G_CTRL 0x0472
+#define B43_PHY_ILT_G_DATA1 0x0473
+#define B43_PHY_ILT_G_DATA2 0x0474
+#define B43_PHY_A_PCTL 0x007B
+#define B43_PHY_G_PCTL 0x0029
+#define B43_PHY_A_CRS 0x0029
+#define B43_PHY_RADIO_BITFIELD 0x0401
+#define B43_PHY_G_CRS 0x0429
+#define B43_PHY_NRSSILT_CTRL 0x0803
+#define B43_PHY_NRSSILT_DATA 0x0804
+
+/* RadioRegisters */
+#define B43_RADIOCTL_ID 0x01
+
+/* MAC Control bitfield */
+#define B43_MACCTL_ENABLED 0x00000001 /* MAC Enabled */
+#define B43_MACCTL_PSM_RUN 0x00000002 /* Run Microcode */
+#define B43_MACCTL_PSM_JMP0 0x00000004 /* Microcode jump to 0 */
+#define B43_MACCTL_SHM_ENABLED 0x00000100 /* SHM Enabled */
+#define B43_MACCTL_SHM_UPPER 0x00000200 /* SHM Upper */
+#define B43_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
+#define B43_MACCTL_PSM_DBG 0x00002000 /* Microcode debugging enabled */
+#define B43_MACCTL_GPOUTSMSK 0x0000C000 /* GPOUT Select Mask */
+#define B43_MACCTL_BE 0x00010000 /* Big Endian mode */
+#define B43_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
+#define B43_MACCTL_AP 0x00040000 /* AccessPoint mode */
+#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */
+#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
+#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */
+#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
+#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
+#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
+#define B43_MACCTL_HWPS 0x02000000 /* Hardware Power Saving */
+#define B43_MACCTL_AWAKE 0x04000000 /* Device is awake */
+#define B43_MACCTL_CLOSEDNET 0x08000000 /* Closed net (no SSID bcast) */
+#define B43_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */
+#define B43_MACCTL_DISCTXSTAT 0x20000000 /* Discard TX status */
+#define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */
+#define B43_MACCTL_GMODE 0x80000000 /* G Mode */
+
+/* 802.11 core specific TM State Low flags */
+#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
+#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */
+#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */
+#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
+#define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
+
+/* 802.11 core specific TM State High flags */
+#define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */
+#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */
+#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */
+
+/* Generic-Interrupt reasons. */
+#define B43_IRQ_MAC_SUSPENDED 0x00000001
+#define B43_IRQ_BEACON 0x00000002
+#define B43_IRQ_TBTT_INDI 0x00000004
+#define B43_IRQ_BEACON_TX_OK 0x00000008
+#define B43_IRQ_BEACON_CANCEL 0x00000010
+#define B43_IRQ_ATIM_END 0x00000020
+#define B43_IRQ_PMQ 0x00000040
+#define B43_IRQ_PIO_WORKAROUND 0x00000100
+#define B43_IRQ_MAC_TXERR 0x00000200
+#define B43_IRQ_PHY_TXERR 0x00000800
+#define B43_IRQ_PMEVENT 0x00001000
+#define B43_IRQ_TIMER0 0x00002000
+#define B43_IRQ_TIMER1 0x00004000
+#define B43_IRQ_DMA 0x00008000
+#define B43_IRQ_TXFIFO_FLUSH_OK 0x00010000
+#define B43_IRQ_CCA_MEASURE_OK 0x00020000
+#define B43_IRQ_NOISESAMPLE_OK 0x00040000
+#define B43_IRQ_UCODE_DEBUG 0x08000000
+#define B43_IRQ_RFKILL 0x10000000
+#define B43_IRQ_TX_OK 0x20000000
+#define B43_IRQ_PHY_G_CHANGED 0x40000000
+#define B43_IRQ_TIMEOUT 0x80000000
+
+#define B43_IRQ_ALL 0xFFFFFFFF
+#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \
+ B43_IRQ_BEACON | \
+ B43_IRQ_TBTT_INDI | \
+ B43_IRQ_ATIM_END | \
+ B43_IRQ_PMQ | \
+ B43_IRQ_MAC_TXERR | \
+ B43_IRQ_PHY_TXERR | \
+ B43_IRQ_DMA | \
+ B43_IRQ_TXFIFO_FLUSH_OK | \
+ B43_IRQ_NOISESAMPLE_OK | \
+ B43_IRQ_UCODE_DEBUG | \
+ B43_IRQ_RFKILL | \
+ B43_IRQ_TX_OK)
+
+/* Device specific rate values.
+ * The actual values defined here are (rate_in_mbps * 2).
+ * Some code depends on this. Don't change it. */
+#define B43_CCK_RATE_1MB 0x02
+#define B43_CCK_RATE_2MB 0x04
+#define B43_CCK_RATE_5MB 0x0B
+#define B43_CCK_RATE_11MB 0x16
+#define B43_OFDM_RATE_6MB 0x0C
+#define B43_OFDM_RATE_9MB 0x12
+#define B43_OFDM_RATE_12MB 0x18
+#define B43_OFDM_RATE_18MB 0x24
+#define B43_OFDM_RATE_24MB 0x30
+#define B43_OFDM_RATE_36MB 0x48
+#define B43_OFDM_RATE_48MB 0x60
+#define B43_OFDM_RATE_54MB 0x6C
+/* Convert a b43 rate value to a rate in 100kbps */
+#define B43_RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+
+#define B43_DEFAULT_SHORT_RETRY_LIMIT 7
+#define B43_DEFAULT_LONG_RETRY_LIMIT 4
+
+/* Max size of a security key */
+#define B43_SEC_KEYSIZE 16
+/* Security algorithms. */
+enum {
+ B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+ B43_SEC_ALGO_WEP40,
+ B43_SEC_ALGO_TKIP,
+ B43_SEC_ALGO_AES,
+ B43_SEC_ALGO_WEP104,
+ B43_SEC_ALGO_AES_LEGACY,
+};
+
+struct b43_dmaring;
+struct b43_pioqueue;
+
+/* The firmware file header */
+#define B43_FW_TYPE_UCODE 'u'
+#define B43_FW_TYPE_PCM 'p'
+#define B43_FW_TYPE_IV 'i'
+struct b43_fw_header {
+ /* File type */
+ u8 type;
+ /* File format version */
+ u8 ver;
+ u8 __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is number-of-ivs. */
+ __be32 size;
+} __attribute__((__packed__));
+
+/* Initial Value file format */
+#define B43_IV_OFFSET_MASK 0x7FFF
+#define B43_IV_32BIT 0x8000
+struct b43_iv {
+ __be16 offset_size;
+ union {
+ __be16 d16;
+ __be32 d32;
+ } data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+
+#define B43_PHYMODE(phytype) (1 << (phytype))
+#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A)
+#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B)
+#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G)
+
+struct b43_phy {
+ /* Possible PHYMODEs on this PHY */
+ u8 possible_phymodes;
+ /* GMODE bit enabled? */
+ bool gmode;
+ /* Possible ieee80211 subsystem hwmodes for this PHY.
+ * Which mode is selected, depends on thr GMODE enabled bit */
+#define B43_MAX_PHYHWMODES 2
+ struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
+
+ /* Analog Type */
+ u8 analog;
+ /* B43_PHYTYPE_ */
+ u8 type;
+ /* PHY revision number. */
+ u8 rev;
+
+ /* Radio versioning */
+ u16 radio_manuf; /* Radio manufacturer */
+ u16 radio_ver; /* Radio version */
+ u8 radio_rev; /* Radio revision */
+
+ bool locked; /* Only used in b43_phy_{un}lock() */
+ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
+
+ /* ACI (adjacent channel interference) flags. */
+ bool aci_enable;
+ bool aci_wlan_automatic;
+ bool aci_hw_rssi;
+
+ /* Radio switched on/off */
+ bool radio_on;
+ struct {
+ /* Values saved when turning the radio off.
+ * They are needed when turning it on again. */
+ bool valid;
+ u16 rfover;
+ u16 rfoverval;
+ } radio_off_context;
+
+ u16 minlowsig[2];
+ u16 minlowsigpos[2];
+
+ /* TSSI to dBm table in use */
+ const s8 *tssi2dbm;
+ /* Target idle TSSI */
+ int tgt_idle_tssi;
+ /* Current idle TSSI */
+ int cur_idle_tssi;
+
+ /* LocalOscillator control values. */
+ struct b43_txpower_lo_control *lo_control;
+ /* Values from b43_calc_loopback_gain() */
+ s16 max_lb_gain; /* Maximum Loopback gain in hdB */
+ s16 trsw_rx_gain; /* TRSW RX gain in hdB */
+ s16 lna_lod_gain; /* LNA lod */
+ s16 lna_gain; /* LNA */
+ s16 pga_gain; /* PGA */
+
+ /* PHY lock for core.rev < 3
+ * This lock is only used by b43_phy_{un}lock()
+ */
+ spinlock_t lock;
+
+ /* Desired TX power level (in dBm).
+ * This is set by the user and adjusted in b43_phy_xmitpower(). */
+ u8 power_level;
+ /* A-PHY TX Power control value. */
+ u16 txpwr_offset;
+
+ /* Current TX power level attenuation control values */
+ struct b43_bbatt bbatt;
+ struct b43_rfatt rfatt;
+ u8 tx_control; /* B43_TXCTL_XXX */
+#ifdef CONFIG_B43_DEBUG
+ bool manual_txpower_control; /* Manual TX-power control enabled? */
+#endif
+ /* Hardware Power Control enabled? */
+ bool hardware_power_control;
+
+ /* Current Interference Mitigation mode */
+ int interfmode;
+ /* Stack of saved values from the Interference Mitigation code.
+ * Each value in the stack is layed out as follows:
+ * bit 0-11: offset
+ * bit 12-15: register ID
+ * bit 16-32: value
+ * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+ */
+#define B43_INTERFSTACK_SIZE 26
+ u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
+
+ /* Saved values from the NRSSI Slope calculation */
+ s16 nrssi[2];
+ s32 nrssislope;
+ /* In memory nrssi lookup table. */
+ s8 nrssi_lt[64];
+
+ /* current channel */
+ u8 channel;
+
+ u16 lofcal;
+
+ u16 initval; //FIXME rename?
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct b43_dma {
+ struct b43_dmaring *tx_ring0;
+ struct b43_dmaring *tx_ring1;
+ struct b43_dmaring *tx_ring2;
+ struct b43_dmaring *tx_ring3;
+ struct b43_dmaring *tx_ring4;
+ struct b43_dmaring *tx_ring5;
+
+ struct b43_dmaring *rx_ring0;
+ struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct b43_pio {
+ struct b43_pioqueue *queue0;
+ struct b43_pioqueue *queue1;
+ struct b43_pioqueue *queue2;
+ struct b43_pioqueue *queue3;
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct b43_noise_calculation {
+ u8 channel_at_start;
+ bool calculation_running;
+ u8 nr_samples;
+ s8 samples[8][4];
+};
+
+struct b43_stats {
+ u8 link_noise;
+ /* Store the last TX/RX times here for updating the leds. */
+ unsigned long last_tx;
+ unsigned long last_rx;
+};
+
+struct b43_key {
+ /* If keyconf is NULL, this key is disabled.
+ * keyconf is a cookie. Don't derefenrence it outside of the set_key
+ * path, because b43 doesn't own it. */
+ struct ieee80211_key_conf *keyconf;
+ u8 algorithm;
+};
+
+struct b43_wldev;
+
+/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
+struct b43_wl {
+ /* Pointer to the active wireless device on this chip */
+ struct b43_wldev *current_dev;
+ /* Pointer to the ieee80211 hardware data structure */
+ struct ieee80211_hw *hw;
+
+ spinlock_t irq_lock;
+ struct mutex mutex;
+ spinlock_t leds_lock;
+
+ /* We can only have one operating interface (802.11 core)
+ * at a time. General information about this interface follows.
+ */
+
+ /* Opaque ID of the operating interface from the ieee80211
+ * subsystem. Do not modify.
+ */
+ int if_id;
+ /* The MAC address of the operating interface. */
+ u8 mac_addr[ETH_ALEN];
+ /* Current BSSID */
+ u8 bssid[ETH_ALEN];
+ /* Interface type. (IEEE80211_IF_TYPE_XXX) */
+ int if_type;
+ /* Is the card operating in AP, STA or IBSS mode? */
+ bool operating;
+ /* filter flags */
+ unsigned int filter_flags;
+ /* Stats about the wireless interface */
+ struct ieee80211_low_level_stats ieee_stats;
+
+ struct hwrng rng;
+ u8 rng_initialized;
+ char rng_name[30 + 1];
+
+ /* The RF-kill button */
+ struct b43_rfkill rfkill;
+
+ /* List of all wireless devices on this chip */
+ struct list_head devlist;
+ u8 nr_devs;
+};
+
+/* Pointers to the firmware data and meta information about it. */
+struct b43_firmware {
+ /* Microcode */
+ const struct firmware *ucode;
+ /* PCM code */
+ const struct firmware *pcm;
+ /* Initial MMIO values for the firmware */
+ const struct firmware *initvals;
+ /* Initial MMIO values for the firmware, band-specific */
+ const struct firmware *initvals_band;
+ /* Firmware revision */
+ u16 rev;
+ /* Firmware patchlevel */
+ u16 patch;
+};
+
+/* Device (802.11 core) initialization status. */
+enum {
+ B43_STAT_UNINIT = 0, /* Uninitialized. */
+ B43_STAT_INITIALIZED = 1, /* Initialized, but not started, yet. */
+ B43_STAT_STARTED = 2, /* Up and running. */
+};
+#define b43_status(wldev) atomic_read(&(wldev)->__init_status)
+#define b43_set_status(wldev, stat) do { \
+ atomic_set(&(wldev)->__init_status, (stat)); \
+ smp_wmb(); \
+ } while (0)
+
+/* XXX--- HOW LOCKING WORKS IN B43 ---XXX
+ *
+ * You should always acquire both, wl->mutex and wl->irq_lock unless:
+ * - You don't need to acquire wl->irq_lock, if the interface is stopped.
+ * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
+ * and packet TX path (and _ONLY_ there.)
+ */
+
+/* Data structure for one wireless device (802.11 core) */
+struct b43_wldev {
+ struct ssb_device *dev;
+ struct b43_wl *wl;
+
+ /* The device initialization status.
+ * Use b43_status() to query. */
+ atomic_t __init_status;
+ /* Saved init status for handling suspend. */
+ int suspend_init_status;
+
+ bool __using_pio; /* Internal, use b43_using_pio(). */
+ bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
+ bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */
+ bool short_preamble; /* TRUE, if short preamble is enabled. */
+ bool short_slot; /* TRUE, if short slot timing is enabled. */
+ bool radio_hw_enable; /* saved state of radio hardware enabled state */
+
+ /* PHY/Radio device. */
+ struct b43_phy phy;
+ union {
+ /* DMA engines. */
+ struct b43_dma dma;
+ /* PIO engines. */
+ struct b43_pio pio;
+ };
+
+ /* Various statistics about the physical device. */
+ struct b43_stats stats;
+
+ /* The device LEDs. */
+ struct b43_led led_tx;
+ struct b43_led led_rx;
+ struct b43_led led_assoc;
+ struct b43_led led_radio;
+
+ /* Reason code of the last interrupt. */
+ u32 irq_reason;
+ u32 dma_reason[6];
+ /* saved irq enable/disable state bitfield. */
+ u32 irq_savedstate;
+ /* Link Quality calculation context. */
+ struct b43_noise_calculation noisecalc;
+ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+ int mac_suspended;
+
+ /* Interrupt Service Routine tasklet (bottom-half) */
+ struct tasklet_struct isr_tasklet;
+
+ /* Periodic tasks */
+ struct delayed_work periodic_work;
+ unsigned int periodic_state;
+
+ struct work_struct restart_work;
+
+ /* encryption/decryption */
+ u16 ktp; /* Key table pointer */
+ u8 max_nr_keys;
+ struct b43_key key[58];
+
+ /* Cached beacon template while uploading the template. */
+ struct sk_buff *cached_beacon;
+
+ /* Firmware data */
+ struct b43_firmware fw;
+
+ /* Devicelist in struct b43_wl (all 802.11 cores) */
+ struct list_head list;
+
+ /* Debugging stuff follows. */
+#ifdef CONFIG_B43_DEBUG
+ struct b43_dfsentry *dfsentry;
+#endif
+};
+
+static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
+{
+ return hw->priv;
+}
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+ return dev->__using_pio;
+}
+#elif defined(CONFIG_B43_DMA)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+ return 0;
+}
+#elif defined(CONFIG_B43_PIO)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+ return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ return ssb_get_drvdata(ssb_dev);
+}
+
+/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+static inline int b43_is_mode(struct b43_wl *wl, int type)
+{
+ return (wl->operating && wl->if_type == type);
+}
+
+static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
+{
+ return ssb_read16(dev->dev, offset);
+}
+
+static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
+{
+ ssb_write16(dev->dev, offset, value);
+}
+
+static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
+{
+ return ssb_read32(dev->dev, offset);
+}
+
+static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
+{
+ ssb_write32(dev->dev, offset, value);
+}
+
+/* Message printing */
+void b43info(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+void b43err(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+void b43warn(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+#if B43_DEBUG
+void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+#else /* DEBUG */
+# define b43dbg(wl, fmt...) do { /* nothing */ } while (0)
+#endif /* DEBUG */
+
+/* A WARN_ON variant that vanishes when b43 debugging is disabled.
+ * This _also_ evaluates the arg with debugging disabled. */
+#if B43_DEBUG
+# define B43_WARN_ON(x) WARN_ON(x)
+#else
+static inline bool __b43_warn_on_dummy(bool x) { return x; }
+# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x)))
+#endif
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max) \
+ ({ \
+ typeof(value) __value = (value); \
+ typeof(value) __min = (min); \
+ typeof(value) __max = (max); \
+ if (__value < __min) \
+ __value = __min; \
+ else if (__value > __max) \
+ __value = __max; \
+ __value; \
+ })
+
+/* Convert an integer to a Q5.2 value */
+#define INT_TO_Q52(i) ((i) << 2)
+/* Convert a Q5.2 value to an integer (precision loss!) */
+#define Q52_TO_INT(q52) ((q52) >> 2)
+/* Macros for printing a value in Q5.2 format */
+#define Q52_FMT "%u.%u"
+#define Q52_ARG(q52) Q52_TO_INT(q52), ((((q52) & 0x3) * 100) / 4)
+
+#endif /* B43_H_ */
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
new file mode 100644
index 000000000000..734e70e1a06d
--- /dev/null
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -0,0 +1,656 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ debugfs driver debugging code
+
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "b43.h"
+#include "main.h"
+#include "debugfs.h"
+#include "dma.h"
+#include "pio.h"
+#include "xmit.h"
+
+
+/* The root directory. */
+static struct dentry *rootdir;
+
+struct b43_debugfs_fops {
+ ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
+ int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
+ struct file_operations fops;
+ /* Offset of struct b43_dfs_file in struct b43_dfsentry */
+ size_t file_struct_offset;
+ /* Take wl->irq_lock before calling read/write? */
+ bool take_irqlock;
+};
+
+static inline
+struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
+ const struct b43_debugfs_fops *dfops)
+{
+ void *p;
+
+ p = dev->dfsentry;
+ p += dfops->file_struct_offset;
+
+ return p;
+}
+
+
+#define fappend(fmt, x...) \
+ do { \
+ if (bufsize - count) \
+ count += snprintf(buf + count, \
+ bufsize - count, \
+ fmt , ##x); \
+ else \
+ printk(KERN_ERR "b43: fappend overflow\n"); \
+ } while (0)
+
+
+/* wl->irq_lock is locked */
+static ssize_t tsf_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ u64 tsf;
+
+ b43_tsf_read(dev, &tsf);
+ fappend("0x%08x%08x\n",
+ (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+ (unsigned int)(tsf & 0xFFFFFFFFULL));
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43_wldev *dev,
+ const char *buf, size_t count)
+{
+ u64 tsf;
+
+ if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+ return -EINVAL;
+ b43_tsf_write(dev, tsf);
+
+ return 0;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t ucode_regs_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ fappend("r%d = 0x%04x\n", i,
+ b43_shm_read16(dev, B43_SHM_SCRATCH, i));
+ }
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t shm_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+ u16 tmp;
+ __le16 *le16buf = (__le16 *)buf;
+
+ for (i = 0; i < 0x1000; i++) {
+ if (bufsize <= 0)
+ break;
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
+ le16buf[i] = cpu_to_le16(tmp);
+ count += sizeof(tmp);
+ bufsize -= sizeof(tmp);
+ }
+
+ return count;
+}
+
+static ssize_t txstat_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
+ ssize_t count = 0;
+ unsigned long flags;
+ int i, idx;
+ struct b43_txstatus *stat;
+
+ spin_lock_irqsave(&log->lock, flags);
+ if (log->end < 0) {
+ fappend("Nothing transmitted, yet\n");
+ goto out_unlock;
+ }
+ fappend("b43 TX status reports:\n\n"
+ "index | cookie | seq | phy_stat | frame_count | "
+ "rts_count | supp_reason | pm_indicated | "
+ "intermediate | for_ampdu | acked\n" "---\n");
+ i = log->end + 1;
+ idx = 0;
+ while (1) {
+ if (i == B43_NR_LOGGED_TXSTATUS)
+ i = 0;
+ stat = &(log->log[i]);
+ if (stat->cookie) {
+ fappend("%03d | "
+ "0x%04X | 0x%04X | 0x%02X | "
+ "0x%X | 0x%X | "
+ "%u | %u | "
+ "%u | %u | %u\n",
+ idx,
+ stat->cookie, stat->seq, stat->phy_stat,
+ stat->frame_count, stat->rts_count,
+ stat->supp_reason, stat->pm_indicated,
+ stat->intermediate, stat->for_ampdu,
+ stat->acked);
+ idx++;
+ }
+ if (i == log->end)
+ break;
+ i++;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&log->lock, flags);
+
+ return count;
+}
+
+static ssize_t txpower_g_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+
+ if (dev->phy.type != B43_PHYTYPE_G) {
+ fappend("Device is not a G-PHY\n");
+ goto out;
+ }
+ fappend("Control: %s\n", dev->phy.manual_txpower_control ?
+ "MANUAL" : "AUTOMATIC");
+ fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att);
+ fappend("Radio attenuation: %u\n", dev->phy.rfatt.att);
+ fappend("TX Mixer Gain: %s\n",
+ (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
+ fappend("PA Gain 2dB: %s\n",
+ (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
+ fappend("PA Gain 3dB: %s\n",
+ (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
+ fappend("\n\n");
+ fappend("You can write to this file:\n");
+ fappend("Writing \"auto\" enables automatic txpower control.\n");
+ fappend
+ ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
+ "enables manual txpower control.\n");
+ fappend("Example: 5 4 0 0 1\n");
+ fappend("Enables manual control with Baseband attenuation 5, "
+ "Radio attenuation 4, No TX Mixer Gain, "
+ "No PA Gain 2dB, With PA Gain 3dB.\n");
+out:
+ return count;
+}
+
+static int txpower_g_write_file(struct b43_wldev *dev,
+ const char *buf, size_t count)
+{
+ unsigned long phy_flags;
+
+ if (dev->phy.type != B43_PHYTYPE_G)
+ return -ENODEV;
+ if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
+ /* Automatic control */
+ dev->phy.manual_txpower_control = 0;
+ b43_phy_xmitpower(dev);
+ } else {
+ int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
+ /* Manual control */
+ if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
+ &txmix, &pa2db, &pa3db) != 5)
+ return -EINVAL;
+ b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+ dev->phy.manual_txpower_control = 1;
+ dev->phy.bbatt.att = bbatt;
+ dev->phy.rfatt.att = rfatt;
+ dev->phy.tx_control = 0;
+ if (txmix)
+ dev->phy.tx_control |= B43_TXCTL_TXMIX;
+ if (pa2db)
+ dev->phy.tx_control |= B43_TXCTL_PA2DB;
+ if (pa3db)
+ dev->phy.tx_control |= B43_TXCTL_PA3DB;
+ b43_phy_lock(dev, phy_flags);
+ b43_radio_lock(dev);
+ b43_set_txpower_g(dev, &dev->phy.bbatt,
+ &dev->phy.rfatt, dev->phy.tx_control);
+ b43_radio_unlock(dev);
+ b43_phy_unlock(dev, phy_flags);
+ }
+
+ return 0;
+}
+
+/* wl->irq_lock is locked */
+static int restart_write_file(struct b43_wldev *dev,
+ const char *buf, size_t count)
+{
+ int err = 0;
+
+ if (count > 0 && buf[0] == '1') {
+ b43_controller_restart(dev, "manually restarted");
+ } else
+ err = -EINVAL;
+
+ return err;
+}
+
+static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize,
+ struct b43_loctl table[B43_NR_BB][B43_NR_RF])
+{
+ unsigned int i, j;
+ struct b43_loctl *ctl;
+
+ for (i = 0; i < B43_NR_BB; i++) {
+ for (j = 0; j < B43_NR_RF; j++) {
+ ctl = &(table[i][j]);
+ fappend("(bbatt %2u, rfatt %2u) -> "
+ "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n",
+ i, j, ctl->i, ctl->q,
+ ctl->used,
+ b43_loctl_is_calibrated(ctl));
+ }
+ }
+
+ return count;
+}
+
+static ssize_t loctls_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ struct b43_txpower_lo_control *lo;
+ int i, err = 0;
+
+ if (dev->phy.type != B43_PHYTYPE_G) {
+ fappend("Device is not a G-PHY\n");
+ err = -ENODEV;
+ goto out;
+ }
+ lo = dev->phy.lo_control;
+ fappend("-- Local Oscillator calibration data --\n\n");
+ fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n",
+ lo->lo_measured,
+ lo->rebuild,
+ dev->phy.hardware_power_control);
+ fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n",
+ lo->tx_bias, lo->tx_magn);
+ fappend("Power Vector: 0x%08X%08X\n",
+ (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
+ (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL));
+ fappend("\nControl table WITH PADMIX:\n");
+ count = append_lo_table(count, buf, bufsize, lo->with_padmix);
+ fappend("\nControl table WITHOUT PADMIX:\n");
+ count = append_lo_table(count, buf, bufsize, lo->no_padmix);
+ fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
+ for (i = 0; i < lo->rfatt_list.len; i++) {
+ fappend("%u(%d), ",
+ lo->rfatt_list.list[i].att,
+ lo->rfatt_list.list[i].with_padmix);
+ }
+ fappend("\n");
+ fappend("\nUsed Baseband attenuation values:\n");
+ for (i = 0; i < lo->bbatt_list.len; i++) {
+ fappend("%u, ",
+ lo->bbatt_list.list[i].att);
+ }
+ fappend("\n");
+
+out:
+ return err ? err : count;
+}
+
+#undef fappend
+
+static int b43_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43_wldev *dev;
+ struct b43_debugfs_fops *dfops;
+ struct b43_dfs_file *dfile;
+ ssize_t ret;
+ char *buf;
+ const size_t bufsize = 1024 * 128;
+ const size_t buforder = get_order(bufsize);
+ int err = 0;
+
+ if (!count)
+ return 0;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
+ if (!dfops->read) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+ dfile = fops_to_dfs_file(dev, dfops);
+
+ if (!dfile->buffer) {
+ buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ /* Sparse warns about the following memset, because it has a big
+ * size value. That warning is bogus, so I will ignore it. --mb */
+ memset(buf, 0, bufsize);
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ ret = dfops->read(dev, buf, bufsize);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ ret = dfops->read(dev, buf, bufsize);
+ if (ret <= 0) {
+ free_pages((unsigned long)buf, buforder);
+ err = ret;
+ goto out_unlock;
+ }
+ dfile->data_len = ret;
+ dfile->buffer = buf;
+ }
+
+ ret = simple_read_from_buffer(userbuf, count, ppos,
+ dfile->buffer,
+ dfile->data_len);
+ if (*ppos >= dfile->data_len) {
+ free_pages((unsigned long)dfile->buffer, buforder);
+ dfile->buffer = NULL;
+ dfile->data_len = 0;
+ }
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : ret;
+}
+
+static ssize_t b43_debugfs_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43_wldev *dev;
+ struct b43_debugfs_fops *dfops;
+ char *buf;
+ int err = 0;
+
+ if (!count)
+ return 0;
+ if (count > PAGE_SIZE)
+ return -E2BIG;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
+ if (!dfops->write) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ if (copy_from_user(buf, userbuf, count)) {
+ err = -EFAULT;
+ goto out_freepage;
+ }
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ err = dfops->write(dev, buf, count);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ err = dfops->write(dev, buf, count);
+ if (err)
+ goto out_freepage;
+
+out_freepage:
+ free_page((unsigned long)buf);
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : count;
+}
+
+
+#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
+ static struct b43_debugfs_fops fops_##name = { \
+ .read = _read, \
+ .write = _write, \
+ .fops = { \
+ .open = b43_debugfs_open, \
+ .read = b43_debugfs_read, \
+ .write = b43_debugfs_write, \
+ }, \
+ .file_struct_offset = offsetof(struct b43_dfsentry, \
+ file_##name), \
+ .take_irqlock = _take_irqlock, \
+ }
+
+B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
+B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
+B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
+B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
+B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
+B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
+B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
+
+
+int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
+{
+ return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
+}
+
+static void b43_remove_dynamic_debug(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e = dev->dfsentry;
+ int i;
+
+ for (i = 0; i < __B43_NR_DYNDBG; i++)
+ debugfs_remove(e->dyn_debug_dentries[i]);
+}
+
+static void b43_add_dynamic_debug(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e = dev->dfsentry;
+ struct dentry *d;
+
+#define add_dyn_dbg(name, id, initstate) do { \
+ e->dyn_debug[id] = (initstate); \
+ d = debugfs_create_bool(name, 0600, e->subdir, \
+ &(e->dyn_debug[id])); \
+ if (!IS_ERR(d)) \
+ e->dyn_debug_dentries[id] = d; \
+ } while (0)
+
+ add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
+ add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
+ add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
+ add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
+ add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
+
+#undef add_dyn_dbg
+}
+
+void b43_debugfs_add_device(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e;
+ struct b43_txstatus_log *log;
+ char devdir[16];
+
+ B43_WARN_ON(!dev);
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ if (!e) {
+ b43err(dev->wl, "debugfs: add device OOM\n");
+ return;
+ }
+ e->dev = dev;
+ log = &e->txstatlog;
+ log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
+ sizeof(struct b43_txstatus), GFP_KERNEL);
+ if (!log->log) {
+ b43err(dev->wl, "debugfs: add device txstatus OOM\n");
+ kfree(e);
+ return;
+ }
+ log->end = -1;
+ spin_lock_init(&log->lock);
+
+ dev->dfsentry = e;
+
+ snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
+ e->subdir = debugfs_create_dir(devdir, rootdir);
+ if (!e->subdir || IS_ERR(e->subdir)) {
+ if (e->subdir == ERR_PTR(-ENODEV)) {
+ b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
+ "enabled in kernel config\n");
+ } else {
+ b43err(dev->wl, "debugfs: cannot create %s directory\n",
+ devdir);
+ }
+ dev->dfsentry = NULL;
+ kfree(log->log);
+ kfree(e);
+ return;
+ }
+
+#define ADD_FILE(name, mode) \
+ do { \
+ struct dentry *d; \
+ d = debugfs_create_file(__stringify(name), \
+ mode, e->subdir, dev, \
+ &fops_##name.fops); \
+ e->file_##name.dentry = NULL; \
+ if (!IS_ERR(d)) \
+ e->file_##name.dentry = d; \
+ } while (0)
+
+
+ ADD_FILE(tsf, 0600);
+ ADD_FILE(ucode_regs, 0400);
+ ADD_FILE(shm, 0400);
+ ADD_FILE(txstat, 0400);
+ ADD_FILE(txpower_g, 0600);
+ ADD_FILE(restart, 0200);
+ ADD_FILE(loctls, 0400);
+
+#undef ADD_FILE
+
+ b43_add_dynamic_debug(dev);
+}
+
+void b43_debugfs_remove_device(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e;
+
+ if (!dev)
+ return;
+ e = dev->dfsentry;
+ if (!e)
+ return;
+ b43_remove_dynamic_debug(dev);
+
+ debugfs_remove(e->file_tsf.dentry);
+ debugfs_remove(e->file_ucode_regs.dentry);
+ debugfs_remove(e->file_shm.dentry);
+ debugfs_remove(e->file_txstat.dentry);
+ debugfs_remove(e->file_txpower_g.dentry);
+ debugfs_remove(e->file_restart.dentry);
+ debugfs_remove(e->file_loctls.dentry);
+
+ debugfs_remove(e->subdir);
+ kfree(e->txstatlog.log);
+ kfree(e);
+}
+
+void b43_debugfs_log_txstat(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ struct b43_dfsentry *e = dev->dfsentry;
+ struct b43_txstatus_log *log;
+ struct b43_txstatus *cur;
+ int i;
+
+ if (!e)
+ return;
+ log = &e->txstatlog;
+ B43_WARN_ON(!irqs_disabled());
+ spin_lock(&log->lock);
+ i = log->end + 1;
+ if (i == B43_NR_LOGGED_TXSTATUS)
+ i = 0;
+ log->end = i;
+ cur = &(log->log[i]);
+ memcpy(cur, status, sizeof(*cur));
+ spin_unlock(&log->lock);
+}
+
+void b43_debugfs_init(void)
+{
+ rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(rootdir))
+ rootdir = NULL;
+}
+
+void b43_debugfs_exit(void)
+{
+ debugfs_remove(rootdir);
+}
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
new file mode 100644
index 000000000000..6eebe858db5a
--- /dev/null
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -0,0 +1,89 @@
+#ifndef B43_DEBUGFS_H_
+#define B43_DEBUGFS_H_
+
+struct b43_wldev;
+struct b43_txstatus;
+
+enum b43_dyndbg { /* Dynamic debugging features */
+ B43_DBG_XMITPOWER,
+ B43_DBG_DMAOVERFLOW,
+ B43_DBG_DMAVERBOSE,
+ B43_DBG_PWORK_FAST,
+ B43_DBG_PWORK_STOP,
+ __B43_NR_DYNDBG,
+};
+
+#ifdef CONFIG_B43_DEBUG
+
+struct dentry;
+
+#define B43_NR_LOGGED_TXSTATUS 100
+
+struct b43_txstatus_log {
+ struct b43_txstatus *log;
+ int end;
+ spinlock_t lock;
+};
+
+struct b43_dfs_file {
+ struct dentry *dentry;
+ char *buffer;
+ size_t data_len;
+};
+
+struct b43_dfsentry {
+ struct b43_wldev *dev;
+ struct dentry *subdir;
+
+ struct b43_dfs_file file_tsf;
+ struct b43_dfs_file file_ucode_regs;
+ struct b43_dfs_file file_shm;
+ struct b43_dfs_file file_txstat;
+ struct b43_dfs_file file_txpower_g;
+ struct b43_dfs_file file_restart;
+ struct b43_dfs_file file_loctls;
+
+ struct b43_txstatus_log txstatlog;
+
+ /* Enabled/Disabled list for the dynamic debugging features. */
+ u32 dyn_debug[__B43_NR_DYNDBG];
+ /* Dentries for the dynamic debugging entries. */
+ struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG];
+};
+
+int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature);
+
+void b43_debugfs_init(void);
+void b43_debugfs_exit(void);
+void b43_debugfs_add_device(struct b43_wldev *dev);
+void b43_debugfs_remove_device(struct b43_wldev *dev);
+void b43_debugfs_log_txstat(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+
+#else /* CONFIG_B43_DEBUG */
+
+static inline int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
+{
+ return 0;
+}
+
+static inline void b43_debugfs_init(void)
+{
+}
+static inline void b43_debugfs_exit(void)
+{
+}
+static inline void b43_debugfs_add_device(struct b43_wldev *dev)
+{
+}
+static inline void b43_debugfs_remove_device(struct b43_wldev *dev)
+{
+}
+static inline void b43_debugfs_log_txstat(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+}
+
+#endif /* CONFIG_B43_DEBUG */
+
+#endif /* B43_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
new file mode 100644
index 000000000000..5e8f8ac0f1dd
--- /dev/null
+++ b/drivers/net/wireless/b43/dma.c
@@ -0,0 +1,1494 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ DMA ringbuffer and descriptor allocation/management
+
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+
+ Some code in this file is derived from the b44.c driver
+ Copyright (C) 2002 David S. Miller
+ Copyright (C) Pekka Pietikainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "dma.h"
+#include "main.h"
+#include "debugfs.h"
+#include "xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+
+/* 32bit DMA ops. */
+static
+struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring,
+ int slot,
+ struct b43_dmadesc_meta **meta)
+{
+ struct b43_dmadesc32 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43_dmadesc_generic *)desc;
+}
+
+static void op32_fill_descriptor(struct b43_dmaring *ring,
+ struct b43_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43_dmadesc32 *descbase = ring->descbase;
+ int slot;
+ u32 ctl;
+ u32 addr;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma32) - descbase);
+ B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addr |= ssb_dma_translation(ring->dev->dev);
+ ctl = (bufsize - ring->frameoffset)
+ & B43_DMA32_DCTL_BYTECNT;
+ if (slot == ring->nr_slots - 1)
+ ctl |= B43_DMA32_DCTL_DTABLEEND;
+ if (start)
+ ctl |= B43_DMA32_DCTL_FRAMESTART;
+ if (end)
+ ctl |= B43_DMA32_DCTL_FRAMEEND;
+ if (irq)
+ ctl |= B43_DMA32_DCTL_IRQ;
+ ctl |= (addrext << B43_DMA32_DCTL_ADDREXT_SHIFT)
+ & B43_DMA32_DCTL_ADDREXT_MASK;
+
+ desc->dma32.control = cpu_to_le32(ctl);
+ desc->dma32.address = cpu_to_le32(addr);
+}
+
+static void op32_poke_tx(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA32_TXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc32)));
+}
+
+static void op32_tx_suspend(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL)
+ | B43_DMA32_TXSUSPEND);
+}
+
+static void op32_tx_resume(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL)
+ & ~B43_DMA32_TXSUSPEND);
+}
+
+static int op32_get_current_rxslot(struct b43_dmaring *ring)
+{
+ u32 val;
+
+ val = b43_dma_read(ring, B43_DMA32_RXSTATUS);
+ val &= B43_DMA32_RXDPTR;
+
+ return (val / sizeof(struct b43_dmadesc32));
+}
+
+static void op32_set_current_rxslot(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA32_RXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc32)));
+}
+
+static const struct b43_dma_ops dma32_ops = {
+ .idx2desc = op32_idx2desc,
+ .fill_descriptor = op32_fill_descriptor,
+ .poke_tx = op32_poke_tx,
+ .tx_suspend = op32_tx_suspend,
+ .tx_resume = op32_tx_resume,
+ .get_current_rxslot = op32_get_current_rxslot,
+ .set_current_rxslot = op32_set_current_rxslot,
+};
+
+/* 64bit DMA ops. */
+static
+struct b43_dmadesc_generic *op64_idx2desc(struct b43_dmaring *ring,
+ int slot,
+ struct b43_dmadesc_meta **meta)
+{
+ struct b43_dmadesc64 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43_dmadesc_generic *)desc;
+}
+
+static void op64_fill_descriptor(struct b43_dmaring *ring,
+ struct b43_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43_dmadesc64 *descbase = ring->descbase;
+ int slot;
+ u32 ctl0 = 0, ctl1 = 0;
+ u32 addrlo, addrhi;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma64) - descbase);
+ B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
+ addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addrhi |= ssb_dma_translation(ring->dev->dev);
+ if (slot == ring->nr_slots - 1)
+ ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
+ if (start)
+ ctl0 |= B43_DMA64_DCTL0_FRAMESTART;
+ if (end)
+ ctl0 |= B43_DMA64_DCTL0_FRAMEEND;
+ if (irq)
+ ctl0 |= B43_DMA64_DCTL0_IRQ;
+ ctl1 |= (bufsize - ring->frameoffset)
+ & B43_DMA64_DCTL1_BYTECNT;
+ ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT)
+ & B43_DMA64_DCTL1_ADDREXT_MASK;
+
+ desc->dma64.control0 = cpu_to_le32(ctl0);
+ desc->dma64.control1 = cpu_to_le32(ctl1);
+ desc->dma64.address_low = cpu_to_le32(addrlo);
+ desc->dma64.address_high = cpu_to_le32(addrhi);
+}
+
+static void op64_poke_tx(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA64_TXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc64)));
+}
+
+static void op64_tx_suspend(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL)
+ | B43_DMA64_TXSUSPEND);
+}
+
+static void op64_tx_resume(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL)
+ & ~B43_DMA64_TXSUSPEND);
+}
+
+static int op64_get_current_rxslot(struct b43_dmaring *ring)
+{
+ u32 val;
+
+ val = b43_dma_read(ring, B43_DMA64_RXSTATUS);
+ val &= B43_DMA64_RXSTATDPTR;
+
+ return (val / sizeof(struct b43_dmadesc64));
+}
+
+static void op64_set_current_rxslot(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA64_RXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc64)));
+}
+
+static const struct b43_dma_ops dma64_ops = {
+ .idx2desc = op64_idx2desc,
+ .fill_descriptor = op64_fill_descriptor,
+ .poke_tx = op64_poke_tx,
+ .tx_suspend = op64_tx_suspend,
+ .tx_resume = op64_tx_resume,
+ .get_current_rxslot = op64_get_current_rxslot,
+ .set_current_rxslot = op64_set_current_rxslot,
+};
+
+static inline int free_slots(struct b43_dmaring *ring)
+{
+ return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct b43_dmaring *ring, int slot)
+{
+ B43_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
+ if (slot == ring->nr_slots - 1)
+ return 0;
+ return slot + 1;
+}
+
+static inline int prev_slot(struct b43_dmaring *ring, int slot)
+{
+ B43_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
+ if (slot == 0)
+ return ring->nr_slots - 1;
+ return slot - 1;
+}
+
+#ifdef CONFIG_B43_DEBUG
+static void update_max_used_slots(struct b43_dmaring *ring,
+ int current_used_slots)
+{
+ if (current_used_slots <= ring->max_used_slots)
+ return;
+ ring->max_used_slots = current_used_slots;
+ if (b43_debug(ring->dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(ring->dev->wl,
+ "max_used_slots increased to %d on %s ring %d\n",
+ ring->max_used_slots,
+ ring->tx ? "TX" : "RX", ring->index);
+ }
+}
+#else
+static inline
+ void update_max_used_slots(struct b43_dmaring *ring, int current_used_slots)
+{
+}
+#endif /* DEBUG */
+
+/* Request a slot for usage. */
+static inline int request_slot(struct b43_dmaring *ring)
+{
+ int slot;
+
+ B43_WARN_ON(!ring->tx);
+ B43_WARN_ON(ring->stopped);
+ B43_WARN_ON(free_slots(ring) == 0);
+
+ slot = next_slot(ring, ring->current_slot);
+ ring->current_slot = slot;
+ ring->used_slots++;
+
+ update_max_used_slots(ring, ring->used_slots);
+
+ return slot;
+}
+
+/* Mac80211-queue to b43-ring mapping */
+static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
+ int queue_priority)
+{
+ struct b43_dmaring *ring;
+
+/*FIXME: For now we always run on TX-ring-1 */
+ return dev->dma.tx_ring1;
+
+ /* 0 = highest priority */
+ switch (queue_priority) {
+ default:
+ B43_WARN_ON(1);
+ /* fallthrough */
+ case 0:
+ ring = dev->dma.tx_ring3;
+ break;
+ case 1:
+ ring = dev->dma.tx_ring2;
+ break;
+ case 2:
+ ring = dev->dma.tx_ring1;
+ break;
+ case 3:
+ ring = dev->dma.tx_ring0;
+ break;
+ case 4:
+ ring = dev->dma.tx_ring4;
+ break;
+ case 5:
+ ring = dev->dma.tx_ring5;
+ break;
+ }
+
+ return ring;
+}
+
+/* Bcm43xx-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct b43_dmaring *ring)
+{
+ static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
+
+/*FIXME: have only one queue, for now */
+ return 0;
+
+ return idx_to_prio[ring->index];
+}
+
+u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+{
+ static const u16 map64[] = {
+ B43_MMIO_DMA64_BASE0,
+ B43_MMIO_DMA64_BASE1,
+ B43_MMIO_DMA64_BASE2,
+ B43_MMIO_DMA64_BASE3,
+ B43_MMIO_DMA64_BASE4,
+ B43_MMIO_DMA64_BASE5,
+ };
+ static const u16 map32[] = {
+ B43_MMIO_DMA32_BASE0,
+ B43_MMIO_DMA32_BASE1,
+ B43_MMIO_DMA32_BASE2,
+ B43_MMIO_DMA32_BASE3,
+ B43_MMIO_DMA32_BASE4,
+ B43_MMIO_DMA32_BASE5,
+ };
+
+ if (dma64bit) {
+ B43_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map64)));
+ return map64[controller_idx];
+ }
+ B43_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map32)));
+ return map32[controller_idx];
+}
+
+static inline
+ dma_addr_t map_descbuffer(struct b43_dmaring *ring,
+ unsigned char *buf, size_t len, int tx)
+{
+ dma_addr_t dmaaddr;
+
+ if (tx) {
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len, DMA_TO_DEVICE);
+ } else {
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len, DMA_FROM_DEVICE);
+ }
+
+ return dmaaddr;
+}
+
+static inline
+ void unmap_descbuffer(struct b43_dmaring *ring,
+ dma_addr_t addr, size_t len, int tx)
+{
+ if (tx) {
+ dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE);
+ } else {
+ dma_unmap_single(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+ }
+}
+
+static inline
+ void sync_descbuffer_for_cpu(struct b43_dmaring *ring,
+ dma_addr_t addr, size_t len)
+{
+ B43_WARN_ON(ring->tx);
+ dma_sync_single_for_cpu(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+ void sync_descbuffer_for_device(struct b43_dmaring *ring,
+ dma_addr_t addr, size_t len)
+{
+ B43_WARN_ON(ring->tx);
+ dma_sync_single_for_device(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+ void free_descriptor_buffer(struct b43_dmaring *ring,
+ struct b43_dmadesc_meta *meta)
+{
+ if (meta->skb) {
+ dev_kfree_skb_any(meta->skb);
+ meta->skb = NULL;
+ }
+}
+
+static int alloc_ringmemory(struct b43_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
+ &(ring->dmabase), GFP_KERNEL);
+ if (!ring->descbase) {
+ b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
+ return -ENOMEM;
+ }
+ memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
+
+ return 0;
+}
+
+static void free_ringmemory(struct b43_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ dma_free_coherent(dev, B43_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+ b43_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+ value = b43_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43_DMA64_RXSTAT;
+ if (value == B43_DMA64_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43_DMA32_RXSTATE;
+ if (value == B43_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43err(dev->wl, "DMA RX reset timed out\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* Reset the RX DMA channel */
+int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+ value = b43_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43_DMA64_TXSTAT;
+ if (value == B43_DMA64_TXSTAT_DISABLED ||
+ value == B43_DMA64_TXSTAT_IDLEWAIT ||
+ value == B43_DMA64_TXSTAT_STOPPED)
+ break;
+ } else {
+ value &= B43_DMA32_TXSTATE;
+ if (value == B43_DMA32_TXSTAT_DISABLED ||
+ value == B43_DMA32_TXSTAT_IDLEWAIT ||
+ value == B43_DMA32_TXSTAT_STOPPED)
+ break;
+ }
+ msleep(1);
+ }
+ offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+ b43_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+ value = b43_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43_DMA64_TXSTAT;
+ if (value == B43_DMA64_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43_DMA32_TXSTATE;
+ if (value == B43_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43err(dev->wl, "DMA TX reset timed out\n");
+ return -ENODEV;
+ }
+ /* ensure the reset is completed. */
+ msleep(1);
+
+ return 0;
+}
+
+static int setup_rx_descbuffer(struct b43_dmaring *ring,
+ struct b43_dmadesc_generic *desc,
+ struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
+{
+ struct b43_rxhdr_fw4 *rxhdr;
+ struct b43_hwtxstatus *txstat;
+ dma_addr_t dmaaddr;
+ struct sk_buff *skb;
+
+ B43_WARN_ON(ring->tx);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+ if (dma_mapping_error(dmaaddr)) {
+ /* ugh. try to realloc in zone_dma */
+ gfp_flags |= GFP_DMA;
+
+ dev_kfree_skb_any(skb);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ }
+
+ if (dma_mapping_error(dmaaddr)) {
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ meta->skb = skb;
+ meta->dmaaddr = dmaaddr;
+ ring->ops->fill_descriptor(ring, desc, dmaaddr,
+ ring->rx_buffersize, 0, 0, 0);
+
+ rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
+ rxhdr->frame_len = 0;
+ txstat = (struct b43_hwtxstatus *)(skb->data);
+ txstat->cookie = 0;
+
+ return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct b43_dmaring *ring)
+{
+ int i, err = -ENOMEM;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+ if (err) {
+ b43err(ring->dev->wl,
+ "Failed to allocate initial descbuffers\n");
+ goto err_unwind;
+ }
+ }
+ mb();
+ ring->used_slots = ring->nr_slots;
+ err = 0;
+ out:
+ return err;
+
+ err_unwind:
+ for (i--; i >= 0; i--) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+ dev_kfree_skb(meta->skb);
+ }
+ goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct b43_dmaring *ring)
+{
+ int err = 0;
+ u32 value;
+ u32 addrext;
+ u32 trans = ssb_dma_translation(ring->dev->dev);
+
+ if (ring->tx) {
+ if (ring->dma64) {
+ u64 ringbase = (u64) (ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43_DMA64_TXENABLE;
+ value |= (addrext << B43_DMA64_TXADDREXT_SHIFT)
+ & B43_DMA64_TXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA64_TXCTL, value);
+ b43_dma_write(ring, B43_DMA64_TXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43_dma_write(ring, B43_DMA64_TXRINGHI,
+ ((ringbase >> 32) &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ } else {
+ u32 ringbase = (u32) (ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43_DMA32_TXENABLE;
+ value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
+ & B43_DMA32_TXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA32_TXCTL, value);
+ b43_dma_write(ring, B43_DMA32_TXRING,
+ (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ }
+ } else {
+ err = alloc_initial_descbuffers(ring);
+ if (err)
+ goto out;
+ if (ring->dma64) {
+ u64 ringbase = (u64) (ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT);
+ value |= B43_DMA64_RXENABLE;
+ value |= (addrext << B43_DMA64_RXADDREXT_SHIFT)
+ & B43_DMA64_RXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA64_RXCTL, value);
+ b43_dma_write(ring, B43_DMA64_RXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43_dma_write(ring, B43_DMA64_RXRINGHI,
+ ((ringbase >> 32) &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+ } else {
+ u32 ringbase = (u32) (ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
+ value |= B43_DMA32_RXENABLE;
+ value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
+ & B43_DMA32_RXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA32_RXCTL, value);
+ b43_dma_write(ring, B43_DMA32_RXRING,
+ (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+ }
+ }
+
+ out:
+ return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct b43_dmaring *ring)
+{
+ if (ring->tx) {
+ b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
+ b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
+ } else
+ b43_dma_write(ring, B43_DMA32_TXRING, 0);
+ } else {
+ b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
+ b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
+ } else
+ b43_dma_write(ring, B43_DMA32_RXRING, 0);
+ }
+}
+
+static void free_all_descbuffers(struct b43_dmaring *ring)
+{
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ int i;
+
+ if (!ring->used_slots)
+ return;
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ if (!meta->skb) {
+ B43_WARN_ON(!ring->tx);
+ continue;
+ }
+ if (ring->tx) {
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
+ } else {
+ unmap_descbuffer(ring, meta->dmaaddr,
+ ring->rx_buffersize, 0);
+ }
+ free_descriptor_buffer(ring, meta);
+ }
+}
+
+static u64 supported_dma_mask(struct b43_wldev *dev)
+{
+ u32 tmp;
+ u16 mmio_base;
+
+ tmp = b43_read32(dev, SSB_TMSHIGH);
+ if (tmp & SSB_TMSHIGH_DMA64)
+ return DMA_64BIT_MASK;
+ mmio_base = b43_dmacontroller_base(0, 0);
+ b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK);
+ tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL);
+ if (tmp & B43_DMA32_TXADDREXT_MASK)
+ return DMA_32BIT_MASK;
+
+ return DMA_30BIT_MASK;
+}
+
+/* Main initialization function. */
+static
+struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
+ int controller_index,
+ int for_tx, int dma64)
+{
+ struct b43_dmaring *ring;
+ int err;
+ int nr_slots;
+ dma_addr_t dma_test;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out;
+
+ nr_slots = B43_RXRING_SLOTS;
+ if (for_tx)
+ nr_slots = B43_TXRING_SLOTS;
+
+ ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta),
+ GFP_KERNEL);
+ if (!ring->meta)
+ goto err_kfree_ring;
+ if (for_tx) {
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct b43_txhdr_fw4),
+ GFP_KERNEL);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ /* test for ability to dma to txhdr_cache */
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43_txhdr_fw4),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test)) {
+ /* ugh realloc */
+ kfree(ring->txhdr_cache);
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct
+ b43_txhdr_fw4),
+ GFP_KERNEL | GFP_DMA);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43_txhdr_fw4),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test))
+ goto err_kfree_txhdr_cache;
+ }
+
+ dma_unmap_single(dev->dev->dev,
+ dma_test, sizeof(struct b43_txhdr_fw4),
+ DMA_TO_DEVICE);
+ }
+
+ ring->dev = dev;
+ ring->nr_slots = nr_slots;
+ ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+ ring->index = controller_index;
+ ring->dma64 = !!dma64;
+ if (dma64)
+ ring->ops = &dma64_ops;
+ else
+ ring->ops = &dma32_ops;
+ if (for_tx) {
+ ring->tx = 1;
+ ring->current_slot = -1;
+ } else {
+ if (ring->index == 0) {
+ ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
+ ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+ } else if (ring->index == 3) {
+ ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE;
+ ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET;
+ } else
+ B43_WARN_ON(1);
+ }
+ spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43_DEBUG
+ ring->last_injected_overflow = jiffies;
+#endif
+
+ err = alloc_ringmemory(ring);
+ if (err)
+ goto err_kfree_txhdr_cache;
+ err = dmacontroller_setup(ring);
+ if (err)
+ goto err_free_ringmemory;
+
+ out:
+ return ring;
+
+ err_free_ringmemory:
+ free_ringmemory(ring);
+ err_kfree_txhdr_cache:
+ kfree(ring->txhdr_cache);
+ err_kfree_meta:
+ kfree(ring->meta);
+ err_kfree_ring:
+ kfree(ring);
+ ring = NULL;
+ goto out;
+}
+
+/* Main cleanup function. */
+static void b43_destroy_dmaring(struct b43_dmaring *ring)
+{
+ if (!ring)
+ return;
+
+ b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+ (ring->dma64) ? "64" : "32",
+ ring->mmio_base,
+ (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
+ /* Device IRQs are disabled prior entering this function,
+ * so no need to take care of concurrency with rx handler stuff.
+ */
+ dmacontroller_cleanup(ring);
+ free_all_descbuffers(ring);
+ free_ringmemory(ring);
+
+ kfree(ring->txhdr_cache);
+ kfree(ring->meta);
+ kfree(ring);
+}
+
+void b43_dma_free(struct b43_wldev *dev)
+{
+ struct b43_dma *dma;
+
+ if (b43_using_pio(dev))
+ return;
+ dma = &dev->dma;
+
+ b43_destroy_dmaring(dma->rx_ring3);
+ dma->rx_ring3 = NULL;
+ b43_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+
+ b43_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ b43_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+ b43_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ b43_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+ b43_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+ b43_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+}
+
+int b43_dma_init(struct b43_wldev *dev)
+{
+ struct b43_dma *dma = &dev->dma;
+ struct b43_dmaring *ring;
+ int err;
+ u64 dmamask;
+ int dma64 = 0;
+
+ dmamask = supported_dma_mask(dev);
+ if (dmamask == DMA_64BIT_MASK)
+ dma64 = 1;
+
+ err = ssb_dma_set_mask(dev->dev, dmamask);
+ if (err) {
+#ifdef B43_PIO
+ b43warn(dev->wl, "DMA for this device not supported. "
+ "Falling back to PIO\n");
+ dev->__using_pio = 1;
+ return -EAGAIN;
+#else
+ b43err(dev->wl, "DMA for this device not supported and "
+ "no PIO support compiled in\n");
+ return -EOPNOTSUPP;
+#endif
+ }
+
+ err = -ENOMEM;
+ /* setup TX DMA channels. */
+ ring = b43_setup_dmaring(dev, 0, 1, dma64);
+ if (!ring)
+ goto out;
+ dma->tx_ring0 = ring;
+
+ ring = b43_setup_dmaring(dev, 1, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx0;
+ dma->tx_ring1 = ring;
+
+ ring = b43_setup_dmaring(dev, 2, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx1;
+ dma->tx_ring2 = ring;
+
+ ring = b43_setup_dmaring(dev, 3, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx2;
+ dma->tx_ring3 = ring;
+
+ ring = b43_setup_dmaring(dev, 4, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx3;
+ dma->tx_ring4 = ring;
+
+ ring = b43_setup_dmaring(dev, 5, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx4;
+ dma->tx_ring5 = ring;
+
+ /* setup RX DMA channels. */
+ ring = b43_setup_dmaring(dev, 0, 0, dma64);
+ if (!ring)
+ goto err_destroy_tx5;
+ dma->rx_ring0 = ring;
+
+ if (dev->dev->id.revision < 5) {
+ ring = b43_setup_dmaring(dev, 3, 0, dma64);
+ if (!ring)
+ goto err_destroy_rx0;
+ dma->rx_ring3 = ring;
+ }
+
+ b43dbg(dev->wl, "%d-bit DMA initialized\n",
+ (dmamask == DMA_64BIT_MASK) ? 64 :
+ (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+ err = 0;
+ out:
+ return err;
+
+ err_destroy_rx0:
+ b43_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+ err_destroy_tx5:
+ b43_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ err_destroy_tx4:
+ b43_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+ err_destroy_tx3:
+ b43_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ err_destroy_tx2:
+ b43_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+ err_destroy_tx1:
+ b43_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+ err_destroy_tx0:
+ b43_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+ goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct b43_dmaring *ring, int slot)
+{
+ u16 cookie = 0x1000;
+
+ /* Use the upper 4 bits of the cookie as
+ * DMA controller ID and store the slot number
+ * in the lower 12 bits.
+ * Note that the cookie must never be 0, as this
+ * is a special value used in RX path.
+ */
+ switch (ring->index) {
+ case 0:
+ cookie = 0xA000;
+ break;
+ case 1:
+ cookie = 0xB000;
+ break;
+ case 2:
+ cookie = 0xC000;
+ break;
+ case 3:
+ cookie = 0xD000;
+ break;
+ case 4:
+ cookie = 0xE000;
+ break;
+ case 5:
+ cookie = 0xF000;
+ break;
+ }
+ B43_WARN_ON(slot & ~0x0FFF);
+ cookie |= (u16) slot;
+
+ return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
+{
+ struct b43_dma *dma = &dev->dma;
+ struct b43_dmaring *ring = NULL;
+
+ switch (cookie & 0xF000) {
+ case 0xA000:
+ ring = dma->tx_ring0;
+ break;
+ case 0xB000:
+ ring = dma->tx_ring1;
+ break;
+ case 0xC000:
+ ring = dma->tx_ring2;
+ break;
+ case 0xD000:
+ ring = dma->tx_ring3;
+ break;
+ case 0xE000:
+ ring = dma->tx_ring4;
+ break;
+ case 0xF000:
+ ring = dma->tx_ring5;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ *slot = (cookie & 0x0FFF);
+ B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+
+ return ring;
+}
+
+static int dma_tx_fragment(struct b43_dmaring *ring,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ const struct b43_dma_ops *ops = ring->ops;
+ u8 *header;
+ int slot;
+ int err;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ struct b43_dmadesc_meta *meta_hdr;
+ struct sk_buff *bounce_skb;
+
+#define SLOTS_PER_PACKET 2
+ B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+
+ /* Get a slot for the header. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta_hdr);
+ memset(meta_hdr, 0, sizeof(*meta_hdr));
+
+ header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
+ b43_generate_txhdr(ring->dev, header,
+ skb->data, skb->len, ctl,
+ generate_cookie(ring, slot));
+
+ meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
+ sizeof(struct b43_txhdr_fw4), 1);
+ if (dma_mapping_error(meta_hdr->dmaaddr))
+ return -EIO;
+ ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+ sizeof(struct b43_txhdr_fw4), 1, 0, 0);
+
+ /* Get a slot for the payload. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta);
+ memset(meta, 0, sizeof(*meta));
+
+ memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
+ meta->skb = skb;
+ meta->is_last_fragment = 1;
+
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ /* create a bounce buffer in zone_dma on mapping failure. */
+ if (dma_mapping_error(meta->dmaaddr)) {
+ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+ if (!bounce_skb) {
+ err = -ENOMEM;
+ goto out_unmap_hdr;
+ }
+
+ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ skb = bounce_skb;
+ meta->skb = skb;
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ if (dma_mapping_error(meta->dmaaddr)) {
+ err = -EIO;
+ goto out_free_bounce;
+ }
+ }
+
+ ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
+
+ /* Now transfer the whole frame. */
+ wmb();
+ ops->poke_tx(ring, next_slot(ring, slot));
+ return 0;
+
+ out_free_bounce:
+ dev_kfree_skb_any(skb);
+ out_unmap_hdr:
+ unmap_descbuffer(ring, meta_hdr->dmaaddr,
+ sizeof(struct b43_txhdr_fw4), 1);
+ return err;
+}
+
+static inline int should_inject_overflow(struct b43_dmaring *ring)
+{
+#ifdef CONFIG_B43_DEBUG
+ if (unlikely(b43_debug(ring->dev, B43_DBG_DMAOVERFLOW))) {
+ /* Check if we should inject another ringbuffer overflow
+ * to test handling of this situation in the stack. */
+ unsigned long next_overflow;
+
+ next_overflow = ring->last_injected_overflow + HZ;
+ if (time_after(jiffies, next_overflow)) {
+ ring->last_injected_overflow = jiffies;
+ b43dbg(ring->dev->wl,
+ "Injecting TX ring overflow on "
+ "DMA controller %d\n", ring->index);
+ return 1;
+ }
+ }
+#endif /* CONFIG_B43_DEBUG */
+ return 0;
+}
+
+int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct b43_dmaring *ring;
+ int err = 0;
+ unsigned long flags;
+
+ ring = priority_to_txring(dev, ctl->queue);
+ spin_lock_irqsave(&ring->lock, flags);
+ B43_WARN_ON(!ring->tx);
+ if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
+ b43warn(dev->wl, "DMA queue overflow\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+ /* Check if the queue was stopped in mac80211,
+ * but we got called nevertheless.
+ * That would be a mac80211 bug. */
+ B43_WARN_ON(ring->stopped);
+
+ err = dma_tx_fragment(ring, skb, ctl);
+ if (unlikely(err)) {
+ b43err(dev->wl, "DMA tx mapping failure\n");
+ goto out_unlock;
+ }
+ ring->nr_tx_packets++;
+ if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+ should_inject_overflow(ring)) {
+ /* This TX ring is full. */
+ ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 1;
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
+ }
+ }
+ out_unlock:
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ return err;
+}
+
+void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ const struct b43_dma_ops *ops;
+ struct b43_dmaring *ring;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ int slot;
+
+ ring = parse_cookie(dev, status->cookie, &slot);
+ if (unlikely(!ring))
+ return;
+ B43_WARN_ON(!irqs_disabled());
+ spin_lock(&ring->lock);
+
+ B43_WARN_ON(!ring->tx);
+ ops = ring->ops;
+ while (1) {
+ B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+ desc = ops->idx2desc(ring, slot, &meta);
+
+ if (meta->skb)
+ unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len,
+ 1);
+ else
+ unmap_descbuffer(ring, meta->dmaaddr,
+ sizeof(struct b43_txhdr_fw4), 1);
+
+ if (meta->is_last_fragment) {
+ B43_WARN_ON(!meta->skb);
+ /* Call back to inform the ieee80211 subsystem about the
+ * status of the transmission.
+ * Some fields of txstat are already filled in dma_tx().
+ */
+ if (status->acked) {
+ meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ if (!(meta->txstat.control.flags
+ & IEEE80211_TXCTL_NO_ACK))
+ meta->txstat.excessive_retries = 1;
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ meta->txstat.retry_count = 0;
+ } else
+ meta->txstat.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+ &(meta->txstat));
+ /* skb is freed by ieee80211_tx_status_irqsafe() */
+ meta->skb = NULL;
+ } else {
+ /* No need to call free_descriptor_buffer here, as
+ * this is only the txhdr, which is not allocated.
+ */
+ B43_WARN_ON(meta->skb);
+ }
+
+ /* Everything unmapped and free'd. So it's not used anymore. */
+ ring->used_slots--;
+
+ if (meta->is_last_fragment)
+ break;
+ slot = next_slot(ring, slot);
+ }
+ dev->stats.last_tx = jiffies;
+ if (ring->stopped) {
+ B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+ ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 0;
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
+ }
+ }
+
+ spin_unlock(&ring->lock);
+}
+
+void b43_dma_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ const int nr_queues = dev->wl->hw->queues;
+ struct b43_dmaring *ring;
+ struct ieee80211_tx_queue_stats_data *data;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < nr_queues; i++) {
+ data = &(stats->data[i]);
+ ring = priority_to_txring(dev, i);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ data->len = ring->used_slots / SLOTS_PER_PACKET;
+ data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+ data->count = ring->nr_tx_packets;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ }
+}
+
+static void dma_rx(struct b43_dmaring *ring, int *slot)
+{
+ const struct b43_dma_ops *ops = ring->ops;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ struct b43_rxhdr_fw4 *rxhdr;
+ struct sk_buff *skb;
+ u16 len;
+ int err;
+ dma_addr_t dmaaddr;
+
+ desc = ops->idx2desc(ring, *slot, &meta);
+
+ sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+ skb = meta->skb;
+
+ if (ring->index == 3) {
+ /* We received an xmit status. */
+ struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data;
+ int i = 0;
+
+ while (hw->cookie == 0) {
+ if (i > 100)
+ break;
+ i++;
+ udelay(2);
+ barrier();
+ }
+ b43_handle_hwtxstatus(ring->dev, hw);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+
+ return;
+ }
+ rxhdr = (struct b43_rxhdr_fw4 *)skb->data;
+ len = le16_to_cpu(rxhdr->frame_len);
+ if (len == 0) {
+ int i = 0;
+
+ do {
+ udelay(2);
+ barrier();
+ len = le16_to_cpu(rxhdr->frame_len);
+ } while (len == 0 && i++ < 5);
+ if (unlikely(len == 0)) {
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ goto drop;
+ }
+ }
+ if (unlikely(len > ring->rx_buffersize)) {
+ /* The data did not fit into one descriptor buffer
+ * and is split over multiple buffers.
+ * This should never happen, as we try to allocate buffers
+ * big enough. So simply ignore this packet.
+ */
+ int cnt = 0;
+ s32 tmp = len;
+
+ while (1) {
+ desc = ops->idx2desc(ring, *slot, &meta);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ *slot = next_slot(ring, *slot);
+ cnt++;
+ tmp -= ring->rx_buffersize;
+ if (tmp <= 0)
+ break;
+ }
+ b43err(ring->dev->wl, "DMA RX buffer too small "
+ "(len: %u, buffer: %u, nr-dropped: %d)\n",
+ len, ring->rx_buffersize, cnt);
+ goto drop;
+ }
+
+ dmaaddr = meta->dmaaddr;
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+ if (unlikely(err)) {
+ b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n");
+ sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
+ goto drop;
+ }
+
+ unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+ skb_put(skb, len + ring->frameoffset);
+ skb_pull(skb, ring->frameoffset);
+
+ b43_rx(ring->dev, skb, rxhdr);
+ drop:
+ return;
+}
+
+void b43_dma_rx(struct b43_dmaring *ring)
+{
+ const struct b43_dma_ops *ops = ring->ops;
+ int slot, current_slot;
+ int used_slots = 0;
+
+ B43_WARN_ON(ring->tx);
+ current_slot = ops->get_current_rxslot(ring);
+ B43_WARN_ON(!(current_slot >= 0 && current_slot < ring->nr_slots));
+
+ slot = ring->current_slot;
+ for (; slot != current_slot; slot = next_slot(ring, slot)) {
+ dma_rx(ring, &slot);
+ update_max_used_slots(ring, ++used_slots);
+ }
+ ops->set_current_rxslot(ring, slot);
+ ring->current_slot = slot;
+}
+
+static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43_WARN_ON(!ring->tx);
+ ring->ops->tx_suspend(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void b43_dma_tx_resume_ring(struct b43_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43_WARN_ON(!ring->tx);
+ ring->ops->tx_resume(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+void b43_dma_tx_suspend(struct b43_wldev *dev)
+{
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring0);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring1);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring2);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring3);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring4);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring5);
+}
+
+void b43_dma_tx_resume(struct b43_wldev *dev)
+{
+ b43_dma_tx_resume_ring(dev->dma.tx_ring5);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring4);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring3);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring2);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring1);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring0);
+ b43_power_saving_ctl_bits(dev, 0);
+}
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
new file mode 100644
index 000000000000..3eed185be725
--- /dev/null
+++ b/drivers/net/wireless/b43/dma.h
@@ -0,0 +1,337 @@
+#ifndef B43_DMA_H_
+#define B43_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+#include "b43.h"
+
+/* DMA-Interrupt reasons. */
+#define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
+ | (1 << 14) | (1 << 15))
+#define B43_DMAIRQ_NONFATALMASK (1 << 13)
+#define B43_DMAIRQ_RX_DONE (1 << 16)
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define B43_DMA32_TXCTL 0x00
+#define B43_DMA32_TXENABLE 0x00000001
+#define B43_DMA32_TXSUSPEND 0x00000002
+#define B43_DMA32_TXLOOPBACK 0x00000004
+#define B43_DMA32_TXFLUSH 0x00000010
+#define B43_DMA32_TXADDREXT_MASK 0x00030000
+#define B43_DMA32_TXADDREXT_SHIFT 16
+#define B43_DMA32_TXRING 0x04
+#define B43_DMA32_TXINDEX 0x08
+#define B43_DMA32_TXSTATUS 0x0C
+#define B43_DMA32_TXDPTR 0x00000FFF
+#define B43_DMA32_TXSTATE 0x0000F000
+#define B43_DMA32_TXSTAT_DISABLED 0x00000000
+#define B43_DMA32_TXSTAT_ACTIVE 0x00001000
+#define B43_DMA32_TXSTAT_IDLEWAIT 0x00002000
+#define B43_DMA32_TXSTAT_STOPPED 0x00003000
+#define B43_DMA32_TXSTAT_SUSP 0x00004000
+#define B43_DMA32_TXERROR 0x000F0000
+#define B43_DMA32_TXERR_NOERR 0x00000000
+#define B43_DMA32_TXERR_PROT 0x00010000
+#define B43_DMA32_TXERR_UNDERRUN 0x00020000
+#define B43_DMA32_TXERR_BUFREAD 0x00030000
+#define B43_DMA32_TXERR_DESCREAD 0x00040000
+#define B43_DMA32_TXACTIVE 0xFFF00000
+#define B43_DMA32_RXCTL 0x10
+#define B43_DMA32_RXENABLE 0x00000001
+#define B43_DMA32_RXFROFF_MASK 0x000000FE
+#define B43_DMA32_RXFROFF_SHIFT 1
+#define B43_DMA32_RXDIRECTFIFO 0x00000100
+#define B43_DMA32_RXADDREXT_MASK 0x00030000
+#define B43_DMA32_RXADDREXT_SHIFT 16
+#define B43_DMA32_RXRING 0x14
+#define B43_DMA32_RXINDEX 0x18
+#define B43_DMA32_RXSTATUS 0x1C
+#define B43_DMA32_RXDPTR 0x00000FFF
+#define B43_DMA32_RXSTATE 0x0000F000
+#define B43_DMA32_RXSTAT_DISABLED 0x00000000
+#define B43_DMA32_RXSTAT_ACTIVE 0x00001000
+#define B43_DMA32_RXSTAT_IDLEWAIT 0x00002000
+#define B43_DMA32_RXSTAT_STOPPED 0x00003000
+#define B43_DMA32_RXERROR 0x000F0000
+#define B43_DMA32_RXERR_NOERR 0x00000000
+#define B43_DMA32_RXERR_PROT 0x00010000
+#define B43_DMA32_RXERR_OVERFLOW 0x00020000
+#define B43_DMA32_RXERR_BUFWRITE 0x00030000
+#define B43_DMA32_RXERR_DESCREAD 0x00040000
+#define B43_DMA32_RXACTIVE 0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct b43_dmadesc32 {
+ __le32 control;
+ __le32 address;
+} __attribute__ ((__packed__));
+#define B43_DMA32_DCTL_BYTECNT 0x00001FFF
+#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000
+#define B43_DMA32_DCTL_ADDREXT_SHIFT 16
+#define B43_DMA32_DCTL_DTABLEEND 0x10000000
+#define B43_DMA32_DCTL_IRQ 0x20000000
+#define B43_DMA32_DCTL_FRAMEEND 0x40000000
+#define B43_DMA32_DCTL_FRAMESTART 0x80000000
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define B43_DMA64_TXCTL 0x00
+#define B43_DMA64_TXENABLE 0x00000001
+#define B43_DMA64_TXSUSPEND 0x00000002
+#define B43_DMA64_TXLOOPBACK 0x00000004
+#define B43_DMA64_TXFLUSH 0x00000010
+#define B43_DMA64_TXADDREXT_MASK 0x00030000
+#define B43_DMA64_TXADDREXT_SHIFT 16
+#define B43_DMA64_TXINDEX 0x04
+#define B43_DMA64_TXRINGLO 0x08
+#define B43_DMA64_TXRINGHI 0x0C
+#define B43_DMA64_TXSTATUS 0x10
+#define B43_DMA64_TXSTATDPTR 0x00001FFF
+#define B43_DMA64_TXSTAT 0xF0000000
+#define B43_DMA64_TXSTAT_DISABLED 0x00000000
+#define B43_DMA64_TXSTAT_ACTIVE 0x10000000
+#define B43_DMA64_TXSTAT_IDLEWAIT 0x20000000
+#define B43_DMA64_TXSTAT_STOPPED 0x30000000
+#define B43_DMA64_TXSTAT_SUSP 0x40000000
+#define B43_DMA64_TXERROR 0x14
+#define B43_DMA64_TXERRDPTR 0x0001FFFF
+#define B43_DMA64_TXERR 0xF0000000
+#define B43_DMA64_TXERR_NOERR 0x00000000
+#define B43_DMA64_TXERR_PROT 0x10000000
+#define B43_DMA64_TXERR_UNDERRUN 0x20000000
+#define B43_DMA64_TXERR_TRANSFER 0x30000000
+#define B43_DMA64_TXERR_DESCREAD 0x40000000
+#define B43_DMA64_TXERR_CORE 0x50000000
+#define B43_DMA64_RXCTL 0x20
+#define B43_DMA64_RXENABLE 0x00000001
+#define B43_DMA64_RXFROFF_MASK 0x000000FE
+#define B43_DMA64_RXFROFF_SHIFT 1
+#define B43_DMA64_RXDIRECTFIFO 0x00000100
+#define B43_DMA64_RXADDREXT_MASK 0x00030000
+#define B43_DMA64_RXADDREXT_SHIFT 16
+#define B43_DMA64_RXINDEX 0x24
+#define B43_DMA64_RXRINGLO 0x28
+#define B43_DMA64_RXRINGHI 0x2C
+#define B43_DMA64_RXSTATUS 0x30
+#define B43_DMA64_RXSTATDPTR 0x00001FFF
+#define B43_DMA64_RXSTAT 0xF0000000
+#define B43_DMA64_RXSTAT_DISABLED 0x00000000
+#define B43_DMA64_RXSTAT_ACTIVE 0x10000000
+#define B43_DMA64_RXSTAT_IDLEWAIT 0x20000000
+#define B43_DMA64_RXSTAT_STOPPED 0x30000000
+#define B43_DMA64_RXSTAT_SUSP 0x40000000
+#define B43_DMA64_RXERROR 0x34
+#define B43_DMA64_RXERRDPTR 0x0001FFFF
+#define B43_DMA64_RXERR 0xF0000000
+#define B43_DMA64_RXERR_NOERR 0x00000000
+#define B43_DMA64_RXERR_PROT 0x10000000
+#define B43_DMA64_RXERR_UNDERRUN 0x20000000
+#define B43_DMA64_RXERR_TRANSFER 0x30000000
+#define B43_DMA64_RXERR_DESCREAD 0x40000000
+#define B43_DMA64_RXERR_CORE 0x50000000
+
+/* 64-bit DMA descriptor. */
+struct b43_dmadesc64 {
+ __le32 control0;
+ __le32 control1;
+ __le32 address_low;
+ __le32 address_high;
+} __attribute__ ((__packed__));
+#define B43_DMA64_DCTL0_DTABLEEND 0x10000000
+#define B43_DMA64_DCTL0_IRQ 0x20000000
+#define B43_DMA64_DCTL0_FRAMEEND 0x40000000
+#define B43_DMA64_DCTL0_FRAMESTART 0x80000000
+#define B43_DMA64_DCTL1_BYTECNT 0x00001FFF
+#define B43_DMA64_DCTL1_ADDREXT_MASK 0x00030000
+#define B43_DMA64_DCTL1_ADDREXT_SHIFT 16
+
+struct b43_dmadesc_generic {
+ union {
+ struct b43_dmadesc32 dma32;
+ struct b43_dmadesc64 dma64;
+ } __attribute__ ((__packed__));
+} __attribute__ ((__packed__));
+
+/* Misc DMA constants */
+#define B43_DMA_RINGMEMSIZE PAGE_SIZE
+#define B43_DMA0_RX_FRAMEOFFSET 30
+#define B43_DMA3_RX_FRAMEOFFSET 0
+
+/* DMA engine tuning knobs */
+#define B43_TXRING_SLOTS 128
+#define B43_RXRING_SLOTS 64
+#define B43_DMA0_RX_BUFFERSIZE (2304 + 100)
+#define B43_DMA3_RX_BUFFERSIZE 16
+
+#ifdef CONFIG_B43_DMA
+
+struct sk_buff;
+struct b43_private;
+struct b43_txstatus;
+
+struct b43_dmadesc_meta {
+ /* The kernel DMA-able buffer. */
+ struct sk_buff *skb;
+ /* DMA base bus-address of the descriptor buffer. */
+ dma_addr_t dmaaddr;
+ /* ieee80211 TX status. Only used once per 802.11 frag. */
+ bool is_last_fragment;
+ struct ieee80211_tx_status txstat;
+};
+
+struct b43_dmaring;
+
+/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
+struct b43_dma_ops {
+ struct b43_dmadesc_generic *(*idx2desc) (struct b43_dmaring * ring,
+ int slot,
+ struct b43_dmadesc_meta **
+ meta);
+ void (*fill_descriptor) (struct b43_dmaring * ring,
+ struct b43_dmadesc_generic * desc,
+ dma_addr_t dmaaddr, u16 bufsize, int start,
+ int end, int irq);
+ void (*poke_tx) (struct b43_dmaring * ring, int slot);
+ void (*tx_suspend) (struct b43_dmaring * ring);
+ void (*tx_resume) (struct b43_dmaring * ring);
+ int (*get_current_rxslot) (struct b43_dmaring * ring);
+ void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
+};
+
+struct b43_dmaring {
+ /* Lowlevel DMA ops. */
+ const struct b43_dma_ops *ops;
+ /* Kernel virtual base address of the ring memory. */
+ void *descbase;
+ /* Meta data about all descriptors. */
+ struct b43_dmadesc_meta *meta;
+ /* Cache of TX headers for each slot.
+ * This is to avoid an allocation on each TX.
+ * This is NULL for an RX ring.
+ */
+ u8 *txhdr_cache;
+ /* (Unadjusted) DMA base bus-address of the ring memory. */
+ dma_addr_t dmabase;
+ /* Number of descriptor slots in the ring. */
+ int nr_slots;
+ /* Number of used descriptor slots. */
+ int used_slots;
+ /* Currently used slot in the ring. */
+ int current_slot;
+ /* Total number of packets sent. Statistics only. */
+ unsigned int nr_tx_packets;
+ /* Frameoffset in octets. */
+ u32 frameoffset;
+ /* Descriptor buffer size. */
+ u16 rx_buffersize;
+ /* The MMIO base register of the DMA controller. */
+ u16 mmio_base;
+ /* DMA controller index number (0-5). */
+ int index;
+ /* Boolean. Is this a TX ring? */
+ bool tx;
+ /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+ bool dma64;
+ /* Boolean. Is this ring stopped at ieee80211 level? */
+ bool stopped;
+ /* Lock, only used for TX. */
+ spinlock_t lock;
+ struct b43_wldev *dev;
+#ifdef CONFIG_B43_DEBUG
+ /* Maximum number of used slots. */
+ int max_used_slots;
+ /* Last time we injected a ring overflow. */
+ unsigned long last_injected_overflow;
+#endif /* CONFIG_B43_DEBUG */
+};
+
+static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
+{
+ return b43_read32(ring->dev, ring->mmio_base + offset);
+}
+
+static inline
+ void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+{
+ b43_write32(ring->dev, ring->mmio_base + offset, value);
+}
+
+int b43_dma_init(struct b43_wldev *dev);
+void b43_dma_free(struct b43_wldev *dev);
+
+int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64);
+int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64);
+
+u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+void b43_dma_tx_suspend(struct b43_wldev *dev);
+void b43_dma_tx_resume(struct b43_wldev *dev);
+
+void b43_dma_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+
+int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+
+void b43_dma_rx(struct b43_dmaring *ring);
+
+#else /* CONFIG_B43_DMA */
+
+static inline int b43_dma_init(struct b43_wldev *dev)
+{
+ return 0;
+}
+static inline void b43_dma_free(struct b43_wldev *dev)
+{
+}
+static inline
+ int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64)
+{
+ return 0;
+}
+static inline
+ int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64)
+{
+ return 0;
+}
+static inline
+ void b43_dma_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+ int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+ void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+}
+static inline void b43_dma_rx(struct b43_dmaring *ring)
+{
+}
+static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
+{
+}
+static inline void b43_dma_tx_resume(struct b43_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43_DMA */
+#endif /* B43_DMA_H_ */
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
new file mode 100644
index 000000000000..19e588582c7c
--- /dev/null
+++ b/drivers/net/wireless/b43/leds.c
@@ -0,0 +1,235 @@
+/*
+
+ Broadcom B43 wireless driver
+ LED control
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "leds.h"
+
+
+static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
+ bool activelow)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned long flags;
+ u16 ctl;
+
+ spin_lock_irqsave(&wl->leds_lock, flags);
+ ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
+ if (activelow)
+ ctl &= ~(1 << led_index);
+ else
+ ctl |= (1 << led_index);
+ b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
+ spin_unlock_irqrestore(&wl->leds_lock, flags);
+}
+
+static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
+ bool activelow)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned long flags;
+ u16 ctl;
+
+ spin_lock_irqsave(&wl->leds_lock, flags);
+ ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
+ if (activelow)
+ ctl |= (1 << led_index);
+ else
+ ctl &= ~(1 << led_index);
+ b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
+ spin_unlock_irqrestore(&wl->leds_lock, flags);
+}
+
+/* Callback from the LED subsystem. */
+static void b43_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
+ struct b43_wldev *dev = led->dev;
+ bool radio_enabled;
+
+ /* Checking the radio-enabled status here is slightly racy,
+ * but we want to avoid the locking overhead and we don't care
+ * whether the LED has the wrong state for a second. */
+ radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
+
+ if (brightness == LED_OFF || !radio_enabled)
+ b43_led_turn_off(dev, led->index, led->activelow);
+ else
+ b43_led_turn_on(dev, led->index, led->activelow);
+}
+
+static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
+ const char *name, char *default_trigger,
+ u8 led_index, bool activelow)
+{
+ int err;
+
+ b43_led_turn_off(dev, led_index, activelow);
+ if (led->dev)
+ return -EEXIST;
+ if (!default_trigger)
+ return -EINVAL;
+ led->dev = dev;
+ led->index = led_index;
+ led->activelow = activelow;
+ strncpy(led->name, name, sizeof(led->name));
+
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = default_trigger;
+ led->led_dev.brightness_set = b43_led_brightness_set;
+
+ err = led_classdev_register(dev->dev->dev, &led->led_dev);
+ if (err) {
+ b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
+ led->dev = NULL;
+ return err;
+ }
+ return 0;
+}
+
+static void b43_unregister_led(struct b43_led *led)
+{
+ if (!led->dev)
+ return;
+ led_classdev_unregister(&led->led_dev);
+ b43_led_turn_off(led->dev, led->index, led->activelow);
+ led->dev = NULL;
+}
+
+static void b43_map_led(struct b43_wldev *dev,
+ u8 led_index,
+ enum b43_led_behaviour behaviour,
+ bool activelow)
+{
+ struct ieee80211_hw *hw = dev->wl->hw;
+ char name[B43_LED_MAX_NAME_LEN + 1];
+
+ /* Map the b43 specific LED behaviour value to the
+ * generic LED triggers. */
+ switch (behaviour) {
+ case B43_LED_INACTIVE:
+ break;
+ case B43_LED_OFF:
+ b43_led_turn_off(dev, led_index, activelow);
+ break;
+ case B43_LED_ON:
+ b43_led_turn_on(dev, led_index, activelow);
+ break;
+ case B43_LED_ACTIVITY:
+ case B43_LED_TRANSFER:
+ case B43_LED_APTRANSFER:
+ snprintf(name, sizeof(name),
+ "b43-%s:tx", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_tx, name,
+ ieee80211_get_tx_led_name(hw),
+ led_index, activelow);
+ snprintf(name, sizeof(name),
+ "b43-%s:rx", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_rx, name,
+ ieee80211_get_rx_led_name(hw),
+ led_index, activelow);
+ break;
+ case B43_LED_RADIO_ALL:
+ case B43_LED_RADIO_A:
+ case B43_LED_RADIO_B:
+ case B43_LED_MODE_BG:
+ snprintf(name, sizeof(name),
+ "b43-%s:radio", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_radio, name,
+ b43_rfkill_led_name(dev),
+ led_index, activelow);
+ break;
+ case B43_LED_WEIRD:
+ case B43_LED_ASSOC:
+ snprintf(name, sizeof(name),
+ "b43-%s:assoc", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_assoc, name,
+ ieee80211_get_assoc_led_name(hw),
+ led_index, activelow);
+ break;
+ default:
+ b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n",
+ behaviour);
+ break;
+ }
+}
+
+void b43_leds_init(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ u8 sprom[4];
+ int i;
+ enum b43_led_behaviour behaviour;
+ bool activelow;
+
+ sprom[0] = bus->sprom.r1.gpio0;
+ sprom[1] = bus->sprom.r1.gpio1;
+ sprom[2] = bus->sprom.r1.gpio2;
+ sprom[3] = bus->sprom.r1.gpio3;
+
+ for (i = 0; i < 4; i++) {
+ if (sprom[i] == 0xFF) {
+ /* There is no LED information in the SPROM
+ * for this LED. Hardcode it here. */
+ activelow = 0;
+ switch (i) {
+ case 0:
+ behaviour = B43_LED_ACTIVITY;
+ activelow = 1;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+ behaviour = B43_LED_RADIO_ALL;
+ break;
+ case 1:
+ behaviour = B43_LED_RADIO_B;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+ behaviour = B43_LED_ASSOC;
+ break;
+ case 2:
+ behaviour = B43_LED_RADIO_A;
+ break;
+ case 3:
+ behaviour = B43_LED_OFF;
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+ } else {
+ behaviour = sprom[i] & B43_LED_BEHAVIOUR;
+ activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
+ }
+ b43_map_led(dev, i, behaviour, activelow);
+ }
+}
+
+void b43_leds_exit(struct b43_wldev *dev)
+{
+ b43_unregister_led(&dev->led_tx);
+ b43_unregister_led(&dev->led_rx);
+ b43_unregister_led(&dev->led_assoc);
+}
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h
new file mode 100644
index 000000000000..b8b1dd521243
--- /dev/null
+++ b/drivers/net/wireless/b43/leds.h
@@ -0,0 +1,64 @@
+#ifndef B43_LEDS_H_
+#define B43_LEDS_H_
+
+struct b43_wldev;
+
+#ifdef CONFIG_B43_LEDS
+
+#include <linux/types.h>
+#include <linux/leds.h>
+
+
+#define B43_LED_MAX_NAME_LEN 31
+
+struct b43_led {
+ struct b43_wldev *dev;
+ /* The LED class device */
+ struct led_classdev led_dev;
+ /* The index number of the LED. */
+ u8 index;
+ /* If activelow is true, the LED is ON if the
+ * bit is switched off. */
+ bool activelow;
+ /* The unique name string for this LED device. */
+ char name[B43_LED_MAX_NAME_LEN + 1];
+};
+
+#define B43_LED_BEHAVIOUR 0x7F
+#define B43_LED_ACTIVELOW 0x80
+/* LED behaviour values */
+enum b43_led_behaviour {
+ B43_LED_OFF,
+ B43_LED_ON,
+ B43_LED_ACTIVITY,
+ B43_LED_RADIO_ALL,
+ B43_LED_RADIO_A,
+ B43_LED_RADIO_B,
+ B43_LED_MODE_BG,
+ B43_LED_TRANSFER,
+ B43_LED_APTRANSFER,
+ B43_LED_WEIRD, //FIXME
+ B43_LED_ASSOC,
+ B43_LED_INACTIVE,
+};
+
+void b43_leds_init(struct b43_wldev *dev);
+void b43_leds_exit(struct b43_wldev *dev);
+
+
+#else /* CONFIG_B43_LEDS */
+/* LED support disabled */
+
+struct b43_led {
+ /* empty */
+};
+
+static inline void b43_leds_init(struct b43_wldev *dev)
+{
+}
+static inline void b43_leds_exit(struct b43_wldev *dev)
+{
+}
+#endif /* CONFIG_B43_LEDS */
+
+#endif /* B43_LEDS_H_ */
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
new file mode 100644
index 000000000000..b14a1753a0d7
--- /dev/null
+++ b/drivers/net/wireless/b43/lo.c
@@ -0,0 +1,1261 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ G PHY LO (LocalOscillator) Measuring and Control routines
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "lo.h"
+#include "phy.h"
+#include "main.h"
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+
+/* Define to 1 to always calibrate all possible LO control pairs.
+ * This is a workaround until we fix the partial LO calibration optimization. */
+#define B43_CALIB_ALL_LOCTLS 1
+
+
+/* Write the LocalOscillator Control (adjust) value-pair. */
+static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 value;
+ u16 reg;
+
+ if (B43_DEBUG) {
+ if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
+ b43dbg(dev->wl, "Invalid LO control pair "
+ "(I: %d, Q: %d)\n", control->i, control->q);
+ dump_stack();
+ return;
+ }
+ }
+
+ value = (u8) (control->q);
+ value |= ((u8) (control->i)) << 8;
+
+ reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
+ b43_phy_write(dev, reg, value);
+}
+
+static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt,
+ struct b43_wldev *dev)
+{
+ int err = 0;
+
+ /* Check the attenuation values against the LO control array sizes. */
+ if (unlikely(rfatt->att >= B43_NR_RF)) {
+ b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
+ err = -EINVAL;
+ }
+ if (unlikely(bbatt->att >= B43_NR_BB)) {
+ b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+#if !B43_CALIB_ALL_LOCTLS
+static
+struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
+ const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
+ return &(lo->no_padmix[0][0]); /* Just prevent a crash */
+ return &(lo->no_padmix[bbatt->att][rfatt->att]);
+}
+#endif /* !B43_CALIB_ALL_LOCTLS */
+
+struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
+ const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
+ return &(lo->no_padmix[0][0]); /* Just prevent a crash */
+ if (rfatt->with_padmix)
+ return &(lo->with_padmix[bbatt->att][rfatt->att]);
+ return &(lo->no_padmix[bbatt->att][rfatt->att]);
+}
+
+/* Call a function for every possible LO control value-pair. */
+static void b43_call_for_each_loctl(struct b43_wldev *dev,
+ void (*func) (struct b43_wldev *,
+ struct b43_loctl *))
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *ctl = phy->lo_control;
+ int i, j;
+
+ for (i = 0; i < B43_NR_BB; i++) {
+ for (j = 0; j < B43_NR_RF; j++)
+ func(dev, &(ctl->with_padmix[i][j]));
+ }
+ for (i = 0; i < B43_NR_BB; i++) {
+ for (j = 0; j < B43_NR_RF; j++)
+ func(dev, &(ctl->no_padmix[i][j]));
+ }
+}
+
+static u16 lo_b_r15_loop(struct b43_wldev *dev)
+{
+ int i;
+ u16 ret = 0;
+
+ for (i = 0; i < 10; i++) {
+ b43_phy_write(dev, 0x0015, 0xAFA0);
+ udelay(1);
+ b43_phy_write(dev, 0x0015, 0xEFA0);
+ udelay(10);
+ b43_phy_write(dev, 0x0015, 0xFFA0);
+ udelay(40);
+ ret += b43_phy_read(dev, 0x002C);
+ }
+
+ return ret;
+}
+
+void b43_lo_b_measure(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 regstack[12] = { 0 };
+ u16 mls;
+ u16 fval;
+ int i, j;
+
+ regstack[0] = b43_phy_read(dev, 0x0015);
+ regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
+
+ if (phy->radio_ver == 0x2053) {
+ regstack[2] = b43_phy_read(dev, 0x000A);
+ regstack[3] = b43_phy_read(dev, 0x002A);
+ regstack[4] = b43_phy_read(dev, 0x0035);
+ regstack[5] = b43_phy_read(dev, 0x0003);
+ regstack[6] = b43_phy_read(dev, 0x0001);
+ regstack[7] = b43_phy_read(dev, 0x0030);
+
+ regstack[8] = b43_radio_read16(dev, 0x0043);
+ regstack[9] = b43_radio_read16(dev, 0x007A);
+ regstack[10] = b43_read16(dev, 0x03EC);
+ regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
+
+ b43_phy_write(dev, 0x0030, 0x00FF);
+ b43_write16(dev, 0x03EC, 0x3F3F);
+ b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
+ b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
+ }
+ b43_phy_write(dev, 0x0015, 0xB000);
+ b43_phy_write(dev, 0x002B, 0x0004);
+
+ if (phy->radio_ver == 0x2053) {
+ b43_phy_write(dev, 0x002B, 0x0203);
+ b43_phy_write(dev, 0x002A, 0x08A3);
+ }
+
+ phy->minlowsig[0] = 0xFFFF;
+
+ for (i = 0; i < 4; i++) {
+ b43_radio_write16(dev, 0x0052, regstack[1] | i);
+ lo_b_r15_loop(dev);
+ }
+ for (i = 0; i < 10; i++) {
+ b43_radio_write16(dev, 0x0052, regstack[1] | i);
+ mls = lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[0]) {
+ phy->minlowsig[0] = mls;
+ phy->minlowsigpos[0] = i;
+ }
+ }
+ b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
+
+ phy->minlowsig[1] = 0xFFFF;
+
+ for (i = -4; i < 5; i += 2) {
+ for (j = -4; j < 5; j += 2) {
+ if (j < 0)
+ fval = (0x0100 * i) + j + 0x0100;
+ else
+ fval = (0x0100 * i) + j;
+ b43_phy_write(dev, 0x002F, fval);
+ mls = lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[1]) {
+ phy->minlowsig[1] = mls;
+ phy->minlowsigpos[1] = fval;
+ }
+ }
+ }
+ phy->minlowsigpos[1] += 0x0101;
+
+ b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
+ if (phy->radio_ver == 0x2053) {
+ b43_phy_write(dev, 0x000A, regstack[2]);
+ b43_phy_write(dev, 0x002A, regstack[3]);
+ b43_phy_write(dev, 0x0035, regstack[4]);
+ b43_phy_write(dev, 0x0003, regstack[5]);
+ b43_phy_write(dev, 0x0001, regstack[6]);
+ b43_phy_write(dev, 0x0030, regstack[7]);
+
+ b43_radio_write16(dev, 0x0043, regstack[8]);
+ b43_radio_write16(dev, 0x007A, regstack[9]);
+
+ b43_radio_write16(dev, 0x0052,
+ (b43_radio_read16(dev, 0x0052) & 0x000F)
+ | regstack[11]);
+
+ b43_write16(dev, 0x03EC, regstack[10]);
+ }
+ b43_phy_write(dev, 0x0015, regstack[0]);
+}
+
+static u16 lo_measure_feedthrough(struct b43_wldev *dev,
+ u16 lna, u16 pga, u16 trsw_rx)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 rfover;
+ u16 feedthrough;
+
+ if (phy->gmode) {
+ lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT;
+ pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT;
+
+ B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA);
+ B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA);
+/*FIXME This assertion fails B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX |
+ B43_PHY_RFOVERVAL_BW));
+*/
+ trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW);
+
+ /* Construct the RF Override Value */
+ rfover = B43_PHY_RFOVERVAL_UNK;
+ rfover |= pga;
+ rfover |= lna;
+ rfover |= trsw_rx;
+ if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
+ phy->rev > 6)
+ rfover |= B43_PHY_RFOVERVAL_EXTLNA;
+
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+ udelay(10);
+ rfover |= B43_PHY_RFOVERVAL_BW_LBW;
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+ udelay(10);
+ rfover |= B43_PHY_RFOVERVAL_BW_LPF;
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+ udelay(10);
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xF300);
+ } else {
+ pga |= B43_PHY_PGACTL_UNKNOWN;
+ b43_phy_write(dev, B43_PHY_PGACTL, pga);
+ udelay(10);
+ pga |= B43_PHY_PGACTL_LOWBANDW;
+ b43_phy_write(dev, B43_PHY_PGACTL, pga);
+ udelay(10);
+ pga |= B43_PHY_PGACTL_LPF;
+ b43_phy_write(dev, B43_PHY_PGACTL, pga);
+ }
+ udelay(21);
+ feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+
+ /* This is a good place to check if we need to relax a bit,
+ * as this is the main function called regularly
+ * in the LO calibration. */
+ cond_resched();
+
+ return feedthrough;
+}
+
+/* TXCTL Register and Value Table.
+ * Returns the "TXCTL Register".
+ * "value" is the "TXCTL Value".
+ * "pad_mix_gain" is the PAD Mixer Gain.
+ */
+static u16 lo_txctl_register_table(struct b43_wldev *dev,
+ u16 * value, u16 * pad_mix_gain)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 reg, v, padmix;
+
+ if (phy->type == B43_PHYTYPE_B) {
+ v = 0x30;
+ if (phy->radio_rev <= 5) {
+ reg = 0x43;
+ padmix = 0;
+ } else {
+ reg = 0x52;
+ padmix = 5;
+ }
+ } else {
+ if (phy->rev >= 2 && phy->radio_rev == 8) {
+ reg = 0x43;
+ v = 0x10;
+ padmix = 2;
+ } else {
+ reg = 0x52;
+ v = 0x30;
+ padmix = 5;
+ }
+ }
+ if (value)
+ *value = v;
+ if (pad_mix_gain)
+ *pad_mix_gain = padmix;
+
+ return reg;
+}
+
+static void lo_measure_txctl_values(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 reg, mask;
+ u16 trsw_rx, pga;
+ u16 radio_pctl_reg;
+
+ static const u8 tx_bias_values[] = {
+ 0x09, 0x08, 0x0A, 0x01, 0x00,
+ 0x02, 0x05, 0x04, 0x06,
+ };
+ static const u8 tx_magn_values[] = {
+ 0x70, 0x40,
+ };
+
+ if (!has_loopback_gain(phy)) {
+ radio_pctl_reg = 6;
+ trsw_rx = 2;
+ pga = 0;
+ } else {
+ int lb_gain; /* Loopback gain (in dB) */
+
+ trsw_rx = 0;
+ lb_gain = phy->max_lb_gain / 2;
+ if (lb_gain > 10) {
+ radio_pctl_reg = 0;
+ pga = abs(10 - lb_gain) / 6;
+ pga = limit_value(pga, 0, 15);
+ } else {
+ int cmp_val;
+ int tmp;
+
+ pga = 0;
+ cmp_val = 0x24;
+ if ((phy->rev >= 2) &&
+ (phy->radio_ver == 0x2050) && (phy->radio_rev == 8))
+ cmp_val = 0x3C;
+ tmp = lb_gain;
+ if ((10 - lb_gain) < cmp_val)
+ tmp = (10 - lb_gain);
+ if (tmp < 0)
+ tmp += 6;
+ else
+ tmp += 3;
+ cmp_val /= 4;
+ tmp /= 4;
+ if (tmp >= cmp_val)
+ radio_pctl_reg = cmp_val;
+ else
+ radio_pctl_reg = tmp;
+ }
+ }
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | radio_pctl_reg);
+ b43_phy_set_baseband_attenuation(dev, 2);
+
+ reg = lo_txctl_register_table(dev, &mask, NULL);
+ mask = ~mask;
+ b43_radio_write16(dev, reg, b43_radio_read16(dev, reg)
+ & mask);
+
+ if (has_tx_magnification(phy)) {
+ int i, j;
+ int feedthrough;
+ int min_feedth = 0xFFFF;
+ u8 tx_magn, tx_bias;
+
+ for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {
+ tx_magn = tx_magn_values[i];
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52)
+ & 0xFF0F) | tx_magn);
+ for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {
+ tx_bias = tx_bias_values[j];
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52)
+ & 0xFFF0) | tx_bias);
+ feedthrough =
+ lo_measure_feedthrough(dev, 0, pga,
+ trsw_rx);
+ if (feedthrough < min_feedth) {
+ lo->tx_bias = tx_bias;
+ lo->tx_magn = tx_magn;
+ min_feedth = feedthrough;
+ }
+ if (lo->tx_bias == 0)
+ break;
+ }
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52)
+ & 0xFF00) | lo->tx_bias | lo->
+ tx_magn);
+ }
+ } else {
+ lo->tx_magn = 0;
+ lo->tx_bias = 0;
+ b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
+ & 0xFFF0); /* TX bias == 0 */
+ }
+}
+
+static void lo_read_power_vector(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 i;
+ u64 tmp;
+ u64 power_vector = 0;
+ int rf_offset, bb_offset;
+ struct b43_loctl *loctl;
+
+ for (i = 0; i < 8; i += 2) {
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
+ /* Clear the top byte. We get holes in the bitmap... */
+ tmp &= 0xFF;
+ power_vector |= (tmp << (i * 8));
+ /* Clear the vector on the device. */
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
+ }
+
+ if (power_vector)
+ lo->power_vector = power_vector;
+ power_vector = lo->power_vector;
+
+ for (i = 0; i < 64; i++) {
+ if (power_vector & ((u64) 1ULL << i)) {
+ /* Now figure out which b43_loctl corresponds
+ * to this bit.
+ */
+ rf_offset = i / lo->rfatt_list.len;
+ bb_offset = i % lo->rfatt_list.len; //FIXME?
+ loctl =
+ b43_get_lo_g_ctl(dev,
+ &lo->rfatt_list.list[rf_offset],
+ &lo->bbatt_list.list[bb_offset]);
+ /* And mark it as "used", as the device told us
+ * through the bitmap it is using it.
+ */
+ loctl->used = 1;
+ }
+ }
+}
+
+/* 802.11/LO/GPHY/MeasuringGains */
+static void lo_measure_gain_values(struct b43_wldev *dev,
+ s16 max_rx_gain, int use_trsw_rx)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (max_rx_gain < 0)
+ max_rx_gain = 0;
+
+ if (has_loopback_gain(phy)) {
+ int trsw_rx = 0;
+ int trsw_rx_gain;
+
+ if (use_trsw_rx) {
+ trsw_rx_gain = phy->trsw_rx_gain / 2;
+ if (max_rx_gain >= trsw_rx_gain) {
+ trsw_rx_gain = max_rx_gain - trsw_rx_gain;
+ trsw_rx = 0x20;
+ }
+ } else
+ trsw_rx_gain = max_rx_gain;
+ if (trsw_rx_gain < 9) {
+ phy->lna_lod_gain = 0;
+ } else {
+ phy->lna_lod_gain = 1;
+ trsw_rx_gain -= 8;
+ }
+ trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D);
+ phy->pga_gain = trsw_rx_gain / 3;
+ if (phy->pga_gain >= 5) {
+ phy->pga_gain -= 5;
+ phy->lna_gain = 2;
+ } else
+ phy->lna_gain = 0;
+ } else {
+ phy->lna_gain = 0;
+ phy->trsw_rx_gain = 0x20;
+ if (max_rx_gain >= 0x14) {
+ phy->lna_lod_gain = 1;
+ phy->pga_gain = 2;
+ } else if (max_rx_gain >= 0x12) {
+ phy->lna_lod_gain = 1;
+ phy->pga_gain = 1;
+ } else if (max_rx_gain >= 0xF) {
+ phy->lna_lod_gain = 1;
+ phy->pga_gain = 0;
+ } else {
+ phy->lna_lod_gain = 0;
+ phy->pga_gain = 0;
+ }
+ }
+
+ tmp = b43_radio_read16(dev, 0x7A);
+ if (phy->lna_lod_gain == 0)
+ tmp &= ~0x0008;
+ else
+ tmp |= 0x0008;
+ b43_radio_write16(dev, 0x7A, tmp);
+}
+
+struct lo_g_saved_values {
+ u8 old_channel;
+
+ /* Core registers */
+ u16 reg_3F4;
+ u16 reg_3E2;
+
+ /* PHY registers */
+ u16 phy_lo_mask;
+ u16 phy_extg_01;
+ u16 phy_dacctl_hwpctl;
+ u16 phy_dacctl;
+ u16 phy_base_14;
+ u16 phy_hpwr_tssictl;
+ u16 phy_analogover;
+ u16 phy_analogoverval;
+ u16 phy_rfover;
+ u16 phy_rfoverval;
+ u16 phy_classctl;
+ u16 phy_base_3E;
+ u16 phy_crs0;
+ u16 phy_pgactl;
+ u16 phy_base_2A;
+ u16 phy_syncctl;
+ u16 phy_base_30;
+ u16 phy_base_06;
+
+ /* Radio registers */
+ u16 radio_43;
+ u16 radio_7A;
+ u16 radio_52;
+};
+
+static void lo_measure_setup(struct b43_wldev *dev,
+ struct lo_g_saved_values *sav)
+{
+ struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 tmp;
+
+ if (b43_has_hardware_pctl(phy)) {
+ sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+ sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
+ sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
+ sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
+ sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
+
+ b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
+ b43_phy_read(dev, B43_PHY_HPWR_TSSICTL)
+ | 0x100);
+ b43_phy_write(dev, B43_PHY_EXTG(0x01),
+ b43_phy_read(dev, B43_PHY_EXTG(0x01))
+ | 0x40);
+ b43_phy_write(dev, B43_PHY_DACCTL,
+ b43_phy_read(dev, B43_PHY_DACCTL)
+ | 0x40);
+ b43_phy_write(dev, B43_PHY_BASE(0x14),
+ b43_phy_read(dev, B43_PHY_BASE(0x14))
+ | 0x200);
+ }
+ if (phy->type == B43_PHYTYPE_B &&
+ phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
+ b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
+ b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
+ }
+ if (!lo->rebuild && b43_has_hardware_pctl(phy))
+ lo_read_power_vector(dev);
+ if (phy->rev >= 2) {
+ sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+ sav->phy_analogoverval =
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+ sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+ sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+ sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
+ sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+
+ b43_phy_write(dev, B43_PHY_CLASSCTL,
+ b43_phy_read(dev, B43_PHY_CLASSCTL)
+ & 0xFFFC);
+ b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+ & 0x7FFF);
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER)
+ | 0x0003);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+ & 0xFFFC);
+ if (phy->type == B43_PHYTYPE_G) {
+ if ((phy->rev >= 7) &&
+ (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
+ } else {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
+ }
+ } else {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
+ }
+ sav->reg_3F4 = b43_read16(dev, 0x3F4);
+ sav->reg_3E2 = b43_read16(dev, 0x3E2);
+ sav->radio_43 = b43_radio_read16(dev, 0x43);
+ sav->radio_7A = b43_radio_read16(dev, 0x7A);
+ sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+ sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
+ sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+ sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
+
+ if (!has_tx_magnification(phy)) {
+ sav->radio_52 = b43_radio_read16(dev, 0x52);
+ sav->radio_52 &= 0x00F0;
+ }
+ if (phy->type == B43_PHYTYPE_B) {
+ sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+ sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
+ b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
+ b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
+ } else {
+ b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
+ | 0x8000);
+ }
+ b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4)
+ & 0xF000);
+
+ tmp =
+ (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
+ b43_phy_write(dev, tmp, 0x007F);
+
+ tmp = sav->phy_syncctl;
+ b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F);
+ tmp = sav->radio_7A;
+ b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
+ if (phy->type == B43_PHYTYPE_G ||
+ (phy->type == B43_PHYTYPE_B &&
+ phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
+ } else
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
+ if (phy->rev >= 2)
+ b43_dummy_transmission(dev);
+ b43_radio_selectchannel(dev, 6, 0);
+ b43_radio_read16(dev, 0x51); /* dummy read */
+ if (phy->type == B43_PHYTYPE_G)
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
+ if (lo->rebuild)
+ lo_measure_txctl_values(dev);
+ if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
+ } else {
+ if (phy->type == B43_PHYTYPE_B)
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+ else
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+ }
+}
+
+static void lo_measure_restore(struct b43_wldev *dev,
+ struct lo_g_saved_values *sav)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 tmp;
+
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
+ tmp = (phy->pga_gain << 8);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
+ udelay(5);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
+ udelay(2);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
+ } else {
+ tmp = (phy->pga_gain | 0xEFA0);
+ b43_phy_write(dev, B43_PHY_PGACTL, tmp);
+ }
+ if (b43_has_hardware_pctl(phy)) {
+ b43_gphy_dc_lt_init(dev);
+ } else {
+ if (lo->rebuild)
+ b43_lo_g_adjust_to(dev, 3, 2, 0);
+ else
+ b43_lo_g_adjust(dev);
+ }
+ if (phy->type == B43_PHYTYPE_G) {
+ if (phy->rev >= 3)
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+ if (phy->rev >= 2)
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
+ }
+ b43_write16(dev, 0x3F4, sav->reg_3F4);
+ b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
+ b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
+ b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
+ b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
+ b43_radio_write16(dev, 0x43, sav->radio_43);
+ b43_radio_write16(dev, 0x7A, sav->radio_7A);
+ if (!has_tx_magnification(phy)) {
+ tmp = sav->radio_52;
+ b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+ & 0xFF0F) | tmp);
+ }
+ b43_write16(dev, 0x3E2, sav->reg_3E2);
+ if (phy->type == B43_PHYTYPE_B &&
+ phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
+ b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
+ b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
+ }
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ sav->phy_analogoverval);
+ b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
+ b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
+ b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
+ b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
+ }
+ if (b43_has_hardware_pctl(phy)) {
+ tmp = (sav->phy_lo_mask & 0xBFFF);
+ b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
+ b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
+ b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
+ b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
+ b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
+ }
+ b43_radio_selectchannel(dev, sav->old_channel, 1);
+}
+
+struct b43_lo_g_statemachine {
+ int current_state;
+ int nr_measured;
+ int state_val_multiplier;
+ u16 lowest_feedth;
+ struct b43_loctl min_loctl;
+};
+
+/* Loop over each possible value in this state. */
+static int lo_probe_possible_loctls(struct b43_wldev *dev,
+ struct b43_loctl *probe_loctl,
+ struct b43_lo_g_statemachine *d)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_loctl test_loctl;
+ struct b43_loctl orig_loctl;
+ struct b43_loctl prev_loctl = {
+ .i = -100,
+ .q = -100,
+ };
+ int i;
+ int begin, end;
+ int found_lower = 0;
+ u16 feedth;
+
+ static const struct b43_loctl modifiers[] = {
+ {.i = 1,.q = 1,},
+ {.i = 1,.q = 0,},
+ {.i = 1,.q = -1,},
+ {.i = 0,.q = -1,},
+ {.i = -1,.q = -1,},
+ {.i = -1,.q = 0,},
+ {.i = -1,.q = 1,},
+ {.i = 0,.q = 1,},
+ };
+
+ if (d->current_state == 0) {
+ begin = 1;
+ end = 8;
+ } else if (d->current_state % 2 == 0) {
+ begin = d->current_state - 1;
+ end = d->current_state + 1;
+ } else {
+ begin = d->current_state - 2;
+ end = d->current_state + 2;
+ }
+ if (begin < 1)
+ begin += 8;
+ if (end > 8)
+ end -= 8;
+
+ memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl));
+ i = begin;
+ d->current_state = i;
+ while (1) {
+ B43_WARN_ON(!(i >= 1 && i <= 8));
+ memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl));
+ test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier;
+ test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier;
+ if ((test_loctl.i != prev_loctl.i ||
+ test_loctl.q != prev_loctl.q) &&
+ (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
+ b43_lo_write(dev, &test_loctl);
+ feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+ phy->pga_gain,
+ phy->trsw_rx_gain);
+ if (feedth < d->lowest_feedth) {
+ memcpy(probe_loctl, &test_loctl,
+ sizeof(struct b43_loctl));
+ found_lower = 1;
+ d->lowest_feedth = feedth;
+ if ((d->nr_measured < 2) &&
+ (!has_loopback_gain(phy) || lo->rebuild))
+ break;
+ }
+ }
+ memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl));
+ if (i == end)
+ break;
+ if (i == 8)
+ i = 1;
+ else
+ i++;
+ d->current_state = i;
+ }
+
+ return found_lower;
+}
+
+static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
+ struct b43_loctl *loctl,
+ int *max_rx_gain)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_lo_g_statemachine d;
+ u16 feedth;
+ int found_lower;
+ struct b43_loctl probe_loctl;
+ int max_repeat = 1, repeat_cnt = 0;
+
+ d.nr_measured = 0;
+ d.state_val_multiplier = 1;
+ if (has_loopback_gain(phy) && !lo->rebuild)
+ d.state_val_multiplier = 3;
+
+ memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
+ if (has_loopback_gain(phy) && lo->rebuild)
+ max_repeat = 4;
+ do {
+ b43_lo_write(dev, &d.min_loctl);
+ feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+ phy->pga_gain,
+ phy->trsw_rx_gain);
+ if (!lo->rebuild && feedth < 0x258) {
+ if (feedth >= 0x12C)
+ *max_rx_gain += 6;
+ else
+ *max_rx_gain += 3;
+ feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+ phy->pga_gain,
+ phy->trsw_rx_gain);
+ }
+ d.lowest_feedth = feedth;
+
+ d.current_state = 0;
+ do {
+ B43_WARN_ON(!
+ (d.current_state >= 0
+ && d.current_state <= 8));
+ memcpy(&probe_loctl, &d.min_loctl,
+ sizeof(struct b43_loctl));
+ found_lower =
+ lo_probe_possible_loctls(dev, &probe_loctl, &d);
+ if (!found_lower)
+ break;
+ if ((probe_loctl.i == d.min_loctl.i) &&
+ (probe_loctl.q == d.min_loctl.q))
+ break;
+ memcpy(&d.min_loctl, &probe_loctl,
+ sizeof(struct b43_loctl));
+ d.nr_measured++;
+ } while (d.nr_measured < 24);
+ memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl));
+
+ if (has_loopback_gain(phy)) {
+ if (d.lowest_feedth > 0x1194)
+ *max_rx_gain -= 6;
+ else if (d.lowest_feedth < 0x5DC)
+ *max_rx_gain += 3;
+ if (repeat_cnt == 0) {
+ if (d.lowest_feedth <= 0x5DC) {
+ d.state_val_multiplier = 1;
+ repeat_cnt++;
+ } else
+ d.state_val_multiplier = 2;
+ } else if (repeat_cnt == 2)
+ d.state_val_multiplier = 1;
+ }
+ lo_measure_gain_values(dev, *max_rx_gain,
+ has_loopback_gain(phy));
+ } while (++repeat_cnt < max_repeat);
+}
+
+#if B43_CALIB_ALL_LOCTLS
+static const struct b43_rfatt b43_full_rfatt_list_items[] = {
+ { .att = 0, .with_padmix = 0, },
+ { .att = 1, .with_padmix = 0, },
+ { .att = 2, .with_padmix = 0, },
+ { .att = 3, .with_padmix = 0, },
+ { .att = 4, .with_padmix = 0, },
+ { .att = 5, .with_padmix = 0, },
+ { .att = 6, .with_padmix = 0, },
+ { .att = 7, .with_padmix = 0, },
+ { .att = 8, .with_padmix = 0, },
+ { .att = 9, .with_padmix = 0, },
+ { .att = 10, .with_padmix = 0, },
+ { .att = 11, .with_padmix = 0, },
+ { .att = 12, .with_padmix = 0, },
+ { .att = 13, .with_padmix = 0, },
+ { .att = 14, .with_padmix = 0, },
+ { .att = 15, .with_padmix = 0, },
+ { .att = 0, .with_padmix = 1, },
+ { .att = 1, .with_padmix = 1, },
+ { .att = 2, .with_padmix = 1, },
+ { .att = 3, .with_padmix = 1, },
+ { .att = 4, .with_padmix = 1, },
+ { .att = 5, .with_padmix = 1, },
+ { .att = 6, .with_padmix = 1, },
+ { .att = 7, .with_padmix = 1, },
+ { .att = 8, .with_padmix = 1, },
+ { .att = 9, .with_padmix = 1, },
+ { .att = 10, .with_padmix = 1, },
+ { .att = 11, .with_padmix = 1, },
+ { .att = 12, .with_padmix = 1, },
+ { .att = 13, .with_padmix = 1, },
+ { .att = 14, .with_padmix = 1, },
+ { .att = 15, .with_padmix = 1, },
+};
+static const struct b43_rfatt_list b43_full_rfatt_list = {
+ .list = b43_full_rfatt_list_items,
+ .len = ARRAY_SIZE(b43_full_rfatt_list_items),
+};
+
+static const struct b43_bbatt b43_full_bbatt_list_items[] = {
+ { .att = 0, },
+ { .att = 1, },
+ { .att = 2, },
+ { .att = 3, },
+ { .att = 4, },
+ { .att = 5, },
+ { .att = 6, },
+ { .att = 7, },
+ { .att = 8, },
+ { .att = 9, },
+ { .att = 10, },
+ { .att = 11, },
+};
+static const struct b43_bbatt_list b43_full_bbatt_list = {
+ .list = b43_full_bbatt_list_items,
+ .len = ARRAY_SIZE(b43_full_bbatt_list_items),
+};
+#endif /* B43_CALIB_ALL_LOCTLS */
+
+static void lo_measure(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_loctl loctl = {
+ .i = 0,
+ .q = 0,
+ };
+ struct b43_loctl *ploctl;
+ int max_rx_gain;
+ int rfidx, bbidx;
+ const struct b43_bbatt_list *bbatt_list;
+ const struct b43_rfatt_list *rfatt_list;
+
+ /* Values from the "TXCTL Register and Value Table" */
+ u16 txctl_reg;
+ u16 txctl_value;
+ u16 pad_mix_gain;
+
+ bbatt_list = &lo->bbatt_list;
+ rfatt_list = &lo->rfatt_list;
+#if B43_CALIB_ALL_LOCTLS
+ bbatt_list = &b43_full_bbatt_list;
+ rfatt_list = &b43_full_rfatt_list;
+#endif
+
+ txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
+
+ for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) {
+
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) |
+ rfatt_list->list[rfidx].att);
+ b43_radio_write16(dev, txctl_reg,
+ (b43_radio_read16(dev, txctl_reg)
+ & ~txctl_value)
+ | (rfatt_list->list[rfidx].with_padmix ?
+ txctl_value : 0));
+
+ for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
+ if (lo->rebuild) {
+#if B43_CALIB_ALL_LOCTLS
+ ploctl = b43_get_lo_g_ctl(dev,
+ &rfatt_list->list[rfidx],
+ &bbatt_list->list[bbidx]);
+#else
+ ploctl = b43_get_lo_g_ctl_nopadmix(dev,
+ &rfatt_list->
+ list[rfidx],
+ &bbatt_list->
+ list[bbidx]);
+#endif
+ } else {
+ ploctl = b43_get_lo_g_ctl(dev,
+ &rfatt_list->list[rfidx],
+ &bbatt_list->list[bbidx]);
+ if (!ploctl->used)
+ continue;
+ }
+ memcpy(&loctl, ploctl, sizeof(loctl));
+ loctl.i = 0;
+ loctl.q = 0;
+
+ max_rx_gain = rfatt_list->list[rfidx].att * 2;
+ max_rx_gain += bbatt_list->list[bbidx].att / 2;
+ if (rfatt_list->list[rfidx].with_padmix)
+ max_rx_gain -= pad_mix_gain;
+ if (has_loopback_gain(phy))
+ max_rx_gain += phy->max_lb_gain;
+ lo_measure_gain_values(dev, max_rx_gain,
+ has_loopback_gain(phy));
+
+ b43_phy_set_baseband_attenuation(dev,
+ bbatt_list->list[bbidx].att);
+ lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
+ if (phy->type == B43_PHYTYPE_B) {
+ loctl.i++;
+ loctl.q++;
+ }
+ b43_loctl_set_calibrated(&loctl, 1);
+ memcpy(ploctl, &loctl, sizeof(loctl));
+ }
+ }
+}
+
+#if B43_DEBUG
+static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
+ int i = control->i;
+ int q = control->q;
+
+ if (b43_loctl_is_calibrated(control)) {
+ if ((abs(i) > 16) || (abs(q) > 16))
+ goto error;
+ } else {
+ if (control->used)
+ goto error;
+ if (dev->phy.lo_control->rebuild) {
+ control->i = 0;
+ control->q = 0;
+ if ((i != B43_LOCTL_POISON) ||
+ (q != B43_LOCTL_POISON))
+ goto error;
+ }
+ }
+ if (is_initializing && control->used)
+ goto error;
+
+ return;
+error:
+ b43err(dev->wl, "LO control pair validation failed "
+ "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
+ i, q, control->used,
+ b43_loctl_is_calibrated(control),
+ is_initializing);
+}
+
+static void validate_all_loctls(struct b43_wldev *dev)
+{
+ b43_call_for_each_loctl(dev, do_validate_loctl);
+}
+
+static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ if (dev->phy.lo_control->rebuild ||
+ control->used) {
+ b43_loctl_set_calibrated(control, 0);
+ control->i = B43_LOCTL_POISON;
+ control->q = B43_LOCTL_POISON;
+ }
+}
+
+static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
+{
+ b43_call_for_each_loctl(dev, do_reset_calib);
+}
+
+#else /* B43_DEBUG */
+static inline void validate_all_loctls(struct b43_wldev *dev) { }
+static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
+#endif /* B43_DEBUG */
+
+void b43_lo_g_measure(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct lo_g_saved_values uninitialized_var(sav);
+
+ B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
+ (phy->type != B43_PHYTYPE_G));
+
+ sav.old_channel = phy->channel;
+ lo_measure_setup(dev, &sav);
+ reset_all_loctl_calibration_states(dev);
+ lo_measure(dev);
+ lo_measure_restore(dev, &sav);
+
+ validate_all_loctls(dev);
+
+ phy->lo_control->lo_measured = 1;
+ phy->lo_control->rebuild = 0;
+}
+
+#if B43_DEBUG
+static void validate_loctl_calibration(struct b43_wldev *dev,
+ struct b43_loctl *loctl,
+ struct b43_rfatt *rfatt,
+ struct b43_bbatt *bbatt)
+{
+ if (b43_loctl_is_calibrated(loctl))
+ return;
+ if (!dev->phy.lo_control->lo_measured) {
+ /* On init we set the attenuation values before we
+ * calibrated the LO. I guess that's OK. */
+ return;
+ }
+ b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated "
+ "control pair: rfatt=%u,%spadmix bbatt=%u\n",
+ rfatt->att,
+ (rfatt->with_padmix) ? "" : "no-",
+ bbatt->att);
+}
+#else
+static inline void validate_loctl_calibration(struct b43_wldev *dev,
+ struct b43_loctl *loctl,
+ struct b43_rfatt *rfatt,
+ struct b43_bbatt *bbatt)
+{
+}
+#endif
+
+static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
+ u8 tx_control)
+{
+ if (tx_control & B43_TXCTL_TXMIX) {
+ if (rf->att < 5)
+ rf->att = 4;
+ }
+}
+
+void b43_lo_g_adjust(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_rfatt rf;
+ struct b43_loctl *loctl;
+
+ memcpy(&rf, &phy->rfatt, sizeof(rf));
+ fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+
+ loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt);
+ validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt);
+ b43_lo_write(dev, loctl);
+}
+
+void b43_lo_g_adjust_to(struct b43_wldev *dev,
+ u16 rfatt, u16 bbatt, u16 tx_control)
+{
+ struct b43_rfatt rf;
+ struct b43_bbatt bb;
+ struct b43_loctl *loctl;
+
+ memset(&rf, 0, sizeof(rf));
+ memset(&bb, 0, sizeof(bb));
+ rf.att = rfatt;
+ bb.att = bbatt;
+ fixup_rfatt_for_txcontrol(&rf, tx_control);
+ loctl = b43_get_lo_g_ctl(dev, &rf, &bb);
+ validate_loctl_calibration(dev, loctl, &rf, &bb);
+ b43_lo_write(dev, loctl);
+}
+
+static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ control->used = 0;
+}
+
+void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ b43_call_for_each_loctl(dev, do_mark_unused);
+ lo->rebuild = 1;
+}
+
+void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_rfatt rf;
+
+ memcpy(&rf, &phy->rfatt, sizeof(rf));
+ fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+
+ b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1;
+}
diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h
new file mode 100644
index 000000000000..455615d1f8c6
--- /dev/null
+++ b/drivers/net/wireless/b43/lo.h
@@ -0,0 +1,112 @@
+#ifndef B43_LO_H_
+#define B43_LO_H_
+
+#include "phy.h"
+
+struct b43_wldev;
+
+/* Local Oscillator control value-pair. */
+struct b43_loctl {
+ /* Control values. */
+ s8 i;
+ s8 q;
+ /* "Used by hardware" flag. */
+ bool used;
+#ifdef CONFIG_B43_DEBUG
+ /* Is this lo-control-array entry calibrated? */
+ bool calibrated;
+#endif
+};
+
+/* Debugging: Poison value for i and q values. */
+#define B43_LOCTL_POISON 111
+
+/* loctl->calibrated debugging mechanism */
+#ifdef CONFIG_B43_DEBUG
+static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
+ bool calibrated)
+{
+ loctl->calibrated = calibrated;
+}
+static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
+{
+ return loctl->calibrated;
+}
+#else
+static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
+ bool calibrated)
+{
+}
+static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
+{
+ return 1;
+}
+#endif
+
+/* TX Power LO Control Array.
+ * Value-pairs to adjust the LocalOscillator are stored
+ * in this structure.
+ * There are two different set of values. One for "Flag is Set"
+ * and one for "Flag is Unset".
+ * By "Flag" the flag in struct b43_rfatt is meant.
+ * The Value arrays are two-dimensional. The first index
+ * is the baseband attenuation and the second index
+ * is the radio attenuation.
+ * Use b43_get_lo_g_ctl() to retrieve a value from the lists.
+ */
+struct b43_txpower_lo_control {
+#define B43_NR_BB 12
+#define B43_NR_RF 16
+ /* LO Control values, with PAD Mixer */
+ struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF];
+ /* LO Control values, without PAD Mixer */
+ struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF];
+
+ /* Flag to indicate a complete rebuild of the two tables above
+ * to the LO measuring code. */
+ bool rebuild;
+
+ /* Lists of valid RF and BB attenuation values for this device. */
+ struct b43_rfatt_list rfatt_list;
+ struct b43_bbatt_list bbatt_list;
+
+ /* Current TX Bias value */
+ u8 tx_bias;
+ /* Current TX Magnification Value (if used by the device) */
+ u8 tx_magn;
+
+ /* GPHY LO is measured. */
+ bool lo_measured;
+
+ /* Saved device PowerVector */
+ u64 power_vector;
+};
+
+/* Measure the BPHY Local Oscillator. */
+void b43_lo_b_measure(struct b43_wldev *dev);
+/* Measure the BPHY/GPHY Local Oscillator. */
+void b43_lo_g_measure(struct b43_wldev *dev);
+
+/* Adjust the Local Oscillator to the saved attenuation
+ * and txctl values.
+ */
+void b43_lo_g_adjust(struct b43_wldev *dev);
+/* Adjust to specific values. */
+void b43_lo_g_adjust_to(struct b43_wldev *dev,
+ u16 rfatt, u16 bbatt, u16 tx_control);
+
+/* Mark all possible b43_lo_g_ctl as "unused" */
+void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev);
+/* Mark the b43_lo_g_ctl corresponding to the current
+ * attenuation values as used.
+ */
+void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev);
+
+/* Get a reference to a LO Control value pair in the
+ * TX Power LO Control Array.
+ */
+struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
+ const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt);
+
+#endif /* B43_LO_H_ */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
new file mode 100644
index 000000000000..c141a264ac45
--- /dev/null
+++ b/drivers/net/wireless/b43/main.c
@@ -0,0 +1,4070 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <asm/unaligned.h>
+
+#include "b43.h"
+#include "main.h"
+#include "debugfs.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+#include "sysfs.h"
+#include "xmit.h"
+#include "sysfs.h"
+#include "lo.h"
+#include "pcmcia.h"
+
+MODULE_DESCRIPTION("Broadcom B43 wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+extern char *nvram_get(char *name);
+
+#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_B43_DMA)
+# define modparam_pio 0
+#elif defined(CONFIG_B43_PIO)
+# define modparam_pio 1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt,
+ "enable(1) / disable(0) Bad Frames Preemption");
+
+static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static char modparam_fwpostfix[16];
+module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
+
+static int modparam_hwpctl;
+module_param_named(hwpctl, modparam_hwpctl, int, 0444);
+MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+static const struct ssb_device_id b43_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+ SSB_DEVTABLE_END
+};
+
+MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
+
+/* Channel and ratetables are shared for all devices.
+ * They can't be const, because ieee80211 puts some precalculated
+ * data in there. This data is the same for all devices, so we don't
+ * get concurrency issues */
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .rate = B43_RATE_TO_BASE100KBPS(_rateid), \
+ .val = (_rateid), \
+ .val2 = (_rateid), \
+ .flags = (_flags), \
+ }
+static struct ieee80211_rate __b43_ratetable[] = {
+ RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+ RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+};
+
+#define b43_a_ratetable (__b43_ratetable + 4)
+#define b43_a_ratetable_size 8
+#define b43_b_ratetable (__b43_ratetable + 0)
+#define b43_b_ratetable_size 4
+#define b43_g_ratetable (__b43_ratetable + 0)
+#define b43_g_ratetable_size 12
+
+#define CHANTAB_ENT(_chanid, _freq) \
+ { \
+ .chan = (_chanid), \
+ .freq = (_freq), \
+ .val = (_chanid), \
+ .flag = IEEE80211_CHAN_W_SCAN | \
+ IEEE80211_CHAN_W_ACTIVE_SCAN | \
+ IEEE80211_CHAN_W_IBSS, \
+ .power_level = 0xFF, \
+ .antenna_max = 0xFF, \
+ }
+static struct ieee80211_channel b43_bg_chantable[] = {
+ CHANTAB_ENT(1, 2412),
+ CHANTAB_ENT(2, 2417),
+ CHANTAB_ENT(3, 2422),
+ CHANTAB_ENT(4, 2427),
+ CHANTAB_ENT(5, 2432),
+ CHANTAB_ENT(6, 2437),
+ CHANTAB_ENT(7, 2442),
+ CHANTAB_ENT(8, 2447),
+ CHANTAB_ENT(9, 2452),
+ CHANTAB_ENT(10, 2457),
+ CHANTAB_ENT(11, 2462),
+ CHANTAB_ENT(12, 2467),
+ CHANTAB_ENT(13, 2472),
+ CHANTAB_ENT(14, 2484),
+};
+
+#define b43_bg_chantable_size ARRAY_SIZE(b43_bg_chantable)
+static struct ieee80211_channel b43_a_chantable[] = {
+ CHANTAB_ENT(36, 5180),
+ CHANTAB_ENT(40, 5200),
+ CHANTAB_ENT(44, 5220),
+ CHANTAB_ENT(48, 5240),
+ CHANTAB_ENT(52, 5260),
+ CHANTAB_ENT(56, 5280),
+ CHANTAB_ENT(60, 5300),
+ CHANTAB_ENT(64, 5320),
+ CHANTAB_ENT(149, 5745),
+ CHANTAB_ENT(153, 5765),
+ CHANTAB_ENT(157, 5785),
+ CHANTAB_ENT(161, 5805),
+ CHANTAB_ENT(165, 5825),
+};
+
+#define b43_a_chantable_size ARRAY_SIZE(b43_a_chantable)
+
+static void b43_wireless_core_exit(struct b43_wldev *dev);
+static int b43_wireless_core_init(struct b43_wldev *dev);
+static void b43_wireless_core_stop(struct b43_wldev *dev);
+static int b43_wireless_core_start(struct b43_wldev *dev);
+
+static int b43_ratelimit(struct b43_wl *wl)
+{
+ if (!wl || !wl->current_dev)
+ return 1;
+ if (b43_status(wl->current_dev) < B43_STAT_STARTED)
+ return 1;
+ /* We are up and running.
+ * Ratelimit the messages to avoid DoS over the net. */
+ return net_ratelimit();
+}
+
+void b43info(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_INFO "b43-%s: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43err(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_ERR "b43-%s ERROR: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43warn(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_WARNING "b43-%s warning: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+#if B43_DEBUG
+void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "b43-%s debug: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+#endif /* DEBUG */
+
+static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
+{
+ u32 macctl;
+
+ B43_WARN_ON(offset % 4 != 0);
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ if (macctl & B43_MACCTL_BE)
+ val = swab32(val);
+
+ b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_RAM_DATA, val);
+}
+
+static inline
+ void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+ u32 control;
+
+ /* "offset" is the WORD offset. */
+
+ control = routing;
+ control <<= 16;
+ control |= offset;
+ b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
+}
+
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+ u32 ret;
+
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
+ ret <<= 16;
+ b43_shm_control_word(dev, routing, (offset >> 2) + 1);
+ ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
+{
+ u16 ret;
+
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+{
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
+ (value >> 16) & 0xffff);
+ mmiowb();
+ b43_shm_control_word(dev, routing, (offset >> 2) + 1);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_SHM_DATA, value);
+}
+
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+{
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA, value);
+}
+
+/* Read HostFlags */
+u32 b43_hf_read(struct b43_wldev * dev)
+{
+ u32 ret;
+
+ ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
+ ret <<= 16;
+ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
+
+ return ret;
+}
+
+/* Write HostFlags */
+void b43_hf_write(struct b43_wldev *dev, u32 value)
+{
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF));
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16));
+}
+
+void b43_tsf_read(struct b43_wldev *dev, u64 * tsf)
+{
+ /* We need to be careful. As we read the TSF from multiple
+ * registers, we should take care of register overflows.
+ * In theory, the whole tsf read process should be atomic.
+ * We try to be atomic here, by restaring the read process,
+ * if any of the high registers changed (overflew).
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 low, high, high2;
+
+ do {
+ high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
+ low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
+ high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
+ } while (unlikely(high != high2));
+
+ *tsf = high;
+ *tsf <<= 32;
+ *tsf |= low;
+ } else {
+ u64 tmp;
+ u16 v0, v1, v2, v3;
+ u16 test1, test2, test3;
+
+ do {
+ v3 = b43_read16(dev, B43_MMIO_TSF_3);
+ v2 = b43_read16(dev, B43_MMIO_TSF_2);
+ v1 = b43_read16(dev, B43_MMIO_TSF_1);
+ v0 = b43_read16(dev, B43_MMIO_TSF_0);
+
+ test3 = b43_read16(dev, B43_MMIO_TSF_3);
+ test2 = b43_read16(dev, B43_MMIO_TSF_2);
+ test1 = b43_read16(dev, B43_MMIO_TSF_1);
+ } while (v3 != test3 || v2 != test2 || v1 != test1);
+
+ *tsf = v3;
+ *tsf <<= 48;
+ tmp = v2;
+ tmp <<= 32;
+ *tsf |= tmp;
+ tmp = v1;
+ tmp <<= 16;
+ *tsf |= tmp;
+ *tsf |= v0;
+ }
+}
+
+static void b43_time_lock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl |= B43_MACCTL_TBTTHOLD;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+}
+
+static void b43_time_unlock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_TBTTHOLD;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+}
+
+static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
+{
+ /* Be careful with the in-progress timer.
+ * First zero out the low register, so we have a full
+ * register-overflow duration to complete the operation.
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+ u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+ b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo);
+ } else {
+ u16 v0 = (tsf & 0x000000000000FFFFULL);
+ u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+ u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+ u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+ b43_write16(dev, B43_MMIO_TSF_0, 0);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_3, v3);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_2, v2);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_1, v1);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_0, v0);
+ }
+}
+
+void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
+{
+ b43_time_lock(dev);
+ b43_tsf_write_locked(dev, tsf);
+ b43_time_unlock(dev);
+}
+
+static
+void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac)
+{
+ static const u8 zero_addr[ETH_ALEN] = { 0 };
+ u16 data;
+
+ if (!mac)
+ mac = zero_addr;
+
+ offset |= 0x0020;
+ b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
+
+ data = mac[0];
+ data |= mac[1] << 8;
+ b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+ data = mac[2];
+ data |= mac[3] << 8;
+ b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+ data = mac[4];
+ data |= mac[5] << 8;
+ b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+}
+
+static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
+{
+ const u8 *mac;
+ const u8 *bssid;
+ u8 mac_bssid[ETH_ALEN * 2];
+ int i;
+ u32 tmp;
+
+ bssid = dev->wl->bssid;
+ mac = dev->wl->mac_addr;
+
+ b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
+
+ memcpy(mac_bssid, mac, ETH_ALEN);
+ memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+ /* Write our MAC address and BSSID to template ram */
+ for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+ tmp = (u32) (mac_bssid[i + 0]);
+ tmp |= (u32) (mac_bssid[i + 1]) << 8;
+ tmp |= (u32) (mac_bssid[i + 2]) << 16;
+ tmp |= (u32) (mac_bssid[i + 3]) << 24;
+ b43_ram_write(dev, 0x20 + i, tmp);
+ }
+}
+
+static void b43_upload_card_macaddress(struct b43_wldev *dev)
+{
+ b43_write_mac_bssid_templates(dev);
+ b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
+}
+
+static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
+{
+ /* slot_time is in usec. */
+ if (dev->phy.type != B43_PHYTYPE_G)
+ return;
+ b43_write16(dev, 0x684, 510 + slot_time);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+}
+
+static void b43_short_slot_timing_enable(struct b43_wldev *dev)
+{
+ b43_set_slot_time(dev, 9);
+ dev->short_slot = 1;
+}
+
+static void b43_short_slot_timing_disable(struct b43_wldev *dev)
+{
+ b43_set_slot_time(dev, 20);
+ dev->short_slot = 0;
+}
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
+
+ return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+ return old_mask;
+}
+
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void b43_synchronize_irq(struct b43_wldev *dev)
+{
+ synchronize_irq(dev->dev->irq);
+ tasklet_kill(&dev->isr_tasklet);
+}
+
+/* DummyTransmission function, as documented on
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void b43_dummy_transmission(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ unsigned int i, max_loop;
+ u16 value;
+ u32 buffer[5] = {
+ 0x00000000,
+ 0x00D40000,
+ 0x00000000,
+ 0x01000000,
+ 0x00000000,
+ };
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ max_loop = 0x1E;
+ buffer[0] = 0x000201CC;
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ max_loop = 0xFA;
+ buffer[0] = 0x000B846E;
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ b43_ram_write(dev, i * 4, buffer[i]);
+
+ /* Commit writes */
+ b43_read32(dev, B43_MMIO_MACCTL);
+
+ b43_write16(dev, 0x0568, 0x0000);
+ b43_write16(dev, 0x07C0, 0x0000);
+ value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0);
+ b43_write16(dev, 0x050C, value);
+ b43_write16(dev, 0x0508, 0x0000);
+ b43_write16(dev, 0x050A, 0x0000);
+ b43_write16(dev, 0x054C, 0x0000);
+ b43_write16(dev, 0x056A, 0x0014);
+ b43_write16(dev, 0x0568, 0x0826);
+ b43_write16(dev, 0x0500, 0x0000);
+ b43_write16(dev, 0x0502, 0x0030);
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43_radio_write16(dev, 0x0051, 0x0017);
+ for (i = 0x00; i < max_loop; i++) {
+ value = b43_read16(dev, 0x050E);
+ if (value & 0x0080)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43_read16(dev, 0x050E);
+ if (value & 0x0400)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43_read16(dev, 0x0690);
+ if (!(value & 0x0100))
+ break;
+ udelay(10);
+ }
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43_radio_write16(dev, 0x0051, 0x0037);
+}
+
+static void key_write(struct b43_wldev *dev,
+ u8 index, u8 algorithm, const u8 * key)
+{
+ unsigned int i;
+ u32 offset;
+ u16 value;
+ u16 kidx;
+
+ /* Key index/algo block */
+ kidx = b43_kidx_to_fw(dev, index);
+ value = ((kidx << 4) | algorithm);
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
+
+ /* Write the key to the Key Table Pointer offset */
+ offset = dev->ktp + (index * B43_SEC_KEYSIZE);
+ for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
+ value = key[i];
+ value |= (u16) (key[i + 1]) << 8;
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
+ }
+}
+
+static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
+{
+ u32 addrtmp[2] = { 0, 0, };
+ u8 per_sta_keys_start = 8;
+
+ if (b43_new_kidx_api(dev))
+ per_sta_keys_start = 4;
+
+ B43_WARN_ON(index < per_sta_keys_start);
+ /* We have two default TX keys and possibly two default RX keys.
+ * Physical mac 0 is mapped to physical key 4 or 8, depending
+ * on the firmware version.
+ * So we must adjust the index here.
+ */
+ index -= per_sta_keys_start;
+
+ if (addr) {
+ addrtmp[0] = addr[0];
+ addrtmp[0] |= ((u32) (addr[1]) << 8);
+ addrtmp[0] |= ((u32) (addr[2]) << 16);
+ addrtmp[0] |= ((u32) (addr[3]) << 24);
+ addrtmp[1] = addr[4];
+ addrtmp[1] |= ((u32) (addr[5]) << 8);
+ }
+
+ if (dev->dev->id.revision >= 5) {
+ /* Receive match transmitter address mechanism */
+ b43_shm_write32(dev, B43_SHM_RCMTA,
+ (index * 2) + 0, addrtmp[0]);
+ b43_shm_write16(dev, B43_SHM_RCMTA,
+ (index * 2) + 1, addrtmp[1]);
+ } else {
+ /* RXE (Receive Engine) and
+ * PSM (Programmable State Machine) mechanism
+ */
+ if (index < 8) {
+ /* TODO write to RCM 16, 19, 22 and 25 */
+ } else {
+ b43_shm_write32(dev, B43_SHM_SHARED,
+ B43_SHM_SH_PSM + (index * 6) + 0,
+ addrtmp[0]);
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_PSM + (index * 6) + 4,
+ addrtmp[1]);
+ }
+ }
+}
+
+static void do_key_write(struct b43_wldev *dev,
+ u8 index, u8 algorithm,
+ const u8 * key, size_t key_len, const u8 * mac_addr)
+{
+ u8 buf[B43_SEC_KEYSIZE] = { 0, };
+ u8 per_sta_keys_start = 8;
+
+ if (b43_new_kidx_api(dev))
+ per_sta_keys_start = 4;
+
+ B43_WARN_ON(index >= dev->max_nr_keys);
+ B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
+
+ if (index >= per_sta_keys_start)
+ keymac_write(dev, index, NULL); /* First zero out mac. */
+ if (key)
+ memcpy(buf, key, key_len);
+ key_write(dev, index, algorithm, buf);
+ if (index >= per_sta_keys_start)
+ keymac_write(dev, index, mac_addr);
+
+ dev->key[index].algorithm = algorithm;
+}
+
+static int b43_key_write(struct b43_wldev *dev,
+ int index, u8 algorithm,
+ const u8 * key, size_t key_len,
+ const u8 * mac_addr,
+ struct ieee80211_key_conf *keyconf)
+{
+ int i;
+ int sta_keys_start;
+
+ if (key_len > B43_SEC_KEYSIZE)
+ return -EINVAL;
+ for (i = 0; i < dev->max_nr_keys; i++) {
+ /* Check that we don't already have this key. */
+ B43_WARN_ON(dev->key[i].keyconf == keyconf);
+ }
+ if (index < 0) {
+ /* Either pairwise key or address is 00:00:00:00:00:00
+ * for transmit-only keys. Search the index. */
+ if (b43_new_kidx_api(dev))
+ sta_keys_start = 4;
+ else
+ sta_keys_start = 8;
+ for (i = sta_keys_start; i < dev->max_nr_keys; i++) {
+ if (!dev->key[i].keyconf) {
+ /* found empty */
+ index = i;
+ break;
+ }
+ }
+ if (index < 0) {
+ b43err(dev->wl, "Out of hardware key memory\n");
+ return -ENOSPC;
+ }
+ } else
+ B43_WARN_ON(index > 3);
+
+ do_key_write(dev, index, algorithm, key, key_len, mac_addr);
+ if ((index <= 3) && !b43_new_kidx_api(dev)) {
+ /* Default RX key */
+ B43_WARN_ON(mac_addr);
+ do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
+ }
+ keyconf->hw_key_idx = index;
+ dev->key[index].keyconf = keyconf;
+
+ return 0;
+}
+
+static int b43_key_clear(struct b43_wldev *dev, int index)
+{
+ if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys)))
+ return -EINVAL;
+ do_key_write(dev, index, B43_SEC_ALGO_NONE,
+ NULL, B43_SEC_KEYSIZE, NULL);
+ if ((index <= 3) && !b43_new_kidx_api(dev)) {
+ do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
+ NULL, B43_SEC_KEYSIZE, NULL);
+ }
+ dev->key[index].keyconf = NULL;
+
+ return 0;
+}
+
+static void b43_clear_keys(struct b43_wldev *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->max_nr_keys; i++)
+ b43_key_clear(dev, i);
+}
+
+void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
+{
+ u32 macctl;
+ u16 ucstat;
+ bool hwps;
+ bool awake;
+ int i;
+
+ B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
+ (ps_flags & B43_PS_DISABLED));
+ B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
+
+ if (ps_flags & B43_PS_ENABLED) {
+ hwps = 1;
+ } else if (ps_flags & B43_PS_DISABLED) {
+ hwps = 0;
+ } else {
+ //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
+ // and thus is not an AP and we are associated, set bit 25
+ }
+ if (ps_flags & B43_PS_AWAKE) {
+ awake = 1;
+ } else if (ps_flags & B43_PS_ASLEEP) {
+ awake = 0;
+ } else {
+ //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
+ // or we are associated, or FIXME, or the latest PS-Poll packet sent was
+ // successful, set bit26
+ }
+
+/* FIXME: For now we force awake-on and hwps-off */
+ hwps = 0;
+ awake = 1;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ if (hwps)
+ macctl |= B43_MACCTL_HWPS;
+ else
+ macctl &= ~B43_MACCTL_HWPS;
+ if (awake)
+ macctl |= B43_MACCTL_AWAKE;
+ else
+ macctl &= ~B43_MACCTL_AWAKE;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ if (awake && dev->dev->id.revision >= 5) {
+ /* Wait for the microcode to wake up. */
+ for (i = 0; i < 100; i++) {
+ ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_UCODESTAT);
+ if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
+ break;
+ udelay(10);
+ }
+ }
+}
+
+/* Turn the Analog ON/OFF */
+static void b43_switch_analog(struct b43_wldev *dev, int on)
+{
+ b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
+}
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+{
+ u32 tmslow;
+ u32 macctl;
+
+ flags |= B43_TMSLOW_PHYCLKEN;
+ flags |= B43_TMSLOW_PHYRESET;
+ ssb_device_enable(dev->dev, flags);
+ msleep(2); /* Wait for the PLL to turn on. */
+
+ /* Now take the PHY out of Reset again */
+ tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ tmslow |= SSB_TMSLOW_FGC;
+ tmslow &= ~B43_TMSLOW_PHYRESET;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+
+ /* Turn Analog ON */
+ b43_switch_analog(dev, 1);
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_GMODE;
+ if (flags & B43_TMSLOW_GMODE)
+ macctl |= B43_MACCTL_GMODE;
+ macctl |= B43_MACCTL_IHR_ENABLED;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+static void handle_irq_transmit_status(struct b43_wldev *dev)
+{
+ u32 v0, v1;
+ u16 tmp;
+ struct b43_txstatus stat;
+
+ while (1) {
+ v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
+ if (!(v0 & 0x00000001))
+ break;
+ v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
+
+ stat.cookie = (v0 >> 16);
+ stat.seq = (v1 & 0x0000FFFF);
+ stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
+ tmp = (v0 & 0x0000FFFF);
+ stat.frame_count = ((tmp & 0xF000) >> 12);
+ stat.rts_count = ((tmp & 0x0F00) >> 8);
+ stat.supp_reason = ((tmp & 0x001C) >> 2);
+ stat.pm_indicated = !!(tmp & 0x0080);
+ stat.intermediate = !!(tmp & 0x0040);
+ stat.for_ampdu = !!(tmp & 0x0020);
+ stat.acked = !!(tmp & 0x0002);
+
+ b43_handle_txstatus(dev, &stat);
+ }
+}
+
+static void drain_txstatus_queue(struct b43_wldev *dev)
+{
+ u32 dummy;
+
+ if (dev->dev->id.revision < 5)
+ return;
+ /* Read all entries from the microcode TXstatus FIFO
+ * and throw them away.
+ */
+ while (1) {
+ dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
+ if (!(dummy & 0x00000001))
+ break;
+ dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
+ }
+}
+
+static u32 b43_jssi_read(struct b43_wldev *dev)
+{
+ u32 val = 0;
+
+ val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
+ val <<= 16;
+ val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
+
+ return val;
+}
+
+static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
+{
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
+}
+
+static void b43_generate_noise_sample(struct b43_wldev *dev)
+{
+ b43_jssi_write(dev, 0x7F7F7F7F);
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
+ b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
+ | (1 << 4));
+ B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
+}
+
+static void b43_calculate_link_quality(struct b43_wldev *dev)
+{
+ /* Top half of Link Quality calculation. */
+
+ if (dev->noisecalc.calculation_running)
+ return;
+ dev->noisecalc.channel_at_start = dev->phy.channel;
+ dev->noisecalc.calculation_running = 1;
+ dev->noisecalc.nr_samples = 0;
+
+ b43_generate_noise_sample(dev);
+}
+
+static void handle_irq_noise(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+ u8 noise[4];
+ u8 i, j;
+ s32 average;
+
+ /* Bottom half of Link Quality calculation. */
+
+ B43_WARN_ON(!dev->noisecalc.calculation_running);
+ if (dev->noisecalc.channel_at_start != phy->channel)
+ goto drop_calculation;
+ *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
+ if (noise[0] == 0x7F || noise[1] == 0x7F ||
+ noise[2] == 0x7F || noise[3] == 0x7F)
+ goto generate_new;
+
+ /* Get the noise samples. */
+ B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
+ i = dev->noisecalc.nr_samples;
+ noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
+ dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
+ dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
+ dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
+ dev->noisecalc.nr_samples++;
+ if (dev->noisecalc.nr_samples == 8) {
+ /* Calculate the Link Quality by the noise samples. */
+ average = 0;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 4; j++)
+ average += dev->noisecalc.samples[i][j];
+ }
+ average /= (8 * 4);
+ average *= 125;
+ average += 64;
+ average /= 128;
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
+ tmp = (tmp / 128) & 0x1F;
+ if (tmp >= 8)
+ average += 2;
+ else
+ average -= 25;
+ if (tmp == 8)
+ average -= 72;
+ else
+ average -= 48;
+
+ dev->stats.link_noise = average;
+ drop_calculation:
+ dev->noisecalc.calculation_running = 0;
+ return;
+ }
+ generate_new:
+ b43_generate_noise_sample(dev);
+}
+
+static void handle_irq_tbtt_indication(struct b43_wldev *dev)
+{
+ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ ///TODO: PS TBTT
+ } else {
+ if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
+ b43_power_saving_ctl_bits(dev, 0);
+ }
+ dev->reg124_set_0x4 = 0;
+ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ dev->reg124_set_0x4 = 1;
+}
+
+static void handle_irq_atim_end(struct b43_wldev *dev)
+{
+ if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
+ return;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
+ b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
+ | 0x4);
+}
+
+static void handle_irq_pmq(struct b43_wldev *dev)
+{
+ u32 tmp;
+
+ //TODO: AP mode.
+
+ while (1) {
+ tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
+ if (!(tmp & 0x00000008))
+ break;
+ }
+ /* 16bit write is odd, but correct. */
+ b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
+}
+
+static void b43_write_template_common(struct b43_wldev *dev,
+ const u8 * data, u16 size,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u32 i, tmp;
+ struct b43_plcp_hdr4 plcp;
+
+ plcp.data = 0;
+ b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
+ ram_offset += sizeof(u32);
+ /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+ * So leave the first two bytes of the next write blank.
+ */
+ tmp = (u32) (data[0]) << 16;
+ tmp |= (u32) (data[1]) << 24;
+ b43_ram_write(dev, ram_offset, tmp);
+ ram_offset += sizeof(u32);
+ for (i = 2; i < size; i += sizeof(u32)) {
+ tmp = (u32) (data[i + 0]);
+ if (i + 1 < size)
+ tmp |= (u32) (data[i + 1]) << 8;
+ if (i + 2 < size)
+ tmp |= (u32) (data[i + 2]) << 16;
+ if (i + 3 < size)
+ tmp |= (u32) (data[i + 3]) << 24;
+ b43_ram_write(dev, ram_offset + i - 2, tmp);
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
+ size + sizeof(struct b43_plcp_hdr6));
+}
+
+static void b43_write_beacon_template(struct b43_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ int len;
+ const u8 *data;
+
+ B43_WARN_ON(!dev->cached_beacon);
+ len = min((size_t) dev->cached_beacon->len,
+ 0x200 - sizeof(struct b43_plcp_hdr6));
+ data = (const u8 *)(dev->cached_beacon->data);
+ b43_write_template_common(dev, data,
+ len, ram_offset, shm_size_offset, rate);
+}
+
+static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
+ u16 shm_offset, u16 size, u8 rate)
+{
+ struct b43_plcp_hdr4 plcp;
+ u32 tmp;
+ __le16 dur;
+
+ plcp.data = 0;
+ b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id, size,
+ B43_RATE_TO_BASE100KBPS(rate));
+ /* Write PLCP in two parts and timing for packet transfer */
+ tmp = le32_to_cpu(plcp.data);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
+ u16 * dest_size, u8 rate)
+{
+ const u8 *src_data;
+ u8 *dest_data;
+ u16 src_size, elem_size, src_pos, dest_pos;
+ __le16 dur;
+ struct ieee80211_hdr *hdr;
+
+ B43_WARN_ON(!dev->cached_beacon);
+ src_size = dev->cached_beacon->len;
+ src_data = (const u8 *)dev->cached_beacon->data;
+
+ if (unlikely(src_size < 0x24)) {
+ b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+ return NULL;
+ }
+
+ dest_data = kmalloc(src_size, GFP_ATOMIC);
+ if (unlikely(!dest_data))
+ return NULL;
+
+ /* 0x24 is offset of first variable-len Information-Element
+ * in beacon frame.
+ */
+ memcpy(dest_data, src_data, 0x24);
+ src_pos = dest_pos = 0x24;
+ for (; src_pos < src_size - 2; src_pos += elem_size) {
+ elem_size = src_data[src_pos + 1] + 2;
+ if (src_data[src_pos] != 0x05) { /* TIM */
+ memcpy(dest_data + dest_pos, src_data + src_pos,
+ elem_size);
+ dest_pos += elem_size;
+ }
+ }
+ *dest_size = dest_pos;
+ hdr = (struct ieee80211_hdr *)dest_data;
+
+ /* Set the frame control. */
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id, *dest_size,
+ B43_RATE_TO_BASE100KBPS(rate));
+ hdr->duration_id = dur;
+
+ return dest_data;
+}
+
+static void b43_write_probe_resp_template(struct b43_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u8 *probe_resp_data;
+ u16 size;
+
+ B43_WARN_ON(!dev->cached_beacon);
+ size = dev->cached_beacon->len;
+ probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
+ if (unlikely(!probe_resp_data))
+ return;
+
+ /* Looks like PLCP headers plus packet timings are stored for
+ * all possible basic rates
+ */
+ b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
+ b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
+ b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
+ b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+
+ size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
+ b43_write_template_common(dev, probe_resp_data,
+ size, ram_offset, shm_size_offset, rate);
+ kfree(probe_resp_data);
+}
+
+static int b43_refresh_cached_beacon(struct b43_wldev *dev,
+ struct sk_buff *beacon)
+{
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = beacon;
+
+ return 0;
+}
+
+static void b43_update_templates(struct b43_wldev *dev)
+{
+ u32 status;
+
+ B43_WARN_ON(!dev->cached_beacon);
+
+ b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
+ b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
+ b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
+
+ status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+ status |= 0x03;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
+{
+ int err;
+
+ err = b43_refresh_cached_beacon(dev, beacon);
+ if (unlikely(err))
+ return;
+ b43_update_templates(dev);
+}
+
+static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
+{
+ u32 tmp;
+ u16 i, len;
+
+ len = min((u16) ssid_len, (u16) 0x100);
+ for (i = 0; i < len; i += sizeof(u32)) {
+ tmp = (u32) (ssid[i + 0]);
+ if (i + 1 < len)
+ tmp |= (u32) (ssid[i + 1]) << 8;
+ if (i + 2 < len)
+ tmp |= (u32) (ssid[i + 2]) << 16;
+ if (i + 3 < len)
+ tmp |= (u32) (ssid[i + 3]) << 24;
+ b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
+}
+
+static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
+{
+ b43_time_lock(dev);
+ if (dev->dev->id.revision >= 3) {
+ b43_write32(dev, 0x188, (beacon_int << 16));
+ } else {
+ b43_write16(dev, 0x606, (beacon_int >> 6));
+ b43_write16(dev, 0x610, beacon_int);
+ }
+ b43_time_unlock(dev);
+}
+
+static void handle_irq_beacon(struct b43_wldev *dev)
+{
+ u32 status;
+
+ if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ return;
+
+ dev->irq_savedstate &= ~B43_IRQ_BEACON;
+ status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+
+ if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+ /* ACK beacon IRQ. */
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
+ dev->irq_savedstate |= B43_IRQ_BEACON;
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = NULL;
+ return;
+ }
+ if (!(status & 0x1)) {
+ b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
+ status |= 0x1;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+ }
+ if (!(status & 0x2)) {
+ b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
+ status |= 0x2;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+ }
+}
+
+static void handle_irq_ucode_debug(struct b43_wldev *dev)
+{
+ //TODO
+}
+
+/* Interrupt handler bottom-half */
+static void b43_interrupt_tasklet(struct b43_wldev *dev)
+{
+ u32 reason;
+ u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
+ u32 merged_dma_reason = 0;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+ B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED);
+
+ reason = dev->irq_reason;
+ for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
+ dma_reason[i] = dev->dma_reason[i];
+ merged_dma_reason |= dma_reason[i];
+ }
+
+ if (unlikely(reason & B43_IRQ_MAC_TXERR))
+ b43err(dev->wl, "MAC transmission error\n");
+
+ if (unlikely(reason & B43_IRQ_PHY_TXERR))
+ b43err(dev->wl, "PHY transmission error\n");
+
+ if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
+ B43_DMAIRQ_NONFATALMASK))) {
+ if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
+ b43err(dev->wl, "Fatal DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ b43_controller_restart(dev, "DMA error");
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ return;
+ }
+ if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
+ b43err(dev->wl, "DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ }
+ }
+
+ if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
+ handle_irq_ucode_debug(dev);
+ if (reason & B43_IRQ_TBTT_INDI)
+ handle_irq_tbtt_indication(dev);
+ if (reason & B43_IRQ_ATIM_END)
+ handle_irq_atim_end(dev);
+ if (reason & B43_IRQ_BEACON)
+ handle_irq_beacon(dev);
+ if (reason & B43_IRQ_PMQ)
+ handle_irq_pmq(dev);
+ if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
+ ;/* TODO */
+ if (reason & B43_IRQ_NOISESAMPLE_OK)
+ handle_irq_noise(dev);
+
+ /* Check the DMA reason registers for received data. */
+ if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
+ if (b43_using_pio(dev))
+ b43_pio_rx(dev->pio.queue0);
+ else
+ b43_dma_rx(dev->dma.rx_ring0);
+ }
+ B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
+ if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
+ if (b43_using_pio(dev))
+ b43_pio_rx(dev->pio.queue3);
+ else
+ b43_dma_rx(dev->dma.rx_ring3);
+ }
+ B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
+
+ if (reason & B43_IRQ_TX_OK)
+ handle_irq_transmit_status(dev);
+
+ b43_interrupt_enable(dev, dev->irq_savedstate);
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
+{
+ u16 rxctl;
+
+ rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
+ if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
+ dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
+ else
+ dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
+}
+
+static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
+{
+ if (b43_using_pio(dev) &&
+ (dev->dev->id.revision < 3) &&
+ (!(reason & B43_IRQ_PIO_WORKAROUND))) {
+ /* Apply a PIO specific workaround to the dma_reasons */
+ pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
+ pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
+ pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
+ pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
+ }
+
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
+
+ b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
+ b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
+ b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
+ b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
+ b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
+ b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct b43_wldev *dev = dev_id;
+ u32 reason;
+
+ if (!dev)
+ return IRQ_NONE;
+
+ spin_lock(&dev->wl->irq_lock);
+
+ if (b43_status(dev) < B43_STAT_STARTED)
+ goto out;
+ reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (reason == 0xffffffff) /* shared IRQ */
+ goto out;
+ ret = IRQ_HANDLED;
+ reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ if (!reason)
+ goto out;
+
+ dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
+ & 0x0000DC00;
+
+ b43_interrupt_ack(dev, reason);
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ dev->irq_reason = reason;
+ tasklet_schedule(&dev->isr_tasklet);
+ out:
+ mmiowb();
+ spin_unlock(&dev->wl->irq_lock);
+
+ return ret;
+}
+
+static void b43_release_firmware(struct b43_wldev *dev)
+{
+ release_firmware(dev->fw.ucode);
+ dev->fw.ucode = NULL;
+ release_firmware(dev->fw.pcm);
+ dev->fw.pcm = NULL;
+ release_firmware(dev->fw.initvals);
+ dev->fw.initvals = NULL;
+ release_firmware(dev->fw.initvals_band);
+ dev->fw.initvals_band = NULL;
+}
+
+static void b43_print_fw_helptext(struct b43_wl *wl)
+{
+ b43err(wl, "You must go to "
+ "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware "
+ "and download the correct firmware (version 4).\n");
+}
+
+static int do_request_fw(struct b43_wldev *dev,
+ const char *name,
+ const struct firmware **fw)
+{
+ char path[sizeof(modparam_fwpostfix) + 32];
+ struct b43_fw_header *hdr;
+ u32 size;
+ int err;
+
+ if (!name)
+ return 0;
+
+ snprintf(path, ARRAY_SIZE(path),
+ "b43%s/%s.fw",
+ modparam_fwpostfix, name);
+ err = request_firmware(fw, path, dev->dev->dev);
+ if (err) {
+ b43err(dev->wl, "Firmware file \"%s\" not found "
+ "or load failed.\n", path);
+ return err;
+ }
+ if ((*fw)->size < sizeof(struct b43_fw_header))
+ goto err_format;
+ hdr = (struct b43_fw_header *)((*fw)->data);
+ switch (hdr->type) {
+ case B43_FW_TYPE_UCODE:
+ case B43_FW_TYPE_PCM:
+ size = be32_to_cpu(hdr->size);
+ if (size != (*fw)->size - sizeof(struct b43_fw_header))
+ goto err_format;
+ /* fallthrough */
+ case B43_FW_TYPE_IV:
+ if (hdr->ver != 1)
+ goto err_format;
+ break;
+ default:
+ goto err_format;
+ }
+
+ return err;
+
+err_format:
+ b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ return -EPROTO;
+}
+
+static int b43_request_firmware(struct b43_wldev *dev)
+{
+ struct b43_firmware *fw = &dev->fw;
+ const u8 rev = dev->dev->id.revision;
+ const char *filename;
+ u32 tmshigh;
+ int err;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ if (!fw->ucode) {
+ if ((rev >= 5) && (rev <= 10))
+ filename = "ucode5";
+ else if ((rev >= 11) && (rev <= 12))
+ filename = "ucode11";
+ else if (rev >= 13)
+ filename = "ucode13";
+ else
+ goto err_no_ucode;
+ err = do_request_fw(dev, filename, &fw->ucode);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->pcm) {
+ if ((rev >= 5) && (rev <= 10))
+ filename = "pcm5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_pcm;
+ err = do_request_fw(dev, filename, &fw->pcm);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals) {
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_GPHY)
+ filename = "a0g1initvals5";
+ else
+ filename = "a0g0initvals5";
+ } else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0initvals5";
+ else if (rev >= 13)
+ filename = "lp0initvals13";
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals_band) {
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_GPHY)
+ filename = "a0g1bsinitvals5";
+ else
+ filename = "a0g0bsinitvals5";
+ } else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0bsinitvals5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals_band);
+ if (err)
+ goto err_load;
+ }
+
+ return 0;
+
+err_load:
+ b43_print_fw_helptext(dev->wl);
+ goto error;
+
+err_no_ucode:
+ err = -ENODEV;
+ b43err(dev->wl, "No microcode available for core rev %u\n", rev);
+ goto error;
+
+err_no_pcm:
+ err = -ENODEV;
+ b43err(dev->wl, "No PCM available for core rev %u\n", rev);
+ goto error;
+
+err_no_initvals:
+ err = -ENODEV;
+ b43err(dev->wl, "No Initial Values firmware file for PHY %u, "
+ "core rev %u\n", dev->phy.type, rev);
+ goto error;
+
+error:
+ b43_release_firmware(dev);
+ return err;
+}
+
+static int b43_upload_microcode(struct b43_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43_fw_header);
+ const __be32 *data;
+ unsigned int i, len;
+ u16 fwrev, fwpatch, fwdate, fwtime;
+ u32 tmp;
+ int err = 0;
+
+ /* Upload Microcode. */
+ data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+ len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+ b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
+ for (i = 0; i < len; i++) {
+ b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
+ udelay(10);
+ }
+
+ if (dev->fw.pcm) {
+ /* Upload PCM data. */
+ data = (__be32 *) (dev->fw.pcm->data + hdr_len);
+ len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+ b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
+ b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
+ /* No need for autoinc bit in SHM_HW */
+ b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
+ for (i = 0; i < len; i++) {
+ b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
+ udelay(10);
+ }
+ }
+
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
+ b43_write32(dev, B43_MMIO_MACCTL,
+ B43_MACCTL_PSM_RUN |
+ B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+ /* Wait for the microcode to load and respond */
+ i = 0;
+ while (1) {
+ tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (tmp == B43_IRQ_MAC_SUSPENDED)
+ break;
+ i++;
+ if (i >= 50) {
+ b43err(dev->wl, "Microcode not responding\n");
+ b43_print_fw_helptext(dev->wl);
+ err = -ENODEV;
+ goto out;
+ }
+ udelay(10);
+ }
+ b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
+
+ /* Get and check the revisions. */
+ fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
+ fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
+ fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
+ fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
+
+ if (fwrev <= 0x128) {
+ b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
+ "binary drivers older than version 4.x is unsupported. "
+ "You must upgrade your firmware files.\n");
+ b43_print_fw_helptext(dev->wl);
+ b43_write32(dev, B43_MMIO_MACCTL, 0);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ b43dbg(dev->wl, "Loading firmware version %u.%u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+ fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+
+ dev->fw.rev = fwrev;
+ dev->fw.patch = fwpatch;
+
+ out:
+ return err;
+}
+
+static int b43_write_initvals(struct b43_wldev *dev,
+ const struct b43_iv *ivals,
+ size_t count,
+ size_t array_size)
+{
+ const struct b43_iv *iv;
+ u16 offset;
+ size_t i;
+ bool bit32;
+
+ BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
+ iv = ivals;
+ for (i = 0; i < count; i++) {
+ if (array_size < sizeof(iv->offset_size))
+ goto err_format;
+ array_size -= sizeof(iv->offset_size);
+ offset = be16_to_cpu(iv->offset_size);
+ bit32 = !!(offset & B43_IV_32BIT);
+ offset &= B43_IV_OFFSET_MASK;
+ if (offset >= 0x1000)
+ goto err_format;
+ if (bit32) {
+ u32 value;
+
+ if (array_size < sizeof(iv->data.d32))
+ goto err_format;
+ array_size -= sizeof(iv->data.d32);
+
+ value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ b43_write32(dev, offset, value);
+
+ iv = (const struct b43_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be32));
+ } else {
+ u16 value;
+
+ if (array_size < sizeof(iv->data.d16))
+ goto err_format;
+ array_size -= sizeof(iv->data.d16);
+
+ value = be16_to_cpu(iv->data.d16);
+ b43_write16(dev, offset, value);
+
+ iv = (const struct b43_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be16));
+ }
+ }
+ if (array_size)
+ goto err_format;
+
+ return 0;
+
+err_format:
+ b43err(dev->wl, "Initial Values Firmware file-format error.\n");
+ b43_print_fw_helptext(dev->wl);
+
+ return -EPROTO;
+}
+
+static int b43_upload_initvals(struct b43_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43_fw_header);
+ const struct b43_fw_header *hdr;
+ struct b43_firmware *fw = &dev->fw;
+ const struct b43_iv *ivals;
+ size_t count;
+ int err;
+
+ hdr = (const struct b43_fw_header *)(fw->initvals->data);
+ ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43_write_initvals(dev, ivals, count,
+ fw->initvals->size - hdr_len);
+ if (err)
+ goto out;
+ if (fw->initvals_band) {
+ hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
+ ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43_write_initvals(dev, ivals, count,
+ fw->initvals_band->size - hdr_len);
+ if (err)
+ goto out;
+ }
+out:
+
+ return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int b43_gpio_init(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+ u32 mask, set;
+
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_GPOUTSMSK);
+
+ b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
+ | 0x000F);
+
+ mask = 0x0000001F;
+ set = 0x0000000F;
+ if (dev->dev->bus->chip_id == 0x4301) {
+ mask |= 0x0060;
+ set |= 0x0060;
+ }
+ if (0 /* FIXME: conditional unknown */ ) {
+ b43_write16(dev, B43_MMIO_GPIO_MASK,
+ b43_read16(dev, B43_MMIO_GPIO_MASK)
+ | 0x0100);
+ mask |= 0x0180;
+ set |= 0x0180;
+ }
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+ b43_write16(dev, B43_MMIO_GPIO_MASK,
+ b43_read16(dev, B43_MMIO_GPIO_MASK)
+ | 0x0200);
+ mask |= 0x0200;
+ set |= 0x0200;
+ }
+ if (dev->dev->id.revision >= 2)
+ mask |= 0x0010; /* FIXME: This is redundant. */
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return 0;
+ ssb_write32(gpiodev, B43_GPIO_CONTROL,
+ (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+ & mask) | set);
+
+ return 0;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static void b43_gpio_cleanup(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return;
+ ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void b43_mac_enable(struct b43_wldev *dev)
+{
+ dev->mac_suspended--;
+ B43_WARN_ON(dev->mac_suspended < 0);
+ B43_WARN_ON(irqs_disabled());
+ if (dev->mac_suspended == 0) {
+ b43_write32(dev, B43_MMIO_MACCTL,
+ b43_read32(dev, B43_MMIO_MACCTL)
+ | B43_MACCTL_ENABLED);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
+ B43_IRQ_MAC_SUSPENDED);
+ /* Commit writes */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ b43_power_saving_ctl_bits(dev, 0);
+
+ /* Re-enable IRQs. */
+ spin_lock_irq(&dev->wl->irq_lock);
+ b43_interrupt_enable(dev, dev->irq_savedstate);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void b43_mac_suspend(struct b43_wldev *dev)
+{
+ int i;
+ u32 tmp;
+
+ might_sleep();
+ B43_WARN_ON(irqs_disabled());
+ B43_WARN_ON(dev->mac_suspended < 0);
+
+ if (dev->mac_suspended == 0) {
+ /* Mask IRQs before suspending MAC. Otherwise
+ * the MAC stays busy and won't suspend. */
+ spin_lock_irq(&dev->wl->irq_lock);
+ tmp = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ b43_synchronize_irq(dev);
+ dev->irq_savedstate = tmp;
+
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+ b43_write32(dev, B43_MMIO_MACCTL,
+ b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_ENABLED);
+ /* force pci to flush the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ for (i = 40; i; i--) {
+ tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (tmp & B43_IRQ_MAC_SUSPENDED)
+ goto out;
+ msleep(1);
+ }
+ b43err(dev->wl, "MAC suspend failed\n");
+ }
+out:
+ dev->mac_suspended++;
+}
+
+static void b43_adjust_opmode(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ u32 ctl;
+ u16 cfp_pretbtt;
+
+ ctl = b43_read32(dev, B43_MMIO_MACCTL);
+ /* Reset status to STA infrastructure mode. */
+ ctl &= ~B43_MACCTL_AP;
+ ctl &= ~B43_MACCTL_KEEP_CTL;
+ ctl &= ~B43_MACCTL_KEEP_BADPLCP;
+ ctl &= ~B43_MACCTL_KEEP_BAD;
+ ctl &= ~B43_MACCTL_PROMISC;
+ ctl &= ~B43_MACCTL_BEACPROMISC;
+ ctl |= B43_MACCTL_INFRA;
+
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ ctl |= B43_MACCTL_AP;
+ else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ ctl &= ~B43_MACCTL_INFRA;
+
+ if (wl->filter_flags & FIF_CONTROL)
+ ctl |= B43_MACCTL_KEEP_CTL;
+ if (wl->filter_flags & FIF_FCSFAIL)
+ ctl |= B43_MACCTL_KEEP_BAD;
+ if (wl->filter_flags & FIF_PLCPFAIL)
+ ctl |= B43_MACCTL_KEEP_BADPLCP;
+ if (wl->filter_flags & FIF_PROMISC_IN_BSS)
+ ctl |= B43_MACCTL_PROMISC;
+ if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+ ctl |= B43_MACCTL_BEACPROMISC;
+
+ /* Workaround: On old hardware the HW-MAC-address-filter
+ * doesn't work properly, so always run promisc in filter
+ * it in software. */
+ if (dev->dev->id.revision <= 4)
+ ctl |= B43_MACCTL_PROMISC;
+
+ b43_write32(dev, B43_MMIO_MACCTL, ctl);
+
+ cfp_pretbtt = 2;
+ if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
+ if (dev->dev->bus->chip_id == 0x4306 &&
+ dev->dev->bus->chip_rev == 3)
+ cfp_pretbtt = 100;
+ else
+ cfp_pretbtt = 50;
+ }
+ b43_write16(dev, 0x612, cfp_pretbtt);
+}
+
+static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
+{
+ u16 offset;
+
+ if (is_ofdm) {
+ offset = 0x480;
+ offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+ } else {
+ offset = 0x4C0;
+ offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
+ b43_shm_read16(dev, B43_SHM_SHARED, offset));
+}
+
+static void b43_rate_memory_init(struct b43_wldev *dev)
+{
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ case B43_PHYTYPE_G:
+ b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
+ if (dev->phy.type == B43_PHYTYPE_A)
+ break;
+ /* fallthrough */
+ case B43_PHYTYPE_B:
+ b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
+ b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
+ b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
+ b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+/* Set the TX-Antenna for management frames sent by firmware. */
+static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
+{
+ u16 ant = 0;
+ u16 tmp;
+
+ switch (antenna) {
+ case B43_ANTENNA0:
+ ant |= B43_TX4_PHY_ANT0;
+ break;
+ case B43_ANTENNA1:
+ ant |= B43_TX4_PHY_ANT1;
+ break;
+ case B43_ANTENNA_AUTO:
+ ant |= B43_TX4_PHY_ANTLAST;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ /* FIXME We also need to set the other flags of the PHY control field somewhere. */
+
+ /* For Beacons */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
+ tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
+ /* For ACK/CTS */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
+ tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
+ /* For Probe Resposes */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
+ tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
+}
+
+/* This is the opposite of b43_chip_init() */
+static void b43_chip_exit(struct b43_wldev *dev)
+{
+ b43_radio_turn_off(dev, 1);
+ b43_leds_exit(dev);
+ b43_gpio_cleanup(dev);
+ /* firmware is released later */
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int b43_chip_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int err, tmp;
+ u32 value32;
+ u16 value16;
+
+ b43_write32(dev, B43_MMIO_MACCTL,
+ B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+
+ err = b43_request_firmware(dev);
+ if (err)
+ goto out;
+ err = b43_upload_microcode(dev);
+ if (err)
+ goto out; /* firmware is released later */
+
+ err = b43_gpio_init(dev);
+ if (err)
+ goto out; /* firmware is released later */
+ b43_leds_init(dev);
+
+ err = b43_upload_initvals(dev);
+ if (err)
+ goto err_leds_exit;
+ b43_radio_turn_on(dev);
+
+ b43_write16(dev, 0x03E6, 0x0000);
+ err = b43_phy_init(dev);
+ if (err)
+ goto err_radio_off;
+
+ /* Select initial Interference Mitigation. */
+ tmp = phy->interfmode;
+ phy->interfmode = B43_INTERFMODE_NONE;
+ b43_radio_set_interference_mitigation(dev, tmp);
+
+ b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
+ b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
+
+ if (phy->type == B43_PHYTYPE_B) {
+ value16 = b43_read16(dev, 0x005E);
+ value16 |= 0x0004;
+ b43_write16(dev, 0x005E, value16);
+ }
+ b43_write32(dev, 0x0100, 0x01000000);
+ if (dev->dev->id.revision < 5)
+ b43_write32(dev, 0x010C, 0x01000000);
+
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_INFRA);
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ | B43_MACCTL_INFRA);
+
+ if (b43_using_pio(dev)) {
+ b43_write32(dev, 0x0210, 0x00000100);
+ b43_write32(dev, 0x0230, 0x00000100);
+ b43_write32(dev, 0x0250, 0x00000100);
+ b43_write32(dev, 0x0270, 0x00000100);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
+ }
+
+ /* Probe Response Timeout value */
+ /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
+
+ /* Initially set the wireless operation mode. */
+ b43_adjust_opmode(dev);
+
+ if (dev->dev->id.revision < 3) {
+ b43_write16(dev, 0x060E, 0x0000);
+ b43_write16(dev, 0x0610, 0x8000);
+ b43_write16(dev, 0x0604, 0x0000);
+ b43_write16(dev, 0x0606, 0x0200);
+ } else {
+ b43_write32(dev, 0x0188, 0x80000000);
+ b43_write32(dev, 0x018C, 0x02000000);
+ }
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
+ b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+ b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+ b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+ b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+ b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+ b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+ value32 = ssb_read32(dev->dev, SSB_TMSLOW);
+ value32 |= 0x00100000;
+ ssb_write32(dev->dev, SSB_TMSLOW, value32);
+
+ b43_write16(dev, B43_MMIO_POWERUP_DELAY,
+ dev->dev->bus->chipco.fast_pwrup_delay);
+
+ err = 0;
+ b43dbg(dev->wl, "Chip initialized\n");
+out:
+ return err;
+
+err_radio_off:
+ b43_radio_turn_off(dev, 1);
+err_leds_exit:
+ b43_leds_exit(dev);
+ b43_gpio_cleanup(dev);
+ return err;
+}
+
+static void b43_periodic_every120sec(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->type != B43_PHYTYPE_G || phy->rev < 2)
+ return;
+
+ b43_mac_suspend(dev);
+ b43_lo_g_measure(dev);
+ b43_mac_enable(dev);
+ if (b43_has_hardware_pctl(phy))
+ b43_lo_g_ctl_mark_all_unused(dev);
+}
+
+static void b43_periodic_every60sec(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!b43_has_hardware_pctl(phy))
+ b43_lo_g_ctl_mark_all_unused(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+ b43_mac_suspend(dev);
+ b43_calc_nrssi_slope(dev);
+ if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
+ u8 old_chan = phy->channel;
+
+ /* VCO Calibration */
+ if (old_chan >= 8)
+ b43_radio_selectchannel(dev, 1, 0);
+ else
+ b43_radio_selectchannel(dev, 13, 0);
+ b43_radio_selectchannel(dev, old_chan, 0);
+ }
+ b43_mac_enable(dev);
+ }
+}
+
+static void b43_periodic_every30sec(struct b43_wldev *dev)
+{
+ /* Update device statistics. */
+ b43_calculate_link_quality(dev);
+}
+
+static void b43_periodic_every15sec(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->type == B43_PHYTYPE_G) {
+ //TODO: update_aci_moving_average
+ if (phy->aci_enable && phy->aci_wlan_automatic) {
+ b43_mac_suspend(dev);
+ if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
+ if (0 /*TODO: bunch of conditions */ ) {
+ b43_radio_set_interference_mitigation
+ (dev, B43_INTERFMODE_MANUALWLAN);
+ }
+ } else if (1 /*TODO*/) {
+ /*
+ if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
+ b43_radio_set_interference_mitigation(dev,
+ B43_INTERFMODE_NONE);
+ }
+ */
+ }
+ b43_mac_enable(dev);
+ } else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
+ phy->rev == 1) {
+ //TODO: implement rev1 workaround
+ }
+ }
+ b43_phy_xmitpower(dev); //FIXME: unless scanning?
+ //TODO for APHY (temperature?)
+}
+
+static void do_periodic_work(struct b43_wldev *dev)
+{
+ unsigned int state;
+
+ state = dev->periodic_state;
+ if (state % 8 == 0)
+ b43_periodic_every120sec(dev);
+ if (state % 4 == 0)
+ b43_periodic_every60sec(dev);
+ if (state % 2 == 0)
+ b43_periodic_every30sec(dev);
+ b43_periodic_every15sec(dev);
+}
+
+/* Periodic work locking policy:
+ * The whole periodic work handler is protected by
+ * wl->mutex. If another lock is needed somewhere in the
+ * pwork callchain, it's aquired in-place, where it's needed.
+ */
+static void b43_periodic_work_handler(struct work_struct *work)
+{
+ struct b43_wldev *dev = container_of(work, struct b43_wldev,
+ periodic_work.work);
+ struct b43_wl *wl = dev->wl;
+ unsigned long delay;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(b43_status(dev) != B43_STAT_STARTED))
+ goto out;
+ if (b43_debug(dev, B43_DBG_PWORK_STOP))
+ goto out_requeue;
+
+ do_periodic_work(dev);
+
+ dev->periodic_state++;
+out_requeue:
+ if (b43_debug(dev, B43_DBG_PWORK_FAST))
+ delay = msecs_to_jiffies(50);
+ else
+ delay = round_jiffies(HZ * 15);
+ queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static void b43_periodic_tasks_setup(struct b43_wldev *dev)
+{
+ struct delayed_work *work = &dev->periodic_work;
+
+ dev->periodic_state = 0;
+ INIT_DELAYED_WORK(work, b43_periodic_work_handler);
+ queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+}
+
+/* Validate access to the chip (SHM) */
+static int b43_validate_chipaccess(struct b43_wldev *dev)
+{
+ u32 value;
+ u32 shm_backup;
+
+ shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+ if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
+ goto error;
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
+ if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
+ goto error;
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
+
+ value = b43_read32(dev, B43_MMIO_MACCTL);
+ if ((value | B43_MACCTL_GMODE) !=
+ (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+ goto error;
+
+ value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (value)
+ goto error;
+
+ return 0;
+ error:
+ b43err(dev->wl, "Failed to validate the chipaccess\n");
+ return -ENODEV;
+}
+
+static void b43_security_init(struct b43_wldev *dev)
+{
+ dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
+ B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
+ dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
+ /* KTP is a word address, but we address SHM bytewise.
+ * So multiply by two.
+ */
+ dev->ktp *= 2;
+ if (dev->dev->id.revision >= 5) {
+ /* Number of RCMTA address slots */
+ b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8);
+ }
+ b43_clear_keys(dev);
+}
+
+static int b43_rng_read(struct hwrng *rng, u32 * data)
+{
+ struct b43_wl *wl = (struct b43_wl *)rng->priv;
+ unsigned long flags;
+
+ /* Don't take wl->mutex here, as it could deadlock with
+ * hwrng internal locking. It's not needed to take
+ * wl->mutex here, anyway. */
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *data = b43_read16(wl->current_dev, B43_MMIO_RNG);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return (sizeof(u16));
+}
+
+static void b43_rng_exit(struct b43_wl *wl)
+{
+ if (wl->rng_initialized)
+ hwrng_unregister(&wl->rng);
+}
+
+static int b43_rng_init(struct b43_wl *wl)
+{
+ int err;
+
+ snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
+ "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
+ wl->rng.name = wl->rng_name;
+ wl->rng.data_read = b43_rng_read;
+ wl->rng.priv = (unsigned long)wl;
+ wl->rng_initialized = 1;
+ err = hwrng_register(&wl->rng);
+ if (err) {
+ wl->rng_initialized = 0;
+ b43err(wl, "Failed to register the random "
+ "number generator (%d)\n", err);
+ }
+
+ return err;
+}
+
+static int b43_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ int err = -ENODEV;
+ unsigned long flags;
+
+ if (unlikely(!dev))
+ goto out;
+ if (unlikely(b43_status(dev) < B43_STAT_STARTED))
+ goto out;
+ /* DMA-TX is done without a global lock. */
+ if (b43_using_pio(dev)) {
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ err = b43_pio_tx(dev, skb, ctl);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ } else
+ err = b43_dma_tx(dev, skb, ctl);
+ out:
+ if (unlikely(err))
+ return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
+}
+
+static int b43_conf_tx(struct ieee80211_hw *hw,
+ int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ return 0;
+}
+
+static int b43_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ int err = -ENODEV;
+
+ if (!dev)
+ goto out;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
+ if (b43_using_pio(dev))
+ b43_pio_get_tx_stats(dev, stats);
+ else
+ b43_dma_get_tx_stats(dev, stats);
+ err = 0;
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out:
+ return err;
+}
+
+static int b43_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ memcpy(stats, &wl->ieee_stats, sizeof(*stats));
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+}
+
+static const char *phymode_to_string(unsigned int phymode)
+{
+ switch (phymode) {
+ case B43_PHYMODE_A:
+ return "A";
+ case B43_PHYMODE_B:
+ return "B";
+ case B43_PHYMODE_G:
+ return "G";
+ default:
+ B43_WARN_ON(1);
+ }
+ return "";
+}
+
+static int find_wldev_for_phymode(struct b43_wl *wl,
+ unsigned int phymode,
+ struct b43_wldev **dev, bool * gmode)
+{
+ struct b43_wldev *d;
+
+ list_for_each_entry(d, &wl->devlist, list) {
+ if (d->phy.possible_phymodes & phymode) {
+ /* Ok, this device supports the PHY-mode.
+ * Now figure out how the gmode bit has to be
+ * set to support it. */
+ if (phymode == B43_PHYMODE_A)
+ *gmode = 0;
+ else
+ *gmode = 1;
+ *dev = d;
+
+ return 0;
+ }
+ }
+
+ return -ESRCH;
+}
+
+static void b43_put_phy_into_reset(struct b43_wldev *dev)
+{
+ struct ssb_device *sdev = dev->dev;
+ u32 tmslow;
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~B43_TMSLOW_GMODE;
+ tmslow |= B43_TMSLOW_PHYRESET;
+ tmslow |= SSB_TMSLOW_FGC;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ tmslow |= B43_TMSLOW_PHYRESET;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+}
+
+/* Expects wl->mutex locked */
+static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
+{
+ struct b43_wldev *up_dev;
+ struct b43_wldev *down_dev;
+ int err;
+ bool gmode = 0;
+ int prev_status;
+
+ err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+ if (err) {
+ b43err(wl, "Could not find a device for %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ return err;
+ }
+ if ((up_dev == wl->current_dev) &&
+ (!!wl->current_dev->phy.gmode == !!gmode)) {
+ /* This device is already running. */
+ return 0;
+ }
+ b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+ phymode_to_string(new_mode));
+ down_dev = wl->current_dev;
+
+ prev_status = b43_status(down_dev);
+ /* Shutdown the currently running core. */
+ if (prev_status >= B43_STAT_STARTED)
+ b43_wireless_core_stop(down_dev);
+ if (prev_status >= B43_STAT_INITIALIZED)
+ b43_wireless_core_exit(down_dev);
+
+ if (down_dev != up_dev) {
+ /* We switch to a different core, so we put PHY into
+ * RESET on the old core. */
+ b43_put_phy_into_reset(down_dev);
+ }
+
+ /* Now start the new core. */
+ up_dev->phy.gmode = gmode;
+ if (prev_status >= B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(up_dev);
+ if (err) {
+ b43err(wl, "Fatal: Could not initialize device for "
+ "newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ goto init_failure;
+ }
+ }
+ if (prev_status >= B43_STAT_STARTED) {
+ err = b43_wireless_core_start(up_dev);
+ if (err) {
+ b43err(wl, "Fatal: Coult not start device for "
+ "newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ b43_wireless_core_exit(up_dev);
+ goto init_failure;
+ }
+ }
+ B43_WARN_ON(b43_status(up_dev) != prev_status);
+
+ wl->current_dev = up_dev;
+
+ return 0;
+ init_failure:
+ /* Whoops, failed to init the new core. No core is operating now. */
+ wl->current_dev = NULL;
+ return err;
+}
+
+static int b43_antenna_from_ieee80211(u8 antenna)
+{
+ switch (antenna) {
+ case 0: /* default/diversity */
+ return B43_ANTENNA_DEFAULT;
+ case 1: /* Antenna 0 */
+ return B43_ANTENNA0;
+ case 2: /* Antenna 1 */
+ return B43_ANTENNA1;
+ default:
+ return B43_ANTENNA_DEFAULT;
+ }
+}
+
+static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ struct b43_phy *phy;
+ unsigned long flags;
+ unsigned int new_phymode = 0xFFFF;
+ int antenna_tx;
+ int antenna_rx;
+ int err = 0;
+ u32 savedirqs;
+
+ antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
+ antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+ mutex_lock(&wl->mutex);
+
+ /* Switch the PHY mode (if necessary). */
+ switch (conf->phymode) {
+ case MODE_IEEE80211A:
+ new_phymode = B43_PHYMODE_A;
+ break;
+ case MODE_IEEE80211B:
+ new_phymode = B43_PHYMODE_B;
+ break;
+ case MODE_IEEE80211G:
+ new_phymode = B43_PHYMODE_G;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ err = b43_switch_phymode(wl, new_phymode);
+ if (err)
+ goto out_unlock_mutex;
+ dev = wl->current_dev;
+ phy = &dev->phy;
+
+ /* Disable IRQs while reconfiguring the device.
+ * This makes it possible to drop the spinlock throughout
+ * the reconfiguration process. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (b43_status(dev) < B43_STAT_STARTED) {
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ goto out_unlock_mutex;
+ }
+ savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43_synchronize_irq(dev);
+
+ /* Switch to the requested channel.
+ * The firmware takes care of races with the TX handler. */
+ if (conf->channel_val != phy->channel)
+ b43_radio_selectchannel(dev, conf->channel_val, 0);
+
+ /* Enable/Disable ShortSlot timing. */
+ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
+ dev->short_slot) {
+ B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+ if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+ b43_short_slot_timing_enable(dev);
+ else
+ b43_short_slot_timing_disable(dev);
+ }
+
+ /* Adjust the desired TX power level. */
+ if (conf->power_level != 0) {
+ if (conf->power_level != phy->power_level) {
+ phy->power_level = conf->power_level;
+ b43_phy_xmitpower(dev);
+ }
+ }
+
+ /* Antennas for RX and management frame TX. */
+ b43_mgmtframe_txantenna(dev, antenna_tx);
+ b43_set_rx_antenna(dev, antenna_rx);
+
+ /* Update templates for AP mode. */
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ b43_set_beacon_int(dev, conf->beacon_int);
+
+ if (!!conf->radio_enabled != phy->radio_on) {
+ if (conf->radio_enabled) {
+ b43_radio_turn_on(dev);
+ b43info(dev->wl, "Radio turned on by software\n");
+ if (!dev->radio_hw_enable) {
+ b43info(dev->wl, "The hardware RF-kill button "
+ "still turns the radio physically off. "
+ "Press the button to turn it on.\n");
+ }
+ } else {
+ b43_radio_turn_off(dev, 0);
+ b43info(dev->wl, "Radio turned off by software\n");
+ }
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_interrupt_enable(dev, savedirqs);
+ mmiowb();
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out_unlock_mutex:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ u8 algorithm;
+ u8 index;
+ int err = -EINVAL;
+ DECLARE_MAC_BUF(mac);
+
+ if (modparam_nohwcrypt)
+ return -ENOSPC; /* User disabled HW-crypto */
+
+ if (!dev)
+ return -ENODEV;
+ switch (key->alg) {
+ case ALG_WEP:
+ if (key->keylen == 5)
+ algorithm = B43_SEC_ALGO_WEP40;
+ else
+ algorithm = B43_SEC_ALGO_WEP104;
+ break;
+ case ALG_TKIP:
+ algorithm = B43_SEC_ALGO_TKIP;
+ break;
+ case ALG_CCMP:
+ algorithm = B43_SEC_ALGO_AES;
+ break;
+ default:
+ B43_WARN_ON(1);
+ goto out;
+ }
+
+ index = (u8) (key->keyidx);
+ if (index > 3)
+ goto out;
+
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ switch (cmd) {
+ case SET_KEY:
+ if (algorithm == B43_SEC_ALGO_TKIP) {
+ /* FIXME: No TKIP hardware encryption for now. */
+ err = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ if (is_broadcast_ether_addr(addr)) {
+ /* addr is FF:FF:FF:FF:FF:FF for default keys */
+ err = b43_key_write(dev, index, algorithm,
+ key->key, key->keylen, NULL, key);
+ } else {
+ /*
+ * either pairwise key or address is 00:00:00:00:00:00
+ * for transmit-only keys
+ */
+ err = b43_key_write(dev, -1, algorithm,
+ key->key, key->keylen, addr, key);
+ }
+ if (err)
+ goto out_unlock;
+
+ if (algorithm == B43_SEC_ALGO_WEP40 ||
+ algorithm == B43_SEC_ALGO_WEP104) {
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
+ } else {
+ b43_hf_write(dev,
+ b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ break;
+ case DISABLE_KEY: {
+ err = b43_key_clear(dev, key->hw_key_idx);
+ if (err)
+ goto out_unlock;
+ break;
+ }
+ default:
+ B43_WARN_ON(1);
+ }
+out_unlock:
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+out:
+ if (!err) {
+ b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
+ "mac: %s\n",
+ cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
+ print_mac(mac, addr));
+ }
+ return err;
+}
+
+static void b43_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed, unsigned int *fflags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev) {
+ *fflags = 0;
+ return;
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *fflags &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ changed &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ wl->filter_flags = *fflags;
+
+ if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
+ b43_adjust_opmode(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+}
+
+static int b43_config_interface(struct ieee80211_hw *hw,
+ int if_id, struct ieee80211_if_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ B43_WARN_ON(wl->if_id != if_id);
+ if (conf->bssid)
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ else
+ memset(wl->bssid, 0, ETH_ALEN);
+ if (b43_status(dev) >= B43_STAT_INITIALIZED) {
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+ B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+ if (conf->beacon)
+ b43_refresh_templates(dev, conf->beacon);
+ }
+ b43_write_mac_bssid_templates(dev);
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+/* Locking: wl->mutex */
+static void b43_wireless_core_stop(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned long flags;
+
+ if (b43_status(dev) < B43_STAT_STARTED)
+ return;
+ b43_set_status(dev, B43_STAT_INITIALIZED);
+
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel the possibly running self-rearming periodic work. */
+ 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.
+
+ /* Disable and sync interrupts. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43_synchronize_irq(dev);
+
+ b43_mac_suspend(dev);
+ free_irq(dev->dev->irq, dev);
+ b43dbg(wl, "Wireless interface stopped\n");
+}
+
+/* Locking: wl->mutex */
+static int b43_wireless_core_start(struct b43_wldev *dev)
+{
+ int err;
+
+ B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
+
+ drain_txstatus_queue(dev);
+ err = request_irq(dev->dev->irq, b43_interrupt_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+ goto out;
+ }
+
+ /* We are ready to run. */
+ b43_set_status(dev, B43_STAT_STARTED);
+
+ /* Start data flow (TX/RX). */
+ b43_mac_enable(dev);
+ b43_interrupt_enable(dev, dev->irq_savedstate);
+ ieee80211_start_queues(dev->wl->hw);
+
+ /* Start maintainance work */
+ b43_periodic_tasks_setup(dev);
+
+ b43dbg(dev->wl, "Wireless interface started\n");
+ out:
+ return err;
+}
+
+/* Get PHY and RADIO versioning numbers */
+static int b43_phy_versioning(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u32 tmp;
+ u8 analog_type;
+ u8 phy_type;
+ u8 phy_rev;
+ u16 radio_manuf;
+ u16 radio_ver;
+ u16 radio_rev;
+ int unsupported = 0;
+
+ /* Get PHY versioning */
+ tmp = b43_read16(dev, B43_MMIO_PHY_VER);
+ analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
+ phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
+ phy_rev = (tmp & B43_PHYVER_VERSION);
+ switch (phy_type) {
+ case B43_PHYTYPE_A:
+ if (phy_rev >= 4)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_B:
+ if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
+ && phy_rev != 7)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_G:
+ if (phy_rev > 8)
+ unsupported = 1;
+ break;
+ default:
+ unsupported = 1;
+ };
+ if (unsupported) {
+ b43err(dev->wl, "FOUND UNSUPPORTED PHY "
+ "(Analog %u, Type %u, Revision %u)\n",
+ analog_type, phy_type, phy_rev);
+ return -EOPNOTSUPP;
+ }
+ b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
+ analog_type, phy_type, phy_rev);
+
+ /* Get RADIO versioning */
+ if (dev->dev->bus->chip_id == 0x4317) {
+ if (dev->dev->bus->chip_rev == 0)
+ tmp = 0x3205017F;
+ else if (dev->dev->bus->chip_rev == 1)
+ tmp = 0x4205017F;
+ else
+ tmp = 0x5205017F;
+ } else {
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
+ tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
+ tmp <<= 16;
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
+ tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+ }
+ radio_manuf = (tmp & 0x00000FFF);
+ radio_ver = (tmp & 0x0FFFF000) >> 12;
+ radio_rev = (tmp & 0xF0000000) >> 28;
+ switch (phy_type) {
+ case B43_PHYTYPE_A:
+ if (radio_ver != 0x2060)
+ unsupported = 1;
+ if (radio_rev != 1)
+ unsupported = 1;
+ if (radio_manuf != 0x17F)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_B:
+ if ((radio_ver & 0xFFF0) != 0x2050)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_G:
+ if (radio_ver != 0x2050)
+ unsupported = 1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ if (unsupported) {
+ b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
+ "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
+ radio_manuf, radio_ver, radio_rev);
+ return -EOPNOTSUPP;
+ }
+ b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
+ radio_manuf, radio_ver, radio_rev);
+
+ phy->radio_manuf = radio_manuf;
+ phy->radio_ver = radio_ver;
+ phy->radio_rev = radio_rev;
+
+ phy->analog = analog_type;
+ phy->type = phy_type;
+ phy->rev = phy_rev;
+
+ return 0;
+}
+
+static void setup_struct_phy_for_init(struct b43_wldev *dev,
+ struct b43_phy *phy)
+{
+ struct b43_txpower_lo_control *lo;
+ int i;
+
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->locked = 0;
+
+ phy->aci_enable = 0;
+ phy->aci_wlan_automatic = 0;
+ phy->aci_hw_rssi = 0;
+
+ phy->radio_off_context.valid = 0;
+
+ lo = phy->lo_control;
+ if (lo) {
+ memset(lo, 0, sizeof(*(phy->lo_control)));
+ lo->rebuild = 1;
+ lo->tx_bias = 0xFF;
+ }
+ phy->max_lb_gain = 0;
+ phy->trsw_rx_gain = 0;
+ phy->txpwr_offset = 0;
+
+ /* NRSSI */
+ phy->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+ phy->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+ phy->nrssi_lt[i] = i;
+
+ phy->lofcal = 0xFFFF;
+ phy->initval = 0xFFFF;
+
+ spin_lock_init(&phy->lock);
+ phy->interfmode = B43_INTERFMODE_NONE;
+ phy->channel = 0xFF;
+
+ phy->hardware_power_control = !!modparam_hwpctl;
+}
+
+static void setup_struct_wldev_for_init(struct b43_wldev *dev)
+{
+ /* Flags */
+ dev->reg124_set_0x4 = 0;
+ /* Assume the radio is enabled. If it's not enabled, the state will
+ * immediately get fixed on the first periodic work run. */
+ dev->radio_hw_enable = 1;
+
+ /* Stats */
+ memset(&dev->stats, 0, sizeof(dev->stats));
+
+ setup_struct_phy_for_init(dev, &dev->phy);
+
+ /* IRQ related flags */
+ dev->irq_reason = 0;
+ memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
+ dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
+
+ dev->mac_suspended = 1;
+
+ /* Noise calculation context */
+ memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
+}
+
+static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
+{
+ struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ u32 hf;
+
+ if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+ return;
+ if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
+ return;
+
+ hf = b43_hf_read(dev);
+ if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+ hf |= B43_HF_BTCOEXALT;
+ else
+ hf |= B43_HF_BTCOEX;
+ b43_hf_write(dev, hf);
+ //TODO
+}
+
+static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
+{ //TODO
+}
+
+static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ struct ssb_bus *bus = dev->dev->bus;
+ u32 tmp;
+
+ if (bus->pcicore.dev &&
+ bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
+ bus->pcicore.dev->id.revision <= 5) {
+ /* IMCFGLO timeouts workaround. */
+ tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ tmp |= 0x32;
+ break;
+ case SSB_BUSTYPE_SSB:
+ tmp |= 0x53;
+ break;
+ }
+ ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+ }
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+}
+
+/* Shutdown a wireless core */
+/* Locking: wl->mutex */
+static void b43_wireless_core_exit(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
+ if (b43_status(dev) != B43_STAT_INITIALIZED)
+ return;
+ b43_set_status(dev, B43_STAT_UNINIT);
+
+ mutex_unlock(&dev->wl->mutex);
+ b43_rfkill_exit(dev);
+ mutex_lock(&dev->wl->mutex);
+
+ b43_rng_exit(dev->wl);
+ b43_pio_free(dev);
+ b43_dma_free(dev);
+ b43_chip_exit(dev);
+ b43_radio_turn_off(dev, 1);
+ b43_switch_analog(dev, 0);
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(dev->dev->bus);
+}
+
+/* Initialize a wireless core */
+static int b43_wireless_core_init(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_sprom *sprom = &bus->sprom;
+ struct b43_phy *phy = &dev->phy;
+ int err;
+ u32 hf, tmp;
+
+ B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto out;
+ if (!ssb_device_is_enabled(dev->dev)) {
+ tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
+ b43_wireless_core_reset(dev, tmp);
+ }
+
+ if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
+ phy->lo_control =
+ kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
+ if (!phy->lo_control) {
+ err = -ENOMEM;
+ goto err_busdown;
+ }
+ }
+ setup_struct_wldev_for_init(dev);
+
+ err = b43_phy_init_tssi2dbm_table(dev);
+ if (err)
+ goto err_kfree_lo_control;
+
+ /* Enable IRQ routing to this device. */
+ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+
+ b43_imcfglo_timeouts_workaround(dev);
+ b43_bluetooth_coext_disable(dev);
+ b43_phy_early_init(dev);
+ err = b43_chip_init(dev);
+ if (err)
+ goto err_kfree_tssitbl;
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
+ hf = b43_hf_read(dev);
+ if (phy->type == B43_PHYTYPE_G) {
+ hf |= B43_HF_SYMW;
+ if (phy->rev == 1)
+ hf |= B43_HF_GDCW;
+ if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+ hf |= B43_HF_OFDMPABOOST;
+ } else if (phy->type == B43_PHYTYPE_B) {
+ hf |= B43_HF_SYMW;
+ if (phy->rev >= 2 && phy->radio_ver == 0x2050)
+ hf &= ~B43_HF_GDCW;
+ }
+ b43_hf_write(dev, hf);
+
+ /* Short/Long Retry Limit.
+ * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+ * the chip-internal counter.
+ */
+ tmp = limit_value(modparam_short_retry, 0, 0xF);
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
+ tmp = limit_value(modparam_long_retry, 0, 0xF);
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
+
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
+
+ /* Disable sending probe responses from firmware.
+ * Setting the MaxTime to one usec will always trigger
+ * a timeout, so we never send any probe resp.
+ * A timeout of zero is infinite. */
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
+
+ b43_rate_memory_init(dev);
+
+ /* Minimum Contention Window */
+ if (phy->type == B43_PHYTYPE_B) {
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
+ } else {
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
+ }
+ /* Maximum Contention Window */
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
+
+ do {
+ if (b43_using_pio(dev)) {
+ err = b43_pio_init(dev);
+ } else {
+ err = b43_dma_init(dev);
+ if (!err)
+ b43_qos_init(dev);
+ }
+ } while (err == -EAGAIN);
+ if (err)
+ goto err_chip_exit;
+
+//FIXME
+#if 1
+ b43_write16(dev, 0x0612, 0x0050);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4);
+#endif
+
+ b43_bluetooth_coext_enable(dev);
+
+ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+ memset(wl->bssid, 0, ETH_ALEN);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43_upload_card_macaddress(dev);
+ b43_security_init(dev);
+ b43_rfkill_init(dev);
+ b43_rng_init(wl);
+
+ b43_set_status(dev, B43_STAT_INITIALIZED);
+
+ out:
+ return err;
+
+ err_chip_exit:
+ b43_chip_exit(dev);
+ err_kfree_tssitbl:
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+ err_kfree_lo_control:
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ err_busdown:
+ ssb_bus_may_powerdown(bus);
+ B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
+ return err;
+}
+
+static int b43_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+
+ /* TODO: allow WDS/AP devices to coexist */
+
+ if (conf->type != IEEE80211_IF_TYPE_AP &&
+ conf->type != IEEE80211_IF_TYPE_STA &&
+ conf->type != IEEE80211_IF_TYPE_WDS &&
+ conf->type != IEEE80211_IF_TYPE_IBSS)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&wl->mutex);
+ if (wl->operating)
+ goto out_mutex_unlock;
+
+ b43dbg(wl, "Adding Interface type %d\n", conf->type);
+
+ dev = wl->current_dev;
+ wl->operating = 1;
+ wl->if_id = conf->if_id;
+ wl->if_type = conf->type;
+ memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ err = 0;
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ b43dbg(wl, "Removing Interface type %d\n", conf->type);
+
+ mutex_lock(&wl->mutex);
+
+ B43_WARN_ON(!wl->operating);
+ B43_WARN_ON(wl->if_id != conf->if_id);
+
+ wl->operating = 0;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ mutex_unlock(&wl->mutex);
+}
+
+static int b43_start(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ int did_init = 0;
+ int err;
+
+ mutex_lock(&wl->mutex);
+
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(dev);
+ if (err)
+ goto out_mutex_unlock;
+ did_init = 1;
+ }
+
+ if (b43_status(dev) < B43_STAT_STARTED) {
+ err = b43_wireless_core_start(dev);
+ if (err) {
+ if (did_init)
+ b43_wireless_core_exit(dev);
+ goto out_mutex_unlock;
+ }
+ }
+
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+void b43_stop(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+
+ mutex_lock(&wl->mutex);
+ if (b43_status(dev) >= B43_STAT_STARTED)
+ b43_wireless_core_stop(dev);
+ b43_wireless_core_exit(dev);
+ mutex_unlock(&wl->mutex);
+}
+
+static const struct ieee80211_ops b43_hw_ops = {
+ .tx = b43_tx,
+ .conf_tx = b43_conf_tx,
+ .add_interface = b43_add_interface,
+ .remove_interface = b43_remove_interface,
+ .config = b43_dev_config,
+ .config_interface = b43_config_interface,
+ .configure_filter = b43_configure_filter,
+ .set_key = b43_dev_set_key,
+ .get_stats = b43_get_stats,
+ .get_tx_stats = b43_get_tx_stats,
+ .start = b43_start,
+ .stop = b43_stop,
+};
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use b43_controller_restart()
+ */
+static void b43_chip_reset(struct work_struct *work)
+{
+ struct b43_wldev *dev =
+ container_of(work, struct b43_wldev, restart_work);
+ struct b43_wl *wl = dev->wl;
+ int err = 0;
+ int prev_status;
+
+ mutex_lock(&wl->mutex);
+
+ prev_status = b43_status(dev);
+ /* Bring the device down... */
+ if (prev_status >= B43_STAT_STARTED)
+ b43_wireless_core_stop(dev);
+ if (prev_status >= B43_STAT_INITIALIZED)
+ b43_wireless_core_exit(dev);
+
+ /* ...and up again. */
+ if (prev_status >= B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(dev);
+ if (err)
+ goto out;
+ }
+ if (prev_status >= B43_STAT_STARTED) {
+ err = b43_wireless_core_start(dev);
+ if (err) {
+ b43_wireless_core_exit(dev);
+ goto out;
+ }
+ }
+ out:
+ mutex_unlock(&wl->mutex);
+ if (err)
+ b43err(wl, "Controller restart FAILED\n");
+ else
+ b43info(wl, "Controller restarted\n");
+}
+
+static int b43_setup_modes(struct b43_wldev *dev,
+ int have_aphy, int have_bphy, int have_gphy)
+{
+ struct ieee80211_hw *hw = dev->wl->hw;
+ struct ieee80211_hw_mode *mode;
+ struct b43_phy *phy = &dev->phy;
+ int cnt = 0;
+ int err;
+
+/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
+ have_aphy = 0;
+
+ phy->possible_phymodes = 0;
+ for (; 1; cnt++) {
+ if (have_aphy) {
+ B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211A;
+ mode->num_channels = b43_a_chantable_size;
+ mode->channels = b43_a_chantable;
+ mode->num_rates = b43_a_ratetable_size;
+ mode->rates = b43_a_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43_PHYMODE_A;
+ have_aphy = 0;
+ continue;
+ }
+ if (have_bphy) {
+ B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211B;
+ mode->num_channels = b43_bg_chantable_size;
+ mode->channels = b43_bg_chantable;
+ mode->num_rates = b43_b_ratetable_size;
+ mode->rates = b43_b_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43_PHYMODE_B;
+ have_bphy = 0;
+ continue;
+ }
+ if (have_gphy) {
+ B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211G;
+ mode->num_channels = b43_bg_chantable_size;
+ mode->channels = b43_bg_chantable;
+ mode->num_rates = b43_g_ratetable_size;
+ mode->rates = b43_g_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43_PHYMODE_G;
+ have_gphy = 0;
+ continue;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void b43_wireless_core_detach(struct b43_wldev *dev)
+{
+ b43_rfkill_free(dev);
+ /* We release firmware that late to not be required to re-request
+ * is all the time when we reinit the core. */
+ b43_release_firmware(dev);
+}
+
+static int b43_wireless_core_attach(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct pci_dev *pdev = bus->host_pci;
+ int err;
+ int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+ u32 tmp;
+
+ /* Do NOT do any device initialization here.
+ * Do it in wireless_core_init() instead.
+ * This function is for gathering basic information about the HW, only.
+ * Also some structs may be set up here. But most likely you want to have
+ * that in core_init(), too.
+ */
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err) {
+ b43err(wl, "Bus powerup failed\n");
+ goto out;
+ }
+ /* Get the PHY type. */
+ if (dev->dev->id.revision >= 5) {
+ u32 tmshigh;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
+ have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
+ if (!have_aphy && !have_gphy)
+ have_bphy = 1;
+ } else if (dev->dev->id.revision == 4) {
+ have_gphy = 1;
+ have_aphy = 1;
+ } else
+ have_bphy = 1;
+
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
+ b43_wireless_core_reset(dev, tmp);
+
+ err = b43_phy_versioning(dev);
+ if (err)
+ goto err_powerdown;
+ /* Check if this device supports multiband. */
+ if (!pdev ||
+ (pdev->device != 0x4312 &&
+ pdev->device != 0x4319 && pdev->device != 0x4324)) {
+ /* No multiband support. */
+ have_aphy = 0;
+ have_bphy = 0;
+ have_gphy = 0;
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ have_aphy = 1;
+ break;
+ case B43_PHYTYPE_B:
+ have_bphy = 1;
+ break;
+ case B43_PHYTYPE_G:
+ have_gphy = 1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
+ b43_wireless_core_reset(dev, tmp);
+
+ err = b43_validate_chipaccess(dev);
+ if (err)
+ goto err_powerdown;
+ err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+ if (err)
+ goto err_powerdown;
+
+ /* Now set some default "current_dev" */
+ if (!wl->current_dev)
+ wl->current_dev = dev;
+ INIT_WORK(&dev->restart_work, b43_chip_reset);
+ b43_rfkill_alloc(dev);
+
+ b43_radio_turn_off(dev, 1);
+ b43_switch_analog(dev, 0);
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(bus);
+
+out:
+ return err;
+
+err_powerdown:
+ ssb_bus_may_powerdown(bus);
+ return err;
+}
+
+static void b43_one_core_detach(struct ssb_device *dev)
+{
+ struct b43_wldev *wldev;
+ struct b43_wl *wl;
+
+ wldev = ssb_get_drvdata(dev);
+ wl = wldev->wl;
+ cancel_work_sync(&wldev->restart_work);
+ b43_debugfs_remove_device(wldev);
+ b43_wireless_core_detach(wldev);
+ list_del(&wldev->list);
+ wl->nr_devs--;
+ ssb_set_drvdata(dev, NULL);
+ kfree(wldev);
+}
+
+static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
+{
+ struct b43_wldev *wldev;
+ struct pci_dev *pdev;
+ int err = -ENOMEM;
+
+ if (!list_empty(&wl->devlist)) {
+ /* We are not the first core on this chip. */
+ pdev = dev->bus->host_pci;
+ /* Only special chips support more than one wireless
+ * core, although some of the other chips have more than
+ * one wireless core as well. Check for this and
+ * bail out early.
+ */
+ if (!pdev ||
+ ((pdev->device != 0x4321) &&
+ (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
+ b43dbg(wl, "Ignoring unconnected 802.11 core\n");
+ return -ENODEV;
+ }
+ }
+
+ wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
+ if (!wldev)
+ goto out;
+
+ wldev->dev = dev;
+ wldev->wl = wl;
+ b43_set_status(wldev, B43_STAT_UNINIT);
+ wldev->bad_frames_preempt = modparam_bad_frames_preempt;
+ tasklet_init(&wldev->isr_tasklet,
+ (void (*)(unsigned long))b43_interrupt_tasklet,
+ (unsigned long)wldev);
+ if (modparam_pio)
+ wldev->__using_pio = 1;
+ INIT_LIST_HEAD(&wldev->list);
+
+ err = b43_wireless_core_attach(wldev);
+ if (err)
+ goto err_kfree_wldev;
+
+ list_add(&wldev->list, &wl->devlist);
+ wl->nr_devs++;
+ ssb_set_drvdata(dev, wldev);
+ b43_debugfs_add_device(wldev);
+
+ out:
+ return err;
+
+ err_kfree_wldev:
+ kfree(wldev);
+ return err;
+}
+
+static void b43_sprom_fixup(struct ssb_bus *bus)
+{
+ /* boardflags workarounds */
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
+ bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
+ bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+ bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
+ bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
+
+ /* Handle case when gain is not set in sprom */
+ if (bus->sprom.r1.antenna_gain_a == 0xFF)
+ bus->sprom.r1.antenna_gain_a = 2;
+ if (bus->sprom.r1.antenna_gain_bg == 0xFF)
+ bus->sprom.r1.antenna_gain_bg = 2;
+
+ /* Convert Antennagain values to Q5.2 */
+ bus->sprom.r1.antenna_gain_a <<= 2;
+ bus->sprom.r1.antenna_gain_bg <<= 2;
+}
+
+static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
+{
+ struct ieee80211_hw *hw = wl->hw;
+
+ ssb_set_devtypedata(dev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+static int b43_wireless_init(struct ssb_device *dev)
+{
+ struct ssb_sprom *sprom = &dev->bus->sprom;
+ struct ieee80211_hw *hw;
+ struct b43_wl *wl;
+ int err = -ENOMEM;
+
+ b43_sprom_fixup(dev->bus);
+
+ hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
+ if (!hw) {
+ b43err(NULL, "Could not allocate ieee80211 device\n");
+ goto out;
+ }
+
+ /* fill hw info */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+ hw->max_signal = 100;
+ hw->max_rssi = -110;
+ hw->max_noise = -110;
+ hw->queues = 1; /* FIXME: hardware has more queues */
+ SET_IEEE80211_DEV(hw, dev->dev);
+ if (is_valid_ether_addr(sprom->r1.et1mac))
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+ else
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+
+ /* Get and initialize struct b43_wl */
+ wl = hw_to_b43_wl(hw);
+ memset(wl, 0, sizeof(*wl));
+ wl->hw = hw;
+ spin_lock_init(&wl->irq_lock);
+ spin_lock_init(&wl->leds_lock);
+ mutex_init(&wl->mutex);
+ INIT_LIST_HEAD(&wl->devlist);
+
+ ssb_set_devtypedata(dev, wl);
+ b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+ err = 0;
+ out:
+ return err;
+}
+
+static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
+{
+ struct b43_wl *wl;
+ int err;
+ int first = 0;
+
+ wl = ssb_get_devtypedata(dev);
+ if (!wl) {
+ /* Probing the first core. Must setup common struct b43_wl */
+ first = 1;
+ err = b43_wireless_init(dev);
+ if (err)
+ goto out;
+ wl = ssb_get_devtypedata(dev);
+ B43_WARN_ON(!wl);
+ }
+ err = b43_one_core_attach(dev, wl);
+ if (err)
+ goto err_wireless_exit;
+
+ if (first) {
+ err = ieee80211_register_hw(wl->hw);
+ if (err)
+ goto err_one_core_detach;
+ }
+
+ out:
+ return err;
+
+ err_one_core_detach:
+ b43_one_core_detach(dev);
+ err_wireless_exit:
+ if (first)
+ b43_wireless_exit(dev, wl);
+ return err;
+}
+
+static void b43_remove(struct ssb_device *dev)
+{
+ struct b43_wl *wl = ssb_get_devtypedata(dev);
+ struct b43_wldev *wldev = ssb_get_drvdata(dev);
+
+ B43_WARN_ON(!wl);
+ if (wl->current_dev == wldev)
+ ieee80211_unregister_hw(wl->hw);
+
+ b43_one_core_detach(dev);
+
+ if (list_empty(&wl->devlist)) {
+ /* Last core on the chip unregistered.
+ * We can destroy common struct b43_wl.
+ */
+ b43_wireless_exit(dev, wl);
+ }
+}
+
+/* Perform a hardware reset. This can be called from any context. */
+void b43_controller_restart(struct b43_wldev *dev, const char *reason)
+{
+ /* Must avoid requeueing, if we are in shutdown. */
+ if (b43_status(dev) < B43_STAT_INITIALIZED)
+ return;
+ b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
+ queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int b43_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ struct b43_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43_wl *wl = wldev->wl;
+
+ b43dbg(wl, "Suspending...\n");
+
+ mutex_lock(&wl->mutex);
+ wldev->suspend_init_status = b43_status(wldev);
+ if (wldev->suspend_init_status >= B43_STAT_STARTED)
+ b43_wireless_core_stop(wldev);
+ if (wldev->suspend_init_status >= B43_STAT_INITIALIZED)
+ b43_wireless_core_exit(wldev);
+ mutex_unlock(&wl->mutex);
+
+ b43dbg(wl, "Device suspended.\n");
+
+ return 0;
+}
+
+static int b43_resume(struct ssb_device *dev)
+{
+ struct b43_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43_wl *wl = wldev->wl;
+ int err = 0;
+
+ b43dbg(wl, "Resuming...\n");
+
+ mutex_lock(&wl->mutex);
+ if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(wldev);
+ if (err) {
+ b43err(wl, "Resume failed at core init\n");
+ goto out;
+ }
+ }
+ if (wldev->suspend_init_status >= B43_STAT_STARTED) {
+ err = b43_wireless_core_start(wldev);
+ if (err) {
+ b43_wireless_core_exit(wldev);
+ b43err(wl, "Resume failed at core start\n");
+ goto out;
+ }
+ }
+ mutex_unlock(&wl->mutex);
+
+ b43dbg(wl, "Device resumed.\n");
+ out:
+ return err;
+}
+
+#else /* CONFIG_PM */
+# define b43_suspend NULL
+# define b43_resume NULL
+#endif /* CONFIG_PM */
+
+static struct ssb_driver b43_ssb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = b43_ssb_tbl,
+ .probe = b43_probe,
+ .remove = b43_remove,
+ .suspend = b43_suspend,
+ .resume = b43_resume,
+};
+
+static int __init b43_init(void)
+{
+ int err;
+
+ b43_debugfs_init();
+ err = b43_pcmcia_init();
+ if (err)
+ goto err_dfs_exit;
+ err = ssb_driver_register(&b43_ssb_driver);
+ if (err)
+ goto err_pcmcia_exit;
+
+ return err;
+
+err_pcmcia_exit:
+ b43_pcmcia_exit();
+err_dfs_exit:
+ b43_debugfs_exit();
+ return err;
+}
+
+static void __exit b43_exit(void)
+{
+ ssb_driver_unregister(&b43_ssb_driver);
+ b43_pcmcia_exit();
+ b43_debugfs_exit();
+}
+
+module_init(b43_init)
+module_exit(b43_exit)
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
new file mode 100644
index 000000000000..284d17da17d1
--- /dev/null
+++ b/drivers/net/wireless/b43/main.h
@@ -0,0 +1,125 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mb@bu3sch.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43_MAIN_H_
+#define B43_MAIN_H_
+
+#include "b43.h"
+
+#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline u8 b43_freq_to_channel_a(int freq)
+{
+ return ((freq - 5000) / 5);
+}
+static inline u8 b43_freq_to_channel_bg(int freq)
+{
+ u8 channel;
+
+ if (freq == 2484)
+ channel = 14;
+ else
+ channel = (freq - 2407) / 5;
+
+ return channel;
+}
+static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
+{
+ if (dev->phy.type == B43_PHYTYPE_A)
+ return b43_freq_to_channel_a(freq);
+ return b43_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline int b43_channel_to_freq_a(u8 channel)
+{
+ return (5000 + (5 * channel));
+}
+static inline int b43_channel_to_freq_bg(u8 channel)
+{
+ int freq;
+
+ if (channel == 14)
+ freq = 2484;
+ else
+ freq = 2407 + (5 * channel);
+
+ return freq;
+}
+static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
+{
+ if (dev->phy.type == B43_PHYTYPE_A)
+ return b43_channel_to_freq_a(channel);
+ return b43_channel_to_freq_bg(channel);
+}
+
+static inline int b43_is_cck_rate(int rate)
+{
+ return (rate == B43_CCK_RATE_1MB ||
+ rate == B43_CCK_RATE_2MB ||
+ rate == B43_CCK_RATE_5MB || rate == B43_CCK_RATE_11MB);
+}
+
+static inline int b43_is_ofdm_rate(int rate)
+{
+ return !b43_is_cck_rate(rate);
+}
+
+void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
+void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
+
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
+
+u32 b43_hf_read(struct b43_wldev *dev);
+void b43_hf_write(struct b43_wldev *dev, u32 value);
+
+void b43_dummy_transmission(struct b43_wldev *dev);
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
+
+void b43_mac_suspend(struct b43_wldev *dev);
+void b43_mac_enable(struct b43_wldev *dev);
+
+void b43_controller_restart(struct b43_wldev *dev, const char *reason);
+
+#define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */
+#define B43_PS_DISABLED (1 << 1) /* Force disable hardware power saving */
+#define B43_PS_AWAKE (1 << 2) /* Force device awake */
+#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */
+void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
+
+#endif /* B43_MAIN_H_ */
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
new file mode 100644
index 000000000000..b242a9a90dd2
--- /dev/null
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -0,0 +1,160 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "pcmcia.h"
+
+#include <linux/ssb/ssb.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+
+static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
+
+#ifdef CONFIG_PM
+static int b43_pcmcia_suspend(struct pcmcia_device *dev)
+{
+ //TODO
+ return 0;
+}
+
+static int b43_pcmcia_resume(struct pcmcia_device *dev)
+{
+ //TODO
+ return 0;
+}
+#else /* CONFIG_PM */
+# define b43_pcmcia_suspend NULL
+# define b43_pcmcia_resume NULL
+#endif /* CONFIG_PM */
+
+static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb;
+ win_req_t win;
+ memreq_t mem;
+ tuple_t tuple;
+ cisparse_t parse;
+ int err = -ENOMEM;
+ int res;
+ unsigned char buf[64];
+
+ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ if (!ssb)
+ goto out;
+
+ err = -ENODEV;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ res = pcmcia_get_first_tuple(dev, &tuple);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+ res = pcmcia_get_tuple_data(dev, &tuple);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+ res = pcmcia_parse_tuple(dev, &tuple, &parse);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+
+ dev->conf.ConfigBase = parse.config.base;
+ dev->conf.Present = parse.config.rmask[0];
+
+ dev->io.BasePort2 = 0;
+ dev->io.NumPorts2 = 0;
+ dev->io.Attributes2 = 0;
+
+ win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+ win.Base = 0;
+ win.Size = SSB_CORE_SIZE;
+ win.AccessSpeed = 1000;
+ res = pcmcia_request_window(&dev, &win, &dev->win);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+
+ mem.CardOffset = 0;
+ mem.Page = 0;
+ res = pcmcia_map_mem_page(dev->win, &mem);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+
+ res = pcmcia_request_configuration(dev, &dev->conf);
+ if (res != CS_SUCCESS)
+ goto err_disable;
+
+ err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
+ dev->priv = ssb;
+
+ out:
+ return err;
+ err_disable:
+ pcmcia_disable_device(dev);
+ err_kfree_ssb:
+ kfree(ssb);
+ return err;
+}
+
+static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ ssb_bus_unregister(ssb);
+ pcmcia_release_window(dev->win);
+ pcmcia_disable_device(dev);
+ kfree(ssb);
+ dev->priv = NULL;
+}
+
+static struct pcmcia_driver b43_pcmcia_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "b43-pcmcia",
+ },
+ .id_table = b43_pcmcia_tbl,
+ .probe = b43_pcmcia_probe,
+ .remove = b43_pcmcia_remove,
+ .suspend = b43_pcmcia_suspend,
+ .resume = b43_pcmcia_resume,
+};
+
+int b43_pcmcia_init(void)
+{
+ return pcmcia_register_driver(&b43_pcmcia_driver);
+}
+
+void b43_pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&b43_pcmcia_driver);
+}
diff --git a/drivers/net/wireless/b43/pcmcia.h b/drivers/net/wireless/b43/pcmcia.h
new file mode 100644
index 000000000000..85f120a67cbe
--- /dev/null
+++ b/drivers/net/wireless/b43/pcmcia.h
@@ -0,0 +1,20 @@
+#ifndef B43_PCMCIA_H_
+#define B43_PCMCIA_H_
+
+#ifdef CONFIG_B43_PCMCIA
+
+int b43_pcmcia_init(void);
+void b43_pcmcia_exit(void);
+
+#else /* CONFIG_B43_PCMCIA */
+
+static inline int b43_pcmcia_init(void)
+{
+ return 0;
+}
+static inline void b43_pcmcia_exit(void)
+{
+}
+
+#endif /* CONFIG_B43_PCMCIA */
+#endif /* B43_PCMCIA_H_ */
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
new file mode 100644
index 000000000000..5f7ffa0a76c0
--- /dev/null
+++ b/drivers/net/wireless/b43/phy.c
@@ -0,0 +1,4380 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "phy.h"
+#include "main.h"
+#include "tables.h"
+#include "lo.h"
+
+static const s8 b43_tssi2dbm_b_table[] = {
+ 0x4D, 0x4C, 0x4B, 0x4A,
+ 0x4A, 0x49, 0x48, 0x47,
+ 0x47, 0x46, 0x45, 0x45,
+ 0x44, 0x43, 0x42, 0x42,
+ 0x41, 0x40, 0x3F, 0x3E,
+ 0x3D, 0x3C, 0x3B, 0x3A,
+ 0x39, 0x38, 0x37, 0x36,
+ 0x35, 0x34, 0x32, 0x31,
+ 0x30, 0x2F, 0x2D, 0x2C,
+ 0x2B, 0x29, 0x28, 0x26,
+ 0x25, 0x23, 0x21, 0x1F,
+ 0x1D, 0x1A, 0x17, 0x14,
+ 0x10, 0x0C, 0x06, 0x00,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+};
+
+static const s8 b43_tssi2dbm_g_table[] = {
+ 77, 77, 77, 76,
+ 76, 76, 75, 75,
+ 74, 74, 73, 73,
+ 73, 72, 72, 71,
+ 71, 70, 70, 69,
+ 68, 68, 67, 67,
+ 66, 65, 65, 64,
+ 63, 63, 62, 61,
+ 60, 59, 58, 57,
+ 56, 55, 54, 53,
+ 52, 50, 49, 47,
+ 45, 43, 40, 37,
+ 33, 28, 22, 14,
+ 5, -7, -20, -20,
+ -20, -20, -20, -20,
+ -20, -20, -20, -20,
+};
+
+const u8 b43_radio_channel_codes_bg[] = {
+ 12, 17, 22, 27,
+ 32, 37, 42, 47,
+ 52, 57, 62, 67,
+ 72, 84,
+};
+
+static void b43_phy_initg(struct b43_wldev *dev);
+
+/* Reverse the bits of a 4bit value.
+ * Example: 1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+ u16 flipped = 0x0000;
+
+ B43_WARN_ON(value & ~0x000F);
+
+ flipped |= (value & 0x0001) << 3;
+ flipped |= (value & 0x0002) << 1;
+ flipped |= (value & 0x0004) >> 1;
+ flipped |= (value & 0x0008) >> 3;
+
+ return flipped;
+}
+
+static void generate_rfatt_list(struct b43_wldev *dev,
+ struct b43_rfatt_list *list)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ /* APHY.rev < 5 || GPHY.rev < 6 */
+ static const struct b43_rfatt rfatt_0[] = {
+ {.att = 3,.with_padmix = 0,},
+ {.att = 1,.with_padmix = 0,},
+ {.att = 5,.with_padmix = 0,},
+ {.att = 7,.with_padmix = 0,},
+ {.att = 9,.with_padmix = 0,},
+ {.att = 2,.with_padmix = 0,},
+ {.att = 0,.with_padmix = 0,},
+ {.att = 4,.with_padmix = 0,},
+ {.att = 6,.with_padmix = 0,},
+ {.att = 8,.with_padmix = 0,},
+ {.att = 1,.with_padmix = 1,},
+ {.att = 2,.with_padmix = 1,},
+ {.att = 3,.with_padmix = 1,},
+ {.att = 4,.with_padmix = 1,},
+ };
+ /* Radio.rev == 8 && Radio.version == 0x2050 */
+ static const struct b43_rfatt rfatt_1[] = {
+ {.att = 2,.with_padmix = 1,},
+ {.att = 4,.with_padmix = 1,},
+ {.att = 6,.with_padmix = 1,},
+ {.att = 8,.with_padmix = 1,},
+ {.att = 10,.with_padmix = 1,},
+ {.att = 12,.with_padmix = 1,},
+ {.att = 14,.with_padmix = 1,},
+ };
+ /* Otherwise */
+ static const struct b43_rfatt rfatt_2[] = {
+ {.att = 0,.with_padmix = 1,},
+ {.att = 2,.with_padmix = 1,},
+ {.att = 4,.with_padmix = 1,},
+ {.att = 6,.with_padmix = 1,},
+ {.att = 8,.with_padmix = 1,},
+ {.att = 9,.with_padmix = 1,},
+ {.att = 9,.with_padmix = 1,},
+ };
+
+ if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
+ (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
+ /* Software pctl */
+ list->list = rfatt_0;
+ list->len = ARRAY_SIZE(rfatt_0);
+ list->min_val = 0;
+ list->max_val = 9;
+ return;
+ }
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ /* Hardware pctl */
+ list->list = rfatt_1;
+ list->len = ARRAY_SIZE(rfatt_1);
+ list->min_val = 2;
+ list->max_val = 14;
+ return;
+ }
+ /* Hardware pctl */
+ list->list = rfatt_2;
+ list->len = ARRAY_SIZE(rfatt_2);
+ list->min_val = 0;
+ list->max_val = 9;
+}
+
+static void generate_bbatt_list(struct b43_wldev *dev,
+ struct b43_bbatt_list *list)
+{
+ static const struct b43_bbatt bbatt_0[] = {
+ {.att = 0,},
+ {.att = 1,},
+ {.att = 2,},
+ {.att = 3,},
+ {.att = 4,},
+ {.att = 5,},
+ {.att = 6,},
+ {.att = 7,},
+ {.att = 8,},
+ };
+
+ list->list = bbatt_0;
+ list->len = ARRAY_SIZE(bbatt_0);
+ list->min_val = 0;
+ list->max_val = 8;
+}
+
+bool b43_has_hardware_pctl(struct b43_phy *phy)
+{
+ if (!phy->hardware_power_control)
+ return 0;
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ if (phy->rev >= 5)
+ return 1;
+ break;
+ case B43_PHYTYPE_G:
+ if (phy->rev >= 6)
+ return 1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ return 0;
+}
+
+static void b43_shm_clear_tssi(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
+ break;
+ }
+}
+
+void b43_raw_phy_lock(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ B43_WARN_ON(!irqs_disabled());
+
+ /* We had a check for MACCTL==0 here, but I think that doesn't
+ * make sense, as MACCTL is never 0 when this is called.
+ * --mb */
+ B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+
+ if (dev->dev->id.revision < 3) {
+ b43_mac_suspend(dev);
+ spin_lock(&phy->lock);
+ } else {
+ if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+ }
+ phy->locked = 1;
+}
+
+void b43_raw_phy_unlock(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ B43_WARN_ON(!irqs_disabled());
+ if (dev->dev->id.revision < 3) {
+ if (phy->locked) {
+ spin_unlock(&phy->lock);
+ b43_mac_enable(dev);
+ }
+ } else {
+ if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43_power_saving_ctl_bits(dev, 0);
+ }
+ phy->locked = 0;
+}
+
+/* Different PHYs require different register routing flags.
+ * This adjusts (and does sanity checks on) the routing flags.
+ */
+static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
+ u16 offset, struct b43_wldev *dev)
+{
+ if (phy->type == B43_PHYTYPE_A) {
+ /* OFDM registers are base-registers for the A-PHY. */
+ offset &= ~B43_PHYROUTE_OFDM_GPHY;
+ }
+ if (offset & B43_PHYROUTE_EXT_GPHY) {
+ /* Ext-G registers are only available on G-PHYs */
+ if (phy->type != B43_PHYTYPE_G) {
+ b43dbg(dev->wl, "EXT-G PHY access at "
+ "0x%04X on %u type PHY\n", offset, phy->type);
+ }
+ }
+
+ return offset;
+}
+
+u16 b43_phy_read(struct b43_wldev * dev, u16 offset)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ offset = adjust_phyreg_for_phytype(phy, offset, dev);
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ offset = adjust_phyreg_for_phytype(phy, offset, dev);
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_PHY_DATA, val);
+}
+
+static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);
+
+/* Adjust the transmission power output (G-PHY) */
+void b43_set_txpower_g(struct b43_wldev *dev,
+ const struct b43_bbatt *bbatt,
+ const struct b43_rfatt *rfatt, u8 tx_control)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 bb, rf;
+ u16 tx_bias, tx_magn;
+
+ bb = bbatt->att;
+ rf = rfatt->att;
+ tx_bias = lo->tx_bias;
+ tx_magn = lo->tx_magn;
+ if (unlikely(tx_bias == 0xFF))
+ tx_bias = 0;
+
+ /* Save the values for later */
+ phy->tx_control = tx_control;
+ memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+ memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
+
+ if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+ b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
+ "rfatt(%u), tx_control(0x%02X), "
+ "tx_bias(0x%02X), tx_magn(0x%02X)\n",
+ bb, rf, tx_control, tx_bias, tx_magn);
+ }
+
+ b43_phy_set_baseband_attenuation(dev, bb);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x43,
+ (rf & 0x000F) | (tx_control & 0x0070));
+ } else {
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | (rf & 0x000F));
+ b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+ & ~0x0070) | (tx_control &
+ 0x0070));
+ }
+ if (has_tx_magnification(phy)) {
+ b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
+ } else {
+ b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+ & 0xFFF0) | (tx_bias & 0x000F));
+ }
+ if (phy->type == B43_PHYTYPE_G)
+ b43_lo_g_adjust(dev);
+}
+
+static void default_baseband_attenuation(struct b43_wldev *dev,
+ struct b43_bbatt *bb)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+ bb->att = 0;
+ else
+ bb->att = 2;
+}
+
+static void default_radio_attenuation(struct b43_wldev *dev,
+ struct b43_rfatt *rf)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+
+ rf->with_padmix = 0;
+
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BCM4309G) {
+ if (bus->boardinfo.rev < 0x43) {
+ rf->att = 2;
+ return;
+ } else if (bus->boardinfo.rev < 0x51) {
+ rf->att = 3;
+ return;
+ }
+ }
+
+ if (phy->type == B43_PHYTYPE_A) {
+ rf->att = 0x60;
+ return;
+ }
+
+ switch (phy->radio_ver) {
+ case 0x2053:
+ switch (phy->radio_rev) {
+ case 1:
+ rf->att = 6;
+ return;
+ }
+ break;
+ case 0x2050:
+ switch (phy->radio_rev) {
+ case 0:
+ rf->att = 5;
+ return;
+ case 1:
+ if (phy->type == B43_PHYTYPE_G) {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type == SSB_BOARD_BCM4309G
+ && bus->boardinfo.rev >= 30)
+ rf->att = 3;
+ else if (bus->boardinfo.vendor ==
+ SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type ==
+ SSB_BOARD_BU4306)
+ rf->att = 3;
+ else
+ rf->att = 1;
+ } else {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type == SSB_BOARD_BCM4309G
+ && bus->boardinfo.rev >= 30)
+ rf->att = 7;
+ else
+ rf->att = 6;
+ }
+ return;
+ case 2:
+ if (phy->type == B43_PHYTYPE_G) {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type == SSB_BOARD_BCM4309G
+ && bus->boardinfo.rev >= 30)
+ rf->att = 3;
+ else if (bus->boardinfo.vendor ==
+ SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type ==
+ SSB_BOARD_BU4306)
+ rf->att = 5;
+ else if (bus->chip_id == 0x4320)
+ rf->att = 4;
+ else
+ rf->att = 3;
+ } else
+ rf->att = 6;
+ return;
+ case 3:
+ rf->att = 5;
+ return;
+ case 4:
+ case 5:
+ rf->att = 1;
+ return;
+ case 6:
+ case 7:
+ rf->att = 5;
+ return;
+ case 8:
+ rf->att = 0xA;
+ rf->with_padmix = 1;
+ return;
+ case 9:
+ default:
+ rf->att = 5;
+ return;
+ }
+ }
+ rf->att = 5;
+}
+
+static u16 default_tx_control(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->radio_ver != 0x2050)
+ return 0;
+ if (phy->radio_rev == 1)
+ return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
+ if (phy->radio_rev < 6)
+ return B43_TXCTL_PA2DB;
+ if (phy->radio_rev == 8)
+ return B43_TXCTL_TXMIX;
+ return 0;
+}
+
+/* This func is called "PHY calibrate" in the specs... */
+void b43_phy_early_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ default_baseband_attenuation(dev, &phy->bbatt);
+ default_radio_attenuation(dev, &phy->rfatt);
+ phy->tx_control = (default_tx_control(dev) << 4);
+
+ /* Commit previous writes */
+ b43_read32(dev, B43_MMIO_MACCTL);
+
+ if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) {
+ generate_rfatt_list(dev, &lo->rfatt_list);
+ generate_bbatt_list(dev, &lo->bbatt_list);
+ }
+ if (phy->type == B43_PHYTYPE_G && phy->rev == 1) {
+ /* Workaround: Temporarly disable gmode through the early init
+ * phase, as the gmode stuff is not needed for phy rev 1 */
+ phy->gmode = 0;
+ b43_wireless_core_reset(dev, 0);
+ b43_phy_initg(dev);
+ phy->gmode = 1;
+ b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
+ }
+}
+
+/* GPHY_TSSI_Power_Lookup_Table_Init */
+static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int i;
+ u16 value;
+
+ for (i = 0; i < 32; i++)
+ b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]);
+ for (i = 32; i < 64; i++)
+ b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]);
+ for (i = 0; i < 64; i += 2) {
+ value = (u16) phy->tssi2dbm[i];
+ value |= ((u16) phy->tssi2dbm[i + 1]) << 8;
+ b43_phy_write(dev, 0x380 + (i / 2), value);
+ }
+}
+
+/* GPHY_Gain_Lookup_Table_Init */
+static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 nr_written = 0;
+ u16 tmp;
+ u8 rf, bb;
+
+ if (!lo->lo_measured) {
+ b43_phy_write(dev, 0x3FF, 0);
+ return;
+ }
+
+ for (rf = 0; rf < lo->rfatt_list.len; rf++) {
+ for (bb = 0; bb < lo->bbatt_list.len; bb++) {
+ if (nr_written >= 0x40)
+ return;
+ tmp = lo->bbatt_list.list[bb].att;
+ tmp <<= 8;
+ if (phy->radio_rev == 8)
+ tmp |= 0x50;
+ else
+ tmp |= 0x40;
+ tmp |= lo->rfatt_list.list[rf].att;
+ b43_phy_write(dev, 0x3C0 + nr_written, tmp);
+ nr_written++;
+ }
+ }
+}
+
+/* GPHY_DC_Lookup_Table */
+void b43_gphy_dc_lt_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_loctl *loctl0;
+ struct b43_loctl *loctl1;
+ int i;
+ int rf_offset, bb_offset;
+ u16 tmp;
+
+ for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
+ rf_offset = i / lo->rfatt_list.len;
+ bb_offset = i % lo->rfatt_list.len;
+
+ loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
+ &lo->bbatt_list.list[bb_offset]);
+ if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
+ rf_offset = (i + 1) / lo->rfatt_list.len;
+ bb_offset = (i + 1) % lo->rfatt_list.len;
+
+ loctl1 =
+ b43_get_lo_g_ctl(dev,
+ &lo->rfatt_list.list[rf_offset],
+ &lo->bbatt_list.list[bb_offset]);
+ } else
+ loctl1 = loctl0;
+
+ tmp = ((u16) loctl0->q & 0xF);
+ tmp |= ((u16) loctl0->i & 0xF) << 4;
+ tmp |= ((u16) loctl1->q & 0xF) << 8;
+ tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME?
+ b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
+ }
+}
+
+static void hardware_pctl_init_aphy(struct b43_wldev *dev)
+{
+ //TODO
+}
+
+static void hardware_pctl_init_gphy(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
+ | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
+ b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
+ | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
+ b43_gphy_tssi_power_lt_init(dev);
+ b43_gphy_gain_lt_init(dev);
+ b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
+ b43_phy_write(dev, 0x0014, 0x0000);
+
+ B43_WARN_ON(phy->rev < 6);
+ b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+ | 0x0800);
+ b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+ & 0xFEFF);
+ b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
+ & 0xFFBF);
+
+ b43_gphy_dc_lt_init(dev);
+}
+
+/* HardwarePowerControl init for A and G PHY */
+static void b43_hardware_pctl_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!b43_has_hardware_pctl(phy)) {
+ /* No hardware power control */
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
+ return;
+ }
+ /* Init the hwpctl related hardware */
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ hardware_pctl_init_aphy(dev);
+ break;
+ case B43_PHYTYPE_G:
+ hardware_pctl_init_gphy(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ /* Enable hardware pctl in firmware. */
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
+}
+
+static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!b43_has_hardware_pctl(phy)) {
+ b43_phy_write(dev, 0x047A, 0xC111);
+ return;
+ }
+
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
+ b43_phy_write(dev, 0x002F, 0x0202);
+ b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
+ b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+ & 0xFF0F) | 0x0010);
+ b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+ | 0x8000);
+ b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+ & 0xFFC0) | 0x0010);
+ b43_phy_write(dev, 0x002E, 0xC07F);
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+ | 0x0400);
+ } else {
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+ | 0x0200);
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+ | 0x0400);
+ b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+ & 0x7FFF);
+ b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
+ & 0xFFFE);
+ b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+ & 0xFFC0) | 0x0010);
+ b43_phy_write(dev, 0x002E, 0xC07F);
+ b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+ & 0xFF0F) | 0x0010);
+ }
+}
+
+/* Intialize B/G PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void b43_phy_init_pctl(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ struct b43_rfatt old_rfatt;
+ struct b43_bbatt old_bbatt;
+ u8 old_tx_control = 0;
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306))
+ return;
+
+ b43_phy_write(dev, 0x0028, 0x8018);
+
+ /* This does something with the Analog... */
+ b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
+ & 0xFFDF);
+
+ if (phy->type == B43_PHYTYPE_G && !phy->gmode)
+ return;
+ b43_hardware_pctl_early_init(dev);
+ if (phy->cur_idle_tssi == 0) {
+ if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+ b43_radio_write16(dev, 0x0076,
+ (b43_radio_read16(dev, 0x0076)
+ & 0x00F7) | 0x0084);
+ } else {
+ struct b43_rfatt rfatt;
+ struct b43_bbatt bbatt;
+
+ memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt));
+ memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt));
+ old_tx_control = phy->tx_control;
+
+ bbatt.att = 11;
+ if (phy->radio_rev == 8) {
+ rfatt.att = 15;
+ rfatt.with_padmix = 1;
+ } else {
+ rfatt.att = 9;
+ rfatt.with_padmix = 0;
+ }
+ b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
+ }
+ b43_dummy_transmission(dev);
+ phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
+ if (B43_DEBUG) {
+ /* Current-Idle-TSSI sanity check. */
+ if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) {
+ b43dbg(dev->wl,
+ "!WARNING! Idle-TSSI phy->cur_idle_tssi "
+ "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
+ "adjustment.\n", phy->cur_idle_tssi,
+ phy->tgt_idle_tssi);
+ phy->cur_idle_tssi = 0;
+ }
+ }
+ if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+ b43_radio_write16(dev, 0x0076,
+ b43_radio_read16(dev, 0x0076)
+ & 0xFF7B);
+ } else {
+ b43_set_txpower_g(dev, &old_bbatt,
+ &old_rfatt, old_tx_control);
+ }
+ }
+ b43_hardware_pctl_init(dev);
+ b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_agcsetup(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset = 0x0000;
+
+ if (phy->rev == 1)
+ offset = 0x4C00;
+
+ b43_ofdmtab_write16(dev, offset, 0, 0x00FE);
+ b43_ofdmtab_write16(dev, offset, 1, 0x000D);
+ b43_ofdmtab_write16(dev, offset, 2, 0x0013);
+ b43_ofdmtab_write16(dev, offset, 3, 0x0019);
+
+ if (phy->rev == 1) {
+ b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710);
+ b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83);
+ b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83);
+ b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D);
+ b43_phy_write(dev, 0x0455, 0x0004);
+ }
+
+ b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5)
+ & 0x00FF) | 0x5700);
+ b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
+ & 0xFF80) | 0x000F);
+ b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
+ & 0xC07F) | 0x2B80);
+ b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0300);
+
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+ | 0x0008);
+
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xFFF0) | 0x0008);
+ b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+ & 0xF0FF) | 0x0600);
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0700);
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0100);
+
+ if (phy->rev == 1) {
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x0007);
+ }
+
+ b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
+ & 0xFF00) | 0x001C);
+ b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
+ & 0xC0FF) | 0x0200);
+ b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
+ & 0xFF00) | 0x001C);
+ b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
+ & 0xFF00) | 0x0020);
+ b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
+ & 0xC0FF) | 0x0200);
+ b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482)
+ & 0xFF00) | 0x002E);
+ b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
+ & 0x00FF) | 0x1A00);
+ b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
+ & 0xFF00) | 0x0028);
+ b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
+ & 0x00FF) | 0x2C00);
+
+ if (phy->rev == 1) {
+ b43_phy_write(dev, 0x0430, 0x092B);
+ b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B)
+ & 0xFFE1) | 0x0002);
+ } else {
+ b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B)
+ & 0xFFE1);
+ b43_phy_write(dev, 0x041F, 0x287A);
+ b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
+ & 0xFFF0) | 0x0004);
+ }
+
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x0422, 0x287A);
+ b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
+ & 0x0FFF) | 0x3000);
+ }
+
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0x8080) | 0x7874);
+ b43_phy_write(dev, 0x048E, 0x1C00);
+
+ offset = 0x0800;
+ if (phy->rev == 1) {
+ offset = 0x5400;
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0600);
+ b43_phy_write(dev, 0x048B, 0x005E);
+ b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+ & 0xFF00) | 0x001E);
+ b43_phy_write(dev, 0x048D, 0x0002);
+ }
+ b43_ofdmtab_write16(dev, offset, 0, 0x00);
+ b43_ofdmtab_write16(dev, offset, 1, 0x07);
+ b43_ofdmtab_write16(dev, offset, 2, 0x10);
+ b43_ofdmtab_write16(dev, offset, 3, 0x1C);
+
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
+ & 0xFFFC);
+ b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
+ & 0xEFFF);
+ }
+}
+
+static void b43_phy_setupg(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ u16 i;
+
+ B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+ if (phy->rev == 1) {
+ b43_phy_write(dev, 0x0406, 0x4F19);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) |
+ 0x0340);
+ b43_phy_write(dev, 0x042C, 0x005A);
+ b43_phy_write(dev, 0x0427, 0x001A);
+
+ for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5800, i,
+ b43_tab_finefreqg[i]);
+ for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]);
+ for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]);
+ } else {
+ /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
+ b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654);
+
+ if (phy->rev == 2) {
+ b43_phy_write(dev, 0x04C0, 0x1861);
+ b43_phy_write(dev, 0x04C1, 0x0271);
+ } else if (phy->rev > 2) {
+ b43_phy_write(dev, 0x04C0, 0x0098);
+ b43_phy_write(dev, 0x04C1, 0x0070);
+ b43_phy_write(dev, 0x04C9, 0x0080);
+ }
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800);
+
+ for (i = 0; i < 64; i++)
+ b43_ofdmtab_write16(dev, 0x4000, i, i);
+ for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]);
+ }
+
+ if (phy->rev <= 2)
+ for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1400, i,
+ b43_tab_noisescaleg1[i]);
+ else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200))
+ for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1400, i,
+ b43_tab_noisescaleg3[i]);
+ else
+ for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1400, i,
+ b43_tab_noisescaleg2[i]);
+
+ if (phy->rev == 2)
+ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5000, i,
+ b43_tab_sigmasqr1[i]);
+ else if ((phy->rev > 2) && (phy->rev <= 8))
+ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5000, i,
+ b43_tab_sigmasqr2[i]);
+
+ if (phy->rev == 1) {
+ for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+ b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
+ for (i = 4; i < 20; i++)
+ b43_ofdmtab_write16(dev, 0x5400, i, 0x0020);
+ b43_phy_agcsetup(dev);
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+ (bus->boardinfo.rev == 0x17))
+ return;
+
+ b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
+ b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
+ } else {
+ for (i = 0; i < 0x20; i++)
+ b43_ofdmtab_write16(dev, 0x1000, i, 0x0820);
+ b43_phy_agcsetup(dev);
+ b43_phy_read(dev, 0x0400); /* dummy read */
+ b43_phy_write(dev, 0x0403, 0x1000);
+ b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+ (bus->boardinfo.rev == 0x17))
+ return;
+
+ b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
+ b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001);
+ }
+}
+
+/* Initialize the noisescaletable for APHY */
+static void b43_phy_init_noisescaletbl(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+ }
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x6700);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x2300);
+ for (i = 0; i < 11; i++) {
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+ }
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x0067);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x0023);
+}
+
+static void b43_phy_setupa(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 i;
+
+ B43_WARN_ON(phy->type != B43_PHYTYPE_A);
+ switch (phy->rev) {
+ case 2:
+ b43_phy_write(dev, 0x008E, 0x3800);
+ b43_phy_write(dev, 0x0035, 0x03FF);
+ b43_phy_write(dev, 0x0036, 0x0400);
+
+ b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
+
+ b43_phy_write(dev, 0x001C, 0x0FF9);
+ b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
+ b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF);
+ b43_radio_write16(dev, 0x0002, 0x07BF);
+
+ b43_phy_write(dev, 0x0024, 0x4680);
+ b43_phy_write(dev, 0x0020, 0x0003);
+ b43_phy_write(dev, 0x001D, 0x0F40);
+ b43_phy_write(dev, 0x001F, 0x1C00);
+
+ b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
+ & 0x00FF) | 0x0400);
+ b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B)
+ & 0xFBFF);
+ b43_phy_write(dev, 0x008E, 0x58C1);
+
+ b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
+ b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
+
+ b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019);
+
+ b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+
+ for (i = 0; i < 16; i++)
+ b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F);
+
+ b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044);
+ b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201);
+ b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040);
+ b43_ofdmtab_write16(dev, 0x3001, 0,
+ (b43_ofdmtab_read16(dev, 0x3001, 0) &
+ 0x0010) | 0x0008);
+
+ for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5800, i,
+ b43_tab_finefreqa[i]);
+ for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]);
+ for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+ b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]);
+ b43_phy_init_noisescaletbl(dev);
+ for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+ b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
+ break;
+ case 3:
+ for (i = 0; i < 64; i++)
+ b43_ofdmtab_write16(dev, 0x4000, i, i);
+
+ b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
+
+ b43_phy_write(dev, 0x001C, 0x0FF9);
+ b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
+ b43_radio_write16(dev, 0x0002, 0x07BF);
+
+ b43_phy_write(dev, 0x0024, 0x4680);
+ b43_phy_write(dev, 0x0020, 0x0003);
+ b43_phy_write(dev, 0x001D, 0x0F40);
+ b43_phy_write(dev, 0x001F, 0x1C00);
+ b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
+ & 0x00FF) | 0x0400);
+
+ b43_ofdmtab_write16(dev, 0x3000, 1,
+ (b43_ofdmtab_read16(dev, 0x3000, 1)
+ & 0x0010) | 0x0008);
+ for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) {
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]);
+ }
+ b43_phy_init_noisescaletbl(dev);
+ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
+ b43_ofdmtab_write16(dev, 0x5000, i,
+ b43_tab_sigmasqr1[i]);
+ }
+
+ b43_phy_write(dev, 0x0003, 0x1808);
+
+ b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
+ b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
+
+ b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019);
+
+ b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+
+ b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+/* Initialize APHY. This is also called for the GPHY in some cases. */
+static void b43_phy_inita(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ u16 tval;
+
+ might_sleep();
+
+ if (phy->type == B43_PHYTYPE_A) {
+ b43_phy_setupa(dev);
+ } else {
+ b43_phy_setupg(dev);
+ if (phy->gmode &&
+ (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL))
+ b43_phy_write(dev, 0x046E, 0x03CF);
+ return;
+ }
+
+ b43_phy_write(dev, B43_PHY_A_CRS,
+ (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340);
+ b43_phy_write(dev, 0x0034, 0x0001);
+
+ //TODO: RSSI AGC
+ b43_phy_write(dev, B43_PHY_A_CRS,
+ b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14));
+ b43_radio_init2060(dev);
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+ (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+ if (phy->lofcal == 0xFFFF) {
+ //TODO: LOF Cal
+ b43_radio_set_tx_iq(dev);
+ } else
+ b43_radio_write16(dev, 0x001E, phy->lofcal);
+ }
+
+ b43_phy_write(dev, 0x007A, 0xF111);
+
+ if (phy->cur_idle_tssi == 0) {
+ b43_radio_write16(dev, 0x0019, 0x0000);
+ b43_radio_write16(dev, 0x0017, 0x0020);
+
+ tval = b43_ofdmtab_read16(dev, 0x3001, 0);
+ if (phy->rev == 1) {
+ b43_ofdmtab_write16(dev, 0x3001, 0,
+ (b43_ofdmtab_read16(dev, 0x3001, 0)
+ & 0xFF87)
+ | 0x0058);
+ } else {
+ b43_ofdmtab_write16(dev, 0x3001, 0,
+ (b43_ofdmtab_read16(dev, 0x3001, 0)
+ & 0xFFC3)
+ | 0x002C);
+ }
+ b43_dummy_transmission(dev);
+ phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL);
+ b43_ofdmtab_write16(dev, 0x3001, 0, tval);
+
+ b43_radio_set_txpower_a(dev, 0x0018);
+ }
+ b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_initb2(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, val;
+
+ b43_write16(dev, 0x03EC, 0x3F22);
+ b43_phy_write(dev, 0x0020, 0x301C);
+ b43_phy_write(dev, 0x0026, 0x0000);
+ b43_phy_write(dev, 0x0030, 0x00C6);
+ b43_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43_phy_write(dev, 0x03E4, 0x3000);
+ b43_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43_radio_write16(dev, 0x0075, 0x0080);
+ b43_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x005A, 0x0070);
+ b43_radio_write16(dev, 0x005B, 0x007B);
+ b43_radio_write16(dev, 0x005C, 0x00B0);
+ b43_radio_write16(dev, 0x007A, 0x000F);
+ b43_phy_write(dev, 0x0038, 0x0677);
+ b43_radio_init2050(dev);
+ }
+ b43_phy_write(dev, 0x0014, 0x0080);
+ b43_phy_write(dev, 0x0032, 0x00CA);
+ b43_phy_write(dev, 0x0032, 0x00CC);
+ b43_phy_write(dev, 0x0035, 0x07C2);
+ b43_lo_b_measure(dev);
+ b43_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver != 0x2050)
+ b43_phy_write(dev, 0x0026, 0xCE00);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
+ b43_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver != 0x2050)
+ b43_phy_write(dev, 0x002A, 0x88C2);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+ b43_phy_init_pctl(dev);
+}
+
+static void b43_phy_initb4(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, val;
+
+ b43_write16(dev, 0x03EC, 0x3F22);
+ b43_phy_write(dev, 0x0020, 0x301C);
+ b43_phy_write(dev, 0x0026, 0x0000);
+ b43_phy_write(dev, 0x0030, 0x00C6);
+ b43_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43_phy_write(dev, 0x03E4, 0x3000);
+ b43_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43_radio_write16(dev, 0x0075, 0x0080);
+ b43_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x005A, 0x0070);
+ b43_radio_write16(dev, 0x005B, 0x007B);
+ b43_radio_write16(dev, 0x005C, 0x00B0);
+ b43_radio_write16(dev, 0x007A, 0x000F);
+ b43_phy_write(dev, 0x0038, 0x0677);
+ b43_radio_init2050(dev);
+ }
+ b43_phy_write(dev, 0x0014, 0x0080);
+ b43_phy_write(dev, 0x0032, 0x00CA);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x0032, 0x00E0);
+ b43_phy_write(dev, 0x0035, 0x07C2);
+
+ b43_lo_b_measure(dev);
+
+ b43_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x0026, 0xCE00);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
+ b43_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x002A, 0x88C2);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+ b43_calc_nrssi_slope(dev);
+ b43_calc_nrssi_threshold(dev);
+ }
+ b43_phy_init_pctl(dev);
+}
+
+static void b43_phy_initb5(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, value;
+ u8 old_channel;
+
+ if (phy->analog == 1) {
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+ | 0x0050);
+ }
+ if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type != SSB_BOARD_BU4306)) {
+ value = 0x2120;
+ for (offset = 0x00A8; offset < 0x00C7; offset++) {
+ b43_phy_write(dev, offset, value);
+ value += 0x202;
+ }
+ }
+ b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
+ | 0x0700);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x0038, 0x0667);
+
+ if (phy->gmode || phy->rev >= 2) {
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A)
+ | 0x0020);
+ b43_radio_write16(dev, 0x0051,
+ b43_radio_read16(dev, 0x0051)
+ | 0x0004);
+ }
+ b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
+
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+
+ b43_phy_write(dev, 0x001C, 0x186A);
+
+ b43_phy_write(dev, 0x0013,
+ (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
+ b43_phy_write(dev, 0x0035,
+ (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
+ b43_phy_write(dev, 0x005D,
+ (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
+ }
+
+ if (dev->bad_frames_preempt) {
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev,
+ B43_PHY_RADIO_BITFIELD) | (1 << 11));
+ }
+
+ if (phy->analog == 1) {
+ b43_phy_write(dev, 0x0026, 0xCE00);
+ b43_phy_write(dev, 0x0021, 0x3763);
+ b43_phy_write(dev, 0x0022, 0x1BC3);
+ b43_phy_write(dev, 0x0023, 0x06F9);
+ b43_phy_write(dev, 0x0024, 0x037E);
+ } else
+ b43_phy_write(dev, 0x0026, 0xCC00);
+ b43_phy_write(dev, 0x0030, 0x00C6);
+ b43_write16(dev, 0x03EC, 0x3F22);
+
+ if (phy->analog == 1)
+ b43_phy_write(dev, 0x0020, 0x3E1C);
+ else
+ b43_phy_write(dev, 0x0020, 0x301C);
+
+ if (phy->analog == 0)
+ b43_write16(dev, 0x03E4, 0x3000);
+
+ old_channel = phy->channel;
+ /* Force to channel 7, even if not supported. */
+ b43_radio_selectchannel(dev, 7, 0);
+
+ if (phy->radio_ver != 0x2050) {
+ b43_radio_write16(dev, 0x0075, 0x0080);
+ b43_radio_write16(dev, 0x0079, 0x0081);
+ }
+
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x005A, 0x0070);
+ }
+
+ b43_radio_write16(dev, 0x005B, 0x007B);
+ b43_radio_write16(dev, 0x005C, 0x00B0);
+
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
+
+ b43_radio_selectchannel(dev, old_channel, 0);
+
+ b43_phy_write(dev, 0x0014, 0x0080);
+ b43_phy_write(dev, 0x0032, 0x00CA);
+ b43_phy_write(dev, 0x002A, 0x88A3);
+
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+
+ if (phy->radio_ver == 0x2050)
+ b43_radio_write16(dev, 0x005D, 0x000D);
+
+ b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
+}
+
+static void b43_phy_initb6(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, val;
+ u8 old_channel;
+
+ b43_phy_write(dev, 0x003E, 0x817A);
+ b43_radio_write16(dev, 0x007A,
+ (b43_radio_read16(dev, 0x007A) | 0x0058));
+ if (phy->radio_rev == 4 || phy->radio_rev == 5) {
+ b43_radio_write16(dev, 0x51, 0x37);
+ b43_radio_write16(dev, 0x52, 0x70);
+ b43_radio_write16(dev, 0x53, 0xB3);
+ b43_radio_write16(dev, 0x54, 0x9B);
+ b43_radio_write16(dev, 0x5A, 0x88);
+ b43_radio_write16(dev, 0x5B, 0x88);
+ b43_radio_write16(dev, 0x5D, 0x88);
+ b43_radio_write16(dev, 0x5E, 0x88);
+ b43_radio_write16(dev, 0x7D, 0x88);
+ b43_hf_write(dev, b43_hf_read(dev)
+ | B43_HF_TSSIRPSMW);
+ }
+ B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x51, 0);
+ b43_radio_write16(dev, 0x52, 0x40);
+ b43_radio_write16(dev, 0x53, 0xB7);
+ b43_radio_write16(dev, 0x54, 0x98);
+ b43_radio_write16(dev, 0x5A, 0x88);
+ b43_radio_write16(dev, 0x5B, 0x6B);
+ b43_radio_write16(dev, 0x5C, 0x0F);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) {
+ b43_radio_write16(dev, 0x5D, 0xFA);
+ b43_radio_write16(dev, 0x5E, 0xD8);
+ } else {
+ b43_radio_write16(dev, 0x5D, 0xF5);
+ b43_radio_write16(dev, 0x5E, 0xB8);
+ }
+ b43_radio_write16(dev, 0x0073, 0x0003);
+ b43_radio_write16(dev, 0x007D, 0x00A8);
+ b43_radio_write16(dev, 0x007C, 0x0001);
+ b43_radio_write16(dev, 0x007E, 0x0008);
+ }
+ val = 0x1E1F;
+ for (offset = 0x0088; offset < 0x0098; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x3E3F;
+ for (offset = 0x0098; offset < 0x00A8; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x2120;
+ for (offset = 0x00A8; offset < 0x00C8; offset++) {
+ b43_phy_write(dev, offset, (val & 0x3F3F));
+ val += 0x0202;
+ }
+ if (phy->type == B43_PHYTYPE_G) {
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0020);
+ b43_radio_write16(dev, 0x0051,
+ b43_radio_read16(dev, 0x0051) | 0x0004);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+ b43_phy_write(dev, 0x5B, 0);
+ b43_phy_write(dev, 0x5C, 0);
+ }
+
+ old_channel = phy->channel;
+ if (old_channel >= 8)
+ b43_radio_selectchannel(dev, 1, 0);
+ else
+ b43_radio_selectchannel(dev, 13, 0);
+
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+ udelay(40);
+ if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
+ | 0x0002));
+ b43_radio_write16(dev, 0x50, 0x20);
+ }
+ if (phy->radio_rev <= 2) {
+ b43_radio_write16(dev, 0x7C, 0x20);
+ b43_radio_write16(dev, 0x5A, 0x70);
+ b43_radio_write16(dev, 0x5B, 0x7B);
+ b43_radio_write16(dev, 0x5C, 0xB0);
+ }
+ b43_radio_write16(dev, 0x007A,
+ (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
+
+ b43_radio_selectchannel(dev, old_channel, 0);
+
+ b43_phy_write(dev, 0x0014, 0x0200);
+ if (phy->radio_rev >= 6)
+ b43_phy_write(dev, 0x2A, 0x88C2);
+ else
+ b43_phy_write(dev, 0x2A, 0x8AC0);
+ b43_phy_write(dev, 0x0038, 0x0668);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+ if (phy->radio_rev <= 5) {
+ b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
+ & 0xFF80) | 0x0003);
+ }
+ if (phy->radio_rev <= 2)
+ b43_radio_write16(dev, 0x005D, 0x000D);
+
+ if (phy->analog == 4) {
+ b43_write16(dev, 0x3E4, 9);
+ b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
+ & 0x0FFF);
+ } else {
+ b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
+ | 0x0004);
+ }
+ if (phy->type == B43_PHYTYPE_B) {
+ b43_write16(dev, 0x03E6, 0x8140);
+ b43_phy_write(dev, 0x0016, 0x0410);
+ b43_phy_write(dev, 0x0017, 0x0820);
+ b43_phy_write(dev, 0x0062, 0x0007);
+ b43_radio_init2050(dev);
+ b43_lo_g_measure(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+ b43_calc_nrssi_slope(dev);
+ b43_calc_nrssi_threshold(dev);
+ }
+ b43_phy_init_pctl(dev);
+ } else if (phy->type == B43_PHYTYPE_G)
+ b43_write16(dev, 0x03E6, 0x0);
+}
+
+static void b43_calc_loopback_gain(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 backup_phy[16] = { 0 };
+ u16 backup_radio[3];
+ u16 backup_bband;
+ u16 i, j, loop_i_max;
+ u16 trsw_rx;
+ u16 loop1_outer_done, loop1_inner_done;
+
+ backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
+ backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+ backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
+ backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+ backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+ }
+ backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
+ backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
+ backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
+ backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
+ backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+ backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
+ backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
+ backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+ backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
+ backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+ backup_bband = phy->bbatt.att;
+ backup_radio[0] = b43_radio_read16(dev, 0x52);
+ backup_radio[1] = b43_radio_read16(dev, 0x43);
+ backup_radio[2] = b43_radio_read16(dev, 0x7A);
+
+ b43_phy_write(dev, B43_PHY_CRS0,
+ b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
+ b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
+ b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev,
+ B43_PHY_ANALOGOVERVAL) & 0xFFFE);
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev,
+ B43_PHY_ANALOGOVERVAL) & 0xFFFD);
+ }
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ & 0xFFCF) | 0x10);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x0A),
+ b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev,
+ B43_PHY_ANALOGOVERVAL) & 0xFFFB);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x03),
+ (b43_phy_read(dev, B43_PHY_BASE(0x03))
+ & 0xFF9F) | 0x40);
+
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x43, 0x000F);
+ } else {
+ b43_radio_write16(dev, 0x52, 0);
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | 0x9);
+ }
+ b43_phy_set_baseband_attenuation(dev, 11);
+
+ if (phy->rev >= 3)
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+ else
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+ b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x2B),
+ (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+ & 0xFFC0) | 0x01);
+ b43_phy_write(dev, B43_PHY_BASE(0x2B),
+ (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+ & 0xC0FF) | 0x800);
+
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
+
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) {
+ if (phy->rev >= 7) {
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER)
+ | 0x0800);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ | 0x8000);
+ }
+ }
+ b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
+ & 0x00F7);
+
+ j = 0;
+ loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
+ for (i = 0; i < loop_i_max; i++) {
+ for (j = 0; j < 16; j++) {
+ b43_radio_write16(dev, 0x43, i);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ & 0xF0FF) | (j << 8));
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ (b43_phy_read(dev, B43_PHY_PGACTL)
+ & 0x0FFF) | 0xA000);
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ b43_phy_read(dev, B43_PHY_PGACTL)
+ | 0xF000);
+ udelay(20);
+ if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+ goto exit_loop1;
+ }
+ }
+ exit_loop1:
+ loop1_outer_done = i;
+ loop1_inner_done = j;
+ if (j >= 8) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ | 0x30);
+ trsw_rx = 0x1B;
+ for (j = j - 8; j < 16; j++) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ & 0xF0FF) | (j << 8));
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ (b43_phy_read(dev, B43_PHY_PGACTL)
+ & 0x0FFF) | 0xA000);
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ b43_phy_read(dev, B43_PHY_PGACTL)
+ | 0xF000);
+ udelay(20);
+ trsw_rx -= 3;
+ if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+ goto exit_loop2;
+ }
+ } else
+ trsw_rx = 0x18;
+ exit_loop2:
+
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
+ b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
+ b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+ b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
+ b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+ b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
+
+ b43_phy_set_baseband_attenuation(dev, backup_bband);
+
+ b43_radio_write16(dev, 0x52, backup_radio[0]);
+ b43_radio_write16(dev, 0x43, backup_radio[1]);
+ b43_radio_write16(dev, 0x7A, backup_radio[2]);
+
+ b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
+ udelay(10);
+ b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
+ b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
+ b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
+
+ phy->max_lb_gain =
+ ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
+ phy->trsw_rx_gain = trsw_rx * 2;
+}
+
+static void b43_phy_initg(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (phy->rev == 1)
+ b43_phy_initb5(dev);
+ else
+ b43_phy_initb6(dev);
+
+ if (phy->rev >= 2 || phy->gmode)
+ b43_phy_inita(dev);
+
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
+ }
+ if (phy->rev == 2) {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0);
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+ }
+ if (phy->rev > 5) {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
+ tmp &= B43_PHYVER_VERSION;
+ if (tmp == 3 || tmp == 5) {
+ b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
+ b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
+ }
+ if (tmp == 5) {
+ b43_phy_write(dev, B43_PHY_OFDM(0xCC),
+ (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
+ & 0x00FF) | 0x1F00);
+ }
+ }
+ if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
+ b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
+ if (phy->radio_rev == 8) {
+ b43_phy_write(dev, B43_PHY_EXTG(0x01),
+ b43_phy_read(dev, B43_PHY_EXTG(0x01))
+ | 0x80);
+ b43_phy_write(dev, B43_PHY_OFDM(0x3E),
+ b43_phy_read(dev, B43_PHY_OFDM(0x3E))
+ | 0x4);
+ }
+ if (has_loopback_gain(phy))
+ b43_calc_loopback_gain(dev);
+
+ if (phy->radio_rev != 8) {
+ if (phy->initval == 0xFFFF)
+ phy->initval = b43_radio_init2050(dev);
+ else
+ b43_radio_write16(dev, 0x0078, phy->initval);
+ }
+ if (phy->lo_control->tx_bias == 0xFF) {
+ b43_lo_g_measure(dev);
+ } else {
+ if (has_tx_magnification(phy)) {
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52) & 0xFF00)
+ | phy->lo_control->tx_bias | phy->
+ lo_control->tx_magn);
+ } else {
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52) & 0xFFF0)
+ | phy->lo_control->tx_bias);
+ }
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, B43_PHY_BASE(0x36),
+ (b43_phy_read(dev, B43_PHY_BASE(0x36))
+ & 0x0FFF) | (phy->lo_control->
+ tx_bias << 12));
+ }
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
+ if (phy->rev < 2)
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ b43_lo_g_adjust(dev);
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+ }
+
+ if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+ /* The specs state to update the NRSSI LT with
+ * the value 0x7FFFFFFF here. I think that is some weird
+ * compiler optimization in the original driver.
+ * Essentially, what we do here is resetting all NRSSI LT
+ * entries to -32 (see the limit_value() in nrssi_hw_update())
+ */
+ b43_nrssi_hw_update(dev, 0xFFFF); //FIXME?
+ b43_calc_nrssi_threshold(dev);
+ } else if (phy->gmode || phy->rev >= 2) {
+ if (phy->nrssi[0] == -1000) {
+ B43_WARN_ON(phy->nrssi[1] != -1000);
+ b43_calc_nrssi_slope(dev);
+ } else
+ b43_calc_nrssi_threshold(dev);
+ }
+ if (phy->radio_rev == 8)
+ b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
+ b43_phy_init_pctl(dev);
+ /* FIXME: The spec says in the following if, the 0 should be replaced
+ 'if OFDM may not be used in the current locale'
+ but OFDM is legal everywhere */
+ if ((dev->dev->bus->chip_id == 0x4306
+ && dev->dev->bus->chip_package == 2) || 0) {
+ b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+ & 0xBFFF);
+ b43_phy_write(dev, B43_PHY_OFDM(0xC3),
+ b43_phy_read(dev, B43_PHY_OFDM(0xC3))
+ & 0x7FFF);
+ }
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
+ u16 baseband_attenuation)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->analog == 0) {
+ b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
+ & 0xFFF0) |
+ baseband_attenuation);
+ } else if (phy->analog > 1) {
+ b43_phy_write(dev, B43_PHY_DACCTL,
+ (b43_phy_read(dev, B43_PHY_DACCTL)
+ & 0xFFC3) | (baseband_attenuation << 2));
+ } else {
+ b43_phy_write(dev, B43_PHY_DACCTL,
+ (b43_phy_read(dev, B43_PHY_DACCTL)
+ & 0xFF87) | (baseband_attenuation << 3));
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
+{
+ struct b43_phy *phy = &dev->phy;
+ s8 dbm = 0;
+ s32 tmp;
+
+ tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ tmp += 0x80;
+ tmp = limit_value(tmp, 0x00, 0xFF);
+ dbm = phy->tssi2dbm[tmp];
+ //TODO: There's a FIXME on the specs
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ tmp = limit_value(tmp, 0x00, 0x3F);
+ dbm = phy->tssi2dbm[tmp];
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ return dbm;
+}
+
+void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+ int *_bbatt, int *_rfatt)
+{
+ int rfatt = *_rfatt;
+ int bbatt = *_bbatt;
+ struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+
+ /* Get baseband and radio attenuation values into their permitted ranges.
+ * Radio attenuation affects power level 4 times as much as baseband. */
+
+ /* Range constants */
+ const int rf_min = lo->rfatt_list.min_val;
+ const int rf_max = lo->rfatt_list.max_val;
+ const int bb_min = lo->bbatt_list.min_val;
+ const int bb_max = lo->bbatt_list.max_val;
+
+ while (1) {
+ if (rfatt > rf_max && bbatt > bb_max - 4)
+ break; /* Can not get it into ranges */
+ if (rfatt < rf_min && bbatt < bb_min + 4)
+ break; /* Can not get it into ranges */
+ if (bbatt > bb_max && rfatt > rf_max - 1)
+ break; /* Can not get it into ranges */
+ if (bbatt < bb_min && rfatt < rf_min + 1)
+ break; /* Can not get it into ranges */
+
+ if (bbatt > bb_max) {
+ bbatt -= 4;
+ rfatt += 1;
+ continue;
+ }
+ if (bbatt < bb_min) {
+ bbatt += 4;
+ rfatt -= 1;
+ continue;
+ }
+ if (rfatt > rf_max) {
+ rfatt -= 1;
+ bbatt += 4;
+ continue;
+ }
+ if (rfatt < rf_min) {
+ rfatt += 1;
+ bbatt -= 4;
+ continue;
+ }
+ break;
+ }
+
+ *_rfatt = limit_value(rfatt, rf_min, rf_max);
+ *_bbatt = limit_value(bbatt, bb_min, bb_max);
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void b43_phy_xmitpower(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->cur_idle_tssi == 0)
+ return;
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306))
+ return;
+#ifdef CONFIG_B43_DEBUG
+ if (phy->manual_txpower_control)
+ return;
+#endif
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:{
+
+ //TODO: Nothing for A PHYs yet :-/
+
+ break;
+ }
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:{
+ u16 tmp;
+ s8 v0, v1, v2, v3;
+ s8 average;
+ int max_pwr;
+ int desired_pwr, estimated_pwr, pwr_adjust;
+ int rfatt_delta, bbatt_delta;
+ int rfatt, bbatt;
+ u8 tx_control;
+ unsigned long phylock_flags;
+
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
+ v0 = (s8) (tmp & 0x00FF);
+ v1 = (s8) ((tmp & 0xFF00) >> 8);
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
+ v2 = (s8) (tmp & 0x00FF);
+ v3 = (s8) ((tmp & 0xFF00) >> 8);
+ tmp = 0;
+
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
+ || v3 == 0x7F) {
+ tmp =
+ b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
+ v0 = (s8) (tmp & 0x00FF);
+ v1 = (s8) ((tmp & 0xFF00) >> 8);
+ tmp =
+ b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
+ v2 = (s8) (tmp & 0x00FF);
+ v3 = (s8) ((tmp & 0xFF00) >> 8);
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
+ || v3 == 0x7F)
+ return;
+ v0 = (v0 + 0x20) & 0x3F;
+ v1 = (v1 + 0x20) & 0x3F;
+ v2 = (v2 + 0x20) & 0x3F;
+ v3 = (v3 + 0x20) & 0x3F;
+ tmp = 1;
+ }
+ b43_shm_clear_tssi(dev);
+
+ average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+ if (tmp
+ && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
+ 0x8))
+ average -= 13;
+
+ estimated_pwr =
+ b43_phy_estimate_power_out(dev, average);
+
+ max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+ if ((dev->dev->bus->sprom.r1.
+ boardflags_lo & B43_BFL_PACTRL)
+ && (phy->type == B43_PHYTYPE_G))
+ max_pwr -= 0x3;
+ if (unlikely(max_pwr <= 0)) {
+ b43warn(dev->wl,
+ "Invalid max-TX-power value in SPROM.\n");
+ max_pwr = 60; /* fake it */
+ dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+ }
+
+ /*TODO:
+ max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
+ where REG is the max power as per the regulatory domain
+ */
+
+ /* Get desired power (in Q5.2) */
+ desired_pwr = INT_TO_Q52(phy->power_level);
+ /* And limit it. max_pwr already is Q5.2 */
+ desired_pwr = limit_value(desired_pwr, 0, max_pwr);
+ if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+ b43dbg(dev->wl,
+ "Current TX power output: " Q52_FMT
+ " dBm, " "Desired TX power output: "
+ Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
+ Q52_ARG(desired_pwr));
+ }
+
+ /* Calculate the adjustment delta. */
+ pwr_adjust = desired_pwr - estimated_pwr;
+
+ /* RF attenuation delta. */
+ rfatt_delta = ((pwr_adjust + 7) / 8);
+ /* Lower attenuation => Bigger power output. Negate it. */
+ rfatt_delta = -rfatt_delta;
+
+ /* Baseband attenuation delta. */
+ bbatt_delta = pwr_adjust / 2;
+ /* Lower attenuation => Bigger power output. Negate it. */
+ bbatt_delta = -bbatt_delta;
+ /* RF att affects power level 4 times as much as
+ * Baseband attennuation. Subtract it. */
+ bbatt_delta -= 4 * rfatt_delta;
+
+ /* So do we finally need to adjust something? */
+ if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
+ b43_lo_g_ctl_mark_cur_used(dev);
+ return;
+ }
+
+ /* Calculate the new attenuation values. */
+ bbatt = phy->bbatt.att;
+ bbatt += bbatt_delta;
+ rfatt = phy->rfatt.att;
+ rfatt += rfatt_delta;
+
+ b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+ tx_control = phy->tx_control;
+ if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+ if (rfatt <= 1) {
+ if (tx_control == 0) {
+ tx_control =
+ B43_TXCTL_PA2DB |
+ B43_TXCTL_TXMIX;
+ rfatt += 2;
+ bbatt += 2;
+ } else if (dev->dev->bus->sprom.r1.
+ boardflags_lo &
+ B43_BFL_PACTRL) {
+ bbatt += 4 * (rfatt - 2);
+ rfatt = 2;
+ }
+ } else if (rfatt > 4 && tx_control) {
+ tx_control = 0;
+ if (bbatt < 3) {
+ rfatt -= 3;
+ bbatt += 2;
+ } else {
+ rfatt -= 2;
+ bbatt -= 2;
+ }
+ }
+ }
+ /* Save the control values */
+ phy->tx_control = tx_control;
+ b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+ phy->rfatt.att = rfatt;
+ phy->bbatt.att = bbatt;
+
+ /* Adjust the hardware */
+ b43_phy_lock(dev, phylock_flags);
+ b43_radio_lock(dev);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
+ phy->tx_control);
+ b43_lo_g_ctl_mark_cur_used(dev);
+ b43_radio_unlock(dev);
+ b43_phy_unlock(dev, phylock_flags);
+ break;
+ }
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
+{
+ if (num < 0)
+ return num / den;
+ else
+ return (num + den / 2) / den;
+}
+
+static inline
+ s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+ s32 m1, m2, f = 256, q, delta;
+ s8 i = 0;
+
+ m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+ m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+ do {
+ if (i > 15)
+ return -EINVAL;
+ q = b43_tssi2dbm_ad(f * 4096 -
+ b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
+ delta = abs(q - f);
+ f = q;
+ i++;
+ } while (delta >= 2);
+ entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+ return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ s16 pab0, pab1, pab2;
+ u8 idx;
+ s8 *dyn_tssi2dbm;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0);
+ pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1);
+ pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2);
+ } else {
+ pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0);
+ pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1);
+ pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2);
+ }
+
+ if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
+ phy->tgt_idle_tssi = 0x34;
+ phy->tssi2dbm = b43_tssi2dbm_b_table;
+ return 0;
+ }
+
+ if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+ pab0 != -1 && pab1 != -1 && pab2 != -1) {
+ /* The pabX values are set in SPROM. Use them. */
+ if (phy->type == B43_PHYTYPE_A) {
+ if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 &&
+ (s8) dev->dev->bus->sprom.r1.itssi_a != -1)
+ phy->tgt_idle_tssi =
+ (s8) (dev->dev->bus->sprom.r1.itssi_a);
+ else
+ phy->tgt_idle_tssi = 62;
+ } else {
+ if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 &&
+ (s8) dev->dev->bus->sprom.r1.itssi_bg != -1)
+ phy->tgt_idle_tssi =
+ (s8) (dev->dev->bus->sprom.r1.itssi_bg);
+ else
+ phy->tgt_idle_tssi = 62;
+ }
+ dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+ if (dyn_tssi2dbm == NULL) {
+ b43err(dev->wl, "Could not allocate memory"
+ "for tssi2dbm table\n");
+ return -ENOMEM;
+ }
+ for (idx = 0; idx < 64; idx++)
+ if (b43_tssi2dbm_entry
+ (dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
+ phy->tssi2dbm = NULL;
+ b43err(dev->wl, "Could not generate "
+ "tssi2dBm table\n");
+ kfree(dyn_tssi2dbm);
+ return -ENODEV;
+ }
+ phy->tssi2dbm = dyn_tssi2dbm;
+ phy->dyn_tssi_tbl = 1;
+ } else {
+ /* pabX values not set in SPROM. */
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ /* APHY needs a generated table. */
+ phy->tssi2dbm = NULL;
+ b43err(dev->wl, "Could not generate tssi2dBm "
+ "table (wrong SPROM info)!\n");
+ return -ENODEV;
+ case B43_PHYTYPE_B:
+ phy->tgt_idle_tssi = 0x34;
+ phy->tssi2dbm = b43_tssi2dbm_b_table;
+ break;
+ case B43_PHYTYPE_G:
+ phy->tgt_idle_tssi = 0x34;
+ phy->tssi2dbm = b43_tssi2dbm_g_table;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int b43_phy_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int err = -ENODEV;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ if (phy->rev == 2 || phy->rev == 3) {
+ b43_phy_inita(dev);
+ err = 0;
+ }
+ break;
+ case B43_PHYTYPE_B:
+ switch (phy->rev) {
+ case 2:
+ b43_phy_initb2(dev);
+ err = 0;
+ break;
+ case 4:
+ b43_phy_initb4(dev);
+ err = 0;
+ break;
+ case 5:
+ b43_phy_initb5(dev);
+ err = 0;
+ break;
+ case 6:
+ b43_phy_initb6(dev);
+ err = 0;
+ break;
+ }
+ break;
+ case B43_PHYTYPE_G:
+ b43_phy_initg(dev);
+ err = 0;
+ break;
+ }
+ if (err)
+ b43err(dev->wl, "Unknown PHYTYPE found\n");
+
+ return err;
+}
+
+void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+ struct b43_phy *phy = &dev->phy;
+ u32 hf;
+ u16 tmp;
+ int autodiv = 0;
+
+ if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
+ autodiv = 1;
+
+ hf = b43_hf_read(dev);
+ hf &= ~B43_HF_ANTDIVHELP;
+ b43_hf_write(dev, hf);
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ case B43_PHYTYPE_G:
+ tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
+ tmp &= ~B43_PHY_BBANDCFG_RXANT;
+ tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+ << B43_PHY_BBANDCFG_RXANT_SHIFT;
+ b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+
+ if (autodiv) {
+ tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+ if (antenna == B43_ANTENNA_AUTO0)
+ tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
+ else
+ tmp |= B43_PHY_ANTDWELL_AUTODIV1;
+ b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+ }
+ if (phy->type == B43_PHYTYPE_G) {
+ tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
+ if (autodiv)
+ tmp |= B43_PHY_ANTWRSETT_ARXDIV;
+ else
+ tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
+ b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
+ if (phy->rev >= 2) {
+ tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+ tmp |= B43_PHY_OFDM61_10;
+ b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+
+ tmp =
+ b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
+ tmp = (tmp & 0xFF00) | 0x15;
+ b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
+ tmp);
+
+ if (phy->rev == 2) {
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ 8);
+ } else {
+ tmp =
+ b43_phy_read(dev,
+ B43_PHY_ADIVRELATED);
+ tmp = (tmp & 0xFF00) | 8;
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ tmp);
+ }
+ }
+ if (phy->rev >= 6)
+ b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
+ } else {
+ if (phy->rev < 3) {
+ tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+ tmp = (tmp & 0xFF00) | 0x24;
+ b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+ } else {
+ tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+ tmp |= 0x10;
+ b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+ if (phy->analog == 3) {
+ b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+ 0x1D);
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ 8);
+ } else {
+ b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+ 0x3A);
+ tmp =
+ b43_phy_read(dev,
+ B43_PHY_ADIVRELATED);
+ tmp = (tmp & 0xFF00) | 8;
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ tmp);
+ }
+ }
+ }
+ break;
+ case B43_PHYTYPE_B:
+ tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+ tmp &= ~B43_PHY_BBANDCFG_RXANT;
+ tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+ << B43_PHY_BBANDCFG_RXANT_SHIFT;
+ b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ hf |= B43_HF_ANTDIVHELP;
+ b43_hf_write(dev, hf);
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_bg(u8 channel)
+{
+ B43_WARN_ON(!(channel >= 1 && channel <= 14));
+
+ return b43_radio_channel_codes_bg[channel - 1];
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_a(u8 channel)
+{
+ B43_WARN_ON(channel > 200);
+
+ return (5000 + 5 * channel);
+}
+
+void b43_radio_lock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl |= B43_MACCTL_RADIOLOCK;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit the write and wait for the device
+ * to exit any radio register access. */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ udelay(10);
+}
+
+void b43_radio_unlock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ /* Commit any write */
+ b43_read16(dev, B43_MMIO_PHY_VER);
+ /* unlock */
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_RADIOLOCK;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ offset |= 0x0040;
+ break;
+ case B43_PHYTYPE_B:
+ if (phy->radio_ver == 0x2053) {
+ if (offset < 0x70)
+ offset += 0x80;
+ else if (offset < 0x80)
+ offset += 0x70;
+ } else if (phy->radio_ver == 0x2050) {
+ offset |= 0x80;
+ } else
+ B43_WARN_ON(1);
+ break;
+ case B43_PHYTYPE_G:
+ offset |= 0x80;
+ break;
+ }
+
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
+ return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
+{
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void b43_set_all_gains(struct b43_wldev *dev,
+ s16 first, s16 second, s16 third)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 i;
+ u16 start = 0x08, end = 0x18;
+ u16 tmp;
+ u16 table;
+
+ if (phy->rev <= 1) {
+ start = 0x10;
+ end = 0x20;
+ }
+
+ table = B43_OFDMTAB_GAINX;
+ if (phy->rev <= 1)
+ table = B43_OFDMTAB_GAINX_R1;
+ for (i = 0; i < 4; i++)
+ b43_ofdmtab_write16(dev, table, i, first);
+
+ for (i = start; i < end; i++)
+ b43_ofdmtab_write16(dev, table, i, second);
+
+ if (third != -1) {
+ tmp = ((u16) third << 14) | ((u16) third << 6);
+ b43_phy_write(dev, 0x04A0,
+ (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
+ b43_phy_write(dev, 0x04A1,
+ (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
+ b43_phy_write(dev, 0x04A2,
+ (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
+ }
+ b43_dummy_transmission(dev);
+}
+
+static void b43_set_original_gains(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 i, tmp;
+ u16 table;
+ u16 start = 0x0008, end = 0x0018;
+
+ if (phy->rev <= 1) {
+ start = 0x0010;
+ end = 0x0020;
+ }
+
+ table = B43_OFDMTAB_GAINX;
+ if (phy->rev <= 1)
+ table = B43_OFDMTAB_GAINX_R1;
+ for (i = 0; i < 4; i++) {
+ tmp = (i & 0xFFFC);
+ tmp |= (i & 0x0001) << 1;
+ tmp |= (i & 0x0002) >> 1;
+
+ b43_ofdmtab_write16(dev, table, i, tmp);
+ }
+
+ for (i = start; i < end; i++)
+ b43_ofdmtab_write16(dev, table, i, i - start);
+
+ b43_phy_write(dev, 0x04A0,
+ (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
+ b43_phy_write(dev, 0x04A1,
+ (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
+ b43_phy_write(dev, 0x04A2,
+ (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
+ b43_dummy_transmission(dev);
+}
+
+/* Synthetic PU workaround */
+static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ might_sleep();
+
+ if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
+ /* We do not need the workaround. */
+ return;
+ }
+
+ if (channel <= 10) {
+ b43_write16(dev, B43_MMIO_CHANNEL,
+ channel2freq_bg(channel + 4));
+ } else {
+ b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
+ }
+ msleep(1);
+ b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+}
+
+u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel)
+{
+ struct b43_phy *phy = &dev->phy;
+ u8 ret = 0;
+ u16 saved, rssi, temp;
+ int i, j = 0;
+
+ saved = b43_phy_read(dev, 0x0403);
+ b43_radio_selectchannel(dev, channel, 0);
+ b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+ if (phy->aci_hw_rssi)
+ rssi = b43_phy_read(dev, 0x048A) & 0x3F;
+ else
+ rssi = saved & 0x3F;
+ /* clamp temp to signed 5bit */
+ if (rssi > 32)
+ rssi -= 64;
+ for (i = 0; i < 100; i++) {
+ temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
+ if (temp > 32)
+ temp -= 64;
+ if (temp < rssi)
+ j++;
+ if (j >= 20)
+ ret = 1;
+ }
+ b43_phy_write(dev, 0x0403, saved);
+
+ return ret;
+}
+
+u8 b43_radio_aci_scan(struct b43_wldev * dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u8 ret[13];
+ unsigned int channel = phy->channel;
+ unsigned int i, j, start, end;
+ unsigned long phylock_flags;
+
+ if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
+ return 0;
+
+ b43_phy_lock(dev, phylock_flags);
+ b43_radio_lock(dev);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+ b43_set_all_gains(dev, 3, 8, 1);
+
+ start = (channel - 5 > 0) ? channel - 5 : 1;
+ end = (channel + 5 < 14) ? channel + 5 : 13;
+
+ for (i = start; i <= end; i++) {
+ if (abs(channel - i) > 2)
+ ret[i - 1] = b43_radio_aci_detect(dev, i);
+ }
+ b43_radio_selectchannel(dev, channel, 0);
+ b43_phy_write(dev, 0x0802,
+ (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
+ b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+ b43_set_original_gains(dev);
+ for (i = 0; i < 13; i++) {
+ if (!ret[i])
+ continue;
+ end = (i + 5 < 13) ? i + 5 : 13;
+ for (j = i; j < end; j++)
+ ret[j] = 1;
+ }
+ b43_radio_unlock(dev);
+ b43_phy_unlock(dev, phylock_flags);
+
+ return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
+{
+ b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+ mmiowb();
+ b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
+{
+ u16 val;
+
+ b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+ val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
+
+ return (s16) val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
+{
+ u16 i;
+ s16 tmp;
+
+ for (i = 0; i < 64; i++) {
+ tmp = b43_nrssi_hw_read(dev, i);
+ tmp -= val;
+ tmp = limit_value(tmp, -32, 31);
+ b43_nrssi_hw_write(dev, i, tmp);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_mem_update(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ s16 i, delta;
+ s32 tmp;
+
+ delta = 0x1F - phy->nrssi[0];
+ for (i = 0; i < 64; i++) {
+ tmp = (i - delta) * phy->nrssislope;
+ tmp /= 0x10000;
+ tmp += 0x3A;
+ tmp = limit_value(tmp, 0, 0x3F);
+ phy->nrssi_lt[i] = tmp;
+ }
+}
+
+static void b43_calc_nrssi_offset(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 backup[20] = { 0 };
+ s16 v47F;
+ u16 i;
+ u16 saved = 0xFFFF;
+
+ backup[0] = b43_phy_read(dev, 0x0001);
+ backup[1] = b43_phy_read(dev, 0x0811);
+ backup[2] = b43_phy_read(dev, 0x0812);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ backup[3] = b43_phy_read(dev, 0x0814);
+ backup[4] = b43_phy_read(dev, 0x0815);
+ }
+ backup[5] = b43_phy_read(dev, 0x005A);
+ backup[6] = b43_phy_read(dev, 0x0059);
+ backup[7] = b43_phy_read(dev, 0x0058);
+ backup[8] = b43_phy_read(dev, 0x000A);
+ backup[9] = b43_phy_read(dev, 0x0003);
+ backup[10] = b43_radio_read16(dev, 0x007A);
+ backup[11] = b43_radio_read16(dev, 0x0043);
+
+ b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
+ b43_phy_write(dev, 0x0001,
+ (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
+ b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+ b43_phy_write(dev, 0x0812,
+ (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+ if (phy->rev >= 6) {
+ backup[12] = b43_phy_read(dev, 0x002E);
+ backup[13] = b43_phy_read(dev, 0x002F);
+ backup[14] = b43_phy_read(dev, 0x080F);
+ backup[15] = b43_phy_read(dev, 0x0810);
+ backup[16] = b43_phy_read(dev, 0x0801);
+ backup[17] = b43_phy_read(dev, 0x0060);
+ backup[18] = b43_phy_read(dev, 0x0014);
+ backup[19] = b43_phy_read(dev, 0x0478);
+
+ b43_phy_write(dev, 0x002E, 0);
+ b43_phy_write(dev, 0x002F, 0);
+ b43_phy_write(dev, 0x080F, 0);
+ b43_phy_write(dev, 0x0810, 0);
+ b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
+ b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
+ b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
+ b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
+ }
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
+ udelay(30);
+
+ v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == 31) {
+ for (i = 7; i >= 4; i--) {
+ b43_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F =
+ (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F < 31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 4;
+ } else {
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x007F);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, 0x0814,
+ b43_phy_read(dev, 0x0814) | 0x0001);
+ b43_phy_write(dev, 0x0815,
+ b43_phy_read(dev, 0x0815) & 0xFFFE);
+ }
+ b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+ b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
+ b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
+ b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
+ b43_phy_write(dev, 0x005A, 0x0480);
+ b43_phy_write(dev, 0x0059, 0x0810);
+ b43_phy_write(dev, 0x0058, 0x000D);
+ if (phy->rev == 0) {
+ b43_phy_write(dev, 0x0003, 0x0122);
+ } else {
+ b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
+ | 0x2000);
+ }
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, 0x0814,
+ b43_phy_read(dev, 0x0814) | 0x0004);
+ b43_phy_write(dev, 0x0815,
+ b43_phy_read(dev, 0x0815) & 0xFFFB);
+ }
+ b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
+ | 0x0040);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x000F);
+ b43_set_all_gains(dev, 3, 0, 1);
+ b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
+ & 0x00F0) | 0x000F);
+ udelay(30);
+ v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == -32) {
+ for (i = 0; i < 4; i++) {
+ b43_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F =
+ (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
+ 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F > -31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 3;
+ } else
+ saved = 0;
+ }
+ b43_radio_write16(dev, 0x007B, saved);
+
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x002E, backup[12]);
+ b43_phy_write(dev, 0x002F, backup[13]);
+ b43_phy_write(dev, 0x080F, backup[14]);
+ b43_phy_write(dev, 0x0810, backup[15]);
+ }
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, 0x0814, backup[3]);
+ b43_phy_write(dev, 0x0815, backup[4]);
+ }
+ b43_phy_write(dev, 0x005A, backup[5]);
+ b43_phy_write(dev, 0x0059, backup[6]);
+ b43_phy_write(dev, 0x0058, backup[7]);
+ b43_phy_write(dev, 0x000A, backup[8]);
+ b43_phy_write(dev, 0x0003, backup[9]);
+ b43_radio_write16(dev, 0x0043, backup[11]);
+ b43_radio_write16(dev, 0x007A, backup[10]);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
+ b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
+ b43_set_original_gains(dev);
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x0801, backup[16]);
+ b43_phy_write(dev, 0x0060, backup[17]);
+ b43_phy_write(dev, 0x0014, backup[18]);
+ b43_phy_write(dev, 0x0478, backup[19]);
+ }
+ b43_phy_write(dev, 0x0001, backup[0]);
+ b43_phy_write(dev, 0x0812, backup[2]);
+ b43_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 backup[18] = { 0 };
+ u16 tmp;
+ s16 nrssi0, nrssi1;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_B:
+ backup[0] = b43_radio_read16(dev, 0x007A);
+ backup[1] = b43_radio_read16(dev, 0x0052);
+ backup[2] = b43_radio_read16(dev, 0x0043);
+ backup[3] = b43_phy_read(dev, 0x0030);
+ backup[4] = b43_phy_read(dev, 0x0026);
+ backup[5] = b43_phy_read(dev, 0x0015);
+ backup[6] = b43_phy_read(dev, 0x002A);
+ backup[7] = b43_phy_read(dev, 0x0020);
+ backup[8] = b43_phy_read(dev, 0x005A);
+ backup[9] = b43_phy_read(dev, 0x0059);
+ backup[10] = b43_phy_read(dev, 0x0058);
+ backup[11] = b43_read16(dev, 0x03E2);
+ backup[12] = b43_read16(dev, 0x03E6);
+ backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+
+ tmp = b43_radio_read16(dev, 0x007A);
+ tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+ b43_radio_write16(dev, 0x007A, tmp);
+ b43_phy_write(dev, 0x0030, 0x00FF);
+ b43_write16(dev, 0x03EC, 0x7F7F);
+ b43_phy_write(dev, 0x0026, 0x0000);
+ b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020);
+ b43_phy_write(dev, 0x002A, 0x08A3);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0080);
+
+ nrssi0 = (s16) b43_phy_read(dev, 0x0027);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x007F);
+ if (phy->rev >= 2) {
+ b43_write16(dev, 0x03E6, 0x0040);
+ } else if (phy->rev == 0) {
+ b43_write16(dev, 0x03E6, 0x0122);
+ } else {
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev,
+ B43_MMIO_CHANNEL_EXT) & 0x2000);
+ }
+ b43_phy_write(dev, 0x0020, 0x3F3F);
+ b43_phy_write(dev, 0x0015, 0xF330);
+ b43_radio_write16(dev, 0x005A, 0x0060);
+ b43_radio_write16(dev, 0x0043,
+ b43_radio_read16(dev, 0x0043) & 0x00F0);
+ b43_phy_write(dev, 0x005A, 0x0480);
+ b43_phy_write(dev, 0x0059, 0x0810);
+ b43_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+
+ nrssi1 = (s16) b43_phy_read(dev, 0x0027);
+ b43_phy_write(dev, 0x0030, backup[3]);
+ b43_radio_write16(dev, 0x007A, backup[0]);
+ b43_write16(dev, 0x03E2, backup[11]);
+ b43_phy_write(dev, 0x0026, backup[4]);
+ b43_phy_write(dev, 0x0015, backup[5]);
+ b43_phy_write(dev, 0x002A, backup[6]);
+ b43_synth_pu_workaround(dev, phy->channel);
+ if (phy->rev != 0)
+ b43_write16(dev, 0x03F4, backup[13]);
+
+ b43_phy_write(dev, 0x0020, backup[7]);
+ b43_phy_write(dev, 0x005A, backup[8]);
+ b43_phy_write(dev, 0x0059, backup[9]);
+ b43_phy_write(dev, 0x0058, backup[10]);
+ b43_radio_write16(dev, 0x0052, backup[1]);
+ b43_radio_write16(dev, 0x0043, backup[2]);
+
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+ if (nrssi0 <= -4) {
+ phy->nrssi[0] = nrssi0;
+ phy->nrssi[1] = nrssi1;
+ }
+ break;
+ case B43_PHYTYPE_G:
+ if (phy->radio_rev >= 9)
+ return;
+ if (phy->radio_rev == 8)
+ b43_calc_nrssi_offset(dev);
+
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+ backup[7] = b43_read16(dev, 0x03E2);
+ b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
+ backup[0] = b43_radio_read16(dev, 0x007A);
+ backup[1] = b43_radio_read16(dev, 0x0052);
+ backup[2] = b43_radio_read16(dev, 0x0043);
+ backup[3] = b43_phy_read(dev, 0x0015);
+ backup[4] = b43_phy_read(dev, 0x005A);
+ backup[5] = b43_phy_read(dev, 0x0059);
+ backup[6] = b43_phy_read(dev, 0x0058);
+ backup[8] = b43_read16(dev, 0x03E6);
+ backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+ if (phy->rev >= 3) {
+ backup[10] = b43_phy_read(dev, 0x002E);
+ backup[11] = b43_phy_read(dev, 0x002F);
+ backup[12] = b43_phy_read(dev, 0x080F);
+ backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
+ backup[14] = b43_phy_read(dev, 0x0801);
+ backup[15] = b43_phy_read(dev, 0x0060);
+ backup[16] = b43_phy_read(dev, 0x0014);
+ backup[17] = b43_phy_read(dev, 0x0478);
+ b43_phy_write(dev, 0x002E, 0);
+ b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
+ switch (phy->rev) {
+ case 4:
+ case 6:
+ case 7:
+ b43_phy_write(dev, 0x0478,
+ b43_phy_read(dev, 0x0478)
+ | 0x0100);
+ b43_phy_write(dev, 0x0801,
+ b43_phy_read(dev, 0x0801)
+ | 0x0040);
+ break;
+ case 3:
+ case 5:
+ b43_phy_write(dev, 0x0801,
+ b43_phy_read(dev, 0x0801)
+ & 0xFFBF);
+ break;
+ }
+ b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
+ | 0x0040);
+ b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
+ | 0x0200);
+ }
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0070);
+ b43_set_all_gains(dev, 0, 8, 0);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x00F7);
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0811,
+ (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+ 0x0030);
+ b43_phy_write(dev, 0x0812,
+ (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+ 0x0010);
+ }
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0080);
+ udelay(20);
+
+ nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi0 >= 0x0020)
+ nrssi0 -= 0x0040;
+
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x007F);
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
+ & 0xFF9F) | 0x0040);
+ }
+
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+ | 0x2000);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x000F);
+ b43_phy_write(dev, 0x0015, 0xF330);
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0812,
+ (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+ 0x0020);
+ b43_phy_write(dev, 0x0811,
+ (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+ 0x0020);
+ }
+
+ b43_set_all_gains(dev, 3, 0, 1);
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x0043, 0x001F);
+ } else {
+ tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
+ b43_radio_write16(dev, 0x0052, tmp | 0x0060);
+ tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
+ b43_radio_write16(dev, 0x0043, tmp | 0x0009);
+ }
+ b43_phy_write(dev, 0x005A, 0x0480);
+ b43_phy_write(dev, 0x0059, 0x0810);
+ b43_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+ nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi1 >= 0x0020)
+ nrssi1 -= 0x0040;
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+ if (nrssi0 >= -4) {
+ phy->nrssi[0] = nrssi1;
+ phy->nrssi[1] = nrssi0;
+ }
+ if (phy->rev >= 3) {
+ b43_phy_write(dev, 0x002E, backup[10]);
+ b43_phy_write(dev, 0x002F, backup[11]);
+ b43_phy_write(dev, 0x080F, backup[12]);
+ b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
+ }
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0812,
+ b43_phy_read(dev, 0x0812) & 0xFFCF);
+ b43_phy_write(dev, 0x0811,
+ b43_phy_read(dev, 0x0811) & 0xFFCF);
+ }
+
+ b43_radio_write16(dev, 0x007A, backup[0]);
+ b43_radio_write16(dev, 0x0052, backup[1]);
+ b43_radio_write16(dev, 0x0043, backup[2]);
+ b43_write16(dev, 0x03E2, backup[7]);
+ b43_write16(dev, 0x03E6, backup[8]);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
+ b43_phy_write(dev, 0x0015, backup[3]);
+ b43_phy_write(dev, 0x005A, backup[4]);
+ b43_phy_write(dev, 0x0059, backup[5]);
+ b43_phy_write(dev, 0x0058, backup[6]);
+ b43_synth_pu_workaround(dev, phy->channel);
+ b43_phy_write(dev, 0x0802,
+ b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
+ b43_set_original_gains(dev);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+ if (phy->rev >= 3) {
+ b43_phy_write(dev, 0x0801, backup[14]);
+ b43_phy_write(dev, 0x0060, backup[15]);
+ b43_phy_write(dev, 0x0014, backup[16]);
+ b43_phy_write(dev, 0x0478, backup[17]);
+ }
+ b43_nrssi_mem_update(dev);
+ b43_calc_nrssi_threshold(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+void b43_calc_nrssi_threshold(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ s32 threshold;
+ s32 a, b;
+ s16 tmp16;
+ u16 tmp_u16;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_B:{
+ if (phy->radio_ver != 0x2050)
+ return;
+ if (!
+ (dev->dev->bus->sprom.r1.
+ boardflags_lo & B43_BFL_RSSI))
+ return;
+
+ if (phy->radio_rev >= 6) {
+ threshold =
+ (phy->nrssi[1] - phy->nrssi[0]) * 32;
+ threshold += 20 * (phy->nrssi[0] + 1);
+ threshold /= 40;
+ } else
+ threshold = phy->nrssi[1] - 5;
+
+ threshold = limit_value(threshold, 0, 0x3E);
+ b43_phy_read(dev, 0x0020); /* dummy read */
+ b43_phy_write(dev, 0x0020,
+ (((u16) threshold) << 8) | 0x001C);
+
+ if (phy->radio_rev >= 6) {
+ b43_phy_write(dev, 0x0087, 0x0E0D);
+ b43_phy_write(dev, 0x0086, 0x0C0B);
+ b43_phy_write(dev, 0x0085, 0x0A09);
+ b43_phy_write(dev, 0x0084, 0x0808);
+ b43_phy_write(dev, 0x0083, 0x0808);
+ b43_phy_write(dev, 0x0082, 0x0604);
+ b43_phy_write(dev, 0x0081, 0x0302);
+ b43_phy_write(dev, 0x0080, 0x0100);
+ }
+ break;
+ }
+ case B43_PHYTYPE_G:
+ if (!phy->gmode ||
+ !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+ tmp16 = b43_nrssi_hw_read(dev, 0x20);
+ if (tmp16 >= 0x20)
+ tmp16 -= 0x40;
+ if (tmp16 < 3) {
+ b43_phy_write(dev, 0x048A,
+ (b43_phy_read(dev, 0x048A)
+ & 0xF000) | 0x09EB);
+ } else {
+ b43_phy_write(dev, 0x048A,
+ (b43_phy_read(dev, 0x048A)
+ & 0xF000) | 0x0AED);
+ }
+ } else {
+ if (phy->interfmode == B43_INTERFMODE_NONWLAN) {
+ a = 0xE;
+ b = 0xA;
+ } else if (!phy->aci_wlan_automatic && phy->aci_enable) {
+ a = 0x13;
+ b = 0x12;
+ } else {
+ a = 0xE;
+ b = 0x11;
+ }
+
+ a = a * (phy->nrssi[1] - phy->nrssi[0]);
+ a += (phy->nrssi[0] << 6);
+ if (a < 32)
+ a += 31;
+ else
+ a += 32;
+ a = a >> 6;
+ a = limit_value(a, -31, 31);
+
+ b = b * (phy->nrssi[1] - phy->nrssi[0]);
+ b += (phy->nrssi[0] << 6);
+ if (b < 32)
+ b += 31;
+ else
+ b += 32;
+ b = b >> 6;
+ b = limit_value(b, -31, 31);
+
+ tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
+ tmp_u16 |= ((u32) b & 0x0000003F);
+ tmp_u16 |= (((u32) a & 0x0000003F) << 6);
+ b43_phy_write(dev, 0x048A, tmp_u16);
+ }
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 * _stackptr, size_t * stackidx,
+ u8 id, u16 offset, u16 value)
+{
+ u32 *stackptr = &(_stackptr[*stackidx]);
+
+ B43_WARN_ON(offset & 0xF000);
+ B43_WARN_ON(id & 0xF0);
+ *stackptr = offset;
+ *stackptr |= ((u32) id) << 12;
+ *stackptr |= ((u32) value) << 16;
+ (*stackidx)++;
+ B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
+}
+
+static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
+{
+ size_t i;
+
+ B43_WARN_ON(offset & 0xF000);
+ B43_WARN_ON(id & 0xF0);
+ for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
+ if ((*stackptr & 0x00000FFF) != offset)
+ continue;
+ if (((*stackptr & 0x0000F000) >> 12) != id)
+ continue;
+ return ((*stackptr & 0xFFFF0000) >> 16);
+ }
+ B43_WARN_ON(1);
+
+ return 0;
+}
+
+#define phy_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x1, (offset), \
+ b43_phy_read(dev, (offset))); \
+ } while (0)
+#define phy_stackrestore(offset) \
+ do { \
+ b43_phy_write(dev, (offset), \
+ _stack_restore(stack, 0x1, \
+ (offset))); \
+ } while (0)
+#define radio_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x2, (offset), \
+ b43_radio_read16(dev, (offset))); \
+ } while (0)
+#define radio_stackrestore(offset) \
+ do { \
+ b43_radio_write16(dev, (offset), \
+ _stack_restore(stack, 0x2, \
+ (offset))); \
+ } while (0)
+#define ofdmtab_stacksave(table, offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x3, (offset)|(table), \
+ b43_ofdmtab_read16(dev, (table), (offset))); \
+ } while (0)
+#define ofdmtab_stackrestore(table, offset) \
+ do { \
+ b43_ofdmtab_write16(dev, (table), (offset), \
+ _stack_restore(stack, 0x3, \
+ (offset)|(table))); \
+ } while (0)
+
+static void
+b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp, flipped;
+ size_t stackidx = 0;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43_phy_write(dev, 0x042B,
+ b43_phy_read(dev, 0x042B) | 0x0800);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev,
+ B43_PHY_G_CRS) & ~0x4000);
+ break;
+ }
+ radio_stacksave(0x0078);
+ tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
+ flipped = flip_4bit(tmp);
+ if (flipped < 10 && flipped >= 8)
+ flipped = 7;
+ else if (flipped >= 10)
+ flipped -= 3;
+ flipped = flip_4bit(flipped);
+ flipped = (flipped << 1) | 0x0020;
+ b43_radio_write16(dev, 0x0078, flipped);
+
+ b43_calc_nrssi_threshold(dev);
+
+ phy_stacksave(0x0406);
+ b43_phy_write(dev, 0x0406, 0x7E28);
+
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev,
+ B43_PHY_RADIO_BITFIELD) | 0x1000);
+
+ phy_stacksave(0x04A0);
+ b43_phy_write(dev, 0x04A0,
+ (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
+ phy_stacksave(0x04A1);
+ b43_phy_write(dev, 0x04A1,
+ (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
+ phy_stacksave(0x04A2);
+ b43_phy_write(dev, 0x04A2,
+ (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
+ phy_stacksave(0x04A8);
+ b43_phy_write(dev, 0x04A8,
+ (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
+ phy_stacksave(0x04AB);
+ b43_phy_write(dev, 0x04AB,
+ (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
+
+ phy_stacksave(0x04A7);
+ b43_phy_write(dev, 0x04A7, 0x0002);
+ phy_stacksave(0x04A3);
+ b43_phy_write(dev, 0x04A3, 0x287A);
+ phy_stacksave(0x04A9);
+ b43_phy_write(dev, 0x04A9, 0x2027);
+ phy_stacksave(0x0493);
+ b43_phy_write(dev, 0x0493, 0x32F5);
+ phy_stacksave(0x04AA);
+ b43_phy_write(dev, 0x04AA, 0x2027);
+ phy_stacksave(0x04AC);
+ b43_phy_write(dev, 0x04AC, 0x32F5);
+ break;
+ case B43_INTERFMODE_MANUALWLAN:
+ if (b43_phy_read(dev, 0x0033) & 0x0800)
+ break;
+
+ phy->aci_enable = 1;
+
+ phy_stacksave(B43_PHY_RADIO_BITFIELD);
+ phy_stacksave(B43_PHY_G_CRS);
+ if (phy->rev < 2) {
+ phy_stacksave(0x0406);
+ } else {
+ phy_stacksave(0x04C0);
+ phy_stacksave(0x04C1);
+ }
+ phy_stacksave(0x0033);
+ phy_stacksave(0x04A7);
+ phy_stacksave(0x04A3);
+ phy_stacksave(0x04A9);
+ phy_stacksave(0x04AA);
+ phy_stacksave(0x04AC);
+ phy_stacksave(0x0493);
+ phy_stacksave(0x04A1);
+ phy_stacksave(0x04A0);
+ phy_stacksave(0x04A2);
+ phy_stacksave(0x048A);
+ phy_stacksave(0x04A8);
+ phy_stacksave(0x04AB);
+ if (phy->rev == 2) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x0415);
+ phy_stacksave(0x0416);
+ phy_stacksave(0x0417);
+ ofdmtab_stacksave(0x1A00, 0x2);
+ ofdmtab_stacksave(0x1A00, 0x3);
+ }
+ phy_stacksave(0x042B);
+ phy_stacksave(0x048C);
+
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+ & ~0x1000);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ (b43_phy_read(dev, B43_PHY_G_CRS)
+ & 0xFFFC) | 0x0002);
+
+ b43_phy_write(dev, 0x0033, 0x0800);
+ b43_phy_write(dev, 0x04A3, 0x2027);
+ b43_phy_write(dev, 0x04A9, 0x1CA8);
+ b43_phy_write(dev, 0x0493, 0x287A);
+ b43_phy_write(dev, 0x04AA, 0x1CA8);
+ b43_phy_write(dev, 0x04AC, 0x287A);
+
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xFFC0) | 0x001A);
+ b43_phy_write(dev, 0x04A7, 0x000D);
+
+ if (phy->rev < 2) {
+ b43_phy_write(dev, 0x0406, 0xFF0D);
+ } else if (phy->rev == 2) {
+ b43_phy_write(dev, 0x04C0, 0xFFFF);
+ b43_phy_write(dev, 0x04C1, 0x00A9);
+ } else {
+ b43_phy_write(dev, 0x04C0, 0x00C1);
+ b43_phy_write(dev, 0x04C1, 0x0059);
+ }
+
+ b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+ & 0xC0FF) | 0x1800);
+ b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+ & 0xFFC0) | 0x0015);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xCFFF) | 0x1000);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xF0FF) | 0x0A00);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xCFFF) | 0x1000);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0800);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xFFCF) | 0x0010);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xFFF0) | 0x0005);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xFFCF) | 0x0010);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xFFF0) | 0x0006);
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0800);
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0500);
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x000B);
+
+ if (phy->rev >= 3) {
+ b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+ & ~0x8000);
+ b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
+ & 0x8000) | 0x36D8);
+ b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
+ & 0x8000) | 0x36D8);
+ b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
+ & 0xFE00) | 0x016D);
+ } else {
+ b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+ | 0x1000);
+ b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
+ & 0x9FFF) | 0x2000);
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
+ }
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
+ | 0x0800);
+ }
+ b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0200);
+ if (phy->rev == 2) {
+ b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
+ & 0xFF00) | 0x007F);
+ b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
+ & 0x00FF) | 0x1300);
+ } else if (phy->rev >= 6) {
+ b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
+ b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
+ b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
+ & 0x00FF);
+ }
+ b43_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+static void
+b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
+{
+ struct b43_phy *phy = &dev->phy;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43_phy_write(dev, 0x042B,
+ b43_phy_read(dev, 0x042B) & ~0x0800);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev,
+ B43_PHY_G_CRS) | 0x4000);
+ break;
+ }
+ radio_stackrestore(0x0078);
+ b43_calc_nrssi_threshold(dev);
+ phy_stackrestore(0x0406);
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
+ if (!dev->bad_frames_preempt) {
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+ & ~(1 << 11));
+ }
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x04A8);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A7);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ break;
+ case B43_INTERFMODE_MANUALWLAN:
+ if (!(b43_phy_read(dev, 0x0033) & 0x0800))
+ break;
+
+ phy->aci_enable = 0;
+
+ phy_stackrestore(B43_PHY_RADIO_BITFIELD);
+ phy_stackrestore(B43_PHY_G_CRS);
+ phy_stackrestore(0x0033);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A7);
+ if (phy->rev >= 2) {
+ phy_stackrestore(0x04C0);
+ phy_stackrestore(0x04C1);
+ } else
+ phy_stackrestore(0x0406);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A8);
+ if (phy->rev == 2) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x0415);
+ phy_stackrestore(0x0416);
+ phy_stackrestore(0x0417);
+ ofdmtab_stackrestore(0x1A00, 0x2);
+ ofdmtab_stackrestore(0x1A00, 0x3);
+ }
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x048A);
+ phy_stackrestore(0x042B);
+ phy_stackrestore(0x048C);
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
+ b43_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ofdmtab_stacksave
+#undef ofdmtab_stackrestore
+
+int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode)
+{
+ struct b43_phy *phy = &dev->phy;
+ int currentmode;
+
+ if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode))
+ return -ENODEV;
+
+ phy->aci_wlan_automatic = 0;
+ switch (mode) {
+ case B43_INTERFMODE_AUTOWLAN:
+ phy->aci_wlan_automatic = 1;
+ if (phy->aci_enable)
+ mode = B43_INTERFMODE_MANUALWLAN;
+ else
+ mode = B43_INTERFMODE_NONE;
+ break;
+ case B43_INTERFMODE_NONE:
+ case B43_INTERFMODE_NONWLAN:
+ case B43_INTERFMODE_MANUALWLAN:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ currentmode = phy->interfmode;
+ if (currentmode == mode)
+ return 0;
+ if (currentmode != B43_INTERFMODE_NONE)
+ b43_radio_interference_mitigation_disable(dev, currentmode);
+
+ if (mode == B43_INTERFMODE_NONE) {
+ phy->aci_enable = 0;
+ phy->aci_hw_rssi = 0;
+ } else
+ b43_radio_interference_mitigation_enable(dev, mode);
+ phy->interfmode = mode;
+
+ return 0;
+}
+
+static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
+{
+ u16 reg, index, ret;
+
+ static const u8 rcc_table[] = {
+ 0x02, 0x03, 0x01, 0x0F,
+ 0x06, 0x07, 0x05, 0x0F,
+ 0x0A, 0x0B, 0x09, 0x0F,
+ 0x0E, 0x0F, 0x0D, 0x0F,
+ };
+
+ reg = b43_radio_read16(dev, 0x60);
+ index = (reg & 0x001E) >> 1;
+ ret = rcc_table[index] << 1;
+ ret |= (reg & 0x0001);
+ ret |= 0x0020;
+
+ return ret;
+}
+
+#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 radio2050_rfover_val(struct b43_wldev *dev,
+ u16 phy_register, unsigned int lpd)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+
+ if (!phy->gmode)
+ return 0;
+
+ if (has_loopback_gain(phy)) {
+ int max_lb_gain = phy->max_lb_gain;
+ u16 extlna;
+ u16 i;
+
+ if (phy->radio_rev == 8)
+ max_lb_gain += 0x3E;
+ else
+ max_lb_gain += 0x26;
+ if (max_lb_gain >= 0x46) {
+ extlna = 0x3000;
+ max_lb_gain -= 0x46;
+ } else if (max_lb_gain >= 0x3A) {
+ extlna = 0x1000;
+ max_lb_gain -= 0x3A;
+ } else if (max_lb_gain >= 0x2E) {
+ extlna = 0x2000;
+ max_lb_gain -= 0x2E;
+ } else {
+ extlna = 0;
+ max_lb_gain -= 0x10;
+ }
+
+ for (i = 0; i < 16; i++) {
+ max_lb_gain -= (i * 6);
+ if (max_lb_gain < 6)
+ break;
+ }
+
+ if ((phy->rev < 7) ||
+ !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x1B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ extlna |= (i << 8);
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0F92;
+ case LPD(0, 0, 1):
+ case LPD(1, 0, 1):
+ return (0x0092 | extlna);
+ case LPD(1, 0, 0):
+ return (0x0093 | extlna);
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ } else {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x9B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ if (extlna)
+ extlna |= 0x8000;
+ extlna |= (i << 8);
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8F92;
+ case LPD(0, 0, 1):
+ return (0x8092 | extlna);
+ case LPD(1, 0, 1):
+ return (0x2092 | extlna);
+ case LPD(1, 0, 0):
+ return (0x2093 | extlna);
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ }
+ } else {
+ if ((phy->rev < 7) ||
+ !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x1B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0FB2;
+ case LPD(0, 0, 1):
+ return 0x00B2;
+ case LPD(1, 0, 1):
+ return 0x30B2;
+ case LPD(1, 0, 0):
+ return 0x30B3;
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ } else {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x9B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8FB2;
+ case LPD(0, 0, 1):
+ return 0x80B2;
+ case LPD(1, 0, 1):
+ return 0x20B2;
+ case LPD(1, 0, 0):
+ return 0x20B3;
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ }
+ }
+ return 0;
+}
+
+struct init2050_saved_values {
+ /* Core registers */
+ u16 reg_3EC;
+ u16 reg_3E6;
+ u16 reg_3F4;
+ /* Radio registers */
+ u16 radio_43;
+ u16 radio_51;
+ u16 radio_52;
+ /* PHY registers */
+ u16 phy_pgactl;
+ u16 phy_base_5A;
+ u16 phy_base_59;
+ u16 phy_base_58;
+ u16 phy_base_30;
+ u16 phy_rfover;
+ u16 phy_rfoverval;
+ u16 phy_analogover;
+ u16 phy_analogoverval;
+ u16 phy_crs0;
+ u16 phy_classctl;
+ u16 phy_lo_mask;
+ u16 phy_lo_ctl;
+ u16 phy_syncctl;
+};
+
+u16 b43_radio_init2050(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct init2050_saved_values sav;
+ u16 rcc;
+ u16 radio78;
+ u16 ret;
+ u16 i, j;
+ u32 tmp1 = 0, tmp2 = 0;
+
+ memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */
+
+ sav.radio_43 = b43_radio_read16(dev, 0x43);
+ sav.radio_51 = b43_radio_read16(dev, 0x51);
+ sav.radio_52 = b43_radio_read16(dev, 0x52);
+ sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+ sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
+ sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
+ sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+
+ if (phy->type == B43_PHYTYPE_B) {
+ sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+ sav.reg_3EC = b43_read16(dev, 0x3EC);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+ b43_write16(dev, 0x3EC, 0x3F3F);
+ } else if (phy->gmode || phy->rev >= 2) {
+ sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+ sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+ sav.phy_analogoverval =
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+ sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+ sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER)
+ | 0x0003);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+ & 0xFFFC);
+ b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+ & 0x7FFF);
+ b43_phy_write(dev, B43_PHY_CLASSCTL,
+ b43_phy_read(dev, B43_PHY_CLASSCTL)
+ & 0xFFFC);
+ if (has_loopback_gain(phy)) {
+ sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+ sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
+
+ if (phy->rev >= 3)
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+ else
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+ b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+ }
+
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+ LPD(0, 1, 1)));
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
+ }
+ b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
+
+ sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+ b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
+ & 0xFF7F);
+ sav.reg_3E6 = b43_read16(dev, 0x3E6);
+ sav.reg_3F4 = b43_read16(dev, 0x3F4);
+
+ if (phy->analog == 0) {
+ b43_write16(dev, 0x03E6, 0x0122);
+ } else {
+ if (phy->analog >= 2) {
+ b43_phy_write(dev, B43_PHY_BASE(0x03),
+ (b43_phy_read(dev, B43_PHY_BASE(0x03))
+ & 0xFFBF) | 0x40);
+ }
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
+ }
+
+ rcc = b43_radio_core_calibration_value(dev);
+
+ if (phy->type == B43_PHYTYPE_B)
+ b43_radio_write16(dev, 0x78, 0x26);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+ LPD(0, 1, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+ LPD(0, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
+ b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
+ | 0x0004);
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x43, 0x1F);
+ } else {
+ b43_radio_write16(dev, 0x52, 0);
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | 0x0009);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+
+ for (i = 0; i < 16; i++) {
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 0)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+ udelay(20);
+ tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ }
+ udelay(10);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ tmp1++;
+ tmp1 >>= 9;
+
+ for (i = 0; i < 16; i++) {
+ radio78 = ((flip_4bit(i) << 1) | 0x20);
+ b43_radio_write16(dev, 0x78, radio78);
+ udelay(10);
+ for (j = 0; j < 16; j++) {
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 0)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+ udelay(10);
+ tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ }
+ tmp2++;
+ tmp2 >>= 8;
+ if (tmp1 < tmp2)
+ break;
+ }
+
+ /* Restore the registers */
+ b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
+ b43_radio_write16(dev, 0x51, sav.radio_51);
+ b43_radio_write16(dev, 0x52, sav.radio_52);
+ b43_radio_write16(dev, 0x43, sav.radio_43);
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+ b43_write16(dev, 0x3E6, sav.reg_3E6);
+ if (phy->analog != 0)
+ b43_write16(dev, 0x3F4, sav.reg_3F4);
+ b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
+ b43_synth_pu_workaround(dev, phy->channel);
+ if (phy->type == B43_PHYTYPE_B) {
+ b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+ b43_write16(dev, 0x3EC, sav.reg_3EC);
+ } else if (phy->gmode) {
+ b43_write16(dev, B43_MMIO_PHY_RADIO,
+ b43_read16(dev, B43_MMIO_PHY_RADIO)
+ & 0x7FFF);
+ b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ sav.phy_analogoverval);
+ b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
+ b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
+ if (has_loopback_gain(phy)) {
+ b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
+ b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
+ }
+ }
+ if (i > 15)
+ ret = radio78;
+ else
+ ret = rcc;
+
+ return ret;
+}
+
+void b43_radio_init2060(struct b43_wldev *dev)
+{
+ int err;
+
+ b43_radio_write16(dev, 0x0004, 0x00C0);
+ b43_radio_write16(dev, 0x0005, 0x0008);
+ b43_radio_write16(dev, 0x0009, 0x0040);
+ b43_radio_write16(dev, 0x0005, 0x00AA);
+ b43_radio_write16(dev, 0x0032, 0x008F);
+ b43_radio_write16(dev, 0x0006, 0x008F);
+ b43_radio_write16(dev, 0x0034, 0x008F);
+ b43_radio_write16(dev, 0x002C, 0x0007);
+ b43_radio_write16(dev, 0x0082, 0x0080);
+ b43_radio_write16(dev, 0x0080, 0x0000);
+ b43_radio_write16(dev, 0x003F, 0x00DA);
+ b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+ msleep(1); /* delay 400usec */
+
+ b43_radio_write16(dev, 0x0081,
+ (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
+ msleep(1); /* delay 400usec */
+
+ b43_radio_write16(dev, 0x0005,
+ (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
+ b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
+ b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
+ b43_radio_write16(dev, 0x0081,
+ (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
+ b43_radio_write16(dev, 0x0005,
+ (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
+ b43_phy_write(dev, 0x0063, 0xDDC6);
+ b43_phy_write(dev, 0x0069, 0x07BE);
+ b43_phy_write(dev, 0x006A, 0x0000);
+
+ err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0);
+ B43_WARN_ON(err);
+
+ msleep(1);
+}
+
+static inline u16 freq_r3A_value(u16 frequency)
+{
+ u16 value;
+
+ if (frequency < 5091)
+ value = 0x0040;
+ else if (frequency < 5321)
+ value = 0x0000;
+ else if (frequency < 5806)
+ value = 0x0080;
+ else
+ value = 0x0040;
+
+ return value;
+}
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev)
+{
+ static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+ static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+ u16 tmp = b43_radio_read16(dev, 0x001E);
+ int i, j;
+
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 5; j++) {
+ if (tmp == (data_high[i] << 4 | data_low[j])) {
+ b43_phy_write(dev, 0x0069,
+ (i - j) << 8 | 0x00C0);
+ return;
+ }
+ }
+ }
+}
+
+int b43_radio_selectchannel(struct b43_wldev *dev,
+ u8 channel, int synthetic_pu_workaround)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 r8, tmp;
+ u16 freq;
+ u16 channelcookie;
+
+ if (channel == 0xFF) {
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ channel = B43_DEFAULT_CHANNEL_A;
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ channel = B43_DEFAULT_CHANNEL_BG;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+
+ /* First we set the channel radio code to prevent the
+ * firmware from sending ghost packets.
+ */
+ channelcookie = channel;
+ if (phy->type == B43_PHYTYPE_A)
+ channelcookie |= 0x100;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
+
+ if (phy->type == B43_PHYTYPE_A) {
+ if (channel > 200)
+ return -EINVAL;
+ freq = channel2freq_a(channel);
+
+ r8 = b43_radio_read16(dev, 0x0008);
+ b43_write16(dev, 0x03F0, freq);
+ b43_radio_write16(dev, 0x0008, r8);
+
+ //TODO: write max channel TX power? to Radio 0x2D
+ tmp = b43_radio_read16(dev, 0x002E);
+ tmp &= 0x0080;
+ //TODO: OR tmp with the Power out estimation for this channel?
+ b43_radio_write16(dev, 0x002E, tmp);
+
+ if (freq >= 4920 && freq <= 5500) {
+ /*
+ * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
+ * = (freq * 0.025862069
+ */
+ r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
+ }
+ b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
+ b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
+ b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
+ b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
+ & 0x000F) | (r8 << 4));
+ b43_radio_write16(dev, 0x002A, (r8 << 4));
+ b43_radio_write16(dev, 0x002B, (r8 << 4));
+ b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
+ & 0x00F0) | (r8 << 4));
+ b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
+ & 0xFF0F) | 0x00B0);
+ b43_radio_write16(dev, 0x0035, 0x00AA);
+ b43_radio_write16(dev, 0x0036, 0x0085);
+ b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
+ & 0xFF20) |
+ freq_r3A_value(freq));
+ b43_radio_write16(dev, 0x003D,
+ b43_radio_read16(dev, 0x003D) & 0x00FF);
+ b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
+ & 0xFF7F) | 0x0080);
+ b43_radio_write16(dev, 0x0035,
+ b43_radio_read16(dev, 0x0035) & 0xFFEF);
+ b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
+ & 0xFFEF) | 0x0010);
+ b43_radio_set_tx_iq(dev);
+ //TODO: TSSI2dbm workaround
+ b43_phy_xmitpower(dev); //FIXME correct?
+ } else {
+ if ((channel < 1) || (channel > 14))
+ return -EINVAL;
+
+ if (synthetic_pu_workaround)
+ b43_synth_pu_workaround(dev, channel);
+
+ b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+
+ if (channel == 14) {
+ if (dev->dev->bus->sprom.r1.country_code ==
+ SSB_SPROM1CCODE_JAPAN)
+ b43_hf_write(dev,
+ b43_hf_read(dev) & ~B43_HF_ACPR);
+ else
+ b43_hf_write(dev,
+ b43_hf_read(dev) | B43_HF_ACPR);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+ | (1 << 11));
+ } else {
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+ & 0xF7BF);
+ }
+ }
+
+ phy->channel = channel;
+ /* Wait for the radio to tune to the channel and stabilize. */
+ msleep(8);
+
+ return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 b43_get_txgain_base_band(u16 txpower)
+{
+ u16 ret;
+
+ B43_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = 2;
+ else if (txpower >= 49)
+ ret = 4;
+ else if (txpower >= 44)
+ ret = 5;
+ else
+ ret = 6;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 b43_get_txgain_freq_power_amp(u16 txpower)
+{
+ u16 ret;
+
+ B43_WARN_ON(txpower > 63);
+
+ if (txpower >= 32)
+ ret = 0;
+ else if (txpower >= 25)
+ ret = 1;
+ else if (txpower >= 20)
+ ret = 2;
+ else if (txpower >= 12)
+ ret = 3;
+ else
+ ret = 4;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 b43_get_txgain_dac(u16 txpower)
+{
+ u16 ret;
+
+ B43_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = txpower - 53;
+ else if (txpower >= 49)
+ ret = txpower - 42;
+ else if (txpower >= 44)
+ ret = txpower - 37;
+ else if (txpower >= 32)
+ ret = txpower - 32;
+ else if (txpower >= 25)
+ ret = txpower - 20;
+ else if (txpower >= 20)
+ ret = txpower - 13;
+ else if (txpower >= 12)
+ ret = txpower - 8;
+ else
+ ret = txpower;
+
+ return ret;
+}
+
+static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 pamp, base, dac, t;
+
+ txpower = limit_value(txpower, 0, 63);
+
+ pamp = b43_get_txgain_freq_power_amp(txpower);
+ pamp <<= 5;
+ pamp &= 0x00E0;
+ b43_phy_write(dev, 0x0019, pamp);
+
+ base = b43_get_txgain_base_band(txpower);
+ base &= 0x000F;
+ b43_phy_write(dev, 0x0017, base | 0x0020);
+
+ t = b43_ofdmtab_read16(dev, 0x3000, 1);
+ t &= 0x0007;
+
+ dac = b43_get_txgain_dac(txpower);
+ dac <<= 3;
+ dac |= t;
+
+ b43_ofdmtab_write16(dev, 0x3000, 1, dac);
+
+ phy->txpwr_offset = txpower;
+
+ //TODO: FuncPlaceholder (Adjust BB loft cancel)
+}
+
+void b43_radio_turn_on(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int err;
+ u8 channel;
+
+ might_sleep();
+
+ if (phy->radio_on)
+ return;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ b43_radio_write16(dev, 0x0004, 0x00C0);
+ b43_radio_write16(dev, 0x0005, 0x0008);
+ b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
+ b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
+ b43_radio_init2060(dev);
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ b43_phy_write(dev, 0x0015, 0x8000);
+ b43_phy_write(dev, 0x0015, 0xCC00);
+ b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
+ if (phy->radio_off_context.valid) {
+ /* Restore the RFover values. */
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ phy->radio_off_context.rfover);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ phy->radio_off_context.rfoverval);
+ phy->radio_off_context.valid = 0;
+ }
+ channel = phy->channel;
+ err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1);
+ err |= b43_radio_selectchannel(dev, channel, 0);
+ B43_WARN_ON(err);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ phy->radio_on = 1;
+}
+
+void b43_radio_turn_off(struct b43_wldev *dev, bool force)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!phy->radio_on && !force)
+ return;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ b43_radio_write16(dev, 0x0004, 0x00FF);
+ b43_radio_write16(dev, 0x0005, 0x00FB);
+ b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
+ b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
+ }
+ if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+ u16 rfover, rfoverval;
+
+ rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+ rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ if (!force) {
+ phy->radio_off_context.rfover = rfover;
+ phy->radio_off_context.rfoverval = rfoverval;
+ phy->radio_off_context.valid = 1;
+ }
+ b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
+ } else
+ b43_phy_write(dev, 0x0015, 0xAA00);
+ phy->radio_on = 0;
+}
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
new file mode 100644
index 000000000000..c64d74504fc0
--- /dev/null
+++ b/drivers/net/wireless/b43/phy.h
@@ -0,0 +1,297 @@
+#ifndef B43_PHY_H_
+#define B43_PHY_H_
+
+#include <linux/types.h>
+
+struct b43_wldev;
+struct b43_phy;
+
+/*** PHY Registers ***/
+
+/* Routing */
+#define B43_PHYROUTE_OFDM_GPHY 0x400
+#define B43_PHYROUTE_EXT_GPHY 0x800
+
+/* Base registers. */
+#define B43_PHY_BASE(reg) (reg)
+/* OFDM (A) registers of a G-PHY */
+#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers */
+#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
+
+/* OFDM (A) PHY Registers */
+#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */
+#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */
+#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
+#define B43_PHY_BBANDCFG_RXANT_SHIFT 7
+#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */
+#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */
+#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */
+#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */
+#define B43_PHY_CRS0 B43_PHY_OFDM(0x29)
+#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */
+#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
+#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
+#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */
+#define B43_PHY_LMS B43_PHY_OFDM(0x55)
+#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */
+#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */
+#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */
+#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */
+#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
+#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
+#define B43_PHY_OTABLENR_SHIFT 10
+#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */
+#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */
+#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */
+#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */
+#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */
+#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
+#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */
+#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */
+#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0)
+#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1)
+#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2)
+#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3)
+#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4)
+#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */
+#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9)
+#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA)
+#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB)
+#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */
+#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */
+#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
+#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
+#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */
+#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */
+#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */
+
+/* CCK (B) PHY Registers */
+#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */
+#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
+#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
+#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
+#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */
+#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */
+#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35)
+#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */
+#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */
+
+/* Extended G-PHY Registers */
+#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
+#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
+#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
+#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
+#define B43_PHY_GTABNR_SHIFT 10
+#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
+#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
+#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
+#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
+#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
+#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
+#define B43_PHY_RFOVERVAL_LNA 0x7000
+#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
+#define B43_PHY_RFOVERVAL_PGA 0x0F00
+#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
+#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
+#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
+#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
+#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
+#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
+#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
+#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
+
+/*** OFDM table numbers ***/
+#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
+#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename
+#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4)
+#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0)
+#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3)
+#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0)
+#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0)
+#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0)
+#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0)
+#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0)
+#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0)
+#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7)
+#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12)
+#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13)
+//TODO
+#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12)
+#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0)
+//TODO
+#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0)
+#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename
+#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1)
+#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4)
+#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0)
+#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0)
+#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0)
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+ u16 offset, u16 value);
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+ u16 offset, u32 value);
+
+/*** G-PHY table numbers */
+#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
+#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
+#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
+#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement
+
+#define B43_DEFAULT_CHANNEL_A 36
+#define B43_DEFAULT_CHANNEL_BG 6
+
+enum {
+ B43_ANTENNA0, /* Antenna 0 */
+ B43_ANTENNA1, /* Antenna 0 */
+ B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
+ B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
+
+ B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
+ B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
+};
+
+enum {
+ B43_INTERFMODE_NONE,
+ B43_INTERFMODE_NONWLAN,
+ B43_INTERFMODE_MANUALWLAN,
+ B43_INTERFMODE_AUTOWLAN,
+};
+
+/* Masks for the different PHY versioning registers. */
+#define B43_PHYVER_ANALOG 0xF000
+#define B43_PHYVER_ANALOG_SHIFT 12
+#define B43_PHYVER_TYPE 0x0F00
+#define B43_PHYVER_TYPE_SHIFT 8
+#define B43_PHYVER_VERSION 0x00FF
+
+void b43_raw_phy_lock(struct b43_wldev *dev);
+#define b43_phy_lock(dev, flags) \
+ do { \
+ local_irq_save(flags); \
+ b43_raw_phy_lock(dev); \
+ } while (0)
+void b43_raw_phy_unlock(struct b43_wldev *dev);
+#define b43_phy_unlock(dev, flags) \
+ do { \
+ b43_raw_phy_unlock(dev); \
+ local_irq_restore(flags); \
+ } while (0)
+
+u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
+void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
+
+int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
+
+void b43_phy_early_init(struct b43_wldev *dev);
+int b43_phy_init(struct b43_wldev *dev);
+
+void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
+
+void b43_phy_xmitpower(struct b43_wldev *dev);
+void b43_gphy_dc_lt_init(struct b43_wldev *dev);
+
+/* Returns the boolean whether the board has HardwarePowerControl */
+bool b43_has_hardware_pctl(struct b43_phy *phy);
+/* Returns the boolean whether "TX Magnification" is enabled. */
+#define has_tx_magnification(phy) \
+ (((phy)->rev >= 2) && \
+ ((phy)->radio_ver == 0x2050) && \
+ ((phy)->radio_rev == 8))
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+ (((phy)->rev > 1) || ((phy)->gmode))
+
+/* Radio Attenuation (RF Attenuation) */
+struct b43_rfatt {
+ u8 att; /* Attenuation value */
+ bool with_padmix; /* Flag, PAD Mixer enabled. */
+};
+struct b43_rfatt_list {
+ /* Attenuation values list */
+ const struct b43_rfatt *list;
+ u8 len;
+ /* Minimum/Maximum attenuation values */
+ u8 min_val;
+ u8 max_val;
+};
+
+/* Baseband Attenuation */
+struct b43_bbatt {
+ u8 att; /* Attenuation value */
+};
+struct b43_bbatt_list {
+ /* Attenuation values list */
+ const struct b43_bbatt *list;
+ u8 len;
+ /* Minimum/Maximum attenuation values */
+ u8 min_val;
+ u8 max_val;
+};
+
+/* tx_control bits. */
+#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
+#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
+#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
+
+/* Write BasebandAttenuation value to the device. */
+void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
+ u16 baseband_attenuation);
+
+extern const u8 b43_radio_channel_codes_bg[];
+
+void b43_radio_lock(struct b43_wldev *dev);
+void b43_radio_unlock(struct b43_wldev *dev);
+
+u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
+void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
+
+u16 b43_radio_init2050(struct b43_wldev *dev);
+void b43_radio_init2060(struct b43_wldev *dev);
+
+void b43_radio_turn_on(struct b43_wldev *dev);
+void b43_radio_turn_off(struct b43_wldev *dev, bool force);
+
+int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
+ int synthetic_pu_workaround);
+
+u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
+u8 b43_radio_aci_scan(struct b43_wldev *dev);
+
+int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev);
+void b43_calc_nrssi_threshold(struct b43_wldev *dev);
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
+void b43_nrssi_mem_update(struct b43_wldev *dev);
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev);
+u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
+
+void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+ int *_bbatt, int *_rfatt);
+
+void b43_set_txpower_g(struct b43_wldev *dev,
+ const struct b43_bbatt *bbatt,
+ const struct b43_rfatt *rfatt, u8 tx_control);
+
+#endif /* B43_PHY_H_ */
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
new file mode 100644
index 000000000000..67752a28eb9c
--- /dev/null
+++ b/drivers/net/wireless/b43/pio.c
@@ -0,0 +1,652 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ PIO Transmission
+
+ Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "pio.h"
+#include "main.h"
+#include "xmit.h"
+
+#include <linux/delay.h>
+
+static void tx_start(struct b43_pioqueue *queue)
+{
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct b43_pioqueue *queue, u8 octet)
+{
+ if (queue->need_workarounds) {
+ b43_pio_write(queue, B43_PIO_TXDATA, octet);
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
+ } else {
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
+ b43_pio_write(queue, B43_PIO_TXDATA, octet);
+ }
+}
+
+static u16 tx_get_next_word(const u8 * txhdr,
+ const u8 * packet,
+ size_t txhdr_size, unsigned int *pos)
+{
+ const u8 *source;
+ unsigned int i = *pos;
+ u16 ret;
+
+ if (i < txhdr_size) {
+ source = txhdr;
+ } else {
+ source = packet;
+ i -= txhdr_size;
+ }
+ ret = le16_to_cpu(*((__le16 *)(source + i)));
+ *pos += 2;
+
+ return ret;
+}
+
+static void tx_data(struct b43_pioqueue *queue,
+ u8 * txhdr, const u8 * packet, unsigned int octets)
+{
+ u16 data;
+ unsigned int i = 0;
+
+ if (queue->need_workarounds) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43_txhdr_fw4), &i);
+ b43_pio_write(queue, B43_PIO_TXDATA, data);
+ }
+ b43_pio_write(queue, B43_PIO_TXCTL,
+ B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
+ while (i < octets - 1) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43_txhdr_fw4), &i);
+ b43_pio_write(queue, B43_PIO_TXDATA, data);
+ }
+ if (octets % 2)
+ tx_octet(queue,
+ packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
+}
+
+static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
+{
+ if (queue->need_workarounds) {
+ b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
+ b43_pio_write(queue, B43_PIO_TXCTL,
+ B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
+ } else {
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
+ }
+}
+
+static u16 generate_cookie(struct b43_pioqueue *queue,
+ struct b43_pio_txpacket *packet)
+{
+ u16 cookie = 0x0000;
+ u16 packetindex;
+
+ /* We use the upper 4 bits for the PIO
+ * controller ID and the lower 12 bits
+ * for the packet index (in the cache).
+ */
+ switch (queue->mmio_base) {
+ case B43_MMIO_PIO1_BASE:
+ break;
+ case B43_MMIO_PIO2_BASE:
+ cookie = 0x1000;
+ break;
+ case B43_MMIO_PIO3_BASE:
+ cookie = 0x2000;
+ break;
+ case B43_MMIO_PIO4_BASE:
+ cookie = 0x3000;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ packetindex = packet->index;
+ B43_WARN_ON(packetindex & ~0x0FFF);
+ cookie |= (u16) packetindex;
+
+ return cookie;
+}
+
+static
+struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
+ u16 cookie, struct b43_pio_txpacket **packet)
+{
+ struct b43_pio *pio = &dev->pio;
+ struct b43_pioqueue *queue = NULL;
+ int packetindex;
+
+ switch (cookie & 0xF000) {
+ case 0x0000:
+ queue = pio->queue0;
+ break;
+ case 0x1000:
+ queue = pio->queue1;
+ break;
+ case 0x2000:
+ queue = pio->queue2;
+ break;
+ case 0x3000:
+ queue = pio->queue3;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ packetindex = (cookie & 0x0FFF);
+ B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
+ *packet = &(queue->tx_packets_cache[packetindex]);
+
+ return queue;
+}
+
+union txhdr_union {
+ struct b43_txhdr_fw4 txhdr_fw4;
+};
+
+static void pio_tx_write_fragment(struct b43_pioqueue *queue,
+ struct sk_buff *skb,
+ struct b43_pio_txpacket *packet,
+ size_t txhdr_size)
+{
+ union txhdr_union txhdr_data;
+ u8 *txhdr = NULL;
+ unsigned int octets;
+
+ txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
+
+ B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+ b43_generate_txhdr(queue->dev,
+ txhdr, skb->data, skb->len,
+ &packet->txstat.control,
+ generate_cookie(queue, packet));
+
+ tx_start(queue);
+ octets = skb->len + txhdr_size;
+ if (queue->need_workarounds)
+ octets--;
+ tx_data(queue, txhdr, (u8 *) skb->data, octets);
+ tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct b43_pio_txpacket *packet)
+{
+ struct b43_pioqueue *queue = packet->queue;
+
+ if (packet->skb)
+ dev_kfree_skb_any(packet->skb);
+ list_move(&packet->list, &queue->txfree);
+ queue->nr_txfree++;
+}
+
+static int pio_tx_packet(struct b43_pio_txpacket *packet)
+{
+ struct b43_pioqueue *queue = packet->queue;
+ struct sk_buff *skb = packet->skb;
+ u16 octets;
+
+ octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
+ if (queue->tx_devq_size < octets) {
+ b43warn(queue->dev->wl, "PIO queue too small. "
+ "Dropping packet.\n");
+ /* Drop it silently (return success) */
+ free_txpacket(packet);
+ return 0;
+ }
+ B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
+ B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
+ /* Check if there is sufficient free space on the device
+ * TX queue. If not, return and let the TX tasklet
+ * retry later.
+ */
+ if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
+ return -EBUSY;
+ if (queue->tx_devq_used + octets > queue->tx_devq_size)
+ return -EBUSY;
+ /* Now poke the device. */
+ pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
+
+ /* Account for the packet size.
+ * (We must not overflow the device TX queue)
+ */
+ queue->tx_devq_packets++;
+ queue->tx_devq_used += octets;
+
+ /* Transmission started, everything ok, move the
+ * packet to the txrunning list.
+ */
+ list_move_tail(&packet->list, &queue->txrunning);
+
+ return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+ struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
+ struct b43_wldev *dev = queue->dev;
+ unsigned long flags;
+ struct b43_pio_txpacket *packet, *tmp_packet;
+ int err;
+ u16 txctl;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ if (queue->tx_frozen)
+ goto out_unlock;
+ txctl = b43_pio_read(queue, B43_PIO_TXCTL);
+ if (txctl & B43_PIO_TXCTL_SUSPEND)
+ goto out_unlock;
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+ /* Try to transmit the packet. This can fail, if
+ * the device queue is full. In case of failure, the
+ * packet is left in the txqueue.
+ * If transmission succeed, the packet is moved to txrunning.
+ * If it is impossible to transmit the packet, it
+ * is dropped.
+ */
+ err = pio_tx_packet(packet);
+ if (err)
+ break;
+ }
+ out_unlock:
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void setup_txqueues(struct b43_pioqueue *queue)
+{
+ struct b43_pio_txpacket *packet;
+ int i;
+
+ queue->nr_txfree = B43_PIO_MAXTXPACKETS;
+ for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
+ packet = &(queue->tx_packets_cache[i]);
+
+ packet->queue = queue;
+ INIT_LIST_HEAD(&packet->list);
+ packet->index = i;
+
+ list_add(&packet->list, &queue->txfree);
+ }
+}
+
+static
+struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
+ u16 pio_mmio_base)
+{
+ struct b43_pioqueue *queue;
+ u16 qsize;
+
+ queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue)
+ goto out;
+
+ queue->dev = dev;
+ queue->mmio_base = pio_mmio_base;
+ queue->need_workarounds = (dev->dev->id.revision < 3);
+
+ INIT_LIST_HEAD(&queue->txfree);
+ INIT_LIST_HEAD(&queue->txqueue);
+ INIT_LIST_HEAD(&queue->txrunning);
+ tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
+
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_BE);
+
+ qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
+ if (qsize == 0) {
+ b43err(dev->wl, "This card does not support PIO "
+ "operation mode. Please use DMA mode "
+ "(module parameter pio=0).\n");
+ goto err_freequeue;
+ }
+ if (qsize <= B43_PIO_TXQADJUST) {
+ b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
+ goto err_freequeue;
+ }
+ qsize -= B43_PIO_TXQADJUST;
+ queue->tx_devq_size = qsize;
+
+ setup_txqueues(queue);
+
+ out:
+ return queue;
+
+ err_freequeue:
+ kfree(queue);
+ queue = NULL;
+ goto out;
+}
+
+static void cancel_transfers(struct b43_pioqueue *queue)
+{
+ struct b43_pio_txpacket *packet, *tmp_packet;
+
+ tasklet_disable(&queue->txtask);
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+ free_txpacket(packet);
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+ free_txpacket(packet);
+}
+
+static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
+{
+ if (!queue)
+ return;
+
+ cancel_transfers(queue);
+ kfree(queue);
+}
+
+void b43_pio_free(struct b43_wldev *dev)
+{
+ struct b43_pio *pio;
+
+ if (!b43_using_pio(dev))
+ return;
+ pio = &dev->pio;
+
+ b43_destroy_pioqueue(pio->queue3);
+ pio->queue3 = NULL;
+ b43_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+ b43_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+ b43_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+}
+
+int b43_pio_init(struct b43_wldev *dev)
+{
+ struct b43_pio *pio = &dev->pio;
+ struct b43_pioqueue *queue;
+ int err = -ENOMEM;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
+ if (!queue)
+ goto out;
+ pio->queue0 = queue;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
+ if (!queue)
+ goto err_destroy0;
+ pio->queue1 = queue;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
+ if (!queue)
+ goto err_destroy1;
+ pio->queue2 = queue;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
+ if (!queue)
+ goto err_destroy2;
+ pio->queue3 = queue;
+
+ if (dev->dev->id.revision < 3)
+ dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
+
+ b43dbg(dev->wl, "PIO initialized\n");
+ err = 0;
+ out:
+ return err;
+
+ err_destroy2:
+ b43_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+ err_destroy1:
+ b43_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+ err_destroy0:
+ b43_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+ goto out;
+}
+
+int b43_pio_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct b43_pioqueue *queue = dev->pio.queue1;
+ struct b43_pio_txpacket *packet;
+
+ B43_WARN_ON(queue->tx_suspended);
+ B43_WARN_ON(list_empty(&queue->txfree));
+
+ packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
+ packet->skb = skb;
+
+ memset(&packet->txstat, 0, sizeof(packet->txstat));
+ memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
+
+ list_move_tail(&packet->list, &queue->txqueue);
+ queue->nr_txfree--;
+ queue->nr_tx_packets++;
+ B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
+
+ tasklet_schedule(&queue->txtask);
+
+ return 0;
+}
+
+void b43_pio_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ struct b43_pioqueue *queue;
+ struct b43_pio_txpacket *packet;
+
+ queue = parse_cookie(dev, status->cookie, &packet);
+ if (B43_WARN_ON(!queue))
+ return;
+
+ queue->tx_devq_packets--;
+ queue->tx_devq_used -=
+ (packet->skb->len + sizeof(struct b43_txhdr_fw4));
+
+ if (status->acked) {
+ packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
+ packet->txstat.excessive_retries = 1;
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ packet->txstat.retry_count = 0;
+ } else
+ packet->txstat.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
+ &(packet->txstat));
+ packet->skb = NULL;
+
+ free_txpacket(packet);
+ /* If there are packets on the txqueue, poke the tasklet
+ * to transmit them.
+ */
+ if (!list_empty(&queue->txqueue))
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43_pio_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43_pio *pio = &dev->pio;
+ struct b43_pioqueue *queue;
+ struct ieee80211_tx_queue_stats_data *data;
+
+ queue = pio->queue1;
+ data = &(stats->data[0]);
+ data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
+ data->limit = B43_PIO_MAXTXPACKETS;
+ data->count = queue->nr_tx_packets;
+}
+
+static void pio_rx_error(struct b43_pioqueue *queue,
+ int clear_buffers, const char *error)
+{
+ int i;
+
+ b43err(queue->dev->wl, "PIO RX error: %s\n", error);
+ b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
+ if (clear_buffers) {
+ B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
+ for (i = 0; i < 15; i++) {
+ /* Dummy read. */
+ b43_pio_read(queue, B43_PIO_RXDATA);
+ }
+ }
+}
+
+void b43_pio_rx(struct b43_pioqueue *queue)
+{
+ __le16 preamble[21] = { 0 };
+ struct b43_rxhdr_fw4 *rxhdr;
+ u16 tmp, len;
+ u32 macstat;
+ int i, preamble_readwords;
+ struct sk_buff *skb;
+
+ tmp = b43_pio_read(queue, B43_PIO_RXCTL);
+ if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
+ return;
+ b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
+
+ for (i = 0; i < 10; i++) {
+ tmp = b43_pio_read(queue, B43_PIO_RXCTL);
+ if (tmp & B43_PIO_RXCTL_READY)
+ goto data_ready;
+ udelay(10);
+ }
+ b43dbg(queue->dev->wl, "PIO RX timed out\n");
+ return;
+data_ready:
+
+ len = b43_pio_read(queue, B43_PIO_RXDATA);
+ if (unlikely(len > 0x700)) {
+ pio_rx_error(queue, 0, "len > 0x700");
+ return;
+ }
+ if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
+ pio_rx_error(queue, 0, "len == 0");
+ return;
+ }
+ preamble[0] = cpu_to_le16(len);
+ if (queue->mmio_base == B43_MMIO_PIO4_BASE)
+ preamble_readwords = 14 / sizeof(u16);
+ else
+ preamble_readwords = 18 / sizeof(u16);
+ for (i = 0; i < preamble_readwords; i++) {
+ tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+ preamble[i + 1] = cpu_to_le16(tmp);
+ }
+ rxhdr = (struct b43_rxhdr_fw4 *)preamble;
+ macstat = le32_to_cpu(rxhdr->mac_status);
+ if (macstat & B43_RX_MAC_FCSERR) {
+ pio_rx_error(queue,
+ (queue->mmio_base == B43_MMIO_PIO1_BASE),
+ "Frame FCS error");
+ return;
+ }
+ if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
+ /* We received an xmit status. */
+ struct b43_hwtxstatus *hw;
+
+ hw = (struct b43_hwtxstatus *)(preamble + 1);
+ b43_handle_hwtxstatus(queue->dev, hw);
+
+ return;
+ }
+
+ skb = dev_alloc_skb(len);
+ if (unlikely(!skb)) {
+ pio_rx_error(queue, 1, "OOM");
+ return;
+ }
+ skb_put(skb, len);
+ for (i = 0; i < len - 1; i += 2) {
+ tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+ *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
+ }
+ if (len % 2) {
+ tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+ skb->data[len - 1] = (tmp & 0x00FF);
+/* The specs say the following is required, but
+ * it is wrong and corrupts the PLCP. If we don't do
+ * this, the PLCP seems to be correct. So ifdef it out for now.
+ */
+#if 0
+ if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
+ skb->data[2] = (tmp & 0xFF00) >> 8;
+ else
+ skb->data[0] = (tmp & 0xFF00) >> 8;
+#endif
+ }
+ b43_rx(queue->dev, skb, rxhdr);
+}
+
+void b43_pio_tx_suspend(struct b43_pioqueue *queue)
+{
+ b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
+ b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
+ | B43_PIO_TXCTL_SUSPEND);
+}
+
+void b43_pio_tx_resume(struct b43_pioqueue *queue)
+{
+ b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
+ & ~B43_PIO_TXCTL_SUSPEND);
+ b43_power_saving_ctl_bits(queue->dev, 0);
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43_pio_freeze_txqueues(struct b43_wldev *dev)
+{
+ struct b43_pio *pio;
+
+ B43_WARN_ON(!b43_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 1;
+ pio->queue1->tx_frozen = 1;
+ pio->queue2->tx_frozen = 1;
+ pio->queue3->tx_frozen = 1;
+}
+
+void b43_pio_thaw_txqueues(struct b43_wldev *dev)
+{
+ struct b43_pio *pio;
+
+ B43_WARN_ON(!b43_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 0;
+ pio->queue1->tx_frozen = 0;
+ pio->queue2->tx_frozen = 0;
+ pio->queue3->tx_frozen = 0;
+ if (!list_empty(&pio->queue0->txqueue))
+ tasklet_schedule(&pio->queue0->txtask);
+ if (!list_empty(&pio->queue1->txqueue))
+ tasklet_schedule(&pio->queue1->txtask);
+ if (!list_empty(&pio->queue2->txqueue))
+ tasklet_schedule(&pio->queue2->txtask);
+ if (!list_empty(&pio->queue3->txqueue))
+ tasklet_schedule(&pio->queue3->txtask);
+}
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
new file mode 100644
index 000000000000..34a44c1b6314
--- /dev/null
+++ b/drivers/net/wireless/b43/pio.h
@@ -0,0 +1,152 @@
+#ifndef B43_PIO_H_
+#define B43_PIO_H_
+
+#include "b43.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#define B43_PIO_TXCTL 0x00
+#define B43_PIO_TXDATA 0x02
+#define B43_PIO_TXQBUFSIZE 0x04
+#define B43_PIO_RXCTL 0x08
+#define B43_PIO_RXDATA 0x0A
+
+#define B43_PIO_TXCTL_WRITELO (1 << 0)
+#define B43_PIO_TXCTL_WRITEHI (1 << 1)
+#define B43_PIO_TXCTL_COMPLETE (1 << 2)
+#define B43_PIO_TXCTL_INIT (1 << 3)
+#define B43_PIO_TXCTL_SUSPEND (1 << 7)
+
+#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0)
+#define B43_PIO_RXCTL_READY (1 << 1)
+
+/* PIO constants */
+#define B43_PIO_MAXTXDEVQPACKETS 31
+#define B43_PIO_TXQADJUST 80
+
+/* PIO tuning knobs */
+#define B43_PIO_MAXTXPACKETS 256
+
+#ifdef CONFIG_B43_PIO
+
+struct b43_pioqueue;
+struct b43_xmitstatus;
+
+struct b43_pio_txpacket {
+ struct b43_pioqueue *queue;
+ struct sk_buff *skb;
+ struct ieee80211_tx_status txstat;
+ struct list_head list;
+ u16 index; /* Index in the tx_packets_cache */
+};
+
+struct b43_pioqueue {
+ struct b43_wldev *dev;
+ u16 mmio_base;
+
+ bool tx_suspended;
+ bool tx_frozen;
+ bool need_workarounds; /* Workarounds needed for core.rev < 3 */
+
+ /* Adjusted size of the device internal TX buffer. */
+ u16 tx_devq_size;
+ /* Used octets of the device internal TX buffer. */
+ u16 tx_devq_used;
+ /* Used packet slots in the device internal TX buffer. */
+ u8 tx_devq_packets;
+ /* Packets from the txfree list can
+ * be taken on incoming TX requests.
+ */
+ struct list_head txfree;
+ unsigned int nr_txfree;
+ /* Packets on the txqueue are queued,
+ * but not completely written to the chip, yet.
+ */
+ struct list_head txqueue;
+ /* Packets on the txrunning queue are completely
+ * posted to the device. We are waiting for the txstatus.
+ */
+ struct list_head txrunning;
+ /* Total number or packets sent.
+ * (This counter can obviously wrap).
+ */
+ unsigned int nr_tx_packets;
+ struct tasklet_struct txtask;
+ struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
+};
+
+static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
+{
+ return b43_read16(queue->dev, queue->mmio_base + offset);
+}
+
+static inline
+ void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
+{
+ b43_write16(queue->dev, queue->mmio_base + offset, value);
+ mmiowb();
+}
+
+int b43_pio_init(struct b43_wldev *dev);
+void b43_pio_free(struct b43_wldev *dev);
+
+int b43_pio_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+void b43_pio_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+void b43_pio_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+void b43_pio_rx(struct b43_pioqueue *queue);
+
+/* Suspend TX queue in hardware. */
+void b43_pio_tx_suspend(struct b43_pioqueue *queue);
+void b43_pio_tx_resume(struct b43_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void b43_pio_freeze_txqueues(struct b43_wldev *dev);
+void b43_pio_thaw_txqueues(struct b43_wldev *dev);
+
+#else /* CONFIG_B43_PIO */
+
+static inline int b43_pio_init(struct b43_wldev *dev)
+{
+ return 0;
+}
+static inline void b43_pio_free(struct b43_wldev *dev)
+{
+}
+static inline
+ int b43_pio_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+ void b43_pio_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+}
+static inline
+ void b43_pio_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline void b43_pio_rx(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
+{
+}
+static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43_PIO */
+#endif /* B43_PIO_H_ */
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
new file mode 100644
index 000000000000..800e0a61a7f5
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -0,0 +1,184 @@
+/*
+
+ Broadcom B43 wireless driver
+ RFKILL support
+
+ Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "rfkill.h"
+#include "b43.h"
+
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
+{
+ if (dev->phy.rev >= 3) {
+ if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
+ & B43_MMIO_RADIO_HWENABLED_HI_MASK))
+ return 1;
+ } else {
+ if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
+ & B43_MMIO_RADIO_HWENABLED_LO_MASK)
+ return 1;
+ }
+ return 0;
+}
+
+/* The poll callback for the hardware button. */
+static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
+{
+ struct b43_wldev *dev = poll_dev->private;
+ struct b43_wl *wl = dev->wl;
+ bool enabled;
+
+ mutex_lock(&wl->mutex);
+ B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
+ enabled = b43_is_hw_radio_enabled(dev);
+ if (unlikely(enabled != dev->radio_hw_enable)) {
+ dev->radio_hw_enable = enabled;
+ b43info(wl, "Radio hardware status changed to %s\n",
+ enabled ? "ENABLED" : "DISABLED");
+ mutex_unlock(&wl->mutex);
+ input_report_key(poll_dev->input, KEY_WLAN, enabled);
+ } else
+ mutex_unlock(&wl->mutex);
+}
+
+/* Called when the RFKILL toggled in software.
+ * This is called without locking. */
+static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
+{
+ struct b43_wldev *dev = data;
+ struct b43_wl *wl = dev->wl;
+ int err = 0;
+
+ mutex_lock(&wl->mutex);
+ if (b43_status(dev) < B43_STAT_INITIALIZED)
+ goto out_unlock;
+
+ switch (state) {
+ case RFKILL_STATE_ON:
+ if (!dev->radio_hw_enable) {
+ /* No luck. We can't toggle the hardware RF-kill
+ * button from software. */
+ err = -EBUSY;
+ goto out_unlock;
+ }
+ if (!dev->phy.radio_on)
+ b43_radio_turn_on(dev);
+ break;
+ case RFKILL_STATE_OFF:
+ if (dev->phy.radio_on)
+ b43_radio_turn_off(dev, 0);
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+char * b43_rfkill_led_name(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+
+ if (!wl->rfkill.rfkill)
+ return NULL;
+ return rfkill_get_led_name(wl->rfkill.rfkill);
+}
+
+void b43_rfkill_init(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct b43_rfkill *rfk = &(wl->rfkill);
+ int err;
+
+ if (rfk->rfkill) {
+ err = rfkill_register(rfk->rfkill);
+ if (err) {
+ b43warn(wl, "Failed to register RF-kill button\n");
+ goto err_free_rfk;
+ }
+ }
+ if (rfk->poll_dev) {
+ err = input_register_polled_device(rfk->poll_dev);
+ if (err) {
+ b43warn(wl, "Failed to register RF-kill polldev\n");
+ goto err_free_polldev;
+ }
+ }
+
+ return;
+err_free_rfk:
+ rfkill_free(rfk->rfkill);
+ rfk->rfkill = NULL;
+err_free_polldev:
+ input_free_polled_device(rfk->poll_dev);
+ rfk->poll_dev = NULL;
+}
+
+void b43_rfkill_exit(struct b43_wldev *dev)
+{
+ struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+ if (rfk->poll_dev)
+ input_unregister_polled_device(rfk->poll_dev);
+ if (rfk->rfkill)
+ rfkill_unregister(rfk->rfkill);
+}
+
+void b43_rfkill_alloc(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct b43_rfkill *rfk = &(wl->rfkill);
+
+ snprintf(rfk->name, sizeof(rfk->name),
+ "b43-%s", wiphy_name(wl->hw->wiphy));
+
+ rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
+ if (!rfk->rfkill) {
+ b43warn(wl, "Failed to allocate RF-kill button\n");
+ return;
+ }
+ rfk->rfkill->name = rfk->name;
+ rfk->rfkill->state = RFKILL_STATE_ON;
+ rfk->rfkill->data = dev;
+ rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
+ rfk->rfkill->user_claim_unsupported = 1;
+
+ rfk->poll_dev = input_allocate_polled_device();
+ if (rfk->poll_dev) {
+ rfk->poll_dev->private = dev;
+ rfk->poll_dev->poll = b43_rfkill_poll;
+ rfk->poll_dev->poll_interval = 1000; /* msecs */
+ } else
+ b43warn(wl, "Failed to allocate RF-kill polldev\n");
+}
+
+void b43_rfkill_free(struct b43_wldev *dev)
+{
+ struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+ input_free_polled_device(rfk->poll_dev);
+ rfk->poll_dev = NULL;
+ rfkill_free(rfk->rfkill);
+ rfk->rfkill = NULL;
+}
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h
new file mode 100644
index 000000000000..29544e8c9e5f
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.h
@@ -0,0 +1,58 @@
+#ifndef B43_RFKILL_H_
+#define B43_RFKILL_H_
+
+struct b43_wldev;
+
+
+#ifdef CONFIG_B43_RFKILL
+
+#include <linux/rfkill.h>
+#include <linux/input-polldev.h>
+
+
+struct b43_rfkill {
+ /* The RFKILL subsystem data structure */
+ struct rfkill *rfkill;
+ /* The poll device for the RFKILL input button */
+ struct input_polled_dev *poll_dev;
+ /* The unique name of this rfkill switch */
+ char name[32];
+};
+
+/* All the init functions return void, because we are not interested
+ * in failing the b43 init process when rfkill init failed. */
+void b43_rfkill_alloc(struct b43_wldev *dev);
+void b43_rfkill_free(struct b43_wldev *dev);
+void b43_rfkill_init(struct b43_wldev *dev);
+void b43_rfkill_exit(struct b43_wldev *dev);
+
+char * b43_rfkill_led_name(struct b43_wldev *dev);
+
+
+#else /* CONFIG_B43_RFKILL */
+/* No RFKILL support. */
+
+struct b43_rfkill {
+ /* empty */
+};
+
+static inline void b43_rfkill_alloc(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_free(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_init(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_exit(struct b43_wldev *dev)
+{
+}
+static inline char * b43_rfkill_led_name(struct b43_wldev *dev)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_B43_RFKILL */
+
+#endif /* B43_RFKILL_H_ */
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
new file mode 100644
index 000000000000..fcb777383e70
--- /dev/null
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -0,0 +1,235 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ SYSFS support routines
+
+ Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "sysfs.h"
+#include "main.h"
+#include "phy.h"
+
+#include <linux/capability.h>
+
+#define GENERIC_FILESIZE 64
+
+static int get_integer(const char *buf, size_t count)
+{
+ char tmp[10 + 1] = { 0 };
+ int ret = -EINVAL;
+
+ if (count == 0)
+ goto out;
+ count = min(count, (size_t) 10);
+ memcpy(tmp, buf, count);
+ ret = simple_strtol(tmp, NULL, 10);
+ out:
+ return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+ if (count != 0) {
+ if (buf[0] == '1')
+ return 1;
+ if (buf[0] == '0')
+ return 0;
+ if (count >= 4 && memcmp(buf, "true", 4) == 0)
+ return 1;
+ if (count >= 5 && memcmp(buf, "false", 5) == 0)
+ return 0;
+ if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+ return 1;
+ if (count >= 2 && memcmp(buf, "no", 2) == 0)
+ return 0;
+ if (count >= 2 && memcmp(buf, "on", 2) == 0)
+ return 1;
+ if (count >= 3 && memcmp(buf, "off", 3) == 0)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static ssize_t b43_attr_interfmode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ ssize_t count = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ switch (wldev->phy.interfmode) {
+ case B43_INTERFMODE_NONE:
+ count =
+ snprintf(buf, PAGE_SIZE,
+ "0 (No Interference Mitigation)\n");
+ break;
+ case B43_INTERFMODE_NONWLAN:
+ count =
+ snprintf(buf, PAGE_SIZE,
+ "1 (Non-WLAN Interference Mitigation)\n");
+ break;
+ case B43_INTERFMODE_MANUALWLAN:
+ count =
+ snprintf(buf, PAGE_SIZE,
+ "2 (WLAN Interference Mitigation)\n");
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43_attr_interfmode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ unsigned long flags;
+ int err;
+ int mode;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mode = get_integer(buf, count);
+ switch (mode) {
+ case 0:
+ mode = B43_INTERFMODE_NONE;
+ break;
+ case 1:
+ mode = B43_INTERFMODE_NONWLAN;
+ break;
+ case 2:
+ mode = B43_INTERFMODE_MANUALWLAN;
+ break;
+ case 3:
+ mode = B43_INTERFMODE_AUTOWLAN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ err = b43_radio_set_interference_mitigation(wldev, mode);
+ if (err) {
+ b43err(wldev->wl, "Interference Mitigation not "
+ "supported by device\n");
+ }
+ mmiowb();
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return err ? err : count;
+}
+
+static DEVICE_ATTR(interference, 0644,
+ b43_attr_interfmode_show, b43_attr_interfmode_store);
+
+static ssize_t b43_attr_preamble_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ ssize_t count;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ if (wldev->short_preamble)
+ count =
+ snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+ else
+ count =
+ snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43_attr_preamble_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ unsigned long flags;
+ int value;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ value = get_boolean(buf, count);
+ if (value < 0)
+ return value;
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ wldev->short_preamble = !!value;
+
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(shortpreamble, 0644,
+ b43_attr_preamble_show, b43_attr_preamble_store);
+
+int b43_sysfs_register(struct b43_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+ int err;
+
+ B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
+
+ err = device_create_file(dev, &dev_attr_interference);
+ if (err)
+ goto out;
+ err = device_create_file(dev, &dev_attr_shortpreamble);
+ if (err)
+ goto err_remove_interfmode;
+
+ out:
+ return err;
+ err_remove_interfmode:
+ device_remove_file(dev, &dev_attr_interference);
+ goto out;
+}
+
+void b43_sysfs_unregister(struct b43_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+
+ device_remove_file(dev, &dev_attr_shortpreamble);
+ device_remove_file(dev, &dev_attr_interference);
+}
diff --git a/drivers/net/wireless/b43/sysfs.h b/drivers/net/wireless/b43/sysfs.h
new file mode 100644
index 000000000000..12bda9ef1a85
--- /dev/null
+++ b/drivers/net/wireless/b43/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef B43_SYSFS_H_
+#define B43_SYSFS_H_
+
+struct b43_wldev;
+
+int b43_sysfs_register(struct b43_wldev *dev);
+void b43_sysfs_unregister(struct b43_wldev *dev);
+
+#endif /* B43_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c
new file mode 100644
index 000000000000..15a87183a572
--- /dev/null
+++ b/drivers/net/wireless/b43/tables.c
@@ -0,0 +1,375 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables.h"
+#include "phy.h"
+
+const u32 b43_tab_rotor[] = {
+ 0xFEB93FFD, 0xFEC63FFD, /* 0 */
+ 0xFED23FFD, 0xFEDF3FFD,
+ 0xFEEC3FFE, 0xFEF83FFE,
+ 0xFF053FFE, 0xFF113FFE,
+ 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+ 0xFF373FFF, 0xFF443FFF,
+ 0xFF503FFF, 0xFF5D3FFF,
+ 0xFF693FFF, 0xFF763FFF,
+ 0xFF824000, 0xFF8F4000, /* 16 */
+ 0xFF9B4000, 0xFFA84000,
+ 0xFFB54000, 0xFFC14000,
+ 0xFFCE4000, 0xFFDA4000,
+ 0xFFE74000, 0xFFF34000, /* 24 */
+ 0x00004000, 0x000D4000,
+ 0x00194000, 0x00264000,
+ 0x00324000, 0x003F4000,
+ 0x004B4000, 0x00584000, /* 32 */
+ 0x00654000, 0x00714000,
+ 0x007E4000, 0x008A3FFF,
+ 0x00973FFF, 0x00A33FFF,
+ 0x00B03FFF, 0x00BC3FFF, /* 40 */
+ 0x00C93FFF, 0x00D63FFF,
+ 0x00E23FFE, 0x00EF3FFE,
+ 0x00FB3FFE, 0x01083FFE,
+ 0x01143FFE, 0x01213FFD, /* 48 */
+ 0x012E3FFD, 0x013A3FFD,
+ 0x01473FFD,
+};
+
+const u32 b43_tab_retard[] = {
+ 0xDB93CB87, 0xD666CF64, /* 0 */
+ 0xD1FDD358, 0xCDA6D826,
+ 0xCA38DD9F, 0xC729E2B4,
+ 0xC469E88E, 0xC26AEE2B,
+ 0xC0DEF46C, 0xC073FA62, /* 8 */
+ 0xC01D00D5, 0xC0760743,
+ 0xC1560D1E, 0xC2E51369,
+ 0xC4ED18FF, 0xC7AC1ED7,
+ 0xCB2823B2, 0xCEFA28D9, /* 16 */
+ 0xD2F62D3F, 0xD7BB3197,
+ 0xDCE53568, 0xE1FE3875,
+ 0xE7D13B35, 0xED663D35,
+ 0xF39B3EC4, 0xF98E3FA7, /* 24 */
+ 0x00004000, 0x06723FA7,
+ 0x0C653EC4, 0x129A3D35,
+ 0x182F3B35, 0x1E023875,
+ 0x231B3568, 0x28453197, /* 32 */
+ 0x2D0A2D3F, 0x310628D9,
+ 0x34D823B2, 0x38541ED7,
+ 0x3B1318FF, 0x3D1B1369,
+ 0x3EAA0D1E, 0x3F8A0743, /* 40 */
+ 0x3FE300D5, 0x3F8DFA62,
+ 0x3F22F46C, 0x3D96EE2B,
+ 0x3B97E88E, 0x38D7E2B4,
+ 0x35C8DD9F, 0x325AD826, /* 48 */
+ 0x2E03D358, 0x299ACF64,
+ 0x246DCB87,
+};
+
+const u16 b43_tab_finefreqa[] = {
+ 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+ 0x0202, 0x0282, 0x0302, 0x0382,
+ 0x0402, 0x0482, 0x0502, 0x0582,
+ 0x05E2, 0x0662, 0x06E2, 0x0762,
+ 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+ 0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+ 0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+ 0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+ 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+ 0x1062, 0x10C2, 0x1122, 0x1182,
+ 0x11E2, 0x1242, 0x12A2, 0x12E2,
+ 0x1342, 0x13A2, 0x1402, 0x1442,
+ 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+ 0x15E2, 0x1622, 0x1662, 0x16C1,
+ 0x1701, 0x1741, 0x1781, 0x17E1,
+ 0x1821, 0x1861, 0x18A1, 0x18E1,
+ 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+ 0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+ 0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+ 0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+ 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+ 0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+ 0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+ 0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+ 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+ 0x2001, 0x2041, 0x2061, 0x2081,
+ 0x20A1, 0x20C1, 0x20E1, 0x2101,
+ 0x2121, 0x2141, 0x2161, 0x2181,
+ 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+ 0x2221, 0x2241, 0x2261, 0x2281,
+ 0x22A1, 0x22C1, 0x22C1, 0x22E1,
+ 0x2301, 0x2321, 0x2341, 0x2361,
+ 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+ 0x23E1, 0x23E1, 0x2401, 0x2421,
+ 0x2441, 0x2441, 0x2461, 0x2481,
+ 0x2481, 0x24A1, 0x24C1, 0x24C1,
+ 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+ 0x2541, 0x2541, 0x2561, 0x2561,
+ 0x2581, 0x25A1, 0x25A1, 0x25C1,
+ 0x25C1, 0x25E1, 0x2601, 0x2601,
+ 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+ 0x2661, 0x2661, 0x2681, 0x2681,
+ 0x26A1, 0x26A1, 0x26C1, 0x26C1,
+ 0x26E1, 0x26E1, 0x2701, 0x2701,
+ 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+ 0x2760, 0x2760, 0x2780, 0x2780,
+ 0x2780, 0x27A0, 0x27A0, 0x27C0,
+ 0x27C0, 0x27E0, 0x27E0, 0x27E0,
+ 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+ 0x2820, 0x2840, 0x2840, 0x2840,
+ 0x2860, 0x2860, 0x2880, 0x2880,
+ 0x2880, 0x28A0, 0x28A0, 0x28A0,
+ 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+ 0x28E0, 0x28E0, 0x2900, 0x2900,
+ 0x2900, 0x2920, 0x2920, 0x2920,
+ 0x2940, 0x2940, 0x2940, 0x2960,
+ 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+ 0x2980, 0x2980, 0x29A0, 0x29A0,
+ 0x29A0, 0x29A0, 0x29C0, 0x29C0,
+ 0x29C0, 0x29E0, 0x29E0, 0x29E0,
+ 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+ 0x2A00, 0x2A20, 0x2A20, 0x2A20,
+ 0x2A20, 0x2A40, 0x2A40, 0x2A40,
+ 0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 b43_tab_finefreqg[] = {
+ 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+ 0x05A9, 0x0669, 0x0709, 0x0789,
+ 0x0829, 0x08A9, 0x0929, 0x0989,
+ 0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+ 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+ 0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+ 0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+ 0x0FA9, 0x0FE9, 0x1029, 0x1089,
+ 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+ 0x11E9, 0x1229, 0x1289, 0x12C9,
+ 0x1309, 0x1349, 0x1389, 0x13C9,
+ 0x1409, 0x1449, 0x14A9, 0x14E9,
+ 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+ 0x1629, 0x1669, 0x16A9, 0x16E8,
+ 0x1728, 0x1768, 0x17A8, 0x17E8,
+ 0x1828, 0x1868, 0x18A8, 0x18E8,
+ 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+ 0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+ 0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+ 0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+ 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+ 0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+ 0x1F48, 0x1F88, 0x1FE8, 0x2028,
+ 0x2068, 0x20A8, 0x2108, 0x2148,
+ 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+ 0x22C8, 0x2308, 0x2348, 0x23A8,
+ 0x23E8, 0x2448, 0x24A8, 0x24E8,
+ 0x2548, 0x25A8, 0x2608, 0x2668,
+ 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+ 0x2847, 0x28C7, 0x2947, 0x29A7,
+ 0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+ 0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+ 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+ 0x3806, 0x38A6, 0x3946, 0x39E6,
+ 0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+ 0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+ 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+ 0x3F45, 0x3FA5, 0x4005, 0x4045,
+ 0x40A5, 0x40E5, 0x4145, 0x4185,
+ 0x41E5, 0x4225, 0x4265, 0x42C5,
+ 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+ 0x4424, 0x4464, 0x44C4, 0x4504,
+ 0x4544, 0x4584, 0x45C4, 0x4604,
+ 0x4644, 0x46A4, 0x46E4, 0x4724,
+ 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+ 0x4864, 0x48A4, 0x48E4, 0x4924,
+ 0x4964, 0x49A4, 0x49E4, 0x4A24,
+ 0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+ 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+ 0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+ 0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+ 0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+ 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+ 0x5083, 0x50C3, 0x5103, 0x5143,
+ 0x5183, 0x51E2, 0x5222, 0x5262,
+ 0x52A2, 0x52E2, 0x5342, 0x5382,
+ 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+ 0x5502, 0x5542, 0x55A2, 0x55E2,
+ 0x5642, 0x5682, 0x56E2, 0x5722,
+ 0x5782, 0x57E1, 0x5841, 0x58A1,
+ 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+ 0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+ 0x5C61, 0x5D01, 0x5D80, 0x5E20,
+ 0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 b43_tab_noisea2[] = {
+ 0x0001, 0x0001, 0x0001, 0xFFFE,
+ 0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 b43_tab_noisea3[] = {
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 b43_tab_noiseg1[] = {
+ 0x013C, 0x01F5, 0x031A, 0x0631,
+ 0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 b43_tab_noiseg2[] = {
+ 0x5484, 0x3C40, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 b43_tab_noisescaleg1[] = {
+ 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+ 0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+ 0x1A1D, 0x1719, 0x1616, 0x1414,
+ 0x1414, 0x1400, 0x1414, 0x1614,
+ 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+ 0x2A27, 0x2F2A, 0x332D, 0x3B35,
+ 0x5140, 0x6C62, 0x0077,
+};
+
+const u16 b43_tab_noisescaleg2[] = {
+ 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+ 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+ 0x969B, 0x9195, 0x8F8F, 0x8A8A,
+ 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+ 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+ 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+ 0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 b43_tab_noisescaleg3[] = {
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 b43_tab_sigmasqr1[] = {
+ 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+ 0x0067, 0x0063, 0x005E, 0x0059,
+ 0x0054, 0x0050, 0x004B, 0x0046,
+ 0x0042, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x0000, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x0042, 0x0046, 0x004B, 0x0050,
+ 0x0054, 0x0059, 0x005E, 0x0063,
+ 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+ 0x007A,
+};
+
+const u16 b43_tab_sigmasqr2[] = {
+ 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+ 0x00D6, 0x00D4, 0x00D2, 0x00CF,
+ 0x00CD, 0x00CA, 0x00C7, 0x00C4,
+ 0x00C1, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x0000, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00C1, 0x00C4, 0x00C7, 0x00CA,
+ 0x00CD, 0x00CF, 0x00D2, 0x00D4,
+ 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+ 0x00DE,
+};
+
+static inline void assert_sizes(void)
+{
+ BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
+ BUILD_BUG_ON(B43_TAB_RETARD_SIZE != ARRAY_SIZE(b43_tab_retard));
+ BUILD_BUG_ON(B43_TAB_FINEFREQA_SIZE != ARRAY_SIZE(b43_tab_finefreqa));
+ BUILD_BUG_ON(B43_TAB_FINEFREQG_SIZE != ARRAY_SIZE(b43_tab_finefreqg));
+ BUILD_BUG_ON(B43_TAB_NOISEA2_SIZE != ARRAY_SIZE(b43_tab_noisea2));
+ BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
+ BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
+ BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
+ BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+ ARRAY_SIZE(b43_tab_noisescaleg1));
+ BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+ ARRAY_SIZE(b43_tab_noisescaleg2));
+ BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+ ARRAY_SIZE(b43_tab_noisescaleg3));
+ BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
+ BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
+}
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
+{
+ assert_sizes();
+
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ return b43_phy_read(dev, B43_PHY_OTABLEI);
+}
+
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+ u16 offset, u16 value)
+{
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ b43_phy_write(dev, B43_PHY_OTABLEI, value);
+}
+
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
+{
+ u32 ret;
+
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
+ ret <<= 16;
+ ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
+
+ return ret;
+}
+
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+ u16 offset, u32 value)
+{
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ b43_phy_write(dev, B43_PHY_OTABLEI, value);
+ b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
+}
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset)
+{
+ b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
+ return b43_phy_read(dev, B43_PHY_GTABDATA);
+}
+
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value)
+{
+ b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
+ b43_phy_write(dev, B43_PHY_GTABDATA, value);
+}
diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h
new file mode 100644
index 000000000000..64635d7b518c
--- /dev/null
+++ b/drivers/net/wireless/b43/tables.h
@@ -0,0 +1,28 @@
+#ifndef B43_TABLES_H_
+#define B43_TABLES_H_
+
+#define B43_TAB_ROTOR_SIZE 53
+extern const u32 b43_tab_rotor[];
+#define B43_TAB_RETARD_SIZE 53
+extern const u32 b43_tab_retard[];
+#define B43_TAB_FINEFREQA_SIZE 256
+extern const u16 b43_tab_finefreqa[];
+#define B43_TAB_FINEFREQG_SIZE 256
+extern const u16 b43_tab_finefreqg[];
+#define B43_TAB_NOISEA2_SIZE 8
+extern const u16 b43_tab_noisea2[];
+#define B43_TAB_NOISEA3_SIZE 8
+extern const u16 b43_tab_noisea3[];
+#define B43_TAB_NOISEG1_SIZE 8
+extern const u16 b43_tab_noiseg1[];
+#define B43_TAB_NOISEG2_SIZE 8
+extern const u16 b43_tab_noiseg2[];
+#define B43_TAB_NOISESCALEG_SIZE 27
+extern const u16 b43_tab_noisescaleg1[];
+extern const u16 b43_tab_noisescaleg2[];
+extern const u16 b43_tab_noisescaleg3[];
+#define B43_TAB_SIGMASQR_SIZE 53
+extern const u16 b43_tab_sigmasqr1[];
+extern const u16 b43_tab_sigmasqr2[];
+
+#endif /* B43_TABLES_H_ */
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
new file mode 100644
index 000000000000..0bd6f8a348a8
--- /dev/null
+++ b/drivers/net/wireless/b43/xmit.c
@@ -0,0 +1,650 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Transmission (TX/RX) related functions.
+
+ Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "xmit.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0]) {
+ case 0x0A:
+ return B43_CCK_RATE_1MB;
+ case 0x14:
+ return B43_CCK_RATE_2MB;
+ case 0x37:
+ return B43_CCK_RATE_5MB;
+ case 0x6E:
+ return B43_CCK_RATE_11MB;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0] & 0xF) {
+ case 0xB:
+ return B43_OFDM_RATE_6MB;
+ case 0xF:
+ return B43_OFDM_RATE_9MB;
+ case 0xA:
+ return B43_OFDM_RATE_12MB;
+ case 0xE:
+ return B43_OFDM_RATE_18MB;
+ case 0x9:
+ return B43_OFDM_RATE_24MB;
+ case 0xD:
+ return B43_OFDM_RATE_36MB;
+ case 0x8:
+ return B43_OFDM_RATE_48MB;
+ case 0xC:
+ return B43_OFDM_RATE_54MB;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43_CCK_RATE_1MB:
+ return 0x0A;
+ case B43_CCK_RATE_2MB:
+ return 0x14;
+ case B43_CCK_RATE_5MB:
+ return 0x37;
+ case B43_CCK_RATE_11MB:
+ return 0x6E;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43_OFDM_RATE_6MB:
+ return 0xB;
+ case B43_OFDM_RATE_9MB:
+ return 0xF;
+ case B43_OFDM_RATE_12MB:
+ return 0xA;
+ case B43_OFDM_RATE_18MB:
+ return 0xE;
+ case B43_OFDM_RATE_24MB:
+ return 0x9;
+ case B43_OFDM_RATE_36MB:
+ return 0xD;
+ case B43_OFDM_RATE_48MB:
+ return 0x8;
+ case B43_OFDM_RATE_54MB:
+ return 0xC;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate)
+{
+ __le32 *data = &(plcp->data);
+ __u8 *raw = plcp->raw;
+
+ if (b43_is_ofdm_rate(bitrate)) {
+ u32 d;
+
+ d = b43_plcp_get_ratecode_ofdm(bitrate);
+ B43_WARN_ON(octets & 0xF000);
+ d |= (octets << 5);
+ *data = cpu_to_le32(d);
+ } else {
+ u32 plen;
+
+ plen = octets * 16 / bitrate;
+ if ((octets * 16 % bitrate) > 0) {
+ plen++;
+ if ((bitrate == B43_CCK_RATE_11MB)
+ && ((octets * 8 % 11) < 4)) {
+ raw[1] = 0x84;
+ } else
+ raw[1] = 0x04;
+ } else
+ raw[1] = 0x04;
+ *data |= cpu_to_le32(plen << 16);
+ raw[0] = b43_plcp_get_ratecode_cck(bitrate);
+ }
+}
+
+static u8 b43_calc_fallback_rate(u8 bitrate)
+{
+ switch (bitrate) {
+ case B43_CCK_RATE_1MB:
+ return B43_CCK_RATE_1MB;
+ case B43_CCK_RATE_2MB:
+ return B43_CCK_RATE_1MB;
+ case B43_CCK_RATE_5MB:
+ return B43_CCK_RATE_2MB;
+ case B43_CCK_RATE_11MB:
+ return B43_CCK_RATE_5MB;
+ case B43_OFDM_RATE_6MB:
+ return B43_CCK_RATE_5MB;
+ case B43_OFDM_RATE_9MB:
+ return B43_OFDM_RATE_6MB;
+ case B43_OFDM_RATE_12MB:
+ return B43_OFDM_RATE_9MB;
+ case B43_OFDM_RATE_18MB:
+ return B43_OFDM_RATE_12MB;
+ case B43_OFDM_RATE_24MB:
+ return B43_OFDM_RATE_18MB;
+ case B43_OFDM_RATE_36MB:
+ return B43_OFDM_RATE_24MB;
+ case B43_OFDM_RATE_48MB:
+ return B43_OFDM_RATE_36MB;
+ case B43_OFDM_RATE_54MB:
+ return B43_OFDM_RATE_48MB;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+static void generate_txhdr_fw4(struct b43_wldev *dev,
+ struct b43_txhdr_fw4 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie)
+{
+ const struct b43_phy *phy = &dev->phy;
+ const struct ieee80211_hdr *wlhdr =
+ (const struct ieee80211_hdr *)fragment_data;
+ int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ u16 fctl = le16_to_cpu(wlhdr->frame_control);
+ u8 rate, rate_fb;
+ int rate_ofdm, rate_fb_ofdm;
+ unsigned int plcp_fragment_len;
+ u32 mac_ctl = 0;
+ u16 phy_ctl = 0;
+ u8 extra_ft = 0;
+
+ memset(txhdr, 0, sizeof(*txhdr));
+
+ rate = txctl->tx_rate;
+ rate_ofdm = b43_is_ofdm_rate(rate);
+ rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+ rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
+
+ if (rate_ofdm)
+ txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate);
+ else
+ txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);
+ txhdr->mac_frame_ctl = wlhdr->frame_control;
+ memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+ /* Calculate duration for fallback rate */
+ if ((rate_fb == rate) ||
+ (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+ (wlhdr->duration_id == cpu_to_le16(0))) {
+ /* If the fallback rate equals the normal rate or the
+ * dur_id field contains an AID, CFP magic or 0,
+ * use the original dur_id field. */
+ txhdr->dur_fb = wlhdr->duration_id;
+ } else {
+ int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_len,
+ fbrate_base100kbps);
+ }
+
+ plcp_fragment_len = fragment_len + FCS_LEN;
+ if (use_encryption) {
+ u8 key_idx = (u16) (txctl->key_idx);
+ struct b43_key *key;
+ int wlhdr_len;
+ size_t iv_len;
+
+ B43_WARN_ON(key_idx >= dev->max_nr_keys);
+ key = &(dev->key[key_idx]);
+ B43_WARN_ON(!key->keyconf);
+
+ /* Hardware appends ICV. */
+ plcp_fragment_len += txctl->icv_len;
+
+ key_idx = b43_kidx_to_fw(dev, key_idx);
+ mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
+ B43_TX4_MAC_KEYIDX;
+ mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
+ B43_TX4_MAC_KEYALG;
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ iv_len = min((size_t) txctl->iv_len,
+ ARRAY_SIZE(txhdr->iv));
+ memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+ }
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
+ plcp_fragment_len, rate);
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
+ plcp_fragment_len, rate_fb);
+
+ /* Extra Frame Types */
+ if (rate_fb_ofdm)
+ extra_ft |= B43_TX4_EFT_FBOFDM;
+
+ /* Set channel radio code. Note that the micrcode ORs 0x100 to
+ * this value before comparing it to the value in SHM, if this
+ * is a 5Ghz packet.
+ */
+ txhdr->chan_radio_code = phy->channel;
+
+ /* PHY TX Control word */
+ if (rate_ofdm)
+ phy_ctl |= B43_TX4_PHY_OFDM;
+ if (dev->short_preamble)
+ phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
+ switch (txctl->antenna_sel_tx) {
+ case 0:
+ phy_ctl |= B43_TX4_PHY_ANTLAST;
+ break;
+ case 1:
+ phy_ctl |= B43_TX4_PHY_ANT0;
+ break;
+ case 2:
+ phy_ctl |= B43_TX4_PHY_ANT1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ /* MAC control */
+ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+ mac_ctl |= B43_TX4_MAC_ACK;
+ if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+ mac_ctl |= B43_TX4_MAC_HWSEQ;
+ if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ mac_ctl |= B43_TX4_MAC_STMSDU;
+ if (phy->type == B43_PHYTYPE_A)
+ mac_ctl |= B43_TX4_MAC_5GHZ;
+
+ /* Generate the RTS or CTS-to-self frame */
+ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+ (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ unsigned int len;
+ struct ieee80211_hdr *hdr;
+ int rts_rate, rts_rate_fb;
+ int rts_rate_ofdm, rts_rate_fb_ofdm;
+
+ rts_rate = txctl->rts_cts_rate;
+ rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
+ rts_rate_fb = b43_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
+
+ if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
+ fragment_data, fragment_len,
+ txctl,
+ (struct ieee80211_cts *)(txhdr->
+ rts_frame));
+ mac_ctl |= B43_TX4_MAC_SENDCTS;
+ len = sizeof(struct ieee80211_cts);
+ } else {
+ ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
+ fragment_data, fragment_len, txctl,
+ (struct ieee80211_rts *)(txhdr->
+ rts_frame));
+ mac_ctl |= B43_TX4_MAC_SENDRTS;
+ len = sizeof(struct ieee80211_rts);
+ }
+ len += FCS_LEN;
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
+ rts_plcp), len,
+ rts_rate);
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
+ rts_plcp_fb),
+ len, rts_rate_fb);
+ hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+ txhdr->rts_dur_fb = hdr->duration_id;
+ if (rts_rate_ofdm) {
+ extra_ft |= B43_TX4_EFT_RTSOFDM;
+ txhdr->phy_rate_rts =
+ b43_plcp_get_ratecode_ofdm(rts_rate);
+ } else
+ txhdr->phy_rate_rts =
+ b43_plcp_get_ratecode_cck(rts_rate);
+ if (rts_rate_fb_ofdm)
+ extra_ft |= B43_TX4_EFT_RTSFBOFDM;
+ mac_ctl |= B43_TX4_MAC_LONGFRAME;
+ }
+
+ /* Magic cookie */
+ txhdr->cookie = cpu_to_le16(cookie);
+
+ /* Apply the bitfields */
+ txhdr->mac_ctl = cpu_to_le32(mac_ctl);
+ txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+ txhdr->extra_ft = extra_ft;
+}
+
+void b43_generate_txhdr(struct b43_wldev *dev,
+ u8 * txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl, u16 cookie)
+{
+ generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
+ fragment_data, fragment_len, txctl, cookie);
+}
+
+static s8 b43_rssi_postprocess(struct b43_wldev *dev,
+ u8 in_rssi, int ofdm,
+ int adjust_2053, int adjust_2050)
+{
+ struct b43_phy *phy = &dev->phy;
+ s32 tmp;
+
+ switch (phy->radio_ver) {
+ case 0x2050:
+ if (ofdm) {
+ tmp = in_rssi;
+ if (tmp > 127)
+ tmp -= 256;
+ tmp *= 73;
+ tmp /= 64;
+ if (adjust_2050)
+ tmp += 25;
+ else
+ tmp -= 3;
+ } else {
+ if (dev->dev->bus->sprom.r1.
+ boardflags_lo & B43_BFL_RSSI) {
+ if (in_rssi > 63)
+ in_rssi = 63;
+ tmp = phy->nrssi_lt[in_rssi];
+ tmp = 31 - tmp;
+ tmp *= -131;
+ tmp /= 128;
+ tmp -= 57;
+ } else {
+ tmp = in_rssi;
+ tmp = 31 - tmp;
+ tmp *= -149;
+ tmp /= 128;
+ tmp -= 68;
+ }
+ if (phy->type == B43_PHYTYPE_G && adjust_2050)
+ tmp += 25;
+ }
+ break;
+ case 0x2060:
+ if (in_rssi > 127)
+ tmp = in_rssi - 256;
+ else
+ tmp = in_rssi;
+ break;
+ default:
+ tmp = in_rssi;
+ tmp -= 11;
+ tmp *= 103;
+ tmp /= 64;
+ if (adjust_2053)
+ tmp -= 109;
+ else
+ tmp -= 83;
+ }
+
+ return (s8) tmp;
+}
+
+//TODO
+#if 0
+static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi)
+{
+ struct b43_phy *phy = &dev->phy;
+ s8 ret;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ //TODO: Incomplete specs.
+ ret = 0;
+ } else
+ ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1);
+
+ return ret;
+}
+#endif
+
+void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
+{
+ struct ieee80211_rx_status status;
+ struct b43_plcp_hdr6 *plcp;
+ struct ieee80211_hdr *wlhdr;
+ const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
+ u16 fctl;
+ u16 phystat0, phystat3, chanstat, mactime;
+ u32 macstat;
+ u16 chanid;
+ u8 jssi;
+ int padding;
+
+ memset(&status, 0, sizeof(status));
+
+ /* Get metadata about the frame from the header. */
+ phystat0 = le16_to_cpu(rxhdr->phy_status0);
+ phystat3 = le16_to_cpu(rxhdr->phy_status3);
+ jssi = rxhdr->jssi;
+ macstat = le32_to_cpu(rxhdr->mac_status);
+ mactime = le16_to_cpu(rxhdr->mac_time);
+ chanstat = le16_to_cpu(rxhdr->channel);
+
+ if (macstat & B43_RX_MAC_FCSERR)
+ dev->wl->ieee_stats.dot11FCSErrorCount++;
+ if (macstat & B43_RX_MAC_DECERR) {
+ /* Decryption with the given key failed.
+ * Drop the packet. We also won't be able to decrypt it with
+ * the key in software. */
+ goto drop;
+ }
+
+ /* Skip PLCP and padding */
+ padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
+ if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) {
+ b43dbg(dev->wl, "RX: Packet size underrun (1)\n");
+ goto drop;
+ }
+ plcp = (struct b43_plcp_hdr6 *)(skb->data + padding);
+ skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding);
+ /* The skb contains the Wireless Header + payload data now */
+ if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */ + FCS_LEN))) {
+ b43dbg(dev->wl, "RX: Packet size underrun (2)\n");
+ goto drop;
+ }
+ wlhdr = (struct ieee80211_hdr *)(skb->data);
+ fctl = le16_to_cpu(wlhdr->frame_control);
+ skb_trim(skb, skb->len - FCS_LEN);
+
+ if (macstat & B43_RX_MAC_DEC) {
+ unsigned int keyidx;
+ int wlhdr_len;
+
+ keyidx = ((macstat & B43_RX_MAC_KEYIDX)
+ >> B43_RX_MAC_KEYIDX_SHIFT);
+ /* We must adjust the key index here. We want the "physical"
+ * key index, but the ucode passed it slightly different.
+ */
+ keyidx = b43_kidx_to_raw(dev, keyidx);
+ B43_WARN_ON(keyidx >= dev->max_nr_keys);
+
+ if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ if (unlikely(skb->len < (wlhdr_len + 3))) {
+ b43dbg(dev->wl,
+ "RX: Packet size underrun (3)\n");
+ goto drop;
+ }
+ status.flag |= RX_FLAG_DECRYPTED;
+ }
+ }
+
+ status.ssi = b43_rssi_postprocess(dev, jssi,
+ (phystat0 & B43_RX_PHYST0_OFDM),
+ (phystat0 & B43_RX_PHYST0_GAINCTL),
+ (phystat3 & B43_RX_PHYST3_TRSTATE));
+ status.noise = dev->stats.link_noise;
+ /* the next line looks wrong, but is what mac80211 wants */
+ status.signal = (jssi * 100) / B43_RX_MAX_SSI;
+ if (phystat0 & B43_RX_PHYST0_OFDM)
+ status.rate = b43_plcp_get_bitrate_ofdm(plcp);
+ else
+ status.rate = b43_plcp_get_bitrate_cck(plcp);
+ status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
+ status.mactime = mactime;
+
+ chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
+ switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+ case B43_PHYTYPE_A:
+ status.phymode = MODE_IEEE80211A;
+ status.freq = chanid;
+ status.channel = b43_freq_to_channel_a(chanid);
+ break;
+ case B43_PHYTYPE_B:
+ status.phymode = MODE_IEEE80211B;
+ status.freq = chanid + 2400;
+ status.channel = b43_freq_to_channel_bg(chanid + 2400);
+ break;
+ case B43_PHYTYPE_G:
+ status.phymode = MODE_IEEE80211G;
+ status.freq = chanid + 2400;
+ status.channel = b43_freq_to_channel_bg(chanid + 2400);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ dev->stats.last_rx = jiffies;
+ ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+
+ return;
+drop:
+ b43dbg(dev->wl, "RX: Packet dropped\n");
+ dev_kfree_skb_any(skb);
+}
+
+void b43_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ b43_debugfs_log_txstat(dev, status);
+
+ if (status->intermediate)
+ return;
+ if (status->for_ampdu)
+ return;
+ if (!status->acked)
+ dev->wl->ieee_stats.dot11ACKFailureCount++;
+ if (status->rts_count) {
+ if (status->rts_count == 0xF) //FIXME
+ dev->wl->ieee_stats.dot11RTSFailureCount++;
+ else
+ dev->wl->ieee_stats.dot11RTSSuccessCount++;
+ }
+
+ if (b43_using_pio(dev))
+ b43_pio_handle_txstatus(dev, status);
+ else
+ b43_dma_handle_txstatus(dev, status);
+}
+
+/* Handle TX status report as received through DMA/PIO queues */
+void b43_handle_hwtxstatus(struct b43_wldev *dev,
+ const struct b43_hwtxstatus *hw)
+{
+ struct b43_txstatus status;
+ u8 tmp;
+
+ status.cookie = le16_to_cpu(hw->cookie);
+ status.seq = le16_to_cpu(hw->seq);
+ status.phy_stat = hw->phy_stat;
+ tmp = hw->count;
+ status.frame_count = (tmp >> 4);
+ status.rts_count = (tmp & 0x0F);
+ tmp = hw->flags;
+ status.supp_reason = ((tmp & 0x1C) >> 2);
+ status.pm_indicated = !!(tmp & 0x80);
+ status.intermediate = !!(tmp & 0x40);
+ status.for_ampdu = !!(tmp & 0x20);
+ status.acked = !!(tmp & 0x02);
+
+ b43_handle_txstatus(dev, &status);
+}
+
+/* Stop any TX operation on the device (suspend the hardware queues) */
+void b43_tx_suspend(struct b43_wldev *dev)
+{
+ if (b43_using_pio(dev))
+ b43_pio_freeze_txqueues(dev);
+ else
+ b43_dma_tx_suspend(dev);
+}
+
+/* Resume any TX operation on the device (resume the hardware queues) */
+void b43_tx_resume(struct b43_wldev *dev)
+{
+ if (b43_using_pio(dev))
+ b43_pio_thaw_txqueues(dev);
+ else
+ b43_dma_tx_resume(dev);
+}
+
+#if 0
+static void upload_qos_parms(struct b43_wldev *dev,
+ const u16 * parms, u16 offset)
+{
+ int i;
+
+ for (i = 0; i < B43_NR_QOSPARMS; i++) {
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ offset + (i * 2), parms[i]);
+ }
+}
+#endif
+
+/* Initialize the QoS parameters */
+void b43_qos_init(struct b43_wldev *dev)
+{
+ /* FIXME: This function must probably be called from the mac80211
+ * config callback. */
+ return;
+
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
+ //FIXME kill magic
+ b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
+
+ /*TODO: We might need some stack support here to get the values. */
+}
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
new file mode 100644
index 000000000000..03bddd251618
--- /dev/null
+++ b/drivers/net/wireless/b43/xmit.h
@@ -0,0 +1,250 @@
+#ifndef B43_XMIT_H_
+#define B43_XMIT_H_
+
+#include "main.h"
+
+#define _b43_declare_plcp_hdr(size) \
+ struct b43_plcp_hdr##size { \
+ union { \
+ __le32 data; \
+ __u8 raw[size]; \
+ } __attribute__((__packed__)); \
+ } __attribute__((__packed__))
+
+/* struct b43_plcp_hdr4 */
+_b43_declare_plcp_hdr(4);
+/* struct b43_plcp_hdr6 */
+_b43_declare_plcp_hdr(6);
+
+#undef _b43_declare_plcp_hdr
+
+/* TX header for v4 firmware */
+struct b43_txhdr_fw4 {
+ __le32 mac_ctl; /* MAC TX control */
+ __le16 mac_frame_ctl; /* Copy of the FrameControl field */
+ __le16 tx_fes_time_norm; /* TX FES Time Normal */
+ __le16 phy_ctl; /* PHY TX control */
+ __le16 phy_ctl_0; /* Unused */
+ __le16 phy_ctl_1; /* Unused */
+ __le16 phy_ctl_rts_0; /* Unused */
+ __le16 phy_ctl_rts_1; /* Unused */
+ __u8 phy_rate; /* PHY rate */
+ __u8 phy_rate_rts; /* PHY rate for RTS/CTS */
+ __u8 extra_ft; /* Extra Frame Types */
+ __u8 chan_radio_code; /* Channel Radio Code */
+ __u8 iv[16]; /* Encryption IV */
+ __u8 tx_receiver[6]; /* TX Frame Receiver address */
+ __le16 tx_fes_time_fb; /* TX FES Time Fallback */
+ struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */
+ __le16 rts_dur_fb; /* RTS fallback duration */
+ struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */
+ __le16 dur_fb; /* Fallback duration */
+ __le16 mm_dur_time; /* Unused */
+ __le16 mm_dur_time_fb; /* Unused */
+ __le32 time_stamp; /* Timestamp */
+ PAD_BYTES(2);
+ __le16 cookie; /* TX frame cookie */
+ __le16 tx_status; /* TX status */
+ struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */
+ __u8 rts_frame[16]; /* The RTS frame (if used) */
+ PAD_BYTES(2);
+ struct b43_plcp_hdr6 plcp; /* Main PLCP */
+} __attribute__ ((__packed__));
+
+/* MAC TX control */
+#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
+#define B43_TX4_MAC_KEYIDX_SHIFT 20
+#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
+#define B43_TX4_MAC_KEYALG_SHIFT 16
+#define B43_TX4_MAC_LIFETIME 0x00001000
+#define B43_TX4_MAC_FRAMEBURST 0x00000800
+#define B43_TX4_MAC_SENDCTS 0x00000400
+#define B43_TX4_MAC_AMPDU 0x00000300
+#define B43_TX4_MAC_AMPDU_SHIFT 8
+#define B43_TX4_MAC_5GHZ 0x00000080
+#define B43_TX4_MAC_IGNPMQ 0x00000020
+#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
+#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
+#define B43_TX4_MAC_SENDRTS 0x00000004
+#define B43_TX4_MAC_LONGFRAME 0x00000002
+#define B43_TX4_MAC_ACK 0x00000001
+
+/* Extra Frame Types */
+#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */
+#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
+#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
+
+/* PHY TX control word */
+#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
+#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
+#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */
+#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
+#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
+#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
+
+void b43_generate_txhdr(struct b43_wldev *dev,
+ u8 * txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl, u16 cookie);
+
+/* Transmit Status */
+struct b43_txstatus {
+ u16 cookie; /* The cookie from the txhdr */
+ u16 seq; /* Sequence number */
+ u8 phy_stat; /* PHY TX status */
+ u8 frame_count; /* Frame transmit count */
+ u8 rts_count; /* RTS transmit count */
+ u8 supp_reason; /* Suppression reason */
+ /* flags */
+ u8 pm_indicated; /* PM mode indicated to AP */
+ u8 intermediate; /* Intermediate status notification (not final) */
+ u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
+ u8 acked; /* Wireless ACK received */
+};
+
+/* txstatus supp_reason values */
+enum {
+ B43_TXST_SUPP_NONE, /* Not suppressed */
+ B43_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
+ B43_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
+ B43_TXST_SUPP_PREV, /* Previous fragment failed */
+ B43_TXST_SUPP_CHAN, /* Channel mismatch */
+ B43_TXST_SUPP_LIFE, /* Lifetime expired */
+ B43_TXST_SUPP_UNDER, /* Buffer underflow */
+ B43_TXST_SUPP_ABNACK, /* Afterburner NACK */
+};
+
+/* Transmit Status as received through DMA/PIO on old chips */
+struct b43_hwtxstatus {
+ PAD_BYTES(4);
+ __le16 cookie;
+ u8 flags;
+ u8 count;
+ PAD_BYTES(2);
+ __le16 seq;
+ u8 phy_stat;
+ PAD_BYTES(1);
+} __attribute__ ((__packed__));
+
+/* Receive header for v4 firmware. */
+struct b43_rxhdr_fw4 {
+ __le16 frame_len; /* Frame length */
+ PAD_BYTES(2);
+ __le16 phy_status0; /* PHY RX Status 0 */
+ __u8 jssi; /* PHY RX Status 1: JSSI */
+ __u8 sig_qual; /* PHY RX Status 1: Signal Quality */
+ __le16 phy_status2; /* PHY RX Status 2 */
+ __le16 phy_status3; /* PHY RX Status 3 */
+ __le32 mac_status; /* MAC RX status */
+ __le16 mac_time;
+ __le16 channel;
+} __attribute__ ((__packed__));
+
+/* PHY RX Status 0 */
+#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
+#define B43_RX_PHYST0_PLCPHCF 0x0200
+#define B43_RX_PHYST0_PLCPFV 0x0100
+#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */
+#define B43_RX_PHYST0_LCRS 0x0040
+#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */
+#define B43_RX_PHYST0_UNSRATE 0x0010
+#define B43_RX_PHYST0_CLIP 0x000C
+#define B43_RX_PHYST0_CLIP_SHIFT 2
+#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */
+#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
+#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
+#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
+#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
+
+/* PHY RX Status 2 */
+#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
+#define B43_RX_PHYST2_LNAG_SHIFT 14
+#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
+#define B43_RX_PHYST2_PNAG_SHIFT 10
+#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */
+
+/* PHY RX Status 3 */
+#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
+#define B43_RX_PHYST3_DIGG_SHIFT 11
+#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */
+
+/* MAC RX Status */
+#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
+#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */
+#define B43_RX_MAC_KEYIDX_SHIFT 5
+#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */
+#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */
+#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
+#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */
+#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */
+
+/* RX channel */
+#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */
+#define B43_RX_CHAN_GAIN_SHIFT 10
+#define B43_RX_CHAN_ID 0x03FC /* Channel ID */
+#define B43_RX_CHAN_ID_SHIFT 2
+#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
+
+u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
+u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate);
+
+void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
+
+void b43_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+
+void b43_handle_hwtxstatus(struct b43_wldev *dev,
+ const struct b43_hwtxstatus *hw);
+
+void b43_tx_suspend(struct b43_wldev *dev);
+void b43_tx_resume(struct b43_wldev *dev);
+
+#define B43_NR_QOSPARMS 22
+enum {
+ B43_QOSPARM_TXOP = 0,
+ B43_QOSPARM_CWMIN,
+ B43_QOSPARM_CWMAX,
+ B43_QOSPARM_CWCUR,
+ B43_QOSPARM_AIFS,
+ B43_QOSPARM_BSLOTS,
+ B43_QOSPARM_REGGAP,
+ B43_QOSPARM_STATUS,
+};
+void b43_qos_init(struct b43_wldev *dev);
+
+/* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+ * We need to account for that here. */
+static inline int b43_new_kidx_api(struct b43_wldev *dev)
+{
+ /* FIXME: Not sure the change was at rev 351 */
+ return (dev->fw.rev >= 351);
+}
+static inline u8 b43_kidx_to_fw(struct b43_wldev *dev, u8 raw_kidx)
+{
+ u8 firmware_kidx;
+ if (b43_new_kidx_api(dev)) {
+ firmware_kidx = raw_kidx;
+ } else {
+ if (raw_kidx >= 4) /* Is per STA key? */
+ firmware_kidx = raw_kidx - 4;
+ else
+ firmware_kidx = raw_kidx; /* TX default key */
+ }
+ return firmware_kidx;
+}
+static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
+{
+ u8 raw_kidx;
+ if (b43_new_kidx_api(dev))
+ raw_kidx = firmware_kidx;
+ else
+ raw_kidx = firmware_kidx + 4; /* RX default keys or per STA keys */
+ return raw_kidx;
+}
+
+#endif /* B43_XMIT_H_ */
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
new file mode 100644
index 000000000000..7e23ec23fc98
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -0,0 +1,89 @@
+config B43LEGACY
+ tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)"
+ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+ select SSB
+ select FW_LOADER
+ select HW_RANDOM
+ ---help---
+ b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
+ BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the
+ Linksys WPC54G V1 PCMCIA devices.
+
+ Newer 802.11g and 802.11a devices need b43.
+
+ It is safe to include both b43 and b43legacy as the underlying glue
+ layer will automatically load the correct version for your device.
+
+ This driver uses V3 firmware, which must be installed separately using
+ b43-fwcutter.
+
+ This driver can be built as a module (recommended) that will be
+ called "b43legacy". If unsure, say M.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B43LEGACY_PCI_AUTOSELECT
+ bool
+ depends on B43LEGACY && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B43LEGACY_PCICORE_AUTOSELECT
+ bool
+ depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B43LEGACY_DEBUG
+ bool "Broadcom 43xx-legacy debugging"
+ depends on B43LEGACY
+ default y
+ ---help---
+ Say Y, because this information will help you get the driver running.
+ This option generates a minimum of log output.
+
+config B43LEGACY_DMA
+ bool
+ depends on B43LEGACY
+
+config B43LEGACY_PIO
+ bool
+ depends on B43LEGACY
+
+choice
+ prompt "Broadcom 43xx-legacy data transfer mode"
+ depends on B43LEGACY
+ default B43LEGACY_DMA_AND_PIO_MODE
+
+config B43LEGACY_DMA_AND_PIO_MODE
+ bool "DMA + PIO"
+ select B43LEGACY_DMA
+ select B43LEGACY_PIO
+ ---help---
+ Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+ data transfer modes. The mode actually used is selectable through
+ the module parameter "pio". With pio=0 as a module parameter, the
+ default DMA is used, otherwise PIO is used.
+
+ If unsure, choose this option.
+
+config B43LEGACY_DMA_MODE
+ bool "DMA (Direct Memory Access) only"
+ select B43LEGACY_DMA
+ ---help---
+ Only include Direct Memory Access (DMA).
+ This reduces the size of the driver module, by omitting the PIO code.
+
+config B43LEGACY_PIO_MODE
+ bool "PIO (Programmed I/O) only"
+ select B43LEGACY_PIO
+ ---help---
+ Only include Programmed I/O (PIO).
+ This reduces the size of the driver module, by omitting the DMA code.
+ Please note that PIO transfers are slow (compared to DMA).
+
+ Also note that not all devices of the b43legacy series support PIO.
+
+ You should use PIO only if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile
new file mode 100644
index 000000000000..ec3a2482bbad
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_B43LEGACY) += b43legacy.o
+b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o
+
+b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o
+b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o
+
+b43legacy-objs := main.o \
+ ilt.o \
+ leds.o \
+ phy.o \
+ radio.o \
+ sysfs.o \
+ xmit.o \
+ $(b43legacy-obj-y)
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
new file mode 100644
index 000000000000..afe145cec067
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -0,0 +1,832 @@
+#ifndef B43legacy_H_
+#define B43legacy_H_
+
+#include <linux/hw_random.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_driver_chipcommon.h>
+
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+
+#include "debugfs.h"
+#include "leds.h"
+#include "phy.h"
+
+
+#define B43legacy_IRQWAIT_MAX_RETRIES 100
+
+#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */
+
+/* MMIO offsets */
+#define B43legacy_MMIO_DMA0_REASON 0x20
+#define B43legacy_MMIO_DMA0_IRQ_MASK 0x24
+#define B43legacy_MMIO_DMA1_REASON 0x28
+#define B43legacy_MMIO_DMA1_IRQ_MASK 0x2C
+#define B43legacy_MMIO_DMA2_REASON 0x30
+#define B43legacy_MMIO_DMA2_IRQ_MASK 0x34
+#define B43legacy_MMIO_DMA3_REASON 0x38
+#define B43legacy_MMIO_DMA3_IRQ_MASK 0x3C
+#define B43legacy_MMIO_DMA4_REASON 0x40
+#define B43legacy_MMIO_DMA4_IRQ_MASK 0x44
+#define B43legacy_MMIO_DMA5_REASON 0x48
+#define B43legacy_MMIO_DMA5_IRQ_MASK 0x4C
+#define B43legacy_MMIO_MACCTL 0x120
+#define B43legacy_MMIO_STATUS_BITFIELD 0x120
+#define B43legacy_MMIO_STATUS2_BITFIELD 0x124
+#define B43legacy_MMIO_GEN_IRQ_REASON 0x128
+#define B43legacy_MMIO_GEN_IRQ_MASK 0x12C
+#define B43legacy_MMIO_RAM_CONTROL 0x130
+#define B43legacy_MMIO_RAM_DATA 0x134
+#define B43legacy_MMIO_PS_STATUS 0x140
+#define B43legacy_MMIO_RADIO_HWENABLED_HI 0x158
+#define B43legacy_MMIO_SHM_CONTROL 0x160
+#define B43legacy_MMIO_SHM_DATA 0x164
+#define B43legacy_MMIO_SHM_DATA_UNALIGNED 0x166
+#define B43legacy_MMIO_XMITSTAT_0 0x170
+#define B43legacy_MMIO_XMITSTAT_1 0x174
+#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
+#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+
+/* 32-bit DMA */
+#define B43legacy_MMIO_DMA32_BASE0 0x200
+#define B43legacy_MMIO_DMA32_BASE1 0x220
+#define B43legacy_MMIO_DMA32_BASE2 0x240
+#define B43legacy_MMIO_DMA32_BASE3 0x260
+#define B43legacy_MMIO_DMA32_BASE4 0x280
+#define B43legacy_MMIO_DMA32_BASE5 0x2A0
+/* 64-bit DMA */
+#define B43legacy_MMIO_DMA64_BASE0 0x200
+#define B43legacy_MMIO_DMA64_BASE1 0x240
+#define B43legacy_MMIO_DMA64_BASE2 0x280
+#define B43legacy_MMIO_DMA64_BASE3 0x2C0
+#define B43legacy_MMIO_DMA64_BASE4 0x300
+#define B43legacy_MMIO_DMA64_BASE5 0x340
+/* PIO */
+#define B43legacy_MMIO_PIO1_BASE 0x300
+#define B43legacy_MMIO_PIO2_BASE 0x310
+#define B43legacy_MMIO_PIO3_BASE 0x320
+#define B43legacy_MMIO_PIO4_BASE 0x330
+
+#define B43legacy_MMIO_PHY_VER 0x3E0
+#define B43legacy_MMIO_PHY_RADIO 0x3E2
+#define B43legacy_MMIO_PHY0 0x3E6
+#define B43legacy_MMIO_ANTENNA 0x3E8
+#define B43legacy_MMIO_CHANNEL 0x3F0
+#define B43legacy_MMIO_CHANNEL_EXT 0x3F4
+#define B43legacy_MMIO_RADIO_CONTROL 0x3F6
+#define B43legacy_MMIO_RADIO_DATA_HIGH 0x3F8
+#define B43legacy_MMIO_RADIO_DATA_LOW 0x3FA
+#define B43legacy_MMIO_PHY_CONTROL 0x3FC
+#define B43legacy_MMIO_PHY_DATA 0x3FE
+#define B43legacy_MMIO_MACFILTER_CONTROL 0x420
+#define B43legacy_MMIO_MACFILTER_DATA 0x422
+#define B43legacy_MMIO_RCMTA_COUNT 0x43C /* Receive Match Transmitter Addr */
+#define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A
+#define B43legacy_MMIO_GPIO_CONTROL 0x49C
+#define B43legacy_MMIO_GPIO_MASK 0x49E
+#define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_3 0x638 /* core rev < 3 only */
+#define B43legacy_MMIO_RNG 0x65A
+#define B43legacy_MMIO_POWERUP_DELAY 0x6A8
+
+/* SPROM boardflags_lo values */
+#define B43legacy_BFL_PACTRL 0x0002
+#define B43legacy_BFL_RSSI 0x0008
+#define B43legacy_BFL_EXTLNA 0x1000
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define B43legacy_GPIO_CONTROL 0x6c
+
+/* SHM Routing */
+#define B43legacy_SHM_SHARED 0x0001
+#define B43legacy_SHM_WIRELESS 0x0002
+#define B43legacy_SHM_HW 0x0004
+#define B43legacy_SHM_UCODE 0x0300
+
+/* SHM Routing modifiers */
+#define B43legacy_SHM_AUTOINC_R 0x0200 /* Read Auto-increment */
+#define B43legacy_SHM_AUTOINC_W 0x0100 /* Write Auto-increment */
+#define B43legacy_SHM_AUTOINC_RW (B43legacy_SHM_AUTOINC_R | \
+ B43legacy_SHM_AUTOINC_W)
+
+/* Misc SHM_SHARED offsets */
+#define B43legacy_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
+#define B43legacy_SHM_SH_HOSTFLO 0x005E /* Hostflags ucode opts (low) */
+#define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */
+/* SHM_SHARED crypto engine */
+#define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */
+/* SHM_SHARED beacon variables */
+#define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */
+/* SHM_SHARED ACK/CTS control */
+#define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */
+/* SHM_SHARED probe response variables */
+#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
+#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
+/* SHM_SHARED rate tables */
+/* SHM_SHARED microcode soft registers */
+#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
+#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
+#define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
+#define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */
+
+#define B43legacy_UCODEFLAGS_OFFSET 0x005E
+
+/* Hardware Radio Enable masks */
+#define B43legacy_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define B43legacy_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+/* HostFlags. See b43legacy_hf_read/write() */
+#define B43legacy_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
+#define B43legacy_HF_GDCW 0x00000020 /* G-PHY DV cancel filter */
+#define B43legacy_HF_OFDMPABOOST 0x00000040 /* Enable PA boost OFDM */
+#define B43legacy_HF_EDCF 0x00000100 /* on if WME/MAC suspended */
+
+/* MacFilter offsets. */
+#define B43legacy_MACFILTER_SELF 0x0000
+#define B43legacy_MACFILTER_BSSID 0x0003
+#define B43legacy_MACFILTER_MAC 0x0010
+
+/* PHYVersioning */
+#define B43legacy_PHYTYPE_B 0x01
+#define B43legacy_PHYTYPE_G 0x02
+
+/* PHYRegisters */
+#define B43legacy_PHY_G_LO_CONTROL 0x0810
+#define B43legacy_PHY_ILT_G_CTRL 0x0472
+#define B43legacy_PHY_ILT_G_DATA1 0x0473
+#define B43legacy_PHY_ILT_G_DATA2 0x0474
+#define B43legacy_PHY_G_PCTL 0x0029
+#define B43legacy_PHY_RADIO_BITFIELD 0x0401
+#define B43legacy_PHY_G_CRS 0x0429
+#define B43legacy_PHY_NRSSILT_CTRL 0x0803
+#define B43legacy_PHY_NRSSILT_DATA 0x0804
+
+/* RadioRegisters */
+#define B43legacy_RADIOCTL_ID 0x01
+
+/* MAC Control bitfield */
+#define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
+#define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
+#define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */
+#define B43legacy_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
+#define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */
+#define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
+#define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
+#define B43legacy_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
+#define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */
+
+/* StatusBitField */
+#define B43legacy_SBF_MAC_ENABLED 0x00000001
+#define B43legacy_SBF_CORE_READY 0x00000004
+#define B43legacy_SBF_400 0x00000400 /*FIXME: fix name*/
+#define B43legacy_SBF_XFER_REG_BYTESWAP 0x00010000
+#define B43legacy_SBF_MODE_NOTADHOC 0x00020000
+#define B43legacy_SBF_MODE_AP 0x00040000
+#define B43legacy_SBF_RADIOREG_LOCK 0x00080000
+#define B43legacy_SBF_MODE_MONITOR 0x00400000
+#define B43legacy_SBF_MODE_PROMISC 0x01000000
+#define B43legacy_SBF_PS1 0x02000000
+#define B43legacy_SBF_PS2 0x04000000
+#define B43legacy_SBF_NO_SSID_BCAST 0x08000000
+#define B43legacy_SBF_TIME_UPDATE 0x10000000
+
+/* 802.11 core specific TM State Low flags */
+#define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
+#define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */
+#define B43legacy_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Ctrl Enbl */
+#define B43legacy_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
+#define B43legacy_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
+
+/* 802.11 core specific TM State High flags */
+#define B43legacy_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available */
+#define B43legacy_TMSHIGH_GPHY 0x00010000 /* G-PHY avail (rev >= 5) */
+
+#define B43legacy_UCODEFLAG_AUTODIV 0x0001
+
+/* Generic-Interrupt reasons. */
+#define B43legacy_IRQ_MAC_SUSPENDED 0x00000001
+#define B43legacy_IRQ_BEACON 0x00000002
+#define B43legacy_IRQ_TBTT_INDI 0x00000004 /* Target Beacon Transmit Time */
+#define B43legacy_IRQ_BEACON_TX_OK 0x00000008
+#define B43legacy_IRQ_BEACON_CANCEL 0x00000010
+#define B43legacy_IRQ_ATIM_END 0x00000020
+#define B43legacy_IRQ_PMQ 0x00000040
+#define B43legacy_IRQ_PIO_WORKAROUND 0x00000100
+#define B43legacy_IRQ_MAC_TXERR 0x00000200
+#define B43legacy_IRQ_PHY_TXERR 0x00000800
+#define B43legacy_IRQ_PMEVENT 0x00001000
+#define B43legacy_IRQ_TIMER0 0x00002000
+#define B43legacy_IRQ_TIMER1 0x00004000
+#define B43legacy_IRQ_DMA 0x00008000
+#define B43legacy_IRQ_TXFIFO_FLUSH_OK 0x00010000
+#define B43legacy_IRQ_CCA_MEASURE_OK 0x00020000
+#define B43legacy_IRQ_NOISESAMPLE_OK 0x00040000
+#define B43legacy_IRQ_UCODE_DEBUG 0x08000000
+#define B43legacy_IRQ_RFKILL 0x10000000
+#define B43legacy_IRQ_TX_OK 0x20000000
+#define B43legacy_IRQ_PHY_G_CHANGED 0x40000000
+#define B43legacy_IRQ_TIMEOUT 0x80000000
+
+#define B43legacy_IRQ_ALL 0xFFFFFFFF
+#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \
+ B43legacy_IRQ_BEACON | \
+ B43legacy_IRQ_TBTT_INDI | \
+ B43legacy_IRQ_ATIM_END | \
+ B43legacy_IRQ_PMQ | \
+ B43legacy_IRQ_MAC_TXERR | \
+ B43legacy_IRQ_PHY_TXERR | \
+ B43legacy_IRQ_DMA | \
+ B43legacy_IRQ_TXFIFO_FLUSH_OK | \
+ B43legacy_IRQ_NOISESAMPLE_OK | \
+ B43legacy_IRQ_UCODE_DEBUG | \
+ B43legacy_IRQ_RFKILL | \
+ B43legacy_IRQ_TX_OK)
+
+/* Device specific rate values.
+ * The actual values defined here are (rate_in_mbps * 2).
+ * Some code depends on this. Don't change it. */
+#define B43legacy_CCK_RATE_1MB 2
+#define B43legacy_CCK_RATE_2MB 4
+#define B43legacy_CCK_RATE_5MB 11
+#define B43legacy_CCK_RATE_11MB 22
+#define B43legacy_OFDM_RATE_6MB 12
+#define B43legacy_OFDM_RATE_9MB 18
+#define B43legacy_OFDM_RATE_12MB 24
+#define B43legacy_OFDM_RATE_18MB 36
+#define B43legacy_OFDM_RATE_24MB 48
+#define B43legacy_OFDM_RATE_36MB 72
+#define B43legacy_OFDM_RATE_48MB 96
+#define B43legacy_OFDM_RATE_54MB 108
+/* Convert a b43legacy rate value to a rate in 100kbps */
+#define B43legacy_RATE_TO_100KBPS(rate) (((rate) * 10) / 2)
+
+
+#define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7
+#define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4
+
+/* Max size of a security key */
+#define B43legacy_SEC_KEYSIZE 16
+/* Security algorithms. */
+enum {
+ B43legacy_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+ B43legacy_SEC_ALGO_WEP40,
+ B43legacy_SEC_ALGO_TKIP,
+ B43legacy_SEC_ALGO_AES,
+ B43legacy_SEC_ALGO_WEP104,
+ B43legacy_SEC_ALGO_AES_LEGACY,
+};
+
+/* Core Information Registers */
+#define B43legacy_CIR_BASE 0xf00
+#define B43legacy_CIR_SBTPSFLAG (B43legacy_CIR_BASE + 0x18)
+#define B43legacy_CIR_SBIMSTATE (B43legacy_CIR_BASE + 0x90)
+#define B43legacy_CIR_SBINTVEC (B43legacy_CIR_BASE + 0x94)
+#define B43legacy_CIR_SBTMSTATELOW (B43legacy_CIR_BASE + 0x98)
+#define B43legacy_CIR_SBTMSTATEHIGH (B43legacy_CIR_BASE + 0x9c)
+#define B43legacy_CIR_SBIMCONFIGLOW (B43legacy_CIR_BASE + 0xa8)
+#define B43legacy_CIR_SB_ID_HI (B43legacy_CIR_BASE + 0xfc)
+
+/* sbtmstatehigh state flags */
+#define B43legacy_SBTMSTATEHIGH_SERROR 0x00000001
+#define B43legacy_SBTMSTATEHIGH_BUSY 0x00000004
+#define B43legacy_SBTMSTATEHIGH_TIMEOUT 0x00000020
+#define B43legacy_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000
+#define B43legacy_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
+#define B43legacy_SBTMSTATEHIGH_DMA64BIT 0x10000000
+#define B43legacy_SBTMSTATEHIGH_GATEDCLK 0x20000000
+#define B43legacy_SBTMSTATEHIGH_BISTFAILED 0x40000000
+#define B43legacy_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
+
+/* sbimstate flags */
+#define B43legacy_SBIMSTATE_IB_ERROR 0x20000
+#define B43legacy_SBIMSTATE_TIMEOUT 0x40000
+
+#define PFX KBUILD_MODNAME ": "
+#ifdef assert
+# undef assert
+#endif
+#ifdef CONFIG_B43LEGACY_DEBUG
+# define B43legacy_WARN_ON(expr) \
+ do { \
+ if (unlikely((expr))) { \
+ printk(KERN_INFO PFX "Test (%s) failed at:" \
+ " %s:%d:%s()\n", \
+ #expr, __FILE__, \
+ __LINE__, __FUNCTION__); \
+ } \
+ } while (0)
+# define B43legacy_BUG_ON(expr) \
+ do { \
+ if (unlikely((expr))) { \
+ printk(KERN_INFO PFX "Test (%s) failed\n", \
+ #expr); \
+ BUG_ON(expr); \
+ } \
+ } while (0)
+# define B43legacy_DEBUG 1
+#else
+# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0)
+# define B43legacy_BUG_ON(x) do { /* nothing */ } while (0)
+# define B43legacy_DEBUG 0
+#endif
+
+
+struct net_device;
+struct pci_dev;
+struct b43legacy_dmaring;
+struct b43legacy_pioqueue;
+
+/* The firmware file header */
+#define B43legacy_FW_TYPE_UCODE 'u'
+#define B43legacy_FW_TYPE_PCM 'p'
+#define B43legacy_FW_TYPE_IV 'i'
+struct b43legacy_fw_header {
+ /* File type */
+ u8 type;
+ /* File format version */
+ u8 ver;
+ u8 __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is number-of-ivs. */
+ __be32 size;
+} __attribute__((__packed__));
+
+/* Initial Value file format */
+#define B43legacy_IV_OFFSET_MASK 0x7FFF
+#define B43legacy_IV_32BIT 0x8000
+struct b43legacy_iv {
+ __be16 offset_size;
+ union {
+ __be16 d16;
+ __be32 d32;
+ } data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+#define B43legacy_PHYMODE(phytype) (1 << (phytype))
+#define B43legacy_PHYMODE_B B43legacy_PHYMODE \
+ ((B43legacy_PHYTYPE_B))
+#define B43legacy_PHYMODE_G B43legacy_PHYMODE \
+ ((B43legacy_PHYTYPE_G))
+
+/* Value pair to measure the LocalOscillator. */
+struct b43legacy_lopair {
+ s8 low;
+ s8 high;
+ u8 used:1;
+};
+#define B43legacy_LO_COUNT (14*4)
+
+struct b43legacy_phy {
+ /* Possible PHYMODEs on this PHY */
+ u8 possible_phymodes;
+ /* GMODE bit enabled in MACCTL? */
+ bool gmode;
+ /* Possible ieee80211 subsystem hwmodes for this PHY.
+ * Which mode is selected, depends on thr GMODE enabled bit */
+#define B43legacy_MAX_PHYHWMODES 2
+ struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES];
+
+ /* Analog Type */
+ u8 analog;
+ /* B43legacy_PHYTYPE_ */
+ u8 type;
+ /* PHY revision number. */
+ u8 rev;
+
+ u16 antenna_diversity;
+ u16 savedpctlreg;
+ /* Radio versioning */
+ u16 radio_manuf; /* Radio manufacturer */
+ u16 radio_ver; /* Radio version */
+ u8 calibrated:1;
+ u8 radio_rev; /* Radio revision */
+
+ bool locked; /* Only used in b43legacy_phy_{un}lock() */
+ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
+
+ /* ACI (adjacent channel interference) flags. */
+ bool aci_enable;
+ bool aci_wlan_automatic;
+ bool aci_hw_rssi;
+
+ /* Radio switched on/off */
+ bool radio_on;
+ struct {
+ /* Values saved when turning the radio off.
+ * They are needed when turning it on again. */
+ bool valid;
+ u16 rfover;
+ u16 rfoverval;
+ } radio_off_context;
+
+ u16 minlowsig[2];
+ u16 minlowsigpos[2];
+
+ /* LO Measurement Data.
+ * Use b43legacy_get_lopair() to get a value.
+ */
+ struct b43legacy_lopair *_lo_pairs;
+ /* TSSI to dBm table in use */
+ const s8 *tssi2dbm;
+ /* idle TSSI value */
+ s8 idle_tssi;
+ /* Target idle TSSI */
+ int tgt_idle_tssi;
+ /* Current idle TSSI */
+ int cur_idle_tssi;
+
+ /* LocalOscillator control values. */
+ struct b43legacy_txpower_lo_control *lo_control;
+ /* Values from b43legacy_calc_loopback_gain() */
+ s16 max_lb_gain; /* Maximum Loopback gain in hdB */
+ s16 trsw_rx_gain; /* TRSW RX gain in hdB */
+ s16 lna_lod_gain; /* LNA lod */
+ s16 lna_gain; /* LNA */
+ s16 pga_gain; /* PGA */
+
+ /* PHY lock for core.rev < 3
+ * This lock is only used by b43legacy_phy_{un}lock()
+ */
+ spinlock_t lock;
+
+ /* Desired TX power level (in dBm). This is set by the user and
+ * adjusted in b43legacy_phy_xmitpower(). */
+ u8 power_level;
+
+ /* Values from b43legacy_calc_loopback_gain() */
+ u16 loopback_gain[2];
+
+ /* TX Power control values. */
+ /* B/G PHY */
+ struct {
+ /* Current Radio Attenuation for TXpower recalculation. */
+ u16 rfatt;
+ /* Current Baseband Attenuation for TXpower recalculation. */
+ u16 bbatt;
+ /* Current TXpower control value for TXpower recalculation. */
+ u16 txctl1;
+ u16 txctl2;
+ };
+ /* A PHY */
+ struct {
+ u16 txpwr_offset;
+ };
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+ bool manual_txpower_control; /* Manual TX-power control enabled? */
+#endif
+ /* Current Interference Mitigation mode */
+ int interfmode;
+ /* Stack of saved values from the Interference Mitigation code.
+ * Each value in the stack is layed out as follows:
+ * bit 0-11: offset
+ * bit 12-15: register ID
+ * bit 16-32: value
+ * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+ */
+#define B43legacy_INTERFSTACK_SIZE 26
+ u32 interfstack[B43legacy_INTERFSTACK_SIZE];
+
+ /* Saved values from the NRSSI Slope calculation */
+ s16 nrssi[2];
+ s32 nrssislope;
+ /* In memory nrssi lookup table. */
+ s8 nrssi_lt[64];
+
+ /* current channel */
+ u8 channel;
+
+ u16 lofcal;
+
+ u16 initval;
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct b43legacy_dma {
+ struct b43legacy_dmaring *tx_ring0;
+ struct b43legacy_dmaring *tx_ring1;
+ struct b43legacy_dmaring *tx_ring2;
+ struct b43legacy_dmaring *tx_ring3;
+ struct b43legacy_dmaring *tx_ring4;
+ struct b43legacy_dmaring *tx_ring5;
+
+ struct b43legacy_dmaring *rx_ring0;
+ struct b43legacy_dmaring *rx_ring3; /* only on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct b43legacy_pio {
+ struct b43legacy_pioqueue *queue0;
+ struct b43legacy_pioqueue *queue1;
+ struct b43legacy_pioqueue *queue2;
+ struct b43legacy_pioqueue *queue3;
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct b43legacy_noise_calculation {
+ u8 channel_at_start;
+ bool calculation_running;
+ u8 nr_samples;
+ s8 samples[8][4];
+};
+
+struct b43legacy_stats {
+ u8 link_noise;
+ /* Store the last TX/RX times here for updating the leds. */
+ unsigned long last_tx;
+ unsigned long last_rx;
+};
+
+struct b43legacy_key {
+ void *keyconf;
+ bool enabled;
+ u8 algorithm;
+};
+
+struct b43legacy_wldev;
+
+/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */
+struct b43legacy_wl {
+ /* Pointer to the active wireless device on this chip */
+ struct b43legacy_wldev *current_dev;
+ /* Pointer to the ieee80211 hardware data structure */
+ struct ieee80211_hw *hw;
+
+ spinlock_t irq_lock; /* locks IRQ */
+ struct mutex mutex; /* locks wireless core state */
+ spinlock_t leds_lock; /* lock for leds */
+
+ /* We can only have one operating interface (802.11 core)
+ * at a time. General information about this interface follows.
+ */
+
+ /* Opaque ID of the operating interface from the ieee80211
+ * subsystem. Do not modify.
+ */
+ int if_id;
+ /* MAC address (can be NULL). */
+ u8 mac_addr[ETH_ALEN];
+ /* Current BSSID (can be NULL). */
+ u8 bssid[ETH_ALEN];
+ /* Interface type. (IEEE80211_IF_TYPE_XXX) */
+ int if_type;
+ /* Is the card operating in AP, STA or IBSS mode? */
+ bool operating;
+ /* filter flags */
+ unsigned int filter_flags;
+ /* Stats about the wireless interface */
+ struct ieee80211_low_level_stats ieee_stats;
+
+ struct hwrng rng;
+ u8 rng_initialized;
+ char rng_name[30 + 1];
+
+ /* List of all wireless devices on this chip */
+ struct list_head devlist;
+ u8 nr_devs;
+};
+
+/* Pointers to the firmware data and meta information about it. */
+struct b43legacy_firmware {
+ /* Microcode */
+ const struct firmware *ucode;
+ /* PCM code */
+ const struct firmware *pcm;
+ /* Initial MMIO values for the firmware */
+ const struct firmware *initvals;
+ /* Initial MMIO values for the firmware, band-specific */
+ const struct firmware *initvals_band;
+ /* Firmware revision */
+ u16 rev;
+ /* Firmware patchlevel */
+ u16 patch;
+};
+
+/* Device (802.11 core) initialization status. */
+enum {
+ B43legacy_STAT_UNINIT = 0, /* Uninitialized. */
+ B43legacy_STAT_INITIALIZED = 1, /* Initialized, not yet started. */
+ B43legacy_STAT_STARTED = 2, /* Up and running. */
+};
+#define b43legacy_status(wldev) atomic_read(&(wldev)->__init_status)
+#define b43legacy_set_status(wldev, stat) do { \
+ atomic_set(&(wldev)->__init_status, (stat)); \
+ smp_wmb(); \
+ } while (0)
+
+/* *** --- HOW LOCKING WORKS IN B43legacy --- ***
+ *
+ * You should always acquire both, wl->mutex and wl->irq_lock unless:
+ * - You don't need to acquire wl->irq_lock, if the interface is stopped.
+ * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
+ * and packet TX path (and _ONLY_ there.)
+ */
+
+/* Data structure for one wireless device (802.11 core) */
+struct b43legacy_wldev {
+ struct ssb_device *dev;
+ struct b43legacy_wl *wl;
+
+ /* The device initialization status.
+ * Use b43legacy_status() to query. */
+ atomic_t __init_status;
+ /* Saved init status for handling suspend. */
+ int suspend_init_status;
+
+ bool __using_pio; /* Using pio rather than dma. */
+ bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
+ bool reg124_set_0x4; /* Variable to keep track of IRQ. */
+ bool short_preamble; /* TRUE if using short preamble. */
+ bool short_slot; /* TRUE if using short slot timing. */
+ bool radio_hw_enable; /* State of radio hardware enable bit. */
+
+ /* PHY/Radio device. */
+ struct b43legacy_phy phy;
+ union {
+ /* DMA engines. */
+ struct b43legacy_dma dma;
+ /* PIO engines. */
+ struct b43legacy_pio pio;
+ };
+
+ /* Various statistics about the physical device. */
+ struct b43legacy_stats stats;
+
+#define B43legacy_NR_LEDS 4
+ struct b43legacy_led leds[B43legacy_NR_LEDS];
+
+ /* Reason code of the last interrupt. */
+ u32 irq_reason;
+ u32 dma_reason[6];
+ /* saved irq enable/disable state bitfield. */
+ u32 irq_savedstate;
+ /* Link Quality calculation context. */
+ struct b43legacy_noise_calculation noisecalc;
+ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+ int mac_suspended;
+
+ /* Interrupt Service Routine tasklet (bottom-half) */
+ struct tasklet_struct isr_tasklet;
+
+ /* Periodic tasks */
+ struct delayed_work periodic_work;
+ unsigned int periodic_state;
+
+ struct work_struct restart_work;
+
+ /* encryption/decryption */
+ u16 ktp; /* Key table pointer */
+ u8 max_nr_keys;
+ struct b43legacy_key key[58];
+
+ /* Cached beacon template while uploading the template. */
+ struct sk_buff *cached_beacon;
+
+ /* Firmware data */
+ struct b43legacy_firmware fw;
+
+ /* Devicelist in struct b43legacy_wl (all 802.11 cores) */
+ struct list_head list;
+
+ /* Debugging stuff follows. */
+#ifdef CONFIG_B43LEGACY_DEBUG
+ struct b43legacy_dfsentry *dfsentry;
+#endif
+};
+
+
+static inline
+struct b43legacy_wl *hw_to_b43legacy_wl(struct ieee80211_hw *hw)
+{
+ return hw->priv;
+}
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+ return dev->__using_pio;
+}
+#elif defined(CONFIG_B43LEGACY_DMA)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+ return 0;
+}
+#elif defined(CONFIG_B43LEGACY_PIO)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+ return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+
+static inline
+struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ return ssb_get_drvdata(ssb_dev);
+}
+
+/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+static inline
+int b43legacy_is_mode(struct b43legacy_wl *wl, int type)
+{
+ return (wl->operating &&
+ wl->if_type == type);
+}
+
+static inline
+bool is_bcm_board_vendor(struct b43legacy_wldev *dev)
+{
+ return (dev->dev->bus->boardinfo.vendor == PCI_VENDOR_ID_BROADCOM);
+}
+
+static inline
+u16 b43legacy_read16(struct b43legacy_wldev *dev, u16 offset)
+{
+ return ssb_read16(dev->dev, offset);
+}
+
+static inline
+void b43legacy_write16(struct b43legacy_wldev *dev, u16 offset, u16 value)
+{
+ ssb_write16(dev->dev, offset, value);
+}
+
+static inline
+u32 b43legacy_read32(struct b43legacy_wldev *dev, u16 offset)
+{
+ return ssb_read32(dev->dev, offset);
+}
+
+static inline
+void b43legacy_write32(struct b43legacy_wldev *dev, u16 offset, u32 value)
+{
+ ssb_write32(dev->dev, offset, value);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_get_lopair(struct b43legacy_phy *phy,
+ u16 radio_attenuation,
+ u16 baseband_attenuation)
+{
+ return phy->_lo_pairs + (radio_attenuation
+ + 14 * (baseband_attenuation / 2));
+}
+
+
+
+/* Message printing */
+void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#if B43legacy_DEBUG
+void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#else /* DEBUG */
+# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
+#endif /* DEBUG */
+
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max) \
+ ({ \
+ typeof(value) __value = (value); \
+ typeof(value) __min = (min); \
+ typeof(value) __max = (max); \
+ if (__value < __min) \
+ __value = __min; \
+ else if (__value > __max) \
+ __value = __max; \
+ __value; \
+ })
+
+/* Macros for printing a value in Q5.2 format */
+#define Q52_FMT "%u.%u"
+#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4)
+
+#endif /* B43legacy_H_ */
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
new file mode 100644
index 000000000000..eefa6fb79685
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -0,0 +1,505 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ debugfs driver debugging code
+
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "debugfs.h"
+#include "dma.h"
+#include "pio.h"
+#include "xmit.h"
+
+
+/* The root directory. */
+static struct dentry *rootdir;
+
+struct b43legacy_debugfs_fops {
+ ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize);
+ int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count);
+ struct file_operations fops;
+ /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */
+ size_t file_struct_offset;
+ /* Take wl->irq_lock before calling read/write? */
+ bool take_irqlock;
+};
+
+static inline
+struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev,
+ const struct b43legacy_debugfs_fops *dfops)
+{
+ void *p;
+
+ p = dev->dfsentry;
+ p += dfops->file_struct_offset;
+
+ return p;
+}
+
+
+#define fappend(fmt, x...) \
+ do { \
+ if (bufsize - count) \
+ count += snprintf(buf + count, \
+ bufsize - count, \
+ fmt , ##x); \
+ else \
+ printk(KERN_ERR "b43legacy: fappend overflow\n"); \
+ } while (0)
+
+
+/* wl->irq_lock is locked */
+static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ u64 tsf;
+
+ b43legacy_tsf_read(dev, &tsf);
+ fappend("0x%08x%08x\n",
+ (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+ (unsigned int)(tsf & 0xFFFFFFFFULL));
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
+{
+ u64 tsf;
+
+ if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+ return -EINVAL;
+ b43legacy_tsf_write(dev, tsf);
+
+ return 0;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ fappend("r%d = 0x%04x\n", i,
+ b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i));
+ }
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+ u16 tmp;
+ __le16 *le16buf = (__le16 *)buf;
+
+ for (i = 0; i < 0x1000; i++) {
+ if (bufsize <= 0)
+ break;
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
+ le16buf[i] = cpu_to_le16(tmp);
+ count += sizeof(tmp);
+ bufsize -= sizeof(tmp);
+ }
+
+ return count;
+}
+
+static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog;
+ ssize_t count = 0;
+ unsigned long flags;
+ int i, idx;
+ struct b43legacy_txstatus *stat;
+
+ spin_lock_irqsave(&log->lock, flags);
+ if (log->end < 0) {
+ fappend("Nothing transmitted, yet\n");
+ goto out_unlock;
+ }
+ fappend("b43legacy TX status reports:\n\n"
+ "index | cookie | seq | phy_stat | frame_count | "
+ "rts_count | supp_reason | pm_indicated | "
+ "intermediate | for_ampdu | acked\n" "---\n");
+ i = log->end + 1;
+ idx = 0;
+ while (1) {
+ if (i == B43legacy_NR_LOGGED_TXSTATUS)
+ i = 0;
+ stat = &(log->log[i]);
+ if (stat->cookie) {
+ fappend("%03d | "
+ "0x%04X | 0x%04X | 0x%02X | "
+ "0x%X | 0x%X | "
+ "%u | %u | "
+ "%u | %u | %u\n",
+ idx,
+ stat->cookie, stat->seq, stat->phy_stat,
+ stat->frame_count, stat->rts_count,
+ stat->supp_reason, stat->pm_indicated,
+ stat->intermediate, stat->for_ampdu,
+ stat->acked);
+ idx++;
+ }
+ if (i == log->end)
+ break;
+ i++;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&log->lock, flags);
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
+{
+ int err = 0;
+
+ if (count > 0 && buf[0] == '1') {
+ b43legacy_controller_restart(dev, "manually restarted");
+ } else
+ err = -EINVAL;
+
+ return err;
+}
+
+#undef fappend
+
+static int b43legacy_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43legacy_wldev *dev;
+ struct b43legacy_debugfs_fops *dfops;
+ struct b43legacy_dfs_file *dfile;
+ ssize_t ret = 0;
+ char *buf;
+ const size_t bufsize = 1024 * 128;
+ const size_t buforder = get_order(bufsize);
+ int err = 0;
+
+ if (!count)
+ return 0;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
+ if (!dfops->read) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+ dfile = fops_to_dfs_file(dev, dfops);
+
+ if (!dfile->buffer) {
+ buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ memset(buf, 0, bufsize);
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ ret = dfops->read(dev, buf, bufsize);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ ret = dfops->read(dev, buf, bufsize);
+ if (ret <= 0) {
+ free_pages((unsigned long)buf, buforder);
+ err = ret;
+ goto out_unlock;
+ }
+ dfile->data_len = ret;
+ dfile->buffer = buf;
+ }
+
+ ret = simple_read_from_buffer(userbuf, count, ppos,
+ dfile->buffer,
+ dfile->data_len);
+ if (*ppos >= dfile->data_len) {
+ free_pages((unsigned long)dfile->buffer, buforder);
+ dfile->buffer = NULL;
+ dfile->data_len = 0;
+ }
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : ret;
+}
+
+static ssize_t b43legacy_debugfs_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43legacy_wldev *dev;
+ struct b43legacy_debugfs_fops *dfops;
+ char *buf;
+ int err = 0;
+
+ if (!count)
+ return 0;
+ if (count > PAGE_SIZE)
+ return -E2BIG;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
+ if (!dfops->write) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ if (copy_from_user(buf, userbuf, count)) {
+ err = -EFAULT;
+ goto out_freepage;
+ }
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ err = dfops->write(dev, buf, count);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ err = dfops->write(dev, buf, count);
+ if (err)
+ goto out_freepage;
+
+out_freepage:
+ free_page((unsigned long)buf);
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : count;
+}
+
+
+#define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
+ static struct b43legacy_debugfs_fops fops_##name = { \
+ .read = _read, \
+ .write = _write, \
+ .fops = { \
+ .open = b43legacy_debugfs_open, \
+ .read = b43legacy_debugfs_read, \
+ .write = b43legacy_debugfs_write, \
+ }, \
+ .file_struct_offset = offsetof(struct b43legacy_dfsentry, \
+ file_##name), \
+ .take_irqlock = _take_irqlock, \
+ }
+
+B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
+B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
+B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
+B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
+B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
+
+
+int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
+{
+ return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
+}
+
+static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e = dev->dfsentry;
+ int i;
+
+ for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
+ debugfs_remove(e->dyn_debug_dentries[i]);
+}
+
+static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e = dev->dfsentry;
+ struct dentry *d;
+
+#define add_dyn_dbg(name, id, initstate) do { \
+ e->dyn_debug[id] = (initstate); \
+ d = debugfs_create_bool(name, 0600, e->subdir, \
+ &(e->dyn_debug[id])); \
+ if (!IS_ERR(d)) \
+ e->dyn_debug_dentries[id] = d; \
+ } while (0)
+
+ add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0);
+ add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0);
+ add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0);
+ add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0);
+ add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0);
+
+#undef add_dyn_dbg
+}
+
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e;
+ struct b43legacy_txstatus_log *log;
+ char devdir[16];
+
+ B43legacy_WARN_ON(!dev);
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ if (!e) {
+ b43legacyerr(dev->wl, "debugfs: add device OOM\n");
+ return;
+ }
+ e->dev = dev;
+ log = &e->txstatlog;
+ log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS,
+ sizeof(struct b43legacy_txstatus), GFP_KERNEL);
+ if (!log->log) {
+ b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n");
+ kfree(e);
+ return;
+ }
+ log->end = -1;
+ spin_lock_init(&log->lock);
+
+ dev->dfsentry = e;
+
+ snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
+ e->subdir = debugfs_create_dir(devdir, rootdir);
+ if (!e->subdir || IS_ERR(e->subdir)) {
+ if (e->subdir == ERR_PTR(-ENODEV)) {
+ b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
+ "enabled in kernel config\n");
+ } else {
+ b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n",
+ devdir);
+ }
+ dev->dfsentry = NULL;
+ kfree(log->log);
+ kfree(e);
+ return;
+ }
+
+#define ADD_FILE(name, mode) \
+ do { \
+ struct dentry *d; \
+ d = debugfs_create_file(__stringify(name), \
+ mode, e->subdir, dev, \
+ &fops_##name.fops); \
+ e->file_##name.dentry = NULL; \
+ if (!IS_ERR(d)) \
+ e->file_##name.dentry = d; \
+ } while (0)
+
+
+ ADD_FILE(tsf, 0600);
+ ADD_FILE(ucode_regs, 0400);
+ ADD_FILE(shm, 0400);
+ ADD_FILE(txstat, 0400);
+ ADD_FILE(restart, 0200);
+
+#undef ADD_FILE
+
+ b43legacy_add_dynamic_debug(dev);
+}
+
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e;
+
+ if (!dev)
+ return;
+ e = dev->dfsentry;
+ if (!e)
+ return;
+ b43legacy_remove_dynamic_debug(dev);
+
+ debugfs_remove(e->file_tsf.dentry);
+ debugfs_remove(e->file_ucode_regs.dentry);
+ debugfs_remove(e->file_shm.dentry);
+ debugfs_remove(e->file_txstat.dentry);
+ debugfs_remove(e->file_restart.dentry);
+
+ debugfs_remove(e->subdir);
+ kfree(e->txstatlog.log);
+ kfree(e);
+}
+
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ struct b43legacy_dfsentry *e = dev->dfsentry;
+ struct b43legacy_txstatus_log *log;
+ struct b43legacy_txstatus *cur;
+ int i;
+
+ if (!e)
+ return;
+ log = &e->txstatlog;
+ B43legacy_WARN_ON(!irqs_disabled());
+ spin_lock(&log->lock);
+ i = log->end + 1;
+ if (i == B43legacy_NR_LOGGED_TXSTATUS)
+ i = 0;
+ log->end = i;
+ cur = &(log->log[i]);
+ memcpy(cur, status, sizeof(*cur));
+ spin_unlock(&log->lock);
+}
+
+void b43legacy_debugfs_init(void)
+{
+ rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(rootdir))
+ rootdir = NULL;
+}
+
+void b43legacy_debugfs_exit(void)
+{
+ debugfs_remove(rootdir);
+}
diff --git a/drivers/net/wireless/b43legacy/debugfs.h b/drivers/net/wireless/b43legacy/debugfs.h
new file mode 100644
index 000000000000..ae3b0d0fa849
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.h
@@ -0,0 +1,89 @@
+#ifndef B43legacy_DEBUGFS_H_
+#define B43legacy_DEBUGFS_H_
+
+struct b43legacy_wldev;
+struct b43legacy_txstatus;
+
+enum b43legacy_dyndbg { /* Dynamic debugging features */
+ B43legacy_DBG_XMITPOWER,
+ B43legacy_DBG_DMAOVERFLOW,
+ B43legacy_DBG_DMAVERBOSE,
+ B43legacy_DBG_PWORK_FAST,
+ B43legacy_DBG_PWORK_STOP,
+ __B43legacy_NR_DYNDBG,
+};
+
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+
+struct dentry;
+
+#define B43legacy_NR_LOGGED_TXSTATUS 100
+
+struct b43legacy_txstatus_log {
+ struct b43legacy_txstatus *log;
+ int end;
+ spinlock_t lock; /* lock for debugging */
+};
+
+struct b43legacy_dfs_file {
+ struct dentry *dentry;
+ char *buffer;
+ size_t data_len;
+};
+
+struct b43legacy_dfsentry {
+ struct b43legacy_wldev *dev;
+ struct dentry *subdir;
+
+ struct b43legacy_dfs_file file_tsf;
+ struct b43legacy_dfs_file file_ucode_regs;
+ struct b43legacy_dfs_file file_shm;
+ struct b43legacy_dfs_file file_txstat;
+ struct b43legacy_dfs_file file_txpower_g;
+ struct b43legacy_dfs_file file_restart;
+ struct b43legacy_dfs_file file_loctls;
+
+ struct b43legacy_txstatus_log txstatlog;
+
+ /* Enabled/Disabled list for the dynamic debugging features. */
+ u32 dyn_debug[__B43legacy_NR_DYNDBG];
+ /* Dentries for the dynamic debugging entries. */
+ struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG];
+};
+
+int b43legacy_debug(struct b43legacy_wldev *dev,
+ enum b43legacy_dyndbg feature);
+
+void b43legacy_debugfs_init(void);
+void b43legacy_debugfs_exit(void);
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev);
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev);
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+
+#else /* CONFIG_B43LEGACY_DEBUG*/
+
+static inline
+int b43legacy_debug(struct b43legacy_wldev *dev,
+ enum b43legacy_dyndbg feature)
+{
+ return 0;
+}
+
+static inline
+void b43legacy_debugfs_init(void) { }
+static inline
+void b43legacy_debugfs_exit(void) { }
+static inline
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) { }
+static inline
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) { }
+static inline
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+ { }
+
+#endif /* CONFIG_B43LEGACY_DEBUG*/
+
+#endif /* B43legacy_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
new file mode 100644
index 000000000000..8cb3dc4c4745
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -0,0 +1,1565 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ DMA ringbuffer and descriptor allocation/management
+
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+
+ Some code in this file is derived from the b44.c driver
+ Copyright (C) 2002 David S. Miller
+ Copyright (C) Pekka Pietikainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "dma.h"
+#include "main.h"
+#include "debugfs.h"
+#include "xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <net/dst.h>
+
+/* 32bit DMA ops. */
+static
+struct b43legacy_dmadesc_generic *op32_idx2desc(
+ struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta **meta)
+{
+ struct b43legacy_dmadesc32 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43legacy_dmadesc_generic *)desc;
+}
+
+static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43legacy_dmadesc32 *descbase = ring->descbase;
+ int slot;
+ u32 ctl;
+ u32 addr;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma32) - descbase);
+ B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addr |= ssb_dma_translation(ring->dev->dev);
+ ctl = (bufsize - ring->frameoffset)
+ & B43legacy_DMA32_DCTL_BYTECNT;
+ if (slot == ring->nr_slots - 1)
+ ctl |= B43legacy_DMA32_DCTL_DTABLEEND;
+ if (start)
+ ctl |= B43legacy_DMA32_DCTL_FRAMESTART;
+ if (end)
+ ctl |= B43legacy_DMA32_DCTL_FRAMEEND;
+ if (irq)
+ ctl |= B43legacy_DMA32_DCTL_IRQ;
+ ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT)
+ & B43legacy_DMA32_DCTL_ADDREXT_MASK;
+
+ desc->dma32.control = cpu_to_le32(ctl);
+ desc->dma32.address = cpu_to_le32(addr);
+}
+
+static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
+}
+
+static void op32_tx_suspend(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
+ | B43legacy_DMA32_TXSUSPEND);
+}
+
+static void op32_tx_resume(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
+ & ~B43legacy_DMA32_TXSUSPEND);
+}
+
+static int op32_get_current_rxslot(struct b43legacy_dmaring *ring)
+{
+ u32 val;
+
+ val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS);
+ val &= B43legacy_DMA32_RXDPTR;
+
+ return (val / sizeof(struct b43legacy_dmadesc32));
+}
+
+static void op32_set_current_rxslot(struct b43legacy_dmaring *ring,
+ int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
+}
+
+static const struct b43legacy_dma_ops dma32_ops = {
+ .idx2desc = op32_idx2desc,
+ .fill_descriptor = op32_fill_descriptor,
+ .poke_tx = op32_poke_tx,
+ .tx_suspend = op32_tx_suspend,
+ .tx_resume = op32_tx_resume,
+ .get_current_rxslot = op32_get_current_rxslot,
+ .set_current_rxslot = op32_set_current_rxslot,
+};
+
+/* 64bit DMA ops. */
+static
+struct b43legacy_dmadesc_generic *op64_idx2desc(
+ struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta
+ **meta)
+{
+ struct b43legacy_dmadesc64 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43legacy_dmadesc_generic *)desc;
+}
+
+static void op64_fill_descriptor(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43legacy_dmadesc64 *descbase = ring->descbase;
+ int slot;
+ u32 ctl0 = 0;
+ u32 ctl1 = 0;
+ u32 addrlo;
+ u32 addrhi;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma64) - descbase);
+ B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+ addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addrhi |= ssb_dma_translation(ring->dev->dev);
+ if (slot == ring->nr_slots - 1)
+ ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND;
+ if (start)
+ ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART;
+ if (end)
+ ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND;
+ if (irq)
+ ctl0 |= B43legacy_DMA64_DCTL0_IRQ;
+ ctl1 |= (bufsize - ring->frameoffset)
+ & B43legacy_DMA64_DCTL1_BYTECNT;
+ ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT)
+ & B43legacy_DMA64_DCTL1_ADDREXT_MASK;
+
+ desc->dma64.control0 = cpu_to_le32(ctl0);
+ desc->dma64.control1 = cpu_to_le32(ctl1);
+ desc->dma64.address_low = cpu_to_le32(addrlo);
+ desc->dma64.address_high = cpu_to_le32(addrhi);
+}
+
+static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
+}
+
+static void op64_tx_suspend(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
+ | B43legacy_DMA64_TXSUSPEND);
+}
+
+static void op64_tx_resume(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
+ & ~B43legacy_DMA64_TXSUSPEND);
+}
+
+static int op64_get_current_rxslot(struct b43legacy_dmaring *ring)
+{
+ u32 val;
+
+ val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS);
+ val &= B43legacy_DMA64_RXSTATDPTR;
+
+ return (val / sizeof(struct b43legacy_dmadesc64));
+}
+
+static void op64_set_current_rxslot(struct b43legacy_dmaring *ring,
+ int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
+}
+
+static const struct b43legacy_dma_ops dma64_ops = {
+ .idx2desc = op64_idx2desc,
+ .fill_descriptor = op64_fill_descriptor,
+ .poke_tx = op64_poke_tx,
+ .tx_suspend = op64_tx_suspend,
+ .tx_resume = op64_tx_resume,
+ .get_current_rxslot = op64_get_current_rxslot,
+ .set_current_rxslot = op64_set_current_rxslot,
+};
+
+
+static inline int free_slots(struct b43legacy_dmaring *ring)
+{
+ return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct b43legacy_dmaring *ring, int slot)
+{
+ B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
+ if (slot == ring->nr_slots - 1)
+ return 0;
+ return slot + 1;
+}
+
+static inline int prev_slot(struct b43legacy_dmaring *ring, int slot)
+{
+ B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
+ if (slot == 0)
+ return ring->nr_slots - 1;
+ return slot - 1;
+}
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+static void update_max_used_slots(struct b43legacy_dmaring *ring,
+ int current_used_slots)
+{
+ if (current_used_slots <= ring->max_used_slots)
+ return;
+ ring->max_used_slots = current_used_slots;
+ if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacydbg(ring->dev->wl,
+ "max_used_slots increased to %d on %s ring %d\n",
+ ring->max_used_slots,
+ ring->tx ? "TX" : "RX",
+ ring->index);
+}
+#else
+static inline
+void update_max_used_slots(struct b43legacy_dmaring *ring,
+ int current_used_slots)
+{ }
+#endif /* DEBUG */
+
+/* Request a slot for usage. */
+static inline
+int request_slot(struct b43legacy_dmaring *ring)
+{
+ int slot;
+
+ B43legacy_WARN_ON(!ring->tx);
+ B43legacy_WARN_ON(ring->stopped);
+ B43legacy_WARN_ON(free_slots(ring) == 0);
+
+ slot = next_slot(ring, ring->current_slot);
+ ring->current_slot = slot;
+ ring->used_slots++;
+
+ update_max_used_slots(ring, ring->used_slots);
+
+ return slot;
+}
+
+/* Mac80211-queue to b43legacy-ring mapping */
+static struct b43legacy_dmaring *priority_to_txring(
+ struct b43legacy_wldev *dev,
+ int queue_priority)
+{
+ struct b43legacy_dmaring *ring;
+
+/*FIXME: For now we always run on TX-ring-1 */
+return dev->dma.tx_ring1;
+
+ /* 0 = highest priority */
+ switch (queue_priority) {
+ default:
+ B43legacy_WARN_ON(1);
+ /* fallthrough */
+ case 0:
+ ring = dev->dma.tx_ring3;
+ break;
+ case 1:
+ ring = dev->dma.tx_ring2;
+ break;
+ case 2:
+ ring = dev->dma.tx_ring1;
+ break;
+ case 3:
+ ring = dev->dma.tx_ring0;
+ break;
+ case 4:
+ ring = dev->dma.tx_ring4;
+ break;
+ case 5:
+ ring = dev->dma.tx_ring5;
+ break;
+ }
+
+ return ring;
+}
+
+/* Bcm4301-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct b43legacy_dmaring *ring)
+{
+ static const u8 idx_to_prio[] =
+ { 3, 2, 1, 0, 4, 5, };
+
+/*FIXME: have only one queue, for now */
+return 0;
+
+ return idx_to_prio[ring->index];
+}
+
+
+u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
+{
+ static const u16 map64[] = {
+ B43legacy_MMIO_DMA64_BASE0,
+ B43legacy_MMIO_DMA64_BASE1,
+ B43legacy_MMIO_DMA64_BASE2,
+ B43legacy_MMIO_DMA64_BASE3,
+ B43legacy_MMIO_DMA64_BASE4,
+ B43legacy_MMIO_DMA64_BASE5,
+ };
+ static const u16 map32[] = {
+ B43legacy_MMIO_DMA32_BASE0,
+ B43legacy_MMIO_DMA32_BASE1,
+ B43legacy_MMIO_DMA32_BASE2,
+ B43legacy_MMIO_DMA32_BASE3,
+ B43legacy_MMIO_DMA32_BASE4,
+ B43legacy_MMIO_DMA32_BASE5,
+ };
+
+ if (dma64bit) {
+ B43legacy_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map64)));
+ return map64[controller_idx];
+ }
+ B43legacy_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map32)));
+ return map32[controller_idx];
+}
+
+static inline
+dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
+ unsigned char *buf,
+ size_t len,
+ int tx)
+{
+ dma_addr_t dmaaddr;
+
+ if (tx)
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len,
+ DMA_TO_DEVICE);
+ else
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len,
+ DMA_FROM_DEVICE);
+
+ return dmaaddr;
+}
+
+static inline
+void unmap_descbuffer(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t len,
+ int tx)
+{
+ if (tx)
+ dma_unmap_single(ring->dev->dev->dev,
+ addr, len,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_single(ring->dev->dev->dev,
+ addr, len,
+ DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t len)
+{
+ B43legacy_WARN_ON(ring->tx);
+
+ dma_sync_single_for_cpu(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t len)
+{
+ B43legacy_WARN_ON(ring->tx);
+
+ dma_sync_single_for_device(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void free_descriptor_buffer(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_meta *meta,
+ int irq_context)
+{
+ if (meta->skb) {
+ if (irq_context)
+ dev_kfree_skb_irq(meta->skb);
+ else
+ dev_kfree_skb(meta->skb);
+ meta->skb = NULL;
+ }
+}
+
+static int alloc_ringmemory(struct b43legacy_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
+ &(ring->dmabase), GFP_KERNEL);
+ if (!ring->descbase) {
+ b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
+ " failed\n");
+ return -ENOMEM;
+ }
+ memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE);
+
+ return 0;
+}
+
+static void free_ringmemory(struct b43legacy_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+ b43legacy_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43legacy_DMA64_RXSTATUS :
+ B43legacy_DMA32_RXSTATUS;
+ value = b43legacy_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43legacy_DMA64_RXSTAT;
+ if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43legacy_DMA32_RXSTATE;
+ if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43legacyerr(dev->wl, "DMA RX reset timed out\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* Reset the RX DMA channel */
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43legacy_DMA64_TXSTATUS :
+ B43legacy_DMA32_TXSTATUS;
+ value = b43legacy_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43legacy_DMA64_TXSTAT;
+ if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
+ value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
+ value == B43legacy_DMA64_TXSTAT_STOPPED)
+ break;
+ } else {
+ value &= B43legacy_DMA32_TXSTATE;
+ if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
+ value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
+ value == B43legacy_DMA32_TXSTAT_STOPPED)
+ break;
+ }
+ msleep(1);
+ }
+ offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL;
+ b43legacy_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43legacy_DMA64_TXSTATUS :
+ B43legacy_DMA32_TXSTATUS;
+ value = b43legacy_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43legacy_DMA64_TXSTAT;
+ if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43legacy_DMA32_TXSTATE;
+ if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43legacyerr(dev->wl, "DMA TX reset timed out\n");
+ return -ENODEV;
+ }
+ /* ensure the reset is completed. */
+ msleep(1);
+
+ return 0;
+}
+
+static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ struct b43legacy_dmadesc_meta *meta,
+ gfp_t gfp_flags)
+{
+ struct b43legacy_rxhdr_fw3 *rxhdr;
+ struct b43legacy_hwtxstatus *txstat;
+ dma_addr_t dmaaddr;
+ struct sk_buff *skb;
+
+ B43legacy_WARN_ON(ring->tx);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ if (dma_mapping_error(dmaaddr)) {
+ /* ugh. try to realloc in zone_dma */
+ gfp_flags |= GFP_DMA;
+
+ dev_kfree_skb_any(skb);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ }
+
+ if (dma_mapping_error(dmaaddr)) {
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ meta->skb = skb;
+ meta->dmaaddr = dmaaddr;
+ ring->ops->fill_descriptor(ring, desc, dmaaddr,
+ ring->rx_buffersize, 0, 0, 0);
+
+ rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data);
+ rxhdr->frame_len = 0;
+ txstat = (struct b43legacy_hwtxstatus *)(skb->data);
+ txstat->cookie = 0;
+
+ return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring)
+{
+ int i;
+ int err = -ENOMEM;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+ if (err) {
+ b43legacyerr(ring->dev->wl,
+ "Failed to allocate initial descbuffers\n");
+ goto err_unwind;
+ }
+ }
+ mb(); /* all descbuffer setup before next line */
+ ring->used_slots = ring->nr_slots;
+ err = 0;
+out:
+ return err;
+
+err_unwind:
+ for (i--; i >= 0; i--) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+ dev_kfree_skb(meta->skb);
+ }
+ goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct b43legacy_dmaring *ring)
+{
+ int err = 0;
+ u32 value;
+ u32 addrext;
+ u32 trans = ssb_dma_translation(ring->dev->dev);
+
+ if (ring->tx) {
+ if (ring->dma64) {
+ u64 ringbase = (u64)(ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43legacy_DMA64_TXENABLE;
+ value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT)
+ & B43legacy_DMA64_TXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI,
+ ((ringbase >> 32)
+ & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ } else {
+ u32 ringbase = (u32)(ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43legacy_DMA32_TXENABLE;
+ value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
+ & B43legacy_DMA32_TXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
+ (ringbase &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ }
+ } else {
+ err = alloc_initial_descbuffers(ring);
+ if (err)
+ goto out;
+ if (ring->dma64) {
+ u64 ringbase = (u64)(ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset <<
+ B43legacy_DMA64_RXFROFF_SHIFT);
+ value |= B43legacy_DMA64_RXENABLE;
+ value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT)
+ & B43legacy_DMA64_RXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI,
+ ((ringbase >> 32) &
+ ~SSB_DMA_TRANSLATION_MASK) |
+ trans);
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
+ 200);
+ } else {
+ u32 ringbase = (u32)(ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset <<
+ B43legacy_DMA32_RXFROFF_SHIFT);
+ value |= B43legacy_DMA32_RXENABLE;
+ value |= (addrext <<
+ B43legacy_DMA32_RXADDREXT_SHIFT)
+ & B43legacy_DMA32_RXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
+ (ringbase &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
+ 200);
+ }
+ }
+
+out:
+ return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
+{
+ if (ring->tx) {
+ b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
+ } else
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
+ } else {
+ b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
+ } else
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
+ }
+}
+
+static void free_all_descbuffers(struct b43legacy_dmaring *ring)
+{
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ int i;
+
+ if (!ring->used_slots)
+ return;
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ if (!meta->skb) {
+ B43legacy_WARN_ON(!ring->tx);
+ continue;
+ }
+ if (ring->tx)
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
+ else
+ unmap_descbuffer(ring, meta->dmaaddr,
+ ring->rx_buffersize, 0);
+ free_descriptor_buffer(ring, meta, 0);
+ }
+}
+
+static u64 supported_dma_mask(struct b43legacy_wldev *dev)
+{
+ u32 tmp;
+ u16 mmio_base;
+
+ tmp = b43legacy_read32(dev, SSB_TMSHIGH);
+ if (tmp & SSB_TMSHIGH_DMA64)
+ return DMA_64BIT_MASK;
+ mmio_base = b43legacy_dmacontroller_base(0, 0);
+ b43legacy_write32(dev,
+ mmio_base + B43legacy_DMA32_TXCTL,
+ B43legacy_DMA32_TXADDREXT_MASK);
+ tmp = b43legacy_read32(dev, mmio_base +
+ B43legacy_DMA32_TXCTL);
+ if (tmp & B43legacy_DMA32_TXADDREXT_MASK)
+ return DMA_32BIT_MASK;
+
+ return DMA_30BIT_MASK;
+}
+
+/* Main initialization function. */
+static
+struct b43legacy_dmaring *b43legacy_setup_dmaring(
+ struct b43legacy_wldev *dev,
+ int controller_index,
+ int for_tx,
+ int dma64)
+{
+ struct b43legacy_dmaring *ring;
+ int err;
+ int nr_slots;
+ dma_addr_t dma_test;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out;
+
+ nr_slots = B43legacy_RXRING_SLOTS;
+ if (for_tx)
+ nr_slots = B43legacy_TXRING_SLOTS;
+
+ ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta),
+ GFP_KERNEL);
+ if (!ring->meta)
+ goto err_kfree_ring;
+ if (for_tx) {
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct b43legacy_txhdr_fw3),
+ GFP_KERNEL);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ /* test for ability to dma to txhdr_cache */
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test)) {
+ /* ugh realloc */
+ kfree(ring->txhdr_cache);
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct b43legacy_txhdr_fw3),
+ GFP_KERNEL | GFP_DMA);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test))
+ goto err_kfree_txhdr_cache;
+ }
+
+ dma_unmap_single(dev->dev->dev,
+ dma_test, sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
+ }
+
+ ring->dev = dev;
+ ring->nr_slots = nr_slots;
+ ring->mmio_base = b43legacy_dmacontroller_base(dma64,
+ controller_index);
+ ring->index = controller_index;
+ ring->dma64 = !!dma64;
+ if (dma64)
+ ring->ops = &dma64_ops;
+ else
+ ring->ops = &dma32_ops;
+ if (for_tx) {
+ ring->tx = 1;
+ ring->current_slot = -1;
+ } else {
+ if (ring->index == 0) {
+ ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE;
+ ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET;
+ } else if (ring->index == 3) {
+ ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE;
+ ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET;
+ } else
+ B43legacy_WARN_ON(1);
+ }
+ spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43LEGACY_DEBUG
+ ring->last_injected_overflow = jiffies;
+#endif
+
+ err = alloc_ringmemory(ring);
+ if (err)
+ goto err_kfree_txhdr_cache;
+ err = dmacontroller_setup(ring);
+ if (err)
+ goto err_free_ringmemory;
+
+out:
+ return ring;
+
+err_free_ringmemory:
+ free_ringmemory(ring);
+err_kfree_txhdr_cache:
+ kfree(ring->txhdr_cache);
+err_kfree_meta:
+ kfree(ring->meta);
+err_kfree_ring:
+ kfree(ring);
+ ring = NULL;
+ goto out;
+}
+
+/* Main cleanup function. */
+static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
+{
+ if (!ring)
+ return;
+
+ b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:"
+ " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base,
+ (ring->tx) ? "TX" : "RX",
+ ring->max_used_slots, ring->nr_slots);
+ /* Device IRQs are disabled prior entering this function,
+ * so no need to take care of concurrency with rx handler stuff.
+ */
+ dmacontroller_cleanup(ring);
+ free_all_descbuffers(ring);
+ free_ringmemory(ring);
+
+ kfree(ring->txhdr_cache);
+ kfree(ring->meta);
+ kfree(ring);
+}
+
+void b43legacy_dma_free(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dma *dma;
+
+ if (b43legacy_using_pio(dev))
+ return;
+ dma = &dev->dma;
+
+ b43legacy_destroy_dmaring(dma->rx_ring3);
+ dma->rx_ring3 = NULL;
+ b43legacy_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+
+ b43legacy_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+}
+
+int b43legacy_dma_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dma *dma = &dev->dma;
+ struct b43legacy_dmaring *ring;
+ int err;
+ u64 dmamask;
+ int dma64 = 0;
+
+ dmamask = supported_dma_mask(dev);
+ if (dmamask == DMA_64BIT_MASK)
+ dma64 = 1;
+
+ err = ssb_dma_set_mask(dev->dev, dmamask);
+ if (err) {
+#ifdef BCM43XX_PIO
+ b43legacywarn(dev->wl, "DMA for this device not supported. "
+ "Falling back to PIO\n");
+ dev->__using_pio = 1;
+ return -EAGAIN;
+#else
+ b43legacyerr(dev->wl, "DMA for this device not supported and "
+ "no PIO support compiled in\n");
+ return -EOPNOTSUPP;
+#endif
+ }
+
+ err = -ENOMEM;
+ /* setup TX DMA channels. */
+ ring = b43legacy_setup_dmaring(dev, 0, 1, dma64);
+ if (!ring)
+ goto out;
+ dma->tx_ring0 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 1, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx0;
+ dma->tx_ring1 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 2, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx1;
+ dma->tx_ring2 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 3, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx2;
+ dma->tx_ring3 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 4, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx3;
+ dma->tx_ring4 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 5, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx4;
+ dma->tx_ring5 = ring;
+
+ /* setup RX DMA channels. */
+ ring = b43legacy_setup_dmaring(dev, 0, 0, dma64);
+ if (!ring)
+ goto err_destroy_tx5;
+ dma->rx_ring0 = ring;
+
+ if (dev->dev->id.revision < 5) {
+ ring = b43legacy_setup_dmaring(dev, 3, 0, dma64);
+ if (!ring)
+ goto err_destroy_rx0;
+ dma->rx_ring3 = ring;
+ }
+
+ b43legacydbg(dev->wl, "%d-bit DMA initialized\n",
+ (dmamask == DMA_64BIT_MASK) ? 64 :
+ (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+ err = 0;
+out:
+ return err;
+
+err_destroy_rx0:
+ b43legacy_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+err_destroy_tx5:
+ b43legacy_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+err_destroy_tx4:
+ b43legacy_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+err_destroy_tx3:
+ b43legacy_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+err_destroy_tx2:
+ b43legacy_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+err_destroy_tx1:
+ b43legacy_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+err_destroy_tx0:
+ b43legacy_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+ goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct b43legacy_dmaring *ring,
+ int slot)
+{
+ u16 cookie = 0x1000;
+
+ /* Use the upper 4 bits of the cookie as
+ * DMA controller ID and store the slot number
+ * in the lower 12 bits.
+ * Note that the cookie must never be 0, as this
+ * is a special value used in RX path.
+ */
+ switch (ring->index) {
+ case 0:
+ cookie = 0xA000;
+ break;
+ case 1:
+ cookie = 0xB000;
+ break;
+ case 2:
+ cookie = 0xC000;
+ break;
+ case 3:
+ cookie = 0xD000;
+ break;
+ case 4:
+ cookie = 0xE000;
+ break;
+ case 5:
+ cookie = 0xF000;
+ break;
+ }
+ B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000));
+ cookie |= (u16)slot;
+
+ return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
+ u16 cookie, int *slot)
+{
+ struct b43legacy_dma *dma = &dev->dma;
+ struct b43legacy_dmaring *ring = NULL;
+
+ switch (cookie & 0xF000) {
+ case 0xA000:
+ ring = dma->tx_ring0;
+ break;
+ case 0xB000:
+ ring = dma->tx_ring1;
+ break;
+ case 0xC000:
+ ring = dma->tx_ring2;
+ break;
+ case 0xD000:
+ ring = dma->tx_ring3;
+ break;
+ case 0xE000:
+ ring = dma->tx_ring4;
+ break;
+ case 0xF000:
+ ring = dma->tx_ring5;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ *slot = (cookie & 0x0FFF);
+ B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+
+ return ring;
+}
+
+static int dma_tx_fragment(struct b43legacy_dmaring *ring,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ const struct b43legacy_dma_ops *ops = ring->ops;
+ u8 *header;
+ int slot;
+ int err;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ struct b43legacy_dmadesc_meta *meta_hdr;
+ struct sk_buff *bounce_skb;
+
+#define SLOTS_PER_PACKET 2
+ B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+
+ /* Get a slot for the header. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta_hdr);
+ memset(meta_hdr, 0, sizeof(*meta_hdr));
+
+ header = &(ring->txhdr_cache[slot * sizeof(
+ struct b43legacy_txhdr_fw3)]);
+ b43legacy_generate_txhdr(ring->dev, header,
+ skb->data, skb->len, ctl,
+ generate_cookie(ring, slot));
+
+ meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
+ sizeof(struct b43legacy_txhdr_fw3), 1);
+ if (dma_mapping_error(meta_hdr->dmaaddr))
+ return -EIO;
+ ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
+
+ /* Get a slot for the payload. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta);
+ memset(meta, 0, sizeof(*meta));
+
+ memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
+ meta->skb = skb;
+ meta->is_last_fragment = 1;
+
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ /* create a bounce buffer in zone_dma on mapping failure. */
+ if (dma_mapping_error(meta->dmaaddr)) {
+ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+ if (!bounce_skb) {
+ err = -ENOMEM;
+ goto out_unmap_hdr;
+ }
+
+ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ skb = bounce_skb;
+ meta->skb = skb;
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ if (dma_mapping_error(meta->dmaaddr)) {
+ err = -EIO;
+ goto out_free_bounce;
+ }
+ }
+
+ ops->fill_descriptor(ring, desc, meta->dmaaddr,
+ skb->len, 0, 1, 1);
+
+ wmb(); /* previous stuff MUST be done */
+ /* Now transfer the whole frame. */
+ ops->poke_tx(ring, next_slot(ring, slot));
+ return 0;
+
+out_free_bounce:
+ dev_kfree_skb_any(skb);
+out_unmap_hdr:
+ unmap_descbuffer(ring, meta_hdr->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3), 1);
+ return err;
+}
+
+static inline
+int should_inject_overflow(struct b43legacy_dmaring *ring)
+{
+#ifdef CONFIG_B43LEGACY_DEBUG
+ if (unlikely(b43legacy_debug(ring->dev,
+ B43legacy_DBG_DMAOVERFLOW))) {
+ /* Check if we should inject another ringbuffer overflow
+ * to test handling of this situation in the stack. */
+ unsigned long next_overflow;
+
+ next_overflow = ring->last_injected_overflow + HZ;
+ if (time_after(jiffies, next_overflow)) {
+ ring->last_injected_overflow = jiffies;
+ b43legacydbg(ring->dev->wl,
+ "Injecting TX ring overflow on "
+ "DMA controller %d\n", ring->index);
+ return 1;
+ }
+ }
+#endif /* CONFIG_B43LEGACY_DEBUG */
+ return 0;
+}
+
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_dmaring *ring;
+ int err = 0;
+ unsigned long flags;
+
+ ring = priority_to_txring(dev, ctl->queue);
+ spin_lock_irqsave(&ring->lock, flags);
+ B43legacy_WARN_ON(!ring->tx);
+ if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
+ b43legacywarn(dev->wl, "DMA queue overflow\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+ /* Check if the queue was stopped in mac80211,
+ * but we got called nevertheless.
+ * That would be a mac80211 bug. */
+ B43legacy_BUG_ON(ring->stopped);
+
+ err = dma_tx_fragment(ring, skb, ctl);
+ if (unlikely(err)) {
+ b43legacyerr(dev->wl, "DMA tx mapping failure\n");
+ goto out_unlock;
+ }
+ ring->nr_tx_packets++;
+ if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+ should_inject_overflow(ring)) {
+ /* This TX ring is full. */
+ ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 1;
+ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacydbg(dev->wl, "Stopped TX ring %d\n",
+ ring->index);
+ }
+out_unlock:
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ return err;
+}
+
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ const struct b43legacy_dma_ops *ops;
+ struct b43legacy_dmaring *ring;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ int slot;
+
+ ring = parse_cookie(dev, status->cookie, &slot);
+ if (unlikely(!ring))
+ return;
+ B43legacy_WARN_ON(!irqs_disabled());
+ spin_lock(&ring->lock);
+
+ B43legacy_WARN_ON(!ring->tx);
+ ops = ring->ops;
+ while (1) {
+ B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+ desc = ops->idx2desc(ring, slot, &meta);
+
+ if (meta->skb)
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
+ else
+ unmap_descbuffer(ring, meta->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3),
+ 1);
+
+ if (meta->is_last_fragment) {
+ B43legacy_WARN_ON(!meta->skb);
+ /* Call back to inform the ieee80211 subsystem about the
+ * status of the transmission.
+ * Some fields of txstat are already filled in dma_tx().
+ */
+ if (status->acked) {
+ meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ if (!(meta->txstat.control.flags
+ & IEEE80211_TXCTL_NO_ACK))
+ meta->txstat.excessive_retries = 1;
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ meta->txstat.retry_count = 0;
+ } else
+ meta->txstat.retry_count = status->frame_count
+ - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+ &(meta->txstat));
+ /* skb is freed by ieee80211_tx_status_irqsafe() */
+ meta->skb = NULL;
+ } else {
+ /* No need to call free_descriptor_buffer here, as
+ * this is only the txhdr, which is not allocated.
+ */
+ B43legacy_WARN_ON(meta->skb != NULL);
+ }
+
+ /* Everything unmapped and free'd. So it's not used anymore. */
+ ring->used_slots--;
+
+ if (meta->is_last_fragment)
+ break;
+ slot = next_slot(ring, slot);
+ }
+ dev->stats.last_tx = jiffies;
+ if (ring->stopped) {
+ B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+ ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 0;
+ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacydbg(dev->wl, "Woke up TX ring %d\n",
+ ring->index);
+ }
+
+ spin_unlock(&ring->lock);
+}
+
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ const int nr_queues = dev->wl->hw->queues;
+ struct b43legacy_dmaring *ring;
+ struct ieee80211_tx_queue_stats_data *data;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < nr_queues; i++) {
+ data = &(stats->data[i]);
+ ring = priority_to_txring(dev, i);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ data->len = ring->used_slots / SLOTS_PER_PACKET;
+ data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+ data->count = ring->nr_tx_packets;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ }
+}
+
+static void dma_rx(struct b43legacy_dmaring *ring,
+ int *slot)
+{
+ const struct b43legacy_dma_ops *ops = ring->ops;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ struct b43legacy_rxhdr_fw3 *rxhdr;
+ struct sk_buff *skb;
+ u16 len;
+ int err;
+ dma_addr_t dmaaddr;
+
+ desc = ops->idx2desc(ring, *slot, &meta);
+
+ sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+ skb = meta->skb;
+
+ if (ring->index == 3) {
+ /* We received an xmit status. */
+ struct b43legacy_hwtxstatus *hw =
+ (struct b43legacy_hwtxstatus *)skb->data;
+ int i = 0;
+
+ while (hw->cookie == 0) {
+ if (i > 100)
+ break;
+ i++;
+ udelay(2);
+ barrier();
+ }
+ b43legacy_handle_hwtxstatus(ring->dev, hw);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+
+ return;
+ }
+ rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data;
+ len = le16_to_cpu(rxhdr->frame_len);
+ if (len == 0) {
+ int i = 0;
+
+ do {
+ udelay(2);
+ barrier();
+ len = le16_to_cpu(rxhdr->frame_len);
+ } while (len == 0 && i++ < 5);
+ if (unlikely(len == 0)) {
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ goto drop;
+ }
+ }
+ if (unlikely(len > ring->rx_buffersize)) {
+ /* The data did not fit into one descriptor buffer
+ * and is split over multiple buffers.
+ * This should never happen, as we try to allocate buffers
+ * big enough. So simply ignore this packet.
+ */
+ int cnt = 0;
+ s32 tmp = len;
+
+ while (1) {
+ desc = ops->idx2desc(ring, *slot, &meta);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ *slot = next_slot(ring, *slot);
+ cnt++;
+ tmp -= ring->rx_buffersize;
+ if (tmp <= 0)
+ break;
+ }
+ b43legacyerr(ring->dev->wl, "DMA RX buffer too small "
+ "(len: %u, buffer: %u, nr-dropped: %d)\n",
+ len, ring->rx_buffersize, cnt);
+ goto drop;
+ }
+
+ dmaaddr = meta->dmaaddr;
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+ if (unlikely(err)) {
+ b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()"
+ " failed\n");
+ sync_descbuffer_for_device(ring, dmaaddr,
+ ring->rx_buffersize);
+ goto drop;
+ }
+
+ unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+ skb_put(skb, len + ring->frameoffset);
+ skb_pull(skb, ring->frameoffset);
+
+ b43legacy_rx(ring->dev, skb, rxhdr);
+drop:
+ return;
+}
+
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
+{
+ const struct b43legacy_dma_ops *ops = ring->ops;
+ int slot;
+ int current_slot;
+ int used_slots = 0;
+
+ B43legacy_WARN_ON(ring->tx);
+ current_slot = ops->get_current_rxslot(ring);
+ B43legacy_WARN_ON(!(current_slot >= 0 && current_slot <
+ ring->nr_slots));
+
+ slot = ring->current_slot;
+ for (; slot != current_slot; slot = next_slot(ring, slot)) {
+ dma_rx(ring, &slot);
+ update_max_used_slots(ring, ++used_slots);
+ }
+ ops->set_current_rxslot(ring, slot);
+ ring->current_slot = slot;
+}
+
+static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43legacy_WARN_ON(!ring->tx);
+ ring->ops->tx_suspend(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43legacy_WARN_ON(!ring->tx);
+ ring->ops->tx_resume(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
+{
+ b43legacy_power_saving_ctl_bits(dev, -1, 1);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5);
+}
+
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
+{
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0);
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+}
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
new file mode 100644
index 000000000000..26f6ab08de75
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -0,0 +1,367 @@
+#ifndef B43legacy_DMA_H_
+#define B43legacy_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+#include "b43legacy.h"
+
+
+/* DMA-Interrupt reasons. */
+#define B43legacy_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
+ | (1 << 14) | (1 << 15))
+#define B43legacy_DMAIRQ_NONFATALMASK (1 << 13)
+#define B43legacy_DMAIRQ_RX_DONE (1 << 16)
+
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define B43legacy_DMA32_TXCTL 0x00
+#define B43legacy_DMA32_TXENABLE 0x00000001
+#define B43legacy_DMA32_TXSUSPEND 0x00000002
+#define B43legacy_DMA32_TXLOOPBACK 0x00000004
+#define B43legacy_DMA32_TXFLUSH 0x00000010
+#define B43legacy_DMA32_TXADDREXT_MASK 0x00030000
+#define B43legacy_DMA32_TXADDREXT_SHIFT 16
+#define B43legacy_DMA32_TXRING 0x04
+#define B43legacy_DMA32_TXINDEX 0x08
+#define B43legacy_DMA32_TXSTATUS 0x0C
+#define B43legacy_DMA32_TXDPTR 0x00000FFF
+#define B43legacy_DMA32_TXSTATE 0x0000F000
+#define B43legacy_DMA32_TXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA32_TXSTAT_ACTIVE 0x00001000
+#define B43legacy_DMA32_TXSTAT_IDLEWAIT 0x00002000
+#define B43legacy_DMA32_TXSTAT_STOPPED 0x00003000
+#define B43legacy_DMA32_TXSTAT_SUSP 0x00004000
+#define B43legacy_DMA32_TXERROR 0x000F0000
+#define B43legacy_DMA32_TXERR_NOERR 0x00000000
+#define B43legacy_DMA32_TXERR_PROT 0x00010000
+#define B43legacy_DMA32_TXERR_UNDERRUN 0x00020000
+#define B43legacy_DMA32_TXERR_BUFREAD 0x00030000
+#define B43legacy_DMA32_TXERR_DESCREAD 0x00040000
+#define B43legacy_DMA32_TXACTIVE 0xFFF00000
+#define B43legacy_DMA32_RXCTL 0x10
+#define B43legacy_DMA32_RXENABLE 0x00000001
+#define B43legacy_DMA32_RXFROFF_MASK 0x000000FE
+#define B43legacy_DMA32_RXFROFF_SHIFT 1
+#define B43legacy_DMA32_RXDIRECTFIFO 0x00000100
+#define B43legacy_DMA32_RXADDREXT_MASK 0x00030000
+#define B43legacy_DMA32_RXADDREXT_SHIFT 16
+#define B43legacy_DMA32_RXRING 0x14
+#define B43legacy_DMA32_RXINDEX 0x18
+#define B43legacy_DMA32_RXSTATUS 0x1C
+#define B43legacy_DMA32_RXDPTR 0x00000FFF
+#define B43legacy_DMA32_RXSTATE 0x0000F000
+#define B43legacy_DMA32_RXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA32_RXSTAT_ACTIVE 0x00001000
+#define B43legacy_DMA32_RXSTAT_IDLEWAIT 0x00002000
+#define B43legacy_DMA32_RXSTAT_STOPPED 0x00003000
+#define B43legacy_DMA32_RXERROR 0x000F0000
+#define B43legacy_DMA32_RXERR_NOERR 0x00000000
+#define B43legacy_DMA32_RXERR_PROT 0x00010000
+#define B43legacy_DMA32_RXERR_OVERFLOW 0x00020000
+#define B43legacy_DMA32_RXERR_BUFWRITE 0x00030000
+#define B43legacy_DMA32_RXERR_DESCREAD 0x00040000
+#define B43legacy_DMA32_RXACTIVE 0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct b43legacy_dmadesc32 {
+ __le32 control;
+ __le32 address;
+} __attribute__((__packed__));
+#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF
+#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000
+#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16
+#define B43legacy_DMA32_DCTL_DTABLEEND 0x10000000
+#define B43legacy_DMA32_DCTL_IRQ 0x20000000
+#define B43legacy_DMA32_DCTL_FRAMEEND 0x40000000
+#define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000
+
+
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define B43legacy_DMA64_TXCTL 0x00
+#define B43legacy_DMA64_TXENABLE 0x00000001
+#define B43legacy_DMA64_TXSUSPEND 0x00000002
+#define B43legacy_DMA64_TXLOOPBACK 0x00000004
+#define B43legacy_DMA64_TXFLUSH 0x00000010
+#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000
+#define B43legacy_DMA64_TXADDREXT_SHIFT 16
+#define B43legacy_DMA64_TXINDEX 0x04
+#define B43legacy_DMA64_TXRINGLO 0x08
+#define B43legacy_DMA64_TXRINGHI 0x0C
+#define B43legacy_DMA64_TXSTATUS 0x10
+#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF
+#define B43legacy_DMA64_TXSTAT 0xF0000000
+#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000
+#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000
+#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000
+#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000
+#define B43legacy_DMA64_TXERROR 0x14
+#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF
+#define B43legacy_DMA64_TXERR 0xF0000000
+#define B43legacy_DMA64_TXERR_NOERR 0x00000000
+#define B43legacy_DMA64_TXERR_PROT 0x10000000
+#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000
+#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000
+#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000
+#define B43legacy_DMA64_TXERR_CORE 0x50000000
+#define B43legacy_DMA64_RXCTL 0x20
+#define B43legacy_DMA64_RXENABLE 0x00000001
+#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE
+#define B43legacy_DMA64_RXFROFF_SHIFT 1
+#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100
+#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000
+#define B43legacy_DMA64_RXADDREXT_SHIFT 16
+#define B43legacy_DMA64_RXINDEX 0x24
+#define B43legacy_DMA64_RXRINGLO 0x28
+#define B43legacy_DMA64_RXRINGHI 0x2C
+#define B43legacy_DMA64_RXSTATUS 0x30
+#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF
+#define B43legacy_DMA64_RXSTAT 0xF0000000
+#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000
+#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000
+#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000
+#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000
+#define B43legacy_DMA64_RXERROR 0x34
+#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF
+#define B43legacy_DMA64_RXERR 0xF0000000
+#define B43legacy_DMA64_RXERR_NOERR 0x00000000
+#define B43legacy_DMA64_RXERR_PROT 0x10000000
+#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000
+#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000
+#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000
+#define B43legacy_DMA64_RXERR_CORE 0x50000000
+
+/* 64-bit DMA descriptor. */
+struct b43legacy_dmadesc64 {
+ __le32 control0;
+ __le32 control1;
+ __le32 address_low;
+ __le32 address_high;
+} __attribute__((__packed__));
+#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000
+#define B43legacy_DMA64_DCTL0_IRQ 0x20000000
+#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000
+#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000
+#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF
+#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000
+#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16
+
+
+
+struct b43legacy_dmadesc_generic {
+ union {
+ struct b43legacy_dmadesc32 dma32;
+ struct b43legacy_dmadesc64 dma64;
+ } __attribute__((__packed__));
+} __attribute__((__packed__));
+
+
+/* Misc DMA constants */
+#define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE
+#define B43legacy_DMA0_RX_FRAMEOFFSET 30
+#define B43legacy_DMA3_RX_FRAMEOFFSET 0
+
+
+/* DMA engine tuning knobs */
+#define B43legacy_TXRING_SLOTS 128
+#define B43legacy_RXRING_SLOTS 64
+#define B43legacy_DMA0_RX_BUFFERSIZE (2304 + 100)
+#define B43legacy_DMA3_RX_BUFFERSIZE 16
+
+
+
+#ifdef CONFIG_B43LEGACY_DMA
+
+
+struct sk_buff;
+struct b43legacy_private;
+struct b43legacy_txstatus;
+
+
+struct b43legacy_dmadesc_meta {
+ /* The kernel DMA-able buffer. */
+ struct sk_buff *skb;
+ /* DMA base bus-address of the descriptor buffer. */
+ dma_addr_t dmaaddr;
+ /* ieee80211 TX status. Only used once per 802.11 frag. */
+ bool is_last_fragment;
+ struct ieee80211_tx_status txstat;
+};
+
+struct b43legacy_dmaring;
+
+/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
+struct b43legacy_dma_ops {
+ struct b43legacy_dmadesc_generic * (*idx2desc)
+ (struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta
+ **meta);
+ void (*fill_descriptor)(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq);
+ void (*poke_tx)(struct b43legacy_dmaring *ring, int slot);
+ void (*tx_suspend)(struct b43legacy_dmaring *ring);
+ void (*tx_resume)(struct b43legacy_dmaring *ring);
+ int (*get_current_rxslot)(struct b43legacy_dmaring *ring);
+ void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
+};
+
+struct b43legacy_dmaring {
+ /* Lowlevel DMA ops. */
+ const struct b43legacy_dma_ops *ops;
+ /* Kernel virtual base address of the ring memory. */
+ void *descbase;
+ /* Meta data about all descriptors. */
+ struct b43legacy_dmadesc_meta *meta;
+ /* Cache of TX headers for each slot.
+ * This is to avoid an allocation on each TX.
+ * This is NULL for an RX ring.
+ */
+ u8 *txhdr_cache;
+ /* (Unadjusted) DMA base bus-address of the ring memory. */
+ dma_addr_t dmabase;
+ /* Number of descriptor slots in the ring. */
+ int nr_slots;
+ /* Number of used descriptor slots. */
+ int used_slots;
+ /* Currently used slot in the ring. */
+ int current_slot;
+ /* Total number of packets sent. Statistics only. */
+ unsigned int nr_tx_packets;
+ /* Frameoffset in octets. */
+ u32 frameoffset;
+ /* Descriptor buffer size. */
+ u16 rx_buffersize;
+ /* The MMIO base register of the DMA controller. */
+ u16 mmio_base;
+ /* DMA controller index number (0-5). */
+ int index;
+ /* Boolean. Is this a TX ring? */
+ bool tx;
+ /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+ bool dma64;
+ /* Boolean. Is this ring stopped at ieee80211 level? */
+ bool stopped;
+ /* Lock, only used for TX. */
+ spinlock_t lock;
+ struct b43legacy_wldev *dev;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ /* Maximum number of used slots. */
+ int max_used_slots;
+ /* Last time we injected a ring overflow. */
+ unsigned long last_injected_overflow;
+#endif /* CONFIG_B43LEGACY_DEBUG*/
+};
+
+
+static inline
+u32 b43legacy_dma_read(struct b43legacy_dmaring *ring,
+ u16 offset)
+{
+ return b43legacy_read32(ring->dev, ring->mmio_base + offset);
+}
+
+static inline
+void b43legacy_dma_write(struct b43legacy_dmaring *ring,
+ u16 offset, u32 value)
+{
+ b43legacy_write32(ring->dev, ring->mmio_base + offset, value);
+}
+
+
+int b43legacy_dma_init(struct b43legacy_wldev *dev);
+void b43legacy_dma_free(struct b43legacy_wldev *dev);
+
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64);
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64);
+
+u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
+
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl);
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring);
+
+#else /* CONFIG_B43LEGACY_DMA */
+
+
+static inline
+int b43legacy_dma_init(struct b43legacy_wldev *dev)
+{
+ return 0;
+}
+static inline
+void b43legacy_dma_free(struct b43legacy_wldev *dev)
+{
+}
+static inline
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64)
+{
+ return 0;
+}
+static inline
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64)
+{
+ return 0;
+}
+static inline
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+}
+static inline
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
+{
+}
+static inline
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
+{
+}
+static inline
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43LEGACY_DMA */
+#endif /* B43legacy_DMA_H_ */
diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c
new file mode 100644
index 000000000000..247fc780ffdb
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.c
@@ -0,0 +1,336 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "ilt.h"
+#include "phy.h"
+
+
+/**** Initial Internal Lookup Tables ****/
+
+const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE] = {
+ 0xFEB93FFD, 0xFEC63FFD, /* 0 */
+ 0xFED23FFD, 0xFEDF3FFD,
+ 0xFEEC3FFE, 0xFEF83FFE,
+ 0xFF053FFE, 0xFF113FFE,
+ 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+ 0xFF373FFF, 0xFF443FFF,
+ 0xFF503FFF, 0xFF5D3FFF,
+ 0xFF693FFF, 0xFF763FFF,
+ 0xFF824000, 0xFF8F4000, /* 16 */
+ 0xFF9B4000, 0xFFA84000,
+ 0xFFB54000, 0xFFC14000,
+ 0xFFCE4000, 0xFFDA4000,
+ 0xFFE74000, 0xFFF34000, /* 24 */
+ 0x00004000, 0x000D4000,
+ 0x00194000, 0x00264000,
+ 0x00324000, 0x003F4000,
+ 0x004B4000, 0x00584000, /* 32 */
+ 0x00654000, 0x00714000,
+ 0x007E4000, 0x008A3FFF,
+ 0x00973FFF, 0x00A33FFF,
+ 0x00B03FFF, 0x00BC3FFF, /* 40 */
+ 0x00C93FFF, 0x00D63FFF,
+ 0x00E23FFE, 0x00EF3FFE,
+ 0x00FB3FFE, 0x01083FFE,
+ 0x01143FFE, 0x01213FFD, /* 48 */
+ 0x012E3FFD, 0x013A3FFD,
+ 0x01473FFD,
+};
+
+const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE] = {
+ 0xDB93CB87, 0xD666CF64, /* 0 */
+ 0xD1FDD358, 0xCDA6D826,
+ 0xCA38DD9F, 0xC729E2B4,
+ 0xC469E88E, 0xC26AEE2B,
+ 0xC0DEF46C, 0xC073FA62, /* 8 */
+ 0xC01D00D5, 0xC0760743,
+ 0xC1560D1E, 0xC2E51369,
+ 0xC4ED18FF, 0xC7AC1ED7,
+ 0xCB2823B2, 0xCEFA28D9, /* 16 */
+ 0xD2F62D3F, 0xD7BB3197,
+ 0xDCE53568, 0xE1FE3875,
+ 0xE7D13B35, 0xED663D35,
+ 0xF39B3EC4, 0xF98E3FA7, /* 24 */
+ 0x00004000, 0x06723FA7,
+ 0x0C653EC4, 0x129A3D35,
+ 0x182F3B35, 0x1E023875,
+ 0x231B3568, 0x28453197, /* 32 */
+ 0x2D0A2D3F, 0x310628D9,
+ 0x34D823B2, 0x38541ED7,
+ 0x3B1318FF, 0x3D1B1369,
+ 0x3EAA0D1E, 0x3F8A0743, /* 40 */
+ 0x3FE300D5, 0x3F8DFA62,
+ 0x3F22F46C, 0x3D96EE2B,
+ 0x3B97E88E, 0x38D7E2B4,
+ 0x35C8DD9F, 0x325AD826, /* 48 */
+ 0x2E03D358, 0x299ACF64,
+ 0x246DCB87,
+};
+
+const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE] = {
+ 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+ 0x0202, 0x0282, 0x0302, 0x0382,
+ 0x0402, 0x0482, 0x0502, 0x0582,
+ 0x05E2, 0x0662, 0x06E2, 0x0762,
+ 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+ 0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+ 0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+ 0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+ 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+ 0x1062, 0x10C2, 0x1122, 0x1182,
+ 0x11E2, 0x1242, 0x12A2, 0x12E2,
+ 0x1342, 0x13A2, 0x1402, 0x1442,
+ 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+ 0x15E2, 0x1622, 0x1662, 0x16C1,
+ 0x1701, 0x1741, 0x1781, 0x17E1,
+ 0x1821, 0x1861, 0x18A1, 0x18E1,
+ 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+ 0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+ 0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+ 0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+ 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+ 0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+ 0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+ 0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+ 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+ 0x2001, 0x2041, 0x2061, 0x2081,
+ 0x20A1, 0x20C1, 0x20E1, 0x2101,
+ 0x2121, 0x2141, 0x2161, 0x2181,
+ 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+ 0x2221, 0x2241, 0x2261, 0x2281,
+ 0x22A1, 0x22C1, 0x22C1, 0x22E1,
+ 0x2301, 0x2321, 0x2341, 0x2361,
+ 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+ 0x23E1, 0x23E1, 0x2401, 0x2421,
+ 0x2441, 0x2441, 0x2461, 0x2481,
+ 0x2481, 0x24A1, 0x24C1, 0x24C1,
+ 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+ 0x2541, 0x2541, 0x2561, 0x2561,
+ 0x2581, 0x25A1, 0x25A1, 0x25C1,
+ 0x25C1, 0x25E1, 0x2601, 0x2601,
+ 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+ 0x2661, 0x2661, 0x2681, 0x2681,
+ 0x26A1, 0x26A1, 0x26C1, 0x26C1,
+ 0x26E1, 0x26E1, 0x2701, 0x2701,
+ 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+ 0x2760, 0x2760, 0x2780, 0x2780,
+ 0x2780, 0x27A0, 0x27A0, 0x27C0,
+ 0x27C0, 0x27E0, 0x27E0, 0x27E0,
+ 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+ 0x2820, 0x2840, 0x2840, 0x2840,
+ 0x2860, 0x2860, 0x2880, 0x2880,
+ 0x2880, 0x28A0, 0x28A0, 0x28A0,
+ 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+ 0x28E0, 0x28E0, 0x2900, 0x2900,
+ 0x2900, 0x2920, 0x2920, 0x2920,
+ 0x2940, 0x2940, 0x2940, 0x2960,
+ 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+ 0x2980, 0x2980, 0x29A0, 0x29A0,
+ 0x29A0, 0x29A0, 0x29C0, 0x29C0,
+ 0x29C0, 0x29E0, 0x29E0, 0x29E0,
+ 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+ 0x2A00, 0x2A20, 0x2A20, 0x2A20,
+ 0x2A20, 0x2A40, 0x2A40, 0x2A40,
+ 0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE] = {
+ 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+ 0x05A9, 0x0669, 0x0709, 0x0789,
+ 0x0829, 0x08A9, 0x0929, 0x0989,
+ 0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+ 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+ 0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+ 0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+ 0x0FA9, 0x0FE9, 0x1029, 0x1089,
+ 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+ 0x11E9, 0x1229, 0x1289, 0x12C9,
+ 0x1309, 0x1349, 0x1389, 0x13C9,
+ 0x1409, 0x1449, 0x14A9, 0x14E9,
+ 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+ 0x1629, 0x1669, 0x16A9, 0x16E8,
+ 0x1728, 0x1768, 0x17A8, 0x17E8,
+ 0x1828, 0x1868, 0x18A8, 0x18E8,
+ 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+ 0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+ 0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+ 0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+ 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+ 0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+ 0x1F48, 0x1F88, 0x1FE8, 0x2028,
+ 0x2068, 0x20A8, 0x2108, 0x2148,
+ 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+ 0x22C8, 0x2308, 0x2348, 0x23A8,
+ 0x23E8, 0x2448, 0x24A8, 0x24E8,
+ 0x2548, 0x25A8, 0x2608, 0x2668,
+ 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+ 0x2847, 0x28C7, 0x2947, 0x29A7,
+ 0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+ 0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+ 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+ 0x3806, 0x38A6, 0x3946, 0x39E6,
+ 0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+ 0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+ 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+ 0x3F45, 0x3FA5, 0x4005, 0x4045,
+ 0x40A5, 0x40E5, 0x4145, 0x4185,
+ 0x41E5, 0x4225, 0x4265, 0x42C5,
+ 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+ 0x4424, 0x4464, 0x44C4, 0x4504,
+ 0x4544, 0x4584, 0x45C4, 0x4604,
+ 0x4644, 0x46A4, 0x46E4, 0x4724,
+ 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+ 0x4864, 0x48A4, 0x48E4, 0x4924,
+ 0x4964, 0x49A4, 0x49E4, 0x4A24,
+ 0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+ 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+ 0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+ 0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+ 0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+ 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+ 0x5083, 0x50C3, 0x5103, 0x5143,
+ 0x5183, 0x51E2, 0x5222, 0x5262,
+ 0x52A2, 0x52E2, 0x5342, 0x5382,
+ 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+ 0x5502, 0x5542, 0x55A2, 0x55E2,
+ 0x5642, 0x5682, 0x56E2, 0x5722,
+ 0x5782, 0x57E1, 0x5841, 0x58A1,
+ 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+ 0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+ 0x5C61, 0x5D01, 0x5D80, 0x5E20,
+ 0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE] = {
+ 0x0001, 0x0001, 0x0001, 0xFFFE,
+ 0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE] = {
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE] = {
+ 0x013C, 0x01F5, 0x031A, 0x0631,
+ 0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE] = {
+ 0x5484, 0x3C40, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE] = {
+ 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+ 0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+ 0x1A1D, 0x1719, 0x1616, 0x1414,
+ 0x1414, 0x1400, 0x1414, 0x1614,
+ 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+ 0x2A27, 0x2F2A, 0x332D, 0x3B35,
+ 0x5140, 0x6C62, 0x0077,
+};
+
+const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE] = {
+ 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+ 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+ 0x969B, 0x9195, 0x8F8F, 0x8A8A,
+ 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+ 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+ 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+ 0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE] = {
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE] = {
+ 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+ 0x0067, 0x0063, 0x005E, 0x0059,
+ 0x0054, 0x0050, 0x004B, 0x0046,
+ 0x0042, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x0000, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x0042, 0x0046, 0x004B, 0x0050,
+ 0x0054, 0x0059, 0x005E, 0x0063,
+ 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+ 0x007A,
+};
+
+const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE] = {
+ 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+ 0x00D6, 0x00D4, 0x00D2, 0x00CF,
+ 0x00CD, 0x00CA, 0x00C7, 0x00C4,
+ 0x00C1, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x0000, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00C1, 0x00C4, 0x00C7, 0x00CA,
+ 0x00CD, 0x00CF, 0x00D2, 0x00D4,
+ 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+ 0x00DE,
+};
+
+/**** Helper functions to access the device Internal Lookup Tables ****/
+
+void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+ mmiowb();
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, val);
+}
+
+void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, u32 val)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+ mmiowb();
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA2,
+ (val & 0xFFFF0000) >> 16);
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1,
+ val & 0x0000FFFF);
+}
+
+u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+ return b43legacy_phy_read(dev, B43legacy_PHY_ILT_G_DATA1);
+}
diff --git a/drivers/net/wireless/b43legacy/ilt.h b/drivers/net/wireless/b43legacy/ilt.h
new file mode 100644
index 000000000000..48bcf37eccb8
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.h
@@ -0,0 +1,34 @@
+#ifndef B43legacy_ILT_H_
+#define B43legacy_ILT_H_
+
+#define B43legacy_ILT_ROTOR_SIZE 53
+extern const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE];
+#define B43legacy_ILT_RETARD_SIZE 53
+extern const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE];
+#define B43legacy_ILT_FINEFREQA_SIZE 256
+extern const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE];
+#define B43legacy_ILT_FINEFREQG_SIZE 256
+extern const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE];
+#define B43legacy_ILT_NOISEA2_SIZE 8
+extern const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE];
+#define B43legacy_ILT_NOISEA3_SIZE 8
+extern const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE];
+#define B43legacy_ILT_NOISEG1_SIZE 8
+extern const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE];
+#define B43legacy_ILT_NOISEG2_SIZE 8
+extern const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE];
+#define B43legacy_ILT_NOISESCALEG_SIZE 27
+extern const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE];
+extern const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE];
+extern const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE];
+#define B43legacy_ILT_SIGMASQR_SIZE 53
+extern const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE];
+extern const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE];
+
+
+void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
+void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset,
+ u32 val);
+u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset);
+
+#endif /* B43legacy_ILT_H_ */
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
new file mode 100644
index 000000000000..a584ea810502
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -0,0 +1,298 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mb@bu3sch.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "leds.h"
+#include "b43legacy.h"
+#include "main.h"
+
+static void b43legacy_led_changestate(struct b43legacy_led *led)
+{
+ struct b43legacy_wldev *dev = led->dev;
+ const int index = led->index;
+ u16 ledctl;
+
+ B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
+ B43legacy_WARN_ON(!led->blink_interval);
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ ledctl ^= (1 << index);
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void b43legacy_led_blink(unsigned long d)
+{
+ struct b43legacy_led *led = (struct b43legacy_led *)d;
+ struct b43legacy_wldev *dev = led->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->leds_lock, flags);
+ if (led->blink_interval) {
+ b43legacy_led_changestate(led);
+ mod_timer(&led->blink_timer, jiffies + led->blink_interval);
+ }
+ spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
+
+static void b43legacy_led_blink_start(struct b43legacy_led *led,
+ unsigned long interval)
+{
+ if (led->blink_interval)
+ return;
+ led->blink_interval = interval;
+ b43legacy_led_changestate(led);
+ led->blink_timer.expires = jiffies + interval;
+ add_timer(&led->blink_timer);
+}
+
+static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync)
+{
+ struct b43legacy_wldev *dev = led->dev;
+ const int index = led->index;
+ u16 ledctl;
+
+ if (!led->blink_interval)
+ return;
+ if (unlikely(sync))
+ del_timer_sync(&led->blink_timer);
+ else
+ del_timer(&led->blink_timer);
+ led->blink_interval = 0;
+
+ /* Make sure the LED is turned off. */
+ B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ if (led->activelow)
+ ledctl |= (1 << index);
+ else
+ ledctl &= ~(1 << index);
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev,
+ struct b43legacy_led *led,
+ int led_index)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+
+ /* This function is called, if the behaviour (and activelow)
+ * information for a LED is missing in the SPROM.
+ * We hardcode the behaviour values for various devices here.
+ * Note that the B43legacy_LED_TEST_XXX behaviour values can
+ * be used to figure out which led is mapped to which index.
+ */
+
+ switch (led_index) {
+ case 0:
+ led->behaviour = B43legacy_LED_ACTIVITY;
+ led->activelow = 1;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+ led->behaviour = B43legacy_LED_RADIO_ALL;
+ break;
+ case 1:
+ led->behaviour = B43legacy_LED_RADIO_B;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+ led->behaviour = B43legacy_LED_ASSOC;
+ break;
+ case 2:
+ led->behaviour = B43legacy_LED_RADIO_A;
+ break;
+ case 3:
+ led->behaviour = B43legacy_LED_OFF;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+int b43legacy_leds_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_led *led;
+ u8 sprom[4];
+ int i;
+
+ sprom[0] = dev->dev->bus->sprom.r1.gpio0;
+ sprom[1] = dev->dev->bus->sprom.r1.gpio1;
+ sprom[2] = dev->dev->bus->sprom.r1.gpio2;
+ sprom[3] = dev->dev->bus->sprom.r1.gpio3;
+
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+ led->index = i;
+ led->dev = dev;
+ setup_timer(&led->blink_timer,
+ b43legacy_led_blink,
+ (unsigned long)led);
+
+ if (sprom[i] == 0xFF)
+ b43legacy_led_init_hardcoded(dev, led, i);
+ else {
+ led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR;
+ led->activelow = !!(sprom[i] &
+ B43legacy_LED_ACTIVELOW);
+ }
+ }
+
+ return 0;
+}
+
+void b43legacy_leds_exit(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_led *led;
+ int i;
+
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+ b43legacy_led_blink_stop(led, 1);
+ }
+ b43legacy_leds_switch_all(dev, 0);
+}
+
+void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity)
+{
+ struct b43legacy_led *led;
+ struct b43legacy_phy *phy = &dev->phy;
+ const int transferring = (jiffies - dev->stats.last_tx)
+ < B43legacy_LED_XFER_THRES;
+ int i;
+ int turn_on;
+ unsigned long interval = 0;
+ u16 ledctl;
+ unsigned long flags;
+ bool radio_enabled = (phy->radio_on && dev->radio_hw_enable);
+
+ spin_lock_irqsave(&dev->wl->leds_lock, flags);
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+
+ turn_on = 0;
+ switch (led->behaviour) {
+ case B43legacy_LED_INACTIVE:
+ continue;
+ case B43legacy_LED_OFF:
+ break;
+ case B43legacy_LED_ON:
+ turn_on = 1;
+ break;
+ case B43legacy_LED_ACTIVITY:
+ turn_on = activity;
+ break;
+ case B43legacy_LED_RADIO_ALL:
+ turn_on = radio_enabled;
+ break;
+ case B43legacy_LED_RADIO_A:
+ break;
+ case B43legacy_LED_RADIO_B:
+ turn_on = radio_enabled;
+ break;
+ case B43legacy_LED_MODE_BG:
+ if (phy->type == B43legacy_PHYTYPE_G && radio_enabled)
+ turn_on = 1;
+ break;
+ case B43legacy_LED_TRANSFER:
+ if (transferring)
+ b43legacy_led_blink_start(led,
+ B43legacy_LEDBLINK_MEDIUM);
+ else
+ b43legacy_led_blink_stop(led, 0);
+ continue;
+ case B43legacy_LED_APTRANSFER:
+ if (b43legacy_is_mode(dev->wl,
+ IEEE80211_IF_TYPE_AP)) {
+ if (transferring) {
+ interval = B43legacy_LEDBLINK_FAST;
+ turn_on = 1;
+ }
+ } else {
+ turn_on = 1;
+ if (transferring)
+ interval = B43legacy_LEDBLINK_FAST;
+ else
+ turn_on = 0;
+ }
+ if (turn_on)
+ b43legacy_led_blink_start(led, interval);
+ else
+ b43legacy_led_blink_stop(led, 0);
+ continue;
+ case B43legacy_LED_WEIRD:
+ break;
+ case B43legacy_LED_ASSOC:
+ turn_on = 1;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ case B43legacy_LED_TEST_BLINKSLOW:
+ b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW);
+ continue;
+ case B43legacy_LED_TEST_BLINKMEDIUM:
+ b43legacy_led_blink_start(led,
+ B43legacy_LEDBLINK_MEDIUM);
+ continue;
+ case B43legacy_LED_TEST_BLINKFAST:
+ b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST);
+ continue;
+#endif /* CONFIG_B43LEGACY_DEBUG */
+ default:
+ B43legacy_BUG_ON(1);
+ };
+
+ if (led->activelow)
+ turn_on = !turn_on;
+ if (turn_on)
+ ledctl |= (1 << i);
+ else
+ ledctl &= ~(1 << i);
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
+
+void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on)
+{
+ struct b43legacy_led *led;
+ u16 ledctl;
+ int i;
+ int bit_on;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->leds_lock, flags);
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+ if (led->behaviour == B43legacy_LED_INACTIVE)
+ continue;
+ if (on)
+ bit_on = led->activelow ? 0 : 1;
+ else
+ bit_on = led->activelow ? 1 : 0;
+ if (bit_on)
+ ledctl |= (1 << i);
+ else
+ ledctl &= ~(1 << i);
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h
new file mode 100644
index 000000000000..b989f503e684
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.h
@@ -0,0 +1,56 @@
+#ifndef B43legacy_LEDS_H_
+#define B43legacy_LEDS_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+
+struct b43legacy_led {
+ u8 behaviour;
+ bool activelow;
+ /* Index in the "leds" array in b43legacy_wldev */
+ u8 index;
+ struct b43legacy_wldev *dev;
+ struct timer_list blink_timer;
+ unsigned long blink_interval;
+};
+
+/* Delay between state changes when blinking in jiffies */
+#define B43legacy_LEDBLINK_SLOW (HZ / 1)
+#define B43legacy_LEDBLINK_MEDIUM (HZ / 4)
+#define B43legacy_LEDBLINK_FAST (HZ / 8)
+
+#define B43legacy_LED_XFER_THRES (HZ / 100)
+
+#define B43legacy_LED_BEHAVIOUR 0x7F
+#define B43legacy_LED_ACTIVELOW 0x80
+enum { /* LED behaviour values */
+ B43legacy_LED_OFF,
+ B43legacy_LED_ON,
+ B43legacy_LED_ACTIVITY,
+ B43legacy_LED_RADIO_ALL,
+ B43legacy_LED_RADIO_A,
+ B43legacy_LED_RADIO_B,
+ B43legacy_LED_MODE_BG,
+ B43legacy_LED_TRANSFER,
+ B43legacy_LED_APTRANSFER,
+ B43legacy_LED_WEIRD,
+ B43legacy_LED_ASSOC,
+ B43legacy_LED_INACTIVE,
+
+ /* Behaviour values for testing.
+ * With these values it is easier to figure out
+ * the real behaviour of leds, in case the SPROM
+ * is missing information.
+ */
+ B43legacy_LED_TEST_BLINKSLOW,
+ B43legacy_LED_TEST_BLINKMEDIUM,
+ B43legacy_LED_TEST_BLINKFAST,
+};
+
+int b43legacy_leds_init(struct b43legacy_wldev *dev);
+void b43legacy_leds_exit(struct b43legacy_wldev *dev);
+void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity);
+void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on);
+
+#endif /* B43legacy_LEDS_H_ */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
new file mode 100644
index 000000000000..f0749510bcd7
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -0,0 +1,3856 @@
+/*
+ *
+ * Broadcom B43legacy wireless driver
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Some parts of the code in this file are derived from the ipw2200
+ * driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <net/dst.h>
+#include <asm/unaligned.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "debugfs.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+#include "sysfs.h"
+#include "xmit.h"
+#include "radio.h"
+
+
+MODULE_DESCRIPTION("Broadcom B43legacy wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_B43LEGACY_DMA)
+# define modparam_pio 0
+#elif defined(CONFIG_B43LEGACY_PIO)
+# define modparam_pio 1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames"
+ " Preemption");
+
+static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static int modparam_noleds;
+module_param_named(noleds, modparam_noleds, int, 0444);
+MODULE_PARM_DESC(noleds, "Turn off all LED activity");
+
+static char modparam_fwpostfix[16];
+module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
+
+/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */
+static const struct ssb_device_id b43legacy_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl);
+
+
+/* Channel and ratetables are shared for all devices.
+ * They can't be const, because ieee80211 puts some precalculated
+ * data in there. This data is the same for all devices, so we don't
+ * get concurrency issues */
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .rate = B43legacy_RATE_TO_100KBPS(_rateid), \
+ .val = (_rateid), \
+ .val2 = (_rateid), \
+ .flags = (_flags), \
+ }
+static struct ieee80211_rate __b43legacy_ratetable[] = {
+ RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+ RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+};
+#define b43legacy_a_ratetable (__b43legacy_ratetable + 4)
+#define b43legacy_a_ratetable_size 8
+#define b43legacy_b_ratetable (__b43legacy_ratetable + 0)
+#define b43legacy_b_ratetable_size 4
+#define b43legacy_g_ratetable (__b43legacy_ratetable + 0)
+#define b43legacy_g_ratetable_size 12
+
+#define CHANTAB_ENT(_chanid, _freq) \
+ { \
+ .chan = (_chanid), \
+ .freq = (_freq), \
+ .val = (_chanid), \
+ .flag = IEEE80211_CHAN_W_SCAN | \
+ IEEE80211_CHAN_W_ACTIVE_SCAN | \
+ IEEE80211_CHAN_W_IBSS, \
+ .power_level = 0x0A, \
+ .antenna_max = 0xFF, \
+ }
+static struct ieee80211_channel b43legacy_bg_chantable[] = {
+ CHANTAB_ENT(1, 2412),
+ CHANTAB_ENT(2, 2417),
+ CHANTAB_ENT(3, 2422),
+ CHANTAB_ENT(4, 2427),
+ CHANTAB_ENT(5, 2432),
+ CHANTAB_ENT(6, 2437),
+ CHANTAB_ENT(7, 2442),
+ CHANTAB_ENT(8, 2447),
+ CHANTAB_ENT(9, 2452),
+ CHANTAB_ENT(10, 2457),
+ CHANTAB_ENT(11, 2462),
+ CHANTAB_ENT(12, 2467),
+ CHANTAB_ENT(13, 2472),
+ CHANTAB_ENT(14, 2484),
+};
+#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable)
+
+static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);
+static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);
+static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev);
+static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev);
+
+
+static int b43legacy_ratelimit(struct b43legacy_wl *wl)
+{
+ if (!wl || !wl->current_dev)
+ return 1;
+ if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED)
+ return 1;
+ /* We are up and running.
+ * Ratelimit the messages to avoid DoS over the net. */
+ return net_ratelimit();
+}
+
+void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_INFO "b43legacy-%s: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_ERR "b43legacy-%s ERROR: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_WARNING "b43legacy-%s warning: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+#if B43legacy_DEBUG
+void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "b43legacy-%s debug: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+#endif /* DEBUG */
+
+static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset,
+ u32 val)
+{
+ u32 status;
+
+ B43legacy_WARN_ON(offset % 4 != 0);
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
+ val = swab32(val);
+
+ b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val);
+}
+
+static inline
+void b43legacy_shm_control_word(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset)
+{
+ u32 control;
+
+ /* "offset" is the WORD offset. */
+
+ control = routing;
+ control <<= 16;
+ control |= offset;
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control);
+}
+
+u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset)
+{
+ u32 ret;
+
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ ret = b43legacy_read16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED);
+ ret <<= 16;
+ b43legacy_shm_control_word(dev, routing,
+ (offset >> 2) + 1);
+ ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset)
+{
+ u16 ret;
+
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ ret = b43legacy_read16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+void b43legacy_shm_write32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset,
+ u32 value)
+{
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43legacy_write16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED,
+ (value >> 16) & 0xffff);
+ mmiowb();
+ b43legacy_shm_control_word(dev, routing,
+ (offset >> 2) + 1);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA,
+ value & 0xffff);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value);
+}
+
+void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset,
+ u16 value)
+{
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43legacy_write16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED,
+ value);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value);
+}
+
+/* Read HostFlags */
+u32 b43legacy_hf_read(struct b43legacy_wldev *dev)
+{
+ u32 ret;
+
+ ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFHI);
+ ret <<= 16;
+ ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFLO);
+
+ return ret;
+}
+
+/* Write HostFlags */
+void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value)
+{
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFLO,
+ (value & 0x0000FFFF));
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFHI,
+ ((value & 0xFFFF0000) >> 16));
+}
+
+void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf)
+{
+ /* We need to be careful. As we read the TSF from multiple
+ * registers, we should take care of register overflows.
+ * In theory, the whole tsf read process should be atomic.
+ * We try to be atomic here, by restaring the read process,
+ * if any of the high registers changed (overflew).
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 low;
+ u32 high;
+ u32 high2;
+
+ do {
+ high = b43legacy_read32(dev,
+ B43legacy_MMIO_REV3PLUS_TSF_HIGH);
+ low = b43legacy_read32(dev,
+ B43legacy_MMIO_REV3PLUS_TSF_LOW);
+ high2 = b43legacy_read32(dev,
+ B43legacy_MMIO_REV3PLUS_TSF_HIGH);
+ } while (unlikely(high != high2));
+
+ *tsf = high;
+ *tsf <<= 32;
+ *tsf |= low;
+ } else {
+ u64 tmp;
+ u16 v0;
+ u16 v1;
+ u16 v2;
+ u16 v3;
+ u16 test1;
+ u16 test2;
+ u16 test3;
+
+ do {
+ v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
+ v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
+ v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
+ v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0);
+
+ test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
+ test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
+ test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
+ } while (v3 != test3 || v2 != test2 || v1 != test1);
+
+ *tsf = v3;
+ *tsf <<= 48;
+ tmp = v2;
+ tmp <<= 32;
+ *tsf |= tmp;
+ tmp = v1;
+ tmp <<= 16;
+ *tsf |= tmp;
+ *tsf |= v0;
+ }
+}
+
+static void b43legacy_time_lock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status |= B43legacy_SBF_TIME_UPDATE;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ mmiowb();
+}
+
+static void b43legacy_time_unlock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status &= ~B43legacy_SBF_TIME_UPDATE;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+}
+
+static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
+{
+ /* Be careful with the in-progress timer.
+ * First zero out the low register, so we have a full
+ * register-overflow duration to complete the operation.
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+ u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+ b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, 0);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH,
+ hi);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW,
+ lo);
+ } else {
+ u16 v0 = (tsf & 0x000000000000FFFFULL);
+ u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+ u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+ u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_0, 0);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_3, v3);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_2, v2);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_1, v1);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_0, v0);
+ }
+}
+
+void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf)
+{
+ b43legacy_time_lock(dev);
+ b43legacy_tsf_write_locked(dev, tsf);
+ b43legacy_time_unlock(dev);
+}
+
+static
+void b43legacy_macfilter_set(struct b43legacy_wldev *dev,
+ u16 offset, const u8 *mac)
+{
+ static const u8 zero_addr[ETH_ALEN] = { 0 };
+ u16 data;
+
+ if (!mac)
+ mac = zero_addr;
+
+ offset |= 0x0020;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_CONTROL, offset);
+
+ data = mac[0];
+ data |= mac[1] << 8;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+ data = mac[2];
+ data |= mac[3] << 8;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+ data = mac[4];
+ data |= mac[5] << 8;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+}
+
+static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev)
+{
+ static const u8 zero_addr[ETH_ALEN] = { 0 };
+ const u8 *mac = dev->wl->mac_addr;
+ const u8 *bssid = dev->wl->bssid;
+ u8 mac_bssid[ETH_ALEN * 2];
+ int i;
+ u32 tmp;
+
+ if (!bssid)
+ bssid = zero_addr;
+ if (!mac)
+ mac = zero_addr;
+
+ b43legacy_macfilter_set(dev, B43legacy_MACFILTER_BSSID, bssid);
+
+ memcpy(mac_bssid, mac, ETH_ALEN);
+ memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+ /* Write our MAC address and BSSID to template ram */
+ for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+ tmp = (u32)(mac_bssid[i + 0]);
+ tmp |= (u32)(mac_bssid[i + 1]) << 8;
+ tmp |= (u32)(mac_bssid[i + 2]) << 16;
+ tmp |= (u32)(mac_bssid[i + 3]) << 24;
+ b43legacy_ram_write(dev, 0x20 + i, tmp);
+ b43legacy_ram_write(dev, 0x78 + i, tmp);
+ b43legacy_ram_write(dev, 0x478 + i, tmp);
+ }
+}
+
+static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev)
+{
+ b43legacy_write_mac_bssid_templates(dev);
+ b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF,
+ dev->wl->mac_addr);
+}
+
+static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
+ u16 slot_time)
+{
+ /* slot_time is in usec. */
+ if (dev->phy.type != B43legacy_PHYTYPE_G)
+ return;
+ b43legacy_write16(dev, 0x684, 510 + slot_time);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0010,
+ slot_time);
+}
+
+static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
+{
+ b43legacy_set_slot_time(dev, 9);
+ dev->short_slot = 1;
+}
+
+static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
+{
+ b43legacy_set_slot_time(dev, 20);
+ dev->short_slot = 0;
+}
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev,
+ u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask |
+ mask);
+
+ return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev,
+ u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+ return old_mask;
+}
+
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev)
+{
+ synchronize_irq(dev->dev->irq);
+ tasklet_kill(&dev->isr_tasklet);
+}
+
+/* DummyTransmission function, as documented on
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void b43legacy_dummy_transmission(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ unsigned int i;
+ unsigned int max_loop;
+ u16 value;
+ u32 buffer[5] = {
+ 0x00000000,
+ 0x00D40000,
+ 0x00000000,
+ 0x01000000,
+ 0x00000000,
+ };
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ max_loop = 0xFA;
+ buffer[0] = 0x000B846E;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ b43legacy_ram_write(dev, i * 4, buffer[i]);
+
+ /* dummy read follows */
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+
+ b43legacy_write16(dev, 0x0568, 0x0000);
+ b43legacy_write16(dev, 0x07C0, 0x0000);
+ b43legacy_write16(dev, 0x050C, 0x0000);
+ b43legacy_write16(dev, 0x0508, 0x0000);
+ b43legacy_write16(dev, 0x050A, 0x0000);
+ b43legacy_write16(dev, 0x054C, 0x0000);
+ b43legacy_write16(dev, 0x056A, 0x0014);
+ b43legacy_write16(dev, 0x0568, 0x0826);
+ b43legacy_write16(dev, 0x0500, 0x0000);
+ b43legacy_write16(dev, 0x0502, 0x0030);
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43legacy_radio_write16(dev, 0x0051, 0x0017);
+ for (i = 0x00; i < max_loop; i++) {
+ value = b43legacy_read16(dev, 0x050E);
+ if (value & 0x0080)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43legacy_read16(dev, 0x050E);
+ if (value & 0x0400)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43legacy_read16(dev, 0x0690);
+ if (!(value & 0x0100))
+ break;
+ udelay(10);
+ }
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43legacy_radio_write16(dev, 0x0051, 0x0037);
+}
+
+/* Turn the Analog ON/OFF */
+static void b43legacy_switch_analog(struct b43legacy_wldev *dev, int on)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_PHY0, on ? 0 : 0xF4);
+}
+
+void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags)
+{
+ u32 tmslow;
+ u32 macctl;
+
+ flags |= B43legacy_TMSLOW_PHYCLKEN;
+ flags |= B43legacy_TMSLOW_PHYRESET;
+ ssb_device_enable(dev->dev, flags);
+ msleep(2); /* Wait for the PLL to turn on. */
+
+ /* Now take the PHY out of Reset again */
+ tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ tmslow |= SSB_TMSLOW_FGC;
+ tmslow &= ~B43legacy_TMSLOW_PHYRESET;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+
+ /* Turn Analog ON */
+ b43legacy_switch_analog(dev, 1);
+
+ macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ macctl &= ~B43legacy_MACCTL_GMODE;
+ if (flags & B43legacy_TMSLOW_GMODE) {
+ macctl |= B43legacy_MACCTL_GMODE;
+ dev->phy.gmode = 1;
+ } else
+ dev->phy.gmode = 0;
+ macctl |= B43legacy_MACCTL_IHR_ENABLED;
+ b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+}
+
+static void handle_irq_transmit_status(struct b43legacy_wldev *dev)
+{
+ u32 v0;
+ u32 v1;
+ u16 tmp;
+ struct b43legacy_txstatus stat;
+
+ while (1) {
+ v0 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
+ if (!(v0 & 0x00000001))
+ break;
+ v1 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
+
+ stat.cookie = (v0 >> 16);
+ stat.seq = (v1 & 0x0000FFFF);
+ stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
+ tmp = (v0 & 0x0000FFFF);
+ stat.frame_count = ((tmp & 0xF000) >> 12);
+ stat.rts_count = ((tmp & 0x0F00) >> 8);
+ stat.supp_reason = ((tmp & 0x001C) >> 2);
+ stat.pm_indicated = !!(tmp & 0x0080);
+ stat.intermediate = !!(tmp & 0x0040);
+ stat.for_ampdu = !!(tmp & 0x0020);
+ stat.acked = !!(tmp & 0x0002);
+
+ b43legacy_handle_txstatus(dev, &stat);
+ }
+}
+
+static void drain_txstatus_queue(struct b43legacy_wldev *dev)
+{
+ u32 dummy;
+
+ if (dev->dev->id.revision < 5)
+ return;
+ /* Read all entries from the microcode TXstatus FIFO
+ * and throw them away.
+ */
+ while (1) {
+ dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
+ if (!(dummy & 0x00000001))
+ break;
+ dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
+ }
+}
+
+static u32 b43legacy_jssi_read(struct b43legacy_wldev *dev)
+{
+ u32 val = 0;
+
+ val = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x40A);
+ val <<= 16;
+ val |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x408);
+
+ return val;
+}
+
+static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi)
+{
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x408,
+ (jssi & 0x0000FFFF));
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x40A,
+ (jssi & 0xFFFF0000) >> 16);
+}
+
+static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
+{
+ b43legacy_jssi_write(dev, 0x7F7F7F7F);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS2_BITFIELD)
+ | (1 << 4));
+ B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
+ dev->phy.channel);
+}
+
+static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev)
+{
+ /* Top half of Link Quality calculation. */
+
+ if (dev->noisecalc.calculation_running)
+ return;
+ dev->noisecalc.channel_at_start = dev->phy.channel;
+ dev->noisecalc.calculation_running = 1;
+ dev->noisecalc.nr_samples = 0;
+
+ b43legacy_generate_noise_sample(dev);
+}
+
+static void handle_irq_noise(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+ u8 noise[4];
+ u8 i;
+ u8 j;
+ s32 average;
+
+ /* Bottom half of Link Quality calculation. */
+
+ B43legacy_WARN_ON(!dev->noisecalc.calculation_running);
+ if (dev->noisecalc.channel_at_start != phy->channel)
+ goto drop_calculation;
+ *((__le32 *)noise) = cpu_to_le32(b43legacy_jssi_read(dev));
+ if (noise[0] == 0x7F || noise[1] == 0x7F ||
+ noise[2] == 0x7F || noise[3] == 0x7F)
+ goto generate_new;
+
+ /* Get the noise samples. */
+ B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
+ i = dev->noisecalc.nr_samples;
+ noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
+ dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
+ dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
+ dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
+ dev->noisecalc.nr_samples++;
+ if (dev->noisecalc.nr_samples == 8) {
+ /* Calculate the Link Quality by the noise samples. */
+ average = 0;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 4; j++)
+ average += dev->noisecalc.samples[i][j];
+ }
+ average /= (8 * 4);
+ average *= 125;
+ average += 64;
+ average /= 128;
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x40C);
+ tmp = (tmp / 128) & 0x1F;
+ if (tmp >= 8)
+ average += 2;
+ else
+ average -= 25;
+ if (tmp == 8)
+ average -= 72;
+ else
+ average -= 48;
+
+ dev->stats.link_noise = average;
+drop_calculation:
+ dev->noisecalc.calculation_running = 0;
+ return;
+ }
+generate_new:
+ b43legacy_generate_noise_sample(dev);
+}
+
+static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev)
+{
+ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ /* TODO: PS TBTT */
+ } else {
+ if (1/*FIXME: the last PSpoll frame was sent successfully */)
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+ dev->reg124_set_0x4 = 0;
+ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ dev->reg124_set_0x4 = 1;
+}
+
+static void handle_irq_atim_end(struct b43legacy_wldev *dev)
+{
+ if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
+ return;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
+ | 0x4);
+}
+
+static void handle_irq_pmq(struct b43legacy_wldev *dev)
+{
+ u32 tmp;
+
+ /* TODO: AP mode. */
+
+ while (1) {
+ tmp = b43legacy_read32(dev, B43legacy_MMIO_PS_STATUS);
+ if (!(tmp & 0x00000008))
+ break;
+ }
+ /* 16bit write is odd, but correct. */
+ b43legacy_write16(dev, B43legacy_MMIO_PS_STATUS, 0x0002);
+}
+
+static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
+ const u8 *data, u16 size,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u32 i;
+ u32 tmp;
+ struct b43legacy_plcp_hdr4 plcp;
+
+ plcp.data = 0;
+ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
+ ram_offset += sizeof(u32);
+ /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+ * So leave the first two bytes of the next write blank.
+ */
+ tmp = (u32)(data[0]) << 16;
+ tmp |= (u32)(data[1]) << 24;
+ b43legacy_ram_write(dev, ram_offset, tmp);
+ ram_offset += sizeof(u32);
+ for (i = 2; i < size; i += sizeof(u32)) {
+ tmp = (u32)(data[i + 0]);
+ if (i + 1 < size)
+ tmp |= (u32)(data[i + 1]) << 8;
+ if (i + 2 < size)
+ tmp |= (u32)(data[i + 2]) << 16;
+ if (i + 3 < size)
+ tmp |= (u32)(data[i + 3]) << 24;
+ b43legacy_ram_write(dev, ram_offset + i - 2, tmp);
+ }
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset,
+ size + sizeof(struct b43legacy_plcp_hdr6));
+}
+
+static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ int len;
+ const u8 *data;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+ len = min((size_t)dev->cached_beacon->len,
+ 0x200 - sizeof(struct b43legacy_plcp_hdr6));
+ data = (const u8 *)(dev->cached_beacon->data);
+ b43legacy_write_template_common(dev, data,
+ len, ram_offset,
+ shm_size_offset, rate);
+}
+
+static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
+ u16 shm_offset, u16 size,
+ u8 rate)
+{
+ struct b43legacy_plcp_hdr4 plcp;
+ u32 tmp;
+ __le16 dur;
+
+ plcp.data = 0;
+ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ size,
+ B43legacy_RATE_TO_100KBPS(rate));
+ /* Write PLCP in two parts and timing for packet transfer */
+ tmp = le32_to_cpu(plcp.data);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset,
+ tmp & 0xFFFF);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2,
+ tmp >> 16);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 6,
+ le16_to_cpu(dur));
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
+ u16 *dest_size, u8 rate)
+{
+ const u8 *src_data;
+ u8 *dest_data;
+ u16 src_size;
+ u16 elem_size;
+ u16 src_pos;
+ u16 dest_pos;
+ __le16 dur;
+ struct ieee80211_hdr *hdr;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+ src_size = dev->cached_beacon->len;
+ src_data = (const u8 *)dev->cached_beacon->data;
+
+ if (unlikely(src_size < 0x24)) {
+ b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: "
+ "invalid beacon\n");
+ return NULL;
+ }
+
+ dest_data = kmalloc(src_size, GFP_ATOMIC);
+ if (unlikely(!dest_data))
+ return NULL;
+
+ /* 0x24 is offset of first variable-len Information-Element
+ * in beacon frame.
+ */
+ memcpy(dest_data, src_data, 0x24);
+ src_pos = 0x24;
+ dest_pos = 0x24;
+ for (; src_pos < src_size - 2; src_pos += elem_size) {
+ elem_size = src_data[src_pos + 1] + 2;
+ if (src_data[src_pos] != 0x05) { /* TIM */
+ memcpy(dest_data + dest_pos, src_data + src_pos,
+ elem_size);
+ dest_pos += elem_size;
+ }
+ }
+ *dest_size = dest_pos;
+ hdr = (struct ieee80211_hdr *)dest_data;
+
+ /* Set the frame control. */
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ *dest_size,
+ B43legacy_RATE_TO_100KBPS(rate));
+ hdr->duration_id = dur;
+
+ return dest_data;
+}
+
+static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u8 *probe_resp_data;
+ u16 size;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+ size = dev->cached_beacon->len;
+ probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate);
+ if (unlikely(!probe_resp_data))
+ return;
+
+ /* Looks like PLCP headers plus packet timings are stored for
+ * all possible basic rates
+ */
+ b43legacy_write_probe_resp_plcp(dev, 0x31A, size,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_probe_resp_plcp(dev, 0x32C, size,
+ B43legacy_CCK_RATE_2MB);
+ b43legacy_write_probe_resp_plcp(dev, 0x33E, size,
+ B43legacy_CCK_RATE_5MB);
+ b43legacy_write_probe_resp_plcp(dev, 0x350, size,
+ B43legacy_CCK_RATE_11MB);
+
+ size = min((size_t)size,
+ 0x200 - sizeof(struct b43legacy_plcp_hdr6));
+ b43legacy_write_template_common(dev, probe_resp_data,
+ size, ram_offset,
+ shm_size_offset, rate);
+ kfree(probe_resp_data);
+}
+
+static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev,
+ struct sk_buff *beacon)
+{
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = beacon;
+
+ return 0;
+}
+
+static void b43legacy_update_templates(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+
+ b43legacy_write_beacon_template(dev, 0x68, 0x18,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
+ B43legacy_CCK_RATE_11MB);
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+ status |= 0x03;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
+ struct sk_buff *beacon)
+{
+ int err;
+
+ err = b43legacy_refresh_cached_beacon(dev, beacon);
+ if (unlikely(err))
+ return;
+ b43legacy_update_templates(dev);
+}
+
+static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
+ const u8 *ssid, u8 ssid_len)
+{
+ u32 tmp;
+ u16 i;
+ u16 len;
+
+ len = min((u16)ssid_len, (u16)0x100);
+ for (i = 0; i < len; i += sizeof(u32)) {
+ tmp = (u32)(ssid[i + 0]);
+ if (i + 1 < len)
+ tmp |= (u32)(ssid[i + 1]) << 8;
+ if (i + 2 < len)
+ tmp |= (u32)(ssid[i + 2]) << 16;
+ if (i + 3 < len)
+ tmp |= (u32)(ssid[i + 3]) << 24;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ 0x380 + i, tmp);
+ }
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ 0x48, len);
+}
+
+static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
+ u16 beacon_int)
+{
+ b43legacy_time_lock(dev);
+ if (dev->dev->id.revision >= 3)
+ b43legacy_write32(dev, 0x188, (beacon_int << 16));
+ else {
+ b43legacy_write16(dev, 0x606, (beacon_int >> 6));
+ b43legacy_write16(dev, 0x610, beacon_int);
+ }
+ b43legacy_time_unlock(dev);
+}
+
+static void handle_irq_beacon(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ return;
+
+ dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+
+ if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+ /* ACK beacon IRQ. */
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ B43legacy_IRQ_BEACON);
+ dev->irq_savedstate |= B43legacy_IRQ_BEACON;
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = NULL;
+ return;
+ }
+ if (!(status & 0x1)) {
+ b43legacy_write_beacon_template(dev, 0x68, 0x18,
+ B43legacy_CCK_RATE_1MB);
+ status |= 0x1;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ status);
+ }
+ if (!(status & 0x2)) {
+ b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+ B43legacy_CCK_RATE_1MB);
+ status |= 0x2;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ status);
+ }
+}
+
+static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
+{
+}
+
+/* Interrupt handler bottom-half */
+static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
+{
+ u32 reason;
+ u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
+ u32 merged_dma_reason = 0;
+ int i;
+ int activity = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+ B43legacy_WARN_ON(b43legacy_status(dev) <
+ B43legacy_STAT_INITIALIZED);
+
+ reason = dev->irq_reason;
+ for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
+ dma_reason[i] = dev->dma_reason[i];
+ merged_dma_reason |= dma_reason[i];
+ }
+
+ if (unlikely(reason & B43legacy_IRQ_MAC_TXERR))
+ b43legacyerr(dev->wl, "MAC transmission error\n");
+
+ if (unlikely(reason & B43legacy_IRQ_PHY_TXERR))
+ b43legacyerr(dev->wl, "PHY transmission error\n");
+
+ if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK |
+ B43legacy_DMAIRQ_NONFATALMASK))) {
+ if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) {
+ b43legacyerr(dev->wl, "Fatal DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ b43legacy_controller_restart(dev, "DMA error");
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ return;
+ }
+ if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK)
+ b43legacyerr(dev->wl, "DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ }
+
+ if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG))
+ handle_irq_ucode_debug(dev);
+ if (reason & B43legacy_IRQ_TBTT_INDI)
+ handle_irq_tbtt_indication(dev);
+ if (reason & B43legacy_IRQ_ATIM_END)
+ handle_irq_atim_end(dev);
+ if (reason & B43legacy_IRQ_BEACON)
+ handle_irq_beacon(dev);
+ if (reason & B43legacy_IRQ_PMQ)
+ handle_irq_pmq(dev);
+ if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK)
+ ;/*TODO*/
+ if (reason & B43legacy_IRQ_NOISESAMPLE_OK)
+ handle_irq_noise(dev);
+
+ /* Check the DMA reason registers for received data. */
+ if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) {
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_rx(dev->pio.queue0);
+ else
+ b43legacy_dma_rx(dev->dma.rx_ring0);
+ /* We intentionally don't set "activity" to 1, here. */
+ }
+ B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE);
+ B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE);
+ if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) {
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_rx(dev->pio.queue3);
+ else
+ b43legacy_dma_rx(dev->dma.rx_ring3);
+ activity = 1;
+ }
+ B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE);
+ B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE);
+
+ if (reason & B43legacy_IRQ_TX_OK) {
+ handle_irq_transmit_status(dev);
+ activity = 1;
+ /* TODO: In AP mode, this also causes sending of powersave
+ responses. */
+ }
+
+ if (!modparam_noleds)
+ b43legacy_leds_update(dev, activity);
+ b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void pio_irq_workaround(struct b43legacy_wldev *dev,
+ u16 base, int queueidx)
+{
+ u16 rxctl;
+
+ rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL);
+ if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE)
+ dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE;
+ else
+ dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE;
+}
+
+static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason)
+{
+ if (b43legacy_using_pio(dev) &&
+ (dev->dev->id.revision < 3) &&
+ (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) {
+ /* Apply a PIO specific workaround to the dma_reasons */
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0);
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1);
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2);
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3);
+ }
+
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason);
+
+ b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON,
+ dev->dma_reason[0]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON,
+ dev->dma_reason[1]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON,
+ dev->dma_reason[2]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON,
+ dev->dma_reason[3]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON,
+ dev->dma_reason[4]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON,
+ dev->dma_reason[5]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct b43legacy_wldev *dev = dev_id;
+ u32 reason;
+
+ if (!dev)
+ return IRQ_NONE;
+
+ spin_lock(&dev->wl->irq_lock);
+
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+ goto out;
+ reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ if (reason == 0xffffffff) /* shared IRQ */
+ goto out;
+ ret = IRQ_HANDLED;
+ reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ if (!reason)
+ goto out;
+
+ dev->dma_reason[0] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA0_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[1] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA1_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[2] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA2_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[3] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA3_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[4] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA4_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[5] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA5_REASON)
+ & 0x0000DC00;
+
+ b43legacy_interrupt_ack(dev, reason);
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+ B43legacy_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ dev->irq_reason = reason;
+ tasklet_schedule(&dev->isr_tasklet);
+out:
+ mmiowb();
+ spin_unlock(&dev->wl->irq_lock);
+
+ return ret;
+}
+
+static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
+{
+ release_firmware(dev->fw.ucode);
+ dev->fw.ucode = NULL;
+ release_firmware(dev->fw.pcm);
+ dev->fw.pcm = NULL;
+ release_firmware(dev->fw.initvals);
+ dev->fw.initvals = NULL;
+ release_firmware(dev->fw.initvals_band);
+ dev->fw.initvals_band = NULL;
+}
+
+static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
+{
+ b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
+ "Drivers/bcm43xx#devicefirmware "
+ "and download the correct firmware (version 3).\n");
+}
+
+static int do_request_fw(struct b43legacy_wldev *dev,
+ const char *name,
+ const struct firmware **fw)
+{
+ char path[sizeof(modparam_fwpostfix) + 32];
+ struct b43legacy_fw_header *hdr;
+ u32 size;
+ int err;
+
+ if (!name)
+ return 0;
+
+ snprintf(path, ARRAY_SIZE(path),
+ "b43legacy%s/%s.fw",
+ modparam_fwpostfix, name);
+ err = request_firmware(fw, path, dev->dev->dev);
+ if (err) {
+ b43legacyerr(dev->wl, "Firmware file \"%s\" not found "
+ "or load failed.\n", path);
+ return err;
+ }
+ if ((*fw)->size < sizeof(struct b43legacy_fw_header))
+ goto err_format;
+ hdr = (struct b43legacy_fw_header *)((*fw)->data);
+ switch (hdr->type) {
+ case B43legacy_FW_TYPE_UCODE:
+ case B43legacy_FW_TYPE_PCM:
+ size = be32_to_cpu(hdr->size);
+ if (size != (*fw)->size - sizeof(struct b43legacy_fw_header))
+ goto err_format;
+ /* fallthrough */
+ case B43legacy_FW_TYPE_IV:
+ if (hdr->ver != 1)
+ goto err_format;
+ break;
+ default:
+ goto err_format;
+ }
+
+ return err;
+
+err_format:
+ b43legacyerr(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ return -EPROTO;
+}
+
+static int b43legacy_request_firmware(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_firmware *fw = &dev->fw;
+ const u8 rev = dev->dev->id.revision;
+ const char *filename;
+ u32 tmshigh;
+ int err;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ if (!fw->ucode) {
+ if (rev == 2)
+ filename = "ucode2";
+ else if (rev == 4)
+ filename = "ucode4";
+ else
+ filename = "ucode5";
+ err = do_request_fw(dev, filename, &fw->ucode);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->pcm) {
+ if (rev < 5)
+ filename = "pcm4";
+ else
+ filename = "pcm5";
+ err = do_request_fw(dev, filename, &fw->pcm);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals) {
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0initvals5";
+ else if (rev == 2 || rev == 4)
+ filename = "b0g0initvals2";
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals_band) {
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0bsinitvals5";
+ else if (rev >= 11)
+ filename = NULL;
+ else if (rev == 2 || rev == 4)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals_band);
+ if (err)
+ goto err_load;
+ }
+
+ return 0;
+
+err_load:
+ b43legacy_print_fw_helptext(dev->wl);
+ goto error;
+
+err_no_initvals:
+ err = -ENODEV;
+ b43legacyerr(dev->wl, "No Initial Values firmware file for PHY %u, "
+ "core rev %u\n", dev->phy.type, rev);
+ goto error;
+
+error:
+ b43legacy_release_firmware(dev);
+ return err;
+}
+
+static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43legacy_fw_header);
+ const __be32 *data;
+ unsigned int i;
+ unsigned int len;
+ u16 fwrev;
+ u16 fwpatch;
+ u16 fwdate;
+ u16 fwtime;
+ u32 tmp;
+ int err = 0;
+
+ /* Upload Microcode. */
+ data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+ len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+ b43legacy_shm_control_word(dev,
+ B43legacy_SHM_UCODE |
+ B43legacy_SHM_AUTOINC_W,
+ 0x0000);
+ for (i = 0; i < len; i++) {
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
+ be32_to_cpu(data[i]));
+ udelay(10);
+ }
+
+ if (dev->fw.pcm) {
+ /* Upload PCM data. */
+ data = (__be32 *) (dev->fw.pcm->data + hdr_len);
+ len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+ b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EA);
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, 0x00004000);
+ /* No need for autoinc bit in SHM_HW */
+ b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EB);
+ for (i = 0; i < len; i++) {
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
+ be32_to_cpu(data[i]));
+ udelay(10);
+ }
+ }
+
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ B43legacy_IRQ_ALL);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
+
+ /* Wait for the microcode to load and respond */
+ i = 0;
+ while (1) {
+ tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ if (tmp == B43legacy_IRQ_MAC_SUSPENDED)
+ break;
+ i++;
+ if (i >= B43legacy_IRQWAIT_MAX_RETRIES) {
+ b43legacyerr(dev->wl, "Microcode not responding\n");
+ b43legacy_print_fw_helptext(dev->wl);
+ err = -ENODEV;
+ goto out;
+ }
+ udelay(10);
+ }
+ /* dummy read follows */
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+
+ /* Get and check the revisions. */
+ fwrev = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODEREV);
+ fwpatch = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODEPATCH);
+ fwdate = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODEDATE);
+ fwtime = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODETIME);
+
+ if (fwrev > 0x128) {
+ b43legacyerr(dev->wl, "YOU ARE TRYING TO LOAD V4 FIRMWARE."
+ " Only firmware from binary drivers version 3.x"
+ " is supported. You must change your firmware"
+ " files.\n");
+ b43legacy_print_fw_helptext(dev->wl);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+
+ dev->fw.rev = fwrev;
+ dev->fw.patch = fwpatch;
+
+out:
+ return err;
+}
+
+static int b43legacy_write_initvals(struct b43legacy_wldev *dev,
+ const struct b43legacy_iv *ivals,
+ size_t count,
+ size_t array_size)
+{
+ const struct b43legacy_iv *iv;
+ u16 offset;
+ size_t i;
+ bool bit32;
+
+ BUILD_BUG_ON(sizeof(struct b43legacy_iv) != 6);
+ iv = ivals;
+ for (i = 0; i < count; i++) {
+ if (array_size < sizeof(iv->offset_size))
+ goto err_format;
+ array_size -= sizeof(iv->offset_size);
+ offset = be16_to_cpu(iv->offset_size);
+ bit32 = !!(offset & B43legacy_IV_32BIT);
+ offset &= B43legacy_IV_OFFSET_MASK;
+ if (offset >= 0x1000)
+ goto err_format;
+ if (bit32) {
+ u32 value;
+
+ if (array_size < sizeof(iv->data.d32))
+ goto err_format;
+ array_size -= sizeof(iv->data.d32);
+
+ value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ b43legacy_write32(dev, offset, value);
+
+ iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be32));
+ } else {
+ u16 value;
+
+ if (array_size < sizeof(iv->data.d16))
+ goto err_format;
+ array_size -= sizeof(iv->data.d16);
+
+ value = be16_to_cpu(iv->data.d16);
+ b43legacy_write16(dev, offset, value);
+
+ iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be16));
+ }
+ }
+ if (array_size)
+ goto err_format;
+
+ return 0;
+
+err_format:
+ b43legacyerr(dev->wl, "Initial Values Firmware file-format error.\n");
+ b43legacy_print_fw_helptext(dev->wl);
+
+ return -EPROTO;
+}
+
+static int b43legacy_upload_initvals(struct b43legacy_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43legacy_fw_header);
+ const struct b43legacy_fw_header *hdr;
+ struct b43legacy_firmware *fw = &dev->fw;
+ const struct b43legacy_iv *ivals;
+ size_t count;
+ int err;
+
+ hdr = (const struct b43legacy_fw_header *)(fw->initvals->data);
+ ivals = (const struct b43legacy_iv *)(fw->initvals->data + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43legacy_write_initvals(dev, ivals, count,
+ fw->initvals->size - hdr_len);
+ if (err)
+ goto out;
+ if (fw->initvals_band) {
+ hdr = (const struct b43legacy_fw_header *)
+ (fw->initvals_band->data);
+ ivals = (const struct b43legacy_iv *)(fw->initvals_band->data
+ + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43legacy_write_initvals(dev, ivals, count,
+ fw->initvals_band->size - hdr_len);
+ if (err)
+ goto out;
+ }
+out:
+
+ return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+ u32 mask;
+ u32 set;
+
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS_BITFIELD)
+ & 0xFFFF3FFF);
+
+ b43legacy_leds_switch_all(dev, 0);
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_GPIO_MASK)
+ | 0x000F);
+
+ mask = 0x0000001F;
+ set = 0x0000000F;
+ if (dev->dev->bus->chip_id == 0x4301) {
+ mask |= 0x0060;
+ set |= 0x0060;
+ }
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) {
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_GPIO_MASK)
+ | 0x0200);
+ mask |= 0x0200;
+ set |= 0x0200;
+ }
+ if (dev->dev->id.revision >= 2)
+ mask |= 0x0010; /* FIXME: This is redundant. */
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return 0;
+ ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
+ (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
+ & mask) | set);
+
+ return 0;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return;
+ ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, 0);
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void b43legacy_mac_enable(struct b43legacy_wldev *dev)
+{
+ dev->mac_suspended--;
+ B43legacy_WARN_ON(dev->mac_suspended < 0);
+ if (dev->mac_suspended == 0) {
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS_BITFIELD)
+ | B43legacy_SBF_MAC_ENABLED);
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ B43legacy_IRQ_MAC_SUSPENDED);
+ /* the next two are dummy reads */
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
+{
+ int i;
+ u32 tmp;
+
+ B43legacy_WARN_ON(dev->mac_suspended < 0);
+ if (dev->mac_suspended == 0) {
+ b43legacy_power_saving_ctl_bits(dev, -1, 1);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS_BITFIELD)
+ & ~B43legacy_SBF_MAC_ENABLED);
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ for (i = 10000; i; i--) {
+ tmp = b43legacy_read32(dev,
+ B43legacy_MMIO_GEN_IRQ_REASON);
+ if (tmp & B43legacy_IRQ_MAC_SUSPENDED)
+ goto out;
+ udelay(1);
+ }
+ b43legacyerr(dev->wl, "MAC suspend failed\n");
+ }
+out:
+ dev->mac_suspended++;
+}
+
+static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ u32 ctl;
+ u16 cfp_pretbtt;
+
+ ctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ /* Reset status to STA infrastructure mode. */
+ ctl &= ~B43legacy_MACCTL_AP;
+ ctl &= ~B43legacy_MACCTL_KEEP_CTL;
+ ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP;
+ ctl &= ~B43legacy_MACCTL_KEEP_BAD;
+ ctl &= ~B43legacy_MACCTL_PROMISC;
+ ctl &= ~B43legacy_MACCTL_BEACPROMISC;
+ ctl |= B43legacy_MACCTL_INFRA;
+
+ if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ ctl |= B43legacy_MACCTL_AP;
+ else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ ctl &= ~B43legacy_MACCTL_INFRA;
+
+ if (wl->filter_flags & FIF_CONTROL)
+ ctl |= B43legacy_MACCTL_KEEP_CTL;
+ if (wl->filter_flags & FIF_FCSFAIL)
+ ctl |= B43legacy_MACCTL_KEEP_BAD;
+ if (wl->filter_flags & FIF_PLCPFAIL)
+ ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
+ if (wl->filter_flags & FIF_PROMISC_IN_BSS)
+ ctl |= B43legacy_MACCTL_PROMISC;
+ if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+ ctl |= B43legacy_MACCTL_BEACPROMISC;
+
+ /* Workaround: On old hardware the HW-MAC-address-filter
+ * doesn't work properly, so always run promisc in filter
+ * it in software. */
+ if (dev->dev->id.revision <= 4)
+ ctl |= B43legacy_MACCTL_PROMISC;
+
+ b43legacy_write32(dev, B43legacy_MMIO_MACCTL, ctl);
+
+ cfp_pretbtt = 2;
+ if ((ctl & B43legacy_MACCTL_INFRA) &&
+ !(ctl & B43legacy_MACCTL_AP)) {
+ if (dev->dev->bus->chip_id == 0x4306 &&
+ dev->dev->bus->chip_rev == 3)
+ cfp_pretbtt = 100;
+ else
+ cfp_pretbtt = 50;
+ }
+ b43legacy_write16(dev, 0x612, cfp_pretbtt);
+}
+
+static void b43legacy_rate_memory_write(struct b43legacy_wldev *dev,
+ u16 rate,
+ int is_ofdm)
+{
+ u16 offset;
+
+ if (is_ofdm) {
+ offset = 0x480;
+ offset += (b43legacy_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+ } else {
+ offset = 0x4C0;
+ offset += (b43legacy_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+ }
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, offset + 0x20,
+ b43legacy_shm_read16(dev,
+ B43legacy_SHM_SHARED, offset));
+}
+
+static void b43legacy_rate_memory_init(struct b43legacy_wldev *dev)
+{
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_G:
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_6MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_12MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_18MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_24MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_36MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_48MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_54MB, 1);
+ /* fallthrough */
+ case B43legacy_PHYTYPE_B:
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_1MB, 0);
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_2MB, 0);
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_5MB, 0);
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_11MB, 0);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+/* Set the TX-Antenna for management frames sent by firmware. */
+static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
+ int antenna)
+{
+ u16 ant = 0;
+ u16 tmp;
+
+ switch (antenna) {
+ case B43legacy_ANTENNA0:
+ ant |= B43legacy_TX4_PHY_ANT0;
+ break;
+ case B43legacy_ANTENNA1:
+ ant |= B43legacy_TX4_PHY_ANT1;
+ break;
+ case B43legacy_ANTENNA_AUTO:
+ ant |= B43legacy_TX4_PHY_ANTLAST;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ /* FIXME We also need to set the other flags of the PHY control
+ * field somewhere. */
+
+ /* For Beacons */
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_BEACPHYCTL);
+ tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_BEACPHYCTL, tmp);
+ /* For ACK/CTS */
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_ACKCTSPHYCTL);
+ tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_ACKCTSPHYCTL, tmp);
+ /* For Probe Resposes */
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_PRPHYCTL);
+ tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_PRPHYCTL, tmp);
+}
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
+{
+ if (dev->phy.rev >= 3) {
+ if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
+ & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
+ return 1;
+ } else {
+ if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
+ & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the opposite of b43legacy_chip_init() */
+static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
+{
+ b43legacy_radio_turn_off(dev);
+ if (!modparam_noleds)
+ b43legacy_leds_exit(dev);
+ b43legacy_gpio_cleanup(dev);
+ /* firmware is released later */
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int err;
+ int tmp;
+ u32 value32;
+ u16 value16;
+
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ B43legacy_SBF_CORE_READY
+ | B43legacy_SBF_400);
+
+ err = b43legacy_request_firmware(dev);
+ if (err)
+ goto out;
+ err = b43legacy_upload_microcode(dev);
+ if (err)
+ goto out; /* firmware is released later */
+
+ err = b43legacy_gpio_init(dev);
+ if (err)
+ goto out; /* firmware is released later */
+ err = b43legacy_upload_initvals(dev);
+ if (err)
+ goto err_gpio_cleanup;
+ b43legacy_radio_turn_on(dev);
+
+ b43legacy_write16(dev, 0x03E6, 0x0000);
+ err = b43legacy_phy_init(dev);
+ if (err)
+ goto err_radio_off;
+
+ /* Select initial Interference Mitigation. */
+ tmp = phy->interfmode;
+ phy->interfmode = B43legacy_INTERFMODE_NONE;
+ b43legacy_radio_set_interference_mitigation(dev, tmp);
+
+ b43legacy_phy_set_antenna_diversity(dev);
+ b43legacy_mgmtframe_txantenna(dev, B43legacy_ANTENNA_DEFAULT);
+
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ value16 = b43legacy_read16(dev, 0x005E);
+ value16 |= 0x0004;
+ b43legacy_write16(dev, 0x005E, value16);
+ }
+ b43legacy_write32(dev, 0x0100, 0x01000000);
+ if (dev->dev->id.revision < 5)
+ b43legacy_write32(dev, 0x010C, 0x01000000);
+
+ value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+ value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ value32 |= B43legacy_SBF_MODE_NOTADHOC;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+
+ if (b43legacy_using_pio(dev)) {
+ b43legacy_write32(dev, 0x0210, 0x00000100);
+ b43legacy_write32(dev, 0x0230, 0x00000100);
+ b43legacy_write32(dev, 0x0250, 0x00000100);
+ b43legacy_write32(dev, 0x0270, 0x00000100);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0034,
+ 0x0000);
+ }
+
+ /* Probe Response Timeout value */
+ /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0074, 0x0000);
+
+ /* Initially set the wireless operation mode. */
+ b43legacy_adjust_opmode(dev);
+
+ if (dev->dev->id.revision < 3) {
+ b43legacy_write16(dev, 0x060E, 0x0000);
+ b43legacy_write16(dev, 0x0610, 0x8000);
+ b43legacy_write16(dev, 0x0604, 0x0000);
+ b43legacy_write16(dev, 0x0606, 0x0200);
+ } else {
+ b43legacy_write32(dev, 0x0188, 0x80000000);
+ b43legacy_write32(dev, 0x018C, 0x02000000);
+ }
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, 0x00004000);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+ value32 = ssb_read32(dev->dev, SSB_TMSLOW);
+ value32 |= 0x00100000;
+ ssb_write32(dev->dev, SSB_TMSLOW, value32);
+
+ b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
+ dev->dev->bus->chipco.fast_pwrup_delay);
+
+ B43legacy_WARN_ON(err != 0);
+ b43legacydbg(dev->wl, "Chip initialized\n");
+out:
+ return err;
+
+err_radio_off:
+ b43legacy_radio_turn_off(dev);
+err_gpio_cleanup:
+ b43legacy_gpio_cleanup(dev);
+ goto out;
+}
+
+static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->type != B43legacy_PHYTYPE_G || phy->rev < 2)
+ return;
+
+ b43legacy_mac_suspend(dev);
+ b43legacy_phy_lo_g_measure(dev);
+ b43legacy_mac_enable(dev);
+}
+
+static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev)
+{
+ b43legacy_phy_lo_mark_all_unused(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+ b43legacy_mac_suspend(dev);
+ b43legacy_calc_nrssi_slope(dev);
+ b43legacy_mac_enable(dev);
+ }
+}
+
+static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
+{
+ /* Update device statistics. */
+ b43legacy_calculate_link_quality(dev);
+}
+
+static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
+{
+ b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */
+}
+
+static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev)
+{
+ bool radio_hw_enable;
+
+ /* check if radio hardware enabled status changed */
+ radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
+ if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
+ dev->radio_hw_enable = radio_hw_enable;
+ b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n",
+ (radio_hw_enable) ? "enabled" : "disabled");
+ b43legacy_leds_update(dev, 0);
+ }
+}
+
+static void do_periodic_work(struct b43legacy_wldev *dev)
+{
+ unsigned int state;
+
+ state = dev->periodic_state;
+ if (state % 120 == 0)
+ b43legacy_periodic_every120sec(dev);
+ if (state % 60 == 0)
+ b43legacy_periodic_every60sec(dev);
+ if (state % 30 == 0)
+ b43legacy_periodic_every30sec(dev);
+ if (state % 15 == 0)
+ b43legacy_periodic_every15sec(dev);
+ b43legacy_periodic_every1sec(dev);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+ int badness = 0;
+
+ if (state % 120 == 0) /* every 120 sec */
+ badness += 10;
+ if (state % 60 == 0) /* every 60 sec */
+ badness += 5;
+ if (state % 30 == 0) /* every 30 sec */
+ badness += 1;
+ if (state % 15 == 0) /* every 15 sec */
+ badness += 1;
+
+#define BADNESS_LIMIT 4
+ return badness;
+}
+
+static void b43legacy_periodic_work_handler(struct work_struct *work)
+{
+ struct b43legacy_wldev *dev =
+ container_of(work, struct b43legacy_wldev,
+ periodic_work.work);
+ unsigned long flags;
+ unsigned long delay;
+ u32 savedirqs = 0;
+ int badness;
+
+ mutex_lock(&dev->wl->mutex);
+
+ if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED))
+ goto out;
+ if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP))
+ goto out_requeue;
+
+ badness = estimate_periodic_work_badness(dev->periodic_state);
+ if (badness > BADNESS_LIMIT) {
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ /* Suspend TX as we don't want to transmit packets while
+ * we recalibrate the hardware. */
+ b43legacy_tx_suspend(dev);
+ savedirqs = b43legacy_interrupt_disable(dev,
+ B43legacy_IRQ_ALL);
+ /* Periodic work will take a long time, so we want it to
+ * be preemtible and release the spinlock. */
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ do_periodic_work(dev);
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ b43legacy_interrupt_enable(dev, savedirqs);
+ b43legacy_tx_resume(dev);
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ } else {
+ /* Take the global driver lock. This will lock any operation. */
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+ do_periodic_work(dev);
+
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ }
+ dev->periodic_state++;
+out_requeue:
+ if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
+ delay = msecs_to_jiffies(50);
+ else
+ delay = round_jiffies(HZ);
+ queue_delayed_work(dev->wl->hw->workqueue,
+ &dev->periodic_work, delay);
+out:
+ mutex_unlock(&dev->wl->mutex);
+}
+
+static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
+{
+ struct delayed_work *work = &dev->periodic_work;
+
+ dev->periodic_state = 0;
+ INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
+ queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+}
+
+/* Validate access to the chip (SHM) */
+static int b43legacy_validate_chipaccess(struct b43legacy_wldev *dev)
+{
+ u32 value;
+ u32 shm_backup;
+
+ shm_backup = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0xAA5555AA);
+ if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
+ 0xAA5555AA)
+ goto error;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0x55AAAA55);
+ if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
+ 0x55AAAA55)
+ goto error;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, shm_backup);
+
+ value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ if ((value | B43legacy_MACCTL_GMODE) !=
+ (B43legacy_MACCTL_GMODE | B43legacy_MACCTL_IHR_ENABLED))
+ goto error;
+
+ value = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ if (value)
+ goto error;
+
+ return 0;
+error:
+ b43legacyerr(dev->wl, "Failed to validate the chipaccess\n");
+ return -ENODEV;
+}
+
+static void b43legacy_security_init(struct b43legacy_wldev *dev)
+{
+ dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
+ B43legacy_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
+ dev->ktp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x0056);
+ /* KTP is a word address, but we address SHM bytewise.
+ * So multiply by two.
+ */
+ dev->ktp *= 2;
+ if (dev->dev->id.revision >= 5)
+ /* Number of RCMTA address slots */
+ b43legacy_write16(dev, B43legacy_MMIO_RCMTA_COUNT,
+ dev->max_nr_keys - 8);
+}
+
+static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
+{
+ struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
+ unsigned long flags;
+
+ /* Don't take wl->mutex here, as it could deadlock with
+ * hwrng internal locking. It's not needed to take
+ * wl->mutex here, anyway. */
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *data = b43legacy_read16(wl->current_dev, B43legacy_MMIO_RNG);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return (sizeof(u16));
+}
+
+static void b43legacy_rng_exit(struct b43legacy_wl *wl)
+{
+ if (wl->rng_initialized)
+ hwrng_unregister(&wl->rng);
+}
+
+static int b43legacy_rng_init(struct b43legacy_wl *wl)
+{
+ int err;
+
+ snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
+ "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
+ wl->rng.name = wl->rng_name;
+ wl->rng.data_read = b43legacy_rng_read;
+ wl->rng.priv = (unsigned long)wl;
+ wl->rng_initialized = 1;
+ err = hwrng_register(&wl->rng);
+ if (err) {
+ wl->rng_initialized = 0;
+ b43legacyerr(wl, "Failed to register the random "
+ "number generator (%d)\n", err);
+ }
+
+ return err;
+}
+
+static int b43legacy_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ int err = -ENODEV;
+ unsigned long flags;
+
+ if (unlikely(!dev))
+ goto out;
+ if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
+ goto out;
+ /* DMA-TX is done without a global lock. */
+ if (b43legacy_using_pio(dev)) {
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ err = b43legacy_pio_tx(dev, skb, ctl);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ } else
+ err = b43legacy_dma_tx(dev, skb, ctl);
+out:
+ if (unlikely(err))
+ return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
+}
+
+static int b43legacy_conf_tx(struct ieee80211_hw *hw,
+ int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ return 0;
+}
+
+static int b43legacy_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ int err = -ENODEV;
+
+ if (!dev)
+ goto out;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) {
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_get_tx_stats(dev, stats);
+ else
+ b43legacy_dma_get_tx_stats(dev, stats);
+ err = 0;
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+out:
+ return err;
+}
+
+static int b43legacy_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ memcpy(stats, &wl->ieee_stats, sizeof(*stats));
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+}
+
+static const char *phymode_to_string(unsigned int phymode)
+{
+ switch (phymode) {
+ case B43legacy_PHYMODE_B:
+ return "B";
+ case B43legacy_PHYMODE_G:
+ return "G";
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ return "";
+}
+
+static int find_wldev_for_phymode(struct b43legacy_wl *wl,
+ unsigned int phymode,
+ struct b43legacy_wldev **dev,
+ bool *gmode)
+{
+ struct b43legacy_wldev *d;
+
+ list_for_each_entry(d, &wl->devlist, list) {
+ if (d->phy.possible_phymodes & phymode) {
+ /* Ok, this device supports the PHY-mode.
+ * Set the gmode bit. */
+ *gmode = 1;
+ *dev = d;
+
+ return 0;
+ }
+ }
+
+ return -ESRCH;
+}
+
+static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev)
+{
+ struct ssb_device *sdev = dev->dev;
+ u32 tmslow;
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~B43legacy_TMSLOW_GMODE;
+ tmslow |= B43legacy_TMSLOW_PHYRESET;
+ tmslow |= SSB_TMSLOW_FGC;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ tmslow |= B43legacy_TMSLOW_PHYRESET;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+}
+
+/* Expects wl->mutex locked */
+static int b43legacy_switch_phymode(struct b43legacy_wl *wl,
+ unsigned int new_mode)
+{
+ struct b43legacy_wldev *up_dev;
+ struct b43legacy_wldev *down_dev;
+ int err;
+ bool gmode = 0;
+ int prev_status;
+
+ err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+ if (err) {
+ b43legacyerr(wl, "Could not find a device for %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ return err;
+ }
+ if ((up_dev == wl->current_dev) &&
+ (!!wl->current_dev->phy.gmode == !!gmode))
+ /* This device is already running. */
+ return 0;
+ b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+ phymode_to_string(new_mode));
+ down_dev = wl->current_dev;
+
+ prev_status = b43legacy_status(down_dev);
+ /* Shutdown the currently running core. */
+ if (prev_status >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(down_dev);
+ if (prev_status >= B43legacy_STAT_INITIALIZED)
+ b43legacy_wireless_core_exit(down_dev);
+
+ if (down_dev != up_dev)
+ /* We switch to a different core, so we put PHY into
+ * RESET on the old core. */
+ b43legacy_put_phy_into_reset(down_dev);
+
+ /* Now start the new core. */
+ up_dev->phy.gmode = gmode;
+ if (prev_status >= B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(up_dev);
+ if (err) {
+ b43legacyerr(wl, "Fatal: Could not initialize device"
+ " for newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ goto init_failure;
+ }
+ }
+ if (prev_status >= B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(up_dev);
+ if (err) {
+ b43legacyerr(wl, "Fatal: Coult not start device for "
+ "newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ b43legacy_wireless_core_exit(up_dev);
+ goto init_failure;
+ }
+ }
+ B43legacy_WARN_ON(b43legacy_status(up_dev) != prev_status);
+
+ b43legacy_shm_write32(up_dev, B43legacy_SHM_SHARED, 0x003E, 0);
+
+ wl->current_dev = up_dev;
+
+ return 0;
+init_failure:
+ /* Whoops, failed to init the new core. No core is operating now. */
+ wl->current_dev = NULL;
+ return err;
+}
+
+static int b43legacy_antenna_from_ieee80211(u8 antenna)
+{
+ switch (antenna) {
+ case 0: /* default/diversity */
+ return B43legacy_ANTENNA_DEFAULT;
+ case 1: /* Antenna 0 */
+ return B43legacy_ANTENNA0;
+ case 2: /* Antenna 1 */
+ return B43legacy_ANTENNA1;
+ default:
+ return B43legacy_ANTENNA_DEFAULT;
+ }
+}
+
+static int b43legacy_dev_config(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev;
+ struct b43legacy_phy *phy;
+ unsigned long flags;
+ unsigned int new_phymode = 0xFFFF;
+ int antenna_tx;
+ int antenna_rx;
+ int err = 0;
+ u32 savedirqs;
+
+ antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
+ antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+ mutex_lock(&wl->mutex);
+
+ /* Switch the PHY mode (if necessary). */
+ switch (conf->phymode) {
+ case MODE_IEEE80211B:
+ new_phymode = B43legacy_PHYMODE_B;
+ break;
+ case MODE_IEEE80211G:
+ new_phymode = B43legacy_PHYMODE_G;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ err = b43legacy_switch_phymode(wl, new_phymode);
+ if (err)
+ goto out_unlock_mutex;
+ dev = wl->current_dev;
+ phy = &dev->phy;
+
+ /* Disable IRQs while reconfiguring the device.
+ * This makes it possible to drop the spinlock throughout
+ * the reconfiguration process. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ goto out_unlock_mutex;
+ }
+ savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ /* Switch to the requested channel.
+ * The firmware takes care of races with the TX handler. */
+ if (conf->channel_val != phy->channel)
+ b43legacy_radio_selectchannel(dev, conf->channel_val, 0);
+
+ /* Enable/Disable ShortSlot timing. */
+ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
+ != dev->short_slot) {
+ B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
+ if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+ b43legacy_short_slot_timing_enable(dev);
+ else
+ b43legacy_short_slot_timing_disable(dev);
+ }
+
+ /* Adjust the desired TX power level. */
+ if (conf->power_level != 0) {
+ if (conf->power_level != phy->power_level) {
+ phy->power_level = conf->power_level;
+ b43legacy_phy_xmitpower(dev);
+ }
+ }
+
+ /* Antennas for RX and management frame TX. */
+ b43legacy_mgmtframe_txantenna(dev, antenna_tx);
+
+ /* Update templates for AP mode. */
+ if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ b43legacy_set_beacon_int(dev, conf->beacon_int);
+
+
+ if (!!conf->radio_enabled != phy->radio_on) {
+ if (conf->radio_enabled) {
+ b43legacy_radio_turn_on(dev);
+ b43legacyinfo(dev->wl, "Radio turned on by software\n");
+ if (!dev->radio_hw_enable)
+ b43legacyinfo(dev->wl, "The hardware RF-kill"
+ " button still turns the radio"
+ " physically off. Press the"
+ " button to turn it on.\n");
+ } else {
+ b43legacy_radio_turn_off(dev);
+ b43legacyinfo(dev->wl, "Radio turned off by"
+ " software\n");
+ }
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_interrupt_enable(dev, savedirqs);
+ mmiowb();
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+out_unlock_mutex:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+ DECLARE_MAC_BUF(mac);
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = -ENODEV;
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+ b43legacydbg(wl, "Using software based encryption for "
+ "mac: %s\n", print_mac(mac, addr));
+ return err;
+}
+
+static void b43legacy_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed,
+ unsigned int *fflags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev) {
+ *fflags = 0;
+ return;
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *fflags &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ changed &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ wl->filter_flags = *fflags;
+
+ if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
+ b43legacy_adjust_opmode(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+}
+
+static int b43legacy_config_interface(struct ieee80211_hw *hw,
+ int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ B43legacy_WARN_ON(wl->if_id != if_id);
+ if (conf->bssid)
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ else
+ memset(wl->bssid, 0, ETH_ALEN);
+ if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
+ if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+ B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
+ if (conf->beacon)
+ b43legacy_refresh_templates(dev, conf->beacon);
+ }
+ b43legacy_write_mac_bssid_templates(dev);
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+/* Locking: wl->mutex */
+static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ unsigned long flags;
+
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+ return;
+ b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
+
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel the possibly running self-rearming periodic work. */
+ cancel_delayed_work_sync(&dev->periodic_work);
+ mutex_lock(&wl->mutex);
+
+ ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
+
+ /* Disable and sync interrupts. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+ B43legacy_IRQ_ALL);
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ b43legacy_mac_suspend(dev);
+ free_irq(dev->dev->irq, dev);
+ b43legacydbg(wl, "Wireless interface stopped\n");
+}
+
+/* Locking: wl->mutex */
+static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
+{
+ int err;
+
+ B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_INITIALIZED);
+
+ drain_txstatus_queue(dev);
+ err = request_irq(dev->dev->irq, b43legacy_interrupt_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ b43legacyerr(dev->wl, "Cannot request IRQ-%d\n",
+ dev->dev->irq);
+ goto out;
+ }
+ /* We are ready to run. */
+ b43legacy_set_status(dev, B43legacy_STAT_STARTED);
+
+ /* Start data flow (TX/RX) */
+ b43legacy_mac_enable(dev);
+ b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+ ieee80211_start_queues(dev->wl->hw);
+
+ /* Start maintenance work */
+ b43legacy_periodic_tasks_setup(dev);
+
+ b43legacydbg(dev->wl, "Wireless interface started\n");
+out:
+ return err;
+}
+
+/* Get PHY and RADIO versioning numbers */
+static int b43legacy_phy_versioning(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u32 tmp;
+ u8 analog_type;
+ u8 phy_type;
+ u8 phy_rev;
+ u16 radio_manuf;
+ u16 radio_ver;
+ u16 radio_rev;
+ int unsupported = 0;
+
+ /* Get PHY versioning */
+ tmp = b43legacy_read16(dev, B43legacy_MMIO_PHY_VER);
+ analog_type = (tmp & B43legacy_PHYVER_ANALOG)
+ >> B43legacy_PHYVER_ANALOG_SHIFT;
+ phy_type = (tmp & B43legacy_PHYVER_TYPE) >> B43legacy_PHYVER_TYPE_SHIFT;
+ phy_rev = (tmp & B43legacy_PHYVER_VERSION);
+ switch (phy_type) {
+ case B43legacy_PHYTYPE_B:
+ if (phy_rev != 2 && phy_rev != 4
+ && phy_rev != 6 && phy_rev != 7)
+ unsupported = 1;
+ break;
+ case B43legacy_PHYTYPE_G:
+ if (phy_rev > 8)
+ unsupported = 1;
+ break;
+ default:
+ unsupported = 1;
+ };
+ if (unsupported) {
+ b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY "
+ "(Analog %u, Type %u, Revision %u)\n",
+ analog_type, phy_type, phy_rev);
+ return -EOPNOTSUPP;
+ }
+ b43legacydbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
+ analog_type, phy_type, phy_rev);
+
+
+ /* Get RADIO versioning */
+ if (dev->dev->bus->chip_id == 0x4317) {
+ if (dev->dev->bus->chip_rev == 0)
+ tmp = 0x3205017F;
+ else if (dev->dev->bus->chip_rev == 1)
+ tmp = 0x4205017F;
+ else
+ tmp = 0x5205017F;
+ } else {
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
+ B43legacy_RADIOCTL_ID);
+ tmp = b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_HIGH);
+ tmp <<= 16;
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
+ B43legacy_RADIOCTL_ID);
+ tmp |= b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
+ }
+ radio_manuf = (tmp & 0x00000FFF);
+ radio_ver = (tmp & 0x0FFFF000) >> 12;
+ radio_rev = (tmp & 0xF0000000) >> 28;
+ switch (phy_type) {
+ case B43legacy_PHYTYPE_B:
+ if ((radio_ver & 0xFFF0) != 0x2050)
+ unsupported = 1;
+ break;
+ case B43legacy_PHYTYPE_G:
+ if (radio_ver != 0x2050)
+ unsupported = 1;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ if (unsupported) {
+ b43legacyerr(dev->wl, "FOUND UNSUPPORTED RADIO "
+ "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
+ radio_manuf, radio_ver, radio_rev);
+ return -EOPNOTSUPP;
+ }
+ b43legacydbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X,"
+ " Revision %u\n", radio_manuf, radio_ver, radio_rev);
+
+
+ phy->radio_manuf = radio_manuf;
+ phy->radio_ver = radio_ver;
+ phy->radio_rev = radio_rev;
+
+ phy->analog = analog_type;
+ phy->type = phy_type;
+ phy->rev = phy_rev;
+
+ return 0;
+}
+
+static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
+ struct b43legacy_phy *phy)
+{
+ struct b43legacy_lopair *lo;
+ int i;
+
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->locked = 0;
+ /* Assume the radio is enabled. If it's not enabled, the state will
+ * immediately get fixed on the first periodic work run. */
+ dev->radio_hw_enable = 1;
+
+ phy->savedpctlreg = 0xFFFF;
+ phy->aci_enable = 0;
+ phy->aci_wlan_automatic = 0;
+ phy->aci_hw_rssi = 0;
+
+ lo = phy->_lo_pairs;
+ if (lo)
+ memset(lo, 0, sizeof(struct b43legacy_lopair) *
+ B43legacy_LO_COUNT);
+ phy->max_lb_gain = 0;
+ phy->trsw_rx_gain = 0;
+
+ /* Set default attenuation values. */
+ phy->bbatt = b43legacy_default_baseband_attenuation(dev);
+ phy->rfatt = b43legacy_default_radio_attenuation(dev);
+ phy->txctl1 = b43legacy_default_txctl1(dev);
+ phy->txpwr_offset = 0;
+
+ /* NRSSI */
+ phy->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+ phy->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+ phy->nrssi_lt[i] = i;
+
+ phy->lofcal = 0xFFFF;
+ phy->initval = 0xFFFF;
+
+ spin_lock_init(&phy->lock);
+ phy->interfmode = B43legacy_INTERFMODE_NONE;
+ phy->channel = 0xFF;
+}
+
+static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
+{
+ /* Flags */
+ dev->reg124_set_0x4 = 0;
+
+ /* Stats */
+ memset(&dev->stats, 0, sizeof(dev->stats));
+
+ setup_struct_phy_for_init(dev, &dev->phy);
+
+ /* IRQ related flags */
+ dev->irq_reason = 0;
+ memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
+ dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE;
+
+ dev->mac_suspended = 1;
+
+ /* Noise calculation context */
+ memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
+}
+
+static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ struct ssb_bus *bus = dev->dev->bus;
+ u32 tmp;
+
+ if (bus->pcicore.dev &&
+ bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
+ bus->pcicore.dev->id.revision <= 5) {
+ /* IMCFGLO timeouts workaround. */
+ tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ tmp |= 0x32;
+ break;
+ case SSB_BUSTYPE_SSB:
+ tmp |= 0x53;
+ break;
+ }
+ ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+ }
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+}
+
+/* Shutdown a wireless core */
+/* Locking: wl->mutex */
+static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ struct b43legacy_phy *phy = &dev->phy;
+
+ B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
+ if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
+ return;
+ b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
+
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel possibly pending workqueues. */
+ cancel_work_sync(&dev->restart_work);
+ mutex_lock(&wl->mutex);
+
+ b43legacy_rng_exit(dev->wl);
+ b43legacy_pio_free(dev);
+ b43legacy_dma_free(dev);
+ b43legacy_chip_exit(dev);
+ b43legacy_radio_turn_off(dev);
+ b43legacy_switch_analog(dev, 0);
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(dev->dev->bus);
+}
+
+static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int i;
+
+ /* Set default attenuation values. */
+ phy->bbatt = b43legacy_default_baseband_attenuation(dev);
+ phy->rfatt = b43legacy_default_radio_attenuation(dev);
+ phy->txctl1 = b43legacy_default_txctl1(dev);
+ phy->txctl2 = 0xFFFF;
+ phy->txpwr_offset = 0;
+
+ /* NRSSI */
+ phy->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+ phy->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+ phy->nrssi_lt[i] = i;
+
+ phy->lofcal = 0xFFFF;
+ phy->initval = 0xFFFF;
+
+ phy->aci_enable = 0;
+ phy->aci_wlan_automatic = 0;
+ phy->aci_hw_rssi = 0;
+
+ phy->antenna_diversity = 0xFFFF;
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->calibrated = 0;
+ phy->locked = 0;
+
+ if (phy->_lo_pairs)
+ memset(phy->_lo_pairs, 0,
+ sizeof(struct b43legacy_lopair) * B43legacy_LO_COUNT);
+ memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+/* Initialize a wireless core */
+static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43legacy_phy *phy = &dev->phy;
+ struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ int err;
+ u32 hf;
+ u32 tmp;
+
+ B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto out;
+ if (!ssb_device_is_enabled(dev->dev)) {
+ tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0;
+ b43legacy_wireless_core_reset(dev, tmp);
+ }
+
+ if ((phy->type == B43legacy_PHYTYPE_B) ||
+ (phy->type == B43legacy_PHYTYPE_G)) {
+ phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair)
+ * B43legacy_LO_COUNT,
+ GFP_KERNEL);
+ if (!phy->_lo_pairs)
+ return -ENOMEM;
+ }
+ setup_struct_wldev_for_init(dev);
+
+ err = b43legacy_phy_init_tssi2dbm_table(dev);
+ if (err)
+ goto err_kfree_lo_control;
+
+ /* Enable IRQ routing to this device. */
+ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+
+ b43legacy_imcfglo_timeouts_workaround(dev);
+ prepare_phy_data_for_init(dev);
+ b43legacy_phy_calibrate(dev);
+ err = b43legacy_chip_init(dev);
+ if (err)
+ goto err_kfree_tssitbl;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_WLCOREREV,
+ dev->dev->id.revision);
+ hf = b43legacy_hf_read(dev);
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ hf |= B43legacy_HF_SYMW;
+ if (phy->rev == 1)
+ hf |= B43legacy_HF_GDCW;
+ if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL)
+ hf |= B43legacy_HF_OFDMPABOOST;
+ } else if (phy->type == B43legacy_PHYTYPE_B) {
+ hf |= B43legacy_HF_SYMW;
+ if (phy->rev >= 2 && phy->radio_ver == 0x2050)
+ hf &= ~B43legacy_HF_GDCW;
+ }
+ b43legacy_hf_write(dev, hf);
+
+ /* Short/Long Retry Limit.
+ * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+ * the chip-internal counter.
+ */
+ tmp = limit_value(modparam_short_retry, 0, 0xF);
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0006, tmp);
+ tmp = limit_value(modparam_long_retry, 0, 0xF);
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0007, tmp);
+
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ 0x0044, 3);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ 0x0046, 2);
+
+ /* Disable sending probe responses from firmware.
+ * Setting the MaxTime to one usec will always trigger
+ * a timeout, so we never send any probe resp.
+ * A timeout of zero is infinite. */
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_PRMAXTIME, 1);
+
+ b43legacy_rate_memory_init(dev);
+
+ /* Minimum Contention Window */
+ if (phy->type == B43legacy_PHYTYPE_B)
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0003, 31);
+ else
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0003, 15);
+ /* Maximum Contention Window */
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0004, 1023);
+
+ do {
+ if (b43legacy_using_pio(dev))
+ err = b43legacy_pio_init(dev);
+ else {
+ err = b43legacy_dma_init(dev);
+ if (!err)
+ b43legacy_qos_init(dev);
+ }
+ } while (err == -EAGAIN);
+ if (err)
+ goto err_chip_exit;
+
+ b43legacy_write16(dev, 0x0612, 0x0050);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
+
+ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+ memset(wl->bssid, 0, ETH_ALEN);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43legacy_upload_card_macaddress(dev);
+ b43legacy_security_init(dev);
+ b43legacy_rng_init(wl);
+
+ b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
+
+out:
+ return err;
+
+err_chip_exit:
+ b43legacy_chip_exit(dev);
+err_kfree_tssitbl:
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+err_kfree_lo_control:
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ ssb_bus_may_powerdown(bus);
+ B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
+ return err;
+}
+
+static int b43legacy_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+
+ /* TODO: allow WDS/AP devices to coexist */
+
+ if (conf->type != IEEE80211_IF_TYPE_AP &&
+ conf->type != IEEE80211_IF_TYPE_STA &&
+ conf->type != IEEE80211_IF_TYPE_WDS &&
+ conf->type != IEEE80211_IF_TYPE_IBSS)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&wl->mutex);
+ if (wl->operating)
+ goto out_mutex_unlock;
+
+ b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
+
+ dev = wl->current_dev;
+ wl->operating = 1;
+ wl->if_id = conf->if_id;
+ wl->if_type = conf->type;
+ memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_adjust_opmode(dev);
+ b43legacy_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ err = 0;
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+
+ mutex_lock(&wl->mutex);
+
+ B43legacy_WARN_ON(!wl->operating);
+ B43legacy_WARN_ON(wl->if_id != conf->if_id);
+
+ wl->operating = 0;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_adjust_opmode(dev);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43legacy_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ mutex_unlock(&wl->mutex);
+}
+
+static int b43legacy_start(struct ieee80211_hw *hw)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ int did_init = 0;
+ int err;
+
+ mutex_lock(&wl->mutex);
+
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(dev);
+ if (err)
+ goto out_mutex_unlock;
+ did_init = 1;
+ }
+
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(dev);
+ if (err) {
+ if (did_init)
+ b43legacy_wireless_core_exit(dev);
+ goto out_mutex_unlock;
+ }
+ }
+
+out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+void b43legacy_stop(struct ieee80211_hw *hw)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+
+ mutex_lock(&wl->mutex);
+ if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(dev);
+ b43legacy_wireless_core_exit(dev);
+ mutex_unlock(&wl->mutex);
+}
+
+
+static const struct ieee80211_ops b43legacy_hw_ops = {
+ .tx = b43legacy_tx,
+ .conf_tx = b43legacy_conf_tx,
+ .add_interface = b43legacy_add_interface,
+ .remove_interface = b43legacy_remove_interface,
+ .config = b43legacy_dev_config,
+ .config_interface = b43legacy_config_interface,
+ .set_key = b43legacy_dev_set_key,
+ .configure_filter = b43legacy_configure_filter,
+ .get_stats = b43legacy_get_stats,
+ .get_tx_stats = b43legacy_get_tx_stats,
+ .start = b43legacy_start,
+ .stop = b43legacy_stop,
+};
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use b43legacy_controller_restart()
+ */
+static void b43legacy_chip_reset(struct work_struct *work)
+{
+ struct b43legacy_wldev *dev =
+ container_of(work, struct b43legacy_wldev, restart_work);
+ struct b43legacy_wl *wl = dev->wl;
+ int err = 0;
+ int prev_status;
+
+ mutex_lock(&wl->mutex);
+
+ prev_status = b43legacy_status(dev);
+ /* Bring the device down... */
+ if (prev_status >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(dev);
+ if (prev_status >= B43legacy_STAT_INITIALIZED)
+ b43legacy_wireless_core_exit(dev);
+
+ /* ...and up again. */
+ if (prev_status >= B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(dev);
+ if (err)
+ goto out;
+ }
+ if (prev_status >= B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(dev);
+ if (err) {
+ b43legacy_wireless_core_exit(dev);
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&wl->mutex);
+ if (err)
+ b43legacyerr(wl, "Controller restart FAILED\n");
+ else
+ b43legacyinfo(wl, "Controller restarted\n");
+}
+
+static int b43legacy_setup_modes(struct b43legacy_wldev *dev,
+ int have_bphy,
+ int have_gphy)
+{
+ struct ieee80211_hw *hw = dev->wl->hw;
+ struct ieee80211_hw_mode *mode;
+ struct b43legacy_phy *phy = &dev->phy;
+ int cnt = 0;
+ int err;
+
+ phy->possible_phymodes = 0;
+ for (; 1; cnt++) {
+ if (have_bphy) {
+ B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211B;
+ mode->num_channels = b43legacy_bg_chantable_size;
+ mode->channels = b43legacy_bg_chantable;
+ mode->num_rates = b43legacy_b_ratetable_size;
+ mode->rates = b43legacy_b_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43legacy_PHYMODE_B;
+ have_bphy = 0;
+ continue;
+ }
+ if (have_gphy) {
+ B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211G;
+ mode->num_channels = b43legacy_bg_chantable_size;
+ mode->channels = b43legacy_bg_chantable;
+ mode->num_rates = b43legacy_g_ratetable_size;
+ mode->rates = b43legacy_g_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43legacy_PHYMODE_G;
+ have_gphy = 0;
+ continue;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev)
+{
+ /* We release firmware that late to not be required to re-request
+ * is all the time when we reinit the core. */
+ b43legacy_release_firmware(dev);
+}
+
+static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct pci_dev *pdev = bus->host_pci;
+ int err;
+ int have_bphy = 0;
+ int have_gphy = 0;
+ u32 tmp;
+
+ /* Do NOT do any device initialization here.
+ * Do it in wireless_core_init() instead.
+ * This function is for gathering basic information about the HW, only.
+ * Also some structs may be set up here. But most likely you want to
+ * have that in core_init(), too.
+ */
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err) {
+ b43legacyerr(wl, "Bus powerup failed\n");
+ goto out;
+ }
+ /* Get the PHY type. */
+ if (dev->dev->id.revision >= 5) {
+ u32 tmshigh;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ have_gphy = !!(tmshigh & B43legacy_TMSHIGH_GPHY);
+ if (!have_gphy)
+ have_bphy = 1;
+ } else if (dev->dev->id.revision == 4)
+ have_gphy = 1;
+ else
+ have_bphy = 1;
+
+ /* Initialize LEDs structs. */
+ err = b43legacy_leds_init(dev);
+ if (err)
+ goto err_powerdown;
+
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
+ b43legacy_wireless_core_reset(dev, tmp);
+
+ err = b43legacy_phy_versioning(dev);
+ if (err)
+ goto err_leds_exit;
+ /* Check if this device supports multiband. */
+ if (!pdev ||
+ (pdev->device != 0x4312 &&
+ pdev->device != 0x4319 &&
+ pdev->device != 0x4324)) {
+ /* No multiband support. */
+ have_bphy = 0;
+ have_gphy = 0;
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_B:
+ have_bphy = 1;
+ break;
+ case B43legacy_PHYTYPE_G:
+ have_gphy = 1;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ }
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
+ b43legacy_wireless_core_reset(dev, tmp);
+
+ err = b43legacy_validate_chipaccess(dev);
+ if (err)
+ goto err_leds_exit;
+ err = b43legacy_setup_modes(dev, have_bphy, have_gphy);
+ if (err)
+ goto err_leds_exit;
+
+ /* Now set some default "current_dev" */
+ if (!wl->current_dev)
+ wl->current_dev = dev;
+ INIT_WORK(&dev->restart_work, b43legacy_chip_reset);
+
+ b43legacy_radio_turn_off(dev);
+ b43legacy_switch_analog(dev, 0);
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(bus);
+
+out:
+ return err;
+
+err_leds_exit:
+ b43legacy_leds_exit(dev);
+err_powerdown:
+ ssb_bus_may_powerdown(bus);
+ return err;
+}
+
+static void b43legacy_one_core_detach(struct ssb_device *dev)
+{
+ struct b43legacy_wldev *wldev;
+ struct b43legacy_wl *wl;
+
+ wldev = ssb_get_drvdata(dev);
+ wl = wldev->wl;
+ cancel_work_sync(&wldev->restart_work);
+ b43legacy_debugfs_remove_device(wldev);
+ b43legacy_wireless_core_detach(wldev);
+ list_del(&wldev->list);
+ wl->nr_devs--;
+ ssb_set_drvdata(dev, NULL);
+ kfree(wldev);
+}
+
+static int b43legacy_one_core_attach(struct ssb_device *dev,
+ struct b43legacy_wl *wl)
+{
+ struct b43legacy_wldev *wldev;
+ struct pci_dev *pdev;
+ int err = -ENOMEM;
+
+ if (!list_empty(&wl->devlist)) {
+ /* We are not the first core on this chip. */
+ pdev = dev->bus->host_pci;
+ /* Only special chips support more than one wireless
+ * core, although some of the other chips have more than
+ * one wireless core as well. Check for this and
+ * bail out early.
+ */
+ if (!pdev ||
+ ((pdev->device != 0x4321) &&
+ (pdev->device != 0x4313) &&
+ (pdev->device != 0x431A))) {
+ b43legacydbg(wl, "Ignoring unconnected 802.11 core\n");
+ return -ENODEV;
+ }
+ }
+
+ wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
+ if (!wldev)
+ goto out;
+
+ wldev->dev = dev;
+ wldev->wl = wl;
+ b43legacy_set_status(wldev, B43legacy_STAT_UNINIT);
+ wldev->bad_frames_preempt = modparam_bad_frames_preempt;
+ tasklet_init(&wldev->isr_tasklet,
+ (void (*)(unsigned long))b43legacy_interrupt_tasklet,
+ (unsigned long)wldev);
+ if (modparam_pio)
+ wldev->__using_pio = 1;
+ INIT_LIST_HEAD(&wldev->list);
+
+ err = b43legacy_wireless_core_attach(wldev);
+ if (err)
+ goto err_kfree_wldev;
+
+ list_add(&wldev->list, &wl->devlist);
+ wl->nr_devs++;
+ ssb_set_drvdata(dev, wldev);
+ b43legacy_debugfs_add_device(wldev);
+out:
+ return err;
+
+err_kfree_wldev:
+ kfree(wldev);
+ return err;
+}
+
+static void b43legacy_sprom_fixup(struct ssb_bus *bus)
+{
+ /* boardflags workarounds */
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+ bus->boardinfo.type == 0x4E &&
+ bus->boardinfo.rev > 0x40)
+ bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL;
+
+ /* Convert Antennagain values to Q5.2 */
+ if (bus->sprom.r1.antenna_gain_bg == 0xFF)
+ bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */
+ bus->sprom.r1.antenna_gain_bg <<= 2;
+}
+
+static void b43legacy_wireless_exit(struct ssb_device *dev,
+ struct b43legacy_wl *wl)
+{
+ struct ieee80211_hw *hw = wl->hw;
+
+ ssb_set_devtypedata(dev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+static int b43legacy_wireless_init(struct ssb_device *dev)
+{
+ struct ssb_sprom *sprom = &dev->bus->sprom;
+ struct ieee80211_hw *hw;
+ struct b43legacy_wl *wl;
+ int err = -ENOMEM;
+
+ b43legacy_sprom_fixup(dev->bus);
+
+ hw = ieee80211_alloc_hw(sizeof(*wl), &b43legacy_hw_ops);
+ if (!hw) {
+ b43legacyerr(NULL, "Could not allocate ieee80211 device\n");
+ goto out;
+ }
+
+ /* fill hw info */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_RX_INCLUDES_FCS;
+ hw->max_signal = 100;
+ hw->max_rssi = -110;
+ hw->max_noise = -110;
+ hw->queues = 1; /* FIXME: hardware has more queues */
+ SET_IEEE80211_DEV(hw, dev->dev);
+ if (is_valid_ether_addr(sprom->r1.et1mac))
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+ else
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+
+ /* Get and initialize struct b43legacy_wl */
+ wl = hw_to_b43legacy_wl(hw);
+ memset(wl, 0, sizeof(*wl));
+ wl->hw = hw;
+ spin_lock_init(&wl->irq_lock);
+ spin_lock_init(&wl->leds_lock);
+ mutex_init(&wl->mutex);
+ INIT_LIST_HEAD(&wl->devlist);
+
+ ssb_set_devtypedata(dev, wl);
+ b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+ err = 0;
+out:
+ return err;
+}
+
+static int b43legacy_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ struct b43legacy_wl *wl;
+ int err;
+ int first = 0;
+
+ wl = ssb_get_devtypedata(dev);
+ if (!wl) {
+ /* Probing the first core - setup common struct b43legacy_wl */
+ first = 1;
+ err = b43legacy_wireless_init(dev);
+ if (err)
+ goto out;
+ wl = ssb_get_devtypedata(dev);
+ B43legacy_WARN_ON(!wl);
+ }
+ err = b43legacy_one_core_attach(dev, wl);
+ if (err)
+ goto err_wireless_exit;
+
+ if (first) {
+ err = ieee80211_register_hw(wl->hw);
+ if (err)
+ goto err_one_core_detach;
+ }
+
+out:
+ return err;
+
+err_one_core_detach:
+ b43legacy_one_core_detach(dev);
+err_wireless_exit:
+ if (first)
+ b43legacy_wireless_exit(dev, wl);
+ return err;
+}
+
+static void b43legacy_remove(struct ssb_device *dev)
+{
+ struct b43legacy_wl *wl = ssb_get_devtypedata(dev);
+ struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+
+ B43legacy_WARN_ON(!wl);
+ if (wl->current_dev == wldev)
+ ieee80211_unregister_hw(wl->hw);
+
+ b43legacy_one_core_detach(dev);
+
+ if (list_empty(&wl->devlist))
+ /* Last core on the chip unregistered.
+ * We can destroy common struct b43legacy_wl.
+ */
+ b43legacy_wireless_exit(dev, wl);
+}
+
+/* Perform a hardware reset. This can be called from any context. */
+void b43legacy_controller_restart(struct b43legacy_wldev *dev,
+ const char *reason)
+{
+ /* Must avoid requeueing, if we are in shutdown. */
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
+ return;
+ b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
+ queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int b43legacy_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43legacy_wl *wl = wldev->wl;
+
+ b43legacydbg(wl, "Suspending...\n");
+
+ mutex_lock(&wl->mutex);
+ wldev->suspend_init_status = b43legacy_status(wldev);
+ if (wldev->suspend_init_status >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(wldev);
+ if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED)
+ b43legacy_wireless_core_exit(wldev);
+ mutex_unlock(&wl->mutex);
+
+ b43legacydbg(wl, "Device suspended.\n");
+
+ return 0;
+}
+
+static int b43legacy_resume(struct ssb_device *dev)
+{
+ struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43legacy_wl *wl = wldev->wl;
+ int err = 0;
+
+ b43legacydbg(wl, "Resuming...\n");
+
+ mutex_lock(&wl->mutex);
+ if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(wldev);
+ if (err) {
+ b43legacyerr(wl, "Resume failed at core init\n");
+ goto out;
+ }
+ }
+ if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(wldev);
+ if (err) {
+ b43legacy_wireless_core_exit(wldev);
+ b43legacyerr(wl, "Resume failed at core start\n");
+ goto out;
+ }
+ }
+ mutex_unlock(&wl->mutex);
+
+ b43legacydbg(wl, "Device resumed.\n");
+out:
+ return err;
+}
+
+#else /* CONFIG_PM */
+# define b43legacy_suspend NULL
+# define b43legacy_resume NULL
+#endif /* CONFIG_PM */
+
+static struct ssb_driver b43legacy_ssb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = b43legacy_ssb_tbl,
+ .probe = b43legacy_probe,
+ .remove = b43legacy_remove,
+ .suspend = b43legacy_suspend,
+ .resume = b43legacy_resume,
+};
+
+static int __init b43legacy_init(void)
+{
+ int err;
+
+ b43legacy_debugfs_init();
+
+ err = ssb_driver_register(&b43legacy_ssb_driver);
+ if (err)
+ goto err_dfs_exit;
+
+ return err;
+
+err_dfs_exit:
+ b43legacy_debugfs_exit();
+ return err;
+}
+
+static void __exit b43legacy_exit(void)
+{
+ ssb_driver_unregister(&b43legacy_ssb_driver);
+ b43legacy_debugfs_exit();
+}
+
+module_init(b43legacy_init)
+module_exit(b43legacy_exit)
diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h
new file mode 100644
index 000000000000..68435c50d8e0
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.h
@@ -0,0 +1,127 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_MAIN_H_
+#define B43legacy_MAIN_H_
+
+#include "b43legacy.h"
+
+
+#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__ , (nr_bytes))
+
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline
+u8 b43legacy_freq_to_channel_bg(int freq)
+{
+ u8 channel;
+
+ if (freq == 2484)
+ channel = 14;
+ else
+ channel = (freq - 2407) / 5;
+
+ return channel;
+}
+static inline
+u8 b43legacy_freq_to_channel(struct b43legacy_wldev *dev,
+ int freq)
+{
+ return b43legacy_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline
+int b43legacy_channel_to_freq_bg(u8 channel)
+{
+ int freq;
+
+ if (channel == 14)
+ freq = 2484;
+ else
+ freq = 2407 + (5 * channel);
+
+ return freq;
+}
+
+static inline
+int b43legacy_channel_to_freq(struct b43legacy_wldev *dev,
+ u8 channel)
+{
+ return b43legacy_channel_to_freq_bg(channel);
+}
+
+static inline
+int b43legacy_is_cck_rate(int rate)
+{
+ return (rate == B43legacy_CCK_RATE_1MB ||
+ rate == B43legacy_CCK_RATE_2MB ||
+ rate == B43legacy_CCK_RATE_5MB ||
+ rate == B43legacy_CCK_RATE_11MB);
+}
+
+static inline
+int b43legacy_is_ofdm_rate(int rate)
+{
+ return !b43legacy_is_cck_rate(rate);
+}
+
+void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf);
+void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf);
+
+u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset);
+u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset);
+void b43legacy_shm_write32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset,
+ u32 value);
+void b43legacy_shm_write16(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset,
+ u16 value);
+
+u32 b43legacy_hf_read(struct b43legacy_wldev *dev);
+void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value);
+
+void b43legacy_dummy_transmission(struct b43legacy_wldev *dev);
+
+void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags);
+
+void b43legacy_mac_suspend(struct b43legacy_wldev *dev);
+void b43legacy_mac_enable(struct b43legacy_wldev *dev);
+
+void b43legacy_controller_restart(struct b43legacy_wldev *dev,
+ const char *reason);
+
+#endif /* B43legacy_MAIN_H_ */
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
new file mode 100644
index 000000000000..22a4b3d0186d
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -0,0 +1,2255 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "b43legacy.h"
+#include "phy.h"
+#include "main.h"
+#include "radio.h"
+#include "ilt.h"
+
+
+static const s8 b43legacy_tssi2dbm_b_table[] = {
+ 0x4D, 0x4C, 0x4B, 0x4A,
+ 0x4A, 0x49, 0x48, 0x47,
+ 0x47, 0x46, 0x45, 0x45,
+ 0x44, 0x43, 0x42, 0x42,
+ 0x41, 0x40, 0x3F, 0x3E,
+ 0x3D, 0x3C, 0x3B, 0x3A,
+ 0x39, 0x38, 0x37, 0x36,
+ 0x35, 0x34, 0x32, 0x31,
+ 0x30, 0x2F, 0x2D, 0x2C,
+ 0x2B, 0x29, 0x28, 0x26,
+ 0x25, 0x23, 0x21, 0x1F,
+ 0x1D, 0x1A, 0x17, 0x14,
+ 0x10, 0x0C, 0x06, 0x00,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+};
+
+static const s8 b43legacy_tssi2dbm_g_table[] = {
+ 77, 77, 77, 76,
+ 76, 76, 75, 75,
+ 74, 74, 73, 73,
+ 73, 72, 72, 71,
+ 71, 70, 70, 69,
+ 68, 68, 67, 67,
+ 66, 65, 65, 64,
+ 63, 63, 62, 61,
+ 60, 59, 58, 57,
+ 56, 55, 54, 53,
+ 52, 50, 49, 47,
+ 45, 43, 40, 37,
+ 33, 28, 22, 14,
+ 5, -7, -20, -20,
+ -20, -20, -20, -20,
+ -20, -20, -20, -20,
+};
+
+static void b43legacy_phy_initg(struct b43legacy_wldev *dev);
+
+
+static inline
+void b43legacy_voluntary_preempt(void)
+{
+ B43legacy_BUG_ON(!(!in_atomic() && !in_irq() &&
+ !in_interrupt() && !irqs_disabled()));
+#ifndef CONFIG_PREEMPT
+ cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
+void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ B43legacy_WARN_ON(!irqs_disabled());
+ if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) {
+ phy->locked = 0;
+ return;
+ }
+ if (dev->dev->id.revision < 3) {
+ b43legacy_mac_suspend(dev);
+ spin_lock(&phy->lock);
+ } else {
+ if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43legacy_power_saving_ctl_bits(dev, -1, 1);
+ }
+ phy->locked = 1;
+}
+
+void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ B43legacy_WARN_ON(!irqs_disabled());
+ if (dev->dev->id.revision < 3) {
+ if (phy->locked) {
+ spin_unlock(&phy->lock);
+ b43legacy_mac_enable(dev);
+ }
+ } else {
+ if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+ phy->locked = 0;
+}
+
+u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
+ return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
+}
+
+void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
+}
+
+void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */
+ if (phy->calibrated)
+ return;
+ if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
+ b43legacy_wireless_core_reset(dev, 0);
+ b43legacy_phy_initg(dev);
+ b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
+ }
+ phy->calibrated = 1;
+}
+
+/* intialize B PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 saved_batt = 0;
+ u16 saved_ratt = 0;
+ u16 saved_txctl1 = 0;
+ int must_reset_txpower = 0;
+
+ B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+ phy->type == B43legacy_PHYTYPE_G));
+ if (is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type == 0x0416))
+ return;
+
+ b43legacy_phy_write(dev, 0x0028, 0x8018);
+ b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
+
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (!phy->gmode)
+ return;
+ b43legacy_phy_write(dev, 0x047A, 0xC111);
+ }
+ if (phy->savedpctlreg != 0xFFFF)
+ return;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ if (phy->manual_txpower_control)
+ return;
+#endif
+
+ if (phy->type == B43legacy_PHYTYPE_B &&
+ phy->rev >= 2 &&
+ phy->radio_ver == 0x2050)
+ b43legacy_radio_write16(dev, 0x0076,
+ b43legacy_radio_read16(dev, 0x0076)
+ | 0x0084);
+ else {
+ saved_batt = phy->bbatt;
+ saved_ratt = phy->rfatt;
+ saved_txctl1 = phy->txctl1;
+ if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
+ && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
+ b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
+ else
+ b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
+ must_reset_txpower = 1;
+ }
+ b43legacy_dummy_transmission(dev);
+
+ phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
+
+ if (must_reset_txpower)
+ b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
+ saved_txctl1);
+ else
+ b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
+ 0x0076) & 0xFF7B);
+ b43legacy_radio_clear_tssi(dev);
+}
+
+static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset = 0x0000;
+
+ if (phy->rev == 1)
+ offset = 0x4C00;
+
+ b43legacy_ilt_write(dev, offset, 0x00FE);
+ b43legacy_ilt_write(dev, offset + 1, 0x000D);
+ b43legacy_ilt_write(dev, offset + 2, 0x0013);
+ b43legacy_ilt_write(dev, offset + 3, 0x0019);
+
+ if (phy->rev == 1) {
+ b43legacy_ilt_write(dev, 0x1800, 0x2710);
+ b43legacy_ilt_write(dev, 0x1801, 0x9B83);
+ b43legacy_ilt_write(dev, 0x1802, 0x9B83);
+ b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
+ b43legacy_phy_write(dev, 0x0455, 0x0004);
+ }
+
+ b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
+ & 0x00FF) | 0x5700);
+ b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
+ & 0xFF80) | 0x000F);
+ b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
+ & 0xC07F) | 0x2B80);
+ b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0300);
+
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0008);
+
+ b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
+ & 0xFFF0) | 0x0008);
+ b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
+ & 0xF0FF) | 0x0600);
+ b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0700);
+ b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0100);
+
+ if (phy->rev == 1)
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x0007);
+
+ b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
+ & 0xFF00) | 0x001C);
+ b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
+ & 0xC0FF) | 0x0200);
+ b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
+ & 0xFF00) | 0x001C);
+ b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
+ & 0xFF00) | 0x0020);
+ b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
+ & 0xC0FF) | 0x0200);
+ b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
+ & 0xFF00) | 0x002E);
+ b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
+ & 0x00FF) | 0x1A00);
+ b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
+ & 0xFF00) | 0x0028);
+ b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
+ & 0x00FF) | 0x2C00);
+
+ if (phy->rev == 1) {
+ b43legacy_phy_write(dev, 0x0430, 0x092B);
+ b43legacy_phy_write(dev, 0x041B,
+ (b43legacy_phy_read(dev, 0x041B)
+ & 0xFFE1) | 0x0002);
+ } else {
+ b43legacy_phy_write(dev, 0x041B,
+ b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
+ b43legacy_phy_write(dev, 0x041F, 0x287A);
+ b43legacy_phy_write(dev, 0x0420,
+ (b43legacy_phy_read(dev, 0x0420)
+ & 0xFFF0) | 0x0004);
+ }
+
+ if (phy->rev > 2) {
+ b43legacy_phy_write(dev, 0x0422, 0x287A);
+ b43legacy_phy_write(dev, 0x0420,
+ (b43legacy_phy_read(dev, 0x0420)
+ & 0x0FFF) | 0x3000);
+ }
+
+ b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
+ & 0x8080) | 0x7874);
+ b43legacy_phy_write(dev, 0x048E, 0x1C00);
+
+ if (phy->rev == 1) {
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0600);
+ b43legacy_phy_write(dev, 0x048B, 0x005E);
+ b43legacy_phy_write(dev, 0x048C,
+ (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
+ | 0x001E);
+ b43legacy_phy_write(dev, 0x048D, 0x0002);
+ }
+
+ b43legacy_ilt_write(dev, offset + 0x0800, 0);
+ b43legacy_ilt_write(dev, offset + 0x0801, 7);
+ b43legacy_ilt_write(dev, offset + 0x0802, 16);
+ b43legacy_ilt_write(dev, offset + 0x0803, 28);
+
+ if (phy->rev >= 6) {
+ b43legacy_phy_write(dev, 0x0426,
+ (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
+ b43legacy_phy_write(dev, 0x0426,
+ (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
+ }
+}
+
+static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 i;
+
+ B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
+ if (phy->rev == 1) {
+ b43legacy_phy_write(dev, 0x0406, 0x4F19);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ (b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
+ b43legacy_phy_write(dev, 0x042C, 0x005A);
+ b43legacy_phy_write(dev, 0x0427, 0x001A);
+
+ for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x5800 + i,
+ b43legacy_ilt_finefreqg[i]);
+ for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1800 + i,
+ b43legacy_ilt_noiseg1[i]);
+ for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
+ b43legacy_ilt_write32(dev, 0x2000 + i,
+ b43legacy_ilt_rotor[i]);
+ } else {
+ /* nrssi values are signed 6-bit values. Why 0x7654 here? */
+ b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
+
+ if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x04C0, 0x1861);
+ b43legacy_phy_write(dev, 0x04C1, 0x0271);
+ } else if (phy->rev > 2) {
+ b43legacy_phy_write(dev, 0x04C0, 0x0098);
+ b43legacy_phy_write(dev, 0x04C1, 0x0070);
+ b43legacy_phy_write(dev, 0x04C9, 0x0080);
+ }
+ b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
+ 0x042B) | 0x800);
+
+ for (i = 0; i < 64; i++)
+ b43legacy_ilt_write(dev, 0x4000 + i, i);
+ for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1800 + i,
+ b43legacy_ilt_noiseg2[i]);
+ }
+
+ if (phy->rev <= 2)
+ for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1400 + i,
+ b43legacy_ilt_noisescaleg1[i]);
+ else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
+ for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1400 + i,
+ b43legacy_ilt_noisescaleg3[i]);
+ else
+ for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1400 + i,
+ b43legacy_ilt_noisescaleg2[i]);
+
+ if (phy->rev == 2)
+ for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x5000 + i,
+ b43legacy_ilt_sigmasqr1[i]);
+ else if ((phy->rev > 2) && (phy->rev <= 8))
+ for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x5000 + i,
+ b43legacy_ilt_sigmasqr2[i]);
+
+ if (phy->rev == 1) {
+ for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
+ b43legacy_ilt_write32(dev, 0x2400 + i,
+ b43legacy_ilt_retard[i]);
+ for (i = 4; i < 20; i++)
+ b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
+ b43legacy_phy_agcsetup(dev);
+
+ if (is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type == 0x0416) &&
+ (dev->dev->bus->boardinfo.rev == 0x0017))
+ return;
+
+ b43legacy_ilt_write(dev, 0x5001, 0x0002);
+ b43legacy_ilt_write(dev, 0x5002, 0x0001);
+ } else {
+ for (i = 0; i <= 0x20; i++)
+ b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
+ b43legacy_phy_agcsetup(dev);
+ b43legacy_phy_read(dev, 0x0400); /* dummy read */
+ b43legacy_phy_write(dev, 0x0403, 0x1000);
+ b43legacy_ilt_write(dev, 0x3C02, 0x000F);
+ b43legacy_ilt_write(dev, 0x3C03, 0x0014);
+
+ if (is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type == 0x0416) &&
+ (dev->dev->bus->boardinfo.rev == 0x0017))
+ return;
+
+ b43legacy_ilt_write(dev, 0x0401, 0x0002);
+ b43legacy_ilt_write(dev, 0x0402, 0x0001);
+ }
+}
+
+/* Initialize the APHY portion of a GPHY. */
+static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
+{
+
+ might_sleep();
+
+ b43legacy_phy_setupg(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL)
+ b43legacy_phy_write(dev, 0x046E, 0x03CF);
+}
+
+static void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ int val;
+
+ b43legacy_write16(dev, 0x03EC, 0x3F22);
+ b43legacy_phy_write(dev, 0x0020, 0x301C);
+ b43legacy_phy_write(dev, 0x0026, 0x0000);
+ b43legacy_phy_write(dev, 0x0030, 0x00C6);
+ b43legacy_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43legacy_phy_write(dev, 0x03E4, 0x3000);
+ b43legacy_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43legacy_radio_write16(dev, 0x0075, 0x0080);
+ b43legacy_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+ b43legacy_radio_write16(dev, 0x007A, 0x000F);
+ b43legacy_phy_write(dev, 0x0038, 0x0677);
+ b43legacy_radio_init2050(dev);
+ }
+ b43legacy_phy_write(dev, 0x0014, 0x0080);
+ b43legacy_phy_write(dev, 0x0032, 0x00CA);
+ b43legacy_phy_write(dev, 0x0032, 0x00CC);
+ b43legacy_phy_write(dev, 0x0035, 0x07C2);
+ b43legacy_phy_lo_b_measure(dev);
+ b43legacy_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver != 0x2050)
+ b43legacy_phy_write(dev, 0x0026, 0xCE00);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
+ b43legacy_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver != 0x2050)
+ b43legacy_phy_write(dev, 0x002A, 0x88C2);
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+ b43legacy_phy_init_pctl(dev);
+}
+
+static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ u16 val;
+
+ b43legacy_write16(dev, 0x03EC, 0x3F22);
+ b43legacy_phy_write(dev, 0x0020, 0x301C);
+ b43legacy_phy_write(dev, 0x0026, 0x0000);
+ b43legacy_phy_write(dev, 0x0030, 0x00C6);
+ b43legacy_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43legacy_phy_write(dev, 0x03E4, 0x3000);
+ b43legacy_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43legacy_radio_write16(dev, 0x0075, 0x0080);
+ b43legacy_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+ b43legacy_radio_write16(dev, 0x007A, 0x000F);
+ b43legacy_phy_write(dev, 0x0038, 0x0677);
+ b43legacy_radio_init2050(dev);
+ }
+ b43legacy_phy_write(dev, 0x0014, 0x0080);
+ b43legacy_phy_write(dev, 0x0032, 0x00CA);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x0032, 0x00E0);
+ b43legacy_phy_write(dev, 0x0035, 0x07C2);
+
+ b43legacy_phy_lo_b_measure(dev);
+
+ b43legacy_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x0026, 0xCE00);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
+ b43legacy_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x002A, 0x88C2);
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+ b43legacy_calc_nrssi_slope(dev);
+ b43legacy_calc_nrssi_threshold(dev);
+ }
+ b43legacy_phy_init_pctl(dev);
+}
+
+static void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ u16 value;
+ u8 old_channel;
+
+ if (phy->analog == 1)
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0050);
+ if (!is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type != 0x0416)) {
+ value = 0x2120;
+ for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
+ b43legacy_phy_write(dev, offset, value);
+ value += 0x0202;
+ }
+ }
+ b43legacy_phy_write(dev, 0x0035,
+ (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
+ | 0x0700);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x0038, 0x0667);
+
+ if (phy->gmode) {
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0020);
+ b43legacy_radio_write16(dev, 0x0051,
+ b43legacy_radio_read16(dev, 0x0051)
+ | 0x0004);
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
+
+ b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
+ | 0x0100);
+ b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
+ | 0x2000);
+
+ b43legacy_phy_write(dev, 0x001C, 0x186A);
+
+ b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
+ 0x0013) & 0x00FF) | 0x1900);
+ b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
+ 0x0035) & 0xFFC0) | 0x0064);
+ b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
+ 0x005D) & 0xFF80) | 0x000A);
+ }
+
+ if (dev->bad_frames_preempt)
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD) | (1 << 11));
+
+ if (phy->analog == 1) {
+ b43legacy_phy_write(dev, 0x0026, 0xCE00);
+ b43legacy_phy_write(dev, 0x0021, 0x3763);
+ b43legacy_phy_write(dev, 0x0022, 0x1BC3);
+ b43legacy_phy_write(dev, 0x0023, 0x06F9);
+ b43legacy_phy_write(dev, 0x0024, 0x037E);
+ } else
+ b43legacy_phy_write(dev, 0x0026, 0xCC00);
+ b43legacy_phy_write(dev, 0x0030, 0x00C6);
+ b43legacy_write16(dev, 0x03EC, 0x3F22);
+
+ if (phy->analog == 1)
+ b43legacy_phy_write(dev, 0x0020, 0x3E1C);
+ else
+ b43legacy_phy_write(dev, 0x0020, 0x301C);
+
+ if (phy->analog == 0)
+ b43legacy_write16(dev, 0x03E4, 0x3000);
+
+ old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
+ /* Force to channel 7, even if not supported. */
+ b43legacy_radio_selectchannel(dev, 7, 0);
+
+ if (phy->radio_ver != 0x2050) {
+ b43legacy_radio_write16(dev, 0x0075, 0x0080);
+ b43legacy_radio_write16(dev, 0x0079, 0x0081);
+ }
+
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ }
+
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+
+ b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
+ 0x007A) | 0x0007);
+
+ b43legacy_radio_selectchannel(dev, old_channel, 0);
+
+ b43legacy_phy_write(dev, 0x0014, 0x0080);
+ b43legacy_phy_write(dev, 0x0032, 0x00CA);
+ b43legacy_phy_write(dev, 0x002A, 0x88A3);
+
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+
+ if (phy->radio_ver == 0x2050)
+ b43legacy_radio_write16(dev, 0x005D, 0x000D);
+
+ b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
+ 0xFFC0) | 0x0004);
+}
+
+static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ u16 val;
+ u8 old_channel;
+
+ b43legacy_phy_write(dev, 0x003E, 0x817A);
+ b43legacy_radio_write16(dev, 0x007A,
+ (b43legacy_radio_read16(dev, 0x007A) | 0x0058));
+ if (phy->radio_rev == 4 ||
+ phy->radio_rev == 5) {
+ b43legacy_radio_write16(dev, 0x0051, 0x0037);
+ b43legacy_radio_write16(dev, 0x0052, 0x0070);
+ b43legacy_radio_write16(dev, 0x0053, 0x00B3);
+ b43legacy_radio_write16(dev, 0x0054, 0x009B);
+ b43legacy_radio_write16(dev, 0x005A, 0x0088);
+ b43legacy_radio_write16(dev, 0x005B, 0x0088);
+ b43legacy_radio_write16(dev, 0x005D, 0x0088);
+ b43legacy_radio_write16(dev, 0x005E, 0x0088);
+ b43legacy_radio_write16(dev, 0x007D, 0x0088);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ (b43legacy_shm_read32(dev,
+ B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET)
+ | 0x00000200));
+ }
+ if (phy->radio_rev == 8) {
+ b43legacy_radio_write16(dev, 0x0051, 0x0000);
+ b43legacy_radio_write16(dev, 0x0052, 0x0040);
+ b43legacy_radio_write16(dev, 0x0053, 0x00B7);
+ b43legacy_radio_write16(dev, 0x0054, 0x0098);
+ b43legacy_radio_write16(dev, 0x005A, 0x0088);
+ b43legacy_radio_write16(dev, 0x005B, 0x006B);
+ b43legacy_radio_write16(dev, 0x005C, 0x000F);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) {
+ b43legacy_radio_write16(dev, 0x005D, 0x00FA);
+ b43legacy_radio_write16(dev, 0x005E, 0x00D8);
+ } else {
+ b43legacy_radio_write16(dev, 0x005D, 0x00F5);
+ b43legacy_radio_write16(dev, 0x005E, 0x00B8);
+ }
+ b43legacy_radio_write16(dev, 0x0073, 0x0003);
+ b43legacy_radio_write16(dev, 0x007D, 0x00A8);
+ b43legacy_radio_write16(dev, 0x007C, 0x0001);
+ b43legacy_radio_write16(dev, 0x007E, 0x0008);
+ }
+ val = 0x1E1F;
+ for (offset = 0x0088; offset < 0x0098; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x3E3F;
+ for (offset = 0x0098; offset < 0x00A8; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x2120;
+ for (offset = 0x00A8; offset < 0x00C8; offset++) {
+ b43legacy_phy_write(dev, offset, (val & 0x3F3F));
+ val += 0x0202;
+ }
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A) |
+ 0x0020);
+ b43legacy_radio_write16(dev, 0x0051,
+ b43legacy_radio_read16(dev, 0x0051) |
+ 0x0004);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) | 0x0100);
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B) | 0x2000);
+ b43legacy_phy_write(dev, 0x5B, 0x0000);
+ b43legacy_phy_write(dev, 0x5C, 0x0000);
+ }
+
+ old_channel = phy->channel;
+ if (old_channel >= 8)
+ b43legacy_radio_selectchannel(dev, 1, 0);
+ else
+ b43legacy_radio_selectchannel(dev, 13, 0);
+
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+ udelay(40);
+ if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+ b43legacy_radio_write16(dev, 0x007C,
+ (b43legacy_radio_read16(dev, 0x007C)
+ | 0x0002));
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ }
+ if (phy->radio_rev <= 2) {
+ b43legacy_radio_write16(dev, 0x007C, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ (b43legacy_radio_read16(dev,
+ 0x007A) & 0x00F8) | 0x0007);
+
+ b43legacy_radio_selectchannel(dev, old_channel, 0);
+
+ b43legacy_phy_write(dev, 0x0014, 0x0200);
+ if (phy->radio_rev >= 6)
+ b43legacy_phy_write(dev, 0x002A, 0x88C2);
+ else
+ b43legacy_phy_write(dev, 0x002A, 0x8AC0);
+ b43legacy_phy_write(dev, 0x0038, 0x0668);
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+ if (phy->radio_rev <= 5)
+ b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
+ 0x005D) & 0xFF80) | 0x0003);
+ if (phy->radio_rev <= 2)
+ b43legacy_radio_write16(dev, 0x005D, 0x000D);
+
+ if (phy->analog == 4) {
+ b43legacy_write16(dev, 0x03E4, 0x0009);
+ b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
+ & 0xFFF);
+ } else
+ b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
+ 0x0002) & 0xFFC0) | 0x0004);
+ if (phy->type == B43legacy_PHYTYPE_G)
+ b43legacy_write16(dev, 0x03E6, 0x0);
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ b43legacy_write16(dev, 0x03E6, 0x8140);
+ b43legacy_phy_write(dev, 0x0016, 0x0410);
+ b43legacy_phy_write(dev, 0x0017, 0x0820);
+ b43legacy_phy_write(dev, 0x0062, 0x0007);
+ b43legacy_radio_init2050(dev);
+ b43legacy_phy_lo_g_measure(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_RSSI) {
+ b43legacy_calc_nrssi_slope(dev);
+ b43legacy_calc_nrssi_threshold(dev);
+ }
+ b43legacy_phy_init_pctl(dev);
+ }
+}
+
+static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup_phy[15] = {0};
+ u16 backup_radio[3];
+ u16 backup_bband;
+ u16 i;
+ u16 loop1_cnt;
+ u16 loop1_done;
+ u16 loop1_omitted;
+ u16 loop2_done;
+
+ backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
+ backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
+ backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
+ backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
+ if (phy->rev != 1) {
+ backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
+ backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
+ }
+ backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
+ backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
+ backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
+ backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
+ backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
+ backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
+ backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
+ backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
+ backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
+ b43legacy_phy_read(dev, 0x002D); /* dummy read */
+ backup_bband = phy->bbatt;
+ backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
+ backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
+ backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
+
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
+ b43legacy_phy_write(dev, 0x0001,
+ b43legacy_phy_read(dev, 0x0001) & 0x8000);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0002);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0001);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0001);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0002);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
+ }
+ b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
+ 0x000C);
+ b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
+ 0x000C);
+
+ b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF) | 0x0030);
+ b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF) | 0x0010);
+
+ b43legacy_phy_write(dev, 0x005A, 0x0780);
+ b43legacy_phy_write(dev, 0x0059, 0xC810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->analog == 0)
+ b43legacy_phy_write(dev, 0x0003, 0x0122);
+ else
+ b43legacy_phy_write(dev, 0x000A,
+ b43legacy_phy_read(dev, 0x000A)
+ | 0x2000);
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0004);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
+ }
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003)
+ & 0xFF9F) | 0x0040);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
+ b43legacy_radio_write16(dev, 0x0052, 0x0000);
+ b43legacy_radio_write16(dev, 0x0043,
+ (b43legacy_radio_read16(dev, 0x0043)
+ & 0xFFF0) | 0x0009);
+ loop1_cnt = 9;
+ } else if (phy->radio_rev == 8) {
+ b43legacy_radio_write16(dev, 0x0043, 0x000F);
+ loop1_cnt = 15;
+ } else
+ loop1_cnt = 0;
+
+ b43legacy_phy_set_baseband_attenuation(dev, 11);
+
+ if (phy->rev >= 3)
+ b43legacy_phy_write(dev, 0x080F, 0xC020);
+ else
+ b43legacy_phy_write(dev, 0x080F, 0x8020);
+ b43legacy_phy_write(dev, 0x0810, 0x0000);
+
+ b43legacy_phy_write(dev, 0x002B,
+ (b43legacy_phy_read(dev, 0x002B)
+ & 0xFFC0) | 0x0001);
+ b43legacy_phy_write(dev, 0x002B,
+ (b43legacy_phy_read(dev, 0x002B)
+ & 0xC0FF) | 0x0800);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0100);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) {
+ if (phy->rev >= 7) {
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811)
+ | 0x0800);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812)
+ | 0x8000);
+ }
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x00F7);
+
+ for (i = 0; i < loop1_cnt; i++) {
+ b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xF0FF) | (i << 8));
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xA000);
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xF000);
+ udelay(20);
+ if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
+ break;
+ }
+ loop1_done = i;
+ loop1_omitted = loop1_cnt - loop1_done;
+
+ loop2_done = 0;
+ if (loop1_done >= 8) {
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812)
+ | 0x0030);
+ for (i = loop1_done - 8; i < 16; i++) {
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xF0FF) | (i << 8));
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xA000);
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xF000);
+ udelay(20);
+ if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
+ break;
+ }
+ }
+
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
+ b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
+ }
+ b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
+ b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
+ b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
+ b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
+ b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
+ b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
+ b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
+ b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
+ b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
+
+ b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
+
+ b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
+ b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
+ b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
+
+ b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
+ udelay(10);
+ b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
+ b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
+ b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
+ b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
+
+ phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
+ phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
+}
+
+static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (phy->rev == 1)
+ b43legacy_phy_initb5(dev);
+ else
+ b43legacy_phy_initb6(dev);
+ if (phy->rev >= 2 || phy->gmode)
+ b43legacy_phy_inita(dev);
+
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0814, 0x0000);
+ b43legacy_phy_write(dev, 0x0815, 0x0000);
+ }
+ if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x0811, 0x0000);
+ b43legacy_phy_write(dev, 0x0015, 0x00C0);
+ }
+ if (phy->rev > 5) {
+ b43legacy_phy_write(dev, 0x0811, 0x0400);
+ b43legacy_phy_write(dev, 0x0015, 0x00C0);
+ }
+ if (phy->rev >= 2 || phy->gmode) {
+ tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
+ if (tmp == 3 || tmp == 5) {
+ b43legacy_phy_write(dev, 0x04C2, 0x1816);
+ b43legacy_phy_write(dev, 0x04C3, 0x8006);
+ if (tmp == 5)
+ b43legacy_phy_write(dev, 0x04CC,
+ (b43legacy_phy_read(dev,
+ 0x04CC) & 0x00FF) |
+ 0x1F00);
+ }
+ b43legacy_phy_write(dev, 0x047E, 0x0078);
+ }
+ if (phy->radio_rev == 8) {
+ b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
+ | 0x0080);
+ b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
+ | 0x0004);
+ }
+ if (phy->rev >= 2 && phy->gmode)
+ b43legacy_calc_loopback_gain(dev);
+ if (phy->radio_rev != 8) {
+ if (phy->initval == 0xFFFF)
+ phy->initval = b43legacy_radio_init2050(dev);
+ else
+ b43legacy_radio_write16(dev, 0x0078, phy->initval);
+ }
+ if (phy->txctl2 == 0xFFFF)
+ b43legacy_phy_lo_g_measure(dev);
+ else {
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
+ b43legacy_radio_write16(dev, 0x0052,
+ (phy->txctl1 << 4) |
+ phy->txctl2);
+ else
+ b43legacy_radio_write16(dev, 0x0052,
+ (b43legacy_radio_read16(dev,
+ 0x0052) & 0xFFF0) |
+ phy->txctl1);
+ if (phy->rev >= 6)
+ b43legacy_phy_write(dev, 0x0036,
+ (b43legacy_phy_read(dev, 0x0036)
+ & 0x0FFF) | (phy->txctl2 << 12));
+ if (dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_PACTRL)
+ b43legacy_phy_write(dev, 0x002E, 0x8075);
+ else
+ b43legacy_phy_write(dev, 0x002E, 0x807F);
+ if (phy->rev < 2)
+ b43legacy_phy_write(dev, 0x002F, 0x0101);
+ else
+ b43legacy_phy_write(dev, 0x002F, 0x0202);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ b43legacy_phy_lo_adjust(dev, 0);
+ b43legacy_phy_write(dev, 0x080F, 0x8078);
+ }
+
+ if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) {
+ /* The specs state to update the NRSSI LT with
+ * the value 0x7FFFFFFF here. I think that is some weird
+ * compiler optimization in the original driver.
+ * Essentially, what we do here is resetting all NRSSI LT
+ * entries to -32 (see the limit_value() in nrssi_hw_update())
+ */
+ b43legacy_nrssi_hw_update(dev, 0xFFFF);
+ b43legacy_calc_nrssi_threshold(dev);
+ } else if (phy->gmode || phy->rev >= 2) {
+ if (phy->nrssi[0] == -1000) {
+ B43legacy_WARN_ON(phy->nrssi[1] != -1000);
+ b43legacy_calc_nrssi_slope(dev);
+ } else {
+ B43legacy_WARN_ON(phy->nrssi[1] == -1000);
+ b43legacy_calc_nrssi_threshold(dev);
+ }
+ }
+ if (phy->radio_rev == 8)
+ b43legacy_phy_write(dev, 0x0805, 0x3230);
+ b43legacy_phy_init_pctl(dev);
+ if (dev->dev->bus->chip_id == 0x4306
+ && dev->dev->bus->chip_package == 2) {
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
+ b43legacy_phy_write(dev, 0x04C3,
+ b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
+ }
+}
+
+static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
+{
+ int i;
+ u16 ret = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ for (i = 0; i < 10; i++) {
+ b43legacy_phy_write(dev, 0x0015, 0xAFA0);
+ udelay(1);
+ b43legacy_phy_write(dev, 0x0015, 0xEFA0);
+ udelay(10);
+ b43legacy_phy_write(dev, 0x0015, 0xFFA0);
+ udelay(40);
+ ret += b43legacy_phy_read(dev, 0x002C);
+ }
+ local_irq_restore(flags);
+ b43legacy_voluntary_preempt();
+
+ return ret;
+}
+
+void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 regstack[12] = { 0 };
+ u16 mls;
+ u16 fval;
+ int i;
+ int j;
+
+ regstack[0] = b43legacy_phy_read(dev, 0x0015);
+ regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
+
+ if (phy->radio_ver == 0x2053) {
+ regstack[2] = b43legacy_phy_read(dev, 0x000A);
+ regstack[3] = b43legacy_phy_read(dev, 0x002A);
+ regstack[4] = b43legacy_phy_read(dev, 0x0035);
+ regstack[5] = b43legacy_phy_read(dev, 0x0003);
+ regstack[6] = b43legacy_phy_read(dev, 0x0001);
+ regstack[7] = b43legacy_phy_read(dev, 0x0030);
+
+ regstack[8] = b43legacy_radio_read16(dev, 0x0043);
+ regstack[9] = b43legacy_radio_read16(dev, 0x007A);
+ regstack[10] = b43legacy_read16(dev, 0x03EC);
+ regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
+
+ b43legacy_phy_write(dev, 0x0030, 0x00FF);
+ b43legacy_write16(dev, 0x03EC, 0x3F3F);
+ b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
+ b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
+ }
+ b43legacy_phy_write(dev, 0x0015, 0xB000);
+ b43legacy_phy_write(dev, 0x002B, 0x0004);
+
+ if (phy->radio_ver == 0x2053) {
+ b43legacy_phy_write(dev, 0x002B, 0x0203);
+ b43legacy_phy_write(dev, 0x002A, 0x08A3);
+ }
+
+ phy->minlowsig[0] = 0xFFFF;
+
+ for (i = 0; i < 4; i++) {
+ b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
+ b43legacy_phy_lo_b_r15_loop(dev);
+ }
+ for (i = 0; i < 10; i++) {
+ b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
+ mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[0]) {
+ phy->minlowsig[0] = mls;
+ phy->minlowsigpos[0] = i;
+ }
+ }
+ b43legacy_radio_write16(dev, 0x0052, regstack[1]
+ | phy->minlowsigpos[0]);
+
+ phy->minlowsig[1] = 0xFFFF;
+
+ for (i = -4; i < 5; i += 2) {
+ for (j = -4; j < 5; j += 2) {
+ if (j < 0)
+ fval = (0x0100 * i) + j + 0x0100;
+ else
+ fval = (0x0100 * i) + j;
+ b43legacy_phy_write(dev, 0x002F, fval);
+ mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[1]) {
+ phy->minlowsig[1] = mls;
+ phy->minlowsigpos[1] = fval;
+ }
+ }
+ }
+ phy->minlowsigpos[1] += 0x0101;
+
+ b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
+ if (phy->radio_ver == 0x2053) {
+ b43legacy_phy_write(dev, 0x000A, regstack[2]);
+ b43legacy_phy_write(dev, 0x002A, regstack[3]);
+ b43legacy_phy_write(dev, 0x0035, regstack[4]);
+ b43legacy_phy_write(dev, 0x0003, regstack[5]);
+ b43legacy_phy_write(dev, 0x0001, regstack[6]);
+ b43legacy_phy_write(dev, 0x0030, regstack[7]);
+
+ b43legacy_radio_write16(dev, 0x0043, regstack[8]);
+ b43legacy_radio_write16(dev, 0x007A, regstack[9]);
+
+ b43legacy_radio_write16(dev, 0x0052,
+ (b43legacy_radio_read16(dev, 0x0052)
+ & 0x000F) | regstack[11]);
+
+ b43legacy_write16(dev, 0x03EC, regstack[10]);
+ }
+ b43legacy_phy_write(dev, 0x0015, regstack[0]);
+}
+
+static inline
+u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
+ u16 control)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x15, 0xE300);
+ control <<= 8;
+ b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
+ udelay(5);
+ b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
+ udelay(2);
+ b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
+ udelay(4);
+ b43legacy_phy_write(dev, 0x0015, 0xF300);
+ udelay(8);
+ } else {
+ b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
+ udelay(2);
+ b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
+ udelay(4);
+ b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
+ udelay(8);
+ }
+ ret = b43legacy_phy_read(dev, 0x002D);
+ local_irq_restore(flags);
+ b43legacy_voluntary_preempt();
+
+ return ret;
+}
+
+static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
+ u16 control)
+{
+ int i;
+ u32 ret = 0;
+
+ for (i = 0; i < 8; i++)
+ ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
+
+ return ret;
+}
+
+/* Write the LocalOscillator CONTROL */
+static inline
+void b43legacy_lo_write(struct b43legacy_wldev *dev,
+ struct b43legacy_lopair *pair)
+{
+ u16 value;
+
+ value = (u8)(pair->low);
+ value |= ((u8)(pair->high)) << 8;
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+ /* Sanity check. */
+ if (pair->low < -8 || pair->low > 8 ||
+ pair->high < -8 || pair->high > 8) {
+ struct b43legacy_phy *phy = &dev->phy;
+ b43legacydbg(dev->wl,
+ "WARNING: Writing invalid LOpair "
+ "(low: %d, high: %d, index: %lu)\n",
+ pair->low, pair->high,
+ (unsigned long)(pair - phy->_lo_pairs));
+ dump_stack();
+ }
+#endif
+
+ b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
+ u16 bbatt,
+ u16 rfatt,
+ u16 tx)
+{
+ static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (bbatt > 6)
+ bbatt = 6;
+ B43legacy_WARN_ON(rfatt >= 10);
+
+ if (tx == 3)
+ return b43legacy_get_lopair(phy, rfatt, bbatt);
+ return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ return b43legacy_find_lopair(dev, phy->bbatt,
+ phy->rfatt, phy->txctl1);
+}
+
+/* Adjust B/G LO */
+void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
+{
+ struct b43legacy_lopair *pair;
+
+ if (fixed) {
+ /* Use fixed values. Only for initialization. */
+ pair = b43legacy_find_lopair(dev, 2, 3, 0);
+ } else
+ pair = b43legacy_current_lopair(dev);
+ b43legacy_lo_write(dev, pair);
+}
+
+static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 txctl2 = 0;
+ u16 i;
+ u32 smallest;
+ u32 tmp;
+
+ b43legacy_radio_write16(dev, 0x0052, 0x0000);
+ udelay(10);
+ smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
+ for (i = 0; i < 16; i++) {
+ b43legacy_radio_write16(dev, 0x0052, i);
+ udelay(10);
+ tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
+ if (tmp < smallest) {
+ smallest = tmp;
+ txctl2 = i;
+ }
+ }
+ phy->txctl2 = txctl2;
+}
+
+static
+void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
+ const struct b43legacy_lopair *in_pair,
+ struct b43legacy_lopair *out_pair,
+ u16 r27)
+{
+ static const struct b43legacy_lopair transitions[8] = {
+ { .high = 1, .low = 1, },
+ { .high = 1, .low = 0, },
+ { .high = 1, .low = -1, },
+ { .high = 0, .low = -1, },
+ { .high = -1, .low = -1, },
+ { .high = -1, .low = 0, },
+ { .high = -1, .low = 1, },
+ { .high = 0, .low = 1, },
+ };
+ struct b43legacy_lopair lowest_transition = {
+ .high = in_pair->high,
+ .low = in_pair->low,
+ };
+ struct b43legacy_lopair tmp_pair;
+ struct b43legacy_lopair transition;
+ int i = 12;
+ int state = 0;
+ int found_lower;
+ int j;
+ int begin;
+ int end;
+ u32 lowest_deviation;
+ u32 tmp;
+
+ /* Note that in_pair and out_pair can point to the same pair.
+ * Be careful. */
+
+ b43legacy_lo_write(dev, &lowest_transition);
+ lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
+ do {
+ found_lower = 0;
+ B43legacy_WARN_ON(!(state >= 0 && state <= 8));
+ if (state == 0) {
+ begin = 1;
+ end = 8;
+ } else if (state % 2 == 0) {
+ begin = state - 1;
+ end = state + 1;
+ } else {
+ begin = state - 2;
+ end = state + 2;
+ }
+ if (begin < 1)
+ begin += 8;
+ if (end > 8)
+ end -= 8;
+
+ j = begin;
+ tmp_pair.high = lowest_transition.high;
+ tmp_pair.low = lowest_transition.low;
+ while (1) {
+ B43legacy_WARN_ON(!(j >= 1 && j <= 8));
+ transition.high = tmp_pair.high +
+ transitions[j - 1].high;
+ transition.low = tmp_pair.low + transitions[j - 1].low;
+ if ((abs(transition.low) < 9)
+ && (abs(transition.high) < 9)) {
+ b43legacy_lo_write(dev, &transition);
+ tmp = b43legacy_phy_lo_g_singledeviation(dev,
+ r27);
+ if (tmp < lowest_deviation) {
+ lowest_deviation = tmp;
+ state = j;
+ found_lower = 1;
+
+ lowest_transition.high =
+ transition.high;
+ lowest_transition.low = transition.low;
+ }
+ }
+ if (j == end)
+ break;
+ if (j == 8)
+ j = 1;
+ else
+ j++;
+ }
+ } while (i-- && found_lower);
+
+ out_pair->high = lowest_transition.high;
+ out_pair->low = lowest_transition.low;
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
+ u16 bbatt)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 value;
+
+ if (phy->analog == 0) {
+ value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
+ value |= (bbatt & 0x000F);
+ b43legacy_write16(dev, 0x03E6, value);
+ return;
+ }
+
+ if (phy->analog > 1) {
+ value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
+ value |= (bbatt << 2) & 0x003C;
+ } else {
+ value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
+ value |= (bbatt << 3) & 0x0078;
+ }
+ b43legacy_phy_write(dev, 0x0060, value);
+}
+
+/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
+void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
+{
+ static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
+ const int is_initializing = (b43legacy_status(dev)
+ < B43legacy_STAT_STARTED);
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 h;
+ u16 i;
+ u16 oldi = 0;
+ u16 j;
+ struct b43legacy_lopair control;
+ struct b43legacy_lopair *tmp_control;
+ u16 tmp;
+ u16 regstack[16] = { 0 };
+ u8 oldchannel;
+
+ /* XXX: What are these? */
+ u8 r27 = 0;
+ u16 r31;
+
+ oldchannel = phy->channel;
+ /* Setup */
+ if (phy->gmode) {
+ regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
+ regstack[1] = b43legacy_phy_read(dev, 0x0802);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
+ & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
+ }
+ regstack[3] = b43legacy_read16(dev, 0x03E2);
+ b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
+ regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+ regstack[5] = b43legacy_phy_read(dev, 0x15);
+ regstack[6] = b43legacy_phy_read(dev, 0x2A);
+ regstack[7] = b43legacy_phy_read(dev, 0x35);
+ regstack[8] = b43legacy_phy_read(dev, 0x60);
+ regstack[9] = b43legacy_radio_read16(dev, 0x43);
+ regstack[10] = b43legacy_radio_read16(dev, 0x7A);
+ regstack[11] = b43legacy_radio_read16(dev, 0x52);
+ if (phy->gmode) {
+ regstack[12] = b43legacy_phy_read(dev, 0x0811);
+ regstack[13] = b43legacy_phy_read(dev, 0x0812);
+ regstack[14] = b43legacy_phy_read(dev, 0x0814);
+ regstack[15] = b43legacy_phy_read(dev, 0x0815);
+ }
+ b43legacy_radio_selectchannel(dev, 6, 0);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
+ & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
+ b43legacy_dummy_transmission(dev);
+ }
+ b43legacy_radio_write16(dev, 0x0043, 0x0006);
+
+ b43legacy_phy_set_baseband_attenuation(dev, 2);
+
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
+ b43legacy_phy_write(dev, 0x002E, 0x007F);
+ b43legacy_phy_write(dev, 0x080F, 0x0078);
+ b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
+ b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
+ b43legacy_phy_write(dev, 0x002B, 0x0203);
+ b43legacy_phy_write(dev, 0x002A, 0x08A3);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
+ b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
+ b43legacy_phy_write(dev, 0x0811, 0x01B3);
+ b43legacy_phy_write(dev, 0x0812, 0x00B2);
+ }
+ if (is_initializing)
+ b43legacy_phy_lo_g_measure_txctl2(dev);
+ b43legacy_phy_write(dev, 0x080F, 0x8078);
+
+ /* Measure */
+ control.low = 0;
+ control.high = 0;
+ for (h = 0; h < 10; h++) {
+ /* Loop over each possible RadioAttenuation (0-9) */
+ i = pairorder[h];
+ if (is_initializing) {
+ if (i == 3) {
+ control.low = 0;
+ control.high = 0;
+ } else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
+ ((i % 2 == 0) && (oldi % 2 == 0))) {
+ tmp_control = b43legacy_get_lopair(phy, oldi,
+ 0);
+ memcpy(&control, tmp_control, sizeof(control));
+ } else {
+ tmp_control = b43legacy_get_lopair(phy, 3, 0);
+ memcpy(&control, tmp_control, sizeof(control));
+ }
+ }
+ /* Loop over each possible BasebandAttenuation/2 */
+ for (j = 0; j < 4; j++) {
+ if (is_initializing) {
+ tmp = i * 2 + j;
+ r27 = 0;
+ r31 = 0;
+ if (tmp > 14) {
+ r31 = 1;
+ if (tmp > 17)
+ r27 = 1;
+ if (tmp > 19)
+ r27 = 2;
+ }
+ } else {
+ tmp_control = b43legacy_get_lopair(phy, i,
+ j * 2);
+ if (!tmp_control->used)
+ continue;
+ memcpy(&control, tmp_control, sizeof(control));
+ r27 = 3;
+ r31 = 0;
+ }
+ b43legacy_radio_write16(dev, 0x43, i);
+ b43legacy_radio_write16(dev, 0x52, phy->txctl2);
+ udelay(10);
+ b43legacy_voluntary_preempt();
+
+ b43legacy_phy_set_baseband_attenuation(dev, j * 2);
+
+ tmp = (regstack[10] & 0xFFF0);
+ if (r31)
+ tmp |= 0x0008;
+ b43legacy_radio_write16(dev, 0x007A, tmp);
+
+ tmp_control = b43legacy_get_lopair(phy, i, j * 2);
+ b43legacy_phy_lo_g_state(dev, &control, tmp_control,
+ r27);
+ }
+ oldi = i;
+ }
+ /* Loop over each possible RadioAttenuation (10-13) */
+ for (i = 10; i < 14; i++) {
+ /* Loop over each possible BasebandAttenuation/2 */
+ for (j = 0; j < 4; j++) {
+ if (is_initializing) {
+ tmp_control = b43legacy_get_lopair(phy, i - 9,
+ j * 2);
+ memcpy(&control, tmp_control, sizeof(control));
+ /* FIXME: The next line is wrong, as the
+ * following if statement can never trigger. */
+ tmp = (i - 9) * 2 + j - 5;
+ r27 = 0;
+ r31 = 0;
+ if (tmp > 14) {
+ r31 = 1;
+ if (tmp > 17)
+ r27 = 1;
+ if (tmp > 19)
+ r27 = 2;
+ }
+ } else {
+ tmp_control = b43legacy_get_lopair(phy, i - 9,
+ j * 2);
+ if (!tmp_control->used)
+ continue;
+ memcpy(&control, tmp_control, sizeof(control));
+ r27 = 3;
+ r31 = 0;
+ }
+ b43legacy_radio_write16(dev, 0x43, i - 9);
+ /* FIXME: shouldn't txctl1 be zero in the next line
+ * and 3 in the loop above? */
+ b43legacy_radio_write16(dev, 0x52,
+ phy->txctl2
+ | (3/*txctl1*/ << 4));
+ udelay(10);
+ b43legacy_voluntary_preempt();
+
+ b43legacy_phy_set_baseband_attenuation(dev, j * 2);
+
+ tmp = (regstack[10] & 0xFFF0);
+ if (r31)
+ tmp |= 0x0008;
+ b43legacy_radio_write16(dev, 0x7A, tmp);
+
+ tmp_control = b43legacy_get_lopair(phy, i, j * 2);
+ b43legacy_phy_lo_g_state(dev, &control, tmp_control,
+ r27);
+ }
+ }
+
+ /* Restoration */
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x0015, 0xE300);
+ b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
+ udelay(5);
+ b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
+ udelay(2);
+ b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
+ b43legacy_voluntary_preempt();
+ } else
+ b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
+ b43legacy_phy_lo_adjust(dev, is_initializing);
+ b43legacy_phy_write(dev, 0x002E, 0x807F);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x002F, 0x0202);
+ else
+ b43legacy_phy_write(dev, 0x002F, 0x0101);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
+ b43legacy_phy_write(dev, 0x0015, regstack[5]);
+ b43legacy_phy_write(dev, 0x002A, regstack[6]);
+ b43legacy_phy_write(dev, 0x0035, regstack[7]);
+ b43legacy_phy_write(dev, 0x0060, regstack[8]);
+ b43legacy_radio_write16(dev, 0x0043, regstack[9]);
+ b43legacy_radio_write16(dev, 0x007A, regstack[10]);
+ regstack[11] &= 0x00F0;
+ regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
+ b43legacy_radio_write16(dev, 0x52, regstack[11]);
+ b43legacy_write16(dev, 0x03E2, regstack[3]);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x0811, regstack[12]);
+ b43legacy_phy_write(dev, 0x0812, regstack[13]);
+ b43legacy_phy_write(dev, 0x0814, regstack[14]);
+ b43legacy_phy_write(dev, 0x0815, regstack[15]);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
+ b43legacy_phy_write(dev, 0x0802, regstack[1]);
+ }
+ b43legacy_radio_selectchannel(dev, oldchannel, 1);
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+ {
+ /* Sanity check for all lopairs. */
+ for (i = 0; i < B43legacy_LO_COUNT; i++) {
+ tmp_control = phy->_lo_pairs + i;
+ if (tmp_control->low < -8 || tmp_control->low > 8 ||
+ tmp_control->high < -8 || tmp_control->high > 8)
+ b43legacywarn(dev->wl,
+ "WARNING: Invalid LOpair (low: %d, high:"
+ " %d, index: %d)\n",
+ tmp_control->low, tmp_control->high, i);
+ }
+ }
+#endif /* CONFIG_B43LEGACY_DEBUG */
+}
+
+static
+void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_lopair *pair;
+
+ pair = b43legacy_current_lopair(dev);
+ pair->used = 1;
+}
+
+void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ struct b43legacy_lopair *pair;
+ int i;
+
+ for (i = 0; i < B43legacy_LO_COUNT; i++) {
+ pair = phy->_lo_pairs + i;
+ pair->used = 0;
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s8 dbm = 0;
+ s32 tmp;
+
+ tmp = phy->idle_tssi;
+ tmp += tssi;
+ tmp -= phy->savedpctlreg;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ tmp = limit_value(tmp, 0x00, 0x3F);
+ dbm = phy->tssi2dbm[tmp];
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ return dbm;
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+ u16 txpower;
+ s8 v0;
+ s8 v1;
+ s8 v2;
+ s8 v3;
+ s8 average;
+ int max_pwr;
+ s16 desired_pwr;
+ s16 estimated_pwr;
+ s16 pwr_adjust;
+ s16 radio_att_delta;
+ s16 baseband_att_delta;
+ s16 radio_attenuation;
+ s16 baseband_attenuation;
+ unsigned long phylock_flags;
+
+ if (phy->savedpctlreg == 0xFFFF)
+ return;
+ if ((dev->dev->bus->boardinfo.type == 0x0416) &&
+ is_bcm_board_vendor(dev))
+ return;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ if (phy->manual_txpower_control)
+ return;
+#endif
+
+ B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+ phy->type == B43legacy_PHYTYPE_G));
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
+ v0 = (s8)(tmp & 0x00FF);
+ v1 = (s8)((tmp & 0xFF00) >> 8);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
+ v2 = (s8)(tmp & 0x00FF);
+ v3 = (s8)((tmp & 0xFF00) >> 8);
+ tmp = 0;
+
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x0070);
+ v0 = (s8)(tmp & 0x00FF);
+ v1 = (s8)((tmp & 0xFF00) >> 8);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x0072);
+ v2 = (s8)(tmp & 0x00FF);
+ v3 = (s8)((tmp & 0xFF00) >> 8);
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
+ return;
+ v0 = (v0 + 0x20) & 0x3F;
+ v1 = (v1 + 0x20) & 0x3F;
+ v2 = (v2 + 0x20) & 0x3F;
+ v3 = (v3 + 0x20) & 0x3F;
+ tmp = 1;
+ }
+ b43legacy_radio_clear_tssi(dev);
+
+ average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+ if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
+ & 0x8))
+ average -= 13;
+
+ estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
+
+ max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+
+ if ((dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_PACTRL) &&
+ (phy->type == B43legacy_PHYTYPE_G))
+ max_pwr -= 0x3;
+ if (unlikely(max_pwr <= 0)) {
+ b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
+ "\n");
+ max_pwr = 74; /* fake it */
+ dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+ }
+
+ /* Use regulatory information to get the maximum power.
+ * In the absence of such data from mac80211, we will use 20 dBm, which
+ * is the value for the EU, US, Canada, and most of the world.
+ * The regulatory maximum is reduced by the antenna gain (from sprom)
+ * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
+ * which accounts for the factor of 4 */
+#define REG_MAX_PWR 20
+ max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg
+ - 0x6, max_pwr);
+
+ /* find the desired power in Q5.2 - power_level is in dBm
+ * and limit it - max_pwr is already in Q5.2 */
+ desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr);
+ if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
+ b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
+ " dBm, Desired TX power output: " Q52_FMT
+ " dBm\n", Q52_ARG(estimated_pwr),
+ Q52_ARG(desired_pwr));
+ /* Check if we need to adjust the current power. The factor of 2 is
+ * for damping */
+ pwr_adjust = (desired_pwr - estimated_pwr) / 2;
+ /* RF attenuation delta
+ * The minus sign is because lower attenuation => more power */
+ radio_att_delta = -(pwr_adjust + 7) >> 3;
+ /* Baseband attenuation delta */
+ baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
+ /* Do we need to adjust anything? */
+ if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
+ b43legacy_phy_lo_mark_current_used(dev);
+ return;
+ }
+
+ /* Calculate the new attenuation values. */
+ baseband_attenuation = phy->bbatt;
+ baseband_attenuation += baseband_att_delta;
+ radio_attenuation = phy->rfatt;
+ radio_attenuation += radio_att_delta;
+
+ /* Get baseband and radio attenuation values into permitted ranges.
+ * baseband 0-11, radio 0-9.
+ * Radio attenuation affects power level 4 times as much as baseband.
+ */
+ if (radio_attenuation < 0) {
+ baseband_attenuation -= (4 * -radio_attenuation);
+ radio_attenuation = 0;
+ } else if (radio_attenuation > 9) {
+ baseband_attenuation += (4 * (radio_attenuation - 9));
+ radio_attenuation = 9;
+ } else {
+ while (baseband_attenuation < 0 && radio_attenuation > 0) {
+ baseband_attenuation += 4;
+ radio_attenuation--;
+ }
+ while (baseband_attenuation > 11 && radio_attenuation < 9) {
+ baseband_attenuation -= 4;
+ radio_attenuation++;
+ }
+ }
+ baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+
+ txpower = phy->txctl1;
+ if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+ if (radio_attenuation <= 1) {
+ if (txpower == 0) {
+ txpower = 3;
+ radio_attenuation += 2;
+ baseband_attenuation += 2;
+ } else if (dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_PACTRL) {
+ baseband_attenuation += 4 *
+ (radio_attenuation - 2);
+ radio_attenuation = 2;
+ }
+ } else if (radio_attenuation > 4 && txpower != 0) {
+ txpower = 0;
+ if (baseband_attenuation < 3) {
+ radio_attenuation -= 3;
+ baseband_attenuation += 2;
+ } else {
+ radio_attenuation -= 2;
+ baseband_attenuation -= 2;
+ }
+ }
+ }
+ /* Save the control values */
+ phy->txctl1 = txpower;
+ baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+ radio_attenuation = limit_value(radio_attenuation, 0, 9);
+ phy->rfatt = radio_attenuation;
+ phy->bbatt = baseband_attenuation;
+
+ /* Adjust the hardware */
+ b43legacy_phy_lock(dev, phylock_flags);
+ b43legacy_radio_lock(dev);
+ b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
+ radio_attenuation, txpower);
+ b43legacy_phy_lo_mark_current_used(dev);
+ b43legacy_radio_unlock(dev);
+ b43legacy_phy_unlock(dev, phylock_flags);
+}
+
+static inline
+s32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
+{
+ if (num < 0)
+ return num/den;
+ else
+ return (num+den/2)/den;
+}
+
+static inline
+s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+ s32 m1;
+ s32 m2;
+ s32 f = 256;
+ s32 q;
+ s32 delta;
+ s8 i = 0;
+
+ m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+ m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+ do {
+ if (i > 15)
+ return -EINVAL;
+ q = b43legacy_tssi2dbm_ad(f * 4096 -
+ b43legacy_tssi2dbm_ad(m2 * f, 16) *
+ f, 2048);
+ delta = abs(q - f);
+ f = q;
+ i++;
+ } while (delta >= 2);
+ entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192),
+ -127, 128);
+ return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s16 pab0;
+ s16 pab1;
+ s16 pab2;
+ u8 idx;
+ s8 *dyn_tssi2dbm;
+
+ B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+ phy->type == B43legacy_PHYTYPE_G));
+ pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0);
+ pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1);
+ pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2);
+
+ if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
+ phy->idle_tssi = 0x34;
+ phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
+ return 0;
+ }
+
+ if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+ pab0 != -1 && pab1 != -1 && pab2 != -1) {
+ /* The pabX values are set in SPROM. Use them. */
+ if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 &&
+ (s8)dev->dev->bus->sprom.r1.itssi_bg != -1)
+ phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg);
+ else
+ phy->idle_tssi = 62;
+ dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+ if (dyn_tssi2dbm == NULL) {
+ b43legacyerr(dev->wl, "Could not allocate memory"
+ "for tssi2dbm table\n");
+ return -ENOMEM;
+ }
+ for (idx = 0; idx < 64; idx++)
+ if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
+ pab1, pab2)) {
+ phy->tssi2dbm = NULL;
+ b43legacyerr(dev->wl, "Could not generate "
+ "tssi2dBm table\n");
+ kfree(dyn_tssi2dbm);
+ return -ENODEV;
+ }
+ phy->tssi2dbm = dyn_tssi2dbm;
+ phy->dyn_tssi_tbl = 1;
+ } else {
+ /* pabX values not set in SPROM. */
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ phy->idle_tssi = 0x34;
+ phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
+ break;
+ case B43legacy_PHYTYPE_G:
+ phy->idle_tssi = 0x34;
+ phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int b43legacy_phy_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int err = -ENODEV;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ switch (phy->rev) {
+ case 2:
+ b43legacy_phy_initb2(dev);
+ err = 0;
+ break;
+ case 4:
+ b43legacy_phy_initb4(dev);
+ err = 0;
+ break;
+ case 5:
+ b43legacy_phy_initb5(dev);
+ err = 0;
+ break;
+ case 6:
+ b43legacy_phy_initb6(dev);
+ err = 0;
+ break;
+ }
+ break;
+ case B43legacy_PHYTYPE_G:
+ b43legacy_phy_initg(dev);
+ err = 0;
+ break;
+ }
+ if (err)
+ b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
+
+ return err;
+}
+
+void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 antennadiv;
+ u16 offset;
+ u16 value;
+ u32 ucodeflags;
+
+ antennadiv = phy->antenna_diversity;
+
+ if (antennadiv == 0xFFFF)
+ antennadiv = 3;
+ B43legacy_WARN_ON(antennadiv > 3);
+
+ ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_G:
+ offset = 0x0400;
+
+ if (antennadiv == 2)
+ value = (3/*automatic*/ << 7);
+ else
+ value = (antennadiv << 7);
+ b43legacy_phy_write(dev, offset + 1,
+ (b43legacy_phy_read(dev, offset + 1)
+ & 0x7E7F) | value);
+
+ if (antennadiv >= 2) {
+ if (antennadiv == 2)
+ value = (antennadiv << 7);
+ else
+ value = (0/*force0*/ << 7);
+ b43legacy_phy_write(dev, offset + 0x2B,
+ (b43legacy_phy_read(dev,
+ offset + 0x2B)
+ & 0xFEFF) | value);
+ }
+
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (antennadiv >= 2)
+ b43legacy_phy_write(dev, 0x048C,
+ b43legacy_phy_read(dev,
+ 0x048C) | 0x2000);
+ else
+ b43legacy_phy_write(dev, 0x048C,
+ b43legacy_phy_read(dev,
+ 0x048C) & ~0x2000);
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0461,
+ b43legacy_phy_read(dev,
+ 0x0461) | 0x0010);
+ b43legacy_phy_write(dev, 0x04AD,
+ (b43legacy_phy_read(dev,
+ 0x04AD)
+ & 0x00FF) | 0x0015);
+ if (phy->rev == 2)
+ b43legacy_phy_write(dev, 0x0427,
+ 0x0008);
+ else
+ b43legacy_phy_write(dev, 0x0427,
+ (b43legacy_phy_read(dev, 0x0427)
+ & 0x00FF) | 0x0008);
+ } else if (phy->rev >= 6)
+ b43legacy_phy_write(dev, 0x049B, 0x00DC);
+ } else {
+ if (phy->rev < 3)
+ b43legacy_phy_write(dev, 0x002B,
+ (b43legacy_phy_read(dev,
+ 0x002B) & 0x00FF)
+ | 0x0024);
+ else {
+ b43legacy_phy_write(dev, 0x0061,
+ b43legacy_phy_read(dev,
+ 0x0061) | 0x0010);
+ if (phy->rev == 3) {
+ b43legacy_phy_write(dev, 0x0093,
+ 0x001D);
+ b43legacy_phy_write(dev, 0x0027,
+ 0x0008);
+ } else {
+ b43legacy_phy_write(dev, 0x0093,
+ 0x003A);
+ b43legacy_phy_write(dev, 0x0027,
+ (b43legacy_phy_read(dev, 0x0027)
+ & 0x00FF) | 0x0008);
+ }
+ }
+ }
+ break;
+ case B43legacy_PHYTYPE_B:
+ if (dev->dev->id.revision == 2)
+ value = (3/*automatic*/ << 7);
+ else
+ value = (antennadiv << 7);
+ b43legacy_phy_write(dev, 0x03E2,
+ (b43legacy_phy_read(dev, 0x03E2)
+ & 0xFE7F) | value);
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+
+ if (antennadiv >= 2) {
+ ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
+ }
+
+ phy->antenna_diversity = antennadiv;
+}
+
+/* Set the PowerSavingControlBits.
+ * Bitvalues:
+ * 0 => unset the bit
+ * 1 => set the bit
+ * -1 => calculate the bit
+ */
+void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
+ int bit25, int bit26)
+{
+ int i;
+ u32 status;
+
+/* FIXME: Force 25 to off and 26 to on for now: */
+bit25 = 0;
+bit26 = 1;
+
+ if (bit25 == -1) {
+ /* TODO: If powersave is not off and FIXME is not set and we
+ * are not in adhoc and thus is not an AP and we arei
+ * associated, set bit 25 */
+ }
+ if (bit26 == -1) {
+ /* TODO: If the device is awake or this is an AP, or we are
+ * scanning, or FIXME, or we are associated, or FIXME,
+ * or the latest PS-Poll packet sent was successful,
+ * set bit26 */
+ }
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ if (bit25)
+ status |= B43legacy_SBF_PS1;
+ else
+ status &= ~B43legacy_SBF_PS1;
+ if (bit26)
+ status |= B43legacy_SBF_PS2;
+ else
+ status &= ~B43legacy_SBF_PS2;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ if (bit26 && dev->dev->id.revision >= 5) {
+ for (i = 0; i < 100; i++) {
+ if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ 0x0040) != 4)
+ break;
+ udelay(10);
+ }
+ }
+}
diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
new file mode 100644
index 000000000000..f11b4271714c
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.h
@@ -0,0 +1,219 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_PHY_H_
+#define B43legacy_PHY_H_
+
+#include <linux/types.h>
+
+enum {
+ B43legacy_ANTENNA0, /* Antenna 0 */
+ B43legacy_ANTENNA1, /* Antenna 0 */
+ B43legacy_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
+ B43legacy_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
+
+ B43legacy_ANTENNA_AUTO = B43legacy_ANTENNA_AUTO0,
+ B43legacy_ANTENNA_DEFAULT = B43legacy_ANTENNA_AUTO,
+};
+
+enum {
+ B43legacy_INTERFMODE_NONE,
+ B43legacy_INTERFMODE_NONWLAN,
+ B43legacy_INTERFMODE_MANUALWLAN,
+ B43legacy_INTERFMODE_AUTOWLAN,
+};
+
+/*** PHY Registers ***/
+
+/* Routing */
+#define B43legacy_PHYROUTE_OFDM_GPHY 0x400
+#define B43legacy_PHYROUTE_EXT_GPHY 0x800
+
+/* Base registers. */
+#define B43legacy_PHY_BASE(reg) (reg)
+/* OFDM (A) registers of a G-PHY */
+#define B43legacy_PHY_OFDM(reg) ((reg) | B43legacy_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers */
+#define B43legacy_PHY_EXTG(reg) ((reg) | B43legacy_PHYROUTE_EXT_GPHY)
+
+
+/* Extended G-PHY Registers */
+#define B43legacy_PHY_CLASSCTL B43legacy_PHY_EXTG(0x02) /* Classify control */
+#define B43legacy_PHY_GTABCTL B43legacy_PHY_EXTG(0x03) /* G-PHY table control (see below) */
+#define B43legacy_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
+#define B43legacy_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
+#define B43legacy_PHY_GTABNR_SHIFT 10
+#define B43legacy_PHY_GTABDATA B43legacy_PHY_EXTG(0x04) /* G-PHY table data */
+#define B43legacy_PHY_LO_MASK B43legacy_PHY_EXTG(0x0F) /* Local Oscillator control mask */
+#define B43legacy_PHY_LO_CTL B43legacy_PHY_EXTG(0x10) /* Local Oscillator control */
+#define B43legacy_PHY_RFOVER B43legacy_PHY_EXTG(0x11) /* RF override */
+#define B43legacy_PHY_RFOVERVAL B43legacy_PHY_EXTG(0x12) /* RF override value */
+/*** OFDM table numbers ***/
+#define B43legacy_OFDMTAB(number, offset) \
+ (((number) << B43legacy_PHY_OTABLENR_SHIFT) \
+ | (offset))
+#define B43legacy_OFDMTAB_AGC1 B43legacy_OFDMTAB(0x00, 0)
+#define B43legacy_OFDMTAB_GAIN0 B43legacy_OFDMTAB(0x00, 0)
+#define B43legacy_OFDMTAB_GAINX B43legacy_OFDMTAB(0x01, 0)
+#define B43legacy_OFDMTAB_GAIN1 B43legacy_OFDMTAB(0x01, 4)
+#define B43legacy_OFDMTAB_AGC3 B43legacy_OFDMTAB(0x02, 0)
+#define B43legacy_OFDMTAB_GAIN2 B43legacy_OFDMTAB(0x02, 3)
+#define B43legacy_OFDMTAB_LNAHPFGAIN1 B43legacy_OFDMTAB(0x03, 0)
+#define B43legacy_OFDMTAB_WRSSI B43legacy_OFDMTAB(0x04, 0)
+#define B43legacy_OFDMTAB_LNAHPFGAIN2 B43legacy_OFDMTAB(0x04, 0)
+#define B43legacy_OFDMTAB_NOISESCALE B43legacy_OFDMTAB(0x05, 0)
+#define B43legacy_OFDMTAB_AGC2 B43legacy_OFDMTAB(0x06, 0)
+#define B43legacy_OFDMTAB_ROTOR B43legacy_OFDMTAB(0x08, 0)
+#define B43legacy_OFDMTAB_ADVRETARD B43legacy_OFDMTAB(0x09, 0)
+#define B43legacy_OFDMTAB_DAC B43legacy_OFDMTAB(0x0C, 0)
+#define B43legacy_OFDMTAB_DC B43legacy_OFDMTAB(0x0E, 7)
+#define B43legacy_OFDMTAB_PWRDYN2 B43legacy_OFDMTAB(0x0E, 12)
+#define B43legacy_OFDMTAB_LNAGAIN B43legacy_OFDMTAB(0x0E, 13)
+
+#define B43legacy_OFDMTAB_LPFGAIN B43legacy_OFDMTAB(0x0F, 12)
+#define B43legacy_OFDMTAB_RSSI B43legacy_OFDMTAB(0x10, 0)
+
+#define B43legacy_OFDMTAB_AGC1_R1 B43legacy_OFDMTAB(0x13, 0)
+#define B43legacy_OFDMTAB_GAINX_R1 B43legacy_OFDMTAB(0x14, 0)
+#define B43legacy_OFDMTAB_MINSIGSQ B43legacy_OFDMTAB(0x14, 1)
+#define B43legacy_OFDMTAB_AGC3_R1 B43legacy_OFDMTAB(0x15, 0)
+#define B43legacy_OFDMTAB_WRSSI_R1 B43legacy_OFDMTAB(0x15, 4)
+#define B43legacy_OFDMTAB_TSSI B43legacy_OFDMTAB(0x15, 0)
+#define B43legacy_OFDMTAB_DACRFPABB B43legacy_OFDMTAB(0x16, 0)
+#define B43legacy_OFDMTAB_DACOFF B43legacy_OFDMTAB(0x17, 0)
+#define B43legacy_OFDMTAB_DCBIAS B43legacy_OFDMTAB(0x18, 0)
+
+void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
+
+/* OFDM (A) PHY Registers */
+#define B43legacy_PHY_VERSION_OFDM B43legacy_PHY_OFDM(0x00) /* Versioning register for A-PHY */
+#define B43legacy_PHY_BBANDCFG B43legacy_PHY_OFDM(0x01) /* Baseband config */
+#define B43legacy_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
+#define B43legacy_PHY_BBANDCFG_RXANT_SHIFT 7
+#define B43legacy_PHY_PWRDOWN B43legacy_PHY_OFDM(0x03) /* Powerdown */
+#define B43legacy_PHY_CRSTHRES1 B43legacy_PHY_OFDM(0x06) /* CRS Threshold 1 */
+#define B43legacy_PHY_LNAHPFCTL B43legacy_PHY_OFDM(0x1C) /* LNA/HPF control */
+#define B43legacy_PHY_ADIVRELATED B43legacy_PHY_OFDM(0x27) /* FIXME rename */
+#define B43legacy_PHY_CRS0 B43legacy_PHY_OFDM(0x29)
+#define B43legacy_PHY_ANTDWELL B43legacy_PHY_OFDM(0x2B) /* Antenna dwell */
+#define B43legacy_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
+#define B43legacy_PHY_ENCORE B43legacy_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
+#define B43legacy_PHY_ENCORE_EN 0x0200 /* Encore enable */
+#define B43legacy_PHY_LMS B43legacy_PHY_OFDM(0x55)
+#define B43legacy_PHY_OFDM61 B43legacy_PHY_OFDM(0x61) /* FIXME rename */
+#define B43legacy_PHY_OFDM61_10 0x0010 /* FIXME rename */
+#define B43legacy_PHY_IQBAL B43legacy_PHY_OFDM(0x69) /* I/Q balance */
+#define B43legacy_PHY_OTABLECTL B43legacy_PHY_OFDM(0x72) /* OFDM table control (see below) */
+#define B43legacy_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
+#define B43legacy_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
+#define B43legacy_PHY_OTABLENR_SHIFT 10
+#define B43legacy_PHY_OTABLEI B43legacy_PHY_OFDM(0x73) /* OFDM table data I */
+#define B43legacy_PHY_OTABLEQ B43legacy_PHY_OFDM(0x74) /* OFDM table data Q */
+#define B43legacy_PHY_HPWR_TSSICTL B43legacy_PHY_OFDM(0x78) /* Hardware power TSSI control */
+#define B43legacy_PHY_NRSSITHRES B43legacy_PHY_OFDM(0x8A) /* NRSSI threshold */
+#define B43legacy_PHY_ANTWRSETT B43legacy_PHY_OFDM(0x8C) /* Antenna WR settle */
+#define B43legacy_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
+#define B43legacy_PHY_CLIPPWRDOWNT B43legacy_PHY_OFDM(0x93) /* Clip powerdown threshold */
+#define B43legacy_PHY_OFDM9B B43legacy_PHY_OFDM(0x9B) /* FIXME rename */
+#define B43legacy_PHY_N1P1GAIN B43legacy_PHY_OFDM(0xA0)
+#define B43legacy_PHY_P1P2GAIN B43legacy_PHY_OFDM(0xA1)
+#define B43legacy_PHY_N1N2GAIN B43legacy_PHY_OFDM(0xA2)
+#define B43legacy_PHY_CLIPTHRES B43legacy_PHY_OFDM(0xA3)
+#define B43legacy_PHY_CLIPN1P2THRES B43legacy_PHY_OFDM(0xA4)
+#define B43legacy_PHY_DIVSRCHIDX B43legacy_PHY_OFDM(0xA8) /* Divider search gain/index */
+#define B43legacy_PHY_CLIPP2THRES B43legacy_PHY_OFDM(0xA9)
+#define B43legacy_PHY_CLIPP3THRES B43legacy_PHY_OFDM(0xAA)
+#define B43legacy_PHY_DIVP1P2GAIN B43legacy_PHY_OFDM(0xAB)
+#define B43legacy_PHY_DIVSRCHGAINBACK B43legacy_PHY_OFDM(0xAD) /* Divider search gain back */
+#define B43legacy_PHY_DIVSRCHGAINCHNG B43legacy_PHY_OFDM(0xAE) /* Divider search gain change */
+#define B43legacy_PHY_CRSTHRES1_R1 B43legacy_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
+#define B43legacy_PHY_CRSTHRES2_R1 B43legacy_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
+#define B43legacy_PHY_TSSIP_LTBASE B43legacy_PHY_OFDM(0x380) /* TSSI power lookup table base */
+#define B43legacy_PHY_DC_LTBASE B43legacy_PHY_OFDM(0x3A0) /* DC lookup table base */
+#define B43legacy_PHY_GAIN_LTBASE B43legacy_PHY_OFDM(0x3C0) /* Gain lookup table base */
+
+void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
+
+/* Masks for the different PHY versioning registers. */
+#define B43legacy_PHYVER_ANALOG 0xF000
+#define B43legacy_PHYVER_ANALOG_SHIFT 12
+#define B43legacy_PHYVER_TYPE 0x0F00
+#define B43legacy_PHYVER_TYPE_SHIFT 8
+#define B43legacy_PHYVER_VERSION 0x00FF
+
+struct b43legacy_wldev;
+
+void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev);
+#define b43legacy_phy_lock(bcm, flags) \
+ do { \
+ local_irq_save(flags); \
+ b43legacy_raw_phy_lock(bcm); \
+ } while (0)
+void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev);
+#define b43legacy_phy_unlock(bcm, flags) \
+ do { \
+ b43legacy_raw_phy_unlock(bcm); \
+ local_irq_restore(flags); \
+ } while (0)
+
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+ (((phy)->rev > 1) || ((phy)->gmode))
+
+u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
+
+int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev);
+int b43legacy_phy_init(struct b43legacy_wldev *dev);
+
+void b43legacy_set_rx_antenna(struct b43legacy_wldev *dev, int antenna);
+
+void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev);
+void b43legacy_phy_calibrate(struct b43legacy_wldev *dev);
+int b43legacy_phy_connect(struct b43legacy_wldev *dev, int connect);
+
+void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev);
+void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev);
+void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev);
+
+/* Adjust the LocalOscillator to the saved values.
+ * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
+ */
+void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed);
+void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev);
+
+void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
+ u16 baseband_attenuation);
+
+void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
+ int bit25, int bit26);
+
+#endif /* B43legacy_PHY_H_ */
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
new file mode 100644
index 000000000000..de843ac147ae
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -0,0 +1,668 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ PIO Transmission
+
+ Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "pio.h"
+#include "main.h"
+#include "xmit.h"
+
+#include <linux/delay.h>
+
+
+static void tx_start(struct b43legacy_pioqueue *queue)
+{
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct b43legacy_pioqueue *queue,
+ u8 octet)
+{
+ if (queue->need_workarounds) {
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO);
+ } else {
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
+ }
+}
+
+static u16 tx_get_next_word(const u8 *txhdr,
+ const u8 *packet,
+ size_t txhdr_size,
+ unsigned int *pos)
+{
+ const u8 *source;
+ unsigned int i = *pos;
+ u16 ret;
+
+ if (i < txhdr_size)
+ source = txhdr;
+ else {
+ source = packet;
+ i -= txhdr_size;
+ }
+ ret = le16_to_cpu(*((__le16 *)(source + i)));
+ *pos += 2;
+
+ return ret;
+}
+
+static void tx_data(struct b43legacy_pioqueue *queue,
+ u8 *txhdr,
+ const u8 *packet,
+ unsigned int octets)
+{
+ u16 data;
+ unsigned int i = 0;
+
+ if (queue->need_workarounds) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43legacy_txhdr_fw3), &i);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
+ }
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO |
+ B43legacy_PIO_TXCTL_WRITEHI);
+ while (i < octets - 1) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43legacy_txhdr_fw3), &i);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
+ }
+ if (octets % 2)
+ tx_octet(queue, packet[octets -
+ sizeof(struct b43legacy_txhdr_fw3) - 1]);
+}
+
+static void tx_complete(struct b43legacy_pioqueue *queue,
+ struct sk_buff *skb)
+{
+ if (queue->need_workarounds) {
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
+ skb->data[skb->len - 1]);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO |
+ B43legacy_PIO_TXCTL_COMPLETE);
+ } else
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_COMPLETE);
+}
+
+static u16 generate_cookie(struct b43legacy_pioqueue *queue,
+ struct b43legacy_pio_txpacket *packet)
+{
+ u16 cookie = 0x0000;
+ int packetindex;
+
+ /* We use the upper 4 bits for the PIO
+ * controller ID and the lower 12 bits
+ * for the packet index (in the cache).
+ */
+ switch (queue->mmio_base) {
+ case B43legacy_MMIO_PIO1_BASE:
+ break;
+ case B43legacy_MMIO_PIO2_BASE:
+ cookie = 0x1000;
+ break;
+ case B43legacy_MMIO_PIO3_BASE:
+ cookie = 0x2000;
+ break;
+ case B43legacy_MMIO_PIO4_BASE:
+ cookie = 0x3000;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ packetindex = pio_txpacket_getindex(packet);
+ B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
+ cookie |= (u16)packetindex;
+
+ return cookie;
+}
+
+static
+struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
+ u16 cookie,
+ struct b43legacy_pio_txpacket **packet)
+{
+ struct b43legacy_pio *pio = &dev->pio;
+ struct b43legacy_pioqueue *queue = NULL;
+ int packetindex;
+
+ switch (cookie & 0xF000) {
+ case 0x0000:
+ queue = pio->queue0;
+ break;
+ case 0x1000:
+ queue = pio->queue1;
+ break;
+ case 0x2000:
+ queue = pio->queue2;
+ break;
+ case 0x3000:
+ queue = pio->queue3;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ packetindex = (cookie & 0x0FFF);
+ B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
+ < B43legacy_PIO_MAXTXPACKETS));
+ *packet = &(queue->tx_packets_cache[packetindex]);
+
+ return queue;
+}
+
+union txhdr_union {
+ struct b43legacy_txhdr_fw3 txhdr_fw3;
+};
+
+static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+ struct sk_buff *skb,
+ struct b43legacy_pio_txpacket *packet,
+ size_t txhdr_size)
+{
+ union txhdr_union txhdr_data;
+ u8 *txhdr = NULL;
+ unsigned int octets;
+
+ txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
+
+ B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+ b43legacy_generate_txhdr(queue->dev,
+ txhdr, skb->data, skb->len,
+ &packet->txstat.control,
+ generate_cookie(queue, packet));
+
+ tx_start(queue);
+ octets = skb->len + txhdr_size;
+ if (queue->need_workarounds)
+ octets--;
+ tx_data(queue, txhdr, (u8 *)skb->data, octets);
+ tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct b43legacy_pio_txpacket *packet,
+ int irq_context)
+{
+ struct b43legacy_pioqueue *queue = packet->queue;
+
+ if (packet->skb) {
+ if (irq_context)
+ dev_kfree_skb_irq(packet->skb);
+ else
+ dev_kfree_skb(packet->skb);
+ }
+ list_move(&packet->list, &queue->txfree);
+ queue->nr_txfree++;
+}
+
+static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
+{
+ struct b43legacy_pioqueue *queue = packet->queue;
+ struct sk_buff *skb = packet->skb;
+ u16 octets;
+
+ octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
+ if (queue->tx_devq_size < octets) {
+ b43legacywarn(queue->dev->wl, "PIO queue too small. "
+ "Dropping packet.\n");
+ /* Drop it silently (return success) */
+ free_txpacket(packet, 1);
+ return 0;
+ }
+ B43legacy_WARN_ON(queue->tx_devq_packets >
+ B43legacy_PIO_MAXTXDEVQPACKETS);
+ B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
+ /* Check if there is sufficient free space on the device
+ * TX queue. If not, return and let the TX tasklet
+ * retry later.
+ */
+ if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
+ return -EBUSY;
+ if (queue->tx_devq_used + octets > queue->tx_devq_size)
+ return -EBUSY;
+ /* Now poke the device. */
+ pio_tx_write_fragment(queue, skb, packet,
+ sizeof(struct b43legacy_txhdr_fw3));
+
+ /* Account for the packet size.
+ * (We must not overflow the device TX queue)
+ */
+ queue->tx_devq_packets++;
+ queue->tx_devq_used += octets;
+
+ /* Transmission started, everything ok, move the
+ * packet to the txrunning list.
+ */
+ list_move_tail(&packet->list, &queue->txrunning);
+
+ return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+ struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
+ struct b43legacy_wldev *dev = queue->dev;
+ unsigned long flags;
+ struct b43legacy_pio_txpacket *packet, *tmp_packet;
+ int err;
+ u16 txctl;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ if (queue->tx_frozen)
+ goto out_unlock;
+ txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
+ if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
+ goto out_unlock;
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+ /* Try to transmit the packet. This can fail, if
+ * the device queue is full. In case of failure, the
+ * packet is left in the txqueue.
+ * If transmission succeed, the packet is moved to txrunning.
+ * If it is impossible to transmit the packet, it
+ * is dropped.
+ */
+ err = pio_tx_packet(packet);
+ if (err)
+ break;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void setup_txqueues(struct b43legacy_pioqueue *queue)
+{
+ struct b43legacy_pio_txpacket *packet;
+ int i;
+
+ queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
+ for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
+ packet = &(queue->tx_packets_cache[i]);
+
+ packet->queue = queue;
+ INIT_LIST_HEAD(&packet->list);
+
+ list_add(&packet->list, &queue->txfree);
+ }
+}
+
+static
+struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
+ u16 pio_mmio_base)
+{
+ struct b43legacy_pioqueue *queue;
+ u32 value;
+ u16 qsize;
+
+ queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue)
+ goto out;
+
+ queue->dev = dev;
+ queue->mmio_base = pio_mmio_base;
+ queue->need_workarounds = (dev->dev->id.revision < 3);
+
+ INIT_LIST_HEAD(&queue->txfree);
+ INIT_LIST_HEAD(&queue->txqueue);
+ INIT_LIST_HEAD(&queue->txrunning);
+ tasklet_init(&queue->txtask, tx_tasklet,
+ (unsigned long)queue);
+
+ value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
+
+ qsize = b43legacy_read16(dev, queue->mmio_base
+ + B43legacy_PIO_TXQBUFSIZE);
+ if (qsize == 0) {
+ b43legacyerr(dev->wl, "This card does not support PIO "
+ "operation mode. Please use DMA mode "
+ "(module parameter pio=0).\n");
+ goto err_freequeue;
+ }
+ if (qsize <= B43legacy_PIO_TXQADJUST) {
+ b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
+ qsize);
+ goto err_freequeue;
+ }
+ qsize -= B43legacy_PIO_TXQADJUST;
+ queue->tx_devq_size = qsize;
+
+ setup_txqueues(queue);
+
+out:
+ return queue;
+
+err_freequeue:
+ kfree(queue);
+ queue = NULL;
+ goto out;
+}
+
+static void cancel_transfers(struct b43legacy_pioqueue *queue)
+{
+ struct b43legacy_pio_txpacket *packet, *tmp_packet;
+
+ tasklet_disable(&queue->txtask);
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+ free_txpacket(packet, 0);
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+ free_txpacket(packet, 0);
+}
+
+static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
+{
+ if (!queue)
+ return;
+
+ cancel_transfers(queue);
+ kfree(queue);
+}
+
+void b43legacy_pio_free(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio;
+
+ if (!b43legacy_using_pio(dev))
+ return;
+ pio = &dev->pio;
+
+ b43legacy_destroy_pioqueue(pio->queue3);
+ pio->queue3 = NULL;
+ b43legacy_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+ b43legacy_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+ b43legacy_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+}
+
+int b43legacy_pio_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio = &dev->pio;
+ struct b43legacy_pioqueue *queue;
+ int err = -ENOMEM;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
+ if (!queue)
+ goto out;
+ pio->queue0 = queue;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
+ if (!queue)
+ goto err_destroy0;
+ pio->queue1 = queue;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
+ if (!queue)
+ goto err_destroy1;
+ pio->queue2 = queue;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
+ if (!queue)
+ goto err_destroy2;
+ pio->queue3 = queue;
+
+ if (dev->dev->id.revision < 3)
+ dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
+
+ b43legacydbg(dev->wl, "PIO initialized\n");
+ err = 0;
+out:
+ return err;
+
+err_destroy2:
+ b43legacy_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+err_destroy1:
+ b43legacy_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+err_destroy0:
+ b43legacy_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+ goto out;
+}
+
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_pioqueue *queue = dev->pio.queue1;
+ struct b43legacy_pio_txpacket *packet;
+
+ B43legacy_WARN_ON(queue->tx_suspended);
+ B43legacy_WARN_ON(list_empty(&queue->txfree));
+
+ packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
+ list);
+ packet->skb = skb;
+
+ memset(&packet->txstat, 0, sizeof(packet->txstat));
+ memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
+
+ list_move_tail(&packet->list, &queue->txqueue);
+ queue->nr_txfree--;
+ queue->nr_tx_packets++;
+ B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
+
+ tasklet_schedule(&queue->txtask);
+
+ return 0;
+}
+
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ struct b43legacy_pioqueue *queue;
+ struct b43legacy_pio_txpacket *packet;
+
+ queue = parse_cookie(dev, status->cookie, &packet);
+ B43legacy_WARN_ON(!queue);
+
+ queue->tx_devq_packets--;
+ queue->tx_devq_used -= (packet->skb->len +
+ sizeof(struct b43legacy_txhdr_fw3));
+
+ if (status->acked)
+ packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ packet->txstat.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
+ &(packet->txstat));
+ packet->skb = NULL;
+
+ free_txpacket(packet, 1);
+ /* If there are packets on the txqueue, poke the tasklet
+ * to transmit them.
+ */
+ if (!list_empty(&queue->txqueue))
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43legacy_pio *pio = &dev->pio;
+ struct b43legacy_pioqueue *queue;
+ struct ieee80211_tx_queue_stats_data *data;
+
+ queue = pio->queue1;
+ data = &(stats->data[0]);
+ data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
+ data->limit = B43legacy_PIO_MAXTXPACKETS;
+ data->count = queue->nr_tx_packets;
+}
+
+static void pio_rx_error(struct b43legacy_pioqueue *queue,
+ int clear_buffers,
+ const char *error)
+{
+ int i;
+
+ b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
+ b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
+ B43legacy_PIO_RXCTL_READY);
+ if (clear_buffers) {
+ B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
+ for (i = 0; i < 15; i++) {
+ /* Dummy read. */
+ b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ }
+ }
+}
+
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
+{
+ __le16 preamble[21] = { 0 };
+ struct b43legacy_rxhdr_fw3 *rxhdr;
+ u16 tmp;
+ u16 len;
+ u16 macstat;
+ int i;
+ int preamble_readwords;
+ struct sk_buff *skb;
+
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
+ if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
+ return;
+ b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
+ B43legacy_PIO_RXCTL_DATAAVAILABLE);
+
+ for (i = 0; i < 10; i++) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
+ if (tmp & B43legacy_PIO_RXCTL_READY)
+ goto data_ready;
+ udelay(10);
+ }
+ b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
+ return;
+data_ready:
+
+ len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ if (unlikely(len > 0x700)) {
+ pio_rx_error(queue, 0, "len > 0x700");
+ return;
+ }
+ if (unlikely(len == 0 && queue->mmio_base !=
+ B43legacy_MMIO_PIO4_BASE)) {
+ pio_rx_error(queue, 0, "len == 0");
+ return;
+ }
+ preamble[0] = cpu_to_le16(len);
+ if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
+ preamble_readwords = 14 / sizeof(u16);
+ else
+ preamble_readwords = 18 / sizeof(u16);
+ for (i = 0; i < preamble_readwords; i++) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ preamble[i + 1] = cpu_to_le16(tmp);
+ }
+ rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
+ macstat = le16_to_cpu(rxhdr->mac_status);
+ if (macstat & B43legacy_RX_MAC_FCSERR) {
+ pio_rx_error(queue,
+ (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
+ "Frame FCS error");
+ return;
+ }
+ if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
+ /* We received an xmit status. */
+ struct b43legacy_hwtxstatus *hw;
+
+ hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
+ b43legacy_handle_hwtxstatus(queue->dev, hw);
+
+ return;
+ }
+
+ skb = dev_alloc_skb(len);
+ if (unlikely(!skb)) {
+ pio_rx_error(queue, 1, "OOM");
+ return;
+ }
+ skb_put(skb, len);
+ for (i = 0; i < len - 1; i += 2) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
+ }
+ if (len % 2) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ skb->data[len - 1] = (tmp & 0x00FF);
+ }
+ b43legacy_rx(queue->dev, skb, rxhdr);
+}
+
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
+{
+ b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
+ | B43legacy_PIO_TXCTL_SUSPEND);
+}
+
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
+{
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
+ & ~B43legacy_PIO_TXCTL_SUSPEND);
+ b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio;
+
+ B43legacy_WARN_ON(!b43legacy_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 1;
+ pio->queue1->tx_frozen = 1;
+ pio->queue2->tx_frozen = 1;
+ pio->queue3->tx_frozen = 1;
+}
+
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio;
+
+ B43legacy_WARN_ON(!b43legacy_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 0;
+ pio->queue1->tx_frozen = 0;
+ pio->queue2->tx_frozen = 0;
+ pio->queue3->tx_frozen = 0;
+ if (!list_empty(&pio->queue0->txqueue))
+ tasklet_schedule(&pio->queue0->txtask);
+ if (!list_empty(&pio->queue1->txqueue))
+ tasklet_schedule(&pio->queue1->txtask);
+ if (!list_empty(&pio->queue2->txqueue))
+ tasklet_schedule(&pio->queue2->txtask);
+ if (!list_empty(&pio->queue3->txqueue))
+ tasklet_schedule(&pio->queue3->txtask);
+}
diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h
new file mode 100644
index 000000000000..5bfed0c40030
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.h
@@ -0,0 +1,172 @@
+#ifndef B43legacy_PIO_H_
+#define B43legacy_PIO_H_
+
+#include "b43legacy.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+
+#define B43legacy_PIO_TXCTL 0x00
+#define B43legacy_PIO_TXDATA 0x02
+#define B43legacy_PIO_TXQBUFSIZE 0x04
+#define B43legacy_PIO_RXCTL 0x08
+#define B43legacy_PIO_RXDATA 0x0A
+
+#define B43legacy_PIO_TXCTL_WRITELO (1 << 0)
+#define B43legacy_PIO_TXCTL_WRITEHI (1 << 1)
+#define B43legacy_PIO_TXCTL_COMPLETE (1 << 2)
+#define B43legacy_PIO_TXCTL_INIT (1 << 3)
+#define B43legacy_PIO_TXCTL_SUSPEND (1 << 7)
+
+#define B43legacy_PIO_RXCTL_DATAAVAILABLE (1 << 0)
+#define B43legacy_PIO_RXCTL_READY (1 << 1)
+
+/* PIO constants */
+#define B43legacy_PIO_MAXTXDEVQPACKETS 31
+#define B43legacy_PIO_TXQADJUST 80
+
+/* PIO tuning knobs */
+#define B43legacy_PIO_MAXTXPACKETS 256
+
+
+
+#ifdef CONFIG_B43LEGACY_PIO
+
+
+struct b43legacy_pioqueue;
+struct b43legacy_xmitstatus;
+
+struct b43legacy_pio_txpacket {
+ struct b43legacy_pioqueue *queue;
+ struct sk_buff *skb;
+ struct ieee80211_tx_status txstat;
+ struct list_head list;
+};
+
+#define pio_txpacket_getindex(packet) ((int)((packet) - \
+ (packet)->queue->tx_packets_cache))
+
+struct b43legacy_pioqueue {
+ struct b43legacy_wldev *dev;
+ u16 mmio_base;
+
+ bool tx_suspended;
+ bool tx_frozen;
+ bool need_workarounds; /* Workarounds needed for core.rev < 3 */
+
+ /* Adjusted size of the device internal TX buffer. */
+ u16 tx_devq_size;
+ /* Used octets of the device internal TX buffer. */
+ u16 tx_devq_used;
+ /* Used packet slots in the device internal TX buffer. */
+ u8 tx_devq_packets;
+ /* Packets from the txfree list can
+ * be taken on incoming TX requests.
+ */
+ struct list_head txfree;
+ unsigned int nr_txfree;
+ /* Packets on the txqueue are queued,
+ * but not completely written to the chip, yet.
+ */
+ struct list_head txqueue;
+ /* Packets on the txrunning queue are completely
+ * posted to the device. We are waiting for the txstatus.
+ */
+ struct list_head txrunning;
+ /* Total number or packets sent.
+ * (This counter can obviously wrap).
+ */
+ unsigned int nr_tx_packets;
+ struct tasklet_struct txtask;
+ struct b43legacy_pio_txpacket
+ tx_packets_cache[B43legacy_PIO_MAXTXPACKETS];
+};
+
+static inline
+u16 b43legacy_pio_read(struct b43legacy_pioqueue *queue,
+ u16 offset)
+{
+ return b43legacy_read16(queue->dev, queue->mmio_base + offset);
+}
+
+static inline
+void b43legacy_pio_write(struct b43legacy_pioqueue *queue,
+ u16 offset, u16 value)
+{
+ b43legacy_write16(queue->dev, queue->mmio_base + offset, value);
+ mmiowb();
+}
+
+
+int b43legacy_pio_init(struct b43legacy_wldev *dev);
+void b43legacy_pio_free(struct b43legacy_wldev *dev);
+
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl);
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue);
+
+/* Suspend TX queue in hardware. */
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue);
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev);
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev);
+
+#else /* CONFIG_B43LEGACY_PIO */
+
+static inline
+int b43legacy_pio_init(struct b43legacy_wldev *dev)
+{
+ return 0;
+}
+static inline
+void b43legacy_pio_free(struct b43legacy_wldev *dev)
+{
+}
+static inline
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+}
+static inline
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
+{
+}
+static inline
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43LEGACY_PIO */
+#endif /* B43legacy_PIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
new file mode 100644
index 000000000000..a361dee664af
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -0,0 +1,2158 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "phy.h"
+#include "radio.h"
+#include "ilt.h"
+
+
+/* Table for b43legacy_radio_calibrationvalue() */
+static const u16 rcc_table[16] = {
+ 0x0002, 0x0003, 0x0001, 0x000F,
+ 0x0006, 0x0007, 0x0005, 0x000F,
+ 0x000A, 0x000B, 0x0009, 0x000F,
+ 0x000E, 0x000F, 0x000D, 0x000F,
+};
+
+/* Reverse the bits of a 4bit value.
+ * Example: 1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+ u16 flipped = 0x0000;
+
+ B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
+
+ flipped |= (value & 0x0001) << 3;
+ flipped |= (value & 0x0002) << 1;
+ flipped |= (value & 0x0004) >> 1;
+ flipped |= (value & 0x0008) >> 3;
+
+ return flipped;
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_bg(u8 channel)
+{
+ /* Frequencies are given as frequencies_bg[index] + 2.4GHz
+ * Starting with channel 1
+ */
+ static const u16 frequencies_bg[14] = {
+ 12, 17, 22, 27,
+ 32, 37, 42, 47,
+ 52, 57, 62, 67,
+ 72, 84,
+ };
+
+ if (unlikely(channel < 1 || channel > 14)) {
+ printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
+ channel);
+ dump_stack();
+ return 2412;
+ }
+
+ return frequencies_bg[channel - 1];
+}
+
+void b43legacy_radio_lock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status |= B43legacy_SBF_RADIOREG_LOCK;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ mmiowb();
+ udelay(10);
+}
+
+void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status &= ~B43legacy_SBF_RADIOREG_LOCK;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ mmiowb();
+}
+
+u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ if (phy->radio_ver == 0x2053) {
+ if (offset < 0x70)
+ offset += 0x80;
+ else if (offset < 0x80)
+ offset += 0x70;
+ } else if (phy->radio_ver == 0x2050)
+ offset |= 0x80;
+ else
+ B43legacy_WARN_ON(1);
+ break;
+ case B43legacy_PHYTYPE_G:
+ offset |= 0x80;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
+ return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
+}
+
+void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
+ s16 first, s16 second, s16 third)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 i;
+ u16 start = 0x08;
+ u16 end = 0x18;
+ u16 offset = 0x0400;
+ u16 tmp;
+
+ if (phy->rev <= 1) {
+ offset = 0x5000;
+ start = 0x10;
+ end = 0x20;
+ }
+
+ for (i = 0; i < 4; i++)
+ b43legacy_ilt_write(dev, offset + i, first);
+
+ for (i = start; i < end; i++)
+ b43legacy_ilt_write(dev, offset + i, second);
+
+ if (third != -1) {
+ tmp = ((u16)third << 14) | ((u16)third << 6);
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
+ | tmp);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
+ | tmp);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
+ | tmp);
+ }
+ b43legacy_dummy_transmission(dev);
+}
+
+static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 i;
+ u16 tmp;
+ u16 offset = 0x0400;
+ u16 start = 0x0008;
+ u16 end = 0x0018;
+
+ if (phy->rev <= 1) {
+ offset = 0x5000;
+ start = 0x0010;
+ end = 0x0020;
+ }
+
+ for (i = 0; i < 4; i++) {
+ tmp = (i & 0xFFFC);
+ tmp |= (i & 0x0001) << 1;
+ tmp |= (i & 0x0002) >> 1;
+
+ b43legacy_ilt_write(dev, offset + i, tmp);
+ }
+
+ for (i = start; i < end; i++)
+ b43legacy_ilt_write(dev, offset + i, i - start);
+
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
+ | 0x4040);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
+ | 0x4040);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
+ | 0x4000);
+ b43legacy_dummy_transmission(dev);
+}
+
+/* Synthetic PU workaround */
+static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
+ u8 channel)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ might_sleep();
+
+ if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
+ /* We do not need the workaround. */
+ return;
+
+ if (channel <= 10)
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel + 4));
+ else
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel));
+ msleep(1);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel));
+}
+
+u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u8 ret = 0;
+ u16 saved;
+ u16 rssi;
+ u16 temp;
+ int i;
+ int j = 0;
+
+ saved = b43legacy_phy_read(dev, 0x0403);
+ b43legacy_radio_selectchannel(dev, channel, 0);
+ b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+ if (phy->aci_hw_rssi)
+ rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
+ else
+ rssi = saved & 0x3F;
+ /* clamp temp to signed 5bit */
+ if (rssi > 32)
+ rssi -= 64;
+ for (i = 0; i < 100; i++) {
+ temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
+ if (temp > 32)
+ temp -= 64;
+ if (temp < rssi)
+ j++;
+ if (j >= 20)
+ ret = 1;
+ }
+ b43legacy_phy_write(dev, 0x0403, saved);
+
+ return ret;
+}
+
+u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u8 ret[13];
+ unsigned int channel = phy->channel;
+ unsigned int i;
+ unsigned int j;
+ unsigned int start;
+ unsigned int end;
+ unsigned long phylock_flags;
+
+ if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
+ return 0;
+
+ b43legacy_phy_lock(dev, phylock_flags);
+ b43legacy_radio_lock(dev);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ & 0x7FFF);
+ b43legacy_set_all_gains(dev, 3, 8, 1);
+
+ start = (channel - 5 > 0) ? channel - 5 : 1;
+ end = (channel + 5 < 14) ? channel + 5 : 13;
+
+ for (i = start; i <= end; i++) {
+ if (abs(channel - i) > 2)
+ ret[i-1] = b43legacy_radio_aci_detect(dev, i);
+ }
+ b43legacy_radio_selectchannel(dev, channel, 0);
+ b43legacy_phy_write(dev, 0x0802,
+ (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
+ | 0x0003);
+ b43legacy_phy_write(dev, 0x0403,
+ b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ | 0x8000);
+ b43legacy_set_original_gains(dev);
+ for (i = 0; i < 13; i++) {
+ if (!ret[i])
+ continue;
+ end = (i + 5 < 13) ? i + 5 : 13;
+ for (j = i; j < end; j++)
+ ret[j] = 1;
+ }
+ b43legacy_radio_unlock(dev);
+ b43legacy_phy_unlock(dev, phylock_flags);
+
+ return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
+ mmiowb();
+ b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
+{
+ u16 val;
+
+ b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
+ val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
+
+ return (s16)val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
+{
+ u16 i;
+ s16 tmp;
+
+ for (i = 0; i < 64; i++) {
+ tmp = b43legacy_nrssi_hw_read(dev, i);
+ tmp -= val;
+ tmp = limit_value(tmp, -32, 31);
+ b43legacy_nrssi_hw_write(dev, i, tmp);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s16 i;
+ s16 delta;
+ s32 tmp;
+
+ delta = 0x1F - phy->nrssi[0];
+ for (i = 0; i < 64; i++) {
+ tmp = (i - delta) * phy->nrssislope;
+ tmp /= 0x10000;
+ tmp += 0x3A;
+ tmp = limit_value(tmp, 0, 0x3F);
+ phy->nrssi_lt[i] = tmp;
+ }
+}
+
+static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup[20] = { 0 };
+ s16 v47F;
+ u16 i;
+ u16 saved = 0xFFFF;
+
+ backup[0] = b43legacy_phy_read(dev, 0x0001);
+ backup[1] = b43legacy_phy_read(dev, 0x0811);
+ backup[2] = b43legacy_phy_read(dev, 0x0812);
+ backup[3] = b43legacy_phy_read(dev, 0x0814);
+ backup[4] = b43legacy_phy_read(dev, 0x0815);
+ backup[5] = b43legacy_phy_read(dev, 0x005A);
+ backup[6] = b43legacy_phy_read(dev, 0x0059);
+ backup[7] = b43legacy_phy_read(dev, 0x0058);
+ backup[8] = b43legacy_phy_read(dev, 0x000A);
+ backup[9] = b43legacy_phy_read(dev, 0x0003);
+ backup[10] = b43legacy_radio_read16(dev, 0x007A);
+ backup[11] = b43legacy_radio_read16(dev, 0x0043);
+
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0001,
+ (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
+ | 0x4000);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x000C);
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
+ | 0x0004);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+ if (phy->rev >= 6) {
+ backup[12] = b43legacy_phy_read(dev, 0x002E);
+ backup[13] = b43legacy_phy_read(dev, 0x002F);
+ backup[14] = b43legacy_phy_read(dev, 0x080F);
+ backup[15] = b43legacy_phy_read(dev, 0x0810);
+ backup[16] = b43legacy_phy_read(dev, 0x0801);
+ backup[17] = b43legacy_phy_read(dev, 0x0060);
+ backup[18] = b43legacy_phy_read(dev, 0x0014);
+ backup[19] = b43legacy_phy_read(dev, 0x0478);
+
+ b43legacy_phy_write(dev, 0x002E, 0);
+ b43legacy_phy_write(dev, 0x002F, 0);
+ b43legacy_phy_write(dev, 0x080F, 0);
+ b43legacy_phy_write(dev, 0x0810, 0);
+ b43legacy_phy_write(dev, 0x0478,
+ b43legacy_phy_read(dev, 0x0478) | 0x0100);
+ b43legacy_phy_write(dev, 0x0801,
+ b43legacy_phy_read(dev, 0x0801) | 0x0040);
+ b43legacy_phy_write(dev, 0x0060,
+ b43legacy_phy_read(dev, 0x0060) | 0x0040);
+ b43legacy_phy_write(dev, 0x0014,
+ b43legacy_phy_read(dev, 0x0014) | 0x0200);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A) | 0x0070);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A) | 0x0080);
+ udelay(30);
+
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == 31) {
+ for (i = 7; i >= 4; i--) {
+ b43legacy_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
+ & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F < 31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 4;
+ } else {
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x007F);
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0001);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x000C);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) | 0x000C);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0030);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) | 0x0030);
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0x0810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->analog == 0)
+ b43legacy_phy_write(dev, 0x0003, 0x0122);
+ else
+ b43legacy_phy_write(dev, 0x000A,
+ b43legacy_phy_read(dev, 0x000A)
+ | 0x2000);
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0004);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
+ | 0x0040);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x000F);
+ b43legacy_set_all_gains(dev, 3, 0, 1);
+ b43legacy_radio_write16(dev, 0x0043,
+ (b43legacy_radio_read16(dev, 0x0043)
+ & 0x00F0) | 0x000F);
+ udelay(30);
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == -32) {
+ for (i = 0; i < 4; i++) {
+ b43legacy_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
+ 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F > -31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 3;
+ } else
+ saved = 0;
+ }
+ b43legacy_radio_write16(dev, 0x007B, saved);
+
+ if (phy->rev >= 6) {
+ b43legacy_phy_write(dev, 0x002E, backup[12]);
+ b43legacy_phy_write(dev, 0x002F, backup[13]);
+ b43legacy_phy_write(dev, 0x080F, backup[14]);
+ b43legacy_phy_write(dev, 0x0810, backup[15]);
+ }
+ b43legacy_phy_write(dev, 0x0814, backup[3]);
+ b43legacy_phy_write(dev, 0x0815, backup[4]);
+ b43legacy_phy_write(dev, 0x005A, backup[5]);
+ b43legacy_phy_write(dev, 0x0059, backup[6]);
+ b43legacy_phy_write(dev, 0x0058, backup[7]);
+ b43legacy_phy_write(dev, 0x000A, backup[8]);
+ b43legacy_phy_write(dev, 0x0003, backup[9]);
+ b43legacy_radio_write16(dev, 0x0043, backup[11]);
+ b43legacy_radio_write16(dev, 0x007A, backup[10]);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) | 0x8000);
+ b43legacy_set_original_gains(dev);
+ if (phy->rev >= 6) {
+ b43legacy_phy_write(dev, 0x0801, backup[16]);
+ b43legacy_phy_write(dev, 0x0060, backup[17]);
+ b43legacy_phy_write(dev, 0x0014, backup[18]);
+ b43legacy_phy_write(dev, 0x0478, backup[19]);
+ }
+ b43legacy_phy_write(dev, 0x0001, backup[0]);
+ b43legacy_phy_write(dev, 0x0812, backup[2]);
+ b43legacy_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup[18] = { 0 };
+ u16 tmp;
+ s16 nrssi0;
+ s16 nrssi1;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ backup[0] = b43legacy_radio_read16(dev, 0x007A);
+ backup[1] = b43legacy_radio_read16(dev, 0x0052);
+ backup[2] = b43legacy_radio_read16(dev, 0x0043);
+ backup[3] = b43legacy_phy_read(dev, 0x0030);
+ backup[4] = b43legacy_phy_read(dev, 0x0026);
+ backup[5] = b43legacy_phy_read(dev, 0x0015);
+ backup[6] = b43legacy_phy_read(dev, 0x002A);
+ backup[7] = b43legacy_phy_read(dev, 0x0020);
+ backup[8] = b43legacy_phy_read(dev, 0x005A);
+ backup[9] = b43legacy_phy_read(dev, 0x0059);
+ backup[10] = b43legacy_phy_read(dev, 0x0058);
+ backup[11] = b43legacy_read16(dev, 0x03E2);
+ backup[12] = b43legacy_read16(dev, 0x03E6);
+ backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+
+ tmp = b43legacy_radio_read16(dev, 0x007A);
+ tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+ b43legacy_radio_write16(dev, 0x007A, tmp);
+ b43legacy_phy_write(dev, 0x0030, 0x00FF);
+ b43legacy_write16(dev, 0x03EC, 0x7F7F);
+ b43legacy_phy_write(dev, 0x0026, 0x0000);
+ b43legacy_phy_write(dev, 0x0015,
+ b43legacy_phy_read(dev, 0x0015) | 0x0020);
+ b43legacy_phy_write(dev, 0x002A, 0x08A3);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0080);
+
+ nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x007F);
+ if (phy->analog >= 2)
+ b43legacy_write16(dev, 0x03E6, 0x0040);
+ else if (phy->analog == 0)
+ b43legacy_write16(dev, 0x03E6, 0x0122);
+ else
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
+ b43legacy_phy_write(dev, 0x0020, 0x3F3F);
+ b43legacy_phy_write(dev, 0x0015, 0xF330);
+ b43legacy_radio_write16(dev, 0x005A, 0x0060);
+ b43legacy_radio_write16(dev, 0x0043,
+ b43legacy_radio_read16(dev, 0x0043)
+ & 0x00F0);
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0x0810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+
+ nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
+ b43legacy_phy_write(dev, 0x0030, backup[3]);
+ b43legacy_radio_write16(dev, 0x007A, backup[0]);
+ b43legacy_write16(dev, 0x03E2, backup[11]);
+ b43legacy_phy_write(dev, 0x0026, backup[4]);
+ b43legacy_phy_write(dev, 0x0015, backup[5]);
+ b43legacy_phy_write(dev, 0x002A, backup[6]);
+ b43legacy_synth_pu_workaround(dev, phy->channel);
+ if (phy->analog != 0)
+ b43legacy_write16(dev, 0x03F4, backup[13]);
+
+ b43legacy_phy_write(dev, 0x0020, backup[7]);
+ b43legacy_phy_write(dev, 0x005A, backup[8]);
+ b43legacy_phy_write(dev, 0x0059, backup[9]);
+ b43legacy_phy_write(dev, 0x0058, backup[10]);
+ b43legacy_radio_write16(dev, 0x0052, backup[1]);
+ b43legacy_radio_write16(dev, 0x0043, backup[2]);
+
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+ if (nrssi0 <= -4) {
+ phy->nrssi[0] = nrssi0;
+ phy->nrssi[1] = nrssi1;
+ }
+ break;
+ case B43legacy_PHYTYPE_G:
+ if (phy->radio_rev >= 9)
+ return;
+ if (phy->radio_rev == 8)
+ b43legacy_calc_nrssi_offset(dev);
+
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
+ backup[7] = b43legacy_read16(dev, 0x03E2);
+ b43legacy_write16(dev, 0x03E2,
+ b43legacy_read16(dev, 0x03E2) | 0x8000);
+ backup[0] = b43legacy_radio_read16(dev, 0x007A);
+ backup[1] = b43legacy_radio_read16(dev, 0x0052);
+ backup[2] = b43legacy_radio_read16(dev, 0x0043);
+ backup[3] = b43legacy_phy_read(dev, 0x0015);
+ backup[4] = b43legacy_phy_read(dev, 0x005A);
+ backup[5] = b43legacy_phy_read(dev, 0x0059);
+ backup[6] = b43legacy_phy_read(dev, 0x0058);
+ backup[8] = b43legacy_read16(dev, 0x03E6);
+ backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+ if (phy->rev >= 3) {
+ backup[10] = b43legacy_phy_read(dev, 0x002E);
+ backup[11] = b43legacy_phy_read(dev, 0x002F);
+ backup[12] = b43legacy_phy_read(dev, 0x080F);
+ backup[13] = b43legacy_phy_read(dev,
+ B43legacy_PHY_G_LO_CONTROL);
+ backup[14] = b43legacy_phy_read(dev, 0x0801);
+ backup[15] = b43legacy_phy_read(dev, 0x0060);
+ backup[16] = b43legacy_phy_read(dev, 0x0014);
+ backup[17] = b43legacy_phy_read(dev, 0x0478);
+ b43legacy_phy_write(dev, 0x002E, 0);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
+ switch (phy->rev) {
+ case 4: case 6: case 7:
+ b43legacy_phy_write(dev, 0x0478,
+ b43legacy_phy_read(dev,
+ 0x0478) | 0x0100);
+ b43legacy_phy_write(dev, 0x0801,
+ b43legacy_phy_read(dev,
+ 0x0801) | 0x0040);
+ break;
+ case 3: case 5:
+ b43legacy_phy_write(dev, 0x0801,
+ b43legacy_phy_read(dev,
+ 0x0801) & 0xFFBF);
+ break;
+ }
+ b43legacy_phy_write(dev, 0x0060,
+ b43legacy_phy_read(dev, 0x0060)
+ | 0x0040);
+ b43legacy_phy_write(dev, 0x0014,
+ b43legacy_phy_read(dev, 0x0014)
+ | 0x0200);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0070);
+ b43legacy_set_all_gains(dev, 0, 8, 0);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x00F7);
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0811,
+ (b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF) | 0x0030);
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF) | 0x0010);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0080);
+ udelay(20);
+
+ nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi0 >= 0x0020)
+ nrssi0 -= 0x0040;
+
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x007F);
+ if (phy->analog >= 2)
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003)
+ & 0xFF9F) | 0x0040);
+
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x000F);
+ b43legacy_phy_write(dev, 0x0015, 0xF330);
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF) | 0x0020);
+ b43legacy_phy_write(dev, 0x0811,
+ (b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF) | 0x0020);
+ }
+
+ b43legacy_set_all_gains(dev, 3, 0, 1);
+ if (phy->radio_rev == 8)
+ b43legacy_radio_write16(dev, 0x0043, 0x001F);
+ else {
+ tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
+ b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
+ tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
+ b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
+ }
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0x0810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+ nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi1 >= 0x0020)
+ nrssi1 -= 0x0040;
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+ if (nrssi0 >= -4) {
+ phy->nrssi[0] = nrssi1;
+ phy->nrssi[1] = nrssi0;
+ }
+ if (phy->rev >= 3) {
+ b43legacy_phy_write(dev, 0x002E, backup[10]);
+ b43legacy_phy_write(dev, 0x002F, backup[11]);
+ b43legacy_phy_write(dev, 0x080F, backup[12]);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
+ backup[13]);
+ }
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF);
+ }
+
+ b43legacy_radio_write16(dev, 0x007A, backup[0]);
+ b43legacy_radio_write16(dev, 0x0052, backup[1]);
+ b43legacy_radio_write16(dev, 0x0043, backup[2]);
+ b43legacy_write16(dev, 0x03E2, backup[7]);
+ b43legacy_write16(dev, 0x03E6, backup[8]);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
+ b43legacy_phy_write(dev, 0x0015, backup[3]);
+ b43legacy_phy_write(dev, 0x005A, backup[4]);
+ b43legacy_phy_write(dev, 0x0059, backup[5]);
+ b43legacy_phy_write(dev, 0x0058, backup[6]);
+ b43legacy_synth_pu_workaround(dev, phy->channel);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) | 0x0003);
+ b43legacy_set_original_gains(dev);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ | 0x8000);
+ if (phy->rev >= 3) {
+ b43legacy_phy_write(dev, 0x0801, backup[14]);
+ b43legacy_phy_write(dev, 0x0060, backup[15]);
+ b43legacy_phy_write(dev, 0x0014, backup[16]);
+ b43legacy_phy_write(dev, 0x0478, backup[17]);
+ }
+ b43legacy_nrssi_mem_update(dev);
+ b43legacy_calc_nrssi_threshold(dev);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s32 threshold;
+ s32 a;
+ s32 b;
+ s16 tmp16;
+ u16 tmp_u16;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B: {
+ if (phy->radio_ver != 0x2050)
+ return;
+ if (!(dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_RSSI))
+ return;
+
+ if (phy->radio_rev >= 6) {
+ threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
+ threshold += 20 * (phy->nrssi[0] + 1);
+ threshold /= 40;
+ } else
+ threshold = phy->nrssi[1] - 5;
+
+ threshold = limit_value(threshold, 0, 0x3E);
+ b43legacy_phy_read(dev, 0x0020); /* dummy read */
+ b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
+ | 0x001C);
+
+ if (phy->radio_rev >= 6) {
+ b43legacy_phy_write(dev, 0x0087, 0x0E0D);
+ b43legacy_phy_write(dev, 0x0086, 0x0C0B);
+ b43legacy_phy_write(dev, 0x0085, 0x0A09);
+ b43legacy_phy_write(dev, 0x0084, 0x0808);
+ b43legacy_phy_write(dev, 0x0083, 0x0808);
+ b43legacy_phy_write(dev, 0x0082, 0x0604);
+ b43legacy_phy_write(dev, 0x0081, 0x0302);
+ b43legacy_phy_write(dev, 0x0080, 0x0100);
+ }
+ break;
+ }
+ case B43legacy_PHYTYPE_G:
+ if (!phy->gmode ||
+ !(dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_RSSI)) {
+ tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
+ if (tmp16 >= 0x20)
+ tmp16 -= 0x40;
+ if (tmp16 < 3)
+ b43legacy_phy_write(dev, 0x048A,
+ (b43legacy_phy_read(dev,
+ 0x048A) & 0xF000) | 0x09EB);
+ else
+ b43legacy_phy_write(dev, 0x048A,
+ (b43legacy_phy_read(dev,
+ 0x048A) & 0xF000) | 0x0AED);
+ } else {
+ if (phy->interfmode ==
+ B43legacy_RADIO_INTERFMODE_NONWLAN) {
+ a = 0xE;
+ b = 0xA;
+ } else if (!phy->aci_wlan_automatic &&
+ phy->aci_enable) {
+ a = 0x13;
+ b = 0x12;
+ } else {
+ a = 0xE;
+ b = 0x11;
+ }
+
+ a = a * (phy->nrssi[1] - phy->nrssi[0]);
+ a += (phy->nrssi[0] << 6);
+ if (a < 32)
+ a += 31;
+ else
+ a += 32;
+ a = a >> 6;
+ a = limit_value(a, -31, 31);
+
+ b = b * (phy->nrssi[1] - phy->nrssi[0]);
+ b += (phy->nrssi[0] << 6);
+ if (b < 32)
+ b += 31;
+ else
+ b += 32;
+ b = b >> 6;
+ b = limit_value(b, -31, 31);
+
+ tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
+ tmp_u16 |= ((u32)b & 0x0000003F);
+ tmp_u16 |= (((u32)a & 0x0000003F) << 6);
+ b43legacy_phy_write(dev, 0x048A, tmp_u16);
+ }
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 *_stackptr, size_t *stackidx,
+ u8 id, u16 offset, u16 value)
+{
+ u32 *stackptr = &(_stackptr[*stackidx]);
+
+ B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
+ B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
+ *stackptr = offset;
+ *stackptr |= ((u32)id) << 13;
+ *stackptr |= ((u32)value) << 16;
+ (*stackidx)++;
+ B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
+}
+
+static u16 _stack_restore(u32 *stackptr,
+ u8 id, u16 offset)
+{
+ size_t i;
+
+ B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
+ B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
+ for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
+ if ((*stackptr & 0x00001FFF) != offset)
+ continue;
+ if (((*stackptr & 0x00007000) >> 13) != id)
+ continue;
+ return ((*stackptr & 0xFFFF0000) >> 16);
+ }
+ B43legacy_BUG_ON(1);
+
+ return 0;
+}
+
+#define phy_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x1, (offset), \
+ b43legacy_phy_read(dev, (offset))); \
+ } while (0)
+#define phy_stackrestore(offset) \
+ do { \
+ b43legacy_phy_write(dev, (offset), \
+ _stack_restore(stack, 0x1, \
+ (offset))); \
+ } while (0)
+#define radio_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x2, (offset), \
+ b43legacy_radio_read16(dev, (offset))); \
+ } while (0)
+#define radio_stackrestore(offset) \
+ do { \
+ b43legacy_radio_write16(dev, (offset), \
+ _stack_restore(stack, 0x2, \
+ (offset))); \
+ } while (0)
+#define ilt_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x3, (offset), \
+ b43legacy_ilt_read(dev, (offset))); \
+ } while (0)
+#define ilt_stackrestore(offset) \
+ do { \
+ b43legacy_ilt_write(dev, (offset), \
+ _stack_restore(stack, 0x3, \
+ (offset))); \
+ } while (0)
+
+static void
+b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
+ int mode)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+ u16 flipped;
+ u32 tmp32;
+ size_t stackidx = 0;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43legacy_RADIO_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B)
+ | 0x0800);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) & ~0x4000);
+ break;
+ }
+ radio_stacksave(0x0078);
+ tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
+ flipped = flip_4bit(tmp);
+ if (flipped < 10 && flipped >= 8)
+ flipped = 7;
+ else if (flipped >= 10)
+ flipped -= 3;
+ flipped = flip_4bit(flipped);
+ flipped = (flipped << 1) | 0x0020;
+ b43legacy_radio_write16(dev, 0x0078, flipped);
+
+ b43legacy_calc_nrssi_threshold(dev);
+
+ phy_stacksave(0x0406);
+ b43legacy_phy_write(dev, 0x0406, 0x7E28);
+
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B) | 0x0800);
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
+
+ phy_stacksave(0x04A0);
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
+ | 0x0008);
+ phy_stacksave(0x04A1);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
+ | 0x0605);
+ phy_stacksave(0x04A2);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
+ | 0x0204);
+ phy_stacksave(0x04A8);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
+ | 0x0803);
+ phy_stacksave(0x04AB);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
+ | 0x0605);
+
+ phy_stacksave(0x04A7);
+ b43legacy_phy_write(dev, 0x04A7, 0x0002);
+ phy_stacksave(0x04A3);
+ b43legacy_phy_write(dev, 0x04A3, 0x287A);
+ phy_stacksave(0x04A9);
+ b43legacy_phy_write(dev, 0x04A9, 0x2027);
+ phy_stacksave(0x0493);
+ b43legacy_phy_write(dev, 0x0493, 0x32F5);
+ phy_stacksave(0x04AA);
+ b43legacy_phy_write(dev, 0x04AA, 0x2027);
+ phy_stacksave(0x04AC);
+ b43legacy_phy_write(dev, 0x04AC, 0x32F5);
+ break;
+ case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+ if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
+ break;
+
+ phy->aci_enable = 1;
+
+ phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
+ phy_stacksave(B43legacy_PHY_G_CRS);
+ if (phy->rev < 2)
+ phy_stacksave(0x0406);
+ else {
+ phy_stacksave(0x04C0);
+ phy_stacksave(0x04C1);
+ }
+ phy_stacksave(0x0033);
+ phy_stacksave(0x04A7);
+ phy_stacksave(0x04A3);
+ phy_stacksave(0x04A9);
+ phy_stacksave(0x04AA);
+ phy_stacksave(0x04AC);
+ phy_stacksave(0x0493);
+ phy_stacksave(0x04A1);
+ phy_stacksave(0x04A0);
+ phy_stacksave(0x04A2);
+ phy_stacksave(0x048A);
+ phy_stacksave(0x04A8);
+ phy_stacksave(0x04AB);
+ if (phy->rev == 2) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x0415);
+ phy_stacksave(0x0416);
+ phy_stacksave(0x0417);
+ ilt_stacksave(0x1A00 + 0x2);
+ ilt_stacksave(0x1A00 + 0x3);
+ }
+ phy_stacksave(0x042B);
+ phy_stacksave(0x048C);
+
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ (b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS)
+ & 0xFFFC) | 0x0002);
+
+ b43legacy_phy_write(dev, 0x0033, 0x0800);
+ b43legacy_phy_write(dev, 0x04A3, 0x2027);
+ b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
+ b43legacy_phy_write(dev, 0x0493, 0x287A);
+ b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
+ b43legacy_phy_write(dev, 0x04AC, 0x287A);
+
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0)
+ & 0xFFC0) | 0x001A);
+ b43legacy_phy_write(dev, 0x04A7, 0x000D);
+
+ if (phy->rev < 2)
+ b43legacy_phy_write(dev, 0x0406, 0xFF0D);
+ else if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
+ b43legacy_phy_write(dev, 0x04C1, 0x00A9);
+ } else {
+ b43legacy_phy_write(dev, 0x04C0, 0x00C1);
+ b43legacy_phy_write(dev, 0x04C1, 0x0059);
+ }
+
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1)
+ & 0xC0FF) | 0x1800);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1)
+ & 0xFFC0) | 0x0015);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xCFFF) | 0x1000);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xF0FF) | 0x0A00);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xCFFF) | 0x1000);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0800);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xFFCF) | 0x0010);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xFFF0) | 0x0005);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xFFCF) | 0x0010);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xFFF0) | 0x0006);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0800);
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0500);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x000B);
+
+ if (phy->rev >= 3) {
+ b43legacy_phy_write(dev, 0x048A,
+ b43legacy_phy_read(dev, 0x048A)
+ & ~0x8000);
+ b43legacy_phy_write(dev, 0x0415,
+ (b43legacy_phy_read(dev, 0x0415)
+ & 0x8000) | 0x36D8);
+ b43legacy_phy_write(dev, 0x0416,
+ (b43legacy_phy_read(dev, 0x0416)
+ & 0x8000) | 0x36D8);
+ b43legacy_phy_write(dev, 0x0417,
+ (b43legacy_phy_read(dev, 0x0417)
+ & 0xFE00) | 0x016D);
+ } else {
+ b43legacy_phy_write(dev, 0x048A,
+ b43legacy_phy_read(dev, 0x048A)
+ | 0x1000);
+ b43legacy_phy_write(dev, 0x048A,
+ (b43legacy_phy_read(dev, 0x048A)
+ & 0x9FFF) | 0x2000);
+ tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ if (!(tmp32 & 0x800)) {
+ tmp32 |= 0x800;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ tmp32);
+ }
+ }
+ if (phy->rev >= 2)
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B)
+ | 0x0800);
+ b43legacy_phy_write(dev, 0x048C,
+ (b43legacy_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0200);
+ if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x04AE,
+ (b43legacy_phy_read(dev, 0x04AE)
+ & 0xFF00) | 0x007F);
+ b43legacy_phy_write(dev, 0x04AD,
+ (b43legacy_phy_read(dev, 0x04AD)
+ & 0x00FF) | 0x1300);
+ } else if (phy->rev >= 6) {
+ b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
+ b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
+ b43legacy_phy_write(dev, 0x04AD,
+ b43legacy_phy_read(dev, 0x04AD)
+ & 0x00FF);
+ }
+ b43legacy_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+static void
+b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
+ int mode)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u32 tmp32;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43legacy_RADIO_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B)
+ & ~0x0800);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) | 0x4000);
+ break;
+ }
+ phy_stackrestore(0x0078);
+ b43legacy_calc_nrssi_threshold(dev);
+ phy_stackrestore(0x0406);
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B) & ~0x0800);
+ if (!dev->bad_frames_preempt)
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD)
+ & ~(1 << 11));
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ | 0x4000);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x04A8);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A7);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ break;
+ case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+ if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
+ break;
+
+ phy->aci_enable = 0;
+
+ phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
+ phy_stackrestore(B43legacy_PHY_G_CRS);
+ phy_stackrestore(0x0033);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A7);
+ if (phy->rev >= 2) {
+ phy_stackrestore(0x04C0);
+ phy_stackrestore(0x04C1);
+ } else
+ phy_stackrestore(0x0406);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A8);
+ if (phy->rev == 2) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x0415);
+ phy_stackrestore(0x0416);
+ phy_stackrestore(0x0417);
+ ilt_stackrestore(0x1A00 + 0x2);
+ ilt_stackrestore(0x1A00 + 0x3);
+ }
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x04A8);
+ phy_stackrestore(0x042B);
+ phy_stackrestore(0x048C);
+ tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ if (tmp32 & 0x800) {
+ tmp32 &= ~0x800;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ tmp32);
+ }
+ b43legacy_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ilt_stacksave
+#undef ilt_stackrestore
+
+int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
+ int mode)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int currentmode;
+
+ if ((phy->type != B43legacy_PHYTYPE_G) ||
+ (phy->rev == 0) || (!phy->gmode))
+ return -ENODEV;
+
+ phy->aci_wlan_automatic = 0;
+ switch (mode) {
+ case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
+ phy->aci_wlan_automatic = 1;
+ if (phy->aci_enable)
+ mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
+ else
+ mode = B43legacy_RADIO_INTERFMODE_NONE;
+ break;
+ case B43legacy_RADIO_INTERFMODE_NONE:
+ case B43legacy_RADIO_INTERFMODE_NONWLAN:
+ case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ currentmode = phy->interfmode;
+ if (currentmode == mode)
+ return 0;
+ if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
+ b43legacy_radio_interference_mitigation_disable(dev,
+ currentmode);
+
+ if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
+ phy->aci_enable = 0;
+ phy->aci_hw_rssi = 0;
+ } else
+ b43legacy_radio_interference_mitigation_enable(dev, mode);
+ phy->interfmode = mode;
+
+ return 0;
+}
+
+u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
+{
+ u16 reg;
+ u16 index;
+ u16 ret;
+
+ reg = b43legacy_radio_read16(dev, 0x0060);
+ index = (reg & 0x001E) >> 1;
+ ret = rcc_table[index] << 1;
+ ret |= (reg & 0x0001);
+ ret |= 0x0020;
+
+ return ret;
+}
+
+#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 loop_or = 0;
+ u16 adj_loopback_gain = phy->loopback_gain[0];
+ u8 loop;
+ u16 extern_lna_control;
+
+ if (!phy->gmode)
+ return 0;
+ if (!has_loopback_gain(phy)) {
+ if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_EXTLNA)) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0FB2;
+ case LPD(0, 0, 1):
+ return 0x00B2;
+ case LPD(1, 0, 1):
+ return 0x30B2;
+ case LPD(1, 0, 0):
+ return 0x30B3;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8FB2;
+ case LPD(0, 0, 1):
+ return 0x80B2;
+ case LPD(1, 0, 1):
+ return 0x20B2;
+ case LPD(1, 0, 0):
+ return 0x20B3;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ }
+ } else {
+ if (phy->radio_rev == 8)
+ adj_loopback_gain += 0x003E;
+ else
+ adj_loopback_gain += 0x0026;
+ if (adj_loopback_gain >= 0x46) {
+ adj_loopback_gain -= 0x46;
+ extern_lna_control = 0x3000;
+ } else if (adj_loopback_gain >= 0x3A) {
+ adj_loopback_gain -= 0x3A;
+ extern_lna_control = 0x2000;
+ } else if (adj_loopback_gain >= 0x2E) {
+ adj_loopback_gain -= 0x2E;
+ extern_lna_control = 0x1000;
+ } else {
+ adj_loopback_gain -= 0x10;
+ extern_lna_control = 0x0000;
+ }
+ for (loop = 0; loop < 16; loop++) {
+ u16 tmp = adj_loopback_gain - 6 * loop;
+ if (tmp < 6)
+ break;
+ }
+
+ loop_or = (loop << 8) | extern_lna_control;
+ if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_EXTLNA) {
+ if (extern_lna_control)
+ loop_or |= 0x8000;
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8F92;
+ case LPD(0, 0, 1):
+ return (0x8092 | loop_or);
+ case LPD(1, 0, 1):
+ return (0x2092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x2093 | loop_or);
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0F92;
+ case LPD(0, 0, 1):
+ case LPD(1, 0, 1):
+ return (0x0092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x0093 | loop_or);
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ }
+ }
+ return 0;
+}
+
+u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup[21] = { 0 };
+ u16 ret;
+ u16 i;
+ u16 j;
+ u32 tmp1 = 0;
+ u32 tmp2 = 0;
+
+ backup[0] = b43legacy_radio_read16(dev, 0x0043);
+ backup[14] = b43legacy_radio_read16(dev, 0x0051);
+ backup[15] = b43legacy_radio_read16(dev, 0x0052);
+ backup[1] = b43legacy_phy_read(dev, 0x0015);
+ backup[16] = b43legacy_phy_read(dev, 0x005A);
+ backup[17] = b43legacy_phy_read(dev, 0x0059);
+ backup[18] = b43legacy_phy_read(dev, 0x0058);
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ backup[2] = b43legacy_phy_read(dev, 0x0030);
+ backup[3] = b43legacy_read16(dev, 0x03EC);
+ b43legacy_phy_write(dev, 0x0030, 0x00FF);
+ b43legacy_write16(dev, 0x03EC, 0x3F3F);
+ } else {
+ if (phy->gmode) {
+ backup[4] = b43legacy_phy_read(dev, 0x0811);
+ backup[5] = b43legacy_phy_read(dev, 0x0812);
+ backup[6] = b43legacy_phy_read(dev, 0x0814);
+ backup[7] = b43legacy_phy_read(dev, 0x0815);
+ backup[8] = b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS);
+ backup[9] = b43legacy_phy_read(dev, 0x0802);
+ b43legacy_phy_write(dev, 0x0814,
+ (b43legacy_phy_read(dev, 0x0814)
+ | 0x0003));
+ b43legacy_phy_write(dev, 0x0815,
+ (b43legacy_phy_read(dev, 0x0815)
+ & 0xFFFC));
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ (b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) & 0x7FFF));
+ b43legacy_phy_write(dev, 0x0802,
+ (b43legacy_phy_read(dev, 0x0802)
+ & 0xFFFC));
+ if (phy->rev > 1) { /* loopback gain enabled */
+ backup[19] = b43legacy_phy_read(dev, 0x080F);
+ backup[20] = b43legacy_phy_read(dev, 0x0810);
+ if (phy->rev >= 3)
+ b43legacy_phy_write(dev, 0x080F,
+ 0xC020);
+ else
+ b43legacy_phy_write(dev, 0x080F,
+ 0x8020);
+ b43legacy_phy_write(dev, 0x0810, 0x0000);
+ }
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(0, 1, 1)));
+ if (phy->rev < 7 ||
+ !(dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_EXTLNA))
+ b43legacy_phy_write(dev, 0x0811, 0x01B3);
+ else
+ b43legacy_phy_write(dev, 0x0811, 0x09B3);
+ }
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
+ (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
+ | 0x8000));
+ backup[10] = b43legacy_phy_read(dev, 0x0035);
+ b43legacy_phy_write(dev, 0x0035,
+ (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
+ backup[11] = b43legacy_read16(dev, 0x03E6);
+ backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+
+ /* Initialization */
+ if (phy->analog == 0)
+ b43legacy_write16(dev, 0x03E6, 0x0122);
+ else {
+ if (phy->analog >= 2)
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003)
+ & 0xFFBF) | 0x0040);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ (b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
+ }
+
+ ret = b43legacy_radio_calibrationvalue(dev);
+
+ if (phy->type == B43legacy_PHYTYPE_B)
+ b43legacy_radio_write16(dev, 0x0078, 0x0026);
+
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(0, 1, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xBFAF);
+ b43legacy_phy_write(dev, 0x002B, 0x1403);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(0, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xBFA0);
+ b43legacy_radio_write16(dev, 0x0051,
+ (b43legacy_radio_read16(dev, 0x0051)
+ | 0x0004));
+ if (phy->radio_rev == 8)
+ b43legacy_radio_write16(dev, 0x0043, 0x001F);
+ else {
+ b43legacy_radio_write16(dev, 0x0052, 0x0000);
+ b43legacy_radio_write16(dev, 0x0043,
+ (b43legacy_radio_read16(dev, 0x0043)
+ & 0xFFF0) | 0x0009);
+ }
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+
+ for (i = 0; i < 16; i++) {
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0xC810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xEFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 0)));
+ b43legacy_phy_write(dev, 0x0015, 0xFFF0);
+ udelay(20);
+ tmp1 += b43legacy_phy_read(dev, 0x002D);
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ }
+
+ tmp1++;
+ tmp1 >>= 9;
+ udelay(10);
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+
+ for (i = 0; i < 16; i++) {
+ b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
+ | 0x0020);
+ backup[13] = b43legacy_radio_read16(dev, 0x0078);
+ udelay(10);
+ for (j = 0; j < 16; j++) {
+ b43legacy_phy_write(dev, 0x005A, 0x0D80);
+ b43legacy_phy_write(dev, 0x0059, 0xC810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xEFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 0)));
+ b43legacy_phy_write(dev, 0x0015, 0xFFF0);
+ udelay(10);
+ tmp2 += b43legacy_phy_read(dev, 0x002D);
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ }
+ tmp2++;
+ tmp2 >>= 8;
+ if (tmp1 < tmp2)
+ break;
+ }
+
+ /* Restore the registers */
+ b43legacy_phy_write(dev, 0x0015, backup[1]);
+ b43legacy_radio_write16(dev, 0x0051, backup[14]);
+ b43legacy_radio_write16(dev, 0x0052, backup[15]);
+ b43legacy_radio_write16(dev, 0x0043, backup[0]);
+ b43legacy_phy_write(dev, 0x005A, backup[16]);
+ b43legacy_phy_write(dev, 0x0059, backup[17]);
+ b43legacy_phy_write(dev, 0x0058, backup[18]);
+ b43legacy_write16(dev, 0x03E6, backup[11]);
+ if (phy->analog != 0)
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
+ b43legacy_phy_write(dev, 0x0035, backup[10]);
+ b43legacy_radio_selectchannel(dev, phy->channel, 1);
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ b43legacy_phy_write(dev, 0x0030, backup[2]);
+ b43legacy_write16(dev, 0x03EC, backup[3]);
+ } else {
+ if (phy->gmode) {
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
+ (b43legacy_read16(dev,
+ B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
+ b43legacy_phy_write(dev, 0x0811, backup[4]);
+ b43legacy_phy_write(dev, 0x0812, backup[5]);
+ b43legacy_phy_write(dev, 0x0814, backup[6]);
+ b43legacy_phy_write(dev, 0x0815, backup[7]);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ backup[8]);
+ b43legacy_phy_write(dev, 0x0802, backup[9]);
+ if (phy->rev > 1) {
+ b43legacy_phy_write(dev, 0x080F, backup[19]);
+ b43legacy_phy_write(dev, 0x0810, backup[20]);
+ }
+ }
+ }
+ if (i >= 15)
+ ret = backup[13];
+
+ return ret;
+}
+
+static inline
+u16 freq_r3A_value(u16 frequency)
+{
+ u16 value;
+
+ if (frequency < 5091)
+ value = 0x0040;
+ else if (frequency < 5321)
+ value = 0x0000;
+ else if (frequency < 5806)
+ value = 0x0080;
+ else
+ value = 0x0040;
+
+ return value;
+}
+
+void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
+{
+ static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+ static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+ u16 tmp = b43legacy_radio_read16(dev, 0x001E);
+ int i;
+ int j;
+
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 5; j++) {
+ if (tmp == (data_high[i] | data_low[j])) {
+ b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
+ 0x00C0);
+ return;
+ }
+ }
+ }
+}
+
+int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
+ u8 channel,
+ int synthetic_pu_workaround)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (channel == 0xFF) {
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ }
+
+/* TODO: Check if channel is valid - return -EINVAL if not */
+ if (synthetic_pu_workaround)
+ b43legacy_synth_pu_workaround(dev, channel);
+
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel));
+
+ if (channel == 14) {
+ if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ b43legacy_shm_read32(dev,
+ B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET)
+ & ~(1 << 7));
+ else
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ b43legacy_shm_read32(dev,
+ B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET)
+ | (1 << 7));
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
+ } else
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
+
+ phy->channel = channel;
+ /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
+ * that 2000 usecs might suffice. */
+ msleep(8);
+
+ return 0;
+}
+
+void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
+{
+ u16 tmp;
+
+ val <<= 8;
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 b43legacy_get_txgain_base_band(u16 txpower)
+{
+ u16 ret;
+
+ B43legacy_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = 2;
+ else if (txpower >= 49)
+ ret = 4;
+ else if (txpower >= 44)
+ ret = 5;
+ else
+ ret = 6;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
+{
+ u16 ret;
+
+ B43legacy_WARN_ON(txpower > 63);
+
+ if (txpower >= 32)
+ ret = 0;
+ else if (txpower >= 25)
+ ret = 1;
+ else if (txpower >= 20)
+ ret = 2;
+ else if (txpower >= 12)
+ ret = 3;
+ else
+ ret = 4;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 b43legacy_get_txgain_dac(u16 txpower)
+{
+ u16 ret;
+
+ B43legacy_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = txpower - 53;
+ else if (txpower >= 49)
+ ret = txpower - 42;
+ else if (txpower >= 44)
+ ret = txpower - 37;
+ else if (txpower >= 32)
+ ret = txpower - 32;
+ else if (txpower >= 25)
+ ret = txpower - 20;
+ else if (txpower >= 20)
+ ret = txpower - 13;
+ else if (txpower >= 12)
+ ret = txpower - 8;
+ else
+ ret = txpower;
+
+ return ret;
+}
+
+void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 pamp;
+ u16 base;
+ u16 dac;
+ u16 ilt;
+
+ txpower = limit_value(txpower, 0, 63);
+
+ pamp = b43legacy_get_txgain_freq_power_amp(txpower);
+ pamp <<= 5;
+ pamp &= 0x00E0;
+ b43legacy_phy_write(dev, 0x0019, pamp);
+
+ base = b43legacy_get_txgain_base_band(txpower);
+ base &= 0x000F;
+ b43legacy_phy_write(dev, 0x0017, base | 0x0020);
+
+ ilt = b43legacy_ilt_read(dev, 0x3001);
+ ilt &= 0x0007;
+
+ dac = b43legacy_get_txgain_dac(txpower);
+ dac <<= 3;
+ dac |= ilt;
+
+ b43legacy_ilt_write(dev, 0x3001, dac);
+
+ phy->txpwr_offset = txpower;
+
+ /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
+}
+
+void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
+ u16 baseband_attenuation,
+ u16 radio_attenuation,
+ u16 txpower)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (baseband_attenuation == 0xFFFF)
+ baseband_attenuation = phy->bbatt;
+ if (radio_attenuation == 0xFFFF)
+ radio_attenuation = phy->rfatt;
+ if (txpower == 0xFFFF)
+ txpower = phy->txctl1;
+ phy->bbatt = baseband_attenuation;
+ phy->rfatt = radio_attenuation;
+ phy->txctl1 = txpower;
+
+ B43legacy_WARN_ON(baseband_attenuation > 11);
+ if (phy->radio_rev < 6)
+ B43legacy_WARN_ON(radio_attenuation > 9);
+ else
+ B43legacy_WARN_ON(radio_attenuation > 31);
+ B43legacy_WARN_ON(txpower > 7);
+
+ b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
+ b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
+ radio_attenuation);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_radio_write16(dev, 0x0052,
+ (b43legacy_radio_read16(dev, 0x0052)
+ & ~0x0070) | ((txpower << 4) & 0x0070));
+ /* FIXME: The spec is very weird and unclear here. */
+ if (phy->type == B43legacy_PHYTYPE_G)
+ b43legacy_phy_lo_adjust(dev, 0);
+}
+
+u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+ return 0;
+ return 2;
+}
+
+u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 att = 0xFFFF;
+
+ switch (phy->radio_ver) {
+ case 0x2053:
+ switch (phy->radio_rev) {
+ case 1:
+ att = 6;
+ break;
+ }
+ break;
+ case 0x2050:
+ switch (phy->radio_rev) {
+ case 0:
+ att = 5;
+ break;
+ case 1:
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421 &&
+ dev->dev->bus->boardinfo.rev >= 30)
+ att = 3;
+ else if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x416)
+ att = 3;
+ else
+ att = 1;
+ } else {
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421 &&
+ dev->dev->bus->boardinfo.rev >= 30)
+ att = 7;
+ else
+ att = 6;
+ }
+ break;
+ case 2:
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421 &&
+ dev->dev->bus->boardinfo.rev >= 30)
+ att = 3;
+ else if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type ==
+ 0x416)
+ att = 5;
+ else if (dev->dev->bus->chip_id == 0x4320)
+ att = 4;
+ else
+ att = 3;
+ } else
+ att = 6;
+ break;
+ case 3:
+ att = 5;
+ break;
+ case 4:
+ case 5:
+ att = 1;
+ break;
+ case 6:
+ case 7:
+ att = 5;
+ break;
+ case 8:
+ att = 0x1A;
+ break;
+ case 9:
+ default:
+ att = 5;
+ }
+ }
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421) {
+ if (dev->dev->bus->boardinfo.rev < 0x43)
+ att = 2;
+ else if (dev->dev->bus->boardinfo.rev < 0x51)
+ att = 3;
+ }
+ if (att == 0xFFFF)
+ att = 5;
+
+ return att;
+}
+
+u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->radio_ver != 0x2050)
+ return 0;
+ if (phy->radio_rev == 1)
+ return 3;
+ if (phy->radio_rev < 6)
+ return 2;
+ if (phy->radio_rev == 8)
+ return 1;
+ return 0;
+}
+
+void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int err;
+ u8 channel;
+
+ might_sleep();
+
+ if (phy->radio_on)
+ return;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ b43legacy_phy_write(dev, 0x0015, 0x8000);
+ b43legacy_phy_write(dev, 0x0015, 0xCC00);
+ b43legacy_phy_write(dev, 0x0015,
+ (phy->gmode ? 0x00C0 : 0x0000));
+ if (phy->radio_off_context.valid) {
+ /* Restore the RFover values. */
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
+ phy->radio_off_context.rfover);
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
+ phy->radio_off_context.rfoverval);
+ phy->radio_off_context.valid = 0;
+ }
+ channel = phy->channel;
+ err = b43legacy_radio_selectchannel(dev,
+ B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
+ err |= b43legacy_radio_selectchannel(dev, channel, 0);
+ B43legacy_WARN_ON(err);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ phy->radio_on = 1;
+ b43legacy_leds_update(dev, 0);
+}
+
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
+ u16 rfover, rfoverval;
+
+ rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
+ rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
+ phy->radio_off_context.rfover = rfover;
+ phy->radio_off_context.rfoverval = rfoverval;
+ phy->radio_off_context.valid = 1;
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
+ rfoverval & 0xFF73);
+ } else
+ b43legacy_phy_write(dev, 0x0015, 0xAA00);
+ phy->radio_on = 0;
+ b43legacydbg(dev->wl, "Radio initialized\n");
+ b43legacy_leds_update(dev, 0);
+}
+
+void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
+ 0x7F7F);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
+ 0x7F7F);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
+ 0x7F7F);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
+ 0x7F7F);
+ break;
+ }
+}
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
new file mode 100644
index 000000000000..6c6a203439e1
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -0,0 +1,98 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_RADIO_H_
+#define B43legacy_RADIO_H_
+
+#include "b43legacy.h"
+
+
+#define B43legacy_RADIO_DEFAULT_CHANNEL_BG 6
+
+/* Force antenna 0. */
+#define B43legacy_RADIO_TXANTENNA_0 0
+/* Force antenna 1. */
+#define B43legacy_RADIO_TXANTENNA_1 1
+/* Use the RX antenna, that was selected for the most recently
+ * received good PLCP header.
+ */
+#define B43legacy_RADIO_TXANTENNA_LASTPLCP 3
+#define B43legacy_RADIO_TXANTENNA_DEFAULT B43legacy_RADIO_TXANTENNA_LASTPLCP
+
+#define B43legacy_RADIO_INTERFMODE_NONE 0
+#define B43legacy_RADIO_INTERFMODE_NONWLAN 1
+#define B43legacy_RADIO_INTERFMODE_MANUALWLAN 2
+#define B43legacy_RADIO_INTERFMODE_AUTOWLAN 3
+
+
+void b43legacy_radio_lock(struct b43legacy_wldev *dev);
+void b43legacy_radio_unlock(struct b43legacy_wldev *dev);
+
+u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val);
+
+u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_turn_on(struct b43legacy_wldev *dev);
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev);
+
+int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel,
+ int synthetic_pu_workaround);
+
+void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower);
+void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
+ u16 baseband_attenuation, u16 attenuation,
+ u16 txpower);
+
+u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev);
+u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev);
+u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val);
+
+void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev);
+
+u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel);
+u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev);
+
+int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
+ int mode);
+
+void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev);
+void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev);
+s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val);
+void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val);
+void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev);
+u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev);
+
+#endif /* B43legacy_RADIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c
new file mode 100644
index 000000000000..56c384fa9b1f
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.c
@@ -0,0 +1,238 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ SYSFS support routines
+
+ Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "sysfs.h"
+#include "b43legacy.h"
+#include "main.h"
+#include "phy.h"
+#include "radio.h"
+
+#include <linux/capability.h>
+
+
+#define GENERIC_FILESIZE 64
+
+
+static int get_integer(const char *buf, size_t count)
+{
+ char tmp[10 + 1] = { 0 };
+ int ret = -EINVAL;
+
+ if (count == 0)
+ goto out;
+ count = min(count, (size_t)10);
+ memcpy(tmp, buf, count);
+ ret = simple_strtol(tmp, NULL, 10);
+out:
+ return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+ if (count != 0) {
+ if (buf[0] == '1')
+ return 1;
+ if (buf[0] == '0')
+ return 0;
+ if (count >= 4 && memcmp(buf, "true", 4) == 0)
+ return 1;
+ if (count >= 5 && memcmp(buf, "false", 5) == 0)
+ return 0;
+ if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+ return 1;
+ if (count >= 2 && memcmp(buf, "no", 2) == 0)
+ return 0;
+ if (count >= 2 && memcmp(buf, "on", 2) == 0)
+ return 1;
+ if (count >= 3 && memcmp(buf, "off", 3) == 0)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static ssize_t b43legacy_attr_interfmode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ ssize_t count = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ switch (wldev->phy.interfmode) {
+ case B43legacy_INTERFMODE_NONE:
+ count = snprintf(buf, PAGE_SIZE, "0 (No Interference"
+ " Mitigation)\n");
+ break;
+ case B43legacy_INTERFMODE_NONWLAN:
+ count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference"
+ " Mitigation)\n");
+ break;
+ case B43legacy_INTERFMODE_MANUALWLAN:
+ count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference"
+ " Mitigation)\n");
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43legacy_attr_interfmode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ unsigned long flags;
+ int err;
+ int mode;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mode = get_integer(buf, count);
+ switch (mode) {
+ case 0:
+ mode = B43legacy_INTERFMODE_NONE;
+ break;
+ case 1:
+ mode = B43legacy_INTERFMODE_NONWLAN;
+ break;
+ case 2:
+ mode = B43legacy_INTERFMODE_MANUALWLAN;
+ break;
+ case 3:
+ mode = B43legacy_INTERFMODE_AUTOWLAN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ err = b43legacy_radio_set_interference_mitigation(wldev, mode);
+ if (err)
+ b43legacyerr(wldev->wl, "Interference Mitigation not "
+ "supported by device\n");
+ mmiowb();
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return err ? err : count;
+}
+
+static DEVICE_ATTR(interference, 0644,
+ b43legacy_attr_interfmode_show,
+ b43legacy_attr_interfmode_store);
+
+static ssize_t b43legacy_attr_preamble_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ ssize_t count;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ if (wldev->short_preamble)
+ count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble"
+ " enabled)\n");
+ else
+ count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble"
+ " disabled)\n");
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43legacy_attr_preamble_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ unsigned long flags;
+ int value;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ value = get_boolean(buf, count);
+ if (value < 0)
+ return value;
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ wldev->short_preamble = !!value;
+
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(shortpreamble, 0644,
+ b43legacy_attr_preamble_show,
+ b43legacy_attr_preamble_store);
+
+int b43legacy_sysfs_register(struct b43legacy_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+ int err;
+
+ B43legacy_WARN_ON(b43legacy_status(wldev) !=
+ B43legacy_STAT_INITIALIZED);
+
+ err = device_create_file(dev, &dev_attr_interference);
+ if (err)
+ goto out;
+ err = device_create_file(dev, &dev_attr_shortpreamble);
+ if (err)
+ goto err_remove_interfmode;
+
+out:
+ return err;
+err_remove_interfmode:
+ device_remove_file(dev, &dev_attr_interference);
+ goto out;
+}
+
+void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+
+ device_remove_file(dev, &dev_attr_shortpreamble);
+ device_remove_file(dev, &dev_attr_interference);
+}
diff --git a/drivers/net/wireless/b43legacy/sysfs.h b/drivers/net/wireless/b43legacy/sysfs.h
new file mode 100644
index 000000000000..417d509803c7
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef B43legacy_SYSFS_H_
+#define B43legacy_SYSFS_H_
+
+struct b43legacy_wldev;
+
+int b43legacy_sysfs_register(struct b43legacy_wldev *dev);
+void b43legacy_sysfs_unregister(struct b43legacy_wldev *dev);
+
+#endif /* B43legacy_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
new file mode 100644
index 000000000000..fa1e65687a63
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -0,0 +1,642 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Transmission (TX/RX) related functions.
+
+ Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <net/dst.h>
+
+#include "xmit.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0]) {
+ case 0x0A:
+ return B43legacy_CCK_RATE_1MB;
+ case 0x14:
+ return B43legacy_CCK_RATE_2MB;
+ case 0x37:
+ return B43legacy_CCK_RATE_5MB;
+ case 0x6E:
+ return B43legacy_CCK_RATE_11MB;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0] & 0xF) {
+ case 0xB:
+ return B43legacy_OFDM_RATE_6MB;
+ case 0xF:
+ return B43legacy_OFDM_RATE_9MB;
+ case 0xA:
+ return B43legacy_OFDM_RATE_12MB;
+ case 0xE:
+ return B43legacy_OFDM_RATE_18MB;
+ case 0x9:
+ return B43legacy_OFDM_RATE_24MB;
+ case 0xD:
+ return B43legacy_OFDM_RATE_36MB;
+ case 0x8:
+ return B43legacy_OFDM_RATE_48MB;
+ case 0xC:
+ return B43legacy_OFDM_RATE_54MB;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43legacy_CCK_RATE_1MB:
+ return 0x0A;
+ case B43legacy_CCK_RATE_2MB:
+ return 0x14;
+ case B43legacy_CCK_RATE_5MB:
+ return 0x37;
+ case B43legacy_CCK_RATE_11MB:
+ return 0x6E;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43legacy_OFDM_RATE_6MB:
+ return 0xB;
+ case B43legacy_OFDM_RATE_9MB:
+ return 0xF;
+ case B43legacy_OFDM_RATE_12MB:
+ return 0xA;
+ case B43legacy_OFDM_RATE_18MB:
+ return 0xE;
+ case B43legacy_OFDM_RATE_24MB:
+ return 0x9;
+ case B43legacy_OFDM_RATE_36MB:
+ return 0xD;
+ case B43legacy_OFDM_RATE_48MB:
+ return 0x8;
+ case B43legacy_OFDM_RATE_54MB:
+ return 0xC;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate)
+{
+ __le32 *data = &(plcp->data);
+ __u8 *raw = plcp->raw;
+
+ if (b43legacy_is_ofdm_rate(bitrate)) {
+ u16 d;
+
+ d = b43legacy_plcp_get_ratecode_ofdm(bitrate);
+ B43legacy_WARN_ON(octets & 0xF000);
+ d |= (octets << 5);
+ *data = cpu_to_le32(d);
+ } else {
+ u32 plen;
+
+ plen = octets * 16 / bitrate;
+ if ((octets * 16 % bitrate) > 0) {
+ plen++;
+ if ((bitrate == B43legacy_CCK_RATE_11MB)
+ && ((octets * 8 % 11) < 4))
+ raw[1] = 0x84;
+ else
+ raw[1] = 0x04;
+ } else
+ raw[1] = 0x04;
+ *data |= cpu_to_le32(plen << 16);
+ raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate);
+ }
+}
+
+static u8 b43legacy_calc_fallback_rate(u8 bitrate)
+{
+ switch (bitrate) {
+ case B43legacy_CCK_RATE_1MB:
+ return B43legacy_CCK_RATE_1MB;
+ case B43legacy_CCK_RATE_2MB:
+ return B43legacy_CCK_RATE_1MB;
+ case B43legacy_CCK_RATE_5MB:
+ return B43legacy_CCK_RATE_2MB;
+ case B43legacy_CCK_RATE_11MB:
+ return B43legacy_CCK_RATE_5MB;
+ case B43legacy_OFDM_RATE_6MB:
+ return B43legacy_CCK_RATE_5MB;
+ case B43legacy_OFDM_RATE_9MB:
+ return B43legacy_OFDM_RATE_6MB;
+ case B43legacy_OFDM_RATE_12MB:
+ return B43legacy_OFDM_RATE_9MB;
+ case B43legacy_OFDM_RATE_18MB:
+ return B43legacy_OFDM_RATE_12MB;
+ case B43legacy_OFDM_RATE_24MB:
+ return B43legacy_OFDM_RATE_18MB;
+ case B43legacy_OFDM_RATE_36MB:
+ return B43legacy_OFDM_RATE_24MB;
+ case B43legacy_OFDM_RATE_48MB:
+ return B43legacy_OFDM_RATE_36MB;
+ case B43legacy_OFDM_RATE_54MB:
+ return B43legacy_OFDM_RATE_48MB;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
+ struct b43legacy_txhdr_fw3 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie)
+{
+ const struct ieee80211_hdr *wlhdr;
+ int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ u16 fctl;
+ u8 rate;
+ u8 rate_fb;
+ int rate_ofdm;
+ int rate_fb_ofdm;
+ unsigned int plcp_fragment_len;
+ u32 mac_ctl = 0;
+ u16 phy_ctl = 0;
+
+ wlhdr = (const struct ieee80211_hdr *)fragment_data;
+ fctl = le16_to_cpu(wlhdr->frame_control);
+
+ memset(txhdr, 0, sizeof(*txhdr));
+
+ rate = txctl->tx_rate;
+ rate_ofdm = b43legacy_is_ofdm_rate(rate);
+ rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+ rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
+
+ txhdr->mac_frame_ctl = wlhdr->frame_control;
+ memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+ /* Calculate duration for fallback rate */
+ if ((rate_fb == rate) ||
+ (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+ (wlhdr->duration_id == cpu_to_le16(0))) {
+ /* If the fallback rate equals the normal rate or the
+ * dur_id field contains an AID, CFP magic or 0,
+ * use the original dur_id field. */
+ txhdr->dur_fb = wlhdr->duration_id;
+ } else {
+ int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_len,
+ fbrate_base100kbps);
+ }
+
+ plcp_fragment_len = fragment_len + FCS_LEN;
+ if (use_encryption) {
+ u8 key_idx = (u16)(txctl->key_idx);
+ struct b43legacy_key *key;
+ int wlhdr_len;
+ size_t iv_len;
+
+ B43legacy_WARN_ON(key_idx >= dev->max_nr_keys);
+ key = &(dev->key[key_idx]);
+
+ if (key->enabled) {
+ /* Hardware appends ICV. */
+ plcp_fragment_len += txctl->icv_len;
+
+ key_idx = b43legacy_kidx_to_fw(dev, key_idx);
+ mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
+ B43legacy_TX4_MAC_KEYIDX;
+ mac_ctl |= (key->algorithm <<
+ B43legacy_TX4_MAC_KEYALG_SHIFT) &
+ B43legacy_TX4_MAC_KEYALG;
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ iv_len = min((size_t)txctl->iv_len,
+ ARRAY_SIZE(txhdr->iv));
+ memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
+ }
+ }
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->plcp), plcp_fragment_len,
+ rate);
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->plcp_fb), plcp_fragment_len,
+ rate_fb);
+
+ /* PHY TX Control word */
+ if (rate_ofdm)
+ phy_ctl |= B43legacy_TX4_PHY_OFDM;
+ if (dev->short_preamble)
+ phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
+ switch (txctl->antenna_sel_tx) {
+ case 0:
+ phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
+ break;
+ case 1:
+ phy_ctl |= B43legacy_TX4_PHY_ANT0;
+ break;
+ case 2:
+ phy_ctl |= B43legacy_TX4_PHY_ANT1;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ /* MAC control */
+ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+ mac_ctl |= B43legacy_TX4_MAC_ACK;
+ if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+ mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
+ if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ mac_ctl |= B43legacy_TX4_MAC_STMSDU;
+ if (rate_fb_ofdm)
+ mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
+
+ /* Generate the RTS or CTS-to-self frame */
+ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+ (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ unsigned int len;
+ struct ieee80211_hdr *hdr;
+ int rts_rate;
+ int rts_rate_fb;
+ int rts_rate_ofdm;
+ int rts_rate_fb_ofdm;
+
+ rts_rate = txctl->rts_cts_rate;
+ rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
+ rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
+ if (rts_rate_fb_ofdm)
+ mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
+
+ if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ ieee80211_ctstoself_get(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_data,
+ fragment_len, txctl,
+ (struct ieee80211_cts *)
+ (txhdr->rts_frame));
+ mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
+ len = sizeof(struct ieee80211_cts);
+ } else {
+ ieee80211_rts_get(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_data, fragment_len, txctl,
+ (struct ieee80211_rts *)
+ (txhdr->rts_frame));
+ mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
+ len = sizeof(struct ieee80211_rts);
+ }
+ len += FCS_LEN;
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->rts_plcp),
+ len, rts_rate);
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->rts_plcp_fb),
+ len, rts_rate_fb);
+ hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+ txhdr->rts_dur_fb = hdr->duration_id;
+ mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
+ }
+
+ /* Magic cookie */
+ txhdr->cookie = cpu_to_le16(cookie);
+
+ /* Apply the bitfields */
+ txhdr->mac_ctl = cpu_to_le32(mac_ctl);
+ txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+}
+
+void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+ u8 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie)
+{
+ generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+ fragment_data, fragment_len,
+ txctl, cookie);
+}
+
+static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
+ u8 in_rssi, int ofdm,
+ int adjust_2053, int adjust_2050)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s32 tmp;
+
+ switch (phy->radio_ver) {
+ case 0x2050:
+ if (ofdm) {
+ tmp = in_rssi;
+ if (tmp > 127)
+ tmp -= 256;
+ tmp *= 73;
+ tmp /= 64;
+ if (adjust_2050)
+ tmp += 25;
+ else
+ tmp -= 3;
+ } else {
+ if (dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_RSSI) {
+ if (in_rssi > 63)
+ in_rssi = 63;
+ tmp = phy->nrssi_lt[in_rssi];
+ tmp = 31 - tmp;
+ tmp *= -131;
+ tmp /= 128;
+ tmp -= 57;
+ } else {
+ tmp = in_rssi;
+ tmp = 31 - tmp;
+ tmp *= -149;
+ tmp /= 128;
+ tmp -= 68;
+ }
+ if (phy->type == B43legacy_PHYTYPE_G &&
+ adjust_2050)
+ tmp += 25;
+ }
+ break;
+ case 0x2060:
+ if (in_rssi > 127)
+ tmp = in_rssi - 256;
+ else
+ tmp = in_rssi;
+ break;
+ default:
+ tmp = in_rssi;
+ tmp -= 11;
+ tmp *= 103;
+ tmp /= 64;
+ if (adjust_2053)
+ tmp -= 109;
+ else
+ tmp -= 83;
+ }
+
+ return (s8)tmp;
+}
+
+void b43legacy_rx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ const void *_rxhdr)
+{
+ struct ieee80211_rx_status status;
+ struct b43legacy_plcp_hdr6 *plcp;
+ struct ieee80211_hdr *wlhdr;
+ const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
+ u16 fctl;
+ u16 phystat0;
+ u16 phystat3;
+ u16 chanstat;
+ u16 mactime;
+ u32 macstat;
+ u16 chanid;
+ u8 jssi;
+ int padding;
+
+ memset(&status, 0, sizeof(status));
+
+ /* Get metadata about the frame from the header. */
+ phystat0 = le16_to_cpu(rxhdr->phy_status0);
+ phystat3 = le16_to_cpu(rxhdr->phy_status3);
+ jssi = rxhdr->jssi;
+ macstat = le16_to_cpu(rxhdr->mac_status);
+ mactime = le16_to_cpu(rxhdr->mac_time);
+ chanstat = le16_to_cpu(rxhdr->channel);
+
+ if (macstat & B43legacy_RX_MAC_FCSERR)
+ dev->wl->ieee_stats.dot11FCSErrorCount++;
+
+ /* Skip PLCP and padding */
+ padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0;
+ if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) +
+ padding))) {
+ b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n");
+ goto drop;
+ }
+ plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding);
+ skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding);
+ /* The skb contains the Wireless Header + payload data now */
+ if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) {
+ b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n");
+ goto drop;
+ }
+ wlhdr = (struct ieee80211_hdr *)(skb->data);
+ fctl = le16_to_cpu(wlhdr->frame_control);
+
+ if ((macstat & B43legacy_RX_MAC_DEC) &&
+ !(macstat & B43legacy_RX_MAC_DECERR)) {
+ unsigned int keyidx;
+ int wlhdr_len;
+ int iv_len;
+ int icv_len;
+
+ keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX)
+ >> B43legacy_RX_MAC_KEYIDX_SHIFT);
+ /* We must adjust the key index here. We want the "physical"
+ * key index, but the ucode passed it slightly different.
+ */
+ keyidx = b43legacy_kidx_to_raw(dev, keyidx);
+ B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
+
+ if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
+ /* Remove PROTECTED flag to mark it as decrypted. */
+ B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
+ fctl &= ~IEEE80211_FCTL_PROTECTED;
+ wlhdr->frame_control = cpu_to_le16(fctl);
+
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ if (unlikely(skb->len < (wlhdr_len + 3))) {
+ b43legacydbg(dev->wl, "RX: Packet size"
+ " underrun3\n");
+ goto drop;
+ }
+ if (skb->data[wlhdr_len + 3] & (1 << 5)) {
+ /* The Ext-IV Bit is set in the "KeyID"
+ * octet of the IV.
+ */
+ iv_len = 8;
+ icv_len = 8;
+ } else {
+ iv_len = 4;
+ icv_len = 4;
+ }
+ if (unlikely(skb->len < (wlhdr_len + iv_len +
+ icv_len))) {
+ b43legacydbg(dev->wl, "RX: Packet size"
+ " underrun4\n");
+ goto drop;
+ }
+ /* Remove the IV */
+ memmove(skb->data + iv_len, skb->data, wlhdr_len);
+ skb_pull(skb, iv_len);
+ /* Remove the ICV */
+ skb_trim(skb, skb->len - icv_len);
+
+ status.flag |= RX_FLAG_DECRYPTED;
+ }
+ }
+
+ status.ssi = b43legacy_rssi_postprocess(dev, jssi,
+ (phystat0 & B43legacy_RX_PHYST0_OFDM),
+ (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
+ (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
+ status.noise = dev->stats.link_noise;
+ status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
+ if (phystat0 & B43legacy_RX_PHYST0_OFDM)
+ status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
+ else
+ status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
+ status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
+ status.mactime = mactime;
+
+ chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
+ B43legacy_RX_CHAN_ID_SHIFT;
+ switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
+ case B43legacy_PHYTYPE_B:
+ status.phymode = MODE_IEEE80211B;
+ status.freq = chanid + 2400;
+ status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+ break;
+ case B43legacy_PHYTYPE_G:
+ status.phymode = MODE_IEEE80211G;
+ status.freq = chanid + 2400;
+ status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+ break;
+ default:
+ b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
+ chanstat);
+ }
+
+ dev->stats.last_rx = jiffies;
+ ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+
+ return;
+drop:
+ b43legacydbg(dev->wl, "RX: Packet dropped\n");
+ dev_kfree_skb_any(skb);
+}
+
+void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ b43legacy_debugfs_log_txstat(dev, status);
+
+ if (status->intermediate)
+ return;
+ if (status->for_ampdu)
+ return;
+ if (!status->acked)
+ dev->wl->ieee_stats.dot11ACKFailureCount++;
+ if (status->rts_count) {
+ if (status->rts_count == 0xF) /* FIXME */
+ dev->wl->ieee_stats.dot11RTSFailureCount++;
+ else
+ dev->wl->ieee_stats.dot11RTSSuccessCount++;
+ }
+
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_handle_txstatus(dev, status);
+ else
+ b43legacy_dma_handle_txstatus(dev, status);
+}
+
+/* Handle TX status report as received through DMA/PIO queues */
+void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_hwtxstatus *hw)
+{
+ struct b43legacy_txstatus status;
+ u8 tmp;
+
+ status.cookie = le16_to_cpu(hw->cookie);
+ status.seq = le16_to_cpu(hw->seq);
+ status.phy_stat = hw->phy_stat;
+ tmp = hw->count;
+ status.frame_count = (tmp >> 4);
+ status.rts_count = (tmp & 0x0F);
+ tmp = hw->flags;
+ status.supp_reason = ((tmp & 0x1C) >> 2);
+ status.pm_indicated = !!(tmp & 0x80);
+ status.intermediate = !!(tmp & 0x40);
+ status.for_ampdu = !!(tmp & 0x20);
+ status.acked = !!(tmp & 0x02);
+
+ b43legacy_handle_txstatus(dev, &status);
+}
+
+/* Stop any TX operation on the device (suspend the hardware queues) */
+void b43legacy_tx_suspend(struct b43legacy_wldev *dev)
+{
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_freeze_txqueues(dev);
+ else
+ b43legacy_dma_tx_suspend(dev);
+}
+
+/* Resume any TX operation on the device (resume the hardware queues) */
+void b43legacy_tx_resume(struct b43legacy_wldev *dev)
+{
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_thaw_txqueues(dev);
+ else
+ b43legacy_dma_tx_resume(dev);
+}
+
+/* Initialize the QoS parameters */
+void b43legacy_qos_init(struct b43legacy_wldev *dev)
+{
+ /* FIXME: This function must probably be called from the mac80211
+ * config callback. */
+return;
+
+ b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF);
+ /* FIXME kill magic */
+ b43legacy_write16(dev, 0x688,
+ b43legacy_read16(dev, 0x688) | 0x4);
+
+
+ /*TODO: We might need some stack support here to get the values. */
+}
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
new file mode 100644
index 000000000000..8a155d0a5d1f
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -0,0 +1,259 @@
+#ifndef B43legacy_XMIT_H_
+#define B43legacy_XMIT_H_
+
+#include "main.h"
+
+
+#define _b43legacy_declare_plcp_hdr(size) \
+ struct b43legacy_plcp_hdr##size { \
+ union { \
+ __le32 data; \
+ __u8 raw[size]; \
+ } __attribute__((__packed__)); \
+ } __attribute__((__packed__))
+
+/* struct b43legacy_plcp_hdr4 */
+_b43legacy_declare_plcp_hdr(4);
+/* struct b43legacy_plcp_hdr6 */
+_b43legacy_declare_plcp_hdr(6);
+
+#undef _b43legacy_declare_plcp_hdr
+
+
+/* TX header for v3 firmware */
+struct b43legacy_txhdr_fw3 {
+ __le32 mac_ctl; /* MAC TX control */
+ __le16 mac_frame_ctl; /* Copy of the FrameControl */
+ __le16 tx_fes_time_norm; /* TX FES Time Normal */
+ __le16 phy_ctl; /* PHY TX control */
+ __u8 iv[16]; /* Encryption IV */
+ __u8 tx_receiver[6]; /* TX Frame Receiver address */
+ __le16 tx_fes_time_fb; /* TX FES Time Fallback */
+ struct b43legacy_plcp_hdr4 rts_plcp_fb; /* RTS fallback PLCP */
+ __le16 rts_dur_fb; /* RTS fallback duration */
+ struct b43legacy_plcp_hdr4 plcp_fb; /* Fallback PLCP */
+ __le16 dur_fb; /* Fallback duration */
+ PAD_BYTES(2);
+ __le16 cookie;
+ __le16 unknown_scb_stuff;
+ struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */
+ __u8 rts_frame[18]; /* The RTS frame (if used) */
+ struct b43legacy_plcp_hdr6 plcp;
+} __attribute__((__packed__));
+
+/* MAC TX control */
+#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
+#define B43legacy_TX4_MAC_KEYIDX_SHIFT 20
+#define B43legacy_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
+#define B43legacy_TX4_MAC_KEYALG_SHIFT 16
+#define B43legacy_TX4_MAC_LIFETIME 0x00001000
+#define B43legacy_TX4_MAC_FRAMEBURST 0x00000800
+#define B43legacy_TX4_MAC_SENDCTS 0x00000400
+#define B43legacy_TX4_MAC_AMPDU 0x00000300
+#define B43legacy_TX4_MAC_AMPDU_SHIFT 8
+#define B43legacy_TX4_MAC_CTSFALLBACKOFDM 0x00000200
+#define B43legacy_TX4_MAC_FALLBACKOFDM 0x00000100
+#define B43legacy_TX4_MAC_5GHZ 0x00000080
+#define B43legacy_TX4_MAC_IGNPMQ 0x00000020
+#define B43legacy_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Seq No */
+#define B43legacy_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
+#define B43legacy_TX4_MAC_SENDRTS 0x00000004
+#define B43legacy_TX4_MAC_LONGFRAME 0x00000002
+#define B43legacy_TX4_MAC_ACK 0x00000001
+
+/* Extra Frame Types */
+#define B43legacy_TX4_EFT_FBOFDM 0x0001 /* Data frame fb rate type */
+#define B43legacy_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
+#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
+
+/* PHY TX control word */
+#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
+#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
+#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */
+#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
+#define B43legacy_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
+#define B43legacy_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
+
+
+
+void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+ u8 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie);
+
+
+/* Transmit Status */
+struct b43legacy_txstatus {
+ u16 cookie; /* The cookie from the txhdr */
+ u16 seq; /* Sequence number */
+ u8 phy_stat; /* PHY TX status */
+ u8 frame_count; /* Frame transmit count */
+ u8 rts_count; /* RTS transmit count */
+ u8 supp_reason; /* Suppression reason */
+ /* flags */
+ u8 pm_indicated;/* PM mode indicated to AP */
+ u8 intermediate;/* Intermediate status notification */
+ u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
+ u8 acked; /* Wireless ACK received */
+};
+
+/* txstatus supp_reason values */
+enum {
+ B43legacy_TXST_SUPP_NONE, /* Not suppressed */
+ B43legacy_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
+ B43legacy_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
+ B43legacy_TXST_SUPP_PREV, /* Previous fragment failed */
+ B43legacy_TXST_SUPP_CHAN, /* Channel mismatch */
+ B43legacy_TXST_SUPP_LIFE, /* Lifetime expired */
+ B43legacy_TXST_SUPP_UNDER, /* Buffer underflow */
+ B43legacy_TXST_SUPP_ABNACK, /* Afterburner NACK */
+};
+
+/* Transmit Status as received through DMA/PIO on old chips */
+struct b43legacy_hwtxstatus {
+ PAD_BYTES(4);
+ __le16 cookie;
+ u8 flags;
+ u8 count;
+ PAD_BYTES(2);
+ __le16 seq;
+ u8 phy_stat;
+ PAD_BYTES(1);
+} __attribute__((__packed__));
+
+
+/* Receive header for v3 firmware. */
+struct b43legacy_rxhdr_fw3 {
+ __le16 frame_len; /* Frame length */
+ PAD_BYTES(2);
+ __le16 phy_status0; /* PHY RX Status 0 */
+ __u8 jssi; /* PHY RX Status 1: JSSI */
+ __u8 sig_qual; /* PHY RX Status 1: Signal Quality */
+ PAD_BYTES(2); /* PHY RX Status 2 */
+ __le16 phy_status3; /* PHY RX Status 3 */
+ __le16 mac_status; /* MAC RX status */
+ __le16 mac_time;
+ __le16 channel;
+} __attribute__((__packed__));
+
+
+/* PHY RX Status 0 */
+#define B43legacy_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
+#define B43legacy_RX_PHYST0_PLCPHCF 0x0200
+#define B43legacy_RX_PHYST0_PLCPFV 0x0100
+#define B43legacy_RX_PHYST0_SHORTPRMBL 0x0080 /* Recvd with Short Preamble */
+#define B43legacy_RX_PHYST0_LCRS 0x0040
+#define B43legacy_RX_PHYST0_ANT 0x0020 /* Antenna */
+#define B43legacy_RX_PHYST0_UNSRATE 0x0010
+#define B43legacy_RX_PHYST0_CLIP 0x000C
+#define B43legacy_RX_PHYST0_CLIP_SHIFT 2
+#define B43legacy_RX_PHYST0_FTYPE 0x0003 /* Frame type */
+#define B43legacy_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
+#define B43legacy_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
+#define B43legacy_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
+#define B43legacy_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
+
+/* PHY RX Status 2 */
+#define B43legacy_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
+#define B43legacy_RX_PHYST2_LNAG_SHIFT 14
+#define B43legacy_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
+#define B43legacy_RX_PHYST2_PNAG_SHIFT 10
+#define B43legacy_RX_PHYST2_FOFF 0x03FF /* F offset */
+
+/* PHY RX Status 3 */
+#define B43legacy_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
+#define B43legacy_RX_PHYST3_DIGG_SHIFT 11
+#define B43legacy_RX_PHYST3_TRSTATE 0x0400 /* TR state */
+
+/* MAC RX Status */
+#define B43legacy_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
+#define B43legacy_RX_MAC_KEYIDX 0x000007E0 /* Key index */
+#define B43legacy_RX_MAC_KEYIDX_SHIFT 5
+#define B43legacy_RX_MAC_DECERR 0x00000010 /* Decrypt error */
+#define B43legacy_RX_MAC_DEC 0x00000008 /* Decryption attempted */
+#define B43legacy_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
+#define B43legacy_RX_MAC_RESP 0x00000002 /* Response frame xmitted */
+#define B43legacy_RX_MAC_FCSERR 0x00000001 /* FCS error */
+
+/* RX channel */
+#define B43legacy_RX_CHAN_GAIN 0xFC00 /* Gain */
+#define B43legacy_RX_CHAN_GAIN_SHIFT 10
+#define B43legacy_RX_CHAN_ID 0x03FC /* Channel ID */
+#define B43legacy_RX_CHAN_ID_SHIFT 2
+#define B43legacy_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
+
+
+
+u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate);
+u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate);
+
+void b43legacy_rx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ const void *_rxhdr);
+
+void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+
+void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_hwtxstatus *hw);
+
+void b43legacy_tx_suspend(struct b43legacy_wldev *dev);
+void b43legacy_tx_resume(struct b43legacy_wldev *dev);
+
+
+#define B43legacy_NR_QOSPARMS 22
+enum {
+ B43legacy_QOSPARM_TXOP = 0,
+ B43legacy_QOSPARM_CWMIN,
+ B43legacy_QOSPARM_CWMAX,
+ B43legacy_QOSPARM_CWCUR,
+ B43legacy_QOSPARM_AIFS,
+ B43legacy_QOSPARM_BSLOTS,
+ B43legacy_QOSPARM_REGGAP,
+ B43legacy_QOSPARM_STATUS,
+};
+
+void b43legacy_qos_init(struct b43legacy_wldev *dev);
+
+
+/* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+ * We need to account for that here. */
+static inline
+int b43legacy_new_kidx_api(struct b43legacy_wldev *dev)
+{
+ /* FIXME: Not sure the change was at rev 351 */
+ return (dev->fw.rev >= 351);
+}
+static inline
+u8 b43legacy_kidx_to_fw(struct b43legacy_wldev *dev, u8 raw_kidx)
+{
+ u8 firmware_kidx;
+ if (b43legacy_new_kidx_api(dev))
+ firmware_kidx = raw_kidx;
+ else {
+ if (raw_kidx >= 4) /* Is per STA key? */
+ firmware_kidx = raw_kidx - 4;
+ else
+ firmware_kidx = raw_kidx; /* TX default key */
+ }
+ return firmware_kidx;
+}
+static inline
+u8 b43legacy_kidx_to_raw(struct b43legacy_wldev *dev, u8 firmware_kidx)
+{
+ u8 raw_kidx;
+ if (b43legacy_new_kidx_api(dev))
+ raw_kidx = firmware_kidx;
+ else
+ /* RX default keys or per STA keys */
+ raw_kidx = firmware_kidx + 4;
+ return raw_kidx;
+}
+
+#endif /* B43legacy_XMIT_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 10e07e865426..5fdbf24d2443 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -994,10 +994,4 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu
__value; \
})
-/** Helpers to print MAC addresses. */
-#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \
- ((u8*)(x))[2], ((u8*)(x))[3], \
- ((u8*)(x))[4], ((u8*)(x))[5]
-
#endif /* BCM43xx_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index c5d6753a55ea..45683437a98d 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2380,7 +2380,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
goto err_gpio_cleanup;
bcm43xx_radio_turn_on(bcm);
bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
- dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+ printk(KERN_INFO PFX "Radio %s by hardware\n",
(bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3129,7 +3129,7 @@ static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
bcm->radio_hw_enable = radio_hw_enable;
- dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+ printk(KERN_INFO PFX "Radio hardware status changed to %s\n",
(radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_leds_update(bcm, 0);
}
@@ -3183,6 +3183,9 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
unsigned long orig_trans_start = 0;
mutex_lock(&bcm->mutex);
+ /* keep from doing and rearming periodic work if shutting down */
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
+ goto unlock_mutex;
if (unlikely(bcm->periodic_state % 60 == 0)) {
/* Periodic work will take a long time, so we want it to
* be preemtible.
@@ -3228,14 +3231,10 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
mmiowb();
bcm->periodic_state++;
spin_unlock_irqrestore(&bcm->irq_lock, flags);
+unlock_mutex:
mutex_unlock(&bcm->mutex);
}
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
-{
- cancel_rearming_delayed_work(&bcm->periodic_work);
-}
-
void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
{
struct delayed_work *work = &bcm->periodic_work;
@@ -3285,6 +3284,14 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
return err;
}
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm)
+{
+ /* The system must be unlocked when this routine is entered.
+ * If not, the next 2 steps may deadlock */
+ cancel_work_sync(&bcm->restart_work);
+ cancel_delayed_work_sync(&bcm->periodic_work);
+}
+
static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
{
int ret = 0;
@@ -3321,7 +3328,12 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm)
{
bcm43xx_rng_exit(bcm);
bcm43xx_sysfs_unregister(bcm);
- bcm43xx_periodic_tasks_delete(bcm);
+
+ mutex_lock(&(bcm)->mutex);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ mutex_unlock(&(bcm)->mutex);
+
+ bcm43xx_cancel_work(bcm);
mutex_lock(&(bcm)->mutex);
bcm43xx_shutdown_all_wireless_cores(bcm);
@@ -4016,7 +4028,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err);
bcm43xx_free_board(bcm);
- flush_scheduled_work();
+ bcm43xx_cancel_work(bcm);
return 0;
}
@@ -4080,7 +4092,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
goto out;
}
/* initialize the net_device struct */
- SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pdev->dev);
net_dev->open = bcm43xx_net_open;
@@ -4148,9 +4159,9 @@ static void bcm43xx_chip_reset(struct work_struct *work)
struct bcm43xx_phyinfo *phy;
int err = -ENODEV;
+ bcm43xx_cancel_work(bcm);
mutex_lock(&(bcm)->mutex);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
- bcm43xx_periodic_tasks_delete(bcm);
phy = bcm43xx_current_phy(bcm);
err = bcm43xx_select_wireless_core(bcm, phy->type);
if (!err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index c8f3c532bab5..14cfbeb582ef 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -122,7 +122,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm);
void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index d779199c30d0..b37f1e348700 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1638,7 +1638,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
return;
}
- if (phy->analog == 1) {
+ if (phy->analog > 1) {
value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
value |= (baseband_attenuation << 2) & 0x003C;
} else {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 6a109f4a1b71..c605099c9baf 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -2146,7 +2146,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
} else
bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
radio->enabled = 0;
- dprintk(KERN_INFO PFX "Radio turned off\n");
+ dprintk(KERN_INFO PFX "Radio initialized\n");
bcm43xx_leds_update(bcm, 0);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index c71b998a3694..8ab5f93d192a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -327,7 +327,7 @@ static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
goto out;
}
- bcm43xx_periodic_tasks_delete(bcm);
+ bcm43xx_cancel_work(bcm);
mutex_lock(&(bcm)->mutex);
err = bcm43xx_select_wireless_core(bcm, phytype);
if (!err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index d6d9413d7f23..6acfdc49dccd 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -444,7 +444,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
u16 maxpower;
if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
- printk(PFX KERN_ERR "TX power not in dBm.\n");
+ printk(KERN_ERR PFX "TX power not in dBm.\n");
return -EOPNOTSUPP;
}
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index ef37a75d550b..547ba84dc797 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -30,12 +30,11 @@ void hostap_dump_rx_header(const char *name,
const struct hfa384x_rx_frame *rx);
void hostap_dump_tx_header(const char *name,
const struct hfa384x_tx_frame *tx);
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
+extern const struct header_ops hostap_80211_ops;
int hostap_80211_get_hdrlen(u16 fc);
struct net_device_stats *hostap_get_stats(struct net_device *dev);
void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int main_dev);
+ int type);
void hostap_set_multicast_list_queue(struct work_struct *work);
int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index cbedc9ee740a..ef084df3d48e 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -19,6 +19,7 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
u16 fc;
+ DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -44,10 +45,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
le16_to_cpu(hdr->seq_ctl));
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
- MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+ printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1));
+ printk(" A2=%s", print_mac(mac, hdr->addr2));
+ printk(" A3=%s", print_mac(mac, hdr->addr3));
if (skb->len >= 30)
- printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+ printk(" A4=%s", print_mac(mac, hdr->addr4));
printk("\n");
}
@@ -534,6 +536,7 @@ static int
hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
u16 fc, struct net_device **wds)
{
+ DECLARE_MAC_BUF(mac);
/* FIX: is this really supposed to accept WDS frames only in Master
* mode? What about Repeater or Managed with WDS frames? */
if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
@@ -549,10 +552,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
/* RA (or BSSID) is not ours - drop */
PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
- "not own or broadcast %s=" MACSTR "\n",
+ "not own or broadcast %s=%s\n",
local->dev->name,
fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
- MAC2STR(hdr->addr1));
+ print_mac(mac, hdr->addr1));
return -1;
}
@@ -565,8 +568,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
/* require that WDS link has been registered with TA or the
* frame is from current AP when using 'AP client mode' */
PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
- "from unknown TA=" MACSTR "\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ "from unknown TA=%s\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
if (local->ap && local->ap->autom_ap_wds)
hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
return -1;
@@ -632,6 +635,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
+ DECLARE_MAC_BUF(mac);
if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
return 0;
@@ -643,8 +647,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MACSTR "\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ "received packet from %s\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
}
return -1;
}
@@ -653,9 +657,9 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
atomic_dec(&crypt->refcnt);
if (res < 0) {
- printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR
+ printk(KERN_DEBUG "%s: decryption failed (SA=%s"
") res=%d\n",
- local->dev->name, MAC2STR(hdr->addr2), res);
+ local->dev->name, print_mac(mac, hdr->addr2), res);
local->comm_tallies.rx_discards_wep_undecryptable++;
return -1;
}
@@ -671,6 +675,7 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
+ DECLARE_MAC_BUF(mac);
if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
return 0;
@@ -683,8 +688,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=" MACSTR " keyidx=%d)\n",
- local->dev->name, MAC2STR(hdr->addr2), keyidx);
+ " (SA=%s keyidx=%d)\n",
+ local->dev->name, print_mac(mac, hdr->addr2), keyidx);
return -1;
}
@@ -716,6 +721,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_crypt_data *crypt = NULL;
void *sta = NULL;
int keyidx = 0;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -792,8 +798,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
- " (SA=" MACSTR ")\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ " (SA=%s)\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
#endif
local->comm_tallies.rx_discards_wep_undecryptable++;
goto rx_dropped;
@@ -807,8 +813,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
(keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
{
printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from " MACSTR "\n", dev->name,
- MAC2STR(hdr->addr2));
+ "from %s\n", dev->name,
+ print_mac(mac, hdr->addr2));
/* TODO: could inform hostapd about this so that it
* could send auth failure report */
goto rx_dropped;
@@ -976,8 +982,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
"unencrypted EAPOL frame\n", local->dev->name);
} else {
printk(KERN_DEBUG "%s: encryption configured, but RX "
- "frame not encrypted (SA=" MACSTR ")\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ "frame not encrypted (SA=%s)\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
goto rx_dropped;
}
}
@@ -986,8 +992,9 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
!hostap_is_eapol_frame(local, skb)) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: dropped unencrypted RX data "
- "frame from " MACSTR " (drop_unencrypted=1)\n",
- dev->name, MAC2STR(hdr->addr2));
+ "frame from %s"
+ " (drop_unencrypted=1)\n",
+ dev->name, print_mac(mac, hdr->addr2));
}
goto rx_dropped;
}
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 3df3c60263d4..e7afc3ec3e6d 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -17,6 +17,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
{
struct ieee80211_hdr_4addr *hdr;
u16 fc;
+ DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -40,10 +41,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
le16_to_cpu(hdr->seq_ctl));
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
- MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+ printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1));
+ printk(" A2=%s", print_mac(mac, hdr->addr2));
+ printk(" A3=%s", print_mac(mac, hdr->addr3));
if (skb->len >= 30)
- printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+ printk(" A4=%s", print_mac(mac, hdr->addr4));
printk("\n");
}
@@ -312,6 +314,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
struct ieee80211_hdr_4addr *hdr;
u16 fc;
int prefix_len, postfix_len, hdr_len, res;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(skb->dev);
local = iface->local;
@@ -326,8 +329,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MACSTR "\n",
- local->dev->name, MAC2STR(hdr->addr1));
+ "TX packet to %s\n",
+ local->dev->name, print_mac(mac, hdr->addr1));
}
kfree_skb(skb);
return NULL;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 90900525379c..6bbdb76b32df 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -94,6 +94,7 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
{
struct sta_info *s;
+ DECLARE_MAC_BUF(mac);
s = ap->sta_hash[STA_HASH(sta->addr)];
if (s == NULL) return;
@@ -108,18 +109,20 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
- printk("AP: could not remove STA " MACSTR " from hash table\n",
- MAC2STR(sta->addr));
+ printk("AP: could not remove STA %s"
+ " from hash table\n",
+ print_mac(mac, sta->addr));
}
static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
{
+ DECLARE_MAC_BUF(mac);
if (sta->ap && sta->local)
hostap_event_expired_sta(sta->local->dev, sta);
if (ap->proc != NULL) {
char name[20];
- sprintf(name, MACSTR, MAC2STR(sta->addr));
+ sprintf(name, "%s", print_mac(mac, sta->addr));
remove_proc_entry(name, ap->proc);
}
@@ -182,6 +185,7 @@ static void ap_handle_timer(unsigned long data)
struct ap_data *ap;
unsigned long next_time = 0;
int was_assoc;
+ DECLARE_MAC_BUF(mac);
if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
@@ -238,8 +242,8 @@ static void ap_handle_timer(unsigned long data)
if (sta->ap) {
if (ap->autom_ap_wds) {
PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
- "connection to AP " MACSTR "\n",
- local->dev->name, MAC2STR(sta->addr));
+ "connection to AP %s\n",
+ local->dev->name, print_mac(mac, sta->addr));
hostap_wds_link_oper(local, sta->addr, WDS_DEL);
}
} else if (sta->timeout_next == STA_NULLFUNC) {
@@ -255,11 +259,11 @@ static void ap_handle_timer(unsigned long data)
} else {
int deauth = sta->timeout_next == STA_DEAUTH;
u16 resp;
- PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR
+ PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
"(last=%lu, jiffies=%lu)\n",
local->dev->name,
deauth ? "deauthentication" : "disassociation",
- MAC2STR(sta->addr), sta->last_rx, jiffies);
+ print_mac(mac, sta->addr), sta->last_rx, jiffies);
resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
@@ -271,9 +275,10 @@ static void ap_handle_timer(unsigned long data)
if (sta->timeout_next == STA_DEAUTH) {
if (sta->flags & WLAN_STA_PERM) {
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been "
- "removed, but it has 'perm' flag\n",
- local->dev->name, MAC2STR(sta->addr));
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " would have been removed, "
+ "but it has 'perm' flag\n",
+ local->dev->name, print_mac(mac, sta->addr));
} else
ap_free_sta(ap, sta);
return;
@@ -327,6 +332,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
struct ap_data *ap = (struct ap_data *) data;
char *policy_txt;
struct mac_entry *entry;
+ DECLARE_MAC_BUF(mac);
if (off != 0) {
*eof = 1;
@@ -357,7 +363,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
break;
}
- p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
+ p += sprintf(p, "%s\n", print_mac(mac, entry->addr));
}
spin_unlock_bh(&ap->mac_restrictions.lock);
@@ -514,6 +520,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
struct ap_data *ap = (struct ap_data *) data;
struct sta_info *sta;
int i;
+ DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -526,7 +533,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
if (!sta->ap)
continue;
- p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr),
+ p += sprintf(p, "%s %d %d %d %d '",
+ print_mac(mac, sta->addr),
sta->u.ap.channel, sta->last_rx_signal,
sta->last_rx_silence, sta->last_rx_rate);
for (i = 0; i < sta->u.ap.ssid_len; i++)
@@ -623,6 +631,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
u16 fc, *pos, auth_alg, auth_transaction, status;
struct sta_info *sta = NULL;
char *txt = NULL;
+ DECLARE_MAC_BUF(mac);
if (ap->local->hostapd) {
dev_kfree_skb(skb);
@@ -674,9 +683,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
if (sta)
atomic_dec(&sta->users);
if (txt) {
- PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d "
- "status=%d - %s\n",
- dev->name, MAC2STR(hdr->addr1), auth_alg,
+ PDEBUG(DEBUG_AP, "%s: %s auth_cb - alg=%d "
+ "trans#=%d status=%d - %s\n",
+ dev->name, print_mac(mac, hdr->addr1), auth_alg,
auth_transaction, status, txt);
}
dev_kfree_skb(skb);
@@ -692,6 +701,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
u16 fc, *pos, status;
struct sta_info *sta = NULL;
char *txt = NULL;
+ DECLARE_MAC_BUF(mac);
if (ap->local->hostapd) {
dev_kfree_skb(skb);
@@ -742,8 +752,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
if (sta)
atomic_dec(&sta->users);
if (txt) {
- PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n",
- dev->name, MAC2STR(hdr->addr1), txt);
+ PDEBUG(DEBUG_AP, "%s: %s assoc_cb - %s\n",
+ dev->name, print_mac(mac, hdr->addr1), txt);
}
dev_kfree_skb(skb);
}
@@ -755,6 +765,7 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
struct ap_data *ap = data;
struct ieee80211_hdr_4addr *hdr;
struct sta_info *sta;
+ DECLARE_MAC_BUF(mac);
if (skb->len < 24)
goto fail;
@@ -766,9 +777,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
sta->flags &= ~WLAN_STA_PENDING_POLL;
spin_unlock(&ap->sta_table_lock);
} else {
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity "
- "poll frame\n", ap->local->dev->name,
- MAC2STR(hdr->addr1));
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " did not ACK activity poll frame\n",
+ ap->local->dev->name, print_mac(mac, hdr->addr1));
}
fail:
@@ -985,6 +996,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
char *p = page;
struct sta_info *sta = (struct sta_info *) data;
int i;
+ DECLARE_MAC_BUF(mac);
/* FIX: possible race condition.. the STA data could have just expired,
* but proc entry was still here so that the read could have started;
@@ -995,11 +1007,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
return 0;
}
- p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n"
+ p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n"
"flags=0x%04x%s%s%s%s%s%s%s\n"
"capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
sta->ap ? "AP" : "STA",
- MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid,
+ print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid,
sta->flags,
sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
@@ -1060,6 +1072,7 @@ static void handle_add_proc_queue(struct work_struct *work)
struct sta_info *sta;
char name[20];
struct add_sta_proc_data *entry, *prev;
+ DECLARE_MAC_BUF(mac);
entry = ap->add_sta_proc_entries;
ap->add_sta_proc_entries = NULL;
@@ -1072,7 +1085,7 @@ static void handle_add_proc_queue(struct work_struct *work)
spin_unlock_bh(&ap->sta_table_lock);
if (sta) {
- sprintf(name, MACSTR, MAC2STR(sta->addr));
+ sprintf(name, "%s", print_mac(mac, sta->addr));
sta->proc = create_proc_read_entry(
name, 0, ap->proc,
prism2_sta_proc_read, sta);
@@ -1290,6 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
struct sta_info *sta = NULL;
struct ieee80211_crypt_data *crypt;
char *txt = "";
+ DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1298,8 +1312,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
if (len < 6) {
PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
- "(len=%d) from " MACSTR "\n", dev->name, len,
- MAC2STR(hdr->addr2));
+ "(len=%d) from %s\n", dev->name, len,
+ print_mac(mac, hdr->addr2));
return;
}
@@ -1364,8 +1378,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
if (time_after(jiffies, sta->u.ap.last_beacon +
(10 * sta->listen_interval * HZ) / 1024)) {
PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
- " assuming AP " MACSTR " is now STA\n",
- dev->name, MAC2STR(sta->addr));
+ " assuming AP %s is now STA\n",
+ dev->name, print_mac(mac, sta->addr));
sta->ap = 0;
sta->flags = 0;
sta->u.sta.challenge = NULL;
@@ -1480,9 +1494,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
}
if (resp) {
- PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d "
- "stat=%d len=%d fc=%04x) ==> %d (%s)\n",
- dev->name, MAC2STR(hdr->addr2), auth_alg,
+ PDEBUG(DEBUG_AP, "%s: %s auth (alg=%d "
+ "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
+ dev->name, print_mac(mac, hdr->addr2), auth_alg,
auth_transaction, status_code, len, fc, resp, txt);
}
}
@@ -1502,13 +1516,14 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
int send_deauth = 0;
char *txt = "";
u8 prev_ap[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
if (len < (reassoc ? 10 : 4)) {
PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
- "(len=%d, reassoc=%d) from " MACSTR "\n",
- dev->name, len, reassoc, MAC2STR(hdr->addr2));
+ "(len=%d, reassoc=%d) from %s\n",
+ dev->name, len, reassoc, print_mac(mac, hdr->addr2));
return;
}
@@ -1585,9 +1600,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
}
if (left > 0) {
- PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra"
- " data (%d bytes) [",
- dev->name, MAC2STR(hdr->addr2), left);
+ PDEBUG(DEBUG_AP, "%s: assoc from %s"
+ " with extra data (%d bytes) [",
+ dev->name, print_mac(mac, hdr->addr2), left);
while (left > 0) {
PDEBUG2(DEBUG_AP, "<%02x>", *u);
u++; left--;
@@ -1687,10 +1702,10 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
}
#if 0
- PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR
- ") => %d(%d) (%s)\n",
- dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len,
- MAC2STR(prev_ap), resp, send_deauth, txt);
+ PDEBUG(DEBUG_AP, "%s: %s %sassoc (len=%d "
+ "prev_ap=%s) => %d(%d) (%s)\n",
+ dev->name, print_mac(mac, hdr->addr2), reassoc ? "re" : "", len,
+ print_mac(mac, prev_ap), resp, send_deauth, txt);
#endif
}
@@ -1705,6 +1720,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
int len;
u16 reason_code, *pos;
struct sta_info *sta = NULL;
+ DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1716,8 +1732,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
pos = (u16 *) body;
reason_code = __le16_to_cpu(*pos);
- PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, "
- "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+ PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, "
+ "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
reason_code);
spin_lock_bh(&local->ap->sta_table_lock);
@@ -1729,9 +1745,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
}
spin_unlock_bh(&local->ap->sta_table_lock);
if (sta == NULL) {
- printk("%s: deauthentication from " MACSTR ", "
+ printk("%s: deauthentication from %s, "
"reason_code=%d, but STA not authenticated\n", dev->name,
- MAC2STR(hdr->addr2), reason_code);
+ print_mac(mac, hdr->addr2), reason_code);
}
}
@@ -1746,6 +1762,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
int len;
u16 reason_code, *pos;
struct sta_info *sta = NULL;
+ DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1757,8 +1774,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
pos = (u16 *) body;
reason_code = __le16_to_cpu(*pos);
- PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, "
- "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+ PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, "
+ "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
reason_code);
spin_lock_bh(&local->ap->sta_table_lock);
@@ -1770,9 +1787,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
}
spin_unlock_bh(&local->ap->sta_table_lock);
if (sta == NULL) {
- printk("%s: disassociation from " MACSTR ", "
+ printk("%s: disassociation from %s, "
"reason_code=%d, but STA not authenticated\n",
- dev->name, MAC2STR(hdr->addr2), reason_code);
+ dev->name, print_mac(mac, hdr->addr2), reason_code);
}
}
@@ -1862,15 +1879,16 @@ static void handle_pspoll(local_info_t *local,
struct sta_info *sta;
u16 aid;
struct sk_buff *skb;
+ DECLARE_MAC_BUF(mac);
- PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR
- " PWRMGT=%d\n",
- MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+ PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%s"
+ ", TA=%s PWRMGT=%d\n",
+ print_mac(mac, hdr->addr1), print_mac(mac, hdr->addr2),
!!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR
- " not own MAC\n", MAC2STR(hdr->addr1));
+ PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=%s"
+ " not own MAC\n", print_mac(mac, hdr->addr1));
return;
}
@@ -1948,6 +1966,7 @@ static void handle_wds_oper_queue(struct work_struct *work)
wds_oper_queue);
local_info_t *local = ap->local;
struct wds_oper_data *entry, *prev;
+ DECLARE_MAC_BUF(mac);
spin_lock_bh(&local->lock);
entry = local->ap->wds_oper_entries;
@@ -1956,10 +1975,10 @@ static void handle_wds_oper_queue(struct work_struct *work)
while (entry) {
PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
- "to AP " MACSTR "\n",
+ "to AP %s\n",
local->dev->name,
entry->type == WDS_ADD ? "adding" : "removing",
- MAC2STR(entry->addr));
+ print_mac(mac, entry->addr));
if (entry->type == WDS_ADD)
prism2_wds_add(local, entry->addr, 0);
else if (entry->type == WDS_DEL)
@@ -2135,6 +2154,7 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
u16 fc, type, stype;
struct ieee80211_hdr_4addr *hdr;
+ DECLARE_MAC_BUF(mac);
/* FIX: should give skb->len to handler functions and check that the
* buffer is long enough */
@@ -2163,8 +2183,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
- MACSTR " not own MAC\n",
- MAC2STR(hdr->addr1));
+ "%s not own MAC\n",
+ print_mac(mac, hdr->addr1));
goto done;
}
@@ -2200,14 +2220,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
}
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR
- " not own MAC\n", MAC2STR(hdr->addr1));
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%s"
+ " not own MAC\n", print_mac(mac, hdr->addr1));
goto done;
}
if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR
- " not own MAC\n", MAC2STR(hdr->addr3));
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%s"
+ " not own MAC\n", print_mac(mac, hdr->addr3));
goto done;
}
@@ -2288,6 +2308,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
struct sk_buff *skb;
struct ieee80211_hdr_4addr *hdr;
struct hostap_80211_rx_status rx_stats;
+ DECLARE_MAC_BUF(mac);
if (skb_queue_empty(&sta->tx_buf))
return;
@@ -2308,8 +2329,8 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
memcpy(hdr->addr2, sta->addr, ETH_ALEN);
hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
- PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for "
- "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr));
+ PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA "
+ "%s\n", local->dev->name, print_mac(mac, sta->addr));
skb->dev = local->dev;
@@ -2636,6 +2657,7 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
int ret = sta->tx_rate;
struct hostap_interface *iface;
local_info_t *local;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -2663,9 +2685,9 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
case 3: sta->tx_rate = 110; break;
default: sta->tx_rate = 0; break;
}
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to"
- " %d\n", dev->name, MAC2STR(sta->addr),
- sta->tx_rate);
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " TX rate raised to %d\n",
+ dev->name, print_mac(mac, sta->addr), sta->tx_rate);
}
sta->tx_since_last_failure = 0;
}
@@ -2683,6 +2705,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
int set_tim, ret;
struct ieee80211_hdr_4addr *hdr;
struct hostap_skb_tx_data *meta;
+ DECLARE_MAC_BUF(mac);
meta = (struct hostap_skb_tx_data *) skb->cb;
ret = AP_TX_CONTINUE;
@@ -2718,7 +2741,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
* print out any errors here. */
if (net_ratelimit()) {
printk(KERN_DEBUG "AP: drop packet to non-associated "
- "STA " MACSTR "\n", MAC2STR(hdr->addr1));
+ "STA %s\n",
+ print_mac(mac, hdr->addr1));
}
#endif
local->ap->tx_drop_nonassoc++;
@@ -2756,8 +2780,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
}
if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
- PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS "
- "mode buffer\n", local->dev->name, MAC2STR(sta->addr));
+ PDEBUG(DEBUG_PS, "%s: No more space in STA (%s"
+ ")'s PS mode buffer\n",
+ local->dev->name, print_mac(mac, sta->addr));
/* Make sure that TIM is set for the station (it might not be
* after AP wlan hw reset). */
/* FIX: should fix hw reset to restore bits based on STA
@@ -2821,6 +2846,7 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
struct sta_info *sta;
struct ieee80211_hdr_4addr *hdr;
struct hostap_skb_tx_data *meta;
+ DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -2829,9 +2855,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
sta = ap_get_sta(local->ap, hdr->addr1);
if (!sta) {
spin_unlock(&local->ap->sta_table_lock);
- PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this "
- "TX error (@%lu)\n",
- local->dev->name, MAC2STR(hdr->addr1), jiffies);
+ PDEBUG(DEBUG_AP, "%s: Could not find STA %s"
+ " for this TX error (@%lu)\n",
+ local->dev->name, print_mac(mac, hdr->addr1), jiffies);
return;
}
@@ -2858,8 +2884,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
case 3: sta->tx_rate = 110; break;
default: sta->tx_rate = 0; break;
}
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered "
- "to %d\n", local->dev->name, MAC2STR(sta->addr),
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " TX rate lowered to %d\n",
+ local->dev->name, print_mac(mac, sta->addr),
sta->tx_rate);
}
sta->tx_consecutive_exc = 0;
@@ -2871,16 +2898,17 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
int pwrmgt, int type, int stype)
{
+ DECLARE_MAC_BUF(mac);
if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
sta->flags |= WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS "
+ PDEBUG(DEBUG_PS2, "STA %s changed to use PS "
"mode (type=0x%02X, stype=0x%02X)\n",
- MAC2STR(sta->addr), type >> 2, stype >> 4);
+ print_mac(mac, sta->addr), type >> 2, stype >> 4);
} else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
sta->flags &= ~WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use "
+ PDEBUG(DEBUG_PS2, "STA %s changed to not use "
"PS mode (type=0x%02X, stype=0x%02X)\n",
- MAC2STR(sta->addr), type >> 2, stype >> 4);
+ print_mac(mac, sta->addr), type >> 2, stype >> 4);
if (type != IEEE80211_FTYPE_CTL ||
stype != IEEE80211_STYPE_PSPOLL)
schedule_packet_send(local, sta);
@@ -2924,6 +2952,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
struct sta_info *sta;
u16 fc, type, stype;
struct ieee80211_hdr_4addr *hdr;
+ DECLARE_MAC_BUF(mac);
if (local->ap == NULL)
return AP_RX_CONTINUE;
@@ -2954,9 +2983,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
} else {
printk(KERN_DEBUG "%s: dropped received packet"
- " from non-associated STA " MACSTR
+ " from non-associated STA "
+ "%s"
" (type=0x%02x, subtype=0x%02x)\n",
- dev->name, MAC2STR(hdr->addr2),
+ dev->name, print_mac(mac, hdr->addr2),
type >> 2, stype >> 4);
hostap_rx(dev, skb, rx_stats);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -2991,8 +3021,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
* being associated. */
printk(KERN_DEBUG "%s: rejected received nullfunc "
"frame without ToDS from not associated STA "
- MACSTR "\n",
- dev->name, MAC2STR(hdr->addr2));
+ "%s\n",
+ dev->name, print_mac(mac, hdr->addr2));
hostap_rx(dev, skb, rx_stats);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
}
@@ -3009,9 +3039,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
* If BSSID is own, report the dropping of this frame. */
if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
printk(KERN_DEBUG "%s: dropped received packet from "
- MACSTR " with no ToDS flag (type=0x%02x, "
- "subtype=0x%02x)\n", dev->name,
- MAC2STR(hdr->addr2), type >> 2, stype >> 4);
+ "%s with no ToDS flag "
+ "(type=0x%02x, subtype=0x%02x)\n", dev->name,
+ print_mac(mac, hdr->addr2), type >> 2, stype >> 4);
hostap_dump_rx_80211(dev->name, skb, rx_stats);
}
ret = AP_RX_DROP;
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index b31e6a05f23c..ceb7f1e5e9e0 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -6,9 +6,6 @@
#define BIT(x) (1 << (x))
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
/* IEEE 802.11 defines */
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 30e723f65979..877d3bdd37a0 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -272,7 +272,7 @@ static int sandisk_enable_wireless(struct net_device *dev)
{
int res, ret = 0;
conf_reg_t reg;
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
tuple_t tuple;
cisparse_t *parse = NULL;
@@ -822,6 +822,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
@@ -889,6 +890,10 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID123(
"corega", "WL PCCL-11", "ISL37300P",
0xa21501a, 0x59868926, 0xc9049a39),
+ PCMCIA_DEVICE_PROD_ID1234(
+ "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
+ "RevA",
+ 0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 959887b70ca7..c592641e914e 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -825,7 +825,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
local->hw_downloading)
return -ENODEV;
- res = down_interruptible(&local->rid_bap_sem);
+ res = mutex_lock_interruptible(&local->rid_bap_mtx);
if (res)
return res;
@@ -834,7 +834,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
"(res=%d, rid=%04x, len=%d)\n",
dev->name, res, rid, len);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
return res;
}
@@ -861,7 +861,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
res = hfa384x_from_bap(dev, BAP0, buf, len);
spin_unlock_bh(&local->baplock);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
if (res) {
if (res != -ENODATA)
@@ -902,7 +902,7 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
/* RID len in words and +1 for rec.rid */
rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
- res = down_interruptible(&local->rid_bap_sem);
+ res = mutex_lock_interruptible(&local->rid_bap_mtx);
if (res)
return res;
@@ -917,12 +917,12 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
if (res) {
printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
"failed - res=%d\n", dev->name, rid, len, res);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
return res;
}
res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
if (res) {
printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
@@ -2335,6 +2335,10 @@ static void prism2_txexc(local_info_t *local)
int show_dump, res;
char *payload = NULL;
struct hfa384x_tx_frame txdesc;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
local->stats.tx_errors++;
@@ -2400,10 +2404,9 @@ static void prism2_txexc(local_info_t *local)
WLAN_FC_GET_STYPE(fc) >> 4,
fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
- PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3="
- MACSTR " A4=" MACSTR "\n",
- MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2),
- MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4));
+ PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n",
+ print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2),
+ print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4));
}
@@ -3171,7 +3174,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
spin_lock_init(&local->cmdlock);
spin_lock_init(&local->baplock);
spin_lock_init(&local->lock);
- init_MUTEX(&local->rid_bap_sem);
+ mutex_init(&local->rid_bap_mtx);
if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
card_idx = 0;
@@ -3254,12 +3257,11 @@ while (0)
INIT_LIST_HEAD(&local->bss_list);
- hostap_setup_dev(dev, local, 1);
- local->saved_eth_header_parse = dev->hard_header_parse;
+ hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER);
dev->hard_start_xmit = hostap_master_start_xmit;
dev->type = ARPHRD_IEEE80211;
- dev->hard_header_parse = hostap_80211_header_parse;
+ dev->header_ops = &hostap_80211_ops;
rtnl_lock();
ret = dev_alloc_name(dev, "wifi%d");
@@ -3424,7 +3426,7 @@ static void prism2_suspend(struct net_device *dev)
struct local_info *local;
union iwreq_data wrqu;
- iface = dev->priv;
+ iface = netdev_priv(dev);
local = iface->local;
/* Send disconnect event, e.g., to trigger reassociation after resume
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index b6a02a02da74..636f4b2382ea 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -166,6 +166,7 @@ static void prism2_host_roaming(local_info_t *local)
struct hfa384x_hostscan_result *selected, *entry;
int i;
unsigned long flags;
+ DECLARE_MAC_BUF(mac);
if (local->last_join_time &&
time_before(jiffies, local->last_join_time + 10 * HZ)) {
@@ -198,8 +199,9 @@ static void prism2_host_roaming(local_info_t *local)
local->preferred_ap[2] || local->preferred_ap[3] ||
local->preferred_ap[4] || local->preferred_ap[5]) {
/* Try to find preferred AP */
- PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n",
- dev->name, MAC2STR(local->preferred_ap));
+ PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID "
+ "%s\n",
+ dev->name, print_mac(mac, local->preferred_ap));
for (i = 0; i < local->last_scan_results_count; i++) {
entry = &local->last_scan_results[i];
if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
@@ -216,8 +218,9 @@ static void prism2_host_roaming(local_info_t *local)
req.channel = selected->chid;
spin_unlock_irqrestore(&local->lock, flags);
- PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n",
- dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel));
+ PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s"
+ " channel=%d\n",
+ dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel));
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
sizeof(req))) {
printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
@@ -409,6 +412,7 @@ static void handle_info_queue_linkstatus(local_info_t *local)
int val = local->prev_link_status;
int connected;
union iwreq_data wrqu;
+ DECLARE_MAC_BUF(mac);
connected =
val == HFA384X_LINKSTATUS_CONNECTED ||
@@ -420,9 +424,10 @@ static void handle_info_queue_linkstatus(local_info_t *local)
printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
"LinkStatus event\n", local->dev->name);
} else {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n",
+ PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID="
+ "%s\n",
local->dev->name,
- MAC2STR((unsigned char *) local->bssid));
+ print_mac(mac, (unsigned char *) local->bssid));
if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
hostap_add_sta(local->ap, local->bssid);
}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 8c71077d653c..40f516d42c5e 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -664,6 +664,7 @@ static int hostap_join_ap(struct net_device *dev)
unsigned long flags;
int i;
struct hfa384x_hostscan_result *entry;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -685,14 +686,14 @@ static int hostap_join_ap(struct net_device *dev)
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest " MACSTR
+ printk(KERN_DEBUG "%s: JoinRequest %s"
" failed\n",
- dev->name, MAC2STR(local->preferred_ap));
+ dev->name, print_mac(mac, local->preferred_ap));
return -1;
}
- printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n",
- dev->name, MAC2STR(local->preferred_ap));
+ printk(KERN_DEBUG "%s: Trying to join BSSID %s\n",
+ dev->name, print_mac(mac, local->preferred_ap));
return 0;
}
@@ -896,11 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local)
if (local->monitor_type == PRISM2_MONITOR_PRISM ||
local->monitor_type == PRISM2_MONITOR_CAPHDR) {
dev->type = ARPHRD_IEEE80211_PRISM;
- dev->hard_header_parse =
- hostap_80211_prism_header_parse;
} else {
dev->type = ARPHRD_IEEE80211;
- dev->hard_header_parse = hostap_80211_header_parse;
}
}
@@ -1140,7 +1138,7 @@ static int hostap_monitor_mode_disable(local_info_t *local)
printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
dev->type = ARPHRD_ETHER;
- dev->hard_header_parse = local->saved_eth_header_parse;
+
if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
(HFA384X_TEST_STOP << 8),
0, NULL, NULL))
@@ -3088,7 +3086,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
size_t len)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
u8 *buf;
@@ -3116,7 +3114,7 @@ static int prism2_ioctl_siwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
switch (data->flags & IW_AUTH_INDEX) {
@@ -3182,7 +3180,7 @@ static int prism2_ioctl_giwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
switch (data->flags & IW_AUTH_INDEX) {
@@ -3221,7 +3219,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
int i, ret = 0;
@@ -3395,7 +3393,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct ieee80211_crypt_data **crypt;
void *sta_ptr;
@@ -3697,8 +3695,10 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
struct prism2_hostapd_param *param,
int param_len)
{
- printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n",
- local->dev->name, MAC2STR(param->sta_addr));
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_DEBUG "%ssta: associated as client with AP "
+ "%s\n",
+ local->dev->name, print_mac(mac, param->sta_addr));
memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
return 0;
}
@@ -3716,7 +3716,7 @@ static int prism2_ioctl_giwgenie(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
int len = local->generic_elem_len - 2;
@@ -3755,7 +3755,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct iw_mlme *mlme = (struct iw_mlme *) extra;
u16 reason;
@@ -3976,9 +3976,9 @@ static const iw_handler prism2_private_handler[] =
const struct iw_handler_def hostap_iw_handler_def =
{
- .num_standard = sizeof(prism2_handler) / sizeof(iw_handler),
- .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler),
- .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(prism2_handler),
+ .num_private = ARRAY_SIZE(prism2_private_handler),
+ .num_private_args = ARRAY_SIZE(prism2_priv),
.standard = (iw_handler *) prism2_handler,
.private = (iw_handler *) prism2_private_handler,
.private_args = (struct iw_priv_args *) prism2_priv,
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 446de51bab74..17c58e9bdad5 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -24,6 +24,7 @@
#include <linux/rtnetlink.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
+#include <net/net_namespace.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
#include <net/ieee80211_crypt.h>
@@ -72,7 +73,7 @@ struct net_device * hostap_add_interface(struct local_info *local,
dev->mem_start = mdev->mem_start;
dev->mem_end = mdev->mem_end;
- hostap_setup_dev(dev, local, 0);
+ hostap_setup_dev(dev, local, type);
dev->destructor = free_netdev;
sprintf(dev->name, "%s%s", prefix, name);
@@ -529,6 +530,10 @@ int hostap_set_auth_algs(local_info_t *local)
void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
{
u16 status, fc;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
status = __le16_to_cpu(rx->status);
@@ -547,13 +552,12 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
- MACSTR "\n",
- MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3),
- MAC2STR(rx->addr4));
+ printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n",
+ print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2),
+ print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4));
- printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n",
- MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr),
+ printk(KERN_DEBUG " dst=%s src=%s len=%d\n",
+ print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr),
__be16_to_cpu(rx->len));
}
@@ -561,6 +565,10 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
{
u16 fc;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
"tx_control=0x%04x; jiffies=%ld\n",
@@ -576,35 +584,37 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
- MACSTR "\n",
- MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3),
- MAC2STR(tx->addr4));
+ printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n",
+ print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2),
+ print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4));
- printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n",
- MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr),
+ printk(KERN_DEBUG " dst=%s src=%s len=%d\n",
+ print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr),
__be16_to_cpu(tx->len));
}
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
+int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
-
+ struct hostap_interface *iface = netdev_priv(skb->dev);
+ local_info_t *local = iface->local;
+
+ if (local->monitor_type == PRISM2_MONITOR_PRISM ||
+ local->monitor_type == PRISM2_MONITOR_CAPHDR) {
+ const unsigned char *mac = skb_mac_header(skb);
+
+ if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
+ memcpy(haddr,
+ mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+ ETH_ALEN); /* addr2 */
+ } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
+ memcpy(haddr,
+ mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+ ETH_ALEN); /* addr2 */
+ }
+ } else
+ memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
-{
- const unsigned char *mac = skb_mac_header(skb);
-
- if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
- memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
- ETH_ALEN); /* addr2 */
- } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
- memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
- ETH_ALEN); /* addr2 */
- }
return ETH_ALEN;
}
@@ -836,9 +846,18 @@ static void prism2_tx_timeout(struct net_device *dev)
local->func->schedule_reset(local);
}
+const struct header_ops hostap_80211_ops = {
+ .create = eth_header,
+ .rebuild = eth_rebuild_header,
+ .cache = eth_header_cache,
+ .cache_update = eth_header_cache_update,
+
+ .parse = hostap_80211_header_parse,
+};
+EXPORT_SYMBOL(hostap_80211_ops);
void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int main_dev)
+ int type)
{
struct hostap_interface *iface;
@@ -858,15 +877,22 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
dev->do_ioctl = hostap_ioctl;
dev->open = prism2_open;
dev->stop = prism2_close;
- dev->hard_start_xmit = hostap_data_start_xmit;
dev->set_mac_address = prism2_set_mac_address;
dev->set_multicast_list = hostap_set_multicast_list;
dev->change_mtu = prism2_change_mtu;
dev->tx_timeout = prism2_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ if (type == HOSTAP_INTERFACE_AP) {
+ dev->hard_start_xmit = hostap_mgmt_start_xmit;
+ dev->type = ARPHRD_IEEE80211;
+ dev->header_ops = &hostap_80211_ops;
+ } else {
+ dev->hard_start_xmit = hostap_data_start_xmit;
+ }
+
dev->mtu = local->mtu;
- if (!main_dev) {
+ if (type != HOSTAP_INTERFACE_MASTER) {
/* use main radio device queue */
dev->tx_queue_len = 0;
}
@@ -876,7 +902,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
netif_stop_queue(dev);
}
-
static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
{
struct net_device *dev = local->dev;
@@ -892,10 +917,6 @@ static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
if (local->apdev == NULL)
return -ENOMEM;
- local->apdev->hard_start_xmit = hostap_mgmt_start_xmit;
- local->apdev->type = ARPHRD_IEEE80211;
- local->apdev->hard_header_parse = hostap_80211_header_parse;
-
return 0;
}
@@ -1093,8 +1114,8 @@ struct proc_dir_entry *hostap_proc;
static int __init hostap_init(void)
{
- if (proc_net != NULL) {
- hostap_proc = proc_mkdir("hostap", proc_net);
+ if (init_net.proc_net != NULL) {
+ hostap_proc = proc_mkdir("hostap", init_net.proc_net);
if (!hostap_proc)
printk(KERN_WARNING "Failed to mkdir "
"/proc/net/hostap\n");
@@ -1109,7 +1130,7 @@ static void __exit hostap_exit(void)
{
if (hostap_proc != NULL) {
hostap_proc = NULL;
- remove_proc_entry("hostap", proc_net);
+ remove_proc_entry("hostap", init_net.proc_net);
}
}
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index d1d8ce022e63..b03536008ad9 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -106,6 +106,7 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off,
local_info_t *local = (local_info_t *) data;
struct list_head *ptr;
struct hostap_interface *iface;
+ DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -117,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off,
iface = list_entry(ptr, struct hostap_interface, list);
if (iface->type != HOSTAP_INTERFACE_WDS)
continue;
- p += sprintf(p, "%s\t" MACSTR "\n",
+ p += sprintf(p, "%s\t%s\n",
iface->dev->name,
- MAC2STR(iface->u.wds.remote_addr));
+ print_mac(mac, iface->u.wds.remote_addr));
if ((p - page) > PROC_LIMIT) {
printk(KERN_DEBUG "%s: wds proc did not fit\n",
local->dev->name);
@@ -147,6 +148,7 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
struct list_head *ptr;
struct hostap_bss_info *bss;
int i;
+ DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -158,8 +160,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
spin_lock_bh(&local->lock);
list_for_each(ptr, &local->bss_list) {
bss = list_entry(ptr, struct hostap_bss_info, list);
- p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t",
- MAC2STR(bss->bssid), bss->last_update,
+ p += sprintf(p, "%s\t%lu\t%u\t0x%x\t",
+ print_mac(mac, bss->bssid), bss->last_update,
bss->count, bss->capab_info);
for (i = 0; i < bss->ssid_len; i++) {
p += sprintf(p, "%c",
@@ -312,6 +314,7 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
int entry, i, len, total = 0;
struct hfa384x_hostscan_result *scanres;
u8 *pos;
+ DECLARE_MAC_BUF(mac);
p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
"SSID\n");
@@ -329,14 +332,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
if ((p - page) > (PAGE_SIZE - 200))
break;
- p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
+ p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ",
le16_to_cpu(scanres->chid),
(s16) le16_to_cpu(scanres->anl),
(s16) le16_to_cpu(scanres->sl),
le16_to_cpu(scanres->beacon_interval),
le16_to_cpu(scanres->capability),
le16_to_cpu(scanres->rate),
- MAC2STR(scanres->bssid),
+ print_mac(mac, scanres->bssid),
le16_to_cpu(scanres->atim));
pos = scanres->sup_rates;
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 87a54aa6f4dd..c27b2c1c06af 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -3,6 +3,7 @@
#include <linux/wireless.h>
#include <linux/netdevice.h>
+#include <linux/mutex.h>
#include <net/iw_handler.h>
#include "hostap_config.h"
@@ -641,7 +642,7 @@ struct local_info {
* when removing entries from the list.
* TX and RX paths can use read lock. */
spinlock_t cmdlock, baplock, lock;
- struct semaphore rid_bap_sem;
+ struct mutex rid_bap_mtx;
u16 infofid; /* MAC buffer id for info frame */
/* txfid, intransmitfid, next_txtid, and next_alloc are protected by
* txfidlock */
@@ -735,8 +736,6 @@ struct local_info {
PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
PRISM2_MONITOR_CAPHDR = 2
} monitor_type;
- int (*saved_eth_header_parse)(struct sk_buff *skb,
- unsigned char *haddr);
int monitor_allow_fcserr;
int hostapd; /* whether user space daemon, hostapd, is used for AP
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 072ede71e575..2d46a16c0945 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -1922,6 +1922,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
u32 chan;
char *txratename;
u8 bssid[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
/*
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1983,9 +1984,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
}
IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
- MAC_FMT ")\n",
+ "%s)\n",
priv->net_dev->name, escape_essid(essid, essid_len),
- txratename, chan, MAC_ARG(bssid));
+ txratename, chan, print_mac(mac, bssid));
/* now we copy read ssid into dev */
if (!(priv->config & CFG_STATIC_ESSID)) {
@@ -2053,10 +2054,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
{
+ DECLARE_MAC_BUF(mac);
+
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%s' " MAC_FMT " \n",
+ "disassociated: '%s' %s \n",
escape_essid(priv->essid, priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
@@ -4049,6 +4052,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
char *out = buf;
int length;
int ret;
+ DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_RF_KILL_MASK)
return 0;
@@ -4076,9 +4080,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
__LINE__);
out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",
- bssid[0], bssid[1], bssid[2],
- bssid[3], bssid[4], bssid[5]);
+ out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid));
out += sprintf(out, "Channel: %d\n", chan);
return out - buf;
@@ -4652,19 +4654,20 @@ static void ipw2100_rx_free(struct ipw2100_priv *priv)
static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
{
u32 length = ETH_ALEN;
- u8 mac[ETH_ALEN];
+ u8 addr[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
int err;
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
+ err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
if (err) {
IPW_DEBUG_INFO("MAC address read failed\n");
return -EIO;
}
- IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
+ memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
+ IPW_DEBUG_INFO("card MAC is %s\n",
+ print_mac(mac, priv->net_dev->dev_addr));
return 0;
}
@@ -5043,10 +5046,10 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
int err;
#ifdef CONFIG_IPW2100_DEBUG
+ DECLARE_MAC_BUF(mac);
if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
- bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
- bssid[5]);
+ IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
+ print_mac(mac, bssid));
else
IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
#endif
@@ -6239,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
IPW_DEBUG_INFO("Attempting to register device...\n");
- SET_MODULE_OWNER(dev);
-
printk(KERN_INFO DRV_NAME
": Detected Intel PRO/Wireless 2100 Network Connection\n");
@@ -6894,6 +6895,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
static const unsigned char off[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+ DECLARE_MAC_BUF(mac);
// sanity checks
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
@@ -6919,13 +6921,8 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
- IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
- wrqu->ap_addr.sa_data[0] & 0xff,
- wrqu->ap_addr.sa_data[1] & 0xff,
- wrqu->ap_addr.sa_data[2] & 0xff,
- wrqu->ap_addr.sa_data[3] & 0xff,
- wrqu->ap_addr.sa_data[4] & 0xff,
- wrqu->ap_addr.sa_data[5] & 0xff);
+ IPW_DEBUG_WX("SET BSSID -> %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
done:
mutex_unlock(&priv->action_mutex);
@@ -6941,6 +6938,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@@ -6950,8 +6948,8 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
return 0;
}
@@ -7868,10 +7866,10 @@ static int ipw2100_wx_set_powermode(struct net_device *dev,
goto done;
}
- if ((mode < 1) || (mode > POWER_MODES))
+ if ((mode < 0) || (mode > POWER_MODES))
mode = IPW_POWER_AUTO;
- if (priv->power_mode != mode)
+ if (IPW_POWER_LEVEL(priv->power_mode) != mode)
err = ipw2100_set_power_mode(priv, mode);
done:
mutex_unlock(&priv->action_mutex);
@@ -7902,7 +7900,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
break;
case IPW_POWER_AUTO:
snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Auto)", 0);
+ "Power save level: %d (Auto)", level);
break;
default:
timeout = timeout_duration[level - 1] / 1000;
@@ -8279,10 +8277,9 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
static struct iw_handler_def ipw2100_wx_handler_def = {
.standard = ipw2100_wx_handlers,
- .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
- .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
- .num_private_args = sizeof(ipw2100_private_args) /
- sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
+ .num_private = ARRAY_SIZE(ipw2100_private_handler),
+ .num_private_args = ARRAY_SIZE(ipw2100_private_args),
.private = (iw_handler *) ipw2100_private_handler,
.private_args = (struct iw_priv_args *)ipw2100_private_args,
.get_wireless_stats = ipw2100_wx_wireless_stats,
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index aa32a97380ec..feb8fcbab2d5 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -70,7 +70,7 @@
#define VQ
#endif
-#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
#define DRV_VERSION IPW2200_VERSION
@@ -1740,8 +1740,10 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
if (disable_radio) {
priv->status |= STATUS_RF_KILL_SW;
- if (priv->workqueue)
+ if (priv->workqueue) {
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
+ }
queue_work(priv->workqueue, &priv->down);
} else {
priv->status &= ~STATUS_RF_KILL_SW;
@@ -1992,6 +1994,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
wake_up_interruptible(&priv->wait_command_queue);
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
schedule_work(&priv->link_down);
queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
handled |= IPW_INTA_BIT_RF_KILL_DONE;
@@ -2247,8 +2250,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
return -1;
}
- IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
- priv->net_dev->name, MAC_ARG(mac));
+ IPW_DEBUG_INFO("%s: Setting MAC to %s\n",
+ priv->net_dev->name, print_mac(mac, mac));
return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
}
@@ -2506,7 +2509,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
break;
}
- param = cpu_to_le32(mode);
+ param = cpu_to_le32(param);
return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
&param);
}
@@ -3796,6 +3799,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
{
struct ipw_station_entry entry;
int i;
+ DECLARE_MAC_BUF(mac);
for (i = 0; i < priv->num_stations; i++) {
if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
@@ -3812,7 +3816,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
if (i == MAX_STATIONS)
return IPW_INVALID_STATION;
- IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid));
+ IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid));
entry.reserved = 0;
entry.support_mode = 0;
@@ -3839,6 +3843,7 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
{
int err;
+ DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_ASSOCIATING) {
IPW_DEBUG_ASSOC("Disassociating while associating.\n");
@@ -3851,9 +3856,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
return;
}
- IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " "
+ IPW_DEBUG_ASSOC("Disassocation attempt from %s "
"on channel %d.\n",
- MAC_ARG(priv->assoc_request.bssid),
+ print_mac(mac, priv->assoc_request.bssid),
priv->assoc_request.channel);
priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
@@ -4341,6 +4346,37 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
}
+static void ipw_scan_event(struct work_struct *work)
+{
+ union iwreq_data wrqu;
+
+ struct ipw_priv *priv =
+ container_of(work, struct ipw_priv, scan_event.work);
+
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+static void handle_scan_event(struct ipw_priv *priv)
+{
+ /* Only userspace-requested scan completion events go out immediately */
+ if (!priv->user_requested_scan) {
+ if (!delayed_work_pending(&priv->scan_event))
+ queue_delayed_work(priv->workqueue, &priv->scan_event,
+ round_jiffies(msecs_to_jiffies(4000)));
+ } else {
+ union iwreq_data wrqu;
+
+ priv->user_requested_scan = 0;
+ cancel_delayed_work(&priv->scan_event);
+
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+}
+
/**
* Handle host notification packet.
* Called from interrupt routine
@@ -4348,6 +4384,7 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
static void ipw_rx_notification(struct ipw_priv *priv,
struct ipw_rx_notification *notif)
{
+ DECLARE_MAC_BUF(mac);
notif->size = le16_to_cpu(notif->size);
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
@@ -4360,11 +4397,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
case CMAS_ASSOCIATED:{
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "associated: '%s' " MAC_FMT
+ "associated: '%s' %s"
" \n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
switch (priv->ieee->iw_mode) {
case IW_MODE_INFRA:
@@ -4444,13 +4481,13 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DL_STATE |
IPW_DL_ASSOC,
"deauthenticated: '%s' "
- MAC_FMT
+ "%s"
": (0x%04X) - %s \n",
escape_essid(priv->
essid,
priv->
essid_len),
- MAC_ARG(priv->bssid),
+ print_mac(mac, priv->bssid),
ntohs(auth->status),
ipw_get_status_code
(ntohs
@@ -4467,11 +4504,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "authenticated: '%s' " MAC_FMT
+ "authenticated: '%s' %s"
"\n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
break;
}
@@ -4496,11 +4533,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "disassociated: '%s' " MAC_FMT
+ "disassociated: '%s' %s"
" \n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &=
~(STATUS_DISASSOCIATING |
@@ -4535,10 +4572,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
switch (auth->state) {
case CMAS_AUTHENTICATED:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "authenticated: '%s' " MAC_FMT " \n",
+ "authenticated: '%s' %s \n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status |= STATUS_AUTH;
break;
@@ -4554,10 +4591,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
}
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "deauthenticated: '%s' " MAC_FMT "\n",
+ "deauthenticated: '%s' %s\n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &= ~(STATUS_ASSOCIATING |
STATUS_AUTH |
@@ -4702,14 +4739,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
* on how the scan was initiated. User space can just
* sync on periodic scan to get fresh data...
* Jean II */
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) {
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN,
- &wrqu, NULL);
- }
+ if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
+ handle_scan_event(priv);
break;
}
@@ -5383,25 +5414,27 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
int roaming)
{
struct ipw_supported_rates rates;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
/* Verify that this network's capability is compatible with the
* current mode (AdHoc or Infrastructure) */
if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
!(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to "
"capability mismatch.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* If we do not have an ESSID for this AP, we can not associate with
* it */
if (network->flags & NETWORK_EMPTY_ESSID) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of hidden ESSID.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5411,11 +5444,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if ((network->ssid_len != match->network->ssid_len) ||
memcmp(network->ssid, match->network->ssid,
network->ssid_len)) {
- IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of non-network ESSID.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
} else {
@@ -5430,9 +5463,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
strncpy(escaped,
escape_essid(network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of ESSID mismatch: '%s'.\n",
- escaped, MAC_ARG(network->bssid),
+ escaped, print_mac(mac, network->bssid),
escape_essid(priv->essid,
priv->essid_len));
return 0;
@@ -5459,10 +5492,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of age: %ums.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
jiffies_to_msecs(jiffies -
network->last_scanned));
return 0;
@@ -5470,10 +5503,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_CHANNEL) &&
(network->channel != priv->channel)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of channel mismatch: %d != %d.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
network->channel, priv->channel);
return 0;
}
@@ -5481,10 +5514,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Verify privacy compatability */
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of privacy mismatch: %s != %s.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
priv->
capability & CAP_PRIVACY_ON ? "on" : "off",
network->
@@ -5494,40 +5527,41 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
}
if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
- "because of the same BSSID match: " MAC_FMT
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ "because of the same BSSID match: %s"
".\n", escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+ print_mac(mac, network->bssid),
+ print_mac(mac2, priv->bssid));
return 0;
}
/* Filter out any incompatible freq / mode combinations */
if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of invalid frequency/mode "
"combination.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* Ensure that the rates supported by the driver are compatible with
* this AP, including verification of basic rates (mandatory) */
if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because configured rate mask excludes "
"AP mandatory rate.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
if (rates.num_rates == 0) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of no compatible rates.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5538,9 +5572,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Set up 'new' AP to this network */
ipw_copy_rates(&match->rates, &rates);
match->network = network;
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n",
+ IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 1;
}
@@ -5594,6 +5628,7 @@ static int ipw_best_network(struct ipw_priv *priv,
struct ieee80211_network *network, int roaming)
{
struct ipw_supported_rates rates;
+ DECLARE_MAC_BUF(mac);
/* Verify that this network's capability is compatible with the
* current mode (AdHoc or Infrastructure) */
@@ -5601,20 +5636,20 @@ static int ipw_best_network(struct ipw_priv *priv,
!(network->capability & WLAN_CAPABILITY_ESS)) ||
(priv->ieee->iw_mode == IW_MODE_ADHOC &&
!(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to "
"capability mismatch.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* If we do not have an ESSID for this AP, we can not associate with
* it */
if (network->flags & NETWORK_EMPTY_ESSID) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of hidden ESSID.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5624,11 +5659,11 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((network->ssid_len != match->network->ssid_len) ||
memcmp(network->ssid, match->network->ssid,
network->ssid_len)) {
- IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of non-network ESSID.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
} else {
@@ -5642,9 +5677,9 @@ static int ipw_best_network(struct ipw_priv *priv,
strncpy(escaped,
escape_essid(network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of ESSID mismatch: '%s'.\n",
- escaped, MAC_ARG(network->bssid),
+ escaped, print_mac(mac, network->bssid),
escape_essid(priv->essid,
priv->essid_len));
return 0;
@@ -5658,12 +5693,12 @@ static int ipw_best_network(struct ipw_priv *priv,
strncpy(escaped,
escape_essid(network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because "
- "'%s (" MAC_FMT ")' has a stronger signal.\n",
- escaped, MAC_ARG(network->bssid),
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because "
+ "'%s (%s)' has a stronger signal.\n",
+ escaped, print_mac(mac, network->bssid),
escape_essid(match->network->ssid,
match->network->ssid_len),
- MAC_ARG(match->network->bssid));
+ print_mac(mac, match->network->bssid));
return 0;
}
@@ -5671,11 +5706,11 @@ static int ipw_best_network(struct ipw_priv *priv,
* last 3 seconds, do not try and associate again... */
if (network->last_associate &&
time_after(network->last_associate + (HZ * 3UL), jiffies)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of storming (%ums since last "
"assoc attempt).\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
jiffies_to_msecs(jiffies -
network->last_associate));
return 0;
@@ -5684,10 +5719,10 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of age: %ums.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
jiffies_to_msecs(jiffies -
network->last_scanned));
return 0;
@@ -5695,10 +5730,10 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_CHANNEL) &&
(network->channel != priv->channel)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of channel mismatch: %d != %d.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
network->channel, priv->channel);
return 0;
}
@@ -5706,10 +5741,10 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Verify privacy compatability */
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of privacy mismatch: %s != %s.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
priv->capability & CAP_PRIVACY_ON ? "on" :
"off",
network->capability &
@@ -5719,48 +5754,48 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_BSSID) &&
memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
- "because of BSSID mismatch: " MAC_FMT ".\n",
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ "because of BSSID mismatch: %s.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+ print_mac(mac, network->bssid), print_mac(mac, priv->bssid));
return 0;
}
/* Filter out any incompatible freq / mode combinations */
if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of invalid frequency/mode "
"combination.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* Filter out invalid channel in current GEO */
if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of invalid channel in current GEO\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* Ensure that the rates supported by the driver are compatible with
* this AP, including verification of basic rates (mandatory) */
if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because configured rate mask excludes "
"AP mandatory rate.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
if (rates.num_rates == 0) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of no compatible rates.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5772,9 +5807,9 @@ static int ipw_best_network(struct ipw_priv *priv,
ipw_copy_rates(&match->rates, &rates);
match->network = network;
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n",
+ IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 1;
}
@@ -6016,6 +6051,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work)
static void ipw_debug_config(struct ipw_priv *priv)
{
+ DECLARE_MAC_BUF(mac);
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
"[CFG 0x%08X]\n", priv->config);
if (priv->config & CFG_STATIC_CHANNEL)
@@ -6028,8 +6064,8 @@ static void ipw_debug_config(struct ipw_priv *priv)
else
IPW_DEBUG_INFO("ESSID unlocked.\n");
if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n",
- MAC_ARG(priv->bssid));
+ IPW_DEBUG_INFO("BSSID locked to %s\n",
+ print_mac(mac, priv->bssid));
else
IPW_DEBUG_INFO("BSSID unlocked.\n");
if (priv->capability & CAP_PRIVACY_ON)
@@ -7221,6 +7257,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
struct ipw_supported_rates *rates, int roaming)
{
int err;
+ DECLARE_MAC_BUF(mac);
if (priv->config & CFG_FIXED_RATE)
ipw_set_fixed_rate(priv, network->mode);
@@ -7388,9 +7425,9 @@ static int ipw_associate_network(struct ipw_priv *priv,
return err;
}
- IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n",
+ IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n",
escape_essid(priv->essid, priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
return 0;
}
@@ -8202,6 +8239,9 @@ static void ipw_rx(struct ipw_priv *priv)
struct ieee80211_hdr_4addr *header;
u32 r, w, i;
u8 network_packet;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
r = ipw_read32(priv, IPW_RX_READ_INDEX);
w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
@@ -8328,14 +8368,17 @@ static void ipw_rx(struct ipw_priv *priv)
header)))
{
IPW_DEBUG_DROP("Dropping: "
- MAC_FMT ", "
- MAC_FMT ", "
- MAC_FMT "\n",
- MAC_ARG(header->
+ "%s, "
+ "%s, "
+ "%s\n",
+ print_mac(mac,
+ header->
addr1),
- MAC_ARG(header->
+ print_mac(mac2,
+ header->
addr2),
- MAC_ARG(header->
+ print_mac(mac3,
+ header->
addr3));
break;
}
@@ -8867,6 +8910,7 @@ static int ipw_wx_set_wap(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
static const unsigned char any[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -8897,8 +8941,8 @@ static int ipw_wx_set_wap(struct net_device *dev,
return 0;
}
- IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Setting mandatory BSSID to %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
@@ -8916,6 +8960,8 @@ static int ipw_wx_get_wap(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
+
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
mutex_lock(&priv->mutex);
@@ -8926,8 +8972,8 @@ static int ipw_wx_get_wap(struct net_device *dev,
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
mutex_unlock(&priv->mutex);
return 0;
}
@@ -9472,6 +9518,10 @@ static int ipw_wx_set_scan(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ mutex_lock(&priv->mutex);
+ priv->user_requested_scan = 1;
+ mutex_unlock(&priv->mutex);
+
if (wrqu->data.length == sizeof(struct iw_scan_req)) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
ipw_request_direct_scan(priv, req->essid,
@@ -9568,6 +9618,7 @@ static int ipw_wx_set_power(struct net_device *dev,
priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
else
priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+
err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
@@ -9604,22 +9655,19 @@ static int ipw_wx_set_powermode(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
int mode = *(int *)extra;
int err;
+
mutex_lock(&priv->mutex);
- if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
+ if ((mode < 1) || (mode > IPW_POWER_LIMIT))
mode = IPW_POWER_AC;
- priv->power_mode = mode;
- } else {
- priv->power_mode = IPW_POWER_ENABLED | mode;
- }
- if (priv->power_mode != mode) {
+ if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
err = ipw_send_power_mode(priv, mode);
-
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
mutex_unlock(&priv->mutex);
return err;
}
+ priv->power_mode = IPW_POWER_ENABLED | mode;
}
mutex_unlock(&priv->mutex);
return 0;
@@ -10135,6 +10183,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
u8 id, hdr_len, unicast;
u16 remaining_bytes;
int fc;
+ DECLARE_MAC_BUF(mac);
hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
switch (priv->ieee->iw_mode) {
@@ -10145,8 +10194,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
id = ipw_add_station(priv, hdr->addr1);
if (id == IPW_INVALID_STATION) {
IPW_WARNING("Attempt to send data to "
- "invalid cell: " MAC_FMT "\n",
- MAC_ARG(hdr->addr1));
+ "invalid cell: %s\n",
+ print_mac(mac, hdr->addr1));
goto drop;
}
}
@@ -10462,13 +10511,15 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p)
{
struct ipw_priv *priv = ieee80211_priv(dev);
struct sockaddr *addr = p;
+ DECLARE_MAC_BUF(mac);
+
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
mutex_lock(&priv->mutex);
priv->config |= CFG_CUSTOM_MAC;
memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
- printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
- priv->net_dev->name, MAC_ARG(priv->mac_addr));
+ printk(KERN_INFO "%s: Setting MAC to %s\n",
+ priv->net_dev->name, print_mac(mac, priv->mac_addr));
queue_work(priv->workqueue, &priv->adapter_restart);
mutex_unlock(&priv->mutex);
return 0;
@@ -10555,7 +10606,7 @@ static irqreturn_t ipw_isr(int irq, void *data)
spin_lock(&priv->irq_lock);
if (!(priv->status & STATUS_INT_ENABLED)) {
- /* Shared IRQ */
+ /* IRQ is disabled */
goto none;
}
@@ -10649,6 +10700,7 @@ static void ipw_link_up(struct ipw_priv *priv)
}
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
ipw_reset_stats(priv);
/* Ensure the rate is updated immediately */
priv->last_rate = ipw_get_current_rate(priv);
@@ -10686,7 +10738,8 @@ static void ipw_link_down(struct ipw_priv *priv)
if (!(priv->status & STATUS_EXIT_PENDING)) {
/* Queue up another scan... */
queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
- }
+ } else
+ cancel_delayed_work(&priv->scan_event);
}
static void ipw_bg_link_down(struct work_struct *work)
@@ -10716,6 +10769,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv)
INIT_WORK(&priv->up, ipw_bg_up);
INIT_WORK(&priv->down, ipw_bg_down);
INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
+ INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
@@ -11627,7 +11681,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_destroy_workqueue;
}
- SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pdev->dev);
mutex_lock(&priv->mutex);
@@ -11748,6 +11801,7 @@ static void ipw_pci_remove(struct pci_dev *pdev)
cancel_delayed_work(&priv->adhoc_check);
cancel_delayed_work(&priv->gather_stats);
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
cancel_delayed_work(&priv->rf_kill);
cancel_delayed_work(&priv->scan_check);
destroy_workqueue(priv->workqueue);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 626a240a87d8..bec8e37a1738 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -45,7 +45,6 @@
#include <linux/firmware.h>
#include <linux/wireless.h>
-#include <linux/dma-mapping.h>
#include <linux/jiffies.h>
#include <asm/io.h>
@@ -1288,6 +1287,8 @@ struct ipw_priv {
struct iw_public_data wireless_data;
+ int user_requested_scan;
+
struct workqueue_struct *workqueue;
struct delayed_work adhoc_check;
@@ -1296,6 +1297,7 @@ struct ipw_priv {
struct work_struct system_config;
struct work_struct rx_replenish;
struct delayed_work request_scan;
+ struct delayed_work scan_event;
struct work_struct request_passive_scan;
struct work_struct adapter_restart;
struct delayed_work rf_kill;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
new file mode 100644
index 000000000000..25cfc6c32509
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -0,0 +1,128 @@
+config IWLWIFI
+ bool "Intel Wireless WiFi Link Drivers"
+ depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ select FW_LOADER
+ default n
+ ---help---
+ Select to enable drivers based on the iwlwifi project. This
+ project provides a common foundation for Intel's wireless
+ drivers designed to use the mac80211 subsystem.
+
+ See <file:Documentation/networking/README.iwlwifi> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging issues and problems.
+
+config IWLWIFI_DEBUG
+ bool "Enable full debugging output in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable debug tracing output for the iwlwifi
+ drivers.
+
+ This will result in the kernel module being ~100k larger. You can
+ control which debug output is sent to the kernel log by setting the
+ value in
+
+ /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+ This entry will only exist if this option is enabled.
+
+ To set a value, simply echo an 8-byte hex value to the same file:
+
+ % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+ You can find the list of debug mask values in:
+ drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h
+
+ If this is your first time using this driver, you should say Y here
+ as the debug information can assist others in helping you resolve
+ any problems you may encounter.
+
+config IWLWIFI_SENSITIVITY
+ bool "Enable Sensitivity Calibration in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable sensitivity calibration for the iwlwifi
+ drivers.
+
+config IWLWIFI_SPECTRUM_MEASUREMENT
+ bool "Enable Spectrum Measurement in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable spectrum measurement for the iwlwifi drivers.
+
+config IWLWIFI_QOS
+ bool "Enable Wireless QoS in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable wireless quality of service (QoS) for the
+ iwlwifi drivers.
+
+config IWLWIFI_HT
+ bool "Enable 802.11n HT features in iwlwifi drivers"
+ depends on EXPERIMENTAL
+ depends on IWLWIFI && MAC80211_HT
+ default n
+ ---help---
+ This option enables IEEE 802.11n High Throughput features
+ for the iwlwifi drivers.
+
+config IWL4965
+ tristate "Intel Wireless WiFi 4965AGN"
+ depends on m && IWLWIFI && EXPERIMENTAL
+ default m
+ ---help---
+ Select to build the driver supporting the:
+
+ Intel Wireless WiFi Link 4965AGN
+
+ This driver uses the kernel's mac80211 subsystem.
+
+ See <file:Documentation/networking/README.iwlwifi> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging any issues or problems.
+
+ In order to use this driver, you will need a microcode (uCode)
+ image for it. You can obtain the microcode from:
+
+ <http://intellinuxwireless.org/>.
+
+ See the above referenced README.iwlwifi for information on where
+ to install the microcode images.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and remvoed from the running kernel whenever you want),
+ say M here and read <file:Documentation/modules.txt>. The module
+ will be called iwl4965.ko.
+
+config IWL3945
+ tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
+ depends on m && IWLWIFI && EXPERIMENTAL
+ default m
+ ---help---
+ Select to build the driver supporting the:
+
+ Intel PRO/Wireless 3945ABG/BG Network Connection
+
+ This driver uses the kernel's mac80211 subsystem.
+
+ See <file:Documentation/networking/README.iwlwifi> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging any issues or problems.
+
+ In order to use this driver, you will need a microcode (uCode)
+ image for it. You can obtain the microcode from:
+
+ <http://intellinuxwireless.org/>.
+
+ See the above referenced README.iwlwifi for information on where
+ to install the microcode images.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and remvoed from the running kernel whenever you want),
+ say M here and read <file:Documentation/modules.txt>. The module
+ will be called iwl3945.ko.
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
new file mode 100644
index 000000000000..3bbd38358d53
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_IWL3945) += iwl3945.o
+iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o
+
+obj-$(CONFIG_IWL4965) += iwl4965.o
+iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
new file mode 100644
index 000000000000..fb5f0649f4f6
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_hw__
+#define __iwl_3945_hw__
+
+#define IWL_RX_BUF_SIZE 3000
+/* card static random access memory (SRAM) for processor data and instructs */
+#define ALM_RTC_INST_UPPER_BOUND (0x014000)
+#define ALM_RTC_DATA_UPPER_BOUND (0x808000)
+
+#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
+#define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE
+#define IWL_MAX_NUM_QUEUES 8
+
+static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+{
+ return (addr >= RTC_DATA_LOWER_BOUND) &&
+ (addr < ALM_RTC_DATA_UPPER_BOUND);
+}
+
+/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE
+ * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
+struct iwl_shared {
+ __le32 tx_base_ptr[8];
+ __le32 rx_read_ptr[3];
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame_data {
+ __le32 addr;
+ __le32 len;
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame {
+ __le32 control_flags;
+ struct iwl_tfd_frame_data pa[4];
+ u8 reserved[28];
+} __attribute__ ((packed));
+
+static inline u8 iwl_hw_get_rate(__le16 rate_n_flags)
+{
+ return le16_to_cpu(rate_n_flags) & 0xFF;
+}
+
+static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags)
+{
+ return le16_to_cpu(rate_n_flags);
+}
+
+static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+ return cpu_to_le16((u16)rate|flags);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
new file mode 100644
index 000000000000..f4aabcf480e4
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -0,0 +1,982 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <net/ieee80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#include <net/mac80211.h>
+#include <linux/wireless.h>
+
+#define IWL 3945
+
+#include "../net/mac80211/ieee80211_rate.h"
+
+#include "iwlwifi.h"
+
+#define RS_NAME "iwl-3945-rs"
+
+struct iwl_rate_scale_data {
+ u64 data;
+ s32 success_counter;
+ s32 success_ratio;
+ s32 counter;
+ s32 average_tpt;
+ unsigned long stamp;
+};
+
+struct iwl_rate_scale_priv {
+ spinlock_t lock;
+ s32 *expected_tpt;
+ unsigned long last_partial_flush;
+ unsigned long last_flush;
+ u32 flush_time;
+ u32 last_tx_packets;
+ u32 tx_packets;
+ u8 tgg;
+ u8 flush_pending;
+ u8 start_rate;
+ u8 ibss_sta_added;
+ struct timer_list rate_scale_flush;
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+};
+
+static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = {
+ 0, 0, 76, 104, 130, 168, 191, 202, 7, 13, 35, 58
+};
+
+static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = {
+ 0, 0, 0, 80, 93, 113, 123, 125, 7, 13, 35, 58
+};
+
+static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = {
+ 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0, 0
+};
+
+static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 7, 13, 35, 58
+};
+
+struct iwl_tpt_entry {
+ s8 min_rssi;
+ u8 index;
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_a[] = {
+ {-60, IWL_RATE_54M_INDEX},
+ {-64, IWL_RATE_48M_INDEX},
+ {-72, IWL_RATE_36M_INDEX},
+ {-80, IWL_RATE_24M_INDEX},
+ {-84, IWL_RATE_18M_INDEX},
+ {-85, IWL_RATE_12M_INDEX},
+ {-87, IWL_RATE_9M_INDEX},
+ {-89, IWL_RATE_6M_INDEX}
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_b[] = {
+ {-86, IWL_RATE_11M_INDEX},
+ {-88, IWL_RATE_5M_INDEX},
+ {-90, IWL_RATE_2M_INDEX},
+ {-92, IWL_RATE_1M_INDEX}
+
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_g[] = {
+ {-60, IWL_RATE_54M_INDEX},
+ {-64, IWL_RATE_48M_INDEX},
+ {-68, IWL_RATE_36M_INDEX},
+ {-80, IWL_RATE_24M_INDEX},
+ {-84, IWL_RATE_18M_INDEX},
+ {-85, IWL_RATE_12M_INDEX},
+ {-86, IWL_RATE_11M_INDEX},
+ {-88, IWL_RATE_5M_INDEX},
+ {-90, IWL_RATE_2M_INDEX},
+ {-92, IWL_RATE_1M_INDEX}
+};
+
+#define IWL_RATE_MAX_WINDOW 62
+#define IWL_RATE_FLUSH (3*HZ/10)
+#define IWL_RATE_WIN_FLUSH (HZ/2)
+#define IWL_RATE_HIGH_TH 11520
+#define IWL_RATE_MIN_FAILURE_TH 8
+#define IWL_RATE_MIN_SUCCESS_TH 8
+#define IWL_RATE_DECREASE_TH 1920
+
+static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
+{
+ u32 index = 0;
+ u32 table_size = 0;
+ struct iwl_tpt_entry *tpt_table = NULL;
+
+ if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL))
+ rssi = IWL_MIN_RSSI_VAL;
+
+ switch (mode) {
+ case MODE_IEEE80211G:
+ tpt_table = iwl_tpt_table_g;
+ table_size = ARRAY_SIZE(iwl_tpt_table_g);
+ break;
+
+ case MODE_IEEE80211A:
+ tpt_table = iwl_tpt_table_a;
+ table_size = ARRAY_SIZE(iwl_tpt_table_a);
+ break;
+
+ default:
+ case MODE_IEEE80211B:
+ tpt_table = iwl_tpt_table_b;
+ table_size = ARRAY_SIZE(iwl_tpt_table_b);
+ break;
+ }
+
+ while ((index < table_size) && (rssi < tpt_table[index].min_rssi))
+ index++;
+
+ index = min(index, (table_size - 1));
+
+ return tpt_table[index].index;
+}
+
+static void iwl_clear_window(struct iwl_rate_scale_data *window)
+{
+ window->data = 0;
+ window->success_counter = 0;
+ window->success_ratio = IWL_INVALID_VALUE;
+ window->counter = 0;
+ window->average_tpt = IWL_INVALID_VALUE;
+ window->stamp = 0;
+}
+
+/**
+ * iwl_rate_scale_flush_windows - flush out the rate scale windows
+ *
+ * Returns the number of windows that have gathered data but were
+ * not flushed. If there were any that were not flushed, then
+ * reschedule the rate flushing routine.
+ */
+static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
+{
+ int unflushed = 0;
+ int i;
+ unsigned long flags;
+
+ /*
+ * For each rate, if we have collected data on that rate
+ * and it has been more than IWL_RATE_WIN_FLUSH
+ * since we flushed, clear out the gathered statistics
+ */
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ if (!rs_priv->win[i].counter)
+ continue;
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+ if (time_after(jiffies, rs_priv->win[i].stamp +
+ IWL_RATE_WIN_FLUSH)) {
+ IWL_DEBUG_RATE("flushing %d samples of rate "
+ "index %d\n",
+ rs_priv->win[i].counter, i);
+ iwl_clear_window(&rs_priv->win[i]);
+ } else
+ unflushed++;
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+ }
+
+ return unflushed;
+}
+
+#define IWL_RATE_FLUSH_MAX 5000 /* msec */
+#define IWL_RATE_FLUSH_MIN 50 /* msec */
+
+static void iwl_bg_rate_scale_flush(unsigned long data)
+{
+ struct iwl_rate_scale_priv *rs_priv = (void *)data;
+ int unflushed = 0;
+ unsigned long flags;
+ u32 packet_count, duration, pps;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ unflushed = iwl_rate_scale_flush_windows(rs_priv);
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ rs_priv->flush_pending = 0;
+
+ /* Number of packets Rx'd since last time this timer ran */
+ packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1;
+
+ rs_priv->last_tx_packets = rs_priv->tx_packets + 1;
+
+ if (unflushed) {
+ duration =
+ jiffies_to_msecs(jiffies - rs_priv->last_partial_flush);
+/* duration = jiffies_to_msecs(rs_priv->flush_time); */
+
+ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n",
+ packet_count, duration);
+
+ /* Determine packets per second */
+ if (duration)
+ pps = (packet_count * 1000) / duration;
+ else
+ pps = 0;
+
+ if (pps) {
+ duration = IWL_RATE_FLUSH_MAX / pps;
+ if (duration < IWL_RATE_FLUSH_MIN)
+ duration = IWL_RATE_FLUSH_MIN;
+ } else
+ duration = IWL_RATE_FLUSH_MAX;
+
+ rs_priv->flush_time = msecs_to_jiffies(duration);
+
+ IWL_DEBUG_RATE("new flush period: %d msec ave %d\n",
+ duration, packet_count);
+
+ mod_timer(&rs_priv->rate_scale_flush, jiffies +
+ rs_priv->flush_time);
+
+ rs_priv->last_partial_flush = jiffies;
+ }
+
+ /* If there weren't any unflushed entries, we don't schedule the timer
+ * to run again */
+
+ rs_priv->last_flush = jiffies;
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ IWL_DEBUG_RATE("leave\n");
+}
+
+/**
+ * iwl_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 64 packets transmitted
+ * at this rate. window->data contains the bitmask of successful
+ * packets.
+ */
+static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate_scale_data *window,
+ int success, int retries)
+{
+ unsigned long flags;
+
+ if (!retries) {
+ IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n");
+ return;
+ }
+
+ while (retries--) {
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ /* If we have filled up the window then subtract one from the
+ * success counter if the high-bit is counting toward
+ * success */
+ if (window->counter == IWL_RATE_MAX_WINDOW) {
+ if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1)))
+ window->success_counter--;
+ } else
+ window->counter++;
+
+ /* Slide the window to the left one bit */
+ window->data = (window->data << 1);
+
+ /* If this packet was a success then set the low bit high */
+ if (success) {
+ window->success_counter++;
+ window->data |= 1;
+ }
+
+ /* window->counter can't be 0 -- it is either >0 or
+ * IWL_RATE_MAX_WINDOW */
+ window->success_ratio = 12800 * window->success_counter /
+ window->counter;
+
+ /* Tag this window as having been updated */
+ window->stamp = jiffies;
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+ }
+}
+
+static void rs_rate_init(void *priv_rate, void *priv_sta,
+ struct ieee80211_local *local, struct sta_info *sta)
+{
+ int i;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+
+ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
+ if (sta->supp_rates & (1 << i)) {
+ sta->txrate = i;
+ break;
+ }
+ }
+
+ sta->last_txrate = sta->txrate;
+
+ IWL_DEBUG_RATE("leave\n");
+}
+
+static void *rs_alloc(struct ieee80211_local *local)
+{
+ return local->hw.priv;
+}
+
+/* rate scale requires free function to be implmented */
+static void rs_free(void *priv)
+{
+ return;
+}
+static void rs_clear(void *priv)
+{
+ return;
+}
+
+
+static void *rs_alloc_sta(void *priv, gfp_t gfp)
+{
+ struct iwl_rate_scale_priv *rs_priv;
+ int i;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+ if (!rs_priv) {
+ IWL_DEBUG_RATE("leave: ENOMEM\n");
+ return NULL;
+ }
+
+ spin_lock_init(&rs_priv->lock);
+
+ rs_priv->start_rate = IWL_RATE_INVALID;
+
+ /* default to just 802.11b */
+ rs_priv->expected_tpt = iwl_expected_tpt_b;
+
+ rs_priv->last_partial_flush = jiffies;
+ rs_priv->last_flush = jiffies;
+ rs_priv->flush_time = IWL_RATE_FLUSH;
+ rs_priv->last_tx_packets = 0;
+ rs_priv->ibss_sta_added = 0;
+
+ init_timer(&rs_priv->rate_scale_flush);
+ rs_priv->rate_scale_flush.data = (unsigned long)rs_priv;
+ rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ iwl_clear_window(&rs_priv->win[i]);
+
+ IWL_DEBUG_RATE("leave\n");
+
+ return rs_priv;
+}
+
+static void rs_free_sta(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+
+ IWL_DEBUG_RATE("enter\n");
+ del_timer_sync(&rs_priv->rate_scale_flush);
+ kfree(rs_priv);
+ IWL_DEBUG_RATE("leave\n");
+}
+
+/**
+ * rs_tx_status - Update rate control values based on Tx results
+ *
+ * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by
+ * the hardware for each rate.
+ */
+static void rs_tx_status(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *tx_resp)
+{
+ u8 retries, current_count;
+ int scale_rate_index, first_index, last_index;
+ unsigned long flags;
+ struct sta_info *sta;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iwl_rate_scale_priv *rs_priv;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ retries = tx_resp->retry_count;
+
+ first_index = tx_resp->control.tx_rate;
+ if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
+ IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n",
+ tx_resp->control.tx_rate, first_index);
+ return;
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+ return;
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ rs_priv->tx_packets++;
+
+ scale_rate_index = first_index;
+ last_index = first_index;
+
+ /*
+ * Update the window for each rate. We determine which rates
+ * were Tx'd based on the total number of retries vs. the number
+ * of retries configured for each rate -- currently set to the
+ * priv value 'retry_rate' vs. rate specific
+ *
+ * On exit from this while loop last_index indicates the rate
+ * at which the frame was finally transmitted (or failed if no
+ * ACK)
+ */
+ while (retries > 0) {
+ if (retries < priv->retry_rate) {
+ current_count = retries;
+ last_index = scale_rate_index;
+ } else {
+ current_count = priv->retry_rate;
+ last_index = iwl_get_prev_ieee_rate(scale_rate_index);
+ }
+
+ /* Update this rate accounting for as many retries
+ * as was used for it (per current_count) */
+ iwl_collect_tx_data(rs_priv,
+ &rs_priv->win[scale_rate_index],
+ 0, current_count);
+ IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
+ scale_rate_index, current_count);
+
+ retries -= current_count;
+
+ if (retries)
+ scale_rate_index =
+ iwl_get_prev_ieee_rate(scale_rate_index);
+ }
+
+ /* Update the last index window with success/failure based on ACK */
+ IWL_DEBUG_RATE("Update rate %d with %s.\n",
+ last_index,
+ (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
+ "success" : "failure");
+ iwl_collect_tx_data(rs_priv,
+ &rs_priv->win[last_index],
+ tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
+
+ /* We updated the rate scale window -- if its been more than
+ * flush_time since the last run, schedule the flush
+ * again */
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ if (!rs_priv->flush_pending &&
+ time_after(jiffies, rs_priv->last_partial_flush +
+ rs_priv->flush_time)) {
+
+ rs_priv->flush_pending = 1;
+ mod_timer(&rs_priv->rate_scale_flush,
+ jiffies + rs_priv->flush_time);
+ }
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ sta_info_put(sta);
+
+ IWL_DEBUG_RATE("leave\n");
+
+ return;
+}
+
+static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
+ *local)
+{
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ int i;
+
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
+ return rate;
+ }
+
+ return &mode->rates[0];
+}
+
+static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
+ u8 index, u16 rate_mask, int phymode)
+{
+ u8 high = IWL_RATE_INVALID;
+ u8 low = IWL_RATE_INVALID;
+
+ /* 802.11A walks to the next literal adjascent rate in
+ * the rate table */
+ if (unlikely(phymode == MODE_IEEE80211A)) {
+ int i;
+ u32 mask;
+
+ /* Find the previous rate that is in the rate mask */
+ i = index - 1;
+ for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (rate_mask & mask) {
+ low = i;
+ break;
+ }
+ }
+
+ /* Find the next rate that is in the rate mask */
+ i = index + 1;
+ for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+ if (rate_mask & mask) {
+ high = i;
+ break;
+ }
+ }
+
+ return (high << 8) | low;
+ }
+
+ low = index;
+ while (low != IWL_RATE_INVALID) {
+ if (rs_priv->tgg)
+ low = iwl_rates[low].prev_rs_tgg;
+ else
+ low = iwl_rates[low].prev_rs;
+ if (low == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << low))
+ break;
+ IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
+ }
+
+ high = index;
+ while (high != IWL_RATE_INVALID) {
+ if (rs_priv->tgg)
+ high = iwl_rates[high].next_rs_tgg;
+ else
+ high = iwl_rates[high].next_rs;
+ if (high == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << high))
+ break;
+ IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
+ }
+
+ return (high << 8) | low;
+}
+
+/**
+ * rs_get_rate - find the rate for the requested packet
+ *
+ * Returns the ieee80211_rate structure allocated by the driver.
+ *
+ * The rate control algorithm has no internal mapping between hw_mode's
+ * rate ordering and the rate ordering used by the rate control algorithm.
+ *
+ * The rate control algorithm uses a single table of rates that goes across
+ * the entire A/B/G spectrum vs. being limited to just one particular
+ * hw_mode.
+ *
+ * As such, we can't convert the index obtained below into the hw_mode's
+ * rate table and must reference the driver allocated rate table
+ *
+ */
+static struct ieee80211_rate *rs_get_rate(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra *extra)
+{
+ u8 low = IWL_RATE_INVALID;
+ u8 high = IWL_RATE_INVALID;
+ u16 high_low;
+ int index;
+ struct iwl_rate_scale_priv *rs_priv;
+ struct iwl_rate_scale_data *window = NULL;
+ int current_tpt = IWL_INVALID_VALUE;
+ int low_tpt = IWL_INVALID_VALUE;
+ int high_tpt = IWL_INVALID_VALUE;
+ u32 fail_count;
+ s8 scale_action = 0;
+ unsigned long flags;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct sta_info *sta;
+ u16 fc, rate_mask;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_RATE("enter\n");
+
+ memset(extra, 0, sizeof(*extra));
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ (is_multicast_ether_addr(hdr->addr1))) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ IWL_DEBUG_RATE("leave: lowest rate (not data or is "
+ "multicast)\n");
+
+ return iwl_get_lowest_rate(local);
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+ if (!sta || !sta->rate_ctrl_priv) {
+ IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+ if (sta)
+ sta_info_put(sta);
+ return NULL;
+ }
+
+ rate_mask = sta->supp_rates;
+ index = min(sta->txrate & 0xffff, IWL_RATE_COUNT - 1);
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !rs_priv->ibss_sta_added) {
+ u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
+ print_mac(mac, hdr->addr1));
+ sta_id = iwl_add_station(priv,
+ hdr->addr1, 0, CMD_ASYNC);
+ }
+ if (sta_id != IWL_INVALID_STATION)
+ rs_priv->ibss_sta_added = 1;
+ }
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ if (rs_priv->start_rate != IWL_RATE_INVALID) {
+ index = rs_priv->start_rate;
+ rs_priv->start_rate = IWL_RATE_INVALID;
+ }
+
+ window = &(rs_priv->win[index]);
+
+ fail_count = window->counter - window->success_counter;
+
+ if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
+ window->average_tpt = IWL_INVALID_VALUE;
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
+ "counter: %d, success_counter: %d, "
+ "expected_tpt is %sNULL\n",
+ index,
+ window->counter,
+ window->success_counter,
+ rs_priv->expected_tpt ? "not " : "");
+ goto out;
+
+ }
+
+ window->average_tpt = ((window->success_ratio *
+ rs_priv->expected_tpt[index] + 64) / 128);
+ current_tpt = window->average_tpt;
+
+ high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask,
+ local->hw.conf.phymode);
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ if (low != IWL_RATE_INVALID)
+ low_tpt = rs_priv->win[low].average_tpt;
+
+ if (high != IWL_RATE_INVALID)
+ high_tpt = rs_priv->win[high].average_tpt;
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ scale_action = 1;
+
+ if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) {
+ IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
+ scale_action = -1;
+ } else if ((low_tpt == IWL_INVALID_VALUE) &&
+ (high_tpt == IWL_INVALID_VALUE))
+ scale_action = 1;
+ else if ((low_tpt != IWL_INVALID_VALUE) &&
+ (high_tpt != IWL_INVALID_VALUE)
+ && (low_tpt < current_tpt)
+ && (high_tpt < current_tpt)) {
+ IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < "
+ "current_tpt [%d]\n",
+ low_tpt, high_tpt, current_tpt);
+ scale_action = 0;
+ } else {
+ if (high_tpt != IWL_INVALID_VALUE) {
+ if (high_tpt > current_tpt)
+ scale_action = 1;
+ else {
+ IWL_DEBUG_RATE
+ ("decrease rate because of high tpt\n");
+ scale_action = -1;
+ }
+ } else if (low_tpt != IWL_INVALID_VALUE) {
+ if (low_tpt > current_tpt) {
+ IWL_DEBUG_RATE
+ ("decrease rate because of low tpt\n");
+ scale_action = -1;
+ } else
+ scale_action = 1;
+ }
+ }
+
+ if ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+ (current_tpt > window->average_tpt)) {
+ IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or "
+ "current_tpt [%d] > average_tpt [%d]\n",
+ window->success_ratio,
+ current_tpt, window->average_tpt);
+ scale_action = 0;
+ }
+
+ switch (scale_action) {
+ case -1:
+ if (low != IWL_RATE_INVALID)
+ index = low;
+ break;
+
+ case 1:
+ if (high != IWL_RATE_INVALID)
+ index = high;
+
+ break;
+
+ case 0:
+ default:
+ break;
+ }
+
+ IWL_DEBUG_RATE("Selected %d (action %d) - low %d high %d\n",
+ index, scale_action, low, high);
+
+ out:
+
+ sta->last_txrate = index;
+ sta->txrate = sta->last_txrate;
+ sta_info_put(sta);
+
+ IWL_DEBUG_RATE("leave: %d\n", index);
+
+ return &priv->ieee_rates[index];
+}
+
+static struct rate_control_ops rs_ops = {
+ .module = NULL,
+ .name = RS_NAME,
+ .tx_status = rs_tx_status,
+ .get_rate = rs_get_rate,
+ .rate_init = rs_rate_init,
+ .clear = rs_clear,
+ .alloc = rs_alloc,
+ .free = rs_free,
+ .alloc_sta = rs_alloc_sta,
+ .free_sta = rs_free_sta,
+};
+
+int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rate_scale_priv *rs_priv;
+ struct sta_info *sta;
+ unsigned long flags;
+ int count = 0, i;
+ u32 samples = 0, success = 0, good = 0;
+ unsigned long now = jiffies;
+ u32 max_time = 0;
+
+ sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta) {
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave - no private rate data!\n");
+ } else
+ IWL_DEBUG_RATE("leave - no station!\n");
+ return sprintf(buf, "station %d not found\n", sta_id);
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+ spin_lock_irqsave(&rs_priv->lock, flags);
+ i = IWL_RATE_54M_INDEX;
+ while (1) {
+ u64 mask;
+ int j;
+
+ count +=
+ sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+
+ mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
+ for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
+ buf[count++] =
+ (rs_priv->win[i].data & mask) ? '1' : '0';
+
+ samples += rs_priv->win[i].counter;
+ good += rs_priv->win[i].success_counter;
+ success += rs_priv->win[i].success_counter * iwl_rates[i].ieee;
+
+ if (rs_priv->win[i].stamp) {
+ int delta =
+ jiffies_to_msecs(now - rs_priv->win[i].stamp);
+
+ if (delta > max_time)
+ max_time = delta;
+
+ count += sprintf(&buf[count], "%5dms\n", delta);
+ } else
+ buf[count++] = '\n';
+
+ j = iwl_get_prev_ieee_rate(i);
+ if (j == i)
+ break;
+ i = j;
+ }
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+ sta_info_put(sta);
+
+ /* Display the average rate of all samples taken.
+ *
+ * NOTE: We multiple # of samples by 2 since the IEEE measurement
+ * added from iwl_rates is actually 2X the rate */
+ if (samples)
+ count += sprintf(
+ &buf[count],
+ "\nAverage rate is %3d.%02dMbs over last %4dms\n"
+ "%3d%% success (%d good packets over %d tries)\n",
+ success / (2 * samples), (success * 5 / samples) % 10,
+ max_time, good * 100 / samples, good, samples);
+ else
+ count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
+
+ return count;
+}
+
+void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+{
+ struct iwl_priv *priv = hw->priv;
+ s32 rssi = 0;
+ unsigned long flags;
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct iwl_rate_scale_priv *rs_priv;
+ struct sta_info *sta;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ if (!local->rate_ctrl->ops->name ||
+ strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
+ IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
+ IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
+ return;
+ }
+
+ sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave - no private rate data!\n");
+ return;
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ rs_priv->tgg = 0;
+ switch (priv->phymode) {
+ case MODE_IEEE80211G:
+ if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
+ rs_priv->tgg = 1;
+ rs_priv->expected_tpt = iwl_expected_tpt_g_prot;
+ } else
+ rs_priv->expected_tpt = iwl_expected_tpt_g;
+ break;
+
+ case MODE_IEEE80211A:
+ rs_priv->expected_tpt = iwl_expected_tpt_a;
+ break;
+
+ default:
+ IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n");
+ case MODE_IEEE80211B:
+ rs_priv->expected_tpt = iwl_expected_tpt_b;
+ break;
+ }
+
+ sta_info_put(sta);
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ rssi = priv->last_rx_rssi;
+ if (rssi == 0)
+ rssi = IWL_MIN_RSSI_VAL;
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi);
+
+ rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode);
+
+ IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
+ "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate,
+ iwl_rates[rs_priv->start_rate].plcp);
+}
+
+void iwl_rate_control_register(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_unregister(&rs_ops);
+}
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
new file mode 100644
index 000000000000..b926738e0ea1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -0,0 +1,191 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_rs_h__
+#define __iwl_3945_rs_h__
+
+struct iwl_rate_info {
+ u8 plcp;
+ u8 ieee;
+ u8 prev_ieee; /* previous rate in IEEE speeds */
+ u8 next_ieee; /* next rate in IEEE speeds */
+ u8 prev_rs; /* previous rate used in rs algo */
+ u8 next_rs; /* next rate used in rs algo */
+ u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
+ u8 next_rs_tgg; /* next rate used in TGG rs algo */
+};
+
+enum {
+ IWL_RATE_6M_INDEX = 0,
+ IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX,
+ IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX,
+ IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX,
+ IWL_RATE_54M_INDEX,
+ IWL_RATE_1M_INDEX,
+ IWL_RATE_2M_INDEX,
+ IWL_RATE_5M_INDEX,
+ IWL_RATE_11M_INDEX,
+ IWL_RATE_COUNT,
+ IWL_RATE_INVM_INDEX,
+ IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+};
+
+enum {
+ IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+ IWL_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
+ IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+ IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define IWL_RATE_6M_MASK (1<<IWL_RATE_6M_INDEX)
+#define IWL_RATE_9M_MASK (1<<IWL_RATE_9M_INDEX)
+#define IWL_RATE_12M_MASK (1<<IWL_RATE_12M_INDEX)
+#define IWL_RATE_18M_MASK (1<<IWL_RATE_18M_INDEX)
+#define IWL_RATE_24M_MASK (1<<IWL_RATE_24M_INDEX)
+#define IWL_RATE_36M_MASK (1<<IWL_RATE_36M_INDEX)
+#define IWL_RATE_48M_MASK (1<<IWL_RATE_48M_INDEX)
+#define IWL_RATE_54M_MASK (1<<IWL_RATE_54M_INDEX)
+#define IWL_RATE_1M_MASK (1<<IWL_RATE_1M_INDEX)
+#define IWL_RATE_2M_MASK (1<<IWL_RATE_2M_INDEX)
+#define IWL_RATE_5M_MASK (1<<IWL_RATE_5M_INDEX)
+#define IWL_RATE_11M_MASK (1<<IWL_RATE_11M_INDEX)
+
+enum {
+ IWL_RATE_6M_PLCP = 13,
+ IWL_RATE_9M_PLCP = 15,
+ IWL_RATE_12M_PLCP = 5,
+ IWL_RATE_18M_PLCP = 7,
+ IWL_RATE_24M_PLCP = 9,
+ IWL_RATE_36M_PLCP = 11,
+ IWL_RATE_48M_PLCP = 1,
+ IWL_RATE_54M_PLCP = 3,
+ IWL_RATE_1M_PLCP = 10,
+ IWL_RATE_2M_PLCP = 20,
+ IWL_RATE_5M_PLCP = 55,
+ IWL_RATE_11M_PLCP = 110,
+};
+
+enum {
+ IWL_RATE_6M_IEEE = 12,
+ IWL_RATE_9M_IEEE = 18,
+ IWL_RATE_12M_IEEE = 24,
+ IWL_RATE_18M_IEEE = 36,
+ IWL_RATE_24M_IEEE = 48,
+ IWL_RATE_36M_IEEE = 72,
+ IWL_RATE_48M_IEEE = 96,
+ IWL_RATE_54M_IEEE = 108,
+ IWL_RATE_1M_IEEE = 2,
+ IWL_RATE_2M_IEEE = 4,
+ IWL_RATE_5M_IEEE = 11,
+ IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_CCK_BASIC_RATES_MASK \
+ (IWL_RATE_1M_MASK | \
+ IWL_RATE_2M_MASK)
+
+#define IWL_CCK_RATES_MASK \
+ (IWL_BASIC_RATES_MASK | \
+ IWL_RATE_5M_MASK | \
+ IWL_RATE_11M_MASK)
+
+#define IWL_OFDM_BASIC_RATES_MASK \
+ (IWL_RATE_6M_MASK | \
+ IWL_RATE_12M_MASK | \
+ IWL_RATE_24M_MASK)
+
+#define IWL_OFDM_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_RATE_9M_MASK | \
+ IWL_RATE_18M_MASK | \
+ IWL_RATE_36M_MASK | \
+ IWL_RATE_48M_MASK | \
+ IWL_RATE_54M_MASK)
+
+#define IWL_BASIC_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_CCK_BASIC_RATES_MASK)
+
+#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+
+#define IWL_INVALID_VALUE -1
+
+#define IWL_MIN_RSSI_VAL -100
+#define IWL_MAX_RSSI_VAL 0
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+{
+ u8 rate = iwl_rates[rate_index].prev_ieee;
+
+ if (rate == IWL_RATE_INVALID)
+ rate = rate_index;
+ return rate;
+}
+
+/**
+ * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ *
+ * NOTE: This is provided as a quick mechanism for a user to visualize
+ * the performance of the rate control alogirthm and is not meant to be
+ * parsed software.
+ */
+extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+
+/**
+ * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ *
+ * The specific througput table used is based on the type of network
+ * the associated with, including A, B, G, and G w/ TGG protection
+ */
+extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module. The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem. This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
new file mode 100644
index 000000000000..acb38750535f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -0,0 +1,2300 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <net/mac80211.h>
+
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#define IWL 3945
+
+#include "iwlwifi.h"
+#include "iwl-helpers.h"
+#include "iwl-3945.h"
+#include "iwl-3945-rs.h"
+
+#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ * rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+ IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18), /* 11mbps */
+};
+
+/* 1 = enable the iwl_disable_events() function */
+#define IWL_EVT_DISABLE (0)
+#define IWL_EVT_DISABLE_SIZE (1532/32)
+
+/**
+ * iwl_disable_events - Disable selected events in uCode event log
+ *
+ * Disable an event by writing "1"s into "disable"
+ * bitmap in SRAM. Bit position corresponds to Event # (id/type).
+ * Default values of 0 enable uCode events to be logged.
+ * Use for only special debugging. This function is just a placeholder as-is,
+ * you'll need to provide the special bits! ...
+ * ... and set IWL_EVT_DISABLE to 1. */
+void iwl_disable_events(struct iwl_priv *priv)
+{
+ int rc;
+ int i;
+ u32 base; /* SRAM address of event log header */
+ u32 disable_ptr; /* SRAM address of event-disable bitmap array */
+ u32 array_size; /* # of u32 entries in array */
+ u32 evt_disable[IWL_EVT_DISABLE_SIZE] = {
+ 0x00000000, /* 31 - 0 Event id numbers */
+ 0x00000000, /* 63 - 32 */
+ 0x00000000, /* 95 - 64 */
+ 0x00000000, /* 127 - 96 */
+ 0x00000000, /* 159 - 128 */
+ 0x00000000, /* 191 - 160 */
+ 0x00000000, /* 223 - 192 */
+ 0x00000000, /* 255 - 224 */
+ 0x00000000, /* 287 - 256 */
+ 0x00000000, /* 319 - 288 */
+ 0x00000000, /* 351 - 320 */
+ 0x00000000, /* 383 - 352 */
+ 0x00000000, /* 415 - 384 */
+ 0x00000000, /* 447 - 416 */
+ 0x00000000, /* 479 - 448 */
+ 0x00000000, /* 511 - 480 */
+ 0x00000000, /* 543 - 512 */
+ 0x00000000, /* 575 - 544 */
+ 0x00000000, /* 607 - 576 */
+ 0x00000000, /* 639 - 608 */
+ 0x00000000, /* 671 - 640 */
+ 0x00000000, /* 703 - 672 */
+ 0x00000000, /* 735 - 704 */
+ 0x00000000, /* 767 - 736 */
+ 0x00000000, /* 799 - 768 */
+ 0x00000000, /* 831 - 800 */
+ 0x00000000, /* 863 - 832 */
+ 0x00000000, /* 895 - 864 */
+ 0x00000000, /* 927 - 896 */
+ 0x00000000, /* 959 - 928 */
+ 0x00000000, /* 991 - 960 */
+ 0x00000000, /* 1023 - 992 */
+ 0x00000000, /* 1055 - 1024 */
+ 0x00000000, /* 1087 - 1056 */
+ 0x00000000, /* 1119 - 1088 */
+ 0x00000000, /* 1151 - 1120 */
+ 0x00000000, /* 1183 - 1152 */
+ 0x00000000, /* 1215 - 1184 */
+ 0x00000000, /* 1247 - 1216 */
+ 0x00000000, /* 1279 - 1248 */
+ 0x00000000, /* 1311 - 1280 */
+ 0x00000000, /* 1343 - 1312 */
+ 0x00000000, /* 1375 - 1344 */
+ 0x00000000, /* 1407 - 1376 */
+ 0x00000000, /* 1439 - 1408 */
+ 0x00000000, /* 1471 - 1440 */
+ 0x00000000, /* 1503 - 1472 */
+ };
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32)));
+ array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32)));
+ iwl_release_restricted_access(priv);
+
+ if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
+ IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",
+ disable_ptr);
+ rc = iwl_grab_restricted_access(priv);
+ for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
+ iwl_write_restricted_mem(priv,
+ disable_ptr +
+ (i * sizeof(u32)),
+ evt_disable[i]);
+
+ iwl_release_restricted_access(priv);
+ } else {
+ IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");
+ IWL_DEBUG_INFO(" by writing \"1\"s into disable bitmap\n");
+ IWL_DEBUG_INFO(" in SRAM at 0x%x, size %d u32s\n",
+ disable_ptr, array_size);
+ }
+
+}
+
+/**
+ * iwl3945_get_antenna_flags - Get antenna flags for RXON command
+ * @priv: eeprom and antenna fields are used to determine antenna flags
+ *
+ * priv->eeprom is used to determine if antenna AUX/MAIN are reversed
+ * priv->antenna specifies the antenna diversity mode:
+ *
+ * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself
+ * IWL_ANTENNA_MAIN - Force MAIN antenna
+ * IWL_ANTENNA_AUX - Force AUX antenna
+ */
+__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
+{
+ switch (priv->antenna) {
+ case IWL_ANTENNA_DIVERSITY:
+ return 0;
+
+ case IWL_ANTENNA_MAIN:
+ if (priv->eeprom.antenna_switch_type)
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
+
+ case IWL_ANTENNA_AUX:
+ if (priv->eeprom.antenna_switch_type)
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
+ }
+
+ /* bad antenna selector value */
+ IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna);
+ return 0; /* "diversity" is default if error */
+}
+
+/*****************************************************************************
+ *
+ * Intel PRO/Wireless 3945ABG/BG Network Connection
+ *
+ * RX handler implementations
+ *
+ * Used by iwl-base.c
+ *
+ *****************************************************************************/
+
+void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
+ (int)sizeof(struct iwl_notif_statistics),
+ le32_to_cpu(pkt->len));
+
+ memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
+
+ priv->last_statistics_time = jiffies;
+}
+
+static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
+ struct iwl_rx_mem_buffer *rxb,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags)
+{
+ struct ieee80211_hdr *hdr;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ short len = le16_to_cpu(rx_hdr->len);
+
+ /* We received data from the HW, so stop the watchdog */
+ if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
+ IWL_DEBUG_DROP("Corruption detected!\n");
+ return;
+ }
+
+ /* We only process data packets if the interface is open */
+ if (unlikely(!priv->is_open)) {
+ IWL_DEBUG_DROP_LIMIT
+ ("Dropping packet while interface is not open.\n");
+ return;
+ }
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb,
+ le32_to_cpu(rx_end->status),
+ stats);
+ iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),
+ len, stats, phy_flags);
+ return;
+ }
+
+ skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
+
+ hdr = (void *)rxb->skb->data;
+
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb,
+ le32_to_cpu(rx_end->status), stats);
+
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ rxb->skb = NULL;
+}
+
+static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ struct ieee80211_hdr *header;
+ u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
+ struct ieee80211_rx_status stats = {
+ .mactime = le64_to_cpu(rx_end->timestamp),
+ .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)),
+ .channel = le16_to_cpu(rx_hdr->channel),
+ .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ MODE_IEEE80211G : MODE_IEEE80211A,
+ .antenna = 0,
+ .rate = rx_hdr->rate,
+ .flag = 0,
+ };
+ u8 network_packet;
+ int snr;
+
+ if ((unlikely(rx_stats->phy_count > 20))) {
+ IWL_DEBUG_DROP
+ ("dsp size out of range [0,20]: "
+ "%d/n", rx_stats->phy_count);
+ return;
+ }
+
+ if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR)
+ || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+ IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
+ return;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags);
+ return;
+ }
+
+ /* Convert 3945's rssi indicator to dBm */
+ stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
+
+ /* Set default noise value to -127 */
+ if (priv->last_rx_noise == 0)
+ priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+ /* 3945 provides noise info for OFDM frames only.
+ * sig_avg and noise_diff are measured by the 3945's digital signal
+ * processor (DSP), and indicate linear levels of signal level and
+ * distortion/noise within the packet preamble after
+ * automatic gain control (AGC). sig_avg should stay fairly
+ * constant if the radio's AGC is working well.
+ * Since these values are linear (not dB or dBm), linear
+ * signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
+ * Convert linear SNR to dB SNR, then subtract that from rssi dBm
+ * to obtain noise level in dBm.
+ * Calculate stats.signal (quality indicator in %) based on SNR. */
+ if (rx_stats_noise_diff) {
+ snr = rx_stats_sig_avg / rx_stats_noise_diff;
+ stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr);
+ stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+
+ /* If noise info not available, calculate signal quality indicator (%)
+ * using just the dBm signal level. */
+ } else {
+ stats.noise = priv->last_rx_noise;
+ stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+ }
+
+
+ IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
+ stats.ssi, stats.noise, stats.signal,
+ rx_stats_sig_avg, rx_stats_noise_diff);
+
+ stats.freq = ieee80211chan2mhz(stats.channel);
+
+ /* can be covered by iwl_report_frame() in most cases */
+/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */
+
+ header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
+
+ network_packet = iwl_is_network_packet(priv, header);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_STATS && net_ratelimit())
+ IWL_DEBUG_STATS
+ ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",
+ network_packet ? '*' : ' ',
+ stats.channel, stats.ssi, stats.ssi,
+ stats.ssi, stats.rate);
+
+ if (iwl_debug_level & (IWL_DL_RX))
+ /* Set "1" to report good data frames in groups of 100 */
+ iwl_report_frame(priv, pkt, header, 1);
+#endif
+
+ if (network_packet) {
+ priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
+ priv->last_tsf = le64_to_cpu(rx_end->timestamp);
+ priv->last_rx_rssi = stats.ssi;
+ priv->last_rx_noise = stats.noise;
+ }
+
+ switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_MGMT:
+ switch (le16_to_cpu(header->frame_control) &
+ IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:{
+ /* If this is a beacon or probe response for
+ * our network then cache the beacon
+ * timestamp */
+ if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)
+ && !compare_ether_addr(header->addr2,
+ priv->bssid)) ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ && !compare_ether_addr(header->addr3,
+ priv->bssid)))) {
+ struct ieee80211_mgmt *mgmt =
+ (struct ieee80211_mgmt *)header;
+ __le32 *pos;
+ pos =
+ (__le32 *) & mgmt->u.beacon.
+ timestamp;
+ priv->timestamp0 = le32_to_cpu(pos[0]);
+ priv->timestamp1 = le32_to_cpu(pos[1]);
+ priv->beacon_int = le16_to_cpu(
+ mgmt->u.beacon.beacon_int);
+ if (priv->call_post_assoc_from_beacon &&
+ (priv->iw_mode ==
+ IEEE80211_IF_TYPE_STA))
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+
+ priv->call_post_assoc_from_beacon = 0;
+ }
+
+ break;
+ }
+
+ case IEEE80211_STYPE_ACTION:
+ /* TODO: Parse 802.11h frames for CSA... */
+ break;
+
+ /*
+ * TODO: There is no callback function from upper
+ * stack to inform us when associated status. this
+ * work around to sniff assoc_resp management frame
+ * and finish the association process.
+ */
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:{
+ struct ieee80211_mgmt *mgnt =
+ (struct ieee80211_mgmt *)header;
+ priv->assoc_id = (~((1 << 15) | (1 << 14)) &
+ le16_to_cpu(mgnt->u.
+ assoc_resp.aid));
+ priv->assoc_capability =
+ le16_to_cpu(mgnt->u.assoc_resp.capab_info);
+ if (priv->beacon_int)
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+ else
+ priv->call_post_assoc_from_beacon = 1;
+ break;
+ }
+
+ case IEEE80211_STYPE_PROBE_REQ:{
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ IWL_DEBUG_DROP
+ ("Dropping (non network): %s"
+ ", %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ return;
+ }
+ }
+
+ iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+ break;
+
+ case IEEE80211_FTYPE_DATA: {
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+
+ if (unlikely(is_duplicate_packet(priv, header)))
+ IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ else
+ iwl3945_handle_data_packet(priv, 1, rxb, &stats,
+ phy_flags);
+ break;
+ }
+ }
+}
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+ dma_addr_t addr, u16 len)
+{
+ int count;
+ u32 pad;
+ struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr;
+
+ count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
+ pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags));
+
+ if ((count >= NUM_TFD_CHUNKS) || (count < 0)) {
+ IWL_ERROR("Error can not send more than %d chunks\n",
+ NUM_TFD_CHUNKS);
+ return -EINVAL;
+ }
+
+ tfd->pa[count].addr = cpu_to_le32(addr);
+ tfd->pa[count].len = cpu_to_le32(len);
+
+ count++;
+
+ tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) |
+ TFD_CTL_PAD_SET(pad));
+
+ return 0;
+}
+
+/**
+ * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ *
+ * Does NOT advance any indexes
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+ struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+ int counter;
+
+ /* classify bd */
+ if (txq->q.id == IWL_CMD_QUEUE_NUM)
+ /* nothing to cleanup after for host commands */
+ return 0;
+
+ /* sanity check */
+ counter = TFD_CTL_COUNT_GET(le32_to_cpu(bd->control_flags));
+ if (counter > NUM_TFD_CHUNKS) {
+ IWL_ERROR("Too many chunks: %i\n", counter);
+ /* @todo issue fatal error, it is quite serious situation */
+ return 0;
+ }
+
+ /* unmap chunks if any */
+
+ for (i = 1; i < counter; i++) {
+ pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr),
+ le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE);
+ if (txq->txb[txq->q.last_used].skb[0]) {
+ struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0];
+ if (txq->txb[txq->q.last_used].skb[0]) {
+ /* Can be called from interrupt context */
+ dev_kfree_skb_any(skb);
+ txq->txb[txq->q.last_used].skb[0] = NULL;
+ }
+ }
+ }
+ return 0;
+}
+
+u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+ int i;
+ int ret = IWL_INVALID_STATION;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ if ((priv->stations[i].used) &&
+ (!compare_ether_addr
+ (priv->stations[i].sta.sta.addr, addr))) {
+ ret = i;
+ goto out;
+ }
+
+ IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
+ print_mac(mac, addr), priv->num_stations);
+ out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
+}
+
+/**
+ * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
+ *
+*/
+void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr, int sta_id, int tx_id)
+{
+ unsigned long flags;
+ u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+ u16 rate_mask;
+ int rate;
+ u8 rts_retry_limit;
+ u8 data_retry_limit;
+ __le32 tx_flags;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ rate = iwl_rates[rate_index].plcp;
+ tx_flags = cmd->cmd.tx.tx_flags;
+
+ /* We need to figure out how to get the sta->supp_rates while
+ * in this running context; perhaps encoding into ctrl->tx_rate? */
+ rate_mask = IWL_RATES_MASK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].current_rate.rate_n_flags = rate;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ (sta_id != IWL3945_BROADCAST_ID) &&
+ (sta_id != IWL_MULTICAST_ID))
+ priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ if (tx_id >= IWL_CMD_QUEUE_NUM)
+ rts_retry_limit = 3;
+ else
+ rts_retry_limit = 7;
+
+ if (ieee80211_is_probe_response(fc)) {
+ data_retry_limit = 3;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ } else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+ if (priv->data_retry_limit != -1)
+ data_retry_limit = priv->data_retry_limit;
+
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+ if (tx_flags & TX_CMD_FLG_RTS_MSK) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
+ cmd->cmd.tx.data_retry_limit = data_retry_limit;
+ cmd->cmd.tx.rate = rate;
+ cmd->cmd.tx.tx_flags = tx_flags;
+
+ /* OFDM */
+ cmd->cmd.tx.supp_rates[0] = rate_mask & IWL_OFDM_RATES_MASK;
+
+ /* CCK */
+ cmd->cmd.tx.supp_rates[1] = (rate_mask >> 8) & 0xF;
+
+ IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
+ "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
+ cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags),
+ cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]);
+}
+
+u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
+{
+ unsigned long flags_spin;
+ struct iwl_station_entry *station;
+
+ if (sta_id == IWL_INVALID_STATION)
+ return IWL_INVALID_STATION;
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ station = &priv->stations[sta_id];
+
+ station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
+ station->sta.rate_n_flags = cpu_to_le16(tx_rate);
+ station->current_rate.rate_n_flags = tx_rate;
+ station->sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+ iwl_send_add_station(priv, &station->sta, flags);
+ IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
+ sta_id, tx_rate);
+ return sta_id;
+}
+
+void iwl_hw_card_show_info(struct iwl_priv *priv)
+{
+ IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n",
+ ((priv->eeprom.board_revision >> 8) & 0x0F),
+ ((priv->eeprom.board_revision >> 8) >> 4),
+ (priv->eeprom.board_revision & 0x00FF));
+
+ IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n",
+ (int)sizeof(priv->eeprom.board_pba_number),
+ priv->eeprom.board_pba_number);
+
+ IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n",
+ priv->eeprom.antenna_switch_type);
+}
+
+static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ if (!pwr_max) {
+ u32 val;
+
+ rc = pci_read_config_dword(priv->pci_dev,
+ PCI_POWER_SOURCE, &val);
+ if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
+ iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ iwl_release_restricted_access(priv);
+
+ iwl_poll_bit(priv, CSR_GPIO_IN,
+ CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
+ CSR_GPIO_IN_BIT_AUX_POWER, 5000);
+ } else
+ iwl_release_restricted_access(priv);
+ } else {
+ iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+
+ iwl_release_restricted_access(priv);
+ iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
+ CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
+ iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0),
+ priv->hw_setting.shared_phys +
+ offsetof(struct iwl_shared, rx_read_ptr[0]));
+ iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0);
+ iwl_write_restricted(priv, FH_RCSR_CONFIG(0),
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
+ ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 |
+ (RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST |
+ (1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
+
+ /* fake read to flush all prev I/O */
+ iwl_read_restricted(priv, FH_RSSR_CTRL);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int iwl3945_tx_reset(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* bypass mode */
+ iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2);
+
+ /* RA 0 is active */
+ iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01);
+
+ /* all 6 fifo are active */
+ iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f);
+
+ iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000);
+ iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002);
+ iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004);
+ iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005);
+
+ iwl_write_restricted(priv, FH_TSSR_CBB_BASE,
+ priv->hw_setting.shared_phys);
+
+ iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG,
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * iwl3945_txq_ctx_reset - Reset TX queue context
+ *
+ * Destroys all DMA structures and initialize them again
+ */
+static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
+{
+ int rc;
+ int txq_id, slots_num;
+
+ iwl_hw_txq_ctx_free(priv);
+
+ /* Tx CMD queue */
+ rc = iwl3945_tx_reset(priv);
+ if (rc)
+ goto error;
+
+ /* Tx queue(s) */
+ for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
+ slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+ txq_id);
+ if (rc) {
+ IWL_ERROR("Tx %d queue init failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return rc;
+
+ error:
+ iwl_hw_txq_ctx_free(priv);
+ return rc;
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+ u8 rev_id;
+ int rc;
+ unsigned long flags;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+
+ iwl_power_init_handle(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return rc;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+ udelay(20);
+ iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Determine HW type */
+ rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+ if (rc)
+ return rc;
+ IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+
+ iwl3945_nic_set_pwr_src(priv, 1);
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
+ IWL_DEBUG_INFO("RTP type \n");
+ else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
+ IWL_DEBUG_INFO("ALM-MB type\n");
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
+ } else {
+ IWL_DEBUG_INFO("ALM-MM type\n");
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Initialize the EEPROM */
+ rc = iwl_eeprom_init(priv);
+ if (rc)
+ return rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
+ IWL_DEBUG_INFO("SKU OP mode is mrc\n");
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
+ } else
+ IWL_DEBUG_INFO("SKU OP mode is basic\n");
+
+ if ((priv->eeprom.board_revision & 0xF0) == 0xD0) {
+ IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
+ priv->eeprom.board_revision);
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+ } else {
+ IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
+ priv->eeprom.board_revision);
+ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+ }
+
+ if (priv->eeprom.almgor_m_version <= 1) {
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
+ IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
+ priv->eeprom.almgor_m_version);
+ } else {
+ IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
+ priv->eeprom.almgor_m_version);
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
+
+ /* Allocate the RX queue, or reset if it is already allocated */
+ if (!rxq->bd) {
+ rc = iwl_rx_queue_alloc(priv);
+ if (rc) {
+ IWL_ERROR("Unable to initialize Rx queue\n");
+ return -ENOMEM;
+ }
+ } else
+ iwl_rx_queue_reset(priv, rxq);
+
+ iwl_rx_replenish(priv);
+
+ iwl3945_rx_init(priv, rxq);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Look at using this instead:
+ rxq->need_update = 1;
+ iwl_rx_queue_update_write_ptr(priv, rxq);
+ */
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
+ iwl_release_restricted_access(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ rc = iwl3945_txq_ctx_reset(priv);
+ if (rc)
+ return rc;
+
+ set_bit(STATUS_INIT, &priv->status);
+
+ return 0;
+}
+
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ /* Tx queues */
+ for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++)
+ iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+}
+
+void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+{
+ int queue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_grab_restricted_access(priv)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_hw_txq_ctx_free(priv);
+ return;
+ }
+
+ /* stop SCD */
+ iwl_write_restricted_reg(priv, SCD_MODE_REG, 0);
+
+ /* reset TFD queues */
+ for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) {
+ iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0);
+ iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS,
+ ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue),
+ 1000);
+ }
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_txq_ctx_free(priv);
+}
+
+int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+{
+ int rc = 0;
+ u32 reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+
+ if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
+ (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+ IWL_DEBUG_INFO("Card in power save, master is already "
+ "stopped\n");
+ else {
+ rc = iwl_poll_bit(priv, CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("stop master\n");
+
+ return rc;
+}
+
+int iwl_hw_nic_reset(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ iwl_hw_nic_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (!rc) {
+ iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+ APMG_CLK_VAL_BSM_CLK_RQT);
+
+ udelay(10);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0);
+ iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG,
+ 0xFFFFFFFF);
+
+ /* enable DMA */
+ iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+ udelay(10);
+
+ iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+ udelay(5);
+ iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+ iwl_release_restricted_access(priv);
+ }
+
+ /* Clear the 'host command active' bit... */
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+/**
+ * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table
+ */
+static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
+{
+ return (new_reading - old_reading) * (-11) / 100;
+}
+
+/**
+ * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range
+ */
+static inline int iwl_hw_reg_temp_out_of_range(int temperature)
+{
+ return (((temperature < -260) || (temperature > 25)) ? 1 : 0);
+}
+
+int iwl_hw_get_temperature(struct iwl_priv *priv)
+{
+ return iwl_read32(priv, CSR_UCODE_DRV_GP2);
+}
+
+/**
+ * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC
+ */
+static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv)
+{
+ int temperature;
+
+ temperature = iwl_hw_get_temperature(priv);
+
+ /* driver's okay range is -260 to +25.
+ * human readable okay range is 0 to +285 */
+ IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT);
+
+ /* handle insane temp reading */
+ if (iwl_hw_reg_temp_out_of_range(temperature)) {
+ IWL_ERROR("Error bad temperature value %d\n", temperature);
+
+ /* if really really hot(?),
+ * substitute the 3rd band/group's temp measured at factory */
+ if (priv->last_temperature > 100)
+ temperature = priv->eeprom.groups[2].temperature;
+ else /* else use most recent "sane" value from driver */
+ temperature = priv->last_temperature;
+ }
+
+ return temperature; /* raw, not "human readable" */
+}
+
+/* Adjust Txpower only if temperature variance is greater than threshold.
+ *
+ * Both are lower than older versions' 9 degrees */
+#define IWL_TEMPERATURE_LIMIT_TIMER 6
+
+/**
+ * is_temp_calib_needed - determines if new calibration is needed
+ *
+ * records new temperature in tx_mgr->temperature.
+ * replaces tx_mgr->last_temperature *only* if calib needed
+ * (assumes caller will actually do the calibration!). */
+static int is_temp_calib_needed(struct iwl_priv *priv)
+{
+ int temp_diff;
+
+ priv->temperature = iwl_hw_reg_txpower_get_temperature(priv);
+ temp_diff = priv->temperature - priv->last_temperature;
+
+ /* get absolute value */
+ if (temp_diff < 0) {
+ IWL_DEBUG_POWER("Getting cooler, delta %d,\n", temp_diff);
+ temp_diff = -temp_diff;
+ } else if (temp_diff == 0)
+ IWL_DEBUG_POWER("Same temp,\n");
+ else
+ IWL_DEBUG_POWER("Getting warmer, delta %d,\n", temp_diff);
+
+ /* if we don't need calibration, *don't* update last_temperature */
+ if (temp_diff < IWL_TEMPERATURE_LIMIT_TIMER) {
+ IWL_DEBUG_POWER("Timed thermal calib not needed\n");
+ return 0;
+ }
+
+ IWL_DEBUG_POWER("Timed thermal calib needed\n");
+
+ /* assume that caller will actually do calib ...
+ * update the "last temperature" value */
+ priv->last_temperature = priv->temperature;
+ return 1;
+}
+
+#define IWL_MAX_GAIN_ENTRIES 78
+#define IWL_CCK_FROM_OFDM_POWER_DIFF -5
+#define IWL_CCK_FROM_OFDM_INDEX_DIFF (10)
+
+/* radio and DSP power table, each step is 1/2 dB.
+ * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */
+static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
+ {
+ {251, 127}, /* 2.4 GHz, highest power */
+ {251, 127},
+ {251, 127},
+ {251, 127},
+ {251, 125},
+ {251, 110},
+ {251, 105},
+ {251, 98},
+ {187, 125},
+ {187, 115},
+ {187, 108},
+ {187, 99},
+ {243, 119},
+ {243, 111},
+ {243, 105},
+ {243, 97},
+ {243, 92},
+ {211, 106},
+ {211, 100},
+ {179, 120},
+ {179, 113},
+ {179, 107},
+ {147, 125},
+ {147, 119},
+ {147, 112},
+ {147, 106},
+ {147, 101},
+ {147, 97},
+ {147, 91},
+ {115, 107},
+ {235, 121},
+ {235, 115},
+ {235, 109},
+ {203, 127},
+ {203, 121},
+ {203, 115},
+ {203, 108},
+ {203, 102},
+ {203, 96},
+ {203, 92},
+ {171, 110},
+ {171, 104},
+ {171, 98},
+ {139, 116},
+ {227, 125},
+ {227, 119},
+ {227, 113},
+ {227, 107},
+ {227, 101},
+ {227, 96},
+ {195, 113},
+ {195, 106},
+ {195, 102},
+ {195, 95},
+ {163, 113},
+ {163, 106},
+ {163, 102},
+ {163, 95},
+ {131, 113},
+ {131, 106},
+ {131, 102},
+ {131, 95},
+ {99, 113},
+ {99, 106},
+ {99, 102},
+ {99, 95},
+ {67, 113},
+ {67, 106},
+ {67, 102},
+ {67, 95},
+ {35, 113},
+ {35, 106},
+ {35, 102},
+ {35, 95},
+ {3, 113},
+ {3, 106},
+ {3, 102},
+ {3, 95} }, /* 2.4 GHz, lowest power */
+ {
+ {251, 127}, /* 5.x GHz, highest power */
+ {251, 120},
+ {251, 114},
+ {219, 119},
+ {219, 101},
+ {187, 113},
+ {187, 102},
+ {155, 114},
+ {155, 103},
+ {123, 117},
+ {123, 107},
+ {123, 99},
+ {123, 92},
+ {91, 108},
+ {59, 125},
+ {59, 118},
+ {59, 109},
+ {59, 102},
+ {59, 96},
+ {59, 90},
+ {27, 104},
+ {27, 98},
+ {27, 92},
+ {115, 118},
+ {115, 111},
+ {115, 104},
+ {83, 126},
+ {83, 121},
+ {83, 113},
+ {83, 105},
+ {83, 99},
+ {51, 118},
+ {51, 111},
+ {51, 104},
+ {51, 98},
+ {19, 116},
+ {19, 109},
+ {19, 102},
+ {19, 98},
+ {19, 93},
+ {171, 113},
+ {171, 107},
+ {171, 99},
+ {139, 120},
+ {139, 113},
+ {139, 107},
+ {139, 99},
+ {107, 120},
+ {107, 113},
+ {107, 107},
+ {107, 99},
+ {75, 120},
+ {75, 113},
+ {75, 107},
+ {75, 99},
+ {43, 120},
+ {43, 113},
+ {43, 107},
+ {43, 99},
+ {11, 120},
+ {11, 113},
+ {11, 107},
+ {11, 99},
+ {131, 107},
+ {131, 99},
+ {99, 120},
+ {99, 113},
+ {99, 107},
+ {99, 99},
+ {67, 120},
+ {67, 113},
+ {67, 107},
+ {67, 99},
+ {35, 120},
+ {35, 113},
+ {35, 107},
+ {35, 99},
+ {3, 120} } /* 5.x GHz, lowest power */
+};
+
+static inline u8 iwl_hw_reg_fix_power_index(int index)
+{
+ if (index < 0)
+ return 0;
+ if (index >= IWL_MAX_GAIN_ENTRIES)
+ return IWL_MAX_GAIN_ENTRIES - 1;
+ return (u8) index;
+}
+
+/* Kick off thermal recalibration check every 60 seconds */
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests
+ *
+ * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
+ * or 6 Mbit (OFDM) rates.
+ */
+static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
+ s32 rate_index, const s8 *clip_pwrs,
+ struct iwl_channel_info *ch_info,
+ int band_index)
+{
+ struct iwl_scan_power_info *scan_power_info;
+ s8 power;
+ u8 power_index;
+
+ scan_power_info = &ch_info->scan_pwr_info[scan_tbl_index];
+
+ /* use this channel group's 6Mbit clipping/saturation pwr,
+ * but cap at regulatory scan power restriction (set during init
+ * based on eeprom channel data) for this channel. */
+ power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX]);
+
+ /* further limit to user's max power preference.
+ * FIXME: Other spectrum management power limitations do not
+ * seem to apply?? */
+ power = min(power, priv->user_txpower_limit);
+ scan_power_info->requested_power = power;
+
+ /* find difference between new scan *power* and current "normal"
+ * Tx *power* for 6Mb. Use this difference (x2) to adjust the
+ * current "normal" temperature-compensated Tx power *index* for
+ * this rate (1Mb or 6Mb) to yield new temp-compensated scan power
+ * *index*. */
+ power_index = ch_info->power_info[rate_index].power_table_index
+ - (power - ch_info->power_info
+ [IWL_RATE_6M_INDEX].requested_power) * 2;
+
+ /* store reference index that we use when adjusting *all* scan
+ * powers. So we can accommodate user (all channel) or spectrum
+ * management (single channel) power changes "between" temperature
+ * feedback compensation procedures.
+ * don't force fit this reference index into gain table; it may be a
+ * negative number. This will help avoid errors when we're at
+ * the lower bounds (highest gains, for warmest temperatures)
+ * of the table. */
+
+ /* don't exceed table bounds for "real" setting */
+ power_index = iwl_hw_reg_fix_power_index(power_index);
+
+ scan_power_info->power_table_index = power_index;
+ scan_power_info->tpc.tx_gain =
+ power_gain_table[band_index][power_index].tx_gain;
+ scan_power_info->tpc.dsp_atten =
+ power_gain_table[band_index][power_index].dsp_atten;
+}
+
+/**
+ * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings
+ *
+ * Configures power settings for all rates for the current channel,
+ * using values from channel info struct, and send to NIC
+ */
+int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+{
+ int rate_idx;
+ const struct iwl_channel_info *ch_info = NULL;
+ struct iwl_txpowertable_cmd txpower = {
+ .channel = priv->active_rxon.channel,
+ };
+
+ txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1;
+ ch_info = iwl_get_channel_info(priv,
+ priv->phymode,
+ le16_to_cpu(priv->active_rxon.channel));
+ if (!ch_info) {
+ IWL_ERROR
+ ("Failed to get channel info for channel %d [%d]\n",
+ le16_to_cpu(priv->active_rxon.channel), priv->phymode);
+ return -EINVAL;
+ }
+
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_POWER("Not calling TX_PWR_TABLE_CMD on "
+ "non-Tx channel.\n");
+ return 0;
+ }
+
+ /* fill cmd with power settings for all rates for current channel */
+ for (rate_idx = 0; rate_idx < IWL_RATE_COUNT; rate_idx++) {
+ txpower.power[rate_idx].tpc = ch_info->power_info[rate_idx].tpc;
+ txpower.power[rate_idx].rate = iwl_rates[rate_idx].plcp;
+
+ IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
+ le16_to_cpu(txpower.channel),
+ txpower.band,
+ txpower.power[rate_idx].tpc.tx_gain,
+ txpower.power[rate_idx].tpc.dsp_atten,
+ txpower.power[rate_idx].rate);
+ }
+
+ return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
+ sizeof(struct iwl_txpowertable_cmd), &txpower);
+
+}
+
+/**
+ * iwl_hw_reg_set_new_power - Configures power tables at new levels
+ * @ch_info: Channel to update. Uses power_info.requested_power.
+ *
+ * Replace requested_power and base_power_index ch_info fields for
+ * one channel.
+ *
+ * Called if user or spectrum management changes power preferences.
+ * Takes into account h/w and modulation limitations (clip power).
+ *
+ * This does *not* send anything to NIC, just sets up ch_info for one channel.
+ *
+ * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to
+ * properly fill out the scan powers, and actual h/w gain settings,
+ * and send changes to NIC
+ */
+static int iwl_hw_reg_set_new_power(struct iwl_priv *priv,
+ struct iwl_channel_info *ch_info)
+{
+ struct iwl_channel_power_info *power_info;
+ int power_changed = 0;
+ int i;
+ const s8 *clip_pwrs;
+ int power;
+
+ /* Get this chnlgrp's rate-to-max/clip-powers table */
+ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+ /* Get this channel's rate-to-current-power settings table */
+ power_info = ch_info->power_info;
+
+ /* update OFDM Txpower settings */
+ for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE;
+ i++, ++power_info) {
+ int delta_idx;
+
+ /* limit new power to be no more than h/w capability */
+ power = min(ch_info->curr_txpow, clip_pwrs[i]);
+ if (power == power_info->requested_power)
+ continue;
+
+ /* find difference between old and new requested powers,
+ * update base (non-temp-compensated) power index */
+ delta_idx = (power - power_info->requested_power) * 2;
+ power_info->base_power_index -= delta_idx;
+
+ /* save new requested power value */
+ power_info->requested_power = power;
+
+ power_changed = 1;
+ }
+
+ /* update CCK Txpower settings, based on OFDM 12M setting ...
+ * ... all CCK power settings for a given channel are the *same*. */
+ if (power_changed) {
+ power =
+ ch_info->power_info[IWL_RATE_12M_INDEX].
+ requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF;
+
+ /* do all CCK rates' iwl_channel_power_info structures */
+ for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) {
+ power_info->requested_power = power;
+ power_info->base_power_index =
+ ch_info->power_info[IWL_RATE_12M_INDEX].
+ base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF;
+ ++power_info;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel
+ *
+ * NOTE: Returned power limit may be less (but not more) than requested,
+ * based strictly on regulatory (eeprom and spectrum mgt) limitations
+ * (no consideration for h/w clipping limitations).
+ */
+static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info)
+{
+ s8 max_power;
+
+#if 0
+ /* if we're using TGd limits, use lower of TGd or EEPROM */
+ if (ch_info->tgd_data.max_power != 0)
+ max_power = min(ch_info->tgd_data.max_power,
+ ch_info->eeprom.max_power_avg);
+
+ /* else just use EEPROM limits */
+ else
+#endif
+ max_power = ch_info->eeprom.max_power_avg;
+
+ return min(max_power, ch_info->max_power_avg);
+}
+
+/**
+ * iwl_hw_reg_comp_txpower_temp - Compensate for temperature
+ *
+ * Compensate txpower settings of *all* channels for temperature.
+ * This only accounts for the difference between current temperature
+ * and the factory calibration temperatures, and bases the new settings
+ * on the channel's base_power_index.
+ *
+ * If RxOn is "associated", this sends the new Txpower to NIC!
+ */
+static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch_info = NULL;
+ int delta_index;
+ const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
+ u8 a_band;
+ u8 rate_index;
+ u8 scan_tbl_index;
+ u8 i;
+ int ref_temp;
+ int temperature = priv->temperature;
+
+ /* set up new Tx power info for each and every channel, 2.4 and 5.x */
+ for (i = 0; i < priv->channel_count; i++) {
+ ch_info = &priv->channel_info[i];
+ a_band = is_channel_a_band(ch_info);
+
+ /* Get this chnlgrp's factory calibration temperature */
+ ref_temp = (s16)priv->eeprom.groups[ch_info->group_index].
+ temperature;
+
+ /* get power index adjustment based on curr and factory
+ * temps */
+ delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+ ref_temp);
+
+ /* set tx power value for all rates, OFDM and CCK */
+ for (rate_index = 0; rate_index < IWL_RATE_COUNT;
+ rate_index++) {
+ int power_idx =
+ ch_info->power_info[rate_index].base_power_index;
+
+ /* temperature compensate */
+ power_idx += delta_index;
+
+ /* stay within table range */
+ power_idx = iwl_hw_reg_fix_power_index(power_idx);
+ ch_info->power_info[rate_index].
+ power_table_index = (u8) power_idx;
+ ch_info->power_info[rate_index].tpc =
+ power_gain_table[a_band][power_idx];
+ }
+
+ /* Get this chnlgrp's rate-to-max/clip-powers table */
+ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+ /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
+ for (scan_tbl_index = 0;
+ scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
+ s32 actual_index = (scan_tbl_index == 0) ?
+ IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX;
+ iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+ actual_index, clip_pwrs,
+ ch_info, a_band);
+ }
+ }
+
+ /* send Txpower command for current channel to ucode */
+ return iwl_hw_reg_send_txpower(priv);
+}
+
+int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+{
+ struct iwl_channel_info *ch_info;
+ s8 max_power;
+ u8 a_band;
+ u8 i;
+
+ if (priv->user_txpower_limit == power) {
+ IWL_DEBUG_POWER("Requested Tx power same as current "
+ "limit: %ddBm.\n", power);
+ return 0;
+ }
+
+ IWL_DEBUG_POWER("Setting upper limit clamp to %ddBm.\n", power);
+ priv->user_txpower_limit = power;
+
+ /* set up new Tx powers for each and every channel, 2.4 and 5.x */
+
+ for (i = 0; i < priv->channel_count; i++) {
+ ch_info = &priv->channel_info[i];
+ a_band = is_channel_a_band(ch_info);
+
+ /* find minimum power of all user and regulatory constraints
+ * (does not consider h/w clipping limitations) */
+ max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info);
+ max_power = min(power, max_power);
+ if (max_power != ch_info->curr_txpow) {
+ ch_info->curr_txpow = max_power;
+
+ /* this considers the h/w clipping limitations */
+ iwl_hw_reg_set_new_power(priv, ch_info);
+ }
+ }
+
+ /* update txpower settings for all channels,
+ * send to NIC if associated. */
+ is_temp_calib_needed(priv);
+ iwl_hw_reg_comp_txpower_temp(priv);
+
+ return 0;
+}
+
+/* will add 3945 channel switch cmd handling later */
+int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ return 0;
+}
+
+/**
+ * iwl3945_reg_txpower_periodic - called when time to check our temperature.
+ *
+ * -- reset periodic timer
+ * -- see if temp has changed enough to warrant re-calibration ... if so:
+ * -- correct coeffs for temp (can reset temp timer)
+ * -- save this temp as "last",
+ * -- send new set of gain settings to NIC
+ * NOTE: This should continue working, even when we're not associated,
+ * so we can keep our internal table of scan powers current. */
+void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
+{
+ /* This will kick in the "brute force"
+ * iwl_hw_reg_comp_txpower_temp() below */
+ if (!is_temp_calib_needed(priv))
+ goto reschedule;
+
+ /* Set up a new set of temp-adjusted TxPowers, send to NIC.
+ * This is based *only* on current temperature,
+ * ignoring any previous power measurements */
+ iwl_hw_reg_comp_txpower_temp(priv);
+
+ reschedule:
+ queue_delayed_work(priv->workqueue,
+ &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
+}
+
+void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ thermal_periodic.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl3945_reg_txpower_periodic(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+/**
+ * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4)
+ * for the channel.
+ *
+ * This function is used when initializing channel-info structs.
+ *
+ * NOTE: These channel groups do *NOT* match the bands above!
+ * These channel groups are based on factory-tested channels;
+ * on A-band, EEPROM's "group frequency" entries represent the top
+ * channel in each group 1-4. Group 5 All B/G channels are in group 0.
+ */
+static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv,
+ const struct iwl_channel_info *ch_info)
+{
+ struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
+ u8 group;
+ u16 group_index = 0; /* based on factory calib frequencies */
+ u8 grp_channel;
+
+ /* Find the group index for the channel ... don't use index 1(?) */
+ if (is_channel_a_band(ch_info)) {
+ for (group = 1; group < 5; group++) {
+ grp_channel = ch_grp[group].group_channel;
+ if (ch_info->channel <= grp_channel) {
+ group_index = group;
+ break;
+ }
+ }
+ /* group 4 has a few channels *above* its factory cal freq */
+ if (group == 5)
+ group_index = 4;
+ } else
+ group_index = 0; /* 2.4 GHz, group 0 */
+
+ IWL_DEBUG_POWER("Chnl %d mapped to grp %d\n", ch_info->channel,
+ group_index);
+ return group_index;
+}
+
+/**
+ * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index
+ *
+ * Interpolate to get nominal (i.e. at factory calibration temperature) index
+ * into radio/DSP gain settings table for requested power.
+ */
+static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv,
+ s8 requested_power,
+ s32 setting_index, s32 *new_index)
+{
+ const struct iwl_eeprom_txpower_group *chnl_grp = NULL;
+ s32 index0, index1;
+ s32 power = 2 * requested_power;
+ s32 i;
+ const struct iwl_eeprom_txpower_sample *samples;
+ s32 gains0, gains1;
+ s32 res;
+ s32 denominator;
+
+ chnl_grp = &priv->eeprom.groups[setting_index];
+ samples = chnl_grp->samples;
+ for (i = 0; i < 5; i++) {
+ if (power == samples[i].power) {
+ *new_index = samples[i].gain_index;
+ return 0;
+ }
+ }
+
+ if (power > samples[1].power) {
+ index0 = 0;
+ index1 = 1;
+ } else if (power > samples[2].power) {
+ index0 = 1;
+ index1 = 2;
+ } else if (power > samples[3].power) {
+ index0 = 2;
+ index1 = 3;
+ } else {
+ index0 = 3;
+ index1 = 4;
+ }
+
+ denominator = (s32) samples[index1].power - (s32) samples[index0].power;
+ if (denominator == 0)
+ return -EINVAL;
+ gains0 = (s32) samples[index0].gain_index * (1 << 19);
+ gains1 = (s32) samples[index1].gain_index * (1 << 19);
+ res = gains0 + (gains1 - gains0) *
+ ((s32) power - (s32) samples[index0].power) / denominator +
+ (1 << 18);
+ *new_index = res >> 19;
+ return 0;
+}
+
+static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv)
+{
+ u32 i;
+ s32 rate_index;
+ const struct iwl_eeprom_txpower_group *group;
+
+ IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n");
+
+ for (i = 0; i < IWL_NUM_TX_CALIB_GROUPS; i++) {
+ s8 *clip_pwrs; /* table of power levels for each rate */
+ s8 satur_pwr; /* saturation power for each chnl group */
+ group = &priv->eeprom.groups[i];
+
+ /* sanity check on factory saturation power value */
+ if (group->saturation_power < 40) {
+ IWL_WARNING("Error: saturation power is %d, "
+ "less than minimum expected 40\n",
+ group->saturation_power);
+ return;
+ }
+
+ /*
+ * Derive requested power levels for each rate, based on
+ * hardware capabilities (saturation power for band).
+ * Basic value is 3dB down from saturation, with further
+ * power reductions for highest 3 data rates. These
+ * backoffs provide headroom for high rate modulation
+ * power peaks, without too much distortion (clipping).
+ */
+ /* we'll fill in this array with h/w max power levels */
+ clip_pwrs = (s8 *) priv->clip_groups[i].clip_powers;
+
+ /* divide factory saturation power by 2 to find -3dB level */
+ satur_pwr = (s8) (group->saturation_power >> 1);
+
+ /* fill in channel group's nominal powers for each rate */
+ for (rate_index = 0;
+ rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) {
+ switch (rate_index) {
+ case IWL_RATE_36M_INDEX:
+ if (i == 0) /* B/G */
+ *clip_pwrs = satur_pwr;
+ else /* A */
+ *clip_pwrs = satur_pwr - 5;
+ break;
+ case IWL_RATE_48M_INDEX:
+ if (i == 0)
+ *clip_pwrs = satur_pwr - 7;
+ else
+ *clip_pwrs = satur_pwr - 10;
+ break;
+ case IWL_RATE_54M_INDEX:
+ if (i == 0)
+ *clip_pwrs = satur_pwr - 9;
+ else
+ *clip_pwrs = satur_pwr - 12;
+ break;
+ default:
+ *clip_pwrs = satur_pwr;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM
+ *
+ * Second pass (during init) to set up priv->channel_info
+ *
+ * Set up Tx-power settings in our channel info database for each VALID
+ * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values
+ * and current temperature.
+ *
+ * Since this is based on current temperature (at init time), these values may
+ * not be valid for very long, but it gives us a starting/default point,
+ * and allows us to active (i.e. using Tx) scan.
+ *
+ * This does *not* write values to NIC, just sets up our internal table.
+ */
+int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch_info = NULL;
+ struct iwl_channel_power_info *pwr_info;
+ int delta_index;
+ u8 rate_index;
+ u8 scan_tbl_index;
+ const s8 *clip_pwrs; /* array of power levels for each rate */
+ u8 gain, dsp_atten;
+ s8 power;
+ u8 pwr_index, base_pwr_index, a_band;
+ u8 i;
+ int temperature;
+
+ /* save temperature reference,
+ * so we can determine next time to calibrate */
+ temperature = iwl_hw_reg_txpower_get_temperature(priv);
+ priv->last_temperature = temperature;
+
+ iwl_hw_reg_init_channel_groups(priv);
+
+ /* initialize Tx power info for each and every channel, 2.4 and 5.x */
+ for (i = 0, ch_info = priv->channel_info; i < priv->channel_count;
+ i++, ch_info++) {
+ a_band = is_channel_a_band(ch_info);
+ if (!is_channel_valid(ch_info))
+ continue;
+
+ /* find this channel's channel group (*not* "band") index */
+ ch_info->group_index =
+ iwl_hw_reg_get_ch_grp_index(priv, ch_info);
+
+ /* Get this chnlgrp's rate->max/clip-powers table */
+ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+ /* calculate power index *adjustment* value according to
+ * diff between current temperature and factory temperature */
+ delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+ priv->eeprom.groups[ch_info->group_index].
+ temperature);
+
+ IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n",
+ ch_info->channel, delta_index, temperature +
+ IWL_TEMP_CONVERT);
+
+ /* set tx power value for all OFDM rates */
+ for (rate_index = 0; rate_index < IWL_OFDM_RATES;
+ rate_index++) {
+ s32 power_idx;
+ int rc;
+
+ /* use channel group's clip-power table,
+ * but don't exceed channel's max power */
+ s8 pwr = min(ch_info->max_power_avg,
+ clip_pwrs[rate_index]);
+
+ pwr_info = &ch_info->power_info[rate_index];
+
+ /* get base (i.e. at factory-measured temperature)
+ * power table index for this rate's power */
+ rc = iwl_hw_reg_get_matched_power_index(priv, pwr,
+ ch_info->group_index,
+ &power_idx);
+ if (rc) {
+ IWL_ERROR("Invalid power index\n");
+ return rc;
+ }
+ pwr_info->base_power_index = (u8) power_idx;
+
+ /* temperature compensate */
+ power_idx += delta_index;
+
+ /* stay within range of gain table */
+ power_idx = iwl_hw_reg_fix_power_index(power_idx);
+
+ /* fill 1 OFDM rate's iwl_channel_power_info struct */
+ pwr_info->requested_power = pwr;
+ pwr_info->power_table_index = (u8) power_idx;
+ pwr_info->tpc.tx_gain =
+ power_gain_table[a_band][power_idx].tx_gain;
+ pwr_info->tpc.dsp_atten =
+ power_gain_table[a_band][power_idx].dsp_atten;
+ }
+
+ /* set tx power for CCK rates, based on OFDM 12 Mbit settings*/
+ pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX];
+ power = pwr_info->requested_power +
+ IWL_CCK_FROM_OFDM_POWER_DIFF;
+ pwr_index = pwr_info->power_table_index +
+ IWL_CCK_FROM_OFDM_INDEX_DIFF;
+ base_pwr_index = pwr_info->base_power_index +
+ IWL_CCK_FROM_OFDM_INDEX_DIFF;
+
+ /* stay within table range */
+ pwr_index = iwl_hw_reg_fix_power_index(pwr_index);
+ gain = power_gain_table[a_band][pwr_index].tx_gain;
+ dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten;
+
+ /* fill each CCK rate's iwl_channel_power_info structure
+ * NOTE: All CCK-rate Txpwrs are the same for a given chnl!
+ * NOTE: CCK rates start at end of OFDM rates! */
+ for (rate_index = IWL_OFDM_RATES;
+ rate_index < IWL_RATE_COUNT; rate_index++) {
+ pwr_info = &ch_info->power_info[rate_index];
+ pwr_info->requested_power = power;
+ pwr_info->power_table_index = pwr_index;
+ pwr_info->base_power_index = base_pwr_index;
+ pwr_info->tpc.tx_gain = gain;
+ pwr_info->tpc.dsp_atten = dsp_atten;
+ }
+
+ /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
+ for (scan_tbl_index = 0;
+ scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
+ s32 actual_index = (scan_tbl_index == 0) ?
+ IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX;
+ iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+ actual_index, clip_pwrs, ch_info, a_band);
+ }
+ }
+
+ return 0;
+}
+
+int iwl_hw_rxq_stop(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0);
+ rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+ if (rc < 0)
+ IWL_ERROR("Can't stop Rx DMA.\n");
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ int rc;
+ unsigned long flags;
+ int txq_id = txq->q.id;
+
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0);
+ iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0);
+
+ iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id),
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
+ iwl_release_restricted_access(priv);
+
+ /* fake read to flush all prev. writes */
+ iwl_read32(priv, FH_TSSR_CBB_BASE);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_hw_get_rx_read(struct iwl_priv *priv)
+{
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ return le32_to_cpu(shared_data->rx_read_ptr[0]);
+}
+
+/**
+ * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
+ */
+int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
+{
+ int rc, i;
+ struct iwl_rate_scaling_cmd rate_cmd = {
+ .reserved = {0, 0, 0},
+ };
+ struct iwl_rate_scaling_info *table = rate_cmd.table;
+
+ for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) {
+ table[i].rate_n_flags =
+ iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0);
+ table[i].try_cnt = priv->retry_rate;
+ table[i].next_rate_index = iwl_get_prev_ieee_rate(i);
+ }
+
+ switch (priv->phymode) {
+ case MODE_IEEE80211A:
+ IWL_DEBUG_RATE("Select A mode rate scale\n");
+ /* If one of the following CCK rates is used,
+ * have it fall back to the 6M OFDM rate */
+ for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++)
+ table[i].next_rate_index = IWL_FIRST_OFDM_RATE;
+
+ /* Don't fall back to CCK rates */
+ table[IWL_RATE_12M_INDEX].next_rate_index = IWL_RATE_9M_INDEX;
+
+ /* Don't drop out of OFDM rates */
+ table[IWL_FIRST_OFDM_RATE].next_rate_index =
+ IWL_FIRST_OFDM_RATE;
+ break;
+
+ case MODE_IEEE80211B:
+ IWL_DEBUG_RATE("Select B mode rate scale\n");
+ /* If an OFDM rate is used, have it fall back to the
+ * 1M CCK rates */
+ for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; i++)
+ table[i].next_rate_index = IWL_FIRST_CCK_RATE;
+
+ /* CCK shouldn't fall back to OFDM... */
+ table[IWL_RATE_11M_INDEX].next_rate_index = IWL_RATE_5M_INDEX;
+ break;
+
+ default:
+ IWL_DEBUG_RATE("Select G mode rate scale\n");
+ break;
+ }
+
+ /* Update the rate scaling for control frame Tx */
+ rate_cmd.table_id = 0;
+ rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+ &rate_cmd);
+ if (rc)
+ return rc;
+
+ /* Update the rate scaling for data frame Tx */
+ rate_cmd.table_id = 1;
+ return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+ &rate_cmd);
+}
+
+int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+{
+ memset((void *)&priv->hw_setting, 0,
+ sizeof(struct iwl_driver_hw_info));
+
+ priv->hw_setting.shared_virt =
+ pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ &priv->hw_setting.shared_phys);
+
+ if (!priv->hw_setting.shared_virt) {
+ IWL_ERROR("failed to allocate pci memory\n");
+ mutex_unlock(&priv->mutex);
+ return -ENOMEM;
+ }
+
+ priv->hw_setting.ac_queue_count = AC_NUM;
+ priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE;
+ priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+ priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
+ priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+ priv->hw_setting.cck_flag = 0;
+ priv->hw_setting.max_stations = IWL3945_STATION_COUNT;
+ priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID;
+ return 0;
+}
+
+unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate)
+{
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ unsigned int frame_size;
+
+ tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u;
+ memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+ tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
+ tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ frame_size = iwl_fill_beacon_frame(priv,
+ tx_beacon_cmd->frame,
+ BROADCAST_ADDR,
+ sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+ BUG_ON(frame_size > MAX_MPDU_SIZE);
+ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+ tx_beacon_cmd->tx.rate = rate;
+ tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
+ TX_CMD_FLG_TSF_MSK);
+
+ /* supp_rates[0] == OFDM */
+ tx_beacon_cmd->tx.supp_rates[0] = IWL_OFDM_BASIC_RATES_MASK;
+
+ /* supp_rates[1] == CCK
+ *
+ * NOTE: IWL_*_RATES_MASK are not in the order that supp_rates
+ * expects so we have to shift them around.
+ *
+ * supp_rates expects:
+ * CCK rates are bit0..3
+ *
+ * However IWL_*_RATES_MASK has:
+ * CCK rates are bit8..11
+ */
+ tx_beacon_cmd->tx.supp_rates[1] =
+ (IWL_CCK_BASIC_RATES_MASK >> 8) & 0xF;
+
+ return (sizeof(struct iwl_tx_beacon_cmd) + frame_size);
+}
+
+void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+{
+ priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
+}
+
+void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+{
+ INIT_DELAYED_WORK(&priv->thermal_periodic,
+ iwl3945_bg_reg_txpower_periodic);
+}
+
+void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+{
+ cancel_delayed_work(&priv->thermal_periodic);
+}
+
+struct pci_device_id iwl_hw_card_ids[] = {
+ {0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
+};
+
+inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+{
+ _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
new file mode 100644
index 000000000000..813902e9f8c2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_h__
+#define __iwl_3945_h__
+
+/*
+ * Forward declare iwl-3945.c functions for iwl-base.c
+ */
+extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
+extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
+extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
+extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
+extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work);
+extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
+extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
+ u16 tx_rate, u8 flags);
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
new file mode 100644
index 000000000000..99a19ef4c743
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -0,0 +1,581 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_4965_hw_h__
+#define __iwl_4965_hw_h__
+
+#define IWL_RX_BUF_SIZE (4 * 1024)
+#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
+#define KDR_RTC_INST_UPPER_BOUND (0x018000)
+#define KDR_RTC_DATA_UPPER_BOUND (0x80A000)
+#define KDR_RTC_INST_SIZE (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define KDR_RTC_DATA_SIZE (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE
+
+static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+{
+ return (addr >= RTC_DATA_LOWER_BOUND) &&
+ (addr < KDR_RTC_DATA_UPPER_BOUND);
+}
+
+/********************* START TXPOWER *****************************************/
+enum {
+ HT_IE_EXT_CHANNEL_NONE = 0,
+ HT_IE_EXT_CHANNEL_ABOVE,
+ HT_IE_EXT_CHANNEL_INVALID,
+ HT_IE_EXT_CHANNEL_BELOW,
+ HT_IE_EXT_CHANNEL_MAX
+};
+
+enum {
+ CALIB_CH_GROUP_1 = 0,
+ CALIB_CH_GROUP_2 = 1,
+ CALIB_CH_GROUP_3 = 2,
+ CALIB_CH_GROUP_4 = 3,
+ CALIB_CH_GROUP_5 = 4,
+ CALIB_CH_GROUP_MAX
+};
+
+/* Temperature calibration offset is 3% 0C in Kelvin */
+#define TEMPERATURE_CALIB_KELVIN_OFFSET 8
+#define TEMPERATURE_CALIB_A_VAL 259
+
+#define IWL_TX_POWER_TEMPERATURE_MIN (263)
+#define IWL_TX_POWER_TEMPERATURE_MAX (410)
+
+#define IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(t) \
+ (((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \
+ ((t) > IWL_TX_POWER_TEMPERATURE_MAX))
+
+#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300)
+
+#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2)
+
+#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
+
+#define IWL_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm = 1 milliwatt */
+#define IWL_TX_POWER_TARGET_POWER_MAX (16) /* 16 dBm */
+
+/* timeout equivalent to 3 minutes */
+#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000
+
+#define IWL_TX_POWER_CCK_COMPENSATION (9)
+
+#define MIN_TX_GAIN_INDEX (0)
+#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9)
+#define MAX_TX_GAIN_INDEX_52GHZ (98)
+#define MIN_TX_GAIN_52GHZ (98)
+#define MAX_TX_GAIN_INDEX_24GHZ (98)
+#define MIN_TX_GAIN_24GHZ (98)
+#define MAX_TX_GAIN (0)
+#define MAX_TX_GAIN_52GHZ_EXT (-9)
+
+#define IWL_TX_POWER_DEFAULT_REGULATORY_24 (34)
+#define IWL_TX_POWER_DEFAULT_REGULATORY_52 (34)
+#define IWL_TX_POWER_REGULATORY_MIN (0)
+#define IWL_TX_POWER_REGULATORY_MAX (34)
+#define IWL_TX_POWER_DEFAULT_SATURATION_24 (38)
+#define IWL_TX_POWER_DEFAULT_SATURATION_52 (38)
+#define IWL_TX_POWER_SATURATION_MIN (20)
+#define IWL_TX_POWER_SATURATION_MAX (50)
+
+/* dv *0.4 = dt; so that 5 degrees temperature diff equals
+ * 12.5 in voltage diff */
+#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9
+
+#define IWL_INVALID_CHANNEL (0xffffffff)
+#define IWL_TX_POWER_REGITRY_BIT (2)
+
+#define MIN_IWL_TX_POWER_CALIB_DUR (100)
+#define IWL_CCK_FROM_OFDM_POWER_DIFF (-5)
+#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9)
+
+/* Number of entries in the gain table */
+#define POWER_GAIN_NUM_ENTRIES 78
+#define TX_POW_MAX_SESSION_NUM 5
+/* timeout equivalent to 3 minutes */
+#define TX_IWL_TIMELIMIT_NOCALIB 1800000000
+
+/* Kedron TX_CALIB_STATES */
+#define IWL_TX_CALIB_STATE_SEND_TX 0x00000001
+#define IWL_TX_CALIB_WAIT_TX_RESPONSE 0x00000002
+#define IWL_TX_CALIB_ENABLED 0x00000004
+#define IWL_TX_CALIB_XVT_ON 0x00000008
+#define IWL_TX_CALIB_TEMPERATURE_CORRECT 0x00000010
+#define IWL_TX_CALIB_WORKING_WITH_XVT 0x00000020
+#define IWL_TX_CALIB_XVT_PERIODICAL 0x00000040
+
+#define NUM_IWL_TX_CALIB_SETTINS 5 /* Number of tx correction groups */
+
+#define IWL_MIN_POWER_IN_VP_TABLE 1 /* 0.5dBm multiplied by 2 */
+#define IWL_MAX_POWER_IN_VP_TABLE 40 /* 20dBm - multiplied by 2 (because
+ * entries are for each 0.5dBm) */
+#define IWL_STEP_IN_VP_TABLE 1 /* 0.5dB - multiplied by 2 */
+#define IWL_NUM_POINTS_IN_VPTABLE \
+ (1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE)
+
+#define MIN_TX_GAIN_INDEX (0)
+#define MAX_TX_GAIN_INDEX_52GHZ (98)
+#define MIN_TX_GAIN_52GHZ (98)
+#define MAX_TX_GAIN_INDEX_24GHZ (98)
+#define MIN_TX_GAIN_24GHZ (98)
+#define MAX_TX_GAIN (0)
+
+/* First and last channels of all groups */
+#define CALIB_IWL_TX_ATTEN_GR1_FCH 34
+#define CALIB_IWL_TX_ATTEN_GR1_LCH 43
+#define CALIB_IWL_TX_ATTEN_GR2_FCH 44
+#define CALIB_IWL_TX_ATTEN_GR2_LCH 70
+#define CALIB_IWL_TX_ATTEN_GR3_FCH 71
+#define CALIB_IWL_TX_ATTEN_GR3_LCH 124
+#define CALIB_IWL_TX_ATTEN_GR4_FCH 125
+#define CALIB_IWL_TX_ATTEN_GR4_LCH 200
+#define CALIB_IWL_TX_ATTEN_GR5_FCH 1
+#define CALIB_IWL_TX_ATTEN_GR5_LCH 20
+
+
+union iwl_tx_power_dual_stream {
+ struct {
+ u8 radio_tx_gain[2];
+ u8 dsp_predis_atten[2];
+ } s;
+ u32 dw;
+};
+
+/********************* END TXPOWER *****************************************/
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1<<22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS (23)
+
+#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1<<23)
+#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2<<23)
+
+#define RXON_FLG_CHANNEL_MODE_POS (25)
+#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3<<25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1<<25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2<<25)
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1<<0)
+#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7<<1)
+#define RXON_RX_CHAIN_VALID_POS (1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7<<4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS (4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7<<7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7)
+#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3<<10)
+#define RXON_RX_CHAIN_CNT_POS (10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3<<12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS (12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1<<14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS (14)
+
+
+#define MCS_DUP_6M_PLCP 0x20
+
+/* OFDM HT rate masks */
+/* ***************************************** */
+#define R_MCS_6M_MSK 0x1
+#define R_MCS_12M_MSK 0x2
+#define R_MCS_18M_MSK 0x4
+#define R_MCS_24M_MSK 0x8
+#define R_MCS_36M_MSK 0x10
+#define R_MCS_48M_MSK 0x20
+#define R_MCS_54M_MSK 0x40
+#define R_MCS_60M_MSK 0x80
+#define R_MCS_12M_DUAL_MSK 0x100
+#define R_MCS_24M_DUAL_MSK 0x200
+#define R_MCS_36M_DUAL_MSK 0x400
+#define R_MCS_48M_DUAL_MSK 0x800
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) (((tbl) == LQ_SISO))
+#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) (((tbl) == LQ_A))
+#define is_g_and(tbl) (((tbl) == LQ_G))
+
+/* Flow Handler Definitions */
+
+/**********************/
+/* Addresses */
+/**********************/
+
+#define FH_MEM_LOWER_BOUND (0x1000)
+#define FH_MEM_UPPER_BOUND (0x1EF0)
+
+#define IWL_FH_REGS_LOWER_BOUND (0x1000)
+#define IWL_FH_REGS_UPPER_BOUND (0x2000)
+
+#define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C)
+
+/* CBBC Area - Circular buffers base address cache pointers table */
+#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
+#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10)
+/* queues 0 - 15 */
+#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
+
+/* RSCSR Area */
+#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0)
+#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND)
+
+#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0)
+#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004)
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008)
+
+/* RCSR Area - Registers address map */
+#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0)
+#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND)
+
+#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0)
+
+/* RSSR Area - Rx shared ctrl & status registers */
+#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40)
+#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00)
+#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND)
+#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004)
+#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008)
+
+/* TCSR */
+#define IWL_FH_TCSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xD00)
+#define IWL_FH_TCSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xE60)
+
+#define IWL_FH_TCSR_CHNL_NUM (7)
+#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
+ (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+
+/* TSSR Area - Tx shared status registers */
+/* TSSR */
+#define IWL_FH_TSSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEA0)
+#define IWL_FH_TSSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEC0)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG (IWL_FH_TSSR_LOWER_BOUND + 0x008)
+#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B (0x00000000)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B (0x00000800)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B (0x00000C00)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005)
+
+#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \
+ ((1 << (_chnl)) << 24)
+#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \
+ ((1 << (_chnl)) << 16)
+
+#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
+ (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
+ IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
+
+/* TCSR: tx_config register values */
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC (0x00000002)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12)
+
+/* RCSR: channel 0 rx_config register defines */
+#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */
+#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */
+
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20)
+#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT (16)
+
+/* RCSR: rx_config register values */
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000)
+
+#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000)
+
+/* RCSR channel 0 config register values */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000)
+
+/* RSCSR: defs used in normal mode */
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK (0x00000FFF) /* bits 0-11 */
+
+#define SCD_WIN_SIZE 64
+#define SCD_FRAME_LIMIT 64
+
+/* memory mapped registers */
+#define SCD_START_OFFSET 0xa02c00
+
+#define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0)
+#define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4)
+#define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10)
+#define SCD_AIT (SCD_START_OFFSET + 0x18)
+#define SCD_TXFACT (SCD_START_OFFSET + 0x1c)
+#define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4)
+#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4)
+#define SCD_SETQUEUENUM (SCD_START_OFFSET + 0xa4)
+#define SCD_SET_TXSTAT_TXED (SCD_START_OFFSET + 0xa8)
+#define SCD_SET_TXSTAT_DONE (SCD_START_OFFSET + 0xac)
+#define SCD_SET_TXSTAT_NOT_SCHD (SCD_START_OFFSET + 0xb0)
+#define SCD_DECREASE_CREDIT (SCD_START_OFFSET + 0xb4)
+#define SCD_DECREASE_SCREDIT (SCD_START_OFFSET + 0xb8)
+#define SCD_LOAD_CREDIT (SCD_START_OFFSET + 0xbc)
+#define SCD_LOAD_SCREDIT (SCD_START_OFFSET + 0xc0)
+#define SCD_BAR (SCD_START_OFFSET + 0xc4)
+#define SCD_BAR_DW0 (SCD_START_OFFSET + 0xc8)
+#define SCD_BAR_DW1 (SCD_START_OFFSET + 0xcc)
+#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0)
+#define SCD_QUERY_REQ (SCD_START_OFFSET + 0xd8)
+#define SCD_QUERY_RES (SCD_START_OFFSET + 0xdc)
+#define SCD_PENDING_FRAMES (SCD_START_OFFSET + 0xe0)
+#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4)
+#define SCD_INTERRUPT_THRESHOLD (SCD_START_OFFSET + 0xe8)
+#define SCD_QUERY_MIN_FRAME_SIZE (SCD_START_OFFSET + 0x100)
+#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4)
+
+/* SRAM structures */
+#define SCD_CONTEXT_DATA_OFFSET 0x380
+#define SCD_TX_STTS_BITMAP_OFFSET 0x400
+#define SCD_TRANSLATE_TBL_OFFSET 0x500
+#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+ ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+
+#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
+ ((1<<(hi))|((1<<(hi))-(1<<(lo))))
+
+
+#define SCD_MODE_REG_BIT_SEARCH_MODE (1<<0)
+#define SCD_MODE_REG_BIT_SBYP_MODE (1<<1)
+
+#define SCD_TXFIFO_POS_TID (0)
+#define SCD_TXFIFO_POS_RA (4)
+#define SCD_QUEUE_STTS_REG_POS_ACTIVE (0)
+#define SCD_QUEUE_STTS_REG_POS_TXF (1)
+#define SCD_QUEUE_STTS_REG_POS_WSL (5)
+#define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8)
+#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10)
+#define SCD_QUEUE_STTS_REG_MSK (0x0007FC00)
+
+#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
+
+#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0)
+#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F)
+#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
+#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
+#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24)
+#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000)
+#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
+#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
+
+#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
+
+static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+{
+ return le32_to_cpu(rate_n_flags) & 0xFF;
+}
+static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags)
+{
+ return le32_to_cpu(rate_n_flags) & 0xFFFF;
+}
+static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+ return cpu_to_le32(flags|(u16)rate);
+}
+
+struct iwl_tfd_frame_data {
+ __le32 tb1_addr;
+
+ __le32 val1;
+ /* __le32 ptb1_32_35:4; */
+#define IWL_tb1_addr_hi_POS 0
+#define IWL_tb1_addr_hi_LEN 4
+#define IWL_tb1_addr_hi_SYM val1
+ /* __le32 tb_len1:12; */
+#define IWL_tb1_len_POS 4
+#define IWL_tb1_len_LEN 12
+#define IWL_tb1_len_SYM val1
+ /* __le32 ptb2_0_15:16; */
+#define IWL_tb2_addr_lo16_POS 16
+#define IWL_tb2_addr_lo16_LEN 16
+#define IWL_tb2_addr_lo16_SYM val1
+
+ __le32 val2;
+ /* __le32 ptb2_16_35:20; */
+#define IWL_tb2_addr_hi20_POS 0
+#define IWL_tb2_addr_hi20_LEN 20
+#define IWL_tb2_addr_hi20_SYM val2
+ /* __le32 tb_len2:12; */
+#define IWL_tb2_len_POS 20
+#define IWL_tb2_len_LEN 12
+#define IWL_tb2_len_SYM val2
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame {
+ __le32 val0;
+ /* __le32 rsvd1:24; */
+ /* __le32 num_tbs:5; */
+#define IWL_num_tbs_POS 24
+#define IWL_num_tbs_LEN 5
+#define IWL_num_tbs_SYM val0
+ /* __le32 rsvd2:1; */
+ /* __le32 padding:2; */
+ struct iwl_tfd_frame_data pa[10];
+ __le32 reserved;
+} __attribute__ ((packed));
+
+#define IWL4965_MAX_WIN_SIZE 64
+#define IWL4965_QUEUE_SIZE 256
+#define IWL4965_NUM_FIFOS 7
+#define IWL_MAX_NUM_QUEUES 16
+
+struct iwl4965_queue_byte_cnt_entry {
+ __le16 val;
+ /* __le16 byte_cnt:12; */
+#define IWL_byte_cnt_POS 0
+#define IWL_byte_cnt_LEN 12
+#define IWL_byte_cnt_SYM val
+ /* __le16 rsvd:4; */
+} __attribute__ ((packed));
+
+struct iwl4965_sched_queue_byte_cnt_tbl {
+ struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
+ IWL4965_MAX_WIN_SIZE];
+ u8 dont_care[1024 -
+ (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) *
+ sizeof(__le16)];
+} __attribute__ ((packed));
+
+/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR
+ * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
+struct iwl_shared {
+ struct iwl4965_sched_queue_byte_cnt_tbl
+ queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
+ __le32 val0;
+
+ /* __le32 rb_closed_stts_rb_num:12; */
+#define IWL_rb_closed_stts_rb_num_POS 0
+#define IWL_rb_closed_stts_rb_num_LEN 12
+#define IWL_rb_closed_stts_rb_num_SYM val0
+ /* __le32 rsrv1:4; */
+ /* __le32 rb_closed_stts_rx_frame_num:12; */
+#define IWL_rb_closed_stts_rx_frame_num_POS 16
+#define IWL_rb_closed_stts_rx_frame_num_LEN 12
+#define IWL_rb_closed_stts_rx_frame_num_SYM val0
+ /* __le32 rsrv2:4; */
+
+ __le32 val1;
+ /* __le32 frame_finished_stts_rb_num:12; */
+#define IWL_frame_finished_stts_rb_num_POS 0
+#define IWL_frame_finished_stts_rb_num_LEN 12
+#define IWL_frame_finished_stts_rb_num_SYM val1
+ /* __le32 rsrv3:4; */
+ /* __le32 frame_finished_stts_rx_frame_num:12; */
+#define IWL_frame_finished_stts_rx_frame_num_POS 16
+#define IWL_frame_finished_stts_rx_frame_num_LEN 12
+#define IWL_frame_finished_stts_rx_frame_num_SYM val1
+ /* __le32 rsrv4:4; */
+
+ __le32 padding1; /* so that allocation will be aligned to 16B */
+ __le32 padding2;
+} __attribute__ ((packed));
+
+#endif /* __iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
new file mode 100644
index 000000000000..287c75705c44
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -0,0 +1,2295 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <net/ieee80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#include <net/mac80211.h>
+#include <linux/wireless.h>
+
+#define IWL 4965
+
+#include "../net/mac80211/ieee80211_rate.h"
+
+#include "iwlwifi.h"
+#include "iwl-helpers.h"
+
+#define RS_NAME "iwl-4965-rs"
+
+#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1
+#define IWL_NUMBER_TRY 1
+#define IWL_HT_NUMBER_TRY 3
+
+#define IWL_RATE_MAX_WINDOW 62
+#define IWL_RATE_HIGH_TH 10880
+#define IWL_RATE_MIN_FAILURE_TH 6
+#define IWL_RATE_MIN_SUCCESS_TH 8
+#define IWL_RATE_DECREASE_TH 1920
+#define IWL_RATE_INCREASE_TH 8960
+#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) /*2 seconds */
+
+static u8 rs_ht_to_legacy[] = {
+ IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+struct iwl_rate {
+ u32 rate_n_flags;
+} __attribute__ ((packed));
+
+struct iwl_rate_scale_data {
+ u64 data;
+ s32 success_counter;
+ s32 success_ratio;
+ s32 counter;
+ s32 average_tpt;
+ unsigned long stamp;
+};
+
+struct iwl_scale_tbl_info {
+ enum iwl_table_type lq_type;
+ enum iwl_antenna_type antenna_type;
+ u8 is_SGI;
+ u8 is_fat;
+ u8 is_dup;
+ u8 action;
+ s32 *expected_tpt;
+ struct iwl_rate current_rate;
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+};
+
+struct iwl_rate_scale_priv {
+ u8 active_tbl;
+ u8 enable_counter;
+ u8 stay_in_tbl;
+ u8 search_better_tbl;
+ s32 last_tpt;
+ u32 table_count_limit;
+ u32 max_failure_limit;
+ u32 max_success_limit;
+ u32 table_count;
+ u32 total_failed;
+ u32 total_success;
+ u32 flush_timer;
+ u8 action_counter;
+ u8 antenna;
+ u8 valid_antenna;
+ u8 is_green;
+ u8 is_dup;
+ u8 phymode;
+ u8 ibss_sta_added;
+ u32 supp_rates;
+ u16 active_rate;
+ u16 active_siso_rate;
+ u16 active_mimo_rate;
+ u16 active_rate_basic;
+ struct iwl_link_quality_cmd lq;
+ struct iwl_scale_tbl_info lq_info[LQ_SIZE];
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *rs_sta_dbgfs_scale_table_file;
+ struct dentry *rs_sta_dbgfs_stats_table_file;
+ struct iwl_rate dbg_fixed;
+ struct iwl_priv *drv;
+#endif
+};
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+ struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ struct sta_info *sta);
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_rate *tx_mcs,
+ struct iwl_link_quality_cmd *tbl);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index)
+{}
+#endif
+static s32 expected_tpt_A[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
+};
+
+static s32 expected_tpt_G[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186
+};
+
+static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202
+};
+
+static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
+};
+
+static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
+};
+
+static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
+};
+
+static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
+};
+
+static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
+};
+
+static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
+};
+
+static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
+};
+
+static int iwl_lq_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ /*We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+static inline u8 iwl_rate_get_rate(u32 rate_n_flags)
+{
+ return (u8)(rate_n_flags & 0xFF);
+}
+
+static int rs_send_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq, u8 flags)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ int i;
+#endif
+ int rc = -1;
+
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_TX_LINK_QUALITY_CMD,
+ .len = sizeof(struct iwl_link_quality_cmd),
+ .meta.flags = flags,
+ .data = lq,
+ };
+
+ if ((lq->sta_id == 0xFF) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ return rc;
+
+ if (lq->sta_id == 0xFF)
+ lq->sta_id = IWL_AP_ID;
+
+ IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
+ IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
+ lq->general_params.single_stream_ant_msk,
+ lq->general_params.dual_stream_ant_msk);
+#ifdef CONFIG_IWLWIFI_DEBUG
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ IWL_DEBUG_RATE("lq index %d 0x%X\n",
+ i, lq->rs_table[i].rate_n_flags);
+#endif
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_lq_sync_callback;
+
+ if (iwl_is_associated(priv) && priv->assoc_station_added &&
+ priv->lq_mngr.lq_ready)
+ rc = iwl_send_cmd(priv, &cmd);
+
+ return rc;
+}
+
+static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+ window->data = 0;
+ window->success_counter = 0;
+ window->success_ratio = IWL_INVALID_VALUE;
+ window->counter = 0;
+ window->average_tpt = IWL_INVALID_VALUE;
+ window->stamp = 0;
+
+ return 0;
+}
+
+static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
+ int scale_index, s32 tpt, u32 status)
+{
+ int rc = 0;
+ struct iwl_rate_scale_data *window = NULL;
+ u64 mask;
+ u8 win_size = IWL_RATE_MAX_WINDOW;
+ s32 fail_count;
+
+ if (scale_index < 0)
+ return -1;
+
+ if (scale_index >= IWL_RATE_COUNT)
+ return -1;
+
+ window = &(windows[scale_index]);
+
+ if (window->counter >= win_size) {
+
+ window->counter = win_size - 1;
+ mask = 1;
+ mask = (mask << (win_size - 1));
+ if ((window->data & mask)) {
+ window->data &= ~mask;
+ window->success_counter = window->success_counter - 1;
+ }
+ }
+
+ window->counter = window->counter + 1;
+ mask = window->data;
+ window->data = (mask << 1);
+ if (status != 0) {
+ window->success_counter = window->success_counter + 1;
+ window->data |= 0x1;
+ }
+
+ if (window->counter > 0)
+ window->success_ratio = 128 * (100 * window->success_counter)
+ / window->counter;
+ else
+ window->success_ratio = IWL_INVALID_VALUE;
+
+ fail_count = window->counter - window->success_counter;
+
+ if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+ (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+ window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+ else
+ window->average_tpt = IWL_INVALID_VALUE;
+
+ window->stamp = jiffies;
+
+ return rc;
+}
+
+int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 use_green)
+{
+ int rc = 0;
+
+ if (is_legacy(tbl->lq_type)) {
+ mcs_rate->rate_n_flags = iwl_rates[index].plcp;
+ if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+ mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
+
+ } else if (is_siso(tbl->lq_type)) {
+ if (index > IWL_LAST_OFDM_RATE)
+ index = IWL_LAST_OFDM_RATE;
+ mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso |
+ RATE_MCS_HT_MSK;
+ } else {
+ if (index > IWL_LAST_OFDM_RATE)
+ index = IWL_LAST_OFDM_RATE;
+ mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo |
+ RATE_MCS_HT_MSK;
+ }
+
+ switch (tbl->antenna_type) {
+ case ANT_BOTH:
+ mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK;
+ break;
+ case ANT_MAIN:
+ mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
+ break;
+ case ANT_AUX:
+ mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
+ break;
+ case ANT_NONE:
+ break;
+ }
+
+ if (is_legacy(tbl->lq_type))
+ return rc;
+
+ if (tbl->is_fat) {
+ if (tbl->is_dup)
+ mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;
+ else
+ mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
+ }
+ if (tbl->is_SGI)
+ mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK;
+
+ if (use_green) {
+ mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK;
+ if (is_siso(tbl->lq_type))
+ mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
+ }
+ return rc;
+}
+
+static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
+ int phymode, struct iwl_scale_tbl_info *tbl,
+ int *rate_idx)
+{
+ int index;
+ u32 ant_msk;
+
+ index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags);
+
+ if (index == IWL_RATE_INVALID) {
+ *rate_idx = -1;
+ return -1;
+ }
+ tbl->is_SGI = 0;
+ tbl->is_fat = 0;
+ tbl->is_dup = 0;
+ tbl->antenna_type = ANT_BOTH;
+
+ if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
+ ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
+
+ if (ant_msk == RATE_MCS_ANT_AB_MSK)
+ tbl->lq_type = LQ_NONE;
+ else {
+
+ if (phymode == MODE_IEEE80211A)
+ tbl->lq_type = LQ_A;
+ else
+ tbl->lq_type = LQ_G;
+
+ if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
+ tbl->antenna_type = ANT_MAIN;
+ else
+ tbl->antenna_type = ANT_AUX;
+ }
+ *rate_idx = index;
+
+ } else if (iwl_rate_get_rate(mcs_rate->rate_n_flags)
+ <= IWL_RATE_SISO_60M_PLCP) {
+ tbl->lq_type = LQ_SISO;
+
+ ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
+ if (ant_msk == RATE_MCS_ANT_AB_MSK)
+ tbl->lq_type = LQ_NONE;
+ else {
+ if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
+ tbl->antenna_type = ANT_MAIN;
+ else
+ tbl->antenna_type = ANT_AUX;
+ }
+ if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+ tbl->is_SGI = 1;
+
+ if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
+ (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+ tbl->is_fat = 1;
+
+ if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+ tbl->is_dup = 1;
+
+ *rate_idx = index;
+ } else {
+ tbl->lq_type = LQ_MIMO;
+ if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+ tbl->is_SGI = 1;
+
+ if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
+ (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+ tbl->is_fat = 1;
+
+ if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+ tbl->is_dup = 1;
+ *rate_idx = index;
+ }
+ return 0;
+}
+
+static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
+ struct iwl_scale_tbl_info *tbl)
+{
+ if (tbl->antenna_type == ANT_AUX) {
+ tbl->antenna_type = ANT_MAIN;
+ new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK;
+ new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
+ } else {
+ tbl->antenna_type = ANT_AUX;
+ new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+ new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
+ }
+}
+
+static inline s8 rs_use_green(struct iwl_priv *priv)
+{
+ s8 rc = 0;
+#ifdef CONFIG_IWLWIFI_HT
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+ return 0;
+
+ if ((priv->current_assoc_ht.is_green_field) &&
+ !(priv->current_assoc_ht.operating_mode & 0x4))
+ rc = 1;
+#endif /*CONFIG_IWLWIFI_HT */
+ return rc;
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,
+ struct ieee80211_hdr *hdr,
+ enum iwl_table_type rate_type,
+ u16 *data_rate)
+{
+ if (is_legacy(rate_type))
+ *data_rate = lq_data->active_rate;
+ else {
+ if (is_siso(rate_type))
+ *data_rate = lq_data->active_siso_rate;
+ else
+ *data_rate = lq_data->active_mimo_rate;
+ }
+
+ if (hdr && is_multicast_ether_addr(hdr->addr1) &&
+ lq_data->active_rate_basic)
+ *data_rate = lq_data->active_rate_basic;
+}
+
+static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
+{
+ u8 high = IWL_RATE_INVALID;
+ u8 low = IWL_RATE_INVALID;
+
+ /* 802.11A or ht walks to the next literal adjascent rate in
+ * the rate table */
+ if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+ int i;
+ u32 mask;
+
+ /* Find the previous rate that is in the rate mask */
+ i = index - 1;
+ for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (rate_mask & mask) {
+ low = i;
+ break;
+ }
+ }
+
+ /* Find the next rate that is in the rate mask */
+ i = index + 1;
+ for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+ if (rate_mask & mask) {
+ high = i;
+ break;
+ }
+ }
+
+ return (high << 8) | low;
+ }
+
+ low = index;
+ while (low != IWL_RATE_INVALID) {
+ low = iwl_rates[low].prev_rs;
+ if (low == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << low))
+ break;
+ IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
+ }
+
+ high = index;
+ while (high != IWL_RATE_INVALID) {
+ high = iwl_rates[high].next_rs;
+ if (high == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << high))
+ break;
+ IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
+ }
+
+ return (high << 8) | low;
+}
+
+static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl, u8 scale_index,
+ u8 ht_possible, struct iwl_rate *mcs_rate)
+{
+ s32 low;
+ u16 rate_mask;
+ u16 high_low;
+ u8 switch_to_legacy = 0;
+ u8 is_green = lq_data->is_green;
+
+ /* check if we need to switch from HT to legacy rates.
+ * assumption is that mandatory rates (1Mbps or 6Mbps)
+ * are always supported (spec demand) */
+ if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+ switch_to_legacy = 1;
+ scale_index = rs_ht_to_legacy[scale_index];
+ if (lq_data->phymode == MODE_IEEE80211A)
+ tbl->lq_type = LQ_A;
+ else
+ tbl->lq_type = LQ_G;
+
+ if ((tbl->antenna_type == ANT_BOTH) ||
+ (tbl->antenna_type == ANT_NONE))
+ tbl->antenna_type = ANT_MAIN;
+
+ tbl->is_fat = 0;
+ tbl->is_SGI = 0;
+ }
+
+ rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask);
+
+ /* mask with station rate restriction */
+ if (is_legacy(tbl->lq_type)) {
+ if (lq_data->phymode == (u8) MODE_IEEE80211A)
+ rate_mask = (u16)(rate_mask &
+ (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+ else
+ rate_mask = (u16)(rate_mask & lq_data->supp_rates);
+ }
+
+ /* if we did switched from HT to legacy check current rate */
+ if ((switch_to_legacy) &&
+ (rate_mask & (1 << scale_index))) {
+ rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+ return 0;
+ }
+
+ high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
+ low = high_low & 0xff;
+
+ if (low != IWL_RATE_INVALID)
+ rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
+ else
+ rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+
+ return 0;
+}
+
+static void rs_tx_status(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *tx_resp)
+{
+ int status;
+ u8 retries;
+ int rs_index, index = 0;
+ struct iwl_rate_scale_priv *lq;
+ struct iwl_link_quality_cmd *table;
+ struct sta_info *sta;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iwl_rate_scale_data *window = NULL;
+ struct iwl_rate_scale_data *search_win = NULL;
+ struct iwl_rate tx_mcs;
+ struct iwl_scale_tbl_info tbl_type;
+ struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
+ u8 active_index = 0;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ s32 tpt = 0;
+
+ IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
+
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+ return;
+
+ retries = tx_resp->retry_count;
+
+ if (retries > 15)
+ retries = 15;
+
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ return;
+ }
+
+ lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+
+ if (!priv->lq_mngr.lq_ready)
+ return;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added)
+ return;
+
+ table = &lq->lq;
+ active_index = lq->active_tbl;
+
+ lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx);
+ if (!lq->antenna)
+ lq->antenna = lq->valid_antenna;
+
+ lq->antenna = lq->valid_antenna;
+ curr_tbl = &(lq->lq_info[active_index]);
+ search_tbl = &(lq->lq_info[(1 - active_index)]);
+ window = (struct iwl_rate_scale_data *)
+ &(curr_tbl->win[0]);
+ search_win = (struct iwl_rate_scale_data *)
+ &(search_tbl->win[0]);
+
+ tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
+
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ &tbl_type, &rs_index);
+ if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
+ IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
+ rs_index, tx_mcs.rate_n_flags);
+ sta_info_put(sta);
+ return;
+ }
+
+ if (retries &&
+ (tx_mcs.rate_n_flags !=
+ le32_to_cpu(table->rs_table[0].rate_n_flags))) {
+ IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
+ tx_mcs.rate_n_flags,
+ le32_to_cpu(table->rs_table[0].rate_n_flags));
+ sta_info_put(sta);
+ return;
+ }
+
+ while (retries) {
+ tx_mcs.rate_n_flags =
+ le32_to_cpu(table->rs_table[index].rate_n_flags);
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ &tbl_type, &rs_index);
+
+ if ((tbl_type.lq_type == search_tbl->lq_type) &&
+ (tbl_type.antenna_type == search_tbl->antenna_type) &&
+ (tbl_type.is_SGI == search_tbl->is_SGI)) {
+ if (search_tbl->expected_tpt)
+ tpt = search_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(search_win,
+ rs_index, tpt, 0);
+ } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
+ (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+ (tbl_type.is_SGI == curr_tbl->is_SGI)) {
+ if (curr_tbl->expected_tpt)
+ tpt = curr_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(window, rs_index, tpt, 0);
+ }
+ if (lq->stay_in_tbl)
+ lq->total_failed++;
+ --retries;
+ index++;
+
+ }
+
+ if (!tx_resp->retry_count)
+ tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
+ else
+ tx_mcs.rate_n_flags =
+ le32_to_cpu(table->rs_table[index].rate_n_flags);
+
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ &tbl_type, &rs_index);
+
+ if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
+ status = 1;
+ else
+ status = 0;
+
+ if ((tbl_type.lq_type == search_tbl->lq_type) &&
+ (tbl_type.antenna_type == search_tbl->antenna_type) &&
+ (tbl_type.is_SGI == search_tbl->is_SGI)) {
+ if (search_tbl->expected_tpt)
+ tpt = search_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(search_win,
+ rs_index, tpt, status);
+ } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
+ (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+ (tbl_type.is_SGI == curr_tbl->is_SGI)) {
+ if (curr_tbl->expected_tpt)
+ tpt = curr_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(window, rs_index, tpt, status);
+ }
+
+ if (lq->stay_in_tbl) {
+ if (status)
+ lq->total_success++;
+ else
+ lq->total_failed++;
+ }
+
+ rs_rate_scale_perform(priv, dev, hdr, sta);
+ sta_info_put(sta);
+ return;
+}
+
+static u8 rs_is_ant_connected(u8 valid_antenna,
+ enum iwl_antenna_type antenna_type)
+{
+ if (antenna_type == ANT_AUX)
+ return ((valid_antenna & 0x2) ? 1:0);
+ else if (antenna_type == ANT_MAIN)
+ return ((valid_antenna & 0x1) ? 1:0);
+ else if (antenna_type == ANT_BOTH) {
+ if ((valid_antenna & 0x3) == 0x3)
+ return 1;
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
+static u8 rs_is_other_ant_connected(u8 valid_antenna,
+ enum iwl_antenna_type antenna_type)
+{
+ if (antenna_type == ANT_AUX)
+ return (rs_is_ant_connected(valid_antenna, ANT_MAIN));
+ else
+ return (rs_is_ant_connected(valid_antenna, ANT_AUX));
+
+ return 0;
+}
+
+static void rs_set_stay_in_table(u8 is_legacy,
+ struct iwl_rate_scale_priv *lq_data)
+{
+ IWL_DEBUG_HT("we are staying in the same table\n");
+ lq_data->stay_in_tbl = 1;
+ if (is_legacy) {
+ lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+ lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+ lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT;
+ } else {
+ lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+ lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+ lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+ }
+ lq_data->table_count = 0;
+ lq_data->total_failed = 0;
+ lq_data->total_success = 0;
+}
+
+static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl)
+{
+ if (is_legacy(tbl->lq_type)) {
+ if (!is_a_band(tbl->lq_type))
+ tbl->expected_tpt = expected_tpt_G;
+ else
+ tbl->expected_tpt = expected_tpt_A;
+ } else if (is_siso(tbl->lq_type)) {
+ if (tbl->is_fat && !lq_data->is_dup)
+ if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_siso40MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_siso40MHz;
+ else if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_siso20MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_siso20MHz;
+
+ } else if (is_mimo(tbl->lq_type)) {
+ if (tbl->is_fat && !lq_data->is_dup)
+ if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_mimo40MHz;
+ else if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_mimo20MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_mimo20MHz;
+ } else
+ tbl->expected_tpt = expected_tpt_G;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+static s32 rs_get_best_rate(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl,
+ u16 rate_mask, s8 index, s8 rate)
+{
+ struct iwl_scale_tbl_info *active_tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ s32 new_rate, high, low, start_hi;
+ s32 active_sr = active_tbl->win[index].success_ratio;
+ s32 *tpt_tbl = tbl->expected_tpt;
+ s32 active_tpt = active_tbl->expected_tpt[index];
+ u16 high_low;
+
+ new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+ for (; ;) {
+ high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);
+
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) &&
+ ((active_sr > IWL_RATE_DECREASE_TH) &&
+ (active_sr <= IWL_RATE_HIGH_TH) &&
+ (tpt_tbl[rate] <= active_tpt))) ||
+ ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+ (tpt_tbl[rate] > active_tpt))) {
+
+ if (start_hi != IWL_RATE_INVALID) {
+ new_rate = start_hi;
+ break;
+ }
+ new_rate = rate;
+ if (low != IWL_RATE_INVALID)
+ rate = low;
+ else
+ break;
+ } else {
+ if (new_rate != IWL_RATE_INVALID)
+ break;
+ else if (high != IWL_RATE_INVALID) {
+ start_hi = high;
+ rate = high;
+ } else {
+ new_rate = rate;
+ break;
+ }
+ }
+ }
+
+ return new_rate;
+}
+#endif /* CONFIG_IWLWIFI_HT */
+
+static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
+{
+ return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
+}
+
+static int rs_switch_to_mimo(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ int rc = -1;
+#ifdef CONFIG_IWLWIFI_HT
+ u16 rate_mask;
+ s32 rate;
+ s8 is_green = lq_data->is_green;
+
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+ return -1;
+
+ IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
+ tbl->lq_type = LQ_MIMO;
+ rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+ &rate_mask);
+
+ if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+ return -1;
+
+ if (!rs_is_both_ant_supp(lq_data->antenna))
+ return -1;
+
+ rc = 0;
+ tbl->is_dup = lq_data->is_dup;
+ tbl->action = 0;
+ if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+ tbl->is_fat = 1;
+ else
+ tbl->is_fat = 0;
+
+ if (tbl->is_fat) {
+ if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+ } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+
+ rs_get_expected_tpt_table(lq_data, tbl);
+
+ rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
+ IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
+ return -1;
+ rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+
+ IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate.rate_n_flags, is_green);
+
+#endif /*CONFIG_IWLWIFI_HT */
+ return rc;
+}
+
+static int rs_switch_to_siso(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ int rc = -1;
+#ifdef CONFIG_IWLWIFI_HT
+ u16 rate_mask;
+ u8 is_green = lq_data->is_green;
+ s32 rate;
+
+ IWL_DEBUG_HT("LQ: try to switch to SISO\n");
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+ return -1;
+
+ rc = 0;
+ tbl->is_dup = lq_data->is_dup;
+ tbl->lq_type = LQ_SISO;
+ tbl->action = 0;
+ rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+ &rate_mask);
+
+ if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+ tbl->is_fat = 1;
+ else
+ tbl->is_fat = 0;
+
+ if (tbl->is_fat) {
+ if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+ } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+
+ if (is_green)
+ tbl->is_SGI = 0;
+
+ rs_get_expected_tpt_table(lq_data, tbl);
+ rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
+ IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_HT("can not switch with index %d rate mask %x\n",
+ rate, rate_mask);
+ return -1;
+ }
+ rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+ IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate.rate_n_flags, is_green);
+
+#endif /*CONFIG_IWLWIFI_HT */
+ return rc;
+}
+
+static int rs_move_legacy_other(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ int index)
+{
+ int rc = 0;
+ struct iwl_scale_tbl_info *tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+
+ for (; ;) {
+ switch (tbl->action) {
+ case IWL_LEGACY_SWITCH_ANTENNA:
+ IWL_DEBUG_HT("LQ Legacy switch Antenna\n");
+
+ search_tbl->lq_type = LQ_NONE;
+ lq_data->action_counter++;
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+ if (!rs_is_other_ant_connected(lq_data->antenna,
+ tbl->antenna_type))
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+
+ rs_toggle_antenna(&(search_tbl->current_rate),
+ search_tbl);
+ rs_get_expected_tpt_table(lq_data, search_tbl);
+ lq_data->search_better_tbl = 1;
+ goto out;
+
+ case IWL_LEGACY_SWITCH_SISO:
+ IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_SISO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ rc = rs_switch_to_siso(priv, lq_data, search_tbl,
+ index);
+ if (!rc) {
+ lq_data->search_better_tbl = 1;
+ lq_data->action_counter = 0;
+ }
+ if (!rc)
+ goto out;
+
+ break;
+ case IWL_LEGACY_SWITCH_MIMO:
+ IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_MIMO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ search_tbl->antenna_type = ANT_BOTH;
+ rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
+ index);
+ if (!rc) {
+ lq_data->search_better_tbl = 1;
+ lq_data->action_counter = 0;
+ }
+ if (!rc)
+ goto out;
+ break;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+
+ if (tbl->action == start_action)
+ break;
+
+ }
+ return 0;
+
+ out:
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+ return 0;
+
+}
+
+static int rs_move_siso_to_other(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ int index)
+{
+ int rc = -1;
+ u8 is_green = lq_data->is_green;
+ struct iwl_scale_tbl_info *tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+
+ for (;;) {
+ lq_data->action_counter++;
+ switch (tbl->action) {
+ case IWL_SISO_SWITCH_ANTENNA:
+ IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
+ search_tbl->lq_type = LQ_NONE;
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+ if (!rs_is_other_ant_connected(lq_data->antenna,
+ tbl->antenna_type))
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->action = IWL_SISO_SWITCH_MIMO;
+ rs_toggle_antenna(&(search_tbl->current_rate),
+ search_tbl);
+ lq_data->search_better_tbl = 1;
+
+ goto out;
+
+ case IWL_SISO_SWITCH_MIMO:
+ IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_MIMO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ search_tbl->antenna_type = ANT_BOTH;
+ rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
+ index);
+ if (!rc)
+ lq_data->search_better_tbl = 1;
+
+ if (!rc)
+ goto out;
+ break;
+ case IWL_SISO_SWITCH_GI:
+ IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->action = 0;
+ if (search_tbl->is_SGI)
+ search_tbl->is_SGI = 0;
+ else if (!is_green)
+ search_tbl->is_SGI = 1;
+ else
+ break;
+ lq_data->search_better_tbl = 1;
+ if ((tbl->lq_type == LQ_SISO) &&
+ (tbl->is_SGI)) {
+ s32 tpt = lq_data->last_tpt / 100;
+ if (((!tbl->is_fat) &&
+ (tpt >= expected_tpt_siso20MHz[index])) ||
+ ((tbl->is_fat) &&
+ (tpt >= expected_tpt_siso40MHz[index])))
+ lq_data->search_better_tbl = 0;
+ }
+ rs_get_expected_tpt_table(lq_data, search_tbl);
+ rs_mcs_from_tbl(&search_tbl->current_rate,
+ search_tbl, index, is_green);
+ goto out;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_SISO_SWITCH_GI)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ return 0;
+
+ out:
+ tbl->action++;
+ if (tbl->action > IWL_SISO_SWITCH_GI)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA;
+ return 0;
+}
+
+static int rs_move_mimo_to_other(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ int index)
+{
+ int rc = -1;
+ s8 is_green = lq_data->is_green;
+ struct iwl_scale_tbl_info *tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+
+ for (;;) {
+ lq_data->action_counter++;
+ switch (tbl->action) {
+ case IWL_MIMO_SWITCH_ANTENNA_A:
+ case IWL_MIMO_SWITCH_ANTENNA_B:
+ IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_SISO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)
+ search_tbl->antenna_type = ANT_MAIN;
+ else
+ search_tbl->antenna_type = ANT_AUX;
+
+ rc = rs_switch_to_siso(priv, lq_data, search_tbl,
+ index);
+ if (!rc) {
+ lq_data->search_better_tbl = 1;
+ goto out;
+ }
+ break;
+
+ case IWL_MIMO_SWITCH_GI:
+ IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_MIMO;
+ search_tbl->antenna_type = ANT_BOTH;
+ search_tbl->action = 0;
+ if (search_tbl->is_SGI)
+ search_tbl->is_SGI = 0;
+ else
+ search_tbl->is_SGI = 1;
+ lq_data->search_better_tbl = 1;
+ if ((tbl->lq_type == LQ_MIMO) &&
+ (tbl->is_SGI)) {
+ s32 tpt = lq_data->last_tpt / 100;
+ if (((!tbl->is_fat) &&
+ (tpt >= expected_tpt_mimo20MHz[index])) ||
+ ((tbl->is_fat) &&
+ (tpt >= expected_tpt_mimo40MHz[index])))
+ lq_data->search_better_tbl = 0;
+ }
+ rs_get_expected_tpt_table(lq_data, search_tbl);
+ rs_mcs_from_tbl(&search_tbl->current_rate,
+ search_tbl, index, is_green);
+ goto out;
+
+ }
+ tbl->action++;
+ if (tbl->action > IWL_MIMO_SWITCH_GI)
+ tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+
+ if (tbl->action == start_action)
+ break;
+ }
+
+ return 0;
+ out:
+ tbl->action++;
+ if (tbl->action > IWL_MIMO_SWITCH_GI)
+ tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+ return 0;
+
+}
+
+static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
+{
+ struct iwl_scale_tbl_info *tbl;
+ int i;
+ int active_tbl;
+ int flush_interval_passed = 0;
+
+ active_tbl = lq_data->active_tbl;
+
+ tbl = &(lq_data->lq_info[active_tbl]);
+
+ if (lq_data->stay_in_tbl) {
+
+ if (lq_data->flush_timer)
+ flush_interval_passed =
+ time_after(jiffies,
+ (unsigned long)(lq_data->flush_timer +
+ IWL_RATE_SCALE_FLUSH_INTVL));
+
+ flush_interval_passed = 0;
+ if ((lq_data->total_failed > lq_data->max_failure_limit) ||
+ (lq_data->total_success > lq_data->max_success_limit) ||
+ ((!lq_data->search_better_tbl) && (lq_data->flush_timer)
+ && (flush_interval_passed))) {
+ IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
+ lq_data->total_failed,
+ lq_data->total_success,
+ flush_interval_passed);
+ lq_data->stay_in_tbl = 0;
+ lq_data->total_failed = 0;
+ lq_data->total_success = 0;
+ lq_data->flush_timer = 0;
+ } else if (lq_data->table_count > 0) {
+ lq_data->table_count++;
+ if (lq_data->table_count >=
+ lq_data->table_count_limit) {
+ lq_data->table_count = 0;
+
+ IWL_DEBUG_HT("LQ: stay in table clear win\n");
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(
+ &(tbl->win[i]));
+ }
+ }
+
+ if (!lq_data->stay_in_tbl) {
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(tbl->win[i]));
+ }
+ }
+}
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+ struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ struct sta_info *sta)
+{
+ int low = IWL_RATE_INVALID;
+ int high = IWL_RATE_INVALID;
+ int index;
+ int i;
+ struct iwl_rate_scale_data *window = NULL;
+ int current_tpt = IWL_INVALID_VALUE;
+ int low_tpt = IWL_INVALID_VALUE;
+ int high_tpt = IWL_INVALID_VALUE;
+ u32 fail_count;
+ s8 scale_action = 0;
+ u16 fc, rate_mask;
+ u8 update_lq = 0;
+ struct iwl_rate_scale_priv *lq_data;
+ struct iwl_scale_tbl_info *tbl, *tbl1;
+ u16 rate_scale_index_msk = 0;
+ struct iwl_rate mcs_rate;
+ u8 is_green = 0;
+ u8 active_tbl = 0;
+ u8 done_search = 0;
+ u16 high_low;
+
+ IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ return;
+ }
+
+ if (!sta || !sta->rate_ctrl_priv)
+ return;
+
+ if (!priv->lq_mngr.lq_ready) {
+ IWL_DEBUG_RATE("still rate scaling not ready\n");
+ return;
+ }
+ lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+
+ if (!lq_data->search_better_tbl)
+ active_tbl = lq_data->active_tbl;
+ else
+ active_tbl = 1 - lq_data->active_tbl;
+
+ tbl = &(lq_data->lq_info[active_tbl]);
+ is_green = lq_data->is_green;
+
+ index = sta->last_txrate;
+
+ IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
+ tbl->lq_type);
+
+ rs_get_supported_rates(lq_data, hdr, tbl->lq_type,
+ &rate_mask);
+
+ IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);
+
+ /* mask with station rate restriction */
+ if (is_legacy(tbl->lq_type)) {
+ if (lq_data->phymode == (u8) MODE_IEEE80211A)
+ rate_scale_index_msk = (u16) (rate_mask &
+ (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+ else
+ rate_scale_index_msk = (u16) (rate_mask &
+ lq_data->supp_rates);
+
+ } else
+ rate_scale_index_msk = rate_mask;
+
+ if (!rate_scale_index_msk)
+ rate_scale_index_msk = rate_mask;
+
+ if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
+ index = IWL_INVALID_VALUE;
+ update_lq = 1;
+
+ /* get the lowest availabe rate */
+ for (i = 0; i <= IWL_RATE_COUNT; i++) {
+ if ((1 << i) & rate_scale_index_msk)
+ index = i;
+ }
+
+ if (index == IWL_INVALID_VALUE) {
+ IWL_WARNING("Can not find a suitable rate\n");
+ return;
+ }
+ }
+
+ if (!tbl->expected_tpt)
+ rs_get_expected_tpt_table(lq_data, tbl);
+
+ window = &(tbl->win[index]);
+
+ fail_count = window->counter - window->success_counter;
+ if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
+ || (tbl->expected_tpt == NULL)) {
+ IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
+ "for index %d\n",
+ window->success_counter, window->counter, index);
+ window->average_tpt = IWL_INVALID_VALUE;
+ rs_stay_in_table(lq_data);
+ if (update_lq) {
+ rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
+ rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+ rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+ }
+ goto out;
+
+ } else
+ window->average_tpt = ((window->success_ratio *
+ tbl->expected_tpt[index] + 64) / 128);
+
+ if (lq_data->search_better_tbl) {
+ int success_limit = IWL_RATE_SCALE_SWITCH;
+
+ if ((window->success_ratio > success_limit) ||
+ (window->average_tpt > lq_data->last_tpt)) {
+ if (!is_legacy(tbl->lq_type)) {
+ IWL_DEBUG_HT("LQ: we are switching to HT"
+ " rate suc %d current tpt %d"
+ " old tpt %d\n",
+ window->success_ratio,
+ window->average_tpt,
+ lq_data->last_tpt);
+ lq_data->enable_counter = 1;
+ }
+ lq_data->active_tbl = active_tbl;
+ current_tpt = window->average_tpt;
+ } else {
+ tbl->lq_type = LQ_NONE;
+ active_tbl = lq_data->active_tbl;
+ tbl = &(lq_data->lq_info[active_tbl]);
+
+ index = iwl_rate_index_from_plcp(
+ tbl->current_rate.rate_n_flags);
+
+ update_lq = 1;
+ current_tpt = lq_data->last_tpt;
+ IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
+ }
+ lq_data->search_better_tbl = 0;
+ done_search = 1;
+ goto lq_update;
+ }
+
+ high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
+ tbl->lq_type);
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ current_tpt = window->average_tpt;
+
+ if (low != IWL_RATE_INVALID)
+ low_tpt = tbl->win[low].average_tpt;
+
+ if (high != IWL_RATE_INVALID)
+ high_tpt = tbl->win[high].average_tpt;
+
+
+ scale_action = 1;
+
+ if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
+ (current_tpt == 0)) {
+ IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
+ scale_action = -1;
+ } else if ((low_tpt == IWL_INVALID_VALUE) &&
+ (high_tpt == IWL_INVALID_VALUE))
+ scale_action = 1;
+ else if ((low_tpt != IWL_INVALID_VALUE) &&
+ (high_tpt != IWL_INVALID_VALUE) &&
+ (low_tpt < current_tpt) &&
+ (high_tpt < current_tpt))
+ scale_action = 0;
+ else {
+ if (high_tpt != IWL_INVALID_VALUE) {
+ if (high_tpt > current_tpt)
+ scale_action = 1;
+ else {
+ IWL_DEBUG_RATE
+ ("decrease rate because of high tpt\n");
+ scale_action = -1;
+ }
+ } else if (low_tpt != IWL_INVALID_VALUE) {
+ if (low_tpt > current_tpt) {
+ IWL_DEBUG_RATE
+ ("decrease rate because of low tpt\n");
+ scale_action = -1;
+ } else
+ scale_action = 1;
+ }
+ }
+
+ if (scale_action == -1) {
+ if ((low != IWL_RATE_INVALID) &&
+ ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+ (current_tpt > (100 * tbl->expected_tpt[low]))))
+ scale_action = 0;
+ } else if ((scale_action == 1) &&
+ (window->success_ratio < IWL_RATE_INCREASE_TH))
+ scale_action = 0;
+
+ switch (scale_action) {
+ case -1:
+ if (low != IWL_RATE_INVALID) {
+ update_lq = 1;
+ index = low;
+ }
+ break;
+ case 1:
+ if (high != IWL_RATE_INVALID) {
+ update_lq = 1;
+ index = high;
+ }
+
+ break;
+ case 0:
+ default:
+ break;
+ }
+
+ IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
+ "high %d type %d\n",
+ index, scale_action, low, high, tbl->lq_type);
+
+ lq_update:
+ if (update_lq) {
+ rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
+ rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+ rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+ }
+ rs_stay_in_table(lq_data);
+
+ if (!update_lq && !done_search && !lq_data->stay_in_tbl) {
+ lq_data->last_tpt = current_tpt;
+
+ if (is_legacy(tbl->lq_type))
+ rs_move_legacy_other(priv, lq_data, index);
+ else if (is_siso(tbl->lq_type))
+ rs_move_siso_to_other(priv, lq_data, index);
+ else
+ rs_move_mimo_to_other(priv, lq_data, index);
+
+ if (lq_data->search_better_tbl) {
+ tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(tbl->win[i]));
+
+ index = iwl_rate_index_from_plcp(
+ tbl->current_rate.rate_n_flags);
+
+ IWL_DEBUG_HT("Switch current mcs: %X index: %d\n",
+ tbl->current_rate.rate_n_flags, index);
+ rs_fill_link_cmd(lq_data, &tbl->current_rate,
+ &lq_data->lq);
+ rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+ }
+ tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
+
+ if (is_legacy(tbl1->lq_type) &&
+#ifdef CONFIG_IWLWIFI_HT
+ !priv->current_assoc_ht.is_ht &&
+#endif
+ (lq_data->action_counter >= 1)) {
+ lq_data->action_counter = 0;
+ IWL_DEBUG_HT("LQ: STAY in legacy table\n");
+ rs_set_stay_in_table(1, lq_data);
+ }
+
+ if (lq_data->enable_counter &&
+ (lq_data->action_counter >= IWL_ACTION_LIMIT)) {
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&
+ (priv->lq_mngr.agg_ctrl.auto_agg)) {
+ priv->lq_mngr.agg_ctrl.tid_retry =
+ TID_ALL_SPECIFIED;
+ schedule_work(&priv->agg_work);
+ }
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+ lq_data->action_counter = 0;
+ rs_set_stay_in_table(0, lq_data);
+ }
+ } else {
+ if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))
+ lq_data->flush_timer = jiffies;
+ }
+
+out:
+ rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
+ i = index;
+ sta->last_txrate = i;
+
+ /* sta->txrate is an index to A mode rates which start
+ * at IWL_FIRST_OFDM_RATE
+ */
+ if (lq_data->phymode == (u8) MODE_IEEE80211A)
+ sta->txrate = i - IWL_FIRST_OFDM_RATE;
+ else
+ sta->txrate = i;
+
+ return;
+}
+
+
+static void rs_initialize_lq(struct iwl_priv *priv,
+ struct sta_info *sta)
+{
+ int i;
+ struct iwl_rate_scale_priv *lq;
+ struct iwl_scale_tbl_info *tbl;
+ u8 active_tbl = 0;
+ int rate_idx;
+ u8 use_green = rs_use_green(priv);
+ struct iwl_rate mcs_rate;
+
+ if (!sta || !sta->rate_ctrl_priv)
+ goto out;
+
+ lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+ i = sta->last_txrate;
+
+ if ((lq->lq.sta_id == 0xff) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ goto out;
+
+ if (!lq->search_better_tbl)
+ active_tbl = lq->active_tbl;
+ else
+ active_tbl = 1 - lq->active_tbl;
+
+ tbl = &(lq->lq_info[active_tbl]);
+
+ if ((i < 0) || (i >= IWL_RATE_COUNT))
+ i = 0;
+
+ mcs_rate.rate_n_flags = iwl_rates[i].plcp ;
+ mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
+ mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+
+ if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+ mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;
+
+ tbl->antenna_type = ANT_AUX;
+ rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);
+ if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
+ rs_toggle_antenna(&mcs_rate, tbl);
+
+ rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
+ tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
+ rs_get_expected_tpt_table(lq, tbl);
+ rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);
+ rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC);
+ out:
+ return;
+}
+
+static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local
+ *local)
+{
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ int i;
+
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
+ return rate;
+ }
+
+ return &mode->rates[0];
+}
+
+static struct ieee80211_rate *rs_get_rate(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra
+ *extra)
+{
+
+ int i;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct sta_info *sta;
+ u16 fc;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct iwl_rate_scale_priv *lq;
+
+ IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
+
+ memset(extra, 0, sizeof(*extra));
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ return rs_get_lowest_rate(local);
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ return rs_get_lowest_rate(local);
+ }
+
+ lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+ i = sta->last_txrate;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) {
+ u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ DECLARE_MAC_BUF(mac);
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
+ print_mac(mac, hdr->addr1));
+ sta_id = iwl_add_station(priv,
+ hdr->addr1, 0, CMD_ASYNC);
+ }
+ if ((sta_id != IWL_INVALID_STATION)) {
+ lq->lq.sta_id = sta_id;
+ lq->lq.rs_table[0].rate_n_flags = 0;
+ lq->ibss_sta_added = 1;
+ rs_initialize_lq(priv, sta);
+ }
+ if (!lq->ibss_sta_added)
+ goto done;
+ }
+
+ done:
+ sta_info_put(sta);
+ if ((i < 0) || (i > IWL_RATE_COUNT))
+ return rs_get_lowest_rate(local);
+
+ return &priv->ieee_rates[i];
+}
+
+static void *rs_alloc_sta(void *priv, gfp_t gfp)
+{
+ struct iwl_rate_scale_priv *crl;
+ int i, j;
+
+ IWL_DEBUG_RATE("create station rate scale window\n");
+
+ crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+
+ if (crl == NULL)
+ return NULL;
+ crl->lq.sta_id = 0xff;
+
+
+ for (j = 0; j < LQ_SIZE; j++)
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+
+ return crl;
+}
+
+static void rs_rate_init(void *priv_rate, void *priv_sta,
+ struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ int i, j;
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct iwl_rate_scale_priv *crl = priv_sta;
+
+ crl->flush_timer = 0;
+ crl->supp_rates = sta->supp_rates;
+ sta->txrate = 3;
+ for (j = 0; j < LQ_SIZE; j++)
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+
+ IWL_DEBUG_RATE("rate scale global init\n");
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+
+ crl->ibss_sta_added = 0;
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ u8 sta_id = iwl_hw_find_station(priv, sta->addr);
+ DECLARE_MAC_BUF(mac);
+
+ /* for IBSS the call are from tasklet */
+ IWL_DEBUG_HT("LQ: ADD station %s\n",
+ print_mac(mac, sta->addr));
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
+ print_mac(mac, sta->addr));
+ sta_id = iwl_add_station(priv,
+ sta->addr, 0, CMD_ASYNC);
+ }
+ if ((sta_id != IWL_INVALID_STATION)) {
+ crl->lq.sta_id = sta_id;
+ crl->lq.rs_table[0].rate_n_flags = 0;
+ }
+ /* FIXME: this is w/a remove it later */
+ priv->assoc_station_added = 1;
+ }
+
+ for (i = 0; i < mode->num_rates; i++) {
+ if ((sta->supp_rates & BIT(i)) &&
+ (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ sta->txrate = i;
+ }
+ sta->last_txrate = sta->txrate;
+ /* For MODE_IEEE80211A mode cck rate are at end
+ * rate table
+ */
+ if (local->hw.conf.phymode == MODE_IEEE80211A)
+ sta->last_txrate += IWL_FIRST_OFDM_RATE;
+
+ crl->is_dup = priv->is_dup;
+ crl->valid_antenna = priv->valid_antenna;
+ crl->antenna = priv->antenna;
+ crl->is_green = rs_use_green(priv);
+ crl->active_rate = priv->active_rate;
+ crl->active_rate &= ~(0x1000);
+ crl->active_rate_basic = priv->active_rate_basic;
+ crl->phymode = priv->phymode;
+#ifdef CONFIG_IWLWIFI_HT
+ crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1);
+ crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1);
+ crl->active_siso_rate &= ~((u16)0x2);
+ crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE;
+
+ crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1);
+ crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1);
+ crl->active_mimo_rate &= ~((u16)0x2);
+ crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE;
+ IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
+ crl->active_mimo_rate);
+#endif /*CONFIG_IWLWIFI_HT*/
+#ifdef CONFIG_MAC80211_DEBUGFS
+ crl->drv = priv;
+#endif
+
+ if (priv->assoc_station_added)
+ priv->lq_mngr.lq_ready = 1;
+
+ rs_initialize_lq(priv, sta);
+}
+
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_rate *tx_mcs,
+ struct iwl_link_quality_cmd *lq_cmd)
+{
+ int index = 0;
+ int rate_idx;
+ int repeat_rate = 0;
+ u8 ant_toggle_count = 0;
+ u8 use_ht_possible = 1;
+ struct iwl_rate new_rate;
+ struct iwl_scale_tbl_info tbl_type = { 0 };
+
+ rs_dbgfs_set_mcs(lq_data, tx_mcs, index);
+
+ rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
+ &tbl_type, &rate_idx);
+
+ if (is_legacy(tbl_type.lq_type)) {
+ ant_toggle_count = 1;
+ repeat_rate = IWL_NUMBER_TRY;
+ } else
+ repeat_rate = IWL_HT_NUMBER_TRY;
+
+ lq_cmd->general_params.mimo_delimiter =
+ is_mimo(tbl_type.lq_type) ? 1 : 0;
+ lq_cmd->rs_table[index].rate_n_flags =
+ cpu_to_le32(tx_mcs->rate_n_flags);
+ new_rate.rate_n_flags = tx_mcs->rate_n_flags;
+
+ if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
+ lq_cmd->general_params.single_stream_ant_msk = 1;
+ else
+ lq_cmd->general_params.single_stream_ant_msk = 2;
+
+ index++;
+ repeat_rate--;
+
+ while (index < LINK_QUAL_MAX_RETRY_NUM) {
+ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+ if (is_legacy(tbl_type.lq_type)) {
+ if (ant_toggle_count <
+ NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+ ant_toggle_count++;
+ else {
+ rs_toggle_antenna(&new_rate, &tbl_type);
+ ant_toggle_count = 1;
+ }
+ }
+
+ rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+ lq_cmd->rs_table[index].rate_n_flags =
+ cpu_to_le32(new_rate.rate_n_flags);
+ repeat_rate--;
+ index++;
+ }
+
+ rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type,
+ &rate_idx);
+
+ if (is_mimo(tbl_type.lq_type))
+ lq_cmd->general_params.mimo_delimiter = index;
+
+ rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
+ use_ht_possible, &new_rate);
+
+ if (is_legacy(tbl_type.lq_type)) {
+ if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+ ant_toggle_count++;
+ else {
+ rs_toggle_antenna(&new_rate, &tbl_type);
+ ant_toggle_count = 1;
+ }
+ repeat_rate = IWL_NUMBER_TRY;
+ } else
+ repeat_rate = IWL_HT_NUMBER_TRY;
+
+ use_ht_possible = 0;
+
+ rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+ lq_cmd->rs_table[index].rate_n_flags =
+ cpu_to_le32(new_rate.rate_n_flags);
+
+ index++;
+ repeat_rate--;
+ }
+
+ lq_cmd->general_params.dual_stream_ant_msk = 3;
+ lq_cmd->agg_params.agg_dis_start_th = 3;
+ lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
+}
+
+static void *rs_alloc(struct ieee80211_local *local)
+{
+ return local->hw.priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv_rate)
+{
+ return;
+}
+
+static void rs_clear(void *priv_rate)
+{
+ struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ if (priv->lq_mngr.agg_ctrl.granted_ba)
+ iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ IWL_DEBUG_RATE("leave\n");
+}
+
+static void rs_free_sta(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+
+ IWL_DEBUG_RATE("enter\n");
+ kfree(rs_priv);
+ IWL_DEBUG_RATE("leave\n");
+}
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index)
+{
+ const u32 cck_rate = 0x820A;
+ if (rs_priv->dbg_fixed.rate_n_flags) {
+ if (index < 12)
+ mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
+ else
+ mcs->rate_n_flags = cck_rate;
+ IWL_DEBUG_RATE("Fixed rate ON\n");
+ return;
+ }
+
+ IWL_DEBUG_RATE("Fixed rate OFF\n");
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+ char buf[64];
+ int buf_size;
+ u32 parsed_rate;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%x", &parsed_rate) == 1)
+ rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
+ else
+ rs_priv->dbg_fixed.rate_n_flags = 0;
+
+ rs_priv->active_rate = 0x0FFF;
+ rs_priv->active_siso_rate = 0x1FD0;
+ rs_priv->active_mimo_rate = 0x1FD0;
+
+ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
+ rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);
+
+ if (rs_priv->dbg_fixed.rate_n_flags) {
+ rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
+ rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
+ }
+
+ return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int i = 0;
+
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+
+ desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
+ desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+ rs_priv->total_failed, rs_priv->total_success,
+ rs_priv->active_rate);
+ desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+ rs_priv->dbg_fixed.rate_n_flags);
+ desc += sprintf(buff+desc, "general:"
+ "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+ rs_priv->lq.general_params.flags,
+ rs_priv->lq.general_params.mimo_delimiter,
+ rs_priv->lq.general_params.single_stream_ant_msk,
+ rs_priv->lq.general_params.dual_stream_ant_msk);
+
+ desc += sprintf(buff+desc, "agg:"
+ "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+ le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
+ rs_priv->lq.agg_params.agg_dis_start_th,
+ rs_priv->lq.agg_params.agg_frame_cnt_limit);
+
+ desc += sprintf(buff+desc,
+ "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+ rs_priv->lq.general_params.start_rate_index[0],
+ rs_priv->lq.general_params.start_rate_index[1],
+ rs_priv->lq.general_params.start_rate_index[2],
+ rs_priv->lq.general_params.start_rate_index[3]);
+
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
+ i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+ .write = rs_sta_dbgfs_scale_table_write,
+ .read = rs_sta_dbgfs_scale_table_read,
+ .open = open_file_generic,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int i, j;
+
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+ for (i = 0; i < LQ_SIZE; i++) {
+ desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
+ "rate=0x%X\n",
+ rs_priv->active_tbl == i?"*":"x",
+ rs_priv->lq_info[i].lq_type,
+ rs_priv->lq_info[i].is_SGI,
+ rs_priv->lq_info[i].is_fat,
+ rs_priv->lq_info[i].is_dup,
+ rs_priv->lq_info[i].current_rate.rate_n_flags);
+ for (j = 0; j < IWL_RATE_COUNT; j++) {
+ desc += sprintf(buff+desc,
+ "counter=%d success=%d %%=%d\n",
+ rs_priv->lq_info[i].win[j].counter,
+ rs_priv->lq_info[i].win[j].success_counter,
+ rs_priv->lq_info[i].win[j].success_ratio);
+ }
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+ .read = rs_sta_dbgfs_stats_table_read,
+ .open = open_file_generic,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+ struct dentry *dir)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+ rs_priv->rs_sta_dbgfs_scale_table_file =
+ debugfs_create_file("rate_scale_table", 0600, dir,
+ rs_priv, &rs_sta_dbgfs_scale_table_ops);
+ rs_priv->rs_sta_dbgfs_stats_table_file =
+ debugfs_create_file("rate_stats_table", 0600, dir,
+ rs_priv, &rs_sta_dbgfs_stats_table_ops);
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+ debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
+ debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
+}
+#endif
+
+static struct rate_control_ops rs_ops = {
+ .module = NULL,
+ .name = RS_NAME,
+ .tx_status = rs_tx_status,
+ .get_rate = rs_get_rate,
+ .rate_init = rs_rate_init,
+ .clear = rs_clear,
+ .alloc = rs_alloc,
+ .free = rs_free,
+ .alloc_sta = rs_alloc_sta,
+ .free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = rs_add_debugfs,
+ .remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rate_scale_priv *rs_priv;
+ struct sta_info *sta;
+ int count = 0, i;
+ u32 samples = 0, success = 0, good = 0;
+ unsigned long now = jiffies;
+ u32 max_time = 0;
+ u8 lq_type, antenna;
+
+ sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta) {
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave - no private rate data!\n");
+ } else
+ IWL_DEBUG_RATE("leave - no station!\n");
+ return sprintf(buf, "station %d not found\n", sta_id);
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type;
+ antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type;
+
+ if (is_legacy(lq_type))
+ i = IWL_RATE_54M_INDEX;
+ else
+ i = IWL_RATE_60M_INDEX;
+ while (1) {
+ u64 mask;
+ int j;
+ int active = rs_priv->active_tbl;
+
+ count +=
+ sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+
+ mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
+ for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
+ buf[count++] =
+ (rs_priv->lq_info[active].win[i].data & mask)
+ ? '1' : '0';
+
+ samples += rs_priv->lq_info[active].win[i].counter;
+ good += rs_priv->lq_info[active].win[i].success_counter;
+ success += rs_priv->lq_info[active].win[i].success_counter *
+ iwl_rates[i].ieee;
+
+ if (rs_priv->lq_info[active].win[i].stamp) {
+ int delta =
+ jiffies_to_msecs(now -
+ rs_priv->lq_info[active].win[i].stamp);
+
+ if (delta > max_time)
+ max_time = delta;
+
+ count += sprintf(&buf[count], "%5dms\n", delta);
+ } else
+ buf[count++] = '\n';
+
+ j = iwl_get_prev_ieee_rate(i);
+ if (j == i)
+ break;
+ i = j;
+ }
+
+ /* Display the average rate of all samples taken.
+ *
+ * NOTE: We multiple # of samples by 2 since the IEEE measurement
+ * added from iwl_rates is actually 2X the rate */
+ if (samples)
+ count += sprintf(&buf[count],
+ "\nAverage rate is %3d.%02dMbs over last %4dms\n"
+ "%3d%% success (%d good packets over %d tries)\n",
+ success / (2 * samples), (success * 5 / samples) % 10,
+ max_time, good * 100 / samples, good, samples);
+ else
+ count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
+ count += sprintf(&buf[count], "\nrate scale type %d anntena %d "
+ "active_search %d rate index %d\n", lq_type, antenna,
+ rs_priv->search_better_tbl, sta->last_txrate);
+
+ sta_info_put(sta);
+ return count;
+}
+
+void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ priv->lq_mngr.lq_ready = 1;
+}
+
+void iwl_rate_control_register(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_unregister(&rs_ops);
+}
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
new file mode 100644
index 000000000000..c6325f72df68
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_4965_rs_h__
+#define __iwl_4965_rs_h__
+
+#include "iwl-4965.h"
+
+struct iwl_rate_info {
+ u8 plcp;
+ u8 plcp_siso;
+ u8 plcp_mimo;
+ u8 ieee;
+ u8 prev_ieee; /* previous rate in IEEE speeds */
+ u8 next_ieee; /* next rate in IEEE speeds */
+ u8 prev_rs; /* previous rate used in rs algo */
+ u8 next_rs; /* next rate used in rs algo */
+ u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
+ u8 next_rs_tgg; /* next rate used in TGG rs algo */
+};
+
+enum {
+ IWL_RATE_1M_INDEX = 0,
+ IWL_RATE_2M_INDEX,
+ IWL_RATE_5M_INDEX,
+ IWL_RATE_11M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX,
+ IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX,
+ IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX,
+ IWL_RATE_54M_INDEX,
+ IWL_RATE_60M_INDEX,
+ IWL_RATE_COUNT,
+ IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+ IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+};
+
+enum {
+ IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+ IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+ IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+ IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define IWL_RATE_6M_MASK (1<<IWL_RATE_6M_INDEX)
+#define IWL_RATE_9M_MASK (1<<IWL_RATE_9M_INDEX)
+#define IWL_RATE_12M_MASK (1<<IWL_RATE_12M_INDEX)
+#define IWL_RATE_18M_MASK (1<<IWL_RATE_18M_INDEX)
+#define IWL_RATE_24M_MASK (1<<IWL_RATE_24M_INDEX)
+#define IWL_RATE_36M_MASK (1<<IWL_RATE_36M_INDEX)
+#define IWL_RATE_48M_MASK (1<<IWL_RATE_48M_INDEX)
+#define IWL_RATE_54M_MASK (1<<IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK (1<<IWL_RATE_60M_INDEX)
+#define IWL_RATE_1M_MASK (1<<IWL_RATE_1M_INDEX)
+#define IWL_RATE_2M_MASK (1<<IWL_RATE_2M_INDEX)
+#define IWL_RATE_5M_MASK (1<<IWL_RATE_5M_INDEX)
+#define IWL_RATE_11M_MASK (1<<IWL_RATE_11M_INDEX)
+
+enum {
+ IWL_RATE_6M_PLCP = 13,
+ IWL_RATE_9M_PLCP = 15,
+ IWL_RATE_12M_PLCP = 5,
+ IWL_RATE_18M_PLCP = 7,
+ IWL_RATE_24M_PLCP = 9,
+ IWL_RATE_36M_PLCP = 11,
+ IWL_RATE_48M_PLCP = 1,
+ IWL_RATE_54M_PLCP = 3,
+ IWL_RATE_60M_PLCP = 3,
+ IWL_RATE_1M_PLCP = 10,
+ IWL_RATE_2M_PLCP = 20,
+ IWL_RATE_5M_PLCP = 55,
+ IWL_RATE_11M_PLCP = 110,
+};
+
+/* OFDM HT rate plcp */
+enum {
+ IWL_RATE_SISO_6M_PLCP = 0,
+ IWL_RATE_SISO_12M_PLCP = 1,
+ IWL_RATE_SISO_18M_PLCP = 2,
+ IWL_RATE_SISO_24M_PLCP = 3,
+ IWL_RATE_SISO_36M_PLCP = 4,
+ IWL_RATE_SISO_48M_PLCP = 5,
+ IWL_RATE_SISO_54M_PLCP = 6,
+ IWL_RATE_SISO_60M_PLCP = 7,
+ IWL_RATE_MIMO_6M_PLCP = 0x8,
+ IWL_RATE_MIMO_12M_PLCP = 0x9,
+ IWL_RATE_MIMO_18M_PLCP = 0xa,
+ IWL_RATE_MIMO_24M_PLCP = 0xb,
+ IWL_RATE_MIMO_36M_PLCP = 0xc,
+ IWL_RATE_MIMO_48M_PLCP = 0xd,
+ IWL_RATE_MIMO_54M_PLCP = 0xe,
+ IWL_RATE_MIMO_60M_PLCP = 0xf,
+ IWL_RATE_SISO_INVM_PLCP,
+ IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+enum {
+ IWL_RATE_6M_IEEE = 12,
+ IWL_RATE_9M_IEEE = 18,
+ IWL_RATE_12M_IEEE = 24,
+ IWL_RATE_18M_IEEE = 36,
+ IWL_RATE_24M_IEEE = 48,
+ IWL_RATE_36M_IEEE = 72,
+ IWL_RATE_48M_IEEE = 96,
+ IWL_RATE_54M_IEEE = 108,
+ IWL_RATE_60M_IEEE = 120,
+ IWL_RATE_1M_IEEE = 2,
+ IWL_RATE_2M_IEEE = 4,
+ IWL_RATE_5M_IEEE = 11,
+ IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_CCK_BASIC_RATES_MASK \
+ (IWL_RATE_1M_MASK | \
+ IWL_RATE_2M_MASK)
+
+#define IWL_CCK_RATES_MASK \
+ (IWL_BASIC_RATES_MASK | \
+ IWL_RATE_5M_MASK | \
+ IWL_RATE_11M_MASK)
+
+#define IWL_OFDM_BASIC_RATES_MASK \
+ (IWL_RATE_6M_MASK | \
+ IWL_RATE_12M_MASK | \
+ IWL_RATE_24M_MASK)
+
+#define IWL_OFDM_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_RATE_9M_MASK | \
+ IWL_RATE_18M_MASK | \
+ IWL_RATE_36M_MASK | \
+ IWL_RATE_48M_MASK | \
+ IWL_RATE_54M_MASK)
+
+#define IWL_BASIC_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_CCK_BASIC_RATES_MASK)
+
+#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+
+#define IWL_INVALID_VALUE -1
+
+#define IWL_MIN_RSSI_VAL -100
+#define IWL_MAX_RSSI_VAL 0
+
+#define IWL_LEGACY_SWITCH_ANTENNA 0
+#define IWL_LEGACY_SWITCH_SISO 1
+#define IWL_LEGACY_SWITCH_MIMO 2
+
+#define IWL_RS_GOOD_RATIO 12800
+
+#define IWL_ACTION_LIMIT 3
+#define IWL_LEGACY_FAILURE_LIMIT 160
+#define IWL_LEGACY_SUCCESS_LIMIT 480
+#define IWL_LEGACY_TABLE_COUNT 160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT 400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500
+#define IWL_NONE_LEGACY_TABLE_COUNT 1500
+
+#define IWL_RATE_SCALE_SWITCH (10880)
+
+#define IWL_SISO_SWITCH_ANTENNA 0
+#define IWL_SISO_SWITCH_MIMO 1
+#define IWL_SISO_SWITCH_GI 2
+
+#define IWL_MIMO_SWITCH_ANTENNA_A 0
+#define IWL_MIMO_SWITCH_ANTENNA_B 1
+#define IWL_MIMO_SWITCH_GI 2
+
+#define LQ_SIZE 2
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+enum iwl_table_type {
+ LQ_NONE,
+ LQ_G,
+ LQ_A,
+ LQ_SISO,
+ LQ_MIMO,
+ LQ_MAX,
+};
+
+enum iwl_antenna_type {
+ ANT_NONE,
+ ANT_MAIN,
+ ANT_AUX,
+ ANT_BOTH,
+};
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+{
+ u8 rate = iwl_rates[rate_index].prev_ieee;
+
+ if (rate == IWL_RATE_INVALID)
+ rate = rate_index;
+ return rate;
+}
+
+extern int iwl_rate_index_from_plcp(int plcp);
+
+/**
+ * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ *
+ * NOTE: This is provided as a quick mechanism for a user to visualize
+ * the performance of the rate control alogirthm and is not meant to be
+ * parsed software.
+ */
+extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+
+/**
+ * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ *
+ * The specific througput table used is based on the type of network
+ * the associated with, including A, B, G, and G w/ TGG protection
+ */
+extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module. The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem. This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
new file mode 100644
index 000000000000..b50d20267c8a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -0,0 +1,4736 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#define IWL 4965
+
+#include "iwlwifi.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_SISO_##s##M_PLCP, \
+ IWL_RATE_MIMO_##s##M_PLCP, \
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
+ IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+};
+
+static int is_fat_channel(__le32 rxon_flags)
+{
+ return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
+ (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
+}
+
+static u8 is_single_stream(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_HT
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht ||
+ (priv->active_rate_ht[1] == 0) ||
+ (priv->ps_mode == IWL_MIMO_PS_STATIC))
+ return 1;
+#else
+ return 1;
+#endif /*CONFIG_IWLWIFI_HT */
+ return 0;
+}
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ * More provides better reception via diversity. Fewer saves power.
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
+ u8 *idle_state, u8 *rx_state)
+{
+ u8 is_single = is_single_stream(priv);
+ u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+
+ /* # of Rx chains to use when expecting MIMO. */
+ if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
+ *rx_state = 2;
+ else
+ *rx_state = 3;
+
+ /* # Rx chains when idling and maybe trying to save power */
+ switch (priv->ps_mode) {
+ case IWL_MIMO_PS_STATIC:
+ case IWL_MIMO_PS_DYNAMIC:
+ *idle_state = (is_cam) ? 2 : 1;
+ break;
+ case IWL_MIMO_PS_NONE:
+ *idle_state = (is_cam) ? *rx_state : 1;
+ break;
+ default:
+ *idle_state = 1;
+ break;
+ }
+
+ return 0;
+}
+
+int iwl_hw_rxq_stop(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* stop HW */
+ iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+ rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+ (1 << 24), 1000);
+ if (rc < 0)
+ IWL_ERROR("Can't stop Rx DMA.\n");
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+ int i;
+ int start = 0;
+ int ret = IWL_INVALID_STATION;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
+ (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+ start = IWL_STA_ID;
+
+ if (is_broadcast_ether_addr(addr))
+ return IWL4965_BROADCAST_ID;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ for (i = start; i < priv->hw_setting.max_stations; i++)
+ if ((priv->stations[i].used) &&
+ (!compare_ether_addr
+ (priv->stations[i].sta.sta.addr, addr))) {
+ ret = i;
+ goto out;
+ }
+
+ IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
+ print_mac(mac, addr), priv->num_stations);
+
+ out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
+}
+
+static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ if (!pwr_max) {
+ u32 val;
+
+ rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+ &val);
+
+ if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+ iwl_set_bits_mask_restricted_reg(
+ priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ } else
+ iwl_set_bits_mask_restricted_reg(
+ priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* stop HW */
+ iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+ rxq->dma_addr >> 8);
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+ (priv->hw_setting.shared_phys +
+ offsetof(struct iwl_shared, val0)) >> 4);
+
+ iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+ FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+ FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+ IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
+ /*0x10 << 4 | */
+ (RX_QUEUE_SIZE_LOG <<
+ FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
+
+ /*
+ * iwl_write32(priv,CSR_INT_COAL_REG,0);
+ */
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int iwl4965_kw_init(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ goto out;
+
+ iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG,
+ priv->kw.dma_addr >> 4);
+ iwl_release_restricted_access(priv);
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+}
+
+static int iwl4965_kw_alloc(struct iwl_priv *priv)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ struct iwl_kw *kw = &priv->kw;
+
+ kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */
+ kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
+ if (!kw->v_addr)
+ return -ENOMEM;
+
+ return 0;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
+ ? # x " " : "")
+
+int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel,
+ const struct iwl_eeprom_channel *eeprom_ch,
+ u8 fat_extension_channel)
+{
+ struct iwl_channel_info *ch_info;
+
+ ch_info = (struct iwl_channel_info *)
+ iwl_get_channel_info(priv, phymode, channel);
+
+ if (!is_channel_valid(ch_info))
+ return -1;
+
+ IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ " %ddBm): Ad-Hoc %ssupported\n",
+ ch_info->channel,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4",
+ CHECK_AND_PRINT(IBSS),
+ CHECK_AND_PRINT(ACTIVE),
+ CHECK_AND_PRINT(RADAR),
+ CHECK_AND_PRINT(WIDE),
+ CHECK_AND_PRINT(NARROW),
+ CHECK_AND_PRINT(DFS),
+ eeprom_ch->flags,
+ eeprom_ch->max_power_avg,
+ ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
+ && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
+ "" : "not ");
+
+ ch_info->fat_eeprom = *eeprom_ch;
+ ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;
+ ch_info->fat_curr_txpow = eeprom_ch->max_power_avg;
+ ch_info->fat_min_power = 0;
+ ch_info->fat_scan_power = eeprom_ch->max_power_avg;
+ ch_info->fat_flags = eeprom_ch->flags;
+ ch_info->fat_extension_channel = fat_extension_channel;
+
+ return 0;
+}
+
+static void iwl4965_kw_free(struct iwl_priv *priv)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ struct iwl_kw *kw = &priv->kw;
+
+ if (kw->v_addr) {
+ pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
+ memset(kw, 0, sizeof(*kw));
+ }
+}
+
+/**
+ * iwl4965_txq_ctx_reset - Reset TX queue context
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+{
+ int rc = 0;
+ int txq_id, slots_num;
+ unsigned long flags;
+
+ iwl4965_kw_free(priv);
+
+ iwl_hw_txq_ctx_free(priv);
+
+ /* Tx CMD queue */
+ rc = iwl4965_kw_alloc(priv);
+ if (rc) {
+ IWL_ERROR("Keep Warm allocation failed");
+ goto error_kw;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (unlikely(rc)) {
+ IWL_ERROR("TX reset failed");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ goto error_reset;
+ }
+
+ iwl_write_restricted_reg(priv, SCD_TXFACT, 0);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ rc = iwl4965_kw_init(priv);
+ if (rc) {
+ IWL_ERROR("kw_init failed\n");
+ goto error_reset;
+ }
+
+ /* Tx queue(s) */
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+ slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+ txq_id);
+ if (rc) {
+ IWL_ERROR("Tx %d queue init failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return rc;
+
+ error:
+ iwl_hw_txq_ctx_free(priv);
+ error_reset:
+ iwl4965_kw_free(priv);
+ error_kw:
+ return rc;
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u8 rev_id;
+ u32 val;
+ u8 val_link;
+
+ iwl_power_init_handle(priv);
+
+ /* nic_init */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return rc;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+
+ iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+ iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+
+ udelay(20);
+
+ iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_restricted_access(priv);
+ iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Determine HW type */
+ rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+ if (rc)
+ return rc;
+
+ IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+
+ iwl4965_nic_set_pwr_src(priv, 1);
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
+ pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
+ /* Enable No Snoop field */
+ pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
+ val & ~(1 << 11));
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Read the EEPROM */
+ rc = iwl_eeprom_init(priv);
+ if (rc)
+ return rc;
+
+ if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
+ IWL_ERROR("Older EEPROM detected! Aborting.\n");
+ return -EINVAL;
+ }
+
+ pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+
+ /* disable L1 entry -- workaround for pre-B1 */
+ pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set CSR_HW_CONFIG_REG for uCode use */
+
+ iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return rc;
+ }
+
+ iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG);
+ iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+ udelay(5);
+ iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_card_show_info(priv);
+
+ /* end nic_init */
+
+ /* Allocate the RX queue, or reset if it is already allocated */
+ if (!rxq->bd) {
+ rc = iwl_rx_queue_alloc(priv);
+ if (rc) {
+ IWL_ERROR("Unable to initialize Rx queue\n");
+ return -ENOMEM;
+ }
+ } else
+ iwl_rx_queue_reset(priv, rxq);
+
+ iwl_rx_replenish(priv);
+
+ iwl4965_rx_init(priv, rxq);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rxq->need_update = 1;
+ iwl_rx_queue_update_write_ptr(priv, rxq);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ rc = iwl4965_txq_ctx_reset(priv);
+ if (rc)
+ return rc;
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
+
+ set_bit(STATUS_INIT, &priv->status);
+
+ return 0;
+}
+
+int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+{
+ int rc = 0;
+ u32 reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+
+ if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
+ (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+ IWL_DEBUG_INFO("Card in power save, master is already "
+ "stopped\n");
+ else {
+ rc = iwl_poll_bit(priv, CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("stop master\n");
+
+ return rc;
+}
+
+void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+{
+
+ int txq_id;
+ unsigned long flags;
+
+ /* reset TFD queues */
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_grab_restricted_access(priv)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ continue;
+ }
+
+ iwl_write_restricted(priv,
+ IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+ 0x0);
+ iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
+ IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
+ (txq_id), 200);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ iwl_hw_txq_ctx_free(priv);
+}
+
+int iwl_hw_nic_reset(struct iwl_priv *priv)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ iwl_hw_nic_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ rc = iwl_poll_bit(priv, CSR_RESET,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
+
+ udelay(10);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (!rc) {
+ iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+
+ udelay(10);
+
+ iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_restricted_access(priv);
+ }
+
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+
+}
+
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ *
+ * This callback is provided in order to queue the statistics_work
+ * in work_queue context (v. softirq)
+ *
+ * This timer function is continually reset to execute within
+ * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
+ * was received. We need to ensure we receive the statistics in order
+ * to update the temperature used for calibrating the TXPOWER. However,
+ * we can't send the statistics command from softirq context (which
+ * is the context which timers run at) so we have to queue off the
+ * statistics_work to actually send the command to the hardware.
+ */
+static void iwl4965_bg_statistics_periodic(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+
+ queue_work(priv->workqueue, &priv->statistics_work);
+}
+
+/**
+ * iwl4965_bg_statistics_work - Send the statistics request to the hardware.
+ *
+ * This is queued by iwl_bg_statistics_periodic.
+ */
+static void iwl4965_bg_statistics_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ statistics_work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_send_statistics_request(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+#define CT_LIMIT_CONST 259
+#define TM_CT_KILL_THRESHOLD 110
+
+void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
+{
+ struct iwl_ct_kill_config cmd;
+ u32 R1, R2, R3;
+ u32 temp_th;
+ u32 crit_temperature;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) {
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+ } else {
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+ }
+
+ temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD);
+
+ crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
+ cmd.critical_temperature_R = cpu_to_le32(crit_temperature);
+ rc = iwl_send_cmd_pdu(priv,
+ REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd);
+ if (rc)
+ IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
+ else
+ IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
+}
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ * but then determines that they are either noise, or transmissions
+ * from a distant wireless network (also "noise", really) that get
+ * "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ * enough to receive all of our own network traffic, but not so
+ * high that our DSP gets too busy trying to lock onto non-network
+ * activity/noise. */
+static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
+ u32 norm_fa,
+ u32 rx_enable_time,
+ struct statistics_general_data *rx_info)
+{
+ u32 max_nrg_cck = 0;
+ int i = 0;
+ u8 max_silence_rssi = 0;
+ u32 silence_ref = 0;
+ u8 silence_rssi_a = 0;
+ u8 silence_rssi_b = 0;
+ u8 silence_rssi_c = 0;
+ u32 val;
+
+ /* "false_alarms" values below are cross-multiplications to assess the
+ * numbers of false alarms within the measured period of actual Rx
+ * (Rx is off when we're txing), vs the min/max expected false alarms
+ * (some should be expected if rx is sensitive enough) in a
+ * hypothetical listening period of 200 time units (TU), 204.8 msec:
+ *
+ * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+ *
+ * */
+ u32 false_alarms = norm_fa * 200 * 1024;
+ u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+ u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+ struct iwl_sensitivity_data *data = NULL;
+
+ data = &(priv->sensitivity_data);
+
+ data->nrg_auto_corr_silence_diff = 0;
+
+ /* Find max silence rssi among all 3 receivers.
+ * This is background noise, which may include transmissions from other
+ * networks, measured during silence before our network's beacon */
+ silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+ ALL_BAND_FILTER)>>8);
+ silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+ ALL_BAND_FILTER)>>8);
+ silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+ ALL_BAND_FILTER)>>8);
+
+ val = max(silence_rssi_b, silence_rssi_c);
+ max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+ /* Store silence rssi in 20-beacon history table */
+ data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+ data->nrg_silence_idx++;
+ if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+ data->nrg_silence_idx = 0;
+
+ /* Find max silence rssi across 20 beacon history */
+ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+ val = data->nrg_silence_rssi[i];
+ silence_ref = max(silence_ref, val);
+ }
+ IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n",
+ silence_rssi_a, silence_rssi_b, silence_rssi_c,
+ silence_ref);
+
+ /* Find max rx energy (min value!) among all 3 receivers,
+ * measured during beacon frame.
+ * Save it in 10-beacon history table. */
+ i = data->nrg_energy_idx;
+ val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+ data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+ data->nrg_energy_idx++;
+ if (data->nrg_energy_idx >= 10)
+ data->nrg_energy_idx = 0;
+
+ /* Find min rx energy (max value) across 10 beacon history.
+ * This is the minimum signal level that we want to receive well.
+ * Add backoff (margin so we don't miss slightly lower energy frames).
+ * This establishes an upper bound (min value) for energy threshold. */
+ max_nrg_cck = data->nrg_value[0];
+ for (i = 1; i < 10; i++)
+ max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+ max_nrg_cck += 6;
+
+ IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+ rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+ rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+ /* Count number of consecutive beacons with fewer-than-desired
+ * false alarms. */
+ if (false_alarms < min_false_alarms)
+ data->num_in_cck_no_fa++;
+ else
+ data->num_in_cck_no_fa = 0;
+ IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n",
+ data->num_in_cck_no_fa);
+
+ /* If we got too many false alarms this time, reduce sensitivity */
+ if (false_alarms > max_false_alarms) {
+ IWL_DEBUG_CALIB("norm FA %u > max FA %u\n",
+ false_alarms, max_false_alarms);
+ IWL_DEBUG_CALIB("... reducing sensitivity\n");
+ data->nrg_curr_state = IWL_FA_TOO_MANY;
+
+ if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) {
+ /* Store for "fewer than desired" on later beacon */
+ data->nrg_silence_ref = silence_ref;
+
+ /* increase energy threshold (reduce nrg value)
+ * to decrease sensitivity */
+ if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK))
+ data->nrg_th_cck = data->nrg_th_cck
+ - NRG_STEP_CCK;
+ }
+
+ /* increase auto_corr values to decrease sensitivity */
+ if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+ data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+ else {
+ val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val);
+ }
+ val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val);
+
+ /* Else if we got fewer than desired, increase sensitivity */
+ } else if (false_alarms < min_false_alarms) {
+ data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+ /* Compare silence level with silence level for most recent
+ * healthy number or too many false alarms */
+ data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+ (s32)silence_ref;
+
+ IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n",
+ false_alarms, min_false_alarms,
+ data->nrg_auto_corr_silence_diff);
+
+ /* Increase value to increase sensitivity, but only if:
+ * 1a) previous beacon did *not* have *too many* false alarms
+ * 1b) AND there's a significant difference in Rx levels
+ * from a previous beacon with too many, or healthy # FAs
+ * OR 2) We've seen a lot of beacons (100) with too few
+ * false alarms */
+ if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+ ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+ (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+ IWL_DEBUG_CALIB("... increasing sensitivity\n");
+ /* Increase nrg value to increase sensitivity */
+ val = data->nrg_th_cck + NRG_STEP_CCK;
+ data->nrg_th_cck = min((u32)NRG_MIN_CCK, val);
+
+ /* Decrease auto_corr values to increase sensitivity */
+ val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val);
+
+ val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck_mrc =
+ max((u32)AUTO_CORR_MIN_CCK_MRC, val);
+
+ } else
+ IWL_DEBUG_CALIB("... but not changing sensitivity\n");
+
+ /* Else we got a healthy number of false alarms, keep status quo */
+ } else {
+ IWL_DEBUG_CALIB(" FA in safe zone\n");
+ data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+ /* Store for use in "fewer than desired" with later beacon */
+ data->nrg_silence_ref = silence_ref;
+
+ /* If previous beacon had too many false alarms,
+ * give it some extra margin by reducing sensitivity again
+ * (but don't go below measured energy of desired Rx) */
+ if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+ IWL_DEBUG_CALIB("... increasing margin\n");
+ data->nrg_th_cck -= NRG_MARGIN;
+ }
+ }
+
+ /* Make sure the energy threshold does not go above the measured
+ * energy of the desired Rx signals (reduced by backoff margin),
+ * or else we might start missing Rx frames.
+ * Lower value is higher energy, so we use max()!
+ */
+ data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+ IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
+
+ data->nrg_prev_state = data->nrg_curr_state;
+
+ return 0;
+}
+
+
+static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
+ u32 norm_fa,
+ u32 rx_enable_time)
+{
+ u32 val;
+ u32 false_alarms = norm_fa * 200 * 1024;
+ u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+ u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+ struct iwl_sensitivity_data *data = NULL;
+
+ data = &(priv->sensitivity_data);
+
+ /* If we got too many false alarms this time, reduce sensitivity */
+ if (false_alarms > max_false_alarms) {
+
+ IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n",
+ false_alarms, max_false_alarms);
+
+ val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm =
+ min((u32)AUTO_CORR_MAX_OFDM, val);
+
+ val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc =
+ min((u32)AUTO_CORR_MAX_OFDM_MRC, val);
+
+ val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_x1 =
+ min((u32)AUTO_CORR_MAX_OFDM_X1, val);
+
+ val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc_x1 =
+ min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val);
+ }
+
+ /* Else if we got fewer than desired, increase sensitivity */
+ else if (false_alarms < min_false_alarms) {
+
+ IWL_DEBUG_CALIB("norm FA %u < min FA %u\n",
+ false_alarms, min_false_alarms);
+
+ val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm =
+ max((u32)AUTO_CORR_MIN_OFDM, val);
+
+ val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc =
+ max((u32)AUTO_CORR_MIN_OFDM_MRC, val);
+
+ val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_x1 =
+ max((u32)AUTO_CORR_MIN_OFDM_X1, val);
+
+ val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc_x1 =
+ max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val);
+ }
+
+ else
+ IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
+ min_false_alarms, false_alarms, max_false_alarms);
+
+ return 0;
+}
+
+static int iwl_sensitivity_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
+{
+ int rc = 0;
+ struct iwl_sensitivity_cmd cmd ;
+ struct iwl_sensitivity_data *data = NULL;
+ struct iwl_host_cmd cmd_out = {
+ .id = SENSITIVITY_CMD,
+ .len = sizeof(struct iwl_sensitivity_cmd),
+ .meta.flags = flags,
+ .data = &cmd,
+ };
+
+ data = &(priv->sensitivity_data);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm);
+ cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+ cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+ cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+ cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_cck);
+ cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+ cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+ cpu_to_le16((u16)data->nrg_th_cck);
+ cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+ cpu_to_le16((u16)data->nrg_th_ofdm);
+
+ cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+ __constant_cpu_to_le16(190);
+ cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+ __constant_cpu_to_le16(390);
+ cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+ __constant_cpu_to_le16(62);
+
+ IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
+ data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
+ data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+ data->nrg_th_ofdm);
+
+ IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n",
+ data->auto_corr_cck, data->auto_corr_cck_mrc,
+ data->nrg_th_cck);
+
+ cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+ if (flags & CMD_ASYNC)
+ cmd_out.meta.u.callback = iwl_sensitivity_callback;
+
+ /* Don't send command to uCode if nothing has changed */
+ if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+ sizeof(u16)*HD_TABLE_SIZE)) {
+ IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n");
+ return 0;
+ }
+
+ /* Copy table for comparison next time */
+ memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ rc = iwl_send_cmd(priv, &cmd_out);
+ if (!rc) {
+ IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
+{
+ int rc = 0;
+ int i;
+ struct iwl_sensitivity_data *data = NULL;
+
+ IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n");
+
+ if (force)
+ memset(&(priv->sensitivity_tbl[0]), 0,
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ /* Clear driver's sensitivity algo data */
+ data = &(priv->sensitivity_data);
+ memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+ data->num_in_cck_no_fa = 0;
+ data->nrg_curr_state = IWL_FA_TOO_MANY;
+ data->nrg_prev_state = IWL_FA_TOO_MANY;
+ data->nrg_silence_ref = 0;
+ data->nrg_silence_idx = 0;
+ data->nrg_energy_idx = 0;
+
+ for (i = 0; i < 10; i++)
+ data->nrg_value[i] = 0;
+
+ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+ data->nrg_silence_rssi[i] = 0;
+
+ data->auto_corr_ofdm = 90;
+ data->auto_corr_ofdm_mrc = 170;
+ data->auto_corr_ofdm_x1 = 105;
+ data->auto_corr_ofdm_mrc_x1 = 220;
+ data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+ data->auto_corr_cck_mrc = 200;
+ data->nrg_th_cck = 100;
+ data->nrg_th_ofdm = 100;
+
+ data->last_bad_plcp_cnt_ofdm = 0;
+ data->last_fa_cnt_ofdm = 0;
+ data->last_bad_plcp_cnt_cck = 0;
+ data->last_fa_cnt_cck = 0;
+
+ /* Clear prior Sensitivity command data to force send to uCode */
+ if (force)
+ memset(&(priv->sensitivity_tbl[0]), 0,
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ rc |= iwl4965_sensitivity_write(priv, flags);
+ IWL_DEBUG_CALIB("<<return 0x%X\n", rc);
+
+ return;
+}
+
+
+/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
+ * Called after every association, but this runs only once!
+ * ... once chain noise is calibrated the first time, it's good forever. */
+void iwl4965_chain_noise_reset(struct iwl_priv *priv)
+{
+ struct iwl_chain_noise_data *data = NULL;
+ int rc = 0;
+
+ data = &(priv->chain_noise_data);
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ struct iwl_calibration_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+ cmd.diff_gain_a = 0;
+ cmd.diff_gain_b = 0;
+ cmd.diff_gain_c = 0;
+ rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd);
+ msleep(4);
+ data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+ IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
+ }
+ return;
+}
+
+/*
+ * Accumulate 20 beacons of signal and noise statistics for each of
+ * 3 receivers/antennas/rx-chains, then figure out:
+ * 1) Which antennas are connected.
+ * 2) Differential rx gain settings to balance the 3 receivers.
+ */
+static void iwl4965_noise_calibration(struct iwl_priv *priv,
+ struct iwl_notif_statistics *stat_resp)
+{
+ struct iwl_chain_noise_data *data = NULL;
+ int rc = 0;
+
+ u32 chain_noise_a;
+ u32 chain_noise_b;
+ u32 chain_noise_c;
+ u32 chain_sig_a;
+ u32 chain_sig_b;
+ u32 chain_sig_c;
+ u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+ u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+ u32 max_average_sig;
+ u16 max_average_sig_antenna_i;
+ u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+ u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+ u16 i = 0;
+ u16 chan_num = INITIALIZATION_VALUE;
+ u32 band = INITIALIZATION_VALUE;
+ u32 active_chains = 0;
+ unsigned long flags;
+ struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+
+ data = &(priv->chain_noise_data);
+
+ /* Accumulate just the first 20 beacons after the first association,
+ * then we're done forever. */
+ if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
+ if (data->state == IWL_CHAIN_NOISE_ALIVE)
+ IWL_DEBUG_CALIB("Wait for noise calib reset\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+ IWL_DEBUG_CALIB(" << Interference data unavailable\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1;
+ chan_num = le16_to_cpu(priv->staging_rxon.channel);
+
+ /* Make sure we accumulate data for just the associated channel
+ * (even if scanning). */
+ if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) ||
+ ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
+ (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) {
+ IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n",
+ chan_num, band);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* Accumulate beacon statistics values across 20 beacons */
+ chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+ IN_BAND_FILTER;
+ chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+ IN_BAND_FILTER;
+ chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+ IN_BAND_FILTER;
+
+ chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+ chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+ chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ data->beacon_count++;
+
+ data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+ data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+ data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+ data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+ data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+ data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+ IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band,
+ data->beacon_count);
+ IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n",
+ chain_sig_a, chain_sig_b, chain_sig_c);
+ IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n",
+ chain_noise_a, chain_noise_b, chain_noise_c);
+
+ /* If this is the 20th beacon, determine:
+ * 1) Disconnected antennas (using signal strengths)
+ * 2) Differential gain (using silence noise) to balance receivers */
+ if (data->beacon_count == CAL_NUM_OF_BEACONS) {
+
+ /* Analyze signal for disconnected antenna */
+ average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
+ average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
+ average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+
+ if (average_sig[0] >= average_sig[1]) {
+ max_average_sig = average_sig[0];
+ max_average_sig_antenna_i = 0;
+ active_chains = (1 << max_average_sig_antenna_i);
+ } else {
+ max_average_sig = average_sig[1];
+ max_average_sig_antenna_i = 1;
+ active_chains = (1 << max_average_sig_antenna_i);
+ }
+
+ if (average_sig[2] >= max_average_sig) {
+ max_average_sig = average_sig[2];
+ max_average_sig_antenna_i = 2;
+ active_chains = (1 << max_average_sig_antenna_i);
+ }
+
+ IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n",
+ average_sig[0], average_sig[1], average_sig[2]);
+ IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n",
+ max_average_sig, max_average_sig_antenna_i);
+
+ /* Compare signal strengths for all 3 receivers. */
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ if (i != max_average_sig_antenna_i) {
+ s32 rssi_delta = (max_average_sig -
+ average_sig[i]);
+
+ /* If signal is very weak, compared with
+ * strongest, mark it as disconnected. */
+ if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+ data->disconn_array[i] = 1;
+ else
+ active_chains |= (1 << i);
+ IWL_DEBUG_CALIB("i = %d rssiDelta = %d "
+ "disconn_array[i] = %d\n",
+ i, rssi_delta, data->disconn_array[i]);
+ }
+ }
+
+ /*If both chains A & B are disconnected -
+ * connect B and leave A as is */
+ if (data->disconn_array[CHAIN_A] &&
+ data->disconn_array[CHAIN_B]) {
+ data->disconn_array[CHAIN_B] = 0;
+ active_chains |= (1 << CHAIN_B);
+ IWL_DEBUG_CALIB("both A & B chains are disconnected! "
+ "W/A - declare B as connected\n");
+ }
+
+ IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
+ active_chains);
+
+ /* Save for use within RXON, TX, SCAN commands, etc. */
+ priv->valid_antenna = active_chains;
+
+ /* Analyze noise for rx balance */
+ average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
+ average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
+ average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ if (!(data->disconn_array[i]) &&
+ (average_noise[i] <= min_average_noise)) {
+ /* This means that chain i is active and has
+ * lower noise values so far: */
+ min_average_noise = average_noise[i];
+ min_average_noise_antenna_i = i;
+ }
+ }
+
+ data->delta_gain_code[min_average_noise_antenna_i] = 0;
+
+ IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n",
+ average_noise[0], average_noise[1],
+ average_noise[2]);
+
+ IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n",
+ min_average_noise, min_average_noise_antenna_i);
+
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ s32 delta_g = 0;
+
+ if (!(data->disconn_array[i]) &&
+ (data->delta_gain_code[i] ==
+ CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) {
+ delta_g = average_noise[i] - min_average_noise;
+ data->delta_gain_code[i] = (u8)((delta_g *
+ 10) / 15);
+ if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE <
+ data->delta_gain_code[i])
+ data->delta_gain_code[i] =
+ CHAIN_NOISE_MAX_DELTA_GAIN_CODE;
+
+ data->delta_gain_code[i] =
+ (data->delta_gain_code[i] | (1 << 2));
+ } else
+ data->delta_gain_code[i] = 0;
+ }
+ IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n",
+ data->delta_gain_code[0],
+ data->delta_gain_code[1],
+ data->delta_gain_code[2]);
+
+ /* Differential gain gets sent to uCode only once */
+ if (!data->radio_write) {
+ struct iwl_calibration_cmd cmd;
+ data->radio_write = 1;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+ cmd.diff_gain_a = data->delta_gain_code[0];
+ cmd.diff_gain_b = data->delta_gain_code[1];
+ cmd.diff_gain_c = data->delta_gain_code[2];
+ rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd);
+ if (rc)
+ IWL_DEBUG_CALIB("fail sending cmd "
+ "REPLY_PHY_CALIBRATION_CMD \n");
+
+ /* TODO we might want recalculate
+ * rx_chain in rxon cmd */
+
+ /* Mark so we run this algo only once! */
+ data->state = IWL_CHAIN_NOISE_CALIBRATED;
+ }
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+ }
+ return;
+}
+
+static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
+ struct iwl_notif_statistics *resp)
+{
+ int rc = 0;
+ u32 rx_enable_time;
+ u32 fa_cck;
+ u32 fa_ofdm;
+ u32 bad_plcp_cck;
+ u32 bad_plcp_ofdm;
+ u32 norm_fa_ofdm;
+ u32 norm_fa_cck;
+ struct iwl_sensitivity_data *data = NULL;
+ struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
+ struct statistics_rx *statistics = &(resp->rx);
+ unsigned long flags;
+ struct statistics_general_data statis;
+
+ data = &(priv->sensitivity_data);
+
+ if (!iwl_is_associated(priv)) {
+ IWL_DEBUG_CALIB("<< - not associated\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+ IWL_DEBUG_CALIB("<< invalid data.\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* Extract Statistics: */
+ rx_enable_time = le32_to_cpu(rx_info->channel_load);
+ fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
+ fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
+ bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
+ bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+
+ statis.beacon_silence_rssi_a =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+ statis.beacon_silence_rssi_b =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+ statis.beacon_silence_rssi_c =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+ statis.beacon_energy_a =
+ le32_to_cpu(statistics->general.beacon_energy_a);
+ statis.beacon_energy_b =
+ le32_to_cpu(statistics->general.beacon_energy_b);
+ statis.beacon_energy_c =
+ le32_to_cpu(statistics->general.beacon_energy_c);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time);
+
+ if (!rx_enable_time) {
+ IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n");
+ return;
+ }
+
+ /* These statistics increase monotonically, and do not reset
+ * at each beacon. Calculate difference from last value, or just
+ * use the new statistics value if it has reset or wrapped around. */
+ if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+ data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+ else {
+ bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+ data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+ }
+
+ if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+ data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+ else {
+ bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+ data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+ }
+
+ if (data->last_fa_cnt_ofdm > fa_ofdm)
+ data->last_fa_cnt_ofdm = fa_ofdm;
+ else {
+ fa_ofdm -= data->last_fa_cnt_ofdm;
+ data->last_fa_cnt_ofdm += fa_ofdm;
+ }
+
+ if (data->last_fa_cnt_cck > fa_cck)
+ data->last_fa_cnt_cck = fa_cck;
+ else {
+ fa_cck -= data->last_fa_cnt_cck;
+ data->last_fa_cnt_cck += fa_cck;
+ }
+
+ /* Total aborted signal locks */
+ norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+ norm_fa_cck = fa_cck + bad_plcp_cck;
+
+ IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck,
+ bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+ iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+ iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+ rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC);
+
+ return;
+}
+
+static void iwl4965_bg_sensitivity_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ sensitivity_work);
+
+ mutex_lock(&priv->mutex);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+ test_bit(STATUS_SCANNING, &priv->status)) {
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (priv->start_calib) {
+ iwl4965_noise_calibration(priv, &priv->statistics);
+
+ if (priv->sensitivity_data.state ==
+ IWL_SENS_CALIB_NEED_REINIT) {
+ iwl4965_init_sensitivity(priv, CMD_ASYNC, 0);
+ priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED;
+ } else
+ iwl4965_sensitivity_calibration(priv,
+ &priv->statistics);
+ }
+
+ mutex_unlock(&priv->mutex);
+ return;
+}
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+
+static void iwl4965_bg_txpower_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ txpower_work);
+
+ /* If a scan happened to start before we got here
+ * then just return; the statistics notification will
+ * kick off another scheduled work to compensate for
+ * any temperature delta we missed here. */
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+ test_bit(STATUS_SCANNING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ /* Regardless of if we are assocaited, we must reconfigure the
+ * TX power since frames can be sent on non-radar channels while
+ * not associated */
+ iwl_hw_reg_send_txpower(priv);
+
+ /* Update last_temperature to keep is_calib_needed from running
+ * when it isn't needed... */
+ priv->last_temperature = priv->temperature;
+
+ mutex_unlock(&priv->mutex);
+}
+
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
+{
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+ (index & 0xff) | (txq_id << 8));
+ iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ int tx_fifo_id, int scd_retry)
+{
+ int txq_id = txq->q.id;
+ int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+
+ iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id),
+ (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+ (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
+ (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
+ (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
+ SCD_QUEUE_STTS_REG_MSK);
+
+ txq->sched_retry = scd_retry;
+
+ IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
+ active ? "Activete" : "Deactivate",
+ scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
+}
+
+static const u16 default_queue_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL_CMD_FIFO_NUM,
+ IWL_TX_FIFO_HCCA_1,
+ IWL_TX_FIFO_HCCA_2
+};
+
+static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
+{
+ set_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
+{
+ clear_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+int iwl4965_alive_notify(struct iwl_priv *priv)
+{
+ u32 a;
+ int i = 0;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ memset(&(priv->sensitivity_data), 0,
+ sizeof(struct iwl_sensitivity_data));
+ memset(&(priv->chain_noise_data), 0,
+ sizeof(struct iwl_chain_noise_data));
+ for (i = 0; i < NUM_RX_CHAINS; i++)
+ priv->chain_noise_data.delta_gain_code[i] =
+ CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+#endif /* CONFIG_IWLWIFI_SENSITIVITY*/
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR);
+ a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
+ for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
+ iwl_write_restricted_mem(priv, a, 0);
+ for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
+ iwl_write_restricted_mem(priv, a, 0);
+ for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
+ iwl_write_restricted_mem(priv, a, 0);
+
+ iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR,
+ (priv->hw_setting.shared_phys +
+ offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10);
+ iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0);
+
+ /* initiate the queues */
+ for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
+ iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0);
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+ iwl_write_restricted_mem(priv, priv->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(i),
+ (SCD_WIN_SIZE <<
+ SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+ SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+ iwl_write_restricted_mem(priv, priv->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(i) +
+ sizeof(u32),
+ (SCD_FRAME_LIMIT <<
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+ }
+ iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK,
+ (1 << priv->hw_setting.max_txq_num) - 1);
+
+ iwl_write_restricted_reg(priv, SCD_TXFACT,
+ SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
+
+ iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ /* map qos queues to fifos one-to-one */
+ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
+ int ac = default_queue_to_tx_fifo[i];
+ iwl4965_txq_ctx_activate(priv, i);
+ iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+ }
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+{
+ priv->hw_setting.shared_virt =
+ pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ &priv->hw_setting.shared_phys);
+
+ if (!priv->hw_setting.shared_virt)
+ return -1;
+
+ memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared));
+
+ priv->hw_setting.max_txq_num = iwl_param_queues_num;
+ priv->hw_setting.ac_queue_count = AC_NUM;
+
+ priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK;
+ priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+ priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
+ priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+
+ priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
+ priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
+ return 0;
+}
+
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ /* Tx queues */
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+ iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+
+ iwl4965_kw_free(priv);
+}
+
+/**
+ * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ *
+ * Does NOT advance any indexes
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+ struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+ int counter = 0;
+ int index, is_odd;
+
+ /* classify bd */
+ if (txq->q.id == IWL_CMD_QUEUE_NUM)
+ /* nothing to cleanup after for host commands */
+ return 0;
+
+ /* sanity check */
+ counter = IWL_GET_BITS(*bd, num_tbs);
+ if (counter > MAX_NUM_OF_TBS) {
+ IWL_ERROR("Too many chunks: %i\n", counter);
+ /* @todo issue fatal error, it is quite serious situation */
+ return 0;
+ }
+
+ /* unmap chunks if any */
+
+ for (i = 0; i < counter; i++) {
+ index = i / 2;
+ is_odd = i & 0x1;
+
+ if (is_odd)
+ pci_unmap_single(
+ dev,
+ IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
+ (IWL_GET_BITS(bd->pa[index],
+ tb2_addr_hi20) << 16),
+ IWL_GET_BITS(bd->pa[index], tb2_len),
+ PCI_DMA_TODEVICE);
+
+ else if (i > 0)
+ pci_unmap_single(dev,
+ le32_to_cpu(bd->pa[index].tb1_addr),
+ IWL_GET_BITS(bd->pa[index], tb1_len),
+ PCI_DMA_TODEVICE);
+
+ if (txq->txb[txq->q.last_used].skb[i]) {
+ struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i];
+
+ dev_kfree_skb(skb);
+ txq->txb[txq->q.last_used].skb[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+{
+ IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n");
+ return -EINVAL;
+}
+
+static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res)
+{
+ s32 sign = 1;
+
+ if (num < 0) {
+ sign = -sign;
+ num = -num;
+ }
+ if (denom < 0) {
+ sign = -sign;
+ denom = -denom;
+ }
+ *res = 1;
+ *res = ((num * 2 + denom) / (denom * 2)) * sign;
+
+ return 1;
+}
+
+static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage,
+ s32 current_voltage)
+{
+ s32 comp = 0;
+
+ if ((TX_POWER_IWL_ILLEGAL_VOLTAGE == eeprom_voltage) ||
+ (TX_POWER_IWL_ILLEGAL_VOLTAGE == current_voltage))
+ return 0;
+
+ iwl4965_math_div_round(current_voltage - eeprom_voltage,
+ TX_POWER_IWL_VOLTAGE_CODES_PER_03V, &comp);
+
+ if (current_voltage > eeprom_voltage)
+ comp *= 2;
+ if ((comp < -2) || (comp > 2))
+ comp = 0;
+
+ return comp;
+}
+
+static const struct iwl_channel_info *
+iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+
+ if (!is_channel_valid(ch_info))
+ return NULL;
+
+ return ch_info;
+}
+
+static s32 iwl4965_get_tx_atten_grp(u16 channel)
+{
+ if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR5_LCH)
+ return CALIB_CH_GROUP_5;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR1_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR1_LCH)
+ return CALIB_CH_GROUP_1;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR2_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR2_LCH)
+ return CALIB_CH_GROUP_2;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR3_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR3_LCH)
+ return CALIB_CH_GROUP_3;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR4_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR4_LCH)
+ return CALIB_CH_GROUP_4;
+
+ IWL_ERROR("Can't find txatten group for channel %d.\n", channel);
+ return -1;
+}
+
+static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
+{
+ s32 b = -1;
+
+ for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
+ if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
+ continue;
+
+ if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
+ && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
+ break;
+ }
+
+ return b;
+}
+
+static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
+{
+ s32 val;
+
+ if (x2 == x1)
+ return y1;
+ else {
+ iwl4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val);
+ return val + y2;
+ }
+}
+
+static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
+ struct iwl_eeprom_calib_ch_info *chan_info)
+{
+ s32 s = -1;
+ u32 c;
+ u32 m;
+ const struct iwl_eeprom_calib_measure *m1;
+ const struct iwl_eeprom_calib_measure *m2;
+ struct iwl_eeprom_calib_measure *omeas;
+ u32 ch_i1;
+ u32 ch_i2;
+
+ s = iwl4965_get_sub_band(priv, channel);
+ if (s >= EEPROM_TX_POWER_BANDS) {
+ IWL_ERROR("Tx Power can not find channel %d ", channel);
+ return -1;
+ }
+
+ ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
+ ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
+ chan_info->ch_num = (u8) channel;
+
+ IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
+ channel, s, ch_i1, ch_i2);
+
+ for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
+ for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
+ m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
+ measurements[c][m]);
+ m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
+ measurements[c][m]);
+ omeas = &(chan_info->measurements[c][m]);
+
+ omeas->actual_pow =
+ (u8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->actual_pow,
+ ch_i2,
+ m2->actual_pow);
+ omeas->gain_idx =
+ (u8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->gain_idx, ch_i2,
+ m2->gain_idx);
+ omeas->temperature =
+ (u8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->temperature,
+ ch_i2,
+ m2->temperature);
+ omeas->pa_det =
+ (s8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->pa_det, ch_i2,
+ m2->pa_det);
+
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m,
+ m1->actual_pow, m2->actual_pow, omeas->actual_pow);
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m,
+ m1->gain_idx, m2->gain_idx, omeas->gain_idx);
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m,
+ m1->pa_det, m2->pa_det, omeas->pa_det);
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d T1=%d T2=%d T=%d\n", c, m,
+ m1->temperature, m2->temperature,
+ omeas->temperature);
+ }
+ }
+
+ return 0;
+}
+
+/* bit-rate-dependent table to prevent Tx distortion, in half-dB units,
+ * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */
+static s32 back_off_table[] = {
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */
+ 10 /* CCK */
+};
+
+/* Thermal compensation values for txpower for various frequency ranges ...
+ * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
+static struct iwl_txpower_comp_entry {
+ s32 degrees_per_05db_a;
+ s32 degrees_per_05db_a_denom;
+} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
+ {9, 2}, /* group 0 5.2, ch 34-43 */
+ {4, 1}, /* group 1 5.2, ch 44-70 */
+ {4, 1}, /* group 2 5.2, ch 71-124 */
+ {4, 1}, /* group 3 5.2, ch 125-200 */
+ {3, 1} /* group 4 2.4, ch all */
+};
+
+static s32 get_min_power_index(s32 rate_power_index, u32 band)
+{
+ if (!band) {
+ if ((rate_power_index & 7) <= 4)
+ return MIN_TX_GAIN_INDEX_52GHZ_EXT;
+ }
+ return MIN_TX_GAIN_INDEX;
+}
+
+struct gain_entry {
+ u8 dsp;
+ u8 radio;
+};
+
+static const struct gain_entry gain_table[2][108] = {
+ /* 5.2GHz power gain index table */
+ {
+ {123, 0x3F}, /* highest txpower */
+ {117, 0x3F},
+ {110, 0x3F},
+ {104, 0x3F},
+ {98, 0x3F},
+ {110, 0x3E},
+ {104, 0x3E},
+ {98, 0x3E},
+ {110, 0x3D},
+ {104, 0x3D},
+ {98, 0x3D},
+ {110, 0x3C},
+ {104, 0x3C},
+ {98, 0x3C},
+ {110, 0x3B},
+ {104, 0x3B},
+ {98, 0x3B},
+ {110, 0x3A},
+ {104, 0x3A},
+ {98, 0x3A},
+ {110, 0x39},
+ {104, 0x39},
+ {98, 0x39},
+ {110, 0x38},
+ {104, 0x38},
+ {98, 0x38},
+ {110, 0x37},
+ {104, 0x37},
+ {98, 0x37},
+ {110, 0x36},
+ {104, 0x36},
+ {98, 0x36},
+ {110, 0x35},
+ {104, 0x35},
+ {98, 0x35},
+ {110, 0x34},
+ {104, 0x34},
+ {98, 0x34},
+ {110, 0x33},
+ {104, 0x33},
+ {98, 0x33},
+ {110, 0x32},
+ {104, 0x32},
+ {98, 0x32},
+ {110, 0x31},
+ {104, 0x31},
+ {98, 0x31},
+ {110, 0x30},
+ {104, 0x30},
+ {98, 0x30},
+ {110, 0x25},
+ {104, 0x25},
+ {98, 0x25},
+ {110, 0x24},
+ {104, 0x24},
+ {98, 0x24},
+ {110, 0x23},
+ {104, 0x23},
+ {98, 0x23},
+ {110, 0x22},
+ {104, 0x18},
+ {98, 0x18},
+ {110, 0x17},
+ {104, 0x17},
+ {98, 0x17},
+ {110, 0x16},
+ {104, 0x16},
+ {98, 0x16},
+ {110, 0x15},
+ {104, 0x15},
+ {98, 0x15},
+ {110, 0x14},
+ {104, 0x14},
+ {98, 0x14},
+ {110, 0x13},
+ {104, 0x13},
+ {98, 0x13},
+ {110, 0x12},
+ {104, 0x08},
+ {98, 0x08},
+ {110, 0x07},
+ {104, 0x07},
+ {98, 0x07},
+ {110, 0x06},
+ {104, 0x06},
+ {98, 0x06},
+ {110, 0x05},
+ {104, 0x05},
+ {98, 0x05},
+ {110, 0x04},
+ {104, 0x04},
+ {98, 0x04},
+ {110, 0x03},
+ {104, 0x03},
+ {98, 0x03},
+ {110, 0x02},
+ {104, 0x02},
+ {98, 0x02},
+ {110, 0x01},
+ {104, 0x01},
+ {98, 0x01},
+ {110, 0x00},
+ {104, 0x00},
+ {98, 0x00},
+ {93, 0x00},
+ {88, 0x00},
+ {83, 0x00},
+ {78, 0x00},
+ },
+ /* 2.4GHz power gain index table */
+ {
+ {110, 0x3f}, /* highest txpower */
+ {104, 0x3f},
+ {98, 0x3f},
+ {110, 0x3e},
+ {104, 0x3e},
+ {98, 0x3e},
+ {110, 0x3d},
+ {104, 0x3d},
+ {98, 0x3d},
+ {110, 0x3c},
+ {104, 0x3c},
+ {98, 0x3c},
+ {110, 0x3b},
+ {104, 0x3b},
+ {98, 0x3b},
+ {110, 0x3a},
+ {104, 0x3a},
+ {98, 0x3a},
+ {110, 0x39},
+ {104, 0x39},
+ {98, 0x39},
+ {110, 0x38},
+ {104, 0x38},
+ {98, 0x38},
+ {110, 0x37},
+ {104, 0x37},
+ {98, 0x37},
+ {110, 0x36},
+ {104, 0x36},
+ {98, 0x36},
+ {110, 0x35},
+ {104, 0x35},
+ {98, 0x35},
+ {110, 0x34},
+ {104, 0x34},
+ {98, 0x34},
+ {110, 0x33},
+ {104, 0x33},
+ {98, 0x33},
+ {110, 0x32},
+ {104, 0x32},
+ {98, 0x32},
+ {110, 0x31},
+ {104, 0x31},
+ {98, 0x31},
+ {110, 0x30},
+ {104, 0x30},
+ {98, 0x30},
+ {110, 0x6},
+ {104, 0x6},
+ {98, 0x6},
+ {110, 0x5},
+ {104, 0x5},
+ {98, 0x5},
+ {110, 0x4},
+ {104, 0x4},
+ {98, 0x4},
+ {110, 0x3},
+ {104, 0x3},
+ {98, 0x3},
+ {110, 0x2},
+ {104, 0x2},
+ {98, 0x2},
+ {110, 0x1},
+ {104, 0x1},
+ {98, 0x1},
+ {110, 0x0},
+ {104, 0x0},
+ {98, 0x0},
+ {97, 0},
+ {96, 0},
+ {95, 0},
+ {94, 0},
+ {93, 0},
+ {92, 0},
+ {91, 0},
+ {90, 0},
+ {89, 0},
+ {88, 0},
+ {87, 0},
+ {86, 0},
+ {85, 0},
+ {84, 0},
+ {83, 0},
+ {82, 0},
+ {81, 0},
+ {80, 0},
+ {79, 0},
+ {78, 0},
+ {77, 0},
+ {76, 0},
+ {75, 0},
+ {74, 0},
+ {73, 0},
+ {72, 0},
+ {71, 0},
+ {70, 0},
+ {69, 0},
+ {68, 0},
+ {67, 0},
+ {66, 0},
+ {65, 0},
+ {64, 0},
+ {63, 0},
+ {62, 0},
+ {61, 0},
+ {60, 0},
+ {59, 0},
+ }
+};
+
+static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
+ u8 is_fat, u8 ctrl_chan_high,
+ struct iwl_tx_power_db *tx_power_tbl)
+{
+ u8 saturation_power;
+ s32 target_power;
+ s32 user_target_power;
+ s32 power_limit;
+ s32 current_temp;
+ s32 reg_limit;
+ s32 current_regulatory;
+ s32 txatten_grp = CALIB_CH_GROUP_MAX;
+ int i;
+ int c;
+ const struct iwl_channel_info *ch_info = NULL;
+ struct iwl_eeprom_calib_ch_info ch_eeprom_info;
+ const struct iwl_eeprom_calib_measure *measurement;
+ s16 voltage;
+ s32 init_voltage;
+ s32 voltage_compensation;
+ s32 degrees_per_05db_num;
+ s32 degrees_per_05db_denom;
+ s32 factory_temp;
+ s32 temperature_comp[2];
+ s32 factory_gain_index[2];
+ s32 factory_actual_pwr[2];
+ s32 power_index;
+
+ /* Sanity check requested level (dBm) */
+ if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) {
+ IWL_WARNING("Requested user TXPOWER %d below limit.\n",
+ priv->user_txpower_limit);
+ return -EINVAL;
+ }
+ if (priv->user_txpower_limit > IWL_TX_POWER_TARGET_POWER_MAX) {
+ IWL_WARNING("Requested user TXPOWER %d above limit.\n",
+ priv->user_txpower_limit);
+ return -EINVAL;
+ }
+
+ /* user_txpower_limit is in dBm, convert to half-dBm (half-dB units
+ * are used for indexing into txpower table) */
+ user_target_power = 2 * priv->user_txpower_limit;
+
+ /* Get current (RXON) channel, band, width */
+ ch_info =
+ iwl4965_get_channel_txpower_info(priv, priv->phymode, channel);
+
+ IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band,
+ is_fat);
+
+ if (!ch_info)
+ return -EINVAL;
+
+ /* get txatten group, used to select 1) thermal txpower adjustment
+ * and 2) mimo txpower balance between Tx chains. */
+ txatten_grp = iwl4965_get_tx_atten_grp(channel);
+ if (txatten_grp < 0)
+ return -EINVAL;
+
+ IWL_DEBUG_TXPOWER("channel %d belongs to txatten group %d\n",
+ channel, txatten_grp);
+
+ if (is_fat) {
+ if (ctrl_chan_high)
+ channel -= 2;
+ else
+ channel += 2;
+ }
+
+ /* hardware txpower limits ...
+ * saturation (clipping distortion) txpowers are in half-dBm */
+ if (band)
+ saturation_power = priv->eeprom.calib_info.saturation_power24;
+ else
+ saturation_power = priv->eeprom.calib_info.saturation_power52;
+
+ if (saturation_power < IWL_TX_POWER_SATURATION_MIN ||
+ saturation_power > IWL_TX_POWER_SATURATION_MAX) {
+ if (band)
+ saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_24;
+ else
+ saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_52;
+ }
+
+ /* regulatory txpower limits ... reg_limit values are in half-dBm,
+ * max_power_avg values are in dBm, convert * 2 */
+ if (is_fat)
+ reg_limit = ch_info->fat_max_power_avg * 2;
+ else
+ reg_limit = ch_info->max_power_avg * 2;
+
+ if ((reg_limit < IWL_TX_POWER_REGULATORY_MIN) ||
+ (reg_limit > IWL_TX_POWER_REGULATORY_MAX)) {
+ if (band)
+ reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_24;
+ else
+ reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_52;
+ }
+
+ /* Interpolate txpower calibration values for this channel,
+ * based on factory calibration tests on spaced channels. */
+ iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);
+
+ /* calculate tx gain adjustment based on power supply voltage */
+ voltage = priv->eeprom.calib_info.voltage;
+ init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
+ voltage_compensation =
+ iwl4965_get_voltage_compensation(voltage, init_voltage);
+
+ IWL_DEBUG_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n",
+ init_voltage,
+ voltage, voltage_compensation);
+
+ /* get current temperature (Celsius) */
+ current_temp = max(priv->temperature, IWL_TX_POWER_TEMPERATURE_MIN);
+ current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX);
+ current_temp = KELVIN_TO_CELSIUS(current_temp);
+
+ /* select thermal txpower adjustment params, based on channel group
+ * (same frequency group used for mimo txatten adjustment) */
+ degrees_per_05db_num =
+ tx_power_cmp_tble[txatten_grp].degrees_per_05db_a;
+ degrees_per_05db_denom =
+ tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom;
+
+ /* get per-chain txpower values from factory measurements */
+ for (c = 0; c < 2; c++) {
+ measurement = &ch_eeprom_info.measurements[c][1];
+
+ /* txgain adjustment (in half-dB steps) based on difference
+ * between factory and current temperature */
+ factory_temp = measurement->temperature;
+ iwl4965_math_div_round((current_temp - factory_temp) *
+ degrees_per_05db_denom,
+ degrees_per_05db_num,
+ &temperature_comp[c]);
+
+ factory_gain_index[c] = measurement->gain_idx;
+ factory_actual_pwr[c] = measurement->actual_pow;
+
+ IWL_DEBUG_TXPOWER("chain = %d\n", c);
+ IWL_DEBUG_TXPOWER("fctry tmp %d, "
+ "curr tmp %d, comp %d steps\n",
+ factory_temp, current_temp,
+ temperature_comp[c]);
+
+ IWL_DEBUG_TXPOWER("fctry idx %d, fctry pwr %d\n",
+ factory_gain_index[c],
+ factory_actual_pwr[c]);
+ }
+
+ /* for each of 33 bit-rates (including 1 for CCK) */
+ for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) {
+ u8 is_mimo_rate;
+ union iwl_tx_power_dual_stream tx_power;
+
+ /* for mimo, reduce each chain's txpower by half
+ * (3dB, 6 steps), so total output power is regulatory
+ * compliant. */
+ if (i & 0x8) {
+ current_regulatory = reg_limit -
+ IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION;
+ is_mimo_rate = 1;
+ } else {
+ current_regulatory = reg_limit;
+ is_mimo_rate = 0;
+ }
+
+ /* find txpower limit, either hardware or regulatory */
+ power_limit = saturation_power - back_off_table[i];
+ if (power_limit > current_regulatory)
+ power_limit = current_regulatory;
+
+ /* reduce user's txpower request if necessary
+ * for this rate on this channel */
+ target_power = user_target_power;
+ if (target_power > power_limit)
+ target_power = power_limit;
+
+ IWL_DEBUG_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n",
+ i, saturation_power - back_off_table[i],
+ current_regulatory, user_target_power,
+ target_power);
+
+ /* for each of 2 Tx chains (radio transmitters) */
+ for (c = 0; c < 2; c++) {
+ s32 atten_value;
+
+ if (is_mimo_rate)
+ atten_value =
+ (s32)le32_to_cpu(priv->card_alive_init.
+ tx_atten[txatten_grp][c]);
+ else
+ atten_value = 0;
+
+ /* calculate index; higher index means lower txpower */
+ power_index = (u8) (factory_gain_index[c] -
+ (target_power -
+ factory_actual_pwr[c]) -
+ temperature_comp[c] -
+ voltage_compensation +
+ atten_value);
+
+/* IWL_DEBUG_TXPOWER("calculated txpower index %d\n",
+ power_index); */
+
+ if (power_index < get_min_power_index(i, band))
+ power_index = get_min_power_index(i, band);
+
+ /* adjust 5 GHz index to support negative indexes */
+ if (!band)
+ power_index += 9;
+
+ /* CCK, rate 32, reduce txpower for CCK */
+ if (i == POWER_TABLE_CCK_ENTRY)
+ power_index +=
+ IWL_TX_POWER_CCK_COMPENSATION_C_STEP;
+
+ /* stay within the table! */
+ if (power_index > 107) {
+ IWL_WARNING("txpower index %d > 107\n",
+ power_index);
+ power_index = 107;
+ }
+ if (power_index < 0) {
+ IWL_WARNING("txpower index %d < 0\n",
+ power_index);
+ power_index = 0;
+ }
+
+ /* fill txpower command for this rate/chain */
+ tx_power.s.radio_tx_gain[c] =
+ gain_table[band][power_index].radio;
+ tx_power.s.dsp_predis_atten[c] =
+ gain_table[band][power_index].dsp;
+
+ IWL_DEBUG_TXPOWER("chain %d mimo %d index %d "
+ "gain 0x%02x dsp %d\n",
+ c, atten_value, power_index,
+ tx_power.s.radio_tx_gain[c],
+ tx_power.s.dsp_predis_atten[c]);
+ }/* for each chain */
+
+ tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);
+
+ }/* for each rate */
+
+ return 0;
+}
+
+/**
+ * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit
+ *
+ * Uses the active RXON for channel, band, and characteristics (fat, high)
+ * The power limit is taken from priv->user_txpower_limit.
+ */
+int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+{
+ struct iwl_txpowertable_cmd cmd = { 0 };
+ int rc = 0;
+ u8 band = 0;
+ u8 is_fat = 0;
+ u8 ctrl_chan_high = 0;
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ /* If this gets hit a lot, switch it to a BUG() and catch
+ * the stack trace to find out who is calling this during
+ * a scan. */
+ IWL_WARNING("TX Power requested while scanning!\n");
+ return -EAGAIN;
+ }
+
+ band = ((priv->phymode == MODE_IEEE80211B) ||
+ (priv->phymode == MODE_IEEE80211G));
+
+ is_fat = is_fat_channel(priv->active_rxon.flags);
+
+ if (is_fat &&
+ (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ ctrl_chan_high = 1;
+
+ cmd.band = band;
+ cmd.channel = priv->active_rxon.channel;
+
+ rc = iwl4965_fill_txpower_tbl(priv, band,
+ le16_to_cpu(priv->active_rxon.channel),
+ is_fat, ctrl_chan_high, &cmd.tx_power);
+ if (rc)
+ return rc;
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
+ return rc;
+}
+
+int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ int rc;
+ u8 band = 0;
+ u8 is_fat = 0;
+ u8 ctrl_chan_high = 0;
+ struct iwl_channel_switch_cmd cmd = { 0 };
+ const struct iwl_channel_info *ch_info;
+
+ band = ((priv->phymode == MODE_IEEE80211B) ||
+ (priv->phymode == MODE_IEEE80211G));
+
+ ch_info = iwl_get_channel_info(priv, priv->phymode, channel);
+
+ is_fat = is_fat_channel(priv->staging_rxon.flags);
+
+ if (is_fat &&
+ (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ ctrl_chan_high = 1;
+
+ cmd.band = band;
+ cmd.expect_beacon = 0;
+ cmd.channel = cpu_to_le16(channel);
+ cmd.rxon_flags = priv->active_rxon.flags;
+ cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ if (ch_info)
+ cmd.expect_beacon = is_channel_radar(ch_info);
+ else
+ cmd.expect_beacon = 1;
+
+ rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat,
+ ctrl_chan_high, &cmd.tx_power);
+ if (rc) {
+ IWL_DEBUG_11H("error:%d fill txpower_tbl\n", rc);
+ return rc;
+ }
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
+ return rc;
+}
+
+#define RTS_HCCA_RETRY_LIMIT 3
+#define RTS_DFAULT_RETRY_LIMIT 60
+
+void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr, int sta_id,
+ int is_hcca)
+{
+ u8 rate;
+ u8 rts_retry_limit = 0;
+ u8 data_retry_limit = 0;
+ __le32 tx_flags;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ tx_flags = cmd->cmd.tx.tx_flags;
+
+ rate = iwl_rates[ctrl->tx_rate].plcp;
+
+ rts_retry_limit = (is_hcca) ?
+ RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
+
+ if (ieee80211_is_probe_response(fc)) {
+ data_retry_limit = 3;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ } else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+ if (priv->data_retry_limit != -1)
+ data_retry_limit = priv->data_retry_limit;
+
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+ if (tx_flags & TX_CMD_FLG_RTS_MSK) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
+ cmd->cmd.tx.data_retry_limit = data_retry_limit;
+ cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0);
+ cmd->cmd.tx.tx_flags = tx_flags;
+}
+
+int iwl_hw_get_rx_read(struct iwl_priv *priv)
+{
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
+}
+
+int iwl_hw_get_temperature(struct iwl_priv *priv)
+{
+ return priv->temperature;
+}
+
+unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate)
+{
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ unsigned int frame_size;
+
+ tx_beacon_cmd = &frame->u.beacon;
+ memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+ tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID;
+ tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ frame_size = iwl_fill_beacon_frame(priv,
+ tx_beacon_cmd->frame,
+ BROADCAST_ADDR,
+ sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+ BUG_ON(frame_size > MAX_MPDU_SIZE);
+ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+ if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
+ tx_beacon_cmd->tx.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
+ else
+ tx_beacon_cmd->tx.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, 0);
+
+ tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
+ TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK);
+ return (sizeof(*tx_beacon_cmd) + frame_size);
+}
+
+int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ int rc;
+ unsigned long flags;
+ int txq_id = txq->q.id;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id),
+ txq->q.dma_addr >> 8);
+ iwl_write_restricted(
+ priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+ IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr)
+{
+ return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
+}
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+ dma_addr_t addr, u16 len)
+{
+ int index, is_odd;
+ struct iwl_tfd_frame *tfd = ptr;
+ u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+ if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
+ IWL_ERROR("Error can not send more than %d chunks\n",
+ MAX_NUM_OF_TBS);
+ return -EINVAL;
+ }
+
+ index = num_tbs / 2;
+ is_odd = num_tbs & 0x1;
+
+ if (!is_odd) {
+ tfd->pa[index].tb1_addr = cpu_to_le32(addr);
+ IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
+ iwl4965_get_dma_hi_address(addr));
+ IWL_SET_BITS(tfd->pa[index], tb1_len, len);
+ } else {
+ IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
+ (u32) (addr & 0xffff));
+ IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
+ IWL_SET_BITS(tfd->pa[index], tb2_len, len);
+ }
+
+ IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+
+ return 0;
+}
+
+void iwl_hw_card_show_info(struct iwl_priv *priv)
+{
+ u16 hw_version = priv->eeprom.board_revision_4965;
+
+ IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
+ ((hw_version >> 8) & 0x0F),
+ ((hw_version >> 8) >> 4), (hw_version & 0x00FF));
+
+ IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
+ priv->eeprom.board_pba_number_4965);
+}
+
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
+
+int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u16 byte_cnt)
+{
+ int len;
+ int txq_id = txq->q.id;
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ if (txq->need_update == 0)
+ return 0;
+
+ len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[txq->q.first_empty], byte_cnt, len);
+
+ if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE)
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty],
+ byte_cnt, len);
+
+ return 0;
+}
+
+/* Set up Rx receiver/antenna/chain usage in "staging" RXON image.
+ * This should not be used for scan command ... it puts data in wrong place. */
+void iwl4965_set_rxon_chain(struct iwl_priv *priv)
+{
+ u8 is_single = is_single_stream(priv);
+ u8 idle_state, rx_state;
+
+ priv->staging_rxon.rx_chain = 0;
+ rx_state = idle_state = 3;
+
+ /* Tell uCode which antennas are actually connected.
+ * Before first association, we assume all antennas are connected.
+ * Just after first association, iwl4965_noise_calibration()
+ * checks which antennas actually *are* connected. */
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS);
+
+ /* How many receivers should we use? */
+ iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state);
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
+
+ if (!is_single && (rx_state >= 2) &&
+ !test_bit(STATUS_POWER_PMI, &priv->status))
+ priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+ else
+ priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+ IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+/*
+ get the traffic load value for tid
+*/
+static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid)
+{
+ u32 load = 0;
+ u32 current_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ unsigned long flags;
+ struct iwl_traffic_load *tid_ptr = NULL;
+
+ if (tid >= TID_MAX_LOAD_COUNT)
+ return 0;
+
+ tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+ current_time -= current_time % TID_ROUND_VALUE;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (!(tid_ptr->queue_count))
+ goto out;
+
+ time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ if (index >= TID_QUEUE_MAX_SIZE) {
+ u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+ while (tid_ptr->queue_count &&
+ (tid_ptr->time_stamp < oldest_time)) {
+ tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+ tid_ptr->packet_count[tid_ptr->head] = 0;
+ tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+ tid_ptr->queue_count--;
+ tid_ptr->head++;
+ if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+ tid_ptr->head = 0;
+ }
+ }
+ load = tid_ptr->total;
+
+ out:
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ return load;
+}
+
+/*
+ increment traffic load value for tid and also remove
+ any old values if passed the certian time period
+*/
+static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid)
+{
+ u32 current_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ unsigned long flags;
+ struct iwl_traffic_load *tid_ptr = NULL;
+
+ if (tid >= TID_MAX_LOAD_COUNT)
+ return;
+
+ tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+ current_time -= current_time % TID_ROUND_VALUE;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (!(tid_ptr->queue_count)) {
+ tid_ptr->total = 1;
+ tid_ptr->time_stamp = current_time;
+ tid_ptr->queue_count = 1;
+ tid_ptr->head = 0;
+ tid_ptr->packet_count[0] = 1;
+ goto out;
+ }
+
+ time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ if (index >= TID_QUEUE_MAX_SIZE) {
+ u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+ while (tid_ptr->queue_count &&
+ (tid_ptr->time_stamp < oldest_time)) {
+ tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+ tid_ptr->packet_count[tid_ptr->head] = 0;
+ tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+ tid_ptr->queue_count--;
+ tid_ptr->head++;
+ if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+ tid_ptr->head = 0;
+ }
+ }
+
+ index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE;
+ tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1;
+ tid_ptr->total = tid_ptr->total + 1;
+
+ if ((index + 1) > tid_ptr->queue_count)
+ tid_ptr->queue_count = index + 1;
+ out:
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+}
+
+#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7
+enum HT_STATUS {
+ BA_STATUS_FAILURE = 0,
+ BA_STATUS_INITIATOR_DELBA,
+ BA_STATUS_RECIPIENT_DELBA,
+ BA_STATUS_RENEW_ADDBA_REQUEST,
+ BA_STATUS_ACTIVE,
+};
+
+static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv)
+{
+ int i;
+ struct iwl_lq_mngr *lq;
+ u8 count = 0;
+ u16 msk;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+ for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
+ msk = 1 << i;
+ if ((lq->agg_ctrl.granted_ba & msk) ||
+ (lq->agg_ctrl.wait_for_agg_status & msk))
+ count++;
+ }
+
+ if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS)
+ return 1;
+
+ return 0;
+}
+
+static void iwl4965_ba_status(struct iwl_priv *priv,
+ u8 tid, enum HT_STATUS status);
+
+static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length,
+ u32 ba_timeout)
+{
+ int rc;
+
+ rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid);
+ if (rc)
+ iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+ return rc;
+}
+
+static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid)
+{
+ int rc;
+
+ rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid);
+ if (rc)
+ iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+ return rc;
+}
+
+static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv,
+ struct iwl_lq_mngr *lq,
+ u8 auto_agg, u8 tid)
+{
+ u32 tid_msk = (1 << tid);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+/*
+ if ((auto_agg) && (!lq->enable_counter)){
+ lq->agg_ctrl.next_retry = 0;
+ lq->agg_ctrl.tid_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ return;
+ }
+*/
+ if (!(lq->agg_ctrl.granted_ba & tid_msk) &&
+ (lq->agg_ctrl.requested_ba & tid_msk)) {
+ u8 available_queues;
+ u32 load;
+
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ available_queues = iwl4964_tl_ba_avail(priv);
+ load = iwl4965_tl_get_load(priv, tid);
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (!available_queues) {
+ if (auto_agg)
+ lq->agg_ctrl.tid_retry |= tid_msk;
+ else {
+ lq->agg_ctrl.requested_ba &= ~tid_msk;
+ lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+ }
+ } else if ((auto_agg) &&
+ ((load <= lq->agg_ctrl.tid_traffic_load_threshold) ||
+ ((lq->agg_ctrl.wait_for_agg_status & tid_msk))))
+ lq->agg_ctrl.tid_retry |= tid_msk;
+ else {
+ lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ iwl4965_perform_addba(priv, tid, 0x40,
+ lq->agg_ctrl.ba_timeout);
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+}
+
+static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid)
+{
+ struct iwl_lq_mngr *lq;
+ unsigned long flags;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ if ((tid < TID_MAX_LOAD_COUNT))
+ iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
+ tid);
+ else if (tid == TID_ALL_SPECIFIED) {
+ if (lq->agg_ctrl.requested_ba) {
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
+ iwl4965_turn_on_agg_for_tid(priv, lq,
+ lq->agg_ctrl.auto_agg, tid);
+ } else {
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ lq->agg_ctrl.tid_retry = 0;
+ lq->agg_ctrl.next_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ }
+ }
+
+}
+
+void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid)
+{
+ u32 tid_msk;
+ struct iwl_lq_mngr *lq;
+ unsigned long flags;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ if ((tid < TID_MAX_LOAD_COUNT)) {
+ tid_msk = 1 << tid;
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+ lq->agg_ctrl.requested_ba &= ~tid_msk;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ iwl4965_perform_delba(priv, tid);
+ } else if (tid == TID_ALL_SPECIFIED) {
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+ tid_msk = 1 << tid;
+ lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ iwl4965_perform_delba(priv, tid);
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ }
+ lq->agg_ctrl.requested_ba = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ }
+}
+
+static void iwl4965_ba_status(struct iwl_priv *priv,
+ u8 tid, enum HT_STATUS status)
+{
+ struct iwl_lq_mngr *lq;
+ u32 tid_msk = (1 << tid);
+ unsigned long flags;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ if ((tid >= TID_MAX_LOAD_COUNT))
+ goto out;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ switch (status) {
+ case BA_STATUS_ACTIVE:
+ if (!(lq->agg_ctrl.granted_ba & tid_msk))
+ lq->agg_ctrl.granted_ba |= tid_msk;
+ break;
+ default:
+ if ((lq->agg_ctrl.granted_ba & tid_msk))
+ lq->agg_ctrl.granted_ba &= ~tid_msk;
+ break;
+ }
+
+ lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+ if (status != BA_STATUS_ACTIVE) {
+ if (lq->agg_ctrl.auto_agg) {
+ lq->agg_ctrl.tid_retry |= tid_msk;
+ lq->agg_ctrl.next_retry =
+ jiffies + msecs_to_jiffies(500);
+ } else
+ lq->agg_ctrl.requested_ba &= ~tid_msk;
+ }
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ out:
+ return;
+}
+
+static void iwl4965_bg_agg_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ agg_work);
+
+ u32 tid;
+ u32 retry_tid;
+ u32 tid_msk;
+ unsigned long flags;
+ struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ retry_tid = lq->agg_ctrl.tid_retry;
+ lq->agg_ctrl.tid_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+ if (retry_tid == TID_ALL_SPECIFIED)
+ iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED);
+ else {
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+ tid_msk = (1 << tid);
+ if (retry_tid & tid_msk)
+ iwl4965_turn_on_agg(priv, tid);
+ }
+ }
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (lq->agg_ctrl.tid_retry)
+ lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500);
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ return;
+}
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+ u8 sta_id, dma_addr_t txcmd_phys,
+ struct ieee80211_hdr *hdr, u8 hdr_len,
+ struct ieee80211_tx_control *ctrl, void *sta_in)
+{
+ struct iwl_tx_cmd cmd;
+ struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0];
+ dma_addr_t scratch_phys;
+ u8 unicast = 0;
+ u8 is_data = 1;
+ u16 fc;
+ u16 rate_flags;
+ int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ __le16 *qc;
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+ is_data = 0;
+
+ memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd));
+ memset(tx, 0, sizeof(struct iwl_tx_cmd));
+ memcpy(tx->hdr, hdr, hdr_len);
+
+ tx->len = cmd.len;
+ tx->driver_txop = cmd.driver_txop;
+ tx->stop_time.life_time = cmd.stop_time.life_time;
+ tx->tx_flags = cmd.tx_flags;
+ tx->sta_id = cmd.sta_id;
+ tx->tid_tspec = cmd.tid_tspec;
+ tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout;
+ tx->next_frame_len = cmd.next_frame_len;
+
+ tx->sec_ctl = cmd.sec_ctl;
+ memcpy(&(tx->key[0]), &(cmd.key[0]), 16);
+ tx->tx_flags = cmd.tx_flags;
+
+ tx->rts_retry_limit = cmd.rts_retry_limit;
+ tx->data_retry_limit = cmd.data_retry_limit;
+
+ scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+ offsetof(struct iwl_tx_cmd, scratch);
+ tx->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+ tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys);
+
+ /* Hard coded to start at the highest retry fallback position
+ * until the 4965 specific rate control algorithm is tied in */
+ tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
+
+ /* Alternate between antenna A and B for successive frames */
+ if (priv->use_ant_b_for_management_frame) {
+ priv->use_ant_b_for_management_frame = 0;
+ rate_flags = RATE_MCS_ANT_B_MSK;
+ } else {
+ priv->use_ant_b_for_management_frame = 1;
+ rate_flags = RATE_MCS_ANT_A_MSK;
+ }
+
+ if (!unicast || !is_data) {
+ if ((rate_index >= IWL_FIRST_CCK_RATE) &&
+ (rate_index <= IWL_LAST_CCK_RATE))
+ rate_flags |= RATE_MCS_CCK_MSK;
+ } else {
+ tx->initial_rate_index = 0;
+ tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+ }
+
+ tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp,
+ rate_flags);
+
+ if (ieee80211_is_probe_request(fc))
+ tx->tx_flags |= TX_CMD_FLG_TSF_MSK;
+ else if (ieee80211_is_back_request(fc))
+ tx->tx_flags |= TX_CMD_FLG_ACK_MSK |
+ TX_CMD_FLG_IMM_BA_RSP_MASK;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
+ u8 tid = 0;
+ tid = (u8) (le16_to_cpu(*qc) & 0xF);
+ if (tid < TID_MAX_LOAD_COUNT)
+ iwl4965_tl_add_packet(priv, tid);
+ }
+
+ if (priv->lq_mngr.agg_ctrl.next_retry &&
+ (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ priv->lq_mngr.agg_ctrl.next_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ schedule_work(&priv->agg_work);
+ }
+#endif
+#endif
+ return 0;
+}
+
+/**
+ * sign_extend - Sign extend a value using specified bit as sign-bit
+ *
+ * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1
+ * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7.
+ *
+ * @param oper value to sign extend
+ * @param index 0 based bit index (0<=index<32) to sign bit
+ */
+static s32 sign_extend(u32 oper, int index)
+{
+ u8 shift = 31 - index;
+
+ return (s32)(oper << shift) >> shift;
+}
+
+/**
+ * iwl4965_get_temperature - return the calibrated temperature (in Kelvin)
+ * @statistics: Provides the temperature reading from the uCode
+ *
+ * A return of <0 indicates bogus data in the statistics
+ */
+int iwl4965_get_temperature(const struct iwl_priv *priv)
+{
+ s32 temperature;
+ s32 vt;
+ s32 R1, R2, R3;
+ u32 R4;
+
+ if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
+ (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) {
+ IWL_DEBUG_TEMP("Running FAT temperature calibration\n");
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+ R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]);
+ } else {
+ IWL_DEBUG_TEMP("Running temperature calibration\n");
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+ R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]);
+ }
+
+ /*
+ * Temperature is only 23 bits so sign extend out to 32
+ *
+ * NOTE If we haven't received a statistics notification yet
+ * with an updated temperature, use R4 provided to us in the
+ * ALIVE response. */
+ if (!test_bit(STATUS_TEMPERATURE, &priv->status))
+ vt = sign_extend(R4, 23);
+ else
+ vt = sign_extend(
+ le32_to_cpu(priv->statistics.general.temperature), 23);
+
+ IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n",
+ R1, R2, R3, vt);
+
+ if (R3 == R1) {
+ IWL_ERROR("Calibration conflict R1 == R3\n");
+ return -1;
+ }
+
+ /* Calculate temperature in degrees Kelvin, adjust by 97%.
+ * Add offset to center the adjustment around 0 degrees Centigrade. */
+ temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2);
+ temperature /= (R3 - R1);
+ temperature = (temperature * 97) / 100 +
+ TEMPERATURE_CALIB_KELVIN_OFFSET;
+
+ IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", temperature,
+ KELVIN_TO_CELSIUS(temperature));
+
+ return temperature;
+}
+
+/* Adjust Txpower only if temperature variance is greater than threshold. */
+#define IWL_TEMPERATURE_THRESHOLD 3
+
+/**
+ * iwl4965_is_temp_calib_needed - determines if new calibration is needed
+ *
+ * If the temperature changed has changed sufficiently, then a recalibration
+ * is needed.
+ *
+ * Assumes caller will replace priv->last_temperature once calibration
+ * executed.
+ */
+static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
+{
+ int temp_diff;
+
+ if (!test_bit(STATUS_STATISTICS, &priv->status)) {
+ IWL_DEBUG_TEMP("Temperature not updated -- no statistics.\n");
+ return 0;
+ }
+
+ temp_diff = priv->temperature - priv->last_temperature;
+
+ /* get absolute value */
+ if (temp_diff < 0) {
+ IWL_DEBUG_POWER("Getting cooler, delta %d, \n", temp_diff);
+ temp_diff = -temp_diff;
+ } else if (temp_diff == 0)
+ IWL_DEBUG_POWER("Same temp, \n");
+ else
+ IWL_DEBUG_POWER("Getting warmer, delta %d, \n", temp_diff);
+
+ if (temp_diff < IWL_TEMPERATURE_THRESHOLD) {
+ IWL_DEBUG_POWER("Thermal txpower calib not needed\n");
+ return 0;
+ }
+
+ IWL_DEBUG_POWER("Thermal txpower calib needed\n");
+
+ return 1;
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ * before arriving beacon. This measurement can be done only if we know
+ * exactly when to expect beacons, therefore only when we're associated. */
+static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
+{
+ struct statistics_rx_non_phy *rx_info
+ = &(priv->statistics.rx.general);
+ int num_active_rx = 0;
+ int total_silence = 0;
+ int bcn_silence_a =
+ le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+ int bcn_silence_b =
+ le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+ int bcn_silence_c =
+ le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+ if (bcn_silence_a) {
+ total_silence += bcn_silence_a;
+ num_active_rx++;
+ }
+ if (bcn_silence_b) {
+ total_silence += bcn_silence_b;
+ num_active_rx++;
+ }
+ if (bcn_silence_c) {
+ total_silence += bcn_silence_c;
+ num_active_rx++;
+ }
+
+ /* Average among active antennas */
+ if (num_active_rx)
+ priv->last_rx_noise = (total_silence / num_active_rx) - 107;
+ else
+ priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+ IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n",
+ bcn_silence_a, bcn_silence_b, bcn_silence_c,
+ priv->last_rx_noise);
+}
+
+void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ int change;
+ s32 temp;
+
+ IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
+ (int)sizeof(priv->statistics), pkt->len);
+
+ change = ((priv->statistics.general.temperature !=
+ pkt->u.stats.general.temperature) ||
+ ((priv->statistics.flag &
+ STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
+ (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)));
+
+ memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
+
+ set_bit(STATUS_STATISTICS, &priv->status);
+
+ /* Reschedule the statistics timer to occur in
+ * REG_RECALIB_PERIOD seconds to ensure we get a
+ * thermal update even if the uCode doesn't give
+ * us one */
+ mod_timer(&priv->statistics_periodic, jiffies +
+ msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+ (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+ iwl4965_rx_calc_noise(priv);
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ queue_work(priv->workqueue, &priv->sensitivity_work);
+#endif
+ }
+
+ /* If the hardware hasn't reported a change in
+ * temperature then don't bother computing a
+ * calibrated temperature value */
+ if (!change)
+ return;
+
+ temp = iwl4965_get_temperature(priv);
+ if (temp < 0)
+ return;
+
+ if (priv->temperature != temp) {
+ if (priv->temperature)
+ IWL_DEBUG_TEMP("Temperature changed "
+ "from %dC to %dC\n",
+ KELVIN_TO_CELSIUS(priv->temperature),
+ KELVIN_TO_CELSIUS(temp));
+ else
+ IWL_DEBUG_TEMP("Temperature "
+ "initialized to %dC\n",
+ KELVIN_TO_CELSIUS(temp));
+ }
+
+ priv->temperature = temp;
+ set_bit(STATUS_TEMPERATURE, &priv->status);
+
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+ iwl4965_is_temp_calib_needed(priv))
+ queue_work(priv->workqueue, &priv->txpower_work);
+}
+
+static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
+ int include_phy,
+ struct iwl_rx_mem_buffer *rxb,
+ struct ieee80211_rx_status *stats)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
+ (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
+ struct ieee80211_hdr *hdr;
+ u16 len;
+ __le32 *rx_end;
+ unsigned int skblen;
+ u32 ampdu_status;
+
+ if (!include_phy && priv->last_phy_res[0])
+ rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+
+ if (!rx_start) {
+ IWL_ERROR("MPDU frame without a PHY data\n");
+ return;
+ }
+ if (include_phy) {
+ hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] +
+ rx_start->cfg_phy_cnt);
+
+ len = le16_to_cpu(rx_start->byte_count);
+
+ rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] +
+ sizeof(struct iwl4965_rx_phy_res) +
+ rx_start->cfg_phy_cnt + len);
+
+ } else {
+ struct iwl4965_rx_mpdu_res_start *amsdu =
+ (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+
+ hdr = (struct ieee80211_hdr *)(pkt->u.raw +
+ sizeof(struct iwl4965_rx_mpdu_res_start));
+ len = le16_to_cpu(amsdu->byte_count);
+ rx_start->byte_count = amsdu->byte_count;
+ rx_end = (__le32 *) (((u8 *) hdr) + len);
+ }
+ if (len > 2342 || len < 16) {
+ IWL_DEBUG_DROP("byte count out of range [16,2342]"
+ " : %d\n", len);
+ return;
+ }
+
+ ampdu_status = le32_to_cpu(*rx_end);
+ skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);
+
+ /* start from MAC */
+ skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
+ skb_put(rxb->skb, len); /* end where data ends */
+
+ /* We only process data packets if the interface is open */
+ if (unlikely(!priv->is_open)) {
+ IWL_DEBUG_DROP_LIMIT
+ ("Dropping packet while interface is not open.\n");
+ return;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb,
+ ampdu_status, stats);
+ iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0);
+ return;
+ }
+
+ stats->flag = 0;
+ hdr = (struct ieee80211_hdr *)rxb->skb->data;
+
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ priv->alloc_rxb_skb--;
+ rxb->skb = NULL;
+#ifdef LED
+ priv->led_packets += len;
+ iwl_setup_activity_timer(priv);
+#endif
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
+{
+ /* data from PHY/DSP regarding signal strength, etc.,
+ * contents are always there, not configurable by host. */
+ struct iwl4965_rx_non_cfg_phy *ncphy =
+ (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy;
+ u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK)
+ >> IWL_AGC_DB_POS;
+
+ u32 valid_antennae =
+ (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK)
+ >> RX_PHY_FLAGS_ANTENNAE_OFFSET;
+ u8 max_rssi = 0;
+ u32 i;
+
+ /* Find max rssi among 3 possible receivers.
+ * These values are measured by the digital signal processor (DSP).
+ * They should stay fairly constant even as the signal strength varies,
+ * if the radio's automatic gain control (AGC) is working right.
+ * AGC value (see below) will provide the "interesting" info. */
+ for (i = 0; i < 3; i++)
+ if (valid_antennae & (1 << i))
+ max_rssi = max(ncphy->rssi_info[i << 1], max_rssi);
+
+ IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+ ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4],
+ max_rssi, agc);
+
+ /* dBm = max_rssi dB - agc dB - constant.
+ * Higher AGC (higher radio gain) means lower signal. */
+ return (max_rssi - agc - IWL_RSSI_OFFSET);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ u8 *ds_params;
+ u8 ds_params_len;
+ u8 *tim;
+ u8 tim_len;
+ u8 *ibss_params;
+ u8 ibss_params_len;
+ u8 *erp_info;
+ u8 erp_info_len;
+ u8 *ht_cap_param;
+ u8 ht_cap_param_len;
+ u8 *ht_extra_param;
+ u8 ht_extra_param_len;
+};
+
+static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems)
+{
+ size_t left = len;
+ u8 *pos = start;
+ int unknown = 0;
+
+ memset(elems, 0, sizeof(*elems));
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left)
+ return -1;
+
+ switch (id) {
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = pos;
+ elems->ds_params_len = elen;
+ break;
+ case WLAN_EID_TIM:
+ elems->tim = pos;
+ elems->tim_len = elen;
+ break;
+ case WLAN_EID_IBSS_PARAMS:
+ elems->ibss_params = pos;
+ elems->ibss_params_len = elen;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = pos;
+ elems->erp_info_len = elen;
+ break;
+ case WLAN_EID_HT_CAPABILITY:
+ elems->ht_cap_param = pos;
+ elems->ht_cap_param_len = elen;
+ break;
+ case WLAN_EID_HT_EXTRA_INFO:
+ elems->ht_extra_param = pos;
+ elems->ht_extra_param_len = elen;
+ break;
+ default:
+ unknown++;
+ break;
+ }
+
+ left -= elen;
+ pos += elen;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IWLWIFI_HT */
+
+static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.sta.modify_mask = 0;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+ /* FIXME: need locking over ps_status ??? */
+ u8 sta_id = iwl_hw_find_station(priv, addr);
+
+ if (sta_id != IWL_INVALID_STATION) {
+ u8 sta_awake = priv->stations[sta_id].
+ ps_status == STA_PS_STATUS_WAKE;
+
+ if (sta_awake && ps_bit)
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+ else if (!sta_awake && !ps_bit) {
+ iwl4965_sta_modify_ps_wake(priv, sta_id);
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+ }
+ }
+}
+
+/* Called for REPLY_4965_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ /* Use phy data (Rx signal strength, etc.) contained within
+ * this rx packet for legacy frames,
+ * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
+ int include_phy = (pkt->hdr.cmd == REPLY_4965_RX);
+ struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
+ (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) :
+ (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+ __le32 *rx_end;
+ unsigned int len = 0;
+ struct ieee80211_hdr *header;
+ u16 fc;
+ struct ieee80211_rx_status stats = {
+ .mactime = le64_to_cpu(rx_start->timestamp),
+ .channel = le16_to_cpu(rx_start->channel),
+ .phymode =
+ (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ MODE_IEEE80211G : MODE_IEEE80211A,
+ .antenna = 0,
+ .rate = iwl_hw_get_rate(rx_start->rate_n_flags),
+ .flag = 0,
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ .ordered = 0
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+ };
+ u8 network_packet;
+
+ if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
+ IWL_DEBUG_DROP
+ ("dsp size out of range [0,20]: "
+ "%d/n", rx_start->cfg_phy_cnt);
+ return;
+ }
+ if (!include_phy) {
+ if (priv->last_phy_res[0])
+ rx_start = (struct iwl4965_rx_phy_res *)
+ &priv->last_phy_res[1];
+ else
+ rx_start = NULL;
+ }
+
+ if (!rx_start) {
+ IWL_ERROR("MPDU frame without a PHY data\n");
+ return;
+ }
+
+ if (include_phy) {
+ header = (struct ieee80211_hdr *)((u8 *) & rx_start[1]
+ + rx_start->cfg_phy_cnt);
+
+ len = le16_to_cpu(rx_start->byte_count);
+ rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt +
+ sizeof(struct iwl4965_rx_phy_res) + len);
+ } else {
+ struct iwl4965_rx_mpdu_res_start *amsdu =
+ (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+
+ header = (void *)(pkt->u.raw +
+ sizeof(struct iwl4965_rx_mpdu_res_start));
+ len = le16_to_cpu(amsdu->byte_count);
+ rx_end = (__le32 *) (pkt->u.raw +
+ sizeof(struct iwl4965_rx_mpdu_res_start) + len);
+ }
+
+ if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) ||
+ !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+ IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n",
+ le32_to_cpu(*rx_end));
+ return;
+ }
+
+ priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
+
+ stats.freq = ieee80211chan2mhz(stats.channel);
+
+ /* Find max signal strength (dBm) among 3 antenna/receiver chains */
+ stats.ssi = iwl4965_calc_rssi(rx_start);
+
+ /* Meaningful noise values are available only from beacon statistics,
+ * which are gathered only when associated, and indicate noise
+ * only for the associated network channel ...
+ * Ignore these noise values while scanning (other channels) */
+ if (iwl_is_associated(priv) &&
+ !test_bit(STATUS_SCANNING, &priv->status)) {
+ stats.noise = priv->last_rx_noise;
+ stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+ } else {
+ stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+ stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+ }
+
+ /* Reset beacon noise level if not associated. */
+ if (!iwl_is_associated(priv))
+ priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ /* TODO: Parts of iwl_report_frame are broken for 4965 */
+ if (iwl_debug_level & (IWL_DL_RX))
+ /* Set "1" to report good data frames in groups of 100 */
+ iwl_report_frame(priv, pkt, header, 1);
+
+ if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS))
+ IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n",
+ stats.ssi, stats.noise, stats.signal,
+ (long unsigned int)le64_to_cpu(rx_start->timestamp));
+#endif
+
+ network_packet = iwl_is_network_packet(priv, header);
+ if (network_packet) {
+ priv->last_rx_rssi = stats.ssi;
+ priv->last_beacon_time = priv->ucode_beacon_time;
+ priv->last_tsf = le64_to_cpu(rx_start->timestamp);
+ }
+
+ fc = le16_to_cpu(header->frame_control);
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_MGMT:
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
+ header->addr2);
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA &&
+ !compare_ether_addr(header->addr2, priv->bssid)) ||
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ !compare_ether_addr(header->addr3, priv->bssid))) {
+ struct ieee80211_mgmt *mgmt =
+ (struct ieee80211_mgmt *)header;
+ u64 timestamp =
+ le64_to_cpu(mgmt->u.beacon.timestamp);
+
+ priv->timestamp0 = timestamp & 0xFFFFFFFF;
+ priv->timestamp1 =
+ (timestamp >> 32) & 0xFFFFFFFF;
+ priv->beacon_int = le16_to_cpu(
+ mgmt->u.beacon.beacon_int);
+ if (priv->call_post_assoc_from_beacon &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+ priv->call_post_assoc_from_beacon = 0;
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+ }
+ }
+ break;
+
+ case IEEE80211_STYPE_ACTION:
+ break;
+
+ /*
+ * TODO: There is no callback function from upper
+ * stack to inform us when associated status. this
+ * work around to sniff assoc_resp management frame
+ * and finish the association process.
+ */
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:
+ if (network_packet && iwl_is_associated(priv)) {
+#ifdef CONFIG_IWLWIFI_HT
+ u8 *pos = NULL;
+ struct ieee802_11_elems elems;
+#endif /*CONFIG_IWLWIFI_HT */
+ struct ieee80211_mgmt *mgnt =
+ (struct ieee80211_mgmt *)header;
+
+ priv->assoc_id = (~((1 << 15) | (1 << 14))
+ & le16_to_cpu(mgnt->u.assoc_resp.aid));
+ priv->assoc_capability =
+ le16_to_cpu(
+ mgnt->u.assoc_resp.capab_info);
+#ifdef CONFIG_IWLWIFI_HT
+ pos = mgnt->u.assoc_resp.variable;
+ if (!parse_elems(pos,
+ len - (pos - (u8 *) mgnt),
+ &elems)) {
+ if (elems.ht_extra_param &&
+ elems.ht_cap_param)
+ break;
+ }
+#endif /*CONFIG_IWLWIFI_HT */
+ /* assoc_id is 0 no association */
+ if (!priv->assoc_id)
+ break;
+ if (priv->beacon_int)
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+ else
+ priv->call_post_assoc_from_beacon = 1;
+ }
+
+ break;
+
+ case IEEE80211_STYPE_PROBE_REQ:
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !iwl_is_associated(priv)) {
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+
+ IWL_DEBUG_DROP("Dropping (non network): "
+ "%s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ return;
+ }
+ }
+ iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_BACK_REQ:
+ IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n");
+ iwl4965_handle_data_packet(priv, 0, include_phy,
+ rxb, &stats);
+ break;
+ default:
+ break;
+ }
+#endif
+
+ break;
+
+ case IEEE80211_FTYPE_DATA: {
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
+ header->addr2);
+
+ if (unlikely(!network_packet))
+ IWL_DEBUG_DROP("Dropping (non network): "
+ "%s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ else if (unlikely(is_duplicate_packet(priv, header)))
+ IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ else
+ iwl4965_handle_data_packet(priv, 1, include_phy, rxb,
+ &stats);
+ break;
+ }
+ default:
+ break;
+
+ }
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ priv->last_phy_res[0] = 1;
+ memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
+ sizeof(struct iwl4965_rx_phy_res));
+}
+
+static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+
+{
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_missed_beacon_notif *missed_beacon;
+
+ missed_beacon = &pkt->u.missed_beacon;
+ if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+ IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+ le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+ le32_to_cpu(missed_beacon->total_missed_becons),
+ le32_to_cpu(missed_beacon->num_recvd_beacons),
+ le32_to_cpu(missed_beacon->num_expected_beacons));
+ priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
+ queue_work(priv->workqueue, &priv->sensitivity_work);
+ }
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx,
+ u32 status, u32 retry_count, u32 rate)
+{
+ struct ieee80211_tx_status *tx_status =
+ &(priv->txq[txq_id].txb[idx].status);
+
+ tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0;
+ tx_status->retry_count += retry_count;
+ tx_status->control.tx_rate = rate;
+}
+
+
+static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv,
+ int sta_id, int tid)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+ priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+
+static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
+ struct iwl_ht_agg *agg,
+ struct iwl_compressed_ba_resp*
+ ba_resp)
+
+{
+ int i, sh, ack;
+ u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl);
+ u32 bitmap0, bitmap1;
+ u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0);
+ u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1);
+
+ if (unlikely(!agg->wait_for_ba)) {
+ IWL_ERROR("Received BA when not expected\n");
+ return -EINVAL;
+ }
+ agg->wait_for_ba = 0;
+ IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl);
+ sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4);
+ if (sh < 0) /* tbw something is wrong with indeces */
+ sh += 0x100;
+
+ /* don't use 64 bits for now */
+ bitmap0 = resp_bitmap0 >> sh;
+ bitmap1 = resp_bitmap1 >> sh;
+ bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh);
+
+ if (agg->frame_count > (64 - sh)) {
+ IWL_DEBUG_TX_REPLY("more frames than bitmap size");
+ return -1;
+ }
+
+ /* check for success or failure according to the
+ * transmitted bitmap and back bitmap */
+ bitmap0 &= agg->bitmap0;
+ bitmap1 &= agg->bitmap1;
+
+ for (i = 0; i < agg->frame_count ; i++) {
+ int idx = (agg->start_idx + i) & 0xff;
+ ack = bitmap0 & (1 << i);
+ IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
+ ack? "ACK":"NACK", i, idx, agg->start_idx + i);
+ iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0,
+ agg->rate_n_flags);
+
+ }
+
+ IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1);
+
+ return 0;
+}
+
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return (index == 0) ? n_bd - 1 : index - 1;
+}
+
+static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+ int index;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_ht_agg *agg;
+ u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow);
+ u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+ if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) {
+ IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
+ return;
+ }
+
+ txq = &priv->txq[ba_resp_scd_flow];
+ agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
+ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+ /* TODO: Need to get this copy more sefely - now good for debug */
+/*
+ {
+ DECLARE_MAC_BUF(mac);
+ IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
+ "sta_id = %d\n",
+ agg->wait_for_ba,
+ print_mac(mac, (u8*) &ba_resp->sta_addr_lo32),
+ ba_resp->sta_id);
+ IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = "
+ "%d, scd_ssn = %d\n",
+ ba_resp->tid,
+ ba_resp->ba_seq_ctl,
+ ba_resp->ba_bitmap1,
+ ba_resp->ba_bitmap0,
+ ba_resp->scd_flow,
+ ba_resp->scd_ssn);
+ IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n",
+ agg->start_idx,
+ agg->bitmap1,
+ agg->bitmap0);
+ }
+*/
+ iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+ /* releases all the TFDs until the SSN */
+ if (txq->q.last_used != (ba_resp_scd_ssn & 0xff))
+ iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
+
+}
+
+
+static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+{
+ iwl_write_restricted_reg(priv,
+ SCD_QUEUE_STATUS_BITS(txq_id),
+ (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+ u16 txq_id)
+{
+ u32 tbl_dw_addr;
+ u32 tbl_dw;
+ u16 scd_q2ratid;
+
+ scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+ tbl_dw_addr = priv->scd_base_addr +
+ SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+
+ tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr);
+
+ if (txq_id & 0x1)
+ tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+ else
+ tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+ iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw);
+
+ return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
+ int tx_fifo, int sta_id, int tid,
+ u16 ssn_idx)
+{
+ unsigned long flags;
+ int rc;
+ u16 ra_tid;
+
+ if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
+ IWL_WARNING("queue number too small: %d, must be > %d\n",
+ txq_id, IWL_BACK_QUEUE_FIRST_ID);
+
+ ra_tid = BUILD_RAxTID(sta_id, tid);
+
+ iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+ iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+
+
+ iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id));
+
+ priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
+ priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+
+ /* supposes that ssn_idx is valid (!= 0xFFF) */
+ iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+ iwl_write_restricted_mem(priv,
+ priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
+ (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+ SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+
+ iwl_write_restricted_mem(priv, priv->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+ (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
+ & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+ iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+
+ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo)
+{
+ unsigned long flags;
+ int rc;
+
+ if (IWL_BACK_QUEUE_FIRST_ID > txq_id) {
+ IWL_WARNING("queue number too small: %d, must be > %d\n",
+ txq_id, IWL_BACK_QUEUE_FIRST_ID);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+ iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id));
+
+ priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
+ priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+ /* supposes that ssn_idx is valid (!= 0xFFF) */
+ iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+ iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+ iwl4965_txq_ctx_deactivate(priv, txq_id);
+ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+#endif/* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+/*
+ * RATE SCALE CODE
+ */
+int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates)
+{
+ return 0;
+}
+
+
+/**
+ * iwl4965_add_station - Initialize a station's hardware rate table
+ *
+ * The uCode contains a table of fallback rates and retries per rate
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This initializes the table for a single retry per data rate
+ * which is not optimal. Setting up an intelligent retry per rate
+ * requires feedback from transmission, which isn't exposed through
+ * rc80211_simple which is what this driver is currently using.
+ *
+ */
+void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int i, r;
+ struct iwl_link_quality_cmd link_cmd = {
+ .reserved1 = 0,
+ };
+ u16 rate_flags;
+
+ /* Set up the rate scaling to start at 54M and fallback
+ * all the way to 1M in IEEE order and then spin on IEEE */
+ if (is_ap)
+ r = IWL_RATE_54M_INDEX;
+ else if (priv->phymode == MODE_IEEE80211A)
+ r = IWL_RATE_6M_INDEX;
+ else
+ r = IWL_RATE_1M_INDEX;
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+ rate_flags = 0;
+ if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+ rate_flags |= RATE_MCS_CCK_MSK;
+
+ rate_flags |= RATE_MCS_ANT_B_MSK;
+ rate_flags &= ~RATE_MCS_ANT_A_MSK;
+ link_cmd.rs_table[i].rate_n_flags =
+ iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+ r = iwl_get_prev_ieee_rate(r);
+ }
+
+ link_cmd.general_params.single_stream_ant_msk = 2;
+ link_cmd.general_params.dual_stream_ant_msk = 3;
+ link_cmd.agg_params.agg_dis_start_th = 3;
+ link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
+
+ /* Update the rate scaling for control frame Tx to AP */
+ link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID;
+
+ iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
+ &link_cmd);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+
+static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
+ u16 channel, u8 extension_chan_offset)
+{
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+ if (!is_channel_valid(ch_info))
+ return 0;
+
+ if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+ return 0;
+
+ if ((ch_info->fat_extension_channel == extension_chan_offset) ||
+ (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
+ return 1;
+
+ return 0;
+}
+
+static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+ const struct sta_ht_info *ht_info)
+{
+
+ if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+ return 0;
+
+ if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)
+ return 0;
+
+ if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+ return 0;
+
+ /* no fat tx allowed on 2.4GHZ */
+ if (priv->phymode != MODE_IEEE80211A)
+ return 0;
+ return (iwl_is_channel_extension(priv, priv->phymode,
+ ht_info->control_channel,
+ ht_info->extension_chan_offset));
+}
+
+void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ u32 val;
+
+ if (!ht_info->is_ht)
+ return;
+
+ if (iwl_is_fat_tx_allowed(priv, ht_info))
+ rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ else
+ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+ RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+
+ if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
+ IWL_DEBUG_ASSOC("control diff than current %d %d\n",
+ le16_to_cpu(rxon->channel),
+ ht_info->control_channel);
+ rxon->channel = cpu_to_le16(ht_info->control_channel);
+ return;
+ }
+
+ /* Note: control channel is oposit to extension channel */
+ switch (ht_info->extension_chan_offset) {
+ case IWL_EXT_CHANNEL_OFFSET_ABOVE:
+ rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+ break;
+ case IWL_EXT_CHANNEL_OFFSET_BELOW:
+ rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+ break;
+ case IWL_EXT_CHANNEL_OFFSET_AUTO:
+ rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ break;
+ default:
+ rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ break;
+ }
+
+ val = ht_info->operating_mode;
+
+ rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
+
+ priv->active_rate_ht[0] = ht_info->supp_rates[0];
+ priv->active_rate_ht[1] = ht_info->supp_rates[1];
+ iwl4965_set_rxon_chain(priv);
+
+ IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
+ "rxon flags 0x%X operation mode :0x%X "
+ "extension channel offset 0x%x "
+ "control chan %d\n",
+ priv->active_rate_ht[0], priv->active_rate_ht[1],
+ le32_to_cpu(rxon->flags), ht_info->operating_mode,
+ ht_info->extension_chan_offset,
+ ht_info->control_channel);
+ return;
+}
+
+void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index)
+{
+ __le32 sta_flags;
+ struct sta_ht_info *ht_info = &priv->current_assoc_ht;
+
+ priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
+ if (!ht_info->is_ht)
+ goto done;
+
+ sta_flags = priv->stations[index].sta.station_flags;
+
+ if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC)
+ sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+ else
+ sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
+
+ sta_flags |= cpu_to_le32(
+ (u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+ sta_flags |= cpu_to_le32(
+ (u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+ sta_flags &= (~STA_FLG_FAT_EN_MSK);
+ ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+ ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ;
+
+ if (iwl_is_fat_tx_allowed(priv, ht_info)) {
+ sta_flags |= STA_FLG_FAT_EN_MSK;
+ ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ;
+ if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ)
+ ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ;
+ }
+ priv->current_channel_width = ht_info->tx_chan_width;
+ priv->stations[index].sta.station_flags = sta_flags;
+ done:
+ return;
+}
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
+ int sta_id, int tid, u16 ssn)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags_msk = 0;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+ priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+ priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
+ int sta_id, int tid)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags_msk = 0;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+ priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static const u16 default_tid_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_AC3
+};
+
+static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+ if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+ return txq_id;
+ return -1;
+}
+
+int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
+ u16 *start_seq_num)
+{
+
+ struct iwl_priv *priv = hw->priv;
+ int sta_id;
+ int tx_fifo;
+ int txq_id;
+ int ssn = -1;
+ unsigned long flags;
+ struct iwl_tid_data *tid_data;
+ DECLARE_MAC_BUF(mac);
+
+ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+ tx_fifo = default_tid_to_tx_fifo[tid];
+ else
+ return -EINVAL;
+
+ IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s"
+ " tid=%d\n", print_mac(mac, da), tid);
+
+ sta_id = iwl_hw_find_station(priv, da);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ txq_id = iwl_txq_ctx_activate_free(priv);
+ if (txq_id == -1)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
+ ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->agg.txq_id = txq_id;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ *start_seq_num = ssn;
+ iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE);
+ return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
+ sta_id, tid, ssn);
+}
+
+
+int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
+ int generator)
+{
+
+ struct iwl_priv *priv = hw->priv;
+ int tx_fifo_id, txq_id, sta_id, ssn = -1;
+ struct iwl_tid_data *tid_data;
+ int rc;
+ DECLARE_MAC_BUF(mac);
+
+ if (!da) {
+ IWL_ERROR("%s: da = NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+ tx_fifo_id = default_tid_to_tx_fifo[tid];
+ else
+ return -EINVAL;
+
+ sta_id = iwl_hw_find_station(priv, da);
+
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ tid_data = &priv->stations[sta_id].tid[tid];
+ ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+ txq_id = tid_data->agg.txq_id;
+
+ rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
+ /* FIXME: need more safe way to handle error condition */
+ if (rc)
+ return rc;
+
+ iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA);
+ IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n",
+ print_mac(mac, da), tid);
+
+ return 0;
+}
+
+int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, u16 start_seq_num)
+{
+ struct iwl_priv *priv = hw->priv;
+ int sta_id;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s"
+ " tid=%d\n", print_mac(mac, da), tid);
+ sta_id = iwl_hw_find_station(priv, da);
+ iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num);
+ return 0;
+}
+
+int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, int generator)
+{
+ struct iwl_priv *priv = hw->priv;
+ int sta_id;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n",
+ print_mac(mac, da), tid);
+ sta_id = iwl_hw_find_station(priv, da);
+ iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
+ return 0;
+}
+
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+/* Set up 4965-specific Rx frame reply handlers */
+void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+{
+ /* Legacy Rx frames */
+ priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx;
+
+ /* High-throughput (HT) Rx frames */
+ priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
+ priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
+
+ priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
+ iwl4965_rx_missed_beacon_notif;
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
+#endif /* CONFIG_IWLWIFI_AGG */
+#endif /* CONFIG_IWLWIFI */
+}
+
+void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+{
+ INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
+ INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work);
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
+#endif
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work);
+#endif /* CONFIG_IWLWIFI_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ init_timer(&priv->statistics_periodic);
+ priv->statistics_periodic.data = (unsigned long)priv;
+ priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
+}
+
+void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+{
+ del_timer_sync(&priv->statistics_periodic);
+
+ cancel_delayed_work(&priv->init_alive_start);
+}
+
+struct pci_device_id iwl_hw_card_ids[] = {
+ {0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
+};
+
+int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+{
+ u16 count;
+ int rc;
+
+ for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+ rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ EEPROM_SEM_TIMEOUT);
+ if (rc >= 0) {
+ IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n",
+ count+1);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
+
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
new file mode 100644
index 000000000000..4c700812b45b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -0,0 +1,341 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_4965_h__
+#define __iwl_4965_h__
+
+struct iwl_priv;
+struct sta_ht_info;
+
+/*
+ * Forward declare iwl-4965.c functions for iwl-base.c
+ */
+extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
+extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv);
+
+extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt);
+extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
+ int is_ap);
+extern void iwl4965_set_rxon_ht(struct iwl_priv *priv,
+ struct sta_ht_info *ht_info);
+
+extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
+extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+ u8 sta_id, dma_addr_t txcmd_phys,
+ struct ieee80211_hdr *hdr, u8 hdr_len,
+ struct ieee80211_tx_control *ctrl, void *sta_in);
+extern int iwl4965_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates);
+extern int iwl4965_alive_notify(struct iwl_priv *priv);
+extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
+extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index);
+
+extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
+extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
+ u8 force);
+extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
+ u16 channel,
+ const struct iwl_eeprom_channel *eeprom_ch,
+ u8 fat_extension_channel);
+extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, u16 *start_seq_num);
+extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, u16 start_seq_num);
+extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, int generator);
+extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, int generator);
+extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid);
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /*CONFIG_IWLWIFI_HT */
+/* Structures, enum, and defines specific to the 4965 */
+
+#define IWL4965_KW_SIZE 0x1000 /*4k */
+
+struct iwl_kw {
+ dma_addr_t dma_addr;
+ void *v_addr;
+ size_t size;
+};
+
+#define TID_QUEUE_CELL_SPACING 50 /*mS */
+#define TID_QUEUE_MAX_SIZE 20
+#define TID_ROUND_VALUE 5 /* mS */
+#define TID_MAX_LOAD_COUNT 8
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+#define TID_ALL_ENABLED 0x7f
+#define TID_ALL_SPECIFIED 0xff
+#define TID_AGG_TPT_THREHOLD 0x0
+
+#define IWL_CHANNEL_WIDTH_20MHZ 0
+#define IWL_CHANNEL_WIDTH_40MHZ 1
+
+#define IWL_MIMO_PS_STATIC 0
+#define IWL_MIMO_PS_NONE 3
+#define IWL_MIMO_PS_DYNAMIC 1
+#define IWL_MIMO_PS_INVALID 2
+
+#define IWL_OPERATION_MODE_AUTO 0
+#define IWL_OPERATION_MODE_HT_ONLY 1
+#define IWL_OPERATION_MODE_MIXED 2
+#define IWL_OPERATION_MODE_20MHZ 3
+
+#define IWL_EXT_CHANNEL_OFFSET_AUTO 0
+#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1
+#define IWL_EXT_CHANNEL_OFFSET_ 2
+#define IWL_EXT_CHANNEL_OFFSET_BELOW 3
+#define IWL_EXT_CHANNEL_OFFSET_MAX 4
+
+#define NRG_NUM_PREV_STAT_L 20
+#define NUM_RX_CHAINS (3)
+
+#define TX_POWER_IWL_ILLEGAL_VDET -100000
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18
+#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34
+#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17
+#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20
+#define TX_POWER_IWL_NOMINAL_POWER 26
+#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1
+#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7
+#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11
+#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1
+#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
+#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
+
+struct iwl_traffic_load {
+ unsigned long time_stamp;
+ u32 packet_count[TID_QUEUE_MAX_SIZE];
+ u8 queue_count;
+ u8 head;
+ u32 total;
+};
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_agg_control {
+ unsigned long next_retry;
+ u32 wait_for_agg_status;
+ u32 tid_retry;
+ u32 requested_ba;
+ u32 granted_ba;
+ u8 auto_agg;
+ u32 tid_traffic_load_threshold;
+ u32 ba_timeout;
+ struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
+};
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+
+struct iwl_lq_mngr {
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ struct iwl_agg_control agg_ctrl;
+#endif
+ spinlock_t lock;
+ s32 max_window_size;
+ s32 *expected_tpt;
+ u8 *next_higher_rate;
+ u8 *next_lower_rate;
+ unsigned long stamp;
+ unsigned long stamp_last;
+ u32 flush_time;
+ u32 tx_packets;
+ u8 lq_ready;
+};
+
+
+/* Sensitivity and chain noise calibration */
+#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
+#define INITIALIZATION_VALUE 0xFFFF
+#define CAL_NUM_OF_BEACONS 20
+#define MAXIMUM_ALLOWED_PATHLOSS 15
+
+/* Param table within SENSITIVITY_CMD */
+#define HD_MIN_ENERGY_CCK_DET_INDEX (0)
+#define HD_MIN_ENERGY_OFDM_DET_INDEX (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
+
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1)
+
+#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
+
+#define MAX_FA_OFDM 50
+#define MIN_FA_OFDM 5
+#define MAX_FA_CCK 50
+#define MIN_FA_CCK 5
+
+#define NRG_MIN_CCK 97
+#define NRG_MAX_CCK 0
+
+#define AUTO_CORR_MIN_OFDM 85
+#define AUTO_CORR_MIN_OFDM_MRC 170
+#define AUTO_CORR_MIN_OFDM_X1 105
+#define AUTO_CORR_MIN_OFDM_MRC_X1 220
+#define AUTO_CORR_MAX_OFDM 120
+#define AUTO_CORR_MAX_OFDM_MRC 210
+#define AUTO_CORR_MAX_OFDM_X1 140
+#define AUTO_CORR_MAX_OFDM_MRC_X1 270
+#define AUTO_CORR_STEP_OFDM 1
+
+#define AUTO_CORR_MIN_CCK (125)
+#define AUTO_CORR_MAX_CCK (200)
+#define AUTO_CORR_MIN_CCK_MRC 200
+#define AUTO_CORR_MAX_CCK_MRC 400
+#define AUTO_CORR_STEP_CCK 3
+#define AUTO_CORR_MAX_TH_CCK 160
+
+#define NRG_ALG 0
+#define AUTO_CORR_ALG 1
+#define NRG_DIFF 2
+#define NRG_STEP_CCK 2
+#define NRG_MARGIN 8
+#define MAX_NUMBER_CCK_NO_FA 100
+
+#define AUTO_CORR_CCK_MIN_VAL_DEF (125)
+
+#define CHAIN_A 0
+#define CHAIN_B 1
+#define CHAIN_C 2
+#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
+#define ALL_BAND_FILTER 0xFF00
+#define IN_BAND_FILTER 0xFF
+#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF
+
+enum iwl_false_alarm_state {
+ IWL_FA_TOO_MANY = 0,
+ IWL_FA_TOO_FEW = 1,
+ IWL_FA_GOOD_RANGE = 2,
+};
+
+enum iwl_chain_noise_state {
+ IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */
+ IWL_CHAIN_NOISE_ACCUMULATE = 1,
+ IWL_CHAIN_NOISE_CALIBRATED = 2,
+};
+
+enum iwl_sensitivity_state {
+ IWL_SENS_CALIB_ALLOWED = 0,
+ IWL_SENS_CALIB_NEED_REINIT = 1,
+};
+
+enum iwl_calib_enabled_state {
+ IWL_CALIB_DISABLED = 0, /* must be 0 */
+ IWL_CALIB_ENABLED = 1,
+};
+
+struct statistics_general_data {
+ u32 beacon_silence_rssi_a;
+ u32 beacon_silence_rssi_b;
+ u32 beacon_silence_rssi_c;
+ u32 beacon_energy_a;
+ u32 beacon_energy_b;
+ u32 beacon_energy_c;
+};
+
+/* Sensitivity calib data */
+struct iwl_sensitivity_data {
+ u32 auto_corr_ofdm;
+ u32 auto_corr_ofdm_mrc;
+ u32 auto_corr_ofdm_x1;
+ u32 auto_corr_ofdm_mrc_x1;
+ u32 auto_corr_cck;
+ u32 auto_corr_cck_mrc;
+
+ u32 last_bad_plcp_cnt_ofdm;
+ u32 last_fa_cnt_ofdm;
+ u32 last_bad_plcp_cnt_cck;
+ u32 last_fa_cnt_cck;
+
+ u32 nrg_curr_state;
+ u32 nrg_prev_state;
+ u32 nrg_value[10];
+ u8 nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
+ u32 nrg_silence_ref;
+ u32 nrg_energy_idx;
+ u32 nrg_silence_idx;
+ u32 nrg_th_cck;
+ s32 nrg_auto_corr_silence_diff;
+ u32 num_in_cck_no_fa;
+ u32 nrg_th_ofdm;
+
+ u8 state;
+};
+
+/* Chain noise (differential Rx gain) calib data */
+struct iwl_chain_noise_data {
+ u8 state;
+ u16 beacon_count;
+ u32 chain_noise_a;
+ u32 chain_noise_b;
+ u32 chain_noise_c;
+ u32 chain_signal_a;
+ u32 chain_signal_b;
+ u32 chain_signal_c;
+ u8 disconn_array[NUM_RX_CHAINS];
+ u8 delta_gain_code[NUM_RX_CHAINS];
+ u8 radio_write;
+};
+
+/* IWL4965 */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_MIMO_POS 3
+#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+#define RATE_MCS_FAT_POS 11
+#define RATE_MCS_FAT_MSK 0x800
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+#define EEPROM_SEM_TIMEOUT 10
+#define EEPROM_SEM_RETRY_LIMIT 1000
+
+#endif /* __iwl_4965_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h
new file mode 100644
index 000000000000..023c3f240cea
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-channel.h
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_channel_h__
+#define __iwl_channel_h__
+
+#define IWL_NUM_SCAN_RATES (2)
+
+struct iwl_channel_tgd_info {
+ u8 type;
+ s8 max_power;
+};
+
+struct iwl_channel_tgh_info {
+ s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl_channel_power_info {
+ struct iwl_tx_power tpc; /* actual radio and DSP gain settings */
+ s8 power_table_index; /* actual (compenst'd) index into gain table */
+ s8 base_power_index; /* gain index for power at factory temp. */
+ s8 requested_power; /* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl_scan_power_info {
+ struct iwl_tx_power tpc; /* actual radio and DSP gain settings */
+ s8 power_table_index; /* actual (compenst'd) index into gain table */
+ s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */
+};
+
+/* Channel unlock period is 15 seconds. If no beacon or probe response
+ * has been received within 15 seconds on a locked channel then the channel
+ * remains locked. */
+#define TX_UNLOCK_PERIOD 15
+
+/* CSA lock period is 15 seconds. If a CSA has been received on a channel in
+ * the last 15 seconds, the channel is locked */
+#define CSA_LOCK_PERIOD 15
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ * with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl_channel_info {
+ struct iwl_channel_tgd_info tgd;
+ struct iwl_channel_tgh_info tgh;
+ struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
+ struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
+ * FAT channel */
+
+ u8 channel; /* channel number */
+ u8 flags; /* flags copied from EEPROM */
+ s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+ s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
+ s8 min_power; /* always 0 */
+ s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */
+
+ u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */
+ u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
+ u8 phymode; /* MODE_IEEE80211{A,B,G} */
+
+ /* Radio/DSP gain settings for each "normal" data Tx rate.
+ * These include, in addition to RF and DSP gain, a few fields for
+ * remembering/modifying gain settings (indexes). */
+ struct iwl_channel_power_info power_info[IWL4965_MAX_RATE];
+
+#if IWL == 4965
+ /* FAT channel info */
+ s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+ s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
+ s8 fat_min_power; /* always 0 */
+ s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */
+ u8 fat_flags; /* flags copied from EEPROM */
+ u8 fat_extension_channel;
+#endif
+
+ /* Radio/DSP gain settings for each scan rate, for directed scans. */
+ struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl_clip_group {
+ /* maximum power level to prevent clipping for each rate, derived by
+ * us from this band's saturation power in EEPROM */
+ const s8 clip_powers[IWL_MAX_RATES];
+};
+
+static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
+{
+ if (ch_info == NULL)
+ return 0;
+ return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl_channel_info *ch_info)
+{
+ return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
+{
+ return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
+{
+ return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
+{
+ return ((ch_info->phymode == MODE_IEEE80211B) ||
+ (ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl_channel_info *ch)
+{
+ return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl_channel_info *ch)
+{
+ return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+extern const struct iwl_channel_info *iwl_get_channel_info(
+ const struct iwl_priv *priv, int phymode, u16 channel);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
new file mode 100644
index 000000000000..9de8d7f6efa3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -0,0 +1,1734 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+enum {
+ REPLY_ALIVE = 0x1,
+ REPLY_ERROR = 0x2,
+
+ /* RXON and QOS commands */
+ REPLY_RXON = 0x10,
+ REPLY_RXON_ASSOC = 0x11,
+ REPLY_QOS_PARAM = 0x13,
+ REPLY_RXON_TIMING = 0x14,
+
+ /* Multi-Station support */
+ REPLY_ADD_STA = 0x18,
+ REPLY_REMOVE_STA = 0x19, /* not used */
+ REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
+
+ /* RX, TX, LEDs */
+#if IWL == 3945
+ REPLY_3945_RX = 0x1b, /* 3945 only */
+#endif
+ REPLY_TX = 0x1c,
+ REPLY_RATE_SCALE = 0x47, /* 3945 only */
+ REPLY_LEDS_CMD = 0x48,
+ REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+ /* 802.11h related */
+ RADAR_NOTIFICATION = 0x70, /* not used */
+ REPLY_QUIET_CMD = 0x71, /* not used */
+ REPLY_CHANNEL_SWITCH = 0x72,
+ CHANNEL_SWITCH_NOTIFICATION = 0x73,
+ REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+ SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+ /* Power Management */
+ POWER_TABLE_CMD = 0x77,
+ PM_SLEEP_NOTIFICATION = 0x7A,
+ PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+ /* Scan commands and notifications */
+ REPLY_SCAN_CMD = 0x80,
+ REPLY_SCAN_ABORT_CMD = 0x81,
+ SCAN_START_NOTIFICATION = 0x82,
+ SCAN_RESULTS_NOTIFICATION = 0x83,
+ SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+ /* IBSS/AP commands */
+ BEACON_NOTIFICATION = 0x90,
+ REPLY_TX_BEACON = 0x91,
+ WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */
+
+ /* Miscellaneous commands */
+ QUIET_NOTIFICATION = 0x96, /* not used */
+ REPLY_TX_PWR_TABLE_CMD = 0x97,
+ MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */
+
+ /* BT config command */
+ REPLY_BT_CONFIG = 0x9b,
+
+ /* 4965 Statistics */
+ REPLY_STATISTICS_CMD = 0x9c,
+ STATISTICS_NOTIFICATION = 0x9d,
+
+ /* RF-KILL commands and notifications */
+ REPLY_CARD_STATE_CMD = 0xa0,
+ CARD_STATE_NOTIFICATION = 0xa1,
+
+ /* Missed beacons notification */
+ MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+#if IWL == 4965
+ REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+ SENSITIVITY_CMD = 0xa8,
+ REPLY_PHY_CALIBRATION_CMD = 0xb0,
+ REPLY_RX_PHY_CMD = 0xc0,
+ REPLY_RX_MPDU_CMD = 0xc1,
+ REPLY_4965_RX = 0xc3,
+ REPLY_COMPRESSED_BA = 0xc5,
+#endif
+ REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Header
+ *
+ *****************************************************************************/
+
+#define IWL_CMD_FAILED_MSK 0x40
+
+struct iwl_cmd_header {
+ u8 cmd;
+ u8 flags;
+ /* We have 15 LSB to use as we please (MSB indicates
+ * a frame Rx'd from the HW). We encode the following
+ * information into the sequence field:
+ *
+ * 0:7 index in fifo
+ * 8:13 fifo selection
+ * 14:14 bit indicating if this packet references the 'extra'
+ * storage at the end of the memory queue
+ * 15:15 (Rx indication)
+ *
+ */
+ __le16 sequence;
+
+ /* command data follows immediately */
+ u8 data[0];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK __constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE (9)
+
+/*
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ */
+struct iwl_alive_resp {
+ u8 ucode_minor;
+ u8 ucode_major;
+ __le16 reserved1;
+ u8 sw_rev[8];
+ u8 ver_type;
+ u8 ver_subtype;
+ __le16 reserved2;
+ __le32 log_event_table_ptr;
+ __le32 error_event_table_ptr;
+ __le32 timestamp;
+ __le32 is_valid;
+} __attribute__ ((packed));
+
+struct iwl_init_alive_resp {
+ u8 ucode_minor;
+ u8 ucode_major;
+ __le16 reserved1;
+ u8 sw_rev[8];
+ u8 ver_type;
+ u8 ver_subtype;
+ __le16 reserved2;
+ __le32 log_event_table_ptr;
+ __le32 error_event_table_ptr;
+ __le32 timestamp;
+ __le32 is_valid;
+
+#if IWL == 4965
+ /* calibration values from "initialize" uCode */
+ __le32 voltage; /* signed */
+ __le32 therm_r1[2]; /* signed 1st for normal, 2nd for FAT channel */
+ __le32 therm_r2[2]; /* signed */
+ __le32 therm_r3[2]; /* signed */
+ __le32 therm_r4[2]; /* signed */
+ __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups,
+ * 2 Tx chains */
+#endif
+} __attribute__ ((packed));
+
+union tsf {
+ u8 byte[8];
+ __le16 word[4];
+ __le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl_error_resp {
+ __le32 error_type;
+ u8 cmd_id;
+ u8 reserved1;
+ __le16 bad_cmd_seq_num;
+#if IWL == 3945
+ __le16 reserved2;
+#endif
+ __le32 error_info;
+ union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types */
+enum {
+ RXON_DEV_TYPE_AP = 1,
+ RXON_DEV_TYPE_ESS = 3,
+ RXON_DEV_TYPE_IBSS = 4,
+ RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6)
+
+/*
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ */
+struct iwl_rxon_cmd {
+ u8 node_addr[6];
+ __le16 reserved1;
+ u8 bssid_addr[6];
+ __le16 reserved2;
+ u8 wlap_bssid_addr[6];
+ __le16 reserved3;
+ u8 dev_type;
+ u8 air_propagation;
+#if IWL == 3945
+ __le16 reserved4;
+#elif IWL == 4965
+ __le16 rx_chain;
+#endif
+ u8 ofdm_basic_rates;
+ u8 cck_basic_rates;
+ __le16 assoc_id;
+ __le32 flags;
+ __le32 filter_flags;
+ __le16 channel;
+#if IWL == 3945
+ __le16 reserved5;
+#elif IWL == 4965
+ u8 ofdm_ht_single_stream_basic_rates;
+ u8 ofdm_ht_dual_stream_basic_rates;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl_rxon_assoc_cmd {
+ __le32 flags;
+ __le32 filter_flags;
+ u8 ofdm_basic_rates;
+ u8 cck_basic_rates;
+#if IWL == 4965
+ u8 ofdm_ht_single_stream_basic_rates;
+ u8 ofdm_ht_dual_stream_basic_rates;
+ __le16 rx_chain_select_flags;
+#endif
+ __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl_rxon_time_cmd {
+ union tsf timestamp;
+ __le16 beacon_interval;
+ __le16 atim_window;
+ __le32 beacon_init_val;
+ __le16 listen_interval;
+ __le16 reserved;
+} __attribute__ ((packed));
+
+struct iwl_tx_power {
+ u8 tx_gain; /* gain for analog radio */
+ u8 dsp_atten; /* gain for DSP */
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_power_per_rate {
+ u8 rate; /* plcp */
+ struct iwl_tx_power tpc;
+ u8 reserved;
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+#define POWER_TABLE_NUM_ENTRIES 33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
+#define POWER_TABLE_CCK_ENTRY 32
+struct tx_power_dual_stream {
+ __le32 dw;
+} __attribute__ ((packed));
+
+struct iwl_tx_power_db {
+ struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl_channel_switch_cmd {
+ u8 band;
+ u8 expect_beacon;
+ __le16 channel;
+ __le32 rxon_flags;
+ __le32 rxon_filter_flags;
+ __le32 switch_time;
+#if IWL == 3945
+ struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+ struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl_csa_notification {
+ __le16 band;
+ __le16 channel;
+ __le32 status; /* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+struct iwl_ac_qos {
+ __le16 cw_min;
+ __le16 cw_max;
+ u8 aifsn;
+ u8 reserved1;
+ __le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10)
+
+/*
+ * TXFIFO Queue number defines
+ */
+/* number of Access categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM 4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ */
+struct iwl_qosparam_cmd {
+ __le32 qos_flags;
+ struct iwl_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+#define IWL_AP_ID 0
+#define IWL_MULTICAST_ID 1
+#define IWL_STA_ID 2
+
+#define IWL3945_BROADCAST_ID 24
+#define IWL3945_STATION_COUNT 25
+
+#define IWL4965_BROADCAST_ID 31
+#define IWL4965_STATION_COUNT 32
+
+#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/
+#define IWL_INVALID_STATION 255
+
+#if IWL == 3945
+#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1<<2);
+#endif
+#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1<<8);
+
+#define STA_CONTROL_MODIFY_MSK 0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS 8
+#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800)
+
+/* modify flags */
+#define STA_MODIFY_KEY_MASK 0x01
+#define STA_MODIFY_TID_DISABLE_TX 0x02
+#define STA_MODIFY_TX_RATE_MSK 0x04
+#define STA_MODIFY_ADDBA_TID_MSK 0x08
+#define STA_MODIFY_DELBA_TID_MSK 0x10
+#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
+
+/*
+ * Antenna masks:
+ * bit14:15 01 B inactive, A active
+ * 10 B active, A inactive
+ * 11 Both active
+ */
+#define RATE_MCS_ANT_A_POS 14
+#define RATE_MCS_ANT_B_POS 15
+#define RATE_MCS_ANT_A_MSK 0x4000
+#define RATE_MCS_ANT_B_MSK 0x8000
+#define RATE_MCS_ANT_AB_MSK 0xc000
+
+struct iwl_keyinfo {
+ __le16 key_flags;
+ u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
+ u8 reserved1;
+ __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
+ __le16 reserved2;
+ u8 key[16]; /* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+struct sta_id_modify {
+ u8 addr[ETH_ALEN];
+ __le16 reserved1;
+ u8 sta_id;
+ u8 modify_mask;
+ __le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ */
+struct iwl_addsta_cmd {
+ u8 mode;
+ u8 reserved[3];
+ struct sta_id_modify sta;
+ struct iwl_keyinfo key;
+ __le32 station_flags;
+ __le32 station_flags_msk;
+ __le16 tid_disable_tx;
+#if IWL == 3945
+ __le16 rate_n_flags;
+#else
+ __le16 reserved1;
+#endif
+ u8 add_immediate_ba_tid;
+ u8 remove_immediate_ba_tid;
+ __le16 add_immediate_ba_ssn;
+#if IWL == 4965
+ __le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl_add_sta_resp {
+ u8 status;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK 0x1
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_frame_stats {
+ u8 phy_count;
+ u8 id;
+ u8 rssi;
+ u8 agc;
+ __le16 sig_avg;
+ __le16 noise_diff;
+ u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl_rx_frame_hdr {
+ __le16 channel;
+ __le16 phy_flags;
+ u8 reserved1;
+ u8 rate;
+ __le16 len;
+ u8 payload[0];
+} __attribute__ ((packed));
+
+#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
+
+#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
+
+#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
+
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)
+
+struct iwl_rx_frame_end {
+ __le32 status;
+ __le64 timestamp;
+ __le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE: DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl_rx_frame {
+ struct iwl_rx_frame_stats stats;
+ struct iwl_rx_frame_hdr hdr;
+ struct iwl_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70)
+#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */
+#define IWL_AGC_DB_POS (7)
+struct iwl4965_rx_non_cfg_phy {
+ __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */
+ __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */
+ u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */
+ u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+ u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */
+ u8 cfg_phy_cnt; /* configurable DSP phy data byte count */
+ u8 stat_id; /* configurable DSP phy data set ID */
+ u8 reserved1;
+ __le64 timestamp; /* TSF at on air rise */
+ __le32 beacon_time_stamp; /* beacon at on-air rise */
+ __le16 phy_flags; /* general phy flags: band, modulation, ... */
+ __le16 channel; /* channel number */
+ __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */
+ __le32 reserved2;
+ __le32 rate_n_flags;
+ __le16 byte_count; /* frame's byte-count */
+ __le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+ __le16 byte_count;
+ __le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ *****************************************************************************/
+
+/* Tx flags */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* ucode ignores BT priority for this frame */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* ucode overrides sequence control */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* signal that this frame is non-last MPDU */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* calculate TSF in outgoing frame */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* activate TX calibration. */
+#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17)
+
+/* signals that 2 bytes pad was inserted
+ after the MAC header */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP 0x01
+#define TX_CMD_SEC_CCM 0x02
+#define TX_CMD_SEC_TKIP 0x03
+#define TX_CMD_SEC_MSK 0x03
+#define TX_CMD_SEC_SHIFT 6
+#define TX_CMD_SEC_KEY128 0x08
+
+/*
+ * TX command Frame life time
+ */
+
+struct iwl_dram_scratch {
+ u8 try_cnt;
+ u8 bt_kill_cnt;
+ __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl_tx_cmd {
+ __le16 len;
+ __le16 next_frame_len;
+ __le32 tx_flags;
+#if IWL == 3945
+ u8 rate;
+ u8 sta_id;
+ u8 tid_tspec;
+#elif IWL == 4965
+ struct iwl_dram_scratch scratch;
+ __le32 rate_n_flags;
+ u8 sta_id;
+#endif
+ u8 sec_ctl;
+#if IWL == 4965
+ u8 initial_rate_index;
+ u8 reserved;
+#endif
+ u8 key[16];
+#if IWL == 3945
+ union {
+ u8 byte[8];
+ __le16 word[4];
+ __le32 dw[2];
+ } tkip_mic;
+ __le32 next_frame_info;
+#elif IWL == 4965
+ __le16 next_frame_flags;
+ __le16 reserved2;
+#endif
+ union {
+ __le32 life_time;
+ __le32 attempt;
+ } stop_time;
+#if IWL == 3945
+ u8 supp_rates[2];
+#elif IWL == 4965
+ __le32 dram_lsb_ptr;
+ u8 dram_msb_ptr;
+#endif
+ u8 rts_retry_limit; /*byte 50 */
+ u8 data_retry_limit; /*byte 51 */
+#if IWL == 4965
+ u8 tid_tspec;
+#endif
+ union {
+ __le16 pm_frame_timeout;
+ __le16 attempt_duration;
+ } timeout;
+ __le16 driver_txop;
+ u8 payload[0];
+ struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required. This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response. This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared. The host must then deactivate the TX Abort
+ * control line. Receiving is still allowed in this case.
+ */
+enum {
+ TX_STATUS_SUCCESS = 0x01,
+ TX_STATUS_DIRECT_DONE = 0x02,
+ TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+ TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+ TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+ TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+ TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+ TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+ TX_STATUS_FAIL_DEST_PS = 0x88,
+ TX_STATUS_FAIL_ABORTED = 0x89,
+ TX_STATUS_FAIL_BT_RETRY = 0x8a,
+ TX_STATUS_FAIL_STA_INVALID = 0x8b,
+ TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+ TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+ TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+ TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+ TX_STATUS_FAIL_TX_LOCKED = 0x90,
+ TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define TX_PACKET_MODE_REGULAR 0x0000
+#define TX_PACKET_MODE_BURST_SEQ 0x0100
+#define TX_PACKET_MODE_BURST_FIRST 0x0200
+
+enum {
+ TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+ TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */
+ TX_STATUS_DELAY_MSK = 0x00000040,
+ TX_STATUS_ABORT_MSK = 0x00000080,
+ TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */
+ TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */
+ TX_RESERVED = 0x00780000, /* bits 19:22 */
+ TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */
+ TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation state
+ ******************************* */
+
+enum {
+ AGG_TX_STATE_TRANSMITTED = 0x00,
+ AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+ AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+ AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+ AGG_TX_STATE_ABORT_MSK = 0x08,
+ AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+ AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+ AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+ AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+ AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+ AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK \
+(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ */
+#if IWL == 4965
+struct iwl_tx_resp {
+ u8 frame_count; /* 1 no aggregation, >1 aggregation */
+ u8 bt_kill_count;
+ u8 failure_rts;
+ u8 failure_frame;
+ __le32 rate_n_flags;
+ __le16 wireless_media_time;
+ __le16 reserved;
+ __le32 pa_power1;
+ __le32 pa_power2;
+ __le32 status; /* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+
+#elif IWL == 3945
+struct iwl_tx_resp {
+ u8 failure_rts;
+ u8 failure_frame;
+ u8 bt_kill_count;
+ u8 rate;
+ __le32 wireless_media_time;
+ __le32 status; /* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ */
+struct iwl_compressed_ba_resp {
+ __le32 sta_addr_lo32;
+ __le16 sta_addr_hi16;
+ __le16 reserved;
+ u8 sta_id;
+ u8 tid;
+ __le16 ba_seq_ctl;
+ __le32 ba_bitmap0;
+ __le32 ba_bitmap1;
+ __le16 scd_flow;
+ __le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ */
+struct iwl_txpowertable_cmd {
+ u8 band; /* 0: 5 GHz, 1: 2.4 GHz */
+ u8 reserved;
+ __le16 channel;
+#if IWL == 3945
+ struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+ struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_rate_scaling_info {
+ __le16 rate_n_flags;
+ u8 try_cnt;
+ u8 next_rate_index;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response
+ *
+ * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
+ *
+ * NOTE: The table of rates passed to the uCode via the
+ * RATE_SCALE command sets up the corresponding order of
+ * rates used for all related commands, including rate
+ * masks, etc.
+ *
+ * For example, if you set 9MB (PLCP 0x0f) as the first
+ * rate in the rate table, the bit mask for that rate
+ * when passed through ofdm_basic_rates on the REPLY_RXON
+ * command would be bit 0 (1<<0)
+ */
+struct iwl_rate_scaling_cmd {
+ u8 table_id;
+ u8 reserved[3];
+ struct iwl_rate_scaling_info table[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1<<0)
+
+#define LINK_QUAL_AC_NUM AC_NUM
+#define LINK_QUAL_MAX_RETRY_NUM 16
+
+#define LINK_QUAL_ANT_A_MSK (1<<0)
+#define LINK_QUAL_ANT_B_MSK (1<<1)
+#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+struct iwl_link_qual_general_params {
+ u8 flags;
+ u8 mimo_delimiter;
+ u8 single_stream_ant_msk;
+ u8 dual_stream_ant_msk;
+ u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+struct iwl_link_qual_agg_params {
+ __le16 agg_time_limit;
+ u8 agg_dis_start_th;
+ u8 agg_frame_cnt_limit;
+ __le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ */
+struct iwl_link_quality_cmd {
+ u8 sta_id;
+ u8 reserved1;
+ __le16 control;
+ struct iwl_link_qual_general_params general_params;
+ struct iwl_link_qual_agg_params agg_params;
+ struct {
+ __le32 rate_n_flags;
+ } rs_table[LINK_QUAL_MAX_RETRY_NUM];
+ __le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ */
+struct iwl_bt_cmd {
+ u8 flags;
+ u8 lead_time;
+ u8 max_kill;
+ u8 reserved;
+ __le32 kill_ack_mask;
+ __le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \
+ RXON_FILTER_CTL2HOST_MSK | \
+ RXON_FILTER_ACCEPT_GRP_MSK | \
+ RXON_FILTER_DIS_DECRYPT_MSK | \
+ RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+ RXON_FILTER_ASSOC_MSK | \
+ RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl_measure_channel {
+ __le32 duration; /* measurement duration in extended beacon
+ * format */
+ u8 channel; /* channel to measure */
+ u8 type; /* see enum iwl_measure_type */
+ __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl_spectrum_cmd {
+ __le16 len; /* number of bytes starting from token */
+ u8 token; /* token id */
+ u8 id; /* measurement id -- 0 or 1 */
+ u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */
+ u8 periodic; /* 1 = periodic */
+ __le16 path_loss_timeout;
+ __le32 start_time; /* start time in extended beacon format */
+ __le32 reserved2;
+ __le32 flags; /* rxon flags */
+ __le32 filter_flags; /* rxon filter flags */
+ __le16 channel_count; /* minimum 1, maximum 10 */
+ __le16 reserved3;
+ struct iwl_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl_spectrum_resp {
+ u8 token;
+ u8 id; /* id of the prior command replaced, or 0xff */
+ __le16 status; /* 0 - command will be handled
+ * 1 - cannot handle (conflicts with another
+ * measurement) */
+} __attribute__ ((packed));
+
+enum iwl_measurement_state {
+ IWL_MEASUREMENT_START = 0,
+ IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl_measurement_status {
+ IWL_MEASUREMENT_OK = 0,
+ IWL_MEASUREMENT_CONCURRENT = 1,
+ IWL_MEASUREMENT_CSA_CONFLICT = 2,
+ IWL_MEASUREMENT_TGH_CONFLICT = 3,
+ /* 4-5 reserved */
+ IWL_MEASUREMENT_STOPPED = 6,
+ IWL_MEASUREMENT_TIMEOUT = 7,
+ IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl_measurement_histogram {
+ __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
+ __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl_measurement_cca_counters {
+ __le32 ofdm;
+ __le32 cck;
+} __attribute__ ((packed));
+
+enum iwl_measure_type {
+ IWL_MEASURE_BASIC = (1 << 0),
+ IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+ IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+ IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+ IWL_MEASURE_FRAME = (1 << 4),
+ /* bits 5:6 are reserved */
+ IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl_spectrum_notification {
+ u8 id; /* measurement id -- 0 or 1 */
+ u8 token;
+ u8 channel_index; /* index in measurement channel list */
+ u8 state; /* 0 - start, 1 - stop */
+ __le32 start_time; /* lower 32-bits of TSF */
+ u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */
+ u8 channel;
+ u8 type; /* see enum iwl_measurement_type */
+ u8 reserved1;
+ /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only
+ * valid if applicable for measurement type requested. */
+ __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */
+ __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */
+ __le32 cca_time; /* channel load time in usecs */
+ u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 -
+ * unidentified */
+ u8 reserved2[3];
+ struct iwl_measurement_histogram histogram;
+ __le32 stop_time; /* lower 32-bits of TSF */
+ __le32 status; /* see iwl_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ * bit 0 - '0' Driver not allow power management
+ * '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ * bit 1 - '0' Don't send sleep notification
+ * '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ * bit 2 - '0' PM have to walk up every DTIM
+ * '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ * bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ * '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ * bit 31/30- '00' use both mac/xtal sleeps
+ * '01' force Mac sleep
+ * '10' force xtal sleep
+ * '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+
+#if IWL == 3945
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1<<2)
+#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1<<3)
+struct iwl_powertable_cmd {
+ __le32 flags;
+ __le32 rx_data_timeout;
+ __le32 tx_data_timeout;
+ __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+} __attribute__((packed));
+
+#elif IWL == 4965
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1<<2)
+#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1<<3)
+
+struct iwl_powertable_cmd {
+ __le16 flags;
+ u8 keep_alive_seconds;
+ u8 debug_flags;
+ __le32 rx_data_timeout;
+ __le32 tx_data_timeout;
+ __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+ __le32 keep_alive_beacons;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl_sleep_notification {
+ u8 pm_sleep_mode;
+ u8 pm_wakeup_src;
+ __le16 reserved;
+ __le32 sleep_time;
+ __le32 tsf_low;
+ __le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states. 3945 and 4965 identical. */
+enum {
+ IWL_PM_NO_SLEEP = 0,
+ IWL_PM_SLP_MAC = 1,
+ IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+ IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+ IWL_PM_SLP_PHY = 4,
+ IWL_PM_SLP_REPENT = 5,
+ IWL_PM_WAKEUP_BY_TIMER = 6,
+ IWL_PM_WAKEUP_BY_DRIVER = 7,
+ IWL_PM_WAKEUP_BY_RFKILL = 8,
+ /* 3 reserved */
+ IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */
+#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */
+struct iwl_card_state_cmd {
+ __le32 status; /* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl_card_state_notif {
+ __le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED 0x01
+#define SW_CARD_DISABLED 0x02
+#define RF_CARD_DISABLED 0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl_ct_kill_config {
+ __le32 reserved;
+ __le32 critical_temperature_M;
+ __le32 critical_temperature_R;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+struct iwl_scan_channel {
+ /* type is defined as:
+ * 0:0 active (0 - passive)
+ * 1:4 SSID direct
+ * If 1 is set then corresponding SSID IE is transmitted in probe
+ * 5:7 reserved
+ */
+ u8 type;
+ u8 channel;
+ struct iwl_tx_power tpc;
+ __le16 active_dwell;
+ __le16 passive_dwell;
+} __attribute__ ((packed));
+
+struct iwl_ssid_ie {
+ u8 id;
+ u8 len;
+ u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX 0x4
+#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ */
+struct iwl_scan_cmd {
+ __le16 len;
+ u8 reserved0;
+ u8 channel_count;
+ __le16 quiet_time; /* dwell only this long on quiet chnl
+ * (active scan) */
+ __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */
+ __le16 good_CRC_th; /* passive -> active promotion threshold */
+#if IWL == 3945
+ __le16 reserved1;
+#elif IWL == 4965
+ __le16 rx_chain;
+#endif
+ __le32 max_out_time; /* max usec to be out of associated (service)
+ * chnl */
+ __le32 suspend_time; /* pause scan this long when returning to svc
+ * chnl.
+ * 3945 -- 31:24 # beacons, 19:0 additional usec,
+ * 4965 -- 31:22 # beacons, 21:0 additional usec.
+ */
+ __le32 flags;
+ __le32 filter_flags;
+
+ struct iwl_tx_cmd tx_cmd;
+ struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+ u8 data[0];
+ /*
+ * The channels start after the probe request payload and are of type:
+ *
+ * struct iwl_scan_channel channels[0];
+ *
+ * NOTE: Only one band of channels can be scanned per pass. You
+ * can not mix 2.4GHz channels and 5.2GHz channels and must
+ * request a scan multiple times (not concurrently)
+ *
+ */
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS 0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl_scanreq_notification {
+ __le32 status; /* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl_scanstart_notification {
+ __le32 tsf_low;
+ __le32 tsf_high;
+ __le32 beacon_timer;
+ u8 channel;
+ u8 band;
+ u8 reserved[2];
+ __le32 status;
+} __attribute__ ((packed));
+
+#define SCAN_OWNER_STATUS 0x1;
+#define MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl_scanresults_notification {
+ u8 channel;
+ u8 band;
+ u8 reserved[2];
+ __le32 tsf_low;
+ __le32 tsf_high;
+ __le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl_scancomplete_notification {
+ u8 scanned_channels;
+ u8 status;
+ u8 reserved;
+ u8 last_channel;
+ __le32 tsf_low;
+ __le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl_beacon_notif {
+ struct iwl_tx_resp beacon_notify_hdr;
+ __le32 low_tsf;
+ __le32 high_tsf;
+ __le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl_tx_beacon_cmd {
+ struct iwl_tx_cmd tx;
+ __le16 tim_idx;
+ u8 tim_size;
+ u8 reserved1;
+ struct ieee80211_hdr frame[0]; /* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+ union {
+ __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } success;
+ union {
+ __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+ __le32 ina_cnt;
+ __le32 fina_cnt;
+ __le32 plcp_err;
+ __le32 crc32_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 false_alarm_cnt;
+ __le32 fina_sync_err_cnt;
+ __le32 sfd_timeout;
+ __le32 fina_timeout;
+ __le32 unresponded_rts;
+ __le32 rxe_frame_limit_overrun;
+ __le32 sent_ack_cnt;
+ __le32 sent_cts_cnt;
+#if IWL == 4965
+ __le32 sent_ba_rsp_cnt;
+ __le32 dsp_self_kill;
+ __le32 mh_format_err;
+ __le32 re_acq_main_rssi_sum;
+ __le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_rx_ht_phy {
+ __le32 plcp_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 crc32_err;
+ __le32 mh_format_err;
+ __le32 agg_crc32_good;
+ __le32 agg_mpdu_cnt;
+ __le32 agg_cnt;
+ __le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_rx_non_phy {
+ __le32 bogus_cts; /* CTS received when not expecting CTS */
+ __le32 bogus_ack; /* ACK received when not expecting ACK */
+ __le32 non_bssid_frames; /* number of frames with BSSID that
+ * doesn't belong to the STA BSSID */
+ __le32 filtered_frames; /* count frames that were dumped in the
+ * filtering process */
+ __le32 non_channel_beacons; /* beacons with our bss id but not on
+ * our serving channel */
+#if IWL == 4965
+ __le32 channel_beacons; /* beacons with our bss id and in our
+ * serving channel */
+ __le32 num_missed_bcon; /* number of missed beacons */
+ __le32 adc_rx_saturation_time; /* count in 0.8us units the time the
+ * ADC was in saturation */
+ __le32 ina_detection_search_time;/* total time (in 0.8us) searched
+ * for INA */
+ __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
+ __le32 interference_data_flag; /* flag for interference data
+ * availability. 1 when data is
+ * available. */
+ __le32 channel_load; /* counts RX Enable time */
+ __le32 dsp_false_alarms; /* DSP false alarm (both OFDM
+ * and CCK) counter */
+ __le32 beacon_rssi_a;
+ __le32 beacon_rssi_b;
+ __le32 beacon_rssi_c;
+ __le32 beacon_energy_a;
+ __le32 beacon_energy_b;
+ __le32 beacon_energy_c;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_rx {
+ struct statistics_rx_phy ofdm;
+ struct statistics_rx_phy cck;
+ struct statistics_rx_non_phy general;
+#if IWL == 4965
+ struct statistics_rx_ht_phy ofdm_ht;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_tx_non_phy_agg {
+ __le32 ba_timeout;
+ __le32 ba_reschedule_frames;
+ __le32 scd_query_agg_frame_cnt;
+ __le32 scd_query_no_agg;
+ __le32 scd_query_agg;
+ __le32 scd_query_mismatch;
+ __le32 frame_not_ready;
+ __le32 underrun;
+ __le32 bt_prio_kill;
+ __le32 rx_ba_rsp_cnt;
+ __le32 reserved2;
+ __le32 reserved3;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_tx {
+ __le32 preamble_cnt;
+ __le32 rx_detected_cnt;
+ __le32 bt_prio_defer_cnt;
+ __le32 bt_prio_kill_cnt;
+ __le32 few_bytes_cnt;
+ __le32 cts_timeout;
+ __le32 ack_timeout;
+ __le32 expected_ack_cnt;
+ __le32 actual_ack_cnt;
+#if IWL == 4965
+ __le32 dump_msdu_cnt;
+ __le32 burst_abort_next_frame_mismatch_cnt;
+ __le32 burst_abort_missing_next_frame_cnt;
+ __le32 cts_timeout_collision;
+ __le32 ack_or_ba_timeout_collision;
+ struct statistics_tx_non_phy_agg agg;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+ __le32 burst_check;
+ __le32 burst_count;
+ __le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+ __le32 tx_on_a;
+ __le32 tx_on_b;
+ __le32 exec_time;
+ __le32 probe_time;
+#if IWL == 4965
+ __le32 reserved1;
+ __le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_general {
+ __le32 temperature;
+#if IWL == 4965
+ __le32 temperature_m;
+#endif
+ struct statistics_dbg dbg;
+ __le32 sleep_time;
+ __le32 slots_out;
+ __le32 slots_idle;
+ __le32 ttl_timestamp;
+ struct statistics_div div;
+#if IWL == 4965
+ __le32 rx_enable_counter;
+ __le32 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl_statistics_cmd {
+ __le32 configuration_flags; /* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans. uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8)
+struct iwl_notif_statistics {
+ __le32 flag;
+ struct statistics_rx rx;
+ struct statistics_tx tx;
+ struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl_missed_beacon_notif {
+ __le32 consequtive_missed_beacons;
+ __le32 total_missed_becons;
+ __le32 num_expected_beacons;
+ __le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ *****************************************************************************/
+
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+#define HD_TABLE_SIZE (11)
+
+struct iwl_sensitivity_cmd {
+ __le16 control;
+ __le16 table[HD_TABLE_SIZE];
+} __attribute__ ((packed));
+
+struct iwl_calibration_cmd {
+ u8 opCode;
+ u8 flags;
+ __le16 reserved;
+ s8 diff_gain_a;
+ s8 diff_gain_b;
+ s8 diff_gain_c;
+ u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl_led_cmd {
+ __le32 interval; /* "interval" in uSec */
+ u8 id; /* 1: Activity, 2: Link, 3: Tech */
+ u8 off; /* # intervals off while blinking;
+ * "0", with >0 "on" value, turns LED on */
+ u8 on; /* # intervals on while blinking;
+ * "0", regardless of "off", turns LED off */
+ u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_packet {
+ __le32 len;
+ struct iwl_cmd_header hdr;
+ union {
+ struct iwl_alive_resp alive_frame;
+ struct iwl_rx_frame rx_frame;
+ struct iwl_tx_resp tx_resp;
+ struct iwl_spectrum_notification spectrum_notif;
+ struct iwl_csa_notification csa_notif;
+ struct iwl_error_resp err_resp;
+ struct iwl_card_state_notif card_state_notif;
+ struct iwl_beacon_notif beacon_status;
+ struct iwl_add_sta_resp add_sta;
+ struct iwl_sleep_notification sleep_notif;
+ struct iwl_spectrum_resp spectrum;
+ struct iwl_notif_statistics stats;
+#if IWL == 4965
+ struct iwl_compressed_ba_resp compressed_ba;
+ struct iwl_missed_beacon_notif missed_beacon;
+#endif
+ __le32 status;
+ u8 raw[0];
+ } u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl_rx_frame))
+
+#endif /* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
new file mode 100644
index 000000000000..72318d78957e
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_debug_h__
+#define __iwl_debug_h__
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+extern u32 iwl_debug_level;
+#define IWL_DEBUG(level, fmt, args...) \
+do { if (iwl_debug_level & (level)) \
+ printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
+ printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+static inline void IWL_DEBUG(int level, const char *fmt, ...)
+{
+}
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IWL_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
+ * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/iwl/debug_level
+ *
+ * you simply need to add your entry to the iwl_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/iwl then you do not have
+ * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IWL_DL_INFO (1<<0)
+#define IWL_DL_MAC80211 (1<<1)
+#define IWL_DL_HOST_COMMAND (1<<2)
+#define IWL_DL_STATE (1<<3)
+
+#define IWL_DL_RADIO (1<<7)
+#define IWL_DL_POWER (1<<8)
+#define IWL_DL_TEMP (1<<9)
+
+#define IWL_DL_NOTIF (1<<10)
+#define IWL_DL_SCAN (1<<11)
+#define IWL_DL_ASSOC (1<<12)
+#define IWL_DL_DROP (1<<13)
+
+#define IWL_DL_TXPOWER (1<<14)
+
+#define IWL_DL_AP (1<<15)
+
+#define IWL_DL_FW (1<<16)
+#define IWL_DL_RF_KILL (1<<17)
+#define IWL_DL_FW_ERRORS (1<<18)
+
+#define IWL_DL_LED (1<<19)
+
+#define IWL_DL_RATE (1<<20)
+
+#define IWL_DL_CALIB (1<<21)
+#define IWL_DL_WEP (1<<22)
+#define IWL_DL_TX (1<<23)
+#define IWL_DL_RX (1<<24)
+#define IWL_DL_ISR (1<<25)
+#define IWL_DL_HT (1<<26)
+#define IWL_DL_IO (1<<27)
+#define IWL_DL_11H (1<<28)
+
+#define IWL_DL_STATS (1<<29)
+#define IWL_DL_TX_REPLY (1<<30)
+#define IWL_DL_QOS (1<<31)
+
+#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IWL_DEBUG_INFO(f, a...) IWL_DEBUG(IWL_DL_INFO, f, ## a)
+
+#define IWL_DEBUG_MAC80211(f, a...) IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_TEMP(f, a...) IWL_DEBUG(IWL_DL_TEMP, f, ## a)
+#define IWL_DEBUG_SCAN(f, a...) IWL_DEBUG(IWL_DL_SCAN, f, ## a)
+#define IWL_DEBUG_RX(f, a...) IWL_DEBUG(IWL_DL_RX, f, ## a)
+#define IWL_DEBUG_TX(f, a...) IWL_DEBUG(IWL_DL_TX, f, ## a)
+#define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a)
+#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
+#define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
+#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
+#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
+#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
+#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
+#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a)
+#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \
+ IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
+#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a)
+#define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a)
+#define IWL_DEBUG_11H(f, a...) IWL_DEBUG(IWL_DL_11H, f, ## a)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
new file mode 100644
index 000000000000..e473c97e3f4f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_eeprom_h__
+#define __iwl_eeprom_h__
+
+/*
+ * This file defines EEPROM related constants, enums, and inline functions.
+ *
+ */
+
+#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */
+/* EEPROM field values */
+#define ANTENNA_SWITCH_NORMAL 0
+#define ANTENNA_SWITCH_INVERSE 1
+
+enum {
+ EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */
+ EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */
+ /* Bit 2 Reserved */
+ EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */
+ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */
+ EEPROM_CHANNEL_WIDE = (1 << 5),
+ EEPROM_CHANNEL_NARROW = (1 << 6),
+ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */
+};
+
+/* EEPROM field lengths */
+#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11
+
+/* EEPROM field lengths */
+#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11
+#define EEPROM_REGULATORY_SKU_ID_LENGTH 4
+#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH 14
+#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH 13
+#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH 12
+#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH 11
+#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH 6
+
+#if IWL == 3945
+#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
+ EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH)
+#elif IWL == 4965
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11
+#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
+ EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH)
+#endif
+
+#define EEPROM_REGULATORY_NUMBER_OF_BANDS 5
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
+#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7)
+
+/* *regulatory* channel data from eeprom, one for each channel */
+struct iwl_eeprom_channel {
+ u8 flags; /* flags copied from EEPROM */
+ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/*
+ * Mapping of a Tx power level, at factory calibration temperature,
+ * to a radio/DSP gain table index.
+ * One for each of 5 "sample" power levels in each band.
+ * v_det is measured at the factory, using the 3945's built-in power amplifier
+ * (PA) output voltage detector. This same detector is used during Tx of
+ * long packets in normal operation to provide feedback as to proper output
+ * level.
+ * Data copied from EEPROM.
+ */
+struct iwl_eeprom_txpower_sample {
+ u8 gain_index; /* index into power (gain) setup table ... */
+ s8 power; /* ... for this pwr level for this chnl group */
+ u16 v_det; /* PA output voltage */
+} __attribute__ ((packed));
+
+/*
+ * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
+ * One for each channel group (a.k.a. "band") (1 for BG, 4 for A).
+ * Tx power setup code interpolates between the 5 "sample" power levels
+ * to determine the nominal setup for a requested power level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl_eeprom_txpower_group {
+ struct iwl_eeprom_txpower_sample samples[5]; /* 5 power levels */
+ s32 a, b, c, d, e; /* coefficients for voltage->power
+ * formula (signed) */
+ s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on
+ * frequency (signed) */
+ s8 saturation_power; /* highest power possible by h/w in this
+ * band */
+ u8 group_channel; /* "representative" channel # in this band */
+ s16 temperature; /* h/w temperature at factory calib this band
+ * (signed) */
+} __attribute__ ((packed));
+
+/*
+ * Temperature-based Tx-power compensation data, not band-specific.
+ * These coefficients are use to modify a/b/c/d/e coeffs based on
+ * difference between current temperature and factory calib temperature.
+ * Data copied from EEPROM.
+ */
+struct iwl_eeprom_temperature_corr {
+ u32 Ta;
+ u32 Tb;
+ u32 Tc;
+ u32 Td;
+ u32 Te;
+} __attribute__ ((packed));
+
+#if IWL == 4965
+#define EEPROM_TX_POWER_TX_CHAINS (2)
+#define EEPROM_TX_POWER_BANDS (8)
+#define EEPROM_TX_POWER_MEASUREMENTS (3)
+#define EEPROM_TX_POWER_VERSION (2)
+#define EEPROM_TX_POWER_VERSION_NEW (5)
+
+struct iwl_eeprom_calib_measure {
+ u8 temperature;
+ u8 gain_idx;
+ u8 actual_pow;
+ s8 pa_det;
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_ch_info {
+ u8 ch_num;
+ struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
+ [EEPROM_TX_POWER_MEASUREMENTS];
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_subband_info {
+ u8 ch_from;
+ u8 ch_to;
+ struct iwl_eeprom_calib_ch_info ch1;
+ struct iwl_eeprom_calib_ch_info ch2;
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_info {
+ u8 saturation_power24;
+ u8 saturation_power52;
+ s16 voltage; /* signed */
+ struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
+} __attribute__ ((packed));
+
+#endif
+
+struct iwl_eeprom {
+ u8 reserved0[16];
+#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
+ u16 device_id; /* abs.ofs: 16 */
+ u8 reserved1[2];
+#define EEPROM_PMC (2*0x0A) /* 2 bytes */
+ u16 pmc; /* abs.ofs: 20 */
+ u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
+ u8 mac_address[6]; /* abs.ofs: 42 */
+ u8 reserved3[58];
+#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
+ u16 board_revision; /* abs.ofs: 106 */
+ u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
+ u8 board_pba_number[9]; /* abs.ofs: 119 */
+ u8 reserved5[8];
+#define EEPROM_VERSION (2*0x44) /* 2 bytes */
+ u16 version; /* abs.ofs: 136 */
+#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
+ u8 sku_cap; /* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */
+ u8 leds_mode; /* abs.ofs: 139 */
+#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
+ u16 oem_mode;
+#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
+ u16 wowlan_mode; /* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */
+ u16 leds_time_interval; /* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */
+ u8 leds_off_time; /* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */
+ u8 leds_on_time; /* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */
+ u8 almgor_m_version; /* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */
+ u8 antenna_switch_type; /* abs.ofs: 149 */
+#if IWL == 3945
+ u8 reserved6[42];
+#else
+ u8 reserved6[8];
+#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */
+ u16 board_revision_4965; /* abs.ofs: 158 */
+ u8 reserved7[13];
+#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */
+ u8 board_pba_number_4965[9]; /* abs.ofs: 173 */
+ u8 reserved8[10];
+#endif
+#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */
+ u8 sku_id[4]; /* abs.ofs: 192 */
+#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */
+ u16 band_1_count; /* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */
+ struct iwl_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */
+ u16 band_2_count; /* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */
+ struct iwl_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
+#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */
+ u16 band_3_count; /* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */
+ struct iwl_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
+#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */
+ u16 band_4_count; /* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */
+ struct iwl_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
+#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */
+ u16 band_5_count; /* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
+ struct iwl_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
+
+/* From here on out the EEPROM diverges between the 4965 and the 3945 */
+#if IWL == 3945
+
+ u8 reserved9[194];
+
+#define EEPROM_TXPOWER_CALIB_GROUP0 0x200
+#define EEPROM_TXPOWER_CALIB_GROUP1 0x240
+#define EEPROM_TXPOWER_CALIB_GROUP2 0x280
+#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0
+#define EEPROM_TXPOWER_CALIB_GROUP4 0x300
+#define IWL_NUM_TX_CALIB_GROUPS 5
+ struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS];
+/* abs.ofs: 512 */
+#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340
+ struct iwl_eeprom_temperature_corr corrections; /* abs.ofs: 832 */
+ u8 reserved16[172]; /* fill out to full 1024 byte block */
+
+/* 4965AGN adds fat channel support */
+#elif IWL == 4965
+
+ u8 reserved10[2];
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */
+ struct iwl_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
+ u8 reserved11[2];
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
+ struct iwl_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
+ u8 reserved12[6];
+#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */
+ u16 calib_version; /* abs.ofs: 364 */
+ u8 reserved13[2];
+#define EEPROM_SATURATION_POWER_OFFSET (2*0xB8) /* 2 bytes */
+ u16 satruation_power; /* abs.ofs: 368 */
+ u8 reserved14[94];
+#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */
+ struct iwl_eeprom_calib_info calib_info; /* abs.ofs: 464 */
+
+ u8 reserved16[140]; /* fill out to full 1024 byte block */
+
+#endif
+
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
new file mode 100644
index 000000000000..e2a8d95ad9cd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -0,0 +1,255 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_helpers_h__
+#define __iwl_helpers_h__
+
+#include <linux/ctype.h>
+
+/*
+ * The structures defined by the hardware/uCode interface
+ * have bit-wise operations. For each bit-field there is
+ * a data symbol in the structure, the start bit position
+ * and the length of the bit-field.
+ *
+ * iwl_get_bits and iwl_set_bits will return or set the
+ * appropriate bits on a 32-bit value.
+ *
+ * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to
+ * expand out to the appropriate call to iwl_get_bits
+ * and iwl_set_bits without having to reference all of the
+ * numerical constants and defines provided in the hardware
+ * definition
+ */
+
+/**
+ * iwl_get_bits - Extract a hardware bit-field value
+ * @src: source hardware value (__le32)
+ * @pos: bit-position (0-based) of first bit of value
+ * @len: length of bit-field
+ *
+ * iwl_get_bits will return the bit-field in cpu endian ordering.
+ *
+ * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and
+ * will collapse to minimal code by the compiler.
+ */
+static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len)
+{
+ u32 tmp = le32_to_cpu(src);
+
+ tmp >>= pos;
+ tmp &= (1UL << len) - 1;
+ return tmp;
+}
+
+/**
+ * iwl_set_bits - Set a hardware bit-field value
+ * @dst: Address of __le32 hardware value
+ * @pos: bit-position (0-based) of first bit of value
+ * @len: length of bit-field
+ * @val: cpu endian value to encode into the bit-field
+ *
+ * iwl_set_bits will encode val into dst, masked to be len bits long at bit
+ * position pos.
+ *
+ * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and
+ * will collapse to minimal code by the compiler.
+ */
+static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val)
+{
+ u32 tmp = le32_to_cpu(*dst);
+
+ tmp &= ~(((1UL << len) - 1) << pos);
+ tmp |= (val & ((1UL << len) - 1)) << pos;
+ *dst = cpu_to_le32(tmp);
+}
+
+static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
+{
+ u16 tmp = le16_to_cpu(*dst);
+
+ tmp &= ~((1UL << (pos + len)) - (1UL << pos));
+ tmp |= (val & ((1UL << len) - 1)) << pos;
+ *dst = cpu_to_le16(tmp);
+}
+
+/*
+ * The bit-field definitions in iwl-xxxx-hw.h are in the form of:
+ *
+ * struct example {
+ * __le32 val1;
+ * #define IWL_name_POS 8
+ * #define IWL_name_LEN 4
+ * #define IWL_name_SYM val1
+ * };
+ *
+ * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver
+ * to call:
+ *
+ * struct example bar;
+ * u32 val = IWL_GET_BITS(bar, name);
+ * val = val * 2;
+ * IWL_SET_BITS(bar, name, val);
+ *
+ * All cpu / host ordering, masking, and shifts are performed by the macros
+ * and iwl_{get,set}_bits.
+ *
+ */
+#define IWL_SET_BITS(s, sym, v) \
+ iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+ IWL_ ## sym ## _LEN, (v))
+
+#define IWL_SET_BITS16(s, sym, v) \
+ iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+ IWL_ ## sym ## _LEN, (v))
+
+#define IWL_GET_BITS(s, sym) \
+ iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+ IWL_ ## sym ## _LEN)
+
+
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
+#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010
+
+static inline struct ieee80211_conf *ieee80211_get_hw_conf(
+ struct ieee80211_hw *hw)
+{
+ return &hw->conf;
+}
+
+#define QOS_CONTROL_LEN 2
+
+#define IEEE80211_STYPE_BACK_REQ 0x0080
+#define IEEE80211_STYPE_BACK 0x0090
+
+
+static inline int ieee80211_is_management(u16 fc)
+{
+ return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT;
+}
+
+static inline int ieee80211_is_control(u16 fc)
+{
+ return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL;
+}
+
+static inline int ieee80211_is_data(u16 fc)
+{
+ return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA;
+}
+
+static inline int ieee80211_is_back_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ);
+}
+
+static inline int ieee80211_is_probe_response(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP);
+}
+
+static inline int ieee80211_is_probe_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ);
+}
+
+static inline int ieee80211_is_beacon(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON);
+}
+
+static inline int ieee80211_is_atim(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM);
+}
+
+static inline int ieee80211_is_assoc_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_assoc_response(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP);
+}
+
+static inline int ieee80211_is_auth(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_deauth(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_disassoc(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_reassoc_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ);
+}
+
+static inline int ieee80211_is_reassoc_response(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
+}
+
+static inline int iwl_check_bits(unsigned long field, unsigned long mask)
+{
+ return ((field & mask) == mask) ? 1 : 0;
+}
+
+static inline unsigned long elapsed_jiffies(unsigned long start,
+ unsigned long end)
+{
+ if (end > start)
+ return end - start;
+
+ return end + (MAX_JIFFY_OFFSET - start);
+}
+
+#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h
new file mode 100644
index 000000000000..1aa6fcd39a5e
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-hw.h
@@ -0,0 +1,537 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwlwifi_hw_h__
+#define __iwlwifi_hw_h__
+
+/*
+ * This file defines hardware constants common to 3945 and 4965.
+ *
+ * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h,
+ * although this file contains a few definitions for which the .c
+ * implementation is the same for 3945 and 4965, except for the value of
+ * a constant.
+ *
+ * uCode API constants are defined in iwl-commands.h.
+ *
+ * NOTE: DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE
+ *
+ * The iwl-*hw.h (and files they include) files should remain OS/driver
+ * implementation independent, declaring only the hardware interface.
+ */
+
+/* uCode queue management definitions */
+#define IWL_CMD_QUEUE_NUM 4
+#define IWL_CMD_FIFO_NUM 4
+#define IWL_BACK_QUEUE_FIRST_ID 7
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+
+#if IWL == 3945
+#define IWL_HT_RATES 0
+#elif IWL == 4965
+#define IWL_HT_RATES 16
+#endif
+
+#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#if IWL == 3945
+#define IWL_RSSI_OFFSET 95
+#elif IWL == 4965
+#define IWL_RSSI_OFFSET 44
+#endif
+
+#include "iwl-eeprom.h"
+#include "iwl-commands.h"
+
+#define PCI_LINK_CTRL 0x0F0
+#define PCI_POWER_SOURCE 0x0C8
+#define PCI_REG_WUM8 0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE (0x000)
+
+#define CSR_SW_VER (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL (CSR_BASE+0x024)
+#define CSR_HW_REV (CSR_BASE+0x028)
+#define CSR_EEPROM_REG (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP (CSR_BASE+0x030)
+#define CSR_GP_UCODE (CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
+#define CSR_LED_REG (CSR_BASE+0x094)
+#define CSR_DRAM_INT_TBL_CTL (CSR_BASE+0x0A0)
+#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
+#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
+#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+
+/* HW I/F configuration */
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400)
+#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR (1<<29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD (1<<28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX (1<<27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR (1<<25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL (1<<7) /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL (1<<6) /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX (1<<3) /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP (1<<1) /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE (1<<0) /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \
+ CSR_INT_BIT_HW_ERR | \
+ CSR_INT_BIT_FH_TX | \
+ CSR_INT_BIT_SW_ERR | \
+ CSR_INT_BIT_RF_KILL | \
+ CSR_INT_BIT_SW_RX | \
+ CSR_INT_BIT_WAKEUP | \
+ CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR (1<<31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR (1<<30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL2 (1<<18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1 (1<<17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0 (1<<16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL6 (1<<6) /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1 (1<<1) /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0 (1<<0) /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
+ CSR_FH_INT_BIT_RX_CHNL2 | \
+ CSR_FH_INT_BIT_RX_CHNL1 | \
+ CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \
+ CSR_FH_INT_BIT_TX_CHNL1 | \
+ CSR_FH_INT_BIT_TX_CHNL0 )
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK (0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
+
+/* CSR_ANA_PLL_CFG */
+#define CSR_ANA_PLL_CFG_SH (0x00880300)
+
+#define CSR_LED_REG_TRUN_ON (0x00000078)
+#define CSR_LED_REG_TRUN_OFF (0x00000038)
+#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
+
+/* DRAM_INT_TBL_CTRL */
+#define CSR_DRAM_INT_TBL_CTRL_EN (1<<31)
+#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK (1<<27)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE (0x400)
+
+#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
+#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
+#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
+
+#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
+
+
+/* SCD (Scheduler) */
+#define SCD_BASE (CSR_BASE + 0x2E00)
+
+#define SCD_MODE_REG (SCD_BASE + 0x000)
+#define SCD_ARASTAT_REG (SCD_BASE + 0x004)
+#define SCD_TXFACT_REG (SCD_BASE + 0x010)
+#define SCD_TXF4MF_REG (SCD_BASE + 0x014)
+#define SCD_TXF5MF_REG (SCD_BASE + 0x020)
+#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C)
+#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030)
+
+/*=== FH (data Flow Handler) ===*/
+#define FH_BASE (0x800)
+
+#define FH_CBCC_TABLE (FH_BASE+0x140)
+#define FH_TFDB_TABLE (FH_BASE+0x180)
+#define FH_RCSR_TABLE (FH_BASE+0x400)
+#define FH_RSSR_TABLE (FH_BASE+0x4c0)
+#define FH_TCSR_TABLE (FH_BASE+0x500)
+#define FH_TSSR_TABLE (FH_BASE+0x680)
+
+/* TFDB (Transmit Frame Buffer Descriptor) */
+#define FH_TFDB(_channel, buf) \
+ (FH_TFDB_TABLE+((_channel)*2+(buf))*0x28)
+#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \
+ (FH_TFDB_TABLE + 0x50 * _channel)
+/* CBCC _channel is [0,2] */
+#define FH_CBCC(_channel) (FH_CBCC_TABLE+(_channel)*0x8)
+#define FH_CBCC_CTRL(_channel) (FH_CBCC(_channel)+0x00)
+#define FH_CBCC_BASE(_channel) (FH_CBCC(_channel)+0x04)
+
+/* RCSR _channel is [0,2] */
+#define FH_RCSR(_channel) (FH_RCSR_TABLE+(_channel)*0x40)
+#define FH_RCSR_CONFIG(_channel) (FH_RCSR(_channel)+0x00)
+#define FH_RCSR_RBD_BASE(_channel) (FH_RCSR(_channel)+0x04)
+#define FH_RCSR_WPTR(_channel) (FH_RCSR(_channel)+0x20)
+#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24)
+
+#if IWL == 3945
+#define FH_RSCSR_CHNL0_WPTR (FH_RCSR_WPTR(0))
+#elif IWL == 4965
+#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
+#endif
+
+/* RSSR */
+#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000)
+#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004)
+/* TCSR */
+#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20)
+#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00)
+#define FH_TCSR_CREDIT(_channel) (FH_TCSR(_channel)+0x04)
+#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08)
+/* TSSR */
+#define FH_TSSR_CBB_BASE (FH_TSSR_TABLE+0x000)
+#define FH_TSSR_MSG_CONFIG (FH_TSSR_TABLE+0x008)
+#define FH_TSSR_TX_STATUS (FH_TSSR_TABLE+0x010)
+/* 18 - reserved */
+
+/* card static random access memory (SRAM) for processor data and instructs */
+#define RTC_INST_LOWER_BOUND (0x000000)
+#define RTC_DATA_LOWER_BOUND (0x800000)
+
+
+/* DBM */
+
+#define ALM_FH_SRVC_CHNL (6)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20)
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005)
+
+#define ALM_TB_MAX_BYTES_COUNT (0xFFF0)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \
+ ((1LU << _channel) << 24)
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \
+ ((1LU << _channel) << 16)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \
+ (ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \
+ ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel))
+#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
+#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
+
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
+
+#define TFD_QUEUE_MIN 0
+#define TFD_QUEUE_MAX 6
+#define TFD_QUEUE_SIZE_MAX (256)
+
+/* spectrum and channel data structures */
+#define IWL_NUM_SCAN_RATES (2)
+
+#define IWL_SCAN_FLAG_24GHZ (1<<0)
+#define IWL_SCAN_FLAG_52GHZ (1<<1)
+#define IWL_SCAN_FLAG_ACTIVE (1<<2)
+#define IWL_SCAN_FLAG_DIRECT (1<<3)
+
+#define IWL_MAX_CMD_SIZE 1024
+
+#define IWL_DEFAULT_TX_RETRY 15
+#define IWL_MAX_TX_RETRY 16
+
+/*********************************************/
+
+#define RFD_SIZE 4
+#define NUM_TFD_CHUNKS 4
+
+#define RX_QUEUE_SIZE 256
+#define RX_QUEUE_MASK 255
+#define RX_QUEUE_SIZE_LOG 8
+
+/* QoS definitions */
+
+#define CW_MIN_OFDM 15
+#define CW_MAX_OFDM 1023
+#define CW_MIN_CCK 31
+#define CW_MAX_CCK 1023
+
+#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM
+#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM
+#define QOS_TX2_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 4 - 1)
+
+#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK
+#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK
+#define QOS_TX2_CW_MIN_CCK ((CW_MIN_CCK + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_CCK ((CW_MIN_CCK + 1) / 4 - 1)
+
+#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM
+#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM
+#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM
+#define QOS_TX3_CW_MAX_OFDM ((CW_MIN_OFDM + 1) / 2 - 1)
+
+#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK
+#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK
+#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK
+#define QOS_TX3_CW_MAX_CCK ((CW_MIN_CCK + 1) / 2 - 1)
+
+#define QOS_TX0_AIFS 3
+#define QOS_TX1_AIFS 7
+#define QOS_TX2_AIFS 2
+#define QOS_TX3_AIFS 2
+
+#define QOS_TX0_ACM 0
+#define QOS_TX1_ACM 0
+#define QOS_TX2_ACM 0
+#define QOS_TX3_ACM 0
+
+#define QOS_TX0_TXOP_LIMIT_CCK 0
+#define QOS_TX1_TXOP_LIMIT_CCK 0
+#define QOS_TX2_TXOP_LIMIT_CCK 6016
+#define QOS_TX3_TXOP_LIMIT_CCK 3264
+
+#define QOS_TX0_TXOP_LIMIT_OFDM 0
+#define QOS_TX1_TXOP_LIMIT_OFDM 0
+#define QOS_TX2_TXOP_LIMIT_OFDM 3008
+#define QOS_TX3_TXOP_LIMIT_OFDM 1504
+
+#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM
+
+#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK
+
+#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM
+
+#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK
+
+#define DEF_TX0_AIFS (2)
+#define DEF_TX1_AIFS (2)
+#define DEF_TX2_AIFS (2)
+#define DEF_TX3_AIFS (2)
+
+#define DEF_TX0_ACM 0
+#define DEF_TX1_ACM 0
+#define DEF_TX2_ACM 0
+#define DEF_TX3_ACM 0
+
+#define DEF_TX0_TXOP_LIMIT_CCK 0
+#define DEF_TX1_TXOP_LIMIT_CCK 0
+#define DEF_TX2_TXOP_LIMIT_CCK 0
+#define DEF_TX3_TXOP_LIMIT_CCK 0
+
+#define DEF_TX0_TXOP_LIMIT_OFDM 0
+#define DEF_TX1_TXOP_LIMIT_OFDM 0
+#define DEF_TX2_TXOP_LIMIT_OFDM 0
+#define DEF_TX3_TXOP_LIMIT_OFDM 0
+
+#define QOS_QOS_SETS 3
+#define QOS_PARAM_SET_ACTIVE 0
+#define QOS_PARAM_SET_DEF_CCK 1
+#define QOS_PARAM_SET_DEF_OFDM 2
+
+#define CTRL_QOS_NO_ACK (0x0020)
+#define DCT_FLAG_EXT_QOS_ENABLED (0x10)
+
+#define U32_PAD(n) ((4-(n))&0x3)
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+#define TFD_CTL_COUNT_SET(n) (n<<24)
+#define TFD_CTL_COUNT_GET(ctl) ((ctl>>24) & 7)
+#define TFD_CTL_PAD_SET(n) (n<<28)
+#define TFD_CTL_PAD_GET(ctl) (ctl>>28)
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+ sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#endif /* __iwlwifi_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
new file mode 100644
index 000000000000..8a8b96fcf48d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_io_h__
+#define __iwl_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * (in the case of *restricted calls) and the current line number is printed
+ * in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl_read_restricted calls the non-check version of
+ * _iwl_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O. In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl,
+ u32 ofs, u32 val)
+{
+ IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n",
+ (u32) (ofs), (u32) (val), f, l);
+ _iwl_write32(iwl, ofs, val);
+}
+#define iwl_write32(iwl, ofs, val) \
+ __iwl_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val)
+#endif
+
+#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs)
+{
+ IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+ return _iwl_read32(iwl, ofs);
+}
+#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl_read32(p, o) _iwl_read32(p, o)
+#endif
+
+static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+ u32 bits, u32 mask, int timeout)
+{
+ int i = 0;
+
+ do {
+ if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
+ return i;
+ mdelay(10);
+ i += 10;
+ } while (i < timeout);
+
+ return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_poll_bit(const char *f, u32 l,
+ struct iwl_priv *priv, u32 addr,
+ u32 bits, u32 mask, int timeout)
+{
+ int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout);
+ if (unlikely(rc == -ETIMEDOUT))
+ IWL_DEBUG_IO
+ ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+ addr, bits, mask, f, l);
+ else
+ IWL_DEBUG_IO
+ ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+ addr, bits, mask, rc, f, l);
+ return rc;
+}
+#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \
+ __iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bit(const char *f, u32 l,
+ struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ u32 val = _iwl_read32(priv, reg) | mask;
+ IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+ _iwl_write32(priv, reg, val);
+}
+#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
+#endif
+
+static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_clear_bit(const char *f, u32 l,
+ struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ u32 val = _iwl_read32(priv, reg) & ~mask;
+ IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+ _iwl_write32(priv, reg, val);
+}
+#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
+{
+ int rc;
+ u32 gp_ctl;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (atomic_read(&priv->restrict_refcnt))
+ return 0;
+#endif
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+ IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+ "wakes up NIC\n");
+
+ /* 10 msec allows time for NIC to complete its data save */
+ gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL);
+ if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+ IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+ "gpctl = 0x%08x\n", gp_ctl);
+ mdelay(10);
+ } else
+ IWL_DEBUG_RF_KILL("power-down complete, "
+ "gpctl = 0x%08x\n", gp_ctl);
+ }
+
+ /* this bit wakes up the NIC */
+ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ rc = _iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+ (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+ CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+ if (rc < 0) {
+ IWL_ERROR("MAC is in deep sleep!\n");
+ return -EIO;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ atomic_inc(&priv->restrict_refcnt);
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_grab_restricted_access(const char *f, u32 l,
+ struct iwl_priv *priv)
+{
+ if (atomic_read(&priv->restrict_refcnt))
+ IWL_DEBUG_INFO("Grabbing access while already held at "
+ "line %d.\n", l);
+
+ IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l);
+
+ return _iwl_grab_restricted_access(priv);
+}
+#define iwl_grab_restricted_access(priv) \
+ __iwl_grab_restricted_access(__FILE__, __LINE__, priv)
+#else
+#define iwl_grab_restricted_access(priv) \
+ _iwl_grab_restricted_access(priv)
+#endif
+
+static inline void _iwl_release_restricted_access(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+ _iwl_clear_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_release_restricted_access(const char *f, u32 l,
+ struct iwl_priv *priv)
+{
+ if (atomic_read(&priv->restrict_refcnt) <= 0)
+ IWL_ERROR("Release unheld restricted access at line %d.\n", l);
+
+ IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l);
+ _iwl_release_restricted_access(priv);
+}
+#define iwl_release_restricted_access(priv) \
+ __iwl_release_restricted_access(__FILE__, __LINE__, priv)
+#else
+#define iwl_release_restricted_access(priv) \
+ _iwl_release_restricted_access(priv)
+#endif
+
+static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg)
+{
+ return _iwl_read32(priv, reg);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read_restricted(const char *f, u32 l,
+ struct iwl_priv *priv, u32 reg)
+{
+ u32 value = _iwl_read_restricted(priv, reg);
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from %s %d\n", f, l);
+ IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value,
+ f, l);
+ return value;
+}
+#define iwl_read_restricted(priv, reg) \
+ __iwl_read_restricted(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl_read_restricted _iwl_read_restricted
+#endif
+
+static inline void _iwl_write_restricted(struct iwl_priv *priv,
+ u32 reg, u32 value)
+{
+ _iwl_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void __iwl_write_restricted(u32 line,
+ struct iwl_priv *priv, u32 reg, u32 value)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_write_restricted(priv, reg, value);
+}
+#define iwl_write_restricted(priv, reg, value) \
+ __iwl_write_restricted(__LINE__, priv, reg, value)
+#else
+#define iwl_write_restricted _iwl_write_restricted
+#endif
+
+static inline void iwl_write_buffer_restricted(struct iwl_priv *priv,
+ u32 reg, u32 len, u32 *values)
+{
+ u32 count = sizeof(u32);
+
+ if ((priv != NULL) && (values != NULL)) {
+ for (; 0 < len; len -= count, reg += count, values++)
+ _iwl_write_restricted(priv, reg, *values);
+ }
+}
+
+static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv,
+ u32 addr, u32 mask, int timeout)
+{
+ int i = 0;
+
+ do {
+ if ((_iwl_read_restricted(priv, addr) & mask) == mask)
+ return i;
+ mdelay(10);
+ i += 10;
+ } while (i < timeout);
+
+ return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_poll_restricted_bit(const char *f, u32 l,
+ struct iwl_priv *priv,
+ u32 addr, u32 mask, int timeout)
+{
+ int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout);
+
+ if (unlikely(rc == -ETIMEDOUT))
+ IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - "
+ "timedout - %s %d\n", addr, mask, f, l);
+ else
+ IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X "
+ "- %s %d\n", addr, mask, rc, f, l);
+ return rc;
+}
+#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \
+ __iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl_poll_restricted_bit _iwl_poll_restricted_bit
+#endif
+
+static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg)
+{
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read_restricted_reg(u32 line,
+ struct iwl_priv *priv, u32 reg)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ return _iwl_read_restricted_reg(priv, reg);
+}
+
+#define iwl_read_restricted_reg(priv, reg) \
+ __iwl_read_restricted_reg(__LINE__, priv, reg)
+#else
+#define iwl_read_restricted_reg _iwl_read_restricted_reg
+#endif
+
+static inline void _iwl_write_restricted_reg(struct iwl_priv *priv,
+ u32 addr, u32 val)
+{
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR,
+ ((addr & 0x0000FFFF) | (3 << 24)));
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write_restricted_reg(u32 line,
+ struct iwl_priv *priv,
+ u32 addr, u32 val)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_write_restricted_reg(priv, addr, val);
+}
+
+#define iwl_write_restricted_reg(priv, addr, val) \
+ __iwl_write_restricted_reg(__LINE__, priv, addr, val);
+#else
+#define iwl_write_restricted_reg _iwl_write_restricted_reg
+#endif
+
+#define _iwl_set_bits_restricted_reg(priv, reg, mask) \
+ _iwl_write_restricted_reg(priv, reg, \
+ (_iwl_read_restricted_reg(priv, reg) | mask))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv
+ *priv, u32 reg, u32 mask)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_set_bits_restricted_reg(priv, reg, mask);
+}
+#define iwl_set_bits_restricted_reg(priv, reg, mask) \
+ __iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask)
+#else
+#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg
+#endif
+
+#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
+ _iwl_write_restricted_reg( \
+ priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_mask_restricted_reg(u32 line,
+ struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask);
+}
+
+#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
+ __iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg
+#endif
+
+static inline void iwl_clear_bits_restricted_reg(struct iwl_priv
+ *priv, u32 reg, u32 mask)
+{
+ u32 val = _iwl_read_restricted_reg(priv, reg);
+ _iwl_write_restricted_reg(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr)
+{
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr);
+ return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr,
+ u32 val)
+{
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr,
+ u32 len, u32 *values)
+{
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
+ for (; 0 < len; len -= sizeof(u32), values++)
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+
+static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg,
+ u32 len, u8 *values)
+{
+ u32 reg_offset = reg;
+ u32 aligment = reg & 0x3;
+
+ /* write any non-dword-aligned stuff at the beginning */
+ if (len < sizeof(u32)) {
+ if ((aligment + len) <= sizeof(u32)) {
+ u8 size;
+ u32 value = 0;
+ size = len - 1;
+ memcpy(&value, values, len);
+ reg_offset = (reg_offset & 0x0000FFFF);
+
+ _iwl_write_restricted(priv,
+ HBUS_TARG_PRPH_WADDR,
+ (reg_offset | (size << 24)));
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT,
+ value);
+ }
+
+ return;
+ }
+
+ /* now write all the dword-aligned stuff */
+ for (; reg_offset < (reg + len);
+ reg_offset += sizeof(u32), values += sizeof(u32))
+ _iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values));
+}
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h
new file mode 100644
index 000000000000..6b490d08fea9
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-priv.h
@@ -0,0 +1,308 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_priv_h__
+#define __iwl_priv_h__
+
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+enum {
+ MEASUREMENT_READY = (1 << 0),
+ MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl_priv {
+
+ /* ieee device used by generic ieee processing code */
+ struct ieee80211_hw *hw;
+ struct ieee80211_channel *ieee_channels;
+ struct ieee80211_rate *ieee_rates;
+
+ /* temporary frame storage list */
+ struct list_head free_frames;
+ int frames_count;
+
+ u8 phymode;
+ int alloc_rxb_skb;
+
+ void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+
+ const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ /* spectrum measurement report caching */
+ struct iwl_spectrum_notification measure_report;
+ u8 measurement_status;
+#endif
+ /* ucode beacon time */
+ u32 ucode_beacon_time;
+
+ /* we allocate array of iwl_channel_info for NIC's valid channels.
+ * Access via channel # using indirect index array */
+ struct iwl_channel_info *channel_info; /* channel info array */
+ u8 channel_count; /* # of channels */
+
+ /* each calibration channel group in the EEPROM has a derived
+ * clip setting for each rate. */
+ const struct iwl_clip_group clip_groups[5];
+
+ /* thermal calibration */
+ s32 temperature; /* degrees Kelvin */
+ s32 last_temperature;
+
+ /* Scan related variables */
+ unsigned long last_scan_jiffies;
+ unsigned long scan_start;
+ unsigned long scan_pass_start;
+ unsigned long scan_start_tsf;
+ int scan_bands;
+ int one_direct_scan;
+ u8 direct_ssid_len;
+ u8 direct_ssid[IW_ESSID_MAX_SIZE];
+ struct iwl_scan_cmd *scan;
+ u8 only_active_channel;
+
+ /* spinlock */
+ spinlock_t lock; /* protect general shared data */
+ spinlock_t hcmd_lock; /* protect hcmd */
+ struct mutex mutex;
+
+ /* basic pci-network driver stuff */
+ struct pci_dev *pci_dev;
+
+ /* pci hardware address support */
+ void __iomem *hw_base;
+
+ /* uCode images, save to reload in case of failure */
+ struct fw_image_desc ucode_code; /* runtime inst */
+ struct fw_image_desc ucode_data; /* runtime data original */
+ struct fw_image_desc ucode_data_backup; /* runtime data save/restore */
+ struct fw_image_desc ucode_init; /* initialization inst */
+ struct fw_image_desc ucode_init_data; /* initialization data */
+ struct fw_image_desc ucode_boot; /* bootstrap inst */
+
+
+ struct iwl_rxon_time_cmd rxon_timing;
+
+ /* We declare this const so it can only be
+ * changed via explicit cast within the
+ * routines that actually update the physical
+ * hardware */
+ const struct iwl_rxon_cmd active_rxon;
+ struct iwl_rxon_cmd staging_rxon;
+
+ int error_recovering;
+ struct iwl_rxon_cmd recovery_rxon;
+
+ /* 1st responses from initialize and runtime uCode images.
+ * 4965's initialize alive response contains some calibration data. */
+ struct iwl_init_alive_resp card_alive_init;
+ struct iwl_alive_resp card_alive;
+
+#ifdef LED
+ /* LED related variables */
+ struct iwl_activity_blink activity;
+ unsigned long led_packets;
+ int led_state;
+#endif
+
+ u16 active_rate;
+ u16 active_rate_basic;
+
+ u8 call_post_assoc_from_beacon;
+ u8 assoc_station_added;
+#if IWL == 4965
+ u8 use_ant_b_for_management_frame; /* Tx antenna selection */
+ /* HT variables */
+ u8 is_dup;
+ u8 is_ht_enabled;
+ u8 channel_width; /* 0=20MHZ, 1=40MHZ */
+ u8 current_channel_width;
+ u8 valid_antenna; /* Bit mask of antennas actually connected */
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ struct iwl_sensitivity_data sensitivity_data;
+ struct iwl_chain_noise_data chain_noise_data;
+ u8 start_calib;
+ __le16 sensitivity_tbl[HD_TABLE_SIZE];
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+
+#ifdef CONFIG_IWLWIFI_HT
+ struct sta_ht_info current_assoc_ht;
+#endif
+ u8 active_rate_ht[2];
+ u8 last_phy_res[100];
+
+ /* Rate scaling data */
+ struct iwl_lq_mngr lq_mngr;
+#endif
+
+ /* Rate scaling data */
+ s8 data_retry_limit;
+ u8 retry_rate;
+
+ wait_queue_head_t wait_command_queue;
+
+ int activity_timer_active;
+
+ /* Rx and Tx DMA processing queues */
+ struct iwl_rx_queue rxq;
+ struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
+#if IWL == 4965
+ unsigned long txq_ctx_active_msk;
+ struct iwl_kw kw; /* keep warm address */
+ u32 scd_base_addr; /* scheduler sram base address */
+#endif
+
+ unsigned long status;
+ u32 config;
+
+ int last_rx_rssi; /* From Rx packet statisitics */
+ int last_rx_noise; /* From beacon statistics */
+
+ struct iwl_power_mgr power_data;
+
+ struct iwl_notif_statistics statistics;
+ unsigned long last_statistics_time;
+
+ /* context information */
+ u8 essid[IW_ESSID_MAX_SIZE];
+ u8 essid_len;
+ u16 rates_mask;
+
+ u32 power_mode;
+ u32 antenna;
+ u8 bssid[ETH_ALEN];
+ u16 rts_threshold;
+ u8 mac_addr[ETH_ALEN];
+
+ /*station table variables */
+ spinlock_t sta_lock;
+ int num_stations;
+ struct iwl_station_entry stations[IWL_STATION_COUNT];
+
+ /* Indication if ieee80211_ops->open has been called */
+ int is_open;
+
+ u8 mac80211_registered;
+ int is_abg;
+
+ u32 notif_missed_beacons;
+
+ /* Rx'd packet timing information */
+ u32 last_beacon_time;
+ u64 last_tsf;
+
+ /* Duplicate packet detection */
+ u16 last_seq_num;
+ u16 last_frag_num;
+ unsigned long last_packet_time;
+ struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+ /* eeprom */
+ struct iwl_eeprom eeprom;
+
+ int iw_mode;
+
+ struct sk_buff *ibss_beacon;
+
+ /* Last Rx'd beacon timestamp */
+ u32 timestamp0;
+ u32 timestamp1;
+ u16 beacon_int;
+ struct iwl_driver_hw_info hw_setting;
+ int interface_id;
+
+ /* Current association information needed to configure the
+ * hardware */
+ u16 assoc_id;
+ u16 assoc_capability;
+ u8 ps_mode;
+
+#ifdef CONFIG_IWLWIFI_QOS
+ struct iwl_qos_info qos_data;
+#endif /*CONFIG_IWLWIFI_QOS */
+
+ struct workqueue_struct *workqueue;
+
+ struct work_struct up;
+ struct work_struct restart;
+ struct work_struct calibrated_work;
+ struct work_struct scan_completed;
+ struct work_struct rx_replenish;
+ struct work_struct rf_kill;
+ struct work_struct abort_scan;
+ struct work_struct update_link_led;
+ struct work_struct auth_work;
+ struct work_struct report_work;
+ struct work_struct request_scan;
+ struct work_struct beacon_update;
+
+ struct tasklet_struct irq_tasklet;
+
+ struct delayed_work init_alive_start;
+ struct delayed_work alive_start;
+ struct delayed_work activity_timer;
+ struct delayed_work thermal_periodic;
+ struct delayed_work gather_stats;
+ struct delayed_work scan_check;
+ struct delayed_work post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+ s8 user_txpower_limit;
+ s8 max_channel_txpower_limit;
+ u32 cck_power_index_compensation;
+
+#ifdef CONFIG_PM
+ u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ /* debugging info */
+ u32 framecnt_to_us;
+ atomic_t restrict_refcnt;
+#endif
+
+#if IWL == 4965
+ struct work_struct txpower_work;
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ struct work_struct sensitivity_work;
+#endif
+ struct work_struct statistics_work;
+ struct timer_list statistics_periodic;
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ struct work_struct agg_work;
+#endif
+
+#endif /* 4965 */
+}; /*iwl_priv */
+
+#endif /* __iwl_priv_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
new file mode 100644
index 000000000000..0df41148eadc
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_prph_h__
+#define __iwl_prph_h__
+
+
+#define PRPH_BASE (0x00000)
+#define PRPH_END (0xFFFFF)
+
+/* APMG (power management) constants */
+#define APMG_BASE (PRPH_BASE + 0x3000)
+#define APMG_CLK_CTRL_REG (APMG_BASE + 0x0000)
+#define APMG_CLK_EN_REG (APMG_BASE + 0x0004)
+#define APMG_CLK_DIS_REG (APMG_BASE + 0x0008)
+#define APMG_PS_CTRL_REG (APMG_BASE + 0x000c)
+#define APMG_PCIDEV_STT_REG (APMG_BASE + 0x0010)
+#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
+#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
+#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+
+#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
+#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
+
+#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
+
+#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+
+#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x01000000)
+
+
+/**
+ * BSM (Bootstrap State Machine)
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down when the embedded control
+ * processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
+ *
+ * When powering back up after sleeps (or during initial uCode load), the BSM
+ * internally loads the short bootstrap program from the special SRAM into the
+ * embedded processor's instruction SRAM, and starts the processor so it runs
+ * the bootstrap program.
+ *
+ * This bootstrap program loads (via PCI busmaster DMA) instructions and data
+ * images for a uCode program from host DRAM locations. The host driver
+ * indicates DRAM locations and sizes for instruction and data images via the
+ * four BSM_DRAM_* registers. Once the bootstrap program loads the new program,
+ * the new program starts automatically.
+ *
+ * The uCode used for open-source drivers includes two programs:
+ *
+ * 1) Initialization -- performs hardware calibration and sets up some
+ * internal data, then notifies host via "initialize alive" notification
+ * (struct iwl_init_alive_resp) that it has completed all of its work.
+ * After signal from host, it then loads and starts the runtime program.
+ * The initialization program must be used when initially setting up the
+ * NIC after loading the driver.
+ *
+ * 2) Runtime/Protocol -- performs all normal runtime operations. This
+ * notifies host via "alive" notification (struct iwl_alive_resp) that it
+ * is ready to be used.
+ *
+ * When initializing the NIC, the host driver does the following procedure:
+ *
+ * 1) Load bootstrap program (instructions only, no data image for bootstrap)
+ * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND
+ *
+ * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
+ * images in host DRAM.
+ *
+ * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
+ * BSM_WR_MEM_SRC_REG = 0
+ * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
+ * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
+ *
+ * 4) Load bootstrap into instruction SRAM:
+ * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
+ *
+ * 5) Wait for load completion:
+ * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
+ *
+ * 6) Enable future boot loads whenever NIC's power management triggers it:
+ * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
+ *
+ * 7) Start the NIC by removing all reset bits:
+ * CSR_RESET = 0
+ *
+ * The bootstrap uCode (already in instruction SRAM) loads initialization
+ * uCode. Initialization uCode performs data initialization, sends
+ * "initialize alive" notification to host, and waits for a signal from
+ * host to load runtime code.
+ *
+ * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
+ * images in host DRAM. The last register loaded must be the instruction
+ * bytecount register ("1" in MSbit tells initialization uCode to load
+ * the runtime uCode):
+ * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD
+ *
+ * 5) Wait for "alive" notification, then issue normal runtime commands.
+ *
+ * Data caching during power-downs:
+ *
+ * Just before the embedded controller powers down (e.g for automatic
+ * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
+ * a current snapshot of the embedded processor's data SRAM into host DRAM.
+ * This caches the data while the embedded processor's memory is powered down.
+ * Location and size are controlled by BSM_DRAM_DATA_* registers.
+ *
+ * NOTE: Instruction SRAM does not need to be saved, since that doesn't
+ * change during operation; the original image (from uCode distribution
+ * file) can be used for reload.
+ *
+ * When powering back up, the BSM loads the bootstrap program. Bootstrap looks
+ * at the BSM_DRAM_* registers, which now point to the runtime instruction
+ * image and the cached (modified) runtime data (*not* the initialization
+ * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the
+ * uCode from where it left off before the power-down.
+ *
+ * NOTE: Initialization uCode does *not* run as part of the save/restore
+ * procedure.
+ *
+ * This save/restore method is mostly for autonomous power management during
+ * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and
+ * RFKILL should use complete restarts (with total re-initialization) of uCode,
+ * allowing total shutdown (including BSM memory).
+ *
+ * Note that, during normal operation, the host DRAM that held the initial
+ * startup data for the runtime code is now being used as a backup data cache
+ * for modified data! If you need to completely re-initialize the NIC, make
+ * sure that you use the runtime data image from the uCode distribution file,
+ * not the modified/saved runtime data. You may want to store a separate
+ * "clean" runtime data image in DRAM to avoid disk reads of distribution file.
+ */
+
+/* BSM bit fields */
+#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */
+#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/
+#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */
+
+/* BSM addresses */
+#define BSM_BASE (PRPH_BASE + 0x3400)
+#define BSM_END (PRPH_BASE + 0x3800)
+
+#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */
+#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */
+#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */
+#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */
+#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */
+
+/*
+ * Pointers and size regs for bootstrap load and data SRAM save/restore.
+ * NOTE: 3945 pointers use bits 31:0 of DRAM address.
+ * 4965 pointers use bits 35:4 of DRAM address.
+ */
+#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090)
+#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094)
+#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098)
+#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C)
+
+/*
+ * BSM special memory, stays powered on during power-save sleeps.
+ * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
+ */
+#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800)
+#define BSM_SRAM_SIZE (1024) /* bytes */
+
+
+#endif /* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
new file mode 100644
index 000000000000..b576ff24eb4f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_spectrum_h__
+#define __iwl_spectrum_h__
+enum { /* ieee80211_basic_report.map */
+ IEEE80211_BASIC_MAP_BSS = (1 << 0),
+ IEEE80211_BASIC_MAP_OFDM = (1 << 1),
+ IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
+ IEEE80211_BASIC_MAP_RADAR = (1 << 3),
+ IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
+ /* Bits 5-7 are reserved */
+
+};
+struct ieee80211_basic_report {
+ u8 channel;
+ __le64 start_time;
+ __le16 duration;
+ u8 map;
+} __attribute__ ((packed));
+
+enum { /* ieee80211_measurement_request.mode */
+ /* Bit 0 is reserved */
+ IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
+ IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
+ IEEE80211_MEASUREMENT_REPORT = (1 << 3),
+ /* Bits 4-7 are reserved */
+};
+
+enum {
+ IEEE80211_REPORT_BASIC = 0, /* required */
+ IEEE80211_REPORT_CCA = 1, /* optional */
+ IEEE80211_REPORT_RPI = 2, /* optional */
+ /* 3-255 reserved */
+};
+
+struct ieee80211_measurement_params {
+ u8 channel;
+ __le64 start_time;
+ __le16 duration;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_request {
+ struct ieee80211_info_element ie;
+ u8 token;
+ u8 mode;
+ u8 type;
+ struct ieee80211_measurement_params params[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_report {
+ struct ieee80211_info_element ie;
+ u8 token;
+ u8 mode;
+ u8 type;
+ union {
+ struct ieee80211_basic_report basic[0];
+ } u;
+} __attribute__ ((packed));
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
new file mode 100644
index 000000000000..75e3b5c3f155
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -0,0 +1,8746 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets
+ * by defining IWL to either 3945 or 4965. The Makefile used when building
+ * the base targets will create base-3945.o and base-4965.o
+ *
+ * The eventual goal is to move as many of the #if IWL / #endif blocks out of
+ * this file and into the hardware specific implementation files (iwl-XXXX.c)
+ * and leave only the common (non #ifdef sprinkled) code in this file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#define IWL 3945
+
+#include "iwlwifi.h"
+#include "iwl-3945.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+u32 iwl_debug_level;
+#endif
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+int iwl_param_disable_hw_scan;
+int iwl_param_debug;
+int iwl_param_disable; /* def: enable radio */
+int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */
+int iwl_param_hwcrypto; /* def: using software encryption */
+int iwl_param_qos_enable = 1;
+int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION \
+"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL3945_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ int hdr_len = ieee80211_get_hdrlen(fc);
+
+ if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+ return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+ return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl_get_hw_mode(
+ struct iwl_priv *priv, int mode)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (priv->modes[i].mode == mode)
+ return &priv->modes[i];
+
+ return NULL;
+}
+
+static int iwl_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+static const char *iwl_escape_essid(const char *essid, u8 essid_len)
+{
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (iwl_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return escaped;
+}
+
+static void iwl_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (!(iwl_debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IWL operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ ***************************************************/
+
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+ int s = q->last_used - q->first_empty;
+
+ if (q->last_used > q->first_empty)
+ s -= q->n_bd;
+
+ if (s <= 0)
+ s += q->n_window;
+ /* keep some reserve to not confuse empty and full situations */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+ return ++index & (n_bd - 1);
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl_queue *q, int i)
+{
+ return q->first_empty > q->last_used ?
+ (i >= q->last_used && i < q->first_empty) :
+ !(i < q->last_used && i >= q->first_empty);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+ if (is_huge)
+ return q->n_window;
+
+ return index & (q->n_window - 1);
+}
+
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+ int count, int slots_num, u32 id)
+{
+ q->n_bd = count;
+ q->n_window = slots_num;
+ q->id = id;
+
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
+ BUG_ON(!is_power_of_2(count));
+
+ /* slots_num must be power-of-two size, otherwise
+ * get_cmd_index is broken. */
+ BUG_ON(!is_power_of_2(slots_num));
+
+ q->low_mark = q->n_window / 4;
+ if (q->low_mark < 4)
+ q->low_mark = 4;
+
+ q->high_mark = q->n_window / 8;
+ if (q->high_mark < 2)
+ q->high_mark = 2;
+
+ q->first_empty = q->last_used = 0;
+
+ return 0;
+}
+
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u32 id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+
+ if (id != IWL_CMD_QUEUE_NUM) {
+ txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+ if (!txq->txb) {
+ IWL_ERROR("kmalloc for auxilary BD "
+ "structures failed\n");
+ goto error;
+ }
+ } else
+ txq->txb = NULL;
+
+ txq->bd = pci_alloc_consistent(dev,
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+ &txq->q.dma_addr);
+
+ if (!txq->bd) {
+ IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+ goto error;
+ }
+ txq->q.id = id;
+
+ return 0;
+
+ error:
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+ int rc = 0;
+
+ /* alocate command space + one big command for scan since scan
+ * command is very huge the system will not have two scan at the
+ * same time */
+ len = sizeof(struct iwl_cmd) * slots_num;
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+ txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+ if (!txq->cmd)
+ return -ENOMEM;
+
+ rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (rc) {
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ return -ENOMEM;
+ }
+ txq->need_update = 0;
+
+ /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+ iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+ iwl_hw_tx_queue_init(priv, txq);
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers. txq itself is not freed.
+ *
+ */
+void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+
+ if (q->n_bd == 0)
+ return;
+
+ /* first, empty all BD's */
+ for (; q->first_empty != q->last_used;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
+ iwl_hw_txq_free_tfd(priv, txq);
+
+ len = sizeof(struct iwl_cmd) * q->n_window;
+ if (q->id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ /* free buffers belonging to queue itself */
+ if (txq->q.n_bd)
+ pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+ txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ /* 0 fill whole structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ *
+ * NOTE: This needs to be overhauled to better synchronize between
+ * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
+ *
+ * mac80211 should also be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+#if 0 /* temparary disable till we add real remove station */
+static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int index = IWL_INVALID_STATION;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ if (priv->stations[i].used &&
+ !compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (unlikely(index == IWL_INVALID_STATION))
+ goto out;
+
+ if (priv->stations[index].used) {
+ priv->stations[index].used = 0;
+ priv->num_stations--;
+ }
+
+ BUG_ON(priv->num_stations < 0);
+
+out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+}
+#endif
+static void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->num_stations = 0;
+ memset(priv->stations, 0, sizeof(priv->stations));
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+ int i;
+ int index = IWL_INVALID_STATION;
+ struct iwl_station_entry *station;
+ unsigned long flags_spin;
+ DECLARE_MAC_BUF(mac);
+ u8 rate;
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+ if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (!priv->stations[i].used &&
+ index == IWL_INVALID_STATION)
+ index = i;
+ }
+
+ /* These twh conditions has the same outcome but keep them separate
+ since they have different meaning */
+ if (unlikely(index == IWL_INVALID_STATION)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ if (priv->stations[index].used &&
+ !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+ station = &priv->stations[index];
+ station->used = 1;
+ priv->num_stations++;
+
+ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+ memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+ station->sta.mode = 0;
+ station->sta.sta.sta_id = index;
+ station->sta.station_flags = 0;
+
+ rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP :
+ IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag;
+
+ /* Turn on both antennas for the station... */
+ station->sta.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
+ station->current_rate.rate_n_flags =
+ le16_to_cpu(station->sta.rate_n_flags);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ iwl_send_add_station(priv, &station->sta, flags);
+ return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS *****/
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+ /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+ * set but EXIT_PENDING is not */
+ return test_bit(STATUS_READY, &priv->status) &&
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+ !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_init(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+
+ if (iwl_is_rfkill(priv))
+ return 0;
+
+ return iwl_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ IWL_CMD(REPLY_ALIVE);
+ IWL_CMD(REPLY_ERROR);
+ IWL_CMD(REPLY_RXON);
+ IWL_CMD(REPLY_RXON_ASSOC);
+ IWL_CMD(REPLY_QOS_PARAM);
+ IWL_CMD(REPLY_RXON_TIMING);
+ IWL_CMD(REPLY_ADD_STA);
+ IWL_CMD(REPLY_REMOVE_STA);
+ IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_3945_RX);
+ IWL_CMD(REPLY_TX);
+ IWL_CMD(REPLY_RATE_SCALE);
+ IWL_CMD(REPLY_LEDS_CMD);
+ IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+ IWL_CMD(RADAR_NOTIFICATION);
+ IWL_CMD(REPLY_QUIET_CMD);
+ IWL_CMD(REPLY_CHANNEL_SWITCH);
+ IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+ IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+ IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+ IWL_CMD(POWER_TABLE_CMD);
+ IWL_CMD(PM_SLEEP_NOTIFICATION);
+ IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+ IWL_CMD(REPLY_SCAN_CMD);
+ IWL_CMD(REPLY_SCAN_ABORT_CMD);
+ IWL_CMD(SCAN_START_NOTIFICATION);
+ IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+ IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+ IWL_CMD(BEACON_NOTIFICATION);
+ IWL_CMD(REPLY_TX_BEACON);
+ IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+ IWL_CMD(QUIET_NOTIFICATION);
+ IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+ IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+ IWL_CMD(REPLY_BT_CONFIG);
+ IWL_CMD(REPLY_STATISTICS_CMD);
+ IWL_CMD(STATISTICS_NOTIFICATION);
+ IWL_CMD(REPLY_CARD_STATE_CMD);
+ IWL_CMD(CARD_STATE_NOTIFICATION);
+ IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_queue *q = &txq->q;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ struct iwl_cmd *out_cmd;
+ u32 idx;
+ u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+ dma_addr_t phys_addr;
+ int pad;
+ u16 count;
+ int ret;
+ unsigned long flags;
+
+ /* If any of the command structures end up being larger than
+ * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+ * we will need to increase the size of the TFD entries */
+ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+ !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ IWL_ERROR("No space for Tx\n");
+ return -ENOSPC;
+ }
+
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+
+ control_flags = (u32 *) tfd;
+
+ idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+ out_cmd = &txq->cmd[idx];
+
+ out_cmd->hdr.cmd = cmd->id;
+ memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+ memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+ /* At this point, the out_cmd now has all of the incoming cmd
+ * information */
+
+ out_cmd->hdr.flags = 0;
+ out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+ INDEX_TO_SEQ(q->first_empty));
+ if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+ phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+ offsetof(struct iwl_cmd, hdr);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+ pad = U32_PAD(cmd->len);
+ count = TFD_CTL_COUNT_GET(*control_flags);
+ *control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad);
+
+ IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+ "%d bytes at %d[%d]:%d\n",
+ get_cmd_string(out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+ fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+
+ txq->need_update = 1;
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ ret = iwl_tx_queue_update_write_ptr(priv, txq);
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return ret ? ret : idx;
+}
+
+int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int ret;
+
+ BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+ /* An asynchronous command can not expect an SKB to be set. */
+ BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+ /* An asynchronous command MUST have a callback. */
+ BUG_ON(!cmd->meta.u.callback);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EBUSY;
+
+ ret = iwl_enqueue_hcmd(priv, cmd);
+ if (ret < 0) {
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ return ret;
+ }
+ return 0;
+}
+
+int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int cmd_idx;
+ int ret;
+ static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+ BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+ /* A synchronous command can not have a callback set. */
+ BUG_ON(cmd->meta.u.callback != NULL);
+
+ if (atomic_xchg(&entry, 1)) {
+ IWL_ERROR("Error sending %s: Already sending a host command\n",
+ get_cmd_string(cmd->id));
+ return -EBUSY;
+ }
+
+ set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+ if (cmd->meta.flags & CMD_WANT_SKB)
+ cmd->meta.source = &cmd->meta;
+
+ cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+ if (cmd_idx < 0) {
+ ret = cmd_idx;
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ goto out;
+ }
+
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+ HOST_COMPLETE_TIMEOUT);
+ if (!ret) {
+ if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+ IWL_ERROR("Error sending %s: time out after %dms.\n",
+ get_cmd_string(cmd->id),
+ jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ ret = -ETIMEDOUT;
+ goto cancel;
+ }
+ }
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+ get_cmd_string(cmd->id));
+ ret = -ECANCELED;
+ goto fail;
+ }
+ if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto fail;
+ }
+ if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+ IWL_ERROR("Error: Response NULL in '%s'\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ goto out;
+
+cancel:
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ struct iwl_cmd *qcmd;
+
+ /* Cancel the CMD_WANT_SKB flag for the cmd in the
+ * TX cmd queue. Otherwise in case the cmd comes
+ * in later, it will possibly set an invalid
+ * address (cmd->meta.source). */
+ qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+ qcmd->meta.flags &= ~CMD_WANT_SKB;
+ }
+fail:
+ if (cmd->meta.u.skb) {
+ dev_kfree_skb_any(cmd->meta.u.skb);
+ cmd->meta.u.skb = NULL;
+ }
+out:
+ atomic_set(&entry, 0);
+ return ret;
+}
+
+int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ /* A command can not be asynchronous AND expect an SKB to be set. */
+ BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
+ (cmd->meta.flags & CMD_WANT_SKB));
+
+ if (cmd->meta.flags & CMD_ASYNC)
+ return iwl_send_cmd_async(priv, cmd);
+
+ return iwl_send_cmd_sync(priv, cmd);
+}
+
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = len,
+ .data = data,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = sizeof(val),
+ .data = &val,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv)
+{
+ return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE: Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+ if (!iwl_get_channel_info(priv, phymode, channel)) {
+ IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+ channel, phymode);
+ return -EINVAL;
+ }
+
+ if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+ (priv->phymode == phymode))
+ return 0;
+
+ priv->staging_rxon.channel = cpu_to_le16(channel);
+ if (phymode == MODE_IEEE80211A)
+ priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+ priv->phymode = phymode;
+
+ IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+ return 0;
+}
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE: This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+ int error = 0;
+ int counter = 1;
+
+ if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+ error |= le32_to_cpu(rxon->flags &
+ (RXON_FLG_TGJ_NARROW_BAND_MSK |
+ RXON_FLG_RADAR_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check 24G fields %d | %d\n",
+ counter++, error);
+ } else {
+ error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+ 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+ if (error)
+ IWL_WARNING("check 52 fields %d | %d\n",
+ counter++, error);
+ error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+ if (error)
+ IWL_WARNING("check 52 CCK %d | %d\n",
+ counter++, error);
+ }
+ error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+ if (error)
+ IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+ /* make sure basic rates 6Mbps and 1Mbps are supported */
+ error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+ ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+ if (error)
+ IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+ error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+ if (error)
+ IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+ if (error)
+ IWL_WARNING("check CCK and short slot %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check CCK & auto detect %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+ RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+ if (error)
+ IWL_WARNING("check TGG and auto detect %d | %d\n",
+ counter++, error);
+
+ if ((rxon->flags & RXON_FLG_DIS_DIV_MSK))
+ error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK |
+ RXON_FLG_ANT_A_MSK)) == 0);
+ if (error)
+ IWL_WARNING("check antenna %d %d\n", counter++, error);
+
+ if (error)
+ IWL_WARNING("Tuning to channel %d\n",
+ le16_to_cpu(rxon->channel));
+
+ if (error) {
+ IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * @priv: staging_rxon is comapred to active_rxon
+ *
+ * If the RXON structure is changing sufficient to require a new
+ * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
+ * to indicate a new tune is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv)
+{
+
+ /* These items are only settable from the full RXON command */
+ if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+ compare_ether_addr(priv->staging_rxon.bssid_addr,
+ priv->active_rxon.bssid_addr) ||
+ compare_ether_addr(priv->staging_rxon.node_addr,
+ priv->active_rxon.node_addr) ||
+ compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+ priv->active_rxon.wlap_bssid_addr) ||
+ (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+ (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+ (priv->staging_rxon.air_propagation !=
+ priv->active_rxon.air_propagation) ||
+ (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+ return 1;
+
+ /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+ * be updated with the RXON_ASSOC command -- however only some
+ * flag transitions are allowed using RXON_ASSOC */
+
+ /* Check if we are not switching bands */
+ if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+ (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+ return 1;
+
+ /* Check if we are switching association toggle */
+ if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+ (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+ return 1;
+
+ return 0;
+}
+
+static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res = NULL;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_RXON_ASSOC,
+ .len = sizeof(rxon_assoc),
+ .meta.flags = CMD_WANT_SKB,
+ .data = &rxon_assoc,
+ };
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved = 0;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+/**
+ * iwl_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is commited to the hardware and
+ * the active_rxon structure is updated with the new data. This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl_commit_rxon(struct iwl_priv *priv)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ int rc = 0;
+ DECLARE_MAC_BUF(mac);
+
+ if (!iwl_is_alive(priv))
+ return -1;
+
+ /* always get timestamp with Rx frame */
+ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+ /* select antenna */
+ priv->staging_rxon.flags &=
+ ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
+ priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);
+
+ rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /* If we don't need to send a full RXON, we can use
+ * iwl_rxon_assoc_cmd which is used to reconfigure filter
+ * and other flags for the current radio configuration. */
+ if (!iwl_full_rxon_required(priv)) {
+ rc = iwl_send_rxon_assoc(priv);
+ if (rc) {
+ IWL_ERROR("Error setting RXON_ASSOC "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ return 0;
+ }
+
+ /* If we are currently associated and the new config requires
+ * an RXON_ASSOC and the new config wants the associated mask enabled,
+ * we must clear the associated from the active configuration
+ * before we apply the new config */
+ if (iwl_is_associated(priv) &&
+ (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+ IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd),
+ &priv->active_rxon);
+
+ /* If the mask clearing failed then we set
+ * active_rxon back to what it was previously */
+ if (rc) {
+ active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+ IWL_ERROR("Error clearing ASSOC_MSK on current "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+ }
+
+ IWL_DEBUG_INFO("Sending RXON\n"
+ "* with%s RXON_FILTER_ASSOC_MSK\n"
+ "* channel = %d\n"
+ "* bssid = %s\n",
+ ((priv->staging_rxon.filter_flags &
+ RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+ le16_to_cpu(priv->staging_rxon.channel),
+ print_mac(mac, priv->staging_rxon.bssid_addr));
+
+ /* Apply the new configuration */
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Error setting new configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ iwl_clear_stations_table(priv);
+
+ /* If we issue a new RXON command which required a tune then we must
+ * send a new TXPOWER command or we won't be able to Tx any frames */
+ rc = iwl_hw_reg_send_txpower(priv);
+ if (rc) {
+ IWL_ERROR("Error setting Tx power (%d).\n", rc);
+ return rc;
+ }
+
+ /* Add the broadcast address so we can send broadcast frames */
+ if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) ==
+ IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+ return -EIO;
+ }
+
+ /* If we have set the ASSOC_MSK and we are in BSS mode then
+ * add the IWL_AP_ID to the station rate table */
+ if (iwl_is_associated(priv) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
+ == IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding AP address for transmit.\n");
+ return -EIO;
+ }
+
+ /* Init the hardware's rate fallback order based on the
+ * phymode */
+ rc = iwl3945_init_hw_rate_table(priv);
+ if (rc) {
+ IWL_ERROR("Error setting HW rate table: %02X\n", rc);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int iwl_send_bt_config(struct iwl_priv *priv)
+{
+ struct iwl_bt_cmd bt_cmd = {
+ .flags = 3,
+ .lead_time = 0xAA,
+ .max_kill = 1,
+ .kill_ack_mask = 0,
+ .kill_cts_mask = 0,
+ };
+
+ return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+ sizeof(struct iwl_bt_cmd), &bt_cmd);
+}
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_ABORT_CMD,
+ .meta.flags = CMD_WANT_SKB,
+ };
+
+ /* If there isn't a scan actively going on in the hardware
+ * then we are in between scan bands and not actually
+ * actively scanning, so don't send the abort command */
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return 0;
+ }
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return rc;
+ }
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->u.status != CAN_ABORT_STATUS) {
+ /* The scan abort will return 1 for success or
+ * 2 for "failure". A failure condition can be
+ * due to simply not being in an active scan which
+ * can occur if we send the scan abort before we
+ * the microcode has notified us that a scan is
+ * completed. */
+ IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_card_state_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb)
+{
+ return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_CARD_STATE_CMD,
+ .len = sizeof(u32),
+ .data = &flags,
+ .meta.flags = meta_flag,
+ };
+
+ if (meta_flag & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_card_state_sync_callback;
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ struct iwl_rx_packet *res = NULL;
+
+ if (!skb) {
+ IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+ return 1;
+ }
+
+ res = (struct iwl_rx_packet *)skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ return 1;
+ }
+
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ break;
+ default:
+ break;
+ }
+
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+int iwl_send_add_station(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags)
+{
+ struct iwl_rx_packet *res = NULL;
+ int rc = 0;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ADD_STA,
+ .len = sizeof(struct iwl_addsta_cmd),
+ .meta.flags = flags,
+ .data = sta,
+ };
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_add_sta_sync_callback;
+ else
+ cmd.meta.flags |= CMD_WANT_SKB;
+
+ rc = iwl_send_cmd(priv, &cmd);
+
+ if (rc || (flags & CMD_ASYNC))
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ rc = -EIO;
+ }
+
+ if (rc == 0) {
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+ break;
+ default:
+ rc = -EIO;
+ IWL_WARNING("REPLY_ADD_STA failed\n");
+ break;
+ }
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_update_sta_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+
+ switch (keyconf->alg) {
+ case ALG_CCMP:
+ key_flags |= STA_KEY_FLG_CCMP;
+ key_flags |= cpu_to_le16(
+ keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+ break;
+ case ALG_TKIP:
+ case ALG_WEP:
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+ keyconf->keylen);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+ keyconf->keylen);
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+ memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+ priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static void iwl_clear_free_frames(struct iwl_priv *priv)
+{
+ struct list_head *element;
+
+ IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+ priv->frames_count);
+
+ while (!list_empty(&priv->free_frames)) {
+ element = priv->free_frames.next;
+ list_del(element);
+ kfree(list_entry(element, struct iwl_frame, list));
+ priv->frames_count--;
+ }
+
+ if (priv->frames_count) {
+ IWL_WARNING("%d frames still in use. Did we lose one?\n",
+ priv->frames_count);
+ priv->frames_count = 0;
+ }
+}
+
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ struct list_head *element;
+ if (list_empty(&priv->free_frames)) {
+ frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+ if (!frame) {
+ IWL_ERROR("Could not allocate frame!\n");
+ return NULL;
+ }
+
+ priv->frames_count++;
+ return frame;
+ }
+
+ element = priv->free_frames.next;
+ list_del(element);
+ return list_entry(element, struct iwl_frame, list);
+}
+
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+ list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left)
+{
+
+ if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+ ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+ return 0;
+
+ if (priv->ibss_beacon->len > left)
+ return 0;
+
+ memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+ return priv->ibss_beacon->len;
+}
+
+static int iwl_rate_index_from_plcp(int plcp)
+{
+ int i = 0;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ if (iwl_rates[i].plcp == plcp)
+ return i;
+ return -1;
+}
+
+static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+{
+ u8 i;
+
+ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+ i = iwl_rates[i].next_ieee) {
+ if (rate_mask & (1 << i))
+ return iwl_rates[i].plcp;
+ }
+
+ return IWL_RATE_INVALID;
+}
+
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ unsigned int frame_size;
+ int rc;
+ u8 rate;
+
+ frame = iwl_get_free_frame(priv);
+
+ if (!frame) {
+ IWL_ERROR("Could not obtain free frame buffer for beacon "
+ "command.\n");
+ return -ENOMEM;
+ }
+
+ if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+ 0xFF0);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_6M_PLCP;
+ } else {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_1M_PLCP;
+ }
+
+ frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+ &frame->u.cmd[0]);
+
+ iwl_free_frame(priv, frame);
+
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+{
+ memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM from adapter into priv->eeprom
+ *
+ * NOTE: This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl_priv *priv)
+{
+ u16 *e = (u16 *)&priv->eeprom;
+ u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+ u32 r;
+ int sz = sizeof(priv->eeprom);
+ int rc;
+ int i;
+ u16 addr;
+
+ /* The EEPROM structure has several padding buffers within it
+ * and when adding new EEPROM maps is subject to programmer errors
+ * which may be very difficult to identify without explicitly
+ * checking the resulting size of the eeprom map. */
+ BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+ if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ return -ENOENT;
+ }
+
+ rc = iwl_eeprom_aqcuire_semaphore(priv);
+ if (rc < 0) {
+ IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+ return -ENOENT;
+ }
+
+ /* eeprom is an array of 16bit values */
+ for (addr = 0; addr < sz; addr += sizeof(u16)) {
+ _iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
+ _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+ for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+ i += IWL_EEPROM_ACCESS_DELAY) {
+ r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+ if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+ break;
+ udelay(IWL_EEPROM_ACCESS_DELAY);
+ }
+
+ if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ return -ETIMEDOUT;
+ }
+ e[addr / 2] = le16_to_cpu(r >> 16);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/**
+ * iwl_report_frame - dump frame to syslog during debug sessions
+ *
+ * hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type
+ * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
+ * is 3945-specific and gives bad output for 4965. Need to split the
+ * functionality, keep common stuff here.
+ */
+void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+ u32 to_us;
+ u32 print_summary = 0;
+ u32 print_dump = 0; /* set to 1 to dump all frames' contents */
+ u32 hundred = 0;
+ u32 dataframe = 0;
+ u16 fc;
+ u16 seq_ctl;
+ u16 channel;
+ u16 phy_flags;
+ int rate_sym;
+ u16 length;
+ u16 status;
+ u16 bcn_tmr;
+ u32 tsf_low;
+ u64 tsf;
+ u8 rssi;
+ u8 agc;
+ u16 sig_avg;
+ u16 noise_diff;
+ struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ u8 *data = IWL_RX_DATA(pkt);
+
+ /* MAC header */
+ fc = le16_to_cpu(header->frame_control);
+ seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+ /* metadata */
+ channel = le16_to_cpu(rx_hdr->channel);
+ phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ rate_sym = rx_hdr->rate;
+ length = le16_to_cpu(rx_hdr->len);
+
+ /* end-of-frame status and timestamp */
+ status = le32_to_cpu(rx_end->status);
+ bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+ tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+ tsf = le64_to_cpu(rx_end->timestamp);
+
+ /* signal statistics */
+ rssi = rx_stats->rssi;
+ agc = rx_stats->agc;
+ sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+ to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+ /* if data frame is to us and all is good,
+ * (optionally) print summary for only 1 out of every 100 */
+ if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+ dataframe = 1;
+ if (!group100)
+ print_summary = 1; /* print each frame */
+ else if (priv->framecnt_to_us < 100) {
+ priv->framecnt_to_us++;
+ print_summary = 0;
+ } else {
+ priv->framecnt_to_us = 0;
+ print_summary = 1;
+ hundred = 1;
+ }
+ } else {
+ /* print summary for all other frames */
+ print_summary = 1;
+ }
+
+ if (print_summary) {
+ char *title;
+ u32 rate;
+
+ if (hundred)
+ title = "100Frames";
+ else if (fc & IEEE80211_FCTL_RETRY)
+ title = "Retry";
+ else if (ieee80211_is_assoc_response(fc))
+ title = "AscRsp";
+ else if (ieee80211_is_reassoc_response(fc))
+ title = "RasRsp";
+ else if (ieee80211_is_probe_response(fc)) {
+ title = "PrbRsp";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_beacon(fc)) {
+ title = "Beacon";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_atim(fc))
+ title = "ATIM";
+ else if (ieee80211_is_auth(fc))
+ title = "Auth";
+ else if (ieee80211_is_deauth(fc))
+ title = "DeAuth";
+ else if (ieee80211_is_disassoc(fc))
+ title = "DisAssoc";
+ else
+ title = "Frame";
+
+ rate = iwl_rate_index_from_plcp(rate_sym);
+ if (rate == -1)
+ rate = 0;
+ else
+ rate = iwl_rates[rate].ieee / 2;
+
+ /* print frame summary.
+ * MAC addresses show just the last byte (for brevity),
+ * but you can hack it to show more, if you'd like to. */
+ if (dataframe)
+ IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+ "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ title, fc, header->addr1[5],
+ length, rssi, channel, rate);
+ else {
+ /* src/dst addresses assume managed mode */
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+ "src=0x%02x, rssi=%u, tim=%lu usec, "
+ "phy=0x%02x, chnl=%d\n",
+ title, fc, header->addr1[5],
+ header->addr3[5], rssi,
+ tsf_low - priv->scan_start_tsf,
+ phy_flags, channel);
+ }
+ }
+ if (print_dump)
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl_unset_hw_setting(struct iwl_priv *priv)
+{
+ if (priv->hw_setting.shared_virt)
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ priv->hw_setting.shared_virt,
+ priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+ u16 basic_rate, int max_count)
+{
+ u16 ret_rates = 0, bit;
+ int i;
+ u8 *rates;
+
+ rates = &(ie[1]);
+
+ for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+ if (bit & supported_rate) {
+ ret_rates |= bit;
+ rates[*ie] = iwl_rates[i].ieee |
+ ((bit & basic_rate) ? 0x80 : 0x00);
+ *ie = *ie + 1;
+ if (*ie >= max_count)
+ break;
+ }
+ }
+
+ return ret_rates;
+}
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+ struct ieee80211_mgmt *frame,
+ int left, int is_direct)
+{
+ int len = 0;
+ u8 *pos = NULL;
+ u16 ret_rates;
+
+ /* Make sure there is enough space for the probe request,
+ * two mandatory IEs and the data */
+ left -= 24;
+ if (left < 0)
+ return 0;
+ len += 24;
+
+ frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+ memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+ memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+ frame->seq_ctrl = 0;
+
+ /* fill in our indirect SSID IE */
+ /* ...next IE... */
+
+ left -= 2;
+ if (left < 0)
+ return 0;
+ len += 2;
+ pos = &(frame->u.probe_req.variable[0]);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0;
+
+ /* fill in our direct SSID IE... */
+ if (is_direct) {
+ /* ...next IE... */
+ left -= 2 + priv->essid_len;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = priv->essid_len;
+ memcpy(pos, priv->essid, priv->essid_len);
+ pos += priv->essid_len;
+ len += 2 + priv->essid_len;
+ }
+
+ /* fill in supported rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos = 0;
+ ret_rates = priv->active_rate = priv->rates_mask;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ iwl_supported_rate_to_ie(pos, priv->active_rate,
+ priv->active_rate_basic, left);
+ len += 2 + *pos;
+ pos += (*pos) + 1;
+ ret_rates = ~ret_rates & priv->active_rate;
+
+ if (ret_rates == 0)
+ goto fill_end;
+
+ /* fill in supported extended rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos = 0;
+ iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left);
+ if (*pos > 0)
+ len += 2 + *pos;
+
+ fill_end:
+ return (u16)len;
+}
+
+/*
+ * QoS support
+*/
+#ifdef CONFIG_IWLWIFI_QOS
+static int iwl_send_qos_params_command(struct iwl_priv *priv,
+ struct iwl_qosparam_cmd *qos)
+{
+
+ return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+ sizeof(struct iwl_qosparam_cmd), qos);
+}
+
+static void iwl_reset_qos(struct iwl_priv *priv)
+{
+ u16 cw_min = 15;
+ u16 cw_max = 1023;
+ u8 aifs = 2;
+ u8 is_legacy = 0;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.qos_active = 0;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ if (!(priv->active_rate & 0xfff0)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+ } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+
+ if (priv->qos_data.qos_active)
+ aifs = 3;
+
+ priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+ if (priv->qos_data.qos_active) {
+ i = 1;
+ priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 2;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(6016);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3008);
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 3;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 4 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16((cw_max + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3264);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(1504);
+ } else {
+ for (i = 1; i < 4; i++) {
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ }
+ }
+ IWL_DEBUG_QOS("set QoS to default \n");
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+ unsigned long flags;
+
+ if (priv == NULL)
+ return;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!priv->qos_data.qos_enable)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.def_qos_parm.qos_flags = 0;
+
+ if (priv->qos_data.qos_cap.q_AP.queue_request &&
+ !priv->qos_data.qos_cap.q_AP.txop_request)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+ if (priv->qos_data.qos_active)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (force || iwl_is_associated(priv)) {
+ IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+ priv->qos_data.qos_active);
+
+ iwl_send_qos_params_command(priv,
+ &(priv->qos_data.def_qos_parm));
+ }
+}
+
+#endif /* CONFIG_IWLWIFI_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le32(0)
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+ __constant_cpu_to_le32(X1), \
+ __constant_cpu_to_le32(X2), \
+ __constant_cpu_to_le32(X3), \
+ __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim 0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+ SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+ SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+ SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+ SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl_power_init_handle(struct iwl_priv *priv)
+{
+ int rc = 0, i;
+ struct iwl_power_mgr *pow_data;
+ int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+ u16 pci_pm;
+
+ IWL_DEBUG_POWER("Initialize power \n");
+
+ pow_data = &(priv->power_data);
+
+ memset(pow_data, 0, sizeof(*pow_data));
+
+ pow_data->active_index = IWL_POWER_RANGE_0;
+ pow_data->dtim_val = 0xffff;
+
+ memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+ memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+ rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+ if (rc != 0)
+ return 0;
+ else {
+ struct iwl_powertable_cmd *cmd;
+
+ IWL_DEBUG_POWER("adjust power command flags\n");
+
+ for (i = 0; i < IWL_POWER_AC; i++) {
+ cmd = &pow_data->pwr_range_0[i].cmd;
+
+ if (pci_pm & 0x1)
+ cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+ else
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+ }
+ }
+ return rc;
+}
+
+static int iwl_update_power_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd, u32 mode)
+{
+ int rc = 0, i;
+ u8 skip;
+ u32 max_sleep = 0;
+ struct iwl_power_vec_entry *range;
+ u8 period = 0;
+ struct iwl_power_mgr *pow_data;
+
+ if (mode > IWL_POWER_INDEX_5) {
+ IWL_DEBUG_POWER("Error invalid power mode \n");
+ return -1;
+ }
+ pow_data = &(priv->power_data);
+
+ if (pow_data->active_index == IWL_POWER_RANGE_0)
+ range = &pow_data->pwr_range_0[0];
+ else
+ range = &pow_data->pwr_range_1[1];
+
+ memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+ if (priv->assoc_network != NULL) {
+ unsigned long flags;
+
+ period = priv->assoc_network->tim.tim_period;
+ }
+#endif /*IWL_MAC80211_DISABLE */
+ skip = range[mode].no_dtim;
+
+ if (period == 0) {
+ period = 1;
+ skip = 0;
+ }
+
+ if (skip == 0) {
+ max_sleep = period;
+ cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ } else {
+ __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+ max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+ cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ }
+
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+ cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ }
+
+ IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+ IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+ IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+ IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+ le32_to_cpu(cmd->sleep_interval[0]),
+ le32_to_cpu(cmd->sleep_interval[1]),
+ le32_to_cpu(cmd->sleep_interval[2]),
+ le32_to_cpu(cmd->sleep_interval[3]),
+ le32_to_cpu(cmd->sleep_interval[4]));
+
+ return rc;
+}
+
+static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+{
+ u32 final_mode = mode;
+ int rc;
+ struct iwl_powertable_cmd cmd;
+
+ /* If on battery, set to 3,
+ * if plugged into AC power, set to CAM ("continuosly aware mode"),
+ * else user level */
+ switch (mode) {
+ case IWL_POWER_BATTERY:
+ final_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_POWER_AC:
+ final_mode = IWL_POWER_MODE_CAM;
+ break;
+ default:
+ final_mode = mode;
+ break;
+ }
+
+ iwl_update_power_cmd(priv, &cmd, final_mode);
+
+ rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+ if (final_mode == IWL_POWER_MODE_CAM)
+ clear_bit(STATUS_POWER_PMI, &priv->status);
+ else
+ set_bit(STATUS_POWER_PMI, &priv->status);
+
+ return rc;
+}
+
+int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ /* Filter incoming packets to determine if they are targeted toward
+ * this network, discarding packets coming from ourselves */
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr2, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our IBSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr3, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr3, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our BSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr2, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ }
+
+ return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_ENTRY(SHORT_LIMIT);
+ TX_STATUS_ENTRY(LONG_LIMIT);
+ TX_STATUS_ENTRY(FIFO_UNDERRUN);
+ TX_STATUS_ENTRY(MGMNT_ABORT);
+ TX_STATUS_ENTRY(NEXT_FRAG);
+ TX_STATUS_ENTRY(LIFE_EXPIRE);
+ TX_STATUS_ENTRY(DEST_PS);
+ TX_STATUS_ENTRY(ABORTED);
+ TX_STATUS_ENTRY(BT_RETRY);
+ TX_STATUS_ENTRY(STA_INVALID);
+ TX_STATUS_ENTRY(FRAG_DROPPED);
+ TX_STATUS_ENTRY(TID_DISABLE);
+ TX_STATUS_ENTRY(FRAME_FLUSHED);
+ TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+ TX_STATUS_ENTRY(TX_LOCKED);
+ TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl_scan_cancel(struct iwl_priv *priv)
+{
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCANNING, &priv->status);
+ return 0;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Queuing scan abort.\n");
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ queue_work(priv->workqueue, &priv->abort_scan);
+
+ } else
+ IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+ unsigned long now = jiffies;
+ int ret;
+
+ ret = iwl_scan_cancel(priv);
+ if (ret && ms) {
+ mutex_unlock(&priv->mutex);
+ while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+ test_bit(STATUS_SCANNING, &priv->status))
+ msleep(1);
+ mutex_lock(&priv->mutex);
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return ret;
+}
+
+static void iwl_sequence_reset(struct iwl_priv *priv)
+{
+ /* Reset ieee stats */
+
+ /* We don't reset the net_device_stats (ieee->stats) on
+ * re-association */
+
+ priv->last_seq_num = -1;
+ priv->last_frag_num = -1;
+ priv->last_packet_time = 0;
+
+ iwl_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL 1024
+#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
+
+static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor =
+ (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+ / MAX_UCODE_BEACON_INTERVAL;
+ new_val = beacon_val / beacon_factor;
+
+ return cpu_to_le16(new_val);
+}
+
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 interval_tm_unit;
+ u64 tsf, result;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int = 0;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+ priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+ priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+ tsf = priv->timestamp1;
+ tsf = ((tsf << 32) | priv->timestamp0);
+
+ beacon_int = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (beacon_int == 0) {
+ priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+ } else {
+ priv->rxon_timing.beacon_interval =
+ cpu_to_le16(beacon_int);
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ }
+
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(conf->beacon_int);
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ interval_tm_unit =
+ (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+ result = do_div(tsf, interval_tm_unit);
+ priv->rxon_timing.beacon_init_val =
+ cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+ IWL_DEBUG_ASSOC
+ ("beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl_scan_initiate(struct iwl_priv *priv)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("APs don't scan.\n");
+ return 0;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan already in progress.\n");
+ return -EAGAIN;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan request while abort pending. "
+ "Queuing.\n");
+ return -EAGAIN;
+ }
+
+ IWL_DEBUG_INFO("Starting scan...\n");
+ priv->scan_bands = 2;
+ set_bit(STATUS_SCANNING, &priv->status);
+ priv->scan_start = jiffies;
+ priv->scan_pass_start = priv->scan_start;
+
+ queue_work(priv->workqueue, &priv->request_scan);
+
+ return 0;
+}
+
+static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (hw_decrypt)
+ rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+ else
+ rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+ return 0;
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+{
+ if (phymode == MODE_IEEE80211A) {
+ priv->staging_rxon.flags &=
+ ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+ | RXON_FLG_CCK_MSK);
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ } else {
+ /* Copied from iwl_bg_post_associate() */
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+ priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+ priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+ }
+}
+
+/*
+ * initilize rxon structure with default values fromm eeprom
+ */
+static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+{
+ const struct iwl_channel_info *ch_info;
+
+ memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_AP:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+ break;
+
+ case IEEE80211_IF_TYPE_STA:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+ priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+ priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+ priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+ RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+ priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+ RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+ }
+
+#if 0
+ /* TODO: Figure out when short_preamble would be set and cache from
+ * that */
+ if (!hw_to_local(priv->hw)->short_preamble)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+ ch_info = iwl_get_channel_info(priv, priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info)
+ ch_info = &priv->channel_info[0];
+
+ /*
+ * in some case A channels are all non IBSS
+ * in this case force B/G channel
+ */
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !(is_channel_ibss(ch_info)))
+ ch_info = &priv->channel_info[0];
+
+ priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+ if (is_channel_a_band(ch_info))
+ priv->phymode = MODE_IEEE80211A;
+ else
+ priv->phymode = MODE_IEEE80211G;
+
+ iwl_set_flags_for_phymode(priv, priv->phymode);
+
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
+ if (mode == IEEE80211_IF_TYPE_IBSS) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv,
+ priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info || !is_channel_ibss(ch_info)) {
+ IWL_ERROR("channel %d not IBSS channel\n",
+ le16_to_cpu(priv->staging_rxon.channel));
+ return -EINVAL;
+ }
+ }
+
+ cancel_delayed_work(&priv->scan_check);
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ return -EAGAIN;
+ }
+
+ priv->iw_mode = mode;
+
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+ iwl_clear_stations_table(priv);
+
+ iwl_commit_rxon(priv);
+
+ return 0;
+}
+
+static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+ struct ieee80211_tx_control *ctl,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb_frag,
+ int last_frag)
+{
+ struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+ switch (keyinfo->alg) {
+ case ALG_CCMP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+ IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+ break;
+
+ case ALG_TKIP:
+#if 0
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+ if (last_frag)
+ memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+ 8);
+ else
+ memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+ break;
+
+ case ALG_WEP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+ (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+ if (keyinfo->keylen == 13)
+ cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+ memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+ IWL_DEBUG_TX("Configuring packet for WEP encryption "
+ "with key %d\n", ctl->key_idx);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+ break;
+ }
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr,
+ int is_unicast, u8 std_id)
+{
+ __le16 *qc;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ __le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+ cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ tx_flags |= TX_CMD_FLG_ACK_MSK;
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ if (ieee80211_is_probe_response(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+ tx_flags |= TX_CMD_FLG_TSF_MSK;
+ } else {
+ tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
+
+ cmd->cmd.tx.sta_id = std_id;
+ if (ieee80211_get_morefrag(hdr))
+ tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+ } else
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+ if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ tx_flags |= TX_CMD_FLG_RTS_MSK;
+ tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+
+ if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+ tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(3);
+ else
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(2);
+ } else
+ cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+ cmd->cmd.tx.driver_txop = 0;
+ cmd->cmd.tx.tx_flags = tx_flags;
+ cmd->cmd.tx.next_frame_len = 0;
+}
+
+static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+ int sta_id;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ /* If this frame is broadcast or not data then use the broadcast
+ * station id */
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return priv->hw_setting.bcast_sta_id;
+
+ switch (priv->iw_mode) {
+
+ /* If this frame is part of a BSS network (we're a station), then
+ * we use the AP's station id */
+ case IEEE80211_IF_TYPE_STA:
+ return IWL_AP_ID;
+
+ /* If we are an AP, then find the station, or use BCAST */
+ case IEEE80211_IF_TYPE_AP:
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+ return priv->hw_setting.bcast_sta_id;
+
+ /* If this frame is part of a IBSS network, then we use the
+ * target specific station id */
+ case IEEE80211_IF_TYPE_IBSS: {
+ DECLARE_MAC_BUF(mac);
+
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ IWL_DEBUG_DROP("Station %s not in station map. "
+ "Defaulting to broadcast...\n",
+ print_mac(mac, hdr->addr1));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ return priv->hw_setting.bcast_sta_id;
+ }
+ default:
+ IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+ return priv->hw_setting.bcast_sta_id;
+ }
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl_tx_skb(struct iwl_priv *priv,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ int txq_id = ctl->queue;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_queue *q = NULL;
+ dma_addr_t phys_addr;
+ dma_addr_t txcmd_phys;
+ struct iwl_cmd *out_cmd = NULL;
+ u16 len, idx, len_org;
+ u8 id, hdr_len, unicast;
+ u8 sta_id;
+ u16 seq_number = 0;
+ u16 fc;
+ __le16 *qc;
+ u8 wait_write_ptr = 0;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_DROP("Dropping - RF KILL\n");
+ goto drop_unlock;
+ }
+
+ if (!priv->interface_id) {
+ IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+ goto drop_unlock;
+ }
+
+ if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+ IWL_ERROR("ERROR: No TX rate available.\n");
+ goto drop_unlock;
+ }
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+ id = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (ieee80211_is_auth(fc))
+ IWL_DEBUG_TX("Sending AUTH frame\n");
+ else if (ieee80211_is_assoc_request(fc))
+ IWL_DEBUG_TX("Sending ASSOC frame\n");
+ else if (ieee80211_is_reassoc_request(fc))
+ IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+ if (!iwl_is_associated(priv) &&
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+ IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+ goto drop_unlock;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ hdr_len = ieee80211_get_hdrlen(fc);
+ sta_id = iwl_get_sta_id(priv, hdr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+ print_mac(mac, hdr->addr1));
+ goto drop;
+ }
+
+ IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ seq_number = priv->stations[sta_id].tid[tid].seq_number &
+ IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = cpu_to_le16(seq_number) |
+ (hdr->seq_ctrl &
+ __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+ seq_number += 0x10;
+ }
+ txq = &priv->txq[txq_id];
+ q = &txq->q;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+ control_flags = (u32 *) tfd;
+ idx = get_cmd_index(q, q->first_empty, 0);
+
+ memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
+ txq->txb[q->first_empty].skb[0] = skb;
+ memcpy(&(txq->txb[q->first_empty].status.control),
+ ctl, sizeof(struct ieee80211_tx_control));
+ out_cmd = &txq->cmd[idx];
+ memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+ memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+ out_cmd->hdr.cmd = REPLY_TX;
+ out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->first_empty)));
+ /* copy frags header */
+ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+ /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+ len = priv->hw_setting.tx_cmd_len +
+ sizeof(struct iwl_cmd_header) + hdr_len;
+
+ len_org = len;
+ len = (len + 3) & ~3;
+
+ if (len_org != len)
+ len_org = 1;
+ else
+ len_org = 0;
+
+ txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+ offsetof(struct iwl_cmd, hdr);
+
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+ if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+ /* 802.11 null functions have no payload... */
+ len = skb->len - hdr_len;
+ if (len) {
+ phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+ len, PCI_DMA_TODEVICE);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+ }
+
+ /* If there is no payload, then only one TFD is used */
+ if (!len)
+ *control_flags = TFD_CTL_COUNT_SET(1);
+ else
+ *control_flags = TFD_CTL_COUNT_SET(2) |
+ TFD_CTL_PAD_SET(U32_PAD(len));
+
+ len = (u16)skb->len;
+ out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+ /* TODO need this for burst mode later on */
+ iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+ /* set is_hcca to 0; it probably will never be implemented */
+ iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+ out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
+ out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
+
+ if (!ieee80211_get_morefrag(hdr)) {
+ txq->need_update = 1;
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
+ }
+
+ iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+ sizeof(out_cmd->cmd.tx));
+
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+ ieee80211_get_hdrlen(fc));
+
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ rc = iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (rc)
+ return rc;
+
+ if ((iwl_queue_space(q) < q->high_mark)
+ && priv->mac80211_registered) {
+ if (wait_write_ptr) {
+ spin_lock_irqsave(&priv->lock, flags);
+ txq->need_update = 1;
+ iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ ieee80211_stop_queue(priv->hw, ctl->queue);
+ }
+
+ return 0;
+
+drop_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+ return -1;
+}
+
+static void iwl_set_rate(struct iwl_priv *priv)
+{
+ const struct ieee80211_hw_mode *hw = NULL;
+ struct ieee80211_rate *rate;
+ int i;
+
+ hw = iwl_get_hw_mode(priv, priv->phymode);
+
+ priv->active_rate = 0;
+ priv->active_rate_basic = 0;
+
+ IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+ hw->mode == MODE_IEEE80211A ?
+ 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+ for (i = 0; i < hw->num_rates; i++) {
+ rate = &(hw->rates[i]);
+ if ((rate->val < IWL_RATE_COUNT) &&
+ (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+ IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+ rate->val, iwl_rates[rate->val].plcp,
+ (rate->flags & IEEE80211_RATE_BASIC) ?
+ "*" : "");
+ priv->active_rate |= (1 << rate->val);
+ if (rate->flags & IEEE80211_RATE_BASIC)
+ priv->active_rate_basic |= (1 << rate->val);
+ } else
+ IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+ rate->val, iwl_rates[rate->val].plcp);
+ }
+
+ IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+ priv->active_rate, priv->active_rate_basic);
+
+ /*
+ * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+ * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+ * OFDM
+ */
+ if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+ priv->staging_rxon.cck_basic_rates =
+ ((priv->active_rate_basic &
+ IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+ else
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+ if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+ priv->staging_rxon.ofdm_basic_rates =
+ ((priv->active_rate_basic &
+ (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+ IWL_FIRST_OFDM_RATE) & 0xFF;
+ else
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+ unsigned long flags;
+
+ if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+ return;
+
+ IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+ disable_radio ? "OFF" : "ON");
+
+ if (disable_radio) {
+ iwl_scan_cancel(priv);
+ /* FIXME: This is a workaround for AP */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_SW_BIT_RFKILL);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ }
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wake up ucode */
+ msleep(10);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (!iwl_grab_restricted_access(priv))
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by HW switch\n");
+ return;
+ }
+
+ queue_work(priv->workqueue, &priv->restart);
+ return;
+}
+
+void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+ u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+ u16 fc =
+ le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+ if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+ return;
+
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return;
+
+ IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+ switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_ICV_MIC)
+ stats->flag |= RX_FLAG_MMIC_ERROR;
+ case RX_RES_STATUS_SEC_TYPE_WEP:
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_DECRYPT_OK) {
+ IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+ stats->flag |= RX_FLAG_DECRYPTED;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ void *data, short len,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags)
+{
+ struct iwl_rt_rx_hdr *iwl_rt;
+
+ /* First cache any information we need before we overwrite
+ * the information provided in the skb from the hardware */
+ s8 signal = stats->ssi;
+ s8 noise = 0;
+ int rate = stats->rate;
+ u64 tsf = stats->mactime;
+ __le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+ /* We received data from the HW, so stop the watchdog */
+ if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
+ IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+ return;
+ }
+
+ /* copy the frame data to write after where the radiotap header goes */
+ iwl_rt = (void *)rxb->skb->data;
+ memmove(iwl_rt->payload, data, len);
+
+ iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+ /* total header + data */
+ iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, sizeof(*iwl_rt) + len);
+
+ /* Big bitfield of all the fields we provide in radiotap */
+ iwl_rt->rt_hdr.it_present =
+ 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));
+
+ /* Zero the flags, we'll add to them as we go */
+ iwl_rt->rt_flags = 0;
+
+ iwl_rt->rt_tsf = cpu_to_le64(tsf);
+
+ /* Convert to dBm */
+ iwl_rt->rt_dbmsignal = signal;
+ iwl_rt->rt_dbmnoise = noise;
+
+ /* Convert the channel frequency and set the flags */
+ iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+ if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+ else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+ else /* 802.11g */
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+ rate = iwl_rate_index_from_plcp(rate);
+ if (rate == -1)
+ iwl_rt->rt_rate = 0;
+ else
+ iwl_rt->rt_rate = iwl_rates[rate].ieee;
+
+ /* antenna number */
+ iwl_rt->rt_antenna =
+ le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+ /* set the preamble flag if we have it */
+ if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+ iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+ stats->flag |= RX_FLAG_RADIOTAP;
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ u16 sc = le16_to_cpu(header->seq_ctrl);
+ u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+ u16 frag = sc & IEEE80211_SCTL_FRAG;
+ u16 *last_seq, *last_frag;
+ unsigned long *last_time;
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS:{
+ struct list_head *p;
+ struct iwl_ibss_seq *entry = NULL;
+ u8 *mac = header->addr2;
+ int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+ __list_for_each(p, &priv->ibss_mac_hash[index]) {
+ entry =
+ list_entry(p, struct iwl_ibss_seq, list);
+ if (!compare_ether_addr(entry->mac, mac))
+ break;
+ }
+ if (p == &priv->ibss_mac_hash[index]) {
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ IWL_ERROR
+ ("Cannot malloc new mac entry\n");
+ return 0;
+ }
+ memcpy(entry->mac, mac, ETH_ALEN);
+ entry->seq_num = seq;
+ entry->frag_num = frag;
+ entry->packet_time = jiffies;
+ list_add(&entry->list,
+ &priv->ibss_mac_hash[index]);
+ return 0;
+ }
+ last_seq = &entry->seq_num;
+ last_frag = &entry->frag_num;
+ last_time = &entry->packet_time;
+ break;
+ }
+ case IEEE80211_IF_TYPE_STA:
+ last_seq = &priv->last_seq_num;
+ last_frag = &priv->last_frag_num;
+ last_time = &priv->last_packet_time;
+ break;
+ default:
+ return 0;
+ }
+ if ((*last_seq == seq) &&
+ time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+ if (*last_frag == frag)
+ goto drop;
+ if (*last_frag + 1 != frag)
+ /* out-of-order fragment */
+ goto drop;
+ } else
+ *last_seq = seq;
+
+ *last_frag = frag;
+ *last_time = jiffies;
+ return 0;
+
+ drop:
+ return 1;
+}
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW 0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH 0xFF000000
+#define TIME_UNIT 1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * 1024;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+ rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+ return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & BEACON_TIME_MASK_LOW;
+ u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & BEACON_TIME_MASK_HIGH) +
+ (addon & BEACON_TIME_MASK_HIGH);
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << 24);
+ } else
+ res += (1 << 24);
+
+ return cpu_to_le32(res);
+}
+
+static int iwl_get_measurement(struct iwl_priv *priv,
+ struct ieee80211_measurement_params *params,
+ u8 type)
+{
+ struct iwl_spectrum_cmd spectrum;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+ .data = (void *)&spectrum,
+ .meta.flags = CMD_WANT_SKB,
+ };
+ u32 add_time = le64_to_cpu(params->start_time);
+ int rc;
+ int spectrum_resp_status;
+ int duration = le16_to_cpu(params->duration);
+
+ if (iwl_is_associated(priv))
+ add_time =
+ iwl_usecs_to_beacons(
+ le64_to_cpu(params->start_time) - priv->last_tsf,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+ memset(&spectrum, 0, sizeof(spectrum));
+
+ spectrum.channel_count = cpu_to_le16(1);
+ spectrum.flags =
+ RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+ spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+ cmd.len = sizeof(spectrum);
+ spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+ if (iwl_is_associated(priv))
+ spectrum.start_time =
+ iwl_add_beacon_time(priv->last_beacon_time,
+ add_time,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ else
+ spectrum.start_time = 0;
+
+ spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+ spectrum.channels[0].channel = params->channel;
+ spectrum.channels[0].type = type;
+ if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+ RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ switch (spectrum_resp_status) {
+ case 0: /* Command will be handled */
+ if (res->u.spectrum.id != 0xff) {
+ IWL_DEBUG_INFO
+ ("Replaced existing measurement: %d\n",
+ res->u.spectrum.id);
+ priv->measurement_status &= ~MEASUREMENT_READY;
+ }
+ priv->measurement_status |= MEASUREMENT_ACTIVE;
+ rc = 0;
+ break;
+
+ case 1: /* Command will not be handled */
+ rc = -EAGAIN;
+ break;
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+#endif
+
+static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+ struct iwl_tx_info *tx_sta)
+{
+
+ tx_sta->status.ack_signal = 0;
+ tx_sta->status.excessive_retries = 0;
+ tx_sta->status.queue_length = 0;
+ tx_sta->status.queue_number = 0;
+
+ if (in_interrupt())
+ ieee80211_tx_status_irqsafe(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+ else
+ ieee80211_tx_status(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+
+ tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW advances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ */
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->first_empty, q->last_used);
+ return 0;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd);
+ q->last_used != index;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+ if (txq_id != IWL_CMD_QUEUE_NUM) {
+ iwl_txstatus_to_ieee(priv,
+ &(txq->txb[txq->q.last_used]));
+ iwl_hw_txq_free_tfd(priv, txq);
+ } else if (nfreed > 1) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ q->first_empty, q->last_used);
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ nfreed++;
+ }
+
+ if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+ (txq_id != IWL_CMD_QUEUE_NUM) &&
+ priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+
+
+ return nfreed;
+}
+
+static int iwl_is_tx_success(u32 status)
+{
+ return (status & 0xFF) == 0x1;
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+static void iwl_rx_reply_tx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_status *tx_status;
+ struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->status);
+
+ if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.first_empty,
+ txq->q.last_used);
+ return;
+ }
+
+ tx_status = &(txq->txb[txq->q.last_used].status);
+
+ tx_status->retry_count = tx_resp->failure_frame;
+ tx_status->queue_number = status;
+ tx_status->queue_length = tx_resp->bt_kill_count;
+ tx_status->queue_length |= tx_resp->failure_rts;
+
+ tx_status->flags =
+ iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+ tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate);
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
+ txq_id, iwl_get_tx_fail_reason(status), status,
+ tx_resp->rate, tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+ if (index != -1)
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_alive_resp *palive;
+ struct delayed_work *pwork;
+
+ palive = &pkt->u.alive_frame;
+
+ IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+ "0x%01X 0x%01X\n",
+ palive->is_valid, palive->ver_type,
+ palive->ver_subtype);
+
+ if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ memcpy(&priv->card_alive_init,
+ &pkt->u.alive_frame,
+ sizeof(struct iwl_init_alive_resp));
+ pwork = &priv->init_alive_start;
+ } else {
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+ memcpy(&priv->card_alive, &pkt->u.alive_frame,
+ sizeof(struct iwl_alive_resp));
+ pwork = &priv->alive_start;
+ iwl_disable_events(priv);
+ }
+
+ /* We delay the ALIVE response by 5ms to
+ * give the HW RF Kill time to activate... */
+ if (palive->is_valid == UCODE_VALID_OK)
+ queue_delayed_work(priv->workqueue, pwork,
+ msecs_to_jiffies(5));
+ else
+ IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+ return;
+}
+
+static void iwl_rx_reply_error(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+ "seq 0x%04X ser 0x%08X\n",
+ le32_to_cpu(pkt->u.err_resp.error_type),
+ get_cmd_string(pkt->u.err_resp.cmd_id),
+ pkt->u.err_resp.cmd_id,
+ le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+ le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
+ struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+ IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+ le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+ if (!report->state) {
+ IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+ "Spectrum Measure Notification: Start\n");
+ return;
+ }
+
+ memcpy(&priv->measure_report, report, sizeof(*report));
+ priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+ IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+ sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+ "notification for %s:\n",
+ le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, beacon_update);
+ struct sk_buff *beacon;
+
+ /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+ beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+ if (!beacon) {
+ IWL_ERROR("update beacon failed\n");
+ return;
+ }
+
+ mutex_lock(&priv->mutex);
+ /* new beacon skb is allocated every time; dispose previous.*/
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = beacon;
+ mutex_unlock(&priv->mutex);
+
+ iwl_send_beacon_cmd(priv);
+}
+
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+ u8 rate = beacon->beacon_notify_hdr.rate;
+
+ IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+ "tsf %d %d rate %d\n",
+ le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+ beacon->beacon_notify_hdr.failure_frame,
+ le32_to_cpu(beacon->ibss_mgr_status),
+ le32_to_cpu(beacon->high_tsf),
+ le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+ queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl_rx_reply_scan(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanreq_notification *notif =
+ (struct iwl_scanreq_notification *)pkt->u.raw;
+
+ IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanstart_notification *notif =
+ (struct iwl_scanstart_notification *)pkt->u.raw;
+ priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+ IWL_DEBUG_SCAN("Scan start: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ notif->tsf_high,
+ notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanresults_notification *notif =
+ (struct iwl_scanresults_notification *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan ch.res: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d "
+ "elapsed=%lu usec (%dms since last)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ le32_to_cpu(notif->tsf_high),
+ le32_to_cpu(notif->tsf_low),
+ le32_to_cpu(notif->statistics[0]),
+ le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->last_scan_jiffies, jiffies)));
+
+ priv->last_scan_jiffies = jiffies;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+ scan_notif->scanned_channels,
+ scan_notif->tsf_low,
+ scan_notif->tsf_high, scan_notif->status);
+
+ /* The HW is no longer scanning */
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+
+ /* The scan completion notification came in, so kill that timer... */
+ cancel_delayed_work(&priv->scan_check);
+
+ IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+ (priv->scan_bands == 2) ? "2.4" : "5.2",
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->scan_pass_start, jiffies)));
+
+ /* Remove this scanned band from the list
+ * of pending bands to scan */
+ priv->scan_bands--;
+
+ /* If a request to abort was given, or the scan did not succeed
+ * then we reset the scan state machine and terminate,
+ * re-queuing another scan if one has been requested */
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_INFO("Aborted scan completed.\n");
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ } else {
+ /* If there are more bands on this scan pass reschedule */
+ if (priv->scan_bands > 0)
+ goto reschedule;
+ }
+
+ priv->last_scan_jiffies = jiffies;
+ IWL_DEBUG_INFO("Setting scan to off\n");
+
+ clear_bit(STATUS_SCANNING, &priv->status);
+
+ IWL_DEBUG_INFO("Scan took %dms\n",
+ jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+ queue_work(priv->workqueue, &priv->scan_completed);
+
+ return;
+
+reschedule:
+ priv->scan_pass_start = jiffies;
+ queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+ unsigned long status = priv->status;
+
+ IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+ (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ if (flags & HW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+ if (flags & SW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+ iwl_scan_cancel(priv);
+
+ if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+ test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+ (test_bit(STATUS_RF_KILL_SW, &status) !=
+ test_bit(STATUS_RF_KILL_SW, &priv->status)))
+ queue_work(priv->workqueue, &priv->rf_kill);
+ else
+ wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+ priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
+ priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
+ priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+ priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
+ priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+ priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+ iwl_rx_pm_debug_statistics_notif;
+ priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+
+ /* NOTE: iwl_rx_statistics is different based on whether
+ * the build is for the 3945 or the 4965. See the
+ * corresponding implementation in iwl-XXXX.c
+ *
+ * The same handler is used for both the REPLY to a
+ * discrete statistics request from the host as well as
+ * for the periodic statistics notification from the uCode
+ */
+ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
+ priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+
+ priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+ priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+ priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+ iwl_rx_scan_results_notif;
+ priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+ iwl_rx_scan_complete_notif;
+ priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
+ priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+
+ /* Setup hardware specific Rx handlers */
+ iwl_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed. The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ int huge = sequence & SEQ_HUGE_FRAME;
+ int cmd_index;
+ struct iwl_cmd *cmd;
+
+ /* If a Tx command is being handled and it isn't in the actual
+ * command queue then there a command routing bug has been introduced
+ * in the queue management code. */
+ if (txq_id != IWL_CMD_QUEUE_NUM)
+ IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+ txq_id, pkt->hdr.cmd);
+ BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+ cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+ cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+ /* Input error checking is done when commands are added to queue. */
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ cmd->meta.source->u.skb = rxb->skb;
+ rxb->skb = NULL;
+ } else if (cmd->meta.u.callback &&
+ !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ rxb->skb = NULL;
+
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+
+ if (!(cmd->meta.flags & CMD_ASYNC)) {
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+ }
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
+ * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replensish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * iwl->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the iwl->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc() Allocates rx_free
+ * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls iwl_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ *
+ * NOTE: This function has 3945 and 4965 specific code sections
+ * but is declared in base due to the majority of the
+ * implementation being the same (only a numeric constant is
+ * different)
+ *
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+ u32 reg = 0;
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if (q->need_update == 0)
+ goto exit_unlock;
+
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ goto exit_unlock;
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+ q->write & ~0x7);
+ iwl_release_restricted_access(priv);
+ } else
+ iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+ q->need_update = 0;
+
+ exit_unlock:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return rc;
+}
+
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
+ *
+ * NOTE: This function has 3945 and 4965 specific code paths in it.
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+ dma_addr_t dma_addr)
+{
+ return cpu_to_le32((u32)dma_addr);
+}
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ int write, rc;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ write = rxq->write & ~0x7;
+ while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ /* If the pre-allocated buffer pool is dropping low, schedule to
+ * refill it */
+ if (rxq->free_count <= RX_LOW_WATERMARK)
+ queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+ /* If we've added more space for the firmware to place data, tell it */
+ if ((write != (rxq->write & ~0x7))
+ || (abs(rxq->write - rxq->read) > 7)) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ rxq->need_update = 1;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during intialization)
+ */
+void iwl_rx_replenish(void *data)
+{
+ struct iwl_priv *priv = data;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ spin_lock_irqsave(&rxq->lock, flags);
+ while (!list_empty(&rxq->rx_used)) {
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ rxb->skb =
+ alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+ if (!rxb->skb) {
+ if (net_ratelimit())
+ printk(KERN_CRIT DRV_NAME
+ ": Can not allocate SKB buffers\n");
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ break;
+ }
+ priv->alloc_rxb_skb++;
+ list_del(element);
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_rx_queue_restock(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int i;
+ for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ }
+
+ pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ rxq->bd = NULL;
+}
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+
+ spin_lock_init(&rxq->lock);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+ if (!rxq->bd)
+ return -ENOMEM;
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ rxq->need_update = 0;
+ return 0;
+}
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&rxq->lock, flags);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb(rxq->pool[i].skb);
+ rxq->pool[i].skb = NULL;
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/* 0 1 2 3 4 5 6 7 8 9 */
+ 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+ 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+ 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+ 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+ 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+ 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+ 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+ 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+ 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+ 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ * (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl_calc_db_from_ratio(int sig_ratio)
+{
+ /* Anything above 1000:1 just report as 60 dB */
+ if (sig_ratio > 1000)
+ return 60;
+
+ /* Above 100:1, divide by 10 and use table,
+ * add 20 dB to make up for divide by 10 */
+ if (sig_ratio > 100)
+ return (20 + (int)ratio2dB[sig_ratio/10]);
+
+ /* We shouldn't see this */
+ if (sig_ratio < 1)
+ return 0;
+
+ /* Use table for ratios 1:1 - 99:1 */
+ return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95) /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ * about formulas used below. */
+int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+ int sig_qual;
+ int degradation = PERFECT_RSSI - rssi_dbm;
+
+ /* If we get a noise measurement, use signal-to-noise ratio (SNR)
+ * as indicator; formula is (signal dbm - noise dbm).
+ * SNR at or above 40 is a great signal (100%).
+ * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+ * Weakest usable signal is usually 10 - 15 dB SNR. */
+ if (noise_dbm) {
+ if (rssi_dbm - noise_dbm >= 40)
+ return 100;
+ else if (rssi_dbm < noise_dbm)
+ return 0;
+ sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+ /* Else use just the signal level.
+ * This formula is a least squares fit of data points collected and
+ * compared with a reference system that had a percentage (%) display
+ * for signal quality. */
+ } else
+ sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+ (15 * RSSI_RANGE + 62 * degradation)) /
+ (RSSI_RANGE * RSSI_RANGE);
+
+ if (sig_qual > 100)
+ sig_qual = 100;
+ else if (sig_qual < 1)
+ sig_qual = 0;
+
+ return sig_qual;
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_priv *priv)
+{
+ struct iwl_rx_mem_buffer *rxb;
+ struct iwl_rx_packet *pkt;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u32 r, i;
+ int reclaim;
+ unsigned long flags;
+
+ r = iwl_hw_get_rx_read(priv);
+ i = rxq->read;
+
+ /* Rx interrupt, but nothing sent from uCode */
+ if (i == r)
+ IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+ while (i != r) {
+ rxb = rxq->queue[i];
+
+ /* If an RXB doesn't have a queue slot associated with it
+ * then a bug has been introduced in the queue refilling
+ * routines -- catch it here */
+ BUG_ON(rxb == NULL);
+
+ rxq->queue[i] = NULL;
+
+ pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+ /* Reclaim a command buffer only if this packet is a response
+ * to a (driver-originated) command.
+ * If the packet (e.g. Rx frame) originated from uCode,
+ * there is no command buffer to reclaim.
+ * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+ * but apparently a few don't get set; catch them here. */
+ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+ (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+ (pkt->hdr.cmd != REPLY_TX);
+
+ /* Based on type of command response or notification,
+ * handle those that need handling via function in
+ * rx_handlers table. See iwl_setup_rx_handlers() */
+ if (priv->rx_handlers[pkt->hdr.cmd]) {
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r = %d, i = %d, %s, 0x%02x\n", r, i,
+ get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ } else {
+ /* No handling needed */
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
+ r, i, get_cmd_string(pkt->hdr.cmd),
+ pkt->hdr.cmd);
+ }
+
+ if (reclaim) {
+ /* Invoke any callbacks, transfer the skb to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
+ * as we reclaim the driver command queue */
+ if (rxb && rxb->skb)
+ iwl_tx_cmd_complete(priv, rxb);
+ else
+ IWL_WARNING("Claim null rxb?\n");
+ }
+
+ /* For now we just don't re-use anything. We can tweak this
+ * later to try and re-use notification packets and SKBs that
+ * fail to Rx correctly */
+ if (rxb->skb != NULL) {
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(rxb->skb);
+ rxb->skb = NULL;
+ }
+
+ pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ spin_lock_irqsave(&rxq->lock, flags);
+ list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ i = (i + 1) & RX_QUEUE_MASK;
+ }
+
+ /* Backtrack one entry */
+ priv->rxq.read = i;
+ iwl_rx_queue_restock(priv);
+}
+
+int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
+{
+ u32 reg = 0;
+ int rc = 0;
+ int txq_id = txq->q.id;
+
+ if (txq->need_update == 0)
+ return rc;
+
+ /* if we're trying to save power */
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ /* wake up nic if it's powered down ...
+ * uCode will wake up, and interrupt us again, so next
+ * time we'll skip this part. */
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return rc;
+ }
+
+ /* restore this queue's parameters in nic hardware. */
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+ iwl_release_restricted_access(priv);
+
+ /* else not in power-save mode, uCode will never sleep when we're
+ * trying to tx (during RFKILL, we're not trying to tx). */
+ } else
+ iwl_write32(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+
+ txq->need_update = 0;
+
+ return rc;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+{
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_RADIO("RX CONFIG:\n");
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+ IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+ IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+ le32_to_cpu(rxon->filter_flags));
+ IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+ IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+ rxon->ofdm_basic_rates);
+ IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+ IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+ print_mac(mac, rxon->node_addr));
+ IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+ print_mac(mac, rxon->bssid_addr));
+ IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR("Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+ switch (i) {
+ case 1:
+ return "FAIL";
+ case 2:
+ return "BAD_PARAM";
+ case 3:
+ return "BAD_CHECKSUM";
+ case 4:
+ return "NMI_INTERRUPT";
+ case 5:
+ return "SYSASSERT";
+ case 6:
+ return "FATAL_ERROR";
+ }
+
+ return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 i;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+ int rc;
+
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ count = iwl_read_restricted_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERROR("Start IWL Error Log Dump:\n");
+ IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+ priv->status, priv->config, count);
+ }
+
+ IWL_ERROR("Desc Time asrtPC blink2 "
+ "ilink1 nmiPC Line\n");
+ for (i = ERROR_START_OFFSET;
+ i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
+ i += ERROR_ELEM_SIZE) {
+ desc = iwl_read_restricted_mem(priv, base + i);
+ time =
+ iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32));
+ blink1 =
+ iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32));
+ blink2 =
+ iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32));
+ ilink1 =
+ iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32));
+ ilink2 =
+ iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32));
+ data1 =
+ iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32));
+
+ IWL_ERROR
+ ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+ desc_lookup(desc), desc, time, blink1, blink2,
+ ilink1, ilink2, data1);
+ }
+
+ iwl_release_restricted_access(priv);
+
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0)
+ IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+ else {
+ data = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+ }
+ }
+}
+
+static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ int rc;
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_restricted_mem(priv, base);
+ mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+ iwl_release_restricted_access(priv);
+ return;
+ }
+
+ IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+ iwl_release_restricted_access(priv);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_priv *priv)
+{
+ /* Set the FW error flag -- cleared on iwl_down */
+ set_bit(STATUS_FW_ERROR, &priv->status);
+
+ /* Cancel currently queued command. */
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
+ iwl_dump_nic_error_log(priv);
+ iwl_dump_nic_event_log(priv);
+ iwl_print_rx_config_cmd(&priv->staging_rxon);
+ }
+#endif
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ /* Keep the restart process from trying to send host
+ * commands by clearing the INIT status bit */
+ clear_bit(STATUS_READY, &priv->status);
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+ "Restarting adapter due to uCode error.\n");
+
+ if (iwl_is_associated(priv)) {
+ memcpy(&priv->recovery_rxon, &priv->active_rxon,
+ sizeof(priv->recovery_rxon));
+ priv->error_recovering = 1;
+ }
+ queue_work(priv->workqueue, &priv->restart);
+ }
+}
+
+static void iwl_error_recovery(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+ sizeof(priv->staging_rxon));
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ iwl_add_station(priv, priv->bssid, 1, 0);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+ priv->error_recovering = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+ u32 inta, handled = 0;
+ u32 inta_fh;
+ unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ u32 inta_mask;
+#endif
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Ack/clear/reset pending uCode interrupts.
+ * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+ * and will clear only when CSR_FH_INT_STATUS gets cleared. */
+ inta = iwl_read32(priv, CSR_INT);
+ iwl_write32(priv, CSR_INT, inta);
+
+ /* Ack/clear/reset pending flow-handler (DMA) interrupts.
+ * Any new interrupts that happen after this, either while we're
+ * in this tasklet, or later, will show up in next ISR/tasklet. */
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_ISR) {
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+ }
+#endif
+
+ /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+ * atomic, make sure that inta covers all the interrupts that
+ * we've discovered, even if FH interrupt came in just after
+ * reading CSR_INT. */
+ if (inta_fh & CSR_FH_INT_RX_MASK)
+ inta |= CSR_INT_BIT_FH_RX;
+ if (inta_fh & CSR_FH_INT_TX_MASK)
+ inta |= CSR_INT_BIT_FH_TX;
+
+ /* Now service all interrupt bits discovered above. */
+ if (inta & CSR_INT_BIT_HW_ERR) {
+ IWL_ERROR("Microcode HW error detected. Restarting.\n");
+
+ /* Tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ iwl_irq_handle_error(priv);
+
+ handled |= CSR_INT_BIT_HW_ERR;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ /* NIC fires this, but we don't use it, redundant with WAKEUP */
+ if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+ IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE)
+ IWL_DEBUG_ISR("Alive interrupt\n");
+ }
+#endif
+ /* Safely ignore these bits for debug checks below */
+ inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+ /* HW RF KILL switch toggled (4965 only) */
+ if (inta & CSR_INT_BIT_RF_KILL) {
+ int hw_rf_kill = 0;
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+ "RF_KILL bit toggled to %s.\n",
+ hw_rf_kill ? "disable radio":"enable radio");
+
+ /* Queue restart only if RF_KILL switch was set to "kill"
+ * when we loaded driver, and is now set to "enable".
+ * After we're Alive, RF_KILL gets handled by
+ * iwl_rx_card_state_notif() */
+ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+
+ handled |= CSR_INT_BIT_RF_KILL;
+ }
+
+ /* Chip got too hot and stopped itself (4965 only) */
+ if (inta & CSR_INT_BIT_CT_KILL) {
+ IWL_ERROR("Microcode CT kill error detected.\n");
+ handled |= CSR_INT_BIT_CT_KILL;
+ }
+
+ /* Error detected by uCode */
+ if (inta & CSR_INT_BIT_SW_ERR) {
+ IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n",
+ inta);
+ iwl_irq_handle_error(priv);
+ handled |= CSR_INT_BIT_SW_ERR;
+ }
+
+ /* uCode wakes up after power-down sleep */
+ if (inta & CSR_INT_BIT_WAKEUP) {
+ IWL_DEBUG_ISR("Wakeup interrupt\n");
+ iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+ handled |= CSR_INT_BIT_WAKEUP;
+ }
+
+ /* All uCode command responses, including Tx command responses,
+ * Rx "responses" (frame-received notification), and other
+ * notifications from uCode come through here*/
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+ iwl_rx_handle(priv);
+ handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+ }
+
+ if (inta & CSR_INT_BIT_FH_TX) {
+ IWL_DEBUG_ISR("Tx interrupt\n");
+
+ iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted(priv,
+ FH_TCSR_CREDIT
+ (ALM_FH_SRVC_CHNL), 0x0);
+ iwl_release_restricted_access(priv);
+ }
+ handled |= CSR_INT_BIT_FH_TX;
+ }
+
+ if (inta & ~handled)
+ IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+ if (inta & ~CSR_INI_SET_MASK) {
+ IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+ inta & ~CSR_INI_SET_MASK);
+ IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh);
+ }
+
+ /* Re-enable all interrupts */
+ iwl_enable_interrupts(priv);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ inta = iwl_read32(priv, CSR_INT);
+ inta_mask = iwl_read32(priv, CSR_INT_MASK);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+ "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+ }
+#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+ struct iwl_priv *priv = data;
+ u32 inta, inta_mask;
+ u32 inta_fh;
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ /* Disable (but don't clear!) interrupts here to avoid
+ * back-to-back ISRs and sporadic interrupts from our NIC.
+ * If we have something to service, the tasklet will re-enable ints.
+ * If we *don't* have something, we'll re-enable before leaving here. */
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* Discover which interrupts are active/pending */
+ inta = iwl_read32(priv, CSR_INT);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+ /* Ignore interrupt if there's nothing in NIC to service.
+ * This may be due to IRQ shared with another device,
+ * or due to sporadic interrupts thrown from our NIC. */
+ if (!inta && !inta_fh) {
+ IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+ goto none;
+ }
+
+ if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+ /* Hardware disappeared */
+ IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+ goto none;
+ }
+
+ IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+
+ /* iwl_irq_tasklet() will service interrupts and re-enable them */
+ tasklet_schedule(&priv->irq_tasklet);
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+
+ none:
+ /* re-enable interrupts here since we don't have anything to service. */
+ iwl_enable_interrupts(priv);
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel. We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware. This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel. There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl_eeprom_band_1[14] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl_eeprom_band_2[] = {
+ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */
+ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */
+ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
+ 145, 149, 153, 157, 161, 165
+};
+
+static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+ int *eeprom_ch_count,
+ const struct iwl_eeprom_channel
+ **eeprom_ch_info,
+ const u8 **eeprom_ch_index)
+{
+ switch (band) {
+ case 1: /* 2.4GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+ *eeprom_ch_info = priv->eeprom.band_1_channels;
+ *eeprom_ch_index = iwl_eeprom_band_1;
+ break;
+ case 2: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+ *eeprom_ch_info = priv->eeprom.band_2_channels;
+ *eeprom_ch_index = iwl_eeprom_band_2;
+ break;
+ case 3: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+ *eeprom_ch_info = priv->eeprom.band_3_channels;
+ *eeprom_ch_index = iwl_eeprom_band_3;
+ break;
+ case 4: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+ *eeprom_ch_info = priv->eeprom.band_4_channels;
+ *eeprom_ch_index = iwl_eeprom_band_4;
+ break;
+ case 5: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+ *eeprom_ch_info = priv->eeprom.band_5_channels;
+ *eeprom_ch_index = iwl_eeprom_band_5;
+ break;
+ default:
+ BUG();
+ return;
+ }
+}
+
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+ int phymode, u16 channel)
+{
+ int i;
+
+ switch (phymode) {
+ case MODE_IEEE80211A:
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel == channel)
+ return &priv->channel_info[i];
+ }
+ break;
+
+ case MODE_IEEE80211B:
+ case MODE_IEEE80211G:
+ if (channel >= 1 && channel <= 14)
+ return &priv->channel_info[channel - 1];
+ break;
+
+ }
+
+ return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+ ? # x " " : "")
+
+static int iwl_init_channel_map(struct iwl_priv *priv)
+{
+ int eeprom_ch_count = 0;
+ const u8 *eeprom_ch_index = NULL;
+ const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+ int band, ch;
+ struct iwl_channel_info *ch_info;
+
+ if (priv->channel_count) {
+ IWL_DEBUG_INFO("Channel map already initialized.\n");
+ return 0;
+ }
+
+ if (priv->eeprom.version < 0x2f) {
+ IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+ priv->eeprom.version);
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+ priv->channel_count =
+ ARRAY_SIZE(iwl_eeprom_band_1) +
+ ARRAY_SIZE(iwl_eeprom_band_2) +
+ ARRAY_SIZE(iwl_eeprom_band_3) +
+ ARRAY_SIZE(iwl_eeprom_band_4) +
+ ARRAY_SIZE(iwl_eeprom_band_5);
+
+ IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+ priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+ priv->channel_count, GFP_KERNEL);
+ if (!priv->channel_info) {
+ IWL_ERROR("Could not allocate channel_info\n");
+ priv->channel_count = 0;
+ return -ENOMEM;
+ }
+
+ ch_info = priv->channel_info;
+
+ /* Loop through the 5 EEPROM bands adding them in order to the
+ * channel map we maintain (that contains additional information than
+ * what just in the EEPROM) */
+ for (band = 1; band <= 5; band++) {
+
+ iwl_init_band_reference(priv, band, &eeprom_ch_count,
+ &eeprom_ch_info, &eeprom_ch_index);
+
+ /* Loop through each band adding each of the channels */
+ for (ch = 0; ch < eeprom_ch_count; ch++) {
+ ch_info->channel = eeprom_ch_index[ch];
+ ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+ MODE_IEEE80211A;
+
+ /* permanently store EEPROM's channel regulatory flags
+ * and max power in channel info database. */
+ ch_info->eeprom = eeprom_ch_info[ch];
+
+ /* Copy the run-time flags so they are there even on
+ * invalid channels */
+ ch_info->flags = eeprom_ch_info[ch].flags;
+
+ if (!(is_channel_valid(ch_info))) {
+ IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+ "No traffic\n",
+ ch_info->channel,
+ ch_info->flags,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4");
+ ch_info++;
+ continue;
+ }
+
+ /* Initialize regulatory-based run-time data */
+ ch_info->max_power_avg = ch_info->curr_txpow =
+ eeprom_ch_info[ch].max_power_avg;
+ ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+ ch_info->min_power = 0;
+
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ " %ddBm): Ad-Hoc %ssupported\n",
+ ch_info->channel,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4",
+ CHECK_AND_PRINT(IBSS),
+ CHECK_AND_PRINT(ACTIVE),
+ CHECK_AND_PRINT(RADAR),
+ CHECK_AND_PRINT(WIDE),
+ CHECK_AND_PRINT(NARROW),
+ CHECK_AND_PRINT(DFS),
+ eeprom_ch_info[ch].flags,
+ eeprom_ch_info[ch].max_power_avg,
+ ((eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_IBSS)
+ && !(eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_RADAR))
+ ? "" : "not ");
+
+ /* Set the user_txpower_limit to the highest power
+ * supported by any channel */
+ if (eeprom_ch_info[ch].max_power_avg >
+ priv->user_txpower_limit)
+ priv->user_txpower_limit =
+ eeprom_ch_info[ch].max_power_avg;
+
+ ch_info++;
+ }
+ }
+
+ if (iwl3945_txpower_set_from_eeprom(priv))
+ return -EIO;
+
+ return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req. This should be set long enough to hear probe responses
+ * from more than one AP. */
+#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52 (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
+#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52 (10)
+#define IWL_PASSIVE_DWELL_BASE (100)
+#define IWL_CHANNEL_TUNE_TIME 5
+
+static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ if (phymode == MODE_IEEE80211A)
+ return IWL_ACTIVE_DWELL_TIME_52;
+ else
+ return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ u16 active = iwl_get_active_dwell_time(priv, phymode);
+ u16 passive = (phymode != MODE_IEEE80211A) ?
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+ if (iwl_is_associated(priv)) {
+ /* If we're associated, we clamp the maximum passive
+ * dwell time to be 98% of the beacon interval (minus
+ * 2 * channel tune time) */
+ passive = priv->beacon_int;
+ if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+ passive = IWL_PASSIVE_DWELL_BASE;
+ passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+ }
+
+ if (passive <= active)
+ passive = active + 1;
+
+ return passive;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+ u8 is_active, u8 direct_mask,
+ struct iwl_scan_channel *scan_ch)
+{
+ const struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode;
+ const struct iwl_channel_info *ch_info;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added, i;
+
+ hw_mode = iwl_get_hw_mode(priv, phymode);
+ if (!hw_mode)
+ return 0;
+
+ channels = hw_mode->channels;
+
+ active_dwell = iwl_get_active_dwell_time(priv, phymode);
+ passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+
+ for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+ if (channels[i].chan ==
+ 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 = channels[i].chan;
+
+ ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+ scan_ch->channel);
+ continue;
+ }
+
+ if (!is_active || is_channel_passive(ch_info) ||
+ !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+ scan_ch->type = 0; /* passive */
+ else
+ scan_ch->type = 1; /* active */
+
+ if (scan_ch->type & 1)
+ scan_ch->type |= (direct_mask << 1);
+
+ if (is_channel_narrow(ch_info))
+ scan_ch->type |= (1 << 7);
+
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+ /* Set power levels to defaults */
+ scan_ch->tpc.dsp_atten = 110;
+ /* scan_pwr_info->tpc.dsp_atten; */
+
+ /*scan_pwr_info->tpc.tx_gain; */
+ if (phymode == MODE_IEEE80211A)
+ scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else {
+ scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level
+ scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+ */
+ }
+
+ IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+ scan_ch->channel,
+ (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+ (scan_ch->type & 1) ?
+ active_dwell : passive_dwell);
+
+ scan_ch++;
+ added++;
+ }
+
+ IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+ return added;
+}
+
+static void iwl_reset_channel_flag(struct iwl_priv *priv)
+{
+ int i, j;
+ for (i = 0; i < 3; i++) {
+ struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+ for (j = 0; j < hw_mode->num_channels; j++)
+ hw_mode->channels[j].flag = hw_mode->channels[j].val;
+ }
+}
+
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates)
+{
+ int i;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ rates[i].rate = iwl_rates[i].ieee * 5;
+ rates[i].val = i; /* Rate scaling will work on indexes */
+ rates[i].val2 = i;
+ rates[i].flags = IEEE80211_RATE_SUPPORTED;
+ /* Only OFDM have the bits-per-symbol set */
+ if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+ rates[i].flags |= IEEE80211_RATE_OFDM;
+ else {
+ /*
+ * If CCK 1M then set rate flag to CCK else CCK_2
+ * which is CCK | PREAMBLE2
+ */
+ rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+ IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+ }
+
+ /* Set up which ones are basic rates... */
+ if (IWL_BASIC_RATES_MASK & (1 << i))
+ rates[i].flags |= IEEE80211_RATE_BASIC;
+ }
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch;
+ struct ieee80211_hw_mode *modes;
+ struct ieee80211_channel *channels;
+ struct ieee80211_channel *geo_ch;
+ struct ieee80211_rate *rates;
+ int i = 0;
+ enum {
+ A = 0,
+ B = 1,
+ G = 2,
+ };
+ int mode_count = 3;
+
+ if (priv->modes) {
+ IWL_DEBUG_INFO("Geography modes already initialized.\n");
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ return 0;
+ }
+
+ modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+ GFP_KERNEL);
+ if (!modes)
+ return -ENOMEM;
+
+ channels = kzalloc(sizeof(struct ieee80211_channel) *
+ priv->channel_count, GFP_KERNEL);
+ if (!channels) {
+ kfree(modes);
+ return -ENOMEM;
+ }
+
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+ GFP_KERNEL);
+ if (!rates) {
+ kfree(modes);
+ kfree(channels);
+ return -ENOMEM;
+ }
+
+ /* 0 = 802.11a
+ * 1 = 802.11b
+ * 2 = 802.11g
+ */
+
+ /* 5.2GHz channels start after the 2.4GHz channels */
+ modes[A].mode = MODE_IEEE80211A;
+ modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ modes[A].rates = rates;
+ modes[A].num_rates = 8; /* just OFDM */
+ modes[A].num_channels = 0;
+
+ modes[B].mode = MODE_IEEE80211B;
+ modes[B].channels = channels;
+ modes[B].rates = &rates[8];
+ modes[B].num_rates = 4; /* just CCK */
+ modes[B].num_channels = 0;
+
+ modes[G].mode = MODE_IEEE80211G;
+ modes[G].channels = channels;
+ modes[G].rates = rates;
+ modes[G].num_rates = 12; /* OFDM & CCK */
+ modes[G].num_channels = 0;
+
+ priv->ieee_channels = channels;
+ priv->ieee_rates = rates;
+
+ iwl_init_hw_rates(priv, rates);
+
+ for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+ ch = &priv->channel_info[i];
+
+ if (!is_channel_valid(ch)) {
+ IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+ "skipping.\n",
+ ch->channel, is_channel_a_band(ch) ?
+ "5.2" : "2.4");
+ continue;
+ }
+
+ if (is_channel_a_band(ch))
+ geo_ch = &modes[A].channels[modes[A].num_channels++];
+ else {
+ geo_ch = &modes[B].channels[modes[B].num_channels++];
+ modes[G].num_channels++;
+ }
+
+ geo_ch->freq = ieee80211chan2mhz(ch->channel);
+ geo_ch->chan = ch->channel;
+ geo_ch->power_level = ch->max_power_avg;
+ geo_ch->antenna_max = 0xff;
+
+ if (is_channel_valid(ch)) {
+ geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+ if (ch->flags & EEPROM_CHANNEL_IBSS)
+ geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+ if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+ geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+ if (ch->flags & EEPROM_CHANNEL_RADAR)
+ geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+ if (ch->max_power_avg > priv->max_channel_txpower_limit)
+ priv->max_channel_txpower_limit =
+ ch->max_power_avg;
+ }
+
+ geo_ch->val = geo_ch->flag;
+ }
+
+ if ((modes[A].num_channels == 0) && priv->is_abg) {
+ printk(KERN_INFO DRV_NAME
+ ": Incorrectly detected BG card as ABG. Please send "
+ "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+ priv->pci_dev->device, priv->pci_dev->subsystem_device);
+ priv->is_abg = 0;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+ modes[G].num_channels, modes[A].num_channels);
+
+ /*
+ * NOTE: We register these in preference of order -- the
+ * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+ * a phymode based on rates or AP capabilities but seems to
+ * configure it purely on if the channel being configured
+ * is supported by a mode -- and the first match is taken
+ */
+
+ if (modes[G].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[G]);
+ if (modes[B].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[B]);
+ if (modes[A].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+ priv->modes = modes;
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+ if (priv->ucode_code.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ priv->ucode_code.v_addr,
+ priv->ucode_code.p_addr);
+ priv->ucode_code.v_addr = NULL;
+ }
+ if (priv->ucode_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ priv->ucode_data.v_addr,
+ priv->ucode_data.p_addr);
+ priv->ucode_data.v_addr = NULL;
+ }
+ if (priv->ucode_data_backup.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ priv->ucode_data_backup.v_addr,
+ priv->ucode_data_backup.p_addr);
+ priv->ucode_data_backup.v_addr = NULL;
+ }
+ if (priv->ucode_init.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ priv->ucode_init.v_addr,
+ priv->ucode_init.p_addr);
+ priv->ucode_init.v_addr = NULL;
+ }
+ if (priv->ucode_init_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ priv->ucode_init_data.v_addr,
+ priv->ucode_init_data.p_addr);
+ priv->ucode_init_data.v_addr = NULL;
+ }
+ if (priv->ucode_boot.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ priv->ucode_boot.v_addr,
+ priv->ucode_boot.p_addr);
+ priv->ucode_boot.v_addr = NULL;
+ }
+}
+
+/**
+ * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int rc = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ if (!errcnt)
+ IWL_DEBUG_INFO
+ ("ucode image in INSTRUCTION memory is good\n");
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int rc = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+ i + RTC_INST_LOWER_BOUND);
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+#if 0 /* Enable this if you want to see details */
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ i, val, *image);
+#endif
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int rc = 0;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Show first several data entries in instruction SRAM.
+ * Selection of bootstrap image is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_full(priv, image, len);
+
+ return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl_verify_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ u32 reg;
+ u32 val;
+
+ IWL_DEBUG_INFO("Begin verify bsm\n");
+
+ /* verify BSM SRAM contents */
+ val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+ for (reg = BSM_SRAM_LOWER_BOUND;
+ reg < BSM_SRAM_LOWER_BOUND + len;
+ reg += sizeof(u32), image ++) {
+ val = iwl_read_restricted_reg(priv, reg);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("BSM uCode verification failed at "
+ "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+ BSM_SRAM_LOWER_BOUND,
+ reg - BSM_SRAM_LOWER_BOUND, len,
+ val, le32_to_cpu(*image));
+ return -EIO;
+ }
+ }
+
+ IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+ return 0;
+}
+
+/**
+ * iwl_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL. When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers. Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image. This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program. This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl_load_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ u32 inst_len;
+ u32 data_len;
+ int rc;
+ int i;
+ u32 done;
+ u32 reg_offset;
+
+ IWL_DEBUG_INFO("Begin load bsm\n");
+
+ /* make sure bootstrap program is no larger than BSM's SRAM size */
+ if (len > IWL_MAX_BSM_SIZE)
+ return -EINVAL;
+
+ /* Tell bootstrap uCode where to find the "Initialize" uCode
+ * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+ * NOTE: iwl_initialize_alive_start() will replace these values,
+ * after the "initialize" uCode has run, to point to
+ * runtime/protocol instructions and backup data cache. */
+ pinst = priv->ucode_init.p_addr;
+ pdata = priv->ucode_init_data.p_addr;
+ inst_len = priv->ucode_init.len;
+ data_len = priv->ucode_init_data.len;
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+ /* Fill BSM memory with bootstrap instructions */
+ for (reg_offset = BSM_SRAM_LOWER_BOUND;
+ reg_offset < BSM_SRAM_LOWER_BOUND + len;
+ reg_offset += sizeof(u32), image++)
+ _iwl_write_restricted_reg(priv, reg_offset,
+ le32_to_cpu(*image));
+
+ rc = iwl_verify_bsm(priv);
+ if (rc) {
+ iwl_release_restricted_access(priv);
+ return rc;
+ }
+
+ /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+ RTC_INST_LOWER_BOUND);
+ iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+ /* Load bootstrap code into instruction SRAM now,
+ * to prepare to load "initialize" uCode */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START);
+
+ /* Wait for load of bootstrap uCode to finish */
+ for (i = 0; i < 100; i++) {
+ done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+ if (!(done & BSM_WR_CTRL_REG_BIT_START))
+ break;
+ udelay(10);
+ }
+ if (i < 100)
+ IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+ else {
+ IWL_ERROR("BSM write did not complete!\n");
+ return -EIO;
+ }
+
+ /* Enable future boot loads whenever power management unit triggers it
+ * (e.g. when powering back up after power-save shutdown) */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START_EN);
+
+ iwl_release_restricted_access(priv);
+
+ return 0;
+}
+
+static void iwl_nic_start(struct iwl_priv *priv)
+{
+ /* Remove all resets to allow NIC to operate */
+ iwl_write32(priv, CSR_RESET, 0);
+}
+
+/**
+ * iwl_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl_read_ucode(struct iwl_priv *priv)
+{
+ struct iwl_ucode *ucode;
+ int rc = 0;
+ const struct firmware *ucode_raw;
+ /* firmware file name contains uCode/driver compatibility version */
+ const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
+ u8 *src;
+ size_t len;
+ u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+ /* Ask kernel firmware_class module to get the boot firmware off disk.
+ * request_firmware() is synchronous, file is in memory on return. */
+ rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+ if (rc < 0) {
+ IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+ goto error;
+ }
+
+ IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+ name, ucode_raw->size);
+
+ /* Make sure that we got at least our header! */
+ if (ucode_raw->size < sizeof(*ucode)) {
+ IWL_ERROR("File size way too small!\n");
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Data from ucode file: header followed by uCode images */
+ ucode = (void *)ucode_raw->data;
+
+ ver = le32_to_cpu(ucode->ver);
+ inst_size = le32_to_cpu(ucode->inst_size);
+ data_size = le32_to_cpu(ucode->data_size);
+ init_size = le32_to_cpu(ucode->init_size);
+ init_data_size = le32_to_cpu(ucode->init_data_size);
+ boot_size = le32_to_cpu(ucode->boot_size);
+
+ IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+ IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+ inst_size);
+ IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+ data_size);
+ IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+ init_size);
+ IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+ init_data_size);
+ IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+ boot_size);
+
+ /* Verify size of file vs. image size info in file's header */
+ if (ucode_raw->size < sizeof(*ucode) +
+ inst_size + data_size + init_size +
+ init_data_size + boot_size) {
+
+ IWL_DEBUG_INFO("uCode file size %d too small\n",
+ (int)ucode_raw->size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Verify that uCode images will fit in card's SRAM */
+ if (inst_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
+ (int)inst_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ if (data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
+ (int)data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init instr len %d too large to fit in card\n",
+ (int)init_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init data len %d too large to fit in card\n",
+ (int)init_data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (boot_size > IWL_MAX_BSM_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode boot instr len %d too large to fit in bsm\n",
+ (int)boot_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Allocate ucode buffers for card's bus-master loading ... */
+
+ /* Runtime instructions and 2 copies of data:
+ * 1) unmodified from disk
+ * 2) backup cache for save/restore during power-downs */
+ priv->ucode_code.len = inst_size;
+ priv->ucode_code.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ &(priv->ucode_code.p_addr));
+
+ priv->ucode_data.len = data_size;
+ priv->ucode_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ &(priv->ucode_data.p_addr));
+
+ priv->ucode_data_backup.len = data_size;
+ priv->ucode_data_backup.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ &(priv->ucode_data_backup.p_addr));
+
+
+ /* Initialization instructions and data */
+ priv->ucode_init.len = init_size;
+ priv->ucode_init.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ &(priv->ucode_init.p_addr));
+
+ priv->ucode_init_data.len = init_data_size;
+ priv->ucode_init_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ &(priv->ucode_init_data.p_addr));
+
+ /* Bootstrap (instructions only, no data) */
+ priv->ucode_boot.len = boot_size;
+ priv->ucode_boot.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ &(priv->ucode_boot.p_addr));
+
+ if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+ !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
+ !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
+ goto err_pci_alloc;
+
+ /* Copy images into buffers for card's bus-master reads ... */
+
+ /* Runtime instructions (first block of data in file) */
+ src = &ucode->data[0];
+ len = priv->ucode_code.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_code.v_addr, src, len);
+ IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+ priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+ /* Runtime data (2nd block)
+ * NOTE: Copy into backup buffer will be done in iwl_up() */
+ src = &ucode->data[inst_size];
+ len = priv->ucode_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_data.v_addr, src, len);
+ memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+ /* Initialization instructions (3rd block) */
+ if (init_size) {
+ src = &ucode->data[inst_size + data_size];
+ len = priv->ucode_init.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init.v_addr, src, len);
+ }
+
+ /* Initialization data (4th block) */
+ if (init_data_size) {
+ src = &ucode->data[inst_size + data_size + init_size];
+ len = priv->ucode_init_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init_data.v_addr, src, len);
+ }
+
+ /* Bootstrap instructions (5th block) */
+ src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+ len = priv->ucode_boot.len;
+ IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_boot.v_addr, src, len);
+
+ /* We have our copies now, allow OS release its copies */
+ release_firmware(ucode_raw);
+ return 0;
+
+ err_pci_alloc:
+ IWL_ERROR("failed to allocate pci memory\n");
+ rc = -ENOMEM;
+ iwl_dealloc_ucode_pci(priv);
+
+ err_release:
+ release_firmware(ucode_raw);
+
+ error:
+ return rc;
+}
+
+
+/**
+ * iwl_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+{
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ int rc = 0;
+ unsigned long flags;
+
+ /* bits 31:0 for 3945 */
+ pinst = priv->ucode_code.p_addr;
+ pdata = priv->ucode_data_backup.p_addr;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* Tell bootstrap uCode where to find image to load */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+ priv->ucode_data.len);
+
+ /* Inst bytecount must be last to set up, bit 31 signals uCode
+ * that all new ptr/size info is in place */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+ priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+ iwl_release_restricted_access(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+ return rc;
+}
+
+/**
+ * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ * Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ * (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl_init_alive_start(struct iwl_priv *priv)
+{
+ /* Check alive response for "valid" sign from uCode */
+ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Initialize Alive failed.\n");
+ goto restart;
+ }
+
+ /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "initialize" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+ goto restart;
+ }
+
+ /* Send pointers to protocol/runtime uCode image ... init code will
+ * load and launch runtime uCode, which will send us another "Alive"
+ * notification. */
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ if (iwl_set_ucode_ptrs(priv)) {
+ /* Runtime instruction load won't happen;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+ goto restart;
+ }
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ * from protocol/runtime uCode (initialization uCode's
+ * Alive gets handled by iwl_init_alive_start()).
+ */
+static void iwl_alive_start(struct iwl_priv *priv)
+{
+ int rc = 0;
+ int thermal_spin = 0;
+ u32 rfkill;
+
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+ if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Alive failed.\n");
+ goto restart;
+ }
+
+ /* Initialize uCode has loaded Runtime uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "runtime" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+ goto restart;
+ }
+
+ iwl_clear_stations_table(priv);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read rfkill status from adapter\n");
+ return;
+ }
+
+ rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG);
+ IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill);
+ iwl_release_restricted_access(priv);
+
+ if (rfkill & 0x1) {
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ /* if rfkill is not on, then wait for thermal
+ * sensor in adapter to kick in */
+ while (iwl_hw_get_temperature(priv) == 0) {
+ thermal_spin++;
+ udelay(10);
+ }
+
+ if (thermal_spin)
+ IWL_DEBUG_INFO("Thermal calibration took %dus\n",
+ thermal_spin * 10);
+ } else
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+
+ /* After the ALIVE response, we can process host commands */
+ set_bit(STATUS_ALIVE, &priv->status);
+
+ /* Clear out the uCode error bit if it is set */
+ clear_bit(STATUS_FW_ERROR, &priv->status);
+
+ rc = iwl_init_channel_map(priv);
+ if (rc) {
+ IWL_ERROR("initializing regulatory failed: %d\n", rc);
+ return;
+ }
+
+ iwl_init_geos(priv);
+
+ if (iwl_is_rfkill(priv))
+ return;
+
+ if (!priv->mac80211_registered) {
+ /* Unlock so any user space entry points can call back into
+ * the driver without a deadlock... */
+ mutex_unlock(&priv->mutex);
+ iwl_rate_control_register(priv->hw);
+ rc = ieee80211_register_hw(priv->hw);
+ priv->hw->conf.beacon_int = 100;
+ mutex_lock(&priv->mutex);
+
+ if (rc) {
+ IWL_ERROR("Failed to register network "
+ "device (error %d)\n", rc);
+ return;
+ }
+
+ priv->mac80211_registered = 1;
+
+ iwl_reset_channel_flag(priv);
+ } else
+ ieee80211_start_queues(priv->hw);
+
+ priv->active_rate = priv->rates_mask;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+ if (iwl_is_associated(priv)) {
+ struct iwl_rxon_cmd *active_rxon =
+ (struct iwl_rxon_cmd *)(&priv->active_rxon);
+
+ memcpy(&priv->staging_rxon, &priv->active_rxon,
+ sizeof(priv->staging_rxon));
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ } else {
+ /* Initialize our rx_config data */
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+ }
+
+ /* Configure BT coexistence */
+ iwl_send_bt_config(priv);
+
+ /* Configure the adapter for unassociated operation */
+ iwl_commit_rxon(priv);
+
+ /* At this point, the NIC is initialized and operational */
+ priv->notif_missed_beacons = 0;
+ set_bit(STATUS_READY, &priv->status);
+
+ iwl3945_reg_txpower_periodic(priv);
+
+ IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+ if (priv->error_recovering)
+ iwl_error_recovery(priv);
+
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+
+static void __iwl_down(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+ struct ieee80211_conf *conf = NULL;
+
+ IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ if (!exit_pending)
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ iwl_clear_stations_table(priv);
+
+ /* Unblock any waiting calls */
+ wake_up_interruptible_all(&priv->wait_command_queue);
+
+ iwl_cancel_deferred_work(priv);
+
+ /* Wipe out the EXIT_PENDING status bit if we are not actually
+ * exiting the module */
+ if (!exit_pending)
+ clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ /* stop and reset the on-board processor */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ /* If we have not previously called iwl_init() then
+ * clear all bits but the RF Kill and SUSPEND bits and return */
+ if (!iwl_is_init(priv)) {
+ priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND;
+ goto exit;
+ }
+
+ /* ...otherwise clear out all the status bits but the RF Kill and
+ * SUSPEND bits and continue taking the NIC down. */
+ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND |
+ test_bit(STATUS_FW_ERROR, &priv->status) <<
+ STATUS_FW_ERROR;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_txq_ctx_stop(priv);
+ iwl_hw_rxq_stop(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_stop_master(priv);
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ iwl_hw_nic_reset(priv);
+
+ exit:
+ memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+ priv->ibss_beacon = NULL;
+
+ /* clear out any free frames */
+ iwl_clear_free_frames(priv);
+}
+
+static void iwl_down(struct iwl_priv *priv)
+{
+ mutex_lock(&priv->mutex);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+ DECLARE_MAC_BUF(mac);
+ int rc, i;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_WARNING("Exit pending; will not bring the NIC up\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+ IWL_WARNING("Radio disabled by SW RF kill (module "
+ "parameter)\n");
+ return 0;
+ }
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ rc = iwl_hw_nic_init(priv);
+ if (rc) {
+ IWL_ERROR("Unable to int nic\n");
+ return rc;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_enable_interrupts(priv);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* Copy original ucode data image from disk into backup cache.
+ * This will be used to initialize the on-board processor's
+ * data SRAM for a clean start when the runtime program first loads. */
+ memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+ priv->ucode_data.len);
+
+ for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+ iwl_clear_stations_table(priv);
+
+ /* load bootstrap state machine,
+ * load bootstrap program into processor's memory,
+ * prepare to load the "initialize" uCode */
+ rc = iwl_load_bsm(priv);
+
+ if (rc) {
+ IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+ continue;
+ }
+
+ /* start card; "initialize" will load runtime ucode */
+ iwl_nic_start(priv);
+
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %s\n",
+ print_mac(mac, priv->mac_addr));
+
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+ IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+ return 0;
+ }
+
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+
+ /* tried to restart and config the device for as long as our
+ * patience could withstand */
+ IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+ return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_init_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, init_alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_init_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_rf_kill(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_rfkill(priv)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+ "HW and/or SW RF Kill no longer active, restarting "
+ "device\n");
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+ } else {
+
+ if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by SW switch\n");
+ else
+ IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+ "Kill switch must be turned off for "
+ "wireless networking to work.\n");
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, scan_check.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_SCANNING, &priv->status) ||
+ test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+ "Scan completion watchdog resetting adapter (%dms)\n",
+ jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_request_scan(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, request_scan);
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_CMD,
+ .len = sizeof(struct iwl_scan_cmd),
+ .meta.flags = CMD_SIZE_HUGE,
+ };
+ int rc = 0;
+ struct iwl_scan_cmd *scan;
+ struct ieee80211_conf *conf = NULL;
+ u8 direct_mask;
+ int phymode;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_WARNING("request scan called when driver not ready.\n");
+ goto done;
+ }
+
+ /* Make sure the scan wasn't cancelled before this queued work
+ * was given the chance to run... */
+ if (!test_bit(STATUS_SCANNING, &priv->status))
+ goto done;
+
+ /* This should never be called or scheduled if there is currently
+ * a scan active in the hardware. */
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+ "Ignoring second request.\n");
+ rc = -EIO;
+ goto done;
+ }
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+ goto done;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n");
+ goto done;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+ goto done;
+ }
+
+ if (!test_bit(STATUS_READY, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n");
+ goto done;
+ }
+
+ if (!priv->scan_bands) {
+ IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+ goto done;
+ }
+
+ if (!priv->scan) {
+ priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+ IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+ if (!priv->scan) {
+ rc = -ENOMEM;
+ goto done;
+ }
+ }
+ scan = priv->scan;
+ memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+ scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+ scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+ if (iwl_is_associated(priv)) {
+ u16 interval = 0;
+ u32 extra;
+ u32 suspend_time = 100;
+ u32 scan_suspend_time = 100;
+ unsigned long flags;
+
+ IWL_DEBUG_INFO("Scanning while associated...\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+ interval = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ scan->suspend_time = 0;
+ scan->max_out_time = cpu_to_le32(600 * 1024);
+ if (!interval)
+ interval = suspend_time;
+ /*
+ * suspend time format:
+ * 0-19: beacon interval in usec (time before exec.)
+ * 20-23: 0
+ * 24-31: number of beacons (suspend between channels)
+ */
+
+ extra = (suspend_time / interval) << 24;
+ scan_suspend_time = 0xFF0FFFFF &
+ (extra | ((suspend_time % interval) * 1024));
+
+ scan->suspend_time = cpu_to_le32(scan_suspend_time);
+ IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+ scan_suspend_time, interval);
+ }
+
+ /* We should add the ability for user to lock to PASSIVE ONLY */
+ if (priv->one_direct_scan) {
+ IWL_DEBUG_SCAN
+ ("Kicking off one direct scan for '%s'\n",
+ iwl_escape_essid(priv->direct_ssid,
+ priv->direct_ssid_len));
+ scan->direct_scan[0].id = WLAN_EID_SSID;
+ scan->direct_scan[0].len = priv->direct_ssid_len;
+ memcpy(scan->direct_scan[0].ssid,
+ priv->direct_ssid, priv->direct_ssid_len);
+ direct_mask = 1;
+ } else if (!iwl_is_associated(priv)) {
+ 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
+ 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 */
+ scan->tx_cmd.len = cpu_to_le16(
+ iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+ IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+ scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+ scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+ scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ /* flags + rate selection */
+
+ switch (priv->scan_bands) {
+ case 2:
+ scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+ scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
+ scan->good_CRC_th = 0;
+ phymode = MODE_IEEE80211G;
+ break;
+
+ case 1:
+ scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
+ scan->good_CRC_th = IWL_GOOD_CRC_TH;
+ phymode = MODE_IEEE80211A;
+ break;
+
+ default:
+ IWL_WARNING("Invalid scan band count\n");
+ goto done;
+ }
+
+ /* select Rx antennas */
+ scan->flags |= iwl3945_get_antenna_flags(priv);
+
+ 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",
+ iwl_escape_essid(priv->essid, priv->essid_len));
+ else
+ IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+ scan->channel_count =
+ iwl_get_channels_for_scan(
+ priv, phymode, 1, /* active */
+ 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 iwl_scan_channel);
+ cmd.data = scan;
+ scan->len = cpu_to_le16(cmd.len);
+
+ set_bit(STATUS_SCAN_HW, &priv->status);
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ goto done;
+
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IWL_SCAN_CHECK_WATCHDOG);
+
+ mutex_unlock(&priv->mutex);
+ return;
+
+ done:
+ /* inform mac80211 sacn aborted */
+ queue_work(priv->workqueue, &priv->scan_completed);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_up(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ __iwl_up(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ iwl_down(priv);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl_bg_rx_replenish(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, rx_replenish);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_rx_replenish(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_post_associate(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv,
+ post_associate.work);
+
+ int rc = 0;
+ struct ieee80211_conf *conf = NULL;
+ DECLARE_MAC_BUF(mac);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+ return;
+ }
+
+
+ IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+ priv->assoc_id,
+ print_mac(mac, priv->active_rxon.bssid_addr));
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+ IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+ priv->assoc_id, priv->beacon_int);
+
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ }
+
+ iwl_commit_rxon(priv);
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_STA:
+ iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+
+ /* clear out the station table */
+ iwl_clear_stations_table(priv);
+
+ iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+ iwl_add_station(priv, priv->bssid, 0, 0);
+ iwl3945_sync_sta(priv, IWL_STA_ID,
+ (priv->phymode == MODE_IEEE80211A)?
+ IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+ CMD_ASYNC);
+ iwl_rate_scale_init(priv->hw, IWL_STA_ID);
+ iwl_send_beacon_cmd(priv);
+
+ break;
+
+ default:
+ IWL_ERROR("%s Should not be called in %d mode\n",
+ __FUNCTION__, priv->iw_mode);
+ break;
+ }
+
+ iwl_sequence_reset(priv);
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_activate_qos(priv, 0);
+#endif /* CONFIG_IWLWIFI_QOS */
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ abort_scan);
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ iwl_send_scan_abort(priv);
+
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, scan_completed);
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ ieee80211_scan_completed(priv->hw);
+
+ /* Since setting the TXPOWER may have been deferred while
+ * performing the scan, fire one off */
+ mutex_lock(&priv->mutex);
+ iwl_hw_reg_send_txpower(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl_mac_start(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ /* we should be verifying the device is ready to be opened */
+ mutex_lock(&priv->mutex);
+
+ priv->is_open = 1;
+
+ if (!iwl_is_rfkill(priv))
+ ieee80211_start_queues(priv->hw);
+
+ mutex_unlock(&priv->mutex);
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static void iwl_mac_stop(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+ priv->is_open = 0;
+ /*netif_stop_queue(dev); */
+ flush_workqueue(priv->workqueue);
+ IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ IWL_DEBUG_MAC80211("leave - monitor\n");
+ return -1;
+ }
+
+ IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+ ctl->tx_rate);
+
+ if (iwl_tx_skb(priv, skb, ctl))
+ dev_kfree_skb_any(skb);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+ if (conf->mac_addr)
+ IWL_DEBUG_MAC80211("enter: MAC %s\n",
+ print_mac(mac, conf->mac_addr));
+
+ if (priv->interface_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->interface_id = conf->if_id;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ iwl_set_mode(priv, conf->type);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+ * what is exposed through include/ declrations */
+ if (unlikely(!iwl_param_disable_hw_scan &&
+ test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+ conf->channel, conf->phymode);
+ IWL_DEBUG_MAC80211("leave - invalid channel\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+ iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+ iwl_set_flags_for_phymode(priv, conf->phymode);
+
+ /* The list of supported rates and rate mask can be different
+ * for each phymode; since the phymode may have changed, reset
+ * the rate mask to what mac80211 lists */
+ iwl_set_rate(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+ if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+ iwl_hw_channel_switch(priv, conf->channel);
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+#endif
+
+ iwl_radio_kill_sw(priv, !conf->radio_enabled);
+
+ if (!conf->radio_enabled) {
+ IWL_DEBUG_MAC80211("leave - radio disabled\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF kill\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ iwl_set_rate(priv);
+
+ if (memcmp(&priv->active_rxon,
+ &priv->staging_rxon, sizeof(priv->staging_rxon)))
+ iwl_commit_rxon(priv);
+ else
+ IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_config_ap(struct iwl_priv *priv)
+{
+ int rc = 0;
+
+ if (priv->status & STATUS_EXIT_PENDING)
+ return;
+
+ /* The following should be done only at AP bring up */
+ if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+ /* RXON - unassoc (to set timing command) */
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ /* RXON Timing */
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ /* FIXME: what should be the assoc_id for AP? */
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability &
+ WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+ }
+ /* restore RXON assoc */
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+ }
+ iwl_send_beacon_cmd(priv);
+
+ /* FIXME - we need to add code here to detect a totally new
+ * configuration, reset the AP, unassoc, rxon timing, assoc,
+ * clear sta table, add BCAST sta... */
+}
+
+static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+ unsigned long flags;
+ int rc;
+
+ if (conf == NULL)
+ return -EIO;
+
+ /* XXX: this MUST use conf->mac_addr */
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!conf->beacon || !conf->ssid_len)) {
+ IWL_DEBUG_MAC80211
+ ("Leaving in AP mode because HostAPD is not ready.\n");
+ return 0;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+ if (conf->bssid)
+ IWL_DEBUG_MAC80211("bssid: %s\n",
+ print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+ !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->interface_id != if_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (!conf->bssid) {
+ conf->bssid = priv->mac_addr;
+ memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+ IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+ print_mac(mac, conf->bssid));
+ }
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = conf->beacon;
+ }
+
+ if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+ !is_multicast_ether_addr(conf->bssid)) {
+ /* If there is currently a HW scan going on in the background
+ * then we need to cancel it else the RXON below will fail. */
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress "
+ "after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ mutex_unlock(&priv->mutex);
+ return -EAGAIN;
+ }
+ memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+ /* TODO: Audit driver for usage of these members and see
+ * if mac80211 deprecates them (priv->bssid looks like it
+ * shouldn't be there, but I haven't scanned the IBSS code
+ * to verify) - jpk */
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_config_ap(priv);
+ else {
+ priv->staging_rxon.filter_flags |=
+ RXON_FILTER_ASSOC_MSK;
+ rc = iwl_commit_rxon(priv);
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+ iwl_add_station(priv,
+ priv->active_rxon.bssid_addr, 1, 0);
+ }
+
+ } else {
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!conf->ssid_len)
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ else
+ memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+ priv->essid_len = conf->ssid_len;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ /*
+ * XXX: dummy
+ * see also iwl_connection_init_rx_config
+ */
+ *total_flags = 0;
+}
+
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ mutex_lock(&priv->mutex);
+ if (priv->interface_id == conf->if_id) {
+ priv->interface_id = 0;
+ memset(priv->bssid, 0, ETH_ALEN);
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ priv->essid_len = 0;
+ }
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!iwl_is_ready_rf(priv)) {
+ rc = -EIO;
+ IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+ goto out_unlock;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
+ rc = -EIO;
+ IWL_ERROR("ERROR: APs don't scan\n");
+ goto out_unlock;
+ }
+
+ /* if we just finished scan ask for delay */
+ if (priv->last_scan_jiffies &&
+ time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+ jiffies)) {
+ rc = -EAGAIN;
+ goto out_unlock;
+ }
+ if (len) {
+ IWL_DEBUG_SCAN("direct scan for "
+ "%s [%d]\n ",
+ iwl_escape_essid(ssid, len), (int)len);
+
+ priv->one_direct_scan = 1;
+ priv->direct_ssid_len = (u8)
+ min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+ memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+ }
+
+ rc = iwl_scan_initiate(priv);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_priv *priv = hw->priv;
+ int rc = 0;
+ u8 sta_id;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_param_hwcrypto) {
+ IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (is_zero_ether_addr(addr))
+ /* only support pairwise keys */
+ return -EOPNOTSUPP;
+
+ sta_id = iwl_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ switch (cmd) {
+ case SET_KEY:
+ rc = iwl_update_sta_key_info(priv, key, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 1);
+ iwl_commit_rxon(priv);
+ key->hw_key_idx = sta_id;
+ IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+ break;
+ case DISABLE_KEY:
+ rc = iwl_clear_sta_key_info(priv, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 0);
+ iwl_commit_rxon(priv);
+ IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct iwl_priv *priv = hw->priv;
+#ifdef CONFIG_IWLWIFI_QOS
+ unsigned long flags;
+ int q;
+#endif /* CONFIG_IWL_QOS */
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ if (queue >= AC_NUM) {
+ IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+ return 0;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (!priv->qos_data.qos_enable) {
+ priv->qos_data.qos_active = 0;
+ IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+ return 0;
+ }
+ q = AC_NUM - 1 - queue;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+ priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+ priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+ priv->qos_data.def_qos_parm.ac[q].edca_txop =
+ cpu_to_le16((params->burst_time * 100));
+
+ priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ priv->qos_data.qos_active = 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_activate_qos(priv, 1);
+ else if (priv->assoc_id && iwl_is_associated(priv))
+ iwl_activate_qos(priv, 0);
+
+ mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWLWIFI_QOS */
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct iwl_priv *priv = hw->priv;
+ int i, avail;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ unsigned long flags;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < AC_NUM; i++) {
+ txq = &priv->txq[i];
+ q = &txq->q;
+ avail = iwl_queue_space(q);
+
+ stats->data[i].len = q->n_window - avail;
+ stats->data[i].limit = q->n_window - q->high_mark;
+ stats->data[i].count = q->n_window;
+
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+ cancel_delayed_work(&priv->post_associate);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = 0;
+ priv->assoc_capability = 0;
+ priv->call_post_assoc_from_beacon = 0;
+
+ /* new association get rid of ibss beacon skb */
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = NULL;
+
+ priv->beacon_int = priv->hw->conf.beacon_int;
+ priv->timestamp1 = 0;
+ priv->timestamp0 = 0;
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ priv->beacon_int = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Per mac80211.h: This is only used in IBSS mode... */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ priv->only_active_channel = 0;
+
+ iwl_set_rate(priv);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ IWL_DEBUG_MAC80211("leave - not IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = skb;
+
+ priv->assoc_id = 0;
+
+ IWL_DEBUG_MAC80211("leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+
+ queue_work(priv->workqueue, &priv->post_associate.work);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 0);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ iwl_debug_level = val;
+
+ return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static ssize_t show_rf_kill(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ /*
+ * 0 - RF kill not enabled
+ * 1 - SW based RF kill active (sysfs)
+ * 2 - HW based RF kill active
+ * 3 - Both HW and SW based RF kill active
+ */
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
+ (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
+
+ return sprintf(buf, "%i\n", val);
+}
+
+static ssize_t store_rf_kill(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ mutex_lock(&priv->mutex);
+ iwl_radio_kill_sw(priv, buf[0] == '1');
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static ssize_t show_temperature(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iwl_priv *priv = d->driver_data;
+ return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in decimal form.\n", buf);
+ else
+ iwl_hw_reg_set_txpower(priv, val);
+
+ return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+ flags);
+ priv->staging_rxon.flags = cpu_to_le32(flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+ "0x%04X\n", filter_flags);
+ priv->staging_rxon.filter_flags =
+ cpu_to_le32(filter_flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+ store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ (priv->phymode << 8) |
+ le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u16 tune = simple_strtoul(p, &p, 0);
+ u8 phymode = (tune >> 8) & 0xff;
+ u16 channel = tune & 0xff;
+
+ IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+ mutex_lock(&priv->mutex);
+ if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+ (priv->phymode != phymode)) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+ if (!ch_info) {
+ IWL_WARNING("Requested invalid phymode/channel "
+ "combination: %d %d\n", phymode, channel);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing phymode and "
+ "rxon.channel = %d %d\n",
+ phymode, channel);
+
+ iwl_set_rxon_channel(priv, phymode, channel);
+ iwl_set_flags_for_phymode(priv, phymode);
+
+ iwl_set_rate(priv);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_spectrum_notification measure_report;
+ u32 size = sizeof(measure_report), len = 0, ofs = 0;
+ u8 *data = (u8 *) & measure_report;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!(priv->measurement_status & MEASUREMENT_READY)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+ }
+ memcpy(&measure_report, &priv->measure_report, size);
+ priv->measurement_status = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct ieee80211_measurement_params params = {
+ .channel = le16_to_cpu(priv->active_rxon.channel),
+ .start_time = cpu_to_le64(priv->last_tsf),
+ .duration = cpu_to_le16(1),
+ };
+ u8 type = IWL_MEASURE_BASIC;
+ u8 buffer[32];
+ u8 channel;
+
+ if (count) {
+ char *p = buffer;
+ strncpy(buffer, buf, min(sizeof(buffer), count));
+ channel = simple_strtoul(p, NULL, 0);
+ if (channel)
+ params.channel = channel;
+
+ p = buffer;
+ while (*p && *p != ' ')
+ p++;
+ if (*p)
+ type = simple_strtoul(p + 1, NULL, 0);
+ }
+
+ IWL_DEBUG_INFO("Invoking measurement of type %d on "
+ "channel %d (for '%s')\n", type, params.channel, buf);
+ iwl_get_measurement(priv, &params, type);
+
+ return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+ show_measurement, store_measurement);
+#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+
+static ssize_t show_rate(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+ i = priv->stations[IWL_AP_ID].current_rate.s.rate;
+ else
+ i = priv->stations[IWL_STA_ID].current_rate.s.rate;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ i = iwl_rate_index_from_plcp(i);
+ if (i == -1)
+ return sprintf(buf, "0\n");
+
+ return sprintf(buf, "%d%s\n",
+ (iwl_rates[i].ieee >> 1),
+ (iwl_rates[i].ieee & 0x1) ? ".5" : "");
+}
+
+static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
+
+static ssize_t store_retry_rate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ priv->retry_rate = simple_strtoul(buf, NULL, 0);
+ if (priv->retry_rate <= 0)
+ priv->retry_rate = 1;
+
+ return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+ store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int rc;
+ int mode;
+
+ mode = simple_strtoul(buf, NULL, 0);
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+ mode = IWL_POWER_AC;
+ else
+ mode |= IWL_POWER_ENABLED;
+
+ if (mode != priv->power_mode) {
+ rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+ if (rc) {
+ IWL_DEBUG_MAC80211("failed setting power mode.\n");
+ goto out;
+ }
+ priv->power_mode = mode;
+ }
+
+ rc = count;
+
+ out:
+ mutex_unlock(&priv->mutex);
+ return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+ 350000,
+ 250000,
+ 75000,
+ 37000,
+ 25000,
+};
+static const s32 period_duration[] = {
+ 400000,
+ 700000,
+ 1000000,
+ 1000000,
+ 1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int level = IWL_POWER_LEVEL(priv->power_mode);
+ char *p = buf;
+
+ p += sprintf(p, "%d ", level);
+ switch (level) {
+ case IWL_POWER_MODE_CAM:
+ case IWL_POWER_AC:
+ p += sprintf(p, "(AC)");
+ break;
+ case IWL_POWER_BATTERY:
+ p += sprintf(p, "(BATTERY)");
+ break;
+ default:
+ p += sprintf(p,
+ "(Timeout %dms, Period %dms)",
+ timeout_duration[level - 1] / 1000,
+ period_duration[level - 1] / 1000);
+ }
+
+ if (!(priv->power_mode & IWL_POWER_ENABLED))
+ p += sprintf(p, " OFF\n");
+ else
+ p += sprintf(p, " \n");
+
+ return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+ store_power_level);
+
+static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int len = 0, i;
+ struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode = NULL;
+ int count = 0;
+
+ if (!iwl_is_ready(priv))
+ return -EAGAIN;
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+ if (!hw_mode)
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ }
+
+ len +=
+ sprintf(&buf[len],
+ "Displaying %d channels in 2.4GHz band "
+ "(802.11bg):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ } else {
+ channels = NULL;
+ count = 0;
+ }
+
+ len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+ "(802.11a):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ u32 size = sizeof(struct iwl_notif_statistics);
+ u32 len = 0, ofs = 0;
+ u8 *data = (u8 *) & priv->statistics;
+ int rc = 0;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ mutex_lock(&priv->mutex);
+ rc = iwl_send_statistics_request(priv);
+ mutex_unlock(&priv->mutex);
+
+ if (rc) {
+ len = sprintf(buf,
+ "Error sending statistics request: 0x%08X\n", rc);
+ return len;
+ }
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ant;
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (count == 0)
+ return 0;
+
+ if (sscanf(buf, "%1i", &ant) != 1) {
+ IWL_DEBUG_INFO("not in hex or decimal form.\n");
+ return count;
+ }
+
+ if ((ant >= 0) && (ant <= 2)) {
+ IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+ priv->antenna = (enum iwl_antenna)ant;
+ } else
+ IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+ return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+ return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+ priv->workqueue = create_workqueue(DRV_NAME);
+
+ init_waitqueue_head(&priv->wait_command_queue);
+
+ INIT_WORK(&priv->up, iwl_bg_up);
+ INIT_WORK(&priv->restart, iwl_bg_restart);
+ INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+ INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+ INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+ INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+ INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+ INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+ INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
+ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+ INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
+ INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+ iwl_hw_setup_deferred_work(priv);
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+ iwl_hw_cancel_deferred_work(priv);
+
+ cancel_delayed_work(&priv->scan_check);
+ cancel_delayed_work(&priv->alive_start);
+ cancel_delayed_work(&priv->post_associate);
+ cancel_work_sync(&priv->beacon_update);
+}
+
+static struct attribute *iwl_sysfs_entries[] = {
+ &dev_attr_antenna.attr,
+ &dev_attr_channels.attr,
+ &dev_attr_dump_errors.attr,
+ &dev_attr_dump_events.attr,
+ &dev_attr_flags.attr,
+ &dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ &dev_attr_measurement.attr,
+#endif
+ &dev_attr_power_level.attr,
+ &dev_attr_rate.attr,
+ &dev_attr_retry_rate.attr,
+ &dev_attr_rf_kill.attr,
+ &dev_attr_rs_window.attr,
+ &dev_attr_statistics.attr,
+ &dev_attr_status.attr,
+ &dev_attr_temperature.attr,
+ &dev_attr_tune.attr,
+ &dev_attr_tx_power.attr,
+
+ NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwl_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl_hw_ops = {
+ .tx = iwl_mac_tx,
+ .start = iwl_mac_start,
+ .stop = iwl_mac_stop,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .config = iwl_mac_config,
+ .config_interface = iwl_mac_config_interface,
+ .configure_filter = iwl_configure_filter,
+ .set_key = iwl_mac_set_key,
+ .get_stats = iwl_mac_get_stats,
+ .get_tx_stats = iwl_mac_get_tx_stats,
+ .conf_tx = iwl_mac_conf_tx,
+ .get_tsf = iwl_mac_get_tsf,
+ .reset_tsf = iwl_mac_reset_tsf,
+ .beacon_update = iwl_mac_beacon_update,
+ .hw_scan = iwl_mac_hw_scan
+};
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = 0;
+ u32 pci_id;
+ struct iwl_priv *priv;
+ struct ieee80211_hw *hw;
+ int i;
+
+ if (iwl_param_disable_hw_scan) {
+ IWL_DEBUG_INFO("Disabling hw_scan\n");
+ iwl_hw_ops.hw_scan = NULL;
+ }
+
+ if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+ (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+ IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+ IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* mac80211 allocates memory for this device instance, including
+ * space for this driver's private structure */
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+ if (hw == NULL) {
+ IWL_ERROR("Can not allocate network device\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+
+ IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+ priv = hw->priv;
+ priv->hw = hw;
+
+ priv->pci_dev = pdev;
+ priv->antenna = (enum iwl_antenna)iwl_param_antenna;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ iwl_debug_level = iwl_param_debug;
+ atomic_set(&priv->restrict_refcnt, 0);
+#endif
+ priv->retry_rate = 1;
+
+ priv->ibss_beacon = NULL;
+
+ /* Tell mac80211 and its clients (e.g. Wireless Extensions)
+ * the range of signal quality values that we'll provide.
+ * Negative values for level/noise indicate that we'll provide dBm.
+ * For WE, at least, non-0 values here *enable* display of values
+ * in app (iwconfig). */
+ hw->max_rssi = -20; /* signal level, negative indicates dBm */
+ hw->max_noise = -20; /* noise level, negative indicates dBm */
+ hw->max_signal = 100; /* link quality indication (%) */
+
+ /* Tell mac80211 our Tx characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+ hw->queues = 4;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+
+ mutex_init(&priv->mutex);
+ if (pci_enable_device(pdev)) {
+ err = -ENODEV;
+ goto out_ieee80211_free_hw;
+ }
+
+ pci_set_master(pdev);
+
+ iwl_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->phymode = -1;
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+ goto out_pci_disable_device;
+ }
+
+ pci_set_drvdata(pdev, priv);
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto out_pci_disable_device;
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+ priv->hw_base = pci_iomap(pdev, 0, 0);
+ if (!priv->hw_base) {
+ err = -ENODEV;
+ goto out_pci_release_regions;
+ }
+
+ IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
+ IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+ /* Initialize module parameter values here */
+
+ if (iwl_param_disable) {
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ IWL_DEBUG_INFO("Radio disabled.\n");
+ }
+
+ priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+ pci_id =
+ (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device;
+
+ switch (pci_id) {
+ case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */
+ case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */
+ case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */
+ case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */
+ priv->is_abg = 0;
+ break;
+
+ /*
+ * Rest are assumed ABG SKU -- if this is not the
+ * case then the card will get the wrong 'Detected'
+ * line in the kernel log however the code that
+ * initializes the GEO table will detect no A-band
+ * channels and remove the is_abg mask.
+ */
+ default:
+ priv->is_abg = 1;
+ break;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n",
+ priv->is_abg ? "A" : "");
+
+ /* Device-specific setup */
+ if (iwl_hw_set_hw_setting(priv)) {
+ IWL_ERROR("failed to set hw settings\n");
+ mutex_unlock(&priv->mutex);
+ goto out_iounmap;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (iwl_param_qos_enable)
+ priv->qos_data.qos_enable = 1;
+
+ iwl_reset_qos(priv);
+
+ priv->qos_data.qos_active = 0;
+ priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWLWIFI_QOS */
+
+ iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+ iwl_setup_deferred_work(priv);
+ iwl_setup_rx_handlers(priv);
+
+ priv->rates_mask = IWL_RATES_MASK;
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IWL_POWER_AC;
+ priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+ pci_enable_msi(pdev);
+
+ err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
+ if (err) {
+ IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+ goto out_disable_msi;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+ if (err) {
+ IWL_ERROR("failed to create sysfs device attributes\n");
+ mutex_unlock(&priv->mutex);
+ goto out_release_irq;
+ }
+
+ /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+ * ucode filename and max sizes are card-specific. */
+ err = iwl_read_ucode(priv);
+ if (err) {
+ IWL_ERROR("Could not read microcode: %d\n", err);
+ mutex_unlock(&priv->mutex);
+ goto out_pci_alloc;
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_INFO("Queing UP work.\n");
+
+ queue_work(priv->workqueue, &priv->up);
+
+ return 0;
+
+ out_pci_alloc:
+ iwl_dealloc_ucode_pci(priv);
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ out_release_irq:
+ free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+ pci_disable_msi(pdev);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ iwl_unset_hw_setting(priv);
+
+ out_iounmap:
+ pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+ pci_release_regions(pdev);
+ out_pci_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+ ieee80211_free_hw(priv->hw);
+ out:
+ return err;
+}
+
+static void iwl_pci_remove(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct list_head *p, *q;
+ int i;
+
+ if (!priv)
+ return;
+
+ IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+ mutex_lock(&priv->mutex);
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+
+ /* Free MAC hash list for ADHOC */
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
+ list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+ list_del(p);
+ kfree(list_entry(p, struct iwl_ibss_seq, list));
+ }
+ }
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ iwl_dealloc_ucode_pci(priv);
+
+ if (priv->rxq.bd)
+ iwl_rx_queue_free(priv, &priv->rxq);
+ iwl_hw_txq_ctx_free(priv);
+
+ iwl_unset_hw_setting(priv);
+ iwl_clear_stations_table(priv);
+
+ if (priv->mac80211_registered) {
+ ieee80211_unregister_hw(priv->hw);
+ iwl_rate_control_unregister(priv->hw);
+ }
+
+ /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+ * priv->workqueue... so we can't take down the workqueue
+ * until now... */
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+
+ free_irq(pdev->irq, priv);
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, priv->hw_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(priv->channel_info);
+
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+ /* Take down the device; powers it off, etc. */
+ __iwl_down(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_resume(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ /* The following it a temporary work around due to the
+ * suspend / resume not fully initializing the NIC correctly.
+ * Without all of the following, resume will not attempt to take
+ * down the NIC (it shouldn't really need to) and will just try
+ * and bring the NIC back up. However that fails during the
+ * ucode verification process. This then causes iwl_down to be
+ * called *after* iwl_hw_nic_init() has succeeded -- which
+ * then lets the next init sequence succeed. So, we've
+ * replicated all of that NIC init code here... */
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ iwl_hw_nic_init(priv);
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_reset(priv);
+
+ /* Bring the device back up */
+ clear_bit(STATUS_IN_SUSPEND, &priv->status);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl_pci_resume(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ int err;
+
+ printk(KERN_INFO "Coming out of suspend...\n");
+
+ mutex_lock(&priv->mutex);
+
+ pci_set_power_state(pdev, PCI_D0);
+ err = pci_enable_device(pdev);
+ pci_restore_state(pdev);
+
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+
+ iwl_resume(priv);
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl_driver = {
+ .name = DRV_NAME,
+ .id_table = iwl_hw_card_ids,
+ .probe = iwl_pci_probe,
+ .remove = __devexit_p(iwl_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
+#endif
+};
+
+static int __init iwl_init(void)
+{
+
+ int ret;
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ ret = pci_register_driver(&iwl_driver);
+ if (ret) {
+ IWL_ERROR("Unable to initialize PCI module\n");
+ return ret;
+ }
+#ifdef CONFIG_IWLWIFI_DEBUG
+ ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+ if (ret) {
+ IWL_ERROR("Unable to create driver sysfs file\n");
+ pci_unregister_driver(&iwl_driver);
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static void __exit iwl_exit(void)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#endif
+ pci_unregister_driver(&iwl_driver);
+}
+
+module_param_named(antenna, iwl_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+ "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
new file mode 100644
index 000000000000..b1a6e39f7821
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -0,0 +1,9340 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets
+ * by defining IWL to either 3945 or 4965. The Makefile used when building
+ * the base targets will create base-3945.o and base-4965.o
+ *
+ * The eventual goal is to move as many of the #if IWL / #endif blocks out of
+ * this file and into the hardware specific implementation files (iwl-XXXX.c)
+ * and leave only the common (non #ifdef sprinkled) code in this file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#define IWL 4965
+
+#include "iwlwifi.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+u32 iwl_debug_level;
+#endif
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+int iwl_param_disable_hw_scan;
+int iwl_param_debug;
+int iwl_param_disable; /* def: enable radio */
+int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */
+int iwl_param_hwcrypto; /* def: using software encryption */
+int iwl_param_qos_enable = 1;
+int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ int hdr_len = ieee80211_get_hdrlen(fc);
+
+ if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+ return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+ return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl_get_hw_mode(
+ struct iwl_priv *priv, int mode)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (priv->modes[i].mode == mode)
+ return &priv->modes[i];
+
+ return NULL;
+}
+
+static int iwl_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+static const char *iwl_escape_essid(const char *essid, u8 essid_len)
+{
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (iwl_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return escaped;
+}
+
+static void iwl_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (!(iwl_debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IWL operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ ***************************************************/
+
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+ int s = q->last_used - q->first_empty;
+
+ if (q->last_used > q->first_empty)
+ s -= q->n_bd;
+
+ if (s <= 0)
+ s += q->n_window;
+ /* keep some reserve to not confuse empty and full situations */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+ return ++index & (n_bd - 1);
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl_queue *q, int i)
+{
+ return q->first_empty > q->last_used ?
+ (i >= q->last_used && i < q->first_empty) :
+ !(i < q->last_used && i >= q->first_empty);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+ if (is_huge)
+ return q->n_window;
+
+ return index & (q->n_window - 1);
+}
+
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+ int count, int slots_num, u32 id)
+{
+ q->n_bd = count;
+ q->n_window = slots_num;
+ q->id = id;
+
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
+ BUG_ON(!is_power_of_2(count));
+
+ /* slots_num must be power-of-two size, otherwise
+ * get_cmd_index is broken. */
+ BUG_ON(!is_power_of_2(slots_num));
+
+ q->low_mark = q->n_window / 4;
+ if (q->low_mark < 4)
+ q->low_mark = 4;
+
+ q->high_mark = q->n_window / 8;
+ if (q->high_mark < 2)
+ q->high_mark = 2;
+
+ q->first_empty = q->last_used = 0;
+
+ return 0;
+}
+
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u32 id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+
+ if (id != IWL_CMD_QUEUE_NUM) {
+ txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+ if (!txq->txb) {
+ IWL_ERROR("kmalloc for auxilary BD "
+ "structures failed\n");
+ goto error;
+ }
+ } else
+ txq->txb = NULL;
+
+ txq->bd = pci_alloc_consistent(dev,
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+ &txq->q.dma_addr);
+
+ if (!txq->bd) {
+ IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+ goto error;
+ }
+ txq->q.id = id;
+
+ return 0;
+
+ error:
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+ int rc = 0;
+
+ /* alocate command space + one big command for scan since scan
+ * command is very huge the system will not have two scan at the
+ * same time */
+ len = sizeof(struct iwl_cmd) * slots_num;
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+ txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+ if (!txq->cmd)
+ return -ENOMEM;
+
+ rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (rc) {
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ return -ENOMEM;
+ }
+ txq->need_update = 0;
+
+ /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+ iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+ iwl_hw_tx_queue_init(priv, txq);
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers. txq itself is not freed.
+ *
+ */
+void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+
+ if (q->n_bd == 0)
+ return;
+
+ /* first, empty all BD's */
+ for (; q->first_empty != q->last_used;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
+ iwl_hw_txq_free_tfd(priv, txq);
+
+ len = sizeof(struct iwl_cmd) * q->n_window;
+ if (q->id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ /* free buffers belonging to queue itself */
+ if (txq->q.n_bd)
+ pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+ txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ /* 0 fill whole structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ *
+ * NOTE: This needs to be overhauled to better synchronize between
+ * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
+ *
+ * mac80211 should also be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+
+#if 0 /* temparary disable till we add real remove station */
+static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int index = IWL_INVALID_STATION;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ if (priv->stations[i].used &&
+ !compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (unlikely(index == IWL_INVALID_STATION))
+ goto out;
+
+ if (priv->stations[index].used) {
+ priv->stations[index].used = 0;
+ priv->num_stations--;
+ }
+
+ BUG_ON(priv->num_stations < 0);
+
+out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+}
+#endif
+
+static void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->num_stations = 0;
+ memset(priv->stations, 0, sizeof(priv->stations));
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+ int i;
+ int index = IWL_INVALID_STATION;
+ struct iwl_station_entry *station;
+ unsigned long flags_spin;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+ if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (!priv->stations[i].used &&
+ index == IWL_INVALID_STATION)
+ index = i;
+ }
+
+
+ /* These twh conditions has the same outcome but keep them separate
+ since they have different meaning */
+ if (unlikely(index == IWL_INVALID_STATION)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ if (priv->stations[index].used &&
+ !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+
+ IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+ station = &priv->stations[index];
+ station->used = 1;
+ priv->num_stations++;
+
+ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+ memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+ station->sta.mode = 0;
+ station->sta.sta.sta_id = index;
+ station->sta.station_flags = 0;
+
+#ifdef CONFIG_IWLWIFI_HT
+ /* BCAST station and IBSS stations do not work in HT mode */
+ if (index != priv->hw_setting.bcast_sta_id &&
+ priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+ iwl4965_set_ht_add_station(priv, index);
+#endif /*CONFIG_IWLWIFI_HT*/
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ iwl_send_add_station(priv, &station->sta, flags);
+ return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS *****/
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+ /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+ * set but EXIT_PENDING is not */
+ return test_bit(STATUS_READY, &priv->status) &&
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+ !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_init(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+
+ if (iwl_is_rfkill(priv))
+ return 0;
+
+ return iwl_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ IWL_CMD(REPLY_ALIVE);
+ IWL_CMD(REPLY_ERROR);
+ IWL_CMD(REPLY_RXON);
+ IWL_CMD(REPLY_RXON_ASSOC);
+ IWL_CMD(REPLY_QOS_PARAM);
+ IWL_CMD(REPLY_RXON_TIMING);
+ IWL_CMD(REPLY_ADD_STA);
+ IWL_CMD(REPLY_REMOVE_STA);
+ IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_TX);
+ IWL_CMD(REPLY_RATE_SCALE);
+ IWL_CMD(REPLY_LEDS_CMD);
+ IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+ IWL_CMD(RADAR_NOTIFICATION);
+ IWL_CMD(REPLY_QUIET_CMD);
+ IWL_CMD(REPLY_CHANNEL_SWITCH);
+ IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+ IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+ IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+ IWL_CMD(POWER_TABLE_CMD);
+ IWL_CMD(PM_SLEEP_NOTIFICATION);
+ IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+ IWL_CMD(REPLY_SCAN_CMD);
+ IWL_CMD(REPLY_SCAN_ABORT_CMD);
+ IWL_CMD(SCAN_START_NOTIFICATION);
+ IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+ IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+ IWL_CMD(BEACON_NOTIFICATION);
+ IWL_CMD(REPLY_TX_BEACON);
+ IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+ IWL_CMD(QUIET_NOTIFICATION);
+ IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+ IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+ IWL_CMD(REPLY_BT_CONFIG);
+ IWL_CMD(REPLY_STATISTICS_CMD);
+ IWL_CMD(STATISTICS_NOTIFICATION);
+ IWL_CMD(REPLY_CARD_STATE_CMD);
+ IWL_CMD(CARD_STATE_NOTIFICATION);
+ IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+ IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
+ IWL_CMD(SENSITIVITY_CMD);
+ IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
+ IWL_CMD(REPLY_RX_PHY_CMD);
+ IWL_CMD(REPLY_RX_MPDU_CMD);
+ IWL_CMD(REPLY_4965_RX);
+ IWL_CMD(REPLY_COMPRESSED_BA);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_queue *q = &txq->q;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ struct iwl_cmd *out_cmd;
+ u32 idx;
+ u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+ dma_addr_t phys_addr;
+ int ret;
+ unsigned long flags;
+
+ /* If any of the command structures end up being larger than
+ * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+ * we will need to increase the size of the TFD entries */
+ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+ !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ IWL_ERROR("No space for Tx\n");
+ return -ENOSPC;
+ }
+
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+
+ control_flags = (u32 *) tfd;
+
+ idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+ out_cmd = &txq->cmd[idx];
+
+ out_cmd->hdr.cmd = cmd->id;
+ memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+ memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+ /* At this point, the out_cmd now has all of the incoming cmd
+ * information */
+
+ out_cmd->hdr.flags = 0;
+ out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+ INDEX_TO_SEQ(q->first_empty));
+ if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+ phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+ offsetof(struct iwl_cmd, hdr);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+ IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+ "%d bytes at %d[%d]:%d\n",
+ get_cmd_string(out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+ fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+
+ txq->need_update = 1;
+ ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ iwl_tx_queue_update_write_ptr(priv, txq);
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return ret ? ret : idx;
+}
+
+int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int ret;
+
+ BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+ /* An asynchronous command can not expect an SKB to be set. */
+ BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+ /* An asynchronous command MUST have a callback. */
+ BUG_ON(!cmd->meta.u.callback);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EBUSY;
+
+ ret = iwl_enqueue_hcmd(priv, cmd);
+ if (ret < 0) {
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ return ret;
+ }
+ return 0;
+}
+
+int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int cmd_idx;
+ int ret;
+ static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+ BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+ /* A synchronous command can not have a callback set. */
+ BUG_ON(cmd->meta.u.callback != NULL);
+
+ if (atomic_xchg(&entry, 1)) {
+ IWL_ERROR("Error sending %s: Already sending a host command\n",
+ get_cmd_string(cmd->id));
+ return -EBUSY;
+ }
+
+ set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+ if (cmd->meta.flags & CMD_WANT_SKB)
+ cmd->meta.source = &cmd->meta;
+
+ cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+ if (cmd_idx < 0) {
+ ret = cmd_idx;
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ goto out;
+ }
+
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+ HOST_COMPLETE_TIMEOUT);
+ if (!ret) {
+ if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+ IWL_ERROR("Error sending %s: time out after %dms.\n",
+ get_cmd_string(cmd->id),
+ jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ ret = -ETIMEDOUT;
+ goto cancel;
+ }
+ }
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+ get_cmd_string(cmd->id));
+ ret = -ECANCELED;
+ goto fail;
+ }
+ if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto fail;
+ }
+ if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+ IWL_ERROR("Error: Response NULL in '%s'\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ goto out;
+
+cancel:
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ struct iwl_cmd *qcmd;
+
+ /* Cancel the CMD_WANT_SKB flag for the cmd in the
+ * TX cmd queue. Otherwise in case the cmd comes
+ * in later, it will possibly set an invalid
+ * address (cmd->meta.source). */
+ qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+ qcmd->meta.flags &= ~CMD_WANT_SKB;
+ }
+fail:
+ if (cmd->meta.u.skb) {
+ dev_kfree_skb_any(cmd->meta.u.skb);
+ cmd->meta.u.skb = NULL;
+ }
+out:
+ atomic_set(&entry, 0);
+ return ret;
+}
+
+int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ /* A command can not be asynchronous AND expect an SKB to be set. */
+ BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
+ (cmd->meta.flags & CMD_WANT_SKB));
+
+ if (cmd->meta.flags & CMD_ASYNC)
+ return iwl_send_cmd_async(priv, cmd);
+
+ return iwl_send_cmd_sync(priv, cmd);
+}
+
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = len,
+ .data = data,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = sizeof(val),
+ .data = &val,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv)
+{
+ return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl_rxon_add_station - add station into station table.
+ *
+ * there is only one AP station with id= IWL_AP_ID
+ * NOTE: mutex must be held before calling the this fnction
+*/
+static int iwl_rxon_add_station(struct iwl_priv *priv,
+ const u8 *addr, int is_ap)
+{
+ u8 sta_id;
+
+ sta_id = iwl_add_station(priv, addr, is_ap, 0);
+ iwl4965_add_station(priv, addr, is_ap);
+
+ return sta_id;
+}
+
+/**
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE: Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+ if (!iwl_get_channel_info(priv, phymode, channel)) {
+ IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+ channel, phymode);
+ return -EINVAL;
+ }
+
+ if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+ (priv->phymode == phymode))
+ return 0;
+
+ priv->staging_rxon.channel = cpu_to_le16(channel);
+ if (phymode == MODE_IEEE80211A)
+ priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+ priv->phymode = phymode;
+
+ IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+ return 0;
+}
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE: This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+ int error = 0;
+ int counter = 1;
+
+ if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+ error |= le32_to_cpu(rxon->flags &
+ (RXON_FLG_TGJ_NARROW_BAND_MSK |
+ RXON_FLG_RADAR_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check 24G fields %d | %d\n",
+ counter++, error);
+ } else {
+ error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+ 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+ if (error)
+ IWL_WARNING("check 52 fields %d | %d\n",
+ counter++, error);
+ error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+ if (error)
+ IWL_WARNING("check 52 CCK %d | %d\n",
+ counter++, error);
+ }
+ error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+ if (error)
+ IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+ /* make sure basic rates 6Mbps and 1Mbps are supported */
+ error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+ ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+ if (error)
+ IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+ error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+ if (error)
+ IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+ if (error)
+ IWL_WARNING("check CCK and short slot %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check CCK & auto detect %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+ RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+ if (error)
+ IWL_WARNING("check TGG and auto detect %d | %d\n",
+ counter++, error);
+
+ if (error)
+ IWL_WARNING("Tuning to channel %d\n",
+ le16_to_cpu(rxon->channel));
+
+ if (error) {
+ IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * @priv: staging_rxon is comapred to active_rxon
+ *
+ * If the RXON structure is changing sufficient to require a new
+ * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
+ * to indicate a new tune is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv)
+{
+
+ /* These items are only settable from the full RXON command */
+ if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+ compare_ether_addr(priv->staging_rxon.bssid_addr,
+ priv->active_rxon.bssid_addr) ||
+ compare_ether_addr(priv->staging_rxon.node_addr,
+ priv->active_rxon.node_addr) ||
+ compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+ priv->active_rxon.wlap_bssid_addr) ||
+ (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+ (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+ (priv->staging_rxon.air_propagation !=
+ priv->active_rxon.air_propagation) ||
+ (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
+ priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
+ (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
+ priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
+ (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
+ (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+ return 1;
+
+ /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+ * be updated with the RXON_ASSOC command -- however only some
+ * flag transitions are allowed using RXON_ASSOC */
+
+ /* Check if we are not switching bands */
+ if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+ (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+ return 1;
+
+ /* Check if we are switching association toggle */
+ if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+ (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+ return 1;
+
+ return 0;
+}
+
+static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res = NULL;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_RXON_ASSOC,
+ .len = sizeof(rxon_assoc),
+ .meta.flags = CMD_WANT_SKB,
+ .data = &rxon_assoc,
+ };
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_ht_single_stream_basic_rates ==
+ rxon2->ofdm_ht_single_stream_basic_rates) &&
+ (rxon1->ofdm_ht_dual_stream_basic_rates ==
+ rxon2->ofdm_ht_dual_stream_basic_rates) &&
+ (rxon1->rx_chain == rxon2->rx_chain) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved = 0;
+ rxon_assoc.ofdm_ht_single_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+ rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+/**
+ * iwl_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is commited to the hardware and
+ * the active_rxon structure is updated with the new data. This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl_commit_rxon(struct iwl_priv *priv)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ DECLARE_MAC_BUF(mac);
+ int rc = 0;
+
+ if (!iwl_is_alive(priv))
+ return -1;
+
+ /* always get timestamp with Rx frame */
+ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+ rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /* If we don't need to send a full RXON, we can use
+ * iwl_rxon_assoc_cmd which is used to reconfigure filter
+ * and other flags for the current radio configuration. */
+ if (!iwl_full_rxon_required(priv)) {
+ rc = iwl_send_rxon_assoc(priv);
+ if (rc) {
+ IWL_ERROR("Error setting RXON_ASSOC "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ return 0;
+ }
+
+ /* station table will be cleared */
+ priv->assoc_station_added = 0;
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+ if (!priv->error_recovering)
+ priv->start_calib = 0;
+
+ iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+ /* If we are currently associated and the new config requires
+ * an RXON_ASSOC and the new config wants the associated mask enabled,
+ * we must clear the associated from the active configuration
+ * before we apply the new config */
+ if (iwl_is_associated(priv) &&
+ (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+ IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd),
+ &priv->active_rxon);
+
+ /* If the mask clearing failed then we set
+ * active_rxon back to what it was previously */
+ if (rc) {
+ active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+ IWL_ERROR("Error clearing ASSOC_MSK on current "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+ }
+
+ IWL_DEBUG_INFO("Sending RXON\n"
+ "* with%s RXON_FILTER_ASSOC_MSK\n"
+ "* channel = %d\n"
+ "* bssid = %s\n",
+ ((priv->staging_rxon.filter_flags &
+ RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+ le16_to_cpu(priv->staging_rxon.channel),
+ print_mac(mac, priv->staging_rxon.bssid_addr));
+
+ /* Apply the new configuration */
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Error setting new configuration (%d).\n", rc);
+ return rc;
+ }
+
+ iwl_clear_stations_table(priv);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ if (!priv->error_recovering)
+ priv->start_calib = 0;
+
+ priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+ iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ /* If we issue a new RXON command which required a tune then we must
+ * send a new TXPOWER command or we won't be able to Tx any frames */
+ rc = iwl_hw_reg_send_txpower(priv);
+ if (rc) {
+ IWL_ERROR("Error setting Tx power (%d).\n", rc);
+ return rc;
+ }
+
+ /* Add the broadcast address so we can send broadcast frames */
+ if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) ==
+ IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+ return -EIO;
+ }
+
+ /* If we have set the ASSOC_MSK and we are in BSS mode then
+ * add the IWL_AP_ID to the station rate table */
+ if (iwl_is_associated(priv) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+ if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+ == IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding AP address for transmit.\n");
+ return -EIO;
+ }
+ priv->assoc_station_added = 1;
+ }
+
+ return 0;
+}
+
+static int iwl_send_bt_config(struct iwl_priv *priv)
+{
+ struct iwl_bt_cmd bt_cmd = {
+ .flags = 3,
+ .lead_time = 0xAA,
+ .max_kill = 1,
+ .kill_ack_mask = 0,
+ .kill_cts_mask = 0,
+ };
+
+ return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+ sizeof(struct iwl_bt_cmd), &bt_cmd);
+}
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_ABORT_CMD,
+ .meta.flags = CMD_WANT_SKB,
+ };
+
+ /* If there isn't a scan actively going on in the hardware
+ * then we are in between scan bands and not actually
+ * actively scanning, so don't send the abort command */
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return 0;
+ }
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return rc;
+ }
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->u.status != CAN_ABORT_STATUS) {
+ /* The scan abort will return 1 for success or
+ * 2 for "failure". A failure condition can be
+ * due to simply not being in an active scan which
+ * can occur if we send the scan abort before we
+ * the microcode has notified us that a scan is
+ * completed. */
+ IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_card_state_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb)
+{
+ return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_CARD_STATE_CMD,
+ .len = sizeof(u32),
+ .data = &flags,
+ .meta.flags = meta_flag,
+ };
+
+ if (meta_flag & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_card_state_sync_callback;
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ struct iwl_rx_packet *res = NULL;
+
+ if (!skb) {
+ IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+ return 1;
+ }
+
+ res = (struct iwl_rx_packet *)skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ return 1;
+ }
+
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ break;
+ default:
+ break;
+ }
+
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+int iwl_send_add_station(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags)
+{
+ struct iwl_rx_packet *res = NULL;
+ int rc = 0;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ADD_STA,
+ .len = sizeof(struct iwl_addsta_cmd),
+ .meta.flags = flags,
+ .data = sta,
+ };
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_add_sta_sync_callback;
+ else
+ cmd.meta.flags |= CMD_WANT_SKB;
+
+ rc = iwl_send_cmd(priv, &cmd);
+
+ if (rc || (flags & CMD_ASYNC))
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ rc = -EIO;
+ }
+
+ if (rc == 0) {
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+ break;
+ default:
+ rc = -EIO;
+ IWL_WARNING("REPLY_ADD_STA failed\n");
+ break;
+ }
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_update_sta_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+
+ switch (keyconf->alg) {
+ case ALG_CCMP:
+ key_flags |= STA_KEY_FLG_CCMP;
+ key_flags |= cpu_to_le16(
+ keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+ break;
+ case ALG_TKIP:
+ case ALG_WEP:
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+ keyconf->keylen);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+ keyconf->keylen);
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+ memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+ priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static void iwl_clear_free_frames(struct iwl_priv *priv)
+{
+ struct list_head *element;
+
+ IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+ priv->frames_count);
+
+ while (!list_empty(&priv->free_frames)) {
+ element = priv->free_frames.next;
+ list_del(element);
+ kfree(list_entry(element, struct iwl_frame, list));
+ priv->frames_count--;
+ }
+
+ if (priv->frames_count) {
+ IWL_WARNING("%d frames still in use. Did we lose one?\n",
+ priv->frames_count);
+ priv->frames_count = 0;
+ }
+}
+
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ struct list_head *element;
+ if (list_empty(&priv->free_frames)) {
+ frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+ if (!frame) {
+ IWL_ERROR("Could not allocate frame!\n");
+ return NULL;
+ }
+
+ priv->frames_count++;
+ return frame;
+ }
+
+ element = priv->free_frames.next;
+ list_del(element);
+ return list_entry(element, struct iwl_frame, list);
+}
+
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+ list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left)
+{
+
+ if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+ ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+ return 0;
+
+ if (priv->ibss_beacon->len > left)
+ return 0;
+
+ memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+ return priv->ibss_beacon->len;
+}
+
+int iwl_rate_index_from_plcp(int plcp)
+{
+ int i = 0;
+
+ if (plcp & RATE_MCS_HT_MSK) {
+ i = (plcp & 0xff);
+
+ if (i >= IWL_RATE_MIMO_6M_PLCP)
+ i = i - IWL_RATE_MIMO_6M_PLCP;
+
+ i += IWL_FIRST_OFDM_RATE;
+ /* skip 9M not supported in ht*/
+ if (i >= IWL_RATE_9M_INDEX)
+ i += 1;
+ if ((i >= IWL_FIRST_OFDM_RATE) &&
+ (i <= IWL_LAST_OFDM_RATE))
+ return i;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(iwl_rates); i++)
+ if (iwl_rates[i].plcp == (plcp &0xFF))
+ return i;
+ }
+ return -1;
+}
+
+static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+{
+ u8 i;
+
+ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+ i = iwl_rates[i].next_ieee) {
+ if (rate_mask & (1 << i))
+ return iwl_rates[i].plcp;
+ }
+
+ return IWL_RATE_INVALID;
+}
+
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ unsigned int frame_size;
+ int rc;
+ u8 rate;
+
+ frame = iwl_get_free_frame(priv);
+
+ if (!frame) {
+ IWL_ERROR("Could not obtain free frame buffer for beacon "
+ "command.\n");
+ return -ENOMEM;
+ }
+
+ if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+ 0xFF0);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_6M_PLCP;
+ } else {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_1M_PLCP;
+ }
+
+ frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+ &frame->u.cmd[0]);
+
+ iwl_free_frame(priv, frame);
+
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+{
+ memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM from adapter into priv->eeprom
+ *
+ * NOTE: This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl_priv *priv)
+{
+ u16 *e = (u16 *)&priv->eeprom;
+ u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+ u32 r;
+ int sz = sizeof(priv->eeprom);
+ int rc;
+ int i;
+ u16 addr;
+
+ /* The EEPROM structure has several padding buffers within it
+ * and when adding new EEPROM maps is subject to programmer errors
+ * which may be very difficult to identify without explicitly
+ * checking the resulting size of the eeprom map. */
+ BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+ if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ return -ENOENT;
+ }
+
+ rc = iwl_eeprom_aqcuire_semaphore(priv);
+ if (rc < 0) {
+ IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+ return -ENOENT;
+ }
+
+ /* eeprom is an array of 16bit values */
+ for (addr = 0; addr < sz; addr += sizeof(u16)) {
+ _iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
+ _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+ for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+ i += IWL_EEPROM_ACCESS_DELAY) {
+ r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+ if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+ break;
+ udelay(IWL_EEPROM_ACCESS_DELAY);
+ }
+
+ if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ rc = -ETIMEDOUT;
+ goto done;
+ }
+ e[addr / 2] = le16_to_cpu(r >> 16);
+ }
+ rc = 0;
+
+done:
+ iwl_eeprom_release_semaphore(priv);
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/**
+ * iwl_report_frame - dump frame to syslog during debug sessions
+ *
+ * hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type
+ * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
+ * is 3945-specific and gives bad output for 4965. Need to split the
+ * functionality, keep common stuff here.
+ */
+void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+ u32 to_us;
+ u32 print_summary = 0;
+ u32 print_dump = 0; /* set to 1 to dump all frames' contents */
+ u32 hundred = 0;
+ u32 dataframe = 0;
+ u16 fc;
+ u16 seq_ctl;
+ u16 channel;
+ u16 phy_flags;
+ int rate_sym;
+ u16 length;
+ u16 status;
+ u16 bcn_tmr;
+ u32 tsf_low;
+ u64 tsf;
+ u8 rssi;
+ u8 agc;
+ u16 sig_avg;
+ u16 noise_diff;
+ struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ u8 *data = IWL_RX_DATA(pkt);
+
+ /* MAC header */
+ fc = le16_to_cpu(header->frame_control);
+ seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+ /* metadata */
+ channel = le16_to_cpu(rx_hdr->channel);
+ phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ rate_sym = rx_hdr->rate;
+ length = le16_to_cpu(rx_hdr->len);
+
+ /* end-of-frame status and timestamp */
+ status = le32_to_cpu(rx_end->status);
+ bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+ tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+ tsf = le64_to_cpu(rx_end->timestamp);
+
+ /* signal statistics */
+ rssi = rx_stats->rssi;
+ agc = rx_stats->agc;
+ sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+ to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+ /* if data frame is to us and all is good,
+ * (optionally) print summary for only 1 out of every 100 */
+ if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+ dataframe = 1;
+ if (!group100)
+ print_summary = 1; /* print each frame */
+ else if (priv->framecnt_to_us < 100) {
+ priv->framecnt_to_us++;
+ print_summary = 0;
+ } else {
+ priv->framecnt_to_us = 0;
+ print_summary = 1;
+ hundred = 1;
+ }
+ } else {
+ /* print summary for all other frames */
+ print_summary = 1;
+ }
+
+ if (print_summary) {
+ char *title;
+ u32 rate;
+
+ if (hundred)
+ title = "100Frames";
+ else if (fc & IEEE80211_FCTL_RETRY)
+ title = "Retry";
+ else if (ieee80211_is_assoc_response(fc))
+ title = "AscRsp";
+ else if (ieee80211_is_reassoc_response(fc))
+ title = "RasRsp";
+ else if (ieee80211_is_probe_response(fc)) {
+ title = "PrbRsp";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_beacon(fc)) {
+ title = "Beacon";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_atim(fc))
+ title = "ATIM";
+ else if (ieee80211_is_auth(fc))
+ title = "Auth";
+ else if (ieee80211_is_deauth(fc))
+ title = "DeAuth";
+ else if (ieee80211_is_disassoc(fc))
+ title = "DisAssoc";
+ else
+ title = "Frame";
+
+ rate = iwl_rate_index_from_plcp(rate_sym);
+ if (rate == -1)
+ rate = 0;
+ else
+ rate = iwl_rates[rate].ieee / 2;
+
+ /* print frame summary.
+ * MAC addresses show just the last byte (for brevity),
+ * but you can hack it to show more, if you'd like to. */
+ if (dataframe)
+ IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+ "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ title, fc, header->addr1[5],
+ length, rssi, channel, rate);
+ else {
+ /* src/dst addresses assume managed mode */
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+ "src=0x%02x, rssi=%u, tim=%lu usec, "
+ "phy=0x%02x, chnl=%d\n",
+ title, fc, header->addr1[5],
+ header->addr3[5], rssi,
+ tsf_low - priv->scan_start_tsf,
+ phy_flags, channel);
+ }
+ }
+ if (print_dump)
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl_unset_hw_setting(struct iwl_priv *priv)
+{
+ if (priv->hw_setting.shared_virt)
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ priv->hw_setting.shared_virt,
+ priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+ u16 basic_rate, int max_count)
+{
+ u16 ret_rates = 0, bit;
+ int i;
+ u8 *rates;
+
+ rates = &(ie[1]);
+
+ for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+ if (bit & supported_rate) {
+ ret_rates |= bit;
+ rates[*ie] = iwl_rates[i].ieee |
+ ((bit & basic_rate) ? 0x80 : 0x00);
+ *ie = *ie + 1;
+ if (*ie >= max_count)
+ break;
+ }
+ }
+
+ return ret_rates;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+void static iwl_set_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap,
+ u8 use_wide_chan);
+#endif
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+ struct ieee80211_mgmt *frame,
+ int left, int is_direct)
+{
+ int len = 0;
+ u8 *pos = NULL;
+ u16 ret_rates;
+
+ /* Make sure there is enough space for the probe request,
+ * two mandatory IEs and the data */
+ left -= 24;
+ if (left < 0)
+ return 0;
+ len += 24;
+
+ frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+ memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+ memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+ frame->seq_ctrl = 0;
+
+ /* fill in our indirect SSID IE */
+ /* ...next IE... */
+
+ left -= 2;
+ if (left < 0)
+ return 0;
+ len += 2;
+ pos = &(frame->u.probe_req.variable[0]);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0;
+
+ /* fill in our direct SSID IE... */
+ if (is_direct) {
+ /* ...next IE... */
+ left -= 2 + priv->essid_len;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = priv->essid_len;
+ memcpy(pos, priv->essid, priv->essid_len);
+ pos += priv->essid_len;
+ len += 2 + priv->essid_len;
+ }
+
+ /* fill in supported rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos = 0;
+ ret_rates = priv->active_rate = priv->rates_mask;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ iwl_supported_rate_to_ie(pos, priv->active_rate,
+ priv->active_rate_basic, left);
+ len += 2 + *pos;
+ pos += (*pos) + 1;
+ ret_rates = ~ret_rates & priv->active_rate;
+
+ if (ret_rates == 0)
+ goto fill_end;
+
+ /* fill in supported extended rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos = 0;
+ iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left);
+ if (*pos > 0)
+ len += 2 + *pos;
+
+#ifdef CONFIG_IWLWIFI_HT
+ if (is_direct && priv->is_ht_enabled) {
+ u8 use_wide_chan = 1;
+
+ if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+ use_wide_chan = 0;
+ pos += (*pos) + 1;
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_capability);
+ iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos,
+ use_wide_chan);
+ len += 2 + sizeof(struct ieee80211_ht_capability);
+ }
+#endif /*CONFIG_IWLWIFI_HT */
+
+ fill_end:
+ return (u16)len;
+}
+
+/*
+ * QoS support
+*/
+#ifdef CONFIG_IWLWIFI_QOS
+static int iwl_send_qos_params_command(struct iwl_priv *priv,
+ struct iwl_qosparam_cmd *qos)
+{
+
+ return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+ sizeof(struct iwl_qosparam_cmd), qos);
+}
+
+static void iwl_reset_qos(struct iwl_priv *priv)
+{
+ u16 cw_min = 15;
+ u16 cw_max = 1023;
+ u8 aifs = 2;
+ u8 is_legacy = 0;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.qos_active = 0;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ if (!(priv->active_rate & 0xfff0)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+ } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+
+ if (priv->qos_data.qos_active)
+ aifs = 3;
+
+ priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+ if (priv->qos_data.qos_active) {
+ i = 1;
+ priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 2;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(6016);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3008);
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 3;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 4 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16((cw_max + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3264);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(1504);
+ } else {
+ for (i = 1; i < 4; i++) {
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ }
+ }
+ IWL_DEBUG_QOS("set QoS to default \n");
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+ unsigned long flags;
+
+ if (priv == NULL)
+ return;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!priv->qos_data.qos_enable)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.def_qos_parm.qos_flags = 0;
+
+ if (priv->qos_data.qos_cap.q_AP.queue_request &&
+ !priv->qos_data.qos_cap.q_AP.txop_request)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+ if (priv->qos_data.qos_active)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (force || iwl_is_associated(priv)) {
+ IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+ priv->qos_data.qos_active);
+
+ iwl_send_qos_params_command(priv,
+ &(priv->qos_data.def_qos_parm));
+ }
+}
+
+#endif /* CONFIG_IWLWIFI_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+ __constant_cpu_to_le32(X1), \
+ __constant_cpu_to_le32(X2), \
+ __constant_cpu_to_le32(X3), \
+ __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim 0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+ SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+ SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+ SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+ SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl_power_init_handle(struct iwl_priv *priv)
+{
+ int rc = 0, i;
+ struct iwl_power_mgr *pow_data;
+ int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+ u16 pci_pm;
+
+ IWL_DEBUG_POWER("Initialize power \n");
+
+ pow_data = &(priv->power_data);
+
+ memset(pow_data, 0, sizeof(*pow_data));
+
+ pow_data->active_index = IWL_POWER_RANGE_0;
+ pow_data->dtim_val = 0xffff;
+
+ memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+ memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+ rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+ if (rc != 0)
+ return 0;
+ else {
+ struct iwl_powertable_cmd *cmd;
+
+ IWL_DEBUG_POWER("adjust power command flags\n");
+
+ for (i = 0; i < IWL_POWER_AC; i++) {
+ cmd = &pow_data->pwr_range_0[i].cmd;
+
+ if (pci_pm & 0x1)
+ cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+ else
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+ }
+ }
+ return rc;
+}
+
+static int iwl_update_power_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd, u32 mode)
+{
+ int rc = 0, i;
+ u8 skip;
+ u32 max_sleep = 0;
+ struct iwl_power_vec_entry *range;
+ u8 period = 0;
+ struct iwl_power_mgr *pow_data;
+
+ if (mode > IWL_POWER_INDEX_5) {
+ IWL_DEBUG_POWER("Error invalid power mode \n");
+ return -1;
+ }
+ pow_data = &(priv->power_data);
+
+ if (pow_data->active_index == IWL_POWER_RANGE_0)
+ range = &pow_data->pwr_range_0[0];
+ else
+ range = &pow_data->pwr_range_1[1];
+
+ memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+ if (priv->assoc_network != NULL) {
+ unsigned long flags;
+
+ period = priv->assoc_network->tim.tim_period;
+ }
+#endif /*IWL_MAC80211_DISABLE */
+ skip = range[mode].no_dtim;
+
+ if (period == 0) {
+ period = 1;
+ skip = 0;
+ }
+
+ if (skip == 0) {
+ max_sleep = period;
+ cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ } else {
+ __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+ max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+ cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ }
+
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+ cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ }
+
+ IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+ IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+ IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+ IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+ le32_to_cpu(cmd->sleep_interval[0]),
+ le32_to_cpu(cmd->sleep_interval[1]),
+ le32_to_cpu(cmd->sleep_interval[2]),
+ le32_to_cpu(cmd->sleep_interval[3]),
+ le32_to_cpu(cmd->sleep_interval[4]));
+
+ return rc;
+}
+
+static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+{
+ u32 final_mode = mode;
+ int rc;
+ struct iwl_powertable_cmd cmd;
+
+ /* If on battery, set to 3,
+ * if plugged into AC power, set to CAM ("continuosly aware mode"),
+ * else user level */
+ switch (mode) {
+ case IWL_POWER_BATTERY:
+ final_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_POWER_AC:
+ final_mode = IWL_POWER_MODE_CAM;
+ break;
+ default:
+ final_mode = mode;
+ break;
+ }
+
+ cmd.keep_alive_beacons = 0;
+
+ iwl_update_power_cmd(priv, &cmd, final_mode);
+
+ rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+ if (final_mode == IWL_POWER_MODE_CAM)
+ clear_bit(STATUS_POWER_PMI, &priv->status);
+ else
+ set_bit(STATUS_POWER_PMI, &priv->status);
+
+ return rc;
+}
+
+int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ /* Filter incoming packets to determine if they are targeted toward
+ * this network, discarding packets coming from ourselves */
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr2, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our IBSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr3, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr3, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our BSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr2, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ }
+
+ return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_ENTRY(SHORT_LIMIT);
+ TX_STATUS_ENTRY(LONG_LIMIT);
+ TX_STATUS_ENTRY(FIFO_UNDERRUN);
+ TX_STATUS_ENTRY(MGMNT_ABORT);
+ TX_STATUS_ENTRY(NEXT_FRAG);
+ TX_STATUS_ENTRY(LIFE_EXPIRE);
+ TX_STATUS_ENTRY(DEST_PS);
+ TX_STATUS_ENTRY(ABORTED);
+ TX_STATUS_ENTRY(BT_RETRY);
+ TX_STATUS_ENTRY(STA_INVALID);
+ TX_STATUS_ENTRY(FRAG_DROPPED);
+ TX_STATUS_ENTRY(TID_DISABLE);
+ TX_STATUS_ENTRY(FRAME_FLUSHED);
+ TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+ TX_STATUS_ENTRY(TX_LOCKED);
+ TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl_scan_cancel(struct iwl_priv *priv)
+{
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCANNING, &priv->status);
+ return 0;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Queuing scan abort.\n");
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ queue_work(priv->workqueue, &priv->abort_scan);
+
+ } else
+ IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+ unsigned long now = jiffies;
+ int ret;
+
+ ret = iwl_scan_cancel(priv);
+ if (ret && ms) {
+ mutex_unlock(&priv->mutex);
+ while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+ test_bit(STATUS_SCANNING, &priv->status))
+ msleep(1);
+ mutex_lock(&priv->mutex);
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return ret;
+}
+
+static void iwl_sequence_reset(struct iwl_priv *priv)
+{
+ /* Reset ieee stats */
+
+ /* We don't reset the net_device_stats (ieee->stats) on
+ * re-association */
+
+ priv->last_seq_num = -1;
+ priv->last_frag_num = -1;
+ priv->last_packet_time = 0;
+
+ iwl_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL 4096
+#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
+
+static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor =
+ (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+ / MAX_UCODE_BEACON_INTERVAL;
+ new_val = beacon_val / beacon_factor;
+
+ return cpu_to_le16(new_val);
+}
+
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 interval_tm_unit;
+ u64 tsf, result;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int = 0;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+ priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+ priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+ tsf = priv->timestamp1;
+ tsf = ((tsf << 32) | priv->timestamp0);
+
+ beacon_int = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (beacon_int == 0) {
+ priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+ } else {
+ priv->rxon_timing.beacon_interval =
+ cpu_to_le16(beacon_int);
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ }
+
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(conf->beacon_int);
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ interval_tm_unit =
+ (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+ result = do_div(tsf, interval_tm_unit);
+ priv->rxon_timing.beacon_init_val =
+ cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+ IWL_DEBUG_ASSOC
+ ("beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl_scan_initiate(struct iwl_priv *priv)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("APs don't scan.\n");
+ return 0;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan already in progress.\n");
+ return -EAGAIN;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan request while abort pending. "
+ "Queuing.\n");
+ return -EAGAIN;
+ }
+
+ IWL_DEBUG_INFO("Starting scan...\n");
+ priv->scan_bands = 2;
+ set_bit(STATUS_SCANNING, &priv->status);
+ priv->scan_start = jiffies;
+ priv->scan_pass_start = priv->scan_start;
+
+ queue_work(priv->workqueue, &priv->request_scan);
+
+ return 0;
+}
+
+static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (hw_decrypt)
+ rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+ else
+ rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+ return 0;
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+{
+ if (phymode == MODE_IEEE80211A) {
+ priv->staging_rxon.flags &=
+ ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+ | RXON_FLG_CCK_MSK);
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ } else {
+ /* Copied from iwl_bg_post_associate() */
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+ priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+ priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+ }
+}
+
+/*
+ * initilize rxon structure with default values fromm eeprom
+ */
+static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+{
+ const struct iwl_channel_info *ch_info;
+
+ memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_AP:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+ break;
+
+ case IEEE80211_IF_TYPE_STA:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+ priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+ priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+ priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+ RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+ priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+ RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+ }
+
+#if 0
+ /* TODO: Figure out when short_preamble would be set and cache from
+ * that */
+ if (!hw_to_local(priv->hw)->short_preamble)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+ ch_info = iwl_get_channel_info(priv, priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info)
+ ch_info = &priv->channel_info[0];
+
+ /*
+ * in some case A channels are all non IBSS
+ * in this case force B/G channel
+ */
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !(is_channel_ibss(ch_info)))
+ ch_info = &priv->channel_info[0];
+
+ priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+ if (is_channel_a_band(ch_info))
+ priv->phymode = MODE_IEEE80211A;
+ else
+ priv->phymode = MODE_IEEE80211G;
+
+ iwl_set_flags_for_phymode(priv, priv->phymode);
+
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+ priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+ RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+ priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
+ priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
+ iwl4965_set_rxon_chain(priv);
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
+ if (mode == IEEE80211_IF_TYPE_IBSS) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv,
+ priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info || !is_channel_ibss(ch_info)) {
+ IWL_ERROR("channel %d not IBSS channel\n",
+ le16_to_cpu(priv->staging_rxon.channel));
+ return -EINVAL;
+ }
+ }
+
+ cancel_delayed_work(&priv->scan_check);
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ return -EAGAIN;
+ }
+
+ priv->iw_mode = mode;
+
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+ iwl_clear_stations_table(priv);
+
+ iwl_commit_rxon(priv);
+
+ return 0;
+}
+
+static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+ struct ieee80211_tx_control *ctl,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb_frag,
+ int last_frag)
+{
+ struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+ switch (keyinfo->alg) {
+ case ALG_CCMP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+ IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+ break;
+
+ case ALG_TKIP:
+#if 0
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+ if (last_frag)
+ memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+ 8);
+ else
+ memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+ break;
+
+ case ALG_WEP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+ (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+ if (keyinfo->keylen == 13)
+ cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+ memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+ IWL_DEBUG_TX("Configuring packet for WEP encryption "
+ "with key %d\n", ctl->key_idx);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+ break;
+ }
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr,
+ int is_unicast, u8 std_id)
+{
+ __le16 *qc;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ __le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+ cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ tx_flags |= TX_CMD_FLG_ACK_MSK;
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ if (ieee80211_is_probe_response(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+ tx_flags |= TX_CMD_FLG_TSF_MSK;
+ } else {
+ tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
+
+ cmd->cmd.tx.sta_id = std_id;
+ if (ieee80211_get_morefrag(hdr))
+ tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+ } else
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+ if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ tx_flags |= TX_CMD_FLG_RTS_MSK;
+ tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+
+ if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+ tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(3);
+ else
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(2);
+ } else
+ cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+ cmd->cmd.tx.driver_txop = 0;
+ cmd->cmd.tx.tx_flags = tx_flags;
+ cmd->cmd.tx.next_frame_len = 0;
+}
+
+static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+ int sta_id;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ DECLARE_MAC_BUF(mac);
+
+ /* If this frame is broadcast or not data then use the broadcast
+ * station id */
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return priv->hw_setting.bcast_sta_id;
+
+ switch (priv->iw_mode) {
+
+ /* If this frame is part of a BSS network (we're a station), then
+ * we use the AP's station id */
+ case IEEE80211_IF_TYPE_STA:
+ return IWL_AP_ID;
+
+ /* If we are an AP, then find the station, or use BCAST */
+ case IEEE80211_IF_TYPE_AP:
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+ return priv->hw_setting.bcast_sta_id;
+
+ /* If this frame is part of a IBSS network, then we use the
+ * target specific station id */
+ case IEEE80211_IF_TYPE_IBSS:
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ IWL_DEBUG_DROP("Station %s not in station map. "
+ "Defaulting to broadcast...\n",
+ print_mac(mac, hdr->addr1));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ return priv->hw_setting.bcast_sta_id;
+
+ default:
+ IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+ return priv->hw_setting.bcast_sta_id;
+ }
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl_tx_skb(struct iwl_priv *priv,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ int txq_id = ctl->queue;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_queue *q = NULL;
+ dma_addr_t phys_addr;
+ dma_addr_t txcmd_phys;
+ struct iwl_cmd *out_cmd = NULL;
+ u16 len, idx, len_org;
+ u8 id, hdr_len, unicast;
+ u8 sta_id;
+ u16 seq_number = 0;
+ u16 fc;
+ __le16 *qc;
+ u8 wait_write_ptr = 0;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_DROP("Dropping - RF KILL\n");
+ goto drop_unlock;
+ }
+
+ if (!priv->interface_id) {
+ IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+ goto drop_unlock;
+ }
+
+ if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+ IWL_ERROR("ERROR: No TX rate available.\n");
+ goto drop_unlock;
+ }
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+ id = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (ieee80211_is_auth(fc))
+ IWL_DEBUG_TX("Sending AUTH frame\n");
+ else if (ieee80211_is_assoc_request(fc))
+ IWL_DEBUG_TX("Sending ASSOC frame\n");
+ else if (ieee80211_is_reassoc_request(fc))
+ IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+ if (!iwl_is_associated(priv) &&
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+ IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+ goto drop_unlock;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ hdr_len = ieee80211_get_hdrlen(fc);
+ sta_id = iwl_get_sta_id(priv, hdr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+ print_mac(mac, hdr->addr1));
+ goto drop;
+ }
+
+ IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ seq_number = priv->stations[sta_id].tid[tid].seq_number &
+ IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = cpu_to_le16(seq_number) |
+ (hdr->seq_ctrl &
+ __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+ seq_number += 0x10;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ /* aggregation is on for this <sta,tid> */
+ if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
+ txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ }
+ txq = &priv->txq[txq_id];
+ q = &txq->q;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+ control_flags = (u32 *) tfd;
+ idx = get_cmd_index(q, q->first_empty, 0);
+
+ memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
+ txq->txb[q->first_empty].skb[0] = skb;
+ memcpy(&(txq->txb[q->first_empty].status.control),
+ ctl, sizeof(struct ieee80211_tx_control));
+ out_cmd = &txq->cmd[idx];
+ memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+ memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+ out_cmd->hdr.cmd = REPLY_TX;
+ out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->first_empty)));
+ /* copy frags header */
+ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+ /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+ len = priv->hw_setting.tx_cmd_len +
+ sizeof(struct iwl_cmd_header) + hdr_len;
+
+ len_org = len;
+ len = (len + 3) & ~3;
+
+ if (len_org != len)
+ len_org = 1;
+ else
+ len_org = 0;
+
+ txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+ offsetof(struct iwl_cmd, hdr);
+
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+ if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+ /* 802.11 null functions have no payload... */
+ len = skb->len - hdr_len;
+ if (len) {
+ phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+ len, PCI_DMA_TODEVICE);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+ }
+
+ if (len_org)
+ out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+ len = (u16)skb->len;
+ out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+ /* TODO need this for burst mode later on */
+ iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+ /* set is_hcca to 0; it probably will never be implemented */
+ iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+ iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
+ hdr, hdr_len, ctl, NULL);
+
+ if (!ieee80211_get_morefrag(hdr)) {
+ txq->need_update = 1;
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
+ }
+
+ iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+ sizeof(out_cmd->cmd.tx));
+
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+ ieee80211_get_hdrlen(fc));
+
+ iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ rc = iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (rc)
+ return rc;
+
+ if ((iwl_queue_space(q) < q->high_mark)
+ && priv->mac80211_registered) {
+ if (wait_write_ptr) {
+ spin_lock_irqsave(&priv->lock, flags);
+ txq->need_update = 1;
+ iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ ieee80211_stop_queue(priv->hw, ctl->queue);
+ }
+
+ return 0;
+
+drop_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+ return -1;
+}
+
+static void iwl_set_rate(struct iwl_priv *priv)
+{
+ const struct ieee80211_hw_mode *hw = NULL;
+ struct ieee80211_rate *rate;
+ int i;
+
+ hw = iwl_get_hw_mode(priv, priv->phymode);
+
+ priv->active_rate = 0;
+ priv->active_rate_basic = 0;
+
+ IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+ hw->mode == MODE_IEEE80211A ?
+ 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+ for (i = 0; i < hw->num_rates; i++) {
+ rate = &(hw->rates[i]);
+ if ((rate->val < IWL_RATE_COUNT) &&
+ (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+ IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+ rate->val, iwl_rates[rate->val].plcp,
+ (rate->flags & IEEE80211_RATE_BASIC) ?
+ "*" : "");
+ priv->active_rate |= (1 << rate->val);
+ if (rate->flags & IEEE80211_RATE_BASIC)
+ priv->active_rate_basic |= (1 << rate->val);
+ } else
+ IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+ rate->val, iwl_rates[rate->val].plcp);
+ }
+
+ IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+ priv->active_rate, priv->active_rate_basic);
+
+ /*
+ * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+ * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+ * OFDM
+ */
+ if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+ priv->staging_rxon.cck_basic_rates =
+ ((priv->active_rate_basic &
+ IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+ else
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+ if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+ priv->staging_rxon.ofdm_basic_rates =
+ ((priv->active_rate_basic &
+ (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+ IWL_FIRST_OFDM_RATE) & 0xFF;
+ else
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+ unsigned long flags;
+
+ if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+ return;
+
+ IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+ disable_radio ? "OFF" : "ON");
+
+ if (disable_radio) {
+ iwl_scan_cancel(priv);
+ /* FIXME: This is a workaround for AP */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_SW_BIT_RFKILL);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ }
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wake up ucode */
+ msleep(10);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (!iwl_grab_restricted_access(priv))
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by HW switch\n");
+ return;
+ }
+
+ queue_work(priv->workqueue, &priv->restart);
+ return;
+}
+
+void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+ u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+ u16 fc =
+ le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+ if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+ return;
+
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return;
+
+ IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+ switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_ICV_MIC)
+ stats->flag |= RX_FLAG_MMIC_ERROR;
+ case RX_RES_STATUS_SEC_TYPE_WEP:
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_DECRYPT_OK) {
+ IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+ stats->flag |= RX_FLAG_DECRYPTED;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ void *data, short len,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags)
+{
+ struct iwl_rt_rx_hdr *iwl_rt;
+
+ /* First cache any information we need before we overwrite
+ * the information provided in the skb from the hardware */
+ s8 signal = stats->ssi;
+ s8 noise = 0;
+ int rate = stats->rate;
+ u64 tsf = stats->mactime;
+ __le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+ /* We received data from the HW, so stop the watchdog */
+ if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
+ IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+ return;
+ }
+
+ /* copy the frame data to write after where the radiotap header goes */
+ iwl_rt = (void *)rxb->skb->data;
+ memmove(iwl_rt->payload, data, len);
+
+ iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+ /* total header + data */
+ iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, sizeof(*iwl_rt) + len);
+
+ /* Big bitfield of all the fields we provide in radiotap */
+ iwl_rt->rt_hdr.it_present =
+ 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));
+
+ /* Zero the flags, we'll add to them as we go */
+ iwl_rt->rt_flags = 0;
+
+ iwl_rt->rt_tsf = cpu_to_le64(tsf);
+
+ /* Convert to dBm */
+ iwl_rt->rt_dbmsignal = signal;
+ iwl_rt->rt_dbmnoise = noise;
+
+ /* Convert the channel frequency and set the flags */
+ iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+ if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+ else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+ else /* 802.11g */
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+ rate = iwl_rate_index_from_plcp(rate);
+ if (rate == -1)
+ iwl_rt->rt_rate = 0;
+ else
+ iwl_rt->rt_rate = iwl_rates[rate].ieee;
+
+ /* antenna number */
+ iwl_rt->rt_antenna =
+ le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+ /* set the preamble flag if we have it */
+ if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+ iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+ stats->flag |= RX_FLAG_RADIOTAP;
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ u16 sc = le16_to_cpu(header->seq_ctrl);
+ u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+ u16 frag = sc & IEEE80211_SCTL_FRAG;
+ u16 *last_seq, *last_frag;
+ unsigned long *last_time;
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS:{
+ struct list_head *p;
+ struct iwl_ibss_seq *entry = NULL;
+ u8 *mac = header->addr2;
+ int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+ __list_for_each(p, &priv->ibss_mac_hash[index]) {
+ entry =
+ list_entry(p, struct iwl_ibss_seq, list);
+ if (!compare_ether_addr(entry->mac, mac))
+ break;
+ }
+ if (p == &priv->ibss_mac_hash[index]) {
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ IWL_ERROR
+ ("Cannot malloc new mac entry\n");
+ return 0;
+ }
+ memcpy(entry->mac, mac, ETH_ALEN);
+ entry->seq_num = seq;
+ entry->frag_num = frag;
+ entry->packet_time = jiffies;
+ list_add(&entry->list,
+ &priv->ibss_mac_hash[index]);
+ return 0;
+ }
+ last_seq = &entry->seq_num;
+ last_frag = &entry->frag_num;
+ last_time = &entry->packet_time;
+ break;
+ }
+ case IEEE80211_IF_TYPE_STA:
+ last_seq = &priv->last_seq_num;
+ last_frag = &priv->last_frag_num;
+ last_time = &priv->last_packet_time;
+ break;
+ default:
+ return 0;
+ }
+ if ((*last_seq == seq) &&
+ time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+ if (*last_frag == frag)
+ goto drop;
+ if (*last_frag + 1 != frag)
+ /* out-of-order fragment */
+ goto drop;
+ } else
+ *last_seq = seq;
+
+ *last_frag = frag;
+ *last_time = jiffies;
+ return 0;
+
+ drop:
+ return 1;
+}
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW 0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH 0xFF000000
+#define TIME_UNIT 1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * 1024;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+ rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+ return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & BEACON_TIME_MASK_LOW;
+ u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & BEACON_TIME_MASK_HIGH) +
+ (addon & BEACON_TIME_MASK_HIGH);
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << 24);
+ } else
+ res += (1 << 24);
+
+ return cpu_to_le32(res);
+}
+
+static int iwl_get_measurement(struct iwl_priv *priv,
+ struct ieee80211_measurement_params *params,
+ u8 type)
+{
+ struct iwl_spectrum_cmd spectrum;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+ .data = (void *)&spectrum,
+ .meta.flags = CMD_WANT_SKB,
+ };
+ u32 add_time = le64_to_cpu(params->start_time);
+ int rc;
+ int spectrum_resp_status;
+ int duration = le16_to_cpu(params->duration);
+
+ if (iwl_is_associated(priv))
+ add_time =
+ iwl_usecs_to_beacons(
+ le64_to_cpu(params->start_time) - priv->last_tsf,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+ memset(&spectrum, 0, sizeof(spectrum));
+
+ spectrum.channel_count = cpu_to_le16(1);
+ spectrum.flags =
+ RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+ spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+ cmd.len = sizeof(spectrum);
+ spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+ if (iwl_is_associated(priv))
+ spectrum.start_time =
+ iwl_add_beacon_time(priv->last_beacon_time,
+ add_time,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ else
+ spectrum.start_time = 0;
+
+ spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+ spectrum.channels[0].channel = params->channel;
+ spectrum.channels[0].type = type;
+ if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+ RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ switch (spectrum_resp_status) {
+ case 0: /* Command will be handled */
+ if (res->u.spectrum.id != 0xff) {
+ IWL_DEBUG_INFO
+ ("Replaced existing measurement: %d\n",
+ res->u.spectrum.id);
+ priv->measurement_status &= ~MEASUREMENT_READY;
+ }
+ priv->measurement_status |= MEASUREMENT_ACTIVE;
+ rc = 0;
+ break;
+
+ case 1: /* Command will not be handled */
+ rc = -EAGAIN;
+ break;
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+#endif
+
+static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+ struct iwl_tx_info *tx_sta)
+{
+
+ tx_sta->status.ack_signal = 0;
+ tx_sta->status.excessive_retries = 0;
+ tx_sta->status.queue_length = 0;
+ tx_sta->status.queue_number = 0;
+
+ if (in_interrupt())
+ ieee80211_tx_status_irqsafe(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+ else
+ ieee80211_tx_status(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+
+ tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW advances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ */
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->first_empty, q->last_used);
+ return 0;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd);
+ q->last_used != index;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+ if (txq_id != IWL_CMD_QUEUE_NUM) {
+ iwl_txstatus_to_ieee(priv,
+ &(txq->txb[txq->q.last_used]));
+ iwl_hw_txq_free_tfd(priv, txq);
+ } else if (nfreed > 1) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ q->first_empty, q->last_used);
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ nfreed++;
+ }
+
+ if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+ (txq_id != IWL_CMD_QUEUE_NUM) &&
+ priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+
+
+ return nfreed;
+}
+
+static int iwl_is_tx_success(u32 status)
+{
+ status &= TX_STATUS_MSK;
+ return (status == TX_STATUS_SUCCESS)
+ || (status == TX_STATUS_DIRECT_DONE);
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+ return IWL_AP_ID;
+ else {
+ u8 *da = ieee80211_get_DA(hdr);
+ return iwl_hw_find_station(priv, da);
+ }
+}
+
+static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
+ struct iwl_priv *priv, int txq_id, int idx)
+{
+ if (priv->txq[txq_id].txb[idx].skb[0])
+ return (struct ieee80211_hdr *)priv->txq[txq_id].
+ txb[idx].skb[0]->data;
+ return NULL;
+}
+
+static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp)
+{
+ __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+ tx_resp->frame_count);
+ return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+ struct iwl_ht_agg *agg,
+ struct iwl_tx_resp *tx_resp,
+ u16 start_idx)
+{
+ u32 status;
+ __le32 *frame_status = &tx_resp->status;
+ struct ieee80211_tx_status *tx_status = NULL;
+ struct ieee80211_hdr *hdr = NULL;
+ int i, sh;
+ int txq_id, idx;
+ u16 seq;
+
+ if (agg->wait_for_ba)
+ IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n");
+
+ agg->frame_count = tx_resp->frame_count;
+ agg->start_idx = start_idx;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ agg->bitmap0 = agg->bitmap1 = 0;
+
+ if (agg->frame_count == 1) {
+ struct iwl_tx_queue *txq ;
+ status = le32_to_cpu(frame_status[0]);
+
+ txq_id = agg->txq_id;
+ txq = &priv->txq[txq_id];
+ /* FIXME: code repetition */
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
+ agg->frame_count, agg->start_idx);
+
+ tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status);
+ tx_status->retry_count = tx_resp->failure_frame;
+ tx_status->queue_number = status & 0xff;
+ tx_status->queue_length = tx_resp->bt_kill_count;
+ tx_status->queue_length |= tx_resp->failure_rts;
+
+ tx_status->flags = iwl_is_tx_success(status)?
+ IEEE80211_TX_STATUS_ACK : 0;
+ tx_status->control.tx_rate =
+ iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+ /* FIXME: code repetition end */
+
+ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+ status & 0xff, tx_resp->failure_frame);
+ IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+ iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+ agg->wait_for_ba = 0;
+ } else {
+ u64 bitmap = 0;
+ int start = agg->start_idx;
+
+ for (i = 0; i < agg->frame_count; i++) {
+ u16 sc;
+ status = le32_to_cpu(frame_status[i]);
+ seq = status >> 16;
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+ AGG_TX_STATE_ABORT_MSK))
+ continue;
+
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+ agg->frame_count, txq_id, idx);
+
+ hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+ sc = le16_to_cpu(hdr->seq_ctrl);
+ if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+ IWL_ERROR("BUG_ON idx doesn't match seq control"
+ " idx=%d, seq_idx=%d, seq=%d\n",
+ idx, SEQ_TO_SN(sc),
+ hdr->seq_ctrl);
+ return -1;
+ }
+
+ IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+ i, idx, SEQ_TO_SN(sc));
+
+ sh = idx - start;
+ if (sh > 64) {
+ sh = (start - idx) + 0xff;
+ bitmap = bitmap << sh;
+ sh = 0;
+ start = idx;
+ } else if (sh < -64)
+ sh = 0xff - (start - idx);
+ else if (sh < 0) {
+ sh = start - idx;
+ start = idx;
+ bitmap = bitmap << sh;
+ sh = 0;
+ }
+ bitmap |= (1 << sh);
+ IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+ start, (u32)(bitmap & 0xFFFFFFFF));
+ }
+
+ agg->bitmap0 = bitmap & 0xFFFFFFFF;
+ agg->bitmap1 = bitmap >> 32;
+ agg->start_idx = start;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n",
+ agg->frame_count, agg->start_idx,
+ agg->bitmap0);
+
+ if (bitmap)
+ agg->wait_for_ba = 1;
+ }
+ return 0;
+}
+#endif
+#endif
+
+static void iwl_rx_reply_tx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_status *tx_status;
+ struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->status);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ int tid, sta_id;
+#endif
+#endif
+
+ if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.first_empty,
+ txq->q.last_used);
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ if (txq->sched_retry) {
+ const u32 scd_ssn = iwl_get_scd_ssn(tx_resp);
+ struct ieee80211_hdr *hdr =
+ iwl_tx_queue_get_hdr(priv, txq_id, index);
+ struct iwl_ht_agg *agg = NULL;
+ __le16 *qc = ieee80211_get_qos_ctrl(hdr);
+
+ if (qc == NULL) {
+ IWL_ERROR("BUG_ON qc is null!!!!\n");
+ return;
+ }
+
+ tid = le16_to_cpu(*qc) & 0xf;
+
+ sta_id = iwl_get_ra_sta_id(priv, hdr);
+ if (unlikely(sta_id == IWL_INVALID_STATION)) {
+ IWL_ERROR("Station not known for\n");
+ return;
+ }
+
+ agg = &priv->stations[sta_id].tid[tid].agg;
+
+ iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
+
+ if ((tx_resp->frame_count == 1) &&
+ !iwl_is_tx_success(status)) {
+ /* TODO: send BAR */
+ }
+
+ if ((txq->q.last_used != (scd_ssn & 0xff))) {
+ index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+ IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+ "%d index %d\n", scd_ssn , index);
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+ }
+ } else {
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ tx_status = &(txq->txb[txq->q.last_used].status);
+
+ tx_status->retry_count = tx_resp->failure_frame;
+ tx_status->queue_number = status;
+ tx_status->queue_length = tx_resp->bt_kill_count;
+ tx_status->queue_length |= tx_resp->failure_rts;
+
+ tx_status->flags =
+ iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+ tx_status->control.tx_rate =
+ iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+ "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+ status, le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+ if (index != -1)
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ }
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_alive_resp *palive;
+ struct delayed_work *pwork;
+
+ palive = &pkt->u.alive_frame;
+
+ IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+ "0x%01X 0x%01X\n",
+ palive->is_valid, palive->ver_type,
+ palive->ver_subtype);
+
+ if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ memcpy(&priv->card_alive_init,
+ &pkt->u.alive_frame,
+ sizeof(struct iwl_init_alive_resp));
+ pwork = &priv->init_alive_start;
+ } else {
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+ memcpy(&priv->card_alive, &pkt->u.alive_frame,
+ sizeof(struct iwl_alive_resp));
+ pwork = &priv->alive_start;
+ }
+
+ /* We delay the ALIVE response by 5ms to
+ * give the HW RF Kill time to activate... */
+ if (palive->is_valid == UCODE_VALID_OK)
+ queue_delayed_work(priv->workqueue, pwork,
+ msecs_to_jiffies(5));
+ else
+ IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+ return;
+}
+
+static void iwl_rx_reply_error(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+ "seq 0x%04X ser 0x%08X\n",
+ le32_to_cpu(pkt->u.err_resp.error_type),
+ get_cmd_string(pkt->u.err_resp.cmd_id),
+ pkt->u.err_resp.cmd_id,
+ le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+ le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
+ struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+ IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+ le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+ if (!report->state) {
+ IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+ "Spectrum Measure Notification: Start\n");
+ return;
+ }
+
+ memcpy(&priv->measure_report, report, sizeof(*report));
+ priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+ IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+ sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+ "notification for %s:\n",
+ le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, beacon_update);
+ struct sk_buff *beacon;
+
+ /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+ beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+ if (!beacon) {
+ IWL_ERROR("update beacon failed\n");
+ return;
+ }
+
+ mutex_lock(&priv->mutex);
+ /* new beacon skb is allocated every time; dispose previous.*/
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = beacon;
+ mutex_unlock(&priv->mutex);
+
+ iwl_send_beacon_cmd(priv);
+}
+
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+ u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+
+ IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+ "tsf %d %d rate %d\n",
+ le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+ beacon->beacon_notify_hdr.failure_frame,
+ le32_to_cpu(beacon->ibss_mgr_status),
+ le32_to_cpu(beacon->high_tsf),
+ le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+ queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl_rx_reply_scan(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanreq_notification *notif =
+ (struct iwl_scanreq_notification *)pkt->u.raw;
+
+ IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanstart_notification *notif =
+ (struct iwl_scanstart_notification *)pkt->u.raw;
+ priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+ IWL_DEBUG_SCAN("Scan start: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ notif->tsf_high,
+ notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanresults_notification *notif =
+ (struct iwl_scanresults_notification *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan ch.res: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d "
+ "elapsed=%lu usec (%dms since last)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ le32_to_cpu(notif->tsf_high),
+ le32_to_cpu(notif->tsf_low),
+ le32_to_cpu(notif->statistics[0]),
+ le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->last_scan_jiffies, jiffies)));
+
+ priv->last_scan_jiffies = jiffies;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+ scan_notif->scanned_channels,
+ scan_notif->tsf_low,
+ scan_notif->tsf_high, scan_notif->status);
+
+ /* The HW is no longer scanning */
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+
+ /* The scan completion notification came in, so kill that timer... */
+ cancel_delayed_work(&priv->scan_check);
+
+ IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+ (priv->scan_bands == 2) ? "2.4" : "5.2",
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->scan_pass_start, jiffies)));
+
+ /* Remove this scanned band from the list
+ * of pending bands to scan */
+ priv->scan_bands--;
+
+ /* If a request to abort was given, or the scan did not succeed
+ * then we reset the scan state machine and terminate,
+ * re-queuing another scan if one has been requested */
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_INFO("Aborted scan completed.\n");
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ } else {
+ /* If there are more bands on this scan pass reschedule */
+ if (priv->scan_bands > 0)
+ goto reschedule;
+ }
+
+ priv->last_scan_jiffies = jiffies;
+ IWL_DEBUG_INFO("Setting scan to off\n");
+
+ clear_bit(STATUS_SCANNING, &priv->status);
+
+ IWL_DEBUG_INFO("Scan took %dms\n",
+ jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+ queue_work(priv->workqueue, &priv->scan_completed);
+
+ return;
+
+reschedule:
+ priv->scan_pass_start = jiffies;
+ queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+ unsigned long status = priv->status;
+
+ IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+ (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+ if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
+ RF_CARD_DISABLED)) {
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted(
+ priv, HBUS_TARG_MBX_C,
+ HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+ iwl_release_restricted_access(priv);
+ }
+
+ if (!(flags & RXON_CARD_DISABLED)) {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted(
+ priv, HBUS_TARG_MBX_C,
+ HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+ iwl_release_restricted_access(priv);
+ }
+ }
+
+ if (flags & RF_CARD_DISABLED) {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (!iwl_grab_restricted_access(priv))
+ iwl_release_restricted_access(priv);
+ }
+ }
+
+ if (flags & HW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+ if (flags & SW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+ if (!(flags & RXON_CARD_DISABLED))
+ iwl_scan_cancel(priv);
+
+ if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+ test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+ (test_bit(STATUS_RF_KILL_SW, &status) !=
+ test_bit(STATUS_RF_KILL_SW, &priv->status)))
+ queue_work(priv->workqueue, &priv->rf_kill);
+ else
+ wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+ priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
+ priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
+ priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+ priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
+ priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+ priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+ iwl_rx_pm_debug_statistics_notif;
+ priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+
+ /* NOTE: iwl_rx_statistics is different based on whether
+ * the build is for the 3945 or the 4965. See the
+ * corresponding implementation in iwl-XXXX.c
+ *
+ * The same handler is used for both the REPLY to a
+ * discrete statistics request from the host as well as
+ * for the periodic statistics notification from the uCode
+ */
+ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
+ priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+
+ priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+ priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+ priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+ iwl_rx_scan_results_notif;
+ priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+ iwl_rx_scan_complete_notif;
+ priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
+ priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+
+ /* Setup hardware specific Rx handlers */
+ iwl_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed. The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ int huge = sequence & SEQ_HUGE_FRAME;
+ int cmd_index;
+ struct iwl_cmd *cmd;
+
+ /* If a Tx command is being handled and it isn't in the actual
+ * command queue then there a command routing bug has been introduced
+ * in the queue management code. */
+ if (txq_id != IWL_CMD_QUEUE_NUM)
+ IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+ txq_id, pkt->hdr.cmd);
+ BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+ cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+ cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+ /* Input error checking is done when commands are added to queue. */
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ cmd->meta.source->u.skb = rxb->skb;
+ rxb->skb = NULL;
+ } else if (cmd->meta.u.callback &&
+ !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ rxb->skb = NULL;
+
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+
+ if (!(cmd->meta.flags & CMD_ASYNC)) {
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+ }
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
+ * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replensish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * iwl->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the iwl->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc() Allocates rx_free
+ * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls iwl_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ *
+ * NOTE: This function has 3945 and 4965 specific code sections
+ * but is declared in base due to the majority of the
+ * implementation being the same (only a numeric constant is
+ * different)
+ *
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+ u32 reg = 0;
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if (q->need_update == 0)
+ goto exit_unlock;
+
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ goto exit_unlock;
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+ q->write & ~0x7);
+ iwl_release_restricted_access(priv);
+ } else
+ iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+ q->need_update = 0;
+
+ exit_unlock:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return rc;
+}
+
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
+ *
+ * NOTE: This function has 3945 and 4965 specific code paths in it.
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+ dma_addr_t dma_addr)
+{
+ return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ int write, rc;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ write = rxq->write & ~0x7;
+ while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ /* If the pre-allocated buffer pool is dropping low, schedule to
+ * refill it */
+ if (rxq->free_count <= RX_LOW_WATERMARK)
+ queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+ /* If we've added more space for the firmware to place data, tell it */
+ if ((write != (rxq->write & ~0x7))
+ || (abs(rxq->write - rxq->read) > 7)) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ rxq->need_update = 1;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during intialization)
+ */
+void iwl_rx_replenish(void *data)
+{
+ struct iwl_priv *priv = data;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ spin_lock_irqsave(&rxq->lock, flags);
+ while (!list_empty(&rxq->rx_used)) {
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ rxb->skb =
+ alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+ if (!rxb->skb) {
+ if (net_ratelimit())
+ printk(KERN_CRIT DRV_NAME
+ ": Can not allocate SKB buffers\n");
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ break;
+ }
+ priv->alloc_rxb_skb++;
+ list_del(element);
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_rx_queue_restock(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int i;
+ for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ }
+
+ pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ rxq->bd = NULL;
+}
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+
+ spin_lock_init(&rxq->lock);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+ if (!rxq->bd)
+ return -ENOMEM;
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ rxq->need_update = 0;
+ return 0;
+}
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&rxq->lock, flags);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb(rxq->pool[i].skb);
+ rxq->pool[i].skb = NULL;
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/* 0 1 2 3 4 5 6 7 8 9 */
+ 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+ 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+ 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+ 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+ 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+ 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+ 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+ 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+ 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+ 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ * (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl_calc_db_from_ratio(int sig_ratio)
+{
+ /* Anything above 1000:1 just report as 60 dB */
+ if (sig_ratio > 1000)
+ return 60;
+
+ /* Above 100:1, divide by 10 and use table,
+ * add 20 dB to make up for divide by 10 */
+ if (sig_ratio > 100)
+ return (20 + (int)ratio2dB[sig_ratio/10]);
+
+ /* We shouldn't see this */
+ if (sig_ratio < 1)
+ return 0;
+
+ /* Use table for ratios 1:1 - 99:1 */
+ return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95) /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ * about formulas used below. */
+int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+ int sig_qual;
+ int degradation = PERFECT_RSSI - rssi_dbm;
+
+ /* If we get a noise measurement, use signal-to-noise ratio (SNR)
+ * as indicator; formula is (signal dbm - noise dbm).
+ * SNR at or above 40 is a great signal (100%).
+ * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+ * Weakest usable signal is usually 10 - 15 dB SNR. */
+ if (noise_dbm) {
+ if (rssi_dbm - noise_dbm >= 40)
+ return 100;
+ else if (rssi_dbm < noise_dbm)
+ return 0;
+ sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+ /* Else use just the signal level.
+ * This formula is a least squares fit of data points collected and
+ * compared with a reference system that had a percentage (%) display
+ * for signal quality. */
+ } else
+ sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+ (15 * RSSI_RANGE + 62 * degradation)) /
+ (RSSI_RANGE * RSSI_RANGE);
+
+ if (sig_qual > 100)
+ sig_qual = 100;
+ else if (sig_qual < 1)
+ sig_qual = 0;
+
+ return sig_qual;
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_priv *priv)
+{
+ struct iwl_rx_mem_buffer *rxb;
+ struct iwl_rx_packet *pkt;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u32 r, i;
+ int reclaim;
+ unsigned long flags;
+
+ r = iwl_hw_get_rx_read(priv);
+ i = rxq->read;
+
+ /* Rx interrupt, but nothing sent from uCode */
+ if (i == r)
+ IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+ while (i != r) {
+ rxb = rxq->queue[i];
+
+ /* If an RXB doesn't have a queue slot associated with it
+ * then a bug has been introduced in the queue refilling
+ * routines -- catch it here */
+ BUG_ON(rxb == NULL);
+
+ rxq->queue[i] = NULL;
+
+ pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+ /* Reclaim a command buffer only if this packet is a response
+ * to a (driver-originated) command.
+ * If the packet (e.g. Rx frame) originated from uCode,
+ * there is no command buffer to reclaim.
+ * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+ * but apparently a few don't get set; catch them here. */
+ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+ (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+ (pkt->hdr.cmd != REPLY_4965_RX) &&
+ (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+ (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+ (pkt->hdr.cmd != REPLY_TX);
+
+ /* Based on type of command response or notification,
+ * handle those that need handling via function in
+ * rx_handlers table. See iwl_setup_rx_handlers() */
+ if (priv->rx_handlers[pkt->hdr.cmd]) {
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r = %d, i = %d, %s, 0x%02x\n", r, i,
+ get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ } else {
+ /* No handling needed */
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
+ r, i, get_cmd_string(pkt->hdr.cmd),
+ pkt->hdr.cmd);
+ }
+
+ if (reclaim) {
+ /* Invoke any callbacks, transfer the skb to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
+ * as we reclaim the driver command queue */
+ if (rxb && rxb->skb)
+ iwl_tx_cmd_complete(priv, rxb);
+ else
+ IWL_WARNING("Claim null rxb?\n");
+ }
+
+ /* For now we just don't re-use anything. We can tweak this
+ * later to try and re-use notification packets and SKBs that
+ * fail to Rx correctly */
+ if (rxb->skb != NULL) {
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(rxb->skb);
+ rxb->skb = NULL;
+ }
+
+ pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ spin_lock_irqsave(&rxq->lock, flags);
+ list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ i = (i + 1) & RX_QUEUE_MASK;
+ }
+
+ /* Backtrack one entry */
+ priv->rxq.read = i;
+ iwl_rx_queue_restock(priv);
+}
+
+int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
+{
+ u32 reg = 0;
+ int rc = 0;
+ int txq_id = txq->q.id;
+
+ if (txq->need_update == 0)
+ return rc;
+
+ /* if we're trying to save power */
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ /* wake up nic if it's powered down ...
+ * uCode will wake up, and interrupt us again, so next
+ * time we'll skip this part. */
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return rc;
+ }
+
+ /* restore this queue's parameters in nic hardware. */
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+ iwl_release_restricted_access(priv);
+
+ /* else not in power-save mode, uCode will never sleep when we're
+ * trying to tx (during RFKILL, we're not trying to tx). */
+ } else
+ iwl_write32(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+
+ txq->need_update = 0;
+
+ return rc;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+{
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_RADIO("RX CONFIG:\n");
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+ IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+ IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+ le32_to_cpu(rxon->filter_flags));
+ IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+ IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+ rxon->ofdm_basic_rates);
+ IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+ IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+ print_mac(mac, rxon->node_addr));
+ IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+ print_mac(mac, rxon->bssid_addr));
+ IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR("Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+ switch (i) {
+ case 1:
+ return "FAIL";
+ case 2:
+ return "BAD_PARAM";
+ case 3:
+ return "BAD_CHECKSUM";
+ case 4:
+ return "NMI_INTERRUPT";
+ case 5:
+ return "SYSASSERT";
+ case 6:
+ return "FATAL_ERROR";
+ }
+
+ return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+ int rc;
+
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ count = iwl_read_restricted_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERROR("Start IWL Error Log Dump:\n");
+ IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+ priv->status, priv->config, count);
+ }
+
+ desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32));
+ blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32));
+ blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32));
+ ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32));
+ ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32));
+ data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32));
+ line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32));
+ time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32));
+
+ IWL_ERROR("Desc Time "
+ "data1 data2 line\n");
+ IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+ desc_lookup(desc), desc, time, data1, data2, line);
+ IWL_ERROR("blink1 blink2 ilink1 ilink2\n");
+ IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+ ilink1, ilink2);
+
+ iwl_release_restricted_access(priv);
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0)
+ IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+ else {
+ data = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+ }
+ }
+}
+
+static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ int rc;
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_restricted_mem(priv, base);
+ mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+ iwl_release_restricted_access(priv);
+ return;
+ }
+
+ IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+ iwl_release_restricted_access(priv);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_priv *priv)
+{
+ /* Set the FW error flag -- cleared on iwl_down */
+ set_bit(STATUS_FW_ERROR, &priv->status);
+
+ /* Cancel currently queued command. */
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
+ iwl_dump_nic_error_log(priv);
+ iwl_dump_nic_event_log(priv);
+ iwl_print_rx_config_cmd(&priv->staging_rxon);
+ }
+#endif
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ /* Keep the restart process from trying to send host
+ * commands by clearing the INIT status bit */
+ clear_bit(STATUS_READY, &priv->status);
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+ "Restarting adapter due to uCode error.\n");
+
+ if (iwl_is_associated(priv)) {
+ memcpy(&priv->recovery_rxon, &priv->active_rxon,
+ sizeof(priv->recovery_rxon));
+ priv->error_recovering = 1;
+ }
+ queue_work(priv->workqueue, &priv->restart);
+ }
+}
+
+static void iwl_error_recovery(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+ sizeof(priv->staging_rxon));
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ iwl_rxon_add_station(priv, priv->bssid, 1);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+ priv->error_recovering = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+ u32 inta, handled = 0;
+ u32 inta_fh;
+ unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ u32 inta_mask;
+#endif
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Ack/clear/reset pending uCode interrupts.
+ * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+ * and will clear only when CSR_FH_INT_STATUS gets cleared. */
+ inta = iwl_read32(priv, CSR_INT);
+ iwl_write32(priv, CSR_INT, inta);
+
+ /* Ack/clear/reset pending flow-handler (DMA) interrupts.
+ * Any new interrupts that happen after this, either while we're
+ * in this tasklet, or later, will show up in next ISR/tasklet. */
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_ISR) {
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+ }
+#endif
+
+ /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+ * atomic, make sure that inta covers all the interrupts that
+ * we've discovered, even if FH interrupt came in just after
+ * reading CSR_INT. */
+ if (inta_fh & CSR_FH_INT_RX_MASK)
+ inta |= CSR_INT_BIT_FH_RX;
+ if (inta_fh & CSR_FH_INT_TX_MASK)
+ inta |= CSR_INT_BIT_FH_TX;
+
+ /* Now service all interrupt bits discovered above. */
+ if (inta & CSR_INT_BIT_HW_ERR) {
+ IWL_ERROR("Microcode HW error detected. Restarting.\n");
+
+ /* Tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ iwl_irq_handle_error(priv);
+
+ handled |= CSR_INT_BIT_HW_ERR;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ /* NIC fires this, but we don't use it, redundant with WAKEUP */
+ if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+ IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE)
+ IWL_DEBUG_ISR("Alive interrupt\n");
+ }
+#endif
+ /* Safely ignore these bits for debug checks below */
+ inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+ /* HW RF KILL switch toggled (4965 only) */
+ if (inta & CSR_INT_BIT_RF_KILL) {
+ int hw_rf_kill = 0;
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+ "RF_KILL bit toggled to %s.\n",
+ hw_rf_kill ? "disable radio":"enable radio");
+
+ /* Queue restart only if RF_KILL switch was set to "kill"
+ * when we loaded driver, and is now set to "enable".
+ * After we're Alive, RF_KILL gets handled by
+ * iwl_rx_card_state_notif() */
+ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+
+ handled |= CSR_INT_BIT_RF_KILL;
+ }
+
+ /* Chip got too hot and stopped itself (4965 only) */
+ if (inta & CSR_INT_BIT_CT_KILL) {
+ IWL_ERROR("Microcode CT kill error detected.\n");
+ handled |= CSR_INT_BIT_CT_KILL;
+ }
+
+ /* Error detected by uCode */
+ if (inta & CSR_INT_BIT_SW_ERR) {
+ IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n",
+ inta);
+ iwl_irq_handle_error(priv);
+ handled |= CSR_INT_BIT_SW_ERR;
+ }
+
+ /* uCode wakes up after power-down sleep */
+ if (inta & CSR_INT_BIT_WAKEUP) {
+ IWL_DEBUG_ISR("Wakeup interrupt\n");
+ iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+ handled |= CSR_INT_BIT_WAKEUP;
+ }
+
+ /* All uCode command responses, including Tx command responses,
+ * Rx "responses" (frame-received notification), and other
+ * notifications from uCode come through here*/
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+ iwl_rx_handle(priv);
+ handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+ }
+
+ if (inta & CSR_INT_BIT_FH_TX) {
+ IWL_DEBUG_ISR("Tx interrupt\n");
+ handled |= CSR_INT_BIT_FH_TX;
+ }
+
+ if (inta & ~handled)
+ IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+ if (inta & ~CSR_INI_SET_MASK) {
+ IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+ inta & ~CSR_INI_SET_MASK);
+ IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh);
+ }
+
+ /* Re-enable all interrupts */
+ iwl_enable_interrupts(priv);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ inta = iwl_read32(priv, CSR_INT);
+ inta_mask = iwl_read32(priv, CSR_INT_MASK);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+ "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+ }
+#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+ struct iwl_priv *priv = data;
+ u32 inta, inta_mask;
+ u32 inta_fh;
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ /* Disable (but don't clear!) interrupts here to avoid
+ * back-to-back ISRs and sporadic interrupts from our NIC.
+ * If we have something to service, the tasklet will re-enable ints.
+ * If we *don't* have something, we'll re-enable before leaving here. */
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* Discover which interrupts are active/pending */
+ inta = iwl_read32(priv, CSR_INT);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+ /* Ignore interrupt if there's nothing in NIC to service.
+ * This may be due to IRQ shared with another device,
+ * or due to sporadic interrupts thrown from our NIC. */
+ if (!inta && !inta_fh) {
+ IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+ goto none;
+ }
+
+ if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+ /* Hardware disappeared */
+ IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+ goto none;
+ }
+
+ IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+
+ /* iwl_irq_tasklet() will service interrupts and re-enable them */
+ tasklet_schedule(&priv->irq_tasklet);
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+
+ none:
+ /* re-enable interrupts here since we don't have anything to service. */
+ iwl_enable_interrupts(priv);
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel. We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware. This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel. There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl_eeprom_band_1[14] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl_eeprom_band_2[] = {
+ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */
+ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */
+ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
+ 145, 149, 153, 157, 161, 165
+};
+
+static u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */
+ 1, 2, 3, 4, 5, 6, 7
+};
+
+static u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */
+ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
+};
+
+static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+ int *eeprom_ch_count,
+ const struct iwl_eeprom_channel
+ **eeprom_ch_info,
+ const u8 **eeprom_ch_index)
+{
+ switch (band) {
+ case 1: /* 2.4GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+ *eeprom_ch_info = priv->eeprom.band_1_channels;
+ *eeprom_ch_index = iwl_eeprom_band_1;
+ break;
+ case 2: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+ *eeprom_ch_info = priv->eeprom.band_2_channels;
+ *eeprom_ch_index = iwl_eeprom_band_2;
+ break;
+ case 3: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+ *eeprom_ch_info = priv->eeprom.band_3_channels;
+ *eeprom_ch_index = iwl_eeprom_band_3;
+ break;
+ case 4: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+ *eeprom_ch_info = priv->eeprom.band_4_channels;
+ *eeprom_ch_index = iwl_eeprom_band_4;
+ break;
+ case 5: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+ *eeprom_ch_info = priv->eeprom.band_5_channels;
+ *eeprom_ch_index = iwl_eeprom_band_5;
+ break;
+ case 6:
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
+ *eeprom_ch_info = priv->eeprom.band_24_channels;
+ *eeprom_ch_index = iwl_eeprom_band_6;
+ break;
+ case 7:
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
+ *eeprom_ch_info = priv->eeprom.band_52_channels;
+ *eeprom_ch_index = iwl_eeprom_band_7;
+ break;
+ default:
+ BUG();
+ return;
+ }
+}
+
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+ int phymode, u16 channel)
+{
+ int i;
+
+ switch (phymode) {
+ case MODE_IEEE80211A:
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel == channel)
+ return &priv->channel_info[i];
+ }
+ break;
+
+ case MODE_IEEE80211B:
+ case MODE_IEEE80211G:
+ if (channel >= 1 && channel <= 14)
+ return &priv->channel_info[channel - 1];
+ break;
+
+ }
+
+ return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+ ? # x " " : "")
+
+static int iwl_init_channel_map(struct iwl_priv *priv)
+{
+ int eeprom_ch_count = 0;
+ const u8 *eeprom_ch_index = NULL;
+ const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+ int band, ch;
+ struct iwl_channel_info *ch_info;
+
+ if (priv->channel_count) {
+ IWL_DEBUG_INFO("Channel map already initialized.\n");
+ return 0;
+ }
+
+ if (priv->eeprom.version < 0x2f) {
+ IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+ priv->eeprom.version);
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+ priv->channel_count =
+ ARRAY_SIZE(iwl_eeprom_band_1) +
+ ARRAY_SIZE(iwl_eeprom_band_2) +
+ ARRAY_SIZE(iwl_eeprom_band_3) +
+ ARRAY_SIZE(iwl_eeprom_band_4) +
+ ARRAY_SIZE(iwl_eeprom_band_5);
+
+ IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+ priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+ priv->channel_count, GFP_KERNEL);
+ if (!priv->channel_info) {
+ IWL_ERROR("Could not allocate channel_info\n");
+ priv->channel_count = 0;
+ return -ENOMEM;
+ }
+
+ ch_info = priv->channel_info;
+
+ /* Loop through the 5 EEPROM bands adding them in order to the
+ * channel map we maintain (that contains additional information than
+ * what just in the EEPROM) */
+ for (band = 1; band <= 5; band++) {
+
+ iwl_init_band_reference(priv, band, &eeprom_ch_count,
+ &eeprom_ch_info, &eeprom_ch_index);
+
+ /* Loop through each band adding each of the channels */
+ for (ch = 0; ch < eeprom_ch_count; ch++) {
+ ch_info->channel = eeprom_ch_index[ch];
+ ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+ MODE_IEEE80211A;
+
+ /* permanently store EEPROM's channel regulatory flags
+ * and max power in channel info database. */
+ ch_info->eeprom = eeprom_ch_info[ch];
+
+ /* Copy the run-time flags so they are there even on
+ * invalid channels */
+ ch_info->flags = eeprom_ch_info[ch].flags;
+
+ if (!(is_channel_valid(ch_info))) {
+ IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+ "No traffic\n",
+ ch_info->channel,
+ ch_info->flags,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4");
+ ch_info++;
+ continue;
+ }
+
+ /* Initialize regulatory-based run-time data */
+ ch_info->max_power_avg = ch_info->curr_txpow =
+ eeprom_ch_info[ch].max_power_avg;
+ ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+ ch_info->min_power = 0;
+
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ " %ddBm): Ad-Hoc %ssupported\n",
+ ch_info->channel,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4",
+ CHECK_AND_PRINT(IBSS),
+ CHECK_AND_PRINT(ACTIVE),
+ CHECK_AND_PRINT(RADAR),
+ CHECK_AND_PRINT(WIDE),
+ CHECK_AND_PRINT(NARROW),
+ CHECK_AND_PRINT(DFS),
+ eeprom_ch_info[ch].flags,
+ eeprom_ch_info[ch].max_power_avg,
+ ((eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_IBSS)
+ && !(eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_RADAR))
+ ? "" : "not ");
+
+ /* Set the user_txpower_limit to the highest power
+ * supported by any channel */
+ if (eeprom_ch_info[ch].max_power_avg >
+ priv->user_txpower_limit)
+ priv->user_txpower_limit =
+ eeprom_ch_info[ch].max_power_avg;
+
+ ch_info++;
+ }
+ }
+
+ for (band = 6; band <= 7; band++) {
+ int phymode;
+ u8 fat_extension_chan;
+
+ iwl_init_band_reference(priv, band, &eeprom_ch_count,
+ &eeprom_ch_info, &eeprom_ch_index);
+
+ phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+ /* Loop through each band adding each of the channels */
+ for (ch = 0; ch < eeprom_ch_count; ch++) {
+
+ if ((band == 6) &&
+ ((eeprom_ch_index[ch] == 5) ||
+ (eeprom_ch_index[ch] == 6) ||
+ (eeprom_ch_index[ch] == 7)))
+ fat_extension_chan = HT_IE_EXT_CHANNEL_MAX;
+ else
+ fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
+
+ iwl4965_set_fat_chan_info(priv, phymode,
+ eeprom_ch_index[ch],
+ &(eeprom_ch_info[ch]),
+ fat_extension_chan);
+
+ iwl4965_set_fat_chan_info(priv, phymode,
+ (eeprom_ch_index[ch] + 4),
+ &(eeprom_ch_info[ch]),
+ HT_IE_EXT_CHANNEL_BELOW);
+ }
+ }
+
+ return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req. This should be set long enough to hear probe responses
+ * from more than one AP. */
+#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52 (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
+#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52 (10)
+#define IWL_PASSIVE_DWELL_BASE (100)
+#define IWL_CHANNEL_TUNE_TIME 5
+
+static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ if (phymode == MODE_IEEE80211A)
+ return IWL_ACTIVE_DWELL_TIME_52;
+ else
+ return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ u16 active = iwl_get_active_dwell_time(priv, phymode);
+ u16 passive = (phymode != MODE_IEEE80211A) ?
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+ if (iwl_is_associated(priv)) {
+ /* If we're associated, we clamp the maximum passive
+ * dwell time to be 98% of the beacon interval (minus
+ * 2 * channel tune time) */
+ passive = priv->beacon_int;
+ if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+ passive = IWL_PASSIVE_DWELL_BASE;
+ passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+ }
+
+ if (passive <= active)
+ passive = active + 1;
+
+ return passive;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+ u8 is_active, u8 direct_mask,
+ struct iwl_scan_channel *scan_ch)
+{
+ const struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode;
+ const struct iwl_channel_info *ch_info;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added, i;
+
+ hw_mode = iwl_get_hw_mode(priv, phymode);
+ if (!hw_mode)
+ return 0;
+
+ channels = hw_mode->channels;
+
+ active_dwell = iwl_get_active_dwell_time(priv, phymode);
+ passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+
+ for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+ if (channels[i].chan ==
+ 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 = channels[i].chan;
+
+ ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+ scan_ch->channel);
+ continue;
+ }
+
+ if (!is_active || is_channel_passive(ch_info) ||
+ !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+ scan_ch->type = 0; /* passive */
+ else
+ scan_ch->type = 1; /* active */
+
+ if (scan_ch->type & 1)
+ scan_ch->type |= (direct_mask << 1);
+
+ if (is_channel_narrow(ch_info))
+ scan_ch->type |= (1 << 7);
+
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+ /* Set power levels to defaults */
+ scan_ch->tpc.dsp_atten = 110;
+ /* scan_pwr_info->tpc.dsp_atten; */
+
+ /*scan_pwr_info->tpc.tx_gain; */
+ if (phymode == MODE_IEEE80211A)
+ scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else {
+ scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level
+ scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+ */
+ }
+
+ IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+ scan_ch->channel,
+ (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+ (scan_ch->type & 1) ?
+ active_dwell : passive_dwell);
+
+ scan_ch++;
+ added++;
+ }
+
+ IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+ return added;
+}
+
+static void iwl_reset_channel_flag(struct iwl_priv *priv)
+{
+ int i, j;
+ for (i = 0; i < 3; i++) {
+ struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+ for (j = 0; j < hw_mode->num_channels; j++)
+ hw_mode->channels[j].flag = hw_mode->channels[j].val;
+ }
+}
+
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates)
+{
+ int i;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ rates[i].rate = iwl_rates[i].ieee * 5;
+ rates[i].val = i; /* Rate scaling will work on indexes */
+ rates[i].val2 = i;
+ rates[i].flags = IEEE80211_RATE_SUPPORTED;
+ /* Only OFDM have the bits-per-symbol set */
+ if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+ rates[i].flags |= IEEE80211_RATE_OFDM;
+ else {
+ /*
+ * If CCK 1M then set rate flag to CCK else CCK_2
+ * which is CCK | PREAMBLE2
+ */
+ rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+ IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+ }
+
+ /* Set up which ones are basic rates... */
+ if (IWL_BASIC_RATES_MASK & (1 << i))
+ rates[i].flags |= IEEE80211_RATE_BASIC;
+ }
+
+ iwl4965_init_hw_rates(priv, rates);
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch;
+ struct ieee80211_hw_mode *modes;
+ struct ieee80211_channel *channels;
+ struct ieee80211_channel *geo_ch;
+ struct ieee80211_rate *rates;
+ int i = 0;
+ enum {
+ A = 0,
+ B = 1,
+ G = 2,
+ A_11N = 3,
+ G_11N = 4,
+ };
+ int mode_count = 5;
+
+ if (priv->modes) {
+ IWL_DEBUG_INFO("Geography modes already initialized.\n");
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ return 0;
+ }
+
+ modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+ GFP_KERNEL);
+ if (!modes)
+ return -ENOMEM;
+
+ channels = kzalloc(sizeof(struct ieee80211_channel) *
+ priv->channel_count, GFP_KERNEL);
+ if (!channels) {
+ kfree(modes);
+ return -ENOMEM;
+ }
+
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+ GFP_KERNEL);
+ if (!rates) {
+ kfree(modes);
+ kfree(channels);
+ return -ENOMEM;
+ }
+
+ /* 0 = 802.11a
+ * 1 = 802.11b
+ * 2 = 802.11g
+ */
+
+ /* 5.2GHz channels start after the 2.4GHz channels */
+ modes[A].mode = MODE_IEEE80211A;
+ modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ modes[A].rates = rates;
+ modes[A].num_rates = 8; /* just OFDM */
+ modes[A].rates = &rates[4];
+ modes[A].num_channels = 0;
+
+ modes[B].mode = MODE_IEEE80211B;
+ modes[B].channels = channels;
+ modes[B].rates = rates;
+ modes[B].num_rates = 4; /* just CCK */
+ modes[B].num_channels = 0;
+
+ modes[G].mode = MODE_IEEE80211G;
+ modes[G].channels = channels;
+ modes[G].rates = rates;
+ modes[G].num_rates = 12; /* OFDM & CCK */
+ modes[G].num_channels = 0;
+
+ modes[G_11N].mode = MODE_IEEE80211G;
+ modes[G_11N].channels = channels;
+ modes[G_11N].num_rates = 13; /* OFDM & CCK */
+ modes[G_11N].rates = rates;
+ modes[G_11N].num_channels = 0;
+
+ modes[A_11N].mode = MODE_IEEE80211A;
+ modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ modes[A_11N].rates = &rates[4];
+ modes[A_11N].num_rates = 9; /* just OFDM */
+ modes[A_11N].num_channels = 0;
+
+ priv->ieee_channels = channels;
+ priv->ieee_rates = rates;
+
+ iwl_init_hw_rates(priv, rates);
+
+ for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+ ch = &priv->channel_info[i];
+
+ if (!is_channel_valid(ch)) {
+ IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+ "skipping.\n",
+ ch->channel, is_channel_a_band(ch) ?
+ "5.2" : "2.4");
+ continue;
+ }
+
+ if (is_channel_a_band(ch)) {
+ geo_ch = &modes[A].channels[modes[A].num_channels++];
+ modes[A_11N].num_channels++;
+ } else {
+ geo_ch = &modes[B].channels[modes[B].num_channels++];
+ modes[G].num_channels++;
+ modes[G_11N].num_channels++;
+ }
+
+ geo_ch->freq = ieee80211chan2mhz(ch->channel);
+ geo_ch->chan = ch->channel;
+ geo_ch->power_level = ch->max_power_avg;
+ geo_ch->antenna_max = 0xff;
+
+ if (is_channel_valid(ch)) {
+ geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+ if (ch->flags & EEPROM_CHANNEL_IBSS)
+ geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+ if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+ geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+ if (ch->flags & EEPROM_CHANNEL_RADAR)
+ geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+ if (ch->max_power_avg > priv->max_channel_txpower_limit)
+ priv->max_channel_txpower_limit =
+ ch->max_power_avg;
+ }
+
+ geo_ch->val = geo_ch->flag;
+ }
+
+ if ((modes[A].num_channels == 0) && priv->is_abg) {
+ printk(KERN_INFO DRV_NAME
+ ": Incorrectly detected BG card as ABG. Please send "
+ "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+ priv->pci_dev->device, priv->pci_dev->subsystem_device);
+ priv->is_abg = 0;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+ modes[G].num_channels, modes[A].num_channels);
+
+ /*
+ * NOTE: We register these in preference of order -- the
+ * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+ * a phymode based on rates or AP capabilities but seems to
+ * configure it purely on if the channel being configured
+ * is supported by a mode -- and the first match is taken
+ */
+
+ if (modes[G].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[G]);
+ if (modes[B].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[B]);
+ if (modes[A].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+ priv->modes = modes;
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+ if (priv->ucode_code.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ priv->ucode_code.v_addr,
+ priv->ucode_code.p_addr);
+ priv->ucode_code.v_addr = NULL;
+ }
+ if (priv->ucode_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ priv->ucode_data.v_addr,
+ priv->ucode_data.p_addr);
+ priv->ucode_data.v_addr = NULL;
+ }
+ if (priv->ucode_data_backup.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ priv->ucode_data_backup.v_addr,
+ priv->ucode_data_backup.p_addr);
+ priv->ucode_data_backup.v_addr = NULL;
+ }
+ if (priv->ucode_init.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ priv->ucode_init.v_addr,
+ priv->ucode_init.p_addr);
+ priv->ucode_init.v_addr = NULL;
+ }
+ if (priv->ucode_init_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ priv->ucode_init_data.v_addr,
+ priv->ucode_init_data.p_addr);
+ priv->ucode_init_data.v_addr = NULL;
+ }
+ if (priv->ucode_boot.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ priv->ucode_boot.v_addr,
+ priv->ucode_boot.p_addr);
+ priv->ucode_boot.v_addr = NULL;
+ }
+}
+
+/**
+ * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int rc = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ if (!errcnt)
+ IWL_DEBUG_INFO
+ ("ucode image in INSTRUCTION memory is good\n");
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int rc = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+ i + RTC_INST_LOWER_BOUND);
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+#if 0 /* Enable this if you want to see details */
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ i, val, *image);
+#endif
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int rc = 0;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Show first several data entries in instruction SRAM.
+ * Selection of bootstrap image is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_full(priv, image, len);
+
+ return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl_verify_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ u32 reg;
+ u32 val;
+
+ IWL_DEBUG_INFO("Begin verify bsm\n");
+
+ /* verify BSM SRAM contents */
+ val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+ for (reg = BSM_SRAM_LOWER_BOUND;
+ reg < BSM_SRAM_LOWER_BOUND + len;
+ reg += sizeof(u32), image ++) {
+ val = iwl_read_restricted_reg(priv, reg);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("BSM uCode verification failed at "
+ "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+ BSM_SRAM_LOWER_BOUND,
+ reg - BSM_SRAM_LOWER_BOUND, len,
+ val, le32_to_cpu(*image));
+ return -EIO;
+ }
+ }
+
+ IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+ return 0;
+}
+
+/**
+ * iwl_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL. When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers. Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image. This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program. This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl_load_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ u32 inst_len;
+ u32 data_len;
+ int rc;
+ int i;
+ u32 done;
+ u32 reg_offset;
+
+ IWL_DEBUG_INFO("Begin load bsm\n");
+
+ /* make sure bootstrap program is no larger than BSM's SRAM size */
+ if (len > IWL_MAX_BSM_SIZE)
+ return -EINVAL;
+
+ /* Tell bootstrap uCode where to find the "Initialize" uCode
+ * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+ * NOTE: iwl_initialize_alive_start() will replace these values,
+ * after the "initialize" uCode has run, to point to
+ * runtime/protocol instructions and backup data cache. */
+ pinst = priv->ucode_init.p_addr >> 4;
+ pdata = priv->ucode_init_data.p_addr >> 4;
+ inst_len = priv->ucode_init.len;
+ data_len = priv->ucode_init_data.len;
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+ /* Fill BSM memory with bootstrap instructions */
+ for (reg_offset = BSM_SRAM_LOWER_BOUND;
+ reg_offset < BSM_SRAM_LOWER_BOUND + len;
+ reg_offset += sizeof(u32), image++)
+ _iwl_write_restricted_reg(priv, reg_offset,
+ le32_to_cpu(*image));
+
+ rc = iwl_verify_bsm(priv);
+ if (rc) {
+ iwl_release_restricted_access(priv);
+ return rc;
+ }
+
+ /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+ RTC_INST_LOWER_BOUND);
+ iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+ /* Load bootstrap code into instruction SRAM now,
+ * to prepare to load "initialize" uCode */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START);
+
+ /* Wait for load of bootstrap uCode to finish */
+ for (i = 0; i < 100; i++) {
+ done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+ if (!(done & BSM_WR_CTRL_REG_BIT_START))
+ break;
+ udelay(10);
+ }
+ if (i < 100)
+ IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+ else {
+ IWL_ERROR("BSM write did not complete!\n");
+ return -EIO;
+ }
+
+ /* Enable future boot loads whenever power management unit triggers it
+ * (e.g. when powering back up after power-save shutdown) */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START_EN);
+
+ iwl_release_restricted_access(priv);
+
+ return 0;
+}
+
+static void iwl_nic_start(struct iwl_priv *priv)
+{
+ /* Remove all resets to allow NIC to operate */
+ iwl_write32(priv, CSR_RESET, 0);
+}
+
+/**
+ * iwl_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl_read_ucode(struct iwl_priv *priv)
+{
+ struct iwl_ucode *ucode;
+ int rc = 0;
+ const struct firmware *ucode_raw;
+ const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
+ u8 *src;
+ size_t len;
+ u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+ /* Ask kernel firmware_class module to get the boot firmware off disk.
+ * request_firmware() is synchronous, file is in memory on return. */
+ rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+ if (rc < 0) {
+ IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+ goto error;
+ }
+
+ IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+ name, ucode_raw->size);
+
+ /* Make sure that we got at least our header! */
+ if (ucode_raw->size < sizeof(*ucode)) {
+ IWL_ERROR("File size way too small!\n");
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Data from ucode file: header followed by uCode images */
+ ucode = (void *)ucode_raw->data;
+
+ ver = le32_to_cpu(ucode->ver);
+ inst_size = le32_to_cpu(ucode->inst_size);
+ data_size = le32_to_cpu(ucode->data_size);
+ init_size = le32_to_cpu(ucode->init_size);
+ init_data_size = le32_to_cpu(ucode->init_data_size);
+ boot_size = le32_to_cpu(ucode->boot_size);
+
+ IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+ IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+ inst_size);
+ IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+ data_size);
+ IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+ init_size);
+ IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+ init_data_size);
+ IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+ boot_size);
+
+ /* Verify size of file vs. image size info in file's header */
+ if (ucode_raw->size < sizeof(*ucode) +
+ inst_size + data_size + init_size +
+ init_data_size + boot_size) {
+
+ IWL_DEBUG_INFO("uCode file size %d too small\n",
+ (int)ucode_raw->size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Verify that uCode images will fit in card's SRAM */
+ if (inst_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
+ (int)inst_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ if (data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
+ (int)data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init instr len %d too large to fit in card\n",
+ (int)init_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init data len %d too large to fit in card\n",
+ (int)init_data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (boot_size > IWL_MAX_BSM_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode boot instr len %d too large to fit in bsm\n",
+ (int)boot_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Allocate ucode buffers for card's bus-master loading ... */
+
+ /* Runtime instructions and 2 copies of data:
+ * 1) unmodified from disk
+ * 2) backup cache for save/restore during power-downs */
+ priv->ucode_code.len = inst_size;
+ priv->ucode_code.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ &(priv->ucode_code.p_addr));
+
+ priv->ucode_data.len = data_size;
+ priv->ucode_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ &(priv->ucode_data.p_addr));
+
+ priv->ucode_data_backup.len = data_size;
+ priv->ucode_data_backup.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ &(priv->ucode_data_backup.p_addr));
+
+
+ /* Initialization instructions and data */
+ priv->ucode_init.len = init_size;
+ priv->ucode_init.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ &(priv->ucode_init.p_addr));
+
+ priv->ucode_init_data.len = init_data_size;
+ priv->ucode_init_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ &(priv->ucode_init_data.p_addr));
+
+ /* Bootstrap (instructions only, no data) */
+ priv->ucode_boot.len = boot_size;
+ priv->ucode_boot.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ &(priv->ucode_boot.p_addr));
+
+ if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+ !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
+ !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
+ goto err_pci_alloc;
+
+ /* Copy images into buffers for card's bus-master reads ... */
+
+ /* Runtime instructions (first block of data in file) */
+ src = &ucode->data[0];
+ len = priv->ucode_code.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_code.v_addr, src, len);
+ IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+ priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+ /* Runtime data (2nd block)
+ * NOTE: Copy into backup buffer will be done in iwl_up() */
+ src = &ucode->data[inst_size];
+ len = priv->ucode_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_data.v_addr, src, len);
+ memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+ /* Initialization instructions (3rd block) */
+ if (init_size) {
+ src = &ucode->data[inst_size + data_size];
+ len = priv->ucode_init.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init.v_addr, src, len);
+ }
+
+ /* Initialization data (4th block) */
+ if (init_data_size) {
+ src = &ucode->data[inst_size + data_size + init_size];
+ len = priv->ucode_init_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init_data.v_addr, src, len);
+ }
+
+ /* Bootstrap instructions (5th block) */
+ src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+ len = priv->ucode_boot.len;
+ IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_boot.v_addr, src, len);
+
+ /* We have our copies now, allow OS release its copies */
+ release_firmware(ucode_raw);
+ return 0;
+
+ err_pci_alloc:
+ IWL_ERROR("failed to allocate pci memory\n");
+ rc = -ENOMEM;
+ iwl_dealloc_ucode_pci(priv);
+
+ err_release:
+ release_firmware(ucode_raw);
+
+ error:
+ return rc;
+}
+
+
+/**
+ * iwl_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+{
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ int rc = 0;
+ unsigned long flags;
+
+ /* bits 35:4 for 4965 */
+ pinst = priv->ucode_code.p_addr >> 4;
+ pdata = priv->ucode_data_backup.p_addr >> 4;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* Tell bootstrap uCode where to find image to load */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+ priv->ucode_data.len);
+
+ /* Inst bytecount must be last to set up, bit 31 signals uCode
+ * that all new ptr/size info is in place */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+ priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+ iwl_release_restricted_access(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+ return rc;
+}
+
+/**
+ * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ * Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ * (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl_init_alive_start(struct iwl_priv *priv)
+{
+ /* Check alive response for "valid" sign from uCode */
+ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Initialize Alive failed.\n");
+ goto restart;
+ }
+
+ /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "initialize" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+ goto restart;
+ }
+
+ /* Calculate temperature */
+ priv->temperature = iwl4965_get_temperature(priv);
+
+ /* Send pointers to protocol/runtime uCode image ... init code will
+ * load and launch runtime uCode, which will send us another "Alive"
+ * notification. */
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ if (iwl_set_ucode_ptrs(priv)) {
+ /* Runtime instruction load won't happen;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+ goto restart;
+ }
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ * from protocol/runtime uCode (initialization uCode's
+ * Alive gets handled by iwl_init_alive_start()).
+ */
+static void iwl_alive_start(struct iwl_priv *priv)
+{
+ int rc = 0;
+
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+ if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Alive failed.\n");
+ goto restart;
+ }
+
+ /* Initialize uCode has loaded Runtime uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "runtime" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+ goto restart;
+ }
+
+ iwl_clear_stations_table(priv);
+
+ rc = iwl4965_alive_notify(priv);
+ if (rc) {
+ IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
+ rc);
+ goto restart;
+ }
+
+ /* After the ALIVE response, we can process host commands */
+ set_bit(STATUS_ALIVE, &priv->status);
+
+ /* Clear out the uCode error bit if it is set */
+ clear_bit(STATUS_FW_ERROR, &priv->status);
+
+ rc = iwl_init_channel_map(priv);
+ if (rc) {
+ IWL_ERROR("initializing regulatory failed: %d\n", rc);
+ return;
+ }
+
+ iwl_init_geos(priv);
+
+ if (iwl_is_rfkill(priv))
+ return;
+
+ if (!priv->mac80211_registered) {
+ /* Unlock so any user space entry points can call back into
+ * the driver without a deadlock... */
+ mutex_unlock(&priv->mutex);
+ iwl_rate_control_register(priv->hw);
+ rc = ieee80211_register_hw(priv->hw);
+ priv->hw->conf.beacon_int = 100;
+ mutex_lock(&priv->mutex);
+
+ if (rc) {
+ IWL_ERROR("Failed to register network "
+ "device (error %d)\n", rc);
+ return;
+ }
+
+ priv->mac80211_registered = 1;
+
+ iwl_reset_channel_flag(priv);
+ } else
+ ieee80211_start_queues(priv->hw);
+
+ priv->active_rate = priv->rates_mask;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+ if (iwl_is_associated(priv)) {
+ struct iwl_rxon_cmd *active_rxon =
+ (struct iwl_rxon_cmd *)(&priv->active_rxon);
+
+ memcpy(&priv->staging_rxon, &priv->active_rxon,
+ sizeof(priv->staging_rxon));
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ } else {
+ /* Initialize our rx_config data */
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+ }
+
+ /* Configure BT coexistence */
+ iwl_send_bt_config(priv);
+
+ /* Configure the adapter for unassociated operation */
+ iwl_commit_rxon(priv);
+
+ /* At this point, the NIC is initialized and operational */
+ priv->notif_missed_beacons = 0;
+ set_bit(STATUS_READY, &priv->status);
+
+ iwl4965_rf_kill_ct_config(priv);
+ IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+ if (priv->error_recovering)
+ iwl_error_recovery(priv);
+
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+
+static void __iwl_down(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+ struct ieee80211_conf *conf = NULL;
+
+ IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ if (!exit_pending)
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ iwl_clear_stations_table(priv);
+
+ /* Unblock any waiting calls */
+ wake_up_interruptible_all(&priv->wait_command_queue);
+
+ iwl_cancel_deferred_work(priv);
+
+ /* Wipe out the EXIT_PENDING status bit if we are not actually
+ * exiting the module */
+ if (!exit_pending)
+ clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ /* stop and reset the on-board processor */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ /* If we have not previously called iwl_init() then
+ * clear all bits but the RF Kill and SUSPEND bits and return */
+ if (!iwl_is_init(priv)) {
+ priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND;
+ goto exit;
+ }
+
+ /* ...otherwise clear out all the status bits but the RF Kill and
+ * SUSPEND bits and continue taking the NIC down. */
+ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND |
+ test_bit(STATUS_FW_ERROR, &priv->status) <<
+ STATUS_FW_ERROR;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_txq_ctx_stop(priv);
+ iwl_hw_rxq_stop(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_stop_master(priv);
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ iwl_hw_nic_reset(priv);
+
+ exit:
+ memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+ priv->ibss_beacon = NULL;
+
+ /* clear out any free frames */
+ iwl_clear_free_frames(priv);
+}
+
+static void iwl_down(struct iwl_priv *priv)
+{
+ mutex_lock(&priv->mutex);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+ DECLARE_MAC_BUF(mac);
+ int rc, i;
+ u32 hw_rf_kill = 0;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_WARNING("Exit pending; will not bring the NIC up\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+ IWL_WARNING("Radio disabled by SW RF kill (module "
+ "parameter)\n");
+ return 0;
+ }
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ rc = iwl_hw_nic_init(priv);
+ if (rc) {
+ IWL_ERROR("Unable to int nic\n");
+ return rc;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_enable_interrupts(priv);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* Copy original ucode data image from disk into backup cache.
+ * This will be used to initialize the on-board processor's
+ * data SRAM for a clean start when the runtime program first loads. */
+ memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+ priv->ucode_data.len);
+
+ /* If platform's RF_KILL switch is set to KILL,
+ * wait for BIT_INT_RF_KILL interrupt before loading uCode
+ * and getting things started */
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
+ IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+ return 0;
+ }
+
+ for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+ iwl_clear_stations_table(priv);
+
+ /* load bootstrap state machine,
+ * load bootstrap program into processor's memory,
+ * prepare to load the "initialize" uCode */
+ rc = iwl_load_bsm(priv);
+
+ if (rc) {
+ IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+ continue;
+ }
+
+ /* start card; "initialize" will load runtime ucode */
+ iwl_nic_start(priv);
+
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %s\n",
+ print_mac(mac, priv->mac_addr));
+
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+ IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+ return 0;
+ }
+
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+
+ /* tried to restart and config the device for as long as our
+ * patience could withstand */
+ IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+ return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_init_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, init_alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_init_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_rf_kill(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_rfkill(priv)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+ "HW and/or SW RF Kill no longer active, restarting "
+ "device\n");
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+ } else {
+
+ if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by SW switch\n");
+ else
+ IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+ "Kill switch must be turned off for "
+ "wireless networking to work.\n");
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, scan_check.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_SCANNING, &priv->status) ||
+ test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+ "Scan completion watchdog resetting adapter (%dms)\n",
+ jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_request_scan(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, request_scan);
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_CMD,
+ .len = sizeof(struct iwl_scan_cmd),
+ .meta.flags = CMD_SIZE_HUGE,
+ };
+ int rc = 0;
+ struct iwl_scan_cmd *scan;
+ struct ieee80211_conf *conf = NULL;
+ u8 direct_mask;
+ int phymode;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_WARNING("request scan called when driver not ready.\n");
+ goto done;
+ }
+
+ /* Make sure the scan wasn't cancelled before this queued work
+ * was given the chance to run... */
+ if (!test_bit(STATUS_SCANNING, &priv->status))
+ goto done;
+
+ /* This should never be called or scheduled if there is currently
+ * a scan active in the hardware. */
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+ "Ignoring second request.\n");
+ rc = -EIO;
+ goto done;
+ }
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+ goto done;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n");
+ goto done;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+ goto done;
+ }
+
+ if (!test_bit(STATUS_READY, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n");
+ goto done;
+ }
+
+ if (!priv->scan_bands) {
+ IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+ goto done;
+ }
+
+ if (!priv->scan) {
+ priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+ IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+ if (!priv->scan) {
+ rc = -ENOMEM;
+ goto done;
+ }
+ }
+ scan = priv->scan;
+ memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+ scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+ scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+ if (iwl_is_associated(priv)) {
+ u16 interval = 0;
+ u32 extra;
+ u32 suspend_time = 100;
+ u32 scan_suspend_time = 100;
+ unsigned long flags;
+
+ IWL_DEBUG_INFO("Scanning while associated...\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+ interval = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ scan->suspend_time = 0;
+ scan->max_out_time = cpu_to_le32(600 * 1024);
+ if (!interval)
+ interval = suspend_time;
+
+ extra = (suspend_time / interval) << 22;
+ scan_suspend_time = (extra |
+ ((suspend_time % interval) * 1024));
+ scan->suspend_time = cpu_to_le32(scan_suspend_time);
+ IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+ scan_suspend_time, interval);
+ }
+
+ /* We should add the ability for user to lock to PASSIVE ONLY */
+ if (priv->one_direct_scan) {
+ IWL_DEBUG_SCAN
+ ("Kicking off one direct scan for '%s'\n",
+ iwl_escape_essid(priv->direct_ssid,
+ priv->direct_ssid_len));
+ scan->direct_scan[0].id = WLAN_EID_SSID;
+ scan->direct_scan[0].len = priv->direct_ssid_len;
+ memcpy(scan->direct_scan[0].ssid,
+ priv->direct_ssid, priv->direct_ssid_len);
+ direct_mask = 1;
+ } else if (!iwl_is_associated(priv)) {
+ 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
+ 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 */
+ scan->tx_cmd.len = cpu_to_le16(
+ iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+ IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+ scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+ scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+ scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ /* flags + rate selection */
+
+ scan->tx_cmd.tx_flags |= cpu_to_le32(0x200);
+
+ switch (priv->scan_bands) {
+ case 2:
+ scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+ scan->tx_cmd.rate_n_flags =
+ iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
+ RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
+
+ scan->good_CRC_th = 0;
+ phymode = MODE_IEEE80211G;
+ break;
+
+ case 1:
+ scan->tx_cmd.rate_n_flags =
+ iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
+ RATE_MCS_ANT_B_MSK);
+ scan->good_CRC_th = IWL_GOOD_CRC_TH;
+ phymode = MODE_IEEE80211A;
+ break;
+
+ default:
+ IWL_WARNING("Invalid scan band count\n");
+ goto done;
+ }
+
+ /* select Rx chains */
+
+ /* Force use of chains B and C (0x6) for scan Rx.
+ * Avoid A (0x1) because of its off-channel reception on A-band.
+ * MIMO is not used here, but value is required to make uCode happy. */
+ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
+ cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
+ (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
+ (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
+
+ 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",
+ iwl_escape_essid(priv->essid, priv->essid_len));
+ else
+ IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+ scan->channel_count =
+ iwl_get_channels_for_scan(
+ priv, phymode, 1, /* active */
+ 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 iwl_scan_channel);
+ cmd.data = scan;
+ scan->len = cpu_to_le16(cmd.len);
+
+ set_bit(STATUS_SCAN_HW, &priv->status);
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ goto done;
+
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IWL_SCAN_CHECK_WATCHDOG);
+
+ mutex_unlock(&priv->mutex);
+ return;
+
+ done:
+ /* inform mac80211 sacn aborted */
+ queue_work(priv->workqueue, &priv->scan_completed);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_up(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ __iwl_up(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ iwl_down(priv);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl_bg_rx_replenish(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, rx_replenish);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_rx_replenish(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_post_associate(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv,
+ post_associate.work);
+
+ int rc = 0;
+ struct ieee80211_conf *conf = NULL;
+ DECLARE_MAC_BUF(mac);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+ return;
+ }
+
+ IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+ priv->assoc_id,
+ print_mac(mac, priv->active_rxon.bssid_addr));
+
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+#ifdef CONFIG_IWLWIFI_HT
+ if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
+ iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
+ else {
+ priv->active_rate_ht[0] = 0;
+ priv->active_rate_ht[1] = 0;
+ priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
+ }
+#endif /* CONFIG_IWLWIFI_HT*/
+ iwl4965_set_rxon_chain(priv);
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+ IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+ priv->assoc_id, priv->beacon_int);
+
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ }
+
+ iwl_commit_rxon(priv);
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_STA:
+ iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+
+ /* clear out the station table */
+ iwl_clear_stations_table(priv);
+
+ iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+ iwl_rxon_add_station(priv, priv->bssid, 0);
+ iwl_rate_scale_init(priv->hw, IWL_STA_ID);
+ iwl_send_beacon_cmd(priv);
+
+ break;
+
+ default:
+ IWL_ERROR("%s Should not be called in %d mode\n",
+ __FUNCTION__, priv->iw_mode);
+ break;
+ }
+
+ iwl_sequence_reset(priv);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ /* Enable Rx differential gain and sensitivity calibrations */
+ iwl4965_chain_noise_reset(priv);
+ priv->start_calib = 1;
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->assoc_station_added = 1;
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_activate_qos(priv, 0);
+#endif /* CONFIG_IWLWIFI_QOS */
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ abort_scan);
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ iwl_send_scan_abort(priv);
+
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, scan_completed);
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ ieee80211_scan_completed(priv->hw);
+
+ /* Since setting the TXPOWER may have been deferred while
+ * performing the scan, fire one off */
+ mutex_lock(&priv->mutex);
+ iwl_hw_reg_send_txpower(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl_mac_start(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ /* we should be verifying the device is ready to be opened */
+ mutex_lock(&priv->mutex);
+
+ priv->is_open = 1;
+
+ if (!iwl_is_rfkill(priv))
+ ieee80211_start_queues(priv->hw);
+
+ mutex_unlock(&priv->mutex);
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static void iwl_mac_stop(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+ priv->is_open = 0;
+ /*netif_stop_queue(dev); */
+ flush_workqueue(priv->workqueue);
+ IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ IWL_DEBUG_MAC80211("leave - monitor\n");
+ return -1;
+ }
+
+ IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+ ctl->tx_rate);
+
+ if (iwl_tx_skb(priv, skb, ctl))
+ dev_kfree_skb_any(skb);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+ if (conf->mac_addr)
+ IWL_DEBUG_MAC80211("enter: MAC %s\n",
+ print_mac(mac, conf->mac_addr));
+
+ if (priv->interface_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->interface_id = conf->if_id;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ iwl_set_mode(priv, conf->type);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+ * what is exposed through include/ declrations */
+ if (unlikely(!iwl_param_disable_hw_scan &&
+ test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+ conf->channel, conf->phymode);
+ IWL_DEBUG_MAC80211("leave - invalid channel\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_IWLWIFI_HT
+ /* if we are switching fron ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel)
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+ && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
+#endif
+ )
+ priv->staging_rxon.flags = 0;
+#endif /* CONFIG_IWLWIFI_HT */
+
+ iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+ iwl_set_flags_for_phymode(priv, conf->phymode);
+
+ /* The list of supported rates and rate mask can be different
+ * for each phymode; since the phymode may have changed, reset
+ * the rate mask to what mac80211 lists */
+ iwl_set_rate(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+ if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+ iwl_hw_channel_switch(priv, conf->channel);
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+#endif
+
+ iwl_radio_kill_sw(priv, !conf->radio_enabled);
+
+ if (!conf->radio_enabled) {
+ IWL_DEBUG_MAC80211("leave - radio disabled\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF kill\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ iwl_set_rate(priv);
+
+ if (memcmp(&priv->active_rxon,
+ &priv->staging_rxon, sizeof(priv->staging_rxon)))
+ iwl_commit_rxon(priv);
+ else
+ IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_config_ap(struct iwl_priv *priv)
+{
+ int rc = 0;
+
+ if (priv->status & STATUS_EXIT_PENDING)
+ return;
+
+ /* The following should be done only at AP bring up */
+ if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+ /* RXON - unassoc (to set timing command) */
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ /* RXON Timing */
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ iwl4965_set_rxon_chain(priv);
+
+ /* FIXME: what should be the assoc_id for AP? */
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability &
+ WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+ }
+ /* restore RXON assoc */
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_activate_qos(priv, 1);
+#endif
+ iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+ }
+ iwl_send_beacon_cmd(priv);
+
+ /* FIXME - we need to add code here to detect a totally new
+ * configuration, reset the AP, unassoc, rxon timing, assoc,
+ * clear sta table, add BCAST sta... */
+}
+
+static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+ unsigned long flags;
+ int rc;
+
+ if (conf == NULL)
+ return -EIO;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!conf->beacon || !conf->ssid_len)) {
+ IWL_DEBUG_MAC80211
+ ("Leaving in AP mode because HostAPD is not ready.\n");
+ return 0;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+ if (conf->bssid)
+ IWL_DEBUG_MAC80211("bssid: %s\n",
+ print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+ !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->interface_id != if_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (!conf->bssid) {
+ conf->bssid = priv->mac_addr;
+ memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+ IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+ print_mac(mac, conf->bssid));
+ }
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = conf->beacon;
+ }
+
+ if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+ !is_multicast_ether_addr(conf->bssid)) {
+ /* If there is currently a HW scan going on in the background
+ * then we need to cancel it else the RXON below will fail. */
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress "
+ "after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ mutex_unlock(&priv->mutex);
+ return -EAGAIN;
+ }
+ memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+ /* TODO: Audit driver for usage of these members and see
+ * if mac80211 deprecates them (priv->bssid looks like it
+ * shouldn't be there, but I haven't scanned the IBSS code
+ * to verify) - jpk */
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_config_ap(priv);
+ else {
+ priv->staging_rxon.filter_flags |=
+ RXON_FILTER_ASSOC_MSK;
+ rc = iwl_commit_rxon(priv);
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+ iwl_rxon_add_station(
+ priv, priv->active_rxon.bssid_addr, 1);
+ }
+
+ } else {
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!conf->ssid_len)
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ else
+ memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+ priv->essid_len = conf->ssid_len;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ /*
+ * XXX: dummy
+ * see also iwl_connection_init_rx_config
+ */
+ *total_flags = 0;
+}
+
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ mutex_lock(&priv->mutex);
+ if (priv->interface_id == conf->if_id) {
+ priv->interface_id = 0;
+ memset(priv->bssid, 0, ETH_ALEN);
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ priv->essid_len = 0;
+ }
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!iwl_is_ready_rf(priv)) {
+ rc = -EIO;
+ IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+ goto out_unlock;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
+ rc = -EIO;
+ IWL_ERROR("ERROR: APs don't scan\n");
+ goto out_unlock;
+ }
+
+ /* if we just finished scan ask for delay */
+ if (priv->last_scan_jiffies &&
+ time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+ jiffies)) {
+ rc = -EAGAIN;
+ goto out_unlock;
+ }
+ if (len) {
+ IWL_DEBUG_SCAN("direct scan for "
+ "%s [%d]\n ",
+ iwl_escape_essid(ssid, len), (int)len);
+
+ priv->one_direct_scan = 1;
+ priv->direct_ssid_len = (u8)
+ min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+ memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+ }
+
+ rc = iwl_scan_initiate(priv);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+ int rc = 0;
+ u8 sta_id;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_param_hwcrypto) {
+ IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (is_zero_ether_addr(addr))
+ /* only support pairwise keys */
+ return -EOPNOTSUPP;
+
+ sta_id = iwl_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ switch (cmd) {
+ case SET_KEY:
+ rc = iwl_update_sta_key_info(priv, key, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 1);
+ iwl_commit_rxon(priv);
+ key->hw_key_idx = sta_id;
+ IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+ break;
+ case DISABLE_KEY:
+ rc = iwl_clear_sta_key_info(priv, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 0);
+ iwl_commit_rxon(priv);
+ IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct iwl_priv *priv = hw->priv;
+#ifdef CONFIG_IWLWIFI_QOS
+ unsigned long flags;
+ int q;
+#endif /* CONFIG_IWL_QOS */
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ if (queue >= AC_NUM) {
+ IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+ return 0;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (!priv->qos_data.qos_enable) {
+ priv->qos_data.qos_active = 0;
+ IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+ return 0;
+ }
+ q = AC_NUM - 1 - queue;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+ priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+ priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+ priv->qos_data.def_qos_parm.ac[q].edca_txop =
+ cpu_to_le16((params->burst_time * 100));
+
+ priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ priv->qos_data.qos_active = 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_activate_qos(priv, 1);
+ else if (priv->assoc_id && iwl_is_associated(priv))
+ iwl_activate_qos(priv, 0);
+
+ mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWLWIFI_QOS */
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct iwl_priv *priv = hw->priv;
+ int i, avail;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ unsigned long flags;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < AC_NUM; i++) {
+ txq = &priv->txq[i];
+ q = &txq->q;
+ avail = iwl_queue_space(q);
+
+ stats->data[i].len = q->n_window - avail;
+ stats->data[i].limit = q->n_window - q->high_mark;
+ stats->data[i].count = q->n_window;
+
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+ priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWLWIFI_HT
+ spin_lock_irqsave(&priv->lock, flags);
+ memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+ spin_unlock_irqrestore(&priv->lock, flags);
+#ifdef CONFIG_IWLWIFI_HT_AGG
+/* if (priv->lq_mngr.agg_ctrl.granted_ba)
+ iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
+
+ memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control));
+ priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
+ priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
+ priv->lq_mngr.agg_ctrl.auto_agg = 1;
+
+ if (priv->lq_mngr.agg_ctrl.auto_agg)
+ priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+
+ cancel_delayed_work(&priv->post_associate);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = 0;
+ priv->assoc_capability = 0;
+ priv->call_post_assoc_from_beacon = 0;
+ priv->assoc_station_added = 0;
+
+ /* new association get rid of ibss beacon skb */
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = NULL;
+
+ priv->beacon_int = priv->hw->conf.beacon_int;
+ priv->timestamp1 = 0;
+ priv->timestamp0 = 0;
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ priv->beacon_int = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Per mac80211.h: This is only used in IBSS mode... */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ priv->only_active_channel = 0;
+
+ iwl_set_rate(priv);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ IWL_DEBUG_MAC80211("leave - not IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = skb;
+
+ priv->assoc_id = 0;
+
+ IWL_DEBUG_MAC80211("leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+
+ queue_work(priv->workqueue, &priv->post_associate.work);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+union ht_cap_info {
+ struct {
+ u16 advanced_coding_cap :1;
+ u16 supported_chan_width_set :1;
+ u16 mimo_power_save_mode :2;
+ u16 green_field :1;
+ u16 short_GI20 :1;
+ u16 short_GI40 :1;
+ u16 tx_stbc :1;
+ u16 rx_stbc :1;
+ u16 beam_forming :1;
+ u16 delayed_ba :1;
+ u16 maximal_amsdu_size :1;
+ u16 cck_mode_at_40MHz :1;
+ u16 psmp_support :1;
+ u16 stbc_ctrl_frame_support :1;
+ u16 sig_txop_protection_support :1;
+ };
+ u16 val;
+} __attribute__ ((packed));
+
+union ht_param_info{
+ struct {
+ u8 max_rx_ampdu_factor :2;
+ u8 mpdu_density :3;
+ u8 reserved :3;
+ };
+ u8 val;
+} __attribute__ ((packed));
+
+union ht_exra_param_info {
+ struct {
+ u8 ext_chan_offset :2;
+ u8 tx_chan_width :1;
+ u8 rifs_mode :1;
+ u8 controlled_access_only :1;
+ u8 service_interval_granularity :3;
+ };
+ u8 val;
+} __attribute__ ((packed));
+
+union ht_operation_mode{
+ struct {
+ u16 op_mode :2;
+ u16 non_GF :1;
+ u16 reserved :13;
+ };
+ u16 val;
+} __attribute__ ((packed));
+
+
+static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
+ struct ieee80211_ht_additional_info *ht_extra,
+ struct sta_ht_info *ht_info_ap,
+ struct sta_ht_info *ht_info)
+{
+ union ht_cap_info cap;
+ union ht_operation_mode op_mode;
+ union ht_param_info param_info;
+ union ht_exra_param_info extra_param_info;
+
+ IWL_DEBUG_MAC80211("enter: \n");
+
+ if (!ht_info) {
+ IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
+ return -1;
+ }
+
+ if (ht_cap) {
+ cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
+ param_info.val = ht_cap->mac_ht_params_info;
+ ht_info->is_ht = 1;
+ if (cap.short_GI20)
+ ht_info->sgf |= 0x1;
+ if (cap.short_GI40)
+ ht_info->sgf |= 0x2;
+ ht_info->is_green_field = cap.green_field;
+ ht_info->max_amsdu_size = cap.maximal_amsdu_size;
+ ht_info->supported_chan_width = cap.supported_chan_width_set;
+ ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
+ memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
+
+ ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
+ ht_info->mpdu_density = param_info.mpdu_density;
+
+ IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
+ ht_cap->supported_mcs_set[0],
+ ht_cap->supported_mcs_set[1]);
+
+ if (ht_info_ap) {
+ ht_info->control_channel = ht_info_ap->control_channel;
+ ht_info->extension_chan_offset =
+ ht_info_ap->extension_chan_offset;
+ ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
+ ht_info->operating_mode = ht_info_ap->operating_mode;
+ }
+
+ if (ht_extra) {
+ extra_param_info.val = ht_extra->ht_param;
+ ht_info->control_channel = ht_extra->control_chan;
+ ht_info->extension_chan_offset =
+ extra_param_info.ext_chan_offset;
+ ht_info->tx_chan_width = extra_param_info.tx_chan_width;
+ op_mode.val = (u16)
+ le16_to_cpu(ht_extra->operation_mode);
+ ht_info->operating_mode = op_mode.op_mode;
+ IWL_DEBUG_MAC80211("control channel %d\n",
+ ht_extra->control_chan);
+ }
+ } else
+ ht_info->is_ht = 0;
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap,
+ struct ieee80211_ht_additional_info *ht_extra)
+{
+ struct iwl_priv *priv = hw->priv;
+ int rs;
+
+ IWL_DEBUG_MAC80211("enter: \n");
+
+ rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+ iwl4965_set_rxon_chain(priv);
+
+ if (priv && priv->assoc_id &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->beacon_int)
+ queue_work(priv->workqueue, &priv->post_associate.work);
+ else
+ priv->call_post_assoc_from_beacon = 1;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ IWL_DEBUG_MAC80211("leave: control channel %d\n",
+ ht_extra->control_chan);
+ return rs;
+
+}
+
+static void iwl_set_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap,
+ u8 use_wide_chan)
+{
+ union ht_cap_info cap;
+ union ht_param_info param_info;
+
+ memset(&cap, 0, sizeof(union ht_cap_info));
+ memset(&param_info, 0, sizeof(union ht_param_info));
+
+ cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
+ cap.green_field = 1;
+ cap.short_GI20 = 1;
+ cap.short_GI40 = 1;
+ cap.supported_chan_width_set = use_wide_chan;
+ cap.mimo_power_save_mode = 0x3;
+
+ param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+ param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
+ ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
+ ht_cap->mac_ht_params_info = (u8) param_info.val;
+
+ ht_cap->supported_mcs_set[0] = 0xff;
+ ht_cap->supported_mcs_set[1] = 0xff;
+ ht_cap->supported_mcs_set[4] =
+ (cap.supported_chan_width_set) ? 0x1: 0x0;
+}
+
+static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap)
+{
+ u8 use_wide_channel = 1;
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter: \n");
+ if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+ use_wide_channel = 0;
+
+ /* no fat tx allowed on 2.4GHZ */
+ if (priv->phymode != MODE_IEEE80211A)
+ use_wide_channel = 0;
+
+ iwl_set_ht_capab(hw, ht_cap, use_wide_channel);
+ IWL_DEBUG_MAC80211("leave: \n");
+}
+#endif /*CONFIG_IWLWIFI_HT*/
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 0);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ iwl_debug_level = val;
+
+ return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static ssize_t show_rf_kill(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ /*
+ * 0 - RF kill not enabled
+ * 1 - SW based RF kill active (sysfs)
+ * 2 - HW based RF kill active
+ * 3 - Both HW and SW based RF kill active
+ */
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
+ (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
+
+ return sprintf(buf, "%i\n", val);
+}
+
+static ssize_t store_rf_kill(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ mutex_lock(&priv->mutex);
+ iwl_radio_kill_sw(priv, buf[0] == '1');
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static ssize_t show_temperature(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iwl_priv *priv = d->driver_data;
+ return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in decimal form.\n", buf);
+ else
+ iwl_hw_reg_set_txpower(priv, val);
+
+ return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+ flags);
+ priv->staging_rxon.flags = cpu_to_le32(flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+ "0x%04X\n", filter_flags);
+ priv->staging_rxon.filter_flags =
+ cpu_to_le32(filter_flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+ store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ (priv->phymode << 8) |
+ le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u16 tune = simple_strtoul(p, &p, 0);
+ u8 phymode = (tune >> 8) & 0xff;
+ u16 channel = tune & 0xff;
+
+ IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+ mutex_lock(&priv->mutex);
+ if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+ (priv->phymode != phymode)) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+ if (!ch_info) {
+ IWL_WARNING("Requested invalid phymode/channel "
+ "combination: %d %d\n", phymode, channel);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing phymode and "
+ "rxon.channel = %d %d\n",
+ phymode, channel);
+
+ iwl_set_rxon_channel(priv, phymode, channel);
+ iwl_set_flags_for_phymode(priv, phymode);
+
+ iwl_set_rate(priv);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_spectrum_notification measure_report;
+ u32 size = sizeof(measure_report), len = 0, ofs = 0;
+ u8 *data = (u8 *) & measure_report;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!(priv->measurement_status & MEASUREMENT_READY)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+ }
+ memcpy(&measure_report, &priv->measure_report, size);
+ priv->measurement_status = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct ieee80211_measurement_params params = {
+ .channel = le16_to_cpu(priv->active_rxon.channel),
+ .start_time = cpu_to_le64(priv->last_tsf),
+ .duration = cpu_to_le16(1),
+ };
+ u8 type = IWL_MEASURE_BASIC;
+ u8 buffer[32];
+ u8 channel;
+
+ if (count) {
+ char *p = buffer;
+ strncpy(buffer, buf, min(sizeof(buffer), count));
+ channel = simple_strtoul(p, NULL, 0);
+ if (channel)
+ params.channel = channel;
+
+ p = buffer;
+ while (*p && *p != ' ')
+ p++;
+ if (*p)
+ type = simple_strtoul(p + 1, NULL, 0);
+ }
+
+ IWL_DEBUG_INFO("Invoking measurement of type %d on "
+ "channel %d (for '%s')\n", type, params.channel, buf);
+ iwl_get_measurement(priv, &params, type);
+
+ return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+ show_measurement, store_measurement);
+#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+
+static ssize_t store_retry_rate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ priv->retry_rate = simple_strtoul(buf, NULL, 0);
+ if (priv->retry_rate <= 0)
+ priv->retry_rate = 1;
+
+ return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+ store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int rc;
+ int mode;
+
+ mode = simple_strtoul(buf, NULL, 0);
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+ mode = IWL_POWER_AC;
+ else
+ mode |= IWL_POWER_ENABLED;
+
+ if (mode != priv->power_mode) {
+ rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+ if (rc) {
+ IWL_DEBUG_MAC80211("failed setting power mode.\n");
+ goto out;
+ }
+ priv->power_mode = mode;
+ }
+
+ rc = count;
+
+ out:
+ mutex_unlock(&priv->mutex);
+ return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+ 350000,
+ 250000,
+ 75000,
+ 37000,
+ 25000,
+};
+static const s32 period_duration[] = {
+ 400000,
+ 700000,
+ 1000000,
+ 1000000,
+ 1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int level = IWL_POWER_LEVEL(priv->power_mode);
+ char *p = buf;
+
+ p += sprintf(p, "%d ", level);
+ switch (level) {
+ case IWL_POWER_MODE_CAM:
+ case IWL_POWER_AC:
+ p += sprintf(p, "(AC)");
+ break;
+ case IWL_POWER_BATTERY:
+ p += sprintf(p, "(BATTERY)");
+ break;
+ default:
+ p += sprintf(p,
+ "(Timeout %dms, Period %dms)",
+ timeout_duration[level - 1] / 1000,
+ period_duration[level - 1] / 1000);
+ }
+
+ if (!(priv->power_mode & IWL_POWER_ENABLED))
+ p += sprintf(p, " OFF\n");
+ else
+ p += sprintf(p, " \n");
+
+ return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+ store_power_level);
+
+static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int len = 0, i;
+ struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode = NULL;
+ int count = 0;
+
+ if (!iwl_is_ready(priv))
+ return -EAGAIN;
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+ if (!hw_mode)
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ }
+
+ len +=
+ sprintf(&buf[len],
+ "Displaying %d channels in 2.4GHz band "
+ "(802.11bg):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ } else {
+ channels = NULL;
+ count = 0;
+ }
+
+ len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+ "(802.11a):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ u32 size = sizeof(struct iwl_notif_statistics);
+ u32 len = 0, ofs = 0;
+ u8 *data = (u8 *) & priv->statistics;
+ int rc = 0;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ mutex_lock(&priv->mutex);
+ rc = iwl_send_statistics_request(priv);
+ mutex_unlock(&priv->mutex);
+
+ if (rc) {
+ len = sprintf(buf,
+ "Error sending statistics request: 0x%08X\n", rc);
+ return len;
+ }
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ant;
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (count == 0)
+ return 0;
+
+ if (sscanf(buf, "%1i", &ant) != 1) {
+ IWL_DEBUG_INFO("not in hex or decimal form.\n");
+ return count;
+ }
+
+ if ((ant >= 0) && (ant <= 2)) {
+ IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+ priv->antenna = (enum iwl_antenna)ant;
+ } else
+ IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+ return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+ return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+ priv->workqueue = create_workqueue(DRV_NAME);
+
+ init_waitqueue_head(&priv->wait_command_queue);
+
+ INIT_WORK(&priv->up, iwl_bg_up);
+ INIT_WORK(&priv->restart, iwl_bg_restart);
+ INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+ INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+ INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+ INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+ INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+ INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+ INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
+ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+ INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
+ INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+ iwl_hw_setup_deferred_work(priv);
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+ iwl_hw_cancel_deferred_work(priv);
+
+ cancel_delayed_work(&priv->scan_check);
+ cancel_delayed_work(&priv->alive_start);
+ cancel_delayed_work(&priv->post_associate);
+ cancel_work_sync(&priv->beacon_update);
+}
+
+static struct attribute *iwl_sysfs_entries[] = {
+ &dev_attr_antenna.attr,
+ &dev_attr_channels.attr,
+ &dev_attr_dump_errors.attr,
+ &dev_attr_dump_events.attr,
+ &dev_attr_flags.attr,
+ &dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ &dev_attr_measurement.attr,
+#endif
+ &dev_attr_power_level.attr,
+ &dev_attr_retry_rate.attr,
+ &dev_attr_rf_kill.attr,
+ &dev_attr_rs_window.attr,
+ &dev_attr_statistics.attr,
+ &dev_attr_status.attr,
+ &dev_attr_temperature.attr,
+ &dev_attr_tune.attr,
+ &dev_attr_tx_power.attr,
+
+ NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwl_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl_hw_ops = {
+ .tx = iwl_mac_tx,
+ .start = iwl_mac_start,
+ .stop = iwl_mac_stop,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .config = iwl_mac_config,
+ .config_interface = iwl_mac_config_interface,
+ .configure_filter = iwl_configure_filter,
+ .set_key = iwl_mac_set_key,
+ .get_stats = iwl_mac_get_stats,
+ .get_tx_stats = iwl_mac_get_tx_stats,
+ .conf_tx = iwl_mac_conf_tx,
+ .get_tsf = iwl_mac_get_tsf,
+ .reset_tsf = iwl_mac_reset_tsf,
+ .beacon_update = iwl_mac_beacon_update,
+#ifdef CONFIG_IWLWIFI_HT
+ .conf_ht = iwl_mac_conf_ht,
+ .get_ht_capab = iwl_mac_get_ht_capab,
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ .ht_tx_agg_start = iwl_mac_ht_tx_agg_start,
+ .ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop,
+ .ht_rx_agg_start = iwl_mac_ht_rx_agg_start,
+ .ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop,
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ .hw_scan = iwl_mac_hw_scan
+};
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = 0;
+ struct iwl_priv *priv;
+ struct ieee80211_hw *hw;
+ int i;
+
+ if (iwl_param_disable_hw_scan) {
+ IWL_DEBUG_INFO("Disabling hw_scan\n");
+ iwl_hw_ops.hw_scan = NULL;
+ }
+
+ if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+ (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+ IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+ IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* mac80211 allocates memory for this device instance, including
+ * space for this driver's private structure */
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+ if (hw == NULL) {
+ IWL_ERROR("Can not allocate network device\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+
+ IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+ priv = hw->priv;
+ priv->hw = hw;
+
+ priv->pci_dev = pdev;
+ priv->antenna = (enum iwl_antenna)iwl_param_antenna;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ iwl_debug_level = iwl_param_debug;
+ atomic_set(&priv->restrict_refcnt, 0);
+#endif
+ priv->retry_rate = 1;
+
+ priv->ibss_beacon = NULL;
+
+ /* Tell mac80211 and its clients (e.g. Wireless Extensions)
+ * the range of signal quality values that we'll provide.
+ * Negative values for level/noise indicate that we'll provide dBm.
+ * For WE, at least, non-0 values here *enable* display of values
+ * in app (iwconfig). */
+ hw->max_rssi = -20; /* signal level, negative indicates dBm */
+ hw->max_noise = -20; /* noise level, negative indicates dBm */
+ hw->max_signal = 100; /* link quality indication (%) */
+
+ /* Tell mac80211 our Tx characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+ hw->queues = 4;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ hw->queues = 16;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+ spin_lock_init(&priv->lq_mngr.lock);
+
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+
+ mutex_init(&priv->mutex);
+ if (pci_enable_device(pdev)) {
+ err = -ENODEV;
+ goto out_ieee80211_free_hw;
+ }
+
+ pci_set_master(pdev);
+
+ iwl_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->phymode = -1;
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+ goto out_pci_disable_device;
+ }
+
+ pci_set_drvdata(pdev, priv);
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto out_pci_disable_device;
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+ priv->hw_base = pci_iomap(pdev, 0, 0);
+ if (!priv->hw_base) {
+ err = -ENODEV;
+ goto out_pci_release_regions;
+ }
+
+ IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
+ IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+ /* Initialize module parameter values here */
+
+ if (iwl_param_disable) {
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ IWL_DEBUG_INFO("Radio disabled.\n");
+ }
+
+ priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+ priv->ps_mode = 0;
+ priv->use_ant_b_for_management_frame = 1; /* start with ant B */
+ priv->is_ht_enabled = 1;
+ priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
+ priv->valid_antenna = 0x7; /* assume all 3 connected */
+ priv->ps_mode = IWL_MIMO_PS_NONE;
+ priv->cck_power_index_compensation = iwl_read32(
+ priv, CSR_HW_REV_WA_REG);
+
+ iwl4965_set_rxon_chain(priv);
+
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel Wireless WiFi Link 4965AGN\n");
+
+ /* Device-specific setup */
+ if (iwl_hw_set_hw_setting(priv)) {
+ IWL_ERROR("failed to set hw settings\n");
+ mutex_unlock(&priv->mutex);
+ goto out_iounmap;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (iwl_param_qos_enable)
+ priv->qos_data.qos_enable = 1;
+
+ iwl_reset_qos(priv);
+
+ priv->qos_data.qos_active = 0;
+ priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWLWIFI_QOS */
+
+ iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+ iwl_setup_deferred_work(priv);
+ iwl_setup_rx_handlers(priv);
+
+ priv->rates_mask = IWL_RATES_MASK;
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IWL_POWER_AC;
+ priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+ pci_enable_msi(pdev);
+
+ err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
+ if (err) {
+ IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+ goto out_disable_msi;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+ if (err) {
+ IWL_ERROR("failed to create sysfs device attributes\n");
+ mutex_unlock(&priv->mutex);
+ goto out_release_irq;
+ }
+
+ /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+ * ucode filename and max sizes are card-specific. */
+ err = iwl_read_ucode(priv);
+ if (err) {
+ IWL_ERROR("Could not read microcode: %d\n", err);
+ mutex_unlock(&priv->mutex);
+ goto out_pci_alloc;
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_INFO("Queing UP work.\n");
+
+ queue_work(priv->workqueue, &priv->up);
+
+ return 0;
+
+ out_pci_alloc:
+ iwl_dealloc_ucode_pci(priv);
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ out_release_irq:
+ free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+ pci_disable_msi(pdev);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ iwl_unset_hw_setting(priv);
+
+ out_iounmap:
+ pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+ pci_release_regions(pdev);
+ out_pci_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+ ieee80211_free_hw(priv->hw);
+ out:
+ return err;
+}
+
+static void iwl_pci_remove(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct list_head *p, *q;
+ int i;
+
+ if (!priv)
+ return;
+
+ IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+ mutex_lock(&priv->mutex);
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+
+ /* Free MAC hash list for ADHOC */
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
+ list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+ list_del(p);
+ kfree(list_entry(p, struct iwl_ibss_seq, list));
+ }
+ }
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ iwl_dealloc_ucode_pci(priv);
+
+ if (priv->rxq.bd)
+ iwl_rx_queue_free(priv, &priv->rxq);
+ iwl_hw_txq_ctx_free(priv);
+
+ iwl_unset_hw_setting(priv);
+ iwl_clear_stations_table(priv);
+
+ if (priv->mac80211_registered) {
+ ieee80211_unregister_hw(priv->hw);
+ iwl_rate_control_unregister(priv->hw);
+ }
+
+ /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+ * priv->workqueue... so we can't take down the workqueue
+ * until now... */
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+
+ free_irq(pdev->irq, priv);
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, priv->hw_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(priv->channel_info);
+
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+ /* Take down the device; powers it off, etc. */
+ __iwl_down(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_resume(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ /* The following it a temporary work around due to the
+ * suspend / resume not fully initializing the NIC correctly.
+ * Without all of the following, resume will not attempt to take
+ * down the NIC (it shouldn't really need to) and will just try
+ * and bring the NIC back up. However that fails during the
+ * ucode verification process. This then causes iwl_down to be
+ * called *after* iwl_hw_nic_init() has succeeded -- which
+ * then lets the next init sequence succeed. So, we've
+ * replicated all of that NIC init code here... */
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ iwl_hw_nic_init(priv);
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_reset(priv);
+
+ /* Bring the device back up */
+ clear_bit(STATUS_IN_SUSPEND, &priv->status);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl_pci_resume(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ int err;
+
+ printk(KERN_INFO "Coming out of suspend...\n");
+
+ mutex_lock(&priv->mutex);
+
+ pci_set_power_state(pdev, PCI_D0);
+ err = pci_enable_device(pdev);
+ pci_restore_state(pdev);
+
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+
+ iwl_resume(priv);
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl_driver = {
+ .name = DRV_NAME,
+ .id_table = iwl_hw_card_ids,
+ .probe = iwl_pci_probe,
+ .remove = __devexit_p(iwl_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
+#endif
+};
+
+static int __init iwl_init(void)
+{
+
+ int ret;
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ ret = pci_register_driver(&iwl_driver);
+ if (ret) {
+ IWL_ERROR("Unable to initialize PCI module\n");
+ return ret;
+ }
+#ifdef CONFIG_IWLWIFI_DEBUG
+ ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+ if (ret) {
+ IWL_ERROR("Unable to create driver sysfs file\n");
+ pci_unregister_driver(&iwl_driver);
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static void __exit iwl_exit(void)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#endif
+ pci_unregister_driver(&iwl_driver);
+}
+
+module_param_named(antenna, iwl_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+ "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h
new file mode 100644
index 000000000000..e0b97c341215
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwlwifi.h
@@ -0,0 +1,713 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwlwifi_h__
+#define __iwlwifi_h__
+
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+struct iwl_priv;
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl_hw_card_ids[];
+
+#if IWL == 3945
+
+#define DRV_NAME "iwl3945"
+#include "iwl-hw.h"
+#include "iwl-3945-hw.h"
+
+#elif IWL == 4965
+
+#define DRV_NAME "iwl4965"
+#include "iwl-hw.h"
+#include "iwl-4965-hw.h"
+
+#endif
+
+#include "iwl-prph.h"
+
+/*
+ * Driver implementation data structures, constants, inline
+ * functions
+ *
+ * NOTE: DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE
+ *
+ * Hardware specific declrations go into iwl-*hw.h
+ *
+ */
+
+#include "iwl-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ * This may be because we're:
+ * 1) Not associated (4965, no beacon statistics being sent to driver)
+ * 2) Scanning (noise measurement does not apply to associated channel)
+ * 3) Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ * Also, -127 works better than 0 when averaging frames with/without
+ * noise info (e.g. averaging might be done in app); measured dBm values are
+ * always negative ... using a negative value as the default keeps all
+ * averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl_param_disable_hw_scan;
+extern int iwl_param_debug;
+extern int iwl_param_mode;
+extern int iwl_param_disable;
+extern int iwl_param_antenna;
+extern int iwl_param_hwcrypto;
+extern int iwl_param_qos_enable;
+extern int iwl_param_queues_num;
+
+enum iwl_antenna {
+ IWL_ANTENNA_DIVERSITY,
+ IWL_ANTENNA_MAIN,
+ IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ * a value of 0 means RTS on all data/management packets
+ * a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ * than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD 2347U
+#define MIN_RTS_THRESHOLD 0U
+#define MAX_RTS_THRESHOLD 2347U
+#define MAX_MSDU_SIZE 2304U
+#define MAX_MPDU_SIZE 2346U
+#define DEFAULT_BEACON_INTERVAL 100U
+#define DEFAULT_SHORT_RETRY_LIMIT 7U
+#define DEFAULT_LONG_RETRY_LIMIT 4U
+
+struct iwl_rx_mem_buffer {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+ struct list_head list;
+};
+
+struct iwl_rt_rx_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ __le64 rt_tsf; /* TSF */
+ u8 rt_flags; /* radiotap packet flags */
+ u8 rt_rate; /* rate in 500kb/s */
+ __le16 rt_channelMHz; /* channel in MHz */
+ __le16 rt_chbitmask; /* channel bitfield */
+ s8 rt_dbmsignal; /* signal in dBm, kluged to signed */
+ s8 rt_dbmnoise;
+ u8 rt_antenna; /* antenna number */
+ u8 payload[0]; /* payload... */
+} __attribute__ ((packed));
+
+struct iwl_rt_tx_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u8 rt_rate; /* rate in 500kb/s */
+ __le16 rt_channel; /* channel in mHz */
+ __le16 rt_chbitmask; /* channel bitfield */
+ s8 rt_dbmsignal; /* signal in dBm, kluged to signed */
+ u8 rt_antenna; /* antenna number */
+ u8 payload[0]; /* payload... */
+} __attribute__ ((packed));
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl_queue {
+ int n_bd; /* number of BDs in this queue */
+ int first_empty; /* 1-st empty entry (index) host_w*/
+ int last_used; /* last used entry (index) host_r*/
+ dma_addr_t dma_addr; /* physical addr for BD's */
+ int n_window; /* safe queue window */
+ u32 id;
+ int low_mark; /* low watermark, resume queue if free
+ * space more than this */
+ int high_mark; /* high watermark, stop queue if free
+ * space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS (20)
+
+struct iwl_tx_info {
+ struct ieee80211_tx_status status;
+ struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl_tx_queue - Tx Queue for DMA
+ * @need_update: need to update read/write index
+ * @shed_retry: queue is HT AGG enabled
+ *
+ * Queue consists of circular buffer of BD's and required locking structures.
+ */
+struct iwl_tx_queue {
+ struct iwl_queue q;
+ struct iwl_tfd_frame *bd;
+ struct iwl_cmd *cmd;
+ dma_addr_t dma_addr_cmd;
+ struct iwl_tx_info *txb;
+ int need_update;
+ int sched_retry;
+ int active;
+};
+
+#include "iwl-channel.h"
+
+#if IWL == 3945
+#include "iwl-3945-rs.h"
+#else
+#include "iwl-4965-rs.h"
+#endif
+
+#define IWL_TX_FIFO_AC0 0
+#define IWL_TX_FIFO_AC1 1
+#define IWL_TX_FIFO_AC2 2
+#define IWL_TX_FIFO_AC3 3
+#define IWL_TX_FIFO_HCCA_1 5
+#define IWL_TX_FIFO_HCCA_2 6
+#define IWL_TX_FIFO_NONE 7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES 4
+
+/* Power management (not Tx power) structures */
+
+struct iwl_power_vec_entry {
+ struct iwl_powertable_cmd cmd;
+ u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0 (0)
+#define IWL_POWER_RANGE_1 (1)
+
+#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3 0x03
+#define IWL_POWER_INDEX_5 0x05
+#define IWL_POWER_AC 0x06
+#define IWL_POWER_BATTERY 0x07
+#define IWL_POWER_LIMIT 0x07
+#define IWL_POWER_MASK 0x0F
+#define IWL_POWER_ENABLED 0x10
+#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK)
+
+struct iwl_power_mgr {
+ spinlock_t lock;
+ struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC];
+ struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC];
+ u8 active_index;
+ u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN 2304
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl_frame {
+ union {
+ struct ieee80211_hdr frame;
+ struct iwl_tx_beacon_cmd beacon;
+ u8 raw[IEEE80211_FRAME_LEN];
+ u8 cmd[360];
+ } u;
+ struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME (0x4000)
+#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+ /* CMD_SIZE_NORMAL = 0, */
+ CMD_SIZE_HUGE = (1 << 0),
+ /* CMD_SYNC = 0, */
+ CMD_ASYNC = (1 << 1),
+ /* CMD_NO_SKB = 0, */
+ CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl_cmd;
+struct iwl_priv;
+
+struct iwl_cmd_meta {
+ struct iwl_cmd_meta *source;
+ union {
+ struct sk_buff *skb;
+ int (*callback)(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb);
+ } __attribute__ ((packed)) u;
+
+ /* The CMD_SIZE_HUGE flag bit indicates that the command
+ * structure is stored at the end of the shared queue memory. */
+ u32 flags;
+
+} __attribute__ ((packed));
+
+struct iwl_cmd {
+ struct iwl_cmd_meta meta;
+ struct iwl_cmd_header hdr;
+ union {
+ struct iwl_addsta_cmd addsta;
+ struct iwl_led_cmd led;
+ u32 flags;
+ u8 val8;
+ u16 val16;
+ u32 val32;
+ struct iwl_bt_cmd bt;
+ struct iwl_rxon_time_cmd rxon_time;
+ struct iwl_powertable_cmd powertable;
+ struct iwl_qosparam_cmd qosparam;
+ struct iwl_tx_cmd tx;
+ struct iwl_tx_beacon_cmd tx_beacon;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ u8 *indirect;
+ u8 payload[360];
+ } __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl_host_cmd {
+ u8 id;
+ u16 len;
+ struct iwl_cmd_meta meta;
+ const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+ sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
+
+/**
+ * struct iwl_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+ __le32 *bd;
+ dma_addr_t dma_addr;
+ struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+ struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+ u32 processed;
+ u32 read;
+ u32 write;
+ u32 free_count;
+ struct list_head rx_free;
+ struct list_head rx_used;
+ int need_update;
+ spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN 8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS 252
+#define MIN_A_CHANNELS 7
+
+#define MAX_B_CHANNELS 14
+#define MIN_B_CHANNELS 1
+
+#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
+#define STATUS_INT_ENABLED 1
+#define STATUS_RF_KILL_HW 2
+#define STATUS_RF_KILL_SW 3
+#define STATUS_INIT 4
+#define STATUS_ALIVE 5
+#define STATUS_READY 6
+#define STATUS_TEMPERATURE 7
+#define STATUS_GEO_CONFIGURED 8
+#define STATUS_EXIT_PENDING 9
+#define STATUS_IN_SUSPEND 10
+#define STATUS_STATISTICS 11
+#define STATUS_SCANNING 12
+#define STATUS_SCAN_ABORTING 13
+#define STATUS_SCAN_HW 14
+#define STATUS_POWER_PMI 15
+#define STATUS_FW_ERROR 16
+
+#define MAX_TID_COUNT 9
+
+#define IWL_INVALID_RATE 0xFF
+#define IWL_INVALID_VALUE -1
+
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_ht_agg {
+ u16 txq_id;
+ u16 frame_count;
+ u16 wait_for_ba;
+ u16 start_idx;
+ u32 bitmap0;
+ u32 bitmap1;
+ u32 rate_n_flags;
+};
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+
+struct iwl_tid_data {
+ u16 seq_number;
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ struct iwl_ht_agg agg;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+};
+
+struct iwl_hw_key {
+ enum ieee80211_key_alg alg;
+ int keylen;
+ u8 key[32];
+};
+
+union iwl_ht_rate_supp {
+ u16 rates;
+ struct {
+ u8 siso_rate;
+ u8 mimo_rate;
+ };
+};
+
+#ifdef CONFIG_IWLWIFI_HT
+#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
+#define HT_IE_MAX_AMSDU_SIZE_4K (0)
+#define CFG_HT_MPDU_DENSITY_2USEC (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+struct sta_ht_info {
+ u8 is_ht;
+ u16 rx_mimo_ps_mode;
+ u16 tx_mimo_ps_mode;
+ u16 control_channel;
+ u8 max_amsdu_size;
+ u8 ampdu_factor;
+ u8 mpdu_density;
+ u8 operating_mode;
+ u8 supported_chan_width;
+ u8 extension_chan_offset;
+ u8 is_green_field;
+ u8 sgf;
+ u8 supp_rates[16];
+ u8 tx_chan_width;
+ u8 chan_width_cap;
+};
+#endif /*CONFIG_IWLWIFI_HT */
+
+#ifdef CONFIG_IWLWIFI_QOS
+
+union iwl_qos_capabity {
+ struct {
+ u8 edca_count:4; /* bit 0-3 */
+ u8 q_ack:1; /* bit 4 */
+ u8 queue_request:1; /* bit 5 */
+ u8 txop_request:1; /* bit 6 */
+ u8 reserved:1; /* bit 7 */
+ } q_AP;
+ struct {
+ u8 acvo_APSD:1; /* bit 0 */
+ u8 acvi_APSD:1; /* bit 1 */
+ u8 ac_bk_APSD:1; /* bit 2 */
+ u8 ac_be_APSD:1; /* bit 3 */
+ u8 q_ack:1; /* bit 4 */
+ u8 max_len:2; /* bit 5-6 */
+ u8 more_data_ack:1; /* bit 7 */
+ } q_STA;
+ u8 val;
+};
+
+/* QoS sturctures */
+struct iwl_qos_info {
+ int qos_enable;
+ int qos_active;
+ union iwl_qos_capabity qos_cap;
+ struct iwl_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWLWIFI_QOS */
+
+#define STA_PS_STATUS_WAKE 0
+#define STA_PS_STATUS_SLEEP 1
+
+struct iwl_station_entry {
+ struct iwl_addsta_cmd sta;
+ struct iwl_tid_data tid[MAX_TID_COUNT];
+#if IWL == 3945
+ union {
+ struct {
+ u8 rate;
+ u8 flags;
+ } s;
+ u16 rate_n_flags;
+ } current_rate;
+#endif
+ u8 used;
+ u8 ps_status;
+ struct iwl_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_image_desc {
+ void *v_addr; /* access by driver */
+ dma_addr_t p_addr; /* access by card's busmaster DMA */
+ u32 len; /* bytes */
+};
+
+/* uCode file layout */
+struct iwl_ucode {
+ __le32 ver; /* major/minor/subminor */
+ __le32 inst_size; /* bytes of runtime instructions */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of initialization instructions */
+ __le32 init_data_size; /* bytes of initialization data */
+ __le32 boot_size; /* bytes of bootstrap instructions */
+ u8 data[0]; /* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl_ibss_seq {
+ u8 mac[ETH_ALEN];
+ u16 seq_num;
+ u16 frag_num;
+ unsigned long packet_time;
+ struct list_head list;
+};
+
+struct iwl_driver_hw_info {
+ u16 max_txq_num;
+ u16 ac_queue_count;
+ u32 rx_buffer_size;
+ u16 tx_cmd_len;
+ u16 max_rxq_size;
+ u16 max_rxq_log;
+ u32 cck_flag;
+ u8 max_stations;
+ u8 bcast_sta_id;
+ void *shared_virt;
+ dma_addr_t shared_phys;
+};
+
+
+#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS (19)
+#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS (23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23)
+#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
+#define HT_SHORT_GI_40MHZ_ONLY (1 << 1)
+
+
+#include "iwl-priv.h"
+
+/* Requires full declaration of iwl_priv before including */
+#include "iwl-io.h"
+
+#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\
+ x->u.rx_frame.stats.payload + \
+ x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\
+ IWL_RX_HDR(x)->payload + \
+ le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl_addsta_cmd;
+extern int iwl_send_add_station(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags);
+extern const char *iwl_get_tx_fail_reason(u32 status);
+extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid,
+ int is_ap, u8 flags);
+extern int iwl_is_network_packet(struct iwl_priv *priv,
+ struct ieee80211_hdr *header);
+extern int iwl_power_init_handle(struct iwl_priv *priv);
+extern int iwl_eeprom_init(struct iwl_priv *priv);
+#ifdef CONFIG_IWLWIFI_DEBUG
+extern void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header,
+ int group100) {}
+#endif
+extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ void *data, short len,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags);
+extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr
+ *header);
+extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+extern int iwl_rx_queue_alloc(struct iwl_priv *priv);
+extern void iwl_rx_queue_reset(struct iwl_priv *priv,
+ struct iwl_rx_queue *rxq);
+extern int iwl_calc_db_from_ratio(int sig_ratio);
+extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, int count, u32 id);
+extern int iwl_rx_queue_restock(struct iwl_priv *priv);
+extern void iwl_rx_replenish(void *data);
+extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
+ const void *data);
+extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
+extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left);
+extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_rx_queue *q);
+extern int iwl_send_statistics_request(struct iwl_priv *priv);
+extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+ u32 decrypt_res,
+ struct ieee80211_rx_status *stats);
+extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+
+extern const u8 BROADCAST_ADDR[ETH_ALEN];
+
+/*
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id,
+ u16 tx_rate, u8 flags);
+
+static inline int iwl_is_associated(struct iwl_priv *priv)
+{
+ return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE: The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl_ <-- Its part of iwlwifi (should be changed to iwl_)
+ * iwl_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl_bg_ <-- Called from work queue context
+ * iwl_mac_ <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv);
+extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv);
+extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv);
+extern int iwl_hw_rxq_stop(struct iwl_priv *priv);
+extern int iwl_hw_set_hw_setting(struct iwl_priv *priv);
+extern int iwl_hw_nic_init(struct iwl_priv *priv);
+extern void iwl_hw_card_show_info(struct iwl_priv *priv);
+extern int iwl_hw_nic_stop_master(struct iwl_priv *priv);
+extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
+extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv);
+extern int iwl_hw_nic_reset(struct iwl_priv *priv);
+extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
+ dma_addr_t addr, u16 len);
+extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+extern int iwl_hw_get_temperature(struct iwl_priv *priv);
+extern int iwl_hw_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate);
+extern int iwl_hw_get_rx_read(struct iwl_priv *priv);
+extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr,
+ int sta_id, int tx_id);
+extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv);
+extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
+extern void iwl_hw_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+extern void iwl_disable_events(struct iwl_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+
+/**
+ * iwl_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE: This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
+ */
+extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+
+extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel);
+extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+#endif
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
index 4cf0ff7b833d..9cf0211de67f 100644
--- a/drivers/net/wireless/libertas/11d.c
+++ b/drivers/net/wireless/libertas/11d.c
@@ -124,17 +124,17 @@ static u8 wlan_channel_known_11d(u8 chan,
u8 nr_chan = parsed_region_chan->nr_chan;
u8 i = 0;
- lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
sizeof(struct chan_power_11d) * nr_chan);
for (i = 0; i < nr_chan; i++) {
if (chan == chanpwr[i].chan) {
- lbs_deb_11d("11D: Found Chan:%d\n", chan);
+ lbs_deb_11d("found chan %d\n", chan);
return 1;
}
}
- lbs_deb_11d("11D: Not Find Chan:%d\n", chan);
+ lbs_deb_11d("chan %d not found\n", chan);
return 0;
}
@@ -174,8 +174,8 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
COUNTRY_CODE_LEN);
- lbs_deb_11d("11D:nrchan=%d\n", nr_chan);
- lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+ lbs_deb_11d("nrchan %d\n", nr_chan);
+ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
sizeof(struct parsed_region_chan_11d));
for (i = 0; i < nr_chan; i++) {
@@ -213,7 +213,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
domaininfo->nr_subband = nr_subband;
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
- lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+ lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
COUNTRY_CODE_LEN + 1 +
sizeof(struct ieeetypes_subbandset) * nr_subband);
return 0;
@@ -233,13 +233,13 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_
struct chan_freq_power *cfp;
if (region_chan == NULL) {
- lbs_deb_11d("11D: region_chan is NULL\n");
+ lbs_deb_11d("region_chan is NULL\n");
return;
}
cfp = region_chan->CFP;
if (cfp == NULL) {
- lbs_deb_11d("11D: cfp equal NULL \n");
+ lbs_deb_11d("cfp is NULL \n");
return;
}
@@ -248,19 +248,19 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_
memcpy(parsed_region_chan->countrycode,
wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
- lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+ lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
parsed_region_chan->band);
for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
parsed_region_chan->chanpwr[i].chan = cfp->channel;
parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
- lbs_deb_11d("11D: Chan[%d] Pwr[%d]\n",
+ lbs_deb_11d("chan %d, pwr %d\n",
parsed_region_chan->chanpwr[i].chan,
parsed_region_chan->chanpwr[i].pwr);
}
parsed_region_chan->nr_chan = region_chan->nrcfp;
- lbs_deb_11d("11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+ lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
return;
}
@@ -336,7 +336,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
6. Others
*/
- lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+ lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
if ((*(countryinfo->countrycode)) == 0
|| (countryinfo->len <= COUNTRY_CODE_LEN)) {
@@ -349,7 +349,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
wlan_region_2_code(countryinfo->countrycode);
lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
- lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+ lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
COUNTRY_CODE_LEN);
parsed_region_chan->band = band;
@@ -364,7 +364,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
if (countryinfo->subband[j].firstchan <= lastchan) {
/*Step2&3. Check First Chan Num increment and no overlap */
- lbs_deb_11d("11D: Chan[%d>%d] Overlap\n",
+ lbs_deb_11d("chan %d>%d, overlap\n",
countryinfo->subband[j].firstchan, lastchan);
continue;
}
@@ -393,7 +393,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
} else {
/*not supported and ignore the chan */
lbs_deb_11d(
- "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+ "i %d, chan %d unsupported in region %x, band %d\n",
i, curchan, region, band);
}
}
@@ -405,7 +405,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
parsed_region_chan->nr_chan = idx;
lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
- lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
done:
@@ -422,15 +422,15 @@ done:
u8 libertas_get_scan_type_11d(u8 chan,
struct parsed_region_chan_11d * parsed_region_chan)
{
- u8 scan_type = cmd_scan_type_passive;
+ u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
lbs_deb_enter(LBS_DEB_11D);
if (wlan_channel_known_11d(chan, parsed_region_chan)) {
- lbs_deb_11d("11D: Found and do Active Scan\n");
- scan_type = cmd_scan_type_active;
+ lbs_deb_11d("found, do active scan\n");
+ scan_type = CMD_SCAN_TYPE_ACTIVE;
} else {
- lbs_deb_11d("11D: Not Find and do Passive Scan\n");
+ lbs_deb_11d("not found, do passive scan\n");
}
lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
@@ -446,25 +446,6 @@ void libertas_init_11d(wlan_private * priv)
return;
}
-static int wlan_enable_11d(wlan_private * priv, u8 flag)
-{
- int ret;
-
- priv->adapter->enable11d = flag;
-
- /* send cmd to FW to enable/disable 11D function in FW */
- ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- cmd_act_set,
- cmd_option_waitforrsp,
- OID_802_11D_ENABLE,
- &priv->adapter->enable11d);
- if (ret)
- lbs_deb_11d("11D: Fail to enable 11D \n");
-
- return 0;
-}
-
/**
* @brief This function sets DOMAIN INFO to FW
* @param priv pointer to wlan_private
@@ -475,15 +456,15 @@ static int set_domain_info_11d(wlan_private * priv)
int ret;
if (!priv->adapter->enable11d) {
- lbs_deb_11d("11D: dnld domain Info with 11d disabled\n");
+ lbs_deb_11d("dnld domain Info with 11d disabled\n");
return 0;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret)
- lbs_deb_11d("11D: Fail to dnld domain Info\n");
+ lbs_deb_11d("fail to dnld domain info\n");
return ret;
}
@@ -505,7 +486,7 @@ int libertas_set_universaltable(wlan_private * priv, u8 band)
adapter->universal_channel[i].nrcfp =
sizeof(channel_freq_power_UN_BG) / size;
- lbs_deb_11d("11D: BG-band nrcfp=%d\n",
+ lbs_deb_11d("BG-band nrcfp %d\n",
adapter->universal_channel[i].nrcfp);
adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
@@ -541,10 +522,10 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
cmd->command = cpu_to_le16(cmdno);
pdomaininfo->action = cpu_to_le16(cmdoption);
- if (cmdoption == cmd_act_get) {
+ if (cmdoption == CMD_ACT_GET) {
cmd->size =
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
- lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
(int)(cmd->size));
goto done;
}
@@ -562,7 +543,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
nr_subband * sizeof(struct ieeetypes_subbandset));
cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
- domain->header.len +
+ le16_to_cpu(domain->header.len) +
sizeof(struct mrvlietypesheader) +
S_DS_GEN);
} else {
@@ -570,7 +551,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
}
- lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size));
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
done:
lbs_deb_enter(LBS_DEB_11D);
@@ -578,31 +559,6 @@ done:
}
/**
- * @brief This function implements private cmd: enable/disable 11D
- * @param priv pointer to wlan_private
- * @param wrq pointer to user data
- * @return 0 or -1
- */
-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
-{
- int data = 0;
- int *val;
-
- lbs_deb_enter(LBS_DEB_11D);
- data = SUBCMD_DATA(wrq);
-
- lbs_deb_11d("enable 11D: %s\n",
- (data == 1) ? "enable" : "Disable");
-
- wlan_enable_11d(priv, data);
- val = (int *)wrq->u.name;
- *val = priv->adapter->enable11d;
-
- lbs_deb_enter(LBS_DEB_11D);
- return 0;
-}
-
-/**
* @brief This function parses countryinfo from AP and download country info to FW
* @param priv pointer to wlan_private
* @param resp pointer to command response buffer
@@ -619,13 +575,13 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv,
lbs_deb_enter(LBS_DEB_11D);
- lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+ lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
(int)le16_to_cpu(resp->size));
nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
sizeof(struct ieeetypes_subbandset);
- lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+ lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
@@ -633,10 +589,10 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv,
}
switch (action) {
- case cmd_act_set: /*Proc Set action */
+ case CMD_ACT_SET: /*Proc Set action */
break;
- case cmd_act_get:
+ case CMD_ACT_GET:
break;
default:
lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
@@ -667,7 +623,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
&adapter->parsed_region_chan);
if (ret == -1) {
- lbs_deb_11d("11D: Err Parse domain_info from AP..\n");
+ lbs_deb_11d("error parsing domain_info from AP\n");
goto done;
}
@@ -679,7 +635,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
ret = set_domain_info_11d(priv);
if (ret) {
- lbs_deb_11d("11D: Err set domainInfo to FW\n");
+ lbs_deb_11d("error setting domain info\n");
goto done;
}
}
@@ -703,7 +659,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
u8 j;
lbs_deb_enter(LBS_DEB_11D);
- lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+ lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
if (priv->adapter->enable11d) {
/* update parsed_region_chan_11; dnld domaininf to FW */
@@ -712,7 +668,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
sizeof(adapter->region_channel[0]); j++) {
region_chan = &adapter->region_channel[j];
- lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", j,
+ lbs_deb_11d("%d region_chan->band %d\n", j,
region_chan->band);
if (!region_chan || !region_chan->valid
@@ -725,7 +681,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
if (j >= sizeof(adapter->region_channel) /
sizeof(adapter->region_channel[0])) {
- lbs_deb_11d("11D:region_chan not found. band[%d]\n",
+ lbs_deb_11d("region_chan not found, band %d\n",
adapter->curbssparams.band);
ret = -1;
goto done;
@@ -745,7 +701,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
ret = set_domain_info_11d(priv);
if (ret) {
- lbs_deb_11d("11D: Err set domainInfo to FW\n");
+ lbs_deb_11d("error setting domain info\n");
goto done;
}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
index 73e42e712911..3a6d1f8db78f 100644
--- a/drivers/net/wireless/libertas/11d.h
+++ b/drivers/net/wireless/libertas/11d.h
@@ -83,8 +83,6 @@ u8 libertas_get_scan_type_11d(u8 chan,
u32 libertas_chan_2_freq(u8 chan, u8 band);
-enum state_11d libertas_get_state_11d(wlan_private * priv);
-
void libertas_init_11d(wlan_private * priv);
int libertas_set_universaltable(wlan_private * priv, u8 band);
@@ -93,8 +91,6 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
struct cmd_ds_command *cmd, u16 cmdno,
u16 cmdOption);
-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
-
int libertas_ret_802_11d_domain_info(wlan_private * priv,
struct cmd_ds_command *resp);
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 32ed4136b0d4..c469d569f090 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,12 +1,13 @@
-libertas-objs := main.o fw.o wext.o \
+libertas-objs := main.o wext.o \
rx.o tx.o cmd.o \
cmdresp.o scan.o \
join.o 11d.o \
debugfs.o \
ethtool.o assoc.o
-usb8xxx-objs += if_bootcmd.o
usb8xxx-objs += if_usb.o
+libertas_cs-objs += if_cs.o
obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index afd5617dd92b..b61b176e9d07 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -16,6 +16,7 @@ static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
{
+ DECLARE_MAC_BUF(mac);
lbs_deb_assoc(
"#### Association Request: %s\n"
" flags: 0x%08lX\n"
@@ -23,13 +24,13 @@ static void print_assoc_req(const char * extra, struct assoc_request * assoc_req
" channel: %d\n"
" band: %d\n"
" mode: %d\n"
- " BSSID: " MAC_FMT "\n"
+ " BSSID: %s\n"
" Encryption:%s%s%s\n"
" auth: %d\n",
extra, assoc_req->flags,
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->channel, assoc_req->band, assoc_req->mode,
- MAC_ARG(assoc_req->bssid),
+ print_mac(mac, assoc_req->bssid),
assoc_req->secinfo.WPAenabled ? " WPA" : "",
assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
assoc_req->secinfo.wep_enabled ? " WEP" : "",
@@ -57,10 +58,8 @@ static int assoc_helper_essid(wlan_private *priv,
lbs_deb_assoc("New SSID requested: '%s'\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len));
if (assoc_req->mode == IW_MODE_INFRA) {
- if (adapter->prescan) {
- libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
- assoc_req->ssid_len, 0);
- }
+ libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
+ assoc_req->ssid_len, 0);
bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
@@ -106,16 +105,17 @@ static int assoc_helper_bssid(wlan_private *priv,
wlan_adapter *adapter = priv->adapter;
int ret = 0;
struct bss_descriptor * bss;
+ DECLARE_MAC_BUF(mac);
- lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT,
- MAC_ARG(assoc_req->bssid));
+ lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
+ print_mac(mac, assoc_req->bssid));
/* Search for index position in list for requested MAC */
bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid,
assoc_req->mode);
if (bss == NULL) {
- lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
- "cannot associate.\n", MAC_ARG(assoc_req->bssid));
+ lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
+ "cannot associate.\n", print_mac(mac, assoc_req->bssid));
goto out;
}
@@ -175,14 +175,14 @@ static int assoc_helper_mode(wlan_private *priv,
if (assoc_req->mode == IW_MODE_INFRA) {
if (adapter->psstate != PS_STATE_FULL_POWER)
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
- adapter->psmode = wlan802_11powermodecam;
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+ adapter->psmode = WLAN802_11POWERMODECAM;
}
adapter->mode = assoc_req->mode;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- 0, cmd_option_waitforrsp,
+ CMD_802_11_SNMP_MIB,
+ 0, CMD_OPTION_WAITFORRSP,
OID_802_11_INFRASTRUCTURE_MODE,
/* Shoot me now */ (void *) (size_t) assoc_req->mode);
@@ -195,9 +195,9 @@ done:
static int update_channel(wlan_private * priv)
{
/* the channel in f/w could be out of sync, get the current channel */
- return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
- cmd_opt_802_11_rf_channel_get,
- cmd_option_waitforrsp, 0, NULL);
+ return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
+ CMD_OPT_802_11_RF_CHANNEL_GET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
}
void libertas_sync_channel(struct work_struct *work)
@@ -227,9 +227,9 @@ static int assoc_helper_channel(wlan_private *priv,
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
adapter->curbssparams.channel, assoc_req->channel);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
- cmd_opt_802_11_rf_channel_set,
- cmd_option_waitforrsp, 0, &assoc_req->channel);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
+ CMD_OPT_802_11_RF_CHANNEL_SET,
+ CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel);
if (ret < 0) {
lbs_deb_assoc("ASSOC: channel: error setting channel.");
}
@@ -278,15 +278,15 @@ static int assoc_helper_wep_keys(wlan_private *priv,
|| assoc_req->wep_keys[2].len
|| assoc_req->wep_keys[3].len) {
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_set_wep,
- cmd_act_add,
- cmd_option_waitforrsp,
+ CMD_802_11_SET_WEP,
+ CMD_ACT_ADD,
+ CMD_OPTION_WAITFORRSP,
0, assoc_req);
} else {
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_set_wep,
- cmd_act_remove,
- cmd_option_waitforrsp,
+ CMD_802_11_SET_WEP,
+ CMD_ACT_REMOVE,
+ CMD_OPTION_WAITFORRSP,
0, NULL);
}
@@ -295,9 +295,9 @@ static int assoc_helper_wep_keys(wlan_private *priv,
/* enable/disable the MAC's WEP packet filter */
if (assoc_req->secinfo.wep_enabled)
- adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+ adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
else
- adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+ adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
ret = libertas_set_mac_packet_filter(priv);
if (ret)
goto out;
@@ -307,7 +307,7 @@ static int assoc_helper_wep_keys(wlan_private *priv,
/* Copy WEP keys into adapter wep key fields */
for (i = 0; i < 4; i++) {
memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
@@ -342,9 +342,9 @@ static int assoc_helper_secinfo(wlan_private *priv,
/* Get RSN enabled/disabled */
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_enable_rsn,
- cmd_act_set,
- cmd_option_waitforrsp,
+ CMD_802_11_ENABLE_RSN,
+ CMD_ACT_GET,
+ CMD_OPTION_WAITFORRSP,
0, &rsn);
if (ret) {
lbs_deb_assoc("Failed to get RSN status: %d", ret);
@@ -359,9 +359,9 @@ static int assoc_helper_secinfo(wlan_private *priv,
/* Set RSN enabled/disabled */
rsn = do_wpa;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_enable_rsn,
- cmd_act_set,
- cmd_option_waitforrsp,
+ CMD_802_11_ENABLE_RSN,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
0, &rsn);
out:
@@ -374,15 +374,40 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
+ unsigned int flags = assoc_req->flags;
lbs_deb_enter(LBS_DEB_ASSOC);
- ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_key_material,
- cmd_act_set,
- cmd_option_waitforrsp,
- 0, assoc_req);
+ /* Work around older firmware bug where WPA unicast and multicast
+ * keys must be set independently. Seen in SDIO parts with firmware
+ * version 5.0.11p0.
+ */
+
+ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_802_11_KEY_MATERIAL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
+ 0, assoc_req);
+ assoc_req->flags = flags;
+ }
+
+ if (ret)
+ goto out;
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+ clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_802_11_KEY_MATERIAL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
+ 0, assoc_req);
+ assoc_req->flags = flags;
+ }
+
+out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
@@ -412,7 +437,7 @@ static int assoc_helper_wpa_ie(wlan_private *priv,
static int should_deauth_infrastructure(wlan_adapter *adapter,
struct assoc_request * assoc_req)
{
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
return 0;
if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
@@ -453,7 +478,7 @@ static int should_deauth_infrastructure(wlan_adapter *adapter,
static int should_stop_adhoc(wlan_adapter *adapter,
struct assoc_request * assoc_req)
{
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
return 0;
if (libertas_ssid_cmp(adapter->curbssparams.ssid,
@@ -483,6 +508,7 @@ void libertas_association_worker(struct work_struct *work)
struct assoc_request * assoc_req = NULL;
int ret = 0;
int find_any_ssid = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_ASSOC);
@@ -556,7 +582,8 @@ void libertas_association_worker(struct work_struct *work)
if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
ret = assoc_helper_mode(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -574,7 +601,8 @@ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
|| test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
ret = assoc_helper_wep_keys(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -582,7 +610,8 @@ lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
ret = assoc_helper_secinfo(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -590,7 +619,8 @@ lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
ret = assoc_helper_wpa_ie(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -599,7 +629,8 @@ lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
|| test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
ret = assoc_helper_wpa_keys(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -618,25 +649,25 @@ lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
success = 0;
}
- if (adapter->connect_status != libertas_connected) {
- lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
+ if (adapter->connect_status != LIBERTAS_CONNECTED) {
+ lbs_deb_assoc("ASSOC: association attempt unsuccessful, "
"not connected.\n");
success = 0;
}
if (success) {
lbs_deb_assoc("ASSOC: association attempt successful. "
- "Associated to '%s' (" MAC_FMT ")\n",
+ "Associated to '%s' (%s)\n",
escape_essid(adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len),
- MAC_ARG(adapter->curbssparams.bssid));
+ print_mac(mac, adapter->curbssparams.bssid));
libertas_prepare_and_send_command(priv,
- cmd_802_11_rssi,
- 0, cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RSSI,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
libertas_prepare_and_send_command(priv,
- cmd_802_11_get_log,
- 0, cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_GET_LOG,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
} else {
ret = -1;
}
@@ -703,7 +734,7 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
int i;
for (i = 0; i < 4; i++) {
memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
}
@@ -712,12 +743,12 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 5e9c31f0932b..e09b7490abbd 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv)
if (priv->adapter->surpriseremoved)
return;
cancel_delayed_work(&priv->assoc_work);
- queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+ queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY);
}
static inline void wlan_cancel_association_work(wlan_private *priv)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 4a8f5dc70239..1cbbd96fdbde 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -15,7 +15,7 @@
static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
static u16 commands_allowed_in_ps[] = {
- cmd_802_11_rssi,
+ CMD_802_11_RSSI,
};
/**
@@ -43,7 +43,7 @@ static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_get_hw_spec);
+ cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
@@ -56,34 +56,29 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
u16 cmd_action)
{
struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
- wlan_adapter *adapter = priv->adapter;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+ cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
S_DS_GEN);
psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0;
switch (cmd_action) {
- case cmd_subcmd_enter_ps:
+ case CMD_SUBCMD_ENTER_PS:
lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
- lbs_deb_cmd("locallisteninterval = %d\n",
- adapter->locallisteninterval);
- psm->locallisteninterval =
- cpu_to_le16(adapter->locallisteninterval);
- psm->nullpktinterval =
- cpu_to_le16(adapter->nullpktinterval);
+ psm->locallisteninterval = 0;
+ psm->nullpktinterval = 0;
psm->multipledtim =
- cpu_to_le16(priv->adapter->multipledtim);
+ cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
break;
- case cmd_subcmd_exit_ps:
+ case CMD_SUBCMD_EXIT_PS:
lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
break;
- case cmd_subcmd_sleep_confirmed:
+ case CMD_SUBCMD_SLEEP_CONFIRMED:
lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
break;
@@ -101,7 +96,9 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
{
u16 *timeout = pdata_buf;
- cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+ S_DS_GEN);
@@ -113,6 +110,7 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
else
cmd->params.inactivity_timeout.timeout = 0;
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -127,13 +125,13 @@ static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+ cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
- if (cmd_action == cmd_act_get) {
+ if (cmd_action == CMD_ACT_GET) {
memset(&adapter->sp, 0, sizeof(struct sleep_params));
memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
sp->action = cpu_to_le16(cmd_action);
- } else if (cmd_action == cmd_act_set) {
+ } else if (cmd_action == CMD_ACT_SET) {
sp->action = cpu_to_le16(cmd_action);
sp->error = cpu_to_le16(adapter->sp.sp_error);
sp->offset = cpu_to_le16(adapter->sp.sp_offset);
@@ -159,10 +157,10 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+ cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
- if (cmd_act == cmd_act_add) {
+ if (cmd_act == CMD_ACT_ADD) {
int i;
if (!assoc_req) {
@@ -171,48 +169,47 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv,
goto done;
}
- wep->action = cpu_to_le16(cmd_act_add);
+ wep->action = cpu_to_le16(CMD_ACT_ADD);
/* default tx key index */
wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
- (u32)cmd_WEP_KEY_INDEX_MASK));
-
- lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex));
+ (u32)CMD_WEP_KEY_INDEX_MASK));
/* Copy key types and material to host command structure */
for (i = 0; i < 4; i++) {
- struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+ struct enc_key * pkey = &assoc_req->wep_keys[i];
switch (pkey->len) {
case KEY_LEN_WEP_40:
- wep->keytype[i] =
- cpu_to_le16(cmd_type_wep_40_bit);
+ wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
memmove(&wep->keymaterial[i], pkey->key,
pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
break;
case KEY_LEN_WEP_104:
- wep->keytype[i] =
- cpu_to_le16(cmd_type_wep_104_bit);
+ wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
memmove(&wep->keymaterial[i], pkey->key,
pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
break;
case 0:
break;
default:
- lbs_deb_cmd("Invalid WEP key %d length of %d\n",
+ lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
i, pkey->len);
ret = -1;
goto done;
break;
}
}
- } else if (cmd_act == cmd_act_remove) {
+ } else if (cmd_act == CMD_ACT_REMOVE) {
/* ACT_REMOVE clears _all_ WEP keys */
- wep->action = cpu_to_le16(cmd_act_remove);
+ wep->action = cpu_to_le16(CMD_ACT_REMOVE);
/* default tx key index */
wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
- (u32)cmd_WEP_KEY_INDEX_MASK));
+ (u32)CMD_WEP_KEY_INDEX_MASK));
+ lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx);
}
ret = 0;
@@ -232,15 +229,16 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+ cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
penableRSN->action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_set) {
+ if (cmd_action == CMD_ACT_SET) {
if (*enable)
- penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+ penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
else
- penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+ penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
+ lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
lbs_deb_leave(LBS_DEB_CMD);
@@ -249,9 +247,9 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
- struct WLAN_802_11_KEY * pkey)
+ struct enc_key * pkey)
{
- pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+ lbs_deb_enter(LBS_DEB_CMD);
if (pkey->flags & KEY_INFO_WPA_ENABLED) {
pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
@@ -264,12 +262,14 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
}
pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
pkeyparamset->keylen = cpu_to_le16(pkey->len);
memcpy(pkeyparamset->key, pkey->key, pkey->len);
pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
+ sizeof(pkeyparamset->keyinfo)
+ sizeof(pkeyparamset->keylen)
+ sizeof(pkeyparamset->key));
+ lbs_deb_leave(LBS_DEB_CMD);
}
static int wlan_cmd_802_11_key_material(wlan_private * priv,
@@ -285,10 +285,10 @@ static int wlan_cmd_802_11_key_material(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_key_material);
+ cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
pkeymaterial->action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_get) {
+ if (cmd_action == CMD_ACT_GET) {
cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
ret = 0;
goto done;
@@ -324,30 +324,37 @@ static int wlan_cmd_802_11_reset(wlan_private * priv,
{
struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
- cmd->command = cpu_to_le16(cmd_802_11_reset);
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd->command = cpu_to_le16(CMD_802_11_RESET);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
reset->action = cpu_to_le16(cmd_action);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int wlan_cmd_802_11_get_log(wlan_private * priv,
struct cmd_ds_command *cmd)
{
- cmd->command = cpu_to_le16(cmd_802_11_get_log);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int wlan_cmd_802_11_get_stat(wlan_private * priv,
struct cmd_ds_command *cmd)
{
- cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -364,15 +371,15 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
- cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+ cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
switch (cmd_oid) {
case OID_802_11_INFRASTRUCTURE_MODE:
{
u8 mode = (u8) (size_t) pdata_buf;
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
- pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+ pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
pSNMPMIB->bufsize = sizeof(u8);
if (mode == IW_MODE_ADHOC) {
ucTemp = SNMP_MIB_VALUE_ADHOC;
@@ -390,10 +397,10 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
{
u32 ulTemp;
- pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+ pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
- if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cmd_act_set;
+ if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = CMD_ACT_SET;
pSNMPMIB->bufsize = sizeof(u16);
ulTemp = *(u32 *)pdata_buf;
*((__le16 *)(pSNMPMIB->value)) =
@@ -406,12 +413,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
{
u32 ulTemp;
- pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+ pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
- if (cmd_action == cmd_act_get) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
- } else if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ if (cmd_action == CMD_ACT_GET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+ } else if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
ulTemp = *((u32 *) pdata_buf);
*((__le16 *)(pSNMPMIB->value)) =
@@ -426,12 +433,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
{
u32 ulTemp;
- pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+ pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I);
- if (cmd_action == cmd_act_get) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
- } else if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ if (cmd_action == CMD_ACT_GET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+ } else if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
ulTemp = *((u32 *)pdata_buf);
*(__le16 *)(pSNMPMIB->value) =
@@ -441,12 +448,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
break;
}
case OID_802_11_TX_RETRYCOUNT:
- pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+ pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
- if (cmd_action == cmd_act_get) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
- } else if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ if (cmd_action == CMD_ACT_GET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+ } else if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
*((__le16 *)(pSNMPMIB->value)) =
cpu_to_le16((u16) adapter->txretrycount);
@@ -463,7 +470,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
lbs_deb_cmd(
- "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+ "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
le16_to_cpu(pSNMPMIB->bufsize),
le16_to_cpu(*(__le16 *) pSNMPMIB->value));
@@ -484,20 +491,20 @@ static int wlan_cmd_802_11_radio_control(wlan_private * priv,
cmd->size =
cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+ cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
pradiocontrol->action = cpu_to_le16(cmd_action);
switch (adapter->preamble) {
- case cmd_type_short_preamble:
+ case CMD_TYPE_SHORT_PREAMBLE:
pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
break;
- case cmd_type_long_preamble:
+ case CMD_TYPE_LONG_PREAMBLE:
pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
break;
- case cmd_type_auto_preamble:
+ case CMD_TYPE_AUTO_PREAMBLE:
default:
pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
break;
@@ -523,7 +530,7 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
cmd->size =
cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+ cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
prtp->action = cpu_to_le16(cmd_action);
lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
@@ -531,23 +538,23 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
le16_to_cpu(prtp->action));
switch (cmd_action) {
- case cmd_act_tx_power_opt_get:
- prtp->action = cpu_to_le16(cmd_act_get);
+ case CMD_ACT_TX_POWER_OPT_GET:
+ prtp->action = cpu_to_le16(CMD_ACT_GET);
prtp->currentlevel = 0;
break;
- case cmd_act_tx_power_opt_set_high:
- prtp->action = cpu_to_le16(cmd_act_set);
- prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_high);
+ case CMD_ACT_TX_POWER_OPT_SET_HIGH:
+ prtp->action = cpu_to_le16(CMD_ACT_SET);
+ prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
break;
- case cmd_act_tx_power_opt_set_mid:
- prtp->action = cpu_to_le16(cmd_act_set);
- prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_mid);
+ case CMD_ACT_TX_POWER_OPT_SET_MID:
+ prtp->action = cpu_to_le16(CMD_ACT_SET);
+ prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
break;
- case cmd_act_tx_power_opt_set_low:
- prtp->action = cpu_to_le16(cmd_act_set);
+ case CMD_ACT_TX_POWER_OPT_SET_LOW:
+ prtp->action = cpu_to_le16(CMD_ACT_SET);
prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
break;
}
@@ -556,19 +563,21 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
return 0;
}
-static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+static int wlan_cmd_802_11_monitor_mode(wlan_private * priv,
struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf)
{
- struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+ struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
- cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
- S_DS_GEN);
+ cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
+ S_DS_GEN);
- rant->action = cpu_to_le16(cmd_action);
- if ((cmd_action == cmd_act_set_rx) || (cmd_action == cmd_act_set_tx)) {
- rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ monitor->action = cpu_to_le16(cmd_action);
+ if (cmd_action == CMD_ACT_SET) {
+ monitor->mode =
+ cpu_to_le16((u16) (*(u32 *) pdata_buf));
}
return 0;
@@ -582,12 +591,11 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
*rateadapt = &cmd->params.rateset;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_CMD);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+ S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
-
- lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
rateadapt->action = cpu_to_le16(cmd_action);
rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto);
@@ -608,19 +616,16 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv,
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
S_DS_GEN);
-
- cmd->command = cpu_to_le16(cmd_802_11_data_rate);
-
+ cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
-
pdatarate->action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_set_tx_fix_rate) {
- pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
- lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n",
- adapter->datarate);
- } else if (cmd_action == cmd_act_set_tx_auto) {
- lbs_deb_cmd("Setting FW for AUTO rate\n");
+ if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
+ pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate);
+ lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
+ adapter->cur_rate);
+ } else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
+ lbs_deb_cmd("DATA_RATE: setting auto\n");
}
lbs_deb_leave(LBS_DEB_CMD);
@@ -634,16 +639,19 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_CMD);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+ cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
+ lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
pMCastAdr->action = cpu_to_le16(cmd_action);
pMCastAdr->nr_of_adrs =
cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
memcpy(pMCastAdr->maclist, adapter->multicastlist,
adapter->nr_of_multicastmacaddr * ETH_ALEN);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -653,16 +661,18 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
{
struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
- cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
S_DS_GEN);
- if (option == cmd_opt_802_11_rf_channel_set) {
+ if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
}
rfchan->action = cpu_to_le16(option);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -671,9 +681,10 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv,
{
wlan_adapter *adapter = priv->adapter;
- cmd->command = cpu_to_le16(cmd_802_11_rssi);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RSSI);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
- cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor);
+ cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
/* reset Beacon SNR/NF/RSSI values */
adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
@@ -683,6 +694,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv,
adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -697,7 +709,7 @@ static int wlan_cmd_reg_access(wlan_private * priv,
offval = (struct wlan_offset_value *)pdata_buf;
switch (cmdptr->command) {
- case cmd_mac_reg_access:
+ case CMD_MAC_REG_ACCESS:
{
struct cmd_ds_mac_reg_access *macreg;
@@ -715,7 +727,7 @@ static int wlan_cmd_reg_access(wlan_private * priv,
break;
}
- case cmd_bbp_reg_access:
+ case CMD_BBP_REG_ACCESS:
{
struct cmd_ds_bbp_reg_access *bbpreg;
@@ -734,7 +746,7 @@ static int wlan_cmd_reg_access(wlan_private * priv,
break;
}
- case cmd_rf_reg_access:
+ case CMD_RF_REG_ACCESS:
{
struct cmd_ds_rf_reg_access *rfreg;
@@ -767,19 +779,21 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv,
{
wlan_adapter *adapter = priv->adapter;
- cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
S_DS_GEN);
cmd->result = 0;
cmd->params.macadd.action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_set) {
+ if (cmd_action == CMD_ACT_SET) {
memcpy(cmd->params.macadd.macadd,
adapter->current_addr, ETH_ALEN);
- lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+ lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6);
}
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -791,7 +805,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+ cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
S_DS_GEN);
cmd->result = 0;
@@ -801,6 +815,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
cmd->params.rdeeprom.value = 0;
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -809,35 +824,36 @@ static int wlan_cmd_bt_access(wlan_private * priv,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
- lbs_deb_cmd("BT CMD(%d)\n", cmd_action);
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
- cmd->command = cpu_to_le16(cmd_bt_access);
+ cmd->command = cpu_to_le16(CMD_BT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action);
switch (cmd_action) {
- case cmd_act_bt_access_add:
+ case CMD_ACT_BT_ACCESS_ADD:
memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
- lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+ lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
break;
- case cmd_act_bt_access_del:
+ case CMD_ACT_BT_ACCESS_DEL:
memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
- lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+ lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
break;
- case cmd_act_bt_access_list:
+ case CMD_ACT_BT_ACCESS_LIST:
bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
break;
- case cmd_act_bt_access_reset:
+ case CMD_ACT_BT_ACCESS_RESET:
break;
- case cmd_act_bt_access_set_invert:
+ case CMD_ACT_BT_ACCESS_SET_INVERT:
bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
break;
- case cmd_act_bt_access_get_invert:
+ case CMD_ACT_BT_ACCESS_GET_INVERT:
break;
default:
break;
}
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -846,9 +862,9 @@ static int wlan_cmd_fwt_access(wlan_private * priv,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
- lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
- cmd->command = cpu_to_le16(cmd_fwt_access);
+ cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
cmd->result = 0;
@@ -859,6 +875,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv,
fwt_access->action = cpu_to_le16(cmd_action);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -867,9 +884,9 @@ static int wlan_cmd_mesh_access(wlan_private * priv,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
- lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
- cmd->command = cpu_to_le16(cmd_mesh_access);
+ cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
cmd->result = 0;
@@ -880,6 +897,18 @@ static int wlan_cmd_mesh_access(wlan_private * priv,
mesh_access->action = cpu_to_le16(cmd_action);
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+static int wlan_cmd_set_boot2_ver(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver;
+ cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN);
+ boot2_ver->version = priv->boot2_version;
return 0;
}
@@ -888,23 +917,23 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u
unsigned long flags;
struct cmd_ds_command *cmdptr;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!cmdnode) {
- lbs_deb_cmd("QUEUE_CMD: cmdnode is NULL\n");
+ lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
goto done;
}
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
if (!cmdptr) {
- lbs_deb_cmd("QUEUE_CMD: cmdptr is NULL\n");
+ lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
goto done;
}
/* Exit_PS command needs to be queued in the header always. */
- if (cmdptr->command == cmd_802_11_ps_mode) {
+ if (cmdptr->command == CMD_802_11_PS_MODE) {
struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
- if (psm->action == cpu_to_le16(cmd_subcmd_exit_ps)) {
+ if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
if (adapter->psstate != PS_STATE_FULL_POWER)
addtail = 0;
}
@@ -920,17 +949,16 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- lbs_deb_cmd("QUEUE_CMD: Inserted node=%p, cmd=0x%x in cmdpendingq\n",
- cmdnode,
+ lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
done:
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/*
* TODO: Fix the issue when DownloadcommandToStation is being called the
- * second time when the command timesout. All the cmdptr->xxx are in little
+ * second time when the command times out. All the cmdptr->xxx are in little
* endian and therefore all the comparissions will fail.
* For now - we are not performing the endian conversion the second time - but
* for PS and DEEP_SLEEP we need to worry
@@ -941,68 +969,59 @@ static int DownloadcommandToStation(wlan_private * priv,
unsigned long flags;
struct cmd_ds_command *cmdptr;
wlan_adapter *adapter = priv->adapter;
- int ret = 0;
+ int ret = -1;
u16 cmdsize;
u16 command;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!adapter || !cmdnode) {
- lbs_deb_cmd("DNLD_CMD: adapter = %p, cmdnode = %p\n",
- adapter, cmdnode);
- if (cmdnode) {
- spin_lock_irqsave(&adapter->driver_lock, flags);
- __libertas_cleanup_and_insert_cmd(priv, cmdnode);
- spin_unlock_irqrestore(&adapter->driver_lock, flags);
- }
- ret = -1;
+ lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
goto done;
}
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
-
spin_lock_irqsave(&adapter->driver_lock, flags);
if (!cmdptr || !cmdptr->size) {
- lbs_deb_cmd("DNLD_CMD: cmdptr is Null or cmd size is Zero, "
- "Not sending\n");
+ lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
__libertas_cleanup_and_insert_cmd(priv, cmdnode);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- ret = -1;
goto done;
}
adapter->cur_cmd = cmdnode;
adapter->cur_cmd_retcode = 0;
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- lbs_deb_cmd("DNLD_CMD:: Before download, size of cmd = %d\n",
- le16_to_cpu(cmdptr->size));
cmdsize = cmdptr->size;
-
command = cpu_to_le16(cmdptr->command);
+ lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
+ command, le16_to_cpu(cmdptr->size), jiffies);
+ lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
+
cmdnode->cmdwaitqwoken = 0;
cmdsize = cpu_to_le16(cmdsize);
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
if (ret != 0) {
- lbs_deb_cmd("DNLD_CMD: Host to Card failed\n");
+ lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd_retcode = ret;
__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
adapter->cur_cmd = NULL;
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- ret = -1;
goto done;
}
- lbs_deb_cmd("DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
- lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+ lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
/* Setup the timer after transmit command */
- if (command == cmd_802_11_scan || command == cmd_802_11_authenticate
- || command == cmd_802_11_associate)
+ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
+ || command == CMD_802_11_ASSOCIATE)
mod_timer(&adapter->command_timer, jiffies + (10*HZ));
else
mod_timer(&adapter->command_timer, jiffies + (5*HZ));
@@ -1010,7 +1029,7 @@ static int DownloadcommandToStation(wlan_private * priv,
ret = 0;
done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
@@ -1021,11 +1040,11 @@ static int wlan_cmd_mac_control(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_mac_control);
+ cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
- lbs_deb_cmd("wlan_cmd_mac_control(): action=0x%X size=%d\n",
+ lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
lbs_deb_leave(LBS_DEB_CMD);
@@ -1041,15 +1060,13 @@ void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node
wlan_adapter *adapter = priv->adapter;
if (!ptempcmd)
- goto done;
+ return;
cleanup_cmdnode(ptempcmd);
list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
-done:
- return;
}
-void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
{
unsigned long flags;
@@ -1065,11 +1082,11 @@ int libertas_set_radio_control(wlan_private * priv)
lbs_deb_enter(LBS_DEB_CMD);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_radio_control,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RADIO_CONTROL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
- lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+ lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
priv->adapter->radioon, priv->adapter->preamble);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
@@ -1082,12 +1099,9 @@ int libertas_set_mac_packet_filter(wlan_private * priv)
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("libertas_set_mac_packet_filter value = %x\n",
- priv->adapter->currentpacketfilter);
-
/* Send MAC control command to station */
ret = libertas_prepare_and_send_command(priv,
- cmd_mac_control, 0, 0, 0, NULL);
+ CMD_MAC_CONTROL, 0, 0, 0, NULL);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
@@ -1115,16 +1129,16 @@ int libertas_prepare_and_send_command(wlan_private * priv,
struct cmd_ds_command *cmdptr;
unsigned long flags;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!adapter) {
- lbs_deb_cmd("PREP_CMD: adapter is Null\n");
+ lbs_deb_host("PREP_CMD: adapter is NULL\n");
ret = -1;
goto done;
}
if (adapter->surpriseremoved) {
- lbs_deb_cmd("PREP_CMD: Card is Removed\n");
+ lbs_deb_host("PREP_CMD: card removed\n");
ret = -1;
goto done;
}
@@ -1132,10 +1146,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdnode = libertas_get_free_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
- lbs_deb_cmd("PREP_CMD: No free cmdnode\n");
+ lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
/* Wake up main thread to execute next command */
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
ret = -1;
goto done;
}
@@ -1144,11 +1158,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
- lbs_deb_cmd("PREP_CMD: Val of cmd ptr=%p, command=0x%X\n",
- cmdptr, cmd_no);
+ lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
if (!cmdptr) {
- lbs_deb_cmd("PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+ lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
libertas_cleanup_and_insert_cmd(priv, cmdnode);
ret = -1;
goto done;
@@ -1162,136 +1175,136 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdptr->result = 0;
switch (cmd_no) {
- case cmd_get_hw_spec:
+ case CMD_GET_HW_SPEC:
ret = wlan_cmd_hw_spec(priv, cmdptr);
break;
- case cmd_802_11_ps_mode:
+ case CMD_802_11_PS_MODE:
ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_scan:
+ case CMD_802_11_SCAN:
ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
break;
- case cmd_mac_control:
+ case CMD_MAC_CONTROL:
ret = wlan_cmd_mac_control(priv, cmdptr);
break;
- case cmd_802_11_associate:
- case cmd_802_11_reassociate:
+ case CMD_802_11_ASSOCIATE:
+ case CMD_802_11_REASSOCIATE:
ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
break;
- case cmd_802_11_deauthenticate:
+ case CMD_802_11_DEAUTHENTICATE:
ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
break;
- case cmd_802_11_set_wep:
+ case CMD_802_11_SET_WEP:
ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_802_11_ad_hoc_start:
+ case CMD_802_11_AD_HOC_START:
ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
break;
- case cmd_code_dnld:
+ case CMD_CODE_DNLD:
break;
- case cmd_802_11_reset:
+ case CMD_802_11_RESET:
ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_get_log:
+ case CMD_802_11_GET_LOG:
ret = wlan_cmd_802_11_get_log(priv, cmdptr);
break;
- case cmd_802_11_authenticate:
+ case CMD_802_11_AUTHENTICATE:
ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
break;
- case cmd_802_11_get_stat:
+ case CMD_802_11_GET_STAT:
ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
break;
- case cmd_802_11_snmp_mib:
+ case CMD_802_11_SNMP_MIB:
ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
cmd_action, cmd_oid, pdata_buf);
break;
- case cmd_mac_reg_access:
- case cmd_bbp_reg_access:
- case cmd_rf_reg_access:
+ case CMD_MAC_REG_ACCESS:
+ case CMD_BBP_REG_ACCESS:
+ case CMD_RF_REG_ACCESS:
ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_802_11_rf_channel:
+ case CMD_802_11_RF_CHANNEL:
ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
cmd_action, pdata_buf);
break;
- case cmd_802_11_rf_tx_power:
+ case CMD_802_11_RF_TX_POWER:
ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
cmd_action, pdata_buf);
break;
- case cmd_802_11_radio_control:
+ case CMD_802_11_RADIO_CONTROL:
ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_rf_antenna:
- ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
- cmd_action, pdata_buf);
- break;
-
- case cmd_802_11_data_rate:
+ case CMD_802_11_DATA_RATE:
ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_rate_adapt_rateset:
+ case CMD_802_11_RATE_ADAPT_RATESET:
ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
cmdptr, cmd_action);
break;
- case cmd_mac_multicast_adr:
+ case CMD_MAC_MULTICAST_ADR:
ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_ad_hoc_join:
+ case CMD_802_11_MONITOR_MODE:
+ ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case CMD_802_11_AD_HOC_JOIN:
ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
break;
- case cmd_802_11_rssi:
+ case CMD_802_11_RSSI:
ret = wlan_cmd_802_11_rssi(priv, cmdptr);
break;
- case cmd_802_11_ad_hoc_stop:
+ case CMD_802_11_AD_HOC_STOP:
ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
break;
- case cmd_802_11_enable_rsn:
+ case CMD_802_11_ENABLE_RSN:
ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
pdata_buf);
break;
- case cmd_802_11_key_material:
+ case CMD_802_11_KEY_MATERIAL:
ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
cmd_oid, pdata_buf);
break;
- case cmd_802_11_pairwise_tsc:
+ case CMD_802_11_PAIRWISE_TSC:
break;
- case cmd_802_11_group_tsc:
+ case CMD_802_11_GROUP_TSC:
break;
- case cmd_802_11_mac_address:
+ case CMD_802_11_MAC_ADDRESS:
ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_eeprom_access:
+ case CMD_802_11_EEPROM_ACCESS:
ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
cmd_action, pdata_buf);
break;
- case cmd_802_11_set_afc:
- case cmd_802_11_get_afc:
+ case CMD_802_11_SET_AFC:
+ case CMD_802_11_GET_AFC:
cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
@@ -1303,22 +1316,22 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
goto done;
- case cmd_802_11d_domain_info:
+ case CMD_802_11D_DOMAIN_INFO:
ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
cmd_no, cmd_action);
break;
- case cmd_802_11_sleep_params:
+ case CMD_802_11_SLEEP_PARAMS:
ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_inactivity_timeout:
+ case CMD_802_11_INACTIVITY_TIMEOUT:
ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
cmd_action, pdata_buf);
libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
break;
- case cmd_802_11_tpc_cfg:
- cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+ case CMD_802_11_TPC_CFG:
+ cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
S_DS_GEN);
@@ -1328,7 +1341,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
break;
- case cmd_802_11_led_gpio_ctrl:
+ case CMD_802_11_LED_GPIO_CTRL:
{
struct mrvlietypes_ledgpio *gpio =
(struct mrvlietypes_ledgpio*)
@@ -1339,7 +1352,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
sizeof(struct cmd_ds_802_11_led_ctrl));
cmdptr->command =
- cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+ cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
cmdptr->size =
@@ -1350,8 +1363,8 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
break;
}
- case cmd_802_11_pwr_cfg:
- cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+ case CMD_802_11_PWR_CFG:
+ cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
S_DS_GEN);
@@ -1360,40 +1373,37 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
break;
- case cmd_bt_access:
+ case CMD_BT_ACCESS:
ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_fwt_access:
+ case CMD_FWT_ACCESS:
ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_mesh_access:
+ case CMD_MESH_ACCESS:
ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_get_tsf:
- cmdptr->command = cpu_to_le16(cmd_get_tsf);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
- S_DS_GEN);
- ret = 0;
+ case CMD_SET_BOOT2_VER:
+ ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_802_11_tx_rate_query:
- cmdptr->command = cpu_to_le16(cmd_802_11_tx_rate_query);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+
+ case CMD_GET_TSF:
+ cmdptr->command = cpu_to_le16(CMD_GET_TSF);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
S_DS_GEN);
- adapter->txrate = 0;
ret = 0;
break;
default:
- lbs_deb_cmd("PREP_CMD: unknown command- %#x\n", cmd_no);
+ lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
break;
}
/* return error, since the command preparation failed */
if (ret != 0) {
- lbs_deb_cmd("PREP_CMD: command preparation failed\n");
+ lbs_deb_host("PREP_CMD: command preparation failed\n");
libertas_cleanup_and_insert_cmd(priv, cmdnode);
ret = -1;
goto done;
@@ -1403,10 +1413,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
libertas_queue_cmd(adapter, cmdnode, 1);
adapter->nr_cmd_pending++;
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
- if (wait_option & cmd_option_waitforrsp) {
- lbs_deb_cmd("PREP_CMD: Wait for CMD response\n");
+ if (wait_option & CMD_OPTION_WAITFORRSP) {
+ lbs_deb_host("PREP_CMD: wait for response\n");
might_sleep();
wait_event_interruptible(cmdnode->cmdwait_q,
cmdnode->cmdwaitqwoken);
@@ -1414,7 +1424,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd_retcode) {
- lbs_deb_cmd("PREP_CMD: command failed with return code=%d\n",
+ lbs_deb_host("PREP_CMD: command failed with return code %d\n",
adapter->cur_cmd_retcode);
adapter->cur_cmd_retcode = 0;
ret = -1;
@@ -1422,7 +1432,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
spin_unlock_irqrestore(&adapter->driver_lock, flags);
done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command);
@@ -1443,14 +1453,13 @@ int libertas_allocate_cmd_buffer(wlan_private * priv)
u8 *ptempvirtualaddr;
wlan_adapter *adapter = priv->adapter;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
/* Allocate and initialize cmdCtrlNode */
ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
- lbs_deb_cmd(
- "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+ lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
ret = -1;
goto done;
}
@@ -1460,8 +1469,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv)
ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
- lbs_deb_cmd(
- "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+ lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
ret = -1;
goto done;
}
@@ -1478,7 +1486,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv)
ret = 0;
done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
@@ -1495,11 +1503,11 @@ int libertas_free_cmd_buffer(wlan_private * priv)
struct cmd_ctrl_node *tempcmd_array;
wlan_adapter *adapter = priv->adapter;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
/* need to check if cmd array is allocated or not */
if (adapter->cmd_array == NULL) {
- lbs_deb_cmd("FREE_CMD_BUF: cmd_array is Null\n");
+ lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
goto done;
}
@@ -1509,7 +1517,6 @@ int libertas_free_cmd_buffer(wlan_private * priv)
ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
if (tempcmd_array[i].bufvirtualaddr) {
- lbs_deb_cmd("Free all the array\n");
kfree(tempcmd_array[i].bufvirtualaddr);
tempcmd_array[i].bufvirtualaddr = NULL;
}
@@ -1517,13 +1524,12 @@ int libertas_free_cmd_buffer(wlan_private * priv)
/* Release cmd_ctrl_node */
if (adapter->cmd_array) {
- lbs_deb_cmd("Free cmd_array\n");
kfree(adapter->cmd_array);
adapter->cmd_array = NULL;
}
done:
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
return 0;
}
@@ -1540,6 +1546,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
wlan_adapter *adapter = priv->adapter;
unsigned long flags;
+ lbs_deb_enter(LBS_DEB_HOST);
+
if (!adapter)
return NULL;
@@ -1549,21 +1557,16 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
list_del((struct list_head *)tempnode);
} else {
- lbs_deb_cmd("GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
tempnode = NULL;
}
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- if (tempnode) {
- /*
- lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
- lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
- tempnode);
- */
+ if (tempnode)
cleanup_cmdnode(tempnode);
- }
+ lbs_deb_leave(LBS_DEB_HOST);
return tempnode;
}
@@ -1575,6 +1578,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
*/
static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
{
+ lbs_deb_enter(LBS_DEB_HOST);
+
if (!ptempnode)
return;
ptempnode->cmdwaitqwoken = 1;
@@ -1586,7 +1591,8 @@ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
if (ptempnode->bufvirtualaddr != NULL)
memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
- return;
+
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
@@ -1603,7 +1609,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv,
struct cmd_ctrl_node *ptempnode,
u32 cmd_oid, u16 wait_option, void *pdata_buf)
{
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!ptempnode)
return;
@@ -1612,7 +1618,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv,
ptempnode->wait_option = wait_option;
ptempnode->pdata_buf = pdata_buf;
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
@@ -1631,12 +1637,15 @@ int libertas_execute_next_command(wlan_private * priv)
unsigned long flags;
int ret = 0;
- lbs_deb_enter(LBS_DEB_CMD);
+ // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+ // only caller to us is libertas_thread() and we get even when a
+ // data packet is received
+ lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd) {
- lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+ lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
spin_unlock_irqrestore(&adapter->driver_lock, flags);
ret = -1;
goto done;
@@ -1650,22 +1659,20 @@ int libertas_execute_next_command(wlan_private * priv)
spin_unlock_irqrestore(&adapter->driver_lock, flags);
if (cmdnode) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
if (is_command_allowed_in_ps(cmdptr->command)) {
if ((adapter->psstate == PS_STATE_SLEEP) ||
(adapter->psstate == PS_STATE_PRE_SLEEP)) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
le16_to_cpu(cmdptr->command),
adapter->psstate);
ret = -1;
goto done;
}
- lbs_deb_cmd("EXEC_NEXT_CMD: OK to send command "
- "0x%x in psstate %d\n",
+ lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
+ "0x%04x in psstate %d\n",
le16_to_cpu(cmdptr->command),
adapter->psstate);
} else if (adapter->psstate != PS_STATE_FULL_POWER) {
@@ -1681,7 +1688,7 @@ int libertas_execute_next_command(wlan_private * priv)
* immediately.
*/
if (cmdptr->command !=
- cpu_to_le16(cmd_802_11_ps_mode)) {
+ cpu_to_le16(CMD_802_11_PS_MODE)) {
/* Prepare to send Exit PS,
* this non PS command will be sent later */
if ((adapter->psstate == PS_STATE_SLEEP)
@@ -1703,13 +1710,13 @@ int libertas_execute_next_command(wlan_private * priv)
struct cmd_ds_802_11_ps_mode *psm =
&cmdptr->params.psmode;
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
psm->action);
if (psm->action !=
- cpu_to_le16(cmd_subcmd_exit_ps)) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+ cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
list_del((struct list_head *)cmdnode);
libertas_cleanup_and_insert_cmd(priv, cmdnode);
@@ -1719,8 +1726,8 @@ int libertas_execute_next_command(wlan_private * priv)
if ((adapter->psstate == PS_STATE_SLEEP) ||
(adapter->psstate == PS_STATE_PRE_SLEEP)) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
list_del((struct list_head *)cmdnode);
libertas_cleanup_and_insert_cmd(priv, cmdnode);
adapter->needtowakeup = 1;
@@ -1729,12 +1736,12 @@ int libertas_execute_next_command(wlan_private * priv)
goto done;
}
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: sending EXIT_PS\n");
}
}
list_del((struct list_head *)cmdnode);
- lbs_deb_cmd("EXEC_NEXT_CMD: Sending 0x%04X command\n",
+ lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
le16_to_cpu(cmdptr->command));
DownloadcommandToStation(priv, cmdnode);
} else {
@@ -1742,23 +1749,23 @@ int libertas_execute_next_command(wlan_private * priv)
* check if in power save mode, if yes, put the device back
* to PS mode
*/
- if ((adapter->psmode != wlan802_11powermodecam) &&
+ if ((adapter->psmode != WLAN802_11POWERMODECAM) &&
(adapter->psstate == PS_STATE_FULL_POWER) &&
- (adapter->connect_status == libertas_connected)) {
+ (adapter->connect_status == LIBERTAS_CONNECTED)) {
if (adapter->secinfo.WPAenabled ||
adapter->secinfo.WPA2enabled) {
/* check for valid WPA group keys */
if (adapter->wpa_mcast_key.len ||
adapter->wpa_unicast_key.len) {
- lbs_deb_cmd(
+ lbs_deb_host(
"EXEC_NEXT_CMD: WPA enabled and GTK_SET"
" go back to PS_SLEEP");
libertas_ps_sleep(priv, 0);
}
} else {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: command PendQ is empty,"
- " go back to PS_SLEEP");
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: cmdpendingq empty, "
+ "go back to PS_SLEEP");
libertas_ps_sleep(priv, 0);
}
}
@@ -1766,7 +1773,7 @@ int libertas_execute_next_command(wlan_private * priv)
ret = 0;
done:
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_THREAD);
return ret;
}
@@ -1775,7 +1782,7 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
union iwreq_data iwrq;
u8 buf[50];
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_WEXT);
memset(&iwrq, 0, sizeof(union iwreq_data));
memset(buf, 0, sizeof(buf));
@@ -1785,13 +1792,13 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
/* Send Event to upper layer */
- lbs_deb_cmd("Event Indication string = %s\n", (char *)buf);
- lbs_deb_cmd("Event Indication String length = %d\n", iwrq.data.length);
+ lbs_deb_wext("event indication string %s\n", (char *)buf);
+ lbs_deb_wext("event indication length %d\n", iwrq.data.length);
+ lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
- lbs_deb_cmd("Sending wireless event IWEVCUSTOM for %s\n", str);
wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_WEXT);
}
static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
@@ -1800,19 +1807,19 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
wlan_adapter *adapter = priv->adapter;
int ret = 0;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
- lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+ lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
size);
- lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+ lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
priv->dnld_sent = DNLD_RES_RECEIVED;
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->intcounter || adapter->currenttxskb)
- lbs_deb_cmd("SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+ lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
adapter->intcounter, adapter->currenttxskb);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
@@ -1824,36 +1831,35 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
if (!adapter->intcounter) {
adapter->psstate = PS_STATE_SLEEP;
} else {
- lbs_deb_cmd("SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+ lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
adapter->intcounter);
}
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- lbs_deb_cmd("SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
- lbs_deb_cmd("+");
+ lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
}
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
void libertas_ps_sleep(wlan_private * priv, int wait_option)
{
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
/*
* PS is currently supported only in Infrastructure mode
* Remove this check if it is to be supported in IBSS mode also
*/
- libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
- cmd_subcmd_enter_ps, wait_option, 0, NULL);
+ libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+ CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
- * @brief This function sends Eixt_PS command to firmware.
+ * @brief This function sends Exit_PS command to firmware.
*
* @param priv A pointer to wlan_private structure
* @param wait_option wait response or not
@@ -1863,17 +1869,15 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option)
{
__le32 Localpsmode;
- lbs_deb_enter(LBS_DEB_CMD);
-
- Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+ lbs_deb_enter(LBS_DEB_HOST);
- lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", wlan802_11powermodecam);
+ Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
- libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
- cmd_subcmd_exit_ps,
+ libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+ CMD_SUBCMD_EXIT_PS,
wait_option, 0, &Localpsmode);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
@@ -1890,31 +1894,31 @@ void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
wlan_adapter *adapter = priv->adapter;
u8 allowed = 1;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (priv->dnld_sent) {
allowed = 0;
- lbs_deb_cmd("D");
+ lbs_deb_host("dnld_sent was set");
}
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd) {
allowed = 0;
- lbs_deb_cmd("C");
+ lbs_deb_host("cur_cmd was set");
}
if (adapter->intcounter > 0) {
allowed = 0;
- lbs_deb_cmd("I%d", adapter->intcounter);
+ lbs_deb_host("intcounter %d", adapter->intcounter);
}
spin_unlock_irqrestore(&adapter->driver_lock, flags);
if (allowed) {
- lbs_deb_cmd("Sending libertas_ps_confirm_sleep\n");
+ lbs_deb_host("sending libertas_ps_confirm_sleep\n");
sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
sizeof(struct PS_CMD_ConfirmSleep));
} else {
- lbs_deb_cmd("Sleep Confirm has been delayed\n");
+ lbs_deb_host("sleep confirm has been delayed\n");
}
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 6ac0d4752fa4..8f90892ea22e 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -28,10 +28,10 @@ void libertas_mac_event_disconnected(wlan_private * priv)
wlan_adapter *adapter = priv->adapter;
union iwreq_data wrqu;
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
return;
- lbs_deb_cmd("Handles disconnect event.\n");
+ lbs_deb_enter(LBS_DEB_CMD);
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -60,22 +60,12 @@ void libertas_mac_event_disconnected(wlan_private * priv)
memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
adapter->nextSNRNF = 0;
adapter->numSNRNF = 0;
- adapter->rxpd_rate = 0;
- lbs_deb_cmd("Current SSID='%s', ssid length=%u\n",
+ lbs_deb_cmd("current SSID '%s', length %u\n",
escape_essid(adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len),
adapter->curbssparams.ssid_len);
- lbs_deb_cmd("Previous SSID='%s', ssid length=%u\n",
- escape_essid(adapter->prev_ssid, adapter->prev_ssid_len),
- adapter->prev_ssid_len);
-
- adapter->connect_status = libertas_disconnected;
- /* Save previous SSID and BSSID for possible reassociation */
- memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid,
- IW_ESSID_MAX_SIZE);
- adapter->prev_ssid_len = adapter->curbssparams.ssid_len;
- memcpy(adapter->prev_bssid, adapter->curbssparams.bssid, ETH_ALEN);
+ adapter->connect_status = LIBERTAS_DISCONNECTED;
/* Clear out associated SSID and BSSID since connection is
* no longer valid.
@@ -86,9 +76,10 @@ void libertas_mac_event_disconnected(wlan_private * priv)
if (adapter->psstate != PS_STATE_FULL_POWER) {
/* make firmware to exit PS mode */
- lbs_deb_cmd("Disconnected, so exit PS mode.\n");
+ lbs_deb_cmd("disconnected, so exit PS mode\n");
libertas_ps_wakeup(priv, 0);
}
+ lbs_deb_leave(LBS_DEB_CMD);
}
/**
@@ -102,6 +93,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event)
{
char buf[50];
+ lbs_deb_enter(LBS_DEB_CMD);
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
@@ -113,6 +105,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event)
}
libertas_send_iwevcustom_event(priv, buf);
+ lbs_deb_leave(LBS_DEB_CMD);
}
static int wlan_ret_reg_access(wlan_private * priv,
@@ -124,7 +117,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
switch (type) {
- case cmd_ret_mac_reg_access:
+ case CMD_RET(CMD_MAC_REG_ACCESS):
{
struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
@@ -133,7 +126,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
break;
}
- case cmd_ret_bbp_reg_access:
+ case CMD_RET(CMD_BBP_REG_ACCESS):
{
struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
@@ -142,7 +135,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
break;
}
- case cmd_ret_rf_reg_access:
+ case CMD_RET(CMD_RF_REG_ACCESS):
{
struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
@@ -155,7 +148,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
ret = -1;
}
- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
@@ -166,6 +159,7 @@ static int wlan_ret_get_hw_spec(wlan_private * priv,
struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
wlan_adapter *adapter = priv->adapter;
int ret = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_CMD);
@@ -173,22 +167,23 @@ static int wlan_ret_get_hw_spec(wlan_private * priv,
memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);
- lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion- %u.%u.%u.p%u\n",
+ lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
adapter->fwreleasenumber[2], adapter->fwreleasenumber[1],
adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]);
- lbs_deb_cmd("GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
- hwspec->permanentaddr[0], hwspec->permanentaddr[1],
- hwspec->permanentaddr[2], hwspec->permanentaddr[3],
- hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
- lbs_deb_cmd("GET_HW_SPEC: hwifversion=0x%X version=0x%X\n",
+ lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
+ print_mac(mac, hwspec->permanentaddr));
+ lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
hwspec->hwifversion, hwspec->version);
- adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+ /* Clamp region code to 8-bit since FW spec indicates that it should
+ * only ever be 8-bit, even though the field size is 16-bit. Some firmware
+ * returns non-zero high 8 bits here.
+ */
+ adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
/* use the region code to search for the index */
if (adapter->regioncode == libertas_region_code_to_index[i]) {
- adapter->regiontableindex = (u16) i;
break;
}
}
@@ -196,7 +191,6 @@ static int wlan_ret_get_hw_spec(wlan_private * priv,
/* if it's unidentified region code, use the default (USA) */
if (i >= MRVDRV_MAX_REGION_CODE) {
adapter->regioncode = 0x10;
- adapter->regiontableindex = 0;
lbs_pr_info("unidentified region code; using the default (USA)\n");
}
@@ -230,8 +224,8 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("error=%x offset=%x stabletime=%x calcontrol=%x\n"
- " extsleepclk=%x\n", le16_to_cpu(sp->error),
+ lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
+ "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
sp->calcontrol, sp->externalsleepclk);
@@ -249,6 +243,7 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv,
static int wlan_ret_802_11_stat(wlan_private * priv,
struct cmd_ds_command *resp)
{
+ lbs_deb_enter(LBS_DEB_CMD);
/* currently adapter->wlan802_11Stat is unused
struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
@@ -258,6 +253,7 @@ static int wlan_ret_802_11_stat(wlan_private * priv,
memcpy(&adapter->wlan802_11Stat,
p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
*/
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -270,28 +266,28 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+ lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
querytype);
- lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize));
+ lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
- if (querytype == cmd_act_get) {
+ if (querytype == CMD_ACT_GET) {
switch (oid) {
- case fragthresh_i:
+ case FRAGTHRESH_I:
priv->adapter->fragthsd =
le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n",
+ lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
priv->adapter->fragthsd);
break;
- case rtsthresh_i:
+ case RTSTHRESH_I:
priv->adapter->rtsthsd =
le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n",
+ lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
priv->adapter->rtsthsd);
break;
- case short_retrylim_i:
+ case SHORT_RETRYLIM_I:
priv->adapter->txretrycount =
le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n",
+ lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
priv->adapter->rtsthsd);
break;
default:
@@ -314,18 +310,19 @@ static int wlan_ret_802_11_key_material(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
/* Copy the returned key to driver private data */
- if (action == cmd_act_get) {
+ if (action == CMD_ACT_GET) {
u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
while (buf_ptr < resp_end) {
struct MrvlIEtype_keyParamSet * pkeyparamset =
(struct MrvlIEtype_keyParamSet *) buf_ptr;
- struct WLAN_802_11_KEY * pkey;
- u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+ struct enc_key * pkey;
u16 param_set_len = le16_to_cpu(pkeyparamset->length);
- u8 * end;
u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+ u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
+ u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
+ u8 * end;
end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+ sizeof (pkeyparamset->length)
@@ -334,20 +331,20 @@ static int wlan_ret_802_11_key_material(wlan_private * priv,
if (end > resp_end)
break;
- if (key_info & KEY_INFO_WPA_UNICAST)
+ if (key_flags & KEY_INFO_WPA_UNICAST)
pkey = &adapter->wpa_unicast_key;
- else if (key_info & KEY_INFO_WPA_MCAST)
+ else if (key_flags & KEY_INFO_WPA_MCAST)
pkey = &adapter->wpa_mcast_key;
else
break;
/* Copy returned key into driver */
- memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ memset(pkey, 0, sizeof(struct enc_key));
if (key_len > sizeof(pkey->key))
break;
- pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
- pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
- pkey->len = le16_to_cpu(pkeyparamset->keylen);
+ pkey->type = key_type;
+ pkey->flags = key_flags;
+ pkey->len = key_len;
memcpy(pkey->key, pkeyparamset->key, pkey->len);
buf_ptr = end + 1;
@@ -382,28 +379,9 @@ static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
- lbs_deb_cmd("Current TxPower Level = %d\n", adapter->txpowerlevel);
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
-static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
- wlan_adapter *adapter = priv->adapter;
- u16 action = le16_to_cpu(pAntenna->action);
-
- if (action == cmd_act_get_rx)
- adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode);
-
- if (action == cmd_act_get_tx)
- adapter->txantennamode = le16_to_cpu(pAntenna->antennamode);
-
- lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
- action, le16_to_cpu(pAntenna->antennamode));
+ lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -415,12 +393,12 @@ static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- if (rates->action == cmd_act_get) {
+ if (rates->action == CMD_ACT_GET) {
adapter->enablehwauto = le16_to_cpu(rates->enablehwauto);
adapter->ratebitmap = le16_to_cpu(rates->bitmap);
}
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -429,21 +407,19 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv,
{
struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
wlan_adapter *adapter = priv->adapter;
- u8 dot11datarate;
lbs_deb_enter(LBS_DEB_CMD);
- lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
- (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+ lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
+ sizeof(struct cmd_ds_802_11_data_rate));
- dot11datarate = pdatarate->datarate[0];
- if (pdatarate->action == cpu_to_le16(cmd_act_get_tx_rate)) {
- memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
- sizeof(adapter->libertas_supported_rates));
- }
- adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+ /* FIXME: get actual rates FW can do if this command actually returns
+ * all data rates supported.
+ */
+ adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]);
+ lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate);
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -457,9 +433,9 @@ static int wlan_ret_802_11_rf_channel(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- if (action == cmd_opt_802_11_rf_channel_get
+ if (action == CMD_OPT_802_11_RF_CHANNEL_GET
&& adapter->curbssparams.channel != newchannel) {
- lbs_deb_cmd("channel Switch: %d to %d\n",
+ lbs_deb_cmd("channel switch from %d to %d\n",
adapter->curbssparams.channel, newchannel);
/* Update the channel again */
@@ -476,6 +452,8 @@ static int wlan_ret_802_11_rssi(wlan_private * priv,
struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_CMD);
+
/* store the non average value */
adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
@@ -491,9 +469,11 @@ static int wlan_ret_802_11_rssi(wlan_private * priv,
CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
- lbs_deb_cmd("Beacon RSSI value = 0x%x\n",
+ lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
+ adapter->RSSI[TYPE_BEACON][TYPE_NOAVG],
adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -504,11 +484,11 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
struct wlan_ioctl_regrdwr *pbuf;
pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
- lbs_deb_cmd("eeprom read len=%x\n",
+ lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
le16_to_cpu(resp->params.rdeeprom.bytecount));
if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
pbuf->NOB = 0;
- lbs_deb_cmd("eeprom read return length is too big\n");
+ lbs_deb_cmd("EEPROM read length too big\n");
return -1;
}
pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
@@ -516,9 +496,10 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
le16_to_cpu(resp->params.rdeeprom.bytecount));
- lbs_dbg_hex("adapter", (char *)&pbuf->value,
+ lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
le16_to_cpu(resp->params.rdeeprom.bytecount));
}
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -533,7 +514,7 @@ static int wlan_ret_get_log(wlan_private * priv,
/* Stored little-endian */
memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -546,12 +527,12 @@ static int libertas_ret_802_11_enable_rsn(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- if (enable_rsn->action == cpu_to_le16(cmd_act_get)) {
+ if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
if (pdata_buf)
*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
}
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -563,135 +544,134 @@ static inline int handle_cmd_response(u16 respcmd,
unsigned long flags;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_HOST);
+
switch (respcmd) {
- case cmd_ret_mac_reg_access:
- case cmd_ret_bbp_reg_access:
- case cmd_ret_rf_reg_access:
+ case CMD_RET(CMD_MAC_REG_ACCESS):
+ case CMD_RET(CMD_BBP_REG_ACCESS):
+ case CMD_RET(CMD_RF_REG_ACCESS):
ret = wlan_ret_reg_access(priv, respcmd, resp);
break;
- case cmd_ret_hw_spec_info:
+ case CMD_RET(CMD_GET_HW_SPEC):
ret = wlan_ret_get_hw_spec(priv, resp);
break;
- case cmd_ret_802_11_scan:
+ case CMD_RET(CMD_802_11_SCAN):
ret = libertas_ret_80211_scan(priv, resp);
break;
- case cmd_ret_802_11_get_log:
+ case CMD_RET(CMD_802_11_GET_LOG):
ret = wlan_ret_get_log(priv, resp);
break;
- case cmd_ret_802_11_associate:
- case cmd_ret_802_11_reassociate:
+ case CMD_RET_802_11_ASSOCIATE:
+ case CMD_RET(CMD_802_11_ASSOCIATE):
+ case CMD_RET(CMD_802_11_REASSOCIATE):
ret = libertas_ret_80211_associate(priv, resp);
break;
- case cmd_ret_802_11_disassociate:
- case cmd_ret_802_11_deauthenticate:
+ case CMD_RET(CMD_802_11_DISASSOCIATE):
+ case CMD_RET(CMD_802_11_DEAUTHENTICATE):
ret = libertas_ret_80211_disassociate(priv, resp);
break;
- case cmd_ret_802_11_ad_hoc_start:
- case cmd_ret_802_11_ad_hoc_join:
+ case CMD_RET(CMD_802_11_AD_HOC_START):
+ case CMD_RET(CMD_802_11_AD_HOC_JOIN):
ret = libertas_ret_80211_ad_hoc_start(priv, resp);
break;
- case cmd_ret_802_11_stat:
+ case CMD_RET(CMD_802_11_GET_STAT):
ret = wlan_ret_802_11_stat(priv, resp);
break;
- case cmd_ret_802_11_snmp_mib:
+ case CMD_RET(CMD_802_11_SNMP_MIB):
ret = wlan_ret_802_11_snmp_mib(priv, resp);
break;
- case cmd_ret_802_11_rf_tx_power:
+ case CMD_RET(CMD_802_11_RF_TX_POWER):
ret = wlan_ret_802_11_rf_tx_power(priv, resp);
break;
- case cmd_ret_802_11_set_afc:
- case cmd_ret_802_11_get_afc:
+ case CMD_RET(CMD_802_11_SET_AFC):
+ case CMD_RET(CMD_802_11_GET_AFC):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
sizeof(struct cmd_ds_802_11_afc));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_rf_antenna:
- ret = wlan_ret_802_11_rf_antenna(priv, resp);
- break;
- case cmd_ret_mac_multicast_adr:
- case cmd_ret_mac_control:
- case cmd_ret_802_11_set_wep:
- case cmd_ret_802_11_reset:
- case cmd_ret_802_11_authenticate:
- case cmd_ret_802_11_radio_control:
- case cmd_ret_802_11_beacon_stop:
+ case CMD_RET(CMD_MAC_MULTICAST_ADR):
+ case CMD_RET(CMD_MAC_CONTROL):
+ case CMD_RET(CMD_802_11_SET_WEP):
+ case CMD_RET(CMD_802_11_RESET):
+ case CMD_RET(CMD_802_11_AUTHENTICATE):
+ case CMD_RET(CMD_802_11_RADIO_CONTROL):
+ case CMD_RET(CMD_802_11_BEACON_STOP):
break;
- case cmd_ret_802_11_enable_rsn:
+ case CMD_RET(CMD_802_11_ENABLE_RSN):
ret = libertas_ret_802_11_enable_rsn(priv, resp);
break;
- case cmd_ret_802_11_data_rate:
+ case CMD_RET(CMD_802_11_DATA_RATE):
ret = wlan_ret_802_11_data_rate(priv, resp);
break;
- case cmd_ret_802_11_rate_adapt_rateset:
+ case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
break;
- case cmd_ret_802_11_rf_channel:
+ case CMD_RET(CMD_802_11_RF_CHANNEL):
ret = wlan_ret_802_11_rf_channel(priv, resp);
break;
- case cmd_ret_802_11_rssi:
+ case CMD_RET(CMD_802_11_RSSI):
ret = wlan_ret_802_11_rssi(priv, resp);
break;
- case cmd_ret_802_11_mac_address:
+ case CMD_RET(CMD_802_11_MAC_ADDRESS):
ret = wlan_ret_802_11_mac_address(priv, resp);
break;
- case cmd_ret_802_11_ad_hoc_stop:
+ case CMD_RET(CMD_802_11_AD_HOC_STOP):
ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
break;
- case cmd_ret_802_11_key_material:
- lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n");
+ case CMD_RET(CMD_802_11_KEY_MATERIAL):
ret = wlan_ret_802_11_key_material(priv, resp);
break;
- case cmd_ret_802_11_eeprom_access:
+ case CMD_RET(CMD_802_11_EEPROM_ACCESS):
ret = wlan_ret_802_11_eeprom_access(priv, resp);
break;
- case cmd_ret_802_11d_domain_info:
+ case CMD_RET(CMD_802_11D_DOMAIN_INFO):
ret = libertas_ret_802_11d_domain_info(priv, resp);
break;
- case cmd_ret_802_11_sleep_params:
+ case CMD_RET(CMD_802_11_SLEEP_PARAMS):
ret = wlan_ret_802_11_sleep_params(priv, resp);
break;
- case cmd_ret_802_11_inactivity_timeout:
+ case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
spin_lock_irqsave(&adapter->driver_lock, flags);
*((u16 *) adapter->cur_cmd->pdata_buf) =
le16_to_cpu(resp->params.inactivity_timeout.timeout);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_tpc_cfg:
+ case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
sizeof(struct cmd_ds_802_11_tpc_cfg));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_led_gpio_ctrl:
+ case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
sizeof(struct cmd_ds_802_11_led_ctrl));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_pwr_cfg:
+ case CMD_RET(CMD_802_11_PWR_CFG):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
sizeof(struct cmd_ds_802_11_pwr_cfg));
@@ -699,39 +679,37 @@ static inline int handle_cmd_response(u16 respcmd,
break;
- case cmd_ret_get_tsf:
+ case CMD_RET(CMD_GET_TSF):
spin_lock_irqsave(&adapter->driver_lock, flags);
memcpy(priv->adapter->cur_cmd->pdata_buf,
&resp->params.gettsf.tsfvalue, sizeof(u64));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_bt_access:
+ case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd->pdata_buf)
memcpy(adapter->cur_cmd->pdata_buf,
&resp->params.bt.addr1, 2 * ETH_ALEN);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_fwt_access:
+ case CMD_RET(CMD_FWT_ACCESS):
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd->pdata_buf)
memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
sizeof(resp->params.fwt));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_mesh_access:
+ case CMD_RET(CMD_MESH_ACCESS):
if (adapter->cur_cmd->pdata_buf)
memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
sizeof(resp->params.mesh));
break;
- case cmd_rte_802_11_tx_rate_query:
- priv->adapter->txrate = resp->params.txrate.txrate;
- break;
default:
- lbs_deb_cmd("CMD_RESP: Unknown command response %#x\n",
+ lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
resp->command);
break;
}
+ lbs_deb_leave(LBS_DEB_HOST);
return ret;
}
@@ -744,9 +722,7 @@ int libertas_process_rx_command(wlan_private * priv)
ulong flags;
u16 result;
- lbs_deb_enter(LBS_DEB_CMD);
-
- lbs_deb_cmd("CMD_RESP: @ %lu\n", jiffies);
+ lbs_deb_enter(LBS_DEB_HOST);
/* Now we got response from FW, cancel the command timer */
del_timer(&adapter->command_timer);
@@ -755,25 +731,23 @@ int libertas_process_rx_command(wlan_private * priv)
spin_lock_irqsave(&adapter->driver_lock, flags);
if (!adapter->cur_cmd) {
- lbs_deb_cmd("CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+ lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
ret = -1;
spin_unlock_irqrestore(&adapter->driver_lock, flags);
goto done;
}
resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
- lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
- priv->upld_len);
-
respcmd = le16_to_cpu(resp->command);
-
result = le16_to_cpu(resp->result);
- lbs_deb_cmd("CMD_RESP: %x result: %d length: %d\n", respcmd,
- result, priv->upld_len);
+ lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
+ respcmd, priv->upld_len, jiffies);
+ lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr,
+ priv->upld_len);
if (!(respcmd & 0x8000)) {
- lbs_deb_cmd("Invalid response to command!");
+ lbs_deb_host("invalid response!\n");
adapter->cur_cmd_retcode = -1;
__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
adapter->nr_cmd_pending--;
@@ -786,16 +760,16 @@ int libertas_process_rx_command(wlan_private * priv)
/* Store the response code to cur_cmd_retcode. */
adapter->cur_cmd_retcode = result;;
- if (respcmd == cmd_ret_802_11_ps_mode) {
+ if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
u16 action = le16_to_cpu(psmode->action);
- lbs_deb_cmd(
- "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ lbs_deb_host(
+ "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
result, action);
if (result) {
- lbs_deb_cmd("CMD_RESP: PS command failed- %#x \n",
+ lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
result);
/*
* We should not re-try enter-ps command in
@@ -803,20 +777,20 @@ int libertas_process_rx_command(wlan_private * priv)
* libertas_execute_next_command().
*/
if (adapter->mode == IW_MODE_ADHOC &&
- action == cmd_subcmd_enter_ps)
- adapter->psmode = wlan802_11powermodecam;
- } else if (action == cmd_subcmd_enter_ps) {
+ action == CMD_SUBCMD_ENTER_PS)
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ } else if (action == CMD_SUBCMD_ENTER_PS) {
adapter->needtowakeup = 0;
adapter->psstate = PS_STATE_AWAKE;
- lbs_deb_cmd("CMD_RESP: Enter_PS command response\n");
- if (adapter->connect_status != libertas_connected) {
+ lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
+ if (adapter->connect_status != LIBERTAS_CONNECTED) {
/*
* When Deauth Event received before Enter_PS command
* response, We need to wake up the firmware.
*/
- lbs_deb_cmd(
- "Disconnected, Going to invoke libertas_ps_wakeup\n");
+ lbs_deb_host(
+ "disconnected, invoking libertas_ps_wakeup\n");
spin_unlock_irqrestore(&adapter->driver_lock, flags);
mutex_unlock(&adapter->lock);
@@ -824,12 +798,12 @@ int libertas_process_rx_command(wlan_private * priv)
mutex_lock(&adapter->lock);
spin_lock_irqsave(&adapter->driver_lock, flags);
}
- } else if (action == cmd_subcmd_exit_ps) {
+ } else if (action == CMD_SUBCMD_EXIT_PS) {
adapter->needtowakeup = 0;
adapter->psstate = PS_STATE_FULL_POWER;
- lbs_deb_cmd("CMD_RESP: Exit_PS command response\n");
+ lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
} else {
- lbs_deb_cmd("CMD_RESP: PS- action=0x%X\n", action);
+ lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
}
__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
@@ -843,22 +817,22 @@ int libertas_process_rx_command(wlan_private * priv)
if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
/* Copy the response back to response buffer */
- memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
-
+ memcpy(adapter->cur_cmd->pdata_buf, resp,
+ le16_to_cpu(resp->size));
adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
}
/* If the command is not successful, cleanup and return failure */
if ((result != 0 || !(respcmd & 0x8000))) {
- lbs_deb_cmd("CMD_RESP: command reply %#x result=%#x\n",
- respcmd, result);
+ lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
+ result, respcmd);
/*
* Handling errors here
*/
switch (respcmd) {
- case cmd_ret_hw_spec_info:
- case cmd_ret_802_11_reset:
- lbs_deb_cmd("CMD_RESP: Reset command failed\n");
+ case CMD_RET(CMD_GET_HW_SPEC):
+ case CMD_RET(CMD_802_11_RESET):
+ lbs_deb_host("CMD_RESP: reset failed\n");
break;
}
@@ -888,7 +862,7 @@ int libertas_process_rx_command(wlan_private * priv)
done:
mutex_unlock(&adapter->lock);
- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
@@ -898,13 +872,13 @@ int libertas_process_event(wlan_private * priv)
wlan_adapter *adapter = priv->adapter;
u32 eventcause;
+ lbs_deb_enter(LBS_DEB_CMD);
+
spin_lock_irq(&adapter->driver_lock);
eventcause = adapter->eventcause;
spin_unlock_irq(&adapter->driver_lock);
- lbs_deb_enter(LBS_DEB_CMD);
-
- lbs_deb_cmd("EVENT Cause %x\n", eventcause);
+ lbs_deb_cmd("event cause 0x%x\n", eventcause);
switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
case MACREG_INT_CODE_LINK_SENSED:
@@ -912,28 +886,27 @@ int libertas_process_event(wlan_private * priv)
break;
case MACREG_INT_CODE_DEAUTHENTICATED:
- lbs_deb_cmd("EVENT: Deauthenticated\n");
+ lbs_deb_cmd("EVENT: deauthenticated\n");
libertas_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_DISASSOCIATED:
- lbs_deb_cmd("EVENT: Disassociated\n");
+ lbs_deb_cmd("EVENT: disassociated\n");
libertas_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
- lbs_deb_cmd("EVENT: Link lost\n");
+ lbs_deb_cmd("EVENT: link lost\n");
libertas_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_PS_SLEEP:
- lbs_deb_cmd("EVENT: SLEEP\n");
- lbs_deb_cmd("_");
+ lbs_deb_cmd("EVENT: sleep\n");
/* handle unexpected PS SLEEP event */
if (adapter->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd(
- "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+ "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
break;
}
adapter->psstate = PS_STATE_PRE_SLEEP;
@@ -943,8 +916,7 @@ int libertas_process_event(wlan_private * priv)
break;
case MACREG_INT_CODE_PS_AWAKE:
- lbs_deb_cmd("EVENT: AWAKE \n");
- lbs_deb_cmd("|");
+ lbs_deb_cmd("EVENT: awake\n");
/* handle unexpected PS AWAKE event */
if (adapter->psstate == PS_STATE_FULL_POWER) {
@@ -962,7 +934,7 @@ int libertas_process_event(wlan_private * priv)
* adapter->needtowakeup will be set to FALSE
* in libertas_ps_wakeup()
*/
- lbs_deb_cmd("Waking up...\n");
+ lbs_deb_cmd("waking up ...\n");
libertas_ps_wakeup(priv, 0);
}
break;
@@ -981,38 +953,43 @@ int libertas_process_event(wlan_private * priv)
break;
case MACREG_INT_CODE_ADHOC_BCN_LOST:
- lbs_deb_cmd("EVENT: HWAC - ADHOC BCN LOST\n");
+ lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
break;
case MACREG_INT_CODE_RSSI_LOW:
- lbs_pr_alert( "EVENT: RSSI_LOW\n");
+ lbs_pr_alert("EVENT: rssi low\n");
break;
case MACREG_INT_CODE_SNR_LOW:
- lbs_pr_alert( "EVENT: SNR_LOW\n");
+ lbs_pr_alert("EVENT: snr low\n");
break;
case MACREG_INT_CODE_MAX_FAIL:
- lbs_pr_alert( "EVENT: MAX_FAIL\n");
+ lbs_pr_alert("EVENT: max fail\n");
break;
case MACREG_INT_CODE_RSSI_HIGH:
- lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+ lbs_pr_alert("EVENT: rssi high\n");
break;
case MACREG_INT_CODE_SNR_HIGH:
- lbs_pr_alert( "EVENT: SNR_HIGH\n");
+ lbs_pr_alert("EVENT: snr high\n");
break;
case MACREG_INT_CODE_MESH_AUTO_STARTED:
- lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n");
- adapter->connect_status = libertas_connected ;
+ /* Ignore spurious autostart events if autostart is disabled */
+ if (!priv->mesh_autostart_enabled) {
+ lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
+ break;
+ }
+ lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
+ adapter->connect_status = LIBERTAS_CONNECTED;
if (priv->mesh_open == 1) {
- netif_wake_queue(priv->mesh_dev) ;
- netif_carrier_on(priv->mesh_dev) ;
+ netif_wake_queue(priv->mesh_dev);
+ netif_carrier_on(priv->mesh_dev);
}
- adapter->mode = IW_MODE_ADHOC ;
+ adapter->mode = IW_MODE_ADHOC;
schedule_work(&priv->sync_channel);
break;
default:
- lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+ lbs_pr_alert("EVENT: unknown event id 0x%04x\n",
eventcause >> SBI_EVENT_CAUSE_SHIFT);
break;
}
@@ -1021,6 +998,6 @@ int libertas_process_event(wlan_private * priv)
adapter->eventcause = 0;
spin_unlock_irq(&adapter->driver_lock);
- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 715cbdaa1d4b..0bda0b511910 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -3,6 +3,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/mm.h>
+#include <linux/string.h>
#include <net/iw_handler.h>
#include "dev.h"
@@ -63,27 +64,27 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
int numscansdone = 0, res;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ DECLARE_MAC_BUF(mac);
struct bss_descriptor * iter_bss;
pos += snprintf(buf+pos, len-pos,
- "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
+ "# | ch | rssi | bssid | cap | Qual | SSID \n");
mutex_lock(&priv->adapter->lock);
list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
- u16 cap;
+ u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
+ u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
+ u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
- memcpy(&cap, &iter_bss->cap, sizeof(cap));
pos += snprintf(buf+pos, len-pos,
- "%02u| %03d | %03ld | " MAC_FMT " |",
+ "%02u| %03d | %04ld | %s |",
numscansdone, iter_bss->channel, iter_bss->rssi,
- MAC_ARG(iter_bss->bssid));
- pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+ print_mac(mac, iter_bss->bssid));
+ pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
pos += snprintf(buf+pos, len-pos, "%c%c%c |",
- iter_bss->cap.ibss ? 'A' : 'I',
- iter_bss->cap.privacy ? 'P' : ' ',
- iter_bss->cap.spectrummgmt ? 'S' : ' ');
- pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf);
- pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi));
+ ibss ? 'A' : 'I', privacy ? 'P' : ' ',
+ spectrum_mgmt ? 'S' : ' ');
+ pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
pos += snprintf(buf+pos, len-pos, " %s\n",
escape_essid(iter_bss->ssid, iter_bss->ssid_len));
@@ -125,9 +126,9 @@ static ssize_t libertas_sleepparams_write(struct file *file,
priv->adapter->sp.sp_reserved = p6;
res = libertas_prepare_and_send_command(priv,
- cmd_802_11_sleep_params,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_SLEEP_PARAMS,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (!res)
res = count;
@@ -150,9 +151,9 @@ static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf
char *buf = (char *)addr;
res = libertas_prepare_and_send_command(priv,
- cmd_802_11_sleep_params,
- cmd_act_get,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_SLEEP_PARAMS,
+ CMD_ACT_GET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (res) {
res = -EFAULT;
goto out_unlock;
@@ -205,7 +206,7 @@ static int libertas_parse_chan(char *buf, size_t count,
if (!start)
return -EINVAL;
start += 5;
- end = strstr(start, " ");
+ end = strchr(start, ' ');
if (!end)
end = buf + count;
hold = kzalloc((end - start)+1, GFP_KERNEL);
@@ -256,7 +257,7 @@ static void libertas_parse_ssid(char *buf, size_t count,
if (!hold)
return;
hold += 5;
- end = strstr(hold, " ");
+ end = strchr(hold, ' ');
if (!end)
end = buf + count - 1;
@@ -386,7 +387,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
struct cmd_ctrl_node **cmdnode,
struct cmd_ds_command **cmd)
{
- u16 wait_option = cmd_option_waitforrsp;
+ u16 wait_option = CMD_OPTION_WAITFORRSP;
if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
@@ -402,7 +403,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
(*cmdnode)->cmdwaitqwoken = 0;
*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
- (*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event);
+ (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
(*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
(*cmd)->result = 0;
return 0;
@@ -429,10 +430,10 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -447,7 +448,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -493,10 +494,10 @@ static u16 libertas_get_events_bitmap(wlan_private *priv)
return res;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -511,7 +512,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv)
return 0;
}
- if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
return 0;
@@ -559,7 +560,7 @@ static ssize_t libertas_lowrssi_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_rssithreshold));
@@ -575,7 +576,7 @@ static ssize_t libertas_lowrssi_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -591,7 +592,7 @@ static ssize_t libertas_lowrssi_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -625,10 +626,10 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -644,7 +645,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -712,7 +713,7 @@ static ssize_t libertas_lowsnr_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_snrthreshold));
@@ -727,7 +728,7 @@ static ssize_t libertas_lowsnr_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -743,7 +744,7 @@ static ssize_t libertas_lowsnr_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -778,10 +779,10 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -797,7 +798,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -864,7 +865,7 @@ static ssize_t libertas_failcount_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_failurecount));
@@ -879,7 +880,7 @@ static ssize_t libertas_failcount_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -895,7 +896,7 @@ static ssize_t libertas_failcount_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -929,10 +930,10 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -948,7 +949,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
free_page(addr);
kfree(response_buf);
@@ -1015,7 +1016,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_beaconsmissed));
@@ -1029,7 +1030,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1045,7 +1046,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
free_page(addr);
kfree(response_buf);
@@ -1079,10 +1080,10 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1098,7 +1099,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -1166,7 +1167,7 @@ static ssize_t libertas_highrssi_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_rssithreshold));
@@ -1181,7 +1182,7 @@ static ssize_t libertas_highrssi_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1196,7 +1197,7 @@ static ssize_t libertas_highrssi_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
return 0;
@@ -1229,10 +1230,10 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1248,7 +1249,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -1316,7 +1317,7 @@ static ssize_t libertas_highsnr_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_snrthreshold));
@@ -1331,7 +1332,7 @@ static ssize_t libertas_highsnr_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1347,7 +1348,7 @@ static ssize_t libertas_highsnr_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -1375,8 +1376,8 @@ static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
offval.value = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_mac_reg_access, 0,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_MAC_REG_ACCESS, 0,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
priv->mac_offset, adapter->offsetvalue.value);
@@ -1433,8 +1434,8 @@ static ssize_t libertas_wrmac_write(struct file *file,
offval.offset = offset;
offval.value = value;
res = libertas_prepare_and_send_command(priv,
- cmd_mac_reg_access, 1,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_MAC_REG_ACCESS, 1,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
res = count;
@@ -1458,8 +1459,8 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
offval.value = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_bbp_reg_access, 0,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_BBP_REG_ACCESS, 0,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
priv->bbp_offset, adapter->offsetvalue.value);
@@ -1517,8 +1518,8 @@ static ssize_t libertas_wrbbp_write(struct file *file,
offval.offset = offset;
offval.value = value;
res = libertas_prepare_and_send_command(priv,
- cmd_bbp_reg_access, 1,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_BBP_REG_ACCESS, 1,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
res = count;
@@ -1542,8 +1543,8 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
offval.value = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_rf_reg_access, 0,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_RF_REG_ACCESS, 0,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
priv->rf_offset, adapter->offsetvalue.value);
@@ -1601,8 +1602,8 @@ static ssize_t libertas_wrrf_write(struct file *file,
offval.offset = offset;
offval.value = value;
res = libertas_prepare_and_send_command(priv,
- cmd_rf_reg_access, 1,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_RF_REG_ACCESS, 1,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
res = count;
@@ -1839,7 +1840,7 @@ static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
char *p2;
struct debug_data *d = (struct debug_data *)f->private_data;
- pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+ pdata = kmalloc(cnt, GFP_KERNEL);
if (pdata == NULL)
return 0;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 40f56bb1eac8..87fea9d5b90a 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -15,14 +15,9 @@ struct wlan_private;
struct sk_buff;
struct net_device;
-extern char *libertas_fw_name;
-
-void libertas_free_adapter(wlan_private * priv);
int libertas_set_mac_packet_filter(wlan_private * priv);
-int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
void libertas_send_tx_feedback(wlan_private * priv);
-u8 libertas_check_last_packet_indication(wlan_private * priv);
int libertas_free_cmd_buffer(wlan_private * priv);
struct cmd_ctrl_node;
@@ -44,8 +39,8 @@ int libertas_execute_next_command(wlan_private * priv);
int libertas_process_event(wlan_private * priv);
void libertas_interrupt(struct net_device *);
int libertas_set_radio_control(wlan_private * priv);
-u32 libertas_index_to_data_rate(u8 index);
-u8 libertas_data_rate_to_index(u32 rate);
+u32 libertas_fw_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_fw_index(u32 rate);
void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
@@ -53,8 +48,6 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
/** The proc fs interface */
int libertas_process_rx_command(wlan_private * priv);
int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
-void libertas_cleanup_and_insert_cmd(wlan_private * priv,
- struct cmd_ctrl_node *ptempcmd);
void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
struct cmd_ctrl_node *ptempcmd);
@@ -75,17 +68,15 @@ void libertas_mac_event_disconnected(wlan_private * priv);
void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
-/* fw.c */
-int libertas_init_fw(wlan_private * priv, char *fw_name);
-
/* main.c */
struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
int *cfp_no);
wlan_private *libertas_add_card(void *card, struct device *dmdev);
-int libertas_activate_card(wlan_private *priv, char *fw_name);
int libertas_remove_card(wlan_private *priv);
+int libertas_start_card(wlan_private *priv);
+int libertas_stop_card(wlan_private *priv);
int libertas_add_mesh(wlan_private *priv, struct device *dev);
void libertas_remove_mesh(wlan_private *priv);
-
+int libertas_reset_device(wlan_private *priv);
#endif /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 4dd43e59bda0..7c5b7f7b45db 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -43,43 +43,43 @@
extern unsigned int libertas_debug;
#ifdef DEBUG
-#define LBS_DEB_LL(grp, fmt, args...) \
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
do { if ((libertas_debug & (grp)) == (grp)) \
- printk(KERN_DEBUG DRV_NAME "%s: " fmt, \
+ printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
in_interrupt() ? " (INT)" : "", ## args); } while (0)
#else
-#define LBS_DEB_LL(grp, fmt, args...) do {} while (0)
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
#endif
#define lbs_deb_enter(grp) \
- LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s():%d enter\n", __FUNCTION__, __LINE__);
+ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__);
#define lbs_deb_enter_args(grp, fmt, args...) \
- LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
+ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
#define lbs_deb_leave(grp) \
- LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave\n", __FUNCTION__, __LINE__);
+ LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__);
#define lbs_deb_leave_args(grp, fmt, args...) \
- LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave, " fmt "\n", \
+ LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \
__FUNCTION__, __LINE__, ##args);
-#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, fmt, ##args)
-#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, fmt, ##args)
-#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, fmt, ##args)
-#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, fmt, ##args)
-#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, fmt, ##args)
-#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, fmt, ##args)
-#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, fmt, ##args)
-#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, fmt, ##args)
-#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, fmt, ##args)
-#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, fmt, ##args)
-#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, fmt, ##args)
-#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, fmt, ##args)
-#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, fmt, ##args)
-#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, fmt, ##args)
-#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, fmt, ##args)
-#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, fmt, ##args)
-#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, fmt, ##args)
-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, "%s:" fmt, (dev)->bus_id, ##args)
-#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, fmt, ##args)
-#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, fmt, ##args)
+#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
+#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
+#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
+#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
+#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
+#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
+#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
+#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
+#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
+#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
+#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
+#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
+#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
+#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
+#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
+#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
+#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
+#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
+#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
+#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -89,22 +89,28 @@ do { if ((libertas_debug & (grp)) == (grp)) \
printk(KERN_ALERT DRV_NAME": " format, ## args)
#ifdef DEBUG
-static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
{
int i = 0;
- if (!(libertas_debug & LBS_DEB_HEX))
- return;
-
- printk(KERN_DEBUG "%s: ", prompt);
- for (i = 1; i <= len; i++) {
- printk("%02x ", (u8) * buf);
- buf++;
+ if (len &&
+ (libertas_debug & LBS_DEB_HEX) &&
+ (libertas_debug & grp))
+ {
+ for (i = 1; i <= len; i++) {
+ if ((i & 0xf) == 1) {
+ if (i != 1)
+ printk("\n");
+ printk(DRV_NAME " %s: ", prompt);
+ }
+ printk("%02x ", (u8) * buf);
+ buf++;
+ }
+ printk("\n");
}
- printk("\n");
}
#else
-#define lbs_dbg_hex(x,y,z) do {} while (0)
+#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0)
#endif
@@ -149,17 +155,18 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
#define MRVDRV_CHANNELS_PER_SCAN 4
#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
-#define MRVDRV_DEBUG_RX_PATH 0x00000001
-#define MRVDRV_DEBUG_TX_PATH 0x00000002
-
#define MRVDRV_MIN_BEACON_INTERVAL 20
#define MRVDRV_MAX_BEACON_INTERVAL 1000
#define MRVDRV_BEACON_INTERVAL 100
+#define MARVELL_MESH_IE_LENGTH 9
+
/** INT status Bit Definition*/
-#define his_cmddnldrdy 0x01
-#define his_cardevent 0x02
-#define his_cmdupldrdy 0x04
+#define MRVDRV_TX_DNLD_RDY 0x0001
+#define MRVDRV_RX_UPLD_RDY 0x0002
+#define MRVDRV_CMD_DNLD_RDY 0x0004
+#define MRVDRV_CMD_UPLD_RDY 0x0008
+#define MRVDRV_CARDEVENT 0x0010
#define SBI_EVENT_CAUSE_SHIFT 3
@@ -218,9 +225,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
#define CMD_F_HOSTCMD (1 << 0)
#define FW_CAPINFO_WPA (1 << 0)
-/** WPA key LENGTH*/
-#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
-
#define KEY_LEN_WPA_AES 16
#define KEY_LEN_WPA_TKIP 32
#define KEY_LEN_WEP_104 13
@@ -247,10 +251,7 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
AVG_SCALE)) / N))
-#define B_SUPPORTED_RATES 8
-#define G_SUPPORTED_RATES 14
-
-#define WLAN_SUPPORTED_RATES 14
+#define MAX_RATES 14
#define MAX_LEDS 8
@@ -264,11 +265,7 @@ typedef struct _wlan_adapter wlan_adapter;
extern const char libertas_driver_version[];
extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
-
-extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
-
-extern u8 libertas_adhoc_rates_b[4];
+extern u8 libertas_bg_rates[MAX_RATES];
/** ENUM definition*/
/** SNRNF_TYPE */
@@ -287,11 +284,11 @@ enum SNRNF_DATA {
/** WLAN_802_11_POWER_MODE */
enum WLAN_802_11_POWER_MODE {
- wlan802_11powermodecam,
- wlan802_11powermodemax_psp,
- wlan802_11Powermodefast_psp,
+ WLAN802_11POWERMODECAM,
+ WLAN802_11POWERMODEMAX_PSP,
+ WLAN802_11POWERMODEFAST_PSP,
/*not a real mode, defined as an upper bound */
- wlan802_11powemodemax
+ WLAN802_11POWEMODEMAX
};
/** PS_STATE */
@@ -311,14 +308,14 @@ enum DNLD_STATE {
/** WLAN_MEDIA_STATE */
enum WLAN_MEDIA_STATE {
- libertas_connected,
- libertas_disconnected
+ LIBERTAS_CONNECTED,
+ LIBERTAS_DISCONNECTED
};
/** WLAN_802_11_PRIVACY_FILTER */
enum WLAN_802_11_PRIVACY_FILTER {
- wlan802_11privfilteracceptall,
- wlan802_11privfilter8021xWEP
+ WLAN802_11PRIVFILTERACCEPTALL,
+ WLAN802_11PRIVFILTER8021XWEP
};
/** mv_ms_type */
@@ -331,23 +328,23 @@ enum mv_ms_type {
/** SNMP_MIB_INDEX_e */
enum SNMP_MIB_INDEX_e {
- desired_bsstype_i = 0,
- op_rateset_i,
- bcnperiod_i,
- dtimperiod_i,
- assocrsp_timeout_i,
- rtsthresh_i,
- short_retrylim_i,
- long_retrylim_i,
- fragthresh_i,
- dot11d_i,
- dot11h_i,
- manufid_i,
- prodID_i,
- manuf_oui_i,
- manuf_name_i,
- manuf_prodname_i,
- manuf_prodver_i,
+ DESIRED_BSSTYPE_I = 0,
+ OP_RATESET_I,
+ BCNPERIOD_I,
+ DTIMPERIOD_I,
+ ASSOCRSP_TIMEOUT_I,
+ RTSTHRESH_I,
+ SHORT_RETRYLIM_I,
+ LONG_RETRYLIM_I,
+ FRAGTHRESH_I,
+ DOT11D_I,
+ DOT11H_I,
+ MANUFID_I,
+ PRODID_I,
+ MANUF_OUI_I,
+ MANUF_NAME_I,
+ MANUF_PRODNAME_I,
+ MANUF_PRODVER_I,
};
/** KEY_TYPE_ID */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 785192b884bc..1fb807aa91b9 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -14,7 +14,6 @@
#include "defs.h"
#include "scan.h"
-#include "thread.h"
extern struct ethtool_ops libertas_ethtool_ops;
@@ -73,10 +72,8 @@ struct current_bss_params {
u8 band;
/** channel */
u8 channel;
- /** number of rates supported */
- int numofrates;
- /** supported rates*/
- u8 datarates[WLAN_SUPPORTED_RATES];
+ /** zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
};
/** sleep_params */
@@ -106,6 +103,8 @@ struct _wlan_private {
int open;
int mesh_open;
int infra_open;
+ int mesh_autostart_enabled;
+ __le16 boot2_version;
char name[DEV_NAME_LEN];
@@ -114,7 +113,9 @@ struct _wlan_private {
struct net_device *dev;
struct net_device_stats stats;
- struct net_device *mesh_dev ; /* Virtual device */
+ struct net_device *mesh_dev; /* Virtual device */
+ struct net_device *rtap_net_dev;
+ struct ieee80211_device *ieee;
struct iw_statistics wstats;
struct wlan_mesh_stats mstats;
@@ -142,20 +143,18 @@ struct _wlan_private {
all other bits reserved 0 */
u8 dnld_sent;
- const struct firmware *firmware;
struct device *hotplug_device;
/** thread to service interrupts */
- struct wlan_thread mainthread;
+ struct task_struct *main_thread;
+ wait_queue_head_t waitq;
+ struct workqueue_struct *work_thread;
+ struct delayed_work scan_work;
struct delayed_work assoc_work;
- struct workqueue_struct *assoc_thread;
struct work_struct sync_channel;
/** Hardware access */
- int (*hw_register_dev) (wlan_private * priv);
- int (*hw_unregister_dev) (wlan_private *);
- int (*hw_prog_firmware) (wlan_private *);
int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb);
int (*hw_get_int_status) (wlan_private * priv, u8 *);
int (*hw_read_event_cause) (wlan_private *);
@@ -188,12 +187,12 @@ struct assoc_request {
u8 bssid[ETH_ALEN];
/** WEP keys */
- struct WLAN_802_11_KEY wep_keys[4];
+ struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
- struct WLAN_802_11_KEY wpa_mcast_key;
- struct WLAN_802_11_KEY wpa_unicast_key;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
struct wlan_802_11_security secinfo;
@@ -259,23 +258,15 @@ struct _wlan_adapter {
/* IW_MODE_* */
u8 mode;
- u8 prev_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 prev_ssid_len;
- u8 prev_bssid[ETH_ALEN];
-
/* Scan results list */
struct list_head network_list;
struct list_head network_free_list;
struct bss_descriptor *networks;
- u8 scantype;
- u32 scanmode;
-
- u16 beaconperiod;
u8 adhoccreate;
/** capability Info used in Association, start, join */
- struct ieeetypes_capinfo capinfo;
+ u16 capability;
/** MAC address information */
u8 current_addr[ETH_ALEN];
@@ -287,20 +278,10 @@ struct _wlan_adapter {
u16 enablehwauto;
u16 ratebitmap;
- /** control G rates */
- u8 adhoc_grate_enabled;
-
- u32 txantenna;
- u32 rxantenna;
u32 fragthsd;
u32 rtsthsd;
- u32 datarate;
- u8 is_datarate_auto;
-
- u16 listeninterval;
- u16 prescan;
u8 txretrycount;
/** Tx-related variables (for single packet tx) */
@@ -311,22 +292,17 @@ struct _wlan_adapter {
u16 currentpacketfilter;
u32 connect_status;
u16 regioncode;
- u16 regiontableindex;
u16 txpowerlevel;
/** POWER MANAGEMENT AND PnP SUPPORT */
u8 surpriseremoved;
- u16 atimwindow;
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
- u16 multipledtim;
u32 psstate;
u8 needtowakeup;
struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
- u16 locallisteninterval;
- u16 nullpktinterval;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
@@ -335,23 +311,18 @@ struct _wlan_adapter {
struct wlan_802_11_security secinfo;
/** WEP keys */
- struct WLAN_802_11_KEY wep_keys[4];
+ struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
- struct WLAN_802_11_KEY wpa_mcast_key;
- struct WLAN_802_11_KEY wpa_unicast_key;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
- u16 rxantennamode;
- u16 txantennamode;
-
/** Requested Signal Strength*/
- u16 bcn_avg_factor;
- u16 data_avg_factor;
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
@@ -359,15 +330,13 @@ struct _wlan_adapter {
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF;
u16 numSNRNF;
- u16 rxpd_rate;
u8 radioon;
u32 preamble;
- /** Multi bands Parameter*/
- u8 libertas_supported_rates[G_SUPPORTED_RATES];
-
- /** Blue Tooth Co-existence Arbitration */
+ /** data rate stuff */
+ u8 cur_rate;
+ u8 auto_rate;
/** sleep_params */
struct sleep_params sp;
@@ -392,14 +361,8 @@ struct _wlan_adapter {
struct wlan_offset_value offsetvalue;
struct cmd_ds_802_11_get_log logmsg;
- u16 scanprobes;
-
- u32 pkttxctrl;
- u16 txrate;
- u32 linkmode;
- u32 radiomode;
- u32 debugmode;
+ u32 monitormode;
u8 fw_ready;
u8 last_scanned_channel;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 96f1974685d4..3dae15211b6a 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -60,8 +60,7 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev,
// mutex_lock(&priv->mutex);
- adapter->prdeeprom =
- (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+ adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
if (!adapter->prdeeprom)
return -ENOMEM;
memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
@@ -72,9 +71,9 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev,
regctrl.action, regctrl.offset, regctrl.NOB);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_eeprom_access,
+ CMD_802_11_EEPROM_ACCESS,
regctrl.action,
- cmd_option_waitforrsp, 0,
+ CMD_OPTION_WAITFORRSP, 0,
&regctrl);
if (ret) {
@@ -110,56 +109,48 @@ static void libertas_ethtool_get_stats(struct net_device * dev,
struct ethtool_stats * stats, u64 * data)
{
wlan_private *priv = dev->priv;
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
lbs_deb_enter(LBS_DEB_ETHTOOL);
- stats->cmd = ETHTOOL_GSTATS;
- BUG_ON(stats->n_stats != MESH_STATS_NUM);
-
- data[0] = priv->mstats.fwd_drop_rbt;
- data[1] = priv->mstats.fwd_drop_ttl;
- data[2] = priv->mstats.fwd_drop_noroute;
- data[3] = priv->mstats.fwd_drop_nobuf;
- data[4] = priv->mstats.fwd_unicast_cnt;
- data[5] = priv->mstats.fwd_bcast_cnt;
- data[6] = priv->mstats.drop_blind;
- data[7] = priv->mstats.tx_failed_cnt;
+ /* Get Mesh Statistics */
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
+ CMD_OPTION_WAITFORRSP, 0, &mesh_access);
+
+ if (ret)
+ return;
+
+ priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
+ priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
+ priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
+ priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
+ priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
+ priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
+ priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
+ priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
+
+ data[0] = priv->mstats.fwd_drop_rbt;
+ data[1] = priv->mstats.fwd_drop_ttl;
+ data[2] = priv->mstats.fwd_drop_noroute;
+ data[3] = priv->mstats.fwd_drop_nobuf;
+ data[4] = priv->mstats.fwd_unicast_cnt;
+ data[5] = priv->mstats.fwd_bcast_cnt;
+ data[6] = priv->mstats.drop_blind;
+ data[7] = priv->mstats.tx_failed_cnt;
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
-static int libertas_ethtool_get_stats_count(struct net_device * dev)
+static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset)
{
- int ret;
- wlan_private *priv = dev->priv;
- struct cmd_ds_mesh_access mesh_access;
-
- lbs_deb_enter(LBS_DEB_ETHTOOL);
-
- /* Get Mesh Statistics */
- ret = libertas_prepare_and_send_command(priv,
- cmd_mesh_access, cmd_act_mesh_get_stats,
- cmd_option_waitforrsp, 0, &mesh_access);
-
- if (ret) {
- ret = 0;
- goto done;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MESH_STATS_NUM;
+ default:
+ return -EOPNOTSUPP;
}
-
- priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
- priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
- priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
- priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
- priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
- priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
- priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
- priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
-
- ret = MESH_STATS_NUM;
-
-done:
- lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
- return ret;
}
static void libertas_ethtool_get_strings (struct net_device * dev,
@@ -186,7 +177,7 @@ struct ethtool_ops libertas_ethtool_ops = {
.get_drvinfo = libertas_ethtool_get_drvinfo,
.get_eeprom = libertas_ethtool_get_eeprom,
.get_eeprom_len = libertas_ethtool_get_eeprom_len,
- .get_stats_count = libertas_ethtool_get_stats_count,
+ .get_sset_count = libertas_ethtool_get_sset_count,
.get_ethtool_stats = libertas_ethtool_get_stats,
.get_strings = libertas_ethtool_get_strings,
};
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
deleted file mode 100644
index 2dc84ff7a54a..000000000000
--- a/drivers/net/wireless/libertas/fw.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/**
- * This file contains the initialization for FW and HW
- */
-#include <linux/firmware.h>
-
-#include "host.h"
-#include "defs.h"
-#include "decl.h"
-#include "dev.h"
-#include "wext.h"
-#include "if_usb.h"
-
-/**
- * @brief This function checks the validity of Boot2/FW image.
- *
- * @param data pointer to image
- * len image length
- * @return 0 or -1
- */
-static int check_fwfile_format(u8 *data, u32 totlen)
-{
- u32 bincmd, exit;
- u32 blksize, offset, len;
- int ret;
-
- ret = 1;
- exit = len = 0;
-
- do {
- struct fwheader *fwh = (void *)data;
-
- bincmd = le32_to_cpu(fwh->dnldcmd);
- blksize = le32_to_cpu(fwh->datalength);
- switch (bincmd) {
- case FW_HAS_DATA_TO_RECV:
- offset = sizeof(struct fwheader) + blksize;
- data += offset;
- len += offset;
- if (len >= totlen)
- exit = 1;
- break;
- case FW_HAS_LAST_BLOCK:
- exit = 1;
- ret = 0;
- break;
- default:
- exit = 1;
- break;
- }
- } while (!exit);
-
- if (ret)
- lbs_pr_err("firmware file format check FAIL\n");
- else
- lbs_deb_fw("firmware file format check PASS\n");
-
- return ret;
-}
-
-/**
- * @brief This function downloads firmware image, gets
- * HW spec from firmware and set basic parameters to
- * firmware.
- *
- * @param priv A pointer to wlan_private structure
- * @return 0 or -1
- */
-static int wlan_setup_station_hw(wlan_private * priv, char *fw_name)
-{
- int ret = -1;
- wlan_adapter *adapter = priv->adapter;
-
- lbs_deb_enter(LBS_DEB_FW);
-
- if ((ret = request_firmware(&priv->firmware, fw_name,
- priv->hotplug_device)) < 0) {
- lbs_pr_err("request_firmware() failed with %#x\n", ret);
- lbs_pr_err("firmware %s not found\n", fw_name);
- goto done;
- }
-
- if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
- release_firmware(priv->firmware);
- goto done;
- }
-
- ret = priv->hw_prog_firmware(priv);
-
- release_firmware(priv->firmware);
-
- if (ret) {
- lbs_deb_fw("bootloader in invalid state\n");
- ret = -1;
- goto done;
- }
-
- /*
- * Read MAC address from HW
- */
- memset(adapter->current_addr, 0xff, ETH_ALEN);
-
- ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
- 0, cmd_option_waitforrsp, 0, NULL);
-
- if (ret) {
- ret = -1;
- goto done;
- }
-
- libertas_set_mac_packet_filter(priv);
-
- /* Get the supported Data rates */
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
- cmd_act_get_tx_rate,
- cmd_option_waitforrsp, 0, NULL);
-
- if (ret) {
- ret = -1;
- goto done;
- }
-
- ret = 0;
-done:
- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
- return ret;
-}
-
-static int wlan_allocate_adapter(wlan_private * priv)
-{
- size_t bufsize;
- wlan_adapter *adapter = priv->adapter;
-
- /* Allocate buffer to store the BSSID list */
- bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
- adapter->networks = kzalloc(bufsize, GFP_KERNEL);
- if (!adapter->networks) {
- lbs_pr_err("Out of memory allocating beacons\n");
- libertas_free_adapter(priv);
- return -ENOMEM;
- }
-
- /* Allocate the command buffers */
- libertas_allocate_cmd_buffer(priv);
-
- memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
- adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
- adapter->libertas_ps_confirm_sleep.command =
- cpu_to_le16(cmd_802_11_ps_mode);
- adapter->libertas_ps_confirm_sleep.size =
- cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
- adapter->libertas_ps_confirm_sleep.result = 0;
- adapter->libertas_ps_confirm_sleep.action =
- cpu_to_le16(cmd_subcmd_sleep_confirmed);
-
- return 0;
-}
-
-static void wlan_init_adapter(wlan_private * priv)
-{
- wlan_adapter *adapter = priv->adapter;
- int i;
-
- adapter->scanprobes = 0;
-
- adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
- adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
-
- /* ATIM params */
- adapter->atimwindow = 0;
-
- adapter->connect_status = libertas_disconnected;
- memset(adapter->current_addr, 0xff, ETH_ALEN);
-
- /* scan type */
- adapter->scantype = cmd_scan_type_active;
-
- /* scan mode */
- adapter->scanmode = cmd_bss_type_any;
-
- /* 802.11 specific */
- adapter->secinfo.wep_enabled = 0;
- for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
- i++)
- memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
- adapter->wep_tx_keyidx = 0;
- adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- adapter->mode = IW_MODE_INFRA;
-
- adapter->pending_assoc_req = NULL;
- adapter->in_progress_assoc_req = NULL;
-
- /* Initialize scan result lists */
- INIT_LIST_HEAD(&adapter->network_free_list);
- INIT_LIST_HEAD(&adapter->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- list_add_tail(&adapter->networks[i].list,
- &adapter->network_free_list);
- }
-
- mutex_init(&adapter->lock);
-
- adapter->prescan = 1;
-
- memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
- adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-
- /* PnP and power profile */
- adapter->surpriseremoved = 0;
-
- adapter->currentpacketfilter =
- cmd_act_mac_rx_on | cmd_act_mac_tx_on;
-
- adapter->radioon = RADIO_ON;
- adapter->txantenna = RF_ANTENNA_2;
- adapter->rxantenna = RF_ANTENNA_AUTO;
-
- adapter->is_datarate_auto = 1;
- adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
-
- // set default value of capinfo.
-#define SHORT_PREAMBLE_ALLOWED 1
- memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
- adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
-
- adapter->psmode = wlan802_11powermodecam;
- adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
-
- adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
-
- adapter->psstate = PS_STATE_FULL_POWER;
- adapter->needtowakeup = 0;
- adapter->locallisteninterval = 0; /* default value in firmware will be used */
-
- adapter->datarate = 0; // Initially indicate the rate as auto
-
- adapter->adhoc_grate_enabled = 0;
-
- adapter->intcounter = 0;
-
- adapter->currenttxskb = NULL;
- adapter->pkttxctrl = 0;
-
- memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
- adapter->tx_queue_idx = 0;
- spin_lock_init(&adapter->txqueue_lock);
-
- return;
-}
-
-static void command_timer_fn(unsigned long data);
-
-int libertas_init_fw(wlan_private * priv, char *fw_name)
-{
- int ret = -1;
- wlan_adapter *adapter = priv->adapter;
-
- lbs_deb_enter(LBS_DEB_FW);
-
- /* Allocate adapter structure */
- if ((ret = wlan_allocate_adapter(priv)) != 0)
- goto done;
-
- /* init adapter structure */
- wlan_init_adapter(priv);
-
- /* init timer etc. */
- setup_timer(&adapter->command_timer, command_timer_fn,
- (unsigned long)priv);
-
- /* download fimrware etc. */
- if ((ret = wlan_setup_station_hw(priv, fw_name)) != 0) {
- del_timer_sync(&adapter->command_timer);
- goto done;
- }
-
- /* init 802.11d */
- libertas_init_11d(priv);
-
- ret = 0;
-done:
- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
- return ret;
-}
-
-void libertas_free_adapter(wlan_private * priv)
-{
- wlan_adapter *adapter = priv->adapter;
-
- if (!adapter) {
- lbs_deb_fw("why double free adapter?\n");
- return;
- }
-
- lbs_deb_fw("free command buffer\n");
- libertas_free_cmd_buffer(priv);
-
- lbs_deb_fw("free command_timer\n");
- del_timer(&adapter->command_timer);
-
- lbs_deb_fw("free scan results table\n");
- kfree(adapter->networks);
- adapter->networks = NULL;
-
- /* Free the adapter object itself */
- lbs_deb_fw("free adapter\n");
- kfree(adapter);
- priv->adapter = NULL;
-}
-
-/**
- * This function handles the timeout of command sending.
- * It will re-send the same command again.
- */
-static void command_timer_fn(unsigned long data)
-{
- wlan_private *priv = (wlan_private *)data;
- wlan_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *ptempnode;
- struct cmd_ds_command *cmd;
- unsigned long flags;
-
- ptempnode = adapter->cur_cmd;
- if (ptempnode == NULL) {
- lbs_deb_fw("ptempnode empty\n");
- return;
- }
-
- cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
- if (!cmd) {
- lbs_deb_fw("cmd is NULL\n");
- return;
- }
-
- lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
-
- if (!adapter->fw_ready)
- return;
-
- spin_lock_irqsave(&adapter->driver_lock, flags);
- adapter->cur_cmd = NULL;
- spin_unlock_irqrestore(&adapter->driver_lock, flags);
-
- lbs_deb_fw("re-sending same command because of timeout\n");
- libertas_queue_cmd(adapter, ptempnode, 0);
-
- wake_up_interruptible(&priv->mainthread.waitq);
-
- return;
-}
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 7509cc10af3c..b37ddbca969f 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -20,224 +20,163 @@
#define OID_802_11_TX_RETRYCOUNT 0x0000801D
#define OID_802_11D_ENABLE 0x00008020
-#define cmd_option_waitforrsp 0x0002
+#define CMD_OPTION_WAITFORRSP 0x0002
-/** Host command ID */
-#define cmd_code_dnld 0x0002
-#define cmd_get_hw_spec 0x0003
-#define cmd_eeprom_update 0x0004
-#define cmd_802_11_reset 0x0005
-#define cmd_802_11_scan 0x0006
-#define cmd_802_11_get_log 0x000b
-#define cmd_mac_multicast_adr 0x0010
-#define cmd_802_11_authenticate 0x0011
-#define cmd_802_11_eeprom_access 0x0059
-#define cmd_802_11_associate 0x0050
-#define cmd_802_11_set_wep 0x0013
-#define cmd_802_11_get_stat 0x0014
-#define cmd_802_3_get_stat 0x0015
-#define cmd_802_11_snmp_mib 0x0016
-#define cmd_mac_reg_map 0x0017
-#define cmd_bbp_reg_map 0x0018
-#define cmd_mac_reg_access 0x0019
-#define cmd_bbp_reg_access 0x001a
-#define cmd_rf_reg_access 0x001b
-#define cmd_802_11_radio_control 0x001c
-#define cmd_802_11_rf_channel 0x001d
-#define cmd_802_11_rf_tx_power 0x001e
-#define cmd_802_11_rssi 0x001f
-#define cmd_802_11_rf_antenna 0x0020
+/** Host command IDs */
-#define cmd_802_11_ps_mode 0x0021
+/* Return command are almost always the same as the host command, but with
+ * bit 15 set high. There are a few exceptions, though...
+ */
+#define CMD_RET(cmd) (0x8000 | cmd)
-#define cmd_802_11_data_rate 0x0022
-#define cmd_rf_reg_map 0x0023
-#define cmd_802_11_deauthenticate 0x0024
-#define cmd_802_11_reassociate 0x0025
-#define cmd_802_11_disassociate 0x0026
-#define cmd_mac_control 0x0028
-#define cmd_802_11_ad_hoc_start 0x002b
-#define cmd_802_11_ad_hoc_join 0x002c
+/* Return command convention exceptions: */
+#define CMD_RET_802_11_ASSOCIATE 0x8012
-#define cmd_802_11_query_tkip_reply_cntrs 0x002e
-#define cmd_802_11_enable_rsn 0x002f
-#define cmd_802_11_pairwise_tsc 0x0036
-#define cmd_802_11_group_tsc 0x0037
-#define cmd_802_11_key_material 0x005e
+/* Command codes */
+#define CMD_CODE_DNLD 0x0002
+#define CMD_GET_HW_SPEC 0x0003
+#define CMD_EEPROM_UPDATE 0x0004
+#define CMD_802_11_RESET 0x0005
+#define CMD_802_11_SCAN 0x0006
+#define CMD_802_11_GET_LOG 0x000b
+#define CMD_MAC_MULTICAST_ADR 0x0010
+#define CMD_802_11_AUTHENTICATE 0x0011
+#define CMD_802_11_EEPROM_ACCESS 0x0059
+#define CMD_802_11_ASSOCIATE 0x0050
+#define CMD_802_11_SET_WEP 0x0013
+#define CMD_802_11_GET_STAT 0x0014
+#define CMD_802_3_GET_STAT 0x0015
+#define CMD_802_11_SNMP_MIB 0x0016
+#define CMD_MAC_REG_MAP 0x0017
+#define CMD_BBP_REG_MAP 0x0018
+#define CMD_MAC_REG_ACCESS 0x0019
+#define CMD_BBP_REG_ACCESS 0x001a
+#define CMD_RF_REG_ACCESS 0x001b
+#define CMD_802_11_RADIO_CONTROL 0x001c
+#define CMD_802_11_RF_CHANNEL 0x001d
+#define CMD_802_11_RF_TX_POWER 0x001e
+#define CMD_802_11_RSSI 0x001f
+#define CMD_802_11_RF_ANTENNA 0x0020
-#define cmd_802_11_set_afc 0x003c
-#define cmd_802_11_get_afc 0x003d
+#define CMD_802_11_PS_MODE 0x0021
-#define cmd_802_11_ad_hoc_stop 0x0040
+#define CMD_802_11_DATA_RATE 0x0022
+#define CMD_RF_REG_MAP 0x0023
+#define CMD_802_11_DEAUTHENTICATE 0x0024
+#define CMD_802_11_REASSOCIATE 0x0025
+#define CMD_802_11_DISASSOCIATE 0x0026
+#define CMD_MAC_CONTROL 0x0028
+#define CMD_802_11_AD_HOC_START 0x002b
+#define CMD_802_11_AD_HOC_JOIN 0x002c
-#define cmd_802_11_beacon_stop 0x0049
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
+#define CMD_802_11_ENABLE_RSN 0x002f
+#define CMD_802_11_PAIRWISE_TSC 0x0036
+#define CMD_802_11_GROUP_TSC 0x0037
+#define CMD_802_11_KEY_MATERIAL 0x005e
-#define cmd_802_11_mac_address 0x004D
-#define cmd_802_11_eeprom_access 0x0059
+#define CMD_802_11_SET_AFC 0x003c
+#define CMD_802_11_GET_AFC 0x003d
-#define cmd_802_11_band_config 0x0058
+#define CMD_802_11_AD_HOC_STOP 0x0040
-#define cmd_802_11d_domain_info 0x005b
+#define CMD_802_11_BEACON_STOP 0x0049
-#define cmd_802_11_sleep_params 0x0066
+#define CMD_802_11_MAC_ADDRESS 0x004D
+#define CMD_802_11_EEPROM_ACCESS 0x0059
-#define cmd_802_11_inactivity_timeout 0x0067
+#define CMD_802_11_BAND_CONFIG 0x0058
-#define cmd_802_11_tpc_cfg 0x0072
-#define cmd_802_11_pwr_cfg 0x0073
+#define CMD_802_11D_DOMAIN_INFO 0x005b
-#define cmd_802_11_led_gpio_ctrl 0x004e
+#define CMD_802_11_SLEEP_PARAMS 0x0066
-#define cmd_802_11_subscribe_event 0x0075
+#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
-#define cmd_802_11_rate_adapt_rateset 0x0076
+#define CMD_802_11_TPC_CFG 0x0072
+#define CMD_802_11_PWR_CFG 0x0073
-#define cmd_802_11_tx_rate_query 0x007f
+#define CMD_802_11_LED_GPIO_CTRL 0x004e
-#define cmd_get_tsf 0x0080
+#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
-#define cmd_bt_access 0x0087
-#define cmd_ret_bt_access 0x8087
+#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
-#define cmd_fwt_access 0x0095
-#define cmd_ret_fwt_access 0x8095
+#define CMD_802_11_TX_RATE_QUERY 0x007f
-#define cmd_mesh_access 0x009b
-#define cmd_ret_mesh_access 0x809b
+#define CMD_GET_TSF 0x0080
+
+#define CMD_BT_ACCESS 0x0087
+
+#define CMD_FWT_ACCESS 0x0095
+
+#define CMD_802_11_MONITOR_MODE 0x0098
+
+#define CMD_MESH_ACCESS 0x009b
+
+#define CMD_SET_BOOT2_VER 0x00a5
/* For the IEEE Power Save */
-#define cmd_subcmd_enter_ps 0x0030
-#define cmd_subcmd_exit_ps 0x0031
-#define cmd_subcmd_sleep_confirmed 0x0034
-#define cmd_subcmd_full_powerdown 0x0035
-#define cmd_subcmd_full_powerup 0x0036
+#define CMD_SUBCMD_ENTER_PS 0x0030
+#define CMD_SUBCMD_EXIT_PS 0x0031
+#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
+#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
+#define CMD_SUBCMD_FULL_POWERUP 0x0036
+
+#define CMD_ENABLE_RSN 0x0001
+#define CMD_DISABLE_RSN 0x0000
+
+#define CMD_ACT_SET 0x0001
+#define CMD_ACT_GET 0x0000
+
+#define CMD_ACT_GET_AES (CMD_ACT_GET + 2)
+#define CMD_ACT_SET_AES (CMD_ACT_SET + 2)
+#define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3)
+
+/* Define action or option for CMD_802_11_SET_WEP */
+#define CMD_ACT_ADD 0x0002
+#define CMD_ACT_REMOVE 0x0004
+#define CMD_ACT_USE_DEFAULT 0x0008
+
+#define CMD_TYPE_WEP_40_BIT 0x01
+#define CMD_TYPE_WEP_104_BIT 0x02
+
+#define CMD_NUM_OF_WEP_KEYS 4
+
+#define CMD_WEP_KEY_INDEX_MASK 0x3fff
-/* command RET code, MSB is set to 1 */
-#define cmd_ret_hw_spec_info 0x8003
-#define cmd_ret_eeprom_update 0x8004
-#define cmd_ret_802_11_reset 0x8005
-#define cmd_ret_802_11_scan 0x8006
-#define cmd_ret_802_11_get_log 0x800b
-#define cmd_ret_mac_control 0x8028
-#define cmd_ret_mac_multicast_adr 0x8010
-#define cmd_ret_802_11_authenticate 0x8011
-#define cmd_ret_802_11_deauthenticate 0x8024
-#define cmd_ret_802_11_associate 0x8012
-#define cmd_ret_802_11_reassociate 0x8025
-#define cmd_ret_802_11_disassociate 0x8026
-#define cmd_ret_802_11_set_wep 0x8013
-#define cmd_ret_802_11_stat 0x8014
-#define cmd_ret_802_3_stat 0x8015
-#define cmd_ret_802_11_snmp_mib 0x8016
-#define cmd_ret_mac_reg_map 0x8017
-#define cmd_ret_bbp_reg_map 0x8018
-#define cmd_ret_rf_reg_map 0x8023
-#define cmd_ret_mac_reg_access 0x8019
-#define cmd_ret_bbp_reg_access 0x801a
-#define cmd_ret_rf_reg_access 0x801b
-#define cmd_ret_802_11_radio_control 0x801c
-#define cmd_ret_802_11_rf_channel 0x801d
-#define cmd_ret_802_11_rssi 0x801f
-#define cmd_ret_802_11_rf_tx_power 0x801e
-#define cmd_ret_802_11_rf_antenna 0x8020
-#define cmd_ret_802_11_ps_mode 0x8021
-#define cmd_ret_802_11_data_rate 0x8022
-
-#define cmd_ret_802_11_ad_hoc_start 0x802B
-#define cmd_ret_802_11_ad_hoc_join 0x802C
-
-#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e
-#define cmd_ret_802_11_enable_rsn 0x802f
-#define cmd_ret_802_11_pairwise_tsc 0x8036
-#define cmd_ret_802_11_group_tsc 0x8037
-#define cmd_ret_802_11_key_material 0x805e
-
-#define cmd_enable_rsn 0x0001
-#define cmd_disable_rsn 0x0000
-
-#define cmd_act_set 0x0001
-#define cmd_act_get 0x0000
-
-#define cmd_act_get_AES (cmd_act_get + 2)
-#define cmd_act_set_AES (cmd_act_set + 2)
-#define cmd_act_remove_aes (cmd_act_set + 3)
-
-#define cmd_ret_802_11_set_afc 0x803c
-#define cmd_ret_802_11_get_afc 0x803d
-
-#define cmd_ret_802_11_ad_hoc_stop 0x8040
-
-#define cmd_ret_802_11_beacon_stop 0x8049
-
-#define cmd_ret_802_11_mac_address 0x804D
-#define cmd_ret_802_11_eeprom_access 0x8059
-
-#define cmd_ret_802_11_band_config 0x8058
-
-#define cmd_ret_802_11_sleep_params 0x8066
-
-#define cmd_ret_802_11_inactivity_timeout 0x8067
-
-#define cmd_ret_802_11d_domain_info (0x8000 | \
- cmd_802_11d_domain_info)
-
-#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000)
-#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000)
-
-#define cmd_ret_802_11_led_gpio_ctrl 0x804e
-
-#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
-
-#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000)
-
-#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000)
-
-#define cmd_ret_get_tsf 0x8080
-
-/* Define action or option for cmd_802_11_set_wep */
-#define cmd_act_add 0x0002
-#define cmd_act_remove 0x0004
-#define cmd_act_use_default 0x0008
-
-#define cmd_type_wep_40_bit 0x0001
-#define cmd_type_wep_104_bit 0x0002
-
-#define cmd_NUM_OF_WEP_KEYS 4
-
-#define cmd_WEP_KEY_INDEX_MASK 0x3fff
-
-/* Define action or option for cmd_802_11_reset */
-#define cmd_act_halt 0x0003
+/* Define action or option for CMD_802_11_RESET */
+#define CMD_ACT_HALT 0x0003
-/* Define action or option for cmd_802_11_scan */
-#define cmd_bss_type_bss 0x0001
-#define cmd_bss_type_ibss 0x0002
-#define cmd_bss_type_any 0x0003
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_BSS_TYPE_BSS 0x0001
+#define CMD_BSS_TYPE_IBSS 0x0002
+#define CMD_BSS_TYPE_ANY 0x0003
-/* Define action or option for cmd_802_11_scan */
-#define cmd_scan_type_active 0x0000
-#define cmd_scan_type_passive 0x0001
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_SCAN_TYPE_ACTIVE 0x0000
+#define CMD_SCAN_TYPE_PASSIVE 0x0001
-#define cmd_scan_radio_type_bg 0
+#define CMD_SCAN_RADIO_TYPE_BG 0
-#define cmd_scan_probe_delay_time 0
+#define CMD_SCAN_PROBE_DELAY_TIME 0
-/* Define action or option for cmd_mac_control */
-#define cmd_act_mac_rx_on 0x0001
-#define cmd_act_mac_tx_on 0x0002
-#define cmd_act_mac_loopback_on 0x0004
-#define cmd_act_mac_wep_enable 0x0008
-#define cmd_act_mac_int_enable 0x0010
-#define cmd_act_mac_multicast_enable 0x0020
-#define cmd_act_mac_broadcast_enable 0x0040
-#define cmd_act_mac_promiscuous_enable 0x0080
-#define cmd_act_mac_all_multicast_enable 0x0100
-#define cmd_act_mac_strict_protection_enable 0x0400
+/* Define action or option for CMD_MAC_CONTROL */
+#define CMD_ACT_MAC_RX_ON 0x0001
+#define CMD_ACT_MAC_TX_ON 0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
+#define CMD_ACT_MAC_WEP_ENABLE 0x0008
+#define CMD_ACT_MAC_INT_ENABLE 0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
-/* Define action or option for cmd_802_11_radio_control */
-#define cmd_type_auto_preamble 0x0001
-#define cmd_type_short_preamble 0x0002
-#define cmd_type_long_preamble 0x0003
+/* Define action or option for CMD_802_11_RADIO_CONTROL */
+#define CMD_TYPE_AUTO_PREAMBLE 0x0001
+#define CMD_TYPE_SHORT_PREAMBLE 0x0002
+#define CMD_TYPE_LONG_PREAMBLE 0x0003
#define TURN_ON_RF 0x01
#define RADIO_ON 0x01
@@ -248,70 +187,80 @@
#define SET_LONG_PREAMBLE 0x01
/* Define action or option for CMD_802_11_RF_CHANNEL */
-#define cmd_opt_802_11_rf_channel_get 0x00
-#define cmd_opt_802_11_rf_channel_set 0x01
-
-/* Define action or option for cmd_802_11_rf_tx_power */
-#define cmd_act_tx_power_opt_get 0x0000
-#define cmd_act_tx_power_opt_set_high 0x8007
-#define cmd_act_tx_power_opt_set_mid 0x8004
-#define cmd_act_tx_power_opt_set_low 0x8000
-
-#define cmd_act_tx_power_index_high 0x0007
-#define cmd_act_tx_power_index_mid 0x0004
-#define cmd_act_tx_power_index_low 0x0000
-
-/* Define action or option for cmd_802_11_data_rate */
-#define cmd_act_set_tx_auto 0x0000
-#define cmd_act_set_tx_fix_rate 0x0001
-#define cmd_act_get_tx_rate 0x0002
-
-#define cmd_act_set_rx 0x0001
-#define cmd_act_set_tx 0x0002
-#define cmd_act_set_both 0x0003
-#define cmd_act_get_rx 0x0004
-#define cmd_act_get_tx 0x0008
-#define cmd_act_get_both 0x000c
-
-/* Define action or option for cmd_802_11_ps_mode */
-#define cmd_type_cam 0x0000
-#define cmd_type_max_psp 0x0001
-#define cmd_type_fast_psp 0x0002
-
-/* Define action or option for cmd_bt_access */
+#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
+
+/* Define action or option for CMD_802_11_RF_TX_POWER */
+#define CMD_ACT_TX_POWER_OPT_GET 0x0000
+#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007
+#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004
+#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000
+
+#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007
+#define CMD_ACT_TX_POWER_INDEX_MID 0x0004
+#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000
+
+/* Define action or option for CMD_802_11_DATA_RATE */
+#define CMD_ACT_SET_TX_AUTO 0x0000
+#define CMD_ACT_SET_TX_FIX_RATE 0x0001
+#define CMD_ACT_GET_TX_RATE 0x0002
+
+#define CMD_ACT_SET_RX 0x0001
+#define CMD_ACT_SET_TX 0x0002
+#define CMD_ACT_SET_BOTH 0x0003
+#define CMD_ACT_GET_RX 0x0004
+#define CMD_ACT_GET_TX 0x0008
+#define CMD_ACT_GET_BOTH 0x000c
+
+/* Define action or option for CMD_802_11_PS_MODE */
+#define CMD_TYPE_CAM 0x0000
+#define CMD_TYPE_MAX_PSP 0x0001
+#define CMD_TYPE_FAST_PSP 0x0002
+
+/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
/* The bt commands start at 5 instead of 1 because the old dft commands
* are mapped to 1-4. These old commands are no longer maintained and
* should not be called.
*/
- cmd_act_bt_access_add = 5,
- cmd_act_bt_access_del,
- cmd_act_bt_access_list,
- cmd_act_bt_access_reset,
- cmd_act_bt_access_set_invert,
- cmd_act_bt_access_get_invert
+ CMD_ACT_BT_ACCESS_ADD = 5,
+ CMD_ACT_BT_ACCESS_DEL,
+ CMD_ACT_BT_ACCESS_LIST,
+ CMD_ACT_BT_ACCESS_RESET,
+ CMD_ACT_BT_ACCESS_SET_INVERT,
+ CMD_ACT_BT_ACCESS_GET_INVERT
};
-/* Define action or option for cmd_fwt_access */
+/* Define action or option for CMD_FWT_ACCESS */
enum cmd_fwt_access_opts {
- cmd_act_fwt_access_add = 1,
- cmd_act_fwt_access_del,
- cmd_act_fwt_access_lookup,
- cmd_act_fwt_access_list,
- cmd_act_fwt_access_list_route,
- cmd_act_fwt_access_list_neighbor,
- cmd_act_fwt_access_reset,
- cmd_act_fwt_access_cleanup,
- cmd_act_fwt_access_time,
+ CMD_ACT_FWT_ACCESS_ADD = 1,
+ CMD_ACT_FWT_ACCESS_DEL,
+ CMD_ACT_FWT_ACCESS_LOOKUP,
+ CMD_ACT_FWT_ACCESS_LIST,
+ CMD_ACT_FWT_ACCESS_LIST_route,
+ CMD_ACT_FWT_ACCESS_LIST_neighbor,
+ CMD_ACT_FWT_ACCESS_RESET,
+ CMD_ACT_FWT_ACCESS_CLEANUP,
+ CMD_ACT_FWT_ACCESS_TIME,
};
-/* Define action or option for cmd_mesh_access */
+/* Define action or option for CMD_MESH_ACCESS */
enum cmd_mesh_access_opts {
- cmd_act_mesh_get_ttl = 1,
- cmd_act_mesh_set_ttl,
- cmd_act_mesh_get_stats,
- cmd_act_mesh_get_anycast,
- cmd_act_mesh_set_anycast,
+ CMD_ACT_MESH_GET_TTL = 1,
+ CMD_ACT_MESH_SET_TTL,
+ CMD_ACT_MESH_GET_STATS,
+ CMD_ACT_MESH_GET_ANYCAST,
+ CMD_ACT_MESH_SET_ANYCAST,
+ CMD_ACT_MESH_SET_LINK_COSTS,
+ CMD_ACT_MESH_GET_LINK_COSTS,
+ CMD_ACT_MESH_SET_BCAST_RATE,
+ CMD_ACT_MESH_GET_BCAST_RATE,
+ CMD_ACT_MESH_SET_RREQ_DELAY,
+ CMD_ACT_MESH_GET_RREQ_DELAY,
+ CMD_ACT_MESH_SET_ROUTE_EXP,
+ CMD_ACT_MESH_GET_ROUTE_EXP,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
};
/** Card Event definition */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index 09b898f6719c..e1045dc02cce 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -83,23 +83,12 @@ struct cmd_ctrl_node {
wait_queue_head_t cmdwait_q;
};
-/* WLAN_802_11_KEY
- *
- * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES)
- * is determined from the keylength field.
- */
-struct WLAN_802_11_KEY {
- __le32 len;
- __le32 flags; /* KEY_INFO_* from wlan_defs.h */
- u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
- __le16 type; /* KEY_TYPE_* from wlan_defs.h */
-};
-
-struct IE_WPA {
- u8 elementid;
- u8 len;
- u8 oui[4];
- __le16 version;
+/* Generic structure to hold all key types. */
+struct enc_key {
+ u16 len;
+ u16 flags; /* KEY_INFO_* from wlan_defs.h */
+ u16 type; /* KEY_TYPE_* from wlan_defs.h */
+ u8 key[32];
};
/* wlan_offset_value */
@@ -108,18 +97,6 @@ struct wlan_offset_value {
u32 value;
};
-struct WLAN_802_11_FIXED_IEs {
- __le64 timestamp;
- __le16 beaconinterval;
- u16 capabilities; /* Actually struct ieeetypes_capinfo */
-};
-
-struct WLAN_802_11_VARIABLE_IEs {
- u8 elementid;
- u8 length;
- u8 data[1];
-};
-
/* Define general data structure */
/* cmd_DS_GEN */
struct cmd_ds_gen {
@@ -131,7 +108,7 @@ struct cmd_ds_gen {
#define S_DS_GEN sizeof(struct cmd_ds_gen)
/*
- * Define data structure for cmd_get_hw_spec
+ * Define data structure for CMD_GET_HW_SPEC
* This structure defines the response for the GET_HW_SPEC command
*/
struct cmd_ds_get_hw_spec {
@@ -178,11 +155,11 @@ struct cmd_ds_802_11_subscribe_event {
/*
* This scan handle Country Information IE(802.11d compliant)
- * Define data structure for cmd_802_11_scan
+ * Define data structure for CMD_802_11_SCAN
*/
struct cmd_ds_802_11_scan {
u8 bsstype;
- u8 BSSID[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
u8 tlvbuffer[1];
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
@@ -237,7 +214,7 @@ struct cmd_ds_802_11_deauthenticate {
struct cmd_ds_802_11_associate {
u8 peerstaaddr[6];
- struct ieeetypes_capinfo capinfo;
+ __le16 capability;
__le16 listeninterval;
__le16 bcnperiod;
u8 dtimperiod;
@@ -260,8 +237,8 @@ struct cmd_ds_802_11_associate_rsp {
};
struct cmd_ds_802_11_ad_hoc_result {
- u8 PAD[3];
- u8 BSSID[ETH_ALEN];
+ u8 pad[3];
+ u8 bssid[ETH_ALEN];
};
struct cmd_ds_802_11_set_wep {
@@ -428,6 +405,16 @@ struct cmd_ds_802_11_rf_antenna {
};
+struct cmd_ds_802_11_monitor_mode {
+ u16 action;
+ u16 mode;
+};
+
+struct cmd_ds_set_boot2_ver {
+ u16 action;
+ u16 version;
+};
+
struct cmd_ds_802_11_ps_mode {
__le16 action;
__le16 nullpktinterval;
@@ -451,8 +438,8 @@ struct PS_CMD_ConfirmSleep {
struct cmd_ds_802_11_data_rate {
__le16 action;
- __le16 reserverd;
- u8 datarate[G_SUPPORTED_RATES];
+ __le16 reserved;
+ u8 rates[MAX_RATES];
};
struct cmd_ds_802_11_rate_adapt_rateset {
@@ -462,30 +449,30 @@ struct cmd_ds_802_11_rate_adapt_rateset {
};
struct cmd_ds_802_11_ad_hoc_start {
- u8 SSID[IW_ESSID_MAX_SIZE];
+ u8 ssid[IW_ESSID_MAX_SIZE];
u8 bsstype;
__le16 beaconperiod;
u8 dtimperiod;
union IEEEtypes_ssparamset ssparamset;
union ieeetypes_phyparamset phyparamset;
__le16 probedelay;
- struct ieeetypes_capinfo cap;
- u8 datarate[G_SUPPORTED_RATES];
+ __le16 capability;
+ u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
} __attribute__ ((packed));
struct adhoc_bssdesc {
- u8 BSSID[6];
- u8 SSID[32];
- u8 bsstype;
+ u8 bssid[6];
+ u8 ssid[32];
+ u8 type;
__le16 beaconperiod;
u8 dtimperiod;
__le64 timestamp;
__le64 localtime;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
- struct ieeetypes_capinfo cap;
- u8 datarates[G_SUPPORTED_RATES];
+ __le16 capability;
+ u8 rates[MAX_RATES];
/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
* Adhoc join command and will cause a binary layout mismatch with
@@ -494,7 +481,7 @@ struct adhoc_bssdesc {
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_join {
- struct adhoc_bssdesc bssdescriptor;
+ struct adhoc_bssdesc bss;
__le16 failtimeout;
__le16 probedelay;
@@ -646,6 +633,7 @@ struct cmd_ds_command {
struct cmd_ds_802_11_snmp_mib smib;
struct cmd_ds_802_11_rf_tx_power txp;
struct cmd_ds_802_11_rf_antenna rant;
+ struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_data_rate drate;
struct cmd_ds_802_11_rate_adapt_rateset rateset;
struct cmd_ds_mac_multicast_adr madr;
@@ -677,6 +665,7 @@ struct cmd_ds_command {
struct cmd_ds_bt_access bt;
struct cmd_ds_fwt_access fwt;
struct cmd_ds_mesh_access mesh;
+ struct cmd_ds_set_boot2_ver boot2_ver;
struct cmd_ds_get_tsf gettsf;
struct cmd_ds_802_11_subscribe_event subscribe_event;
} params;
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
deleted file mode 100644
index 8bca306ffad9..000000000000
--- a/drivers/net/wireless/libertas/if_bootcmd.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * This file contains functions used in USB Boot command
- * and Boot2/FW update
- */
-
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-#include <linux/usb.h>
-
-#define DRV_NAME "usb8xxx"
-
-#include "defs.h"
-#include "dev.h"
-#include "if_usb.h"
-
-/**
- * @brief This function issues Boot command to the Boot2 code
- * @param ivalue 1:Boot from FW by USB-Download
- * 2:Boot from FW in EEPROM
- * @return 0
- */
-int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
-{
- struct usb_card_rec *cardp = priv->card;
- struct bootcmdstr sbootcmd;
- int i;
-
- /* Prepare command */
- sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
- sbootcmd.u8cmd_tag = ivalue;
- for (i=0; i<11; i++)
- sbootcmd.au8dumy[i]=0x00;
- memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
-
- /* Issue command */
- usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
-
- return 0;
-}
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
new file mode 100644
index 000000000000..0360cad363a8
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -0,0 +1,969 @@
+/*
+
+ Driver for the Marvell 8385 based compact flash WLAN cards.
+
+ (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/io.h>
+
+#define DRV_NAME "libertas_cs"
+
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+
+
+/********************************************************************/
+/* Module stuff */
+/********************************************************************/
+
+MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
+MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
+MODULE_LICENSE("GPL");
+
+
+
+/********************************************************************/
+/* Data structures */
+/********************************************************************/
+
+struct if_cs_card {
+ struct pcmcia_device *p_dev;
+ wlan_private *priv;
+ void __iomem *iobase;
+};
+
+
+
+/********************************************************************/
+/* Hardware access */
+/********************************************************************/
+
+/* This define enables wrapper functions which allow you
+ to dump all register accesses. You normally won't this,
+ except for development */
+/* #define DEBUG_IO */
+
+#ifdef DEBUG_IO
+static int debug_output = 0;
+#else
+/* This way the compiler optimizes the printk's away */
+#define debug_output 0
+#endif
+
+static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
+{
+ unsigned int val = ioread8(card->iobase + reg);
+ if (debug_output)
+ printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
+ return val;
+}
+static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
+{
+ unsigned int val = ioread16(card->iobase + reg);
+ if (debug_output)
+ printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
+ return val;
+}
+static inline void if_cs_read16_rep(
+ struct if_cs_card *card,
+ uint reg,
+ void *buf,
+ unsigned long count)
+{
+ if (debug_output)
+ printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
+ reg, count);
+ ioread16_rep(card->iobase + reg, buf, count);
+}
+
+static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
+{
+ if (debug_output)
+ printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
+ iowrite8(val, card->iobase + reg);
+}
+
+static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
+{
+ if (debug_output)
+ printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
+ iowrite16(val, card->iobase + reg);
+}
+
+static inline void if_cs_write16_rep(
+ struct if_cs_card *card,
+ uint reg,
+ void *buf,
+ unsigned long count)
+{
+ if (debug_output)
+ printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
+ reg, count);
+ iowrite16_rep(card->iobase + reg, buf, count);
+}
+
+
+/*
+ * I know that polling/delaying is frowned upon. However, this procedure
+ * with polling is needed while downloading the firmware. At this stage,
+ * the hardware does unfortunately not create any interrupts.
+ *
+ * Fortunately, this function is never used once the firmware is in
+ * the card. :-)
+ *
+ * As a reference, see the "Firmware Specification v5.1", page 18
+ * and 19. I did not follow their suggested timing to the word,
+ * but this works nice & fast anyway.
+ */
+static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
+{
+ int i;
+
+ for (i = 0; i < 500; i++) {
+ u8 val = if_cs_read8(card, addr);
+ if (val == reg)
+ return i;
+ udelay(100);
+ }
+ return -ETIME;
+}
+
+
+
+/* Host control registers and their bit definitions */
+
+#define IF_CS_H_STATUS 0x00000000
+#define IF_CS_H_STATUS_TX_OVER 0x0001
+#define IF_CS_H_STATUS_RX_OVER 0x0002
+#define IF_CS_H_STATUS_DNLD_OVER 0x0004
+
+#define IF_CS_H_INT_CAUSE 0x00000002
+#define IF_CS_H_IC_TX_OVER 0x0001
+#define IF_CS_H_IC_RX_OVER 0x0002
+#define IF_CS_H_IC_DNLD_OVER 0x0004
+#define IF_CS_H_IC_HOST_EVENT 0x0008
+#define IF_CS_H_IC_MASK 0x001f
+
+#define IF_CS_H_INT_MASK 0x00000004
+#define IF_CS_H_IM_MASK 0x001f
+
+#define IF_CS_H_WRITE_LEN 0x00000014
+
+#define IF_CS_H_WRITE 0x00000016
+
+#define IF_CS_H_CMD_LEN 0x00000018
+
+#define IF_CS_H_CMD 0x0000001A
+
+#define IF_CS_C_READ_LEN 0x00000024
+
+#define IF_CS_H_READ 0x00000010
+
+/* Card control registers and their bit definitions */
+
+#define IF_CS_C_STATUS 0x00000020
+#define IF_CS_C_S_TX_DNLD_RDY 0x0001
+#define IF_CS_C_S_RX_UPLD_RDY 0x0002
+#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
+#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
+#define IF_CS_C_S_CARDEVENT 0x0010
+#define IF_CS_C_S_MASK 0x001f
+#define IF_CS_C_S_STATUS_MASK 0x7f00
+/* The following definitions should be the same as the MRVDRV_ ones */
+
+#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
+#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
+#endif
+#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
+#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
+#endif
+#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
+#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
+#endif
+
+#define IF_CS_C_INT_CAUSE 0x00000022
+#define IF_CS_C_IC_MASK 0x001f
+
+#define IF_CS_C_SQ_READ_LOW 0x00000028
+#define IF_CS_C_SQ_HELPER_OK 0x10
+
+#define IF_CS_C_CMD_LEN 0x00000030
+
+#define IF_CS_C_CMD 0x00000012
+
+#define IF_CS_SCRATCH 0x0000003F
+
+
+
+/********************************************************************/
+/* Interrupts */
+/********************************************************************/
+
+static inline void if_cs_enable_ints(struct if_cs_card *card)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ if_cs_write16(card, IF_CS_H_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
+}
+
+static irqreturn_t if_cs_interrupt(int irq, void *data)
+{
+ struct if_cs_card *card = (struct if_cs_card *)data;
+ u16 int_cause;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
+ if(int_cause == 0x0) {
+ /* Not for us */
+ return IRQ_NONE;
+
+ } else if(int_cause == 0xffff) {
+ /* Read in junk, the card has probably been removed */
+ card->priv->adapter->surpriseremoved = 1;
+
+ } else {
+ if(int_cause & IF_CS_H_IC_TX_OVER) {
+ card->priv->dnld_sent = DNLD_RES_RECEIVED;
+ if (!card->priv->adapter->cur_cmd)
+ wake_up_interruptible(&card->priv->waitq);
+
+ if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED)
+ netif_wake_queue(card->priv->dev);
+ }
+
+ /* clear interrupt */
+ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
+ }
+
+ libertas_interrupt(card->priv->dev);
+
+ return IRQ_HANDLED;
+}
+
+
+
+
+/********************************************************************/
+/* I/O */
+/********************************************************************/
+
+/*
+ * Called from if_cs_host_to_card to send a command to the hardware
+ */
+static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb)
+{
+ struct if_cs_card *card = (struct if_cs_card *)priv->card;
+ int ret = -1;
+ int loops = 0;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ /* Is hardware ready? */
+ while (1) {
+ u16 val = if_cs_read16(card, IF_CS_C_STATUS);
+ if (val & IF_CS_C_S_CMD_DNLD_RDY)
+ break;
+ if (++loops > 100) {
+ lbs_pr_err("card not ready for commands\n");
+ goto done;
+ }
+ mdelay(1);
+ }
+
+ if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
+
+ if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
+ /* Are we supposed to transfer an odd amount of bytes? */
+ if (nb & 1)
+ if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
+
+ /* "Assert the download over interrupt command in the Host
+ * status register" */
+ if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+
+ /* "Assert the download over interrupt command in the Card
+ * interrupt case register" */
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+ ret = 0;
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+/*
+ * Called from if_cs_host_to_card to send a data to the hardware
+ */
+static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb)
+{
+ struct if_cs_card *card = (struct if_cs_card *)priv->card;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
+
+ /* write even number of bytes, then odd byte if necessary */
+ if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
+ if (nb & 1)
+ if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
+
+ if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
+
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+/*
+ * Get the command result out of the card.
+ */
+static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len)
+{
+ int ret = -1;
+ u16 val;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ /* is hardware ready? */
+ val = if_cs_read16(priv->card, IF_CS_C_STATUS);
+ if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
+ lbs_pr_err("card not ready for CMD\n");
+ goto out;
+ }
+
+ *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
+ if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) {
+ lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
+ goto out;
+ }
+
+ /* read even number of bytes, then odd byte if necessary */
+ if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
+ if (*len & 1)
+ data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
+
+ ret = 0;
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
+ return ret;
+}
+
+
+static struct sk_buff *if_cs_receive_data(wlan_private *priv)
+{
+ struct sk_buff *skb = NULL;
+ u16 len;
+ u8 *data;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
+ if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+ lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
+ priv->stats.rx_dropped++;
+ printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
+ goto dat_err;
+ }
+
+ //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
+ skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
+ if (!skb)
+ goto out;
+ skb_put(skb, len);
+ skb_reserve(skb, 2);/* 16 byte align */
+ data = skb->data;
+
+ /* read even number of bytes, then odd byte if necessary */
+ if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
+ if (len & 1)
+ data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
+
+dat_err:
+ if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
+ if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
+ return skb;
+}
+
+
+
+/********************************************************************/
+/* Firmware */
+/********************************************************************/
+
+/*
+ * Tries to program the helper firmware.
+ *
+ * Return 0 on success
+ */
+static int if_cs_prog_helper(struct if_cs_card *card)
+{
+ int ret = 0;
+ int sent = 0;
+ u8 scratch;
+ const struct firmware *fw;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ scratch = if_cs_read8(card, IF_CS_SCRATCH);
+
+ /* "If the value is 0x5a, the firmware is already
+ * downloaded successfully"
+ */
+ if (scratch == 0x5a)
+ goto done;
+
+ /* "If the value is != 00, it is invalid value of register */
+ if (scratch != 0x00) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ /* TODO: make firmware file configurable */
+ ret = request_firmware(&fw, "libertas_cs_helper.fw",
+ &handle_to_dev(card->p_dev));
+ if (ret) {
+ lbs_pr_err("can't load helper firmware\n");
+ ret = -ENODEV;
+ goto done;
+ }
+ lbs_deb_cs("helper size %td\n", fw->size);
+
+ /* "Set the 5 bytes of the helper image to 0" */
+ /* Not needed, this contains an ARM branch instruction */
+
+ for (;;) {
+ /* "the number of bytes to send is 256" */
+ int count = 256;
+ int remain = fw->size - sent;
+
+ if (remain < count)
+ count = remain;
+ /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
+ __LINE__, sent, fw->size); */
+
+ /* "write the number of bytes to be sent to the I/O Command
+ * write length register" */
+ if_cs_write16(card, IF_CS_H_CMD_LEN, count);
+
+ /* "write this to I/O Command port register as 16 bit writes */
+ if (count)
+ if_cs_write16_rep(card, IF_CS_H_CMD,
+ &fw->data[sent],
+ count >> 1);
+
+ /* "Assert the download over interrupt command in the Host
+ * status register" */
+ if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+
+ /* "Assert the download over interrupt command in the Card
+ * interrupt case register" */
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+
+ /* "The host polls the Card Status register ... for 50 ms before
+ declaring a failure */
+ ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
+ IF_CS_C_S_CMD_DNLD_RDY);
+ if (ret < 0) {
+ lbs_pr_err("can't download helper at 0x%x, ret %d\n",
+ sent, ret);
+ goto done;
+ }
+
+ if (count == 0)
+ break;
+
+ sent += count;
+ }
+
+ release_firmware(fw);
+ ret = 0;
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+static int if_cs_prog_real(struct if_cs_card *card)
+{
+ const struct firmware *fw;
+ int ret = 0;
+ int retry = 0;
+ int len = 0;
+ int sent;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ /* TODO: make firmware file configurable */
+ ret = request_firmware(&fw, "libertas_cs.fw",
+ &handle_to_dev(card->p_dev));
+ if (ret) {
+ lbs_pr_err("can't load firmware\n");
+ ret = -ENODEV;
+ goto done;
+ }
+ lbs_deb_cs("fw size %td\n", fw->size);
+
+ ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
+ if (ret < 0) {
+ int i;
+ lbs_pr_err("helper firmware doesn't answer\n");
+ for (i = 0; i < 0x50; i += 2)
+ printk(KERN_INFO "## HS %02x: %04x\n",
+ i, if_cs_read16(card, i));
+ goto err_release;
+ }
+
+ for (sent = 0; sent < fw->size; sent += len) {
+ len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
+ /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
+ __LINE__, sent, fw->size); */
+ if (len & 1) {
+ retry++;
+ lbs_pr_info("odd, need to retry this firmware block\n");
+ } else {
+ retry = 0;
+ }
+
+ if (retry > 20) {
+ lbs_pr_err("could not download firmware\n");
+ ret = -ENODEV;
+ goto err_release;
+ }
+ if (retry) {
+ sent -= len;
+ }
+
+
+ if_cs_write16(card, IF_CS_H_CMD_LEN, len);
+
+ if_cs_write16_rep(card, IF_CS_H_CMD,
+ &fw->data[sent],
+ (len+1) >> 1);
+ if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+
+ ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
+ IF_CS_C_S_CMD_DNLD_RDY);
+ if (ret < 0) {
+ lbs_pr_err("can't download firmware at 0x%x\n", sent);
+ goto err_release;
+ }
+ }
+
+ ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
+ if (ret < 0) {
+ lbs_pr_err("firmware download failed\n");
+ goto err_release;
+ }
+
+ ret = 0;
+ goto done;
+
+
+err_release:
+ release_firmware(fw);
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+
+/********************************************************************/
+/* Callback functions for libertas.ko */
+/********************************************************************/
+
+/* Send commands or data packets to the card */
+static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
+{
+ int ret = -1;
+
+ lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
+
+ switch (type) {
+ case MVMS_DAT:
+ priv->dnld_sent = DNLD_DATA_SENT;
+ if_cs_send_data(priv, buf, nb);
+ ret = 0;
+ break;
+ case MVMS_CMD:
+ priv->dnld_sent = DNLD_CMD_SENT;
+ ret = if_cs_send_cmd(priv, buf, nb);
+ break;
+ default:
+ lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+static int if_cs_get_int_status(wlan_private *priv, u8 *ireg)
+{
+ struct if_cs_card *card = (struct if_cs_card *)priv->card;
+ //wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 int_cause;
+ u8 *cmdbuf;
+ *ireg = 0;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ if (priv->adapter->surpriseremoved)
+ goto out;
+
+ int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
+ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
+
+ *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
+
+ if (!*ireg)
+ goto sbi_get_int_status_exit;
+
+sbi_get_int_status_exit:
+
+ /* is there a data packet for us? */
+ if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
+ struct sk_buff *skb = if_cs_receive_data(priv);
+ libertas_process_rxed_packet(priv, skb);
+ *ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
+ }
+
+ if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+ }
+
+ /* Card has a command result for us */
+ if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
+ spin_lock(&priv->adapter->driver_lock);
+ if (!priv->adapter->cur_cmd) {
+ cmdbuf = priv->upld_buf;
+ priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;
+ } else {
+ cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+ }
+
+ ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);
+ spin_unlock(&priv->adapter->driver_lock);
+ if (ret < 0)
+ lbs_pr_err("could not receive cmd from card\n");
+ }
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy);
+ return ret;
+}
+
+
+static int if_cs_read_event_cause(wlan_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+
+ priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
+ if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
+
+ return 0;
+}
+
+
+
+/********************************************************************/
+/* Card Services */
+/********************************************************************/
+
+/*
+ * After a card is removed, if_cs_release() will unregister the
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void if_cs_release(struct pcmcia_device *p_dev)
+{
+ struct if_cs_card *card = p_dev->priv;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ pcmcia_disable_device(p_dev);
+ free_irq(p_dev->irq.AssignedIRQ, card);
+ if (card->iobase)
+ ioport_unmap(card->iobase);
+
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+/*
+ * This creates an "instance" of the driver, allocating local data
+ * structures for one device. The device is registered with Card
+ * Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a card
+ * insertion event.
+ */
+static int if_cs_probe(struct pcmcia_device *p_dev)
+{
+ int ret = -ENOMEM;
+ wlan_private *priv;
+ struct if_cs_card *card;
+ /* CIS parsing */
+ tuple_t tuple;
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+ cistpl_io_t *io = &cfg->io;
+ u_char buf[64];
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
+ if (!card) {
+ lbs_pr_err("error in kzalloc\n");
+ goto out;
+ }
+ card->p_dev = p_dev;
+ p_dev->priv = card;
+
+ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ p_dev->irq.Handler = NULL;
+ p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+ p_dev->conf.Attributes = 0;
+ p_dev->conf.IntType = INT_MEMORY_AND_IO;
+
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
+ (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
+ (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
+ {
+ lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
+ goto out1;
+ }
+
+ p_dev->conf.ConfigIndex = cfg->index;
+
+ /* Do we need to allocate an interrupt? */
+ if (cfg->irq.IRQInfo1) {
+ p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+ }
+
+ /* IO window settings */
+ if (cfg->io.nwin != 1) {
+ lbs_pr_err("wrong CIS (check number of IO windows)\n");
+ ret = -ENODEV;
+ goto out1;
+ }
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->io.BasePort1 = io->win[0].base;
+ p_dev->io.NumPorts1 = io->win[0].len;
+
+ /* This reserves IO space but doesn't actually enable it */
+ ret = pcmcia_request_io(p_dev, &p_dev->io);
+ if (ret) {
+ lbs_pr_err("error in pcmcia_request_io\n");
+ goto out1;
+ }
+
+ /*
+ * Allocate an interrupt line. Note that this does not assign
+ * a handler to the interrupt, unless the 'Handler' member of
+ * the irq structure is initialized.
+ */
+ if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {
+ ret = pcmcia_request_irq(p_dev, &p_dev->irq);
+ if (ret) {
+ lbs_pr_err("error in pcmcia_request_irq\n");
+ goto out1;
+ }
+ }
+
+ /* Initialize io access */
+ card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
+ if (!card->iobase) {
+ lbs_pr_err("error in ioport_map\n");
+ ret = -EIO;
+ goto out1;
+ }
+
+ /*
+ * This actually configures the PCMCIA socket -- setting up
+ * the I/O windows and the interrupt mapping, and putting the
+ * card and host interface into "Memory and IO" mode.
+ */
+ ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+ if (ret) {
+ lbs_pr_err("error in pcmcia_request_configuration\n");
+ goto out2;
+ }
+
+ /* Finally, report what we've done */
+ lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
+ p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
+ p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
+
+
+ /* Load the firmware early, before calling into libertas.ko */
+ ret = if_cs_prog_helper(card);
+ if (ret == 0)
+ ret = if_cs_prog_real(card);
+ if (ret)
+ goto out2;
+
+ /* Make this card known to the libertas driver */
+ priv = libertas_add_card(card, &p_dev->dev);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ /* Store pointers to our call-back functions */
+ card->priv = priv;
+ priv->card = card;
+ priv->hw_host_to_card = if_cs_host_to_card;
+ priv->hw_get_int_status = if_cs_get_int_status;
+ priv->hw_read_event_cause = if_cs_read_event_cause;
+
+ priv->adapter->fw_ready = 1;
+
+ /* Now actually get the IRQ */
+ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
+ IRQF_SHARED, DRV_NAME, card);
+ if (ret) {
+ lbs_pr_err("error in request_irq\n");
+ goto out3;
+ }
+
+ if_cs_enable_ints(card);
+
+ /* And finally bring the card up */
+ if (libertas_start_card(priv) != 0) {
+ lbs_pr_err("could not activate card\n");
+ goto out3;
+ }
+
+ ret = 0;
+ goto out;
+
+out3:
+ libertas_remove_card(priv);
+out2:
+ ioport_unmap(card->iobase);
+out1:
+ pcmcia_disable_device(p_dev);
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+/*
+ * This deletes a driver "instance". The device is de-registered with
+ * Card Services. If it has been released, all local data structures
+ * are freed. Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void if_cs_detach(struct pcmcia_device *p_dev)
+{
+ struct if_cs_card *card = p_dev->priv;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ libertas_stop_card(card->priv);
+ libertas_remove_card(card->priv);
+ if_cs_disable_ints(card);
+ if_cs_release(p_dev);
+ kfree(card);
+
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+
+/********************************************************************/
+/* Module initialization */
+/********************************************************************/
+
+static struct pcmcia_device_id if_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
+
+
+static struct pcmcia_driver libertas_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRV_NAME,
+ },
+ .probe = if_cs_probe,
+ .remove = if_cs_detach,
+ .id_table = if_cs_ids,
+};
+
+
+static int __init if_cs_init(void)
+{
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CS);
+ ret = pcmcia_register_driver(&libertas_driver);
+ lbs_deb_leave(LBS_DEB_CS);
+ return ret;
+}
+
+
+static void __exit if_cs_exit(void)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ pcmcia_unregister_driver(&libertas_driver);
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+module_init(if_cs_init);
+module_exit(if_cs_exit);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 998317571ec2..cb59f46ed126 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -21,7 +21,7 @@
static const char usbdriver_name[] = "usb8xxx";
static u8 *default_fw_name = "usb8388.bin";
-char *libertas_fw_name = NULL;
+static char *libertas_fw_name = NULL;
module_param_named(fw_name, libertas_fw_name, charp, 0644);
/*
@@ -44,13 +44,14 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
static void if_usb_receive(struct urb *urb);
static void if_usb_receive_fwload(struct urb *urb);
-static int if_usb_reset_device(wlan_private *priv);
-static int if_usb_register_dev(wlan_private * priv);
-static int if_usb_unregister_dev(wlan_private *);
-static int if_usb_prog_firmware(wlan_private *);
+static int if_usb_prog_firmware(struct usb_card_rec *cardp);
static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
static int if_usb_get_int_status(wlan_private * priv, u8 *);
static int if_usb_read_event_cause(wlan_private *);
+static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb);
+static void if_usb_free(struct usb_card_rec *cardp);
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp);
+static int if_usb_reset_device(struct usb_card_rec *cardp);
/**
* @brief call back function to handle the status of the URB
@@ -59,29 +60,40 @@ static int if_usb_read_event_cause(wlan_private *);
*/
static void if_usb_write_bulk_callback(struct urb *urb)
{
- wlan_private *priv = (wlan_private *) (urb->context);
- wlan_adapter *adapter = priv->adapter;
- struct net_device *dev = priv->dev;
+ struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context;
/* handle the transmission complete validations */
- if (urb->status != 0) {
- /* print the failure status number for debug */
- lbs_pr_info("URB in failure status: %d\n", urb->status);
- } else {
+ if (urb->status == 0) {
+ wlan_private *priv = cardp->priv;
+
/*
lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
urb->actual_length);
*/
- priv->dnld_sent = DNLD_RES_RECEIVED;
- /* Wake main thread if commands are pending */
- if (!adapter->cur_cmd)
- wake_up_interruptible(&priv->mainthread.waitq);
- if ((adapter->connect_status == libertas_connected)) {
- netif_wake_queue(dev);
- netif_wake_queue(priv->mesh_dev);
+
+ /* Used for both firmware TX and regular TX. priv isn't
+ * valid at firmware load time.
+ */
+ if (priv) {
+ wlan_adapter *adapter = priv->adapter;
+ struct net_device *dev = priv->dev;
+
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+
+ /* Wake main thread if commands are pending */
+ if (!adapter->cur_cmd)
+ wake_up_interruptible(&priv->waitq);
+
+ if ((adapter->connect_status == LIBERTAS_CONNECTED)) {
+ netif_wake_queue(dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
}
+ } else {
+ /* print the failure status number for debug */
+ lbs_pr_info("URB in failure status: %d\n", urb->status);
}
return;
@@ -92,7 +104,7 @@ static void if_usb_write_bulk_callback(struct urb *urb)
* @param cardp pointer usb_card_rec
* @return N/A
*/
-void if_usb_free(struct usb_card_rec *cardp)
+static void if_usb_free(struct usb_card_rec *cardp)
{
lbs_deb_enter(LBS_DEB_USB);
@@ -203,21 +215,35 @@ static int if_usb_probe(struct usb_interface *intf,
}
}
+ /* Upload firmware */
+ cardp->rinfo.cardp = cardp;
+ if (if_usb_prog_firmware(cardp)) {
+ lbs_deb_usbd(&udev->dev, "FW upload failed");
+ goto err_prog_firmware;
+ }
+
if (!(priv = libertas_add_card(cardp, &udev->dev)))
- goto dealloc;
+ goto err_prog_firmware;
+
+ cardp->priv = priv;
if (libertas_add_mesh(priv, &udev->dev))
goto err_add_mesh;
- priv->hw_register_dev = if_usb_register_dev;
- priv->hw_unregister_dev = if_usb_unregister_dev;
- priv->hw_prog_firmware = if_usb_prog_firmware;
+ cardp->eth_dev = priv->dev;
+
priv->hw_host_to_card = if_usb_host_to_card;
priv->hw_get_int_status = if_usb_get_int_status;
priv->hw_read_event_cause = if_usb_read_event_cause;
+ priv->boot2_version = udev->descriptor.bcdDevice;
- if (libertas_activate_card(priv, libertas_fw_name))
- goto err_activate_card;
+ /* Delay 200 ms to waiting for the FW ready */
+ if_usb_submit_rx_urb(cardp);
+ msleep_interruptible(200);
+ priv->adapter->fw_ready = 1;
+
+ if (libertas_start_card(priv))
+ goto err_start_card;
list_add_tail(&cardp->list, &usb_devices);
@@ -226,11 +252,12 @@ static int if_usb_probe(struct usb_interface *intf,
return 0;
-err_activate_card:
+err_start_card:
libertas_remove_mesh(priv);
err_add_mesh:
- free_netdev(priv->dev);
- kfree(priv->adapter);
+ libertas_remove_card(priv);
+err_prog_firmware:
+ if_usb_reset_device(cardp);
dealloc:
if_usb_free(cardp);
@@ -247,21 +274,22 @@ static void if_usb_disconnect(struct usb_interface *intf)
{
struct usb_card_rec *cardp = usb_get_intfdata(intf);
wlan_private *priv = (wlan_private *) cardp->priv;
- wlan_adapter *adapter = NULL;
- adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_MAIN);
- /*
- * Update Surprise removed to TRUE
- */
- adapter->surpriseremoved = 1;
+ /* Update Surprise removed to TRUE */
+ cardp->surprise_removed = 1;
list_del(&cardp->list);
- /* card is removed and we can call wlan_remove_card */
- lbs_deb_usbd(&cardp->udev->dev, "call remove card\n");
- libertas_remove_mesh(priv);
- libertas_remove_card(priv);
+ if (priv) {
+ wlan_adapter *adapter = priv->adapter;
+
+ adapter->surpriseremoved = 1;
+ libertas_stop_card(priv);
+ libertas_remove_mesh(priv);
+ libertas_remove_card(priv);
+ }
/* Unlink and free urb */
if_usb_free(cardp);
@@ -269,7 +297,7 @@ static void if_usb_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
- return;
+ lbs_deb_leave(LBS_DEB_MAIN);
}
/**
@@ -277,12 +305,11 @@ static void if_usb_disconnect(struct usb_interface *intf)
* @param priv pointer to wlan_private
* @return 0
*/
-static int if_prog_firmware(wlan_private * priv)
+static int if_prog_firmware(struct usb_card_rec *cardp)
{
- struct usb_card_rec *cardp = priv->card;
struct FWData *fwdata;
struct fwheader *fwheader;
- u8 *firmware = priv->firmware->data;
+ u8 *firmware = cardp->fw->data;
fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
@@ -330,7 +357,7 @@ static int if_prog_firmware(wlan_private * priv)
cardp->totalbytes);
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
} else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
/*
@@ -340,7 +367,7 @@ static int if_prog_firmware(wlan_private * priv)
"Donwloading FW JUMP BLOCK\n");
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
cardp->fwfinalblk = 1;
}
@@ -355,17 +382,20 @@ static int if_prog_firmware(wlan_private * priv)
return 0;
}
-static int libertas_do_reset(wlan_private *priv)
+static int if_usb_reset_device(struct usb_card_rec *cardp)
{
int ret;
- struct usb_card_rec *cardp = priv->card;
+ wlan_private * priv = cardp->priv;
lbs_deb_enter(LBS_DEB_USB);
+ /* Try a USB port reset first, if that fails send the reset
+ * command to the firmware.
+ */
ret = usb_reset_device(cardp->udev);
- if (!ret) {
+ if (!ret && priv) {
msleep(10);
- if_usb_reset_device(priv);
+ ret = libertas_reset_device(priv);
msleep(10);
}
@@ -381,14 +411,12 @@ static int libertas_do_reset(wlan_private *priv)
* @param nb data length
* @return 0 or -1
*/
-int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
{
- /* pointer to card structure */
- struct usb_card_rec *cardp = priv->card;
int ret = -1;
/* check if device is removed */
- if (priv->adapter->surpriseremoved) {
+ if (cardp->surprise_removed) {
lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
goto tx_ret;
}
@@ -396,7 +424,7 @@ int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
usb_sndbulkpipe(cardp->udev,
cardp->bulk_out_endpointAddr),
- payload, nb, if_usb_write_bulk_callback, priv);
+ payload, nb, if_usb_write_bulk_callback, cardp);
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
@@ -413,11 +441,9 @@ tx_ret:
return ret;
}
-static int __if_usb_submit_rx_urb(wlan_private * priv,
- void (*callbackfn)
- (struct urb *urb))
+static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
+ void (*callbackfn)(struct urb *urb))
{
- struct usb_card_rec *cardp = priv->card;
struct sk_buff *skb;
struct read_cb_info *rinfo = &cardp->rinfo;
int ret = -1;
@@ -453,22 +479,21 @@ rx_ret:
return ret;
}
-static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp)
{
- return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+ return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
}
-static inline int if_usb_submit_rx_urb(wlan_private * priv)
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp)
{
- return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+ return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
}
static void if_usb_receive_fwload(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
- wlan_private *priv = rinfo->priv;
struct sk_buff *skb = rinfo->skb;
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
struct fwsyncheader *syncfwheader;
struct bootcmdrespStr bootcmdresp;
@@ -484,7 +509,7 @@ static void if_usb_receive_fwload(struct urb *urb)
sizeof(bootcmdresp));
if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
kfree_skb(skb);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n");
@@ -508,7 +533,7 @@ static void if_usb_receive_fwload(struct urb *urb)
"Received valid boot command response\n");
}
kfree_skb(skb);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
return;
}
@@ -544,9 +569,9 @@ static void if_usb_receive_fwload(struct urb *urb)
goto exit;
}
- if_prog_firmware(priv);
+ if_prog_firmware(cardp);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
exit:
kfree(syncfwheader);
@@ -596,11 +621,11 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
* data to clear the interrupt */
if (!priv->adapter->cur_cmd) {
cmdbuf = priv->upld_buf;
- priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+ priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
} else
cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
- cardp->usb_int_cause |= his_cmdupldrdy;
+ cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
priv->upld_len);
@@ -625,17 +650,19 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
static void if_usb_receive(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
- wlan_private *priv = rinfo->priv;
struct sk_buff *skb = rinfo->skb;
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
+ wlan_private * priv = cardp->priv;
int recvlength = urb->actual_length;
u8 *recvbuff = NULL;
- u32 recvtype;
+ u32 recvtype = 0;
lbs_deb_enter(LBS_DEB_USB);
if (recvlength) {
+ __le32 tmp;
+
if (urb->status) {
lbs_deb_usbd(&cardp->udev->dev,
"URB status is failed\n");
@@ -644,18 +671,14 @@ static void if_usb_receive(struct urb *urb)
}
recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
- memcpy(&recvtype, recvbuff, sizeof(u32));
- lbs_deb_usbd(&cardp->udev->dev,
- "Recv length = 0x%x\n", recvlength);
- lbs_deb_usbd(&cardp->udev->dev,
- "Receive type = 0x%X\n", recvtype);
- recvtype = le32_to_cpu(recvtype);
+ memcpy(&tmp, recvbuff, sizeof(u32));
+ recvtype = le32_to_cpu(tmp);
lbs_deb_usbd(&cardp->udev->dev,
- "Receive type after = 0x%X\n", recvtype);
+ "Recv length = 0x%x, Recv type = 0x%X\n",
+ recvlength, recvtype);
} else if (urb->status)
goto rx_exit;
-
switch (recvtype) {
case CMD_TYPE_DATA:
process_cmdtypedata(recvlength, skb, cardp, priv);
@@ -677,18 +700,20 @@ static void if_usb_receive(struct urb *urb)
break;
}
cardp->usb_event_cause <<= 3;
- cardp->usb_int_cause |= his_cardevent;
+ cardp->usb_int_cause |= MRVDRV_CARDEVENT;
kfree_skb(skb);
libertas_interrupt(priv->dev);
spin_unlock(&priv->adapter->driver_lock);
goto rx_exit;
default:
+ lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
+ recvtype);
kfree_skb(skb);
break;
}
setup_for_next:
- if_usb_submit_rx_urb(priv);
+ if_usb_submit_rx_urb(cardp);
rx_exit:
lbs_deb_leave(LBS_DEB_USB);
}
@@ -703,21 +728,19 @@ rx_exit:
*/
static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
{
- int ret = -1;
- u32 tmp;
struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
if (type == MVMS_CMD) {
- tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+ __le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST);
priv->dnld_sent = DNLD_CMD_SENT;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
} else {
- tmp = cpu_to_le32(CMD_TYPE_DATA);
+ __le32 tmp = cpu_to_le32(CMD_TYPE_DATA);
priv->dnld_sent = DNLD_DATA_SENT;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
@@ -725,10 +748,8 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n
memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
- ret =
- usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
-
- return ret;
+ return usb_tx_block(cardp, cardp->bulk_out_buffer,
+ nb + MESSAGE_HEADER_LEN);
}
/* called with adapter->driver_lock held */
@@ -747,80 +768,109 @@ static int if_usb_get_int_status(wlan_private * priv, u8 * ireg)
static int if_usb_read_event_cause(wlan_private * priv)
{
struct usb_card_rec *cardp = priv->card;
+
priv->adapter->eventcause = cardp->usb_event_cause;
/* Re-submit rx urb here to avoid event lost issue */
- if_usb_submit_rx_urb(priv);
+ if_usb_submit_rx_urb(cardp);
return 0;
}
-static int if_usb_reset_device(wlan_private *priv)
+/**
+ * @brief This function issues Boot command to the Boot2 code
+ * @param ivalue 1:Boot from FW by USB-Download
+ * 2:Boot from FW in EEPROM
+ * @return 0
+ */
+static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
{
- int ret;
-
- lbs_deb_enter(LBS_DEB_USB);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
- cmd_act_halt, 0, 0, NULL);
- msleep_interruptible(10);
-
- lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
- return ret;
-}
+ struct bootcmdstr sbootcmd;
+ int i;
-static int if_usb_unregister_dev(wlan_private * priv)
-{
- int ret = 0;
+ /* Prepare command */
+ sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+ sbootcmd.u8cmd_tag = ivalue;
+ for (i=0; i<11; i++)
+ sbootcmd.au8dumy[i]=0x00;
+ memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
- /* Need to send a Reset command to device before USB resources freed
- * and wlan_remove_card() called, then device can handle FW download
- * again.
- */
- if (priv)
- if_usb_reset_device(priv);
+ /* Issue command */
+ usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
- return ret;
+ return 0;
}
/**
- * @brief This function register usb device and initialize parameter
- * @param priv pointer to wlan_private
- * @return 0 or -1
+ * @brief This function checks the validity of Boot2/FW image.
+ *
+ * @param data pointer to image
+ * len image length
+ * @return 0 or -1
*/
-static int if_usb_register_dev(wlan_private * priv)
+static int check_fwfile_format(u8 *data, u32 totlen)
{
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ u32 bincmd, exit;
+ u32 blksize, offset, len;
+ int ret;
- lbs_deb_enter(LBS_DEB_USB);
+ ret = 1;
+ exit = len = 0;
- cardp->priv = priv;
- cardp->eth_dev = priv->dev;
- priv->hotplug_device = &(cardp->udev->dev);
+ do {
+ struct fwheader *fwh = (void *)data;
+
+ bincmd = le32_to_cpu(fwh->dnldcmd);
+ blksize = le32_to_cpu(fwh->datalength);
+ switch (bincmd) {
+ case FW_HAS_DATA_TO_RECV:
+ offset = sizeof(struct fwheader) + blksize;
+ data += offset;
+ len += offset;
+ if (len >= totlen)
+ exit = 1;
+ break;
+ case FW_HAS_LAST_BLOCK:
+ exit = 1;
+ ret = 0;
+ break;
+ default:
+ exit = 1;
+ break;
+ }
+ } while (!exit);
- lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n",
- cardp->udev);
+ if (ret)
+ lbs_pr_err("firmware file format check FAIL\n");
+ else
+ lbs_deb_fw("firmware file format check PASS\n");
- lbs_deb_leave(LBS_DEB_USB);
- return 0;
+ return ret;
}
-
-static int if_usb_prog_firmware(wlan_private * priv)
+static int if_usb_prog_firmware(struct usb_card_rec *cardp)
{
- struct usb_card_rec *cardp = priv->card;
int i = 0;
static int reset_count = 10;
int ret = 0;
lbs_deb_enter(LBS_DEB_USB);
- cardp->rinfo.priv = priv;
+ if ((ret = request_firmware(&cardp->fw, libertas_fw_name,
+ &cardp->udev->dev)) < 0) {
+ lbs_pr_err("request_firmware() failed with %#x\n", ret);
+ lbs_pr_err("firmware %s not found\n", libertas_fw_name);
+ goto done;
+ }
+
+ if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
+ goto release_fw;
restart:
- if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+ if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
ret = -1;
- goto done;
+ goto release_fw;
}
cardp->bootcmdresp = 0;
@@ -828,7 +878,7 @@ restart:
int j = 0;
i++;
/* Issue Boot command = 1, Boot from Download-FW */
- if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+ if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
/* wait for command response */
do {
j++;
@@ -838,14 +888,13 @@ restart:
if (cardp->bootcmdresp == 0) {
if (--reset_count >= 0) {
- libertas_do_reset(priv);
+ if_usb_reset_device(cardp);
goto restart;
}
return -1;
}
i = 0;
- priv->adapter->fw_ready = 0;
cardp->totalbytes = 0;
cardp->fwlastblksent = 0;
@@ -855,40 +904,38 @@ restart:
cardp->totalbytes = 0;
cardp->fwfinalblk = 0;
- if_prog_firmware(priv);
+ if_prog_firmware(cardp);
do {
lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
i++;
msleep_interruptible(100);
- if (priv->adapter->surpriseremoved || i >= 20)
+ if (cardp->surprise_removed || i >= 20)
break;
} while (!cardp->fwdnldover);
if (!cardp->fwdnldover) {
lbs_pr_info("failed to load fw, resetting device!\n");
if (--reset_count >= 0) {
- libertas_do_reset(priv);
+ if_usb_reset_device(cardp);
goto restart;
}
lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -1;
- goto done;
+ goto release_fw;
}
- if_usb_submit_rx_urb(priv);
-
- /* Delay 200 ms to waiting for the FW ready */
- msleep_interruptible(200);
-
- priv->adapter->fw_ready = 1;
+release_fw:
+ release_firmware(cardp->fw);
+ cardp->fw = NULL;
done:
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret;
}
+
#ifdef CONFIG_PM
static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
@@ -900,6 +947,19 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
if (priv->adapter->psstate != PS_STATE_FULL_POWER)
return -1;
+ if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
+ /* Mesh autostart must be activated while sleeping
+ * On resume it will go back to the current state
+ */
+ struct cmd_ds_mesh_access mesh_access;
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(1);
+ libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ }
+
netif_device_detach(cardp->eth_dev);
netif_device_detach(priv->mesh_dev);
@@ -927,6 +987,19 @@ static int if_usb_resume(struct usb_interface *intf)
netif_device_attach(cardp->eth_dev);
netif_device_attach(priv->mesh_dev);
+ if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
+ /* Mesh autostart was activated while sleeping
+ * Disable it if appropriate
+ */
+ struct cmd_ds_mesh_access mesh_access;
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(0);
+ libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ }
+
lbs_deb_leave(LBS_DEB_USB);
return 0;
}
@@ -970,8 +1043,10 @@ static void if_usb_exit_module(void)
lbs_deb_enter(LBS_DEB_MAIN);
- list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list)
- if_usb_reset_device((wlan_private *) cardp->priv);
+ list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) {
+ libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET,
+ CMD_ACT_HALT, 0, 0, NULL);
+ }
/* API unregisters the driver from USB subsystem */
usb_deregister(&if_usb_driver);
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index 156bb485e1a6..e07a10ed28b5 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -38,7 +38,7 @@ struct bootcmdrespStr
/* read callback private data */
struct read_cb_info {
- wlan_private *priv;
+ struct usb_card_rec *cardp;
struct sk_buff *skb;
};
@@ -58,6 +58,7 @@ struct usb_card_rec {
int bulk_out_size;
u8 bulk_out_endpointAddr;
+ const struct firmware *fw;
u8 CRC_OK;
u32 fwseqnum;
u32 lastseqnum;
@@ -65,6 +66,7 @@ struct usb_card_rec {
u32 fwlastblksent;
u8 fwdnldover;
u8 fwfinalblk;
+ u8 surprise_removed;
u32 usb_event_cause;
u8 usb_int_cause;
@@ -102,8 +104,4 @@ struct fwsyncheader {
#define FW_DATA_XMIT_SIZE \
sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
-int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
-void if_usb_free(struct usb_card_rec *cardp);
-int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
-
#endif
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
index 78ac3064a0bd..dc24a05c9447 100644
--- a/drivers/net/wireless/libertas/join.c
+++ b/drivers/net/wireless/libertas/join.c
@@ -17,10 +17,13 @@
#include "dev.h"
#include "assoc.h"
-#define AD_HOC_CAP_PRIVACY_ON 1
+/* The firmware needs certain bits masked out of the beacon-derviced capability
+ * field when associating/joining to BSSs.
+ */
+#define CAPINFO_MASK (~(0xda00))
/**
- * @brief This function finds out the common rates between rate1 and rate2.
+ * @brief This function finds common rates between rate1 and card rates.
*
* It will fill common rates in rate1 as output if found.
*
@@ -29,75 +32,87 @@
*
* @param adapter A pointer to wlan_adapter structure
* @param rate1 the buffer which keeps input and output
- * @param rate1_size the size of rate1 buffer
- * @param rate2 the buffer which keeps rate2
- * @param rate2_size the size of rate2 buffer.
+ * @param rate1_size the size of rate1 buffer; new size of buffer on return
*
* @return 0 or -1
*/
-static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
- int rate1_size, u8 * rate2, int rate2_size)
+static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size)
{
- u8 *ptr = rate1;
- int ret = 0;
+ u8 *card_rates = libertas_bg_rates;
+ size_t num_card_rates = sizeof(libertas_bg_rates);
+ int ret = 0, i, j;
u8 tmp[30];
- int i;
+ size_t tmp_size = 0;
- memset(&tmp, 0, sizeof(tmp));
- memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
- memset(rate1, 0, rate1_size);
-
- /* Mask the top bit of the original values */
- for (i = 0; tmp[i] && i < sizeof(tmp); i++)
- tmp[i] &= 0x7F;
-
- for (i = 0; rate2[i] && i < rate2_size; i++) {
- /* Check for Card Rate in tmp, excluding the top bit */
- if (strchr(tmp, rate2[i] & 0x7F)) {
- /* values match, so copy the Card Rate to rate1 */
- *rate1++ = rate2[i];
+ /* For each rate in card_rates that exists in rate1, copy to tmp */
+ for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
+ for (j = 0; rates[j] && (j < *rates_size); j++) {
+ if (rates[j] == card_rates[i])
+ tmp[tmp_size++] = card_rates[i];
}
}
- lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
- lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
- lbs_dbg_hex("Common rates:", ptr, rate1_size);
- lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate);
+ lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
+ lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+ lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate);
- if (!adapter->is_datarate_auto) {
- while (*ptr) {
- if ((*ptr & 0x7f) == adapter->datarate) {
- ret = 0;
+ if (!adapter->auto_rate) {
+ for (i = 0; i < tmp_size; i++) {
+ if (tmp[i] == adapter->cur_rate)
goto done;
- }
- ptr++;
}
- lbs_pr_alert( "Previously set fixed data rate %#x isn't "
- "compatible with the network.\n", adapter->datarate);
-
+ lbs_pr_alert("Previously set fixed data rate %#x isn't "
+ "compatible with the network.\n", adapter->cur_rate);
ret = -1;
goto done;
}
-
ret = 0;
+
done:
+ memset(rates, 0, *rates_size);
+ *rates_size = min_t(int, tmp_size, *rates_size);
+ memcpy(rates, tmp, *rates_size);
return ret;
}
-int libertas_send_deauth(wlan_private * priv)
+
+/**
+ * @brief Sets the MSB on basic rates as the firmware requires
+ *
+ * Scan through an array and set the MSB for basic data rates.
+ *
+ * @param rates buffer of data rates
+ * @param len size of buffer
+ */
+static void libertas_set_basic_rate_flags(u8 * rates, size_t len)
{
- wlan_adapter *adapter = priv->adapter;
- int ret = 0;
+ int i;
- if (adapter->mode == IW_MODE_INFRA &&
- adapter->connect_status == libertas_connected)
- ret = libertas_send_deauthentication(priv);
- else
- ret = -ENOTSUPP;
+ for (i = 0; i < len; i++) {
+ if (rates[i] == 0x02 || rates[i] == 0x04 ||
+ rates[i] == 0x0b || rates[i] == 0x16)
+ rates[i] |= 0x80;
+ }
+}
- return ret;
+/**
+ * @brief Unsets the MSB on basic rates
+ *
+ * Scan through an array and unset the MSB for basic data rates.
+ *
+ * @param rates buffer of data rates
+ * @param len size of buffer
+ */
+void libertas_unset_basic_rate_flags(u8 * rates, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ rates[i] &= 0x7f;
}
+
/**
* @brief Associate to a specific BSS discovered in a scan
*
@@ -113,23 +128,24 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
lbs_deb_enter(LBS_DEB_JOIN);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
- 0, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
+ 0, CMD_OPTION_WAITFORRSP,
0, assoc_req->bss.bssid);
if (ret)
goto done;
/* set preamble to firmware */
- if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble)
- adapter->preamble = cmd_type_short_preamble;
+ if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+ adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
else
- adapter->preamble = cmd_type_long_preamble;
+ adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
libertas_set_radio_control(priv);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
- 0, cmd_option_waitforrsp, 0, assoc_req);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
+ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -150,12 +166,12 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass
adapter->adhoccreate = 1;
- if (!adapter->capinfo.shortpreamble) {
- lbs_deb_join("AdhocStart: Long preamble\n");
- adapter->preamble = cmd_type_long_preamble;
- } else {
+ if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
lbs_deb_join("AdhocStart: Short preamble\n");
- adapter->preamble = cmd_type_short_preamble;
+ adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
+ } else {
+ lbs_deb_join("AdhocStart: Long preamble\n");
+ adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
}
libertas_set_radio_control(priv);
@@ -163,8 +179,8 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass
lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
- 0, cmd_option_waitforrsp, 0, assoc_req);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
+ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
return ret;
}
@@ -194,25 +210,37 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso
bss->ssid_len);
/* check if the requested SSID is already joined */
- if (adapter->curbssparams.ssid_len
+ if ( adapter->curbssparams.ssid_len
&& !libertas_ssid_cmp(adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len,
bss->ssid, bss->ssid_len)
- && (adapter->mode == IW_MODE_ADHOC)) {
- lbs_deb_join(
- "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
- "not attempting to re-join");
- return -1;
+ && (adapter->mode == IW_MODE_ADHOC)
+ && (adapter->connect_status == LIBERTAS_CONNECTED)) {
+ union iwreq_data wrqu;
+
+ lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
+ "current, not attempting to re-join");
+
+ /* Send the re-association event though, because the association
+ * request really was successful, even if just a null-op.
+ */
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid,
+ ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ goto out;
}
- /*Use shortpreamble only when both creator and card supports
+ /* Use shortpreamble only when both creator and card supports
short preamble */
- if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+ if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
lbs_deb_join("AdhocJoin: Long preamble\n");
- adapter->preamble = cmd_type_long_preamble;
+ adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
} else {
lbs_deb_join("AdhocJoin: Short preamble\n");
- adapter->preamble = cmd_type_short_preamble;
+ adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
}
libertas_set_radio_control(priv);
@@ -222,17 +250,18 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso
adapter->adhoccreate = 0;
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
- 0, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
+ 0, CMD_OPTION_WAITFORRSP,
OID_802_11_SSID, assoc_req);
+out:
return ret;
}
int libertas_stop_adhoc_network(wlan_private * priv)
{
- return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
- 0, cmd_option_waitforrsp, 0, NULL);
+ return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
@@ -243,8 +272,8 @@ int libertas_stop_adhoc_network(wlan_private * priv)
*/
int libertas_send_deauthentication(wlan_private * priv)
{
- return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
- 0, cmd_option_waitforrsp, 0, NULL);
+ return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
@@ -264,10 +293,11 @@ int libertas_cmd_80211_authenticate(wlan_private * priv,
struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
int ret = -1;
u8 *bssid = pdata_buf;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
- cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+ cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+ S_DS_GEN);
@@ -290,8 +320,8 @@ int libertas_cmd_80211_authenticate(wlan_private * priv,
memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
- lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n",
- MAC_ARG(bssid), pauthenticate->authtype);
+ lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n",
+ print_mac(mac, bssid), pauthenticate->authtype);
ret = 0;
out:
@@ -307,7 +337,7 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv,
lbs_deb_enter(LBS_DEB_JOIN);
- cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+ cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
S_DS_GEN);
@@ -330,9 +360,7 @@ int libertas_cmd_80211_associate(wlan_private * priv,
int ret = 0;
struct assoc_request * assoc_req = pdata_buf;
struct bss_descriptor * bss = &assoc_req->bss;
- u8 *card_rates;
u8 *pos;
- int card_rates_size;
u16 tmpcap, tmplen;
struct mrvlietypes_ssidparamset *ssid;
struct mrvlietypes_phyparamset *phy;
@@ -349,15 +377,15 @@ int libertas_cmd_80211_associate(wlan_private * priv,
goto done;
}
- cmd->command = cpu_to_le16(cmd_802_11_associate);
+ cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
pos += sizeof(passo->peerstaaddr);
/* set the listen interval */
- passo->listeninterval = cpu_to_le16(adapter->listeninterval);
+ passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
- pos += sizeof(passo->capinfo);
+ pos += sizeof(passo->capability);
pos += sizeof(passo->listeninterval);
pos += sizeof(passo->bcnperiod);
pos += sizeof(passo->dtimperiod);
@@ -386,23 +414,24 @@ int libertas_cmd_80211_associate(wlan_private * priv,
rates = (struct mrvlietypes_ratesparamset *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
-
- memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES);
-
- card_rates = libertas_supported_rates;
- card_rates_size = sizeof(libertas_supported_rates);
-
- if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
- card_rates, card_rates_size)) {
+ memcpy(&rates->rates, &bss->rates, MAX_RATES);
+ tmplen = MAX_RATES;
+ if (get_common_rates(adapter, rates->rates, &tmplen)) {
ret = -1;
goto done;
}
-
- tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
- adapter->curbssparams.numofrates = tmplen;
-
pos += sizeof(rates->header) + tmplen;
rates->header.len = cpu_to_le16(tmplen);
+ lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen);
+
+ /* Copy the infra. association rates into Current BSS state structure */
+ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+ memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen);
+
+ /* Set MSB on basic rates as the firmware requires, but _after_
+ * copying to current bss rates.
+ */
+ libertas_set_basic_rate_flags(rates->rates, tmplen);
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
rsn = (struct mrvlietypes_rsnparamset *) pos;
@@ -411,7 +440,7 @@ int libertas_cmd_80211_associate(wlan_private * priv,
tmplen = (u16) assoc_req->wpa_ie[1];
rsn->header.len = cpu_to_le16(tmplen);
memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
- lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+ lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
sizeof(rsn->header) + tmplen);
pos += sizeof(rsn->header) + tmplen;
}
@@ -419,20 +448,6 @@ int libertas_cmd_80211_associate(wlan_private * priv,
/* update curbssparams */
adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
- /* Copy the infra. association rates into Current BSS state structure */
- memcpy(&adapter->curbssparams.datarates, &rates->rates,
- min_t(size_t, sizeof(adapter->curbssparams.datarates),
- cpu_to_le16(rates->header.len)));
-
- lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
- cpu_to_le16(rates->header.len));
-
- /* set IBSS field */
- if (bss->mode == IW_MODE_INFRA) {
-#define CAPINFO_ESS_MODE 1
- passo->capinfo.ess = CAPINFO_ESS_MODE;
- }
-
if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto done;
@@ -440,12 +455,13 @@ int libertas_cmd_80211_associate(wlan_private * priv,
cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
- /* set the capability info at last */
- memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo));
- tmpcap &= CAPINFO_MASK;
- lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+ /* set the capability info */
+ tmpcap = (bss->capability & CAPINFO_MASK);
+ if (bss->mode == IW_MODE_INFRA)
+ tmpcap |= WLAN_CAPABILITY_ESS;
+ passo->capability = cpu_to_le16(tmpcap);
+ lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n",
tmpcap, CAPINFO_MASK);
- memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -459,8 +475,9 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
int ret = 0;
int cmdappendsize = 0;
- int i;
struct assoc_request * assoc_req = pdata_buf;
+ u16 tmpcap = 0;
+ size_t ratesize = 0;
lbs_deb_enter(LBS_DEB_JOIN);
@@ -469,7 +486,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
goto done;
}
- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
/*
* Fill in the parameters for 2 data structures:
@@ -483,17 +500,17 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
* and operational rates.
*/
- memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
- memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len);
+ memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
+ memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->ssid_len);
/* set the BSS type */
- adhs->bsstype = cmd_bss_type_ibss;
+ adhs->bsstype = CMD_BSS_TYPE_IBSS;
adapter->mode = IW_MODE_ADHOC;
- adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod);
+ adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL);
/* set Physical param set */
#define DS_PARA_IE_ID 3
@@ -515,45 +532,36 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
- adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow);
+ adhs->ssparamset.ibssparamset.atimwindow = 0;
/* set capability info */
- adhs->cap.ess = 0;
- adhs->cap.ibss = 1;
-
- /* probedelay */
- adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
-
- /* set up privacy in adapter->scantable[i] */
+ tmpcap = WLAN_CAPABILITY_IBSS;
if (assoc_req->secinfo.wep_enabled) {
lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
- adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ tmpcap |= WLAN_CAPABILITY_PRIVACY;
} else {
lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
}
+ adhs->capability = cpu_to_le16(tmpcap);
- memset(adhs->datarate, 0, sizeof(adhs->datarate));
-
- if (adapter->adhoc_grate_enabled) {
- memcpy(adhs->datarate, libertas_adhoc_rates_g,
- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
- } else {
- memcpy(adhs->datarate, libertas_adhoc_rates_b,
- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
- }
-
- /* Find the last non zero */
- for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
+ /* probedelay */
+ adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
- adapter->curbssparams.numofrates = i;
+ memset(adhs->rates, 0, sizeof(adhs->rates));
+ ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates));
+ memcpy(adhs->rates, libertas_bg_rates, ratesize);
/* Copy the ad-hoc creating rates into Current BSS state structure */
- memcpy(&adapter->curbssparams.datarates,
- &adhs->datarate, adapter->curbssparams.numofrates);
+ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+ memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize);
+
+ /* Set MSB on basic rates as the firmware requires, but _after_
+ * copying to current bss rates.
+ */
+ libertas_set_basic_rate_flags(adhs->rates, ratesize);
lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
- adhs->datarate[0], adhs->datarate[1],
- adhs->datarate[2], adhs->datarate[3]);
+ adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
@@ -575,7 +583,7 @@ done:
int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
struct cmd_ds_command *cmd)
{
- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
cmd->size = cpu_to_le16(S_DS_GEN);
return 0;
@@ -585,101 +593,84 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
wlan_adapter *adapter = priv->adapter;
- struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+ struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
struct assoc_request * assoc_req = pdata_buf;
struct bss_descriptor *bss = &assoc_req->bss;
int cmdappendsize = 0;
int ret = 0;
- u8 *card_rates;
- int card_rates_size;
- u16 tmpcap;
- int i;
+ u16 ratesize = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
- padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+ join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
+ join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
- padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod);
+ memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
+ memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
- memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN);
- memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len);
+ memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
+ sizeof(union ieeetypes_phyparamset));
- memcpy(&padhocjoin->bssdescriptor.phyparamset,
- &bss->phyparamset, sizeof(union ieeetypes_phyparamset));
-
- memcpy(&padhocjoin->bssdescriptor.ssparamset,
- &bss->ssparamset, sizeof(union IEEEtypes_ssparamset));
-
- memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo));
- tmpcap &= CAPINFO_MASK;
+ memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
+ sizeof(union IEEEtypes_ssparamset));
+ join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
- tmpcap, CAPINFO_MASK);
- memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
- sizeof(struct ieeetypes_capinfo));
+ bss->capability, CAPINFO_MASK);
/* information on BSSID descriptor passed to FW */
lbs_deb_join(
- "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n",
- MAC_ARG(padhocjoin->bssdescriptor.BSSID),
- padhocjoin->bssdescriptor.SSID);
+ "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
+ print_mac(mac, join_cmd->bss.bssid),
+ join_cmd->bss.ssid);
/* failtimeout */
- padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+ join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
/* probedelay */
- padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
-
- /* Copy Data rates from the rates recorded in scan response */
- memset(padhocjoin->bssdescriptor.datarates, 0,
- sizeof(padhocjoin->bssdescriptor.datarates));
- memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates,
- min(sizeof(padhocjoin->bssdescriptor.datarates),
- sizeof(bss->datarates)));
-
- card_rates = libertas_supported_rates;
- card_rates_size = sizeof(libertas_supported_rates);
+ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
adapter->curbssparams.channel = bss->channel;
- if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
- sizeof(padhocjoin->bssdescriptor.datarates),
- card_rates, card_rates_size)) {
+ /* Copy Data rates from the rates recorded in scan response */
+ memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
+ ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
+ memcpy(join_cmd->bss.rates, bss->rates, ratesize);
+ if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
ret = -1;
goto done;
}
- /* Find the last non zero */
- for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
- && padhocjoin->bssdescriptor.datarates[i]; i++) ;
-
- adapter->curbssparams.numofrates = i;
+ /* Copy the ad-hoc creating rates into Current BSS state structure */
+ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+ memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize);
- /*
- * Copy the adhoc joining rates to Current BSS State structure
+ /* Set MSB on basic rates as the firmware requires, but _after_
+ * copying to current bss rates.
*/
- memcpy(adapter->curbssparams.datarates,
- padhocjoin->bssdescriptor.datarates,
- adapter->curbssparams.numofrates);
+ libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
- padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+ join_cmd->bss.ssparamset.ibssparamset.atimwindow =
cpu_to_le16(bss->atimwindow);
if (assoc_req->secinfo.wep_enabled) {
- padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ u16 tmp = le16_to_cpu(join_cmd->bss.capability);
+ tmp |= WLAN_CAPABILITY_PRIVACY;
+ join_cmd->bss.capability = cpu_to_le16(tmp);
}
- if (adapter->psmode == wlan802_11powermodemax_psp) {
+ if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
/* wake up first */
__le32 Localpsmode;
- Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+ Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_ps_mode,
- cmd_act_set,
+ CMD_802_11_PS_MODE,
+ CMD_ACT_SET,
0, 0, &Localpsmode);
if (ret) {
@@ -709,6 +700,7 @@ int libertas_ret_80211_associate(wlan_private * priv,
union iwreq_data wrqu;
struct ieeetypes_assocrsp *passocrsp;
struct bss_descriptor * bss;
+ u16 status_code;
lbs_deb_enter(LBS_DEB_JOIN);
@@ -721,21 +713,65 @@ int libertas_ret_80211_associate(wlan_private * priv,
passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
- if (le16_to_cpu(passocrsp->statuscode)) {
- libertas_mac_event_disconnected(priv);
+ /*
+ * Older FW versions map the IEEE 802.11 Status Code in the association
+ * response to the following values returned in passocrsp->statuscode:
+ *
+ * IEEE Status Code Marvell Status Code
+ * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
+ * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * others -> 0x0003 ASSOC_RESULT_REFUSED
+ *
+ * Other response codes:
+ * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+ * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+ * association response from the AP)
+ */
- lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n",
- le16_to_cpu(passocrsp->statuscode));
+ status_code = le16_to_cpu(passocrsp->statuscode);
+ switch (status_code) {
+ case 0x00:
+ lbs_deb_join("ASSOC_RESP: Association succeeded\n");
+ break;
+ case 0x01:
+ lbs_deb_join("ASSOC_RESP: Association failed; invalid "
+ "parameters (status code %d)\n", status_code);
+ break;
+ case 0x02:
+ lbs_deb_join("ASSOC_RESP: Association failed; internal timer "
+ "expired while waiting for the AP (status code %d)"
+ "\n", status_code);
+ break;
+ case 0x03:
+ lbs_deb_join("ASSOC_RESP: Association failed; association "
+ "was refused by the AP (status code %d)\n",
+ status_code);
+ break;
+ case 0x04:
+ lbs_deb_join("ASSOC_RESP: Association failed; authentication "
+ "was refused by the AP (status code %d)\n",
+ status_code);
+ break;
+ default:
+ lbs_deb_join("ASSOC_RESP: Association failed; reason unknown "
+ "(status code %d)\n", status_code);
+ break;
+ }
+ if (status_code) {
+ libertas_mac_event_disconnected(priv);
ret = -1;
goto done;
}
- lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+ lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params,
le16_to_cpu(resp->size) - S_DS_GEN);
/* Send a Media Connected event, according to the Spec */
- adapter->connect_status = libertas_connected;
+ adapter->connect_status = LIBERTAS_CONNECTED;
lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
escape_essid(bss->ssid, bss->ssid_len));
@@ -759,10 +795,10 @@ int libertas_ret_80211_associate(wlan_private * priv,
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
-
- lbs_deb_join("ASSOC_RESP: Associated \n");
+ if (priv->mesh_dev) {
+ netif_carrier_on(priv->mesh_dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -794,6 +830,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_802_11_ad_hoc_result *padhocresult;
union iwreq_data wrqu;
struct bss_descriptor *bss;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -815,7 +852,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
*/
if (result) {
lbs_deb_join("ADHOC_RESP: failed\n");
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
libertas_mac_event_disconnected(priv);
}
ret = -1;
@@ -830,11 +867,11 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
escape_essid(bss->ssid, bss->ssid_len));
/* Send a Media Connected event, according to the Spec */
- adapter->connect_status = libertas_connected;
+ adapter->connect_status = LIBERTAS_CONNECTED;
- if (command == cmd_ret_802_11_ad_hoc_start) {
+ if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
/* Update the created network descriptor with the new BSSID */
- memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN);
+ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
}
/* Set the BSSID from the joined/started descriptor */
@@ -847,8 +884,10 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev) {
+ netif_carrier_on(priv->mesh_dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
@@ -857,8 +896,8 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
- lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n",
- MAC_ARG(padhocresult->BSSID));
+ lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
+ print_mac(mac, padhocresult->bssid));
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
index d522630ff8cf..894a072b9f8d 100644
--- a/drivers/net/wireless/libertas/join.h
+++ b/drivers/net/wireless/libertas/join.h
@@ -12,45 +12,42 @@
#include "dev.h"
struct cmd_ds_command;
-extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+int libertas_cmd_80211_authenticate(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
struct cmd_ds_command *cmd);
-extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
struct cmd_ds_command *cmd);
-extern int libertas_cmd_80211_associate(wlan_private * priv,
+int libertas_cmd_80211_associate(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_ret_80211_disassociate(wlan_private * priv,
+int libertas_ret_80211_disassociate(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_ret_80211_associate(wlan_private * priv,
+int libertas_ret_80211_associate(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_reassociation_thread(void *data);
-
-extern int libertas_start_adhoc_network(wlan_private * priv,
+int libertas_start_adhoc_network(wlan_private * priv,
struct assoc_request * assoc_req);
-extern int libertas_join_adhoc_network(wlan_private * priv,
+int libertas_join_adhoc_network(wlan_private * priv,
struct assoc_request * assoc_req);
-extern int libertas_stop_adhoc_network(wlan_private * priv);
-
-extern int libertas_send_deauthentication(wlan_private * priv);
-extern int libertas_send_deauth(wlan_private * priv);
+int libertas_stop_adhoc_network(wlan_private * priv);
-extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+int libertas_send_deauthentication(wlan_private * priv);
int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req);
+void libertas_unset_basic_rate_flags(u8 * rates, size_t len);
+
#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 9f366242c392..5ead08312e1e 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -10,6 +10,7 @@
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
+#include <linux/kthread.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
@@ -20,8 +21,9 @@
#include "wext.h"
#include "debugfs.h"
#include "assoc.h"
+#include "join.h"
-#define DRIVER_RELEASE_VERSION "322.p0"
+#define DRIVER_RELEASE_VERSION "323.p0"
const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
#ifdef DEBUG
"-dbg"
@@ -121,57 +123,88 @@ struct region_cfp_table {
static struct region_cfp_table region_cfp_table[] = {
{0x10, /*US FCC */
channel_freq_power_US_BG,
- sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x20, /*CANADA IC */
channel_freq_power_US_BG,
- sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x30, /*EU*/ channel_freq_power_EU_BG,
- sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_EU_BG),
}
,
{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
- sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_SPN_BG),
}
,
{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
- sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_FR_BG),
}
,
{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
- sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_JPN_BG),
}
,
/*Add new region here */
};
/**
- * the rates supported
+ * the table to keep region code
*/
-u8 libertas_supported_rates[G_SUPPORTED_RATES] =
- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
- * the rates supported for ad-hoc G mode
+ * 802.11b/g supported bitrates (in 500Kb/s units)
*/
-u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
+u8 libertas_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
/**
- * the rates supported for ad-hoc B mode
+ * FW rate table. FW refers to rates by their index in this table, not by the
+ * rate value itself. Values of 0x00 are
+ * reserved positions.
*/
-u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+static u8 fw_data_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
/**
- * the table to keep region code
+ * @brief use index to get the data rate
+ *
+ * @param idx The index of data rate
+ * @return data rate or 0
*/
-u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
- { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+u32 libertas_fw_index_to_data_rate(u8 idx)
+{
+ if (idx >= sizeof(fw_data_rates))
+ idx = 0;
+ return fw_data_rates[idx];
+}
+
+/**
+ * @brief use rate to get the index
+ *
+ * @param rate data rate
+ * @return index or 0
+ */
+u8 libertas_data_rate_to_fw_index(u32 rate)
+{
+ u8 i;
+
+ if (!rate)
+ return 0;
+
+ for (i = 0; i < sizeof(fw_data_rates); i++) {
+ if (rate == fw_data_rates[i])
+ return i;
+ }
+ return 0;
+}
/**
* Attributes exported through sysfs
@@ -187,9 +220,9 @@ static ssize_t libertas_anycast_get(struct device * dev,
memset(&mesh_access, 0, sizeof(mesh_access));
libertas_prepare_and_send_command(to_net_dev(dev)->priv,
- cmd_mesh_access,
- cmd_act_mesh_get_anycast,
- cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_GET_ANYCAST,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
}
@@ -208,18 +241,127 @@ static ssize_t libertas_anycast_set(struct device * dev,
mesh_access.data[0] = cpu_to_le32(datum);
libertas_prepare_and_send_command((to_net_dev(dev))->priv,
- cmd_mesh_access,
- cmd_act_mesh_set_anycast,
- cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_ANYCAST,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ return strlen(buf);
+}
+
+int libertas_add_rtap(wlan_private *priv);
+void libertas_remove_rtap(wlan_private *priv);
+
+/**
+ * Get function for sysfs attribute rtap
+ */
+static ssize_t libertas_rtap_get(struct device * dev,
+ struct device_attribute *attr, char * buf)
+{
+ wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
+ wlan_adapter *adapter = priv->adapter;
+ return snprintf(buf, 5, "0x%X\n", adapter->monitormode);
+}
+
+/**
+ * Set function for sysfs attribute rtap
+ */
+static ssize_t libertas_rtap_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ int monitor_mode;
+ wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ sscanf(buf, "%x", &monitor_mode);
+ if (monitor_mode != WLAN_MONITOR_OFF) {
+ if(adapter->monitormode == monitor_mode)
+ return strlen(buf);
+ if (adapter->monitormode == WLAN_MONITOR_OFF) {
+ if (adapter->mode == IW_MODE_INFRA)
+ libertas_send_deauthentication(priv);
+ else if (adapter->mode == IW_MODE_ADHOC)
+ libertas_stop_adhoc_network(priv);
+ libertas_add_rtap(priv);
+ }
+ adapter->monitormode = monitor_mode;
+ }
+
+ else {
+ if(adapter->monitormode == WLAN_MONITOR_OFF)
+ return strlen(buf);
+ adapter->monitormode = WLAN_MONITOR_OFF;
+ libertas_remove_rtap(priv);
+ netif_wake_queue(priv->dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
+
+ libertas_prepare_and_send_command(priv,
+ CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode);
return strlen(buf);
}
/**
+ * libertas_rtap attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-rtap)
+ */
+static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get,
+ libertas_rtap_set );
+
+/**
* anycast_mask attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/anycast_mask)
*/
static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);
+static ssize_t libertas_autostart_enabled_get(struct device * dev,
+ struct device_attribute *attr, char * buf)
+{
+ struct cmd_ds_mesh_access mesh_access;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+
+ return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));
+}
+
+static ssize_t libertas_autostart_enabled_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ uint32_t datum;
+ wlan_private * priv = (to_net_dev(dev))->priv;
+ int ret;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ sscanf(buf, "%d", &datum);
+ mesh_access.data[0] = cpu_to_le32(datum);
+
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ if (ret == 0)
+ priv->mesh_autostart_enabled = datum ? 1 : 0;
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(autostart_enabled, 0644,
+ libertas_autostart_enabled_get, libertas_autostart_enabled_set);
+
+static struct attribute *libertas_mesh_sysfs_entries[] = {
+ &dev_attr_anycast_mask.attr,
+ &dev_attr_autostart_enabled.attr,
+ NULL,
+};
+
+static struct attribute_group libertas_mesh_attr_group = {
+ .attrs = libertas_mesh_sysfs_entries,
+};
+
/**
* @brief Check if the device can be open and wait if necessary.
*
@@ -255,7 +397,7 @@ static int pre_open_check(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_dev_open(struct net_device *dev)
+static int libertas_dev_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
wlan_adapter *adapter = priv->adapter;
@@ -264,12 +406,14 @@ static int wlan_dev_open(struct net_device *dev)
priv->open = 1;
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
netif_carrier_on(priv->dev);
- netif_carrier_on(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_carrier_on(priv->mesh_dev);
} else {
netif_carrier_off(priv->dev);
- netif_carrier_off(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_carrier_off(priv->mesh_dev);
}
lbs_deb_leave(LBS_DEB_NET);
@@ -281,7 +425,7 @@ static int wlan_dev_open(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int mesh_open(struct net_device *dev)
+static int libertas_mesh_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv ;
@@ -290,7 +434,7 @@ static int mesh_open(struct net_device *dev)
priv->mesh_open = 1 ;
netif_wake_queue(priv->mesh_dev);
if (priv->infra_open == 0)
- return wlan_dev_open(priv->dev) ;
+ return libertas_dev_open(priv->dev) ;
return 0;
}
@@ -300,7 +444,7 @@ static int mesh_open(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_open(struct net_device *dev)
+static int libertas_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv ;
@@ -309,11 +453,11 @@ static int wlan_open(struct net_device *dev)
priv->infra_open = 1 ;
netif_wake_queue(priv->dev);
if (priv->open == 0)
- return wlan_dev_open(priv->dev) ;
+ return libertas_dev_open(priv->dev) ;
return 0;
}
-static int wlan_dev_close(struct net_device *dev)
+static int libertas_dev_close(struct net_device *dev)
{
wlan_private *priv = dev->priv;
@@ -332,14 +476,14 @@ static int wlan_dev_close(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int mesh_close(struct net_device *dev)
+static int libertas_mesh_close(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) (dev->priv);
priv->mesh_open = 0;
netif_stop_queue(priv->mesh_dev);
if (priv->infra_open == 0)
- return wlan_dev_close(dev);
+ return libertas_dev_close(dev);
else
return 0;
}
@@ -350,20 +494,20 @@ static int mesh_close(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_close(struct net_device *dev)
+static int libertas_close(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
netif_stop_queue(dev);
priv->infra_open = 0;
if (priv->mesh_open == 0)
- return wlan_dev_close(dev);
+ return libertas_dev_close(dev);
else
return 0;
}
-static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int ret = 0;
wlan_private *priv = dev->priv;
@@ -376,7 +520,8 @@ static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
if (libertas_process_tx(priv, skb) == 0)
dev->trans_start = jiffies;
@@ -386,41 +531,52 @@ done:
}
/**
- * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark mesh packets and handover them to libertas_hard_start_xmit
*
*/
-static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
wlan_private *priv = dev->priv;
int ret;
lbs_deb_enter(LBS_DEB_MESH);
+ if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+ }
SET_MESH_FRAME(skb);
- ret = wlan_hard_start_xmit(skb, priv->dev);
+ ret = libertas_hard_start_xmit(skb, priv->dev);
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret;
}
/**
- * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit
*
*/
-static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ wlan_private *priv = dev->priv;
int ret;
lbs_deb_enter(LBS_DEB_NET);
+ if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+ }
+
UNSET_MESH_FRAME(skb);
- ret = wlan_hard_start_xmit(skb, dev);
+ ret = libertas_hard_start_xmit(skb, dev);
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
-static void wlan_tx_timeout(struct net_device *dev)
+static void libertas_tx_timeout(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
@@ -432,16 +588,17 @@ static void wlan_tx_timeout(struct net_device *dev)
dev->trans_start = jiffies;
if (priv->adapter->currenttxskb) {
- if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
/* If we are here, we have not received feedback from
the previous packet. Assume TX_FAIL and move on. */
priv->adapter->eventcause = 0x01000000;
libertas_send_tx_feedback(priv);
} else
- wake_up_interruptible(&priv->mainthread.waitq);
- } else if (priv->adapter->connect_status == libertas_connected) {
+ wake_up_interruptible(&priv->waitq);
+ } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_wake_queue(priv->dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
lbs_deb_leave(LBS_DEB_TX);
@@ -453,14 +610,14 @@ static void wlan_tx_timeout(struct net_device *dev)
* @param dev A pointer to wlan_private structure
* @return A pointer to net_device_stats structure
*/
-static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+static struct net_device_stats *libertas_get_stats(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
return &priv->stats;
}
-static int wlan_set_mac_address(struct net_device *dev, void *addr)
+static int libertas_set_mac_address(struct net_device *dev, void *addr)
{
int ret = 0;
wlan_private *priv = (wlan_private *) dev->priv;
@@ -475,14 +632,14 @@ static int wlan_set_mac_address(struct net_device *dev, void *addr)
memset(adapter->current_addr, 0, ETH_ALEN);
/* dev->dev_addr is 8 bytes */
- lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
- lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret) {
lbs_deb_net("set MAC address failed\n");
@@ -490,7 +647,7 @@ static int wlan_set_mac_address(struct net_device *dev, void *addr)
goto done;
}
- lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN);
memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
@@ -500,7 +657,7 @@ done:
return ret;
}
-static int wlan_copy_multicast_address(wlan_adapter * adapter,
+static int libertas_copy_multicast_address(wlan_adapter * adapter,
struct net_device *dev)
{
int i = 0;
@@ -515,11 +672,12 @@ static int wlan_copy_multicast_address(wlan_adapter * adapter,
}
-static void wlan_set_multicast_list(struct net_device *dev)
+static void libertas_set_multicast_list(struct net_device *dev)
{
wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
int oldpacketfilter;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_NET);
@@ -528,57 +686,52 @@ static void wlan_set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
lbs_deb_net("enable promiscuous mode\n");
adapter->currentpacketfilter |=
- cmd_act_mac_promiscuous_enable;
+ CMD_ACT_MAC_PROMISCUOUS_ENABLE;
adapter->currentpacketfilter &=
- ~(cmd_act_mac_all_multicast_enable |
- cmd_act_mac_multicast_enable);
+ ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+ CMD_ACT_MAC_MULTICAST_ENABLE);
} else {
/* Multicast */
adapter->currentpacketfilter &=
- ~cmd_act_mac_promiscuous_enable;
+ ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (dev->flags & IFF_ALLMULTI || dev->mc_count >
MRVDRV_MAX_MULTICAST_LIST_SIZE) {
lbs_deb_net( "enabling all multicast\n");
adapter->currentpacketfilter |=
- cmd_act_mac_all_multicast_enable;
+ CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
adapter->currentpacketfilter &=
- ~cmd_act_mac_multicast_enable;
+ ~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
adapter->currentpacketfilter &=
- ~cmd_act_mac_all_multicast_enable;
+ ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
if (!dev->mc_count) {
lbs_deb_net("no multicast addresses, "
"disabling multicast\n");
adapter->currentpacketfilter &=
- ~cmd_act_mac_multicast_enable;
+ ~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
int i;
adapter->currentpacketfilter |=
- cmd_act_mac_multicast_enable;
+ CMD_ACT_MAC_MULTICAST_ENABLE;
adapter->nr_of_multicastmacaddr =
- wlan_copy_multicast_address(adapter, dev);
+ libertas_copy_multicast_address(adapter, dev);
lbs_deb_net("multicast addresses: %d\n",
dev->mc_count);
for (i = 0; i < dev->mc_count; i++) {
- lbs_deb_net("Multicast address %d:"
- MAC_FMT "\n", i,
- adapter->multicastlist[i][0],
- adapter->multicastlist[i][1],
- adapter->multicastlist[i][2],
- adapter->multicastlist[i][3],
- adapter->multicastlist[i][4],
- adapter->multicastlist[i][5]);
+ lbs_deb_net("Multicast address %d:%s\n",
+ i, print_mac(mac,
+ adapter->multicastlist[i]));
}
/* send multicast addresses to firmware */
libertas_prepare_and_send_command(priv,
- cmd_mac_multicast_adr,
- cmd_act_set, 0, 0,
+ CMD_MAC_MULTICAST_ADR,
+ CMD_ACT_SET, 0, 0,
NULL);
}
}
@@ -599,18 +752,16 @@ static void wlan_set_multicast_list(struct net_device *dev)
* @param data A pointer to wlan_thread structure
* @return 0
*/
-static int wlan_service_main_thread(void *data)
+static int libertas_thread(void *data)
{
- struct wlan_thread *thread = data;
- wlan_private *priv = thread->priv;
+ struct net_device *dev = data;
+ wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
wait_queue_t wait;
u8 ireg = 0;
lbs_deb_enter(LBS_DEB_THREAD);
- wlan_activate_thread(thread);
-
init_waitqueue_entry(&wait, current);
set_freezable();
@@ -620,7 +771,7 @@ static int wlan_service_main_thread(void *data)
adapter->intcounter,
adapter->currenttxskb, priv->dnld_sent);
- add_wait_queue(&thread->waitq, &wait);
+ add_wait_queue(&priv->waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&adapter->driver_lock);
if ((adapter->psstate == PS_STATE_SLEEP) ||
@@ -636,14 +787,13 @@ static int wlan_service_main_thread(void *data)
} else
spin_unlock_irq(&adapter->driver_lock);
-
lbs_deb_thread(
"main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
"dnld_sent=%d\n", adapter->intcounter,
adapter->currenttxskb, priv->dnld_sent);
set_current_state(TASK_RUNNING);
- remove_wait_queue(&thread->waitq, &wait);
+ remove_wait_queue(&priv->waitq, &wait);
try_to_freeze();
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p "
@@ -681,20 +831,20 @@ static int wlan_service_main_thread(void *data)
adapter->currenttxskb, priv->dnld_sent);
/* command response? */
- if (adapter->hisregcpy & his_cmdupldrdy) {
+ if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
lbs_deb_thread("main-thread: cmd response ready\n");
- adapter->hisregcpy &= ~his_cmdupldrdy;
+ adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
spin_unlock_irq(&adapter->driver_lock);
libertas_process_rx_command(priv);
spin_lock_irq(&adapter->driver_lock);
}
/* Any Card Event */
- if (adapter->hisregcpy & his_cardevent) {
+ if (adapter->hisregcpy & MRVDRV_CARDEVENT) {
lbs_deb_thread("main-thread: Card Event Activity\n");
- adapter->hisregcpy &= ~his_cardevent;
+ adapter->hisregcpy &= ~MRVDRV_CARDEVENT;
if (priv->hw_read_event_cause(priv)) {
lbs_pr_alert(
@@ -711,7 +861,7 @@ static int wlan_service_main_thread(void *data)
if (adapter->psstate == PS_STATE_PRE_SLEEP) {
if (!priv->dnld_sent && !adapter->cur_cmd) {
if (adapter->connect_status ==
- libertas_connected) {
+ LIBERTAS_CONNECTED) {
lbs_deb_thread(
"main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
"dnld_sent=%d cur_cmd=%p, confirm now\n",
@@ -758,13 +908,214 @@ static int wlan_service_main_thread(void *data)
del_timer(&adapter->command_timer);
adapter->nr_cmd_pending = 0;
wake_up_all(&adapter->cmd_pending);
- wlan_deactivate_thread(thread);
lbs_deb_leave(LBS_DEB_THREAD);
return 0;
}
/**
+ * @brief This function downloads firmware image, gets
+ * HW spec from firmware and set basic parameters to
+ * firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+static int wlan_setup_firmware(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_mesh_access mesh_access;
+
+ lbs_deb_enter(LBS_DEB_FW);
+
+ /*
+ * Read MAC address from HW
+ */
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_mac_packet_filter(priv);
+
+ /* Get the supported Data rates */
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+ CMD_ACT_GET_TX_RATE,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ /* Disable mesh autostart */
+ if (priv->mesh_dev) {
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(0);
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+ priv->mesh_autostart_enabled = 0;
+ }
+
+ /* Set the boot2 version in firmware */
+ ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ ret = 0;
+done:
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+ wlan_private *priv = (wlan_private *)data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *ptempnode;
+ struct cmd_ds_command *cmd;
+ unsigned long flags;
+
+ ptempnode = adapter->cur_cmd;
+ if (ptempnode == NULL) {
+ lbs_deb_fw("ptempnode empty\n");
+ return;
+ }
+
+ cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+ if (!cmd) {
+ lbs_deb_fw("cmd is NULL\n");
+ return;
+ }
+
+ lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
+
+ if (!adapter->fw_ready)
+ return;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_deb_fw("re-sending same command because of timeout\n");
+ libertas_queue_cmd(adapter, ptempnode, 0);
+
+ wake_up_interruptible(&priv->waitq);
+
+ return;
+}
+
+static int libertas_init_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ size_t bufsize;
+ int i, ret = 0;
+
+ /* Allocate buffer to store the BSSID list */
+ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
+ adapter->networks = kzalloc(bufsize, GFP_KERNEL);
+ if (!adapter->networks) {
+ lbs_pr_err("Out of memory allocating beacons\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Initialize scan result lists */
+ INIT_LIST_HEAD(&adapter->network_free_list);
+ INIT_LIST_HEAD(&adapter->network_list);
+ for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+ list_add_tail(&adapter->networks[i].list,
+ &adapter->network_free_list);
+ }
+
+ adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+ adapter->libertas_ps_confirm_sleep.command =
+ cpu_to_le16(CMD_802_11_PS_MODE);
+ adapter->libertas_ps_confirm_sleep.size =
+ cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.action =
+ cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
+
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ adapter->connect_status = LIBERTAS_DISCONNECTED;
+ adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+ adapter->mode = IW_MODE_INFRA;
+ adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+ adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+ adapter->radioon = RADIO_ON;
+ adapter->auto_rate = 1;
+ adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ adapter->psstate = PS_STATE_FULL_POWER;
+
+ mutex_init(&adapter->lock);
+
+ memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+ adapter->tx_queue_idx = 0;
+ spin_lock_init(&adapter->txqueue_lock);
+
+ setup_timer(&adapter->command_timer, command_timer_fn,
+ (unsigned long)priv);
+
+ INIT_LIST_HEAD(&adapter->cmdfreeq);
+ INIT_LIST_HEAD(&adapter->cmdpendingq);
+
+ spin_lock_init(&adapter->driver_lock);
+ init_waitqueue_head(&adapter->cmd_pending);
+ adapter->nr_cmd_pending = 0;
+
+ /* Allocate the command buffers */
+ if (libertas_allocate_cmd_buffer(priv)) {
+ lbs_pr_err("Out of memory allocating command buffers\n");
+ ret = -1;
+ }
+
+out:
+ return ret;
+}
+
+static void libertas_free_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!adapter) {
+ lbs_deb_fw("why double free adapter?\n");
+ return;
+ }
+
+ lbs_deb_fw("free command buffer\n");
+ libertas_free_cmd_buffer(priv);
+
+ lbs_deb_fw("free command_timer\n");
+ del_timer(&adapter->command_timer);
+
+ lbs_deb_fw("free scan results table\n");
+ kfree(adapter->networks);
+ adapter->networks = NULL;
+
+ /* Free the adapter object itself */
+ lbs_deb_fw("free adapter\n");
+ kfree(adapter);
+ priv->adapter = NULL;
+}
+
+/**
* @brief This function adds the card. it will probe the
* card, allocate the wlan_priv and initialize the device.
*
@@ -781,7 +1132,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
/* Allocate an Ethernet device and register it */
if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
lbs_pr_err("init ethX device failed\n");
- return NULL;
+ goto done;
}
priv = dev->priv;
@@ -791,20 +1142,24 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
goto err_kzalloc;
}
+ if (libertas_init_adapter(priv)) {
+ lbs_pr_err("failed to initialize adapter structure.\n");
+ goto err_init_adapter;
+ }
+
priv->dev = dev;
priv->card = card;
priv->mesh_open = 0;
priv->infra_open = 0;
-
- SET_MODULE_OWNER(dev);
+ priv->hotplug_device = dmdev;
/* Setup the OS Interface to our functions */
- dev->open = wlan_open;
- dev->hard_start_xmit = wlan_pre_start_xmit;
- dev->stop = wlan_close;
- dev->set_mac_address = wlan_set_mac_address;
- dev->tx_timeout = wlan_tx_timeout;
- dev->get_stats = wlan_get_stats;
+ dev->open = libertas_open;
+ dev->hard_start_xmit = libertas_pre_start_xmit;
+ dev->stop = libertas_close;
+ dev->set_mac_address = libertas_set_mac_address;
+ dev->tx_timeout = libertas_tx_timeout;
+ dev->get_stats = libertas_get_stats;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &libertas_ethtool_ops;
#ifdef WIRELESS_EXT
@@ -813,84 +1168,148 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
#define NETIF_F_DYNALLOC 16
dev->features |= NETIF_F_DYNALLOC;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- dev->set_multicast_list = wlan_set_multicast_list;
+ dev->set_multicast_list = libertas_set_multicast_list;
SET_NETDEV_DEV(dev, dmdev);
- INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
- INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+ priv->rtap_net_dev = NULL;
+ if (device_create_file(dmdev, &dev_attr_libertas_rtap))
+ goto err_init_adapter;
+
+ lbs_deb_thread("Starting main thread...\n");
+ init_waitqueue_head(&priv->waitq);
+ priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+ if (IS_ERR(priv->main_thread)) {
+ lbs_deb_thread("Error creating main thread.\n");
+ goto err_kthread_run;
+ }
+
+ priv->work_thread = create_singlethread_workqueue("libertas_worker");
+ INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+ INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
+ INIT_WORK(&priv->sync_channel, libertas_sync_channel);
- spin_lock_init(&priv->adapter->driver_lock);
- init_waitqueue_head(&priv->adapter->cmd_pending);
- priv->adapter->nr_cmd_pending = 0;
goto done;
+err_kthread_run:
+ device_remove_file(dmdev, &dev_attr_libertas_rtap);
+
+err_init_adapter:
+ libertas_free_adapter(priv);
+
err_kzalloc:
free_netdev(dev);
priv = NULL;
+
done:
lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
return priv;
}
EXPORT_SYMBOL_GPL(libertas_add_card);
-int libertas_activate_card(wlan_private *priv, char *fw_name)
+
+int libertas_remove_card(wlan_private *priv)
{
+ wlan_adapter *adapter = priv->adapter;
struct net_device *dev = priv->dev;
- int ret = -1;
+ union iwreq_data wrqu;
lbs_deb_enter(LBS_DEB_MAIN);
- lbs_deb_thread("Starting kthread...\n");
- priv->mainthread.priv = priv;
- wlan_create_thread(wlan_service_main_thread,
- &priv->mainthread, "wlan_main_service");
+ libertas_remove_rtap(priv);
- priv->assoc_thread =
- create_singlethread_workqueue("libertas_assoc");
- INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
- INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+ dev = priv->dev;
+ device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
- /*
- * Register the device. Fillup the private data structure with
- * relevant information from the card and request for the required
- * IRQ.
- */
- if (priv->hw_register_dev(priv) < 0) {
- lbs_pr_err("failed to register WLAN device\n");
- goto err_registerdev;
- }
+ cancel_delayed_work(&priv->scan_work);
+ cancel_delayed_work(&priv->assoc_work);
+ destroy_workqueue(priv->work_thread);
- /* init FW and HW */
- if (fw_name && libertas_init_fw(priv, fw_name)) {
- lbs_pr_err("firmware init failed\n");
- goto err_registerdev;
+ if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
+ memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+ /* Stop the thread servicing the interrupts */
+ adapter->surpriseremoved = 1;
+ kthread_stop(priv->main_thread);
+
+ libertas_free_adapter(priv);
+
+ priv->dev = NULL;
+ free_netdev(dev);
+
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(libertas_remove_card);
+
+
+int libertas_start_card(wlan_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ /* poke the firmware */
+ ret = wlan_setup_firmware(priv);
+ if (ret)
+ goto done;
+
+ /* init 802.11d */
+ libertas_init_11d(priv);
+
if (register_netdev(dev)) {
lbs_pr_err("cannot register ethX device\n");
- goto err_init_fw;
+ goto done;
}
- lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
-
libertas_debugfs_init_one(priv, dev);
+ lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+
ret = 0;
- goto done;
-err_init_fw:
- priv->hw_unregister_dev(priv);
-err_registerdev:
- destroy_workqueue(priv->assoc_thread);
- /* Stop the thread servicing the interrupts */
- wake_up_interruptible(&priv->mainthread.waitq);
- wlan_terminate_thread(&priv->mainthread);
done:
- lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
return ret;
}
-EXPORT_SYMBOL_GPL(libertas_activate_card);
+EXPORT_SYMBOL_GPL(libertas_start_card);
+
+
+int libertas_stop_card(wlan_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = -1;
+ struct cmd_ctrl_node *cmdnode;
+ unsigned long flags;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+
+ libertas_debugfs_remove_one(priv);
+
+ /* Flush pending command nodes */
+ spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+ list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+ cmdnode->cmdwaitqwoken = 1;
+ wake_up_interruptible(&cmdnode->cmdwait_q);
+ }
+ spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+
+ unregister_netdev(dev);
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_stop_card);
/**
@@ -915,13 +1334,11 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
mesh_dev->priv = priv;
priv->mesh_dev = mesh_dev;
- SET_MODULE_OWNER(mesh_dev);
-
- mesh_dev->open = mesh_open;
- mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
- mesh_dev->stop = mesh_close;
- mesh_dev->get_stats = wlan_get_stats;
- mesh_dev->set_mac_address = wlan_set_mac_address;
+ mesh_dev->open = libertas_mesh_open;
+ mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit;
+ mesh_dev->stop = libertas_mesh_close;
+ mesh_dev->get_stats = libertas_get_stats;
+ mesh_dev->set_mac_address = libertas_set_mac_address;
mesh_dev->ethtool_ops = &libertas_ethtool_ops;
memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
sizeof(priv->dev->dev_addr));
@@ -940,7 +1357,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
goto err_free;
}
- ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+ ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
if (ret)
goto err_unregister;
@@ -948,7 +1365,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
ret = 0;
goto done;
-
err_unregister:
unregister_netdev(mesh_dev);
@@ -961,86 +1377,12 @@ done:
}
EXPORT_SYMBOL_GPL(libertas_add_mesh);
-static void wake_pending_cmdnodes(wlan_private *priv)
-{
- struct cmd_ctrl_node *cmdnode;
- unsigned long flags;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- spin_lock_irqsave(&priv->adapter->driver_lock, flags);
- list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
- cmdnode->cmdwaitqwoken = 1;
- wake_up_interruptible(&cmdnode->cmdwait_q);
- }
- spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
-}
-
-
-int libertas_remove_card(wlan_private *priv)
-{
- wlan_adapter *adapter;
- struct net_device *dev;
- union iwreq_data wrqu;
-
- lbs_deb_enter(LBS_DEB_NET);
-
- if (!priv)
- goto out;
-
- adapter = priv->adapter;
-
- if (!adapter)
- goto out;
-
- dev = priv->dev;
-
- netif_stop_queue(priv->dev);
- netif_carrier_off(priv->dev);
-
- wake_pending_cmdnodes(priv);
-
- unregister_netdev(dev);
-
- cancel_delayed_work(&priv->assoc_work);
- destroy_workqueue(priv->assoc_thread);
-
- if (adapter->psmode == wlan802_11powermodemax_psp) {
- adapter->psmode = wlan802_11powermodecam;
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
- }
-
- memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
- adapter->surpriseremoved = 1;
-
- /* Stop the thread servicing the interrupts */
- wlan_terminate_thread(&priv->mainthread);
-
- libertas_debugfs_remove_one(priv);
-
- lbs_deb_net("free adapter\n");
- libertas_free_adapter(priv);
-
- lbs_deb_net("unregister finish\n");
-
- priv->dev = NULL;
- free_netdev(dev);
-
-out:
- lbs_deb_leave(LBS_DEB_NET);
- return 0;
-}
-EXPORT_SYMBOL_GPL(libertas_remove_card);
-
void libertas_remove_mesh(wlan_private *priv)
{
struct net_device *mesh_dev;
- lbs_deb_enter(LBS_DEB_NET);
+ lbs_deb_enter(LBS_DEB_MAIN);
if (!priv)
goto out;
@@ -1050,14 +1392,14 @@ void libertas_remove_mesh(wlan_private *priv)
netif_stop_queue(mesh_dev);
netif_carrier_off(priv->mesh_dev);
- device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+ sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL ;
free_netdev(mesh_dev);
out:
- lbs_deb_leave(LBS_DEB_NET);
+ lbs_deb_leave(LBS_DEB_MAIN);
}
EXPORT_SYMBOL_GPL(libertas_remove_mesh);
@@ -1076,7 +1418,7 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c
lbs_deb_enter(LBS_DEB_MAIN);
- end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+ end = ARRAY_SIZE(region_cfp_table);
for (i = 0; i < end ; i++) {
lbs_deb_main("region_cfp_table[i].region=%d\n",
@@ -1148,15 +1490,30 @@ void libertas_interrupt(struct net_device *dev)
if (priv->adapter->psstate == PS_STATE_SLEEP) {
priv->adapter->psstate = PS_STATE_AWAKE;
netif_wake_queue(dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
lbs_deb_leave(LBS_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(libertas_interrupt);
+int libertas_reset_device(wlan_private *priv)
+{
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET,
+ CMD_ACT_HALT, 0, 0, NULL);
+ msleep_interruptible(10);
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_reset_device);
+
static int libertas_init_module(void)
{
lbs_deb_enter(LBS_DEB_MAIN);
@@ -1174,6 +1531,81 @@ static void libertas_exit_module(void)
lbs_deb_leave(LBS_DEB_MAIN);
}
+/*
+ * rtap interface support fuctions
+ */
+
+static int libertas_rtap_open(struct net_device *dev)
+{
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static int libertas_rtap_stop(struct net_device *dev)
+{
+ return 0;
+}
+
+static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+}
+
+static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+ return &priv->ieee->stats;
+}
+
+
+void libertas_remove_rtap(wlan_private *priv)
+{
+ if (priv->rtap_net_dev == NULL)
+ return;
+ unregister_netdev(priv->rtap_net_dev);
+ free_ieee80211(priv->rtap_net_dev);
+ priv->rtap_net_dev = NULL;
+}
+
+int libertas_add_rtap(wlan_private *priv)
+{
+ int rc = 0;
+
+ if (priv->rtap_net_dev)
+ return -EPERM;
+
+ priv->rtap_net_dev = alloc_ieee80211(0);
+ if (priv->rtap_net_dev == NULL)
+ return -ENOMEM;
+
+
+ priv->ieee = netdev_priv(priv->rtap_net_dev);
+
+ strcpy(priv->rtap_net_dev->name, "rtap%d");
+
+ priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ priv->rtap_net_dev->open = libertas_rtap_open;
+ priv->rtap_net_dev->stop = libertas_rtap_stop;
+ priv->rtap_net_dev->get_stats = libertas_rtap_get_stats;
+ priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit;
+ priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list;
+ priv->rtap_net_dev->priv = priv;
+
+ priv->ieee->iw_mode = IW_MODE_MONITOR;
+
+ rc = register_netdev(priv->rtap_net_dev);
+ if (rc) {
+ free_ieee80211(priv->rtap_net_dev);
+ priv->rtap_net_dev = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+
+
module_init(libertas_init_module);
module_exit(libertas_exit_module);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 769c86fb9509..0420e5b9ff9b 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -85,12 +85,12 @@ static u8 wlan_getavgnf(wlan_private * priv)
static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
{
wlan_adapter *adapter = priv->adapter;
- if (adapter->numSNRNF < adapter->data_avg_factor)
+ if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
adapter->numSNRNF++;
adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
adapter->nextSNRNF++;
- if (adapter->nextSNRNF >= adapter->data_avg_factor)
+ if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
adapter->nextSNRNF = 0;
return;
}
@@ -117,8 +117,6 @@ static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
wlan_save_rawSNRNF(priv, p_rx_pd);
- adapter->rxpd_rate = p_rx_pd->rx_rate;
-
adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
@@ -140,12 +138,15 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
{
lbs_deb_rx("skb->data %p\n", skb->data);
- if (priv->mesh_dev && IS_MESH_FRAME(skb))
- skb->protocol = eth_type_trans(skb, priv->mesh_dev);
- else
- skb->protocol = eth_type_trans(skb, priv->dev);
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+ skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
+ } else {
+ if (priv->mesh_dev && IS_MESH_FRAME(skb))
+ skb->protocol = eth_type_trans(skb, priv->mesh_dev);
+ else
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ }
skb->ip_summed = CHECKSUM_UNNECESSARY;
-
netif_rx(skb);
}
@@ -172,11 +173,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
lbs_deb_enter(LBS_DEB_RX);
- if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
- lbs_dbg_hex("RX packet: ", skb->data,
- min_t(unsigned int, skb->len, 100));
-
- if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
return process_rxed_802_11_packet(priv, skb);
p_rx_pkt = (struct rxpackethdr *) skb->data;
@@ -186,7 +183,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
else
UNSET_MESH_FRAME(skb);
- lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
min_t(unsigned int, skb->len, 100));
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
@@ -210,9 +207,9 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
- lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
sizeof(p_rx_pkt->eth803_hdr.dest_addr));
- lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
sizeof(p_rx_pkt->eth803_hdr.src_addr));
if (memcmp(&p_rx_pkt->rfc1042_hdr,
@@ -244,7 +241,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
*/
hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
} else {
- lbs_dbg_hex("RX Data: LLC/SNAP",
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
(u8 *) & p_rx_pkt->rfc1042_hdr,
sizeof(p_rx_pkt->rfc1042_hdr));
@@ -260,8 +257,8 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
- if (adapter->is_datarate_auto)
- adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+ if (adapter->auto_rate)
+ adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate);
wlan_compute_rssi(priv, p_rx_pd);
@@ -296,21 +293,22 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
return 11;
case 3: /* 11 Mbps */
return 22;
- case 4: /* 6 Mbps */
+ /* case 4: reserved */
+ case 5: /* 6 Mbps */
return 12;
- case 5: /* 9 Mbps */
+ case 6: /* 9 Mbps */
return 18;
- case 6: /* 12 Mbps */
+ case 7: /* 12 Mbps */
return 24;
- case 7: /* 18 Mbps */
+ case 8: /* 18 Mbps */
return 36;
- case 8: /* 24 Mbps */
+ case 9: /* 24 Mbps */
return 48;
- case 9: /* 36 Mbps */
+ case 10: /* 36 Mbps */
return 72;
- case 10: /* 48 Mbps */
+ case 11: /* 48 Mbps */
return 96;
- case 11: /* 54 Mbps */
+ case 12: /* 54 Mbps */
return 108;
}
lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
@@ -340,7 +338,7 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
p_rx_pkt = (struct rx80211packethdr *) skb->data;
prxpd = &p_rx_pkt->rx_pd;
- // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+ // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
lbs_deb_rx("rx err: frame received wit bad length\n");
@@ -361,20 +359,19 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
/* create the exported radio header */
- switch (priv->adapter->radiomode) {
- case WLAN_RADIOMODE_NONE:
+ if(priv->adapter->monitormode == WLAN_MONITOR_OFF) {
/* no radio header */
/* chop the rxpd */
skb_pull(skb, sizeof(struct rxpd));
- break;
+ }
- case WLAN_RADIOMODE_RADIOTAP:
+ else {
/* radiotap header */
radiotap_hdr.hdr.it_version = 0;
/* XXX must check this value for pad */
radiotap_hdr.hdr.it_pad = 0;
- radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
- radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+ radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
+ radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
/* unknown values */
radiotap_hdr.flags = 0;
radiotap_hdr.chan_freq = 0;
@@ -389,8 +386,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
- // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
-
/* chop the rxpd */
skb_pull(skb, sizeof(struct rxpd));
@@ -408,25 +403,13 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
rx_radiotap_hdr));
memcpy(pradiotap_hdr, &radiotap_hdr,
sizeof(struct rx_radiotap_hdr));
- //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
- break;
-
- default:
- /* unknown header */
- lbs_pr_alert("Unknown radiomode %i\n",
- priv->adapter->radiomode);
- /* don't export any header */
- /* chop the rxpd */
- skb_pull(skb, sizeof(struct rxpd));
- break;
}
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
- if (adapter->is_datarate_auto) {
- adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
- }
+ if (adapter->auto_rate)
+ adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate);
wlan_compute_rssi(priv, prxpd);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index c3043dcb541e..ad1e67d984ce 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -13,10 +13,13 @@
#include <net/ieee80211.h>
#include <net/iw_handler.h>
+#include <asm/unaligned.h>
+
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "scan.h"
+#include "join.h"
//! Approximate amount of data needed to pass a scan result back to iwlist
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
@@ -62,6 +65,15 @@
static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+
+
+/*********************************************************************/
+/* */
+/* Misc helper functions */
+/* */
+/*********************************************************************/
+
static inline void clear_bss_descriptor (struct bss_descriptor * bss)
{
/* Don't blow away ->list, just BSS data */
@@ -74,9 +86,9 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo,
if ( !secinfo->wep_enabled
&& !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && match_bss->wpa_ie[0] != WPA_IE
- && match_bss->rsn_ie[0] != WPA2_IE
- && !match_bss->privacy) {
+ && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
+ && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+ && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
return 1;
}
return 0;
@@ -88,7 +100,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo,
if ( secinfo->wep_enabled
&& !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && match_bss->privacy) {
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
return 1;
}
return 0;
@@ -99,9 +111,10 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo,
{
if ( !secinfo->wep_enabled
&& secinfo->WPAenabled
- && (match_bss->wpa_ie[0] == WPA_IE)
+ && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && bss->privacy */
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ */
) {
return 1;
}
@@ -113,9 +126,10 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo,
{
if ( !secinfo->wep_enabled
&& secinfo->WPA2enabled
- && (match_bss->rsn_ie[0] == WPA2_IE)
+ && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && bss->privacy */
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ */
) {
return 1;
}
@@ -128,9 +142,9 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo,
if ( !secinfo->wep_enabled
&& !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && (match_bss->wpa_ie[0] != WPA_IE)
- && (match_bss->rsn_ie[0] != WPA2_IE)
- && match_bss->privacy) {
+ && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
+ && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
return 1;
}
return 0;
@@ -160,7 +174,7 @@ static int is_network_compatible(wlan_adapter * adapter,
{
int matched = 0;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter(LBS_DEB_SCAN);
if (bss->mode != mode)
goto done;
@@ -177,7 +191,7 @@ static int is_network_compatible(wlan_adapter * adapter,
adapter->secinfo.wep_enabled ? "e" : "d",
adapter->secinfo.WPAenabled ? "e" : "d",
adapter->secinfo.WPA2enabled ? "e" : "d",
- bss->privacy);
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
lbs_deb_scan(
@@ -187,15 +201,14 @@ static int is_network_compatible(wlan_adapter * adapter,
adapter->secinfo.wep_enabled ? "e" : "d",
adapter->secinfo.WPAenabled ? "e" : "d",
adapter->secinfo.WPA2enabled ? "e" : "d",
- bss->privacy);
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
lbs_deb_scan(
"is_network_compatible() dynamic WEP: "
"wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
- bss->wpa_ie[0],
- bss->rsn_ie[0],
- bss->privacy);
+ bss->wpa_ie[0], bss->rsn_ie[0],
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
}
@@ -207,16 +220,44 @@ static int is_network_compatible(wlan_adapter * adapter,
adapter->secinfo.wep_enabled ? "e" : "d",
adapter->secinfo.WPAenabled ? "e" : "d",
adapter->secinfo.WPA2enabled ? "e" : "d",
- bss->privacy);
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
done:
- lbs_deb_leave(LBS_DEB_SCAN);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
return matched;
}
/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+{
+ if (ssid1_len != ssid2_len)
+ return -1;
+
+ return memcmp(ssid1, ssid2, ssid1_len);
+}
+
+
+
+
+/*********************************************************************/
+/* */
+/* Main scanning support */
+/* */
+/*********************************************************************/
+
+
+/**
* @brief Create a channel list for the driver to scan based on region info
*
+ * Only used from wlan_scan_setup_scan_config()
+ *
* Use the driver region/band information to construct a comprehensive list
* of channels to scan. This routine is used for any scan that is not
* provided a specific channel list to scan.
@@ -244,17 +285,19 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
int nextchan;
u8 scantype;
+ lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
+
chanidx = 0;
/* Set the default scan type to the user specified type, will later
* be changed to passive on a per channel basis if restricted by
* regulatory requirements (11d or 11h)
*/
- scantype = adapter->scantype;
+ scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
if (priv->adapter->enable11d &&
- adapter->connect_status != libertas_connected) {
+ adapter->connect_status != LIBERTAS_CONNECTED) {
/* Scan all the supported chan for the first scan */
if (!adapter->universal_channel[rgnidx].valid)
continue;
@@ -286,11 +329,11 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
case BAND_G:
default:
scanchanlist[chanidx].radiotype =
- cmd_scan_radio_type_bg;
+ CMD_SCAN_RADIO_TYPE_BG;
break;
}
- if (scantype == cmd_scan_type_passive) {
+ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
scanchanlist[chanidx].maxscantime =
cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
scanchanlist[chanidx].chanscanmode.passivescan =
@@ -312,6 +355,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
}
}
+
+/* Delayed partial scan worker */
+void libertas_scan_worker(struct work_struct *work)
+{
+ wlan_private *priv = container_of(work, wlan_private, scan_work.work);
+
+ wlan_scan_networks(priv, NULL, 0);
+}
+
+
/**
* @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
*
@@ -359,7 +412,6 @@ wlan_scan_setup_scan_config(wlan_private * priv,
u8 * pfilteredscan,
u8 * pscancurrentonly)
{
- wlan_adapter *adapter = priv->adapter;
struct mrvlietypes_numprobes *pnumprobestlv;
struct mrvlietypes_ssidparamset *pssidtlv;
struct wlan_scan_cmd_config * pscancfgout = NULL;
@@ -371,6 +423,8 @@ wlan_scan_setup_scan_config(wlan_private * priv,
int channel;
int radiotype;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
if (pscancfgout == NULL)
goto out;
@@ -407,15 +461,12 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*pscancurrentonly = 0;
if (puserscanin) {
-
/* Set the bss type scan filter, use adapter setting if unset */
pscancfgout->bsstype =
- (puserscanin->bsstype ? puserscanin->bsstype : adapter->
- scanmode);
+ puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
/* Set the number of probes to send, use adapter setting if unset */
- numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
- adapter->scanprobes);
+ numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0;
/*
* Set the BSSID filter to the incoming configuration,
@@ -447,8 +498,8 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*pfilteredscan = 1;
}
} else {
- pscancfgout->bsstype = adapter->scanmode;
- numprobes = adapter->scanprobes;
+ pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
+ numprobes = 0;
}
/* If the input config or adapter has the number of Probes set, add tlv */
@@ -469,59 +520,56 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*/
*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
- if (puserscanin && puserscanin->chanlist[0].channumber) {
-
- lbs_deb_scan("Scan: Using supplied channel list\n");
+ if (!puserscanin || !puserscanin->chanlist[0].channumber) {
+ /* Create a default channel scan list */
+ lbs_deb_scan("creating full region channel list\n");
+ wlan_scan_create_channel_list(priv, pscanchanlist,
+ *pfilteredscan);
+ goto out;
+ }
- for (chanidx = 0;
- chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
- && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+ for (chanidx = 0;
+ chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+ && puserscanin->chanlist[chanidx].channumber; chanidx++) {
- channel = puserscanin->chanlist[chanidx].channumber;
- (pscanchanlist + chanidx)->channumber = channel;
+ channel = puserscanin->chanlist[chanidx].channumber;
+ (pscanchanlist + chanidx)->channumber = channel;
- radiotype = puserscanin->chanlist[chanidx].radiotype;
- (pscanchanlist + chanidx)->radiotype = radiotype;
+ radiotype = puserscanin->chanlist[chanidx].radiotype;
+ (pscanchanlist + chanidx)->radiotype = radiotype;
- scantype = puserscanin->chanlist[chanidx].scantype;
+ scantype = puserscanin->chanlist[chanidx].scantype;
- if (scantype == cmd_scan_type_passive) {
- (pscanchanlist +
- chanidx)->chanscanmode.passivescan = 1;
- } else {
- (pscanchanlist +
- chanidx)->chanscanmode.passivescan = 0;
- }
+ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 1;
+ } else {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 0;
+ }
- if (puserscanin->chanlist[chanidx].scantime) {
- scandur =
- puserscanin->chanlist[chanidx].scantime;
+ if (puserscanin->chanlist[chanidx].scantime) {
+ scandur = puserscanin->chanlist[chanidx].scantime;
+ } else {
+ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+ scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
} else {
- if (scantype == cmd_scan_type_passive) {
- scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
- } else {
- scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
- }
+ scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
}
-
- (pscanchanlist + chanidx)->minscantime =
- cpu_to_le16(scandur);
- (pscanchanlist + chanidx)->maxscantime =
- cpu_to_le16(scandur);
}
- /* Check if we are only scanning the current channel */
- if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
- ==
- priv->adapter->curbssparams.channel)) {
- *pscancurrentonly = 1;
- lbs_deb_scan("Scan: Scanning current channel only");
- }
+ (pscanchanlist + chanidx)->minscantime =
+ cpu_to_le16(scandur);
+ (pscanchanlist + chanidx)->maxscantime =
+ cpu_to_le16(scandur);
+ }
- } else {
- lbs_deb_scan("Scan: Creating full region channel list\n");
- wlan_scan_create_channel_list(priv, pscanchanlist,
- *pfilteredscan);
+ /* Check if we are only scanning the current channel */
+ if ((chanidx == 1) &&
+ (puserscanin->chanlist[0].channumber ==
+ priv->adapter->curbssparams.channel)) {
+ *pscancurrentonly = 1;
+ lbs_deb_scan("scanning current channel only");
}
out:
@@ -531,6 +579,8 @@ out:
/**
* @brief Construct and send multiple scan config commands to the firmware
*
+ * Only used from wlan_scan_networks()
+ *
* Previous routines have created a wlan_scan_cmd_config with any requested
* TLVs. This function splits the channel TLV into maxchanperscan lists
* and sends the portion of the channel TLV along with the other TLVs
@@ -568,12 +618,14 @@ static int wlan_scan_channel_list(wlan_private * priv,
int scanned = 0;
union iwreq_data wrqu;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
+ "full_scan %d", maxchanperscan, filteredscan, full_scan);
- if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
- lbs_deb_scan("Scan: Null detect: %p, %p, %p\n",
- pscancfgout, pchantlvout, pscanchanlist);
- return -1;
+ if (!pscancfgout || !pchantlvout || !pscanchanlist) {
+ lbs_deb_scan("pscancfgout, pchantlvout or "
+ "pscanchanlist is NULL\n");
+ ret = -1;
+ goto out;
}
pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
@@ -605,12 +657,13 @@ static int wlan_scan_channel_list(wlan_private * priv,
while (tlvidx < maxchanperscan && ptmpchan->channumber
&& !doneearly && scanned < 2) {
- lbs_deb_scan(
- "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
- ptmpchan->channumber, ptmpchan->radiotype,
- ptmpchan->chanscanmode.passivescan,
- ptmpchan->chanscanmode.disablechanfilt,
- ptmpchan->maxscantime);
+ lbs_deb_scan("channel %d, radio %d, passive %d, "
+ "dischanflt %d, maxscantime %d\n",
+ ptmpchan->channumber,
+ ptmpchan->radiotype,
+ ptmpchan->chanscanmode.passivescan,
+ ptmpchan->chanscanmode.disablechanfilt,
+ ptmpchan->maxscantime);
/* Copy the current channel TLV to the command being prepared */
memcpy(pchantlvout->chanscanparam + tlvidx,
@@ -667,7 +720,7 @@ static int wlan_scan_channel_list(wlan_private * priv,
}
/* Send the scan command to the firmware with the specified cfg */
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
0, 0, pscancfgout);
if (scanned >= 2 && !full_scan) {
ret = 0;
@@ -679,24 +732,38 @@ static int wlan_scan_channel_list(wlan_private * priv,
done:
priv->adapter->last_scanned_channel = ptmpchan->channumber;
- /* Tell userspace the scan table has been updated */
- memset(&wrqu, 0, sizeof(union iwreq_data));
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+ if (priv->adapter->last_scanned_channel) {
+ /* Schedule the next part of the partial scan */
+ if (!full_scan && !priv->adapter->surpriseremoved) {
+ cancel_delayed_work(&priv->scan_work);
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(300));
+ }
+ } else {
+ /* All done, tell userspace the scan table has been updated */
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+out:
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret;
}
-static void
-clear_selected_scan_list_entries(wlan_adapter * adapter,
- const struct wlan_ioctl_user_scan_cfg * scan_cfg)
+/*
+ * Only used from wlan_scan_networks()
+*/
+static void clear_selected_scan_list_entries(wlan_adapter *adapter,
+ const struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
- struct bss_descriptor * bss;
- struct bss_descriptor * safe;
+ struct bss_descriptor *bss;
+ struct bss_descriptor *safe;
u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
if (!scan_cfg)
- return;
+ goto out;
if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
clear_ssid_flag = 1;
@@ -708,7 +775,7 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
}
if (!clear_ssid_flag && !clear_bssid_flag)
- return;
+ goto out;
mutex_lock(&adapter->lock);
list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
@@ -731,12 +798,16 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
}
}
mutex_unlock(&adapter->lock);
+out:
+ lbs_deb_leave(LBS_DEB_SCAN);
}
/**
* @brief Internal function used to start a scan based on an input config
*
+ * Also used from debugfs
+ *
* Use the input user scan configuration information when provided in
* order to send the appropriate scan commands to firmware to populate or
* update the internal driver scan table
@@ -744,12 +815,13 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
* @param priv A pointer to wlan_private structure
* @param puserscanin Pointer to the input configuration for the requested
* scan.
+ * @param full_scan ???
*
* @return 0 or < 0 if error
*/
int wlan_scan_networks(wlan_private * priv,
- const struct wlan_ioctl_user_scan_cfg * puserscanin,
- int full_scan)
+ const struct wlan_ioctl_user_scan_cfg * puserscanin,
+ int full_scan)
{
wlan_adapter * adapter = priv->adapter;
struct mrvlietypes_chanlistparamset *pchantlvout;
@@ -762,9 +834,16 @@ int wlan_scan_networks(wlan_private * priv,
#ifdef CONFIG_LIBERTAS_DEBUG
struct bss_descriptor * iter_bss;
int i = 0;
+ DECLARE_MAC_BUF(mac);
#endif
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
+
+ /* Cancel any partial outstanding partial scans if this scan
+ * is a full scan.
+ */
+ if (full_scan && delayed_work_pending(&priv->scan_work))
+ cancel_delayed_work(&priv->scan_work);
scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
@@ -791,8 +870,10 @@ int wlan_scan_networks(wlan_private * priv,
if (!scancurrentchanonly) {
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
- netif_stop_queue(priv->mesh_dev);
- netif_carrier_off(priv->mesh_dev);
+ if (priv->mesh_dev) {
+ netif_stop_queue(priv->mesh_dev);
+ netif_carrier_off(priv->mesh_dev);
+ }
}
ret = wlan_scan_channel_list(priv,
@@ -807,19 +888,22 @@ int wlan_scan_networks(wlan_private * priv,
#ifdef CONFIG_LIBERTAS_DEBUG
/* Dump the scan table */
mutex_lock(&adapter->lock);
+ lbs_deb_scan("The scan table contains:\n");
list_for_each_entry (iter_bss, &adapter->network_list, list) {
- lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n",
- i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi,
+ lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
+ i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
escape_essid(iter_bss->ssid, iter_bss->ssid_len));
}
mutex_unlock(&adapter->lock);
#endif
- if (priv->adapter->connect_status == libertas_connected) {
+ if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev) {
+ netif_carrier_on(priv->mesh_dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
}
out:
@@ -834,58 +918,6 @@ out:
}
/**
- * @brief Inspect the scan response buffer for pointers to expected TLVs
- *
- * TLVs can be included at the end of the scan response BSS information.
- * Parse the data in the buffer for pointers to TLVs that can potentially
- * be passed back in the response
- *
- * @param ptlv Pointer to the start of the TLV buffer to parse
- * @param tlvbufsize size of the TLV buffer
- * @param ptsftlv Output parameter: Pointer to the TSF TLV if found
- *
- * @return void
- */
-static
-void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
- int tlvbufsize,
- struct mrvlietypes_tsftimestamp ** ptsftlv)
-{
- struct mrvlietypes_data *pcurrenttlv;
- int tlvbufleft;
- u16 tlvtype;
- u16 tlvlen;
-
- pcurrenttlv = ptlv;
- tlvbufleft = tlvbufsize;
- *ptsftlv = NULL;
-
- lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
- lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
-
- while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
- tlvtype = le16_to_cpu(pcurrenttlv->header.type);
- tlvlen = le16_to_cpu(pcurrenttlv->header.len);
-
- switch (tlvtype) {
- case TLV_TYPE_TSFTIMESTAMP:
- *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
- break;
-
- default:
- lbs_deb_scan("SCAN_RESP: Unhandled TLV = %d\n",
- tlvtype);
- /* Give up, this seems corrupted */
- return;
- } /* switch */
-
- tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
- pcurrenttlv =
- (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
- } /* while */
-}
-
-/**
* @brief Interpret a BSS scan response returned from the firmware
*
* Parse the various fixed fields and IEs passed back for a a BSS probe
@@ -899,67 +931,49 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
static int libertas_process_bss(struct bss_descriptor * bss,
u8 ** pbeaconinfo, int *bytesleft)
{
- enum ieeetypes_elementid elemID;
struct ieeetypes_fhparamset *pFH;
struct ieeetypes_dsparamset *pDS;
struct ieeetypes_cfparamset *pCF;
struct ieeetypes_ibssparamset *pibss;
- struct ieeetypes_capinfo *pcap;
- struct WLAN_802_11_FIXED_IEs fixedie;
- u8 *pcurrentptr;
- u8 *pRate;
- u8 elemlen;
- u8 bytestocopy;
- u8 ratesize;
- u16 beaconsize;
- u8 founddatarateie;
- int bytesleftforcurrentbeacon;
- int ret;
-
- struct IE_WPA *pIe;
- const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
-
+ DECLARE_MAC_BUF(mac);
struct ieeetypes_countryinfoset *pcountryinfo;
+ u8 *pos, *end, *p;
+ u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
+ u16 beaconsize = 0;
+ int ret;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- founddatarateie = 0;
- ratesize = 0;
- beaconsize = 0;
+ lbs_deb_enter(LBS_DEB_SCAN);
if (*bytesleft >= sizeof(beaconsize)) {
/* Extract & convert beacon size from the command buffer */
- beaconsize = le16_to_cpup((void *)*pbeaconinfo);
+ beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo));
*bytesleft -= sizeof(beaconsize);
*pbeaconinfo += sizeof(beaconsize);
}
if (beaconsize == 0 || beaconsize > *bytesleft) {
-
*pbeaconinfo += *bytesleft;
*bytesleft = 0;
-
- return -1;
+ ret = -1;
+ goto done;
}
/* Initialize the current working beacon pointer for this BSS iteration */
- pcurrentptr = *pbeaconinfo;
+ pos = *pbeaconinfo;
+ end = pos + beaconsize;
/* Advance the return beacon pointer past the current beacon */
*pbeaconinfo += beaconsize;
*bytesleft -= beaconsize;
- bytesleftforcurrentbeacon = beaconsize;
-
- memcpy(bss->bssid, pcurrentptr, ETH_ALEN);
- lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid));
+ memcpy(bss->bssid, pos, ETH_ALEN);
+ lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
+ pos += ETH_ALEN;
- pcurrentptr += ETH_ALEN;
- bytesleftforcurrentbeacon -= ETH_ALEN;
-
- if (bytesleftforcurrentbeacon < 12) {
+ if ((end - pos) < 12) {
lbs_deb_scan("process_bss: Not enough bytes left\n");
- return -1;
+ ret = -1;
+ goto done;
}
/*
@@ -968,85 +982,61 @@ static int libertas_process_bss(struct bss_descriptor * bss,
*/
/* RSSI is 1 byte long */
- bss->rssi = *pcurrentptr;
- lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr);
- pcurrentptr += 1;
- bytesleftforcurrentbeacon -= 1;
+ bss->rssi = *pos;
+ lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
+ pos++;
/* time stamp is 8 bytes long */
- fixedie.timestamp = bss->timestamp = le64_to_cpup((void *)pcurrentptr);
- pcurrentptr += 8;
- bytesleftforcurrentbeacon -= 8;
+ pos += 8;
/* beacon interval is 2 bytes long */
- fixedie.beaconinterval = bss->beaconperiod = le16_to_cpup((void *)pcurrentptr);
- pcurrentptr += 2;
- bytesleftforcurrentbeacon -= 2;
+ bss->beaconperiod = le16_to_cpup((void *) pos);
+ pos += 2;
/* capability information is 2 bytes long */
- memcpy(&fixedie.capabilities, pcurrentptr, 2);
- lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n",
- fixedie.capabilities);
- pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
- memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo));
- pcurrentptr += 2;
- bytesleftforcurrentbeacon -= 2;
-
- /* rest of the current buffer are IE's */
- lbs_deb_scan("process_bss: IE length for this AP = %d\n",
- bytesleftforcurrentbeacon);
+ bss->capability = le16_to_cpup((void *) pos);
+ lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
+ pos += 2;
- lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr,
- bytesleftforcurrentbeacon);
-
- if (pcap->privacy) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
lbs_deb_scan("process_bss: AP WEP enabled\n");
- bss->privacy = wlan802_11privfilter8021xWEP;
- } else {
- bss->privacy = wlan802_11privfilteracceptall;
- }
-
- if (pcap->ibss == 1) {
+ if (bss->capability & WLAN_CAPABILITY_IBSS)
bss->mode = IW_MODE_ADHOC;
- } else {
+ else
bss->mode = IW_MODE_INFRA;
- }
+
+ /* rest of the current buffer are IE's */
+ lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
/* process variable IE */
- while (bytesleftforcurrentbeacon >= 2) {
- elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
- elemlen = *((u8 *) pcurrentptr + 1);
+ while (pos <= end - 2) {
+ struct ieee80211_info_element * elem =
+ (struct ieee80211_info_element *) pos;
- if (bytesleftforcurrentbeacon < elemlen) {
+ if (pos + elem->len > end) {
lbs_deb_scan("process_bss: error in processing IE, "
"bytes left < IE length\n");
- bytesleftforcurrentbeacon = 0;
- continue;
+ break;
}
- switch (elemID) {
- case SSID:
- bss->ssid_len = elemlen;
- memcpy(bss->ssid, (pcurrentptr + 2), elemlen);
+ switch (elem->id) {
+ case MFIE_TYPE_SSID:
+ bss->ssid_len = elem->len;
+ memcpy(bss->ssid, elem->data, elem->len);
lbs_deb_scan("ssid '%s', ssid length %u\n",
escape_essid(bss->ssid, bss->ssid_len),
bss->ssid_len);
break;
- case SUPPORTED_RATES:
- memcpy(bss->datarates, (pcurrentptr + 2), elemlen);
- memmove(bss->libertas_supported_rates, (pcurrentptr + 2),
- elemlen);
- ratesize = elemlen;
- founddatarateie = 1;
+ case MFIE_TYPE_RATES:
+ n_basic_rates = min_t(u8, MAX_RATES, elem->len);
+ memcpy(bss->rates, elem->data, n_basic_rates);
+ got_basic_rates = 1;
break;
- case EXTRA_IE:
- lbs_deb_scan("process_bss: EXTRA_IE Found!\n");
- break;
-
- case FH_PARAM_SET:
- pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+ case MFIE_TYPE_FH_SET:
+ pFH = (struct ieeetypes_fhparamset *) pos;
memmove(&bss->phyparamset.fhparamset, pFH,
sizeof(struct ieeetypes_fhparamset));
#if 0 /* I think we can store these LE */
@@ -1055,21 +1045,21 @@ static int libertas_process_bss(struct bss_descriptor * bss,
#endif
break;
- case DS_PARAM_SET:
- pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+ case MFIE_TYPE_DS_SET:
+ pDS = (struct ieeetypes_dsparamset *) pos;
bss->channel = pDS->currentchan;
memcpy(&bss->phyparamset.dsparamset, pDS,
sizeof(struct ieeetypes_dsparamset));
break;
- case CF_PARAM_SET:
- pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+ case MFIE_TYPE_CF_SET:
+ pCF = (struct ieeetypes_cfparamset *) pos;
memcpy(&bss->ssparamset.cfparamset, pCF,
sizeof(struct ieeetypes_cfparamset));
break;
- case IBSS_PARAM_SET:
- pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+ case MFIE_TYPE_IBSS_SET:
+ pibss = (struct ieeetypes_ibssparamset *) pos;
bss->atimwindow = le32_to_cpu(pibss->atimwindow);
memmove(&bss->ssparamset.ibssparamset, pibss,
sizeof(struct ieeetypes_ibssparamset));
@@ -1079,9 +1069,8 @@ static int libertas_process_bss(struct bss_descriptor * bss,
#endif
break;
- /* Handle Country Info IE */
- case COUNTRY_INFO:
- pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr;
+ case MFIE_TYPE_COUNTRY:
+ pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
|| pcountryinfo->len > 254) {
lbs_deb_scan("process_bss: 11D- Err "
@@ -1094,70 +1083,63 @@ static int libertas_process_bss(struct bss_descriptor * bss,
memcpy(&bss->countryinfo,
pcountryinfo, pcountryinfo->len + 2);
- lbs_dbg_hex("process_bss: 11D- CountryInfo:",
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
(u8 *) pcountryinfo,
(u32) (pcountryinfo->len + 2));
break;
- case EXTENDED_SUPPORTED_RATES:
- /*
- * only process extended supported rate
- * if data rate is already found.
- * data rate IE should come before
+ case MFIE_TYPE_RATES_EX:
+ /* only process extended supported rate if data rate is
+ * already found. Data rate IE should come before
* extended supported rate IE
*/
- if (founddatarateie) {
- if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
- bytestocopy =
- (WLAN_SUPPORTED_RATES - ratesize);
- } else {
- bytestocopy = elemlen;
- }
-
- pRate = (u8 *) bss->datarates;
- pRate += ratesize;
- memmove(pRate, (pcurrentptr + 2), bytestocopy);
- pRate = (u8 *) bss->libertas_supported_rates;
- pRate += ratesize;
- memmove(pRate, (pcurrentptr + 2), bytestocopy);
- }
- break;
-
- case VENDOR_SPECIFIC_221:
-#define IE_ID_LEN_FIELDS_BYTES 2
- pIe = (struct IE_WPA *)pcurrentptr;
-
- if (memcmp(pIe->oui, oui01, sizeof(oui01)))
+ if (!got_basic_rates)
break;
- bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
- MAX_WPA_IE_LEN);
- memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len);
- lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen);
+ n_ex_rates = elem->len;
+ if (n_basic_rates + n_ex_rates > MAX_RATES)
+ n_ex_rates = MAX_RATES - n_basic_rates;
+
+ p = bss->rates + n_basic_rates;
+ memcpy(p, elem->data, n_ex_rates);
break;
- case WPA2_IE:
- pIe = (struct IE_WPA *)pcurrentptr;
- bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
- MAX_WPA_IE_LEN);
- memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len);
- lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen);
+
+ case MFIE_TYPE_GENERIC:
+ if (elem->len >= 4 &&
+ elem->data[0] == 0x00 &&
+ elem->data[1] == 0x50 &&
+ elem->data[2] == 0xf2 &&
+ elem->data[3] == 0x01) {
+ bss->wpa_ie_len = min(elem->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
+ elem->len);
+ } else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
+ elem->data[0] == 0x00 &&
+ elem->data[1] == 0x50 &&
+ elem->data[2] == 0x43 &&
+ elem->data[3] == 0x04) {
+ bss->mesh = 1;
+ }
break;
- case TIM:
+
+ case MFIE_TYPE_RSN:
+ bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
+ memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
break;
- case CHALLENGE_TEXT:
+ default:
break;
}
- pcurrentptr += elemlen + 2;
-
- /* need to account for IE ID and IE len */
- bytesleftforcurrentbeacon -= (elemlen + 2);
-
- } /* while (bytesleftforcurrentbeacon > 2) */
+ pos += elem->len + 2;
+ }
/* Timestamp */
bss->last_scanned = jiffies;
+ libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
ret = 0;
@@ -1167,40 +1149,28 @@ done:
}
/**
- * @brief Compare two SSIDs
- *
- * @param ssid1 A pointer to ssid to compare
- * @param ssid2 A pointer to ssid to compare
- *
- * @return 0--ssid is same, otherwise is different
- */
-int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
-{
- if (ssid1_len != ssid2_len)
- return -1;
-
- return memcmp(ssid1, ssid2, ssid1_len);
-}
-
-/**
* @brief This function finds a specific compatible BSSID in the scan list
*
+ * Used in association code
+ *
* @param adapter A pointer to wlan_adapter
* @param bssid BSSID to find in the scan list
* @param mode Network mode: Infrastructure or IBSS
*
* @return index in BSSID list, or error return code (< 0)
*/
-struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter,
u8 * bssid, u8 mode)
{
struct bss_descriptor * iter_bss;
struct bss_descriptor * found_bss = NULL;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
if (!bssid)
- return NULL;
+ goto out;
- lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ",
+ lbs_deb_hex(LBS_DEB_SCAN, "looking for",
bssid, ETH_ALEN);
/* Look through the scan table for a compatible match. The loop will
@@ -1225,12 +1195,16 @@ struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
}
mutex_unlock(&adapter->lock);
+out:
+ lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
return found_bss;
}
/**
* @brief This function finds ssid in ssid list.
*
+ * Used in association code
+ *
* @param adapter A pointer to wlan_adapter
* @param ssid SSID to find in the list
* @param bssid BSSID to qualify the SSID selection (if provided)
@@ -1247,6 +1221,8 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
struct bss_descriptor * found_bss = NULL;
struct bss_descriptor * tmp_oldest = NULL;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
mutex_lock(&adapter->lock);
list_for_each_entry (iter_bss, &adapter->network_list, list) {
@@ -1291,6 +1267,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
out:
mutex_unlock(&adapter->lock);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
return found_bss;
}
@@ -1304,13 +1281,15 @@ out:
*
* @return index in BSSID list
*/
-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
+static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
u8 mode)
{
u8 bestrssi = 0;
struct bss_descriptor * iter_bss;
struct bss_descriptor * best_bss = NULL;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
mutex_lock(&adapter->lock);
list_for_each_entry (iter_bss, &adapter->network_list, list) {
@@ -1335,12 +1314,15 @@ struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
}
mutex_unlock(&adapter->lock);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
return best_bss;
}
/**
* @brief Find the AP with specific ssid in the scan list
*
+ * Used from association worker.
+ *
* @param priv A pointer to wlan_private structure
* @param pSSID A pointer to AP's ssid
*
@@ -1353,11 +1335,11 @@ int libertas_find_best_network_ssid(wlan_private * priv,
int ret = -1;
struct bss_descriptor * found;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter(LBS_DEB_SCAN);
wlan_scan_networks(priv, NULL, 1);
if (adapter->surpriseremoved)
- return -1;
+ goto out;
wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
@@ -1369,6 +1351,7 @@ int libertas_find_best_network_ssid(wlan_private * priv,
ret = 0;
}
+out:
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret;
}
@@ -1391,7 +1374,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_SCAN);
- wlan_scan_networks(priv, NULL, 0);
+ if (!delayed_work_pending(&priv->scan_work)) {
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(50));
+ }
if (adapter->surpriseremoved)
return -1;
@@ -1400,10 +1386,17 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
return 0;
}
+
/**
* @brief Send a scan command for all available channels filtered on a spec
*
+ * Used in association code and from debugfs
+ *
* @param priv A pointer to wlan_private structure
+ * @param ssid A pointer to the SSID to scan for
+ * @param ssid_len Length of the SSID
+ * @param clear_ssid Should existing scan results with this SSID
+ * be cleared?
* @param prequestedssid A pointer to AP's ssid
* @param keeppreviousscan Flag used to save/clear scan table before scan
*
@@ -1416,7 +1409,8 @@ int libertas_send_specific_ssid_scan(wlan_private * priv,
struct wlan_ioctl_user_scan_cfg scancfg;
int ret = 0;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d",
+ escape_essid(ssid, ssid_len), clear_ssid);
if (!ssid_len)
goto out;
@@ -1427,47 +1421,27 @@ int libertas_send_specific_ssid_scan(wlan_private * priv,
scancfg.clear_ssid = clear_ssid;
wlan_scan_networks(priv, &scancfg, 1);
- if (adapter->surpriseremoved)
- return -1;
+ if (adapter->surpriseremoved) {
+ ret = -1;
+ goto out;
+ }
wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
out:
- lbs_deb_leave(LBS_DEB_ASSOC);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret;
}
-/**
- * @brief scan an AP with specific BSSID
- *
- * @param priv A pointer to wlan_private structure
- * @param bssid A pointer to AP's bssid
- * @param keeppreviousscan Flag used to save/clear scan table before scan
- *
- * @return 0-success, otherwise fail
- */
-int libertas_send_specific_bssid_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid)
-{
- struct wlan_ioctl_user_scan_cfg scancfg;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
- if (bssid == NULL)
- goto out;
- memset(&scancfg, 0x00, sizeof(scancfg));
- memcpy(scancfg.bssid, bssid, ETH_ALEN);
- scancfg.clear_bssid = clear_bssid;
- wlan_scan_networks(priv, &scancfg, 1);
- if (priv->adapter->surpriseremoved)
- return -1;
- wait_event_interruptible(priv->adapter->cmd_pending,
- !priv->adapter->nr_cmd_pending);
+/*********************************************************************/
+/* */
+/* Support for Wireless Extensions */
+/* */
+/*********************************************************************/
-out:
- lbs_deb_leave(LBS_DEB_ASSOC);
- return 0;
-}
+#define MAX_CUSTOM_LEN 64
static inline char *libertas_translate_scan(wlan_private *priv,
char *start, char *stop,
@@ -1483,10 +1457,13 @@ static inline char *libertas_translate_scan(wlan_private *priv,
#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
u8 rssi;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel);
if (!cfp) {
lbs_deb_scan("Invalid channel number %d\n", bss->channel);
- return NULL;
+ start = NULL;
+ goto out;
}
/* First entry *MUST* be the AP BSSID */
@@ -1550,7 +1527,7 @@ static inline char *libertas_translate_scan(wlan_private *priv,
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
- if (bss->privacy) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
} else {
iwe.u.data.flags = IW_ENCODE_DISABLED;
@@ -1565,12 +1542,9 @@ static inline char *libertas_translate_scan(wlan_private *priv,
iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = 0;
- for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) {
- u8 rate = bss->libertas_supported_rates[j];
- if (rate == 0)
- break; /* no more rates */
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = (rate & 0x7f) * 500000;
+ for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+ /* Bit rate given in 500 kb/s units */
+ iwe.u.bitrate.value = bss->rates[j] * 500000;
current_val = iwe_stream_add_value(start, current_val,
stop, &iwe, IW_EV_PARAM_LEN);
}
@@ -1605,11 +1579,25 @@ static inline char *libertas_translate_scan(wlan_private *priv,
start = iwe_stream_add_point(start, stop, &iwe, buf);
}
+ if (bss->mesh) {
+ char custom[MAX_CUSTOM_LEN];
+ char *p = custom;
+
+ iwe.cmd = IWEVCUSTOM;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ "mesh-type: olpc");
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(start, stop, &iwe, custom);
+ }
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
return start;
}
/**
- * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ * @brief Handle Retrieve scan table ioctl
*
* @param dev A pointer to net_device structure
* @param info A pointer to iw_request_info structure
@@ -1630,16 +1618,12 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
struct bss_descriptor * iter_bss;
struct bss_descriptor * safe;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* If we've got an uncompleted scan, schedule the next part */
- if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
- wlan_scan_networks(priv, NULL, 0);
+ lbs_deb_enter(LBS_DEB_SCAN);
/* Update RSSI if current BSS is a locally created ad-hoc BSS */
if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
- libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
- cmd_option_waitforrsp, 0, NULL);
+ libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
}
mutex_lock(&adapter->lock);
@@ -1652,6 +1636,10 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
break;
}
+ /* For mesh device, list only mesh networks */
+ if (dev == priv->mesh_dev && !iter_bss->mesh)
+ continue;
+
/* Prune old an old scan result */
stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
if (time_after(jiffies, stale_time)) {
@@ -1672,19 +1660,27 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
dwrq->length = (ev - extra);
dwrq->flags = 0;
- lbs_deb_leave(LBS_DEB_ASSOC);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err);
return err;
}
+
+
+
+/*********************************************************************/
+/* */
+/* Command execution */
+/* */
+/*********************************************************************/
+
+
/**
* @brief Prepare a scan command to be sent to the firmware
*
- * Use the wlan_scan_cmd_config sent to the command processing module in
- * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
- * struct to send to firmware.
+ * Called from libertas_prepare_and_send_command() in cmd.c
*
- * The fixed fields specifying the BSS type and BSSID filters as well as a
- * variable number/length of TLVs are sent in the command to firmware.
+ * Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
+ * as well as a variable number/length of TLVs to the firmware.
*
* @param priv A pointer to wlan_private structure
* @param cmd A pointer to cmd_ds_command structure to be sent to
@@ -1693,36 +1689,31 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
* to set the fields/TLVs for the command sent to firmware
*
* @return 0 or -1
- *
- * @sa wlan_scan_create_channel_list
*/
int libertas_cmd_80211_scan(wlan_private * priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
- struct wlan_scan_cmd_config *pscancfg;
+ struct wlan_scan_cmd_config *pscancfg = pdata_buf;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- pscancfg = pdata_buf;
+ lbs_deb_enter(LBS_DEB_SCAN);
/* Set fixed field variables in scan command */
pscan->bsstype = pscancfg->bsstype;
- memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID));
+ memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
- cmd->command = cpu_to_le16(cmd_802_11_scan);
+ cmd->command = cpu_to_le16(CMD_802_11_SCAN);
/* size is equal to the sizeof(fixed portions) + the TLV len + header */
- cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
- + sizeof(pscan->BSSID)
- + pscancfg->tlvbufferlen + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
+ + pscancfg->tlvbufferlen + S_DS_GEN);
- lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+ lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
le16_to_cpu(cmd->seqnum));
- lbs_deb_leave(LBS_DEB_ASSOC);
+ lbs_deb_leave(LBS_DEB_SCAN);
return 0;
}
@@ -1741,6 +1732,8 @@ static inline int is_same_network(struct bss_descriptor *src,
/**
* @brief This function handles the command response of scan
*
+ * Called from handle_cmd_response() in cmdrespc.
+ *
* The response buffer for the scan command has the following
* memory layout:
*
@@ -1766,8 +1759,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
{
wlan_adapter *adapter = priv->adapter;
struct cmd_ds_802_11_scan_rsp *pscan;
- struct mrvlietypes_data *ptlv;
- struct mrvlietypes_tsftimestamp *ptsftlv;
struct bss_descriptor * iter_bss;
struct bss_descriptor * safe;
u8 *pbssinfo;
@@ -1777,7 +1768,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
int tlvbufsize;
int ret;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter(LBS_DEB_SCAN);
/* Prune old entries from scan table */
list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
@@ -1798,10 +1789,10 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
goto done;
}
- bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+ bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize));
lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
- scanrespsize = le16_to_cpu(resp->size);
+ scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
pscan->nr_sets);
@@ -1816,11 +1807,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+ sizeof(pscan->nr_sets)
+ S_DS_GEN);
- ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
-
- /* Search the TLV buffer space in the scan response for any valid TLVs */
- wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
-
/*
* Process each scan response returned (pscan->nr_sets). Save
* the information in the newbssentry and then insert into the
@@ -1831,6 +1817,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
struct bss_descriptor new;
struct bss_descriptor * found = NULL;
struct bss_descriptor * oldest = NULL;
+ DECLARE_MAC_BUF(mac);
/* Process the data fields and IEs returned for this BSS */
memset(&new, 0, sizeof (struct bss_descriptor));
@@ -1869,19 +1856,8 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
continue;
}
- lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n",
- new.bssid[0], new.bssid[1], new.bssid[2],
- new.bssid[3], new.bssid[4], new.bssid[5]);
-
- /*
- * If the TSF TLV was appended to the scan results, save the
- * this entries TSF value in the networktsf field. The
- * networktsf is the firmware's TSF value at the time the
- * beacon or probe response was received.
- */
- if (ptsftlv) {
- new.networktsf = le64_to_cpup(&ptsftlv->tsftable[idx]);
- }
+ lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
+ print_mac(mac, new.bssid));
/* Copy the locally created newbssentry to the scan table */
memcpy(found, &new, offsetof(struct bss_descriptor, list));
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index bd019e5ff1eb..c29c031bef8c 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -140,8 +140,7 @@ struct bss_descriptor {
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
- /* WEP encryption requirement */
- u32 privacy;
+ u16 capability;
/* receive signal strength in dBm */
long rssi;
@@ -152,18 +151,16 @@ struct bss_descriptor {
u32 atimwindow;
+ /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
u8 mode;
- u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
- __le64 timestamp; //!< TSF value included in the beacon/probe response
+ /* zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+
unsigned long last_scanned;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
- struct ieeetypes_capinfo cap;
- u8 datarates[WLAN_SUPPORTED_RATES];
-
- u64 networktsf; //!< TSF timestamp from the current firmware TSF
struct ieeetypes_countryinfofullset countryinfo;
@@ -172,34 +169,31 @@ struct bss_descriptor {
u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len;
+ u8 mesh;
+
struct list_head list;
};
-extern int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
int channel);
-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
- u8 mode);
-
-extern struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
u8 * bssid, u8 mode);
int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid,
u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
-extern int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
+int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
u8 ssid_len, u8 clear_ssid);
-extern int libertas_send_specific_bssid_scan(wlan_private * priv,
- u8 * bssid, u8 clear_bssid);
-extern int libertas_cmd_80211_scan(wlan_private * priv,
+int libertas_cmd_80211_scan(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_ret_80211_scan(wlan_private * priv,
+int libertas_ret_80211_scan(wlan_private * priv,
struct cmd_ds_command *resp);
int wlan_scan_networks(wlan_private * priv,
@@ -211,9 +205,11 @@ struct ifreq;
struct iw_point;
struct iw_param;
struct iw_request_info;
-extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra);
-extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra);
+void libertas_scan_worker(struct work_struct *work);
+
#endif /* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
deleted file mode 100644
index b1f34d92ff3e..000000000000
--- a/drivers/net/wireless/libertas/thread.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef __WLAN_THREAD_H_
-#define __WLAN_THREAD_H_
-
-#include <linux/kthread.h>
-
-struct wlan_thread {
- struct task_struct *task;
- wait_queue_head_t waitq;
- pid_t pid;
- void *priv;
-};
-
-static inline void wlan_activate_thread(struct wlan_thread * thr)
-{
- /** Record the thread pid */
- thr->pid = current->pid;
-
- /** Initialize the wait queue */
- init_waitqueue_head(&thr->waitq);
-}
-
-static inline void wlan_deactivate_thread(struct wlan_thread * thr)
-{
- lbs_deb_enter(LBS_DEB_THREAD);
-
- thr->pid = 0;
-
- lbs_deb_leave(LBS_DEB_THREAD);
-}
-
-static inline void wlan_create_thread(int (*wlanfunc) (void *),
- struct wlan_thread * thr, char *name)
-{
- thr->task = kthread_run(wlanfunc, thr, "%s", name);
-}
-
-static inline int wlan_terminate_thread(struct wlan_thread * thr)
-{
- lbs_deb_enter(LBS_DEB_THREAD);
-
- /* Check if the thread is active or not */
- if (!thr->pid) {
- printk(KERN_ERR "Thread does not exist\n");
- return -1;
- }
- kthread_stop(thr->task);
-
- lbs_deb_leave(LBS_DEB_THREAD);
- return 0;
-}
-
-#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 17c437635a00..fbec06c10dd7 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -58,7 +58,6 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
*/
static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
{
- wlan_adapter *adapter = priv->adapter;
int ret = 0;
struct txpd localtxpd;
struct txpd *plocaltxpd = &localtxpd;
@@ -72,10 +71,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
if (priv->adapter->surpriseremoved)
return -1;
- if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
- lbs_dbg_hex("TX packet: ", skb->data,
- min_t(unsigned int, skb->len, 100));
-
if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
@@ -90,11 +85,8 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
/* offset of actual data */
plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
- /* TxCtrl set by user or default */
- plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl);
-
p802x_hdr = skb->data;
- if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
/* locate radiotap header */
pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
@@ -103,7 +95,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
if (new_rate != 0) {
/* use new tx_control[4:0] */
- new_rate |= (adapter->pkttxctrl & ~0x1f);
plocaltxpd->tx_control = cpu_to_le32(new_rate);
}
@@ -115,12 +106,12 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
}
/* copy destination address from 802.3 or 802.11 header */
- if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
else
memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
- lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+ lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
if (IS_MESH_FRAME(skb)) {
plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
@@ -130,7 +121,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
ptr += sizeof(struct txpd);
- lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+ lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
ret = priv->hw_host_to_card(priv, MVMS_DAT,
priv->adapter->tmptxbuf,
@@ -153,13 +144,14 @@ done:
priv->stats.tx_errors++;
}
- if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) {
/* Keep the skb to echo it back once Tx feedback is
received from FW */
skb_orphan(skb);
/* stop processing outgoing pkts */
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
/* freeze any packets already in our queues */
priv->adapter->TxLockFlag = 1;
} else {
@@ -198,10 +190,12 @@ static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
if (adapter->tx_queue_idx == NR_TX_QUEUE) {
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
} else {
netif_start_queue(priv->dev);
- netif_start_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_start_queue(priv->mesh_dev);
}
spin_unlock(&adapter->txqueue_lock);
@@ -219,7 +213,7 @@ int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
int ret = -1;
lbs_deb_enter(LBS_DEB_TX);
- lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+ lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
if (priv->dnld_sent) {
lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
@@ -258,16 +252,12 @@ void libertas_send_tx_feedback(wlan_private * priv)
int txfail;
int try_count;
- if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+ if (adapter->monitormode == WLAN_MONITOR_OFF ||
adapter->currenttxskb == NULL)
return;
radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
- if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
- lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
- min_t(unsigned int, adapter->currenttxskb->len, 100));
-
txfail = (status >> 24);
#if 0
@@ -283,9 +273,10 @@ void libertas_send_tx_feedback(wlan_private * priv)
libertas_upload_rx_packet(priv, adapter->currenttxskb);
adapter->currenttxskb = NULL;
priv->adapter->TxLockFlag = 0;
- if (priv->adapter->connect_status == libertas_connected) {
+ if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_wake_queue(priv->dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
}
EXPORT_SYMBOL_GPL(libertas_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 028e2f3b53d6..a43a5f63c879 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -7,71 +7,6 @@
#include <linux/if_ether.h>
#include <asm/byteorder.h>
-/** IEEE type definitions */
-enum ieeetypes_elementid {
- SSID = 0,
- SUPPORTED_RATES,
- FH_PARAM_SET,
- DS_PARAM_SET,
- CF_PARAM_SET,
- TIM,
- IBSS_PARAM_SET,
- COUNTRY_INFO = 7,
-
- CHALLENGE_TEXT = 16,
-
- EXTENDED_SUPPORTED_RATES = 50,
-
- VENDOR_SPECIFIC_221 = 221,
-
- WPA_IE = 221,
- WPA2_IE = 48,
-
- EXTRA_IE = 133,
-} __attribute__ ((packed));
-
-#ifdef __BIG_ENDIAN
-#define CAPINFO_MASK (~(0xda00))
-#else
-#define CAPINFO_MASK (~(0x00da))
-#endif
-
-struct ieeetypes_capinfo {
-#ifdef __BIG_ENDIAN_BITFIELD
- u8 chanagility:1;
- u8 pbcc:1;
- u8 shortpreamble:1;
- u8 privacy:1;
- u8 cfpollrqst:1;
- u8 cfpollable:1;
- u8 ibss:1;
- u8 ess:1;
- u8 rsrvd1:2;
- u8 dsssofdm:1;
- u8 rsvrd2:1;
- u8 apsd:1;
- u8 shortslottime:1;
- u8 rsrvd3:1;
- u8 spectrummgmt:1;
-#else
- u8 ess:1;
- u8 ibss:1;
- u8 cfpollable:1;
- u8 cfpollrqst:1;
- u8 privacy:1;
- u8 shortpreamble:1;
- u8 pbcc:1;
- u8 chanagility:1;
- u8 spectrummgmt:1;
- u8 rsrvd3:1;
- u8 shortslottime:1;
- u8 apsd:1;
- u8 rsvrd2:1;
- u8 dsssofdm:1;
- u8 rsrvd1:2;
-#endif
-} __attribute__ ((packed));
-
struct ieeetypes_cfparamset {
u8 elementid;
u8 len;
@@ -114,7 +49,7 @@ union ieeetypes_phyparamset {
} __attribute__ ((packed));
struct ieeetypes_assocrsp {
- struct ieeetypes_capinfo capability;
+ __le16 capability;
__le16 statuscode;
__le16 aid;
u8 iebuffer[1];
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 2fcc3bf21081..c6f5aa3cb465 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -22,60 +22,6 @@
/**
- * the rates supported by the card
- */
-static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
- { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
- 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
-};
-
-/**
- * @brief Convert mw value to dbm value
- *
- * @param mw the value of mw
- * @return the value of dbm
- */
-static int mw_to_dbm(int mw)
-{
- if (mw < 2)
- return 0;
- else if (mw < 3)
- return 3;
- else if (mw < 4)
- return 5;
- else if (mw < 6)
- return 7;
- else if (mw < 7)
- return 8;
- else if (mw < 8)
- return 9;
- else if (mw < 10)
- return 10;
- else if (mw < 13)
- return 11;
- else if (mw < 16)
- return 12;
- else if (mw < 20)
- return 13;
- else if (mw < 25)
- return 14;
- else if (mw < 32)
- return 15;
- else if (mw < 40)
- return 16;
- else if (mw < 50)
- return 17;
- else if (mw < 63)
- return 18;
- else if (mw < 79)
- return 19;
- else if (mw < 100)
- return 20;
- else
- return 21;
-}
-
-/**
* @brief Find the channel frequency power info with specific channel
*
* @param adapter A pointer to wlan_adapter structure
@@ -165,7 +111,7 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
* @option Radio Option
* @return 0 --success, otherwise fail
*/
-int wlan_radio_ioctl(wlan_private * priv, u8 option)
+static int wlan_radio_ioctl(wlan_private * priv, u8 option)
{
int ret = 0;
wlan_adapter *adapter = priv->adapter;
@@ -177,9 +123,9 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option)
adapter->radioon = option;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_radio_control,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RADIO_CONTROL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
}
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -187,84 +133,31 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option)
}
/**
- * @brief Copy rates
- *
- * @param dest A pointer to Dest Buf
- * @param src A pointer to Src Buf
- * @param len The len of Src Buf
- * @return Number of rates copyed
- */
-static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
-{
- int i;
-
- for (i = 0; i < len && src[i]; i++, pos++) {
- if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
- break;
- dest[pos] = src[i];
- }
-
- return pos;
-}
-
-/**
- * @brief Get active data rates
+ * @brief Copy active data rates based on adapter mode and status
*
* @param adapter A pointer to wlan_adapter structure
* @param rate The buf to return the active rates
- * @return The number of rates
*/
-static int get_active_data_rates(wlan_adapter * adapter,
- u8* rates)
+static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates)
{
- int k = 0;
-
lbs_deb_enter(LBS_DEB_WEXT);
- if (adapter->connect_status != libertas_connected) {
- if (adapter->mode == IW_MODE_INFRA) {
- lbs_deb_wext("infra\n");
- k = copyrates(rates, k, libertas_supported_rates,
- sizeof(libertas_supported_rates));
- } else {
- lbs_deb_wext("Adhoc G\n");
- k = copyrates(rates, k, libertas_adhoc_rates_g,
- sizeof(libertas_adhoc_rates_g));
- }
- } else {
- k = copyrates(rates, 0, adapter->curbssparams.datarates,
- adapter->curbssparams.numofrates);
- }
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
+ memcpy(rates, libertas_bg_rates, MAX_RATES);
+ else
+ memcpy(rates, adapter->curbssparams.rates, MAX_RATES);
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
- return k;
+ lbs_deb_leave(LBS_DEB_WEXT);
}
static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
char *cwrq, char *extra)
{
- const char *cp;
- char comm[6] = { "COMM-" };
- char mrvl[6] = { "MRVL-" };
- int cnt;
lbs_deb_enter(LBS_DEB_WEXT);
- strcpy(cwrq, mrvl);
-
- cp = strstr(libertas_driver_version, comm);
- if (cp == libertas_driver_version) //skip leading "COMM-"
- cp = libertas_driver_version + strlen(comm);
- else
- cp = libertas_driver_version;
-
- cnt = strlen(mrvl);
- cwrq += cnt;
- while (cnt < 16 && (*cp != '-')) {
- *cwrq++ = toupper(*cp++);
- cnt++;
- }
- *cwrq = '\0';
+ /* We could add support for 802.11n here as needed. Jean II */
+ snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
@@ -305,7 +198,7 @@ static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
} else {
memset(awrq->sa_data, 0, ETH_ALEN);
@@ -349,24 +242,11 @@ static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- /*
- * Get the Nick Name saved
- */
-
- mutex_lock(&adapter->lock);
- strncpy(extra, adapter->nodename, 16);
- mutex_unlock(&adapter->lock);
-
- extra[16] = '\0';
+ dwrq->length = strlen(adapter->nodename);
+ memcpy(extra, adapter->nodename, dwrq->length);
+ extra[dwrq->length] = '\0';
- /*
- * If none, we may want to get the one that was set
- */
-
- /*
- * Push it out !
- */
- dwrq->length = strlen(extra) + 1;
+ dwrq->flags = 1; /* active */
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
@@ -382,20 +262,21 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
/* Use nickname to indicate that mesh is on */
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
strncpy(extra, "Mesh", 12);
extra[12] = '\0';
- dwrq->length = strlen(extra) + 1;
+ dwrq->length = strlen(extra);
}
else {
extra[0] = '\0';
- dwrq->length = 1 ;
+ dwrq->length = 0;
}
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
+
static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
@@ -414,8 +295,8 @@ static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
adapter->rtsthsd = rthr;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_set, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
OID_802_11_RTS_THRESHOLD, &rthr);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -432,8 +313,8 @@ static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
adapter->rtsthsd = 0;
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_get, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
OID_802_11_RTS_THRESHOLD, NULL);
if (ret)
goto out;
@@ -467,8 +348,8 @@ static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
adapter->fragthsd = fthr;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_set, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -486,8 +367,8 @@ static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
adapter->fragthsd = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- cmd_act_get, cmd_option_waitforrsp,
+ CMD_802_11_SNMP_MIB,
+ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
if (ret)
goto out;
@@ -539,9 +420,9 @@ static int wlan_get_txpow(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_rf_tx_power,
- cmd_act_tx_power_opt_get,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RF_TX_POWER,
+ CMD_ACT_TX_POWER_OPT_GET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret)
goto out;
@@ -581,9 +462,9 @@ static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
/* Adding 1 to convert retry count to try count */
adapter->txretrycount = vwrq->value + 1;
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_set,
- cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
OID_802_11_TX_RETRYCOUNT, NULL);
if (ret)
@@ -608,8 +489,8 @@ static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
adapter->txretrycount = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- cmd_act_get, cmd_option_waitforrsp,
+ CMD_802_11_SNMP_MIB,
+ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
OID_802_11_TX_RETRYCOUNT, NULL);
if (ret)
goto out;
@@ -673,7 +554,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
wlan_adapter *adapter = priv->adapter;
struct iw_range *range = (struct iw_range *)extra;
struct chan_freq_power *cfp;
- u8 rates[WLAN_SUPPORTED_RATES];
+ u8 rates[MAX_RATES + 1];
u8 flag = 0;
@@ -686,19 +567,17 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
range->max_nwid = 0;
memset(rates, 0, sizeof(rates));
- range->num_bitrates = get_active_data_rates(adapter, rates);
-
- for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
- i++) {
- range->bitrate[i] = (rates[i] & 0x7f) * 500000;
- }
+ copy_active_data_rates(adapter, rates);
+ range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
+ for (i = 0; i < range->num_bitrates; i++)
+ range->bitrate[i] = rates[i] * 500000;
range->num_bitrates = i;
lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
range->num_bitrates);
range->num_frequency = 0;
if (priv->adapter->enable11d &&
- adapter->connect_status == libertas_connected) {
+ adapter->connect_status == LIBERTAS_CONNECTED) {
u8 chan_no;
u8 band;
@@ -858,9 +737,9 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
*/
if (vwrq->disabled) {
- adapter->psmode = wlan802_11powermodecam;
+ adapter->psmode = WLAN802_11POWERMODECAM;
if (adapter->psstate != PS_STATE_FULL_POWER) {
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
return 0;
@@ -875,14 +754,14 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
return -EINVAL;
}
- if (adapter->psmode != wlan802_11powermodecam) {
+ if (adapter->psmode != WLAN802_11POWERMODECAM) {
return 0;
}
- adapter->psmode = wlan802_11powermodemax_psp;
+ adapter->psmode = WLAN802_11POWERMODEMAX_PSP;
- if (adapter->connect_status == libertas_connected) {
- libertas_ps_sleep(priv, cmd_option_waitforrsp);
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
+ libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
}
lbs_deb_leave(LBS_DEB_WEXT);
@@ -900,8 +779,8 @@ static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
mode = adapter->psmode;
- if ((vwrq->disabled = (mode == wlan802_11powermodecam))
- || adapter->connect_status == libertas_disconnected)
+ if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM))
+ || adapter->connect_status == LIBERTAS_DISCONNECTED)
{
goto out;
}
@@ -937,7 +816,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
priv->wstats.status = adapter->mode;
/* If we're not associated, all quality values are meaningless */
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
goto out;
/* Quality by RSSI */
@@ -973,7 +852,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
/* Quality by TX errors */
priv->wstats.discard.retries = priv->stats.tx_errors;
- tx_retries = le16_to_cpu(adapter->logmsg.retry);
+ tx_retries = le32_to_cpu(adapter->logmsg.retry);
if (tx_retries > 75)
tx_qual = (90 - tx_retries) * POOR / 15;
@@ -989,20 +868,20 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
(PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
quality = min(quality, tx_qual);
- priv->wstats.discard.code = le16_to_cpu(adapter->logmsg.wepundecryptable);
- priv->wstats.discard.fragment = le16_to_cpu(adapter->logmsg.rxfrag);
+ priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable);
+ priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag);
priv->wstats.discard.retries = tx_retries;
- priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure);
+ priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure);
/* Calculate quality */
- priv->wstats.qual.qual = max(quality, (u32)100);
+ priv->wstats.qual.qual = min_t(u8, quality, 100);
priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
stats_valid = 1;
/* update stats asynchronously for future calls */
- libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+ libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
- libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+ libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
0, 0, NULL);
out:
if (!stats_valid) {
@@ -1080,88 +959,46 @@ out:
return ret;
}
-/**
- * @brief use index to get the data rate
- *
- * @param index The index of data rate
- * @return data rate or 0
- */
-u32 libertas_index_to_data_rate(u8 index)
-{
- if (index >= sizeof(libertas_wlan_data_rates))
- index = 0;
-
- return libertas_wlan_data_rates[index];
-}
-
-/**
- * @brief use rate to get the index
- *
- * @param rate data rate
- * @return index or 0
- */
-u8 libertas_data_rate_to_index(u32 rate)
-{
- u8 *ptr;
-
- if (rate)
- if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
- sizeof(libertas_wlan_data_rates))))
- return (ptr - libertas_wlan_data_rates);
-
- return 0;
-}
-
static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
- u32 data_rate;
+ u32 new_rate;
u16 action;
- int ret = 0;
- u8 rates[WLAN_SUPPORTED_RATES];
- u8 *rate;
+ int ret = -EINVAL;
+ u8 rates[MAX_RATES + 1];
lbs_deb_enter(LBS_DEB_WEXT);
-
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
+ /* Auto rate? */
if (vwrq->value == -1) {
- action = cmd_act_set_tx_auto; // Auto
- adapter->is_datarate_auto = 1;
- adapter->datarate = 0;
+ action = CMD_ACT_SET_TX_AUTO;
+ adapter->auto_rate = 1;
+ adapter->cur_rate = 0;
} else {
- if (vwrq->value % 100000) {
- return -EINVAL;
- }
-
- data_rate = vwrq->value / 500000;
+ if (vwrq->value % 100000)
+ goto out;
memset(rates, 0, sizeof(rates));
- get_active_data_rates(adapter, rates);
- rate = rates;
- while (*rate) {
- lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
- data_rate);
- if ((*rate & 0x7f) == (data_rate & 0x7f))
- break;
- rate++;
- }
- if (!*rate) {
- lbs_pr_alert("fixed data rate 0x%X out "
- "of range\n", data_rate);
- return -EINVAL;
+ copy_active_data_rates(adapter, rates);
+ new_rate = vwrq->value / 500000;
+ if (!memchr(rates, new_rate, sizeof(rates))) {
+ lbs_pr_alert("fixed data rate 0x%X out of range\n",
+ new_rate);
+ goto out;
}
- adapter->datarate = data_rate;
- action = cmd_act_set_tx_fix_rate;
- adapter->is_datarate_auto = 0;
+ adapter->cur_rate = new_rate;
+ action = CMD_ACT_SET_TX_FIX_RATE;
+ adapter->auto_rate = 0;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
- action, cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+ action, CMD_OPTION_WAITFORRSP, 0, NULL);
+out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
@@ -1174,14 +1011,19 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (adapter->is_datarate_auto) {
- vwrq->fixed = 0;
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
+ vwrq->value = adapter->cur_rate * 500000;
+
+ if (adapter->auto_rate)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+
} else {
- vwrq->fixed = 1;
+ vwrq->fixed = 0;
+ vwrq->value = 0;
}
- vwrq->value = adapter->datarate * 500000;
-
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
@@ -1298,7 +1140,7 @@ static int wlan_get_encode(struct net_device *dev,
dwrq->flags |= IW_ENCODE_NOKEY;
- lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
+ lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
extra[0], extra[1], extra[2],
extra[3], extra[4], extra[5], dwrq->length);
@@ -1325,7 +1167,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req,
int set_tx_key)
{
int ret = 0;
- struct WLAN_802_11_KEY *pkey;
+ struct enc_key *pkey;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1344,7 +1186,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req,
pkey = &assoc_req->wep_keys[index];
if (key_length > 0) {
- memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ memset(pkey, 0, sizeof(struct enc_key));
pkey->type = KEY_TYPE_ID_WEP;
/* Standardize the key length */
@@ -1412,11 +1254,11 @@ static void disable_wpa(struct assoc_request *assoc_req)
{
lbs_deb_enter(LBS_DEB_WEXT);
- memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY));
+ memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
- memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY));
+ memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
@@ -1567,7 +1409,7 @@ static int wlan_get_encodeext(struct net_device *dev,
&& (adapter->secinfo.WPAenabled ||
adapter->secinfo.WPA2enabled)) {
/* WPA */
- struct WLAN_802_11_KEY * pkey = NULL;
+ struct enc_key * pkey = NULL;
if ( adapter->wpa_mcast_key.len
&& (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
@@ -1679,7 +1521,7 @@ static int wlan_set_encodeext(struct net_device *dev,
if (set_tx_key)
set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
- struct WLAN_802_11_KEY * pkey;
+ struct enc_key * pkey;
/* validate key length */
if (((alg == IW_ENCODE_ALG_TKIP)
@@ -1702,7 +1544,7 @@ static int wlan_set_encodeext(struct net_device *dev,
set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
}
- memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+ memset(pkey, 0, sizeof (struct enc_key));
memcpy(pkey->key, ext->key, ext->key_len);
pkey->len = ext->key_len;
if (pkey->len)
@@ -1976,12 +1818,14 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
return 0;
}
- adapter->preamble = cmd_type_auto_preamble;
+ adapter->preamble = CMD_TYPE_AUTO_PREAMBLE;
wlan_radio_ioctl(priv, RADIO_ON);
+ /* Userspace check in iwrange if it should use dBm or mW,
+ * therefore this should never happen... Jean II */
if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
- dbm = (u16) mw_to_dbm(vwrq->value);
+ return -EOPNOTSUPP;
} else
dbm = (u16) vwrq->value;
@@ -1993,9 +1837,9 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
lbs_deb_wext("txpower set %d dbm\n", dbm);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_rf_tx_power,
- cmd_act_tx_power_opt_set_low,
- cmd_option_waitforrsp, 0, (void *)&dbm);
+ CMD_802_11_RF_TX_POWER,
+ CMD_ACT_TX_POWER_OPT_SET_LOW,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
@@ -2017,7 +1861,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
/*
* Get the current SSID
*/
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
memcpy(extra, adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len);
extra[adapter->curbssparams.ssid_len] = '\0';
@@ -2029,12 +1873,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
* If none, we may want to get the one that was set
*/
- /* To make the driver backward compatible with WPA supplicant v0.2.4 */
- if (dwrq->length == 32) /* check with WPA supplicant buffer size */
- dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len,
- IW_ESSID_MAX_SIZE);
- else
- dwrq->length = adapter->curbssparams.ssid_len + 1;
+ dwrq->length = adapter->curbssparams.ssid_len;
dwrq->flags = 1; /* active */
@@ -2055,14 +1894,6 @@ static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- /*
- * WE-20 and earlier NULL pad the end of the SSID and increment
- * SSID length so it can be used like a string. WE-21 and later don't,
- * but some userspace tools aren't able to cope with the change.
- */
- if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0'))
- in_ssid_len--;
-
/* Check the size of the string */
if (in_ssid_len > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
@@ -2129,13 +1960,14 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
wlan_adapter *adapter = priv->adapter;
struct assoc_request * assoc_req;
int ret = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_WEXT);
if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL;
- lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+ lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
mutex_lock(&adapter->lock);
@@ -2298,13 +2130,13 @@ static const iw_handler mesh_wlan_handler[] = {
(iw_handler) NULL, /* SIOCSIWPMKSA */
};
struct iw_handler_def libertas_handler_def = {
- .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(wlan_handler),
.standard = (iw_handler *) wlan_handler,
.get_wireless_stats = wlan_get_wireless_stats,
};
struct iw_handler_def mesh_handler_def = {
- .num_standard = sizeof(mesh_wlan_handler) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(mesh_wlan_handler),
.standard = (iw_handler *) mesh_wlan_handler,
.get_wireless_stats = wlan_get_wireless_stats,
};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 3d5196c9553a..6aa444c7de8d 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -4,9 +4,6 @@
#ifndef _WLAN_WEXT_H_
#define _WLAN_WEXT_H_
-#define SUBCMD_OFFSET 4
-#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
-
/** wlan_ioctl_regrdwr */
struct wlan_ioctl_regrdwr {
/** Which register to access */
@@ -18,13 +15,9 @@ struct wlan_ioctl_regrdwr {
u32 value;
};
-#define WLAN_LINKMODE_802_3 0
-#define WLAN_LINKMODE_802_11 2
-#define WLAN_RADIOMODE_NONE 0
-#define WLAN_RADIOMODE_RADIOTAP 2
+#define WLAN_MONITOR_OFF 0
extern struct iw_handler_def libertas_handler_def;
extern struct iw_handler_def mesh_handler_def;
-int wlan_radio_ioctl(wlan_private * priv, u8 option);
#endif /* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/net2280.h b/drivers/net/wireless/net2280.h
new file mode 100644
index 000000000000..120eb831b287
--- /dev/null
+++ b/drivers/net/wireless/net2280.h
@@ -0,0 +1,452 @@
+#ifndef NET2280_H
+#define NET2280_H
+/*
+ * NetChip 2280 high/full speed USB device controller.
+ * Unlike many such controllers, this one talks PCI.
+ */
+
+/*
+ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* NET2280 MEMORY MAPPED REGISTERS
+ *
+ * The register layout came from the chip documentation, and the bit
+ * number definitions were extracted from chip specification.
+ *
+ * Use the shift operator ('<<') to build bit masks, with readl/writel
+ * to access the registers through PCI.
+ */
+
+/* main registers, BAR0 + 0x0000 */
+struct net2280_regs {
+ // offset 0x0000
+ __le32 devinit;
+#define LOCAL_CLOCK_FREQUENCY 8
+#define FORCE_PCI_RESET 7
+#define PCI_ID 6
+#define PCI_ENABLE 5
+#define FIFO_SOFT_RESET 4
+#define CFG_SOFT_RESET 3
+#define PCI_SOFT_RESET 2
+#define USB_SOFT_RESET 1
+#define M8051_RESET 0
+ __le32 eectl;
+#define EEPROM_ADDRESS_WIDTH 23
+#define EEPROM_CHIP_SELECT_ACTIVE 22
+#define EEPROM_PRESENT 21
+#define EEPROM_VALID 20
+#define EEPROM_BUSY 19
+#define EEPROM_CHIP_SELECT_ENABLE 18
+#define EEPROM_BYTE_READ_START 17
+#define EEPROM_BYTE_WRITE_START 16
+#define EEPROM_READ_DATA 8
+#define EEPROM_WRITE_DATA 0
+ __le32 eeclkfreq;
+ u32 _unused0;
+ // offset 0x0010
+
+ __le32 pciirqenb0; /* interrupt PCI master ... */
+#define SETUP_PACKET_INTERRUPT_ENABLE 7
+#define ENDPOINT_F_INTERRUPT_ENABLE 6
+#define ENDPOINT_E_INTERRUPT_ENABLE 5
+#define ENDPOINT_D_INTERRUPT_ENABLE 4
+#define ENDPOINT_C_INTERRUPT_ENABLE 3
+#define ENDPOINT_B_INTERRUPT_ENABLE 2
+#define ENDPOINT_A_INTERRUPT_ENABLE 1
+#define ENDPOINT_0_INTERRUPT_ENABLE 0
+ __le32 pciirqenb1;
+#define PCI_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+ __le32 cpu_irqenb0; /* ... or onboard 8051 */
+#define SETUP_PACKET_INTERRUPT_ENABLE 7
+#define ENDPOINT_F_INTERRUPT_ENABLE 6
+#define ENDPOINT_E_INTERRUPT_ENABLE 5
+#define ENDPOINT_D_INTERRUPT_ENABLE 4
+#define ENDPOINT_C_INTERRUPT_ENABLE 3
+#define ENDPOINT_B_INTERRUPT_ENABLE 2
+#define ENDPOINT_A_INTERRUPT_ENABLE 1
+#define ENDPOINT_0_INTERRUPT_ENABLE 0
+ __le32 cpu_irqenb1;
+#define CPU_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_INTA_INTERRUPT_ENABLE 24
+#define PCI_PME_INTERRUPT_ENABLE 23
+#define PCI_SERR_INTERRUPT_ENABLE 22
+#define PCI_PERR_INTERRUPT_ENABLE 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+
+ // offset 0x0020
+ u32 _unused1;
+ __le32 usbirqenb1;
+#define USB_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_INTA_INTERRUPT_ENABLE 24
+#define PCI_PME_INTERRUPT_ENABLE 23
+#define PCI_SERR_INTERRUPT_ENABLE 22
+#define PCI_PERR_INTERRUPT_ENABLE 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+ __le32 irqstat0;
+#define INTA_ASSERTED 12
+#define SETUP_PACKET_INTERRUPT 7
+#define ENDPOINT_F_INTERRUPT 6
+#define ENDPOINT_E_INTERRUPT 5
+#define ENDPOINT_D_INTERRUPT 4
+#define ENDPOINT_C_INTERRUPT 3
+#define ENDPOINT_B_INTERRUPT 2
+#define ENDPOINT_A_INTERRUPT 1
+#define ENDPOINT_0_INTERRUPT 0
+ __le32 irqstat1;
+#define POWER_STATE_CHANGE_INTERRUPT 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT 26
+#define PCI_PARITY_ERROR_INTERRUPT 25
+#define PCI_INTA_INTERRUPT 24
+#define PCI_PME_INTERRUPT 23
+#define PCI_SERR_INTERRUPT 22
+#define PCI_PERR_INTERRUPT 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19
+#define PCI_RETRY_ABORT_INTERRUPT 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16
+#define GPIO_INTERRUPT 13
+#define DMA_D_INTERRUPT 12
+#define DMA_C_INTERRUPT 11
+#define DMA_B_INTERRUPT 10
+#define DMA_A_INTERRUPT 9
+#define EEPROM_DONE_INTERRUPT 8
+#define VBUS_INTERRUPT 7
+#define CONTROL_STATUS_INTERRUPT 6
+#define ROOT_PORT_RESET_INTERRUPT 4
+#define SUSPEND_REQUEST_INTERRUPT 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2
+#define RESUME_INTERRUPT 1
+#define SOF_INTERRUPT 0
+ // offset 0x0030
+ __le32 idxaddr;
+ __le32 idxdata;
+ __le32 fifoctl;
+#define PCI_BASE2_RANGE 16
+#define IGNORE_FIFO_AVAILABILITY 3
+#define PCI_BASE2_SELECT 2
+#define FIFO_CONFIGURATION_SELECT 0
+ u32 _unused2;
+ // offset 0x0040
+ __le32 memaddr;
+#define START 28
+#define DIRECTION 27
+#define FIFO_DIAGNOSTIC_SELECT 24
+#define MEMORY_ADDRESS 0
+ __le32 memdata0;
+ __le32 memdata1;
+ u32 _unused3;
+ // offset 0x0050
+ __le32 gpioctl;
+#define GPIO3_LED_SELECT 12
+#define GPIO3_INTERRUPT_ENABLE 11
+#define GPIO2_INTERRUPT_ENABLE 10
+#define GPIO1_INTERRUPT_ENABLE 9
+#define GPIO0_INTERRUPT_ENABLE 8
+#define GPIO3_OUTPUT_ENABLE 7
+#define GPIO2_OUTPUT_ENABLE 6
+#define GPIO1_OUTPUT_ENABLE 5
+#define GPIO0_OUTPUT_ENABLE 4
+#define GPIO3_DATA 3
+#define GPIO2_DATA 2
+#define GPIO1_DATA 1
+#define GPIO0_DATA 0
+ __le32 gpiostat;
+#define GPIO3_INTERRUPT 3
+#define GPIO2_INTERRUPT 2
+#define GPIO1_INTERRUPT 1
+#define GPIO0_INTERRUPT 0
+} __attribute__ ((packed));
+
+/* usb control, BAR0 + 0x0080 */
+struct net2280_usb_regs {
+ // offset 0x0080
+ __le32 stdrsp;
+#define STALL_UNSUPPORTED_REQUESTS 31
+#define SET_TEST_MODE 16
+#define GET_OTHER_SPEED_CONFIGURATION 15
+#define GET_DEVICE_QUALIFIER 14
+#define SET_ADDRESS 13
+#define ENDPOINT_SET_CLEAR_HALT 12
+#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11
+#define GET_STRING_DESCRIPTOR_2 10
+#define GET_STRING_DESCRIPTOR_1 9
+#define GET_STRING_DESCRIPTOR_0 8
+#define GET_SET_INTERFACE 6
+#define GET_SET_CONFIGURATION 5
+#define GET_CONFIGURATION_DESCRIPTOR 4
+#define GET_DEVICE_DESCRIPTOR 3
+#define GET_ENDPOINT_STATUS 2
+#define GET_INTERFACE_STATUS 1
+#define GET_DEVICE_STATUS 0
+ __le32 prodvendid;
+#define PRODUCT_ID 16
+#define VENDOR_ID 0
+ __le32 relnum;
+ __le32 usbctl;
+#define SERIAL_NUMBER_INDEX 16
+#define PRODUCT_ID_STRING_ENABLE 13
+#define VENDOR_ID_STRING_ENABLE 12
+#define USB_ROOT_PORT_WAKEUP_ENABLE 11
+#define VBUS_PIN 10
+#define TIMED_DISCONNECT 9
+#define SUSPEND_IMMEDIATELY 7
+#define SELF_POWERED_USB_DEVICE 6
+#define REMOTE_WAKEUP_SUPPORT 5
+#define PME_POLARITY 4
+#define USB_DETECT_ENABLE 3
+#define PME_WAKEUP_ENABLE 2
+#define DEVICE_REMOTE_WAKEUP_ENABLE 1
+#define SELF_POWERED_STATUS 0
+ // offset 0x0090
+ __le32 usbstat;
+#define HIGH_SPEED 7
+#define FULL_SPEED 6
+#define GENERATE_RESUME 5
+#define GENERATE_DEVICE_REMOTE_WAKEUP 4
+ __le32 xcvrdiag;
+#define FORCE_HIGH_SPEED_MODE 31
+#define FORCE_FULL_SPEED_MODE 30
+#define USB_TEST_MODE 24
+#define LINE_STATE 16
+#define TRANSCEIVER_OPERATION_MODE 2
+#define TRANSCEIVER_SELECT 1
+#define TERMINATION_SELECT 0
+ __le32 setup0123;
+ __le32 setup4567;
+ // offset 0x0090
+ u32 _unused0;
+ __le32 ouraddr;
+#define FORCE_IMMEDIATE 7
+#define OUR_USB_ADDRESS 0
+ __le32 ourconfig;
+} __attribute__ ((packed));
+
+/* pci control, BAR0 + 0x0100 */
+struct net2280_pci_regs {
+ // offset 0x0100
+ __le32 pcimstctl;
+#define PCI_ARBITER_PARK_SELECT 13
+#define PCI_MULTI LEVEL_ARBITER 12
+#define PCI_RETRY_ABORT_ENABLE 11
+#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10
+#define DMA_READ_MULTIPLE_ENABLE 9
+#define DMA_READ_LINE_ENABLE 8
+#define PCI_MASTER_COMMAND_SELECT 6
+#define MEM_READ_OR_WRITE 0
+#define IO_READ_OR_WRITE 1
+#define CFG_READ_OR_WRITE 2
+#define PCI_MASTER_START 5
+#define PCI_MASTER_READ_WRITE 4
+#define PCI_MASTER_WRITE 0
+#define PCI_MASTER_READ 1
+#define PCI_MASTER_BYTE_WRITE_ENABLES 0
+ __le32 pcimstaddr;
+ __le32 pcimstdata;
+ __le32 pcimststat;
+#define PCI_ARBITER_CLEAR 2
+#define PCI_EXTERNAL_ARBITER 1
+#define PCI_HOST_MODE 0
+} __attribute__ ((packed));
+
+/* dma control, BAR0 + 0x0180 ... array of four structs like this,
+ * for channels 0..3. see also struct net2280_dma: descriptor
+ * that can be loaded into some of these registers.
+ */
+struct net2280_dma_regs { /* [11.7] */
+ // offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
+ __le32 dmactl;
+#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25
+#define DMA_CLEAR_COUNT_ENABLE 21
+#define DESCRIPTOR_POLLING_RATE 19
+#define POLL_CONTINUOUS 0
+#define POLL_1_USEC 1
+#define POLL_100_USEC 2
+#define POLL_1_MSEC 3
+#define DMA_VALID_BIT_POLLING_ENABLE 18
+#define DMA_VALID_BIT_ENABLE 17
+#define DMA_SCATTER_GATHER_ENABLE 16
+#define DMA_OUT_AUTO_START_ENABLE 4
+#define DMA_PREEMPT_ENABLE 3
+#define DMA_FIFO_VALIDATE 2
+#define DMA_ENABLE 1
+#define DMA_ADDRESS_HOLD 0
+ __le32 dmastat;
+#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25
+#define DMA_TRANSACTION_DONE_INTERRUPT 24
+#define DMA_ABORT 1
+#define DMA_START 0
+ u32 _unused0[2];
+ // offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
+ __le32 dmacount;
+#define VALID_BIT 31
+#define DMA_DIRECTION 30
+#define DMA_DONE_INTERRUPT_ENABLE 29
+#define END_OF_CHAIN 28
+#define DMA_BYTE_COUNT_MASK ((1<<24)-1)
+#define DMA_BYTE_COUNT 0
+ __le32 dmaaddr;
+ __le32 dmadesc;
+ u32 _unused1;
+} __attribute__ ((packed));
+
+/* dedicated endpoint registers, BAR0 + 0x0200 */
+
+struct net2280_dep_regs { /* [11.8] */
+ // offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+ __le32 dep_cfg;
+ // offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+ __le32 dep_rsp;
+ u32 _unused[2];
+} __attribute__ ((packed));
+
+/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
+ * like this, for ep0 then the configurable endpoints A..F
+ * ep0 reserved for control; E and F have only 64 bytes of fifo
+ */
+struct net2280_ep_regs { /* [11.9] */
+ // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+ __le32 ep_cfg;
+#define ENDPOINT_BYTE_COUNT 16
+#define ENDPOINT_ENABLE 10
+#define ENDPOINT_TYPE 8
+#define ENDPOINT_DIRECTION 7
+#define ENDPOINT_NUMBER 0
+ __le32 ep_rsp;
+#define SET_NAK_OUT_PACKETS 15
+#define SET_EP_HIDE_STATUS_PHASE 14
+#define SET_EP_FORCE_CRC_ERROR 13
+#define SET_INTERRUPT_MODE 12
+#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11
+#define SET_NAK_OUT_PACKETS_MODE 10
+#define SET_ENDPOINT_TOGGLE 9
+#define SET_ENDPOINT_HALT 8
+#define CLEAR_NAK_OUT_PACKETS 7
+#define CLEAR_EP_HIDE_STATUS_PHASE 6
+#define CLEAR_EP_FORCE_CRC_ERROR 5
+#define CLEAR_INTERRUPT_MODE 4
+#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3
+#define CLEAR_NAK_OUT_PACKETS_MODE 2
+#define CLEAR_ENDPOINT_TOGGLE 1
+#define CLEAR_ENDPOINT_HALT 0
+ __le32 ep_irqenb;
+#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6
+#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5
+#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3
+#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2
+#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1
+#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0
+ __le32 ep_stat;
+#define FIFO_VALID_COUNT 24
+#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22
+#define TIMEOUT 21
+#define USB_STALL_SENT 20
+#define USB_IN_NAK_SENT 19
+#define USB_IN_ACK_RCVD 18
+#define USB_OUT_PING_NAK_SENT 17
+#define USB_OUT_ACK_SENT 16
+#define FIFO_OVERFLOW 13
+#define FIFO_UNDERFLOW 12
+#define FIFO_FULL 11
+#define FIFO_EMPTY 10
+#define FIFO_FLUSH 9
+#define SHORT_PACKET_OUT_DONE_INTERRUPT 6
+#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5
+#define NAK_OUT_PACKETS 4
+#define DATA_PACKET_RECEIVED_INTERRUPT 3
+#define DATA_PACKET_TRANSMITTED_INTERRUPT 2
+#define DATA_OUT_PING_TOKEN_INTERRUPT 1
+#define DATA_IN_TOKEN_INTERRUPT 0
+ // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+ __le32 ep_avail;
+ __le32 ep_data;
+ u32 _unused0[2];
+} __attribute__ ((packed));
+
+struct net2280_reg_write {
+ __le16 port;
+ __le32 addr;
+ __le32 val;
+} __attribute__ ((packed));
+
+struct net2280_reg_read {
+ __le16 port;
+ __le32 addr;
+} __attribute__ ((packed));
+#endif /* NET2280_H */
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 45b00e13ab2b..c2d71afd57e5 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -412,7 +412,6 @@ static int netwave_probe(struct pcmcia_device *link)
spin_lock_init(&priv->spinlock);
/* Netwave specific entries in the device structure */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &netwave_start_xmit;
dev->get_stats = &netwave_get_stats;
dev->set_multicast_list = &set_multicast_list;
@@ -710,9 +709,9 @@ static const iw_handler netwave_private_handler[] =
static const struct iw_handler_def netwave_handler_def =
{
- .num_standard = sizeof(netwave_handler)/sizeof(iw_handler),
- .num_private = sizeof(netwave_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(netwave_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(netwave_handler),
+ .num_private = ARRAY_SIZE(netwave_private_handler),
+ .num_private_args = ARRAY_SIZE(netwave_private_args),
.standard = (iw_handler *) netwave_handler,
.private = (iw_handler *) netwave_private_handler,
.private_args = (struct iw_priv_args *) netwave_private_args,
@@ -738,6 +737,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
win_req_t req;
memreq_t mem;
u_char __iomem *ramBase = NULL;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
@@ -806,12 +806,13 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
for (i = 0; i < 6; i++)
dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
- printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
- "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
- (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
- (int) readb(ramBase+NETWAVE_EREG_NI+1));
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx"
+ "id %c%c, hw_addr %s\n",
+ dev->name, dev->base_addr, dev->irq,
+ (u_long) ramBase,
+ (int) readb(ramBase+NETWAVE_EREG_NI),
+ (int) readb(ramBase+NETWAVE_EREG_NI+1),
+ print_mac(mac, dev->dev_addr));
/* get revision words */
printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n",
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 062286dc8e15..ca6c2da7bc5d 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2232,6 +2232,7 @@ static int orinoco_init(struct net_device *dev)
struct hermes_idstring nickbuf;
u16 reclen;
int len;
+ DECLARE_MAC_BUF(mac);
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
@@ -2274,10 +2275,8 @@ static int orinoco_init(struct net_device *dev)
goto out;
}
- printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->name, dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5]);
+ printk(KERN_DEBUG "%s: MAC address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
/* Get the station name */
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d1e502236b2a..8b7f5768a103 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -313,7 +313,6 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Ok, we have the configuration, prepare to register the netdev */
dev->base_addr = link->io.BasePort1;
dev->irq = link->irq.AssignedIRQ;
- SET_MODULE_OWNER(dev);
card->node.major = card->node.minor = 0;
SET_NETDEV_DEV(dev, &handle_to_dev(link));
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index eaf3d13b851c..35ec5fcf81a6 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -193,7 +193,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 97a8b4ff32bd..2547d5dac0d3 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -148,7 +148,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 31162ac25a92..98fe165337d1 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -232,7 +232,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 7c7b960c91df..df493185a4af 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -134,7 +134,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
@@ -190,7 +189,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = dev->priv;
+ struct orinoco_private *priv = netdev_priv(dev);
struct orinoco_pci_card *card = priv->card;
unregister_netdev(dev);
diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h
new file mode 100644
index 000000000000..744c866066c5
--- /dev/null
+++ b/drivers/net/wireless/p54.h
@@ -0,0 +1,81 @@
+#ifndef PRISM54_H
+#define PRISM54_H
+
+/*
+ * Shared defines for all mac80211 Prism54 code
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+enum control_frame_types {
+ P54_CONTROL_TYPE_FILTER_SET = 0,
+ P54_CONTROL_TYPE_CHANNEL_CHANGE,
+ P54_CONTROL_TYPE_FREQDONE,
+ P54_CONTROL_TYPE_DCFINIT,
+ P54_CONTROL_TYPE_FREEQUEUE = 7,
+ P54_CONTROL_TYPE_TXDONE,
+ P54_CONTROL_TYPE_PING,
+ P54_CONTROL_TYPE_STAT_READBACK,
+ P54_CONTROL_TYPE_BBP,
+ P54_CONTROL_TYPE_EEPROM_READBACK,
+ P54_CONTROL_TYPE_LED
+};
+
+struct p54_control_hdr {
+ __le16 magic1;
+ __le16 len;
+ __le32 req_id;
+ __le16 type; /* enum control_frame_types */
+ u8 retry1;
+ u8 retry2;
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */)
+#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 )
+
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+struct p54_common {
+ u32 rx_start;
+ u32 rx_end;
+ struct sk_buff_head tx_queue;
+ void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx);
+ int (*open)(struct ieee80211_hw *dev);
+ void (*stop)(struct ieee80211_hw *dev);
+ int mode;
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ struct pda_iq_autocal_entry *iq_autocal;
+ unsigned int iq_autocal_len;
+ struct pda_channel_output_limit *output_limit;
+ unsigned int output_limit_len;
+ struct pda_pa_curve_data *curve_data;
+ __le16 rxhw;
+ u8 version;
+ unsigned int tx_hdr_len;
+ void *cached_vdcf;
+ unsigned int fw_var;
+ /* FIXME: this channels/modes/rates stuff sucks */
+ struct ieee80211_channel channels[14];
+ struct ieee80211_rate rates[12];
+ struct ieee80211_hw_mode modes[2];
+ struct ieee80211_tx_queue_stats tx_stats;
+};
+
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
+void p54_fill_eeprom_readback(struct p54_control_hdr *hdr);
+struct ieee80211_hw *p54_init_common(size_t priv_data_len);
+void p54_free_common(struct ieee80211_hw *dev);
+
+#endif /* PRISM54_H */
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
new file mode 100644
index 000000000000..2c63cf0ad2cd
--- /dev/null
+++ b/drivers/net/wireless/p54common.c
@@ -0,0 +1,1019 @@
+
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54common.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+ struct p54_common *priv = dev->priv;
+ struct bootrec_exp_if *exp_if;
+ struct bootrec *bootrec;
+ u32 *data = (u32 *)fw->data;
+ u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+ u8 *fw_version = NULL;
+ size_t len;
+ int i;
+
+ if (priv->rx_start)
+ return;
+
+ while (data < end_data && *data)
+ data++;
+
+ while (data < end_data && !*data)
+ data++;
+
+ bootrec = (struct bootrec *) data;
+
+ while (bootrec->data <= end_data &&
+ (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
+ u32 code = le32_to_cpu(bootrec->code);
+ switch (code) {
+ case BR_CODE_COMPONENT_ID:
+ switch (be32_to_cpu(*bootrec->data)) {
+ case FW_FMAC:
+ printk(KERN_INFO "p54: FreeMAC firmware\n");
+ break;
+ case FW_LM20:
+ printk(KERN_INFO "p54: LM20 firmware\n");
+ break;
+ case FW_LM86:
+ printk(KERN_INFO "p54: LM86 firmware\n");
+ break;
+ case FW_LM87:
+ printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+ break;
+ default:
+ printk(KERN_INFO "p54: unknown firmware\n");
+ break;
+ }
+ break;
+ case BR_CODE_COMPONENT_VERSION:
+ /* 24 bytes should be enough for all firmwares */
+ if (strnlen((unsigned char*)bootrec->data, 24) < 24)
+ fw_version = (unsigned char*)bootrec->data;
+ break;
+ case BR_CODE_DESCR:
+ priv->rx_start = le32_to_cpu(bootrec->data[1]);
+ /* FIXME add sanity checking */
+ priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500;
+ break;
+ case BR_CODE_EXPOSED_IF:
+ exp_if = (struct bootrec_exp_if *) bootrec->data;
+ for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+ if (exp_if[i].if_id == 0x1a)
+ priv->fw_var = le16_to_cpu(exp_if[i].variant);
+ break;
+ case BR_CODE_DEPENDENT_IF:
+ break;
+ case BR_CODE_END_OF_BRA:
+ case LEGACY_BR_CODE_END_OF_BRA:
+ end_data = NULL;
+ break;
+ default:
+ break;
+ }
+ bootrec = (struct bootrec *)&bootrec->data[len];
+ }
+
+ if (fw_version)
+ printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
+ fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var >= 0x300) {
+ /* Firmware supports QoS, use it! */
+ priv->tx_stats.data[0].limit = 3;
+ priv->tx_stats.data[1].limit = 4;
+ priv->tx_stats.data[2].limit = 3;
+ priv->tx_stats.data[3].limit = 1;
+ dev->queues = 4;
+ }
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct pda_pa_curve_data_sample_rev1 *rev1;
+ struct pda_pa_curve_data_sample_rev0 *rev0;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*rev1) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = priv->curve_data->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ rev1 = target;
+ rev0 = source;
+
+ rev1->rf_power = rev0->rf_power;
+ rev1->pa_detector = rev0->pa_detector;
+ rev1->data_64qam = rev0->pcv;
+ /* "invent" the points for the other modulations */
+#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
+ rev1->data_16qam = SUB(rev0->pcv, 12);
+ rev1->data_qpsk = SUB(rev1->data_16qam, 12);
+ rev1->data_bpsk = SUB(rev1->data_qpsk, 12);
+ rev1->data_barker= SUB(rev1->data_bpsk, 14);
+#undef SUB
+ target += sizeof(*rev1);
+ source += sizeof(*rev0);
+ }
+ }
+
+ return 0;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+ struct p54_common *priv = dev->priv;
+ struct eeprom_pda_wrap *wrap = NULL;
+ struct pda_entry *entry;
+ int i = 0;
+ unsigned int data_len, entry_len;
+ void *tmp;
+ int err;
+
+ wrap = (struct eeprom_pda_wrap *) eeprom;
+ entry = (void *)wrap->data + wrap->len;
+ i += 2;
+ i += le16_to_cpu(entry->len)*2;
+ while (i < len) {
+ entry_len = le16_to_cpu(entry->len);
+ data_len = ((entry_len - 1) << 1);
+ switch (le16_to_cpu(entry->code)) {
+ case PDR_MAC_ADDRESS:
+ SET_IEEE80211_PERM_ADDR(dev, entry->data);
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+ if (data_len < 2) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ priv->output_limit = kmalloc(entry->data[1] *
+ sizeof(*priv->output_limit), GFP_KERNEL);
+
+ if (!priv->output_limit) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->output_limit, &entry->data[2],
+ entry->data[1]*sizeof(*priv->output_limit));
+ priv->output_limit_len = entry->data[1];
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA:
+ if (data_len < sizeof(struct pda_pa_curve_data)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) {
+ priv->curve_data = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->curve_data) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->curve_data, entry->data, data_len);
+ } else {
+ err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data);
+ if (err)
+ goto err;
+ }
+
+ break;
+ case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+ priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->iq_autocal) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->iq_autocal, entry->data, data_len);
+ priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+ break;
+ case PDR_INTERFACE_LIST:
+ tmp = entry->data;
+ while ((u8 *)tmp < entry->data + data_len) {
+ struct bootrec_exp_if *exp_if = tmp;
+ if (le16_to_cpu(exp_if->if_id) == 0xF)
+ priv->rxhw = exp_if->variant & cpu_to_le16(0x07);
+ tmp += sizeof(struct bootrec_exp_if);
+ }
+ break;
+ case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+ priv->version = *(u8 *)(entry->data + 1);
+ break;
+ case PDR_END:
+ i = len;
+ break;
+ }
+
+ entry = (void *)entry + (entry_len + 1)*2;
+ i += 2;
+ i += entry_len*2;
+ }
+
+ if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {
+ printk(KERN_ERR "p54: not all required entries found in eeprom!\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+ err:
+ if (priv->iq_autocal) {
+ kfree(priv->iq_autocal);
+ priv->iq_autocal = NULL;
+ }
+
+ if (priv->output_limit) {
+ kfree(priv->output_limit);
+ priv->output_limit = NULL;
+ }
+
+ if (priv->curve_data) {
+ kfree(priv->curve_data);
+ priv->curve_data = NULL;
+ }
+
+ printk(KERN_ERR "p54: eeprom parse failed!\n");
+ return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+void p54_fill_eeprom_readback(struct p54_control_hdr *hdr)
+{
+ struct p54_eeprom_lm86 *eeprom_hdr;
+
+ hdr->magic1 = cpu_to_le16(0x8000);
+ hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000);
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
+ hdr->retry1 = hdr->retry2 = 0;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
+ eeprom_hdr->offset = 0x0;
+ eeprom_hdr->len = cpu_to_le16(0x2000);
+}
+EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback);
+
+static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
+ struct ieee80211_rx_status rx_status = {0};
+ u16 freq = le16_to_cpu(hdr->freq);
+
+ rx_status.ssi = hdr->rssi;
+ rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */
+ rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5;
+ rx_status.freq = freq;
+ rx_status.phymode = MODE_IEEE80211G;
+ rx_status.antenna = hdr->antenna;
+ rx_status.mactime = le64_to_cpu(hdr->timestamp);
+
+ skb_pull(skb, sizeof(*hdr));
+ skb_trim(skb, le16_to_cpu(hdr->len));
+
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+}
+
+static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int i;
+
+ /* ieee80211_start_queues is great if all queues are really empty.
+ * But, what if some are full? */
+
+ for (i = 0; i < dev->queues; i++)
+ if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit)
+ ieee80211_wake_queue(dev, i);
+}
+
+static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+ struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
+ struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
+ u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
+ struct memrecord *range = NULL;
+ u32 freed = 0;
+ u32 last_addr = priv->rx_start;
+
+ while (entry != (struct sk_buff *)&priv->tx_queue) {
+ range = (struct memrecord *)&entry->cb;
+ if (range->start_addr == addr) {
+ struct ieee80211_tx_status status = {{0}};
+ struct p54_control_hdr *entry_hdr;
+ struct p54_tx_control_allocdata *entry_data;
+ int pad = 0;
+
+ if (entry->next != (struct sk_buff *)&priv->tx_queue)
+ freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr;
+ else
+ freed = priv->rx_end - last_addr;
+
+ last_addr = range->end_addr;
+ __skb_unlink(entry, &priv->tx_queue);
+ if (!range->control) {
+ kfree_skb(entry);
+ break;
+ }
+ memcpy(&status.control, range->control,
+ sizeof(status.control));
+ kfree(range->control);
+ priv->tx_stats.data[status.control.queue].len--;
+
+ entry_hdr = (struct p54_control_hdr *) entry->data;
+ entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
+ if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
+ pad = entry_data->align[0];
+
+ if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) {
+ if (!(payload->status & 0x01))
+ status.flags |= IEEE80211_TX_STATUS_ACK;
+ else
+ status.excessive_retries = 1;
+ }
+ status.retry_count = payload->retries - 1;
+ status.ack_signal = le16_to_cpu(payload->ack_rssi);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(dev, entry, &status);
+ break;
+ } else
+ last_addr = range->end_addr;
+ entry = entry->next;
+ }
+
+ if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+ sizeof(struct p54_control_hdr))
+ p54_wake_free_queues(dev);
+}
+
+static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+
+ switch (le16_to_cpu(hdr->type)) {
+ case P54_CONTROL_TYPE_TXDONE:
+ p54_rx_frame_sent(dev, skb);
+ break;
+ case P54_CONTROL_TYPE_BBP:
+ break;
+ default:
+ printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+ wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
+ break;
+ }
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+ switch (type) {
+ case 0x00:
+ case 0x01:
+ p54_rx_data(dev, skb);
+ return -1;
+ case 0x4d:
+ /* TODO: do something better... but then again, I've never seen this happen */
+ printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
+ wiphy_name(dev->wiphy));
+ break;
+ case 0x80:
+ p54_rx_control(dev, skb);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n",
+ wiphy_name(dev->wiphy), type);
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees
+ * allocated areas.
+ */
+static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct p54_control_hdr *data, u32 len,
+ struct ieee80211_tx_control *control)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *entry = priv->tx_queue.next;
+ struct sk_buff *target_skb = NULL;
+ struct memrecord *range;
+ u32 last_addr = priv->rx_start;
+ u32 largest_hole = 0;
+ u32 target_addr = priv->rx_start;
+ unsigned long flags;
+ unsigned int left;
+ len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ left = skb_queue_len(&priv->tx_queue);
+ while (left--) {
+ u32 hole_size;
+ range = (struct memrecord *)&entry->cb;
+ hole_size = range->start_addr - last_addr;
+ if (!target_skb && hole_size >= len) {
+ target_skb = entry->prev;
+ hole_size -= len;
+ target_addr = last_addr;
+ }
+ largest_hole = max(largest_hole, hole_size);
+ last_addr = range->end_addr;
+ entry = entry->next;
+ }
+ if (!target_skb && priv->rx_end - last_addr >= len) {
+ target_skb = priv->tx_queue.prev;
+ largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
+ if (!skb_queue_empty(&priv->tx_queue)) {
+ range = (struct memrecord *)&target_skb->cb;
+ target_addr = range->end_addr;
+ }
+ } else
+ largest_hole = max(largest_hole, priv->rx_end - last_addr);
+
+ if (skb) {
+ range = (struct memrecord *)&skb->cb;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ range->control = control;
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+ sizeof(struct p54_control_hdr))
+ ieee80211_stop_queues(dev);
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+ data->req_id = cpu_to_le32(target_addr + 0x70);
+}
+
+static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_tx_queue_stats_data *current_queue;
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_allocdata *txhdr;
+ struct ieee80211_tx_control *control_copy;
+ size_t padding, len;
+ u8 rate;
+
+ current_queue = &priv->tx_stats.data[control->queue];
+ if (unlikely(current_queue->len > current_queue->limit))
+ return NETDEV_TX_BUSY;
+ current_queue->len++;
+ current_queue->count++;
+ if (current_queue->len == current_queue->limit)
+ ieee80211_stop_queue(dev, control->queue);
+
+ padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+ len = skb->len;
+
+ control_copy = kmalloc(sizeof(*control), GFP_ATOMIC);
+ if (control_copy)
+ memcpy(control_copy, control, sizeof(*control));
+
+ txhdr = (struct p54_tx_control_allocdata *)
+ skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
+
+ if (padding)
+ hdr->magic1 = cpu_to_le16(0x4010);
+ else
+ hdr->magic1 = cpu_to_le16(0x0010);
+ hdr->len = cpu_to_le16(len);
+ hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1);
+ hdr->retry1 = hdr->retry2 = control->retry_limit;
+ p54_assign_address(dev, skb, hdr, skb->len, control_copy);
+
+ memset(txhdr->wep_key, 0x0, 16);
+ txhdr->padding = 0;
+ txhdr->padding2 = 0;
+
+ /* TODO: add support for alternate retry TX rates */
+ rate = control->tx_rate;
+ if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ rate |= 0x40;
+ else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ rate |= 0x20;
+ memset(txhdr->rateset, rate, 8);
+ txhdr->wep_key_present = 0;
+ txhdr->wep_key_len = 0;
+ txhdr->frame_type = cpu_to_le32(control->queue + 4);
+ txhdr->magic4 = 0;
+ txhdr->antenna = (control->antenna_sel_tx == 0) ?
+ 2 : control->antenna_sel_tx - 1;
+ txhdr->output_power = 0x7f; // HW Maximum
+ txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+ 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
+ if (padding)
+ txhdr->align[0] = padding;
+
+ priv->tx(dev, hdr, skb->len, 0);
+ return 0;
+}
+
+static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
+ const u8 *dst, const u8 *src, u8 antenna,
+ u32 magic3, u32 magic8, u32 magic9)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_filter *filter;
+
+ hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
+ priv->tx_hdr_len, GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+
+ filter = (struct p54_tx_control_filter *) hdr->data;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*filter));
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL);
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
+
+ filter->filter_type = cpu_to_le16(filter_type);
+ memcpy(filter->dst, dst, ETH_ALEN);
+ if (!src)
+ memset(filter->src, ~0, ETH_ALEN);
+ else
+ memcpy(filter->src, src, ETH_ALEN);
+ filter->antenna = antenna;
+ filter->magic3 = cpu_to_le32(magic3);
+ filter->rx_addr = cpu_to_le32(priv->rx_end);
+ filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */
+ filter->rxhw = priv->rxhw;
+ filter->magic8 = cpu_to_le16(magic8);
+ filter->magic9 = cpu_to_le16(magic9);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1);
+ return 0;
+}
+
+static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_channel *chan;
+ unsigned int i;
+ size_t payload_len = sizeof(*chan) + sizeof(u32)*2 +
+ sizeof(*chan->curve_data) *
+ priv->curve_data->points_per_channel;
+ void *entry;
+
+ hdr = kzalloc(sizeof(*hdr) + payload_len +
+ priv->tx_hdr_len, GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+
+ chan = (struct p54_tx_control_channel *) hdr->data;
+
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*chan));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL);
+
+ chan->magic1 = cpu_to_le16(0x1);
+ chan->magic2 = cpu_to_le16(0x0);
+
+ for (i = 0; i < priv->iq_autocal_len; i++) {
+ if (priv->iq_autocal[i].freq != freq)
+ continue;
+
+ memcpy(&chan->iq_autocal, &priv->iq_autocal[i],
+ sizeof(*priv->iq_autocal));
+ break;
+ }
+ if (i == priv->iq_autocal_len)
+ goto err;
+
+ for (i = 0; i < priv->output_limit_len; i++) {
+ if (priv->output_limit[i].freq != freq)
+ continue;
+
+ chan->val_barker = 0x38;
+ chan->val_bpsk = priv->output_limit[i].val_bpsk;
+ chan->val_qpsk = priv->output_limit[i].val_qpsk;
+ chan->val_16qam = priv->output_limit[i].val_16qam;
+ chan->val_64qam = priv->output_limit[i].val_64qam;
+ break;
+ }
+ if (i == priv->output_limit_len)
+ goto err;
+
+ chan->pa_points_per_curve = priv->curve_data->points_per_channel;
+
+ entry = priv->curve_data->data;
+ for (i = 0; i < priv->curve_data->channels; i++) {
+ if (*((__le16 *)entry) != freq) {
+ entry += sizeof(__le16);
+ entry += sizeof(struct pda_pa_curve_data_sample_rev1) *
+ chan->pa_points_per_curve;
+ continue;
+ }
+
+ entry += sizeof(__le16);
+ memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
+ chan->pa_points_per_curve);
+ break;
+ }
+
+ memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1);
+ return 0;
+
+ err:
+ printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
+ kfree(hdr);
+ return -EINVAL;
+}
+
+static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_led *led;
+
+ hdr = kzalloc(sizeof(*hdr) + sizeof(*led) +
+ priv->tx_hdr_len, GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*led));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL);
+
+ led = (struct p54_tx_control_led *) hdr->data;
+ led->mode = cpu_to_le16(mode);
+ led->led_permanent = cpu_to_le16(link);
+ led->led_temporary = cpu_to_le16(act);
+ led->duration = cpu_to_le16(1000);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1);
+
+ return 0;
+}
+
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \
+do { \
+ queue.aifs = cpu_to_le16(ai_fs); \
+ queue.cwmin = cpu_to_le16(cw_min); \
+ queue.cwmax = cpu_to_le16(cw_max); \
+ queue.txop = (burst == 0) ? \
+ 0 : cpu_to_le16((burst * 100) / 32 + 1); \
+} while(0)
+
+static void p54_init_vdcf(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_vdcf *vdcf;
+
+ /* all USB V1 adapters need a extra headroom */
+ hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*vdcf));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT);
+ hdr->req_id = cpu_to_le32(priv->rx_start);
+
+ vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+
+ P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f);
+ P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e);
+ P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014);
+ P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000);
+}
+
+static void p54_set_vdcf(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_vdcf *vdcf;
+
+ hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL);
+
+ vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+
+ if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+ vdcf->slottime = 9;
+ vdcf->magic1 = 0x00;
+ vdcf->magic2 = 0x10;
+ } else {
+ vdcf->slottime = 20;
+ vdcf->magic1 = 0x0a;
+ vdcf->magic2 = 0x06;
+ }
+
+ /* (see prism54/isl_oid.h for further details) */
+ vdcf->frameburst = cpu_to_le16(0);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ err = priv->open(dev);
+ if (!err)
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+
+ return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&priv->tx_queue))) {
+ struct memrecord *range = (struct memrecord *)&skb->cb;
+ if (range->control)
+ kfree(range->control);
+ kfree_skb(skb);
+ }
+ priv->stop(dev);
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->mode = conf->type;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
+ p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
+ break;
+ default:
+ BUG(); /* impossible */
+ break;
+ }
+
+ p54_set_leds(dev, 1, 0, 0);
+
+ return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+ memset(priv->mac_addr, 0, ETH_ALEN);
+ p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
+}
+
+static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ int ret;
+
+ ret = p54_set_freq(dev, cpu_to_le16(conf->freq));
+ p54_set_vdcf(dev);
+ return ret;
+}
+
+static int p54_config_interface(struct ieee80211_hw *dev, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
+ p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
+ p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ return 0;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ struct p54_common *priv = dev->priv;
+
+ *total_flags &= FIF_BCN_PRBRESP_PROMISC;
+
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ p54_set_filter(dev, 0, priv->mac_addr,
+ NULL, 2, 0, 0, 0);
+ else
+ p54_set_filter(dev, 0, priv->mac_addr,
+ priv->bssid, 2, 0, 0, 0);
+ }
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_tx_control_vdcf *vdcf;
+
+ vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
+ ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
+
+ if ((params) && !((queue < 0) || (queue > 4))) {
+ P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
+ params->cw_min, params->cw_max, params->burst_time);
+ } else
+ return -EINVAL;
+
+ p54_set_vdcf(dev);
+
+ return 0;
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ /* TODO */
+ return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < dev->queues; i++)
+ memcpy(&stats->data[i], &priv->tx_stats.data[i],
+ sizeof(stats->data[i]));
+
+ return 0;
+}
+
+static const struct ieee80211_ops p54_ops = {
+ .tx = p54_tx,
+ .start = p54_start,
+ .stop = p54_stop,
+ .add_interface = p54_add_interface,
+ .remove_interface = p54_remove_interface,
+ .config = p54_config,
+ .config_interface = p54_config_interface,
+ .configure_filter = p54_configure_filter,
+ .conf_tx = p54_conf_tx,
+ .get_stats = p54_get_stats,
+ .get_tx_stats = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+ struct ieee80211_hw *dev;
+ struct p54_common *priv;
+ int i;
+
+ dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+ if (!dev)
+ return NULL;
+
+ priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+ skb_queue_head_init(&priv->tx_queue);
+ memcpy(priv->channels, p54_channels, sizeof(p54_channels));
+ memcpy(priv->rates, p54_rates, sizeof(p54_rates));
+ priv->modes[1].mode = MODE_IEEE80211B;
+ priv->modes[1].num_rates = 4;
+ priv->modes[1].rates = priv->rates;
+ priv->modes[1].num_channels = ARRAY_SIZE(p54_channels);
+ priv->modes[1].channels = priv->channels;
+ priv->modes[0].mode = MODE_IEEE80211G;
+ priv->modes[0].num_rates = ARRAY_SIZE(p54_rates);
+ priv->modes[0].rates = priv->rates;
+ priv->modes[0].num_channels = ARRAY_SIZE(p54_channels);
+ priv->modes[0].channels = priv->channels;
+ dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
+ IEEE80211_HW_RX_INCLUDES_FCS;
+ dev->channel_change_time = 1000; /* TODO: find actual value */
+ dev->max_rssi = 127;
+
+ priv->tx_stats.data[0].limit = 5;
+ dev->queues = 1;
+
+ dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
+ sizeof(struct p54_tx_control_allocdata);
+
+ priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) +
+ priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
+
+ if (!priv->cached_vdcf) {
+ ieee80211_free_hw(dev);
+ return NULL;
+ }
+
+ p54_init_vdcf(dev);
+
+ for (i = 0; i < 2; i++) {
+ if (ieee80211_register_hwmode(dev, &priv->modes[i])) {
+ kfree(priv->cached_vdcf);
+ ieee80211_free_hw(dev);
+ return NULL;
+ }
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ kfree(priv->cached_vdcf);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+static int __init p54_init(void)
+{
+ return 0;
+}
+
+static void __exit p54_exit(void)
+{
+}
+
+module_init(p54_init);
+module_exit(p54_exit);
diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h
new file mode 100644
index 000000000000..a721334e20d9
--- /dev/null
+++ b/drivers/net/wireless/p54common.h
@@ -0,0 +1,329 @@
+#ifndef PRISM54COMMON_H
+#define PRISM54COMMON_H
+
+/*
+ * Common code specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+struct bootrec {
+ __le32 code;
+ __le32 len;
+ u32 data[0];
+} __attribute__((packed));
+
+struct bootrec_exp_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+ __le16 btm_compat;
+ __le16 top_compat;
+} __attribute__((packed));
+
+#define BR_CODE_MIN 0x80000000
+#define BR_CODE_COMPONENT_ID 0x80000001
+#define BR_CODE_COMPONENT_VERSION 0x80000002
+#define BR_CODE_DEPENDENT_IF 0x80000003
+#define BR_CODE_EXPOSED_IF 0x80000004
+#define BR_CODE_DESCR 0x80000101
+#define BR_CODE_MAX 0x8FFFFFFF
+#define BR_CODE_END_OF_BRA 0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+ __le16 len; /* includes both code and data */
+ __le16 code;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct eeprom_pda_wrap {
+ u32 magic;
+ u16 pad;
+ u16 len;
+ u32 arm_opcode;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct pda_iq_autocal_entry {
+ __le16 freq;
+ __le16 iq_param[4];
+} __attribute__ ((packed));
+
+struct pda_channel_output_limit {
+ __le16 freq;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ u8 rate_set_mask;
+ u8 rate_set_size;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data_sample_rev0 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 pcv;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data_sample_rev1 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+ u8 padding;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data {
+ u8 cal_method_rev;
+ u8 channels;
+ u8 points_per_channel;
+ u8 padding;
+ u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END 0x0000
+#define PDR_MANUFACTURING_PART_NUMBER 0x0001
+#define PDR_PDA_VERSION 0x0002
+#define PDR_NIC_SERIAL_NUMBER 0x0003
+
+#define PDR_MAC_ADDRESS 0x0101
+#define PDR_REGULATORY_DOMAIN_LIST 0x0103
+#define PDR_TEMPERATURE_TYPE 0x0107
+
+#define PDR_PRISM_PCI_IDENTIFIER 0x0402
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION 0x1000
+#define PDR_INTERFACE_LIST 0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
+#define PDR_OEM_NAME 0x1003
+#define PDR_PRODUCT_NAME 0x1004
+#define PDR_UTF8_OEM_NAME 0x1005
+#define PDR_UTF8_PRODUCT_NAME 0x1006
+#define PDR_COUNTRY_LIST 0x1007
+#define PDR_DEFAULT_COUNTRY 0x1008
+
+#define PDR_ANTENNA_GAIN 0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
+#define PDR_REGULATORY_POWER_LIMITS 0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS 0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+
+/* stored in skb->cb */
+struct memrecord {
+ u32 start_addr;
+ u32 end_addr;
+ struct ieee80211_tx_control *control;
+};
+
+struct p54_eeprom_lm86 {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct p54_rx_hdr {
+ __le16 magic;
+ __le16 len;
+ __le16 freq;
+ u8 antenna;
+ u8 rate;
+ u8 rssi;
+ u8 quality;
+ u16 unknown2;
+ __le64 timestamp;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct p54_frame_sent_hdr {
+ u8 status;
+ u8 retries;
+ __le16 ack_rssi;
+ __le16 seq;
+ u16 rate;
+} __attribute__ ((packed));
+
+struct p54_tx_control_allocdata {
+ u8 rateset[8];
+ u16 padding;
+ u8 wep_key_present;
+ u8 wep_key_len;
+ u8 wep_key[16];
+ __le32 frame_type;
+ u32 padding2;
+ __le16 magic4;
+ u8 antenna;
+ u8 output_power;
+ __le32 magic5;
+ u8 align[0];
+} __attribute__ ((packed));
+
+struct p54_tx_control_filter {
+ __le16 filter_type;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 antenna;
+ u8 debug;
+ __le32 magic3;
+ u8 rates[8]; // FIXME: what's this for?
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 magic8;
+ __le16 magic9;
+} __attribute__ ((packed));
+
+struct p54_tx_control_channel {
+ __le16 magic1;
+ __le16 magic2;
+ u8 padding1[20];
+ struct pda_iq_autocal_entry iq_autocal;
+ u8 pa_points_per_curve;
+ u8 val_barker;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ struct pda_pa_curve_data_sample_rev1 curve_data[0];
+ /* additional padding/data after curve_data */
+} __attribute__ ((packed));
+
+struct p54_tx_control_led {
+ __le16 mode;
+ __le16 led_temporary;
+ __le16 led_permanent;
+ __le16 duration;
+} __attribute__ ((packed));
+
+struct p54_tx_vdcf_queues {
+ __le16 aifs;
+ __le16 cwmin;
+ __le16 cwmax;
+ __le16 txop;
+} __attribute__ ((packed));
+
+struct p54_tx_control_vdcf {
+ u8 padding;
+ u8 slottime;
+ u8 magic1;
+ u8 magic2;
+ struct p54_tx_vdcf_queues queue[8];
+ u8 pad2[4];
+ __le16 frameburst;
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate p54_rates[] = {
+ { .rate = 10,
+ .val = 0,
+ .val2 = 0x10,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 20,
+ .val = 1,
+ .val2 = 0x11,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 55,
+ .val = 2,
+ .val2 = 0x12,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 110,
+ .val = 3,
+ .val2 = 0x13,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 60,
+ .val = 4,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 90,
+ .val = 5,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 120,
+ .val = 6,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 180,
+ .val = 7,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 240,
+ .val = 8,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 360,
+ .val = 9,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 480,
+ .val = 10,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 540,
+ .val = 11,
+ .flags = IEEE80211_RATE_OFDM },
+};
+
+// TODO: just generate this..
+static const struct ieee80211_channel p54_channels[] = {
+ { .chan = 1,
+ .freq = 2412},
+ { .chan = 2,
+ .freq = 2417},
+ { .chan = 3,
+ .freq = 2422},
+ { .chan = 4,
+ .freq = 2427},
+ { .chan = 5,
+ .freq = 2432},
+ { .chan = 6,
+ .freq = 2437},
+ { .chan = 7,
+ .freq = 2442},
+ { .chan = 8,
+ .freq = 2447},
+ { .chan = 9,
+ .freq = 2452},
+ { .chan = 10,
+ .freq = 2457},
+ { .chan = 11,
+ .freq = 2462},
+ { .chan = 12,
+ .freq = 2467},
+ { .chan = 13,
+ .freq = 2472},
+ { .chan = 14,
+ .freq = 2484}
+};
+
+#endif /* PRISM54COMMON_H */
diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c
new file mode 100644
index 000000000000..410b54387f23
--- /dev/null
+++ b/drivers/net/wireless/p54pci.c
@@ -0,0 +1,692 @@
+
+/*
+ * Linux device driver for PCI based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54pci.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 PCI wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54pci");
+
+static struct pci_device_id p54p_table[] __devinitdata = {
+ /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
+ { PCI_DEVICE(0x1260, 0x3890) },
+ /* 3COM 3CRWE154G72 Wireless LAN adapter */
+ { PCI_DEVICE(0x10b7, 0x6001) },
+ /* Intersil PRISM Indigo Wireless LAN adapter */
+ { PCI_DEVICE(0x1260, 0x3877) },
+ /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */
+ { PCI_DEVICE(0x1260, 0x3886) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, p54p_table);
+
+static int p54p_upload_firmware(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ const struct firmware *fw_entry = NULL;
+ __le32 reg;
+ int err;
+ u32 *data;
+ u32 remains, left, device_addr;
+
+ P54P_WRITE(int_enable, 0);
+ P54P_READ(int_enable);
+ udelay(10);
+
+ reg = P54P_READ(ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+ P54P_WRITE(ctrl_stat, reg);
+ P54P_READ(ctrl_stat);
+ udelay(10);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+ udelay(10);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+
+ mdelay(50);
+
+ err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): cannot find firmware "
+ "(isl3886)\n", pci_name(priv->pdev));
+ return err;
+ }
+
+ p54_parse_firmware(dev, fw_entry);
+
+ data = (u32 *) fw_entry->data;
+ remains = fw_entry->size;
+ device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
+ while (remains) {
+ u32 i = 0;
+ left = min((u32)0x1000, remains);
+ P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr));
+ P54P_READ(int_enable);
+
+ device_addr += 0x1000;
+ while (i < left) {
+ P54P_WRITE(direct_mem_win[i], *data++);
+ i += sizeof(u32);
+ }
+
+ remains -= left;
+ P54P_READ(int_enable);
+ }
+
+ release_firmware(fw_entry);
+
+ reg = P54P_READ(ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+ P54P_WRITE(ctrl_stat, reg);
+ P54P_READ(ctrl_stat);
+ udelay(10);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+ udelay(10);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+ udelay(10);
+
+ return 0;
+}
+
+static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id)
+{
+ struct p54p_priv *priv = (struct p54p_priv *) dev_id;
+ __le32 reg;
+
+ reg = P54P_READ(int_ident);
+ P54P_WRITE(int_ack, reg);
+
+ if (reg & P54P_READ(int_enable))
+ complete(&priv->boot_comp);
+
+ return IRQ_HANDLED;
+}
+
+static int p54p_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ int err;
+ struct p54_control_hdr *hdr;
+ void *eeprom;
+ dma_addr_t rx_mapping, tx_mapping;
+ u16 alen;
+
+ init_completion(&priv->boot_comp);
+ err = request_irq(priv->pdev->irq, &p54p_simple_interrupt,
+ IRQF_SHARED, "prism54pci", priv);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n",
+ pci_name(priv->pdev));
+ return err;
+ }
+
+ eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL);
+ if (!eeprom) {
+ printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n",
+ pci_name(priv->pdev));
+ err = -ENOMEM;
+ goto out;
+ }
+
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+ P54P_WRITE(ring_control_base, priv->ring_control_dma);
+ P54P_READ(ring_control_base);
+ udelay(10);
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+ P54P_READ(int_enable);
+ udelay(10);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+ if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+ printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n",
+ pci_name(priv->pdev));
+ err = -EINVAL;
+ goto out;
+ }
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+ P54P_READ(int_enable);
+
+ hdr = eeprom + 0x2010;
+ p54_fill_eeprom_readback(hdr);
+ hdr->req_id = cpu_to_le32(priv->common.rx_start);
+
+ rx_mapping = pci_map_single(priv->pdev, eeprom,
+ 0x2010, PCI_DMA_FROMDEVICE);
+ tx_mapping = pci_map_single(priv->pdev, (void *)hdr,
+ EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
+
+ priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
+ priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
+ priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
+ priv->ring_control->tx_data[0].device_addr = hdr->req_id;
+ priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
+
+ priv->ring_control->host_idx[2] = cpu_to_le32(1);
+ priv->ring_control->host_idx[1] = cpu_to_le32(1);
+
+ wmb();
+ mdelay(100);
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+
+ wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
+ wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
+
+ pci_unmap_single(priv->pdev, tx_mapping,
+ EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
+ pci_unmap_single(priv->pdev, rx_mapping,
+ 0x2010, PCI_DMA_FROMDEVICE);
+
+ alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len);
+ if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 ||
+ alen < 0x10) {
+ printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n",
+ pci_name(priv->pdev));
+ err = -EINVAL;
+ goto out;
+ }
+
+ p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10);
+
+ out:
+ kfree(eeprom);
+ P54P_WRITE(int_enable, 0);
+ P54P_READ(int_enable);
+ udelay(10);
+ free_irq(priv->pdev->irq, priv);
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+ return err;
+}
+
+static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ u32 limit, host_idx, idx;
+
+ host_idx = le32_to_cpu(priv->ring_control->host_idx[0]);
+ limit = host_idx;
+ limit -= le32_to_cpu(priv->ring_control->device_idx[0]);
+ limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit;
+
+ idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data);
+ while (limit-- > 1) {
+ struct p54p_desc *desc = &priv->ring_control->rx_data[idx];
+
+ if (!desc->host_addr) {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ skb = dev_alloc_skb(MAX_RX_SIZE);
+ if (!skb)
+ break;
+
+ mapping = pci_map_single(priv->pdev,
+ skb_tail_pointer(skb),
+ MAX_RX_SIZE,
+ PCI_DMA_FROMDEVICE);
+ desc->host_addr = cpu_to_le32(mapping);
+ desc->device_addr = 0; // FIXME: necessary?
+ desc->len = cpu_to_le16(MAX_RX_SIZE);
+ desc->flags = 0;
+ priv->rx_buf[idx] = skb;
+ }
+
+ idx++;
+ host_idx++;
+ idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+ }
+
+ wmb();
+ priv->ring_control->host_idx[0] = cpu_to_le32(host_idx);
+}
+
+static irqreturn_t p54p_interrupt(int irq, void *dev_id)
+{
+ struct ieee80211_hw *dev = dev_id;
+ struct p54p_priv *priv = dev->priv;
+ __le32 reg;
+
+ spin_lock(&priv->lock);
+ reg = P54P_READ(int_ident);
+ if (unlikely(reg == 0xFFFFFFFF)) {
+ spin_unlock(&priv->lock);
+ return IRQ_HANDLED;
+ }
+
+ P54P_WRITE(int_ack, reg);
+
+ reg &= P54P_READ(int_enable);
+
+ if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) {
+ struct p54p_desc *desc;
+ u32 idx, i;
+ i = priv->tx_idx;
+ i %= ARRAY_SIZE(priv->ring_control->tx_data);
+ priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]);
+ idx %= ARRAY_SIZE(priv->ring_control->tx_data);
+
+ while (i != idx) {
+ desc = &priv->ring_control->tx_data[i];
+ if (priv->tx_buf[i]) {
+ kfree(priv->tx_buf[i]);
+ priv->tx_buf[i] = NULL;
+ }
+
+ pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+ le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+ desc->host_addr = 0;
+ desc->device_addr = 0;
+ desc->len = 0;
+ desc->flags = 0;
+
+ i++;
+ i %= ARRAY_SIZE(priv->ring_control->tx_data);
+ }
+
+ i = priv->rx_idx;
+ i %= ARRAY_SIZE(priv->ring_control->rx_data);
+ priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]);
+ idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+ while (i != idx) {
+ u16 len;
+ struct sk_buff *skb;
+ desc = &priv->ring_control->rx_data[i];
+ len = le16_to_cpu(desc->len);
+ skb = priv->rx_buf[i];
+
+ skb_put(skb, len);
+
+ if (p54_rx(dev, skb)) {
+ pci_unmap_single(priv->pdev,
+ le32_to_cpu(desc->host_addr),
+ MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+
+ priv->rx_buf[i] = NULL;
+ desc->host_addr = 0;
+ } else {
+ skb_trim(skb, 0);
+ desc->len = cpu_to_le16(MAX_RX_SIZE);
+ }
+
+ i++;
+ i %= ARRAY_SIZE(priv->ring_control->rx_data);
+ }
+
+ p54p_refill_rx_ring(dev);
+
+ wmb();
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+ } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
+ complete(&priv->boot_comp);
+
+ spin_unlock(&priv->lock);
+
+ return reg ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54p_priv *priv = dev->priv;
+ unsigned long flags;
+ struct p54p_desc *desc;
+ dma_addr_t mapping;
+ u32 device_idx, idx, i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ device_idx = le32_to_cpu(priv->ring_control->device_idx[1]);
+ idx = le32_to_cpu(priv->ring_control->host_idx[1]);
+ i = idx % ARRAY_SIZE(priv->ring_control->tx_data);
+
+ mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
+ desc = &priv->ring_control->tx_data[i];
+ desc->host_addr = cpu_to_le32(mapping);
+ desc->device_addr = data->req_id;
+ desc->len = cpu_to_le16(len);
+ desc->flags = 0;
+
+ wmb();
+ priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1);
+
+ if (free_on_tx)
+ priv->tx_buf[i] = data;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+ P54P_READ(dev_int);
+
+ /* FIXME: unlikely to happen because the device usually runs out of
+ memory before we fill the ring up, but we can make it impossible */
+ if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2)
+ printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
+}
+
+static int p54p_open(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ int err;
+
+ init_completion(&priv->boot_comp);
+ err = request_irq(priv->pdev->irq, &p54p_interrupt,
+ IRQF_SHARED, "prism54pci", dev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to register IRQ handler\n",
+ wiphy_name(dev->wiphy));
+ return err;
+ }
+
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+ priv->rx_idx = priv->tx_idx = 0;
+ p54p_refill_rx_ring(dev);
+
+ p54p_upload_firmware(dev);
+
+ P54P_WRITE(ring_control_base, priv->ring_control_dma);
+ P54P_READ(ring_control_base);
+ wmb();
+ udelay(10);
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+ P54P_READ(int_enable);
+ wmb();
+ udelay(10);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+ P54P_READ(dev_int);
+
+ if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+ printk(KERN_ERR "%s: Cannot boot firmware!\n",
+ wiphy_name(dev->wiphy));
+ free_irq(priv->pdev->irq, dev);
+ return -ETIMEDOUT;
+ }
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+ P54P_READ(int_enable);
+ wmb();
+ udelay(10);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+ P54P_READ(dev_int);
+ wmb();
+ udelay(10);
+
+ return 0;
+}
+
+static void p54p_stop(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ unsigned int i;
+ struct p54p_desc *desc;
+
+ P54P_WRITE(int_enable, 0);
+ P54P_READ(int_enable);
+ udelay(10);
+
+ free_irq(priv->pdev->irq, dev);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+ for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) {
+ desc = &priv->ring_control->rx_data[i];
+ if (desc->host_addr)
+ pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+ MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+ kfree_skb(priv->rx_buf[i]);
+ priv->rx_buf[i] = NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) {
+ desc = &priv->ring_control->tx_data[i];
+ if (desc->host_addr)
+ pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+ le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+ kfree(priv->tx_buf[i]);
+ priv->tx_buf[i] = NULL;
+ }
+
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+}
+
+static int __devinit p54p_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct p54p_priv *priv;
+ struct ieee80211_hw *dev;
+ unsigned long mem_addr, mem_len;
+ int err;
+ DECLARE_MAC_BUF(mac);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ mem_addr = pci_resource_start(pdev, 0);
+ mem_len = pci_resource_len(pdev, 0);
+ if (mem_len < sizeof(struct p54p_csr)) {
+ printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n",
+ pci_name(pdev));
+ pci_disable_device(pdev);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, "prism54pci");
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n",
+ pci_name(pdev));
+ goto err_free_reg;
+ }
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ pci_write_config_byte(pdev, 0x40, 0);
+ pci_write_config_byte(pdev, 0x41, 0);
+
+ dev = p54_init_common(sizeof(*priv));
+ if (!dev) {
+ printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_free_reg;
+ }
+
+ priv = dev->priv;
+ priv->pdev = pdev;
+
+ SET_IEEE80211_DEV(dev, &pdev->dev);
+ pci_set_drvdata(pdev, dev);
+
+ priv->map = ioremap(mem_addr, mem_len);
+ if (!priv->map) {
+ printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n",
+ pci_name(pdev));
+ err = -EINVAL; // TODO: use a better error code?
+ goto err_free_dev;
+ }
+
+ priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
+ &priv->ring_control_dma);
+ if (!priv->ring_control) {
+ printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_iounmap;
+ }
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+
+ err = p54p_upload_firmware(dev);
+ if (err)
+ goto err_free_desc;
+
+ err = p54p_read_eeprom(dev);
+ if (err)
+ goto err_free_desc;
+
+ priv->common.open = p54p_open;
+ priv->common.stop = p54p_stop;
+ priv->common.tx = p54p_tx;
+
+ spin_lock_init(&priv->lock);
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n",
+ pci_name(pdev));
+ goto err_free_common;
+ }
+
+ printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
+ wiphy_name(dev->wiphy),
+ print_mac(mac, dev->wiphy->perm_addr),
+ priv->common.version);
+
+ return 0;
+
+ err_free_common:
+ p54_free_common(dev);
+
+ err_free_desc:
+ pci_free_consistent(pdev, sizeof(*priv->ring_control),
+ priv->ring_control, priv->ring_control_dma);
+
+ err_iounmap:
+ iounmap(priv->map);
+
+ err_free_dev:
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(dev);
+
+ err_free_reg:
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void __devexit p54p_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct p54p_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+ priv = dev->priv;
+ pci_free_consistent(pdev, sizeof(*priv->ring_control),
+ priv->ring_control, priv->ring_control_dma);
+ p54_free_common(dev);
+ iounmap(priv->map);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(dev);
+}
+
+#ifdef CONFIG_PM
+static int p54p_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct p54p_priv *priv = dev->priv;
+
+ if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+ ieee80211_stop_queues(dev);
+ p54p_stop(dev);
+ }
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int p54p_resume(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct p54p_priv *priv = dev->priv;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+ p54p_open(dev);
+ ieee80211_start_queues(dev);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver p54p_driver = {
+ .name = "prism54pci",
+ .id_table = p54p_table,
+ .probe = p54p_probe,
+ .remove = __devexit_p(p54p_remove),
+#ifdef CONFIG_PM
+ .suspend = p54p_suspend,
+ .resume = p54p_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init p54p_init(void)
+{
+ return pci_register_driver(&p54p_driver);
+}
+
+static void __exit p54p_exit(void)
+{
+ pci_unregister_driver(&p54p_driver);
+}
+
+module_init(p54p_init);
+module_exit(p54p_exit);
diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h
new file mode 100644
index 000000000000..52feb597dc4a
--- /dev/null
+++ b/drivers/net/wireless/p54pci.h
@@ -0,0 +1,106 @@
+#ifndef PRISM54PCI_H
+#define PRISM54PCI_H
+
+/*
+ * Defines for PCI based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+/* Device Interrupt register bits */
+#define ISL38XX_DEV_INT_RESET 0x0001
+#define ISL38XX_DEV_INT_UPDATE 0x0002
+#define ISL38XX_DEV_INT_WAKEUP 0x0008
+#define ISL38XX_DEV_INT_SLEEP 0x0010
+#define ISL38XX_DEV_INT_ABORT 0x0020
+/* these two only used in USB */
+#define ISL38XX_DEV_INT_DATA 0x0040
+#define ISL38XX_DEV_INT_MGMT 0x0080
+
+#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000
+#define ISL38XX_DEV_INT_PCIUART_DR 0x8000
+
+/* Interrupt Identification/Acknowledge/Enable register bits */
+#define ISL38XX_INT_IDENT_UPDATE 0x0002
+#define ISL38XX_INT_IDENT_INIT 0x0004
+#define ISL38XX_INT_IDENT_WAKEUP 0x0008
+#define ISL38XX_INT_IDENT_SLEEP 0x0010
+#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000
+#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000
+
+/* Control/Status register bits */
+#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
+#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
+#define ISL38XX_CTRL_STAT_RESET 0x10000000
+#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000
+#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000
+#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000
+
+struct p54p_csr {
+ __le32 dev_int;
+ u8 unused_1[12];
+ __le32 int_ident;
+ __le32 int_ack;
+ __le32 int_enable;
+ u8 unused_2[4];
+ union {
+ __le32 ring_control_base;
+ __le32 gen_purp_com[2];
+ };
+ u8 unused_3[8];
+ __le32 direct_mem_base;
+ u8 unused_4[44];
+ __le32 dma_addr;
+ __le32 dma_len;
+ __le32 dma_ctrl;
+ u8 unused_5[12];
+ __le32 ctrl_stat;
+ u8 unused_6[1924];
+ u8 cardbus_cis[0x800];
+ u8 direct_mem_win[0x1000];
+} __attribute__ ((packed));
+
+/* usb backend only needs the register defines above */
+#ifndef PRISM54USB_H
+struct p54p_desc {
+ __le32 host_addr;
+ __le32 device_addr;
+ __le16 len;
+ __le16 flags;
+} __attribute__ ((packed));
+
+struct p54p_ring_control {
+ __le32 host_idx[4];
+ __le32 device_idx[4];
+ struct p54p_desc rx_data[8];
+ struct p54p_desc tx_data[32];
+ struct p54p_desc rx_mgmt[4];
+ struct p54p_desc tx_mgmt[4];
+} __attribute__ ((packed));
+
+#define P54P_READ(r) __raw_readl(&priv->map->r)
+#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r)
+
+struct p54p_priv {
+ struct p54_common common;
+ struct pci_dev *pdev;
+ struct p54p_csr __iomem *map;
+
+ spinlock_t lock;
+ struct p54p_ring_control *ring_control;
+ dma_addr_t ring_control_dma;
+ u32 rx_idx, tx_idx;
+ struct sk_buff *rx_buf[8];
+ void *tx_buf[32];
+ struct completion boot_comp;
+};
+
+#endif /* PRISM54USB_H */
+#endif /* PRISM54PCI_H */
diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c
new file mode 100644
index 000000000000..755482a5a938
--- /dev/null
+++ b/drivers/net/wireless/p54usb.c
@@ -0,0 +1,907 @@
+
+/*
+ * Linux device driver for USB based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54usb.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 USB wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54usb");
+
+static struct usb_device_id p54u_table[] __devinitdata = {
+ /* Version 1 devices (pci chip + net2280) */
+ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
+ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
+ {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
+ {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
+ {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
+ {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
+ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
+ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
+ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
+ {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
+ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
+ {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
+ {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
+ {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
+
+ /* Version 2 devices (3887) */
+ {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
+ {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
+ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
+ {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
+ {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
+ {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
+ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
+ {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
+ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
+ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
+ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
+ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
+ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
+ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
+ {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, p54u_table);
+
+static void p54u_rx_cb(struct urb *urb)
+{
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
+ struct ieee80211_hw *dev = info->dev;
+ struct p54u_priv *priv = dev->priv;
+
+ if (unlikely(urb->status)) {
+ info->urb = NULL;
+ usb_free_urb(urb);
+ return;
+ }
+
+ skb_unlink(skb, &priv->rx_queue);
+ skb_put(skb, urb->actual_length);
+ if (!priv->hw_type)
+ skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+ if (p54_rx(dev, skb)) {
+ skb = dev_alloc_skb(MAX_RX_SIZE);
+ if (unlikely(!skb)) {
+ usb_free_urb(urb);
+ /* TODO check rx queue length and refill *somewhere* */
+ return;
+ }
+
+ info = (struct p54u_rx_info *) skb->cb;
+ info->urb = urb;
+ info->dev = dev;
+ urb->transfer_buffer = skb_tail_pointer(skb);
+ urb->context = skb;
+ skb_queue_tail(&priv->rx_queue, skb);
+ } else {
+ skb_trim(skb, 0);
+ skb_queue_tail(&priv->rx_queue, skb);
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void p54u_tx_cb(struct urb *urb)
+{
+ usb_free_urb(urb);
+}
+
+static void p54u_tx_free_cb(struct urb *urb)
+{
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+}
+
+static int p54u_init_urbs(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *entry;
+ struct sk_buff *skb;
+ struct p54u_rx_info *info;
+
+ while (skb_queue_len(&priv->rx_queue) < 32) {
+ skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
+ if (!skb)
+ break;
+ entry = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry) {
+ kfree_skb(skb);
+ break;
+ }
+ usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb);
+ info = (struct p54u_rx_info *) skb->cb;
+ info->urb = entry;
+ info->dev = dev;
+ skb_queue_tail(&priv->rx_queue, skb);
+ usb_submit_urb(entry, GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+static void p54u_free_urbs(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct p54u_rx_info *info;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&priv->rx_queue))) {
+ info = (struct p54u_rx_info *) skb->cb;
+ if (!info->urb)
+ continue;
+
+ usb_kill_urb(info->urb);
+ kfree_skb(skb);
+ }
+}
+
+static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *addr_urb, *data_urb;
+
+ addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!addr_urb)
+ return;
+
+ data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!data_urb) {
+ usb_free_urb(addr_urb);
+ return;
+ }
+
+ usb_fill_bulk_urb(addr_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
+ sizeof(data->req_id), p54u_tx_cb, dev);
+ usb_fill_bulk_urb(data_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
+ free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+
+ usb_submit_urb(addr_urb, GFP_ATOMIC);
+ usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *int_urb, *data_urb;
+ struct net2280_tx_hdr *hdr;
+ struct net2280_reg_write *reg;
+
+ reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
+ if (!reg)
+ return;
+
+ int_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!int_urb) {
+ kfree(reg);
+ return;
+ }
+
+ data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!data_urb) {
+ kfree(reg);
+ usb_free_urb(int_urb);
+ return;
+ }
+
+ reg->port = cpu_to_le16(NET2280_DEV_U32);
+ reg->addr = cpu_to_le32(P54U_DEV_BASE);
+ reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+
+ len += sizeof(*data);
+ hdr = (void *)data - sizeof(*hdr);
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->device_addr = data->req_id;
+ hdr->len = cpu_to_le16(len);
+
+ usb_fill_bulk_urb(int_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
+ p54u_tx_free_cb, dev);
+ usb_submit_urb(int_urb, GFP_ATOMIC);
+
+ usb_fill_bulk_urb(data_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
+ free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+ usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
+static int p54u_write(struct p54u_priv *priv,
+ struct net2280_reg_write *buf,
+ enum net2280_op_type type,
+ __le32 addr, __le32 val)
+{
+ unsigned int ep;
+ int alen;
+
+ if (type & 0x0800)
+ ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
+ else
+ ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
+
+ buf->port = cpu_to_le16(type);
+ buf->addr = addr;
+ buf->val = val;
+
+ return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
+}
+
+static int p54u_read(struct p54u_priv *priv, void *buf,
+ enum net2280_op_type type,
+ __le32 addr, __le32 *val)
+{
+ struct net2280_reg_read *read = buf;
+ __le32 *reg = buf;
+ unsigned int ep;
+ int alen, err;
+
+ if (type & 0x0800)
+ ep = P54U_PIPE_DEV;
+ else
+ ep = P54U_PIPE_BRG;
+
+ read->port = cpu_to_le16(type);
+ read->addr = addr;
+
+ err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+ read, sizeof(*read), &alen, 1000);
+ if (err)
+ return err;
+
+ err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
+ reg, sizeof(*reg), &alen, 1000);
+ if (err)
+ return err;
+
+ *val = *reg;
+ return 0;
+}
+
+static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
+ void *data, size_t len)
+{
+ int alen;
+ return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+ data, len, &alen, 2000);
+}
+
+static int p54u_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ void *buf;
+ struct p54_control_hdr *hdr;
+ int err, alen;
+ size_t offset = priv->hw_type ? 0x10 : 0x20;
+
+ buf = kmalloc(0x2020, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "prism54usb: cannot allocate memory for"
+ "eeprom readback!\n");
+ return -ENOMEM;
+ }
+
+ if (priv->hw_type) {
+ *((u32 *) buf) = priv->common.rx_start;
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+ if (err) {
+ printk(KERN_ERR "prism54usb: addr send failed\n");
+ goto fail;
+ }
+ } else {
+ struct net2280_reg_write *reg = buf;
+ reg->port = cpu_to_le16(NET2280_DEV_U32);
+ reg->addr = cpu_to_le32(P54U_DEV_BASE);
+ reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+ err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
+ if (err) {
+ printk(KERN_ERR "prism54usb: dev_int send failed\n");
+ goto fail;
+ }
+ }
+
+ hdr = buf + priv->common.tx_hdr_len;
+ p54_fill_eeprom_readback(hdr);
+ hdr->req_id = cpu_to_le32(priv->common.rx_start);
+ if (priv->common.tx_hdr_len) {
+ struct net2280_tx_hdr *tx_hdr = buf;
+ tx_hdr->device_addr = hdr->req_id;
+ tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN);
+ }
+
+ /* we can just pretend to send 0x2000 bytes of nothing in the headers */
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
+ EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
+ if (err) {
+ printk(KERN_ERR "prism54usb: eeprom req send failed\n");
+ goto fail;
+ }
+
+ err = usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
+ buf, 0x2020, &alen, 1000);
+ if (!err && alen > offset) {
+ p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
+ } else {
+ printk(KERN_ERR "prism54usb: eeprom read failed!\n");
+ err = -EINVAL;
+ goto fail;
+ }
+
+ fail:
+ kfree(buf);
+ return err;
+}
+
+static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
+{
+ static char start_string[] = "~~~~<\r";
+ struct p54u_priv *priv = dev->priv;
+ const struct firmware *fw_entry = NULL;
+ int err, alen;
+ u8 carry = 0;
+ u8 *buf, *tmp, *data;
+ unsigned int left, remains, block_size;
+ struct x2_header *hdr;
+ unsigned long timeout;
+
+ tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
+ err = -ENOMEM;
+ goto err_bufalloc;
+ }
+
+ memcpy(buf, start_string, 4);
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
+ if (err) {
+ printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
+ goto err_reset;
+ }
+
+ err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+ if (err) {
+ printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
+ goto err_req_fw_failed;
+ }
+
+ p54_parse_firmware(dev, fw_entry);
+
+ left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
+ strcpy(buf, start_string);
+ left -= strlen(start_string);
+ tmp += strlen(start_string);
+
+ data = fw_entry->data;
+ remains = fw_entry->size;
+
+ hdr = (struct x2_header *)(buf + strlen(start_string));
+ memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
+ hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
+ hdr->fw_length = cpu_to_le32(fw_entry->size);
+ hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
+ sizeof(u32)*2));
+ left -= sizeof(*hdr);
+ tmp += sizeof(*hdr);
+
+ while (remains) {
+ while (left--) {
+ if (carry) {
+ *tmp++ = carry;
+ carry = 0;
+ remains--;
+ continue;
+ }
+ switch (*data) {
+ case '~':
+ *tmp++ = '}';
+ carry = '^';
+ break;
+ case '}':
+ *tmp++ = '}';
+ carry = ']';
+ break;
+ default:
+ *tmp++ = *data;
+ remains--;
+ break;
+ }
+ data++;
+ }
+
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+ goto err_upload_failed;
+ }
+
+ tmp = buf;
+ left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
+ }
+
+ *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+ goto err_upload_failed;
+ }
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(err = usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+ if (alen > 2 && !memcmp(buf, "OK", 2))
+ break;
+
+ if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
+ printk(KERN_INFO "prism54usb: firmware upload failed!\n");
+ err = -EINVAL;
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "prism54usb: firmware boot timed out!\n");
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+ if (err)
+ goto err_upload_failed;
+
+ buf[0] = 'g';
+ buf[1] = '\r';
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware boot failed!\n");
+ goto err_upload_failed;
+ }
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(err = usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+ if (alen > 0 && buf[0] == 'g')
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+ if (err)
+ goto err_upload_failed;
+
+ err_upload_failed:
+ release_firmware(fw_entry);
+ err_req_fw_failed:
+ err_reset:
+ kfree(buf);
+ err_bufalloc:
+ return err;
+}
+
+static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ const struct firmware *fw_entry = NULL;
+ const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
+ int err, alen;
+ void *buf;
+ __le32 reg;
+ unsigned int remains, offset;
+ u8 *data;
+
+ buf = kmalloc(512, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
+ return -ENOMEM;
+ }
+
+ err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+ if (err) {
+ printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
+ kfree(buf);
+ return err;
+ }
+
+ p54_parse_firmware(dev, fw_entry);
+
+#define P54U_WRITE(type, addr, data) \
+ do {\
+ err = p54u_write(priv, buf, type,\
+ cpu_to_le32((u32)(unsigned long)addr), data);\
+ if (err) \
+ goto fail;\
+ } while (0)
+
+#define P54U_READ(type, addr) \
+ do {\
+ err = p54u_read(priv, buf, type,\
+ cpu_to_le32((u32)(unsigned long)addr), &reg);\
+ if (err)\
+ goto fail;\
+ } while (0)
+
+ /* power down net2280 bridge */
+ P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
+ reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
+ reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+ mdelay(100);
+
+ /* power up bridge */
+ reg |= cpu_to_le32(P54U_BRG_POWER_UP);
+ reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+ mdelay(100);
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
+ cpu_to_le32(NET2280_CLK_30Mhz |
+ NET2280_PCI_ENABLE |
+ NET2280_PCI_SOFT_RESET));
+
+ mdelay(20);
+
+ P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
+ cpu_to_le32(PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER));
+
+ P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
+ cpu_to_le32(NET2280_BASE));
+
+ P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
+ reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
+ P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
+
+ // TODO: we really need this?
+ P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
+ cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+ P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
+ cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+
+ P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
+ cpu_to_le32(NET2280_BASE2));
+
+ /* finally done setting up the bridge */
+
+ P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
+ cpu_to_le32(PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER));
+
+ P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
+ P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
+ cpu_to_le32(P54U_DEV_BASE));
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+ /* do romboot */
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
+
+ P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(20);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(20);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(100);
+
+ P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+ /* finally, we can upload firmware now! */
+ remains = fw_entry->size;
+ data = fw_entry->data;
+ offset = ISL38XX_DEV_FIRMWARE_ADDR;
+
+ while (remains) {
+ unsigned int block_len = min(remains, (unsigned int)512);
+ memcpy(buf, data, block_len);
+
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware block upload "
+ "failed\n");
+ goto fail;
+ }
+
+ P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
+ cpu_to_le32(0xc0000f00));
+
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0020 | (unsigned long)&devreg->direct_mem_win,
+ cpu_to_le32(1));
+
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0024 | (unsigned long)&devreg->direct_mem_win,
+ cpu_to_le32(block_len));
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0028 | (unsigned long)&devreg->direct_mem_win,
+ cpu_to_le32(offset));
+
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
+ cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
+ cpu_to_le32(block_len >> 2));
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
+ cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
+
+ mdelay(10);
+
+ P54U_READ(NET2280_DEV_U32,
+ 0x002C | (unsigned long)&devreg->direct_mem_win);
+ if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
+ !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
+ printk(KERN_ERR "prism54usb: firmware DMA transfer "
+ "failed\n");
+ goto fail;
+ }
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
+ cpu_to_le32(NET2280_FIFO_FLUSH));
+
+ remains -= block_len;
+ data += block_len;
+ offset += block_len;
+ }
+
+ /* do ramboot */
+ P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(20);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(100);
+
+ P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+ /* start up the firmware */
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
+ cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
+ NET2280_USB_INTERRUPT_ENABLE));
+
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
+ cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+ err = usb_interrupt_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
+ buf, sizeof(__le32), &alen, 1000);
+ if (err || alen != sizeof(__le32))
+ goto fail;
+
+ P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+ if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
+ err = -EINVAL;
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+#undef P54U_WRITE
+#undef P54U_READ
+
+ fail:
+ release_firmware(fw_entry);
+ kfree(buf);
+ return err;
+}
+
+static int p54u_open(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ int err;
+
+ err = p54u_init_urbs(dev);
+ if (err) {
+ return err;
+ }
+
+ priv->common.open = p54u_init_urbs;
+
+ return 0;
+}
+
+static void p54u_stop(struct ieee80211_hw *dev)
+{
+ /* TODO: figure out how to reliably stop the 3887 and net2280 so
+ the hardware is still usable next time we want to start it.
+ until then, we just stop listening to the hardware.. */
+ p54u_free_urbs(dev);
+ return;
+}
+
+static int __devinit p54u_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct ieee80211_hw *dev;
+ struct p54u_priv *priv;
+ int err;
+ unsigned int i, recognized_pipes;
+ DECLARE_MAC_BUF(mac);
+
+ dev = p54_init_common(sizeof(*priv));
+ if (!dev) {
+ printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n");
+ return -ENOMEM;
+ }
+
+ priv = dev->priv;
+
+ SET_IEEE80211_DEV(dev, &intf->dev);
+ usb_set_intfdata(intf, dev);
+ priv->udev = udev;
+
+ usb_get_dev(udev);
+
+ /* really lazy and simple way of figuring out if we're a 3887 */
+ /* TODO: should just stick the identification in the device table */
+ i = intf->altsetting->desc.bNumEndpoints;
+ recognized_pipes = 0;
+ while (i--) {
+ switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
+ case P54U_PIPE_DATA:
+ case P54U_PIPE_MGMT:
+ case P54U_PIPE_BRG:
+ case P54U_PIPE_DEV:
+ case P54U_PIPE_DATA | USB_DIR_IN:
+ case P54U_PIPE_MGMT | USB_DIR_IN:
+ case P54U_PIPE_BRG | USB_DIR_IN:
+ case P54U_PIPE_DEV | USB_DIR_IN:
+ case P54U_PIPE_INT | USB_DIR_IN:
+ recognized_pipes++;
+ }
+ }
+ priv->common.open = p54u_open;
+
+ if (recognized_pipes < P54U_PIPE_NUMBER) {
+ priv->hw_type = P54U_3887;
+ priv->common.tx = p54u_tx_3887;
+ } else {
+ dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
+ priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
+ priv->common.tx = p54u_tx_net2280;
+ }
+ priv->common.stop = p54u_stop;
+
+ if (priv->hw_type)
+ err = p54u_upload_firmware_3887(dev);
+ else
+ err = p54u_upload_firmware_net2280(dev);
+ if (err)
+ goto err_free_dev;
+
+ err = p54u_read_eeprom(dev);
+ if (err)
+ goto err_free_dev;
+
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ u8 perm_addr[ETH_ALEN];
+
+ printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
+ random_ether_addr(perm_addr);
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+ }
+
+ skb_queue_head_init(&priv->rx_queue);
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "prism54usb: Cannot register netdevice\n");
+ goto err_free_dev;
+ }
+
+ printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
+ wiphy_name(dev->wiphy),
+ print_mac(mac, dev->wiphy->perm_addr),
+ priv->common.version);
+
+ return 0;
+
+ err_free_dev:
+ ieee80211_free_hw(dev);
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(udev);
+ return err;
+}
+
+static void __devexit p54u_disconnect(struct usb_interface *intf)
+{
+ struct ieee80211_hw *dev = usb_get_intfdata(intf);
+ struct p54u_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+
+ priv = dev->priv;
+ usb_put_dev(interface_to_usbdev(intf));
+ p54_free_common(dev);
+ ieee80211_free_hw(dev);
+}
+
+static struct usb_driver p54u_driver = {
+ .name = "prism54usb",
+ .id_table = p54u_table,
+ .probe = p54u_probe,
+ .disconnect = p54u_disconnect,
+};
+
+static int __init p54u_init(void)
+{
+ return usb_register(&p54u_driver);
+}
+
+static void __exit p54u_exit(void)
+{
+ usb_deregister(&p54u_driver);
+}
+
+module_init(p54u_init);
+module_exit(p54u_exit);
diff --git a/drivers/net/wireless/p54usb.h b/drivers/net/wireless/p54usb.h
new file mode 100644
index 000000000000..d1896b396c1c
--- /dev/null
+++ b/drivers/net/wireless/p54usb.h
@@ -0,0 +1,133 @@
+#ifndef PRISM54USB_H
+#define PRISM54USB_H
+
+/*
+ * Defines for USB based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+/* for isl3886 register definitions used on ver 1 devices */
+#include "p54pci.h"
+#include "net2280.h"
+
+/* pci */
+#define NET2280_BASE 0x10000000
+#define NET2280_BASE2 0x20000000
+
+/* gpio */
+#define P54U_BRG_POWER_UP (1 << GPIO0_DATA)
+#define P54U_BRG_POWER_DOWN (1 << GPIO1_DATA)
+
+/* devinit */
+#define NET2280_CLK_4Mhz (15 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_30Mhz (2 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_60Mhz (1 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_STOP (0 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_PCI_ENABLE (1 << PCI_ENABLE)
+#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET)
+
+/* endpoints */
+#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+#define NET2280_FIFO_FLUSH (1 << FIFO_FLUSH)
+
+/* irq */
+#define NET2280_USB_INTERRUPT_ENABLE (1 << USB_INTERRUPT_ENABLE)
+#define NET2280_PCI_INTA_INTERRUPT (1 << PCI_INTA_INTERRUPT)
+#define NET2280_PCI_INTA_INTERRUPT_ENABLE (1 << PCI_INTA_INTERRUPT_ENABLE)
+
+/* registers */
+#define NET2280_DEVINIT 0x00
+#define NET2280_USBIRQENB1 0x24
+#define NET2280_IRQSTAT1 0x2c
+#define NET2280_FIFOCTL 0x38
+#define NET2280_GPIOCTL 0x50
+#define NET2280_RELNUM 0x88
+#define NET2280_EPA_RSP 0x324
+#define NET2280_EPA_STAT 0x32c
+#define NET2280_EPB_STAT 0x34c
+#define NET2280_EPC_RSP 0x364
+#define NET2280_EPC_STAT 0x36c
+#define NET2280_EPD_STAT 0x38c
+
+#define NET2280_EPA_CFG 0x320
+#define NET2280_EPB_CFG 0x340
+#define NET2280_EPC_CFG 0x360
+#define NET2280_EPD_CFG 0x380
+#define NET2280_EPE_CFG 0x3A0
+#define NET2280_EPF_CFG 0x3C0
+#define P54U_DEV_BASE 0x40000000
+
+struct net2280_tx_hdr {
+ __le32 device_addr;
+ __le16 len;
+ __le16 follower; /* ? */
+ u8 padding[8];
+} __attribute__((packed));
+
+/* Some flags for the isl hardware registers controlling DMA inside the
+ * chip */
+#define ISL38XX_DMA_STATUS_DONE 0x00000001
+#define ISL38XX_DMA_STATUS_READY 0x00000002
+#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000
+#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004
+
+enum net2280_op_type {
+ NET2280_BRG_U32 = 0x001F,
+ NET2280_BRG_CFG_U32 = 0x000F,
+ NET2280_BRG_CFG_U16 = 0x0003,
+ NET2280_DEV_U32 = 0x080F,
+ NET2280_DEV_CFG_U32 = 0x088F,
+ NET2280_DEV_CFG_U16 = 0x0883
+};
+
+#define P54U_FW_BLOCK 2048
+
+#define X2_SIGNATURE "x2 "
+#define X2_SIGNATURE_SIZE 4
+
+struct x2_header {
+ u8 signature[X2_SIGNATURE_SIZE];
+ __le32 fw_load_addr;
+ __le32 fw_length;
+ __le32 crc;
+} __attribute__((packed));
+
+/* pipes 3 and 4 are not used by the driver */
+#define P54U_PIPE_NUMBER 9
+
+enum p54u_pipe_addr {
+ P54U_PIPE_DATA = 0x01,
+ P54U_PIPE_MGMT = 0x02,
+ P54U_PIPE_3 = 0x03,
+ P54U_PIPE_4 = 0x04,
+ P54U_PIPE_BRG = 0x0d,
+ P54U_PIPE_DEV = 0x0e,
+ P54U_PIPE_INT = 0x0f
+};
+
+struct p54u_rx_info {
+ struct urb *urb;
+ struct ieee80211_hw *dev;
+};
+
+struct p54u_priv {
+ struct p54_common common;
+ struct usb_device *udev;
+ enum {
+ P54U_NET2280 = 0,
+ P54U_3887
+ } hw_type;
+
+ spinlock_t lock;
+ struct sk_buff_head rx_queue;
+};
+
+#endif /* PRISM54USB_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 585f5996d292..6d80ca421cf0 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1753,7 +1753,7 @@ prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
int rvalue;
enum oid_num_t n = dwrq->flags;
- rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
+ rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r);
dwrq->length = mgt_response_to_str(n, &r, extra);
if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
kfree(r.ptr);
@@ -1766,7 +1766,7 @@ prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
{
u32 oid = uwrq[0], u = uwrq[1];
- return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
+ return mgt_set_request(netdev_priv(ndev), oid, 0, &u);
}
static int
@@ -1775,7 +1775,7 @@ prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
{
u32 oid = dwrq->flags;
- return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
+ return mgt_set_request(netdev_priv(ndev), oid, 0, extra);
}
void
@@ -2029,12 +2029,12 @@ static void
format_event(islpci_private *priv, char *dest, const char *str,
const struct obj_mlme *mlme, u16 *length, int error)
{
- const u8 *a = mlme->address;
+ DECLARE_MAC_BUF(mac);
int n = snprintf(dest, IW_CUSTOM_MAX,
- "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
+ "%s %s %s %s (%2.2X)",
str,
((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
- a[0], a[1], a[2], a[3], a[4], a[5],
+ print_mac(mac, mlme->address),
(error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
: ""), mlme->code);
BUG_ON(n > IW_CUSTOM_MAX);
@@ -2105,15 +2105,13 @@ struct ieee80211_beacon_phdr {
#define WLAN_EID_GENERIC 0xdd
static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
static void
prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len)
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
+ DECLARE_MAC_BUF(mac);
if (wpa_ie_len > MAX_WPA_IE_LEN)
wpa_ie_len = MAX_WPA_IE_LEN;
@@ -2154,8 +2152,8 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
bss->wpa_ie_len = wpa_ie_len;
bss->last_update = jiffies;
} else {
- printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
- "\n", MAC2STR(bssid));
+ printk(KERN_DEBUG "Failed to add BSS WPA entry for "
+ "%s\n", print_mac(mac, bssid));
}
/* expire old entries from WPA list */
@@ -2221,6 +2219,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
{
struct ieee80211_beacon_phdr *hdr;
u8 *pos, *end;
+ DECLARE_MAC_BUF(mac);
if (!priv->wpa)
return;
@@ -2231,7 +2230,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
while (pos < end) {
if (pos + 2 + pos[1] > end) {
printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
- "for " MACSTR "\n", MAC2STR(addr));
+ "for %s\n", print_mac(mac, addr));
return;
}
if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
@@ -2270,6 +2269,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
size_t len = 0; /* u16, better? */
u8 *payload = NULL, *pos = NULL;
int ret;
+ DECLARE_MAC_BUF(mac);
/* I think all trapable objects are listed here.
* Some oids have a EX version. The difference is that they are emitted
@@ -2358,14 +2358,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
break;
memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
- printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
- mlmeex->address[0],
- mlmeex->address[1],
- mlmeex->address[2],
- mlmeex->address[3],
- mlmeex->address[4],
- mlmeex->address[5]
- );
+ printk(KERN_DEBUG "Authenticate from: address:\t%s\n",
+ print_mac(mac, mlmeex->address));
confirm->id = -1; /* or mlmeex->id ? */
confirm->state = 0; /* not used */
confirm->code = 0;
@@ -2410,15 +2404,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
- printk(KERN_DEBUG "No WPA IE found from "
- "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
- mlmeex->address[0],
- mlmeex->address[1],
- mlmeex->address[2],
- mlmeex->address[3],
- mlmeex->address[4],
- mlmeex->address[5]
- );
+ printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
+ print_mac(mac, mlmeex->address));
kfree(confirm);
break;
}
@@ -2454,15 +2441,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
- printk(KERN_DEBUG "No WPA IE found from "
- "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
- mlmeex->address[0],
- mlmeex->address[1],
- mlmeex->address[2],
- mlmeex->address[3],
- mlmeex->address[4],
- mlmeex->address[5]
- );
+ printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
+ print_mac(mac, mlmeex->address));
kfree(confirm);
break;
}
@@ -3239,10 +3219,9 @@ static const iw_handler prism54_private_handler[] = {
};
const struct iw_handler_def prism54_handler_def = {
- .num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
- .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
- .num_private_args =
- sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(prism54_handler),
+ .num_private = ARRAY_SIZE(prism54_private_handler),
+ .num_private_args = ARRAY_SIZE(prism54_private_args),
.standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args,
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 084795355b74..219dd651dc41 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -808,7 +808,6 @@ islpci_setup(struct pci_dev *pdev)
if (!ndev)
return ndev;
- SET_MODULE_OWNER(ndev);
pci_set_drvdata(pdev, ndev);
#if defined(SET_NETDEV_DEV)
SET_NETDEV_DEV(ndev, &pdev->dev);
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
index 42780320cd5c..57a4ac34bed6 100644
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -244,13 +244,11 @@ mgt_init(islpci_private *priv)
/* Alloc the cache */
for (i = 0; i < OID_NUM_LAST; i++) {
if (isl_oid[i].flags & OID_FLAG_CACHED) {
- priv->mib[i] = kmalloc(isl_oid[i].size *
+ priv->mib[i] = kzalloc(isl_oid[i].size *
(isl_oid[i].range + 1),
GFP_KERNEL);
if (!priv->mib[i])
return -ENOMEM;
- memset(priv->mib[i], 0,
- isl_oid[i].size * (isl_oid[i].range + 1));
} else
priv->mib[i] = NULL;
}
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 3be624295a1f..f87fe10059ae 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -314,7 +314,7 @@ static int ray_probe(struct pcmcia_device *p_dev)
if (!dev)
goto fail_alloc_dev;
- local = dev->priv;
+ local = netdev_priv(dev);
local->finder = p_dev;
/* The io structure describes IO port mapping. None used here */
@@ -356,7 +356,6 @@ static int ray_probe(struct pcmcia_device *p_dev)
dev->set_multicast_list = &set_multicast_list;
DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
- SET_MODULE_OWNER(dev);
dev->init = &ray_dev_init;
dev->open = &ray_open;
dev->stop = &ray_dev_close;
@@ -388,7 +387,7 @@ static void ray_detach(struct pcmcia_device *link)
ray_release(link);
- local = (ray_dev_t *)dev->priv;
+ local = netdev_priv(dev);
del_timer(&local->timer);
if (link->priv) {
@@ -412,7 +411,8 @@ static int ray_config(struct pcmcia_device *link)
win_req_t req;
memreq_t mem;
struct net_device *dev = (struct net_device *)link->priv;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
DEBUG(1, "ray_config(0x%p)\n", link);
@@ -483,10 +483,8 @@ static int ray_config(struct pcmcia_device *link)
strcpy(local->node.dev_name, dev->name);
link->dev_node = &local->node;
- printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
- dev->name, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n",
+ dev->name, dev->irq, print_mac(mac, dev->dev_addr));
return 0;
@@ -520,7 +518,7 @@ static int ray_init(struct net_device *dev)
int i;
UCHAR *p;
struct ccs __iomem *pccs;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
DEBUG(1, "ray_init(0x%p)\n", dev);
if (!(pcmcia_dev_present(link))) {
@@ -581,7 +579,7 @@ static int ray_init(struct net_device *dev)
static int dl_startup_params(struct net_device *dev)
{
int ccsindex;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct ccs __iomem *pccs;
struct pcmcia_device *link = local->finder;
@@ -786,7 +784,7 @@ static void join_net(u_long data)
static void ray_release(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int i;
DEBUG(1, "ray_release(0x%p)\n", link);
@@ -834,7 +832,7 @@ int ray_dev_init(struct net_device *dev)
#ifdef RAY_IMMEDIATE_INIT
int i;
#endif /* RAY_IMMEDIATE_INIT */
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
@@ -868,7 +866,7 @@ int ray_dev_init(struct net_device *dev)
/*===========================================================================*/
static int ray_dev_config(struct net_device *dev, struct ifmap *map)
{
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
/* Dummy routine to satisfy device structure */
DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
@@ -882,7 +880,7 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map)
/*===========================================================================*/
static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
short length = skb->len;
@@ -925,7 +923,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev,
UCHAR msg_type)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct ccs __iomem *pccs;
int ccsindex;
int offset;
@@ -1099,7 +1097,7 @@ static int ray_set_freq(struct net_device *dev,
struct iw_freq *fwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
/* Reject if card is already initialised */
@@ -1124,7 +1122,7 @@ static int ray_get_freq(struct net_device *dev,
struct iw_freq *fwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
fwrq->m = local->sparm.b5.a_hop_pattern;
fwrq->e = 0;
@@ -1140,7 +1138,7 @@ static int ray_set_essid(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
/* Reject if card is already initialised */
if(local->card_status != CARD_AWAITING_PARAM)
@@ -1173,7 +1171,7 @@ static int ray_get_essid(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
/* Get the essid that was set */
memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
@@ -1194,7 +1192,7 @@ static int ray_get_wap(struct net_device *dev,
struct sockaddr *awrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
memcpy(awrq->sa_data, local->bss_id, ETH_ALEN);
awrq->sa_family = ARPHRD_ETHER;
@@ -1211,7 +1209,7 @@ static int ray_set_rate(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
/* Reject if card is already initialised */
if(local->card_status != CARD_AWAITING_PARAM)
@@ -1240,7 +1238,7 @@ static int ray_get_rate(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
if(local->net_default_tx_rate == 3)
vwrq->value = 2000000; /* Hum... */
@@ -1260,7 +1258,7 @@ static int ray_set_rts(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int rthr = vwrq->value;
/* Reject if card is already initialised */
@@ -1290,7 +1288,7 @@ static int ray_get_rts(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
+ local->sparm.b5.a_rts_threshold[1];
@@ -1309,7 +1307,7 @@ static int ray_set_frag(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int fthr = vwrq->value;
/* Reject if card is already initialised */
@@ -1338,7 +1336,7 @@ static int ray_get_frag(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
+ local->sparm.b5.a_frag_threshold[1];
@@ -1357,7 +1355,7 @@ static int ray_set_mode(struct net_device *dev,
__u32 *uwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
char card_mode = 1;
@@ -1389,7 +1387,7 @@ static int ray_get_mode(struct net_device *dev,
__u32 *uwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
if(local->sparm.b5.a_network_type)
*uwrq = IW_MODE_INFRA;
@@ -1492,7 +1490,7 @@ static int ray_commit(struct net_device *dev,
*/
static iw_stats * ray_get_wireless_stats(struct net_device * dev)
{
- ray_dev_t * local = (ray_dev_t *) dev->priv;
+ ray_dev_t * local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE;
@@ -1568,9 +1566,9 @@ static const struct iw_priv_args ray_private_args[] = {
static const struct iw_handler_def ray_handler_def =
{
- .num_standard = sizeof(ray_handler)/sizeof(iw_handler),
- .num_private = sizeof(ray_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(ray_handler),
+ .num_private = ARRAY_SIZE(ray_private_handler),
+ .num_private_args = ARRAY_SIZE(ray_private_args),
.standard = ray_handler,
.private = ray_private_handler,
.private_args = ray_private_args,
@@ -1580,7 +1578,7 @@ static const struct iw_handler_def ray_handler_def =
/*===========================================================================*/
static int ray_open(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link;
link = local->finder;
@@ -1614,7 +1612,7 @@ static int ray_open(struct net_device *dev)
/*===========================================================================*/
static int ray_dev_close(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link;
link = local->finder;
@@ -1773,7 +1771,7 @@ static int parse_addr(char *in_str, UCHAR *out)
/*===========================================================================*/
static struct net_device_stats *ray_get_stats(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE;
if (!(pcmcia_dev_present(link))) {
@@ -1803,7 +1801,7 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev)
/*===========================================================================*/
static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
int ccsindex;
int i;
@@ -1840,7 +1838,7 @@ static void ray_update_multi_list(struct net_device *dev, int all)
int ccsindex;
struct ccs __iomem *pccs;
int i = 0;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
void __iomem *p = local->sram + HOST_TO_ECF_BASE;
@@ -1884,7 +1882,7 @@ static void ray_update_multi_list(struct net_device *dev, int all)
/*===========================================================================*/
static void set_multicast_list(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
UCHAR promisc;
DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
@@ -1935,7 +1933,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
- local = (ray_dev_t *)dev->priv;
+ local = netdev_priv(dev);
link = (struct pcmcia_device *)local->finder;
if (!pcmcia_dev_present(link)) {
DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
@@ -2165,7 +2163,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i
{
struct sk_buff *skb = NULL;
struct rcs __iomem *prcslink = prcs;
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
UCHAR *rx_ptr;
int total_len;
int tmp;
@@ -2611,6 +2609,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
UCHAR *p;
struct freq_hop_element *pfh;
UCHAR c[33];
+ DECLARE_MAC_BUF(mac);
link = this_device;
if (!link)
@@ -2618,7 +2617,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
dev = (struct net_device *)link->priv;
if (!dev)
return 0;
- local = (ray_dev_t *)dev->priv;
+ local = netdev_priv(dev);
if (!local)
return 0;
@@ -2640,9 +2639,8 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
nettype[local->sparm.b5.a_network_type], c);
p = local->bss_id;
- len += sprintf(buf + len,
- "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
- p[0],p[1],p[2],p[3],p[4],p[5]);
+ len += sprintf(buf + len, "BSSID = %s\n",
+ print_mac(mac, p));
len += sprintf(buf + len, "Country code = %d\n",
local->sparm.b5.a_curr_country_code);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
new file mode 100644
index 000000000000..da05b1faf60d
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -0,0 +1,130 @@
+config RT2X00
+ tristate "Ralink driver support"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This will enable the experimental support for the Ralink drivers,
+ developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
+
+ These drivers will make use of the Devicescape ieee80211 stack.
+
+ When building one of the individual drivers, the rt2x00 library
+ will also be created. That library (when the driver is built as
+ a module) will be called "rt2x00lib.ko".
+
+config RT2X00_LIB
+ tristate
+ depends on RT2X00
+
+config RT2X00_LIB_PCI
+ tristate
+ depends on RT2X00
+ select RT2X00_LIB
+
+config RT2X00_LIB_USB
+ tristate
+ depends on RT2X00
+ select RT2X00_LIB
+
+config RT2X00_LIB_FIRMWARE
+ boolean
+ depends on RT2X00_LIB
+ select CRC_ITU_T
+ select FW_LOADER
+
+config RT2X00_LIB_RFKILL
+ boolean
+ depends on RT2X00_LIB
+ select RFKILL
+ select INPUT_POLLDEV
+
+config RT2400PCI
+ tristate "Ralink rt2400 pci/pcmcia support"
+ depends on RT2X00 && PCI
+ select RT2X00_LIB_PCI
+ select EEPROM_93CX6
+ ---help---
+ This is an experimental driver for the Ralink rt2400 wireless chip.
+
+ When compiled as a module, this driver will be called "rt2400pci.ko".
+
+config RT2400PCI_RFKILL
+ bool "RT2400 rfkill support"
+ depends on RT2400PCI
+ select RT2X00_LIB_RFKILL
+ ---help---
+ This adds support for integrated rt2400 devices that feature a
+ hardware button to control the radio state.
+ This feature depends on the RF switch subsystem rfkill.
+
+config RT2500PCI
+ tristate "Ralink rt2500 pci/pcmcia support"
+ depends on RT2X00 && PCI
+ select RT2X00_LIB_PCI
+ select EEPROM_93CX6
+ ---help---
+ This is an experimental driver for the Ralink rt2500 wireless chip.
+
+ When compiled as a module, this driver will be called "rt2500pci.ko".
+
+config RT2500PCI_RFKILL
+ bool "RT2500 rfkill support"
+ depends on RT2500PCI
+ select RT2X00_LIB_RFKILL
+ ---help---
+ This adds support for integrated rt2500 devices that feature a
+ hardware button to control the radio state.
+ This feature depends on the RF switch subsystem rfkill.
+
+config RT61PCI
+ tristate "Ralink rt61 pci/pcmcia support"
+ depends on RT2X00 && PCI
+ select RT2X00_LIB_PCI
+ select RT2X00_LIB_FIRMWARE
+ select EEPROM_93CX6
+ ---help---
+ This is an experimental driver for the Ralink rt61 wireless chip.
+
+ When compiled as a module, this driver will be called "rt61pci.ko".
+
+config RT61PCI_RFKILL
+ bool "RT61 rfkill support"
+ depends on RT61PCI
+ select RT2X00_LIB_RFKILL
+ ---help---
+ This adds support for integrated rt61 devices that feature a
+ hardware button to control the radio state.
+ This feature depends on the RF switch subsystem rfkill.
+
+config RT2500USB
+ tristate "Ralink rt2500 usb support"
+ depends on RT2X00 && USB
+ select RT2X00_LIB_USB
+ ---help---
+ This is an experimental driver for the Ralink rt2500 wireless chip.
+
+ When compiled as a module, this driver will be called "rt2500usb.ko".
+
+config RT73USB
+ tristate "Ralink rt73 usb support"
+ depends on RT2X00 && USB
+ select RT2X00_LIB_USB
+ select RT2X00_LIB_FIRMWARE
+ ---help---
+ This is an experimental driver for the Ralink rt73 wireless chip.
+
+ When compiled as a module, this driver will be called "rt73usb.ko".
+
+config RT2X00_LIB_DEBUGFS
+ bool "Ralink debugfs support"
+ depends on RT2X00_LIB && MAC80211_DEBUGFS
+ ---help---
+ Enable creation of debugfs files for the rt2x00 drivers.
+ These debugfs files support both reading and writing of the
+ most important register types of the rt2x00 devices.
+
+config RT2X00_DEBUG
+ bool "Ralink debug output"
+ depends on RT2X00_LIB
+ ---help---
+ Enable debugging output for all rt2x00 modules
+
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
new file mode 100644
index 000000000000..30d654a42eea
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -0,0 +1,22 @@
+rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o
+
+ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
+ rt2x00lib-objs += rt2x00debug.o
+endif
+
+ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y)
+ rt2x00lib-objs += rt2x00rfkill.o
+endif
+
+ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y)
+ rt2x00lib-objs += rt2x00firmware.o
+endif
+
+obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
+obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
+obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
+obj-$(CONFIG_RT2400PCI) += rt2400pci.o
+obj-$(CONFIG_RT2500PCI) += rt2500pci.o
+obj-$(CONFIG_RT61PCI) += rt61pci.o
+obj-$(CONFIG_RT2500USB) += rt2500usb.o
+obj-$(CONFIG_RT73USB) += rt73usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
new file mode 100644
index 000000000000..31c1dd271627
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -0,0 +1,1664 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2400pci
+ Abstract: rt2400pci device specific routines.
+ Supported chipsets: RT2460.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2400pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2400pci.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2x00pci_register_read and rt2x00pci_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
+ if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2400pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+}
+
+static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2400pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2400pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+}
+
+static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
+ if (!rt2x00_get_field32(reg, RFCSR_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT);
+}
+
+static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2400pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2400pci_read_csr,
+ .write = rt2400pci_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2400pci_bbp_read,
+ .write = rt2400pci_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2400pci_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT2400PCI_RFKILL
+static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+#else
+#define rt2400pci_rfkill_poll NULL
+#endif /* CONFIG_RT2400PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Enable beacon config
+ */
+ rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+ rt2x00_set_field32(&reg, BCNCSR1_PRELOAD,
+ PREAMBLE + get_duration(IEEE80211_HEADER, 20));
+ rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+}
+
+static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ int preamble_mask;
+ u32 reg;
+
+ /*
+ * When short preamble is enabled, we should set bit 0x08
+ */
+ preamble_mask = short_preamble << 3;
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+ 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_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+ rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+ rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+ rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+ rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+}
+
+static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+}
+
+static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf)
+{
+ /*
+ * Switch on tuning bits.
+ */
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
+
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ /*
+ * RF2420 chipset don't need any additional actions.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2420))
+ return;
+
+ /*
+ * For the RT2421 chipsets we need to write an invalid
+ * reference clock rate to activate auto_tune.
+ * After that we set the value back to the correct channel.
+ */
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ msleep(1);
+
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ msleep(1);
+
+ /*
+ * Switch off tuning bits.
+ */
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0);
+
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ /*
+ * Clear false CRC during channel switch.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+}
+
+static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
+{
+ rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
+}
+
+static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ int antenna_tx, int antenna_rx)
+{
+ u8 r1;
+ u8 r4;
+
+ rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+ rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (antenna_tx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ }
+
+ rt2400pci_bbp_write(rt2x00dev, 4, r4);
+ rt2400pci_bbp_write(rt2x00dev, 1, r1);
+}
+
+static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+ libconf->conf->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+}
+
+static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt2400pci_config_channel(rt2x00dev, &libconf->rf);
+ if (flags & CONFIG_UPDATE_TXPOWER)
+ rt2400pci_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt2400pci_config_antenna(rt2x00dev,
+ libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt2400pci_config_duration(rt2x00dev, libconf);
+}
+
+static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_tx_queue_params *params)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_CWMIN, params->cw_min);
+ rt2x00_set_field32(&reg, CSR11_CWMAX, params->cw_max);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+
+ rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+
+ if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ } else {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u8 bbp;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2400pci_bbp_read(rt2x00dev, 39, &bbp);
+ rt2x00dev->link.false_cca = bbp;
+}
+
+static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt2400pci_bbp_write(rt2x00dev, 13, 0x08);
+ rt2x00dev->link.vgc_level = 0x08;
+}
+
+static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ u8 reg;
+
+ /*
+ * The link tuner should not run longer then 60 seconds,
+ * and should run once every 2 seconds.
+ */
+ if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1))
+ return;
+
+ /*
+ * Base r13 link tuning on the false cca count.
+ */
+ rt2400pci_bbp_read(rt2x00dev, 13, &reg);
+
+ if (rt2x00dev->link.false_cca > 512 && reg < 0x20) {
+ rt2400pci_bbp_write(rt2x00dev, 13, ++reg);
+ rt2x00dev->link.vgc_level = reg;
+ } else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) {
+ rt2400pci_bbp_write(rt2x00dev, 13, --reg);
+ rt2x00dev->link.vgc_level = reg;
+ }
+}
+
+/*
+ * Initialization functions.
+ */
+static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_desc *rxd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ rxd = ring->entry[i].priv;
+
+ rt2x00_desc_read(rxd, 2, &word);
+ rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
+ ring->data_size);
+ rt2x00_desc_write(rxd, 2, word);
+
+ rt2x00_desc_read(rxd, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(rxd, 1, word);
+
+ rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_desc *txd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ txd = ring->entry[i].priv;
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
+ ring->data_size);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(txd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(ring);
+}
+
+static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize rings.
+ */
+ rt2400pci_init_rxring(rt2x00dev);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ /*
+ * Initialize registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+ rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_TXD,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM,
+ rt2x00dev->bcn[1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+ rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+ rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+ rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
+ rt2x00dev->bcn[1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+ rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
+ rt2x00dev->bcn[0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+ rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
+ rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+ rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+ rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+ rt2x00dev->rx->data_dma);
+ rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+
+ return 0;
+}
+
+static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00023f20);
+ rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+
+ rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+ rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
+ rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
+ rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
+ rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+ rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
+ (rt2x00dev->rx->data_size / 128));
+ rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+
+ rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA0, 133);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID0, 134);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA1, 136);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID1, 135);
+ rt2x00pci_register_write(rt2x00dev, ARCSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 3); /* Tx power.*/
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 32); /* Signal */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 36); /* Rssi */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00217223);
+ rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+
+ rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+ rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
+ rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 154);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 154);
+ rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ /*
+ * We must clear the FCS and FIFO error count.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+
+ return 0;
+}
+
+static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2400pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt2400pci_bbp_write(rt2x00dev, 1, 0x00);
+ rt2400pci_bbp_write(rt2x00dev, 3, 0x27);
+ rt2400pci_bbp_write(rt2x00dev, 4, 0x08);
+ rt2400pci_bbp_write(rt2x00dev, 10, 0x0f);
+ rt2400pci_bbp_write(rt2x00dev, 15, 0x72);
+ rt2400pci_bbp_write(rt2x00dev, 16, 0x74);
+ rt2400pci_bbp_write(rt2x00dev, 17, 0x20);
+ rt2400pci_bbp_write(rt2x00dev, 18, 0x72);
+ rt2400pci_bbp_write(rt2x00dev, 19, 0x0b);
+ rt2400pci_bbp_write(rt2x00dev, 20, 0x00);
+ rt2400pci_bbp_write(rt2x00dev, 28, 0x11);
+ rt2400pci_bbp_write(rt2x00dev, 29, 0x04);
+ rt2400pci_bbp_write(rt2x00dev, 30, 0x21);
+ rt2400pci_bbp_write(rt2x00dev, 31, 0x00);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt2400pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_OFF);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
+ rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt2400pci_init_rings(rt2x00dev) ||
+ rt2400pci_init_registers(rt2x00dev) ||
+ rt2400pci_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+ /*
+ * Enable LED
+ */
+ rt2400pci_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Disable LED
+ */
+ rt2400pci_disable_led(rt2x00dev);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Cancel RX and TX.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+
+ /*
+ * Disable interrupts.
+ */
+ rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char bbp_state;
+ char rf_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
+ rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
+ rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
+ rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+ if (bbp_state == state && rf_state == state)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state: bbp %d and rf %d.\n",
+ state, bbp_state, rf_state);
+
+ return -EBUSY;
+}
+
+static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt2400pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt2400pci_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt2400pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2400pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+ u32 signal = 0;
+ u32 service = 0;
+ u32 length_high = 0;
+ u32 length_low = 0;
+
+ /*
+ * The PLCP values should be treated as if they
+ * were BBP values.
+ */
+ rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal);
+ rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5);
+ rt2x00_set_field32(&signal, BBPCSR_BUSY, 1);
+
+ rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service);
+ rt2x00_set_field32(&service, BBPCSR_REGNUM, 6);
+ rt2x00_set_field32(&service, BBPCSR_BUSY, 1);
+
+ rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high);
+ rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7);
+ rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1);
+
+ rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low);
+ rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8);
+ rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1);
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 3, &word);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service);
+ rt2x00_desc_write(txd, 3, word);
+
+ rt2x00_desc_read(txd, 4, &word);
+ rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low);
+ rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high);
+ rt2x00_desc_write(txd, 4, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_RTS,
+ test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ }
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ if (queue == IEEE80211_TX_QUEUE_DATA0)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA1)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2400pci_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word2;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 2, &word2);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ desc->ofdm = 0;
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_entry *entry;
+ struct data_desc *txd;
+ u32 word;
+ int tx_status;
+ int retry;
+
+ while (!rt2x00_ring_empty(ring)) {
+ entry = rt2x00_get_data_entry_done(ring);
+ txd = entry->priv;
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ !rt2x00_get_field32(word, TXD_W0_VALID))
+ break;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+
+ rt2x00lib_txdone(entry, tx_status, retry);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_desc_write(txd, 0, word);
+ rt2x00_ring_index_done_inc(ring);
+ }
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ entry = ring->entry;
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+}
+
+static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * Handle interrupts, walk through all bits
+ * and run the tasks, the bits are checked in order of
+ * priority.
+ */
+
+ /*
+ * 1 - Beacon timer expired interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
+ rt2x00lib_beacondone(rt2x00dev);
+
+ /*
+ * 2 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_RXDONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 3 - Atim ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
+ rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+
+ /*
+ * 4 - Priority ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
+ rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+ /*
+ * 5 - Tx ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
+ rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+ u16 word;
+ u8 *mac;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt2400pci_eepromregister_read;
+ eeprom.register_write = rt2400pci_eepromregister_write;
+ eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ ERROR(rt2x00dev, "Invalid EEPROM data detected.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2460, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2421)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Store led mode, for correct led behaviour.
+ */
+ rt2x00dev->led_mode =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+#ifdef CONFIG_RT2400PCI_RFKILL
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT2400PCI_RFKILL */
+
+ /*
+ * Check if the BBP tuning should be enabled.
+ */
+ if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2420 & RF2421
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg[] = {
+ { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 },
+ { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 },
+ { 3, 0x00022058, 0x000c2002, 0x00000101, 0 },
+ { 4, 0x00022058, 0x000c2016, 0x00000101, 0 },
+ { 5, 0x00022058, 0x000c202a, 0x00000101, 0 },
+ { 6, 0x00022058, 0x000c203e, 0x00000101, 0 },
+ { 7, 0x00022058, 0x000c2052, 0x00000101, 0 },
+ { 8, 0x00022058, 0x000c2066, 0x00000101, 0 },
+ { 9, 0x00022058, 0x000c207a, 0x00000101, 0 },
+ { 10, 0x00022058, 0x000c208e, 0x00000101, 0 },
+ { 11, 0x00022058, 0x000c20a2, 0x00000101, 0 },
+ { 12, 0x00022058, 0x000c20b6, 0x00000101, 0 },
+ { 13, 0x00022058, 0x000c20ca, 0x00000101, 0 },
+ { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 },
+};
+
+static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = 0;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 2;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 1;
+ spec->num_rates = 4;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg);
+ spec->channels = rf_vals_bg;
+}
+
+static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2400pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2400pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt2400pci_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires the beacon ring
+ */
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * since there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
+ rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ return 0;
+}
+
+static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
+ int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * We don't support variating cw_min and cw_max variables
+ * per queue. So by default we only configure the TX queue,
+ * and ignore all other configurations.
+ */
+ if (queue != IEEE80211_TX_QUEUE_DATA0)
+ return -EINVAL;
+
+ if (rt2x00mac_conf_tx(hw, queue, params))
+ return -EINVAL;
+
+ /*
+ * Write configuration to register.
+ */
+ rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params);
+
+ return 0;
+}
+
+static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
+ rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+ tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
+
+ return tsf;
+}
+
+static void rt2400pci_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00pci_register_write(rt2x00dev, CSR16, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+}
+
+static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+ return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
+}
+
+static const struct ieee80211_ops rt2400pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt2400pci_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt2400pci_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2400pci_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt2400pci_get_tsf,
+ .reset_tsf = rt2400pci_reset_tsf,
+ .beacon_update = rt2x00pci_beacon_update,
+ .tx_last_beacon = rt2400pci_tx_last_beacon,
+};
+
+static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
+ .irq_handler = rt2400pci_interrupt,
+ .probe_hw = rt2400pci_probe_hw,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .set_device_state = rt2400pci_set_device_state,
+ .rfkill_poll = rt2400pci_rfkill_poll,
+ .link_stats = rt2400pci_link_stats,
+ .reset_tuner = rt2400pci_reset_tuner,
+ .link_tuner = rt2400pci_link_tuner,
+ .write_tx_desc = rt2400pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .kick_tx_queue = rt2400pci_kick_tx_queue,
+ .fill_rxdone = rt2400pci_fill_rxdone,
+ .config_mac_addr = rt2400pci_config_mac_addr,
+ .config_bssid = rt2400pci_config_bssid,
+ .config_type = rt2400pci_config_type,
+ .config_preamble = rt2400pci_config_preamble,
+ .config = rt2400pci_config,
+};
+
+static const struct rt2x00_ops rt2400pci_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt2400pci_rt2x00_ops,
+ .hw = &rt2400pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2400pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2400pci module information.
+ */
+static struct pci_device_id rt2400pci_device_table[] = {
+ { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt2400pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rt2400pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+
+static int __init rt2400pci_init(void)
+{
+ return pci_register_driver(&rt2400pci_driver);
+}
+
+static void __exit rt2400pci_exit(void)
+{
+ pci_unregister_driver(&rt2400pci_driver);
+}
+
+module_init(rt2400pci_init);
+module_exit(rt2400pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
new file mode 100644
index 000000000000..ae22501f085d
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -0,0 +1,943 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2400pci
+ Abstract: Data structures and registers for the rt2400pci module.
+ Supported chipsets: RT2460.
+ */
+
+#ifndef RT2400PCI_H
+#define RT2400PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2420 0x0000
+#define RF2421 0x0001
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 100
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x0000
+#define CSR_REG_SIZE 0x014c
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0100
+#define BBP_SIZE 0x0020
+#define RF_SIZE 0x0010
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * CSR0: ASIC revision number.
+ */
+#define CSR0 0x0000
+
+/*
+ * CSR1: System control register.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define CSR1 0x0004
+#define CSR1_SOFT_RESET FIELD32(0x00000001)
+#define CSR1_BBP_RESET FIELD32(0x00000002)
+#define CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * CSR2: System admin status register (invalid).
+ */
+#define CSR2 0x0008
+
+/*
+ * CSR3: STA MAC address register 0.
+ */
+#define CSR3 0x000c
+#define CSR3_BYTE0 FIELD32(0x000000ff)
+#define CSR3_BYTE1 FIELD32(0x0000ff00)
+#define CSR3_BYTE2 FIELD32(0x00ff0000)
+#define CSR3_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR4: STA MAC address register 1.
+ */
+#define CSR4 0x0010
+#define CSR4_BYTE4 FIELD32(0x000000ff)
+#define CSR4_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR5: BSSID register 0.
+ */
+#define CSR5 0x0014
+#define CSR5_BYTE0 FIELD32(0x000000ff)
+#define CSR5_BYTE1 FIELD32(0x0000ff00)
+#define CSR5_BYTE2 FIELD32(0x00ff0000)
+#define CSR5_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR6: BSSID register 1.
+ */
+#define CSR6 0x0018
+#define CSR6_BYTE4 FIELD32(0x000000ff)
+#define CSR6_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR7: Interrupt source register.
+ * Write 1 to clear interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ */
+#define CSR7 0x001c
+#define CSR7_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR7_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR7_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR7_RXDONE FIELD32(0x00000040)
+
+/*
+ * CSR8: Interrupt mask register.
+ * Write 1 to mask interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ */
+#define CSR8 0x0020
+#define CSR8_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR8_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR8_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR8_RXDONE FIELD32(0x00000040)
+
+/*
+ * CSR9: Maximum frame length register.
+ * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
+ */
+#define CSR9 0x0024
+#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80)
+
+/*
+ * CSR11: Back-off control register.
+ * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
+ * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
+ * SLOT_TIME: Slot time, default is 20us for 802.11b.
+ * LONG_RETRY: Long retry count.
+ * SHORT_RETRY: Short retry count.
+ */
+#define CSR11 0x002c
+#define CSR11_CWMIN FIELD32(0x0000000f)
+#define CSR11_CWMAX FIELD32(0x000000f0)
+#define CSR11_SLOT_TIME FIELD32(0x00001f00)
+#define CSR11_LONG_RETRY FIELD32(0x00ff0000)
+#define CSR11_SHORT_RETRY FIELD32(0xff000000)
+
+/*
+ * CSR12: Synchronization configuration register 0.
+ * All units in 1/16 TU.
+ * BEACON_INTERVAL: Beacon interval, default is 100 TU.
+ * CFPMAX_DURATION: Cfp maximum duration, default is 100 TU.
+ */
+#define CSR12 0x0030
+#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000)
+
+/*
+ * CSR13: Synchronization configuration register 1.
+ * All units in 1/16 TU.
+ * ATIMW_DURATION: Atim window duration.
+ * CFP_PERIOD: Cfp period, default is 0 TU.
+ */
+#define CSR13 0x0034
+#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff)
+#define CSR13_CFP_PERIOD FIELD32(0x00ff0000)
+
+/*
+ * CSR14: Synchronization control register.
+ * TSF_COUNT: Enable tsf auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable tbcn with reload value.
+ * TCFP: Enable tcfp & cfp / cp switching.
+ * TATIMW: Enable tatimw & atim window switching.
+ * BEACON_GEN: Enable beacon generator.
+ * CFP_COUNT_PRELOAD: Cfp count preload value.
+ * TBCM_PRELOAD: Tbcn preload value in units of 64us.
+ */
+#define CSR14 0x0038
+#define CSR14_TSF_COUNT FIELD32(0x00000001)
+#define CSR14_TSF_SYNC FIELD32(0x00000006)
+#define CSR14_TBCN FIELD32(0x00000008)
+#define CSR14_TCFP FIELD32(0x00000010)
+#define CSR14_TATIMW FIELD32(0x00000020)
+#define CSR14_BEACON_GEN FIELD32(0x00000040)
+#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00)
+#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000)
+
+/*
+ * CSR15: Synchronization status register.
+ * CFP: ASIC is in contention-free period.
+ * ATIMW: ASIC is in ATIM window.
+ * BEACON_SENT: Beacon is send.
+ */
+#define CSR15 0x003c
+#define CSR15_CFP FIELD32(0x00000001)
+#define CSR15_ATIMW FIELD32(0x00000002)
+#define CSR15_BEACON_SENT FIELD32(0x00000004)
+
+/*
+ * CSR16: TSF timer register 0.
+ */
+#define CSR16 0x0040
+#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR17: TSF timer register 1.
+ */
+#define CSR17 0x0044
+#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR18: IFS timer register 0.
+ * SIFS: Sifs, default is 10 us.
+ * PIFS: Pifs, default is 30 us.
+ */
+#define CSR18 0x0048
+#define CSR18_SIFS FIELD32(0x0000ffff)
+#define CSR18_PIFS FIELD32(0xffff0000)
+
+/*
+ * CSR19: IFS timer register 1.
+ * DIFS: Difs, default is 50 us.
+ * EIFS: Eifs, default is 364 us.
+ */
+#define CSR19 0x004c
+#define CSR19_DIFS FIELD32(0x0000ffff)
+#define CSR19_EIFS FIELD32(0xffff0000)
+
+/*
+ * CSR20: Wakeup timer register.
+ * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTOWAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define CSR20 0x0050
+#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff)
+#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000)
+#define CSR20_AUTOWAKE FIELD32(0x01000000)
+
+/*
+ * CSR21: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ */
+#define CSR21 0x0054
+#define CSR21_RELOAD FIELD32(0x00000001)
+#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002)
+#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004)
+#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008)
+#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010)
+#define CSR21_TYPE_93C46 FIELD32(0x00000020)
+
+/*
+ * CSR22: CFP control register.
+ * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
+ * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
+ */
+#define CSR22 0x0058
+#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff)
+#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000)
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXCSR0: TX Control Register.
+ * KICK_TX: Kick tx ring.
+ * KICK_ATIM: Kick atim ring.
+ * KICK_PRIO: Kick priority ring.
+ * ABORT: Abort all transmit related ring operation.
+ */
+#define TXCSR0 0x0060
+#define TXCSR0_KICK_TX FIELD32(0x00000001)
+#define TXCSR0_KICK_ATIM FIELD32(0x00000002)
+#define TXCSR0_KICK_PRIO FIELD32(0x00000004)
+#define TXCSR0_ABORT FIELD32(0x00000008)
+
+/*
+ * TXCSR1: TX Configuration Register.
+ * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
+ * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
+ * TSF_OFFSET: Insert tsf offset.
+ * AUTORESPONDER: Enable auto responder which include ack & cts.
+ */
+#define TXCSR1 0x0064
+#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00)
+#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000)
+#define TXCSR1_AUTORESPONDER FIELD32(0x01000000)
+
+/*
+ * TXCSR2: Tx descriptor configuration register.
+ * TXD_SIZE: Tx descriptor size, default is 48.
+ * NUM_TXD: Number of tx entries in ring.
+ * NUM_ATIM: Number of atim entries in ring.
+ * NUM_PRIO: Number of priority entries in ring.
+ */
+#define TXCSR2 0x0068
+#define TXCSR2_TXD_SIZE FIELD32(0x000000ff)
+#define TXCSR2_NUM_TXD FIELD32(0x0000ff00)
+#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000)
+#define TXCSR2_NUM_PRIO FIELD32(0xff000000)
+
+/*
+ * TXCSR3: TX Ring Base address register.
+ */
+#define TXCSR3 0x006c
+#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR4: TX Atim Ring Base address register.
+ */
+#define TXCSR4 0x0070
+#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR5: TX Prio Ring Base address register.
+ */
+#define TXCSR5 0x0074
+#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR6: Beacon Base address register.
+ */
+#define TXCSR6 0x0078
+#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR7: Auto responder control register.
+ * AR_POWERMANAGEMENT: Auto responder power management bit.
+ */
+#define TXCSR7 0x007c
+#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001)
+
+/*
+ * Receive related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * RXCSR0: RX Control Register.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * PASS_CRC: Pass all packets with crc attached.
+ */
+#define RXCSR0 0x0080
+#define RXCSR0_DISABLE_RX FIELD32(0x00000001)
+#define RXCSR0_DROP_CRC FIELD32(0x00000002)
+#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004)
+#define RXCSR0_DROP_CONTROL FIELD32(0x00000008)
+#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010)
+#define RXCSR0_DROP_TODS FIELD32(0x00000020)
+#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040)
+#define RXCSR0_PASS_CRC FIELD32(0x00000080)
+
+/*
+ * RXCSR1: RX descriptor configuration register.
+ * RXD_SIZE: Rx descriptor size, default is 32b.
+ * NUM_RXD: Number of rx entries in ring.
+ */
+#define RXCSR1 0x0084
+#define RXCSR1_RXD_SIZE FIELD32(0x000000ff)
+#define RXCSR1_NUM_RXD FIELD32(0x0000ff00)
+
+/*
+ * RXCSR2: RX Ring base address register.
+ */
+#define RXCSR2 0x0088
+#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * RXCSR3: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR3 0x0090
+#define RXCSR3_BBP_ID0 FIELD32(0x0000007f)
+#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define RXCSR3_BBP_ID1 FIELD32(0x00007f00)
+#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define RXCSR3_BBP_ID2 FIELD32(0x007f0000)
+#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define RXCSR3_BBP_ID3 FIELD32(0x7f000000)
+#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * RXCSR4: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR4 0x0094
+#define RXCSR4_BBP_ID4 FIELD32(0x0000007f)
+#define RXCSR4_BBP_ID4_VALID FIELD32(0x00000080)
+#define RXCSR4_BBP_ID5 FIELD32(0x00007f00)
+#define RXCSR4_BBP_ID5_VALID FIELD32(0x00008000)
+
+/*
+ * ARCSR0: Auto Responder PLCP config register 0.
+ * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
+ * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR0 0x0098
+#define ARCSR0_AR_BBP_DATA0 FIELD32(0x000000ff)
+#define ARCSR0_AR_BBP_ID0 FIELD32(0x0000ff00)
+#define ARCSR0_AR_BBP_DATA1 FIELD32(0x00ff0000)
+#define ARCSR0_AR_BBP_ID1 FIELD32(0xff000000)
+
+/*
+ * ARCSR1: Auto Responder PLCP config register 1.
+ * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
+ * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR1 0x009c
+#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff)
+#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00)
+#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000)
+#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000)
+
+/*
+ * Miscellaneous Registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PCICSR: PCI control register.
+ * BIG_ENDIAN: 1: big endian, 0: little endian.
+ * RX_TRESHOLD: Rx threshold in dw to start pci access
+ * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
+ * TX_TRESHOLD: Tx threshold in dw to start pci access
+ * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
+ * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
+ * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
+ */
+#define PCICSR 0x008c
+#define PCICSR_BIG_ENDIAN FIELD32(0x00000001)
+#define PCICSR_RX_TRESHOLD FIELD32(0x00000006)
+#define PCICSR_TX_TRESHOLD FIELD32(0x00000018)
+#define PCICSR_BURST_LENTH FIELD32(0x00000060)
+#define PCICSR_ENABLE_CLK FIELD32(0x00000080)
+
+/*
+ * CNT0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define CNT0 0x00a0
+#define CNT0_FCS_ERROR FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT1: PLCP error count.
+ * CNT2: Long error count.
+ * CNT3: CCA false alarm count.
+ * CNT4: Rx FIFO overflow count.
+ * CNT5: Tx FIFO underrun count.
+ */
+#define TIMECSR2 0x00a8
+#define CNT1 0x00ac
+#define CNT2 0x00b0
+#define TIMECSR3 0x00b4
+#define CNT3 0x00b8
+#define CNT4 0x00bc
+#define CNT5 0x00c0
+
+/*
+ * Baseband Control Register.
+ */
+
+/*
+ * PWRCSR0: Power mode configuration register.
+ */
+#define PWRCSR0 0x00c4
+
+/*
+ * Power state transition time registers.
+ */
+#define PSCSR0 0x00c8
+#define PSCSR1 0x00cc
+#define PSCSR2 0x00d0
+#define PSCSR3 0x00d4
+
+/*
+ * PWRCSR1: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURR_STATE: BBP current state.
+ * RF_CURR_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define PWRCSR1 0x00d8
+#define PWRCSR1_SET_STATE FIELD32(0x00000001)
+#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006)
+#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018)
+#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060)
+#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180)
+#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200)
+
+/*
+ * TIMECSR: Timer control register.
+ * US_COUNT: 1 us timer count in units of clock cycles.
+ * US_64_COUNT: 64 us timer count in units of 1 us timer.
+ * BEACON_EXPECT: Beacon expect window.
+ */
+#define TIMECSR 0x00dc
+#define TIMECSR_US_COUNT FIELD32(0x000000ff)
+#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00)
+#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000)
+
+/*
+ * MACCSR0: MAC configuration register 0.
+ */
+#define MACCSR0 0x00e0
+
+/*
+ * MACCSR1: MAC configuration register 1.
+ * KICK_RX: Kick one-shot rx in one-shot rx mode.
+ * ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
+ * BBPRX_RESET_MODE: Ralink bbp rx reset mode.
+ * AUTO_TXBBP: Auto tx logic access bbp control register.
+ * AUTO_RXBBP: Auto rx logic access bbp control register.
+ * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
+ * INTERSIL_IF: Intersil if calibration pin.
+ */
+#define MACCSR1 0x00e4
+#define MACCSR1_KICK_RX FIELD32(0x00000001)
+#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002)
+#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004)
+#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008)
+#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010)
+#define MACCSR1_LOOPBACK FIELD32(0x00000060)
+#define MACCSR1_INTERSIL_IF FIELD32(0x00000080)
+
+/*
+ * RALINKCSR: Ralink Rx auto-reset BBCR.
+ * AR_BBP_DATA#: Auto reset BBP register # data.
+ * AR_BBP_ID#: Auto reset BBP register # id.
+ */
+#define RALINKCSR 0x00e8
+#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff)
+#define RALINKCSR_AR_BBP_ID0 FIELD32(0x0000ff00)
+#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000)
+#define RALINKCSR_AR_BBP_ID1 FIELD32(0xff000000)
+
+/*
+ * BCNCSR: Beacon interval control register.
+ * CHANGE: Write one to change beacon interval.
+ * DELTATIME: The delta time value.
+ * NUM_BEACON: Number of beacon according to mode.
+ * MODE: Please refer to asic specs.
+ * PLUS: Plus or minus delta time value.
+ */
+#define BCNCSR 0x00ec
+#define BCNCSR_CHANGE FIELD32(0x00000001)
+#define BCNCSR_DELTATIME FIELD32(0x0000001e)
+#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0)
+#define BCNCSR_MODE FIELD32(0x00006000)
+#define BCNCSR_PLUS FIELD32(0x00008000)
+
+/*
+ * BBP / RF / IF Control Register.
+ */
+
+/*
+ * BBPCSR: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REGNUM: Selected BBP register.
+ * BUSY: 1: asic is busy execute BBP programming.
+ * WRITE_CONTROL: 1: write BBP, 0: read BBP.
+ */
+#define BBPCSR 0x00f0
+#define BBPCSR_VALUE FIELD32(0x000000ff)
+#define BBPCSR_REGNUM FIELD32(0x00007f00)
+#define BBPCSR_BUSY FIELD32(0x00008000)
+#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000)
+
+/*
+ * RFCSR: RF serial control register.
+ * VALUE: Register value + id to program into rf/if.
+ * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * IF_SELECT: Chip to program: 0: rf, 1: if.
+ * PLL_LD: Rf pll_ld status.
+ * BUSY: 1: asic is busy execute rf programming.
+ */
+#define RFCSR 0x00f4
+#define RFCSR_VALUE FIELD32(0x00ffffff)
+#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define RFCSR_IF_SELECT FIELD32(0x20000000)
+#define RFCSR_PLL_LD FIELD32(0x40000000)
+#define RFCSR_BUSY FIELD32(0x80000000)
+
+/*
+ * LEDCSR: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY: 0: idle, 1: active.
+ */
+#define LEDCSR 0x00f8
+#define LEDCSR_ON_PERIOD FIELD32(0x000000ff)
+#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00)
+#define LEDCSR_LINK FIELD32(0x00010000)
+#define LEDCSR_ACTIVITY FIELD32(0x00020000)
+
+/*
+ * ASIC pointer information.
+ * RXPTR: Current RX ring address.
+ * TXPTR: Current Tx ring address.
+ * PRIPTR: Current Priority ring address.
+ * ATIMPTR: Current ATIM ring address.
+ */
+#define RXPTR 0x0100
+#define TXPTR 0x0104
+#define PRIPTR 0x0108
+#define ATIMPTR 0x010c
+
+/*
+ * GPIO and others.
+ */
+
+/*
+ * GPIOCSR: GPIO control register.
+ */
+#define GPIOCSR 0x0120
+#define GPIOCSR_BIT0 FIELD32(0x00000001)
+#define GPIOCSR_BIT1 FIELD32(0x00000002)
+#define GPIOCSR_BIT2 FIELD32(0x00000004)
+#define GPIOCSR_BIT3 FIELD32(0x00000008)
+#define GPIOCSR_BIT4 FIELD32(0x00000010)
+#define GPIOCSR_BIT5 FIELD32(0x00000020)
+#define GPIOCSR_BIT6 FIELD32(0x00000040)
+#define GPIOCSR_BIT7 FIELD32(0x00000080)
+
+/*
+ * BBPPCSR: BBP Pin control register.
+ */
+#define BBPPCSR 0x0124
+
+/*
+ * BCNCSR1: Tx BEACON offset time control register.
+ * PRELOAD: Beacon timer offset in units of usec.
+ */
+#define BCNCSR1 0x0130
+#define BCNCSR1_PRELOAD FIELD32(0x0000ffff)
+
+/*
+ * MACCSR2: TX_PE to RX_PE turn-around time control register
+ * DELAY: RX_PE low width, in units of pci clock cycle.
+ */
+#define MACCSR2 0x0134
+#define MACCSR2_DELAY FIELD32(0x000000ff)
+
+/*
+ * ARCSR2: 1 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR2 0x013c
+#define ARCSR2_SIGNAL FIELD32(0x000000ff)
+#define ARCSR2_SERVICE FIELD32(0x0000ff00)
+#define ARCSR2_LENGTH_LOW FIELD32(0x00ff0000)
+#define ARCSR2_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR3: 2 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR3 0x0140
+#define ARCSR3_SIGNAL FIELD32(0x000000ff)
+#define ARCSR3_SERVICE FIELD32(0x0000ff00)
+#define ARCSR3_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR4: 5.5 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR4 0x0144
+#define ARCSR4_SIGNAL FIELD32(0x000000ff)
+#define ARCSR4_SERVICE FIELD32(0x0000ff00)
+#define ARCSR4_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR5: 11 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR5 0x0148
+#define ARCSR5_SIGNAL FIELD32(0x000000ff)
+#define ARCSR5_SERVICE FIELD32(0x0000ff00)
+#define ARCSR5_LENGTH FIELD32(0xffff0000)
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R1: TX antenna control
+ */
+#define BBP_R1_TX_ANTENNA FIELD8(0x03)
+
+/*
+ * R4: RX antenna control
+ */
+#define BBP_R4_RX_ANTENNA FIELD8(0x06)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER FIELD32(0x00000100)
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RF_TYPE: Rf_type of this adapter.
+ * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
+ * RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ */
+#define EEPROM_ANTENNA 0x0b
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0040)
+#define EEPROM_ANTENNA_LED_MODE FIELD16(0x0180)
+#define EEPROM_ANTENNA_RX_AGCVGC_TUNING FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0c
+#define EEPROM_BBP_SIZE 7
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START 0x13
+#define EEPROM_TXPOWER_SIZE 7
+#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2 FIELD16(0xff00)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 8 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 8 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_RESULT FIELD32(0x0000001c)
+#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
+#define TXD_W0_ACK FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
+#define TXD_W0_RTS FIELD32(0x00000800)
+#define TXD_W0_IFS FIELD32(0x00006000)
+#define TXD_W0_RETRY_MODE FIELD32(0x00008000)
+#define TXD_W0_AGC FIELD32(0x00ff0000)
+#define TXD_W0_R2 FIELD32(0xff000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define TXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
+#define TXD_W2_DATABYTE_COUNT FIELD32(0xffff0000)
+
+/*
+ * Word3 & 4: PLCP information
+ */
+#define TXD_W3_PLCP_SIGNAL FIELD32(0x0000ffff)
+#define TXD_W3_PLCP_SERVICE FIELD32(0xffff0000)
+#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x0000ffff)
+#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0xffff0000)
+
+/*
+ * Word5
+ */
+#define TXD_W5_BBCR4 FIELD32(0x0000ffff)
+#define TXD_W5_AGC_REG FIELD32(0x007f0000)
+#define TXD_W5_AGC_REG_VALID FIELD32(0x00800000)
+#define TXD_W5_XXX_REG FIELD32(0x7f000000)
+#define TXD_W5_XXX_REG_VALID FIELD32(0x80000000)
+
+/*
+ * Word6
+ */
+#define TXD_W6_SK_BUFF FIELD32(0xffffffff)
+
+/*
+ * Word7
+ */
+#define TXD_W7_RESERVED FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
+#define RXD_W0_MULTICAST FIELD32(0x00000004)
+#define RXD_W0_BROADCAST FIELD32(0x00000008)
+#define RXD_W0_MY_BSS FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
+#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0xffff0000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
+#define RXD_W2_SIGNAL FIELD32(0x00ff0000)
+#define RXD_W2_RSSI FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define RXD_W3_BBR2 FIELD32(0x000000ff)
+#define RXD_W3_BBR3 FIELD32(0x0000ff00)
+#define RXD_W3_BBR4 FIELD32(0x00ff0000)
+#define RXD_W3_BBR5 FIELD32(0xff000000)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RX_END_TIME FIELD32(0xffffffff)
+
+/*
+ * Word5 & 6 & 7: Reserved
+ */
+#define RXD_W5_RESERVED FIELD32(0xffffffff)
+#define RXD_W6_RESERVED FIELD32(0xffffffff)
+#define RXD_W7_RESERVED FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ * NOTE: Logics in rt2400pci for txpower are reversed
+ * compared to the other rt2x00 drivers. A higher txpower
+ * value means that the txpower must be lowered. This is
+ * important when converting the value coming from the
+ * dscape stack to the rt2400 acceptable value.
+ */
+#define MIN_TXPOWER 31
+#define MAX_TXPOWER 62
+#define DEFAULT_TXPOWER 39
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \
+ ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \
+ (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ (__txpower) += MIN_TXPOWER; \
+ ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \
+ (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \
+})
+
+#endif /* RT2400PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
new file mode 100644
index 000000000000..ff2d63267b19
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -0,0 +1,1971 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500pci
+ Abstract: rt2500pci device specific routines.
+ Supported chipsets: RT2560.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2500pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2500pci.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2x00pci_register_read and rt2x00pci_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
+ if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+}
+
+static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+}
+
+static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
+ if (!rt2x00_get_field32(reg, RFCSR_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT);
+}
+
+static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2500pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2500pci_read_csr,
+ .write = rt2500pci_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2500pci_bbp_read,
+ .write = rt2500pci_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2500pci_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT2500PCI_RFKILL
+static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+#else
+#define rt2500pci_rfkill_poll NULL
+#endif /* CONFIG_RT2500PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Enable beacon config
+ */
+ rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+ rt2x00_set_field32(&reg, BCNCSR1_PRELOAD,
+ PREAMBLE + get_duration(IEEE80211_HEADER, 20));
+ rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN,
+ rt2x00lib_get_ring(rt2x00dev,
+ IEEE80211_TX_QUEUE_BEACON)
+ ->tx_params.cw_min);
+ rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+}
+
+static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ int preamble_mask;
+ u32 reg;
+
+ /*
+ * When short preamble is enabled, we should set bit 0x08
+ */
+ preamble_mask = short_preamble << 3;
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+ 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_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+ rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+ rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+ rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+ rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+}
+
+static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+}
+
+static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r70;
+
+ /*
+ * Set TXpower.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+ /*
+ * Switch on tuning bits.
+ * For RT2523 devices we do not need to update the R1 register.
+ */
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
+
+ /*
+ * For RT2525 we should first set the channel to half band higher.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ static const u32 vals[] = {
+ 0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
+ 0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
+ 0x00080d1e, 0x00080d22, 0x00080d26, 0x00080d2a,
+ 0x00080d2e, 0x00080d3a
+ };
+
+ rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500pci_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+ rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500pci_rf_write(rt2x00dev, 4, rf->rf4);
+ }
+
+ rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ /*
+ * Channel 14 requires the Japan filter bit to be set.
+ */
+ r70 = 0x46;
+ rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, rf->channel == 14);
+ rt2500pci_bbp_write(rt2x00dev, 70, r70);
+
+ msleep(1);
+
+ /*
+ * Switch off tuning bits.
+ * For RT2523 devices we do not need to update the R1 register.
+ */
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
+ rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+ }
+
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0);
+ rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ /*
+ * Clear false CRC during channel switch.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+}
+
+static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 rf3;
+
+ rt2x00_rf_read(rt2x00dev, 3, &rf3);
+ rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2500pci_rf_write(rt2x00dev, 3, rf3);
+}
+
+static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ u32 reg;
+ u8 r14;
+ u8 r2;
+
+ rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+ rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+ rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (antenna_tx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * RT2525E and RT5222 need to flip TX I/Q
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+ /*
+ * RT2525E does not need RX I/Q Flip.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+ } else {
+ rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+ rt2500pci_bbp_write(rt2x00dev, 14, r14);
+ rt2500pci_bbp_write(rt2x00dev, 2, r2);
+}
+
+static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+ libconf->conf->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+}
+
+static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt2500pci_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt2500pci_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt2500pci_config_antenna(rt2x00dev,
+ libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt2500pci_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+
+ rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+
+ if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ } else {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT3, &reg);
+ rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
+}
+
+static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt2500pci_bbp_write(rt2x00dev, 17, 0x48);
+ rt2x00dev->link.vgc_level = 0x48;
+}
+
+static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u8 r17;
+
+ /*
+ * To prevent collisions with MAC ASIC on chipsets
+ * up to version C the link tuning should halt after 20
+ * seconds.
+ */
+ if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+ rt2x00dev->link.count > 20)
+ return;
+
+ rt2500pci_bbp_read(rt2x00dev, 17, &r17);
+
+ /*
+ * Chipset versions C and lower should directly continue
+ * to the dynamic CCA tuning.
+ */
+ if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D)
+ goto dynamic_cca_tune;
+
+ /*
+ * A too low RSSI will cause too much false CCA which will
+ * then corrupt the R17 tuning. To remidy this the tuning should
+ * be stopped (While making sure the R17 value will not exceed limits)
+ */
+ if (rssi < -80 && rt2x00dev->link.count > 20) {
+ if (r17 >= 0x41) {
+ r17 = rt2x00dev->link.vgc_level;
+ rt2500pci_bbp_write(rt2x00dev, 17, r17);
+ }
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ if (r17 != 0x50)
+ rt2500pci_bbp_write(rt2x00dev, 17, 0x50);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ if (r17 != 0x41)
+ rt2500pci_bbp_write(rt2x00dev, 17, 0x41);
+ return;
+ }
+
+ /*
+ * Leave short or middle distance condition, restore r17
+ * to the dynamic tuning range.
+ */
+ if (r17 >= 0x41) {
+ rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.vgc_level);
+ return;
+ }
+
+dynamic_cca_tune:
+
+ /*
+ * R17 is inside the dynamic tuning range,
+ * start tuning the link based on the false cca counter.
+ */
+ if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) {
+ rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
+ rt2x00dev->link.vgc_level = r17;
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) {
+ rt2500pci_bbp_write(rt2x00dev, 17, --r17);
+ rt2x00dev->link.vgc_level = r17;
+ }
+}
+
+/*
+ * Initialization functions.
+ */
+static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_desc *rxd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ rxd = ring->entry[i].priv;
+
+ rt2x00_desc_read(rxd, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(rxd, 1, word);
+
+ rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_desc *txd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ txd = ring->entry[i].priv;
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(txd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(ring);
+}
+
+static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize rings.
+ */
+ rt2500pci_init_rxring(rt2x00dev);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ /*
+ * Initialize registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+ rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_TXD,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM,
+ rt2x00dev->bcn[1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+ rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+ rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+ rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
+ rt2x00dev->bcn[1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+ rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
+ rt2x00dev->bcn[0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+ rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
+ rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+ rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+ rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+ rt2x00dev->rx->data_dma);
+ rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+
+ return 0;
+}
+
+static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00020002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+
+ rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+ rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
+ rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
+ rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
+ rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+ rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
+ rt2x00dev->rx->data_size / 128);
+ rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+
+ /*
+ * Always use CWmin and CWmax set in descriptor.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_write(rt2x00dev, CNT3, 0);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID0, 10);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID1, 11);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID2, 13);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID3, 12);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR8, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARTCSR0, &reg);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_1MBS, 112);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_2MBS, 56);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_5_5MBS, 20);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_11MBS, 10);
+ rt2x00pci_register_write(rt2x00dev, ARTCSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARTCSR1, &reg);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_6MBS, 45);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_9MBS, 37);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_12MBS, 33);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_18MBS, 29);
+ rt2x00pci_register_write(rt2x00dev, ARTCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARTCSR2, &reg);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_24MBS, 29);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_36MBS, 25);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_48MBS, 25);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_54MBS, 25);
+ rt2x00pci_register_write(rt2x00dev, ARTCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 47); /* CCK Signal */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 51); /* Rssi */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 42); /* OFDM Rate */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID3, 51); /* RSSI */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, PCICSR, &reg);
+ rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
+ rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
+ rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
+ rt2x00_set_field32(&reg, PCICSR_BURST_LENTH, 1);
+ rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
+ rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
+ rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
+ rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+
+ rt2x00pci_register_write(rt2x00dev, GPIOCSR, 0x0000ff00);
+ rt2x00pci_register_write(rt2x00dev, TESTCSR, 0x000000f0);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00213223);
+ rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+
+ rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+ rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
+ rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 26);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID0, 1);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 26);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID1, 1);
+ rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR1, 0x82188200);
+
+ rt2x00pci_register_write(rt2x00dev, TXACKCSR0, 0x00000020);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ /*
+ * We must clear the FCS and FIFO error count.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+
+ return 0;
+}
+
+static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt2500pci_bbp_write(rt2x00dev, 3, 0x02);
+ rt2500pci_bbp_write(rt2x00dev, 4, 0x19);
+ rt2500pci_bbp_write(rt2x00dev, 14, 0x1c);
+ rt2500pci_bbp_write(rt2x00dev, 15, 0x30);
+ rt2500pci_bbp_write(rt2x00dev, 16, 0xac);
+ rt2500pci_bbp_write(rt2x00dev, 18, 0x18);
+ rt2500pci_bbp_write(rt2x00dev, 19, 0xff);
+ rt2500pci_bbp_write(rt2x00dev, 20, 0x1e);
+ rt2500pci_bbp_write(rt2x00dev, 21, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 22, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 23, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 24, 0x70);
+ rt2500pci_bbp_write(rt2x00dev, 25, 0x40);
+ rt2500pci_bbp_write(rt2x00dev, 26, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 27, 0x23);
+ rt2500pci_bbp_write(rt2x00dev, 30, 0x10);
+ rt2500pci_bbp_write(rt2x00dev, 31, 0x2b);
+ rt2500pci_bbp_write(rt2x00dev, 32, 0xb9);
+ rt2500pci_bbp_write(rt2x00dev, 34, 0x12);
+ rt2500pci_bbp_write(rt2x00dev, 35, 0x50);
+ rt2500pci_bbp_write(rt2x00dev, 39, 0xc4);
+ rt2500pci_bbp_write(rt2x00dev, 40, 0x02);
+ rt2500pci_bbp_write(rt2x00dev, 41, 0x60);
+ rt2500pci_bbp_write(rt2x00dev, 53, 0x10);
+ rt2500pci_bbp_write(rt2x00dev, 54, 0x18);
+ rt2500pci_bbp_write(rt2x00dev, 56, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 57, 0x10);
+ rt2500pci_bbp_write(rt2x00dev, 58, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 61, 0x6d);
+ rt2500pci_bbp_write(rt2x00dev, 62, 0x10);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt2500pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_OFF);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
+ rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt2500pci_init_rings(rt2x00dev) ||
+ rt2500pci_init_registers(rt2x00dev) ||
+ rt2500pci_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+ /*
+ * Enable LED
+ */
+ rt2500pci_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Disable LED
+ */
+ rt2500pci_disable_led(rt2x00dev);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Cancel RX and TX.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+
+ /*
+ * Disable interrupts.
+ */
+ rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char bbp_state;
+ char rf_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
+ rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
+ rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
+ rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+ if (bbp_state == state && rf_state == state)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state: bbp %d and rf %d.\n",
+ state, bbp_state, rf_state);
+
+ return -EBUSY;
+}
+
+static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt2500pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt2500pci_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt2500pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2500pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 3, &word);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 3, word);
+
+ rt2x00_desc_read(txd, 10, &word);
+ rt2x00_set_field32(&word, TXD_W10_RTS,
+ test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+ rt2x00_desc_write(txd, 10, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ }
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ if (queue == IEEE80211_TX_QUEUE_DATA0)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA1)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2500pci_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word2;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 2, &word2);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_entry *entry;
+ struct data_desc *txd;
+ u32 word;
+ int tx_status;
+ int retry;
+
+ while (!rt2x00_ring_empty(ring)) {
+ entry = rt2x00_get_data_entry_done(ring);
+ txd = entry->priv;
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ !rt2x00_get_field32(word, TXD_W0_VALID))
+ break;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+
+ rt2x00lib_txdone(entry, tx_status, retry);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_desc_write(txd, 0, word);
+ rt2x00_ring_index_done_inc(ring);
+ }
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ entry = ring->entry;
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+}
+
+static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * Handle interrupts, walk through all bits
+ * and run the tasks, the bits are checked in order of
+ * priority.
+ */
+
+ /*
+ * 1 - Beacon timer expired interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
+ rt2x00lib_beacondone(rt2x00dev);
+
+ /*
+ * 2 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_RXDONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 3 - Atim ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
+ rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+
+ /*
+ * 4 - Priority ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
+ rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+ /*
+ * 5 - Tx ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
+ rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+ u16 word;
+ u8 *mac;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt2500pci_eepromregister_read;
+ eeprom.register_write = rt2500pci_eepromregister_write;
+ eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n",
+ print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
+ DEFAULT_RSSI_OFFSET);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
+ EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+ }
+
+ return 0;
+}
+
+static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2560, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Store led mode, for correct led behaviour.
+ */
+ rt2x00dev->led_mode =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+#ifdef CONFIG_RT2500PCI_RFKILL
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT2500PCI_RFKILL */
+
+ /*
+ * Check if the BBP tuning should be enabled.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+ /*
+ * Read the RSSI <-> dBm offset information.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
+ rt2x00dev->rssi_offset =
+ rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2522
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2522[] = {
+ { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 },
+ { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 },
+ { 3, 0x00002050, 0x000c2002, 0x00000101, 0 },
+ { 4, 0x00002050, 0x000c2016, 0x00000101, 0 },
+ { 5, 0x00002050, 0x000c202a, 0x00000101, 0 },
+ { 6, 0x00002050, 0x000c203e, 0x00000101, 0 },
+ { 7, 0x00002050, 0x000c2052, 0x00000101, 0 },
+ { 8, 0x00002050, 0x000c2066, 0x00000101, 0 },
+ { 9, 0x00002050, 0x000c207a, 0x00000101, 0 },
+ { 10, 0x00002050, 0x000c208e, 0x00000101, 0 },
+ { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 },
+ { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 },
+ { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 },
+ { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 },
+};
+
+/*
+ * RF value list for RF2523
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2523[] = {
+ { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b },
+ { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b },
+ { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b },
+ { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b },
+ { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b },
+ { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b },
+ { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b },
+ { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b },
+ { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b },
+ { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b },
+ { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b },
+ { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b },
+ { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b },
+ { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2524
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2524[] = {
+ { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b },
+ { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b },
+ { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b },
+ { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b },
+ { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b },
+ { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b },
+ { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b },
+ { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b },
+ { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b },
+ { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b },
+ { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b },
+ { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b },
+ { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b },
+ { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525[] = {
+ { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b },
+ { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b },
+ { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b },
+ { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b },
+ { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b },
+ { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b },
+ { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b },
+ { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b },
+ { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b },
+ { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b },
+ { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b },
+ { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b },
+ { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b },
+ { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525e
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525e[] = {
+ { 1, 0x00022020, 0x00081136, 0x00060111, 0x00000a0b },
+ { 2, 0x00022020, 0x0008113a, 0x00060111, 0x00000a0b },
+ { 3, 0x00022020, 0x0008113e, 0x00060111, 0x00000a0b },
+ { 4, 0x00022020, 0x00081182, 0x00060111, 0x00000a0b },
+ { 5, 0x00022020, 0x00081186, 0x00060111, 0x00000a0b },
+ { 6, 0x00022020, 0x0008118a, 0x00060111, 0x00000a0b },
+ { 7, 0x00022020, 0x0008118e, 0x00060111, 0x00000a0b },
+ { 8, 0x00022020, 0x00081192, 0x00060111, 0x00000a0b },
+ { 9, 0x00022020, 0x00081196, 0x00060111, 0x00000a0b },
+ { 10, 0x00022020, 0x0008119a, 0x00060111, 0x00000a0b },
+ { 11, 0x00022020, 0x0008119e, 0x00060111, 0x00000a0b },
+ { 12, 0x00022020, 0x000811a2, 0x00060111, 0x00000a0b },
+ { 13, 0x00022020, 0x000811a6, 0x00060111, 0x00000a0b },
+ { 14, 0x00022020, 0x000811ae, 0x00060111, 0x00000a1b },
+};
+
+/*
+ * RF value list for RF5222
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5222[] = {
+ { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b },
+ { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b },
+ { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b },
+ { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b },
+ { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b },
+ { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b },
+ { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b },
+ { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b },
+ { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b },
+ { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b },
+ { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b },
+ { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b },
+ { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b },
+ { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f },
+ { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f },
+ { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f },
+ { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f },
+ { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f },
+ { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f },
+ { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f },
+ { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f },
+ { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f },
+ { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f },
+ { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f },
+ { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f },
+ { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f },
+ { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f },
+ { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f },
+ { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f },
+ { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f },
+
+ /* 802.11 UNII */
+ { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f },
+ { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 },
+ { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 },
+ { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 },
+ { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
+};
+
+static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = 0;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 2;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
+ spec->channels = rf_vals_bg_2522;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
+ spec->channels = rf_vals_bg_2523;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
+ spec->channels = rf_vals_bg_2524;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
+ spec->channels = rf_vals_bg_2525;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
+ spec->channels = rf_vals_bg_2525e;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5222);
+ spec->channels = rf_vals_5222;
+ spec->num_modes = 3;
+ }
+}
+
+static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2500pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2500pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt2500pci_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires the beacon ring
+ */
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2500pci_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_BCAST, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
+ rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ return 0;
+}
+
+static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
+ rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+ tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
+
+ return tsf;
+}
+
+static void rt2500pci_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00pci_register_write(rt2x00dev, CSR16, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+}
+
+static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+ return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
+}
+
+static const struct ieee80211_ops rt2500pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt2500pci_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt2500pci_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt2500pci_get_tsf,
+ .reset_tsf = rt2500pci_reset_tsf,
+ .beacon_update = rt2x00pci_beacon_update,
+ .tx_last_beacon = rt2500pci_tx_last_beacon,
+};
+
+static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
+ .irq_handler = rt2500pci_interrupt,
+ .probe_hw = rt2500pci_probe_hw,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .set_device_state = rt2500pci_set_device_state,
+ .rfkill_poll = rt2500pci_rfkill_poll,
+ .link_stats = rt2500pci_link_stats,
+ .reset_tuner = rt2500pci_reset_tuner,
+ .link_tuner = rt2500pci_link_tuner,
+ .write_tx_desc = rt2500pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .kick_tx_queue = rt2500pci_kick_tx_queue,
+ .fill_rxdone = rt2500pci_fill_rxdone,
+ .config_mac_addr = rt2500pci_config_mac_addr,
+ .config_bssid = rt2500pci_config_bssid,
+ .config_type = rt2500pci_config_type,
+ .config_preamble = rt2500pci_config_preamble,
+ .config = rt2500pci_config,
+};
+
+static const struct rt2x00_ops rt2500pci_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt2500pci_rt2x00_ops,
+ .hw = &rt2500pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2500pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2500pci module information.
+ */
+static struct pci_device_id rt2500pci_device_table[] = {
+ { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2500 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt2500pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rt2500pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+
+static int __init rt2500pci_init(void)
+{
+ return pci_register_driver(&rt2500pci_driver);
+}
+
+static void __exit rt2500pci_exit(void)
+{
+ pci_unregister_driver(&rt2500pci_driver);
+}
+
+module_init(rt2500pci_init);
+module_exit(rt2500pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
new file mode 100644
index 000000000000..d92aa56b2f4b
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -0,0 +1,1236 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500pci
+ Abstract: Data structures and registers for the rt2500pci module.
+ Supported chipsets: RT2560.
+ */
+
+#ifndef RT2500PCI_H
+#define RT2500PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2522 0x0000
+#define RF2523 0x0001
+#define RF2524 0x0002
+#define RF2525 0x0003
+#define RF2525E 0x0004
+#define RF5222 0x0010
+
+/*
+ * RT2560 version
+ */
+#define RT2560_VERSION_B 2
+#define RT2560_VERSION_C 3
+#define RT2560_VERSION_D 4
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 121
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x0000
+#define CSR_REG_SIZE 0x0174
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0200
+#define BBP_SIZE 0x0040
+#define RF_SIZE 0x0014
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * CSR0: ASIC revision number.
+ */
+#define CSR0 0x0000
+
+/*
+ * CSR1: System control register.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define CSR1 0x0004
+#define CSR1_SOFT_RESET FIELD32(0x00000001)
+#define CSR1_BBP_RESET FIELD32(0x00000002)
+#define CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * CSR2: System admin status register (invalid).
+ */
+#define CSR2 0x0008
+
+/*
+ * CSR3: STA MAC address register 0.
+ */
+#define CSR3 0x000c
+#define CSR3_BYTE0 FIELD32(0x000000ff)
+#define CSR3_BYTE1 FIELD32(0x0000ff00)
+#define CSR3_BYTE2 FIELD32(0x00ff0000)
+#define CSR3_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR4: STA MAC address register 1.
+ */
+#define CSR4 0x0010
+#define CSR4_BYTE4 FIELD32(0x000000ff)
+#define CSR4_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR5: BSSID register 0.
+ */
+#define CSR5 0x0014
+#define CSR5_BYTE0 FIELD32(0x000000ff)
+#define CSR5_BYTE1 FIELD32(0x0000ff00)
+#define CSR5_BYTE2 FIELD32(0x00ff0000)
+#define CSR5_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR6: BSSID register 1.
+ */
+#define CSR6 0x0018
+#define CSR6_BYTE4 FIELD32(0x000000ff)
+#define CSR6_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR7: Interrupt source register.
+ * Write 1 to clear.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ * DECRYPTION_DONE: Decryption done interrupt.
+ * ENCRYPTION_DONE: Encryption done interrupt.
+ * UART1_TX_TRESHOLD: UART1 TX reaches threshold.
+ * UART1_RX_TRESHOLD: UART1 RX reaches threshold.
+ * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold.
+ * UART1_TX_BUFF_ERROR: UART1 TX buffer error.
+ * UART1_RX_BUFF_ERROR: UART1 RX buffer error.
+ * UART2_TX_TRESHOLD: UART2 TX reaches threshold.
+ * UART2_RX_TRESHOLD: UART2 RX reaches threshold.
+ * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold.
+ * UART2_TX_BUFF_ERROR: UART2 TX buffer error.
+ * UART2_RX_BUFF_ERROR: UART2 RX buffer error.
+ * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period).
+
+ */
+#define CSR7 0x001c
+#define CSR7_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR7_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR7_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR7_RXDONE FIELD32(0x00000040)
+#define CSR7_DECRYPTION_DONE FIELD32(0x00000080)
+#define CSR7_ENCRYPTION_DONE FIELD32(0x00000100)
+#define CSR7_UART1_TX_TRESHOLD FIELD32(0x00000200)
+#define CSR7_UART1_RX_TRESHOLD FIELD32(0x00000400)
+#define CSR7_UART1_IDLE_TRESHOLD FIELD32(0x00000800)
+#define CSR7_UART1_TX_BUFF_ERROR FIELD32(0x00001000)
+#define CSR7_UART1_RX_BUFF_ERROR FIELD32(0x00002000)
+#define CSR7_UART2_TX_TRESHOLD FIELD32(0x00004000)
+#define CSR7_UART2_RX_TRESHOLD FIELD32(0x00008000)
+#define CSR7_UART2_IDLE_TRESHOLD FIELD32(0x00010000)
+#define CSR7_UART2_TX_BUFF_ERROR FIELD32(0x00020000)
+#define CSR7_UART2_RX_BUFF_ERROR FIELD32(0x00040000)
+#define CSR7_TIMER_CSR3_EXPIRE FIELD32(0x00080000)
+
+/*
+ * CSR8: Interrupt mask register.
+ * Write 1 to mask interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ * DECRYPTION_DONE: Decryption done interrupt.
+ * ENCRYPTION_DONE: Encryption done interrupt.
+ * UART1_TX_TRESHOLD: UART1 TX reaches threshold.
+ * UART1_RX_TRESHOLD: UART1 RX reaches threshold.
+ * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold.
+ * UART1_TX_BUFF_ERROR: UART1 TX buffer error.
+ * UART1_RX_BUFF_ERROR: UART1 RX buffer error.
+ * UART2_TX_TRESHOLD: UART2 TX reaches threshold.
+ * UART2_RX_TRESHOLD: UART2 RX reaches threshold.
+ * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold.
+ * UART2_TX_BUFF_ERROR: UART2 TX buffer error.
+ * UART2_RX_BUFF_ERROR: UART2 RX buffer error.
+ * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period).
+ */
+#define CSR8 0x0020
+#define CSR8_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR8_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR8_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR8_RXDONE FIELD32(0x00000040)
+#define CSR8_DECRYPTION_DONE FIELD32(0x00000080)
+#define CSR8_ENCRYPTION_DONE FIELD32(0x00000100)
+#define CSR8_UART1_TX_TRESHOLD FIELD32(0x00000200)
+#define CSR8_UART1_RX_TRESHOLD FIELD32(0x00000400)
+#define CSR8_UART1_IDLE_TRESHOLD FIELD32(0x00000800)
+#define CSR8_UART1_TX_BUFF_ERROR FIELD32(0x00001000)
+#define CSR8_UART1_RX_BUFF_ERROR FIELD32(0x00002000)
+#define CSR8_UART2_TX_TRESHOLD FIELD32(0x00004000)
+#define CSR8_UART2_RX_TRESHOLD FIELD32(0x00008000)
+#define CSR8_UART2_IDLE_TRESHOLD FIELD32(0x00010000)
+#define CSR8_UART2_TX_BUFF_ERROR FIELD32(0x00020000)
+#define CSR8_UART2_RX_BUFF_ERROR FIELD32(0x00040000)
+#define CSR8_TIMER_CSR3_EXPIRE FIELD32(0x00080000)
+
+/*
+ * CSR9: Maximum frame length register.
+ * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
+ */
+#define CSR9 0x0024
+#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80)
+
+/*
+ * SECCSR0: WEP control register.
+ * KICK_DECRYPT: Kick decryption engine, self-clear.
+ * ONE_SHOT: 0: ring mode, 1: One shot only mode.
+ * DESC_ADDRESS: Descriptor physical address of frame.
+ */
+#define SECCSR0 0x0028
+#define SECCSR0_KICK_DECRYPT FIELD32(0x00000001)
+#define SECCSR0_ONE_SHOT FIELD32(0x00000002)
+#define SECCSR0_DESC_ADDRESS FIELD32(0xfffffffc)
+
+/*
+ * CSR11: Back-off control register.
+ * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
+ * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
+ * SLOT_TIME: Slot time, default is 20us for 802.11b
+ * CW_SELECT: CWmin/CWmax selection, 1: Register, 0: TXD.
+ * LONG_RETRY: Long retry count.
+ * SHORT_RETRY: Short retry count.
+ */
+#define CSR11 0x002c
+#define CSR11_CWMIN FIELD32(0x0000000f)
+#define CSR11_CWMAX FIELD32(0x000000f0)
+#define CSR11_SLOT_TIME FIELD32(0x00001f00)
+#define CSR11_CW_SELECT FIELD32(0x00002000)
+#define CSR11_LONG_RETRY FIELD32(0x00ff0000)
+#define CSR11_SHORT_RETRY FIELD32(0xff000000)
+
+/*
+ * CSR12: Synchronization configuration register 0.
+ * All units in 1/16 TU.
+ * BEACON_INTERVAL: Beacon interval, default is 100 TU.
+ * CFP_MAX_DURATION: Cfp maximum duration, default is 100 TU.
+ */
+#define CSR12 0x0030
+#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000)
+
+/*
+ * CSR13: Synchronization configuration register 1.
+ * All units in 1/16 TU.
+ * ATIMW_DURATION: Atim window duration.
+ * CFP_PERIOD: Cfp period, default is 0 TU.
+ */
+#define CSR13 0x0034
+#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff)
+#define CSR13_CFP_PERIOD FIELD32(0x00ff0000)
+
+/*
+ * CSR14: Synchronization control register.
+ * TSF_COUNT: Enable tsf auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable tbcn with reload value.
+ * TCFP: Enable tcfp & cfp / cp switching.
+ * TATIMW: Enable tatimw & atim window switching.
+ * BEACON_GEN: Enable beacon generator.
+ * CFP_COUNT_PRELOAD: Cfp count preload value.
+ * TBCM_PRELOAD: Tbcn preload value in units of 64us.
+ */
+#define CSR14 0x0038
+#define CSR14_TSF_COUNT FIELD32(0x00000001)
+#define CSR14_TSF_SYNC FIELD32(0x00000006)
+#define CSR14_TBCN FIELD32(0x00000008)
+#define CSR14_TCFP FIELD32(0x00000010)
+#define CSR14_TATIMW FIELD32(0x00000020)
+#define CSR14_BEACON_GEN FIELD32(0x00000040)
+#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00)
+#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000)
+
+/*
+ * CSR15: Synchronization status register.
+ * CFP: ASIC is in contention-free period.
+ * ATIMW: ASIC is in ATIM window.
+ * BEACON_SENT: Beacon is send.
+ */
+#define CSR15 0x003c
+#define CSR15_CFP FIELD32(0x00000001)
+#define CSR15_ATIMW FIELD32(0x00000002)
+#define CSR15_BEACON_SENT FIELD32(0x00000004)
+
+/*
+ * CSR16: TSF timer register 0.
+ */
+#define CSR16 0x0040
+#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR17: TSF timer register 1.
+ */
+#define CSR17 0x0044
+#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR18: IFS timer register 0.
+ * SIFS: Sifs, default is 10 us.
+ * PIFS: Pifs, default is 30 us.
+ */
+#define CSR18 0x0048
+#define CSR18_SIFS FIELD32(0x000001ff)
+#define CSR18_PIFS FIELD32(0x001f0000)
+
+/*
+ * CSR19: IFS timer register 1.
+ * DIFS: Difs, default is 50 us.
+ * EIFS: Eifs, default is 364 us.
+ */
+#define CSR19 0x004c
+#define CSR19_DIFS FIELD32(0x0000ffff)
+#define CSR19_EIFS FIELD32(0xffff0000)
+
+/*
+ * CSR20: Wakeup timer register.
+ * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTOWAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define CSR20 0x0050
+#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff)
+#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000)
+#define CSR20_AUTOWAKE FIELD32(0x01000000)
+
+/*
+ * CSR21: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ */
+#define CSR21 0x0054
+#define CSR21_RELOAD FIELD32(0x00000001)
+#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002)
+#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004)
+#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008)
+#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010)
+#define CSR21_TYPE_93C46 FIELD32(0x00000020)
+
+/*
+ * CSR22: CFP control register.
+ * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
+ * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
+ */
+#define CSR22 0x0058
+#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff)
+#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000)
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXCSR0: TX Control Register.
+ * KICK_TX: Kick tx ring.
+ * KICK_ATIM: Kick atim ring.
+ * KICK_PRIO: Kick priority ring.
+ * ABORT: Abort all transmit related ring operation.
+ */
+#define TXCSR0 0x0060
+#define TXCSR0_KICK_TX FIELD32(0x00000001)
+#define TXCSR0_KICK_ATIM FIELD32(0x00000002)
+#define TXCSR0_KICK_PRIO FIELD32(0x00000004)
+#define TXCSR0_ABORT FIELD32(0x00000008)
+
+/*
+ * TXCSR1: TX Configuration Register.
+ * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
+ * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
+ * TSF_OFFSET: Insert tsf offset.
+ * AUTORESPONDER: Enable auto responder which include ack & cts.
+ */
+#define TXCSR1 0x0064
+#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00)
+#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000)
+#define TXCSR1_AUTORESPONDER FIELD32(0x01000000)
+
+/*
+ * TXCSR2: Tx descriptor configuration register.
+ * TXD_SIZE: Tx descriptor size, default is 48.
+ * NUM_TXD: Number of tx entries in ring.
+ * NUM_ATIM: Number of atim entries in ring.
+ * NUM_PRIO: Number of priority entries in ring.
+ */
+#define TXCSR2 0x0068
+#define TXCSR2_TXD_SIZE FIELD32(0x000000ff)
+#define TXCSR2_NUM_TXD FIELD32(0x0000ff00)
+#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000)
+#define TXCSR2_NUM_PRIO FIELD32(0xff000000)
+
+/*
+ * TXCSR3: TX Ring Base address register.
+ */
+#define TXCSR3 0x006c
+#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR4: TX Atim Ring Base address register.
+ */
+#define TXCSR4 0x0070
+#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR5: TX Prio Ring Base address register.
+ */
+#define TXCSR5 0x0074
+#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR6: Beacon Base address register.
+ */
+#define TXCSR6 0x0078
+#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR7: Auto responder control register.
+ * AR_POWERMANAGEMENT: Auto responder power management bit.
+ */
+#define TXCSR7 0x007c
+#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001)
+
+/*
+ * TXCSR8: CCK Tx BBP register.
+ */
+#define TXCSR8 0x0098
+#define TXCSR8_BBP_ID0 FIELD32(0x0000007f)
+#define TXCSR8_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXCSR8_BBP_ID1 FIELD32(0x00007f00)
+#define TXCSR8_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXCSR8_BBP_ID2 FIELD32(0x007f0000)
+#define TXCSR8_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXCSR8_BBP_ID3 FIELD32(0x7f000000)
+#define TXCSR8_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXCSR9: OFDM TX BBP registers
+ * OFDM_SIGNAL: BBP rate field address for OFDM.
+ * OFDM_SERVICE: BBP service field address for OFDM.
+ * OFDM_LENGTH_LOW: BBP length low byte address for OFDM.
+ * OFDM_LENGTH_HIGH: BBP length high byte address for OFDM.
+ */
+#define TXCSR9 0x0094
+#define TXCSR9_OFDM_RATE FIELD32(0x000000ff)
+#define TXCSR9_OFDM_SERVICE FIELD32(0x0000ff00)
+#define TXCSR9_OFDM_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXCSR9_OFDM_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Receive related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * RXCSR0: RX Control Register.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * PASS_CRC: Pass all packets with crc attached.
+ * PASS_CRC: Pass all packets with crc attached.
+ * PASS_PLCP: Pass all packets with 4 bytes PLCP attached.
+ * DROP_MCAST: Drop multicast frames.
+ * DROP_BCAST: Drop broadcast frames.
+ * ENABLE_QOS: Accept QOS data frame and parse QOS field.
+ */
+#define RXCSR0 0x0080
+#define RXCSR0_DISABLE_RX FIELD32(0x00000001)
+#define RXCSR0_DROP_CRC FIELD32(0x00000002)
+#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004)
+#define RXCSR0_DROP_CONTROL FIELD32(0x00000008)
+#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010)
+#define RXCSR0_DROP_TODS FIELD32(0x00000020)
+#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040)
+#define RXCSR0_PASS_CRC FIELD32(0x00000080)
+#define RXCSR0_PASS_PLCP FIELD32(0x00000100)
+#define RXCSR0_DROP_MCAST FIELD32(0x00000200)
+#define RXCSR0_DROP_BCAST FIELD32(0x00000400)
+#define RXCSR0_ENABLE_QOS FIELD32(0x00000800)
+
+/*
+ * RXCSR1: RX descriptor configuration register.
+ * RXD_SIZE: Rx descriptor size, default is 32b.
+ * NUM_RXD: Number of rx entries in ring.
+ */
+#define RXCSR1 0x0084
+#define RXCSR1_RXD_SIZE FIELD32(0x000000ff)
+#define RXCSR1_NUM_RXD FIELD32(0x0000ff00)
+
+/*
+ * RXCSR2: RX Ring base address register.
+ */
+#define RXCSR2 0x0088
+#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * RXCSR3: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR3 0x0090
+#define RXCSR3_BBP_ID0 FIELD32(0x0000007f)
+#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define RXCSR3_BBP_ID1 FIELD32(0x00007f00)
+#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define RXCSR3_BBP_ID2 FIELD32(0x007f0000)
+#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define RXCSR3_BBP_ID3 FIELD32(0x7f000000)
+#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * ARCSR1: Auto Responder PLCP config register 1.
+ * AR_BBP_DATA#: Auto responder BBP register # data.
+ * AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR1 0x009c
+#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff)
+#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00)
+#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000)
+#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000)
+
+/*
+ * Miscellaneous Registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+
+ */
+
+/*
+ * PCICSR: PCI control register.
+ * BIG_ENDIAN: 1: big endian, 0: little endian.
+ * RX_TRESHOLD: Rx threshold in dw to start pci access
+ * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
+ * TX_TRESHOLD: Tx threshold in dw to start pci access
+ * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
+ * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
+ * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
+ * READ_MULTIPLE: Enable memory read multiple.
+ * WRITE_INVALID: Enable memory write & invalid.
+ */
+#define PCICSR 0x008c
+#define PCICSR_BIG_ENDIAN FIELD32(0x00000001)
+#define PCICSR_RX_TRESHOLD FIELD32(0x00000006)
+#define PCICSR_TX_TRESHOLD FIELD32(0x00000018)
+#define PCICSR_BURST_LENTH FIELD32(0x00000060)
+#define PCICSR_ENABLE_CLK FIELD32(0x00000080)
+#define PCICSR_READ_MULTIPLE FIELD32(0x00000100)
+#define PCICSR_WRITE_INVALID FIELD32(0x00000200)
+
+/*
+ * CNT0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define CNT0 0x00a0
+#define CNT0_FCS_ERROR FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT1: PLCP error count.
+ * CNT2: Long error count.
+ */
+#define TIMECSR2 0x00a8
+#define CNT1 0x00ac
+#define CNT2 0x00b0
+#define TIMECSR3 0x00b4
+
+/*
+ * CNT3: CCA false alarm count.
+ */
+#define CNT3 0x00b8
+#define CNT3_FALSE_CCA FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT4: Rx FIFO overflow count.
+ * CNT5: Tx FIFO underrun count.
+ */
+#define CNT4 0x00bc
+#define CNT5 0x00c0
+
+/*
+ * Baseband Control Register.
+ */
+
+/*
+ * PWRCSR0: Power mode configuration register.
+ */
+#define PWRCSR0 0x00c4
+
+/*
+ * Power state transition time registers.
+ */
+#define PSCSR0 0x00c8
+#define PSCSR1 0x00cc
+#define PSCSR2 0x00d0
+#define PSCSR3 0x00d4
+
+/*
+ * PWRCSR1: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURR_STATE: BBP current state.
+ * RF_CURR_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define PWRCSR1 0x00d8
+#define PWRCSR1_SET_STATE FIELD32(0x00000001)
+#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006)
+#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018)
+#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060)
+#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180)
+#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200)
+
+/*
+ * TIMECSR: Timer control register.
+ * US_COUNT: 1 us timer count in units of clock cycles.
+ * US_64_COUNT: 64 us timer count in units of 1 us timer.
+ * BEACON_EXPECT: Beacon expect window.
+ */
+#define TIMECSR 0x00dc
+#define TIMECSR_US_COUNT FIELD32(0x000000ff)
+#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00)
+#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000)
+
+/*
+ * MACCSR0: MAC configuration register 0.
+ */
+#define MACCSR0 0x00e0
+
+/*
+ * MACCSR1: MAC configuration register 1.
+ * KICK_RX: Kick one-shot rx in one-shot rx mode.
+ * ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
+ * BBPRX_RESET_MODE: Ralink bbp rx reset mode.
+ * AUTO_TXBBP: Auto tx logic access bbp control register.
+ * AUTO_RXBBP: Auto rx logic access bbp control register.
+ * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
+ * INTERSIL_IF: Intersil if calibration pin.
+ */
+#define MACCSR1 0x00e4
+#define MACCSR1_KICK_RX FIELD32(0x00000001)
+#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002)
+#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004)
+#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008)
+#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010)
+#define MACCSR1_LOOPBACK FIELD32(0x00000060)
+#define MACCSR1_INTERSIL_IF FIELD32(0x00000080)
+
+/*
+ * RALINKCSR: Ralink Rx auto-reset BBCR.
+ * AR_BBP_DATA#: Auto reset BBP register # data.
+ * AR_BBP_ID#: Auto reset BBP register # id.
+ */
+#define RALINKCSR 0x00e8
+#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff)
+#define RALINKCSR_AR_BBP_ID0 FIELD32(0x00007f00)
+#define RALINKCSR_AR_BBP_VALID0 FIELD32(0x00008000)
+#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000)
+#define RALINKCSR_AR_BBP_ID1 FIELD32(0x7f000000)
+#define RALINKCSR_AR_BBP_VALID1 FIELD32(0x80000000)
+
+/*
+ * BCNCSR: Beacon interval control register.
+ * CHANGE: Write one to change beacon interval.
+ * DELTATIME: The delta time value.
+ * NUM_BEACON: Number of beacon according to mode.
+ * MODE: Please refer to asic specs.
+ * PLUS: Plus or minus delta time value.
+ */
+#define BCNCSR 0x00ec
+#define BCNCSR_CHANGE FIELD32(0x00000001)
+#define BCNCSR_DELTATIME FIELD32(0x0000001e)
+#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0)
+#define BCNCSR_MODE FIELD32(0x00006000)
+#define BCNCSR_PLUS FIELD32(0x00008000)
+
+/*
+ * BBP / RF / IF Control Register.
+ */
+
+/*
+ * BBPCSR: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REGNUM: Selected BBP register.
+ * BUSY: 1: asic is busy execute BBP programming.
+ * WRITE_CONTROL: 1: write BBP, 0: read BBP.
+ */
+#define BBPCSR 0x00f0
+#define BBPCSR_VALUE FIELD32(0x000000ff)
+#define BBPCSR_REGNUM FIELD32(0x00007f00)
+#define BBPCSR_BUSY FIELD32(0x00008000)
+#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000)
+
+/*
+ * RFCSR: RF serial control register.
+ * VALUE: Register value + id to program into rf/if.
+ * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * IF_SELECT: Chip to program: 0: rf, 1: if.
+ * PLL_LD: Rf pll_ld status.
+ * BUSY: 1: asic is busy execute rf programming.
+ */
+#define RFCSR 0x00f4
+#define RFCSR_VALUE FIELD32(0x00ffffff)
+#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define RFCSR_IF_SELECT FIELD32(0x20000000)
+#define RFCSR_PLL_LD FIELD32(0x40000000)
+#define RFCSR_BUSY FIELD32(0x80000000)
+
+/*
+ * LEDCSR: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY: 0: idle, 1: active.
+ * LINK_POLARITY: 0: active low, 1: active high.
+ * ACTIVITY_POLARITY: 0: active low, 1: active high.
+ * LED_DEFAULT: LED state for "enable" 0: ON, 1: OFF.
+ */
+#define LEDCSR 0x00f8
+#define LEDCSR_ON_PERIOD FIELD32(0x000000ff)
+#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00)
+#define LEDCSR_LINK FIELD32(0x00010000)
+#define LEDCSR_ACTIVITY FIELD32(0x00020000)
+#define LEDCSR_LINK_POLARITY FIELD32(0x00040000)
+#define LEDCSR_ACTIVITY_POLARITY FIELD32(0x00080000)
+#define LEDCSR_LED_DEFAULT FIELD32(0x00100000)
+
+/*
+ * AES control register.
+ */
+#define SECCSR3 0x00fc
+
+/*
+ * ASIC pointer information.
+ * RXPTR: Current RX ring address.
+ * TXPTR: Current Tx ring address.
+ * PRIPTR: Current Priority ring address.
+ * ATIMPTR: Current ATIM ring address.
+ */
+#define RXPTR 0x0100
+#define TXPTR 0x0104
+#define PRIPTR 0x0108
+#define ATIMPTR 0x010c
+
+/*
+ * TXACKCSR0: TX ACK timeout.
+ */
+#define TXACKCSR0 0x0110
+
+/*
+ * ACK timeout count registers.
+ * ACKCNT0: TX ACK timeout count.
+ * ACKCNT1: RX ACK timeout count.
+ */
+#define ACKCNT0 0x0114
+#define ACKCNT1 0x0118
+
+/*
+ * GPIO and others.
+ */
+
+/*
+ * GPIOCSR: GPIO control register.
+ */
+#define GPIOCSR 0x0120
+#define GPIOCSR_BIT0 FIELD32(0x00000001)
+#define GPIOCSR_BIT1 FIELD32(0x00000002)
+#define GPIOCSR_BIT2 FIELD32(0x00000004)
+#define GPIOCSR_BIT3 FIELD32(0x00000008)
+#define GPIOCSR_BIT4 FIELD32(0x00000010)
+#define GPIOCSR_BIT5 FIELD32(0x00000020)
+#define GPIOCSR_BIT6 FIELD32(0x00000040)
+#define GPIOCSR_BIT7 FIELD32(0x00000080)
+#define GPIOCSR_DIR0 FIELD32(0x00000100)
+#define GPIOCSR_DIR1 FIELD32(0x00000200)
+#define GPIOCSR_DIR2 FIELD32(0x00000400)
+#define GPIOCSR_DIR3 FIELD32(0x00000800)
+#define GPIOCSR_DIR4 FIELD32(0x00001000)
+#define GPIOCSR_DIR5 FIELD32(0x00002000)
+#define GPIOCSR_DIR6 FIELD32(0x00004000)
+#define GPIOCSR_DIR7 FIELD32(0x00008000)
+
+/*
+ * FIFO pointer registers.
+ * FIFOCSR0: TX FIFO pointer.
+ * FIFOCSR1: RX FIFO pointer.
+ */
+#define FIFOCSR0 0x0128
+#define FIFOCSR1 0x012c
+
+/*
+ * BCNCSR1: Tx BEACON offset time control register.
+ * PRELOAD: Beacon timer offset in units of usec.
+ * BEACON_CWMIN: 2^CwMin.
+ */
+#define BCNCSR1 0x0130
+#define BCNCSR1_PRELOAD FIELD32(0x0000ffff)
+#define BCNCSR1_BEACON_CWMIN FIELD32(0x000f0000)
+
+/*
+ * MACCSR2: TX_PE to RX_PE turn-around time control register
+ * DELAY: RX_PE low width, in units of pci clock cycle.
+ */
+#define MACCSR2 0x0134
+#define MACCSR2_DELAY FIELD32(0x000000ff)
+
+/*
+ * TESTCSR: TEST mode selection register.
+ */
+#define TESTCSR 0x0138
+
+/*
+ * ARCSR2: 1 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR2 0x013c
+#define ARCSR2_SIGNAL FIELD32(0x000000ff)
+#define ARCSR2_SERVICE FIELD32(0x0000ff00)
+#define ARCSR2_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR3: 2 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR3 0x0140
+#define ARCSR3_SIGNAL FIELD32(0x000000ff)
+#define ARCSR3_SERVICE FIELD32(0x0000ff00)
+#define ARCSR3_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR4: 5.5 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR4 0x0144
+#define ARCSR4_SIGNAL FIELD32(0x000000ff)
+#define ARCSR4_SERVICE FIELD32(0x0000ff00)
+#define ARCSR4_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR5: 11 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR5 0x0148
+#define ARCSR5_SIGNAL FIELD32(0x000000ff)
+#define ARCSR5_SERVICE FIELD32(0x0000ff00)
+#define ARCSR5_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARTCSR0: CCK ACK/CTS payload consumed time for 1/2/5.5/11 mbps.
+ */
+#define ARTCSR0 0x014c
+#define ARTCSR0_ACK_CTS_11MBS FIELD32(0x000000ff)
+#define ARTCSR0_ACK_CTS_5_5MBS FIELD32(0x0000ff00)
+#define ARTCSR0_ACK_CTS_2MBS FIELD32(0x00ff0000)
+#define ARTCSR0_ACK_CTS_1MBS FIELD32(0xff000000)
+
+
+/*
+ * ARTCSR1: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define ARTCSR1 0x0150
+#define ARTCSR1_ACK_CTS_6MBS FIELD32(0x000000ff)
+#define ARTCSR1_ACK_CTS_9MBS FIELD32(0x0000ff00)
+#define ARTCSR1_ACK_CTS_12MBS FIELD32(0x00ff0000)
+#define ARTCSR1_ACK_CTS_18MBS FIELD32(0xff000000)
+
+/*
+ * ARTCSR2: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define ARTCSR2 0x0154
+#define ARTCSR2_ACK_CTS_24MBS FIELD32(0x000000ff)
+#define ARTCSR2_ACK_CTS_36MBS FIELD32(0x0000ff00)
+#define ARTCSR2_ACK_CTS_48MBS FIELD32(0x00ff0000)
+#define ARTCSR2_ACK_CTS_54MBS FIELD32(0xff000000)
+
+/*
+ * SECCSR1_RT2509: WEP control register.
+ * KICK_ENCRYPT: Kick encryption engine, self-clear.
+ * ONE_SHOT: 0: ring mode, 1: One shot only mode.
+ * DESC_ADDRESS: Descriptor physical address of frame.
+ */
+#define SECCSR1 0x0158
+#define SECCSR1_KICK_ENCRYPT FIELD32(0x00000001)
+#define SECCSR1_ONE_SHOT FIELD32(0x00000002)
+#define SECCSR1_DESC_ADDRESS FIELD32(0xfffffffc)
+
+/*
+ * BBPCSR1: BBP TX configuration.
+ */
+#define BBPCSR1 0x015c
+#define BBPCSR1_CCK FIELD32(0x00000003)
+#define BBPCSR1_CCK_FLIP FIELD32(0x00000004)
+#define BBPCSR1_OFDM FIELD32(0x00030000)
+#define BBPCSR1_OFDM_FLIP FIELD32(0x00040000)
+
+/*
+ * Dual band configuration registers.
+ * DBANDCSR0: Dual band configuration register 0.
+ * DBANDCSR1: Dual band configuration register 1.
+ */
+#define DBANDCSR0 0x0160
+#define DBANDCSR1 0x0164
+
+/*
+ * BBPPCSR: BBP Pin control register.
+ */
+#define BBPPCSR 0x0168
+
+/*
+ * MAC special debug mode selection registers.
+ * DBGSEL0: MAC special debug mode selection register 0.
+ * DBGSEL1: MAC special debug mode selection register 1.
+ */
+#define DBGSEL0 0x016c
+#define DBGSEL1 0x0170
+
+/*
+ * BISTCSR: BBP BIST register.
+ */
+#define BISTCSR 0x0174
+
+/*
+ * Multicast filter registers.
+ * MCAST0: Multicast filter register 0.
+ * MCAST1: Multicast filter register 1.
+ */
+#define MCAST0 0x0178
+#define MCAST1 0x017c
+
+/*
+ * UART registers.
+ * UARTCSR0: UART1 TX register.
+ * UARTCSR1: UART1 RX register.
+ * UARTCSR3: UART1 frame control register.
+ * UARTCSR4: UART1 buffer control register.
+ * UART2CSR0: UART2 TX register.
+ * UART2CSR1: UART2 RX register.
+ * UART2CSR3: UART2 frame control register.
+ * UART2CSR4: UART2 buffer control register.
+ */
+#define UARTCSR0 0x0180
+#define UARTCSR1 0x0184
+#define UARTCSR3 0x0188
+#define UARTCSR4 0x018c
+#define UART2CSR0 0x0190
+#define UART2CSR1 0x0194
+#define UART2CSR3 0x0198
+#define UART2CSR4 0x019c
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2: TX antenna control
+ */
+#define BBP_R2_TX_ANTENNA FIELD8(0x03)
+#define BBP_R2_TX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * R14: RX antenna control
+ */
+#define BBP_R14_RX_ANTENNA FIELD8(0x03)
+#define BBP_R14_RX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * BBP_R70
+ */
+#define BBP_R70_JAPAN_FILTER FIELD8(0x08)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER FIELD32(0x00000100)
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x10
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * CARDBUS_ACCEL: 0: enable, 1: disable.
+ * DYN_BBP_TUNE: 0: enable, 1: disable.
+ * CCK_TX_POWER: CCK TX power compensation.
+ */
+#define EEPROM_NIC 0x11
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001)
+#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002)
+#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c)
+
+/*
+ * EEPROM geography.
+ * GEO: Default geography setting for device.
+ */
+#define EEPROM_GEOGRAPHY 0x12
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x13
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START 0x23
+#define EEPROM_TXPOWER_SIZE 7
+#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2 FIELD16(0xff00)
+
+/*
+ * RSSI <-> dBm offset calibration
+ */
+#define EEPROM_CALIBRATE_OFFSET 0x3e
+#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 11 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 11 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_RESULT FIELD32(0x0000001c)
+#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
+#define TXD_W0_ACK FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
+#define TXD_W0_OFDM FIELD32(0x00000800)
+#define TXD_W0_CIPHER_OWNER FIELD32(0x00001000)
+#define TXD_W0_IFS FIELD32(0x00006000)
+#define TXD_W0_RETRY_MODE FIELD32(0x00008000)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define TXD_W2_IV_OFFSET FIELD32(0x0000003f)
+#define TXD_W2_AIFS FIELD32(0x000000c0)
+#define TXD_W2_CWMIN FIELD32(0x00000f00)
+#define TXD_W2_CWMAX FIELD32(0x0000f000)
+
+/*
+ * Word3: PLCP information
+ */
+#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W3_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W3_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W3_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word4
+ */
+#define TXD_W4_IV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ */
+#define TXD_W5_EIV FIELD32(0xffffffff)
+
+/*
+ * Word6-9: Key
+ */
+#define TXD_W6_KEY FIELD32(0xffffffff)
+#define TXD_W7_KEY FIELD32(0xffffffff)
+#define TXD_W8_KEY FIELD32(0xffffffff)
+#define TXD_W9_KEY FIELD32(0xffffffff)
+
+/*
+ * Word10
+ */
+#define TXD_W10_RTS FIELD32(0x00000001)
+#define TXD_W10_TX_RATE FIELD32(0x000000fe)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
+#define RXD_W0_MULTICAST FIELD32(0x00000004)
+#define RXD_W0_BROADCAST FIELD32(0x00000008)
+#define RXD_W0_MY_BSS FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
+#define RXD_W0_OFDM FIELD32(0x00000040)
+#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
+#define RXD_W0_CIPHER_OWNER FIELD32(0x00000100)
+#define RXD_W0_ICV_ERROR FIELD32(0x00000200)
+#define RXD_W0_IV_OFFSET FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define RXD_W2_SIGNAL FIELD32(0x000000ff)
+#define RXD_W2_RSSI FIELD32(0x0000ff00)
+#define RXD_W2_TA FIELD32(0xffff0000)
+
+/*
+ * Word3
+ */
+#define RXD_W3_TA FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_IV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ */
+#define RXD_W5_EIV FIELD32(0xffffffff)
+
+/*
+ * Word6-9: Key
+ */
+#define RXD_W6_KEY FIELD32(0xffffffff)
+#define RXD_W7_KEY FIELD32(0xffffffff)
+#define RXD_W8_KEY FIELD32(0xffffffff)
+#define RXD_W9_KEY FIELD32(0xffffffff)
+
+/*
+ * Word10
+ */
+#define RXD_W10_DROP FIELD32(0x00000001)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT2500PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
new file mode 100644
index 000000000000..7cdc80a122bb
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -0,0 +1,1832 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500usb
+ Abstract: rt2500usb device specific routines.
+ Supported chipsets: RT2570.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2500usb"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+#include "rt2500usb.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2500usb_register_read and rt2500usb_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u16 *value)
+{
+ __le16 reg;
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(u16), REGISTER_TIMEOUT);
+ *value = le16_to_cpu(reg);
+}
+
+static inline void rt2500usb_register_multiread(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u16 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ value, length, timeout);
+}
+
+static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u16 value)
+{
+ __le16 reg = cpu_to_le16(value);
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(u16), REGISTER_TIMEOUT);
+}
+
+static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u16 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, length, timeout);
+}
+
+static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_register_read(rt2x00dev, PHY_CSR8, &reg);
+ if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u16 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
+
+ rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+}
+
+static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u16 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+
+ rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ rt2500usb_register_read(rt2x00dev, PHY_CSR7, &reg);
+ *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+}
+
+static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u16 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_register_read(rt2x00dev, PHY_CSR10, &reg);
+ if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+
+ rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) )
+
+static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+}
+
+static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2500usb_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2500usb_read_csr,
+ .write = rt2500usb_write_csr,
+ .word_size = sizeof(u16),
+ .word_count = CSR_REG_SIZE / sizeof(u16),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2500usb_bbp_read,
+ .write = rt2500usb_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2500usb_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
+{
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, &mac,
+ (3 * sizeof(__le16)));
+}
+
+static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
+{
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid,
+ (3 * sizeof(__le16)));
+}
+
+static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u16 reg;
+
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+
+ /*
+ * Enable beacon config
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR20_OFFSET,
+ (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6);
+ if (type == IEEE80211_IF_TYPE_STA)
+ rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
+ else
+ rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 2);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR18_OFFSET, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, tsf_sync);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+}
+
+static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ u16 reg;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+ return;
+ }
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR1_ACK_TIMEOUT, ack_timeout);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR10, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+}
+
+static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int phymode,
+ const int basic_rate_mask)
+{
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
+
+ if (phymode == HWMODE_B) {
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040);
+ } else {
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c);
+ }
+}
+
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ /*
+ * Set TXpower.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+ /*
+ * For RT2525E we should first set the channel to half band higher.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ static const u32 vals[] = {
+ 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+ 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+ 0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+ 0x00000902, 0x00000906
+ };
+
+ rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+ }
+
+ rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 rf3;
+
+ rt2x00_rf_read(rt2x00dev, 3, &rf3);
+ rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
+static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ u8 r2;
+ u8 r14;
+ u16 csr5;
+ u16 csr6;
+
+ rt2500usb_bbp_read(rt2x00dev, 2, &r2);
+ rt2500usb_bbp_read(rt2x00dev, 14, &r14);
+ rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5);
+ rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (antenna_tx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * RT2525E and RT5222 need to flip TX I/Q
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
+
+ /*
+ * RT2525E does not need RX I/Q Flip.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+ } else {
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 0);
+ }
+
+ rt2500usb_bbp_write(rt2x00dev, 2, r2);
+ rt2500usb_bbp_write(rt2x00dev, 14, r14);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR5, csr5);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
+}
+
+static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u16 reg;
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
+ libconf->conf->beacon_int * 4);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+}
+
+static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt2500usb_config_phymode(rt2x00dev, libconf->phymode,
+ libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt2500usb_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt2500usb_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt2500usb_config_antenna(rt2x00dev,
+ libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt2500usb_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR21, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR21_ON_PERIOD, 70);
+ rt2x00_set_field16(&reg, MAC_CSR21_OFF_PERIOD, 30);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
+
+ if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
+ } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
+ } else {
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
+ }
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
+}
+
+static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2500usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2500usb_register_read(rt2x00dev, STA_CSR3, &reg);
+ rt2x00dev->link.false_cca =
+ rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
+}
+
+static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ u16 eeprom;
+ u16 value;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW);
+ rt2500usb_bbp_write(rt2x00dev, 24, value);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW);
+ rt2500usb_bbp_write(rt2x00dev, 25, value);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW);
+ rt2500usb_bbp_write(rt2x00dev, 61, value);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER);
+ rt2500usb_bbp_write(rt2x00dev, 17, value);
+
+ rt2x00dev->link.vgc_level = value;
+}
+
+static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u16 bbp_thresh;
+ u16 vgc_bound;
+ u16 sens;
+ u16 r24;
+ u16 r25;
+ u16 r61;
+ u16 r17_sens;
+ u8 r17;
+ u8 up_bound;
+ u8 low_bound;
+
+ /*
+ * Determine the BBP tuning threshold and correctly
+ * set BBP 24, 25 and 61.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh);
+ bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61);
+
+ if ((rssi + bbp_thresh) > 0) {
+ r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH);
+ r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH);
+ r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH);
+ } else {
+ r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW);
+ r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW);
+ r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW);
+ }
+
+ rt2500usb_bbp_write(rt2x00dev, 24, r24);
+ rt2500usb_bbp_write(rt2x00dev, 25, r25);
+ rt2500usb_bbp_write(rt2x00dev, 61, r61);
+
+ /*
+ * Read current r17 value, as well as the sensitivity values
+ * for the r17 register.
+ */
+ rt2500usb_bbp_read(rt2x00dev, 17, &r17);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens);
+
+ /*
+ * A too low RSSI will cause too much false CCA which will
+ * then corrupt the R17 tuning. To remidy this the tuning should
+ * be stopped (While making sure the R17 value will not exceed limits)
+ */
+ if (rssi >= -40) {
+ if (r17 != 0x60)
+ rt2500usb_bbp_write(rt2x00dev, 17, 0x60);
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW);
+ if (r17 != sens)
+ rt2500usb_bbp_write(rt2x00dev, 17, sens);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH);
+ if (r17 != sens)
+ rt2500usb_bbp_write(rt2x00dev, 17, sens);
+ return;
+ }
+
+ /*
+ * Leave short or middle distance condition, restore r17
+ * to the dynamic tuning range.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound);
+ vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER);
+
+ low_bound = 0x32;
+ if (rssi >= -77)
+ up_bound = vgc_bound;
+ else
+ up_bound = vgc_bound - (-77 - rssi);
+
+ if (up_bound < low_bound)
+ up_bound = low_bound;
+
+ if (r17 > up_bound) {
+ rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
+ rt2x00dev->link.vgc_level = up_bound;
+ } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
+ rt2x00dev->link.vgc_level = r17;
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ rt2500usb_bbp_write(rt2x00dev, 17, --r17);
+ rt2x00dev->link.vgc_level = r17;
+ }
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0x0001,
+ USB_MODE_TEST, REGISTER_TIMEOUT);
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308,
+ 0x00f0, REGISTER_TIMEOUT);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR5, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0, 13);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID1, 12);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID1_VALID, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR6, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID0, 10);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID1, 11);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID1_VALID, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID0, 7);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID1, 6);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID1_VALID, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID0, 5);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1_VALID, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ if (rt2x00_get_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+ rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
+ reg &= ~0x0002;
+ } else {
+ reg = 0x3002;
+ }
+ rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg);
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0002);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR22, 0x0053);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR8_MAX_FRAME_UNIT,
+ rt2x00dev->rx->data_size);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0xff);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR18_DELAY_AFTER_BEACON, 90);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
+
+ rt2500usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+ rt2x00_set_field16(&reg, PHY_CSR4_LOW_RF_LE, 1);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR1_AUTO_SEQUENCE, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ return 0;
+}
+
+static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 value;
+ u8 reg_id;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt2500usb_bbp_write(rt2x00dev, 3, 0x02);
+ rt2500usb_bbp_write(rt2x00dev, 4, 0x19);
+ rt2500usb_bbp_write(rt2x00dev, 14, 0x1c);
+ rt2500usb_bbp_write(rt2x00dev, 15, 0x30);
+ rt2500usb_bbp_write(rt2x00dev, 16, 0xac);
+ rt2500usb_bbp_write(rt2x00dev, 18, 0x18);
+ rt2500usb_bbp_write(rt2x00dev, 19, 0xff);
+ rt2500usb_bbp_write(rt2x00dev, 20, 0x1e);
+ rt2500usb_bbp_write(rt2x00dev, 21, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 22, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 23, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 24, 0x80);
+ rt2500usb_bbp_write(rt2x00dev, 25, 0x50);
+ rt2500usb_bbp_write(rt2x00dev, 26, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 27, 0x23);
+ rt2500usb_bbp_write(rt2x00dev, 30, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 31, 0x2b);
+ rt2500usb_bbp_write(rt2x00dev, 32, 0xb9);
+ rt2500usb_bbp_write(rt2x00dev, 34, 0x12);
+ rt2500usb_bbp_write(rt2x00dev, 35, 0x50);
+ rt2500usb_bbp_write(rt2x00dev, 39, 0xc4);
+ rt2500usb_bbp_write(rt2x00dev, 40, 0x02);
+ rt2500usb_bbp_write(rt2x00dev, 41, 0x60);
+ rt2500usb_bbp_write(rt2x00dev, 53, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 54, 0x18);
+ rt2500usb_bbp_write(rt2x00dev, 56, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 57, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 58, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 61, 0x60);
+ rt2500usb_bbp_write(rt2x00dev, 62, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 75, 0xff);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt2500usb_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u16 reg;
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
+static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt2500usb_init_registers(rt2x00dev) ||
+ rt2500usb_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ rt2x00usb_enable_radio(rt2x00dev);
+
+ /*
+ * Enable LED
+ */
+ rt2500usb_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Disable LED
+ */
+ rt2500usb_disable_led(rt2x00dev);
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+
+ rt2x00usb_disable_radio(rt2x00dev);
+}
+
+static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u16 reg;
+ u16 reg2;
+ unsigned int i;
+ char put_to_sleep;
+ char bbp_state;
+ char rf_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ reg = 0;
+ rt2x00_set_field16(&reg, MAC_CSR17_BBP_DESIRE_STATE, state);
+ rt2x00_set_field16(&reg, MAC_CSR17_RF_DESIRE_STATE, state);
+ rt2x00_set_field16(&reg, MAC_CSR17_PUT_TO_SLEEP, put_to_sleep);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+ rt2x00_set_field16(&reg, MAC_CSR17_SET_STATE, 1);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_register_read(rt2x00dev, MAC_CSR17, &reg2);
+ bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE);
+ rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE);
+ if (bbp_state == state && rf_state == state)
+ return 0;
+ rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+ msleep(30);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state: bbp %d and rf %d.\n",
+ state, bbp_state, rf_state);
+
+ return -EBUSY;
+}
+
+static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt2500usb_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt2500usb_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt2500usb_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2500usb_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
+ !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+ int maxpacket, struct sk_buff *skb)
+{
+ int length;
+
+ /*
+ * The length _must_ be a multiple of 2,
+ * but it must _not_ be a multiple of the USB packet size.
+ */
+ length = roundup(skb->len, 2);
+ length += (2 * !(length % maxpacket));
+
+ return length;
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u16 reg;
+
+ if (queue != IEEE80211_TX_QUEUE_BEACON)
+ return;
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+ /*
+ * Beacon generation will fail initially.
+ * To prevent this we need to register the TXRX_CSR19
+ * register several times.
+ */
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ }
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2500usb_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct urb *urb = entry->priv;
+ struct data_desc *rxd = (struct data_desc *)(entry->skb->data +
+ (urb->actual_length -
+ entry->ring->desc_size));
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+ return;
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2500usb_beacondone(struct urb *urb)
+{
+ struct data_entry *entry = (struct data_entry *)urb->context;
+ struct data_ring *ring = entry->ring;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags))
+ return;
+
+ /*
+ * Check if this was the guardian beacon,
+ * if that was the case we need to send the real beacon now.
+ * Otherwise we should free the sk_buffer, the device
+ * should be doing the rest of the work now.
+ */
+ if (ring->index == 1) {
+ rt2x00_ring_index_done_inc(ring);
+ entry = rt2x00_get_data_entry(ring);
+ usb_submit_urb(entry->priv, GFP_ATOMIC);
+ rt2x00_ring_index_inc(ring);
+ } else if (ring->index_done == 1) {
+ entry = rt2x00_get_data_entry_done(ring);
+ if (entry->skb) {
+ dev_kfree_skb(entry->skb);
+ entry->skb = NULL;
+ }
+ rt2x00_ring_index_done_inc(ring);
+ }
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 word;
+ u8 *mac;
+
+ rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
+ DEFAULT_RSSI_OFFSET);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
+ EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word);
+ EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
+ EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
+ EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R24, word);
+ EEPROM(rt2x00dev, "BBPtune r24: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R25, word);
+ EEPROM(rt2x00dev, "BBPtune r25: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R61, word);
+ EEPROM(rt2x00dev, "BBPtune r61: 0x%04x\n", word);
+ }
+
+ return 0;
+}
+
+static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
+
+ if (rt2x00_rev(&rt2x00dev->chip, 0xffff0)) {
+ ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ return -ENODEV;
+ }
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Store led mode, for correct led behaviour.
+ */
+ rt2x00dev->led_mode =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ /*
+ * Check if the BBP tuning should be disabled.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+ /*
+ * Read the RSSI <-> dBm offset information.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
+ rt2x00dev->rssi_offset =
+ rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2522
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2522[] = {
+ { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 },
+ { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 },
+ { 3, 0x00002050, 0x000c2002, 0x00000101, 0 },
+ { 4, 0x00002050, 0x000c2016, 0x00000101, 0 },
+ { 5, 0x00002050, 0x000c202a, 0x00000101, 0 },
+ { 6, 0x00002050, 0x000c203e, 0x00000101, 0 },
+ { 7, 0x00002050, 0x000c2052, 0x00000101, 0 },
+ { 8, 0x00002050, 0x000c2066, 0x00000101, 0 },
+ { 9, 0x00002050, 0x000c207a, 0x00000101, 0 },
+ { 10, 0x00002050, 0x000c208e, 0x00000101, 0 },
+ { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 },
+ { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 },
+ { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 },
+ { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 },
+};
+
+/*
+ * RF value list for RF2523
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2523[] = {
+ { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b },
+ { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b },
+ { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b },
+ { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b },
+ { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b },
+ { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b },
+ { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b },
+ { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b },
+ { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b },
+ { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b },
+ { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b },
+ { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b },
+ { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b },
+ { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2524
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2524[] = {
+ { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b },
+ { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b },
+ { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b },
+ { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b },
+ { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b },
+ { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b },
+ { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b },
+ { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b },
+ { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b },
+ { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b },
+ { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b },
+ { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b },
+ { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b },
+ { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525[] = {
+ { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b },
+ { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b },
+ { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b },
+ { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b },
+ { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b },
+ { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b },
+ { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b },
+ { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b },
+ { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b },
+ { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b },
+ { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b },
+ { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b },
+ { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b },
+ { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525e
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525e[] = {
+ { 1, 0x00022010, 0x0000089a, 0x00060111, 0x00000e1b },
+ { 2, 0x00022010, 0x0000089e, 0x00060111, 0x00000e07 },
+ { 3, 0x00022010, 0x0000089e, 0x00060111, 0x00000e1b },
+ { 4, 0x00022010, 0x000008a2, 0x00060111, 0x00000e07 },
+ { 5, 0x00022010, 0x000008a2, 0x00060111, 0x00000e1b },
+ { 6, 0x00022010, 0x000008a6, 0x00060111, 0x00000e07 },
+ { 7, 0x00022010, 0x000008a6, 0x00060111, 0x00000e1b },
+ { 8, 0x00022010, 0x000008aa, 0x00060111, 0x00000e07 },
+ { 9, 0x00022010, 0x000008aa, 0x00060111, 0x00000e1b },
+ { 10, 0x00022010, 0x000008ae, 0x00060111, 0x00000e07 },
+ { 11, 0x00022010, 0x000008ae, 0x00060111, 0x00000e1b },
+ { 12, 0x00022010, 0x000008b2, 0x00060111, 0x00000e07 },
+ { 13, 0x00022010, 0x000008b2, 0x00060111, 0x00000e1b },
+ { 14, 0x00022010, 0x000008b6, 0x00060111, 0x00000e23 },
+};
+
+/*
+ * RF value list for RF5222
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5222[] = {
+ { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b },
+ { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b },
+ { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b },
+ { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b },
+ { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b },
+ { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b },
+ { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b },
+ { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b },
+ { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b },
+ { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b },
+ { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b },
+ { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b },
+ { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b },
+ { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f },
+ { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f },
+ { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f },
+ { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f },
+ { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f },
+ { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f },
+ { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f },
+ { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f },
+ { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f },
+ { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f },
+ { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f },
+ { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f },
+ { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f },
+ { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f },
+ { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f },
+ { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f },
+ { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f },
+
+ /* 802.11 UNII */
+ { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f },
+ { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 },
+ { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 },
+ { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 },
+ { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
+};
+
+static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 2;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
+ spec->channels = rf_vals_bg_2522;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
+ spec->channels = rf_vals_bg_2523;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
+ spec->channels = rf_vals_bg_2524;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
+ spec->channels = rf_vals_bg_2525;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
+ spec->channels = rf_vals_bg_2525e;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5222);
+ spec->channels = rf_vals_5222;
+ spec->num_modes = 3;
+ }
+}
+
+static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2500usb_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2500usb_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt2500usb_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires the beacon ring
+ */
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u16 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ return;
+ }
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_BROADCAST, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
+static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct data_ring *ring =
+ rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ struct data_entry *beacon;
+ struct data_entry *guardian;
+ int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int max_packet = usb_maxpacket(usb_dev, pipe, 1);
+ int length;
+
+ /*
+ * Just in case the ieee80211 doesn't set this,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * Obtain 2 entries, one for the guardian byte,
+ * the second for the actual beacon.
+ */
+ guardian = rt2x00_get_data_entry(ring);
+ rt2x00_ring_index_inc(ring);
+ beacon = rt2x00_get_data_entry(ring);
+
+ /*
+ * First we create the beacon.
+ */
+ skb_push(skb, ring->desc_size);
+ memset(skb->data, 0, ring->desc_size);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ ring->desc_size),
+ skb->len - ring->desc_size, control);
+
+ length = rt2500usb_get_tx_data_len(rt2x00dev, max_packet, skb);
+
+ usb_fill_bulk_urb(beacon->priv, usb_dev, pipe,
+ skb->data, length, rt2500usb_beacondone, beacon);
+
+ beacon->skb = skb;
+
+ /*
+ * Second we need to create the guardian byte.
+ * We only need a single byte, so lets recycle
+ * the 'flags' field we are not using for beacons.
+ */
+ guardian->flags = 0;
+ usb_fill_bulk_urb(guardian->priv, usb_dev, pipe,
+ &guardian->flags, 1, rt2500usb_beacondone, guardian);
+
+ /*
+ * Send out the guardian byte.
+ */
+ usb_submit_urb(guardian->priv, GFP_ATOMIC);
+
+ /*
+ * Enable beacon generation.
+ */
+ rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rt2500usb_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt2500usb_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .beacon_update = rt2500usb_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
+ .probe_hw = rt2500usb_probe_hw,
+ .initialize = rt2x00usb_initialize,
+ .uninitialize = rt2x00usb_uninitialize,
+ .set_device_state = rt2500usb_set_device_state,
+ .link_stats = rt2500usb_link_stats,
+ .reset_tuner = rt2500usb_reset_tuner,
+ .link_tuner = rt2500usb_link_tuner,
+ .write_tx_desc = rt2500usb_write_tx_desc,
+ .write_tx_data = rt2x00usb_write_tx_data,
+ .get_tx_data_len = rt2500usb_get_tx_data_len,
+ .kick_tx_queue = rt2500usb_kick_tx_queue,
+ .fill_rxdone = rt2500usb_fill_rxdone,
+ .config_mac_addr = rt2500usb_config_mac_addr,
+ .config_bssid = rt2500usb_config_bssid,
+ .config_type = rt2500usb_config_type,
+ .config_preamble = rt2500usb_config_preamble,
+ .config = rt2500usb_config,
+};
+
+static const struct rt2x00_ops rt2500usb_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt2500usb_rt2x00_ops,
+ .hw = &rt2500usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2500usb_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt2500usb module information.
+ */
+static struct usb_device_id rt2500usb_device_table[] = {
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Belkin */
+ { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Cisco Systems */
+ { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Conceptronic */
+ { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* D-LINK */
+ { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Gigabyte */
+ { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Hercules */
+ { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Melco */
+ { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
+
+ /* MSI */
+ { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Siemens */
+ { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* SMC */
+ { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Spairon */
+ { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Trust */
+ { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Zinwell */
+ { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2500 USB Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards");
+MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver rt2500usb_driver = {
+ .name = DRV_NAME,
+ .id_table = rt2500usb_device_table,
+ .probe = rt2x00usb_probe,
+ .disconnect = rt2x00usb_disconnect,
+ .suspend = rt2x00usb_suspend,
+ .resume = rt2x00usb_resume,
+};
+
+static int __init rt2500usb_init(void)
+{
+ return usb_register(&rt2500usb_driver);
+}
+
+static void __exit rt2500usb_exit(void)
+{
+ usb_deregister(&rt2500usb_driver);
+}
+
+module_init(rt2500usb_init);
+module_exit(rt2500usb_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
new file mode 100644
index 000000000000..b18d56e73cf1
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -0,0 +1,798 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500usb
+ Abstract: Data structures and registers for the rt2500usb module.
+ Supported chipsets: RT2570.
+ */
+
+#ifndef RT2500USB_H
+#define RT2500USB_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2522 0x0000
+#define RF2523 0x0001
+#define RF2524 0x0002
+#define RF2525 0x0003
+#define RF2525E 0x0005
+#define RF5222 0x0010
+
+/*
+ * RT2570 version
+ */
+#define RT2570_VERSION_B 2
+#define RT2570_VERSION_C 3
+#define RT2570_VERSION_D 4
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x0400
+#define CSR_REG_SIZE 0x0100
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x006a
+#define BBP_SIZE 0x0060
+#define RF_SIZE 0x0014
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0 0x0400
+
+/*
+ * MAC_CSR1: System control.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define MAC_CSR1 0x0402
+#define MAC_CSR1_SOFT_RESET FIELD16(0x00000001)
+#define MAC_CSR1_BBP_RESET FIELD16(0x00000002)
+#define MAC_CSR1_HOST_READY FIELD16(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2 0x0404
+#define MAC_CSR2_BYTE0 FIELD16(0x00ff)
+#define MAC_CSR2_BYTE1 FIELD16(0xff00)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3 0x0406
+#define MAC_CSR3_BYTE2 FIELD16(0x00ff)
+#define MAC_CSR3_BYTE3 FIELD16(0xff00)
+
+/*
+ * MAC_CSR4: STA MAC register 2.
+ */
+#define MAC_CSR4 0X0408
+#define MAC_CSR4_BYTE4 FIELD16(0x00ff)
+#define MAC_CSR4_BYTE5 FIELD16(0xff00)
+
+/*
+ * MAC_CSR5: BSSID register 0.
+ */
+#define MAC_CSR5 0x040a
+#define MAC_CSR5_BYTE0 FIELD16(0x00ff)
+#define MAC_CSR5_BYTE1 FIELD16(0xff00)
+
+/*
+ * MAC_CSR6: BSSID register 1.
+ */
+#define MAC_CSR6 0x040c
+#define MAC_CSR6_BYTE2 FIELD16(0x00ff)
+#define MAC_CSR6_BYTE3 FIELD16(0xff00)
+
+/*
+ * MAC_CSR7: BSSID register 2.
+ */
+#define MAC_CSR7 0x040e
+#define MAC_CSR7_BYTE4 FIELD16(0x00ff)
+#define MAC_CSR7_BYTE5 FIELD16(0xff00)
+
+/*
+ * MAC_CSR8: Max frame length.
+ */
+#define MAC_CSR8 0x0410
+#define MAC_CSR8_MAX_FRAME_UNIT FIELD16(0x0fff)
+
+/*
+ * Misc MAC_CSR registers.
+ * MAC_CSR9: Timer control.
+ * MAC_CSR10: Slot time.
+ * MAC_CSR11: IFS.
+ * MAC_CSR12: EIFS.
+ * MAC_CSR13: Power mode0.
+ * MAC_CSR14: Power mode1.
+ * MAC_CSR15: Power saving transition0
+ * MAC_CSR16: Power saving transition1
+ */
+#define MAC_CSR9 0x0412
+#define MAC_CSR10 0x0414
+#define MAC_CSR11 0x0416
+#define MAC_CSR12 0x0418
+#define MAC_CSR13 0x041a
+#define MAC_CSR14 0x041c
+#define MAC_CSR15 0x041e
+#define MAC_CSR16 0x0420
+
+/*
+ * MAC_CSR17: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURRENT_STATE: BBP current state.
+ * RF_CURRENT_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define MAC_CSR17 0x0422
+#define MAC_CSR17_SET_STATE FIELD16(0x0001)
+#define MAC_CSR17_BBP_DESIRE_STATE FIELD16(0x0006)
+#define MAC_CSR17_RF_DESIRE_STATE FIELD16(0x0018)
+#define MAC_CSR17_BBP_CURR_STATE FIELD16(0x0060)
+#define MAC_CSR17_RF_CURR_STATE FIELD16(0x0180)
+#define MAC_CSR17_PUT_TO_SLEEP FIELD16(0x0200)
+
+/*
+ * MAC_CSR18: Wakeup timer register.
+ * DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU.
+ * BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTO_WAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define MAC_CSR18 0x0424
+#define MAC_CSR18_DELAY_AFTER_BEACON FIELD16(0x00ff)
+#define MAC_CSR18_BEACONS_BEFORE_WAKEUP FIELD16(0x7f00)
+#define MAC_CSR18_AUTO_WAKE FIELD16(0x8000)
+
+/*
+ * MAC_CSR19: GPIO control register.
+ */
+#define MAC_CSR19 0x0426
+
+/*
+ * MAC_CSR20: LED control register.
+ * ACTIVITY: 0: idle, 1: active.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR20 0x0428
+#define MAC_CSR20_ACTIVITY FIELD16(0x0001)
+#define MAC_CSR20_LINK FIELD16(0x0002)
+#define MAC_CSR20_ACTIVITY_POLARITY FIELD16(0x0004)
+
+/*
+ * MAC_CSR21: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ */
+#define MAC_CSR21 0x042a
+#define MAC_CSR21_ON_PERIOD FIELD16(0x00ff)
+#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00)
+
+/*
+ * Collision window control register.
+ */
+#define MAC_CSR22 0x042c
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: Security control register.
+ */
+#define TXRX_CSR0 0x0440
+#define TXRX_CSR0_ALGORITHM FIELD16(0x0007)
+#define TXRX_CSR0_IV_OFFSET FIELD16(0x01f8)
+#define TXRX_CSR0_KEY_ID FIELD16(0x1e00)
+
+/*
+ * TXRX_CSR1: TX configuration.
+ * ACK_TIMEOUT: ACK Timeout in unit of 1-us.
+ * TSF_OFFSET: TSF offset in MAC header.
+ * AUTO_SEQUENCE: Let ASIC control frame sequence number.
+ */
+#define TXRX_CSR1 0x0442
+#define TXRX_CSR1_ACK_TIMEOUT FIELD16(0x00ff)
+#define TXRX_CSR1_TSF_OFFSET FIELD16(0x7f00)
+#define TXRX_CSR1_AUTO_SEQUENCE FIELD16(0x8000)
+
+/*
+ * TXRX_CSR2: RX control.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MCAST: Drop multicast frames.
+ * DROP_BCAST: Drop broadcast frames.
+ */
+#define TXRX_CSR2 0x0444
+#define TXRX_CSR2_DISABLE_RX FIELD16(0x0001)
+#define TXRX_CSR2_DROP_CRC FIELD16(0x0002)
+#define TXRX_CSR2_DROP_PHYSICAL FIELD16(0x0004)
+#define TXRX_CSR2_DROP_CONTROL FIELD16(0x0008)
+#define TXRX_CSR2_DROP_NOT_TO_ME FIELD16(0x0010)
+#define TXRX_CSR2_DROP_TODS FIELD16(0x0020)
+#define TXRX_CSR2_DROP_VERSION_ERROR FIELD16(0x0040)
+#define TXRX_CSR2_DROP_MULTICAST FIELD16(0x0200)
+#define TXRX_CSR2_DROP_BROADCAST FIELD16(0x0400)
+
+/*
+ * RX BBP ID registers
+ * TXRX_CSR3: CCK RX BBP ID.
+ * TXRX_CSR4: OFDM RX BBP ID.
+ */
+#define TXRX_CSR3 0x0446
+#define TXRX_CSR4 0x0448
+
+/*
+ * TXRX_CSR5: CCK TX BBP ID0.
+ */
+#define TXRX_CSR5 0x044a
+#define TXRX_CSR5_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR5_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR5_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR5_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR6: CCK TX BBP ID1.
+ */
+#define TXRX_CSR6 0x044c
+#define TXRX_CSR6_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR6_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR6_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR6_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR7: OFDM TX BBP ID0.
+ */
+#define TXRX_CSR7 0x044e
+#define TXRX_CSR7_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR7_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR7_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR5: OFDM TX BBP ID1.
+ */
+#define TXRX_CSR8 0x0450
+#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR8_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR8_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR8_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR9: TX ACK time-out.
+ */
+#define TXRX_CSR9 0x0452
+
+/*
+ * TXRX_CSR10: Auto responder control.
+ */
+#define TXRX_CSR10 0x0454
+#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004)
+
+/*
+ * TXRX_CSR11: Auto responder basic rate.
+ */
+#define TXRX_CSR11 0x0456
+
+/*
+ * ACK/CTS time registers.
+ */
+#define TXRX_CSR12 0x0458
+#define TXRX_CSR13 0x045a
+#define TXRX_CSR14 0x045c
+#define TXRX_CSR15 0x045e
+#define TXRX_CSR16 0x0460
+#define TXRX_CSR17 0x0462
+
+/*
+ * TXRX_CSR18: Synchronization control register.
+ */
+#define TXRX_CSR18 0x0464
+#define TXRX_CSR18_OFFSET FIELD16(0x000f)
+#define TXRX_CSR18_INTERVAL FIELD16(0xfff0)
+
+/*
+ * TXRX_CSR19: Synchronization control register.
+ * TSF_COUNT: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable Tbcn with reload value.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR19 0x0466
+#define TXRX_CSR19_TSF_COUNT FIELD16(0x0001)
+#define TXRX_CSR19_TSF_SYNC FIELD16(0x0006)
+#define TXRX_CSR19_TBCN FIELD16(0x0008)
+#define TXRX_CSR19_BEACON_GEN FIELD16(0x0010)
+
+/*
+ * TXRX_CSR20: Tx BEACON offset time control register.
+ * OFFSET: In units of usec.
+ * BCN_EXPECT_WINDOW: Default: 2^CWmin
+ */
+#define TXRX_CSR20 0x0468
+#define TXRX_CSR20_OFFSET FIELD16(0x1fff)
+#define TXRX_CSR20_BCN_EXPECT_WINDOW FIELD16(0xe000)
+
+/*
+ * TXRX_CSR21
+ */
+#define TXRX_CSR21 0x046a
+
+/*
+ * Encryption related CSRs.
+ *
+ */
+
+/*
+ * SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7
+ */
+#define SEC_CSR0 0x0480
+#define SEC_CSR1 0x0482
+#define SEC_CSR2 0x0484
+#define SEC_CSR3 0x0486
+#define SEC_CSR4 0x0488
+#define SEC_CSR5 0x048a
+#define SEC_CSR6 0x048c
+#define SEC_CSR7 0x048e
+
+/*
+ * SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7
+ */
+#define SEC_CSR8 0x0490
+#define SEC_CSR9 0x0492
+#define SEC_CSR10 0x0494
+#define SEC_CSR11 0x0496
+#define SEC_CSR12 0x0498
+#define SEC_CSR13 0x049a
+#define SEC_CSR14 0x049c
+#define SEC_CSR15 0x049e
+
+/*
+ * SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7
+ */
+#define SEC_CSR16 0x04a0
+#define SEC_CSR17 0x04a2
+#define SEC_CSR18 0X04A4
+#define SEC_CSR19 0x04a6
+#define SEC_CSR20 0x04a8
+#define SEC_CSR21 0x04aa
+#define SEC_CSR22 0x04ac
+#define SEC_CSR23 0x04ae
+
+/*
+ * SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7
+ */
+#define SEC_CSR24 0x04b0
+#define SEC_CSR25 0x04b2
+#define SEC_CSR26 0x04b4
+#define SEC_CSR27 0x04b6
+#define SEC_CSR28 0x04b8
+#define SEC_CSR29 0x04ba
+#define SEC_CSR30 0x04bc
+#define SEC_CSR31 0x04be
+
+/*
+ * PHY control registers.
+ */
+
+/*
+ * PHY_CSR0: RF switching timing control.
+ */
+#define PHY_CSR0 0x04c0
+
+/*
+ * PHY_CSR1: TX PA configuration.
+ */
+#define PHY_CSR1 0x04c2
+
+/*
+ * MAC configuration registers.
+ * PHY_CSR2: TX MAC configuration.
+ * PHY_CSR3: RX MAC configuration.
+ */
+#define PHY_CSR2 0x04c4
+#define PHY_CSR3 0x04c6
+
+/*
+ * PHY_CSR4: Interface configuration.
+ */
+#define PHY_CSR4 0x04c8
+#define PHY_CSR4_LOW_RF_LE FIELD16(0x0001)
+
+/*
+ * BBP pre-TX registers.
+ * PHY_CSR5: BBP pre-TX CCK.
+ */
+#define PHY_CSR5 0x04ca
+#define PHY_CSR5_CCK FIELD16(0x0003)
+#define PHY_CSR5_CCK_FLIP FIELD16(0x0004)
+
+/*
+ * BBP pre-TX registers.
+ * PHY_CSR6: BBP pre-TX OFDM.
+ */
+#define PHY_CSR6 0x04cc
+#define PHY_CSR6_OFDM FIELD16(0x0003)
+#define PHY_CSR6_OFDM_FLIP FIELD16(0x0004)
+
+/*
+ * PHY_CSR7: BBP access register 0.
+ * BBP_DATA: BBP data.
+ * BBP_REG_ID: BBP register ID.
+ * BBP_READ_CONTROL: 0: write, 1: read.
+ */
+#define PHY_CSR7 0x04ce
+#define PHY_CSR7_DATA FIELD16(0x00ff)
+#define PHY_CSR7_REG_ID FIELD16(0x7f00)
+#define PHY_CSR7_READ_CONTROL FIELD16(0x8000)
+
+/*
+ * PHY_CSR8: BBP access register 1.
+ * BBP_BUSY: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR8 0x04d0
+#define PHY_CSR8_BUSY FIELD16(0x0001)
+
+/*
+ * PHY_CSR9: RF access register.
+ * RF_VALUE: Register value + id to program into rf/if.
+ */
+#define PHY_CSR9 0x04d2
+#define PHY_CSR9_RF_VALUE FIELD16(0xffff)
+
+/*
+ * PHY_CSR10: RF access register.
+ * RF_VALUE: Register value + id to program into rf/if.
+ * RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * RF_IF_SELECT: Chip to program: 0: rf, 1: if.
+ * RF_PLL_LD: Rf pll_ld status.
+ * RF_BUSY: 1: asic is busy execute rf programming.
+ */
+#define PHY_CSR10 0x04d4
+#define PHY_CSR10_RF_VALUE FIELD16(0x00ff)
+#define PHY_CSR10_RF_NUMBER_OF_BITS FIELD16(0x1f00)
+#define PHY_CSR10_RF_IF_SELECT FIELD16(0x2000)
+#define PHY_CSR10_RF_PLL_LD FIELD16(0x4000)
+#define PHY_CSR10_RF_BUSY FIELD16(0x8000)
+
+/*
+ * STA_CSR0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define STA_CSR0 0x04e0
+#define STA_CSR0_FCS_ERROR FIELD16(0xffff)
+
+/*
+ * STA_CSR1: PLCP error count.
+ */
+#define STA_CSR1 0x04e2
+
+/*
+ * STA_CSR2: LONG error count.
+ */
+#define STA_CSR2 0x04e4
+
+/*
+ * STA_CSR3: CCA false alarm.
+ * FALSE_CCA_ERROR: False CCA error count, cleared when read.
+ */
+#define STA_CSR3 0x04e6
+#define STA_CSR3_FALSE_CCA_ERROR FIELD16(0xffff)
+
+/*
+ * STA_CSR4: RX FIFO overflow.
+ */
+#define STA_CSR4 0x04e8
+
+/*
+ * STA_CSR5: Beacon sent counter.
+ */
+#define STA_CSR5 0x04ea
+
+/*
+ * Statistics registers
+ */
+#define STA_CSR6 0x04ec
+#define STA_CSR7 0x04ee
+#define STA_CSR8 0x04f0
+#define STA_CSR9 0x04f2
+#define STA_CSR10 0x04f4
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2: TX antenna control
+ */
+#define BBP_R2_TX_ANTENNA FIELD8(0x03)
+#define BBP_R2_TX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * R14: RX antenna control
+ */
+#define BBP_R14_RX_ANTENNA FIELD8(0x03)
+#define BBP_R14_RX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * RF registers.
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER FIELD32(0x00000100)
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * EEPROM contents.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x000b
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * CARDBUS_ACCEL: 0: enable, 1: disable.
+ * DYN_BBP_TUNE: 0: enable, 1: disable.
+ * CCK_TX_POWER: CCK TX power compensation.
+ */
+#define EEPROM_NIC 0x000c
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001)
+#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002)
+#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c)
+
+/*
+ * EEPROM geography.
+ * GEO: Default geography setting for device.
+ */
+#define EEPROM_GEOGRAPHY 0x000d
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x000e
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START 0x001e
+#define EEPROM_TXPOWER_SIZE 7
+#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2 FIELD16(0xff00)
+
+/*
+ * EEPROM Tuning threshold
+ */
+#define EEPROM_BBPTUNE 0x0030
+#define EEPROM_BBPTUNE_THRESHOLD FIELD16(0x00ff)
+
+/*
+ * EEPROM BBP R24 Tuning.
+ */
+#define EEPROM_BBPTUNE_R24 0x0031
+#define EEPROM_BBPTUNE_R24_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R24_HIGH FIELD16(0xff00)
+
+/*
+ * EEPROM BBP R25 Tuning.
+ */
+#define EEPROM_BBPTUNE_R25 0x0032
+#define EEPROM_BBPTUNE_R25_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R25_HIGH FIELD16(0xff00)
+
+/*
+ * EEPROM BBP R24 Tuning.
+ */
+#define EEPROM_BBPTUNE_R61 0x0033
+#define EEPROM_BBPTUNE_R61_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R61_HIGH FIELD16(0xff00)
+
+/*
+ * EEPROM BBP VGC Tuning.
+ */
+#define EEPROM_BBPTUNE_VGC 0x0034
+#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff)
+
+/*
+ * EEPROM BBP R17 Tuning.
+ */
+#define EEPROM_BBPTUNE_R17 0x0035
+#define EEPROM_BBPTUNE_R17_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R17_HIGH FIELD16(0xff00)
+
+/*
+ * RSSI <-> dBm offset calibration
+ */
+#define EEPROM_CALIBRATE_OFFSET 0x0036
+#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 5 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 4 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_PACKET_ID FIELD32(0x0000000f)
+#define TXD_W0_RETRY_LIMIT FIELD32(0x000000f0)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
+#define TXD_W0_ACK FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
+#define TXD_W0_OFDM FIELD32(0x00000800)
+#define TXD_W0_NEW_SEQ FIELD32(0x00001000)
+#define TXD_W0_IFS FIELD32(0x00006000)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_CIPHER FIELD32(0x20000000)
+#define TXD_W0_KEY_ID FIELD32(0xc0000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_IV_OFFSET FIELD32(0x0000003f)
+#define TXD_W1_AIFS FIELD32(0x000000c0)
+#define TXD_W1_CWMIN FIELD32(0x00000f00)
+#define TXD_W1_CWMAX FIELD32(0x0000f000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
+#define RXD_W0_MULTICAST FIELD32(0x00000004)
+#define RXD_W0_BROADCAST FIELD32(0x00000008)
+#define RXD_W0_MY_BSS FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
+#define RXD_W0_OFDM FIELD32(0x00000040)
+#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
+#define RXD_W0_CIPHER FIELD32(0x00000100)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000200)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_RSSI FIELD32(0x000000ff)
+#define RXD_W1_SIGNAL FIELD32(0x0000ff00)
+
+/*
+ * Word2
+ */
+#define RXD_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ */
+#define RXD_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT2500USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
new file mode 100644
index 000000000000..9845e584b731
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -0,0 +1,838 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 global information.
+ */
+
+#ifndef RT2X00_H
+#define RT2X00_H
+
+#include <linux/bitops.h>
+#include <linux/prefetch.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+
+#include <net/mac80211.h>
+
+#include "rt2x00debug.h"
+#include "rt2x00reg.h"
+#include "rt2x00ring.h"
+
+/*
+ * Module information.
+ * DRV_NAME should be set within the individual module source files.
+ */
+#define DRV_VERSION "2.0.10"
+#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
+
+/*
+ * Debug definitions.
+ * Debug output has to be enabled during compile time.
+ */
+#define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \
+ printk(__kernlvl "%s -> %s: %s - " __msg, \
+ wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args)
+
+#define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \
+ printk(__kernlvl "%s -> %s: %s - " __msg, \
+ DRV_NAME, __FUNCTION__, __lvl, ##__args)
+
+#ifdef CONFIG_RT2X00_DEBUG
+#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
+ DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args);
+#else
+#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
+ do { } while (0)
+#endif /* CONFIG_RT2X00_DEBUG */
+
+/*
+ * Various debug levels.
+ * The debug levels PANIC and ERROR both indicate serious problems,
+ * for this reason they should never be ignored.
+ * The special ERROR_PROBE message is for messages that are generated
+ * when the rt2x00_dev is not yet initialized.
+ */
+#define PANIC(__dev, __msg, __args...) \
+ DEBUG_PRINTK_MSG(__dev, KERN_CRIT, "Panic", __msg, ##__args)
+#define ERROR(__dev, __msg, __args...) \
+ DEBUG_PRINTK_MSG(__dev, KERN_ERR, "Error", __msg, ##__args)
+#define ERROR_PROBE(__msg, __args...) \
+ DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args)
+#define WARNING(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args)
+#define NOTICE(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args)
+#define INFO(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args)
+#define DEBUG(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args)
+#define EEPROM(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
+
+/*
+ * Ring sizes.
+ * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes.
+ * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings.
+ * MGMT_FRAME_SIZE is used for the BEACON ring.
+ */
+#define DATA_FRAME_SIZE 2432
+#define MGMT_FRAME_SIZE 256
+
+/*
+ * Number of entries in a packet ring.
+ * PCI devices only need 1 Beacon entry,
+ * but USB devices require a second because they
+ * have to send a Guardian byte first.
+ */
+#define RX_ENTRIES 12
+#define TX_ENTRIES 12
+#define ATIM_ENTRIES 1
+#define BEACON_ENTRIES 2
+
+/*
+ * Standard timing and size defines.
+ * These values should follow the ieee80211 specifications.
+ */
+#define ACK_SIZE 14
+#define IEEE80211_HEADER 24
+#define PLCP 48
+#define BEACON 100
+#define PREAMBLE 144
+#define SHORT_PREAMBLE 72
+#define SLOT_TIME 20
+#define SHORT_SLOT_TIME 9
+#define SIFS 10
+#define PIFS ( SIFS + SLOT_TIME )
+#define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME )
+#define DIFS ( PIFS + SLOT_TIME )
+#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME )
+#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+
+/*
+ * IEEE802.11 header defines
+ */
+static inline int is_rts_frame(u16 fc)
+{
+ return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
+}
+
+static inline int is_cts_frame(u16 fc)
+{
+ return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
+}
+
+static inline int is_probe_resp(u16 fc)
+{
+ return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
+}
+
+/*
+ * Chipset identification
+ * The chipset on the device is composed of a RT and RF chip.
+ * The chipset combination is important for determining device capabilities.
+ */
+struct rt2x00_chip {
+ u16 rt;
+#define RT2460 0x0101
+#define RT2560 0x0201
+#define RT2570 0x1201
+#define RT2561s 0x0301 /* Turbo */
+#define RT2561 0x0302
+#define RT2661 0x0401
+#define RT2571 0x1300
+
+ u16 rf;
+ u32 rev;
+};
+
+/*
+ * RF register values that belong to a particular channel.
+ */
+struct rf_channel {
+ int channel;
+ u32 rf1;
+ u32 rf2;
+ u32 rf3;
+ u32 rf4;
+};
+
+/*
+ * To optimize the quality of the link we need to store
+ * the quality of received frames and periodically
+ * optimize the link.
+ */
+struct link {
+ /*
+ * Link tuner counter
+ * The number of times the link has been tuned
+ * since the radio has been switched on.
+ */
+ u32 count;
+
+ /*
+ * Statistics required for Link tuning.
+ * For the average RSSI value we use the "Walking average" approach.
+ * When adding RSSI to the average value the following calculation
+ * is needed:
+ *
+ * avg_rssi = ((avg_rssi * 7) + rssi) / 8;
+ *
+ * The advantage of this approach is that we only need 1 variable
+ * to store the average in (No need for a count and a total).
+ * But more importantly, normal average values will over time
+ * move less and less towards newly added values this results
+ * that with link tuning, the device can have a very good RSSI
+ * for a few minutes but when the device is moved away from the AP
+ * the average will not decrease fast enough to compensate.
+ * The walking average compensates this and will move towards
+ * the new values correctly allowing a effective link tuning.
+ */
+ int avg_rssi;
+ int vgc_level;
+ int false_cca;
+
+ /*
+ * Statistics required for Signal quality calculation.
+ * For calculating the Signal quality we have to determine
+ * the total number of success and failed RX and TX frames.
+ * After that we also use the average RSSI value to help
+ * determining the signal quality.
+ * For the calculation we will use the following algorithm:
+ *
+ * rssi_percentage = (avg_rssi * 100) / rssi_offset
+ * rx_percentage = (rx_success * 100) / rx_total
+ * tx_percentage = (tx_success * 100) / tx_total
+ * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
+ * (WEIGHT_TX * tx_percentage) +
+ * (WEIGHT_RX * rx_percentage)) / 100
+ *
+ * This value should then be checked to not be greated then 100.
+ */
+ int rx_percentage;
+ int rx_success;
+ int rx_failed;
+ int tx_percentage;
+ int tx_success;
+ int tx_failed;
+#define WEIGHT_RSSI 20
+#define WEIGHT_RX 40
+#define WEIGHT_TX 40
+
+ /*
+ * Work structure for scheduling periodic link tuning.
+ */
+ struct delayed_work work;
+};
+
+/*
+ * Clear all counters inside the link structure.
+ * This can be easiest achieved by memsetting everything
+ * except for the work structure at the end.
+ */
+static inline void rt2x00_clear_link(struct link *link)
+{
+ memset(link, 0x00, sizeof(*link) - sizeof(link->work));
+ link->rx_percentage = 50;
+ link->tx_percentage = 50;
+}
+
+/*
+ * Update the rssi using the walking average approach.
+ */
+static inline void rt2x00_update_link_rssi(struct link *link, int rssi)
+{
+ if (!link->avg_rssi)
+ link->avg_rssi = rssi;
+ else
+ link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8;
+}
+
+/*
+ * When the avg_rssi is unset or no frames have been received),
+ * we need to return the default value which needs to be less
+ * than -80 so the device will select the maximum sensitivity.
+ */
+static inline int rt2x00_get_link_rssi(struct link *link)
+{
+ return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128;
+}
+
+/*
+ * Interface structure
+ * Configuration details about the current interface.
+ */
+struct interface {
+ /*
+ * Interface identification. The value is assigned
+ * to us by the 80211 stack, and is used to request
+ * new beacons.
+ */
+ int id;
+
+ /*
+ * Current working type (IEEE80211_IF_TYPE_*).
+ * When set to INVALID_INTERFACE, no interface is configured.
+ */
+ int type;
+#define INVALID_INTERFACE IEEE80211_IF_TYPE_INVALID
+
+ /*
+ * MAC of the device.
+ */
+ u8 mac[ETH_ALEN];
+
+ /*
+ * BBSID of the AP to associate with.
+ */
+ u8 bssid[ETH_ALEN];
+
+ /*
+ * Store the packet filter mode for the current interface.
+ */
+ unsigned int filter;
+};
+
+static inline int is_interface_present(struct interface *intf)
+{
+ return !!intf->id;
+}
+
+static inline int is_interface_type(struct interface *intf, int type)
+{
+ return intf->type == type;
+}
+
+/*
+ * Details about the supported modes, rates and channels
+ * of a particular chipset. This is used by rt2x00lib
+ * to build the ieee80211_hw_mode array for mac80211.
+ */
+struct hw_mode_spec {
+ /*
+ * Number of modes, rates and channels.
+ */
+ int num_modes;
+ int num_rates;
+ int num_channels;
+
+ /*
+ * txpower values.
+ */
+ const u8 *tx_power_a;
+ const u8 *tx_power_bg;
+ u8 tx_power_default;
+
+ /*
+ * Device/chipset specific value.
+ */
+ const struct rf_channel *channels;
+};
+
+/*
+ * Configuration structure wrapper around the
+ * mac80211 configuration structure.
+ * When mac80211 configures the driver, rt2x00lib
+ * can precalculate values which are equal for all
+ * rt2x00 drivers. Those values can be stored in here.
+ */
+struct rt2x00lib_conf {
+ struct ieee80211_conf *conf;
+ struct rf_channel rf;
+
+ int phymode;
+
+ int basic_rates;
+ int slot_time;
+
+ short sifs;
+ short pifs;
+ short difs;
+ short eifs;
+};
+
+/*
+ * rt2x00lib callback functions.
+ */
+struct rt2x00lib_ops {
+ /*
+ * Interrupt handlers.
+ */
+ irq_handler_t irq_handler;
+
+ /*
+ * Device init handlers.
+ */
+ int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
+ char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev);
+ int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data,
+ const size_t len);
+
+ /*
+ * Device initialization/deinitialization handlers.
+ */
+ int (*initialize) (struct rt2x00_dev *rt2x00dev);
+ void (*uninitialize) (struct rt2x00_dev *rt2x00dev);
+
+ /*
+ * Radio control handlers.
+ */
+ int (*set_device_state) (struct rt2x00_dev *rt2x00dev,
+ enum dev_state state);
+ int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
+ void (*link_stats) (struct rt2x00_dev *rt2x00dev);
+ void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
+ void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
+
+ /*
+ * TX control handlers
+ */
+ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control);
+ int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+ int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int maxpacket,
+ struct sk_buff *skb);
+ void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
+ unsigned int queue);
+
+ /*
+ * RX control handlers
+ */
+ void (*fill_rxdone) (struct data_entry *entry,
+ struct rxdata_entry_desc *desc);
+
+ /*
+ * Configuration handlers.
+ */
+ void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac);
+ void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid);
+ void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync);
+ void (*config_preamble) (struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time);
+ void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags,
+ struct rt2x00lib_conf *libconf);
+#define CONFIG_UPDATE_PHYMODE ( 1 << 1 )
+#define CONFIG_UPDATE_CHANNEL ( 1 << 2 )
+#define CONFIG_UPDATE_TXPOWER ( 1 << 3 )
+#define CONFIG_UPDATE_ANTENNA ( 1 << 4 )
+#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 )
+#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 )
+#define CONFIG_UPDATE_ALL 0xffff
+};
+
+/*
+ * rt2x00 driver callback operation structure.
+ */
+struct rt2x00_ops {
+ const char *name;
+ const unsigned int rxd_size;
+ const unsigned int txd_size;
+ const unsigned int eeprom_size;
+ const unsigned int rf_size;
+ const struct rt2x00lib_ops *lib;
+ const struct ieee80211_ops *hw;
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ const struct rt2x00debug *debugfs;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt2x00 device flags
+ */
+enum rt2x00_flags {
+ /*
+ * Device state flags
+ */
+ DEVICE_PRESENT,
+ DEVICE_REGISTERED_HW,
+ DEVICE_INITIALIZED,
+ DEVICE_STARTED,
+ DEVICE_STARTED_SUSPEND,
+ DEVICE_ENABLED_RADIO,
+ DEVICE_DISABLED_RADIO_HW,
+
+ /*
+ * Driver features
+ */
+ DRIVER_REQUIRE_FIRMWARE,
+ DRIVER_REQUIRE_BEACON_RING,
+
+ /*
+ * Driver configuration
+ */
+ CONFIG_SUPPORT_HW_BUTTON,
+ CONFIG_FRAME_TYPE,
+ CONFIG_RF_SEQUENCE,
+ CONFIG_EXTERNAL_LNA_A,
+ CONFIG_EXTERNAL_LNA_BG,
+ CONFIG_DOUBLE_ANTENNA,
+ CONFIG_DISABLE_LINK_TUNING,
+ CONFIG_SHORT_PREAMBLE,
+};
+
+/*
+ * rt2x00 device structure.
+ */
+struct rt2x00_dev {
+ /*
+ * Device structure.
+ * The structure stored in here depends on the
+ * system bus (PCI or USB).
+ * When accessing this variable, the rt2x00dev_{pci,usb}
+ * macro's should be used for correct typecasting.
+ */
+ void *dev;
+#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev )
+#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev )
+
+ /*
+ * Callback functions.
+ */
+ const struct rt2x00_ops *ops;
+
+ /*
+ * IEEE80211 control structure.
+ */
+ struct ieee80211_hw *hw;
+ struct ieee80211_hw_mode *hwmodes;
+ unsigned int curr_hwmode;
+#define HWMODE_B 0
+#define HWMODE_G 1
+#define HWMODE_A 2
+
+ /*
+ * rfkill structure for RF state switching support.
+ * This will only be compiled in when required.
+ */
+#ifdef CONFIG_RT2X00_LIB_RFKILL
+ struct rfkill *rfkill;
+ struct input_polled_dev *poll_dev;
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
+
+ /*
+ * If enabled, the debugfs interface structures
+ * required for deregistration of debugfs.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ const struct rt2x00debug_intf *debugfs_intf;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+ /*
+ * Device flags.
+ * In these flags the current status and some
+ * of the device capabilities are stored.
+ */
+ unsigned long flags;
+
+ /*
+ * Chipset identification.
+ */
+ struct rt2x00_chip chip;
+
+ /*
+ * hw capability specifications.
+ */
+ struct hw_mode_spec spec;
+
+ /*
+ * Register pointers
+ * csr_addr: Base register address. (PCI)
+ * csr_cache: CSR cache for usb_control_msg. (USB)
+ */
+ void __iomem *csr_addr;
+ void *csr_cache;
+
+ /*
+ * Interface configuration.
+ */
+ struct interface interface;
+
+ /*
+ * Link quality
+ */
+ struct link link;
+
+ /*
+ * EEPROM data.
+ */
+ __le16 *eeprom;
+
+ /*
+ * Active RF register values.
+ * These are stored here so we don't need
+ * to read the rf registers and can directly
+ * use this value instead.
+ * This field should be accessed by using
+ * rt2x00_rf_read() and rt2x00_rf_write().
+ */
+ u32 *rf;
+
+ /*
+ * Current TX power value.
+ */
+ u16 tx_power;
+
+ /*
+ * LED register (for rt61pci & rt73usb).
+ */
+ u16 led_reg;
+
+ /*
+ * Led mode (LED_MODE_*)
+ */
+ u8 led_mode;
+
+ /*
+ * Rssi <-> Dbm offset
+ */
+ u8 rssi_offset;
+
+ /*
+ * Frequency offset (for rt61pci & rt73usb).
+ */
+ u8 freq_offset;
+
+ /*
+ * Low level statistics which will have
+ * to be kept up to date while device is running.
+ */
+ struct ieee80211_low_level_stats low_level_stats;
+
+ /*
+ * RX configuration information.
+ */
+ struct ieee80211_rx_status rx_status;
+
+ /*
+ * Scheduled work.
+ */
+ struct work_struct beacon_work;
+ struct work_struct filter_work;
+ struct work_struct config_work;
+
+ /*
+ * Data ring arrays for RX, TX and Beacon.
+ * The Beacon array also contains the Atim ring
+ * if that is supported by the device.
+ */
+ int data_rings;
+ struct data_ring *rx;
+ struct data_ring *tx;
+ struct data_ring *bcn;
+
+ /*
+ * Firmware image.
+ */
+ const struct firmware *fw;
+};
+
+/*
+ * For-each loop for the ring array.
+ * All rings have been allocated as a single array,
+ * this means we can create a very simply loop macro
+ * that is capable of looping through all rings.
+ * ring_end(), txring_end() and ring_loop() are helper macro's which
+ * should not be used directly. Instead the following should be used:
+ * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim)
+ * txring_for_each() - Loops through TX data rings (TX only)
+ * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim)
+ */
+#define ring_end(__dev) \
+ &(__dev)->rx[(__dev)->data_rings]
+
+#define txring_end(__dev) \
+ &(__dev)->tx[(__dev)->hw->queues]
+
+#define ring_loop(__entry, __start, __end) \
+ for ((__entry) = (__start); \
+ prefetch(&(__entry)[1]), (__entry) != (__end); \
+ (__entry) = &(__entry)[1])
+
+#define ring_for_each(__dev, __entry) \
+ ring_loop(__entry, (__dev)->rx, ring_end(__dev))
+
+#define txring_for_each(__dev, __entry) \
+ ring_loop(__entry, (__dev)->tx, txring_end(__dev))
+
+#define txringall_for_each(__dev, __entry) \
+ ring_loop(__entry, (__dev)->tx, ring_end(__dev))
+
+/*
+ * Generic RF access.
+ * The RF is being accessed by word index.
+ */
+static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ *data = rt2x00dev->rf[word];
+}
+
+static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00dev->rf[word] = data;
+}
+
+/*
+ * Generic EEPROM access.
+ * The EEPROM is being accessed by word index.
+ */
+static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word)
+{
+ return (void *)&rt2x00dev->eeprom[word];
+}
+
+static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u16 *data)
+{
+ *data = le16_to_cpu(rt2x00dev->eeprom[word]);
+}
+
+static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u16 data)
+{
+ rt2x00dev->eeprom[word] = cpu_to_le16(data);
+}
+
+/*
+ * Chipset handlers
+ */
+static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
+ const u16 rt, const u16 rf, const u32 rev)
+{
+ INFO(rt2x00dev,
+ "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
+ rt, rf, rev);
+
+ rt2x00dev->chip.rt = rt;
+ rt2x00dev->chip.rf = rf;
+ rt2x00dev->chip.rev = rev;
+}
+
+static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
+{
+ return (chipset->rt == chip);
+}
+
+static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
+{
+ return (chipset->rf == chip);
+}
+
+static inline u16 rt2x00_get_rev(const struct rt2x00_chip *chipset)
+{
+ return chipset->rev;
+}
+
+static inline u16 rt2x00_rev(const struct rt2x00_chip *chipset, const u32 mask)
+{
+ return chipset->rev & mask;
+}
+
+/*
+ * Duration calculations
+ * The rate variable passed is: 100kbs.
+ * To convert from bytes to bits we multiply size with 8,
+ * then the size is multiplied with 10 to make the
+ * real rate -> rate argument correction.
+ */
+static inline u16 get_duration(const unsigned int size, const u8 rate)
+{
+ return ((size * 8 * 10) / rate);
+}
+
+static inline u16 get_duration_res(const unsigned int size, const u8 rate)
+{
+ return ((size * 8 * 10) % rate);
+}
+
+/*
+ * Library functions.
+ */
+struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
+ const unsigned int queue);
+
+/*
+ * Interrupt context handlers.
+ */
+void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_txdone(struct data_entry *entry,
+ const int status, const int retry);
+void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
+ struct rxdata_entry_desc *desc);
+
+/*
+ * TX descriptor initializer
+ */
+void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control);
+
+/*
+ * mac80211 handlers.
+ */
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+int rt2x00mac_start(struct ieee80211_hw *hw);
+void rt2x00mac_stop(struct ieee80211_hw *hw);
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf);
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats);
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats);
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+ int cts_protection, int preamble);
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params);
+
+/*
+ * Driver allocation handlers.
+ */
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev);
+#ifdef CONFIG_PM
+int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state);
+int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev);
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
new file mode 100644
index 000000000000..12914cf7156c
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -0,0 +1,205 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 generic configuration routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+
+/*
+ * The MAC and BSSID addressess are simple array of bytes,
+ * these arrays are little endian, so when sending the addressess
+ * to the drivers, copy the it into a endian-signed variable.
+ *
+ * Note that all devices (except rt2500usb) have 32 bits
+ * register word sizes. This means that whatever variable we
+ * pass _must_ be a multiple of 32 bits. Otherwise the device
+ * might not accept what we are sending to it.
+ * This will also make it easier for the driver to write
+ * the data to the device.
+ *
+ * Also note that when NULL is passed as address the
+ * we will send 00:00:00:00:00 to the device to clear the address.
+ * This will prevent the device being confused when it wants
+ * to ACK frames or consideres itself associated.
+ */
+void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac)
+{
+ __le32 reg[2];
+
+ memset(&reg, 0, sizeof(reg));
+ if (mac)
+ memcpy(&reg, mac, ETH_ALEN);
+
+ rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, &reg[0]);
+}
+
+void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
+{
+ __le32 reg[2];
+
+ memset(&reg, 0, sizeof(reg));
+ if (bssid)
+ memcpy(&reg, bssid, ETH_ALEN);
+
+ rt2x00dev->ops->lib->config_bssid(rt2x00dev, &reg[0]);
+}
+
+void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type)
+{
+ int tsf_sync;
+
+ switch (type) {
+ case IEEE80211_IF_TYPE_IBSS:
+ case IEEE80211_IF_TYPE_AP:
+ tsf_sync = TSF_SYNC_BEACON;
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ tsf_sync = TSF_SYNC_INFRA;
+ break;
+ default:
+ tsf_sync = TSF_SYNC_NONE;
+ break;
+ }
+
+ rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync);
+}
+
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf, const int force_config)
+{
+ struct rt2x00lib_conf libconf;
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_rate *rate;
+ int flags = 0;
+ int short_slot_time;
+
+ /*
+ * In some situations we want to force all configurations
+ * to be reloaded (When resuming for instance).
+ */
+ if (force_config) {
+ flags = CONFIG_UPDATE_ALL;
+ goto config;
+ }
+
+ /*
+ * Check which configuration options have been
+ * updated and should be send to the device.
+ */
+ if (rt2x00dev->rx_status.phymode != conf->phymode)
+ flags |= CONFIG_UPDATE_PHYMODE;
+ if (rt2x00dev->rx_status.channel != conf->channel)
+ flags |= CONFIG_UPDATE_CHANNEL;
+ if (rt2x00dev->tx_power != conf->power_level)
+ flags |= CONFIG_UPDATE_TXPOWER;
+ if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx)
+ flags |= CONFIG_UPDATE_ANTENNA;
+
+ /*
+ * The following configuration options are never
+ * stored anywhere and will always be updated.
+ */
+ flags |= CONFIG_UPDATE_SLOT_TIME;
+ flags |= CONFIG_UPDATE_BEACON_INT;
+
+ /*
+ * We have determined what options should be updated,
+ * now precalculate device configuration values depending
+ * on what configuration options need to be updated.
+ */
+config:
+ memset(&libconf, 0, sizeof(libconf));
+
+ if (flags & CONFIG_UPDATE_PHYMODE) {
+ switch (conf->phymode) {
+ case MODE_IEEE80211A:
+ libconf.phymode = HWMODE_A;
+ break;
+ case MODE_IEEE80211B:
+ libconf.phymode = HWMODE_B;
+ break;
+ case MODE_IEEE80211G:
+ libconf.phymode = HWMODE_G;
+ break;
+ default:
+ ERROR(rt2x00dev,
+ "Attempt to configure unsupported mode (%d)"
+ "Defaulting to 802.11b", conf->phymode);
+ libconf.phymode = HWMODE_B;
+ }
+
+ mode = &rt2x00dev->hwmodes[libconf.phymode];
+ rate = &mode->rates[mode->num_rates - 1];
+
+ libconf.basic_rates =
+ DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK;
+ }
+
+ if (flags & CONFIG_UPDATE_CHANNEL) {
+ memcpy(&libconf.rf,
+ &rt2x00dev->spec.channels[conf->channel_val],
+ sizeof(libconf.rf));
+ }
+
+ if (flags & CONFIG_UPDATE_SLOT_TIME) {
+ short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
+
+ libconf.slot_time =
+ short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
+ libconf.sifs = SIFS;
+ libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
+ libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
+ libconf.eifs = EIFS;
+ }
+
+ libconf.conf = conf;
+
+ /*
+ * Start configuration.
+ */
+ rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf);
+
+ /*
+ * Some configuration changes affect the link quality
+ * which means we need to reset the link tuner.
+ */
+ if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+ rt2x00lib_reset_link_tuner(rt2x00dev);
+
+ rt2x00dev->curr_hwmode = libconf.phymode;
+ rt2x00dev->rx_status.phymode = conf->phymode;
+ rt2x00dev->rx_status.freq = conf->freq;
+ rt2x00dev->rx_status.channel = conf->channel;
+ rt2x00dev->tx_power = conf->power_level;
+ rt2x00dev->rx_status.antenna = conf->antenna_sel_rx;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
new file mode 100644
index 000000000000..9275d6f9517e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -0,0 +1,368 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 debugfs specific routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+#define PRINT_LINE_LEN_MAX 32
+
+struct rt2x00debug_intf {
+ /*
+ * Pointer to driver structure where
+ * this debugfs entry belongs to.
+ */
+ struct rt2x00_dev *rt2x00dev;
+
+ /*
+ * Reference to the rt2x00debug structure
+ * which can be used to communicate with
+ * the registers.
+ */
+ const struct rt2x00debug *debug;
+
+ /*
+ * Debugfs entries for:
+ * - driver folder
+ * - driver file
+ * - chipset file
+ * - device flags file
+ * - register offset/value files
+ * - eeprom offset/value files
+ * - bbp offset/value files
+ * - rf offset/value files
+ */
+ struct dentry *driver_folder;
+ struct dentry *driver_entry;
+ struct dentry *chipset_entry;
+ struct dentry *dev_flags;
+ struct dentry *csr_off_entry;
+ struct dentry *csr_val_entry;
+ struct dentry *eeprom_off_entry;
+ struct dentry *eeprom_val_entry;
+ struct dentry *bbp_off_entry;
+ struct dentry *bbp_val_entry;
+ struct dentry *rf_off_entry;
+ struct dentry *rf_val_entry;
+
+ /*
+ * Driver and chipset files will use a data buffer
+ * that has been created in advance. This will simplify
+ * the code since we can use the debugfs functions.
+ */
+ struct debugfs_blob_wrapper driver_blob;
+ struct debugfs_blob_wrapper chipset_blob;
+
+ /*
+ * Requested offset for each register type.
+ */
+ unsigned int offset_csr;
+ unsigned int offset_eeprom;
+ unsigned int offset_bbp;
+ unsigned int offset_rf;
+};
+
+static int rt2x00debug_file_open(struct inode *inode, struct file *file)
+{
+ struct rt2x00debug_intf *intf = inode->i_private;
+
+ file->private_data = inode->i_private;
+
+ if (!try_module_get(intf->debug->owner))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int rt2x00debug_file_release(struct inode *inode, struct file *file)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+
+ module_put(intf->debug->owner);
+
+ return 0;
+}
+
+#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
+static ssize_t rt2x00debug_read_##__name(struct file *file, \
+ char __user *buf, \
+ size_t length, \
+ loff_t *offset) \
+{ \
+ struct rt2x00debug_intf *intf = file->private_data; \
+ const struct rt2x00debug *debug = intf->debug; \
+ char line[16]; \
+ size_t size; \
+ __type value; \
+ \
+ if (*offset) \
+ return 0; \
+ \
+ if (intf->offset_##__name >= debug->__name.word_count) \
+ return -EINVAL; \
+ \
+ debug->__name.read(intf->rt2x00dev, \
+ intf->offset_##__name, &value); \
+ \
+ size = sprintf(line, __format, value); \
+ \
+ if (copy_to_user(buf, line, size)) \
+ return -EFAULT; \
+ \
+ *offset += size; \
+ return size; \
+}
+
+#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
+static ssize_t rt2x00debug_write_##__name(struct file *file, \
+ const char __user *buf,\
+ size_t length, \
+ loff_t *offset) \
+{ \
+ struct rt2x00debug_intf *intf = file->private_data; \
+ const struct rt2x00debug *debug = intf->debug; \
+ char line[16]; \
+ size_t size; \
+ __type value; \
+ \
+ if (*offset) \
+ return 0; \
+ \
+ if (!capable(CAP_NET_ADMIN)) \
+ return -EPERM; \
+ \
+ if (intf->offset_##__name >= debug->__name.word_count) \
+ return -EINVAL; \
+ \
+ if (copy_from_user(line, buf, length)) \
+ return -EFAULT; \
+ \
+ size = strlen(line); \
+ value = simple_strtoul(line, NULL, 0); \
+ \
+ debug->__name.write(intf->rt2x00dev, \
+ intf->offset_##__name, value); \
+ \
+ *offset += size; \
+ return size; \
+}
+
+#define RT2X00DEBUGFS_OPS(__name, __format, __type) \
+RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \
+RT2X00DEBUGFS_OPS_WRITE(__name, __type); \
+ \
+static const struct file_operations rt2x00debug_fop_##__name = {\
+ .owner = THIS_MODULE, \
+ .read = rt2x00debug_read_##__name, \
+ .write = rt2x00debug_write_##__name, \
+ .open = rt2x00debug_file_open, \
+ .release = rt2x00debug_file_release, \
+};
+
+RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
+RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
+RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
+RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
+
+static ssize_t rt2x00debug_read_dev_flags(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ char line[16];
+ size_t size;
+
+ if (*offset)
+ return 0;
+
+ size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
+
+ if (copy_to_user(buf, line, size))
+ return -EFAULT;
+
+ *offset += size;
+ return size;
+}
+
+static const struct file_operations rt2x00debug_fop_dev_flags = {
+ .owner = THIS_MODULE,
+ .read = rt2x00debug_read_dev_flags,
+ .open = rt2x00debug_file_open,
+ .release = rt2x00debug_file_release,
+};
+
+static struct dentry *rt2x00debug_create_file_driver(const char *name,
+ struct rt2x00debug_intf
+ *intf,
+ struct debugfs_blob_wrapper
+ *blob)
+{
+ char *data;
+
+ data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ blob->data = data;
+ data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name);
+ data += sprintf(data, "version: %s\n", DRV_VERSION);
+ data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
+ blob->size = strlen(blob->data);
+
+ return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+}
+
+static struct dentry *rt2x00debug_create_file_chipset(const char *name,
+ struct rt2x00debug_intf
+ *intf,
+ struct
+ debugfs_blob_wrapper
+ *blob)
+{
+ const struct rt2x00debug *debug = intf->debug;
+ char *data;
+
+ data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ blob->data = data;
+ data += sprintf(data, "csr length: %d\n", debug->csr.word_count);
+ data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count);
+ data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count);
+ data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
+ blob->size = strlen(blob->data);
+
+ return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+}
+
+void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
+ struct rt2x00debug_intf *intf;
+
+ intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
+ if (!intf) {
+ ERROR(rt2x00dev, "Failed to allocate debug handler.\n");
+ return;
+ }
+
+ intf->debug = debug;
+ intf->rt2x00dev = rt2x00dev;
+ rt2x00dev->debugfs_intf = intf;
+
+ intf->driver_folder =
+ debugfs_create_dir(intf->rt2x00dev->ops->name,
+ rt2x00dev->hw->wiphy->debugfsdir);
+ if (IS_ERR(intf->driver_folder))
+ goto exit;
+
+ intf->driver_entry =
+ rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
+ if (IS_ERR(intf->driver_entry))
+ goto exit;
+
+ intf->chipset_entry =
+ rt2x00debug_create_file_chipset("chipset",
+ intf, &intf->chipset_blob);
+ if (IS_ERR(intf->chipset_entry))
+ goto exit;
+
+ intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO,
+ intf->driver_folder, intf,
+ &rt2x00debug_fop_dev_flags);
+ if (IS_ERR(intf->dev_flags))
+ goto exit;
+
+#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \
+({ \
+ (__intf)->__name##_off_entry = \
+ debugfs_create_u32(__stringify(__name) "_offset", \
+ S_IRUGO | S_IWUSR, \
+ (__intf)->driver_folder, \
+ &(__intf)->offset_##__name); \
+ if (IS_ERR((__intf)->__name##_off_entry)) \
+ goto exit; \
+ \
+ (__intf)->__name##_val_entry = \
+ debugfs_create_file(__stringify(__name) "_value", \
+ S_IRUGO | S_IWUSR, \
+ (__intf)->driver_folder, \
+ (__intf), &rt2x00debug_fop_##__name);\
+ if (IS_ERR((__intf)->__name##_val_entry)) \
+ goto exit; \
+})
+
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, csr);
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom);
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp);
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, rf);
+
+#undef RT2X00DEBUGFS_CREATE_ENTRY
+
+ return;
+
+exit:
+ rt2x00debug_deregister(rt2x00dev);
+ ERROR(rt2x00dev, "Failed to register debug handler.\n");
+
+ return;
+}
+
+void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+
+ if (unlikely(!intf))
+ return;
+
+ debugfs_remove(intf->rf_val_entry);
+ debugfs_remove(intf->rf_off_entry);
+ debugfs_remove(intf->bbp_val_entry);
+ debugfs_remove(intf->bbp_off_entry);
+ debugfs_remove(intf->eeprom_val_entry);
+ debugfs_remove(intf->eeprom_off_entry);
+ debugfs_remove(intf->csr_val_entry);
+ debugfs_remove(intf->csr_off_entry);
+ debugfs_remove(intf->dev_flags);
+ debugfs_remove(intf->chipset_entry);
+ debugfs_remove(intf->driver_entry);
+ debugfs_remove(intf->driver_folder);
+ kfree(intf->chipset_blob.data);
+ kfree(intf->driver_blob.data);
+ kfree(intf);
+
+ rt2x00dev->debugfs_intf = NULL;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h
new file mode 100644
index 000000000000..860e8fa3a0da
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00debug
+ Abstract: Data structures for the rt2x00debug.
+ */
+
+#ifndef RT2X00DEBUG_H
+#define RT2X00DEBUG_H
+
+struct rt2x00_dev;
+
+#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \
+struct reg##__name { \
+ void (*read)(const struct rt2x00_dev *rt2x00dev, \
+ const unsigned int word, __type *data); \
+ void (*write)(const struct rt2x00_dev *rt2x00dev, \
+ const unsigned int word, __type data); \
+ \
+ unsigned int word_size; \
+ unsigned int word_count; \
+} __name
+
+struct rt2x00debug {
+ /*
+ * Reference to the modules structure.
+ */
+ struct module *owner;
+
+ /*
+ * Register access entries.
+ */
+ RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32);
+ RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
+ RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
+ RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
+};
+
+#endif /* RT2X00DEBUG_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
new file mode 100644
index 000000000000..bb6f46cfbb9f
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -0,0 +1,1202 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 generic device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+/*
+ * Ring handler.
+ */
+struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
+ const unsigned int queue)
+{
+ int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Check if we are requesting a reqular TX ring,
+ * or if we are requesting a Beacon or Atim ring.
+ * For Atim rings, we should check if it is supported.
+ */
+ if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
+ return &rt2x00dev->tx[queue];
+
+ if (!rt2x00dev->bcn || !beacon)
+ return NULL;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON)
+ return &rt2x00dev->bcn[0];
+ else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ return &rt2x00dev->bcn[1];
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_get_ring);
+
+/*
+ * Link tuning handlers
+ */
+static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00_clear_link(&rt2x00dev->link);
+
+ /*
+ * Reset the link tuner.
+ */
+ rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+
+ queue_delayed_work(rt2x00dev->hw->workqueue,
+ &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+}
+
+static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ cancel_delayed_work_sync(&rt2x00dev->link.work);
+}
+
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ rt2x00lib_stop_link_tuner(rt2x00dev);
+ rt2x00lib_start_link_tuner(rt2x00dev);
+}
+
+/*
+ * Radio control handlers.
+ */
+int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ int status;
+
+ /*
+ * Don't enable the radio twice.
+ * And check if the hardware button has been disabled.
+ */
+ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Enable radio.
+ */
+ status = rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_ON);
+ if (status)
+ return status;
+
+ __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);
+
+ /*
+ * Enable RX.
+ */
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+
+ /*
+ * Start the TX queues.
+ */
+ ieee80211_start_queues(rt2x00dev->hw);
+
+ return 0;
+}
+
+void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Stop all scheduled work.
+ */
+ if (work_pending(&rt2x00dev->beacon_work))
+ cancel_work_sync(&rt2x00dev->beacon_work);
+ if (work_pending(&rt2x00dev->filter_work))
+ cancel_work_sync(&rt2x00dev->filter_work);
+ if (work_pending(&rt2x00dev->config_work))
+ cancel_work_sync(&rt2x00dev->config_work);
+
+ /*
+ * Stop the TX queues.
+ */
+ ieee80211_stop_queues(rt2x00dev->hw);
+
+ /*
+ * Disable RX.
+ */
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+
+ /*
+ * Disable radio.
+ */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF);
+}
+
+void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+ /*
+ * When we are disabling the RX, we should also stop the link tuner.
+ */
+ if (state == STATE_RADIO_RX_OFF)
+ rt2x00lib_stop_link_tuner(rt2x00dev);
+
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+
+ /*
+ * When we are enabling the RX, we should also start the link tuner.
+ */
+ if (state == STATE_RADIO_RX_ON &&
+ is_interface_present(&rt2x00dev->interface))
+ rt2x00lib_start_link_tuner(rt2x00dev);
+}
+
+static void rt2x00lib_precalculate_link_signal(struct link *link)
+{
+ if (link->rx_failed || link->rx_success)
+ link->rx_percentage =
+ (link->rx_success * 100) /
+ (link->rx_failed + link->rx_success);
+ else
+ link->rx_percentage = 50;
+
+ if (link->tx_failed || link->tx_success)
+ link->tx_percentage =
+ (link->tx_success * 100) /
+ (link->tx_failed + link->tx_success);
+ else
+ link->tx_percentage = 50;
+
+ link->rx_success = 0;
+ link->rx_failed = 0;
+ link->tx_success = 0;
+ link->tx_failed = 0;
+}
+
+static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
+ int rssi)
+{
+ int rssi_percentage = 0;
+ int signal;
+
+ /*
+ * We need a positive value for the RSSI.
+ */
+ if (rssi < 0)
+ rssi += rt2x00dev->rssi_offset;
+
+ /*
+ * Calculate the different percentages,
+ * which will be used for the signal.
+ */
+ if (rt2x00dev->rssi_offset)
+ rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
+
+ /*
+ * Add the individual percentages and use the WEIGHT
+ * defines to calculate the current link signal.
+ */
+ signal = ((WEIGHT_RSSI * rssi_percentage) +
+ (WEIGHT_TX * rt2x00dev->link.tx_percentage) +
+ (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100;
+
+ return (signal > 100) ? 100 : signal;
+}
+
+static void rt2x00lib_link_tuner(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, link.work.work);
+
+ /*
+ * When the radio is shutting down we should
+ * immediately cease all link tuning.
+ */
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Update statistics.
+ */
+ rt2x00dev->ops->lib->link_stats(rt2x00dev);
+
+ rt2x00dev->low_level_stats.dot11FCSErrorCount +=
+ rt2x00dev->link.rx_failed;
+
+ /*
+ * Only perform the link tuning when Link tuning
+ * has been enabled (This could have been disabled from the EEPROM).
+ */
+ if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
+ rt2x00dev->ops->lib->link_tuner(rt2x00dev);
+
+ /*
+ * Precalculate a portion of the link signal which is
+ * in based on the tx/rx success/failure counters.
+ */
+ rt2x00lib_precalculate_link_signal(&rt2x00dev->link);
+
+ /*
+ * Increase tuner counter, and reschedule the next link tuner run.
+ */
+ rt2x00dev->link.count++;
+ queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
+ LINK_TUNE_INTERVAL);
+}
+
+static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, filter_work);
+ unsigned int filter = rt2x00dev->interface.filter;
+
+ /*
+ * Since we had stored the filter inside interface.filter,
+ * we should now clear that field. Otherwise the driver will
+ * assume nothing has changed (*total_flags will be compared
+ * to interface.filter to determine if any action is required).
+ */
+ rt2x00dev->interface.filter = 0;
+
+ rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw,
+ filter, &filter, 0, NULL);
+}
+
+static void rt2x00lib_configuration_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, config_work);
+ int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+ rt2x00mac_erp_ie_changed(rt2x00dev->hw,
+ IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble);
+}
+
+/*
+ * Interrupt context handlers.
+ */
+static void rt2x00lib_beacondone_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, beacon_work);
+ struct data_ring *ring =
+ rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+ struct sk_buff *skb;
+
+ skb = ieee80211_beacon_get(rt2x00dev->hw,
+ rt2x00dev->interface.id,
+ &entry->tx_status.control);
+ if (!skb)
+ return;
+
+ rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
+ &entry->tx_status.control);
+
+ dev_kfree_skb(skb);
+}
+
+void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
+
+void rt2x00lib_txdone(struct data_entry *entry,
+ const int status, const int retry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+ struct ieee80211_tx_status *tx_status = &entry->tx_status;
+ struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats;
+ int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY);
+ int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID ||
+ status == TX_FAIL_OTHER);
+
+ /*
+ * Update TX statistics.
+ */
+ tx_status->flags = 0;
+ tx_status->ack_signal = 0;
+ tx_status->excessive_retries = (status == TX_FAIL_RETRY);
+ tx_status->retry_count = retry;
+ rt2x00dev->link.tx_success += success;
+ rt2x00dev->link.tx_failed += retry + fail;
+
+ if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (success)
+ tx_status->flags |= IEEE80211_TX_STATUS_ACK;
+ else
+ stats->dot11ACKFailureCount++;
+ }
+
+ tx_status->queue_length = entry->ring->stats.limit;
+ tx_status->queue_number = tx_status->control.queue;
+
+ if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ if (success)
+ stats->dot11RTSSuccessCount++;
+ else
+ stats->dot11RTSFailureCount++;
+ }
+
+ /*
+ * Send the tx_status to mac80211,
+ * that method also cleans up the skb structure.
+ */
+ ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status);
+ entry->skb = NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
+
+void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
+ struct rxdata_entry_desc *desc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+ struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_rate *rate;
+ unsigned int i;
+ int val = 0;
+
+ /*
+ * Update RX statistics.
+ */
+ mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode];
+ for (i = 0; i < mode->num_rates; i++) {
+ rate = &mode->rates[i];
+
+ /*
+ * When frame was received with an OFDM bitrate,
+ * the signal is the PLCP value. If it was received with
+ * a CCK bitrate the signal is the rate in 0.5kbit/s.
+ */
+ if (!desc->ofdm)
+ val = DEVICE_GET_RATE_FIELD(rate->val, RATE);
+ else
+ val = DEVICE_GET_RATE_FIELD(rate->val, PLCP);
+
+ if (val == desc->signal) {
+ val = rate->val;
+ break;
+ }
+ }
+
+ rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi);
+ rt2x00dev->link.rx_success++;
+ rx_status->rate = val;
+ rx_status->signal =
+ rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
+ rx_status->ssi = desc->rssi;
+ rx_status->flag = desc->flags;
+
+ /*
+ * Send frame to mac80211
+ */
+ ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
+
+/*
+ * TX descriptor initializer
+ */
+void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ struct txdata_entry_desc desc;
+ struct data_ring *ring;
+ int tx_rate;
+ int bitrate;
+ int duration;
+ int residual;
+ u16 frame_control;
+ u16 seq_ctrl;
+
+ /*
+ * Make sure the descriptor is properly cleared.
+ */
+ memset(&desc, 0x00, sizeof(desc));
+
+ /*
+ * Get ring pointer, if we fail to obtain the
+ * correct ring, then use the first TX ring.
+ */
+ ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+ if (!ring)
+ ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+ desc.cw_min = ring->tx_params.cw_min;
+ desc.cw_max = ring->tx_params.cw_max;
+ desc.aifs = ring->tx_params.aifs;
+
+ /*
+ * Identify queue
+ */
+ if (control->queue < rt2x00dev->hw->queues)
+ desc.queue = control->queue;
+ else if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+ control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ desc.queue = QUEUE_MGMT;
+ else
+ desc.queue = QUEUE_OTHER;
+
+ /*
+ * Read required fields from ieee80211 header.
+ */
+ frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+ seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl);
+
+ tx_rate = control->tx_rate;
+
+ /*
+ * Check if this is a RTS/CTS frame
+ */
+ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
+ __set_bit(ENTRY_TXD_BURST, &desc.flags);
+ if (is_rts_frame(frame_control))
+ __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags);
+ if (control->rts_cts_rate)
+ tx_rate = control->rts_cts_rate;
+ }
+
+ /*
+ * Check for OFDM
+ */
+ if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK)
+ __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags);
+
+ /*
+ * Check if more fragments are pending
+ */
+ if (ieee80211_get_morefrag(ieee80211hdr)) {
+ __set_bit(ENTRY_TXD_BURST, &desc.flags);
+ __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags);
+ }
+
+ /*
+ * Beacons and probe responses require the tsf timestamp
+ * to be inserted into the frame.
+ */
+ if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+ is_probe_resp(frame_control))
+ __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags);
+
+ /*
+ * Determine with what IFS priority this frame should be send.
+ * Set ifs to IFS_SIFS when the this is not the first fragment,
+ * or this fragment came after RTS/CTS.
+ */
+ if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
+ test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags))
+ desc.ifs = IFS_SIFS;
+ else
+ desc.ifs = IFS_BACKOFF;
+
+ /*
+ * PLCP setup
+ * Length calculation depends on OFDM/CCK rate.
+ */
+ desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+ desc.service = 0x04;
+
+ if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) {
+ desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f;
+ desc.length_low = ((length + FCS_LEN) & 0x3f);
+ } else {
+ bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
+
+ /*
+ * Convert length to microseconds.
+ */
+ residual = get_duration_res(length + FCS_LEN, bitrate);
+ duration = get_duration(length + FCS_LEN, bitrate);
+
+ if (residual != 0) {
+ duration++;
+
+ /*
+ * Check if we need to set the Length Extension
+ */
+ if (bitrate == 110 && residual <= 3)
+ desc.service |= 0x80;
+ }
+
+ desc.length_high = (duration >> 8) & 0xff;
+ desc.length_low = duration & 0xff;
+
+ /*
+ * When preamble is enabled we should set the
+ * preamble bit for the signal.
+ */
+ if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
+ desc.signal |= 0x08;
+ }
+
+ rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc,
+ ieee80211hdr, length, control);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
+
+/*
+ * Driver initialization handlers.
+ */
+static void rt2x00lib_channel(struct ieee80211_channel *entry,
+ const int channel, const int tx_power,
+ const int value)
+{
+ entry->chan = channel;
+ if (channel <= 14)
+ entry->freq = 2407 + (5 * channel);
+ else
+ entry->freq = 5000 + (5 * channel);
+ entry->val = value;
+ entry->flag =
+ IEEE80211_CHAN_W_IBSS |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_SCAN;
+ entry->power_level = tx_power;
+ entry->antenna_max = 0xff;
+}
+
+static void rt2x00lib_rate(struct ieee80211_rate *entry,
+ const int rate, const int mask,
+ const int plcp, const int flags)
+{
+ entry->rate = rate;
+ entry->val =
+ DEVICE_SET_RATE_FIELD(rate, RATE) |
+ DEVICE_SET_RATE_FIELD(mask, RATEMASK) |
+ DEVICE_SET_RATE_FIELD(plcp, PLCP);
+ entry->flags = flags;
+ entry->val2 = entry->val;
+ if (entry->flags & IEEE80211_RATE_PREAMBLE2)
+ entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE);
+ entry->min_rssi_ack = 0;
+ entry->min_rssi_ack_delta = 0;
+}
+
+static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
+ struct hw_mode_spec *spec)
+{
+ struct ieee80211_hw *hw = rt2x00dev->hw;
+ struct ieee80211_hw_mode *hwmodes;
+ struct ieee80211_channel *channels;
+ struct ieee80211_rate *rates;
+ unsigned int i;
+ unsigned char tx_power;
+
+ hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL);
+ if (!hwmodes)
+ goto exit;
+
+ channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL);
+ if (!channels)
+ goto exit_free_modes;
+
+ rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL);
+ if (!rates)
+ goto exit_free_channels;
+
+ /*
+ * Initialize Rate list.
+ */
+ rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB,
+ 0x00, IEEE80211_RATE_CCK);
+ rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB,
+ 0x01, IEEE80211_RATE_CCK_2);
+ rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB,
+ 0x02, IEEE80211_RATE_CCK_2);
+ rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB,
+ 0x03, IEEE80211_RATE_CCK_2);
+
+ if (spec->num_rates > 4) {
+ rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB,
+ 0x0b, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB,
+ 0x0f, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB,
+ 0x0a, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB,
+ 0x0e, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB,
+ 0x09, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB,
+ 0x0d, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB,
+ 0x08, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB,
+ 0x0c, IEEE80211_RATE_OFDM);
+ }
+
+ /*
+ * Initialize Channel list.
+ */
+ for (i = 0; i < spec->num_channels; i++) {
+ if (spec->channels[i].channel <= 14)
+ tx_power = spec->tx_power_bg[i];
+ else if (spec->tx_power_a)
+ tx_power = spec->tx_power_a[i];
+ else
+ tx_power = spec->tx_power_default;
+
+ rt2x00lib_channel(&channels[i],
+ spec->channels[i].channel, tx_power, i);
+ }
+
+ /*
+ * Intitialize 802.11b
+ * Rates: CCK.
+ * Channels: OFDM.
+ */
+ if (spec->num_modes > HWMODE_B) {
+ hwmodes[HWMODE_B].mode = MODE_IEEE80211B;
+ hwmodes[HWMODE_B].num_channels = 14;
+ hwmodes[HWMODE_B].num_rates = 4;
+ hwmodes[HWMODE_B].channels = channels;
+ hwmodes[HWMODE_B].rates = rates;
+ }
+
+ /*
+ * Intitialize 802.11g
+ * Rates: CCK, OFDM.
+ * Channels: OFDM.
+ */
+ if (spec->num_modes > HWMODE_G) {
+ hwmodes[HWMODE_G].mode = MODE_IEEE80211G;
+ hwmodes[HWMODE_G].num_channels = 14;
+ hwmodes[HWMODE_G].num_rates = spec->num_rates;
+ hwmodes[HWMODE_G].channels = channels;
+ hwmodes[HWMODE_G].rates = rates;
+ }
+
+ /*
+ * Intitialize 802.11a
+ * Rates: OFDM.
+ * Channels: OFDM, UNII, HiperLAN2.
+ */
+ if (spec->num_modes > HWMODE_A) {
+ hwmodes[HWMODE_A].mode = MODE_IEEE80211A;
+ hwmodes[HWMODE_A].num_channels = spec->num_channels - 14;
+ hwmodes[HWMODE_A].num_rates = spec->num_rates - 4;
+ hwmodes[HWMODE_A].channels = &channels[14];
+ hwmodes[HWMODE_A].rates = &rates[4];
+ }
+
+ if (spec->num_modes > HWMODE_G &&
+ ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G]))
+ goto exit_free_rates;
+
+ if (spec->num_modes > HWMODE_B &&
+ ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B]))
+ goto exit_free_rates;
+
+ if (spec->num_modes > HWMODE_A &&
+ ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A]))
+ goto exit_free_rates;
+
+ rt2x00dev->hwmodes = hwmodes;
+
+ return 0;
+
+exit_free_rates:
+ kfree(rates);
+
+exit_free_channels:
+ kfree(channels);
+
+exit_free_modes:
+ kfree(hwmodes);
+
+exit:
+ ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n");
+ return -ENOMEM;
+}
+
+static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
+{
+ if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
+ ieee80211_unregister_hw(rt2x00dev->hw);
+
+ if (likely(rt2x00dev->hwmodes)) {
+ kfree(rt2x00dev->hwmodes->channels);
+ kfree(rt2x00dev->hwmodes->rates);
+ kfree(rt2x00dev->hwmodes);
+ rt2x00dev->hwmodes = NULL;
+ }
+}
+
+static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ int status;
+
+ /*
+ * Initialize HW modes.
+ */
+ status = rt2x00lib_probe_hw_modes(rt2x00dev, spec);
+ if (status)
+ return status;
+
+ /*
+ * Register HW.
+ */
+ status = ieee80211_register_hw(rt2x00dev->hw);
+ if (status) {
+ rt2x00lib_remove_hw(rt2x00dev);
+ return status;
+ }
+
+ __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags);
+
+ return 0;
+}
+
+/*
+ * Initialization/uninitialization handlers.
+ */
+static int rt2x00lib_alloc_entries(struct data_ring *ring,
+ const u16 max_entries, const u16 data_size,
+ const u16 desc_size)
+{
+ struct data_entry *entry;
+ unsigned int i;
+
+ ring->stats.limit = max_entries;
+ ring->data_size = data_size;
+ ring->desc_size = desc_size;
+
+ /*
+ * Allocate all ring entries.
+ */
+ entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ entry[i].flags = 0;
+ entry[i].ring = ring;
+ entry[i].skb = NULL;
+ }
+
+ ring->entry = entry;
+
+ return 0;
+}
+
+static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ /*
+ * Allocate the RX ring.
+ */
+ if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE,
+ rt2x00dev->ops->rxd_size))
+ return -ENOMEM;
+
+ /*
+ * First allocate the TX rings.
+ */
+ txring_for_each(rt2x00dev, ring) {
+ if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE,
+ rt2x00dev->ops->txd_size))
+ return -ENOMEM;
+ }
+
+ if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Allocate the BEACON ring.
+ */
+ if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES,
+ MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size))
+ return -ENOMEM;
+
+ /*
+ * Allocate the Atim ring.
+ */
+ if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES,
+ DATA_FRAME_SIZE, rt2x00dev->ops->txd_size))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ ring_for_each(rt2x00dev, ring) {
+ kfree(ring->entry);
+ ring->entry = NULL;
+ }
+}
+
+void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Unregister rfkill.
+ */
+ rt2x00rfkill_unregister(rt2x00dev);
+
+ /*
+ * Allow the HW to uninitialize.
+ */
+ rt2x00dev->ops->lib->uninitialize(rt2x00dev);
+
+ /*
+ * Free allocated ring entries.
+ */
+ rt2x00lib_free_ring_entries(rt2x00dev);
+}
+
+int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ int status;
+
+ if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Allocate all ring entries.
+ */
+ status = rt2x00lib_alloc_ring_entries(rt2x00dev);
+ if (status) {
+ ERROR(rt2x00dev, "Ring entries allocation failed.\n");
+ return status;
+ }
+
+ /*
+ * Initialize the device.
+ */
+ status = rt2x00dev->ops->lib->initialize(rt2x00dev);
+ if (status)
+ goto exit;
+
+ __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
+
+ /*
+ * Register the rfkill handler.
+ */
+ status = rt2x00rfkill_register(rt2x00dev);
+ if (status)
+ goto exit_unitialize;
+
+ return 0;
+
+exit_unitialize:
+ rt2x00lib_uninitialize(rt2x00dev);
+
+exit:
+ rt2x00lib_free_ring_entries(rt2x00dev);
+
+ return status;
+}
+
+/*
+ * driver allocation handlers.
+ */
+static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ /*
+ * We need the following rings:
+ * RX: 1
+ * TX: hw->queues
+ * Beacon: 1 (if required)
+ * Atim: 1 (if required)
+ */
+ rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues +
+ (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags));
+
+ ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL);
+ if (!ring) {
+ ERROR(rt2x00dev, "Ring allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Initialize pointers
+ */
+ rt2x00dev->rx = ring;
+ rt2x00dev->tx = &rt2x00dev->rx[1];
+ if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
+ rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues];
+
+ /*
+ * Initialize ring parameters.
+ * cw_min: 2^5 = 32.
+ * cw_max: 2^10 = 1024.
+ */
+ ring_for_each(rt2x00dev, ring) {
+ ring->rt2x00dev = rt2x00dev;
+ ring->tx_params.aifs = 2;
+ ring->tx_params.cw_min = 5;
+ ring->tx_params.cw_max = 10;
+ }
+
+ return 0;
+}
+
+static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rx);
+ rt2x00dev->rx = NULL;
+ rt2x00dev->tx = NULL;
+ rt2x00dev->bcn = NULL;
+}
+
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
+{
+ int retval = -ENOMEM;
+
+ /*
+ * Let the driver probe the device to detect the capabilities.
+ */
+ retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to allocate device.\n");
+ goto exit;
+ }
+
+ /*
+ * Initialize configuration work.
+ */
+ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled);
+ INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
+ INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled);
+ INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
+
+ /*
+ * Reset current working type.
+ */
+ rt2x00dev->interface.type = INVALID_INTERFACE;
+
+ /*
+ * Allocate ring array.
+ */
+ retval = rt2x00lib_alloc_rings(rt2x00dev);
+ if (retval)
+ goto exit;
+
+ /*
+ * Initialize ieee80211 structure.
+ */
+ retval = rt2x00lib_probe_hw(rt2x00dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to initialize hw.\n");
+ goto exit;
+ }
+
+ /*
+ * Allocatie rfkill.
+ */
+ retval = rt2x00rfkill_allocate(rt2x00dev);
+ if (retval)
+ goto exit;
+
+ /*
+ * Open the debugfs entry.
+ */
+ rt2x00debug_register(rt2x00dev);
+
+ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ return 0;
+
+exit:
+ rt2x00lib_remove_dev(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
+
+void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
+{
+ __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Disable radio.
+ */
+ rt2x00lib_disable_radio(rt2x00dev);
+
+ /*
+ * Uninitialize device.
+ */
+ rt2x00lib_uninitialize(rt2x00dev);
+
+ /*
+ * Close debugfs entry.
+ */
+ rt2x00debug_deregister(rt2x00dev);
+
+ /*
+ * Free rfkill
+ */
+ rt2x00rfkill_free(rt2x00dev);
+
+ /*
+ * Free ieee80211_hw memory.
+ */
+ rt2x00lib_remove_hw(rt2x00dev);
+
+ /*
+ * Free firmware image.
+ */
+ rt2x00lib_free_firmware(rt2x00dev);
+
+ /*
+ * Free ring structures.
+ */
+ rt2x00lib_free_rings(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
+
+/*
+ * Device state handlers
+ */
+#ifdef CONFIG_PM
+int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
+{
+ int retval;
+
+ NOTICE(rt2x00dev, "Going to sleep.\n");
+ __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Only continue if mac80211 has open interfaces.
+ */
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ goto exit;
+ __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags);
+
+ /*
+ * Disable radio and unitialize all items
+ * that must be recreated on resume.
+ */
+ rt2x00mac_stop(rt2x00dev->hw);
+ rt2x00lib_uninitialize(rt2x00dev);
+ rt2x00debug_deregister(rt2x00dev);
+
+exit:
+ /*
+ * Set device mode to sleep for power management.
+ */
+ retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
+
+int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
+{
+ struct interface *intf = &rt2x00dev->interface;
+ int retval;
+
+ NOTICE(rt2x00dev, "Waking up.\n");
+ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Open the debugfs entry.
+ */
+ rt2x00debug_register(rt2x00dev);
+
+ /*
+ * Only continue if mac80211 had open interfaces.
+ */
+ if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Reinitialize device and all active interfaces.
+ */
+ retval = rt2x00mac_start(rt2x00dev->hw);
+ if (retval)
+ goto exit;
+
+ /*
+ * Reconfigure device.
+ */
+ rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1);
+ if (!rt2x00dev->hw->conf.radio_enabled)
+ rt2x00lib_disable_radio(rt2x00dev);
+
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+ rt2x00lib_config_type(rt2x00dev, intf->type);
+
+ /*
+ * It is possible that during that mac80211 has attempted
+ * to send frames while we were suspending or resuming.
+ * In that case we have disabled the TX queue and should
+ * now enable it again
+ */
+ ieee80211_start_queues(rt2x00dev->hw);
+
+ /*
+ * When in Master or Ad-hoc mode,
+ * restart Beacon transmitting by faking a beacondone event.
+ */
+ if (intf->type == IEEE80211_IF_TYPE_AP ||
+ intf->type == IEEE80211_IF_TYPE_IBSS)
+ rt2x00lib_beacondone(rt2x00dev);
+
+ return 0;
+
+exit:
+ rt2x00lib_disable_radio(rt2x00dev);
+ rt2x00lib_uninitialize(rt2x00dev);
+ rt2x00debug_deregister(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00lib module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
new file mode 100644
index 000000000000..236025f8b90f
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 firmware loading routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/crc-itu-t.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+ const struct firmware *fw;
+ char *fw_name;
+ int retval;
+ u16 crc;
+ u16 tmp;
+
+ /*
+ * Read correct firmware from harddisk.
+ */
+ fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
+ if (!fw_name) {
+ ERROR(rt2x00dev,
+ "Invalid firmware filename.\n"
+ "Please file bug report to %s.\n", DRV_PROJECT);
+ return -EINVAL;
+ }
+
+ INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name);
+
+ retval = request_firmware(&fw, fw_name, device);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to request Firmware.\n");
+ return retval;
+ }
+
+ if (!fw || !fw->size || !fw->data) {
+ ERROR(rt2x00dev, "Failed to read Firmware.\n");
+ return -ENOENT;
+ }
+
+ /*
+ * Validate the firmware using 16 bit CRC.
+ * The last 2 bytes of the firmware are the CRC
+ * so substract those 2 bytes from the CRC checksum,
+ * and set those 2 bytes to 0 when calculating CRC.
+ */
+ tmp = 0;
+ crc = crc_itu_t(0, fw->data, fw->size - 2);
+ crc = crc_itu_t(crc, (u8 *)&tmp, 2);
+
+ if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) {
+ ERROR(rt2x00dev, "Firmware CRC error.\n");
+ retval = -ENOENT;
+ goto exit;
+ }
+
+ INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
+ fw->data[fw->size - 4], fw->data[fw->size - 3]);
+
+ rt2x00dev->fw = fw;
+
+ return 0;
+
+exit:
+ release_firmware(fw);
+
+ return retval;
+}
+
+int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ if (!rt2x00dev->fw) {
+ retval = rt2x00lib_request_firmware(rt2x00dev);
+ if (retval)
+ return retval;
+ }
+
+ /*
+ * Send firmware to the device.
+ */
+ retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
+ rt2x00dev->fw->data,
+ rt2x00dev->fw->size);
+ return retval;
+}
+
+void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ release_firmware(rt2x00dev->fw);
+ rt2x00dev->fw = NULL;
+}
+
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
new file mode 100644
index 000000000000..298faa9d3f61
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: Data structures and definitions for the rt2x00lib module.
+ */
+
+#ifndef RT2X00LIB_H
+#define RT2X00LIB_H
+
+/*
+ * Interval defines
+ * Both the link tuner as the rfkill will be called once per second.
+ */
+#define LINK_TUNE_INTERVAL ( round_jiffies(HZ) )
+#define RFKILL_POLL_INTERVAL ( 1000 )
+
+/*
+ * Radio control handlers.
+ */
+int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state);
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Initialization handlers.
+ */
+int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Configuration handlers.
+ */
+void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
+void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
+void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type);
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf, const int force_config);
+
+/*
+ * Firmware handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_FIRMWARE
+int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_FIRMWARE */
+
+/*
+ * Debugfs handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
+#else
+static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * RFkill handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_RFKILL
+int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
+int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
+void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+
+static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+
+static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
+
+#endif /* RT2X00LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
new file mode 100644
index 000000000000..4a6a0bd01ff1
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -0,0 +1,438 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00mac
+ Abstract: rt2x00 generic mac80211 routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
+{
+ struct sk_buff *skb;
+ int size;
+
+ if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ size = sizeof(struct ieee80211_cts);
+ else
+ size = sizeof(struct ieee80211_rts);
+
+ skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom);
+ if (!skb) {
+ WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
+ skb_put(skb, size);
+
+ if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_cts *)(skb->data));
+ else
+ ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));
+
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+ WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ return NETDEV_TX_OK;
+}
+
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ struct data_ring *ring;
+ u16 frame_control;
+
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ * Note that we can only stop the TX queues inside the TX path
+ * due to possible race conditions in mac80211.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
+ ieee80211_stop_queues(hw);
+ return 0;
+ }
+
+ /*
+ * Determine which ring to put packet on.
+ */
+ ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+ if (unlikely(!ring)) {
+ ERROR(rt2x00dev,
+ "Attempt to send packet over invalid queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ /*
+ * If CTS/RTS is required. and this frame is not CTS or RTS,
+ * create and queue that frame first. But make sure we have
+ * at least enough entries available to send this CTS/RTS
+ * frame as well as the data frame.
+ */
+ frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+ if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
+ (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT))) {
+ if (rt2x00_ring_free(ring) <= 1)
+ return NETDEV_TX_BUSY;
+
+ if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
+ return NETDEV_TX_BUSY;
+ }
+
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control))
+ return NETDEV_TX_BUSY;
+
+ if (rt2x00dev->ops->lib->kick_tx_queue)
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+ return NETDEV_TX_OK;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_tx);
+
+int rt2x00mac_start(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int status;
+
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * If this is the first interface which is added,
+ * we should load the firmware now.
+ */
+ if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+ status = rt2x00lib_load_firmware(rt2x00dev);
+ if (status)
+ return status;
+ }
+
+ /*
+ * Initialize the device.
+ */
+ status = rt2x00lib_initialize(rt2x00dev);
+ if (status)
+ return status;
+
+ /*
+ * Enable radio.
+ */
+ status = rt2x00lib_enable_radio(rt2x00dev);
+ if (status) {
+ rt2x00lib_uninitialize(rt2x00dev);
+ return status;
+ }
+
+ __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_start);
+
+void rt2x00mac_stop(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Perhaps we can add something smarter here,
+ * but for now just disabling the radio should do.
+ */
+ rt2x00lib_disable_radio(rt2x00dev);
+
+ __clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_stop);
+
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+
+ /*
+ * Don't allow interfaces to be added while
+ * either the device has disappeared or when
+ * another interface is already present.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ is_interface_present(intf))
+ return -ENOBUFS;
+
+ intf->id = conf->if_id;
+ intf->type = conf->type;
+ if (conf->type == IEEE80211_IF_TYPE_AP)
+ memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
+ memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
+
+ /*
+ * The MAC adddress must be configured after the device
+ * has been initialized. Otherwise the device can reset
+ * the MAC registers.
+ */
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_type(rt2x00dev, conf->type);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
+
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+
+ /*
+ * Don't allow interfaces to be remove while
+ * either the device has disappeared or when
+ * no interface is present.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ !is_interface_present(intf))
+ return;
+
+ intf->id = 0;
+ intf->type = INVALID_INTERFACE;
+ memset(&intf->bssid, 0x00, ETH_ALEN);
+ memset(&intf->mac, 0x00, ETH_ALEN);
+
+ /*
+ * Make sure the bssid and mac address registers
+ * are cleared to prevent false ACKing of frames.
+ */
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+ rt2x00lib_config_type(rt2x00dev, intf->type);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
+
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Check if we need to disable the radio,
+ * if this is not the case, at least the RX must be disabled.
+ */
+ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
+ if (!conf->radio_enabled)
+ rt2x00lib_disable_radio(rt2x00dev);
+ else
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ }
+
+ rt2x00lib_config(rt2x00dev, conf, 0);
+
+ /*
+ * Reenable RX only if the radio should be on.
+ */
+ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ else if (conf->radio_enabled)
+ return rt2x00lib_enable_radio(rt2x00dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_config);
+
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ int status;
+
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * If the given type does not match the configured type,
+ * there has been a problem.
+ */
+ if (conf->type != intf->type)
+ return -EINVAL;
+
+ /*
+ * If the interface does not work in master mode,
+ * then the bssid value in the interface structure
+ * should now be set.
+ */
+ if (conf->type != IEEE80211_IF_TYPE_AP)
+ memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+
+ /*
+ * We only need to initialize the beacon when master mode is enabled.
+ */
+ if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
+ return 0;
+
+ status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
+ conf->beacon,
+ conf->beacon_control);
+ if (status)
+ dev_kfree_skb(conf->beacon);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
+
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * The dot11ACKFailureCount, dot11RTSFailureCount and
+ * dot11RTSSuccessCount are updated in interrupt time.
+ * dot11FCSErrorCount is updated in the link tuner.
+ */
+ memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
+
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ unsigned int i;
+
+ for (i = 0; i < hw->queues; i++)
+ memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
+ sizeof(rt2x00dev->tx[i].stats));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
+
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+ int cts_protection, int preamble)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int short_preamble;
+ int ack_timeout;
+ int ack_consume_time;
+ int difs;
+
+ /*
+ * We only support changing preamble mode.
+ */
+ if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE))
+ return;
+
+ short_preamble = !preamble;
+ preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE;
+
+ difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
+ SHORT_DIFS : DIFS;
+ ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+ ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+ if (short_preamble)
+ __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+ else
+ __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+ rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
+ ack_timeout, ack_consume_time);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed);
+
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_ring *ring;
+
+ ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ if (unlikely(!ring))
+ return -EINVAL;
+
+ /*
+ * The passed variables are stored as real value ((2^n)-1).
+ * Ralink registers require to know the bit number 'n'.
+ */
+ if (params->cw_min)
+ ring->tx_params.cw_min = fls(params->cw_min);
+ else
+ ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */
+
+ if (params->cw_max)
+ ring->tx_params.cw_max = fls(params->cw_max);
+ else
+ ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */
+
+ if (params->aifs)
+ ring->tx_params.aifs = params->aifs;
+ else
+ ring->tx_params.aifs = 2;
+
+ INFO(rt2x00dev,
+ "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
+ queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
+ ring->tx_params.aifs);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
new file mode 100644
index 000000000000..2780df00623c
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -0,0 +1,474 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00pci
+ Abstract: rt2x00 generic pci device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00pci"
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+
+/*
+ * Beacon handlers.
+ */
+int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_ring *ring =
+ rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+
+ /*
+ * Just in case mac80211 doesn't set this correctly,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * Update the beacon entry.
+ */
+ memcpy(entry->data_addr, skb->data, skb->len);
+ rt2x00lib_write_tx_desc(rt2x00dev, entry->priv,
+ (struct ieee80211_hdr *)skb->data,
+ skb->len, control);
+
+ /*
+ * Enable beacon generation.
+ */
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+ struct data_desc *txd = entry->priv;
+ u32 word;
+
+ if (rt2x00_ring_full(ring)) {
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
+ rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
+ ERROR(rt2x00dev,
+ "Arrived at non-free entry in the non-full queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ entry->skb = skb;
+ memcpy(&entry->tx_status.control, control, sizeof(*control));
+ memcpy(entry->data_addr, skb->data, skb->len);
+ rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr,
+ skb->len, control);
+
+ rt2x00_ring_index_inc(ring);
+
+ if (rt2x00_ring_full(ring))
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
+
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_entry *entry;
+ struct data_desc *rxd;
+ struct sk_buff *skb;
+ struct rxdata_entry_desc desc;
+ u32 word;
+
+ while (1) {
+ entry = rt2x00_get_data_entry(ring);
+ rxd = entry->priv;
+ rt2x00_desc_read(rxd, 0, &word);
+
+ if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+ break;
+
+ memset(&desc, 0x00, sizeof(desc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+ /*
+ * Allocate the sk_buffer, initialize it and copy
+ * all data into it.
+ */
+ skb = dev_alloc_skb(desc.size + NET_IP_ALIGN);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, desc.size);
+ memcpy(skb->data, entry->data_addr, desc.size);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, skb, &desc);
+
+ if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+ rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_inc(ring);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+
+/*
+ * Device initialization handlers.
+ */
+#define priv_offset(__ring, __i) \
+({ \
+ ring->data_addr + (i * ring->desc_size); \
+})
+
+#define data_addr_offset(__ring, __i) \
+({ \
+ (__ring)->data_addr + \
+ ((__ring)->stats.limit * (__ring)->desc_size) + \
+ ((__i) * (__ring)->data_size); \
+})
+
+#define data_dma_offset(__ring, __i) \
+({ \
+ (__ring)->data_dma + \
+ ((__ring)->stats.limit * (__ring)->desc_size) + \
+ ((__i) * (__ring)->data_size); \
+})
+
+static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ unsigned int i;
+
+ /*
+ * Allocate DMA memory for descriptor and buffer.
+ */
+ ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev),
+ rt2x00_get_ring_size(ring),
+ &ring->data_dma);
+ if (!ring->data_addr)
+ return -ENOMEM;
+
+ /*
+ * Initialize all ring entries to contain valid
+ * addresses.
+ */
+ for (i = 0; i < ring->stats.limit; i++) {
+ ring->entry[i].priv = priv_offset(ring, i);
+ ring->entry[i].data_addr = data_addr_offset(ring, i);
+ ring->entry[i].data_dma = data_dma_offset(ring, i);
+ }
+
+ return 0;
+}
+
+static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ if (ring->data_addr)
+ pci_free_consistent(rt2x00dev_pci(rt2x00dev),
+ rt2x00_get_ring_size(ring),
+ ring->data_addr, ring->data_dma);
+ ring->data_addr = NULL;
+}
+
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+ struct data_ring *ring;
+ int status;
+
+ /*
+ * Allocate DMA
+ */
+ ring_for_each(rt2x00dev, ring) {
+ status = rt2x00pci_alloc_dma(rt2x00dev, ring);
+ if (status)
+ goto exit;
+ }
+
+ /*
+ * Register interrupt handler.
+ */
+ status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler,
+ IRQF_SHARED, pci_name(pci_dev), rt2x00dev);
+ if (status) {
+ ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
+ pci_dev->irq, status);
+ return status;
+ }
+
+ return 0;
+
+exit:
+ rt2x00pci_uninitialize(rt2x00dev);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
+
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ /*
+ * Free irq line.
+ */
+ free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
+
+ /*
+ * Free DMA
+ */
+ ring_for_each(rt2x00dev, ring)
+ rt2x00pci_free_dma(rt2x00dev, ring);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
+
+/*
+ * PCI driver handlers.
+ */
+static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rf);
+ rt2x00dev->rf = NULL;
+
+ kfree(rt2x00dev->eeprom);
+ rt2x00dev->eeprom = NULL;
+
+ if (rt2x00dev->csr_addr) {
+ iounmap(rt2x00dev->csr_addr);
+ rt2x00dev->csr_addr = NULL;
+ }
+}
+
+static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+ struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+
+ rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+ if (!rt2x00dev->csr_addr)
+ goto exit;
+
+ rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+ if (!rt2x00dev->eeprom)
+ goto exit;
+
+ rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+ if (!rt2x00dev->rf)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR_PROBE("Failed to allocate registers.\n");
+
+ rt2x00pci_free_reg(rt2x00dev);
+
+ return -ENOMEM;
+}
+
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+{
+ struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
+ struct ieee80211_hw *hw;
+ struct rt2x00_dev *rt2x00dev;
+ int retval;
+
+ retval = pci_request_regions(pci_dev, pci_name(pci_dev));
+ if (retval) {
+ ERROR_PROBE("PCI request regions failed.\n");
+ return retval;
+ }
+
+ retval = pci_enable_device(pci_dev);
+ if (retval) {
+ ERROR_PROBE("Enable device failed.\n");
+ goto exit_release_regions;
+ }
+
+ pci_set_master(pci_dev);
+
+ if (pci_set_mwi(pci_dev))
+ ERROR_PROBE("MWI not available.\n");
+
+ if (pci_set_dma_mask(pci_dev, DMA_64BIT_MASK) &&
+ pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
+ ERROR_PROBE("PCI DMA not supported.\n");
+ retval = -EIO;
+ goto exit_disable_device;
+ }
+
+ hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ if (!hw) {
+ ERROR_PROBE("Failed to allocate hardware.\n");
+ retval = -ENOMEM;
+ goto exit_disable_device;
+ }
+
+ pci_set_drvdata(pci_dev, hw);
+
+ rt2x00dev = hw->priv;
+ rt2x00dev->dev = pci_dev;
+ rt2x00dev->ops = ops;
+ rt2x00dev->hw = hw;
+
+ retval = rt2x00pci_alloc_reg(rt2x00dev);
+ if (retval)
+ goto exit_free_device;
+
+ retval = rt2x00lib_probe_dev(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00pci_free_reg(rt2x00dev);
+
+exit_free_device:
+ ieee80211_free_hw(hw);
+
+exit_disable_device:
+ if (retval != -EBUSY)
+ pci_disable_device(pci_dev);
+
+exit_release_regions:
+ pci_release_regions(pci_dev);
+
+ pci_set_drvdata(pci_dev, NULL);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_probe);
+
+void rt2x00pci_remove(struct pci_dev *pci_dev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Free all allocated data.
+ */
+ rt2x00lib_remove_dev(rt2x00dev);
+ rt2x00pci_free_reg(rt2x00dev);
+ ieee80211_free_hw(hw);
+
+ /*
+ * Free the PCI device data.
+ */
+ pci_set_drvdata(pci_dev, NULL);
+ pci_disable_device(pci_dev);
+ pci_release_regions(pci_dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_remove);
+
+#ifdef CONFIG_PM
+int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ retval = rt2x00lib_suspend(rt2x00dev, state);
+ if (retval)
+ return retval;
+
+ rt2x00pci_free_reg(rt2x00dev);
+
+ pci_save_state(pci_dev);
+ pci_disable_device(pci_dev);
+ return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_suspend);
+
+int rt2x00pci_resume(struct pci_dev *pci_dev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ if (pci_set_power_state(pci_dev, PCI_D0) ||
+ pci_enable_device(pci_dev) ||
+ pci_restore_state(pci_dev)) {
+ ERROR(rt2x00dev, "Failed to resume device.\n");
+ return -EIO;
+ }
+
+ retval = rt2x00pci_alloc_reg(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2x00lib_resume(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00pci_free_reg(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00pci module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
new file mode 100644
index 000000000000..82adeac061d0
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -0,0 +1,127 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00pci
+ Abstract: Data structures for the rt2x00pci module.
+ */
+
+#ifndef RT2X00PCI_H
+#define RT2X00PCI_H
+
+#include <linux/io.h>
+
+/*
+ * This variable should be used with the
+ * pci_driver structure initialization.
+ */
+#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
+
+/*
+ * Register defines.
+ * Some registers require multiple attempts before success,
+ * in those cases REGISTER_BUSY_COUNT attempts should be
+ * taken with a REGISTER_BUSY_DELAY interval.
+ */
+#define REGISTER_BUSY_COUNT 5
+#define REGISTER_BUSY_DELAY 100
+
+/*
+ * Descriptor availability flags.
+ * All PCI device descriptors have these 2 flags
+ * with the exact same definition.
+ * By storing them here we can use them inside rt2x00pci
+ * for some simple entry availability checking.
+ */
+#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001)
+#define TXD_ENTRY_VALID FIELD32(0x00000002)
+#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001)
+
+/*
+ * Register access.
+ */
+static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ u32 *value)
+{
+ *value = readl(rt2x00dev->csr_addr + offset);
+}
+
+static inline void
+rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ void *value, const u16 length)
+{
+ memcpy_fromio(value, rt2x00dev->csr_addr + offset, length);
+}
+
+static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ u32 value)
+{
+ writel(value, rt2x00dev->csr_addr + offset);
+}
+
+static inline void
+rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ void *value, const u16 length)
+{
+ memcpy_toio(rt2x00dev->csr_addr + offset, value, length);
+}
+
+/*
+ * Beacon handlers.
+ */
+int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * PCI driver handlers.
+ */
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
+void rt2x00pci_remove(struct pci_dev *pci_dev);
+#ifdef CONFIG_PM
+int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state);
+int rt2x00pci_resume(struct pci_dev *pci_dev);
+#else
+#define rt2x00pci_suspend NULL
+#define rt2x00pci_resume NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
new file mode 100644
index 000000000000..838421216da0
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -0,0 +1,292 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 generic register information.
+ */
+
+#ifndef RT2X00REG_H
+#define RT2X00REG_H
+
+/*
+ * TX result flags.
+ */
+enum TX_STATUS {
+ TX_SUCCESS = 0,
+ TX_SUCCESS_RETRY = 1,
+ TX_FAIL_RETRY = 2,
+ TX_FAIL_INVALID = 3,
+ TX_FAIL_OTHER = 4,
+};
+
+/*
+ * Antenna values
+ */
+enum antenna {
+ ANTENNA_SW_DIVERSITY = 0,
+ ANTENNA_A = 1,
+ ANTENNA_B = 2,
+ ANTENNA_HW_DIVERSITY = 3,
+};
+
+/*
+ * Led mode values.
+ */
+enum led_mode {
+ LED_MODE_DEFAULT = 0,
+ LED_MODE_TXRX_ACTIVITY = 1,
+ LED_MODE_SIGNAL_STRENGTH = 2,
+ LED_MODE_ASUS = 3,
+ LED_MODE_ALPHA = 4,
+};
+
+/*
+ * TSF sync values
+ */
+enum tsf_sync {
+ TSF_SYNC_NONE = 0,
+ TSF_SYNC_INFRA = 1,
+ TSF_SYNC_BEACON = 2,
+};
+
+/*
+ * Device states
+ */
+enum dev_state {
+ STATE_DEEP_SLEEP = 0,
+ STATE_SLEEP = 1,
+ STATE_STANDBY = 2,
+ STATE_AWAKE = 3,
+
+/*
+ * Additional device states, these values are
+ * not strict since they are not directly passed
+ * into the device.
+ */
+ STATE_RADIO_ON,
+ STATE_RADIO_OFF,
+ STATE_RADIO_RX_ON,
+ STATE_RADIO_RX_OFF,
+ STATE_RADIO_IRQ_ON,
+ STATE_RADIO_IRQ_OFF,
+};
+
+/*
+ * IFS backoff values
+ */
+enum ifs {
+ IFS_BACKOFF = 0,
+ IFS_SIFS = 1,
+ IFS_NEW_BACKOFF = 2,
+ IFS_NONE = 3,
+};
+
+/*
+ * Cipher types for hardware encryption
+ */
+enum cipher {
+ CIPHER_NONE = 0,
+ CIPHER_WEP64 = 1,
+ CIPHER_WEP128 = 2,
+ CIPHER_TKIP = 3,
+ CIPHER_AES = 4,
+/*
+ * The following fields were added by rt61pci and rt73usb.
+ */
+ CIPHER_CKIP64 = 5,
+ CIPHER_CKIP128 = 6,
+ CIPHER_TKIP_NO_MIC = 7,
+};
+
+/*
+ * Register handlers.
+ * We store the position of a register field inside a field structure,
+ * This will simplify the process of setting and reading a certain field
+ * inside the register while making sure the process remains byte order safe.
+ */
+struct rt2x00_field8 {
+ u8 bit_offset;
+ u8 bit_mask;
+};
+
+struct rt2x00_field16 {
+ u16 bit_offset;
+ u16 bit_mask;
+};
+
+struct rt2x00_field32 {
+ u32 bit_offset;
+ u32 bit_mask;
+};
+
+/*
+ * Power of two check, this will check
+ * if the mask that has been given contains
+ * and contiguous set of bits.
+ */
+#define is_power_of_two(x) ( !((x) & ((x)-1)) )
+#define low_bit_mask(x) ( ((x)-1) & ~(x) )
+#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x))
+
+#define FIELD8(__mask) \
+({ \
+ BUILD_BUG_ON(!(__mask) || \
+ !is_valid_mask(__mask) || \
+ (__mask) != (u8)(__mask)); \
+ (struct rt2x00_field8) { \
+ __ffs(__mask), (__mask) \
+ }; \
+})
+
+#define FIELD16(__mask) \
+({ \
+ BUILD_BUG_ON(!(__mask) || \
+ !is_valid_mask(__mask) || \
+ (__mask) != (u16)(__mask));\
+ (struct rt2x00_field16) { \
+ __ffs(__mask), (__mask) \
+ }; \
+})
+
+#define FIELD32(__mask) \
+({ \
+ BUILD_BUG_ON(!(__mask) || \
+ !is_valid_mask(__mask) || \
+ (__mask) != (u32)(__mask));\
+ (struct rt2x00_field32) { \
+ __ffs(__mask), (__mask) \
+ }; \
+})
+
+static inline void rt2x00_set_field32(u32 *reg,
+ const struct rt2x00_field32 field,
+ const u32 value)
+{
+ *reg &= ~(field.bit_mask);
+ *reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u32 rt2x00_get_field32(const u32 reg,
+ const struct rt2x00_field32 field)
+{
+ return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+static inline void rt2x00_set_field16(u16 *reg,
+ const struct rt2x00_field16 field,
+ const u16 value)
+{
+ *reg &= ~(field.bit_mask);
+ *reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u16 rt2x00_get_field16(const u16 reg,
+ const struct rt2x00_field16 field)
+{
+ return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+static inline void rt2x00_set_field8(u8 *reg,
+ const struct rt2x00_field8 field,
+ const u8 value)
+{
+ *reg &= ~(field.bit_mask);
+ *reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u8 rt2x00_get_field8(const u8 reg,
+ const struct rt2x00_field8 field)
+{
+ return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+/*
+ * Device specific rate value.
+ * We will have to create the device specific rate value
+ * passed to the ieee80211 kernel. We need to make it a consist of
+ * multiple fields because we want to store more then 1 device specific
+ * values inside the value.
+ * 1 - rate, stored as 100 kbit/s.
+ * 2 - preamble, short_preamble enabled flag.
+ * 3 - MASK_RATE, which rates are enabled in this mode, this mask
+ * corresponds with the TX register format for the current device.
+ * 4 - plcp, 802.11b rates are device specific,
+ * 802.11g rates are set according to the ieee802.11a-1999 p.14.
+ * The bit to enable preamble is set in a seperate define.
+ */
+#define DEV_RATE FIELD32(0x000007ff)
+#define DEV_PREAMBLE FIELD32(0x00000800)
+#define DEV_RATEMASK FIELD32(0x00fff000)
+#define DEV_PLCP FIELD32(0xff000000)
+
+/*
+ * Bitfields
+ */
+#define DEV_RATEBIT_1MB ( 1 << 0 )
+#define DEV_RATEBIT_2MB ( 1 << 1 )
+#define DEV_RATEBIT_5_5MB ( 1 << 2 )
+#define DEV_RATEBIT_11MB ( 1 << 3 )
+#define DEV_RATEBIT_6MB ( 1 << 4 )
+#define DEV_RATEBIT_9MB ( 1 << 5 )
+#define DEV_RATEBIT_12MB ( 1 << 6 )
+#define DEV_RATEBIT_18MB ( 1 << 7 )
+#define DEV_RATEBIT_24MB ( 1 << 8 )
+#define DEV_RATEBIT_36MB ( 1 << 9 )
+#define DEV_RATEBIT_48MB ( 1 << 10 )
+#define DEV_RATEBIT_54MB ( 1 << 11 )
+
+/*
+ * Bitmasks for DEV_RATEMASK
+ */
+#define DEV_RATEMASK_1MB ( (DEV_RATEBIT_1MB << 1) -1 )
+#define DEV_RATEMASK_2MB ( (DEV_RATEBIT_2MB << 1) -1 )
+#define DEV_RATEMASK_5_5MB ( (DEV_RATEBIT_5_5MB << 1) -1 )
+#define DEV_RATEMASK_11MB ( (DEV_RATEBIT_11MB << 1) -1 )
+#define DEV_RATEMASK_6MB ( (DEV_RATEBIT_6MB << 1) -1 )
+#define DEV_RATEMASK_9MB ( (DEV_RATEBIT_9MB << 1) -1 )
+#define DEV_RATEMASK_12MB ( (DEV_RATEBIT_12MB << 1) -1 )
+#define DEV_RATEMASK_18MB ( (DEV_RATEBIT_18MB << 1) -1 )
+#define DEV_RATEMASK_24MB ( (DEV_RATEBIT_24MB << 1) -1 )
+#define DEV_RATEMASK_36MB ( (DEV_RATEBIT_36MB << 1) -1 )
+#define DEV_RATEMASK_48MB ( (DEV_RATEBIT_48MB << 1) -1 )
+#define DEV_RATEMASK_54MB ( (DEV_RATEBIT_54MB << 1) -1 )
+
+/*
+ * Bitmask groups of bitrates
+ */
+#define DEV_BASIC_RATEMASK \
+ ( DEV_RATEMASK_11MB | \
+ DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB )
+
+#define DEV_CCK_RATEMASK ( DEV_RATEMASK_11MB )
+#define DEV_OFDM_RATEMASK ( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK )
+
+/*
+ * Macro's to set and get specific fields from the device specific val and val2
+ * fields inside the ieee80211_rate entry.
+ */
+#define DEVICE_SET_RATE_FIELD(__value, __mask) \
+ (int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask )
+
+#define DEVICE_GET_RATE_FIELD(__value, __mask) \
+ (int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset )
+
+#endif /* RT2X00REG_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
new file mode 100644
index 000000000000..a0f8b8e0a24b
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
@@ -0,0 +1,146 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00rfkill
+ Abstract: rt2x00 rfkill routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rfkill.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
+{
+ struct rt2x00_dev *rt2x00dev = data;
+ int retval = 0;
+
+ if (unlikely(!rt2x00dev))
+ return 0;
+
+ /*
+ * Only continue if there are enabled interfaces.
+ */
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return 0;
+
+ if (state == RFKILL_STATE_ON) {
+ INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
+ __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+ retval = rt2x00lib_enable_radio(rt2x00dev);
+ } else if (state == RFKILL_STATE_OFF) {
+ INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
+ __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+ rt2x00lib_disable_radio(rt2x00dev);
+ }
+
+ return retval;
+}
+
+static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
+{
+ struct rt2x00_dev *rt2x00dev = poll_dev->private;
+ int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+ if (rt2x00dev->rfkill->state != state)
+ input_report_key(poll_dev->input, KEY_WLAN, 1);
+}
+
+int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return 0;
+
+ retval = rfkill_register(rt2x00dev->rfkill);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to register rfkill handler.\n");
+ return retval;
+ }
+
+ retval = input_register_polled_device(rt2x00dev->poll_dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to register polled device.\n");
+ rfkill_unregister(rt2x00dev->rfkill);
+ return retval;
+ }
+
+ return 0;
+}
+
+void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return;
+
+ input_unregister_polled_device(rt2x00dev->poll_dev);
+ rfkill_unregister(rt2x00dev->rfkill);
+}
+
+int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
+{
+ struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return 0;
+
+ rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
+ if (!rt2x00dev->rfkill) {
+ ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
+ return -ENOMEM;
+ }
+
+ rt2x00dev->rfkill->name = rt2x00dev->ops->name;
+ rt2x00dev->rfkill->data = rt2x00dev;
+ rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+ rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
+
+ rt2x00dev->poll_dev = input_allocate_polled_device();
+ if (!rt2x00dev->poll_dev) {
+ ERROR(rt2x00dev, "Failed to allocate polled device.\n");
+ rfkill_free(rt2x00dev->rfkill);
+ return -ENOMEM;
+ }
+
+ rt2x00dev->poll_dev->private = rt2x00dev;
+ rt2x00dev->poll_dev->poll = rt2x00rfkill_poll;
+ rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
+
+ return 0;
+}
+
+void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return;
+
+ input_free_polled_device(rt2x00dev->poll_dev);
+ rfkill_free(rt2x00dev->rfkill);
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h
new file mode 100644
index 000000000000..1a864d32cfbd
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00ring.h
@@ -0,0 +1,268 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 ring datastructures and routines
+ */
+
+#ifndef RT2X00RING_H
+#define RT2X00RING_H
+
+/*
+ * data_desc
+ * Each data entry also contains a descriptor which is used by the
+ * device to determine what should be done with the packet and
+ * what the current status is.
+ * This structure is greatly simplified, but the descriptors
+ * are basically a list of little endian 32 bit values.
+ * Make the array by default 1 word big, this will allow us
+ * to use sizeof() correctly.
+ */
+struct data_desc {
+ __le32 word[1];
+};
+
+/*
+ * rxdata_entry_desc
+ * Summary of information that has been read from the
+ * RX frame descriptor.
+ */
+struct rxdata_entry_desc {
+ int signal;
+ int rssi;
+ int ofdm;
+ int size;
+ int flags;
+};
+
+/*
+ * txdata_entry_desc
+ * Summary of information that should be written into the
+ * descriptor for sending a TX frame.
+ */
+struct txdata_entry_desc {
+ unsigned long flags;
+#define ENTRY_TXDONE 1
+#define ENTRY_TXD_RTS_FRAME 2
+#define ENTRY_TXD_OFDM_RATE 3
+#define ENTRY_TXD_MORE_FRAG 4
+#define ENTRY_TXD_REQ_TIMESTAMP 5
+#define ENTRY_TXD_BURST 6
+
+/*
+ * Queue ID. ID's 0-4 are data TX rings
+ */
+ int queue;
+#define QUEUE_MGMT 13
+#define QUEUE_RX 14
+#define QUEUE_OTHER 15
+
+ /*
+ * PLCP values.
+ */
+ u16 length_high;
+ u16 length_low;
+ u16 signal;
+ u16 service;
+
+ /*
+ * Timing information
+ */
+ int aifs;
+ int ifs;
+ int cw_min;
+ int cw_max;
+};
+
+/*
+ * data_entry
+ * The data ring is a list of data entries.
+ * Each entry holds a reference to the descriptor
+ * and the data buffer. For TX rings the reference to the
+ * sk_buff of the packet being transmitted is also stored here.
+ */
+struct data_entry {
+ /*
+ * Status flags
+ */
+ unsigned long flags;
+#define ENTRY_OWNER_NIC 1
+
+ /*
+ * Ring we belong to.
+ */
+ struct data_ring *ring;
+
+ /*
+ * sk_buff for the packet which is being transmitted
+ * in this entry (Only used with TX related rings).
+ */
+ struct sk_buff *skb;
+
+ /*
+ * Store a ieee80211_tx_status structure in each
+ * ring entry, this will optimize the txdone
+ * handler.
+ */
+ struct ieee80211_tx_status tx_status;
+
+ /*
+ * private pointer specific to driver.
+ */
+ void *priv;
+
+ /*
+ * Data address for this entry.
+ */
+ void *data_addr;
+ dma_addr_t data_dma;
+};
+
+/*
+ * data_ring
+ * Data rings are used by the device to send and receive packets.
+ * The data_addr is the base address of the data memory.
+ * To determine at which point in the ring we are,
+ * have to use the rt2x00_ring_index_*() functions.
+ */
+struct data_ring {
+ /*
+ * Pointer to main rt2x00dev structure where this
+ * ring belongs to.
+ */
+ struct rt2x00_dev *rt2x00dev;
+
+ /*
+ * Base address for the device specific data entries.
+ */
+ struct data_entry *entry;
+
+ /*
+ * TX queue statistic info.
+ */
+ struct ieee80211_tx_queue_stats_data stats;
+
+ /*
+ * TX Queue parameters.
+ */
+ struct ieee80211_tx_queue_params tx_params;
+
+ /*
+ * Base address for data ring.
+ */
+ dma_addr_t data_dma;
+ void *data_addr;
+
+ /*
+ * Index variables.
+ */
+ u16 index;
+ u16 index_done;
+
+ /*
+ * Size of packet and descriptor in bytes.
+ */
+ u16 data_size;
+ u16 desc_size;
+};
+
+/*
+ * Handlers to determine the address of the current device specific
+ * data entry, where either index or index_done points to.
+ */
+static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring)
+{
+ return &ring->entry[ring->index];
+}
+
+static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring
+ *ring)
+{
+ return &ring->entry[ring->index_done];
+}
+
+/*
+ * Total ring memory
+ */
+static inline int rt2x00_get_ring_size(struct data_ring *ring)
+{
+ return ring->stats.limit * (ring->desc_size + ring->data_size);
+}
+
+/*
+ * Ring index manipulation functions.
+ */
+static inline void rt2x00_ring_index_inc(struct data_ring *ring)
+{
+ ring->index++;
+ if (ring->index >= ring->stats.limit)
+ ring->index = 0;
+ ring->stats.len++;
+}
+
+static inline void rt2x00_ring_index_done_inc(struct data_ring *ring)
+{
+ ring->index_done++;
+ if (ring->index_done >= ring->stats.limit)
+ ring->index_done = 0;
+ ring->stats.len--;
+ ring->stats.count++;
+}
+
+static inline void rt2x00_ring_index_clear(struct data_ring *ring)
+{
+ ring->index = 0;
+ ring->index_done = 0;
+ ring->stats.len = 0;
+ ring->stats.count = 0;
+}
+
+static inline int rt2x00_ring_empty(struct data_ring *ring)
+{
+ return ring->stats.len == 0;
+}
+
+static inline int rt2x00_ring_full(struct data_ring *ring)
+{
+ return ring->stats.len == ring->stats.limit;
+}
+
+static inline int rt2x00_ring_free(struct data_ring *ring)
+{
+ return ring->stats.limit - ring->stats.len;
+}
+
+/*
+ * TX/RX Descriptor access functions.
+ */
+static inline void rt2x00_desc_read(struct data_desc *desc,
+ const u8 word, u32 *value)
+{
+ *value = le32_to_cpu(desc->word[word]);
+}
+
+static inline void rt2x00_desc_write(struct data_desc *desc,
+ const u8 word, const u32 value)
+{
+ desc->word[word] = cpu_to_le32(value);
+}
+
+#endif /* RT2X00RING_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
new file mode 100644
index 000000000000..73cc726c4046
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -0,0 +1,592 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00usb
+ Abstract: rt2x00 generic usb device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00usb"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+
+/*
+ * Interfacing with the HW.
+ */
+int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, const u16 value,
+ void *buffer, const u16 buffer_length,
+ const int timeout)
+{
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ int status;
+ unsigned int i;
+ unsigned int pipe =
+ (requesttype == USB_VENDOR_REQUEST_IN) ?
+ usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ status = usb_control_msg(usb_dev, pipe, request, requesttype,
+ value, offset, buffer, buffer_length,
+ timeout);
+ if (status >= 0)
+ return 0;
+
+ /*
+ * Check for errors
+ * -ENODEV: Device has disappeared, no point continuing.
+ * All other errors: Try again.
+ */
+ else if (status == -ENODEV)
+ break;
+ }
+
+ ERROR(rt2x00dev,
+ "Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n",
+ request, offset, status);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
+
+int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, void *buffer,
+ const u16 buffer_length, const int timeout)
+{
+ int status;
+
+ /*
+ * Check for Cache availability.
+ */
+ if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) {
+ ERROR(rt2x00dev, "CSR cache not available.\n");
+ return -ENOMEM;
+ }
+
+ if (requesttype == USB_VENDOR_REQUEST_OUT)
+ memcpy(rt2x00dev->csr_cache, buffer, buffer_length);
+
+ status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype,
+ offset, 0, rt2x00dev->csr_cache,
+ buffer_length, timeout);
+
+ if (!status && requesttype == USB_VENDOR_REQUEST_IN)
+ memcpy(buffer, rt2x00dev->csr_cache, buffer_length);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
+
+/*
+ * TX data handlers.
+ */
+static void rt2x00usb_interrupt_txdone(struct urb *urb)
+{
+ struct data_entry *entry = (struct data_entry *)urb->context;
+ struct data_ring *ring = entry->ring;
+ struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+ struct data_desc *txd = (struct data_desc *)entry->skb->data;
+ u32 word;
+ int tx_status;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+ return;
+
+ rt2x00_desc_read(txd, 0, &word);
+
+ /*
+ * Remove the descriptor data from the buffer.
+ */
+ skb_pull(entry->skb, ring->desc_size);
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+
+ rt2x00lib_txdone(entry, tx_status, 0);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_ring_index_done_inc(entry->ring);
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+}
+
+int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+ int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int max_packet = usb_maxpacket(usb_dev, pipe, 1);
+ u32 length;
+
+ if (rt2x00_ring_full(ring)) {
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) {
+ ERROR(rt2x00dev,
+ "Arrived at non-free entry in the non-full queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ /*
+ * Add the descriptor in front of the skb.
+ */
+ skb_push(skb, ring->desc_size);
+ memset(skb->data, 0, ring->desc_size);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ ring->desc_size),
+ skb->len - ring->desc_size, control);
+ memcpy(&entry->tx_status.control, control, sizeof(*control));
+ entry->skb = skb;
+
+ /*
+ * USB devices cannot blindly pass the skb->len as the
+ * length of the data to usb_fill_bulk_urb. Pass the skb
+ * to the driver to determine what the length should be.
+ */
+ length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev,
+ max_packet, skb);
+
+ /*
+ * Initialize URB and send the frame to the device.
+ */
+ __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ usb_fill_bulk_urb(entry->priv, usb_dev, pipe,
+ skb->data, length, rt2x00usb_interrupt_txdone, entry);
+ usb_submit_urb(entry->priv, GFP_ATOMIC);
+
+ rt2x00_ring_index_inc(ring);
+
+ if (rt2x00_ring_full(ring))
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
+
+/*
+ * RX data handlers.
+ */
+static void rt2x00usb_interrupt_rxdone(struct urb *urb)
+{
+ struct data_entry *entry = (struct data_entry *)urb->context;
+ struct data_ring *ring = entry->ring;
+ struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+ struct sk_buff *skb;
+ struct rxdata_entry_desc desc;
+ int frame_size;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+ return;
+
+ /*
+ * Check if the received data is simply too small
+ * to be actually valid, or if the urb is signaling
+ * a problem.
+ */
+ if (urb->actual_length < entry->ring->desc_size || urb->status)
+ goto skip_entry;
+
+ memset(&desc, 0x00, sizeof(desc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+ /*
+ * Allocate a new sk buffer to replace the current one.
+ * If allocation fails, we should drop the current frame
+ * so we can recycle the existing sk buffer for the new frame.
+ */
+ frame_size = entry->ring->data_size + entry->ring->desc_size;
+ skb = dev_alloc_skb(frame_size + NET_IP_ALIGN);
+ if (!skb)
+ goto skip_entry;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, frame_size);
+
+ /*
+ * Trim the skb_buffer to only contain the valid
+ * frame data (so ignore the device's descriptor).
+ */
+ skb_trim(entry->skb, desc.size);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, entry->skb, &desc);
+
+ /*
+ * Replace current entry's skb with the newly allocated one,
+ * and reinitialize the urb.
+ */
+ entry->skb = skb;
+ urb->transfer_buffer = entry->skb->data;
+ urb->transfer_buffer_length = entry->skb->len;
+
+skip_entry:
+ if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+ __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ usb_submit_urb(urb, GFP_ATOMIC);
+ }
+
+ rt2x00_ring_index_inc(ring);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct data_ring *ring;
+ struct data_entry *entry;
+ unsigned int i;
+
+ /*
+ * Initialize the TX rings
+ */
+ txringall_for_each(rt2x00dev, ring) {
+ for (i = 0; i < ring->stats.limit; i++)
+ ring->entry[i].flags = 0;
+
+ rt2x00_ring_index_clear(ring);
+ }
+
+ /*
+ * Initialize and start the RX ring.
+ */
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+
+ for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+ entry = &rt2x00dev->rx->entry[i];
+
+ usb_fill_bulk_urb(entry->priv, usb_dev,
+ usb_rcvbulkpipe(usb_dev, 1),
+ entry->skb->data, entry->skb->len,
+ rt2x00usb_interrupt_rxdone, entry);
+
+ __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ usb_submit_urb(entry->priv, GFP_ATOMIC);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio);
+
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+ unsigned int i;
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+ REGISTER_TIMEOUT);
+
+ /*
+ * Cancel all rings.
+ */
+ ring_for_each(rt2x00dev, ring) {
+ for (i = 0; i < ring->stats.limit; i++)
+ usb_kill_urb(ring->entry[i].priv);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
+
+/*
+ * Device initialization handlers.
+ */
+static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ unsigned int i;
+
+ /*
+ * Allocate the URB's
+ */
+ for (i = 0; i < ring->stats.limit; i++) {
+ ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ring->entry[i].priv)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ unsigned int i;
+
+ if (!ring->entry)
+ return;
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ usb_kill_urb(ring->entry[i].priv);
+ usb_free_urb(ring->entry[i].priv);
+ if (ring->entry[i].skb)
+ kfree_skb(ring->entry[i].skb);
+ }
+}
+
+int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+ struct sk_buff *skb;
+ unsigned int entry_size;
+ unsigned int i;
+ int status;
+
+ /*
+ * Allocate DMA
+ */
+ ring_for_each(rt2x00dev, ring) {
+ status = rt2x00usb_alloc_urb(rt2x00dev, ring);
+ if (status)
+ goto exit;
+ }
+
+ /*
+ * For the RX ring, skb's should be allocated.
+ */
+ entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
+ for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+ skb = dev_alloc_skb(NET_IP_ALIGN + entry_size);
+ if (!skb)
+ goto exit;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, entry_size);
+
+ rt2x00dev->rx->entry[i].skb = skb;
+ }
+
+ return 0;
+
+exit:
+ rt2x00usb_uninitialize(rt2x00dev);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_initialize);
+
+void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ ring_for_each(rt2x00dev, ring)
+ rt2x00usb_free_urb(rt2x00dev, ring);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
+
+/*
+ * USB driver handlers.
+ */
+static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rf);
+ rt2x00dev->rf = NULL;
+
+ kfree(rt2x00dev->eeprom);
+ rt2x00dev->eeprom = NULL;
+
+ kfree(rt2x00dev->csr_cache);
+ rt2x00dev->csr_cache = NULL;
+}
+
+static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
+ if (!rt2x00dev->csr_cache)
+ goto exit;
+
+ rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+ if (!rt2x00dev->eeprom)
+ goto exit;
+
+ rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+ if (!rt2x00dev->rf)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR_PROBE("Failed to allocate registers.\n");
+
+ rt2x00usb_free_reg(rt2x00dev);
+
+ return -ENOMEM;
+}
+
+int rt2x00usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
+ struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;
+ struct ieee80211_hw *hw;
+ struct rt2x00_dev *rt2x00dev;
+ int retval;
+
+ usb_dev = usb_get_dev(usb_dev);
+
+ hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ if (!hw) {
+ ERROR_PROBE("Failed to allocate hardware.\n");
+ retval = -ENOMEM;
+ goto exit_put_device;
+ }
+
+ usb_set_intfdata(usb_intf, hw);
+
+ rt2x00dev = hw->priv;
+ rt2x00dev->dev = usb_intf;
+ rt2x00dev->ops = ops;
+ rt2x00dev->hw = hw;
+
+ retval = rt2x00usb_alloc_reg(rt2x00dev);
+ if (retval)
+ goto exit_free_device;
+
+ retval = rt2x00lib_probe_dev(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00usb_free_reg(rt2x00dev);
+
+exit_free_device:
+ ieee80211_free_hw(hw);
+
+exit_put_device:
+ usb_put_dev(usb_dev);
+
+ usb_set_intfdata(usb_intf, NULL);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_probe);
+
+void rt2x00usb_disconnect(struct usb_interface *usb_intf)
+{
+ struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Free all allocated data.
+ */
+ rt2x00lib_remove_dev(rt2x00dev);
+ rt2x00usb_free_reg(rt2x00dev);
+ ieee80211_free_hw(hw);
+
+ /*
+ * Free the USB device data.
+ */
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disconnect);
+
+#ifdef CONFIG_PM
+int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
+{
+ struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ retval = rt2x00lib_suspend(rt2x00dev, state);
+ if (retval)
+ return retval;
+
+ rt2x00usb_free_reg(rt2x00dev);
+
+ /*
+ * Decrease usbdev refcount.
+ */
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
+
+int rt2x00usb_resume(struct usb_interface *usb_intf)
+{
+ struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ usb_get_dev(interface_to_usbdev(usb_intf));
+
+ retval = rt2x00usb_alloc_reg(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2x00lib_resume(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00usb_free_reg(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00pci module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
new file mode 100644
index 000000000000..2681abe4d49e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -0,0 +1,180 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00usb
+ Abstract: Data structures for the rt2x00usb module.
+ */
+
+#ifndef RT2X00USB_H
+#define RT2X00USB_H
+
+/*
+ * This variable should be used with the
+ * usb_driver structure initialization.
+ */
+#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
+
+/*
+ * Register defines.
+ * Some registers require multiple attempts before success,
+ * in those cases REGISTER_BUSY_COUNT attempts should be
+ * taken with a REGISTER_BUSY_DELAY interval.
+ * For USB vendor requests we need to pass a timeout
+ * time in ms, for this we use the REGISTER_TIMEOUT,
+ * however when loading firmware a higher value is
+ * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE.
+ */
+#define REGISTER_BUSY_COUNT 5
+#define REGISTER_BUSY_DELAY 100
+#define REGISTER_TIMEOUT 500
+#define REGISTER_TIMEOUT_FIRMWARE 1000
+
+/*
+ * Cache size
+ */
+#define CSR_CACHE_SIZE 8
+#define CSR_CACHE_SIZE_FIRMWARE 64
+
+/*
+ * USB request types.
+ */
+#define USB_VENDOR_REQUEST ( USB_TYPE_VENDOR | USB_RECIP_DEVICE )
+#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST )
+#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST )
+
+/*
+ * USB vendor commands.
+ */
+#define USB_DEVICE_MODE 0x01
+#define USB_SINGLE_WRITE 0x02
+#define USB_SINGLE_READ 0x03
+#define USB_MULTI_WRITE 0x06
+#define USB_MULTI_READ 0x07
+#define USB_EEPROM_WRITE 0x08
+#define USB_EEPROM_READ 0x09
+#define USB_LED_CONTROL 0x0a /* RT73USB */
+#define USB_RX_CONTROL 0x0c
+
+/*
+ * Device modes offset
+ */
+#define USB_MODE_RESET 0x01
+#define USB_MODE_UNPLUG 0x02
+#define USB_MODE_FUNCTION 0x03
+#define USB_MODE_TEST 0x04
+#define USB_MODE_SLEEP 0x07 /* RT73USB */
+#define USB_MODE_FIRMWARE 0x08 /* RT73USB */
+#define USB_MODE_WAKEUP 0x09 /* RT73USB */
+
+/*
+ * Used to read/write from/to the device.
+ * This is the main function to communicate with the device,
+ * the buffer argument _must_ either be NULL or point to
+ * a buffer allocated by kmalloc. Failure to do so can lead
+ * to unexpected behavior depending on the architecture.
+ */
+int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, const u16 value,
+ void *buffer, const u16 buffer_length,
+ const int timeout);
+
+/*
+ * Used to read/write from/to the device.
+ * This function will use a previously with kmalloc allocated cache
+ * to communicate with the device. The contents of the buffer pointer
+ * will be copied to this cache when writing, or read from the cache
+ * when reading.
+ * Buffers send to rt2x00usb_vendor_request _must_ be allocated with
+ * kmalloc. Hence the reason for using a previously allocated cache
+ * which has been allocated properly.
+ */
+int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, void *buffer,
+ const u16 buffer_length, const int timeout);
+
+/*
+ * Simple wrapper around rt2x00usb_vendor_request to write a single
+ * command to the device. Since we don't use the buffer argument we
+ * don't have to worry about kmalloc here.
+ */
+static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev
+ *rt2x00dev,
+ const u8 request,
+ const u16 offset,
+ const u16 value,
+ const int timeout)
+{
+ return rt2x00usb_vendor_request(rt2x00dev, request,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, NULL, 0, timeout);
+}
+
+/*
+ * Simple wrapper around rt2x00usb_vendor_request to read the eeprom
+ * from the device. Note that the eeprom argument _must_ be allocated using
+ * kmalloc for correct handling inside the kernel USB layer.
+ */
+static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+ __le16 *eeprom, const u16 lenght)
+{
+ int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16));
+
+ return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
+ USB_VENDOR_REQUEST_IN, 0x0000,
+ 0x0000, eeprom, lenght, timeout);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * USB driver handlers.
+ */
+int rt2x00usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id);
+void rt2x00usb_disconnect(struct usb_interface *usb_intf);
+#ifdef CONFIG_PM
+int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
+int rt2x00usb_resume(struct usb_interface *usb_intf);
+#else
+#define rt2x00usb_suspend NULL
+#define rt2x00usb_resume NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
new file mode 100644
index 000000000000..01dbef19d651
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -0,0 +1,2557 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt61pci
+ Abstract: rt61pci device specific routines.
+ Supported chipsets: RT2561, RT2561s, RT2661.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt61pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt61pci.h"
+
+/*
+ * Register access.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt61pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+}
+
+static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt61pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt61pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+}
+
+static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev,
+ const u8 command, const u8 token,
+ const u8 arg0, const u8 arg1)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
+
+ if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) {
+ ERROR(rt2x00dev, "mcu request error. "
+ "Request 0x%02x failed for token 0x%02x.\n",
+ command, token);
+ return;
+ }
+
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+}
+
+static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
+}
+
+static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt61pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt61pci_read_csr,
+ .write = rt61pci_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt61pci_bbp_read,
+ .write = rt61pci_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt61pci_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT61PCI_RFKILL
+static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+ return rt2x00_get_field32(reg, MAC_CSR13_BIT5);;
+}
+#else
+#define rt61pci_rfkill_poll NULL
+#endif /* CONFIG_RT61PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(mac[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+ mac[1] = cpu_to_le32(tmp);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(bssid[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
+ bssid[1] = cpu_to_le32(tmp);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
+static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r3;
+ u8 r94;
+ u8 smart;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+ r94 = 6;
+ if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+ r94 += txpower - MAX_TXPOWER;
+ else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+ r94 += txpower;
+ rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ struct rf_channel rf;
+
+ rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+ rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+ rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+ rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+ rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt61pci_bbp_read(rt2x00dev, 4, &r4);
+ rt61pci_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
+ !rt2x00_rf(&rt2x00dev->chip, RF5225));
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !!(rt2x00dev->curr_hwmode != HWMODE_A));
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+ rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt61pci_bbp_read(rt2x00dev, 4, &r4);
+ rt61pci_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
+ !rt2x00_rf(&rt2x00dev->chip, RF2527));
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+ rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
+ const int p1, const int p2)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+
+ if (p1 != 0xff) {
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT4, !!p1);
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT12, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+ }
+ if (p2 != 0xff) {
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT3, !p2);
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT11, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+ }
+}
+
+static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u16 eeprom;
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt61pci_bbp_read(rt2x00dev, 4, &r4);
+ rt61pci_bbp_read(rt2x00dev, 77, &r77);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+ rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+ } else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) {
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) {
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ }
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+ } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+ rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+ case 0:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+ break;
+ case 1:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
+ break;
+ case 2:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+ break;
+ case 3:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+ break;
+ }
+ } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+ !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+ case 0:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+ break;
+ case 1:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
+ break;
+ case 2:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+ break;
+ case 3:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+ break;
+ }
+ }
+
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+ rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+struct antenna_sel {
+ u8 word;
+ /*
+ * value[0] -> non-LNA
+ * value[1] -> LNA
+ */
+ u8 value[2];
+};
+
+static const struct antenna_sel antenna_sel_a[] = {
+ { 96, { 0x58, 0x78 } },
+ { 104, { 0x38, 0x48 } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x60, 0x60 } },
+ { 97, { 0x58, 0x58 } },
+ { 98, { 0x58, 0x58 } },
+};
+
+static const struct antenna_sel antenna_sel_bg[] = {
+ { 96, { 0x48, 0x68 } },
+ { 104, { 0x2c, 0x3c } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x50, 0x50 } },
+ { 97, { 0x48, 0x48 } },
+ { 98, { 0x48, 0x48 } },
+};
+
+static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ const struct antenna_sel *sel;
+ unsigned int lna;
+ unsigned int i;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A) {
+ sel = antenna_sel_a;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
+ } else {
+ sel = antenna_sel_bg;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
+ rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5325))
+ rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+ else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
+ rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+ else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+ if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
+ rt61pci_config_antenna_2x(rt2x00dev, antenna_tx,
+ antenna_rx);
+ else
+ rt61pci_config_antenna_2529(rt2x00dev, antenna_tx,
+ antenna_rx);
+ }
+}
+
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt61pci_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt61pci_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 led_reg;
+ u8 arg0;
+ u8 arg1;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR14, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg);
+
+ led_reg = rt2x00dev->led_reg;
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1);
+ else
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1);
+
+ arg0 = led_reg & 0xff;
+ arg1 = (led_reg >> 8) & 0xff;
+
+ rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
+}
+
+static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u16 led_reg;
+ u8 arg0;
+ u8 arg1;
+
+ led_reg = rt2x00dev->led_reg;
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0);
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
+
+ arg0 = led_reg & 0xff;
+ arg1 = (led_reg >> 8) & 0xff;
+
+ rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
+}
+
+static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+ u8 led;
+
+ if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
+ return;
+
+ /*
+ * Led handling requires a positive value for the rssi,
+ * to do that correctly we need to add the correction.
+ */
+ rssi += rt2x00dev->rssi_offset;
+
+ if (rssi <= 30)
+ led = 0;
+ else if (rssi <= 39)
+ led = 1;
+ else if (rssi <= 49)
+ led = 2;
+ else if (rssi <= 53)
+ led = 3;
+ else if (rssi <= 63)
+ led = 4;
+ else
+ led = 5;
+
+ rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0);
+}
+
+/*
+ * Link tuning
+ */
+static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00dev->link.false_cca =
+ rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+}
+
+static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt61pci_bbp_write(rt2x00dev, 17, 0x20);
+ rt2x00dev->link.vgc_level = 0x20;
+}
+
+static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u8 r17;
+ u8 up_bound;
+ u8 low_bound;
+
+ /*
+ * Update Led strength
+ */
+ rt61pci_activity_led(rt2x00dev, rssi);
+
+ rt61pci_bbp_read(rt2x00dev, 17, &r17);
+
+ /*
+ * Determine r17 bounds.
+ */
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ low_bound = 0x28;
+ up_bound = 0x48;
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ low_bound += 0x10;
+ up_bound += 0x10;
+ }
+ } else {
+ low_bound = 0x20;
+ up_bound = 0x40;
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ low_bound += 0x10;
+ up_bound += 0x10;
+ }
+ }
+
+ /*
+ * Special big-R17 for very short distance
+ */
+ if (rssi >= -35) {
+ if (r17 != 0x60)
+ rt61pci_bbp_write(rt2x00dev, 17, 0x60);
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ if (r17 != up_bound)
+ rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * Special big-R17 for middle-short distance
+ */
+ if (rssi >= -66) {
+ low_bound += 0x10;
+ if (r17 != low_bound)
+ rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ low_bound += 0x08;
+ if (r17 != low_bound)
+ rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+ return;
+ }
+
+ /*
+ * Special case: Change up_bound based on the rssi.
+ * Lower up_bound when rssi is weaker then -74 dBm.
+ */
+ up_bound -= 2 * (-74 - rssi);
+ if (low_bound > up_bound)
+ up_bound = low_bound;
+
+ if (r17 > up_bound) {
+ rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * r17 does not yet exceed upper limit, continue and base
+ * the r17 tuning on the false CCA count.
+ */
+ if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ if (++r17 > up_bound)
+ r17 = up_bound;
+ rt61pci_bbp_write(rt2x00dev, 17, r17);
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ if (--r17 < low_bound)
+ r17 = low_bound;
+ rt61pci_bbp_write(rt2x00dev, 17, r17);
+ }
+}
+
+/*
+ * Firmware name function.
+ */
+static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+ char *fw_name;
+
+ switch (rt2x00dev->chip.rt) {
+ case RT2561:
+ fw_name = FIRMWARE_RT2561;
+ break;
+ case RT2561s:
+ fw_name = FIRMWARE_RT2561s;
+ break;
+ case RT2661:
+ fw_name = FIRMWARE_RT2661;
+ break;
+ default:
+ fw_name = NULL;
+ break;
+ }
+
+ return fw_name;
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
+ const size_t len)
+{
+ int i;
+ u32 reg;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < 100; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg)
+ break;
+ msleep(1);
+ }
+
+ if (!reg) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Prepare MCU and mailbox for firmware loading.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+ rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, 0);
+
+ /*
+ * Write firmware to device.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 1);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
+
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 0);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 0);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+ for (i = 0; i < 100; i++) {
+ rt2x00pci_register_read(rt2x00dev, MCU_CNTL_CSR, &reg);
+ if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY))
+ break;
+ msleep(1);
+ }
+
+ if (i == 100) {
+ ERROR(rt2x00dev, "MCU Control register not ready.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Reset MAC and BBP registers.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ return 0;
+}
+
+static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_desc *rxd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ rxd = ring->entry[i].priv;
+
+ rt2x00_desc_read(rxd, 5, &word);
+ rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(rxd, 5, word);
+
+ rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_desc *txd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ txd = ring->entry[i].priv;
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue);
+ rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i);
+ rt2x00_desc_write(txd, 5, word);
+
+ rt2x00_desc_read(txd, 6, &word);
+ rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(txd, 6, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(txd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(ring);
+}
+
+static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize rings.
+ */
+ rt61pci_init_rxring(rt2x00dev);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4);
+
+ /*
+ * Initialize registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, &reg);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC0_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC1_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC2_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC3_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit);
+ rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, &reg);
+ rt2x00_set_field32(&reg, TX_RING_CSR1_MGMT_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR1_TXD_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size /
+ 4);
+ rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, MGMT_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma);
+ rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE,
+ rt2x00dev->rx->stats.limit);
+ rt2x00_set_field32(&reg, RX_RING_CSR_RXD_SIZE,
+ rt2x00dev->rx->desc_size / 4);
+ rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
+ rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
+ rt2x00dev->rx->data_dma);
+ rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC0, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC1, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC2, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC3, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_MGMT, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, &reg);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1);
+ rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_CNTL_CSR_LOAD_RXD, 1);
+ rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+
+ return 0;
+}
+
+static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ /*
+ * CCK TXD BBP registers
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+ /*
+ * OFDM TXD BBP registers
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x0000071c);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
+
+ /*
+ * Invalidate all Shared Keys (SEC_CSR0),
+ * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
+ */
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR7, 0x00000a08);
+
+ rt2x00pci_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404);
+
+ rt2x00pci_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200);
+
+ rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+
+ rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
+ rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
+ rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+
+ /*
+ * We must clear the error counters.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00pci_register_read(rt2x00dev, STA_CSR2, &reg);
+
+ /*
+ * Reset MAC and BBP registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ return 0;
+}
+
+static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt61pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt61pci_bbp_write(rt2x00dev, 3, 0x00);
+ rt61pci_bbp_write(rt2x00dev, 15, 0x30);
+ rt61pci_bbp_write(rt2x00dev, 21, 0xc8);
+ rt61pci_bbp_write(rt2x00dev, 22, 0x38);
+ rt61pci_bbp_write(rt2x00dev, 23, 0x06);
+ rt61pci_bbp_write(rt2x00dev, 24, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 25, 0x0a);
+ rt61pci_bbp_write(rt2x00dev, 26, 0x0d);
+ rt61pci_bbp_write(rt2x00dev, 34, 0x12);
+ rt61pci_bbp_write(rt2x00dev, 37, 0x07);
+ rt61pci_bbp_write(rt2x00dev, 39, 0xf8);
+ rt61pci_bbp_write(rt2x00dev, 41, 0x60);
+ rt61pci_bbp_write(rt2x00dev, 53, 0x10);
+ rt61pci_bbp_write(rt2x00dev, 54, 0x18);
+ rt61pci_bbp_write(rt2x00dev, 60, 0x10);
+ rt61pci_bbp_write(rt2x00dev, 61, 0x04);
+ rt61pci_bbp_write(rt2x00dev, 62, 0x04);
+ rt61pci_bbp_write(rt2x00dev, 75, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 86, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 88, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 90, 0x0f);
+ rt61pci_bbp_write(rt2x00dev, 99, 0x00);
+ rt61pci_bbp_write(rt2x00dev, 102, 0x16);
+ rt61pci_bbp_write(rt2x00dev, 107, 0x04);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt61pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_OFF);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+}
+
+static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize all registers.
+ */
+ if (rt61pci_init_rings(rt2x00dev) ||
+ rt61pci_init_registers(rt2x00dev) ||
+ rt61pci_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+ /*
+ * Enable RX.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_CNTL_CSR_ENABLE_RX_DMA, 1);
+ rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+
+ /*
+ * Enable LED
+ */
+ rt61pci_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Disable LED
+ */
+ rt61pci_disable_led(rt2x00dev);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+
+ /*
+ * Cancel RX and TX.
+ */
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_MGMT, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+
+ /*
+ * Disable interrupts.
+ */
+ rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char current_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
+ rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+ current_state =
+ rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+ if (current_state == !put_to_sleep)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state %d.\n", !put_to_sleep, current_state);
+
+ return -EBUSY;
+}
+
+static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt61pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt61pci_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt61pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt61pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_TX_POWER,
+ TXPOWER_TO_DEV(control->power_level));
+ rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
+ rt2x00_desc_write(txd, 5, word);
+
+ rt2x00_desc_read(txd, 11, &word);
+ rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length);
+ rt2x00_desc_write(txd, 11, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_BURST,
+ test_bit(ENTRY_TXD_BURST, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ /*
+ * For Wi-Fi faily generated beacons between participating
+ * stations. Set TBTT phase adaptive adjustment step to 8us.
+ */
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ if (queue == IEEE80211_TX_QUEUE_DATA0)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA1)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA2)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA3)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA4)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_MGMT, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+ u16 eeprom;
+ u8 offset;
+ u8 lna;
+
+ lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+ switch (lna) {
+ case 3:
+ offset = 90;
+ break;
+ case 2:
+ offset = 74;
+ break;
+ case 1:
+ offset = 64;
+ break;
+ default:
+ return 0;
+ }
+
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ offset += 14;
+
+ if (lna == 3 || lna == 2)
+ offset += 10;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ offset += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ }
+
+ return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static void rt61pci_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+ return;
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+ struct data_entry *entry;
+ struct data_desc *txd;
+ u32 word;
+ u32 reg;
+ u32 old_reg;
+ int type;
+ int index;
+ int tx_status;
+ int retry;
+
+ /*
+ * During each loop we will compare the freshly read
+ * STA_CSR4 register value with the value read from
+ * the previous loop. If the 2 values are equal then
+ * we should stop processing because the chance it
+ * quite big that the device has been unplugged and
+ * we risk going into an endless loop.
+ */
+ old_reg = 0;
+
+ while (1) {
+ rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
+ if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
+ break;
+
+ if (old_reg == reg)
+ break;
+ old_reg = reg;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * ring identication number.
+ */
+ type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE);
+ ring = rt2x00lib_get_ring(rt2x00dev, type);
+ if (unlikely(!ring))
+ continue;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * index number.
+ */
+ index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
+ if (unlikely(index >= ring->stats.limit))
+ continue;
+
+ entry = &ring->entry[index];
+ txd = entry->priv;
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ !rt2x00_get_field32(word, TXD_W0_VALID))
+ return;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+ retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
+
+ rt2x00lib_txdone(entry, tx_status, retry);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_desc_write(txd, 0, word);
+ rt2x00_ring_index_done_inc(entry->ring);
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+ }
+}
+
+static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg_mcu;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
+
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ if (!reg && !reg_mcu)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * Handle interrupts, walk through all bits
+ * and run the tasks, the bits are checked in order of
+ * priority.
+ */
+
+ /*
+ * 1 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 2 - Tx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
+ rt61pci_txdone(rt2x00dev);
+
+ /*
+ * 3 - Handle MCU command done.
+ */
+ if (reg_mcu)
+ rt2x00pci_register_write(rt2x00dev,
+ M2H_CMD_DONE_CSR, 0xffffffff);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+ u16 word;
+ u8 *mac;
+ s8 value;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt61pci_eepromregister_read;
+ eeprom.register_write = rt61pci_eepromregister_write;
+ eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_TX_RX_FIXED, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
+ LED_MODE_DEFAULT);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
+ EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ }
+
+ return 0;
+}
+
+static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+ u16 device;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ * To determine the RT chip we have to read the
+ * PCI header of the device.
+ */
+ pci_read_config_word(rt2x00dev_pci(rt2x00dev),
+ PCI_CONFIG_HEADER_DEVICE, &device);
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, device, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5325) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2527) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Read the Frame type.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
+ __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+
+ /*
+ * Determine number of antenna's.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
+ __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+#ifdef CONFIG_RT61PCI_RFKILL
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT61PCI_RFKILL */
+
+ /*
+ * Read frequency offset and RF programming sequence.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ))
+ __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags);
+
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+ /*
+ * Read external LNA informations.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ /*
+ * Store led settings, for correct led behaviour.
+ * If the eeprom value is invalid,
+ * switch to default led mode.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
+
+ rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
+
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
+ rt2x00dev->led_mode);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_0));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_1));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_2));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_3));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_4));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+ rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_G));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_A));
+
+ return 0;
+}
+
+/*
+ * RF value list for RF5225 & RF5325
+ * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled
+ */
+static const struct rf_channel rf_vals_noseq[] = {
+ { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+ { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+ { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+ { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+ { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+ { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+ { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+ { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+ { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+ { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+ { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+ { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+ { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+ { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
+ { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
+ { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
+ { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
+ { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
+ { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
+ { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
+ { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
+ { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
+ { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
+ { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
+ { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
+ { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
+ { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
+ { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
+ { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
+ { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
+ { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
+ { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
+ { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
+ { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
+ { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
+ { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
+ { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
+ { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
+};
+
+/*
+ * RF value list for RF5225 & RF5325
+ * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled
+ */
+static const struct rf_channel rf_vals_seq[] = {
+ { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+ { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+ { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+ { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+ { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+ { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+ { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+ { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+ { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+ { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+ { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+ { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+ { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+ { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 },
+ { 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 },
+ { 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b },
+ { 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b },
+ { 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 },
+ { 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 },
+ { 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 },
+ { 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 },
+ { 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 },
+ { 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 },
+ { 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 },
+ { 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 },
+ { 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 },
+ { 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b },
+ { 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b },
+ { 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 },
+ { 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 },
+ { 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b },
+ { 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b },
+ { 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 },
+ { 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 },
+ { 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b },
+ { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 },
+ { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b },
+ { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 },
+};
+
+static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = 0;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 5;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_noseq;
+ } else {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_seq;
+ }
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5325)) {
+ spec->num_modes = 3;
+ spec->num_channels = ARRAY_SIZE(rf_vals_seq);
+
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ spec->tx_power_a = txpower;
+ }
+}
+
+static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt61pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt61pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt61pci_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires firmware
+ */
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt61pci_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BORADCAST, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
+ rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ return 0;
+}
+
+static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
+
+ return tsf;
+}
+
+static void rt61pci_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0);
+}
+
+static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Just in case the ieee80211 doesn't set this,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * We need to append the descriptor in front of the
+ * beacon frame.
+ */
+ if (skb_headroom(skb) < TXD_DESC_SIZE) {
+ if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+ }
+
+ /*
+ * First we create the beacon.
+ */
+ skb_push(skb, TXD_DESC_SIZE);
+ memset(skb->data, 0, TXD_DESC_SIZE);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ TXD_DESC_SIZE),
+ skb->len - TXD_DESC_SIZE, control);
+
+ /*
+ * Write entire beacon with descriptor to register,
+ * and kick the beacon generator.
+ */
+ rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0,
+ skb->data, skb->len);
+ rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rt61pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt61pci_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt61pci_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt61pci_get_tsf,
+ .reset_tsf = rt61pci_reset_tsf,
+ .beacon_update = rt61pci_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
+ .irq_handler = rt61pci_interrupt,
+ .probe_hw = rt61pci_probe_hw,
+ .get_firmware_name = rt61pci_get_firmware_name,
+ .load_firmware = rt61pci_load_firmware,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .set_device_state = rt61pci_set_device_state,
+ .rfkill_poll = rt61pci_rfkill_poll,
+ .link_stats = rt61pci_link_stats,
+ .reset_tuner = rt61pci_reset_tuner,
+ .link_tuner = rt61pci_link_tuner,
+ .write_tx_desc = rt61pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .kick_tx_queue = rt61pci_kick_tx_queue,
+ .fill_rxdone = rt61pci_fill_rxdone,
+ .config_mac_addr = rt61pci_config_mac_addr,
+ .config_bssid = rt61pci_config_bssid,
+ .config_type = rt61pci_config_type,
+ .config_preamble = rt61pci_config_preamble,
+ .config = rt61pci_config,
+};
+
+static const struct rt2x00_ops rt61pci_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt61pci_rt2x00_ops,
+ .hw = &rt61pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt61pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT61pci module information.
+ */
+static struct pci_device_id rt61pci_device_table[] = {
+ /* RT2561s */
+ { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
+ /* RT2561 v2 */
+ { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) },
+ /* RT2661 */
+ { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 "
+ "PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt61pci_device_table);
+MODULE_FIRMWARE(FIRMWARE_RT2561);
+MODULE_FIRMWARE(FIRMWARE_RT2561s);
+MODULE_FIRMWARE(FIRMWARE_RT2661);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt61pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rt61pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+
+static int __init rt61pci_init(void)
+{
+ return pci_register_driver(&rt61pci_driver);
+}
+
+static void __exit rt61pci_exit(void)
+{
+ pci_unregister_driver(&rt61pci_driver);
+}
+
+module_init(rt61pci_init);
+module_exit(rt61pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
new file mode 100644
index 000000000000..6721d7dd32bc
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -0,0 +1,1457 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt61pci
+ Abstract: Data structures and registers for the rt61pci module.
+ Supported chipsets: RT2561, RT2561s, RT2661.
+ */
+
+#ifndef RT61PCI_H
+#define RT61PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF5225 0x0001
+#define RF5325 0x0002
+#define RF2527 0x0003
+#define RF2529 0x0004
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x3000
+#define CSR_REG_SIZE 0x04b0
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0100
+#define BBP_SIZE 0x0080
+#define RF_SIZE 0x0014
+
+/*
+ * PCI registers.
+ */
+
+/*
+ * PCI Configuration Header
+ */
+#define PCI_CONFIG_HEADER_VENDOR 0x0000
+#define PCI_CONFIG_HEADER_DEVICE 0x0002
+
+/*
+ * HOST_CMD_CSR: For HOST to interrupt embedded processor
+ */
+#define HOST_CMD_CSR 0x0008
+#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x0000007f)
+#define HOST_CMD_CSR_INTERRUPT_MCU FIELD32(0x00000080)
+
+/*
+ * MCU_CNTL_CSR
+ * SELECT_BANK: Select 8051 program bank.
+ * RESET: Enable 8051 reset state.
+ * READY: Ready state for 8051.
+ */
+#define MCU_CNTL_CSR 0x000c
+#define MCU_CNTL_CSR_SELECT_BANK FIELD32(0x00000001)
+#define MCU_CNTL_CSR_RESET FIELD32(0x00000002)
+#define MCU_CNTL_CSR_READY FIELD32(0x00000004)
+
+/*
+ * SOFT_RESET_CSR
+ */
+#define SOFT_RESET_CSR 0x0010
+
+/*
+ * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register.
+ */
+#define MCU_INT_SOURCE_CSR 0x0014
+#define MCU_INT_SOURCE_CSR_0 FIELD32(0x00000001)
+#define MCU_INT_SOURCE_CSR_1 FIELD32(0x00000002)
+#define MCU_INT_SOURCE_CSR_2 FIELD32(0x00000004)
+#define MCU_INT_SOURCE_CSR_3 FIELD32(0x00000008)
+#define MCU_INT_SOURCE_CSR_4 FIELD32(0x00000010)
+#define MCU_INT_SOURCE_CSR_5 FIELD32(0x00000020)
+#define MCU_INT_SOURCE_CSR_6 FIELD32(0x00000040)
+#define MCU_INT_SOURCE_CSR_7 FIELD32(0x00000080)
+#define MCU_INT_SOURCE_CSR_TWAKEUP FIELD32(0x00000100)
+#define MCU_INT_SOURCE_CSR_TBTT_EXPIRE FIELD32(0x00000200)
+
+/*
+ * MCU_INT_MASK_CSR: MCU interrupt source/mask register.
+ */
+#define MCU_INT_MASK_CSR 0x0018
+#define MCU_INT_MASK_CSR_0 FIELD32(0x00000001)
+#define MCU_INT_MASK_CSR_1 FIELD32(0x00000002)
+#define MCU_INT_MASK_CSR_2 FIELD32(0x00000004)
+#define MCU_INT_MASK_CSR_3 FIELD32(0x00000008)
+#define MCU_INT_MASK_CSR_4 FIELD32(0x00000010)
+#define MCU_INT_MASK_CSR_5 FIELD32(0x00000020)
+#define MCU_INT_MASK_CSR_6 FIELD32(0x00000040)
+#define MCU_INT_MASK_CSR_7 FIELD32(0x00000080)
+#define MCU_INT_MASK_CSR_TWAKEUP FIELD32(0x00000100)
+#define MCU_INT_MASK_CSR_TBTT_EXPIRE FIELD32(0x00000200)
+
+/*
+ * PCI_USEC_CSR
+ */
+#define PCI_USEC_CSR 0x001c
+
+/*
+ * Security key table memory.
+ * 16 entries 32-byte for shared key table
+ * 64 entries 32-byte for pairwise key table
+ * 64 entries 8-byte for pairwise ta key table
+ */
+#define SHARED_KEY_TABLE_BASE 0x1000
+#define PAIRWISE_KEY_TABLE_BASE 0x1200
+#define PAIRWISE_TA_TABLE_BASE 0x1a00
+
+struct hw_key_entry {
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct hw_pairwise_ta_entry {
+ u8 address[6];
+ u8 reserved[2];
+} __attribute__ ((packed));
+
+/*
+ * Other on-chip shared memory space.
+ */
+#define HW_CIS_BASE 0x2000
+#define HW_NULL_BASE 0x2b00
+
+/*
+ * Since NULL frame won't be that long (256 byte),
+ * We steal 16 tail bytes to save debugging settings.
+ */
+#define HW_DEBUG_SETTING_BASE 0x2bf0
+
+/*
+ * On-chip BEACON frame space.
+ */
+#define HW_BEACON_BASE0 0x2c00
+#define HW_BEACON_BASE1 0x2d00
+#define HW_BEACON_BASE2 0x2e00
+#define HW_BEACON_BASE3 0x2f00
+#define HW_BEACON_OFFSET 0x0100
+
+/*
+ * HOST-MCU shared memory.
+ */
+
+/*
+ * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ */
+#define H2M_MAILBOX_CSR 0x2100
+#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff)
+#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000)
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE FIELD16(0x001f)
+#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020)
+#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040)
+#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080)
+#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100)
+#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200)
+#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400)
+#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800)
+#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000)
+#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000)
+#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000)
+#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000)
+
+/*
+ * M2H_CMD_DONE_CSR.
+ */
+#define M2H_CMD_DONE_CSR 0x2104
+
+/*
+ * MCU_TXOP_ARRAY_BASE.
+ */
+#define MCU_TXOP_ARRAY_BASE 0x2110
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0 0x3000
+
+/*
+ * MAC_CSR1: System control register.
+ * SOFT_RESET: Software reset bit, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset BBP.
+ * HOST_READY: Host is ready after initialization, 1: ready.
+ */
+#define MAC_CSR1 0x3004
+#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001)
+#define MAC_CSR1_BBP_RESET FIELD32(0x00000002)
+#define MAC_CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2 0x3008
+#define MAC_CSR2_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR2_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3 0x300c
+#define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR4: BSSID register 0.
+ */
+#define MAC_CSR4 0x3010
+#define MAC_CSR4_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR4_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR5: BSSID register 1.
+ * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ */
+#define MAC_CSR5 0x3014
+#define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR6: Maximum frame length register.
+ */
+#define MAC_CSR6 0x3018
+#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff)
+
+/*
+ * MAC_CSR7: Reserved
+ */
+#define MAC_CSR7 0x301c
+
+/*
+ * MAC_CSR8: SIFS/EIFS register.
+ * All units are in US.
+ */
+#define MAC_CSR8 0x3020
+#define MAC_CSR8_SIFS FIELD32(0x000000ff)
+#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00)
+#define MAC_CSR8_EIFS FIELD32(0xffff0000)
+
+/*
+ * MAC_CSR9: Back-Off control register.
+ * SLOT_TIME: Slot time, default is 20us for 802.11BG.
+ * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1).
+ * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1).
+ * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD.
+ */
+#define MAC_CSR9 0x3024
+#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff)
+#define MAC_CSR9_CWMIN FIELD32(0x00000f00)
+#define MAC_CSR9_CWMAX FIELD32(0x0000f000)
+#define MAC_CSR9_CW_SELECT FIELD32(0x00010000)
+
+/*
+ * MAC_CSR10: Power state configuration.
+ */
+#define MAC_CSR10 0x3028
+
+/*
+ * MAC_CSR11: Power saving transition time register.
+ * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * WAKEUP_LATENCY: In unit of TU.
+ */
+#define MAC_CSR11 0x302c
+#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff)
+#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00)
+#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000)
+#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000)
+
+/*
+ * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1).
+ * CURRENT_STATE: 0:sleep, 1:awake.
+ * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP.
+ * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake.
+ */
+#define MAC_CSR12 0x3030
+#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001)
+#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002)
+#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004)
+#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008)
+
+/*
+ * MAC_CSR13: GPIO.
+ */
+#define MAC_CSR13 0x3034
+#define MAC_CSR13_BIT0 FIELD32(0x00000001)
+#define MAC_CSR13_BIT1 FIELD32(0x00000002)
+#define MAC_CSR13_BIT2 FIELD32(0x00000004)
+#define MAC_CSR13_BIT3 FIELD32(0x00000008)
+#define MAC_CSR13_BIT4 FIELD32(0x00000010)
+#define MAC_CSR13_BIT5 FIELD32(0x00000020)
+#define MAC_CSR13_BIT6 FIELD32(0x00000040)
+#define MAC_CSR13_BIT7 FIELD32(0x00000080)
+#define MAC_CSR13_BIT8 FIELD32(0x00000100)
+#define MAC_CSR13_BIT9 FIELD32(0x00000200)
+#define MAC_CSR13_BIT10 FIELD32(0x00000400)
+#define MAC_CSR13_BIT11 FIELD32(0x00000800)
+#define MAC_CSR13_BIT12 FIELD32(0x00001000)
+
+/*
+ * MAC_CSR14: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON.
+ * SW_LED: s/w LED, 1: ON, 0: OFF.
+ * HW_LED_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR14 0x3038
+#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff)
+#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00)
+#define MAC_CSR14_HW_LED FIELD32(0x00010000)
+#define MAC_CSR14_SW_LED FIELD32(0x00020000)
+#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000)
+#define MAC_CSR14_SW_LED2 FIELD32(0x00080000)
+
+/*
+ * MAC_CSR15: NAV control.
+ */
+#define MAC_CSR15 0x303c
+
+/*
+ * TXRX control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: TX/RX configuration register.
+ * TSF_OFFSET: Default is 24.
+ * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame.
+ * DISABLE_RX: Disable Rx engine.
+ * DROP_CRC: Drop CRC error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TO_DS: Drop fram ToDs bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MULTICAST: Drop multicast frames.
+ * DROP_BORADCAST: Drop broadcast frames.
+ * ROP_ACK_CTS: Drop received ACK and CTS.
+ */
+#define TXRX_CSR0 0x3040
+#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00)
+#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000)
+#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000)
+#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000)
+#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000)
+#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000)
+#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000)
+#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000)
+#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000)
+#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000)
+#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000)
+#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000)
+
+/*
+ * TXRX_CSR1
+ */
+#define TXRX_CSR1 0x3044
+#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR2
+ */
+#define TXRX_CSR2 0x3048
+#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR3
+ */
+#define TXRX_CSR3 0x304c
+#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR4: Auto-Responder/Tx-retry register.
+ * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble.
+ * OFDM_TX_RATE_DOWN: 1:enable.
+ * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step.
+ * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M.
+ */
+#define TXRX_CSR4 0x3050
+#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff)
+#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700)
+#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000)
+#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000)
+#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000)
+#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000)
+#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000)
+#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000)
+#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000)
+#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000)
+
+/*
+ * TXRX_CSR5
+ */
+#define TXRX_CSR5 0x3054
+
+/*
+ * TXRX_CSR6: ACK/CTS payload consumed time
+ */
+#define TXRX_CSR6 0x3058
+
+/*
+ * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define TXRX_CSR7 0x305c
+#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff)
+#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00)
+#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000)
+#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define TXRX_CSR8 0x3060
+#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff)
+#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00)
+#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000)
+#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR9: Synchronization control register.
+ * BEACON_INTERVAL: In unit of 1/16 TU.
+ * TSF_TICKING: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR9 0x3064
+#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000)
+#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000)
+#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000)
+#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000)
+#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR10: BEACON alignment.
+ */
+#define TXRX_CSR10 0x3068
+
+/*
+ * TXRX_CSR11: AES mask.
+ */
+#define TXRX_CSR11 0x306c
+
+/*
+ * TXRX_CSR12: TSF low 32.
+ */
+#define TXRX_CSR12 0x3070
+#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR13: TSF high 32.
+ */
+#define TXRX_CSR13 0x3074
+#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR14: TBTT timer.
+ */
+#define TXRX_CSR14 0x3078
+
+/*
+ * TXRX_CSR15: TKIP MIC priority byte "AND" mask.
+ */
+#define TXRX_CSR15 0x307c
+
+/*
+ * PHY control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PHY_CSR0: RF/PS control.
+ */
+#define PHY_CSR0 0x3080
+#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000)
+#define PHY_CSR0_PA_PE_A FIELD32(0x00020000)
+
+/*
+ * PHY_CSR1
+ */
+#define PHY_CSR1 0x3084
+
+/*
+ * PHY_CSR2: Pre-TX BBP control.
+ */
+#define PHY_CSR2 0x3088
+
+/*
+ * PHY_CSR3: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REG_NUM: Selected BBP register.
+ * READ_CONTROL: 0: Write BBP, 1: Read BBP.
+ * BUSY: 1: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR3 0x308c
+#define PHY_CSR3_VALUE FIELD32(0x000000ff)
+#define PHY_CSR3_REGNUM FIELD32(0x00007f00)
+#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000)
+#define PHY_CSR3_BUSY FIELD32(0x00010000)
+
+/*
+ * PHY_CSR4: RF serial control register
+ * VALUE: Register value (include register id) serial out to RF/IF chip.
+ * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22).
+ * IF_SELECT: 1: select IF to program, 0: select RF to program.
+ * PLL_LD: RF PLL_LD status.
+ * BUSY: 1: ASIC is busy execute RF programming.
+ */
+#define PHY_CSR4 0x3090
+#define PHY_CSR4_VALUE FIELD32(0x00ffffff)
+#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define PHY_CSR4_IF_SELECT FIELD32(0x20000000)
+#define PHY_CSR4_PLL_LD FIELD32(0x40000000)
+#define PHY_CSR4_BUSY FIELD32(0x80000000)
+
+/*
+ * PHY_CSR5: RX to TX signal switch timing control.
+ */
+#define PHY_CSR5 0x3094
+#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR6: TX to RX signal timing control.
+ */
+#define PHY_CSR6 0x3098
+#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR7: TX DAC switching timing control.
+ */
+#define PHY_CSR7 0x309c
+
+/*
+ * Security control register.
+ */
+
+/*
+ * SEC_CSR0: Shared key table control.
+ */
+#define SEC_CSR0 0x30a0
+#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001)
+#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002)
+#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004)
+#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008)
+#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010)
+#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020)
+#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040)
+#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080)
+#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100)
+#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200)
+#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400)
+#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800)
+#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000)
+#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000)
+#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000)
+#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000)
+
+/*
+ * SEC_CSR1: Shared key table security mode register.
+ */
+#define SEC_CSR1 0x30a4
+#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * Pairwise key table valid bitmap registers.
+ * SEC_CSR2: pairwise key table valid bitmap 0.
+ * SEC_CSR3: pairwise key table valid bitmap 1.
+ */
+#define SEC_CSR2 0x30a8
+#define SEC_CSR3 0x30ac
+
+/*
+ * SEC_CSR4: Pairwise key table lookup control.
+ */
+#define SEC_CSR4 0x30b0
+
+/*
+ * SEC_CSR5: shared key table security mode register.
+ */
+#define SEC_CSR5 0x30b4
+#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * STA control registers.
+ */
+
+/*
+ * STA_CSR0: RX PLCP error count & RX FCS error count.
+ */
+#define STA_CSR0 0x30c0
+#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff)
+#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR1: RX False CCA count & RX LONG frame count.
+ */
+#define STA_CSR1 0x30c4
+#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff)
+#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR2: TX Beacon count and RX FIFO overflow count.
+ */
+#define STA_CSR2 0x30c8
+#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff)
+#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000)
+
+/*
+ * STA_CSR3: TX Beacon count.
+ */
+#define STA_CSR3 0x30cc
+#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff)
+
+/*
+ * STA_CSR4: TX Result status register.
+ * VALID: 1:This register contains a valid TX result.
+ */
+#define STA_CSR4 0x30d0
+#define STA_CSR4_VALID FIELD32(0x00000001)
+#define STA_CSR4_TX_RESULT FIELD32(0x0000000e)
+#define STA_CSR4_RETRY_COUNT FIELD32(0x000000f0)
+#define STA_CSR4_PID_SUBTYPE FIELD32(0x00001f00)
+#define STA_CSR4_PID_TYPE FIELD32(0x0000e000)
+#define STA_CSR4_TXRATE FIELD32(0x000f0000)
+
+/*
+ * QOS control registers.
+ */
+
+/*
+ * QOS_CSR0: TXOP holder MAC address register.
+ */
+#define QOS_CSR0 0x30e0
+#define QOS_CSR0_BYTE0 FIELD32(0x000000ff)
+#define QOS_CSR0_BYTE1 FIELD32(0x0000ff00)
+#define QOS_CSR0_BYTE2 FIELD32(0x00ff0000)
+#define QOS_CSR0_BYTE3 FIELD32(0xff000000)
+
+/*
+ * QOS_CSR1: TXOP holder MAC address register.
+ */
+#define QOS_CSR1 0x30e4
+#define QOS_CSR1_BYTE4 FIELD32(0x000000ff)
+#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * QOS_CSR2: TXOP holder timeout register.
+ */
+#define QOS_CSR2 0x30e8
+
+/*
+ * RX QOS-CFPOLL MAC address register.
+ * QOS_CSR3: RX QOS-CFPOLL MAC address 0.
+ * QOS_CSR4: RX QOS-CFPOLL MAC address 1.
+ */
+#define QOS_CSR3 0x30ec
+#define QOS_CSR4 0x30f0
+
+/*
+ * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL.
+ */
+#define QOS_CSR5 0x30f4
+
+/*
+ * Host DMA registers.
+ */
+
+/*
+ * AC0_BASE_CSR: AC_BK base address.
+ */
+#define AC0_BASE_CSR 0x3400
+#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * AC1_BASE_CSR: AC_BE base address.
+ */
+#define AC1_BASE_CSR 0x3404
+#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * AC2_BASE_CSR: AC_VI base address.
+ */
+#define AC2_BASE_CSR 0x3408
+#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * AC3_BASE_CSR: AC_VO base address.
+ */
+#define AC3_BASE_CSR 0x340c
+#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * MGMT_BASE_CSR: MGMT ring base address.
+ */
+#define MGMT_BASE_CSR 0x3410
+#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
+ */
+#define TX_RING_CSR0 0x3418
+#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff)
+#define TX_RING_CSR0_AC1_RING_SIZE FIELD32(0x0000ff00)
+#define TX_RING_CSR0_AC2_RING_SIZE FIELD32(0x00ff0000)
+#define TX_RING_CSR0_AC3_RING_SIZE FIELD32(0xff000000)
+
+/*
+ * TX_RING_CSR1: TX Ring size for MGMT Ring, HCCA Ring
+ * TXD_SIZE: In unit of 32-bit.
+ */
+#define TX_RING_CSR1 0x341c
+#define TX_RING_CSR1_MGMT_RING_SIZE FIELD32(0x000000ff)
+#define TX_RING_CSR1_HCCA_RING_SIZE FIELD32(0x0000ff00)
+#define TX_RING_CSR1_TXD_SIZE FIELD32(0x003f0000)
+
+/*
+ * AIFSN_CSR: AIFSN for each EDCA AC.
+ * AIFSN0: For AC_BK.
+ * AIFSN1: For AC_BE.
+ * AIFSN2: For AC_VI.
+ * AIFSN3: For AC_VO.
+ */
+#define AIFSN_CSR 0x3420
+#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
+#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0)
+#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00)
+#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000)
+
+/*
+ * CWMIN_CSR: CWmin for each EDCA AC.
+ * CWMIN0: For AC_BK.
+ * CWMIN1: For AC_BE.
+ * CWMIN2: For AC_VI.
+ * CWMIN3: For AC_VO.
+ */
+#define CWMIN_CSR 0x3424
+#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
+#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0)
+#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00)
+#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000)
+
+/*
+ * CWMAX_CSR: CWmax for each EDCA AC.
+ * CWMAX0: For AC_BK.
+ * CWMAX1: For AC_BE.
+ * CWMAX2: For AC_VI.
+ * CWMAX3: For AC_VO.
+ */
+#define CWMAX_CSR 0x3428
+#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
+#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0)
+#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00)
+#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)
+
+/*
+ * TX_DMA_DST_CSR: TX DMA destination
+ * 0: TX ring0, 1: TX ring1, 2: TX ring2 3: invalid
+ */
+#define TX_DMA_DST_CSR 0x342c
+#define TX_DMA_DST_CSR_DEST_AC0 FIELD32(0x00000003)
+#define TX_DMA_DST_CSR_DEST_AC1 FIELD32(0x0000000c)
+#define TX_DMA_DST_CSR_DEST_AC2 FIELD32(0x00000030)
+#define TX_DMA_DST_CSR_DEST_AC3 FIELD32(0x000000c0)
+#define TX_DMA_DST_CSR_DEST_MGMT FIELD32(0x00000300)
+
+/*
+ * TX_CNTL_CSR: KICK/Abort TX.
+ * KICK_TX_AC0: For AC_BK.
+ * KICK_TX_AC1: For AC_BE.
+ * KICK_TX_AC2: For AC_VI.
+ * KICK_TX_AC3: For AC_VO.
+ * ABORT_TX_AC0: For AC_BK.
+ * ABORT_TX_AC1: For AC_BE.
+ * ABORT_TX_AC2: For AC_VI.
+ * ABORT_TX_AC3: For AC_VO.
+ */
+#define TX_CNTL_CSR 0x3430
+#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001)
+#define TX_CNTL_CSR_KICK_TX_AC1 FIELD32(0x00000002)
+#define TX_CNTL_CSR_KICK_TX_AC2 FIELD32(0x00000004)
+#define TX_CNTL_CSR_KICK_TX_AC3 FIELD32(0x00000008)
+#define TX_CNTL_CSR_KICK_TX_MGMT FIELD32(0x00000010)
+#define TX_CNTL_CSR_ABORT_TX_AC0 FIELD32(0x00010000)
+#define TX_CNTL_CSR_ABORT_TX_AC1 FIELD32(0x00020000)
+#define TX_CNTL_CSR_ABORT_TX_AC2 FIELD32(0x00040000)
+#define TX_CNTL_CSR_ABORT_TX_AC3 FIELD32(0x00080000)
+#define TX_CNTL_CSR_ABORT_TX_MGMT FIELD32(0x00100000)
+
+/*
+ * LOAD_TX_RING_CSR: Load RX de
+ */
+#define LOAD_TX_RING_CSR 0x3434
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC0 FIELD32(0x00000001)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC1 FIELD32(0x00000002)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC2 FIELD32(0x00000004)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC3 FIELD32(0x00000008)
+#define LOAD_TX_RING_CSR_LOAD_TXD_MGMT FIELD32(0x00000010)
+
+/*
+ * Several read-only registers, for debugging.
+ */
+#define AC0_TXPTR_CSR 0x3438
+#define AC1_TXPTR_CSR 0x343c
+#define AC2_TXPTR_CSR 0x3440
+#define AC3_TXPTR_CSR 0x3444
+#define MGMT_TXPTR_CSR 0x3448
+
+/*
+ * RX_BASE_CSR
+ */
+#define RX_BASE_CSR 0x3450
+#define RX_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * RX_RING_CSR.
+ * RXD_SIZE: In unit of 32-bit.
+ */
+#define RX_RING_CSR 0x3454
+#define RX_RING_CSR_RING_SIZE FIELD32(0x000000ff)
+#define RX_RING_CSR_RXD_SIZE FIELD32(0x00003f00)
+#define RX_RING_CSR_RXD_WRITEBACK_SIZE FIELD32(0x00070000)
+
+/*
+ * RX_CNTL_CSR
+ */
+#define RX_CNTL_CSR 0x3458
+#define RX_CNTL_CSR_ENABLE_RX_DMA FIELD32(0x00000001)
+#define RX_CNTL_CSR_LOAD_RXD FIELD32(0x00000002)
+
+/*
+ * RXPTR_CSR: Read-only, for debugging.
+ */
+#define RXPTR_CSR 0x345c
+
+/*
+ * PCI_CFG_CSR
+ */
+#define PCI_CFG_CSR 0x3460
+
+/*
+ * BUF_FORMAT_CSR
+ */
+#define BUF_FORMAT_CSR 0x3464
+
+/*
+ * INT_SOURCE_CSR: Interrupt source register.
+ * Write one to clear corresponding bit.
+ */
+#define INT_SOURCE_CSR 0x3468
+#define INT_SOURCE_CSR_TXDONE FIELD32(0x00000001)
+#define INT_SOURCE_CSR_RXDONE FIELD32(0x00000002)
+#define INT_SOURCE_CSR_BEACON_DONE FIELD32(0x00000004)
+#define INT_SOURCE_CSR_TX_ABORT_DONE FIELD32(0x00000010)
+#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00010000)
+#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00020000)
+#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00040000)
+#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00080000)
+#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00100000)
+#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00200000)
+
+/*
+ * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF.
+ * MITIGATION_PERIOD: Interrupt mitigation in unit of 32 PCI clock.
+ */
+#define INT_MASK_CSR 0x346c
+#define INT_MASK_CSR_TXDONE FIELD32(0x00000001)
+#define INT_MASK_CSR_RXDONE FIELD32(0x00000002)
+#define INT_MASK_CSR_BEACON_DONE FIELD32(0x00000004)
+#define INT_MASK_CSR_TX_ABORT_DONE FIELD32(0x00000010)
+#define INT_MASK_CSR_ENABLE_MITIGATION FIELD32(0x00000080)
+#define INT_MASK_CSR_MITIGATION_PERIOD FIELD32(0x0000ff00)
+#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00010000)
+#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00020000)
+#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00040000)
+#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00080000)
+#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00100000)
+#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00200000)
+
+/*
+ * E2PROM_CSR: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR 0x3470
+#define E2PROM_CSR_RELOAD FIELD32(0x00000001)
+#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000002)
+#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_IN FIELD32(0x00000008)
+#define E2PROM_CSR_DATA_OUT FIELD32(0x00000010)
+#define E2PROM_CSR_TYPE_93C46 FIELD32(0x00000020)
+#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
+
+/*
+ * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
+ * AC0_TX_OP: For AC_BK, in unit of 32us.
+ * AC1_TX_OP: For AC_BE, in unit of 32us.
+ */
+#define AC_TXOP_CSR0 0x3474
+#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
+ * AC2_TX_OP: For AC_VI, in unit of 32us.
+ * AC3_TX_OP: For AC_VO, in unit of 32us.
+ */
+#define AC_TXOP_CSR1 0x3478
+#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000)
+
+/*
+ * DMA_STATUS_CSR
+ */
+#define DMA_STATUS_CSR 0x3480
+
+/*
+ * TEST_MODE_CSR
+ */
+#define TEST_MODE_CSR 0x3484
+
+/*
+ * UART0_TX_CSR
+ */
+#define UART0_TX_CSR 0x3488
+
+/*
+ * UART0_RX_CSR
+ */
+#define UART0_RX_CSR 0x348c
+
+/*
+ * UART0_FRAME_CSR
+ */
+#define UART0_FRAME_CSR 0x3490
+
+/*
+ * UART0_BUFFER_CSR
+ */
+#define UART0_BUFFER_CSR 0x3494
+
+/*
+ * IO_CNTL_CSR
+ */
+#define IO_CNTL_CSR 0x3498
+
+/*
+ * UART_INT_SOURCE_CSR
+ */
+#define UART_INT_SOURCE_CSR 0x34a8
+
+/*
+ * UART_INT_MASK_CSR
+ */
+#define UART_INT_MASK_CSR 0x34ac
+
+/*
+ * PBF_QUEUE_CSR
+ */
+#define PBF_QUEUE_CSR 0x34b0
+
+/*
+ * Firmware DMA registers.
+ * Firmware DMA registers are dedicated for MCU usage
+ * and should not be touched by host driver.
+ * Therefore we skip the definition of these registers.
+ */
+#define FW_TX_BASE_CSR 0x34c0
+#define FW_TX_START_CSR 0x34c4
+#define FW_TX_LAST_CSR 0x34c8
+#define FW_MODE_CNTL_CSR 0x34cc
+#define FW_TXPTR_CSR 0x34d0
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2561 "rt2561.bin"
+#define FIRMWARE_RT2561s "rt2561s.bin"
+#define FIRMWARE_RT2661 "rt2661.bin"
+#define FIRMWARE_IMAGE_BASE 0x4000
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2
+ */
+#define BBP_R2_BG_MODE FIELD8(0x20)
+
+/*
+ * R3
+ */
+#define BBP_R3_SMART_MODE FIELD8(0x01)
+
+/*
+ * R4: RX antenna control
+ * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
+ */
+#define BBP_R4_RX_ANTENNA FIELD8(0x03)
+#define BBP_R4_RX_FRAME_END FIELD8(0x20)
+
+/*
+ * R77
+ */
+#define BBP_R77_PAIR FIELD8(0x03)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * RF 4
+ */
+#define RF4_FREQ_OFFSET FIELD32(0x0003f000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0004
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0006
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x0010
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * ENABLE_DIVERSITY: 1:enable, 0:disable.
+ * EXTERNAL_LNA_BG: External LNA enable for 2.4G.
+ * CARDBUS_ACCEL: 0:enable, 1:disable.
+ * EXTERNAL_LNA_A: External LNA enable for 5G.
+ */
+#define EEPROM_NIC 0x0011
+#define EEPROM_NIC_ENABLE_DIVERSITY FIELD16(0x0001)
+#define EEPROM_NIC_TX_DIVERSITY FIELD16(0x0002)
+#define EEPROM_NIC_TX_RX_FIXED FIELD16(0x000c)
+#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0010)
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0020)
+#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0040)
+
+/*
+ * EEPROM geography.
+ * GEO_A: Default geographical setting for 5GHz band
+ * GEO: Default geographical setting.
+ */
+#define EEPROM_GEOGRAPHY 0x0012
+#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff)
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0013
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11G
+ */
+#define EEPROM_TXPOWER_G_START 0x0023
+#define EEPROM_TXPOWER_G_SIZE 7
+#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_G_2 FIELD16(0xff00)
+
+/*
+ * EEPROM Frequency
+ */
+#define EEPROM_FREQ 0x002f
+#define EEPROM_FREQ_OFFSET FIELD16(0x00ff)
+#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00)
+#define EEPROM_FREQ_SEQ FIELD16(0x0300)
+
+/*
+ * EEPROM LED.
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED 0x0030
+#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A_START 0x0031
+#define EEPROM_TXPOWER_A_SIZE 12
+#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG 0x004d
+#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A 0x004e
+#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00)
+
+/*
+ * MCU mailbox commands.
+ */
+#define MCU_SLEEP 0x30
+#define MCU_WAKEUP 0x31
+#define MCU_LED 0x50
+#define MCU_LED_STRENGTH 0x52
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 16 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 16 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used.
+ * KEY_TABLE: Use per-client pairwise KEY table.
+ * KEY_INDEX:
+ * Key index (0~31) to the pairwise KEY table.
+ * 0~3 to shared KEY table 0 (BSS0).
+ * 4~7 to shared KEY table 1 (BSS1).
+ * 8~11 to shared KEY table 2 (BSS2).
+ * 12~15 to shared KEY table 3 (BSS3).
+ * BURST: Next frame belongs to same "burst" event.
+ */
+#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000004)
+#define TXD_W0_ACK FIELD32(0x00000008)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000010)
+#define TXD_W0_OFDM FIELD32(0x00000020)
+#define TXD_W0_IFS FIELD32(0x00000040)
+#define TXD_W0_RETRY_MODE FIELD32(0x00000080)
+#define TXD_W0_TKIP_MIC FIELD32(0x00000100)
+#define TXD_W0_KEY_TABLE FIELD32(0x00000200)
+#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_BURST FIELD32(0x10000000)
+#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * HOST_Q_ID: EDCA/HCCA queue ID.
+ * HW_SEQUENCE: MAC overwrites the frame sequence number.
+ * BUFFER_COUNT: Number of buffers in this TXD.
+ */
+#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f)
+#define TXD_W1_AIFSN FIELD32(0x000000f0)
+#define TXD_W1_CWMIN FIELD32(0x00000f00)
+#define TXD_W1_CWMAX FIELD32(0x0000f000)
+#define TXD_W1_IV_OFFSET FIELD32(0x003f0000)
+#define TXD_W1_PIGGY_BACK FIELD32(0x01000000)
+#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000)
+#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
+ * TXD_W5_PID_SUBTYPE: Driver assigned packet ID index for txdone handler.
+ * TXD_W5_PID_TYPE: Driver assigned packet ID type for txdone handler.
+ * WAITING_DMA_DONE_INT: TXD been filled with data
+ * and waiting for TxDoneISR housekeeping.
+ */
+#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff)
+#define TXD_W5_PID_SUBTYPE FIELD32(0x00001f00)
+#define TXD_W5_PID_TYPE FIELD32(0x0000e000)
+#define TXD_W5_TX_POWER FIELD32(0x00ff0000)
+#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000)
+
+/*
+ * the above 24-byte is called TXINFO and will be DMAed to MAC block
+ * through TXFIFO. MAC block use this TXINFO to control the transmission
+ * behavior of this frame.
+ * The following fields are not used by MAC block.
+ * They are used by DMA block and HOST driver only.
+ * Once a frame has been DMA to ASIC, all the following fields are useless
+ * to ASIC.
+ */
+
+/*
+ * Word6-10: Buffer physical address
+ */
+#define TXD_W6_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W7_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W8_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W9_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W10_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word11-13: Buffer length
+ */
+#define TXD_W11_BUFFER_LENGTH0 FIELD32(0x00000fff)
+#define TXD_W11_BUFFER_LENGTH1 FIELD32(0x0fff0000)
+#define TXD_W12_BUFFER_LENGTH2 FIELD32(0x00000fff)
+#define TXD_W12_BUFFER_LENGTH3 FIELD32(0x0fff0000)
+#define TXD_W13_BUFFER_LENGTH4 FIELD32(0x00000fff)
+
+/*
+ * Word14
+ */
+#define TXD_W14_SK_BUFFER FIELD32(0xffffffff)
+
+/*
+ * Word15
+ */
+#define TXD_W15_NEXT_SK_BUFFER FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key.
+ * KEY_INDEX: Decryption key actually used.
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_DROP FIELD32(0x00000002)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004)
+#define RXD_W0_MULTICAST FIELD32(0x00000008)
+#define RXD_W0_BROADCAST FIELD32(0x00000010)
+#define RXD_W0_MY_BSS FIELD32(0x00000020)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000040)
+#define RXD_W0_OFDM FIELD32(0x00000080)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300)
+#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * SIGNAL: RX raw data rate reported by BBP.
+ */
+#define RXD_W1_SIGNAL FIELD32(0x000000ff)
+#define RXD_W1_RSSI_AGC FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA FIELD32(0x00006000)
+#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000)
+
+/*
+ * Word2
+ * IV: Received IV of originally encrypted.
+ */
+#define RXD_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * EIV: Received EIV of originally encrypted.
+ */
+#define RXD_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RESERVED FIELD32(0xffffffff)
+
+/*
+ * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
+ * and passed to the HOST driver.
+ * The following fields are for DMA block and HOST usage only.
+ * Can't be touched by ASIC MAC block.
+ */
+
+/*
+ * Word5
+ */
+#define RXD_W5_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word6-15: Reserved
+ */
+#define RXD_W6_RESERVED FIELD32(0xffffffff)
+#define RXD_W7_RESERVED FIELD32(0xffffffff)
+#define RXD_W8_RESERVED FIELD32(0xffffffff)
+#define RXD_W9_RESERVED FIELD32(0xffffffff)
+#define RXD_W10_RESERVED FIELD32(0xffffffff)
+#define RXD_W11_RESERVED FIELD32(0xffffffff)
+#define RXD_W12_RESERVED FIELD32(0xffffffff)
+#define RXD_W13_RESERVED FIELD32(0xffffffff)
+#define RXD_W14_RESERVED FIELD32(0xffffffff)
+#define RXD_W15_RESERVED FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT61PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
new file mode 100644
index 000000000000..3e42759473c3
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -0,0 +1,2110 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt73usb
+ Abstract: rt73usb device specific routines.
+ Supported chipsets: rt2571W & rt2671.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt73usb"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+#include "rt73usb.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt73usb_register_read and rt73usb_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset, u32 *value)
+{
+ __le32 reg;
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(u32), REGISTER_TIMEOUT);
+ *value = le32_to_cpu(reg);
+}
+
+static inline void rt73usb_register_multiread(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ value, length, timeout);
+}
+
+static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset, u32 value)
+{
+ __le32 reg = cpu_to_le32(value);
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(u32), REGISTER_TIMEOUT);
+}
+
+static inline void rt73usb_register_multiwrite(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, length, timeout);
+}
+
+static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_register_read(rt2x00dev, PHY_CSR3, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt73usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+}
+
+static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt73usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt73usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+}
+
+static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+
+ /*
+ * RF5225 and RF2527 contain 21 bits per RF register value,
+ * all others contain 20 bits.
+ */
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+ 20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527)));
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt73usb_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt73usb_read_csr,
+ .write = rt73usb_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt73usb_bbp_read,
+ .write = rt73usb_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt73usb_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(mac[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+ mac[1] = cpu_to_le32(tmp);
+
+ rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(bssid[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
+ bssid[1] = cpu_to_le32(tmp);
+
+ rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ u32 reg;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+ return;
+ }
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
+static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r3;
+ u8 r94;
+ u8 smart;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+ r94 = 6;
+ if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+ r94 += txpower - MAX_TXPOWER;
+ else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+ r94 += txpower;
+ rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ struct rf_channel rf;
+
+ rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+ rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+ rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+ rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+ rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt73usb_bbp_read(rt2x00dev, 4, &r4);
+ rt73usb_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !!(rt2x00dev->curr_hwmode != HWMODE_A));
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt73usb_bbp_write(rt2x00dev, 77, r77);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+ rt73usb_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt73usb_bbp_read(rt2x00dev, 4, &r4);
+ rt73usb_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt73usb_bbp_write(rt2x00dev, 77, r77);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+ rt73usb_bbp_write(rt2x00dev, 4, r4);
+}
+
+struct antenna_sel {
+ u8 word;
+ /*
+ * value[0] -> non-LNA
+ * value[1] -> LNA
+ */
+ u8 value[2];
+};
+
+static const struct antenna_sel antenna_sel_a[] = {
+ { 96, { 0x58, 0x78 } },
+ { 104, { 0x38, 0x48 } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x60, 0x60 } },
+ { 97, { 0x58, 0x58 } },
+ { 98, { 0x58, 0x58 } },
+};
+
+static const struct antenna_sel antenna_sel_bg[] = {
+ { 96, { 0x48, 0x68 } },
+ { 104, { 0x2c, 0x3c } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x50, 0x50 } },
+ { 97, { 0x48, 0x48 } },
+ { 98, { 0x48, 0x48 } },
+};
+
+static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ const struct antenna_sel *sel;
+ unsigned int lna;
+ unsigned int i;
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A) {
+ sel = antenna_sel_a;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
+ } else {
+ sel = antenna_sel_bg;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
+ rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5225))
+ rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+ else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527))
+ rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+}
+
+static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
+ rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
+ rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt73usb_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt73usb_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR14, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
+ rt73usb_register_write(rt2x00dev, MAC_CSR14, reg);
+
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
+ rt2x00_set_field16(&rt2x00dev->led_reg,
+ MCU_LEDCS_LINK_A_STATUS, 1);
+ else
+ rt2x00_set_field16(&rt2x00dev->led_reg,
+ MCU_LEDCS_LINK_BG_STATUS, 1);
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
+ rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
+ rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+ u32 led;
+
+ if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
+ return;
+
+ /*
+ * Led handling requires a positive value for the rssi,
+ * to do that correctly we need to add the correction.
+ */
+ rssi += rt2x00dev->rssi_offset;
+
+ if (rssi <= 30)
+ led = 0;
+ else if (rssi <= 39)
+ led = 1;
+ else if (rssi <= 49)
+ led = 2;
+ else if (rssi <= 53)
+ led = 3;
+ else if (rssi <= 63)
+ led = 4;
+ else
+ led = 5;
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led,
+ rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+/*
+ * Link tuning
+ */
+static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+ rt2x00dev->link.false_cca =
+ rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+}
+
+static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt73usb_bbp_write(rt2x00dev, 17, 0x20);
+ rt2x00dev->link.vgc_level = 0x20;
+}
+
+static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u8 r17;
+ u8 up_bound;
+ u8 low_bound;
+
+ /*
+ * Update Led strength
+ */
+ rt73usb_activity_led(rt2x00dev, rssi);
+
+ rt73usb_bbp_read(rt2x00dev, 17, &r17);
+
+ /*
+ * Determine r17 bounds.
+ */
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ low_bound = 0x28;
+ up_bound = 0x48;
+
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ low_bound += 0x10;
+ up_bound += 0x10;
+ }
+ } else {
+ if (rssi > -82) {
+ low_bound = 0x1c;
+ up_bound = 0x40;
+ } else if (rssi > -84) {
+ low_bound = 0x1c;
+ up_bound = 0x20;
+ } else {
+ low_bound = 0x1c;
+ up_bound = 0x1c;
+ }
+
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ low_bound += 0x14;
+ up_bound += 0x10;
+ }
+ }
+
+ /*
+ * Special big-R17 for very short distance
+ */
+ if (rssi > -35) {
+ if (r17 != 0x60)
+ rt73usb_bbp_write(rt2x00dev, 17, 0x60);
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ if (r17 != up_bound)
+ rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * Special big-R17 for middle-short distance
+ */
+ if (rssi >= -66) {
+ low_bound += 0x10;
+ if (r17 != low_bound)
+ rt73usb_bbp_write(rt2x00dev, 17, low_bound);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ if (r17 != (low_bound + 0x10))
+ rt73usb_bbp_write(rt2x00dev, 17, low_bound + 0x08);
+ return;
+ }
+
+ /*
+ * Special case: Change up_bound based on the rssi.
+ * Lower up_bound when rssi is weaker then -74 dBm.
+ */
+ up_bound -= 2 * (-74 - rssi);
+ if (low_bound > up_bound)
+ up_bound = low_bound;
+
+ if (r17 > up_bound) {
+ rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * r17 does not yet exceed upper limit, continue and base
+ * the r17 tuning on the false CCA count.
+ */
+ if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ r17 += 4;
+ if (r17 > up_bound)
+ r17 = up_bound;
+ rt73usb_bbp_write(rt2x00dev, 17, r17);
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ r17 -= 4;
+ if (r17 < low_bound)
+ r17 = low_bound;
+ rt73usb_bbp_write(rt2x00dev, 17, r17);
+ }
+}
+
+/*
+ * Firmware name function.
+ */
+static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+ return FIRMWARE_RT2571;
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
+ const size_t len)
+{
+ unsigned int i;
+ int status;
+ u32 reg;
+ char *ptr = data;
+ char *cache;
+ int buflen;
+ int timeout;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < 100; i++) {
+ rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg)
+ break;
+ msleep(1);
+ }
+
+ if (!reg) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Write firmware to device.
+ * We setup a seperate cache for this action,
+ * since we are going to write larger chunks of data
+ * then normally used cache size.
+ */
+ cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL);
+ if (!cache) {
+ ERROR(rt2x00dev, "Failed to allocate firmware cache.\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) {
+ buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE);
+ timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32));
+
+ memcpy(cache, ptr, buflen);
+
+ rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT,
+ FIRMWARE_IMAGE_BASE + i, 0x0000,
+ cache, buflen, timeout);
+
+ ptr += buflen;
+ }
+
+ kfree(cache);
+
+ /*
+ * Send firmware request to device to load firmware,
+ * we need to specify a long timeout time.
+ */
+ status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE,
+ 0x0000, USB_MODE_FIRMWARE,
+ REGISTER_TIMEOUT_FIRMWARE);
+ if (status < 0) {
+ ERROR(rt2x00dev, "Failed to write Firmware to device.\n");
+ return status;
+ }
+
+ rt73usb_disable_led(rt2x00dev);
+
+ return 0;
+}
+
+static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ /*
+ * CCK TXD BBP registers
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+ /*
+ * OFDM TXD BBP registers
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+ rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
+ rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+
+ rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+
+ /*
+ * Invalidate all Shared Keys (SEC_CSR0),
+ * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
+ */
+ rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+
+ reg = 0x000023b0;
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527))
+ rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
+ rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+ rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+
+ rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
+ rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
+ rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
+ rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ /*
+ * We must clear the error counters.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+
+ /*
+ * Reset MAC and BBP registers.
+ */
+ rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+ rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ return 0;
+}
+
+static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt73usb_bbp_write(rt2x00dev, 3, 0x80);
+ rt73usb_bbp_write(rt2x00dev, 15, 0x30);
+ rt73usb_bbp_write(rt2x00dev, 21, 0xc8);
+ rt73usb_bbp_write(rt2x00dev, 22, 0x38);
+ rt73usb_bbp_write(rt2x00dev, 23, 0x06);
+ rt73usb_bbp_write(rt2x00dev, 24, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 25, 0x0a);
+ rt73usb_bbp_write(rt2x00dev, 26, 0x0d);
+ rt73usb_bbp_write(rt2x00dev, 32, 0x0b);
+ rt73usb_bbp_write(rt2x00dev, 34, 0x12);
+ rt73usb_bbp_write(rt2x00dev, 37, 0x07);
+ rt73usb_bbp_write(rt2x00dev, 39, 0xf8);
+ rt73usb_bbp_write(rt2x00dev, 41, 0x60);
+ rt73usb_bbp_write(rt2x00dev, 53, 0x10);
+ rt73usb_bbp_write(rt2x00dev, 54, 0x18);
+ rt73usb_bbp_write(rt2x00dev, 60, 0x10);
+ rt73usb_bbp_write(rt2x00dev, 61, 0x04);
+ rt73usb_bbp_write(rt2x00dev, 62, 0x04);
+ rt73usb_bbp_write(rt2x00dev, 75, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 86, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 88, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 90, 0x0f);
+ rt73usb_bbp_write(rt2x00dev, 99, 0x00);
+ rt73usb_bbp_write(rt2x00dev, 102, 0x16);
+ rt73usb_bbp_write(rt2x00dev, 107, 0x04);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt73usb_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt73usb_init_registers(rt2x00dev) ||
+ rt73usb_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ rt2x00usb_enable_radio(rt2x00dev);
+
+ /*
+ * Enable LED
+ */
+ rt73usb_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Disable LED
+ */
+ rt73usb_disable_led(rt2x00dev);
+
+ rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+
+ rt2x00usb_disable_radio(rt2x00dev);
+}
+
+static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char current_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
+ rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
+ rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ current_state =
+ rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+ if (current_state == !put_to_sleep)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state %d.\n", !put_to_sleep, current_state);
+
+ return -EBUSY;
+}
+
+static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt73usb_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt73usb_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt73usb_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt73usb_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_TX_POWER,
+ TXPOWER_TO_DEV(control->power_level));
+ rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
+ rt2x00_desc_write(txd, 5, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_BURST,
+ test_bit(ENTRY_TXD_BURST, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_BURST2,
+ test_bit(ENTRY_TXD_BURST, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+ int maxpacket, struct sk_buff *skb)
+{
+ int length;
+
+ /*
+ * The length _must_ be a multiple of 4,
+ * but it must _not_ be a multiple of the USB packet size.
+ */
+ length = roundup(skb->len, 4);
+ length += (4 * !(length % maxpacket));
+
+ return length;
+}
+
+/*
+ * TX data initialization
+ */
+static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue != IEEE80211_TX_QUEUE_BEACON)
+ return;
+
+ /*
+ * For Wi-Fi faily generated beacons between participating stations.
+ * Set TBTT phase adaptive adjustment step to 8us (default 16us)
+ */
+ rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
+}
+
+/*
+ * RX control handlers
+ */
+static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+ u16 eeprom;
+ u8 offset;
+ u8 lna;
+
+ lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+ switch (lna) {
+ case 3:
+ offset = 90;
+ break;
+ case 2:
+ offset = 74;
+ break;
+ case 1:
+ offset = 64;
+ break;
+ default:
+ return 0;
+ }
+
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ if (lna == 3 || lna == 2)
+ offset += 10;
+ } else {
+ if (lna == 3)
+ offset += 6;
+ else if (lna == 2)
+ offset += 8;
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ offset += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ }
+
+ return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static void rt73usb_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = (struct data_desc *)entry->skb->data;
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+ /*
+ * Pull the skb to clear the descriptor area.
+ */
+ skb_pull(entry->skb, entry->ring->desc_size);
+
+ return;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 word;
+ u8 *mac;
+ s8 value;
+
+ rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5226);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_ACT, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_0, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_1, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_2, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_3, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_4, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
+ LED_MODE_DEFAULT);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
+ EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ }
+
+ return 0;
+}
+
+static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
+
+ if (!rt2x00_rev(&rt2x00dev->chip, 0x25730)) {
+ ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ return -ENODEV;
+ }
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2528) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5225) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Read the Frame type.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
+ __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+
+ /*
+ * Read frequency offset.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+ /*
+ * Read external LNA informations.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) {
+ __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ }
+
+ /*
+ * Store led settings, for correct led behaviour.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
+
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
+ rt2x00dev->led_mode);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_0));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_1));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_2));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_3));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_4));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+ rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_G));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_A));
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2528
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2528[] = {
+ { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b },
+ { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f },
+ { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b },
+ { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f },
+ { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b },
+ { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f },
+ { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b },
+ { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f },
+ { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b },
+ { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f },
+ { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b },
+ { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f },
+ { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b },
+ { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 },
+};
+
+/*
+ * RF value list for RF5226
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5226[] = {
+ { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b },
+ { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f },
+ { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b },
+ { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f },
+ { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b },
+ { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f },
+ { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b },
+ { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f },
+ { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b },
+ { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f },
+ { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b },
+ { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f },
+ { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b },
+ { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002c0c, 0x0000099a, 0x00098255, 0x000fea23 },
+ { 40, 0x00002c0c, 0x000009a2, 0x00098255, 0x000fea03 },
+ { 44, 0x00002c0c, 0x000009a6, 0x00098255, 0x000fea0b },
+ { 48, 0x00002c0c, 0x000009aa, 0x00098255, 0x000fea13 },
+ { 52, 0x00002c0c, 0x000009ae, 0x00098255, 0x000fea1b },
+ { 56, 0x00002c0c, 0x000009b2, 0x00098255, 0x000fea23 },
+ { 60, 0x00002c0c, 0x000009ba, 0x00098255, 0x000fea03 },
+ { 64, 0x00002c0c, 0x000009be, 0x00098255, 0x000fea0b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002c0c, 0x00000a2a, 0x000b8255, 0x000fea03 },
+ { 104, 0x00002c0c, 0x00000a2e, 0x000b8255, 0x000fea0b },
+ { 108, 0x00002c0c, 0x00000a32, 0x000b8255, 0x000fea13 },
+ { 112, 0x00002c0c, 0x00000a36, 0x000b8255, 0x000fea1b },
+ { 116, 0x00002c0c, 0x00000a3a, 0x000b8255, 0x000fea23 },
+ { 120, 0x00002c0c, 0x00000a82, 0x000b8255, 0x000fea03 },
+ { 124, 0x00002c0c, 0x00000a86, 0x000b8255, 0x000fea0b },
+ { 128, 0x00002c0c, 0x00000a8a, 0x000b8255, 0x000fea13 },
+ { 132, 0x00002c0c, 0x00000a8e, 0x000b8255, 0x000fea1b },
+ { 136, 0x00002c0c, 0x00000a92, 0x000b8255, 0x000fea23 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002c0c, 0x00000a9a, 0x000b8255, 0x000fea03 },
+ { 149, 0x00002c0c, 0x00000aa2, 0x000b8255, 0x000fea1f },
+ { 153, 0x00002c0c, 0x00000aa6, 0x000b8255, 0x000fea27 },
+ { 157, 0x00002c0c, 0x00000aae, 0x000b8255, 0x000fea07 },
+ { 161, 0x00002c0c, 0x00000ab2, 0x000b8255, 0x000fea0f },
+ { 165, 0x00002c0c, 0x00000ab6, 0x000b8255, 0x000fea17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002c0c, 0x0008099a, 0x000da255, 0x000d3a0b },
+ { 38, 0x00002c0c, 0x0008099e, 0x000da255, 0x000d3a13 },
+ { 42, 0x00002c0c, 0x000809a2, 0x000da255, 0x000d3a1b },
+ { 46, 0x00002c0c, 0x000809a6, 0x000da255, 0x000d3a23 },
+};
+
+/*
+ * RF value list for RF5225 & RF2527
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5225_2527[] = {
+ { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+ { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+ { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+ { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+ { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+ { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+ { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+ { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+ { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+ { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+ { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+ { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+ { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+ { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
+ { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
+ { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
+ { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
+ { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
+ { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
+ { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
+ { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
+ { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
+ { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
+ { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
+ { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
+ { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
+ { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
+ { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
+ { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
+ { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
+ { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
+ { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
+ { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
+ { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
+ { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
+ { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
+ { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
+ { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
+};
+
+
+static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 5;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
+ spec->channels = rf_vals_bg_2528;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5226);
+ spec->channels = rf_vals_5226;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_5225_2527;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
+ spec->channels = rf_vals_5225_2527;
+ }
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+ spec->num_modes = 3;
+
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ spec->tx_power_a = txpower;
+ }
+}
+
+static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt73usb_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt73usb_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt73usb_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires firmware
+ */
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt73usb_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ return;
+ }
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
+ rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ return 0;
+}
+
+#if 0
+/*
+ * Mac80211 demands get_tsf must be atomic.
+ * This is not possible for rt73usb since all register access
+ * functions require sleeping. Untill mac80211 no longer needs
+ * get_tsf to be atomic, this function should be disabled.
+ */
+static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
+ rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
+
+ return tsf;
+}
+#else
+#define rt73usb_get_tsf NULL
+#endif
+
+static void rt73usb_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0);
+}
+
+static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int timeout;
+
+ /*
+ * Just in case the ieee80211 doesn't set this,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * First we create the beacon.
+ */
+ skb_push(skb, TXD_DESC_SIZE);
+ memset(skb->data, 0, TXD_DESC_SIZE);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ TXD_DESC_SIZE),
+ skb->len - TXD_DESC_SIZE, control);
+
+ /*
+ * Write entire beacon with descriptor to register,
+ * and kick the beacon generator.
+ */
+ timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
+ rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT,
+ HW_BEACON_BASE0, 0x0000,
+ skb->data, skb->len, timeout);
+ rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rt73usb_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt73usb_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt73usb_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt73usb_get_tsf,
+ .reset_tsf = rt73usb_reset_tsf,
+ .beacon_update = rt73usb_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
+ .probe_hw = rt73usb_probe_hw,
+ .get_firmware_name = rt73usb_get_firmware_name,
+ .load_firmware = rt73usb_load_firmware,
+ .initialize = rt2x00usb_initialize,
+ .uninitialize = rt2x00usb_uninitialize,
+ .set_device_state = rt73usb_set_device_state,
+ .link_stats = rt73usb_link_stats,
+ .reset_tuner = rt73usb_reset_tuner,
+ .link_tuner = rt73usb_link_tuner,
+ .write_tx_desc = rt73usb_write_tx_desc,
+ .write_tx_data = rt2x00usb_write_tx_data,
+ .get_tx_data_len = rt73usb_get_tx_data_len,
+ .kick_tx_queue = rt73usb_kick_tx_queue,
+ .fill_rxdone = rt73usb_fill_rxdone,
+ .config_mac_addr = rt73usb_config_mac_addr,
+ .config_bssid = rt73usb_config_bssid,
+ .config_type = rt73usb_config_type,
+ .config_preamble = rt73usb_config_preamble,
+ .config = rt73usb_config,
+};
+
+static const struct rt2x00_ops rt73usb_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt73usb_rt2x00_ops,
+ .hw = &rt73usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt73usb_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt73usb module information.
+ */
+static struct usb_device_id rt73usb_device_table[] = {
+ /* AboCom */
+ { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Askey */
+ { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Belkin */
+ { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Billionton */
+ { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Buffalo */
+ { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* CNet */
+ { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Conceptronic */
+ { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* D-Link */
+ { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Gemtek */
+ { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Gigabyte */
+ { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Huawei-3Com */
+ { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Hercules */
+ { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Linksys */
+ { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* MSI */
+ { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Qcom */
+ { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Senao */
+ { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Sitecom */
+ { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Surecom */
+ { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Planex */
+ { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT73 USB Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2571W & RT2671 USB chipset based cards");
+MODULE_DEVICE_TABLE(usb, rt73usb_device_table);
+MODULE_FIRMWARE(FIRMWARE_RT2571);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver rt73usb_driver = {
+ .name = DRV_NAME,
+ .id_table = rt73usb_device_table,
+ .probe = rt2x00usb_probe,
+ .disconnect = rt2x00usb_disconnect,
+ .suspend = rt2x00usb_suspend,
+ .resume = rt2x00usb_resume,
+};
+
+static int __init rt73usb_init(void)
+{
+ return usb_register(&rt73usb_driver);
+}
+
+static void __exit rt73usb_exit(void)
+{
+ usb_deregister(&rt73usb_driver);
+}
+
+module_init(rt73usb_init);
+module_exit(rt73usb_exit);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
new file mode 100644
index 000000000000..f0951519f74b
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -0,0 +1,1024 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt73usb
+ Abstract: Data structures and registers for the rt73usb module.
+ Supported chipsets: rt2571W & rt2671.
+ */
+
+#ifndef RT73USB_H
+#define RT73USB_H
+
+/*
+ * RF chip defines.
+ */
+#define RF5226 0x0001
+#define RF2528 0x0002
+#define RF5225 0x0003
+#define RF2527 0x0004
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x3000
+#define CSR_REG_SIZE 0x04b0
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0100
+#define BBP_SIZE 0x0080
+#define RF_SIZE 0x0014
+
+/*
+ * USB registers.
+ */
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE FIELD16(0x001f)
+#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020)
+#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040)
+#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080)
+#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100)
+#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200)
+#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400)
+#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800)
+#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000)
+#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000)
+#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000)
+#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000)
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2571 "rt73.bin"
+#define FIRMWARE_IMAGE_BASE 0x0800
+
+/*
+ * Security key table memory.
+ * 16 entries 32-byte for shared key table
+ * 64 entries 32-byte for pairwise key table
+ * 64 entries 8-byte for pairwise ta key table
+ */
+#define SHARED_KEY_TABLE_BASE 0x1000
+#define PAIRWISE_KEY_TABLE_BASE 0x1200
+#define PAIRWISE_TA_TABLE_BASE 0x1a00
+
+struct hw_key_entry {
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct hw_pairwise_ta_entry {
+ u8 address[6];
+ u8 reserved[2];
+} __attribute__ ((packed));
+
+/*
+ * Since NULL frame won't be that long (256 byte),
+ * We steal 16 tail bytes to save debugging settings.
+ */
+#define HW_DEBUG_SETTING_BASE 0x2bf0
+
+/*
+ * On-chip BEACON frame space.
+ */
+#define HW_BEACON_BASE0 0x2400
+#define HW_BEACON_BASE1 0x2500
+#define HW_BEACON_BASE2 0x2600
+#define HW_BEACON_BASE3 0x2700
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0 0x3000
+
+/*
+ * MAC_CSR1: System control register.
+ * SOFT_RESET: Software reset bit, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset BBP.
+ * HOST_READY: Host is ready after initialization, 1: ready.
+ */
+#define MAC_CSR1 0x3004
+#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001)
+#define MAC_CSR1_BBP_RESET FIELD32(0x00000002)
+#define MAC_CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2 0x3008
+#define MAC_CSR2_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR2_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3 0x300c
+#define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR4: BSSID register 0.
+ */
+#define MAC_CSR4 0x3010
+#define MAC_CSR4_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR4_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR5: BSSID register 1.
+ * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ */
+#define MAC_CSR5 0x3014
+#define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR6: Maximum frame length register.
+ */
+#define MAC_CSR6 0x3018
+#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff)
+
+/*
+ * MAC_CSR7: Reserved
+ */
+#define MAC_CSR7 0x301c
+
+/*
+ * MAC_CSR8: SIFS/EIFS register.
+ * All units are in US.
+ */
+#define MAC_CSR8 0x3020
+#define MAC_CSR8_SIFS FIELD32(0x000000ff)
+#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00)
+#define MAC_CSR8_EIFS FIELD32(0xffff0000)
+
+/*
+ * MAC_CSR9: Back-Off control register.
+ * SLOT_TIME: Slot time, default is 20us for 802.11BG.
+ * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1).
+ * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1).
+ * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD.
+ */
+#define MAC_CSR9 0x3024
+#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff)
+#define MAC_CSR9_CWMIN FIELD32(0x00000f00)
+#define MAC_CSR9_CWMAX FIELD32(0x0000f000)
+#define MAC_CSR9_CW_SELECT FIELD32(0x00010000)
+
+/*
+ * MAC_CSR10: Power state configuration.
+ */
+#define MAC_CSR10 0x3028
+
+/*
+ * MAC_CSR11: Power saving transition time register.
+ * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * WAKEUP_LATENCY: In unit of TU.
+ */
+#define MAC_CSR11 0x302c
+#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff)
+#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00)
+#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000)
+#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000)
+
+/*
+ * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1).
+ * CURRENT_STATE: 0:sleep, 1:awake.
+ * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP.
+ * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake.
+ */
+#define MAC_CSR12 0x3030
+#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001)
+#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002)
+#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004)
+#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008)
+
+/*
+ * MAC_CSR13: GPIO.
+ */
+#define MAC_CSR13 0x3034
+
+/*
+ * MAC_CSR14: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON.
+ * SW_LED: s/w LED, 1: ON, 0: OFF.
+ * HW_LED_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR14 0x3038
+#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff)
+#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00)
+#define MAC_CSR14_HW_LED FIELD32(0x00010000)
+#define MAC_CSR14_SW_LED FIELD32(0x00020000)
+#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000)
+#define MAC_CSR14_SW_LED2 FIELD32(0x00080000)
+
+/*
+ * MAC_CSR15: NAV control.
+ */
+#define MAC_CSR15 0x303c
+
+/*
+ * TXRX control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: TX/RX configuration register.
+ * TSF_OFFSET: Default is 24.
+ * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame.
+ * DISABLE_RX: Disable Rx engine.
+ * DROP_CRC: Drop CRC error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TO_DS: Drop fram ToDs bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MULTICAST: Drop multicast frames.
+ * DROP_BORADCAST: Drop broadcast frames.
+ * ROP_ACK_CTS: Drop received ACK and CTS.
+ */
+#define TXRX_CSR0 0x3040
+#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00)
+#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000)
+#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000)
+#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000)
+#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000)
+#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000)
+#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000)
+#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000)
+#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000)
+#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000)
+#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000)
+#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000)
+
+/*
+ * TXRX_CSR1
+ */
+#define TXRX_CSR1 0x3044
+#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR2
+ */
+#define TXRX_CSR2 0x3048
+#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR3
+ */
+#define TXRX_CSR3 0x304c
+#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR4: Auto-Responder/Tx-retry register.
+ * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble.
+ * OFDM_TX_RATE_DOWN: 1:enable.
+ * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step.
+ * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M.
+ */
+#define TXRX_CSR4 0x3050
+#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff)
+#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700)
+#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000)
+#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000)
+#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000)
+#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000)
+#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000)
+#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000)
+#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000)
+#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000)
+
+/*
+ * TXRX_CSR5
+ */
+#define TXRX_CSR5 0x3054
+
+/*
+ * TXRX_CSR6: ACK/CTS payload consumed time
+ */
+#define TXRX_CSR6 0x3058
+
+/*
+ * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define TXRX_CSR7 0x305c
+#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff)
+#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00)
+#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000)
+#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define TXRX_CSR8 0x3060
+#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff)
+#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00)
+#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000)
+#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR9: Synchronization control register.
+ * BEACON_INTERVAL: In unit of 1/16 TU.
+ * TSF_TICKING: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR9 0x3064
+#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000)
+#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000)
+#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000)
+#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000)
+#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR10: BEACON alignment.
+ */
+#define TXRX_CSR10 0x3068
+
+/*
+ * TXRX_CSR11: AES mask.
+ */
+#define TXRX_CSR11 0x306c
+
+/*
+ * TXRX_CSR12: TSF low 32.
+ */
+#define TXRX_CSR12 0x3070
+#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR13: TSF high 32.
+ */
+#define TXRX_CSR13 0x3074
+#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR14: TBTT timer.
+ */
+#define TXRX_CSR14 0x3078
+
+/*
+ * TXRX_CSR15: TKIP MIC priority byte "AND" mask.
+ */
+#define TXRX_CSR15 0x307c
+
+/*
+ * PHY control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PHY_CSR0: RF/PS control.
+ */
+#define PHY_CSR0 0x3080
+#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000)
+#define PHY_CSR0_PA_PE_A FIELD32(0x00020000)
+
+/*
+ * PHY_CSR1
+ */
+#define PHY_CSR1 0x3084
+#define PHY_CSR1_RF_RPI FIELD32(0x00010000)
+
+/*
+ * PHY_CSR2: Pre-TX BBP control.
+ */
+#define PHY_CSR2 0x3088
+
+/*
+ * PHY_CSR3: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REG_NUM: Selected BBP register.
+ * READ_CONTROL: 0: Write BBP, 1: Read BBP.
+ * BUSY: 1: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR3 0x308c
+#define PHY_CSR3_VALUE FIELD32(0x000000ff)
+#define PHY_CSR3_REGNUM FIELD32(0x00007f00)
+#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000)
+#define PHY_CSR3_BUSY FIELD32(0x00010000)
+
+/*
+ * PHY_CSR4: RF serial control register
+ * VALUE: Register value (include register id) serial out to RF/IF chip.
+ * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22).
+ * IF_SELECT: 1: select IF to program, 0: select RF to program.
+ * PLL_LD: RF PLL_LD status.
+ * BUSY: 1: ASIC is busy execute RF programming.
+ */
+#define PHY_CSR4 0x3090
+#define PHY_CSR4_VALUE FIELD32(0x00ffffff)
+#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define PHY_CSR4_IF_SELECT FIELD32(0x20000000)
+#define PHY_CSR4_PLL_LD FIELD32(0x40000000)
+#define PHY_CSR4_BUSY FIELD32(0x80000000)
+
+/*
+ * PHY_CSR5: RX to TX signal switch timing control.
+ */
+#define PHY_CSR5 0x3094
+#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR6: TX to RX signal timing control.
+ */
+#define PHY_CSR6 0x3098
+#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR7: TX DAC switching timing control.
+ */
+#define PHY_CSR7 0x309c
+
+/*
+ * Security control register.
+ */
+
+/*
+ * SEC_CSR0: Shared key table control.
+ */
+#define SEC_CSR0 0x30a0
+#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001)
+#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002)
+#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004)
+#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008)
+#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010)
+#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020)
+#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040)
+#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080)
+#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100)
+#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200)
+#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400)
+#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800)
+#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000)
+#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000)
+#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000)
+#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000)
+
+/*
+ * SEC_CSR1: Shared key table security mode register.
+ */
+#define SEC_CSR1 0x30a4
+#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * Pairwise key table valid bitmap registers.
+ * SEC_CSR2: pairwise key table valid bitmap 0.
+ * SEC_CSR3: pairwise key table valid bitmap 1.
+ */
+#define SEC_CSR2 0x30a8
+#define SEC_CSR3 0x30ac
+
+/*
+ * SEC_CSR4: Pairwise key table lookup control.
+ */
+#define SEC_CSR4 0x30b0
+
+/*
+ * SEC_CSR5: shared key table security mode register.
+ */
+#define SEC_CSR5 0x30b4
+#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * STA control registers.
+ */
+
+/*
+ * STA_CSR0: RX PLCP error count & RX FCS error count.
+ */
+#define STA_CSR0 0x30c0
+#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff)
+#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR1: RX False CCA count & RX LONG frame count.
+ */
+#define STA_CSR1 0x30c4
+#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff)
+#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR2: TX Beacon count and RX FIFO overflow count.
+ */
+#define STA_CSR2 0x30c8
+#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff)
+#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000)
+
+/*
+ * STA_CSR3: TX Beacon count.
+ */
+#define STA_CSR3 0x30cc
+#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff)
+
+/*
+ * STA_CSR4: TX Retry count.
+ */
+#define STA_CSR4 0x30d0
+#define STA_CSR4_TX_NO_RETRY_COUNT FIELD32(0x0000ffff)
+#define STA_CSR4_TX_ONE_RETRY_COUNT FIELD32(0xffff0000)
+
+/*
+ * STA_CSR5: TX Retry count.
+ */
+#define STA_CSR5 0x30d4
+#define STA_CSR4_TX_MULTI_RETRY_COUNT FIELD32(0x0000ffff)
+#define STA_CSR4_TX_RETRY_FAIL_COUNT FIELD32(0xffff0000)
+
+/*
+ * QOS control registers.
+ */
+
+/*
+ * QOS_CSR1: TXOP holder MAC address register.
+ */
+#define QOS_CSR1 0x30e4
+#define QOS_CSR1_BYTE4 FIELD32(0x000000ff)
+#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * QOS_CSR2: TXOP holder timeout register.
+ */
+#define QOS_CSR2 0x30e8
+
+/*
+ * RX QOS-CFPOLL MAC address register.
+ * QOS_CSR3: RX QOS-CFPOLL MAC address 0.
+ * QOS_CSR4: RX QOS-CFPOLL MAC address 1.
+ */
+#define QOS_CSR3 0x30ec
+#define QOS_CSR4 0x30f0
+
+/*
+ * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL.
+ */
+#define QOS_CSR5 0x30f4
+
+/*
+ * WMM Scheduler Register
+ */
+
+/*
+ * AIFSN_CSR: AIFSN for each EDCA AC.
+ * AIFSN0: For AC_BK.
+ * AIFSN1: For AC_BE.
+ * AIFSN2: For AC_VI.
+ * AIFSN3: For AC_VO.
+ */
+#define AIFSN_CSR 0x0400
+#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
+#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0)
+#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00)
+#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000)
+
+/*
+ * CWMIN_CSR: CWmin for each EDCA AC.
+ * CWMIN0: For AC_BK.
+ * CWMIN1: For AC_BE.
+ * CWMIN2: For AC_VI.
+ * CWMIN3: For AC_VO.
+ */
+#define CWMIN_CSR 0x0404
+#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
+#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0)
+#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00)
+#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000)
+
+/*
+ * CWMAX_CSR: CWmax for each EDCA AC.
+ * CWMAX0: For AC_BK.
+ * CWMAX1: For AC_BE.
+ * CWMAX2: For AC_VI.
+ * CWMAX3: For AC_VO.
+ */
+#define CWMAX_CSR 0x0408
+#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
+#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0)
+#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00)
+#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)
+
+/*
+ * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
+ * AC0_TX_OP: For AC_BK, in unit of 32us.
+ * AC1_TX_OP: For AC_BE, in unit of 32us.
+ */
+#define AC_TXOP_CSR0 0x040c
+#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
+ * AC2_TX_OP: For AC_VI, in unit of 32us.
+ * AC3_TX_OP: For AC_VO, in unit of 32us.
+ */
+#define AC_TXOP_CSR1 0x0410
+#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000)
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2
+ */
+#define BBP_R2_BG_MODE FIELD8(0x20)
+
+/*
+ * R3
+ */
+#define BBP_R3_SMART_MODE FIELD8(0x01)
+
+/*
+ * R4: RX antenna control
+ * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
+ */
+#define BBP_R4_RX_ANTENNA FIELD8(0x03)
+#define BBP_R4_RX_FRAME_END FIELD8(0x20)
+
+/*
+ * R77
+ */
+#define BBP_R77_PAIR FIELD8(0x03)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * RF 4
+ */
+#define RF4_FREQ_OFFSET FIELD32(0x0003f000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x0010
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * EXTERNAL_LNA: External LNA.
+ */
+#define EEPROM_NIC 0x0011
+#define EEPROM_NIC_EXTERNAL_LNA FIELD16(0x0010)
+
+/*
+ * EEPROM geography.
+ * GEO_A: Default geographical setting for 5GHz band
+ * GEO: Default geographical setting.
+ */
+#define EEPROM_GEOGRAPHY 0x0012
+#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff)
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0013
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11G
+ */
+#define EEPROM_TXPOWER_G_START 0x0023
+#define EEPROM_TXPOWER_G_SIZE 7
+#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_G_2 FIELD16(0xff00)
+
+/*
+ * EEPROM Frequency
+ */
+#define EEPROM_FREQ 0x002f
+#define EEPROM_FREQ_OFFSET FIELD16(0x00ff)
+#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00)
+#define EEPROM_FREQ_SEQ FIELD16(0x0300)
+
+/*
+ * EEPROM LED.
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED 0x0030
+#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A_START 0x0031
+#define EEPROM_TXPOWER_A_SIZE 12
+#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG 0x004d
+#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A 0x004e
+#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 6 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 6 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ * BURST: Next frame belongs to same "burst" event.
+ * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used.
+ * KEY_TABLE: Use per-client pairwise KEY table.
+ * KEY_INDEX:
+ * Key index (0~31) to the pairwise KEY table.
+ * 0~3 to shared KEY table 0 (BSS0).
+ * 4~7 to shared KEY table 1 (BSS1).
+ * 8~11 to shared KEY table 2 (BSS2).
+ * 12~15 to shared KEY table 3 (BSS3).
+ * BURST2: For backward compatibility, set to same value as BURST.
+ */
+#define TXD_W0_BURST FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000004)
+#define TXD_W0_ACK FIELD32(0x00000008)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000010)
+#define TXD_W0_OFDM FIELD32(0x00000020)
+#define TXD_W0_IFS FIELD32(0x00000040)
+#define TXD_W0_RETRY_MODE FIELD32(0x00000080)
+#define TXD_W0_TKIP_MIC FIELD32(0x00000100)
+#define TXD_W0_KEY_TABLE FIELD32(0x00000200)
+#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_BURST2 FIELD32(0x10000000)
+#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * HOST_Q_ID: EDCA/HCCA queue ID.
+ * HW_SEQUENCE: MAC overwrites the frame sequence number.
+ * BUFFER_COUNT: Number of buffers in this TXD.
+ */
+#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f)
+#define TXD_W1_AIFSN FIELD32(0x000000f0)
+#define TXD_W1_CWMIN FIELD32(0x00000f00)
+#define TXD_W1_CWMAX FIELD32(0x0000f000)
+#define TXD_W1_IV_OFFSET FIELD32(0x003f0000)
+#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000)
+#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
+ * PACKET_ID: Driver assigned packet ID to categorize TXResult in interrupt.
+ * WAITING_DMA_DONE_INT: TXD been filled with data
+ * and waiting for TxDoneISR housekeeping.
+ */
+#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff)
+#define TXD_W5_PACKET_ID FIELD32(0x0000ff00)
+#define TXD_W5_TX_POWER FIELD32(0x00ff0000)
+#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key.
+ * KEY_INDEX: Decryption key actually used.
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_DROP FIELD32(0x00000002)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004)
+#define RXD_W0_MULTICAST FIELD32(0x00000008)
+#define RXD_W0_BROADCAST FIELD32(0x00000010)
+#define RXD_W0_MY_BSS FIELD32(0x00000020)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000040)
+#define RXD_W0_OFDM FIELD32(0x00000080)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300)
+#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * WORD1
+ * SIGNAL: RX raw data rate reported by BBP.
+ * RSSI: RSSI reported by BBP.
+ */
+#define RXD_W1_SIGNAL FIELD32(0x000000ff)
+#define RXD_W1_RSSI_AGC FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA FIELD32(0x00006000)
+#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000)
+
+/*
+ * Word2
+ * IV: Received IV of originally encrypted.
+ */
+#define RXD_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * EIV: Received EIV of originally encrypted.
+ */
+#define RXD_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RESERVED FIELD32(0xffffffff)
+
+/*
+ * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
+ * and passed to the HOST driver.
+ * The following fields are for DMA block and HOST usage only.
+ * Can't be touched by ASIC MAC block.
+ */
+
+/*
+ * Word5
+ */
+#define RXD_W5_RESERVED FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT73USB_H */
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 6124e467b156..6ad322ef0da1 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -36,8 +36,7 @@ struct rtl8187_rx_info {
};
struct rtl8187_rx_hdr {
- __le16 len;
- __le16 rate;
+ __le32 flags;
u8 noise;
u8 signal;
u8 agc;
@@ -67,13 +66,14 @@ struct rtl8187_priv {
struct rtl818x_csr *map;
void (*rf_init)(struct ieee80211_hw *);
int mode;
+ int if_id;
/* rtl8187 specific */
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
struct ieee80211_hw_mode modes[2];
struct usb_device *udev;
- u8 *hwaddr;
+ u32 rx_conf;
u16 txpwr_base;
u8 asic_rev;
struct sk_buff_head rx_queue;
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index cea85894b7f2..0ef887dd2867 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -36,11 +36,64 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
/* Netgear */
{USB_DEVICE(0x0846, 0x6100)},
{USB_DEVICE(0x0846, 0x6a00)},
+ /* HP */
+ {USB_DEVICE(0x03f0, 0xca02)},
{}
};
MODULE_DEVICE_TABLE(usb, rtl8187_table);
+static void rtl8187_iowrite_async_cb(struct urb *urb)
+{
+ kfree(urb->context);
+ usb_free_urb(urb);
+}
+
+static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
+ void *data, u16 len)
+{
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct rtl8187_async_write_data {
+ u8 data[4];
+ struct usb_ctrlrequest dr;
+ } *buf;
+
+ buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+ if (!buf)
+ return;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ kfree(buf);
+ return;
+ }
+
+ dr = &buf->dr;
+
+ dr->bRequestType = RTL8187_REQT_WRITE;
+ dr->bRequest = RTL8187_REQ_SET_REG;
+ dr->wValue = addr;
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(len);
+
+ memcpy(buf, data, len);
+
+ usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ (unsigned char *)dr, buf, len,
+ rtl8187_iowrite_async_cb, buf);
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
+ __le32 *addr, u32 val)
+{
+ __le32 buf = cpu_to_le32(val);
+
+ rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr),
+ &buf, sizeof(buf));
+}
+
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
{
struct rtl8187_priv *priv = dev->priv;
@@ -96,7 +149,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
tmp |= RTL8187_TX_FLAG_RTS;
hdr->rts_duration =
- ieee80211_rts_duration(dev, skb->len, control);
+ ieee80211_rts_duration(dev, priv->if_id, skb->len, control);
}
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
tmp |= RTL8187_TX_FLAG_CTS;
@@ -125,6 +178,7 @@ static void rtl8187_rx_cb(struct urb *urb)
struct rtl8187_rx_hdr *hdr;
struct ieee80211_rx_status rx_status = { 0 };
int rate, signal;
+ u32 flags;
spin_lock(&priv->rx_queue.lock);
if (skb->next)
@@ -143,10 +197,11 @@ static void rtl8187_rx_cb(struct urb *urb)
skb_put(skb, urb->actual_length);
hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
- skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+ flags = le32_to_cpu(hdr->flags);
+ skb_trim(skb, flags & 0x0FFF);
signal = hdr->agc >> 1;
- rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+ rate = (flags >> 20) & 0xF;
if (rate > 3) { /* OFDM rate */
if (signal > 90)
signal = 90;
@@ -169,6 +224,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rx_status.channel = dev->conf.channel;
rx_status.phymode = dev->conf.phymode;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
+ if (flags & (1 << 13))
+ rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
ieee80211_rx_irqsafe(dev, skb, &rx_status);
skb = dev_alloc_skb(RTL8187_MAX_RX);
@@ -293,8 +350,6 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
- for (i = 0; i < ETH_ALEN; i++)
- rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
@@ -365,7 +420,7 @@ static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
}
-static int rtl8187_open(struct ieee80211_hw *dev)
+static int rtl8187_start(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
u32 reg;
@@ -383,16 +438,13 @@ static int rtl8187_open(struct ieee80211_hw *dev)
RTL818X_RX_CONF_RX_AUTORESETPHY |
RTL818X_RX_CONF_BSSID |
RTL818X_RX_CONF_MGMT |
- RTL818X_RX_CONF_CTRL |
RTL818X_RX_CONF_DATA |
(7 << 13 /* RX FIFO threshold NONE */) |
(7 << 10 /* MAX RX DMA */) |
RTL818X_RX_CONF_BROADCAST |
- RTL818X_RX_CONF_MULTICAST |
RTL818X_RX_CONF_NICMAC;
- if (priv->mode == IEEE80211_IF_TYPE_MNTR)
- reg |= RTL818X_RX_CONF_MONITOR;
+ priv->rx_conf = reg;
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
@@ -419,7 +471,7 @@ static int rtl8187_open(struct ieee80211_hw *dev)
return 0;
}
-static int rtl8187_stop(struct ieee80211_hw *dev)
+static void rtl8187_stop(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
struct rtl8187_rx_info *info;
@@ -445,28 +497,31 @@ static int rtl8187_stop(struct ieee80211_hw *dev)
usb_kill_urb(info->urb);
kfree_skb(skb);
}
- return 0;
+ return;
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
+ int i;
- /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
- if (priv->mode != IEEE80211_IF_TYPE_MGMT)
- return -1;
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
switch (conf->type) {
case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_MNTR:
priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}
- priv->hwaddr = conf->mac_addr;
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ for (i = 0; i < ETH_ALEN; i++)
+ rtl818x_iowrite8(priv, &priv->map->MAC[i],
+ ((u8 *)conf->mac_addr)[i]);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
return 0;
}
@@ -475,7 +530,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_MGMT;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
}
static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -510,6 +565,8 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
struct rtl8187_priv *priv = dev->priv;
int i;
+ priv->if_id = if_id;
+
for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
@@ -521,14 +578,52 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
return 0;
}
+static void rtl8187_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ *total_flags = 0;
+
+ if (changed_flags & FIF_PROMISC_IN_BSS)
+ priv->rx_conf ^= RTL818X_RX_CONF_NICMAC;
+ if (changed_flags & FIF_ALLMULTI)
+ priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST;
+ if (changed_flags & FIF_FCSFAIL)
+ priv->rx_conf ^= RTL818X_RX_CONF_FCS;
+ if (changed_flags & FIF_CONTROL)
+ priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
+ if (changed_flags & FIF_OTHER_BSS)
+ priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
+
+ if (mc_count > 0)
+ priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
+
+ if (priv->rx_conf & RTL818X_RX_CONF_NICMAC)
+ *total_flags |= FIF_PROMISC_IN_BSS;
+ if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST)
+ *total_flags |= FIF_ALLMULTI;
+ if (priv->rx_conf & RTL818X_RX_CONF_FCS)
+ *total_flags |= FIF_FCSFAIL;
+ if (priv->rx_conf & RTL818X_RX_CONF_CTRL)
+ *total_flags |= FIF_CONTROL;
+ if (priv->rx_conf & RTL818X_RX_CONF_MONITOR)
+ *total_flags |= FIF_OTHER_BSS;
+
+ rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
+}
+
static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx,
- .open = rtl8187_open,
+ .start = rtl8187_start,
.stop = rtl8187_stop,
.add_interface = rtl8187_add_interface,
.remove_interface = rtl8187_remove_interface,
.config = rtl8187_config,
.config_interface = rtl8187_config_interface,
+ .configure_filter = rtl8187_configure_filter,
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -572,6 +667,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
struct ieee80211_channel *channel;
u16 txpwr, reg;
int err, i;
+ DECLARE_MAC_BUF(mac);
dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
if (!dev) {
@@ -601,11 +697,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
priv->modes[1].rates = priv->rates;
priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
priv->modes[1].channels = priv->channels;
- priv->mode = IEEE80211_IF_TYPE_MGMT;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_WEP_INCLUDE_IV |
- IEEE80211_HW_DATA_NULLFUNC_ACK;
+ IEEE80211_HW_RX_INCLUDES_FCS;
dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
dev->queues = 1;
dev->max_rssi = 65;
@@ -681,8 +775,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
goto err_free_dev;
}
- printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
- wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
+ printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n",
+ wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
"rtl8225" : "rtl8225z2");
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
index 283de30628e1..880d4becae31 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x.h
@@ -71,6 +71,7 @@ struct rtl818x_csr {
#define RTL818X_RX_CONF_NICMAC (1 << 1)
#define RTL818X_RX_CONF_MULTICAST (1 << 2)
#define RTL818X_RX_CONF_BROADCAST (1 << 3)
+#define RTL818X_RX_CONF_FCS (1 << 5)
#define RTL818X_RX_CONF_DATA (1 << 18)
#define RTL818X_RX_CONF_CTRL (1 << 19)
#define RTL818X_RX_CONF_MGMT (1 << 20)
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index af70460f008a..98df9bc7836a 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -782,7 +782,6 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Ok, we have the configuration, prepare to register the netdev */
dev->base_addr = link->io.BasePort1;
dev->irq = link->irq.AssignedIRQ;
- SET_MODULE_OWNER(dev);
card->node.major = card->node.minor = 0;
/* Reset card and download firmware */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index ef32a5c1e818..4bd14b331862 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -107,6 +107,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE";
#include <linux/serialP.h>
#include <linux/rcupdate.h>
#include <net/arp.h>
+#include <net/net_namespace.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -1630,8 +1631,8 @@ static void strip_IdleTask(unsigned long parameter)
*/
static int strip_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct strip *strip_info = netdev_priv(dev);
STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header));
@@ -1971,7 +1972,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
sizeof(zero_address))) {
struct net_device *dev;
read_lock_bh(&dev_base_lock);
- for_each_netdev(dev) {
+ for_each_netdev(&init_net, dev) {
if (dev->type == strip_info->dev->type &&
!memcmp(dev->dev_addr,
&strip_info->true_dev_addr,
@@ -2496,6 +2497,11 @@ static int strip_close_low(struct net_device *dev)
return 0;
}
+static const struct header_ops strip_header_ops = {
+ .create = strip_header,
+ .rebuild = strip_rebuild_header,
+};
+
/*
* This routine is called by DDI when the
* (dynamically assigned) device is registered
@@ -2507,8 +2513,6 @@ static void strip_dev_setup(struct net_device *dev)
* Finish setting up the DEVICE info.
*/
- SET_MODULE_OWNER(dev);
-
dev->trans_start = 0;
dev->last_rx = 0;
dev->tx_queue_len = 30; /* Drop after 30 frames queued */
@@ -2532,8 +2536,8 @@ static void strip_dev_setup(struct net_device *dev)
dev->open = strip_open_low;
dev->stop = strip_close_low;
dev->hard_start_xmit = strip_xmit;
- dev->hard_header = strip_header;
- dev->rebuild_header = strip_rebuild_header;
+ dev->header_ops = &strip_header_ops;
+
dev->set_mac_address = strip_set_mac_address;
dev->get_stats = strip_get_stats;
dev->change_mtu = strip_change_mtu;
@@ -2571,7 +2575,7 @@ static struct strip *strip_alloc(void)
return NULL; /* If no more memory, return */
- strip_info = dev->priv;
+ strip_info = netdev_priv(dev);
strip_info->dev = dev;
strip_info->magic = STRIP_MAGIC;
@@ -2787,7 +2791,7 @@ static int __init strip_init_driver(void)
/*
* Register the status file with /proc
*/
- proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops);
+ proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops);
return status;
}
@@ -2809,7 +2813,7 @@ static void __exit strip_exit_driver(void)
}
/* Unregister with the /proc/net file here. */
- proc_net_remove("strip");
+ proc_net_remove(&init_net, "strip");
if ((i = tty_unregister_ldisc(N_STRIP)))
printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i);
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 1cf090d60edc..a1f8a1687842 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -880,6 +880,8 @@ static void wv_82586_reconfig(struct net_device * dev)
*/
static void wv_psa_show(psa_t * p)
{
+ DECLARE_MAC_BUF(mac);
+
printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
@@ -891,22 +893,13 @@ static void wv_psa_show(psa_t * p)
printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG
- "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
- p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
- p->psa_unused0[6]);
+ printk(KERN_DEBUG "psa_unused0[]: %s\n",
+ print_mac(mac, p->psa_unused0));
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG
- "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
- p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
- p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
- printk(KERN_DEBUG
- "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
- p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
- p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
+ printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_univ_mac_addr));
+ printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_local_mac_addr));
printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
p->psa_univ_local_sel);
printk("psa_comp_number: %d, ", p->psa_comp_number);
@@ -1248,14 +1241,14 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */
{ /* Name of the function */
int i;
int maxi;
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG
- "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
- msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+ "%s: %s(): dest %s, length %d\n",
+ msg1, msg2, print_mac(mac, p), length);
printk(KERN_DEBUG
- "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
- msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
- p[13]);
+ "%s: %s(): src %s, type 0x%02X%02X\n",
+ msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
#ifdef DEBUG_PACKET_DUMP
@@ -1286,7 +1279,9 @@ static void wv_init_info(struct net_device * dev)
short ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv;
psa_t psa;
- int i;
+#ifdef DEBUG_BASIC_SHOW
+ DECLARE_MAC_BUF(mac);
+#endif
/* Read the parameter storage area */
psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1303,10 +1298,8 @@ static void wv_init_info(struct net_device * dev)
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff. */
- printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
- for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
- printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
- printk(", IRQ %d", dev->irq);
+ printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d",
+ dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq);
/* Print current network ID. */
if (psa.psa_nwid_select)
@@ -2400,9 +2393,9 @@ static const struct iw_priv_args wavelan_private_args[] = {
static const struct iw_handler_def wavelan_handler_def =
{
- .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
- .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(wavelan_handler),
+ .num_private = ARRAY_SIZE(wavelan_private_handler),
+ .num_private_args = ARRAY_SIZE(wavelan_private_args),
.standard = wavelan_handler,
.private = wavelan_private_handler,
.private_args = wavelan_private_args,
@@ -3596,15 +3589,15 @@ static void wv_82586_config(struct net_device * dev)
WAVELAN_ADDR_SIZE >> 1);
#ifdef DEBUG_CONFIG_INFO
+ {
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG
"%s: wv_82586_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
for (dmi = dev->mc_list; dmi; dmi = dmi->next)
- printk(KERN_DEBUG
- " %02x:%02x:%02x:%02x:%02x:%02x\n",
- dmi->dmi_addr[0], dmi->dmi_addr[1],
- dmi->dmi_addr[2], dmi->dmi_addr[3],
- dmi->dmi_addr[4], dmi->dmi_addr[5]);
+ printk(KERN_DEBUG " %s\n",
+ print_mac(mac, dmi->dmi_addr));
+ }
#endif
}
@@ -4177,7 +4170,6 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr)
/* Init spinlock */
spin_lock_init(&lp->spinlock);
- SET_MODULE_OWNER(dev);
dev->open = wavelan_open;
dev->stop = wavelan_close;
dev->hard_start_xmit = wavelan_packet_xmit;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 5740d4d4267c..577c647824fe 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1042,6 +1042,7 @@ wv_82593_reconfig(struct net_device * dev)
static void
wv_psa_show(psa_t * p)
{
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
@@ -1055,29 +1056,13 @@ wv_psa_show(psa_t * p)
printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- p->psa_unused0[0],
- p->psa_unused0[1],
- p->psa_unused0[2],
- p->psa_unused0[3],
- p->psa_unused0[4],
- p->psa_unused0[5],
- p->psa_unused0[6]);
+ printk(KERN_DEBUG "psa_unused0[]: %s\n",
+ print_mac(mac, p->psa_unused0));
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_univ_mac_addr[0],
- p->psa_univ_mac_addr[1],
- p->psa_univ_mac_addr[2],
- p->psa_univ_mac_addr[3],
- p->psa_univ_mac_addr[4],
- p->psa_univ_mac_addr[5]);
- printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_local_mac_addr[0],
- p->psa_local_mac_addr[1],
- p->psa_local_mac_addr[2],
- p->psa_local_mac_addr[3],
- p->psa_local_mac_addr[4],
- p->psa_local_mac_addr[5]);
+ printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_univ_mac_addr));
+ printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_local_mac_addr));
printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
printk("psa_comp_number: %d, ", p->psa_comp_number);
printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
@@ -1277,11 +1262,12 @@ wv_packet_info(u_char * p, /* Packet to dump */
{
int i;
int maxi;
+ DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
- msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
- printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
- msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+ printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n",
+ msg1, msg2, print_mac(mac, p), length);
+ printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n",
+ msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
#ifdef DEBUG_PACKET_DUMP
@@ -1312,7 +1298,7 @@ wv_init_info(struct net_device * dev)
{
kio_addr_t base = dev->base_addr;
psa_t psa;
- int i;
+ DECLARE_MAC_BUF(mac);
/* Read the parameter storage area */
psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1329,10 +1315,10 @@ wv_init_info(struct net_device * dev)
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff */
- printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr",
- dev->name, base, dev->irq);
- for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
- printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+ printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, "
+ "hw_addr %s",
+ dev->name, base, dev->irq,
+ print_mac(mac, dev->dev_addr));
/* Print current network id */
if(psa.psa_nwid_select)
@@ -2719,9 +2705,9 @@ static const iw_handler wavelan_private_handler[] =
static const struct iw_handler_def wavelan_handler_def =
{
- .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
- .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(wavelan_handler),
+ .num_private = ARRAY_SIZE(wavelan_private_handler),
+ .num_private_args = ARRAY_SIZE(wavelan_private_args),
.standard = wavelan_handler,
.private = wavelan_private_handler,
.private_args = wavelan_private_args,
@@ -3691,12 +3677,12 @@ wv_82593_config(struct net_device * dev)
int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
#ifdef DEBUG_CONFIG_INFO
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
for(dmi=dev->mc_list; dmi; dmi=dmi->next)
- printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+ printk(KERN_DEBUG " %s\n",
+ print_mac(mac, dmi->dmi_addr));
#endif
/* Initialize adapter's ethernet multicast addresses */
@@ -4577,7 +4563,6 @@ wavelan_probe(struct pcmcia_device *p_dev)
lp->dev = dev;
/* wavelan NET3 callbacks */
- SET_MODULE_OWNER(dev);
dev->open = &wavelan_open;
dev->stop = &wavelan_close;
dev->hard_start_xmit = &wavelan_packet_xmit;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index c8b5c2271938..42a36b3f3ff7 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -859,12 +859,11 @@ static int wl3501_esbq_confirm(struct wl3501_card *this)
static void wl3501_online(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
- printk(KERN_INFO "%s: Wireless LAN online. BSSID: "
- "%02X %02X %02X %02X %02X %02X\n", dev->name,
- this->bssid[0], this->bssid[1], this->bssid[2],
- this->bssid[3], this->bssid[4], this->bssid[5]);
+ printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n",
+ dev->name, print_mac(mac, this->bssid));
netif_wake_queue(dev);
}
@@ -907,7 +906,7 @@ static int wl3501_mgmt_association(struct wl3501_card *this)
static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct wl3501_join_confirm sig;
dprintk(3, "entry");
@@ -1046,7 +1045,7 @@ static inline void wl3501_start_confirm_interrupt(struct net_device *dev,
static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev,
u16 addr)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct wl3501_assoc_confirm sig;
dprintk(3, "entry");
@@ -1075,7 +1074,7 @@ static inline void wl3501_rx_interrupt(struct net_device *dev)
int morepkts;
u16 addr;
u8 sig_id;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
dprintk(3, "entry");
loop:
@@ -1257,7 +1256,7 @@ fail:
static int wl3501_close(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = -ENODEV;
unsigned long flags;
struct pcmcia_device *link;
@@ -1289,7 +1288,7 @@ static int wl3501_close(struct net_device *dev)
*/
static int wl3501_reset(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = -ENODEV;
wl3501_block_interrupt(this);
@@ -1318,7 +1317,7 @@ out:
static void wl3501_tx_timeout(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct net_device_stats *stats = &this->stats;
unsigned long flags;
int rc;
@@ -1344,7 +1343,7 @@ static void wl3501_tx_timeout(struct net_device *dev)
static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int enabled, rc;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&this->lock, flags);
@@ -1371,7 +1370,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int wl3501_open(struct net_device *dev)
{
int rc = -ENODEV;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
unsigned long flags;
struct pcmcia_device *link;
link = this->p_dev;
@@ -1410,14 +1409,14 @@ fail:
static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
return &this->stats;
}
static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct iw_statistics *wstats = &this->wstats;
u32 value; /* size checked: it is u32 */
@@ -1497,7 +1496,7 @@ static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info,
static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int channel = wrqu->freq.m;
int rc = -EINVAL;
@@ -1511,7 +1510,7 @@ static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000;
wrqu->freq.e = 1;
@@ -1526,7 +1525,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,
if (wrqu->mode == IW_MODE_INFRA ||
wrqu->mode == IW_MODE_ADHOC ||
wrqu->mode == IW_MODE_AUTO) {
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
this->net_type = wrqu->mode;
rc = wl3501_reset(dev);
@@ -1537,7 +1536,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->mode = this->net_type;
return 0;
@@ -1546,7 +1545,7 @@ static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->sens.value = this->rssi;
wrqu->sens.disabled = !wrqu->sens.value;
@@ -1577,7 +1576,7 @@ static int wl3501_get_range(struct net_device *dev,
static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
int rc = -EINVAL;
@@ -1597,7 +1596,7 @@ out:
static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN);
@@ -1616,7 +1615,7 @@ static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int i;
char *current_ev = extra;
struct iw_event iwe;
@@ -1666,7 +1665,7 @@ static int wl3501_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
if (wrqu->data.flags) {
iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
@@ -1683,7 +1682,7 @@ static int wl3501_get_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&this->lock, flags);
@@ -1697,7 +1696,7 @@ static int wl3501_get_essid(struct net_device *dev,
static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
if (wrqu->data.length > sizeof(this->nick))
return -E2BIG;
@@ -1708,7 +1707,7 @@ static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
strlcpy(extra, this->nick, 32);
wrqu->data.length = strlen(extra);
@@ -1733,7 +1732,7 @@ static int wl3501_get_rts_threshold(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD,
&threshold, sizeof(threshold));
if (!rc) {
@@ -1749,7 +1748,7 @@ static int wl3501_get_frag_threshold(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD,
&threshold, sizeof(threshold));
if (!rc) {
@@ -1765,7 +1764,7 @@ static int wl3501_get_txpow(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u16 txpow;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
&txpow, sizeof(txpow));
@@ -1787,7 +1786,7 @@ static int wl3501_get_retry(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u8 retry; /* size checked: it is u8 */
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
&retry, sizeof(retry));
@@ -1814,7 +1813,7 @@ static int wl3501_get_encode(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u8 implemented, restricted, keys[100], len_keys, tocopy;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
&implemented, sizeof(implemented));
@@ -1841,7 +1840,6 @@ static int wl3501_get_encode(struct net_device *dev,
tocopy = min_t(u8, len_keys, wrqu->encoding.length);
tocopy = min_t(u8, tocopy, 100);
wrqu->encoding.length = tocopy;
- memset(extra, 0, tocopy);
memcpy(extra, keys, tocopy);
out:
return rc;
@@ -1852,7 +1850,7 @@ static int wl3501_get_power(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u8 pwr_state;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_CURRENT_PWR_STATE,
&pwr_state, sizeof(pwr_state));
@@ -1894,7 +1892,7 @@ static const iw_handler wl3501_handler[] = {
};
static const struct iw_handler_def wl3501_handler_def = {
- .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(wl3501_handler),
.standard = (iw_handler *)wl3501_handler,
.get_wireless_stats = wl3501_get_wireless_stats,
};
@@ -1937,7 +1935,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
dev->tx_timeout = wl3501_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
dev->get_stats = wl3501_get_stats;
- this = dev->priv;
+ this = netdev_priv(dev);
this->wireless_data.spy_data = &this->spy_data;
this->p_dev = p_dev;
dev->wireless_data = &this->wireless_data;
@@ -1967,6 +1965,7 @@ static int wl3501_config(struct pcmcia_device *link)
struct net_device *dev = link->priv;
int i = 0, j, last_fn, last_ret;
struct wl3501_card *this;
+ DECLARE_MAC_BUF(mac);
/* Try allocating IO ports. This tries a few fixed addresses. If you
* want, you can also read the card's config table to pick addresses --
@@ -2004,9 +2003,7 @@ static int wl3501_config(struct pcmcia_device *link)
goto failed;
}
- SET_MODULE_OWNER(dev);
-
- this = dev->priv;
+ this = netdev_priv(dev);
/*
* At this point, the dev_node_t structure(s) should be initialized and
* arranged in a linked list at link->dev_node.
@@ -2022,14 +2019,14 @@ static int wl3501_config(struct pcmcia_device *link)
}
strcpy(this->node.dev_name, dev->name);
- /* print probe information */
- printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:",
- dev->name, this->base_addr, (int)dev->irq);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = ((char *)&this->mac_addr)[i];
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- }
- printk("\n");
+
+ /* print probe information */
+ printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
+ "MAC addr in flash ROM:%s\n",
+ dev->name, this->base_addr, (int)dev->irq,
+ print_mac(mac, dev->dev_addr));
/*
* Initialize card parameters - added by jss
*/
@@ -2079,7 +2076,7 @@ static int wl3501_suspend(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);
+ wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND);
if (link->open)
netif_device_detach(dev);
@@ -2090,7 +2087,7 @@ static int wl3501_resume(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);
+ wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME);
if (link->open) {
wl3501_reset(dev);
netif_device_attach(dev);
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 4d505903352c..7a2f2a98edab 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -4,7 +4,7 @@ zd1211rw-objs := zd_chip.o zd_ieee80211.o \
zd_mac.o zd_netdev.o \
zd_rf_al2230.o zd_rf_rf2959.o \
zd_rf_al7230b.o zd_rf_uw2453.o \
- zd_rf.o zd_usb.o zd_util.o
+ zd_rf.o zd_usb.o
ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index c39f1984b84d..f831b68f1b9c 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -28,7 +28,6 @@
#include "zd_ieee80211.h"
#include "zd_mac.h"
#include "zd_rf.h"
-#include "zd_util.h"
void zd_chip_init(struct zd_chip *chip,
struct net_device *netdev,
@@ -106,7 +105,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
{
int r;
int i;
- zd_addr_t *a16 = (zd_addr_t *)NULL;
+ zd_addr_t *a16;
u16 *v16;
unsigned int count16;
@@ -377,6 +376,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
[0] = { .addr = CR_MAC_ADDR_P1 },
[1] = { .addr = CR_MAC_ADDR_P2 },
};
+ DECLARE_MAC_BUF(mac);
reqs[0].value = (mac_addr[3] << 24)
| (mac_addr[2] << 16)
@@ -386,7 +386,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
| mac_addr[4];
dev_dbg_f(zd_chip_dev(chip),
- "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+ "mac addr %s\n", print_mac(mac, mac_addr));
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
@@ -500,8 +500,6 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip)
return r;
}
- dev_dbg_f(zd_chip_dev(chip),
- "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
tmp &= ~UNLOCK_PHY_REGS;
r = zd_iowrite32_locked(chip, tmp, CR_REG1);
@@ -523,8 +521,6 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip)
return r;
}
- dev_dbg_f(zd_chip_dev(chip),
- "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
tmp |= UNLOCK_PHY_REGS;
r = zd_iowrite32_locked(chip, tmp, CR_REG1);
@@ -841,8 +837,6 @@ static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
s->atim_wnd_period = values[0];
s->pre_tbtt = values[1];
s->beacon_interval = values[2];
- dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
- s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
return 0;
}
@@ -864,9 +858,6 @@ static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
reqs[2].addr = CR_BCN_INTERVAL;
reqs[2].value = s->beacon_interval;
- dev_dbg_f(zd_chip_dev(chip),
- "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
- s->beacon_interval);
return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
}
@@ -1018,19 +1009,19 @@ int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
u32 value = 0;
/* Modulation bit */
- if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM)
+ if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM)
rts_mod = ZD_RX_OFDM;
dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n",
rts_rate, preamble);
- value |= rts_rate << RTSCTS_SH_RTS_RATE;
+ value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE;
value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE;
value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
value |= preamble << RTSCTS_SH_CTS_PMB_TYPE;
/* We always send 11M self-CTS messages, like the vendor driver. */
- value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE;
+ value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE);
@@ -1160,16 +1151,12 @@ out:
static int update_pwr_int(struct zd_chip *chip, u8 channel)
{
u8 value = chip->pwr_int_values[channel - 1];
- dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
- channel, value);
return zd_iowrite16_locked(chip, value, CR31);
}
static int update_pwr_cal(struct zd_chip *chip, u8 channel)
{
u8 value = chip->pwr_cal_values[channel-1];
- dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
- channel, value);
return zd_iowrite16_locked(chip, value, CR68);
}
@@ -1184,9 +1171,6 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
ioreqs[2].addr = CR65;
ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
- dev_dbg_f(zd_chip_dev(chip),
- "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
- channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
@@ -1344,7 +1328,7 @@ int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates)
return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
}
-static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
{
static const u16 constants[] = {
715, 655, 585, 540, 470, 410, 360, 315,
@@ -1358,7 +1342,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
/* It seems that their quality parameter is somehow per signal
* and is now transferred per bit.
*/
- switch (rate) {
+ switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_12M:
case ZD_OFDM_RATE_24M:
@@ -1385,7 +1369,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
break;
}
- switch (rate) {
+ switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_9M:
i += 3;
@@ -1409,11 +1393,11 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
return i;
}
-static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size)
{
int r;
- r = ofdm_qual_db(status_quality, rate, size);
+ r = ofdm_qual_db(status_quality, zd_rate, size);
ZD_ASSERT(r >= 0);
if (r < 0)
r = 0;
@@ -1474,12 +1458,17 @@ static int cck_qual_percent(u8 status_quality)
return r <= 100 ? r : 100;
}
+static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
+{
+ return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
+}
+
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
const struct rx_status *status)
{
return (status->frame_status&ZD_RX_OFDM) ?
ofdm_qual_percent(status->signal_quality_ofdm,
- zd_ofdm_plcp_header_rate(rx_frame),
+ zd_rate_from_ofdm_plcp_header(rx_frame),
size) :
cck_qual_percent(status->signal_quality_cck);
}
@@ -1495,32 +1484,32 @@ u8 zd_rx_strength_percent(u8 rssi)
u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
{
static const u16 ofdm_rates[] = {
- [ZD_OFDM_RATE_6M] = 60,
- [ZD_OFDM_RATE_9M] = 90,
- [ZD_OFDM_RATE_12M] = 120,
- [ZD_OFDM_RATE_18M] = 180,
- [ZD_OFDM_RATE_24M] = 240,
- [ZD_OFDM_RATE_36M] = 360,
- [ZD_OFDM_RATE_48M] = 480,
- [ZD_OFDM_RATE_54M] = 540,
+ [ZD_OFDM_PLCP_RATE_6M] = 60,
+ [ZD_OFDM_PLCP_RATE_9M] = 90,
+ [ZD_OFDM_PLCP_RATE_12M] = 120,
+ [ZD_OFDM_PLCP_RATE_18M] = 180,
+ [ZD_OFDM_PLCP_RATE_24M] = 240,
+ [ZD_OFDM_PLCP_RATE_36M] = 360,
+ [ZD_OFDM_PLCP_RATE_48M] = 480,
+ [ZD_OFDM_PLCP_RATE_54M] = 540,
};
u16 rate;
if (status->frame_status & ZD_RX_OFDM) {
+ /* Deals with PLCP OFDM rate (not zd_rates) */
u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
rate = ofdm_rates[ofdm_rate & 0xf];
} else {
- u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
- switch (cck_rate) {
- case ZD_CCK_SIGNAL_1M:
+ switch (zd_cck_plcp_header_signal(rx_frame)) {
+ case ZD_CCK_PLCP_SIGNAL_1M:
rate = 10;
break;
- case ZD_CCK_SIGNAL_2M:
+ case ZD_CCK_PLCP_SIGNAL_2M:
rate = 20;
break;
- case ZD_CCK_SIGNAL_5M5:
+ case ZD_CCK_PLCP_SIGNAL_5M5:
rate = 55;
break;
- case ZD_CCK_SIGNAL_11M:
+ case ZD_CCK_PLCP_SIGNAL_11M:
rate = 110;
break;
default:
@@ -1638,7 +1627,5 @@ int zd_chip_set_multicast_hash(struct zd_chip *chip,
{ CR_GROUP_HASH_P2, hash->high },
};
- dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n",
- ioreqs[0].value, ioreqs[1].value);
return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index f4698576ab71..8009b70213e2 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -871,11 +871,6 @@ static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
return r;
}
-static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
-{
- return zd_iowrite32(chip, CR_RX_FILTER, filter);
-}
-
int zd_chip_lock_phy_regs(struct zd_chip *chip);
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index deb99d1eaa77..505b4d7dd0e2 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/stringify.h>
#include <linux/device.h>
-#include <linux/kernel.h>
typedef u16 __nocast zd_addr_t;
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index c4f36d39642b..fbf6491dce7e 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -43,21 +43,25 @@ struct ofdm_plcp_header {
__le16 service;
} __attribute__((packed));
-static inline u8 zd_ofdm_plcp_header_rate(
- const struct ofdm_plcp_header *header)
+static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
{
return header->prefix[0] & 0xf;
}
-/* These are referred to as zd_rates */
-#define ZD_OFDM_RATE_6M 0xb
-#define ZD_OFDM_RATE_9M 0xf
-#define ZD_OFDM_RATE_12M 0xa
-#define ZD_OFDM_RATE_18M 0xe
-#define ZD_OFDM_RATE_24M 0x9
-#define ZD_OFDM_RATE_36M 0xd
-#define ZD_OFDM_RATE_48M 0x8
-#define ZD_OFDM_RATE_54M 0xc
+/* The following defines give the encoding of the 4-bit rate field in the
+ * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
+ * define the zd-rate values for OFDM.
+ *
+ * See the struct zd_ctrlset definition in zd_mac.h.
+ */
+#define ZD_OFDM_PLCP_RATE_6M 0xb
+#define ZD_OFDM_PLCP_RATE_9M 0xf
+#define ZD_OFDM_PLCP_RATE_12M 0xa
+#define ZD_OFDM_PLCP_RATE_18M 0xe
+#define ZD_OFDM_PLCP_RATE_24M 0x9
+#define ZD_OFDM_PLCP_RATE_36M 0xd
+#define ZD_OFDM_PLCP_RATE_48M 0x8
+#define ZD_OFDM_PLCP_RATE_54M 0xc
struct cck_plcp_header {
u8 signal;
@@ -66,15 +70,22 @@ struct cck_plcp_header {
__le16 crc16;
} __attribute__((packed));
-static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
{
return header->signal;
}
-#define ZD_CCK_SIGNAL_1M 0x0a
-#define ZD_CCK_SIGNAL_2M 0x14
-#define ZD_CCK_SIGNAL_5M5 0x37
-#define ZD_CCK_SIGNAL_11M 0x6e
+/* These defines give the encodings of the signal field in the 802.11b PLCP
+ * header. The signal field gives the bit rate of the following packet. Even
+ * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
+ * rate to stay consistent with Zydas and our use of the term.
+ *
+ * Notify that these values are *not* used in the zd-rates.
+ */
+#define ZD_CCK_PLCP_SIGNAL_1M 0x0a
+#define ZD_CCK_PLCP_SIGNAL_2M 0x14
+#define ZD_CCK_PLCP_SIGNAL_5M5 0x37
+#define ZD_CCK_PLCP_SIGNAL_11M 0x6e
enum ieee80211_std {
IEEE80211B = 0x01,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index f6c487aa8246..a903645e157a 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -28,7 +28,6 @@
#include "zd_ieee80211.h"
#include "zd_netdev.h"
#include "zd_rf.h"
-#include "zd_util.h"
static void ieee_init(struct ieee80211_device *ieee);
static void softmac_init(struct ieee80211softmac_device *sm);
@@ -161,13 +160,33 @@ void zd_mac_clear(struct zd_mac *mac)
ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
}
-static int reset_mode(struct zd_mac *mac)
+static int set_rx_filter(struct zd_mac *mac)
{
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
}
+static int set_sniffer(struct zd_mac *mac)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
+ ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);
+ return 0;
+}
+
+static int set_mc_hash(struct zd_mac *mac)
+{
+ struct zd_mc_hash hash;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ zd_mc_clear(&hash);
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ zd_mc_add_all(&hash);
+
+ return zd_chip_set_multicast_hash(&mac->chip, &hash);
+}
+
int zd_mac_open(struct net_device *netdev)
{
struct zd_mac *mac = zd_netdev_mac(netdev);
@@ -194,7 +213,13 @@ int zd_mac_open(struct net_device *netdev)
r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
if (r < 0)
goto disable_int;
- r = reset_mode(mac);
+ r = set_rx_filter(mac);
+ if (r)
+ goto disable_int;
+ r = set_sniffer(mac);
+ if (r)
+ goto disable_int;
+ r = set_mc_hash(mac);
if (r)
goto disable_int;
r = zd_chip_switch_radio_on(chip);
@@ -263,12 +288,13 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p)
struct sockaddr *addr = p;
struct zd_mac *mac = zd_netdev_mac(netdev);
struct zd_chip *chip = &mac->chip;
+ DECLARE_MAC_BUF(mac2);
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
dev_dbg_f(zd_mac_dev(mac),
- "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+ "Setting MAC to %s\n", print_mac(mac2, addr->sa_data));
if (netdev->flags & IFF_UP) {
r = zd_write_mac_addr(chip, addr->sa_data);
@@ -298,18 +324,21 @@ static void set_multicast_hash_handler(struct work_struct *work)
void zd_mac_set_multicast_list(struct net_device *dev)
{
- struct zd_mc_hash hash;
struct zd_mac *mac = zd_netdev_mac(dev);
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct zd_mc_hash hash;
struct dev_mc_list *mc;
unsigned long flags;
+ DECLARE_MAC_BUF(mac2);
- if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+ if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) ||
+ ieee->iw_mode == IW_MODE_MONITOR) {
zd_mc_add_all(&hash);
} else {
zd_mc_clear(&hash);
for (mc = dev->mc_list; mc; mc = mc->next) {
- dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
- MAC_ARG(mc->dmi_addr));
+ dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
+ print_mac(mac2, mc->dmi_addr));
zd_mc_add_addr(&hash, mc->dmi_addr);
}
}
@@ -582,28 +611,6 @@ u8 zd_mac_get_channel(struct zd_mac *mac)
return channel;
}
-/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
-static u8 zd_rate_typed(u8 zd_rate)
-{
- static const u8 typed_rates[16] = {
- [ZD_CCK_RATE_1M] = ZD_CS_CCK|ZD_CCK_RATE_1M,
- [ZD_CCK_RATE_2M] = ZD_CS_CCK|ZD_CCK_RATE_2M,
- [ZD_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CCK_RATE_5_5M,
- [ZD_CCK_RATE_11M] = ZD_CS_CCK|ZD_CCK_RATE_11M,
- [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
- [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
- [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
- [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
- [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
- [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
- [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
- [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
- };
-
- ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
- return typed_rates[zd_rate & ZD_CS_RATE_MASK];
-}
-
int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
{
struct ieee80211_device *ieee;
@@ -628,8 +635,12 @@ int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
ieee->iw_mode = mode;
spin_unlock_irq(&ieee->lock);
- if (netif_running(mac->netdev))
- return reset_mode(mac);
+ if (netif_running(mac->netdev)) {
+ int r = set_rx_filter(mac);
+ if (r)
+ return r;
+ return set_sniffer(mac);
+ }
return 0;
}
@@ -707,25 +718,30 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
{
+ /* ZD_PURE_RATE() must be used to remove the modulation type flag of
+ * the zd-rate values. */
static const u8 rate_divisor[] = {
- [ZD_CCK_RATE_1M] = 1,
- [ZD_CCK_RATE_2M] = 2,
- [ZD_CCK_RATE_5_5M] = 11, /* bits must be doubled */
- [ZD_CCK_RATE_11M] = 11,
- [ZD_OFDM_RATE_6M] = 6,
- [ZD_OFDM_RATE_9M] = 9,
- [ZD_OFDM_RATE_12M] = 12,
- [ZD_OFDM_RATE_18M] = 18,
- [ZD_OFDM_RATE_24M] = 24,
- [ZD_OFDM_RATE_36M] = 36,
- [ZD_OFDM_RATE_48M] = 48,
- [ZD_OFDM_RATE_54M] = 54,
+ [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1,
+ [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2,
+
+ /* bits must be doubled */
+ [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11,
+
+ [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54,
};
u32 bits = (u32)tx_length * 8;
u32 divisor;
- divisor = rate_divisor[zd_rate];
+ divisor = rate_divisor[ZD_PURE_RATE(zd_rate)];
if (divisor == 0)
return -EINVAL;
@@ -748,52 +764,24 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
return bits/divisor;
}
-enum {
- R2M_SHORT_PREAMBLE = 0x01,
- R2M_11A = 0x02,
-};
-
-static u8 zd_rate_to_modulation(u8 zd_rate, int flags)
-{
- u8 modulation;
-
- modulation = zd_rate_typed(zd_rate);
- if (flags & R2M_SHORT_PREAMBLE) {
- switch (ZD_CS_RATE(modulation)) {
- case ZD_CCK_RATE_2M:
- case ZD_CCK_RATE_5_5M:
- case ZD_CCK_RATE_11M:
- modulation |= ZD_CS_CCK_PREA_SHORT;
- return modulation;
- }
- }
- if (flags & R2M_11A) {
- if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
- modulation |= ZD_CS_OFDM_MODE_11A;
- }
- return modulation;
-}
-
static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
struct ieee80211_hdr_4addr *hdr)
{
struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
- u8 rate, zd_rate;
+ u8 rate;
int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
int is_multicast = is_multicast_ether_addr(hdr->addr1);
int short_preamble = ieee80211softmac_short_preamble_ok(softmac,
is_multicast, is_mgt);
- int flags = 0;
- /* FIXME: 802.11a? */
rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt);
+ cs->modulation = rate_to_zd_rate(rate);
- if (short_preamble)
- flags |= R2M_SHORT_PREAMBLE;
-
- zd_rate = rate_to_zd_rate(rate);
- cs->modulation = zd_rate_to_modulation(zd_rate, flags);
+ /* Set short preamble bit when appropriate */
+ if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK
+ && cs->modulation != ZD_CCK_RATE_1M)
+ cs->modulation |= ZD_CCK_PREA_SHORT;
}
static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
@@ -822,7 +810,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
cs->control |= ZD_CS_MULTICAST;
/* PS-POLL */
- if (stype == IEEE80211_STYPE_PSPOLL)
+ if (ftype == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL)
cs->control |= ZD_CS_PS_POLL_FRAME;
/* Unicast data frames over the threshold should have RTS */
@@ -832,7 +820,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
cs->control |= ZD_CS_RTS;
/* Use CTS-to-self protection if required */
- if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM &&
+ if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM &&
ieee80211softmac_protection_needed(softmac)) {
/* FIXME: avoid sending RTS *and* self-CTS, is that correct? */
cs->control &= ~ZD_CS_RTS;
@@ -893,7 +881,7 @@ static int fill_ctrlset(struct zd_mac *mac,
* - see line 53 of zdinlinef.h
*/
cs->service = 0;
- r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+ r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation),
le16_to_cpu(cs->tx_length));
if (r < 0)
return r;
@@ -902,7 +890,7 @@ static int fill_ctrlset(struct zd_mac *mac,
if (next_frag_len == 0) {
cs->next_frame_length = 0;
} else {
- r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+ r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation),
next_frag_len);
if (r < 0)
return r;
@@ -1077,7 +1065,8 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
{
const struct rx_status *status;
- *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+ *pstatus = status = (struct rx_status *)
+ (buffer + (length - sizeof(struct rx_status)));
if (status->frame_status & ZD_RX_ERROR) {
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
ieee->stats.rx_errors++;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 9f9344eb50f9..1b15bde3ff60 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -40,28 +40,51 @@ struct zd_ctrlset {
#define ZD_CS_RESERVED_SIZE 25
-/* zd_crtlset field modulation */
-#define ZD_CS_RATE_MASK 0x0f
-#define ZD_CS_TYPE_MASK 0x10
-#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
-#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
-
-#define ZD_CS_CCK 0x00
-#define ZD_CS_OFDM 0x10
-
-/* These are referred to as zd_rates */
-#define ZD_CCK_RATE_1M 0x00
-#define ZD_CCK_RATE_2M 0x01
-#define ZD_CCK_RATE_5_5M 0x02
-#define ZD_CCK_RATE_11M 0x03
-/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+/* The field modulation of struct zd_ctrlset controls the bit rate, the use
+ * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or
+ * 802.11g in OFDM mode.
+ *
+ * The term zd-rate is used for the combination of the modulation type flag
+ * and the "pure" rate value.
*/
-
-/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
-#define ZD_CS_CCK_PREA_LONG 0x00
-#define ZD_CS_CCK_PREA_SHORT 0x20
-#define ZD_CS_OFDM_MODE_11G 0x00
-#define ZD_CS_OFDM_MODE_11A 0x20
+#define ZD_PURE_RATE_MASK 0x0f
+#define ZD_MODULATION_TYPE_MASK 0x10
+#define ZD_RATE_MASK (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK)
+#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK)
+#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK)
+#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK)
+
+/* The two possible modulation types. Notify that 802.11b doesn't use the CCK
+ * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain
+ * consistent with uses the term at other places.
+ */
+#define ZD_CCK 0x00
+#define ZD_OFDM 0x10
+
+/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates.
+ * For OFDM the PLCP rate encodings are used. We combine these "pure" rates
+ * with the modulation type flag and call the resulting values zd-rates.
+ */
+#define ZD_CCK_RATE_1M (ZD_CCK|0x00)
+#define ZD_CCK_RATE_2M (ZD_CCK|0x01)
+#define ZD_CCK_RATE_5_5M (ZD_CCK|0x02)
+#define ZD_CCK_RATE_11M (ZD_CCK|0x03)
+#define ZD_OFDM_RATE_6M (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M)
+#define ZD_OFDM_RATE_9M (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M)
+#define ZD_OFDM_RATE_12M (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M)
+#define ZD_OFDM_RATE_18M (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M)
+#define ZD_OFDM_RATE_24M (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M)
+#define ZD_OFDM_RATE_36M (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M)
+#define ZD_OFDM_RATE_48M (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M)
+#define ZD_OFDM_RATE_54M (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M)
+
+/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK
+ * mode or the 802.11a/802.11g selection in OFDM mode.
+ */
+#define ZD_CCK_PREA_LONG 0x00
+#define ZD_CCK_PREA_SHORT 0x20
+#define ZD_OFDM_MODE_11G 0x00
+#define ZD_OFDM_MODE_11A 0x20
/* zd_ctrlset control field */
#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 8bda48de31ef..047cab3d87df 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -233,7 +233,6 @@ struct net_device *zd_netdev_alloc(struct usb_interface *intf)
return NULL;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &intf->dev);
dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 28d41a29d7b1..b0684f965761 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -31,7 +31,6 @@
#include "zd_netdev.h"
#include "zd_mac.h"
#include "zd_usb.h"
-#include "zd_util.h"
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
@@ -55,6 +54,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -72,6 +72,11 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
deleted file mode 100644
index d20036c15d11..000000000000
--- a/drivers/net/wireless/zd1211rw/zd_util.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* zd_util.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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
- *
- * Utility program
- */
-
-#include "zd_def.h"
-#include "zd_util.h"
-
-#ifdef DEBUG
-static char hex(u8 v)
-{
- v &= 0xf;
- return (v < 10 ? '0' : 'a' - 10) + v;
-}
-
-static char hex_print(u8 c)
-{
- return (0x20 <= c && c < 0x7f) ? c : '.';
-}
-
-static void dump_line(const u8 *bytes, size_t size)
-{
- char c;
- size_t i;
-
- size = size <= 8 ? size : 8;
- printk(KERN_DEBUG "zd1211 %p ", bytes);
- for (i = 0; i < 8; i++) {
- switch (i) {
- case 1:
- case 5:
- c = '.';
- break;
- case 3:
- c = ':';
- break;
- default:
- c = ' ';
- }
- if (i < size) {
- printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
- } else {
- printk(" %c", c);
- }
- }
-
- for (i = 0; i < size; i++)
- printk("%c", hex_print(bytes[i]));
- printk("\n");
-}
-
-void zd_hexdump(const void *bytes, size_t size)
-{
- size_t i = 0;
-
- do {
- dump_line((u8 *)bytes + i, size-i);
- i += 8;
- } while (i < size);
-}
-#endif /* DEBUG */
-
-void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
-{
- if (buffer_size < tail_size)
- return NULL;
- return (u8 *)buffer + (buffer_size - tail_size);
-}
diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h
deleted file mode 100644
index ce26f7adea92..000000000000
--- a/drivers/net/wireless/zd1211rw/zd_util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* zd_util.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_UTIL_H
-#define _ZD_UTIL_H
-
-void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
-
-#ifdef DEBUG
-void zd_hexdump(const void *bytes, size_t size);
-#else
-#define zd_hexdump(bytes, size)
-#endif /* DEBUG */
-
-#endif /* _ZD_UTIL_H */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
new file mode 100644
index 000000000000..f464b82c7d5f
--- /dev/null
+++ b/drivers/net/xen-netfront.c
@@ -0,0 +1,1817 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <net/ip.h>
+
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <xen/interface/io/netif.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/grant_table.h>
+
+static struct ethtool_ops xennet_ethtool_ops;
+
+struct netfront_cb {
+ struct page *page;
+ unsigned offset;
+};
+
+#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
+
+#define RX_COPY_THRESHOLD 256
+
+#define GRANT_INVALID_REF 0
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+
+struct netfront_info {
+ struct list_head list;
+ struct net_device *netdev;
+
+ struct napi_struct napi;
+
+ struct xen_netif_tx_front_ring tx;
+ struct xen_netif_rx_front_ring rx;
+
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+
+ unsigned int evtchn;
+
+ /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+ unsigned rx_min_target, rx_max_target, rx_target;
+ struct sk_buff_head rx_batch;
+
+ struct timer_list rx_refill_timer;
+
+ /*
+ * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
+ * are linked from tx_skb_freelist through skb_entry.link.
+ *
+ * NB. Freelist index entries are always going to be less than
+ * PAGE_OFFSET, whereas pointers to skbs will always be equal or
+ * greater than PAGE_OFFSET: we use this property to distinguish
+ * them.
+ */
+ union skb_entry {
+ struct sk_buff *skb;
+ unsigned link;
+ } tx_skbs[NET_TX_RING_SIZE];
+ grant_ref_t gref_tx_head;
+ grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+ unsigned tx_skb_freelist;
+
+ struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
+ grant_ref_t gref_rx_head;
+ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+ struct xenbus_device *xbdev;
+ int tx_ring_ref;
+ int rx_ring_ref;
+
+ unsigned long rx_pfn_array[NET_RX_RING_SIZE];
+ struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
+ struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+};
+
+struct netfront_rx_info {
+ struct xen_netif_rx_response rx;
+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+};
+
+/*
+ * Access macros for acquiring freeing slots in tx_skbs[].
+ */
+
+static void add_id_to_freelist(unsigned *head, union skb_entry *list,
+ unsigned short id)
+{
+ list[id].link = *head;
+ *head = id;
+}
+
+static unsigned short get_id_from_freelist(unsigned *head,
+ union skb_entry *list)
+{
+ unsigned int id = *head;
+ *head = list[id].link;
+ return id;
+}
+
+static int xennet_rxidx(RING_IDX idx)
+{
+ return idx & (NET_RX_RING_SIZE - 1);
+}
+
+static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
+ RING_IDX ri)
+{
+ int i = xennet_rxidx(ri);
+ struct sk_buff *skb = np->rx_skbs[i];
+ np->rx_skbs[i] = NULL;
+ return skb;
+}
+
+static grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
+ RING_IDX ri)
+{
+ int i = xennet_rxidx(ri);
+ grant_ref_t ref = np->grant_rx_ref[i];
+ np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ return ref;
+}
+
+#ifdef CONFIG_SYSFS
+static int xennet_sysfs_addif(struct net_device *netdev);
+static void xennet_sysfs_delif(struct net_device *netdev);
+#else /* !CONFIG_SYSFS */
+#define xennet_sysfs_addif(dev) (0)
+#define xennet_sysfs_delif(dev) do { } while (0)
+#endif
+
+static int xennet_can_sg(struct net_device *dev)
+{
+ return dev->features & NETIF_F_SG;
+}
+
+
+static void rx_refill_timeout(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct netfront_info *np = netdev_priv(dev);
+ netif_rx_schedule(dev, &np->napi);
+}
+
+static int netfront_tx_slot_available(struct netfront_info *np)
+{
+ return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
+ (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+}
+
+static void xennet_maybe_wake_tx(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+
+ if (unlikely(netif_queue_stopped(dev)) &&
+ netfront_tx_slot_available(np) &&
+ likely(netif_running(dev)))
+ netif_wake_queue(dev);
+}
+
+static void xennet_alloc_rx_buffers(struct net_device *dev)
+{
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct page *page;
+ int i, batch_target, notify;
+ RING_IDX req_prod = np->rx.req_prod_pvt;
+ grant_ref_t ref;
+ unsigned long pfn;
+ void *vaddr;
+ struct xen_netif_rx_request *req;
+
+ if (unlikely(!netif_carrier_ok(dev)))
+ return;
+
+ /*
+ * Allocate skbuffs greedily, even though we batch updates to the
+ * receive ring. This creates a less bursty demand on the memory
+ * allocator, so should reduce the chance of failed allocation requests
+ * both for ourself and for other kernel subsystems.
+ */
+ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
+ for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+ skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!skb))
+ goto no_skb;
+
+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+ if (!page) {
+ kfree_skb(skb);
+no_skb:
+ /* Any skbuffs queued for refill? Force them out. */
+ if (i != 0)
+ goto refill;
+ /* Could not allocate any skbuffs. Try again later. */
+ mod_timer(&np->rx_refill_timer,
+ jiffies + (HZ/10));
+ break;
+ }
+
+ skb_shinfo(skb)->frags[0].page = page;
+ skb_shinfo(skb)->nr_frags = 1;
+ __skb_queue_tail(&np->rx_batch, skb);
+ }
+
+ /* Is the batch large enough to be worthwhile? */
+ if (i < (np->rx_target/2)) {
+ if (req_prod > np->rx.sring->req_prod)
+ goto push;
+ return;
+ }
+
+ /* Adjust our fill target if we risked running out of buffers. */
+ if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
+ ((np->rx_target *= 2) > np->rx_max_target))
+ np->rx_target = np->rx_max_target;
+
+ refill:
+ for (i = 0; ; i++) {
+ skb = __skb_dequeue(&np->rx_batch);
+ if (skb == NULL)
+ break;
+
+ skb->dev = dev;
+
+ id = xennet_rxidx(req_prod + i);
+
+ BUG_ON(np->rx_skbs[id]);
+ np->rx_skbs[id] = skb;
+
+ ref = gnttab_claim_grant_reference(&np->gref_rx_head);
+ BUG_ON((signed short)ref < 0);
+ np->grant_rx_ref[id] = ref;
+
+ pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
+ vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+
+ req = RING_GET_REQUEST(&np->rx, req_prod + i);
+ gnttab_grant_foreign_access_ref(ref,
+ np->xbdev->otherend_id,
+ pfn_to_mfn(pfn),
+ 0);
+
+ req->id = id;
+ req->gref = ref;
+ }
+
+ wmb(); /* barrier so backend seens requests */
+
+ /* Above is a suitable barrier to ensure backend will see requests. */
+ np->rx.req_prod_pvt = req_prod + i;
+ push:
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+ if (notify)
+ notify_remote_via_irq(np->netdev->irq);
+}
+
+static int xennet_open(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+
+ napi_enable(&np->napi);
+
+ spin_lock_bh(&np->rx_lock);
+ if (netif_carrier_ok(dev)) {
+ xennet_alloc_rx_buffers(dev);
+ np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ netif_rx_schedule(dev, &np->napi);
+ }
+ spin_unlock_bh(&np->rx_lock);
+
+ xennet_maybe_wake_tx(dev);
+
+ return 0;
+}
+
+static void xennet_tx_buf_gc(struct net_device *dev)
+{
+ RING_IDX cons, prod;
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ BUG_ON(!netif_carrier_ok(dev));
+
+ do {
+ prod = np->tx.sring->rsp_prod;
+ rmb(); /* Ensure we see responses up to 'rp'. */
+
+ for (cons = np->tx.rsp_cons; cons != prod; cons++) {
+ struct xen_netif_tx_response *txrsp;
+
+ txrsp = RING_GET_RESPONSE(&np->tx, cons);
+ if (txrsp->status == NETIF_RSP_NULL)
+ continue;
+
+ id = txrsp->id;
+ skb = np->tx_skbs[id].skb;
+ if (unlikely(gnttab_query_foreign_access(
+ np->grant_tx_ref[id]) != 0)) {
+ printk(KERN_ALERT "xennet_tx_buf_gc: warning "
+ "-- grant still in use by backend "
+ "domain.\n");
+ BUG();
+ }
+ gnttab_end_foreign_access_ref(
+ np->grant_tx_ref[id], GNTMAP_readonly);
+ gnttab_release_grant_reference(
+ &np->gref_tx_head, np->grant_tx_ref[id]);
+ np->grant_tx_ref[id] = GRANT_INVALID_REF;
+ add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
+ dev_kfree_skb_irq(skb);
+ }
+
+ np->tx.rsp_cons = prod;
+
+ /*
+ * Set a new event, then check for race with update of tx_cons.
+ * Note that it is essential to schedule a callback, no matter
+ * how few buffers are pending. Even if there is space in the
+ * transmit ring, higher layers may be blocked because too much
+ * data is outstanding: in such cases notification from Xen is
+ * likely to be the only kick that we'll get.
+ */
+ np->tx.sring->rsp_event =
+ prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+ mb(); /* update shared area */
+ } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+ xennet_maybe_wake_tx(dev);
+}
+
+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
+ struct xen_netif_tx_request *tx)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ char *data = skb->data;
+ unsigned long mfn;
+ RING_IDX prod = np->tx.req_prod_pvt;
+ int frags = skb_shinfo(skb)->nr_frags;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+ unsigned int id;
+ grant_ref_t ref;
+ int i;
+
+ /* While the header overlaps a page boundary (including being
+ larger than a page), split it it into page-sized chunks. */
+ while (len > PAGE_SIZE - offset) {
+ tx->size = PAGE_SIZE - offset;
+ tx->flags |= NETTXF_more_data;
+ len -= tx->size;
+ data += tx->size;
+ offset = 0;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = virt_to_mfn(data);
+ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = len;
+ tx->flags = 0;
+ }
+
+ /* Grant backend access to each skb fragment page. */
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+ tx->flags |= NETTXF_more_data;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = pfn_to_mfn(page_to_pfn(frag->page));
+ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = frag->page_offset;
+ tx->size = frag->size;
+ tx->flags = 0;
+ }
+
+ np->tx.req_prod_pvt = prod;
+}
+
+static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct xen_netif_tx_request *tx;
+ struct xen_netif_extra_info *extra;
+ char *data = skb->data;
+ RING_IDX i;
+ grant_ref_t ref;
+ unsigned long mfn;
+ int notify;
+ int frags = skb_shinfo(skb)->nr_frags;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+
+ frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+ if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
+ printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
+ frags);
+ dump_stack();
+ goto drop;
+ }
+
+ spin_lock_irq(&np->tx_lock);
+
+ if (unlikely(!netif_carrier_ok(dev) ||
+ (frags > 1 && !xennet_can_sg(dev)) ||
+ netif_needs_gso(dev, skb))) {
+ spin_unlock_irq(&np->tx_lock);
+ goto drop;
+ }
+
+ i = np->tx.req_prod_pvt;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb;
+
+ tx = RING_GET_REQUEST(&np->tx, i);
+
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+ mfn = virt_to_mfn(data);
+ gnttab_grant_foreign_access_ref(
+ ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = len;
+ extra = NULL;
+
+ tx->flags = 0;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ /* local packet? */
+ tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed. */
+ tx->flags |= NETTXF_data_validated;
+
+ if (skb_shinfo(skb)->gso_size) {
+ struct xen_netif_extra_info *gso;
+
+ gso = (struct xen_netif_extra_info *)
+ RING_GET_REQUEST(&np->tx, ++i);
+
+ if (extra)
+ extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+ else
+ tx->flags |= NETTXF_extra_info;
+
+ gso->u.gso.size = skb_shinfo(skb)->gso_size;
+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+ gso->u.gso.pad = 0;
+ gso->u.gso.features = 0;
+
+ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+ gso->flags = 0;
+ extra = gso;
+ }
+
+ np->tx.req_prod_pvt = i + 1;
+
+ xennet_make_frags(skb, dev, tx);
+ tx->size = skb->len;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
+ if (notify)
+ notify_remote_via_irq(np->netdev->irq);
+
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+
+ /* Note: It is not safe to access skb after xennet_tx_buf_gc()! */
+ xennet_tx_buf_gc(dev);
+
+ if (!netfront_tx_slot_available(np))
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&np->tx_lock);
+
+ return 0;
+
+ drop:
+ dev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static int xennet_close(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ netif_stop_queue(np->netdev);
+ napi_disable(&np->napi);
+ return 0;
+}
+
+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
+ grant_ref_t ref)
+{
+ int new = xennet_rxidx(np->rx.req_prod_pvt);
+
+ BUG_ON(np->rx_skbs[new]);
+ np->rx_skbs[new] = skb;
+ np->grant_rx_ref[new] = ref;
+ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
+ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
+ np->rx.req_prod_pvt++;
+}
+
+static int xennet_get_extras(struct netfront_info *np,
+ struct xen_netif_extra_info *extras,
+ RING_IDX rp)
+
+{
+ struct xen_netif_extra_info *extra;
+ struct device *dev = &np->netdev->dev;
+ RING_IDX cons = np->rx.rsp_cons;
+ int err = 0;
+
+ do {
+ struct sk_buff *skb;
+ grant_ref_t ref;
+
+ if (unlikely(cons + 1 == rp)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Missing extra info\n");
+ err = -EBADR;
+ break;
+ }
+
+ extra = (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&np->rx, ++cons);
+
+ if (unlikely(!extra->type ||
+ extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Invalid extra type: %d\n",
+ extra->type);
+ err = -EINVAL;
+ } else {
+ memcpy(&extras[extra->type - 1], extra,
+ sizeof(*extra));
+ }
+
+ skb = xennet_get_rx_skb(np, cons);
+ ref = xennet_get_rx_ref(np, cons);
+ xennet_move_rx_slot(np, skb, ref);
+ } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+ np->rx.rsp_cons = cons;
+ return err;
+}
+
+static int xennet_get_responses(struct netfront_info *np,
+ struct netfront_rx_info *rinfo, RING_IDX rp,
+ struct sk_buff_head *list)
+{
+ struct xen_netif_rx_response *rx = &rinfo->rx;
+ struct xen_netif_extra_info *extras = rinfo->extras;
+ struct device *dev = &np->netdev->dev;
+ RING_IDX cons = np->rx.rsp_cons;
+ struct sk_buff *skb = xennet_get_rx_skb(np, cons);
+ grant_ref_t ref = xennet_get_rx_ref(np, cons);
+ int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+ int frags = 1;
+ int err = 0;
+ unsigned long ret;
+
+ if (rx->flags & NETRXF_extra_info) {
+ err = xennet_get_extras(np, extras, rp);
+ cons = np->rx.rsp_cons;
+ }
+
+ for (;;) {
+ if (unlikely(rx->status < 0 ||
+ rx->offset + rx->status > PAGE_SIZE)) {
+ if (net_ratelimit())
+ dev_warn(dev, "rx->offset: %x, size: %u\n",
+ rx->offset, rx->status);
+ xennet_move_rx_slot(np, skb, ref);
+ err = -EINVAL;
+ goto next;
+ }
+
+ /*
+ * This definitely indicates a bug, either in this driver or in
+ * the backend driver. In future this should flag the bad
+ * situation to the system controller to reboot the backed.
+ */
+ if (ref == GRANT_INVALID_REF) {
+ if (net_ratelimit())
+ dev_warn(dev, "Bad rx response id %d.\n",
+ rx->id);
+ err = -EINVAL;
+ goto next;
+ }
+
+ ret = gnttab_end_foreign_access_ref(ref, 0);
+ BUG_ON(!ret);
+
+ gnttab_release_grant_reference(&np->gref_rx_head, ref);
+
+ __skb_queue_tail(list, skb);
+
+next:
+ if (!(rx->flags & NETRXF_more_data))
+ break;
+
+ if (cons + frags == rp) {
+ if (net_ratelimit())
+ dev_warn(dev, "Need more frags\n");
+ err = -ENOENT;
+ break;
+ }
+
+ rx = RING_GET_RESPONSE(&np->rx, cons + frags);
+ skb = xennet_get_rx_skb(np, cons + frags);
+ ref = xennet_get_rx_ref(np, cons + frags);
+ frags++;
+ }
+
+ if (unlikely(frags > max)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Too many frags\n");
+ err = -E2BIG;
+ }
+
+ if (unlikely(err))
+ np->rx.rsp_cons = cons + frags;
+
+ return err;
+}
+
+static int xennet_set_skb_gso(struct sk_buff *skb,
+ struct xen_netif_extra_info *gso)
+{
+ if (!gso->u.gso.size) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "GSO size must not be zero.\n");
+ return -EINVAL;
+ }
+
+ /* Currently only TCPv4 S.O. is supported. */
+ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type);
+ return -EINVAL;
+ }
+
+ skb_shinfo(skb)->gso_size = gso->u.gso.size;
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+ /* Header must be checked, and gso_segs computed. */
+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+ skb_shinfo(skb)->gso_segs = 0;
+
+ return 0;
+}
+
+static RING_IDX xennet_fill_frags(struct netfront_info *np,
+ struct sk_buff *skb,
+ struct sk_buff_head *list)
+{
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ int nr_frags = shinfo->nr_frags;
+ RING_IDX cons = np->rx.rsp_cons;
+ skb_frag_t *frag = shinfo->frags + nr_frags;
+ struct sk_buff *nskb;
+
+ while ((nskb = __skb_dequeue(list))) {
+ struct xen_netif_rx_response *rx =
+ RING_GET_RESPONSE(&np->rx, ++cons);
+
+ frag->page = skb_shinfo(nskb)->frags[0].page;
+ frag->page_offset = rx->offset;
+ frag->size = rx->status;
+
+ skb->data_len += rx->status;
+
+ skb_shinfo(nskb)->nr_frags = 0;
+ kfree_skb(nskb);
+
+ frag++;
+ nr_frags++;
+ }
+
+ shinfo->nr_frags = nr_frags;
+ return cons;
+}
+
+static int skb_checksum_setup(struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ unsigned char *th;
+ int err = -EPROTO;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
+
+ iph = (void *)skb->data;
+ th = skb->data + 4 * iph->ihl;
+ if (th >= skb_tail_pointer(skb))
+ goto out;
+
+ skb->csum_start = th - skb->head;
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ skb->csum_offset = offsetof(struct tcphdr, check);
+ break;
+ case IPPROTO_UDP:
+ skb->csum_offset = offsetof(struct udphdr, check);
+ break;
+ default:
+ if (net_ratelimit())
+ printk(KERN_ERR "Attempting to checksum a non-"
+ "TCP/UDP packet, dropping a protocol"
+ " %d packet", iph->protocol);
+ goto out;
+ }
+
+ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+ goto out;
+
+ err = 0;
+
+out:
+ return err;
+}
+
+static int handle_incoming_queue(struct net_device *dev,
+ struct sk_buff_head *rxq)
+{
+ int packets_dropped = 0;
+ struct sk_buff *skb;
+
+ while ((skb = __skb_dequeue(rxq)) != NULL) {
+ struct page *page = NETFRONT_SKB_CB(skb)->page;
+ void *vaddr = page_address(page);
+ unsigned offset = NETFRONT_SKB_CB(skb)->offset;
+
+ memcpy(skb->data, vaddr + offset,
+ skb_headlen(skb));
+
+ if (page != skb_shinfo(skb)->frags[0].page)
+ __free_page(page);
+
+ /* Ethernet work: Delayed to here as it peeks the header. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_checksum_setup(skb)) {
+ kfree_skb(skb);
+ packets_dropped++;
+ dev->stats.rx_errors++;
+ continue;
+ }
+ }
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+
+ /* Pass it up. */
+ netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ }
+
+ return packets_dropped;
+}
+
+static int xennet_poll(struct napi_struct *napi, int budget)
+{
+ struct netfront_info *np = container_of(napi, struct netfront_info, napi);
+ struct net_device *dev = np->netdev;
+ struct sk_buff *skb;
+ struct netfront_rx_info rinfo;
+ struct xen_netif_rx_response *rx = &rinfo.rx;
+ struct xen_netif_extra_info *extras = rinfo.extras;
+ RING_IDX i, rp;
+ int work_done;
+ struct sk_buff_head rxq;
+ struct sk_buff_head errq;
+ struct sk_buff_head tmpq;
+ unsigned long flags;
+ unsigned int len;
+ int err;
+
+ spin_lock(&np->rx_lock);
+
+ if (unlikely(!netif_carrier_ok(dev))) {
+ spin_unlock(&np->rx_lock);
+ return 0;
+ }
+
+ skb_queue_head_init(&rxq);
+ skb_queue_head_init(&errq);
+ skb_queue_head_init(&tmpq);
+
+ rp = np->rx.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ i = np->rx.rsp_cons;
+ work_done = 0;
+ while ((i != rp) && (work_done < budget)) {
+ memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
+ memset(extras, 0, sizeof(rinfo.extras));
+
+ err = xennet_get_responses(np, &rinfo, rp, &tmpq);
+
+ if (unlikely(err)) {
+err:
+ while ((skb = __skb_dequeue(&tmpq)))
+ __skb_queue_tail(&errq, skb);
+ dev->stats.rx_errors++;
+ i = np->rx.rsp_cons;
+ continue;
+ }
+
+ skb = __skb_dequeue(&tmpq);
+
+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+ struct xen_netif_extra_info *gso;
+ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+ if (unlikely(xennet_set_skb_gso(skb, gso))) {
+ __skb_queue_head(&tmpq, skb);
+ np->rx.rsp_cons += skb_queue_len(&tmpq);
+ goto err;
+ }
+ }
+
+ NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+ NETFRONT_SKB_CB(skb)->offset = rx->offset;
+
+ len = rx->status;
+ if (len > RX_COPY_THRESHOLD)
+ len = RX_COPY_THRESHOLD;
+ skb_put(skb, len);
+
+ if (rx->status > len) {
+ skb_shinfo(skb)->frags[0].page_offset =
+ rx->offset + len;
+ skb_shinfo(skb)->frags[0].size = rx->status - len;
+ skb->data_len = rx->status - len;
+ } else {
+ skb_shinfo(skb)->frags[0].page = NULL;
+ skb_shinfo(skb)->nr_frags = 0;
+ }
+
+ i = xennet_fill_frags(np, skb, &tmpq);
+
+ /*
+ * Truesize approximates the size of true data plus
+ * any supervisor overheads. Adding hypervisor
+ * overheads has been shown to significantly reduce
+ * achievable bandwidth with the default receive
+ * buffer size. It is therefore not wise to account
+ * for it here.
+ *
+ * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
+ * to RX_COPY_THRESHOLD + the supervisor
+ * overheads. Here, we add the size of the data pulled
+ * in xennet_fill_frags().
+ *
+ * We also adjust for any unused space in the main
+ * data area by subtracting (RX_COPY_THRESHOLD -
+ * len). This is especially important with drivers
+ * which split incoming packets into header and data,
+ * using only 66 bytes of the main data area (see the
+ * e1000 driver for example.) On such systems,
+ * without this last adjustement, our achievable
+ * receive throughout using the standard receive
+ * buffer size was cut by 25%(!!!).
+ */
+ skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+ skb->len += skb->data_len;
+
+ if (rx->flags & NETRXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ else if (rx->flags & NETRXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ __skb_queue_tail(&rxq, skb);
+
+ np->rx.rsp_cons = ++i;
+ work_done++;
+ }
+
+ while ((skb = __skb_dequeue(&errq)))
+ kfree_skb(skb);
+
+ work_done -= handle_incoming_queue(dev, &rxq);
+
+ /* If we get a callback with very few responses, reduce fill target. */
+ /* NB. Note exponential increase, linear decrease. */
+ if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
+ ((3*np->rx_target) / 4)) &&
+ (--np->rx_target < np->rx_min_target))
+ np->rx_target = np->rx_min_target;
+
+ xennet_alloc_rx_buffers(dev);
+
+ if (work_done < budget) {
+ int more_to_do = 0;
+
+ local_irq_save(flags);
+
+ RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
+ if (!more_to_do)
+ __netif_rx_complete(dev, napi);
+
+ local_irq_restore(flags);
+ }
+
+ spin_unlock(&np->rx_lock);
+
+ return work_done;
+}
+
+static int xennet_change_mtu(struct net_device *dev, int mtu)
+{
+ int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+ if (mtu > max)
+ return -EINVAL;
+ dev->mtu = mtu;
+ return 0;
+}
+
+static void xennet_release_tx_bufs(struct netfront_info *np)
+{
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ /* Skip over entries which are actually freelist references */
+ if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET)
+ continue;
+
+ skb = np->tx_skbs[i].skb;
+ gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
+ GNTMAP_readonly);
+ gnttab_release_grant_reference(&np->gref_tx_head,
+ np->grant_tx_ref[i]);
+ np->grant_tx_ref[i] = GRANT_INVALID_REF;
+ add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
+ dev_kfree_skb_irq(skb);
+ }
+}
+
+static void xennet_release_rx_bufs(struct netfront_info *np)
+{
+ struct mmu_update *mmu = np->rx_mmu;
+ struct multicall_entry *mcl = np->rx_mcl;
+ struct sk_buff_head free_list;
+ struct sk_buff *skb;
+ unsigned long mfn;
+ int xfer = 0, noxfer = 0, unused = 0;
+ int id, ref;
+
+ dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
+ __func__);
+ return;
+
+ skb_queue_head_init(&free_list);
+
+ spin_lock_bh(&np->rx_lock);
+
+ for (id = 0; id < NET_RX_RING_SIZE; id++) {
+ ref = np->grant_rx_ref[id];
+ if (ref == GRANT_INVALID_REF) {
+ unused++;
+ continue;
+ }
+
+ skb = np->rx_skbs[id];
+ mfn = gnttab_end_foreign_transfer_ref(ref);
+ gnttab_release_grant_reference(&np->gref_rx_head, ref);
+ np->grant_rx_ref[id] = GRANT_INVALID_REF;
+
+ if (0 == mfn) {
+ skb_shinfo(skb)->nr_frags = 0;
+ dev_kfree_skb(skb);
+ noxfer++;
+ continue;
+ }
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Remap the page. */
+ struct page *page = skb_shinfo(skb)->frags[0].page;
+ unsigned long pfn = page_to_pfn(page);
+ void *vaddr = page_address(page);
+
+ MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
+ mfn_pte(mfn, PAGE_KERNEL),
+ 0);
+ mcl++;
+ mmu->ptr = ((u64)mfn << PAGE_SHIFT)
+ | MMU_MACHPHYS_UPDATE;
+ mmu->val = pfn;
+ mmu++;
+
+ set_phys_to_machine(pfn, mfn);
+ }
+ __skb_queue_tail(&free_list, skb);
+ xfer++;
+ }
+
+ dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
+ __func__, xfer, noxfer, unused);
+
+ if (xfer) {
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Do all the remapping work and M2P updates. */
+ MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
+ 0, DOMID_SELF);
+ mcl++;
+ HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
+ }
+ }
+
+ while ((skb = __skb_dequeue(&free_list)) != NULL)
+ dev_kfree_skb(skb);
+
+ spin_unlock_bh(&np->rx_lock);
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ xennet_release_tx_bufs(np);
+ xennet_release_rx_bufs(np);
+ gnttab_free_grant_references(np->gref_tx_head);
+ gnttab_free_grant_references(np->gref_rx_head);
+}
+
+static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
+{
+ int i, err;
+ struct net_device *netdev;
+ struct netfront_info *np;
+
+ netdev = alloc_etherdev(sizeof(struct netfront_info));
+ if (!netdev) {
+ printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ np = netdev_priv(netdev);
+ np->xbdev = dev;
+
+ spin_lock_init(&np->tx_lock);
+ spin_lock_init(&np->rx_lock);
+
+ skb_queue_head_init(&np->rx_batch);
+ np->rx_target = RX_DFL_MIN_TARGET;
+ np->rx_min_target = RX_DFL_MIN_TARGET;
+ np->rx_max_target = RX_MAX_TARGET;
+
+ init_timer(&np->rx_refill_timer);
+ np->rx_refill_timer.data = (unsigned long)netdev;
+ np->rx_refill_timer.function = rx_refill_timeout;
+
+ /* Initialise tx_skbs as a free chain containing every entry. */
+ np->tx_skb_freelist = 0;
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ np->tx_skbs[i].link = i+1;
+ np->grant_tx_ref[i] = GRANT_INVALID_REF;
+ }
+
+ /* Clear out rx_skbs */
+ for (i = 0; i < NET_RX_RING_SIZE; i++) {
+ np->rx_skbs[i] = NULL;
+ np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ }
+
+ /* A grant for every tx ring slot */
+ if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+ &np->gref_tx_head) < 0) {
+ printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ /* A grant for every rx ring slot */
+ if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+ &np->gref_rx_head) < 0) {
+ printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
+ err = -ENOMEM;
+ goto exit_free_tx;
+ }
+
+ netdev->open = xennet_open;
+ netdev->hard_start_xmit = xennet_start_xmit;
+ netdev->stop = xennet_close;
+ netif_napi_add(netdev, &np->napi, xennet_poll, 64);
+ netdev->uninit = xennet_uninit;
+ netdev->change_mtu = xennet_change_mtu;
+ netdev->features = NETIF_F_IP_CSUM;
+
+ SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
+ SET_NETDEV_DEV(netdev, &dev->dev);
+
+ np->netdev = netdev;
+
+ netif_carrier_off(netdev);
+
+ return netdev;
+
+ exit_free_tx:
+ gnttab_free_grant_references(np->gref_tx_head);
+ exit:
+ free_netdev(netdev);
+ return ERR_PTR(err);
+}
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int __devinit netfront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err;
+ struct net_device *netdev;
+ struct netfront_info *info;
+
+ netdev = xennet_create_dev(dev);
+ if (IS_ERR(netdev)) {
+ err = PTR_ERR(netdev);
+ xenbus_dev_fatal(dev, err, "creating netdev");
+ return err;
+ }
+
+ info = netdev_priv(netdev);
+ dev->dev.driver_data = info;
+
+ err = register_netdev(info->netdev);
+ if (err) {
+ printk(KERN_WARNING "%s: register_netdev err=%d\n",
+ __func__, err);
+ goto fail;
+ }
+
+ err = xennet_sysfs_addif(info->netdev);
+ if (err) {
+ unregister_netdev(info->netdev);
+ printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
+ __func__, err);
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ free_netdev(netdev);
+ dev->dev.driver_data = NULL;
+ return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+ /* This frees the page as a side-effect */
+ if (ref != GRANT_INVALID_REF)
+ gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info)
+{
+ /* Stop old i/f to prevent errors whilst we rebuild the state. */
+ spin_lock_bh(&info->rx_lock);
+ spin_lock_irq(&info->tx_lock);
+ netif_carrier_off(info->netdev);
+ spin_unlock_irq(&info->tx_lock);
+ spin_unlock_bh(&info->rx_lock);
+
+ if (info->netdev->irq)
+ unbind_from_irqhandler(info->netdev->irq, info->netdev);
+ info->evtchn = info->netdev->irq = 0;
+
+ /* End access and free the pages */
+ xennet_end_access(info->tx_ring_ref, info->tx.sring);
+ xennet_end_access(info->rx_ring_ref, info->rx.sring);
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->tx.sring = NULL;
+ info->rx.sring = NULL;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int netfront_resume(struct xenbus_device *dev)
+{
+ struct netfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+ xennet_disconnect_backend(info);
+ return 0;
+}
+
+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
+ char *s, *e, *macstr;
+ int i;
+
+ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+ if (IS_ERR(macstr))
+ return PTR_ERR(macstr);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ mac[i] = simple_strtoul(s, &e, 16);
+ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+ kfree(macstr);
+ return -ENOENT;
+ }
+ s = e+1;
+ }
+
+ kfree(macstr);
+ return 0;
+}
+
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct netfront_info *np = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&np->tx_lock, flags);
+
+ if (likely(netif_carrier_ok(dev))) {
+ xennet_tx_buf_gc(dev);
+ /* Under tx_lock: protects access to rx shared-ring indexes. */
+ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ netif_rx_schedule(dev, &np->napi);
+ }
+
+ spin_unlock_irqrestore(&np->tx_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
+{
+ struct xen_netif_tx_sring *txs;
+ struct xen_netif_rx_sring *rxs;
+ int err;
+ struct net_device *netdev = info->netdev;
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->rx.sring = NULL;
+ info->tx.sring = NULL;
+ netdev->irq = 0;
+
+ err = xen_net_read_mac(dev, netdev->dev_addr);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+ goto fail;
+ }
+
+ txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+ if (!txs) {
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev, err, "allocating tx ring page");
+ goto fail;
+ }
+ SHARED_RING_INIT(txs);
+ FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(txs));
+ if (err < 0) {
+ free_page((unsigned long)txs);
+ goto fail;
+ }
+
+ info->tx_ring_ref = err;
+ rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+ if (!rxs) {
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev, err, "allocating rx ring page");
+ goto fail;
+ }
+ SHARED_RING_INIT(rxs);
+ FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
+ if (err < 0) {
+ free_page((unsigned long)rxs);
+ goto fail;
+ }
+ info->rx_ring_ref = err;
+
+ err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (err)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
+ IRQF_SAMPLE_RANDOM, netdev->name,
+ netdev);
+ if (err < 0)
+ goto fail;
+ netdev->irq = err;
+ return 0;
+
+ fail:
+ return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+ struct netfront_info *info)
+{
+ const char *message;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_netfront(dev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_ring;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",
+ info->tx_ring_ref);
+ if (err) {
+ message = "writing tx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",
+ info->rx_ring_ref);
+ if (err) {
+ message = "writing rx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
+ 1);
+ if (err) {
+ message = "writing request-rx-copy";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
+ if (err) {
+ message = "writing feature-rx-notify";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
+ if (err) {
+ message = "writing feature-sg";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
+ if (err) {
+ message = "writing feature-gso-tcpv4";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_ring;
+ }
+
+ return 0;
+
+ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_ring:
+ xennet_disconnect_backend(info);
+ out:
+ return err;
+}
+
+static int xennet_set_sg(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+ "%d", &val) < 0)
+ val = 0;
+ if (!val)
+ return -ENOSYS;
+ } else if (dev->mtu > ETH_DATA_LEN)
+ dev->mtu = ETH_DATA_LEN;
+
+ return ethtool_op_set_sg(dev, data);
+}
+
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-gso-tcpv4", "%d", &val) < 0)
+ val = 0;
+ if (!val)
+ return -ENOSYS;
+ }
+
+ return ethtool_op_set_tso(dev, data);
+}
+
+static void xennet_set_features(struct net_device *dev)
+{
+ /* Turn off all GSO bits except ROBUST. */
+ dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+ dev->features |= NETIF_F_GSO_ROBUST;
+ xennet_set_sg(dev, 0);
+
+ /* We need checksum offload to enable scatter/gather and TSO. */
+ if (!(dev->features & NETIF_F_IP_CSUM))
+ return;
+
+ if (!xennet_set_sg(dev, 1))
+ xennet_set_tso(dev, 1);
+}
+
+static int xennet_connect(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ int i, requeue_idx, err;
+ struct sk_buff *skb;
+ grant_ref_t ref;
+ struct xen_netif_rx_request *req;
+ unsigned int feature_rx_copy;
+
+ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-rx-copy", "%u", &feature_rx_copy);
+ if (err != 1)
+ feature_rx_copy = 0;
+
+ if (!feature_rx_copy) {
+ dev_info(&dev->dev,
+ "backend does not support copying recieve path");
+ return -ENODEV;
+ }
+
+ err = talk_to_backend(np->xbdev, np);
+ if (err)
+ return err;
+
+ xennet_set_features(dev);
+
+ spin_lock_bh(&np->rx_lock);
+ spin_lock_irq(&np->tx_lock);
+
+ /* Step 1: Discard all pending TX packet fragments. */
+ xennet_release_tx_bufs(np);
+
+ /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+ for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+ if (!np->rx_skbs[i])
+ continue;
+
+ skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
+ ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
+ req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+ gnttab_grant_foreign_access_ref(
+ ref, np->xbdev->otherend_id,
+ pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+ frags->page)),
+ 0);
+ req->gref = ref;
+ req->id = requeue_idx;
+
+ requeue_idx++;
+ }
+
+ np->rx.req_prod_pvt = requeue_idx;
+
+ /*
+ * Step 3: All public and private state should now be sane. Get
+ * ready to start sending and receiving packets and give the driver
+ * domain a kick because we've probably just requeued some
+ * packets.
+ */
+ netif_carrier_on(np->netdev);
+ notify_remote_via_irq(np->netdev->irq);
+ xennet_tx_buf_gc(dev);
+ xennet_alloc_rx_buffers(dev);
+
+ spin_unlock_irq(&np->tx_lock);
+ spin_unlock_bh(&np->rx_lock);
+
+ return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct netfront_info *np = dev->dev.driver_data;
+ struct net_device *netdev = np->netdev;
+
+ dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateInitWait:
+ if (dev->state != XenbusStateInitialising)
+ break;
+ if (xennet_connect(netdev) != 0)
+ break;
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ xenbus_frontend_closed(dev);
+ break;
+ }
+}
+
+static struct ethtool_ops xennet_ethtool_ops =
+{
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_sg = xennet_set_sg,
+ .set_tso = xennet_set_tso,
+ .get_link = ethtool_op_get_link,
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_rxbuf_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_min_target);
+}
+
+static ssize_t store_rxbuf_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *np = netdev_priv(netdev);
+ char *endp;
+ unsigned long target;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ target = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EBADMSG;
+
+ if (target < RX_MIN_TARGET)
+ target = RX_MIN_TARGET;
+ if (target > RX_MAX_TARGET)
+ target = RX_MAX_TARGET;
+
+ spin_lock_bh(&np->rx_lock);
+ if (target > np->rx_max_target)
+ np->rx_max_target = target;
+ np->rx_min_target = target;
+ if (target > np->rx_target)
+ np->rx_target = target;
+
+ xennet_alloc_rx_buffers(netdev);
+
+ spin_unlock_bh(&np->rx_lock);
+ return len;
+}
+
+static ssize_t show_rxbuf_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_max_target);
+}
+
+static ssize_t store_rxbuf_max(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *np = netdev_priv(netdev);
+ char *endp;
+ unsigned long target;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ target = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EBADMSG;
+
+ if (target < RX_MIN_TARGET)
+ target = RX_MIN_TARGET;
+ if (target > RX_MAX_TARGET)
+ target = RX_MAX_TARGET;
+
+ spin_lock_bh(&np->rx_lock);
+ if (target < np->rx_min_target)
+ np->rx_min_target = target;
+ np->rx_max_target = target;
+ if (target < np->rx_target)
+ np->rx_target = target;
+
+ xennet_alloc_rx_buffers(netdev);
+
+ spin_unlock_bh(&np->rx_lock);
+ return len;
+}
+
+static ssize_t show_rxbuf_cur(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_target);
+}
+
+static struct device_attribute xennet_attrs[] = {
+ __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
+ __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
+ __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+};
+
+static int xennet_sysfs_addif(struct net_device *netdev)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
+ err = device_create_file(&netdev->dev,
+ &xennet_attrs[i]);
+ if (err)
+ goto fail;
+ }
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ device_remove_file(&netdev->dev, &xennet_attrs[i]);
+ return err;
+}
+
+static void xennet_sysfs_delif(struct net_device *netdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
+ device_remove_file(&netdev->dev, &xennet_attrs[i]);
+}
+
+#endif /* CONFIG_SYSFS */
+
+static struct xenbus_device_id netfront_ids[] = {
+ { "vif" },
+ { "" }
+};
+
+
+static int __devexit xennet_remove(struct xenbus_device *dev)
+{
+ struct netfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+ unregister_netdev(info->netdev);
+
+ xennet_disconnect_backend(info);
+
+ del_timer_sync(&info->rx_refill_timer);
+
+ xennet_sysfs_delif(info->netdev);
+
+ free_netdev(info->netdev);
+
+ return 0;
+}
+
+static struct xenbus_driver netfront = {
+ .name = "vif",
+ .owner = THIS_MODULE,
+ .ids = netfront_ids,
+ .probe = netfront_probe,
+ .remove = __devexit_p(xennet_remove),
+ .resume = netfront_resume,
+ .otherend_changed = backend_changed,
+};
+
+static int __init netif_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ if (is_initial_xendomain())
+ return 0;
+
+ printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
+
+ return xenbus_register_frontend(&netfront);
+}
+module_init(netif_init);
+
+
+static void __exit netif_exit(void)
+{
+ if (is_initial_xendomain())
+ return;
+
+ return xenbus_unregister_driver(&netfront);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 870c5393c21a..87f002ade531 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -318,7 +318,6 @@ struct yellowfin_private {
dma_addr_t tx_status_dma;
struct timer_list timer; /* Media selection timer. */
- struct net_device_stats stats;
/* Frequently used and paired value: keep adjacent for cache effect. */
int chip_id, drv_flags;
struct pci_dev *pci_dev;
@@ -353,7 +352,6 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
static int yellowfin_rx(struct net_device *dev);
static void yellowfin_error(struct net_device *dev, int intr_status);
static int yellowfin_close(struct net_device *dev);
-static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static const struct ethtool_ops ethtool_ops;
@@ -376,6 +374,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
#else
int bar = 1;
#endif
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -392,7 +391,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
printk (KERN_ERR PFX "cannot allocate ethernet device\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
np = netdev_priv(dev);
@@ -470,7 +468,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
dev->open = &yellowfin_open;
dev->hard_start_xmit = &yellowfin_start_xmit;
dev->stop = &yellowfin_close;
- dev->get_stats = &yellowfin_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &netdev_ioctl;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
@@ -484,12 +481,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
if (i)
goto err_out_unmap_status;
- printk(KERN_INFO "%s: %s type %8x at %p, ",
+ printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n",
dev->name, pci_id_tbl[chip_idx].name,
- ioread32(ioaddr + ChipRev), ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ ioread32(ioaddr + ChipRev), ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
if (np->drv_flags & HasMII) {
int phy, phy_idx = 0;
@@ -718,7 +713,7 @@ static void yellowfin_tx_timeout(struct net_device *dev)
netif_wake_queue (dev); /* Typical path */
dev->trans_start = jiffies;
- yp->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -924,8 +919,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
if (yp->tx_ring[entry].result_status == 0)
break;
skb = yp->tx_skbuff[entry];
- yp->stats.tx_packets++;
- yp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
/* Free the original skb. */
pci_unmap_single(yp->pci_dev, yp->tx_ring[entry].addr,
skb->len, PCI_DMA_TODEVICE);
@@ -969,20 +964,20 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
dev->name, tx_errs);
#endif
- yp->stats.tx_errors++;
- if (tx_errs & 0xF800) yp->stats.tx_aborted_errors++;
- if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++;
- if (tx_errs & 0x2000) yp->stats.tx_window_errors++;
- if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++;
+ if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++;
+ if (tx_errs & 0x2000) dev->stats.tx_window_errors++;
+ if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++;
} else {
#ifndef final_version
if (yellowfin_debug > 4)
printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
dev->name, tx_errs);
#endif
- yp->stats.tx_bytes += skb->len;
- yp->stats.collisions += tx_errs & 15;
- yp->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.collisions += tx_errs & 15;
+ dev->stats.tx_packets++;
}
/* Free the original skb. */
pci_unmap_single(yp->pci_dev,
@@ -1077,26 +1072,26 @@ static int yellowfin_rx(struct net_device *dev)
if (data_size != 0)
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
" status %4.4x, data_size %d!\n", dev->name, desc_status, data_size);
- yp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) {
/* There was a error. */
if (yellowfin_debug > 3)
printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n",
frame_status);
- yp->stats.rx_errors++;
- if (frame_status & 0x0060) yp->stats.rx_length_errors++;
- if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
- if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
- if (frame_status < 0) yp->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ if (frame_status & 0x0060) dev->stats.rx_length_errors++;
+ if (frame_status & 0x0008) dev->stats.rx_frame_errors++;
+ if (frame_status & 0x0010) dev->stats.rx_crc_errors++;
+ if (frame_status < 0) dev->stats.rx_dropped++;
} else if ( !(yp->drv_flags & IsGigabit) &&
((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
u8 status1 = buf_addr[data_size-2];
u8 status2 = buf_addr[data_size-1];
- yp->stats.rx_errors++;
- if (status1 & 0xC0) yp->stats.rx_length_errors++;
- if (status2 & 0x03) yp->stats.rx_frame_errors++;
- if (status2 & 0x04) yp->stats.rx_crc_errors++;
- if (status2 & 0x80) yp->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ if (status1 & 0xC0) dev->stats.rx_length_errors++;
+ if (status2 & 0x03) dev->stats.rx_frame_errors++;
+ if (status2 & 0x04) dev->stats.rx_crc_errors++;
+ if (status2 & 0x80) dev->stats.rx_dropped++;
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
} else if ((yp->flags & HasMACAddrBug) &&
memcmp(le32_to_cpu(yp->rx_ring_dma +
@@ -1105,11 +1100,11 @@ static int yellowfin_rx(struct net_device *dev)
memcmp(le32_to_cpu(yp->rx_ring_dma +
entry*sizeof(struct yellowfin_desc)),
"\377\377\377\377\377\377", 6) != 0) {
- if (bogus_rx++ == 0)
- printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:"
- "%2.2x:%2.2x.\n",
- dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
- buf_addr[3], buf_addr[4], buf_addr[5]);
+ if (bogus_rx++ == 0) {
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_WARNING "%s: Bad frame to %s\n",
+ dev->name, print_mac(mac, buf_addr));
+ }
#endif
} else {
struct sk_buff *skb;
@@ -1146,8 +1141,8 @@ static int yellowfin_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- yp->stats.rx_packets++;
- yp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
entry = (++yp->cur_rx) % RX_RING_SIZE;
}
@@ -1181,15 +1176,13 @@ static int yellowfin_rx(struct net_device *dev)
static void yellowfin_error(struct net_device *dev, int intr_status)
{
- struct yellowfin_private *yp = netdev_priv(dev);
-
printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
dev->name, intr_status);
/* Hmmmmm, it's not clear what to do here. */
if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
- yp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
- yp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
static int yellowfin_close(struct net_device *dev)
@@ -1281,12 +1274,6 @@ static int yellowfin_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- return &yp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor. */
static void set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 4032e9f6f9b0..a86c022d6a94 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -128,7 +128,6 @@ MODULE_LICENSE("GPL");
struct znet_private {
int rx_dma, tx_dma;
- struct net_device_stats stats;
spinlock_t lock;
short sia_base, sia_size, io_size;
struct i82593_conf_block i593_init;
@@ -161,7 +160,6 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t znet_interrupt(int irq, void *dev_id);
static void znet_rx(struct net_device *dev);
static int znet_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
static void hardware_init(struct net_device *dev);
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
static void znet_tx_timeout (struct net_device *dev);
@@ -372,6 +370,7 @@ static int __init znet_probe (void)
struct net_device *dev;
char *p;
int err = -ENOMEM;
+ DECLARE_MAC_BUF(mac);
/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
@@ -388,22 +387,20 @@ static int __init znet_probe (void)
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER (dev);
-
znet = dev->priv;
netinfo = (struct netidblk *)p;
dev->base_addr = netinfo->iobase1;
dev->irq = netinfo->irq1;
- printk(KERN_INFO "%s: ZNET at %#3lx,", dev->name, dev->base_addr);
-
/* The station address is in the "netidblk" at 0x0f0000. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]);
+ dev->dev_addr[i] = netinfo->netid[i];
- printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1,
- netinfo->dma2);
+ printk(KERN_INFO "%s: ZNET at %#3lx, %s"
+ ", using IRQ %d DMA %d and %d.\n",
+ dev->name, dev->base_addr, print_mac(mac, dev->dev_addr),
+ dev->irq, netinfo->dma1, netinfo->dma2);
if (znet_debug > 1) {
printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
@@ -447,7 +444,6 @@ static int __init znet_probe (void)
dev->open = &znet_open;
dev->hard_start_xmit = &znet_send_packet;
dev->stop = &znet_close;
- dev->get_stats = net_get_stats;
dev->set_multicast_list = &znet_set_multicast_list;
dev->tx_timeout = znet_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -566,7 +562,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
ushort *tx_link = znet->tx_cur - 1;
ushort rnd_len = (length + 1)>>1;
- znet->stats.tx_bytes+=length;
+ dev->stats.tx_bytes+=length;
if (znet->tx_cur >= znet->tx_end)
znet->tx_cur = znet->tx_start;
@@ -641,20 +637,20 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id)
tx_status = inw(ioaddr);
/* It's undocumented, but tx_status seems to match the i82586. */
if (tx_status & TX_OK) {
- znet->stats.tx_packets++;
- znet->stats.collisions += tx_status & TX_NCOL_MASK;
+ dev->stats.tx_packets++;
+ dev->stats.collisions += tx_status & TX_NCOL_MASK;
} else {
if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
- znet->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & TX_UND_RUN)
- znet->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (!(tx_status & TX_HRT_BEAT))
- znet->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (tx_status & TX_MAX_COL)
- znet->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
/* ...and the catch-all. */
if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
- znet->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Transceiver may be stuck if cable
* was removed while emiting a
@@ -750,19 +746,19 @@ static void znet_rx(struct net_device *dev)
this_rfp_ptr[-3]<<1);
/* Once again we must assume that the i82586 docs apply. */
if ( ! (status & RX_RCV_OK)) { /* There was an error. */
- znet->stats.rx_errors++;
- if (status & RX_CRC_ERR) znet->stats.rx_crc_errors++;
- if (status & RX_ALG_ERR) znet->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
+ if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
#if 0
- if (status & 0x0200) znet->stats.rx_over_errors++; /* Wrong. */
- if (status & 0x0100) znet->stats.rx_fifo_errors++;
+ if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
+ if (status & 0x0100) dev->stats.rx_fifo_errors++;
#else
/* maz : Wild guess... */
- if (status & RX_OVRRUN) znet->stats.rx_over_errors++;
+ if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
#endif
- if (status & RX_SRT_FRM) znet->stats.rx_length_errors++;
+ if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
} else if (pkt_len > 1536) {
- znet->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
@@ -771,7 +767,7 @@ static void znet_rx(struct net_device *dev)
if (skb == NULL) {
if (znet_debug)
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- znet->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -791,8 +787,8 @@ static void znet_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- znet->stats.rx_packets++;
- znet->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
znet->rx_cur = this_rfp_ptr;
if (znet->rx_cur >= znet->rx_end)
@@ -829,15 +825,6 @@ static int znet_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
- struct znet_private *znet = dev->priv;
-
- return &znet->stats;
-}
-
static void show_dma(struct net_device *dev)
{
short ioaddr = dev->base_addr;
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index d85e2ea0b6af..3926b2aa9cca 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -125,7 +125,6 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z,
dev = ____alloc_ei_netdev(0);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) {
free_netdev(dev);
return -EBUSY;
@@ -152,6 +151,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
};
+ DECLARE_MAC_BUF(mac);
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
@@ -191,7 +191,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
{0x00, NE_EN0_RSARHI},
{E8390_RREAD+E8390_START, NE_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
}
@@ -212,12 +212,12 @@ static int __devinit zorro8390_init(struct net_device *dev,
i = request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ dev->dev_addr[i] = SA_prom[i];
+
#ifdef DEBUG
- printk(" %2.2x", SA_prom[i]);
+ printk("%s", print_mac(mac, dev->dev_addr));
#endif
- dev->dev_addr[i] = SA_prom[i];
- }
ei_status.name = name;
ei_status.tx_start_page = start_page;
@@ -244,10 +244,8 @@ static int __devinit zorro8390_init(struct net_device *dev,
return err;
}
- printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n",
+ dev->name, name, board, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 3a0a3a734933..e503c9c98032 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -466,9 +466,8 @@ static struct nubus_dev* __init
parent->base, dir.base);
/* Actually we should probably panic if this fails */
- if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
+ if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->resid = parent->type;
dev->directory = dir.base;
dev->board = board;
@@ -800,9 +799,8 @@ static struct nubus_board* __init nubus_add_board(int slot, int bytelanes)
nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
/* Actually we should probably panic if this fails */
- if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
+ if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
return NULL;
- memset(board, 0, sizeof(*board));
board->fblock = rp;
/* Dump the format block for debugging purposes */
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 000000000000..c03072b12f42
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,3 @@
+config OF_DEVICE
+ def_bool y
+ depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 000000000000..ab9be5d5255b
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 000000000000..9377f3bc410a
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+ const int *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return *ip;
+ } while (np->parent);
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+ const int *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return *ip;
+ } while (np->parent);
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp)
+{
+ struct property *pp;
+
+ read_lock(&devtree_lock);
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (of_prop_cmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ read_unlock(&devtree_lock);
+
+ return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name, lenp);
+
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ const char* cp;
+ int cplen, l;
+
+ cp = of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ * of_get_parent - Get a node's parent if any
+ * @node: Node to get parent
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ struct device_node *np;
+
+ if (!node)
+ return NULL;
+
+ read_lock(&devtree_lock);
+ np = of_node_get(node->parent);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ * of_get_next_child - Iterate a node childs
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ read_lock(&devtree_lock);
+ next = prev ? prev->sibling : node->child;
+ for (; next; next = next->sibling)
+ if (of_node_get(next))
+ break;
+ of_node_put(prev);
+ read_unlock(&devtree_lock);
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ * of_find_node_by_path - Find a node matching a full OF path
+ * @path: The full path to match
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np = allnodes;
+
+ read_lock(&devtree_lock);
+ for (; np; np = np->allnext) {
+ if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+ && of_node_get(np))
+ break;
+ }
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ * of_find_node_by_name - Find a node by its "name" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @name: The name string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext)
+ if (np->name && (of_node_cmp(np->name, name) == 0)
+ && of_node_get(np))
+ break;
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ * of_find_node_by_type - Find a node by its "device_type" property
+ * @from: The node to start searching from, or NULL to start searching
+ * the entire device tree. The node you pass will not be
+ * searched, only the next one will; typically, you pass
+ * what the previous call returned. of_node_put() will be
+ * called on from for you.
+ * @type: The type string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext)
+ if (np->type && (of_node_cmp(np->type, type) == 0)
+ && of_node_get(np))
+ break;
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ * of_find_compatible_node - Find a node based on type and one of the
+ * tokens in its "compatible" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @type: The type string to match "device_type" or NULL to ignore
+ * @compatible: The string to match to one of the tokens in the device
+ * "compatible" list.
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext) {
+ if (type
+ && !(np->type && (of_node_cmp(np->type, type) == 0)))
+ continue;
+ if (of_device_is_compatible(np, compatible) && of_node_get(np))
+ break;
+ }
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644
index 000000000000..6245f060fb77
--- /dev/null
+++ b/drivers/of/device.c
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= node->name
+ && !strcmp(matches->name, node->name);
+ if (matches->type[0])
+ match &= node->type
+ && !strcmp(matches->type, node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
+{
+ if (!dev->node)
+ return NULL;
+ return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->dev);
+ if (tmp)
+ return to_of_device(tmp);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ of_node_put(ofdev->node);
+ kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+ int rc;
+
+ BUG_ON(ofdev->node == NULL);
+
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+
+ rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+ if (rc)
+ device_unregister(&ofdev->dev);
+
+ return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+ device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644
index 000000000000..864f09fd9f86
--- /dev/null
+++ b/drivers/of/platform.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ * and Arnd Bergmann, IBM Corp.
+ * Merged from powerpc/kernel/of_platform.c and
+ * sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+ const struct of_device_id *matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+ bus->name = name;
+ bus->match = of_platform_bus_match;
+ bus->probe = of_platform_device_probe;
+ bus->remove = of_platform_device_remove;
+ bus->suspend = of_platform_device_suspend;
+ bus->resume = of_platform_device_resume;
+ return bus_register(bus);
+}
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index edd6de995726..8134c7e198a5 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -26,8 +26,9 @@
#include <linux/profile.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/oprofile.h>
#include <linux/sched.h>
-
+
#include "oprofile_stats.h"
#include "event_buffer.h"
#include "cpu_buffer.h"
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 9b6a4ebd03e3..5076ed1ebd8f 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -19,28 +19,10 @@ void free_event_buffer(void);
/* wake up the process sleeping on the event file */
void wake_up_buffer_waiter(void);
-
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE ~0UL
-#define CTX_SWITCH_CODE 1
-#define CPU_SWITCH_CODE 2
-#define COOKIE_SWITCH_CODE 3
-#define KERNEL_ENTER_SWITCH_CODE 4
-#define KERNEL_EXIT_SWITCH_CODE 5
-#define MODULE_LOADED_CODE 6
-#define CTX_TGID_CODE 7
-#define TRACE_BEGIN_CODE 8
-#define TRACE_END_CODE 9
-
+
#define INVALID_COOKIE ~0UL
#define NO_COOKIE 0UL
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
-
extern const struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index e5162a64018b..2c645170f06e 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -53,9 +53,24 @@ int oprofile_setup(void)
* us missing task deaths and eventually oopsing
* when trying to process the event buffer.
*/
+ if (oprofile_ops.sync_start) {
+ int sync_ret = oprofile_ops.sync_start();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ case -1:
+ goto out3;
+ default:
+ goto out3;
+ }
+ }
+do_generic:
if ((err = sync_start()))
goto out3;
+post_sync:
is_setup = 1;
mutex_unlock(&start_mutex);
return 0;
@@ -118,7 +133,20 @@ out:
void oprofile_shutdown(void)
{
mutex_lock(&start_mutex);
+ if (oprofile_ops.sync_stop) {
+ int sync_ret = oprofile_ops.sync_stop();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ default:
+ goto post_sync;
+ }
+ }
+do_generic:
sync_stop();
+post_sync:
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
is_setup = 0;
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index e5d7ed92d6f7..a6d6b2488ffc 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -359,7 +359,7 @@ static __inline__ int led_get_net_activity(void)
* for reading should be OK */
read_lock(&dev_base_lock);
rcu_read_lock();
- for_each_netdev(dev) {
+ for_each_netdev(&init_net, dev) {
struct net_device_stats *stats;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index a708c329675e..38cdf9fa36a7 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -73,6 +73,7 @@
#include <linux/termios.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/delay.h>
#include <asm/io.h>
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 09c93ff932b1..d449b150930e 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -35,7 +35,7 @@ if PARPORT
config PARPORT_PC
tristate "PC-style hardware"
- depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+ depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
---help---
You should say Y here if you have a PC-style parallel port. All
IBM PC compatible computers and some Alphas have PC-style
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 8b7d84eca05d..802a81d47367 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -105,9 +105,8 @@ static int parport_probe(struct pcmcia_device *link)
DEBUG(0, "parport_attach()\n");
/* Create new parport device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) return -ENOMEM;
- memset(info, 0, sizeof(*info));
link->priv = info;
info->p_dev = link;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 5d58ad55d85c..e2be84001105 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -3445,7 +3445,6 @@ static void __exit parport_pc_exit(void)
pnp_unregister_driver (&parport_pc_pnp_driver);
platform_driver_unregister(&parport_pc_platform_driver);
- spin_lock(&ports_lock);
while (!list_empty(&ports_list)) {
struct parport_pc_private *priv;
struct parport *port;
@@ -3455,11 +3454,8 @@ static void __exit parport_pc_exit(void)
if (port->dev && port->dev->bus == &platform_bus_type)
platform_device_unregister(
to_platform_device(port->dev));
- spin_unlock(&ports_lock);
parport_pc_unregister_port(port);
- spin_lock(&ports_lock);
}
- spin_unlock(&ports_lock);
}
MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 90ea3b8b99b0..bd6ad8b38168 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -324,10 +324,9 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
struct parport_serial_private *priv;
int err;
- priv = kmalloc (sizeof *priv, GFP_KERNEL);
+ priv = kzalloc (sizeof *priv, GFP_KERNEL);
if (!priv)
return -ENOMEM;
- memset(priv, 0, sizeof(struct parport_serial_private));
pci_set_drvdata (dev, priv);
err = pci_enable_device (dev);
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 1c97e7dd130b..2b5352a7dffc 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -3,12 +3,9 @@
#include <linux/module.h>
#include "pci.h"
-int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct pci_dev *pdev;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp,
if (!pdev)
return -ENODEV;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_CLASS=%04X", pdev->class))
+ if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
+ if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+ if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_SLOT_NAME=%s", pci_name(pdev)))
+ if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+ if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device,
(u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
(u8)(pdev->class)))
return -ENOMEM;
-
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 70db38c0ced9..56829f82be4a 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -267,7 +267,10 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
if (subevent == 0x80) {
dbg("%s: generationg bus event\n", __FUNCTION__);
- acpi_bus_generate_event(note->device, note->event, detail);
+ acpi_bus_generate_proc_event(note->device, note->event, detail);
+ acpi_bus_generate_netlink_event(note->device->pnp.device_class,
+ note->device->dev.bus_id,
+ note->event, detail);
} else
note->event = event;
}
@@ -399,7 +402,7 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
status = acpi_get_object_info(handle, &info_buffer);
if (ACPI_FAILURE(status)) {
- err("%s: Failed to get device information", __FUNCTION__);
+ err("%s: Failed to get device information\n", __FUNCTION__);
return 0;
}
info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index d590a99930fa..a96b739b2d35 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -45,7 +45,7 @@
#include "cpqphp.h"
#include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */
+#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */
/* Global variables */
@@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot)
* slot. */
bus->number = tbus;
pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0),
- PCI_REVISION_ID, &work);
+ PCI_CLASS_REVISION, &work);
if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
pci_bus_read_config_dword(bus,
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 79ff6b4de3a6..3ef0a4875a62 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -37,6 +37,7 @@
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
+#include <linux/kthread.h>
#include "cpqphp.h"
static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
@@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func
u8 behind_bridge, struct resource_lists *resources);
static void interrupt_event_handler(struct controller *ctrl);
-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
-static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending; /* = 0 */
-/* things needed for the long_delay function */
-static struct semaphore delay_sem;
-static wait_queue_head_t delay_wait;
+static struct task_struct *cpqhp_event_thread;
+static unsigned long pushbutton_pending; /* = 0 */
/* delay is in jiffies to wait for */
static void long_delay(int delay)
{
- DECLARE_WAITQUEUE(wait, current);
-
- /* only allow 1 customer into the delay queue at once
- * yes this makes some people wait even longer, but who really cares?
- * this is for _huge_ delays to make the hardware happy as the
- * signals bounce around
+ /*
+ * XXX(hch): if someone is bored please convert all callers
+ * to call msleep_interruptible directly. They really want
+ * to specify timeouts in natural units and spend a lot of
+ * effort converting them to jiffies..
*/
- down (&delay_sem);
-
- init_waitqueue_head(&delay_wait);
-
- add_wait_queue(&delay_wait, &wait);
msleep_interruptible(jiffies_to_msecs(delay));
- remove_wait_queue(&delay_wait, &wait);
-
- up(&delay_sem);
}
@@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
}
if (schedule_flag) {
- up(&event_semaphore);
- dbg("Signal event_semaphore\n");
+ wake_up_process(cpqhp_event_thread);
+ dbg("Waking even thread");
}
return IRQ_HANDLED;
}
@@ -973,16 +960,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber)
struct pci_func *new_slot;
struct pci_func *next;
- new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
-
+ new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
if (new_slot == NULL) {
/* I'm not dead yet!
* You will be. */
return new_slot;
}
- memset(new_slot, 0, sizeof(struct pci_func));
-
new_slot->next = NULL;
new_slot->configured = 1;
@@ -1738,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control
static void pushbutton_helper_thread(unsigned long data)
{
pushbutton_pending = data;
- up(&event_semaphore);
+ wake_up_process(cpqhp_event_thread);
}
@@ -1746,16 +1730,14 @@ static void pushbutton_helper_thread(unsigned long data)
static int event_thread(void* data)
{
struct controller *ctrl;
- lock_kernel();
- daemonize("phpd_event");
-
- unlock_kernel();
while (1) {
dbg("!!!!event_thread sleeping\n");
- down_interruptible (&event_semaphore);
- dbg("event_thread woken finished = %d\n", event_finished);
- if (event_finished) break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ if (kthread_should_stop())
+ break;
/* Do stuff here */
if (pushbutton_pending)
cpqhp_pushbutton_thread(pushbutton_pending);
@@ -1764,38 +1746,24 @@ static int event_thread(void* data)
interrupt_event_handler(ctrl);
}
dbg("event_thread signals exit\n");
- up(&event_exit);
return 0;
}
-
int cpqhp_event_start_thread(void)
{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX(&delay_sem);
- init_MUTEX_LOCKED(&event_semaphore);
- init_MUTEX_LOCKED(&event_exit);
- event_finished=0;
-
- pid = kernel_thread(event_thread, NULL, 0);
- if (pid < 0) {
+ cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event");
+ if (IS_ERR(cpqhp_event_thread)) {
err ("Can't start up our event thread\n");
- return -1;
+ return PTR_ERR(cpqhp_event_thread);
}
- dbg("Our event thread pid = %d\n", pid);
+
return 0;
}
void cpqhp_event_stop_thread(void)
{
- event_finished = 1;
- dbg("event_thread finish command given\n");
- up(&event_semaphore);
- dbg("wait for event_thread to exit\n");
- down(&event_exit);
+ kthread_stop(cpqhp_event_thread);
}
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index fc7c74d72595..3f6cd20e95d2 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -37,7 +37,7 @@
#include "../pci.h"
#include "cpqphp.h"
#include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */
+#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */
u8 cpqhp_nic_irq;
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 0316eeaaeb29..a90c28d0c69d 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -35,7 +35,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
#include "../pci.h"
-#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */
+#include "../../../arch/x86/pci/pci.h" /* for struct irq_routing_table */
#include "ibmphp.h"
#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON)
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index d06ccb69e411..c31e7bf34502 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -35,7 +35,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sched.h>
-
+#include <linux/kthread.h>
#include "ibmphp.h"
static int to_debug = 0;
@@ -101,12 +101,11 @@ static int to_debug = 0;
//----------------------------------------------------------------------------
// global variables
//----------------------------------------------------------------------------
-static int ibmphp_shutdown;
-static int tid_poll;
static struct mutex sem_hpcaccess; // lock access to HPC
static struct semaphore semOperations; // lock all operations and
// access to data structures
static struct semaphore sem_exit; // make sure polling thread goes away
+static struct task_struct *ibmphp_poll_thread;
//----------------------------------------------------------------------------
// local function prototypes
//----------------------------------------------------------------------------
@@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8);
static u8 hpc_readcmdtoindex (u8, u8);
static void get_hpc_access (void);
static void free_hpc_access (void);
-static void poll_hpc (void);
+static int poll_hpc(void *data);
static int process_changeinstatus (struct slot *, struct slot *);
static int process_changeinlatch (u8, u8, struct controller *);
-static int hpc_poll_thread (void *);
static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *);
//----------------------------------------------------------------------------
@@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void)
init_MUTEX (&semOperations);
init_MUTEX_LOCKED (&sem_exit);
to_debug = 0;
- ibmphp_shutdown = 0;
- tid_poll = 0;
debug ("%s - Exit\n", __FUNCTION__);
}
@@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void)
#define POLL_LATCH_REGISTER 0
#define POLL_SLOTS 1
#define POLL_SLEEP 2
-static void poll_hpc (void)
+static int poll_hpc(void *data)
{
struct slot myslot;
struct slot *pslot = NULL;
@@ -833,10 +829,7 @@ static void poll_hpc (void)
debug ("%s - Entry\n", __FUNCTION__);
- while (!ibmphp_shutdown) {
- if (ibmphp_shutdown)
- break;
-
+ while (!kthread_should_stop()) {
/* try to get the lock to do some kind of hardware access */
down (&semOperations);
@@ -896,7 +889,7 @@ static void poll_hpc (void)
up (&semOperations);
msleep(POLL_INTERVAL_SEC * 1000);
- if (ibmphp_shutdown)
+ if (kthread_should_stop())
break;
down (&semOperations);
@@ -915,6 +908,7 @@ static void poll_hpc (void)
}
up (&sem_exit);
debug ("%s - Exit\n", __FUNCTION__);
+ return 0;
}
@@ -1050,47 +1044,20 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
}
/*----------------------------------------------------------------------
-* Name: hpc_poll_thread
-*
-* Action: polling
-*
-* Return 0
-* Value:
-*---------------------------------------------------------------------*/
-static int hpc_poll_thread (void *data)
-{
- debug ("%s - Entry\n", __FUNCTION__);
-
- daemonize("hpc_poll");
- allow_signal(SIGKILL);
-
- poll_hpc ();
-
- tid_poll = 0;
- debug ("%s - Exit\n", __FUNCTION__);
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
* Name: ibmphp_hpc_start_poll_thread
*
* Action: start polling thread
*---------------------------------------------------------------------*/
int __init ibmphp_hpc_start_poll_thread (void)
{
- int rc = 0;
-
debug ("%s - Entry\n", __FUNCTION__);
- tid_poll = kernel_thread (hpc_poll_thread, NULL, 0);
- if (tid_poll < 0) {
+ ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll");
+ if (IS_ERR(ibmphp_poll_thread)) {
err ("%s - Error, thread not started\n", __FUNCTION__);
- rc = -1;
+ return PTR_ERR(ibmphp_poll_thread);
}
-
- debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
- return rc;
+ return 0;
}
/*----------------------------------------------------------------------
@@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void)
{
debug ("%s - Entry\n", __FUNCTION__);
- ibmphp_shutdown = 1;
+ kthread_stop(ibmphp_poll_thread);
debug ("before locking operations \n");
ibmphp_lock_operations ();
debug ("after locking operations \n");
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index bd433ef6bfc6..f0eba534f805 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -694,66 +694,6 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
if ((slot == NULL) || (info == NULL))
return -ENODEV;
- /*
- * check all fields in the info structure, and update timestamps
- * for the files referring to the fields that have now changed.
- */
- if ((has_power_file(slot) == 0) &&
- (slot->info->power_status != info->power_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_power.attr);
- if (retval)
- return retval;
- }
-
- if ((has_attention_file(slot) == 0) &&
- (slot->info->attention_status != info->attention_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_attention.attr);
- if (retval)
- return retval;
- }
-
- if ((has_latch_file(slot) == 0) &&
- (slot->info->latch_status != info->latch_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_latch.attr);
- if (retval)
- return retval;
- }
-
- if ((has_adapter_file(slot) == 0) &&
- (slot->info->adapter_status != info->adapter_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_presence.attr);
- if (retval)
- return retval;
- }
-
- if ((has_address_file(slot) == 0) &&
- (slot->info->address != info->address)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_address.attr);
- if (retval)
- return retval;
- }
-
- if ((has_max_bus_speed_file(slot) == 0) &&
- (slot->info->max_bus_speed != info->max_bus_speed)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_max_bus_speed.attr);
- if (retval)
- return retval;
- }
-
- if ((has_cur_bus_speed_file(slot) == 0) &&
- (slot->info->cur_bus_speed != info->cur_bus_speed)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_cur_bus_speed.attr);
- if (retval)
- return retval;
- }
-
memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
return 0;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index e5d3f0b4f45a..6462ac3b405f 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
hotplug_slot->info->attention_status = status;
-
- if (ATTN_LED(slot->ctrl->ctrlcap))
+
+ if (ATTN_LED(slot->ctrl->ctrlcap))
slot->hpc_ops->set_attention_status(slot, status);
return 0;
@@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
+
retval = slot->hpc_ops->get_max_bus_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
@@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
+
retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
@@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
struct slot *t_slot;
u8 value;
struct pci_dev *pdev;
-
+
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
err("%s : out of memory\n", __FUNCTION__);
@@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev)
#ifdef CONFIG_PM
static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
{
- printk("%s ENTRY\n", __FUNCTION__);
+ printk("%s ENTRY\n", __FUNCTION__);
return 0;
}
static int pciehp_resume (struct pcie_device *dev)
{
- printk("%s ENTRY\n", __FUNCTION__);
+ printk("%s ENTRY\n", __FUNCTION__);
return 0;
}
#endif
-static struct pcie_port_service_id port_pci_ids[] = { {
- .vendor = PCI_ANY_ID,
+static struct pcie_port_service_id port_pci_ids[] = { {
+ .vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.port_type = PCIE_ANY_PORT,
.service_type = PCIE_PORT_SERVICE_HP,
- .driver_data = 0,
+ .driver_data = 0,
}, { /* end: all zeroes */ }
};
static const char device_name[] = "hpdriver";
@@ -540,10 +540,6 @@ static int __init pcied_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
- pciehp_poll_mode = 1;
-#endif
-
retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 98e541ffef3d..c8cb49c5a752 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
@@ -181,7 +181,7 @@ 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 (pslot->hpc_ops->power_off_slot(pslot)) {
+ if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n",
__FUNCTION__);
return;
@@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
}
if (PWR_LED(ctrl->ctrlcap))
- pslot->hpc_ops->green_led_off(pslot);
+ pslot->hpc_ops->green_led_off(pslot);
if (ATTN_LED(ctrl->ctrlcap)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
@@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot)
if (retval)
return retval;
}
-
+
if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
@@ -548,7 +548,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->ctrlcap)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot)
return -ENODEV;
}
}
-
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%s)\n", __FUNCTION__,
@@ -593,7 +593,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->ctrlcap)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
@@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%s)\n", __FUNCTION__,
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 016eea94a8a5..06d025b8b13f 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -39,37 +39,6 @@
#include "../pci.h"
#include "pciehp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
@@ -160,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
/* Link Width Encoding */
#define LNK_X1 0x01
#define LNK_X2 0x02
-#define LNK_X4 0x04
+#define LNK_X4 0x04
#define LNK_X8 0x08
#define LNK_X12 0x0C
-#define LNK_X16 0x10
+#define LNK_X16 0x10
#define LNK_X32 0x20
/*Field definitions of Link Status Register */
@@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#define EMI_STATE 0x0080
#define EMI_STATUS_BIT 7
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-
static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec);
@@ -231,14 +198,12 @@ static void int_poll_timeout(unsigned long data)
{
struct controller *ctrl = (struct controller *)data;
- DBG_ENTER_ROUTINE
-
/* Poll for interrupt events. regs == NULL => polling */
pcie_isr(0, ctrl);
init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
- pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+ pciehp_poll_time = 2; /* default polling interval is 2 sec */
start_int_poll_timer(ctrl, pciehp_poll_time);
}
@@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
u16 slot_ctrl;
unsigned long flags;
- DBG_ENTER_ROUTINE
-
mutex_lock(&ctrl->ctrl_lock);
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
@@ -299,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
goto out;
}
- if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
+ if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
/* After 1 sec and CMD_COMPLETED still not set, just
proceed forward to issue the next command according
to spec. Just print out the error message */
@@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
retval = pcie_wait_cmd(ctrl);
out:
mutex_unlock(&ctrl->ctrl_lock);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl)
u16 lnk_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -350,26 +310,22 @@ static int hpc_check_lnk_status(struct controller *ctrl)
}
dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
- if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
+ if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
!(lnk_status & NEG_LINK_WD)) {
err("%s : Link Training Error occurs \n", __FUNCTION__);
retval = -1;
return retval;
}
- DBG_LEAVE_ROUTINE
return retval;
}
-
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
-
- DBG_ENTER_ROUTINE
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
@@ -400,7 +356,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -410,8 +365,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
-
- DBG_ENTER_ROUTINE
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
@@ -428,35 +381,30 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
*status = 1;
break;
case 1:
- *status = 0;
+ *status = 0;
break;
default:
*status = 0xFF;
break;
}
- DBG_LEAVE_ROUTINE
return retval;
}
-
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
- *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
+ *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -467,8 +415,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
u8 card_state;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
@@ -477,7 +423,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
*status = (card_state == 1) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -488,16 +433,13 @@ static int hpc_query_power_fault(struct slot *slot)
u8 pwr_fault;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-
- DBG_LEAVE_ROUTINE
+
return pwr_fault;
}
@@ -507,8 +449,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s : Cannot check EMI status\n", __FUNCTION__);
@@ -516,7 +456,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
}
*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -526,8 +465,6 @@ static int hpc_toggle_emi(struct slot *slot)
u16 cmd_mask;
int rc;
- DBG_ENTER_ROUTINE
-
slot_cmd = EMI_CTRL;
cmd_mask = EMI_CTRL;
if (!pciehp_poll_mode) {
@@ -537,7 +474,7 @@ static int hpc_toggle_emi(struct slot *slot)
rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
- DBG_LEAVE_ROUTINE
+
return rc;
}
@@ -548,8 +485,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u16 cmd_mask;
int rc;
- DBG_ENTER_ROUTINE
-
cmd_mask = ATTN_LED_CTRL;
switch (value) {
case 0 : /* turn off */
@@ -572,19 +507,15 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- DBG_LEAVE_ROUTINE
+
return rc;
}
-
static void hpc_set_green_led_on(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
-
- DBG_ENTER_ROUTINE
slot_cmd = 0x0100;
cmd_mask = PWR_LED_CTRL;
@@ -597,8 +528,6 @@ static void hpc_set_green_led_on(struct slot *slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_set_green_led_off(struct slot *slot)
@@ -607,8 +536,6 @@ static void hpc_set_green_led_off(struct slot *slot)
u16 slot_cmd;
u16 cmd_mask;
- DBG_ENTER_ROUTINE
-
slot_cmd = 0x0300;
cmd_mask = PWR_LED_CTRL;
if (!pciehp_poll_mode) {
@@ -619,9 +546,6 @@ static void hpc_set_green_led_off(struct slot *slot)
pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_set_green_led_blink(struct slot *slot)
@@ -629,8 +553,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
-
- DBG_ENTER_ROUTINE
slot_cmd = 0x0200;
cmd_mask = PWR_LED_CTRL;
@@ -643,14 +565,10 @@ static void hpc_set_green_led_blink(struct slot *slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_release_ctlr(struct controller *ctrl)
{
- DBG_ENTER_ROUTINE
-
if (pciehp_poll_mode)
del_timer(&ctrl->poll_timer);
else
@@ -662,8 +580,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&pciehp_num_controllers))
destroy_workqueue(pciehp_wq);
-
- DBG_LEAVE_ROUTINE
}
static int hpc_power_on_slot(struct slot * slot)
@@ -674,8 +590,6 @@ static int hpc_power_on_slot(struct slot * slot)
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
/* Clear sticky power-fault bit from previous power failures */
@@ -719,8 +633,6 @@ static int hpc_power_on_slot(struct slot * slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
-
return retval;
}
@@ -731,8 +643,6 @@ static int hpc_power_off_slot(struct slot * slot)
u16 cmd_mask;
int retval = 0;
- DBG_ENTER_ROUTINE
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
slot_cmd = POWER_OFF;
@@ -764,8 +674,6 @@ static int hpc_power_off_slot(struct slot * slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
-
return retval;
}
@@ -784,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_NONE;
}
- intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
- PRSN_DETECT_CHANGED | CMD_COMPLETED );
+ intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+ MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
intr_loc = slot_status & intr_detect;
@@ -807,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
__FUNCTION__, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ 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",
@@ -825,7 +734,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
}
dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
__FUNCTION__, slot_status);
-
+
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -835,10 +744,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_NONE;
}
}
-
+
if (intr_loc & CMD_COMPLETED) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
*/
ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
@@ -892,7 +801,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
__FUNCTION__);
return IRQ_NONE;
}
-
+
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -904,19 +813,17 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
__FUNCTION__, temp_word);
}
-
+
return IRQ_HANDLED;
}
-static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -934,19 +841,18 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
*value = lnk_speed;
dbg("Max link speed = %d\n", lnk_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_max_lnk_width(struct slot *slot,
+ enum pcie_link_width *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -985,19 +891,17 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
*value = lnk_wdth;
dbg("Max link width = %d\n", lnk_wdth);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -1015,25 +919,24 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
*value = lnk_speed;
dbg("Current link speed = %d\n", lnk_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_cur_lnk_width(struct slot *slot,
+ enum pcie_link_width *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
-
+
switch ((lnk_status & 0x03F0) >> 4){
case 0:
lnk_wdth = PCIE_LNK_WIDTH_RESRV;
@@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value
*value = lnk_wdth;
dbg("Current link width = %d\n", lnk_wdth);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -1085,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
.get_max_lnk_width = hpc_get_max_lnk_width,
.get_cur_lnk_width = hpc_get_cur_lnk_width,
-
+
.query_power_fault = hpc_query_power_fault,
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
.check_lnk_status = hpc_check_lnk_status,
};
@@ -1138,6 +1041,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
dbg("Trying to get hotplug control for %s \n",
(char *)string.pointer);
status = pci_osc_control_set(handle,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL |
OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
if (status == AE_NOT_FOUND)
status = acpi_run_oshp(handle);
@@ -1163,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
}
#endif
-
-
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
int rc;
@@ -1176,8 +1078,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
- DBG_ENTER_ROUTINE
-
pdev = dev->port;
ctrl->pci_dev = pdev; /* save pci_dev in context */
@@ -1201,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: CAPREG offset %x cap_reg %x\n",
__FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
- if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+ 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", __FUNCTION__);
+ dbg("%s : This is not a root port or the port is not "
+ "connected to a slot\n", __FUNCTION__);
goto abort_free_ctlr;
}
@@ -1236,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
- for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+ 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);
+ 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);
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
@@ -1267,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL %x value read %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+ 0x00;
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
@@ -1330,14 +1234,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
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;
- temp_word = (temp_word & ~intr_enable) | intr_enable;
+ temp_word = (temp_word & ~intr_enable) | intr_enable;
if (pciehp_poll_mode) {
temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
@@ -1345,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
}
- /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+ /*
+ * 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", __FUNCTION__);
@@ -1356,14 +1263,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
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", __FUNCTION__);
goto abort_disable_intr;
}
-
+
if (pciehp_force) {
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(ctrl->pci_dev));
@@ -1375,10 +1282,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->hpc_ops = &pciehp_hpc_ops;
- DBG_LEAVE_ROUTINE
return 0;
- /* We end up here for the many possible ways to fail this API. */
+ /* 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) {
@@ -1395,6 +1301,5 @@ abort_free_irq:
free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 854aaea09e4d..c424aded13fb 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot)
int pciehp_unconfigure_device(struct slot *p_slot)
{
- int rc = 0;
+ int ret, rc = 0;
int j;
u8 bctl = 0;
+ u8 presence = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
@@ -263,23 +264,28 @@ int pciehp_unconfigure_device(struct slot *p_slot)
continue;
}
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
- if (bctl & PCI_BRIDGE_CTL_VGA) {
- err("Cannot remove display device %s\n",
+ ret = p_slot->hpc_ops->get_adapter_status(p_slot,
+ &presence);
+ if (!ret && presence) {
+ pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
+ &bctl);
+ if (bctl & PCI_BRIDGE_CTL_VGA) {
+ err("Cannot remove display device %s\n",
pci_name(temp));
- pci_dev_put(temp);
- continue;
+ pci_dev_put(temp);
+ continue;
+ }
}
}
pci_remove_bus_device(temp);
pci_dev_put(temp);
}
- /*
+ /*
* Some PCI Express root ports require fixup after hot-plug operation.
*/
- if (pcie_mch_quirk)
+ if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
-
+
return rc;
}
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index df076064a3e0..a080fedf0332 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = {
};
struct kset dlpar_io_kset = {
- .kobj = {.name = DLPAR_KOBJ_NAME,
- .ktype = &ktype_dlpar_io,
+ .kobj = {.ktype = &ktype_dlpar_io,
.parent = &pci_hotplug_slots_subsys.kobj},
.ktype = &ktype_dlpar_io,
};
int dlpar_sysfs_init(void)
{
+ kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
if (kset_register(&dlpar_io_kset)) {
printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
- dlpar_io_kset.kobj.name);
+ kobject_name(&dlpar_io_kset.kobj));
return -EINVAL;
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index be1df85e5e2d..87e01615053d 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
} else {
msg->address_hi = 0;
- pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
}
msg->data = data;
break;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c8062494009f..5c6a5d043007 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -220,6 +220,7 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
}
EXPORT_SYMBOL(pci_osc_control_set);
+#ifdef CONFIG_ACPI_SLEEP
/*
* _SxD returns the D-state with the highest power
* (lowest D-state number) supported in the S-state "x".
@@ -245,16 +246,34 @@ EXPORT_SYMBOL(pci_osc_control_set);
* currently we simply return _SxD, if present.
*/
-static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state)
+static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
+ pm_message_t state)
{
- /* TBD */
-
- return -ENODEV;
+ int acpi_state;
+
+ acpi_state = acpi_pm_device_sleep_state(&pdev->dev,
+ device_may_wakeup(&pdev->dev), NULL);
+ if (acpi_state < 0)
+ return PCI_POWER_ERROR;
+
+ switch (acpi_state) {
+ case ACPI_STATE_D0:
+ return PCI_D0;
+ case ACPI_STATE_D1:
+ return PCI_D1;
+ case ACPI_STATE_D2:
+ return PCI_D2;
+ case ACPI_STATE_D3:
+ return PCI_D3hot;
+ }
+ return PCI_POWER_ERROR;
}
+#endif
static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ acpi_handle tmp;
static int state_conv[] = {
[0] = 0,
[1] = 1,
@@ -266,6 +285,9 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (!handle)
return -ENODEV;
+ /* If the ACPI device has _EJ0, ignore the device */
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+ return 0;
return acpi_bus_set_power(handle, acpi_state);
}
@@ -320,7 +342,9 @@ static int __init acpi_pci_init(void)
ret = register_acpi_bus_type(&acpi_pci_bus);
if (ret)
return 0;
+#ifdef CONFIG_ACPI_SLEEP
platform_pci_choose_state = acpi_pci_choose_state;
+#endif
platform_pci_set_power_state = acpi_pci_set_power_state;
return 0;
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8e58ea3d95c0..6e2760b6c20a 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
if (!dynid)
return -ENOMEM;
- INIT_LIST_HEAD(&dynid->node);
dynid->id.vendor = vendor;
dynid->id.device = device;
dynid->id.subvendor = subvendor;
@@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
driver_data : 0UL;
spin_lock(&pdrv->dynids.lock);
- list_add_tail(&pdrv->dynids.list, &dynid->node);
+ list_add_tail(&dynid->node, &pdrv->dynids.list);
spin_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->driver)) {
@@ -310,7 +309,7 @@ static int pci_default_resume(struct pci_dev *pci_dev)
/* restore the PCI config space */
pci_restore_state(pci_dev);
/* if the device was enabled before suspend, reenable */
- retval = __pci_reenable_device(pci_dev);
+ retval = pci_reenable_device(pci_dev);
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
@@ -532,8 +531,7 @@ void pci_dev_put(struct pci_dev *dev)
}
#ifndef CONFIG_HOTPLUG
-int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 03fd59e80fef..728b3c863d87 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -17,11 +17,16 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/log2.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
unsigned int pci_pm_d3_delay = 10;
+#ifdef CONFIG_PCI_DOMAINS
+int pci_domains_supported = 1;
+#endif
+
#define DEFAULT_CARDBUS_IO_SIZE (256)
#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
@@ -499,7 +504,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
return 0;
}
-int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
/**
* pci_choose_state - Choose the power state of a PCI device
@@ -513,15 +518,15 @@ int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
{
- int ret;
+ pci_power_t ret;
if (!pci_find_capability(dev, PCI_CAP_ID_PM))
return PCI_D0;
if (platform_pci_choose_state) {
ret = platform_pci_choose_state(dev, state);
- if (ret >= 0)
- state.event = ret;
+ if (ret != PCI_POWER_ERROR)
+ return ret;
}
switch (state.event) {
@@ -695,14 +700,13 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
}
/**
- * __pci_reenable_device - Resume abandoned device
+ * pci_reenable_device - Resume abandoned device
* @dev: PCI device to be resumed
*
* Note this function is a backend of pci_default_resume and is not supposed
* to be called by normal code, write proper resume handler and use it instead.
*/
-int
-__pci_reenable_device(struct pci_dev *dev)
+int pci_reenable_device(struct pci_dev *dev)
{
if (atomic_read(&dev->enable_cnt))
return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
@@ -1455,7 +1459,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
int cap, err = -EINVAL;
u32 stat, cmd, v, o;
- if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
+ if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))
goto out;
v = ffs(mmrbc) - 10;
@@ -1517,7 +1521,7 @@ EXPORT_SYMBOL(pcie_get_readrq);
/**
* pcie_set_readrq - set PCI Express maximum memory read request
* @dev: PCI device to query
- * @count: maximum memory read count in bytes
+ * @rq: maximum memory read count in bytes
* valid values are 128, 256, 512, 1024, 2048, 4096
*
* If possible sets maximum read byte count
@@ -1527,7 +1531,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
int cap, err = -EINVAL;
u16 ctl, v;
- if (rq < 128 || rq > 4096 || (rq & (rq-1)))
+ if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
goto out;
v = (ffs(rq) - 8) << 12;
@@ -1567,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
return bars;
}
+static void __devinit pci_no_domains(void)
+{
+#ifdef CONFIG_PCI_DOMAINS
+ pci_domains_supported = 0;
+#endif
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1586,6 +1597,10 @@ static int __devinit pci_setup(char *str)
if (*str && (str = pcibios_setup(str)) && *str) {
if (!strcmp(str, "nomsi")) {
pci_no_msi();
+ } else if (!strcmp(str, "noaer")) {
+ pci_no_aer();
+ } else if (!strcmp(str, "nodomains")) {
+ pci_no_domains();
} else if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "cbmemsize=", 10)) {
@@ -1604,6 +1619,7 @@ early_param("pci", pci_setup);
device_initcall(pci_init);
EXPORT_SYMBOL_GPL(pci_restore_bars);
+EXPORT_SYMBOL(pci_reenable_device);
EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pcim_enable_device);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 3fec13d3add7..6fda33de84e8 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,19 +1,12 @@
/* Functions internal to the PCI core code */
-extern int __must_check __pci_reenable_device(struct pci_dev *);
-extern int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
-extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
- resource_size_t size, resource_size_t align,
- resource_size_t min, unsigned int type_mask,
- void (*alignf)(void *, struct resource *,
- resource_size_t, resource_size_t),
- void *alignf_data);
+
/* Firmware callbacks */
-extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
@@ -36,7 +29,6 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
/* Functions for PCI Hotplug drivers to use */
extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
-extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
extern void pci_remove_legacy_files(struct pci_bus *bus);
@@ -59,6 +51,12 @@ void pci_restore_msi_state(struct pci_dev *dev);
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
#endif
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+#else
+static inline void pci_no_aer(void) { }
+#endif
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 0ad92a8ad8b1..287a9311716c 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE
When in doubt, say N.
-config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_PCIE
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 6846fb42b399..7a62f7dd9009 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = {
.reset_link = aer_root_reset,
};
+static int pcie_aer_disable;
+
+void pci_no_aer(void)
+{
+ pcie_aer_disable = 1; /* has priority over 'forceload' */
+}
+
/**
* aer_irq - Root Port's ISR
* @irq: IRQ assigned to Root Port
@@ -148,11 +155,10 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
{
struct aer_rpc *rpc;
- if (!(rpc = kmalloc(sizeof(struct aer_rpc),
+ if (!(rpc = kzalloc(sizeof(struct aer_rpc),
GFP_KERNEL)))
return NULL;
- memset(rpc, 0, sizeof(struct aer_rpc));
/*
* Initialize Root lock access, e_lock, to Root Error Status Reg,
* Root Error ID Reg, and Root error producer/consumer index.
@@ -328,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev)
**/
static int __init aer_service_init(void)
{
+ if (pcie_aer_disable)
+ return -ENXIO;
return pcie_port_service_register(&aerdriver);
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 34b8dae0d90f..5db6b6690b59 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
if (sz) {
res->flags = (l & IORESOURCE_ROM_ENABLE) |
- IORESOURCE_MEM | IORESOURCE_PREFETCH |
- IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+ IORESOURCE_MEM | IORESOURCE_READONLY;
res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (unsigned long) sz;
}
@@ -285,7 +284,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
}
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
+void pci_read_bridge_bases(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
@@ -597,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
if (!is_cardbus) {
- child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA;
+ child->bridge_ctl = bctl;
/*
* Adjust subordinate busnr in parent buses.
* We do this before scanning for children because
@@ -653,20 +652,20 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+ /* Has only triggered on CardBus, fixup is in yenta_socket */
while (bus->parent) {
if ((child->subordinate > bus->subordinate) ||
(child->number > bus->subordinate) ||
(child->number < bus->number) ||
(child->subordinate < bus->number)) {
- printk(KERN_WARNING "PCI: Bus #%02x (-#%02x) is "
- "hidden behind%s bridge #%02x (-#%02x)%s\n",
- child->number, child->subordinate,
- bus->self->transparent ? " transparent" : " ",
- bus->number, bus->subordinate,
- pcibios_assign_all_busses() ? " " :
- " (try 'pci=assign-busses')");
- printk(KERN_WARNING "Please report the result to "
- "<bk@suse.de> to fix this permanently\n");
+ pr_debug("PCI: Bus #%02x (-#%02x) is %s"
+ "hidden behind%s bridge #%02x (-#%02x)\n",
+ child->number, child->subordinate,
+ (bus->number > child->subordinate &&
+ bus->subordinate < child->number) ?
+ "wholly " : " partially",
+ bus->self->transparent ? " transparent" : " ",
+ bus->number, bus->subordinate);
}
bus = bus->parent;
}
@@ -744,22 +743,46 @@ static int pci_setup_device(struct pci_dev * dev)
*/
if (class == PCI_CLASS_STORAGE_IDE) {
u8 progif;
+ struct pci_bus_region region;
+
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 0) {
- dev->resource[0].start = 0x1F0;
- dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = LEGACY_IO_RESOURCE;
- dev->resource[1].start = 0x3F6;
- dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = LEGACY_IO_RESOURCE;
+ struct resource resource = {
+ .start = 0x1F0,
+ .end = 0x1F7,
+ .flags = LEGACY_IO_RESOURCE,
+ };
+
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[0].start = region.start;
+ dev->resource[0].end = region.end;
+ dev->resource[0].flags = resource.flags;
+ resource.start = 0x3F6;
+ resource.end = 0x3F6;
+ resource.flags = LEGACY_IO_RESOURCE;
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[1].start = region.start;
+ dev->resource[1].end = region.end;
+ dev->resource[1].flags = resource.flags;
}
if ((progif & 4) == 0) {
- dev->resource[2].start = 0x170;
- dev->resource[2].end = 0x177;
- dev->resource[2].flags = LEGACY_IO_RESOURCE;
- dev->resource[3].start = 0x376;
- dev->resource[3].end = 0x376;
- dev->resource[3].flags = LEGACY_IO_RESOURCE;
+ struct resource resource = {
+ .start = 0x170,
+ .end = 0x177,
+ .flags = LEGACY_IO_RESOURCE,
+ };
+
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[2].start = region.start;
+ dev->resource[2].end = region.end;
+ dev->resource[2].flags = resource.flags;
+ resource.start = 0x376;
+ resource.end = 0x376;
+ resource.flags = LEGACY_IO_RESOURCE;
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[3].start = region.start;
+ dev->resource[3].end = region.end;
+ dev->resource[3].flags = resource.flags;
}
}
break;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 90adc62d07ff..716439e25dd2 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
*/
if (capable(CAP_SYS_ADMIN))
- size = dev->cfg_size;
+ size = dp->size;
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
size = 128;
else
@@ -129,11 +129,11 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_path.dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
- int size = dev->cfg_size;
+ int size = dp->size;
int cnt;
if (pos >= size)
@@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
}
*ppos = pos;
+ i_size_write(ino, dp->size);
return nbytes;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c559085c89a5..59d4da2734c1 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_
*/
static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
{
- u8 rev;
u32 region;
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
- if (rev & 0x10) {
+ if (dev->revision & 0x10) {
pci_read_config_dword(dev, 0x48, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
@@ -629,12 +627,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk
*/
static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
{
- unsigned char revid;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
- if (dev->subordinate && revid <= 0x12) {
+ if (dev->subordinate && dev->revision <= 0x12) {
printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
- "MMRBC\n", revid);
+ "MMRBC\n", dev->revision);
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
}
}
@@ -930,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge );
-/*
- * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled
- * when a PCI-Soundcard is added. The BIOS only gives Options
- * "Disabled" and "AUTO". This Quirk Sets the corresponding
- * Register-Value to enable the Soundcard.
- *
- * FIXME: Presently this quirk will run on anything that has an 8237
- * which isn't correct, we need to check DMI tables or something in
- * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it
- * runs everywhere at present we suppress the printk output in most
- * irrelevant cases.
- */
-static void k8t_sound_hostbridge(struct pci_dev *dev)
-{
- unsigned char val;
-
- pci_read_config_byte(dev, 0x50, &val);
- if (val == 0x88 || val == 0xc8) {
- /* Assume it's probably a MSI-K8T-Neo2Fir */
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n");
- pci_write_config_byte(dev, 0x50, val & (~0x40));
-
- /* Verify the Change for Status output */
- pci_read_config_byte(dev, 0x50, &val);
- if (val & 0x40)
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n");
- else
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n");
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
@@ -972,8 +935,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho
*
* The SMBus PCI Device can be activated by setting a bit in the ICH LPC
* bridge. Unfortunately, this device has no subvendor/subdevice ID. So it
- * becomes necessary to do this tweak in two steps -- I've chosen the Host
- * bridge as trigger.
+ * becomes necessary to do this tweak in two steps -- the chosen trigger
+ * is either the Host bridge (preferred) or on-board VGA controller.
*
* Note that we used to unhide the SMBus that way on Toshiba laptops
* (Satellite A40 and Tecra M2) but then found that the thermal management
@@ -1070,6 +1033,14 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x0058: /* Compaq Evo N620c */
asus_hides_smbus = 1;
}
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82810_IG3)
+ switch(dev->subsystem_device) {
+ case 0xB16C: /* Compaq Deskpro EP 401963-001 (PCA# 010174) */
+ /* Motherboard doesn't have Host bridge
+ * subvendor/subdevice IDs, therefore checking
+ * its on-board VGA controller */
+ asus_hides_smbus = 1;
+ }
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge );
@@ -1082,6 +1053,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, as
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge );
+
static void asus_hides_smbus_lpc(struct pci_dev *dev)
{
u16 val;
@@ -1099,12 +1072,14 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev)
printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
}
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
@@ -1432,7 +1407,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
{
u16 command;
- u32 bar;
u8 __iomem *csr;
u8 cmd_hi;
@@ -1464,12 +1438,12 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
* re-enable them when it's ready.
*/
pci_read_config_word(dev, PCI_COMMAND, &command);
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar);
- if (!(command & PCI_COMMAND_MEMORY) || !bar)
+ if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0))
return;
- csr = ioremap(bar, 8);
+ /* Convert from PCI bus to resource space. */
+ csr = ioremap(pci_resource_start(dev, 0), 8);
if (!csr) {
printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
pci_name(dev));
@@ -1485,7 +1459,7 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
iounmap(csr);
}
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
{
@@ -1650,6 +1624,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCN
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000_PCIX, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RD580, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RX790, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS690, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5e5191ec8de6..401e03c920bd 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus)
break;
case PCI_CLASS_BRIDGE_PCI:
+ /* don't size subtractive decoding (transparent)
+ * PCI-to-PCI bridges */
+ if (bus->self->transparent)
+ break;
pci_bridge_check_ranges(bus);
+ /* fall through */
default:
pbus_size_io(bus);
/* If the bridge supports prefetchable range, size it
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 568f1877315c..05ca2ed9eb51 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev,
dev->irq = irq;
pr_debug("PCI: fixup irq: (%s) got %d\n",
- dev->dev.kobj.name, dev->irq);
+ kobject_name(&dev->dev.kobj), dev->irq);
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 7c93a108f9b8..a0aca46ce877 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -409,6 +409,9 @@ static void socket_shutdown(struct pcmcia_socket *s)
#endif
s->functions = 0;
+ /* give socket some time to power down */
+ msleep(100);
+
s->ops->get_status(s, &status);
if (status & SS_POWERON) {
printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
@@ -904,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+ struct kobj_uevent_env *env)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
- int i = 0, length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "SOCKET_NO=%u", s->sock))
+ if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 143c6efc478a..55baa1f0fcbb 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
#ifdef CONFIG_HOTPLUG
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct pcmcia_device *p_dev;
- int i, length = 0;
+ int i;
u32 hash[4] = { 0, 0, 0, 0};
if (!dev)
@@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
}
- i = 0;
-
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "SOCKET_NO=%u",
- p_dev->socket->sock))
+ if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE_NO=%02X",
- p_dev->device_no))
+ if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+ if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
"pa%08Xpb%08Xpc%08Xpd%08X",
p_dev->has_manf_id ? p_dev->manf_id : 0,
p_dev->has_card_id ? p_dev->card_id : 0,
@@ -1112,21 +1101,46 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
hash[3]))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
#else
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
#endif
+/************************ runtime PM support ***************************/
+
+static int pcmcia_dev_suspend(struct device *dev, pm_message_t state);
+static int pcmcia_dev_resume(struct device *dev);
+
+static int runtime_suspend(struct device *dev)
+{
+ int rc;
+
+ down(&dev->sem);
+ rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
+ up(&dev->sem);
+ if (!rc)
+ dev->power.power_state.event = PM_EVENT_SUSPEND;
+ return rc;
+}
+
+static void runtime_resume(struct device *dev)
+{
+ int rc;
+
+ down(&dev->sem);
+ rc = pcmcia_dev_resume(dev);
+ up(&dev->sem);
+ if (!rc)
+ dev->power.power_state.event = PM_EVENT_ON;
+}
+
/************************ per-device sysfs output ***************************/
#define pcmcia_device_attr(field, test, format) \
@@ -1173,9 +1187,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
return -EINVAL;
if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
- ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
+ ret = runtime_suspend(dev);
else if (p_dev->suspended && !strncmp(buf, "on", 2))
- dpm_runtime_resume(dev);
+ runtime_resume(dev);
return ret ? ret : count;
}
@@ -1312,10 +1326,10 @@ static int pcmcia_bus_suspend_callback(struct device *dev, void * _data)
struct pcmcia_socket *skt = _data;
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->socket != skt)
+ if (p_dev->socket != skt || p_dev->suspended)
return 0;
- return dpm_runtime_suspend(dev, PMSG_SUSPEND);
+ return runtime_suspend(dev);
}
static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
@@ -1323,10 +1337,10 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
struct pcmcia_socket *skt = _data;
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->socket != skt)
+ if (p_dev->socket != skt || !p_dev->suspended)
return 0;
- dpm_runtime_resume(dev);
+ runtime_resume(dev);
return 0;
}
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 3c45142c40b2..b01985498460 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1316,7 +1316,7 @@ static struct of_device_id m8xx_pcmcia_match[] = {
MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
static struct of_platform_driver m8xx_pcmcia_driver = {
- .name = (char *)driver_name,
+ .name = driver_name,
.match_table = m8xx_pcmcia_match,
.probe = m8xx_probe,
.remove = m8xx_remove,
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 383107ba4bd3..f6722ba0dd1e 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void)
if (!mst_pcmcia_device)
return -ENOMEM;
- mst_pcmcia_device->dev.uevent_suppress = 0;
mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
ret = platform_device_add(mst_pcmcia_device);
@@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init);
module_exit(mst_pcmcia_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index a2daa3f531b2..d5c33bd78d68 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void)
if (!sharpsl_pcmcia_device)
return -ENOMEM;
- sharpsl_pcmcia_device->dev.uevent_suppress = 0;
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
@@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit);
MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index dd6384b1efce..6c0440c20e31 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -2,7 +2,6 @@
* card.c - contains functions for managing groups of PnP devices
*
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/module.h>
@@ -13,26 +12,31 @@
LIST_HEAD(pnp_cards);
static LIST_HEAD(pnp_card_drivers);
-
-static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
+static const struct pnp_card_device_id *match_card(struct pnp_card_driver *drv,
+ struct pnp_card *card)
{
- const struct pnp_card_device_id * drv_id = drv->id_table;
- while (*drv_id->id){
- if (compare_pnp_id(card->id,drv_id->id)) {
+ const struct pnp_card_device_id *drv_id = drv->id_table;
+
+ while (*drv_id->id) {
+ if (compare_pnp_id(card->id, drv_id->id)) {
int i = 0;
+
for (;;) {
int found;
struct pnp_dev *dev;
- if (i == PNP_MAX_DEVICES || ! *drv_id->devs[i].id)
+
+ if (i == PNP_MAX_DEVICES ||
+ !*drv_id->devs[i].id)
return drv_id;
found = 0;
card_for_each_dev(card, dev) {
- if (compare_pnp_id(dev->id, drv_id->devs[i].id)) {
+ if (compare_pnp_id(dev->id,
+ drv_id->devs[i].id)) {
found = 1;
break;
}
}
- if (! found)
+ if (!found)
break;
i++;
}
@@ -42,14 +46,15 @@ static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv
return NULL;
}
-static void card_remove(struct pnp_dev * dev)
+static void card_remove(struct pnp_dev *dev)
{
dev->card_link = NULL;
}
-static void card_remove_first(struct pnp_dev * dev)
+static void card_remove_first(struct pnp_dev *dev)
{
- struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
+ struct pnp_card_driver *drv = to_pnp_card_driver(dev->driver);
+
if (!dev->card || !drv)
return;
if (drv->remove)
@@ -67,7 +72,7 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
if (!drv->probe)
return 0;
- id = match_card(drv,card);
+ id = match_card(drv, card);
if (!id)
return 0;
@@ -94,12 +99,11 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
* pnp_add_card_id - adds an EISA id to the specified card
* @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)
+int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card)
{
- struct pnp_id * ptr;
+ struct pnp_id *ptr;
+
if (!id)
return -EINVAL;
if (!card)
@@ -115,10 +119,11 @@ int pnp_add_card_id(struct pnp_id *id, struct pnp_card * card)
return 0;
}
-static void pnp_free_card_ids(struct pnp_card * card)
+static void pnp_free_card_ids(struct pnp_card *card)
{
- struct pnp_id * id;
+ struct pnp_id *id;
struct pnp_id *next;
+
if (!card)
return;
id = card->id;
@@ -131,49 +136,55 @@ static void pnp_free_card_ids(struct pnp_card * card)
static void pnp_release_card(struct device *dmdev)
{
- struct pnp_card * card = to_pnp_card(dmdev);
+ struct pnp_card *card = to_pnp_card(dmdev);
+
pnp_free_card_ids(card);
kfree(card);
}
-
-static ssize_t pnp_show_card_name(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_card_name(struct device *dmdev,
+ struct device_attribute *attr, char *buf)
{
char *str = buf;
struct pnp_card *card = to_pnp_card(dmdev);
- str += sprintf(str,"%s\n", card->name);
+
+ str += sprintf(str, "%s\n", card->name);
return (str - buf);
}
-static DEVICE_ATTR(name,S_IRUGO,pnp_show_card_name,NULL);
+static DEVICE_ATTR(name, S_IRUGO, pnp_show_card_name, NULL);
-static ssize_t pnp_show_card_ids(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_card_ids(struct device *dmdev,
+ struct device_attribute *attr, char *buf)
{
char *str = buf;
struct pnp_card *card = to_pnp_card(dmdev);
- struct pnp_id * pos = card->id;
+ struct pnp_id *pos = card->id;
while (pos) {
- str += sprintf(str,"%s\n", pos->id);
+ str += sprintf(str, "%s\n", pos->id);
pos = pos->next;
}
return (str - buf);
}
-static DEVICE_ATTR(card_id,S_IRUGO,pnp_show_card_ids,NULL);
+static DEVICE_ATTR(card_id, S_IRUGO, pnp_show_card_ids, NULL);
static int pnp_interface_attach_card(struct pnp_card *card)
{
- int rc = device_create_file(&card->dev,&dev_attr_name);
- if (rc) return rc;
+ int rc = device_create_file(&card->dev, &dev_attr_name);
- rc = device_create_file(&card->dev,&dev_attr_card_id);
- if (rc) goto err_name;
+ if (rc)
+ return rc;
+
+ rc = device_create_file(&card->dev, &dev_attr_card_id);
+ if (rc)
+ goto err_name;
return 0;
err_name:
- device_remove_file(&card->dev,&dev_attr_name);
+ device_remove_file(&card->dev, &dev_attr_name);
return rc;
}
@@ -181,15 +192,16 @@ err_name:
* pnp_add_card - adds a PnP card to the PnP Layer
* @card: pointer to the card to add
*/
-
-int pnp_add_card(struct pnp_card * card)
+int pnp_add_card(struct pnp_card *card)
{
int error;
- struct list_head * pos, * temp;
+ struct list_head *pos, *temp;
+
if (!card || !card->protocol)
return -EINVAL;
- sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
+ 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;
@@ -205,18 +217,21 @@ int pnp_add_card(struct pnp_card * card)
/* we wait until now to add devices in order to ensure the drivers
* will be able to use all of the related devices on the card
* without waiting any unresonable length of time */
- list_for_each(pos,&card->devices){
+ list_for_each(pos, &card->devices) {
struct pnp_dev *dev = card_to_pnp_dev(pos);
__pnp_add_device(dev);
}
/* match with card drivers */
- list_for_each_safe(pos,temp,&pnp_card_drivers){
- struct pnp_card_driver * drv = list_entry(pos, struct pnp_card_driver, global_list);
- card_probe(card,drv);
+ list_for_each_safe(pos, temp, &pnp_card_drivers) {
+ struct pnp_card_driver *drv =
+ list_entry(pos, struct pnp_card_driver,
+ global_list);
+ card_probe(card, drv);
}
} else
- pnp_err("sysfs failure, card '%s' will be unavailable", card->dev.bus_id);
+ pnp_err("sysfs failure, card '%s' will be unavailable",
+ card->dev.bus_id);
return error;
}
@@ -224,10 +239,10 @@ int pnp_add_card(struct pnp_card * card)
* pnp_remove_card - removes a PnP card from the PnP Layer
* @card: pointer to the card to remove
*/
-
-void pnp_remove_card(struct pnp_card * card)
+void pnp_remove_card(struct pnp_card *card)
{
struct list_head *pos, *temp;
+
if (!card)
return;
device_unregister(&card->dev);
@@ -235,7 +250,7 @@ void pnp_remove_card(struct pnp_card * card)
list_del(&card->global_list);
list_del(&card->protocol_list);
spin_unlock(&pnp_lock);
- list_for_each_safe(pos,temp,&card->devices){
+ list_for_each_safe(pos, temp, &card->devices) {
struct pnp_dev *dev = card_to_pnp_dev(pos);
pnp_remove_card_device(dev);
}
@@ -246,15 +261,14 @@ void pnp_remove_card(struct pnp_card * card)
* @card: pointer to the card to add to
* @dev: pointer to the device to add
*/
-
-int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
+int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev)
{
if (!card || !dev || !dev->protocol)
return -EINVAL;
dev->dev.parent = &card->dev;
dev->card_link = NULL;
- snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x", dev->protocol->number,
- card->number,dev->number);
+ snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x",
+ dev->protocol->number, card->number, dev->number);
spin_lock(&pnp_lock);
dev->card = card;
list_add_tail(&dev->card_list, &card->devices);
@@ -266,8 +280,7 @@ int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
* pnp_remove_card_device- removes a device from the specified card
* @dev: pointer to the device to remove
*/
-
-void pnp_remove_card_device(struct pnp_dev * dev)
+void pnp_remove_card_device(struct pnp_dev *dev)
{
spin_lock(&pnp_lock);
dev->card = NULL;
@@ -282,13 +295,14 @@ void pnp_remove_card_device(struct pnp_dev * dev)
* @id: pointer to a PnP ID structure that explains the rules for finding the device
* @from: Starting place to search from. If NULL it will start from the begining.
*/
-
-struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char * id, struct pnp_dev * from)
+struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink,
+ const char *id, struct pnp_dev *from)
{
- struct list_head * pos;
- struct pnp_dev * dev;
- struct pnp_card_driver * drv;
- struct pnp_card * card;
+ struct list_head *pos;
+ struct pnp_dev *dev;
+ struct pnp_card_driver *drv;
+ struct pnp_card *card;
+
if (!clink || !id)
goto done;
card = clink->card;
@@ -302,7 +316,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char
}
while (pos != &card->devices) {
dev = card_to_pnp_dev(pos);
- if ((!dev->card_link) && compare_pnp_id(dev->id,id))
+ if ((!dev->card_link) && compare_pnp_id(dev->id, id))
goto found;
pos = pos->next;
}
@@ -330,10 +344,10 @@ err_out:
* pnp_release_card_device - call this when the driver no longer needs the device
* @dev: pointer to the PnP device stucture
*/
-
-void pnp_release_card_device(struct pnp_dev * dev)
+void pnp_release_card_device(struct pnp_dev *dev)
{
- struct pnp_card_driver * drv = dev->card_link->driver;
+ struct pnp_card_driver *drv = dev->card_link->driver;
+
if (!drv)
return;
drv->link.remove = &card_remove;
@@ -347,6 +361,7 @@ void pnp_release_card_device(struct pnp_dev * dev)
static int card_suspend(struct pnp_dev *dev, pm_message_t state)
{
struct pnp_card_link *link = dev->card_link;
+
if (link->pm_state.event == state.event)
return 0;
link->pm_state = state;
@@ -356,6 +371,7 @@ static int card_suspend(struct pnp_dev *dev, pm_message_t state)
static int card_resume(struct pnp_dev *dev)
{
struct pnp_card_link *link = dev->card_link;
+
if (link->pm_state.event == PM_EVENT_ON)
return 0;
link->pm_state = PMSG_ON;
@@ -367,8 +383,7 @@ static int card_resume(struct pnp_dev *dev)
* pnp_register_card_driver - registers a PnP card driver with the PnP Layer
* @drv: pointer to the driver to register
*/
-
-int pnp_register_card_driver(struct pnp_card_driver * drv)
+int pnp_register_card_driver(struct pnp_card_driver *drv)
{
int error;
struct list_head *pos, *temp;
@@ -389,9 +404,10 @@ int pnp_register_card_driver(struct pnp_card_driver * drv)
list_add_tail(&drv->global_list, &pnp_card_drivers);
spin_unlock(&pnp_lock);
- list_for_each_safe(pos,temp,&pnp_cards){
- struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
- card_probe(card,drv);
+ list_for_each_safe(pos, temp, &pnp_cards) {
+ struct pnp_card *card =
+ list_entry(pos, struct pnp_card, global_list);
+ card_probe(card, drv);
}
return 0;
}
@@ -400,8 +416,7 @@ int pnp_register_card_driver(struct pnp_card_driver * drv)
* pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
* @drv: pointer to the driver to unregister
*/
-
-void pnp_unregister_card_driver(struct pnp_card_driver * drv)
+void pnp_unregister_card_driver(struct pnp_card_driver *drv)
{
spin_lock(&pnp_lock);
list_del(&drv->global_list);
@@ -409,13 +424,6 @@ void pnp_unregister_card_driver(struct pnp_card_driver * drv)
pnp_unregister_driver(&drv->link);
}
-#if 0
-EXPORT_SYMBOL(pnp_add_card);
-EXPORT_SYMBOL(pnp_remove_card);
-EXPORT_SYMBOL(pnp_add_card_device);
-EXPORT_SYMBOL(pnp_remove_card_device);
-EXPORT_SYMBOL(pnp_add_card_id);
-#endif /* 0 */
EXPORT_SYMBOL(pnp_request_card_device);
EXPORT_SYMBOL(pnp_release_card_device);
EXPORT_SYMBOL(pnp_register_card_driver);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 3e20b1cc7778..d5964feb14de 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -2,7 +2,6 @@
* core.c - contains all core device and protocol registration functions
*
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/pnp.h>
@@ -18,7 +17,6 @@
#include "base.h"
-
static LIST_HEAD(pnp_protocols);
LIST_HEAD(pnp_global);
DEFINE_SPINLOCK(pnp_lock);
@@ -35,12 +33,11 @@ void *pnp_alloc(long size)
{
void *result;
- result = kmalloc(size, GFP_KERNEL);
- if (!result){
+ result = kzalloc(size, GFP_KERNEL);
+ if (!result) {
printk(KERN_ERR "pnp: Out of Memory\n");
return NULL;
}
- memset(result, 0, size);
return result;
}
@@ -50,14 +47,10 @@ void *pnp_alloc(long size)
*
* Ex protocols: ISAPNP, PNPBIOS, etc
*/
-
int pnp_register_protocol(struct pnp_protocol *protocol)
{
int nodenum;
- struct list_head * pos;
-
- if (!protocol)
- return -EINVAL;
+ struct list_head *pos;
INIT_LIST_HEAD(&protocol->devices);
INIT_LIST_HEAD(&protocol->cards);
@@ -65,9 +58,9 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
spin_lock(&pnp_lock);
/* assign the lowest unused number */
- list_for_each(pos,&pnp_protocols) {
- struct pnp_protocol * cur = to_pnp_protocol(pos);
- if (cur->number == nodenum){
+ list_for_each(pos, &pnp_protocols) {
+ struct pnp_protocol *cur = to_pnp_protocol(pos);
+ if (cur->number == nodenum) {
pos = &pnp_protocols;
nodenum++;
}
@@ -84,7 +77,6 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
/**
* pnp_protocol_unregister - removes a pnp protocol from the pnp layer
* @protocol: pointer to the corresponding pnp_protocol structure
- *
*/
void pnp_unregister_protocol(struct pnp_protocol *protocol)
{
@@ -94,13 +86,11 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol)
device_unregister(&protocol->dev);
}
-
static void pnp_free_ids(struct pnp_dev *dev)
{
- struct pnp_id * id;
- struct pnp_id * next;
- if (!dev)
- return;
+ struct pnp_id *id;
+ struct pnp_id *next;
+
id = dev->id;
while (id) {
next = id->next;
@@ -111,7 +101,8 @@ static void pnp_free_ids(struct pnp_dev *dev)
static void pnp_release_device(struct device *dmdev)
{
- struct pnp_dev * dev = to_pnp_dev(dmdev);
+ struct pnp_dev *dev = to_pnp_dev(dmdev);
+
pnp_free_option(dev->independent);
pnp_free_option(dev->dependent);
pnp_free_ids(dev);
@@ -121,6 +112,7 @@ static void pnp_release_device(struct device *dmdev)
int __pnp_add_device(struct pnp_dev *dev)
{
int ret;
+
pnp_fixup_device(dev);
dev->dev.bus = &pnp_bus_type;
dev->dev.dma_mask = &dev->dma_mask;
@@ -144,13 +136,13 @@ int __pnp_add_device(struct pnp_dev *dev)
*
* adds to driver model, name database, fixups, interface, etc.
*/
-
int pnp_add_device(struct pnp_dev *dev)
{
- if (!dev || !dev->protocol || dev->card)
+ if (dev->card)
return -EINVAL;
dev->dev.parent = &dev->protocol->dev;
- sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, dev->number);
+ sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
+ dev->number);
return __pnp_add_device(dev);
}
@@ -163,21 +155,6 @@ void __pnp_remove_device(struct pnp_dev *dev)
device_unregister(&dev->dev);
}
-/**
- * pnp_remove_device - removes a pnp device from the pnp layer
- * @dev: pointer to dev to add
- *
- * this function will free all mem used by dev
- */
-#if 0
-void pnp_remove_device(struct pnp_dev *dev)
-{
- if (!dev || dev->card)
- return;
- __pnp_remove_device(dev);
-}
-#endif /* 0 */
-
static int __init pnp_init(void)
{
printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n");
@@ -185,10 +162,3 @@ static int __init pnp_init(void)
}
subsys_initcall(pnp_init);
-
-#if 0
-EXPORT_SYMBOL(pnp_register_protocol);
-EXPORT_SYMBOL(pnp_unregister_protocol);
-EXPORT_SYMBOL(pnp_add_device);
-EXPORT_SYMBOL(pnp_remove_device);
-#endif /* 0 */
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e161423b4300..2fa64a6b25c8 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -2,7 +2,6 @@
* driver.c - device id matching, driver model, etc.
*
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/string.h>
@@ -16,12 +15,11 @@
static int compare_func(const char *ida, const char *idb)
{
int i;
+
/* we only need to compare the last 4 chars */
- for (i=3; i<7; i++)
- {
+ for (i = 3; i < 7; i++) {
if (ida[i] != 'X' &&
- idb[i] != 'X' &&
- toupper(ida[i]) != toupper(idb[i]))
+ idb[i] != 'X' && toupper(ida[i]) != toupper(idb[i]))
return 0;
}
return 1;
@@ -31,20 +29,22 @@ int compare_pnp_id(struct pnp_id *pos, const char *id)
{
if (!pos || !id || (strlen(id) != 7))
return 0;
- if (memcmp(id,"ANYDEVS",7)==0)
+ if (memcmp(id, "ANYDEVS", 7) == 0)
return 1;
- while (pos){
- if (memcmp(pos->id,id,3)==0)
- if (compare_func(pos->id,id)==1)
+ while (pos) {
+ if (memcmp(pos->id, id, 3) == 0)
+ if (compare_func(pos->id, id) == 1)
return 1;
pos = pos->next;
}
return 0;
}
-static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct pnp_dev *dev)
+static const struct pnp_device_id *match_device(struct pnp_driver *drv,
+ struct pnp_dev *dev)
{
const struct pnp_device_id *drv_id = drv->id_table;
+
if (!drv_id)
return NULL;
@@ -59,7 +59,7 @@ static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct
int pnp_device_attach(struct pnp_dev *pnp_dev)
{
spin_lock(&pnp_lock);
- if(pnp_dev->status != PNP_READY){
+ if (pnp_dev->status != PNP_READY) {
spin_unlock(&pnp_lock);
return -EBUSY;
}
@@ -86,7 +86,8 @@ static int pnp_device_probe(struct device *dev)
pnp_dev = to_pnp_dev(dev);
pnp_drv = to_pnp_driver(dev->driver);
- pnp_dbg("match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name);
+ pnp_dbg("match found with the PnP device '%s' and the driver '%s'",
+ dev->bus_id, pnp_drv->name);
error = pnp_device_attach(pnp_dev);
if (error < 0)
@@ -99,7 +100,7 @@ static int pnp_device_probe(struct device *dev)
return error;
}
} else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
- == PNP_DRIVER_RES_DISABLE) {
+ == PNP_DRIVER_RES_DISABLE) {
error = pnp_disable_dev(pnp_dev);
if (error < 0)
return error;
@@ -110,7 +111,7 @@ static int pnp_device_probe(struct device *dev)
if (dev_id != NULL)
error = pnp_drv->probe(pnp_dev, dev_id);
}
- if (error >= 0){
+ if (error >= 0) {
pnp_dev->driver = pnp_drv;
error = 0;
} else
@@ -124,8 +125,8 @@ fail:
static int pnp_device_remove(struct device *dev)
{
- struct pnp_dev * pnp_dev = to_pnp_dev(dev);
- struct pnp_driver * drv = pnp_dev->driver;
+ struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+ struct pnp_driver *drv = pnp_dev->driver;
if (drv) {
if (drv->remove)
@@ -138,8 +139,9 @@ static int pnp_device_remove(struct device *dev)
static int pnp_bus_match(struct device *dev, struct device_driver *drv)
{
- struct pnp_dev * pnp_dev = to_pnp_dev(dev);
- struct pnp_driver * pnp_drv = to_pnp_driver(drv);
+ struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+ struct pnp_driver *pnp_drv = to_pnp_driver(drv);
+
if (match_device(pnp_drv, pnp_dev) == NULL)
return 0;
return 1;
@@ -147,8 +149,8 @@ static int pnp_bus_match(struct device *dev, struct device_driver *drv)
static int pnp_bus_suspend(struct device *dev, pm_message_t state)
{
- struct pnp_dev * pnp_dev = to_pnp_dev(dev);
- struct pnp_driver * pnp_drv = pnp_dev->driver;
+ struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+ struct pnp_driver *pnp_drv = pnp_dev->driver;
int error;
if (!pnp_drv)
@@ -162,23 +164,28 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) &&
pnp_can_disable(pnp_dev)) {
- error = pnp_stop_dev(pnp_dev);
- if (error)
- return error;
+ error = pnp_stop_dev(pnp_dev);
+ if (error)
+ return error;
}
+ if (pnp_dev->protocol && pnp_dev->protocol->suspend)
+ pnp_dev->protocol->suspend(pnp_dev, state);
return 0;
}
static int pnp_bus_resume(struct device *dev)
{
- struct pnp_dev * pnp_dev = to_pnp_dev(dev);
- struct pnp_driver * pnp_drv = pnp_dev->driver;
+ struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+ struct pnp_driver *pnp_drv = pnp_dev->driver;
int error;
if (!pnp_drv)
return 0;
+ if (pnp_dev->protocol && pnp_dev->protocol->resume)
+ pnp_dev->protocol->resume(pnp_dev);
+
if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
error = pnp_start_dev(pnp_dev);
if (error)
@@ -192,12 +199,12 @@ static int pnp_bus_resume(struct device *dev)
}
struct bus_type pnp_bus_type = {
- .name = "pnp",
- .match = pnp_bus_match,
- .probe = pnp_device_probe,
- .remove = pnp_device_remove,
+ .name = "pnp",
+ .match = pnp_bus_match,
+ .probe = pnp_device_probe,
+ .remove = pnp_device_remove,
.suspend = pnp_bus_suspend,
- .resume = pnp_bus_resume,
+ .resume = pnp_bus_resume,
};
int pnp_register_driver(struct pnp_driver *drv)
@@ -220,16 +227,11 @@ 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
- *
*/
-
int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
{
struct pnp_id *ptr;
- if (!id)
- return -EINVAL;
- if (!dev)
- return -EINVAL;
+
id->next = NULL;
ptr = dev->id;
while (ptr && ptr->next)
@@ -243,8 +245,5 @@ int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
EXPORT_SYMBOL(pnp_register_driver);
EXPORT_SYMBOL(pnp_unregister_driver);
-#if 0
-EXPORT_SYMBOL(pnp_add_id);
-#endif
EXPORT_SYMBOL(pnp_device_attach);
EXPORT_SYMBOL(pnp_device_detach);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index ac9fcd499f3f..a0cfb75bbb8d 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -3,7 +3,6 @@
*
* Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/pnp.h>
@@ -29,7 +28,7 @@ struct pnp_info_buffer {
typedef struct pnp_info_buffer pnp_info_buffer_t;
-static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
+static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
{
va_list args;
int res;
@@ -48,14 +47,18 @@ static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
return res;
}
-static void pnp_print_port(pnp_info_buffer_t *buffer, char *space, struct pnp_port *port)
+static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
+ struct pnp_port *port)
{
- pnp_printf(buffer, "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
- space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
- port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
+ pnp_printf(buffer,
+ "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
+ space, port->min, port->max,
+ port->align ? (port->align - 1) : 0, port->size,
+ port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
}
-static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq *irq)
+static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
+ struct pnp_irq *irq)
{
int first = 1, i;
@@ -85,14 +88,15 @@ static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq
pnp_printf(buffer, "\n");
}
-static void pnp_print_dma(pnp_info_buffer_t *buffer, char *space, struct pnp_dma *dma)
+static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
+ struct pnp_dma *dma)
{
int first = 1, i;
char *s;
pnp_printf(buffer, "%sdma ", space);
for (i = 0; i < 8; i++)
- if (dma->map & (1<<i)) {
+ if (dma->map & (1 << i)) {
if (!first) {
pnp_printf(buffer, ",");
} else {
@@ -136,12 +140,13 @@ static void pnp_print_dma(pnp_info_buffer_t *buffer, char *space, struct pnp_dma
pnp_printf(buffer, " %s\n", s);
}
-static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem *mem)
+static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
+ struct pnp_mem *mem)
{
char *s;
pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
- space, mem->min, mem->max, mem->align, mem->size);
+ space, mem->min, mem->max, mem->align, mem->size);
if (mem->flags & IORESOURCE_MEM_WRITEABLE)
pnp_printf(buffer, ", writeable");
if (mem->flags & IORESOURCE_MEM_CACHEABLE)
@@ -168,7 +173,7 @@ static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem
pnp_printf(buffer, ", %s\n", s);
}
-static void pnp_print_option(pnp_info_buffer_t *buffer, char *space,
+static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
struct pnp_option *option, int dep)
{
char *s;
@@ -179,19 +184,19 @@ static void pnp_print_option(pnp_info_buffer_t *buffer, char *space,
if (dep) {
switch (option->priority) {
- case PNP_RES_PRIORITY_PREFERRED:
+ case PNP_RES_PRIORITY_PREFERRED:
s = "preferred";
break;
- case PNP_RES_PRIORITY_ACCEPTABLE:
+ case PNP_RES_PRIORITY_ACCEPTABLE:
s = "acceptable";
break;
- case PNP_RES_PRIORITY_FUNCTIONAL:
+ case PNP_RES_PRIORITY_FUNCTIONAL:
s = "functional";
break;
- default:
+ default:
s = "invalid";
}
- pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s);
+ pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
}
for (port = option->port; port; port = port->next)
@@ -204,16 +209,16 @@ static void pnp_print_option(pnp_info_buffer_t *buffer, char *space,
pnp_print_mem(buffer, space, mem);
}
-
-static ssize_t pnp_show_options(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_options(struct device *dmdev,
+ struct device_attribute *attr, char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
- struct pnp_option * independent = dev->independent;
- struct pnp_option * dependent = dev->dependent;
+ struct pnp_option *independent = dev->independent;
+ struct pnp_option *dependent = dev->dependent;
int ret, dep = 1;
pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
- pnp_alloc(sizeof(pnp_info_buffer_t));
+ pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
return -ENOMEM;
@@ -223,7 +228,7 @@ static ssize_t pnp_show_options(struct device *dmdev, struct device_attribute *a
if (independent)
pnp_print_option(buffer, "", independent, 0);
- while (dependent){
+ while (dependent) {
pnp_print_option(buffer, " ", dependent, dep);
dependent = dependent->next;
dep++;
@@ -233,10 +238,11 @@ static ssize_t pnp_show_options(struct device *dmdev, struct device_attribute *a
return ret;
}
-static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL);
-
+static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL);
-static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_current_resources(struct device *dmdev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
int i, ret;
@@ -252,52 +258,56 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
buffer->buffer = buf;
buffer->curr = buffer->buffer;
- pnp_printf(buffer,"state = ");
+ pnp_printf(buffer, "state = ");
if (dev->active)
- pnp_printf(buffer,"active\n");
+ pnp_printf(buffer, "active\n");
else
- pnp_printf(buffer,"disabled\n");
+ pnp_printf(buffer, "disabled\n");
for (i = 0; i < PNP_MAX_PORT; i++) {
if (pnp_port_valid(dev, i)) {
- pnp_printf(buffer,"io");
+ pnp_printf(buffer, "io");
if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
- pnp_printf(buffer," disabled\n");
+ 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));
+ pnp_printf(buffer, " 0x%llx-0x%llx\n",
+ (unsigned long long)
+ pnp_port_start(dev, i),
+ (unsigned long long)pnp_port_end(dev,
+ i));
}
}
for (i = 0; i < PNP_MAX_MEM; i++) {
if (pnp_mem_valid(dev, i)) {
- pnp_printf(buffer,"mem");
+ pnp_printf(buffer, "mem");
if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
- pnp_printf(buffer," disabled\n");
+ 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));
+ pnp_printf(buffer, " 0x%llx-0x%llx\n",
+ (unsigned long long)
+ pnp_mem_start(dev, i),
+ (unsigned long long)pnp_mem_end(dev,
+ i));
}
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (pnp_irq_valid(dev, i)) {
- pnp_printf(buffer,"irq");
+ pnp_printf(buffer, "irq");
if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
- pnp_printf(buffer," disabled\n");
+ pnp_printf(buffer, " disabled\n");
else
- pnp_printf(buffer," %lld\n",
- (unsigned long long)pnp_irq(dev, i));
+ pnp_printf(buffer, " %lld\n",
+ (unsigned long long)pnp_irq(dev, i));
}
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if (pnp_dma_valid(dev, i)) {
- pnp_printf(buffer,"dma");
+ pnp_printf(buffer, "dma");
if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
- pnp_printf(buffer," disabled\n");
+ pnp_printf(buffer, " disabled\n");
else
- pnp_printf(buffer," %lld\n",
- (unsigned long long)pnp_dma(dev, i));
+ pnp_printf(buffer, " %lld\n",
+ (unsigned long long)pnp_dma(dev, i));
}
}
ret = (buffer->curr - buf);
@@ -308,55 +318,57 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
extern struct semaphore pnp_res_mutex;
static ssize_t
-pnp_set_current_resources(struct device * dmdev, struct device_attribute *attr, const char * ubuf, size_t count)
+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);
- char *buf = (void *)ubuf;
- int retval = 0;
+ char *buf = (void *)ubuf;
+ int retval = 0;
if (dev->status & PNP_ATTACHED) {
retval = -EBUSY;
- pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id);
+ pnp_info("Device %s cannot be configured because it is in use.",
+ dev->dev.bus_id);
goto done;
}
while (isspace(*buf))
++buf;
- if (!strnicmp(buf,"disable",7)) {
+ if (!strnicmp(buf, "disable", 7)) {
retval = pnp_disable_dev(dev);
goto done;
}
- if (!strnicmp(buf,"activate",8)) {
+ if (!strnicmp(buf, "activate", 8)) {
retval = pnp_activate_dev(dev);
goto done;
}
- if (!strnicmp(buf,"fill",4)) {
+ if (!strnicmp(buf, "fill", 4)) {
if (dev->active)
goto done;
retval = pnp_auto_config_dev(dev);
goto done;
}
- if (!strnicmp(buf,"auto",4)) {
+ if (!strnicmp(buf, "auto", 4)) {
if (dev->active)
goto done;
pnp_init_resource_table(&dev->res);
retval = pnp_auto_config_dev(dev);
goto done;
}
- if (!strnicmp(buf,"clear",5)) {
+ if (!strnicmp(buf, "clear", 5)) {
if (dev->active)
goto done;
pnp_init_resource_table(&dev->res);
goto done;
}
- if (!strnicmp(buf,"get",3)) {
+ if (!strnicmp(buf, "get", 3)) {
down(&pnp_res_mutex);
if (pnp_can_read(dev))
dev->protocol->get(dev, &dev->res);
up(&pnp_res_mutex);
goto done;
}
- if (!strnicmp(buf,"set",3)) {
+ if (!strnicmp(buf, "set", 3)) {
int nport = 0, nmem = 0, nirq = 0, ndma = 0;
if (dev->active)
goto done;
@@ -366,65 +378,77 @@ pnp_set_current_resources(struct device * dmdev, struct device_attribute *attr,
while (1) {
while (isspace(*buf))
++buf;
- if (!strnicmp(buf,"io",2)) {
+ if (!strnicmp(buf, "io", 2)) {
buf += 2;
while (isspace(*buf))
++buf;
- dev->res.port_resource[nport].start = simple_strtoul(buf,&buf,0);
+ dev->res.port_resource[nport].start =
+ simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
++buf;
- if(*buf == '-') {
+ if (*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
- dev->res.port_resource[nport].end = simple_strtoul(buf,&buf,0);
+ dev->res.port_resource[nport].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;
+ 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;
continue;
}
- if (!strnicmp(buf,"mem",3)) {
+ if (!strnicmp(buf, "mem", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.mem_resource[nmem].start = simple_strtoul(buf,&buf,0);
+ dev->res.mem_resource[nmem].start =
+ simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
++buf;
- if(*buf == '-') {
+ if (*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
- dev->res.mem_resource[nmem].end = simple_strtoul(buf,&buf,0);
+ dev->res.mem_resource[nmem].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;
+ 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;
continue;
}
- if (!strnicmp(buf,"irq",3)) {
+ 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;
+ 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;
continue;
}
- if (!strnicmp(buf,"dma",3)) {
+ 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;
+ 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;
@@ -435,45 +459,51 @@ pnp_set_current_resources(struct device * dmdev, struct device_attribute *attr,
up(&pnp_res_mutex);
goto done;
}
- done:
+
+done:
if (retval < 0)
return retval;
return count;
}
-static DEVICE_ATTR(resources,S_IRUGO | S_IWUSR,
- pnp_show_current_resources,pnp_set_current_resources);
+static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR,
+ pnp_show_current_resources, pnp_set_current_resources);
-static ssize_t pnp_show_current_ids(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_current_ids(struct device *dmdev,
+ struct device_attribute *attr, char *buf)
{
char *str = buf;
struct pnp_dev *dev = to_pnp_dev(dmdev);
- struct pnp_id * pos = dev->id;
+ struct pnp_id *pos = dev->id;
while (pos) {
- str += sprintf(str,"%s\n", pos->id);
+ str += sprintf(str, "%s\n", pos->id);
pos = pos->next;
}
return (str - buf);
}
-static DEVICE_ATTR(id,S_IRUGO,pnp_show_current_ids,NULL);
+static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL);
int pnp_interface_attach_device(struct pnp_dev *dev)
{
- int rc = device_create_file(&dev->dev,&dev_attr_options);
- if (rc) goto err;
- rc = device_create_file(&dev->dev,&dev_attr_resources);
- if (rc) goto err_opt;
- rc = device_create_file(&dev->dev,&dev_attr_id);
- if (rc) goto err_res;
+ int rc = device_create_file(&dev->dev, &dev_attr_options);
+
+ if (rc)
+ goto err;
+ rc = device_create_file(&dev->dev, &dev_attr_resources);
+ if (rc)
+ goto err_opt;
+ rc = device_create_file(&dev->dev, &dev_attr_id);
+ if (rc)
+ goto err_res;
return 0;
err_res:
- device_remove_file(&dev->dev,&dev_attr_resources);
+ device_remove_file(&dev->dev, &dev_attr_resources);
err_opt:
- device_remove_file(&dev->dev,&dev_attr_options);
+ device_remove_file(&dev->dev, &dev_attr_options);
err:
return rc;
}
diff --git a/drivers/pnp/isapnp/compat.c b/drivers/pnp/isapnp/compat.c
index 0697ab88a9ac..10bdcc4d4f7b 100644
--- a/drivers/pnp/isapnp/compat.c
+++ b/drivers/pnp/isapnp/compat.c
@@ -3,34 +3,30 @@
* the old isapnp APIs. If possible use the new APIs instead.
*
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
*/
-
-/* TODO: see if more isapnp functions are needed here */
#include <linux/module.h>
#include <linux/isapnp.h>
#include <linux/string.h>
-static void pnp_convert_id(char *buf, unsigned short vendor, unsigned short device)
+static void pnp_convert_id(char *buf, unsigned short vendor,
+ unsigned short device)
{
sprintf(buf, "%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);
+ '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);
}
-struct pnp_card *pnp_find_card(unsigned short vendor,
- unsigned short device,
+struct pnp_card *pnp_find_card(unsigned short vendor, unsigned short device,
struct pnp_card *from)
{
char id[8];
char any[8];
struct list_head *list;
+
pnp_convert_id(id, vendor, device);
pnp_convert_id(any, ISAPNP_ANY_ID, ISAPNP_ANY_ID);
@@ -38,20 +34,20 @@ struct pnp_card *pnp_find_card(unsigned short vendor,
while (list != &pnp_cards) {
struct pnp_card *card = global_to_pnp_card(list);
- if (compare_pnp_id(card->id,id) || (memcmp(id,any,7)==0))
+
+ if (compare_pnp_id(card->id, id) || (memcmp(id, any, 7) == 0))
return card;
list = list->next;
}
return NULL;
}
-struct pnp_dev *pnp_find_dev(struct pnp_card *card,
- unsigned short vendor,
- unsigned short function,
- struct pnp_dev *from)
+struct pnp_dev *pnp_find_dev(struct pnp_card *card, unsigned short vendor,
+ unsigned short function, struct pnp_dev *from)
{
char id[8];
char any[8];
+
pnp_convert_id(id, vendor, function);
pnp_convert_id(any, ISAPNP_ANY_ID, ISAPNP_ANY_ID);
if (card == NULL) { /* look for a logical device from all cards */
@@ -63,7 +59,9 @@ struct pnp_dev *pnp_find_dev(struct pnp_card *card,
while (list != &pnp_global) {
struct pnp_dev *dev = global_to_pnp_dev(list);
- if (compare_pnp_id(dev->id,id) || (memcmp(id,any,7)==0))
+
+ if (compare_pnp_id(dev->id, id) ||
+ (memcmp(id, any, 7) == 0))
return dev;
list = list->next;
}
@@ -78,7 +76,8 @@ struct pnp_dev *pnp_find_dev(struct pnp_card *card,
}
while (list != &card->devices) {
struct pnp_dev *dev = card_to_pnp_dev(list);
- if (compare_pnp_id(dev->id,id))
+
+ if (compare_pnp_id(dev->id, id))
return dev;
list = list->next;
}
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 914d00c423ad..b035d60a1dcc 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -47,14 +47,11 @@
#if 0
#define ISAPNP_REGION_OK
#endif
-#if 0
-#define ISAPNP_DEBUG
-#endif
-int isapnp_disable; /* Disable ISA PnP */
-static int isapnp_rdp; /* Read Data Port */
-static int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
-static int isapnp_verbose = 1; /* verbose mode */
+int isapnp_disable; /* Disable ISA PnP */
+static int isapnp_rdp; /* Read Data Port */
+static int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
+static int isapnp_verbose = 1; /* verbose mode */
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Generic ISA Plug & Play support");
@@ -93,7 +90,6 @@ MODULE_LICENSE("GPL");
static unsigned char isapnp_checksum_value;
static DEFINE_MUTEX(isapnp_cfg_mutex);
-static int isapnp_detected;
static int isapnp_csn_count;
/* some prototypes */
@@ -126,7 +122,7 @@ static unsigned short isapnp_read_word(unsigned char idx)
unsigned short val;
val = isapnp_read_byte(idx);
- val = (val << 8) + isapnp_read_byte(idx+1);
+ val = (val << 8) + isapnp_read_byte(idx + 1);
return val;
}
@@ -139,7 +135,7 @@ void isapnp_write_byte(unsigned char idx, unsigned char val)
static void isapnp_write_word(unsigned char idx, unsigned short val)
{
isapnp_write_byte(idx, val >> 8);
- isapnp_write_byte(idx+1, val);
+ isapnp_write_byte(idx + 1, val);
}
static void isapnp_key(void)
@@ -193,7 +189,7 @@ static void isapnp_deactivate(unsigned char logdev)
static void __init isapnp_peek(unsigned char *data, int bytes)
{
int i, j;
- unsigned char d=0;
+ unsigned char d = 0;
for (i = 1; i <= bytes; i++) {
for (j = 0; j < 20; j++) {
@@ -220,19 +216,18 @@ static int isapnp_next_rdp(void)
{
int rdp = isapnp_rdp;
static int old_rdp = 0;
-
- if(old_rdp)
- {
+
+ if (old_rdp) {
release_region(old_rdp, 1);
old_rdp = 0;
}
while (rdp <= 0x3ff) {
/*
- * We cannot use NE2000 probe spaces for ISAPnP or we
- * will lock up machines.
+ * We cannot use NE2000 probe spaces for ISAPnP or we
+ * will lock up machines.
*/
- if ((rdp < 0x280 || rdp > 0x380) && request_region(rdp, 1, "ISAPnP"))
- {
+ if ((rdp < 0x280 || rdp > 0x380)
+ && request_region(rdp, 1, "ISAPnP")) {
isapnp_rdp = rdp;
old_rdp = rdp;
return 0;
@@ -253,7 +248,6 @@ static inline void isapnp_set_rdp(void)
* Perform an isolation. The port selection code now tries to avoid
* "dangerous to read" ports.
*/
-
static int __init isapnp_isolate_rdp_select(void)
{
isapnp_wait();
@@ -282,7 +276,6 @@ static int __init isapnp_isolate_rdp_select(void)
/*
* Isolate (assign uniqued CSN) to all ISA PnP devices.
*/
-
static int __init isapnp_isolate(void)
{
unsigned char checksum = 0x6a;
@@ -305,7 +298,9 @@ static int __init isapnp_isolate(void)
udelay(250);
if (data == 0x55aa)
bit = 0x01;
- checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
+ checksum =
+ ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
+ | (checksum >> 1);
bit = 0x00;
}
for (i = 65; i <= 72; i++) {
@@ -336,7 +331,7 @@ static int __init isapnp_isolate(void)
} else if (iteration > 1) {
break;
}
- __next:
+__next:
if (csn == 255)
break;
checksum = 0x6a;
@@ -351,13 +346,12 @@ static int __init isapnp_isolate(void)
/*
* Read one tag from stream.
*/
-
static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
{
unsigned char tag, tmp[2];
isapnp_peek(&tag, 1);
- if (tag == 0) /* invalid tag */
+ if (tag == 0) /* invalid tag */
return -1;
if (tag & 0x80) { /* large item */
*type = tag;
@@ -368,7 +362,8 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
*size = tag & 0x07;
}
#if 0
- printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
+ printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type,
+ *size);
#endif
if (*type == 0xff && *size == 0xffff) /* probably invalid data */
return -1;
@@ -378,7 +373,6 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
/*
* Skip specified number of bytes from stream.
*/
-
static void __init isapnp_skip_bytes(int count)
{
isapnp_peek(NULL, count);
@@ -387,31 +381,30 @@ 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)
+static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor,
+ unsigned short device)
{
- struct pnp_id * id;
+ 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);
+ '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, int size, int number)
+static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
+ int size, int number)
{
unsigned char tmp[6];
struct pnp_dev *dev;
@@ -435,13 +428,11 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si
return dev;
}
-
/*
* Add IRQ resource to resources list.
*/
-
static void __init isapnp_parse_irq_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[3];
struct pnp_irq *irq;
@@ -458,15 +449,13 @@ static void __init isapnp_parse_irq_resource(struct pnp_option *option,
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
pnp_register_irq_resource(option, irq);
- return;
}
/*
* Add DMA resource to resources list.
*/
-
static void __init isapnp_parse_dma_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[2];
struct pnp_dma *dma;
@@ -478,15 +467,13 @@ static void __init isapnp_parse_dma_resource(struct pnp_option *option,
dma->map = tmp[0];
dma->flags = tmp[1];
pnp_register_dma_resource(option, dma);
- return;
}
/*
* Add port resource to resources list.
*/
-
static void __init isapnp_parse_port_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[7];
struct pnp_port *port;
@@ -500,16 +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);
- return;
+ pnp_register_port_resource(option, port);
}
/*
* Add fixed port resource to resources list.
*/
-
static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[3];
struct pnp_port *port;
@@ -522,16 +507,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);
- return;
+ pnp_register_port_resource(option, port);
}
/*
* Add memory resource to resources list.
*/
-
static void __init isapnp_parse_mem_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[9];
struct pnp_mem *mem;
@@ -545,16 +528,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);
- return;
+ pnp_register_mem_resource(option, mem);
}
/*
* Add 32-bit memory resource to resources list.
*/
-
static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[17];
struct pnp_mem *mem;
@@ -565,18 +546,19 @@ static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
return;
mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
- mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
- mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
+ mem->align =
+ (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
+ 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(option, mem);
}
/*
* Add 32-bit fixed memory resource to resources list.
*/
-
static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
- int size)
+ int size)
{
unsigned char tmp[9];
struct pnp_mem *mem;
@@ -585,28 +567,29 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
- mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
+ mem->min = mem->max =
+ (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
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(option, mem);
}
/*
* Parse card name for ISA PnP device.
- */
-
+ */
static void __init
isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
{
if (name[0] == '\0') {
- unsigned short size1 = *size >= name_max ? (name_max - 1) : *size;
+ unsigned short size1 =
+ *size >= name_max ? (name_max - 1) : *size;
isapnp_peek(name, size1);
name[size1] = '\0';
*size -= size1;
/* clean whitespace from end of string */
- while (size1 > 0 && name[--size1] == ' ')
+ while (size1 > 0 && name[--size1] == ' ')
name[size1] = '\0';
}
}
@@ -614,7 +597,6 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
/*
* Parse resource map for logical device.
*/
-
static int __init isapnp_create_device(struct pnp_card *card,
unsigned short size)
{
@@ -622,6 +604,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
unsigned char type, tmp[17];
struct pnp_option *option;
struct pnp_dev *dev;
+
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
option = pnp_register_independent_option(dev);
@@ -629,17 +612,19 @@ static int __init isapnp_create_device(struct pnp_card *card,
kfree(dev);
return 1;
}
- pnp_add_card_device(card,dev);
+ pnp_add_card_device(card, dev);
while (1) {
- if (isapnp_read_tag(&type, &size)<0)
+ if (isapnp_read_tag(&type, &size) < 0)
return 1;
if (skip && type != _STAG_LOGDEVID && type != _STAG_END)
goto __skip;
switch (type) {
case _STAG_LOGDEVID:
if (size >= 5 && size <= 6) {
- if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
+ if ((dev =
+ isapnp_parse_device(card, size,
+ number++)) == NULL)
return 1;
size = 0;
skip = 0;
@@ -648,7 +633,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
kfree(dev);
return 1;
}
- pnp_add_card_device(card,dev);
+ pnp_add_card_device(card, dev);
} else {
skip = 1;
}
@@ -658,7 +643,8 @@ 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]);
+ isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0],
+ (tmp[3] << 8) | tmp[2]);
compat++;
size = 0;
}
@@ -684,7 +670,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
priority = 0x100 | tmp[0];
size = 0;
}
- option = pnp_register_dependent_option(dev,priority);
+ option = pnp_register_dependent_option(dev, priority);
if (!option)
return 1;
break;
@@ -739,11 +725,13 @@ 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);
+ printk(KERN_ERR
+ "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n",
+ type, dev->number, card->number);
}
- __skip:
- if (size > 0)
- isapnp_skip_bytes(size);
+__skip:
+ if (size > 0)
+ isapnp_skip_bytes(size);
}
return 0;
}
@@ -751,14 +739,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
/*
* Parse resource map for ISA PnP card.
*/
-
static void __init isapnp_parse_resource_map(struct pnp_card *card)
{
unsigned char type, tmp[17];
unsigned short size;
while (1) {
- if (isapnp_read_tag(&type, &size)<0)
+ if (isapnp_read_tag(&type, &size) < 0)
return;
switch (type) {
case _STAG_PNPVERNO:
@@ -771,7 +758,7 @@ static void __init isapnp_parse_resource_map(struct pnp_card *card)
break;
case _STAG_LOGDEVID:
if (size >= 5 && size <= 6) {
- if (isapnp_create_device(card, size)==1)
+ if (isapnp_create_device(card, size) == 1)
return;
size = 0;
}
@@ -779,7 +766,8 @@ static void __init isapnp_parse_resource_map(struct pnp_card *card)
case _STAG_VENDOR:
break;
case _LTAG_ANSISTR:
- isapnp_parse_name(card->name, sizeof(card->name), &size);
+ isapnp_parse_name(card->name, sizeof(card->name),
+ &size);
break;
case _LTAG_UNICODESTR:
/* silently ignore */
@@ -792,18 +780,19 @@ 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);
+ printk(KERN_ERR
+ "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n",
+ type, card->number);
}
- __skip:
- if (size > 0)
- isapnp_skip_bytes(size);
+__skip:
+ if (size > 0)
+ isapnp_skip_bytes(size);
}
}
/*
* Compute ISA PnP checksum for first eight bytes.
*/
-
static unsigned char __init isapnp_checksum(unsigned char *data)
{
int i, j;
@@ -815,7 +804,9 @@ static unsigned char __init isapnp_checksum(unsigned char *data)
bit = 0;
if (b & (1 << j))
bit = 1;
- checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
+ checksum =
+ ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
+ | (checksum >> 1);
}
}
return checksum;
@@ -824,27 +815,25 @@ 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)
+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);
+ 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);
+ '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)
{
int csn;
@@ -858,22 +847,29 @@ static int __init isapnp_build_device_list(void)
isapnp_peek(header, 9);
checksum = isapnp_checksum(header);
#if 0
- printk(KERN_DEBUG "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
+ "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);
#endif
- if ((card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
+ 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_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);
+ printk(KERN_ERR
+ "isapnp: checksum for device %i is not valid (0x%x)\n",
+ csn, isapnp_checksum_value);
card->checksum = isapnp_checksum_value;
card->protocol = &isapnp_protocol;
@@ -890,6 +886,7 @@ static int __init isapnp_build_device_list(void)
int isapnp_present(void)
{
struct pnp_card *card;
+
pnp_for_each_card(card) {
if (card->protocol == &isapnp_protocol)
return 1;
@@ -911,13 +908,13 @@ int isapnp_cfg_begin(int csn, int logdev)
/* it is possible to set RDP only in the isolation phase */
/* Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
isapnp_write_byte(0x02, 0x04); /* clear CSN of card */
- mdelay(2); /* is this necessary? */
- isapnp_wake(csn); /* bring card into sleep state */
- isapnp_wake(0); /* bring card into isolation state */
- isapnp_set_rdp(); /* reset the RDP port */
- udelay(1000); /* delay 1000us */
+ mdelay(2); /* is this necessary? */
+ isapnp_wake(csn); /* bring card into sleep state */
+ isapnp_wake(0); /* bring card into isolation state */
+ isapnp_set_rdp(); /* reset the RDP port */
+ udelay(1000); /* delay 1000us */
isapnp_write_byte(0x06, csn); /* reset CSN to previous value */
- udelay(250); /* is this necessary? */
+ udelay(250); /* is this necessary? */
#endif
if (logdev >= 0)
isapnp_device(logdev);
@@ -931,22 +928,18 @@ int isapnp_cfg_end(void)
return 0;
}
-
/*
- * Inititialization.
+ * Initialization.
*/
-
EXPORT_SYMBOL(isapnp_protocol);
EXPORT_SYMBOL(isapnp_present);
EXPORT_SYMBOL(isapnp_cfg_begin);
EXPORT_SYMBOL(isapnp_cfg_end);
-#if 0
-EXPORT_SYMBOL(isapnp_read_byte);
-#endif
EXPORT_SYMBOL(isapnp_write_byte);
-static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res)
+static int isapnp_read_resources(struct pnp_dev *dev,
+ struct pnp_resource_table *res)
{
int tmp, ret;
@@ -960,33 +953,40 @@ static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table
res->port_resource[tmp].flags = IORESOURCE_IO;
}
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
- ret = isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
+ 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 (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
- ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8);
+ 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].start =
+ res->irq_resource[tmp].end = ret;
res->irq_resource[tmp].flags = IORESOURCE_IRQ;
}
for (tmp = 0; tmp < PNP_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].start =
+ res->dma_resource[tmp].end = ret;
res->dma_resource[tmp].flags = IORESOURCE_DMA;
}
}
return 0;
}
-static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
+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);
@@ -994,24 +994,44 @@ static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table *
return ret;
}
-static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
+static int isapnp_set_resources(struct pnp_dev *dev,
+ struct pnp_resource_table *res)
{
int tmp;
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
- for (tmp = 0; tmp < PNP_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 < PNP_MAX_IRQ && (res->irq_resource[tmp].flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; tmp++) {
+ for (tmp = 0;
+ tmp < PNP_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 < PNP_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);
+ isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
}
- for (tmp = 0; tmp < PNP_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 < PNP_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);
+ for (tmp = 0;
+ tmp < PNP_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 < PNP_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();
@@ -1020,7 +1040,7 @@ static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table *
static int isapnp_disable_resources(struct pnp_dev *dev)
{
- if (!dev || !dev->active)
+ if (!dev->active)
return -EINVAL;
isapnp_cfg_begin(dev->card->number, dev->number);
isapnp_deactivate(dev->number);
@@ -1030,9 +1050,9 @@ static int isapnp_disable_resources(struct pnp_dev *dev)
}
struct pnp_protocol isapnp_protocol = {
- .name = "ISA Plug and Play",
- .get = isapnp_get_resources,
- .set = isapnp_set_resources,
+ .name = "ISA Plug and Play",
+ .get = isapnp_get_resources,
+ .set = isapnp_set_resources,
.disable = isapnp_disable_resources,
};
@@ -1043,7 +1063,6 @@ static int __init isapnp_init(void)
struct pnp_dev *dev;
if (isapnp_disable) {
- isapnp_detected = 0;
printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
return 0;
}
@@ -1053,31 +1072,36 @@ static int __init isapnp_init(void)
#endif
#ifdef ISAPNP_REGION_OK
if (!request_region(_PIDXR, 1, "isapnp index")) {
- printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
+ printk(KERN_ERR "isapnp: Index Register 0x%x already used\n",
+ _PIDXR);
return -EBUSY;
}
#endif
if (!request_region(_PNPWRP, 1, "isapnp write")) {
- printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
+ printk(KERN_ERR
+ "isapnp: Write Data Register 0x%x already used\n",
+ _PNPWRP);
#ifdef ISAPNP_REGION_OK
release_region(_PIDXR, 1);
#endif
return -EBUSY;
}
- if(pnp_register_protocol(&isapnp_protocol)<0)
+ if (pnp_register_protocol(&isapnp_protocol) < 0)
return -EBUSY;
/*
- * Print a message. The existing ISAPnP code is hanging machines
- * so let the user know where.
+ * Print a message. The existing ISAPnP code is hanging machines
+ * so let the user know where.
*/
-
+
printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");
if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
isapnp_rdp |= 3;
if (!request_region(isapnp_rdp, 1, "isapnp read")) {
- printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
+ printk(KERN_ERR
+ "isapnp: Read Data Register 0x%x already used\n",
+ isapnp_rdp);
#ifdef ISAPNP_REGION_OK
release_region(_PIDXR, 1);
#endif
@@ -1086,17 +1110,15 @@ static int __init isapnp_init(void)
}
isapnp_set_rdp();
}
- isapnp_detected = 1;
if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) {
cards = isapnp_isolate();
- if (cards < 0 ||
- (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
+ if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
#ifdef ISAPNP_REGION_OK
release_region(_PIDXR, 1);
#endif
release_region(_PNPWRP, 1);
- isapnp_detected = 0;
- printk(KERN_INFO "isapnp: No Plug & Play device found\n");
+ printk(KERN_INFO
+ "isapnp: No Plug & Play device found\n");
return 0;
}
request_region(isapnp_rdp, 1, "isapnp read");
@@ -1104,22 +1126,25 @@ static int __init isapnp_init(void)
isapnp_build_device_list();
cards = 0;
- protocol_for_each_card(&isapnp_protocol,card) {
+ protocol_for_each_card(&isapnp_protocol, card) {
cards++;
if (isapnp_verbose) {
- printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
+ printk(KERN_INFO "isapnp: 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");
+ card_for_each_dev(card, dev) {
+ printk(KERN_INFO "isapnp: Device '%s'\n",
+ dev->name[0] ? dev->name : "Unknown");
}
}
}
- if (cards) {
- printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":"");
- } else {
+ if (cards)
+ printk(KERN_INFO
+ "isapnp: %i Plug & Play card%s detected total\n", cards,
+ cards > 1 ? "s" : "");
+ else
printk(KERN_INFO "isapnp: No Plug & Play card found\n");
- }
isapnp_proc_init();
return 0;
@@ -1141,11 +1166,10 @@ __setup("noisapnp", isapnp_setup_disable);
static int __init isapnp_setup_isapnp(char *str)
{
- (void)((get_option(&str,&isapnp_rdp) == 2) &&
- (get_option(&str,&isapnp_reset) == 2) &&
- (get_option(&str,&isapnp_verbose) == 2));
+ (void)((get_option(&str, &isapnp_rdp) == 2) &&
+ (get_option(&str, &isapnp_reset) == 2) &&
+ (get_option(&str, &isapnp_verbose) == 2));
return 1;
}
__setup("isapnp=", isapnp_setup_isapnp);
-
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 40b724ebe23b..560ccb640816 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -2,7 +2,6 @@
* ISA Plug & Play support
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
*
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -16,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <linux/module.h>
@@ -54,7 +52,8 @@ static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
return (file->f_pos = new);
}
-static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,
+ size_t nbytes, loff_t * ppos)
{
struct inode *ino = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp = PDE(ino);
@@ -74,7 +73,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t
return -EINVAL;
isapnp_cfg_begin(dev->card->number, dev->number);
- for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
+ for (; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
unsigned char val;
val = isapnp_read_byte(pos);
__put_user(val, buf);
@@ -85,10 +84,9 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t
return nbytes;
}
-static const struct file_operations isapnp_proc_bus_file_operations =
-{
- .llseek = isapnp_proc_bus_lseek,
- .read = isapnp_proc_bus_read,
+static const struct file_operations isapnp_proc_bus_file_operations = {
+ .llseek = isapnp_proc_bus_lseek,
+ .read = isapnp_proc_bus_read,
};
static int isapnp_proc_attach_device(struct pnp_dev *dev)
@@ -114,57 +112,13 @@ static int isapnp_proc_attach_device(struct pnp_dev *dev)
return 0;
}
-#ifdef MODULE
-static int __exit isapnp_proc_detach_device(struct pnp_dev *dev)
-{
- struct pnp_card *bus = dev->card;
- struct proc_dir_entry *de;
- char name[16];
-
- if (!(de = bus->procdir))
- return -EINVAL;
- sprintf(name, "%02x", dev->number);
- remove_proc_entry(name, de);
- return 0;
-}
-
-static int __exit isapnp_proc_detach_bus(struct pnp_card *bus)
-{
- struct proc_dir_entry *de;
- char name[16];
-
- if (!(de = bus->procdir))
- return -EINVAL;
- sprintf(name, "%02x", bus->number);
- remove_proc_entry(name, isapnp_proc_bus_dir);
- return 0;
-}
-#endif /* MODULE */
-
int __init isapnp_proc_init(void)
{
struct pnp_dev *dev;
+
isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
- protocol_for_each_dev(&isapnp_protocol,dev) {
+ protocol_for_each_dev(&isapnp_protocol, dev) {
isapnp_proc_attach_device(dev);
}
return 0;
}
-
-#ifdef MODULE
-int __exit isapnp_proc_done(void)
-{
- struct pnp_dev *dev;
- struct pnp_bus *card;
-
- isapnp_for_each_dev(dev) {
- isapnp_proc_detach_device(dev);
- }
- isapnp_for_each_card(card) {
- isapnp_proc_detach_bus(card);
- }
- if (isapnp_proc_bus_dir)
- remove_proc_entry("isapnp", proc_bus);
- return 0;
-}
-#endif /* MODULE */
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 57e6ab1004d0..0826287eef53 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -3,7 +3,6 @@
*
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/errno.h>
@@ -22,11 +21,9 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
resource_size_t *start, *end;
unsigned long *flags;
- if (!dev || !rule)
- return -EINVAL;
-
if (idx >= PNP_MAX_PORT) {
- pnp_err("More than 4 ports is incompatible with pnp specifications.");
+ pnp_err
+ ("More than 4 ports is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -41,11 +38,11 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
/* set the initial values */
*flags |= rule->flags | IORESOURCE_IO;
- *flags &= ~IORESOURCE_UNSET;
+ *flags &= ~IORESOURCE_UNSET;
if (!rule->size) {
*flags |= IORESOURCE_DISABLED;
- return 1; /* skip disabled resource requests */
+ return 1; /* skip disabled resource requests */
}
*start = rule->min;
@@ -66,11 +63,9 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
resource_size_t *start, *end;
unsigned long *flags;
- if (!dev || !rule)
- return -EINVAL;
-
if (idx >= PNP_MAX_MEM) {
- pnp_err("More than 8 mems is incompatible with pnp specifications.");
+ pnp_err
+ ("More than 8 mems is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -85,7 +80,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
/* set the initial values */
*flags |= rule->flags | IORESOURCE_MEM;
- *flags &= ~IORESOURCE_UNSET;
+ *flags &= ~IORESOURCE_UNSET;
/* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
@@ -99,11 +94,11 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
if (!rule->size) {
*flags |= IORESOURCE_DISABLED;
- return 1; /* skip disabled resource requests */
+ return 1; /* skip disabled resource requests */
}
*start = rule->min;
- *end = *start + rule->size -1;
+ *end = *start + rule->size - 1;
/* run through until pnp_check_mem is happy */
while (!pnp_check_mem(dev, idx)) {
@@ -115,7 +110,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
return 1;
}
-static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
+static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
{
resource_size_t *start, *end;
unsigned long *flags;
@@ -126,11 +121,9 @@ 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 (!dev || !rule)
- return -EINVAL;
-
if (idx >= PNP_MAX_IRQ) {
- pnp_err("More than 2 irqs is incompatible with pnp specifications.");
+ pnp_err
+ ("More than 2 irqs is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -145,11 +138,11 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
/* set the initial values */
*flags |= rule->flags | IORESOURCE_IRQ;
- *flags &= ~IORESOURCE_UNSET;
+ *flags &= ~IORESOURCE_UNSET;
if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
*flags |= IORESOURCE_DISABLED;
- return 1; /* skip disabled resource requests */
+ return 1; /* skip disabled resource requests */
}
/* TBD: need check for >16 IRQ */
@@ -159,9 +152,9 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
return 1;
}
for (i = 0; i < 16; i++) {
- if(test_bit(xtab[i], rule->map)) {
+ if (test_bit(xtab[i], rule->map)) {
*start = *end = xtab[i];
- if(pnp_check_irq(dev, idx))
+ if (pnp_check_irq(dev, idx))
return 1;
}
}
@@ -179,11 +172,9 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1, 3, 5, 6, 7, 0, 2, 4
};
- if (!dev || !rule)
- return -EINVAL;
-
if (idx >= PNP_MAX_DMA) {
- pnp_err("More than 2 dmas is incompatible with pnp specifications.");
+ pnp_err
+ ("More than 2 dmas is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -198,17 +189,17 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
/* set the initial values */
*flags |= rule->flags | IORESOURCE_DMA;
- *flags &= ~IORESOURCE_UNSET;
+ *flags &= ~IORESOURCE_UNSET;
if (!rule->map) {
*flags |= IORESOURCE_DISABLED;
- return 1; /* skip disabled resource requests */
+ return 1; /* skip disabled resource requests */
}
for (i = 0; i < 8; i++) {
- if(rule->map & (1<<xtab[i])) {
+ if (rule->map & (1 << xtab[i])) {
*start = *end = xtab[i];
- if(pnp_check_dma(dev, idx))
+ if (pnp_check_dma(dev, idx))
return 1;
}
}
@@ -218,72 +209,80 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
/**
* 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)
{
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;
+ table->irq_resource[idx].flags =
+ IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
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;
+ table->dma_resource[idx].flags =
+ IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
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;
+ table->port_resource[idx].flags =
+ IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
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;
+ table->mem_resource[idx].flags =
+ IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
}
/**
* 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_resource_table *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->irq_resource[idx].flags =
+ IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
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->dma_resource[idx].flags =
+ IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
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->port_resource[idx].flags =
+ IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
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->mem_resource[idx].flags =
+ IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
}
@@ -306,7 +305,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
return -ENODEV;
down(&pnp_res_mutex);
- pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
+ pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
if (dev->independent) {
port = dev->independent->port;
mem = dev->independent->mem;
@@ -341,10 +340,11 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
if (depnum) {
struct pnp_option *dep;
int i;
- for (i=1,dep=dev->dependent; i<depnum; i++, dep=dep->next)
- if(!dep)
+ for (i = 1, dep = dev->dependent; i < depnum;
+ i++, dep = dep->next)
+ if (!dep)
goto fail;
- port =dep->port;
+ port = dep->port;
mem = dep->mem;
irq = dep->irq;
dma = dep->dma;
@@ -392,12 +392,12 @@ fail:
*
* 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 pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
+ int mode)
{
int i;
- struct pnp_resource_table * bak;
- if (!dev || !res)
- return -EINVAL;
+ struct pnp_resource_table *bak;
+
if (!pnp_can_configure(dev))
return -ENODEV;
bak = pnp_alloc(sizeof(struct pnp_resource_table));
@@ -409,19 +409,19 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res,
dev->res = *res;
if (!(mode & PNP_CONFIG_FORCE)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
- if(!pnp_check_port(dev,i))
+ if (!pnp_check_port(dev, i))
goto fail;
}
for (i = 0; i < PNP_MAX_MEM; i++) {
- if(!pnp_check_mem(dev,i))
+ if (!pnp_check_mem(dev, i))
goto fail;
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
- if(!pnp_check_irq(dev,i))
+ if (!pnp_check_irq(dev, i))
goto fail;
}
for (i = 0; i < PNP_MAX_DMA; i++) {
- if(!pnp_check_dma(dev,i))
+ if (!pnp_check_dma(dev, i))
goto fail;
}
}
@@ -440,18 +440,15 @@ fail:
/**
* pnp_auto_config_dev - automatically assigns resources to a device
* @dev: pointer to the desired device
- *
*/
int pnp_auto_config_dev(struct pnp_dev *dev)
{
struct pnp_option *dep;
int i = 1;
- if(!dev)
- return -EINVAL;
-
- if(!pnp_can_configure(dev)) {
- pnp_dbg("Device %s does not support resource configuration.", dev->dev.bus_id);
+ if (!pnp_can_configure(dev)) {
+ pnp_dbg("Device %s does not support resource configuration.",
+ dev->dev.bus_id);
return -ENODEV;
}
@@ -476,23 +473,22 @@ int pnp_auto_config_dev(struct pnp_dev *dev)
* pnp_start_dev - low-level start of the PnP device
* @dev: pointer to the desired device
*
- * assumes that resources have alread been allocated
+ * assumes that resources have already been allocated
*/
-
int pnp_start_dev(struct pnp_dev *dev)
{
if (!pnp_can_write(dev)) {
- pnp_dbg("Device %s does not support activation.", dev->dev.bus_id);
+ pnp_dbg("Device %s does not support activation.",
+ dev->dev.bus_id);
return -EINVAL;
}
- if (dev->protocol->set(dev, &dev->res)<0) {
+ if (dev->protocol->set(dev, &dev->res) < 0) {
pnp_err("Failed to activate device %s.", dev->dev.bus_id);
return -EIO;
}
pnp_info("Device %s activated.", dev->dev.bus_id);
-
return 0;
}
@@ -502,20 +498,19 @@ int pnp_start_dev(struct pnp_dev *dev)
*
* does not free resources
*/
-
int pnp_stop_dev(struct pnp_dev *dev)
{
if (!pnp_can_disable(dev)) {
- pnp_dbg("Device %s does not support disabling.", dev->dev.bus_id);
+ pnp_dbg("Device %s does not support disabling.",
+ dev->dev.bus_id);
return -EINVAL;
}
- if (dev->protocol->disable(dev)<0) {
+ if (dev->protocol->disable(dev) < 0) {
pnp_err("Failed to disable device %s.", dev->dev.bus_id);
return -EIO;
}
pnp_info("Device %s disabled.", dev->dev.bus_id);
-
return 0;
}
@@ -529,11 +524,8 @@ int pnp_activate_dev(struct pnp_dev *dev)
{
int error;
- if (!dev)
- return -EINVAL;
- if (dev->active) {
- return 0; /* the device is already active */
- }
+ if (dev->active)
+ return 0; /* the device is already active */
/* ensure resources are allocated */
if (pnp_auto_config_dev(dev))
@@ -544,7 +536,6 @@ int pnp_activate_dev(struct pnp_dev *dev)
return error;
dev->active = 1;
-
return 1;
}
@@ -558,11 +549,8 @@ int pnp_disable_dev(struct pnp_dev *dev)
{
int error;
- if (!dev)
- return -EINVAL;
- if (!dev->active) {
- return 0; /* the device is already disabled */
- }
+ if (!dev->active)
+ return 0; /* the device is already disabled */
error = pnp_stop_dev(dev);
if (error)
@@ -583,23 +571,16 @@ int pnp_disable_dev(struct pnp_dev *dev)
* @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_size_t size)
{
- if (resource == NULL)
- return;
resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
resource->start = start;
resource->end = start + size - 1;
}
-
EXPORT_SYMBOL(pnp_manual_config_dev);
-#if 0
-EXPORT_SYMBOL(pnp_auto_config_dev);
-#endif
EXPORT_SYMBOL(pnp_start_dev);
EXPORT_SYMBOL(pnp_stop_dev);
EXPORT_SYMBOL(pnp_activate_dev);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index a00548799e98..a5a372222d69 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -21,7 +21,10 @@
#include <linux/acpi.h>
#include <linux/pnp.h>
+#include <linux/mod_devicetable.h>
#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+
#include "pnpacpi.h"
static int num = 0;
@@ -31,17 +34,19 @@ static int num = 0;
* used by the kernel (PCI root, ...), as it is harmless and there were
* already present in pnpbios. But there is an exception for devices that
* have irqs (PIC, Timer) because we call acpi_register_gsi.
- * Finaly only devices that have a CRS method need to be in this list.
+ * Finally, only devices that have a CRS method need to be in this list.
*/
-static char __initdata excluded_id_list[] =
- "PNP0C09," /* EC */
- "PNP0C0F," /* Link device */
- "PNP0000," /* PIC */
- "PNP0100," /* Timer */
- ;
+static struct __initdata acpi_device_id excluded_id_list[] = {
+ {"PNP0C09", 0}, /* EC */
+ {"PNP0C0F", 0}, /* Link device */
+ {"PNP0000", 0}, /* PIC */
+ {"PNP0100", 0}, /* Timer */
+ {"", 0},
+};
+
static inline int is_exclusive_device(struct acpi_device *dev)
{
- return (!acpi_match_ids(dev, excluded_id_list));
+ return (!acpi_match_device_ids(dev, excluded_id_list));
}
/*
@@ -79,15 +84,18 @@ static void __init pnpidacpi_to_pnpid(char *id, char *str)
str[7] = '\0';
}
-static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+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);
+
+ 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,
+ struct pnp_resource_table *res)
{
acpi_handle handle = dev->data;
struct acpi_buffer buffer;
@@ -114,16 +122,36 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
acpi_status status;
/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
- status = acpi_evaluate_object((acpi_handle)dev->data,
- "_DIS", NULL, NULL);
+ status = acpi_evaluate_object((acpi_handle) dev->data,
+ "_DIS", NULL, NULL);
return ACPI_FAILURE(status) ? -ENODEV : 0;
}
+#ifdef CONFIG_ACPI_SLEEP
+static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+ return acpi_bus_set_power((acpi_handle) dev->data,
+ acpi_pm_device_sleep_state(&dev->dev,
+ device_may_wakeup
+ (&dev->dev),
+ NULL));
+}
+
+static int pnpacpi_resume(struct pnp_dev *dev)
+{
+ return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0);
+}
+#endif
+
static struct pnp_protocol pnpacpi_protocol = {
- .name = "Plug and Play ACPI",
- .get = pnpacpi_get_resources,
- .set = pnpacpi_set_resources,
+ .name = "Plug and Play ACPI",
+ .get = pnpacpi_get_resources,
+ .set = pnpacpi_set_resources,
.disable = pnpacpi_disable_resources,
+#ifdef CONFIG_ACPI_SLEEP
+ .suspend = pnpacpi_suspend,
+ .resume = pnpacpi_resume,
+#endif
};
static int __init pnpacpi_add_device(struct acpi_device *device)
@@ -135,17 +163,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
status = acpi_get_handle(device->handle, "_CRS", &temp);
if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
- is_exclusive_device(device))
+ is_exclusive_device(device))
return 0;
pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev) {
pnp_err("Out of memory");
return -ENOMEM;
}
dev->data = device->handle;
- /* .enabled means if the device can decode the resources */
+ /* .enabled means the device can decode the resources */
dev->active = device->status.enabled;
status = acpi_get_handle(device->handle, "_SRS", &temp);
if (ACPI_SUCCESS(status))
@@ -175,20 +203,23 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
pnp_add_id(dev_id, dev);
- if(dev->active) {
+ if (dev->active) {
/* parse allocated resource */
- status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
+ 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);
+ pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s",
+ dev_id->id);
goto err1;
}
}
- if(dev->capabilities & PNP_CONFIGURABLE) {
+ if (dev->capabilities & PNP_CONFIGURABLE) {
status = pnpacpi_parse_resource_option_data(device->handle,
- dev);
+ dev);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
+ pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s",
+ dev_id->id);
goto err1;
}
}
@@ -214,7 +245,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (!dev->active)
pnp_init_resource_table(&dev->res);
pnp_add_device(dev);
- num ++;
+ num++;
return AE_OK;
err1:
@@ -225,7 +256,8 @@ err:
}
static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
- u32 lvl, void *context, void **rv)
+ u32 lvl, void *context,
+ void **rv)
{
struct acpi_device *device;
@@ -238,23 +270,22 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
static int __init acpi_pnp_match(struct device *dev, void *_pnp)
{
- struct acpi_device *acpi = to_acpi_device(dev);
- struct pnp_dev *pnp = _pnp;
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pnp_dev *pnp = _pnp;
/* true means it matched */
return acpi->flags.hardware_id
- && !acpi_get_physical_device(acpi->handle)
- && compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
+ && !acpi_get_physical_device(acpi->handle)
+ && compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
}
-static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle)
+static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle)
{
- struct device *adev;
- struct acpi_device *acpi;
+ struct device *adev;
+ struct acpi_device *acpi;
adev = bus_find_device(&acpi_bus_type, NULL,
- to_pnp_dev(dev),
- acpi_pnp_match);
+ to_pnp_dev(dev), acpi_pnp_match);
if (!adev)
return -ENODEV;
@@ -268,7 +299,7 @@ static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle)
* pnpdev->dev.archdata.acpi_handle point to its ACPI sibling.
*/
static struct acpi_bus_type __initdata acpi_pnp_bus = {
- .bus = &pnp_bus_type,
+ .bus = &pnp_bus_type,
.find_device = acpi_pnp_find_device,
};
@@ -288,6 +319,7 @@ static int __init pnpacpi_init(void)
pnp_platform_devices = 1;
return 0;
}
+
subsys_initcall(pnpacpi_init);
static int __init pnpacpi_setup(char *str)
@@ -298,8 +330,5 @@ static int __init pnpacpi_setup(char *str)
pnpacpi_disabled = 1;
return 1;
}
-__setup("pnpacpi=", pnpacpi_setup);
-#if 0
-EXPORT_SYMBOL(pnpacpi_protocol);
-#endif
+__setup("pnpacpi=", pnpacpi_setup);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 118ac9779b3c..0e3b8d0ff06b 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -34,20 +34,17 @@
*/
static int irq_flags(int triggering, int polarity)
{
- int flag;
if (triggering == ACPI_LEVEL_SENSITIVE) {
if (polarity == ACPI_ACTIVE_LOW)
- flag = IORESOURCE_IRQ_LOWLEVEL;
+ return IORESOURCE_IRQ_LOWLEVEL;
else
- flag = IORESOURCE_IRQ_HIGHLEVEL;
- }
- else {
+ return IORESOURCE_IRQ_HIGHLEVEL;
+ } else {
if (polarity == ACPI_ACTIVE_LOW)
- flag = IORESOURCE_IRQ_LOWEDGE;
+ return IORESOURCE_IRQ_LOWEDGE;
else
- flag = IORESOURCE_IRQ_HIGHEDGE;
+ return IORESOURCE_IRQ_HIGHEDGE;
}
- return flag;
}
static void decode_irq_flags(int flag, int *triggering, int *polarity)
@@ -72,9 +69,9 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity)
}
}
-static void
-pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
- int triggering, int polarity, int shareable)
+static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
+ u32 gsi, int triggering,
+ int polarity, int shareable)
{
int i = 0;
int irq;
@@ -83,12 +80,12 @@ pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
return;
while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_IRQ)
+ i < PNP_MAX_IRQ)
i++;
if (i >= PNP_MAX_IRQ)
return;
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
+ res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
res->irq_resource[i].flags |= irq_flags(triggering, polarity);
irq = acpi_register_gsi(gsi, triggering, polarity);
if (irq < 0) {
@@ -147,17 +144,19 @@ 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_dmaresource(struct pnp_resource_table *res,
+ u32 dma, int type,
+ int bus_master, int transfer)
{
int i = 0;
+
while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
+ !(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);
+ 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;
@@ -167,19 +166,19 @@ pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, u32 dma,
}
}
-static void
-pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
- u64 io, u64 len, int io_decode)
+static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
+ u64 io, u64 len, int io_decode)
{
int i = 0;
+
while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_PORT)
+ i < PNP_MAX_PORT)
i++;
if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
+ 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) {
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
res->port_resource[i].flags |= IORESOURCE_DISABLED;
return;
}
@@ -188,21 +187,22 @@ pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
}
}
-static void
-pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
- u64 mem, u64 len, int write_protect)
+static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
+ u64 mem, u64 len,
+ int write_protect)
{
int i = 0;
+
while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
- (i < PNP_MAX_MEM))
+ (i < PNP_MAX_MEM))
i++;
if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
+ 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)
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
res->mem_resource[i].start = mem;
@@ -210,9 +210,8 @@ pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
}
}
-static void
-pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
- struct acpi_resource *res)
+static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
+ struct acpi_resource *res)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
@@ -220,7 +219,7 @@ pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
status = acpi_resource_to_address64(res, p);
if (!ACPI_SUCCESS(status)) {
pnp_warn("PnPACPI: failed to convert resource type %d",
- res->type);
+ res->type);
return;
}
@@ -229,17 +228,19 @@ pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
if (p->resource_type == ACPI_MEMORY_RANGE)
pnpacpi_parse_allocated_memresource(res_table,
- p->minimum, p->address_length, p->info.mem.write_protect);
+ p->minimum, p->address_length,
+ p->info.mem.write_protect);
else if (p->resource_type == ACPI_IO_RANGE)
pnpacpi_parse_allocated_ioresource(res_table,
- p->minimum, p->address_length,
- p->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16);
+ p->minimum, p->address_length,
+ p->granularity == 0xfff ? ACPI_DECODE_10 :
+ ACPI_DECODE_16);
}
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
- void *data)
+ void *data)
{
- struct pnp_resource_table *res_table = (struct pnp_resource_table *)data;
+ struct pnp_resource_table *res_table = data;
int i;
switch (res->type) {
@@ -260,17 +261,17 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
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);
+ res->data.dma.channels[0],
+ res->data.dma.type,
+ res->data.dma.bus_master,
+ res->data.dma.transfer);
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);
+ res->data.io.minimum,
+ res->data.io.address_length,
+ res->data.io.io_decode);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -279,9 +280,9 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_FIXED_IO:
pnpacpi_parse_allocated_ioresource(res_table,
- res->data.fixed_io.address,
- res->data.fixed_io.address_length,
- ACPI_DECODE_10);
+ res->data.fixed_io.address,
+ res->data.fixed_io.address_length,
+ ACPI_DECODE_10);
break;
case ACPI_RESOURCE_TYPE_VENDOR:
@@ -292,21 +293,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
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);
+ res->data.memory24.minimum,
+ res->data.memory24.address_length,
+ res->data.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);
+ res->data.memory32.minimum,
+ res->data.memory32.address_length,
+ res->data.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);
+ res->data.fixed_memory32.address,
+ res->data.fixed_memory32.address_length,
+ res->data.fixed_memory32.write_protect);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
@@ -343,18 +344,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
return AE_OK;
}
-acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table *res)
+acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
+ struct pnp_resource_table * res)
{
/* Blank the resource table values */
pnp_init_resource_table(res);
- return acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_allocated_resource, res);
+ return acpi_walk_resources(handle, METHOD_NAME__CRS,
+ pnpacpi_allocated_resource, res);
}
-static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_resource_dma *p)
+static void pnpacpi_parse_dma_option(struct pnp_option *option,
+ struct acpi_resource_dma *p)
{
int i;
- struct pnp_dma * dma;
+ struct pnp_dma *dma;
if (p->channel_count == 0)
return;
@@ -362,18 +366,16 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_reso
if (!dma)
return;
- for(i = 0; i < p->channel_count; i++)
+ for (i = 0; i < p->channel_count; i++)
dma->map |= 1 << p->channels[i];
dma->flags = dma_flags(p->type, p->bus_master, p->transfer);
pnp_register_dma_resource(option, dma);
- return;
}
-
static void pnpacpi_parse_irq_option(struct pnp_option *option,
- struct acpi_resource_irq *p)
+ struct acpi_resource_irq *p)
{
int i;
struct pnp_irq *irq;
@@ -384,17 +386,16 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
if (!irq)
return;
- for(i = 0; i < p->interrupt_count; i++)
+ 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);
pnp_register_irq_resource(option, irq);
- return;
}
static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
- struct acpi_resource_extended_irq *p)
+ struct acpi_resource_extended_irq *p)
{
int i;
struct pnp_irq *irq;
@@ -405,18 +406,16 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
if (!irq)
return;
- for(i = 0; i < p->interrupt_count; i++)
+ 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);
pnp_register_irq_resource(option, irq);
- return;
}
-static void
-pnpacpi_parse_port_option(struct pnp_option *option,
- struct acpi_resource_io *io)
+static void pnpacpi_parse_port_option(struct pnp_option *option,
+ struct acpi_resource_io *io)
{
struct pnp_port *port;
@@ -430,14 +429,12 @@ pnpacpi_parse_port_option(struct pnp_option *option,
port->align = io->alignment;
port->size = io->address_length;
port->flags = ACPI_DECODE_16 == io->io_decode ?
- PNP_PORT_FLAG_16BITADDR : 0;
+ PNP_PORT_FLAG_16BITADDR : 0;
pnp_register_port_resource(option, port);
- return;
}
-static void
-pnpacpi_parse_fixed_port_option(struct pnp_option *option,
- struct acpi_resource_fixed_io *io)
+static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+ struct acpi_resource_fixed_io *io)
{
struct pnp_port *port;
@@ -451,12 +448,10 @@ pnpacpi_parse_fixed_port_option(struct pnp_option *option,
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
pnp_register_port_resource(option, port);
- return;
}
-static void
-pnpacpi_parse_mem24_option(struct pnp_option *option,
- struct acpi_resource_memory24 *p)
+static void pnpacpi_parse_mem24_option(struct pnp_option *option,
+ struct acpi_resource_memory24 *p)
{
struct pnp_mem *mem;
@@ -471,15 +466,13 @@ pnpacpi_parse_mem24_option(struct pnp_option *option,
mem->size = p->address_length;
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
- IORESOURCE_MEM_WRITEABLE : 0;
+ IORESOURCE_MEM_WRITEABLE : 0;
pnp_register_mem_resource(option, mem);
- return;
}
-static void
-pnpacpi_parse_mem32_option(struct pnp_option *option,
- struct acpi_resource_memory32 *p)
+static void pnpacpi_parse_mem32_option(struct pnp_option *option,
+ struct acpi_resource_memory32 *p)
{
struct pnp_mem *mem;
@@ -494,15 +487,13 @@ pnpacpi_parse_mem32_option(struct pnp_option *option,
mem->size = p->address_length;
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
- IORESOURCE_MEM_WRITEABLE : 0;
+ IORESOURCE_MEM_WRITEABLE : 0;
pnp_register_mem_resource(option, mem);
- return;
}
-static void
-pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
- struct acpi_resource_fixed_memory32 *p)
+static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+ struct acpi_resource_fixed_memory32 *p)
{
struct pnp_mem *mem;
@@ -516,14 +507,13 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
mem->align = 0;
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
- IORESOURCE_MEM_WRITEABLE : 0;
+ IORESOURCE_MEM_WRITEABLE : 0;
pnp_register_mem_resource(option, mem);
- return;
}
-static void
-pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
+static void pnpacpi_parse_address_option(struct pnp_option *option,
+ struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
@@ -532,7 +522,8 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
status = acpi_resource_to_address64(r, p);
if (!ACPI_SUCCESS(status)) {
- pnp_warn("PnPACPI: failed to convert resource type %d", r->type);
+ pnp_warn("PnPACPI: failed to convert resource type %d",
+ r->type);
return;
}
@@ -547,7 +538,8 @@ pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
mem->size = p->address_length;
mem->align = 0;
mem->flags = (p->info.mem.write_protect ==
- ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE : 0;
+ ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE
+ : 0;
pnp_register_mem_resource(option, mem);
} else if (p->resource_type == ACPI_IO_RANGE) {
port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
@@ -568,109 +560,107 @@ struct acpipnp_parse_option_s {
};
static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
- void *data)
+ void *data)
{
int priority = 0;
- struct acpipnp_parse_option_s *parse_data = (struct acpipnp_parse_option_s *)data;
+ struct acpipnp_parse_option_s *parse_data = data;
struct pnp_dev *dev = parse_data->dev;
struct pnp_option *option = parse_data->option;
switch (res->type) {
- case ACPI_RESOURCE_TYPE_IRQ:
- pnpacpi_parse_irq_option(option, &res->data.irq);
- break;
+ case ACPI_RESOURCE_TYPE_IRQ:
+ pnpacpi_parse_irq_option(option, &res->data.irq);
+ break;
- case ACPI_RESOURCE_TYPE_DMA:
- pnpacpi_parse_dma_option(option, &res->data.dma);
- break;
+ case ACPI_RESOURCE_TYPE_DMA:
+ pnpacpi_parse_dma_option(option, &res->data.dma);
+ break;
- case ACPI_RESOURCE_TYPE_START_DEPENDENT:
- switch (res->data.start_dpf.compatibility_priority) {
- case ACPI_GOOD_CONFIGURATION:
- priority = PNP_RES_PRIORITY_PREFERRED;
- break;
-
- case ACPI_ACCEPTABLE_CONFIGURATION:
- priority = PNP_RES_PRIORITY_ACCEPTABLE;
- break;
-
- case ACPI_SUB_OPTIMAL_CONFIGURATION:
- priority = PNP_RES_PRIORITY_FUNCTIONAL;
- break;
- default:
- priority = PNP_RES_PRIORITY_INVALID;
- break;
- }
- /* TBD: Considering performace/robustness bits */
- option = pnp_register_dependent_option(dev, priority);
- if (!option)
- return AE_ERROR;
- parse_data->option = option;
+ case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+ switch (res->data.start_dpf.compatibility_priority) {
+ case ACPI_GOOD_CONFIGURATION:
+ priority = PNP_RES_PRIORITY_PREFERRED;
break;
- case ACPI_RESOURCE_TYPE_END_DEPENDENT:
- /*only one EndDependentFn is allowed*/
- if (!parse_data->option_independent) {
- pnp_warn("PnPACPI: more than one EndDependentFn");
- return AE_ERROR;
- }
- parse_data->option = parse_data->option_independent;
- parse_data->option_independent = NULL;
+ case ACPI_ACCEPTABLE_CONFIGURATION:
+ priority = PNP_RES_PRIORITY_ACCEPTABLE;
break;
- case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_port_option(option, &res->data.io);
+ case ACPI_SUB_OPTIMAL_CONFIGURATION:
+ priority = PNP_RES_PRIORITY_FUNCTIONAL;
break;
-
- case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_fixed_port_option(option,
- &res->data.fixed_io);
+ default:
+ priority = PNP_RES_PRIORITY_INVALID;
break;
+ }
+ /* TBD: Consider performance/robustness bits */
+ option = pnp_register_dependent_option(dev, priority);
+ if (!option)
+ return AE_ERROR;
+ parse_data->option = option;
+ break;
- case ACPI_RESOURCE_TYPE_VENDOR:
- case ACPI_RESOURCE_TYPE_END_TAG:
- break;
+ case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+ /*only one EndDependentFn is allowed */
+ if (!parse_data->option_independent) {
+ pnp_warn("PnPACPI: more than one EndDependentFn");
+ return AE_ERROR;
+ }
+ parse_data->option = parse_data->option_independent;
+ parse_data->option_independent = NULL;
+ break;
- case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_mem24_option(option, &res->data.memory24);
- break;
+ case ACPI_RESOURCE_TYPE_IO:
+ pnpacpi_parse_port_option(option, &res->data.io);
+ break;
- case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_mem32_option(option, &res->data.memory32);
- break;
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ pnpacpi_parse_fixed_port_option(option, &res->data.fixed_io);
+ break;
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_fixed_mem32_option(option,
- &res->data.fixed_memory32);
- break;
+ case ACPI_RESOURCE_TYPE_VENDOR:
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ break;
- case ACPI_RESOURCE_TYPE_ADDRESS16:
- case ACPI_RESOURCE_TYPE_ADDRESS32:
- case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_address_option(option, res);
- break;
+ case ACPI_RESOURCE_TYPE_MEMORY24:
+ pnpacpi_parse_mem24_option(option, &res->data.memory24);
+ break;
- case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
- break;
+ case ACPI_RESOURCE_TYPE_MEMORY32:
+ pnpacpi_parse_mem32_option(option, &res->data.memory32);
+ break;
- case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnpacpi_parse_ext_irq_option(option,
- &res->data.extended_irq);
- break;
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ pnpacpi_parse_fixed_mem32_option(option,
+ &res->data.fixed_memory32);
+ break;
- case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
- break;
+ case ACPI_RESOURCE_TYPE_ADDRESS16:
+ case ACPI_RESOURCE_TYPE_ADDRESS32:
+ case ACPI_RESOURCE_TYPE_ADDRESS64:
+ pnpacpi_parse_address_option(option, res);
+ break;
- default:
- pnp_warn("PnPACPI: unknown resource type %d", res->type);
- return AE_ERROR;
+ case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+ break;
+
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ pnpacpi_parse_ext_irq_option(option, &res->data.extended_irq);
+ break;
+
+ case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
+ break;
+
+ default:
+ pnp_warn("PnPACPI: unknown resource type %d", res->type);
+ return AE_ERROR;
}
return AE_OK;
}
acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
- struct pnp_dev *dev)
+ struct pnp_dev * dev)
{
acpi_status status;
struct acpipnp_parse_option_s parse_data;
@@ -681,7 +671,7 @@ acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
parse_data.option_independent = parse_data.option;
parse_data.dev = dev;
status = acpi_walk_resources(handle, METHOD_NAME__PRS,
- pnpacpi_option_resource, &parse_data);
+ pnpacpi_option_resource, &parse_data);
return status;
}
@@ -709,9 +699,9 @@ static int pnpacpi_supported_resource(struct acpi_resource *res)
* Set resource
*/
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
- void *data)
+ void *data)
{
- int *res_cnt = (int *)data;
+ int *res_cnt = data;
if (pnpacpi_supported_resource(res))
(*res_cnt)++;
@@ -720,7 +710,7 @@ static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
{
- struct acpi_resource **resource = (struct acpi_resource **)data;
+ struct acpi_resource **resource = data;
if (pnpacpi_supported_resource(res)) {
(*resource)->type = res->type;
@@ -732,14 +722,14 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
}
int pnpacpi_build_resource_template(acpi_handle handle,
- struct acpi_buffer *buffer)
+ struct acpi_buffer *buffer)
{
struct acpi_resource *resource;
int res_cnt = 0;
acpi_status status;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- pnpacpi_count_resources, &res_cnt);
+ pnpacpi_count_resources, &res_cnt);
if (ACPI_FAILURE(status)) {
pnp_err("Evaluate _CRS failed");
return -EINVAL;
@@ -753,7 +743,7 @@ int pnpacpi_build_resource_template(acpi_handle handle,
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);
+ pnpacpi_type_resources, &resource);
if (ACPI_FAILURE(status)) {
kfree(buffer->pointer);
pnp_err("Evaluate _CRS failed");
@@ -766,7 +756,7 @@ int pnpacpi_build_resource_template(acpi_handle handle,
}
static void pnpacpi_encode_irq(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
int triggering, polarity;
@@ -782,7 +772,7 @@ static void pnpacpi_encode_irq(struct acpi_resource *resource,
}
static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
int triggering, polarity;
@@ -799,32 +789,32 @@ static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
}
static void pnpacpi_encode_dma(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
/* 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;
- break;
- case IORESOURCE_DMA_TYPEB:
- resource->data.dma.type = ACPI_TYPE_B;
- break;
- case IORESOURCE_DMA_TYPEF:
- resource->data.dma.type = ACPI_TYPE_F;
- break;
- default:
- resource->data.dma.type = ACPI_COMPATIBILITY;
+ case IORESOURCE_DMA_TYPEA:
+ resource->data.dma.type = ACPI_TYPE_A;
+ break;
+ case IORESOURCE_DMA_TYPEB:
+ resource->data.dma.type = ACPI_TYPE_B;
+ break;
+ case IORESOURCE_DMA_TYPEF:
+ resource->data.dma.type = ACPI_TYPE_F;
+ break;
+ default:
+ resource->data.dma.type = ACPI_COMPATIBILITY;
}
switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
- case IORESOURCE_DMA_8BIT:
- resource->data.dma.transfer = ACPI_TRANSFER_8;
- break;
- case IORESOURCE_DMA_8AND16BIT:
- resource->data.dma.transfer = ACPI_TRANSFER_8_16;
- break;
- default:
- resource->data.dma.transfer = ACPI_TRANSFER_16;
+ case IORESOURCE_DMA_8BIT:
+ resource->data.dma.transfer = ACPI_TRANSFER_8;
+ break;
+ case IORESOURCE_DMA_8AND16BIT:
+ resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+ break;
+ default:
+ resource->data.dma.transfer = ACPI_TRANSFER_16;
}
resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
@@ -833,31 +823,31 @@ static void pnpacpi_encode_dma(struct acpi_resource *resource,
}
static void pnpacpi_encode_io(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
- resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
- ACPI_DECODE_16 : ACPI_DECODE_10;
+ resource->data.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.alignment = 0; /* Correct? */
resource->data.io.address_length = p->end - p->start + 1;
}
static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
resource->data.fixed_io.address = p->start;
resource->data.fixed_io.address_length = p->end - p->start + 1;
}
static void pnpacpi_encode_mem24(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
/* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
resource->data.memory24.write_protect =
- (p->flags & IORESOURCE_MEM_WRITEABLE) ?
- ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+ (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;
@@ -865,11 +855,11 @@ static void pnpacpi_encode_mem24(struct acpi_resource *resource,
}
static void pnpacpi_encode_mem32(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
resource->data.memory32.write_protect =
- (p->flags & IORESOURCE_MEM_WRITEABLE) ?
- ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+ (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;
@@ -877,74 +867,76 @@ static void pnpacpi_encode_mem32(struct acpi_resource *resource,
}
static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
- struct resource *p)
+ struct resource *p)
{
resource->data.fixed_memory32.write_protect =
- (p->flags & IORESOURCE_MEM_WRITEABLE) ?
- ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+ (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;
}
int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
- struct acpi_buffer *buffer)
+ struct acpi_buffer *buffer)
{
int i = 0;
/* pnpacpi_build_resource_template allocates extra mem */
- int res_cnt = (buffer->length - 1)/sizeof(struct acpi_resource) - 1;
- struct acpi_resource *resource = (struct acpi_resource*)buffer->pointer;
+ int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
+ struct acpi_resource *resource = buffer->pointer;
int port = 0, irq = 0, dma = 0, mem = 0;
pnp_dbg("res cnt %d", res_cnt);
while (i < res_cnt) {
- switch(resource->type) {
+ switch (resource->type) {
case ACPI_RESOURCE_TYPE_IRQ:
pnp_dbg("Encode irq");
pnpacpi_encode_irq(resource,
- &res_table->irq_resource[irq]);
+ &res_table->irq_resource[irq]);
irq++;
break;
case ACPI_RESOURCE_TYPE_DMA:
pnp_dbg("Encode dma");
pnpacpi_encode_dma(resource,
- &res_table->dma_resource[dma]);
+ &res_table->dma_resource[dma]);
dma++;
break;
case ACPI_RESOURCE_TYPE_IO:
pnp_dbg("Encode io");
pnpacpi_encode_io(resource,
- &res_table->port_resource[port]);
+ &res_table->port_resource[port]);
port++;
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
pnp_dbg("Encode fixed io");
pnpacpi_encode_fixed_io(resource,
- &res_table->port_resource[port]);
+ &res_table->
+ port_resource[port]);
port++;
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
pnp_dbg("Encode mem24");
pnpacpi_encode_mem24(resource,
- &res_table->mem_resource[mem]);
+ &res_table->mem_resource[mem]);
mem++;
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
pnp_dbg("Encode mem32");
pnpacpi_encode_mem32(resource,
- &res_table->mem_resource[mem]);
+ &res_table->mem_resource[mem]);
mem++;
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
pnp_dbg("Encode fixed mem32");
pnpacpi_encode_fixed_mem32(resource,
- &res_table->mem_resource[mem]);
+ &res_table->
+ mem_resource[mem]);
mem++;
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
pnp_dbg("Encode ext irq");
pnpacpi_encode_ext_irq(resource,
- &res_table->irq_resource[irq]);
+ &res_table->irq_resource[irq]);
irq++;
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -956,7 +948,7 @@ int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
case ACPI_RESOURCE_TYPE_ADDRESS64:
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
- default: /* other type */
+ default: /* other type */
pnp_warn("unknown resource type %d", resource->type);
return -EINVAL;
}
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index a1f0b0ba2bfe..5dba68fe33f5 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -1,6 +1,5 @@
/*
* bioscalls.c - the lowlevel layer of the PnPBIOS driver
- *
*/
#include <linux/types.h>
@@ -26,11 +25,10 @@
#include "pnpbios.h"
static struct {
- u16 offset;
- u16 segment;
+ u16 offset;
+ u16 segment;
} pnp_bios_callpoint;
-
/*
* These are some opcodes for a "static asmlinkage"
* As this code is *not* executed inside the linux kernel segment, but in a
@@ -44,8 +42,7 @@ static struct {
asmlinkage void pnp_bios_callfunc(void);
-__asm__(
- ".text \n"
+__asm__(".text \n"
__ALIGN_STR "\n"
"pnp_bios_callfunc:\n"
" pushl %edx \n"
@@ -55,8 +52,7 @@ __asm__(
" lcallw *pnp_bios_callpoint\n"
" addl $16, %esp \n"
" lret \n"
- ".previous \n"
-);
+ ".previous \n");
#define Q2_SET_SEL(cpu, selname, address, size) \
do { \
@@ -78,7 +74,6 @@ u32 pnp_bios_is_utter_crap = 0;
static spinlock_t pnp_bios_lock;
-
/*
* Support Functions
*/
@@ -97,7 +92,7 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
* PnP BIOSes are generally not terribly re-entrant.
* Also, don't rely on them to save everything correctly.
*/
- if(pnp_bios_is_utter_crap)
+ if (pnp_bios_is_utter_crap)
return PNP_FUNCTION_NOT_SUPPORTED;
cpu = get_cpu();
@@ -113,112 +108,128 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
if (ts2_size)
Q2_SET_SEL(smp_processor_id(), PNP_TS2, ts2_base, ts2_size);
- __asm__ __volatile__(
- "pushl %%ebp\n\t"
- "pushl %%edi\n\t"
- "pushl %%esi\n\t"
- "pushl %%ds\n\t"
- "pushl %%es\n\t"
- "pushl %%fs\n\t"
- "pushl %%gs\n\t"
- "pushfl\n\t"
- "movl %%esp, pnp_bios_fault_esp\n\t"
- "movl $1f, pnp_bios_fault_eip\n\t"
- "lcall %5,%6\n\t"
- "1:popfl\n\t"
- "popl %%gs\n\t"
- "popl %%fs\n\t"
- "popl %%es\n\t"
- "popl %%ds\n\t"
- "popl %%esi\n\t"
- "popl %%edi\n\t"
- "popl %%ebp\n\t"
- : "=a" (status)
- : "0" ((func) | (((u32)arg1) << 16)),
- "b" ((arg2) | (((u32)arg3) << 16)),
- "c" ((arg4) | (((u32)arg5) << 16)),
- "d" ((arg6) | (((u32)arg7) << 16)),
- "i" (PNP_CS32),
- "i" (0)
- : "memory"
- );
+ __asm__ __volatile__("pushl %%ebp\n\t"
+ "pushl %%edi\n\t"
+ "pushl %%esi\n\t"
+ "pushl %%ds\n\t"
+ "pushl %%es\n\t"
+ "pushl %%fs\n\t"
+ "pushl %%gs\n\t"
+ "pushfl\n\t"
+ "movl %%esp, pnp_bios_fault_esp\n\t"
+ "movl $1f, pnp_bios_fault_eip\n\t"
+ "lcall %5,%6\n\t"
+ "1:popfl\n\t"
+ "popl %%gs\n\t"
+ "popl %%fs\n\t"
+ "popl %%es\n\t"
+ "popl %%ds\n\t"
+ "popl %%esi\n\t"
+ "popl %%edi\n\t"
+ "popl %%ebp\n\t":"=a"(status)
+ :"0"((func) | (((u32) arg1) << 16)),
+ "b"((arg2) | (((u32) arg3) << 16)),
+ "c"((arg4) | (((u32) arg5) << 16)),
+ "d"((arg6) | (((u32) arg7) << 16)),
+ "i"(PNP_CS32), "i"(0)
+ :"memory");
spin_unlock_irqrestore(&pnp_bios_lock, flags);
get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40;
put_cpu();
/* If we get here and this is set then the PnP BIOS faulted on us. */
- if(pnp_bios_is_utter_crap)
- {
- printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
- printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
- printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
+ if (pnp_bios_is_utter_crap) {
+ printk(KERN_ERR
+ "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
+ printk(KERN_ERR
+ "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
+ printk(KERN_ERR
+ "PnPBIOS: Check with your vendor for an updated BIOS\n");
}
return status;
}
-void pnpbios_print_status(const char * module, u16 status)
+void pnpbios_print_status(const char *module, u16 status)
{
- switch(status) {
+ switch (status) {
case PNP_SUCCESS:
printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
break;
case PNP_NOT_SET_STATICALLY:
- printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n",
+ module);
break;
case PNP_UNKNOWN_FUNCTION:
- printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n",
+ module);
break;
case PNP_FUNCTION_NOT_SUPPORTED:
- printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
+ printk(KERN_ERR
+ "PnPBIOS: %s: function not supported on this system\n",
+ module);
break;
case PNP_INVALID_HANDLE:
printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
break;
case PNP_BAD_PARAMETER:
- printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n",
+ module);
break;
case PNP_SET_FAILED:
- printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n",
+ module);
break;
case PNP_EVENTS_NOT_PENDING:
printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
break;
case PNP_SYSTEM_NOT_DOCKED:
- printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n",
+ module);
break;
case PNP_NO_ISA_PNP_CARDS:
- printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
+ printk(KERN_ERR
+ "PnPBIOS: %s: no isapnp cards are installed on this system\n",
+ module);
break;
case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
- printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
+ printk(KERN_ERR
+ "PnPBIOS: %s: cannot determine the capabilities of the docking station\n",
+ module);
break;
case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
- printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
+ printk(KERN_ERR
+ "PnPBIOS: %s: unable to undock, the system does not have a battery\n",
+ module);
break;
case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
- printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
+ printk(KERN_ERR
+ "PnPBIOS: %s: could not dock due to resource conflicts\n",
+ module);
break;
case PNP_BUFFER_TOO_SMALL:
- printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n",
+ module);
break;
case PNP_USE_ESCD_SUPPORT:
printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
break;
case PNP_MESSAGE_NOT_SUPPORTED:
- printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n",
+ module);
break;
case PNP_HARDWARE_ERROR:
- printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
+ printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n",
+ module);
break;
default:
- printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
+ printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module,
+ status);
break;
}
}
-
/*
* PnP BIOS Low Level Calls
*/
@@ -243,19 +254,22 @@ void pnpbios_print_status(const char * module, u16 status)
static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
u16 status;
+
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0,
- data, sizeof(struct pnp_dev_node_info), NULL, 0);
+ status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2,
+ PNP_TS1, PNP_DS, 0, 0, data,
+ sizeof(struct pnp_dev_node_info), NULL, 0);
data->no_nodes &= 0xff;
return status;
}
int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
- int status = __pnp_bios_dev_node_info( data );
- if ( status )
- pnpbios_print_status( "dev_node_info", status );
+ int status = __pnp_bios_dev_node_info(data);
+
+ if (status)
+ pnpbios_print_status("dev_node_info", status);
return status;
}
@@ -273,17 +287,20 @@ int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
* or volatile current (0) config
* Output: *nodenum=next node or 0xff if no more nodes
*/
-static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+static int __pnp_bios_get_dev_node(u8 *nodenum, char boot,
+ struct pnp_bios_node *data)
{
u16 status;
u16 tmp_nodenum;
+
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- if ( !boot && pnpbios_dont_use_current_config )
+ if (!boot && pnpbios_dont_use_current_config)
return PNP_FUNCTION_NOT_SUPPORTED;
tmp_nodenum = *nodenum;
- status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
- &tmp_nodenum, sizeof(tmp_nodenum), data, 65536);
+ status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2,
+ boot ? 2 : 1, PNP_DS, 0, &tmp_nodenum,
+ sizeof(tmp_nodenum), data, 65536);
*nodenum = tmp_nodenum;
return status;
}
@@ -291,104 +308,66 @@ static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node
int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
int status;
- status = __pnp_bios_get_dev_node( nodenum, boot, data );
- if ( status )
- pnpbios_print_status( "get_dev_node", status );
+
+ status = __pnp_bios_get_dev_node(nodenum, boot, data);
+ if (status)
+ pnpbios_print_status("get_dev_node", status);
return status;
}
-
/*
* Call PnP BIOS with function 0x02, "set system device node"
* Input: *nodenum = desired node,
* boot = whether to set nonvolatile boot (!=0)
* or volatile current (0) config
*/
-static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+static int __pnp_bios_set_dev_node(u8 nodenum, char boot,
+ struct pnp_bios_node *data)
{
u16 status;
+
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- if ( !boot && pnpbios_dont_use_current_config )
+ if (!boot && pnpbios_dont_use_current_config)
return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
- data, 65536, NULL, 0);
+ status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1,
+ boot ? 2 : 1, PNP_DS, 0, 0, data, 65536, NULL,
+ 0);
return status;
}
int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
int status;
- status = __pnp_bios_set_dev_node( nodenum, boot, data );
- if ( status ) {
- pnpbios_print_status( "set_dev_node", status );
+
+ status = __pnp_bios_set_dev_node(nodenum, boot, data);
+ if (status) {
+ pnpbios_print_status("set_dev_node", status);
return status;
}
- if ( !boot ) { /* Update devlist */
- status = pnp_bios_get_dev_node( &nodenum, boot, data );
- if ( status )
+ if (!boot) { /* Update devlist */
+ status = pnp_bios_get_dev_node(&nodenum, boot, data);
+ if (status)
return status;
}
return status;
}
-#if needed
-/*
- * Call PnP BIOS with function 0x03, "get event"
- */
-static int pnp_bios_get_event(u16 *event)
-{
- u16 status;
- if (!pnp_bios_present())
- return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0,
- event, sizeof(u16), NULL, 0);
- return status;
-}
-#endif
-
-#if needed
-/*
- * Call PnP BIOS with function 0x04, "send message"
- */
-static int pnp_bios_send_message(u16 message)
-{
- u16 status;
- if (!pnp_bios_present())
- return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- return status;
-}
-#endif
-
/*
* Call PnP BIOS with function 0x05, "get docking station information"
*/
int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
{
u16 status;
- if (!pnp_bios_present())
- return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
- data, sizeof(struct pnp_docking_station_info), NULL, 0);
- return status;
-}
-#if needed
-/*
- * Call PnP BIOS with function 0x09, "set statically allocated resource
- * information"
- */
-static int pnp_bios_set_stat_res(char *info)
-{
- u16 status;
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
- info, *((u16 *) info), 0, 0);
+ status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1,
+ PNP_DS, 0, 0, 0, 0, data,
+ sizeof(struct pnp_docking_station_info), NULL,
+ 0);
return status;
}
-#endif
/*
* Call PnP BIOS with function 0x0a, "get statically allocated resource
@@ -397,36 +376,23 @@ static int pnp_bios_set_stat_res(char *info)
static int __pnp_bios_get_stat_res(char *info)
{
u16 status;
+
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
- info, 65536, NULL, 0);
+ status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1,
+ PNP_DS, 0, 0, 0, 0, info, 65536, NULL, 0);
return status;
}
int pnp_bios_get_stat_res(char *info)
{
int status;
- status = __pnp_bios_get_stat_res( info );
- if ( status )
- pnpbios_print_status( "get_stat_res", status );
- return status;
-}
-#if needed
-/*
- * Call PnP BIOS with function 0x0b, "get APM id table"
- */
-static int pnp_bios_apm_id_table(char *table, u16 *size)
-{
- u16 status;
- if (!pnp_bios_present())
- return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0,
- table, *size, size, sizeof(u16));
+ status = __pnp_bios_get_stat_res(info);
+ if (status)
+ pnpbios_print_status("get_stat_res", status);
return status;
}
-#endif
/*
* Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
@@ -434,19 +400,22 @@ static int pnp_bios_apm_id_table(char *table, u16 *size)
static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
u16 status;
+
if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
- data, sizeof(struct pnp_isa_config_struc), NULL, 0);
+ status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS,
+ 0, 0, 0, 0, data,
+ sizeof(struct pnp_isa_config_struc), NULL, 0);
return status;
}
int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
int status;
- status = __pnp_bios_isapnp_config( data );
- if ( status )
- pnpbios_print_status( "isapnp_config", status );
+
+ status = __pnp_bios_isapnp_config(data);
+ if (status)
+ pnpbios_print_status("isapnp_config", status);
return status;
}
@@ -456,19 +425,22 @@ int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
static int __pnp_bios_escd_info(struct escd_info_struc *data)
{
u16 status;
+
if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS,
- data, sizeof(struct escd_info_struc), NULL, 0);
+ status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4,
+ PNP_TS1, PNP_DS, data,
+ sizeof(struct escd_info_struc), NULL, 0);
return status;
}
int pnp_bios_escd_info(struct escd_info_struc *data)
{
int status;
- status = __pnp_bios_escd_info( data );
- if ( status )
- pnpbios_print_status( "escd_info", status );
+
+ status = __pnp_bios_escd_info(data);
+ if (status)
+ pnpbios_print_status("escd_info", status);
return status;
}
@@ -479,57 +451,42 @@ int pnp_bios_escd_info(struct escd_info_struc *data)
static int __pnp_bios_read_escd(char *data, u32 nvram_base)
{
u16 status;
+
if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
- data, 65536, __va(nvram_base), 65536);
+ status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0,
+ 0, data, 65536, __va(nvram_base), 65536);
return status;
}
int pnp_bios_read_escd(char *data, u32 nvram_base)
{
int status;
- status = __pnp_bios_read_escd( data, nvram_base );
- if ( status )
- pnpbios_print_status( "read_escd", status );
- return status;
-}
-#if needed
-/*
- * Call PnP BIOS function 0x43, "write ESCD"
- */
-static int pnp_bios_write_escd(char *data, u32 nvram_base)
-{
- u16 status;
- if (!pnp_bios_present())
- return ESCD_FUNCTION_NOT_SUPPORTED;
- status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
- data, 65536, __va(nvram_base), 65536);
+ status = __pnp_bios_read_escd(data, nvram_base);
+ if (status)
+ pnpbios_print_status("read_escd", status);
return status;
}
-#endif
-
-
-/*
- * Initialization
- */
void pnpbios_calls_init(union pnp_bios_install_struct *header)
{
int i;
+
spin_lock_init(&pnp_bios_lock);
pnp_bios_callpoint.offset = header->fields.pm16offset;
pnp_bios_callpoint.segment = PNP_CS16;
set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
- for (i = 0; i < NR_CPUS; i++) {
- struct desc_struct *gdt = get_cpu_gdt_table(i);
- if (!gdt)
- continue;
- set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc);
- set_base(gdt[GDT_ENTRY_PNPBIOS_CS16], __va(header->fields.pm16cseg));
- set_base(gdt[GDT_ENTRY_PNPBIOS_DS], __va(header->fields.pm16dseg));
- }
+ for (i = 0; i < NR_CPUS; i++) {
+ struct desc_struct *gdt = get_cpu_gdt_table(i);
+ if (!gdt)
+ continue;
+ set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc);
+ set_base(gdt[GDT_ENTRY_PNPBIOS_CS16],
+ __va(header->fields.pm16cseg));
+ set_base(gdt[GDT_ENTRY_PNPBIOS_DS],
+ __va(header->fields.pm16dseg));
+ }
}
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 03baf1c64a2e..4e9fd37cff35 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -32,7 +32,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
+
/* Change Log
*
* Adam Belay - <ambx1@neo.rr.com> - March 16, 2003
@@ -71,14 +71,13 @@
#include "pnpbios.h"
-
/*
*
* PnP BIOS INTERFACE
*
*/
-static union pnp_bios_install_struct * pnp_bios_install = NULL;
+static union pnp_bios_install_struct *pnp_bios_install = NULL;
int pnp_bios_present(void)
{
@@ -101,36 +100,35 @@ static struct completion unload_sem;
/*
* (Much of this belongs in a shared routine somewhere)
*/
-
static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
{
- char *argv [3], **envp, *buf, *scratch;
+ char *argv[3], **envp, *buf, *scratch;
int i = 0, value;
- if (!current->fs->root) {
+ if (!current->fs->root)
return -EAGAIN;
- }
- if (!(envp = kcalloc(20, sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = kcalloc(20, sizeof(char *), GFP_KERNEL)))
return -ENOMEM;
- }
if (!(buf = kzalloc(256, GFP_KERNEL))) {
- kfree (envp);
+ kfree(envp);
return -ENOMEM;
}
- /* FIXME: if there are actual users of this, it should be integrated into
- * the driver core and use the usual infrastructure like sysfs and uevents */
- argv [0] = "/sbin/pnpbios";
- argv [1] = "dock";
- argv [2] = NULL;
+ /* FIXME: if there are actual users of this, it should be
+ * integrated into the driver core and use the usual infrastructure
+ * like sysfs and uevents
+ */
+ argv[0] = "/sbin/pnpbios";
+ argv[1] = "dock";
+ argv[2] = NULL;
/* minimal command environment */
- envp [i++] = "HOME=/";
- envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
#ifdef DEBUG
/* hint that policy agent should enter no-stdout debug mode */
- envp [i++] = "DEBUG=kernel";
+ envp[i++] = "DEBUG=kernel";
#endif
/* extensible set of named bus-specific parameters,
* supporting multiple driver selection algorithms.
@@ -138,33 +136,33 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
scratch = buf;
/* action: add, remove */
- envp [i++] = scratch;
- scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
+ envp[i++] = scratch;
+ scratch += sprintf(scratch, "ACTION=%s", dock ? "add" : "remove") + 1;
/* Report the ident for the dock */
- envp [i++] = scratch;
- scratch += sprintf (scratch, "DOCK=%x/%x/%x",
- info->location_id, info->serial, info->capabilities);
+ envp[i++] = scratch;
+ scratch += sprintf(scratch, "DOCK=%x/%x/%x",
+ info->location_id, info->serial, info->capabilities);
envp[i] = NULL;
-
- value = call_usermodehelper (argv [0], argv, envp, 0);
- kfree (buf);
- kfree (envp);
+
+ value = call_usermodehelper(argv [0], argv, envp, UMH_WAIT_EXEC);
+ kfree(buf);
+ kfree(envp);
return 0;
}
/*
* Poll the PnP docking at regular intervals
*/
-static int pnp_dock_thread(void * unused)
+static int pnp_dock_thread(void *unused)
{
static struct pnp_docking_station_info now;
int docked = -1, d = 0;
+
set_freezable();
- while (!unloading)
- {
+ while (!unloading) {
int status;
-
+
/*
* Poll every 2 seconds
*/
@@ -175,30 +173,29 @@ static int pnp_dock_thread(void * unused)
status = pnp_bios_dock_station_info(&now);
- switch(status)
- {
+ switch (status) {
/*
* No dock to manage
*/
- case PNP_FUNCTION_NOT_SUPPORTED:
- complete_and_exit(&unload_sem, 0);
- case PNP_SYSTEM_NOT_DOCKED:
- d = 0;
- break;
- case PNP_SUCCESS:
- d = 1;
- break;
- default:
- pnpbios_print_status( "pnp_dock_thread", status );
- continue;
+ case PNP_FUNCTION_NOT_SUPPORTED:
+ complete_and_exit(&unload_sem, 0);
+ case PNP_SYSTEM_NOT_DOCKED:
+ d = 0;
+ break;
+ case PNP_SUCCESS:
+ d = 1;
+ break;
+ default:
+ pnpbios_print_status("pnp_dock_thread", status);
+ continue;
}
- if(d != docked)
- {
- if(pnp_dock_event(d, &now)==0)
- {
+ if (d != docked) {
+ if (pnp_dock_event(d, &now) == 0) {
docked = d;
#if 0
- printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
+ printk(KERN_INFO
+ "PnPBIOS: Docking station %stached\n",
+ docked ? "at" : "de");
#endif
}
}
@@ -206,21 +203,21 @@ static int pnp_dock_thread(void * unused)
complete_and_exit(&unload_sem, 0);
}
-#endif /* CONFIG_HOTPLUG */
+#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,
+ struct pnp_resource_table *res)
{
u8 nodenum = dev->number;
- struct pnp_bios_node * node;
+ struct pnp_bios_node *node;
- /* just in case */
- if(!pnpbios_is_dynamic(dev))
+ if (!pnpbios_is_dynamic(dev))
return -EPERM;
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
- if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
+ if (pnp_bios_get_dev_node(&nodenum, (char)PNPMODE_DYNAMIC, node)) {
kfree(node);
return -ENODEV;
}
@@ -230,24 +227,24 @@ static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table
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,
+ struct pnp_resource_table *res)
{
u8 nodenum = dev->number;
- struct pnp_bios_node * node;
+ struct pnp_bios_node *node;
int ret;
- /* just in case */
if (!pnpbios_is_dynamic(dev))
return -EPERM;
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
- if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
+ if (pnp_bios_get_dev_node(&nodenum, (char)PNPMODE_DYNAMIC, node)) {
kfree(node);
return -ENODEV;
}
- if(pnpbios_write_resources_to_node(res, node)<0) {
+ if (pnpbios_write_resources_to_node(res, node) < 0) {
kfree(node);
return -1;
}
@@ -258,18 +255,19 @@ static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table
return ret;
}
-static void pnpbios_zero_data_stream(struct pnp_bios_node * node)
+static void pnpbios_zero_data_stream(struct pnp_bios_node *node)
{
- unsigned char * p = (char *)node->data;
- unsigned char * end = (char *)(node->data + node->size);
+ unsigned char *p = (char *)node->data;
+ unsigned char *end = (char *)(node->data + node->size);
unsigned int len;
int i;
+
while ((char *)p < (char *)end) {
- if(p[0] & 0x80) { /* large tag */
+ if (p[0] & 0x80) { /* large tag */
len = (p[2] << 8) | p[1];
p += 3;
} else {
- if (((p[0]>>3) & 0x0f) == 0x0f)
+ if (((p[0] >> 3) & 0x0f) == 0x0f)
return;
len = p[0] & 0x07;
p += 1;
@@ -278,24 +276,24 @@ static void pnpbios_zero_data_stream(struct pnp_bios_node * node)
p[i] = 0;
p += len;
}
- printk(KERN_ERR "PnPBIOS: Resource structure did not contain an end tag.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Resource structure did not contain an end tag.\n");
}
static int pnpbios_disable_resources(struct pnp_dev *dev)
{
- struct pnp_bios_node * node;
+ struct pnp_bios_node *node;
u8 nodenum = dev->number;
int ret;
- /* just in case */
- if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
+ if (dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
return -EPERM;
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -ENOMEM;
- if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
+ if (pnp_bios_get_dev_node(&nodenum, (char)PNPMODE_DYNAMIC, node)) {
kfree(node);
return -ENODEV;
}
@@ -311,22 +309,22 @@ static int pnpbios_disable_resources(struct pnp_dev *dev)
/* PnP Layer support */
struct pnp_protocol pnpbios_protocol = {
- .name = "Plug and Play BIOS",
- .get = pnpbios_get_resources,
- .set = pnpbios_set_resources,
+ .name = "Plug and Play BIOS",
+ .get = pnpbios_get_resources,
+ .set = pnpbios_set_resources,
.disable = pnpbios_disable_resources,
};
-static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
+static int insert_device(struct pnp_dev *dev, struct pnp_bios_node *node)
{
- struct list_head * pos;
- struct pnp_dev * pnp_dev;
+ struct list_head *pos;
+ struct pnp_dev *pnp_dev;
struct pnp_id *dev_id;
char id[8];
/* check if the device is already added */
dev->number = node->handle;
- list_for_each (pos, &pnpbios_protocol.devices){
+ list_for_each(pos, &pnpbios_protocol.devices) {
pnp_dev = list_entry(pos, struct pnp_dev, protocol_list);
if (dev->number == pnp_dev->number)
return -1;
@@ -336,8 +334,8 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
return -1;
- pnpid32_to_pnpid(node->eisa_id,id);
- memcpy(dev_id->id,id,7);
+ 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);
@@ -375,35 +373,41 @@ static void __init build_devlist(void)
if (!node)
return;
- for(nodenum=0; nodenum<0xff; ) {
+ for (nodenum = 0; nodenum < 0xff;) {
u8 thisnodenum = nodenum;
/* eventually we will want to use PNPMODE_STATIC here but for now
* dynamic will help us catch buggy bioses to add to the blacklist.
*/
if (!pnpbios_dont_use_current_config) {
- if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node))
+ if (pnp_bios_get_dev_node
+ (&nodenum, (char)PNPMODE_DYNAMIC, node))
break;
} else {
- if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node))
+ if (pnp_bios_get_dev_node
+ (&nodenum, (char)PNPMODE_STATIC, node))
break;
}
nodes_got++;
- dev = kzalloc(sizeof (struct pnp_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev)
break;
- if(insert_device(dev,node)<0)
+ if (insert_device(dev, node) < 0)
kfree(dev);
else
devs++;
if (nodenum <= thisnodenum) {
- printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ printk(KERN_ERR
+ "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
+ (unsigned int)nodenum,
+ (unsigned int)thisnodenum);
break;
}
}
kfree(node);
- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
- nodes_got, nodes_got != 1 ? "s" : "", devs);
+ printk(KERN_INFO
+ "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
+ nodes_got, nodes_got != 1 ? "s" : "", devs);
}
/*
@@ -412,19 +416,18 @@ static void __init build_devlist(void)
*
*/
-static int pnpbios_disabled; /* = 0 */
-int pnpbios_dont_use_current_config; /* = 0 */
+static int pnpbios_disabled;
+int pnpbios_dont_use_current_config;
-#ifndef MODULE
static int __init pnpbios_setup(char *str)
{
int invert;
while ((str != NULL) && (*str != '\0')) {
if (strncmp(str, "off", 3) == 0)
- pnpbios_disabled=1;
+ pnpbios_disabled = 1;
if (strncmp(str, "on", 2) == 0)
- pnpbios_disabled=0;
+ pnpbios_disabled = 0;
invert = (strncmp(str, "no-", 3) == 0);
if (invert)
str += 3;
@@ -439,7 +442,6 @@ static int __init pnpbios_setup(char *str)
}
__setup("pnpbios=", pnpbios_setup);
-#endif
/* PnP BIOS signature: "$PnP" */
#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
@@ -453,35 +455,41 @@ static int __init pnpbios_probe_system(void)
printk(KERN_INFO "PnPBIOS: Scanning system for PnP BIOS support...\n");
/*
- * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
* structure and, if one is found, sets up the selectors and
* entry points
*/
- for (check = (union pnp_bios_install_struct *) __va(0xf0000);
- check < (union pnp_bios_install_struct *) __va(0xffff0);
+ for (check = (union pnp_bios_install_struct *)__va(0xf0000);
+ check < (union pnp_bios_install_struct *)__va(0xffff0);
check = (void *)check + 16) {
if (check->fields.signature != PNP_SIGNATURE)
continue;
- printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
+ printk(KERN_INFO
+ "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n",
+ check);
length = check->fields.length;
if (!length) {
- printk(KERN_ERR "PnPBIOS: installation structure is invalid, skipping\n");
+ printk(KERN_ERR
+ "PnPBIOS: installation structure is invalid, skipping\n");
continue;
}
for (sum = 0, i = 0; i < length; i++)
sum += check->chars[i];
if (sum) {
- printk(KERN_ERR "PnPBIOS: installation structure is corrupted, skipping\n");
+ printk(KERN_ERR
+ "PnPBIOS: installation structure is corrupted, skipping\n");
continue;
}
if (check->fields.version < 0x10) {
- printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
+ printk(KERN_WARNING
+ "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
check->fields.version >> 4,
check->fields.version & 15);
continue;
}
- printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
- check->fields.version >> 4, check->fields.version & 15,
+ printk(KERN_INFO
+ "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
+ check->fields.version >> 4, check->fields.version & 15,
check->fields.pm16cseg, check->fields.pm16offset,
check->fields.pm16dseg);
pnp_bios_install = check;
@@ -492,32 +500,32 @@ static int __init pnpbios_probe_system(void)
return 0;
}
-static int __init exploding_pnp_bios(struct dmi_system_id *d)
+static int __init exploding_pnp_bios(const struct dmi_system_id *d)
{
printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident);
return 0;
}
static struct dmi_system_id pnpbios_dmi_table[] __initdata = {
- { /* PnPBIOS GPF on boot */
- .callback = exploding_pnp_bios,
- .ident = "Higraded P14H",
- .matches = {
- DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
- DMI_MATCH(DMI_BIOS_VERSION, "07.00T"),
- DMI_MATCH(DMI_SYS_VENDOR, "Higraded"),
- DMI_MATCH(DMI_PRODUCT_NAME, "P14H"),
- },
- },
- { /* PnPBIOS GPF on boot */
- .callback = exploding_pnp_bios,
- .ident = "ASUS P4P800",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_BOARD_NAME, "P4P800"),
- },
- },
- { }
+ { /* PnPBIOS GPF on boot */
+ .callback = exploding_pnp_bios,
+ .ident = "Higraded P14H",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ DMI_MATCH(DMI_BIOS_VERSION, "07.00T"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Higraded"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "P14H"),
+ },
+ },
+ { /* PnPBIOS GPF on boot */
+ .callback = exploding_pnp_bios,
+ .ident = "ASUS P4P800",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "P4P800"),
+ },
+ },
+ {}
};
static int __init pnpbios_init(void)
@@ -533,14 +541,13 @@ static int __init pnpbios_init(void)
printk(KERN_INFO "PnPBIOS: Disabled\n");
return -ENODEV;
}
-
#ifdef CONFIG_PNPACPI
if (!acpi_disabled && !pnpacpi_disabled) {
pnpbios_disabled = 1;
printk(KERN_INFO "PnPBIOS: Disabled by ACPI PNP\n");
return -ENODEV;
}
-#endif /* CONFIG_ACPI */
+#endif /* CONFIG_ACPI */
/* scan the system for pnpbios support */
if (!pnpbios_probe_system())
@@ -552,14 +559,16 @@ static int __init pnpbios_init(void)
/* read the node info */
ret = pnp_bios_dev_node_info(&node_info);
if (ret) {
- printk(KERN_ERR "PnPBIOS: Unable to get node info. Aborting.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Unable to get node info. Aborting.\n");
return ret;
}
/* register with the pnp layer */
ret = pnp_register_protocol(&pnpbios_protocol);
if (ret) {
- printk(KERN_ERR "PnPBIOS: Unable to register driver. Aborting.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Unable to register driver. Aborting.\n");
return ret;
}
@@ -580,6 +589,7 @@ subsys_initcall(pnpbios_init);
static int __init pnpbios_thread_init(void)
{
struct task_struct *task;
+
#if defined(CONFIG_PPC_MERGE)
if (check_legacy_ioport(PNPBIOS_BASE))
return 0;
@@ -595,48 +605,7 @@ static int __init pnpbios_thread_init(void)
return 0;
}
-#ifndef MODULE
-
-/* init/main.c calls pnpbios_init early */
-
/* Start the kernel thread later: */
module_init(pnpbios_thread_init);
-#else
-
-/*
- * N.B.: Building pnpbios as a module hasn't been fully implemented
- */
-
-MODULE_LICENSE("GPL");
-
-static int __init pnpbios_init_all(void)
-{
- int r;
-
- r = pnpbios_init();
- if (r)
- return r;
- r = pnpbios_thread_init();
- if (r)
- return r;
- return 0;
-}
-
-static void __exit pnpbios_exit(void)
-{
-#ifdef CONFIG_HOTPLUG
- unloading = 1;
- wait_for_completion(&unload_sem);
-#endif
- pnpbios_proc_exit();
- /* We ought to free resources here */
- return;
-}
-
-module_init(pnpbios_init_all);
-module_exit(pnpbios_exit);
-
-#endif
-
EXPORT_SYMBOL(pnpbios_protocol);
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 8027073f7919..9d9841f24a85 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -18,9 +18,6 @@
* The other files are human-readable.
*/
-//#include <pcmcia/config.h>
-//#include <pcmcia/k_compat.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -37,42 +34,37 @@ static struct proc_dir_entry *proc_pnp = NULL;
static struct proc_dir_entry *proc_pnp_boot = NULL;
static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
struct pnp_isa_config_struc pnps;
if (pnp_bios_isapnp_config(&pnps))
return -EIO;
return snprintf(buf, count,
- "structure_revision %d\n"
- "number_of_CSNs %d\n"
- "ISA_read_data_port 0x%x\n",
- pnps.revision,
- pnps.no_csns,
- pnps.isa_rd_data_port
- );
+ "structure_revision %d\n"
+ "number_of_CSNs %d\n"
+ "ISA_read_data_port 0x%x\n",
+ pnps.revision, pnps.no_csns, pnps.isa_rd_data_port);
}
static int proc_read_escdinfo(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
struct escd_info_struc escd;
if (pnp_bios_escd_info(&escd))
return -EIO;
return snprintf(buf, count,
- "min_ESCD_write_size %d\n"
- "ESCD_size %d\n"
- "NVRAM_base 0x%x\n",
- escd.min_escd_write_size,
- escd.escd_size,
- escd.nv_storage_base
- );
+ "min_ESCD_write_size %d\n"
+ "ESCD_size %d\n"
+ "NVRAM_base 0x%x\n",
+ escd.min_escd_write_size,
+ escd.escd_size, escd.nv_storage_base);
}
#define MAX_SANE_ESCD_SIZE (32*1024)
static int proc_read_escd(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
struct escd_info_struc escd;
char *tmpbuf;
@@ -83,30 +75,36 @@ static int proc_read_escd(char *buf, char **start, off_t pos,
/* sanity check */
if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
- printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
+ printk(KERN_ERR
+ "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
return -EFBIG;
}
tmpbuf = kzalloc(escd.escd_size, GFP_KERNEL);
- if (!tmpbuf) return -ENOMEM;
+ if (!tmpbuf)
+ return -ENOMEM;
if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
kfree(tmpbuf);
return -EIO;
}
- escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256;
+ escd_size =
+ (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1]) * 256;
/* sanity check */
if (escd_size > MAX_SANE_ESCD_SIZE) {
- printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
+ printk(KERN_ERR
+ "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
return -EFBIG;
}
escd_left_to_read = escd_size - pos;
- if (escd_left_to_read < 0) escd_left_to_read = 0;
- if (escd_left_to_read == 0) *eof = 1;
- n = min(count,escd_left_to_read);
+ if (escd_left_to_read < 0)
+ escd_left_to_read = 0;
+ if (escd_left_to_read == 0)
+ *eof = 1;
+ n = min(count, escd_left_to_read);
memcpy(buf, tmpbuf + pos, n);
kfree(tmpbuf);
*start = buf;
@@ -114,17 +112,17 @@ static int proc_read_escd(char *buf, char **start, off_t pos,
}
static int proc_read_legacyres(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
/* Assume that the following won't overflow the buffer */
- if (pnp_bios_get_stat_res(buf))
+ if (pnp_bios_get_stat_res(buf))
return -EIO;
- return count; // FIXME: Return actual length
+ return count; // FIXME: Return actual length
}
static int proc_read_devices(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
struct pnp_bios_node *node;
u8 nodenum;
@@ -134,9 +132,10 @@ static int proc_read_devices(char *buf, char **start, off_t pos,
return 0;
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
- if (!node) return -ENOMEM;
+ if (!node)
+ return -ENOMEM;
- for (nodenum=pos; nodenum<0xff; ) {
+ for (nodenum = pos; nodenum < 0xff;) {
u8 thisnodenum = nodenum;
/* 26 = the number of characters per line sprintf'ed */
if ((p - buf + 26) > count)
@@ -148,7 +147,11 @@ static int proc_read_devices(char *buf, char **start, off_t pos,
node->type_code[0], node->type_code[1],
node->type_code[2], node->flags);
if (nodenum <= thisnodenum) {
- printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ printk(KERN_ERR
+ "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
+ "PnPBIOS: proc_read_devices:",
+ (unsigned int)nodenum,
+ (unsigned int)thisnodenum);
*eof = 1;
break;
}
@@ -156,12 +159,12 @@ static int proc_read_devices(char *buf, char **start, off_t pos,
kfree(node);
if (nodenum == 0xff)
*eof = 1;
- *start = (char *)((off_t)nodenum - pos);
+ *start = (char *)((off_t) nodenum - pos);
return p - buf;
}
static int proc_read_node(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
+ int count, int *eof, void *data)
{
struct pnp_bios_node *node;
int boot = (long)data >> 8;
@@ -169,7 +172,8 @@ static int proc_read_node(char *buf, char **start, off_t pos,
int len;
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
- if (!node) return -ENOMEM;
+ if (!node)
+ return -ENOMEM;
if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
kfree(node);
return -EIO;
@@ -180,8 +184,8 @@ static int proc_read_node(char *buf, char **start, off_t pos,
return len;
}
-static int proc_write_node(struct file *file, const char __user *buf,
- unsigned long count, void *data)
+static int proc_write_node(struct file *file, const char __user * buf,
+ unsigned long count, void *data)
{
struct pnp_bios_node *node;
int boot = (long)data >> 8;
@@ -213,7 +217,7 @@ out:
return ret;
}
-int pnpbios_interface_attach_device(struct pnp_bios_node * node)
+int pnpbios_interface_attach_device(struct pnp_bios_node *node)
{
char name[3];
struct proc_dir_entry *ent;
@@ -222,7 +226,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node * node)
if (!proc_pnp)
return -EIO;
- if ( !pnpbios_dont_use_current_config ) {
+ if (!pnpbios_dont_use_current_config) {
ent = create_proc_entry(name, 0, proc_pnp);
if (ent) {
ent->read_proc = proc_read_node;
@@ -237,7 +241,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node * node)
if (ent) {
ent->read_proc = proc_read_node;
ent->write_proc = proc_write_node;
- ent->data = (void *)(long)(node->handle+0x100);
+ ent->data = (void *)(long)(node->handle + 0x100);
return 0;
}
@@ -249,7 +253,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node * node)
* work and the pnpbios_dont_use_current_config flag
* should already have been set to the appropriate value
*/
-int __init pnpbios_proc_init( void )
+int __init pnpbios_proc_init(void)
{
proc_pnp = proc_mkdir("pnp", proc_bus);
if (!proc_pnp)
@@ -258,10 +262,13 @@ int __init pnpbios_proc_init( void )
if (!proc_pnp_boot)
return -EIO;
create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
- create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
- create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
+ create_proc_read_entry("configuration_info", 0, proc_pnp,
+ proc_read_pnpconfig, NULL);
+ create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo,
+ NULL);
create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
- create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
+ create_proc_read_entry("legacy_device_resources", 0, proc_pnp,
+ proc_read_legacyres, NULL);
return 0;
}
@@ -274,9 +281,9 @@ void __exit pnpbios_proc_exit(void)
if (!proc_pnp)
return;
- for (i=0; i<0xff; i++) {
+ for (i = 0; i < 0xff; i++) {
sprintf(name, "%02x", i);
- if ( !pnpbios_dont_use_current_config )
+ if (!pnpbios_dont_use_current_config)
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}
@@ -287,6 +294,4 @@ void __exit pnpbios_proc_exit(void)
remove_proc_entry("devices", proc_pnp);
remove_proc_entry("boot", proc_pnp);
remove_proc_entry("pnp", proc_bus);
-
- return;
}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 3c2ab8394e3f..3fabf11b0027 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -1,6 +1,5 @@
/*
* rsparser.c - parses and encodes pnpbios resource data streams
- *
*/
#include <linux/ctype.h>
@@ -12,8 +11,10 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
#else
-inline void pcibios_penalize_isa_irq(int irq, int active) {}
-#endif /* CONFIG_PCI */
+inline void pcibios_penalize_isa_irq(int irq, int active)
+{
+}
+#endif /* CONFIG_PCI */
#include "pnpbios.h"
@@ -52,75 +53,88 @@ 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_irqresource(struct pnp_resource_table *res,
+ int irq)
{
int i = 0;
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_IRQ) i++;
+
+ 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
+ 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;
+ res->irq_resource[i].end = (unsigned long)irq;
pcibios_penalize_isa_irq(irq, 1);
}
}
-static void
-pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
+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))
+ !(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 = 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;
+ res->dma_resource[i].end = (unsigned long)dma;
}
}
-static void
-pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len)
+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++;
+
+ 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_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].start = (unsigned long)io;
res->port_resource[i].end = (unsigned long)(io + len - 1);
}
}
-static void
-pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len)
+static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
+ int mem, int len)
{
int i = 0;
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_MEM) i++;
+
+ 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
+ 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].start = (unsigned long)mem;
res->mem_resource[i].end = (unsigned long)(mem + len - 1);
}
}
-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(unsigned char *p,
+ unsigned char *end,
+ struct
+ pnp_resource_table
+ *res)
{
unsigned int len, tag;
int io, size, mask, i;
@@ -134,12 +148,12 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
while ((char *)p < (char *)end) {
/* determine the type of tag */
- if (p[0] & LARGE_TAG) { /* large tag */
+ if (p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
tag = p[0];
- } else { /* small tag */
+ } else { /* small tag */
len = p[0] & 0x07;
- tag = ((p[0]>>3) & 0x0f);
+ tag = ((p[0] >> 3) & 0x0f);
}
switch (tag) {
@@ -147,8 +161,8 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
- io = *(short *) &p[4];
- size = *(short *) &p[10];
+ io = *(short *)&p[4];
+ size = *(short *)&p[10];
pnpbios_parse_allocated_memresource(res, io, size);
break;
@@ -163,16 +177,16 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
- io = *(int *) &p[4];
- size = *(int *) &p[16];
+ io = *(int *)&p[4];
+ size = *(int *)&p[16];
pnpbios_parse_allocated_memresource(res, io, size);
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
- io = *(int *) &p[4];
- size = *(int *) &p[8];
+ io = *(int *)&p[4];
+ size = *(int *)&p[8];
pnpbios_parse_allocated_memresource(res, io, size);
break;
@@ -180,9 +194,10 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
if (len < 2 || len > 3)
goto len_err;
io = -1;
- mask= p[1] + p[2]*256;
- for (i=0;i<16;i++, mask=mask>>1)
- if(mask & 0x01) io=i;
+ 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);
break;
@@ -191,15 +206,16 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
goto len_err;
io = -1;
mask = p[1];
- for (i=0;i<8;i++, mask = mask>>1)
- if(mask & 0x01) io=i;
+ for (i = 0; i < 8; i++, mask = mask >> 1)
+ if (mask & 0x01)
+ io = i;
pnpbios_parse_allocated_dmaresource(res, io);
break;
case SMALL_TAG_PORT:
if (len != 7)
goto len_err;
- io = p[2] + p[3] *256;
+ io = p[2] + p[3] * 256;
size = p[7];
pnpbios_parse_allocated_ioresource(res, io, size);
break;
@@ -218,12 +234,14 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
case SMALL_TAG_END:
p = p + 2;
- return (unsigned char *)p;
+ return (unsigned char *)p;
break;
- default: /* an unkown tag */
- len_err:
- printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+ default: /* an unkown tag */
+len_err:
+ printk(KERN_ERR
+ "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+ tag, len);
break;
}
@@ -234,20 +252,21 @@ pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, st
p += len + 1;
}
- printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Resource structure does not contain an end tag.\n");
return NULL;
}
-
/*
* Resource Configuration Options
*/
-static void
-pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_mem_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_mem * mem;
+ struct pnp_mem *mem;
+
mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
@@ -256,14 +275,14 @@ pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
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);
- return;
+ pnp_register_mem_resource(option, mem);
}
-static void
-pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_mem32_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_mem * mem;
+ struct pnp_mem *mem;
+
mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
@@ -272,14 +291,14 @@ pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option
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);
- return;
+ pnp_register_mem_resource(option, mem);
}
-static void
-pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_mem * mem;
+ struct pnp_mem *mem;
+
mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
if (!mem)
return;
@@ -287,14 +306,13 @@ pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *
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);
- return;
+ pnp_register_mem_resource(option, mem);
}
-static void
-pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_irq_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_irq * irq;
+ struct pnp_irq *irq;
unsigned long bits;
irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
@@ -306,27 +324,27 @@ pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
irq->flags = p[3];
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(option,irq);
- return;
+ pnp_register_irq_resource(option, irq);
}
-static void
-pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_dma_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_dma * dma;
+ struct pnp_dma *dma;
+
dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
if (!dma)
return;
dma->map = p[1];
dma->flags = p[2];
- pnp_register_dma_resource(option,dma);
- return;
+ pnp_register_dma_resource(option, dma);
}
-static void
-pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_port_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_port * port;
+ struct pnp_port *port;
+
port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
@@ -335,14 +353,14 @@ pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
port->align = p[6];
port->size = p[7];
port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option,port);
- return;
+ pnp_register_port_resource(option, port);
}
-static void
-pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
- struct pnp_port * port;
+ struct pnp_port *port;
+
port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
return;
@@ -350,12 +368,12 @@ pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *o
port->size = p[3];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option,port);
- return;
+ pnp_register_port_resource(option, port);
}
-static unsigned char *
-pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
+static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p,
+ unsigned char *end,
+ struct pnp_dev *dev)
{
unsigned int len, tag;
int priority = 0;
@@ -371,12 +389,12 @@ pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struc
while ((char *)p < (char *)end) {
/* determine the type of tag */
- if (p[0] & LARGE_TAG) { /* large tag */
+ if (p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
tag = p[0];
- } else { /* small tag */
+ } else { /* small tag */
len = p[0] & 0x07;
- tag = ((p[0]>>3) & 0x0f);
+ tag = ((p[0] >> 3) & 0x0f);
}
switch (tag) {
@@ -442,16 +460,19 @@ pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struc
if (len != 0)
goto len_err;
if (option_independent == option)
- printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
+ printk(KERN_WARNING
+ "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
option = option_independent;
break;
case SMALL_TAG_END:
- return p + 2;
+ return p + 2;
- default: /* an unkown tag */
- len_err:
- printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+ default: /* an unkown tag */
+len_err:
+ printk(KERN_ERR
+ "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+ tag, len);
break;
}
@@ -462,19 +483,18 @@ pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struc
p += len + 1;
}
- printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Resource structure does not contain an end tag.\n");
return NULL;
}
-
/*
* 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)
{
@@ -483,21 +503,20 @@ void pnpid32_to_pnpid(u32 id, char *str)
id = be32_to_cpu(id);
str[0] = CHAR(id, 26);
str[1] = CHAR(id, 21);
- str[2] = CHAR(id,16);
+ 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';
-
- return;
}
-//
+
#undef CHAR
#undef HEX
-static unsigned char *
-pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev)
+static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
+ unsigned char *end,
+ struct pnp_dev *dev)
{
int len, tag;
char id[8];
@@ -509,40 +528,45 @@ pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_de
while ((char *)p < (char *)end) {
/* determine the type of tag */
- if (p[0] & LARGE_TAG) { /* large tag */
+ if (p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
tag = p[0];
- } else { /* small tag */
+ } else { /* small tag */
len = p[0] & 0x07;
- tag = ((p[0]>>3) & 0x0f);
+ tag = ((p[0] >> 3) & 0x0f);
}
switch (tag) {
case LARGE_TAG_ANSISTR:
- strncpy(dev->name, p + 3, len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
- dev->name[len >= PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
+ strncpy(dev->name, p + 3,
+ len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
+ dev->name[len >=
+ PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
break;
- case SMALL_TAG_COMPATDEVID: /* compatible ID */
+ case SMALL_TAG_COMPATDEVID: /* compatible ID */
if (len != 4)
goto len_err;
- dev_id = kzalloc(sizeof (struct pnp_id), GFP_KERNEL);
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
return NULL;
- pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
+ pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] <<
+ 24, id);
memcpy(&dev_id->id, id, 7);
pnp_add_id(dev_id, dev);
break;
case SMALL_TAG_END:
p = p + 2;
- return (unsigned char *)p;
+ return (unsigned char *)p;
break;
- default: /* an unkown tag */
- len_err:
- printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+ default: /* an unkown tag */
+len_err:
+ printk(KERN_ERR
+ "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+ tag, len);
break;
}
@@ -553,33 +577,34 @@ pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_de
p += len + 1;
}
- printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Resource structure does not contain an end tag.\n");
return NULL;
}
-
/*
* Allocated Resource Encoding
*/
-static void pnpbios_encode_mem(unsigned char *p, struct resource * res)
+static void pnpbios_encode_mem(unsigned char *p, struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
+
p[4] = (base >> 8) & 0xff;
p[5] = ((base >> 8) >> 8) & 0xff;
p[6] = (base >> 8) & 0xff;
p[7] = ((base >> 8) >> 8) & 0xff;
p[10] = (len >> 8) & 0xff;
p[11] = ((len >> 8) >> 8) & 0xff;
- return;
}
-static void pnpbios_encode_mem32(unsigned char *p, struct resource * res)
+static void pnpbios_encode_mem32(unsigned char *p, struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
+
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[6] = (base >> 16) & 0xff;
@@ -592,12 +617,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;
- return;
}
-static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource * res)
-{ unsigned long base = res->start;
+static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res)
+{
+ unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
+
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[6] = (base >> 16) & 0xff;
@@ -606,50 +632,52 @@ 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;
- return;
}
-static void pnpbios_encode_irq(unsigned char *p, struct resource * res)
+static void pnpbios_encode_irq(unsigned char *p, struct resource *res)
{
unsigned long map = 0;
+
map = 1 << res->start;
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
- return;
}
-static void pnpbios_encode_dma(unsigned char *p, struct resource * res)
+static void pnpbios_encode_dma(unsigned char *p, struct resource *res)
{
unsigned long map = 0;
+
map = 1 << res->start;
p[1] = map & 0xff;
- return;
}
-static void pnpbios_encode_port(unsigned char *p, struct resource * res)
+static void pnpbios_encode_port(unsigned char *p, struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
+
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[7] = len & 0xff;
- return;
}
-static void pnpbios_encode_fixed_port(unsigned char *p, struct resource * res)
+static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
+
p[1] = base & 0xff;
p[2] = (base >> 8) & 0xff;
p[3] = len & 0xff;
- return;
}
-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(unsigned char *p,
+ unsigned char *end,
+ struct
+ pnp_resource_table
+ *res)
{
unsigned int len, tag;
int port = 0, irq = 0, dma = 0, mem = 0;
@@ -660,12 +688,12 @@ pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, s
while ((char *)p < (char *)end) {
/* determine the type of tag */
- if (p[0] & LARGE_TAG) { /* large tag */
+ if (p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
tag = p[0];
- } else { /* small tag */
+ } else { /* small tag */
len = p[0] & 0x07;
- tag = ((p[0]>>3) & 0x0f);
+ tag = ((p[0] >> 3) & 0x0f);
}
switch (tag) {
@@ -725,12 +753,14 @@ pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, s
case SMALL_TAG_END:
p = p + 2;
- return (unsigned char *)p;
+ return (unsigned char *)p;
break;
- default: /* an unkown tag */
- len_err:
- printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+ default: /* an unkown tag */
+len_err:
+ printk(KERN_ERR
+ "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+ tag, len);
break;
}
@@ -741,52 +771,52 @@ pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, s
p += len + 1;
}
- printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+ printk(KERN_ERR
+ "PnPBIOS: Resource structure does not contain an end tag.\n");
return NULL;
}
-
/*
* Core Parsing Functions
*/
-int
-pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node)
+int pnpbios_parse_data_stream(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,&dev->res);
+ unsigned char *p = (char *)node->data;
+ unsigned char *end = (char *)(node->data + node->size);
+
+ p = pnpbios_parse_allocated_resource_data(p, end, &dev->res);
if (!p)
return -EIO;
- p = pnpbios_parse_resource_option_data(p,end,dev);
+ p = pnpbios_parse_resource_option_data(p, end, dev);
if (!p)
return -EIO;
- p = pnpbios_parse_compatible_ids(p,end,dev);
+ p = pnpbios_parse_compatible_ids(p, end, dev);
if (!p)
return -EIO;
return 0;
}
-int
-pnpbios_read_resources_from_node(struct pnp_resource_table *res,
- struct pnp_bios_node * node)
+int pnpbios_read_resources_from_node(struct pnp_resource_table *res,
+ 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);
+ unsigned char *p = (char *)node->data;
+ unsigned char *end = (char *)(node->data + node->size);
+
+ p = pnpbios_parse_allocated_resource_data(p, end, res);
if (!p)
return -EIO;
return 0;
}
-int
-pnpbios_write_resources_to_node(struct pnp_resource_table *res,
- struct pnp_bios_node * node)
+int pnpbios_write_resources_to_node(struct pnp_resource_table *res,
+ 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);
+ unsigned char *p = (char *)node->data;
+ unsigned char *end = (char *)(node->data + node->size);
+
+ p = pnpbios_encode_allocated_resource_data(p, end, res);
if (!p)
return -EIO;
return 0;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 7c3236690cc3..6b0cf0c2a088 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -19,7 +19,6 @@
#include <linux/io.h>
#include "base.h"
-
static void quirk_awe32_resources(struct pnp_dev *dev)
{
struct pnp_port *port, *port2, *port3;
@@ -31,7 +30,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev)
* two extra ports (at offset 0x400 and 0x800 from the one given) by
* hand.
*/
- for ( ; res ; res = res->next ) {
+ for (; res; res = res->next) {
port2 = pnp_alloc(sizeof(struct pnp_port));
if (!port2)
return;
@@ -58,18 +57,19 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev)
struct pnp_option *res = dev->dependent;
unsigned long tmp;
- for ( ; res ; res = res->next ) {
+ for (; res; res = res->next) {
struct pnp_irq *irq;
struct pnp_dma *dma;
- for( irq = res->irq; irq; irq = irq->next ) { // Valid irqs are 5, 7, 10
+ for (irq = res->irq; irq; irq = irq->next) { // Valid irqs are 5, 7, 10
tmp = 0x04A0;
bitmap_copy(irq->map, &tmp, 16); // 0000 0100 1010 0000
}
- for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
- if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
+ for (dma = res->dma; dma; dma = dma->next) // Valid 8bit dma channels are 1,3
+ if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
+ IORESOURCE_DMA_8BIT)
dma->map = 0x000A;
}
printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n");
@@ -79,7 +79,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
{
struct pnp_port *port;
struct pnp_option *res = dev->dependent;
- int changed = 0;
+ int changed = 0;
/*
* The default range on the mpu port for these devices is 0x388-0x388.
@@ -87,129 +87,26 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
* auto-configured.
*/
- for( ; res ; res = res->next ) {
+ for (; res; res = res->next) {
port = res->port;
- if(!port)
+ if (!port)
continue;
port = port->next;
- if(!port)
+ if (!port)
continue;
port = port->next;
- if(!port)
+ if (!port)
continue;
- if(port->min != port->max)
+ if (port->min != port->max)
continue;
port->max += 0x70;
changed = 1;
}
- if(changed)
- printk(KERN_INFO "pnp: SB audio device quirk - increasing port range\n");
- return;
-}
-
-static int quirk_smc_fir_enabled(struct pnp_dev *dev)
-{
- unsigned long firbase;
- u8 bank, high, low, chip;
-
- if (!pnp_port_valid(dev, 1))
- return 0;
-
- firbase = pnp_port_start(dev, 1);
-
- /* Select register bank 3 */
- bank = inb(firbase + 7);
- bank &= 0xf0;
- bank |= 3;
- outb(bank, firbase + 7);
-
- high = inb(firbase + 0);
- low = inb(firbase + 1);
- chip = inb(firbase + 2);
-
- /* This corresponds to the check in smsc_ircc_present() */
- if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2))
- return 1;
-
- return 0;
+ if (changed)
+ printk(KERN_INFO
+ "pnp: SB audio device quirk - increasing port range\n");
}
-static void quirk_smc_enable(struct pnp_dev *dev)
-{
- struct resource fir, sir, irq;
-
- pnp_activate_dev(dev);
- if (quirk_smc_fir_enabled(dev))
- return;
-
- /*
- * Sometimes the BIOS claims the device is enabled, but it reports
- * the wrong FIR resources or doesn't properly configure ISA or LPC
- * bridges on the way to the device.
- *
- * HP nc6000 and nc8000/nw8000 laptops have known problems like
- * this. Fortunately, they do fix things up if we auto-configure
- * the device using its _PRS and _SRS methods.
- */
- dev_err(&dev->dev, "%s not responding at SIR 0x%lx, FIR 0x%lx; "
- "auto-configuring\n", dev->id->id,
- (unsigned long) pnp_port_start(dev, 0),
- (unsigned long) pnp_port_start(dev, 1));
-
- pnp_disable_dev(dev);
- pnp_init_resource_table(&dev->res);
- pnp_auto_config_dev(dev);
- pnp_activate_dev(dev);
- if (quirk_smc_fir_enabled(dev)) {
- dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n",
- (unsigned long) pnp_port_start(dev, 0),
- (unsigned long) pnp_port_start(dev, 1));
- return;
- }
-
- /*
- * The Toshiba Portege 4000 _CRS reports the FIR region first,
- * followed by the SIR region. The BIOS will configure the bridge,
- * but only if we call _SRS with SIR first, then FIR. It also
- * reports the IRQ as active high, when it is really active low.
- */
- dev_err(&dev->dev, "not responding at SIR 0x%lx, FIR 0x%lx; "
- "swapping SIR/FIR and reconfiguring\n",
- (unsigned long) pnp_port_start(dev, 0),
- (unsigned long) pnp_port_start(dev, 1));
-
- /*
- * Clear IORESOURCE_AUTO so pnp_activate_dev() doesn't reassign
- * these resources any more.
- */
- fir = dev->res.port_resource[0];
- sir = dev->res.port_resource[1];
- fir.flags &= ~IORESOURCE_AUTO;
- sir.flags &= ~IORESOURCE_AUTO;
-
- irq = dev->res.irq_resource[0];
- irq.flags &= ~IORESOURCE_AUTO;
- irq.flags &= ~IORESOURCE_BITS;
- irq.flags |= IORESOURCE_IRQ_LOWEDGE;
-
- pnp_disable_dev(dev);
- dev->res.port_resource[0] = sir;
- dev->res.port_resource[1] = fir;
- dev->res.irq_resource[0] = irq;
- pnp_activate_dev(dev);
-
- if (quirk_smc_fir_enabled(dev)) {
- dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n",
- (unsigned long) pnp_port_start(dev, 0),
- (unsigned long) pnp_port_start(dev, 1));
- return;
- }
-
- dev_err(&dev->dev, "giving up; try \"smsc-ircc2.nopnp\" and "
- "email bjorn.helgaas@hp.com\n");
-}
-
-
/*
* PnP Quirks
* Cards or devices that need some tweaking due to incomplete resource info
@@ -217,21 +114,20 @@ static void quirk_smc_enable(struct pnp_dev *dev)
static struct pnp_fixup pnp_fixups[] = {
/* Soundblaster awe io port quirk */
- { "CTL0021", quirk_awe32_resources },
- { "CTL0022", quirk_awe32_resources },
- { "CTL0023", quirk_awe32_resources },
+ {"CTL0021", quirk_awe32_resources},
+ {"CTL0022", quirk_awe32_resources},
+ {"CTL0023", quirk_awe32_resources},
/* CMI 8330 interrupt and dma fix */
- { "@X@0001", quirk_cmi8330_resources },
+ {"@X@0001", quirk_cmi8330_resources},
/* Soundblaster audio device io port range quirk */
- { "CTL0001", quirk_sb16audio_resources },
- { "CTL0031", quirk_sb16audio_resources },
- { "CTL0041", quirk_sb16audio_resources },
- { "CTL0042", quirk_sb16audio_resources },
- { "CTL0043", quirk_sb16audio_resources },
- { "CTL0044", quirk_sb16audio_resources },
- { "CTL0045", quirk_sb16audio_resources },
- { "SMCf010", quirk_smc_enable },
- { "" }
+ {"CTL0001", quirk_sb16audio_resources},
+ {"CTL0031", quirk_sb16audio_resources},
+ {"CTL0041", quirk_sb16audio_resources},
+ {"CTL0042", quirk_sb16audio_resources},
+ {"CTL0043", quirk_sb16audio_resources},
+ {"CTL0044", quirk_sb16audio_resources},
+ {"CTL0045", quirk_sb16audio_resources},
+ {""}
};
void pnp_fixup_device(struct pnp_dev *dev)
@@ -239,9 +135,8 @@ void pnp_fixup_device(struct pnp_dev *dev)
int i = 0;
while (*pnp_fixups[i].id) {
- if (compare_pnp_id(dev->id,pnp_fixups[i].id)) {
- pnp_dbg("Calling quirk for %s",
- dev->dev.bus_id);
+ if (compare_pnp_id(dev->id, pnp_fixups[i].id)) {
+ pnp_dbg("Calling quirk for %s", dev->dev.bus_id);
pnp_fixups[i].quirk_function(dev);
}
i++;
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index a685fbec4604..ef1286900db3 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -3,7 +3,6 @@
*
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/module.h>
@@ -20,21 +19,19 @@
#include <linux/pnp.h>
#include "base.h"
-static int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
-static int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */
-static int pnp_reserve_io[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some I/O region */
-static int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memory region */
-
+static int pnp_reserve_irq[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
+static int pnp_reserve_dma[8] = {[0 ... 7] = -1 }; /* reserve (don't use) some DMA */
+static int pnp_reserve_io[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some I/O region */
+static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some memory region */
/*
* option registration
*/
-static struct pnp_option * pnp_build_option(int priority)
+static struct pnp_option *pnp_build_option(int priority)
{
struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
- /* check if pnp_alloc ran out of memory */
if (!option)
return NULL;
@@ -46,11 +43,9 @@ static struct pnp_option * pnp_build_option(int priority)
return option;
}
-struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev)
+struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
{
struct pnp_option *option;
- if (!dev)
- return NULL;
option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
@@ -61,11 +56,10 @@ struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev)
return option;
}
-struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority)
+struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
+ int priority)
{
struct pnp_option *option;
- if (!dev)
- return NULL;
option = pnp_build_option(priority);
@@ -82,10 +76,6 @@ struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int prior
int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
{
struct pnp_irq *ptr;
- if (!option)
- return -EINVAL;
- if (!data)
- return -EINVAL;
ptr = option->irq;
while (ptr && ptr->next)
@@ -110,10 +100,6 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
{
struct pnp_dma *ptr;
- if (!option)
- return -EINVAL;
- if (!data)
- return -EINVAL;
ptr = option->dma;
while (ptr && ptr->next)
@@ -129,10 +115,6 @@ int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
{
struct pnp_port *ptr;
- if (!option)
- return -EINVAL;
- if (!data)
- return -EINVAL;
ptr = option->port;
while (ptr && ptr->next)
@@ -148,10 +130,6 @@ int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
{
struct pnp_mem *ptr;
- if (!option)
- return -EINVAL;
- if (!data)
- return -EINVAL;
ptr = option->mem;
while (ptr && ptr->next)
@@ -222,7 +200,6 @@ void pnp_free_option(struct pnp_option *option)
}
}
-
/*
* resource validity checking
*/
@@ -236,11 +213,12 @@ 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, int idx)
{
int tmp;
struct pnp_dev *tdev;
resource_size_t *port, *end, *tport, *tend;
+
port = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
@@ -250,8 +228,8 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
- if(!dev->active) {
- if (__check_region(&ioport_resource, *port, length(port,end)))
+ if (!dev->active) {
+ if (__check_region(&ioport_resource, *port, length(port, end)))
return 0;
}
@@ -259,7 +237,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
for (tmp = 0; tmp < 8; tmp++) {
int rport = pnp_reserve_io[tmp << 1];
int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
- if (ranged_conflict(port,end,&rport,&rend))
+ if (ranged_conflict(port, end, &rport, &rend))
return 0;
}
@@ -268,7 +246,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &dev->res.port_resource[tmp].start;
tend = &dev->res.port_resource[tmp].end;
- if (ranged_conflict(port,end,tport,tend))
+ if (ranged_conflict(port, end, tport, tend))
return 0;
}
}
@@ -279,11 +257,12 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
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))
+ if (cannot_compare
+ (tdev->res.port_resource[tmp].flags))
continue;
tport = &tdev->res.port_resource[tmp].start;
tend = &tdev->res.port_resource[tmp].end;
- if (ranged_conflict(port,end,tport,tend))
+ if (ranged_conflict(port, end, tport, tend))
return 0;
}
}
@@ -292,11 +271,12 @@ 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, int idx)
{
int tmp;
struct pnp_dev *tdev;
resource_size_t *addr, *end, *taddr, *tend;
+
addr = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
@@ -306,8 +286,8 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
- if(!dev->active) {
- if (check_mem_region(*addr, length(addr,end)))
+ if (!dev->active) {
+ if (check_mem_region(*addr, length(addr, end)))
return 0;
}
@@ -315,7 +295,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
for (tmp = 0; tmp < 8; tmp++) {
int raddr = pnp_reserve_mem[tmp << 1];
int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
- if (ranged_conflict(addr,end,&raddr,&rend))
+ if (ranged_conflict(addr, end, &raddr, &rend))
return 0;
}
@@ -324,7 +304,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &dev->res.mem_resource[tmp].start;
tend = &dev->res.mem_resource[tmp].end;
- if (ranged_conflict(addr,end,taddr,tend))
+ if (ranged_conflict(addr, end, taddr, tend))
return 0;
}
}
@@ -335,11 +315,12 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
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))
+ if (cannot_compare
+ (tdev->res.mem_resource[tmp].flags))
continue;
taddr = &tdev->res.mem_resource[tmp].start;
tend = &tdev->res.mem_resource[tmp].end;
- if (ranged_conflict(addr,end,taddr,tend))
+ if (ranged_conflict(addr, end, taddr, tend))
return 0;
}
}
@@ -353,11 +334,11 @@ 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, int idx)
{
int tmp;
struct pnp_dev *tdev;
- resource_size_t * irq = &dev->res.irq_resource[idx].start;
+ resource_size_t *irq = &dev->res.irq_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (cannot_compare(dev->res.irq_resource[idx].flags))
@@ -394,9 +375,9 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
- if(!dev->active) {
+ if (!dev->active) {
if (request_irq(*irq, pnp_test_handler,
- IRQF_DISABLED|IRQF_PROBE_SHARED, "pnp", NULL))
+ IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
return 0;
free_irq(*irq, NULL);
}
@@ -407,7 +388,8 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
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))
+ if (cannot_compare
+ (tdev->res.irq_resource[tmp].flags))
continue;
if ((tdev->res.irq_resource[tmp].start == *irq))
return 0;
@@ -418,12 +400,12 @@ 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, int idx)
{
#ifndef CONFIG_IA64
int tmp;
struct pnp_dev *tdev;
- resource_size_t * dma = &dev->res.dma_resource[idx].start;
+ resource_size_t *dma = &dev->res.dma_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (cannot_compare(dev->res.dma_resource[idx].flags))
@@ -449,7 +431,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
- if(!dev->active) {
+ if (!dev->active) {
if (request_dma(*dma, "pnp"))
return 0;
free_dma(*dma);
@@ -461,7 +443,8 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
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))
+ if (cannot_compare
+ (tdev->res.dma_resource[tmp].flags))
continue;
if ((tdev->res.dma_resource[tmp].start == *dma))
return 0;
@@ -471,30 +454,18 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
return 1;
#else
- /* IA64 hasn't legacy DMA */
+ /* IA64 does not have legacy DMA */
return 0;
#endif
}
-
-#if 0
-EXPORT_SYMBOL(pnp_register_dependent_option);
-EXPORT_SYMBOL(pnp_register_independent_option);
-EXPORT_SYMBOL(pnp_register_irq_resource);
-EXPORT_SYMBOL(pnp_register_dma_resource);
-EXPORT_SYMBOL(pnp_register_port_resource);
-EXPORT_SYMBOL(pnp_register_mem_resource);
-#endif /* 0 */
-
-
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
-
static int __init pnp_setup_reserve_irq(char *str)
{
int i;
for (i = 0; i < 16; i++)
- if (get_option(&str,&pnp_reserve_irq[i]) != 2)
+ if (get_option(&str, &pnp_reserve_irq[i]) != 2)
break;
return 1;
}
@@ -502,13 +473,12 @@ static int __init pnp_setup_reserve_irq(char *str)
__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
/* format is: pnp_reserve_dma=dma1[,dma2] .... */
-
static int __init pnp_setup_reserve_dma(char *str)
{
int i;
for (i = 0; i < 8; i++)
- if (get_option(&str,&pnp_reserve_dma[i]) != 2)
+ if (get_option(&str, &pnp_reserve_dma[i]) != 2)
break;
return 1;
}
@@ -516,13 +486,12 @@ static int __init pnp_setup_reserve_dma(char *str)
__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
-
static int __init pnp_setup_reserve_io(char *str)
{
int i;
for (i = 0; i < 16; i++)
- if (get_option(&str,&pnp_reserve_io[i]) != 2)
+ if (get_option(&str, &pnp_reserve_io[i]) != 2)
break;
return 1;
}
@@ -530,13 +499,12 @@ static int __init pnp_setup_reserve_io(char *str)
__setup("pnp_reserve_io=", pnp_setup_reserve_io);
/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
-
static int __init pnp_setup_reserve_mem(char *str)
{
int i;
for (i = 0; i < 16; i++)
- if (get_option(&str,&pnp_reserve_mem[i]) != 2)
+ if (get_option(&str, &pnp_reserve_mem[i]) != 2)
break;
return 1;
}
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 946a0dcd627d..13c608f5fb30 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -1,8 +1,7 @@
/*
- * support.c - provides standard pnp functions for the use of pnp protocol drivers,
+ * support.c - standard functions for the use of pnp protocol drivers
*
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
- *
*/
#include <linux/module.h>
@@ -11,22 +10,18 @@
#include "base.h"
/**
- * pnp_is_active - Determines if a device is active based on its current resources
+ * pnp_is_active - Determines if a device is active based on its current
+ * resources
* @dev: pointer to the desired PnP device
- *
*/
-
-int pnp_is_active(struct pnp_dev * dev)
+int pnp_is_active(struct pnp_dev *dev)
{
if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
!pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
- pnp_irq(dev, 0) == -1 &&
- pnp_dma(dev, 0) == -1)
- return 0;
+ pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
+ return 0;
else
return 1;
}
-
-
EXPORT_SYMBOL(pnp_is_active);
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index a8a95540b1ef..a06f980b3ac9 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -16,13 +16,14 @@
static const struct pnp_device_id pnp_dev_table[] = {
/* General ID for reserving resources */
- { "PNP0c02", 0 },
+ {"PNP0c02", 0},
/* memory controller */
- { "PNP0c01", 0 },
- { "", 0 }
+ {"PNP0c01", 0},
+ {"", 0}
};
-static void reserve_range(const char *pnpid, resource_size_t start, resource_size_t end, int port)
+static void reserve_range(const char *pnpid, resource_size_t start,
+ resource_size_t end, int port)
{
struct resource *res;
char *regionid;
@@ -32,9 +33,9 @@ static void reserve_range(const char *pnpid, resource_size_t start, resource_siz
return;
snprintf(regionid, 16, "pnp %s", pnpid);
if (port)
- res = request_region(start, end-start+1, regionid);
+ res = request_region(start, end - start + 1, regionid);
else
- res = request_mem_region(start, end-start+1, regionid);
+ res = request_mem_region(start, end - start + 1, regionid);
if (res == NULL)
kfree(regionid);
else
@@ -44,11 +45,10 @@ static void reserve_range(const char *pnpid, resource_size_t start, resource_siz
* example do reserve stuff they know about too, so we may well
* have double reservations.
*/
- printk(KERN_INFO
- "pnp: %s: %s range 0x%llx-0x%llx %s reserved\n",
- pnpid, port ? "ioport" : "iomem",
- (unsigned long long)start, (unsigned long long)end,
- NULL != res ? "has been" : "could not be");
+ printk(KERN_INFO "pnp: %s: %s range 0x%llx-0x%llx %s reserved\n",
+ pnpid, port ? "ioport" : "iomem",
+ (unsigned long long)start, (unsigned long long)end,
+ NULL != res ? "has been" : "could not be");
}
static void reserve_resources_of_dev(const struct pnp_dev *dev)
@@ -74,7 +74,7 @@ static void reserve_resources_of_dev(const struct pnp_dev *dev)
continue; /* invalid */
reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
- pnp_port_end(dev, i), 1);
+ pnp_port_end(dev, i), 1);
}
for (i = 0; i < PNP_MAX_MEM; i++) {
@@ -82,24 +82,22 @@ static void reserve_resources_of_dev(const struct pnp_dev *dev)
continue;
reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
- pnp_mem_end(dev, i), 0);
+ pnp_mem_end(dev, i), 0);
}
-
- return;
}
-static int system_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
+static int system_pnp_probe(struct pnp_dev *dev,
+ const struct pnp_device_id *dev_id)
{
reserve_resources_of_dev(dev);
return 0;
}
static struct pnp_driver system_pnp_driver = {
- .name = "system",
- .id_table = pnp_dev_table,
- .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
- .probe = system_pnp_probe,
- .remove = NULL,
+ .name = "system",
+ .id_table = pnp_dev_table,
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .probe = system_pnp_probe,
};
static int __init pnp_system_init(void)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3f6e176e6ea1..58c806e9c58a 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -38,7 +38,7 @@ config BATTERY_DS2760
config BATTERY_PMU
tristate "Apple PMU battery"
- depends on ADB_PMU
+ depends on PPC32 && ADB_PMU
help
Say Y here to expose battery information on Apple machines
through the generic battery class.
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index a9880d468ee4..f38ba482be75 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -14,8 +14,7 @@
extern int power_supply_create_attrs(struct power_supply *psy);
extern void power_supply_remove_attrs(struct power_supply *psy);
-extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
#else
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index c7c4574729b1..249f61bae639 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp)
return ret;
}
-int power_supply_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct power_supply *psy = dev_get_drvdata(dev);
- int i = 0, length = 0, ret = 0, j;
+ int ret = 0, j;
char *prop_buf;
char *attrname;
@@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_NAME=%s", psy->name);
+ ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
if (ret)
return ret;
@@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_%s=%s",
- attrname, prop_buf);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
@@ -282,9 +278,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_%s=%s",
- attrname, prop_buf);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index f935c1f71a58..44420723a359 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -297,11 +297,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
struct rio_switch *rswitch;
int result, rdid;
- rdev = kmalloc(sizeof(struct rio_dev), GFP_KERNEL);
+ rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL);
if (!rdev)
goto out;
- memset(rdev, 0, sizeof(struct rio_dev));
rdev->net = net;
rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
&result);
@@ -801,9 +800,8 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
{
struct rio_net *net;
- net = kmalloc(sizeof(struct rio_net), GFP_KERNEL);
+ net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
if (net) {
- memset(net, 0, sizeof(struct rio_net));
INIT_LIST_HEAD(&net->node);
INIT_LIST_HEAD(&net->devices);
INIT_LIST_HEAD(&net->mports);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cea401feb0f3..ff9e35cb308d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -2,15 +2,13 @@
# RTC class/drivers configuration
#
-menu "Real Time Clock"
- depends on !S390
-
config RTC_LIB
tristate
-config RTC_CLASS
- tristate "RTC class"
+menuconfig RTC_CLASS
+ tristate "Real Time Clock"
default n
+ depends on !S390
select RTC_LIB
help
Generic RTC class support. If you say yes here, you will
@@ -20,6 +18,8 @@ config RTC_CLASS
This driver can also be built as a module. If so, the module
will be called rtc-class.
+if RTC_CLASS
+
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
depends on RTC_CLASS = y
@@ -38,6 +38,9 @@ config RTC_HCTOSYS_DEVICE
clock, usually rtc0. Initialization is done when the system
starts up, and when it resumes from a low power state.
+ The driver for this RTC device must be loaded before late_initcall
+ functions run, so it must usually be statically linked.
+
This clock should be battery-backed, so that it reads the correct
time when the system boots from a power-off state. Otherwise, your
system will need an external clock source (like an NTP server).
@@ -55,11 +58,10 @@ config RTC_DEBUG
and individual RTC drivers.
comment "RTC interfaces"
- depends on RTC_CLASS
config RTC_INTF_SYSFS
boolean "/sys/class/rtc/rtcN (sysfs)"
- depends on RTC_CLASS && SYSFS
+ depends on SYSFS
default RTC_CLASS
help
Say yes here if you want to use your RTCs using sysfs interfaces,
@@ -70,7 +72,7 @@ config RTC_INTF_SYSFS
config RTC_INTF_PROC
boolean "/proc/driver/rtc (procfs for rtc0)"
- depends on RTC_CLASS && PROC_FS
+ depends on PROC_FS
default RTC_CLASS
help
Say yes here if you want to use your first RTC through the proc
@@ -82,7 +84,6 @@ config RTC_INTF_PROC
config RTC_INTF_DEV
boolean "/dev/rtcN (character devices)"
- depends on RTC_CLASS
default RTC_CLASS
help
Say yes here if you want to use your RTCs using the /dev
@@ -104,7 +105,6 @@ config RTC_INTF_DEV_UIE_EMUL
config RTC_DRV_TEST
tristate "Test driver/device"
- depends on RTC_CLASS
help
If you say yes here you get support for the
RTC test driver. It's a software RTC which can be
@@ -118,11 +118,12 @@ config RTC_DRV_TEST
will be called rtc-test.
comment "I2C RTC drivers"
- depends on RTC_CLASS && I2C
+ depends on I2C
+
+if I2C
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for various compatible RTC
chips (often with battery backup) connected with I2C. This driver
@@ -140,7 +141,6 @@ config RTC_DRV_DS1307
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Dallas/Maxim DS1672 timekeeping chip.
@@ -150,7 +150,6 @@ config RTC_DRV_DS1672
config RTC_DRV_MAX6900
tristate "Maxim 6900"
- depends on RTC_CLASS && I2C
help
If you say yes here you will get support for the
Maxim MAX6900 I2C RTC chip.
@@ -160,7 +159,6 @@ config RTC_DRV_MAX6900
config RTC_DRV_RS5C372
tristate "Ricoh RS5C372A/B, RV5C386, RV5C387A"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Ricoh RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips.
@@ -170,7 +168,6 @@ config RTC_DRV_RS5C372
config RTC_DRV_ISL1208
tristate "Intersil 1208"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Intersil 1208 RTC chip.
@@ -180,7 +177,6 @@ config RTC_DRV_ISL1208
config RTC_DRV_X1205
tristate "Xicor/Intersil X1205"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Xicor/Intersil X1205 RTC chip.
@@ -190,7 +186,6 @@ config RTC_DRV_X1205
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Philips PCF8563 RTC chip. The Epson RTC8564
@@ -201,7 +196,6 @@ config RTC_DRV_PCF8563
config RTC_DRV_PCF8583
tristate "Philips PCF8583"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the Philips PCF8583
RTC chip found on Acorn RiscPCs. This driver supports the
@@ -214,7 +208,6 @@ config RTC_DRV_PCF8583
config RTC_DRV_M41T80
tristate "ST M41T80 series RTC"
- depends on RTC_CLASS && I2C
help
If you say Y here you will get support for the
ST M41T80 RTC chips series. Currently following chips are
@@ -233,19 +226,21 @@ config RTC_DRV_M41T80_WDT
config RTC_DRV_TWL92330
boolean "TI TWL92330/Menelaus"
- depends on RTC_CLASS && I2C && MENELAUS
+ depends on MENELAUS
help
If you say yes here you get support for the RTC on the
TWL92330 "Menelaus" power mangement chip, used with OMAP2
platforms. The support is integrated with the rest of
the Menelaus driver; it's not separate module.
+endif # I2C
+
comment "SPI RTC drivers"
- depends on RTC_CLASS && SPI_MASTER
+
+if SPI_MASTER
config RTC_DRV_RS5C348
tristate "Ricoh RS5C348A/B"
- depends on RTC_CLASS && SPI_MASTER
help
If you say yes here you get support for the
Ricoh RS5C348A and RS5C348B RTC chips.
@@ -255,7 +250,6 @@ config RTC_DRV_RS5C348
config RTC_DRV_MAX6902
tristate "Maxim 6902"
- depends on RTC_CLASS && SPI_MASTER
help
If you say yes here you will get support for the
Maxim MAX6902 SPI RTC chip.
@@ -263,8 +257,9 @@ config RTC_DRV_MAX6902
This driver can also be built as a module. If so, the module
will be called rtc-max6902.
+endif # SPI_MASTER
+
comment "Platform RTC drivers"
- depends on RTC_CLASS
# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
@@ -272,8 +267,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
- depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
- || M32R || ATARI || PPC || MIPS)
+ depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
help
Say "yes" here to get direct support for the real time clock
found in every PC or ACPI-based system, and some other boards.
@@ -291,13 +285,12 @@ config RTC_DRV_CMOS
config RTC_DRV_DS1216
tristate "Dallas DS1216"
- depends on RTC_CLASS && SNI_RM
+ depends on SNI_RM
help
If you say yes here you get support for the Dallas DS1216 RTC chips.
config RTC_DRV_DS1553
tristate "Dallas DS1553"
- depends on RTC_CLASS
help
If you say yes here you get support for the
Dallas DS1553 timekeeping chip.
@@ -305,9 +298,18 @@ config RTC_DRV_DS1553
This driver can also be built as a module. If so, the module
will be called rtc-ds1553.
+config RTC_DRV_STK17TA8
+ tristate "Simtek STK17TA8"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Simtek STK17TA8 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-stk17ta8.
+
config RTC_DRV_DS1742
tristate "Dallas DS1742/1743"
- depends on RTC_CLASS
help
If you say yes here you get support for the
Dallas DS1742/1743 timekeeping chip.
@@ -317,7 +319,6 @@ config RTC_DRV_DS1742
config RTC_DRV_M48T86
tristate "ST M48T86/Dallas DS12887"
- depends on RTC_CLASS
help
If you say Y here you will get support for the
ST M48T86 and Dallas DS12887 RTC chips.
@@ -327,7 +328,6 @@ config RTC_DRV_M48T86
config RTC_DRV_M48T59
tristate "ST M48T59"
- depends on RTC_CLASS
help
If you say Y here you will get support for the
ST M48T59 RTC chip.
@@ -337,7 +337,6 @@ config RTC_DRV_M48T59
config RTC_DRV_V3020
tristate "EM Microelectronic V3020"
- depends on RTC_CLASS
help
If you say yes here you will get support for the
EM Microelectronic v3020 RTC chip.
@@ -346,19 +345,17 @@ config RTC_DRV_V3020
will be called rtc-v3020.
comment "on-CPU RTC drivers"
- depends on RTC_CLASS
config RTC_DRV_OMAP
tristate "TI OMAP1"
- depends on RTC_CLASS && ( \
- ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+ depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730
help
Say "yes" here to support the real time clock on TI OMAP1 chips.
This driver can also be built as a module called rtc-omap.
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
- depends on RTC_CLASS && ARCH_S3C2410
+ depends on ARCH_S3C2410
help
RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic
@@ -374,7 +371,7 @@ config RTC_DRV_S3C
config RTC_DRV_EP93XX
tristate "Cirrus Logic EP93XX"
- depends on RTC_CLASS && ARCH_EP93XX
+ depends on ARCH_EP93XX
help
If you say yes here you get support for the
RTC embedded in the Cirrus Logic EP93XX processors.
@@ -384,7 +381,7 @@ config RTC_DRV_EP93XX
config RTC_DRV_SA1100
tristate "SA11x0/PXA2xx"
- depends on RTC_CLASS && (ARCH_SA1100 || ARCH_PXA)
+ depends on ARCH_SA1100 || ARCH_PXA
help
If you say Y here you will get access to the real time clock
built into your SA11x0 or PXA2xx CPU.
@@ -394,7 +391,7 @@ config RTC_DRV_SA1100
config RTC_DRV_SH
tristate "SuperH On-Chip RTC"
- depends on RTC_CLASS && SUPERH
+ depends on RTC_CLASS && (CPU_SH3 || CPU_SH4)
help
Say Y here to enable support for the on-chip RTC found in
most SuperH processors.
@@ -404,7 +401,7 @@ config RTC_DRV_SH
config RTC_DRV_VR41XX
tristate "NEC VR41XX"
- depends on RTC_CLASS && CPU_VR41XX
+ depends on CPU_VR41XX
help
If you say Y here you will get access to the real time clock
built into your NEC VR41XX CPU.
@@ -414,7 +411,7 @@ config RTC_DRV_VR41XX
config RTC_DRV_PL031
tristate "ARM AMBA PL031 RTC"
- depends on RTC_CLASS && ARM_AMBA
+ depends on ARM_AMBA
help
If you say Y here you will get access to ARM AMBA
PrimeCell PL031 RTC found on certain ARM SOCs.
@@ -424,20 +421,20 @@ config RTC_DRV_PL031
config RTC_DRV_AT32AP700X
tristate "AT32AP700X series RTC"
- depends on RTC_CLASS && PLATFORM_AT32AP
+ depends on PLATFORM_AT32AP
help
Driver for the internal RTC (Realtime Clock) on Atmel AVR32
AT32AP700x family processors.
config RTC_DRV_AT91RM9200
tristate "AT91RM9200"
- depends on RTC_CLASS && ARCH_AT91RM9200
+ depends on ARCH_AT91RM9200
help
Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
config RTC_DRV_BFIN
tristate "Blackfin On-Chip RTC"
- depends on RTC_CLASS && BFIN
+ depends on BFIN
help
If you say yes here you will get support for the
Blackfin On-Chip Real Time Clock.
@@ -447,8 +444,8 @@ config RTC_DRV_BFIN
config RTC_DRV_RS5C313
tristate "Ricoh RS5C313"
- depends on RTC_CLASS && SH_LANDISK
+ depends on SH_LANDISK
help
If you say yes here you get support for the Ricoh RS5C313 RTC chips.
-endmenu
+endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 3109af9a1651..d3a33aa2696f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -15,33 +15,36 @@ rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
+# Keep the list ordered.
+
+obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
+obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
-obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
-obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
-obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
-obj-$(CONFIG_RTC_DRV_AT32AP700X) += rtc-at32ap700x.o
+obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
+obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
+obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
+obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
+obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
+obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
+obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
+obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
+obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
-obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
-obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
-obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
-obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
-obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
-obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
-obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
-obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
-obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
-obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
-obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
-obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
-obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
-obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
-obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
+obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 8b3cd31d6a61..10ab3b71ffc6 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -46,6 +46,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
+ struct timespec ts = current_kernel_time();
if (strncmp(rtc->dev.bus_id,
CONFIG_RTC_HCTOSYS_DEVICE,
@@ -57,8 +58,8 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
/* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
set_normalized_timespec(&delta,
- xtime.tv_sec - oldtime,
- xtime.tv_nsec - (NSEC_PER_SEC >> 1));
+ ts.tv_sec - oldtime,
+ ts.tv_nsec - (NSEC_PER_SEC >> 1));
return 0;
}
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 260ead959918..1aa709dda0d6 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -1,6 +1,6 @@
/*
* Blackfin On-Chip Real Time Clock Driver
- * Supports BF531/BF532/BF533/BF534/BF536/BF537
+ * Supports BF53[123]/BF53[467]/BF54[2489]
*
* Copyright 2004-2007 Analog Devices Inc.
*
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e24ea82dc35b..5d760bb6c2cd 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -235,7 +235,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0;
}
-static int cmos_set_freq(struct device *dev, int freq)
+static int cmos_irq_set_freq(struct device *dev, int freq)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
int f;
@@ -259,6 +259,34 @@ static int cmos_set_freq(struct device *dev, int freq)
return 0;
}
+static int cmos_irq_set_state(struct device *dev, int enabled)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char rtc_control, rtc_intr;
+ unsigned long flags;
+
+ if (!is_valid_irq(cmos->irq))
+ return -ENXIO;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+
+ if (enabled)
+ rtc_control |= RTC_PIE;
+ else
+ rtc_control &= ~RTC_PIE;
+
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+
+ rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(rtc_intr))
+ rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+}
+
#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
static int
@@ -360,7 +388,8 @@ static const struct rtc_class_ops cmos_rtc_ops = {
.read_alarm = cmos_read_alarm,
.set_alarm = cmos_set_alarm,
.proc = cmos_procfs,
- .irq_set_freq = cmos_set_freq,
+ .irq_set_freq = cmos_irq_set_freq,
+ .irq_set_state = cmos_irq_set_state,
};
/*----------------------------------------------------------------*/
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 304535942de2..005fff3a3508 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -348,6 +348,8 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
case RTC_IRQP_SET:
if (ops->irq_set_freq)
err = rtc_irq_set_freq(rtc, rtc->irq_task, arg);
+ else
+ err = -ENOTTY;
break;
#if 0
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 5158a625671f..db6f3f0d8982 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -352,7 +352,7 @@ read_rtc:
/* oscillator fault? clear flag, and warn */
if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL,
- ds1307->regs[DS1337_REG_CONTROL]
+ ds1307->regs[DS1307_REG_CONTROL]
& ~DS1338_BIT_OSF);
dev_warn(&client->dev, "SET TIME!\n");
goto read_rtc;
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index f98a83a11aae..5ab3492817d1 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -61,7 +61,7 @@
struct rtc_plat_data {
struct rtc_device *rtc;
void __iomem *ioaddr;
- unsigned long baseaddr;
+ resource_size_t baseaddr;
unsigned long last_jiffies;
int irq;
unsigned int irqen;
@@ -407,7 +407,7 @@ static __init int ds1553_init(void)
static __exit void ds1553_exit(void)
{
- return platform_driver_unregister(&ds1553_rtc_driver);
+ platform_driver_unregister(&ds1553_rtc_driver);
}
module_init(ds1553_init);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index d1778ae8bca5..67291b0f8283 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -55,7 +55,7 @@ struct rtc_plat_data {
void __iomem *ioaddr_rtc;
size_t size_nvram;
size_t size;
- unsigned long baseaddr;
+ resource_size_t baseaddr;
unsigned long last_jiffies;
};
@@ -263,7 +263,7 @@ static __init int ds1742_init(void)
static __exit void ds1742_exit(void)
{
- return platform_driver_unregister(&ds1742_rtc_driver);
+ platform_driver_unregister(&ds1742_rtc_driver);
}
module_init(ds1742_init);
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 80c4a8463065..1cb33cac1237 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -892,7 +892,7 @@ static int m41t80_remove(struct i2c_client *client)
static struct i2c_driver m41t80_driver = {
.driver = {
- .name = "m41t80",
+ .name = "rtc-m41t80",
},
.probe = m41t80_probe,
.remove = m41t80_remove,
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 33b752350ab5..bf60d35f580b 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -35,7 +35,7 @@
struct m48t59_private {
void __iomem *ioaddr;
unsigned int size; /* iomem size */
- unsigned int irq;
+ int irq;
struct rtc_device *rtc;
spinlock_t lock; /* serialize the NVRAM and RTC access */
};
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index eee4ee5bb75a..a1cd448639c9 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -31,17 +31,24 @@
#define MAX6900_REG_DW 5 /* day of week 1-7 */
#define MAX6900_REG_YR 6 /* year 00-99 */
#define MAX6900_REG_CT 7 /* control */
-#define MAX6900_REG_LEN 8
+ /* register 8 is undocumented */
+#define MAX6900_REG_CENTURY 9 /* century */
+#define MAX6900_REG_LEN 10
+
+#define MAX6900_BURST_LEN 8 /* can burst r/w first 8 regs */
#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */
+
/*
* register read/write commands
*/
#define MAX6900_REG_CONTROL_WRITE 0x8e
-#define MAX6900_REG_BURST_READ 0xbf
-#define MAX6900_REG_BURST_WRITE 0xbe
+#define MAX6900_REG_CENTURY_WRITE 0x92
+#define MAX6900_REG_CENTURY_READ 0x93
#define MAX6900_REG_RESERVED_READ 0x96
+#define MAX6900_REG_BURST_WRITE 0xbe
+#define MAX6900_REG_BURST_READ 0xbf
#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */
@@ -58,19 +65,32 @@ static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
{
- u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
- struct i2c_msg msgs[2] = {
+ u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
+ u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
+ struct i2c_msg msgs[4] = {
{
.addr = client->addr,
.flags = 0, /* write */
- .len = sizeof(reg_addr),
- .buf = reg_addr
+ .len = sizeof(reg_burst_read),
+ .buf = reg_burst_read
},
{
.addr = client->addr,
.flags = I2C_M_RD,
- .len = MAX6900_REG_LEN,
+ .len = MAX6900_BURST_LEN,
.buf = buf
+ },
+ {
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(reg_century_read),
+ .buf = reg_century_read
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf[MAX6900_REG_CENTURY]),
+ .buf = &buf[MAX6900_REG_CENTURY]
}
};
int rc;
@@ -86,33 +106,58 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
{
- u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
- struct i2c_msg msgs[1] = {
+ u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
+ struct i2c_msg century_msgs[1] = {
{
.addr = client->addr,
.flags = 0, /* write */
- .len = MAX6900_REG_LEN + 1,
- .buf = i2c_buf
+ .len = sizeof(i2c_century_buf),
+ .buf = i2c_century_buf
+ }
+ };
+ u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+ struct i2c_msg burst_msgs[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(i2c_burst_buf),
+ .buf = i2c_burst_buf
}
};
int rc;
- memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
+ /*
+ * We have to make separate calls to i2c_transfer because of
+ * the need to delay after each write to the chip. Also,
+ * we write the century byte first, since we set the write-protect
+ * bit as part of the burst write.
+ */
+ i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+ rc = i2c_transfer(client->adapter, century_msgs,
+ ARRAY_SIZE(century_msgs));
+ if (rc != ARRAY_SIZE(century_msgs))
+ goto write_failed;
+ msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
- rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (rc != ARRAY_SIZE(msgs)) {
- dev_err(&client->dev, "%s: register write failed\n",
- __FUNCTION__);
- return -EIO;
- }
+ memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
+
+ rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
+ if (rc != ARRAY_SIZE(burst_msgs))
+ goto write_failed;
msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
return 0;
+
+write_failed:
+ dev_err(&client->dev, "%s: register write failed\n",
+ __FUNCTION__);
+ return -EIO;
}
static int max6900_i2c_validate_client(struct i2c_client *client)
{
u8 regs[MAX6900_REG_LEN];
- u8 zero_mask[MAX6900_REG_LEN] = {
+ u8 zero_mask[] = {
0x80, /* seconds */
0x80, /* minutes */
0x40, /* hours */
@@ -134,7 +179,7 @@ static int max6900_i2c_validate_client(struct i2c_client *client)
if (rc < 0)
return rc;
- for (i = 0; i < MAX6900_REG_LEN; ++i) {
+ for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
if (regs[i] & zero_mask[i])
return -ENODEV;
}
@@ -156,7 +201,8 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
- tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+ tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
+ BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
return 0;
@@ -189,9 +235,11 @@ static int max6900_i2c_set_time(struct i2c_client *client,
regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
- regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
- regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */
+ regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
+ regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
+ /* set write protect */
+ regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
rc = max6900_i2c_write_regs(client, regs);
if (rc < 0)
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index d94170728075..3e183cfee10f 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -13,7 +13,7 @@
*
* 24-May-2006: Raphael Assenat <raph@8d.com>
* - Major rework
- * Converted to rtc_device and uses the SPI layer.
+ * Converted to rtc_device and uses the SPI layer.
*
* ??-???-2005: Someone at Compulab
* - Initial driver creation.
@@ -259,11 +259,11 @@ static int __devexit max6902_remove(struct spi_device *spi)
static struct spi_driver max6902_driver = {
.driver = {
- .name = "max6902",
+ .name = "rtc-max6902",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
- .probe = max6902_probe,
+ .probe = max6902_probe,
.remove = __devexit_p(max6902_remove),
};
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index f50f3fc353cd..839462659afa 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -226,7 +226,7 @@ static int __devexit rs5c348_remove(struct spi_device *spi)
static struct spi_driver rs5c348_driver = {
.driver = {
- .name = "rs5c348",
+ .name = "rtc-rs5c348",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 54b613053468..8c1012b432bb 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -29,7 +29,7 @@
#include <asm/mach/time.h>
-#include <asm/arch/regs-rtc.h>
+#include <asm/plat-s3c/regs-rtc.h>
/* I have yet to find an S3C implementation with more than one
* of these rtc blocks in */
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index e0f91dfce0f5..93ee05eeaeba 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -365,6 +365,7 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* Reset pre-scaler & stop RTC */
tmp = readb(rtc->regbase + RCR2);
tmp |= RCR2_RESET;
+ tmp &= ~RCR2_START;
writeb(tmp, rtc->regbase + RCR2);
writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
new file mode 100644
index 000000000000..8288b6b2bf2b
--- /dev/null
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -0,0 +1,422 @@
+/*
+ * A RTC driver for the Simtek STK17TA8
+ *
+ * By Thomas Hommel <thomas.hommel@gefanuc.com>
+ *
+ * Based on the DS1553 driver from
+ * Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE 0x20000
+#define RTC_OFFSET 0x1fff0
+
+#define RTC_FLAGS (RTC_OFFSET + 0)
+#define RTC_CENTURY (RTC_OFFSET + 1)
+#define RTC_SECONDS_ALARM (RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM (RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM (RTC_OFFSET + 4)
+#define RTC_DATE_ALARM (RTC_OFFSET + 5)
+#define RTC_INTERRUPTS (RTC_OFFSET + 6)
+#define RTC_WATCHDOG (RTC_OFFSET + 7)
+#define RTC_CALIBRATION (RTC_OFFSET + 8)
+#define RTC_SECONDS (RTC_OFFSET + 9)
+#define RTC_MINUTES (RTC_OFFSET + 10)
+#define RTC_HOURS (RTC_OFFSET + 11)
+#define RTC_DAY (RTC_OFFSET + 12)
+#define RTC_DATE (RTC_OFFSET + 13)
+#define RTC_MONTH (RTC_OFFSET + 14)
+#define RTC_YEAR (RTC_OFFSET + 15)
+
+#define RTC_SECONDS_MASK 0x7f
+#define RTC_DAY_MASK 0x07
+#define RTC_CAL_MASK 0x3f
+
+/* Bits in the Calibration register */
+#define RTC_STOP 0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF 0x40
+#define RTC_FLAGS_PF 0x20
+#define RTC_WRITE 0x02
+#define RTC_READ 0x01
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AIE 0x40
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ unsigned long baseaddr;
+ unsigned long last_jiffies;
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ u8 flags;
+
+ flags = readb(pdata->ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+
+ writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+ writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
+
+ writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+ return 0;
+}
+
+static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned int year, month, day, hour, minute, second, week;
+ unsigned int century;
+ u8 flags;
+
+ /* give enough time to update RTC in case of continuous read */
+ if (pdata->last_jiffies == jiffies)
+ msleep(1);
+ pdata->last_jiffies = jiffies;
+
+ flags = readb(pdata->ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
+ second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+ minute = readb(ioaddr + RTC_MINUTES);
+ hour = readb(ioaddr + RTC_HOURS);
+ day = readb(ioaddr + RTC_DATE);
+ week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+ month = readb(ioaddr + RTC_MONTH);
+ year = readb(ioaddr + RTC_YEAR);
+ century = readb(ioaddr + RTC_CENTURY);
+ writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
+ tm->tm_sec = BCD2BIN(second);
+ tm->tm_min = BCD2BIN(minute);
+ tm->tm_hour = BCD2BIN(hour);
+ tm->tm_mday = BCD2BIN(day);
+ tm->tm_wday = BCD2BIN(week);
+ tm->tm_mon = BCD2BIN(month) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+ return 0;
+}
+
+static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long irqflags;
+ u8 flags;
+
+ spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags);
+
+ flags = readb(ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+
+ writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_mday),
+ ioaddr + RTC_DATE_ALARM);
+ writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_hour),
+ ioaddr + RTC_HOURS_ALARM);
+ writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_min),
+ ioaddr + RTC_MINUTES_ALARM);
+ writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_sec),
+ ioaddr + RTC_SECONDS_ALARM);
+ writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
+ readb(ioaddr + RTC_FLAGS); /* clear interrupts */
+ writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags);
+}
+
+static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ pdata->alrm_mday = alrm->time.tm_mday;
+ pdata->alrm_hour = alrm->time.tm_hour;
+ pdata->alrm_min = alrm->time.tm_min;
+ pdata->alrm_sec = alrm->time.tm_sec;
+ if (alrm->enabled)
+ pdata->irqen |= RTC_AF;
+ stk17ta8_rtc_update_alarm(pdata);
+ return 0;
+}
+
+static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+ alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+ alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+ alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+ alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+ return 0;
+}
+
+static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long events = RTC_IRQF;
+
+ /* read and clear interrupt */
+ if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+ return IRQ_NONE;
+ if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+ events |= RTC_UF;
+ else
+ events |= RTC_AF;
+ rtc_update_irq(pdata->rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+static void stk17ta8_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq >= 0) {
+ pdata->irqen = 0;
+ stk17ta8_rtc_update_alarm(pdata);
+ }
+}
+
+static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ pdata->irqen &= ~RTC_AF;
+ stk17ta8_rtc_update_alarm(pdata);
+ break;
+ case RTC_AIE_ON:
+ pdata->irqen |= RTC_AF;
+ stk17ta8_rtc_update_alarm(pdata);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops stk17ta8_rtc_ops = {
+ .read_time = stk17ta8_rtc_read_time,
+ .set_time = stk17ta8_rtc_set_time,
+ .read_alarm = stk17ta8_rtc_read_alarm,
+ .set_alarm = stk17ta8_rtc_set_alarm,
+ .release = stk17ta8_rtc_release,
+ .ioctl = stk17ta8_rtc_ioctl,
+};
+
+static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ *buf++ = readb(ioaddr + pos++);
+ return count;
+}
+
+static ssize_t stk17ta8_nvram_write(struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ writeb(*buf++, ioaddr + pos++);
+ return count;
+}
+
+static struct bin_attribute stk17ta8_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = RTC_OFFSET,
+ .read = stk17ta8_nvram_read,
+ .write = stk17ta8_nvram_write,
+};
+
+static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ unsigned int cal;
+ unsigned int flags;
+ struct rtc_plat_data *pdata;
+ void __iomem *ioaddr = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ pdata->irq = -1;
+ if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+ if (!ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ioaddr;
+ pdata->irq = platform_get_irq(pdev, 0);
+
+ /* turn RTC on if it was not on */
+ cal = readb(ioaddr + RTC_CALIBRATION);
+ if (cal & RTC_STOP) {
+ cal &= RTC_CAL_MASK;
+ flags = readb(ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+ writeb(cal, ioaddr + RTC_CALIBRATION);
+ writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+ }
+ if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ if (pdata->irq >= 0) {
+ writeb(0, ioaddr + RTC_INTERRUPTS);
+ if (request_irq(pdata->irq, stk17ta8_rtc_interrupt,
+ IRQF_DISABLED | IRQF_SHARED,
+ pdev->name, pdev) < 0) {
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &stk17ta8_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+ if (ret)
+ goto out;
+ return 0;
+ out:
+ if (pdata->rtc)
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0) {
+ writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+ free_irq(pdata->irq, pdev);
+ }
+ iounmap(pdata->ioaddr);
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver stk17ta8_rtc_driver = {
+ .probe = stk17ta8_rtc_probe,
+ .remove = __devexit_p(stk17ta8_rtc_remove),
+ .driver = {
+ .name = "stk17ta8",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int stk17ta8_init(void)
+{
+ return platform_driver_register(&stk17ta8_rtc_driver);
+}
+
+static __exit void stk17ta8_exit(void)
+{
+ return platform_driver_unregister(&stk17ta8_rtc_driver);
+}
+
+module_init(stk17ta8_init);
+module_exit(stk17ta8_exit);
+
+MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
+MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 3b58d3d5d38a..a6b572978dc0 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -26,6 +26,7 @@
#include <linux/types.h>
#include <linux/bcd.h>
#include <linux/rtc-v3020.h>
+#include <linux/delay.h>
#include <asm/io.h>
@@ -47,6 +48,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
for (i = 0; i < 4; i++) {
writel((tmp & 1) << chip->leftshift, chip->ioaddress);
tmp >>= 1;
+ udelay(1);
}
/* Commands dont have data */
@@ -54,6 +56,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address,
for (i = 0; i < 8; i++) {
writel((data & 1) << chip->leftshift, chip->ioaddress);
data >>= 1;
+ udelay(1);
}
}
}
@@ -66,12 +69,14 @@ static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
for (i = 0; i < 4; i++) {
writel((address & 1) << chip->leftshift, chip->ioaddress);
address >>= 1;
+ udelay(1);
}
for (i = 0; i < 8; i++) {
data >>= 1;
if (readl(chip->ioaddress) & (1 << chip->leftshift))
data |= 0x80;
+ udelay(1);
}
return data;
@@ -95,7 +100,7 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt)
tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
dt->tm_mday = BCD2BIN(tmp);
tmp = v3020_get_reg(chip, V3020_MONTH);
- dt->tm_mon = BCD2BIN(tmp);
+ dt->tm_mon = BCD2BIN(tmp) - 1;
tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
dt->tm_wday = BCD2BIN(tmp);
tmp = v3020_get_reg(chip, V3020_YEAR);
@@ -135,7 +140,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min));
v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour));
v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday));
- v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon));
+ v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon + 1));
v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday));
v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100));
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index bfeca57098fa..e6bfce690ca3 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1187,7 +1187,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
static void
__dasd_process_blk_queue(struct dasd_device * device)
{
- request_queue_t *queue;
+ struct request_queue *queue;
struct request *req;
struct dasd_ccw_req *cqr;
int nr_queued;
@@ -1740,7 +1740,7 @@ dasd_cancel_req(struct dasd_ccw_req *cqr)
* Dasd request queue function. Called from ll_rw_blk.c
*/
static void
-do_dasd_request(request_queue_t * queue)
+do_dasd_request(struct request_queue * queue)
{
struct dasd_device *device;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 6a89cefe99bb..0c67258fb9ec 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -291,7 +291,7 @@ dasd_parse_keyword( char *parsestring ) {
dasd_page_cache =
kmem_cache_create("dasd_page_cache", PAGE_SIZE,
PAGE_SIZE, SLAB_CACHE_DMA,
- NULL, NULL );
+ NULL);
if (!dasd_page_cache)
MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
"fixed buffer mode disabled.");
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index eccac1c3b71b..571320ab9e1a 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -24,6 +24,7 @@
#include <asm/s390_ext.h>
#include <asm/todclk.h>
#include <asm/vtoc.h>
+#include <asm/diag.h>
#include "dasd_int.h"
#include "dasd_diag.h"
@@ -471,14 +472,13 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
struct dasd_ccw_req *cqr;
struct dasd_diag_req *dreq;
struct dasd_diag_bio *dbio;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst;
unsigned int count, datasize;
sector_t recid, first_rec, last_rec;
unsigned int blksize, off;
unsigned char rw_cmd;
- int i;
if (rq_data_dir(req) == READ)
rw_cmd = MDSK_READ_REQ;
@@ -492,13 +492,11 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
/* Check struct bio and count the number of blocks for the request. */
count = 0;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- if (bv->bv_len & (blksize - 1))
- /* Fba can only do full blocks. */
- return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (device->s2b_shift + 9);
- }
+ rq_for_each_segment(bv, req, iter) {
+ if (bv->bv_len & (blksize - 1))
+ /* Fba can only do full blocks. */
+ return ERR_PTR(-EINVAL);
+ count += bv->bv_len >> (device->s2b_shift + 9);
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -515,18 +513,16 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
dreq->block_count = count;
dbio = dreq->bio;
recid = first_rec;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len; off += blksize) {
- memset(dbio, 0, sizeof (struct dasd_diag_bio));
- dbio->type = rw_cmd;
- dbio->block_number = recid + 1;
- dbio->buffer = dst;
- dbio++;
- dst += blksize;
- recid++;
- }
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += blksize) {
+ memset(dbio, 0, sizeof (struct dasd_diag_bio));
+ dbio->type = rw_cmd;
+ dbio->block_number = recid + 1;
+ dbio->buffer = dst;
+ dbio++;
+ dst += blksize;
+ recid++;
}
}
cqr->retries = DIAG_MAX_RETRIES;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 418b4e63a4fa..44adf8496bda 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -555,7 +555,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
if (conf_data == NULL) {
MESSAGE(KERN_WARNING, "%s", "No configuration "
"data retrieved");
- continue; /* no errror */
+ continue; /* no error */
}
if (conf_len != sizeof (struct dasd_eckd_confdata)) {
MESSAGE(KERN_WARNING,
@@ -564,7 +564,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
conf_len,
sizeof (struct dasd_eckd_confdata));
kfree(conf_data);
- continue; /* no errror */
+ continue; /* no error */
}
/* save first valid configuration data */
if (!conf_data_saved){
@@ -1176,7 +1176,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
struct LO_eckd_data *LO_data;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst;
unsigned int blksize, blk_per_trk, off;
@@ -1185,7 +1185,6 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
sector_t first_trk, last_trk;
unsigned int first_offs, last_offs;
unsigned char cmd, rcmd;
- int i;
private = (struct dasd_eckd_private *) device->private;
if (rq_data_dir(req) == READ)
@@ -1206,18 +1205,15 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
/* Check struct bio and count the number of blocks for the request. */
count = 0;
cidaw = 0;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- if (bv->bv_len & (blksize - 1))
- /* Eckd can only do full blocks. */
- return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (device->s2b_shift + 9);
+ rq_for_each_segment(bv, req, iter) {
+ if (bv->bv_len & (blksize - 1))
+ /* Eckd can only do full blocks. */
+ return ERR_PTR(-EINVAL);
+ count += bv->bv_len >> (device->s2b_shift + 9);
#if defined(CONFIG_64BIT)
- if (idal_is_needed (page_address(bv->bv_page),
- bv->bv_len))
- cidaw += bv->bv_len >> (device->s2b_shift + 9);
+ if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+ cidaw += bv->bv_len >> (device->s2b_shift + 9);
#endif
- }
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -1257,7 +1253,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
last_rec - recid + 1, cmd, device, blksize);
}
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
if (dasd_page_cache) {
char *copy = kmem_cache_alloc(dasd_page_cache,
@@ -1328,12 +1324,12 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
struct dasd_eckd_private *private;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst, *cda;
unsigned int blksize, blk_per_trk, off;
sector_t recid;
- int i, status;
+ int status;
if (!dasd_page_cache)
goto out;
@@ -1346,7 +1342,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
ccw++;
if (private->uses_cdl == 0 || recid > 2*blk_per_trk)
ccw++;
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
for (off = 0; off < bv->bv_len; off += blksize) {
/* Skip locate record. */
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index da16ead8aff2..1d95822e0b8e 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -234,14 +234,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
struct LO_fba_data *LO_data;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst;
int count, cidaw, cplength, datasize;
sector_t recid, first_rec, last_rec;
unsigned int blksize, off;
unsigned char cmd;
- int i;
private = (struct dasd_fba_private *) device->private;
if (rq_data_dir(req) == READ) {
@@ -257,18 +256,15 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
/* Check struct bio and count the number of blocks for the request. */
count = 0;
cidaw = 0;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- if (bv->bv_len & (blksize - 1))
- /* Fba can only do full blocks. */
- return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (device->s2b_shift + 9);
+ rq_for_each_segment(bv, req, iter) {
+ if (bv->bv_len & (blksize - 1))
+ /* Fba can only do full blocks. */
+ return ERR_PTR(-EINVAL);
+ count += bv->bv_len >> (device->s2b_shift + 9);
#if defined(CONFIG_64BIT)
- if (idal_is_needed (page_address(bv->bv_page),
- bv->bv_len))
- cidaw += bv->bv_len / blksize;
+ if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+ cidaw += bv->bv_len / blksize;
#endif
- }
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -304,7 +300,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count);
}
recid = first_rec;
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
if (dasd_page_cache) {
char *copy = kmem_cache_alloc(dasd_page_cache,
@@ -359,11 +355,11 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
struct dasd_fba_private *private;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst, *cda;
unsigned int blksize, off;
- int i, status;
+ int status;
if (!dasd_page_cache)
goto out;
@@ -374,7 +370,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
ccw++;
if (private->rdc_data.mode.bits.data_chain != 0)
ccw++;
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
for (off = 0; off < bv->bv_len; off += blksize) {
/* Skip locate record. */
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 241294cba415..d427daeef511 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -53,6 +53,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
+#include <linux/log2.h>
#include <asm/ccwdev.h>
#include <linux/workqueue.h>
#include <asm/debug.h>
@@ -293,7 +294,7 @@ struct dasd_uid {
struct dasd_device {
/* Block device stuff. */
struct gendisk *gdp;
- request_queue_t *request_queue;
+ struct request_queue *request_queue;
spinlock_t request_queue_lock;
struct block_device *bdev;
unsigned int devindex;
@@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem)
static inline int
dasd_check_blocksize(int bsize)
{
- if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+ if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
return -EMEDIUMTYPE;
return 0;
}
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 35765f6a86e0..859f870552e3 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -621,7 +621,7 @@ out:
}
static int
-dcssblk_make_request(request_queue_t *q, struct bio *bio)
+dcssblk_make_request(struct request_queue *q, struct bio *bio)
{
struct dcssblk_dev_info *dev_info;
struct bio_vec *bvec;
@@ -674,10 +674,10 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
}
bytes_done += bvec->bv_len;
}
- bio_endio(bio, bytes_done, 0);
+ bio_endio(bio, 0);
return 0;
fail:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index a04d9120cef0..f231bc21b1ca 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -191,7 +191,7 @@ static unsigned long __init xpram_highest_page_index(void)
/*
* Block device make request function.
*/
-static int xpram_make_request(request_queue_t *q, struct bio *bio)
+static int xpram_make_request(struct request_queue *q, struct bio *bio)
{
xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data;
struct bio_vec *bvec;
@@ -230,12 +230,10 @@ static int xpram_make_request(request_queue_t *q, struct bio *bio)
}
}
set_bit(BIO_UPTODATE, &bio->bi_flags);
- bytes = bio->bi_size;
- bio->bi_size = 0;
- bio->bi_end_io(bio, bytes, 0);
+ bio_endio(bio, 0);
return 0;
fail:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 3f36cb3910ee..643033890e34 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -44,15 +44,9 @@ config CCW_CONSOLE
depends on TN3215_CONSOLE || TN3270_CONSOLE
default y
-config SCLP
- bool "Support for SCLP"
- depends on S390
- help
- Include support for the SCLP interface to the service element.
-
config SCLP_TTY
bool "Support for SCLP line mode terminal"
- depends on SCLP
+ depends on S390
help
Include support for IBM SCLP line-mode terminals.
@@ -65,7 +59,7 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY
bool "Support for SCLP VT220-compatible terminal"
- depends on SCLP
+ depends on S390
help
Include support for an IBM SCLP VT220-compatible terminal.
@@ -78,7 +72,7 @@ config SCLP_VT220_CONSOLE
config SCLP_CPI
tristate "Control-Program Identification"
- depends on SCLP
+ depends on S390
help
This option enables the hardware console interface for system
identification. This is commonly used for workload management and
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6000bdee4082..0e1f35c9ed9d 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev)
struct raw3215_info *raw;
int line;
+ /* Console is special. */
+ if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+ return 0;
raw = kmalloc(sizeof(struct raw3215_info) +
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
if (raw == NULL)
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index fd3479119eb4..0b040557db02 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -22,6 +22,7 @@
#include <asm/ebcdic.h>
#include "raw3270.h"
+#include "tty3270.h"
#include "ctrlchar.h"
#define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count)
spin_unlock_irqrestore(&cp->view.lock,flags);
}
-extern struct tty_driver *tty3270_driver;
-
static struct tty_driver *
con3270_device(struct console *c, int *index)
{
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 268598ef3efe..20442fbf9346 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -17,6 +17,7 @@
#include <linux/miscdevice.h>
#include <linux/ctype.h>
#include <linux/poll.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
@@ -41,6 +42,7 @@ struct mon_private {
size_t hdr_to_read;
size_t data_to_read;
struct mon_buf *current_buf;
+ struct mutex thread_mutex;
};
/*
@@ -179,6 +181,7 @@ static int monwrite_open(struct inode *inode, struct file *filp)
return -ENOMEM;
INIT_LIST_HEAD(&monpriv->list);
monpriv->hdr_to_read = sizeof(monpriv->hdr);
+ mutex_init(&monpriv->thread_mutex);
filp->private_data = monpriv;
return nonseekable_open(inode, filp);
}
@@ -209,6 +212,7 @@ static ssize_t monwrite_write(struct file *filp, const char __user *data,
void *to;
int rc;
+ mutex_lock(&monpriv->thread_mutex);
for (written = 0; written < count; ) {
if (monpriv->hdr_to_read) {
len = min(count - written, monpriv->hdr_to_read);
@@ -247,11 +251,13 @@ static ssize_t monwrite_write(struct file *filp, const char __user *data,
}
monpriv->hdr_to_read = sizeof(monpriv->hdr);
}
+ mutex_unlock(&monpriv->thread_mutex);
return written;
out_error:
monpriv->data_to_read = 0;
monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
+ mutex_unlock(&monpriv->thread_mutex);
return rc;
}
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 743944ad61ec..2edd5fb6d3dc 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -21,6 +21,7 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/ebcdic.h>
+#include <asm/diag.h>
#include "raw3270.h"
@@ -147,8 +148,7 @@ raw3270_request_alloc(size_t size)
* Allocate a new 3270 ccw request from bootmem. Only works very
* early in the boot process. Only con3270.c should be using this.
*/
-struct raw3270_request *
-raw3270_request_alloc_bootmem(size_t size)
+struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size)
{
struct raw3270_request *rq;
@@ -848,8 +848,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
/*
* Setup 3270 device configured as console.
*/
-struct raw3270 *
-raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
{
struct raw3270 *rp;
char *ascebc;
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index fa62e6944057..25629b92dec3 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t {
#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
+static void __sclp_make_read_req(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
@@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
-static inline void __sclp_make_read_req(void);
static void
__sclp_queue_read_req(void)
@@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data)
}
/* Prepare read event data request. Called while sclp_lock is locked. */
-static inline void
-__sclp_make_read_req(void)
+static void __sclp_make_read_req(void)
{
struct sccb_header *sccb;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 726334757bbf..40cd21bc5cc4 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -621,11 +621,24 @@ sclp_vt220_flush_buffer(struct tty_struct *tty)
/*
* Initialize all relevant components and register driver with system.
*/
-static int
-__sclp_vt220_init(int early)
+static void __init __sclp_vt220_cleanup(void)
+{
+ struct list_head *page, *p;
+
+ list_for_each_safe(page, p, &sclp_vt220_empty) {
+ list_del(page);
+ if (slab_is_available())
+ free_page((unsigned long) page);
+ else
+ free_bootmem((unsigned long) page, PAGE_SIZE);
+ }
+}
+
+static int __init __sclp_vt220_init(void)
{
void *page;
int i;
+ int num_pages;
if (sclp_vt220_initialized)
return 0;
@@ -642,13 +655,16 @@ __sclp_vt220_init(int early)
sclp_vt220_flush_later = 0;
/* Allocate pages for output buffering */
- for (i = 0; i < (early ? MAX_CONSOLE_PAGES : MAX_KMEM_PAGES); i++) {
- if (early)
- page = alloc_bootmem_low_pages(PAGE_SIZE);
- else
+ num_pages = slab_is_available() ? MAX_KMEM_PAGES : MAX_CONSOLE_PAGES;
+ for (i = 0; i < num_pages; i++) {
+ if (slab_is_available())
page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!page)
+ else
+ page = alloc_bootmem_low_pages(PAGE_SIZE);
+ if (!page) {
+ __sclp_vt220_cleanup();
return -ENOMEM;
+ }
list_add_tail((struct list_head *) page, &sclp_vt220_empty);
}
return 0;
@@ -662,14 +678,13 @@ static const struct tty_operations sclp_vt220_ops = {
.flush_chars = sclp_vt220_flush_chars,
.write_room = sclp_vt220_write_room,
.chars_in_buffer = sclp_vt220_chars_in_buffer,
- .flush_buffer = sclp_vt220_flush_buffer
+ .flush_buffer = sclp_vt220_flush_buffer,
};
/*
* Register driver with SCLP and Linux and initialize internal tty structures.
*/
-static int __init
-sclp_vt220_tty_init(void)
+static int __init sclp_vt220_tty_init(void)
{
struct tty_driver *driver;
int rc;
@@ -679,18 +694,15 @@ sclp_vt220_tty_init(void)
driver = alloc_tty_driver(1);
if (!driver)
return -ENOMEM;
- rc = __sclp_vt220_init(0);
- if (rc) {
- put_tty_driver(driver);
- return rc;
- }
+ rc = __sclp_vt220_init();
+ if (rc)
+ goto out_driver;
rc = sclp_register(&sclp_vt220_register);
if (rc) {
printk(KERN_ERR SCLP_VT220_PRINT_HEADER
"could not register tty - "
"sclp_register returned %d\n", rc);
- put_tty_driver(driver);
- return rc;
+ goto out_init;
}
driver->owner = THIS_MODULE;
@@ -709,14 +721,20 @@ sclp_vt220_tty_init(void)
printk(KERN_ERR SCLP_VT220_PRINT_HEADER
"could not register tty - "
"tty_register_driver returned %d\n", rc);
- put_tty_driver(driver);
- return rc;
+ goto out_sclp;
}
sclp_vt220_driver = driver;
return 0;
-}
-module_init(sclp_vt220_tty_init);
+out_sclp:
+ sclp_unregister(&sclp_vt220_register);
+out_init:
+ __sclp_vt220_cleanup();
+out_driver:
+ put_tty_driver(driver);
+ return rc;
+}
+__initcall(sclp_vt220_tty_init);
#ifdef CONFIG_SCLP_VT220_CONSOLE
@@ -762,7 +780,7 @@ sclp_vt220_con_init(void)
if (!CONSOLE_IS_SCLP)
return 0;
- rc = __sclp_vt220_init(1);
+ rc = __sclp_vt220_init();
if (rc)
return rc;
/* Attach linux console */
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 3b52f5c1dbef..dddf8d62c153 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -188,7 +188,7 @@ struct tape_blk_data
{
struct tape_device * device;
/* Block device request queue. */
- request_queue_t * request_queue;
+ struct request_queue * request_queue;
spinlock_t request_queue_lock;
/* Task to move entries from block request to CCS request queue. */
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index e765875e8db2..5b47e9cce75f 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -131,10 +131,9 @@ tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
{
struct tape_34xx_work *p;
- if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
+ if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- memset(p, 0, sizeof(*p));
INIT_WORK(&p->work, tape_34xx_work_handler);
p->device = tape_get_device_reference(device);
@@ -1135,21 +1134,18 @@ tape_34xx_bread(struct tape_device *device, struct request *req)
{
struct tape_request *request;
struct ccw1 *ccw;
- int count = 0, i;
+ int count = 0;
unsigned off;
char *dst;
struct bio_vec *bv;
- struct bio *bio;
+ struct req_iterator iter;
struct tape_34xx_block_id * start_block;
DBF_EVENT(6, "xBREDid:");
/* Count the number of blocks for the request. */
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
- }
- }
+ rq_for_each_segment(bv, req, iter)
+ count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
/* Allocate the ccw request. */
request = tape_alloc_request(3+count+1, 8);
@@ -1176,18 +1172,15 @@ tape_34xx_bread(struct tape_device *device, struct request *req)
ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- dst = kmap(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len;
- off += TAPEBLOCK_HSEC_SIZE) {
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = READ_FORWARD;
- ccw->count = TAPEBLOCK_HSEC_SIZE;
- set_normalized_cda(ccw, (void*) __pa(dst));
- ccw++;
- dst += TAPEBLOCK_HSEC_SIZE;
- }
+ rq_for_each_segment(bv, req, iter) {
+ dst = kmap(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
+ ccw->flags = CCW_FLAG_CC;
+ ccw->cmd_code = READ_FORWARD;
+ ccw->count = TAPEBLOCK_HSEC_SIZE;
+ set_normalized_cda(ccw, (void*) __pa(dst));
+ ccw++;
+ dst += TAPEBLOCK_HSEC_SIZE;
}
}
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 7e2b2ab49264..da25f8e24152 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -623,21 +623,19 @@ tape_3590_bread(struct tape_device *device, struct request *req)
{
struct tape_request *request;
struct ccw1 *ccw;
- int count = 0, start_block, i;
+ int count = 0, start_block;
unsigned off;
char *dst;
struct bio_vec *bv;
- struct bio *bio;
+ struct req_iterator iter;
DBF_EVENT(6, "xBREDid:");
start_block = req->sector >> TAPEBLOCK_HSEC_S2B;
DBF_EVENT(6, "start_block = %i\n", start_block);
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
- }
- }
+ rq_for_each_segment(bv, req, iter)
+ count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
+
request = tape_alloc_request(2 + count + 1, 4);
if (IS_ERR(request))
return request;
@@ -653,21 +651,18 @@ tape_3590_bread(struct tape_device *device, struct request *req)
*/
ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len;
- off += TAPEBLOCK_HSEC_SIZE) {
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = READ_FORWARD;
- ccw->count = TAPEBLOCK_HSEC_SIZE;
- set_normalized_cda(ccw, (void *) __pa(dst));
- ccw++;
- dst += TAPEBLOCK_HSEC_SIZE;
- }
- if (off > bv->bv_len)
- BUG();
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
+ ccw->flags = CCW_FLAG_CC;
+ ccw->cmd_code = READ_FORWARD;
+ ccw->count = TAPEBLOCK_HSEC_SIZE;
+ set_normalized_cda(ccw, (void *) __pa(dst));
+ ccw++;
+ dst += TAPEBLOCK_HSEC_SIZE;
}
+ if (off > bv->bv_len)
+ BUG();
}
ccw = tape_ccw_end(ccw, NOP, 0, NULL);
DBF_EVENT(6, "xBREDccwg\n");
@@ -713,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device,
c_info = &TAPE_3590_CRYPT_INFO(device);
- if (sense->masst == MSENSE_UNASSOCIATED) {
+ DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
+ switch (sense->macst) {
+ case 0x04:
+ case 0x05:
+ case 0x06:
tape_med_state_set(device, MS_UNLOADED);
TAPE_3590_CRYPT_INFO(device).medium_status = 0;
return;
- }
- if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
- PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+ case 0x08:
+ case 0x09:
+ tape_med_state_set(device, MS_LOADED);
+ break;
+ default:
+ tape_med_state_set(device, MS_UNKNOWN);
return;
}
- tape_med_state_set(device, MS_LOADED);
c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
if (sense->flags & MSENSE_CRYPT_MASK) {
PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -840,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
/* Probably result of halt ssch */
return TAPE_IO_PENDING;
else if (irb->scsw.dstat == 0x85)
- /* Device Ready -> check medium state */
- tape_3590_schedule_work(device, TO_MSEN);
- else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+ /* Device Ready */
+ DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
+ else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
tape_3590_schedule_work(device, TO_READ_ATTMSG);
- else {
+ } else {
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
tape_dump_sense(device, NULL, irb);
}
+ /* check medium state */
+ tape_3590_schedule_work(device, TO_MSEN);
return TAPE_IO_SUCCESS;
}
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index dd0ecaed592e..eeb92e2ed0cc 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -147,7 +147,7 @@ static void
tapeblock_requeue(struct work_struct *work) {
struct tape_blk_data * blkdat;
struct tape_device * device;
- request_queue_t * queue;
+ struct request_queue * queue;
int nr_queued;
struct request * req;
struct list_head * l;
@@ -194,7 +194,7 @@ tapeblock_requeue(struct work_struct *work) {
* Tape request queue function. Called from ll_rw_blk.c
*/
static void
-tapeblock_request_fn(request_queue_t *queue)
+tapeblock_request_fn(struct request_queue *queue)
{
struct tape_device *device;
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index bc33068b9ce2..70b1980a08b6 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -25,8 +25,8 @@
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
-
#include "raw3270.h"
+#include "tty3270.h"
#include "keyboard.h"
#define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix)
static void
tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
{
- tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
- cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
+ int max_cx = max(0, cx);
+ int max_cy = max(0, cy);
+
+ tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+ cy = min_t(int, tp->view.rows - 3, max_cy);
if (cy != tp->cy) {
tty3270_convert_line(tp, tp->cy);
tp->cy = cy;
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
new file mode 100644
index 000000000000..799da57f0390
--- /dev/null
+++ b/drivers/s390/char/tty3270.h
@@ -0,0 +1,16 @@
+/*
+ * drivers/s390/char/tty3270.h
+ *
+ * Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __DRIVERS_S390_CHAR_TTY3270_H
+#define __DRIVERS_S390_CHAR_TTY3270_H
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+
+extern struct tty_driver *tty3270_driver;
+
+#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index e90b0f846195..d70a6e65bf14 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -14,6 +14,7 @@
#include <asm/cio.h>
#include <asm/ccwdev.h>
#include <asm/debug.h>
+#include <asm/diag.h>
#include "vmur.h"
@@ -68,8 +69,26 @@ static struct ccw_driver ur_driver = {
.set_offline = ur_set_offline,
};
+static DEFINE_MUTEX(vmur_mutex);
+
/*
* Allocation, freeing, getting and putting of urdev structures
+ *
+ * Each ur device (urd) contains a reference to its corresponding ccw device
+ * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
+ * ur device using the cdev->dev.driver_data pointer.
+ *
+ * urd references:
+ * - ur_probe gets a urd reference, ur_remove drops the reference
+ * (cdev->dev.driver_data)
+ * - ur_open gets a urd reference, ur_relase drops the reference
+ * (urf->urd)
+ *
+ * cdev references:
+ * - urdev_alloc get a cdev reference (urd->cdev)
+ * - urdev_free drops the cdev reference (urd->cdev)
+ *
+ * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock
*/
static struct urdev *urdev_alloc(struct ccw_device *cdev)
{
@@ -78,51 +97,72 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
if (!urd)
return NULL;
- urd->cdev = cdev;
urd->reclen = cdev->id.driver_info;
ccw_device_get_id(cdev, &urd->dev_id);
mutex_init(&urd->io_mutex);
mutex_init(&urd->open_mutex);
+ atomic_set(&urd->ref_count, 1);
+ urd->cdev = cdev;
+ get_device(&cdev->dev);
return urd;
}
static void urdev_free(struct urdev *urd)
{
+ TRACE("urdev_free: %p\n", urd);
+ if (urd->cdev)
+ put_device(&urd->cdev->dev);
kfree(urd);
}
-/*
- * This is how the character device driver gets a reference to a
- * ur device. When this call returns successfully, a reference has
- * been taken (by get_device) on the underlying kobject. The recipient
- * of this urdev pointer must eventually drop it with urdev_put(urd)
- * which does the corresponding put_device().
- */
+static void urdev_get(struct urdev *urd)
+{
+ atomic_inc(&urd->ref_count);
+}
+
+static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
+{
+ struct urdev *urd;
+ unsigned long flags;
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ urd = cdev->dev.driver_data;
+ if (urd)
+ urdev_get(urd);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return urd;
+}
+
static struct urdev *urdev_get_from_devno(u16 devno)
{
char bus_id[16];
struct ccw_device *cdev;
+ struct urdev *urd;
sprintf(bus_id, "0.0.%04x", devno);
cdev = get_ccwdev_by_busid(&ur_driver, bus_id);
if (!cdev)
return NULL;
-
- return cdev->dev.driver_data;
+ urd = urdev_get_from_cdev(cdev);
+ put_device(&cdev->dev);
+ return urd;
}
static void urdev_put(struct urdev *urd)
{
- put_device(&urd->cdev->dev);
+ if (atomic_dec_and_test(&urd->ref_count))
+ urdev_free(urd);
}
/*
* Low-level functions to do I/O to a ur device.
* alloc_chan_prog
+ * free_chan_prog
* do_ur_io
* ur_int_handler
*
* alloc_chan_prog allocates and builds the channel program
+ * free_chan_prog frees memory of the channel program
*
* do_ur_io issues the channel program to the device and blocks waiting
* on a completion event it publishes at urd->io_done. The function
@@ -137,6 +177,16 @@ static void urdev_put(struct urdev *urd)
* address pointer that alloc_chan_prog returned.
*/
+static void free_chan_prog(struct ccw1 *cpa)
+{
+ struct ccw1 *ptr = cpa;
+
+ while (ptr->cda) {
+ kfree((void *)(addr_t) ptr->cda);
+ ptr++;
+ }
+ kfree(cpa);
+}
/*
* alloc_chan_prog
@@ -144,44 +194,45 @@ static void urdev_put(struct urdev *urd)
* with a final NOP CCW command-chained on (which ensures that CE and DE
* are presented together in a single interrupt instead of as separate
* interrupts unless an incorrect length indication kicks in first). The
- * data length in each CCW is reclen. The caller must ensure that count
- * is an integral multiple of reclen.
- * The channel program pointer returned by this function must be freed
- * with kfree. The caller is responsible for checking that
- * count/reclen is not ridiculously large.
+ * data length in each CCW is reclen.
*/
-static struct ccw1 *alloc_chan_prog(char *buf, size_t count, size_t reclen)
+static struct ccw1 *alloc_chan_prog(const char __user *ubuf, int rec_count,
+ int reclen)
{
- size_t num_ccws;
struct ccw1 *cpa;
+ void *kbuf;
int i;
- TRACE("alloc_chan_prog(%p, %zu, %zu)\n", buf, count, reclen);
+ TRACE("alloc_chan_prog(%p, %i, %i)\n", ubuf, rec_count, reclen);
/*
* We chain a NOP onto the writes to force CE+DE together.
* That means we allocate room for CCWs to cover count/reclen
* records plus a NOP.
*/
- num_ccws = count / reclen + 1;
- cpa = kmalloc(num_ccws * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+ cpa = kzalloc((rec_count + 1) * sizeof(struct ccw1),
+ GFP_KERNEL | GFP_DMA);
if (!cpa)
- return NULL;
+ return ERR_PTR(-ENOMEM);
- for (i = 0; count; i++) {
+ for (i = 0; i < rec_count; i++) {
cpa[i].cmd_code = WRITE_CCW_CMD;
cpa[i].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
cpa[i].count = reclen;
- cpa[i].cda = __pa(buf);
- buf += reclen;
- count -= reclen;
+ kbuf = kmalloc(reclen, GFP_KERNEL | GFP_DMA);
+ if (!kbuf) {
+ free_chan_prog(cpa);
+ return ERR_PTR(-ENOMEM);
+ }
+ cpa[i].cda = (u32)(addr_t) kbuf;
+ if (copy_from_user(kbuf, ubuf, reclen)) {
+ free_chan_prog(cpa);
+ return ERR_PTR(-EFAULT);
+ }
+ ubuf += reclen;
}
/* The following NOP CCW forces CE+DE to be presented together */
cpa[i].cmd_code = CCW_CMD_NOOP;
- cpa[i].flags = 0;
- cpa[i].count = 0;
- cpa[i].cda = 0;
-
return cpa;
}
@@ -189,7 +240,7 @@ static int do_ur_io(struct urdev *urd, struct ccw1 *cpa)
{
int rc;
struct ccw_device *cdev = urd->cdev;
- DECLARE_COMPLETION(event);
+ DECLARE_COMPLETION_ONSTACK(event);
TRACE("do_ur_io: cpa=%p\n", cpa);
@@ -232,6 +283,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
return;
}
urd = cdev->dev.driver_data;
+ BUG_ON(!urd);
/* On special conditions irb is an error pointer */
if (IS_ERR(irb))
urd->io_request_rc = PTR_ERR(irb);
@@ -249,9 +301,15 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
static ssize_t ur_attr_reclen_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct urdev *urd = dev->driver_data;
+ struct urdev *urd;
+ int rc;
- return sprintf(buf, "%zu\n", urd->reclen);
+ urd = urdev_get_from_cdev(to_ccwdev(dev));
+ if (!urd)
+ return -ENODEV;
+ rc = sprintf(buf, "%zu\n", urd->reclen);
+ urdev_put(urd);
+ return rc;
}
static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL);
@@ -325,24 +383,11 @@ static ssize_t do_write(struct urdev *urd, const char __user *udata,
size_t count, size_t reclen, loff_t *ppos)
{
struct ccw1 *cpa;
- char *buf;
int rc;
- /* Data buffer must be under 2GB line for fmt1 CCWs: hence GFP_DMA */
- buf = kmalloc(count, GFP_KERNEL | GFP_DMA);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, udata, count)) {
- rc = -EFAULT;
- goto fail_kfree_buf;
- }
-
- cpa = alloc_chan_prog(buf, count, reclen);
- if (!cpa) {
- rc = -ENOMEM;
- goto fail_kfree_buf;
- }
+ cpa = alloc_chan_prog(udata, count / reclen, reclen);
+ if (IS_ERR(cpa))
+ return PTR_ERR(cpa);
rc = do_ur_io(urd, cpa);
if (rc)
@@ -354,10 +399,9 @@ static ssize_t do_write(struct urdev *urd, const char __user *udata,
}
*ppos += count;
rc = count;
+
fail_kfree_cpa:
- kfree(cpa);
-fail_kfree_buf:
- kfree(buf);
+ free_chan_prog(cpa);
return rc;
}
@@ -380,31 +424,6 @@ static ssize_t ur_write(struct file *file, const char __user *udata,
return do_write(urf->urd, udata, count, urf->dev_reclen, ppos);
}
-static int do_diag_14(unsigned long rx, unsigned long ry1,
- unsigned long subcode)
-{
- register unsigned long _ry1 asm("2") = ry1;
- register unsigned long _ry2 asm("3") = subcode;
- int rc = 0;
-
- asm volatile(
-#ifdef CONFIG_64BIT
- " sam31\n"
- " diag %2,2,0x14\n"
- " sam64\n"
-#else
- " diag %2,2,0x14\n"
-#endif
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (rc), "+d" (_ry2)
- : "d" (rx), "d" (_ry1)
- : "cc");
-
- TRACE("diag 14: subcode=0x%lx, cc=%i\n", subcode, rc);
- return rc;
-}
-
/*
* diagnose code 0x14 subcode 0x0028 - position spool file to designated
* record
@@ -416,7 +435,7 @@ static int diag_position_to_record(int devno, int record)
{
int cc;
- cc = do_diag_14(record, devno, 0x28);
+ cc = diag14(record, devno, 0x28);
switch (cc) {
case 0:
return 0;
@@ -441,7 +460,7 @@ static int diag_read_file(int devno, char *buf)
{
int cc;
- cc = do_diag_14((unsigned long) buf, devno, 0x00);
+ cc = diag14((unsigned long) buf, devno, 0x00);
switch (cc) {
case 0:
return 0;
@@ -473,7 +492,7 @@ static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
return rc;
len = min((size_t) PAGE_SIZE, count);
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (!buf)
return -ENOMEM;
@@ -486,7 +505,7 @@ static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
}
if (rc)
goto fail;
- if (reclen)
+ if (reclen && (copied == 0) && (*offs < PAGE_SIZE))
*((u16 *) &buf[FILE_RECLEN_OFFSET]) = reclen;
len = min(count - copied, PAGE_SIZE - res);
if (copy_to_user(ubuf + copied, buf + res, len)) {
@@ -500,7 +519,7 @@ static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
*offs += copied;
rc = copied;
fail:
- kfree(buf);
+ free_page((unsigned long) buf);
return rc;
}
@@ -534,7 +553,7 @@ static int diag_read_next_file_info(struct file_control_block *buf, int spid)
{
int cc;
- cc = do_diag_14((unsigned long) buf, spid, 0xfff);
+ cc = diag14((unsigned long) buf, spid, 0xfff);
switch (cc) {
case 0:
return 0;
@@ -543,56 +562,97 @@ static int diag_read_next_file_info(struct file_control_block *buf, int spid)
}
}
-static int verify_device(struct urdev *urd)
+static int verify_uri_device(struct urdev *urd)
{
- struct file_control_block fcb;
+ struct file_control_block *fcb;
char *buf;
int rc;
+ fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);
+ if (!fcb)
+ return -ENOMEM;
+
+ /* check for empty reader device (beginning of chain) */
+ rc = diag_read_next_file_info(fcb, 0);
+ if (rc)
+ goto fail_free_fcb;
+
+ /* if file is in hold status, we do not read it */
+ if (fcb->file_stat & (FLG_SYSTEM_HOLD | FLG_USER_HOLD)) {
+ rc = -EPERM;
+ goto fail_free_fcb;
+ }
+
+ /* open file on virtual reader */
+ buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto fail_free_fcb;
+ }
+ rc = diag_read_file(urd->dev_id.devno, buf);
+ if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
+ goto fail_free_buf;
+
+ /* check if the file on top of the queue is open now */
+ rc = diag_read_next_file_info(fcb, 0);
+ if (rc)
+ goto fail_free_buf;
+ if (!(fcb->file_stat & FLG_IN_USE)) {
+ rc = -EMFILE;
+ goto fail_free_buf;
+ }
+ rc = 0;
+
+fail_free_buf:
+ free_page((unsigned long) buf);
+fail_free_fcb:
+ kfree(fcb);
+ return rc;
+}
+
+static int verify_device(struct urdev *urd)
+{
switch (urd->class) {
case DEV_CLASS_UR_O:
return 0; /* no check needed here */
case DEV_CLASS_UR_I:
- /* check for empty reader device (beginning of chain) */
- rc = diag_read_next_file_info(&fcb, 0);
- if (rc)
- return rc;
-
- /* open file on virtual reader */
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- rc = diag_read_file(urd->dev_id.devno, buf);
- kfree(buf);
-
- if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
- return rc;
- return 0;
+ return verify_uri_device(urd);
default:
return -ENOTSUPP;
}
}
-static int get_file_reclen(struct urdev *urd)
+static int get_uri_file_reclen(struct urdev *urd)
{
- struct file_control_block fcb;
+ struct file_control_block *fcb;
int rc;
+ fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);
+ if (!fcb)
+ return -ENOMEM;
+ rc = diag_read_next_file_info(fcb, 0);
+ if (rc)
+ goto fail_free;
+ if (fcb->file_stat & FLG_CP_DUMP)
+ rc = 0;
+ else
+ rc = fcb->rec_len;
+
+fail_free:
+ kfree(fcb);
+ return rc;
+}
+
+static int get_file_reclen(struct urdev *urd)
+{
switch (urd->class) {
case DEV_CLASS_UR_O:
return 0;
case DEV_CLASS_UR_I:
- rc = diag_read_next_file_info(&fcb, 0);
- if (rc)
- return rc;
- break;
+ return get_uri_file_reclen(urd);
default:
return -ENOTSUPP;
}
- if (fcb.file_stat & FLG_CP_DUMP)
- return 0;
-
- return fcb.rec_len;
}
static int ur_open(struct inode *inode, struct file *file)
@@ -710,64 +770,63 @@ static struct file_operations ur_fops = {
/*
* ccw_device infrastructure:
- * ur_probe gets its own ref to the device (i.e. get_device),
- * creates the struct urdev, the device attributes, sets up
- * the interrupt handler and validates the virtual unit record device.
- * ur_remove removes the device attributes, frees the struct urdev
- * and drops (put_device) the ref to the device we got in ur_probe.
+ * ur_probe creates the struct urdev (with refcount = 1), the device
+ * attributes, sets up the interrupt handler and validates the virtual
+ * unit record device.
+ * ur_remove removes the device attributes and drops the reference to
+ * struct urdev.
+ *
+ * ur_probe, ur_remove, ur_set_online and ur_set_offline are serialized
+ * by the vmur_mutex lock.
+ *
+ * urd->char_device is used as indication that the online function has
+ * been completed successfully.
*/
static int ur_probe(struct ccw_device *cdev)
{
struct urdev *urd;
int rc;
- TRACE("ur_probe: cdev=%p state=%d\n", cdev, *(int *) cdev->private);
-
- if (!get_device(&cdev->dev))
- return -ENODEV;
+ TRACE("ur_probe: cdev=%p\n", cdev);
+ mutex_lock(&vmur_mutex);
urd = urdev_alloc(cdev);
if (!urd) {
rc = -ENOMEM;
- goto fail;
+ goto fail_unlock;
}
+
rc = ur_create_attributes(&cdev->dev);
if (rc) {
rc = -ENOMEM;
- goto fail;
+ goto fail_urdev_put;
}
- cdev->dev.driver_data = urd;
cdev->handler = ur_int_handler;
/* validate virtual unit record device */
urd->class = get_urd_class(urd);
if (urd->class < 0) {
rc = urd->class;
- goto fail;
+ goto fail_remove_attr;
}
if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) {
rc = -ENOTSUPP;
- goto fail;
+ goto fail_remove_attr;
}
+ spin_lock_irq(get_ccwdev_lock(cdev));
+ cdev->dev.driver_data = urd;
+ spin_unlock_irq(get_ccwdev_lock(cdev));
+ mutex_unlock(&vmur_mutex);
return 0;
-fail:
- urdev_free(urd);
- put_device(&cdev->dev);
- return rc;
-}
-
-static void ur_remove(struct ccw_device *cdev)
-{
- struct urdev *urd = cdev->dev.driver_data;
-
- TRACE("ur_remove\n");
- if (cdev->online)
- ur_set_offline(cdev);
+fail_remove_attr:
ur_remove_attributes(&cdev->dev);
- urdev_free(urd);
- put_device(&cdev->dev);
+fail_urdev_put:
+ urdev_put(urd);
+fail_unlock:
+ mutex_unlock(&vmur_mutex);
+ return rc;
}
static int ur_set_online(struct ccw_device *cdev)
@@ -776,20 +835,29 @@ static int ur_set_online(struct ccw_device *cdev)
int minor, major, rc;
char node_id[16];
- TRACE("ur_set_online: cdev=%p state=%d\n", cdev,
- *(int *) cdev->private);
+ TRACE("ur_set_online: cdev=%p\n", cdev);
- if (!try_module_get(ur_driver.owner))
- return -EINVAL;
+ mutex_lock(&vmur_mutex);
+ urd = urdev_get_from_cdev(cdev);
+ if (!urd) {
+ /* ur_remove already deleted our urd */
+ rc = -ENODEV;
+ goto fail_unlock;
+ }
+
+ if (urd->char_device) {
+ /* Another ur_set_online was faster */
+ rc = -EBUSY;
+ goto fail_urdev_put;
+ }
- urd = (struct urdev *) cdev->dev.driver_data;
minor = urd->dev_id.devno;
major = MAJOR(ur_first_dev_maj_min);
urd->char_device = cdev_alloc();
if (!urd->char_device) {
rc = -ENOMEM;
- goto fail_module_put;
+ goto fail_urdev_put;
}
cdev_init(urd->char_device, &ur_fops);
@@ -818,29 +886,79 @@ static int ur_set_online(struct ccw_device *cdev)
TRACE("ur_set_online: device_create rc=%d\n", rc);
goto fail_free_cdev;
}
-
+ urdev_put(urd);
+ mutex_unlock(&vmur_mutex);
return 0;
fail_free_cdev:
cdev_del(urd->char_device);
-fail_module_put:
- module_put(ur_driver.owner);
-
+ urd->char_device = NULL;
+fail_urdev_put:
+ urdev_put(urd);
+fail_unlock:
+ mutex_unlock(&vmur_mutex);
return rc;
}
-static int ur_set_offline(struct ccw_device *cdev)
+static int ur_set_offline_force(struct ccw_device *cdev, int force)
{
struct urdev *urd;
+ int rc;
- TRACE("ur_set_offline: cdev=%p cdev->private=%p state=%d\n",
- cdev, cdev->private, *(int *) cdev->private);
- urd = (struct urdev *) cdev->dev.driver_data;
+ TRACE("ur_set_offline: cdev=%p\n", cdev);
+ urd = urdev_get_from_cdev(cdev);
+ if (!urd)
+ /* ur_remove already deleted our urd */
+ return -ENODEV;
+ if (!urd->char_device) {
+ /* Another ur_set_offline was faster */
+ rc = -EBUSY;
+ goto fail_urdev_put;
+ }
+ if (!force && (atomic_read(&urd->ref_count) > 2)) {
+ /* There is still a user of urd (e.g. ur_open) */
+ TRACE("ur_set_offline: BUSY\n");
+ rc = -EBUSY;
+ goto fail_urdev_put;
+ }
device_destroy(vmur_class, urd->char_device->dev);
cdev_del(urd->char_device);
- module_put(ur_driver.owner);
+ urd->char_device = NULL;
+ rc = 0;
- return 0;
+fail_urdev_put:
+ urdev_put(urd);
+ return rc;
+}
+
+static int ur_set_offline(struct ccw_device *cdev)
+{
+ int rc;
+
+ mutex_lock(&vmur_mutex);
+ rc = ur_set_offline_force(cdev, 0);
+ mutex_unlock(&vmur_mutex);
+ return rc;
+}
+
+static void ur_remove(struct ccw_device *cdev)
+{
+ unsigned long flags;
+
+ TRACE("ur_remove\n");
+
+ mutex_lock(&vmur_mutex);
+
+ if (cdev->online)
+ ur_set_offline_force(cdev, 1);
+ ur_remove_attributes(&cdev->dev);
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ urdev_put(cdev->dev.driver_data);
+ cdev->dev.driver_data = NULL;
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+
+ mutex_unlock(&vmur_mutex);
}
/*
diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h
index 16d0a4e38e40..fa959644735a 100644
--- a/drivers/s390/char/vmur.h
+++ b/drivers/s390/char/vmur.h
@@ -50,7 +50,10 @@ struct file_control_block {
char rest[200];
} __attribute__ ((packed));
-#define FLG_CP_DUMP 0x10
+#define FLG_SYSTEM_HOLD 0x04
+#define FLG_CP_DUMP 0x10
+#define FLG_USER_HOLD 0x20
+#define FLG_IN_USE 0x80
/*
* A struct urdev is created for each ur device that is made available
@@ -67,6 +70,7 @@ struct urdev {
size_t reclen; /* Record length for *write* CCWs */
int class; /* VM device class */
int io_request_rc; /* return code from I/O request */
+ atomic_t ref_count; /* reference counter */
};
/*
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 680b9b58b80e..6f40facb1c4d 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout,
"0: la %0,0\n"
"1:\n"
EX_TABLE(0b,1b)
- : "=d" (err) : "d"(__func), "d"(__timeout),
- "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+ : "+d" (err) : "d"(__func), "d"(__timeout),
+ "d"(__cmdp), "d"(__cmdl) : "1", "cc");
return err;
}
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3712ede16723..7073daf77981 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count)
if (count == 0)
return 0;
- flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+ flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
asm volatile (
"0: mvcle %1,%2,0x0\n"
"1: jo 0b\n"
" lhi %0,0x0\n"
"2:\n"
EX_TABLE(1b,2b)
- : "+d" (rc)
- : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+ : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+ "+d" (_len2), "=m" (*((long*)dest))
+ : "m" (*((long*)src))
: "cc", "memory");
__raw_local_irq_ssm(flags);
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index ec0404874fad..bd5f16f80bf8 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -51,7 +51,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to,
to = from;
if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
- printk (KERN_WARNING "Invalid blacklist range "
+ printk (KERN_WARNING "cio: Invalid blacklist range "
"0.%x.%04x to 0.%x.%04x, skipping\n",
ssid, from, ssid, to);
return;
@@ -119,7 +119,7 @@ blacklist_busid(char **str, int *id0, int *ssid, int *devno)
return 0;
confused:
strsep(str, ",\n");
- printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav);
+ printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
return 1;
}
@@ -166,22 +166,19 @@ blacklist_parse_parameters (char *str, range_action action)
continue;
}
if (*str == '-') {
- printk(KERN_WARNING "invalid cio_ignore "
+ 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 "invalid cio_ignore range "
- "%x.%x.%04x-%x.%x.%04x\n",
- from_id0, from_ssid, from,
- to_id0, to_ssid, to);
+ 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;
}
- pr_debug("blacklist_setup: adding range "
- "from %x.%x.%04x to %x.%x.%04x\n",
- from_id0, from_ssid, from, to_id0, to_ssid, to);
blacklist_range (ra, from, to, to_ssid);
}
}
@@ -239,7 +236,7 @@ blacklist_parse_proc_parameters (char *buf)
*/
blacklist_parse_parameters (buf + 4, add);
} else {
- printk (KERN_WARNING "cio_ignore: Parse error; \n"
+ 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>,"
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e5ccda63e883..5baa517c3b66 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
return 0;
}
static int
-ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
- int buffer_size)
+ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env)
{
/* TODO */
return 0;
@@ -152,16 +151,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
-/*
- * try to add a new ccwgroup device for one driver
- * argc and argv[] are a list of bus_id's of devices
- * belonging to the driver.
+/**
+ * ccwgroup_create() - 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
+ *
+ * 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
+ * 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(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int argc, char *argv[])
{
struct ccwgroup_device *gdev;
int i;
@@ -359,7 +366,6 @@ ccwgroup_probe (struct device *dev)
if ((ret = device_create_file(dev, &dev_attr_online)))
return ret;
- pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id);
ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
if (ret)
device_remove_file(dev, &dev_attr_online);
@@ -376,8 +382,6 @@ ccwgroup_remove (struct device *dev)
gdev = to_ccwgroupdev(dev);
gdrv = to_ccwgroupdrv(dev->driver);
- pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id);
-
device_remove_file(dev, &dev_attr_online);
if (gdrv && gdrv->remove)
@@ -393,8 +397,13 @@ static struct bus_type ccwgroup_bus_type = {
.remove = ccwgroup_remove,
};
-int
-ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_register() - register a ccw group driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ */
+int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
{
/* register our new driver with the core */
cdriver->driver.bus = &ccwgroup_bus_type;
@@ -409,8 +418,13 @@ __ccwgroup_match_all(struct device *dev, void *data)
return 1;
}
-void
-ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_unregister() - deregister a ccw group driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
{
struct device *dev;
@@ -430,8 +444,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
driver_unregister(&cdriver->driver);
}
-int
-ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_probe_ccwdev() - probe function for slave devices
+ * @cdev: ccw device to be probed
+ *
+ * This is a dummy probe function for ccw devices that are slave devices in
+ * a ccw group device.
+ * Returns:
+ * always %0
+ */
+int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
{
return 0;
}
@@ -455,8 +477,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
return NULL;
}
-void
-ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_remove_ccwdev() - remove function for slave devices
+ * @cdev: ccw device to be removed
+ *
+ * This is a remove function for ccw devices that are slave devices in a ccw
+ * group device. It sets the ccw device offline and also deregisters the
+ * embedding ccw group device.
+ */
+void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index b57d93d986c0..42c1f4659adb 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -14,7 +14,7 @@
#include <linux/jiffies.h>
#include <linux/wait.h>
#include <linux/mutex.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
#include <asm/chpid.h>
#include <asm/sclp.h>
@@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue;
/* Return channel_path struct for given chpid. */
static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
{
- return css[chpid.cssid]->chps[chpid.id];
+ return channel_subsystems[chpid.cssid]->chps[chpid.id];
}
/* Set vary state for given chpid. */
@@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
opm = 0;
chp_id_init(&chpid);
- for (i=0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
opm <<= 1;
chpid.id = sch->schib.pmcw.chpid[i];
if (chp_get_status(chpid) != 0)
@@ -118,17 +118,11 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
chpid.id);
- CIO_TRACE_EVENT( 2, dbf_text);
+ CIO_TRACE_EVENT(2, dbf_text);
status = chp_get_status(chpid);
- if (status < 0) {
- printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
- chpid.cssid, chpid.id);
- return -EINVAL;
- }
-
if (!on && !status) {
- printk(KERN_ERR "chpid %x.%02x is already offline\n",
+ printk(KERN_ERR "cio: chpid %x.%02x is already offline\n",
chpid.cssid, chpid.id);
return -EINVAL;
}
@@ -146,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct channel_path *chp;
+ struct device *device;
unsigned int size;
- chp = to_channelpath(container_of(kobj, struct device, kobj));
+ device = container_of(kobj, struct device, kobj);
+ chp = to_channelpath(device);
if (!chp->cmg_chars)
return 0;
@@ -199,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj,
{
struct channel_path *chp;
struct channel_subsystem *css;
+ struct device *device;
unsigned int size;
- chp = to_channelpath(container_of(kobj, struct device, kobj));
+ device = container_of(kobj, struct device, kobj);
+ chp = to_channelpath(device);
css = to_css(chp->dev.parent);
size = sizeof(struct cmg_entry);
@@ -359,7 +357,7 @@ static ssize_t chp_shared_show(struct device *dev,
static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
-static struct attribute * chp_attrs[] = {
+static struct attribute *chp_attrs[] = {
&dev_attr_status.attr,
&dev_attr_configure.attr,
&dev_attr_type.attr,
@@ -401,7 +399,7 @@ int chp_new(struct chp_id chpid)
/* fill in status, etc. */
chp->chpid = chpid;
chp->state = 1;
- chp->dev.parent = &css[chpid.cssid]->device;
+ chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
chp->dev.release = chp_release;
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
chpid.id);
@@ -421,21 +419,14 @@ int chp_new(struct chp_id chpid)
if (ret)
goto out_free;
} else {
- static int msg_done;
-
- if (!msg_done) {
- printk(KERN_WARNING "cio: Channel measurements not "
- "available, continuing.\n");
- msg_done = 1;
- }
chp->cmg = -1;
}
/* make it known to the system */
ret = device_register(&chp->dev);
if (ret) {
- printk(KERN_WARNING "%s: could not register %x.%02x\n",
- __func__, chpid.cssid, chpid.id);
+ CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n",
+ chpid.cssid, chpid.id, ret);
goto out_free;
}
ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
@@ -443,18 +434,18 @@ int chp_new(struct chp_id chpid)
device_unregister(&chp->dev);
goto out_free;
}
- mutex_lock(&css[chpid.cssid]->mutex);
- if (css[chpid.cssid]->cm_enabled) {
+ mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
+ if (channel_subsystems[chpid.cssid]->cm_enabled) {
ret = chp_add_cmg_attr(chp);
if (ret) {
sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
device_unregister(&chp->dev);
- mutex_unlock(&css[chpid.cssid]->mutex);
+ mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
goto out_free;
}
}
- css[chpid.cssid]->chps[chpid.id] = chp;
- mutex_unlock(&css[chpid.cssid]->mutex);
+ channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
+ mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
return ret;
out_free:
kfree(chp);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index ea92ac4d6577..597c0c76a2ad 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -990,16 +990,20 @@ out:
return ret;
}
-static int __init
-chsc_alloc_sei_area(void)
+int __init chsc_alloc_sei_area(void)
{
sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!sei_page)
- printk(KERN_WARNING"Can't allocate page for processing of " \
- "chsc machine checks!\n");
+ CIO_MSG_EVENT(0, "Can't allocate page for processing of "
+ "chsc machine checks!\n");
return (sei_page ? 0 : -ENOMEM);
}
+void __init chsc_free_sei_area(void)
+{
+ kfree(sei_page);
+}
+
int __init
chsc_enable_facility(int operation_code)
{
@@ -1051,8 +1055,6 @@ chsc_enable_facility(int operation_code)
return ret;
}
-subsys_initcall(chsc_alloc_sei_area);
-
struct css_general_char css_general_characteristics;
struct css_chsc_char css_chsc_characteristics;
@@ -1073,8 +1075,8 @@ chsc_determine_css_characteristics(void)
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
- printk(KERN_WARNING"cio: Was not able to determine available" \
- "CHSCs due to no memory.\n");
+ CIO_MSG_EVENT(0, "Was not able to determine available"
+ "CHSCs due to no memory.\n");
return -ENOMEM;
}
@@ -1083,15 +1085,15 @@ chsc_determine_css_characteristics(void)
result = chsc(scsc_area);
if (result) {
- printk(KERN_WARNING"cio: Was not able to determine " \
- "available CHSCs, cc=%i.\n", result);
+ CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "
+ "cc=%i.\n", result);
result = -EIO;
goto exit;
}
if (scsc_area->response.code != 1) {
- printk(KERN_WARNING"cio: Was not able to determine " \
- "available CHSCs.\n");
+ CIO_MSG_EVENT(0, "Was not able to determine "
+ "available CHSCs.\n");
result = -EIO;
goto exit;
}
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 2ad81d11cf7b..d1f5db1e69b9 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -79,6 +79,8 @@ extern int chsc_get_ssd_info(struct subchannel_id schid,
struct chsc_ssd_info *ssd);
extern int chsc_determine_css_characteristics(void);
extern int css_characteristics_avail;
+extern int chsc_alloc_sei_area(void);
+extern void chsc_free_sei_area(void);
extern int chsc_enable_facility(int);
struct channel_subsystem;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ea1defba5693..46905345159e 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -47,8 +47,8 @@ cio_setup (char *parm)
else if (!strcmp (parm, "no"))
cio_show_msg = 0;
else
- printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",
- parm);
+ printk(KERN_ERR "cio: cio_setup: "
+ "invalid cio_msg parameter '%s'", parm);
return 1;
}
@@ -80,7 +80,6 @@ cio_debug_init (void)
goto out_unregister;
debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
debug_set_level (cio_debug_crw_id, 2);
- pr_debug("debugging initialized\n");
return 0;
out_unregister:
@@ -90,7 +89,7 @@ out_unregister:
debug_unregister (cio_debug_trace_id);
if (cio_debug_crw_id)
debug_unregister (cio_debug_crw_id);
- pr_debug("could not initialize debugging\n");
+ printk(KERN_WARNING"cio: could not initialize debugging\n");
return -1;
}
@@ -568,7 +567,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
*/
if (sch->st != 0) {
CIO_DEBUG(KERN_INFO, 0,
- "Subchannel 0.%x.%04x reports "
+ "cio: 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. */
@@ -601,7 +600,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->lpm = sch->schib.pmcw.pam & sch->opm;
CIO_DEBUG(KERN_INFO, 0,
- "Detected device %04x on subchannel 0.%x.%04X"
+ "cio: 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,
@@ -620,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1; /* multipath mode */
+ /* clean up possible residual cmf stuff */
+ sch->schib.pmcw.mme = 0;
+ sch->schib.pmcw.mbfc = 0;
+ sch->schib.pmcw.mbi = 0;
+ sch->schib.mba = 0;
return 0;
out:
if (!cio_is_console(schid))
@@ -766,7 +770,7 @@ cio_get_console_sch_no(void)
/* unlike in 2.4, we cannot autoprobe here, since
* the channel subsystem is not fully initialized.
* With some luck, the HWC console can take over */
- printk(KERN_WARNING "No ccw console found!\n");
+ printk(KERN_WARNING "cio: No ccw console found!\n");
return -1;
}
return console_irq;
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index f88844adae1b..c9bf8989930f 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -23,6 +23,8 @@ extern debug_info_t *cio_debug_crw_id;
static inline void
CIO_HEX_EVENT(int level, void *data, int length)
{
+ if (unlikely(!cio_debug_trace_id))
+ return;
while (length > 0) {
debug_event(cio_debug_trace_id, level, data, length);
length -= cio_debug_trace_id->buf_size;
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 28abd697be1a..b960f66843e4 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -45,7 +45,8 @@
#include "ioasm.h"
#include "chsc.h"
-/* parameter to enable cmf during boot, possible uses are:
+/*
+ * parameter to enable cmf during boot, possible uses are:
* "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
* used on any subchannel
* "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
@@ -73,18 +74,20 @@ enum cmb_index {
* enum cmb_format - types of supported measurement block formats
*
* @CMF_BASIC: traditional channel measurement blocks supported
- * by all machines that we run on
+ * by all machines that we run on
* @CMF_EXTENDED: improved format that was introduced with the z990
- * machine
- * @CMF_AUTODETECT: default: use extended format when running on a z990
- * or later machine, otherwise fall back to basic format
- **/
+ * machine
+ * @CMF_AUTODETECT: default: use extended format when running on a machine
+ * supporting extended format, otherwise fall back to
+ * basic format
+ */
enum cmb_format {
CMF_BASIC,
CMF_EXTENDED,
CMF_AUTODETECT = -1,
};
-/**
+
+/*
* format - actual format for all measurement blocks
*
* The format module parameter can be set to a value of 0 (zero)
@@ -105,20 +108,21 @@ module_param(format, bool, 0444);
* either with the help of a special pool or with kmalloc
* @free: free memory allocated with @alloc
* @set: enable or disable measurement
+ * @read: read a measurement entry at an index
* @readall: read a measurement block in a common format
* @reset: clear the data in the associated measurement block and
* reset its time stamp
* @align: align an allocated block so that the hardware can use it
*/
struct cmb_operations {
- int (*alloc) (struct ccw_device*);
- void(*free) (struct ccw_device*);
- int (*set) (struct ccw_device*, u32);
- u64 (*read) (struct ccw_device*, int);
- int (*readall)(struct ccw_device*, struct cmbdata *);
- void (*reset) (struct ccw_device*);
- void * (*align) (void *);
-
+ int (*alloc) (struct ccw_device *);
+ void (*free) (struct ccw_device *);
+ int (*set) (struct ccw_device *, u32);
+ u64 (*read) (struct ccw_device *, int);
+ int (*readall)(struct ccw_device *, struct cmbdata *);
+ void (*reset) (struct ccw_device *);
+ void *(*align) (void *);
+/* private: */
struct attribute_group *attr_group;
};
static struct cmb_operations *cmbops;
@@ -130,9 +134,11 @@ struct cmb_data {
unsigned long long last_update; /* when last_block was updated */
};
-/* our user interface is designed in terms of nanoseconds,
+/*
+ * Our user interface is designed in terms of nanoseconds,
* while the hardware measures total times in its own
- * unit.*/
+ * unit.
+ */
static inline u64 time_to_nsec(u32 value)
{
return ((u64)value) * 128000ull;
@@ -159,12 +165,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
return ret;
}
-/* activate or deactivate the channel monitor. When area is NULL,
+/*
+ * Activate or deactivate the channel monitor. When area is NULL,
* the monitor is deactivated. The channel monitor needs to
* be active in order to measure subchannels, which also need
- * to be enabled. */
-static inline void
-cmf_activate(void *area, unsigned int onoff)
+ * to be enabled.
+ */
+static inline void cmf_activate(void *area, unsigned int onoff)
{
register void * __gpr2 asm("2");
register long __gpr1 asm("1");
@@ -175,8 +182,8 @@ cmf_activate(void *area, unsigned int onoff)
asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
}
-static int
-set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
+static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
+ unsigned long address)
{
int ret;
int retry;
@@ -466,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev)
*
* @mem: pointer to CMBs (only in basic measurement mode)
* @list: contains a linked list of all subchannels
+ * @num_channels: number of channels to be measured
* @lock: protect concurrent access to @mem and @list
*/
struct cmb_area {
@@ -481,28 +489,36 @@ static struct cmb_area cmb_area = {
.num_channels = 1024,
};
-
/* ****** old style CMB handling ********/
-/** int maxchannels
- *
+/*
* Basic channel measurement blocks are allocated in one contiguous
* block of memory, which can not be moved as long as any channel
* is active. Therefore, a maximum number of subchannels needs to
* be defined somewhere. This is a module parameter, defaulting to
* a resonable value of 1024, or 32 kb of memory.
* Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096
+ * maximum is 4096.
*/
module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
/**
* struct cmb - basic channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @reserved: unused in basic measurement mode
*
- * cmb as used by the hardware the fields are described in z/Architecture
- * Principles of Operation, chapter 17.
- * The area to be a contiguous array and may not be reallocated or freed.
+ * The measurement block as used by the hardware. The fields are described
+ * further in z/Architecture Principles of Operation, chapter 17.
+ *
+ * The cmb area made up from these blocks must be a contiguous array and may
+ * not be reallocated or freed.
* Only one cmb area can be present in the system.
*/
struct cmb {
@@ -516,8 +532,9 @@ struct cmb {
u32 reserved[2];
};
-/* insert a single device into the cmb_area list
- * called with cmb_area.lock held from alloc_cmb
+/*
+ * Insert a single device into the cmb_area list.
+ * Called with cmb_area.lock held from alloc_cmb.
*/
static int alloc_cmb_single(struct ccw_device *cdev,
struct cmb_data *cmb_data)
@@ -532,9 +549,11 @@ static int alloc_cmb_single(struct ccw_device *cdev,
goto out;
}
- /* find first unused cmb in cmb_area.mem.
- * this is a little tricky: cmb_area.list
- * remains sorted by ->cmb->hw_data pointers */
+ /*
+ * Find first unused cmb in cmb_area.mem.
+ * This is a little tricky: cmb_area.list
+ * remains sorted by ->cmb->hw_data pointers.
+ */
cmb = cmb_area.mem;
list_for_each_entry(node, &cmb_area.list, cmb_list) {
struct cmb_data *data;
@@ -558,8 +577,7 @@ out:
return ret;
}
-static int
-alloc_cmb (struct ccw_device *cdev)
+static int alloc_cmb(struct ccw_device *cdev)
{
int ret;
struct cmb *mem;
@@ -594,6 +612,9 @@ alloc_cmb (struct ccw_device *cdev)
free_pages((unsigned long)mem, get_order(size));
} else if (!mem) {
/* no luck */
+ printk(KERN_WARNING "cio: failed to allocate area "
+ "for measuring %d subchannels\n",
+ cmb_area.num_channels);
ret = -ENOMEM;
goto out;
} else {
@@ -667,7 +688,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme)
return set_schib_wait(cdev, mme, 0, offset);
}
-static u64 read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb(struct ccw_device *cdev, int index)
{
struct cmb *cmb;
u32 val;
@@ -717,7 +738,7 @@ out:
return ret;
}
-static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
{
struct cmb *cmb;
struct cmb_data *cmb_data;
@@ -790,14 +811,25 @@ static struct cmb_operations cmbops_basic = {
.align = align_cmb,
.attr_group = &cmf_attr_group,
};
-
+
/* ******** extended cmb handling ********/
/**
* struct cmbe - extended channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy
+ * @initial_command_response_time: initial command response time
+ * @reserved: unused
*
- * cmb as used by the hardware, may be in any 64 bit physical location,
- * the fields are described in z/Architecture Principles of Operation,
+ * The measurement block as used by the hardware. May be in any 64 bit physical
+ * location.
+ * The fields are described further in z/Architecture Principles of Operation,
* third edition, chapter 17.
*/
struct cmbe {
@@ -813,10 +845,12 @@ struct cmbe {
u32 reserved[7];
};
-/* kmalloc only guarantees 8 byte alignment, but we need cmbe
+/*
+ * kmalloc only guarantees 8 byte alignment, but we need cmbe
* pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes */
-static inline struct cmbe* cmbe_align(struct cmbe *c)
+ * enough space for two cmbes.
+ */
+static inline struct cmbe *cmbe_align(struct cmbe *c)
{
unsigned long addr;
addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -824,7 +858,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
return (struct cmbe*)addr;
}
-static int alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe(struct ccw_device *cdev)
{
struct cmbe *cmbe;
struct cmb_data *cmb_data;
@@ -870,7 +904,7 @@ out_free:
return ret;
}
-static void free_cmbe (struct ccw_device *cdev)
+static void free_cmbe(struct ccw_device *cdev)
{
struct cmb_data *cmb_data;
@@ -909,7 +943,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
}
-static u64 read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe(struct ccw_device *cdev, int index)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -967,7 +1001,7 @@ out:
return ret;
}
-static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -1044,17 +1078,16 @@ static struct cmb_operations cmbops_extended = {
.align = align_cmbe,
.attr_group = &cmf_attr_group_ext,
};
-
-static ssize_t
-cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
{
return sprintf(buf, "%lld\n",
(unsigned long long) cmf_read(to_ccwdev(dev), idx));
}
-static ssize_t
-cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_sample_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct ccw_device *cdev;
long interval;
@@ -1076,8 +1109,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%ld\n", interval);
}
-static ssize_t
-cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_utilization(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct cmbdata data;
u64 utilization;
@@ -1109,14 +1143,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
}
#define cmf_attr(name) \
-static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(name, 0444, show_##name, NULL);
#define cmf_attr_avg(name) \
-static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
+static ssize_t show_avg_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
cmf_attr(ssch_rsch_count);
cmf_attr(sample_count);
@@ -1128,7 +1164,8 @@ cmf_attr_avg(device_active_only_time);
cmf_attr_avg(device_busy_time);
cmf_attr_avg(initial_command_response_time);
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
+ NULL);
static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
static struct attribute *cmf_attributes[] = {
@@ -1169,12 +1206,16 @@ static struct attribute_group cmf_attr_group_ext = {
.attrs = cmf_attributes_ext,
};
-static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
}
-static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
+static ssize_t cmb_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t c)
{
struct ccw_device *cdev;
int ret;
@@ -1185,12 +1226,12 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att
case '0':
ret = disable_cmf(cdev);
if (ret)
- printk(KERN_INFO "disable_cmf failed (%d)\n", ret);
+ dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
break;
case '1':
ret = enable_cmf(cdev);
if (ret && ret != -EBUSY)
- printk(KERN_INFO "enable_cmf failed (%d)\n", ret);
+ dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
break;
}
@@ -1199,9 +1240,16 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att
DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
-/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
-int
-enable_cmf(struct ccw_device *cdev)
+/**
+ * enable_cmf() - switch on the channel measurement for a specific device
+ * @cdev: The ccw device to be enabled
+ *
+ * Returns %0 for success or a negative error value.
+ *
+ * Context:
+ * non-atomic
+ */
+int enable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1222,8 +1270,16 @@ enable_cmf(struct ccw_device *cdev)
return ret;
}
-int
-disable_cmf(struct ccw_device *cdev)
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ * @cdev: The ccw device to be disabled
+ *
+ * Returns %0 for success or a negative error value.
+ *
+ * Context:
+ * non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1235,14 +1291,32 @@ disable_cmf(struct ccw_device *cdev)
return ret;
}
-u64
-cmf_read(struct ccw_device *cdev, int index)
+/**
+ * cmf_read() - read one value from the current channel measurement block
+ * @cdev: the channel to be read
+ * @index: the index of the value to be read
+ *
+ * Returns the value read or %0 if the value cannot be read.
+ *
+ * Context:
+ * any
+ */
+u64 cmf_read(struct ccw_device *cdev, int index)
{
return cmbops->read(cdev, index);
}
-int
-cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+/**
+ * cmf_readall() - read the current channel measurement block
+ * @cdev: the channel to be read
+ * @data: a pointer to a data block that will be filled
+ *
+ * Returns %0 on success, a negative error value otherwise.
+ *
+ * Context:
+ * any
+ */
+int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
{
return cmbops->readall(cdev, data);
}
@@ -1254,15 +1328,16 @@ int cmf_reenable(struct ccw_device *cdev)
return cmbops->set(cdev, 2);
}
-static int __init
-init_cmf(void)
+static int __init init_cmf(void)
{
char *format_string;
char *detect_string = "parameter";
- /* We cannot really autoprobe this. If the user did not give a parameter,
- see if we are running on z990 or up, otherwise fall back to basic mode. */
-
+ /*
+ * If the user did not give a parameter, see if we are running on a
+ * machine supporting extended measurement blocks, otherwise fall back
+ * to basic mode.
+ */
if (format == CMF_AUTODETECT) {
if (!css_characteristics_avail ||
!css_general_characteristics.ext_mb) {
@@ -1279,26 +1354,19 @@ init_cmf(void)
case CMF_BASIC:
format_string = "basic";
cmbops = &cmbops_basic;
- if (cmb_area.num_channels > 4096 || cmb_area.num_channels < 1) {
- printk(KERN_ERR "Basic channel measurement facility"
- " can only use 1 to 4096 devices\n"
- KERN_ERR "when the cmf driver is built"
- " as a loadable module\n");
- return 1;
- }
break;
case CMF_EXTENDED:
- format_string = "extended";
+ format_string = "extended";
cmbops = &cmbops_extended;
break;
default:
- printk(KERN_ERR "Invalid format %d for channel "
+ printk(KERN_ERR "cio: Invalid format %d for channel "
"measurement facility\n", format);
return 1;
}
- printk(KERN_INFO "Channel measurement facility using %s format (%s)\n",
- format_string, detect_string);
+ printk(KERN_INFO "cio: Channel measurement facility using %s "
+ "format (%s)\n", format_string, detect_string);
return 0;
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index dfca0ef139fd..5d83dd471461 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/list.h>
+#include <linux/reboot.h>
#include "css.h"
#include "cio.h"
@@ -27,7 +28,7 @@ int css_init_done = 0;
static int need_reprobe = 0;
static int max_ssid = 0;
-struct channel_subsystem *css[__MAX_CSSID + 1];
+struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
@@ -79,6 +80,7 @@ css_alloc_subchannel(struct subchannel_id schid)
sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
ret = cio_modify(sch);
if (ret) {
+ kfree(sch->lock);
kfree(sch);
return ERR_PTR(ret);
}
@@ -109,7 +111,7 @@ css_subchannel_release(struct device *dev)
}
}
-int css_sch_device_register(struct subchannel *sch)
+static int css_sch_device_register(struct subchannel *sch)
{
int ret;
@@ -176,7 +178,7 @@ static int css_register_subchannel(struct subchannel *sch)
int ret;
/* Initialize the subchannel structure */
- sch->dev.parent = &css[0]->device;
+ sch->dev.parent = &channel_subsystems[0]->device;
sch->dev.bus = &css_bus_type;
sch->dev.release = &css_subchannel_release;
sch->dev.groups = subch_attr_groups;
@@ -184,8 +186,8 @@ static int css_register_subchannel(struct subchannel *sch)
/* make it known to the system */
ret = css_sch_device_register(sch);
if (ret) {
- printk (KERN_WARNING "%s: could not register %s\n",
- __func__, sch->dev.bus_id);
+ CIO_MSG_EVENT(0, "Could not register sch 0.%x.%04x: %d\n",
+ sch->schid.ssid, sch->schid.sch_no, ret);
return ret;
}
return ret;
@@ -371,15 +373,12 @@ static int __init slow_subchannel_init(void)
spin_lock_init(&slow_subchannel_lock);
slow_subchannel_set = idset_sch_new();
if (!slow_subchannel_set) {
- printk(KERN_WARNING "cio: could not allocate slow subchannel "
- "set\n");
+ CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n");
return -ENOMEM;
}
return 0;
}
-subsys_initcall(slow_subchannel_init);
-
static void css_slow_path_func(struct work_struct *unused)
{
struct subchannel_id schid;
@@ -425,8 +424,8 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
struct subchannel *sch;
int ret;
- CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
- schid.ssid, schid.sch_no);
+ CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
+ schid.ssid, schid.sch_no);
if (need_reprobe)
return -EAGAIN;
@@ -608,30 +607,55 @@ static int __init setup_css(int nr)
{
u32 tod_high;
int ret;
+ struct channel_subsystem *css;
- memset(css[nr], 0, sizeof(struct channel_subsystem));
- css[nr]->pseudo_subchannel =
- kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
- if (!css[nr]->pseudo_subchannel)
+ css = channel_subsystems[nr];
+ memset(css, 0, sizeof(struct channel_subsystem));
+ css->pseudo_subchannel =
+ kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
+ if (!css->pseudo_subchannel)
return -ENOMEM;
- css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
- css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
- sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
- ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+ css->pseudo_subchannel->dev.parent = &css->device;
+ css->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css->pseudo_subchannel);
if (ret) {
- kfree(css[nr]->pseudo_subchannel);
+ kfree(css->pseudo_subchannel);
return ret;
}
- mutex_init(&css[nr]->mutex);
- css[nr]->valid = 1;
- css[nr]->cssid = nr;
- sprintf(css[nr]->device.bus_id, "css%x", nr);
- css[nr]->device.release = channel_subsystem_release;
+ mutex_init(&css->mutex);
+ css->valid = 1;
+ css->cssid = nr;
+ sprintf(css->device.bus_id, "css%x", nr);
+ css->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
- css_generate_pgid(css[nr], tod_high);
+ css_generate_pgid(css, tod_high);
return 0;
}
+static int css_reboot_event(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ int ret, i;
+
+ ret = NOTIFY_DONE;
+ for (i = 0; i <= __MAX_CSSID; i++) {
+ struct channel_subsystem *css;
+
+ css = channel_subsystems[i];
+ if (css->cm_enabled)
+ if (chsc_secm(css, 0))
+ ret = NOTIFY_BAD;
+ }
+
+ return ret;
+}
+
+static struct notifier_block css_reboot_notifier = {
+ .notifier_call = css_reboot_event,
+};
+
/*
* Now that the driver core is running, we can setup our channel subsystem.
* The struct subchannel's are created during probing (except for the
@@ -642,9 +666,20 @@ init_channel_subsystem (void)
{
int ret, i;
- if (chsc_determine_css_characteristics() == 0)
+ ret = chsc_determine_css_characteristics();
+ if (ret == -ENOMEM)
+ goto out; /* No need to continue. */
+ if (ret == 0)
css_characteristics_avail = 1;
+ ret = chsc_alloc_sei_area();
+ if (ret)
+ goto out;
+
+ ret = slow_subchannel_init();
+ if (ret)
+ goto out;
+
if ((ret = bus_register(&css_bus_type)))
goto out;
@@ -661,55 +696,71 @@ init_channel_subsystem (void)
}
/* Setup css structure. */
for (i = 0; i <= __MAX_CSSID; i++) {
- css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
- if (!css[i]) {
+ struct channel_subsystem *css;
+
+ css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+ if (!css) {
ret = -ENOMEM;
goto out_unregister;
}
+ channel_subsystems[i] = css;
ret = setup_css(i);
if (ret)
goto out_free;
- ret = device_register(&css[i]->device);
+ ret = device_register(&css->device);
if (ret)
goto out_free_all;
if (css_characteristics_avail &&
css_chsc_characteristics.secm) {
- ret = device_create_file(&css[i]->device,
+ ret = device_create_file(&css->device,
&dev_attr_cm_enable);
if (ret)
goto out_device;
}
- ret = device_register(&css[i]->pseudo_subchannel->dev);
+ ret = device_register(&css->pseudo_subchannel->dev);
if (ret)
goto out_file;
}
+ ret = register_reboot_notifier(&css_reboot_notifier);
+ if (ret)
+ goto out_pseudo;
css_init_done = 1;
ctl_set_bit(6, 28);
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_pseudo:
+ device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
out_file:
- device_remove_file(&css[i]->device, &dev_attr_cm_enable);
+ device_remove_file(&channel_subsystems[i]->device,
+ &dev_attr_cm_enable);
out_device:
- device_unregister(&css[i]->device);
+ device_unregister(&channel_subsystems[i]->device);
out_free_all:
- kfree(css[i]->pseudo_subchannel->lock);
- kfree(css[i]->pseudo_subchannel);
+ kfree(channel_subsystems[i]->pseudo_subchannel->lock);
+ kfree(channel_subsystems[i]->pseudo_subchannel);
out_free:
- kfree(css[i]);
+ kfree(channel_subsystems[i]);
out_unregister:
while (i > 0) {
+ struct channel_subsystem *css;
+
i--;
- device_unregister(&css[i]->pseudo_subchannel->dev);
+ css = channel_subsystems[i];
+ device_unregister(&css->pseudo_subchannel->dev);
if (css_characteristics_avail && css_chsc_characteristics.secm)
- device_remove_file(&css[i]->device,
+ device_remove_file(&css->device,
&dev_attr_cm_enable);
- device_unregister(&css[i]->device);
+ device_unregister(&css->device);
}
out_bus:
bus_unregister(&css_bus_type);
out:
+ chsc_free_sei_area();
+ kfree(slow_subchannel_set);
+ printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",
+ ret);
return ret;
}
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index ed7977531c3f..81215ef32435 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -139,7 +139,6 @@ struct css_driver {
*/
extern struct bus_type css_bus_type;
-extern int css_sch_device_register(struct subchannel *);
extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
@@ -168,7 +167,7 @@ struct channel_subsystem {
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
extern struct bus_type css_bus_type;
-extern struct channel_subsystem *css[];
+extern struct channel_subsystem *channel_subsystems[];
/* Some helper functions for disconnected state. */
int device_is_disconnected(struct subchannel *);
@@ -192,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *);
extern struct workqueue_struct *slow_path_wq;
-int subchannel_add_files (struct device *);
extern struct attribute_group *subch_attr_groups[];
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 001682e70f67..7ee57f084a89 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -21,6 +21,7 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/param.h> /* HZ */
+#include <asm/cmb.h>
#include "cio.h"
#include "cio_debug.h"
@@ -78,45 +79,37 @@ static int snprint_alias(char *buf, size_t size,
/* Set up environment variables for ccw device uevent. Return 0 on success,
* non-zero otherwise. */
-static int ccw_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct ccw_device *cdev = to_ccwdev(dev);
struct ccw_device_id *id = &(cdev->id);
- int i = 0;
- int len = 0;
int ret;
char modalias_buf[30];
/* CU_TYPE= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "CU_TYPE=%04X", id->cu_type);
+ ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type);
if (ret)
return ret;
/* CU_MODEL= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "CU_MODEL=%02X", id->cu_model);
+ ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model);
if (ret)
return ret;
/* The next two can be zero, that's ok for us */
/* DEV_TYPE= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "DEV_TYPE=%04X", id->dev_type);
+ ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type);
if (ret)
return ret;
/* DEV_MODEL= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "DEV_MODEL=%02X", id->dev_model);
+ ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model);
if (ret)
return ret;
/* MODALIAS= */
snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "MODALIAS=%s", modalias_buf);
+ ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf);
return ret;
}
@@ -338,19 +331,34 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
rc = device_schedule_callback(&cdev->dev,
ccw_device_remove_orphan_cb);
if (rc)
- dev_info(&cdev->dev, "Couldn't unregister orphan\n");
+ CIO_MSG_EVENT(2, "Couldn't unregister orphan "
+ "0.%x.%04x\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
return;
}
/* Deregister subchannel, which will kill the ccw device. */
rc = device_schedule_callback(cdev->dev.parent,
ccw_device_remove_sch_cb);
if (rc)
- dev_info(&cdev->dev,
- "Couldn't unregister disconnected device\n");
+ CIO_MSG_EVENT(2, "Couldn't unregister disconnected device "
+ "0.%x.%04x\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
}
-int
-ccw_device_set_offline(struct ccw_device *cdev)
+/**
+ * ccw_device_set_offline() - disable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function calls the driver's set_offline() function for @cdev, if
+ * given, and then disables @cdev.
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ * Context:
+ * enabled, ccw device lock not held
+ */
+int ccw_device_set_offline(struct ccw_device *cdev)
{
int ret;
@@ -379,15 +387,28 @@ ccw_device_set_offline(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- pr_debug("ccw_device_offline returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
cdev->online = 1;
}
return ret;
}
-int
-ccw_device_set_online(struct ccw_device *cdev)
+/**
+ * ccw_device_set_online() - enable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function first enables @cdev and then calls the driver's set_online()
+ * function for @cdev, if given. If set_online() returns an error, @cdev is
+ * disabled again.
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ * Context:
+ * enabled, ccw device lock not held
+ */
+int ccw_device_set_online(struct ccw_device *cdev)
{
int ret;
@@ -402,8 +423,10 @@ ccw_device_set_online(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- pr_debug("ccw_device_online returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "ccw_device_online returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
return ret;
}
if (cdev->private->state != DEV_STATE_ONLINE)
@@ -417,9 +440,11 @@ ccw_device_set_online(struct ccw_device *cdev)
spin_unlock_irq(cdev->ccwlock);
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
- else
- pr_debug("ccw_device_offline returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ else
+ CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
return (ret == 0) ? -ENODEV : ret;
}
@@ -439,9 +464,10 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
if (cdev->id.cu_type == 0) {
ret = ccw_device_recognition(cdev);
if (ret) {
- printk(KERN_WARNING"Couldn't start recognition "
- "for device %s (ret=%d)\n",
- cdev->dev.bus_id, ret);
+ CIO_MSG_EVENT(0, "Couldn't start recognition "
+ "for device 0.%x.%04x (ret=%d)\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
return ret;
}
wait_event(cdev->private->wait_q,
@@ -461,8 +487,8 @@ static void online_store_handle_online(struct ccw_device *cdev, int force)
if (force && cdev->private->state == DEV_STATE_BOXED) {
ret = ccw_device_stlck(cdev);
if (ret) {
- printk(KERN_WARNING"ccw_device_stlck for device %s "
- "returned %d!\n", cdev->dev.bus_id, ret);
+ dev_warn(&cdev->dev,
+ "ccw_device_stlck returned %d!\n", ret);
return;
}
if (cdev->id.cu_type == 0)
@@ -893,8 +919,10 @@ io_subchannel_register(struct work_struct *work)
ret = device_reprobe(&cdev->dev);
if (ret)
/* We can't do much here. */
- dev_info(&cdev->dev, "device_reprobe() returned"
- " %d\n", ret);
+ CIO_MSG_EVENT(2, "device_reprobe() returned"
+ " %d for 0.%x.%04x\n", ret,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
}
goto out;
}
@@ -907,8 +935,9 @@ io_subchannel_register(struct work_struct *work)
/* make it known to the system */
ret = ccw_device_register(cdev);
if (ret) {
- printk (KERN_WARNING "%s: could not register %s\n",
- __func__, cdev->dev.bus_id);
+ CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
put_device(&cdev->dev);
spin_lock_irqsave(sch->lock, flags);
sch->dev.driver_data = NULL;
@@ -929,8 +958,7 @@ out:
wake_up(&ccw_device_init_wq);
}
-void
-ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct work_struct *work)
{
struct ccw_device_private *priv;
struct ccw_device *cdev;
@@ -1083,6 +1111,7 @@ io_subchannel_probe (struct subchannel *sch)
* device, e.g. the console.
*/
cdev = sch->dev.driver_data;
+ cdev->dev.groups = ccwdev_attr_groups;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
/*
@@ -1308,8 +1337,19 @@ __ccwdev_check_busid(struct device *dev, void *id)
}
-struct ccw_device *
-get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
+/**
+ * get_ccwdev_by_busid() - obtain device from a bus id
+ * @cdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @cdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ * If a match is found, its reference count of the found device is increased
+ * and it is returned; else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+ const char *bus_id)
{
struct device *dev;
struct device_driver *drv;
@@ -1361,7 +1401,6 @@ ccw_device_remove (struct device *dev)
struct ccw_driver *cdrv = cdev->drv;
int ret;
- pr_debug("removing device %s\n", cdev->dev.bus_id);
if (cdrv->remove)
cdrv->remove(cdev);
if (cdev->online) {
@@ -1374,24 +1413,44 @@ ccw_device_remove (struct device *dev)
dev_fsm_final_state(cdev));
else
//FIXME: we can't fail!
- pr_debug("ccw_device_offline returned %d, device %s\n",
- ret, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ "device 0.%x.%04x\n",
+ ret, cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
}
ccw_device_set_timeout(cdev, 0);
cdev->drv = NULL;
return 0;
}
+static void ccw_device_shutdown(struct device *dev)
+{
+ struct ccw_device *cdev;
+
+ cdev = to_ccwdev(dev);
+ if (cdev->drv && cdev->drv->shutdown)
+ cdev->drv->shutdown(cdev);
+ disable_cmf(cdev);
+}
+
struct bus_type ccw_bus_type = {
.name = "ccw",
.match = ccw_bus_match,
.uevent = ccw_uevent,
.probe = ccw_device_probe,
.remove = ccw_device_remove,
+ .shutdown = ccw_device_shutdown,
};
-int
-ccw_driver_register (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_register() - register a ccw driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ */
+int ccw_driver_register(struct ccw_driver *cdriver)
{
struct device_driver *drv = &cdriver->driver;
@@ -1401,8 +1460,13 @@ ccw_driver_register (struct ccw_driver *cdriver)
return driver_register(drv);
}
-void
-ccw_driver_unregister (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_unregister() - deregister a ccw driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccw_driver_unregister(struct ccw_driver *cdriver)
{
driver_unregister(&cdriver->driver);
}
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index b66338b76579..0d4089600439 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
void ccw_device_do_unreg_rereg(struct work_struct *);
-void ccw_device_call_sch_unregister(struct work_struct *);
void ccw_device_move_to_orphanage(struct work_struct *);
int ccw_device_is_orphan(struct ccw_device *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 6bba80929577..8867443b8060 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -268,7 +268,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
switch (state) {
case DEV_STATE_NOT_OPER:
CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : unknown device %04x on subchannel "
+ "cio: SenseID : unknown device %04x on subchannel "
"0.%x.%04x\n", cdev->private->dev_id.devno,
sch->schid.ssid, sch->schid.sch_no);
break;
@@ -293,7 +293,8 @@ 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: "
+ CIO_DEBUG(KERN_INFO, 2,
+ "cio: SenseID : device 0.%x.%04x reports: "
"CU Type/Mod = %04X/%02X, Dev Type/Mod = "
"%04X/%02X\n",
cdev->private->dev_id.ssid,
@@ -303,7 +304,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
break;
case DEV_STATE_BOXED:
CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : boxed device %04x on subchannel "
+ "cio: SenseID : boxed device %04x on subchannel "
"0.%x.%04x\n", cdev->private->dev_id.devno,
sch->schid.ssid, sch->schid.sch_no);
break;
@@ -388,7 +389,7 @@ 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",
+ "cio: Boxed device %04x on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) {
@@ -445,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
if (cdev->private->pgid[last].inf.ps.state1 ==
SNID_STATE1_RESET)
/* No previous pgid found */
- memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+ memcpy(&cdev->private->pgid[0],
+ &channel_subsystems[0]->global_pgid,
sizeof(struct pgid));
else
/* Use existing pgid */
@@ -542,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
}
-static void
-ccw_device_nopath_notify(struct work_struct *work)
-{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
- struct subchannel *sch;
- int ret;
- unsigned long flags;
-
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- spin_lock_irqsave(cdev->ccwlock, flags);
- sch = to_subchannel(cdev->dev.parent);
- /* Extra sanity. */
- if (sch->lpm)
- goto out_unlock;
- if (sch->driver && sch->driver->notify) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
- spin_lock_irqsave(cdev->ccwlock, flags);
- } else
- ret = 0;
- if (!ret) {
- if (get_device(&sch->dev)) {
- /* Driver doesn't want to keep device. */
- cio_disable_subchannel(sch);
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work,
- &cdev->private->kick_work);
- } else
- put_device(&sch->dev);
- }
- } else {
- cio_disable_subchannel(sch);
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- }
-out_unlock:
- spin_unlock_irqrestore(cdev->ccwlock, flags);
-}
-
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
@@ -630,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
default:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
- if (cdev->online) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
+ if (cdev->online)
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ else
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -689,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err)
break;
default:
cdev->private->flags.donotify = 0;
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -764,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
}
/*
- * Handle not operational event while offline.
+ * Handle not operational event in non-special state.
*/
-static void
-ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_generic_notoper(struct ccw_device *cdev,
+ enum dev_event dev_event)
{
struct subchannel *sch;
cdev->private->state = DEV_STATE_NOT_OPER;
sch = to_subchannel(cdev->dev.parent);
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
- wake_up(&cdev->private->wait_q);
-}
-
-/*
- * Handle not operational event while online.
- */
-static void
-ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
- struct subchannel *sch;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- if (sch->driver->notify) {
- spin_unlock_irq(cdev->ccwlock);
- ret = sch->driver->notify(&sch->dev,
- sch->lpm ? CIO_GONE : CIO_NO_PATH);
- spin_lock_irq(cdev->ccwlock);
- } else
- ret = 0;
- if (ret) {
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- return;
- }
- cdev->private->state = DEV_STATE_NOT_OPER;
- cio_disable_subchannel(sch);
- if (sch->schib.scsw.actl != 0) {
- // FIXME: not-oper indication to device driver ?
- ccw_device_call_handler(cdev);
- }
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
- wake_up(&cdev->private->wait_q);
+ css_schedule_eval(sch->schid);
}
/*
@@ -914,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
cdev->private->state = DEV_STATE_TIMEOUT_KILL;
return;
}
- if (ret == -ENODEV) {
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- } else if (cdev->handler)
+ if (ret == -ENODEV)
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ else if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-ETIMEDOUT));
}
@@ -946,9 +844,10 @@ 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 {
- printk(KERN_INFO "Huh? %s(%s): unsolicited "
- "interrupt...\n",
- __FUNCTION__, cdev->dev.bus_id);
+ CIO_MSG_EVENT(2, "Huh? 0.%x.%04x: unsolicited "
+ "interrupt during w4sense...\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
if (cdev->handler)
cdev->handler (cdev, 0, irb);
}
@@ -1215,8 +1114,8 @@ 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)
{
- printk(KERN_EMERG "dev_jumptable[%i][%i] == NULL\n",
- cdev->private->state, dev_event);
+ CIO_MSG_EVENT(0, "dev_jumptable[%i][%i] == NULL\n",
+ cdev->private->state, dev_event);
BUG();
}
@@ -1231,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_SENSE_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
@@ -1243,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_OFFLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_ONLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_online_timeout,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_W4SENSE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_w4sense,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_DISBAND_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_disband_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_BOXED] = {
- [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_stlck_done,
[DEV_EVENT_TIMEOUT] = ccw_device_stlck_done,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
/* states to wait for i/o completion before doing something */
[DEV_STATE_CLEAR_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_clear_verify,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_TIMEOUT_KILL] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 60b9347f7c92..f232832f2b22 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -17,6 +17,7 @@
#include <asm/delay.h>
#include <asm/cio.h>
#include <asm/lowcore.h>
+#include <asm/diag.h>
#include "cio.h"
#include "cio_debug.h"
@@ -25,51 +26,6 @@
#include "ioasm.h"
/*
- * diag210 is used under VM to get information about a virtual device
- */
-int
-diag210(struct diag210 * addr)
-{
- /*
- * diag 210 needs its data below the 2GB border, so we
- * use a static data area to be sure
- */
- static struct diag210 diag210_tmp;
- static DEFINE_SPINLOCK(diag210_lock);
- unsigned long flags;
- int ccode;
-
- spin_lock_irqsave(&diag210_lock, flags);
- diag210_tmp = *addr;
-
-#ifdef CONFIG_64BIT
- asm volatile(
- " lhi %0,-1\n"
- " sam31\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1: sam64\n"
- EX_TABLE(0b,1b)
- : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
-#else
- asm volatile(
- " lhi %0,-1\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
-#endif
-
- *addr = diag210_tmp;
- spin_unlock_irqrestore(&diag210_lock, flags);
-
- return ccode;
-}
-
-/*
* Input :
* devno - device number
* ps - pointer to sense ID data area
@@ -349,5 +305,3 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
break;
}
}
-
-EXPORT_SYMBOL(diag210);
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index a5d263fb55ae..7fd2dadc3297 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -25,6 +25,16 @@
#include "device.h"
#include "chp.h"
+/**
+ * ccw_device_set_options_mask() - set some options and unset the rest
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, all flags not specified in @flags
+ * are cleared.
+ * Returns:
+ * %0 on success, -%EINVAL on an invalid flag combination.
+ */
int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+/**
+ * ccw_device_set_options() - set some options
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, the remainder is left untouched.
+ * Returns:
+ * %0 on success, -%EINVAL if an invalid flag combination would ensue.
+ */
int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+/**
+ * ccw_device_clear_options() - clear some options
+ * @cdev: device for which the options are to be cleared
+ * @flags: options to be cleared
+ *
+ * All flags specified in @flags are cleared, the remainder is left untouched.
+ */
void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
{
cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
}
-int
-ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_clear() - terminate I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ * outstanding, otherwise the intparm associated with the I/O request
+ * is returned
+ *
+ * ccw_device_clear() calls csch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-int
-ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags)
+/**
+ * ccw_device_start_key() - start a s390 channel program with key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags)
{
struct subchannel *sch;
int ret;
@@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-
-int
-ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags, int expires)
+/**
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags, int expires)
{
int ret;
@@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-int
-ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags)
+/**
+ * ccw_device_start() - start a s390 channel program
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, unsigned long flags)
{
return ccw_device_start_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags);
}
-int
-ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags,
- int expires)
+/**
+ * ccw_device_start_timeout() - start a s390 channel program with timeout
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm,
+ unsigned long flags, int expires)
{
return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags,
@@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
}
-int
-ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_halt() - halt I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ * outstanding, otherwise the intparm associated with the I/O request
+ * is returned
+ *
+ * ccw_device_halt() calls hsch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state,
+ * -%EBUSY on device busy or interrupt pending.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-int
-ccw_device_resume(struct ccw_device *cdev)
+/**
+ * ccw_device_resume() - resume channel program execution
+ * @cdev: target ccw device
+ *
+ * ccw_device_resume() calls rsch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state,
+ * -%EBUSY on device busy or interrupt pending.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_resume(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev)
return 1;
}
-/*
- * Search for CIW command in extended sense data.
+/**
+ * ccw_device_get_ciw() - Search for CIW command in extended sense data.
+ * @cdev: ccw device to inspect
+ * @ct: command type to look for
+ *
+ * During SenseID, command information words (CIWs) describing special
+ * commands available to the device may have been stored in the extended
+ * sense data. This function searches for CIWs of a specified command
+ * type in the extended sense data.
+ * Returns:
+ * %NULL if no extended sense data has been stored or if no CIW of the
+ * specified command type could be found,
+ * else a pointer to the CIW of the specified command type.
*/
-struct ciw *
-ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
{
int ciw_cnt;
@@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
return NULL;
}
-__u8
-ccw_device_get_path_mask(struct ccw_device *cdev)
+/**
+ * ccw_device_get_path_mask() - get currently available paths
+ * @cdev: ccw device to be queried
+ * Returns:
+ * %0 if no subchannel for the device is available,
+ * else the mask of currently available paths for the ccw device's subchannel.
+ */
+__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -288,253 +470,6 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
return sch->lpm;
}
-static void
-ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
-{
- if (!ip)
- /* unsolicited interrupt */
- return;
-
- /* Abuse intparm for error reporting. */
- if (IS_ERR(irb))
- cdev->private->intparm = -EIO;
- else if (irb->scsw.cc == 1)
- /* Retry for deferred condition code. */
- cdev->private->intparm = -EAGAIN;
- else if ((irb->scsw.dstat !=
- (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
- (irb->scsw.cstat != 0)) {
- /*
- * We didn't get channel end / device end. Check if path
- * verification has been started; we can retry after it has
- * finished. We also retry unit checks except for command reject
- * or intervention required. Also check for long busy
- * conditions.
- */
- if (cdev->private->flags.doverify ||
- cdev->private->state == DEV_STATE_VERIFY)
- cdev->private->intparm = -EAGAIN;
- else if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
- !(irb->ecw[0] &
- (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
- cdev->private->intparm = -EAGAIN;
- else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
- (irb->scsw.dstat & DEV_STAT_DEV_END) &&
- (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
- cdev->private->intparm = -EAGAIN;
- else
- cdev->private->intparm = -EIO;
-
- } else
- cdev->private->intparm = 0;
- wake_up(&cdev->private->wait_q);
-}
-
-static int
-__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
-{
- int ret;
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- do {
- ccw_device_set_timeout(cdev, 60 * HZ);
- ret = cio_start (sch, ccw, lpm);
- if (ret != 0)
- ccw_device_set_timeout(cdev, 0);
- if (ret == -EBUSY) {
- /* Try again later. */
- spin_unlock_irq(sch->lock);
- msleep(10);
- spin_lock_irq(sch->lock);
- continue;
- }
- if (ret != 0)
- /* Non-retryable error. */
- break;
- /* Wait for end of request. */
- cdev->private->intparm = magic;
- spin_unlock_irq(sch->lock);
- wait_event(cdev->private->wait_q,
- (cdev->private->intparm == -EIO) ||
- (cdev->private->intparm == -EAGAIN) ||
- (cdev->private->intparm == 0));
- spin_lock_irq(sch->lock);
- /* Check at least for channel end / device end */
- if (cdev->private->intparm == -EIO) {
- /* Non-retryable error. */
- ret = -EIO;
- break;
- }
- if (cdev->private->intparm == 0)
- /* Success. */
- break;
- /* Try again later. */
- spin_unlock_irq(sch->lock);
- msleep(10);
- spin_lock_irq(sch->lock);
- } while (1);
-
- return ret;
-}
-
-/**
- * read_dev_chars() - read device characteristics
- * @param cdev target ccw device
- * @param buffer pointer to buffer for rdc data
- * @param length size of rdc data
- * @returns 0 for success, negative error value on failure
- *
- * Context:
- * called for online device, lock not held
- **/
-int
-read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
-{
- void (*handler)(struct ccw_device *, unsigned long, struct irb *);
- struct subchannel *sch;
- int ret;
- struct ccw1 *rdc_ccw;
-
- if (!cdev)
- return -ENODEV;
- if (!buffer || !length)
- return -EINVAL;
- sch = to_subchannel(cdev->dev.parent);
-
- CIO_TRACE_EVENT (4, "rddevch");
- CIO_TRACE_EVENT (4, sch->dev.bus_id);
-
- rdc_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
- if (!rdc_ccw)
- return -ENOMEM;
- rdc_ccw->cmd_code = CCW_CMD_RDC;
- rdc_ccw->count = length;
- rdc_ccw->flags = CCW_FLAG_SLI;
- ret = set_normalized_cda (rdc_ccw, (*buffer));
- if (ret != 0) {
- kfree(rdc_ccw);
- return ret;
- }
-
- spin_lock_irq(sch->lock);
- /* Save interrupt handler. */
- handler = cdev->handler;
- /* Temporarily install own handler. */
- cdev->handler = ccw_device_wake_up;
- if (cdev->private->state != DEV_STATE_ONLINE)
- ret = -ENODEV;
- else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
- !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
- cdev->private->flags.doverify)
- ret = -EBUSY;
- else
- /* 0x00D9C4C3 == ebcdic "RDC" */
- ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, 0);
-
- /* Restore interrupt handler. */
- cdev->handler = handler;
- spin_unlock_irq(sch->lock);
-
- clear_normalized_cda (rdc_ccw);
- kfree(rdc_ccw);
-
- return ret;
-}
-
-/*
- * Read Configuration data using path mask
- */
-int
-read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lpm)
-{
- void (*handler)(struct ccw_device *, unsigned long, struct irb *);
- struct subchannel *sch;
- struct ciw *ciw;
- char *rcd_buf;
- int ret;
- struct ccw1 *rcd_ccw;
-
- if (!cdev)
- return -ENODEV;
- if (!buffer || !length)
- return -EINVAL;
- sch = to_subchannel(cdev->dev.parent);
-
- CIO_TRACE_EVENT (4, "rdconf");
- CIO_TRACE_EVENT (4, sch->dev.bus_id);
-
- /*
- * scan for RCD command in extended SenseID data
- */
- ciw = ccw_device_get_ciw(cdev, CIW_TYPE_RCD);
- if (!ciw || ciw->cmd == 0)
- return -EOPNOTSUPP;
-
- /* Adjust requested path mask to excluded varied off paths. */
- if (lpm) {
- lpm &= sch->opm;
- if (lpm == 0)
- return -EACCES;
- }
-
- rcd_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
- if (!rcd_ccw)
- return -ENOMEM;
- rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
- if (!rcd_buf) {
- kfree(rcd_ccw);
- return -ENOMEM;
- }
- rcd_ccw->cmd_code = ciw->cmd;
- rcd_ccw->cda = (__u32) __pa (rcd_buf);
- rcd_ccw->count = ciw->count;
- rcd_ccw->flags = CCW_FLAG_SLI;
-
- spin_lock_irq(sch->lock);
- /* Save interrupt handler. */
- handler = cdev->handler;
- /* Temporarily install own handler. */
- cdev->handler = ccw_device_wake_up;
- if (cdev->private->state != DEV_STATE_ONLINE)
- ret = -ENODEV;
- else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
- !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
- cdev->private->flags.doverify)
- ret = -EBUSY;
- else
- /* 0x00D9C3C4 == ebcdic "RCD" */
- ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, lpm);
-
- /* Restore interrupt handler. */
- cdev->handler = handler;
- spin_unlock_irq(sch->lock);
-
- /*
- * on success we update the user input parms
- */
- if (ret) {
- kfree (rcd_buf);
- *buffer = NULL;
- *length = 0;
- } else {
- *length = ciw->count;
- *buffer = rcd_buf;
- }
- kfree(rcd_ccw);
-
- return ret;
-}
-
-/*
- * Read Configuration data
- */
-int
-read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
-{
- return read_conf_data_lpm (cdev, buffer, length, 0);
-}
-
/*
* Try to break the lock on a boxed device.
*/
@@ -604,8 +539,7 @@ out_unlock:
return ret;
}
-void *
-ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
{
struct subchannel *sch;
struct chp_id chpid;
@@ -635,12 +569,6 @@ _ccw_device_get_subchannel_number(struct ccw_device *cdev)
return cdev->private->schid.sch_no;
}
-int
-_ccw_device_get_device_number(struct ccw_device *cdev)
-{
- return cdev->private->dev_id.devno;
-}
-
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_options_mask);
@@ -655,9 +583,5 @@ EXPORT_SYMBOL(ccw_device_start_timeout_key);
EXPORT_SYMBOL(ccw_device_start_key);
EXPORT_SYMBOL(ccw_device_get_ciw);
EXPORT_SYMBOL(ccw_device_get_path_mask);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
-EXPORT_SYMBOL(_ccw_device_get_device_number);
EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc);
-EXPORT_SYMBOL_GPL(read_conf_data_lpm);
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index ed026a1dc324..40a3208c7cf3 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -81,6 +81,7 @@ static __u32 volatile spare_indicator;
static atomic_t spare_indicator_usecount;
#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
static mempool_t *qdio_mempool_scssc;
+static struct kmem_cache *qdio_q_cache;
static debug_info_t *qdio_dbf_setup;
static debug_info_t *qdio_dbf_sbal;
@@ -194,6 +195,8 @@ qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
again:
ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt);
rc = qdio_check_ccq(q, ccq);
+ if ((ccq == 96) && (tmp_cnt != *cnt))
+ rc = 0;
if (rc == 1) {
QDIO_DBF_TEXT5(1,trace,"eqAGAIN");
goto again;
@@ -739,7 +742,8 @@ qdio_get_outbound_buffer_frontier(struct qdio_q *q)
first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used),
(QDIO_MAX_BUFFERS_PER_Q-1));
- if ((!q->is_iqdio_q)&&(!q->hydra_gives_outbound_pcis))
+ if (((!q->is_iqdio_q) && (!q->hydra_gives_outbound_pcis)) ||
+ (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH))
SYNC_MEMORY;
check_next:
@@ -1020,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q)
}
static void
-qdio_outbound_processing(struct qdio_q *q)
+qdio_outbound_processing(unsigned long q)
{
- __qdio_outbound_processing(q);
+ __qdio_outbound_processing((struct qdio_q *) q);
}
/************************* INBOUND ROUTINES *******************************/
@@ -1445,9 +1449,10 @@ out:
}
static void
-tiqdio_inbound_processing(struct qdio_q *q)
+tiqdio_inbound_processing(unsigned long q)
{
- __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
+ __tiqdio_inbound_processing((struct qdio_q *) q,
+ atomic_read(&spare_indicator_usecount));
}
static void
@@ -1490,9 +1495,9 @@ again:
}
static void
-qdio_inbound_processing(struct qdio_q *q)
+qdio_inbound_processing(unsigned long q)
{
- __qdio_inbound_processing(q);
+ __qdio_inbound_processing((struct qdio_q *) q);
}
/************************* MAIN ROUTINES *******************************/
@@ -1617,23 +1622,21 @@ static void
qdio_release_irq_memory(struct qdio_irq *irq_ptr)
{
int i;
+ struct qdio_q *q;
- for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) {
- if (!irq_ptr->input_qs[i])
- goto next;
-
- kfree(irq_ptr->input_qs[i]->slib);
- kfree(irq_ptr->input_qs[i]);
-
-next:
- if (!irq_ptr->output_qs[i])
- continue;
-
- kfree(irq_ptr->output_qs[i]->slib);
- kfree(irq_ptr->output_qs[i]);
-
+ for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
+ q = irq_ptr->input_qs[i];
+ if (q) {
+ free_page((unsigned long) q->slib);
+ kmem_cache_free(qdio_q_cache, q);
+ }
+ q = irq_ptr->output_qs[i];
+ if (q) {
+ free_page((unsigned long) q->slib);
+ kmem_cache_free(qdio_q_cache, q);
+ }
}
- kfree(irq_ptr->qdr);
+ free_page((unsigned long) irq_ptr->qdr);
free_page((unsigned long) irq_ptr);
}
@@ -1680,44 +1683,35 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
{
int i;
struct qdio_q *q;
- int result=-ENOMEM;
-
- for (i=0;i<no_input_qs;i++) {
- q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
- if (!q) {
- QDIO_PRINT_ERR("kmalloc of q failed!\n");
- goto out;
- }
+ for (i = 0; i < no_input_qs; i++) {
+ q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+ memset(q, 0, sizeof(*q));
- q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) {
- QDIO_PRINT_ERR("kmalloc of slib failed!\n");
- goto out;
+ kmem_cache_free(qdio_q_cache, q);
+ return -ENOMEM;
}
-
irq_ptr->input_qs[i]=q;
}
- for (i=0;i<no_output_qs;i++) {
- q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
-
- if (!q) {
- goto out;
- }
+ for (i = 0; i < no_output_qs; i++) {
+ q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+ memset(q, 0, sizeof(*q));
- q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+ q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
if (!q->slib) {
- QDIO_PRINT_ERR("kmalloc of slib failed!\n");
- goto out;
+ kmem_cache_free(qdio_q_cache, q);
+ return -ENOMEM;
}
-
irq_ptr->output_qs[i]=q;
}
-
- result=0;
-out:
- return result;
+ return 0;
}
static void
@@ -1767,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->handler=input_handler;
q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
- q->tasklet.data=(unsigned long)q;
/* q->is_thinint_q isn't valid at this time, but
- * irq_ptr->is_thinint_irq is */
- q->tasklet.func=(void(*)(unsigned long))
- ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
- &qdio_inbound_processing);
+ * irq_ptr->is_thinint_irq is
+ */
+ if (irq_ptr->is_thinint_irq)
+ tasklet_init(&q->tasklet, tiqdio_inbound_processing,
+ (unsigned long) q);
+ else
+ tasklet_init(&q->tasklet, qdio_inbound_processing,
+ (unsigned long) q);
/* actually this is not used for inbound queues. yet. */
atomic_set(&q->busy_siga_counter,0);
@@ -1843,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->last_move_ftc=0;
q->handler=output_handler;
- q->tasklet.data=(unsigned long)q;
- q->tasklet.func=(void(*)(unsigned long))
- &qdio_outbound_processing;
- q->timer.function=(void(*)(unsigned long))
- &qdio_outbound_processing;
- q->timer.data = (long)q;
- init_timer(&q->timer);
+ tasklet_init(&q->tasklet, qdio_outbound_processing,
+ (unsigned long) q);
+ setup_timer(&q->timer, qdio_outbound_processing,
+ (unsigned long) q);
atomic_set(&q->busy_siga_counter,0);
q->timing.busy_start=0;
@@ -2985,17 +2979,17 @@ qdio_allocate(struct qdio_initialize *init_data)
QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
if (!irq_ptr) {
- QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n");
+ QDIO_PRINT_ERR("allocation of irq_ptr failed!\n");
return -ENOMEM;
}
init_MUTEX(&irq_ptr->setting_up_sema);
/* QDR must be in DMA area since CCW data address is only 32 bit */
- irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
+ irq_ptr->qdr = (struct qdr *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) {
free_page((unsigned long) irq_ptr);
- QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
+ QDIO_PRINT_ERR("allocation of irq_ptr->qdr failed!\n");
return -ENOMEM;
}
QDIO_DBF_TEXT0(0,setup,"qdr:");
@@ -3004,6 +2998,7 @@ qdio_allocate(struct qdio_initialize *init_data)
if (qdio_alloc_qs(irq_ptr,
init_data->no_input_qs,
init_data->no_output_qs)) {
+ QDIO_PRINT_ERR("queue allocation failed!\n");
qdio_release_irq_memory(irq_ptr);
return -ENOMEM;
}
@@ -3732,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count
#endif /* CONFIG_64BIT */
}
} else {
- QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+ QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
@@ -3895,9 +3890,19 @@ init_QDIO(void)
if (res)
return res;
+ qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
+ 256, 0, NULL);
+ if (!qdio_q_cache) {
+ qdio_release_qdio_memory();
+ return -ENOMEM;
+ }
+
res = qdio_register_dbf_views();
- if (res)
+ if (res) {
+ kmem_cache_destroy(qdio_q_cache);
+ qdio_release_qdio_memory();
return res;
+ }
QDIO_DBF_TEXT0(0,setup,"initQDIO");
res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
@@ -3929,6 +3934,7 @@ cleanup_QDIO(void)
qdio_release_qdio_memory();
qdio_unregister_dbf_views();
mempool_destroy(qdio_mempool_scssc);
+ kmem_cache_destroy(qdio_q_cache);
bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
printk("qdio: %s: module removed\n",version);
}
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 90bd22014513..67aaff3e668d 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
* uevent function for AP devices. It sets up a single environment
* variable DEV_TYPE which contains the hardware device type.
*/
-static int ap_uevent (struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
{
struct ap_device *ap_dev = to_ap_dev(dev);
- int retval = 0, length = 0, i = 0;
+ int retval = 0;
if (!ap_dev)
return -ENODEV;
/* Set up DEV_TYPE environment variable. */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEV_TYPE=%04X", ap_dev->device_type);
+ retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
if (retval)
return retval;
/* Add MODALIAS= */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=ap:t%02X", ap_dev->device_type);
+ retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
- envp[i] = NULL;
return retval;
}
@@ -1231,8 +1225,9 @@ static void ap_reset_domain(void)
{
int i;
- for (i = 0; i < AP_DEVICES; i++)
- ap_reset_queue(AP_MKQID(i, ap_domain_index));
+ if (ap_domain_index != -1)
+ for (i = 0; i < AP_DEVICES; i++)
+ ap_reset_queue(AP_MKQID(i, ap_domain_index));
}
static void ap_reset_all(void)
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
index 2a9349ad68b7..44253fdd4136 100644
--- a/drivers/s390/crypto/zcrypt_mono.c
+++ b/drivers/s390/crypto/zcrypt_mono.c
@@ -45,7 +45,7 @@
/**
* The module initialization code.
*/
-int __init zcrypt_init(void)
+static int __init zcrypt_init(void)
{
int rc;
@@ -86,7 +86,7 @@ out:
/**
* The module termination code.
*/
-void __exit zcrypt_exit(void)
+static void __exit zcrypt_exit(void)
{
zcrypt_cex2a_exit();
zcrypt_pcixcc_exit();
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 64948788d301..70b9ddc8cf9d 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
};
struct {
struct type6_hdr hdr;
- struct ica_CPRBX cprbx;
+ struct CPRBX cprbx;
} __attribute__((packed)) *msg = ap_msg->message;
int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
}
if (service_rc == 8 && service_rs == 770) {
PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
- zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
- return -EAGAIN;
+ return -EINVAL;
}
if (service_rc == 8 && service_rs == 783) {
PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
return -EAGAIN;
}
+ if (service_rc == 12 && service_rs == 769) {
+ PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+ return -EINVAL;
+ }
PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
service_rc, service_rs);
zdev->online = 0;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
index a78ff307fd19..8cb7d7a6973b 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -28,51 +28,6 @@
#ifndef _ZCRYPT_PCIXCC_H_
#define _ZCRYPT_PCIXCC_H_
-/**
- * CPRBX
- * Note that all shorts and ints are big-endian.
- * All pointer fields are 16 bytes long, and mean nothing.
- *
- * A request CPRB is followed by a request_parameter_block.
- *
- * The request (or reply) parameter block is organized thus:
- * function code
- * VUD block
- * key block
- */
-struct CPRBX {
- unsigned short cprb_len; /* CPRB length 220 */
- unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
- unsigned char pad_000[3]; /* Alignment pad bytes */
- unsigned char func_id[2]; /* function id 0x5432 */
- unsigned char cprb_flags[4]; /* Flags */
- unsigned int req_parml; /* request parameter buffer len */
- unsigned int req_datal; /* request data buffer */
- unsigned int rpl_msgbl; /* reply message block length */
- unsigned int rpld_parml; /* replied parameter block len */
- unsigned int rpl_datal; /* reply data block len */
- unsigned int rpld_datal; /* replied data block len */
- unsigned int req_extbl; /* request extension block len */
- unsigned char pad_001[4]; /* reserved */
- unsigned int rpld_extbl; /* replied extension block len */
- unsigned char req_parmb[16]; /* request parm block 'address' */
- unsigned char req_datab[16]; /* request data block 'address' */
- unsigned char rpl_parmb[16]; /* reply parm block 'address' */
- unsigned char rpl_datab[16]; /* reply data block 'address' */
- unsigned char req_extb[16]; /* request extension block 'addr'*/
- unsigned char rpl_extb[16]; /* reply extension block 'addres'*/
- unsigned short ccp_rtcode; /* server return code */
- unsigned short ccp_rscode; /* server reason code */
- unsigned int mac_data_len; /* Mac Data Length */
- unsigned char logon_id[8]; /* Logon Identifier */
- unsigned char mac_value[8]; /* Mac Value */
- unsigned char mac_content_flgs;/* Mac content flag byte */
- unsigned char pad_002; /* Alignment */
- unsigned short domain; /* Domain */
- unsigned char pad_003[12]; /* Domain masks */
- unsigned char pad_004[36]; /* reserved */
-} __attribute__((packed));
-
int zcrypt_pcixcc_init(void);
void zcrypt_pcixcc_exit(void);
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 348bb7b82771..399695f7b1af 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -317,8 +317,8 @@ claw_probe(struct ccwgroup_device *cgdev)
CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
return -ENOMEM;
}
- privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
- privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+ privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+ privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL);
if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
probe_error(cgdev);
put_device(&cgdev->dev);
@@ -327,8 +327,6 @@ claw_probe(struct ccwgroup_device *cgdev)
CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
return -ENOMEM;
}
- memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
- memset(privptr->p_env, 0x00, sizeof(struct claw_env));
memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
@@ -3893,7 +3891,6 @@ claw_init_netdevice(struct net_device * dev)
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 1300;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
#ifdef FUNCTRACE
printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
#endif
@@ -3924,7 +3921,7 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
ccw_device_get_id(cdev, &dev_id);
p_ch->devno = dev_id.devno;
- if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
+ if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "%s Out of memory in %s for irb\n",
p_ch->id,__FUNCTION__);
#ifdef FUNCTRACE
@@ -3933,7 +3930,6 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
#endif
return -ENOMEM;
}
- memset(p_ch->irb, 0, sizeof (struct irb));
#ifdef FUNCTRACE
printk(KERN_INFO "%s:%s Exit on line %d\n",
cdev->dev.bus_id,__FUNCTION__,__LINE__);
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index b20fd0681733..449937233732 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -674,7 +674,7 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
int first = 1;
int i;
unsigned long duration;
- struct timespec done_stamp = xtime;
+ struct timespec done_stamp = current_kernel_time();
DBF_TEXT(trace, 4, __FUNCTION__);
@@ -730,7 +730,7 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
spin_unlock(&ch->collect_lock);
ch->ccw[1].count = ch->trans_skb->len;
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
- ch->prof.send_stamp = xtime;
+ ch->prof.send_stamp = current_kernel_time();
rc = ccw_device_start(ch->cdev, &ch->ccw[0],
(unsigned long) ch, 0xff, 0);
ch->prof.doios_multi++;
@@ -2281,7 +2281,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
fsm_newstate(ch->fsm, CH_STATE_TX);
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
- ch->prof.send_stamp = xtime;
+ ch->prof.send_stamp = current_kernel_time();
rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx],
(unsigned long) ch, 0xff, 0);
spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
@@ -2823,7 +2823,6 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device,
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 100;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
return dev;
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 08a994fdd1a4..0fd663b23d76 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1400,11 +1400,14 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
cdev->dev.bus_id, dstat, cstat);
if (rc) {
- lcs_schedule_recovery(card);
- wake_up(&card->wait_q);
- return;
+ channel->state = LCS_CH_STATE_ERROR;
}
}
+ if (channel->state == LCS_CH_STATE_ERROR) {
+ lcs_schedule_recovery(card);
+ wake_up(&card->wait_q);
+ return;
+ }
/* How far in the ccw chain have we processed? */
if ((channel->state != LCS_CH_STATE_INIT) &&
(irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
@@ -1708,6 +1711,8 @@ lcs_stopcard(struct lcs_card *card)
if (card->read.state != LCS_CH_STATE_STOPPED &&
card->write.state != LCS_CH_STATE_STOPPED &&
+ card->read.state != LCS_CH_STATE_ERROR &&
+ card->write.state != LCS_CH_STATE_ERROR &&
card->state == DEV_STATE_UP) {
lcs_clear_multicast_list(card);
rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);
@@ -2145,7 +2150,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
card->dev->stop = lcs_stop_device;
card->dev->hard_start_xmit = lcs_start_xmit;
card->dev->get_stats = lcs_getstats;
- SET_MODULE_OWNER(dev);
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
if (!lcs_check_multicast_support(card))
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h
index 0e1e4a0a88f0..8976fb0b070a 100644
--- a/drivers/s390/net/lcs.h
+++ b/drivers/s390/net/lcs.h
@@ -138,6 +138,7 @@ enum lcs_channel_states {
LCS_CH_STATE_RUNNING,
LCS_CH_STATE_SUSPENDED,
LCS_CH_STATE_CLEARED,
+ LCS_CH_STATE_ERROR,
};
/**
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 3d28e1a5bf79..4d18d6419ddc 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -753,7 +753,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
header.next = 0;
memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
- conn->prof.send_stamp = xtime;
+ conn->prof.send_stamp = current_kernel_time();
txmsg.class = 0;
txmsg.tag = 0;
rc = iucv_message_send(conn->path, &txmsg, 0, 0,
@@ -1185,7 +1185,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
fsm_newstate(conn->fsm, CONN_STATE_TX);
- conn->prof.send_stamp = xtime;
+ conn->prof.send_stamp = current_kernel_time();
msg.tag = 1;
msg.class = 0;
@@ -1904,7 +1904,6 @@ static void netiucv_setup_netdevice(struct net_device *dev)
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
}
/**
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index ec18bae05df0..8c6b72d05b1d 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -833,8 +833,7 @@ struct qeth_card {
struct qeth_qdio_info qdio;
struct qeth_perf_stats perf_stats;
int use_hard_stop;
- int (*orig_hard_header)(struct sk_buff *,struct net_device *,
- unsigned short,void *,void *,unsigned);
+ const struct header_ops *orig_header_ops;
struct qeth_osn_info osn_info;
atomic_t force_alloc_skb;
};
@@ -1178,9 +1177,9 @@ qeth_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
char *buf)
{
if (proto == QETH_PROT_IPV4)
- return qeth_ipaddr4_to_string(addr, buf);
+ qeth_ipaddr4_to_string(addr, buf);
else if (proto == QETH_PROT_IPV6)
- return qeth_ipaddr6_to_string(addr, buf);
+ qeth_ipaddr6_to_string(addr, buf);
}
static inline int
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 70108fb16906..e3c268cfbffe 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -159,13 +159,15 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
buffer = buf->buffer;
/* fill one skb into buffer */
for (i = 0; i < ctx->elements_per_skb; ++i){
- buffer->element[buf->next_element_to_fill].addr =
- ctx->elements[element].addr;
- buffer->element[buf->next_element_to_fill].length =
- ctx->elements[element].length;
- buffer->element[buf->next_element_to_fill].flags =
- ctx->elements[element].flags;
- buf->next_element_to_fill++;
+ if (ctx->elements[element].length != 0) {
+ buffer->element[buf->next_element_to_fill].
+ addr = ctx->elements[element].addr;
+ buffer->element[buf->next_element_to_fill].
+ length = ctx->elements[element].length;
+ buffer->element[buf->next_element_to_fill].
+ flags = ctx->elements[element].flags;
+ buf->next_element_to_fill++;
+ }
element++;
elements--;
}
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 57f69434fbf9..a2d08c9ba3c4 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -160,6 +160,9 @@ qeth_set_multicast_list(struct net_device *);
static void
qeth_setadp_promisc_mode(struct qeth_card *);
+static int
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr);
+
static void
qeth_notify_processes(void)
{
@@ -561,7 +564,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
}
static int
-qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
+qeth_threads_running(struct qeth_card *card, unsigned long threads);
static void
@@ -576,8 +579,7 @@ qeth_remove_device(struct ccwgroup_device *cgdev)
if (!card)
return;
- if (qeth_wait_for_threads(card, 0xffffffff))
- return;
+ wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
if (cgdev->state == CCWGROUP_ONLINE){
card->use_hard_stop = 1;
@@ -821,14 +823,15 @@ __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
again:
list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
if (addr->is_multicast) {
+ list_del(&addr->entry);
spin_unlock_irqrestore(&card->ip_lock, *flags);
rc = qeth_deregister_addr_entry(card, addr);
spin_lock_irqsave(&card->ip_lock, *flags);
if (!rc) {
- list_del(&addr->entry);
kfree(addr);
goto again;
- }
+ } else
+ list_add(&addr->entry, &card->ip_list);
}
}
}
@@ -1542,16 +1545,21 @@ qeth_idx_write_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob)
card = CARD_FROM_CDEV(channel->ccwdev);
if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
- PRINT_ERR("IDX_ACTIVATE on write channel device %s: negative "
- "reply\n", CARD_WDEV_ID(card));
+ if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+ PRINT_ERR("IDX_ACTIVATE on write channel device %s: "
+ "adapter exclusively used by another host\n",
+ CARD_WDEV_ID(card));
+ else
+ PRINT_ERR("IDX_ACTIVATE on write channel device %s: "
+ "negative reply\n", CARD_WDEV_ID(card));
goto out;
}
memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {
PRINT_WARN("IDX_ACTIVATE on write channel device %s: "
- "function level mismatch "
- "(sent: 0x%x, received: 0x%x)\n",
- CARD_WDEV_ID(card), card->info.func_level, temp);
+ "function level mismatch "
+ "(sent: 0x%x, received: 0x%x)\n",
+ CARD_WDEV_ID(card), card->info.func_level, temp);
goto out;
}
channel->state = CH_STATE_UP;
@@ -1597,8 +1605,13 @@ qeth_idx_read_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob)
goto out;
}
if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
- PRINT_ERR("IDX_ACTIVATE on read channel device %s: negative "
- "reply\n", CARD_RDEV_ID(card));
+ if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+ PRINT_ERR("IDX_ACTIVATE on read channel device %s: "
+ "adapter exclusively used by another host\n",
+ CARD_RDEV_ID(card));
+ else
+ PRINT_ERR("IDX_ACTIVATE on read channel device %s: "
+ "negative reply\n", CARD_RDEV_ID(card));
goto out;
}
@@ -1613,8 +1626,8 @@ qeth_idx_read_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob)
memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
if (temp != qeth_peer_func_level(card->info.func_level)) {
PRINT_WARN("IDX_ACTIVATE on read channel device %s: function "
- "level mismatch (sent: 0x%x, received: 0x%x)\n",
- CARD_RDEV_ID(card), card->info.func_level, temp);
+ "level mismatch (sent: 0x%x, received: 0x%x)\n",
+ CARD_RDEV_ID(card), card->info.func_level, temp);
goto out;
}
memcpy(&card->token.issuer_rm_r,
@@ -2496,7 +2509,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
struct iphdr *ip_hdr;
QETH_DBF_TEXT(trace,5,"skbfktr");
- skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_TR);
+ skb_set_mac_header(skb, (int)-QETH_FAKE_LL_LEN_TR);
/* this is a fake ethernet header */
fake_hdr = tr_hdr(skb);
@@ -2689,10 +2702,15 @@ qeth_process_inbound_buffer(struct qeth_card *card,
qeth_layer2_rebuild_skb(card, skb, hdr);
else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
vlan_tag = qeth_rebuild_skb(card, skb, hdr);
- else { /*in case of OSN*/
+ else if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) {
skb_push(skb, sizeof(struct qeth_hdr));
skb_copy_to_linear_data(skb, hdr,
sizeof(struct qeth_hdr));
+ } else { /* unknown header type */
+ dev_kfree_skb_any(skb);
+ QETH_DBF_TEXT(trace, 3, "inbunkno");
+ QETH_DBF_HEX(control, 3, hdr, QETH_DBF_CONTROL_LEN);
+ continue;
}
/* is device UP ? */
if (!(card->dev->flags & IFF_UP)){
@@ -2804,13 +2822,16 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
if (newcount < count) {
/* we are in memory shortage so we switch back to
traditional skb allocation and drop packages */
- if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1))
- printk(KERN_WARNING
- "qeth: switch to alloc skb\n");
+ if (!atomic_read(&card->force_alloc_skb) &&
+ net_ratelimit())
+ PRINT_WARN("Switch to alloc skb\n");
+ atomic_set(&card->force_alloc_skb, 3);
count = newcount;
} else {
- if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0))
- printk(KERN_WARNING "qeth: switch to sg\n");
+ if ((atomic_read(&card->force_alloc_skb) == 1) &&
+ net_ratelimit())
+ PRINT_WARN("Switch to sg\n");
+ atomic_add_unless(&card->force_alloc_skb, -1, 0);
}
/*
@@ -3354,10 +3375,12 @@ out_freeoutq:
while (i > 0)
kfree(card->qdio.out_qs[--i]);
kfree(card->qdio.out_qs);
+ card->qdio.out_qs = NULL;
out_freepool:
qeth_free_buffer_pool(card);
out_freeinq:
kfree(card->qdio.in_q);
+ card->qdio.in_q = NULL;
out_nomem:
atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED);
return -ENOMEM;
@@ -3373,16 +3396,20 @@ qeth_free_qdio_buffers(struct qeth_card *card)
QETH_QDIO_UNINITIALIZED)
return;
kfree(card->qdio.in_q);
+ card->qdio.in_q = NULL;
/* inbound buffer pool */
qeth_free_buffer_pool(card);
/* free outbound qdio_qs */
- for (i = 0; i < card->qdio.no_out_queues; ++i){
- for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
- qeth_clear_output_buffer(card->qdio.out_qs[i],
- &card->qdio.out_qs[i]->bufs[j]);
- kfree(card->qdio.out_qs[i]);
+ if (card->qdio.out_qs) {
+ for (i = 0; i < card->qdio.no_out_queues; ++i) {
+ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
+ qeth_clear_output_buffer(card->qdio.out_qs[i],
+ &card->qdio.out_qs[i]->bufs[j]);
+ kfree(card->qdio.out_qs[i]);
+ }
+ kfree(card->qdio.out_qs);
+ card->qdio.out_qs = NULL;
}
- kfree(card->qdio.out_qs);
}
static void
@@ -3393,7 +3420,7 @@ qeth_clear_qdio_buffers(struct qeth_card *card)
QETH_DBF_TEXT(trace, 2, "clearqdbf");
/* clear outbound buffers to free skbs */
for (i = 0; i < card->qdio.no_out_queues; ++i)
- if (card->qdio.out_qs[i]){
+ if (card->qdio.out_qs && card->qdio.out_qs[i]) {
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
qeth_clear_output_buffer(card->qdio.out_qs[i],
&card->qdio.out_qs[i]->bufs[j]);
@@ -3769,8 +3796,8 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype)
/*hard_header fake function; used in case fake_ll is set */
static int
qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr, const void *saddr,
+ unsigned len)
{
if(dev->type == ARPHRD_IEEE802_TR){
struct trh_hdr *hdr;
@@ -3793,6 +3820,11 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
}
}
+static const struct header_ops qeth_fake_ops = {
+ .create = qeth_fake_header,
+ .parse = qeth_hard_header_parse,
+};
+
static int
qeth_send_packet(struct qeth_card *, struct sk_buff *);
@@ -4482,7 +4514,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
/* check if we have enough elements (including following
* free buffers) to handle eddp context */
if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
- printk("eddp tx_dropped 1\n");
+ if (net_ratelimit())
+ PRINT_WARN("eddp tx_dropped 1\n");
rc = -EBUSY;
goto out;
}
@@ -4553,6 +4586,53 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
return elements_needed;
}
+static void qeth_tx_csum(struct sk_buff *skb)
+{
+ int tlen;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ tlen = ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2);
+ switch (ip_hdr(skb)->protocol) {
+ case IPPROTO_TCP:
+ tcp_hdr(skb)->check = 0;
+ tcp_hdr(skb)->check = csum_tcpudp_magic(
+ ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
+ tlen, ip_hdr(skb)->protocol,
+ skb_checksum(skb, skb_transport_offset(skb),
+ tlen, 0));
+ break;
+ case IPPROTO_UDP:
+ udp_hdr(skb)->check = 0;
+ udp_hdr(skb)->check = csum_tcpudp_magic(
+ ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
+ tlen, ip_hdr(skb)->protocol,
+ skb_checksum(skb, skb_transport_offset(skb),
+ tlen, 0));
+ break;
+ }
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ switch (ipv6_hdr(skb)->nexthdr) {
+ case IPPROTO_TCP:
+ tcp_hdr(skb)->check = 0;
+ tcp_hdr(skb)->check = csum_ipv6_magic(
+ &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+ ipv6_hdr(skb)->payload_len,
+ ipv6_hdr(skb)->nexthdr,
+ skb_checksum(skb, skb_transport_offset(skb),
+ ipv6_hdr(skb)->payload_len, 0));
+ break;
+ case IPPROTO_UDP:
+ udp_hdr(skb)->check = 0;
+ udp_hdr(skb)->check = csum_ipv6_magic(
+ &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+ ipv6_hdr(skb)->payload_len,
+ ipv6_hdr(skb)->nexthdr,
+ skb_checksum(skb, skb_transport_offset(skb),
+ ipv6_hdr(skb)->payload_len, 0));
+ break;
+ }
+ }
+}
static int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
@@ -4584,7 +4664,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
if (!card->options.layer2) {
ipv = qeth_get_ip_version(skb);
- if ((card->dev->hard_header == qeth_fake_header) && ipv) {
+ if ((card->dev->header_ops == &qeth_fake_ops) && ipv) {
new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
if (!new_skb)
return -ENOMEM;
@@ -4638,12 +4718,22 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
elements_needed += elems;
}
+ if ((large_send == QETH_LARGE_SEND_NO) &&
+ (skb->ip_summed == CHECKSUM_PARTIAL))
+ qeth_tx_csum(new_skb);
+
if (card->info.type != QETH_CARD_TYPE_IQD)
rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements_needed, ctx);
- else
+ else {
+ if ((!card->options.layer2) &&
+ (ipv == 0)) {
+ __qeth_free_new_skb(skb, new_skb);
+ return -EPERM;
+ }
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
elements_needed, ctx);
+ }
if (!rc) {
card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes;
@@ -6385,20 +6475,18 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
static u32
qeth_ethtool_get_tx_csum(struct net_device *dev)
{
- /* We may need to say that we support tx csum offload if
- * we do EDDP or TSO. There are discussions going on to
- * enforce rules in the stack and in ethtool that make
- * SG and TSO depend on HW_CSUM. At the moment there are
- * no such rules....
- * If we say yes here, we have to checksum outbound packets
- * any time. */
- return 0;
+ return (dev->features & NETIF_F_HW_CSUM) != 0;
}
static int
qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data)
{
- return -EINVAL;
+ if (data)
+ dev->features |= NETIF_F_HW_CSUM;
+ else
+ dev->features &= ~NETIF_F_HW_CSUM;
+
+ return 0;
}
static u32
@@ -6488,12 +6576,16 @@ static struct ethtool_ops qeth_ethtool_ops = {
};
static int
-qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr)
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
- struct qeth_card *card;
- struct ethhdr *eth;
+ const struct qeth_card *card;
+ const struct ethhdr *eth;
+ struct net_device *dev = skb->dev;
- card = qeth_get_card_from_dev(skb->dev);
+ if (dev->type != ARPHRD_IEEE802_TR)
+ return 0;
+
+ card = qeth_get_card_from_dev(dev);
if (card->options.layer2)
goto haveheader;
#ifdef CONFIG_QETH_IPV6
@@ -6523,6 +6615,10 @@ haveheader:
return ETH_ALEN;
}
+static const struct header_ops qeth_null_ops = {
+ .parse = qeth_hard_header_parse,
+};
+
static int
qeth_netdev_init(struct net_device *dev)
{
@@ -6547,12 +6643,8 @@ qeth_netdev_init(struct net_device *dev)
dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
#endif
- if (qeth_get_netdev_flags(card) & IFF_NOARP) {
- dev->rebuild_header = NULL;
- dev->hard_header = NULL;
- dev->header_cache_update = NULL;
- dev->hard_header_cache = NULL;
- }
+ dev->header_ops = &qeth_null_ops;
+
#ifdef CONFIG_QETH_IPV6
/*IPv6 address autoconfiguration stuff*/
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
@@ -6560,11 +6652,8 @@ qeth_netdev_init(struct net_device *dev)
#endif
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
- dev->hard_header = qeth_fake_header;
- if (dev->type == ARPHRD_IEEE802_TR)
- dev->hard_header_parse = NULL;
- else
- dev->hard_header_parse = qeth_hard_header_parse;
+ dev->header_ops = &qeth_fake_ops;
+
dev->set_mac_address = qeth_layer2_set_mac_address;
dev->flags |= qeth_get_netdev_flags(card);
if ((card->options.fake_broadcast) ||
@@ -6576,7 +6665,6 @@ qeth_netdev_init(struct net_device *dev)
dev->mtu = card->info.initial_mtu;
if (card->info.type != QETH_CARD_TYPE_OSN)
SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops);
- SET_MODULE_OWNER(dev);
return 0;
}
@@ -6668,10 +6756,10 @@ retry:
}
/*network device will be recovered*/
if (card->dev) {
- card->dev->hard_header = card->orig_hard_header;
+ card->dev->header_ops = card->orig_header_ops;
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
- card->dev->hard_header = qeth_fake_header;
+ card->dev->header_ops = &qeth_fake_ops;
return 0;
}
/* at first set_online allocate netdev */
@@ -6685,7 +6773,7 @@ retry:
goto out;
}
card->dev->priv = card;
- card->orig_hard_header = card->dev->hard_header;
+ card->orig_header_ops = card->dev->header_ops;
card->dev->type = qeth_get_arphdr_type(card->info.type,
card->info.link_type);
card->dev->init = qeth_netdev_init;
@@ -7412,7 +7500,8 @@ qeth_start_ipa_tso(struct qeth_card *card)
}
if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){
card->options.large_send = QETH_LARGE_SEND_NO;
- card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG);
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+ NETIF_F_HW_CSUM);
}
return rc;
}
@@ -7552,22 +7641,26 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type)
card->options.large_send = type;
switch (card->options.large_send) {
case QETH_LARGE_SEND_EDDP:
- card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+ card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
+ NETIF_F_HW_CSUM;
break;
case QETH_LARGE_SEND_TSO:
if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){
- card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+ card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
+ NETIF_F_HW_CSUM;
} else {
PRINT_WARN("TSO not supported on %s. "
"large_send set to 'no'.\n",
card->dev->name);
- card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+ NETIF_F_HW_CSUM);
card->options.large_send = QETH_LARGE_SEND_NO;
rc = -EOPNOTSUPP;
}
break;
default: /* includes QETH_LARGE_SEND_NO */
- card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+ NETIF_F_HW_CSUM);
break;
}
if (card->state == CARD_STATE_UP)
@@ -8231,7 +8324,7 @@ qeth_arp_constructor(struct neighbour *neigh)
if (card == NULL)
goto out;
if((card->options.layer2) ||
- (card->dev->hard_header == qeth_fake_header))
+ (card->dev->header_ops == &qeth_fake_ops))
goto out;
rcu_read_lock();
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 1d8083c91765..6de2da5ed5fd 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -565,6 +565,7 @@ extern unsigned char IDX_ACTIVATE_WRITE[];
#define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
+#define QETH_IDX_ACT_CAUSE_CODE(buffer) (buffer)[0x09]
#define PDU_ENCAPSULATION(buffer) \
(buffer + *(buffer + (*(buffer+0x0b)) + \
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index bb0287ad1aac..2cc3f3a0e393 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -1760,10 +1760,10 @@ qeth_remove_device_attributes(struct device *dev)
{
struct qeth_card *card = dev->driver_data;
- if (card->info.type == QETH_CARD_TYPE_OSN)
- return sysfs_remove_group(&dev->kobj,
- &qeth_osn_device_attr_group);
-
+ if (card->info.type == QETH_CARD_TYPE_OSN) {
+ sysfs_remove_group(&dev->kobj, &qeth_osn_device_attr_group);
+ return;
+ }
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index a1db95925138..90aa53fc4f3e 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -259,21 +259,21 @@ zfcp_module_init(void)
size = sizeof(struct zfcp_fsf_req_qtcb);
align = calc_alignment(size);
zfcp_data.fsf_req_qtcb_cache =
- kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL);
+ kmem_cache_create("zfcp_fsf", size, align, 0, NULL);
if (!zfcp_data.fsf_req_qtcb_cache)
goto out;
size = sizeof(struct fsf_status_read_buffer);
align = calc_alignment(size);
zfcp_data.sr_buffer_cache =
- kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL);
+ kmem_cache_create("zfcp_sr", size, align, 0, NULL);
if (!zfcp_data.sr_buffer_cache)
goto out_sr_cache;
size = sizeof(struct zfcp_gid_pn_data);
align = calc_alignment(size);
zfcp_data.gid_pn_cache =
- kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL);
+ kmem_cache_create("zfcp_gid", size, align, 0, NULL);
if (!zfcp_data.gid_pn_cache)
goto out_gid_cache;
@@ -1503,7 +1503,7 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
data->ct.pool = pool;
}
} else {
- data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC);
+ data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC);
}
if (NULL == data)
@@ -1526,15 +1526,12 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
* zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request
* @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed
*/
-static void
-zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
+static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
{
- if ((gid_pn->ct.pool != 0))
+ if (gid_pn->ct.pool)
mempool_free(gid_pn, gid_pn->ct.pool);
else
- kfree(gid_pn);
-
- return;
+ kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn);
}
/**
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 1c8f71a59855..c0d1c0eb3209 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *);
static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct device *);
+static void zfcp_ccw_shutdown(struct ccw_device *);
static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = {
.set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
- .driver = {
- .shutdown = zfcp_ccw_shutdown,
- },
+ .shutdown = zfcp_ccw_shutdown,
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -277,12 +275,12 @@ zfcp_ccw_register(void)
* Makes sure that QDIO queues are down when the system gets stopped.
*/
static void
-zfcp_ccw_shutdown(struct device *dev)
+zfcp_ccw_shutdown(struct ccw_device *cdev)
{
struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema);
- adapter = dev_get_drvdata(dev);
+ adapter = dev_get_drvdata(&cdev->dev);
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 5f3212440f68..ffa3bf756943 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -19,8 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <asm/debug.h>
#include <linux/ctype.h>
+#include <asm/debug.h>
#include "zfcp_ext.h"
static u32 dbfsize = 4;
@@ -35,17 +35,17 @@ static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
- struct timespec xtime;
+ struct timespec dbftime;
int len = 0;
stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
sec = stck >> 12;
do_div(sec, 1000000);
- xtime.tv_sec = sec;
+ dbftime.tv_sec = sec;
stck -= (sec * 1000000) << 12;
- xtime.tv_nsec = ((stck * 1000) >> 12);
+ dbftime.tv_nsec = ((stck * 1000) >> 12);
len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
- label, xtime.tv_sec, xtime.tv_nsec);
+ label, dbftime.tv_sec, dbftime.tv_nsec);
return len;
}
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 22649639230b..b36dfc40d9fa 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -126,6 +126,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
#define ZFCP_MIN_OUTPUT_THRESHOLD 1 /* ignored by QDIO layer */
#define QDIO_SCSI_QFMT 1 /* 1 for FSF */
+#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
/********************* FSF SPECIFIC DEFINES *********************************/
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 4e7cb6dc4d34..16b4418ab257 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int);
static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
-static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
@@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
static void zfcp_erp_action_ready(struct zfcp_erp_action *);
static int zfcp_erp_action_exists(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
static void zfcp_erp_memwait_handler(unsigned long);
@@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data)
* action gets an appropriate flag and will be processed
* accordingly
*/
-void zfcp_erp_timeout_handler(unsigned long data)
+static void zfcp_erp_timeout_handler(unsigned long data)
{
struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action,
return retval;
}
-static inline int
+static int
zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
{
return
@@ -1626,7 +1626,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
{
struct zfcp_erp_add_work *p;
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
"the FCP-LUN 0x%Lx connected to "
@@ -1639,7 +1639,6 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
}
zfcp_unit_get(unit);
- memset(p, 0, sizeof(*p));
atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
INIT_WORK(&p->work, zfcp_erp_scsi_scan);
p->unit = unit;
@@ -2002,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
* returns: 0 - successful setup
* !0 - failed setup
*/
-int
+static int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{
int retval;
@@ -3249,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
zfcp_erp_action_dismiss(&unit->erp_action);
}
-static inline void
-zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -3259,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
}
-static inline void
-zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 0eb31e162b15..99299976e891 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1930,7 +1930,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
skip_fsfstatus:
send_els->status = retval;
- if (send_els->handler != 0)
+ if (send_els->handler)
send_els->handler(send_els->handler_data);
return retval;
@@ -4154,8 +4154,9 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
fcp_rsp_iu->fcp_resid,
(int) zfcp_get_fcp_dl(fcp_cmnd_iu));
- scpnt->resid = fcp_rsp_iu->fcp_resid;
- if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow)
+ scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
+ if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
+ scpnt->underflow)
set_host_byte(&scpnt->result, DID_ERROR);
}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index bdf5782b8a7a..c6899efdc8f6 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -36,8 +36,6 @@ static void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
static int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static int zfcp_qdio_sbals_from_buffer
- (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
static qdio_handler_t zfcp_qdio_request_handler;
static qdio_handler_t zfcp_qdio_response_handler;
@@ -47,103 +45,56 @@ static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
/*
- * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
- * array in the adapter struct.
- * Cur_buf is the pointer array and count can be any number of required
- * buffers, the page-fitting arithmetic is done entirely within this funciton.
+ * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
+ * in the adapter struct sbuf is the pointer array.
*
- * returns: number of buffers allocated
* locks: must only be called with zfcp_data.config_sema taken
*/
-static int
-zfcp_qdio_buffers_enqueue(struct qdio_buffer **cur_buf, int count)
+static void
+zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf)
{
- int buf_pos;
- int qdio_buffers_per_page;
- int page_pos = 0;
- struct qdio_buffer *first_in_page = NULL;
-
- qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
- ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
-
- for (buf_pos = 0; buf_pos < count; buf_pos++) {
- if (page_pos == 0) {
- cur_buf[buf_pos] = (struct qdio_buffer *)
- get_zeroed_page(GFP_KERNEL);
- if (cur_buf[buf_pos] == NULL) {
- ZFCP_LOG_INFO("error: allocation of "
- "QDIO buffer failed \n");
- goto out;
- }
- first_in_page = cur_buf[buf_pos];
- } else {
- cur_buf[buf_pos] = first_in_page + page_pos;
+ int pos;
- }
- /* was initialised to zero */
- page_pos++;
- page_pos %= qdio_buffers_per_page;
- }
- out:
- return buf_pos;
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE)
+ free_page((unsigned long) sbuf[pos]);
}
/*
- * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
- * in the adapter struct cur_buf is the pointer array and count can be any
- * number of buffers in the array that should be freed starting from buffer 0
+ * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
+ * array in the adapter struct.
+ * Cur_buf is the pointer array
*
+ * returns: zero on success else -ENOMEM
* locks: must only be called with zfcp_data.config_sema taken
*/
-static void
-zfcp_qdio_buffers_dequeue(struct qdio_buffer **cur_buf, int count)
+static int
+zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf)
{
- int buf_pos;
- int qdio_buffers_per_page;
-
- qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
- ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
+ int pos;
- for (buf_pos = 0; buf_pos < count; buf_pos += qdio_buffers_per_page)
- free_page((unsigned long) cur_buf[buf_pos]);
- return;
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) {
+ sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL);
+ if (!sbuf[pos]) {
+ zfcp_qdio_buffers_dequeue(sbuf);
+ return -ENOMEM;
+ }
+ }
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++)
+ if (pos % QBUFF_PER_PAGE)
+ sbuf[pos] = sbuf[pos - 1] + 1;
+ return 0;
}
/* locks: must only be called with zfcp_data.config_sema taken */
int
zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter)
{
- int buffer_count;
- int retval = 0;
-
- buffer_count =
- zfcp_qdio_buffers_enqueue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
- ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for request "
- "queue\n", buffer_count);
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- buffer_count);
- retval = -ENOMEM;
- goto out;
- }
+ int ret;
- buffer_count =
- zfcp_qdio_buffers_enqueue(&(adapter->response_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
- ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for response "
- "queue", buffer_count);
- zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
- buffer_count);
- ZFCP_LOG_TRACE("freeing request_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- retval = -ENOMEM;
- goto out;
- }
- out:
- return retval;
+ ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer);
+ if (ret)
+ return ret;
+ return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer);
}
/* locks: must only be called with zfcp_data.config_sema taken */
@@ -151,12 +102,10 @@ void
zfcp_qdio_free_queues(struct zfcp_adapter *adapter)
{
ZFCP_LOG_TRACE("freeing request_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
+ zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer);
ZFCP_LOG_TRACE("freeing response_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
+ zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer);
}
int
@@ -681,28 +630,6 @@ out:
/**
- * zfcp_qdio_sbals_from_buffer - fill SBALs from buffer
- * @fsf_req: request to be processed
- * @sbtype: SBALE flags
- * @buffer: data buffer
- * @length: length of buffer
- * @max_sbals: upper bound for number of SBALs to be used
- */
-static int
-zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
- void *buffer, unsigned long length, int max_sbals)
-{
- struct scatterlist sg_segment;
-
- zfcp_address_to_sg(buffer, &sg_segment);
- sg_segment.length = length;
-
- return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1,
- max_sbals);
-}
-
-
-/**
* zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command
* @fsf_req: request to be processed
* @sbtype: SBALE flags
@@ -713,18 +640,9 @@ int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{
- if (scsi_cmnd->use_sg) {
- return zfcp_qdio_sbals_from_sg(fsf_req, sbtype,
- (struct scatterlist *)
- scsi_cmnd->request_buffer,
- scsi_cmnd->use_sg,
- ZFCP_MAX_SBALS_PER_REQ);
- } else {
- return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype,
- scsi_cmnd->request_buffer,
- scsi_cmnd->request_bufflen,
- ZFCP_MAX_SBALS_PER_REQ);
- }
+ return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, scsi_sglist(scsi_cmnd),
+ scsi_sg_count(scsi_cmnd),
+ ZFCP_MAX_SBALS_PER_REQ);
}
/**
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 0acf6db0a08d..ad7eb4a9261c 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -764,7 +764,9 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
return;
ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
- if (ret == 0) {
+ if (ret) {
+ kfree(data);
+ } else {
adapter->stats_reset = jiffies/HZ;
old_data = adapter->stats_reset_data;
adapter->stats_reset_data = data; /* finally freed in
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 35a73168333f..400c65bfb8c7 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -15,6 +15,7 @@ config SUN_OPENPROMIO
config SUN_MOSTEK_RTC
tristate "Mostek real time clock support"
+ depends on SPARC32
help
The Mostek RTC chip is used on all known Sun computers except
some JavaStations. For a JavaStation you need to say Y both here
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index a54e4140683a..0bde26989a23 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -7,6 +7,7 @@
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/kmod.h>
+#include <linux/reboot.h>
#include <asm/oplib.h>
#include <asm/ebus.h>
@@ -170,8 +171,6 @@ static void get_current_temps(struct bbc_cpu_temperature *tp)
static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
{
static int shutting_down = 0;
- static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
char *type = "???";
s8 val = -1;
@@ -195,7 +194,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
shutting_down = 1;
- if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+ if (orderly_poweroff(true) < 0)
printk(KERN_CRIT "envctrl: shutdown execution failed\n");
}
@@ -480,11 +479,12 @@ static int kenvctrld(void *__unused)
static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
{
- struct bbc_cpu_temperature *tp = kmalloc(sizeof(*tp), GFP_KERNEL);
+ struct bbc_cpu_temperature *tp;
+ tp = kzalloc(sizeof(*tp), GFP_KERNEL);
if (!tp)
return;
- memset(tp, 0, sizeof(*tp));
+
tp->client = bbc_i2c_attach(echild);
if (!tp->client) {
kfree(tp);
@@ -526,11 +526,12 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
{
- struct bbc_fan_control *fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+ struct bbc_fan_control *fp;
+ fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (!fp)
return;
- memset(fp, 0, sizeof(*fp));
+
fp->client = bbc_i2c_attach(echild);
if (!fp->client) {
kfree(fp);
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 178155bf9db6..ac8ef2ce07fb 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -156,10 +156,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
if (!bp)
return NULL;
- client = kmalloc(sizeof(*client), GFP_KERNEL);
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return NULL;
- memset(client, 0, sizeof(*client));
client->bp = bp;
client->echild = echild;
client->bus = echild->resource[0].start;
@@ -358,13 +357,13 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
{
- struct bbc_i2c_bus *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
+ struct bbc_i2c_bus *bp;
struct linux_ebus_child *echild;
int entry;
+ bp = kzalloc(sizeof(*bp), GFP_KERNEL);
if (!bp)
return -ENOMEM;
- memset(bp, 0, sizeof(*bp));
bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
if (!bp->i2c_control_regs)
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 8328acab47fd..dadabef116b6 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/kmod.h>
+#include <linux/reboot.h>
#include <asm/ebus.h>
#include <asm/uaccess.h>
@@ -966,10 +967,6 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type)
static void envctrl_do_shutdown(void)
{
static int inprog = 0;
- static char *envp[] = {
- "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = {
- "/sbin/shutdown", "-h", "now", NULL };
int ret;
if (inprog != 0)
@@ -977,7 +974,7 @@ static void envctrl_do_shutdown(void)
inprog = 1;
printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
- ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+ ret = orderly_poweroff(true);
if (ret < 0) {
printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n");
inprog = 0; /* unlikely to succeed, but we could try again */
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 5157a2abc58d..4b7079fdc10c 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -185,7 +185,7 @@ static void jsfd_read(char *buf, unsigned long p, size_t togo) {
}
}
-static void jsfd_do_request(request_queue_t *q)
+static void jsfd_do_request(struct request_queue *q)
{
struct request *req;
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 6afc7e5df0d4..9269f7fbd363 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -248,6 +248,7 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp)
buffer,inout.len);
if (copy_to_user(argp,&inout,sizeof(inout))) {
+ vfc_unlock_device(dev);
kfree(buffer);
return -EFAULT;
}
@@ -656,12 +657,9 @@ static int vfc_probe(void)
if (!cards)
return -ENODEV;
- vfc_dev_lst = kmalloc(sizeof(struct vfc_dev *) *
- (cards+1),
- GFP_KERNEL);
+ vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
if (vfc_dev_lst == NULL)
return -ENOMEM;
- memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1));
vfc_dev_lst[cards] = NULL;
ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 002643392d42..c37d7c2587ff 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -33,6 +33,7 @@ struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
+ struct dev_archdata *sd;
unsigned long base;
const void *pval;
int len, err;
@@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
sbus_fill_device_irq(sdev);
+ sd = &sdev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &sdev->ofdev;
+
sdev->ofdev.node = dp;
if (sdev->parent)
sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
@@ -205,6 +210,10 @@ static void __init walk_children(struct device_node *dp, struct sbus_dev *parent
sdev->bus = sbus;
sdev->parent = parent;
+ sdev->ofdev.dev.archdata.iommu =
+ sbus->ofdev.dev.archdata.iommu;
+ sdev->ofdev.dev.archdata.stc =
+ sbus->ofdev.dev.archdata.stc;
fill_sbus_device(dp, sdev);
@@ -264,6 +273,11 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus)
sdev->bus = sbus;
sdev->parent = NULL;
+ sdev->ofdev.dev.archdata.iommu =
+ sbus->ofdev.dev.archdata.iommu;
+ sdev->ofdev.dev.archdata.stc =
+ sbus->ofdev.dev.archdata.stc;
+
fill_sbus_device(dev_dp, sdev);
walk_children(dev_dp, sdev, sbus);
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 76c09097175f..efd9d8d3a890 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -4,7 +4,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
Modifications By: Tom Couch <linuxraid@amcc.com>
- Copyright (C) 2004-2006 Applied Micro Circuits Corporation.
+ Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -69,6 +69,8 @@
2.26.02.008 - Free irq handler in __twa_shutdown().
Serialize reset code.
Add support for 9650SE controllers.
+ 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
+ 2.26.02.010 - Add support for 9690SA controllers.
*/
#include <linux/module.h>
@@ -92,7 +94,7 @@
#include "3w-9xxx.h"
/* Globals */
-#define TW_DRIVER_VERSION "2.26.02.008"
+#define TW_DRIVER_VERSION "2.26.02.010"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
@@ -124,11 +126,11 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
unsigned short *fw_on_ctlr_branch,
unsigned short *fw_on_ctlr_build,
u32 *init_connect_result);
-static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
@@ -683,7 +685,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
full_command_packet = &tw_ioctl->firmware_command;
/* Load request id and sglist for both command types */
- twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+ twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
@@ -700,10 +702,10 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
/* Now we need to reset the board */
printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
- tw_dev->host->host_no, TW_DRIVER, 0xc,
+ tw_dev->host->host_no, TW_DRIVER, 0x37,
cmd);
retval = TW_IOCTL_ERROR_OS_EIO;
- twa_reset_device_extension(tw_dev, 1);
+ twa_reset_device_extension(tw_dev);
goto out3;
}
@@ -890,7 +892,9 @@ static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
}
if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
- if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags)))
+ if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
+ (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
+ (!test_bit(TW_IN_RESET, &tw_dev->flags)))
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
}
@@ -935,8 +939,7 @@ static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
unsigned long before;
int retval = 1;
- if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) ||
- (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) {
+ if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
before = jiffies;
while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
@@ -1160,13 +1163,12 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
}
/* Allocate event info space */
- tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+ tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
if (!tw_dev->event_queue[0]) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
goto out;
}
- memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
for (i = 0; i < TW_Q_LENGTH; i++) {
tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
@@ -1196,7 +1198,6 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
u32 status_reg_value;
TW_Response_Queue response_que;
TW_Command_Full *full_command_packet;
- TW_Command *command_packet;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
int handled = 0;
@@ -1274,7 +1275,6 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
request_id = TW_RESID_OUT(response_que.response_id);
full_command_packet = tw_dev->command_packet_virt[request_id];
error = 0;
- command_packet = &full_command_packet->command.oldcommand;
/* Check for command packet errors */
if (full_command_packet->command.newcommand.status != 0) {
if (tw_dev->srb[request_id] != 0) {
@@ -1353,11 +1353,15 @@ twa_interrupt_bail:
} /* End twa_interrupt() */
/* This function will load the request id and various sgls for ioctls */
-static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
{
TW_Command *oldcommand;
TW_Command_Apache *newcommand;
TW_SG_Entry *sgl;
+ unsigned int pae = 0;
+
+ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+ pae = 1;
if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
newcommand = &full_command_packet->command.newcommand;
@@ -1373,12 +1377,14 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d
if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
/* Load the sg list */
- sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
+ if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
+ sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
+ else
+ sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
sgl->length = cpu_to_le32(length);
- if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
- oldcommand->size += 1;
+ oldcommand->size += pae;
}
}
} /* End twa_load_sgl() */
@@ -1507,7 +1513,8 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
command_que_value = tw_dev->command_packet_phys[request_id];
/* For 9650SE write low 4 bytes first */
- if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+ if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+ (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
command_que_value += TW_COMMAND_OFFSET;
writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
}
@@ -1538,7 +1545,8 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
goto out;
} else {
- if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+ if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+ (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
/* Now write upper 4 bytes */
writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
} else {
@@ -1562,7 +1570,7 @@ out:
} /* End twa_post_command_packet() */
/* This function will reset a device extension */
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
{
int i = 0;
int retval = 1;
@@ -1720,7 +1728,7 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
mutex_lock(&tw_dev->ioctl_lock);
/* Now reset the card and some of the device extension data */
- if (twa_reset_device_extension(tw_dev, 0)) {
+ if (twa_reset_device_extension(tw_dev)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
goto out;
}
@@ -2002,11 +2010,14 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
pci_set_master(pdev);
- retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK);
- if (retval) {
- TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
- goto out_disable_device;
- }
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+ || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+ || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
if (!host) {
@@ -2054,7 +2065,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
goto out_iounmap;
/* Set host specific parameters */
- if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE)
+ if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+ (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
host->max_id = TW_MAX_UNITS_9650SE;
else
host->max_id = TW_MAX_UNITS;
@@ -2161,6 +2173,8 @@ static struct pci_device_id twa_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 7901517d4513..d14a9479e389 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -4,7 +4,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
Modifications By: Tom Couch <linuxraid@amcc.com>
- Copyright (C) 2004-2006 Applied Micro Circuits Corporation.
+ Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -419,6 +419,9 @@ static twa_message_type twa_error_table[] = {
#ifndef PCI_DEVICE_ID_3WARE_9650SE
#define PCI_DEVICE_ID_3WARE_9650SE 0x1004
#endif
+#ifndef PCI_DEVICE_ID_3WARE_9690SA
+#define PCI_DEVICE_ID_3WARE_9690SA 0x1005
+#endif
/* Bitmask macros to eliminate bitfields */
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 372723161c97..6f2c71ef47ee 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -282,7 +282,7 @@ config SCSI_ISCSI_ATTRS
config SCSI_SAS_ATTRS
tristate "SAS Transport Attributes"
- depends on SCSI
+ depends on SCSI && BLK_DEV_BSG
help
If you wish to export transport-specific information about
each attached SAS device to sysfs, say Y.
@@ -291,8 +291,12 @@ source "drivers/scsi/libsas/Kconfig"
endmenu
-menu "SCSI low-level drivers"
+menuconfig SCSI_LOWLEVEL
+ bool "SCSI low-level drivers"
depends on SCSI!=n
+ default y
+
+if SCSI_LOWLEVEL
config ISCSI_TCP
tristate "iSCSI Initiator over TCP/IP"
@@ -363,6 +367,7 @@ config SCSI_3W_9XXX
config SCSI_7000FASST
tristate "7000FASST SCSI support"
depends on ISA && SCSI && ISA_DMA_API
+ select CHECK_SIGNATURE
help
This driver supports the Western Digital 7000 SCSI host adapter
family. Some information is in the source:
@@ -384,6 +389,7 @@ config SCSI_AHA152X
tristate "Adaptec AHA152X/2825 support"
depends on ISA && SCSI && !64BIT
select SCSI_SPI_ATTRS
+ select CHECK_SIGNATURE
---help---
This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825
SCSI host adapters. It also works for the AVA-1505, but the IRQ etc.
@@ -483,7 +489,7 @@ 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
+ depends on !64BIT && 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
@@ -579,6 +585,7 @@ config SCSI_DTC3280
tristate "DTC3180/3280 SCSI support"
depends on ISA && SCSI
select SCSI_SPI_ATTRS
+ select CHECK_SIGNATURE
help
This is support for DTC 3180/3280 SCSI Host Adapters. Please read
the SCSI-HOWTO, available from
@@ -653,6 +660,7 @@ config SCSI_EATA_PIO
config SCSI_FUTURE_DOMAIN
tristate "Future Domain 16xx SCSI/AHA-2920A support"
depends on (ISA || PCI) && SCSI
+ select CHECK_SIGNATURE
---help---
This is support for Future Domain's 16-bit SCSI host adapters
(TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
@@ -1320,6 +1328,7 @@ config SCSI_LPFC
config SCSI_SEAGATE
tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
depends on X86 && ISA && SCSI
+ select CHECK_SIGNATURE
---help---
These are 8-bit SCSI controllers; the ST-01 is also supported by
this driver. It is explained in section 3.9 of the SCSI-HOWTO,
@@ -1393,6 +1402,7 @@ config SCSI_T128
tristate "Trantor T128/T128F/T228 SCSI support"
depends on ISA && SCSI
select SCSI_SPI_ATTRS
+ select CHECK_SIGNATURE
---help---
This is support for a SCSI host adapter. It is explained in section
3.11 of the SCSI-HOWTO, available from
@@ -1557,7 +1567,7 @@ config A3000_SCSI
built-in SCSI controller, say Y. Otherwise, say N.
To compile this driver as a module, choose M here: the
- module will be called wd33c93.
+ module will be called a3000.
config A2091_SCSI
tristate "A2091/A590 WD33C93A support"
@@ -1567,7 +1577,7 @@ config A2091_SCSI
say N.
To compile this driver as a module, choose M here: the
- module will be called wd33c93.
+ module will be called a2091.
config GVP11_SCSI
tristate "GVP Series II WD33C93A support"
@@ -1800,7 +1810,7 @@ config SCSI_SRP
To compile this driver as a module, choose M here: the
module will be called libsrp.
-endmenu
+endif # SCSI_LOWLEVEL
source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 0f8689557158..86a7ba7bad63 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -132,6 +132,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
+obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 8b5334c56f0a..79b4df158140 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -95,6 +95,8 @@ enum {
/* The master ring of all esp hosts we are managing in this driver. */
static struct NCR_ESP *espchain;
int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
irqreturn_t esp_intr(int irq, void *dev_id);
@@ -524,6 +526,7 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Eat any bitrot in the chip and we are done... */
trash = esp_read(eregs->esp_intrpt);
}
+EXPORT_SYMBOL(esp_bootup_reset);
/* Allocate structure and insert basic data such as SCSI chip frequency
* data and a pointer to the device
@@ -772,6 +775,7 @@ const char *esp_info(struct Scsi_Host *host)
panic("Bogon ESP revision");
};
}
+EXPORT_SYMBOL(esp_info);
/* From Wolfgang Stanglmeier's NCR scsi driver. */
struct info_str
@@ -902,6 +906,7 @@ int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t off
*start = buffer;
return esp_host_info(esp, buffer, offset, length);
}
+EXPORT_SYMBOL(esp_proc_info);
static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
@@ -3535,6 +3540,7 @@ state_machine:
if(esp->dma_irq_exit)
esp->dma_irq_exit(esp);
}
+EXPORT_SYMBOL(esp_handle);
#ifndef CONFIG_SMP
irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3606,11 +3612,10 @@ out:
int esp_slave_alloc(struct scsi_device *SDptr)
{
struct esp_device *esp_dev =
- kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+ kzalloc(sizeof(struct esp_device), GFP_ATOMIC);
if (!esp_dev)
return -ENOMEM;
- memset(esp_dev, 0, sizeof(struct esp_device));
SDptr->hostdata = esp_dev;
return 0;
}
@@ -3632,6 +3637,7 @@ void esp_release(void)
esps_in_use--;
esps_running = esps_in_use;
}
+EXPORT_SYMBOL(esp_release);
#endif
EXPORT_SYMBOL(esp_abort);
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index f12864abed2f..3a8089705feb 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -181,13 +181,12 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
struct Scsi_Host *host;
int ret;
- hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+ hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host"
"data, detatching\n", siop);
return -ENOMEM;
}
- memset(hostdata, 0, sizeof(*hostdata));
if (!request_region(region, 64, "NCR_D700")) {
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index 778844c3544a..a8bbdc2273b8 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -148,11 +148,10 @@ NCR_Q720_probe(struct device *dev)
__u32 base_addr, mem_size;
void __iomem *mem_base;
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memset(p, 0, sizeof(*p));
pos2 = mca_device_read_pos(mca_dev, 2);
/* enable device */
pos2 |= NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE;
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
index 6a5784683ed3..0c758d1452ba 100644
--- a/drivers/scsi/a4000t.c
+++ b/drivers/scsi/a4000t.c
@@ -79,6 +79,7 @@ static int __devinit a4000t_probe(struct device *dev)
goto out_put_host;
}
+ dev_set_drvdata(dev, host);
scsi_scan_host(host);
return 0;
@@ -95,7 +96,7 @@ static int __devinit a4000t_probe(struct device *dev)
static __devexit int a4000t_device_remove(struct device *dev)
{
- struct Scsi_Host *host = dev_to_shost(dev);
+ struct Scsi_Host *host = dev_get_drvdata(dev);
struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
scsi_remove_host(host);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 0b6fd0b654d2..6800e578e4b1 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -194,8 +194,7 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
struct scsi_device *device;
if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
- dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"))
-;
+ dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
aac_fib_complete(fibptr);
aac_fib_free(fibptr);
return 0;
@@ -751,6 +750,101 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
inqstrcpy ("V1.0", str->prl);
}
+static void get_container_serial_callback(void *context, struct fib * fibptr)
+{
+ struct aac_get_serial_resp * get_serial_reply;
+ struct scsi_cmnd * scsicmd;
+
+ BUG_ON(fibptr == NULL);
+
+ scsicmd = (struct scsi_cmnd *) context;
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
+ get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
+ /* Failure is irrelevant, using default value instead */
+ if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
+ char sp[13];
+ /* EVPD bit set */
+ sp[0] = INQD_PDT_DA;
+ sp[1] = scsicmd->cmnd[2];
+ sp[2] = 0;
+ sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
+ le32_to_cpu(get_serial_reply->uid));
+ aac_internal_transfer(scsicmd, sp, 0, sizeof(sp));
+ }
+
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ scsicmd->scsi_done(scsicmd);
+}
+
+/**
+ * aac_get_container_serial - get container serial, none blocking.
+ */
+static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
+{
+ int status;
+ struct aac_get_serial *dinfo;
+ struct fib * cmd_fibcontext;
+ struct aac_dev * dev;
+
+ dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+
+ if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+ return -ENOMEM;
+
+ aac_fib_init(cmd_fibcontext);
+ dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
+
+ dinfo->command = cpu_to_le32(VM_ContainerConfig);
+ dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
+ dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
+
+ status = aac_fib_send(ContainerCommand,
+ cmd_fibcontext,
+ sizeof (struct aac_get_serial),
+ FsaNormal,
+ 0, 1,
+ (fib_callback) get_container_serial_callback,
+ (void *) scsicmd);
+
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+
+ printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
+ aac_fib_complete(cmd_fibcontext);
+ aac_fib_free(cmd_fibcontext);
+ return -1;
+}
+
+/* Function: setinqserial
+ *
+ * Arguments: [1] pointer to void [1] int
+ *
+ * Purpose: Sets SCSI Unit Serial number.
+ * This is a fake. We should read a proper
+ * serial number from the container. <SuSE>But
+ * without docs it's quite hard to do it :-)
+ * So this will have to do in the meantime.</SuSE>
+ */
+
+static int setinqserial(struct aac_dev *dev, void *data, int cid)
+{
+ /*
+ * This breaks array migration.
+ */
+ return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
+ le32_to_cpu(dev->adapter_info.serial[0]), cid);
+}
+
static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
u8 a_sense_code, u8 incorrect_length,
u8 bit_pointer, u16 field_pointer,
@@ -1594,23 +1688,23 @@ static void synchronize_callback(void *context, struct fib *fibptr)
if (!aac_valid_context(cmd, fibptr))
return;
- dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
+ dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
smp_processor_id(), jiffies));
BUG_ON(fibptr == NULL);
synchronizereply = fib_data(fibptr);
if (le32_to_cpu(synchronizereply->status) == CT_OK)
- cmd->result = DID_OK << 16 |
+ cmd->result = DID_OK << 16 |
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
else {
struct scsi_device *sdev = cmd->device;
struct aac_dev *dev = fibptr->dev;
u32 cid = sdev_id(sdev);
- printk(KERN_WARNING
+ printk(KERN_WARNING
"synchronize_callback: synchronize failed, status = %d\n",
le32_to_cpu(synchronizereply->status));
- cmd->result = DID_OK << 16 |
+ cmd->result = DID_OK << 16 |
COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
HARDWARE_ERROR,
@@ -1618,7 +1712,7 @@ static void synchronize_callback(void *context, struct fib *fibptr)
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
0, 0);
memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
- min(sizeof(dev->fsa_dev[cid].sense_data),
+ min(sizeof(dev->fsa_dev[cid].sense_data),
sizeof(cmd->sense_buffer)));
}
@@ -1636,6 +1730,9 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
struct scsi_device *sdev = scsicmd->device;
int active = 0;
struct aac_dev *aac;
+ u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) |
+ (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+ u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
unsigned long flags;
/*
@@ -1644,7 +1741,51 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
*/
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(cmd, &sdev->cmd_list, list)
- if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+ if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+ u64 cmnd_lba;
+ u32 cmnd_count;
+
+ if (cmd->cmnd[0] == WRITE_6) {
+ cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) |
+ (cmd->cmnd[2] << 8) |
+ cmd->cmnd[3];
+ cmnd_count = cmd->cmnd[4];
+ if (cmnd_count == 0)
+ cmnd_count = 256;
+ } else if (cmd->cmnd[0] == WRITE_16) {
+ cmnd_lba = ((u64)cmd->cmnd[2] << 56) |
+ ((u64)cmd->cmnd[3] << 48) |
+ ((u64)cmd->cmnd[4] << 40) |
+ ((u64)cmd->cmnd[5] << 32) |
+ ((u64)cmd->cmnd[6] << 24) |
+ (cmd->cmnd[7] << 16) |
+ (cmd->cmnd[8] << 8) |
+ cmd->cmnd[9];
+ cmnd_count = (cmd->cmnd[10] << 24) |
+ (cmd->cmnd[11] << 16) |
+ (cmd->cmnd[12] << 8) |
+ cmd->cmnd[13];
+ } else if (cmd->cmnd[0] == WRITE_12) {
+ cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
+ (cmd->cmnd[3] << 16) |
+ (cmd->cmnd[4] << 8) |
+ cmd->cmnd[5];
+ cmnd_count = (cmd->cmnd[6] << 24) |
+ (cmd->cmnd[7] << 16) |
+ (cmd->cmnd[8] << 8) |
+ cmd->cmnd[9];
+ } else if (cmd->cmnd[0] == WRITE_10) {
+ cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
+ (cmd->cmnd[3] << 16) |
+ (cmd->cmnd[4] << 8) |
+ cmd->cmnd[5];
+ cmnd_count = (cmd->cmnd[7] << 8) |
+ cmd->cmnd[8];
+ } else
+ continue;
+ if (((cmnd_lba + cmnd_count) < lba) ||
+ (count && ((lba + count) < cmnd_lba)))
+ continue;
++active;
break;
}
@@ -1673,7 +1814,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
- synchronizecmd->count =
+ synchronizecmd->count =
cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
/*
@@ -1695,7 +1836,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
return 0;
}
- printk(KERN_WARNING
+ printk(KERN_WARNING
"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
aac_fib_complete(cmd_fibcontext);
aac_fib_free(cmd_fibcontext);
@@ -1798,6 +1939,49 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
memset(&inq_data, 0, sizeof (struct inquiry_data));
+ if (scsicmd->cmnd[1] & 0x1 ) {
+ char *arr = (char *)&inq_data;
+
+ /* EVPD bit set */
+ arr[0] = (scmd_id(scsicmd) == host->this_id) ?
+ INQD_PDT_PROC : INQD_PDT_DA;
+ if (scsicmd->cmnd[2] == 0) {
+ /* supported vital product data pages */
+ arr[3] = 2;
+ arr[4] = 0x0;
+ arr[5] = 0x80;
+ arr[1] = scsicmd->cmnd[2];
+ aac_internal_transfer(scsicmd, &inq_data, 0,
+ sizeof(inq_data));
+ scsicmd->result = DID_OK << 16 |
+ COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+ } else if (scsicmd->cmnd[2] == 0x80) {
+ /* unit serial number page */
+ arr[3] = setinqserial(dev, &arr[4],
+ scmd_id(scsicmd));
+ arr[1] = scsicmd->cmnd[2];
+ aac_internal_transfer(scsicmd, &inq_data, 0,
+ sizeof(inq_data));
+ return aac_get_container_serial(scsicmd);
+ } else {
+ /* vpd page not implemented */
+ scsicmd->result = DID_OK << 16 |
+ COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST,
+ SENCODE_INVALID_CDB_FIELD,
+ ASENCODE_NO_SENSE, 0, 7, 2, 0);
+ memcpy(scsicmd->sense_buffer,
+ &dev->fsa_dev[cid].sense_data,
+ (sizeof(dev->fsa_dev[cid].sense_data) >
+ sizeof(scsicmd->sense_buffer))
+ ? sizeof(scsicmd->sense_buffer)
+ : sizeof(dev->fsa_dev[cid].sense_data));
+ }
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
inq_data.inqd_len = 31;
@@ -2070,7 +2254,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
}
else return -EINVAL;
- qd.valid = fsa_dev_ptr[qd.cnum].valid;
+ qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
qd.locked = fsa_dev_ptr[qd.cnum].locked;
qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index f1d3b66af879..94727b9375ec 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 2447
+# define AAC_DRIVER_BUILD 2449
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -1567,6 +1567,20 @@ struct aac_get_name_resp {
u8 data[16];
};
+#define CT_CID_TO_32BITS_UID 165
+struct aac_get_serial {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_CID_TO_32BITS_UID */
+ __le32 cid;
+};
+
+struct aac_get_serial_resp {
+ __le32 dummy0;
+ __le32 dummy1;
+ __le32 status; /* CT_OK */
+ __le32 uid;
+};
+
/*
* The following command is sent to shut down each container.
*/
@@ -1793,10 +1807,10 @@ struct aac_aifcmd {
* accounting for the fact capacity could be a 64 bit value
*
*/
-static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
+static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
{
sector_div(capacity, divisor);
- return (u32)capacity;
+ return capacity;
}
/* SCp.phase values */
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index d510839c0bb2..bb870906b4cf 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -80,7 +80,11 @@ static int fib_map_alloc(struct aac_dev *dev)
void aac_fib_map_free(struct aac_dev *dev)
{
- pci_free_consistent(dev->pdev, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), dev->hw_fib_va, dev->hw_fib_pa);
+ pci_free_consistent(dev->pdev,
+ dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
+ dev->hw_fib_va, dev->hw_fib_pa);
+ dev->hw_fib_va = NULL;
+ dev->hw_fib_pa = 0;
}
/**
@@ -1087,8 +1091,6 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
* case.
*/
aac_fib_map_free(aac);
- aac->hw_fib_va = NULL;
- aac->hw_fib_pa = 0;
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
aac->comm_addr = NULL;
aac->comm_phys = 0;
@@ -1098,12 +1100,12 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
- if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
goto out;
} else {
- if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
goto out;
}
if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index d76e1a8cb93a..a7f42a17b5c7 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -636,6 +636,8 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
static int aac_cfg_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
return aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
}
@@ -689,6 +691,8 @@ static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg);
}
#endif
@@ -822,7 +826,7 @@ static ssize_t aac_show_reset_adapter(struct class_device *class_dev,
tmp = aac_adapter_check_health(dev);
if ((tmp == 0) && dev->in_reset)
tmp = -EBUSY;
- len = snprintf(buf, PAGE_SIZE, "0x%x", tmp);
+ len = snprintf(buf, PAGE_SIZE, "0x%x\n", tmp);
return len;
}
@@ -1106,7 +1110,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
__aac_shutdown(aac);
out_unmap:
aac_fib_map_free(aac);
- pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+ if (aac->comm_addr)
+ pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr,
+ aac->comm_phys);
kfree(aac->queues);
aac_adapter_ioremap(aac, 0);
kfree(aac->fibs);
@@ -1122,9 +1128,8 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
static void aac_shutdown(struct pci_dev *dev)
{
struct Scsi_Host *shost = pci_get_drvdata(dev);
- struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
scsi_block_requests(shost);
- __aac_shutdown(aac);
+ __aac_shutdown((struct aac_dev *)shost->hostdata);
}
static void __devexit aac_remove_one(struct pci_dev *pdev)
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
index a8ace5677813..c55f7c862f0e 100644
--- a/drivers/scsi/aacraid/nark.c
+++ b/drivers/scsi/aacraid/nark.c
@@ -1,11 +1,10 @@
/*
* Adaptec AAC series RAID controller driver
- * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
*
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2006-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index 9c5fcfb398c2..8cd6588a83e3 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index ebc65b9fea92..73eef3dc5dc6 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -472,7 +472,7 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
else {
bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
- if (!bled && (var != 0x00000001))
+ if (!bled && (var != 0x00000001) && (var != 0x3803000F))
bled = -EINVAL;
}
if (bled && (bled != -ETIMEDOUT))
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2b6689709e53..79c0b6e37a3b 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3K" /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3K" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -802,7 +802,6 @@
#include <linux/pci.h>
#endif /* CONFIG_PCI */
-
/*
* --- Driver Options
*/
@@ -816,18 +815,6 @@
/* Enable driver tracing. */
/* #define ADVANSYS_DEBUG */
-
-/*
- * --- Debugging Header
- */
-
-#ifdef ADVANSYS_DEBUG
-#define STATIC
-#else /* ADVANSYS_DEBUG */
-#define STATIC static
-#endif /* ADVANSYS_DEBUG */
-
-
/*
* --- Asc Library Constants and Macros
*/
@@ -845,10 +832,10 @@
* are all consistent at 8, 16, and 32 bits respectively. Pointers
* and long types are 64 bits on Alpha and UltraSPARC.
*/
-#define ASC_PADDR __u32 /* Physical/Bus address data type. */
-#define ASC_VADDR __u32 /* Virtual address data type. */
-#define ASC_DCNT __u32 /* Unsigned Data count type. */
-#define ASC_SDCNT __s32 /* Signed Data count type. */
+#define ASC_PADDR __u32 /* Physical/Bus address data type. */
+#define ASC_VADDR __u32 /* Virtual address data type. */
+#define ASC_DCNT __u32 /* Unsigned Data count type. */
+#define ASC_SDCNT __s32 /* Signed Data count type. */
/*
* These macros are used to convert a virtual address to a
@@ -911,7 +898,7 @@ typedef unsigned char uchar;
#define CC_VERY_LONG_SG_LIST 0
#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
-#define PortAddr unsigned short /* port address size */
+#define PortAddr unsigned short /* port address size */
#define inp(port) inb(port)
#define outp(port, byte) outb((byte), (port))
@@ -1038,17 +1025,17 @@ typedef unsigned char uchar;
#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
typedef struct {
- uchar periph;
- uchar devtype;
- uchar ver;
- uchar byte3;
- uchar add_len;
- uchar res1;
- uchar res2;
- uchar flags;
- uchar vendor_id[8];
- uchar product_id[16];
- uchar product_rev_level[4];
+ uchar periph;
+ uchar devtype;
+ uchar ver;
+ uchar byte3;
+ uchar add_len;
+ uchar res1;
+ uchar res2;
+ uchar flags;
+ uchar vendor_id[8];
+ uchar product_id[16];
+ uchar product_rev_level[4];
} ASC_SCSI_INQUIRY;
#define ASC_SG_LIST_PER_Q 7
@@ -1165,139 +1152,139 @@ typedef struct {
#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
typedef struct asc_scsiq_1 {
- uchar status;
- uchar q_no;
- uchar cntl;
- uchar sg_queue_cnt;
- uchar target_id;
- uchar target_lun;
- ASC_PADDR data_addr;
- ASC_DCNT data_cnt;
- ASC_PADDR sense_addr;
- uchar sense_len;
- uchar extra_bytes;
+ uchar status;
+ uchar q_no;
+ uchar cntl;
+ uchar sg_queue_cnt;
+ uchar target_id;
+ uchar target_lun;
+ ASC_PADDR data_addr;
+ ASC_DCNT data_cnt;
+ ASC_PADDR sense_addr;
+ uchar sense_len;
+ uchar extra_bytes;
} ASC_SCSIQ_1;
typedef struct asc_scsiq_2 {
- ASC_VADDR srb_ptr;
- uchar target_ix;
- uchar flag;
- uchar cdb_len;
- uchar tag_code;
- ushort vm_id;
+ ASC_VADDR srb_ptr;
+ uchar target_ix;
+ uchar flag;
+ uchar cdb_len;
+ uchar tag_code;
+ ushort vm_id;
} ASC_SCSIQ_2;
typedef struct asc_scsiq_3 {
- uchar done_stat;
- uchar host_stat;
- uchar scsi_stat;
- uchar scsi_msg;
+ uchar done_stat;
+ uchar host_stat;
+ uchar scsi_stat;
+ uchar scsi_msg;
} ASC_SCSIQ_3;
typedef struct asc_scsiq_4 {
- uchar cdb[ASC_MAX_CDB_LEN];
- uchar y_first_sg_list_qp;
- uchar y_working_sg_qp;
- uchar y_working_sg_ix;
- uchar y_res;
- ushort x_req_count;
- ushort x_reconnect_rtn;
- ASC_PADDR x_saved_data_addr;
- ASC_DCNT x_saved_data_cnt;
+ uchar cdb[ASC_MAX_CDB_LEN];
+ uchar y_first_sg_list_qp;
+ uchar y_working_sg_qp;
+ uchar y_working_sg_ix;
+ uchar y_res;
+ ushort x_req_count;
+ ushort x_reconnect_rtn;
+ ASC_PADDR x_saved_data_addr;
+ ASC_DCNT x_saved_data_cnt;
} ASC_SCSIQ_4;
typedef struct asc_q_done_info {
- ASC_SCSIQ_2 d2;
- ASC_SCSIQ_3 d3;
- uchar q_status;
- uchar q_no;
- uchar cntl;
- uchar sense_len;
- uchar extra_bytes;
- uchar res;
- ASC_DCNT remain_bytes;
+ ASC_SCSIQ_2 d2;
+ ASC_SCSIQ_3 d3;
+ uchar q_status;
+ uchar q_no;
+ uchar cntl;
+ uchar sense_len;
+ uchar extra_bytes;
+ uchar res;
+ ASC_DCNT remain_bytes;
} ASC_QDONE_INFO;
typedef struct asc_sg_list {
- ASC_PADDR addr;
- ASC_DCNT bytes;
+ ASC_PADDR addr;
+ ASC_DCNT bytes;
} ASC_SG_LIST;
typedef struct asc_sg_head {
- ushort entry_cnt;
- ushort queue_cnt;
- ushort entry_to_copy;
- ushort res;
- ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
+ ushort entry_cnt;
+ ushort queue_cnt;
+ ushort entry_to_copy;
+ ushort res;
+ ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
} ASC_SG_HEAD;
#define ASC_MIN_SG_LIST 2
typedef struct asc_min_sg_head {
- ushort entry_cnt;
- ushort queue_cnt;
- ushort entry_to_copy;
- ushort res;
- ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
+ ushort entry_cnt;
+ ushort queue_cnt;
+ ushort entry_to_copy;
+ ushort res;
+ ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
} ASC_MIN_SG_HEAD;
#define QCX_SORT (0x0001)
#define QCX_COALEASE (0x0002)
typedef struct asc_scsi_q {
- ASC_SCSIQ_1 q1;
- ASC_SCSIQ_2 q2;
- uchar *cdbptr;
- ASC_SG_HEAD *sg_head;
- ushort remain_sg_entry_cnt;
- ushort next_sg_index;
+ ASC_SCSIQ_1 q1;
+ ASC_SCSIQ_2 q2;
+ uchar *cdbptr;
+ ASC_SG_HEAD *sg_head;
+ ushort remain_sg_entry_cnt;
+ ushort next_sg_index;
} ASC_SCSI_Q;
typedef struct asc_scsi_req_q {
- ASC_SCSIQ_1 r1;
- ASC_SCSIQ_2 r2;
- uchar *cdbptr;
- ASC_SG_HEAD *sg_head;
- uchar *sense_ptr;
- ASC_SCSIQ_3 r3;
- uchar cdb[ASC_MAX_CDB_LEN];
- uchar sense[ASC_MIN_SENSE_LEN];
+ ASC_SCSIQ_1 r1;
+ ASC_SCSIQ_2 r2;
+ uchar *cdbptr;
+ ASC_SG_HEAD *sg_head;
+ uchar *sense_ptr;
+ ASC_SCSIQ_3 r3;
+ uchar cdb[ASC_MAX_CDB_LEN];
+ uchar sense[ASC_MIN_SENSE_LEN];
} ASC_SCSI_REQ_Q;
typedef struct asc_scsi_bios_req_q {
- ASC_SCSIQ_1 r1;
- ASC_SCSIQ_2 r2;
- uchar *cdbptr;
- ASC_SG_HEAD *sg_head;
- uchar *sense_ptr;
- ASC_SCSIQ_3 r3;
- uchar cdb[ASC_MAX_CDB_LEN];
- uchar sense[ASC_MIN_SENSE_LEN];
+ ASC_SCSIQ_1 r1;
+ ASC_SCSIQ_2 r2;
+ uchar *cdbptr;
+ ASC_SG_HEAD *sg_head;
+ uchar *sense_ptr;
+ ASC_SCSIQ_3 r3;
+ uchar cdb[ASC_MAX_CDB_LEN];
+ uchar sense[ASC_MIN_SENSE_LEN];
} ASC_SCSI_BIOS_REQ_Q;
typedef struct asc_risc_q {
- uchar fwd;
- uchar bwd;
- ASC_SCSIQ_1 i1;
- ASC_SCSIQ_2 i2;
- ASC_SCSIQ_3 i3;
- ASC_SCSIQ_4 i4;
+ uchar fwd;
+ uchar bwd;
+ ASC_SCSIQ_1 i1;
+ ASC_SCSIQ_2 i2;
+ ASC_SCSIQ_3 i3;
+ ASC_SCSIQ_4 i4;
} ASC_RISC_Q;
typedef struct asc_sg_list_q {
- uchar seq_no;
- uchar q_no;
- uchar cntl;
- uchar sg_head_qp;
- uchar sg_list_cnt;
- uchar sg_cur_list_cnt;
+ uchar seq_no;
+ uchar q_no;
+ uchar cntl;
+ uchar sg_head_qp;
+ uchar sg_list_cnt;
+ uchar sg_cur_list_cnt;
} ASC_SG_LIST_Q;
typedef struct asc_risc_sg_list_q {
- uchar fwd;
- uchar bwd;
- ASC_SG_LIST_Q sg;
- ASC_SG_LIST sg_list[7];
+ uchar fwd;
+ uchar bwd;
+ ASC_SG_LIST_Q sg;
+ ASC_SG_LIST sg_list[7];
} ASC_RISC_SG_LIST_Q;
#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
@@ -1431,25 +1418,25 @@ typedef struct asc_risc_sg_list_q {
#define SYN_ULTRA_XFER_NS_15 107
typedef struct ext_msg {
- uchar msg_type;
- uchar msg_len;
- uchar msg_req;
- union {
- struct {
- uchar sdtr_xfer_period;
- uchar sdtr_req_ack_offset;
- } sdtr;
- struct {
- uchar wdtr_width;
- } wdtr;
- struct {
- uchar mdp_b3;
- uchar mdp_b2;
- uchar mdp_b1;
- uchar mdp_b0;
- } mdp;
- } u_ext_msg;
- uchar res;
+ uchar msg_type;
+ uchar msg_len;
+ uchar msg_req;
+ union {
+ struct {
+ uchar sdtr_xfer_period;
+ uchar sdtr_req_ack_offset;
+ } sdtr;
+ struct {
+ uchar wdtr_width;
+ } wdtr;
+ struct {
+ uchar mdp_b3;
+ uchar mdp_b2;
+ uchar mdp_b1;
+ uchar mdp_b0;
+ } mdp;
+ } u_ext_msg;
+ uchar res;
} EXT_MSG;
#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
@@ -1461,24 +1448,24 @@ typedef struct ext_msg {
#define mdp_b0 u_ext_msg.mdp_b0
typedef struct asc_dvc_cfg {
- ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
- ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
- ASC_SCSI_BIT_ID_TYPE disc_enable;
- ASC_SCSI_BIT_ID_TYPE sdtr_enable;
- uchar chip_scsi_id;
- uchar isa_dma_speed;
- uchar isa_dma_channel;
- uchar chip_version;
- ushort lib_serial_no;
- ushort lib_version;
- ushort mcode_date;
- ushort mcode_version;
- uchar max_tag_qng[ASC_MAX_TID + 1];
- uchar *overrun_buf;
- uchar sdtr_period_offset[ASC_MAX_TID + 1];
- ushort pci_slot_info;
- uchar adapter_info[6];
- struct device *dev;
+ ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
+ ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
+ ASC_SCSI_BIT_ID_TYPE disc_enable;
+ ASC_SCSI_BIT_ID_TYPE sdtr_enable;
+ uchar chip_scsi_id;
+ uchar isa_dma_speed;
+ uchar isa_dma_channel;
+ uchar chip_version;
+ ushort lib_serial_no;
+ ushort lib_version;
+ ushort mcode_date;
+ ushort mcode_version;
+ uchar max_tag_qng[ASC_MAX_TID + 1];
+ uchar *overrun_buf;
+ uchar sdtr_period_offset[ASC_MAX_TID + 1];
+ ushort pci_slot_info;
+ uchar adapter_info[6];
+ struct device *dev;
} ASC_DVC_CFG;
#define ASC_DEF_DVC_CNTL 0xFFFF
@@ -1501,64 +1488,64 @@ typedef struct asc_dvc_cfg {
#define ASC_MIN_TAGGED_CMD 7
#define ASC_MAX_SCSI_RESET_WAIT 30
-struct asc_dvc_var; /* Forward Declaration. */
+struct asc_dvc_var; /* Forward Declaration. */
-typedef void (* ASC_ISR_CALLBACK)(struct asc_dvc_var *, ASC_QDONE_INFO *);
-typedef int (* ASC_EXE_CALLBACK)(struct asc_dvc_var *, ASC_SCSI_Q *);
+typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
+typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
typedef struct asc_dvc_var {
- PortAddr iop_base;
- ushort err_code;
- ushort dvc_cntl;
- ushort bug_fix_cntl;
- ushort bus_type;
- ASC_ISR_CALLBACK isr_callback;
- ASC_EXE_CALLBACK exe_callback;
- ASC_SCSI_BIT_ID_TYPE init_sdtr;
- ASC_SCSI_BIT_ID_TYPE sdtr_done;
- ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
- ASC_SCSI_BIT_ID_TYPE unit_not_ready;
- ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
- ASC_SCSI_BIT_ID_TYPE start_motor;
- uchar scsi_reset_wait;
- uchar chip_no;
- char is_in_int;
- uchar max_total_qng;
- uchar cur_total_qng;
- uchar in_critical_cnt;
- uchar irq_no;
- uchar last_q_shortage;
- ushort init_state;
- uchar cur_dvc_qng[ASC_MAX_TID + 1];
- uchar max_dvc_qng[ASC_MAX_TID + 1];
- ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
- ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
- uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
- ASC_DVC_CFG *cfg;
- ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
- char redo_scam;
- ushort res2;
- uchar dos_int13_table[ASC_MAX_TID + 1];
- ASC_DCNT max_dma_count;
- ASC_SCSI_BIT_ID_TYPE no_scam;
- ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
- uchar max_sdtr_index;
- uchar host_init_sdtr_index;
- struct asc_board *drv_ptr;
- ASC_DCNT uc_break;
+ PortAddr iop_base;
+ ushort err_code;
+ ushort dvc_cntl;
+ ushort bug_fix_cntl;
+ ushort bus_type;
+ ASC_ISR_CALLBACK isr_callback;
+ ASC_EXE_CALLBACK exe_callback;
+ ASC_SCSI_BIT_ID_TYPE init_sdtr;
+ ASC_SCSI_BIT_ID_TYPE sdtr_done;
+ ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
+ ASC_SCSI_BIT_ID_TYPE unit_not_ready;
+ ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
+ ASC_SCSI_BIT_ID_TYPE start_motor;
+ uchar scsi_reset_wait;
+ uchar chip_no;
+ char is_in_int;
+ uchar max_total_qng;
+ uchar cur_total_qng;
+ uchar in_critical_cnt;
+ uchar irq_no;
+ uchar last_q_shortage;
+ ushort init_state;
+ uchar cur_dvc_qng[ASC_MAX_TID + 1];
+ uchar max_dvc_qng[ASC_MAX_TID + 1];
+ ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
+ ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
+ uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+ ASC_DVC_CFG *cfg;
+ ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
+ char redo_scam;
+ ushort res2;
+ uchar dos_int13_table[ASC_MAX_TID + 1];
+ ASC_DCNT max_dma_count;
+ ASC_SCSI_BIT_ID_TYPE no_scam;
+ ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+ uchar max_sdtr_index;
+ uchar host_init_sdtr_index;
+ struct asc_board *drv_ptr;
+ ASC_DCNT uc_break;
} ASC_DVC_VAR;
typedef struct asc_dvc_inq_info {
- uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+ uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
} ASC_DVC_INQ_INFO;
typedef struct asc_cap_info {
- ASC_DCNT lba;
- ASC_DCNT blk_size;
+ ASC_DCNT lba;
+ ASC_DCNT blk_size;
} ASC_CAP_INFO;
typedef struct asc_cap_info_array {
- ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+ ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
} ASC_CAP_INFO_ARRAY;
#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
@@ -1603,23 +1590,23 @@ typedef struct asc_cap_info_array {
((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
typedef struct asceep_config {
- ushort cfg_lsw;
- ushort cfg_msw;
- uchar init_sdtr;
- uchar disc_enable;
- uchar use_cmd_qng;
- uchar start_motor;
- uchar max_total_qng;
- uchar max_tag_qng;
- uchar bios_scan;
- uchar power_up_wait;
- uchar no_scam;
- uchar id_speed; /* low order 4 bits is chip scsi id */
- /* high order 4 bits is isa dma speed */
- uchar dos_int13_table[ASC_MAX_TID + 1];
- uchar adapter_info[6];
- ushort cntl;
- ushort chksum;
+ ushort cfg_lsw;
+ ushort cfg_msw;
+ uchar init_sdtr;
+ uchar disc_enable;
+ uchar use_cmd_qng;
+ uchar start_motor;
+ uchar max_total_qng;
+ uchar max_tag_qng;
+ uchar bios_scan;
+ uchar power_up_wait;
+ uchar no_scam;
+ uchar id_speed; /* low order 4 bits is chip scsi id */
+ /* high order 4 bits is isa dma speed */
+ uchar dos_int13_table[ASC_MAX_TID + 1];
+ uchar adapter_info[6];
+ ushort cntl;
+ ushort chksum;
} ASCEEP_CONFIG;
#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
@@ -1827,8 +1814,8 @@ typedef struct asceep_config {
#define ASC_MC_SAVE_DATA_WSIZE 0x40
typedef struct asc_mc_saved {
- ushort data[ASC_MC_SAVE_DATA_WSIZE];
- ushort code[ASC_MC_SAVE_CODE_WSIZE];
+ ushort data[ASC_MC_SAVE_DATA_WSIZE];
+ ushort code[ASC_MC_SAVE_CODE_WSIZE];
} ASC_MC_SAVED;
#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
@@ -1900,120 +1887,113 @@ typedef struct asc_mc_saved {
#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
-STATIC int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
-STATIC int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
-STATIC void AscWaitEEPRead(void);
-STATIC void AscWaitEEPWrite(void);
-STATIC ushort AscReadEEPWord(PortAddr, uchar);
-STATIC ushort AscWriteEEPWord(PortAddr, uchar, ushort);
-STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-STATIC int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
-STATIC int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-STATIC int AscStartChip(PortAddr);
-STATIC int AscStopChip(PortAddr);
-STATIC void AscSetChipIH(PortAddr, ushort);
-STATIC int AscIsChipHalted(PortAddr);
-STATIC void AscAckInterrupt(PortAddr);
-STATIC void AscDisableInterrupt(PortAddr);
-STATIC void AscEnableInterrupt(PortAddr);
-STATIC void AscSetBank(PortAddr, uchar);
-STATIC int AscResetChipAndScsiBus(ASC_DVC_VAR *);
+static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
+static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
+static void AscWaitEEPRead(void);
+static void AscWaitEEPWrite(void);
+static ushort AscReadEEPWord(PortAddr, uchar);
+static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
+static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscStartChip(PortAddr);
+static int AscStopChip(PortAddr);
+static void AscSetChipIH(PortAddr, ushort);
+static int AscIsChipHalted(PortAddr);
+static void AscAckInterrupt(PortAddr);
+static void AscDisableInterrupt(PortAddr);
+static void AscEnableInterrupt(PortAddr);
+static void AscSetBank(PortAddr, uchar);
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
#ifdef CONFIG_ISA
-STATIC ushort AscGetIsaDmaChannel(PortAddr);
-STATIC ushort AscSetIsaDmaChannel(PortAddr, ushort);
-STATIC uchar AscSetIsaDmaSpeed(PortAddr, uchar);
-STATIC uchar AscGetIsaDmaSpeed(PortAddr);
+static ushort AscGetIsaDmaChannel(PortAddr);
+static ushort AscSetIsaDmaChannel(PortAddr, ushort);
+static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
+static uchar AscGetIsaDmaSpeed(PortAddr);
#endif /* CONFIG_ISA */
-STATIC uchar AscReadLramByte(PortAddr, ushort);
-STATIC ushort AscReadLramWord(PortAddr, ushort);
+static uchar AscReadLramByte(PortAddr, ushort);
+static ushort AscReadLramWord(PortAddr, ushort);
#if CC_VERY_LONG_SG_LIST
-STATIC ASC_DCNT AscReadLramDWord(PortAddr, ushort);
+static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
#endif /* CC_VERY_LONG_SG_LIST */
-STATIC void AscWriteLramWord(PortAddr, ushort, ushort);
-STATIC void AscWriteLramByte(PortAddr, ushort, uchar);
-STATIC ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
-STATIC void AscMemWordSetLram(PortAddr, ushort, ushort, int);
-STATIC void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-STATIC void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-STATIC void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
-STATIC ushort AscInitAscDvcVar(ASC_DVC_VAR *);
-STATIC ushort AscInitFromEEP(ASC_DVC_VAR *);
-STATIC ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
-STATIC ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
-STATIC int AscTestExternalLram(ASC_DVC_VAR *);
-STATIC uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
-STATIC uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
-STATIC void AscSetChipSDTR(PortAddr, uchar, uchar);
-STATIC uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
-STATIC uchar AscAllocFreeQueue(PortAddr, uchar);
-STATIC uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-STATIC int AscHostReqRiscHalt(PortAddr);
-STATIC int AscStopQueueExe(PortAddr);
-STATIC int AscSendScsiQueue(ASC_DVC_VAR *,
- ASC_SCSI_Q * scsiq,
- uchar n_q_required);
-STATIC int AscPutReadyQueue(ASC_DVC_VAR *,
- ASC_SCSI_Q *, uchar);
-STATIC int AscPutReadySgListQueue(ASC_DVC_VAR *,
- ASC_SCSI_Q *, uchar);
-STATIC int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
-STATIC int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-STATIC ushort AscInitLram(ASC_DVC_VAR *);
-STATIC ushort AscInitQLinkVar(ASC_DVC_VAR *);
-STATIC int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
-STATIC int AscIsrChipHalted(ASC_DVC_VAR *);
-STATIC uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
- ASC_QDONE_INFO *, ASC_DCNT);
-STATIC int AscIsrQDone(ASC_DVC_VAR *);
-STATIC int AscCompareString(uchar *, uchar *, int);
+static void AscWriteLramWord(PortAddr, ushort, ushort);
+static void AscWriteLramByte(PortAddr, ushort, uchar);
+static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
+static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
+static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
+static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
+static ushort AscInitFromEEP(ASC_DVC_VAR *);
+static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
+static int AscTestExternalLram(ASC_DVC_VAR *);
+static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
+static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
+static void AscSetChipSDTR(PortAddr, uchar, uchar);
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
+static uchar AscAllocFreeQueue(PortAddr, uchar);
+static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
+static int AscHostReqRiscHalt(PortAddr);
+static int AscStopQueueExe(PortAddr);
+static int AscSendScsiQueue(ASC_DVC_VAR *,
+ ASC_SCSI_Q *scsiq, uchar n_q_required);
+static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
+static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
+static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
+static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
+static ushort AscInitLram(ASC_DVC_VAR *);
+static ushort AscInitQLinkVar(ASC_DVC_VAR *);
+static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
+static int AscIsrChipHalted(ASC_DVC_VAR *);
+static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
+ ASC_QDONE_INFO *, ASC_DCNT);
+static int AscIsrQDone(ASC_DVC_VAR *);
+static int AscCompareString(uchar *, uchar *, int);
#ifdef CONFIG_ISA
-STATIC ushort AscGetEisaChipCfg(PortAddr);
-STATIC ASC_DCNT AscGetEisaProductID(PortAddr);
-STATIC PortAddr AscSearchIOPortAddrEISA(PortAddr);
-STATIC PortAddr AscSearchIOPortAddr11(PortAddr);
-STATIC PortAddr AscSearchIOPortAddr(PortAddr, ushort);
-STATIC void AscSetISAPNPWaitForKey(void);
+static ushort AscGetEisaChipCfg(PortAddr);
+static ASC_DCNT AscGetEisaProductID(PortAddr);
+static PortAddr AscSearchIOPortAddrEISA(PortAddr);
+static PortAddr AscSearchIOPortAddr11(PortAddr);
+static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
+static void AscSetISAPNPWaitForKey(void);
#endif /* CONFIG_ISA */
-STATIC uchar AscGetChipScsiCtrl(PortAddr);
-STATIC uchar AscSetChipScsiID(PortAddr, uchar);
-STATIC uchar AscGetChipVersion(PortAddr, ushort);
-STATIC ushort AscGetChipBusType(PortAddr);
-STATIC ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
-STATIC int AscFindSignature(PortAddr);
-STATIC void AscToggleIRQAct(PortAddr);
-STATIC uchar AscGetChipIRQ(PortAddr, ushort);
-STATIC uchar AscSetChipIRQ(PortAddr, uchar, ushort);
-STATIC ushort AscGetChipBiosAddress(PortAddr, ushort);
-STATIC inline ulong DvcEnterCritical(void);
-STATIC inline void DvcLeaveCritical(ulong);
+static uchar AscGetChipScsiCtrl(PortAddr);
+static uchar AscSetChipScsiID(PortAddr, uchar);
+static uchar AscGetChipVersion(PortAddr, ushort);
+static ushort AscGetChipBusType(PortAddr);
+static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
+static int AscFindSignature(PortAddr);
+static void AscToggleIRQAct(PortAddr);
+static uchar AscGetChipIRQ(PortAddr, ushort);
+static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
+static ushort AscGetChipBiosAddress(PortAddr, ushort);
+static inline ulong DvcEnterCritical(void);
+static inline void DvcLeaveCritical(ulong);
#ifdef CONFIG_PCI
-STATIC uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
-STATIC void DvcWritePCIConfigByte(ASC_DVC_VAR *,
- ushort, uchar);
+static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
+static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
#endif /* CONFIG_PCI */
-STATIC ushort AscGetChipBiosAddress(PortAddr, ushort);
-STATIC void DvcSleepMilliSecond(ASC_DCNT);
-STATIC void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
-STATIC void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
-STATIC void DvcGetQinfo(PortAddr, ushort, uchar *, int);
-STATIC ushort AscInitGetConfig(ASC_DVC_VAR *);
-STATIC ushort AscInitSetConfig(ASC_DVC_VAR *);
-STATIC ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
-STATIC void AscAsyncFix(ASC_DVC_VAR *, uchar,
- ASC_SCSI_INQUIRY *);
-STATIC int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
-STATIC void AscInquiryHandling(ASC_DVC_VAR *,
- uchar, ASC_SCSI_INQUIRY *);
-STATIC int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
-STATIC int AscISR(ASC_DVC_VAR *);
-STATIC uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar,
- uchar);
-STATIC int AscSgListToQueue(int);
+static ushort AscGetChipBiosAddress(PortAddr, ushort);
+static void DvcSleepMilliSecond(ASC_DCNT);
+static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
+static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
+static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
+static ushort AscInitGetConfig(ASC_DVC_VAR *);
+static ushort AscInitSetConfig(ASC_DVC_VAR *);
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
+static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
+static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
+static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
+static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
+static int AscISR(ASC_DVC_VAR *);
+static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
+static int AscSgListToQueue(int);
#ifdef CONFIG_ISA
-STATIC void AscEnableIsaDma(uchar);
+static void AscEnableIsaDma(uchar);
#endif /* CONFIG_ISA */
-STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
-static const char *advansys_info(struct Scsi_Host *shp);
+static ASC_DCNT AscGetMaxDmaCount(ushort);
+static const char *advansys_info(struct Scsi_Host *shost);
/*
* --- Adv Library Constants and Macros
@@ -2035,10 +2015,10 @@ static const char *advansys_info(struct Scsi_Host *shp);
* are all consistent at 8, 16, and 32 bits respectively. Pointers
* and long types are 64 bits on Alpha and UltraSPARC.
*/
-#define ADV_PADDR __u32 /* Physical address data type. */
-#define ADV_VADDR __u32 /* Virtual address data type. */
-#define ADV_DCNT __u32 /* Unsigned Data count type. */
-#define ADV_SDCNT __s32 /* Signed Data count type. */
+#define ADV_PADDR __u32 /* Physical address data type. */
+#define ADV_VADDR __u32 /* Virtual address data type. */
+#define ADV_DCNT __u32 /* Unsigned Data count type. */
+#define ADV_SDCNT __s32 /* Signed Data count type. */
/*
* These macros are used to convert a virtual address to a
@@ -2051,7 +2031,7 @@ static const char *advansys_info(struct Scsi_Host *shp);
#define ADV_VADDR_TO_U32 virt_to_bus
#define ADV_U32_TO_VADDR bus_to_virt
-#define AdvPortAddr void __iomem * /* Virtual memory address size */
+#define AdvPortAddr void __iomem * /* Virtual memory address size */
/*
* Define Adv Library required memory access macros.
@@ -2103,20 +2083,20 @@ static const char *advansys_info(struct Scsi_Host *shp);
#define ADV_EEP_DVC_CFG_BEGIN (0x00)
#define ADV_EEP_DVC_CFG_END (0x15)
-#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
+#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
#define ADV_EEP_MAX_WORD_ADDR (0x1E)
#define ADV_EEP_DELAY_MS 100
-#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
-#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
+#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
+#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
/*
* For the ASC3550 Bit 13 is Termination Polarity control bit.
* For later ICs Bit 13 controls whether the CIS (Card Information
* Service Section) is loaded from EEPROM.
*/
-#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
-#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
+#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
+#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
/*
* ASC38C1600 Bit 11
*
@@ -2128,280 +2108,277 @@ static const char *advansys_info(struct Scsi_Host *shp);
* INT B in the PCI Configuration Space Int Pin field. If it is 1, then
* Function 1 will specify INT A.
*/
-#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
-
-typedef struct adveep_3550_config
-{
- /* Word Offset, Description */
-
- ushort cfg_lsw; /* 00 power up initialization */
- /* bit 13 set - Term Polarity Control */
- /* bit 14 set - BIOS Enable */
- /* bit 15 set - Big Endian Mode */
- ushort cfg_msw; /* 01 unused */
- ushort disc_enable; /* 02 disconnect enable */
- ushort wdtr_able; /* 03 Wide DTR able */
- ushort sdtr_able; /* 04 Synchronous DTR able */
- ushort start_motor; /* 05 send start up motor */
- ushort tagqng_able; /* 06 tag queuing able */
- ushort bios_scan; /* 07 BIOS device control */
- ushort scam_tolerant; /* 08 no scam */
-
- uchar adapter_scsi_id; /* 09 Host Adapter ID */
- uchar bios_boot_delay; /* power up wait */
-
- uchar scsi_reset_delay; /* 10 reset delay */
- uchar bios_id_lun; /* first boot device scsi id & lun */
- /* high nibble is lun */
- /* low nibble is scsi id */
-
- uchar termination; /* 11 0 - automatic */
- /* 1 - low off / high off */
- /* 2 - low off / high on */
- /* 3 - low on / high on */
- /* There is no low on / high off */
-
- uchar reserved1; /* reserved byte (not used) */
-
- ushort bios_ctrl; /* 12 BIOS control bits */
- /* bit 0 BIOS don't act as initiator. */
- /* bit 1 BIOS > 1 GB support */
- /* bit 2 BIOS > 2 Disk Support */
- /* bit 3 BIOS don't support removables */
- /* bit 4 BIOS support bootable CD */
- /* bit 5 BIOS scan enabled */
- /* bit 6 BIOS support multiple LUNs */
- /* bit 7 BIOS display of message */
- /* bit 8 SCAM disabled */
- /* bit 9 Reset SCSI bus during init. */
- /* bit 10 */
- /* bit 11 No verbose initialization. */
- /* bit 12 SCSI parity enabled */
- /* bit 13 */
- /* bit 14 */
- /* bit 15 */
- ushort ultra_able; /* 13 ULTRA speed able */
- ushort reserved2; /* 14 reserved */
- uchar max_host_qng; /* 15 maximum host queuing */
- uchar max_dvc_qng; /* maximum per device queuing */
- ushort dvc_cntl; /* 16 control bit for driver */
- ushort bug_fix; /* 17 control bit for bug fix */
- ushort serial_number_word1; /* 18 Board serial number word 1 */
- ushort serial_number_word2; /* 19 Board serial number word 2 */
- ushort serial_number_word3; /* 20 Board serial number word 3 */
- ushort check_sum; /* 21 EEP check sum */
- uchar oem_name[16]; /* 22 OEM name */
- ushort dvc_err_code; /* 30 last device driver error code */
- ushort adv_err_code; /* 31 last uc and Adv Lib error code */
- ushort adv_err_addr; /* 32 last uc error address */
- ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
- ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
- ushort saved_adv_err_addr; /* 35 saved last uc error address */
- ushort num_of_err; /* 36 number of error */
+#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
+
+typedef struct adveep_3550_config {
+ /* Word Offset, Description */
+
+ ushort cfg_lsw; /* 00 power up initialization */
+ /* bit 13 set - Term Polarity Control */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ ushort cfg_msw; /* 01 unused */
+ ushort disc_enable; /* 02 disconnect enable */
+ ushort wdtr_able; /* 03 Wide DTR able */
+ ushort sdtr_able; /* 04 Synchronous DTR able */
+ ushort start_motor; /* 05 send start up motor */
+ ushort tagqng_able; /* 06 tag queuing able */
+ ushort bios_scan; /* 07 BIOS device control */
+ ushort scam_tolerant; /* 08 no scam */
+
+ uchar adapter_scsi_id; /* 09 Host Adapter ID */
+ uchar bios_boot_delay; /* power up wait */
+
+ uchar scsi_reset_delay; /* 10 reset delay */
+ uchar bios_id_lun; /* first boot device scsi id & lun */
+ /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ uchar termination; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ uchar reserved1; /* reserved byte (not used) */
+
+ ushort bios_ctrl; /* 12 BIOS control bits */
+ /* bit 0 BIOS don't act as initiator. */
+ /* bit 1 BIOS > 1 GB support */
+ /* bit 2 BIOS > 2 Disk Support */
+ /* bit 3 BIOS don't support removables */
+ /* bit 4 BIOS support bootable CD */
+ /* bit 5 BIOS scan enabled */
+ /* bit 6 BIOS support multiple LUNs */
+ /* bit 7 BIOS display of message */
+ /* bit 8 SCAM disabled */
+ /* bit 9 Reset SCSI bus during init. */
+ /* bit 10 */
+ /* bit 11 No verbose initialization. */
+ /* bit 12 SCSI parity enabled */
+ /* bit 13 */
+ /* bit 14 */
+ /* bit 15 */
+ ushort ultra_able; /* 13 ULTRA speed able */
+ ushort reserved2; /* 14 reserved */
+ uchar max_host_qng; /* 15 maximum host queuing */
+ uchar max_dvc_qng; /* maximum per device queuing */
+ ushort dvc_cntl; /* 16 control bit for driver */
+ ushort bug_fix; /* 17 control bit for bug fix */
+ ushort serial_number_word1; /* 18 Board serial number word 1 */
+ ushort serial_number_word2; /* 19 Board serial number word 2 */
+ ushort serial_number_word3; /* 20 Board serial number word 3 */
+ ushort check_sum; /* 21 EEP check sum */
+ uchar oem_name[16]; /* 22 OEM name */
+ ushort dvc_err_code; /* 30 last device driver error code */
+ ushort adv_err_code; /* 31 last uc and Adv Lib error code */
+ ushort adv_err_addr; /* 32 last uc error address */
+ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
+ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
+ ushort saved_adv_err_addr; /* 35 saved last uc error address */
+ ushort num_of_err; /* 36 number of error */
} ADVEEP_3550_CONFIG;
-typedef struct adveep_38C0800_config
-{
- /* Word Offset, Description */
-
- ushort cfg_lsw; /* 00 power up initialization */
- /* bit 13 set - Load CIS */
- /* bit 14 set - BIOS Enable */
- /* bit 15 set - Big Endian Mode */
- ushort cfg_msw; /* 01 unused */
- ushort disc_enable; /* 02 disconnect enable */
- ushort wdtr_able; /* 03 Wide DTR able */
- ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
- ushort start_motor; /* 05 send start up motor */
- ushort tagqng_able; /* 06 tag queuing able */
- ushort bios_scan; /* 07 BIOS device control */
- ushort scam_tolerant; /* 08 no scam */
-
- uchar adapter_scsi_id; /* 09 Host Adapter ID */
- uchar bios_boot_delay; /* power up wait */
-
- uchar scsi_reset_delay; /* 10 reset delay */
- uchar bios_id_lun; /* first boot device scsi id & lun */
- /* high nibble is lun */
- /* low nibble is scsi id */
-
- uchar termination_se; /* 11 0 - automatic */
- /* 1 - low off / high off */
- /* 2 - low off / high on */
- /* 3 - low on / high on */
- /* There is no low on / high off */
-
- uchar termination_lvd; /* 11 0 - automatic */
- /* 1 - low off / high off */
- /* 2 - low off / high on */
- /* 3 - low on / high on */
- /* There is no low on / high off */
-
- ushort bios_ctrl; /* 12 BIOS control bits */
- /* bit 0 BIOS don't act as initiator. */
- /* bit 1 BIOS > 1 GB support */
- /* bit 2 BIOS > 2 Disk Support */
- /* bit 3 BIOS don't support removables */
- /* bit 4 BIOS support bootable CD */
- /* bit 5 BIOS scan enabled */
- /* bit 6 BIOS support multiple LUNs */
- /* bit 7 BIOS display of message */
- /* bit 8 SCAM disabled */
- /* bit 9 Reset SCSI bus during init. */
- /* bit 10 */
- /* bit 11 No verbose initialization. */
- /* bit 12 SCSI parity enabled */
- /* bit 13 */
- /* bit 14 */
- /* bit 15 */
- ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
- ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
- uchar max_host_qng; /* 15 maximum host queueing */
- uchar max_dvc_qng; /* maximum per device queuing */
- ushort dvc_cntl; /* 16 control bit for driver */
- ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
- ushort serial_number_word1; /* 18 Board serial number word 1 */
- ushort serial_number_word2; /* 19 Board serial number word 2 */
- ushort serial_number_word3; /* 20 Board serial number word 3 */
- ushort check_sum; /* 21 EEP check sum */
- uchar oem_name[16]; /* 22 OEM name */
- ushort dvc_err_code; /* 30 last device driver error code */
- ushort adv_err_code; /* 31 last uc and Adv Lib error code */
- ushort adv_err_addr; /* 32 last uc error address */
- ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
- ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
- ushort saved_adv_err_addr; /* 35 saved last uc error address */
- ushort reserved36; /* 36 reserved */
- ushort reserved37; /* 37 reserved */
- ushort reserved38; /* 38 reserved */
- ushort reserved39; /* 39 reserved */
- ushort reserved40; /* 40 reserved */
- ushort reserved41; /* 41 reserved */
- ushort reserved42; /* 42 reserved */
- ushort reserved43; /* 43 reserved */
- ushort reserved44; /* 44 reserved */
- ushort reserved45; /* 45 reserved */
- ushort reserved46; /* 46 reserved */
- ushort reserved47; /* 47 reserved */
- ushort reserved48; /* 48 reserved */
- ushort reserved49; /* 49 reserved */
- ushort reserved50; /* 50 reserved */
- ushort reserved51; /* 51 reserved */
- ushort reserved52; /* 52 reserved */
- ushort reserved53; /* 53 reserved */
- ushort reserved54; /* 54 reserved */
- ushort reserved55; /* 55 reserved */
- ushort cisptr_lsw; /* 56 CIS PTR LSW */
- ushort cisprt_msw; /* 57 CIS PTR MSW */
- ushort subsysvid; /* 58 SubSystem Vendor ID */
- ushort subsysid; /* 59 SubSystem ID */
- ushort reserved60; /* 60 reserved */
- ushort reserved61; /* 61 reserved */
- ushort reserved62; /* 62 reserved */
- ushort reserved63; /* 63 reserved */
+typedef struct adveep_38C0800_config {
+ /* Word Offset, Description */
+
+ ushort cfg_lsw; /* 00 power up initialization */
+ /* bit 13 set - Load CIS */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ ushort cfg_msw; /* 01 unused */
+ ushort disc_enable; /* 02 disconnect enable */
+ ushort wdtr_able; /* 03 Wide DTR able */
+ ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
+ ushort start_motor; /* 05 send start up motor */
+ ushort tagqng_able; /* 06 tag queuing able */
+ ushort bios_scan; /* 07 BIOS device control */
+ ushort scam_tolerant; /* 08 no scam */
+
+ uchar adapter_scsi_id; /* 09 Host Adapter ID */
+ uchar bios_boot_delay; /* power up wait */
+
+ uchar scsi_reset_delay; /* 10 reset delay */
+ uchar bios_id_lun; /* first boot device scsi id & lun */
+ /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ uchar termination_se; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ uchar termination_lvd; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ ushort bios_ctrl; /* 12 BIOS control bits */
+ /* bit 0 BIOS don't act as initiator. */
+ /* bit 1 BIOS > 1 GB support */
+ /* bit 2 BIOS > 2 Disk Support */
+ /* bit 3 BIOS don't support removables */
+ /* bit 4 BIOS support bootable CD */
+ /* bit 5 BIOS scan enabled */
+ /* bit 6 BIOS support multiple LUNs */
+ /* bit 7 BIOS display of message */
+ /* bit 8 SCAM disabled */
+ /* bit 9 Reset SCSI bus during init. */
+ /* bit 10 */
+ /* bit 11 No verbose initialization. */
+ /* bit 12 SCSI parity enabled */
+ /* bit 13 */
+ /* bit 14 */
+ /* bit 15 */
+ ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
+ ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
+ uchar max_host_qng; /* 15 maximum host queueing */
+ uchar max_dvc_qng; /* maximum per device queuing */
+ ushort dvc_cntl; /* 16 control bit for driver */
+ ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
+ ushort serial_number_word1; /* 18 Board serial number word 1 */
+ ushort serial_number_word2; /* 19 Board serial number word 2 */
+ ushort serial_number_word3; /* 20 Board serial number word 3 */
+ ushort check_sum; /* 21 EEP check sum */
+ uchar oem_name[16]; /* 22 OEM name */
+ ushort dvc_err_code; /* 30 last device driver error code */
+ ushort adv_err_code; /* 31 last uc and Adv Lib error code */
+ ushort adv_err_addr; /* 32 last uc error address */
+ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
+ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
+ ushort saved_adv_err_addr; /* 35 saved last uc error address */
+ ushort reserved36; /* 36 reserved */
+ ushort reserved37; /* 37 reserved */
+ ushort reserved38; /* 38 reserved */
+ ushort reserved39; /* 39 reserved */
+ ushort reserved40; /* 40 reserved */
+ ushort reserved41; /* 41 reserved */
+ ushort reserved42; /* 42 reserved */
+ ushort reserved43; /* 43 reserved */
+ ushort reserved44; /* 44 reserved */
+ ushort reserved45; /* 45 reserved */
+ ushort reserved46; /* 46 reserved */
+ ushort reserved47; /* 47 reserved */
+ ushort reserved48; /* 48 reserved */
+ ushort reserved49; /* 49 reserved */
+ ushort reserved50; /* 50 reserved */
+ ushort reserved51; /* 51 reserved */
+ ushort reserved52; /* 52 reserved */
+ ushort reserved53; /* 53 reserved */
+ ushort reserved54; /* 54 reserved */
+ ushort reserved55; /* 55 reserved */
+ ushort cisptr_lsw; /* 56 CIS PTR LSW */
+ ushort cisprt_msw; /* 57 CIS PTR MSW */
+ ushort subsysvid; /* 58 SubSystem Vendor ID */
+ ushort subsysid; /* 59 SubSystem ID */
+ ushort reserved60; /* 60 reserved */
+ ushort reserved61; /* 61 reserved */
+ ushort reserved62; /* 62 reserved */
+ ushort reserved63; /* 63 reserved */
} ADVEEP_38C0800_CONFIG;
-typedef struct adveep_38C1600_config
-{
- /* Word Offset, Description */
-
- ushort cfg_lsw; /* 00 power up initialization */
- /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
- /* clear - Func. 0 INTA, Func. 1 INTB */
- /* bit 13 set - Load CIS */
- /* bit 14 set - BIOS Enable */
- /* bit 15 set - Big Endian Mode */
- ushort cfg_msw; /* 01 unused */
- ushort disc_enable; /* 02 disconnect enable */
- ushort wdtr_able; /* 03 Wide DTR able */
- ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
- ushort start_motor; /* 05 send start up motor */
- ushort tagqng_able; /* 06 tag queuing able */
- ushort bios_scan; /* 07 BIOS device control */
- ushort scam_tolerant; /* 08 no scam */
-
- uchar adapter_scsi_id; /* 09 Host Adapter ID */
- uchar bios_boot_delay; /* power up wait */
-
- uchar scsi_reset_delay; /* 10 reset delay */
- uchar bios_id_lun; /* first boot device scsi id & lun */
- /* high nibble is lun */
- /* low nibble is scsi id */
-
- uchar termination_se; /* 11 0 - automatic */
- /* 1 - low off / high off */
- /* 2 - low off / high on */
- /* 3 - low on / high on */
- /* There is no low on / high off */
-
- uchar termination_lvd; /* 11 0 - automatic */
- /* 1 - low off / high off */
- /* 2 - low off / high on */
- /* 3 - low on / high on */
- /* There is no low on / high off */
-
- ushort bios_ctrl; /* 12 BIOS control bits */
- /* bit 0 BIOS don't act as initiator. */
- /* bit 1 BIOS > 1 GB support */
- /* bit 2 BIOS > 2 Disk Support */
- /* bit 3 BIOS don't support removables */
- /* bit 4 BIOS support bootable CD */
- /* bit 5 BIOS scan enabled */
- /* bit 6 BIOS support multiple LUNs */
- /* bit 7 BIOS display of message */
- /* bit 8 SCAM disabled */
- /* bit 9 Reset SCSI bus during init. */
- /* bit 10 Basic Integrity Checking disabled */
- /* bit 11 No verbose initialization. */
- /* bit 12 SCSI parity enabled */
- /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
- /* bit 14 */
- /* bit 15 */
- ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
- ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
- uchar max_host_qng; /* 15 maximum host queueing */
- uchar max_dvc_qng; /* maximum per device queuing */
- ushort dvc_cntl; /* 16 control bit for driver */
- ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
- ushort serial_number_word1; /* 18 Board serial number word 1 */
- ushort serial_number_word2; /* 19 Board serial number word 2 */
- ushort serial_number_word3; /* 20 Board serial number word 3 */
- ushort check_sum; /* 21 EEP check sum */
- uchar oem_name[16]; /* 22 OEM name */
- ushort dvc_err_code; /* 30 last device driver error code */
- ushort adv_err_code; /* 31 last uc and Adv Lib error code */
- ushort adv_err_addr; /* 32 last uc error address */
- ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
- ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
- ushort saved_adv_err_addr; /* 35 saved last uc error address */
- ushort reserved36; /* 36 reserved */
- ushort reserved37; /* 37 reserved */
- ushort reserved38; /* 38 reserved */
- ushort reserved39; /* 39 reserved */
- ushort reserved40; /* 40 reserved */
- ushort reserved41; /* 41 reserved */
- ushort reserved42; /* 42 reserved */
- ushort reserved43; /* 43 reserved */
- ushort reserved44; /* 44 reserved */
- ushort reserved45; /* 45 reserved */
- ushort reserved46; /* 46 reserved */
- ushort reserved47; /* 47 reserved */
- ushort reserved48; /* 48 reserved */
- ushort reserved49; /* 49 reserved */
- ushort reserved50; /* 50 reserved */
- ushort reserved51; /* 51 reserved */
- ushort reserved52; /* 52 reserved */
- ushort reserved53; /* 53 reserved */
- ushort reserved54; /* 54 reserved */
- ushort reserved55; /* 55 reserved */
- ushort cisptr_lsw; /* 56 CIS PTR LSW */
- ushort cisprt_msw; /* 57 CIS PTR MSW */
- ushort subsysvid; /* 58 SubSystem Vendor ID */
- ushort subsysid; /* 59 SubSystem ID */
- ushort reserved60; /* 60 reserved */
- ushort reserved61; /* 61 reserved */
- ushort reserved62; /* 62 reserved */
- ushort reserved63; /* 63 reserved */
+typedef struct adveep_38C1600_config {
+ /* Word Offset, Description */
+
+ ushort cfg_lsw; /* 00 power up initialization */
+ /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
+ /* clear - Func. 0 INTA, Func. 1 INTB */
+ /* bit 13 set - Load CIS */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ ushort cfg_msw; /* 01 unused */
+ ushort disc_enable; /* 02 disconnect enable */
+ ushort wdtr_able; /* 03 Wide DTR able */
+ ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
+ ushort start_motor; /* 05 send start up motor */
+ ushort tagqng_able; /* 06 tag queuing able */
+ ushort bios_scan; /* 07 BIOS device control */
+ ushort scam_tolerant; /* 08 no scam */
+
+ uchar adapter_scsi_id; /* 09 Host Adapter ID */
+ uchar bios_boot_delay; /* power up wait */
+
+ uchar scsi_reset_delay; /* 10 reset delay */
+ uchar bios_id_lun; /* first boot device scsi id & lun */
+ /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ uchar termination_se; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ uchar termination_lvd; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ ushort bios_ctrl; /* 12 BIOS control bits */
+ /* bit 0 BIOS don't act as initiator. */
+ /* bit 1 BIOS > 1 GB support */
+ /* bit 2 BIOS > 2 Disk Support */
+ /* bit 3 BIOS don't support removables */
+ /* bit 4 BIOS support bootable CD */
+ /* bit 5 BIOS scan enabled */
+ /* bit 6 BIOS support multiple LUNs */
+ /* bit 7 BIOS display of message */
+ /* bit 8 SCAM disabled */
+ /* bit 9 Reset SCSI bus during init. */
+ /* bit 10 Basic Integrity Checking disabled */
+ /* bit 11 No verbose initialization. */
+ /* bit 12 SCSI parity enabled */
+ /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
+ /* bit 14 */
+ /* bit 15 */
+ ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
+ ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
+ uchar max_host_qng; /* 15 maximum host queueing */
+ uchar max_dvc_qng; /* maximum per device queuing */
+ ushort dvc_cntl; /* 16 control bit for driver */
+ ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
+ ushort serial_number_word1; /* 18 Board serial number word 1 */
+ ushort serial_number_word2; /* 19 Board serial number word 2 */
+ ushort serial_number_word3; /* 20 Board serial number word 3 */
+ ushort check_sum; /* 21 EEP check sum */
+ uchar oem_name[16]; /* 22 OEM name */
+ ushort dvc_err_code; /* 30 last device driver error code */
+ ushort adv_err_code; /* 31 last uc and Adv Lib error code */
+ ushort adv_err_addr; /* 32 last uc error address */
+ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
+ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
+ ushort saved_adv_err_addr; /* 35 saved last uc error address */
+ ushort reserved36; /* 36 reserved */
+ ushort reserved37; /* 37 reserved */
+ ushort reserved38; /* 38 reserved */
+ ushort reserved39; /* 39 reserved */
+ ushort reserved40; /* 40 reserved */
+ ushort reserved41; /* 41 reserved */
+ ushort reserved42; /* 42 reserved */
+ ushort reserved43; /* 43 reserved */
+ ushort reserved44; /* 44 reserved */
+ ushort reserved45; /* 45 reserved */
+ ushort reserved46; /* 46 reserved */
+ ushort reserved47; /* 47 reserved */
+ ushort reserved48; /* 48 reserved */
+ ushort reserved49; /* 49 reserved */
+ ushort reserved50; /* 50 reserved */
+ ushort reserved51; /* 51 reserved */
+ ushort reserved52; /* 52 reserved */
+ ushort reserved53; /* 53 reserved */
+ ushort reserved54; /* 54 reserved */
+ ushort reserved55; /* 55 reserved */
+ ushort cisptr_lsw; /* 56 CIS PTR LSW */
+ ushort cisprt_msw; /* 57 CIS PTR MSW */
+ ushort subsysvid; /* 58 SubSystem Vendor ID */
+ ushort subsysid; /* 59 SubSystem ID */
+ ushort reserved60; /* 60 reserved */
+ ushort reserved61; /* 61 reserved */
+ ushort reserved62; /* 62 reserved */
+ ushort reserved63; /* 63 reserved */
} ADVEEP_38C1600_CONFIG;
/*
@@ -2427,11 +2404,11 @@ typedef struct adveep_38C1600_config
#define BIOS_CTRL_SCSI_PARITY 0x1000
#define BIOS_CTRL_AIPP_DIS 0x2000
-#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
-#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
+#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
+#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
-#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
-#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
+#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
+#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
/*
* XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
@@ -2440,9 +2417,9 @@ typedef struct adveep_38C1600_config
*
* #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
*/
-#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
-#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
-#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
+#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
+#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
+#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
/*
* Byte I/O register address from base of 'iop_base'.
@@ -2515,39 +2492,39 @@ typedef struct adveep_38C1600_config
/*
* Word I/O register address from base of 'iop_base'.
*/
-#define IOPW_CHIP_ID_0 0x00 /* CID0 */
-#define IOPW_CTRL_REG 0x02 /* CC */
-#define IOPW_RAM_ADDR 0x04 /* LA */
-#define IOPW_RAM_DATA 0x06 /* LD */
+#define IOPW_CHIP_ID_0 0x00 /* CID0 */
+#define IOPW_CTRL_REG 0x02 /* CC */
+#define IOPW_RAM_ADDR 0x04 /* LA */
+#define IOPW_RAM_DATA 0x06 /* LD */
#define IOPW_RES_ADDR_08 0x08
-#define IOPW_RISC_CSR 0x0A /* CSR */
-#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
-#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
+#define IOPW_RISC_CSR 0x0A /* CSR */
+#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
+#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
#define IOPW_RES_ADDR_10 0x10
-#define IOPW_SEL_MASK 0x12 /* SM */
+#define IOPW_SEL_MASK 0x12 /* SM */
#define IOPW_RES_ADDR_14 0x14
-#define IOPW_FLASH_ADDR 0x16 /* FA */
+#define IOPW_FLASH_ADDR 0x16 /* FA */
#define IOPW_RES_ADDR_18 0x18
-#define IOPW_EE_CMD 0x1A /* EC */
-#define IOPW_EE_DATA 0x1C /* ED */
-#define IOPW_SFIFO_CNT 0x1E /* SFC */
+#define IOPW_EE_CMD 0x1A /* EC */
+#define IOPW_EE_DATA 0x1C /* ED */
+#define IOPW_SFIFO_CNT 0x1E /* SFC */
#define IOPW_RES_ADDR_20 0x20
-#define IOPW_Q_BASE 0x22 /* QB */
-#define IOPW_QP 0x24 /* QP */
-#define IOPW_IX 0x26 /* IX */
-#define IOPW_SP 0x28 /* SP */
-#define IOPW_PC 0x2A /* PC */
+#define IOPW_Q_BASE 0x22 /* QB */
+#define IOPW_QP 0x24 /* QP */
+#define IOPW_IX 0x26 /* IX */
+#define IOPW_SP 0x28 /* SP */
+#define IOPW_PC 0x2A /* PC */
#define IOPW_RES_ADDR_2C 0x2C
#define IOPW_RES_ADDR_2E 0x2E
-#define IOPW_SCSI_DATA 0x30 /* SD */
-#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
-#define IOPW_SCSI_CTRL 0x34 /* SC */
-#define IOPW_HSHK_CFG 0x36 /* HCFG */
-#define IOPW_SXFR_STATUS 0x36 /* SXS */
-#define IOPW_SXFR_CNTL 0x38 /* SXL */
-#define IOPW_SXFR_CNTH 0x3A /* SXH */
+#define IOPW_SCSI_DATA 0x30 /* SD */
+#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
+#define IOPW_SCSI_CTRL 0x34 /* SC */
+#define IOPW_HSHK_CFG 0x36 /* HCFG */
+#define IOPW_SXFR_STATUS 0x36 /* SXS */
+#define IOPW_SXFR_CNTL 0x38 /* SXL */
+#define IOPW_SXFR_CNTH 0x3A /* SXH */
#define IOPW_RES_ADDR_3C 0x3C
-#define IOPW_RFIFO_DATA 0x3E /* RFD */
+#define IOPW_RFIFO_DATA 0x3E /* RFD */
/*
* Doubleword I/O register address from base of 'iop_base'.
@@ -2621,36 +2598,36 @@ typedef struct adveep_38C1600_config
/*
* SCSI_CFG0 Register bit definitions
*/
-#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
-#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
-#define EVEN_PARITY 0x1000 /* Select Even Parity */
-#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
-#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
-#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
-#define SCAM_EN 0x0080 /* Enable SCAM selection */
-#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
-#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
-#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
-#define OUR_ID 0x000F /* SCSI ID */
+#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
+#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
+#define EVEN_PARITY 0x1000 /* Select Even Parity */
+#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
+#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
+#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
+#define SCAM_EN 0x0080 /* Enable SCAM selection */
+#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
+#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
+#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
+#define OUR_ID 0x000F /* SCSI ID */
/*
* SCSI_CFG1 Register bit definitions
*/
-#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
-#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
-#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
-#define FILTER_SEL 0x0C00 /* Filter Period Selection */
-#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
-#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
-#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
-#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
-#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
-#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
-#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
-#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
-#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
-#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
-#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
+#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
+#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
+#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
+#define FILTER_SEL 0x0C00 /* Filter Period Selection */
+#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
+#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
+#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
+#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
+#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
+#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
+#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
+#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
+#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
+#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
+#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
/*
* Addendum for ASC-38C0800 Chip
@@ -2663,24 +2640,23 @@ typedef struct adveep_38C1600_config
* Also each ASC-38C1600 function or channel uses only cable bits [5:4]
* and [1:0]. Bits [14], [7:6], [3:2] are unused.
*/
-#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
-#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
-#define HVD 0x1000 /* HVD Device Detect */
-#define LVD 0x0800 /* LVD Device Detect */
-#define SE 0x0400 /* SE Device Detect */
-#define TERM_LVD 0x00C0 /* LVD Termination Bits */
-#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
-#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
-#define TERM_SE 0x0030 /* SE Termination Bits */
-#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
-#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
-#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
-#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
-#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
-#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
-#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
-#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
-
+#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
+#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
+#define HVD 0x1000 /* HVD Device Detect */
+#define LVD 0x0800 /* LVD Device Detect */
+#define SE 0x0400 /* SE Device Detect */
+#define TERM_LVD 0x00C0 /* LVD Termination Bits */
+#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
+#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
+#define TERM_SE 0x0030 /* SE Termination Bits */
+#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
+#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
+#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
+#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
+#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
+#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
+#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
+#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
#define CABLE_ILLEGAL_A 0x7
/* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
@@ -2691,39 +2667,39 @@ typedef struct adveep_38C1600_config
/*
* MEM_CFG Register bit definitions
*/
-#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
-#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
-#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
-#define RAM_SZ_2KB 0x00 /* 2 KB */
-#define RAM_SZ_4KB 0x04 /* 4 KB */
-#define RAM_SZ_8KB 0x08 /* 8 KB */
-#define RAM_SZ_16KB 0x0C /* 16 KB */
-#define RAM_SZ_32KB 0x10 /* 32 KB */
-#define RAM_SZ_64KB 0x14 /* 64 KB */
+#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
+#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
+#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
+#define RAM_SZ_2KB 0x00 /* 2 KB */
+#define RAM_SZ_4KB 0x04 /* 4 KB */
+#define RAM_SZ_8KB 0x08 /* 8 KB */
+#define RAM_SZ_16KB 0x0C /* 16 KB */
+#define RAM_SZ_32KB 0x10 /* 32 KB */
+#define RAM_SZ_64KB 0x14 /* 64 KB */
/*
* DMA_CFG0 Register bit definitions
*
* This register is only accessible to the host.
*/
-#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
-#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
-#define FIFO_THRESH_16B 0x00 /* 16 bytes */
-#define FIFO_THRESH_32B 0x20 /* 32 bytes */
-#define FIFO_THRESH_48B 0x30 /* 48 bytes */
-#define FIFO_THRESH_64B 0x40 /* 64 bytes */
-#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
-#define FIFO_THRESH_96B 0x60 /* 96 bytes */
-#define FIFO_THRESH_112B 0x70 /* 112 bytes */
-#define START_CTL 0x0C /* DMA start conditions */
-#define START_CTL_TH 0x00 /* Wait threshold level (default) */
-#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
-#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
-#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
-#define READ_CMD 0x03 /* Memory Read Method */
-#define READ_CMD_MR 0x00 /* Memory Read */
-#define READ_CMD_MRL 0x02 /* Memory Read Long */
-#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
+#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
+#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
+#define FIFO_THRESH_16B 0x00 /* 16 bytes */
+#define FIFO_THRESH_32B 0x20 /* 32 bytes */
+#define FIFO_THRESH_48B 0x30 /* 48 bytes */
+#define FIFO_THRESH_64B 0x40 /* 64 bytes */
+#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
+#define FIFO_THRESH_96B 0x60 /* 96 bytes */
+#define FIFO_THRESH_112B 0x70 /* 112 bytes */
+#define START_CTL 0x0C /* DMA start conditions */
+#define START_CTL_TH 0x00 /* Wait threshold level (default) */
+#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
+#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
+#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
+#define READ_CMD 0x03 /* Memory Read Method */
+#define READ_CMD_MR 0x00 /* Memory Read */
+#define READ_CMD_MRL 0x02 /* Memory Read Long */
+#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
/*
* ASC-38C0800 RAM BIST Register bit definitions
@@ -2747,7 +2723,7 @@ typedef struct adveep_38C1600_config
* IOPB_PCI_INT_CFG Bit Field Definitions
*/
-#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
+#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
/*
* Bit 1 can be set to change the interrupt for the Function to operate in
@@ -2780,53 +2756,52 @@ typedef struct adveep_38C1600_config
#define ADV_BUSY 0
#define ADV_ERROR (-1)
-
/*
* ADV_DVC_VAR 'warn_code' values
*/
-#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
-#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
-#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
-#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
-#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
+#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
+#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
+#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
+#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
+#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
-#define ADV_MAX_TID 15 /* max. target identifier */
-#define ADV_MAX_LUN 7 /* max. logical unit number */
+#define ADV_MAX_TID 15 /* max. target identifier */
+#define ADV_MAX_LUN 7 /* max. logical unit number */
/*
* Error code values are set in ADV_DVC_VAR 'err_code'.
*/
-#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
-#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
-#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
-#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
-#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
-#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
-#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
-#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
-#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
-#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
-#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
-#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
-#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
+#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
+#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
+#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
+#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
+#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
+#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
+#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
+#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
+#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
/*
* Fixed locations of microcode operating variables.
*/
-#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
-#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
-#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
-#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
-#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
-#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
-#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
-#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
-#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
-#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
-#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
-#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
-#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
+#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
+#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
+#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
+#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
+#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
+#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
+#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
+#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
+#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
+#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
+#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
+#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
+#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
#define ASC_MC_CHIP_TYPE 0x009A
#define ASC_MC_INTRB_CODE 0x009B
#define ASC_MC_WDTR_ABLE 0x009C
@@ -2844,9 +2819,9 @@ typedef struct adveep_38C1600_config
#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
-#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
+#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
#define ASC_MC_WDTR_DONE 0x0124
-#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
+#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
#define ASC_MC_ICQ 0x0160
#define ASC_MC_IRQ 0x0164
#define ASC_MC_PPR_ABLE 0x017A
@@ -2865,8 +2840,8 @@ typedef struct adveep_38C1600_config
* Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
* and handled by the microcode.
*/
-#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
-#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
+#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
+#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
/*
* ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
@@ -2875,45 +2850,44 @@ typedef struct adveep_38C1600_config
#define HSHK_CFG_RATE 0x0F00
#define HSHK_CFG_OFFSET 0x001F
-#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
-#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
-#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
-#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
-
-#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
-#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
-#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
-#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
-#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
-
-#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
-#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
-#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
-#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
-#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
+#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
+#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
+#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
+#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
+
+#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
+#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
+#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
+#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
+#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
+
+#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
+#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
+#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
+#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
+#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
/*
* Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
* ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
*/
-#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
-#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
+#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
/*
* All fields here are accessed by the board microcode and need to be
* little-endian.
*/
-typedef struct adv_carr_t
-{
- ADV_VADDR carr_va; /* Carrier Virtual Address */
- ADV_PADDR carr_pa; /* Carrier Physical Address */
- ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
- /*
- * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
- *
- * next_vpa [3:1] Reserved Bits
- * next_vpa [0] Done Flag set in Response Queue.
- */
- ADV_VADDR next_vpa;
+typedef struct adv_carr_t {
+ ADV_VADDR carr_va; /* Carrier Virtual Address */
+ ADV_PADDR carr_pa; /* Carrier Physical Address */
+ ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
+ /*
+ * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
+ *
+ * next_vpa [3:1] Reserved Bits
+ * next_vpa [0] Done Flag set in Response Queue.
+ */
+ ADV_VADDR next_vpa;
} ADV_CARR_T;
/*
@@ -2940,13 +2914,13 @@ typedef struct adv_carr_t
* The Adv Library should limit use to the lower nibble (4 bits) of
* a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
*/
-#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
-#define ADV_SCSIQ_DONE 0x02 /* request done */
-#define ADV_DONT_RETRY 0x08 /* don't do retry */
+#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
+#define ADV_SCSIQ_DONE 0x02 /* request done */
+#define ADV_DONT_RETRY 0x08 /* don't do retry */
-#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
-#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
-#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
+#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
+#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
+#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
/*
* Adapter temporary configuration structure
@@ -2960,30 +2934,30 @@ typedef struct adv_carr_t
* value of the field is never reset.
*/
typedef struct adv_dvc_cfg {
- ushort disc_enable; /* enable disconnection */
- uchar chip_version; /* chip version */
- uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
- ushort lib_version; /* Adv Library version number */
- ushort control_flag; /* Microcode Control Flag */
- ushort mcode_date; /* Microcode date */
- ushort mcode_version; /* Microcode version */
- ushort pci_slot_info; /* high byte device/function number */
- /* bits 7-3 device num., bits 2-0 function num. */
- /* low byte bus num. */
- ushort serial1; /* EEPROM serial number word 1 */
- ushort serial2; /* EEPROM serial number word 2 */
- ushort serial3; /* EEPROM serial number word 3 */
- struct device *dev; /* pointer to the pci dev structure for this board */
+ ushort disc_enable; /* enable disconnection */
+ uchar chip_version; /* chip version */
+ uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
+ ushort lib_version; /* Adv Library version number */
+ ushort control_flag; /* Microcode Control Flag */
+ ushort mcode_date; /* Microcode date */
+ ushort mcode_version; /* Microcode version */
+ ushort pci_slot_info; /* high byte device/function number */
+ /* bits 7-3 device num., bits 2-0 function num. */
+ /* low byte bus num. */
+ ushort serial1; /* EEPROM serial number word 1 */
+ ushort serial2; /* EEPROM serial number word 2 */
+ ushort serial3; /* EEPROM serial number word 3 */
+ struct device *dev; /* pointer to the pci dev structure for this board */
} ADV_DVC_CFG;
struct adv_dvc_var;
struct adv_scsi_req_q;
-typedef void (* ADV_ISR_CALLBACK)
- (struct adv_dvc_var *, struct adv_scsi_req_q *);
+typedef void (*ADV_ISR_CALLBACK)
+ (struct adv_dvc_var *, struct adv_scsi_req_q *);
-typedef void (* ADV_ASYNC_CALLBACK)
- (struct adv_dvc_var *, uchar);
+typedef void (*ADV_ASYNC_CALLBACK)
+ (struct adv_dvc_var *, uchar);
/*
* Adapter operation variable structure.
@@ -2998,55 +2972,55 @@ typedef void (* ADV_ASYNC_CALLBACK)
* of the feature, the field is cleared.
*/
typedef struct adv_dvc_var {
- AdvPortAddr iop_base; /* I/O port address */
- ushort err_code; /* fatal error code */
- ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
- ADV_ISR_CALLBACK isr_callback;
- ADV_ASYNC_CALLBACK async_callback;
- ushort wdtr_able; /* try WDTR for a device */
- ushort sdtr_able; /* try SDTR for a device */
- ushort ultra_able; /* try SDTR Ultra speed for a device */
- ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
- ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
- ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
- ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
- ushort tagqng_able; /* try tagged queuing with a device */
- ushort ppr_able; /* PPR message capable per TID bitmask. */
- uchar max_dvc_qng; /* maximum number of tagged commands per device */
- ushort start_motor; /* start motor command allowed */
- uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
- uchar chip_no; /* should be assigned by caller */
- uchar max_host_qng; /* maximum number of Q'ed command allowed */
- uchar irq_no; /* IRQ number */
- ushort no_scam; /* scam_tolerant of EEPROM */
- struct asc_board *drv_ptr; /* driver pointer to private structure */
- uchar chip_scsi_id; /* chip SCSI target ID */
- uchar chip_type;
- uchar bist_err_code;
- ADV_CARR_T *carrier_buf;
- ADV_CARR_T *carr_freelist; /* Carrier free list. */
- ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
- ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
- ushort carr_pending_cnt; /* Count of pending carriers. */
- /*
- * Note: The following fields will not be used after initialization. The
- * driver may discard the buffer after initialization is done.
- */
- ADV_DVC_CFG *cfg; /* temporary configuration structure */
+ AdvPortAddr iop_base; /* I/O port address */
+ ushort err_code; /* fatal error code */
+ ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
+ ADV_ISR_CALLBACK isr_callback;
+ ADV_ASYNC_CALLBACK async_callback;
+ ushort wdtr_able; /* try WDTR for a device */
+ ushort sdtr_able; /* try SDTR for a device */
+ ushort ultra_able; /* try SDTR Ultra speed for a device */
+ ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
+ ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
+ ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
+ ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
+ ushort tagqng_able; /* try tagged queuing with a device */
+ ushort ppr_able; /* PPR message capable per TID bitmask. */
+ uchar max_dvc_qng; /* maximum number of tagged commands per device */
+ ushort start_motor; /* start motor command allowed */
+ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
+ uchar chip_no; /* should be assigned by caller */
+ uchar max_host_qng; /* maximum number of Q'ed command allowed */
+ uchar irq_no; /* IRQ number */
+ ushort no_scam; /* scam_tolerant of EEPROM */
+ struct asc_board *drv_ptr; /* driver pointer to private structure */
+ uchar chip_scsi_id; /* chip SCSI target ID */
+ uchar chip_type;
+ uchar bist_err_code;
+ ADV_CARR_T *carrier_buf;
+ ADV_CARR_T *carr_freelist; /* Carrier free list. */
+ ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
+ ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
+ ushort carr_pending_cnt; /* Count of pending carriers. */
+ /*
+ * Note: The following fields will not be used after initialization. The
+ * driver may discard the buffer after initialization is done.
+ */
+ ADV_DVC_CFG *cfg; /* temporary configuration structure */
} ADV_DVC_VAR;
#define NO_OF_SG_PER_BLOCK 15
typedef struct asc_sg_block {
- uchar reserved1;
- uchar reserved2;
- uchar reserved3;
- uchar sg_cnt; /* Valid entries in block. */
- ADV_PADDR sg_ptr; /* Pointer to next sg block. */
- struct {
- ADV_PADDR sg_addr; /* SG element address. */
- ADV_DCNT sg_count; /* SG element count. */
- } sg_list[NO_OF_SG_PER_BLOCK];
+ uchar reserved1;
+ uchar reserved2;
+ uchar reserved3;
+ uchar sg_cnt; /* Valid entries in block. */
+ ADV_PADDR sg_ptr; /* Pointer to next sg block. */
+ struct {
+ ADV_PADDR sg_addr; /* SG element address. */
+ ADV_DCNT sg_count; /* SG element count. */
+ } sg_list[NO_OF_SG_PER_BLOCK];
} ADV_SG_BLOCK;
/*
@@ -3061,37 +3035,37 @@ typedef struct asc_sg_block {
* order.
*/
typedef struct adv_scsi_req_q {
- uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
- uchar target_cmd;
- uchar target_id; /* Device target identifier. */
- uchar target_lun; /* Device target logical unit number. */
- ADV_PADDR data_addr; /* Data buffer physical address. */
- ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
- ADV_PADDR sense_addr;
- ADV_PADDR carr_pa;
- uchar mflag;
- uchar sense_len;
- uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
- uchar scsi_cntl;
- uchar done_status; /* Completion status. */
- uchar scsi_status; /* SCSI status byte. */
- uchar host_status; /* Ucode host status. */
- uchar sg_working_ix;
- uchar cdb[12]; /* SCSI CDB bytes 0-11. */
- ADV_PADDR sg_real_addr; /* SG list physical address. */
- ADV_PADDR scsiq_rptr;
- uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
- ADV_VADDR scsiq_ptr;
- ADV_VADDR carr_va;
- /*
- * End of microcode structure - 60 bytes. The rest of the structure
- * is used by the Adv Library and ignored by the microcode.
- */
- ADV_VADDR srb_ptr;
- ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
- char *vdata_addr; /* Data buffer virtual address. */
- uchar a_flag;
- uchar pad[2]; /* Pad out to a word boundary. */
+ uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
+ uchar target_cmd;
+ uchar target_id; /* Device target identifier. */
+ uchar target_lun; /* Device target logical unit number. */
+ ADV_PADDR data_addr; /* Data buffer physical address. */
+ ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
+ ADV_PADDR sense_addr;
+ ADV_PADDR carr_pa;
+ uchar mflag;
+ uchar sense_len;
+ uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
+ uchar scsi_cntl;
+ uchar done_status; /* Completion status. */
+ uchar scsi_status; /* SCSI status byte. */
+ uchar host_status; /* Ucode host status. */
+ uchar sg_working_ix;
+ uchar cdb[12]; /* SCSI CDB bytes 0-11. */
+ ADV_PADDR sg_real_addr; /* SG list physical address. */
+ ADV_PADDR scsiq_rptr;
+ uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
+ ADV_VADDR scsiq_ptr;
+ ADV_VADDR carr_va;
+ /*
+ * End of microcode structure - 60 bytes. The rest of the structure
+ * is used by the Adv Library and ignored by the microcode.
+ */
+ ADV_VADDR srb_ptr;
+ ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+ char *vdata_addr; /* Data buffer virtual address. */
+ uchar a_flag;
+ uchar pad[2]; /* Pad out to a word boundary. */
} ADV_SCSI_REQ_Q;
/*
@@ -3103,8 +3077,8 @@ typedef struct adv_scsi_req_q {
#define IDLE_CMD_SEND_INT 0x0004
#define IDLE_CMD_ABORT 0x0008
#define IDLE_CMD_DEVICE_RESET 0x0010
-#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
-#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
#define IDLE_CMD_SCSIREQ 0x0080
#define IDLE_CMD_STATUS_SUCCESS 0x0001
@@ -3118,60 +3092,59 @@ typedef struct adv_scsi_req_q {
/*
* Wait loop time out values.
*/
-#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
-#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
-#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
-#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
-#define SCSI_MAX_RETRY 10 /* retry count */
-
-#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
-#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
-#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
-#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
+#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
+#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
+#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
+#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
+#define SCSI_MAX_RETRY 10 /* retry count */
+#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
+#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
+#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
+#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
-#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
+#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
/*
* Device drivers must define the following functions.
*/
-STATIC inline ulong DvcEnterCritical(void);
-STATIC inline void DvcLeaveCritical(ulong);
-STATIC void DvcSleepMilliSecond(ADV_DCNT);
-STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
-STATIC void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
-STATIC ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
- uchar *, ASC_SDCNT *, int);
-STATIC void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
+static inline ulong DvcEnterCritical(void);
+static inline void DvcLeaveCritical(ulong);
+static void DvcSleepMilliSecond(ADV_DCNT);
+static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
+static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
+static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
+ uchar *, ASC_SDCNT *, int);
+static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
/*
* Adv Library functions available to drivers.
*/
-STATIC int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int AdvISR(ADV_DVC_VAR *);
-STATIC int AdvInitGetConfig(ADV_DVC_VAR *);
-STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *);
-STATIC int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
-STATIC int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
-STATIC int AdvResetChipAndSB(ADV_DVC_VAR *);
-STATIC int AdvResetSB(ADV_DVC_VAR *asc_dvc);
+static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+static int AdvISR(ADV_DVC_VAR *);
+static int AdvInitGetConfig(ADV_DVC_VAR *);
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
+static int AdvResetChipAndSB(ADV_DVC_VAR *);
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
/*
* Internal Adv Library functions.
*/
-STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
-STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int AdvInitFrom3550EEP(ADV_DVC_VAR *);
-STATIC int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
-STATIC int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
-STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-STATIC void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-STATIC void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-STATIC ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-STATIC void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-STATIC void AdvWaitEEPCmd(AdvPortAddr);
-STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
+static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
+static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
+static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
+static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+static void AdvWaitEEPCmd(AdvPortAddr);
+static ushort AdvReadEEPWord(AdvPortAddr, int);
/*
* PCI Bus Definitions
@@ -3241,7 +3214,6 @@ do { \
#define AdvWriteWordAutoIncLram(iop_base, word) \
(ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
-
/*
* Define macro to check for Condor signature.
*
@@ -3313,7 +3285,7 @@ do { \
* ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
*/
-#define QD_NO_STATUS 0x00 /* Request not completed yet. */
+#define QD_NO_STATUS 0x00 /* Request not completed yet. */
#define QD_NO_ERROR 0x01
#define QD_ABORTED_BY_HOST 0x02
#define QD_WITH_ERROR 0x04
@@ -3323,30 +3295,29 @@ do { \
#define QHSTA_M_DATA_OVER_RUN 0x12
#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
#define QHSTA_M_QUEUE_ABORTED 0x15
-#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
-#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
-#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
-#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
-#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
-#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
-#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
+#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
+#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
+#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
+#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
+#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
+#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
+#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
-#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
-#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
-#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
-#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
-#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
-#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
-#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
-#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
+#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
+#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
+#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
+#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
+#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
+#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
+#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
#define QHSTA_M_WTM_TIMEOUT 0x41
#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
-#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
-#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
-#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
-
+#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
+#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
+#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
/*
* Default EEPROM Configuration structure defined in a_init.c.
@@ -3358,12 +3329,12 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
/*
* DvcGetPhyAddr() flag arguments
*/
-#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
-#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
-#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
-#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
-#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
-#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
+#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
+#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
+#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
+#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
+#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
+#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
/* Return the address that is aligned at the next doubleword >= to 'addr'. */
#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
@@ -3413,43 +3384,42 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
typedef struct {
- uchar periph; /* peripheral device type [0:4] */
- /* peripheral qualifier [5:7] */
- uchar devtype; /* device type modifier (for SCSI I) [0:6] */
- /* RMB - removable medium bit [7] */
- uchar ver; /* ANSI approved version [0:2] */
- /* ECMA version [3:5] */
- /* ISO version [6:7] */
- uchar byte3; /* response data format [0:3] */
- /* 0 SCSI 1 */
- /* 1 CCS */
- /* 2 SCSI-2 */
- /* 3-F reserved */
- /* reserved [4:5] */
- /* terminate I/O process bit (see 5.6.22) [6] */
- /* asynch. event notification (processor) [7] */
- uchar add_len; /* additional length */
- uchar res1; /* reserved */
- uchar res2; /* reserved */
- uchar flags; /* soft reset implemented [0] */
- /* command queuing [1] */
- /* reserved [2] */
- /* linked command for this logical unit [3] */
- /* synchronous data transfer [4] */
- /* wide bus 16 bit data transfer [5] */
- /* wide bus 32 bit data transfer [6] */
- /* relative addressing mode [7] */
- uchar vendor_id[8]; /* vendor identification */
- uchar product_id[16]; /* product identification */
- uchar product_rev_level[4]; /* product revision level */
- uchar vendor_specific[20]; /* vendor specific */
- uchar info; /* information unit supported [0] */
- /* quick arbitrate supported [1] */
- /* clocking field [2:3] */
- /* reserved [4:7] */
- uchar res3; /* reserved */
-} ADV_SCSI_INQUIRY; /* 58 bytes */
-
+ uchar periph; /* peripheral device type [0:4] */
+ /* peripheral qualifier [5:7] */
+ uchar devtype; /* device type modifier (for SCSI I) [0:6] */
+ /* RMB - removable medium bit [7] */
+ uchar ver; /* ANSI approved version [0:2] */
+ /* ECMA version [3:5] */
+ /* ISO version [6:7] */
+ uchar byte3; /* response data format [0:3] */
+ /* 0 SCSI 1 */
+ /* 1 CCS */
+ /* 2 SCSI-2 */
+ /* 3-F reserved */
+ /* reserved [4:5] */
+ /* terminate I/O process bit (see 5.6.22) [6] */
+ /* asynch. event notification (processor) [7] */
+ uchar add_len; /* additional length */
+ uchar res1; /* reserved */
+ uchar res2; /* reserved */
+ uchar flags; /* soft reset implemented [0] */
+ /* command queuing [1] */
+ /* reserved [2] */
+ /* linked command for this logical unit [3] */
+ /* synchronous data transfer [4] */
+ /* wide bus 16 bit data transfer [5] */
+ /* wide bus 32 bit data transfer [6] */
+ /* relative addressing mode [7] */
+ uchar vendor_id[8]; /* vendor identification */
+ uchar product_id[16]; /* product identification */
+ uchar product_rev_level[4]; /* product revision level */
+ uchar vendor_specific[20]; /* vendor specific */
+ uchar info; /* information unit supported [0] */
+ /* quick arbitrate supported [1] */
+ /* clocking field [2:3] */
+ /* reserved [4:7] */
+ uchar res3; /* reserved */
+} ADV_SCSI_INQUIRY; /* 58 bytes */
/*
* --- Driver Constants and Macros
@@ -3464,15 +3434,15 @@ typedef struct {
/* asc_board_t flags */
#define ASC_HOST_IN_RESET 0x01
-#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
+#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
#define ASC_SELECT_QUEUE_DEPTHS 0x08
#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
-#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
+#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
-#define ASC_INFO_SIZE 128 /* advansys_info() line size */
+#define ASC_INFO_SIZE 128 /* advansys_info() line size */
#ifdef CONFIG_PROC_FS
/* /proc/scsi/advansys/[0...] related definitions */
@@ -3514,7 +3484,7 @@ typedef struct {
* REQPTIME(reqp) - reqp's time stamp value
* REQTIMESTAMP() - system time stamp value
*/
-typedef struct scsi_cmnd REQ, *REQP;
+typedef struct scsi_cmnd REQ, *REQP;
#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
#define REQPTID(reqp) ((reqp)->device->id)
@@ -3564,17 +3534,17 @@ typedef struct scsi_cmnd REQ, *REQP;
#define PCI_MAX_SLOT 0x1F
#define PCI_MAX_BUS 0xFF
#define PCI_IOADDRESS_MASK 0xFFFE
-#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
#ifndef ADVANSYS_STATS
-#define ASC_STATS(shp, counter)
-#define ASC_STATS_ADD(shp, counter, count)
+#define ASC_STATS(shost, counter)
+#define ASC_STATS_ADD(shost, counter, count)
#else /* ADVANSYS_STATS */
-#define ASC_STATS(shp, counter) \
- (ASC_BOARDP(shp)->asc_stats.counter++)
+#define ASC_STATS(shost, counter) \
+ (ASC_BOARDP(shost)->asc_stats.counter++)
-#define ASC_STATS_ADD(shp, counter, count) \
- (ASC_BOARDP(shp)->asc_stats.counter += (count))
+#define ASC_STATS_ADD(shost, counter, count) \
+ (ASC_BOARDP(shost)->asc_stats.counter += (count))
#endif /* ADVANSYS_STATS */
#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
@@ -3617,7 +3587,6 @@ typedef struct scsi_cmnd REQ, *REQP;
printk((s), (a1), (a2), (a3), (a4)); \
}
-
#ifndef ADVANSYS_DEBUG
#define ASC_DBG(lvl, s)
@@ -3746,7 +3715,6 @@ typedef struct scsi_cmnd REQ, *REQP;
#endif /* ADVANSYS_ASSERT */
-
/*
* --- Driver Structures
*/
@@ -3755,27 +3723,27 @@ typedef struct scsi_cmnd REQ, *REQP;
/* Per board statistics structure */
struct asc_stats {
- /* Driver Entrypoint Statistics */
- ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
- ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
- ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
- ADV_DCNT interrupt; /* # advansys_interrupt() calls */
- ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
- ADV_DCNT done; /* # calls to request's scsi_done function */
- ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
- ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
- ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
- /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
- ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
- ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
- ADV_DCNT exe_error; /* # ASC_ERROR returns. */
- ADV_DCNT exe_unknown; /* # unknown returns. */
- /* Data Transfer Statistics */
- ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
- ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
- ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
- ADV_DCNT sg_elem; /* # scatter-gather elements */
- ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
+ /* Driver Entrypoint Statistics */
+ ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
+ ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
+ ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
+ ADV_DCNT interrupt; /* # advansys_interrupt() calls */
+ ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
+ ADV_DCNT done; /* # calls to request's scsi_done function */
+ ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
+ ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
+ ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
+ /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
+ ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
+ ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
+ ADV_DCNT exe_error; /* # ASC_ERROR returns. */
+ ADV_DCNT exe_unknown; /* # unknown returns. */
+ /* Data Transfer Statistics */
+ ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
+ ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
+ ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
+ ADV_DCNT sg_elem; /* # scatter-gather elements */
+ ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
};
#endif /* ADVANSYS_STATS */
@@ -3783,17 +3751,17 @@ struct asc_stats {
* Request queuing structure
*/
typedef struct asc_queue {
- ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
- REQP q_first[ADV_MAX_TID+1]; /* first queued request */
- REQP q_last[ADV_MAX_TID+1]; /* last queued request */
+ ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
+ REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
+ REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
#ifdef ADVANSYS_STATS
- short q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */
- short q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */
- ADV_DCNT q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
- ADV_DCNT q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
- ushort q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */
- ushort q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */
-#endif /* ADVANSYS_STATS */
+ short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
+ short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
+ ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
+ ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
+ ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
+ ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
+#endif /* ADVANSYS_STATS */
} asc_queue_t;
/*
@@ -3814,17 +3782,17 @@ typedef struct asc_queue {
* Both structures must be 32 byte aligned.
*/
typedef struct adv_sgblk {
- ADV_SG_BLOCK sg_block; /* Sgblock structure. */
- uchar align[32]; /* Sgblock structure padding. */
- struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
+ ADV_SG_BLOCK sg_block; /* Sgblock structure. */
+ uchar align[32]; /* Sgblock structure padding. */
+ struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
} adv_sgblk_t;
typedef struct adv_req {
- ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
- uchar align[32]; /* Request structure padding. */
- struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
- adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
- struct adv_req *next_reqp; /* Next Request Structure. */
+ ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
+ uchar align[32]; /* Request structure padding. */
+ struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
+ adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
+ struct adv_req *next_reqp; /* Next Request Structure. */
} adv_req_t;
/*
@@ -3835,113 +3803,109 @@ typedef struct adv_req {
* field. It is guaranteed to be allocated from DMA-able memory.
*/
typedef struct asc_board {
- int id; /* Board Id */
- uint flags; /* Board flags */
- union {
- ASC_DVC_VAR asc_dvc_var; /* Narrow board */
- ADV_DVC_VAR adv_dvc_var; /* Wide board */
- } dvc_var;
- union {
- ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
- ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
- } dvc_cfg;
- ushort asc_n_io_port; /* Number I/O ports. */
- asc_queue_t active; /* Active command queue */
- asc_queue_t waiting; /* Waiting command queue */
- asc_queue_t done; /* Done command queue */
- ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
- struct scsi_device *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
- ushort reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
- ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
- ushort queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
- union {
- ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
- ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
- ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
- ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
- } eep_config;
- ulong last_reset; /* Saved last reset time */
- spinlock_t lock; /* Board spinlock */
+ int id; /* Board Id */
+ uint flags; /* Board flags */
+ union {
+ ASC_DVC_VAR asc_dvc_var; /* Narrow board */
+ ADV_DVC_VAR adv_dvc_var; /* Wide board */
+ } dvc_var;
+ union {
+ ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
+ ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
+ } dvc_cfg;
+ ushort asc_n_io_port; /* Number I/O ports. */
+ asc_queue_t active; /* Active command queue */
+ asc_queue_t waiting; /* Waiting command queue */
+ asc_queue_t done; /* Done command queue */
+ ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
+ struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
+ ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
+ ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
+ ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
+ union {
+ ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
+ ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
+ ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
+ ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
+ } eep_config;
+ ulong last_reset; /* Saved last reset time */
+ spinlock_t lock; /* Board spinlock */
#ifdef CONFIG_PROC_FS
- /* /proc/scsi/advansys/[0...] */
- char *prtbuf; /* /proc print buffer */
-#endif /* CONFIG_PROC_FS */
+ /* /proc/scsi/advansys/[0...] */
+ char *prtbuf; /* /proc print buffer */
+#endif /* CONFIG_PROC_FS */
#ifdef ADVANSYS_STATS
- struct asc_stats asc_stats; /* Board statistics */
-#endif /* ADVANSYS_STATS */
- /*
- * The following fields are used only for Narrow Boards.
- */
- /* The following three structures must be in DMA-able memory. */
- ASC_SCSI_REQ_Q scsireqq;
- ASC_CAP_INFO cap_info;
- ASC_SCSI_INQUIRY inquiry;
- uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */
- /*
- * The following fields are used only for Wide Boards.
- */
- void __iomem *ioremap_addr; /* I/O Memory remap address. */
- ushort ioport; /* I/O Port address. */
- ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
- adv_req_t *orig_reqp; /* adv_req_t memory block. */
- adv_req_t *adv_reqp; /* Request structures. */
- adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
- ushort bios_signature; /* BIOS Signature. */
- ushort bios_version; /* BIOS Version. */
- ushort bios_codeseg; /* BIOS Code Segment. */
- ushort bios_codelen; /* BIOS Code Segment Length. */
+ struct asc_stats asc_stats; /* Board statistics */
+#endif /* ADVANSYS_STATS */
+ /*
+ * The following fields are used only for Narrow Boards.
+ */
+ /* The following three structures must be in DMA-able memory. */
+ ASC_SCSI_REQ_Q scsireqq;
+ ASC_CAP_INFO cap_info;
+ ASC_SCSI_INQUIRY inquiry;
+ uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
+ /*
+ * The following fields are used only for Wide Boards.
+ */
+ void __iomem *ioremap_addr; /* I/O Memory remap address. */
+ ushort ioport; /* I/O Port address. */
+ ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
+ adv_req_t *orig_reqp; /* adv_req_t memory block. */
+ adv_req_t *adv_reqp; /* Request structures. */
+ adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
+ ushort bios_signature; /* BIOS Signature. */
+ ushort bios_version; /* BIOS Version. */
+ ushort bios_codeseg; /* BIOS Code Segment. */
+ ushort bios_codelen; /* BIOS Code Segment Length. */
} asc_board_t;
/*
* PCI configuration structures
*/
-typedef struct _PCI_DATA_
-{
- uchar type;
- uchar bus;
- uchar slot;
- uchar func;
- uchar offset;
+typedef struct _PCI_DATA_ {
+ uchar type;
+ uchar bus;
+ uchar slot;
+ uchar func;
+ uchar offset;
} PCI_DATA;
-typedef struct _PCI_DEVICE_
-{
- ushort vendorID;
- ushort deviceID;
- ushort slotNumber;
- ushort slotFound;
- uchar busNumber;
- uchar maxBusNumber;
- uchar devFunc;
- ushort startSlot;
- ushort endSlot;
- uchar bridge;
- uchar type;
+typedef struct _PCI_DEVICE_ {
+ ushort vendorID;
+ ushort deviceID;
+ ushort slotNumber;
+ ushort slotFound;
+ uchar busNumber;
+ uchar maxBusNumber;
+ uchar devFunc;
+ ushort startSlot;
+ ushort endSlot;
+ uchar bridge;
+ uchar type;
} PCI_DEVICE;
-typedef struct _PCI_CONFIG_SPACE_
-{
- ushort vendorID;
- ushort deviceID;
- ushort command;
- ushort status;
- uchar revision;
- uchar classCode[3];
- uchar cacheSize;
- uchar latencyTimer;
- uchar headerType;
- uchar bist;
- ADV_PADDR baseAddress[6];
- ushort reserved[4];
- ADV_PADDR optionRomAddr;
- ushort reserved2[4];
- uchar irqLine;
- uchar irqPin;
- uchar minGnt;
- uchar maxLatency;
+typedef struct _PCI_CONFIG_SPACE_ {
+ ushort vendorID;
+ ushort deviceID;
+ ushort command;
+ ushort status;
+ uchar revision;
+ uchar classCode[3];
+ uchar cacheSize;
+ uchar latencyTimer;
+ uchar headerType;
+ uchar bist;
+ ADV_PADDR baseAddress[6];
+ ushort reserved[4];
+ ADV_PADDR optionRomAddr;
+ ushort reserved2[4];
+ uchar irqLine;
+ uchar irqPin;
+ uchar minGnt;
+ uchar maxLatency;
} PCI_CONFIG_SPACE;
-
/*
* --- Driver Data
*/
@@ -3949,44 +3913,42 @@ typedef struct _PCI_CONFIG_SPACE_
/* Note: All driver global data should be initialized. */
/* Number of boards detected in system. */
-STATIC int asc_board_count = 0;
-STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
+static int asc_board_count = 0;
+static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
/* Overrun buffer used by all narrow boards. */
-STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
+static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
/*
* Global structures required to issue a command.
*/
-STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
-STATIC ASC_SG_HEAD asc_sg_head = { 0 };
+static ASC_SCSI_Q asc_scsi_q = { {0} };
+static ASC_SG_HEAD asc_sg_head = { 0 };
/* List of supported bus types. */
-STATIC ushort asc_bus[ASC_NUM_BUS] __initdata = {
- ASC_IS_ISA,
- ASC_IS_VL,
- ASC_IS_EISA,
- ASC_IS_PCI,
+static ushort asc_bus[ASC_NUM_BUS] __initdata = {
+ ASC_IS_ISA,
+ ASC_IS_VL,
+ ASC_IS_EISA,
+ ASC_IS_PCI,
};
-STATIC int asc_iopflag = ASC_FALSE;
-STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+static int asc_iopflag = ASC_FALSE;
+static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
#ifdef ADVANSYS_DEBUG
-STATIC char *
-asc_bus_name[ASC_NUM_BUS] = {
- "ASC_IS_ISA",
- "ASC_IS_VL",
- "ASC_IS_EISA",
- "ASC_IS_PCI",
+static char *asc_bus_name[ASC_NUM_BUS] = {
+ "ASC_IS_ISA",
+ "ASC_IS_VL",
+ "ASC_IS_EISA",
+ "ASC_IS_PCI",
};
-STATIC int asc_dbglvl = 3;
+static int asc_dbglvl = 3;
#endif /* ADVANSYS_DEBUG */
/* Declaration for Asc Library internal data referenced by driver. */
-STATIC PortAddr _asc_def_iop_base[];
-
+static PortAddr _asc_def_iop_base[];
/*
* --- Driver Function Prototypes
@@ -3994,62 +3956,61 @@ STATIC PortAddr _asc_def_iop_base[];
* advansys.h contains function prototypes for functions global to Linux.
*/
-STATIC irqreturn_t advansys_interrupt(int, void *);
-STATIC int advansys_slave_configure(struct scsi_device *);
-STATIC void asc_scsi_done_list(struct scsi_cmnd *);
-STATIC int asc_execute_scsi_cmnd(struct scsi_cmnd *);
-STATIC int asc_build_req(asc_board_t *, struct scsi_cmnd *);
-STATIC int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
-STATIC int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
-STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC void adv_async_callback(ADV_DVC_VAR *, uchar);
-STATIC void asc_enqueue(asc_queue_t *, REQP, int);
-STATIC REQP asc_dequeue(asc_queue_t *, int);
-STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
-STATIC int asc_rmqueue(asc_queue_t *, REQP);
-STATIC void asc_execute_queue(asc_queue_t *);
+static irqreturn_t advansys_interrupt(int, void *);
+static int advansys_slave_configure(struct scsi_device *);
+static void asc_scsi_done_list(struct scsi_cmnd *);
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
+static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
+static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
+static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
+static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
+static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+static void adv_async_callback(ADV_DVC_VAR *, uchar);
+static void asc_enqueue(asc_queue_t *, REQP, int);
+static REQP asc_dequeue(asc_queue_t *, int);
+static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
+static int asc_rmqueue(asc_queue_t *, REQP);
+static void asc_execute_queue(asc_queue_t *);
#ifdef CONFIG_PROC_FS
-STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int);
-STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
-STATIC int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
-STATIC int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_line(char *, int, char *fmt, ...);
+static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
+static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
+static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
+static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
+static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
+static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
+static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
+static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
+static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
+static int asc_prt_line(char *, int, char *fmt, ...);
#endif /* CONFIG_PROC_FS */
/* Declaration for Asc Library internal functions referenced by driver. */
-STATIC int AscFindSignature(PortAddr);
-STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscFindSignature(PortAddr);
+static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
/* Statistics function prototypes. */
#ifdef ADVANSYS_STATS
#ifdef CONFIG_PROC_FS
-STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
+static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
+static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
#endif /* CONFIG_PROC_FS */
#endif /* ADVANSYS_STATS */
/* Debug function prototypes. */
#ifdef ADVANSYS_DEBUG
-STATIC void asc_prt_scsi_host(struct Scsi_Host *);
-STATIC void asc_prt_scsi_cmnd(struct scsi_cmnd *);
-STATIC void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
-STATIC void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
-STATIC void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
-STATIC void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
-STATIC void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
-STATIC void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
-STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
-STATIC void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
-STATIC void asc_prt_hex(char *f, uchar *, int);
+static void asc_prt_scsi_host(struct Scsi_Host *);
+static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
+static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
+static void asc_prt_hex(char *f, uchar *, int);
#endif /* ADVANSYS_DEBUG */
-
#ifdef CONFIG_PROC_FS
/*
* advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
@@ -4073,1389 +4034,210 @@ STATIC void asc_prt_hex(char *f, uchar *, int);
*/
static int
advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
- off_t offset, int length, int inout)
+ off_t offset, int length, int inout)
{
- struct Scsi_Host *shp;
- asc_board_t *boardp;
- int i;
- char *cp;
- int cplen;
- int cnt;
- int totcnt;
- int leftlen;
- char *curbuf;
- off_t advoffset;
+ struct Scsi_Host *shp;
+ asc_board_t *boardp;
+ int i;
+ char *cp;
+ int cplen;
+ int cnt;
+ int totcnt;
+ int leftlen;
+ char *curbuf;
+ off_t advoffset;
#ifdef ADVANSYS_STATS
- int tgt_id;
+ int tgt_id;
#endif /* ADVANSYS_STATS */
- ASC_DBG(1, "advansys_proc_info: begin\n");
-
- /*
- * User write not supported.
- */
- if (inout == TRUE) {
- return(-ENOSYS);
- }
+ ASC_DBG(1, "advansys_proc_info: begin\n");
- /*
- * User read of /proc/scsi/advansys/[0...] file.
- */
-
- /* Find the specified board. */
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i]->host_no == shost->host_no) {
- break;
- }
- }
- if (i == asc_board_count) {
- return(-ENOENT);
- }
-
- shp = asc_host[i];
- boardp = ASC_BOARDP(shp);
-
- /* Copy read data starting at the beginning of the buffer. */
- *start = buffer;
- curbuf = buffer;
- advoffset = 0;
- totcnt = 0;
- leftlen = length;
-
- /*
- * Get board configuration information.
- *
- * advansys_info() returns the board string from its own static buffer.
- */
- cp = (char *) advansys_info(shp);
- strcat(cp, "\n");
- cplen = strlen(cp);
- /* Copy board information. */
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ /*
+ * User write not supported.
+ */
+ if (inout == TRUE) {
+ return (-ENOSYS);
+ }
- /*
- * Display Wide Board BIOS Information.
- */
- if (ASC_WIDE_BOARD(boardp)) {
- cp = boardp->prtbuf;
- cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
+ /*
+ * User read of /proc/scsi/advansys/[0...] file.
+ */
- /*
- * Display driver information for each device attached to the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ /* Find the specified board. */
+ for (i = 0; i < asc_board_count; i++) {
+ if (asc_host[i]->host_no == shost->host_no) {
+ break;
+ }
+ }
+ if (i == asc_board_count) {
+ return (-ENOENT);
+ }
- /*
- * Display EEPROM configuration for the board.
- */
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
- }
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ shp = asc_host[i];
+ boardp = ASC_BOARDP(shp);
+
+ /* Copy read data starting at the beginning of the buffer. */
+ *start = buffer;
+ curbuf = buffer;
+ advoffset = 0;
+ totcnt = 0;
+ leftlen = length;
+
+ /*
+ * Get board configuration information.
+ *
+ * advansys_info() returns the board string from its own static buffer.
+ */
+ cp = (char *)advansys_info(shp);
+ strcat(cp, "\n");
+ cplen = strlen(cp);
+ /* Copy board information. */
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display Wide Board BIOS Information.
+ */
+ if (ASC_WIDE_BOARD(boardp)) {
+ cp = boardp->prtbuf;
+ cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
+ ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+ cnt =
+ asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+ cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+ }
- /*
- * Display driver configuration and information for the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ /*
+ * Display driver information for each device attached to the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
+ ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display EEPROM configuration for the board.
+ */
+ cp = boardp->prtbuf;
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+ } else {
+ cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+ }
+ ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display driver configuration and information for the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+ ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
#ifdef ADVANSYS_STATS
- /*
- * Display driver statistics for the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display driver statistics for each target.
- */
- for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
- cp = boardp->prtbuf;
- cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
+ /*
+ * Display driver statistics for the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
+ ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display driver statistics for each target.
+ */
+ for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
+ cp = boardp->prtbuf;
+ cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
+ ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+ cnt =
+ asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+ cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+ }
#endif /* ADVANSYS_STATS */
- /*
- * Display Asc Library dynamic configuration information
- * for the board.
- */
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
- }
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-
- return totcnt;
-}
-#endif /* CONFIG_PROC_FS */
-
-/*
- * advansys_detect()
- *
- * Detect function for AdvanSys adapters.
- *
- * Argument is a pointer to the host driver's scsi_hosts entry.
- *
- * Return number of adapters found.
- *
- * Note: Because this function is called during system initialization
- * it must not call SCSI mid-level functions including scsi_malloc()
- * and scsi_free().
- */
-static int __init
-advansys_detect(struct scsi_host_template *tpnt)
-{
- static int detect_called = ASC_FALSE;
- int iop;
- int bus;
- struct Scsi_Host *shp = NULL;
- asc_board_t *boardp = NULL;
- ASC_DVC_VAR *asc_dvc_varp = NULL;
- ADV_DVC_VAR *adv_dvc_varp = NULL;
- adv_sgblk_t *sgp = NULL;
- int ioport = 0;
- int share_irq = FALSE;
- int iolen = 0;
- struct device *dev = NULL;
-#ifdef CONFIG_PCI
- int pci_init_search = 0;
- struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
- int pci_card_cnt_max = 0;
- int pci_card_cnt = 0;
- struct pci_dev *pci_devp = NULL;
- int pci_device_id_cnt = 0;
- unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
- PCI_DEVICE_ID_ASP_1200A,
- PCI_DEVICE_ID_ASP_ABP940,
- PCI_DEVICE_ID_ASP_ABP940U,
- PCI_DEVICE_ID_ASP_ABP940UW,
- PCI_DEVICE_ID_38C0800_REV1,
- PCI_DEVICE_ID_38C1600_REV1
- };
- ADV_PADDR pci_memory_address;
-#endif /* CONFIG_PCI */
- int warn_code, err_code;
- int ret;
-
- if (detect_called == ASC_FALSE) {
- detect_called = ASC_TRUE;
- } else {
- printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
- return 0;
- }
-
- ASC_DBG(1, "advansys_detect: begin\n");
-
- asc_board_count = 0;
-
- /*
- * If I/O port probing has been modified, then verify and
- * clean-up the 'asc_ioport' list.
- */
- if (asc_iopflag == ASC_TRUE) {
- for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
- ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
- ioport, asc_ioport[ioport]);
- if (asc_ioport[ioport] != 0) {
- for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
- if (_asc_def_iop_base[iop] == asc_ioport[ioport]) {
- break;
- }
- }
- if (iop == ASC_IOADR_TABLE_MAX_IX) {
- printk(
-"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
- asc_ioport[ioport]);
- asc_ioport[ioport] = 0;
- }
- }
- }
- ioport = 0;
- }
-
- for (bus = 0; bus < ASC_NUM_BUS; bus++) {
-
- ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
- bus, asc_bus_name[bus]);
- iop = 0;
-
- while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
-
- ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
- asc_board_count);
-
- switch (asc_bus[bus]) {
- case ASC_IS_ISA:
- case ASC_IS_VL:
-#ifdef CONFIG_ISA
- if (asc_iopflag == ASC_FALSE) {
- iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
- } else {
- /*
- * ISA and VL I/O port scanning has either been
- * eliminated or limited to selected ports on
- * the LILO command line, /etc/lilo.conf, or
- * by setting variables when the module was loaded.
- */
- ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
- ioport_try_again:
- iop = 0;
- for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
- if ((iop = asc_ioport[ioport]) != 0) {
- break;
- }
- }
- if (iop) {
- ASC_DBG1(1,
- "advansys_detect: probing I/O port 0x%x...\n",
- iop);
- if (!request_region(iop, ASC_IOADR_GAP, "advansys")){
- printk(
-"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
- /* Don't try this I/O port twice. */
- asc_ioport[ioport] = 0;
- goto ioport_try_again;
- } else if (AscFindSignature(iop) == ASC_FALSE) {
- printk(
-"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
- /* Don't try this I/O port twice. */
- release_region(iop, ASC_IOADR_GAP);
- asc_ioport[ioport] = 0;
- goto ioport_try_again;
- } else {
- /*
- * If this isn't an ISA board, then it must be
- * a VL board. If currently looking an ISA
- * board is being looked for then try for
- * another ISA board in 'asc_ioport'.
- */
- if (asc_bus[bus] == ASC_IS_ISA &&
- (AscGetChipVersion(iop, ASC_IS_ISA) &
- ASC_CHIP_VER_ISA_BIT) == 0) {
- /*
- * Don't clear 'asc_ioport[ioport]'. Try
- * this board again for VL. Increment
- * 'ioport' past this board.
- */
- ioport++;
- release_region(iop, ASC_IOADR_GAP);
- goto ioport_try_again;
- }
- }
- /*
- * This board appears good, don't try the I/O port
- * again by clearing its value. Increment 'ioport'
- * for the next iteration.
- */
- asc_ioport[ioport++] = 0;
- }
- }
-#endif /* CONFIG_ISA */
- break;
-
- case ASC_IS_EISA:
-#ifdef CONFIG_ISA
- iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-#endif /* CONFIG_ISA */
- break;
-
- case ASC_IS_PCI:
-#ifdef CONFIG_PCI
- if (pci_init_search == 0) {
- int i, j;
-
- pci_init_search = 1;
-
- /* Find all PCI cards. */
- while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
- if ((pci_devp = pci_find_device(PCI_VENDOR_ID_ASP,
- pci_device_id[pci_device_id_cnt], pci_devp)) ==
- NULL) {
- pci_device_id_cnt++;
- } else {
- if (pci_enable_device(pci_devp) == 0) {
- pci_devicep[pci_card_cnt_max++] = pci_devp;
- }
- }
- }
-
- /*
- * Sort PCI cards in ascending order by PCI Bus, Slot,
- * and Device Number.
- */
- for (i = 0; i < pci_card_cnt_max - 1; i++)
- {
- for (j = i + 1; j < pci_card_cnt_max; j++) {
- if ((pci_devicep[j]->bus->number <
- pci_devicep[i]->bus->number) ||
- ((pci_devicep[j]->bus->number ==
- pci_devicep[i]->bus->number) &&
- (pci_devicep[j]->devfn <
- pci_devicep[i]->devfn))) {
- pci_devp = pci_devicep[i];
- pci_devicep[i] = pci_devicep[j];
- pci_devicep[j] = pci_devp;
- }
- }
- }
-
- pci_card_cnt = 0;
- } else {
- pci_card_cnt++;
- }
-
- if (pci_card_cnt == pci_card_cnt_max) {
- iop = 0;
- } else {
- pci_devp = pci_devicep[pci_card_cnt];
-
- ASC_DBG2(2,
- "advansys_detect: devfn %d, bus number %d\n",
- pci_devp->devfn, pci_devp->bus->number);
- iop = pci_resource_start(pci_devp, 0);
- ASC_DBG2(1,
- "advansys_detect: vendorID %X, deviceID %X\n",
- pci_devp->vendor, pci_devp->device);
- ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
- iop, pci_devp->irq);
- }
- if(pci_devp)
- dev = &pci_devp->dev;
-
-#endif /* CONFIG_PCI */
- break;
-
- default:
- ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
- asc_bus[bus]);
- break;
- }
- ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
-
- /*
- * Adapter not found, try next bus type.
- */
- if (iop == 0) {
- break;
- }
-
- /*
- * Adapter found.
- *
- * Register the adapter, get its configuration, and
- * initialize it.
- */
- ASC_DBG(2, "advansys_detect: scsi_register()\n");
- shp = scsi_register(tpnt, sizeof(asc_board_t));
-
- if (shp == NULL) {
- continue;
- }
-
- /* Save a pointer to the Scsi_Host of each board found. */
- asc_host[asc_board_count++] = shp;
-
- /* Initialize private per board data */
- boardp = ASC_BOARDP(shp);
- memset(boardp, 0, sizeof(asc_board_t));
- boardp->id = asc_board_count - 1;
-
- /* Initialize spinlock. */
- spin_lock_init(&boardp->lock);
-
- /*
- * Handle both narrow and wide boards.
- *
- * If a Wide board was detected, set the board structure
- * wide board flag. Set-up the board structure based on
- * the board type.
- */
-#ifdef CONFIG_PCI
- if (asc_bus[bus] == ASC_IS_PCI &&
- (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW ||
- pci_devp->device == PCI_DEVICE_ID_38C0800_REV1 ||
- pci_devp->device == PCI_DEVICE_ID_38C1600_REV1))
- {
- boardp->flags |= ASC_IS_WIDE_BOARD;
- }
-#endif /* CONFIG_PCI */
-
- if (ASC_NARROW_BOARD(boardp)) {
- ASC_DBG(1, "advansys_detect: narrow board\n");
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- asc_dvc_varp->bus_type = asc_bus[bus];
- asc_dvc_varp->drv_ptr = boardp;
- asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
- asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
- asc_dvc_varp->iop_base = iop;
- asc_dvc_varp->isr_callback = asc_isr_callback;
- } else {
- ASC_DBG(1, "advansys_detect: wide board\n");
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- adv_dvc_varp->drv_ptr = boardp;
- adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
- adv_dvc_varp->isr_callback = adv_isr_callback;
- adv_dvc_varp->async_callback = adv_async_callback;
-#ifdef CONFIG_PCI
- if (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW)
- {
- ASC_DBG(1, "advansys_detect: ASC-3550\n");
- adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
- } else if (pci_devp->device == PCI_DEVICE_ID_38C0800_REV1)
- {
- ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
- adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
- } else
- {
- ASC_DBG(1, "advansys_detect: ASC-38C1600\n");
- adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
- }
-#endif /* CONFIG_PCI */
-
- /*
- * Map the board's registers into virtual memory for
- * PCI slave access. Only memory accesses are used to
- * access the board's registers.
- *
- * Note: The PCI register base address is not always
- * page aligned, but the address passed to ioremap()
- * must be page aligned. It is guaranteed that the
- * PCI register base address will not cross a page
- * boundary.
- */
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- iolen = ADV_3550_IOLEN;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- iolen = ADV_38C0800_IOLEN;
- } else
- {
- iolen = ADV_38C1600_IOLEN;
- }
-#ifdef CONFIG_PCI
- pci_memory_address = pci_resource_start(pci_devp, 1);
- ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n",
- (ulong) pci_memory_address);
- if ((boardp->ioremap_addr =
- ioremap(pci_memory_address & PAGE_MASK,
- PAGE_SIZE)) == 0) {
- ASC_PRINT3(
-"advansys_detect: board %d: ioremap(%x, %d) returned NULL\n",
- boardp->id, pci_memory_address, iolen);
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
- ASC_DBG1(1, "advansys_detect: ioremap_addr: 0x%lx\n",
- (ulong) boardp->ioremap_addr);
- adv_dvc_varp->iop_base = (AdvPortAddr)
- (boardp->ioremap_addr +
- (pci_memory_address - (pci_memory_address & PAGE_MASK)));
- ASC_DBG1(1, "advansys_detect: iop_base: 0x%lx\n",
- adv_dvc_varp->iop_base);
-#endif /* CONFIG_PCI */
-
- /*
- * Even though it isn't used to access wide boards, other
- * than for the debug line below, save I/O Port address so
- * that it can be reported.
- */
- boardp->ioport = iop;
-
- ASC_DBG2(1,
-"advansys_detect: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
- (ushort) inp(iop + 1), (ushort) inpw(iop));
- }
-
-#ifdef CONFIG_PROC_FS
- /*
- * Allocate buffer for printing information from
- * /proc/scsi/advansys/[0...].
- */
- if ((boardp->prtbuf =
- kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
- ASC_PRINT3(
-"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
- boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
-#endif /* CONFIG_PROC_FS */
-
- if (ASC_NARROW_BOARD(boardp)) {
- asc_dvc_varp->cfg->dev = dev;
- /*
- * Set the board bus type and PCI IRQ before
- * calling AscInitGetConfig().
- */
- switch (asc_dvc_varp->bus_type) {
-#ifdef CONFIG_ISA
- case ASC_IS_ISA:
- shp->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
- break;
- case ASC_IS_VL:
- shp->unchecked_isa_dma = FALSE;
- share_irq = FALSE;
- break;
- case ASC_IS_EISA:
- shp->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
- break;
-#endif /* CONFIG_ISA */
-#ifdef CONFIG_PCI
- case ASC_IS_PCI:
- shp->irq = asc_dvc_varp->irq_no = pci_devp->irq;
- asc_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pci_devp->bus->number,
- PCI_SLOT(pci_devp->devfn),
- PCI_FUNC(pci_devp->devfn));
- shp->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
- break;
-#endif /* CONFIG_PCI */
- default:
- ASC_PRINT2(
-"advansys_detect: board %d: unknown adapter type: %d\n",
- boardp->id, asc_dvc_varp->bus_type);
- shp->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
- break;
- }
- } else {
- adv_dvc_varp->cfg->dev = dev;
- /*
- * For Wide boards set PCI information before calling
- * AdvInitGetConfig().
- */
-#ifdef CONFIG_PCI
- shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
- adv_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pci_devp->bus->number,
- PCI_SLOT(pci_devp->devfn),
- PCI_FUNC(pci_devp->devfn));
- shp->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
-#endif /* CONFIG_PCI */
- }
-
- /*
- * Read the board configuration.
- */
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * NOTE: AscInitGetConfig() may change the board's
- * bus_type value. The asc_bus[bus] value should no
- * longer be used. If the bus_type field must be
- * referenced only use the bit-wise AND operator "&".
- */
- ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
- switch(ret = AscInitGetConfig(asc_dvc_varp)) {
- case 0: /* No error */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1(
-"AscInitGetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1(
-"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1(
-"AscInitGetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1(
-"AscInitGetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1(
-"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2(
-"AscInitGetConfig: board %d: unknown warning: 0x%x\n",
- boardp->id, ret);
- break;
- }
- if ((err_code = asc_dvc_varp->err_code) != 0) {
- ASC_PRINT3(
-"AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->init_state,
- asc_dvc_varp->err_code);
- }
- } else {
- ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n");
- if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
- ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
- boardp->id, ret);
- }
- if ((err_code = adv_dvc_varp->err_code) != 0) {
- ASC_PRINT2(
-"AdvInitGetConfig: board %d error: err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- }
- }
-
- if (err_code != 0) {
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
-
- /*
- * Save the EEPROM configuration so that it can be displayed
- * from /proc/scsi/advansys/[0...].
- */
- if (ASC_NARROW_BOARD(boardp)) {
-
- ASCEEP_CONFIG *ep;
-
- /*
- * Set the adapter's target id bit in the 'init_tidmask' field.
- */
- boardp->init_tidmask |=
- ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
-
- /*
- * Save EEPROM settings for the board.
- */
- ep = &boardp->eep_config.asc_eep;
-
- ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
- ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
- ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
- ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
- ep->start_motor = asc_dvc_varp->start_motor;
- ep->cntl = asc_dvc_varp->dvc_cntl;
- ep->no_scam = asc_dvc_varp->no_scam;
- ep->max_total_qng = asc_dvc_varp->max_total_qng;
- ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
- /* 'max_tag_qng' is set to the same value for every device. */
- ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
- ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
- ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
- ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
- ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
- ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
- ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
-
- /*
- * Modify board configuration.
- */
- ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
- switch (ret = AscInitSetConfig(asc_dvc_varp)) {
- case 0: /* No error. */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1(
-"AscInitSetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1(
-"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1(
-"AscInitSetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1(
-"AscInitSetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1(
-"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2(
-"AscInitSetConfig: board %d: unknown warning: 0x%x\n",
- boardp->id, ret);
- break;
- }
- if (asc_dvc_varp->err_code != 0) {
- ASC_PRINT3(
-"AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->init_state,
- asc_dvc_varp->err_code);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
-
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
- /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
- shp->irq = asc_dvc_varp->irq_no;
- }
- } else {
- ADVEEP_3550_CONFIG *ep_3550;
- ADVEEP_38C0800_CONFIG *ep_38C0800;
- ADVEEP_38C1600_CONFIG *ep_38C1600;
-
- /*
- * Save Wide EEP Configuration Information.
- */
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- ep_3550 = &boardp->eep_config.adv_3550_eep;
-
- ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
- ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
- ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
- ep_3550->termination = adv_dvc_varp->cfg->termination;
- ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
- ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
- ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
- ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
- ep_3550->ultra_able = adv_dvc_varp->ultra_able;
- ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
- ep_3550->start_motor = adv_dvc_varp->start_motor;
- ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
- ep_3550->serial_number_word1 =
- adv_dvc_varp->cfg->serial1;
- ep_3550->serial_number_word2 =
- adv_dvc_varp->cfg->serial2;
- ep_3550->serial_number_word3 =
- adv_dvc_varp->cfg->serial3;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
-
- ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
- ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
- ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
- ep_38C0800->termination_lvd =
- adv_dvc_varp->cfg->termination;
- ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable;
- ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
- ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
- ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
- ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
- ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
- ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
- ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
- ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
- ep_38C0800->start_motor = adv_dvc_varp->start_motor;
- ep_38C0800->scsi_reset_delay =
- adv_dvc_varp->scsi_reset_wait;
- ep_38C0800->serial_number_word1 =
- adv_dvc_varp->cfg->serial1;
- ep_38C0800->serial_number_word2 =
- adv_dvc_varp->cfg->serial2;
- ep_38C0800->serial_number_word3 =
- adv_dvc_varp->cfg->serial3;
- } else
- {
- ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
-
- ep_38C1600->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
- ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
- ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
- ep_38C1600->termination_lvd =
- adv_dvc_varp->cfg->termination;
- ep_38C1600->disc_enable = adv_dvc_varp->cfg->disc_enable;
- ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
- ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
- ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
- ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
- ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
- ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
- ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
- ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
- ep_38C1600->start_motor = adv_dvc_varp->start_motor;
- ep_38C1600->scsi_reset_delay =
- adv_dvc_varp->scsi_reset_wait;
- ep_38C1600->serial_number_word1 =
- adv_dvc_varp->cfg->serial1;
- ep_38C1600->serial_number_word2 =
- adv_dvc_varp->cfg->serial2;
- ep_38C1600->serial_number_word3 =
- adv_dvc_varp->cfg->serial3;
- }
-
- /*
- * Set the adapter's target id bit in the 'init_tidmask' field.
- */
- boardp->init_tidmask |=
- ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
-
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
- shp->irq = adv_dvc_varp->irq_no;
- }
-
- /*
- * Channels are numbered beginning with 0. For AdvanSys one host
- * structure supports one channel. Multi-channel boards have a
- * separate host structure for each channel.
- */
- shp->max_channel = 0;
- if (ASC_NARROW_BOARD(boardp)) {
- shp->max_id = ASC_MAX_TID + 1;
- shp->max_lun = ASC_MAX_LUN + 1;
-
- shp->io_port = asc_dvc_varp->iop_base;
- boardp->asc_n_io_port = ASC_IOADR_GAP;
- shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
-
- /* Set maximum number of queues the adapter can handle. */
- shp->can_queue = asc_dvc_varp->max_total_qng;
- } else {
- shp->max_id = ADV_MAX_TID + 1;
- shp->max_lun = ADV_MAX_LUN + 1;
-
- /*
- * Save the I/O Port address and length even though
- * I/O ports are not used to access Wide boards.
- * Instead the Wide boards are accessed with
- * PCI Memory Mapped I/O.
- */
- shp->io_port = iop;
- boardp->asc_n_io_port = iolen;
-
- shp->this_id = adv_dvc_varp->chip_scsi_id;
-
- /* Set maximum number of queues the adapter can handle. */
- shp->can_queue = adv_dvc_varp->max_host_qng;
- }
-
- /*
- * 'n_io_port' currently is one byte.
- *
- * Set a value to 'n_io_port', but never referenced it because
- * it may be truncated.
- */
- shp->n_io_port = boardp->asc_n_io_port <= 255 ?
- boardp->asc_n_io_port : 255;
-
- /*
- * Following v1.3.89, 'cmd_per_lun' is no longer needed
- * and should be set to zero.
- *
- * But because of a bug introduced in v1.3.89 if the driver is
- * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
- * SCSI function 'allocate_device' will panic. To allow the driver
- * to work as a module in these kernels set 'cmd_per_lun' to 1.
- *
- * Note: This is wrong. cmd_per_lun should be set to the depth
- * you want on untagged devices always.
-#ifdef MODULE
- */
- shp->cmd_per_lun = 1;
-/* #else
- shp->cmd_per_lun = 0;
-#endif */
-
- /*
- * Set the maximum number of scatter-gather elements the
- * adapter can handle.
- */
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Allow two commands with 'sg_tablesize' scatter-gather
- * elements to be executed simultaneously. This value is
- * the theoretical hardware limit. It may be decreased
- * below.
- */
- shp->sg_tablesize =
- (((asc_dvc_varp->max_total_qng - 2) / 2) *
- ASC_SG_LIST_PER_Q) + 1;
- } else {
- shp->sg_tablesize = ADV_MAX_SG_LIST;
- }
-
- /*
- * The value of 'sg_tablesize' can not exceed the SCSI
- * mid-level driver definition of SG_ALL. SG_ALL also
- * must not be exceeded, because it is used to define the
- * size of the scatter-gather table in 'struct asc_sg_head'.
- */
- if (shp->sg_tablesize > SG_ALL) {
- shp->sg_tablesize = SG_ALL;
- }
-
- ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
- shp->sg_tablesize);
-
- /* BIOS start address. */
- if (ASC_NARROW_BOARD(boardp)) {
- shp->base =
- ((ulong) AscGetChipBiosAddress(
- asc_dvc_varp->iop_base,
- asc_dvc_varp->bus_type));
- } else {
- /*
- * Fill-in BIOS board variables. The Wide BIOS saves
- * information in LRAM that is used by the driver.
- */
- AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE,
- boardp->bios_signature);
- AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION,
- boardp->bios_version);
- AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG,
- boardp->bios_codeseg);
- AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN,
- boardp->bios_codelen);
-
- ASC_DBG2(1,
- "advansys_detect: bios_signature 0x%x, bios_version 0x%x\n",
- boardp->bios_signature, boardp->bios_version);
-
- ASC_DBG2(1,
- "advansys_detect: bios_codeseg 0x%x, bios_codelen 0x%x\n",
- boardp->bios_codeseg, boardp->bios_codelen);
-
- /*
- * If the BIOS saved a valid signature, then fill in
- * the BIOS code segment base address.
- */
- if (boardp->bios_signature == 0x55AA) {
- /*
- * Convert x86 realmode code segment to a linear
- * address by shifting left 4.
- */
- shp->base = ((ulong) boardp->bios_codeseg << 4);
- } else {
- shp->base = 0;
- }
- }
-
- /*
- * Register Board Resources - I/O Port, DMA, IRQ
- */
-
- /*
- * Register I/O port range.
- *
- * For Wide boards the I/O ports are not used to access
- * the board, but request the region anyway.
- *
- * 'shp->n_io_port' is not referenced, because it may be truncated.
- */
- ASC_DBG2(2,
- "advansys_detect: request_region port 0x%lx, len 0x%x\n",
- (ulong) shp->io_port, boardp->asc_n_io_port);
- if (request_region(shp->io_port, boardp->asc_n_io_port,
- "advansys") == NULL) {
- ASC_PRINT3(
-"advansys_detect: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
- boardp->id, (ulong) shp->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
-
- /* Register DMA Channel for Narrow boards. */
- shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
-#ifdef CONFIG_ISA
- if (ASC_NARROW_BOARD(boardp)) {
- /* Register DMA channel for ISA bus. */
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
- if ((ret =
- request_dma(shp->dma_channel, "advansys")) != 0) {
- ASC_PRINT3(
-"advansys_detect: board %d: request_dma() %d failed %d\n",
- boardp->id, shp->dma_channel, ret);
- release_region(shp->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
- AscEnableIsaDma(shp->dma_channel);
- }
- }
-#endif /* CONFIG_ISA */
+ /*
+ * Display Asc Library dynamic configuration information
+ * for the board.
+ */
+ cp = boardp->prtbuf;
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
+ } else {
+ cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
+ }
+ ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
- /* Register IRQ Number. */
- ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
- /*
- * If request_irq() fails with the IRQF_DISABLED flag set,
- * then try again without the IRQF_DISABLED flag set. This
- * allows IRQ sharing to work even with other drivers that
- * do not set the IRQF_DISABLED flag.
- *
- * If IRQF_DISABLED is not set, then interrupts are enabled
- * before the driver interrupt function is called.
- */
- if (((ret = request_irq(shp->irq, advansys_interrupt,
- IRQF_DISABLED | (share_irq == TRUE ? IRQF_SHARED : 0),
- "advansys", boardp)) != 0) &&
- ((ret = request_irq(shp->irq, advansys_interrupt,
- (share_irq == TRUE ? IRQF_SHARED : 0),
- "advansys", boardp)) != 0))
- {
- if (ret == -EBUSY) {
- ASC_PRINT2(
-"advansys_detect: board %d: request_irq(): IRQ 0x%x already in use.\n",
- boardp->id, shp->irq);
- } else if (ret == -EINVAL) {
- ASC_PRINT2(
-"advansys_detect: board %d: request_irq(): IRQ 0x%x not valid.\n",
- boardp->id, shp->irq);
- } else {
- ASC_PRINT3(
-"advansys_detect: board %d: request_irq(): IRQ 0x%x failed with %d\n",
- boardp->id, shp->irq, ret);
- }
- release_region(shp->io_port, boardp->asc_n_io_port);
- iounmap(boardp->ioremap_addr);
- if (shp->dma_channel != NO_ISA_DMA) {
- free_dma(shp->dma_channel);
- }
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
-
- /*
- * Initialize board RISC chip and enable interrupts.
- */
- if (ASC_NARROW_BOARD(boardp)) {
- ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
- warn_code = AscInitAsc1000Driver(asc_dvc_varp);
- err_code = asc_dvc_varp->err_code;
-
- if (warn_code || err_code) {
- ASC_PRINT4(
-"advansys_detect: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
- boardp->id, asc_dvc_varp->init_state,
- warn_code, err_code);
- }
- } else {
- ADV_CARR_T *carrp;
- int req_cnt = 0;
- adv_req_t *reqp = NULL;
- int sg_cnt = 0;
-
- /*
- * Allocate buffer carrier structures. The total size
- * is about 4 KB, so allocate all at once.
- */
- carrp =
- (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
- ASC_DBG1(1, "advansys_detect: carrp 0x%lx\n", (ulong) carrp);
-
- if (carrp == NULL) {
- goto kmalloc_error;
- }
-
- /*
- * Allocate up to 'max_host_qng' request structures for
- * the Wide board. The total size is about 16 KB, so
- * allocate all at once. If the allocation fails decrement
- * and try again.
- */
- for (req_cnt = adv_dvc_varp->max_host_qng;
- req_cnt > 0; req_cnt--) {
-
- reqp = (adv_req_t *)
- kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
-
- ASC_DBG3(1,
- "advansys_detect: reqp 0x%lx, req_cnt %d, bytes %lu\n",
- (ulong) reqp, req_cnt,
- (ulong) sizeof(adv_req_t) * req_cnt);
-
- if (reqp != NULL) {
- break;
- }
- }
- if (reqp == NULL)
- {
- goto kmalloc_error;
- }
-
- /*
- * Allocate up to ADV_TOT_SG_BLOCK request structures for
- * the Wide board. Each structure is about 136 bytes.
- */
- boardp->adv_sgblkp = NULL;
- for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
-
- sgp = (adv_sgblk_t *)
- kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
-
- if (sgp == NULL) {
- break;
- }
-
- sgp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgp;
-
- }
- ASC_DBG3(1,
- "advansys_detect: sg_cnt %d * %u = %u bytes\n",
- sg_cnt, sizeof(adv_sgblk_t),
- (unsigned) (sizeof(adv_sgblk_t) * sg_cnt));
-
- /*
- * If no request structures or scatter-gather structures could
- * be allocated, then return an error. Otherwise continue with
- * initialization.
- */
- kmalloc_error:
- if (carrp == NULL)
- {
- ASC_PRINT1(
-"advansys_detect: board %d error: failed to kmalloc() carrier buffer.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else if (reqp == NULL) {
- kfree(carrp);
- ASC_PRINT1(
-"advansys_detect: board %d error: failed to kmalloc() adv_req_t buffer.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else if (boardp->adv_sgblkp == NULL) {
- kfree(carrp);
- kfree(reqp);
- ASC_PRINT1(
-"advansys_detect: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else {
-
- /* Save carrier buffer pointer. */
- boardp->orig_carrp = carrp;
-
- /*
- * Save original pointer for kfree() in case the
- * driver is built as a module and can be unloaded.
- */
- boardp->orig_reqp = reqp;
-
- adv_dvc_varp->carrier_buf = carrp;
-
- /*
- * Point 'adv_reqp' to the request structures and
- * link them together.
- */
- req_cnt--;
- reqp[req_cnt].next_reqp = NULL;
- for (; req_cnt > 0; req_cnt--) {
- reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
- }
- boardp->adv_reqp = &reqp[0];
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- ASC_DBG(2,
- "advansys_detect: AdvInitAsc3550Driver()\n");
- warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- ASC_DBG(2,
- "advansys_detect: AdvInitAsc38C0800Driver()\n");
- warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
- } else {
- ASC_DBG(2,
- "advansys_detect: AdvInitAsc38C1600Driver()\n");
- warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
- }
- err_code = adv_dvc_varp->err_code;
-
- if (warn_code || err_code) {
- ASC_PRINT3(
-"advansys_detect: board %d error: warn 0x%x, error 0x%x\n",
- boardp->id, warn_code, err_code);
- }
- }
- }
-
- if (err_code != 0) {
- release_region(shp->io_port, boardp->asc_n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
- iounmap(boardp->ioremap_addr);
- kfree(boardp->orig_carrp);
- boardp->orig_carrp = NULL;
- if (boardp->orig_reqp) {
- kfree(boardp->orig_reqp);
- boardp->orig_reqp = boardp->adv_reqp = NULL;
- }
- while ((sgp = boardp->adv_sgblkp) != NULL)
- {
- boardp->adv_sgblkp = sgp->next_sgblkp;
- kfree(sgp);
- }
- }
- if (shp->dma_channel != NO_ISA_DMA) {
- free_dma(shp->dma_channel);
- }
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- free_irq(shp->irq, boardp);
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
- ASC_DBG_PRT_SCSI_HOST(2, shp);
- }
- }
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
- return asc_board_count;
+ return totcnt;
}
-
-/*
- * advansys_release()
- *
- * Release resources allocated for a single AdvanSys adapter.
- */
-static int
-advansys_release(struct Scsi_Host *shp)
-{
- asc_board_t *boardp;
-
- ASC_DBG(1, "advansys_release: begin\n");
- boardp = ASC_BOARDP(shp);
- free_irq(shp->irq, boardp);
- if (shp->dma_channel != NO_ISA_DMA) {
- ASC_DBG(1, "advansys_release: free_dma()\n");
- free_dma(shp->dma_channel);
- }
- release_region(shp->io_port, boardp->asc_n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
- adv_sgblk_t *sgp = NULL;
-
- iounmap(boardp->ioremap_addr);
- kfree(boardp->orig_carrp);
- boardp->orig_carrp = NULL;
- if (boardp->orig_reqp) {
- kfree(boardp->orig_reqp);
- boardp->orig_reqp = boardp->adv_reqp = NULL;
- }
- while ((sgp = boardp->adv_sgblkp) != NULL)
- {
- boardp->adv_sgblkp = sgp->next_sgblkp;
- kfree(sgp);
- }
- }
-#ifdef CONFIG_PROC_FS
- ASC_ASSERT(boardp->prtbuf != NULL);
- kfree(boardp->prtbuf);
#endif /* CONFIG_PROC_FS */
- scsi_unregister(shp);
- ASC_DBG(1, "advansys_release: end\n");
- return 0;
-}
/*
* advansys_info()
@@ -5466,91 +4248,87 @@ advansys_release(struct Scsi_Host *shp)
* Note: The information line should not exceed ASC_INFO_SIZE bytes,
* otherwise the static 'info' array will be overrun.
*/
-static const char *
-advansys_info(struct Scsi_Host *shp)
+static const char *advansys_info(struct Scsi_Host *shost)
{
- static char info[ASC_INFO_SIZE];
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- char *busname;
- int iolen;
- char *widename = NULL;
-
- boardp = ASC_BOARDP(shp);
- if (ASC_NARROW_BOARD(boardp)) {
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- ASC_DBG(1, "advansys_info: begin\n");
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
- busname = "ISA PnP";
- } else {
- busname = "ISA";
- }
- /* Don't reference 'shp->n_io_port'; It may be truncated. */
- sprintf(info,
-"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
- ASC_VERSION, busname,
- (ulong) shp->io_port,
- (ulong) shp->io_port + boardp->asc_n_io_port - 1,
- shp->irq, shp->dma_channel);
- } else {
- if (asc_dvc_varp->bus_type & ASC_IS_VL) {
- busname = "VL";
- } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
- busname = "EISA";
- } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
- == ASC_IS_PCI_ULTRA) {
- busname = "PCI Ultra";
- } else {
- busname = "PCI";
- }
- } else {
- busname = "?";
- ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n",
- boardp->id, asc_dvc_varp->bus_type);
- }
- /* Don't reference 'shp->n_io_port'; It may be truncated. */
- sprintf(info,
- "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
- ASC_VERSION, busname,
- (ulong) shp->io_port,
- (ulong) shp->io_port + boardp->asc_n_io_port - 1,
- shp->irq);
- }
- } else {
- /*
- * Wide Adapter Information
- *
- * Memory-mapped I/O is used instead of I/O space to access
- * the adapter, but display the I/O Port range. The Memory
- * I/O address is displayed through the driver /proc file.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- iolen = ADV_3550_IOLEN;
- widename = "Ultra-Wide";
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- iolen = ADV_38C0800_IOLEN;
- widename = "Ultra2-Wide";
- } else
- {
- iolen = ADV_38C1600_IOLEN;
- widename = "Ultra3-Wide";
- }
- sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
- ASC_VERSION,
- widename,
- (ulong) adv_dvc_varp->iop_base,
- (ulong) adv_dvc_varp->iop_base + iolen - 1,
- shp->irq);
- }
- ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
- ASC_DBG(1, "advansys_info: end\n");
- return info;
+ static char info[ASC_INFO_SIZE];
+ asc_board_t *boardp;
+ ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ char *busname;
+ int iolen;
+ char *widename = NULL;
+
+ boardp = ASC_BOARDP(shost);
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ ASC_DBG(1, "advansys_info: begin\n");
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
+ ASC_IS_ISAPNP) {
+ busname = "ISA PnP";
+ } else {
+ busname = "ISA";
+ }
+ /* Don't reference 'shost->n_io_port'; It may be truncated. */
+ sprintf(info,
+ "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+ ASC_VERSION, busname,
+ (ulong)shost->io_port,
+ (ulong)shost->io_port + boardp->asc_n_io_port -
+ 1, shost->irq, shost->dma_channel);
+ } else {
+ if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+ busname = "VL";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+ busname = "EISA";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+ == ASC_IS_PCI_ULTRA) {
+ busname = "PCI Ultra";
+ } else {
+ busname = "PCI";
+ }
+ } else {
+ busname = "?";
+ ASC_PRINT2
+ ("advansys_info: board %d: unknown bus type %d\n",
+ boardp->id, asc_dvc_varp->bus_type);
+ }
+ /* Don't reference 'shost->n_io_port'; It may be truncated. */
+ sprintf(info,
+ "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+ ASC_VERSION, busname,
+ (ulong)shost->io_port,
+ (ulong)shost->io_port + boardp->asc_n_io_port -
+ 1, shost->irq);
+ }
+ } else {
+ /*
+ * Wide Adapter Information
+ *
+ * Memory-mapped I/O is used instead of I/O space to access
+ * the adapter, but display the I/O Port range. The Memory
+ * I/O address is displayed through the driver /proc file.
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ iolen = ADV_3550_IOLEN;
+ widename = "Ultra-Wide";
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ iolen = ADV_38C0800_IOLEN;
+ widename = "Ultra2-Wide";
+ } else {
+ iolen = ADV_38C1600_IOLEN;
+ widename = "Ultra3-Wide";
+ }
+ sprintf(info,
+ "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+ ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
+ (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
+ }
+ ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
+ ASC_DBG(1, "advansys_info: end\n");
+ return info;
}
/*
@@ -5560,82 +4338,82 @@ advansys_info(struct Scsi_Host *shp)
* in the 'scp' result field.
*/
static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
{
- struct Scsi_Host *shp;
- asc_board_t *boardp;
- ulong flags;
- struct scsi_cmnd *done_scp;
+ struct Scsi_Host *shost;
+ asc_board_t *boardp;
+ ulong flags;
+ struct scsi_cmnd *done_scp;
- shp = scp->device->host;
- boardp = ASC_BOARDP(shp);
- ASC_STATS(shp, queuecommand);
+ shost = scp->device->host;
+ boardp = ASC_BOARDP(shost);
+ ASC_STATS(shost, queuecommand);
- /* host_lock taken by mid-level prior to call but need to protect */
- /* against own ISR */
- spin_lock_irqsave(&boardp->lock, flags);
+ /* host_lock taken by mid-level prior to call but need to protect */
+ /* against own ISR */
+ spin_lock_irqsave(&boardp->lock, flags);
- /*
- * Block new commands while handling a reset or abort request.
- */
- if (boardp->flags & ASC_HOST_IN_RESET) {
- ASC_DBG1(1,
- "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
- (ulong) scp);
- scp->result = HOST_BYTE(DID_RESET);
-
- /*
- * Add blocked requests to the board's 'done' queue. The queued
- * requests will be completed at the end of the abort or reset
- * handling.
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&boardp->lock, flags);
- return 0;
- }
+ /*
+ * Block new commands while handling a reset or abort request.
+ */
+ if (boardp->flags & ASC_HOST_IN_RESET) {
+ ASC_DBG1(1,
+ "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
+ (ulong)scp);
+ scp->result = HOST_BYTE(DID_RESET);
- /*
- * Attempt to execute any waiting commands for the board.
- */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1,
- "advansys_queuecommand: before asc_execute_queue() waiting\n");
- asc_execute_queue(&boardp->waiting);
- }
+ /*
+ * Add blocked requests to the board's 'done' queue. The queued
+ * requests will be completed at the end of the abort or reset
+ * handling.
+ */
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ spin_unlock_irqrestore(&boardp->lock, flags);
+ return 0;
+ }
- /*
- * Save the function pointer to Linux mid-level 'done' function
- * and attempt to execute the command.
- *
- * If ASC_NOERROR is returned the request has been added to the
- * board's 'active' queue and will be completed by the interrupt
- * handler.
- *
- * If ASC_BUSY is returned add the request to the board's per
- * target waiting list. This is the first time the request has
- * been tried. Add it to the back of the waiting list. It will be
- * retried later.
- *
- * If an error occurred, the request will have been placed on the
- * board's 'done' queue and must be completed before returning.
- */
- scp->scsi_done = done;
- switch (asc_execute_scsi_cmnd(scp)) {
- case ASC_NOERROR:
- break;
- case ASC_BUSY:
- asc_enqueue(&boardp->waiting, scp, ASC_BACK);
- break;
- case ASC_ERROR:
- default:
- done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
- /* Interrupts could be enabled here. */
- asc_scsi_done_list(done_scp);
- break;
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
+ /*
+ * Attempt to execute any waiting commands for the board.
+ */
+ if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+ ASC_DBG(1,
+ "advansys_queuecommand: before asc_execute_queue() waiting\n");
+ asc_execute_queue(&boardp->waiting);
+ }
+
+ /*
+ * Save the function pointer to Linux mid-level 'done' function
+ * and attempt to execute the command.
+ *
+ * If ASC_NOERROR is returned the request has been added to the
+ * board's 'active' queue and will be completed by the interrupt
+ * handler.
+ *
+ * If ASC_BUSY is returned add the request to the board's per
+ * target waiting list. This is the first time the request has
+ * been tried. Add it to the back of the waiting list. It will be
+ * retried later.
+ *
+ * If an error occurred, the request will have been placed on the
+ * board's 'done' queue and must be completed before returning.
+ */
+ scp->scsi_done = done;
+ switch (asc_execute_scsi_cmnd(scp)) {
+ case ASC_NOERROR:
+ break;
+ case ASC_BUSY:
+ asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+ break;
+ case ASC_ERROR:
+ default:
+ done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
+ /* Interrupts could be enabled here. */
+ asc_scsi_done_list(done_scp);
+ break;
+ }
+ spin_unlock_irqrestore(&boardp->lock, flags);
- return 0;
+ return 0;
}
/*
@@ -5647,178 +4425,187 @@ advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
* sleeping is allowed and no locking other than for host structures is
* required. Returns SUCCESS or FAILED.
*/
-static int
-advansys_reset(struct scsi_cmnd *scp)
+static int advansys_reset(struct scsi_cmnd *scp)
{
- struct Scsi_Host *shp;
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ulong flags;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *tscp, *new_last_scp;
- int status;
- int ret = SUCCESS;
-
- ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong) scp);
+ struct Scsi_Host *shost;
+ asc_board_t *boardp;
+ ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ ulong flags;
+ struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
+ struct scsi_cmnd *tscp, *new_last_scp;
+ int status;
+ int ret = SUCCESS;
+
+ ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
#ifdef ADVANSYS_STATS
- if (scp->device->host != NULL) {
- ASC_STATS(scp->device->host, reset);
- }
+ if (scp->device->host != NULL) {
+ ASC_STATS(scp->device->host, reset);
+ }
#endif /* ADVANSYS_STATS */
- if ((shp = scp->device->host) == NULL) {
- scp->result = HOST_BYTE(DID_ERROR);
- return FAILED;
- }
+ if ((shost = scp->device->host) == NULL) {
+ scp->result = HOST_BYTE(DID_ERROR);
+ return FAILED;
+ }
- boardp = ASC_BOARDP(shp);
+ boardp = ASC_BOARDP(shost);
- ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
- boardp->id);
- /*
- * Check for re-entrancy.
- */
- spin_lock_irqsave(&boardp->lock, flags);
- if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&boardp->lock, flags);
- return FAILED;
- }
- boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
-
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-
- /*
- * Reset the chip and SCSI bus.
- */
- ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
- status = AscInitAsc1000Driver(asc_dvc_varp);
-
- /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
- if (asc_dvc_varp->err_code) {
- ASC_PRINT2(
- "advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ret = FAILED;
- } else if (status) {
- ASC_PRINT2(
- "advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
- boardp->id, status);
- } else {
- ASC_PRINT1(
- "advansys_reset: board %d: SCSI bus reset successful.\n",
- boardp->id);
- }
-
- ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
+ ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
+ boardp->id);
+ /*
+ * Check for re-entrancy.
+ */
spin_lock_irqsave(&boardp->lock, flags);
+ if (boardp->flags & ASC_HOST_IN_RESET) {
+ spin_unlock_irqrestore(&boardp->lock, flags);
+ return FAILED;
+ }
+ boardp->flags |= ASC_HOST_IN_RESET;
+ spin_unlock_irqrestore(&boardp->lock, flags);
- } else {
- /*
- * Wide Board
- *
- * If the suggest reset bus flags are set, then reset the bus.
- * Otherwise only reset the device.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-
- /*
- * Reset the target's SCSI bus.
- */
- ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
- switch (AdvResetChipAndSB(adv_dvc_varp)) {
- case ASC_TRUE:
- ASC_PRINT1("advansys_reset: board %d: SCSI bus reset successful.\n",
- boardp->id);
- break;
- case ASC_FALSE:
- default:
- ASC_PRINT1("advansys_reset: board %d: SCSI bus reset error.\n",
- boardp->id);
- ret = FAILED;
- break;
- }
- spin_lock_irqsave(&boardp->lock, flags);
- (void) AdvISR(adv_dvc_varp);
- }
- /* Board lock is held. */
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Narrow Board
+ */
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- /*
- * Dequeue all board 'done' requests. A pointer to the last request
- * is returned in 'last_scp'.
- */
- done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
+ /*
+ * Reset the chip and SCSI bus.
+ */
+ ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
+ status = AscInitAsc1000Driver(asc_dvc_varp);
+
+ /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+ if (asc_dvc_varp->err_code) {
+ ASC_PRINT2
+ ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
+ boardp->id, asc_dvc_varp->err_code);
+ ret = FAILED;
+ } else if (status) {
+ ASC_PRINT2
+ ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
+ boardp->id, status);
+ } else {
+ ASC_PRINT1
+ ("advansys_reset: board %d: SCSI bus reset successful.\n",
+ boardp->id);
+ }
+
+ ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
+ spin_lock_irqsave(&boardp->lock, flags);
- /*
- * Dequeue all board 'active' requests for all devices and set
- * the request status to DID_RESET. A pointer to the last request
- * is returned in 'last_scp'.
- */
- if (done_scp == NULL) {
- done_scp = asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
- &boardp->active, &new_last_scp, ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
+ } else {
+ /*
+ * Wide Board
+ *
+ * If the suggest reset bus flags are set, then reset the bus.
+ * Otherwise only reset the device.
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- /*
- * Dequeue all 'waiting' requests and set the request status
- * to DID_RESET.
- */
- if (done_scp == NULL) {
- done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
- &boardp->waiting, &new_last_scp, ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
+ /*
+ * Reset the target's SCSI bus.
+ */
+ ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+ switch (AdvResetChipAndSB(adv_dvc_varp)) {
+ case ASC_TRUE:
+ ASC_PRINT1
+ ("advansys_reset: board %d: SCSI bus reset successful.\n",
+ boardp->id);
+ break;
+ case ASC_FALSE:
+ default:
+ ASC_PRINT1
+ ("advansys_reset: board %d: SCSI bus reset error.\n",
+ boardp->id);
+ ret = FAILED;
+ break;
+ }
+ spin_lock_irqsave(&boardp->lock, flags);
+ (void)AdvISR(adv_dvc_varp);
+ }
+ /* Board lock is held. */
+
+ /*
+ * Dequeue all board 'done' requests. A pointer to the last request
+ * is returned in 'last_scp'.
+ */
+ done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
+
+ /*
+ * Dequeue all board 'active' requests for all devices and set
+ * the request status to DID_RESET. A pointer to the last request
+ * is returned in 'last_scp'.
+ */
+ if (done_scp == NULL) {
+ done_scp =
+ asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
+ for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+ tscp->result = HOST_BYTE(DID_RESET);
+ }
+ } else {
+ /* Append to 'done_scp' at the end with 'last_scp'. */
+ ASC_ASSERT(last_scp != NULL);
+ last_scp->host_scribble =
+ (unsigned char *)asc_dequeue_list(&boardp->active,
+ &new_last_scp,
+ ASC_TID_ALL);
+ if (new_last_scp != NULL) {
+ ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+ for (tscp = REQPNEXT(last_scp); tscp;
+ tscp = REQPNEXT(tscp)) {
+ tscp->result = HOST_BYTE(DID_RESET);
+ }
+ last_scp = new_last_scp;
+ }
+ }
- /* Save the time of the most recently completed reset. */
- boardp->last_reset = jiffies;
+ /*
+ * Dequeue all 'waiting' requests and set the request status
+ * to DID_RESET.
+ */
+ if (done_scp == NULL) {
+ done_scp =
+ asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
+ for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+ tscp->result = HOST_BYTE(DID_RESET);
+ }
+ } else {
+ /* Append to 'done_scp' at the end with 'last_scp'. */
+ ASC_ASSERT(last_scp != NULL);
+ last_scp->host_scribble =
+ (unsigned char *)asc_dequeue_list(&boardp->waiting,
+ &new_last_scp,
+ ASC_TID_ALL);
+ if (new_last_scp != NULL) {
+ ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+ for (tscp = REQPNEXT(last_scp); tscp;
+ tscp = REQPNEXT(tscp)) {
+ tscp->result = HOST_BYTE(DID_RESET);
+ }
+ last_scp = new_last_scp;
+ }
+ }
- /* Clear reset flag. */
- boardp->flags &= ~ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
+ /* Save the time of the most recently completed reset. */
+ boardp->last_reset = jiffies;
- /*
- * Complete all the 'done_scp' requests.
- */
- if (done_scp != NULL) {
- asc_scsi_done_list(done_scp);
- }
+ /* Clear reset flag. */
+ boardp->flags &= ~ASC_HOST_IN_RESET;
+ spin_unlock_irqrestore(&boardp->lock, flags);
- ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+ /*
+ * Complete all the 'done_scp' requests.
+ */
+ if (done_scp != NULL) {
+ asc_scsi_done_list(done_scp);
+ }
- return ret;
+ ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+
+ return ret;
}
/*
@@ -5834,71 +4621,70 @@ advansys_reset(struct scsi_cmnd *scp)
*/
static int
advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int ip[])
+ sector_t capacity, int ip[])
{
- asc_board_t *boardp;
-
- ASC_DBG(1, "advansys_biosparam: begin\n");
- ASC_STATS(sdev->host, biosparam);
- boardp = ASC_BOARDP(sdev->host);
- if (ASC_NARROW_BOARD(boardp)) {
- if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
- ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- }
- } else {
- if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
- BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- }
- }
- ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
- ASC_DBG(1, "advansys_biosparam: end\n");
- return 0;
+ asc_board_t *boardp;
+
+ ASC_DBG(1, "advansys_biosparam: begin\n");
+ ASC_STATS(sdev->host, biosparam);
+ boardp = ASC_BOARDP(sdev->host);
+ if (ASC_NARROW_BOARD(boardp)) {
+ if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+ ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
+ } else {
+ if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+ BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
+ }
+ ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+ ASC_DBG(1, "advansys_biosparam: end\n");
+ return 0;
}
-/*
- * --- Loadable Driver Support
- */
+static int __init advansys_detect(struct scsi_host_template *tpnt);
+static int advansys_release(struct Scsi_Host *shp);
static struct scsi_host_template driver_template = {
- .proc_name = "advansys",
+ .proc_name = "advansys",
#ifdef CONFIG_PROC_FS
- .proc_info = advansys_proc_info,
+ .proc_info = advansys_proc_info,
#endif
- .name = "advansys",
- .detect = advansys_detect,
- .release = advansys_release,
- .info = advansys_info,
- .queuecommand = advansys_queuecommand,
- .eh_bus_reset_handler = advansys_reset,
- .bios_param = advansys_biosparam,
- .slave_configure = advansys_slave_configure,
- /*
- * Because the driver may control an ISA adapter 'unchecked_isa_dma'
- * must be set. The flag will be cleared in advansys_detect for non-ISA
- * adapters. Refer to the comment in scsi_module.c for more information.
- */
- .unchecked_isa_dma = 1,
- /*
- * All adapters controlled by this driver are capable of large
- * scatter-gather lists. According to the mid-level SCSI documentation
- * this obviates any performance gain provided by setting
- * 'use_clustering'. But empirically while CPU utilization is increased
- * by enabling clustering, I/O throughput increases as well.
- */
- .use_clustering = ENABLE_CLUSTERING,
+ .name = "advansys",
+ .detect = advansys_detect,
+ .release = advansys_release,
+ .info = advansys_info,
+ .queuecommand = advansys_queuecommand,
+ .eh_bus_reset_handler = advansys_reset,
+ .bios_param = advansys_biosparam,
+ .slave_configure = advansys_slave_configure,
+ /*
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+ * must be set. The flag will be cleared in advansys_detect for non-ISA
+ * adapters. Refer to the comment in scsi_module.c for more information.
+ */
+ .unchecked_isa_dma = 1,
+ /*
+ * All adapters controlled by this driver are capable of large
+ * scatter-gather lists. According to the mid-level SCSI documentation
+ * this obviates any performance gain provided by setting
+ * 'use_clustering'. But empirically while CPU utilization is increased
+ * by enabling clustering, I/O throughput increases as well.
+ */
+ .use_clustering = ENABLE_CLUSTERING,
};
-#include "scsi_module.c"
+#include "scsi_module.c"
/*
* --- Miscellaneous Driver Functions
@@ -5913,130 +4699,138 @@ static struct scsi_host_template driver_template = {
* to the AdvanSys driver which is for a device sharing an interrupt with
* an AdvanSys adapter.
*/
-STATIC irqreturn_t
-advansys_interrupt(int irq, void *dev_id)
+static irqreturn_t advansys_interrupt(int irq, void *dev_id)
{
- ulong flags;
- int i;
- asc_board_t *boardp;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *new_last_scp;
- struct Scsi_Host *shp;
-
- ASC_DBG(1, "advansys_interrupt: begin\n");
+ ulong flags;
+ int i;
+ asc_board_t *boardp;
+ struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
+ struct scsi_cmnd *new_last_scp;
+ struct Scsi_Host *shost;
+
+ ASC_DBG(1, "advansys_interrupt: begin\n");
+
+ /*
+ * Check for interrupts on all boards.
+ * AscISR() will call asc_isr_callback().
+ */
+ for (i = 0; i < asc_board_count; i++) {
+ shost = asc_host[i];
+ boardp = ASC_BOARDP(shost);
+ ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
+ i, (ulong)boardp);
+ spin_lock_irqsave(&boardp->lock, flags);
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Narrow Board
+ */
+ if (AscIsIntPending(shost->io_port)) {
+ ASC_STATS(shost, interrupt);
+ ASC_DBG(1,
+ "advansys_interrupt: before AscISR()\n");
+ AscISR(&boardp->dvc_var.asc_dvc_var);
+ }
+ } else {
+ /*
+ * Wide Board
+ */
+ ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
+ if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+ ASC_STATS(shost, interrupt);
+ }
+ }
- /*
- * Check for interrupts on all boards.
- * AscISR() will call asc_isr_callback().
- */
- for (i = 0; i < asc_board_count; i++) {
- shp = asc_host[i];
- boardp = ASC_BOARDP(shp);
- ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
- i, (ulong) boardp);
- spin_lock_irqsave(&boardp->lock, flags);
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- if (AscIsIntPending(shp->io_port)) {
- ASC_STATS(shp, interrupt);
- ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
- AscISR(&boardp->dvc_var.asc_dvc_var);
- }
- } else {
- /*
- * Wide Board
- */
- ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
- if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(shp, interrupt);
- }
- }
-
- /*
- * Start waiting requests and create a list of completed requests.
- *
- * If a reset request is being performed for the board, the reset
- * handler will complete pending requests after it has completed.
- */
- if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
- ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
- (ulong) done_scp, (ulong) last_scp);
-
- /* Start any waiting commands for the board. */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
- asc_execute_queue(&boardp->waiting);
- }
-
- /*
- * Add to the list of requests that must be completed.
- *
- * 'done_scp' will always be NULL on the first iteration
- * of this loop. 'last_scp' is set at the same time as
- * 'done_scp'.
- */
- if (done_scp == NULL) {
- done_scp = asc_dequeue_list(&boardp->done, &last_scp,
- ASC_TID_ALL);
- } else {
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
- &boardp->done, &new_last_scp, ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- last_scp = new_last_scp;
- }
- }
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
- }
+ /*
+ * Start waiting requests and create a list of completed requests.
+ *
+ * If a reset request is being performed for the board, the reset
+ * handler will complete pending requests after it has completed.
+ */
+ if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
+ ASC_DBG2(1,
+ "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
+ (ulong)done_scp, (ulong)last_scp);
+
+ /* Start any waiting commands for the board. */
+ if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+ ASC_DBG(1,
+ "advansys_interrupt: before asc_execute_queue()\n");
+ asc_execute_queue(&boardp->waiting);
+ }
+
+ /*
+ * Add to the list of requests that must be completed.
+ *
+ * 'done_scp' will always be NULL on the first iteration
+ * of this loop. 'last_scp' is set at the same time as
+ * 'done_scp'.
+ */
+ if (done_scp == NULL) {
+ done_scp =
+ asc_dequeue_list(&boardp->done, &last_scp,
+ ASC_TID_ALL);
+ } else {
+ ASC_ASSERT(last_scp != NULL);
+ last_scp->host_scribble =
+ (unsigned char *)asc_dequeue_list(&boardp->
+ done,
+ &new_last_scp,
+ ASC_TID_ALL);
+ if (new_last_scp != NULL) {
+ ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+ last_scp = new_last_scp;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&boardp->lock, flags);
+ }
- /*
- * If interrupts were enabled on entry, then they
- * are now enabled here.
- *
- * Complete all requests on the done list.
- */
+ /*
+ * If interrupts were enabled on entry, then they
+ * are now enabled here.
+ *
+ * Complete all requests on the done list.
+ */
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp);
- ASC_DBG(1, "advansys_interrupt: end\n");
- return IRQ_HANDLED;
+ ASC_DBG(1, "advansys_interrupt: end\n");
+ return IRQ_HANDLED;
}
/*
* Set the number of commands to queue per device for the
* specified host adapter.
*/
-STATIC int
-advansys_slave_configure(struct scsi_device *device)
+static int advansys_slave_configure(struct scsi_device *device)
{
- asc_board_t *boardp;
+ asc_board_t *boardp;
- boardp = ASC_BOARDP(device->host);
- boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
- /*
- * Save a pointer to the device and set its initial/maximum
- * queue depth. Only save the pointer for a lun0 dev though.
- */
- if(device->lun == 0)
- boardp->device[device->id] = device;
- if(device->tagged_supported) {
- if (ASC_NARROW_BOARD(boardp)) {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]);
- } else {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- boardp->dvc_var.adv_dvc_var.max_dvc_qng);
- }
- } else {
- scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
- }
- ASC_DBG4(1, "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
- (ulong) device, (ulong) boardp, device->id, device->queue_depth);
- return 0;
+ boardp = ASC_BOARDP(device->host);
+ boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
+ /*
+ * Save a pointer to the device and set its initial/maximum
+ * queue depth. Only save the pointer for a lun0 dev though.
+ */
+ if (device->lun == 0)
+ boardp->device[device->id] = device;
+ if (device->tagged_supported) {
+ if (ASC_NARROW_BOARD(boardp)) {
+ scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+ boardp->dvc_var.asc_dvc_var.
+ max_dvc_qng[device->id]);
+ } else {
+ scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+ boardp->dvc_var.adv_dvc_var.
+ max_dvc_qng);
+ }
+ } else {
+ scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
+ }
+ ASC_DBG4(1,
+ "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
+ (ulong)device, (ulong)boardp, device->id, device->queue_depth);
+ return 0;
}
/*
@@ -6045,43 +4839,44 @@ advansys_slave_configure(struct scsi_device *device)
*
* Interrupts can be enabled on entry.
*/
-STATIC void
-asc_scsi_done_list(struct scsi_cmnd *scp)
+static void asc_scsi_done_list(struct scsi_cmnd *scp)
{
- struct scsi_cmnd *tscp;
+ struct scsi_cmnd *tscp;
- ASC_DBG(2, "asc_scsi_done_list: begin\n");
- while (scp != NULL) {
- asc_board_t *boardp;
- struct device *dev;
+ ASC_DBG(2, "asc_scsi_done_list: begin\n");
+ while (scp != NULL) {
+ asc_board_t *boardp;
+ struct device *dev;
- ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp);
- tscp = REQPNEXT(scp);
- scp->host_scribble = NULL;
+ ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
+ tscp = REQPNEXT(scp);
+ scp->host_scribble = NULL;
- boardp = ASC_BOARDP(scp->device->host);
+ boardp = ASC_BOARDP(scp->device->host);
- if (ASC_NARROW_BOARD(boardp))
- dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
- else
- dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+ if (ASC_NARROW_BOARD(boardp))
+ dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+ else
+ dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
- if (scp->use_sg)
- dma_unmap_sg(dev, (struct scatterlist *)scp->request_buffer,
- scp->use_sg, scp->sc_data_direction);
- else if (scp->request_bufflen)
- dma_unmap_single(dev, scp->SCp.dma_handle,
- scp->request_bufflen, scp->sc_data_direction);
+ if (scp->use_sg)
+ dma_unmap_sg(dev,
+ (struct scatterlist *)scp->request_buffer,
+ scp->use_sg, scp->sc_data_direction);
+ else if (scp->request_bufflen)
+ dma_unmap_single(dev, scp->SCp.dma_handle,
+ scp->request_bufflen,
+ scp->sc_data_direction);
- ASC_STATS(scp->device->host, done);
- ASC_ASSERT(scp->scsi_done != NULL);
+ ASC_STATS(scp->device->host, done);
+ ASC_ASSERT(scp->scsi_done != NULL);
- scp->scsi_done(scp);
+ scp->scsi_done(scp);
- scp = tscp;
- }
- ASC_DBG(2, "asc_scsi_done_list: done\n");
- return;
+ scp = tscp;
+ }
+ ASC_DBG(2, "asc_scsi_done_list: done\n");
+ return;
}
/*
@@ -6130,168 +4925,170 @@ asc_scsi_done_list(struct scsi_cmnd *scp)
* If ASC_BUSY is returned the request will be enqueued by the
* caller on the target's waiting queue and re-tried later.
*/
-STATIC int
-asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
{
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ADV_SCSI_REQ_Q *adv_scsiqp;
- struct scsi_device *device;
- int ret;
-
- ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
- (ulong) scp, (ulong) scp->scsi_done);
-
- boardp = ASC_BOARDP(scp->device->host);
- device = boardp->device[scp->device->id];
-
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Build and execute Narrow Board request.
- */
-
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-
- /*
- * Build Asc Library request structure using the
- * global structures 'asc_scsi_req' and 'asc_sg_head'.
- *
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- *
- * asc_build_req() can not return ASC_BUSY.
- */
- if (asc_build_req(boardp, scp) == ASC_ERROR) {
- ASC_STATS(scp->device->host, build_error);
- return ASC_ERROR;
- }
-
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
- switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
- case ASC_NOERROR:
- ASC_STATS(scp->device->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->device->host, exe_busy);
- break;
- case ASC_ERROR:
- ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- }
- } else {
- /*
- * Build and execute Wide Board request.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-
- /*
- * Build and get a pointer to an Adv Library request structure.
- *
- * If the request is successfully built then send it below,
- * otherwise return with an error.
- */
- switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
- /*
- * If busy is returned the request has not been enqueued.
- * It will be enqueued by the caller on the target's waiting
- * queue and retried later.
- *
- * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
- * count wide board busy conditions. They are updated in
- * adv_build_req and adv_get_sglist, respectively.
- */
- return ASC_BUSY;
- case ASC_ERROR:
- /*
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- */
- default:
- ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
- ASC_STATS(scp->device->host, build_error);
- return ASC_ERROR;
- }
-
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
- switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_STATS(scp->device->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->device->host, exe_busy);
- break;
- case ASC_ERROR:
- ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- }
- }
+ asc_board_t *boardp;
+ ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ ADV_SCSI_REQ_Q *adv_scsiqp;
+ struct scsi_device *device;
+ int ret;
+
+ ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
+ (ulong)scp, (ulong)scp->scsi_done);
+
+ boardp = ASC_BOARDP(scp->device->host);
+ device = boardp->device[scp->device->id];
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Build and execute Narrow Board request.
+ */
+
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+
+ /*
+ * Build Asc Library request structure using the
+ * global structures 'asc_scsi_req' and 'asc_sg_head'.
+ *
+ * If an error is returned, then the request has been
+ * queued on the board done queue. It will be completed
+ * by the caller.
+ *
+ * asc_build_req() can not return ASC_BUSY.
+ */
+ if (asc_build_req(boardp, scp) == ASC_ERROR) {
+ ASC_STATS(scp->device->host, build_error);
+ return ASC_ERROR;
+ }
- ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
- return ret;
+ /*
+ * Execute the command. If there is no error, add the command
+ * to the active queue.
+ */
+ switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
+ case ASC_NOERROR:
+ ASC_STATS(scp->device->host, exe_noerror);
+ /*
+ * Increment monotonically increasing per device successful
+ * request counter. Wrapping doesn't matter.
+ */
+ boardp->reqcnt[scp->device->id]++;
+ asc_enqueue(&boardp->active, scp, ASC_BACK);
+ ASC_DBG(1,
+ "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ /*
+ * Caller will enqueue request on the target's waiting queue
+ * and retry later.
+ */
+ ASC_STATS(scp->device->host, exe_busy);
+ break;
+ case ASC_ERROR:
+ ASC_PRINT2
+ ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
+ boardp->id, asc_dvc_varp->err_code);
+ ASC_STATS(scp->device->host, exe_error);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ default:
+ ASC_PRINT2
+ ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
+ boardp->id, asc_dvc_varp->err_code);
+ ASC_STATS(scp->device->host, exe_unknown);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ }
+ } else {
+ /*
+ * Build and execute Wide Board request.
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+
+ /*
+ * Build and get a pointer to an Adv Library request structure.
+ *
+ * If the request is successfully built then send it below,
+ * otherwise return with an error.
+ */
+ switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+ case ASC_NOERROR:
+ ASC_DBG(3,
+ "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ ASC_DBG(1,
+ "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
+ /*
+ * If busy is returned the request has not been enqueued.
+ * It will be enqueued by the caller on the target's waiting
+ * queue and retried later.
+ *
+ * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
+ * count wide board busy conditions. They are updated in
+ * adv_build_req and adv_get_sglist, respectively.
+ */
+ return ASC_BUSY;
+ case ASC_ERROR:
+ /*
+ * If an error is returned, then the request has been
+ * queued on the board done queue. It will be completed
+ * by the caller.
+ */
+ default:
+ ASC_DBG(1,
+ "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
+ ASC_STATS(scp->device->host, build_error);
+ return ASC_ERROR;
+ }
+
+ /*
+ * Execute the command. If there is no error, add the command
+ * to the active queue.
+ */
+ switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
+ case ASC_NOERROR:
+ ASC_STATS(scp->device->host, exe_noerror);
+ /*
+ * Increment monotonically increasing per device successful
+ * request counter. Wrapping doesn't matter.
+ */
+ boardp->reqcnt[scp->device->id]++;
+ asc_enqueue(&boardp->active, scp, ASC_BACK);
+ ASC_DBG(1,
+ "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ /*
+ * Caller will enqueue request on the target's waiting queue
+ * and retry later.
+ */
+ ASC_STATS(scp->device->host, exe_busy);
+ break;
+ case ASC_ERROR:
+ ASC_PRINT2
+ ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
+ boardp->id, adv_dvc_varp->err_code);
+ ASC_STATS(scp->device->host, exe_error);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ default:
+ ASC_PRINT2
+ ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
+ boardp->id, adv_dvc_varp->err_code);
+ ASC_STATS(scp->device->host, exe_unknown);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ }
+ }
+
+ ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+ return ret;
}
/*
@@ -6303,131 +5100,140 @@ asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
* If an error occurs, then queue the request on the board done
* queue and return ASC_ERROR.
*/
-STATIC int
-asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
+static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
{
- struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
-
- /*
- * Mutually exclusive access is required to 'asc_scsi_q' and
- * 'asc_sg_head' until after the request is started.
- */
- memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
-
- /*
- * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
- */
- asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
-
- /*
- * Build the ASC_SCSI_Q request.
- *
- * For narrow boards a CDB length maximum of 12 bytes
- * is supported.
- */
- if (scp->cmd_len > ASC_MAX_CDB_LEN) {
- ASC_PRINT3(
-"asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
- boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- asc_scsi_q.cdbptr = &scp->cmnd[0];
- asc_scsi_q.q2.cdb_len = scp->cmd_len;
- asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
- asc_scsi_q.q1.target_lun = scp->device->lun;
- asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
- asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+ struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+
+ /*
+ * Mutually exclusive access is required to 'asc_scsi_q' and
+ * 'asc_sg_head' until after the request is started.
+ */
+ memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
+
+ /*
+ * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
+ */
+ asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
+
+ /*
+ * Build the ASC_SCSI_Q request.
+ *
+ * For narrow boards a CDB length maximum of 12 bytes
+ * is supported.
+ */
+ if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+ ASC_PRINT3
+ ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
+ boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ return ASC_ERROR;
+ }
+ asc_scsi_q.cdbptr = &scp->cmnd[0];
+ asc_scsi_q.q2.cdb_len = scp->cmd_len;
+ asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
+ asc_scsi_q.q1.target_lun = scp->device->lun;
+ asc_scsi_q.q2.target_ix =
+ ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+ asc_scsi_q.q1.sense_addr =
+ cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+ asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+
+ /*
+ * If there are any outstanding requests for the current target,
+ * then every 255th request send an ORDERED request. This heuristic
+ * tries to retain the benefit of request sorting while preventing
+ * request starvation. 255 is the max number of tags or pending commands
+ * a device may have outstanding.
+ *
+ * The request count is incremented below for every successfully
+ * started request.
+ *
+ */
+ if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
+ (boardp->reqcnt[scp->device->id] % 255) == 0) {
+ asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
+ } else {
+ asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
+ }
- /*
- * If there are any outstanding requests for the current target,
- * then every 255th request send an ORDERED request. This heuristic
- * tries to retain the benefit of request sorting while preventing
- * request starvation. 255 is the max number of tags or pending commands
- * a device may have outstanding.
- *
- * The request count is incremented below for every successfully
- * started request.
- *
- */
- if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
- (boardp->reqcnt[scp->device->id] % 255) == 0) {
- asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
- } else {
- asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
- }
+ /*
+ * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
+ * buffer command.
+ */
+ if (scp->use_sg == 0) {
+ /*
+ * CDB request of single contiguous buffer.
+ */
+ ASC_STATS(scp->device->host, cont_cnt);
+ scp->SCp.dma_handle = scp->request_bufflen ?
+ dma_map_single(dev, scp->request_buffer,
+ scp->request_bufflen,
+ scp->sc_data_direction) : 0;
+ asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
+ asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
+ ASC_STATS_ADD(scp->device->host, cont_xfer,
+ ASC_CEILING(scp->request_bufflen, 512));
+ asc_scsi_q.q1.sg_queue_cnt = 0;
+ asc_scsi_q.sg_head = NULL;
+ } else {
+ /*
+ * CDB scatter-gather request list.
+ */
+ int sgcnt;
+ int use_sg;
+ struct scatterlist *slp;
+
+ slp = (struct scatterlist *)scp->request_buffer;
+ use_sg =
+ dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+ if (use_sg > scp->device->host->sg_tablesize) {
+ ASC_PRINT3
+ ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
+ boardp->id, use_sg,
+ scp->device->host->sg_tablesize);
+ dma_unmap_sg(dev, slp, scp->use_sg,
+ scp->sc_data_direction);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ return ASC_ERROR;
+ }
+
+ ASC_STATS(scp->device->host, sg_cnt);
- /*
- * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- ASC_STATS(scp->device->host, cont_cnt);
- scp->SCp.dma_handle = scp->request_bufflen ?
- dma_map_single(dev, scp->request_buffer,
- scp->request_bufflen, scp->sc_data_direction) : 0;
- asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
- asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
- ASC_STATS_ADD(scp->device->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- asc_scsi_q.q1.sg_queue_cnt = 0;
- asc_scsi_q.sg_head = NULL;
- } else {
- /*
- * CDB scatter-gather request list.
- */
- int sgcnt;
- int use_sg;
- struct scatterlist *slp;
+ /*
+ * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
+ * structure to point to it.
+ */
+ memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
+
+ asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+ asc_scsi_q.sg_head = &asc_sg_head;
+ asc_scsi_q.q1.data_cnt = 0;
+ asc_scsi_q.q1.data_addr = 0;
+ /* This is a byte value, otherwise it would need to be swapped. */
+ asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
+ ASC_STATS_ADD(scp->device->host, sg_elem,
+ asc_sg_head.entry_cnt);
- slp = (struct scatterlist *)scp->request_buffer;
- use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-
- if (use_sg > scp->device->host->sg_tablesize) {
- ASC_PRINT3(
-"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
- boardp->id, use_sg, scp->device->host->sg_tablesize);
- dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
-
- ASC_STATS(scp->device->host, sg_cnt);
-
- /*
- * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
- * structure to point to it.
- */
- memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
-
- asc_scsi_q.q1.cntl |= QC_SG_HEAD;
- asc_scsi_q.sg_head = &asc_sg_head;
- asc_scsi_q.q1.data_cnt = 0;
- asc_scsi_q.q1.data_addr = 0;
- /* This is a byte value, otherwise it would need to be swapped. */
- asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
- ASC_STATS_ADD(scp->device->host, sg_elem, asc_sg_head.entry_cnt);
-
- /*
- * Convert scatter-gather list into ASC_SG_HEAD list.
- */
- for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
- asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(sg_dma_address(slp));
- asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(sg_dma_len(slp));
- ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
- }
- }
+ /*
+ * Convert scatter-gather list into ASC_SG_HEAD list.
+ */
+ for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
+ asc_sg_head.sg_list[sgcnt].addr =
+ cpu_to_le32(sg_dma_address(slp));
+ asc_sg_head.sg_list[sgcnt].bytes =
+ cpu_to_le32(sg_dma_len(slp));
+ ASC_STATS_ADD(scp->device->host, sg_xfer,
+ ASC_CEILING(sg_dma_len(slp), 512));
+ }
+ }
- ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+ ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
- return ASC_NOERROR;
+ return ASC_NOERROR;
}
/*
@@ -6440,162 +5246,168 @@ asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
* microcode for DMA addresses or math operations are byte swapped
* to little-endian order.
*/
-STATIC int
+static int
adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
- ADV_SCSI_REQ_Q **adv_scsiqpp)
+ ADV_SCSI_REQ_Q **adv_scsiqpp)
{
- adv_req_t *reqp;
- ADV_SCSI_REQ_Q *scsiqp;
- int i;
- int ret;
- struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
-
- /*
- * Allocate an adv_req_t structure from the board to execute
- * the command.
- */
- if (boardp->adv_reqp == NULL) {
- ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
- ASC_STATS(scp->device->host, adv_build_noreq);
- return ASC_BUSY;
- } else {
- reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp->next_reqp;
- reqp->next_reqp = NULL;
- }
-
- /*
- * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
- */
- scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
-
- /*
- * Initialize the structure.
- */
- scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
-
- /*
- * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
- */
- scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
-
- /*
- * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
- */
- reqp->cmndp = scp;
+ adv_req_t *reqp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ int i;
+ int ret;
+ struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+
+ /*
+ * Allocate an adv_req_t structure from the board to execute
+ * the command.
+ */
+ if (boardp->adv_reqp == NULL) {
+ ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
+ ASC_STATS(scp->device->host, adv_build_noreq);
+ return ASC_BUSY;
+ } else {
+ reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp->next_reqp;
+ reqp->next_reqp = NULL;
+ }
- /*
- * Build the ADV_SCSI_REQ_Q request.
- */
+ /*
+ * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+ */
+ scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+
+ /*
+ * Initialize the structure.
+ */
+ scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
+
+ /*
+ * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+ */
+ scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
+
+ /*
+ * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
+ */
+ reqp->cmndp = scp;
+
+ /*
+ * Build the ADV_SCSI_REQ_Q request.
+ */
+
+ /*
+ * Set CDB length and copy it to the request structure.
+ * For wide boards a CDB length maximum of 16 bytes
+ * is supported.
+ */
+ if (scp->cmd_len > ADV_MAX_CDB_LEN) {
+ ASC_PRINT3
+ ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
+ boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ return ASC_ERROR;
+ }
+ scsiqp->cdb_len = scp->cmd_len;
+ /* Copy first 12 CDB bytes to cdb[]. */
+ for (i = 0; i < scp->cmd_len && i < 12; i++) {
+ scsiqp->cdb[i] = scp->cmnd[i];
+ }
+ /* Copy last 4 CDB bytes, if present, to cdb16[]. */
+ for (; i < scp->cmd_len; i++) {
+ scsiqp->cdb16[i - 12] = scp->cmnd[i];
+ }
- /*
- * Set CDB length and copy it to the request structure.
- * For wide boards a CDB length maximum of 16 bytes
- * is supported.
- */
- if (scp->cmd_len > ADV_MAX_CDB_LEN) {
- ASC_PRINT3(
-"adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
- boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- scsiqp->cdb_len = scp->cmd_len;
- /* Copy first 12 CDB bytes to cdb[]. */
- for (i = 0; i < scp->cmd_len && i < 12; i++) {
- scsiqp->cdb[i] = scp->cmnd[i];
- }
- /* Copy last 4 CDB bytes, if present, to cdb16[]. */
- for (; i < scp->cmd_len; i++) {
- scsiqp->cdb16[i - 12] = scp->cmnd[i];
- }
+ scsiqp->target_id = scp->device->id;
+ scsiqp->target_lun = scp->device->lun;
- scsiqp->target_id = scp->device->id;
- scsiqp->target_lun = scp->device->lun;
+ scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+ scsiqp->sense_len = sizeof(scp->sense_buffer);
- scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- scsiqp->sense_len = sizeof(scp->sense_buffer);
+ /*
+ * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
+ * buffer command.
+ */
- /*
- * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
-
- scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- scsiqp->vdata_addr = scp->request_buffer;
- scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
-
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- reqp->sgblkp = NULL;
scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- if (scp->request_bufflen) {
- scsiqp->vdata_addr = scp->request_buffer;
- scp->SCp.dma_handle =
- dma_map_single(dev, scp->request_buffer,
- scp->request_bufflen, scp->sc_data_direction);
- } else {
- scsiqp->vdata_addr = NULL;
- scp->SCp.dma_handle = 0;
- }
- scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
- scsiqp->sg_list_ptr = NULL;
- scsiqp->sg_real_addr = 0;
- ASC_STATS(scp->device->host, cont_cnt);
- ASC_STATS_ADD(scp->device->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- } else {
- /*
- * CDB scatter-gather request list.
- */
- struct scatterlist *slp;
- int use_sg;
+ scsiqp->vdata_addr = scp->request_buffer;
+ scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
- slp = (struct scatterlist *)scp->request_buffer;
- use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-
- if (use_sg > ADV_MAX_SG_LIST) {
- ASC_PRINT3(
-"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
- boardp->id, use_sg, scp->device->host->sg_tablesize);
- dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
-
- /*
- * Free the 'adv_req_t' structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
-
- return ASC_ERROR;
- }
-
- if ((ret = adv_get_sglist(boardp, reqp, scp, use_sg)) != ADV_SUCCESS) {
- /*
- * Free the adv_req_t structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
-
- return ret;
- }
-
- ASC_STATS(scp->device->host, sg_cnt);
- ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
- }
+ if (scp->use_sg == 0) {
+ /*
+ * CDB request of single contiguous buffer.
+ */
+ reqp->sgblkp = NULL;
+ scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+ if (scp->request_bufflen) {
+ scsiqp->vdata_addr = scp->request_buffer;
+ scp->SCp.dma_handle =
+ dma_map_single(dev, scp->request_buffer,
+ scp->request_bufflen,
+ scp->sc_data_direction);
+ } else {
+ scsiqp->vdata_addr = NULL;
+ scp->SCp.dma_handle = 0;
+ }
+ scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
+ scsiqp->sg_list_ptr = NULL;
+ scsiqp->sg_real_addr = 0;
+ ASC_STATS(scp->device->host, cont_cnt);
+ ASC_STATS_ADD(scp->device->host, cont_xfer,
+ ASC_CEILING(scp->request_bufflen, 512));
+ } else {
+ /*
+ * CDB scatter-gather request list.
+ */
+ struct scatterlist *slp;
+ int use_sg;
+
+ slp = (struct scatterlist *)scp->request_buffer;
+ use_sg =
+ dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+ if (use_sg > ADV_MAX_SG_LIST) {
+ ASC_PRINT3
+ ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
+ boardp->id, use_sg,
+ scp->device->host->sg_tablesize);
+ dma_unmap_sg(dev, slp, scp->use_sg,
+ scp->sc_data_direction);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+ /*
+ * Free the 'adv_req_t' structure by adding it back to the
+ * board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ASC_ERROR;
+ }
+
+ if ((ret =
+ adv_get_sglist(boardp, reqp, scp,
+ use_sg)) != ADV_SUCCESS) {
+ /*
+ * Free the adv_req_t structure by adding it back to the
+ * board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ret;
+ }
+
+ ASC_STATS(scp->device->host, sg_cnt);
+ ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
+ }
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
- *adv_scsiqpp = scsiqp;
+ *adv_scsiqpp = scsiqp;
- return ASC_NOERROR;
+ return ASC_NOERROR;
}
/*
@@ -6610,108 +5422,109 @@ adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
* ADV_SUCCESS(1) - SG List successfully created
* ADV_ERROR(-1) - SG List creation failed
*/
-STATIC int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, int use_sg)
+static int
+adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
+ int use_sg)
{
- adv_sgblk_t *sgblkp;
- ADV_SCSI_REQ_Q *scsiqp;
- struct scatterlist *slp;
- int sg_elem_cnt;
- ADV_SG_BLOCK *sg_block, *prev_sg_block;
- ADV_PADDR sg_block_paddr;
- int i;
-
- scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
- slp = (struct scatterlist *) scp->request_buffer;
- sg_elem_cnt = use_sg;
- prev_sg_block = NULL;
- reqp->sgblkp = NULL;
-
- do
- {
- /*
- * Allocate a 'adv_sgblk_t' structure from the board free
- * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
- * (15) scatter-gather elements.
- */
- if ((sgblkp = boardp->adv_sgblkp) == NULL) {
- ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
- ASC_STATS(scp->device->host, adv_build_nosg);
-
- /*
- * Allocation failed. Free 'adv_sgblk_t' structures already
- * allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL)
- {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
-
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
- }
- return ASC_BUSY;
- } else {
- /* Complete 'adv_sgblk_t' board allocation. */
- boardp->adv_sgblkp = sgblkp->next_sgblkp;
- sgblkp->next_sgblkp = NULL;
-
- /*
- * Get 8 byte aligned virtual and physical addresses for
- * the allocated ADV_SG_BLOCK structure.
- */
- sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block);
- sg_block_paddr = virt_to_bus(sg_block);
-
- /*
- * Check if this is the first 'adv_sgblk_t' for the request.
- */
- if (reqp->sgblkp == NULL)
- {
- /* Request's first scatter-gather block. */
- reqp->sgblkp = sgblkp;
-
- /*
- * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
- * address pointers.
- */
- scsiqp->sg_list_ptr = sg_block;
- scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
- } else
- {
- /* Request's second or later scatter-gather block. */
- sgblkp->next_sgblkp = reqp->sgblkp;
- reqp->sgblkp = sgblkp;
-
- /*
- * Point the previous ADV_SG_BLOCK structure to
- * the newly allocated ADV_SG_BLOCK structure.
- */
- ASC_ASSERT(prev_sg_block != NULL);
- prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
- }
- }
-
- for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
- {
- sg_block->sg_list[i].sg_addr = cpu_to_le32(sg_dma_address(slp));
- sg_block->sg_list[i].sg_count = cpu_to_le32(sg_dma_len(slp));
- ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
-
- if (--sg_elem_cnt == 0)
- { /* Last ADV_SG_BLOCK and scatter-gather entry. */
- sg_block->sg_cnt = i + 1;
- sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
- return ADV_SUCCESS;
- }
- slp++;
- }
- sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
- prev_sg_block = sg_block;
- }
- while (1);
- /* NOTREACHED */
+ adv_sgblk_t *sgblkp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ struct scatterlist *slp;
+ int sg_elem_cnt;
+ ADV_SG_BLOCK *sg_block, *prev_sg_block;
+ ADV_PADDR sg_block_paddr;
+ int i;
+
+ scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+ slp = (struct scatterlist *)scp->request_buffer;
+ sg_elem_cnt = use_sg;
+ prev_sg_block = NULL;
+ reqp->sgblkp = NULL;
+
+ do {
+ /*
+ * Allocate a 'adv_sgblk_t' structure from the board free
+ * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+ * (15) scatter-gather elements.
+ */
+ if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+ ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
+ ASC_STATS(scp->device->host, adv_build_nosg);
+
+ /*
+ * Allocation failed. Free 'adv_sgblk_t' structures already
+ * allocated for the request.
+ */
+ while ((sgblkp = reqp->sgblkp) != NULL) {
+ /* Remove 'sgblkp' from the request list. */
+ reqp->sgblkp = sgblkp->next_sgblkp;
+
+ /* Add 'sgblkp' to the board free list. */
+ sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgblkp;
+ }
+ return ASC_BUSY;
+ } else {
+ /* Complete 'adv_sgblk_t' board allocation. */
+ boardp->adv_sgblkp = sgblkp->next_sgblkp;
+ sgblkp->next_sgblkp = NULL;
+
+ /*
+ * Get 8 byte aligned virtual and physical addresses for
+ * the allocated ADV_SG_BLOCK structure.
+ */
+ sg_block =
+ (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
+ sg_block_paddr = virt_to_bus(sg_block);
+
+ /*
+ * Check if this is the first 'adv_sgblk_t' for the request.
+ */
+ if (reqp->sgblkp == NULL) {
+ /* Request's first scatter-gather block. */
+ reqp->sgblkp = sgblkp;
+
+ /*
+ * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+ * address pointers.
+ */
+ scsiqp->sg_list_ptr = sg_block;
+ scsiqp->sg_real_addr =
+ cpu_to_le32(sg_block_paddr);
+ } else {
+ /* Request's second or later scatter-gather block. */
+ sgblkp->next_sgblkp = reqp->sgblkp;
+ reqp->sgblkp = sgblkp;
+
+ /*
+ * Point the previous ADV_SG_BLOCK structure to
+ * the newly allocated ADV_SG_BLOCK structure.
+ */
+ ASC_ASSERT(prev_sg_block != NULL);
+ prev_sg_block->sg_ptr =
+ cpu_to_le32(sg_block_paddr);
+ }
+ }
+
+ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
+ sg_block->sg_list[i].sg_addr =
+ cpu_to_le32(sg_dma_address(slp));
+ sg_block->sg_list[i].sg_count =
+ cpu_to_le32(sg_dma_len(slp));
+ ASC_STATS_ADD(scp->device->host, sg_xfer,
+ ASC_CEILING(sg_dma_len(slp), 512));
+
+ if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
+ sg_block->sg_cnt = i + 1;
+ sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
+ return ADV_SUCCESS;
+ }
+ slp++;
+ }
+ sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+ prev_sg_block = sg_block;
+ }
+ while (1);
+ /* NOTREACHED */
}
/*
@@ -6719,165 +5532,171 @@ adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, int
*
* Interrupt callback function for the Narrow SCSI Asc Library.
*/
-STATIC void
-asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
{
- asc_board_t *boardp;
- struct scsi_cmnd *scp;
- struct Scsi_Host *shp;
- int i;
-
- ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
- (ulong) asc_dvc_varp, (ulong) qdonep);
- ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+ asc_board_t *boardp;
+ struct scsi_cmnd *scp;
+ struct Scsi_Host *shost;
+ int i;
+
+ ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
+ (ulong)asc_dvc_varp, (ulong)qdonep);
+ ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+
+ /*
+ * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+ * command that has been completed.
+ */
+ scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
+ ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
+
+ if (scp == NULL) {
+ ASC_PRINT("asc_isr_callback: scp is NULL\n");
+ return;
+ }
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ /*
+ * If the request's host pointer is not valid, display a
+ * message and return.
+ */
+ shost = scp->device->host;
+ for (i = 0; i < asc_board_count; i++) {
+ if (asc_host[i] == shost) {
+ break;
+ }
+ }
+ if (i == asc_board_count) {
+ ASC_PRINT2
+ ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
+ (ulong)scp, (ulong)shost);
+ return;
+ }
- /*
- * Get the struct scsi_cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- */
- scp = (struct scsi_cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
- ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong) scp);
-
- if (scp == NULL) {
- ASC_PRINT("asc_isr_callback: scp is NULL\n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+ ASC_STATS(shost, callback);
+ ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
+
+ /*
+ * If the request isn't found on the active queue, it may
+ * have been removed to handle a reset request.
+ * Display a message and return.
+ */
+ boardp = ASC_BOARDP(shost);
+ ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
+ if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+ ASC_PRINT2
+ ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
+ boardp->id, (ulong)scp);
+ return;
+ }
- /*
- * If the request's host pointer is not valid, display a
- * message and return.
- */
- shp = scp->device->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shp) {
- break;
- }
- }
- if (i == asc_board_count) {
- ASC_PRINT2(
- "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
- (ulong) scp, (ulong) shp);
- return;
- }
+ /*
+ * 'qdonep' contains the command's ending status.
+ */
+ switch (qdonep->d3.done_stat) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
+ scp->result = 0;
- ASC_STATS(shp, callback);
- ASC_DBG1(1, "asc_isr_callback: shp 0x%lx\n", (ulong) shp);
+ /*
+ * If an INQUIRY command completed successfully, then call
+ * the AscInquiryHandling() function to set-up the device.
+ */
+ if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
+ (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
+ AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
+ (ASC_SCSI_INQUIRY *)scp->
+ request_buffer);
+ }
- /*
- * If the request isn't found on the active queue, it may
- * have been removed to handle a reset request.
- * Display a message and return.
- */
- boardp = ASC_BOARDP(shp);
- ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2(
- "asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong) scp);
- return;
- }
+ /*
+ * Check for an underrun condition.
+ *
+ * If there was no error and an underrun condition, then
+ * then return the number of underrun bytes.
+ */
+ if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
+ qdonep->remain_bytes <= scp->request_bufflen) {
+ ASC_DBG1(1,
+ "asc_isr_callback: underrun condition %u bytes\n",
+ (unsigned)qdonep->remain_bytes);
+ scp->resid = qdonep->remain_bytes;
+ }
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
+ switch (qdonep->d3.host_stat) {
+ case QHSTA_NO_ERROR:
+ if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+ ASC_DBG(2,
+ "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by target drivers
+ * defined in scsi.h shifts the status byte returned by
+ * host drivers right by 1 bit. This is why target drivers
+ * also use right shifted status byte definitions. For
+ * instance target drivers use CHECK_CONDITION, defined to
+ * 0x1, instead of the SCSI defined check condition value
+ * of 0x2. Host drivers are supposed to return the status
+ * byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ } else {
+ scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
+ }
+ break;
+
+ default:
+ /* QHSTA error occurred */
+ ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
+ qdonep->d3.host_stat);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
+ scp->result =
+ HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
+ scsi_msg) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ break;
+
+ default:
+ ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
+ qdonep->d3.done_stat);
+ scp->result =
+ HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
+ scsi_msg) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ break;
+ }
- /*
- * 'qdonep' contains the command's ending status.
- */
- switch (qdonep->d3.done_stat) {
- case QD_NO_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
- scp->result = 0;
-
- /*
- * If an INQUIRY command completed successfully, then call
- * the AscInquiryHandling() function to set-up the device.
- */
- if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
- (scp->request_bufflen - qdonep->remain_bytes) >= 8)
- {
- AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
- (ASC_SCSI_INQUIRY *) scp->request_buffer);
- }
-
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
- qdonep->remain_bytes <= scp->request_bufflen) {
- ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
- (unsigned) qdonep->remain_bytes);
- scp->resid = qdonep->remain_bytes;
- }
- break;
-
- case QD_WITH_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
- switch (qdonep->d3.host_stat) {
- case QHSTA_NO_ERROR:
- if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
- ASC_DBG(2, "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- } else {
- scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
- }
- break;
-
- default:
- /* QHSTA error occurred */
- ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
- qdonep->d3.host_stat);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
- }
- break;
-
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
- scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
-
- default:
- ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", qdonep->d3.done_stat);
- scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
- }
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request finished normally, then set the bit for the target
+ * to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+ qdonep->d3.done_stat == QD_NO_ERROR &&
+ qdonep->d3.host_stat == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ }
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
- qdonep->d3.done_stat == QD_NO_ERROR &&
- qdonep->d3.host_stat == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
- }
+ /*
+ * Because interrupts may be enabled by the 'struct scsi_cmnd' done
+ * function, add the command to the end of the board's done queue.
+ * The done function for the command will be called from
+ * advansys_interrupt().
+ */
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
- /*
- * Because interrupts may be enabled by the 'struct scsi_cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
-
- return;
+ return;
}
/*
@@ -6885,238 +5704,240 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
*
* Callback function for the Wide SCSI Adv Library.
*/
-STATIC void
-adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
{
- asc_board_t *boardp;
- adv_req_t *reqp;
- adv_sgblk_t *sgblkp;
- struct scsi_cmnd *scp;
- struct Scsi_Host *shp;
- int i;
- ADV_DCNT resid_cnt;
-
-
- ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
- (ulong) adv_dvc_varp, (ulong) scsiqp);
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
-
- /*
- * Get the adv_req_t structure for the command that has been
- * completed. The adv_req_t structure actually contains the
- * completed ADV_SCSI_REQ_Q structure.
- */
- reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr);
- ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong) reqp);
- if (reqp == NULL) {
- ASC_PRINT("adv_isr_callback: reqp is NULL\n");
- return;
- }
-
- /*
- * Get the struct scsi_cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- *
- * Note: The adv_req_t request structure and adv_sgblk_t structure,
- * if any, are dropped, because a board structure pointer can not be
- * determined.
- */
- scp = reqp->cmndp;
- ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong) scp);
- if (scp == NULL) {
- ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
-
- /*
- * If the request's host pointer is not valid, display a message
- * and return.
- */
- shp = scp->device->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shp) {
- break;
- }
- }
- /*
- * Note: If the host structure is not found, the adv_req_t request
- * structure and adv_sgblk_t structure, if any, is dropped.
- */
- if (i == asc_board_count) {
- ASC_PRINT2(
- "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
- (ulong) scp, (ulong) shp);
- return;
- }
+ asc_board_t *boardp;
+ adv_req_t *reqp;
+ adv_sgblk_t *sgblkp;
+ struct scsi_cmnd *scp;
+ struct Scsi_Host *shost;
+ int i;
+ ADV_DCNT resid_cnt;
+
+ ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
+ (ulong)adv_dvc_varp, (ulong)scsiqp);
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+
+ /*
+ * Get the adv_req_t structure for the command that has been
+ * completed. The adv_req_t structure actually contains the
+ * completed ADV_SCSI_REQ_Q structure.
+ */
+ reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+ ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
+ if (reqp == NULL) {
+ ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+ return;
+ }
- ASC_STATS(shp, callback);
- ASC_DBG1(1, "adv_isr_callback: shp 0x%lx\n", (ulong) shp);
+ /*
+ * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+ * command that has been completed.
+ *
+ * Note: The adv_req_t request structure and adv_sgblk_t structure,
+ * if any, are dropped, because a board structure pointer can not be
+ * determined.
+ */
+ scp = reqp->cmndp;
+ ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
+ if (scp == NULL) {
+ ASC_PRINT
+ ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+ return;
+ }
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ /*
+ * If the request's host pointer is not valid, display a message
+ * and return.
+ */
+ shost = scp->device->host;
+ for (i = 0; i < asc_board_count; i++) {
+ if (asc_host[i] == shost) {
+ break;
+ }
+ }
+ /*
+ * Note: If the host structure is not found, the adv_req_t request
+ * structure and adv_sgblk_t structure, if any, is dropped.
+ */
+ if (i == asc_board_count) {
+ ASC_PRINT2
+ ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
+ (ulong)scp, (ulong)shost);
+ return;
+ }
- /*
- * If the request isn't found on the active queue, it may have been
- * removed to handle a reset request. Display a message and return.
- *
- * Note: Because the structure may still be in use don't attempt
- * to free the adv_req_t and adv_sgblk_t, if any, structures.
- */
- boardp = ASC_BOARDP(shp);
- ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2(
- "adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong) scp);
- return;
- }
+ ASC_STATS(shost, callback);
+ ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
+
+ /*
+ * If the request isn't found on the active queue, it may have been
+ * removed to handle a reset request. Display a message and return.
+ *
+ * Note: Because the structure may still be in use don't attempt
+ * to free the adv_req_t and adv_sgblk_t, if any, structures.
+ */
+ boardp = ASC_BOARDP(shost);
+ ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
+ if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+ ASC_PRINT2
+ ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
+ boardp->id, (ulong)scp);
+ return;
+ }
- /*
- * 'done_status' contains the command's ending status.
- */
- switch (scsiqp->done_status) {
- case QD_NO_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
- scp->result = 0;
-
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- resid_cnt = le32_to_cpu(scsiqp->data_cnt);
- if (scp->request_bufflen != 0 && resid_cnt != 0 &&
- resid_cnt <= scp->request_bufflen) {
- ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
- (ulong) resid_cnt);
- scp->resid = resid_cnt;
- }
- break;
-
- case QD_WITH_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
- switch (scsiqp->host_status) {
- case QHSTA_NO_ERROR:
- if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
- ASC_DBG(2, "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(scsiqp->scsi_status);
- } else {
- scp->result = STATUS_BYTE(scsiqp->scsi_status);
- }
- break;
-
- default:
- /* Some other QHSTA error occurred. */
- ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
- scsiqp->host_status);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
- }
- break;
-
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
- scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
- break;
-
- default:
- ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", scsiqp->done_status);
- scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
- break;
- }
+ /*
+ * 'done_status' contains the command's ending status.
+ */
+ switch (scsiqp->done_status) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
+ scp->result = 0;
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
- scsiqp->done_status == QD_NO_ERROR &&
- scsiqp->host_status == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
- }
+ /*
+ * Check for an underrun condition.
+ *
+ * If there was no error and an underrun condition, then
+ * then return the number of underrun bytes.
+ */
+ resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+ if (scp->request_bufflen != 0 && resid_cnt != 0 &&
+ resid_cnt <= scp->request_bufflen) {
+ ASC_DBG1(1,
+ "adv_isr_callback: underrun condition %lu bytes\n",
+ (ulong)resid_cnt);
+ scp->resid = resid_cnt;
+ }
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
+ switch (scsiqp->host_status) {
+ case QHSTA_NO_ERROR:
+ if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+ ASC_DBG(2,
+ "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by target drivers
+ * defined in scsi.h shifts the status byte returned by
+ * host drivers right by 1 bit. This is why target drivers
+ * also use right shifted status byte definitions. For
+ * instance target drivers use CHECK_CONDITION, defined to
+ * 0x1, instead of the SCSI defined check condition value
+ * of 0x2. Host drivers are supposed to return the status
+ * byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(scsiqp->scsi_status);
+ } else {
+ scp->result = STATUS_BYTE(scsiqp->scsi_status);
+ }
+ break;
+
+ default:
+ /* Some other QHSTA error occurred. */
+ ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
+ scsiqp->host_status);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
+ scp->result =
+ HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
+
+ default:
+ ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
+ scsiqp->done_status);
+ scp->result =
+ HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
+ }
- /*
- * Because interrupts may be enabled by the 'struct scsi_cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request finished normally, then set the bit for the target
+ * to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+ scsiqp->done_status == QD_NO_ERROR &&
+ scsiqp->host_status == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ }
- /*
- * Free all 'adv_sgblk_t' structures allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL)
- {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
-
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
- }
+ /*
+ * Because interrupts may be enabled by the 'struct scsi_cmnd' done
+ * function, add the command to the end of the board's done queue.
+ * The done function for the command will be called from
+ * advansys_interrupt().
+ */
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+ /*
+ * Free all 'adv_sgblk_t' structures allocated for the request.
+ */
+ while ((sgblkp = reqp->sgblkp) != NULL) {
+ /* Remove 'sgblkp' from the request list. */
+ reqp->sgblkp = sgblkp->next_sgblkp;
+
+ /* Add 'sgblkp' to the board free list. */
+ sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgblkp;
+ }
- /*
- * Free the adv_req_t structure used with the command by adding
- * it back to the board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
+ /*
+ * Free the adv_req_t structure used with the command by adding
+ * it back to the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
- ASC_DBG(1, "adv_isr_callback: done\n");
+ ASC_DBG(1, "adv_isr_callback: done\n");
- return;
+ return;
}
/*
* adv_async_callback() - Adv Library asynchronous event callback function.
*/
-STATIC void
-adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
{
- switch (code)
- {
- case ADV_ASYNC_SCSI_BUS_RESET_DET:
- /*
- * The firmware detected a SCSI Bus reset.
- */
- ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
- break;
-
- case ADV_ASYNC_RDMA_FAILURE:
- /*
- * Handle RDMA failure by resetting the SCSI Bus and
- * possibly the chip if it is unresponsive. Log the error
- * with a unique code.
- */
- ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
- AdvResetChipAndSB(adv_dvc_varp);
- break;
-
- case ADV_HOST_SCSI_BUS_RESET:
- /*
- * Host generated SCSI bus reset occurred.
- */
- ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
- break;
-
- default:
- ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
- break;
- }
+ switch (code) {
+ case ADV_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ ASC_DBG(0,
+ "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+ break;
+
+ case ADV_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the SCSI Bus and
+ * possibly the chip if it is unresponsive. Log the error
+ * with a unique code.
+ */
+ ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
+ AdvResetChipAndSB(adv_dvc_varp);
+ break;
+
+ case ADV_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
+ break;
+
+ default:
+ ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
+ break;
+ }
}
/*
@@ -7127,50 +5948,50 @@ adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
*
* 'REQPNEXT(reqp)' returns reqp's next pointer.
*/
-STATIC void
-asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
+static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
{
- int tid;
-
- ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
- (ulong) ascq, (ulong) reqp, flag);
- ASC_ASSERT(reqp != NULL);
- ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if (flag == ASC_FRONT) {
- reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
- ascq->q_first[tid] = reqp;
- /* If the queue was empty, set the last pointer. */
- if (ascq->q_last[tid] == NULL) {
- ascq->q_last[tid] = reqp;
- }
- } else { /* ASC_BACK */
- if (ascq->q_last[tid] != NULL) {
- ascq->q_last[tid]->host_scribble = (unsigned char *)reqp;
- }
- ascq->q_last[tid] = reqp;
- reqp->host_scribble = NULL;
- /* If the queue was empty, set the first pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_first[tid] = reqp;
- }
- }
- /* The queue has at least one entry, set its bit. */
- ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
+ int tid;
+
+ ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
+ (ulong)ascq, (ulong)reqp, flag);
+ ASC_ASSERT(reqp != NULL);
+ ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+ tid = REQPTID(reqp);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+ if (flag == ASC_FRONT) {
+ reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
+ ascq->q_first[tid] = reqp;
+ /* If the queue was empty, set the last pointer. */
+ if (ascq->q_last[tid] == NULL) {
+ ascq->q_last[tid] = reqp;
+ }
+ } else { /* ASC_BACK */
+ if (ascq->q_last[tid] != NULL) {
+ ascq->q_last[tid]->host_scribble =
+ (unsigned char *)reqp;
+ }
+ ascq->q_last[tid] = reqp;
+ reqp->host_scribble = NULL;
+ /* If the queue was empty, set the first pointer. */
+ if (ascq->q_first[tid] == NULL) {
+ ascq->q_first[tid] = reqp;
+ }
+ }
+ /* The queue has at least one entry, set its bit. */
+ ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_tot_cnt[tid]++;
- ascq->q_cur_cnt[tid]++;
- if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
- ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
- ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
- tid, ascq->q_max_cnt[tid]);
- }
- REQPTIME(reqp) = REQTIMESTAMP();
+ /* Maintain request queue statistics. */
+ ascq->q_tot_cnt[tid]++;
+ ascq->q_cur_cnt[tid]++;
+ if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
+ ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
+ ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
+ tid, ascq->q_max_cnt[tid]);
+ }
+ REQPTIME(reqp) = REQTIMESTAMP();
#endif /* ADVANSYS_STATS */
- ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong) reqp);
- return;
+ ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
+ return;
}
/*
@@ -7180,31 +6001,30 @@ asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
*
* 'REQPNEXT(reqp)' returns reqp's next pointer.
*/
-STATIC REQP
-asc_dequeue(asc_queue_t *ascq, int tid)
+static REQP asc_dequeue(asc_queue_t *ascq, int tid)
{
- REQP reqp;
-
- ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if ((reqp = ascq->q_first[tid]) != NULL) {
- ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
+ REQP reqp;
+
+ ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+ if ((reqp = ascq->q_first[tid]) != NULL) {
+ ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
+ ascq->q_first[tid] = REQPNEXT(reqp);
+ /* If the queue is empty, clear its bit and the last pointer. */
+ if (ascq->q_first[tid] == NULL) {
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+ ASC_ASSERT(ascq->q_last[tid] == reqp);
+ ascq->q_last[tid] = NULL;
+ }
#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_cur_cnt[tid]--;
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
- REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
+ /* Maintain request queue statistics. */
+ ascq->q_cur_cnt[tid]--;
+ ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+ REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
#endif /* ADVANSYS_STATS */
- }
- ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong) reqp);
- return reqp;
+ }
+ ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
+ return reqp;
}
/*
@@ -7227,74 +6047,76 @@ asc_dequeue(asc_queue_t *ascq, int tid)
* Unfortunately collecting queuing time statistics adds overhead to
* the function that isn't inherent to the function's algorithm.
*/
-STATIC REQP
-asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
{
- REQP firstp, lastp;
- int i;
-
- ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
- ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
-
- /*
- * If 'tid' is not ASC_TID_ALL, return requests only for
- * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
- * requests for all tids.
- */
- if (tid != ASC_TID_ALL) {
- /* Return all requests for the specified 'tid'. */
- if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
- /* List is empty; Set first and last return pointers to NULL. */
- firstp = lastp = NULL;
- } else {
- firstp = ascq->q_first[tid];
- lastp = ascq->q_last[tid];
- ascq->q_first[tid] = ascq->q_last[tid] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+ REQP firstp, lastp;
+ int i;
+
+ ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
+ ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
+
+ /*
+ * If 'tid' is not ASC_TID_ALL, return requests only for
+ * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+ * requests for all tids.
+ */
+ if (tid != ASC_TID_ALL) {
+ /* Return all requests for the specified 'tid'. */
+ if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
+ /* List is empty; Set first and last return pointers to NULL. */
+ firstp = lastp = NULL;
+ } else {
+ firstp = ascq->q_first[tid];
+ lastp = ascq->q_last[tid];
+ ascq->q_first[tid] = ascq->q_last[tid] = NULL;
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- ascq->q_cur_cnt[tid] = 0;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
- }
- }
+ {
+ REQP reqp;
+ ascq->q_cur_cnt[tid] = 0;
+ for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+ REQTIMESTAT("asc_dequeue_list", ascq,
+ reqp, tid);
+ }
+ }
#endif /* ADVANSYS_STATS */
- }
- } else {
- /* Return all requests for all tids. */
- firstp = lastp = NULL;
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if (firstp == NULL) {
- firstp = ascq->q_first[i];
- lastp = ascq->q_last[i];
- } else {
- ASC_ASSERT(lastp != NULL);
- lastp->host_scribble = (unsigned char *)ascq->q_first[i];
- lastp = ascq->q_last[i];
- }
- ascq->q_first[i] = ascq->q_last[i] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+ }
+ } else {
+ /* Return all requests for all tids. */
+ firstp = lastp = NULL;
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
+ if (firstp == NULL) {
+ firstp = ascq->q_first[i];
+ lastp = ascq->q_last[i];
+ } else {
+ ASC_ASSERT(lastp != NULL);
+ lastp->host_scribble =
+ (unsigned char *)ascq->q_first[i];
+ lastp = ascq->q_last[i];
+ }
+ ascq->q_first[i] = ascq->q_last[i] = NULL;
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
#ifdef ADVANSYS_STATS
- ascq->q_cur_cnt[i] = 0;
+ ascq->q_cur_cnt[i] = 0;
#endif /* ADVANSYS_STATS */
- }
- }
+ }
+ }
#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->device->id);
- }
- }
+ {
+ REQP reqp;
+ for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+ REQTIMESTAT("asc_dequeue_list", ascq, reqp,
+ reqp->device->id);
+ }
+ }
#endif /* ADVANSYS_STATS */
- }
- if (lastpp) {
- *lastpp = lastp;
- }
- ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong) firstp);
- return firstp;
+ }
+ if (lastpp) {
+ *lastpp = lastp;
+ }
+ ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
+ return firstp;
}
/*
@@ -7307,67 +6129,67 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
* Return ASC_TRUE if the command was found and removed,
* otherwise return ASC_FALSE.
*/
-STATIC int
-asc_rmqueue(asc_queue_t *ascq, REQP reqp)
+static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
{
- REQP currp, prevp;
- int tid;
- int ret = ASC_FALSE;
-
- ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
- (ulong) ascq, (ulong) reqp);
- ASC_ASSERT(reqp != NULL);
-
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-
- /*
- * Handle the common case of 'reqp' being the first
- * entry on the queue.
- */
- if (reqp == ascq->q_first[tid]) {
- ret = ASC_TRUE;
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is now empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
- } else if (ascq->q_first[tid] != NULL) {
- ASC_ASSERT(ascq->q_last[tid] != NULL);
- /*
- * Because the case of 'reqp' being the first entry has been
- * handled above and it is known the queue is not empty, if
- * 'reqp' is found on the queue it is guaranteed the queue will
- * not become empty and that 'q_first[tid]' will not be changed.
- *
- * Set 'prevp' to the first entry, 'currp' to the second entry,
- * and search for 'reqp'.
- */
- for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
- currp; prevp = currp, currp = REQPNEXT(currp)) {
- if (currp == reqp) {
- ret = ASC_TRUE;
- prevp->host_scribble = (unsigned char *)REQPNEXT(currp);
- reqp->host_scribble = NULL;
- if (ascq->q_last[tid] == reqp) {
- ascq->q_last[tid] = prevp;
- }
- break;
- }
- }
- }
+ REQP currp, prevp;
+ int tid;
+ int ret = ASC_FALSE;
+
+ ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
+ (ulong)ascq, (ulong)reqp);
+ ASC_ASSERT(reqp != NULL);
+
+ tid = REQPTID(reqp);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+
+ /*
+ * Handle the common case of 'reqp' being the first
+ * entry on the queue.
+ */
+ if (reqp == ascq->q_first[tid]) {
+ ret = ASC_TRUE;
+ ascq->q_first[tid] = REQPNEXT(reqp);
+ /* If the queue is now empty, clear its bit and the last pointer. */
+ if (ascq->q_first[tid] == NULL) {
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+ ASC_ASSERT(ascq->q_last[tid] == reqp);
+ ascq->q_last[tid] = NULL;
+ }
+ } else if (ascq->q_first[tid] != NULL) {
+ ASC_ASSERT(ascq->q_last[tid] != NULL);
+ /*
+ * Because the case of 'reqp' being the first entry has been
+ * handled above and it is known the queue is not empty, if
+ * 'reqp' is found on the queue it is guaranteed the queue will
+ * not become empty and that 'q_first[tid]' will not be changed.
+ *
+ * Set 'prevp' to the first entry, 'currp' to the second entry,
+ * and search for 'reqp'.
+ */
+ for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+ currp; prevp = currp, currp = REQPNEXT(currp)) {
+ if (currp == reqp) {
+ ret = ASC_TRUE;
+ prevp->host_scribble =
+ (unsigned char *)REQPNEXT(currp);
+ reqp->host_scribble = NULL;
+ if (ascq->q_last[tid] == reqp) {
+ ascq->q_last[tid] = prevp;
+ }
+ break;
+ }
+ }
+ }
#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- if (ret == ASC_TRUE) {
- ascq->q_cur_cnt[tid]--;
- REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
- }
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+ /* Maintain request queue statistics. */
+ if (ret == ASC_TRUE) {
+ ascq->q_cur_cnt[tid]--;
+ REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
+ }
+ ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
#endif /* ADVANSYS_STATS */
- ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong) reqp, ret);
- return ret;
+ ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
+ return ret;
}
/*
@@ -7375,37 +6197,38 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
*
* Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
*/
-STATIC void
-asc_execute_queue(asc_queue_t *ascq)
+static void asc_execute_queue(asc_queue_t *ascq)
{
- ADV_SCSI_BIT_ID_TYPE scan_tidmask;
- REQP reqp;
- int i;
-
- ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong) ascq);
- /*
- * Execute queued commands for devices attached to
- * the current board in round-robin fashion.
- */
- scan_tidmask = ascq->q_tidmask;
- do {
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if ((reqp = asc_dequeue(ascq, i)) == NULL) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- } else if (asc_execute_scsi_cmnd((struct scsi_cmnd *) reqp)
- == ASC_BUSY) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- /*
- * The request returned ASC_BUSY. Enqueue at the front of
- * target's waiting list to maintain correct ordering.
- */
- asc_enqueue(ascq, reqp, ASC_FRONT);
- }
- }
- }
- } while (scan_tidmask);
- return;
+ ADV_SCSI_BIT_ID_TYPE scan_tidmask;
+ REQP reqp;
+ int i;
+
+ ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
+ /*
+ * Execute queued commands for devices attached to
+ * the current board in round-robin fashion.
+ */
+ scan_tidmask = ascq->q_tidmask;
+ do {
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
+ if ((reqp = asc_dequeue(ascq, i)) == NULL) {
+ scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+ } else
+ if (asc_execute_scsi_cmnd
+ ((struct scsi_cmnd *)reqp)
+ == ASC_BUSY) {
+ scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+ /*
+ * The request returned ASC_BUSY. Enqueue at the front of
+ * target's waiting list to maintain correct ordering.
+ */
+ asc_enqueue(ascq, reqp, ASC_FRONT);
+ }
+ }
+ }
+ } while (scan_tidmask);
+ return;
}
#ifdef CONFIG_PROC_FS
@@ -7420,102 +6243,102 @@ asc_execute_queue(asc_queue_t *ascq)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- int chip_scsi_id;
- int i;
-
- boardp = ASC_BOARDP(shp);
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
-"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no);
- ASC_PRT_NEXT();
-
- if (ASC_NARROW_BOARD(boardp)) {
- chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
- } else {
- chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
- }
+ asc_board_t *boardp;
+ int leftlen;
+ int totlen;
+ int len;
+ int chip_scsi_id;
+ int i;
+
+ boardp = ASC_BOARDP(shost);
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nDevice Information for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+ } else {
+ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ }
- len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %X,", i);
- ASC_PRT_NEXT();
- }
- }
- len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
- ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
+ len = asc_prt_line(cp, leftlen, " %X,", i);
+ ASC_PRT_NEXT();
+ }
+ }
+ len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
+ ASC_PRT_NEXT();
- return totlen;
+ return totlen;
}
/*
* Display Wide Board BIOS Information.
*/
-STATIC int
-asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- ushort major, minor, letter;
-
- boardp = ASC_BOARDP(shp);
- leftlen = cplen;
- totlen = len = 0;
+ asc_board_t *boardp;
+ int leftlen;
+ int totlen;
+ int len;
+ ushort major, minor, letter;
+
+ boardp = ASC_BOARDP(shost);
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+ ASC_PRT_NEXT();
+
+ /*
+ * If the BIOS saved a valid signature, then fill in
+ * the BIOS code segment base address.
+ */
+ if (boardp->bios_signature != 0x55AA) {
+ len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
+ ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen,
+ "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+ ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen,
+ "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
+ ASC_PRT_NEXT();
+ } else {
+ major = (boardp->bios_version >> 12) & 0xF;
+ minor = (boardp->bios_version >> 8) & 0xF;
+ letter = (boardp->bios_version & 0xFF);
- len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
- ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+ major, minor,
+ letter >= 26 ? '?' : letter + 'A');
+ ASC_PRT_NEXT();
- /*
- * If the BIOS saved a valid signature, then fill in
- * the BIOS code segment base address.
- */
- if (boardp->bios_signature != 0x55AA) {
- len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
-"BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
-"can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
- ASC_PRT_NEXT();
- } else {
- major = (boardp->bios_version >> 12) & 0xF;
- minor = (boardp->bios_version >> 8) & 0xF;
- letter = (boardp->bios_version & 0xFF);
-
- len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
- major, minor, letter >= 26 ? '?' : letter + 'A');
- ASC_PRT_NEXT();
-
- /*
- * Current available ROM BIOS release is 3.1I for UW
- * and 3.2I for U2W. This code doesn't differentiate
- * UW and U2W boards.
- */
- if (major < 3 || (major <= 3 && minor < 1) ||
- (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) {
- len = asc_prt_line(cp, leftlen,
-"Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
-"ftp://ftp.connectcom.net/pub\n");
- ASC_PRT_NEXT();
- }
- }
+ /*
+ * Current available ROM BIOS release is 3.1I for UW
+ * and 3.2I for U2W. This code doesn't differentiate
+ * UW and U2W boards.
+ */
+ if (major < 3 || (major <= 3 && minor < 1) ||
+ (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
+ len = asc_prt_line(cp, leftlen,
+ "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
+ ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen,
+ "ftp://ftp.connectcom.net/pub\n");
+ ASC_PRT_NEXT();
+ }
+ }
- return totlen;
+ return totlen;
}
/*
@@ -7541,80 +6364,79 @@ asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
*
* Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
*/
-STATIC int
-asc_get_eeprom_string(ushort *serialnum, uchar *cp)
+static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
{
- ushort w, num;
-
- if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) {
- return ASC_FALSE;
- } else {
- /*
- * First word - 6 digits.
- */
- w = serialnum[0];
-
- /* Product type - 1st digit. */
- if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
- /* Product type is P=Prototype */
- *cp += 0x8;
- }
- cp++;
-
- /* Manufacturing location - 2nd digit. */
- *cp++ = 'A' + ((w & 0x1C00) >> 10);
-
- /* Product ID - 3rd, 4th digits. */
- num = w & 0x3FF;
- *cp++ = '0' + (num / 100);
- num %= 100;
- *cp++ = '0' + (num / 10);
-
- /* Product revision - 5th digit. */
- *cp++ = 'A' + (num % 10);
-
- /*
- * Second word
- */
- w = serialnum[1];
-
- /*
- * Year - 6th digit.
- *
- * If bit 15 of third word is set, then the
- * last digit of the year is greater than 7.
- */
- if (serialnum[2] & 0x8000) {
- *cp++ = '8' + ((w & 0x1C0) >> 6);
- } else {
- *cp++ = '0' + ((w & 0x1C0) >> 6);
- }
-
- /* Week of year - 7th, 8th digits. */
- num = w & 0x003F;
- *cp++ = '0' + num / 10;
- num %= 10;
- *cp++ = '0' + num;
-
- /*
- * Third word
- */
- w = serialnum[2] & 0x7FFF;
-
- /* Serial number - 9th digit. */
- *cp++ = 'A' + (w / 1000);
-
- /* 10th, 11th, 12th digits. */
- num = w % 1000;
- *cp++ = '0' + num / 100;
- num %= 100;
- *cp++ = '0' + num / 10;
- num %= 10;
- *cp++ = '0' + num;
-
- *cp = '\0'; /* Null Terminate the string. */
- return ASC_TRUE;
- }
+ ushort w, num;
+
+ if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
+ return ASC_FALSE;
+ } else {
+ /*
+ * First word - 6 digits.
+ */
+ w = serialnum[0];
+
+ /* Product type - 1st digit. */
+ if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
+ /* Product type is P=Prototype */
+ *cp += 0x8;
+ }
+ cp++;
+
+ /* Manufacturing location - 2nd digit. */
+ *cp++ = 'A' + ((w & 0x1C00) >> 10);
+
+ /* Product ID - 3rd, 4th digits. */
+ num = w & 0x3FF;
+ *cp++ = '0' + (num / 100);
+ num %= 100;
+ *cp++ = '0' + (num / 10);
+
+ /* Product revision - 5th digit. */
+ *cp++ = 'A' + (num % 10);
+
+ /*
+ * Second word
+ */
+ w = serialnum[1];
+
+ /*
+ * Year - 6th digit.
+ *
+ * If bit 15 of third word is set, then the
+ * last digit of the year is greater than 7.
+ */
+ if (serialnum[2] & 0x8000) {
+ *cp++ = '8' + ((w & 0x1C0) >> 6);
+ } else {
+ *cp++ = '0' + ((w & 0x1C0) >> 6);
+ }
+
+ /* Week of year - 7th, 8th digits. */
+ num = w & 0x003F;
+ *cp++ = '0' + num / 10;
+ num %= 10;
+ *cp++ = '0' + num;
+
+ /*
+ * Third word
+ */
+ w = serialnum[2] & 0x7FFF;
+
+ /* Serial number - 9th digit. */
+ *cp++ = 'A' + (w / 1000);
+
+ /* 10th, 11th, 12th digits. */
+ num = w % 1000;
+ *cp++ = '0' + num / 100;
+ num %= 100;
+ *cp++ = '0' + num / 10;
+ num %= 10;
+ *cp++ = '0' + num;
+
+ *cp = '\0'; /* Null Terminate the string. */
+ return ASC_TRUE;
+ }
}
/*
@@ -7628,122 +6450,127 @@ asc_get_eeprom_string(ushort *serialnum, uchar *cp)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- int leftlen;
- int totlen;
- int len;
- ASCEEP_CONFIG *ep;
- int i;
+ asc_board_t *boardp;
+ ASC_DVC_VAR *asc_dvc_varp;
+ int leftlen;
+ int totlen;
+ int len;
+ ASCEEP_CONFIG *ep;
+ int i;
#ifdef CONFIG_ISA
- int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+ int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
#endif /* CONFIG_ISA */
- uchar serialstr[13];
-
- boardp = ASC_BOARDP(shp);
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- ep = &boardp->eep_config.asc_eep;
-
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
-"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
- ASC_PRT_NEXT();
-
- if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) ==
- ASC_TRUE) {
- len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
- ASC_PRT_NEXT();
- } else {
- if (ep->adapter_info[5] == 0xBB) {
- len = asc_prt_line(cp, leftlen,
- " Default Settings Used for EEPROM-less Adapter.\n");
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Serial Number Signature Not Present.\n");
- ASC_PRT_NEXT();
- }
- }
+ uchar serialstr[13];
+
+ boardp = ASC_BOARDP(shost);
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ ep = &boardp->eep_config.asc_eep;
+
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
+ == ASC_TRUE) {
+ len =
+ asc_prt_line(cp, leftlen, " Serial Number: %s\n",
+ serialstr);
+ ASC_PRT_NEXT();
+ } else {
+ if (ep->adapter_info[5] == 0xBB) {
+ len = asc_prt_line(cp, leftlen,
+ " Default Settings Used for EEPROM-less Adapter.\n");
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ " Serial Number Signature Not Present.\n");
+ ASC_PRT_NEXT();
+ }
+ }
- len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" cntl 0x%x, no_scam 0x%x\n",
- ep->cntl, ep->no_scam);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Target ID: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d", i);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Disconnects: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Command Queuing: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Start Motor: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
+ ep->max_tag_qng);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Target ID: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %d", i);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Disconnects: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->
+ disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Command Queuing: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->
+ use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Start Motor: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->
+ start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->
+ init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
#ifdef CONFIG_ISA
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- len = asc_prt_line(cp, leftlen,
-" Host ISA DMA speed: %d MB/S\n",
- isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
- ASC_PRT_NEXT();
- }
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ len = asc_prt_line(cp, leftlen,
+ " Host ISA DMA speed: %d MB/S\n",
+ isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
+ ASC_PRT_NEXT();
+ }
#endif /* CONFIG_ISA */
- return totlen;
+ return totlen;
}
/*
@@ -7757,300 +6584,282 @@ asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- ADV_DVC_VAR *adv_dvc_varp;
- int leftlen;
- int totlen;
- int len;
- int i;
- char *termstr;
- uchar serialstr[13];
- ADVEEP_3550_CONFIG *ep_3550 = NULL;
- ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
- ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
- ushort word;
- ushort *wordp;
- ushort sdtr_speed = 0;
-
- boardp = ASC_BOARDP(shp);
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- ep_3550 = &boardp->eep_config.adv_3550_eep;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
- } else
- {
- ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
- }
+ asc_board_t *boardp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ int leftlen;
+ int totlen;
+ int len;
+ int i;
+ char *termstr;
+ uchar serialstr[13];
+ ADVEEP_3550_CONFIG *ep_3550 = NULL;
+ ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
+ ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
+ ushort word;
+ ushort *wordp;
+ ushort sdtr_speed = 0;
+
+ boardp = ASC_BOARDP(shost);
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ ep_3550 = &boardp->eep_config.adv_3550_eep;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+ } else {
+ ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+ }
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
-"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
- ASC_PRT_NEXT();
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- wordp = &ep_3550->serial_number_word1;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- wordp = &ep_38C0800->serial_number_word1;
- } else
- {
- wordp = &ep_38C1600->serial_number_word1;
- }
+ leftlen = cplen;
+ totlen = len = 0;
- if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
- len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Serial Number Signature Not Present.\n");
- ASC_PRT_NEXT();
- }
+ len = asc_prt_line(cp, leftlen,
+ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
- ep_3550->max_dvc_qng);
- ASC_PRT_NEXT();
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
- ep_38C0800->max_dvc_qng);
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng,
- ep_38C1600->max_dvc_qng);
- ASC_PRT_NEXT();
- }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->termination;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->termination_lvd;
- } else
- {
- word = ep_38C1600->termination_lvd;
- }
- switch (word) {
- case 1:
- termstr = "Low Off/High Off";
- break;
- case 2:
- termstr = "Low Off/High On";
- break;
- case 3:
- termstr = "Low On/High On";
- break;
- default:
- case 0:
- termstr = "Automatic";
- break;
- }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ wordp = &ep_3550->serial_number_word1;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ wordp = &ep_38C0800->serial_number_word1;
+ } else {
+ wordp = &ep_38C1600->serial_number_word1;
+ }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: 0x%x\n",
- ep_3550->termination, termstr, ep_3550->bios_ctrl);
- ASC_PRT_NEXT();
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: 0x%x\n",
- ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: 0x%x\n",
- ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl);
- ASC_PRT_NEXT();
- }
+ if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
+ len =
+ asc_prt_line(cp, leftlen, " Serial Number: %s\n",
+ serialstr);
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ " Serial Number Signature Not Present.\n");
+ ASC_PRT_NEXT();
+ }
- len = asc_prt_line(cp, leftlen,
-" Target ID: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %X", i);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->disc_enable;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->disc_enable;
- } else
- {
- word = ep_38C1600->disc_enable;
- }
- len = asc_prt_line(cp, leftlen,
-" Disconnects: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->tagqng_able;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->tagqng_able;
- } else
- {
- word = ep_38C1600->tagqng_able;
- }
- len = asc_prt_line(cp, leftlen,
-" Command Queuing: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->start_motor;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->start_motor;
- } else
- {
- word = ep_38C1600->start_motor;
- }
- len = asc_prt_line(cp, leftlen,
-" Start Motor: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
- }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ len = asc_prt_line(cp, leftlen,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_3550->adapter_scsi_id,
+ ep_3550->max_host_qng, ep_3550->max_dvc_qng);
+ ASC_PRT_NEXT();
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ len = asc_prt_line(cp, leftlen,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_38C0800->adapter_scsi_id,
+ ep_38C0800->max_host_qng,
+ ep_38C0800->max_dvc_qng);
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_38C1600->adapter_scsi_id,
+ ep_38C1600->max_host_qng,
+ ep_38C1600->max_dvc_qng);
+ ASC_PRT_NEXT();
+ }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ word = ep_3550->termination;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ word = ep_38C0800->termination_lvd;
+ } else {
+ word = ep_38C1600->termination_lvd;
+ }
+ switch (word) {
+ case 1:
+ termstr = "Low Off/High Off";
+ break;
+ case 2:
+ termstr = "Low Off/High On";
+ break;
+ case 3:
+ termstr = "Low On/High On";
+ break;
+ default:
+ case 0:
+ termstr = "Automatic";
+ break;
+ }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- len = asc_prt_line(cp, leftlen,
-" Ultra Transfer: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
- }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ len = asc_prt_line(cp, leftlen,
+ " termination: %u (%s), bios_ctrl: 0x%x\n",
+ ep_3550->termination, termstr,
+ ep_3550->bios_ctrl);
+ ASC_PRT_NEXT();
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ len = asc_prt_line(cp, leftlen,
+ " termination: %u (%s), bios_ctrl: 0x%x\n",
+ ep_38C0800->termination_lvd, termstr,
+ ep_38C0800->bios_ctrl);
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ " termination: %u (%s), bios_ctrl: 0x%x\n",
+ ep_38C1600->termination_lvd, termstr,
+ ep_38C1600->bios_ctrl);
+ ASC_PRT_NEXT();
+ }
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
- {
- word = ep_3550->wdtr_able;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
- {
- word = ep_38C0800->wdtr_able;
- } else
- {
- word = ep_38C1600->wdtr_able;
- }
- len = asc_prt_line(cp, leftlen,
-" Wide Transfer: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
- adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600)
- {
- len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer Speed (Mhz):\n ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- char *speed_str;
-
- if (i == 0)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed1;
- } else if (i == 4)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed2;
- } else if (i == 8)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed3;
- } else if (i == 12)
- {
- sdtr_speed = adv_dvc_varp->sdtr_speed4;
- }
- switch (sdtr_speed & ADV_MAX_TID)
- {
- case 0: speed_str = "Off"; break;
- case 1: speed_str = " 5"; break;
- case 2: speed_str = " 10"; break;
- case 3: speed_str = " 20"; break;
- case 4: speed_str = " 40"; break;
- case 5: speed_str = " 80"; break;
- default: speed_str = "Unk"; break;
- }
- len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
- ASC_PRT_NEXT();
- if (i == 7)
- {
- len = asc_prt_line(cp, leftlen, "\n ");
- ASC_PRT_NEXT();
- }
- sdtr_speed >>= 4;
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
- }
+ len = asc_prt_line(cp, leftlen, " Target ID: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %X", i);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ word = ep_3550->disc_enable;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ word = ep_38C0800->disc_enable;
+ } else {
+ word = ep_38C1600->disc_enable;
+ }
+ len = asc_prt_line(cp, leftlen, " Disconnects: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ word = ep_3550->tagqng_able;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ word = ep_38C0800->tagqng_able;
+ } else {
+ word = ep_38C1600->tagqng_able;
+ }
+ len = asc_prt_line(cp, leftlen, " Command Queuing: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ word = ep_3550->start_motor;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ word = ep_38C0800->start_motor;
+ } else {
+ word = ep_38C1600->start_motor;
+ }
+ len = asc_prt_line(cp, leftlen, " Start Motor: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep_3550->
+ sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
+ 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+ }
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep_3550->
+ ultra_able & ADV_TID_TO_TIDMASK(i))
+ ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+ }
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ word = ep_3550->wdtr_able;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ word = ep_38C0800->wdtr_able;
+ } else {
+ word = ep_38C1600->wdtr_able;
+ }
+ len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
+ adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
+ len = asc_prt_line(cp, leftlen,
+ " Synchronous Transfer Speed (Mhz):\n ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ char *speed_str;
+
+ if (i == 0) {
+ sdtr_speed = adv_dvc_varp->sdtr_speed1;
+ } else if (i == 4) {
+ sdtr_speed = adv_dvc_varp->sdtr_speed2;
+ } else if (i == 8) {
+ sdtr_speed = adv_dvc_varp->sdtr_speed3;
+ } else if (i == 12) {
+ sdtr_speed = adv_dvc_varp->sdtr_speed4;
+ }
+ switch (sdtr_speed & ADV_MAX_TID) {
+ case 0:
+ speed_str = "Off";
+ break;
+ case 1:
+ speed_str = " 5";
+ break;
+ case 2:
+ speed_str = " 10";
+ break;
+ case 3:
+ speed_str = " 20";
+ break;
+ case 4:
+ speed_str = " 40";
+ break;
+ case 5:
+ speed_str = " 80";
+ break;
+ default:
+ speed_str = "Unk";
+ break;
+ }
+ len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+ ASC_PRT_NEXT();
+ if (i == 7) {
+ len = asc_prt_line(cp, leftlen, "\n ");
+ ASC_PRT_NEXT();
+ }
+ sdtr_speed >>= 4;
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+ }
- return totlen;
+ return totlen;
}
/*
@@ -8062,60 +6871,60 @@ asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- int chip_scsi_id;
-
- boardp = ASC_BOARDP(shp);
-
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
-"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
- shp->host_no);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
- shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
- shp->max_channel);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
- shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
- shp->cmd_per_lun);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" unchecked_isa_dma %d, use_clustering %d\n",
- shp->unchecked_isa_dma, shp->use_clustering);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
- boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port);
- ASC_PRT_NEXT();
-
- /* 'shp->n_io_port' may be truncated because it is only one byte. */
- len = asc_prt_line(cp, leftlen,
-" io_port 0x%x, n_io_port 0x%x\n",
- shp->io_port, shp->n_io_port);
- ASC_PRT_NEXT();
-
- if (ASC_NARROW_BOARD(boardp)) {
- chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
- } else {
- chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
- }
+ asc_board_t *boardp;
+ int leftlen;
+ int totlen;
+ int len;
+ int chip_scsi_id;
+
+ boardp = ASC_BOARDP(shost);
+
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+ shost->host_busy, shost->last_reset, shost->max_id,
+ shost->max_lun, shost->max_channel);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+ shost->unique_id, shost->can_queue, shost->this_id,
+ shost->sg_tablesize, shost->cmd_per_lun);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " unchecked_isa_dma %d, use_clustering %d\n",
+ shost->unchecked_isa_dma, shost->use_clustering);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
+ boardp->flags, boardp->last_reset, jiffies,
+ boardp->asc_n_io_port);
+ ASC_PRT_NEXT();
+
+ /* 'shost->n_io_port' may be truncated because it is only one byte. */
+ len = asc_prt_line(cp, leftlen,
+ " io_port 0x%x, n_io_port 0x%x\n",
+ shost->io_port, shost->n_io_port);
+ ASC_PRT_NEXT();
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+ } else {
+ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ }
- return totlen;
+ return totlen;
}
/*
@@ -8129,178 +6938,181 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- int chip_scsi_id;
- int leftlen;
- int totlen;
- int len;
- ASC_DVC_VAR *v;
- ASC_DVC_CFG *c;
- int i;
- int renegotiate = 0;
-
- boardp = ASC_BOARDP(shp);
- v = &boardp->dvc_var.asc_dvc_var;
- c = &boardp->dvc_cfg.asc_dvc_cfg;
- chip_scsi_id = c->chip_scsi_id;
-
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
-"\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
- shp->host_no);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
- c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" mcode_version 0x%x, err_code %u\n",
- c->mcode_version, v->err_code);
- ASC_PRT_NEXT();
-
- /* Current number of commands waiting for the host. */
- len = asc_prt_line(cp, leftlen,
-" Total Command Pending: %d\n", v->cur_total_qng);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Command Queuing:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- /* Current number of commands waiting for a device. */
- len = asc_prt_line(cp, leftlen,
-" Command Queue Pending:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- /* Current limit on number of commands that can be sent to a device. */
- len = asc_prt_line(cp, leftlen,
-" Command Queue Limit:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- /* Indicate whether the device has returned queue full status. */
- len = asc_prt_line(cp, leftlen,
-" Command Queue Full:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %X:Y-%d",
- i, boardp->queue_full_cnt[i]);
- } else {
- len = asc_prt_line(cp, leftlen, " %X:N", i);
- }
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- for (i = 0; i <= ASC_MAX_TID; i++) {
- uchar syn_period_ix;
-
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
- ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- len = asc_prt_line(cp, leftlen, " %X:", i);
- ASC_PRT_NEXT();
-
- if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
- {
- len = asc_prt_line(cp, leftlen, " Asynchronous");
- ASC_PRT_NEXT();
- } else
- {
- syn_period_ix =
- (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
-
- len = asc_prt_line(cp, leftlen,
- " Transfer Period Factor: %d (%d.%d Mhz),",
- v->sdtr_period_tbl[syn_period_ix],
- 250 / v->sdtr_period_tbl[syn_period_ix],
- ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
- boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
- ASC_PRT_NEXT();
- }
-
- if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*\n");
- renegotiate = 1;
- } else
- {
- len = asc_prt_line(cp, leftlen, "\n");
- }
- ASC_PRT_NEXT();
- }
+ asc_board_t *boardp;
+ int chip_scsi_id;
+ int leftlen;
+ int totlen;
+ int len;
+ ASC_DVC_VAR *v;
+ ASC_DVC_CFG *c;
+ int i;
+ int renegotiate = 0;
+
+ boardp = ASC_BOARDP(shost);
+ v = &boardp->dvc_var.asc_dvc_var;
+ c = &boardp->dvc_cfg.asc_dvc_cfg;
+ chip_scsi_id = c->chip_scsi_id;
+
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
+ c->chip_version, c->lib_version, c->lib_serial_no,
+ c->mcode_date);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " mcode_version 0x%x, err_code %u\n",
+ c->mcode_version, v->err_code);
+ ASC_PRT_NEXT();
+
+ /* Current number of commands waiting for the host. */
+ len = asc_prt_line(cp, leftlen,
+ " Total Command Pending: %d\n", v->cur_total_qng);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Command Queuing:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i,
+ (v->
+ use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
+ 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ /* Current number of commands waiting for a device. */
+ len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ /* Current limit on number of commands that can be sent to a device. */
+ len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ /* Indicate whether the device has returned queue full status. */
+ len = asc_prt_line(cp, leftlen, " Command Queue Full:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
+ len = asc_prt_line(cp, leftlen, " %X:Y-%d",
+ i, boardp->queue_full_cnt[i]);
+ } else {
+ len = asc_prt_line(cp, leftlen, " %X:N", i);
+ }
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i,
+ (v->
+ sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ uchar syn_period_ix;
+
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+ ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:", i);
+ ASC_PRT_NEXT();
+
+ if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
+ len = asc_prt_line(cp, leftlen, " Asynchronous");
+ ASC_PRT_NEXT();
+ } else {
+ syn_period_ix =
+ (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
+ 1);
+
+ len = asc_prt_line(cp, leftlen,
+ " Transfer Period Factor: %d (%d.%d Mhz),",
+ v->sdtr_period_tbl[syn_period_ix],
+ 250 /
+ v->sdtr_period_tbl[syn_period_ix],
+ ASC_TENTHS(250,
+ v->
+ sdtr_period_tbl
+ [syn_period_ix]));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+ boardp->
+ sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+ ASC_PRT_NEXT();
+ }
+
+ if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+ len = asc_prt_line(cp, leftlen, "*\n");
+ renegotiate = 1;
+ } else {
+ len = asc_prt_line(cp, leftlen, "\n");
+ }
+ ASC_PRT_NEXT();
+ }
- if (renegotiate)
- {
- len = asc_prt_line(cp, leftlen,
- " * = Re-negotiation pending before next command.\n");
- ASC_PRT_NEXT();
- }
+ if (renegotiate) {
+ len = asc_prt_line(cp, leftlen,
+ " * = Re-negotiation pending before next command.\n");
+ ASC_PRT_NEXT();
+ }
- return totlen;
+ return totlen;
}
/*
@@ -8314,237 +7126,242 @@ asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
- int leftlen;
- int totlen;
- int len;
- int i;
- ADV_DVC_VAR *v;
- ADV_DVC_CFG *c;
- AdvPortAddr iop_base;
- ushort chip_scsi_id;
- ushort lramword;
- uchar lrambyte;
- ushort tagqng_able;
- ushort sdtr_able, wdtr_able;
- ushort wdtr_done, sdtr_done;
- ushort period = 0;
- int renegotiate = 0;
-
- boardp = ASC_BOARDP(shp);
- v = &boardp->dvc_var.adv_dvc_var;
- c = &boardp->dvc_cfg.adv_dvc_cfg;
- iop_base = v->iop_base;
- chip_scsi_id = v->chip_scsi_id;
-
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
-"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
- shp->host_no);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" iop_base 0x%lx, cable_detect: %X, err_code %u\n",
- v->iop_base,
- AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
- v->err_code);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
- c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
- ASC_PRT_NEXT();
-
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- len = asc_prt_line(cp, leftlen,
-" Queuing Enabled:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Queue Limit:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte);
-
- len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" Command Pending:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte);
-
- len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- len = asc_prt_line(cp, leftlen,
-" Wide Enabled:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
- len = asc_prt_line(cp, leftlen,
-" Transfer Bit Width:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
- lramword);
-
- len = asc_prt_line(cp, leftlen, " %X:%d",
- i, (lramword & 0x8000) ? 16 : 8);
- ASC_PRT_NEXT();
-
- if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
- (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*");
- ASC_PRT_NEXT();
- renegotiate = 1;
- }
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- len = asc_prt_line(cp, leftlen,
-" Synchronous Enabled:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
- for (i = 0; i <= ADV_MAX_TID; i++) {
-
- AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
- lramword);
- lramword &= ~0x8000;
-
- if ((chip_scsi_id == i) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
- ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
- continue;
- }
-
- len = asc_prt_line(cp, leftlen, " %X:", i);
- ASC_PRT_NEXT();
-
- if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
- {
- len = asc_prt_line(cp, leftlen, " Asynchronous");
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
- ASC_PRT_NEXT();
-
- if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
- {
- len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
- ASC_PRT_NEXT();
- } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
- {
- len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
- ASC_PRT_NEXT();
- } else /* 20 Mhz or below. */
- {
- period = (((lramword >> 8) * 25) + 50)/4;
-
- if (period == 0) /* Should never happen. */
- {
- len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
- ASC_PRT_NEXT();
- } else
- {
- len = asc_prt_line(cp, leftlen,
- "%d (%d.%d Mhz),",
- period, 250/period, ASC_TENTHS(250, period));
- ASC_PRT_NEXT();
- }
- }
-
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
- lramword & 0x1F);
- ASC_PRT_NEXT();
- }
-
- if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*\n");
- renegotiate = 1;
- } else
- {
- len = asc_prt_line(cp, leftlen, "\n");
- }
- ASC_PRT_NEXT();
- }
+ asc_board_t *boardp;
+ int leftlen;
+ int totlen;
+ int len;
+ int i;
+ ADV_DVC_VAR *v;
+ ADV_DVC_CFG *c;
+ AdvPortAddr iop_base;
+ ushort chip_scsi_id;
+ ushort lramword;
+ uchar lrambyte;
+ ushort tagqng_able;
+ ushort sdtr_able, wdtr_able;
+ ushort wdtr_done, sdtr_done;
+ ushort period = 0;
+ int renegotiate = 0;
+
+ boardp = ASC_BOARDP(shost);
+ v = &boardp->dvc_var.adv_dvc_var;
+ c = &boardp->dvc_cfg.adv_dvc_cfg;
+ iop_base = v->iop_base;
+ chip_scsi_id = v->chip_scsi_id;
+
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
+ v->iop_base,
+ AdvReadWordRegister(iop_base,
+ IOPW_SCSI_CFG1) & CABLE_DETECT,
+ v->err_code);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
+ c->chip_version, c->lib_version, c->mcode_date,
+ c->mcode_version);
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i,
+ (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Queue Limit:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
+ lrambyte);
+
+ len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " Command Pending:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
+ lrambyte);
+
+ len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ len = asc_prt_line(cp, leftlen, " Wide Enabled:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i,
+ (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
+ len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ AdvReadWordLram(iop_base,
+ ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+ lramword);
+
+ len = asc_prt_line(cp, leftlen, " %X:%d",
+ i, (lramword & 0x8000) ? 16 : 8);
+ ASC_PRT_NEXT();
+
+ if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+ (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+ len = asc_prt_line(cp, leftlen, "*");
+ ASC_PRT_NEXT();
+ renegotiate = 1;
+ }
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i,
+ (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+ 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+
+ AdvReadWordLram(iop_base,
+ ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+ lramword);
+ lramword &= ~0x8000;
+
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+ ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:", i);
+ ASC_PRT_NEXT();
+
+ if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
+ len = asc_prt_line(cp, leftlen, " Asynchronous");
+ ASC_PRT_NEXT();
+ } else {
+ len =
+ asc_prt_line(cp, leftlen,
+ " Transfer Period Factor: ");
+ ASC_PRT_NEXT();
+
+ if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
+ len =
+ asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+ ASC_PRT_NEXT();
+ } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
+ len =
+ asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+ ASC_PRT_NEXT();
+ } else { /* 20 Mhz or below. */
+
+ period = (((lramword >> 8) * 25) + 50) / 4;
+
+ if (period == 0) { /* Should never happen. */
+ len =
+ asc_prt_line(cp, leftlen,
+ "%d (? Mhz), ");
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ "%d (%d.%d Mhz),",
+ period, 250 / period,
+ ASC_TENTHS(250,
+ period));
+ ASC_PRT_NEXT();
+ }
+ }
+
+ len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+ lramword & 0x1F);
+ ASC_PRT_NEXT();
+ }
+
+ if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+ len = asc_prt_line(cp, leftlen, "*\n");
+ renegotiate = 1;
+ } else {
+ len = asc_prt_line(cp, leftlen, "\n");
+ }
+ ASC_PRT_NEXT();
+ }
- if (renegotiate)
- {
- len = asc_prt_line(cp, leftlen,
- " * = Re-negotiation pending before next command.\n");
- ASC_PRT_NEXT();
- }
+ if (renegotiate) {
+ len = asc_prt_line(cp, leftlen,
+ " * = Re-negotiation pending before next command.\n");
+ ASC_PRT_NEXT();
+ }
- return totlen;
+ return totlen;
}
/*
@@ -8553,30 +7370,30 @@ asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
* Copy proc information to a read buffer taking into account the current
* read offset in the file and the remaining space in the read buffer.
*/
-STATIC int
+static int
asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
- char *cp, int cplen)
+ char *cp, int cplen)
{
- int cnt = 0;
-
- ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
- (unsigned) offset, (unsigned) advoffset, cplen);
- if (offset <= advoffset) {
- /* Read offset below current offset, copy everything. */
- cnt = min(cplen, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
- (ulong) curbuf, (ulong) cp, cnt);
- memcpy(curbuf, cp, cnt);
- } else if (offset < advoffset + cplen) {
- /* Read offset within current range, partial copy. */
- cnt = (advoffset + cplen) - offset;
- cp = (cp + cplen) - cnt;
- cnt = min(cnt, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
- (ulong) curbuf, (ulong) cp, cnt);
- memcpy(curbuf, cp, cnt);
- }
- return cnt;
+ int cnt = 0;
+
+ ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+ (unsigned)offset, (unsigned)advoffset, cplen);
+ if (offset <= advoffset) {
+ /* Read offset below current offset, copy everything. */
+ cnt = min(cplen, leftlen);
+ ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+ (ulong)curbuf, (ulong)cp, cnt);
+ memcpy(curbuf, cp, cnt);
+ } else if (offset < advoffset + cplen) {
+ /* Read offset within current range, partial copy. */
+ cnt = (advoffset + cplen) - offset;
+ cp = (cp + cplen) - cnt;
+ cnt = min(cnt, leftlen);
+ ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+ (ulong)curbuf, (ulong)cp, cnt);
+ memcpy(curbuf, cp, cnt);
+ }
+ return cnt;
}
/*
@@ -8590,29 +7407,27 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
* Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
* will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
*/
-STATIC int
-asc_prt_line(char *buf, int buflen, char *fmt, ...)
+static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
{
- va_list args;
- int ret;
- char s[ASC_PRTLINE_SIZE];
-
- va_start(args, fmt);
- ret = vsprintf(s, fmt, args);
- ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
- if (buf == NULL) {
- (void) printk(s);
- ret = 0;
- } else {
- ret = min(buflen, ret);
- memcpy(buf, s, ret);
- }
- va_end(args);
- return ret;
+ va_list args;
+ int ret;
+ char s[ASC_PRTLINE_SIZE];
+
+ va_start(args, fmt);
+ ret = vsprintf(s, fmt, args);
+ ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
+ if (buf == NULL) {
+ (void)printk(s);
+ ret = 0;
+ } else {
+ ret = min(buflen, ret);
+ memcpy(buf, s, ret);
+ }
+ va_end(args);
+ return ret;
}
#endif /* CONFIG_PROC_FS */
-
/*
* --- Functions Required by the Asc Library
*/
@@ -8623,31 +7438,28 @@ asc_prt_line(char *buf, int buflen, char *fmt, ...)
* from a timer interrupt, because this function may be
* called when interrupts are disabled.
*/
-STATIC void
-DvcSleepMilliSecond(ADV_DCNT n)
+static void DvcSleepMilliSecond(ADV_DCNT n)
{
- ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n);
- mdelay(n);
+ ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
+ mdelay(n);
}
/*
* Currently and inline noop but leave as a placeholder.
* Leave DvcEnterCritical() as a noop placeholder.
*/
-STATIC inline ulong
-DvcEnterCritical(void)
+static inline ulong DvcEnterCritical(void)
{
- return 0;
+ return 0;
}
/*
* Critical sections are all protected by the board spinlock.
* Leave DvcLeaveCritical() as a noop placeholder.
*/
-STATIC inline void
-DvcLeaveCritical(ulong flags)
+static inline void DvcLeaveCritical(ulong flags)
{
- return;
+ return;
}
/*
@@ -8660,20 +7472,20 @@ DvcLeaveCritical(ulong flags)
* Description:
* Output an ASC_SCSI_Q structure to the chip
*/
-STATIC void
+static void
DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
{
- int i;
-
- ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- if (i == 4 || i == 20) {
- continue;
- }
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort) outbuf[i + 1] << 8) | outbuf[i]);
- }
+ int i;
+
+ ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ if (i == 4 || i == 20) {
+ continue;
+ }
+ outpw(iop_base + IOP_RAM_DATA,
+ ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
+ }
}
/*
@@ -8686,52 +7498,46 @@ DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
* Description:
* Input an ASC_QDONE_INFO structure from the chip
*/
-STATIC void
+static void
DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
{
- int i;
- ushort word;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- if (i == 10) {
- continue;
- }
- word = inpw(iop_base + IOP_RAM_DATA);
- inbuf[i] = word & 0xff;
- inbuf[i + 1] = (word >> 8) & 0xff;
- }
- ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
+ int i;
+ ushort word;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ if (i == 10) {
+ continue;
+ }
+ word = inpw(iop_base + IOP_RAM_DATA);
+ inbuf[i] = word & 0xff;
+ inbuf[i + 1] = (word >> 8) & 0xff;
+ }
+ ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
}
/*
* Read a PCI configuration byte.
*/
-STATIC uchar __init
-DvcReadPCIConfigByte(
- ASC_DVC_VAR *asc_dvc,
- ushort offset)
+static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
{
#ifdef CONFIG_PCI
- uchar byte_data;
- pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
- return byte_data;
+ uchar byte_data;
+ pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
+ return byte_data;
#else /* !defined(CONFIG_PCI) */
- return 0;
+ return 0;
#endif /* !defined(CONFIG_PCI) */
}
/*
* Write a PCI configuration byte.
*/
-STATIC void __init
-DvcWritePCIConfigByte(
- ASC_DVC_VAR *asc_dvc,
- ushort offset,
- uchar byte_data)
+static void __init
+DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
{
#ifdef CONFIG_PCI
- pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
+ pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
#endif /* CONFIG_PCI */
}
@@ -8739,51 +7545,43 @@ DvcWritePCIConfigByte(
* Return the BIOS address of the adapter at the specified
* I/O port and with the specified bus type.
*/
-STATIC ushort __init
-AscGetChipBiosAddress(
- PortAddr iop_base,
- ushort bus_type)
+static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
{
- ushort cfg_lsw;
- ushort bios_addr;
-
- /*
- * The PCI BIOS is re-located by the motherboard BIOS. Because
- * of this the driver can not determine where a PCI BIOS is
- * loaded and executes.
- */
- if (bus_type & ASC_IS_PCI)
- {
- return(0);
- }
-
+ ushort cfg_lsw;
+ ushort bios_addr;
+
+ /*
+ * The PCI BIOS is re-located by the motherboard BIOS. Because
+ * of this the driver can not determine where a PCI BIOS is
+ * loaded and executes.
+ */
+ if (bus_type & ASC_IS_PCI) {
+ return (0);
+ }
#ifdef CONFIG_ISA
- if((bus_type & ASC_IS_EISA) != 0)
- {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- cfg_lsw &= 0x000F;
- bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
- (cfg_lsw * ASC_BIOS_BANK_SIZE));
- return(bios_addr);
- }/* if */
+ if ((bus_type & ASC_IS_EISA) != 0) {
+ cfg_lsw = AscGetEisaChipCfg(iop_base);
+ cfg_lsw &= 0x000F;
+ bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
+ (cfg_lsw * ASC_BIOS_BANK_SIZE));
+ return (bios_addr);
+ } /* if */
#endif /* CONFIG_ISA */
- cfg_lsw = AscGetChipCfgLsw(iop_base);
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
- /*
- * ISA PnP uses the top bit as the 32K BIOS flag
- */
- if (bus_type == ASC_IS_ISAPNP)
- {
- cfg_lsw &= 0x7FFF;
- }/* if */
-
- bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
- ASC_BIOS_MIN_ADDR);
- return(bios_addr);
+ /*
+ * ISA PnP uses the top bit as the 32K BIOS flag
+ */
+ if (bus_type == ASC_IS_ISAPNP) {
+ cfg_lsw &= 0x7FFF;
+ }
+ /* if */
+ bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
+ ASC_BIOS_MIN_ADDR);
+ return (bios_addr);
}
-
/*
* --- Functions Required by the Adv Library
*/
@@ -8801,49 +7599,44 @@ AscGetChipBiosAddress(
*/
ADV_PADDR
DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
- uchar *vaddr, ADV_SDCNT *lenp, int flag)
+ uchar *vaddr, ADV_SDCNT *lenp, int flag)
{
- ADV_PADDR paddr;
+ ADV_PADDR paddr;
- paddr = virt_to_bus(vaddr);
+ paddr = virt_to_bus(vaddr);
- ASC_DBG4(4,
- "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
- (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr);
+ ASC_DBG4(4,
+ "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
+ (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
+ (ulong)paddr);
- return paddr;
+ return paddr;
}
/*
* Read a PCI configuration byte.
*/
-STATIC uchar __init
-DvcAdvReadPCIConfigByte(
- ADV_DVC_VAR *asc_dvc,
- ushort offset)
+static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
{
#ifdef CONFIG_PCI
- uchar byte_data;
- pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
- return byte_data;
+ uchar byte_data;
+ pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
+ return byte_data;
#else /* CONFIG_PCI */
- return 0;
+ return 0;
#endif /* CONFIG_PCI */
}
/*
* Write a PCI configuration byte.
*/
-STATIC void __init
-DvcAdvWritePCIConfigByte(
- ADV_DVC_VAR *asc_dvc,
- ushort offset,
- uchar byte_data)
+static void __init
+DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
{
#ifdef CONFIG_PCI
- pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
+ pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
#else /* CONFIG_PCI */
- return;
+ return;
#endif /* CONFIG_PCI */
}
@@ -8862,97 +7655,98 @@ DvcAdvWritePCIConfigByte(
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- asc_board_t *boardp;
-
- leftlen = cplen;
- totlen = len = 0;
-
- boardp = ASC_BOARDP(shp);
- s = &boardp->asc_stats;
-
- len = asc_prt_line(cp, leftlen,
-"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
- s->queuecommand, s->reset, s->biosparam, s->interrupt);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
- s->callback, s->done, s->build_error, s->adv_build_noreq,
- s->adv_build_nosg);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
- s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
- ASC_PRT_NEXT();
-
- /*
- * Display data transfer statistics.
- */
- if (s->cont_cnt > 0) {
- len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
- s->cont_xfer/2,
- ASC_TENTHS(s->cont_xfer, 2));
- ASC_PRT_NEXT();
-
- /* Contiguous transfer average size */
- len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
- (s->cont_xfer/2)/s->cont_cnt,
- ASC_TENTHS((s->cont_xfer/2), s->cont_cnt));
- ASC_PRT_NEXT();
- }
+ int leftlen;
+ int totlen;
+ int len;
+ struct asc_stats *s;
+ asc_board_t *boardp;
- if (s->sg_cnt > 0) {
+ leftlen = cplen;
+ totlen = len = 0;
+
+ boardp = ASC_BOARDP(shost);
+ s = &boardp->asc_stats;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+ s->queuecommand, s->reset, s->biosparam,
+ s->interrupt);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+ s->callback, s->done, s->build_error,
+ s->adv_build_noreq, s->adv_build_nosg);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+ s->exe_noerror, s->exe_busy, s->exe_error,
+ s->exe_unknown);
+ ASC_PRT_NEXT();
+
+ /*
+ * Display data transfer statistics.
+ */
+ if (s->cont_cnt > 0) {
+ len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
+ s->cont_xfer / 2,
+ ASC_TENTHS(s->cont_xfer, 2));
+ ASC_PRT_NEXT();
+
+ /* Contiguous transfer average size */
+ len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
+ (s->cont_xfer / 2) / s->cont_cnt,
+ ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
+ ASC_PRT_NEXT();
+ }
- len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
- s->sg_cnt, s->sg_elem);
- ASC_PRT_NEXT();
+ if (s->sg_cnt > 0) {
- len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
- s->sg_xfer/2,
- ASC_TENTHS(s->sg_xfer, 2));
- ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
+ s->sg_cnt, s->sg_elem);
+ ASC_PRT_NEXT();
- /* Scatter gather transfer statistics */
- len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
- s->sg_elem/s->sg_cnt,
- ASC_TENTHS(s->sg_elem, s->sg_cnt));
- ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
+ s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
+ ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
- (s->sg_xfer/2)/s->sg_elem,
- ASC_TENTHS((s->sg_xfer/2), s->sg_elem));
- ASC_PRT_NEXT();
+ /* Scatter gather transfer statistics */
+ len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+ s->sg_elem / s->sg_cnt,
+ ASC_TENTHS(s->sg_elem, s->sg_cnt));
+ ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
- (s->sg_xfer/2)/s->sg_cnt,
- ASC_TENTHS((s->sg_xfer/2), s->sg_cnt));
- ASC_PRT_NEXT();
- }
+ len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+ (s->sg_xfer / 2) / s->sg_elem,
+ ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
+ ASC_PRT_NEXT();
- /*
- * Display request queuing statistics.
- */
- len = asc_prt_line(cp, leftlen,
-" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ);
- ASC_PRT_NEXT();
+ len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+ (s->sg_xfer / 2) / s->sg_cnt,
+ ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
+ ASC_PRT_NEXT();
+ }
+ /*
+ * Display request queuing statistics.
+ */
+ len = asc_prt_line(cp, leftlen,
+ " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
+ HZ);
+ ASC_PRT_NEXT();
- return totlen;
+ return totlen;
}
/*
@@ -8967,70 +7761,89 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
* Return the number of characters copied into 'cp'. No more than
* 'cplen' characters will be copied to 'cp'.
*/
-STATIC int
-asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen)
+static int
+asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- ushort chip_scsi_id;
- asc_board_t *boardp;
- asc_queue_t *active;
- asc_queue_t *waiting;
-
- leftlen = cplen;
- totlen = len = 0;
-
- boardp = ASC_BOARDP(shp);
- s = &boardp->asc_stats;
-
- active = &ASC_BOARDP(shp)->active;
- waiting = &ASC_BOARDP(shp)->waiting;
-
- if (ASC_NARROW_BOARD(boardp)) {
- chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
- } else {
- chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
- }
+ int leftlen;
+ int totlen;
+ int len;
+ struct asc_stats *s;
+ ushort chip_scsi_id;
+ asc_board_t *boardp;
+ asc_queue_t *active;
+ asc_queue_t *waiting;
- if ((chip_scsi_id == tgt_id) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
- return 0;
- }
+ leftlen = cplen;
+ totlen = len = 0;
+
+ boardp = ASC_BOARDP(shost);
+ s = &boardp->asc_stats;
+
+ active = &ASC_BOARDP(shost)->active;
+ waiting = &ASC_BOARDP(shost)->waiting;
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+ } else {
+ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ }
+
+ if ((chip_scsi_id == tgt_id) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
+ return 0;
+ }
- do {
- if (active->q_tot_cnt[tgt_id] > 0 || waiting->q_tot_cnt[tgt_id] > 0) {
- len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
- active->q_cur_cnt[tgt_id], active->q_max_cnt[tgt_id],
- active->q_tot_cnt[tgt_id],
- active->q_min_tim[tgt_id], active->q_max_tim[tgt_id],
- (active->q_tot_cnt[tgt_id] == 0) ? 0 :
- (active->q_tot_tim[tgt_id]/active->q_tot_cnt[tgt_id]),
- (active->q_tot_cnt[tgt_id] == 0) ? 0 :
- ASC_TENTHS(active->q_tot_tim[tgt_id],
- active->q_tot_cnt[tgt_id]));
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
-" waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
- waiting->q_cur_cnt[tgt_id], waiting->q_max_cnt[tgt_id],
- waiting->q_tot_cnt[tgt_id],
- waiting->q_min_tim[tgt_id], waiting->q_max_tim[tgt_id],
- (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
- (waiting->q_tot_tim[tgt_id]/waiting->q_tot_cnt[tgt_id]),
- (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
- ASC_TENTHS(waiting->q_tot_tim[tgt_id],
- waiting->q_tot_cnt[tgt_id]));
- ASC_PRT_NEXT();
- }
- } while (0);
-
- return totlen;
+ do {
+ if (active->q_tot_cnt[tgt_id] > 0
+ || waiting->q_tot_cnt[tgt_id] > 0) {
+ len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
+ active->q_cur_cnt[tgt_id],
+ active->q_max_cnt[tgt_id],
+ active->q_tot_cnt[tgt_id],
+ active->q_min_tim[tgt_id],
+ active->q_max_tim[tgt_id],
+ (active->q_tot_cnt[tgt_id] ==
+ 0) ? 0 : (active->
+ q_tot_tim[tgt_id] /
+ active->
+ q_tot_cnt[tgt_id]),
+ (active->q_tot_cnt[tgt_id] ==
+ 0) ? 0 : ASC_TENTHS(active->
+ q_tot_tim
+ [tgt_id],
+ active->
+ q_tot_cnt
+ [tgt_id]));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
+ waiting->q_cur_cnt[tgt_id],
+ waiting->q_max_cnt[tgt_id],
+ waiting->q_tot_cnt[tgt_id],
+ waiting->q_min_tim[tgt_id],
+ waiting->q_max_tim[tgt_id],
+ (waiting->q_tot_cnt[tgt_id] ==
+ 0) ? 0 : (waiting->
+ q_tot_tim[tgt_id] /
+ waiting->
+ q_tot_cnt[tgt_id]),
+ (waiting->q_tot_cnt[tgt_id] ==
+ 0) ? 0 : ASC_TENTHS(waiting->
+ q_tot_tim
+ [tgt_id],
+ waiting->
+ q_tot_cnt
+ [tgt_id]));
+ ASC_PRT_NEXT();
+ }
+ } while (0);
+
+ return totlen;
}
#endif /* CONFIG_PROC_FS */
#endif /* ADVANSYS_STATS */
@@ -9039,207 +7852,181 @@ asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen)
/*
* asc_prt_scsi_host()
*/
-STATIC void
-asc_prt_scsi_host(struct Scsi_Host *s)
+static void asc_prt_scsi_host(struct Scsi_Host *s)
{
- asc_board_t *boardp;
-
- boardp = ASC_BOARDP(s);
-
- printk("Scsi_Host at addr 0x%lx\n", (ulong) s);
- printk(
-" host_busy %u, host_no %d, last_reset %d,\n",
- s->host_busy, s->host_no,
- (unsigned) s->last_reset);
-
- printk(
-" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
- (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq);
-
- printk(
-" dma_channel %d, this_id %d, can_queue %d,\n",
- s->dma_channel, s->this_id, s->can_queue);
-
- printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
-
- if (ASC_NARROW_BOARD(boardp)) {
- asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
- asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
- } else {
- asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
- asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
- }
+ asc_board_t *boardp;
+
+ boardp = ASC_BOARDP(s);
+
+ printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
+ printk(" host_busy %u, host_no %d, last_reset %d,\n",
+ s->host_busy, s->host_no, (unsigned)s->last_reset);
+
+ printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
+ (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
+
+ printk(" dma_channel %d, this_id %d, can_queue %d,\n",
+ s->dma_channel, s->this_id, s->can_queue);
+
+ printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
+ asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
+ } else {
+ asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
+ asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+ }
}
/*
* asc_prt_scsi_cmnd()
*/
-STATIC void
-asc_prt_scsi_cmnd(struct scsi_cmnd *s)
+static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
{
- printk("struct scsi_cmnd at addr 0x%lx\n", (ulong) s);
+ printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
- printk(
-" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
- (ulong) s->device->host, (ulong) s->device, s->device->id, s->device->lun,
- s->device->channel);
+ printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
+ (ulong)s->device->host, (ulong)s->device, s->device->id,
+ s->device->lun, s->device->channel);
- asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+ asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
- printk (
-"sc_data_direction %u, resid %d\n",
- s->sc_data_direction, s->resid);
+ printk("sc_data_direction %u, resid %d\n",
+ s->sc_data_direction, s->resid);
- printk(
-" use_sg %u, sglist_len %u\n",
- s->use_sg, s->sglist_len);
+ printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
- printk(
-" serial_number 0x%x, retries %d, allowed %d\n",
- (unsigned) s->serial_number, s->retries, s->allowed);
+ printk(" serial_number 0x%x, retries %d, allowed %d\n",
+ (unsigned)s->serial_number, s->retries, s->allowed);
- printk(
-" timeout_per_command %d\n",
- s->timeout_per_command);
+ printk(" timeout_per_command %d\n", s->timeout_per_command);
- printk(
-" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
- (ulong) s->scsi_done, (ulong) s->done,
- (ulong) s->host_scribble, s->result);
+ printk
+ (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
+ (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
+ s->result);
- printk(
-" tag %u, pid %u\n",
- (unsigned) s->tag, (unsigned) s->pid);
+ printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
}
/*
* asc_prt_asc_dvc_var()
*/
-STATIC void
-asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
{
- printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong) h);
-
- printk(
-" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
- h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
-
- printk(
-" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
- h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback,
- (unsigned) h->init_sdtr);
-
- printk(
-" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
- (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
- (unsigned) h->unit_not_ready, (unsigned) h->chip_no);
-
- printk(
-" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
- (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
- (unsigned) h->scsi_reset_wait);
-
- printk(
-" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
- (unsigned) h->is_in_int, (unsigned) h->max_total_qng,
- (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
-
- printk(
-" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
- (unsigned) h->last_q_shortage, (unsigned) h->init_state,
- (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
-
- printk(
-" cfg 0x%lx, irq_no 0x%x\n",
- (ulong) h->cfg, (unsigned) h->irq_no);
+ printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
+
+ printk
+ (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
+ h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+
+ printk
+ (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
+ h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
+ (unsigned)h->init_sdtr);
+
+ printk
+ (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
+ (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
+ (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
+
+ printk
+ (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
+ (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
+ (unsigned)h->scsi_reset_wait);
+
+ printk
+ (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
+ (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
+ (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
+
+ printk
+ (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
+ (unsigned)h->last_q_shortage, (unsigned)h->init_state,
+ (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
+
+ printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
}
/*
* asc_prt_asc_dvc_cfg()
*/
-STATIC void
-asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
{
- printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong) h);
-
- printk(
-" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
- h->can_tagged_qng, h->cmd_qng_enabled);
- printk(
-" disc_enable 0x%x, sdtr_enable 0x%x,\n",
- h->disc_enable, h->sdtr_enable);
-
- printk(
-" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
- h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
- h->chip_version);
-
- printk(
-" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
- to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
- h->mcode_date);
-
- printk(
-" mcode_version %d, overrun_buf 0x%lx\n",
- h->mcode_version, (ulong) h->overrun_buf);
+ printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
+
+ printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+ h->can_tagged_qng, h->cmd_qng_enabled);
+ printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+ h->disc_enable, h->sdtr_enable);
+
+ printk
+ (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
+ h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
+ h->chip_version);
+
+ printk
+ (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
+ to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
+ h->mcode_date);
+
+ printk(" mcode_version %d, overrun_buf 0x%lx\n",
+ h->mcode_version, (ulong)h->overrun_buf);
}
/*
* asc_prt_asc_scsi_q()
*/
-STATIC void
-asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
{
- ASC_SG_HEAD *sgp;
- int i;
-
- printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong) q);
-
- printk(
-" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
- q->q2.target_ix, q->q1.target_lun,
- (ulong) q->q2.srb_ptr, q->q2.tag_code);
-
- printk(
-" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
- (ulong) le32_to_cpu(q->q1.data_addr),
- (ulong) le32_to_cpu(q->q1.data_cnt),
- (ulong) le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
-
- printk(
-" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
- (ulong) q->cdbptr, q->q2.cdb_len,
- (ulong) q->sg_head, q->q1.sg_queue_cnt);
-
- if (q->sg_head) {
- sgp = q->sg_head;
- printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong) sgp);
- printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
- for (i = 0; i < sgp->entry_cnt; i++) {
- printk(" [%u]: addr 0x%lx, bytes %lu\n",
- i, (ulong) le32_to_cpu(sgp->sg_list[i].addr),
- (ulong) le32_to_cpu(sgp->sg_list[i].bytes));
- }
+ ASC_SG_HEAD *sgp;
+ int i;
+
+ printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
+
+ printk
+ (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
+ q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
+ q->q2.tag_code);
+
+ printk
+ (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ (ulong)le32_to_cpu(q->q1.data_addr),
+ (ulong)le32_to_cpu(q->q1.data_cnt),
+ (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
+
+ printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
+ (ulong)q->cdbptr, q->q2.cdb_len,
+ (ulong)q->sg_head, q->q1.sg_queue_cnt);
+
+ if (q->sg_head) {
+ sgp = q->sg_head;
+ printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
+ printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
+ sgp->queue_cnt);
+ for (i = 0; i < sgp->entry_cnt; i++) {
+ printk(" [%u]: addr 0x%lx, bytes %lu\n",
+ i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
+ (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
+ }
- }
+ }
}
/*
* asc_prt_asc_qdone_info()
*/
-STATIC void
-asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
{
- printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong) q);
- printk(
-" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
- (ulong) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
- q->d2.tag_code);
- printk(
-" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
- q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+ printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
+ printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+ (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+ q->d2.tag_code);
+ printk
+ (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+ q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
}
/*
@@ -9247,41 +8034,33 @@ asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
*
* Display an ADV_DVC_VAR structure.
*/
-STATIC void
-asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
{
- printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h);
-
- printk(
-" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
- (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able);
-
- printk(
-" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
- (ulong) h->isr_callback, (unsigned) h->sdtr_able,
- (unsigned) h->wdtr_able);
-
- printk(
-" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
- (unsigned) h->start_motor,
- (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
-
- printk(
-" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
- (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
- (ulong) h->carr_freelist);
-
- printk(
-" icq_sp 0x%lx, irq_sp 0x%lx\n",
- (ulong) h->icq_sp, (ulong) h->irq_sp);
-
- printk(
-" no_scam 0x%x, tagqng_able 0x%x\n",
- (unsigned) h->no_scam, (unsigned) h->tagqng_able);
-
- printk(
-" chip_scsi_id 0x%x, cfg 0x%lx\n",
- (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+ printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
+
+ printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+ (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
+
+ printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
+ (ulong)h->isr_callback, (unsigned)h->sdtr_able,
+ (unsigned)h->wdtr_able);
+
+ printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
+ (unsigned)h->start_motor,
+ (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
+
+ printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
+ (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
+ (ulong)h->carr_freelist);
+
+ printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
+ (ulong)h->icq_sp, (ulong)h->irq_sp);
+
+ printk(" no_scam 0x%x, tagqng_able 0x%x\n",
+ (unsigned)h->no_scam, (unsigned)h->tagqng_able);
+
+ printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
+ (unsigned)h->chip_scsi_id, (ulong)h->cfg);
}
/*
@@ -9289,26 +8068,21 @@ asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
*
* Display an ADV_DVC_CFG structure.
*/
-STATIC void
-asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
{
- printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h);
+ printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
- printk(
-" disc_enable 0x%x, termination 0x%x\n",
- h->disc_enable, h->termination);
+ printk(" disc_enable 0x%x, termination 0x%x\n",
+ h->disc_enable, h->termination);
- printk(
-" chip_version 0x%x, mcode_date 0x%x\n",
- h->chip_version, h->mcode_date);
+ printk(" chip_version 0x%x, mcode_date 0x%x\n",
+ h->chip_version, h->mcode_date);
- printk(
-" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
- h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
+ printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
+ h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
- printk(
-" control_flag 0x%x, pci_slot_info 0x%x\n",
- h->control_flag, h->pci_slot_info);
+ printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
+ h->control_flag, h->pci_slot_info);
}
/*
@@ -9316,60 +8090,54 @@ asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
*
* Display an ADV_SCSI_REQ_Q structure.
*/
-STATIC void
-asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
{
- int sg_blk_cnt;
- struct asc_sg_block *sg_ptr;
-
- printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong) q);
-
- printk(
-" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
- q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag);
-
- printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
- q->cntl, (ulong) le32_to_cpu(q->data_addr), (ulong) q->vdata_addr);
-
- printk(
-" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
- (ulong) le32_to_cpu(q->data_cnt),
- (ulong) le32_to_cpu(q->sense_addr), q->sense_len);
-
- printk(
-" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
- q->cdb_len, q->done_status, q->host_status, q->scsi_status);
-
- printk(
-" sg_working_ix 0x%x, target_cmd %u\n",
- q->sg_working_ix, q->target_cmd);
-
- printk(
-" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
- (ulong) le32_to_cpu(q->scsiq_rptr),
- (ulong) le32_to_cpu(q->sg_real_addr), (ulong) q->sg_list_ptr);
-
- /* Display the request's ADV_SG_BLOCK structures. */
- if (q->sg_list_ptr != NULL)
- {
- sg_blk_cnt = 0;
- while (1) {
- /*
- * 'sg_ptr' is a physical address. Convert it to a virtual
- * address by indexing 'sg_blk_cnt' into the virtual address
- * array 'sg_list_ptr'.
- *
- * XXX - Assumes all SG physical blocks are virtually contiguous.
- */
- sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
- asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
- if (sg_ptr->sg_ptr == 0)
- {
- break;
- }
- sg_blk_cnt++;
- }
- }
+ int sg_blk_cnt;
+ struct asc_sg_block *sg_ptr;
+
+ printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
+
+ printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+ q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
+
+ printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+ q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
+
+ printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ (ulong)le32_to_cpu(q->data_cnt),
+ (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
+
+ printk
+ (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+ q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+
+ printk(" sg_working_ix 0x%x, target_cmd %u\n",
+ q->sg_working_ix, q->target_cmd);
+
+ printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+ (ulong)le32_to_cpu(q->scsiq_rptr),
+ (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
+
+ /* Display the request's ADV_SG_BLOCK structures. */
+ if (q->sg_list_ptr != NULL) {
+ sg_blk_cnt = 0;
+ while (1) {
+ /*
+ * 'sg_ptr' is a physical address. Convert it to a virtual
+ * address by indexing 'sg_blk_cnt' into the virtual address
+ * array 'sg_list_ptr'.
+ *
+ * XXX - Assumes all SG physical blocks are virtually contiguous.
+ */
+ sg_ptr =
+ &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
+ asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+ if (sg_ptr->sg_ptr == 0) {
+ break;
+ }
+ sg_blk_cnt++;
+ }
+ }
}
/*
@@ -9377,24 +8145,23 @@ asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
*
* Display an ADV_SG_BLOCK structure.
*/
-STATIC void
-asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
{
- int i;
-
- printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
- (ulong) b, sgblockno);
- printk(" sg_cnt %u, sg_ptr 0x%lx\n",
- b->sg_cnt, (ulong) le32_to_cpu(b->sg_ptr));
- ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
- if (b->sg_ptr != 0)
- {
- ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
- }
- for (i = 0; i < b->sg_cnt; i++) {
- printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
- i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count);
- }
+ int i;
+
+ printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
+ (ulong)b, sgblockno);
+ printk(" sg_cnt %u, sg_ptr 0x%lx\n",
+ b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
+ ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
+ if (b->sg_ptr != 0) {
+ ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+ }
+ for (i = 0; i < b->sg_cnt; i++) {
+ printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
+ i, (ulong)b->sg_list[i].sg_addr,
+ (ulong)b->sg_list[i].sg_count);
+ }
}
/*
@@ -9403,55 +8170,55 @@ asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
* Print hexadecimal output in 4 byte groupings 32 bytes
* or 8 double-words per line.
*/
-STATIC void
-asc_prt_hex(char *f, uchar *s, int l)
+static void asc_prt_hex(char *f, uchar *s, int l)
{
- int i;
- int j;
- int k;
- int m;
-
- printk("%s: (%d bytes)\n", f, l);
-
- for (i = 0; i < l; i += 32) {
-
- /* Display a maximum of 8 double-words per line. */
- if ((k = (l - i) / 4) >= 8) {
- k = 8;
- m = 0;
- } else {
- m = (l - i) % 4;
- }
-
- for (j = 0; j < k; j++) {
- printk(" %2.2X%2.2X%2.2X%2.2X",
- (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1],
- (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]);
- }
-
- switch (m) {
- case 0:
- default:
- break;
- case 1:
- printk(" %2.2X",
- (unsigned) s[i+(j*4)]);
- break;
- case 2:
- printk(" %2.2X%2.2X",
- (unsigned) s[i+(j*4)],
- (unsigned) s[i+(j*4)+1]);
- break;
- case 3:
- printk(" %2.2X%2.2X%2.2X",
- (unsigned) s[i+(j*4)+1],
- (unsigned) s[i+(j*4)+2],
- (unsigned) s[i+(j*4)+3]);
- break;
- }
-
- printk("\n");
- }
+ int i;
+ int j;
+ int k;
+ int m;
+
+ printk("%s: (%d bytes)\n", f, l);
+
+ for (i = 0; i < l; i += 32) {
+
+ /* Display a maximum of 8 double-words per line. */
+ if ((k = (l - i) / 4) >= 8) {
+ k = 8;
+ m = 0;
+ } else {
+ m = (l - i) % 4;
+ }
+
+ for (j = 0; j < k; j++) {
+ printk(" %2.2X%2.2X%2.2X%2.2X",
+ (unsigned)s[i + (j * 4)],
+ (unsigned)s[i + (j * 4) + 1],
+ (unsigned)s[i + (j * 4) + 2],
+ (unsigned)s[i + (j * 4) + 3]);
+ }
+
+ switch (m) {
+ case 0:
+ default:
+ break;
+ case 1:
+ printk(" %2.2X", (unsigned)s[i + (j * 4)]);
+ break;
+ case 2:
+ printk(" %2.2X%2.2X",
+ (unsigned)s[i + (j * 4)],
+ (unsigned)s[i + (j * 4) + 1]);
+ break;
+ case 3:
+ printk(" %2.2X%2.2X%2.2X",
+ (unsigned)s[i + (j * 4) + 1],
+ (unsigned)s[i + (j * 4) + 2],
+ (unsigned)s[i + (j * 4) + 3]);
+ break;
+ }
+
+ printk("\n");
+ }
}
#endif /* ADVANSYS_DEBUG */
@@ -9459,3380 +8226,3400 @@ asc_prt_hex(char *f, uchar *s, int l)
* --- Asc Library Functions
*/
-STATIC ushort __init
-AscGetEisaChipCfg(
- PortAddr iop_base)
+static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
{
- PortAddr eisa_cfg_iop;
+ PortAddr eisa_cfg_iop;
- eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
- (PortAddr) (ASC_EISA_CFG_IOP_MASK);
- return (inpw(eisa_cfg_iop));
+ eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+ (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+ return (inpw(eisa_cfg_iop));
}
-STATIC uchar __init
-AscSetChipScsiID(
- PortAddr iop_base,
- uchar new_host_id
-)
+static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
{
- ushort cfg_lsw;
+ ushort cfg_lsw;
- if (AscGetChipScsiID(iop_base) == new_host_id) {
- return (new_host_id);
- }
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- cfg_lsw &= 0xF8FF;
- cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetChipScsiID(iop_base));
+ if (AscGetChipScsiID(iop_base) == new_host_id) {
+ return (new_host_id);
+ }
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ cfg_lsw &= 0xF8FF;
+ cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ return (AscGetChipScsiID(iop_base));
}
-STATIC uchar __init
-AscGetChipScsiCtrl(
- PortAddr iop_base)
+static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
{
- uchar sc;
+ uchar sc;
- AscSetBank(iop_base, 1);
- sc = inp(iop_base + IOP_REG_SC);
- AscSetBank(iop_base, 0);
- return (sc);
+ AscSetBank(iop_base, 1);
+ sc = inp(iop_base + IOP_REG_SC);
+ AscSetBank(iop_base, 0);
+ return (sc);
}
-STATIC uchar __init
-AscGetChipVersion(
- PortAddr iop_base,
- ushort bus_type
-)
+static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
{
- if ((bus_type & ASC_IS_EISA) != 0) {
- PortAddr eisa_iop;
- uchar revision;
- eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
- (PortAddr) ASC_EISA_REV_IOP_MASK;
- revision = inp(eisa_iop);
- return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision));
- }
- return (AscGetChipVerNo(iop_base));
+ if ((bus_type & ASC_IS_EISA) != 0) {
+ PortAddr eisa_iop;
+ uchar revision;
+ eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+ (PortAddr) ASC_EISA_REV_IOP_MASK;
+ revision = inp(eisa_iop);
+ return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+ }
+ return (AscGetChipVerNo(iop_base));
}
-STATIC ushort __init
-AscGetChipBusType(
- PortAddr iop_base)
+static ushort __init AscGetChipBusType(PortAddr iop_base)
{
- ushort chip_ver;
-
- chip_ver = AscGetChipVerNo(iop_base);
- if (
- (chip_ver >= ASC_CHIP_MIN_VER_VL)
- && (chip_ver <= ASC_CHIP_MAX_VER_VL)
-) {
- if (
- ((iop_base & 0x0C30) == 0x0C30)
- || ((iop_base & 0x0C50) == 0x0C50)
-) {
- return (ASC_IS_EISA);
- }
- return (ASC_IS_VL);
- }
- if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
- (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
- if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
- return (ASC_IS_ISAPNP);
- }
- return (ASC_IS_ISA);
- } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
- (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
- return (ASC_IS_PCI);
- }
- return (0);
+ ushort chip_ver;
+
+ chip_ver = AscGetChipVerNo(iop_base);
+ if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
+ && (chip_ver <= ASC_CHIP_MAX_VER_VL)
+ ) {
+ if (((iop_base & 0x0C30) == 0x0C30)
+ || ((iop_base & 0x0C50) == 0x0C50)
+ ) {
+ return (ASC_IS_EISA);
+ }
+ return (ASC_IS_VL);
+ }
+ if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
+ (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
+ if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
+ return (ASC_IS_ISAPNP);
+ }
+ return (ASC_IS_ISA);
+ } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
+ (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
+ return (ASC_IS_PCI);
+ }
+ return (0);
}
-STATIC ASC_DCNT
-AscLoadMicroCode(
- PortAddr iop_base,
- ushort s_addr,
- uchar *mcode_buf,
- ushort mcode_size
-)
+static ASC_DCNT
+AscLoadMicroCode(PortAddr iop_base,
+ ushort s_addr, uchar *mcode_buf, ushort mcode_size)
{
- ASC_DCNT chksum;
- ushort mcode_word_size;
- ushort mcode_chksum;
-
- /* Write the microcode buffer starting at LRAM address 0. */
- mcode_word_size = (ushort) (mcode_size >> 1);
- AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
- AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
-
- chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
- ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong) chksum);
- mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
- (ushort) ASC_CODE_SEC_BEG,
- (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
- ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
- (ulong) mcode_chksum);
- AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
- AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
- return (chksum);
+ ASC_DCNT chksum;
+ ushort mcode_word_size;
+ ushort mcode_chksum;
+
+ /* Write the microcode buffer starting at LRAM address 0. */
+ mcode_word_size = (ushort)(mcode_size >> 1);
+ AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+ AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+
+ chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+ ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
+ mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
+ (ushort)ASC_CODE_SEC_BEG,
+ (ushort)((mcode_size -
+ s_addr - (ushort)
+ ASC_CODE_SEC_BEG) /
+ 2));
+ ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
+ (ulong)mcode_chksum);
+ AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+ AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+ return (chksum);
}
-STATIC int
-AscFindSignature(
- PortAddr iop_base
-)
+static int AscFindSignature(PortAddr iop_base)
{
- ushort sig_word;
-
- ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
- iop_base, AscGetChipSignatureByte(iop_base));
- if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
- ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
- iop_base, AscGetChipSignatureWord(iop_base));
- sig_word = AscGetChipSignatureWord(iop_base);
- if ((sig_word == (ushort) ASC_1000_ID0W) ||
- (sig_word == (ushort) ASC_1000_ID0W_FIX)) {
- return (1);
- }
- }
- return (0);
+ ushort sig_word;
+
+ ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
+ iop_base, AscGetChipSignatureByte(iop_base));
+ if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
+ ASC_DBG2(1,
+ "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
+ iop_base, AscGetChipSignatureWord(iop_base));
+ sig_word = AscGetChipSignatureWord(iop_base);
+ if ((sig_word == (ushort)ASC_1000_ID0W) ||
+ (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
+ return (1);
+ }
+ }
+ return (0);
}
-STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata =
-{
- 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
- ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
+ 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
+ ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
};
#ifdef CONFIG_ISA
-STATIC uchar _isa_pnp_inited __initdata = 0;
+static uchar _isa_pnp_inited __initdata = 0;
-STATIC PortAddr __init
-AscSearchIOPortAddr(
- PortAddr iop_beg,
- ushort bus_type)
+static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
{
- if (bus_type & ASC_IS_VL) {
- while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
- if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) {
- return (iop_beg);
- }
- }
- return (0);
- }
- if (bus_type & ASC_IS_ISA) {
- if (_isa_pnp_inited == 0) {
- AscSetISAPNPWaitForKey();
- _isa_pnp_inited++;
- }
- while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
- if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) {
- return (iop_beg);
- }
- }
- return (0);
- }
- if (bus_type & ASC_IS_EISA) {
- if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
- return (iop_beg);
- }
- return (0);
- }
- return (0);
+ if (bus_type & ASC_IS_VL) {
+ while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+ if (AscGetChipVersion(iop_beg, bus_type) <=
+ ASC_CHIP_MAX_VER_VL) {
+ return (iop_beg);
+ }
+ }
+ return (0);
+ }
+ if (bus_type & ASC_IS_ISA) {
+ if (_isa_pnp_inited == 0) {
+ AscSetISAPNPWaitForKey();
+ _isa_pnp_inited++;
+ }
+ while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+ if ((AscGetChipVersion(iop_beg, bus_type) &
+ ASC_CHIP_VER_ISA_BIT) != 0) {
+ return (iop_beg);
+ }
+ }
+ return (0);
+ }
+ if (bus_type & ASC_IS_EISA) {
+ if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
+ return (iop_beg);
+ }
+ return (0);
+ }
+ return (0);
}
-STATIC PortAddr __init
-AscSearchIOPortAddr11(
- PortAddr s_addr
-)
+static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
{
- int i;
- PortAddr iop_base;
+ int i;
+ PortAddr iop_base;
- for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
- if (_asc_def_iop_base[i] > s_addr) {
- break;
- }
- }
- for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
- iop_base = _asc_def_iop_base[i];
- if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")){
- ASC_DBG1(1,
- "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
- iop_base);
- continue;
- }
- ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base);
- release_region(iop_base, ASC_IOADR_GAP);
- if (AscFindSignature(iop_base)) {
- return (iop_base);
- }
- }
- return (0);
+ for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+ if (_asc_def_iop_base[i] > s_addr) {
+ break;
+ }
+ }
+ for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+ iop_base = _asc_def_iop_base[i];
+ if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
+ ASC_DBG1(1,
+ "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
+ iop_base);
+ continue;
+ }
+ ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
+ iop_base);
+ release_region(iop_base, ASC_IOADR_GAP);
+ if (AscFindSignature(iop_base)) {
+ return (iop_base);
+ }
+ }
+ return (0);
}
-STATIC void __init
-AscSetISAPNPWaitForKey(void)
+static void __init AscSetISAPNPWaitForKey(void)
{
- outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
- outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
- return;
+ outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
+ outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
+ return;
}
#endif /* CONFIG_ISA */
-STATIC void __init
-AscToggleIRQAct(
- PortAddr iop_base
-)
+static void __init AscToggleIRQAct(PortAddr iop_base)
{
- AscSetChipStatus(iop_base, CIW_IRQ_ACT);
- AscSetChipStatus(iop_base, 0);
- return;
+ AscSetChipStatus(iop_base, CIW_IRQ_ACT);
+ AscSetChipStatus(iop_base, 0);
+ return;
}
-STATIC uchar __init
-AscGetChipIRQ(
- PortAddr iop_base,
- ushort bus_type)
+static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
{
- ushort cfg_lsw;
- uchar chip_irq;
-
- if ((bus_type & ASC_IS_EISA) != 0) {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
- if ((chip_irq == 13) || (chip_irq > 15)) {
- return (0);
- }
- return (chip_irq);
- }
- if ((bus_type & ASC_IS_VL) != 0) {
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07));
- if ((chip_irq == 0) ||
- (chip_irq == 4) ||
- (chip_irq == 7)) {
- return (0);
- }
- return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
- }
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03));
- if (chip_irq == 3)
- chip_irq += (uchar) 2;
- return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
+ ushort cfg_lsw;
+ uchar chip_irq;
+
+ if ((bus_type & ASC_IS_EISA) != 0) {
+ cfg_lsw = AscGetEisaChipCfg(iop_base);
+ chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
+ if ((chip_irq == 13) || (chip_irq > 15)) {
+ return (0);
+ }
+ return (chip_irq);
+ }
+ if ((bus_type & ASC_IS_VL) != 0) {
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
+ if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
+ return (0);
+ }
+ return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
+ }
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
+ if (chip_irq == 3)
+ chip_irq += (uchar)2;
+ return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
}
-STATIC uchar __init
-AscSetChipIRQ(
- PortAddr iop_base,
- uchar irq_no,
- ushort bus_type)
+static uchar __init
+AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
{
- ushort cfg_lsw;
-
- if ((bus_type & ASC_IS_VL) != 0) {
- if (irq_no != 0) {
- if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
- irq_no = 0;
- } else {
- irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1));
- }
- }
- cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3);
- cfg_lsw |= (ushort) 0x0010;
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- AscToggleIRQAct(iop_base);
- cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0);
- cfg_lsw |= (ushort) ((irq_no & 0x07) << 2);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- AscToggleIRQAct(iop_base);
- return (AscGetChipIRQ(iop_base, bus_type));
- }
- if ((bus_type & (ASC_IS_ISA)) != 0) {
- if (irq_no == 15)
- irq_no -= (uchar) 2;
- irq_no -= (uchar) ASC_MIN_IRQ_NO;
- cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3);
- cfg_lsw |= (ushort) ((irq_no & 0x03) << 2);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetChipIRQ(iop_base, bus_type));
- }
- return (0);
+ ushort cfg_lsw;
+
+ if ((bus_type & ASC_IS_VL) != 0) {
+ if (irq_no != 0) {
+ if ((irq_no < ASC_MIN_IRQ_NO)
+ || (irq_no > ASC_MAX_IRQ_NO)) {
+ irq_no = 0;
+ } else {
+ irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
+ }
+ }
+ cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
+ cfg_lsw |= (ushort)0x0010;
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ AscToggleIRQAct(iop_base);
+ cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
+ cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ AscToggleIRQAct(iop_base);
+ return (AscGetChipIRQ(iop_base, bus_type));
+ }
+ if ((bus_type & (ASC_IS_ISA)) != 0) {
+ if (irq_no == 15)
+ irq_no -= (uchar)2;
+ irq_no -= (uchar)ASC_MIN_IRQ_NO;
+ cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
+ cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ return (AscGetChipIRQ(iop_base, bus_type));
+ }
+ return (0);
}
#ifdef CONFIG_ISA
-STATIC void __init
-AscEnableIsaDma(
- uchar dma_channel)
+static void __init AscEnableIsaDma(uchar dma_channel)
{
- if (dma_channel < 4) {
- outp(0x000B, (ushort) (0xC0 | dma_channel));
- outp(0x000A, dma_channel);
- } else if (dma_channel < 8) {
- outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4)));
- outp(0x00D4, (ushort) (dma_channel - 4));
- }
- return;
+ if (dma_channel < 4) {
+ outp(0x000B, (ushort)(0xC0 | dma_channel));
+ outp(0x000A, dma_channel);
+ } else if (dma_channel < 8) {
+ outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
+ outp(0x00D4, (ushort)(dma_channel - 4));
+ }
+ return;
}
#endif /* CONFIG_ISA */
-STATIC int
-AscIsrChipHalted(
- ASC_DVC_VAR *asc_dvc
-)
+static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
{
- EXT_MSG ext_msg;
- EXT_MSG out_msg;
- ushort halt_q_addr;
- int sdtr_accept;
- ushort int_halt_code;
- ASC_SCSI_BIT_ID_TYPE scsi_busy;
- ASC_SCSI_BIT_ID_TYPE target_id;
- PortAddr iop_base;
- uchar tag_code;
- uchar q_status;
- uchar halt_qp;
- uchar sdtr_data;
- uchar target_ix;
- uchar q_cntl, tid_no;
- uchar cur_dvc_qng;
- uchar asyn_sdtr;
- uchar scsi_status;
- asc_board_t *boardp;
-
- ASC_ASSERT(asc_dvc->drv_ptr != NULL);
- boardp = asc_dvc->drv_ptr;
-
- iop_base = asc_dvc->iop_base;
- int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
-
- halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
- halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
- target_ix = AscReadLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX));
- q_cntl = AscReadLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL));
- tid_no = ASC_TIX_TO_TID(target_ix);
- target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
- if (asc_dvc->pci_fix_asyn_xfer & target_id) {
- asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
- } else {
- asyn_sdtr = 0;
- }
- if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
- if (asc_dvc->pci_fix_asyn_xfer & target_id) {
- AscSetChipSDTR(iop_base, 0, tid_no);
- boardp->sdtr_data[tid_no] = 0;
- }
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
- if (asc_dvc->pci_fix_asyn_xfer & target_id) {
- AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
- boardp->sdtr_data[tid_no] = asyn_sdtr;
- }
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
-
- AscMemWordCopyPtrFromLram(iop_base,
- ASCV_MSGIN_BEG,
- (uchar *) &ext_msg,
- sizeof(EXT_MSG) >> 1);
-
- if (ext_msg.msg_type == MS_EXTEND &&
- ext_msg.msg_req == MS_SDTR_CODE &&
- ext_msg.msg_len == MS_SDTR_LEN) {
- sdtr_accept = TRUE;
- if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
-
- sdtr_accept = FALSE;
- ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
- }
- if ((ext_msg.xfer_period <
- asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]) ||
- (ext_msg.xfer_period >
- asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])) {
- sdtr_accept = FALSE;
- ext_msg.xfer_period =
- asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index];
- }
- if (sdtr_accept) {
- sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
- ext_msg.req_ack_offset);
- if ((sdtr_data == 0xFF)) {
-
- q_cntl |= QC_MSG_OUT;
- asc_dvc->init_sdtr &= ~target_id;
- asc_dvc->sdtr_done &= ~target_id;
- AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
- boardp->sdtr_data[tid_no] = asyn_sdtr;
- }
- }
- if (ext_msg.req_ack_offset == 0) {
-
- q_cntl &= ~QC_MSG_OUT;
- asc_dvc->init_sdtr &= ~target_id;
- asc_dvc->sdtr_done &= ~target_id;
- AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
- } else {
- if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
-
- q_cntl &= ~QC_MSG_OUT;
- asc_dvc->sdtr_done |= target_id;
- asc_dvc->init_sdtr |= target_id;
- asc_dvc->pci_fix_asyn_xfer &= ~target_id;
- sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
- ext_msg.req_ack_offset);
- AscSetChipSDTR(iop_base, sdtr_data, tid_no);
- boardp->sdtr_data[tid_no] = sdtr_data;
- } else {
-
- q_cntl |= QC_MSG_OUT;
- AscMsgOutSDTR(asc_dvc,
- ext_msg.xfer_period,
- ext_msg.req_ack_offset);
- asc_dvc->pci_fix_asyn_xfer &= ~target_id;
- sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
- ext_msg.req_ack_offset);
- AscSetChipSDTR(iop_base, sdtr_data, tid_no);
- boardp->sdtr_data[tid_no] = sdtr_data;
- asc_dvc->sdtr_done |= target_id;
- asc_dvc->init_sdtr |= target_id;
- }
- }
-
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
- q_cntl);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- } else if (ext_msg.msg_type == MS_EXTEND &&
- ext_msg.msg_req == MS_WDTR_CODE &&
- ext_msg.msg_len == MS_WDTR_LEN) {
-
- ext_msg.wdtr_width = 0;
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *) &ext_msg,
- sizeof(EXT_MSG) >> 1);
- q_cntl |= QC_MSG_OUT;
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
- q_cntl);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- } else {
-
- ext_msg.msg_type = MESSAGE_REJECT;
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *) &ext_msg,
- sizeof(EXT_MSG) >> 1);
- q_cntl |= QC_MSG_OUT;
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
- q_cntl);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- }
- } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
-
- q_cntl |= QC_REQ_SENSE;
-
- if ((asc_dvc->init_sdtr & target_id) != 0) {
-
- asc_dvc->sdtr_done &= ~target_id;
-
- sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
- q_cntl |= QC_MSG_OUT;
- AscMsgOutSDTR(asc_dvc,
- asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
- (uchar) (asc_dvc->max_sdtr_index - 1)],
- (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
- }
-
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
- q_cntl);
-
- tag_code = AscReadLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
- tag_code &= 0xDC;
- if (
- (asc_dvc->pci_fix_asyn_xfer & target_id)
- && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
-) {
-
- tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
- | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
-
- }
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE),
- tag_code);
-
- q_status = AscReadLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS));
- q_status |= (QS_READY | QS_BUSY);
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
- q_status);
-
- scsi_busy = AscReadLramByte(iop_base,
- (ushort) ASCV_SCSIBUSY_B);
- scsi_busy &= ~target_id;
- AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy);
-
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
-
- AscMemWordCopyPtrFromLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *) &out_msg,
- sizeof(EXT_MSG) >> 1);
-
- if ((out_msg.msg_type == MS_EXTEND) &&
- (out_msg.msg_len == MS_SDTR_LEN) &&
- (out_msg.msg_req == MS_SDTR_CODE)) {
-
- asc_dvc->init_sdtr &= ~target_id;
- asc_dvc->sdtr_done &= ~target_id;
- AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
- boardp->sdtr_data[tid_no] = asyn_sdtr;
- }
- q_cntl &= ~QC_MSG_OUT;
- AscWriteLramByte(iop_base,
- (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
- q_cntl);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
-
- scsi_status = AscReadLramByte(iop_base,
- (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS));
- cur_dvc_qng = AscReadLramByte(iop_base,
- (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix));
- if ((cur_dvc_qng > 0) &&
- (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
-
- scsi_busy = AscReadLramByte(iop_base,
- (ushort) ASCV_SCSIBUSY_B);
- scsi_busy |= target_id;
- AscWriteLramByte(iop_base,
- (ushort) ASCV_SCSIBUSY_B, scsi_busy);
- asc_dvc->queue_full_or_busy |= target_id;
-
- if (scsi_status == SAM_STAT_TASK_SET_FULL) {
- if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
- cur_dvc_qng -= 1;
- asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
-
- AscWriteLramByte(iop_base,
- (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG +
- (ushort) tid_no),
- cur_dvc_qng);
-
- /*
- * Set the device queue depth to the number of
- * active requests when the QUEUE FULL condition
- * was encountered.
- */
- boardp->queue_full |= target_id;
- boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
- }
- }
- }
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return (0);
- }
+ EXT_MSG ext_msg;
+ EXT_MSG out_msg;
+ ushort halt_q_addr;
+ int sdtr_accept;
+ ushort int_halt_code;
+ ASC_SCSI_BIT_ID_TYPE scsi_busy;
+ ASC_SCSI_BIT_ID_TYPE target_id;
+ PortAddr iop_base;
+ uchar tag_code;
+ uchar q_status;
+ uchar halt_qp;
+ uchar sdtr_data;
+ uchar target_ix;
+ uchar q_cntl, tid_no;
+ uchar cur_dvc_qng;
+ uchar asyn_sdtr;
+ uchar scsi_status;
+ asc_board_t *boardp;
+
+ ASC_ASSERT(asc_dvc->drv_ptr != NULL);
+ boardp = asc_dvc->drv_ptr;
+
+ iop_base = asc_dvc->iop_base;
+ int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
+
+ halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
+ halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
+ target_ix = AscReadLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_TARGET_IX));
+ q_cntl =
+ AscReadLramByte(iop_base,
+ (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
+ if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+ asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
+ } else {
+ asyn_sdtr = 0;
+ }
+ if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
+ if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+ AscSetChipSDTR(iop_base, 0, tid_no);
+ boardp->sdtr_data[tid_no] = 0;
+ }
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
+ if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+ AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+ boardp->sdtr_data[tid_no] = asyn_sdtr;
+ }
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
+
+ AscMemWordCopyPtrFromLram(iop_base,
+ ASCV_MSGIN_BEG,
+ (uchar *)&ext_msg,
+ sizeof(EXT_MSG) >> 1);
+
+ if (ext_msg.msg_type == MS_EXTEND &&
+ ext_msg.msg_req == MS_SDTR_CODE &&
+ ext_msg.msg_len == MS_SDTR_LEN) {
+ sdtr_accept = TRUE;
+ if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
+
+ sdtr_accept = FALSE;
+ ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
+ }
+ if ((ext_msg.xfer_period <
+ asc_dvc->sdtr_period_tbl[asc_dvc->
+ host_init_sdtr_index])
+ || (ext_msg.xfer_period >
+ asc_dvc->sdtr_period_tbl[asc_dvc->
+ max_sdtr_index])) {
+ sdtr_accept = FALSE;
+ ext_msg.xfer_period =
+ asc_dvc->sdtr_period_tbl[asc_dvc->
+ host_init_sdtr_index];
+ }
+ if (sdtr_accept) {
+ sdtr_data =
+ AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+ ext_msg.req_ack_offset);
+ if ((sdtr_data == 0xFF)) {
+
+ q_cntl |= QC_MSG_OUT;
+ asc_dvc->init_sdtr &= ~target_id;
+ asc_dvc->sdtr_done &= ~target_id;
+ AscSetChipSDTR(iop_base, asyn_sdtr,
+ tid_no);
+ boardp->sdtr_data[tid_no] = asyn_sdtr;
+ }
+ }
+ if (ext_msg.req_ack_offset == 0) {
+
+ q_cntl &= ~QC_MSG_OUT;
+ asc_dvc->init_sdtr &= ~target_id;
+ asc_dvc->sdtr_done &= ~target_id;
+ AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+ } else {
+ if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+
+ q_cntl &= ~QC_MSG_OUT;
+ asc_dvc->sdtr_done |= target_id;
+ asc_dvc->init_sdtr |= target_id;
+ asc_dvc->pci_fix_asyn_xfer &=
+ ~target_id;
+ sdtr_data =
+ AscCalSDTRData(asc_dvc,
+ ext_msg.xfer_period,
+ ext_msg.
+ req_ack_offset);
+ AscSetChipSDTR(iop_base, sdtr_data,
+ tid_no);
+ boardp->sdtr_data[tid_no] = sdtr_data;
+ } else {
+
+ q_cntl |= QC_MSG_OUT;
+ AscMsgOutSDTR(asc_dvc,
+ ext_msg.xfer_period,
+ ext_msg.req_ack_offset);
+ asc_dvc->pci_fix_asyn_xfer &=
+ ~target_id;
+ sdtr_data =
+ AscCalSDTRData(asc_dvc,
+ ext_msg.xfer_period,
+ ext_msg.
+ req_ack_offset);
+ AscSetChipSDTR(iop_base, sdtr_data,
+ tid_no);
+ boardp->sdtr_data[tid_no] = sdtr_data;
+ asc_dvc->sdtr_done |= target_id;
+ asc_dvc->init_sdtr |= target_id;
+ }
+ }
+
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_CNTL),
+ q_cntl);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ } else if (ext_msg.msg_type == MS_EXTEND &&
+ ext_msg.msg_req == MS_WDTR_CODE &&
+ ext_msg.msg_len == MS_WDTR_LEN) {
+
+ ext_msg.wdtr_width = 0;
+ AscMemWordCopyPtrToLram(iop_base,
+ ASCV_MSGOUT_BEG,
+ (uchar *)&ext_msg,
+ sizeof(EXT_MSG) >> 1);
+ q_cntl |= QC_MSG_OUT;
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_CNTL),
+ q_cntl);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ } else {
+
+ ext_msg.msg_type = MESSAGE_REJECT;
+ AscMemWordCopyPtrToLram(iop_base,
+ ASCV_MSGOUT_BEG,
+ (uchar *)&ext_msg,
+ sizeof(EXT_MSG) >> 1);
+ q_cntl |= QC_MSG_OUT;
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_CNTL),
+ q_cntl);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ }
+ } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
+
+ q_cntl |= QC_REQ_SENSE;
+
+ if ((asc_dvc->init_sdtr & target_id) != 0) {
+
+ asc_dvc->sdtr_done &= ~target_id;
+
+ sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+ q_cntl |= QC_MSG_OUT;
+ AscMsgOutSDTR(asc_dvc,
+ asc_dvc->
+ sdtr_period_tbl[(sdtr_data >> 4) &
+ (uchar)(asc_dvc->
+ max_sdtr_index -
+ 1)],
+ (uchar)(sdtr_data & (uchar)
+ ASC_SYN_MAX_OFFSET));
+ }
+
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
+
+ tag_code = AscReadLramByte(iop_base,
+ (ushort)(halt_q_addr + (ushort)
+ ASC_SCSIQ_B_TAG_CODE));
+ tag_code &= 0xDC;
+ if ((asc_dvc->pci_fix_asyn_xfer & target_id)
+ && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
+ ) {
+
+ tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
+ | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
+
+ }
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_TAG_CODE),
+ tag_code);
+
+ q_status = AscReadLramByte(iop_base,
+ (ushort)(halt_q_addr + (ushort)
+ ASC_SCSIQ_B_STATUS));
+ q_status |= (QS_READY | QS_BUSY);
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_STATUS),
+ q_status);
+
+ scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
+ scsi_busy &= ~target_id;
+ AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
+
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
+
+ AscMemWordCopyPtrFromLram(iop_base,
+ ASCV_MSGOUT_BEG,
+ (uchar *)&out_msg,
+ sizeof(EXT_MSG) >> 1);
+
+ if ((out_msg.msg_type == MS_EXTEND) &&
+ (out_msg.msg_len == MS_SDTR_LEN) &&
+ (out_msg.msg_req == MS_SDTR_CODE)) {
+
+ asc_dvc->init_sdtr &= ~target_id;
+ asc_dvc->sdtr_done &= ~target_id;
+ AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+ boardp->sdtr_data[tid_no] = asyn_sdtr;
+ }
+ q_cntl &= ~QC_MSG_OUT;
+ AscWriteLramByte(iop_base,
+ (ushort)(halt_q_addr +
+ (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
+
+ scsi_status = AscReadLramByte(iop_base,
+ (ushort)((ushort)halt_q_addr +
+ (ushort)
+ ASC_SCSIQ_SCSI_STATUS));
+ cur_dvc_qng =
+ AscReadLramByte(iop_base,
+ (ushort)((ushort)ASC_QADR_BEG +
+ (ushort)target_ix));
+ if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
+
+ scsi_busy = AscReadLramByte(iop_base,
+ (ushort)ASCV_SCSIBUSY_B);
+ scsi_busy |= target_id;
+ AscWriteLramByte(iop_base,
+ (ushort)ASCV_SCSIBUSY_B, scsi_busy);
+ asc_dvc->queue_full_or_busy |= target_id;
+
+ if (scsi_status == SAM_STAT_TASK_SET_FULL) {
+ if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
+ cur_dvc_qng -= 1;
+ asc_dvc->max_dvc_qng[tid_no] =
+ cur_dvc_qng;
+
+ AscWriteLramByte(iop_base,
+ (ushort)((ushort)
+ ASCV_MAX_DVC_QNG_BEG
+ + (ushort)
+ tid_no),
+ cur_dvc_qng);
+
+ /*
+ * Set the device queue depth to the number of
+ * active requests when the QUEUE FULL condition
+ * was encountered.
+ */
+ boardp->queue_full |= target_id;
+ boardp->queue_full_cnt[tid_no] =
+ cur_dvc_qng;
+ }
+ }
+ }
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ }
#if CC_VERY_LONG_SG_LIST
- else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
- {
- uchar q_no;
- ushort q_addr;
- uchar sg_wk_q_no;
- uchar first_sg_wk_q_no;
- ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
- ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
- ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
- ushort sg_list_dwords;
- ushort sg_entry_cnt;
- uchar next_qp;
- int i;
-
- q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
- if (q_no == ASC_QLINK_END)
- {
- return(0);
- }
-
- q_addr = ASC_QNO_TO_QADDR(q_no);
-
- /*
- * Convert the request's SRB pointer to a host ASC_SCSI_REQ
- * structure pointer using a macro provided by the driver.
- * The ASC_SCSI_REQ pointer provides a pointer to the
- * host ASC_SG_HEAD structure.
- */
- /* Read request's SRB pointer. */
- scsiq = (ASC_SCSI_Q *)
- ASC_SRB2SCSIQ(
- ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
- (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR))));
-
- /*
- * Get request's first and working SG queue.
- */
- sg_wk_q_no = AscReadLramByte(iop_base,
- (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
-
- first_sg_wk_q_no = AscReadLramByte(iop_base,
- (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
-
- /*
- * Reset request's working SG queue back to the
- * first SG queue.
- */
- AscWriteLramByte(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
- first_sg_wk_q_no);
-
- sg_head = scsiq->sg_head;
-
- /*
- * Set sg_entry_cnt to the number of SG elements
- * that will be completed on this interrupt.
- *
- * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
- * SG elements. The data_cnt and data_addr fields which
- * add 1 to the SG element capacity are not used when
- * restarting SG handling after a halt.
- */
- if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
- {
- sg_entry_cnt = ASC_MAX_SG_LIST - 1;
-
- /*
- * Keep track of remaining number of SG elements that will
- * need to be handled on the next interrupt.
- */
- scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
- } else
- {
- sg_entry_cnt = scsiq->remain_sg_entry_cnt;
- scsiq->remain_sg_entry_cnt = 0;
- }
-
- /*
- * Copy SG elements into the list of allocated SG queues.
- *
- * Last index completed is saved in scsiq->next_sg_index.
- */
- next_qp = first_sg_wk_q_no;
- q_addr = ASC_QNO_TO_QADDR(next_qp);
- scsi_sg_q.sg_head_qp = q_no;
- scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
- for( i = 0; i < sg_head->queue_cnt; i++)
- {
- scsi_sg_q.seq_no = i + 1;
- if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
- {
- sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
- sg_entry_cnt -= ASC_SG_LIST_PER_Q;
- /*
- * After very first SG queue RISC FW uses next
- * SG queue first element then checks sg_list_cnt
- * against zero and then decrements, so set
- * sg_list_cnt 1 less than number of SG elements
- * in each SG queue.
- */
- scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
- scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
- } else {
- /*
- * This is the last SG queue in the list of
- * allocated SG queues. If there are more
- * SG elements than will fit in the allocated
- * queues, then set the QCSG_SG_XFER_MORE flag.
- */
- if (scsiq->remain_sg_entry_cnt != 0)
- {
- scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
- } else
- {
- scsi_sg_q.cntl |= QCSG_SG_XFER_END;
- }
- /* equals sg_entry_cnt * 2 */
- sg_list_dwords = sg_entry_cnt << 1;
- scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
- scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
- sg_entry_cnt = 0;
- }
-
- scsi_sg_q.q_no = next_qp;
- AscMemWordCopyPtrToLram(iop_base,
- q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
- (uchar *) &scsi_sg_q,
- sizeof(ASC_SG_LIST_Q) >> 1);
-
- AscMemDWordCopyPtrToLram(iop_base,
- q_addr + ASC_SGQ_LIST_BEG,
- (uchar *) &sg_head->sg_list[scsiq->next_sg_index],
- sg_list_dwords);
-
- scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
-
- /*
- * If the just completed SG queue contained the
- * last SG element, then no more SG queues need
- * to be written.
- */
- if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
- {
- break;
- }
-
- next_qp = AscReadLramByte( iop_base,
- ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
- q_addr = ASC_QNO_TO_QADDR( next_qp );
- }
-
- /*
- * Clear the halt condition so the RISC will be restarted
- * after the return.
- */
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- return(0);
- }
+ else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
+ uchar q_no;
+ ushort q_addr;
+ uchar sg_wk_q_no;
+ uchar first_sg_wk_q_no;
+ ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
+ ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
+ ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
+ ushort sg_list_dwords;
+ ushort sg_entry_cnt;
+ uchar next_qp;
+ int i;
+
+ q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
+ if (q_no == ASC_QLINK_END) {
+ return (0);
+ }
+
+ q_addr = ASC_QNO_TO_QADDR(q_no);
+
+ /*
+ * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+ * structure pointer using a macro provided by the driver.
+ * The ASC_SCSI_REQ pointer provides a pointer to the
+ * host ASC_SG_HEAD structure.
+ */
+ /* Read request's SRB pointer. */
+ scsiq = (ASC_SCSI_Q *)
+ ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
+ (ushort)
+ (q_addr +
+ ASC_SCSIQ_D_SRBPTR))));
+
+ /*
+ * Get request's first and working SG queue.
+ */
+ sg_wk_q_no = AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_SG_WK_QP));
+
+ first_sg_wk_q_no = AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_FIRST_SG_WK_QP));
+
+ /*
+ * Reset request's working SG queue back to the
+ * first SG queue.
+ */
+ AscWriteLramByte(iop_base,
+ (ushort)(q_addr +
+ (ushort)ASC_SCSIQ_B_SG_WK_QP),
+ first_sg_wk_q_no);
+
+ sg_head = scsiq->sg_head;
+
+ /*
+ * Set sg_entry_cnt to the number of SG elements
+ * that will be completed on this interrupt.
+ *
+ * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+ * SG elements. The data_cnt and data_addr fields which
+ * add 1 to the SG element capacity are not used when
+ * restarting SG handling after a halt.
+ */
+ if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
+ sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+ /*
+ * Keep track of remaining number of SG elements that will
+ * need to be handled on the next interrupt.
+ */
+ scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+ } else {
+ sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+ scsiq->remain_sg_entry_cnt = 0;
+ }
+
+ /*
+ * Copy SG elements into the list of allocated SG queues.
+ *
+ * Last index completed is saved in scsiq->next_sg_index.
+ */
+ next_qp = first_sg_wk_q_no;
+ q_addr = ASC_QNO_TO_QADDR(next_qp);
+ scsi_sg_q.sg_head_qp = q_no;
+ scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+ for (i = 0; i < sg_head->queue_cnt; i++) {
+ scsi_sg_q.seq_no = i + 1;
+ if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+ sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
+ sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+ /*
+ * After very first SG queue RISC FW uses next
+ * SG queue first element then checks sg_list_cnt
+ * against zero and then decrements, so set
+ * sg_list_cnt 1 less than number of SG elements
+ * in each SG queue.
+ */
+ scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+ scsi_sg_q.sg_cur_list_cnt =
+ ASC_SG_LIST_PER_Q - 1;
+ } else {
+ /*
+ * This is the last SG queue in the list of
+ * allocated SG queues. If there are more
+ * SG elements than will fit in the allocated
+ * queues, then set the QCSG_SG_XFER_MORE flag.
+ */
+ if (scsiq->remain_sg_entry_cnt != 0) {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+ } else {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+ }
+ /* equals sg_entry_cnt * 2 */
+ sg_list_dwords = sg_entry_cnt << 1;
+ scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+ scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+ sg_entry_cnt = 0;
+ }
+
+ scsi_sg_q.q_no = next_qp;
+ AscMemWordCopyPtrToLram(iop_base,
+ q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+ (uchar *)&scsi_sg_q,
+ sizeof(ASC_SG_LIST_Q) >> 1);
+
+ AscMemDWordCopyPtrToLram(iop_base,
+ q_addr + ASC_SGQ_LIST_BEG,
+ (uchar *)&sg_head->
+ sg_list[scsiq->next_sg_index],
+ sg_list_dwords);
+
+ scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+ /*
+ * If the just completed SG queue contained the
+ * last SG element, then no more SG queues need
+ * to be written.
+ */
+ if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
+ break;
+ }
+
+ next_qp = AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_FWD));
+ q_addr = ASC_QNO_TO_QADDR(next_qp);
+ }
+
+ /*
+ * Clear the halt condition so the RISC will be restarted
+ * after the return.
+ */
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ return (0);
+ }
#endif /* CC_VERY_LONG_SG_LIST */
- return (0);
+ return (0);
}
-STATIC uchar
-_AscCopyLramScsiDoneQ(
- PortAddr iop_base,
- ushort q_addr,
- ASC_QDONE_INFO * scsiq,
- ASC_DCNT max_dma_count
-)
+static uchar
+_AscCopyLramScsiDoneQ(PortAddr iop_base,
+ ushort q_addr,
+ ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
{
- ushort _val;
- uchar sg_queue_cnt;
-
- DvcGetQinfo(iop_base,
- q_addr + ASC_SCSIQ_DONE_INFO_BEG,
- (uchar *) scsiq,
- (sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2);
-
- _val = AscReadLramWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
- scsiq->q_status = (uchar) _val;
- scsiq->q_no = (uchar) (_val >> 8);
- _val = AscReadLramWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL));
- scsiq->cntl = (uchar) _val;
- sg_queue_cnt = (uchar) (_val >> 8);
- _val = AscReadLramWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
- scsiq->sense_len = (uchar) _val;
- scsiq->extra_bytes = (uchar) (_val >> 8);
-
- /*
- * Read high word of remain bytes from alternate location.
- */
- scsiq->remain_bytes = (((ADV_DCNT) AscReadLramWord( iop_base,
- (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
- /*
- * Read low word of remain bytes from original location.
- */
- scsiq->remain_bytes += AscReadLramWord(iop_base,
- (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
-
- scsiq->remain_bytes &= max_dma_count;
- return (sg_queue_cnt);
+ ushort _val;
+ uchar sg_queue_cnt;
+
+ DvcGetQinfo(iop_base,
+ q_addr + ASC_SCSIQ_DONE_INFO_BEG,
+ (uchar *)scsiq,
+ (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
+
+ _val = AscReadLramWord(iop_base,
+ (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
+ scsiq->q_status = (uchar)_val;
+ scsiq->q_no = (uchar)(_val >> 8);
+ _val = AscReadLramWord(iop_base,
+ (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
+ scsiq->cntl = (uchar)_val;
+ sg_queue_cnt = (uchar)(_val >> 8);
+ _val = AscReadLramWord(iop_base,
+ (ushort)(q_addr +
+ (ushort)ASC_SCSIQ_B_SENSE_LEN));
+ scsiq->sense_len = (uchar)_val;
+ scsiq->extra_bytes = (uchar)(_val >> 8);
+
+ /*
+ * Read high word of remain bytes from alternate location.
+ */
+ scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
+ (ushort)(q_addr +
+ (ushort)
+ ASC_SCSIQ_W_ALT_DC1)))
+ << 16);
+ /*
+ * Read low word of remain bytes from original location.
+ */
+ scsiq->remain_bytes += AscReadLramWord(iop_base,
+ (ushort)(q_addr + (ushort)
+ ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
+ scsiq->remain_bytes &= max_dma_count;
+ return (sg_queue_cnt);
}
-STATIC int
-AscIsrQDone(
- ASC_DVC_VAR *asc_dvc
-)
+static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
{
- uchar next_qp;
- uchar n_q_used;
- uchar sg_list_qp;
- uchar sg_queue_cnt;
- uchar q_cnt;
- uchar done_q_tail;
- uchar tid_no;
- ASC_SCSI_BIT_ID_TYPE scsi_busy;
- ASC_SCSI_BIT_ID_TYPE target_id;
- PortAddr iop_base;
- ushort q_addr;
- ushort sg_q_addr;
- uchar cur_target_qng;
- ASC_QDONE_INFO scsiq_buf;
- ASC_QDONE_INFO *scsiq;
- int false_overrun;
- ASC_ISR_CALLBACK asc_isr_callback;
-
- iop_base = asc_dvc->iop_base;
- asc_isr_callback = asc_dvc->isr_callback;
- n_q_used = 1;
- scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
- done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
- q_addr = ASC_QNO_TO_QADDR(done_q_tail);
- next_qp = AscReadLramByte(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD));
- if (next_qp != ASC_QLINK_END) {
- AscPutVarDoneQTail(iop_base, next_qp);
- q_addr = ASC_QNO_TO_QADDR(next_qp);
- sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
- asc_dvc->max_dma_count);
- AscWriteLramByte(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
- (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED)));
- tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
- target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
- if ((scsiq->cntl & QC_SG_HEAD) != 0) {
- sg_q_addr = q_addr;
- sg_list_qp = next_qp;
- for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
- sg_list_qp = AscReadLramByte(iop_base,
- (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD));
- sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
- if (sg_list_qp == ASC_QLINK_END) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS);
- scsiq->d3.done_stat = QD_WITH_ERROR;
- scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED;
- goto FATAL_ERR_QDONE;
- }
- AscWriteLramByte(iop_base,
- (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
- QS_FREE);
- }
- n_q_used = sg_queue_cnt + 1;
- AscPutVarDoneQTail(iop_base, sg_list_qp);
- }
- if (asc_dvc->queue_full_or_busy & target_id) {
- cur_target_qng = AscReadLramByte(iop_base,
- (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix));
- if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
- scsi_busy = AscReadLramByte(iop_base,
- (ushort) ASCV_SCSIBUSY_B);
- scsi_busy &= ~target_id;
- AscWriteLramByte(iop_base,
- (ushort) ASCV_SCSIBUSY_B, scsi_busy);
- asc_dvc->queue_full_or_busy &= ~target_id;
- }
- }
- if (asc_dvc->cur_total_qng >= n_q_used) {
- asc_dvc->cur_total_qng -= n_q_used;
- if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
- asc_dvc->cur_dvc_qng[tid_no]--;
- }
- } else {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
- scsiq->d3.done_stat = QD_WITH_ERROR;
- goto FATAL_ERR_QDONE;
- }
- if ((scsiq->d2.srb_ptr == 0UL) ||
- ((scsiq->q_status & QS_ABORTED) != 0)) {
- return (0x11);
- } else if (scsiq->q_status == QS_DONE) {
- false_overrun = FALSE;
- if (scsiq->extra_bytes != 0) {
- scsiq->remain_bytes += (ADV_DCNT) scsiq->extra_bytes;
- }
- if (scsiq->d3.done_stat == QD_WITH_ERROR) {
- if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) {
- if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
- scsiq->d3.done_stat = QD_NO_ERROR;
- scsiq->d3.host_stat = QHSTA_NO_ERROR;
- } else if (false_overrun) {
- scsiq->d3.done_stat = QD_NO_ERROR;
- scsiq->d3.host_stat = QHSTA_NO_ERROR;
- }
- } else if (scsiq->d3.host_stat ==
- QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
- AscStopChip(iop_base);
- AscSetChipControl(iop_base,
- (uchar) (CC_SCSI_RESET | CC_HALT));
- DvcDelayNanoSecond(asc_dvc, 60000);
- AscSetChipControl(iop_base, CC_HALT);
- AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
- AscSetChipStatus(iop_base, 0);
- AscSetChipControl(iop_base, 0);
- }
- }
- if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
- (*asc_isr_callback) (asc_dvc, scsiq);
- } else {
- if ((AscReadLramByte(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
- START_STOP)) {
- asc_dvc->unit_not_ready &= ~target_id;
- if (scsiq->d3.done_stat != QD_NO_ERROR) {
- asc_dvc->start_motor &= ~target_id;
- }
- }
- }
- return (1);
- } else {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
- FATAL_ERR_QDONE:
- if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
- (*asc_isr_callback) (asc_dvc, scsiq);
- }
- return (0x80);
- }
- }
- return (0);
+ uchar next_qp;
+ uchar n_q_used;
+ uchar sg_list_qp;
+ uchar sg_queue_cnt;
+ uchar q_cnt;
+ uchar done_q_tail;
+ uchar tid_no;
+ ASC_SCSI_BIT_ID_TYPE scsi_busy;
+ ASC_SCSI_BIT_ID_TYPE target_id;
+ PortAddr iop_base;
+ ushort q_addr;
+ ushort sg_q_addr;
+ uchar cur_target_qng;
+ ASC_QDONE_INFO scsiq_buf;
+ ASC_QDONE_INFO *scsiq;
+ int false_overrun;
+ ASC_ISR_CALLBACK asc_isr_callback;
+
+ iop_base = asc_dvc->iop_base;
+ asc_isr_callback = asc_dvc->isr_callback;
+ n_q_used = 1;
+ scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
+ done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
+ q_addr = ASC_QNO_TO_QADDR(done_q_tail);
+ next_qp = AscReadLramByte(iop_base,
+ (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
+ if (next_qp != ASC_QLINK_END) {
+ AscPutVarDoneQTail(iop_base, next_qp);
+ q_addr = ASC_QNO_TO_QADDR(next_qp);
+ sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
+ asc_dvc->max_dma_count);
+ AscWriteLramByte(iop_base,
+ (ushort)(q_addr +
+ (ushort)ASC_SCSIQ_B_STATUS),
+ (uchar)(scsiq->
+ q_status & (uchar)~(QS_READY |
+ QS_ABORTED)));
+ tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
+ target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
+ if ((scsiq->cntl & QC_SG_HEAD) != 0) {
+ sg_q_addr = q_addr;
+ sg_list_qp = next_qp;
+ for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
+ sg_list_qp = AscReadLramByte(iop_base,
+ (ushort)(sg_q_addr
+ + (ushort)
+ ASC_SCSIQ_B_FWD));
+ sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
+ if (sg_list_qp == ASC_QLINK_END) {
+ AscSetLibErrorCode(asc_dvc,
+ ASCQ_ERR_SG_Q_LINKS);
+ scsiq->d3.done_stat = QD_WITH_ERROR;
+ scsiq->d3.host_stat =
+ QHSTA_D_QDONE_SG_LIST_CORRUPTED;
+ goto FATAL_ERR_QDONE;
+ }
+ AscWriteLramByte(iop_base,
+ (ushort)(sg_q_addr + (ushort)
+ ASC_SCSIQ_B_STATUS),
+ QS_FREE);
+ }
+ n_q_used = sg_queue_cnt + 1;
+ AscPutVarDoneQTail(iop_base, sg_list_qp);
+ }
+ if (asc_dvc->queue_full_or_busy & target_id) {
+ cur_target_qng = AscReadLramByte(iop_base,
+ (ushort)((ushort)
+ ASC_QADR_BEG
+ + (ushort)
+ scsiq->d2.
+ target_ix));
+ if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
+ scsi_busy = AscReadLramByte(iop_base, (ushort)
+ ASCV_SCSIBUSY_B);
+ scsi_busy &= ~target_id;
+ AscWriteLramByte(iop_base,
+ (ushort)ASCV_SCSIBUSY_B,
+ scsi_busy);
+ asc_dvc->queue_full_or_busy &= ~target_id;
+ }
+ }
+ if (asc_dvc->cur_total_qng >= n_q_used) {
+ asc_dvc->cur_total_qng -= n_q_used;
+ if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
+ asc_dvc->cur_dvc_qng[tid_no]--;
+ }
+ } else {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
+ scsiq->d3.done_stat = QD_WITH_ERROR;
+ goto FATAL_ERR_QDONE;
+ }
+ if ((scsiq->d2.srb_ptr == 0UL) ||
+ ((scsiq->q_status & QS_ABORTED) != 0)) {
+ return (0x11);
+ } else if (scsiq->q_status == QS_DONE) {
+ false_overrun = FALSE;
+ if (scsiq->extra_bytes != 0) {
+ scsiq->remain_bytes +=
+ (ADV_DCNT)scsiq->extra_bytes;
+ }
+ if (scsiq->d3.done_stat == QD_WITH_ERROR) {
+ if (scsiq->d3.host_stat ==
+ QHSTA_M_DATA_OVER_RUN) {
+ if ((scsiq->
+ cntl & (QC_DATA_IN | QC_DATA_OUT))
+ == 0) {
+ scsiq->d3.done_stat =
+ QD_NO_ERROR;
+ scsiq->d3.host_stat =
+ QHSTA_NO_ERROR;
+ } else if (false_overrun) {
+ scsiq->d3.done_stat =
+ QD_NO_ERROR;
+ scsiq->d3.host_stat =
+ QHSTA_NO_ERROR;
+ }
+ } else if (scsiq->d3.host_stat ==
+ QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
+ AscStopChip(iop_base);
+ AscSetChipControl(iop_base,
+ (uchar)(CC_SCSI_RESET
+ | CC_HALT));
+ DvcDelayNanoSecond(asc_dvc, 60000);
+ AscSetChipControl(iop_base, CC_HALT);
+ AscSetChipStatus(iop_base,
+ CIW_CLR_SCSI_RESET_INT);
+ AscSetChipStatus(iop_base, 0);
+ AscSetChipControl(iop_base, 0);
+ }
+ }
+ if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+ (*asc_isr_callback) (asc_dvc, scsiq);
+ } else {
+ if ((AscReadLramByte(iop_base,
+ (ushort)(q_addr + (ushort)
+ ASC_SCSIQ_CDB_BEG))
+ == START_STOP)) {
+ asc_dvc->unit_not_ready &= ~target_id;
+ if (scsiq->d3.done_stat != QD_NO_ERROR) {
+ asc_dvc->start_motor &=
+ ~target_id;
+ }
+ }
+ }
+ return (1);
+ } else {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
+ FATAL_ERR_QDONE:
+ if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+ (*asc_isr_callback) (asc_dvc, scsiq);
+ }
+ return (0x80);
+ }
+ }
+ return (0);
}
-STATIC int
-AscISR(
- ASC_DVC_VAR *asc_dvc
-)
+static int AscISR(ASC_DVC_VAR *asc_dvc)
{
- ASC_CS_TYPE chipstat;
- PortAddr iop_base;
- ushort saved_ram_addr;
- uchar ctrl_reg;
- uchar saved_ctrl_reg;
- int int_pending;
- int status;
- uchar host_flag;
-
- iop_base = asc_dvc->iop_base;
- int_pending = FALSE;
-
- if (AscIsIntPending(iop_base) == 0)
- {
- return int_pending;
- }
+ ASC_CS_TYPE chipstat;
+ PortAddr iop_base;
+ ushort saved_ram_addr;
+ uchar ctrl_reg;
+ uchar saved_ctrl_reg;
+ int int_pending;
+ int status;
+ uchar host_flag;
+
+ iop_base = asc_dvc->iop_base;
+ int_pending = FALSE;
+
+ if (AscIsIntPending(iop_base) == 0) {
+ return int_pending;
+ }
- if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
- || (asc_dvc->isr_callback == 0)
-) {
- return (ERR);
- }
- if (asc_dvc->in_critical_cnt != 0) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
- return (ERR);
- }
- if (asc_dvc->is_in_int) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
- return (ERR);
- }
- asc_dvc->is_in_int = TRUE;
- ctrl_reg = AscGetChipControl(iop_base);
- saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
- CC_SINGLE_STEP | CC_DIAG | CC_TEST));
- chipstat = AscGetChipStatus(iop_base);
- if (chipstat & CSW_SCSI_RESET_LATCH) {
- if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
- int i = 10;
- int_pending = TRUE;
- asc_dvc->sdtr_done = 0;
- saved_ctrl_reg &= (uchar) (~CC_HALT);
- while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) &&
- (i-- > 0))
- {
- DvcSleepMilliSecond(100);
- }
- AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
- AscSetChipControl(iop_base, CC_HALT);
- AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
- AscSetChipStatus(iop_base, 0);
- chipstat = AscGetChipStatus(iop_base);
- }
- }
- saved_ram_addr = AscGetChipLramAddr(iop_base);
- host_flag = AscReadLramByte(iop_base,
- ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR);
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
- (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
- if ((chipstat & CSW_INT_PENDING)
- || (int_pending)
-) {
- AscAckInterrupt(iop_base);
- int_pending = TRUE;
- if ((chipstat & CSW_HALTED) &&
- (ctrl_reg & CC_SINGLE_STEP)) {
- if (AscIsrChipHalted(asc_dvc) == ERR) {
- goto ISR_REPORT_QDONE_FATAL_ERROR;
- } else {
- saved_ctrl_reg &= (uchar) (~CC_HALT);
- }
- } else {
- ISR_REPORT_QDONE_FATAL_ERROR:
- if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
- while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) {
- }
- } else {
- do {
- if ((status = AscIsrQDone(asc_dvc)) == 1) {
- break;
- }
- } while (status == 0x11);
- }
- if ((status & 0x80) != 0)
- int_pending = ERR;
- }
- }
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
- AscSetChipLramAddr(iop_base, saved_ram_addr);
- AscSetChipControl(iop_base, saved_ctrl_reg);
- asc_dvc->is_in_int = FALSE;
- return (int_pending);
+ if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
+ || (asc_dvc->isr_callback == 0)
+ ) {
+ return (ERR);
+ }
+ if (asc_dvc->in_critical_cnt != 0) {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
+ return (ERR);
+ }
+ if (asc_dvc->is_in_int) {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
+ return (ERR);
+ }
+ asc_dvc->is_in_int = TRUE;
+ ctrl_reg = AscGetChipControl(iop_base);
+ saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
+ CC_SINGLE_STEP | CC_DIAG | CC_TEST));
+ chipstat = AscGetChipStatus(iop_base);
+ if (chipstat & CSW_SCSI_RESET_LATCH) {
+ if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+ int i = 10;
+ int_pending = TRUE;
+ asc_dvc->sdtr_done = 0;
+ saved_ctrl_reg &= (uchar)(~CC_HALT);
+ while ((AscGetChipStatus(iop_base) &
+ CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
+ DvcSleepMilliSecond(100);
+ }
+ AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
+ AscSetChipControl(iop_base, CC_HALT);
+ AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+ AscSetChipStatus(iop_base, 0);
+ chipstat = AscGetChipStatus(iop_base);
+ }
+ }
+ saved_ram_addr = AscGetChipLramAddr(iop_base);
+ host_flag = AscReadLramByte(iop_base,
+ ASCV_HOST_FLAG_B) &
+ (uchar)(~ASC_HOST_FLAG_IN_ISR);
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+ (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
+ if ((chipstat & CSW_INT_PENDING)
+ || (int_pending)
+ ) {
+ AscAckInterrupt(iop_base);
+ int_pending = TRUE;
+ if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
+ if (AscIsrChipHalted(asc_dvc) == ERR) {
+ goto ISR_REPORT_QDONE_FATAL_ERROR;
+ } else {
+ saved_ctrl_reg &= (uchar)(~CC_HALT);
+ }
+ } else {
+ ISR_REPORT_QDONE_FATAL_ERROR:
+ if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
+ while (((status =
+ AscIsrQDone(asc_dvc)) & 0x01) != 0) {
+ }
+ } else {
+ do {
+ if ((status =
+ AscIsrQDone(asc_dvc)) == 1) {
+ break;
+ }
+ } while (status == 0x11);
+ }
+ if ((status & 0x80) != 0)
+ int_pending = ERR;
+ }
+ }
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+ AscSetChipLramAddr(iop_base, saved_ram_addr);
+ AscSetChipControl(iop_base, saved_ctrl_reg);
+ asc_dvc->is_in_int = FALSE;
+ return (int_pending);
}
/* Microcode buffer is kept after initialization for error recovery. */
-STATIC uchar _asc_mcode_buf[] =
-{
- 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
- 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80,
- 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
- 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
- 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00,
- 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1,
- 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
- 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00, 0x84, 0x97, 0x07, 0xA6,
- 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00,
- 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
- 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x34, 0x01, 0x00, 0x33,
- 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04,
- 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
- 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01, 0x00, 0x33, 0x0A, 0x00,
- 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04,
- 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
- 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x3C, 0x01, 0x00, 0x05,
- 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01,
- 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
- 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23,
- 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0,
- 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x84, 0x97,
- 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80,
- 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
- 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x04, 0x98, 0xF0, 0x80,
- 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6,
- 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
- 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02, 0x07, 0xA6, 0x5A, 0x02,
- 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96,
- 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
- 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01,
- 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02,
- 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
- 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43,
- 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01,
- 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
- 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8, 0x00, 0x33, 0x1F, 0x00,
- 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6,
- 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
- 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xEE, 0x82,
- 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8,
- 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
- 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x3C, 0x04, 0x06, 0xA6,
- 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83,
- 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
- 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x7A, 0x03,
- 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03,
- 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
- 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6, 0xA4, 0x03, 0x00, 0xA6,
- 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03,
- 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
- 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95, 0xC0, 0x83, 0x00, 0x33,
- 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23,
- 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
- 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04, 0x06, 0xA6, 0x0A, 0x04,
- 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84,
- 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
- 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6, 0x38, 0x04, 0x00, 0x33,
- 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC,
- 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
- 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01,
- 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00,
- 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
- 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04, 0x08, 0x23, 0x22, 0xA3,
- 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23,
- 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
- 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xE8, 0x81,
- 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81,
- 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
- 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xF4, 0x04, 0x00, 0x33,
- 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01,
- 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
- 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85, 0x46, 0x97, 0xCD, 0x04,
- 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85,
- 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
- 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01,
- 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01,
- 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
- 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xF8, 0x05,
- 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0,
- 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
- 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x62, 0x97, 0x04, 0x85,
- 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0,
- 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
- 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05, 0x80, 0x67, 0x80, 0x63,
- 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23,
- 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
- 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6,
- 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
- 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01,
- 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
- 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23, 0xDF, 0x00, 0x06, 0xA6,
- 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20,
- 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
- 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63,
- 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43,
- 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
- 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x07, 0xA6, 0xD6, 0x06,
- 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6,
- 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
- 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01,
- 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33,
- 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
- 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00, 0x80, 0x67,
- 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61,
- 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
- 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05,
- 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01,
- 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
- 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, 0x70, 0x00,
- 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00,
- 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
- 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC4, 0x07, 0x00, 0x33,
- 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01,
- 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
- 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63,
- 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02,
- 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
- 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF3, 0x04,
- 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08,
- 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
- 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5A, 0x88, 0x02, 0x01,
- 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08,
- 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
- 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B,
- 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09,
- 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
- 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
- 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
- 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
- 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
- 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
- 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
+static uchar _asc_mcode_buf[] = {
+ 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
+ 0x03, 0x23, 0x36, 0x40,
+ 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
+ 0xC2, 0x00, 0x92, 0x80,
+ 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
+ 0xB6, 0x00, 0x92, 0x80,
+ 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
+ 0x92, 0x80, 0x80, 0x62,
+ 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
+ 0xCD, 0x04, 0x4D, 0x00,
+ 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
+ 0xE6, 0x84, 0xD2, 0xC1,
+ 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
+ 0xC6, 0x81, 0xC2, 0x88,
+ 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
+ 0x84, 0x97, 0x07, 0xA6,
+ 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
+ 0xC2, 0x88, 0xCE, 0x00,
+ 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
+ 0x80, 0x63, 0x07, 0xA6,
+ 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
+ 0x34, 0x01, 0x00, 0x33,
+ 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
+ 0x68, 0x98, 0x4D, 0x04,
+ 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
+ 0xF8, 0x88, 0xFB, 0x23,
+ 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
+ 0x00, 0x33, 0x0A, 0x00,
+ 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
+ 0xC2, 0x88, 0xCD, 0x04,
+ 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
+ 0x06, 0xAB, 0x82, 0x01,
+ 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
+ 0x3C, 0x01, 0x00, 0x05,
+ 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
+ 0x15, 0x23, 0xA1, 0x01,
+ 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA0,
+ 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
+ 0xC2, 0x88, 0x06, 0x23,
+ 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
+ 0x57, 0x60, 0x00, 0xA0,
+ 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
+ 0x4B, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
+ 0x4F, 0x00, 0x84, 0x97,
+ 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
+ 0x48, 0x04, 0x84, 0x80,
+ 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
+ 0x81, 0x73, 0x06, 0x29,
+ 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
+ 0x04, 0x98, 0xF0, 0x80,
+ 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
+ 0x34, 0x02, 0x03, 0xA6,
+ 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
+ 0x46, 0x82, 0xFE, 0x95,
+ 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
+ 0x07, 0xA6, 0x5A, 0x02,
+ 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
+ 0x48, 0x82, 0x60, 0x96,
+ 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
+ 0x04, 0x01, 0x0C, 0xDC,
+ 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
+ 0x6F, 0x00, 0xA5, 0x01,
+ 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
+ 0x02, 0xA6, 0xAA, 0x02,
+ 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
+ 0x01, 0xA6, 0xB4, 0x02,
+ 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
+ 0x80, 0x63, 0x00, 0x43,
+ 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
+ 0x04, 0x61, 0x84, 0x01,
+ 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
+ 0x00, 0x00, 0xEA, 0x82,
+ 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
+ 0x00, 0x33, 0x1F, 0x00,
+ 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
+ 0xB6, 0x2D, 0x01, 0xA6,
+ 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
+ 0x10, 0x03, 0x03, 0xA6,
+ 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
+ 0x7C, 0x95, 0xEE, 0x82,
+ 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
+ 0x04, 0x01, 0x2D, 0xC8,
+ 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
+ 0x05, 0x05, 0x86, 0x98,
+ 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
+ 0x3C, 0x04, 0x06, 0xA6,
+ 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
+ 0x7C, 0x95, 0x32, 0x83,
+ 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
+ 0xEB, 0x04, 0x00, 0x33,
+ 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
+ 0xFF, 0xA2, 0x7A, 0x03,
+ 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
+ 0x00, 0xA2, 0x9A, 0x03,
+ 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
+ 0x01, 0xA6, 0x96, 0x03,
+ 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
+ 0xA4, 0x03, 0x00, 0xA6,
+ 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
+ 0x07, 0xA6, 0xB2, 0x03,
+ 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
+ 0xA8, 0x98, 0x80, 0x42,
+ 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+ 0xC0, 0x83, 0x00, 0x33,
+ 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
+ 0xA0, 0x01, 0x12, 0x23,
+ 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
+ 0x80, 0x67, 0x05, 0x23,
+ 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
+ 0x06, 0xA6, 0x0A, 0x04,
+ 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
+ 0xF4, 0x83, 0x20, 0x84,
+ 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+ 0x83, 0x03, 0x80, 0x63,
+ 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
+ 0x38, 0x04, 0x00, 0x33,
+ 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
+ 0x1D, 0x01, 0x06, 0xCC,
+ 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
+ 0xA2, 0x0D, 0x80, 0x63,
+ 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
+ 0x80, 0x63, 0xA3, 0x01,
+ 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
+ 0x76, 0x04, 0xE0, 0x00,
+ 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
+ 0x00, 0x33, 0x1E, 0x00,
+ 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
+ 0x08, 0x23, 0x22, 0xA3,
+ 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
+ 0xC4, 0x04, 0x42, 0x23,
+ 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
+ 0xF8, 0x88, 0x04, 0x98,
+ 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
+ 0x81, 0x62, 0xE8, 0x81,
+ 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
+ 0x00, 0x33, 0x00, 0x81,
+ 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
+ 0xF8, 0x88, 0x04, 0x23,
+ 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
+ 0xF4, 0x04, 0x00, 0x33,
+ 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
+ 0x04, 0x23, 0xA0, 0x01,
+ 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
+ 0x00, 0xA3, 0x22, 0x05,
+ 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
+ 0x46, 0x97, 0xCD, 0x04,
+ 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
+ 0x82, 0x01, 0x34, 0x85,
+ 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
+ 0x1D, 0x01, 0x04, 0xD6,
+ 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
+ 0x49, 0x00, 0x81, 0x01,
+ 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
+ 0x49, 0x04, 0x80, 0x01,
+ 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
+ 0x01, 0x23, 0xEA, 0x00,
+ 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
+ 0x07, 0xA4, 0xF8, 0x05,
+ 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
+ 0xC2, 0x88, 0x04, 0xA0,
+ 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0xA4, 0x05,
+ 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
+ 0x62, 0x97, 0x04, 0x85,
+ 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
+ 0xF4, 0x85, 0x03, 0xA0,
+ 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
+ 0xCC, 0x86, 0x07, 0xA0,
+ 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
+ 0x80, 0x67, 0x80, 0x63,
+ 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
+ 0xF8, 0x88, 0x07, 0x23,
+ 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
+ 0x00, 0x63, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
+ 0x07, 0x41, 0x83, 0x03,
+ 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
+ 0x1D, 0x01, 0x01, 0xD6,
+ 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
+ 0x07, 0xA6, 0x7C, 0x05,
+ 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
+ 0x52, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
+ 0x00, 0x63, 0x1D, 0x01,
+ 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
+ 0x07, 0x41, 0x00, 0x63,
+ 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
+ 0xDF, 0x00, 0x06, 0xA6,
+ 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
+ 0x00, 0x40, 0xC0, 0x20,
+ 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
+ 0x06, 0xA6, 0x94, 0x06,
+ 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
+ 0x40, 0x0E, 0x80, 0x63,
+ 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
+ 0x80, 0x63, 0x00, 0x43,
+ 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
+ 0x80, 0x67, 0x40, 0x0E,
+ 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
+ 0x07, 0xA6, 0xD6, 0x06,
+ 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
+ 0x0A, 0x2B, 0x07, 0xA6,
+ 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
+ 0xF4, 0x06, 0xC0, 0x0E,
+ 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
+ 0x81, 0x62, 0x04, 0x01,
+ 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
+ 0x8C, 0x06, 0x00, 0x33,
+ 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
+ 0x80, 0x63, 0x06, 0xA6,
+ 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
+ 0x00, 0x00, 0x80, 0x67,
+ 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
+ 0xBF, 0x23, 0x04, 0x61,
+ 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
+ 0x00, 0x01, 0xF2, 0x00,
+ 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
+ 0x80, 0x05, 0x81, 0x05,
+ 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
+ 0x70, 0x00, 0x81, 0x01,
+ 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
+ 0x70, 0x00, 0x80, 0x01,
+ 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
+ 0xF1, 0x00, 0x70, 0x00,
+ 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
+ 0x71, 0x04, 0x70, 0x00,
+ 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
+ 0xA3, 0x01, 0xA2, 0x01,
+ 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
+ 0xC4, 0x07, 0x00, 0x33,
+ 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
+ 0x48, 0x00, 0xB0, 0x01,
+ 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
+ 0x00, 0xA2, 0xE4, 0x07,
+ 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
+ 0x05, 0x05, 0x00, 0x63,
+ 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
+ 0x76, 0x08, 0x80, 0x02,
+ 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
+ 0x00, 0x02, 0x00, 0xA0,
+ 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
+ 0x00, 0x63, 0xF3, 0x04,
+ 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
+ 0x00, 0xA2, 0x44, 0x08,
+ 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
+ 0x24, 0x08, 0x04, 0x98,
+ 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
+ 0x5A, 0x88, 0x02, 0x01,
+ 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
+ 0x00, 0xA3, 0x64, 0x08,
+ 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
+ 0x06, 0xA6, 0x76, 0x08,
+ 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
+ 0x00, 0x63, 0x38, 0x2B,
+ 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
+ 0x05, 0x05, 0xB2, 0x09,
+ 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
+ 0x80, 0x32, 0x80, 0x36,
+ 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
+ 0x40, 0x36, 0x40, 0x3A,
+ 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
+ 0x5D, 0x00, 0xFE, 0xC3,
+ 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
+ 0xFF, 0xFD, 0x80, 0x73,
+ 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
+ 0xA1, 0x23, 0xA1, 0x01,
+ 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
+ 0x80, 0x00, 0x03, 0xC2,
+ 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
+ 0xA0, 0x01, 0xE6, 0x84,
};
-STATIC ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
-STATIC ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
+static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
-STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
-{
- INQUIRY,
- REQUEST_SENSE,
- READ_CAPACITY,
- READ_TOC,
- MODE_SELECT,
- MODE_SENSE,
- MODE_SELECT_10,
- MODE_SENSE_10,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF
+static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
+ INQUIRY,
+ REQUEST_SENSE,
+ READ_CAPACITY,
+ READ_TOC,
+ MODE_SELECT,
+ MODE_SENSE,
+ MODE_SELECT_10,
+ MODE_SENSE_10,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
};
-STATIC int
-AscExeScsiQueue(
- ASC_DVC_VAR *asc_dvc,
- ASC_SCSI_Q *scsiq
-)
+static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
{
- PortAddr iop_base;
- ulong last_int_level;
- int sta;
- int n_q_required;
- int disable_syn_offset_one_fix;
- int i;
- ASC_PADDR addr;
- ASC_EXE_CALLBACK asc_exe_callback;
- ushort sg_entry_cnt = 0;
- ushort sg_entry_cnt_minus_one = 0;
- uchar target_ix;
- uchar tid_no;
- uchar sdtr_data;
- uchar extra_bytes;
- uchar scsi_cmd;
- uchar disable_cmd;
- ASC_SG_HEAD *sg_head;
- ASC_DCNT data_cnt;
-
- iop_base = asc_dvc->iop_base;
- sg_head = scsiq->sg_head;
- asc_exe_callback = asc_dvc->exe_callback;
- if (asc_dvc->err_code != 0)
- return (ERR);
- if (scsiq == (ASC_SCSI_Q *) 0L) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
- return (ERR);
- }
- scsiq->q1.q_no = 0;
- if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
- scsiq->q1.extra_bytes = 0;
- }
- sta = 0;
- target_ix = scsiq->q2.target_ix;
- tid_no = ASC_TIX_TO_TID(target_ix);
- n_q_required = 1;
- if (scsiq->cdbptr[0] == REQUEST_SENSE) {
- if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
- asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
- sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
- AscMsgOutSDTR(asc_dvc,
- asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
- (uchar) (asc_dvc->max_sdtr_index - 1)],
- (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
- scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
- }
- }
- last_int_level = DvcEnterCritical();
- if (asc_dvc->in_critical_cnt != 0) {
- DvcLeaveCritical(last_int_level);
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
- return (ERR);
- }
- asc_dvc->in_critical_cnt++;
- if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
- if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (ERR);
- }
+ PortAddr iop_base;
+ ulong last_int_level;
+ int sta;
+ int n_q_required;
+ int disable_syn_offset_one_fix;
+ int i;
+ ASC_PADDR addr;
+ ASC_EXE_CALLBACK asc_exe_callback;
+ ushort sg_entry_cnt = 0;
+ ushort sg_entry_cnt_minus_one = 0;
+ uchar target_ix;
+ uchar tid_no;
+ uchar sdtr_data;
+ uchar extra_bytes;
+ uchar scsi_cmd;
+ uchar disable_cmd;
+ ASC_SG_HEAD *sg_head;
+ ASC_DCNT data_cnt;
+
+ iop_base = asc_dvc->iop_base;
+ sg_head = scsiq->sg_head;
+ asc_exe_callback = asc_dvc->exe_callback;
+ if (asc_dvc->err_code != 0)
+ return (ERR);
+ if (scsiq == (ASC_SCSI_Q *)0L) {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
+ return (ERR);
+ }
+ scsiq->q1.q_no = 0;
+ if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+ scsiq->q1.extra_bytes = 0;
+ }
+ sta = 0;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ n_q_required = 1;
+ if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+ if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+ asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
+ sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+ AscMsgOutSDTR(asc_dvc,
+ asc_dvc->
+ sdtr_period_tbl[(sdtr_data >> 4) &
+ (uchar)(asc_dvc->
+ max_sdtr_index -
+ 1)],
+ (uchar)(sdtr_data & (uchar)
+ ASC_SYN_MAX_OFFSET));
+ scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+ }
+ }
+ last_int_level = DvcEnterCritical();
+ if (asc_dvc->in_critical_cnt != 0) {
+ DvcLeaveCritical(last_int_level);
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+ return (ERR);
+ }
+ asc_dvc->in_critical_cnt++;
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+ asc_dvc->in_critical_cnt--;
+ DvcLeaveCritical(last_int_level);
+ return (ERR);
+ }
#if !CC_VERY_LONG_SG_LIST
- if (sg_entry_cnt > ASC_MAX_SG_LIST)
- {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return(ERR);
- }
+ if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+ asc_dvc->in_critical_cnt--;
+ DvcLeaveCritical(last_int_level);
+ return (ERR);
+ }
#endif /* !CC_VERY_LONG_SG_LIST */
- if (sg_entry_cnt == 1) {
- scsiq->q1.data_addr = (ADV_PADDR) sg_head->sg_list[0].addr;
- scsiq->q1.data_cnt = (ADV_DCNT) sg_head->sg_list[0].bytes;
- scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
- }
- sg_entry_cnt_minus_one = sg_entry_cnt - 1;
- }
- scsi_cmd = scsiq->cdbptr[0];
- disable_syn_offset_one_fix = FALSE;
- if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
- !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
- if (scsiq->q1.cntl & QC_SG_HEAD) {
- data_cnt = 0;
- for (i = 0; i < sg_entry_cnt; i++) {
- data_cnt += (ADV_DCNT) le32_to_cpu(sg_head->sg_list[i].bytes);
- }
- } else {
- data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
- }
- if (data_cnt != 0UL) {
- if (data_cnt < 512UL) {
- disable_syn_offset_one_fix = TRUE;
- } else {
- for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) {
- disable_cmd = _syn_offset_one_disable_cmd[i];
- if (disable_cmd == 0xFF) {
- break;
- }
- if (scsi_cmd == disable_cmd) {
- disable_syn_offset_one_fix = TRUE;
- break;
- }
- }
- }
- }
- }
- if (disable_syn_offset_one_fix) {
- scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
- scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
- ASC_TAG_FLAG_DISABLE_DISCONNECT);
- } else {
- scsiq->q2.tag_code &= 0x27;
- }
- if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
- if (asc_dvc->bug_fix_cntl) {
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
- if ((scsi_cmd == READ_6) ||
- (scsi_cmd == READ_10)) {
- addr =
- (ADV_PADDR) le32_to_cpu(
- sg_head->sg_list[sg_entry_cnt_minus_one].addr) +
- (ADV_DCNT) le32_to_cpu(
- sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
- extra_bytes = (uchar) ((ushort) addr & 0x0003);
- if ((extra_bytes != 0) &&
- ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
- == 0)) {
- scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
- scsiq->q1.extra_bytes = extra_bytes;
- data_cnt = le32_to_cpu(
- sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
- data_cnt -= (ASC_DCNT) extra_bytes;
- sg_head->sg_list[sg_entry_cnt_minus_one].bytes =
- cpu_to_le32(data_cnt);
- }
- }
- }
- }
- sg_head->entry_to_copy = sg_head->entry_cnt;
+ if (sg_entry_cnt == 1) {
+ scsiq->q1.data_addr =
+ (ADV_PADDR)sg_head->sg_list[0].addr;
+ scsiq->q1.data_cnt =
+ (ADV_DCNT)sg_head->sg_list[0].bytes;
+ scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+ }
+ sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+ }
+ scsi_cmd = scsiq->cdbptr[0];
+ disable_syn_offset_one_fix = FALSE;
+ if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+ !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+ if (scsiq->q1.cntl & QC_SG_HEAD) {
+ data_cnt = 0;
+ for (i = 0; i < sg_entry_cnt; i++) {
+ data_cnt +=
+ (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
+ bytes);
+ }
+ } else {
+ data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+ }
+ if (data_cnt != 0UL) {
+ if (data_cnt < 512UL) {
+ disable_syn_offset_one_fix = TRUE;
+ } else {
+ for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
+ i++) {
+ disable_cmd =
+ _syn_offset_one_disable_cmd[i];
+ if (disable_cmd == 0xFF) {
+ break;
+ }
+ if (scsi_cmd == disable_cmd) {
+ disable_syn_offset_one_fix =
+ TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (disable_syn_offset_one_fix) {
+ scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+ scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+ ASC_TAG_FLAG_DISABLE_DISCONNECT);
+ } else {
+ scsiq->q2.tag_code &= 0x27;
+ }
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ if (asc_dvc->bug_fix_cntl) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+ if ((scsi_cmd == READ_6) ||
+ (scsi_cmd == READ_10)) {
+ addr =
+ (ADV_PADDR)le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ addr) +
+ (ADV_DCNT)le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes);
+ extra_bytes =
+ (uchar)((ushort)addr & 0x0003);
+ if ((extra_bytes != 0)
+ &&
+ ((scsiq->q2.
+ tag_code &
+ ASC_TAG_FLAG_EXTRA_BYTES)
+ == 0)) {
+ scsiq->q2.tag_code |=
+ ASC_TAG_FLAG_EXTRA_BYTES;
+ scsiq->q1.extra_bytes =
+ extra_bytes;
+ data_cnt =
+ le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes);
+ data_cnt -=
+ (ASC_DCNT) extra_bytes;
+ sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes =
+ cpu_to_le32(data_cnt);
+ }
+ }
+ }
+ }
+ sg_head->entry_to_copy = sg_head->entry_cnt;
#if CC_VERY_LONG_SG_LIST
- /*
- * Set the sg_entry_cnt to the maximum possible. The rest of
- * the SG elements will be copied when the RISC completes the
- * SG elements that fit and halts.
- */
- if (sg_entry_cnt > ASC_MAX_SG_LIST)
- {
- sg_entry_cnt = ASC_MAX_SG_LIST;
- }
+ /*
+ * Set the sg_entry_cnt to the maximum possible. The rest of
+ * the SG elements will be copied when the RISC completes the
+ * SG elements that fit and halts.
+ */
+ if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+ sg_entry_cnt = ASC_MAX_SG_LIST;
+ }
#endif /* CC_VERY_LONG_SG_LIST */
- n_q_required = AscSgListToQueue(sg_entry_cnt);
- if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
- (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
- if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
- n_q_required)) == 1) {
- asc_dvc->in_critical_cnt--;
- if (asc_exe_callback != 0) {
- (*asc_exe_callback) (asc_dvc, scsiq);
- }
- DvcLeaveCritical(last_int_level);
- return (sta);
- }
- }
- } else {
- if (asc_dvc->bug_fix_cntl) {
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
- if ((scsi_cmd == READ_6) ||
- (scsi_cmd == READ_10)) {
- addr = le32_to_cpu(scsiq->q1.data_addr) +
- le32_to_cpu(scsiq->q1.data_cnt);
- extra_bytes = (uchar) ((ushort) addr & 0x0003);
- if ((extra_bytes != 0) &&
- ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
- == 0)) {
- data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
- if (((ushort) data_cnt & 0x01FF) == 0) {
- scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
- data_cnt -= (ASC_DCNT) extra_bytes;
- scsiq->q1.data_cnt = cpu_to_le32(data_cnt);
- scsiq->q1.extra_bytes = extra_bytes;
- }
- }
- }
- }
- }
- n_q_required = 1;
- if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
- ((scsiq->q1.cntl & QC_URGENT) != 0)) {
- if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
- n_q_required)) == 1) {
- asc_dvc->in_critical_cnt--;
- if (asc_exe_callback != 0) {
- (*asc_exe_callback) (asc_dvc, scsiq);
- }
- DvcLeaveCritical(last_int_level);
- return (sta);
- }
- }
- }
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (sta);
+ n_q_required = AscSgListToQueue(sg_entry_cnt);
+ if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+ (uint) n_q_required)
+ || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+ if ((sta =
+ AscSendScsiQueue(asc_dvc, scsiq,
+ n_q_required)) == 1) {
+ asc_dvc->in_critical_cnt--;
+ if (asc_exe_callback != 0) {
+ (*asc_exe_callback) (asc_dvc, scsiq);
+ }
+ DvcLeaveCritical(last_int_level);
+ return (sta);
+ }
+ }
+ } else {
+ if (asc_dvc->bug_fix_cntl) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+ if ((scsi_cmd == READ_6) ||
+ (scsi_cmd == READ_10)) {
+ addr =
+ le32_to_cpu(scsiq->q1.data_addr) +
+ le32_to_cpu(scsiq->q1.data_cnt);
+ extra_bytes =
+ (uchar)((ushort)addr & 0x0003);
+ if ((extra_bytes != 0)
+ &&
+ ((scsiq->q2.
+ tag_code &
+ ASC_TAG_FLAG_EXTRA_BYTES)
+ == 0)) {
+ data_cnt =
+ le32_to_cpu(scsiq->q1.
+ data_cnt);
+ if (((ushort)data_cnt & 0x01FF)
+ == 0) {
+ scsiq->q2.tag_code |=
+ ASC_TAG_FLAG_EXTRA_BYTES;
+ data_cnt -= (ASC_DCNT)
+ extra_bytes;
+ scsiq->q1.data_cnt =
+ cpu_to_le32
+ (data_cnt);
+ scsiq->q1.extra_bytes =
+ extra_bytes;
+ }
+ }
+ }
+ }
+ }
+ n_q_required = 1;
+ if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+ ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+ if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+ n_q_required)) == 1) {
+ asc_dvc->in_critical_cnt--;
+ if (asc_exe_callback != 0) {
+ (*asc_exe_callback) (asc_dvc, scsiq);
+ }
+ DvcLeaveCritical(last_int_level);
+ return (sta);
+ }
+ }
+ }
+ asc_dvc->in_critical_cnt--;
+ DvcLeaveCritical(last_int_level);
+ return (sta);
}
-STATIC int
-AscSendScsiQueue(
- ASC_DVC_VAR *asc_dvc,
- ASC_SCSI_Q *scsiq,
- uchar n_q_required
-)
+static int
+AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
{
- PortAddr iop_base;
- uchar free_q_head;
- uchar next_qp;
- uchar tid_no;
- uchar target_ix;
- int sta;
-
- iop_base = asc_dvc->iop_base;
- target_ix = scsiq->q2.target_ix;
- tid_no = ASC_TIX_TO_TID(target_ix);
- sta = 0;
- free_q_head = (uchar) AscGetVarFreeQHead(iop_base);
- if (n_q_required > 1) {
- if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
- free_q_head, (uchar) (n_q_required)))
- != (uchar) ASC_QLINK_END) {
- asc_dvc->last_q_shortage = 0;
- scsiq->sg_head->queue_cnt = n_q_required - 1;
- scsiq->q1.q_no = free_q_head;
- if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
- free_q_head)) == 1) {
- AscPutVarFreeQHead(iop_base, next_qp);
- asc_dvc->cur_total_qng += (uchar) (n_q_required);
- asc_dvc->cur_dvc_qng[tid_no]++;
- }
- return (sta);
- }
- } else if (n_q_required == 1) {
- if ((next_qp = AscAllocFreeQueue(iop_base,
- free_q_head)) != ASC_QLINK_END) {
- scsiq->q1.q_no = free_q_head;
- if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
- free_q_head)) == 1) {
- AscPutVarFreeQHead(iop_base, next_qp);
- asc_dvc->cur_total_qng++;
- asc_dvc->cur_dvc_qng[tid_no]++;
- }
- return (sta);
- }
- }
- return (sta);
+ PortAddr iop_base;
+ uchar free_q_head;
+ uchar next_qp;
+ uchar tid_no;
+ uchar target_ix;
+ int sta;
+
+ iop_base = asc_dvc->iop_base;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ sta = 0;
+ free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
+ if (n_q_required > 1) {
+ if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
+ free_q_head, (uchar)
+ (n_q_required)))
+ != (uchar)ASC_QLINK_END) {
+ asc_dvc->last_q_shortage = 0;
+ scsiq->sg_head->queue_cnt = n_q_required - 1;
+ scsiq->q1.q_no = free_q_head;
+ if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+ free_q_head)) == 1) {
+ AscPutVarFreeQHead(iop_base, next_qp);
+ asc_dvc->cur_total_qng += (uchar)(n_q_required);
+ asc_dvc->cur_dvc_qng[tid_no]++;
+ }
+ return (sta);
+ }
+ } else if (n_q_required == 1) {
+ if ((next_qp = AscAllocFreeQueue(iop_base,
+ free_q_head)) !=
+ ASC_QLINK_END) {
+ scsiq->q1.q_no = free_q_head;
+ if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
+ free_q_head)) == 1) {
+ AscPutVarFreeQHead(iop_base, next_qp);
+ asc_dvc->cur_total_qng++;
+ asc_dvc->cur_dvc_qng[tid_no]++;
+ }
+ return (sta);
+ }
+ }
+ return (sta);
}
-STATIC int
-AscSgListToQueue(
- int sg_list
-)
+static int AscSgListToQueue(int sg_list)
{
- int n_sg_list_qs;
+ int n_sg_list_qs;
- n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
- if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
- n_sg_list_qs++;
- return (n_sg_list_qs + 1);
+ n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
+ if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
+ n_sg_list_qs++;
+ return (n_sg_list_qs + 1);
}
-
-STATIC uint
-AscGetNumOfFreeQueue(
- ASC_DVC_VAR *asc_dvc,
- uchar target_ix,
- uchar n_qs
-)
+static uint
+AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
{
- uint cur_used_qs;
- uint cur_free_qs;
- ASC_SCSI_BIT_ID_TYPE target_id;
- uchar tid_no;
-
- target_id = ASC_TIX_TO_TARGET_ID(target_ix);
- tid_no = ASC_TIX_TO_TID(target_ix);
- if ((asc_dvc->unit_not_ready & target_id) ||
- (asc_dvc->queue_full_or_busy & target_id)) {
- return (0);
- }
- if (n_qs == 1) {
- cur_used_qs = (uint) asc_dvc->cur_total_qng +
- (uint) asc_dvc->last_q_shortage +
- (uint) ASC_MIN_FREE_Q;
- } else {
- cur_used_qs = (uint) asc_dvc->cur_total_qng +
- (uint) ASC_MIN_FREE_Q;
- }
- if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
- cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
- if (asc_dvc->cur_dvc_qng[tid_no] >=
- asc_dvc->max_dvc_qng[tid_no]) {
- return (0);
- }
- return (cur_free_qs);
- }
- if (n_qs > 1) {
- if ((n_qs > asc_dvc->last_q_shortage) && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
- asc_dvc->last_q_shortage = n_qs;
- }
- }
- return (0);
+ uint cur_used_qs;
+ uint cur_free_qs;
+ ASC_SCSI_BIT_ID_TYPE target_id;
+ uchar tid_no;
+
+ target_id = ASC_TIX_TO_TARGET_ID(target_ix);
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ if ((asc_dvc->unit_not_ready & target_id) ||
+ (asc_dvc->queue_full_or_busy & target_id)) {
+ return (0);
+ }
+ if (n_qs == 1) {
+ cur_used_qs = (uint) asc_dvc->cur_total_qng +
+ (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
+ } else {
+ cur_used_qs = (uint) asc_dvc->cur_total_qng +
+ (uint) ASC_MIN_FREE_Q;
+ }
+ if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
+ cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
+ if (asc_dvc->cur_dvc_qng[tid_no] >=
+ asc_dvc->max_dvc_qng[tid_no]) {
+ return (0);
+ }
+ return (cur_free_qs);
+ }
+ if (n_qs > 1) {
+ if ((n_qs > asc_dvc->last_q_shortage)
+ && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
+ asc_dvc->last_q_shortage = n_qs;
+ }
+ }
+ return (0);
}
-STATIC int
-AscPutReadyQueue(
- ASC_DVC_VAR *asc_dvc,
- ASC_SCSI_Q *scsiq,
- uchar q_no
-)
+static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
{
- ushort q_addr;
- uchar tid_no;
- uchar sdtr_data;
- uchar syn_period_ix;
- uchar syn_offset;
- PortAddr iop_base;
-
- iop_base = asc_dvc->iop_base;
- if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
- ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
- tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
- sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
- syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
- syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
- AscMsgOutSDTR(asc_dvc,
- asc_dvc->sdtr_period_tbl[syn_period_ix],
- syn_offset);
- scsiq->q1.cntl |= QC_MSG_OUT;
- }
- q_addr = ASC_QNO_TO_QADDR(q_no);
- if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
- scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG ;
- }
- scsiq->q1.status = QS_FREE;
- AscMemWordCopyPtrToLram(iop_base,
- q_addr + ASC_SCSIQ_CDB_BEG,
- (uchar *) scsiq->cdbptr,
- scsiq->q2.cdb_len >> 1);
-
- DvcPutScsiQ(iop_base,
- q_addr + ASC_SCSIQ_CPY_BEG,
- (uchar *) &scsiq->q1.cntl,
- ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
- AscWriteLramWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
- (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
- return (1);
+ ushort q_addr;
+ uchar tid_no;
+ uchar sdtr_data;
+ uchar syn_period_ix;
+ uchar syn_offset;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+ ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
+ tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
+ sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+ syn_period_ix =
+ (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
+ syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
+ AscMsgOutSDTR(asc_dvc,
+ asc_dvc->sdtr_period_tbl[syn_period_ix],
+ syn_offset);
+ scsiq->q1.cntl |= QC_MSG_OUT;
+ }
+ q_addr = ASC_QNO_TO_QADDR(q_no);
+ if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
+ scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+ }
+ scsiq->q1.status = QS_FREE;
+ AscMemWordCopyPtrToLram(iop_base,
+ q_addr + ASC_SCSIQ_CDB_BEG,
+ (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
+
+ DvcPutScsiQ(iop_base,
+ q_addr + ASC_SCSIQ_CPY_BEG,
+ (uchar *)&scsiq->q1.cntl,
+ ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
+ AscWriteLramWord(iop_base,
+ (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
+ (ushort)(((ushort)scsiq->q1.
+ q_no << 8) | (ushort)QS_READY));
+ return (1);
}
-STATIC int
-AscPutReadySgListQueue(
- ASC_DVC_VAR *asc_dvc,
- ASC_SCSI_Q *scsiq,
- uchar q_no
-)
+static int
+AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
{
- int sta;
- int i;
- ASC_SG_HEAD *sg_head;
- ASC_SG_LIST_Q scsi_sg_q;
- ASC_DCNT saved_data_addr;
- ASC_DCNT saved_data_cnt;
- PortAddr iop_base;
- ushort sg_list_dwords;
- ushort sg_index;
- ushort sg_entry_cnt;
- ushort q_addr;
- uchar next_qp;
-
- iop_base = asc_dvc->iop_base;
- sg_head = scsiq->sg_head;
- saved_data_addr = scsiq->q1.data_addr;
- saved_data_cnt = scsiq->q1.data_cnt;
- scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
- scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
+ int sta;
+ int i;
+ ASC_SG_HEAD *sg_head;
+ ASC_SG_LIST_Q scsi_sg_q;
+ ASC_DCNT saved_data_addr;
+ ASC_DCNT saved_data_cnt;
+ PortAddr iop_base;
+ ushort sg_list_dwords;
+ ushort sg_index;
+ ushort sg_entry_cnt;
+ ushort q_addr;
+ uchar next_qp;
+
+ iop_base = asc_dvc->iop_base;
+ sg_head = scsiq->sg_head;
+ saved_data_addr = scsiq->q1.data_addr;
+ saved_data_cnt = scsiq->q1.data_cnt;
+ scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
+ scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
#if CC_VERY_LONG_SG_LIST
- /*
- * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
- * then not all SG elements will fit in the allocated queues.
- * The rest of the SG elements will be copied when the RISC
- * completes the SG elements that fit and halts.
- */
- if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
- {
- /*
- * Set sg_entry_cnt to be the number of SG elements that
- * will fit in the allocated SG queues. It is minus 1, because
- * the first SG element is handled above. ASC_MAX_SG_LIST is
- * already inflated by 1 to account for this. For example it
- * may be 50 which is 1 + 7 queues * 7 SG elements.
- */
- sg_entry_cnt = ASC_MAX_SG_LIST - 1;
-
- /*
- * Keep track of remaining number of SG elements that will
- * need to be handled from a_isr.c.
- */
- scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
- } else
- {
+ /*
+ * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+ * then not all SG elements will fit in the allocated queues.
+ * The rest of the SG elements will be copied when the RISC
+ * completes the SG elements that fit and halts.
+ */
+ if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
+ /*
+ * Set sg_entry_cnt to be the number of SG elements that
+ * will fit in the allocated SG queues. It is minus 1, because
+ * the first SG element is handled above. ASC_MAX_SG_LIST is
+ * already inflated by 1 to account for this. For example it
+ * may be 50 which is 1 + 7 queues * 7 SG elements.
+ */
+ sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+ /*
+ * Keep track of remaining number of SG elements that will
+ * need to be handled from a_isr.c.
+ */
+ scsiq->remain_sg_entry_cnt =
+ sg_head->entry_cnt - ASC_MAX_SG_LIST;
+ } else {
#endif /* CC_VERY_LONG_SG_LIST */
- /*
- * Set sg_entry_cnt to be the number of SG elements that
- * will fit in the allocated SG queues. It is minus 1, because
- * the first SG element is handled above.
- */
- sg_entry_cnt = sg_head->entry_cnt - 1;
+ /*
+ * Set sg_entry_cnt to be the number of SG elements that
+ * will fit in the allocated SG queues. It is minus 1, because
+ * the first SG element is handled above.
+ */
+ sg_entry_cnt = sg_head->entry_cnt - 1;
#if CC_VERY_LONG_SG_LIST
- }
+ }
#endif /* CC_VERY_LONG_SG_LIST */
- if (sg_entry_cnt != 0) {
- scsiq->q1.cntl |= QC_SG_HEAD;
- q_addr = ASC_QNO_TO_QADDR(q_no);
- sg_index = 1;
- scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
- scsi_sg_q.sg_head_qp = q_no;
- scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
- for (i = 0; i < sg_head->queue_cnt; i++) {
- scsi_sg_q.seq_no = i + 1;
- if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
- sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
- sg_entry_cnt -= ASC_SG_LIST_PER_Q;
- if (i == 0) {
- scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q;
- scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q;
- } else {
- scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
- scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
- }
- } else {
+ if (sg_entry_cnt != 0) {
+ scsiq->q1.cntl |= QC_SG_HEAD;
+ q_addr = ASC_QNO_TO_QADDR(q_no);
+ sg_index = 1;
+ scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+ scsi_sg_q.sg_head_qp = q_no;
+ scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+ for (i = 0; i < sg_head->queue_cnt; i++) {
+ scsi_sg_q.seq_no = i + 1;
+ if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+ sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
+ sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+ if (i == 0) {
+ scsi_sg_q.sg_list_cnt =
+ ASC_SG_LIST_PER_Q;
+ scsi_sg_q.sg_cur_list_cnt =
+ ASC_SG_LIST_PER_Q;
+ } else {
+ scsi_sg_q.sg_list_cnt =
+ ASC_SG_LIST_PER_Q - 1;
+ scsi_sg_q.sg_cur_list_cnt =
+ ASC_SG_LIST_PER_Q - 1;
+ }
+ } else {
#if CC_VERY_LONG_SG_LIST
- /*
- * This is the last SG queue in the list of
- * allocated SG queues. If there are more
- * SG elements than will fit in the allocated
- * queues, then set the QCSG_SG_XFER_MORE flag.
- */
- if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
- {
- scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
- } else
- {
+ /*
+ * This is the last SG queue in the list of
+ * allocated SG queues. If there are more
+ * SG elements than will fit in the allocated
+ * queues, then set the QCSG_SG_XFER_MORE flag.
+ */
+ if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
+ scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+ } else {
#endif /* CC_VERY_LONG_SG_LIST */
- scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+ scsi_sg_q.cntl |= QCSG_SG_XFER_END;
#if CC_VERY_LONG_SG_LIST
- }
+ }
#endif /* CC_VERY_LONG_SG_LIST */
- sg_list_dwords = sg_entry_cnt << 1;
- if (i == 0) {
- scsi_sg_q.sg_list_cnt = sg_entry_cnt;
- scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt;
- } else {
- scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
- scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
- }
- sg_entry_cnt = 0;
- }
- next_qp = AscReadLramByte(iop_base,
- (ushort) (q_addr + ASC_SCSIQ_B_FWD));
- scsi_sg_q.q_no = next_qp;
- q_addr = ASC_QNO_TO_QADDR(next_qp);
- AscMemWordCopyPtrToLram(iop_base,
- q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
- (uchar *) &scsi_sg_q,
- sizeof(ASC_SG_LIST_Q) >> 1);
- AscMemDWordCopyPtrToLram(iop_base,
- q_addr + ASC_SGQ_LIST_BEG,
- (uchar *) &sg_head->sg_list[sg_index],
- sg_list_dwords);
- sg_index += ASC_SG_LIST_PER_Q;
- scsiq->next_sg_index = sg_index;
- }
- } else {
- scsiq->q1.cntl &= ~QC_SG_HEAD;
- }
- sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
- scsiq->q1.data_addr = saved_data_addr;
- scsiq->q1.data_cnt = saved_data_cnt;
- return (sta);
+ sg_list_dwords = sg_entry_cnt << 1;
+ if (i == 0) {
+ scsi_sg_q.sg_list_cnt = sg_entry_cnt;
+ scsi_sg_q.sg_cur_list_cnt =
+ sg_entry_cnt;
+ } else {
+ scsi_sg_q.sg_list_cnt =
+ sg_entry_cnt - 1;
+ scsi_sg_q.sg_cur_list_cnt =
+ sg_entry_cnt - 1;
+ }
+ sg_entry_cnt = 0;
+ }
+ next_qp = AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_FWD));
+ scsi_sg_q.q_no = next_qp;
+ q_addr = ASC_QNO_TO_QADDR(next_qp);
+ AscMemWordCopyPtrToLram(iop_base,
+ q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+ (uchar *)&scsi_sg_q,
+ sizeof(ASC_SG_LIST_Q) >> 1);
+ AscMemDWordCopyPtrToLram(iop_base,
+ q_addr + ASC_SGQ_LIST_BEG,
+ (uchar *)&sg_head->
+ sg_list[sg_index],
+ sg_list_dwords);
+ sg_index += ASC_SG_LIST_PER_Q;
+ scsiq->next_sg_index = sg_index;
+ }
+ } else {
+ scsiq->q1.cntl &= ~QC_SG_HEAD;
+ }
+ sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
+ scsiq->q1.data_addr = saved_data_addr;
+ scsiq->q1.data_cnt = saved_data_cnt;
+ return (sta);
}
-STATIC int
-AscSetRunChipSynRegAtID(
- PortAddr iop_base,
- uchar tid_no,
- uchar sdtr_data
-)
+static int
+AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
{
- int sta = FALSE;
+ int sta = FALSE;
- if (AscHostReqRiscHalt(iop_base)) {
- sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
- AscStartChip(iop_base);
- return (sta);
- }
- return (sta);
+ if (AscHostReqRiscHalt(iop_base)) {
+ sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+ AscStartChip(iop_base);
+ return (sta);
+ }
+ return (sta);
}
-STATIC int
-AscSetChipSynRegAtID(
- PortAddr iop_base,
- uchar id,
- uchar sdtr_data
-)
+static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
{
- ASC_SCSI_BIT_ID_TYPE org_id;
- int i;
- int sta = TRUE;
-
- AscSetBank(iop_base, 1);
- org_id = AscReadChipDvcID(iop_base);
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if (org_id == (0x01 << i))
- break;
- }
- org_id = (ASC_SCSI_BIT_ID_TYPE) i;
- AscWriteChipDvcID(iop_base, id);
- if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
- AscSetBank(iop_base, 0);
- AscSetChipSyn(iop_base, sdtr_data);
- if (AscGetChipSyn(iop_base) != sdtr_data) {
- sta = FALSE;
- }
- } else {
- sta = FALSE;
- }
- AscSetBank(iop_base, 1);
- AscWriteChipDvcID(iop_base, org_id);
- AscSetBank(iop_base, 0);
- return (sta);
+ ASC_SCSI_BIT_ID_TYPE org_id;
+ int i;
+ int sta = TRUE;
+
+ AscSetBank(iop_base, 1);
+ org_id = AscReadChipDvcID(iop_base);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if (org_id == (0x01 << i))
+ break;
+ }
+ org_id = (ASC_SCSI_BIT_ID_TYPE) i;
+ AscWriteChipDvcID(iop_base, id);
+ if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+ AscSetBank(iop_base, 0);
+ AscSetChipSyn(iop_base, sdtr_data);
+ if (AscGetChipSyn(iop_base) != sdtr_data) {
+ sta = FALSE;
+ }
+ } else {
+ sta = FALSE;
+ }
+ AscSetBank(iop_base, 1);
+ AscWriteChipDvcID(iop_base, org_id);
+ AscSetBank(iop_base, 0);
+ return (sta);
}
-STATIC ushort
-AscInitLram(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
{
- uchar i;
- ushort s_addr;
- PortAddr iop_base;
- ushort warn_code;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
- (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1)
-);
- i = ASC_MIN_ACTIVE_QNO;
- s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
- (uchar) (i + 1));
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
- (uchar) (asc_dvc->max_total_qng));
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
- (uchar) i);
- i++;
- s_addr += ASC_QBLK_SIZE;
- for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
- (uchar) (i + 1));
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
- (uchar) (i - 1));
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
- (uchar) i);
- }
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
- (uchar) ASC_QLINK_END);
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
- (uchar) (asc_dvc->max_total_qng - 1));
- AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
- (uchar) asc_dvc->max_total_qng);
- i++;
- s_addr += ASC_QBLK_SIZE;
- for (; i <= (uchar) (asc_dvc->max_total_qng + 3);
- i++, s_addr += ASC_QBLK_SIZE) {
- AscWriteLramByte(iop_base,
- (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i);
- AscWriteLramByte(iop_base,
- (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i);
- AscWriteLramByte(iop_base,
- (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i);
- }
- return (warn_code);
+ uchar i;
+ ushort s_addr;
+ PortAddr iop_base;
+ ushort warn_code;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+ (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
+ 64) >> 1)
+ );
+ i = ASC_MIN_ACTIVE_QNO;
+ s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)(i + 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(asc_dvc->max_total_qng));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)i);
+ i++;
+ s_addr += ASC_QBLK_SIZE;
+ for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)(i + 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(i - 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)i);
+ }
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)ASC_QLINK_END);
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(asc_dvc->max_total_qng - 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)asc_dvc->max_total_qng);
+ i++;
+ s_addr += ASC_QBLK_SIZE;
+ for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
+ i++, s_addr += ASC_QBLK_SIZE) {
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+ }
+ return (warn_code);
}
-STATIC ushort
-AscInitQLinkVar(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
{
- PortAddr iop_base;
- int i;
- ushort lram_addr;
-
- iop_base = asc_dvc->iop_base;
- AscPutRiscVarFreeQHead(iop_base, 1);
- AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
- AscPutVarFreeQHead(iop_base, 1);
- AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
- AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
- (uchar) ((int) asc_dvc->max_total_qng + 1));
- AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
- (uchar) ((int) asc_dvc->max_total_qng + 2));
- AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B,
- asc_dvc->max_total_qng);
- AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
- AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
- AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
- AscPutQDoneInProgress(iop_base, 0);
- lram_addr = ASC_QADR_BEG;
- for (i = 0; i < 32; i++, lram_addr += 2) {
- AscWriteLramWord(iop_base, lram_addr, 0);
- }
- return (0);
+ PortAddr iop_base;
+ int i;
+ ushort lram_addr;
+
+ iop_base = asc_dvc->iop_base;
+ AscPutRiscVarFreeQHead(iop_base, 1);
+ AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+ AscPutVarFreeQHead(iop_base, 1);
+ AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+ AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+ (uchar)((int)asc_dvc->max_total_qng + 1));
+ AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+ (uchar)((int)asc_dvc->max_total_qng + 2));
+ AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
+ asc_dvc->max_total_qng);
+ AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+ AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+ AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+ AscPutQDoneInProgress(iop_base, 0);
+ lram_addr = ASC_QADR_BEG;
+ for (i = 0; i < 32; i++, lram_addr += 2) {
+ AscWriteLramWord(iop_base, lram_addr, 0);
+ }
+ return (0);
}
-STATIC int
-AscSetLibErrorCode(
- ASC_DVC_VAR *asc_dvc,
- ushort err_code
-)
+static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
{
- if (asc_dvc->err_code == 0) {
- asc_dvc->err_code = err_code;
- AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
- err_code);
- }
- return (err_code);
+ if (asc_dvc->err_code == 0) {
+ asc_dvc->err_code = err_code;
+ AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+ err_code);
+ }
+ return (err_code);
}
-
-STATIC uchar
-AscMsgOutSDTR(
- ASC_DVC_VAR *asc_dvc,
- uchar sdtr_period,
- uchar sdtr_offset
-)
+static uchar
+AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
{
- EXT_MSG sdtr_buf;
- uchar sdtr_period_index;
- PortAddr iop_base;
-
- iop_base = asc_dvc->iop_base;
- sdtr_buf.msg_type = MS_EXTEND;
- sdtr_buf.msg_len = MS_SDTR_LEN;
- sdtr_buf.msg_req = MS_SDTR_CODE;
- sdtr_buf.xfer_period = sdtr_period;
- sdtr_offset &= ASC_SYN_MAX_OFFSET;
- sdtr_buf.req_ack_offset = sdtr_offset;
- if ((sdtr_period_index =
- AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
- asc_dvc->max_sdtr_index) {
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *) &sdtr_buf,
- sizeof (EXT_MSG) >> 1);
- return ((sdtr_period_index << 4) | sdtr_offset);
- } else {
-
- sdtr_buf.req_ack_offset = 0;
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *) &sdtr_buf,
- sizeof (EXT_MSG) >> 1);
- return (0);
- }
+ EXT_MSG sdtr_buf;
+ uchar sdtr_period_index;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ sdtr_buf.msg_type = MS_EXTEND;
+ sdtr_buf.msg_len = MS_SDTR_LEN;
+ sdtr_buf.msg_req = MS_SDTR_CODE;
+ sdtr_buf.xfer_period = sdtr_period;
+ sdtr_offset &= ASC_SYN_MAX_OFFSET;
+ sdtr_buf.req_ack_offset = sdtr_offset;
+ if ((sdtr_period_index =
+ AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
+ asc_dvc->max_sdtr_index) {
+ AscMemWordCopyPtrToLram(iop_base,
+ ASCV_MSGOUT_BEG,
+ (uchar *)&sdtr_buf,
+ sizeof(EXT_MSG) >> 1);
+ return ((sdtr_period_index << 4) | sdtr_offset);
+ } else {
+
+ sdtr_buf.req_ack_offset = 0;
+ AscMemWordCopyPtrToLram(iop_base,
+ ASCV_MSGOUT_BEG,
+ (uchar *)&sdtr_buf,
+ sizeof(EXT_MSG) >> 1);
+ return (0);
+ }
}
-STATIC uchar
-AscCalSDTRData(
- ASC_DVC_VAR *asc_dvc,
- uchar sdtr_period,
- uchar syn_offset
-)
+static uchar
+AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
{
- uchar byte;
- uchar sdtr_period_ix;
-
- sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
- if (
- (sdtr_period_ix > asc_dvc->max_sdtr_index)
-) {
- return (0xFF);
- }
- byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
- return (byte);
+ uchar byte;
+ uchar sdtr_period_ix;
+
+ sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+ if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
+ ) {
+ return (0xFF);
+ }
+ byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+ return (byte);
}
-STATIC void
-AscSetChipSDTR(
- PortAddr iop_base,
- uchar sdtr_data,
- uchar tid_no
-)
+static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
{
- AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
- AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
- return;
+ AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+ AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
+ return;
}
-STATIC uchar
-AscGetSynPeriodIndex(
- ASC_DVC_VAR *asc_dvc,
- uchar syn_time
-)
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
{
- uchar *period_table;
- int max_index;
- int min_index;
- int i;
-
- period_table = asc_dvc->sdtr_period_tbl;
- max_index = (int) asc_dvc->max_sdtr_index;
- min_index = (int)asc_dvc->host_init_sdtr_index;
- if ((syn_time <= period_table[max_index])) {
- for (i = min_index; i < (max_index - 1); i++) {
- if (syn_time <= period_table[i]) {
- return ((uchar) i);
- }
- }
- return ((uchar) max_index);
- } else {
- return ((uchar) (max_index + 1));
- }
+ uchar *period_table;
+ int max_index;
+ int min_index;
+ int i;
+
+ period_table = asc_dvc->sdtr_period_tbl;
+ max_index = (int)asc_dvc->max_sdtr_index;
+ min_index = (int)asc_dvc->host_init_sdtr_index;
+ if ((syn_time <= period_table[max_index])) {
+ for (i = min_index; i < (max_index - 1); i++) {
+ if (syn_time <= period_table[i]) {
+ return ((uchar)i);
+ }
+ }
+ return ((uchar)max_index);
+ } else {
+ return ((uchar)(max_index + 1));
+ }
}
-STATIC uchar
-AscAllocFreeQueue(
- PortAddr iop_base,
- uchar free_q_head
-)
+static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
{
- ushort q_addr;
- uchar next_qp;
- uchar q_status;
-
- q_addr = ASC_QNO_TO_QADDR(free_q_head);
- q_status = (uchar) AscReadLramByte(iop_base,
- (ushort) (q_addr + ASC_SCSIQ_B_STATUS));
- next_qp = AscReadLramByte(iop_base,
- (ushort) (q_addr + ASC_SCSIQ_B_FWD));
- if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
- return (next_qp);
- }
- return (ASC_QLINK_END);
+ ushort q_addr;
+ uchar next_qp;
+ uchar q_status;
+
+ q_addr = ASC_QNO_TO_QADDR(free_q_head);
+ q_status = (uchar)AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_STATUS));
+ next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
+ if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
+ return (next_qp);
+ }
+ return (ASC_QLINK_END);
}
-STATIC uchar
-AscAllocMultipleFreeQueue(
- PortAddr iop_base,
- uchar free_q_head,
- uchar n_free_q
-)
+static uchar
+AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
{
- uchar i;
+ uchar i;
- for (i = 0; i < n_free_q; i++) {
- if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
- == ASC_QLINK_END) {
- return (ASC_QLINK_END);
- }
- }
- return (free_q_head);
+ for (i = 0; i < n_free_q; i++) {
+ if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
+ == ASC_QLINK_END) {
+ return (ASC_QLINK_END);
+ }
+ }
+ return (free_q_head);
}
-STATIC int
-AscHostReqRiscHalt(
- PortAddr iop_base
-)
+static int AscHostReqRiscHalt(PortAddr iop_base)
{
- int count = 0;
- int sta = 0;
- uchar saved_stop_code;
-
- if (AscIsChipHalted(iop_base))
- return (1);
- saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
- ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP
-);
- do {
- if (AscIsChipHalted(iop_base)) {
- sta = 1;
- break;
- }
- DvcSleepMilliSecond(100);
- } while (count++ < 20);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
- return (sta);
+ int count = 0;
+ int sta = 0;
+ uchar saved_stop_code;
+
+ if (AscIsChipHalted(iop_base))
+ return (1);
+ saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+ ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
+ do {
+ if (AscIsChipHalted(iop_base)) {
+ sta = 1;
+ break;
+ }
+ DvcSleepMilliSecond(100);
+ } while (count++ < 20);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+ return (sta);
}
-STATIC int
-AscStopQueueExe(
- PortAddr iop_base
-)
+static int AscStopQueueExe(PortAddr iop_base)
{
- int count = 0;
-
- if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
- ASC_STOP_REQ_RISC_STOP);
- do {
- if (
- AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
- ASC_STOP_ACK_RISC_STOP) {
- return (1);
- }
- DvcSleepMilliSecond(100);
- } while (count++ < 20);
- }
- return (0);
+ int count = 0;
+
+ if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+ ASC_STOP_REQ_RISC_STOP);
+ do {
+ if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+ ASC_STOP_ACK_RISC_STOP) {
+ return (1);
+ }
+ DvcSleepMilliSecond(100);
+ } while (count++ < 20);
+ }
+ return (0);
}
-STATIC void
-DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
+static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
{
- udelay(micro_sec);
+ udelay(micro_sec);
}
-STATIC void
-DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
+static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
{
- udelay((nano_sec + 999)/1000);
+ udelay((nano_sec + 999) / 1000);
}
#ifdef CONFIG_ISA
-STATIC ASC_DCNT __init
-AscGetEisaProductID(
- PortAddr iop_base)
+static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
{
- PortAddr eisa_iop;
- ushort product_id_high, product_id_low;
- ASC_DCNT product_id;
-
- eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
- product_id_low = inpw(eisa_iop);
- product_id_high = inpw(eisa_iop + 2);
- product_id = ((ASC_DCNT) product_id_high << 16) |
- (ASC_DCNT) product_id_low;
- return (product_id);
+ PortAddr eisa_iop;
+ ushort product_id_high, product_id_low;
+ ASC_DCNT product_id;
+
+ eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
+ product_id_low = inpw(eisa_iop);
+ product_id_high = inpw(eisa_iop + 2);
+ product_id = ((ASC_DCNT) product_id_high << 16) |
+ (ASC_DCNT) product_id_low;
+ return (product_id);
}
-STATIC PortAddr __init
-AscSearchIOPortAddrEISA(
- PortAddr iop_base)
+static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
{
- ASC_DCNT eisa_product_id;
-
- if (iop_base == 0) {
- iop_base = ASC_EISA_MIN_IOP_ADDR;
- } else {
- if (iop_base == ASC_EISA_MAX_IOP_ADDR)
- return (0);
- if ((iop_base & 0x0050) == 0x0050) {
- iop_base += ASC_EISA_BIG_IOP_GAP;
- } else {
- iop_base += ASC_EISA_SMALL_IOP_GAP;
- }
- }
- while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
- eisa_product_id = AscGetEisaProductID(iop_base);
- if ((eisa_product_id == ASC_EISA_ID_740) ||
- (eisa_product_id == ASC_EISA_ID_750)) {
- if (AscFindSignature(iop_base)) {
- inpw(iop_base + 4);
- return (iop_base);
- }
- }
- if (iop_base == ASC_EISA_MAX_IOP_ADDR)
- return (0);
- if ((iop_base & 0x0050) == 0x0050) {
- iop_base += ASC_EISA_BIG_IOP_GAP;
- } else {
- iop_base += ASC_EISA_SMALL_IOP_GAP;
- }
- }
- return (0);
+ ASC_DCNT eisa_product_id;
+
+ if (iop_base == 0) {
+ iop_base = ASC_EISA_MIN_IOP_ADDR;
+ } else {
+ if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+ return (0);
+ if ((iop_base & 0x0050) == 0x0050) {
+ iop_base += ASC_EISA_BIG_IOP_GAP;
+ } else {
+ iop_base += ASC_EISA_SMALL_IOP_GAP;
+ }
+ }
+ while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
+ eisa_product_id = AscGetEisaProductID(iop_base);
+ if ((eisa_product_id == ASC_EISA_ID_740) ||
+ (eisa_product_id == ASC_EISA_ID_750)) {
+ if (AscFindSignature(iop_base)) {
+ inpw(iop_base + 4);
+ return (iop_base);
+ }
+ }
+ if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+ return (0);
+ if ((iop_base & 0x0050) == 0x0050) {
+ iop_base += ASC_EISA_BIG_IOP_GAP;
+ } else {
+ iop_base += ASC_EISA_SMALL_IOP_GAP;
+ }
+ }
+ return (0);
}
#endif /* CONFIG_ISA */
-STATIC int
-AscStartChip(
- PortAddr iop_base
-)
+static int AscStartChip(PortAddr iop_base)
{
- AscSetChipControl(iop_base, 0);
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
- return (0);
- }
- return (1);
+ AscSetChipControl(iop_base, 0);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+ return (0);
+ }
+ return (1);
}
-STATIC int
-AscStopChip(
- PortAddr iop_base
-)
+static int AscStopChip(PortAddr iop_base)
{
- uchar cc_val;
-
- cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
- AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
- AscSetChipIH(iop_base, INS_HALT);
- AscSetChipIH(iop_base, INS_RFLAG_WTM);
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
- return (0);
- }
- return (1);
+ uchar cc_val;
+
+ cc_val =
+ AscGetChipControl(iop_base) &
+ (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+ AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
+ AscSetChipIH(iop_base, INS_HALT);
+ AscSetChipIH(iop_base, INS_RFLAG_WTM);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+ return (0);
+ }
+ return (1);
}
-STATIC int
-AscIsChipHalted(
- PortAddr iop_base
-)
+static int AscIsChipHalted(PortAddr iop_base)
{
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
- if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
- return (1);
- }
- }
- return (0);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+ if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+ return (1);
+ }
+ }
+ return (0);
}
-STATIC void
-AscSetChipIH(
- PortAddr iop_base,
- ushort ins_code
-)
+static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
{
- AscSetBank(iop_base, 1);
- AscWriteChipIH(iop_base, ins_code);
- AscSetBank(iop_base, 0);
- return;
+ AscSetBank(iop_base, 1);
+ AscWriteChipIH(iop_base, ins_code);
+ AscSetBank(iop_base, 0);
+ return;
}
-STATIC void
-AscAckInterrupt(
- PortAddr iop_base
-)
+static void AscAckInterrupt(PortAddr iop_base)
{
- uchar host_flag;
- uchar risc_flag;
- ushort loop;
-
- loop = 0;
- do {
- risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
- if (loop++ > 0x7FFF) {
- break;
- }
- } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
- host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
- (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT));
- AscSetChipStatus(iop_base, CIW_INT_ACK);
- loop = 0;
- while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
- AscSetChipStatus(iop_base, CIW_INT_ACK);
- if (loop++ > 3) {
- break;
- }
- }
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
- return;
+ uchar host_flag;
+ uchar risc_flag;
+ ushort loop;
+
+ loop = 0;
+ do {
+ risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+ if (loop++ > 0x7FFF) {
+ break;
+ }
+ } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+ host_flag =
+ AscReadLramByte(iop_base,
+ ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+ (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
+ AscSetChipStatus(iop_base, CIW_INT_ACK);
+ loop = 0;
+ while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+ AscSetChipStatus(iop_base, CIW_INT_ACK);
+ if (loop++ > 3) {
+ break;
+ }
+ }
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+ return;
}
-STATIC void
-AscDisableInterrupt(
- PortAddr iop_base
-)
+static void AscDisableInterrupt(PortAddr iop_base)
{
- ushort cfg;
+ ushort cfg;
- cfg = AscGetChipCfgLsw(iop_base);
- AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
- return;
+ cfg = AscGetChipCfgLsw(iop_base);
+ AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+ return;
}
-STATIC void
-AscEnableInterrupt(
- PortAddr iop_base
-)
+static void AscEnableInterrupt(PortAddr iop_base)
{
- ushort cfg;
+ ushort cfg;
- cfg = AscGetChipCfgLsw(iop_base);
- AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
- return;
+ cfg = AscGetChipCfgLsw(iop_base);
+ AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+ return;
}
-
-
-STATIC void
-AscSetBank(
- PortAddr iop_base,
- uchar bank
-)
+static void AscSetBank(PortAddr iop_base, uchar bank)
{
- uchar val;
-
- val = AscGetChipControl(iop_base) &
- (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
- if (bank == 1) {
- val |= CC_BANK_ONE;
- } else if (bank == 2) {
- val |= CC_DIAG | CC_BANK_ONE;
- } else {
- val &= ~CC_BANK_ONE;
- }
- AscSetChipControl(iop_base, val);
- return;
+ uchar val;
+
+ val = AscGetChipControl(iop_base) &
+ (~
+ (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
+ CC_CHIP_RESET));
+ if (bank == 1) {
+ val |= CC_BANK_ONE;
+ } else if (bank == 2) {
+ val |= CC_DIAG | CC_BANK_ONE;
+ } else {
+ val &= ~CC_BANK_ONE;
+ }
+ AscSetChipControl(iop_base, val);
+ return;
}
-STATIC int
-AscResetChipAndScsiBus(
- ASC_DVC_VAR *asc_dvc
-)
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
{
- PortAddr iop_base;
- int i = 10;
+ PortAddr iop_base;
+ int i = 10;
- iop_base = asc_dvc->iop_base;
- while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0))
- {
- DvcSleepMilliSecond(100);
- }
- AscStopChip(iop_base);
- AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
- DvcDelayNanoSecond(asc_dvc, 60000);
- AscSetChipIH(iop_base, INS_RFLAG_WTM);
- AscSetChipIH(iop_base, INS_HALT);
- AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
- AscSetChipControl(iop_base, CC_HALT);
- DvcSleepMilliSecond(200);
- AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
- AscSetChipStatus(iop_base, 0);
- return (AscIsChipHalted(iop_base));
+ iop_base = asc_dvc->iop_base;
+ while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
+ && (i-- > 0)) {
+ DvcSleepMilliSecond(100);
+ }
+ AscStopChip(iop_base);
+ AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+ DvcDelayNanoSecond(asc_dvc, 60000);
+ AscSetChipIH(iop_base, INS_RFLAG_WTM);
+ AscSetChipIH(iop_base, INS_HALT);
+ AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+ AscSetChipControl(iop_base, CC_HALT);
+ DvcSleepMilliSecond(200);
+ AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+ AscSetChipStatus(iop_base, 0);
+ return (AscIsChipHalted(iop_base));
}
-STATIC ASC_DCNT __init
-AscGetMaxDmaCount(
- ushort bus_type)
+static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
{
- if (bus_type & ASC_IS_ISA)
- return (ASC_MAX_ISA_DMA_COUNT);
- else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
- return (ASC_MAX_VL_DMA_COUNT);
- return (ASC_MAX_PCI_DMA_COUNT);
+ if (bus_type & ASC_IS_ISA)
+ return (ASC_MAX_ISA_DMA_COUNT);
+ else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
+ return (ASC_MAX_VL_DMA_COUNT);
+ return (ASC_MAX_PCI_DMA_COUNT);
}
#ifdef CONFIG_ISA
-STATIC ushort __init
-AscGetIsaDmaChannel(
- PortAddr iop_base)
+static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
{
- ushort channel;
-
- channel = AscGetChipCfgLsw(iop_base) & 0x0003;
- if (channel == 0x03)
- return (0);
- else if (channel == 0x00)
- return (7);
- return (channel + 4);
+ ushort channel;
+
+ channel = AscGetChipCfgLsw(iop_base) & 0x0003;
+ if (channel == 0x03)
+ return (0);
+ else if (channel == 0x00)
+ return (7);
+ return (channel + 4);
}
-STATIC ushort __init
-AscSetIsaDmaChannel(
- PortAddr iop_base,
- ushort dma_channel)
+static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
{
- ushort cfg_lsw;
- uchar value;
-
- if ((dma_channel >= 5) && (dma_channel <= 7)) {
- if (dma_channel == 7)
- value = 0x00;
- else
- value = dma_channel - 4;
- cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
- cfg_lsw |= value;
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetIsaDmaChannel(iop_base));
- }
- return (0);
+ ushort cfg_lsw;
+ uchar value;
+
+ if ((dma_channel >= 5) && (dma_channel <= 7)) {
+ if (dma_channel == 7)
+ value = 0x00;
+ else
+ value = dma_channel - 4;
+ cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
+ cfg_lsw |= value;
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ return (AscGetIsaDmaChannel(iop_base));
+ }
+ return (0);
}
-STATIC uchar __init
-AscSetIsaDmaSpeed(
- PortAddr iop_base,
- uchar speed_value)
+static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
{
- speed_value &= 0x07;
- AscSetBank(iop_base, 1);
- AscWriteChipDmaSpeed(iop_base, speed_value);
- AscSetBank(iop_base, 0);
- return (AscGetIsaDmaSpeed(iop_base));
+ speed_value &= 0x07;
+ AscSetBank(iop_base, 1);
+ AscWriteChipDmaSpeed(iop_base, speed_value);
+ AscSetBank(iop_base, 0);
+ return (AscGetIsaDmaSpeed(iop_base));
}
-STATIC uchar __init
-AscGetIsaDmaSpeed(
- PortAddr iop_base
-)
+static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
{
- uchar speed_value;
+ uchar speed_value;
- AscSetBank(iop_base, 1);
- speed_value = AscReadChipDmaSpeed(iop_base);
- speed_value &= 0x07;
- AscSetBank(iop_base, 0);
- return (speed_value);
+ AscSetBank(iop_base, 1);
+ speed_value = AscReadChipDmaSpeed(iop_base);
+ speed_value &= 0x07;
+ AscSetBank(iop_base, 0);
+ return (speed_value);
}
#endif /* CONFIG_ISA */
-STATIC ushort __init
-AscReadPCIConfigWord(
- ASC_DVC_VAR *asc_dvc,
- ushort pci_config_offset)
+static ushort __init
+AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
{
- uchar lsb, msb;
+ uchar lsb, msb;
- lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
- msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
- return ((ushort) ((msb << 8) | lsb));
+ lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
+ msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
+ return ((ushort)((msb << 8) | lsb));
}
-STATIC ushort __init
-AscInitGetConfig(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
{
- ushort warn_code;
- PortAddr iop_base;
- ushort PCIDeviceID;
- ushort PCIVendorID;
- uchar PCIRevisionID;
- uchar prevCmdRegBits;
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
- asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
- if (asc_dvc->err_code != 0) {
- return (UW_ERR);
- }
- if (asc_dvc->bus_type == ASC_IS_PCI) {
- PCIVendorID = AscReadPCIConfigWord(asc_dvc,
- AscPCIConfigVendorIDRegister);
-
- PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
- AscPCIConfigDeviceIDRegister);
-
- PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigRevisionIDRegister);
-
- if (PCIVendorID != PCI_VENDOR_ID_ASP) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister);
-
- if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
- AscPCICmdRegBits_IOMemBusMaster) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister,
- (prevCmdRegBits |
- AscPCICmdRegBits_IOMemBusMaster));
-
- if ((DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister)
- & AscPCICmdRegBits_IOMemBusMaster)
- != AscPCICmdRegBits_IOMemBusMaster) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
- if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
- (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer, 0x00);
- if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
- != 0x00) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
- if (DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer) < 0x20) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer, 0x20);
-
- if (DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer) < 0x20) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
- }
- }
+ ushort warn_code;
+ PortAddr iop_base;
+ ushort PCIDeviceID;
+ ushort PCIVendorID;
+ uchar PCIRevisionID;
+ uchar prevCmdRegBits;
+
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
+ asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+ if (asc_dvc->err_code != 0) {
+ return (UW_ERR);
+ }
+ if (asc_dvc->bus_type == ASC_IS_PCI) {
+ PCIVendorID = AscReadPCIConfigWord(asc_dvc,
+ AscPCIConfigVendorIDRegister);
+
+ PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
+ AscPCIConfigDeviceIDRegister);
+
+ PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigRevisionIDRegister);
+
+ if (PCIVendorID != PCI_VENDOR_ID_ASP) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister);
+
+ if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
+ AscPCICmdRegBits_IOMemBusMaster) {
+ DvcWritePCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister,
+ (prevCmdRegBits |
+ AscPCICmdRegBits_IOMemBusMaster));
+
+ if ((DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister)
+ & AscPCICmdRegBits_IOMemBusMaster)
+ != AscPCICmdRegBits_IOMemBusMaster) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
+ if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
+ (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
+ DvcWritePCIConfigByte(asc_dvc,
+ AscPCIConfigLatencyTimer, 0x00);
+ if (DvcReadPCIConfigByte
+ (asc_dvc, AscPCIConfigLatencyTimer)
+ != 0x00) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
+ if (DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigLatencyTimer) <
+ 0x20) {
+ DvcWritePCIConfigByte(asc_dvc,
+ AscPCIConfigLatencyTimer,
+ 0x20);
+
+ if (DvcReadPCIConfigByte(asc_dvc,
+ AscPCIConfigLatencyTimer)
+ < 0x20) {
+ warn_code |=
+ ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
+ }
+ }
- if (AscFindSignature(iop_base)) {
- warn_code |= AscInitAscDvcVar(asc_dvc);
- warn_code |= AscInitFromEEP(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
- if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
- asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
- }
- } else {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- }
- return(warn_code);
+ if (AscFindSignature(iop_base)) {
+ warn_code |= AscInitAscDvcVar(asc_dvc);
+ warn_code |= AscInitFromEEP(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+ if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
+ asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
+ }
+ } else {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ }
+ return (warn_code);
}
-STATIC ushort __init
-AscInitSetConfig(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
{
- ushort warn_code = 0;
-
- asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- if (AscFindSignature(asc_dvc->iop_base)) {
- warn_code |= AscInitFromAscDvcVar(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
- } else {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- }
- return (warn_code);
+ ushort warn_code = 0;
+
+ asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+ if (asc_dvc->err_code != 0)
+ return (UW_ERR);
+ if (AscFindSignature(asc_dvc->iop_base)) {
+ warn_code |= AscInitFromAscDvcVar(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
+ } else {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ }
+ return (warn_code);
}
-STATIC ushort __init
-AscInitFromAscDvcVar(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
{
- PortAddr iop_base;
- ushort cfg_msw;
- ushort warn_code;
- ushort pci_device_id = 0;
+ PortAddr iop_base;
+ ushort cfg_msw;
+ ushort warn_code;
+ ushort pci_device_id = 0;
- iop_base = asc_dvc->iop_base;
+ iop_base = asc_dvc->iop_base;
#ifdef CONFIG_PCI
- if (asc_dvc->cfg->dev)
- pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
+ if (asc_dvc->cfg->dev)
+ pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
#endif
- warn_code = 0;
- cfg_msw = AscGetChipCfgMsw(iop_base);
- if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
- cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
- warn_code |= ASC_WARN_CFG_MSW_RECOVER;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- }
- if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
- asc_dvc->cfg->cmd_qng_enabled) {
- asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
- warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
- }
- if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
- warn_code |= ASC_WARN_AUTO_CONFIG;
- }
- if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
- if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
- != asc_dvc->irq_no) {
- asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
- }
- }
- if (asc_dvc->bus_type & ASC_IS_PCI) {
- cfg_msw &= 0xFFC0;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
- } else {
- if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
- (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
- }
- }
- } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
- if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
- == ASC_CHIP_VER_ASYN_BUG) {
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
- }
- }
- if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
- asc_dvc->cfg->chip_scsi_id) {
- asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
- }
+ warn_code = 0;
+ cfg_msw = AscGetChipCfgMsw(iop_base);
+ if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+ cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+ warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ }
+ if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+ asc_dvc->cfg->cmd_qng_enabled) {
+ asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+ warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+ }
+ if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+ warn_code |= ASC_WARN_AUTO_CONFIG;
+ }
+ if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
+ if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
+ != asc_dvc->irq_no) {
+ asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
+ }
+ }
+ if (asc_dvc->bus_type & ASC_IS_PCI) {
+ cfg_msw &= 0xFFC0;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+ } else {
+ if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
+ (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+ asc_dvc->bug_fix_cntl |=
+ ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+ }
+ } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+ == ASC_CHIP_VER_ASYN_BUG) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+ }
+ if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+ asc_dvc->cfg->chip_scsi_id) {
+ asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+ }
#ifdef CONFIG_ISA
- if (asc_dvc->bus_type & ASC_IS_ISA) {
- AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
- AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
- }
+ if (asc_dvc->bus_type & ASC_IS_ISA) {
+ AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+ AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+ }
#endif /* CONFIG_ISA */
- return (warn_code);
+ return (warn_code);
}
-STATIC ushort
-AscInitAsc1000Driver(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
{
- ushort warn_code;
- PortAddr iop_base;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
- !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
- AscResetChipAndScsiBus(asc_dvc);
- DvcSleepMilliSecond((ASC_DCNT)
- ((ushort) asc_dvc->scsi_reset_wait * 1000));
- }
- asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- if (!AscFindSignature(asc_dvc->iop_base)) {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- return (warn_code);
- }
- AscDisableInterrupt(iop_base);
- warn_code |= AscInitLram(asc_dvc);
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
- (ulong) _asc_mcode_chksum);
- if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
- _asc_mcode_size) != _asc_mcode_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return (warn_code);
- }
- warn_code |= AscInitMicroCodeVar(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
- AscEnableInterrupt(iop_base);
- return (warn_code);
+ ushort warn_code;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+ !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+ AscResetChipAndScsiBus(asc_dvc);
+ DvcSleepMilliSecond((ASC_DCNT)
+ ((ushort)asc_dvc->scsi_reset_wait * 1000));
+ }
+ asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+ if (asc_dvc->err_code != 0)
+ return (UW_ERR);
+ if (!AscFindSignature(asc_dvc->iop_base)) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return (warn_code);
+ }
+ AscDisableInterrupt(iop_base);
+ warn_code |= AscInitLram(asc_dvc);
+ if (asc_dvc->err_code != 0)
+ return (UW_ERR);
+ ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
+ (ulong)_asc_mcode_chksum);
+ if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
+ _asc_mcode_size) != _asc_mcode_chksum) {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return (warn_code);
+ }
+ warn_code |= AscInitMicroCodeVar(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+ AscEnableInterrupt(iop_base);
+ return (warn_code);
}
-STATIC ushort __init
-AscInitAscDvcVar(
- ASC_DVC_VAR *asc_dvc)
+static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
{
- int i;
- PortAddr iop_base;
- ushort warn_code;
- uchar chip_version;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- asc_dvc->err_code = 0;
- if ((asc_dvc->bus_type &
- (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
- asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
- }
- AscSetChipControl(iop_base, CC_HALT);
- AscSetChipStatus(iop_base, 0);
- asc_dvc->bug_fix_cntl = 0;
- asc_dvc->pci_fix_asyn_xfer = 0;
- asc_dvc->pci_fix_asyn_xfer_always = 0;
- /* asc_dvc->init_state initalized in AscInitGetConfig(). */
- asc_dvc->sdtr_done = 0;
- asc_dvc->cur_total_qng = 0;
- asc_dvc->is_in_int = 0;
- asc_dvc->in_critical_cnt = 0;
- asc_dvc->last_q_shortage = 0;
- asc_dvc->use_tagged_qng = 0;
- asc_dvc->no_scam = 0;
- asc_dvc->unit_not_ready = 0;
- asc_dvc->queue_full_or_busy = 0;
- asc_dvc->redo_scam = 0;
- asc_dvc->res2 = 0;
- asc_dvc->host_init_sdtr_index = 0;
- asc_dvc->cfg->can_tagged_qng = 0;
- asc_dvc->cfg->cmd_qng_enabled = 0;
- asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
- asc_dvc->init_sdtr = 0;
- asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
- asc_dvc->scsi_reset_wait = 3;
- asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
- asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
- asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
- asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
- asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
- asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
- asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
- ASC_LIB_VERSION_MINOR;
- chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
- asc_dvc->cfg->chip_version = chip_version;
- asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
- asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
- asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
- asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
- asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
- asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
- asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
- asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
- asc_dvc->max_sdtr_index = 7;
- if ((asc_dvc->bus_type & ASC_IS_PCI) &&
- (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
- asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
- asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
- asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
- asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
- asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
- asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
- asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
- asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
- asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
- asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
- asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
- asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
- asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
- asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
- asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
- asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
- asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
- asc_dvc->max_sdtr_index = 15;
- if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150)
- {
- AscSetExtraControl(iop_base,
- (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
- } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
- AscSetExtraControl(iop_base,
- (SEC_ACTIVE_NEGATE | SEC_ENABLE_FILTER));
- }
- }
- if (asc_dvc->bus_type == ASC_IS_PCI) {
- AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
- }
+ int i;
+ PortAddr iop_base;
+ ushort warn_code;
+ uchar chip_version;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ asc_dvc->err_code = 0;
+ if ((asc_dvc->bus_type &
+ (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
+ asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
+ }
+ AscSetChipControl(iop_base, CC_HALT);
+ AscSetChipStatus(iop_base, 0);
+ asc_dvc->bug_fix_cntl = 0;
+ asc_dvc->pci_fix_asyn_xfer = 0;
+ asc_dvc->pci_fix_asyn_xfer_always = 0;
+ /* asc_dvc->init_state initalized in AscInitGetConfig(). */
+ asc_dvc->sdtr_done = 0;
+ asc_dvc->cur_total_qng = 0;
+ asc_dvc->is_in_int = 0;
+ asc_dvc->in_critical_cnt = 0;
+ asc_dvc->last_q_shortage = 0;
+ asc_dvc->use_tagged_qng = 0;
+ asc_dvc->no_scam = 0;
+ asc_dvc->unit_not_ready = 0;
+ asc_dvc->queue_full_or_busy = 0;
+ asc_dvc->redo_scam = 0;
+ asc_dvc->res2 = 0;
+ asc_dvc->host_init_sdtr_index = 0;
+ asc_dvc->cfg->can_tagged_qng = 0;
+ asc_dvc->cfg->cmd_qng_enabled = 0;
+ asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
+ asc_dvc->init_sdtr = 0;
+ asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
+ asc_dvc->scsi_reset_wait = 3;
+ asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
+ asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
+ asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
+ asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
+ asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
+ asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
+ asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
+ ASC_LIB_VERSION_MINOR;
+ chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
+ asc_dvc->cfg->chip_version = chip_version;
+ asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
+ asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
+ asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
+ asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
+ asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
+ asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
+ asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
+ asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
+ asc_dvc->max_sdtr_index = 7;
+ if ((asc_dvc->bus_type & ASC_IS_PCI) &&
+ (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
+ asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
+ asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
+ asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
+ asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
+ asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
+ asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
+ asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
+ asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
+ asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
+ asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
+ asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
+ asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
+ asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
+ asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
+ asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
+ asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
+ asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
+ asc_dvc->max_sdtr_index = 15;
+ if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
+ AscSetExtraControl(iop_base,
+ (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+ } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
+ AscSetExtraControl(iop_base,
+ (SEC_ACTIVE_NEGATE |
+ SEC_ENABLE_FILTER));
+ }
+ }
+ if (asc_dvc->bus_type == ASC_IS_PCI) {
+ AscSetExtraControl(iop_base,
+ (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+ }
- asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
- if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
- AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
- asc_dvc->bus_type = ASC_IS_ISAPNP;
- }
+ asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
+ if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
+ AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+ asc_dvc->bus_type = ASC_IS_ISAPNP;
+ }
#ifdef CONFIG_ISA
- if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
- asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
- }
+ if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+ asc_dvc->cfg->isa_dma_channel =
+ (uchar)AscGetIsaDmaChannel(iop_base);
+ }
#endif /* CONFIG_ISA */
- for (i = 0; i <= ASC_MAX_TID; i++) {
- asc_dvc->cur_dvc_qng[i] = 0;
- asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
- asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *) 0L;
- asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *) 0L;
- asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
- }
- return (warn_code);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ asc_dvc->cur_dvc_qng[i] = 0;
+ asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
+ asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
+ asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
+ asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
+ }
+ return (warn_code);
}
-STATIC ushort __init
-AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
{
- ASCEEP_CONFIG eep_config_buf;
- ASCEEP_CONFIG *eep_config;
- PortAddr iop_base;
- ushort chksum;
- ushort warn_code;
- ushort cfg_msw, cfg_lsw;
- int i;
- int write_eep = 0;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
- AscStopQueueExe(iop_base);
- if ((AscStopChip(iop_base) == FALSE) ||
- (AscGetChipScsiCtrl(iop_base) != 0)) {
- asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
- AscResetChipAndScsiBus(asc_dvc);
- DvcSleepMilliSecond((ASC_DCNT)
- ((ushort) asc_dvc->scsi_reset_wait * 1000));
- }
- if (AscIsChipHalted(iop_base) == FALSE) {
- asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return (warn_code);
- }
- AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
- if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
- asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return (warn_code);
- }
- eep_config = (ASCEEP_CONFIG *) &eep_config_buf;
- cfg_msw = AscGetChipCfgMsw(iop_base);
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
- cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
- warn_code |= ASC_WARN_CFG_MSW_RECOVER;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- }
- chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
- ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
- if (chksum == 0) {
- chksum = 0xaa55;
- }
- if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
- warn_code |= ASC_WARN_AUTO_CONFIG;
- if (asc_dvc->cfg->chip_version == 3) {
- if (eep_config->cfg_lsw != cfg_lsw) {
- warn_code |= ASC_WARN_EEPROM_RECOVER;
- eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base);
- }
- if (eep_config->cfg_msw != cfg_msw) {
- warn_code |= ASC_WARN_EEPROM_RECOVER;
- eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
- }
- }
- }
- eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
- eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
- ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
- eep_config->chksum);
- if (chksum != eep_config->chksum) {
- if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
- ASC_CHIP_VER_PCI_ULTRA_3050 )
- {
- ASC_DBG(1,
-"AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
- eep_config->init_sdtr = 0xFF;
- eep_config->disc_enable = 0xFF;
- eep_config->start_motor = 0xFF;
- eep_config->use_cmd_qng = 0;
- eep_config->max_total_qng = 0xF0;
- eep_config->max_tag_qng = 0x20;
- eep_config->cntl = 0xBFFF;
- ASC_EEP_SET_CHIP_ID(eep_config, 7);
- eep_config->no_scam = 0;
- eep_config->adapter_info[0] = 0;
- eep_config->adapter_info[1] = 0;
- eep_config->adapter_info[2] = 0;
- eep_config->adapter_info[3] = 0;
- eep_config->adapter_info[4] = 0;
- /* Indicate EEPROM-less board. */
- eep_config->adapter_info[5] = 0xBB;
- } else {
- ASC_PRINT(
-"AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
- write_eep = 1;
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
- }
- }
- asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
- asc_dvc->cfg->disc_enable = eep_config->disc_enable;
- asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
- asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
- asc_dvc->start_motor = eep_config->start_motor;
- asc_dvc->dvc_cntl = eep_config->cntl;
- asc_dvc->no_scam = eep_config->no_scam;
- asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
- asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
- asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
- asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
- asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
- asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
- if (!AscTestExternalLram(asc_dvc)) {
- if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
- eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
- eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
- } else {
- eep_config->cfg_msw |= 0x0800;
- cfg_msw |= 0x0800;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
- eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
- }
- } else {
- }
- if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
- eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
- }
- if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
- eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
- }
- if (eep_config->max_tag_qng > eep_config->max_total_qng) {
- eep_config->max_tag_qng = eep_config->max_total_qng;
- }
- if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
- eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
- }
- asc_dvc->max_total_qng = eep_config->max_total_qng;
- if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
- eep_config->use_cmd_qng) {
- eep_config->disc_enable = eep_config->use_cmd_qng;
- warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
- }
- if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
- asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
- }
- ASC_EEP_SET_CHIP_ID(eep_config, ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
- asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
- if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
- !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
- asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
- }
+ ASCEEP_CONFIG eep_config_buf;
+ ASCEEP_CONFIG *eep_config;
+ PortAddr iop_base;
+ ushort chksum;
+ ushort warn_code;
+ ushort cfg_msw, cfg_lsw;
+ int i;
+ int write_eep = 0;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+ AscStopQueueExe(iop_base);
+ if ((AscStopChip(iop_base) == FALSE) ||
+ (AscGetChipScsiCtrl(iop_base) != 0)) {
+ asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+ AscResetChipAndScsiBus(asc_dvc);
+ DvcSleepMilliSecond((ASC_DCNT)
+ ((ushort)asc_dvc->scsi_reset_wait * 1000));
+ }
+ if (AscIsChipHalted(iop_base) == FALSE) {
+ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+ return (warn_code);
+ }
+ AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+ if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+ return (warn_code);
+ }
+ eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
+ cfg_msw = AscGetChipCfgMsw(iop_base);
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+ cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+ warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ }
+ chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+ ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
+ if (chksum == 0) {
+ chksum = 0xaa55;
+ }
+ if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+ warn_code |= ASC_WARN_AUTO_CONFIG;
+ if (asc_dvc->cfg->chip_version == 3) {
+ if (eep_config->cfg_lsw != cfg_lsw) {
+ warn_code |= ASC_WARN_EEPROM_RECOVER;
+ eep_config->cfg_lsw =
+ AscGetChipCfgLsw(iop_base);
+ }
+ if (eep_config->cfg_msw != cfg_msw) {
+ warn_code |= ASC_WARN_EEPROM_RECOVER;
+ eep_config->cfg_msw =
+ AscGetChipCfgMsw(iop_base);
+ }
+ }
+ }
+ eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+ ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
+ eep_config->chksum);
+ if (chksum != eep_config->chksum) {
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+ ASC_CHIP_VER_PCI_ULTRA_3050) {
+ ASC_DBG(1,
+ "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
+ eep_config->init_sdtr = 0xFF;
+ eep_config->disc_enable = 0xFF;
+ eep_config->start_motor = 0xFF;
+ eep_config->use_cmd_qng = 0;
+ eep_config->max_total_qng = 0xF0;
+ eep_config->max_tag_qng = 0x20;
+ eep_config->cntl = 0xBFFF;
+ ASC_EEP_SET_CHIP_ID(eep_config, 7);
+ eep_config->no_scam = 0;
+ eep_config->adapter_info[0] = 0;
+ eep_config->adapter_info[1] = 0;
+ eep_config->adapter_info[2] = 0;
+ eep_config->adapter_info[3] = 0;
+ eep_config->adapter_info[4] = 0;
+ /* Indicate EEPROM-less board. */
+ eep_config->adapter_info[5] = 0xBB;
+ } else {
+ ASC_PRINT
+ ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
+ write_eep = 1;
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
+ }
+ }
+ asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
+ asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+ asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+ asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
+ asc_dvc->start_motor = eep_config->start_motor;
+ asc_dvc->dvc_cntl = eep_config->cntl;
+ asc_dvc->no_scam = eep_config->no_scam;
+ asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+ asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+ asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+ asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+ asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+ asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+ if (!AscTestExternalLram(asc_dvc)) {
+ if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
+ ASC_IS_PCI_ULTRA)) {
+ eep_config->max_total_qng =
+ ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+ eep_config->max_tag_qng =
+ ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+ } else {
+ eep_config->cfg_msw |= 0x0800;
+ cfg_msw |= 0x0800;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+ eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
+ }
+ } else {
+ }
+ if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+ eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+ }
+ if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+ eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+ }
+ if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+ eep_config->max_tag_qng = eep_config->max_total_qng;
+ }
+ if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+ eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+ }
+ asc_dvc->max_total_qng = eep_config->max_total_qng;
+ if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+ eep_config->use_cmd_qng) {
+ eep_config->disc_enable = eep_config->use_cmd_qng;
+ warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+ }
+ if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
+ asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
+ }
+ ASC_EEP_SET_CHIP_ID(eep_config,
+ ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+ asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
+ if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+ !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+ asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+ }
- for (i = 0; i <= ASC_MAX_TID; i++) {
- asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
- asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
- asc_dvc->cfg->sdtr_period_offset[i] =
- (uchar) (ASC_DEF_SDTR_OFFSET |
- (asc_dvc->host_init_sdtr_index << 4));
- }
- eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
- if (write_eep) {
- if ((i = AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type)) !=
- 0) {
- ASC_PRINT1(
-"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
- } else {
- ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
- }
- }
- return (warn_code);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+ asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+ asc_dvc->cfg->sdtr_period_offset[i] =
+ (uchar)(ASC_DEF_SDTR_OFFSET |
+ (asc_dvc->host_init_sdtr_index << 4));
+ }
+ eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+ if (write_eep) {
+ if ((i =
+ AscSetEEPConfig(iop_base, eep_config,
+ asc_dvc->bus_type)) != 0) {
+ ASC_PRINT1
+ ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
+ i);
+ } else {
+ ASC_PRINT
+ ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
+ }
+ }
+ return (warn_code);
}
-STATIC ushort
-AscInitMicroCodeVar(
- ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
{
- int i;
- ushort warn_code;
- PortAddr iop_base;
- ASC_PADDR phy_addr;
- ASC_DCNT phy_size;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- for (i = 0; i <= ASC_MAX_TID; i++) {
- AscPutMCodeInitSDTRAtID(iop_base, i,
- asc_dvc->cfg->sdtr_period_offset[i]
-);
- }
+ int i;
+ ushort warn_code;
+ PortAddr iop_base;
+ ASC_PADDR phy_addr;
+ ASC_DCNT phy_size;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ AscPutMCodeInitSDTRAtID(iop_base, i,
+ asc_dvc->cfg->sdtr_period_offset[i]
+ );
+ }
- AscInitQLinkVar(asc_dvc);
- AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
- asc_dvc->cfg->disc_enable);
- AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
- ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
-
- /* Align overrun buffer on an 8 byte boundary. */
- phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
- phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
- AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
- (uchar *) &phy_addr, 1);
- phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
- AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
- (uchar *) &phy_size, 1);
-
- asc_dvc->cfg->mcode_date =
- AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W);
- asc_dvc->cfg->mcode_version =
- AscReadLramWord(iop_base, (ushort) ASCV_MC_VER_W);
-
- AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
- if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
- asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return (warn_code);
- }
- if (AscStartChip(iop_base) != 1) {
- asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return (warn_code);
- }
+ AscInitQLinkVar(asc_dvc);
+ AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+ asc_dvc->cfg->disc_enable);
+ AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+ ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+
+ /* Align overrun buffer on an 8 byte boundary. */
+ phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
+ phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
+ AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+ (uchar *)&phy_addr, 1);
+ phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
+ AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+ (uchar *)&phy_size, 1);
+
+ asc_dvc->cfg->mcode_date =
+ AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
+ asc_dvc->cfg->mcode_version =
+ AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+
+ AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+ if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+ return (warn_code);
+ }
+ if (AscStartChip(iop_base) != 1) {
+ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+ return (warn_code);
+ }
- return (warn_code);
+ return (warn_code);
}
-STATIC int __init
-AscTestExternalLram(
- ASC_DVC_VAR *asc_dvc)
+static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
{
- PortAddr iop_base;
- ushort q_addr;
- ushort saved_word;
- int sta;
-
- iop_base = asc_dvc->iop_base;
- sta = 0;
- q_addr = ASC_QNO_TO_QADDR(241);
- saved_word = AscReadLramWord(iop_base, q_addr);
- AscSetChipLramAddr(iop_base, q_addr);
- AscSetChipLramData(iop_base, 0x55AA);
- DvcSleepMilliSecond(10);
- AscSetChipLramAddr(iop_base, q_addr);
- if (AscGetChipLramData(iop_base) == 0x55AA) {
- sta = 1;
- AscWriteLramWord(iop_base, q_addr, saved_word);
- }
- return (sta);
+ PortAddr iop_base;
+ ushort q_addr;
+ ushort saved_word;
+ int sta;
+
+ iop_base = asc_dvc->iop_base;
+ sta = 0;
+ q_addr = ASC_QNO_TO_QADDR(241);
+ saved_word = AscReadLramWord(iop_base, q_addr);
+ AscSetChipLramAddr(iop_base, q_addr);
+ AscSetChipLramData(iop_base, 0x55AA);
+ DvcSleepMilliSecond(10);
+ AscSetChipLramAddr(iop_base, q_addr);
+ if (AscGetChipLramData(iop_base) == 0x55AA) {
+ sta = 1;
+ AscWriteLramWord(iop_base, q_addr, saved_word);
+ }
+ return (sta);
}
-STATIC int __init
-AscWriteEEPCmdReg(
- PortAddr iop_base,
- uchar cmd_reg
-)
+static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
{
- uchar read_back;
- int retry;
-
- retry = 0;
- while (TRUE) {
- AscSetChipEEPCmd(iop_base, cmd_reg);
- DvcSleepMilliSecond(1);
- read_back = AscGetChipEEPCmd(iop_base);
- if (read_back == cmd_reg) {
- return (1);
- }
- if (retry++ > ASC_EEP_MAX_RETRY) {
- return (0);
- }
- }
+ uchar read_back;
+ int retry;
+
+ retry = 0;
+ while (TRUE) {
+ AscSetChipEEPCmd(iop_base, cmd_reg);
+ DvcSleepMilliSecond(1);
+ read_back = AscGetChipEEPCmd(iop_base);
+ if (read_back == cmd_reg) {
+ return (1);
+ }
+ if (retry++ > ASC_EEP_MAX_RETRY) {
+ return (0);
+ }
+ }
}
-STATIC int __init
-AscWriteEEPDataReg(
- PortAddr iop_base,
- ushort data_reg
-)
+static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
{
- ushort read_back;
- int retry;
-
- retry = 0;
- while (TRUE) {
- AscSetChipEEPData(iop_base, data_reg);
- DvcSleepMilliSecond(1);
- read_back = AscGetChipEEPData(iop_base);
- if (read_back == data_reg) {
- return (1);
- }
- if (retry++ > ASC_EEP_MAX_RETRY) {
- return (0);
- }
- }
+ ushort read_back;
+ int retry;
+
+ retry = 0;
+ while (TRUE) {
+ AscSetChipEEPData(iop_base, data_reg);
+ DvcSleepMilliSecond(1);
+ read_back = AscGetChipEEPData(iop_base);
+ if (read_back == data_reg) {
+ return (1);
+ }
+ if (retry++ > ASC_EEP_MAX_RETRY) {
+ return (0);
+ }
+ }
}
-STATIC void __init
-AscWaitEEPRead(void)
+static void __init AscWaitEEPRead(void)
{
- DvcSleepMilliSecond(1);
- return;
+ DvcSleepMilliSecond(1);
+ return;
}
-STATIC void __init
-AscWaitEEPWrite(void)
+static void __init AscWaitEEPWrite(void)
{
- DvcSleepMilliSecond(20);
- return;
+ DvcSleepMilliSecond(20);
+ return;
}
-STATIC ushort __init
-AscReadEEPWord(
- PortAddr iop_base,
- uchar addr)
+static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
{
- ushort read_wval;
- uchar cmd_reg;
-
- AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
- AscWaitEEPRead();
- cmd_reg = addr | ASC_EEP_CMD_READ;
- AscWriteEEPCmdReg(iop_base, cmd_reg);
- AscWaitEEPRead();
- read_wval = AscGetChipEEPData(iop_base);
- AscWaitEEPRead();
- return (read_wval);
+ ushort read_wval;
+ uchar cmd_reg;
+
+ AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+ AscWaitEEPRead();
+ cmd_reg = addr | ASC_EEP_CMD_READ;
+ AscWriteEEPCmdReg(iop_base, cmd_reg);
+ AscWaitEEPRead();
+ read_wval = AscGetChipEEPData(iop_base);
+ AscWaitEEPRead();
+ return (read_wval);
}
-STATIC ushort __init
-AscWriteEEPWord(
- PortAddr iop_base,
- uchar addr,
- ushort word_val)
+static ushort __init
+AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
{
- ushort read_wval;
-
- read_wval = AscReadEEPWord(iop_base, addr);
- if (read_wval != word_val) {
- AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
- AscWaitEEPRead();
- AscWriteEEPDataReg(iop_base, word_val);
- AscWaitEEPRead();
- AscWriteEEPCmdReg(iop_base,
- (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr));
- AscWaitEEPWrite();
- AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
- AscWaitEEPRead();
- return (AscReadEEPWord(iop_base, addr));
- }
- return (read_wval);
+ ushort read_wval;
+
+ read_wval = AscReadEEPWord(iop_base, addr);
+ if (read_wval != word_val) {
+ AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
+ AscWaitEEPRead();
+ AscWriteEEPDataReg(iop_base, word_val);
+ AscWaitEEPRead();
+ AscWriteEEPCmdReg(iop_base,
+ (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
+ AscWaitEEPWrite();
+ AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+ AscWaitEEPRead();
+ return (AscReadEEPWord(iop_base, addr));
+ }
+ return (read_wval);
}
-STATIC ushort __init
-AscGetEEPConfig(
- PortAddr iop_base,
- ASCEEP_CONFIG * cfg_buf, ushort bus_type)
+static ushort __init
+AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
- ushort wval;
- ushort sum;
- ushort *wbuf;
- int cfg_beg;
- int cfg_end;
- int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
- int s_addr;
-
- wbuf = (ushort *) cfg_buf;
- sum = 0;
- /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
- for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
- *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
- sum += *wbuf;
- }
- if (bus_type & ASC_IS_VL) {
- cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
- cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
- } else {
- cfg_beg = ASC_EEP_DVC_CFG_BEG;
- cfg_end = ASC_EEP_MAX_DVC_ADDR;
- }
- for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
- wval = AscReadEEPWord( iop_base, ( uchar )s_addr ) ;
- if (s_addr <= uchar_end_in_config) {
- /*
- * Swap all char fields - must unswap bytes already swapped
- * by AscReadEEPWord().
- */
- *wbuf = le16_to_cpu(wval);
- } else {
- /* Don't swap word field at the end - cntl field. */
- *wbuf = wval;
- }
- sum += wval; /* Checksum treats all EEPROM data as words. */
- }
- /*
- * Read the checksum word which will be compared against 'sum'
- * by the caller. Word field already swapped.
- */
- *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
- return (sum);
+ ushort wval;
+ ushort sum;
+ ushort *wbuf;
+ int cfg_beg;
+ int cfg_end;
+ int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+ int s_addr;
+
+ wbuf = (ushort *)cfg_buf;
+ sum = 0;
+ /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+ sum += *wbuf;
+ }
+ if (bus_type & ASC_IS_VL) {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+ } else {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR;
+ }
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ wval = AscReadEEPWord(iop_base, (uchar)s_addr);
+ if (s_addr <= uchar_end_in_config) {
+ /*
+ * Swap all char fields - must unswap bytes already swapped
+ * by AscReadEEPWord().
+ */
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ /* Don't swap word field at the end - cntl field. */
+ *wbuf = wval;
+ }
+ sum += wval; /* Checksum treats all EEPROM data as words. */
+ }
+ /*
+ * Read the checksum word which will be compared against 'sum'
+ * by the caller. Word field already swapped.
+ */
+ *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+ return (sum);
}
-STATIC int __init
-AscSetEEPConfigOnce(
- PortAddr iop_base,
- ASCEEP_CONFIG * cfg_buf, ushort bus_type)
+static int __init
+AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
- int n_error;
- ushort *wbuf;
- ushort word;
- ushort sum;
- int s_addr;
- int cfg_beg;
- int cfg_end;
- int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
-
-
- wbuf = (ushort *) cfg_buf;
- n_error = 0;
- sum = 0;
- /* Write two config words; AscWriteEEPWord() will swap bytes. */
- for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
- sum += *wbuf;
- if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
- n_error++;
- }
- }
- if (bus_type & ASC_IS_VL) {
- cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
- cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
- } else {
- cfg_beg = ASC_EEP_DVC_CFG_BEG;
- cfg_end = ASC_EEP_MAX_DVC_ADDR;
- }
- for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
- if (s_addr <= uchar_end_in_config) {
- /*
- * This is a char field. Swap char fields before they are
- * swapped again by AscWriteEEPWord().
- */
- word = cpu_to_le16(*wbuf);
- if (word != AscWriteEEPWord( iop_base, (uchar) s_addr, word)) {
- n_error++;
- }
- } else {
- /* Don't swap word field at the end - cntl field. */
- if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
- n_error++;
- }
- }
- sum += *wbuf; /* Checksum calculated from word values. */
- }
- /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
- *wbuf = sum;
- if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
- n_error++;
- }
+ int n_error;
+ ushort *wbuf;
+ ushort word;
+ ushort sum;
+ int s_addr;
+ int cfg_beg;
+ int cfg_end;
+ int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+
+ wbuf = (ushort *)cfg_buf;
+ n_error = 0;
+ sum = 0;
+ /* Write two config words; AscWriteEEPWord() will swap bytes. */
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ sum += *wbuf;
+ if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
+ n_error++;
+ }
+ }
+ if (bus_type & ASC_IS_VL) {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+ } else {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR;
+ }
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ if (s_addr <= uchar_end_in_config) {
+ /*
+ * This is a char field. Swap char fields before they are
+ * swapped again by AscWriteEEPWord().
+ */
+ word = cpu_to_le16(*wbuf);
+ if (word !=
+ AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
+ n_error++;
+ }
+ } else {
+ /* Don't swap word field at the end - cntl field. */
+ if (*wbuf !=
+ AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
+ n_error++;
+ }
+ }
+ sum += *wbuf; /* Checksum calculated from word values. */
+ }
+ /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
+ *wbuf = sum;
+ if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
+ n_error++;
+ }
- /* Read EEPROM back again. */
- wbuf = (ushort *) cfg_buf;
- /*
- * Read two config words; Byte-swapping done by AscReadEEPWord().
- */
- for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
- if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
- n_error++;
- }
- }
- if (bus_type & ASC_IS_VL) {
- cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
- cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
- } else {
- cfg_beg = ASC_EEP_DVC_CFG_BEG;
- cfg_end = ASC_EEP_MAX_DVC_ADDR;
- }
- for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
- if (s_addr <= uchar_end_in_config) {
- /*
- * Swap all char fields. Must unswap bytes already swapped
- * by AscReadEEPWord().
- */
- word = le16_to_cpu(AscReadEEPWord(iop_base, (uchar) s_addr));
- } else {
- /* Don't swap word field at the end - cntl field. */
- word = AscReadEEPWord(iop_base, (uchar) s_addr);
- }
- if (*wbuf != word) {
- n_error++;
- }
- }
- /* Read checksum; Byte swapping not needed. */
- if (AscReadEEPWord(iop_base, (uchar) s_addr) != sum) {
- n_error++;
- }
- return (n_error);
+ /* Read EEPROM back again. */
+ wbuf = (ushort *)cfg_buf;
+ /*
+ * Read two config words; Byte-swapping done by AscReadEEPWord().
+ */
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
+ n_error++;
+ }
+ }
+ if (bus_type & ASC_IS_VL) {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+ } else {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR;
+ }
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ if (s_addr <= uchar_end_in_config) {
+ /*
+ * Swap all char fields. Must unswap bytes already swapped
+ * by AscReadEEPWord().
+ */
+ word =
+ le16_to_cpu(AscReadEEPWord
+ (iop_base, (uchar)s_addr));
+ } else {
+ /* Don't swap word field at the end - cntl field. */
+ word = AscReadEEPWord(iop_base, (uchar)s_addr);
+ }
+ if (*wbuf != word) {
+ n_error++;
+ }
+ }
+ /* Read checksum; Byte swapping not needed. */
+ if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
+ n_error++;
+ }
+ return (n_error);
}
-STATIC int __init
-AscSetEEPConfig(
- PortAddr iop_base,
- ASCEEP_CONFIG * cfg_buf, ushort bus_type
-)
+static int __init
+AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
- int retry;
- int n_error;
-
- retry = 0;
- while (TRUE) {
- if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
- bus_type)) == 0) {
- break;
- }
- if (++retry > ASC_EEP_MAX_RETRY) {
- break;
- }
- }
- return (n_error);
+ int retry;
+ int n_error;
+
+ retry = 0;
+ while (TRUE) {
+ if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
+ bus_type)) == 0) {
+ break;
+ }
+ if (++retry > ASC_EEP_MAX_RETRY) {
+ break;
+ }
+ }
+ return (n_error);
}
-STATIC void
-AscAsyncFix(
- ASC_DVC_VAR *asc_dvc,
- uchar tid_no,
- ASC_SCSI_INQUIRY *inq)
+static void
+AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
{
- uchar dvc_type;
- ASC_SCSI_BIT_ID_TYPE tid_bits;
-
- dvc_type = ASC_INQ_DVC_TYPE(inq);
- tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
-
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
- {
- if (!(asc_dvc->init_sdtr & tid_bits))
- {
- if ((dvc_type == TYPE_ROM) &&
- (AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "HP ", 3) == 0))
- {
- asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
- }
- asc_dvc->pci_fix_asyn_xfer |= tid_bits;
- if ((dvc_type == TYPE_PROCESSOR) ||
- (dvc_type == TYPE_SCANNER) ||
- (dvc_type == TYPE_ROM) ||
- (dvc_type == TYPE_TAPE))
- {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
-
- if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
- {
- AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
- ASYN_SDTR_DATA_FIX_PCI_REV_AB);
- }
- }
- }
- return;
+ uchar dvc_type;
+ ASC_SCSI_BIT_ID_TYPE tid_bits;
+
+ dvc_type = ASC_INQ_DVC_TYPE(inq);
+ tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
+
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
+ if (!(asc_dvc->init_sdtr & tid_bits)) {
+ if ((dvc_type == TYPE_ROM) &&
+ (AscCompareString((uchar *)inq->vendor_id,
+ (uchar *)"HP ", 3) == 0)) {
+ asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
+ }
+ asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+ if ((dvc_type == TYPE_PROCESSOR) ||
+ (dvc_type == TYPE_SCANNER) ||
+ (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
+ asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+ }
+
+ if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+ AscSetRunChipSynRegAtID(asc_dvc->iop_base,
+ tid_no,
+ ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+ }
+ }
+ }
+ return;
}
-STATIC int
-AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
+static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
{
- if ((inq->add_len >= 32) &&
- (AscCompareString((uchar *) inq->vendor_id,
- (uchar *) "QUANTUM XP34301", 15) == 0) &&
- (AscCompareString((uchar *) inq->product_rev_level,
- (uchar *) "1071", 4) == 0))
- {
- return 0;
- }
- return 1;
+ if ((inq->add_len >= 32) &&
+ (AscCompareString((uchar *)inq->vendor_id,
+ (uchar *)"QUANTUM XP34301", 15) == 0) &&
+ (AscCompareString((uchar *)inq->product_rev_level,
+ (uchar *)"1071", 4) == 0)) {
+ return 0;
+ }
+ return 1;
}
-STATIC void
-AscInquiryHandling(ASC_DVC_VAR *asc_dvc,
- uchar tid_no, ASC_SCSI_INQUIRY *inq)
+static void
+AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
{
- ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
- ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
-
- orig_init_sdtr = asc_dvc->init_sdtr;
- orig_use_tagged_qng = asc_dvc->use_tagged_qng;
-
- asc_dvc->init_sdtr &= ~tid_bit;
- asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
- asc_dvc->use_tagged_qng &= ~tid_bit;
-
- if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
- if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
- asc_dvc->init_sdtr |= tid_bit;
- }
- if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
- ASC_INQ_CMD_QUEUE(inq)) {
- if (AscTagQueuingSafe(inq)) {
- asc_dvc->use_tagged_qng |= tid_bit;
- asc_dvc->cfg->can_tagged_qng |= tid_bit;
- }
- }
- }
- if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
- AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
- asc_dvc->cfg->disc_enable);
- AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
- asc_dvc->use_tagged_qng);
- AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
- asc_dvc->cfg->can_tagged_qng);
-
- asc_dvc->max_dvc_qng[tid_no] =
- asc_dvc->cfg->max_tag_qng[tid_no];
- AscWriteLramByte(asc_dvc->iop_base,
- (ushort) (ASCV_MAX_DVC_QNG_BEG + tid_no),
- asc_dvc->max_dvc_qng[tid_no]);
- }
- if (orig_init_sdtr != asc_dvc->init_sdtr) {
- AscAsyncFix(asc_dvc, tid_no, inq);
- }
- return;
+ ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
+ ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
+
+ orig_init_sdtr = asc_dvc->init_sdtr;
+ orig_use_tagged_qng = asc_dvc->use_tagged_qng;
+
+ asc_dvc->init_sdtr &= ~tid_bit;
+ asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
+ asc_dvc->use_tagged_qng &= ~tid_bit;
+
+ if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
+ if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
+ asc_dvc->init_sdtr |= tid_bit;
+ }
+ if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
+ ASC_INQ_CMD_QUEUE(inq)) {
+ if (AscTagQueuingSafe(inq)) {
+ asc_dvc->use_tagged_qng |= tid_bit;
+ asc_dvc->cfg->can_tagged_qng |= tid_bit;
+ }
+ }
+ }
+ if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
+ asc_dvc->cfg->disc_enable);
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
+ asc_dvc->use_tagged_qng);
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
+ asc_dvc->cfg->can_tagged_qng);
+
+ asc_dvc->max_dvc_qng[tid_no] =
+ asc_dvc->cfg->max_tag_qng[tid_no];
+ AscWriteLramByte(asc_dvc->iop_base,
+ (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
+ asc_dvc->max_dvc_qng[tid_no]);
+ }
+ if (orig_init_sdtr != asc_dvc->init_sdtr) {
+ AscAsyncFix(asc_dvc, tid_no, inq);
+ }
+ return;
}
-STATIC int
-AscCompareString(
- uchar *str1,
- uchar *str2,
- int len
-)
+static int AscCompareString(uchar *str1, uchar *str2, int len)
{
- int i;
- int diff;
+ int i;
+ int diff;
- for (i = 0; i < len; i++) {
- diff = (int) (str1[i] - str2[i]);
- if (diff != 0)
- return (diff);
- }
- return (0);
+ for (i = 0; i < len; i++) {
+ diff = (int)(str1[i] - str2[i]);
+ if (diff != 0)
+ return (diff);
+ }
+ return (0);
}
-STATIC uchar
-AscReadLramByte(
- PortAddr iop_base,
- ushort addr
-)
+static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
{
- uchar byte_data;
- ushort word_data;
-
- if (isodd_word(addr)) {
- AscSetChipLramAddr(iop_base, addr - 1);
- word_data = AscGetChipLramData(iop_base);
- byte_data = (uchar) ((word_data >> 8) & 0xFF);
- } else {
- AscSetChipLramAddr(iop_base, addr);
- word_data = AscGetChipLramData(iop_base);
- byte_data = (uchar) (word_data & 0xFF);
- }
- return (byte_data);
+ uchar byte_data;
+ ushort word_data;
+
+ if (isodd_word(addr)) {
+ AscSetChipLramAddr(iop_base, addr - 1);
+ word_data = AscGetChipLramData(iop_base);
+ byte_data = (uchar)((word_data >> 8) & 0xFF);
+ } else {
+ AscSetChipLramAddr(iop_base, addr);
+ word_data = AscGetChipLramData(iop_base);
+ byte_data = (uchar)(word_data & 0xFF);
+ }
+ return (byte_data);
}
-STATIC ushort
-AscReadLramWord(
- PortAddr iop_base,
- ushort addr
-)
+
+static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
{
- ushort word_data;
+ ushort word_data;
- AscSetChipLramAddr(iop_base, addr);
- word_data = AscGetChipLramData(iop_base);
- return (word_data);
+ AscSetChipLramAddr(iop_base, addr);
+ word_data = AscGetChipLramData(iop_base);
+ return (word_data);
}
#if CC_VERY_LONG_SG_LIST
-STATIC ASC_DCNT
-AscReadLramDWord(
- PortAddr iop_base,
- ushort addr
-)
+static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
{
- ushort val_low, val_high;
- ASC_DCNT dword_data;
-
- AscSetChipLramAddr(iop_base, addr);
- val_low = AscGetChipLramData(iop_base);
- val_high = AscGetChipLramData(iop_base);
- dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
- return (dword_data);
+ ushort val_low, val_high;
+ ASC_DCNT dword_data;
+
+ AscSetChipLramAddr(iop_base, addr);
+ val_low = AscGetChipLramData(iop_base);
+ val_high = AscGetChipLramData(iop_base);
+ dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
+ return (dword_data);
}
#endif /* CC_VERY_LONG_SG_LIST */
-STATIC void
-AscWriteLramWord(
- PortAddr iop_base,
- ushort addr,
- ushort word_val
-)
+static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
{
- AscSetChipLramAddr(iop_base, addr);
- AscSetChipLramData(iop_base, word_val);
- return;
+ AscSetChipLramAddr(iop_base, addr);
+ AscSetChipLramData(iop_base, word_val);
+ return;
}
-STATIC void
-AscWriteLramByte(
- PortAddr iop_base,
- ushort addr,
- uchar byte_val
-)
+static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
{
- ushort word_data;
-
- if (isodd_word(addr)) {
- addr--;
- word_data = AscReadLramWord(iop_base, addr);
- word_data &= 0x00FF;
- word_data |= (((ushort) byte_val << 8) & 0xFF00);
- } else {
- word_data = AscReadLramWord(iop_base, addr);
- word_data &= 0xFF00;
- word_data |= ((ushort) byte_val & 0x00FF);
- }
- AscWriteLramWord(iop_base, addr, word_data);
- return;
+ ushort word_data;
+
+ if (isodd_word(addr)) {
+ addr--;
+ word_data = AscReadLramWord(iop_base, addr);
+ word_data &= 0x00FF;
+ word_data |= (((ushort)byte_val << 8) & 0xFF00);
+ } else {
+ word_data = AscReadLramWord(iop_base, addr);
+ word_data &= 0xFF00;
+ word_data |= ((ushort)byte_val & 0x00FF);
+ }
+ AscWriteLramWord(iop_base, addr, word_data);
+ return;
}
/*
@@ -12841,30 +11628,26 @@ AscWriteLramByte(
* The source data is assumed to be in little-endian order in memory
* and is maintained in little-endian order when written to LRAM.
*/
-STATIC void
-AscMemWordCopyPtrToLram(
- PortAddr iop_base,
- ushort s_addr,
- uchar *s_buffer,
- int words
-)
+static void
+AscMemWordCopyPtrToLram(PortAddr iop_base,
+ ushort s_addr, uchar *s_buffer, int words)
{
- int i;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- /*
- * On a little-endian system the second argument below
- * produces a little-endian ushort which is written to
- * LRAM in little-endian order. On a big-endian system
- * the second argument produces a big-endian ushort which
- * is "transparently" byte-swapped by outpw() and written
- * in little-endian order to LRAM.
- */
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]);
- }
- return;
+ int i;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ /*
+ * On a little-endian system the second argument below
+ * produces a little-endian ushort which is written to
+ * LRAM in little-endian order. On a big-endian system
+ * the second argument produces a big-endian ushort which
+ * is "transparently" byte-swapped by outpw() and written
+ * in little-endian order to LRAM.
+ */
+ outpw(iop_base + IOP_RAM_DATA,
+ ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
+ }
+ return;
}
/*
@@ -12873,24 +11656,18 @@ AscMemWordCopyPtrToLram(
* The source data is assumed to be in little-endian order in memory
* and is maintained in little-endian order when writen to LRAM.
*/
-STATIC void
-AscMemDWordCopyPtrToLram(
- PortAddr iop_base,
- ushort s_addr,
- uchar *s_buffer,
- int dwords
-)
+static void
+AscMemDWordCopyPtrToLram(PortAddr iop_base,
+ ushort s_addr, uchar *s_buffer, int dwords)
{
- int i;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 4 * dwords; i += 4) {
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort) s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
- }
- return;
+ int i;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 4 * dwords; i += 4) {
+ outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
+ outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
+ }
+ return;
}
/*
@@ -12899,61 +11676,46 @@ AscMemDWordCopyPtrToLram(
* The source data is assumed to be in little-endian order in LRAM
* and is maintained in little-endian order when written to memory.
*/
-STATIC void
-AscMemWordCopyPtrFromLram(
- PortAddr iop_base,
- ushort s_addr,
- uchar *d_buffer,
- int words
-)
+static void
+AscMemWordCopyPtrFromLram(PortAddr iop_base,
+ ushort s_addr, uchar *d_buffer, int words)
{
- int i;
- ushort word;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- word = inpw(iop_base + IOP_RAM_DATA);
- d_buffer[i] = word & 0xff;
- d_buffer[i + 1] = (word >> 8) & 0xff;
- }
- return;
+ int i;
+ ushort word;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ word = inpw(iop_base + IOP_RAM_DATA);
+ d_buffer[i] = word & 0xff;
+ d_buffer[i + 1] = (word >> 8) & 0xff;
+ }
+ return;
}
-STATIC ASC_DCNT
-AscMemSumLramWord(
- PortAddr iop_base,
- ushort s_addr,
- int words
-)
+static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
{
- ASC_DCNT sum;
- int i;
+ ASC_DCNT sum;
+ int i;
- sum = 0L;
- for (i = 0; i < words; i++, s_addr += 2) {
- sum += AscReadLramWord(iop_base, s_addr);
- }
- return (sum);
+ sum = 0L;
+ for (i = 0; i < words; i++, s_addr += 2) {
+ sum += AscReadLramWord(iop_base, s_addr);
+ }
+ return (sum);
}
-STATIC void
-AscMemWordSetLram(
- PortAddr iop_base,
- ushort s_addr,
- ushort set_wval,
- int words
-)
+static void
+AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
{
- int i;
+ int i;
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < words; i++) {
- AscSetChipLramData(iop_base, set_wval);
- }
- return;
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < words; i++) {
+ AscSetChipLramData(iop_base, set_wval);
+ }
+ return;
}
-
/*
* --- Adv Library Functions
*/
@@ -12961,1076 +11723,2112 @@ AscMemWordSetLram(
/* a_mcode.h */
/* Microcode buffer is kept after initialization for error recovery. */
-STATIC unsigned char _adv_asc3550_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc, 0x01, 0x00, 0x48, 0xe4,
- 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7,
- 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
- 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00, 0x00, 0xec, 0x85, 0xf0,
- 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00,
- 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
- 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea,
- 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
- 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
- 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00, 0x3e, 0x00, 0x80, 0x00,
- 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
- 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
- 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
- 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15,
- 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
- 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
- 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c,
- 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
- 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00,
- 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10,
- 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
- 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45,
- 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6,
- 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
- 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x9e, 0x00, 0xa8, 0x00,
- 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01,
- 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
- 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x06, 0x12,
- 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17,
- 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
- 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55, 0x14, 0x56, 0x77, 0x57,
- 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe,
- 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xcf,
- 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b, 0x02, 0xfe, 0xd4, 0x0c,
- 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6,
- 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
- 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02, 0xfe, 0x46, 0xf0, 0xfe,
- 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44,
- 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
- 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9,
- 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e,
- 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
- 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x17, 0x06,
- 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe,
- 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
- 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe, 0x69, 0x10, 0x17, 0x06,
- 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe,
- 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
- 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0x99, 0x01,
- 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02,
- 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
- 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0, 0xfe, 0x56, 0x03, 0xfe,
- 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe,
- 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
- 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40, 0x01, 0x0e, 0xac, 0x75,
- 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe,
- 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
- 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe, 0x0a, 0xf0, 0xfe, 0x7a,
- 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe,
- 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
- 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3, 0x0a, 0xca, 0x01, 0x0e,
- 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f,
- 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
- 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2b, 0xff, 0x02,
- 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5,
- 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
- 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d, 0xfe, 0x2a, 0x13, 0x2f,
- 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86,
- 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
- 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22,
- 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29,
- 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
- 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a, 0xfe, 0x70, 0x12, 0x49,
- 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31,
- 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
- 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05, 0x11, 0xfe, 0xe3, 0x00,
- 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24,
- 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
- 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01, 0x86, 0x24, 0x06, 0x12,
- 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92,
- 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
- 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13, 0x47, 0x01, 0xa7, 0x26,
- 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14,
- 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
- 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x14,
- 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57,
- 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
- 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68, 0x06, 0x11, 0x9a, 0x01,
- 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72,
- 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
- 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07, 0x8d, 0x81, 0x02, 0x22,
- 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
- 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
- 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15, 0xfe, 0x1b, 0x00, 0x01,
- 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01,
- 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
- 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12,
- 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d,
- 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
- 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x77, 0xfe, 0xca,
- 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12,
- 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
- 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f, 0x40, 0x12, 0x58, 0x01,
- 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe,
- 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
- 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a, 0xfe, 0x2a, 0x12, 0xfe,
- 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe,
- 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
- 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x39, 0x18, 0x3a,
- 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48,
- 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
- 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x7a, 0x08, 0x8d,
- 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06,
- 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
- 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe, 0x52, 0x12, 0xfe, 0x2c,
- 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10,
- 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
- 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xb5, 0xfe,
- 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d,
- 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
- 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a, 0xfe, 0x74, 0x18, 0x1c,
- 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27,
- 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
- 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc, 0xfe, 0x83, 0x80, 0xfe,
- 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59,
- 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
- 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e, 0x79, 0x56, 0x68, 0x57,
- 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b,
- 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
- 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x10, 0x58, 0xfe,
- 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09,
- 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
- 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08, 0x11, 0x9b, 0x09, 0x04,
- 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe,
- 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
- 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9, 0x14, 0x7a, 0x01, 0x33,
- 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf,
- 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
- 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x84, 0x05, 0xcb, 0x1c,
- 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a,
- 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
- 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe, 0x22, 0x00, 0x02, 0x5a,
- 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe,
- 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
- 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00, 0x2a, 0x13, 0xfe, 0x4e,
- 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73,
- 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
- 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xdb, 0x10, 0x11, 0xfe,
- 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8,
- 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
- 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c, 0x09, 0x04, 0x0b, 0xfe,
- 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6,
- 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
- 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x02, 0x29,
- 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b,
- 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
- 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01, 0xe8, 0x59, 0x11, 0x2d,
- 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e,
- 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
- 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
- 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe,
- 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
- 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa, 0xab, 0x70, 0x05, 0x6b,
- 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01,
- 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
- 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e, 0x1d, 0xfe, 0xce, 0x45,
- 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe,
- 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
- 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe,
- 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee,
- 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
- 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12, 0xce, 0x1e, 0x2d, 0x47,
- 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe,
- 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
- 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
- 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea,
- 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
- 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01,
- 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e,
- 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
- 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57,
- 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe,
- 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
- 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xe1,
- 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c,
- 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
- 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01, 0xe8, 0x11, 0xfe, 0xe9,
- 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14,
- 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
- 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80, 0x40, 0x12, 0x20, 0x63,
- 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac,
- 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
- 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x24, 0x69, 0x12, 0xc9,
- 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
- 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
- 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c, 0x46, 0x1e, 0x20, 0xed,
- 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c,
- 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
- 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46, 0xfa, 0xef, 0xfe, 0x42,
- 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0,
- 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
- 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e, 0x10, 0x07, 0x7e, 0x45,
- 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97,
- 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
- 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b, 0xfe, 0x48, 0x12, 0x07,
- 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07,
- 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
- 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b, 0x01, 0x08, 0x8c, 0x43,
- 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b,
- 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
- 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe, 0xc6, 0x10, 0x1e, 0x58,
- 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23,
- 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
- 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0xfe,
- 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57,
- 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
- 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e, 0x58, 0xfe, 0x1f, 0x40,
- 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44,
- 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
- 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06, 0x12, 0xcd, 0x02, 0x5b,
- 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21,
- 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
- 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
- 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32,
- 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
- 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44, 0x01, 0x08, 0x1f, 0xa2,
- 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49,
- 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
- 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1, 0x05, 0xc6, 0x28, 0x84,
- 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
- 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
- 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06, 0x21, 0x44, 0x01, 0xfe,
- 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b,
- 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
- 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xd8, 0x14, 0x02, 0x5c,
- 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72,
- 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
- 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0xfe, 0xff, 0x7f,
- 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c,
- 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
- 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58, 0x03, 0x0a, 0x50, 0x01,
- 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4,
- 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
- 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe,
- 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60,
- 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
- 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe, 0xcc, 0x12, 0x49, 0x04,
- 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13,
- 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
- 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c, 0x13, 0x06, 0xfe, 0x56,
- 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93,
- 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
- 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90, 0x01, 0xba, 0xfe, 0x4e,
- 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe,
- 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
- 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba, 0xfe, 0x9c, 0x14, 0xb7,
- 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7,
- 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
- 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x0b, 0x01,
- 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03,
- 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
- 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89, 0x4a, 0x01, 0x08, 0x03,
- 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00,
- 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
- 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd, 0x01, 0x43, 0x1e, 0xcd,
- 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10,
- 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
- 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3, 0x88, 0x03, 0x0a, 0x42,
- 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2,
- 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
- 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe,
- 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe,
- 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
- 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58, 0x05, 0xfe, 0x66, 0x01,
- 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66,
- 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
- 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17, 0x10, 0x71, 0xfe, 0x83,
- 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe,
- 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
- 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71, 0xfe, 0x30, 0xbc, 0xfe,
- 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a,
- 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
- 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc, 0xfe, 0x1d, 0xf7, 0x4f,
- 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58,
- 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
- 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14, 0x06, 0x37, 0x95, 0xa9,
- 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d,
- 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
- 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x3c, 0x8a, 0x0a,
- 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc,
- 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
- 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xf6, 0xfe, 0xd6, 0xf0,
- 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76,
- 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
- 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68, 0xc8, 0xfe, 0x48, 0x55,
- 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0,
- 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
- 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01, 0x0e, 0x73, 0x75, 0x03,
- 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b,
- 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
- 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05, 0xfe, 0x94, 0x00, 0xfe,
- 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e,
- 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
- 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1b, 0xfe, 0x5a,
- 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07,
- 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
- 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9, 0x03, 0x25, 0xfe, 0xca,
- 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
+static unsigned char _adv_asc3550_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
+ 0x01, 0x00, 0x48, 0xe4,
+ 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
+ 0x28, 0x0e, 0x9e, 0xe7,
+ 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
+ 0x55, 0xf0, 0x01, 0xf6,
+ 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
+ 0x00, 0xec, 0x85, 0xf0,
+ 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
+ 0x86, 0xf0, 0xb4, 0x00,
+ 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
+ 0xaa, 0x18, 0x02, 0x80,
+ 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
+ 0x00, 0x57, 0x01, 0xea,
+ 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
+ 0x03, 0xe6, 0xb6, 0x00,
+ 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
+ 0x02, 0x4a, 0xb9, 0x54,
+ 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
+ 0x3e, 0x00, 0x80, 0x00,
+ 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
+ 0x74, 0x01, 0x76, 0x01,
+ 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
+ 0x4c, 0x1c, 0xbb, 0x55,
+ 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
+ 0x03, 0xf7, 0x06, 0xf7,
+ 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
+ 0x30, 0x13, 0x64, 0x15,
+ 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
+ 0x04, 0xea, 0x5d, 0xf0,
+ 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
+ 0xcc, 0x00, 0x20, 0x01,
+ 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
+ 0x40, 0x13, 0x30, 0x1c,
+ 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+ 0x59, 0xf0, 0xa7, 0xf0,
+ 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
+ 0xa4, 0x00, 0xb5, 0x00,
+ 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
+ 0x14, 0x0e, 0x02, 0x10,
+ 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
+ 0x10, 0x15, 0x14, 0x15,
+ 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
+ 0x91, 0x44, 0x0a, 0x45,
+ 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
+ 0x83, 0x59, 0x05, 0xe6,
+ 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
+ 0x02, 0xfa, 0x03, 0xfa,
+ 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
+ 0x9e, 0x00, 0xa8, 0x00,
+ 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
+ 0x7a, 0x01, 0xc0, 0x01,
+ 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
+ 0x69, 0x08, 0xba, 0x08,
+ 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
+ 0xf1, 0x10, 0x06, 0x12,
+ 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
+ 0x8a, 0x15, 0xc6, 0x17,
+ 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
+ 0x0e, 0x47, 0x48, 0x47,
+ 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
+ 0x14, 0x56, 0x77, 0x57,
+ 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
+ 0xf0, 0x29, 0x02, 0xfe,
+ 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
+ 0xfe, 0x80, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24,
+ 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
+ 0x00, 0x00, 0xff, 0x08,
+ 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
+ 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xcf,
+ 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
+ 0x0b, 0x3c, 0x2a, 0xfe,
+ 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
+ 0xfe, 0xf0, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
+ 0x02, 0xfe, 0xd4, 0x0c,
+ 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
+ 0x1c, 0x05, 0xfe, 0xa6,
+ 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
+ 0xf0, 0xfe, 0x86, 0x02,
+ 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
+ 0xfe, 0x46, 0xf0, 0xfe,
+ 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
+ 0x44, 0x02, 0xfe, 0x44,
+ 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
+ 0xa0, 0x17, 0x06, 0x18,
+ 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0xe9,
+ 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
+ 0x0a, 0x6b, 0x01, 0x9e,
+ 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
+ 0x01, 0x82, 0xfe, 0xbd,
+ 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x17, 0x06,
+ 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
+ 0xfe, 0x94, 0x02, 0xfe,
+ 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
+ 0x01, 0xfe, 0x54, 0x0f,
+ 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
+ 0x69, 0x10, 0x17, 0x06,
+ 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
+ 0xf6, 0xc7, 0x01, 0xfe,
+ 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
+ 0x02, 0x29, 0x0a, 0x40,
+ 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+ 0x58, 0x0a, 0x99, 0x01,
+ 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
+ 0x2a, 0x46, 0xfe, 0x02,
+ 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
+ 0x01, 0xfe, 0x07, 0x4b,
+ 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
+ 0xfe, 0x56, 0x03, 0xfe,
+ 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
+ 0xfe, 0x9f, 0xf0, 0xfe,
+ 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
+ 0x1c, 0xeb, 0x09, 0x04,
+ 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
+ 0x01, 0x0e, 0xac, 0x75,
+ 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
+ 0xfe, 0x82, 0xf0, 0xfe,
+ 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
+ 0x32, 0x1f, 0xfe, 0xb4,
+ 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
+ 0x0a, 0xf0, 0xfe, 0x7a,
+ 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
+ 0x01, 0x33, 0x8f, 0xfe,
+ 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
+ 0xf7, 0xfe, 0x48, 0x1c,
+ 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
+ 0x0a, 0xca, 0x01, 0x0e,
+ 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
+ 0x2c, 0x01, 0x33, 0x8f,
+ 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
+ 0xfe, 0x3c, 0x04, 0x1f,
+ 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+ 0x12, 0x2b, 0xff, 0x02,
+ 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
+ 0x22, 0x30, 0x2e, 0xd5,
+ 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
+ 0xfe, 0x4c, 0x54, 0x64,
+ 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
+ 0xfe, 0x2a, 0x13, 0x2f,
+ 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
+ 0xd3, 0xfa, 0xef, 0x86,
+ 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
+ 0x1d, 0xfe, 0x1c, 0x12,
+ 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
+ 0x70, 0x0c, 0x02, 0x22,
+ 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
+ 0x01, 0x33, 0x02, 0x29,
+ 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
+ 0x80, 0xfe, 0x31, 0xe4,
+ 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
+ 0xfe, 0x70, 0x12, 0x49,
+ 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
+ 0x80, 0x05, 0xfe, 0x31,
+ 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
+ 0x28, 0xfe, 0x42, 0x12,
+ 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
+ 0x11, 0xfe, 0xe3, 0x00,
+ 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
+ 0x64, 0x05, 0x83, 0x24,
+ 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
+ 0x09, 0x48, 0x01, 0x08,
+ 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
+ 0x86, 0x24, 0x06, 0x12,
+ 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
+ 0x01, 0xa7, 0x14, 0x92,
+ 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
+ 0x02, 0x22, 0x05, 0xfe,
+ 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
+ 0x47, 0x01, 0xa7, 0x26,
+ 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
+ 0x01, 0xfe, 0xaa, 0x14,
+ 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
+ 0x05, 0x50, 0xb4, 0x0c,
+ 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
+ 0x13, 0x01, 0xfe, 0x14,
+ 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
+ 0xff, 0x02, 0x00, 0x57,
+ 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
+ 0x72, 0x06, 0x49, 0x04,
+ 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
+ 0x06, 0x11, 0x9a, 0x01,
+ 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
+ 0x01, 0xa7, 0xec, 0x72,
+ 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
+ 0xfe, 0x0a, 0xf0, 0xfe,
+ 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
+ 0x8d, 0x81, 0x02, 0x22,
+ 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
+ 0x01, 0x08, 0x15, 0x00,
+ 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
+ 0x00, 0x02, 0xfe, 0x32,
+ 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
+ 0xfe, 0x1b, 0x00, 0x01,
+ 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
+ 0x08, 0x15, 0x06, 0x01,
+ 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
+ 0x9a, 0x81, 0x4b, 0x1d,
+ 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
+ 0x45, 0xfe, 0x32, 0x12,
+ 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
+ 0xfe, 0x32, 0x07, 0x8d,
+ 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
+ 0x06, 0x15, 0x19, 0x02,
+ 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x77, 0xfe, 0xca,
+ 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
+ 0x10, 0xfe, 0x0e, 0x12,
+ 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
+ 0x83, 0xe7, 0xc4, 0xa1,
+ 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
+ 0x40, 0x12, 0x58, 0x01,
+ 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
+ 0x51, 0x83, 0xfb, 0xfe,
+ 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
+ 0xfe, 0x40, 0x50, 0xfe,
+ 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
+ 0xfe, 0x2a, 0x12, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
+ 0x85, 0x01, 0xa8, 0xfe,
+ 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
+ 0x18, 0x57, 0xfb, 0xfe,
+ 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
+ 0x0c, 0x39, 0x18, 0x3a,
+ 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
+ 0x11, 0x65, 0xfe, 0x48,
+ 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
+ 0xdd, 0xb8, 0xfe, 0x80,
+ 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
+ 0xfe, 0x7a, 0x08, 0x8d,
+ 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
+ 0x10, 0x61, 0x04, 0x06,
+ 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
+ 0x12, 0xfe, 0x2e, 0x1c,
+ 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
+ 0x52, 0x12, 0xfe, 0x2c,
+ 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
+ 0x08, 0xfe, 0x8a, 0x10,
+ 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
+ 0x24, 0x0a, 0xab, 0xfe,
+ 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
+ 0x1c, 0x12, 0xb5, 0xfe,
+ 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
+ 0x1c, 0x06, 0x16, 0x9d,
+ 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
+ 0x14, 0x92, 0x01, 0x33,
+ 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
+ 0xfe, 0x74, 0x18, 0x1c,
+ 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
+ 0x01, 0xe6, 0x1e, 0x27,
+ 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
+ 0x09, 0x04, 0x6a, 0xfe,
+ 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
+ 0xfe, 0x83, 0x80, 0xfe,
+ 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
+ 0x27, 0xfe, 0x40, 0x59,
+ 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
+ 0x7c, 0xbe, 0x54, 0xbf,
+ 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
+ 0x79, 0x56, 0x68, 0x57,
+ 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
+ 0xa2, 0x23, 0x0c, 0x7b,
+ 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
+ 0x16, 0xd7, 0x79, 0x39,
+ 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
+ 0xfe, 0x10, 0x58, 0xfe,
+ 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
+ 0x19, 0x16, 0xd7, 0x09,
+ 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
+ 0xfe, 0x10, 0x90, 0xfe,
+ 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
+ 0x11, 0x9b, 0x09, 0x04,
+ 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
+ 0xfe, 0x0c, 0x58, 0xfe,
+ 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
+ 0x0b, 0xfe, 0x1a, 0x12,
+ 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
+ 0x14, 0x7a, 0x01, 0x33,
+ 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
+ 0xfe, 0xed, 0x19, 0xbf,
+ 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
+ 0x34, 0xfe, 0x74, 0x10,
+ 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+ 0x84, 0x05, 0xcb, 0x1c,
+ 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
+ 0xf0, 0xfe, 0xc4, 0x0a,
+ 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
+ 0xce, 0xf0, 0xfe, 0xca,
+ 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
+ 0x22, 0x00, 0x02, 0x5a,
+ 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
+ 0xfe, 0xd0, 0xf0, 0xfe,
+ 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
+ 0x4c, 0xfe, 0x10, 0x10,
+ 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
+ 0x2a, 0x13, 0xfe, 0x4e,
+ 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
+ 0x16, 0x32, 0x2a, 0x73,
+ 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
+ 0x32, 0x8c, 0xfe, 0x48,
+ 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
+ 0xdb, 0x10, 0x11, 0xfe,
+ 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
+ 0x22, 0x30, 0x2e, 0xd8,
+ 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
+ 0x45, 0x0f, 0xfe, 0x42,
+ 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
+ 0x09, 0x04, 0x0b, 0xfe,
+ 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
+ 0x00, 0x21, 0xfe, 0xa6,
+ 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
+ 0xfe, 0xe2, 0x10, 0x01,
+ 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
+ 0x01, 0x6f, 0x02, 0x29,
+ 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
+ 0x01, 0x86, 0x3e, 0x0b,
+ 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
+ 0x3e, 0x0b, 0x0f, 0xfe,
+ 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
+ 0xe8, 0x59, 0x11, 0x2d,
+ 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
+ 0x04, 0x0b, 0x84, 0x3e,
+ 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
+ 0x09, 0x04, 0x1b, 0xfe,
+ 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
+ 0x1c, 0x1c, 0xfe, 0x9d,
+ 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
+ 0xfe, 0x15, 0x00, 0xfe,
+ 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
+ 0x0f, 0xfe, 0x47, 0x00,
+ 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
+ 0xab, 0x70, 0x05, 0x6b,
+ 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
+ 0x1c, 0x42, 0x59, 0x01,
+ 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
+ 0x00, 0x37, 0x97, 0x01,
+ 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
+ 0x1d, 0xfe, 0xce, 0x45,
+ 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
+ 0x57, 0x05, 0x51, 0xfe,
+ 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
+ 0x46, 0x09, 0x04, 0x1d,
+ 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
+ 0x99, 0x01, 0x0e, 0xfe,
+ 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
+ 0xfe, 0xee, 0x14, 0xee,
+ 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
+ 0x13, 0x02, 0x29, 0x1e,
+ 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
+ 0xce, 0x1e, 0x2d, 0x47,
+ 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
+ 0x12, 0x4d, 0x01, 0xfe,
+ 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
+ 0xf0, 0x0d, 0xfe, 0x02,
+ 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
+ 0xf6, 0xfe, 0x34, 0x01,
+ 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
+ 0xaf, 0xfe, 0x02, 0xea,
+ 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
+ 0x05, 0xfe, 0x38, 0x01,
+ 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
+ 0x0c, 0xfe, 0x62, 0x01,
+ 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
+ 0x03, 0x23, 0x03, 0x1e,
+ 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
+ 0x71, 0x13, 0xfe, 0x24,
+ 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57,
+ 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
+ 0x80, 0x5d, 0x03, 0xfe,
+ 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
+ 0x75, 0x03, 0x09, 0x04,
+ 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+ 0xfe, 0x1e, 0x80, 0xe1,
+ 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
+ 0x90, 0xa3, 0xfe, 0x3c,
+ 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
+ 0x16, 0x2f, 0x07, 0x2d,
+ 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
+ 0xe8, 0x11, 0xfe, 0xe9,
+ 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0x14,
+ 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
+ 0x09, 0x04, 0x4f, 0xfe,
+ 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+ 0x40, 0x12, 0x20, 0x63,
+ 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
+ 0x1c, 0x05, 0xfe, 0xac,
+ 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
+ 0xfe, 0xb0, 0x00, 0xfe,
+ 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+ 0x24, 0x69, 0x12, 0xc9,
+ 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
+ 0x90, 0x4d, 0xfe, 0x91,
+ 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
+ 0xfe, 0x90, 0x4d, 0xfe,
+ 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
+ 0x46, 0x1e, 0x20, 0xed,
+ 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
+ 0x70, 0xfe, 0x14, 0x1c,
+ 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
+ 0xfe, 0x07, 0xe6, 0x1d,
+ 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
+ 0xfa, 0xef, 0xfe, 0x42,
+ 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
+ 0xfe, 0x36, 0x12, 0xf0,
+ 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
+ 0x3d, 0x75, 0x07, 0x10,
+ 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
+ 0x10, 0x07, 0x7e, 0x45,
+ 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
+ 0xfe, 0x01, 0xec, 0x97,
+ 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
+ 0x27, 0x01, 0xda, 0xfe,
+ 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
+ 0xfe, 0x48, 0x12, 0x07,
+ 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
+ 0xfe, 0x3e, 0x11, 0x07,
+ 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
+ 0x11, 0x07, 0x19, 0xfe,
+ 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
+ 0x01, 0x08, 0x8c, 0x43,
+ 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
+ 0x7e, 0x02, 0x29, 0x2b,
+ 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
+ 0xfc, 0x10, 0x09, 0x04,
+ 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
+ 0xc6, 0x10, 0x1e, 0x58,
+ 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
+ 0x54, 0x18, 0x55, 0x23,
+ 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
+ 0xa5, 0xc0, 0x38, 0xc1,
+ 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
+ 0x05, 0xfa, 0x4e, 0xfe,
+ 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
+ 0x0c, 0x56, 0x18, 0x57,
+ 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
+ 0x00, 0x56, 0xfe, 0xa1,
+ 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
+ 0x58, 0xfe, 0x1f, 0x40,
+ 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
+ 0x31, 0x57, 0xfe, 0x44,
+ 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
+ 0x8a, 0x50, 0x05, 0x39,
+ 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
+ 0x12, 0xcd, 0x02, 0x5b,
+ 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
+ 0x2f, 0x07, 0x9b, 0x21,
+ 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
+ 0x39, 0x68, 0x3a, 0xfe,
+ 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
+ 0x51, 0xfe, 0x8e, 0x51,
+ 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
+ 0x01, 0x08, 0x25, 0x32,
+ 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
+ 0x3b, 0x02, 0x44, 0x01,
+ 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
+ 0x01, 0x08, 0x1f, 0xa2,
+ 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
+ 0x00, 0x28, 0x84, 0x49,
+ 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
+ 0x78, 0x3d, 0xfe, 0xda,
+ 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
+ 0x05, 0xc6, 0x28, 0x84,
+ 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
+ 0x14, 0xfe, 0x03, 0x17,
+ 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
+ 0xfe, 0xaa, 0x14, 0x02,
+ 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
+ 0x21, 0x44, 0x01, 0xfe,
+ 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
+ 0xfe, 0x4a, 0xf4, 0x0b,
+ 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
+ 0x85, 0x02, 0x5b, 0x05,
+ 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
+ 0xd8, 0x14, 0x02, 0x5c,
+ 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
+ 0x01, 0x08, 0x23, 0x72,
+ 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
+ 0x12, 0x5e, 0x2b, 0x01,
+ 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+ 0x1c, 0xfe, 0xff, 0x7f,
+ 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
+ 0x57, 0x48, 0x8b, 0x1c,
+ 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
+ 0x00, 0x57, 0x48, 0x8b,
+ 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
+ 0x03, 0x0a, 0x50, 0x01,
+ 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
+ 0x54, 0xfe, 0x00, 0xf4,
+ 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
+ 0x03, 0x7c, 0x63, 0x27,
+ 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
+ 0xfe, 0x82, 0x4a, 0xfe,
+ 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
+ 0x42, 0x48, 0x5f, 0x60,
+ 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
+ 0x1f, 0xfe, 0xa2, 0x14,
+ 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
+ 0xcc, 0x12, 0x49, 0x04,
+ 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
+ 0xe8, 0x13, 0x3b, 0x13,
+ 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
+ 0xa1, 0xff, 0x02, 0x83,
+ 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
+ 0x13, 0x06, 0xfe, 0x56,
+ 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
+ 0x64, 0x00, 0x17, 0x93,
+ 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
+ 0xc8, 0x00, 0x8e, 0xe4,
+ 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
+ 0x01, 0xba, 0xfe, 0x4e,
+ 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
+ 0xfe, 0x60, 0x14, 0xfe,
+ 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
+ 0xfe, 0x22, 0x13, 0x1c,
+ 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
+ 0xfe, 0x9c, 0x14, 0xb7,
+ 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
+ 0xfe, 0x9c, 0x14, 0xb7,
+ 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
+ 0xfe, 0xb4, 0x56, 0xfe,
+ 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
+ 0xe5, 0x15, 0x0b, 0x01,
+ 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
+ 0x49, 0x01, 0x08, 0x03,
+ 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
+ 0x15, 0x06, 0x01, 0x08,
+ 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
+ 0x4a, 0x01, 0x08, 0x03,
+ 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
+ 0xfe, 0x49, 0xf4, 0x00,
+ 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
+ 0x08, 0x2f, 0x07, 0xfe,
+ 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
+ 0x01, 0x43, 0x1e, 0xcd,
+ 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
+ 0xed, 0x88, 0x07, 0x10,
+ 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
+ 0x80, 0x01, 0x0e, 0x88,
+ 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
+ 0x88, 0x03, 0x0a, 0x42,
+ 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
+ 0xfe, 0x80, 0x80, 0xf2,
+ 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
+ 0x01, 0x82, 0x03, 0x17,
+ 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
+ 0xfe, 0x24, 0x1c, 0xfe,
+ 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
+ 0x91, 0x1d, 0x66, 0xfe,
+ 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
+ 0xda, 0x10, 0x17, 0x10,
+ 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
+ 0x05, 0xfe, 0x66, 0x01,
+ 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
+ 0xfe, 0x3c, 0x50, 0x66,
+ 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
+ 0x40, 0x16, 0xfe, 0xb6,
+ 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
+ 0x10, 0x71, 0xfe, 0x83,
+ 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
+ 0xfe, 0x62, 0x16, 0xfe,
+ 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
+ 0xfe, 0x98, 0xe7, 0x00,
+ 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
+ 0xfe, 0x30, 0xbc, 0xfe,
+ 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+ 0xc5, 0x90, 0xfe, 0x9a,
+ 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
+ 0x42, 0x10, 0xfe, 0x02,
+ 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
+ 0xfe, 0x1d, 0xf7, 0x4f,
+ 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
+ 0x47, 0xfe, 0x83, 0x58,
+ 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
+ 0xfe, 0xdd, 0x00, 0x63,
+ 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
+ 0x06, 0x37, 0x95, 0xa9,
+ 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
+ 0x18, 0x1c, 0x1a, 0x5d,
+ 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
+ 0xe1, 0x10, 0x78, 0x2c,
+ 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
+ 0x13, 0x3c, 0x8a, 0x0a,
+ 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
+ 0xe3, 0xfe, 0x00, 0xcc,
+ 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
+ 0x0e, 0xf2, 0x01, 0x6f,
+ 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
+ 0xf6, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
+ 0x15, 0x00, 0x59, 0x76,
+ 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
+ 0x11, 0x2d, 0x01, 0x6f,
+ 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
+ 0xc8, 0xfe, 0x48, 0x55,
+ 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
+ 0x99, 0x01, 0x0e, 0xf0,
+ 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
+ 0x75, 0x03, 0x0a, 0x42,
+ 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
+ 0x0e, 0x73, 0x75, 0x03,
+ 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
+ 0xfe, 0x3a, 0x45, 0x5b,
+ 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
+ 0xfe, 0x02, 0xe6, 0x1b,
+ 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
+ 0xfe, 0x94, 0x00, 0xfe,
+ 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
+ 0xe6, 0x2c, 0xfe, 0x4e,
+ 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
+ 0x03, 0x07, 0x7a, 0xfe,
+ 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+ 0x07, 0x1b, 0xfe, 0x5a,
+ 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
+ 0x24, 0x2c, 0xdc, 0x07,
+ 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
+ 0x9f, 0xad, 0x03, 0x14,
+ 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
+ 0x03, 0x25, 0xfe, 0xca,
+ 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
+ 0x00, 0x00,
};
-STATIC unsigned short _adv_asc3550_size =
- sizeof(_adv_asc3550_buf); /* 0x13AD */
-STATIC ADV_DCNT _adv_asc3550_chksum =
- 0x04D52DDDUL; /* Expanded little-endian checksum. */
+static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
+static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
/* Microcode buffer is kept after initialization for error recovery. */
-STATIC unsigned char _adv_asc38C0800_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4, 0x01, 0x00, 0x48, 0xe4,
- 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6,
- 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
- 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0, 0x18, 0xf4, 0x08, 0x00,
- 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0,
- 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
- 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13, 0xba, 0x13, 0x18, 0x40,
- 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01,
- 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
- 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12, 0x08, 0x12, 0x02, 0x4a,
- 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa,
- 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
- 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d, 0x06, 0x13, 0x4c, 0x1c,
- 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00,
- 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
- 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa, 0x05, 0x00, 0x34, 0x00,
- 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f,
- 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
- 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0,
- 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00,
- 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
- 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13, 0x12, 0x13, 0x24, 0x14,
- 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44,
- 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
- 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0, 0x04, 0xf8,
- 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00,
- 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
- 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08, 0x68, 0x08, 0x69, 0x08,
- 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10,
- 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
- 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18, 0xca, 0x18, 0xe6, 0x19,
- 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe,
- 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xd6,
- 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d, 0x02, 0xfe, 0xc8, 0x0d,
- 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6,
- 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
- 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02, 0xfe, 0x46, 0xf0, 0xfe,
- 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44,
- 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
- 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9,
- 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8,
- 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
- 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x18, 0x06,
- 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe,
- 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
- 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe, 0x69, 0x10, 0x18, 0x06,
- 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe,
- 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
- 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
- 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
- 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x40, 0x1c, 0x1c,
- 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0,
- 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
- 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13, 0x21, 0x22, 0xa3, 0xb7,
- 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9,
- 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
- 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe, 0x06, 0xf0, 0xfe, 0xc8,
- 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe,
- 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
- 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x74, 0x01, 0xaf, 0x8c,
- 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79,
- 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
- 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d, 0xfe, 0x3c, 0x04, 0x3b,
- 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b,
- 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
- 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0x4f, 0x79, 0x2a,
- 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32,
- 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
- 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x08, 0x13, 0x32, 0x07,
- 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d,
- 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
- 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36, 0x02, 0x2b, 0xfe, 0x42,
- 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe,
- 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
- 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28, 0x17, 0xfe, 0x90, 0x05,
- 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe,
- 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
- 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0x12, 0xfe, 0xe3, 0x00,
- 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25,
- 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
- 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2, 0x08, 0x53, 0x05, 0xcb,
- 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22,
- 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
- 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb, 0x03, 0x5c, 0x28, 0xfe,
- 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02,
- 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
- 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62, 0x12, 0x03, 0x45, 0x28,
- 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc,
- 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
- 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01, 0xfe, 0xcc, 0x15, 0x1d,
- 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45,
- 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
- 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07, 0xfe, 0x06, 0xf0, 0xfe,
- 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b,
- 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
- 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38, 0x12, 0x08, 0x05, 0x1a,
- 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
- 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
- 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b, 0xfe, 0x09, 0x6f, 0xba,
- 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c,
- 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
- 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07,
- 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
- 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b, 0x37, 0x01, 0xb3, 0xb8,
- 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51,
- 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
- 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d, 0x14, 0x3e, 0xfe, 0x4a,
- 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14,
- 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
- 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f,
- 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c,
- 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
- 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe, 0x9a, 0x08, 0xc6, 0xfe,
- 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24,
- 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
- 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e, 0x1c, 0x02, 0xfe, 0x18,
- 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa,
- 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
- 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18, 0xfe, 0xf1, 0x18, 0xfe,
- 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95,
- 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
- 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18, 0x0b, 0xb6, 0xfe, 0xbf,
- 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2,
- 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
- 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15, 0x9d, 0x01, 0x36, 0x10,
- 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19,
- 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
- 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0x08, 0x05,
- 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c,
- 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
- 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18, 0x8f, 0xfe, 0xe3, 0x54,
- 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b,
- 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
- 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00, 0xad, 0xfe, 0x01, 0x59,
- 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3,
- 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
- 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63, 0x02, 0x4a, 0x08, 0x05,
- 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1,
- 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
- 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29, 0x61, 0x0c, 0x7f, 0x14,
- 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c,
- 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
- 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40, 0xe4, 0x08, 0x05, 0x1f,
- 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f,
- 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
- 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19, 0x81, 0x50, 0xfe, 0x10,
- 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6,
- 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
- 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7, 0x08, 0x05, 0x0a, 0xfe,
- 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e,
- 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
- 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe, 0x00, 0xff, 0x35, 0xfe,
- 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03,
- 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
- 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0,
- 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00,
- 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
- 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea, 0x0b, 0x10, 0x58, 0xfe,
- 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f,
- 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
- 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20, 0x0c, 0x1c, 0x34, 0x94,
- 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10,
- 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
- 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24, 0x33, 0x31, 0xdf, 0xbc,
- 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d,
- 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
- 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x44, 0xfe, 0x28, 0x00,
- 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f,
- 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
- 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xac,
- 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01,
- 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
- 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05, 0x1a, 0xfe, 0x58, 0x12,
- 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe,
- 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
- 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10, 0xfe, 0x13, 0x00, 0xfe,
- 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5,
- 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
- 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0, 0xb4, 0x15, 0xfe, 0x31,
- 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44,
- 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
- 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x44, 0x48,
- 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
- 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0xce, 0x47, 0xfe, 0xad,
- 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13,
- 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
- 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe, 0x3a, 0x01, 0x56, 0xfe,
- 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05,
- 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
- 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13, 0x15, 0x1a, 0x39, 0xa0,
- 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01,
- 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
- 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12, 0x22, 0x9f, 0xb7, 0x13,
- 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9,
- 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
- 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21, 0xfe, 0x00, 0xcc, 0x04,
- 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07,
- 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
- 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x0a, 0xfe, 0x3c, 0x50,
- 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b,
- 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
- 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01,
- 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01,
- 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
- 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00,
-
- 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09,
- 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
- 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc, 0x0f, 0x44, 0x11, 0x0f,
- 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20,
- 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
- 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x04, 0x42,
- 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01,
- 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
- 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45,
- 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09,
- 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d, 0xfe, 0x01, 0xec, 0xa2,
- 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe,
- 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
- 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17, 0xfe, 0x32, 0x12, 0x07,
- 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12,
- 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
- 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d, 0x32, 0x07, 0xa6, 0xfe,
- 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12,
- 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
- 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21, 0x0c, 0x7f, 0x0c, 0x80,
- 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55,
- 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
- 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40, 0x88, 0x9b, 0x2e, 0x9c,
- 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14,
- 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
- 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
- 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40,
- 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
- 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23, 0x72, 0x01, 0xaf, 0x1e,
- 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe,
- 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
- 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31,
- 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d,
- 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
- 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53, 0x05, 0x1f, 0x35, 0xa9,
- 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c,
- 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
- 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x03, 0x5c, 0xc1, 0x0c,
- 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c,
- 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
- 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a, 0xf4, 0x06, 0xea, 0x32,
- 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89,
- 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
- 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0, 0x13, 0x1c, 0xfe, 0xd0,
- 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02,
- 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
- 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04,
- 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52,
- 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
- 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52, 0xfe, 0x00, 0x7d, 0xfe,
- 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f,
- 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
- 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33,
- 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
- 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
- 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c, 0x30, 0xfe, 0x78, 0x10,
- 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00,
- 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
- 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28, 0x10, 0x69, 0x06, 0xfe,
- 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06,
- 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
- 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4, 0x9e, 0xfe, 0xf3, 0x10,
- 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
- 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
- 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d, 0xf4, 0x00, 0xe9, 0x91,
- 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01,
- 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
- 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x19, 0x01, 0x0b,
- 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76,
- 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
- 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01,
- 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00,
- 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
- 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e, 0x07, 0x11, 0xae, 0x09,
- 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80,
- 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
- 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xfe, 0x80, 0x4c,
- 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87,
- 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
- 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4, 0x17, 0xad, 0x9a, 0x1b,
- 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10,
- 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
- 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c,
- 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17,
- 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
- 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x2e, 0x97, 0xfe, 0x5a,
- 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
- 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
- 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0xcb, 0x97, 0xfe, 0x92,
- 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02,
- 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
- 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x9a, 0x5b, 0x41, 0xfe,
- 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd,
- 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
- 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04, 0xfe, 0x7e, 0x18, 0x1e,
- 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10,
- 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
- 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc,
- 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
- 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c, 0xe7, 0x0a, 0x10, 0xfe,
- 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37,
- 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
- 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77, 0x13, 0xa3, 0x04, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8,
- 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
- 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe, 0x1c, 0x19, 0x03, 0xfe,
- 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19,
- 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
- 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe, 0x08, 0x10, 0x03, 0xfe,
- 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7,
- 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
- 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19, 0x04, 0x07, 0x7e, 0xfe,
- 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a,
- 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
- 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59, 0xa9, 0xb8, 0x04, 0x15,
- 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c,
- 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
- 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
+static unsigned char _adv_asc38C0800_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
+ 0x01, 0x00, 0x48, 0xe4,
+ 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
+ 0x1c, 0x0f, 0x00, 0xf6,
+ 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
+ 0x09, 0xe7, 0x55, 0xf0,
+ 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
+ 0x18, 0xf4, 0x08, 0x00,
+ 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
+ 0x86, 0xf0, 0xb1, 0xf0,
+ 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
+ 0x3c, 0x00, 0xbb, 0x00,
+ 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
+ 0xba, 0x13, 0x18, 0x40,
+ 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
+ 0x6e, 0x01, 0x74, 0x01,
+ 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
+ 0xc0, 0x00, 0x01, 0x01,
+ 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
+ 0x08, 0x12, 0x02, 0x4a,
+ 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
+ 0x5d, 0xf0, 0x02, 0xfa,
+ 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
+ 0x68, 0x01, 0x6a, 0x01,
+ 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
+ 0x06, 0x13, 0x4c, 0x1c,
+ 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
+ 0x0f, 0x00, 0x47, 0x00,
+ 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
+ 0x4e, 0x1c, 0x10, 0x44,
+ 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
+ 0x05, 0x00, 0x34, 0x00,
+ 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
+ 0x42, 0x0c, 0x12, 0x0f,
+ 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
+ 0x00, 0x4e, 0x42, 0x54,
+ 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+ 0x59, 0xf0, 0xb8, 0xf0,
+ 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
+ 0x19, 0x00, 0x33, 0x00,
+ 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
+ 0xe7, 0x00, 0xe2, 0x03,
+ 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
+ 0x12, 0x13, 0x24, 0x14,
+ 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
+ 0x36, 0x1c, 0x08, 0x44,
+ 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
+ 0x3a, 0x55, 0x83, 0x55,
+ 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
+ 0x0c, 0xf0, 0x04, 0xf8,
+ 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
+ 0xa8, 0x00, 0xaa, 0x00,
+ 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
+ 0xc4, 0x01, 0xc6, 0x01,
+ 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
+ 0x68, 0x08, 0x69, 0x08,
+ 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
+ 0xed, 0x10, 0xf1, 0x10,
+ 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
+ 0x1e, 0x13, 0x46, 0x14,
+ 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
+ 0xca, 0x18, 0xe6, 0x19,
+ 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
+ 0xf0, 0x2b, 0x02, 0xfe,
+ 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
+ 0xfe, 0x84, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24,
+ 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
+ 0x00, 0x00, 0xff, 0x08,
+ 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
+ 0xff, 0xff, 0xff, 0x11,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xd6,
+ 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
+ 0x0a, 0x42, 0x2c, 0xfe,
+ 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
+ 0xfe, 0xf4, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
+ 0x02, 0xfe, 0xc8, 0x0d,
+ 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
+ 0x1c, 0x03, 0xfe, 0xa6,
+ 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
+ 0xf0, 0xfe, 0x8a, 0x02,
+ 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
+ 0xfe, 0x46, 0xf0, 0xfe,
+ 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
+ 0x48, 0x02, 0xfe, 0x44,
+ 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
+ 0xaa, 0x18, 0x06, 0x14,
+ 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0xe9,
+ 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
+ 0x09, 0x70, 0x01, 0xa8,
+ 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
+ 0x01, 0x87, 0xfe, 0xbd,
+ 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x18, 0x06,
+ 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
+ 0xfe, 0x98, 0x02, 0xfe,
+ 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
+ 0x01, 0xfe, 0x48, 0x10,
+ 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
+ 0x69, 0x10, 0x18, 0x06,
+ 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
+ 0xf6, 0xce, 0x01, 0xfe,
+ 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
+ 0x82, 0x16, 0x02, 0x2b,
+ 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
+ 0xfe, 0x41, 0x58, 0x09,
+ 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
+ 0x82, 0x16, 0x02, 0x2b,
+ 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
+ 0xfe, 0x77, 0x57, 0xfe,
+ 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
+ 0xfe, 0x40, 0x1c, 0x1c,
+ 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
+ 0x03, 0xfe, 0x11, 0xf0,
+ 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
+ 0xfe, 0x11, 0x00, 0x02,
+ 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
+ 0x21, 0x22, 0xa3, 0xb7,
+ 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
+ 0x12, 0xd1, 0x1c, 0xd9,
+ 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
+ 0xfe, 0xe4, 0x00, 0x27,
+ 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
+ 0x06, 0xf0, 0xfe, 0xc8,
+ 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
+ 0x70, 0x28, 0x17, 0xfe,
+ 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
+ 0xf9, 0x2c, 0x99, 0x19,
+ 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
+ 0x74, 0x01, 0xaf, 0x8c,
+ 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
+ 0x8d, 0x51, 0x64, 0x79,
+ 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
+ 0xfe, 0x6a, 0x02, 0x02,
+ 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
+ 0xfe, 0x3c, 0x04, 0x3b,
+ 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
+ 0x00, 0x10, 0x01, 0x0b,
+ 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
+ 0xfe, 0x4c, 0x44, 0xfe,
+ 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
+ 0xda, 0x4f, 0x79, 0x2a,
+ 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
+ 0xfe, 0x2a, 0x13, 0x32,
+ 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
+ 0x54, 0x6b, 0xda, 0xfe,
+ 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+ 0x08, 0x13, 0x32, 0x07,
+ 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
+ 0x08, 0x05, 0x06, 0x4d,
+ 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
+ 0x2d, 0x12, 0xfe, 0xe6,
+ 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
+ 0x02, 0x2b, 0xfe, 0x42,
+ 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
+ 0xfe, 0x87, 0x80, 0xfe,
+ 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
+ 0x07, 0x19, 0xfe, 0x7c,
+ 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
+ 0x17, 0xfe, 0x90, 0x05,
+ 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
+ 0xa0, 0x00, 0x28, 0xfe,
+ 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
+ 0x34, 0xfe, 0x89, 0x48,
+ 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
+ 0x12, 0xfe, 0xe3, 0x00,
+ 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
+ 0x70, 0x05, 0x88, 0x25,
+ 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
+ 0x09, 0x48, 0xff, 0x02,
+ 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
+ 0x08, 0x53, 0x05, 0xcb,
+ 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
+ 0x05, 0x1b, 0xfe, 0x22,
+ 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
+ 0x0d, 0x00, 0x01, 0x36,
+ 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
+ 0x03, 0x5c, 0x28, 0xfe,
+ 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
+ 0x05, 0x1f, 0xfe, 0x02,
+ 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
+ 0x01, 0x4b, 0x12, 0xfe,
+ 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
+ 0x12, 0x03, 0x45, 0x28,
+ 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
+ 0x43, 0x48, 0xc4, 0xcc,
+ 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
+ 0x6e, 0x41, 0x01, 0xb2,
+ 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
+ 0xfe, 0xcc, 0x15, 0x1d,
+ 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
+ 0x45, 0xc1, 0x0c, 0x45,
+ 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
+ 0xe2, 0x00, 0x27, 0xdb,
+ 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
+ 0xfe, 0x06, 0xf0, 0xfe,
+ 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
+ 0x16, 0x19, 0x01, 0x0b,
+ 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
+ 0xfe, 0x99, 0xa4, 0x01,
+ 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
+ 0x12, 0x08, 0x05, 0x1a,
+ 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
+ 0x0b, 0x16, 0x00, 0x01,
+ 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
+ 0xe2, 0x6c, 0x58, 0xbe,
+ 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
+ 0xfe, 0x09, 0x6f, 0xba,
+ 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
+ 0xfe, 0x54, 0x07, 0x1c,
+ 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
+ 0x07, 0x02, 0x24, 0x01,
+ 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
+ 0x37, 0x22, 0x20, 0x07,
+ 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
+ 0xfe, 0x06, 0x10, 0xfe,
+ 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
+ 0x37, 0x01, 0xb3, 0xb8,
+ 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
+ 0x50, 0xfe, 0x44, 0x51,
+ 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
+ 0x14, 0x5f, 0xfe, 0x0c,
+ 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
+ 0x14, 0x3e, 0xfe, 0x4a,
+ 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x0c, 0x60, 0x14,
+ 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
+ 0xfe, 0x44, 0x90, 0xfe,
+ 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+ 0x0c, 0x5e, 0x14, 0x5f,
+ 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
+ 0x14, 0x3c, 0x21, 0x0c,
+ 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
+ 0x27, 0xdd, 0xfe, 0x9e,
+ 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
+ 0x9a, 0x08, 0xc6, 0xfe,
+ 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
+ 0x95, 0x86, 0x02, 0x24,
+ 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
+ 0x06, 0xfe, 0x10, 0x12,
+ 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
+ 0x1c, 0x02, 0xfe, 0x18,
+ 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
+ 0x2c, 0x1c, 0xfe, 0xaa,
+ 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
+ 0xde, 0x09, 0xfe, 0xb7,
+ 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
+ 0xfe, 0xf1, 0x18, 0xfe,
+ 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
+ 0x14, 0x59, 0xfe, 0x95,
+ 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
+ 0xfe, 0xf0, 0x08, 0xb5,
+ 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
+ 0x0b, 0xb6, 0xfe, 0xbf,
+ 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
+ 0x12, 0xc2, 0xfe, 0xd2,
+ 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
+ 0x06, 0x17, 0x85, 0xc5,
+ 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
+ 0x9d, 0x01, 0x36, 0x10,
+ 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
+ 0x98, 0x80, 0xfe, 0x19,
+ 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
+ 0xfe, 0x44, 0x54, 0xbe,
+ 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
+ 0x02, 0x4a, 0x08, 0x05,
+ 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
+ 0x9c, 0x3c, 0xfe, 0x6c,
+ 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
+ 0x3b, 0x40, 0x03, 0x49,
+ 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
+ 0x8f, 0xfe, 0xe3, 0x54,
+ 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
+ 0xda, 0x09, 0xfe, 0x8b,
+ 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
+ 0x0a, 0x3a, 0x49, 0x3b,
+ 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
+ 0xad, 0xfe, 0x01, 0x59,
+ 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
+ 0x49, 0x8f, 0xfe, 0xe3,
+ 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
+ 0x4a, 0x3a, 0x49, 0x3b,
+ 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
+ 0x02, 0x4a, 0x08, 0x05,
+ 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
+ 0xb7, 0xfe, 0x03, 0xa1,
+ 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
+ 0xfe, 0x86, 0x91, 0x6a,
+ 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
+ 0x61, 0x0c, 0x7f, 0x14,
+ 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
+ 0x9b, 0x2e, 0x9c, 0x3c,
+ 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
+ 0xfa, 0x3c, 0x01, 0xef,
+ 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
+ 0xe4, 0x08, 0x05, 0x1f,
+ 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
+ 0x03, 0x5e, 0x29, 0x5f,
+ 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
+ 0xf4, 0x09, 0x08, 0x05,
+ 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
+ 0x81, 0x50, 0xfe, 0x10,
+ 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
+ 0x08, 0x09, 0x12, 0xa6,
+ 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
+ 0x08, 0x09, 0xfe, 0x0c,
+ 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
+ 0x08, 0x05, 0x0a, 0xfe,
+ 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
+ 0xf0, 0xe2, 0x15, 0x7e,
+ 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
+ 0x57, 0x3d, 0xfe, 0xed,
+ 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
+ 0x00, 0xff, 0x35, 0xfe,
+ 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
+ 0x1e, 0x19, 0x8a, 0x03,
+ 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
+ 0xfe, 0xd1, 0xf0, 0xfe,
+ 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
+ 0x10, 0xfe, 0xce, 0xf0,
+ 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
+ 0x10, 0xfe, 0x22, 0x00,
+ 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
+ 0x02, 0x65, 0xfe, 0xd0,
+ 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
+ 0x0b, 0x10, 0x58, 0xfe,
+ 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
+ 0x12, 0x00, 0x2c, 0x0f,
+ 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
+ 0x0c, 0xbc, 0x17, 0x34,
+ 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
+ 0x0c, 0x1c, 0x34, 0x94,
+ 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
+ 0x4b, 0xfe, 0xdb, 0x10,
+ 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
+ 0x89, 0xf0, 0x24, 0x33,
+ 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
+ 0x33, 0x31, 0xdf, 0xbc,
+ 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
+ 0x17, 0xfe, 0x2c, 0x0d,
+ 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
+ 0x12, 0x55, 0xfe, 0x28,
+ 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
+ 0x44, 0xfe, 0x28, 0x00,
+ 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
+ 0x0f, 0x64, 0x12, 0x2f,
+ 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
+ 0x0a, 0xfe, 0xb4, 0x10,
+ 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
+ 0xfe, 0x34, 0x46, 0xac,
+ 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
+ 0x37, 0x01, 0xf5, 0x01,
+ 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
+ 0xfe, 0x2e, 0x03, 0x08,
+ 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
+ 0x1a, 0xfe, 0x58, 0x12,
+ 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
+ 0xfe, 0x50, 0x0d, 0xfe,
+ 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
+ 0xfe, 0xa9, 0x10, 0x10,
+ 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
+ 0xfe, 0x13, 0x00, 0xfe,
+ 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
+ 0x24, 0x00, 0x8c, 0xb5,
+ 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
+ 0xfe, 0x9d, 0x41, 0xfe,
+ 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
+ 0xb4, 0x15, 0xfe, 0x31,
+ 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
+ 0xec, 0xd0, 0xfc, 0x44,
+ 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
+ 0x4b, 0x91, 0xfe, 0x75,
+ 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
+ 0x0e, 0xfe, 0x44, 0x48,
+ 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
+ 0xfe, 0x41, 0x58, 0x09,
+ 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
+ 0x2e, 0x03, 0x09, 0x5d,
+ 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
+ 0xce, 0x47, 0xfe, 0xad,
+ 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
+ 0x59, 0x13, 0x9f, 0x13,
+ 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
+ 0xe0, 0x0e, 0x0f, 0x06,
+ 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
+ 0x3a, 0x01, 0x56, 0xfe,
+ 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
+ 0x20, 0x4f, 0xfe, 0x05,
+ 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
+ 0x48, 0xf4, 0x0d, 0xfe,
+ 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
+ 0x15, 0x1a, 0x39, 0xa0,
+ 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
+ 0x0c, 0xfe, 0x60, 0x01,
+ 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
+ 0x06, 0x13, 0x2f, 0x12,
+ 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
+ 0x22, 0x9f, 0xb7, 0x13,
+ 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
+ 0xa0, 0xb4, 0xfe, 0xd9,
+ 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
+ 0xc3, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
+ 0xfe, 0x00, 0xcc, 0x04,
+ 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
+ 0xfe, 0x1c, 0x80, 0x07,
+ 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
+ 0xfe, 0x0c, 0x90, 0xfe,
+ 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+ 0x0a, 0xfe, 0x3c, 0x50,
+ 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
+ 0x16, 0x08, 0x05, 0x1b,
+ 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
+ 0xfe, 0x2c, 0x13, 0x01,
+ 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+ 0x0c, 0xfe, 0x64, 0x01,
+ 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
+ 0x80, 0x8d, 0xfe, 0x01,
+ 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
+ 0x22, 0x20, 0xfb, 0x79,
+ 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+ 0x03, 0xfe, 0xae, 0x00,
+
+ 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
+ 0xb2, 0x00, 0xfe, 0x09,
+ 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
+ 0x45, 0x0f, 0x46, 0x52,
+ 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
+ 0x0f, 0x44, 0x11, 0x0f,
+ 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
+ 0x25, 0x11, 0x13, 0x20,
+ 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x04, 0x42,
+ 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
+ 0xf5, 0x13, 0x04, 0x01,
+ 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
+ 0x13, 0x32, 0x07, 0x2f,
+ 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
+ 0x41, 0x48, 0xfe, 0x45,
+ 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
+ 0x07, 0x11, 0xac, 0x09,
+ 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
+ 0x82, 0x4e, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
+ 0xfe, 0x01, 0xec, 0xa2,
+ 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
+ 0x2a, 0x01, 0xe3, 0xfe,
+ 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
+ 0xfe, 0x48, 0x12, 0x07,
+ 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
+ 0xfe, 0x32, 0x12, 0x07,
+ 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
+ 0x1f, 0xfe, 0x12, 0x12,
+ 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
+ 0x94, 0x4b, 0x04, 0x2d,
+ 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
+ 0x32, 0x07, 0xa6, 0xfe,
+ 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
+ 0x5a, 0xfe, 0x72, 0x12,
+ 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
+ 0xfe, 0x26, 0x13, 0x03,
+ 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
+ 0x0c, 0x7f, 0x0c, 0x80,
+ 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
+ 0x3c, 0xfe, 0x04, 0x55,
+ 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
+ 0x91, 0x10, 0x03, 0x3f,
+ 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
+ 0x88, 0x9b, 0x2e, 0x9c,
+ 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
+ 0x56, 0x0c, 0x5e, 0x14,
+ 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
+ 0x03, 0x60, 0x29, 0x61,
+ 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
+ 0x50, 0xfe, 0xc6, 0x50,
+ 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
+ 0x29, 0x3e, 0xfe, 0x40,
+ 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
+ 0x2d, 0x01, 0x0b, 0x1d,
+ 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
+ 0x72, 0x01, 0xaf, 0x1e,
+ 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
+ 0x0a, 0x55, 0x35, 0xfe,
+ 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
+ 0x02, 0x72, 0xfe, 0x19,
+ 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
+ 0x1d, 0xe8, 0x33, 0x31,
+ 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
+ 0x0b, 0x1c, 0x34, 0x1d,
+ 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
+ 0x33, 0x31, 0xfe, 0xe8,
+ 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
+ 0x05, 0x1f, 0x35, 0xa9,
+ 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
+ 0x14, 0x01, 0xaf, 0x8c,
+ 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
+ 0x03, 0x45, 0x28, 0x35,
+ 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
+ 0x03, 0x5c, 0xc1, 0x0c,
+ 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
+ 0x89, 0x01, 0x0b, 0x1c,
+ 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
+ 0xfe, 0x42, 0x58, 0xf1,
+ 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
+ 0xf4, 0x06, 0xea, 0x32,
+ 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
+ 0x01, 0x0b, 0x26, 0x89,
+ 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
+ 0x26, 0xfe, 0xd4, 0x13,
+ 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
+ 0x13, 0x1c, 0xfe, 0xd0,
+ 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
+ 0x0f, 0x71, 0xff, 0x02,
+ 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
+ 0x00, 0x5c, 0x04, 0x0f,
+ 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
+ 0xfe, 0x00, 0x5c, 0x04,
+ 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
+ 0x02, 0x00, 0x57, 0x52,
+ 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
+ 0x87, 0x04, 0xfe, 0x03,
+ 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
+ 0xfe, 0x00, 0x7d, 0xfe,
+ 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
+ 0x14, 0x5f, 0x57, 0x3f,
+ 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
+ 0x5a, 0x8d, 0x04, 0x01,
+ 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
+ 0xfe, 0x96, 0x15, 0x33,
+ 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
+ 0x0a, 0xfe, 0xc1, 0x59,
+ 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
+ 0x21, 0x69, 0x1a, 0xee,
+ 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
+ 0x30, 0xfe, 0x78, 0x10,
+ 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
+ 0x98, 0xfe, 0x30, 0x00,
+ 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
+ 0x98, 0xfe, 0x64, 0x00,
+ 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
+ 0x10, 0x69, 0x06, 0xfe,
+ 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
+ 0x18, 0x59, 0x0f, 0x06,
+ 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
+ 0x43, 0xf4, 0x9f, 0xfe,
+ 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
+ 0x9e, 0xfe, 0xf3, 0x10,
+ 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
+ 0x17, 0xfe, 0x4d, 0xe4,
+ 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
+ 0x17, 0xfe, 0x4d, 0xe4,
+ 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
+ 0xf4, 0x00, 0xe9, 0x91,
+ 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
+ 0x04, 0x16, 0x06, 0x01,
+ 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
+ 0x0b, 0x26, 0xf3, 0x76,
+ 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+ 0x16, 0x19, 0x01, 0x0b,
+ 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
+ 0x0b, 0x26, 0xb1, 0x76,
+ 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
+ 0xfe, 0x48, 0x13, 0xb8,
+ 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
+ 0xec, 0xfe, 0x27, 0x01,
+ 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
+ 0x07, 0xfe, 0xe3, 0x00,
+ 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
+ 0x22, 0xd4, 0x07, 0x06,
+ 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
+ 0x07, 0x11, 0xae, 0x09,
+ 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
+ 0x0e, 0x8e, 0xfe, 0x80,
+ 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
+ 0x09, 0x48, 0x01, 0x0e,
+ 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
+ 0x80, 0xfe, 0x80, 0x4c,
+ 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
+ 0x09, 0x5d, 0x01, 0x87,
+ 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
+ 0x19, 0xde, 0xfe, 0x24,
+ 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
+ 0x17, 0xad, 0x9a, 0x1b,
+ 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
+ 0x16, 0xfe, 0xda, 0x10,
+ 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
+ 0x18, 0x58, 0x03, 0xfe,
+ 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
+ 0xf4, 0x06, 0xfe, 0x3c,
+ 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
+ 0x97, 0xfe, 0x38, 0x17,
+ 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
+ 0x10, 0x18, 0x11, 0x75,
+ 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
+ 0x2e, 0x97, 0xfe, 0x5a,
+ 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
+ 0xfe, 0x98, 0xe7, 0x00,
+ 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
+ 0xfe, 0x30, 0xbc, 0xfe,
+ 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+ 0xcb, 0x97, 0xfe, 0x92,
+ 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
+ 0x42, 0x10, 0xfe, 0x02,
+ 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
+ 0x03, 0xa1, 0xfe, 0x1d,
+ 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
+ 0x9a, 0x5b, 0x41, 0xfe,
+ 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
+ 0x11, 0x12, 0xfe, 0xdd,
+ 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
+ 0x17, 0x15, 0x06, 0x39,
+ 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
+ 0xfe, 0x7e, 0x18, 0x1e,
+ 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
+ 0x12, 0xfe, 0xe1, 0x10,
+ 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
+ 0x13, 0x42, 0x92, 0x09,
+ 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+ 0xf0, 0xfe, 0x00, 0xcc,
+ 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
+ 0x0e, 0xfe, 0x80, 0x4c,
+ 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
+ 0x24, 0x12, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
+ 0xe7, 0x0a, 0x10, 0xfe,
+ 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
+ 0x08, 0x54, 0x1b, 0x37,
+ 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
+ 0x90, 0x3a, 0xce, 0x3b,
+ 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
+ 0x13, 0xa3, 0x04, 0x09,
+ 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
+ 0x44, 0x17, 0xfe, 0xe8,
+ 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
+ 0x5d, 0x01, 0xa8, 0x09,
+ 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
+ 0x1c, 0x19, 0x03, 0xfe,
+ 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
+ 0x6b, 0xfe, 0x2e, 0x19,
+ 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
+ 0xfe, 0x0b, 0x00, 0x6b,
+ 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
+ 0x08, 0x10, 0x03, 0xfe,
+ 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
+ 0x04, 0x68, 0x54, 0xe7,
+ 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
+ 0x1a, 0xf4, 0xfe, 0x00,
+ 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
+ 0x04, 0x07, 0x7e, 0xfe,
+ 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+ 0x07, 0x1a, 0xfe, 0x5a,
+ 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
+ 0x25, 0x6d, 0xe5, 0x07,
+ 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
+ 0xa9, 0xb8, 0x04, 0x15,
+ 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
+ 0x40, 0x5c, 0x04, 0x1c,
+ 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
+ 0xf7, 0xfe, 0x82, 0xf0,
+ 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
};
-STATIC unsigned short _adv_asc38C0800_size =
- sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
-STATIC ADV_DCNT _adv_asc38C0800_chksum =
- 0x050D3FD8UL; /* Expanded little-endian checksum. */
+static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
+static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
/* Microcode buffer is kept after initialization for error recovery. */
-STATIC unsigned char _adv_asc38C1600_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0, 0x18, 0xe4, 0x01, 0x00,
- 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f,
- 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
- 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00, 0x98, 0x57, 0x01, 0xe6,
- 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0,
- 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
- 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01, 0x06, 0x13, 0x0c, 0x1c,
- 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80,
- 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
- 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x04, 0x13, 0xbb, 0x55,
- 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00,
- 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
- 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
- 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01,
- 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
- 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x06, 0x00,
- 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c,
- 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
- 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00,
- 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09,
- 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
- 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00,
- 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
- 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x42, 0x1d, 0x08, 0x44,
- 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59,
- 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
- 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0xa8, 0x00, 0xaa, 0x00,
- 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01,
- 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
- 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10, 0xf3, 0x10, 0x06, 0x12,
- 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe,
- 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00, 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00, 0xfe, 0x04, 0xf7, 0xe8,
- 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d, 0x05, 0xfe, 0x08, 0x0f,
- 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe,
- 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
- 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8, 0x02, 0xfe, 0x46, 0xf0,
- 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe,
- 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
- 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02, 0x1c, 0xf5, 0xfe, 0x1e,
- 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01,
- 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
- 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe, 0x58, 0x1c, 0x1c,
- 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02,
- 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
- 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09, 0x1a, 0x31, 0xfe, 0x69,
- 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c,
- 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
- 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00,
- 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54,
- 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
- 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0, 0xfe, 0xe4, 0x01, 0xfe,
- 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66,
- 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
- 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05, 0x70, 0x37, 0xfe, 0x48,
- 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20,
- 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
- 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32, 0x15, 0xfe, 0xe4, 0x00,
- 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe,
- 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
- 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xfe, 0x46, 0x1c,
- 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75,
- 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
- 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02,
- 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04,
- 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
- 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25, 0xee, 0xfe, 0x4c, 0x44,
- 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d,
- 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
- 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10, 0x13, 0x34, 0xfe, 0x4c,
- 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06,
- 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
- 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f, 0xfe, 0xa4, 0x0e, 0x05,
- 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b,
- 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
- 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04, 0xfe, 0x87, 0x83, 0xfe,
- 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20,
- 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
- 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda, 0x05, 0xd0, 0x54, 0x01,
- 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff,
- 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
- 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01, 0x38, 0xfe, 0x4a, 0xf0,
- 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e,
- 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
- 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe, 0x1c, 0x00, 0x4d, 0x01,
- 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12,
- 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
- 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13, 0x03, 0xb6, 0x1e, 0xfe,
- 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a,
- 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
- 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x03, 0x9a, 0x1e, 0xfe,
- 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06,
- 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
- 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17, 0xfe, 0xea, 0x06, 0x01,
- 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15,
- 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
- 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a, 0x1e, 0xfe, 0x1a, 0x12,
- 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80,
- 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
- 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x17, 0xfe,
- 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01,
- 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
- 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0x9c, 0x32, 0x5f,
- 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
- 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
- 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14,
- 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe,
- 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
- 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
- 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe,
- 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
- 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x53, 0x63, 0x4e,
- 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0,
- 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
- 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe, 0x1e, 0xfe, 0x99, 0x58,
- 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c,
- 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
- 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40, 0x01, 0x0c, 0x61, 0x65,
- 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50,
- 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
- 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e, 0x01, 0xfe, 0xfe, 0x1e,
- 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06,
- 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
- 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04, 0xfe, 0x9f, 0x83, 0x33,
- 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6,
- 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
- 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90, 0x04, 0xfe, 0xc0, 0x93,
- 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c,
- 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
- 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
- 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a,
- 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
- 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07, 0xfe, 0x14, 0x12, 0x01,
- 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe,
- 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
- 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe, 0x92, 0x10, 0xc4, 0xf6,
- 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b,
- 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
- 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07, 0x1b, 0xbf, 0xd4, 0x5b,
- 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f,
- 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
- 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78, 0x0f, 0x4d, 0x01, 0xfe,
- 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2,
- 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
- 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe, 0x83, 0x83, 0xfe, 0xc9,
- 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84,
- 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
- 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0x10,
- 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64,
- 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
- 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97, 0x10, 0x98, 0x91, 0x6c,
- 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01,
- 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
- 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x01, 0x0c,
- 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04,
- 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
- 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb, 0x01, 0x0c, 0x06, 0x0d,
- 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d,
- 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
- 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
- 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00,
- 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
- 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe, 0x76, 0x10, 0xac, 0xfe,
- 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe,
- 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
- 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2, 0x0c, 0xfe, 0x3e, 0x10,
- 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe,
- 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
- 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3, 0xfe, 0xcc, 0xf0, 0xef,
- 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
- 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
- 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32, 0x2f, 0xfe, 0x3e, 0x0d,
- 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f,
- 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
- 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8, 0x9c, 0x2f, 0xfe, 0x8c,
- 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70,
- 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
- 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b, 0xfe, 0xda, 0x0e, 0x0a,
- 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4,
- 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
- 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe, 0xcc, 0x10, 0x01, 0xa7,
- 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe,
- 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
- 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x40, 0x15,
- 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01,
- 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
- 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe,
- 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44,
- 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
- 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19, 0xfe, 0x41, 0x00, 0xa2,
- 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04,
- 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
- 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01, 0xfe, 0xd4, 0x11, 0x05,
- 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51,
- 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
- 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01, 0x0c, 0x06, 0x28, 0xfe,
- 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe,
- 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
- 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x05,
- 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c,
- 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
- 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe, 0xf0, 0x1a, 0x03, 0xfe,
- 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00,
- 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
- 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02, 0xea, 0xe7, 0x53, 0x92,
- 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23,
- 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
- 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02, 0x26, 0x02, 0x21, 0x96,
- 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10,
- 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
- 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe, 0x00, 0xcc, 0x02, 0xfe,
- 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80,
- 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
- 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe, 0x1d, 0x80, 0x04, 0xfe,
- 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14,
- 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
- 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09, 0x56, 0xfb, 0x01, 0xfe,
- 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15,
- 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
- 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe, 0x96, 0x90, 0x04, 0xfe,
- 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06,
- 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
- 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40, 0x21, 0x2c, 0xfe, 0x00,
- 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe,
- 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
- 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10, 0x66, 0x10, 0x55, 0x10,
- 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88,
- 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
- 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c,
- 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe,
- 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
- 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01, 0xa7, 0x90, 0x34, 0x60,
- 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34,
- 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
- 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a,
- 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe,
- 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
- 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01, 0xf4, 0xfe, 0xdd, 0x10,
- 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe,
- 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
- 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09, 0x24, 0xfe, 0x12, 0x12,
- 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32,
- 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
- 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80, 0x13, 0x01, 0x0c, 0x06,
- 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe,
- 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
- 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49, 0x88, 0x20, 0x6e, 0x01,
- 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa,
- 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
- 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe, 0xe5,
- 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01,
- 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
- 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x68, 0x3b,
- 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2,
- 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
- 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01, 0xa6, 0x23, 0x3f, 0x1b,
- 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31,
- 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
- 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0,
- 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05,
- 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
- 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03, 0xb6, 0x1e, 0x83, 0x01,
- 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01,
- 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
- 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e, 0x05, 0x72, 0xfe, 0xc0,
- 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17,
- 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
- 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe, 0xe8, 0x14, 0x01, 0xa6,
- 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43,
- 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
- 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd, 0x09,
- 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8,
- 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
- 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0xc0, 0x19, 0x05,
- 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26,
- 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
- 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0xfe, 0xff,
- 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad,
- 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
- 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e, 0x02, 0x13, 0x58, 0xff,
- 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01,
- 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
- 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07, 0x7c, 0x3a, 0x0b, 0x0e,
- 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00,
- 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
- 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77, 0x02, 0x01, 0xc6, 0xfe,
- 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08,
- 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
- 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12, 0x48, 0xfe, 0x08, 0x17,
- 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07,
- 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
- 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x1c, 0x63, 0x13,
- 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80,
- 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
- 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8, 0x00, 0x1c, 0x95, 0x13,
- 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96,
- 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
- 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x49,
- 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe,
- 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
- 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xbe, 0xfe, 0x03,
- 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16,
- 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
- 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27,
- 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24,
- 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
- 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10, 0xfe, 0x40, 0x5a, 0x23,
- 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa,
- 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
- 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe, 0x43, 0x48, 0x2d, 0x93,
- 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4,
- 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
- 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa, 0x18, 0x45, 0xfe, 0x1c,
- 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4,
- 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
- 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe, 0x7e, 0x01, 0xfe, 0xc8,
- 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01,
- 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
- 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14,
- 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07,
- 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
- 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01, 0x08, 0x02, 0x50, 0x02,
- 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08,
- 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
- 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17, 0x74, 0x5f, 0xcc, 0x01,
- 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00,
- 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
- 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13, 0x16, 0xfe, 0x64, 0x1a,
- 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02,
- 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
- 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa, 0xfe, 0x80, 0xe7, 0x1a,
- 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18,
- 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
- 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x0a,
- 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
- 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
- 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe, 0xf4, 0x1a, 0xfe, 0xfa,
- 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03,
- 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
- 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x24, 0xb1, 0xfe,
- 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c,
- 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
- 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe, 0xaf, 0x19, 0xfe, 0x98,
- 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f,
- 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
- 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a, 0x7c, 0x12, 0xfe, 0x0f,
- 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b,
- 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
- 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee, 0x1b, 0xfe, 0x36, 0x14,
- 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a,
- 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
- 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe, 0x39, 0xf0, 0x75, 0x26,
- 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe,
- 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
- 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe,
- 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb,
- 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
- 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14, 0x56,
- 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15,
- 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
- 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90,
- 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20,
- 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
- 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09, 0x1a, 0xa4, 0x0a, 0x67,
- 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52,
- 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
- 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10, 0xfe, 0x4e, 0xe4, 0xfe,
- 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03,
- 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
- 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe,
- 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a,
- 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
- 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe, 0x1a, 0x10, 0x09, 0x0d,
- 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42,
- 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
- 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e, 0xfe, 0x82, 0xf0, 0xfe,
- 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18,
- 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
- 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86, 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04,
- 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
- 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04, 0xfe, 0x99, 0x83, 0xfe,
- 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47,
- 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x08, 0x90, 0x04,
- 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79,
- 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x3c, 0x90, 0x04,
- 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83,
- 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
+static unsigned char _adv_asc38C1600_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
+ 0x18, 0xe4, 0x01, 0x00,
+ 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
+ 0x07, 0x17, 0xc0, 0x5f,
+ 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
+ 0x85, 0xf0, 0x86, 0xf0,
+ 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
+ 0x98, 0x57, 0x01, 0xe6,
+ 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
+ 0x38, 0x54, 0x32, 0xf0,
+ 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
+ 0x00, 0xe6, 0xb1, 0xf0,
+ 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
+ 0x06, 0x13, 0x0c, 0x1c,
+ 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
+ 0xb9, 0x54, 0x00, 0x80,
+ 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
+ 0x03, 0xe6, 0x01, 0xea,
+ 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+ 0x04, 0x13, 0xbb, 0x55,
+ 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
+ 0xbb, 0x00, 0xc0, 0x00,
+ 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
+ 0x4c, 0x1c, 0x4e, 0x1c,
+ 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
+ 0x24, 0x01, 0x3c, 0x01,
+ 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
+ 0x78, 0x01, 0x7c, 0x01,
+ 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
+ 0x6e, 0x1e, 0x02, 0x48,
+ 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
+ 0x03, 0xfc, 0x06, 0x00,
+ 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
+ 0x30, 0x1c, 0x38, 0x1c,
+ 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
+ 0x5d, 0xf0, 0xa7, 0xf0,
+ 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
+ 0x33, 0x00, 0x34, 0x00,
+ 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
+ 0x79, 0x01, 0x3c, 0x09,
+ 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
+ 0x40, 0x16, 0x50, 0x16,
+ 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
+ 0x05, 0xf0, 0x09, 0xf0,
+ 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
+ 0x9c, 0x00, 0xa4, 0x00,
+ 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
+ 0xe9, 0x09, 0x5c, 0x0c,
+ 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
+ 0x42, 0x1d, 0x08, 0x44,
+ 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
+ 0x83, 0x55, 0x83, 0x59,
+ 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
+ 0x4b, 0xf4, 0x04, 0xf8,
+ 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
+ 0xa8, 0x00, 0xaa, 0x00,
+ 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
+ 0x7a, 0x01, 0x82, 0x01,
+ 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
+ 0x68, 0x08, 0x10, 0x0d,
+ 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
+ 0xf3, 0x10, 0x06, 0x12,
+ 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
+ 0xf0, 0x35, 0x05, 0xfe,
+ 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
+ 0xfe, 0x88, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24,
+ 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
+ 0x00, 0x00, 0xff, 0x08,
+ 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
+ 0xff, 0xff, 0xff, 0x13,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xe8,
+ 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
+ 0x0d, 0x51, 0x37, 0xfe,
+ 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
+ 0xfe, 0xf8, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
+ 0x05, 0xfe, 0x08, 0x0f,
+ 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
+ 0x28, 0x1c, 0x03, 0xfe,
+ 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
+ 0x48, 0xf0, 0xfe, 0x90,
+ 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
+ 0x02, 0xfe, 0x46, 0xf0,
+ 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
+ 0xfe, 0x4e, 0x02, 0xfe,
+ 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
+ 0x0d, 0xa2, 0x1c, 0x07,
+ 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
+ 0x1c, 0xf5, 0xfe, 0x1e,
+ 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
+ 0xde, 0x0a, 0x81, 0x01,
+ 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
+ 0x81, 0x01, 0x5c, 0xfe,
+ 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
+ 0xfe, 0x58, 0x1c, 0x1c,
+ 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
+ 0x2b, 0xfe, 0x9e, 0x02,
+ 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
+ 0x00, 0x47, 0xb8, 0x01,
+ 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
+ 0x1a, 0x31, 0xfe, 0x69,
+ 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
+ 0x1e, 0x1e, 0x20, 0x2c,
+ 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
+ 0x44, 0x15, 0x56, 0x51,
+ 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
+ 0x01, 0x18, 0x09, 0x00,
+ 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
+ 0x18, 0xfe, 0xc8, 0x54,
+ 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
+ 0xfe, 0x02, 0xe8, 0x30,
+ 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
+ 0xfe, 0xe4, 0x01, 0xfe,
+ 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
+ 0x26, 0xf0, 0xfe, 0x66,
+ 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
+ 0xef, 0x10, 0xfe, 0x9f,
+ 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
+ 0x70, 0x37, 0xfe, 0x48,
+ 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
+ 0x21, 0xb9, 0xc7, 0x20,
+ 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
+ 0xe1, 0x2a, 0xeb, 0xfe,
+ 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
+ 0x15, 0xfe, 0xe4, 0x00,
+ 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
+ 0xfe, 0x06, 0xf0, 0xfe,
+ 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
+ 0x03, 0x81, 0x1e, 0x1b,
+ 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
+ 0xea, 0xfe, 0x46, 0x1c,
+ 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
+ 0xfe, 0x48, 0x1c, 0x75,
+ 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
+ 0xe1, 0x01, 0x18, 0x77,
+ 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
+ 0x8f, 0xfe, 0x70, 0x02,
+ 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
+ 0x16, 0xfe, 0x4a, 0x04,
+ 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
+ 0x02, 0x00, 0x10, 0x01,
+ 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
+ 0xee, 0xfe, 0x4c, 0x44,
+ 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
+ 0x7b, 0xec, 0x60, 0x8d,
+ 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
+ 0x0c, 0x06, 0x28, 0xfe,
+ 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
+ 0x13, 0x34, 0xfe, 0x4c,
+ 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
+ 0x13, 0x01, 0x0c, 0x06,
+ 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
+ 0x28, 0xf9, 0x1f, 0x7f,
+ 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
+ 0xfe, 0xa4, 0x0e, 0x05,
+ 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
+ 0x9c, 0x93, 0x3a, 0x0b,
+ 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
+ 0x7d, 0x1d, 0xfe, 0x46,
+ 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
+ 0xfe, 0x87, 0x83, 0xfe,
+ 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
+ 0x13, 0x0f, 0xfe, 0x20,
+ 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
+ 0x12, 0x01, 0x38, 0x06,
+ 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
+ 0x05, 0xd0, 0x54, 0x01,
+ 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
+ 0x50, 0x12, 0x5e, 0xff,
+ 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
+ 0x00, 0x10, 0x2f, 0xfe,
+ 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
+ 0x38, 0xfe, 0x4a, 0xf0,
+ 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
+ 0x21, 0x00, 0xf1, 0x2e,
+ 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
+ 0x10, 0x2f, 0xfe, 0xd0,
+ 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
+ 0x1c, 0x00, 0x4d, 0x01,
+ 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
+ 0x28, 0xfe, 0x24, 0x12,
+ 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
+ 0x0d, 0x00, 0x01, 0x42,
+ 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
+ 0x03, 0xb6, 0x1e, 0xfe,
+ 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
+ 0xfe, 0x72, 0x06, 0x0a,
+ 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
+ 0x19, 0x16, 0xfe, 0x68,
+ 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
+ 0x03, 0x9a, 0x1e, 0xfe,
+ 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
+ 0x48, 0xfe, 0x92, 0x06,
+ 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
+ 0x58, 0xff, 0x02, 0x00,
+ 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
+ 0xfe, 0xea, 0x06, 0x01,
+ 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
+ 0xfe, 0xe0, 0x06, 0x15,
+ 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
+ 0x01, 0x84, 0xfe, 0xae,
+ 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
+ 0x1e, 0xfe, 0x1a, 0x12,
+ 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
+ 0x43, 0x48, 0x62, 0x80,
+ 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
+ 0x36, 0xfe, 0x02, 0xf6,
+ 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
+ 0xd0, 0x0d, 0x17, 0xfe,
+ 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
+ 0x9e, 0x15, 0x82, 0x01,
+ 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
+ 0x57, 0x10, 0xe6, 0x05,
+ 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
+ 0xfe, 0x9c, 0x32, 0x5f,
+ 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
+ 0xfe, 0x0a, 0xf0, 0xfe,
+ 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
+ 0xaf, 0xa0, 0x05, 0x29,
+ 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
+ 0x00, 0x01, 0x08, 0x14,
+ 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
+ 0x14, 0x00, 0x05, 0xfe,
+ 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
+ 0x12, 0xfe, 0x30, 0x13,
+ 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
+ 0x01, 0x08, 0x14, 0x00,
+ 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
+ 0x78, 0x4f, 0x0f, 0xfe,
+ 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
+ 0x28, 0x48, 0xfe, 0x6c,
+ 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
+ 0x12, 0x53, 0x63, 0x4e,
+ 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
+ 0x6c, 0x08, 0xaf, 0xa0,
+ 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
+ 0x05, 0xed, 0xfe, 0x9c,
+ 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
+ 0x1e, 0xfe, 0x99, 0x58,
+ 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
+ 0x22, 0x6b, 0x01, 0x0c,
+ 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
+ 0x1e, 0x47, 0x2c, 0x7a,
+ 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
+ 0x01, 0x0c, 0x61, 0x65,
+ 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
+ 0x16, 0xfe, 0x08, 0x50,
+ 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
+ 0x01, 0xfe, 0xce, 0x1e,
+ 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
+ 0x01, 0xfe, 0xfe, 0x1e,
+ 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
+ 0x10, 0x01, 0x0c, 0x06,
+ 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
+ 0x10, 0x6a, 0x22, 0x6b,
+ 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
+ 0xfe, 0x9f, 0x83, 0x33,
+ 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
+ 0x3a, 0x0b, 0xfe, 0xc6,
+ 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
+ 0x01, 0xfe, 0xce, 0x1e,
+ 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
+ 0x04, 0xfe, 0xc0, 0x93,
+ 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
+ 0x10, 0x4b, 0x22, 0x4c,
+ 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
+ 0x4e, 0x11, 0x2f, 0xfe,
+ 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
+ 0x3c, 0x37, 0x88, 0xf5,
+ 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
+ 0xd3, 0xfe, 0x42, 0x0a,
+ 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
+ 0x05, 0x29, 0x01, 0x41,
+ 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
+ 0xfe, 0x14, 0x12, 0x01,
+ 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
+ 0x2e, 0x1c, 0x05, 0xfe,
+ 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
+ 0xfe, 0x2c, 0x1c, 0xfe,
+ 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
+ 0x92, 0x10, 0xc4, 0xf6,
+ 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
+ 0xe7, 0x10, 0xfe, 0x2b,
+ 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
+ 0xac, 0xfe, 0xd2, 0xf0,
+ 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
+ 0x1b, 0xbf, 0xd4, 0x5b,
+ 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
+ 0x5e, 0x32, 0x1f, 0x7f,
+ 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
+ 0x05, 0x70, 0xfe, 0x74,
+ 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
+ 0x0f, 0x4d, 0x01, 0xfe,
+ 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
+ 0x0d, 0x2b, 0xfe, 0xe2,
+ 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
+ 0xfe, 0x88, 0x13, 0x21,
+ 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
+ 0x83, 0x83, 0xfe, 0xc9,
+ 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
+ 0x91, 0x04, 0xfe, 0x84,
+ 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
+ 0xfe, 0xcb, 0x57, 0x0b,
+ 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
+ 0x6a, 0x3b, 0x6b, 0x10,
+ 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
+ 0x20, 0x6e, 0xdb, 0x64,
+ 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
+ 0xfe, 0x04, 0xfa, 0x64,
+ 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
+ 0x10, 0x98, 0x91, 0x6c,
+ 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
+ 0x4b, 0x7e, 0x4c, 0x01,
+ 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
+ 0x58, 0xfe, 0x91, 0x58,
+ 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
+ 0x1b, 0x40, 0x01, 0x0c,
+ 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
+ 0xfe, 0x10, 0x90, 0x04,
+ 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
+ 0x79, 0x0b, 0x0e, 0xfe,
+ 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
+ 0x01, 0x0c, 0x06, 0x0d,
+ 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
+ 0x0c, 0x58, 0xfe, 0x8d,
+ 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
+ 0x83, 0x33, 0x0b, 0x0e,
+ 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
+ 0x19, 0xfe, 0x19, 0x41,
+ 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
+ 0x19, 0xfe, 0x44, 0x00,
+ 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
+ 0x4c, 0xfe, 0x0c, 0x51,
+ 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
+ 0x76, 0x10, 0xac, 0xfe,
+ 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
+ 0xe3, 0x23, 0x07, 0xfe,
+ 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
+ 0xcc, 0x0c, 0x1f, 0x92,
+ 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
+ 0x0c, 0xfe, 0x3e, 0x10,
+ 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
+ 0xfe, 0xcb, 0xf0, 0xfe,
+ 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
+ 0xf4, 0x0c, 0x19, 0x94,
+ 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
+ 0xfe, 0xcc, 0xf0, 0xef,
+ 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
+ 0x4e, 0x11, 0x2f, 0xfe,
+ 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
+ 0x3c, 0x37, 0x88, 0xf5,
+ 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
+ 0x2f, 0xfe, 0x3e, 0x0d,
+ 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
+ 0xd2, 0x9f, 0xd3, 0x9f,
+ 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
+ 0xc5, 0x75, 0xd7, 0x99,
+ 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
+ 0x9c, 0x2f, 0xfe, 0x8c,
+ 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
+ 0x42, 0x00, 0x05, 0x70,
+ 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
+ 0x0d, 0xfe, 0x44, 0x13,
+ 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
+ 0xfe, 0xda, 0x0e, 0x0a,
+ 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
+ 0x10, 0x01, 0xfe, 0xf4,
+ 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
+ 0x15, 0x56, 0x01, 0x85,
+ 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
+ 0xcc, 0x10, 0x01, 0xa7,
+ 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
+ 0xfe, 0x99, 0x83, 0xfe,
+ 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
+ 0x43, 0x00, 0xfe, 0xa2,
+ 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
+ 0x00, 0x1d, 0x40, 0x15,
+ 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
+ 0xfe, 0x3a, 0x03, 0x01,
+ 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
+ 0x76, 0x06, 0x12, 0xfe,
+ 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
+ 0xfe, 0x9d, 0xf0, 0xfe,
+ 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
+ 0x0c, 0x61, 0x12, 0x44,
+ 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
+ 0xfe, 0x2e, 0x10, 0x19,
+ 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
+ 0xfe, 0x41, 0x00, 0xa2,
+ 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
+ 0xea, 0x4f, 0xfe, 0x04,
+ 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
+ 0x35, 0xfe, 0x12, 0x1c,
+ 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
+ 0xfe, 0xd4, 0x11, 0x05,
+ 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
+ 0xce, 0x45, 0x31, 0x51,
+ 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
+ 0x67, 0xfe, 0x98, 0x56,
+ 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
+ 0x0c, 0x06, 0x28, 0xfe,
+ 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
+ 0xfe, 0xfa, 0x14, 0xfe,
+ 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
+ 0xfe, 0xe0, 0x14, 0xfe,
+ 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
+ 0xfe, 0xad, 0x13, 0x05,
+ 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
+ 0xe7, 0xfe, 0x08, 0x1c,
+ 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
+ 0x48, 0x55, 0xa5, 0x3b,
+ 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
+ 0xf0, 0x1a, 0x03, 0xfe,
+ 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
+ 0xec, 0xe7, 0x53, 0x00,
+ 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
+ 0x01, 0xfe, 0x62, 0x1b,
+ 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
+ 0xea, 0xe7, 0x53, 0x92,
+ 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
+ 0xfe, 0x38, 0x01, 0x23,
+ 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
+ 0x01, 0x01, 0xfe, 0x1e,
+ 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
+ 0x26, 0x02, 0x21, 0x96,
+ 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
+ 0xc3, 0xfe, 0xe1, 0x10,
+ 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
+ 0xfe, 0x03, 0xdc, 0xfe,
+ 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
+ 0x00, 0xcc, 0x02, 0xfe,
+ 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
+ 0x0f, 0xfe, 0x1c, 0x80,
+ 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
+ 0x0f, 0xfe, 0x1e, 0x80,
+ 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
+ 0x1d, 0x80, 0x04, 0xfe,
+ 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
+ 0x1e, 0xac, 0xfe, 0x14,
+ 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
+ 0x1f, 0xfe, 0x30, 0xf4,
+ 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
+ 0x56, 0xfb, 0x01, 0xfe,
+ 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
+ 0xfe, 0x00, 0x1d, 0x15,
+ 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
+ 0x22, 0x1b, 0xfe, 0x1e,
+ 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
+ 0x96, 0x90, 0x04, 0xfe,
+ 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
+ 0x01, 0x01, 0x0c, 0x06,
+ 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
+ 0x0e, 0x77, 0xfe, 0x01,
+ 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
+ 0x21, 0x2c, 0xfe, 0x00,
+ 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
+ 0x06, 0x58, 0x03, 0xfe,
+ 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
+ 0x03, 0xfe, 0xb2, 0x00,
+ 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
+ 0x66, 0x10, 0x55, 0x10,
+ 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
+ 0x54, 0x2b, 0xfe, 0x88,
+ 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
+ 0x91, 0x54, 0x2b, 0xfe,
+ 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
+ 0x00, 0x40, 0x8d, 0x2c,
+ 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
+ 0x12, 0x1c, 0x75, 0xfe,
+ 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
+ 0x14, 0xfe, 0x0e, 0x47,
+ 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
+ 0xa7, 0x90, 0x34, 0x60,
+ 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
+ 0x09, 0x56, 0xfe, 0x34,
+ 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
+ 0xfe, 0x45, 0x48, 0x01,
+ 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
+ 0x09, 0x1a, 0xa5, 0x0a,
+ 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
+ 0xfe, 0x14, 0x56, 0xfe,
+ 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
+ 0xec, 0xb8, 0xfe, 0x9e,
+ 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
+ 0xf4, 0xfe, 0xdd, 0x10,
+ 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
+ 0x12, 0x09, 0x0d, 0xfe,
+ 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
+ 0x13, 0x09, 0xfe, 0x23,
+ 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
+ 0x24, 0xfe, 0x12, 0x12,
+ 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
+ 0xae, 0x41, 0x02, 0x32,
+ 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
+ 0x35, 0x32, 0x01, 0x43,
+ 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
+ 0x13, 0x01, 0x0c, 0x06,
+ 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
+ 0xe5, 0x55, 0xb0, 0xfe,
+ 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
+ 0xfe, 0xb6, 0x0e, 0x10,
+ 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
+ 0x88, 0x20, 0x6e, 0x01,
+ 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
+ 0x55, 0xfe, 0x04, 0xfa,
+ 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
+ 0xfe, 0x40, 0x56, 0xfe,
+ 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+ 0x44, 0x55, 0xfe, 0xe5,
+ 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
+ 0x68, 0x22, 0x69, 0x01,
+ 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
+ 0x6b, 0xfe, 0x2c, 0x50,
+ 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
+ 0x50, 0x03, 0x68, 0x3b,
+ 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
+ 0x40, 0x50, 0xfe, 0xc2,
+ 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
+ 0x16, 0x3d, 0x27, 0x25,
+ 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
+ 0xa6, 0x23, 0x3f, 0x1b,
+ 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
+ 0xfe, 0x0a, 0x55, 0x31,
+ 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
+ 0x51, 0x05, 0x72, 0x01,
+ 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
+ 0x2a, 0x3c, 0x16, 0xc0,
+ 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
+ 0xfe, 0x66, 0x15, 0x05,
+ 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
+ 0x2b, 0x3d, 0x01, 0x08,
+ 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
+ 0xb6, 0x1e, 0x83, 0x01,
+ 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
+ 0x07, 0x90, 0x3f, 0x01,
+ 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
+ 0x01, 0x43, 0x09, 0x82,
+ 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
+ 0x05, 0x72, 0xfe, 0xc0,
+ 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
+ 0x32, 0x01, 0x08, 0x17,
+ 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
+ 0x3d, 0x27, 0x25, 0xbd,
+ 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
+ 0xe8, 0x14, 0x01, 0xa6,
+ 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
+ 0x0e, 0x12, 0x01, 0x43,
+ 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
+ 0x01, 0x08, 0x17, 0x73,
+ 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
+ 0x27, 0x25, 0xbd, 0x09,
+ 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
+ 0xb6, 0x14, 0x86, 0xa8,
+ 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
+ 0x82, 0x4e, 0x05, 0x72,
+ 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
+ 0xfe, 0xc0, 0x19, 0x05,
+ 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
+ 0xcc, 0x01, 0x08, 0x26,
+ 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
+ 0xcc, 0x15, 0x5e, 0x32,
+ 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+ 0xad, 0x23, 0xfe, 0xff,
+ 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
+ 0x00, 0x57, 0x52, 0xad,
+ 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
+ 0x02, 0x00, 0x57, 0x52,
+ 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
+ 0x02, 0x13, 0x58, 0xff,
+ 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
+ 0x5c, 0x0a, 0x55, 0x01,
+ 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
+ 0xff, 0x03, 0x00, 0x54,
+ 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
+ 0x7c, 0x3a, 0x0b, 0x0e,
+ 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
+ 0xfe, 0x1a, 0xf7, 0x00,
+ 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
+ 0xda, 0x6d, 0x02, 0xfe,
+ 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
+ 0x02, 0x01, 0xc6, 0xfe,
+ 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
+ 0x25, 0xbe, 0x01, 0x08,
+ 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
+ 0x03, 0x9a, 0x1e, 0xfe,
+ 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
+ 0x48, 0xfe, 0x08, 0x17,
+ 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
+ 0x17, 0x4d, 0x13, 0x07,
+ 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
+ 0xff, 0x02, 0x83, 0x55,
+ 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
+ 0x17, 0x1c, 0x63, 0x13,
+ 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
+ 0x00, 0xb0, 0xfe, 0x80,
+ 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
+ 0x53, 0x07, 0xfe, 0x60,
+ 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
+ 0x00, 0x1c, 0x95, 0x13,
+ 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
+ 0xfe, 0x43, 0xf4, 0x96,
+ 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
+ 0xf4, 0x94, 0xf6, 0x8b,
+ 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
+ 0xda, 0x17, 0x62, 0x49,
+ 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
+ 0x71, 0x50, 0x26, 0xfe,
+ 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
+ 0x58, 0x02, 0x50, 0x13,
+ 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
+ 0x25, 0xbe, 0xfe, 0x03,
+ 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
+ 0x0a, 0x01, 0x08, 0x16,
+ 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
+ 0x01, 0x08, 0x16, 0xa9,
+ 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
+ 0x08, 0x16, 0xa9, 0x27,
+ 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
+ 0x01, 0x38, 0x06, 0x24,
+ 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
+ 0x78, 0x03, 0x9a, 0x1e,
+ 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
+ 0xfe, 0x40, 0x5a, 0x23,
+ 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
+ 0x80, 0x48, 0xfe, 0xaa,
+ 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
+ 0xfe, 0xac, 0x1d, 0xfe,
+ 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
+ 0x43, 0x48, 0x2d, 0x93,
+ 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
+ 0x36, 0xfe, 0x34, 0xf4,
+ 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
+ 0x28, 0x10, 0xfe, 0xc0,
+ 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
+ 0x18, 0x45, 0xfe, 0x1c,
+ 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
+ 0x19, 0xfe, 0x04, 0xf4,
+ 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
+ 0x21, 0xfe, 0x7f, 0x01,
+ 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
+ 0x7e, 0x01, 0xfe, 0xc8,
+ 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
+ 0x21, 0xfe, 0x81, 0x01,
+ 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
+ 0x13, 0x0d, 0x02, 0x14,
+ 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
+ 0xfe, 0x82, 0x19, 0x14,
+ 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
+ 0x08, 0x02, 0x14, 0x07,
+ 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
+ 0x01, 0x08, 0x17, 0xc1,
+ 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
+ 0x08, 0x02, 0x50, 0x02,
+ 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
+ 0x14, 0x12, 0x01, 0x08,
+ 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
+ 0x08, 0x17, 0x74, 0xfe,
+ 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
+ 0x74, 0x5f, 0xcc, 0x01,
+ 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
+ 0xfe, 0x49, 0xf4, 0x00,
+ 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
+ 0x02, 0x00, 0x10, 0x2f,
+ 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
+ 0x16, 0xfe, 0x64, 0x1a,
+ 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
+ 0x61, 0x07, 0x44, 0x02,
+ 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
+ 0x13, 0x0a, 0x9d, 0x01,
+ 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
+ 0xfe, 0x80, 0xe7, 0x1a,
+ 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
+ 0x0a, 0x5a, 0x01, 0x18,
+ 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
+ 0x7e, 0x1e, 0xfe, 0x80,
+ 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
+ 0xfe, 0x80, 0x4c, 0x0a,
+ 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
+ 0xfe, 0x19, 0xde, 0xfe,
+ 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
+ 0x2a, 0x1c, 0xfa, 0xb3,
+ 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
+ 0xf4, 0x1a, 0xfe, 0xfa,
+ 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
+ 0xfe, 0x18, 0x58, 0x03,
+ 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
+ 0xfe, 0x30, 0xf4, 0x07,
+ 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
+ 0xf7, 0x24, 0xb1, 0xfe,
+ 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
+ 0xfe, 0xba, 0x10, 0x1c,
+ 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
+ 0x1d, 0xf7, 0x54, 0xb1,
+ 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
+ 0xaf, 0x19, 0xfe, 0x98,
+ 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
+ 0x1a, 0x87, 0x8b, 0x0f,
+ 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
+ 0xfe, 0x32, 0x90, 0x04,
+ 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
+ 0x7c, 0x12, 0xfe, 0x0f,
+ 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
+ 0x31, 0x02, 0xc9, 0x2b,
+ 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
+ 0x6a, 0xfe, 0x19, 0xfe,
+ 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
+ 0x1b, 0xfe, 0x36, 0x14,
+ 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
+ 0xfe, 0x80, 0xe7, 0x1a,
+ 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
+ 0x30, 0xfe, 0x12, 0x45,
+ 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
+ 0x39, 0xf0, 0x75, 0x26,
+ 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
+ 0xe3, 0x23, 0x07, 0xfe,
+ 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
+ 0x56, 0xfe, 0x3c, 0x13,
+ 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
+ 0x01, 0x18, 0xcb, 0xfe,
+ 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
+ 0xfe, 0x00, 0xcc, 0xcb,
+ 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
+ 0xfe, 0x80, 0x4c, 0x01,
+ 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
+ 0x12, 0xfe, 0x14, 0x56,
+ 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
+ 0x0d, 0x19, 0xfe, 0x15,
+ 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
+ 0x83, 0xfe, 0x18, 0x80,
+ 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
+ 0x90, 0xfe, 0xba, 0x90,
+ 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
+ 0x21, 0xb9, 0x88, 0x20,
+ 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
+ 0x18, 0xfe, 0x49, 0x44,
+ 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
+ 0x1a, 0xa4, 0x0a, 0x67,
+ 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
+ 0x1d, 0x7b, 0xfe, 0x52,
+ 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
+ 0x4e, 0xe4, 0xdd, 0x7b,
+ 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
+ 0xfe, 0x4e, 0xe4, 0xfe,
+ 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
+ 0xfe, 0x08, 0x10, 0x03,
+ 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
+ 0x68, 0x54, 0xfe, 0xf1,
+ 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
+ 0xfe, 0x1a, 0xf4, 0xfe,
+ 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
+ 0x09, 0x92, 0xfe, 0x5a,
+ 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
+ 0x5a, 0xf0, 0xfe, 0xc8,
+ 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
+ 0x1a, 0x10, 0x09, 0x0d,
+ 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
+ 0x1f, 0x93, 0x01, 0x42,
+ 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
+ 0xfe, 0x14, 0xf0, 0x08,
+ 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
+ 0xfe, 0x82, 0xf0, 0xfe,
+ 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
+ 0x02, 0x0f, 0xfe, 0x18,
+ 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
+ 0x80, 0x04, 0xfe, 0x82,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
+ 0x83, 0x33, 0x0b, 0x0e,
+ 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
+ 0x02, 0x0f, 0xfe, 0x04,
+ 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
+ 0x80, 0x04, 0xfe, 0x80,
+ 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
+ 0xfe, 0x99, 0x83, 0xfe,
+ 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
+ 0x83, 0xfe, 0xce, 0x47,
+ 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
+ 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x08, 0x90, 0x04,
+ 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
+ 0xfe, 0x8a, 0x93, 0x79,
+ 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
+ 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x3c, 0x90, 0x04,
+ 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
+ 0x04, 0xfe, 0x83, 0x83,
+ 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
};
-STATIC unsigned short _adv_asc38C1600_size =
- sizeof(_adv_asc38C1600_buf); /* 0x1673 */
-STATIC ADV_DCNT _adv_asc38C1600_chksum =
- 0x0604EF77UL; /* Expanded little-endian checksum. */
+static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
+static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
/* a_init.c */
/*
@@ -14049,340 +13847,340 @@ STATIC ADV_DCNT _adv_asc38C1600_chksum =
* on big-endian platforms so char fields read as words are actually being
* unswapped on big-endian platforms.
*/
-STATIC ADVEEP_3550_CONFIG
-Default_3550_EEPROM_Config __initdata = {
- ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
- 0x0000, /* cfg_msw */
- 0xFFFF, /* disc_enable */
- 0xFFFF, /* wdtr_able */
- 0xFFFF, /* sdtr_able */
- 0xFFFF, /* start_motor */
- 0xFFFF, /* tagqng_able */
- 0xFFFF, /* bios_scan */
- 0, /* scam_tolerant */
- 7, /* adapter_scsi_id */
- 0, /* bios_boot_delay */
- 3, /* scsi_reset_delay */
- 0, /* bios_id_lun */
- 0, /* termination */
- 0, /* reserved1 */
- 0xFFE7, /* bios_ctrl */
- 0xFFFF, /* ultra_able */
- 0, /* reserved2 */
- ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
- ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
- 0, /* dvc_cntl */
- 0, /* bug_fix */
- 0, /* serial_number_word1 */
- 0, /* serial_number_word2 */
- 0, /* serial_number_word3 */
- 0, /* check_sum */
- { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */
- 0, /* dvc_err_code */
- 0, /* adv_err_code */
- 0, /* adv_err_addr */
- 0, /* saved_dvc_err_code */
- 0, /* saved_adv_err_code */
- 0, /* saved_adv_err_addr */
- 0 /* num_of_err */
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
+ ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
+ 0x0000, /* cfg_msw */
+ 0xFFFF, /* disc_enable */
+ 0xFFFF, /* wdtr_able */
+ 0xFFFF, /* sdtr_able */
+ 0xFFFF, /* start_motor */
+ 0xFFFF, /* tagqng_able */
+ 0xFFFF, /* bios_scan */
+ 0, /* scam_tolerant */
+ 7, /* adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* termination */
+ 0, /* reserved1 */
+ 0xFFE7, /* bios_ctrl */
+ 0xFFFF, /* ultra_able */
+ 0, /* reserved2 */
+ ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
+ ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* dvc_cntl */
+ 0, /* bug_fix */
+ 0, /* serial_number_word1 */
+ 0, /* serial_number_word2 */
+ 0, /* serial_number_word3 */
+ 0, /* check_sum */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , /* oem_name[16] */
+ 0, /* dvc_err_code */
+ 0, /* adv_err_code */
+ 0, /* adv_err_addr */
+ 0, /* saved_dvc_err_code */
+ 0, /* saved_adv_err_code */
+ 0, /* saved_adv_err_addr */
+ 0 /* num_of_err */
};
-STATIC ADVEEP_3550_CONFIG
-ADVEEP_3550_Config_Field_IsChar __initdata = {
- 0, /* cfg_lsw */
- 0, /* cfg_msw */
- 0, /* -disc_enable */
- 0, /* wdtr_able */
- 0, /* sdtr_able */
- 0, /* start_motor */
- 0, /* tagqng_able */
- 0, /* bios_scan */
- 0, /* scam_tolerant */
- 1, /* adapter_scsi_id */
- 1, /* bios_boot_delay */
- 1, /* scsi_reset_delay */
- 1, /* bios_id_lun */
- 1, /* termination */
- 1, /* reserved1 */
- 0, /* bios_ctrl */
- 0, /* ultra_able */
- 0, /* reserved2 */
- 1, /* max_host_qng */
- 1, /* max_dvc_qng */
- 0, /* dvc_cntl */
- 0, /* bug_fix */
- 0, /* serial_number_word1 */
- 0, /* serial_number_word2 */
- 0, /* serial_number_word3 */
- 0, /* check_sum */
- { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* oem_name[16] */
- 0, /* dvc_err_code */
- 0, /* adv_err_code */
- 0, /* adv_err_addr */
- 0, /* saved_dvc_err_code */
- 0, /* saved_adv_err_code */
- 0, /* saved_adv_err_addr */
- 0 /* num_of_err */
+static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
+ 0, /* cfg_lsw */
+ 0, /* cfg_msw */
+ 0, /* -disc_enable */
+ 0, /* wdtr_able */
+ 0, /* sdtr_able */
+ 0, /* start_motor */
+ 0, /* tagqng_able */
+ 0, /* bios_scan */
+ 0, /* scam_tolerant */
+ 1, /* adapter_scsi_id */
+ 1, /* bios_boot_delay */
+ 1, /* scsi_reset_delay */
+ 1, /* bios_id_lun */
+ 1, /* termination */
+ 1, /* reserved1 */
+ 0, /* bios_ctrl */
+ 0, /* ultra_able */
+ 0, /* reserved2 */
+ 1, /* max_host_qng */
+ 1, /* max_dvc_qng */
+ 0, /* dvc_cntl */
+ 0, /* bug_fix */
+ 0, /* serial_number_word1 */
+ 0, /* serial_number_word2 */
+ 0, /* serial_number_word3 */
+ 0, /* check_sum */
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ , /* oem_name[16] */
+ 0, /* dvc_err_code */
+ 0, /* adv_err_code */
+ 0, /* adv_err_addr */
+ 0, /* saved_dvc_err_code */
+ 0, /* saved_adv_err_code */
+ 0, /* saved_adv_err_addr */
+ 0 /* num_of_err */
};
-STATIC ADVEEP_38C0800_CONFIG
-Default_38C0800_EEPROM_Config __initdata = {
- ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
- 0x0000, /* 01 cfg_msw */
- 0xFFFF, /* 02 disc_enable */
- 0xFFFF, /* 03 wdtr_able */
- 0x4444, /* 04 sdtr_speed1 */
- 0xFFFF, /* 05 start_motor */
- 0xFFFF, /* 06 tagqng_able */
- 0xFFFF, /* 07 bios_scan */
- 0, /* 08 scam_tolerant */
- 7, /* 09 adapter_scsi_id */
- 0, /* bios_boot_delay */
- 3, /* 10 scsi_reset_delay */
- 0, /* bios_id_lun */
- 0, /* 11 termination_se */
- 0, /* termination_lvd */
- 0xFFE7, /* 12 bios_ctrl */
- 0x4444, /* 13 sdtr_speed2 */
- 0x4444, /* 14 sdtr_speed3 */
- ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
- ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
- 0, /* 16 dvc_cntl */
- 0x4444, /* 17 sdtr_speed4 */
- 0, /* 18 serial_number_word1 */
- 0, /* 19 serial_number_word2 */
- 0, /* 20 serial_number_word3 */
- 0, /* 21 check_sum */
- { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
- 0, /* 30 dvc_err_code */
- 0, /* 31 adv_err_code */
- 0, /* 32 adv_err_addr */
- 0, /* 33 saved_dvc_err_code */
- 0, /* 34 saved_adv_err_code */
- 0, /* 35 saved_adv_err_addr */
- 0, /* 36 reserved */
- 0, /* 37 reserved */
- 0, /* 38 reserved */
- 0, /* 39 reserved */
- 0, /* 40 reserved */
- 0, /* 41 reserved */
- 0, /* 42 reserved */
- 0, /* 43 reserved */
- 0, /* 44 reserved */
- 0, /* 45 reserved */
- 0, /* 46 reserved */
- 0, /* 47 reserved */
- 0, /* 48 reserved */
- 0, /* 49 reserved */
- 0, /* 50 reserved */
- 0, /* 51 reserved */
- 0, /* 52 reserved */
- 0, /* 53 reserved */
- 0, /* 54 reserved */
- 0, /* 55 reserved */
- 0, /* 56 cisptr_lsw */
- 0, /* 57 cisprt_msw */
- PCI_VENDOR_ID_ASP, /* 58 subsysvid */
- PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
- 0, /* 60 reserved */
- 0, /* 61 reserved */
- 0, /* 62 reserved */
- 0 /* 63 reserved */
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
+ ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
+ 0x0000, /* 01 cfg_msw */
+ 0xFFFF, /* 02 disc_enable */
+ 0xFFFF, /* 03 wdtr_able */
+ 0x4444, /* 04 sdtr_speed1 */
+ 0xFFFF, /* 05 start_motor */
+ 0xFFFF, /* 06 tagqng_able */
+ 0xFFFF, /* 07 bios_scan */
+ 0, /* 08 scam_tolerant */
+ 7, /* 09 adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* 10 scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* 11 termination_se */
+ 0, /* termination_lvd */
+ 0xFFE7, /* 12 bios_ctrl */
+ 0x4444, /* 13 sdtr_speed2 */
+ 0x4444, /* 14 sdtr_speed3 */
+ ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
+ ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* 16 dvc_cntl */
+ 0x4444, /* 17 sdtr_speed4 */
+ 0, /* 18 serial_number_word1 */
+ 0, /* 19 serial_number_word2 */
+ 0, /* 20 serial_number_word3 */
+ 0, /* 21 check_sum */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , /* 22-29 oem_name[16] */
+ 0, /* 30 dvc_err_code */
+ 0, /* 31 adv_err_code */
+ 0, /* 32 adv_err_addr */
+ 0, /* 33 saved_dvc_err_code */
+ 0, /* 34 saved_adv_err_code */
+ 0, /* 35 saved_adv_err_addr */
+ 0, /* 36 reserved */
+ 0, /* 37 reserved */
+ 0, /* 38 reserved */
+ 0, /* 39 reserved */
+ 0, /* 40 reserved */
+ 0, /* 41 reserved */
+ 0, /* 42 reserved */
+ 0, /* 43 reserved */
+ 0, /* 44 reserved */
+ 0, /* 45 reserved */
+ 0, /* 46 reserved */
+ 0, /* 47 reserved */
+ 0, /* 48 reserved */
+ 0, /* 49 reserved */
+ 0, /* 50 reserved */
+ 0, /* 51 reserved */
+ 0, /* 52 reserved */
+ 0, /* 53 reserved */
+ 0, /* 54 reserved */
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
+ PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+ 0 /* 63 reserved */
};
-STATIC ADVEEP_38C0800_CONFIG
-ADVEEP_38C0800_Config_Field_IsChar __initdata = {
- 0, /* 00 cfg_lsw */
- 0, /* 01 cfg_msw */
- 0, /* 02 disc_enable */
- 0, /* 03 wdtr_able */
- 0, /* 04 sdtr_speed1 */
- 0, /* 05 start_motor */
- 0, /* 06 tagqng_able */
- 0, /* 07 bios_scan */
- 0, /* 08 scam_tolerant */
- 1, /* 09 adapter_scsi_id */
- 1, /* bios_boot_delay */
- 1, /* 10 scsi_reset_delay */
- 1, /* bios_id_lun */
- 1, /* 11 termination_se */
- 1, /* termination_lvd */
- 0, /* 12 bios_ctrl */
- 0, /* 13 sdtr_speed2 */
- 0, /* 14 sdtr_speed3 */
- 1, /* 15 max_host_qng */
- 1, /* max_dvc_qng */
- 0, /* 16 dvc_cntl */
- 0, /* 17 sdtr_speed4 */
- 0, /* 18 serial_number_word1 */
- 0, /* 19 serial_number_word2 */
- 0, /* 20 serial_number_word3 */
- 0, /* 21 check_sum */
- { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
- 0, /* 30 dvc_err_code */
- 0, /* 31 adv_err_code */
- 0, /* 32 adv_err_addr */
- 0, /* 33 saved_dvc_err_code */
- 0, /* 34 saved_adv_err_code */
- 0, /* 35 saved_adv_err_addr */
- 0, /* 36 reserved */
- 0, /* 37 reserved */
- 0, /* 38 reserved */
- 0, /* 39 reserved */
- 0, /* 40 reserved */
- 0, /* 41 reserved */
- 0, /* 42 reserved */
- 0, /* 43 reserved */
- 0, /* 44 reserved */
- 0, /* 45 reserved */
- 0, /* 46 reserved */
- 0, /* 47 reserved */
- 0, /* 48 reserved */
- 0, /* 49 reserved */
- 0, /* 50 reserved */
- 0, /* 51 reserved */
- 0, /* 52 reserved */
- 0, /* 53 reserved */
- 0, /* 54 reserved */
- 0, /* 55 reserved */
- 0, /* 56 cisptr_lsw */
- 0, /* 57 cisprt_msw */
- 0, /* 58 subsysvid */
- 0, /* 59 subsysid */
- 0, /* 60 reserved */
- 0, /* 61 reserved */
- 0, /* 62 reserved */
- 0 /* 63 reserved */
+static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
+ 0, /* 00 cfg_lsw */
+ 0, /* 01 cfg_msw */
+ 0, /* 02 disc_enable */
+ 0, /* 03 wdtr_able */
+ 0, /* 04 sdtr_speed1 */
+ 0, /* 05 start_motor */
+ 0, /* 06 tagqng_able */
+ 0, /* 07 bios_scan */
+ 0, /* 08 scam_tolerant */
+ 1, /* 09 adapter_scsi_id */
+ 1, /* bios_boot_delay */
+ 1, /* 10 scsi_reset_delay */
+ 1, /* bios_id_lun */
+ 1, /* 11 termination_se */
+ 1, /* termination_lvd */
+ 0, /* 12 bios_ctrl */
+ 0, /* 13 sdtr_speed2 */
+ 0, /* 14 sdtr_speed3 */
+ 1, /* 15 max_host_qng */
+ 1, /* max_dvc_qng */
+ 0, /* 16 dvc_cntl */
+ 0, /* 17 sdtr_speed4 */
+ 0, /* 18 serial_number_word1 */
+ 0, /* 19 serial_number_word2 */
+ 0, /* 20 serial_number_word3 */
+ 0, /* 21 check_sum */
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ , /* 22-29 oem_name[16] */
+ 0, /* 30 dvc_err_code */
+ 0, /* 31 adv_err_code */
+ 0, /* 32 adv_err_addr */
+ 0, /* 33 saved_dvc_err_code */
+ 0, /* 34 saved_adv_err_code */
+ 0, /* 35 saved_adv_err_addr */
+ 0, /* 36 reserved */
+ 0, /* 37 reserved */
+ 0, /* 38 reserved */
+ 0, /* 39 reserved */
+ 0, /* 40 reserved */
+ 0, /* 41 reserved */
+ 0, /* 42 reserved */
+ 0, /* 43 reserved */
+ 0, /* 44 reserved */
+ 0, /* 45 reserved */
+ 0, /* 46 reserved */
+ 0, /* 47 reserved */
+ 0, /* 48 reserved */
+ 0, /* 49 reserved */
+ 0, /* 50 reserved */
+ 0, /* 51 reserved */
+ 0, /* 52 reserved */
+ 0, /* 53 reserved */
+ 0, /* 54 reserved */
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+ 0, /* 58 subsysvid */
+ 0, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+ 0 /* 63 reserved */
};
-STATIC ADVEEP_38C1600_CONFIG
-Default_38C1600_EEPROM_Config __initdata = {
- ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
- 0x0000, /* 01 cfg_msw */
- 0xFFFF, /* 02 disc_enable */
- 0xFFFF, /* 03 wdtr_able */
- 0x5555, /* 04 sdtr_speed1 */
- 0xFFFF, /* 05 start_motor */
- 0xFFFF, /* 06 tagqng_able */
- 0xFFFF, /* 07 bios_scan */
- 0, /* 08 scam_tolerant */
- 7, /* 09 adapter_scsi_id */
- 0, /* bios_boot_delay */
- 3, /* 10 scsi_reset_delay */
- 0, /* bios_id_lun */
- 0, /* 11 termination_se */
- 0, /* termination_lvd */
- 0xFFE7, /* 12 bios_ctrl */
- 0x5555, /* 13 sdtr_speed2 */
- 0x5555, /* 14 sdtr_speed3 */
- ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
- ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
- 0, /* 16 dvc_cntl */
- 0x5555, /* 17 sdtr_speed4 */
- 0, /* 18 serial_number_word1 */
- 0, /* 19 serial_number_word2 */
- 0, /* 20 serial_number_word3 */
- 0, /* 21 check_sum */
- { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
- 0, /* 30 dvc_err_code */
- 0, /* 31 adv_err_code */
- 0, /* 32 adv_err_addr */
- 0, /* 33 saved_dvc_err_code */
- 0, /* 34 saved_adv_err_code */
- 0, /* 35 saved_adv_err_addr */
- 0, /* 36 reserved */
- 0, /* 37 reserved */
- 0, /* 38 reserved */
- 0, /* 39 reserved */
- 0, /* 40 reserved */
- 0, /* 41 reserved */
- 0, /* 42 reserved */
- 0, /* 43 reserved */
- 0, /* 44 reserved */
- 0, /* 45 reserved */
- 0, /* 46 reserved */
- 0, /* 47 reserved */
- 0, /* 48 reserved */
- 0, /* 49 reserved */
- 0, /* 50 reserved */
- 0, /* 51 reserved */
- 0, /* 52 reserved */
- 0, /* 53 reserved */
- 0, /* 54 reserved */
- 0, /* 55 reserved */
- 0, /* 56 cisptr_lsw */
- 0, /* 57 cisprt_msw */
- PCI_VENDOR_ID_ASP, /* 58 subsysvid */
- PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
- 0, /* 60 reserved */
- 0, /* 61 reserved */
- 0, /* 62 reserved */
- 0 /* 63 reserved */
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
+ ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
+ 0x0000, /* 01 cfg_msw */
+ 0xFFFF, /* 02 disc_enable */
+ 0xFFFF, /* 03 wdtr_able */
+ 0x5555, /* 04 sdtr_speed1 */
+ 0xFFFF, /* 05 start_motor */
+ 0xFFFF, /* 06 tagqng_able */
+ 0xFFFF, /* 07 bios_scan */
+ 0, /* 08 scam_tolerant */
+ 7, /* 09 adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* 10 scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* 11 termination_se */
+ 0, /* termination_lvd */
+ 0xFFE7, /* 12 bios_ctrl */
+ 0x5555, /* 13 sdtr_speed2 */
+ 0x5555, /* 14 sdtr_speed3 */
+ ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
+ ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* 16 dvc_cntl */
+ 0x5555, /* 17 sdtr_speed4 */
+ 0, /* 18 serial_number_word1 */
+ 0, /* 19 serial_number_word2 */
+ 0, /* 20 serial_number_word3 */
+ 0, /* 21 check_sum */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , /* 22-29 oem_name[16] */
+ 0, /* 30 dvc_err_code */
+ 0, /* 31 adv_err_code */
+ 0, /* 32 adv_err_addr */
+ 0, /* 33 saved_dvc_err_code */
+ 0, /* 34 saved_adv_err_code */
+ 0, /* 35 saved_adv_err_addr */
+ 0, /* 36 reserved */
+ 0, /* 37 reserved */
+ 0, /* 38 reserved */
+ 0, /* 39 reserved */
+ 0, /* 40 reserved */
+ 0, /* 41 reserved */
+ 0, /* 42 reserved */
+ 0, /* 43 reserved */
+ 0, /* 44 reserved */
+ 0, /* 45 reserved */
+ 0, /* 46 reserved */
+ 0, /* 47 reserved */
+ 0, /* 48 reserved */
+ 0, /* 49 reserved */
+ 0, /* 50 reserved */
+ 0, /* 51 reserved */
+ 0, /* 52 reserved */
+ 0, /* 53 reserved */
+ 0, /* 54 reserved */
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
+ PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+ 0 /* 63 reserved */
};
-STATIC ADVEEP_38C1600_CONFIG
-ADVEEP_38C1600_Config_Field_IsChar __initdata = {
- 0, /* 00 cfg_lsw */
- 0, /* 01 cfg_msw */
- 0, /* 02 disc_enable */
- 0, /* 03 wdtr_able */
- 0, /* 04 sdtr_speed1 */
- 0, /* 05 start_motor */
- 0, /* 06 tagqng_able */
- 0, /* 07 bios_scan */
- 0, /* 08 scam_tolerant */
- 1, /* 09 adapter_scsi_id */
- 1, /* bios_boot_delay */
- 1, /* 10 scsi_reset_delay */
- 1, /* bios_id_lun */
- 1, /* 11 termination_se */
- 1, /* termination_lvd */
- 0, /* 12 bios_ctrl */
- 0, /* 13 sdtr_speed2 */
- 0, /* 14 sdtr_speed3 */
- 1, /* 15 max_host_qng */
- 1, /* max_dvc_qng */
- 0, /* 16 dvc_cntl */
- 0, /* 17 sdtr_speed4 */
- 0, /* 18 serial_number_word1 */
- 0, /* 19 serial_number_word2 */
- 0, /* 20 serial_number_word3 */
- 0, /* 21 check_sum */
- { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
- 0, /* 30 dvc_err_code */
- 0, /* 31 adv_err_code */
- 0, /* 32 adv_err_addr */
- 0, /* 33 saved_dvc_err_code */
- 0, /* 34 saved_adv_err_code */
- 0, /* 35 saved_adv_err_addr */
- 0, /* 36 reserved */
- 0, /* 37 reserved */
- 0, /* 38 reserved */
- 0, /* 39 reserved */
- 0, /* 40 reserved */
- 0, /* 41 reserved */
- 0, /* 42 reserved */
- 0, /* 43 reserved */
- 0, /* 44 reserved */
- 0, /* 45 reserved */
- 0, /* 46 reserved */
- 0, /* 47 reserved */
- 0, /* 48 reserved */
- 0, /* 49 reserved */
- 0, /* 50 reserved */
- 0, /* 51 reserved */
- 0, /* 52 reserved */
- 0, /* 53 reserved */
- 0, /* 54 reserved */
- 0, /* 55 reserved */
- 0, /* 56 cisptr_lsw */
- 0, /* 57 cisprt_msw */
- 0, /* 58 subsysvid */
- 0, /* 59 subsysid */
- 0, /* 60 reserved */
- 0, /* 61 reserved */
- 0, /* 62 reserved */
- 0 /* 63 reserved */
+static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
+ 0, /* 00 cfg_lsw */
+ 0, /* 01 cfg_msw */
+ 0, /* 02 disc_enable */
+ 0, /* 03 wdtr_able */
+ 0, /* 04 sdtr_speed1 */
+ 0, /* 05 start_motor */
+ 0, /* 06 tagqng_able */
+ 0, /* 07 bios_scan */
+ 0, /* 08 scam_tolerant */
+ 1, /* 09 adapter_scsi_id */
+ 1, /* bios_boot_delay */
+ 1, /* 10 scsi_reset_delay */
+ 1, /* bios_id_lun */
+ 1, /* 11 termination_se */
+ 1, /* termination_lvd */
+ 0, /* 12 bios_ctrl */
+ 0, /* 13 sdtr_speed2 */
+ 0, /* 14 sdtr_speed3 */
+ 1, /* 15 max_host_qng */
+ 1, /* max_dvc_qng */
+ 0, /* 16 dvc_cntl */
+ 0, /* 17 sdtr_speed4 */
+ 0, /* 18 serial_number_word1 */
+ 0, /* 19 serial_number_word2 */
+ 0, /* 20 serial_number_word3 */
+ 0, /* 21 check_sum */
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ , /* 22-29 oem_name[16] */
+ 0, /* 30 dvc_err_code */
+ 0, /* 31 adv_err_code */
+ 0, /* 32 adv_err_addr */
+ 0, /* 33 saved_dvc_err_code */
+ 0, /* 34 saved_adv_err_code */
+ 0, /* 35 saved_adv_err_addr */
+ 0, /* 36 reserved */
+ 0, /* 37 reserved */
+ 0, /* 38 reserved */
+ 0, /* 39 reserved */
+ 0, /* 40 reserved */
+ 0, /* 41 reserved */
+ 0, /* 42 reserved */
+ 0, /* 43 reserved */
+ 0, /* 44 reserved */
+ 0, /* 45 reserved */
+ 0, /* 46 reserved */
+ 0, /* 47 reserved */
+ 0, /* 48 reserved */
+ 0, /* 49 reserved */
+ 0, /* 50 reserved */
+ 0, /* 51 reserved */
+ 0, /* 52 reserved */
+ 0, /* 53 reserved */
+ 0, /* 54 reserved */
+ 0, /* 55 reserved */
+ 0, /* 56 cisptr_lsw */
+ 0, /* 57 cisprt_msw */
+ 0, /* 58 subsysvid */
+ 0, /* 59 subsysid */
+ 0, /* 60 reserved */
+ 0, /* 61 reserved */
+ 0, /* 62 reserved */
+ 0 /* 63 reserved */
};
/*
@@ -14393,136 +14191,128 @@ ADVEEP_38C1600_Config_Field_IsChar __initdata = {
* For a non-fatal error return a warning code. If there are no warnings
* then 0 is returned.
*/
-STATIC int __init
-AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
{
- ushort warn_code;
- AdvPortAddr iop_base;
- uchar pci_cmd_reg;
- int status;
-
- warn_code = 0;
- asc_dvc->err_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * PCI Command Register
- *
- * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
- * I/O Space Control, Memory Space Control and Bus Master Control bits.
- */
-
- if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister))
- & AscPCICmdRegBits_BusMastering)
- != AscPCICmdRegBits_BusMastering)
- {
- pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
-
- DvcAdvWritePCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister, pci_cmd_reg);
-
- if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister))
- & AscPCICmdRegBits_BusMastering)
- != AscPCICmdRegBits_BusMastering)
- {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
-
- /*
- * PCI Latency Timer
- *
- * If the "latency timer" register is 0x20 or above, then we don't need
- * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
- * comes up less than 0x20).
- */
- if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
- DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20);
- if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20)
- {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
-
- /*
- * Save the state of the PCI Configuration Command Register
- * "Parity Error Response Control" Bit. If the bit is clear (0),
- * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
- * DMA parity errors.
- */
- asc_dvc->cfg->control_flag = 0;
- if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
- & AscPCICmdRegBits_ParErrRespCtrl)) == 0)
- {
- asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
- }
+ ushort warn_code;
+ AdvPortAddr iop_base;
+ uchar pci_cmd_reg;
+ int status;
+
+ warn_code = 0;
+ asc_dvc->err_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * PCI Command Register
+ *
+ * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
+ * I/O Space Control, Memory Space Control and Bus Master Control bits.
+ */
+
+ if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister))
+ & AscPCICmdRegBits_BusMastering)
+ != AscPCICmdRegBits_BusMastering) {
+ pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
+
+ DvcAdvWritePCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister,
+ pci_cmd_reg);
+
+ if (((DvcAdvReadPCIConfigByte
+ (asc_dvc, AscPCIConfigCommandRegister))
+ & AscPCICmdRegBits_BusMastering)
+ != AscPCICmdRegBits_BusMastering) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
- asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
- ADV_LIB_VERSION_MINOR;
- asc_dvc->cfg->chip_version =
- AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+ /*
+ * PCI Latency Timer
+ *
+ * If the "latency timer" register is 0x20 or above, then we don't need
+ * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
+ * comes up less than 0x20).
+ */
+ if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
+ DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
+ 0x20);
+ if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
+ 0x20) {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
- ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
- (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
- (ushort) ADV_CHIP_ID_BYTE);
+ /*
+ * Save the state of the PCI Configuration Command Register
+ * "Parity Error Response Control" Bit. If the bit is clear (0),
+ * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+ * DMA parity errors.
+ */
+ asc_dvc->cfg->control_flag = 0;
+ if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
+ & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
+ asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
+ }
- ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
- (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
- (ushort) ADV_CHIP_ID_WORD);
+ asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
+ ADV_LIB_VERSION_MINOR;
+ asc_dvc->cfg->chip_version =
+ AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+
+ ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
+ (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+ (ushort)ADV_CHIP_ID_BYTE);
+
+ ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
+ (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+ (ushort)ADV_CHIP_ID_WORD);
+
+ /*
+ * Reset the chip to start and allow register writes.
+ */
+ if (AdvFindSignature(iop_base) == 0) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return ADV_ERROR;
+ } else {
+ /*
+ * The caller must set 'chip_type' to a valid setting.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+ asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- /*
- * Reset the chip to start and allow register writes.
- */
- if (AdvFindSignature(iop_base) == 0)
- {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- return ADV_ERROR;
- }
- else {
- /*
- * The caller must set 'chip_type' to a valid setting.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
- asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
- asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
- {
- asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- /*
- * Reset Chip.
- */
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_WR_IO_REG);
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
- {
- if ((status = AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR)
- {
- return ADV_ERROR;
- }
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
- {
- if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
- {
- return ADV_ERROR;
- }
- } else
- {
- if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR)
- {
- return ADV_ERROR;
- }
- }
- warn_code |= status;
- }
+ /*
+ * Reset Chip.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_RESET);
+ DvcSleepMilliSecond(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
+
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ if ((status =
+ AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
+ return ADV_ERROR;
+ }
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ if ((status =
+ AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
+ return ADV_ERROR;
+ }
+ } else {
+ if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
+ return ADV_ERROR;
+ }
+ }
+ warn_code |= status;
+ }
- return warn_code;
+ return warn_code;
}
/*
@@ -14535,574 +14325,563 @@ AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
*
* Needed after initialization for error recovery.
*/
-STATIC int
-AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- int word;
- int j;
- int adv_asc3550_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able = 0, sdtr_able, tagqng_able;
- uchar max_cmd[ADV_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0)
- {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC3550)
- {
- asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
- {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
- {
- ushort bios_version, major, minor;
-
- bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
- major = (bios_version >> 12) & 0xF;
- minor = (bios_version >> 8) & 0xF;
- if (major < 3 || (major == 3 && minor == 1))
- {
- /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
- AdvReadWordLram(iop_base, 0x120, wdtr_able);
- } else
- {
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- }
- }
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- /* Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc3550_size; i++)
- {
- if (_adv_asc3550_buf[i] == 0xff)
- {
- for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[i + 3] << 8) |
- _adv_asc3550_buf[i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc3550_buf[i] == 0xfe)
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[i + 2] << 8) |
- _adv_asc3550_buf[i + 1]));
- i += 2;
- word++;
- } else
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) |
- _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
- word++;
- }
- }
-
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc3550_expanded_size = word;
-
- /*
- * Clear the rest of ASC-3550 Internal RAM (8KB).
- */
- for (; word < ADV_3550_MEMSIZE; word += 2)
- {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc3550_expanded_size; word += 2)
- {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
-
- if (sum != _adv_asc3550_chksum)
- {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
- {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2)
- {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read and save microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC3550.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
- {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
- * threshold of 128 bytes. This register is only accessible to the host.
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- START_CTL_EMFU | READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
- {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
- }
-
- /*
- * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
- * bitmask. These values determine the maximum SDTR speed negotiated
- * with a device.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- *
- * 4-bit speed SDTR speed name
- * =========== ===============
- * 0000b (0x0) SDTR disabled
- * 0001b (0x1) 5 Mhz
- * 0010b (0x2) 10 Mhz
- * 0011b (0x3) 20 Mhz (Ultra)
- * 0100b (0x4) 40 Mhz (LVD/Ultra2)
- * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
- * 0110b (0x6) Undefined
- * .
- * 1111b (0xF) Undefined
- */
- word = 0;
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
- {
- /* Set Ultra speed for TID 'tid'. */
- word |= (0x3 << (4 * (tid % 4)));
- } else
- {
- /* Set Fast speed for TID 'tid'. */
- word |= (0x2 << (4 * (tid % 4)));
- }
- if (tid == 3) /* Check if done with sdtr_speed1. */
- {
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
- word = 0;
- } else if (tid == 7) /* Check if done with sdtr_speed2. */
- {
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
- word = 0;
- } else if (tid == 11) /* Check if done with sdtr_speed3. */
- {
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
- word = 0;
- } else if (tid == 15) /* Check if done with sdtr_speed4. */
- {
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
- /* End of loop. */
- }
- }
-
- /*
- * Set microcode operating variable for the disconnect per TID bitmask.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADV_DCNT sum;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int j;
+ int adv_asc3550_expanded_size;
+ ADV_CARR_T *carrp;
+ ADV_DCNT contig_len;
+ ADV_SDCNT buf_size;
+ ADV_PADDR carr_paddr;
+ int i;
+ ushort scsi_cfg1;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able = 0, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
+
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0) {
+ return ADV_ERROR;
+ }
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
+ asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- /*
- * Determine SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- /* Read current SCSI_CFG1 Register value. */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ /*
+ * Save current per TID negotiated values.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
+ ushort bios_version, major, minor;
+
+ bios_version =
+ bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
+ major = (bios_version >> 12) & 0xF;
+ minor = (bios_version >> 8) & 0xF;
+ if (major < 3 || (major == 3 && minor == 1)) {
+ /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+ AdvReadWordLram(iop_base, 0x120, wdtr_able);
+ } else {
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ }
+ }
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
- /*
- * If all three connectors are in use, return an error.
- */
- if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
- (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
- {
- asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
- return ADV_ERROR;
- }
+ /*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ /* Assume the following compressed format of the microcode buffer:
+ *
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
+ *
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ */
+ word = 0;
+ for (i = 253 * 2; i < _adv_asc3550_size; i++) {
+ if (_adv_asc3550_buf[i] == 0xff) {
+ for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc3550_buf
+ [i +
+ 3] << 8) |
+ _adv_asc3550_buf
+ [i + 2]));
+ word++;
+ }
+ i += 3;
+ } else if (_adv_asc3550_buf[i] == 0xfe) {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc3550_buf[i +
+ 2]
+ << 8) |
+ _adv_asc3550_buf[i +
+ 1]));
+ i += 2;
+ word++;
+ } else {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+ word++;
+ }
+ }
- /*
- * If the internal narrow cable is reversed all of the SCSI_CTRL
- * register signals will be set. Check for and return an error if
- * this condition is found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
- {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
+ /*
+ * Set 'word' for later use to clear the rest of memory and save
+ * the expanded mcode size.
+ */
+ word *= 2;
+ adv_asc3550_expanded_size = word;
+
+ /*
+ * Clear the rest of ASC-3550 Internal RAM (8KB).
+ */
+ for (; word < ADV_3550_MEMSIZE; word += 2) {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ }
- /*
- * If this is a differential board and a single-ended device
- * is attached to one of the connectors, return an error.
- */
- if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
- {
- asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
- return ADV_ERROR;
- }
+ /*
+ * Verify the microcode checksum.
+ */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- /*
- * If automatic termination control is enabled, then set the
- * termination value based on a table listed in a_condor.h.
- *
- * If manual termination was specified with an EEPROM setting
- * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
- * is ready to be 'ored' into SCSI_CFG1.
- */
- if (asc_dvc->cfg->termination == 0)
- {
- /*
- * The software always controls termination by setting TERM_CTL_SEL.
- * If TERM_CTL_SEL were set to 0, the hardware would set termination.
- */
- asc_dvc->cfg->termination |= TERM_CTL_SEL;
-
- switch(scsi_cfg1 & CABLE_DETECT)
- {
- /* TERM_CTL_H: on, TERM_CTL_L: on */
- case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
- asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
- break;
-
- /* TERM_CTL_H: on, TERM_CTL_L: off */
- case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
- asc_dvc->cfg->termination |= TERM_CTL_H;
- break;
-
- /* TERM_CTL_H: off, TERM_CTL_L: off */
- case 0x2: case 0x6:
- break;
- }
- }
+ for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
- /*
- * Clear any set TERM_CTL_H and TERM_CTL_L bits.
- */
- scsi_cfg1 &= ~TERM_CTL;
+ if (sum != _adv_asc3550_chksum) {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return ADV_ERROR;
+ }
- /*
- * Invert the TERM_CTL_H and TERM_CTL_L bits and then
- * set 'scsi_cfg1'. The TERM_POL bit does not need to be
- * referenced, because the hardware internally inverts
- * the Termination High and Low bits if TERM_POL is set.
- */
- scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set filter value and possibly modified termination control
- * bits in the Microcode SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
- FLTR_DISABLE | scsi_cfg1);
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+ /*
+ * Read and save microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
+
+ /*
+ * Set the chip type to indicate the ASC3550.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-3550 has 8KB internal memory.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_8KB);
+ /*
+ * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+ * threshold of 128 bytes. This register is only accessible to the host.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ START_CTL_EMFU | READ_CMD_MRM);
+
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in AdvInquiryHandling() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+ /*
+ * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+ * bitmask. These values determine the maximum SDTR speed negotiated
+ * with a device.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ *
+ * 4-bit speed SDTR speed name
+ * =========== ===============
+ * 0000b (0x0) SDTR disabled
+ * 0001b (0x1) 5 Mhz
+ * 0010b (0x2) 10 Mhz
+ * 0011b (0x3) 20 Mhz (Ultra)
+ * 0100b (0x4) 40 Mhz (LVD/Ultra2)
+ * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
+ * 0110b (0x6) Undefined
+ * .
+ * 1111b (0xF) Undefined
+ */
+ word = 0;
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
+ /* Set Ultra speed for TID 'tid'. */
+ word |= (0x3 << (4 * (tid % 4)));
+ } else {
+ /* Set Fast speed for TID 'tid'. */
+ word |= (0x2 << (4 * (tid % 4)));
+ }
+ if (tid == 3) { /* Check if done with sdtr_speed1. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+ word = 0;
+ } else if (tid == 7) { /* Check if done with sdtr_speed2. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+ word = 0;
+ } else if (tid == 11) { /* Check if done with sdtr_speed3. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+ word = 0;
+ } else if (tid == 15) { /* Check if done with sdtr_speed4. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+ /* End of loop. */
+ }
+ }
- /*
- * Build carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
- {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else
- {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
+ /*
+ * Set microcode operating variable for the disconnect per TID bitmask.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
+
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If all three connectors are in use, return an error.
+ */
+ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+ (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
+ asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+ return ADV_ERROR;
+ }
- do {
- /*
- * Get physical address of the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
- (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
-
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T))
- {
- carrp++;
- continue;
- }
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
+ /*
+ * If this is a differential board and a single-ended device
+ * is attached to one of the connectors, return an error.
+ */
+ if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
+ asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+ return ADV_ERROR;
+ }
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
- {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+ /*
+ * If automatic termination control is enabled, then set the
+ * termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting
+ * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+ * is ready to be 'ored' into SCSI_CFG1.
+ */
+ if (asc_dvc->cfg->termination == 0) {
+ /*
+ * The software always controls termination by setting TERM_CTL_SEL.
+ * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+ */
+ asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+ switch (scsi_cfg1 & CABLE_DETECT) {
+ /* TERM_CTL_H: on, TERM_CTL_L: on */
+ case 0x3:
+ case 0x7:
+ case 0xB:
+ case 0xD:
+ case 0xE:
+ case 0xF:
+ asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+ break;
+
+ /* TERM_CTL_H: on, TERM_CTL_L: off */
+ case 0x1:
+ case 0x5:
+ case 0x9:
+ case 0xA:
+ case 0xC:
+ asc_dvc->cfg->termination |= TERM_CTL_H;
+ break;
+
+ /* TERM_CTL_H: off, TERM_CTL_L: off */
+ case 0x2:
+ case 0x6:
+ break;
+ }
+ }
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ /*
+ * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+ */
+ scsi_cfg1 &= ~TERM_CTL;
+
+ /*
+ * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+ * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+ * referenced, because the hardware internally inverts
+ * the Termination High and Low bits if TERM_POL is set.
+ */
+ scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set filter value and possibly modified termination control
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+ FLTR_DISABLE | scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-3550 has 8KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_8KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ /*
+ * Build carrier freelist.
+ *
+ * Driver must have already allocated memory and set 'carrier_buf'.
+ */
+ ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
- /*
- * Set RISC ICQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+ do {
+ /*
+ * Get physical address of the carrier 'carrp'.
+ */
+ contig_len = sizeof(ADV_CARR_T);
+ carr_paddr =
+ cpu_to_le32(DvcGetPhyAddr
+ (asc_dvc, NULL, (uchar *)carrp,
+ (ADV_SDCNT *)&contig_len,
+ ADV_IS_CARRIER_FLAG));
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
- {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+ buf_size -= sizeof(ADV_CARR_T);
- /*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
- */
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC IRQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
+ /*
+ * If the current carrier is not physically contiguous, then
+ * maybe there was a page crossing. Try the next carrier aligned
+ * start address.
+ */
+ if (contig_len < sizeof(ADV_CARR_T)) {
+ carrp++;
+ continue;
+ }
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+ /*
+ * Insert the carrier at the beginning of the freelist.
+ */
+ carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = carrp;
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
+ carrp++;
+ }
+ while (buf_size > 0);
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
- {
- /*
- * If the BIOS Signature is present in memory, restore the
- * BIOS Handshake Configuration Table and do not perform
- * a SCSI Bus Reset.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
- {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
- } else
- {
- if (AdvResetSB(asc_dvc) != ADV_TRUE)
- {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
- }
- }
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
- return warn_code;
+ return warn_code;
}
/*
@@ -15115,619 +14894,610 @@ AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
*
* Needed after initialization for error recovery.
*/
-STATIC int
-AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- int word;
- int j;
- int adv_asc38C0800_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar byte;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able, sdtr_able, tagqng_able;
- uchar max_cmd[ADV_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0)
- {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
- {
- asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
- {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * RAM BIST (RAM Built-In Self Test)
- *
- * Address : I/O base + offset 0x38h register (byte).
- * Function: Bit 7-6(RW) : RAM mode
- * Normal Mode : 0x00
- * Pre-test Mode : 0x40
- * RAM Test Mode : 0x80
- * Bit 5 : unused
- * Bit 4(RO) : Done bit
- * Bit 3-0(RO) : Status
- * Host Error : 0x08
- * Int_RAM Error : 0x04
- * RISC Error : 0x02
- * SCSI Error : 0x01
- * No Error : 0x00
- *
- * Note: RAM BIST code should be put right here, before loading the
- * microcode and after saving the RISC memory BIOS region.
- */
-
- /*
- * LRAM Pre-test
- *
- * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
- * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
- * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
- * to NORMAL_MODE, return an error too.
- */
- for (i = 0; i < 2; i++)
- {
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
- {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
-
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
- != NORMAL_VALUE)
- {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
- }
-
- /*
- * LRAM Test - It takes about 1.5 ms to run through the test.
- *
- * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
- * If Done bit not set or Status not 0, save register byte, set the
- * err_code, and return an error.
- */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
-
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
- {
- /* Get here if Done bit not set or Status not 0. */
- asc_dvc->bist_err_code = byte; /* for BIOS display message */
- asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
- return ADV_ERROR;
- }
-
- /* We need to reset back to normal mode after LRAM test passes. */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- *
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- /* Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
- {
- if (_adv_asc38C0800_buf[i] == 0xff)
- {
- for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf[i + 3] << 8) |
- _adv_asc38C0800_buf[i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc38C0800_buf[i] == 0xfe)
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf[i + 2] << 8) |
- _adv_asc38C0800_buf[i + 1]));
- i += 2;
- word++;
- } else
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) |
- _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
- word++;
- }
- }
-
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc38C0800_expanded_size = word;
-
- /*
- * Clear the rest of ASC-38C0800 Internal RAM (16KB).
- */
- for (; word < ADV_38C0800_MEMSIZE; word += 2)
- {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
- {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
- ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
-
- ASC_DBG2(1,
- "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
- (ulong) sum, (ulong) _adv_asc38C0800_chksum);
-
- if (sum != _adv_asc38C0800_chksum)
- {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
- {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2)
- {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC38C0800.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
-
- /*
- * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
- * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
- * cable detection and then we are able to read C_DET[3:0].
- *
- * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
- * Microcode Default Value' section below.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
- {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
- * bits for the default FIFO threshold.
- *
- * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
- *
- * For DMA Errata #4 set the BC_THRESH_ENB bit.
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
- {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
- }
-
- /*
- * Set microcode operating variables for DISC and SDTR_SPEED1,
- * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
- * configuration values.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADV_DCNT sum;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int j;
+ int adv_asc38C0800_expanded_size;
+ ADV_CARR_T *carrp;
+ ADV_DCNT contig_len;
+ ADV_SDCNT buf_size;
+ ADV_PADDR carr_paddr;
+ int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
+
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0) {
+ return ADV_ERROR;
+ }
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- /*
- * Determine SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- /* Read current SCSI_CFG1 Register value. */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
- /*
- * If the internal narrow cable is reversed all of the SCSI_CTRL
- * register signals will be set. Check for and return an error if
- * this condition is found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
- {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
+ /*
+ * RAM BIST (RAM Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
+
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++) {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0
+ || (byte & 0x0F) != PRE_TEST_VALUE) {
+ asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
+
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE) {
+ asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
+ }
- /*
- * All kind of combinations of devices attached to one of four connectors
- * are acceptable except HVD device attached. For example, LVD device can
- * be attached to SE connector while SE device attached to LVD connector.
- * If LVD device attached to SE connector, it only runs up to Ultra speed.
- *
- * If an HVD device is attached to one of LVD connectors, return an error.
- * However, there is no way to detect HVD device attached to SE connectors.
- */
- if (scsi_cfg1 & HVD)
- {
- asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
- return ADV_ERROR;
- }
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
+
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
- /*
- * If either SE or LVD automatic termination control is enabled, then
- * set the termination value based on a table listed in a_condor.h.
- *
- * If manual termination was specified with an EEPROM setting then
- * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
- * be 'ored' into SCSI_CFG1.
- */
- if ((asc_dvc->cfg->termination & TERM_SE) == 0)
- {
- /* SE automatic termination control is enabled. */
- switch(scsi_cfg1 & C_DET_SE)
- {
- /* TERM_SE_HI: on, TERM_SE_LO: on */
- case 0x1: case 0x2: case 0x3:
- asc_dvc->cfg->termination |= TERM_SE;
- break;
-
- /* TERM_SE_HI: on, TERM_SE_LO: off */
- case 0x0:
- asc_dvc->cfg->termination |= TERM_SE_HI;
- break;
- }
- }
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+ /*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ *
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+ /* Assume the following compressed format of the microcode buffer:
+ *
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
+ *
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ */
+ word = 0;
+ for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
+ if (_adv_asc38C0800_buf[i] == 0xff) {
+ for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc38C0800_buf
+ [i +
+ 3] << 8) |
+ _adv_asc38C0800_buf
+ [i + 2]));
+ word++;
+ }
+ i += 3;
+ } else if (_adv_asc38C0800_buf[i] == 0xfe) {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc38C0800_buf
+ [i +
+ 2] << 8) |
+ _adv_asc38C0800_buf[i
+ +
+ 1]));
+ i += 2;
+ word++;
+ } else {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+ word++;
+ }
+ }
- if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
- {
- /* LVD automatic termination control is enabled. */
- switch(scsi_cfg1 & C_DET_LVD)
- {
- /* TERM_LVD_HI: on, TERM_LVD_LO: on */
- case 0x4: case 0x8: case 0xC:
- asc_dvc->cfg->termination |= TERM_LVD;
- break;
-
- /* TERM_LVD_HI: off, TERM_LVD_LO: off */
- case 0x0:
- break;
- }
- }
+ /*
+ * Set 'word' for later use to clear the rest of memory and save
+ * the expanded mcode size.
+ */
+ word *= 2;
+ adv_asc38C0800_expanded_size = word;
+
+ /*
+ * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+ */
+ for (; word < ADV_38C0800_MEMSIZE; word += 2) {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ }
- /*
- * Clear any set TERM_SE and TERM_LVD bits.
- */
- scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+ /*
+ * Verify the microcode checksum.
+ */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- /*
- * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
- */
- scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+ for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
- /*
- * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
- * and set possibly modified termination control bits in the Microcode
- * SCSI_CFG1 Register Value.
- */
- scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+ ASC_DBG2(1,
+ "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
+ (ulong)sum, (ulong)_adv_asc38C0800_chksum);
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set possibly modified termination control and reset DIS_TERM_DRV
- * bits in the Microcode SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+ if (sum != _adv_asc38C0800_chksum) {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return ADV_ERROR;
+ }
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-38C0800 has 16KB internal memory.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_16KB);
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
+
+ /*
+ * Set the chip type to indicate the ASC38C0800.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+ scsi_cfg1 | DIS_TERM_DRV);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- /*
- * Build the carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
- {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else
- {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
+ /*
+ * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+ * bits for the default FIFO threshold.
+ *
+ * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+ *
+ * For DMA Errata #4 set the BC_THRESH_ENB bit.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
+ READ_CMD_MRM);
+
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in AdvInquiryHandling() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- do {
- /*
- * Get physical address for the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
- (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
-
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T))
- {
- carrp++;
- continue;
- }
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
+
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
+ /*
+ * All kind of combinations of devices attached to one of four connectors
+ * are acceptable except HVD device attached. For example, LVD device can
+ * be attached to SE connector while SE device attached to LVD connector.
+ * If LVD device attached to SE connector, it only runs up to Ultra speed.
+ *
+ * If an HVD device is attached to one of LVD connectors, return an error.
+ * However, there is no way to detect HVD device attached to SE connectors.
+ */
+ if (scsi_cfg1 & HVD) {
+ asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
- {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+ /*
+ * If either SE or LVD automatic termination control is enabled, then
+ * set the termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting then
+ * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+ * be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+ /* SE automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_SE) {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
+
+ /* TERM_SE_HI: on, TERM_SE_LO: off */
+ case 0x0:
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ break;
+ }
+ }
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
+ /* LVD automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_LVD) {
+ /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+ case 0x4:
+ case 0x8:
+ case 0xC:
+ asc_dvc->cfg->termination |= TERM_LVD;
+ break;
+
+ /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+ case 0x0:
+ break;
+ }
+ }
- /*
- * Set RISC ICQ physical address start value.
- * carr_pa is LE, must be native before write
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+ /*
+ * Clear any set TERM_SE and TERM_LVD bits.
+ */
+ scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+
+ /*
+ * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+
+ /*
+ * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+ * and set possibly modified termination control bits in the Microcode
+ * SCSI_CFG1 Register Value.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control and reset DIS_TERM_DRV
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C0800 has 16KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ /*
+ * Build the carrier freelist.
+ *
+ * Driver must have already allocated memory and set 'carrier_buf'.
+ */
+ ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
- {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+ do {
+ /*
+ * Get physical address for the carrier 'carrp'.
+ */
+ contig_len = sizeof(ADV_CARR_T);
+ carr_paddr =
+ cpu_to_le32(DvcGetPhyAddr
+ (asc_dvc, NULL, (uchar *)carrp,
+ (ADV_SDCNT *)&contig_len,
+ ADV_IS_CARRIER_FLAG));
- /*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
- */
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ buf_size -= sizeof(ADV_CARR_T);
- /*
- * Set RISC IRQ physical address start value.
- *
- * carr_pa is LE, must be native before write *
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
+ /*
+ * If the current carrier is not physically contiguous, then
+ * maybe there was a page crossing. Try the next carrier aligned
+ * start address.
+ */
+ if (contig_len < sizeof(ADV_CARR_T)) {
+ carrp++;
+ continue;
+ }
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+ /*
+ * Insert the carrier at the beginning of the freelist.
+ */
+ carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = carrp;
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
+ carrp++;
+ }
+ while (buf_size > 0);
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
- {
- /*
- * If the BIOS Signature is present in memory, restore the
- * BIOS Handshake Configuration Table and do not perform
- * a SCSI Bus Reset.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
- {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
- } else
- {
- if (AdvResetSB(asc_dvc) != ADV_TRUE)
- {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
- }
- }
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value.
+ * carr_pa is LE, must be native before write
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ *
+ * carr_pa is LE, must be native before write *
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
- return warn_code;
+ return warn_code;
}
/*
@@ -15740,630 +15510,617 @@ AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
*
* Needed after initialization for error recovery.
*/
-STATIC int
-AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- long word;
- int j;
- int adv_asc38C1600_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar byte;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
- uchar max_cmd[ASC_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0)
- {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
- {
- asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
- {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ASC_MAX_TID; tid++)
- {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * RAM BIST (Built-In Self Test)
- *
- * Address : I/O base + offset 0x38h register (byte).
- * Function: Bit 7-6(RW) : RAM mode
- * Normal Mode : 0x00
- * Pre-test Mode : 0x40
- * RAM Test Mode : 0x80
- * Bit 5 : unused
- * Bit 4(RO) : Done bit
- * Bit 3-0(RO) : Status
- * Host Error : 0x08
- * Int_RAM Error : 0x04
- * RISC Error : 0x02
- * SCSI Error : 0x01
- * No Error : 0x00
- *
- * Note: RAM BIST code should be put right here, before loading the
- * microcode and after saving the RISC memory BIOS region.
- */
-
- /*
- * LRAM Pre-test
- *
- * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
- * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
- * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
- * to NORMAL_MODE, return an error too.
- */
- for (i = 0; i < 2; i++)
- {
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
- {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
-
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
- != NORMAL_VALUE)
- {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
- }
-
- /*
- * LRAM Test - It takes about 1.5 ms to run through the test.
- *
- * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
- * If Done bit not set or Status not 0, save register byte, set the
- * err_code, and return an error.
- */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
-
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
- {
- /* Get here if Done bit not set or Status not 0. */
- asc_dvc->bist_err_code = byte; /* for BIOS display message */
- asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
- return ADV_ERROR;
- }
-
- /* We need to reset back to normal mode after LRAM test passes. */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- *
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- /*
- * Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc38C1600_size; i++)
- {
- if (_adv_asc38C1600_buf[i] == 0xff)
- {
- for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++)
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf[i + 3] << 8) |
- _adv_asc38C1600_buf[i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc38C1600_buf[i] == 0xfe)
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf[i + 2] << 8) |
- _adv_asc38C1600_buf[i + 1]));
- i += 2;
- word++;
- } else
- {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) |
- _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
- word++;
- }
- }
-
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc38C1600_expanded_size = word;
-
- /*
- * Clear the rest of ASC-38C1600 Internal RAM (32KB).
- */
- for (; word < ADV_38C1600_MEMSIZE; word += 2)
- {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc38C1600_expanded_size; word += 2)
- {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
-
- if (sum != _adv_asc38C1600_chksum)
- {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
- {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2)
- {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC38C1600.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
-
- /*
- * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
- * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
- * cable detection and then we are able to read C_DET[3:0].
- *
- * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
- * Microcode Default Value' section below.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
- {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * If the BIOS control flag AIPP (Asynchronous Information
- * Phase Protection) disable bit is not set, then set the firmware
- * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
- * AIPP checking and encoding.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0)
- {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_ENABLE_AIPP;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
- * and START_CTL_TH [3:2].
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
- {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
- }
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADV_DCNT sum;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ long word;
+ int j;
+ int adv_asc38C1600_expanded_size;
+ ADV_CARR_T *carrp;
+ ADV_DCNT contig_len;
+ ADV_SDCNT buf_size;
+ ADV_PADDR carr_paddr;
+ int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
+ uchar max_cmd[ASC_MAX_TID + 1];
+
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0) {
+ return ADV_ERROR;
+ }
- /*
- * Set microcode operating variables for DISC and SDTR_SPEED1,
- * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
- * configuration values.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- /*
- * Calculate SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- *
- * Each ASC-38C1600 function has only two cable detect bits.
- * The bus mode override bits are in IOPB_SOFT_OVER_WR.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
- /*
- * If the cable is reversed all of the SCSI_CTRL register signals
- * will be set. Check for and return an error if this condition is
- * found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
- {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
+ /*
+ * RAM BIST (Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
+
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++) {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0
+ || (byte & 0x0F) != PRE_TEST_VALUE) {
+ asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
+
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE) {
+ asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
+ }
- /*
- * Each ASC-38C1600 function has two connectors. Only an HVD device
- * can not be connected to either connector. An LVD device or SE device
- * may be connected to either connecor. If an SE device is connected,
- * then at most Ultra speed (20 Mhz) can be used on both connectors.
- *
- * If an HVD device is attached, return an error.
- */
- if (scsi_cfg1 & HVD)
- {
- asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
- return ADV_ERROR;
- }
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
+
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
- /*
- * Each function in the ASC-38C1600 uses only the SE cable detect and
- * termination because there are two connectors for each function. Each
- * function may use either LVD or SE mode. Corresponding the SE automatic
- * termination control EEPROM bits are used for each function. Each
- * function has its own EEPROM. If SE automatic control is enabled for
- * the function, then set the termination value based on a table listed
- * in a_condor.h.
- *
- * If manual termination is specified in the EEPROM for the function,
- * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
- * ready to be 'ored' into SCSI_CFG1.
- */
- if ((asc_dvc->cfg->termination & TERM_SE) == 0)
- {
- /* SE automatic termination control is enabled. */
- switch(scsi_cfg1 & C_DET_SE)
- {
- /* TERM_SE_HI: on, TERM_SE_LO: on */
- case 0x1: case 0x2: case 0x3:
- asc_dvc->cfg->termination |= TERM_SE;
- break;
-
- case 0x0:
- if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0)
- {
- /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
- }
- else
- {
- /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
- asc_dvc->cfg->termination |= TERM_SE_HI;
- }
- break;
- }
- }
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+ /*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ *
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+ /*
+ * Assume the following compressed format of the microcode buffer:
+ *
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
+ *
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ */
+ word = 0;
+ for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
+ if (_adv_asc38C1600_buf[i] == 0xff) {
+ for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc38C1600_buf
+ [i +
+ 3] << 8) |
+ _adv_asc38C1600_buf
+ [i + 2]));
+ word++;
+ }
+ i += 3;
+ } else if (_adv_asc38C1600_buf[i] == 0xfe) {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc38C1600_buf
+ [i +
+ 2] << 8) |
+ _adv_asc38C1600_buf[i
+ +
+ 1]));
+ i += 2;
+ word++;
+ } else {
+ AdvWriteWordAutoIncLram(iop_base, (((ushort)
+ _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
+ word++;
+ }
+ }
- /*
- * Clear any set TERM_SE bits.
- */
- scsi_cfg1 &= ~TERM_SE;
+ /*
+ * Set 'word' for later use to clear the rest of memory and save
+ * the expanded mcode size.
+ */
+ word *= 2;
+ adv_asc38C1600_expanded_size = word;
+
+ /*
+ * Clear the rest of ASC-38C1600 Internal RAM (32KB).
+ */
+ for (; word < ADV_38C1600_MEMSIZE; word += 2) {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ }
- /*
- * Invert the TERM_SE bits and then set 'scsi_cfg1'.
- */
- scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
+ /*
+ * Verify the microcode checksum.
+ */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- /*
- * Clear Big Endian and Terminator Polarity bits and set possibly
- * modified termination control bits in the Microcode SCSI_CFG1
- * Register Value.
- *
- * Big Endian bit is not used even on big endian machines.
- */
- scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+ for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set possibly modified termination control bits in the Microcode
- * SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+ if (sum != _adv_asc38C1600_chksum) {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return ADV_ERROR;
+ }
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-38C1600 has 32KB internal memory.
- *
- * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
- * out a special 16K Adv Library and Microcode version. After the issue
- * resolved, we should turn back to the 32K support. Both a_condor.h and
- * mcode.sas files also need to be updated.
- *
- * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- * BIOS_EN | RAM_SZ_32KB);
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, BIOS_EN | RAM_SZ_16KB);
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
+
+ /*
+ * Set the chip type to indicate the ASC38C1600.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
+
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+ scsi_cfg1 | DIS_TERM_DRV);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- /*
- * Build the carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
-
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
- {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else
- {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
+ /*
+ * If the BIOS control flag AIPP (Asynchronous Information
+ * Phase Protection) disable bit is not set, then set the firmware
+ * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+ * AIPP checking and encoding.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_ENABLE_AIPP;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- do {
- /*
- * Get physical address for the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
- (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
-
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T))
- {
- carrp++;
- continue;
- }
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
+ /*
+ * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+ * and START_CTL_TH [3:2].
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in AdvInquiryHandling() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
- {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
+
+ /*
+ * Calculate SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ *
+ * Each ASC-38C1600 function has only two cable detect bits.
+ * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If the cable is reversed all of the SCSI_CTRL register signals
+ * will be set. Check for and return an error if this condition is
+ * found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ /*
+ * Each ASC-38C1600 function has two connectors. Only an HVD device
+ * can not be connected to either connector. An LVD device or SE device
+ * may be connected to either connecor. If an SE device is connected,
+ * then at most Ultra speed (20 Mhz) can be used on both connectors.
+ *
+ * If an HVD device is attached, return an error.
+ */
+ if (scsi_cfg1 & HVD) {
+ asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
- /*
- * Set RISC ICQ physical address start value. Initialize the
- * COMMA register to the same value otherwise the RISC will
- * prematurely detect a command is available.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
- AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
- le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+ /*
+ * Each function in the ASC-38C1600 uses only the SE cable detect and
+ * termination because there are two connectors for each function. Each
+ * function may use either LVD or SE mode. Corresponding the SE automatic
+ * termination control EEPROM bits are used for each function. Each
+ * function has its own EEPROM. If SE automatic control is enabled for
+ * the function, then set the termination value based on a table listed
+ * in a_condor.h.
+ *
+ * If manual termination is specified in the EEPROM for the function,
+ * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+ * ready to be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+ /* SE automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_SE) {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
+
+ case 0x0:
+ if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
+ /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+ } else {
+ /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ }
+ break;
+ }
+ }
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
- {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+ /*
+ * Clear any set TERM_SE bits.
+ */
+ scsi_cfg1 &= ~TERM_SE;
+
+ /*
+ * Invert the TERM_SE bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
+
+ /*
+ * Clear Big Endian and Terminator Polarity bits and set possibly
+ * modified termination control bits in the Microcode SCSI_CFG1
+ * Register Value.
+ *
+ * Big Endian bit is not used even on big endian machines.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control bits in the Microcode
+ * SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C1600 has 32KB internal memory.
+ *
+ * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+ * out a special 16K Adv Library and Microcode version. After the issue
+ * resolved, we should turn back to the 32K support. Both a_condor.h and
+ * mcode.sas files also need to be updated.
+ *
+ * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ * BIOS_EN | RAM_SZ_32KB);
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ /*
+ * Build the carrier freelist.
+ *
+ * Driver must have already allocated memory and set 'carrier_buf'.
+ */
+
+ ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
- /*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
- */
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ do {
+ /*
+ * Get physical address for the carrier 'carrp'.
+ */
+ contig_len = sizeof(ADV_CARR_T);
+ carr_paddr =
+ cpu_to_le32(DvcGetPhyAddr
+ (asc_dvc, NULL, (uchar *)carrp,
+ (ADV_SDCNT *)&contig_len,
+ ADV_IS_CARRIER_FLAG));
- /*
- * Set RISC IRQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
+ buf_size -= sizeof(ADV_CARR_T);
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
+ /*
+ * If the current carrier is not physically contiguous, then
+ * maybe there was a page crossing. Try the next carrier aligned
+ * start address.
+ */
+ if (contig_len < sizeof(ADV_CARR_T)) {
+ carrp++;
+ continue;
+ }
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ /*
+ * Insert the carrier at the beginning of the freelist.
+ */
+ carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = carrp;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
- {
- /*
- * If the BIOS Signature is present in memory, restore the
- * per TID microcode operating variables.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
- {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ASC_MAX_TID; tid++)
- {
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
- } else
- {
- if (AdvResetSB(asc_dvc) != ADV_TRUE)
- {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
- }
- }
+ carrp++;
+ }
+ while (buf_size > 0);
+
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value. Initialize the
+ * COMMA register to the same value otherwise the RISC will
+ * prematurely detect a command is available.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+ AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+ le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * per TID microcode operating variables.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
- return warn_code;
+ return warn_code;
}
/*
@@ -16378,164 +16135,146 @@ AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-STATIC int __init
-AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADVEEP_3550_CONFIG eep_config;
- int i;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADVEEP_3550_CONFIG eep_config;
+ int i;
- iop_base = asc_dvc->iop_base;
+ iop_base = asc_dvc->iop_base;
- warn_code = 0;
+ warn_code = 0;
- /*
- * Read the board's EEPROM configuration.
- *
- * Set default values if a bad checksum is found.
- */
- if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
- {
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
-
- /*
- * Set EEPROM default values.
- */
- for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
- {
- *((uchar *) &eep_config + i) =
- *((uchar *) &Default_3550_EEPROM_Config + i);
- }
-
- /*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
- */
- eep_config.serial_number_word3 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
- eep_config.serial_number_word2 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
- eep_config.serial_number_word1 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
-
- AdvSet3550EEPConfig(iop_base, &eep_config);
- }
- /*
- * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
- * EEPROM configuration that was read.
- *
- * This is the mapping of EEPROM fields to Adv Library fields.
- */
- asc_dvc->wdtr_able = eep_config.wdtr_able;
- asc_dvc->sdtr_able = eep_config.sdtr_able;
- asc_dvc->ultra_able = eep_config.ultra_able;
- asc_dvc->tagqng_able = eep_config.tagqng_able;
- asc_dvc->cfg->disc_enable = eep_config.disc_enable;
- asc_dvc->max_host_qng = eep_config.max_host_qng;
- asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
- asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
- asc_dvc->start_motor = eep_config.start_motor;
- asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
- asc_dvc->bios_ctrl = eep_config.bios_ctrl;
- asc_dvc->no_scam = eep_config.scam_tolerant;
- asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
- asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
- asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+ /*
+ * Read the board's EEPROM configuration.
+ *
+ * Set default values if a bad checksum is found.
+ */
+ if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
- /*
- * Set the host maximum queuing (max. 253, min. 16) and the per device
- * maximum queuing (max. 63, min. 4).
- */
- if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
- {
- eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
- } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
- {
- /* If the value is zero, assume it is uninitialized. */
- if (eep_config.max_host_qng == 0)
- {
- eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
- } else
- {
- eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
- }
- }
+ /*
+ * Set EEPROM default values.
+ */
+ for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
+ *((uchar *)&eep_config + i) =
+ *((uchar *)&Default_3550_EEPROM_Config + i);
+ }
- if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
- {
- eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
- } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
- {
- /* If the value is zero, assume it is uninitialized. */
- if (eep_config.max_dvc_qng == 0)
- {
- eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
- } else
- {
- eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
- }
- }
+ /*
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ eep_config.serial_number_word3 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
- /*
- * If 'max_dvc_qng' is greater than 'max_host_qng', then
- * set 'max_dvc_qng' to 'max_host_qng'.
- */
- if (eep_config.max_dvc_qng > eep_config.max_host_qng)
- {
- eep_config.max_dvc_qng = eep_config.max_host_qng;
- }
+ eep_config.serial_number_word2 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
- /*
- * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
- * values based on possibly adjusted EEPROM values.
- */
- asc_dvc->max_host_qng = eep_config.max_host_qng;
- asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ eep_config.serial_number_word1 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+
+ AdvSet3550EEPConfig(iop_base, &eep_config);
+ }
+ /*
+ * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+ * EEPROM configuration that was read.
+ *
+ * This is the mapping of EEPROM fields to Adv Library fields.
+ */
+ asc_dvc->wdtr_able = eep_config.wdtr_able;
+ asc_dvc->sdtr_able = eep_config.sdtr_able;
+ asc_dvc->ultra_able = eep_config.ultra_able;
+ asc_dvc->tagqng_able = eep_config.tagqng_able;
+ asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+ asc_dvc->start_motor = eep_config.start_motor;
+ asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+ asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+ asc_dvc->no_scam = eep_config.scam_tolerant;
+ asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+ asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+ asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+ /*
+ * Set the host maximum queuing (max. 253, min. 16) and the per device
+ * maximum queuing (max. 63, min. 4).
+ */
+ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_host_qng == 0) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else {
+ eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+ }
+ }
+ if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_dvc_qng == 0) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else {
+ eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+ }
+ }
- /*
- * If the EEPROM 'termination' field is set to automatic (0), then set
- * the ADV_DVC_CFG 'termination' field to automatic also.
- *
- * If the termination is specified with a non-zero 'termination'
- * value check that a legal value is set and set the ADV_DVC_CFG
- * 'termination' field appropriately.
- */
- if (eep_config.termination == 0)
- {
- asc_dvc->cfg->termination = 0; /* auto termination */
- } else
- {
- /* Enable manual control with low off / high off. */
- if (eep_config.termination == 1)
- {
- asc_dvc->cfg->termination = TERM_CTL_SEL;
-
- /* Enable manual control with low off / high on. */
- } else if (eep_config.termination == 2)
- {
- asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
-
- /* Enable manual control with low on / high on. */
- } else if (eep_config.termination == 3)
- {
- asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
- } else
- {
- /*
- * The EEPROM 'termination' field contains a bad value. Use
- * automatic termination instead.
- */
- asc_dvc->cfg->termination = 0;
- warn_code |= ASC_WARN_EEPROM_TERMINATION;
- }
- }
+ /*
+ * If 'max_dvc_qng' is greater than 'max_host_qng', then
+ * set 'max_dvc_qng' to 'max_host_qng'.
+ */
+ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+ eep_config.max_dvc_qng = eep_config.max_host_qng;
+ }
- return warn_code;
+ /*
+ * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+ * values based on possibly adjusted EEPROM values.
+ */
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+ /*
+ * If the EEPROM 'termination' field is set to automatic (0), then set
+ * the ADV_DVC_CFG 'termination' field to automatic also.
+ *
+ * If the termination is specified with a non-zero 'termination'
+ * value check that a legal value is set and set the ADV_DVC_CFG
+ * 'termination' field appropriately.
+ */
+ if (eep_config.termination == 0) {
+ asc_dvc->cfg->termination = 0; /* auto termination */
+ } else {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination == 1) {
+ asc_dvc->cfg->termination = TERM_CTL_SEL;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination == 2) {
+ asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination == 3) {
+ asc_dvc->cfg->termination =
+ TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+ } else {
+ /*
+ * The EEPROM 'termination' field contains a bad value. Use
+ * automatic termination instead.
+ */
+ asc_dvc->cfg->termination = 0;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
+
+ return warn_code;
}
/*
@@ -16550,225 +16289,195 @@ AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-STATIC int __init
-AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADVEEP_38C0800_CONFIG eep_config;
- int i;
- uchar tid, termination;
- ushort sdtr_speed = 0;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADVEEP_38C0800_CONFIG eep_config;
+ int i;
+ uchar tid, termination;
+ ushort sdtr_speed = 0;
+
+ iop_base = asc_dvc->iop_base;
+
+ warn_code = 0;
+
+ /*
+ * Read the board's EEPROM configuration.
+ *
+ * Set default values if a bad checksum is found.
+ */
+ if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
+ eep_config.check_sum) {
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
- iop_base = asc_dvc->iop_base;
+ /*
+ * Set EEPROM default values.
+ */
+ for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
+ *((uchar *)&eep_config + i) =
+ *((uchar *)&Default_38C0800_EEPROM_Config + i);
+ }
- warn_code = 0;
+ /*
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ eep_config.serial_number_word3 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
- /*
- * Read the board's EEPROM configuration.
- *
- * Set default values if a bad checksum is found.
- */
- if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
- {
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
-
- /*
- * Set EEPROM default values.
- */
- for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
- {
- *((uchar *) &eep_config + i) =
- *((uchar *) &Default_38C0800_EEPROM_Config + i);
- }
-
- /*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
- */
- eep_config.serial_number_word3 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
- eep_config.serial_number_word2 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
- eep_config.serial_number_word1 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
-
- AdvSet38C0800EEPConfig(iop_base, &eep_config);
- }
- /*
- * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
- * EEPROM configuration that was read.
- *
- * This is the mapping of EEPROM fields to Adv Library fields.
- */
- asc_dvc->wdtr_able = eep_config.wdtr_able;
- asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
- asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
- asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
- asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
- asc_dvc->tagqng_able = eep_config.tagqng_able;
- asc_dvc->cfg->disc_enable = eep_config.disc_enable;
- asc_dvc->max_host_qng = eep_config.max_host_qng;
- asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
- asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
- asc_dvc->start_motor = eep_config.start_motor;
- asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
- asc_dvc->bios_ctrl = eep_config.bios_ctrl;
- asc_dvc->no_scam = eep_config.scam_tolerant;
- asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
- asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
- asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+ eep_config.serial_number_word2 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
- /*
- * For every Target ID if any of its 'sdtr_speed[1234]' bits
- * are set, then set an 'sdtr_able' bit for it.
- */
- asc_dvc->sdtr_able = 0;
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- if (tid == 0)
- {
- sdtr_speed = asc_dvc->sdtr_speed1;
- } else if (tid == 4)
- {
- sdtr_speed = asc_dvc->sdtr_speed2;
- } else if (tid == 8)
- {
- sdtr_speed = asc_dvc->sdtr_speed3;
- } else if (tid == 12)
- {
- sdtr_speed = asc_dvc->sdtr_speed4;
- }
- if (sdtr_speed & ADV_MAX_TID)
- {
- asc_dvc->sdtr_able |= (1 << tid);
- }
- sdtr_speed >>= 4;
- }
+ eep_config.serial_number_word1 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
- /*
- * Set the host maximum queuing (max. 253, min. 16) and the per device
- * maximum queuing (max. 63, min. 4).
- */
- if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
- {
- eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
- } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
- {
- /* If the value is zero, assume it is uninitialized. */
- if (eep_config.max_host_qng == 0)
- {
- eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
- } else
- {
- eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
- }
- }
+ AdvSet38C0800EEPConfig(iop_base, &eep_config);
+ }
+ /*
+ * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+ * EEPROM configuration that was read.
+ *
+ * This is the mapping of EEPROM fields to Adv Library fields.
+ */
+ asc_dvc->wdtr_able = eep_config.wdtr_able;
+ asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+ asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+ asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+ asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+ asc_dvc->tagqng_able = eep_config.tagqng_able;
+ asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+ asc_dvc->start_motor = eep_config.start_motor;
+ asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+ asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+ asc_dvc->no_scam = eep_config.scam_tolerant;
+ asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+ asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+ asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+ /*
+ * For every Target ID if any of its 'sdtr_speed[1234]' bits
+ * are set, then set an 'sdtr_able' bit for it.
+ */
+ asc_dvc->sdtr_able = 0;
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ if (tid == 0) {
+ sdtr_speed = asc_dvc->sdtr_speed1;
+ } else if (tid == 4) {
+ sdtr_speed = asc_dvc->sdtr_speed2;
+ } else if (tid == 8) {
+ sdtr_speed = asc_dvc->sdtr_speed3;
+ } else if (tid == 12) {
+ sdtr_speed = asc_dvc->sdtr_speed4;
+ }
+ if (sdtr_speed & ADV_MAX_TID) {
+ asc_dvc->sdtr_able |= (1 << tid);
+ }
+ sdtr_speed >>= 4;
+ }
- if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
- {
- eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
- } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
- {
- /* If the value is zero, assume it is uninitialized. */
- if (eep_config.max_dvc_qng == 0)
- {
- eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
- } else
- {
- eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
- }
- }
+ /*
+ * Set the host maximum queuing (max. 253, min. 16) and the per device
+ * maximum queuing (max. 63, min. 4).
+ */
+ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_host_qng == 0) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else {
+ eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+ }
+ }
- /*
- * If 'max_dvc_qng' is greater than 'max_host_qng', then
- * set 'max_dvc_qng' to 'max_host_qng'.
- */
- if (eep_config.max_dvc_qng > eep_config.max_host_qng)
- {
- eep_config.max_dvc_qng = eep_config.max_host_qng;
- }
+ if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_dvc_qng == 0) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else {
+ eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+ }
+ }
- /*
- * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
- * values based on possibly adjusted EEPROM values.
- */
- asc_dvc->max_host_qng = eep_config.max_host_qng;
- asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ /*
+ * If 'max_dvc_qng' is greater than 'max_host_qng', then
+ * set 'max_dvc_qng' to 'max_host_qng'.
+ */
+ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+ eep_config.max_dvc_qng = eep_config.max_host_qng;
+ }
- /*
- * If the EEPROM 'termination' field is set to automatic (0), then set
- * the ADV_DVC_CFG 'termination' field to automatic also.
- *
- * If the termination is specified with a non-zero 'termination'
- * value check that a legal value is set and set the ADV_DVC_CFG
- * 'termination' field appropriately.
- */
- if (eep_config.termination_se == 0)
- {
- termination = 0; /* auto termination for SE */
- } else
- {
- /* Enable manual control with low off / high off. */
- if (eep_config.termination_se == 1)
- {
- termination = 0;
-
- /* Enable manual control with low off / high on. */
- } else if (eep_config.termination_se == 2)
- {
- termination = TERM_SE_HI;
-
- /* Enable manual control with low on / high on. */
- } else if (eep_config.termination_se == 3)
- {
- termination = TERM_SE;
- } else
- {
- /*
- * The EEPROM 'termination_se' field contains a bad value.
- * Use automatic termination instead.
- */
- termination = 0;
- warn_code |= ASC_WARN_EEPROM_TERMINATION;
- }
- }
+ /*
+ * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+ * values based on possibly adjusted EEPROM values.
+ */
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+ /*
+ * If the EEPROM 'termination' field is set to automatic (0), then set
+ * the ADV_DVC_CFG 'termination' field to automatic also.
+ *
+ * If the termination is specified with a non-zero 'termination'
+ * value check that a legal value is set and set the ADV_DVC_CFG
+ * 'termination' field appropriately.
+ */
+ if (eep_config.termination_se == 0) {
+ termination = 0; /* auto termination for SE */
+ } else {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination_se == 1) {
+ termination = 0;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination_se == 2) {
+ termination = TERM_SE_HI;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination_se == 3) {
+ termination = TERM_SE;
+ } else {
+ /*
+ * The EEPROM 'termination_se' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ termination = 0;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
- if (eep_config.termination_lvd == 0)
- {
- asc_dvc->cfg->termination = termination; /* auto termination for LVD */
- } else
- {
- /* Enable manual control with low off / high off. */
- if (eep_config.termination_lvd == 1)
- {
- asc_dvc->cfg->termination = termination;
-
- /* Enable manual control with low off / high on. */
- } else if (eep_config.termination_lvd == 2)
- {
- asc_dvc->cfg->termination = termination | TERM_LVD_HI;
-
- /* Enable manual control with low on / high on. */
- } else if (eep_config.termination_lvd == 3)
- {
- asc_dvc->cfg->termination =
- termination | TERM_LVD;
- } else
- {
- /*
- * The EEPROM 'termination_lvd' field contains a bad value.
- * Use automatic termination instead.
- */
- asc_dvc->cfg->termination = termination;
- warn_code |= ASC_WARN_EEPROM_TERMINATION;
- }
- }
+ if (eep_config.termination_lvd == 0) {
+ asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+ } else {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination_lvd == 1) {
+ asc_dvc->cfg->termination = termination;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination_lvd == 2) {
+ asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination_lvd == 3) {
+ asc_dvc->cfg->termination = termination | TERM_LVD;
+ } else {
+ /*
+ * The EEPROM 'termination_lvd' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ asc_dvc->cfg->termination = termination;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
- return warn_code;
+ return warn_code;
}
/*
@@ -16783,265 +16492,240 @@ AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-STATIC int __init
-AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADVEEP_38C1600_CONFIG eep_config;
- int i;
- uchar tid, termination;
- ushort sdtr_speed = 0;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADVEEP_38C1600_CONFIG eep_config;
+ int i;
+ uchar tid, termination;
+ ushort sdtr_speed = 0;
+
+ iop_base = asc_dvc->iop_base;
+
+ warn_code = 0;
+
+ /*
+ * Read the board's EEPROM configuration.
+ *
+ * Set default values if a bad checksum is found.
+ */
+ if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
+ eep_config.check_sum) {
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
- iop_base = asc_dvc->iop_base;
+ /*
+ * Set EEPROM default values.
+ */
+ for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
+ if (i == 1
+ && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
+ 0) {
+ /*
+ * Set Function 1 EEPROM Word 0 MSB
+ *
+ * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
+ * EEPROM bits.
+ *
+ * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
+ * old Mac system booting problem. The Expansion ROM must
+ * be disabled in Function 1 for these systems.
+ *
+ */
+ *((uchar *)&eep_config + i) =
+ ((*
+ ((uchar *)&Default_38C1600_EEPROM_Config
+ +
+ i)) &
+ (~
+ (((ADV_EEPROM_BIOS_ENABLE |
+ ADV_EEPROM_INTAB) >> 8) & 0xFF)));
+
+ /*
+ * Set the INTAB (bit 11) if the GPIO 0 input indicates
+ * the Function 1 interrupt line is wired to INTA.
+ *
+ * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+ * 1 - Function 1 interrupt line wired to INT A.
+ * 0 - Function 1 interrupt line wired to INT B.
+ *
+ * Note: Adapter boards always have Function 0 wired to INTA.
+ * Put all 5 GPIO bits in input mode and then read
+ * their input values.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
+ 0);
+ if (AdvReadByteRegister
+ (iop_base, IOPB_GPIO_DATA) & 0x01) {
+ /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
+ *((uchar *)&eep_config + i) |=
+ ((ADV_EEPROM_INTAB >> 8) & 0xFF);
+ }
+ } else {
+ *((uchar *)&eep_config + i) =
+ *((uchar *)&Default_38C1600_EEPROM_Config
+ + i);
+ }
+ }
- warn_code = 0;
+ /*
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ eep_config.serial_number_word3 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
- /*
- * Read the board's EEPROM configuration.
- *
- * Set default values if a bad checksum is found.
- */
- if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
- {
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
-
- /*
- * Set EEPROM default values.
- */
- for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++)
- {
- if (i == 1 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != 0)
- {
- /*
- * Set Function 1 EEPROM Word 0 MSB
- *
- * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
- * EEPROM bits.
- *
- * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
- * old Mac system booting problem. The Expansion ROM must
- * be disabled in Function 1 for these systems.
- *
- */
- *((uchar *) &eep_config + i) =
- ((*((uchar *) &Default_38C1600_EEPROM_Config + i)) &
- (~(((ADV_EEPROM_BIOS_ENABLE | ADV_EEPROM_INTAB) >> 8) &
- 0xFF)));
-
- /*
- * Set the INTAB (bit 11) if the GPIO 0 input indicates
- * the Function 1 interrupt line is wired to INTA.
- *
- * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
- * 1 - Function 1 interrupt line wired to INT A.
- * 0 - Function 1 interrupt line wired to INT B.
- *
- * Note: Adapter boards always have Function 0 wired to INTA.
- * Put all 5 GPIO bits in input mode and then read
- * their input values.
- */
- AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
- if (AdvReadByteRegister(iop_base, IOPB_GPIO_DATA) & 0x01)
- {
- /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
- *((uchar *) &eep_config + i) |=
- ((ADV_EEPROM_INTAB >> 8) & 0xFF);
- }
- }
- else
- {
- *((uchar *) &eep_config + i) =
- *((uchar *) &Default_38C1600_EEPROM_Config + i);
- }
- }
-
- /*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
- */
- eep_config.serial_number_word3 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
- eep_config.serial_number_word2 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
- eep_config.serial_number_word1 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
-
- AdvSet38C1600EEPConfig(iop_base, &eep_config);
- }
+ eep_config.serial_number_word2 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
- /*
- * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
- * EEPROM configuration that was read.
- *
- * This is the mapping of EEPROM fields to Adv Library fields.
- */
- asc_dvc->wdtr_able = eep_config.wdtr_able;
- asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
- asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
- asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
- asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
- asc_dvc->ppr_able = 0;
- asc_dvc->tagqng_able = eep_config.tagqng_able;
- asc_dvc->cfg->disc_enable = eep_config.disc_enable;
- asc_dvc->max_host_qng = eep_config.max_host_qng;
- asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
- asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
- asc_dvc->start_motor = eep_config.start_motor;
- asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
- asc_dvc->bios_ctrl = eep_config.bios_ctrl;
- asc_dvc->no_scam = eep_config.scam_tolerant;
+ eep_config.serial_number_word1 =
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
- /*
- * For every Target ID if any of its 'sdtr_speed[1234]' bits
- * are set, then set an 'sdtr_able' bit for it.
- */
- asc_dvc->sdtr_able = 0;
- for (tid = 0; tid <= ASC_MAX_TID; tid++)
- {
- if (tid == 0)
- {
- sdtr_speed = asc_dvc->sdtr_speed1;
- } else if (tid == 4)
- {
- sdtr_speed = asc_dvc->sdtr_speed2;
- } else if (tid == 8)
- {
- sdtr_speed = asc_dvc->sdtr_speed3;
- } else if (tid == 12)
- {
- sdtr_speed = asc_dvc->sdtr_speed4;
- }
- if (sdtr_speed & ASC_MAX_TID)
- {
- asc_dvc->sdtr_able |= (1 << tid);
- }
- sdtr_speed >>= 4;
- }
+ AdvSet38C1600EEPConfig(iop_base, &eep_config);
+ }
- /*
- * Set the host maximum queuing (max. 253, min. 16) and the per device
- * maximum queuing (max. 63, min. 4).
- */
- if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
- {
- eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
- } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
- {
- /* If the value is zero, assume it is uninitialized. */
- if (eep_config.max_host_qng == 0)
- {
- eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
- } else
- {
- eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
- }
- }
+ /*
+ * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+ * EEPROM configuration that was read.
+ *
+ * This is the mapping of EEPROM fields to Adv Library fields.
+ */
+ asc_dvc->wdtr_able = eep_config.wdtr_able;
+ asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+ asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+ asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+ asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+ asc_dvc->ppr_able = 0;
+ asc_dvc->tagqng_able = eep_config.tagqng_able;
+ asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
+ asc_dvc->start_motor = eep_config.start_motor;
+ asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+ asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+ asc_dvc->no_scam = eep_config.scam_tolerant;
+
+ /*
+ * For every Target ID if any of its 'sdtr_speed[1234]' bits
+ * are set, then set an 'sdtr_able' bit for it.
+ */
+ asc_dvc->sdtr_able = 0;
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ if (tid == 0) {
+ sdtr_speed = asc_dvc->sdtr_speed1;
+ } else if (tid == 4) {
+ sdtr_speed = asc_dvc->sdtr_speed2;
+ } else if (tid == 8) {
+ sdtr_speed = asc_dvc->sdtr_speed3;
+ } else if (tid == 12) {
+ sdtr_speed = asc_dvc->sdtr_speed4;
+ }
+ if (sdtr_speed & ASC_MAX_TID) {
+ asc_dvc->sdtr_able |= (1 << tid);
+ }
+ sdtr_speed >>= 4;
+ }
- if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
- {
- eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
- } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
- {
- /* If the value is zero, assume it is uninitialized. */
- if (eep_config.max_dvc_qng == 0)
- {
- eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
- } else
- {
- eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
- }
- }
+ /*
+ * Set the host maximum queuing (max. 253, min. 16) and the per device
+ * maximum queuing (max. 63, min. 4).
+ */
+ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_host_qng == 0) {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else {
+ eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+ }
+ }
- /*
- * If 'max_dvc_qng' is greater than 'max_host_qng', then
- * set 'max_dvc_qng' to 'max_host_qng'.
- */
- if (eep_config.max_dvc_qng > eep_config.max_host_qng)
- {
- eep_config.max_dvc_qng = eep_config.max_host_qng;
- }
+ if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_dvc_qng == 0) {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else {
+ eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+ }
+ }
- /*
- * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
- * values based on possibly adjusted EEPROM values.
- */
- asc_dvc->max_host_qng = eep_config.max_host_qng;
- asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ /*
+ * If 'max_dvc_qng' is greater than 'max_host_qng', then
+ * set 'max_dvc_qng' to 'max_host_qng'.
+ */
+ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+ eep_config.max_dvc_qng = eep_config.max_host_qng;
+ }
- /*
- * If the EEPROM 'termination' field is set to automatic (0), then set
- * the ASC_DVC_CFG 'termination' field to automatic also.
- *
- * If the termination is specified with a non-zero 'termination'
- * value check that a legal value is set and set the ASC_DVC_CFG
- * 'termination' field appropriately.
- */
- if (eep_config.termination_se == 0)
- {
- termination = 0; /* auto termination for SE */
- } else
- {
- /* Enable manual control with low off / high off. */
- if (eep_config.termination_se == 1)
- {
- termination = 0;
-
- /* Enable manual control with low off / high on. */
- } else if (eep_config.termination_se == 2)
- {
- termination = TERM_SE_HI;
-
- /* Enable manual control with low on / high on. */
- } else if (eep_config.termination_se == 3)
- {
- termination = TERM_SE;
- } else
- {
- /*
- * The EEPROM 'termination_se' field contains a bad value.
- * Use automatic termination instead.
- */
- termination = 0;
- warn_code |= ASC_WARN_EEPROM_TERMINATION;
- }
- }
+ /*
+ * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
+ * values based on possibly adjusted EEPROM values.
+ */
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+ /*
+ * If the EEPROM 'termination' field is set to automatic (0), then set
+ * the ASC_DVC_CFG 'termination' field to automatic also.
+ *
+ * If the termination is specified with a non-zero 'termination'
+ * value check that a legal value is set and set the ASC_DVC_CFG
+ * 'termination' field appropriately.
+ */
+ if (eep_config.termination_se == 0) {
+ termination = 0; /* auto termination for SE */
+ } else {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination_se == 1) {
+ termination = 0;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination_se == 2) {
+ termination = TERM_SE_HI;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination_se == 3) {
+ termination = TERM_SE;
+ } else {
+ /*
+ * The EEPROM 'termination_se' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ termination = 0;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
- if (eep_config.termination_lvd == 0)
- {
- asc_dvc->cfg->termination = termination; /* auto termination for LVD */
- } else
- {
- /* Enable manual control with low off / high off. */
- if (eep_config.termination_lvd == 1)
- {
- asc_dvc->cfg->termination = termination;
-
- /* Enable manual control with low off / high on. */
- } else if (eep_config.termination_lvd == 2)
- {
- asc_dvc->cfg->termination = termination | TERM_LVD_HI;
-
- /* Enable manual control with low on / high on. */
- } else if (eep_config.termination_lvd == 3)
- {
- asc_dvc->cfg->termination =
- termination | TERM_LVD;
- } else
- {
- /*
- * The EEPROM 'termination_lvd' field contains a bad value.
- * Use automatic termination instead.
- */
- asc_dvc->cfg->termination = termination;
- warn_code |= ASC_WARN_EEPROM_TERMINATION;
- }
- }
+ if (eep_config.termination_lvd == 0) {
+ asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+ } else {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination_lvd == 1) {
+ asc_dvc->cfg->termination = termination;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination_lvd == 2) {
+ asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination_lvd == 3) {
+ asc_dvc->cfg->termination = termination | TERM_LVD;
+ } else {
+ /*
+ * The EEPROM 'termination_lvd' field contains a bad value.
+ * Use automatic termination instead.
+ */
+ asc_dvc->cfg->termination = termination;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
- return warn_code;
+ return warn_code;
}
/*
@@ -17049,45 +16733,42 @@ AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
*
* Return a checksum based on the EEPROM configuration read.
*/
-STATIC ushort __init
+static ushort __init
AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
- wbuf = (ushort *) cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END;
- eep_addr++, wbuf++)
- {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++; charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR;
- eep_addr++, wbuf++)
- {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
+
+ charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
+
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
+ }
+ }
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
+
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
+ }
+ }
+ return chksum;
}
/*
@@ -17095,46 +16776,42 @@ AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
*
* Return a checksum based on the EEPROM configuration read.
*/
-STATIC ushort __init
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
- ADVEEP_38C0800_CONFIG *cfg_buf)
+static ushort __init
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
- wbuf = (ushort *) cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END;
- eep_addr++, wbuf++)
- {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++; charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR;
- eep_addr++, wbuf++)
- {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
+
+ charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
+
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
+ }
+ }
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
+
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
+ }
+ }
+ return chksum;
}
/*
@@ -17142,81 +16819,74 @@ AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
*
* Return a checksum based on the EEPROM configuration read.
*/
-STATIC ushort __init
-AdvGet38C1600EEPConfig(AdvPortAddr iop_base,
- ADVEEP_38C1600_CONFIG *cfg_buf)
+static ushort __init
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort*) &ADVEEP_38C1600_Config_Field_IsChar;
- wbuf = (ushort *) cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END;
- eep_addr++, wbuf++)
- {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++; charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR;
- eep_addr++, wbuf++)
- {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
+
+ charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
+
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
+ }
+ }
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
+
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
+ }
+ }
+ return chksum;
}
/*
* Read the EEPROM from specified location
*/
-STATIC ushort __init
-AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
{
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_READ | eep_word_addr);
- AdvWaitEEPCmd(iop_base);
- return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_READ | eep_word_addr);
+ AdvWaitEEPCmd(iop_base);
+ return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
}
/*
* Wait for EEPROM command to complete
*/
-STATIC void __init
-AdvWaitEEPCmd(AdvPortAddr iop_base)
+static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
{
- int eep_delay_ms;
-
- for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++)
- {
- if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE)
- {
- break;
- }
- DvcSleepMilliSecond(1);
- }
- if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0)
- {
- ASC_ASSERT(0);
- }
- return;
+ int eep_delay_ms;
+
+ for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
+ if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
+ ASC_EEP_CMD_DONE) {
+ break;
+ }
+ DvcSleepMilliSecond(1);
+ }
+ if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
+ 0) {
+ ASC_ASSERT(0);
+ }
+ return;
}
/*
@@ -17225,201 +16895,202 @@ AdvWaitEEPCmd(AdvPortAddr iop_base)
void __init
AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
- ushort *wbuf;
- ushort addr, chksum;
- ushort *charfields;
-
- wbuf = (ushort *) cfg_buf;
- charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
- {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
-
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++; charfields++;
+ ushort *wbuf;
+ ushort addr, chksum;
+ ushort *charfields;
+
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+ chksum = 0;
+
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
+
+ /*
+ * Write EEPROM from word 0 to word 20.
+ */
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
+
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
+ }
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+ }
- /*
- * Write EEPROM OEM name at words 22 to 29.
- */
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
- {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
+ /*
+ * Write EEPROM checksum at word 21.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
+
+ /*
+ * Write EEPROM OEM name at words 22 to 29.
+ */
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
+
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+ return;
}
/*
* Write the EEPROM from 'cfg_buf'.
*/
void __init
-AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
- ADVEEP_38C0800_CONFIG *cfg_buf)
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
{
- ushort *wbuf;
- ushort *charfields;
- ushort addr, chksum;
-
- wbuf = (ushort *) cfg_buf;
- charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
- {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
-
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++; charfields++;
+ ushort *wbuf;
+ ushort *charfields;
+ ushort addr, chksum;
+
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+ chksum = 0;
+
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
+
+ /*
+ * Write EEPROM from word 0 to word 20.
+ */
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
+
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
+ }
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+ }
- /*
- * Write EEPROM OEM name at words 22 to 29.
- */
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
- {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
+ /*
+ * Write EEPROM checksum at word 21.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
+
+ /*
+ * Write EEPROM OEM name at words 22 to 29.
+ */
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
+
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+ return;
}
/*
* Write the EEPROM from 'cfg_buf'.
*/
void __init
-AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
- ADVEEP_38C1600_CONFIG *cfg_buf)
+AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
{
- ushort *wbuf;
- ushort *charfields;
- ushort addr, chksum;
-
- wbuf = (ushort *) cfg_buf;
- charfields = (ushort *) &ADVEEP_38C1600_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
- {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
-
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++; charfields++;
+ ushort *wbuf;
+ ushort *charfields;
+ ushort addr, chksum;
+
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+ chksum = 0;
+
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
+
+ /*
+ * Write EEPROM from word 0 to word 20.
+ */
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
+
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
+ }
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+ }
- /*
- * Write EEPROM OEM name at words 22 to 29.
- */
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
- {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
+ /*
+ * Write EEPROM checksum at word 21.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
+
+ /*
+ * Write EEPROM OEM name at words 22 to 29.
+ */
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
+
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+ return;
}
/* a_advlib.c */
@@ -17444,126 +17115,120 @@ AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
* ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
* host IC error.
*/
-STATIC int
-AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
- ADV_SCSI_REQ_Q *scsiq)
+static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
{
- ulong last_int_level;
- AdvPortAddr iop_base;
- ADV_DCNT req_size;
- ADV_PADDR req_paddr;
- ADV_CARR_T *new_carrp;
-
- ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
-
- /*
- * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
- */
- if (scsiq->target_id > ADV_MAX_TID)
- {
- scsiq->host_status = QHSTA_M_INVALID_DEVICE;
- scsiq->done_status = QD_WITH_ERROR;
- return ADV_ERROR;
- }
-
- iop_base = asc_dvc->iop_base;
-
- last_int_level = DvcEnterCritical();
-
- /*
- * Allocate a carrier ensuring at least one carrier always
- * remains on the freelist and initialize fields.
- */
- if ((new_carrp = asc_dvc->carr_freelist) == NULL)
- {
- DvcLeaveCritical(last_int_level);
- return ADV_BUSY;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
- asc_dvc->carr_pending_cnt++;
-
- /*
- * Set the carrier to be a stopper by setting 'next_vpa'
- * to the stopper value. The current stopper will be changed
- * below to point to the new stopper.
- */
- new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Clear the ADV_SCSI_REQ_Q done flag.
- */
- scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
- req_size = sizeof(ADV_SCSI_REQ_Q);
- req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
- (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG);
-
- ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
- ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
-
- /* Wait for assertion before making little-endian */
- req_paddr = cpu_to_le32(req_paddr);
-
- /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
- scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
- scsiq->scsiq_rptr = req_paddr;
+ ulong last_int_level;
+ AdvPortAddr iop_base;
+ ADV_DCNT req_size;
+ ADV_PADDR req_paddr;
+ ADV_CARR_T *new_carrp;
+
+ ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+
+ /*
+ * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+ */
+ if (scsiq->target_id > ADV_MAX_TID) {
+ scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+ scsiq->done_status = QD_WITH_ERROR;
+ return ADV_ERROR;
+ }
- scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
- /*
- * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
- * order during initialization.
- */
- scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
-
- /*
- * Use the current stopper to send the ADV_SCSI_REQ_Q command to
- * the microcode. The newly allocated stopper will become the new
- * stopper.
- */
- asc_dvc->icq_sp->areq_vpa = req_paddr;
+ iop_base = asc_dvc->iop_base;
- /*
- * Set the 'next_vpa' pointer for the old stopper to be the
- * physical address of the new stopper. The RISC can only
- * follow physical addresses.
- */
- asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
+ last_int_level = DvcEnterCritical();
- /*
- * Set the host adapter stopper pointer to point to the new carrier.
- */
- asc_dvc->icq_sp = new_carrp;
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
- asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
- {
- /*
- * Tickle the RISC to tell it to read its Command Queue Head pointer.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
- {
- /*
- * Clear the tickle value. In the ASC-3550 the RISC flag
- * command 'clr_tickle_a' does not work unless the host
- * value is cleared.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
- }
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
- {
- /*
- * Notify the RISC a carrier is ready by writing the physical
- * address of the new carrier stopper to the COMMA register.
- */
- AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
- le32_to_cpu(new_carrp->carr_pa));
- }
+ /*
+ * Allocate a carrier ensuring at least one carrier always
+ * remains on the freelist and initialize fields.
+ */
+ if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
+ DvcLeaveCritical(last_int_level);
+ return ADV_BUSY;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
+ asc_dvc->carr_pending_cnt++;
+
+ /*
+ * Set the carrier to be a stopper by setting 'next_vpa'
+ * to the stopper value. The current stopper will be changed
+ * below to point to the new stopper.
+ */
+ new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Clear the ADV_SCSI_REQ_Q done flag.
+ */
+ scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+ req_size = sizeof(ADV_SCSI_REQ_Q);
+ req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
+ (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
+
+ ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
+ ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+ /* Wait for assertion before making little-endian */
+ req_paddr = cpu_to_le32(req_paddr);
+
+ /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+ scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
+ scsiq->scsiq_rptr = req_paddr;
+
+ scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
+ /*
+ * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+ * order during initialization.
+ */
+ scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
+
+ /*
+ * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+ * the microcode. The newly allocated stopper will become the new
+ * stopper.
+ */
+ asc_dvc->icq_sp->areq_vpa = req_paddr;
+
+ /*
+ * Set the 'next_vpa' pointer for the old stopper to be the
+ * physical address of the new stopper. The RISC can only
+ * follow physical addresses.
+ */
+ asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
+
+ /*
+ * Set the host adapter stopper pointer to point to the new carrier.
+ */
+ asc_dvc->icq_sp = new_carrp;
+
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+ asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ /*
+ * Tickle the RISC to tell it to read its Command Queue Head pointer.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_a' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+ ADV_TICKLE_NOP);
+ }
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ /*
+ * Notify the RISC a carrier is ready by writing the physical
+ * address of the new carrier stopper to the COMMA register.
+ */
+ AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+ le32_to_cpu(new_carrp->carr_pa));
+ }
- DvcLeaveCritical(last_int_level);
+ DvcLeaveCritical(last_int_level);
- return ADV_SUCCESS;
+ return ADV_SUCCESS;
}
/*
@@ -17575,42 +17240,39 @@ AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
* ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
* may be hung which requires driver recovery.
*/
-STATIC int
-AdvResetSB(ADV_DVC_VAR *asc_dvc)
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
{
- int status;
-
- /*
- * Send the SCSI Bus Reset idle start idle command which asserts
- * the SCSI Bus Reset signal.
- */
- status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L);
- if (status != ADV_TRUE)
- {
- return status;
- }
-
- /*
- * Delay for the specified SCSI Bus Reset hold time.
- *
- * The hold time delay is done on the host because the RISC has no
- * microsecond accurate timer.
- */
- DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+ int status;
+
+ /*
+ * Send the SCSI Bus Reset idle start idle command which asserts
+ * the SCSI Bus Reset signal.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
+ if (status != ADV_TRUE) {
+ return status;
+ }
- /*
- * Send the SCSI Bus Reset end idle command which de-asserts
- * the SCSI Bus Reset signal and purges any pending requests.
- */
- status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L);
- if (status != ADV_TRUE)
- {
- return status;
- }
+ /*
+ * Delay for the specified SCSI Bus Reset hold time.
+ *
+ * The hold time delay is done on the host because the RISC has no
+ * microsecond accurate timer.
+ */
+ DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
+
+ /*
+ * Send the SCSI Bus Reset end idle command which de-asserts
+ * the SCSI Bus Reset signal and purges any pending requests.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
+ if (status != ADV_TRUE) {
+ return status;
+ }
- DvcSleepMilliSecond((ADV_DCNT) asc_dvc->scsi_reset_wait * 1000);
+ DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
- return status;
+ return status;
}
/*
@@ -17620,99 +17282,89 @@ AdvResetSB(ADV_DVC_VAR *asc_dvc)
* ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
* ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
*/
-STATIC int
-AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
+static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
{
- int status;
- ushort wdtr_able, sdtr_able, tagqng_able;
- ushort ppr_able = 0;
- uchar tid, max_cmd[ADV_MAX_TID + 1];
- AdvPortAddr iop_base;
- ushort bios_sig;
-
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
- {
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- }
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * Force the AdvInitAsc3550/38C0800Driver() function to
- * perform a SCSI Bus Reset by clearing the BIOS signature word.
- * The initialization functions assumes a SCSI Bus Reset is not
- * needed if the BIOS signature word is present.
- */
- AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
- AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
-
- /*
- * Stop chip and reset it.
- */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
-
- /*
- * Reset Adv Library error code, if any, and try
- * re-initializing the chip.
- */
- asc_dvc->err_code = 0;
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
- {
- status = AdvInitAsc38C1600Driver(asc_dvc);
- }
- else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
- {
- status = AdvInitAsc38C0800Driver(asc_dvc);
- } else
- {
- status = AdvInitAsc3550Driver(asc_dvc);
- }
+ int status;
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ ushort ppr_able = 0;
+ uchar tid, max_cmd[ADV_MAX_TID + 1];
+ AdvPortAddr iop_base;
+ ushort bios_sig;
+
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ }
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
- /* Translate initialization return value to status value. */
- if (status == 0)
- {
- status = ADV_TRUE;
- } else
- {
- status = ADV_FALSE;
- }
+ /*
+ * Force the AdvInitAsc3550/38C0800Driver() function to
+ * perform a SCSI Bus Reset by clearing the BIOS signature word.
+ * The initialization functions assumes a SCSI Bus Reset is not
+ * needed if the BIOS signature word is present.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+
+ /*
+ * Stop chip and reset it.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+ DvcSleepMilliSecond(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
+
+ /*
+ * Reset Adv Library error code, if any, and try
+ * re-initializing the chip.
+ */
+ asc_dvc->err_code = 0;
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ status = AdvInitAsc38C1600Driver(asc_dvc);
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ status = AdvInitAsc38C0800Driver(asc_dvc);
+ } else {
+ status = AdvInitAsc3550Driver(asc_dvc);
+ }
- /*
- * Restore the BIOS signature word.
- */
- AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ /* Translate initialization return value to status value. */
+ if (status == 0) {
+ status = ADV_TRUE;
+ } else {
+ status = ADV_FALSE;
+ }
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
- {
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- }
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++)
- {
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ /*
+ * Restore the BIOS signature word.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
- return status;
+ return status;
}
/*
@@ -17734,158 +17386,151 @@ AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
* ADV_TRUE(1) - interrupt was pending
* ADV_FALSE(0) - no interrupt was pending
*/
-STATIC int
-AdvISR(ADV_DVC_VAR *asc_dvc)
+static int AdvISR(ADV_DVC_VAR *asc_dvc)
{
- AdvPortAddr iop_base;
- uchar int_stat;
- ushort target_bit;
- ADV_CARR_T *free_carrp;
- ADV_VADDR irq_next_vpa;
- int flags;
- ADV_SCSI_REQ_Q *scsiq;
-
- flags = DvcEnterCritical();
-
- iop_base = asc_dvc->iop_base;
-
- /* Reading the register clears the interrupt. */
- int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
-
- if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
- ADV_INTR_STATUS_INTRC)) == 0)
- {
- DvcLeaveCritical(flags);
- return ADV_FALSE;
- }
+ AdvPortAddr iop_base;
+ uchar int_stat;
+ ushort target_bit;
+ ADV_CARR_T *free_carrp;
+ ADV_VADDR irq_next_vpa;
+ int flags;
+ ADV_SCSI_REQ_Q *scsiq;
- /*
- * Notify the driver of an asynchronous microcode condition by
- * calling the ADV_DVC_VAR.async_callback function. The function
- * is passed the microcode ASC_MC_INTRB_CODE byte value.
- */
- if (int_stat & ADV_INTR_STATUS_INTRB)
- {
- uchar intrb_code;
-
- AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
- asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
- {
- if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
- asc_dvc->carr_pending_cnt != 0)
- {
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
- {
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
- }
- }
- }
-
- if (asc_dvc->async_callback != 0)
- {
- (*asc_dvc->async_callback)(asc_dvc, intrb_code);
- }
- }
+ flags = DvcEnterCritical();
- /*
- * Check if the IRQ stopper carrier contains a completed request.
- */
- while (((irq_next_vpa =
- le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0)
- {
- /*
- * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
- * The RISC will have set 'areq_vpa' to a virtual address.
- *
- * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
- * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
- * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
- * in AdvExeScsiQueue().
- */
- scsiq = (ADV_SCSI_REQ_Q *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
-
- /*
- * Request finished with good status and the queue was not
- * DMAed to host memory by the firmware. Set all status fields
- * to indicate good status.
- */
- if ((irq_next_vpa & ASC_RQ_GOOD) != 0)
- {
- scsiq->done_status = QD_NO_ERROR;
- scsiq->host_status = scsiq->scsi_status = 0;
- scsiq->data_cnt = 0L;
- }
-
- /*
- * Advance the stopper pointer to the next carrier
- * ignoring the lower four bits. Free the previous
- * stopper carrier.
- */
- free_carrp = asc_dvc->irq_sp;
- asc_dvc->irq_sp = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
-
- free_carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = free_carrp;
- asc_dvc->carr_pending_cnt--;
-
- ASC_ASSERT(scsiq != NULL);
- target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
-
- /*
- * Clear request microcode control flag.
- */
- scsiq->cntl = 0;
-
- /*
- * If the command that completed was a SCSI INQUIRY and
- * LUN 0 was sent the command, then process the INQUIRY
- * command information for the device.
- *
- * Note: If data returned were either VPD or CmdDt data,
- * don't process the INQUIRY command information for
- * the device, otherwise may erroneously set *_able bits.
- */
- if (scsiq->done_status == QD_NO_ERROR &&
- scsiq->cdb[0] == INQUIRY &&
- scsiq->target_lun == 0 &&
- (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
- == ADV_INQ_RTN_STD_INQUIRY_DATA)
- {
- AdvInquiryHandling(asc_dvc, scsiq);
- }
-
- /*
- * Notify the driver of the completed request by passing
- * the ADV_SCSI_REQ_Q pointer to its callback function.
- */
- scsiq->a_flag |= ADV_SCSIQ_DONE;
- (*asc_dvc->isr_callback)(asc_dvc, scsiq);
- /*
- * Note: After the driver callback function is called, 'scsiq'
- * can no longer be referenced.
- *
- * Fall through and continue processing other completed
- * requests...
- */
-
- /*
- * Disable interrupts again in case the driver inadvertently
- * enabled interrupts in its callback function.
- *
- * The DvcEnterCritical() return value is ignored, because
- * the 'flags' saved when AdvISR() was first entered will be
- * used to restore the interrupt flag on exit.
- */
- (void) DvcEnterCritical();
- }
- DvcLeaveCritical(flags);
- return ADV_TRUE;
+ iop_base = asc_dvc->iop_base;
+
+ /* Reading the register clears the interrupt. */
+ int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+ if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+ ADV_INTR_STATUS_INTRC)) == 0) {
+ DvcLeaveCritical(flags);
+ return ADV_FALSE;
+ }
+
+ /*
+ * Notify the driver of an asynchronous microcode condition by
+ * calling the ADV_DVC_VAR.async_callback function. The function
+ * is passed the microcode ASC_MC_INTRB_CODE byte value.
+ */
+ if (int_stat & ADV_INTR_STATUS_INTRB) {
+ uchar intrb_code;
+
+ AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+ asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+ asc_dvc->carr_pending_cnt != 0) {
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+ ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ AdvWriteByteRegister(iop_base,
+ IOPB_TICKLE,
+ ADV_TICKLE_NOP);
+ }
+ }
+ }
+
+ if (asc_dvc->async_callback != 0) {
+ (*asc_dvc->async_callback) (asc_dvc, intrb_code);
+ }
+ }
+
+ /*
+ * Check if the IRQ stopper carrier contains a completed request.
+ */
+ while (((irq_next_vpa =
+ le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
+ /*
+ * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+ * The RISC will have set 'areq_vpa' to a virtual address.
+ *
+ * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+ * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+ * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+ * in AdvExeScsiQueue().
+ */
+ scsiq = (ADV_SCSI_REQ_Q *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+
+ /*
+ * Request finished with good status and the queue was not
+ * DMAed to host memory by the firmware. Set all status fields
+ * to indicate good status.
+ */
+ if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
+ scsiq->done_status = QD_NO_ERROR;
+ scsiq->host_status = scsiq->scsi_status = 0;
+ scsiq->data_cnt = 0L;
+ }
+
+ /*
+ * Advance the stopper pointer to the next carrier
+ * ignoring the lower four bits. Free the previous
+ * stopper carrier.
+ */
+ free_carrp = asc_dvc->irq_sp;
+ asc_dvc->irq_sp = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
+
+ free_carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = free_carrp;
+ asc_dvc->carr_pending_cnt--;
+
+ ASC_ASSERT(scsiq != NULL);
+ target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+ /*
+ * Clear request microcode control flag.
+ */
+ scsiq->cntl = 0;
+
+ /*
+ * If the command that completed was a SCSI INQUIRY and
+ * LUN 0 was sent the command, then process the INQUIRY
+ * command information for the device.
+ *
+ * Note: If data returned were either VPD or CmdDt data,
+ * don't process the INQUIRY command information for
+ * the device, otherwise may erroneously set *_able bits.
+ */
+ if (scsiq->done_status == QD_NO_ERROR &&
+ scsiq->cdb[0] == INQUIRY &&
+ scsiq->target_lun == 0 &&
+ (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
+ == ADV_INQ_RTN_STD_INQUIRY_DATA) {
+ AdvInquiryHandling(asc_dvc, scsiq);
+ }
+
+ /*
+ * Notify the driver of the completed request by passing
+ * the ADV_SCSI_REQ_Q pointer to its callback function.
+ */
+ scsiq->a_flag |= ADV_SCSIQ_DONE;
+ (*asc_dvc->isr_callback) (asc_dvc, scsiq);
+ /*
+ * Note: After the driver callback function is called, 'scsiq'
+ * can no longer be referenced.
+ *
+ * Fall through and continue processing other completed
+ * requests...
+ */
+
+ /*
+ * Disable interrupts again in case the driver inadvertently
+ * enabled interrupts in its callback function.
+ *
+ * The DvcEnterCritical() return value is ignored, because
+ * the 'flags' saved when AdvISR() was first entered will be
+ * used to restore the interrupt flag on exit.
+ */
+ (void)DvcEnterCritical();
+ }
+ DvcLeaveCritical(flags);
+ return ADV_TRUE;
}
/*
@@ -17902,71 +17547,67 @@ AdvISR(ADV_DVC_VAR *asc_dvc)
* ADV_FALSE - command failed
* ADV_ERROR - command timed out
*/
-STATIC int
+static int
AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
- ushort idle_cmd,
- ADV_DCNT idle_cmd_parameter)
+ ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
{
- ulong last_int_level;
- int result;
- ADV_DCNT i, j;
- AdvPortAddr iop_base;
-
- last_int_level = DvcEnterCritical();
-
- iop_base = asc_dvc->iop_base;
-
- /*
- * Clear the idle command status which is set by the microcode
- * to a non-zero value to indicate when the command is completed.
- * The non-zero result is one of the IDLE_CMD_STATUS_* values
- * defined in a_advlib.h.
- */
- AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0);
-
- /*
- * Write the idle command value after the idle command parameter
- * has been written to avoid a race condition. If the order is not
- * followed, the microcode may process the idle command before the
- * parameters have been written to LRAM.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
- cpu_to_le32(idle_cmd_parameter));
- AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
-
- /*
- * Tickle the RISC to tell it to process the idle command.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
- {
- /*
- * Clear the tickle value. In the ASC-3550 the RISC flag
- * command 'clr_tickle_b' does not work unless the host
- * value is cleared.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
- }
+ ulong last_int_level;
+ int result;
+ ADV_DCNT i, j;
+ AdvPortAddr iop_base;
+
+ last_int_level = DvcEnterCritical();
+
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Clear the idle command status which is set by the microcode
+ * to a non-zero value to indicate when the command is completed.
+ * The non-zero result is one of the IDLE_CMD_STATUS_* values
+ * defined in a_advlib.h.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
+
+ /*
+ * Write the idle command value after the idle command parameter
+ * has been written to avoid a race condition. If the order is not
+ * followed, the microcode may process the idle command before the
+ * parameters have been written to LRAM.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+ cpu_to_le32(idle_cmd_parameter));
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+
+ /*
+ * Tickle the RISC to tell it to process the idle command.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_b' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+ }
- /* Wait for up to 100 millisecond for the idle command to timeout. */
- for (i = 0; i < SCSI_WAIT_100_MSEC; i++)
- {
- /* Poll once each microsecond for command completion. */
- for (j = 0; j < SCSI_US_PER_MSEC; j++)
- {
- AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result);
- if (result != 0)
- {
- DvcLeaveCritical(last_int_level);
- return result;
- }
- DvcDelayMicroSecond(asc_dvc, (ushort) 1);
- }
- }
+ /* Wait for up to 100 millisecond for the idle command to timeout. */
+ for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
+ /* Poll once each microsecond for command completion. */
+ for (j = 0; j < SCSI_US_PER_MSEC; j++) {
+ AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
+ result);
+ if (result != 0) {
+ DvcLeaveCritical(last_int_level);
+ return result;
+ }
+ DvcDelayMicroSecond(asc_dvc, (ushort)1);
+ }
+ }
- ASC_ASSERT(0); /* The idle command should never timeout. */
- DvcLeaveCritical(last_int_level);
- return ADV_ERROR;
+ ASC_ASSERT(0); /* The idle command should never timeout. */
+ DvcLeaveCritical(last_int_level);
+ return ADV_ERROR;
}
/*
@@ -17976,179 +17617,1415 @@ AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
* microcode operating variables that affect WDTR, SDTR, and Tag
* Queuing.
*/
-STATIC void
-AdvInquiryHandling(
- ADV_DVC_VAR *asc_dvc,
- ADV_SCSI_REQ_Q *scsiq)
+static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
{
- AdvPortAddr iop_base;
- uchar tid;
- ADV_SCSI_INQUIRY *inq;
- ushort tidmask;
- ushort cfg_word;
+ AdvPortAddr iop_base;
+ uchar tid;
+ ADV_SCSI_INQUIRY *inq;
+ ushort tidmask;
+ ushort cfg_word;
+
+ /*
+ * AdvInquiryHandling() requires up to INQUIRY information Byte 7
+ * to be available.
+ *
+ * If less than 8 bytes of INQUIRY information were requested or less
+ * than 8 bytes were transferred, then return. cdb[4] is the request
+ * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
+ * microcode to the transfer residual count.
+ */
+
+ if (scsiq->cdb[4] < 8 ||
+ (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
+ return;
+ }
- /*
- * AdvInquiryHandling() requires up to INQUIRY information Byte 7
- * to be available.
- *
- * If less than 8 bytes of INQUIRY information were requested or less
- * than 8 bytes were transferred, then return. cdb[4] is the request
- * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
- * microcode to the transfer residual count.
- */
-
- if (scsiq->cdb[4] < 8 ||
- (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8)
- {
- return;
- }
+ iop_base = asc_dvc->iop_base;
+ tid = scsiq->target_id;
- iop_base = asc_dvc->iop_base;
- tid = scsiq->target_id;
+ inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
- inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
+ /*
+ * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+ */
+ if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
+ return;
+ } else {
+ /*
+ * INQUIRY Byte 7 Handling
+ *
+ * Use a device's INQUIRY byte 7 to determine whether it
+ * supports WDTR, SDTR, and Tag Queuing. If the feature
+ * is enabled in the EEPROM and the device supports the
+ * feature, then enable it in the microcode.
+ */
- /*
- * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
- */
- if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2)
- {
- return;
- } else
- {
- /*
- * INQUIRY Byte 7 Handling
- *
- * Use a device's INQUIRY byte 7 to determine whether it
- * supports WDTR, SDTR, and Tag Queuing. If the feature
- * is enabled in the EEPROM and the device supports the
- * feature, then enable it in the microcode.
- */
-
- tidmask = ADV_TID_TO_TIDMASK(tid);
-
- /*
- * Wide Transfers
- *
- * If the EEPROM enabled WDTR for the device and the device
- * supports wide bus (16 bit) transfers, then turn on the
- * device's 'wdtr_able' bit and write the new value to the
- * microcode.
- */
- if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq))
- {
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
- if ((cfg_word & tidmask) == 0)
- {
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
-
- /*
- * Clear the microcode "SDTR negotiation" and "WDTR
- * negotiation" done indicators for the target to cause
- * it to negotiate with the new setting set above.
- * WDTR when accepted causes the target to enter
- * asynchronous mode, so SDTR must be negotiated.
- */
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
- AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
- }
- }
-
- /*
- * Synchronous Transfers
- *
- * If the EEPROM enabled SDTR for the device and the device
- * supports synchronous transfers, then turn on the device's
- * 'sdtr_able' bit. Write the new value to the microcode.
- */
- if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq))
- {
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
- if ((cfg_word & tidmask) == 0)
- {
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
-
- /*
- * Clear the microcode "SDTR negotiation" done indicator
- * for the target to cause it to negotiate with the new
- * setting set above.
- */
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
- }
- }
- /*
- * If the Inquiry data included enough space for the SPI-3
- * Clocking field, then check if DT mode is supported.
- */
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
- (scsiq->cdb[4] >= 57 ||
- (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57))
- {
- /*
- * PPR (Parallel Protocol Request) Capable
- *
- * If the device supports DT mode, then it must be PPR capable.
- * The PPR message will be used in place of the SDTR and WDTR
- * messages to negotiate synchronous speed and offset, transfer
- * width, and protocol options.
- */
- if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY)
- {
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
- asc_dvc->ppr_able |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
- }
- }
-
- /*
- * If the EEPROM enabled Tag Queuing for the device and the
- * device supports Tag Queueing, then turn on the device's
- * 'tagqng_enable' bit in the microcode and set the microcode
- * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
- * value.
- *
- * Tag Queuing is disabled for the BIOS which runs in polled
- * mode and would see no benefit from Tag Queuing. Also by
- * disabling Tag Queuing in the BIOS devices with Tag Queuing
- * bugs will at least work with the BIOS.
- */
- if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq))
- {
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
-
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- asc_dvc->max_dvc_qng);
- }
- }
+ tidmask = ADV_TID_TO_TIDMASK(tid);
+
+ /*
+ * Wide Transfers
+ *
+ * If the EEPROM enabled WDTR for the device and the device
+ * supports wide bus (16 bit) transfers, then turn on the
+ * device's 'wdtr_able' bit and write the new value to the
+ * microcode.
+ */
+ if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) == 0) {
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ cfg_word);
+
+ /*
+ * Clear the microcode "SDTR negotiation" and "WDTR
+ * negotiation" done indicators for the target to cause
+ * it to negotiate with the new setting set above.
+ * WDTR when accepted causes the target to enter
+ * asynchronous mode, so SDTR must be negotiated.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
+ cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
+ cfg_word);
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
+ cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
+ cfg_word);
+ }
+ }
+
+ /*
+ * Synchronous Transfers
+ *
+ * If the EEPROM enabled SDTR for the device and the device
+ * supports synchronous transfers, then turn on the device's
+ * 'sdtr_able' bit. Write the new value to the microcode.
+ */
+ if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) == 0) {
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ cfg_word);
+
+ /*
+ * Clear the microcode "SDTR negotiation" done indicator
+ * for the target to cause it to negotiate with the new
+ * setting set above.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
+ cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
+ cfg_word);
+ }
+ }
+ /*
+ * If the Inquiry data included enough space for the SPI-3
+ * Clocking field, then check if DT mode is supported.
+ */
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
+ (scsiq->cdb[4] >= 57 ||
+ (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
+ /*
+ * PPR (Parallel Protocol Request) Capable
+ *
+ * If the device supports DT mode, then it must be PPR capable.
+ * The PPR message will be used in place of the SDTR and WDTR
+ * messages to negotiate synchronous speed and offset, transfer
+ * width, and protocol options.
+ */
+ if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
+ asc_dvc->ppr_able);
+ asc_dvc->ppr_able |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
+ asc_dvc->ppr_able);
+ }
+ }
+
+ /*
+ * If the EEPROM enabled Tag Queuing for the device and the
+ * device supports Tag Queueing, then turn on the device's
+ * 'tagqng_enable' bit in the microcode and set the microcode
+ * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
+ * value.
+ *
+ * Tag Queuing is disabled for the BIOS which runs in polled
+ * mode and would see no benefit from Tag Queuing. Also by
+ * disabling Tag Queuing in the BIOS devices with Tag Queuing
+ * bugs will at least work with the BIOS.
+ */
+ if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ cfg_word);
+
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ asc_dvc->max_dvc_qng);
+ }
+ }
}
+
MODULE_LICENSE("Dual BSD/GPL");
+static struct Scsi_Host *__devinit
+advansys_board_found(int iop, struct device *dev, int bus_type)
+{
+ struct Scsi_Host *shost;
+ struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
+ asc_board_t *boardp;
+ ASC_DVC_VAR *asc_dvc_varp = NULL;
+ ADV_DVC_VAR *adv_dvc_varp = NULL;
+ adv_sgblk_t *sgp = NULL;
+ int share_irq = FALSE;
+ int iolen = 0;
+ ADV_PADDR pci_memory_address;
+ int warn_code, err_code;
+ int ret;
+
+ /*
+ * Adapter found.
+ *
+ * Register the adapter, get its configuration, and
+ * initialize it.
+ */
+ ASC_DBG(2, "advansys_board_found: scsi_register()\n");
+ shost = scsi_register(&driver_template, sizeof(asc_board_t));
+
+ if (!shost)
+ return NULL;
+
+ /* Save a pointer to the Scsi_Host of each board found. */
+ asc_host[asc_board_count++] = shost;
+
+ /* Initialize private per board data */
+ boardp = ASC_BOARDP(shost);
+ memset(boardp, 0, sizeof(asc_board_t));
+ boardp->id = asc_board_count - 1;
+
+ /* Initialize spinlock. */
+ spin_lock_init(&boardp->lock);
+
+ /*
+ * Handle both narrow and wide boards.
+ *
+ * If a Wide board was detected, set the board structure
+ * wide board flag. Set-up the board structure based on
+ * the board type.
+ */
+#ifdef CONFIG_PCI
+ if (bus_type == ASC_IS_PCI &&
+ (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+ pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
+ pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
+ boardp->flags |= ASC_IS_WIDE_BOARD;
+ }
+#endif /* CONFIG_PCI */
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DBG(1, "advansys_board_found: narrow board\n");
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ asc_dvc_varp->bus_type = bus_type;
+ asc_dvc_varp->drv_ptr = boardp;
+ asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
+ asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
+ asc_dvc_varp->iop_base = iop;
+ asc_dvc_varp->isr_callback = asc_isr_callback;
+ } else {
+ ASC_DBG(1, "advansys_board_found: wide board\n");
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ adv_dvc_varp->drv_ptr = boardp;
+ adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
+ adv_dvc_varp->isr_callback = adv_isr_callback;
+ adv_dvc_varp->async_callback = adv_async_callback;
+#ifdef CONFIG_PCI
+ if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
+ ASC_DBG(1, "advansys_board_found: ASC-3550\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+ } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
+ ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+ } else {
+ ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
+ adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
+ }
+#endif /* CONFIG_PCI */
+
+ /*
+ * Map the board's registers into virtual memory for
+ * PCI slave access. Only memory accesses are used to
+ * access the board's registers.
+ *
+ * Note: The PCI register base address is not always
+ * page aligned, but the address passed to ioremap()
+ * must be page aligned. It is guaranteed that the
+ * PCI register base address will not cross a page
+ * boundary.
+ */
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ iolen = ADV_3550_IOLEN;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ iolen = ADV_38C0800_IOLEN;
+ } else {
+ iolen = ADV_38C1600_IOLEN;
+ }
+#ifdef CONFIG_PCI
+ pci_memory_address = pci_resource_start(pdev, 1);
+ ASC_DBG1(1,
+ "advansys_board_found: pci_memory_address: 0x%lx\n",
+ (ulong)pci_memory_address);
+ if ((boardp->ioremap_addr =
+ ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
+ ASC_PRINT3
+ ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
+ boardp->id, pci_memory_address, iolen);
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+ ASC_DBG1(1,
+ "advansys_board_found: ioremap_addr: 0x%lx\n",
+ (ulong)boardp->ioremap_addr);
+ adv_dvc_varp->iop_base = (AdvPortAddr)
+ (boardp->ioremap_addr +
+ (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+ ASC_DBG1(1,
+ "advansys_board_found: iop_base: 0x%lx\n",
+ adv_dvc_varp->iop_base);
+#endif /* CONFIG_PCI */
+
+ /*
+ * Even though it isn't used to access wide boards, other
+ * than for the debug line below, save I/O Port address so
+ * that it can be reported.
+ */
+ boardp->ioport = iop;
+
+ ASC_DBG2(1,
+ "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
+ (ushort)inp(iop + 1), (ushort)inpw(iop));
+ }
+
+#ifdef CONFIG_PROC_FS
+ /*
+ * Allocate buffer for printing information from
+ * /proc/scsi/advansys/[0...].
+ */
+ if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
+ ASC_PRINT3
+ ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
+ boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+#endif /* CONFIG_PROC_FS */
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_dvc_varp->cfg->dev = dev;
+ /*
+ * Set the board bus type and PCI IRQ before
+ * calling AscInitGetConfig().
+ */
+ switch (asc_dvc_varp->bus_type) {
+#ifdef CONFIG_ISA
+ case ASC_IS_ISA:
+ shost->unchecked_isa_dma = TRUE;
+ share_irq = FALSE;
+ break;
+ case ASC_IS_VL:
+ shost->unchecked_isa_dma = FALSE;
+ share_irq = FALSE;
+ break;
+ case ASC_IS_EISA:
+ shost->unchecked_isa_dma = FALSE;
+ share_irq = TRUE;
+ break;
+#endif /* CONFIG_ISA */
+#ifdef CONFIG_PCI
+ case ASC_IS_PCI:
+ shost->irq = asc_dvc_varp->irq_no = pdev->irq;
+ asc_dvc_varp->cfg->pci_slot_info =
+ ASC_PCI_MKID(pdev->bus->number,
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+ shost->unchecked_isa_dma = FALSE;
+ share_irq = TRUE;
+ break;
+#endif /* CONFIG_PCI */
+ default:
+ ASC_PRINT2
+ ("advansys_board_found: board %d: unknown adapter type: %d\n",
+ boardp->id, asc_dvc_varp->bus_type);
+ shost->unchecked_isa_dma = TRUE;
+ share_irq = FALSE;
+ break;
+ }
+ } else {
+ adv_dvc_varp->cfg->dev = dev;
+ /*
+ * For Wide boards set PCI information before calling
+ * AdvInitGetConfig().
+ */
+#ifdef CONFIG_PCI
+ shost->irq = adv_dvc_varp->irq_no = pdev->irq;
+ adv_dvc_varp->cfg->pci_slot_info =
+ ASC_PCI_MKID(pdev->bus->number,
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+ shost->unchecked_isa_dma = FALSE;
+ share_irq = TRUE;
+#endif /* CONFIG_PCI */
+ }
+
+ /*
+ * Read the board configuration.
+ */
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * NOTE: AscInitGetConfig() may change the board's
+ * bus_type value. The bus_type value should no
+ * longer be used. If the bus_type field must be
+ * referenced only use the bit-wise AND operator "&".
+ */
+ ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
+ switch (ret = AscInitGetConfig(asc_dvc_varp)) {
+ case 0: /* No error */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ ASC_PRINT1
+ ("AscInitGetConfig: board %d: I/O port address modified\n",
+ boardp->id);
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ ASC_PRINT1
+ ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
+ boardp->id);
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ ASC_PRINT1
+ ("AscInitGetConfig: board %d: EEPROM checksum error\n",
+ boardp->id);
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ ASC_PRINT1
+ ("AscInitGetConfig: board %d: IRQ modified\n",
+ boardp->id);
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ ASC_PRINT1
+ ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
+ boardp->id);
+ break;
+ default:
+ ASC_PRINT2
+ ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
+ boardp->id, ret);
+ break;
+ }
+ if ((err_code = asc_dvc_varp->err_code) != 0) {
+ ASC_PRINT3
+ ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
+ boardp->id,
+ asc_dvc_varp->init_state, asc_dvc_varp->err_code);
+ }
+ } else {
+ ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
+ if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
+ ASC_PRINT2
+ ("AdvInitGetConfig: board %d: warning: 0x%x\n",
+ boardp->id, ret);
+ }
+ if ((err_code = adv_dvc_varp->err_code) != 0) {
+ ASC_PRINT2
+ ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
+ boardp->id, adv_dvc_varp->err_code);
+ }
+ }
+
+ if (err_code != 0) {
+#ifdef CONFIG_PROC_FS
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+
+ /*
+ * Save the EEPROM configuration so that it can be displayed
+ * from /proc/scsi/advansys/[0...].
+ */
+ if (ASC_NARROW_BOARD(boardp)) {
+
+ ASCEEP_CONFIG *ep;
+
+ /*
+ * Set the adapter's target id bit in the 'init_tidmask' field.
+ */
+ boardp->init_tidmask |=
+ ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
+
+ /*
+ * Save EEPROM settings for the board.
+ */
+ ep = &boardp->eep_config.asc_eep;
+
+ ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
+ ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
+ ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
+ ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
+ ep->start_motor = asc_dvc_varp->start_motor;
+ ep->cntl = asc_dvc_varp->dvc_cntl;
+ ep->no_scam = asc_dvc_varp->no_scam;
+ ep->max_total_qng = asc_dvc_varp->max_total_qng;
+ ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
+ /* 'max_tag_qng' is set to the same value for every device. */
+ ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
+ ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
+ ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
+ ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
+ ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
+ ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
+ ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
+
+ /*
+ * Modify board configuration.
+ */
+ ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
+ switch (ret = AscInitSetConfig(asc_dvc_varp)) {
+ case 0: /* No error. */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ ASC_PRINT1
+ ("AscInitSetConfig: board %d: I/O port address modified\n",
+ boardp->id);
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ ASC_PRINT1
+ ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
+ boardp->id);
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ ASC_PRINT1
+ ("AscInitSetConfig: board %d: EEPROM checksum error\n",
+ boardp->id);
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ ASC_PRINT1
+ ("AscInitSetConfig: board %d: IRQ modified\n",
+ boardp->id);
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ ASC_PRINT1
+ ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
+ boardp->id);
+ break;
+ default:
+ ASC_PRINT2
+ ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
+ boardp->id, ret);
+ break;
+ }
+ if (asc_dvc_varp->err_code != 0) {
+ ASC_PRINT3
+ ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
+ boardp->id,
+ asc_dvc_varp->init_state, asc_dvc_varp->err_code);
+#ifdef CONFIG_PROC_FS
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+
+ /*
+ * Finish initializing the 'Scsi_Host' structure.
+ */
+ /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
+ if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
+ shost->irq = asc_dvc_varp->irq_no;
+ }
+ } else {
+ ADVEEP_3550_CONFIG *ep_3550;
+ ADVEEP_38C0800_CONFIG *ep_38C0800;
+ ADVEEP_38C1600_CONFIG *ep_38C1600;
+
+ /*
+ * Save Wide EEP Configuration Information.
+ */
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ ep_3550 = &boardp->eep_config.adv_3550_eep;
+
+ ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+ ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
+ ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+ ep_3550->termination = adv_dvc_varp->cfg->termination;
+ ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
+ ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
+ ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
+ ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
+ ep_3550->ultra_able = adv_dvc_varp->ultra_able;
+ ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_3550->start_motor = adv_dvc_varp->start_motor;
+ ep_3550->scsi_reset_delay =
+ adv_dvc_varp->scsi_reset_wait;
+ ep_3550->serial_number_word1 =
+ adv_dvc_varp->cfg->serial1;
+ ep_3550->serial_number_word2 =
+ adv_dvc_varp->cfg->serial2;
+ ep_3550->serial_number_word3 =
+ adv_dvc_varp->cfg->serial3;
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+
+ ep_38C0800->adapter_scsi_id =
+ adv_dvc_varp->chip_scsi_id;
+ ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
+ ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+ ep_38C0800->termination_lvd =
+ adv_dvc_varp->cfg->termination;
+ ep_38C0800->disc_enable =
+ adv_dvc_varp->cfg->disc_enable;
+ ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
+ ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
+ ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+ ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+ ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+ ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+ ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_38C0800->start_motor = adv_dvc_varp->start_motor;
+ ep_38C0800->scsi_reset_delay =
+ adv_dvc_varp->scsi_reset_wait;
+ ep_38C0800->serial_number_word1 =
+ adv_dvc_varp->cfg->serial1;
+ ep_38C0800->serial_number_word2 =
+ adv_dvc_varp->cfg->serial2;
+ ep_38C0800->serial_number_word3 =
+ adv_dvc_varp->cfg->serial3;
+ } else {
+ ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+
+ ep_38C1600->adapter_scsi_id =
+ adv_dvc_varp->chip_scsi_id;
+ ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
+ ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+ ep_38C1600->termination_lvd =
+ adv_dvc_varp->cfg->termination;
+ ep_38C1600->disc_enable =
+ adv_dvc_varp->cfg->disc_enable;
+ ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
+ ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
+ ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+ ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+ ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+ ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+ ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep_38C1600->start_motor = adv_dvc_varp->start_motor;
+ ep_38C1600->scsi_reset_delay =
+ adv_dvc_varp->scsi_reset_wait;
+ ep_38C1600->serial_number_word1 =
+ adv_dvc_varp->cfg->serial1;
+ ep_38C1600->serial_number_word2 =
+ adv_dvc_varp->cfg->serial2;
+ ep_38C1600->serial_number_word3 =
+ adv_dvc_varp->cfg->serial3;
+ }
+
+ /*
+ * Set the adapter's target id bit in the 'init_tidmask' field.
+ */
+ boardp->init_tidmask |=
+ ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
+
+ /*
+ * Finish initializing the 'Scsi_Host' structure.
+ */
+ shost->irq = adv_dvc_varp->irq_no;
+ }
+
+ /*
+ * Channels are numbered beginning with 0. For AdvanSys one host
+ * structure supports one channel. Multi-channel boards have a
+ * separate host structure for each channel.
+ */
+ shost->max_channel = 0;
+ if (ASC_NARROW_BOARD(boardp)) {
+ shost->max_id = ASC_MAX_TID + 1;
+ shost->max_lun = ASC_MAX_LUN + 1;
+
+ shost->io_port = asc_dvc_varp->iop_base;
+ boardp->asc_n_io_port = ASC_IOADR_GAP;
+ shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
+
+ /* Set maximum number of queues the adapter can handle. */
+ shost->can_queue = asc_dvc_varp->max_total_qng;
+ } else {
+ shost->max_id = ADV_MAX_TID + 1;
+ shost->max_lun = ADV_MAX_LUN + 1;
+
+ /*
+ * Save the I/O Port address and length even though
+ * I/O ports are not used to access Wide boards.
+ * Instead the Wide boards are accessed with
+ * PCI Memory Mapped I/O.
+ */
+ shost->io_port = iop;
+ boardp->asc_n_io_port = iolen;
+
+ shost->this_id = adv_dvc_varp->chip_scsi_id;
+
+ /* Set maximum number of queues the adapter can handle. */
+ shost->can_queue = adv_dvc_varp->max_host_qng;
+ }
+
+ /*
+ * 'n_io_port' currently is one byte.
+ *
+ * Set a value to 'n_io_port', but never referenced it because
+ * it may be truncated.
+ */
+ shost->n_io_port = boardp->asc_n_io_port <= 255 ?
+ boardp->asc_n_io_port : 255;
+
+ /*
+ * Following v1.3.89, 'cmd_per_lun' is no longer needed
+ * and should be set to zero.
+ *
+ * But because of a bug introduced in v1.3.89 if the driver is
+ * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
+ * SCSI function 'allocate_device' will panic. To allow the driver
+ * to work as a module in these kernels set 'cmd_per_lun' to 1.
+ *
+ * Note: This is wrong. cmd_per_lun should be set to the depth
+ * you want on untagged devices always.
+ #ifdef MODULE
+ */
+ shost->cmd_per_lun = 1;
+/* #else
+ shost->cmd_per_lun = 0;
+#endif */
+
+ /*
+ * Set the maximum number of scatter-gather elements the
+ * adapter can handle.
+ */
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Allow two commands with 'sg_tablesize' scatter-gather
+ * elements to be executed simultaneously. This value is
+ * the theoretical hardware limit. It may be decreased
+ * below.
+ */
+ shost->sg_tablesize =
+ (((asc_dvc_varp->max_total_qng - 2) / 2) *
+ ASC_SG_LIST_PER_Q) + 1;
+ } else {
+ shost->sg_tablesize = ADV_MAX_SG_LIST;
+ }
+
+ /*
+ * The value of 'sg_tablesize' can not exceed the SCSI
+ * mid-level driver definition of SG_ALL. SG_ALL also
+ * must not be exceeded, because it is used to define the
+ * size of the scatter-gather table in 'struct asc_sg_head'.
+ */
+ if (shost->sg_tablesize > SG_ALL) {
+ shost->sg_tablesize = SG_ALL;
+ }
+
+ ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
+
+ /* BIOS start address. */
+ if (ASC_NARROW_BOARD(boardp)) {
+ shost->base = ((ulong)
+ AscGetChipBiosAddress(asc_dvc_varp->
+ iop_base,
+ asc_dvc_varp->bus_type));
+ } else {
+ /*
+ * Fill-in BIOS board variables. The Wide BIOS saves
+ * information in LRAM that is used by the driver.
+ */
+ AdvReadWordLram(adv_dvc_varp->iop_base,
+ BIOS_SIGNATURE, boardp->bios_signature);
+ AdvReadWordLram(adv_dvc_varp->iop_base,
+ BIOS_VERSION, boardp->bios_version);
+ AdvReadWordLram(adv_dvc_varp->iop_base,
+ BIOS_CODESEG, boardp->bios_codeseg);
+ AdvReadWordLram(adv_dvc_varp->iop_base,
+ BIOS_CODELEN, boardp->bios_codelen);
+
+ ASC_DBG2(1,
+ "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
+ boardp->bios_signature, boardp->bios_version);
+
+ ASC_DBG2(1,
+ "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
+ boardp->bios_codeseg, boardp->bios_codelen);
+
+ /*
+ * If the BIOS saved a valid signature, then fill in
+ * the BIOS code segment base address.
+ */
+ if (boardp->bios_signature == 0x55AA) {
+ /*
+ * Convert x86 realmode code segment to a linear
+ * address by shifting left 4.
+ */
+ shost->base = ((ulong)boardp->bios_codeseg << 4);
+ } else {
+ shost->base = 0;
+ }
+ }
+
+ /*
+ * Register Board Resources - I/O Port, DMA, IRQ
+ */
+
+ /*
+ * Register I/O port range.
+ *
+ * For Wide boards the I/O ports are not used to access
+ * the board, but request the region anyway.
+ *
+ * 'shost->n_io_port' is not referenced, because it may be truncated.
+ */
+ ASC_DBG2(2,
+ "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
+ (ulong)shost->io_port, boardp->asc_n_io_port);
+ if (request_region(shost->io_port, boardp->asc_n_io_port,
+ "advansys") == NULL) {
+ ASC_PRINT3
+ ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
+ boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+
+ /* Register DMA Channel for Narrow boards. */
+ shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
+#ifdef CONFIG_ISA
+ if (ASC_NARROW_BOARD(boardp)) {
+ /* Register DMA channel for ISA bus. */
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
+ if ((ret =
+ request_dma(shost->dma_channel, "advansys")) != 0) {
+ ASC_PRINT3
+ ("advansys_board_found: board %d: request_dma() %d failed %d\n",
+ boardp->id, shost->dma_channel, ret);
+ release_region(shost->io_port,
+ boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+ AscEnableIsaDma(shost->dma_channel);
+ }
+ }
+#endif /* CONFIG_ISA */
+
+ /* Register IRQ Number. */
+ ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
+ /*
+ * If request_irq() fails with the IRQF_DISABLED flag set,
+ * then try again without the IRQF_DISABLED flag set. This
+ * allows IRQ sharing to work even with other drivers that
+ * do not set the IRQF_DISABLED flag.
+ *
+ * If IRQF_DISABLED is not set, then interrupts are enabled
+ * before the driver interrupt function is called.
+ */
+ if (((ret = request_irq(shost->irq, advansys_interrupt,
+ IRQF_DISABLED | (share_irq ==
+ TRUE ?
+ IRQF_SHARED :
+ 0), "advansys", boardp)) != 0)
+ &&
+ ((ret =
+ request_irq(shost->irq, advansys_interrupt,
+ (share_irq == TRUE ? IRQF_SHARED : 0),
+ "advansys", boardp)) != 0)) {
+ if (ret == -EBUSY) {
+ ASC_PRINT2
+ ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
+ boardp->id, shost->irq);
+ } else if (ret == -EINVAL) {
+ ASC_PRINT2
+ ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
+ boardp->id, shost->irq);
+ } else {
+ ASC_PRINT3
+ ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
+ boardp->id, shost->irq, ret);
+ }
+ release_region(shost->io_port, boardp->asc_n_io_port);
+ iounmap(boardp->ioremap_addr);
+ if (shost->dma_channel != NO_ISA_DMA) {
+ free_dma(shost->dma_channel);
+ }
+#ifdef CONFIG_PROC_FS
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+
+ /*
+ * Initialize board RISC chip and enable interrupts.
+ */
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
+ warn_code = AscInitAsc1000Driver(asc_dvc_varp);
+ err_code = asc_dvc_varp->err_code;
+
+ if (warn_code || err_code) {
+ ASC_PRINT4
+ ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
+ boardp->id,
+ asc_dvc_varp->init_state, warn_code, err_code);
+ }
+ } else {
+ ADV_CARR_T *carrp;
+ int req_cnt = 0;
+ adv_req_t *reqp = NULL;
+ int sg_cnt = 0;
+
+ /*
+ * Allocate buffer carrier structures. The total size
+ * is about 4 KB, so allocate all at once.
+ */
+ carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
+ ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
+
+ if (carrp == NULL) {
+ goto kmalloc_error;
+ }
+
+ /*
+ * Allocate up to 'max_host_qng' request structures for
+ * the Wide board. The total size is about 16 KB, so
+ * allocate all at once. If the allocation fails decrement
+ * and try again.
+ */
+ for (req_cnt = adv_dvc_varp->max_host_qng;
+ req_cnt > 0; req_cnt--) {
+
+ reqp = (adv_req_t *)
+ kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+
+ ASC_DBG3(1,
+ "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
+ (ulong)reqp, req_cnt,
+ (ulong)sizeof(adv_req_t) * req_cnt);
+
+ if (reqp != NULL) {
+ break;
+ }
+ }
+ if (reqp == NULL) {
+ goto kmalloc_error;
+ }
+
+ /*
+ * Allocate up to ADV_TOT_SG_BLOCK request structures for
+ * the Wide board. Each structure is about 136 bytes.
+ */
+ boardp->adv_sgblkp = NULL;
+ for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+
+ sgp = (adv_sgblk_t *)
+ kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
+
+ if (sgp == NULL) {
+ break;
+ }
+
+ sgp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgp;
+
+ }
+ ASC_DBG3(1,
+ "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
+ sg_cnt, sizeof(adv_sgblk_t),
+ (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
+
+ /*
+ * If no request structures or scatter-gather structures could
+ * be allocated, then return an error. Otherwise continue with
+ * initialization.
+ */
+ kmalloc_error:
+ if (carrp == NULL) {
+ ASC_PRINT1
+ ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
+ boardp->id);
+ err_code = ADV_ERROR;
+ } else if (reqp == NULL) {
+ kfree(carrp);
+ ASC_PRINT1
+ ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
+ boardp->id);
+ err_code = ADV_ERROR;
+ } else if (boardp->adv_sgblkp == NULL) {
+ kfree(carrp);
+ kfree(reqp);
+ ASC_PRINT1
+ ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
+ boardp->id);
+ err_code = ADV_ERROR;
+ } else {
+
+ /* Save carrier buffer pointer. */
+ boardp->orig_carrp = carrp;
+
+ /*
+ * Save original pointer for kfree() in case the
+ * driver is built as a module and can be unloaded.
+ */
+ boardp->orig_reqp = reqp;
+
+ adv_dvc_varp->carrier_buf = carrp;
+
+ /*
+ * Point 'adv_reqp' to the request structures and
+ * link them together.
+ */
+ req_cnt--;
+ reqp[req_cnt].next_reqp = NULL;
+ for (; req_cnt > 0; req_cnt--) {
+ reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
+ }
+ boardp->adv_reqp = &reqp[0];
+
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ ASC_DBG(2,
+ "advansys_board_found: AdvInitAsc3550Driver()\n");
+ warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+ } else if (adv_dvc_varp->chip_type ==
+ ADV_CHIP_ASC38C0800) {
+ ASC_DBG(2,
+ "advansys_board_found: AdvInitAsc38C0800Driver()\n");
+ warn_code =
+ AdvInitAsc38C0800Driver(adv_dvc_varp);
+ } else {
+ ASC_DBG(2,
+ "advansys_board_found: AdvInitAsc38C1600Driver()\n");
+ warn_code =
+ AdvInitAsc38C1600Driver(adv_dvc_varp);
+ }
+ err_code = adv_dvc_varp->err_code;
+
+ if (warn_code || err_code) {
+ ASC_PRINT3
+ ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
+ boardp->id, warn_code, err_code);
+ }
+ }
+ }
+
+ if (err_code != 0) {
+ release_region(shost->io_port, boardp->asc_n_io_port);
+ if (ASC_WIDE_BOARD(boardp)) {
+ iounmap(boardp->ioremap_addr);
+ kfree(boardp->orig_carrp);
+ boardp->orig_carrp = NULL;
+ if (boardp->orig_reqp) {
+ kfree(boardp->orig_reqp);
+ boardp->orig_reqp = boardp->adv_reqp = NULL;
+ }
+ while ((sgp = boardp->adv_sgblkp) != NULL) {
+ boardp->adv_sgblkp = sgp->next_sgblkp;
+ kfree(sgp);
+ }
+ }
+ if (shost->dma_channel != NO_ISA_DMA) {
+ free_dma(shost->dma_channel);
+ }
+#ifdef CONFIG_PROC_FS
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ free_irq(shost->irq, boardp);
+ scsi_unregister(shost);
+ asc_board_count--;
+ return NULL;
+ }
+ ASC_DBG_PRT_SCSI_HOST(2, shost);
+
+ return shost;
+}
+
+/*
+ * advansys_detect()
+ *
+ * Detect function for AdvanSys adapters.
+ *
+ * Argument is a pointer to the host driver's scsi_hosts entry.
+ *
+ * Return number of adapters found.
+ *
+ * Note: Because this function is called during system initialization
+ * it must not call SCSI mid-level functions including scsi_malloc()
+ * and scsi_free().
+ */
+static int __init advansys_detect(struct scsi_host_template *tpnt)
+{
+ static int detect_called = ASC_FALSE;
+ int iop;
+ int bus;
+ int ioport = 0;
+ struct device *dev = NULL;
+#ifdef CONFIG_PCI
+ int pci_init_search = 0;
+ struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
+ int pci_card_cnt_max = 0;
+ int pci_card_cnt = 0;
+ struct pci_dev *pdev = NULL;
+ int pci_device_id_cnt = 0;
+ unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
+ PCI_DEVICE_ID_ASP_1200A,
+ PCI_DEVICE_ID_ASP_ABP940,
+ PCI_DEVICE_ID_ASP_ABP940U,
+ PCI_DEVICE_ID_ASP_ABP940UW,
+ PCI_DEVICE_ID_38C0800_REV1,
+ PCI_DEVICE_ID_38C1600_REV1
+ };
+#endif /* CONFIG_PCI */
+
+ if (detect_called == ASC_FALSE) {
+ detect_called = ASC_TRUE;
+ } else {
+ printk
+ ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+ return 0;
+ }
+
+ ASC_DBG(1, "advansys_detect: begin\n");
+
+ asc_board_count = 0;
+
+ /*
+ * If I/O port probing has been modified, then verify and
+ * clean-up the 'asc_ioport' list.
+ */
+ if (asc_iopflag == ASC_TRUE) {
+ for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
+ ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
+ ioport, asc_ioport[ioport]);
+ if (asc_ioport[ioport] != 0) {
+ for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
+ iop++) {
+ if (_asc_def_iop_base[iop] ==
+ asc_ioport[ioport]) {
+ break;
+ }
+ }
+ if (iop == ASC_IOADR_TABLE_MAX_IX) {
+ printk
+ ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
+ asc_ioport[ioport]);
+ asc_ioport[ioport] = 0;
+ }
+ }
+ }
+ ioport = 0;
+ }
+
+ for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+
+ ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
+ bus, asc_bus_name[bus]);
+ iop = 0;
+
+ while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+
+ ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
+ asc_board_count);
+
+ switch (asc_bus[bus]) {
+ case ASC_IS_ISA:
+ case ASC_IS_VL:
+#ifdef CONFIG_ISA
+ if (asc_iopflag == ASC_FALSE) {
+ iop =
+ AscSearchIOPortAddr(iop,
+ asc_bus[bus]);
+ } else {
+ /*
+ * ISA and VL I/O port scanning has either been
+ * eliminated or limited to selected ports on
+ * the LILO command line, /etc/lilo.conf, or
+ * by setting variables when the module was loaded.
+ */
+ ASC_DBG(1,
+ "advansys_detect: I/O port scanning modified\n");
+ ioport_try_again:
+ iop = 0;
+ for (; ioport < ASC_NUM_IOPORT_PROBE;
+ ioport++) {
+ if ((iop =
+ asc_ioport[ioport]) != 0) {
+ break;
+ }
+ }
+ if (iop) {
+ ASC_DBG1(1,
+ "advansys_detect: probing I/O port 0x%x...\n",
+ iop);
+ if (!request_region
+ (iop, ASC_IOADR_GAP,
+ "advansys")) {
+ printk
+ ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
+ iop);
+ /* Don't try this I/O port twice. */
+ asc_ioport[ioport] = 0;
+ goto ioport_try_again;
+ } else if (AscFindSignature(iop)
+ == ASC_FALSE) {
+ printk
+ ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
+ iop);
+ /* Don't try this I/O port twice. */
+ release_region(iop,
+ ASC_IOADR_GAP);
+ asc_ioport[ioport] = 0;
+ goto ioport_try_again;
+ } else {
+ /*
+ * If this isn't an ISA board, then it must be
+ * a VL board. If currently looking an ISA
+ * board is being looked for then try for
+ * another ISA board in 'asc_ioport'.
+ */
+ if (asc_bus[bus] ==
+ ASC_IS_ISA
+ &&
+ (AscGetChipVersion
+ (iop,
+ ASC_IS_ISA) &
+ ASC_CHIP_VER_ISA_BIT)
+ == 0) {
+ /*
+ * Don't clear 'asc_ioport[ioport]'. Try
+ * this board again for VL. Increment
+ * 'ioport' past this board.
+ */
+ ioport++;
+ release_region
+ (iop,
+ ASC_IOADR_GAP);
+ goto ioport_try_again;
+ }
+ }
+ /*
+ * This board appears good, don't try the I/O port
+ * again by clearing its value. Increment 'ioport'
+ * for the next iteration.
+ */
+ asc_ioport[ioport++] = 0;
+ }
+ }
+#endif /* CONFIG_ISA */
+ break;
+
+ case ASC_IS_EISA:
+#ifdef CONFIG_ISA
+ iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+#endif /* CONFIG_ISA */
+ break;
+
+ case ASC_IS_PCI:
+#ifdef CONFIG_PCI
+ if (pci_init_search == 0) {
+ int i, j;
+
+ pci_init_search = 1;
+
+ /* Find all PCI cards. */
+ while (pci_device_id_cnt <
+ ASC_PCI_DEVICE_ID_CNT) {
+ if ((pdev =
+ pci_find_device
+ (PCI_VENDOR_ID_ASP,
+ pci_device_id
+ [pci_device_id_cnt],
+ pdev)) == NULL) {
+ pci_device_id_cnt++;
+ } else {
+ if (pci_enable_device
+ (pdev) == 0) {
+ pci_devicep
+ [pci_card_cnt_max++]
+ = pdev;
+ }
+ }
+ }
+
+ /*
+ * Sort PCI cards in ascending order by PCI Bus, Slot,
+ * and Device Number.
+ */
+ for (i = 0; i < pci_card_cnt_max - 1;
+ i++) {
+ for (j = i + 1;
+ j < pci_card_cnt_max;
+ j++) {
+ if ((pci_devicep[j]->
+ bus->number <
+ pci_devicep[i]->
+ bus->number)
+ ||
+ ((pci_devicep[j]->
+ bus->number ==
+ pci_devicep[i]->
+ bus->number)
+ &&
+ (pci_devicep[j]->
+ devfn <
+ pci_devicep[i]->
+ devfn))) {
+ pdev =
+ pci_devicep
+ [i];
+ pci_devicep[i] =
+ pci_devicep
+ [j];
+ pci_devicep[j] =
+ pdev;
+ }
+ }
+ }
+
+ pci_card_cnt = 0;
+ } else {
+ pci_card_cnt++;
+ }
+
+ if (pci_card_cnt == pci_card_cnt_max) {
+ iop = 0;
+ } else {
+ pdev = pci_devicep[pci_card_cnt];
+
+ ASC_DBG2(2,
+ "advansys_detect: devfn %d, bus number %d\n",
+ pdev->devfn,
+ pdev->bus->number);
+ iop = pci_resource_start(pdev, 0);
+ ASC_DBG2(1,
+ "advansys_detect: vendorID %X, deviceID %X\n",
+ pdev->vendor,
+ pdev->device);
+ ASC_DBG2(2,
+ "advansys_detect: iop %X, irqLine %d\n",
+ iop, pdev->irq);
+ }
+ if (pdev)
+ dev = &pdev->dev;
+
+#endif /* CONFIG_PCI */
+ break;
+
+ default:
+ ASC_PRINT1
+ ("advansys_detect: unknown bus type: %d\n",
+ asc_bus[bus]);
+ break;
+ }
+ ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
+
+ /*
+ * Adapter not found, try next bus type.
+ */
+ if (iop == 0) {
+ break;
+ }
+
+ advansys_board_found(iop, dev, asc_bus[bus]);
+ }
+ }
+
+ ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
+ asc_board_count);
+ return asc_board_count;
+}
+
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+static int advansys_release(struct Scsi_Host *shost)
+{
+ asc_board_t *boardp;
+
+ ASC_DBG(1, "advansys_release: begin\n");
+ boardp = ASC_BOARDP(shost);
+ free_irq(shost->irq, boardp);
+ if (shost->dma_channel != NO_ISA_DMA) {
+ ASC_DBG(1, "advansys_release: free_dma()\n");
+ free_dma(shost->dma_channel);
+ }
+ release_region(shost->io_port, boardp->asc_n_io_port);
+ if (ASC_WIDE_BOARD(boardp)) {
+ adv_sgblk_t *sgp = NULL;
+
+ iounmap(boardp->ioremap_addr);
+ kfree(boardp->orig_carrp);
+ boardp->orig_carrp = NULL;
+ if (boardp->orig_reqp) {
+ kfree(boardp->orig_reqp);
+ boardp->orig_reqp = boardp->adv_reqp = NULL;
+ }
+ while ((sgp = boardp->adv_sgblkp) != NULL) {
+ boardp->adv_sgblkp = sgp->next_sgblkp;
+ kfree(sgp);
+ }
+ }
+#ifdef CONFIG_PROC_FS
+ ASC_ASSERT(boardp->prtbuf != NULL);
+ kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+ scsi_unregister(shost);
+ ASC_DBG(1, "advansys_release: end\n");
+ return 0;
+}
+
#ifdef CONFIG_PCI
/* PCI Devices supported by this driver */
static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { }
+ {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {}
};
+
MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
#endif /* CONFIG_PCI */
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 85f2394ffc3e..d30a30786dda 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -289,18 +289,18 @@ static LIST_HEAD(aha152x_host_list);
if(spin_is_locked(&QLOCK)) { \
DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
} \
- DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+ DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
spin_lock_irqsave(&QLOCK,flags); \
- DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+ DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
QLOCKER=__FUNCTION__; \
QLOCKERL=__LINE__; \
} while(0)
#define DO_UNLOCK(flags) \
do { \
- DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+ DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
spin_unlock_irqrestore(&QLOCK,flags); \
- DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+ DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
QLOCKER="(not locked)"; \
QLOCKERL=0; \
} while(0)
@@ -322,6 +322,12 @@ static LIST_HEAD(aha152x_host_list);
(cmd) ? ((cmd)->device->id & 0x0f) : -1, \
(cmd) ? ((cmd)->device->lun & 0x07) : -1
+static inline void
+CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
+{
+ scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
+}
+
#define DELAY_DEFAULT 1000
#if defined(PCMCIA)
@@ -552,14 +558,11 @@ struct aha152x_hostdata {
struct aha152x_scdata {
Scsi_Cmnd *next; /* next sc in queue */
struct completion *done;/* semaphore to block on */
- unsigned char cmd_len;
- unsigned char cmnd[MAX_COMMAND_SIZE];
- unsigned short use_sg;
- unsigned request_bufflen;
- void *request_buffer;
+ unsigned char aha_orig_cmd_len;
+ unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE];
+ int aha_orig_resid;
};
-
/* access macros for hostdata */
#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
@@ -978,15 +981,15 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
#if defined(AHA152X_DEBUG)
if (HOSTDATA(shpnt)->debug & debug_queue) {
printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
- CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+ CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len,
+ scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
__scsi_print_command(SCpnt->cmnd);
}
#endif
SCpnt->scsi_done = done;
- SCpnt->resid = SCpnt->request_bufflen;
SCpnt->SCp.phase = not_issued | phase;
- SCpnt->SCp.Status = CHECK_CONDITION;
+ SCpnt->SCp.Status = 0x1; /* Ilegal status by SCSI standard */
SCpnt->SCp.Message = 0;
SCpnt->SCp.have_data_in = 0;
SCpnt->SCp.sent_command = 0;
@@ -997,20 +1000,11 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
return FAILED;
}
} else {
- struct aha152x_scdata *sc;
-
SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
if(SCpnt->host_scribble==0) {
printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
return FAILED;
}
-
- sc = SCDATA(SCpnt);
- memcpy(sc->cmnd, SCpnt->cmnd, sizeof(sc->cmnd));
- sc->request_buffer = SCpnt->request_buffer;
- sc->request_bufflen = SCpnt->request_bufflen;
- sc->use_sg = SCpnt->use_sg;
- sc->cmd_len = SCpnt->cmd_len;
}
SCNEXT(SCpnt) = NULL;
@@ -1022,16 +1016,25 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
SCp.buffer : next buffer
SCp.buffers_residual : left buffers in list
SCp.phase : current state of the command */
- if (SCpnt->use_sg) {
- SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
- SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
- } else {
- SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
- SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+
+ if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) {
+ if (phase & check_condition) {
+ SCpnt->SCp.ptr = SCpnt->sense_buffer;
+ SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+ scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer));
+ } else {
+ SCpnt->SCp.ptr = NULL;
+ SCpnt->SCp.this_residual = 0;
+ scsi_set_resid(SCpnt, 0);
+ }
SCpnt->SCp.buffer = NULL;
SCpnt->SCp.buffers_residual = 0;
+ } else {
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+ SCpnt->SCp.buffer = scsi_sglist(SCpnt);
+ SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
+ SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+ SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
}
DO_LOCK(flags);
@@ -1150,9 +1153,6 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
DECLARE_COMPLETION(done);
int ret, issued, disconnected;
unsigned char old_cmd_len = SCpnt->cmd_len;
- unsigned short old_use_sg = SCpnt->use_sg;
- void *old_buffer = SCpnt->request_buffer;
- unsigned old_bufflen = SCpnt->request_bufflen;
unsigned long flags;
unsigned long timeleft;
@@ -1174,9 +1174,6 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
DO_UNLOCK(flags);
SCpnt->cmd_len = 0;
- SCpnt->use_sg = 0;
- SCpnt->request_buffer = NULL;
- SCpnt->request_bufflen = 0;
aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
@@ -1189,9 +1186,6 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
}
SCpnt->cmd_len = old_cmd_len;
- SCpnt->use_sg = old_use_sg;
- SCpnt->request_buffer = old_buffer;
- SCpnt->request_bufflen = old_bufflen;
DO_LOCK(flags);
@@ -1531,8 +1525,8 @@ static void busfree_run(struct Scsi_Host *shpnt)
/* target sent DISCONNECT */
DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
CMDINFO(CURRENT_SC),
- CURRENT_SC->resid,
- CURRENT_SC->request_bufflen);
+ scsi_get_resid(CURRENT_SC),
+ scsi_bufflen(CURRENT_SC));
#if defined(AHA152X_STAT)
HOSTDATA(shpnt)->disconnections++;
#endif
@@ -1568,18 +1562,16 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
/* restore old command */
- memcpy(cmd->cmnd, sc->cmnd, sizeof(sc->cmnd));
- cmd->request_buffer = sc->request_buffer;
- cmd->request_bufflen = sc->request_bufflen;
- cmd->use_sg = sc->use_sg;
- cmd->cmd_len = sc->cmd_len;
+ memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd));
+ cmd->cmd_len = sc->aha_orig_cmd_len;
+ scsi_set_resid(cmd, sc->aha_orig_resid);
- cmd->SCp.Status = 0x02;
+ cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
SETPORT(PORTA, 0); /* turn led off */
- } else if(DONE_SC->SCp.Status==0x02) {
+ } else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) {
#if defined(AHA152X_STAT)
HOSTDATA(shpnt)->busfree_with_check_condition++;
#endif
@@ -1587,13 +1579,23 @@ static void busfree_run(struct Scsi_Host *shpnt)
DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
#endif
- if(!(DONE_SC->SCp.Status & not_issued)) {
+ if(!(DONE_SC->SCp.phase & not_issued)) {
+ struct aha152x_scdata *sc;
Scsi_Cmnd *ptr = DONE_SC;
DONE_SC=NULL;
#if 0
DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
#endif
+ /* save old command */
+ sc = SCDATA(ptr);
+ /* It was allocated in aha152x_internal_queue? */
+ BUG_ON(!sc);
+ memcpy(sc->aha_orig_cmnd, ptr->cmnd,
+ sizeof(ptr->cmnd));
+ sc->aha_orig_cmd_len = ptr->cmd_len;
+ sc->aha_orig_resid = scsi_get_resid(ptr);
+
ptr->cmnd[0] = REQUEST_SENSE;
ptr->cmnd[1] = 0;
ptr->cmnd[2] = 0;
@@ -1601,10 +1603,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
ptr->cmnd[4] = sizeof(ptr->sense_buffer);
ptr->cmnd[5] = 0;
ptr->cmd_len = 6;
- ptr->use_sg = 0;
- ptr->request_buffer = ptr->sense_buffer;
- ptr->request_bufflen = sizeof(ptr->sense_buffer);
-
+
DO_UNLOCK(flags);
aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
DO_LOCK(flags);
@@ -2180,7 +2179,8 @@ static void datai_init(struct Scsi_Host *shpnt)
DATA_LEN=0;
DPRINTK(debug_datai,
DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
- CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+ CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+ scsi_get_resid(CURRENT_SC));
}
static void datai_run(struct Scsi_Host *shpnt)
@@ -2293,11 +2293,12 @@ static void datai_run(struct Scsi_Host *shpnt)
static void datai_end(struct Scsi_Host *shpnt)
{
- CURRENT_SC->resid -= GETSTCNT();
+ CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
DPRINTK(debug_datai,
DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
- CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
+ CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+ scsi_get_resid(CURRENT_SC), GETSTCNT());
SETPORT(SXFRCTL0, CH1|CLRSTCNT);
SETPORT(DMACNTRL0, 0);
@@ -2318,11 +2319,12 @@ static void datao_init(struct Scsi_Host *shpnt)
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
- DATA_LEN = CURRENT_SC->resid;
+ DATA_LEN = scsi_get_resid(CURRENT_SC);
DPRINTK(debug_datao,
DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
- CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+ CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+ scsi_get_resid(CURRENT_SC));
}
static void datao_run(struct Scsi_Host *shpnt)
@@ -2346,7 +2348,7 @@ static void datao_run(struct Scsi_Host *shpnt)
SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
CURRENT_SC->SCp.this_residual--;
- CURRENT_SC->resid--;
+ CMD_INC_RESID(CURRENT_SC, -1);
SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
}
@@ -2355,7 +2357,7 @@ static void datao_run(struct Scsi_Host *shpnt)
outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
CURRENT_SC->SCp.ptr += 2 * data_count;
CURRENT_SC->SCp.this_residual -= 2 * data_count;
- CURRENT_SC->resid -= 2 * data_count;
+ CMD_INC_RESID(CURRENT_SC, -2 * data_count);
}
if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
@@ -2381,35 +2383,34 @@ static void datao_run(struct Scsi_Host *shpnt)
static void datao_end(struct Scsi_Host *shpnt)
{
if(TESTLO(DMASTAT, DFIFOEMP)) {
- int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+ int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
+ GETSTCNT();
DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
CMDINFO(CURRENT_SC),
data_count,
- DATA_LEN-CURRENT_SC->resid,
+ DATA_LEN - scsi_get_resid(CURRENT_SC),
GETSTCNT());
- CURRENT_SC->resid += data_count;
+ CMD_INC_RESID(CURRENT_SC, data_count);
- if(CURRENT_SC->use_sg) {
- data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
- while(data_count>0) {
- CURRENT_SC->SCp.buffer--;
- CURRENT_SC->SCp.buffers_residual++;
- data_count -= CURRENT_SC->SCp.buffer->length;
- }
- CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
- } else {
- CURRENT_SC->SCp.ptr -= data_count;
- CURRENT_SC->SCp.this_residual += data_count;
+ data_count -= CURRENT_SC->SCp.ptr -
+ SG_ADDRESS(CURRENT_SC->SCp.buffer);
+ while(data_count>0) {
+ CURRENT_SC->SCp.buffer--;
+ CURRENT_SC->SCp.buffers_residual++;
+ data_count -= CURRENT_SC->SCp.buffer->length;
}
+ CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
+ data_count;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
+ data_count;
}
DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
CMDINFO(CURRENT_SC),
- CURRENT_SC->request_bufflen,
- CURRENT_SC->resid,
+ scsi_bufflen(CURRENT_SC),
+ scsi_get_resid(CURRENT_SC),
GETSTCNT());
SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2936,7 +2937,7 @@ static void show_command(Scsi_Cmnd *ptr)
__scsi_print_command(ptr->cmnd);
printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
- ptr->request_bufflen, ptr->resid);
+ scsi_bufflen(ptr), scsi_get_resid(ptr));
if (ptr->SCp.phase & not_issued)
printk("not issued|");
@@ -3006,7 +3007,8 @@ static int get_command(char *pos, Scsi_Cmnd * ptr)
SPRINTF("0x%02x ", ptr->cmnd[i]);
SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
- ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+ scsi_get_resid(ptr), ptr->SCp.this_residual,
+ ptr->SCp.buffers_residual);
if (ptr->SCp.phase & not_issued)
SPRINTF("not issued|");
@@ -3395,7 +3397,7 @@ static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start
PDEBUG(debug_datai, "data in");
PDEBUG(debug_datao, "data out");
PDEBUG(debug_eh, "eh");
- PDEBUG(debug_locks, "locks");
+ PDEBUG(debug_locking, "locks");
PDEBUG(debug_phases, "phases");
SPRINTF("\n");
@@ -3474,6 +3476,12 @@ static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start
return thislength < length ? thislength : length;
}
+static int aha152x_adjust_queue(struct scsi_device *device)
+{
+ blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
+ return 0;
+}
+
static struct scsi_host_template aha152x_driver_template = {
.module = THIS_MODULE,
.name = AHA152X_REVID,
@@ -3490,6 +3498,7 @@ static struct scsi_host_template aha152x_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
+ .slave_alloc = aha152x_adjust_queue,
};
#if !defined(PCMCIA)
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
index d2add24d02a3..ac4bfa438bf2 100644
--- a/drivers/scsi/aha152x.h
+++ b/drivers/scsi/aha152x.h
@@ -298,7 +298,7 @@ typedef union {
enum {
debug_procinfo = 0x0001,
debug_queue = 0x0002,
- debug_locks = 0x0004,
+ debug_locking = 0x0004,
debug_intr = 0x0008,
debug_selection = 0x0010,
debug_msgo = 0x0020,
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 286ab83116f9..a055a96e3ad3 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -2284,9 +2284,12 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period)
if (period < 8)
period = 8;
if (period < 10) {
- ppr_options |= MSG_EXT_PPR_DT_REQ;
- if (period == 8)
- ppr_options |= MSG_EXT_PPR_IU_REQ;
+ if (spi_max_width(starget)) {
+ ppr_options |= MSG_EXT_PPR_DT_REQ;
+ if (period == 8)
+ ppr_options |= MSG_EXT_PPR_IU_REQ;
+ } else
+ period = 10;
}
dt = ppr_options & MSG_EXT_PPR_DT_REQ;
@@ -2365,7 +2368,7 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt)
printf("%s: %s DT\n", ahd_name(ahd),
dt ? "enabling" : "disabling");
#endif
- if (dt) {
+ if (dt && spi_max_width(starget)) {
ppr_options |= MSG_EXT_PPR_DT_REQ;
if (!width)
ahd_linux_set_width(starget, 1);
@@ -2447,7 +2450,7 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu)
iu ? "enabling" : "disabling");
#endif
- if (iu) {
+ if (iu && spi_max_width(starget)) {
ppr_options |= MSG_EXT_PPR_IU_REQ;
ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */
}
@@ -2487,7 +2490,7 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm)
rdstrm ? "enabling" : "disabling");
#endif
- if (rdstrm)
+ if (rdstrm && spi_max_width(starget))
ppr_options |= MSG_EXT_PPR_RD_STRM;
ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2523,7 +2526,7 @@ static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow)
wrflow ? "enabling" : "disabling");
#endif
- if (wrflow)
+ if (wrflow && spi_max_width(starget))
ppr_options |= MSG_EXT_PPR_WR_FLOW;
ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2567,7 +2570,7 @@ static void ahd_linux_set_rti(struct scsi_target *starget, int rti)
rti ? "enabling" : "disabling");
#endif
- if (rti)
+ if (rti && spi_max_width(starget))
ppr_options |= MSG_EXT_PPR_RTI;
ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2603,7 +2606,7 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
pcomp ? "Enable" : "Disable");
#endif
- if (pcomp) {
+ if (pcomp && spi_max_width(starget)) {
uint8_t precomp;
if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
@@ -2647,7 +2650,7 @@ static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold)
unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
unsigned long flags;
- if (hold)
+ if (hold && spi_max_width(starget))
ppr_options |= MSG_EXT_PPR_HOLD_MCS;
ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 75733b09f27a..f350b5e89e76 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -1701,7 +1701,16 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
&& maxsync < AHC_SYNCRATE_ULTRA2)
maxsync = AHC_SYNCRATE_ULTRA2;
-
+
+ /* Now set the maxsync based on the card capabilities
+ * DT is already done above */
+ if ((ahc->features & (AHC_DT | AHC_ULTRA2)) == 0
+ && maxsync < AHC_SYNCRATE_ULTRA)
+ maxsync = AHC_SYNCRATE_ULTRA;
+ if ((ahc->features & (AHC_DT | AHC_ULTRA2 | AHC_ULTRA)) == 0
+ && maxsync < AHC_SYNCRATE_FAST)
+ maxsync = AHC_SYNCRATE_FAST;
+
for (syncrate = &ahc_syncrates[maxsync];
syncrate->rate != NULL;
syncrate++) {
@@ -1765,6 +1774,17 @@ ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
else
scsirate &= SXFR;
+ /* now set maxsync based on card capabilities */
+ if ((ahc->features & AHC_DT) == 0 && maxsync < AHC_SYNCRATE_ULTRA2)
+ maxsync = AHC_SYNCRATE_ULTRA2;
+ if ((ahc->features & (AHC_DT | AHC_ULTRA2)) == 0
+ && maxsync < AHC_SYNCRATE_ULTRA)
+ maxsync = AHC_SYNCRATE_ULTRA;
+ if ((ahc->features & (AHC_DT | AHC_ULTRA2 | AHC_ULTRA)) == 0
+ && maxsync < AHC_SYNCRATE_FAST)
+ maxsync = AHC_SYNCRATE_FAST;
+
+
syncrate = &ahc_syncrates[maxsync];
while (syncrate->rate != NULL) {
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 1803ab6fc21c..2e9c38f2e8a6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -2317,8 +2317,13 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period)
if (period < 9)
period = 9; /* 12.5ns is our minimum */
- if (period == 9)
- ppr_options |= MSG_EXT_PPR_DT_REQ;
+ if (period == 9) {
+ if (spi_max_width(starget))
+ ppr_options |= MSG_EXT_PPR_DT_REQ;
+ else
+ /* need wide for DT and need DT for 12.5 ns */
+ period = 10;
+ }
ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
starget->channel + 'A', ROLE_INITIATOR);
@@ -2381,7 +2386,7 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
unsigned long flags;
struct ahc_syncrate *syncrate;
- if (dt) {
+ if (dt && spi_max_width(starget)) {
ppr_options |= MSG_EXT_PPR_DT_REQ;
if (!width)
ahc_linux_set_width(starget, 1);
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index c520e5b41fb5..3dce618bf414 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -126,7 +126,7 @@ static inline int asd_init_sata(struct domain_device *dev)
if (w76 & 0x100) /* NCQ? */
qdepth = (w75 & 0x1F) + 1;
asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
- (1<<qdepth)-1);
+ (1ULL<<qdepth)-1);
asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
}
if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 1c0d7578e791..63bcde246447 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -81,6 +81,9 @@ static struct scsi_host_template aic94xx_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .slave_alloc = sas_slave_alloc,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
};
static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
@@ -462,7 +465,7 @@ static int asd_create_global_caches(void)
sizeof(struct asd_dma_tok),
0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!asd_dma_token_cache) {
asd_printk("couldn't create dma token cache\n");
return -ENOMEM;
@@ -474,7 +477,7 @@ static int asd_create_global_caches(void)
sizeof(struct asd_ascb),
0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!asd_ascb_cache) {
asd_printk("couldn't create ascb cache\n");
goto Err;
@@ -583,7 +586,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
goto Err;
}
asd_ha->pcidev = dev;
- asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+ asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
asd_ha->sas_ha.lldd_ha = asd_ha;
asd_ha->name = asd_dev->name;
@@ -602,8 +605,6 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
goto Err_free;
}
-
-
err = asd_dev->setup(asd_ha);
if (err)
goto Err_free;
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index e2ad5bed9403..ab13824df856 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -74,8 +74,13 @@ static inline int asd_map_scatterlist(struct sas_task *task,
return 0;
}
- num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ /* STP tasks come from libata which has already mapped
+ * the SG list */
+ if (sas_protocol_ata(task->task_proto))
+ num_sg = task->num_scatter;
+ else
+ num_sg = pci_map_sg(asd_ha->pcidev, task->scatter,
+ task->num_scatter, task->data_dir);
if (num_sg == 0)
return -ENOMEM;
@@ -120,8 +125,9 @@ static inline int asd_map_scatterlist(struct sas_task *task,
return 0;
err_unmap:
- pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ if (sas_protocol_ata(task->task_proto))
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
return res;
}
@@ -142,8 +148,9 @@ static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
}
asd_free_coherent(asd_ha, ascb->sg_arr);
- pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ if (task->task_proto != SAS_PROTOCOL_STP)
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
}
/* ---------- Task complete tasklet ---------- */
@@ -391,7 +398,6 @@ static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
scb->ata_task.fis = task->ata_task.fis;
- scb->ata_task.fis.fis_type = 0x27;
if (likely(!task->ata_task.device_control_reg_update))
scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
@@ -445,7 +451,7 @@ static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
struct scb *scb;
pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
- PCI_DMA_FROMDEVICE);
+ PCI_DMA_TODEVICE);
pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
PCI_DMA_FROMDEVICE);
@@ -480,7 +486,7 @@ static void asd_unbuild_smp_ascb(struct asd_ascb *a)
BUG_ON(!task);
pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
- PCI_DMA_FROMDEVICE);
+ PCI_DMA_TODEVICE);
pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
PCI_DMA_FROMDEVICE);
}
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
index d006a8cb4a74..7236143941f3 100644
--- a/drivers/scsi/arm/Kconfig
+++ b/drivers/scsi/arm/Kconfig
@@ -74,15 +74,6 @@ config SCSI_CUMANA_1
This enables support for the Cumana SCSI I card. If you have an
Acorn system with one of these, say Y. If unsure, say N.
-config SCSI_ECOSCSI
- tristate "EcoScsi support (EXPERIMENTAL)"
- depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
- select SCSI_SPI_ATTRS
- help
- This enables support for the EcoSCSI card -- a small card that sits
- in the Econet socket. If you have an Acorn system with one of these,
- say Y. If unsure, say N.
-
config SCSI_OAK1
tristate "Oak SCSI support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && SCSI
diff --git a/drivers/scsi/arm/Makefile b/drivers/scsi/arm/Makefile
index e8db17924c1d..16c3e86a6b1b 100644
--- a/drivers/scsi/arm/Makefile
+++ b/drivers/scsi/arm/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_SCSI_ACORNSCSI_3) += acornscsi_mod.o queue.o msgqueue.o
obj-$(CONFIG_SCSI_ARXESCSI) += arxescsi.o fas216.o queue.o msgqueue.o
obj-$(CONFIG_SCSI_CUMANA_1) += cumana_1.o
obj-$(CONFIG_SCSI_CUMANA_2) += cumana_2.o fas216.o queue.o msgqueue.o
-obj-$(CONFIG_SCSI_ECOSCSI) += ecoscsi.o
obj-$(CONFIG_SCSI_OAK1) += oak.o
obj-$(CONFIG_SCSI_POWERTECSCSI) += powertec.o fas216.o queue.o msgqueue.o
obj-$(CONFIG_SCSI_EESOXSCSI) += eesox.o fas216.o queue.o msgqueue.o
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index cf9a21cea6d9..49d838e90a24 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -24,7 +24,7 @@
#define CUMANASCSI_PUBLIC_RELEASE 1
-#define NCR5380_implementation_fields int port, ctrl
+#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
#define NCR5380_local_declare() struct Scsi_Host *_instance
#define NCR5380_setup(instance) _instance = instance
#define NCR5380_read(reg) cumanascsi_read(_instance, reg)
@@ -33,6 +33,11 @@
#define NCR5380_queue_command cumanascsi_queue_command
#define NCR5380_proc_info cumanascsi_proc_info
+#define NCR5380_implementation_fields \
+ unsigned ctrl; \
+ void __iomem *base; \
+ void __iomem *dma
+
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
@@ -47,192 +52,162 @@ const char *cumanascsi_info(struct Scsi_Host *spnt)
return "";
}
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
-#define STAT(p) inb((p)+1)
-#define IN(p) inb((p))
-#define OUT(v,p) outb((v), (p))
-#else
-#define CTRL(p,v) (p[-2308] = (*ctrl = (v)))
-#define STAT(p) (p[4])
-#define IN(p) (*(p))
-#define IN2(p) ((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p) (*(p) = (v))
-#define OUT2(v,p) (*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v) (((v)<<16)|((v) & 0x0000ffff))
-#define H(v) (((v)>>16)|((v) & 0xffff0000))
+#define CTRL 0x16fc
+#define STAT 0x2004
+#define L(v) (((v)<<16)|((v) & 0x0000ffff))
+#define H(v) (((v)>>16)|((v) & 0xffff0000))
static inline int
-NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
{
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
- int oldctrl = *ctrl;
unsigned long *laddr;
-#ifdef NOT_EFFICIENT
- int iobase = instance->io_port;
- int dma_io = iobase & ~(0x3C0000>>2);
-#else
- volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
- volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+ void __iomem *dma = priv(host)->dma + 0x2000;
if(!len) return 0;
- CTRL(iobase, 0x02);
+ writeb(0x02, priv(host)->base + CTRL);
laddr = (unsigned long *)addr;
while(len >= 32)
{
- int status;
+ unsigned int status;
unsigned long v;
- status = STAT(iobase);
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(!(status & 0x40))
continue;
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
len -= 32;
if(len == 0)
break;
}
addr = (unsigned char *)laddr;
- CTRL(iobase, 0x12);
+ writeb(0x12, priv(host)->base + CTRL);
+
while(len > 0)
{
- int status;
- status = STAT(iobase);
+ unsigned int status;
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- OUT(*addr++, dma_io);
+ writeb(*addr++, dma);
if(--len == 0)
break;
}
- status = STAT(iobase);
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- OUT(*addr++, dma_io);
+ writeb(*addr++, dma);
if(--len == 0)
break;
}
}
end:
- CTRL(iobase, oldctrl|0x40);
+ writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
return len;
}
static inline int
-NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
{
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
- int oldctrl = *ctrl;
unsigned long *laddr;
-#ifdef NOT_EFFICIENT
- int iobase = instance->io_port;
- int dma_io = iobase & ~(0x3C0000>>2);
-#else
- volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
- volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+ void __iomem *dma = priv(host)->dma + 0x2000;
if(!len) return 0;
- CTRL(iobase, 0x00);
+ writeb(0x00, priv(host)->base + CTRL);
laddr = (unsigned long *)addr;
while(len >= 32)
{
- int status;
- status = STAT(iobase);
+ unsigned int status;
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(!(status & 0x40))
continue;
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
len -= 32;
if(len == 0)
break;
}
addr = (unsigned char *)laddr;
- CTRL(iobase, 0x10);
+ writeb(0x10, priv(host)->base + CTRL);
+
while(len > 0)
{
- int status;
- status = STAT(iobase);
+ unsigned int status;
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- *addr++ = IN(dma_io);
+ *addr++ = readb(dma);
if(--len == 0)
break;
}
- status = STAT(iobase);
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- *addr++ = IN(dma_io);
+ *addr++ = readb(dma);
if(--len == 0)
break;
}
}
end:
- CTRL(iobase, oldctrl|0x40);
+ writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
return len;
}
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
+static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
+{
+ void __iomem *base = priv(host)->base;
+ unsigned char val;
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
+ writeb(0, base + CTRL);
-static char cumanascsi_read(struct Scsi_Host *instance, int reg)
-{
- unsigned int iobase = instance->io_port;
- int i;
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+ val = readb(base + 0x2100 + (reg << 2));
- CTRL(iobase, 0);
- i = inb(iobase + 64 + reg);
- CTRL(iobase, 0x40);
+ priv(host)->ctrl = 0x40;
+ writeb(0x40, base + CTRL);
- return i;
+ return val;
}
-static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
+static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
{
- int iobase = instance->io_port;
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+ void __iomem *base = priv(host)->base;
- CTRL(iobase, 0);
- outb(value, iobase + 64 + reg);
- CTRL(iobase, 0x40);
-}
+ writeb(0, base + CTRL);
-#undef CTRL
+ writeb(value, base + 0x2100 + (reg << 2));
+
+ priv(host)->ctrl = 0x40;
+ writeb(0x40, base + CTRL);
+}
#include "../NCR5380.c"
@@ -256,32 +231,46 @@ static int __devinit
cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct Scsi_Host *host;
- int ret = -ENOMEM;
+ int ret;
- host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
- if (!host)
+ ret = ecard_request_resources(ec);
+ if (ret)
goto out;
- host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
+ host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
+ if (!host) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
+
+ priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
+ ecard_resource_len(ec, ECARD_RES_IOCSLOW));
+ priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!priv(host)->base || !priv(host)->dma) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+
host->irq = ec->irq;
NCR5380_init(host, 0);
+ priv(host)->ctrl = 0;
+ writeb(0, priv(host)->base + CTRL);
+
host->n_io_port = 255;
if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
ret = -EBUSY;
- goto out_free;
+ goto out_unmap;
}
- ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
- outb(0x00, host->io_port - 577);
-
ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, host->irq, ret);
- goto out_release;
+ goto out_unmap;
}
printk("scsi%d: at port 0x%08lx irq %d",
@@ -301,10 +290,12 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
out_free_irq:
free_irq(host->irq, host);
- out_release:
- release_region(host->io_port, host->n_io_port);
- out_free:
+ out_unmap:
+ iounmap(priv(host)->base);
+ iounmap(priv(host)->dma);
scsi_host_put(host);
+ out_release:
+ ecard_release_resources(ec);
out:
return ret;
}
@@ -318,8 +309,10 @@ static void __devexit cumanascsi1_remove(struct expansion_card *ec)
scsi_remove_host(host);
free_irq(host->irq, host);
NCR5380_exit(host);
- release_region(host->io_port, host->n_io_port);
+ iounmap(priv(host)->base);
+ iounmap(priv(host)->dma);
scsi_host_put(host);
+ ecard_release_resources(ec);
}
static const struct ecard_id cumanascsi1_cids[] = {
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
deleted file mode 100644
index 378e7af0c5d6..000000000000
--- a/drivers/scsi/arm/ecoscsi.c
+++ /dev/null
@@ -1,236 +0,0 @@
-#define AUTOSENSE
-/* #define PSEUDO_DMA */
-
-/*
- * EcoSCSI Generic NCR5380 driver
- *
- * Copyright 1995, Russell King
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
- */
-
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include "../scsi.h"
-#include <scsi/scsi_host.h>
-
-#define NCR5380_implementation_fields int port, ctrl
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
-
-#define NCR5380_read(reg) ecoscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value)
-
-#define NCR5380_intr ecoscsi_intr
-#define NCR5380_queue_command ecoscsi_queue_command
-#define NCR5380_proc_info ecoscsi_proc_info
-
-#include "../NCR5380.h"
-
-#define ECOSCSI_PUBLIC_RELEASE 1
-
-static char ecoscsi_read(struct Scsi_Host *instance, int reg)
-{
- int iobase = instance->io_port;
- outb(reg | 8, iobase);
- return inb(iobase + 1);
-}
-
-static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
- int iobase = instance->io_port;
- outb(reg | 8, iobase);
- outb(value, iobase + 1);
-}
-
-/*
- * Function : ecoscsi_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- * equal to the number of ints.
- *
- */
-
-void ecoscsi_setup(char *str, int *ints)
-{
-}
-
-const char * ecoscsi_info (struct Scsi_Host *spnt)
-{
- return "";
-}
-
-#if 0
-#define STAT(p) inw(p + 144)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
- int len)
-{
- int iobase = host->io_port;
-printk("writing %p len %d\n",addr, len);
- if(!len) return -1;
-
- while(1)
- {
- int status;
- while(((status = STAT(iobase)) & 0x100)==0);
- }
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
- int len)
-{
- int iobase = host->io_port;
- int iobase2= host->io_port + 0x100;
- unsigned char *start = addr;
- int s;
-printk("reading %p len %d\n",addr, len);
- outb(inb(iobase + 128), iobase + 135);
- while(len > 0)
- {
- int status,b,i, timeout;
- timeout = 0x07FFFFFF;
- while(((status = STAT(iobase)) & 0x100)==0)
- {
- timeout--;
- if(status & 0x200 || !timeout)
- {
- printk("status = %p\n",status);
- outb(0, iobase + 135);
- return 1;
- }
- }
- if(len >= 128)
- {
- for(i=0; i<64; i++)
- {
- b = inw(iobase + 136);
- *addr++ = b;
- *addr++ = b>>8;
- }
- len -= 128;
- }
- else
- {
- b = inw(iobase + 136);
- *addr ++ = b;
- len -= 1;
- if(len)
- *addr ++ = b>>8;
- len -= 1;
- }
- }
- outb(0, iobase + 135);
- printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
- return 1;
-}
-#endif
-#undef STAT
-
-#define BOARD_NORMAL 0
-#define BOARD_NCR53C400 1
-
-#include "../NCR5380.c"
-
-static struct scsi_host_template ecoscsi_template = {
- .module = THIS_MODULE,
- .name = "Serial Port EcoSCSI NCR5380",
- .proc_name = "ecoscsi",
- .info = ecoscsi_info,
- .queuecommand = ecoscsi_queue_command,
- .eh_abort_handler = NCR5380_abort,
- .eh_bus_reset_handler = NCR5380_bus_reset,
- .can_queue = 16,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-static struct Scsi_Host *host;
-
-static int __init ecoscsi_init(void)
-{
-
- host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
- if (!host)
- return 0;
-
- host->io_port = 0x80ce8000;
- host->n_io_port = 144;
- host->irq = IRQ_NONE;
-
- if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
- goto unregister_scsi;
-
- ecoscsi_write(host, MODE_REG, 0x20); /* Is it really SCSI? */
- if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg. */
- goto release_reg;
-
- ecoscsi_write(host, MODE_REG, 0x00 ); /* it back. */
- if (ecoscsi_read(host, MODE_REG) != 0x00)
- goto release_reg;
-
- NCR5380_init(host, 0);
-
- printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
- printk("\nscsi%d:", host->host_no);
- NCR5380_print_options(host);
- printk("\n");
-
- scsi_add_host(host, NULL); /* XXX handle failure */
- scsi_scan_host(host);
- return 0;
-
-release_reg:
- release_region(host->io_port, host->n_io_port);
-unregister_scsi:
- scsi_host_put(host);
- return -ENODEV;
-}
-
-static void __exit ecoscsi_exit(void)
-{
- scsi_remove_host(host);
-
- if (shpnt->irq != IRQ_NONE)
- free_irq(shpnt->irq, NULL);
- NCR5380_exit(host);
- if (shpnt->io_port)
- release_region(shpnt->io_port, shpnt->n_io_port);
-
- scsi_host_put(host);
- return 0;
-}
-
-module_init(ecoscsi_init);
-module_exit(ecoscsi_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index c21b8392c928..849cdf89f7bb 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -23,15 +23,18 @@
#define OAKSCSI_PUBLIC_RELEASE 1
-#define NCR5380_read(reg) oakscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value)
+#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
+#define NCR5380_local_declare() void __iomem *_base
+#define NCR5380_setup(host) _base = priv(host)->base
+
+#define NCR5380_read(reg) readb(_base + ((reg) << 2))
+#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
#define NCR5380_intr oakscsi_intr
#define NCR5380_queue_command oakscsi_queue_command
#define NCR5380_proc_info oakscsi_proc_info
-#define NCR5380_implementation_fields int port, ctrl
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
+#define NCR5380_implementation_fields \
+ void __iomem *base
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
@@ -39,60 +42,62 @@
#include "../NCR5380.h"
#undef START_DMA_INITIATOR_RECEIVE_REG
-#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
+#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
const char * oakscsi_info (struct Scsi_Host *spnt)
{
return "";
}
-#define STAT(p) inw(p + 144)
-extern void inswb(int from, void *to, int len);
+#define STAT ((128 + 16) << 2)
+#define DATA ((128 + 8) << 2)
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
int len)
{
- int iobase = instance->io_port;
+ void __iomem *base = priv(instance)->base;
+
printk("writing %p len %d\n",addr, len);
if(!len) return -1;
while(1)
{
int status;
- while(((status = STAT(iobase)) & 0x100)==0);
+ while (((status = readw(base + STAT)) & 0x100)==0);
}
}
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
int len)
{
- int iobase = instance->io_port;
+ void __iomem *base = priv(instance)->base;
printk("reading %p len %d\n", addr, len);
while(len > 0)
{
- int status, timeout;
+ unsigned int status, timeout;
unsigned long b;
timeout = 0x01FFFFFF;
- while(((status = STAT(iobase)) & 0x100)==0)
+ while (((status = readw(base + STAT)) & 0x100)==0)
{
timeout--;
if(status & 0x200 || !timeout)
{
- printk("status = %08X\n",status);
+ printk("status = %08X\n", status);
return 1;
}
}
+
if(len >= 128)
{
- inswb(iobase + 136, addr, 128);
+ readsw(base + DATA, addr, 128);
addr += 128;
len -= 128;
}
else
{
- b = (unsigned long) inw(iobase + 136);
+ b = (unsigned long) readw(base + DATA);
*addr ++ = b;
len -= 1;
if(len)
@@ -103,10 +108,8 @@ printk("reading %p len %d\n", addr, len);
return 0;
}
-#define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg)))
-#define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg)))
-
#undef STAT
+#undef DATA
#include "../NCR5380.c"
@@ -132,18 +135,26 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
struct Scsi_Host *host;
int ret = -ENOMEM;
- host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
- if (!host)
+ ret = ecard_request_resources(ec);
+ if (ret)
goto out;
- host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+ host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
+ if (!host) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!priv(host)->base) {
+ ret = -ENOMEM;
+ goto unreg;
+ }
+
host->irq = IRQ_NONE;
host->n_io_port = 255;
- ret = -EBUSY;
- if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
- goto unreg;
-
NCR5380_init(host, 0);
printk("scsi%d: at port 0x%08lx irqs disabled",
@@ -156,15 +167,17 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
ret = scsi_add_host(host, &ec->dev);
if (ret)
- goto out_release;
+ goto out_unmap;
scsi_scan_host(host);
goto out;
- out_release:
- release_region(host->io_port, host->n_io_port);
+ out_unmap:
+ iounmap(priv(host)->base);
unreg:
scsi_host_put(host);
+ release:
+ ecard_release_resources(ec);
out:
return ret;
}
@@ -177,8 +190,9 @@ static void __devexit oakscsi_remove(struct expansion_card *ec)
scsi_remove_host(host);
NCR5380_exit(host);
- release_region(host->io_port, host->n_io_port);
+ iounmap(priv(host)->base);
scsi_host_put(host);
+ ecard_release_resources(ec);
}
static const struct ecard_id oakscsi_cids[] = {
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
index 012cdea7946d..cac354086737 100644
--- a/drivers/scsi/bvme6000_scsi.c
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -74,6 +74,7 @@ bvme6000_probe(struct device *dev)
goto out_put_host;
}
+ dev_set_drvdata(dev, host);
scsi_scan_host(host);
return 0;
@@ -89,7 +90,7 @@ bvme6000_probe(struct device *dev)
static __devexit int
bvme6000_device_remove(struct device *dev)
{
- struct Scsi_Host *host = dev_to_shost(dev);
+ struct Scsi_Host *host = dev_get_drvdata(dev);
struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
scsi_remove_host(host);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 2e2362d787ca..502732ac270d 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -173,20 +173,20 @@ static struct pci_device_id dptids[] = {
};
MODULE_DEVICE_TABLE(pci,dptids);
-static int adpt_detect(struct scsi_host_template* sht)
+static void adpt_exit(void);
+
+static int adpt_detect(void)
{
struct pci_dev *pDev = NULL;
adpt_hba* pHba;
- adpt_init();
-
PINFO("Detecting Adaptec I2O RAID controllers...\n");
/* search for all Adatpec I2O RAID cards */
while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
if(pDev->device == PCI_DPT_DEVICE_ID ||
pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
- if(adpt_install_hba(sht, pDev) ){
+ if(adpt_install_hba(pDev) ){
PERROR("Could not Init an I2O RAID device\n");
PERROR("Will not try to detect others.\n");
return hba_count-1;
@@ -248,34 +248,33 @@ rebuild_sys_tab:
}
for (pHba = hba_chain; pHba; pHba = pHba->next) {
- if( adpt_scsi_register(pHba,sht) < 0){
+ if (adpt_scsi_register(pHba) < 0) {
adpt_i2o_delete_hba(pHba);
continue;
}
pHba->initialized = TRUE;
pHba->state &= ~DPTI_STATE_RESET;
+ scsi_scan_host(pHba->host);
}
// Register our control device node
// nodes will need to be created in /dev to access this
// the nodes can not be created from within the driver
if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) {
- adpt_i2o_sys_shutdown();
+ adpt_exit();
return 0;
}
return hba_count;
}
-/*
- * scsi_unregister will be called AFTER we return.
- */
-static int adpt_release(struct Scsi_Host *host)
+static int adpt_release(adpt_hba *pHba)
{
- adpt_hba* pHba = (adpt_hba*) host->hostdata[0];
+ struct Scsi_Host *shost = pHba->host;
+ scsi_remove_host(shost);
// adpt_i2o_quiesce_hba(pHba);
adpt_i2o_delete_hba(pHba);
- scsi_unregister(host);
+ scsi_host_put(shost);
return 0;
}
@@ -882,7 +881,7 @@ static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p)
#endif
-static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
+static int adpt_install_hba(struct pci_dev* pDev)
{
adpt_hba* pHba = NULL;
@@ -1031,8 +1030,6 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
mutex_lock(&adpt_configuration_lock);
- // scsi_unregister calls our adpt_release which
- // does a quiese
if(pHba->host){
free_irq(pHba->host->irq, pHba);
}
@@ -1084,17 +1081,6 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
}
-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;
@@ -2180,37 +2166,6 @@ 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)
-{
- struct Scsi_Host *host = NULL;
-
- host = scsi_register(sht, sizeof(adpt_hba*));
- if (host == NULL) {
- printk ("%s: scsi_register returned NULL\n",pHba->name);
- return -1;
- }
- host->hostdata[0] = (unsigned long)pHba;
- pHba->host = host;
-
- host->irq = pHba->pDev->irq;
- /* no IO ports, so don't have to set host->io_port and
- * host->n_io_port
- */
- host->io_port = 0;
- host->n_io_port = 0;
- /* see comments in scsi_host.h */
- host->max_id = 16;
- host->max_lun = 256;
- host->max_channel = pHba->top_scsi_channel + 1;
- host->cmd_per_lun = 1;
- host->unique_id = (uint) pHba;
- host->sg_tablesize = pHba->sg_tablesize;
- host->can_queue = pHba->post_fifo_size;
-
- return 0;
-}
-
-
static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
{
adpt_hba* pHba;
@@ -3329,12 +3284,10 @@ static static void adpt_delay(int millisec)
#endif
-static struct scsi_host_template driver_template = {
+static struct scsi_host_template adpt_template = {
.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,
@@ -3348,5 +3301,62 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
};
-#include "scsi_module.c"
+
+static s32 adpt_scsi_register(adpt_hba* pHba)
+{
+ struct Scsi_Host *host;
+
+ host = scsi_host_alloc(&adpt_template, sizeof(adpt_hba*));
+ if (host == NULL) {
+ printk ("%s: scsi_host_alloc returned NULL\n",pHba->name);
+ return -1;
+ }
+ host->hostdata[0] = (unsigned long)pHba;
+ pHba->host = host;
+
+ host->irq = pHba->pDev->irq;
+ /* no IO ports, so don't have to set host->io_port and
+ * host->n_io_port
+ */
+ host->io_port = 0;
+ host->n_io_port = 0;
+ /* see comments in scsi_host.h */
+ host->max_id = 16;
+ host->max_lun = 256;
+ host->max_channel = pHba->top_scsi_channel + 1;
+ host->cmd_per_lun = 1;
+ host->unique_id = (uint) pHba;
+ host->sg_tablesize = pHba->sg_tablesize;
+ host->can_queue = pHba->post_fifo_size;
+
+ if (scsi_add_host(host, &pHba->pDev->dev)) {
+ scsi_host_put(host);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __init adpt_init(void)
+{
+ int count;
+
+ printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+#ifdef REBOOT_NOTIFIER
+ register_reboot_notifier(&adpt_reboot_notifier);
+#endif
+
+ count = adpt_detect();
+
+ return count > 0 ? 0 : -ENODEV;
+}
+
+static void __exit adpt_exit(void)
+{
+ while (hba_chain)
+ adpt_release(hba_chain);
+}
+
+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..0892f6c70319 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -28,11 +28,9 @@
* SCSI interface function Prototypes
*/
-static int adpt_detect(struct scsi_host_template * sht);
static int adpt_queue(struct scsi_cmnd * cmd, void (*cmdcomplete) (struct scsi_cmnd *));
static int adpt_abort(struct scsi_cmnd * cmd);
static int adpt_reset(struct scsi_cmnd* cmd);
-static int adpt_release(struct Scsi_Host *host);
static int adpt_slave_configure(struct scsi_device *);
static const char *adpt_info(struct Scsi_Host *pSHost);
@@ -49,8 +47,6 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
#define DPT_DRIVER_NAME "Adaptec I2O RAID"
-#ifndef HOSTS_C
-
#include "dpt/sys_info.h"
#include <linux/wait.h>
#include "dpt/dpti_i2o.h"
@@ -289,7 +285,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_register(adpt_hba* pHba);
static s32 adpt_hba_reset(adpt_hba* pHba);
static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
static s32 adpt_rescan(adpt_hba* pHba);
@@ -299,7 +295,7 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba);
static void adpt_inquiry(adpt_hba* pHba);
static void adpt_fail_posted_scbs(adpt_hba* pHba);
static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun);
-static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) ;
+static int adpt_install_hba(struct pci_dev* pDev) ;
static int adpt_i2o_online_hba(adpt_hba* pHba);
static void adpt_i2o_post_wait_complete(u32, int);
static int adpt_i2o_systab_send(adpt_hba* pHba);
@@ -343,5 +339,4 @@ static void adpt_i386_info(sysInfo_S* si);
#define FW_DEBUG_BLED_OFFSET 8
#define FW_DEBUG_FLAGS_NO_HEADERS_B 0x01
-#endif /* !HOSTS_C */
#endif /* _DPT_H */
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 77b06a983fa7..95cf7b6cd622 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2314,6 +2314,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
esp->host->transportt = esp_transport_template;
esp->host->max_lun = ESP_MAX_LUN;
esp->host->cmd_per_lun = 2;
+ esp->host->unique_id = instance;
esp_set_clock_params(esp);
@@ -2337,7 +2338,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
if (err)
return err;
- esp->host->unique_id = instance++;
+ instance++;
scsi_scan_host(esp->host);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d0b95ce0ba00..55e4d2dc2bbe 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -902,11 +902,6 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
return;
/* GDT PCI controller found, resources are already in pdev */
pcistr[*cnt].pdev = pdev;
- pcistr[*cnt].vendor_id = vendor;
- pcistr[*cnt].device_id = device;
- pcistr[*cnt].subdevice_id = pdev->subsystem_device;
- pcistr[*cnt].bus = pdev->bus->number;
- pcistr[*cnt].device_fn = pdev->devfn;
pcistr[*cnt].irq = pdev->irq;
base0 = pci_resource_flags(pdev, 0);
base1 = pci_resource_flags(pdev, 1);
@@ -926,7 +921,8 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
pcistr[*cnt].io = pci_resource_start(pdev, 1);
}
TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
- pcistr[*cnt].bus, PCI_SLOT(pcistr[*cnt].device_fn),
+ pcistr[*cnt].pdev->bus->number,
+ PCI_SLOT(pcistr[*cnt].pdev->devfn),
pcistr[*cnt].irq, pcistr[*cnt].dpmem));
(*cnt)++;
}
@@ -946,20 +942,20 @@ static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
changed = FALSE;
for (i = 0; i < cnt-1; ++i) {
if (!reverse_scan) {
- if ((pcistr[i].bus > pcistr[i+1].bus) ||
- (pcistr[i].bus == pcistr[i+1].bus &&
- PCI_SLOT(pcistr[i].device_fn) >
- PCI_SLOT(pcistr[i+1].device_fn))) {
+ if ((pcistr[i].pdev->bus->number > pcistr[i+1].pdev->bus->number) ||
+ (pcistr[i].pdev->bus->number == pcistr[i+1].pdev->bus->number &&
+ PCI_SLOT(pcistr[i].pdev->devfn) >
+ PCI_SLOT(pcistr[i+1].pdev->devfn))) {
temp = pcistr[i];
pcistr[i] = pcistr[i+1];
pcistr[i+1] = temp;
changed = TRUE;
}
} else {
- if ((pcistr[i].bus < pcistr[i+1].bus) ||
- (pcistr[i].bus == pcistr[i+1].bus &&
- PCI_SLOT(pcistr[i].device_fn) <
- PCI_SLOT(pcistr[i+1].device_fn))) {
+ if ((pcistr[i].pdev->bus->number < pcistr[i+1].pdev->bus->number) ||
+ (pcistr[i].pdev->bus->number == pcistr[i+1].pdev->bus->number &&
+ PCI_SLOT(pcistr[i].pdev->devfn) <
+ PCI_SLOT(pcistr[i+1].pdev->devfn))) {
temp = pcistr[i];
pcistr[i] = pcistr[i+1];
pcistr[i+1] = temp;
@@ -1176,17 +1172,16 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
TRACE(("gdth_init_pci()\n"));
- if (pcistr->vendor_id == PCI_VENDOR_ID_INTEL)
+ if (pcistr->pdev->vendor == PCI_VENDOR_ID_INTEL)
ha->oem_id = OEM_ID_INTEL;
else
ha->oem_id = OEM_ID_ICP;
- ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
- ha->stype = (ulong32)pcistr->device_id;
- ha->subdevice_id = pcistr->subdevice_id;
+ ha->brd_phys = (pcistr->pdev->bus->number << 8) | (pcistr->pdev->devfn & 0xf8);
+ ha->stype = (ulong32)pcistr->pdev->device;
ha->irq = pcistr->irq;
ha->pdev = pcistr->pdev;
- if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000/B */
+ if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000/B */
TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str));
if (ha->brd == NULL) {
@@ -1293,7 +1288,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->dma64_support = 0;
- } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
+ } else if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
ha->plx = (gdt6c_plx_regs *)pcistr->io;
TRACE2(("init_pci_new() dpmem %lx irq %d\n",
pcistr->dpmem,ha->irq));
@@ -4601,7 +4596,8 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
}
/* controller found and initialized */
printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
- pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
+ pcistr[ctr].pdev->bus->number,
+ PCI_SLOT(pcistr[ctr].pdev->devfn), ha->irq);
if (request_irq(ha->irq, gdth_interrupt,
IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
@@ -4637,7 +4633,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
#endif
ha->scratch_busy = FALSE;
ha->req_first = NULL;
- ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
+ ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
if (max_ids > 0 && max_ids < ha->tid_cnt)
ha->tid_cnt = max_ids;
for (i=0; i<GDTH_MAXCMDS; ++i)
@@ -4810,7 +4806,7 @@ static const char *gdth_ctr_name(int hanum)
} else if (ha->type == GDT_ISA) {
return("GDT2000/2020");
} else if (ha->type == GDT_PCI) {
- switch (ha->stype) {
+ switch (ha->pdev->device) {
case PCI_DEVICE_ID_VORTEX_GDT60x0:
return("GDT6000/6020/6050");
case PCI_DEVICE_ID_VORTEX_GDT6000B:
@@ -5448,12 +5444,12 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
ctrt.type =
(ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
if (ha->stype >= 0x300)
- ctrt.ext_type = 0x6000 | ha->subdevice_id;
+ ctrt.ext_type = 0x6000 | ha->pdev->subsystem_device;
else
ctrt.ext_type = 0x6000 | ha->stype;
}
- ctrt.device_id = ha->stype;
- ctrt.sub_device_id = ha->subdevice_id;
+ ctrt.device_id = ha->pdev->device;
+ ctrt.sub_device_id = ha->pdev->subsystem_device;
}
ctrt.info = ha->brd_phys;
ctrt.oem_id = ha->oem_id;
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 8c29eafd51c5..37423300592e 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -845,11 +845,6 @@ typedef struct {
/* PCI resources */
typedef struct {
struct pci_dev *pdev;
- ushort vendor_id; /* vendor (ICP, Intel, ..) */
- ushort device_id; /* device ID (0,..,9) */
- ushort subdevice_id; /* sub device ID */
- unchar bus; /* PCI bus */
- unchar device_fn; /* PCI device/function no. */
ulong dpmem; /* DPRAM address */
ulong io; /* IO address */
ulong io_mm; /* IO address mem. mapped */
@@ -862,7 +857,6 @@ typedef struct {
ushort oem_id; /* OEM */
ushort type; /* controller class */
ulong32 stype; /* subtype (PCI: device ID) */
- ushort subdevice_id; /* sub device ID (PCI) */
ushort fw_vers; /* firmware version */
ushort cache_feat; /* feat. cache serv. (s/g,..)*/
ushort raw_feat; /* feat. raw service (s/g,..)*/
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index bd8e7f323c69..96bc31266c98 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -220,7 +220,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
get_device(&shost->shost_gendev);
if (shost->transportt->host_size &&
- (shost->shost_data = kmalloc(shost->transportt->host_size,
+ (shost->shost_data = kzalloc(shost->transportt->host_size,
GFP_KERNEL)) == NULL)
goto out_del_classdev;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5870866abc99..5ecc63d1b436 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -393,12 +393,6 @@ static int map_sg_data(struct scsi_cmnd *cmd,
return 1;
else if (sg_mapped < 0)
return 0;
- else if (sg_mapped > SG_ALL) {
- printk(KERN_ERR
- "ibmvscsi: More than %d mapped sg entries, got %d\n",
- SG_ALL, sg_mapped);
- return 0;
- }
set_srp_direction(cmd, srp_cmd, sg_mapped);
@@ -708,8 +702,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
struct srp_cmd *srp_cmd;
struct srp_event_struct *evt_struct;
struct srp_indirect_buf *indirect;
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
u16 lun = lun_from_dev(cmnd->device);
u8 out_fmt, in_fmt;
@@ -960,8 +953,7 @@ static void sync_completion(struct srp_event_struct *evt_struct)
*/
static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
{
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
struct srp_tsk_mgmt *tsk_mgmt;
struct srp_event_struct *evt;
struct srp_event_struct *tmp_evt, *found_evt;
@@ -1084,9 +1076,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
*/
static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
{
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
-
+ struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
struct srp_tsk_mgmt *tsk_mgmt;
struct srp_event_struct *evt;
struct srp_event_struct *tmp_evt, *pos;
@@ -1183,8 +1173,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
{
unsigned long wait_switch = 0;
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
@@ -1412,8 +1401,7 @@ static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)shost->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
len = snprintf(buf, PAGE_SIZE, "%s\n",
@@ -1433,8 +1421,7 @@ static ssize_t show_host_partition_name(struct class_device *class_dev,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)shost->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
len = snprintf(buf, PAGE_SIZE, "%s\n",
@@ -1454,8 +1441,7 @@ static ssize_t show_host_partition_number(struct class_device *class_dev,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)shost->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1474,8 +1460,7 @@ static struct class_device_attribute ibmvscsi_host_partition_number = {
static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)shost->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1494,8 +1479,7 @@ static struct class_device_attribute ibmvscsi_host_mad_version = {
static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)shost->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
@@ -1513,8 +1497,7 @@ static struct class_device_attribute ibmvscsi_host_os_type = {
static ssize_t show_host_config(struct class_device *class_dev, char *buf)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
- struct ibmvscsi_host_data *hostdata =
- (struct ibmvscsi_host_data *)shost->hostdata;
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
/* returns null-terminated host config data */
if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
@@ -1582,7 +1565,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto scsi_host_alloc_failed;
}
- hostdata = (struct ibmvscsi_host_data *)host->hostdata;
+ hostdata = shost_priv(host);
memset(hostdata, 0x00, sizeof(*hostdata));
INIT_LIST_HEAD(&hostdata->sent);
hostdata->host = host;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index bb90df8bdce4..1cc01acc2808 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -328,17 +328,15 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co
u8 *buf;
/* stuff a sense request in front of our current request */
- pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
- rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
- buf = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);
- if (pc == NULL || rq == NULL || buf == NULL) {
+ pc = kzalloc(sizeof(idescsi_pc_t), GFP_ATOMIC);
+ rq = kmalloc(sizeof(struct request), GFP_ATOMIC);
+ buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);
+ if (!pc || !rq || !buf) {
kfree(buf);
kfree(rq);
kfree(pc);
return -ENOMEM;
}
- memset (pc, 0, sizeof (idescsi_pc_t));
- memset (buf, 0, SCSI_SENSE_BUFFERSIZE);
ide_init_drive_cmd(rq);
rq->special = (char *) pc;
pc->rq = rq;
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 0464c182c577..005d2b05f32d 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1159,11 +1159,10 @@ static int __imm_attach(struct parport *pb)
init_waitqueue_head(&waiting);
- dev = kmalloc(sizeof(imm_struct), GFP_KERNEL);
+ dev = kzalloc(sizeof(imm_struct), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(imm_struct));
dev->base = -1;
dev->mode = IMM_AUTODETECT;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f142eafb6fc7..b41dfb539021 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3829,18 +3829,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
/**
* ipr_sata_reset - Reset the SATA port
- * @ap: SATA port to reset
+ * @link: SATA link to reset
* @classes: class of the attached device
*
- * This function issues a SATA phy reset to the affected ATA port.
+ * This function issues a SATA phy reset to the affected ATA link.
*
* Return value:
* 0 on success / non-zero on failure
**/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
- struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_sata_port *sata_port = link->ap->private_data;
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
struct ipr_resource_entry *res;
unsigned long lock_flags = 0;
@@ -4981,22 +4981,22 @@ static void ipr_ata_phy_reset(struct ata_port *ap)
rc = ipr_device_reset(ioa_cfg, res);
if (rc) {
- ap->ops->port_disable(ap);
+ ata_port_disable(ap);
goto out_unlock;
}
switch(res->cfgte.proto) {
case IPR_PROTO_SATA:
case IPR_PROTO_SAS_STP:
- ap->device[0].class = ATA_DEV_ATA;
+ ap->link.device[0].class = ATA_DEV_ATA;
break;
case IPR_PROTO_SATA_ATAPI:
case IPR_PROTO_SAS_STP_ATAPI:
- ap->device[0].class = ATA_DEV_ATAPI;
+ ap->link.device[0].class = ATA_DEV_ATAPI;
break;
default:
- ap->device[0].class = ATA_DEV_UNKNOWN;
- ap->ops->port_disable(ap);
+ ap->link.device[0].class = ATA_DEV_UNKNOWN;
+ ata_port_disable(ap);
break;
};
@@ -5262,7 +5262,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap)
}
static struct ata_port_operations ipr_sata_ops = {
- .port_disable = ata_port_disable,
.check_status = ipr_ata_check_status,
.check_altstatus = ipr_ata_check_altstatus,
.dev_select = ata_noop_dev_select,
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 9f8ed6b81576..492a51bd6aa8 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -7068,14 +7068,13 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
subdevice_id = pci_dev->subsystem_device;
/* found a controller */
- ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
+ ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
if (ha == NULL) {
IPS_PRINTK(KERN_WARNING, pci_dev,
"Unable to allocate temporary ha struct\n");
return -1;
}
- memset(ha, 0, sizeof (ips_ha_t));
ips_sh[index] = NULL;
ips_ha[index] = ha;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index aebcd5fcdc55..a21455d0274c 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1885,7 +1885,7 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
struct sockaddr_in *sin;
int rc = 0, len;
- addr = kmalloc(GFP_KERNEL, sizeof(*addr));
+ addr = kmalloc(sizeof(*addr), GFP_KERNEL);
if (!addr)
return -ENOMEM;
@@ -2216,11 +2216,13 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
{
+ blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY);
blk_queue_dma_alignment(sdev->request_queue, 0);
return 0;
}
static struct scsi_host_template iscsi_sht = {
+ .module = THIS_MODULE,
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index 5c32a69e41ba..3126824da36d 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -101,13 +101,12 @@ lasi700_probe(struct parisc_device *dev)
struct NCR_700_Host_Parameters *hostdata;
struct Scsi_Host *host;
- hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+ hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "%s: Failed to allocate host data\n",
dev->dev.bus_id);
return -ENOMEM;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
hostdata->dev = &dev->dev;
dma_set_mask(&dev->dev, DMA_32BIT_MASK);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 4d85ce100192..efceed451b46 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -596,9 +596,16 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (hdr->itt != RESERVED_ITT) {
hdr->itt = build_itt(mtask->itt, conn->id, session->age);
+ /*
+ * TODO: We always use immediate, so we never hit this.
+ * If we start to send tmfs or nops as non-immediate then
+ * we should start checking the cmdsn numbers for mgmt tasks.
+ */
if (conn->c_stage == ISCSI_CONN_STARTED &&
- !(hdr->opcode & ISCSI_OP_IMMEDIATE))
+ !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+ session->queued_cmdsn++;
session->cmdsn++;
+ }
}
if (session->tt->init_mgmt_task)
@@ -641,9 +648,11 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
/*
* Check for iSCSI window and take care of CmdSN wrap-around
*/
- if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) {
- debug_scsi("iSCSI CmdSN closed. MaxCmdSN %u CmdSN %u\n",
- session->max_cmdsn, session->cmdsn);
+ if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
+ debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u "
+ "CmdSN %u/%u\n", session->exp_cmdsn,
+ session->max_cmdsn, session->cmdsn,
+ session->queued_cmdsn);
return -ENOSPC;
}
return 0;
@@ -722,23 +731,25 @@ check_mgmt:
/* process command queue */
while (!list_empty(&conn->xmitqueue)) {
- rc = iscsi_check_cmdsn_window_closed(conn);
- if (rc) {
- spin_unlock_bh(&conn->session->lock);
- return rc;
- }
/*
* iscsi tcp may readd the task to the xmitqueue to send
* write data
*/
conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running);
- if (conn->ctask->state == ISCSI_TASK_PENDING) {
+ switch (conn->ctask->state) {
+ case ISCSI_TASK_ABORTING:
+ break;
+ case ISCSI_TASK_PENDING:
iscsi_prep_scsi_cmd_pdu(conn->ctask);
conn->session->tt->init_cmd_task(conn->ctask);
+ /* fall through */
+ default:
+ conn->ctask->state = ISCSI_TASK_RUNNING;
+ break;
}
- conn->ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(conn->xmitqueue.next, &conn->run_list);
+
rc = iscsi_xmit_ctask(conn);
if (rc)
goto again;
@@ -834,12 +845,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto fault;
}
- /*
- * We check this here and in data xmit, because if we get to the point
- * that this check is hitting the window then we have enough IO in
- * flight and enough IO waiting to be transmitted it is better
- * to let the scsi/block layer queue up.
- */
if (iscsi_check_cmdsn_window_closed(conn)) {
reason = FAILURE_WINDOW_CLOSED;
goto reject;
@@ -850,6 +855,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
reason = FAILURE_OOM;
goto reject;
}
+ session->queued_cmdsn++;
+
sc->SCp.phase = session->age;
sc->SCp.ptr = (char *)ctask;
@@ -1049,7 +1056,9 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
NULL, 0);
if (!ctask->mtask) {
+ spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ spin_lock_bh(&session->lock)
debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
return -EPERM;
}
@@ -1066,6 +1075,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
}
spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
scsi_queue_work(session->host, &conn->xmitwork);
/*
@@ -1083,6 +1093,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
if (signal_pending(current))
flush_signals(current);
del_timer_sync(&conn->tmabort_timer);
+ mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
return 0;
}
@@ -1140,7 +1151,13 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
if (!sc)
return;
- if (ctask->state != ISCSI_TASK_PENDING)
+ if (ctask->state == ISCSI_TASK_PENDING)
+ /*
+ * cmd never made it to the xmit thread, so we should not count
+ * the cmd in the sequencing
+ */
+ conn->session->queued_cmdsn--;
+ else
conn->session->tt->cleanup_cmd_task(conn, ctask);
iscsi_ctask_mtask_cleanup(ctask);
@@ -1152,31 +1169,45 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
__iscsi_put_ctask(ctask);
}
+static void iscsi_suspend_tx(struct iscsi_conn *conn)
+{
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ scsi_flush_work(conn->session->host);
+}
+
+static void iscsi_start_tx(struct iscsi_conn *conn)
+{
+ clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+
int iscsi_eh_abort(struct scsi_cmnd *sc)
{
+ struct Scsi_Host *host = sc->device->host;
+ struct iscsi_session *session = iscsi_hostdata(host->hostdata);
struct iscsi_cmd_task *ctask;
struct iscsi_conn *conn;
- struct iscsi_session *session;
int rc;
+ mutex_lock(&session->eh_mutex);
+ spin_lock_bh(&session->lock);
/*
* if session was ISCSI_STATE_IN_RECOVERY then we may not have
* got the command.
*/
if (!sc->SCp.ptr) {
debug_scsi("sc never reached iscsi layer or it completed.\n");
+ spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
return SUCCESS;
}
ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
conn = ctask->conn;
- session = conn->session;
conn->eh_abort_cnt++;
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
- spin_lock_bh(&session->lock);
-
/*
* If we are not logged in or we have started a new session
* then let the host reset code handle this
@@ -1213,6 +1244,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
switch (conn->tmabort_state) {
case TMABORT_SUCCESS:
spin_unlock_bh(&session->lock);
+ iscsi_suspend_tx(conn);
/*
* clean up task if aborted. grab the recv lock as a writer
*/
@@ -1221,11 +1253,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
fail_command(conn, ctask, DID_ABORT << 16);
spin_unlock(&session->lock);
write_unlock_bh(conn->recv_lock);
- /*
- * make sure xmit thread is not still touching the
- * ctask/scsi_cmnd
- */
- scsi_flush_work(session->host);
+ iscsi_start_tx(conn);
goto success_unlocked;
case TMABORT_NOT_FOUND:
if (!ctask->sc) {
@@ -1245,12 +1273,14 @@ success:
spin_unlock_bh(&session->lock);
success_unlocked:
debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+ mutex_unlock(&session->eh_mutex);
return SUCCESS;
failed:
spin_unlock_bh(&session->lock);
failed_unlocked:
debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+ mutex_unlock(&session->eh_mutex);
return FAILED;
}
EXPORT_SYMBOL_GPL(iscsi_eh_abort);
@@ -1392,11 +1422,12 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
session->state = ISCSI_STATE_FREE;
session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
session->cmds_max = cmds_max;
- session->cmdsn = initial_cmdsn;
+ session->queued_cmdsn = session->cmdsn = initial_cmdsn;
session->exp_cmdsn = initial_cmdsn + 1;
session->max_cmdsn = initial_cmdsn + 1;
session->max_r2t = 1;
session->tt = iscsit;
+ mutex_init(&session->eh_mutex);
/* initialize SCSI PDU commands pool */
if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
@@ -1473,6 +1504,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
struct module *owner = cls_session->transport->owner;
+ iscsi_unblock_session(cls_session);
scsi_remove_host(shost);
iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
@@ -1615,11 +1647,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
kfree(conn->persistent_address);
__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
sizeof(void*));
- if (session->leadconn == conn) {
+ if (session->leadconn == conn)
session->leadconn = NULL;
- /* no connections exits.. reset sequencing */
- session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
- }
spin_unlock_bh(&session->lock);
kfifo_free(conn->mgmtqueue);
@@ -1649,6 +1678,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
spin_lock_bh(&session->lock);
conn->c_stage = ISCSI_CONN_STARTED;
session->state = ISCSI_STATE_LOGGED_IN;
+ session->queued_cmdsn = session->cmdsn;
switch(conn->stop_stage) {
case STOP_CONN_RECOVER:
@@ -1731,9 +1761,22 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
{
int old_stop_stage;
+ mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
if (conn->stop_stage == STOP_CONN_TERM) {
spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
+ return;
+ }
+
+ /*
+ * The LLD either freed/unset the lock on us, or userspace called
+ * stop but did not create a proper connection (connection was never
+ * bound or it was unbound then stop was called).
+ */
+ if (!conn->recv_lock) {
+ spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
return;
}
@@ -1750,9 +1793,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
old_stop_stage = conn->stop_stage;
conn->stop_stage = flag;
conn->c_stage = ISCSI_CONN_STOPPED;
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
spin_unlock_bh(&session->lock);
- scsi_flush_work(session->host);
+
+ iscsi_suspend_tx(conn);
write_lock_bh(conn->recv_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1781,6 +1824,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
fail_all_commands(conn);
flush_control_queues(session, conn);
spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
}
void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index aafdc92f8312..c01a40d321d4 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -30,6 +30,14 @@ config SCSI_SAS_LIBSAS
This provides transport specific helpers for SAS drivers which
use the domain device construct (like the aic94xxx).
+config SCSI_SAS_ATA
+ bool "ATA support for libsas (requires libata)"
+ depends on SCSI_SAS_LIBSAS
+ depends on ATA = y || ATA = SCSI_SAS_LIBSAS
+ help
+ Builds in ATA support into libsas. Will necessitate
+ the loading of libata along with libsas.
+
config SCSI_SAS_LIBSAS_DEBUG
bool "Compile the SAS Domain Transport Attributes in debug mode"
default y
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index 44d972a3b4bd..fd387b91856e 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -34,3 +34,4 @@ libsas-y += sas_init.o \
sas_discover.o \
sas_expander.o \
sas_scsi_host.o
+libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
new file mode 100644
index 000000000000..0829b55c64d2
--- /dev/null
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -0,0 +1,816 @@
+/*
+ * Support for SATA devices on Serial Attached SCSI (SAS) controllers
+ *
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Written by: Darrick J. Wong <djwong@us.ibm.com>, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <linux/scatterlist.h>
+
+#include <scsi/sas_ata.h>
+#include "sas_internal.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+#include "../scsi_transport_api.h"
+#include <scsi/scsi_eh.h>
+
+static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
+{
+ /* Cheesy attempt to translate SAS errors into ATA. Hah! */
+
+ /* transport error */
+ if (ts->resp == SAS_TASK_UNDELIVERED)
+ return AC_ERR_ATA_BUS;
+
+ /* ts->resp == SAS_TASK_COMPLETE */
+ /* task delivered, what happened afterwards? */
+ switch (ts->stat) {
+ case SAS_DEV_NO_RESPONSE:
+ return AC_ERR_TIMEOUT;
+
+ case SAS_INTERRUPTED:
+ case SAS_PHY_DOWN:
+ case SAS_NAK_R_ERR:
+ return AC_ERR_ATA_BUS;
+
+
+ case SAS_DATA_UNDERRUN:
+ /*
+ * Some programs that use the taskfile interface
+ * (smartctl in particular) can cause underrun
+ * problems. Ignore these errors, perhaps at our
+ * peril.
+ */
+ return 0;
+
+ case SAS_DATA_OVERRUN:
+ case SAS_QUEUE_FULL:
+ case SAS_DEVICE_UNKNOWN:
+ case SAS_SG_ERR:
+ return AC_ERR_INVALID;
+
+ case SAM_CHECK_COND:
+ case SAS_OPEN_TO:
+ case SAS_OPEN_REJECT:
+ SAS_DPRINTK("%s: Saw error %d. What to do?\n",
+ __FUNCTION__, ts->stat);
+ return AC_ERR_OTHER;
+
+ case SAS_ABORTED_TASK:
+ return AC_ERR_DEV;
+
+ case SAS_PROTO_RESPONSE:
+ /* This means the ending_fis has the error
+ * value; return 0 here to collect it */
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void sas_ata_task_done(struct sas_task *task)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+ struct domain_device *dev;
+ struct task_status_struct *stat = &task->task_status;
+ struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf;
+ struct sas_ha_struct *sas_ha;
+ enum ata_completion_errors ac;
+ unsigned long flags;
+
+ if (!qc)
+ goto qc_already_gone;
+
+ dev = qc->ap->private_data;
+ sas_ha = dev->port->ha;
+
+ spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+ if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_GOOD) {
+ ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
+ qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+ dev->sata_dev.sstatus = resp->sstatus;
+ dev->sata_dev.serror = resp->serror;
+ dev->sata_dev.scontrol = resp->scontrol;
+ } else if (stat->stat != SAM_STAT_GOOD) {
+ ac = sas_to_ata_err(stat);
+ if (ac) {
+ SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__,
+ stat->stat);
+ /* We saw a SAS error. Send a vague error. */
+ qc->err_mask = ac;
+ dev->sata_dev.tf.feature = 0x04; /* status err */
+ dev->sata_dev.tf.command = ATA_ERR;
+ }
+ }
+
+ qc->lldd_task = NULL;
+ if (qc->scsicmd)
+ ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+ ata_qc_complete(qc);
+ spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+
+ /*
+ * If the sas_task has an ata qc, a scsi_cmnd and the aborted
+ * flag is set, then we must have come in via the libsas EH
+ * functions. When we exit this function, we need to put the
+ * scsi_cmnd on the list of finished errors. The ata_qc_complete
+ * call cleans up the libata side of things but we're protected
+ * from the scsi_cmnd going away because the scsi_cmnd is owned
+ * by the EH, making libata's call to scsi_done a NOP.
+ */
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (qc->scsicmd && task->task_state_flags & SAS_TASK_STATE_ABORTED)
+ scsi_eh_finish_cmd(qc->scsicmd, &sas_ha->eh_done_q);
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+qc_already_gone:
+ list_del_init(&task->list);
+ sas_free_task(task);
+}
+
+static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
+{
+ int res;
+ struct sas_task *task;
+ struct domain_device *dev = qc->ap->private_data;
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct Scsi_Host *host = sas_ha->core.shost;
+ struct sas_internal *i = to_sas_internal(host->transportt);
+ struct scatterlist *sg;
+ unsigned int num = 0;
+ unsigned int xfer = 0;
+
+ task = sas_alloc_task(GFP_ATOMIC);
+ if (!task)
+ return AC_ERR_SYSTEM;
+ task->dev = dev;
+ task->task_proto = SAS_PROTOCOL_STP;
+ task->task_done = sas_ata_task_done;
+
+ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ) {
+ /* Need to zero out the tag libata assigned us */
+ qc->tf.nsect = 0;
+ }
+
+ ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
+ task->uldd_task = qc;
+ if (is_atapi_taskfile(&qc->tf)) {
+ memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
+ task->total_xfer_len = qc->nbytes + qc->pad_len;
+ task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+ } else {
+ ata_for_each_sg(sg, qc) {
+ num++;
+ xfer += sg->length;
+ }
+
+ task->total_xfer_len = xfer;
+ task->num_scatter = num;
+ }
+
+ task->data_dir = qc->dma_dir;
+ task->scatter = qc->__sg;
+ task->ata_task.retry_count = 1;
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ qc->lldd_task = task;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NCQ:
+ task->ata_task.use_ncq = 1;
+ /* fall through */
+ case ATA_PROT_ATAPI_DMA:
+ case ATA_PROT_DMA:
+ task->ata_task.dma_xfer = 1;
+ break;
+ }
+
+ if (qc->scsicmd)
+ ASSIGN_SAS_TASK(qc->scsicmd, task);
+
+ if (sas_ha->lldd_max_execute_num < 2)
+ res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+ else
+ res = sas_queue_up(task);
+
+ /* Examine */
+ if (res) {
+ SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+
+ if (qc->scsicmd)
+ ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+ sas_free_task(task);
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+
+static u8 sas_ata_check_status(struct ata_port *ap)
+{
+ struct domain_device *dev = ap->private_data;
+ return dev->sata_dev.tf.command;
+}
+
+static void sas_ata_phy_reset(struct ata_port *ap)
+{
+ struct domain_device *dev = ap->private_data;
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+ int res = 0;
+
+ if (i->dft->lldd_I_T_nexus_reset)
+ res = i->dft->lldd_I_T_nexus_reset(dev);
+
+ if (res)
+ SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
+
+ switch (dev->sata_dev.command_set) {
+ case ATA_COMMAND_SET:
+ SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
+ ap->link.device[0].class = ATA_DEV_ATA;
+ break;
+ case ATAPI_COMMAND_SET:
+ SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
+ ap->link.device[0].class = ATA_DEV_ATAPI;
+ break;
+ default:
+ SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
+ __FUNCTION__,
+ dev->sata_dev.command_set);
+ ap->link.device[0].class = ATA_DEV_UNKNOWN;
+ break;
+ }
+
+ ap->cbl = ATA_CBL_SATA;
+}
+
+static void sas_ata_post_internal(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask) {
+ /*
+ * Find the sas_task and kill it. By this point,
+ * libata has decided to kill the qc, so we needn't
+ * bother with sas_ata_task_done. But we still
+ * ought to abort the task.
+ */
+ struct sas_task *task = qc->lldd_task;
+ unsigned long flags;
+
+ qc->lldd_task = NULL;
+ if (task) {
+ /* Should this be a AT(API) device reset? */
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ task->uldd_task = NULL;
+ __sas_task_abort(task);
+ }
+ }
+}
+
+static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct domain_device *dev = ap->private_data;
+ memcpy(tf, &dev->sata_dev.tf, sizeof (*tf));
+}
+
+static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
+ u32 val)
+{
+ struct domain_device *dev = ap->private_data;
+
+ SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ dev->sata_dev.sstatus = val;
+ break;
+ case SCR_CONTROL:
+ dev->sata_dev.scontrol = val;
+ break;
+ case SCR_ERROR:
+ dev->sata_dev.serror = val;
+ break;
+ case SCR_ACTIVE:
+ dev->sata_dev.ap->link.sactive = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
+ u32 *val)
+{
+ struct domain_device *dev = ap->private_data;
+
+ SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ *val = dev->sata_dev.sstatus;
+ return 0;
+ case SCR_CONTROL:
+ *val = dev->sata_dev.scontrol;
+ return 0;
+ case SCR_ERROR:
+ *val = dev->sata_dev.serror;
+ return 0;
+ case SCR_ACTIVE:
+ *val = dev->sata_dev.ap->link.sactive;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct ata_port_operations sas_sata_ops = {
+ .check_status = sas_ata_check_status,
+ .check_altstatus = sas_ata_check_status,
+ .dev_select = ata_noop_dev_select,
+ .phy_reset = sas_ata_phy_reset,
+ .post_internal_cmd = sas_ata_post_internal,
+ .tf_read = sas_ata_tf_read,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = sas_ata_qc_issue,
+ .port_start = ata_sas_port_start,
+ .port_stop = ata_sas_port_stop,
+ .scr_read = sas_ata_scr_read,
+ .scr_write = sas_ata_scr_write
+};
+
+static struct ata_port_info sata_port_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+ .pio_mask = 0x1f, /* PIO0-4 */
+ .mwdma_mask = 0x07, /* MWDMA0-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sas_sata_ops
+};
+
+int sas_ata_init_host_and_port(struct domain_device *found_dev,
+ struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ struct ata_port *ap;
+
+ ata_host_init(&found_dev->sata_dev.ata_host,
+ ha->dev,
+ sata_port_info.flags,
+ &sas_sata_ops);
+ ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host,
+ &sata_port_info,
+ shost);
+ if (!ap) {
+ SAS_DPRINTK("ata_sas_port_alloc failed.\n");
+ return -ENODEV;
+ }
+
+ ap->private_data = found_dev;
+ ap->cbl = ATA_CBL_SATA;
+ ap->scsi_host = shost;
+ found_dev->sata_dev.ap = ap;
+
+ return 0;
+}
+
+void sas_ata_task_abort(struct sas_task *task)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+ struct completion *waiting;
+
+ /* Bounce SCSI-initiated commands to the SCSI EH */
+ if (qc->scsicmd) {
+ scsi_req_abort_cmd(qc->scsicmd);
+ scsi_schedule_eh(qc->scsicmd->device->host);
+ return;
+ }
+
+ /* Internal command, fake a timeout and complete. */
+ qc->flags &= ~ATA_QCFLAG_ACTIVE;
+ qc->flags |= ATA_QCFLAG_FAILED;
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ waiting = qc->private_data;
+ complete(waiting);
+}
+
+static void sas_task_timedout(unsigned long _task)
+{
+ struct sas_task *task = (void *) _task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ complete(&task->completion);
+}
+
+static void sas_disc_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+#define SAS_DEV_TIMEOUT 10
+
+/**
+ * sas_execute_task -- Basic task processing for discovery
+ * @task: the task to be executed
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @dma_dir: DMA direction. DMA_xxx
+ */
+static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+ enum dma_data_direction dma_dir)
+{
+ int res = 0;
+ struct scatterlist *scatter = NULL;
+ struct task_status_struct *ts = &task->task_status;
+ int num_scatter = 0;
+ int retries = 0;
+ struct sas_internal *i =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+ if (dma_dir != DMA_NONE) {
+ scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
+ if (!scatter)
+ goto out;
+
+ sg_init_one(scatter, buffer, size);
+ num_scatter = 1;
+ }
+
+ task->task_proto = task->dev->tproto;
+ task->scatter = scatter;
+ task->num_scatter = num_scatter;
+ task->total_xfer_len = size;
+ task->data_dir = dma_dir;
+ task->task_done = sas_disc_task_done;
+ if (dma_dir != DMA_NONE &&
+ sas_protocol_ata(task->task_proto)) {
+ task->num_scatter = dma_map_sg(task->dev->port->ha->dev,
+ task->scatter,
+ task->num_scatter,
+ task->data_dir);
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ init_completion(&task->completion);
+
+ task->timer.data = (unsigned long) task;
+ task->timer.function = sas_task_timedout;
+ task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+ if (res) {
+ del_timer(&task->timer);
+ SAS_DPRINTK("executing SAS discovery task failed:%d\n",
+ res);
+ goto ex_err;
+ }
+ wait_for_completion(&task->completion);
+ res = -ETASK;
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ int res2;
+ SAS_DPRINTK("task aborted, flags:0x%x\n",
+ task->task_state_flags);
+ res2 = i->dft->lldd_abort_task(task);
+ SAS_DPRINTK("came back from abort task\n");
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ if (res2 == TMF_RESP_FUNC_COMPLETE)
+ continue; /* Retry the task */
+ else
+ goto ex_err;
+ }
+ }
+ if (task->task_status.stat == SAM_BUSY ||
+ task->task_status.stat == SAM_TASK_SET_FULL ||
+ task->task_status.stat == SAS_QUEUE_FULL) {
+ SAS_DPRINTK("task: q busy, sleeping...\n");
+ schedule_timeout_interruptible(HZ);
+ } else if (task->task_status.stat == SAM_CHECK_COND) {
+ struct scsi_sense_hdr shdr;
+
+ if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
+ &shdr)) {
+ SAS_DPRINTK("couldn't normalize sense\n");
+ continue;
+ }
+ if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
+ (shdr.sense_key == 2 && shdr.asc == 4 &&
+ shdr.ascq == 1)) {
+ SAS_DPRINTK("device %016llx LUN: %016llx "
+ "powering up or not ready yet, "
+ "sleeping...\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN));
+
+ schedule_timeout_interruptible(5*HZ);
+ } else if (shdr.sense_key == 1) {
+ res = 0;
+ break;
+ } else if (shdr.sense_key == 5) {
+ break;
+ } else {
+ SAS_DPRINTK("dev %016llx LUN: %016llx "
+ "sense key:0x%x ASC:0x%x ASCQ:0x%x"
+ "\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN),
+ shdr.sense_key,
+ shdr.asc, shdr.ascq);
+ }
+ } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
+ task->task_status.stat != SAM_GOOD) {
+ SAS_DPRINTK("task finished with resp:0x%x, "
+ "stat:0x%x\n",
+ task->task_status.resp,
+ task->task_status.stat);
+ goto ex_err;
+ } else {
+ res = 0;
+ break;
+ }
+ }
+ex_err:
+ if (dma_dir != DMA_NONE) {
+ if (sas_protocol_ata(task->task_proto))
+ dma_unmap_sg(task->dev->port->ha->dev,
+ task->scatter, task->num_scatter,
+ task->data_dir);
+ kfree(scatter);
+ }
+out:
+ return res;
+}
+
+/* ---------- SATA ---------- */
+
+static void sas_get_ata_command_set(struct domain_device *dev)
+{
+ struct dev_to_host_fis *fis =
+ (struct dev_to_host_fis *) dev->frame_rcvd;
+
+ if ((fis->sector_count == 1 && /* ATA */
+ fis->lbal == 1 &&
+ fis->lbam == 0 &&
+ fis->lbah == 0 &&
+ fis->device == 0)
+ ||
+ (fis->sector_count == 0 && /* CE-ATA (mATA) */
+ fis->lbal == 0 &&
+ fis->lbam == 0xCE &&
+ fis->lbah == 0xAA &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATA_COMMAND_SET;
+
+ else if ((fis->interrupt_reason == 1 && /* ATAPI */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x14 &&
+ fis->byte_count_high == 0xEB &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+
+ else if ((fis->sector_count == 1 && /* SEMB */
+ fis->lbal == 1 &&
+ fis->lbam == 0x3C &&
+ fis->lbah == 0xC3 &&
+ fis->device == 0)
+ ||
+ (fis->interrupt_reason == 1 && /* SATA PM */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x69 &&
+ fis->byte_count_high == 0x96 &&
+ (fis->device & ~0x10) == 0))
+
+ /* Treat it as a superset? */
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+}
+
+/**
+ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
+ * @dev: the device to send the command to
+ * @command: the command register
+ * @features: the features register
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @dma_dir: DMA direction. DMA_xxx
+ */
+static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
+ u8 features, void *buffer, int size,
+ enum dma_data_direction dma_dir)
+{
+ int res = 0;
+ struct sas_task *task;
+ struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
+ &dev->frame_rcvd[0];
+
+ res = -ENOMEM;
+ task = sas_alloc_task(GFP_KERNEL);
+ if (!task)
+ goto out;
+
+ task->dev = dev;
+
+ task->ata_task.fis.fis_type = 0x27;
+ task->ata_task.fis.command = command;
+ task->ata_task.fis.features = features;
+ task->ata_task.fis.device = d2h_fis->device;
+ task->ata_task.retry_count = 1;
+
+ res = sas_execute_task(task, buffer, size, dma_dir);
+
+ sas_free_task(task);
+out:
+ return res;
+}
+
+static void sas_sata_propagate_sas_addr(struct domain_device *dev)
+{
+ unsigned long flags;
+ struct asd_sas_port *port = dev->port;
+ struct asd_sas_phy *phy;
+
+ BUG_ON(dev->parent);
+
+ memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_lock_irqsave(&port->phy_list_lock, flags);
+ list_for_each_entry(phy, &port->phy_list, port_phy_el)
+ memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+}
+
+#define ATA_IDENTIFY_DEV 0xEC
+#define ATA_IDENTIFY_PACKET_DEV 0xA1
+#define ATA_SET_FEATURES 0xEF
+#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
+
+/**
+ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
+ * @dev: STP/SATA device of interest (ATA/ATAPI)
+ *
+ * The LLDD has already been notified of this device, so that we can
+ * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
+ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
+ * performance for this device.
+ */
+static int sas_discover_sata_dev(struct domain_device *dev)
+{
+ int res;
+ __le16 *identify_x;
+ u8 command;
+
+ identify_x = kzalloc(512, GFP_KERNEL);
+ if (!identify_x)
+ return -ENOMEM;
+
+ if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
+ dev->sata_dev.identify_device = identify_x;
+ command = ATA_IDENTIFY_DEV;
+ } else {
+ dev->sata_dev.identify_packet_device = identify_x;
+ command = ATA_IDENTIFY_PACKET_DEV;
+ }
+
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ DMA_FROM_DEVICE);
+ if (res)
+ goto out_err;
+
+ /* lives on the media? */
+ if (le16_to_cpu(identify_x[0]) & 4) {
+ /* incomplete response */
+ SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
+ "dev %llx\n", SAS_ADDR(dev->sas_addr));
+ if (!le16_to_cpu(identify_x[83] & (1<<6)))
+ goto cont1;
+ res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
+ ATA_FEATURE_PUP_STBY_SPIN_UP,
+ NULL, 0, DMA_NONE);
+ if (res)
+ goto cont1;
+
+ schedule_timeout_interruptible(5*HZ); /* More time? */
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ DMA_FROM_DEVICE);
+ if (res)
+ goto out_err;
+ }
+cont1:
+ /* Get WWN */
+ if (dev->port->oob_mode != SATA_OOB_MODE) {
+ memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
+ SAS_ADDR_SIZE);
+ } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
+ (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
+ == 0x5000) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ dev->sas_addr[2*i] =
+ (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
+ dev->sas_addr[2*i+1] =
+ le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
+ }
+ }
+ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+ if (!dev->parent)
+ sas_sata_propagate_sas_addr(dev);
+
+ /* XXX Hint: register this SATA device with SATL.
+ When this returns, dev->sata_dev->lu is alive and
+ present.
+ sas_satl_register_dev(dev);
+ */
+
+ sas_fill_in_rphy(dev, dev->rphy);
+
+ return 0;
+out_err:
+ dev->sata_dev.identify_packet_device = NULL;
+ dev->sata_dev.identify_device = NULL;
+ kfree(identify_x);
+ return res;
+}
+
+static int sas_discover_sata_pm(struct domain_device *dev)
+{
+ return -ENODEV;
+}
+
+/**
+ * sas_discover_sata -- discover an STP/SATA domain device
+ * @dev: pointer to struct domain_device of interest
+ *
+ * First we notify the LLDD of this device, so we can send frames to
+ * it. Then depending on the type of device we call the appropriate
+ * discover functions. Once device discover is done, we notify the
+ * LLDD so that it can fine-tune its parameters for the device, by
+ * removing it and then adding it. That is, the second time around,
+ * the driver would have certain fields, that it is looking at, set.
+ * Finally we initialize the kobj so that the device can be added to
+ * the system at registration time. Devices directly attached to a HA
+ * port, have no parents. All other devices do, and should have their
+ * "parent" pointer set appropriately before calling this function.
+ */
+int sas_discover_sata(struct domain_device *dev)
+{
+ int res;
+
+ sas_get_ata_command_set(dev);
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ switch (dev->dev_type) {
+ case SATA_DEV:
+ res = sas_discover_sata_dev(dev);
+ break;
+ case SATA_PM:
+ res = sas_discover_sata_pm(dev);
+ break;
+ default:
+ break;
+ }
+ sas_notify_lldd_dev_gone(dev);
+ if (!res) {
+ sas_notify_lldd_dev_found(dev);
+ res = sas_rphy_add(dev->rphy);
+ }
+
+ return res;
+}
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index a65598b1e536..7ef0afc3cd68 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/pci.h>
#include <linux/scatterlist.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
@@ -55,149 +54,6 @@ void sas_init_dev(struct domain_device *dev)
}
}
-static void sas_task_timedout(unsigned long _task)
-{
- struct sas_task *task = (void *) _task;
- unsigned long flags;
-
- spin_lock_irqsave(&task->task_state_lock, flags);
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
- task->task_state_flags |= SAS_TASK_STATE_ABORTED;
- spin_unlock_irqrestore(&task->task_state_lock, flags);
-
- complete(&task->completion);
-}
-
-static void sas_disc_task_done(struct sas_task *task)
-{
- if (!del_timer(&task->timer))
- return;
- complete(&task->completion);
-}
-
-#define SAS_DEV_TIMEOUT 10
-
-/**
- * sas_execute_task -- Basic task processing for discovery
- * @task: the task to be executed
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @pci_dma_dir: PCI_DMA_...
- */
-static int sas_execute_task(struct sas_task *task, void *buffer, int size,
- int pci_dma_dir)
-{
- int res = 0;
- struct scatterlist *scatter = NULL;
- struct task_status_struct *ts = &task->task_status;
- int num_scatter = 0;
- int retries = 0;
- struct sas_internal *i =
- to_sas_internal(task->dev->port->ha->core.shost->transportt);
-
- if (pci_dma_dir != PCI_DMA_NONE) {
- scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
- if (!scatter)
- goto out;
-
- sg_init_one(scatter, buffer, size);
- num_scatter = 1;
- }
-
- task->task_proto = task->dev->tproto;
- task->scatter = scatter;
- task->num_scatter = num_scatter;
- task->total_xfer_len = size;
- task->data_dir = pci_dma_dir;
- task->task_done = sas_disc_task_done;
-
- for (retries = 0; retries < 5; retries++) {
- task->task_state_flags = SAS_TASK_STATE_PENDING;
- init_completion(&task->completion);
-
- task->timer.data = (unsigned long) task;
- task->timer.function = sas_task_timedout;
- task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
- add_timer(&task->timer);
-
- res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
- if (res) {
- del_timer(&task->timer);
- SAS_DPRINTK("executing SAS discovery task failed:%d\n",
- res);
- goto ex_err;
- }
- wait_for_completion(&task->completion);
- res = -ETASK;
- if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
- int res2;
- SAS_DPRINTK("task aborted, flags:0x%x\n",
- task->task_state_flags);
- res2 = i->dft->lldd_abort_task(task);
- SAS_DPRINTK("came back from abort task\n");
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
- if (res2 == TMF_RESP_FUNC_COMPLETE)
- continue; /* Retry the task */
- else
- goto ex_err;
- }
- }
- if (task->task_status.stat == SAM_BUSY ||
- task->task_status.stat == SAM_TASK_SET_FULL ||
- task->task_status.stat == SAS_QUEUE_FULL) {
- SAS_DPRINTK("task: q busy, sleeping...\n");
- schedule_timeout_interruptible(HZ);
- } else if (task->task_status.stat == SAM_CHECK_COND) {
- struct scsi_sense_hdr shdr;
-
- if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
- &shdr)) {
- SAS_DPRINTK("couldn't normalize sense\n");
- continue;
- }
- if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
- (shdr.sense_key == 2 && shdr.asc == 4 &&
- shdr.ascq == 1)) {
- SAS_DPRINTK("device %016llx LUN: %016llx "
- "powering up or not ready yet, "
- "sleeping...\n",
- SAS_ADDR(task->dev->sas_addr),
- SAS_ADDR(task->ssp_task.LUN));
-
- schedule_timeout_interruptible(5*HZ);
- } else if (shdr.sense_key == 1) {
- res = 0;
- break;
- } else if (shdr.sense_key == 5) {
- break;
- } else {
- SAS_DPRINTK("dev %016llx LUN: %016llx "
- "sense key:0x%x ASC:0x%x ASCQ:0x%x"
- "\n",
- SAS_ADDR(task->dev->sas_addr),
- SAS_ADDR(task->ssp_task.LUN),
- shdr.sense_key,
- shdr.asc, shdr.ascq);
- }
- } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
- task->task_status.stat != SAM_GOOD) {
- SAS_DPRINTK("task finished with resp:0x%x, "
- "stat:0x%x\n",
- task->task_status.resp,
- task->task_status.stat);
- goto ex_err;
- } else {
- res = 0;
- break;
- }
- }
-ex_err:
- if (pci_dma_dir != PCI_DMA_NONE)
- kfree(scatter);
-out:
- return res;
-}
-
/* ---------- Domain device discovery ---------- */
/**
@@ -255,6 +111,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
switch (dev->dev_type) {
case SAS_END_DEV:
+ case SATA_DEV:
rphy = sas_end_device_alloc(port->port);
break;
case EDGE_DEV:
@@ -265,7 +122,6 @@ static int sas_get_port_device(struct asd_sas_port *port)
rphy = sas_expander_alloc(port->port,
SAS_FANOUT_EXPANDER_DEVICE);
break;
- case SATA_DEV:
default:
printk("ERROR: Unidentified device type %d\n", dev->dev_type);
rphy = NULL;
@@ -292,207 +148,15 @@ static int sas_get_port_device(struct asd_sas_port *port)
port->disc.max_level = 0;
dev->rphy = rphy;
- spin_lock(&port->dev_list_lock);
+ spin_lock_irq(&port->dev_list_lock);
list_add_tail(&dev->dev_list_node, &port->dev_list);
- spin_unlock(&port->dev_list_lock);
+ spin_unlock_irq(&port->dev_list_lock);
return 0;
}
/* ---------- Discover and Revalidate ---------- */
-/* ---------- SATA ---------- */
-
-static void sas_get_ata_command_set(struct domain_device *dev)
-{
- struct dev_to_host_fis *fis =
- (struct dev_to_host_fis *) dev->frame_rcvd;
-
- if ((fis->sector_count == 1 && /* ATA */
- fis->lbal == 1 &&
- fis->lbam == 0 &&
- fis->lbah == 0 &&
- fis->device == 0)
- ||
- (fis->sector_count == 0 && /* CE-ATA (mATA) */
- fis->lbal == 0 &&
- fis->lbam == 0xCE &&
- fis->lbah == 0xAA &&
- (fis->device & ~0x10) == 0))
-
- dev->sata_dev.command_set = ATA_COMMAND_SET;
-
- else if ((fis->interrupt_reason == 1 && /* ATAPI */
- fis->lbal == 1 &&
- fis->byte_count_low == 0x14 &&
- fis->byte_count_high == 0xEB &&
- (fis->device & ~0x10) == 0))
-
- dev->sata_dev.command_set = ATAPI_COMMAND_SET;
-
- else if ((fis->sector_count == 1 && /* SEMB */
- fis->lbal == 1 &&
- fis->lbam == 0x3C &&
- fis->lbah == 0xC3 &&
- fis->device == 0)
- ||
- (fis->interrupt_reason == 1 && /* SATA PM */
- fis->lbal == 1 &&
- fis->byte_count_low == 0x69 &&
- fis->byte_count_high == 0x96 &&
- (fis->device & ~0x10) == 0))
-
- /* Treat it as a superset? */
- dev->sata_dev.command_set = ATAPI_COMMAND_SET;
-}
-
-/**
- * sas_issue_ata_cmd -- Basic SATA command processing for discovery
- * @dev: the device to send the command to
- * @command: the command register
- * @features: the features register
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @pci_dma_dir: PCI_DMA_...
- */
-static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
- u8 features, void *buffer, int size,
- int pci_dma_dir)
-{
- int res = 0;
- struct sas_task *task;
- struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
- &dev->frame_rcvd[0];
-
- res = -ENOMEM;
- task = sas_alloc_task(GFP_KERNEL);
- if (!task)
- goto out;
-
- task->dev = dev;
-
- task->ata_task.fis.command = command;
- task->ata_task.fis.features = features;
- task->ata_task.fis.device = d2h_fis->device;
- task->ata_task.retry_count = 1;
-
- res = sas_execute_task(task, buffer, size, pci_dma_dir);
-
- sas_free_task(task);
-out:
- return res;
-}
-
-static void sas_sata_propagate_sas_addr(struct domain_device *dev)
-{
- unsigned long flags;
- struct asd_sas_port *port = dev->port;
- struct asd_sas_phy *phy;
-
- BUG_ON(dev->parent);
-
- memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
- spin_lock_irqsave(&port->phy_list_lock, flags);
- list_for_each_entry(phy, &port->phy_list, port_phy_el)
- memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
- spin_unlock_irqrestore(&port->phy_list_lock, flags);
-}
-
-#define ATA_IDENTIFY_DEV 0xEC
-#define ATA_IDENTIFY_PACKET_DEV 0xA1
-#define ATA_SET_FEATURES 0xEF
-#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
-
-/**
- * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
- * @dev: STP/SATA device of interest (ATA/ATAPI)
- *
- * The LLDD has already been notified of this device, so that we can
- * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
- * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
- * performance for this device.
- */
-static int sas_discover_sata_dev(struct domain_device *dev)
-{
- int res;
- __le16 *identify_x;
- u8 command;
-
- identify_x = kzalloc(512, GFP_KERNEL);
- if (!identify_x)
- return -ENOMEM;
-
- if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
- dev->sata_dev.identify_device = identify_x;
- command = ATA_IDENTIFY_DEV;
- } else {
- dev->sata_dev.identify_packet_device = identify_x;
- command = ATA_IDENTIFY_PACKET_DEV;
- }
-
- res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
- PCI_DMA_FROMDEVICE);
- if (res)
- goto out_err;
-
- /* lives on the media? */
- if (le16_to_cpu(identify_x[0]) & 4) {
- /* incomplete response */
- SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
- "dev %llx\n", SAS_ADDR(dev->sas_addr));
- if (!le16_to_cpu(identify_x[83] & (1<<6)))
- goto cont1;
- res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
- ATA_FEATURE_PUP_STBY_SPIN_UP,
- NULL, 0, PCI_DMA_NONE);
- if (res)
- goto cont1;
-
- schedule_timeout_interruptible(5*HZ); /* More time? */
- res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
- PCI_DMA_FROMDEVICE);
- if (res)
- goto out_err;
- }
-cont1:
- /* Get WWN */
- if (dev->port->oob_mode != SATA_OOB_MODE) {
- memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
- SAS_ADDR_SIZE);
- } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
- (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
- == 0x5000) {
- int i;
-
- for (i = 0; i < 4; i++) {
- dev->sas_addr[2*i] =
- (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
- dev->sas_addr[2*i+1] =
- le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
- }
- }
- sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
- if (!dev->parent)
- sas_sata_propagate_sas_addr(dev);
-
- /* XXX Hint: register this SATA device with SATL.
- When this returns, dev->sata_dev->lu is alive and
- present.
- sas_satl_register_dev(dev);
- */
- return 0;
-out_err:
- dev->sata_dev.identify_packet_device = NULL;
- dev->sata_dev.identify_device = NULL;
- kfree(identify_x);
- return res;
-}
-
-static int sas_discover_sata_pm(struct domain_device *dev)
-{
- return -ENODEV;
-}
-
int sas_notify_lldd_dev_found(struct domain_device *dev)
{
int res = 0;
@@ -505,7 +169,7 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
if (res) {
printk("sas: driver on pcidev %s cannot handle "
"device %llx, error:%d\n",
- pci_name(sas_ha->pcidev),
+ sas_ha->dev->bus_id,
SAS_ADDR(dev->sas_addr), res);
}
}
@@ -525,60 +189,6 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
/* ---------- Common/dispatchers ---------- */
-/**
- * sas_discover_sata -- discover an STP/SATA domain device
- * @dev: pointer to struct domain_device of interest
- *
- * First we notify the LLDD of this device, so we can send frames to
- * it. Then depending on the type of device we call the appropriate
- * discover functions. Once device discover is done, we notify the
- * LLDD so that it can fine-tune its parameters for the device, by
- * removing it and then adding it. That is, the second time around,
- * the driver would have certain fields, that it is looking at, set.
- * Finally we initialize the kobj so that the device can be added to
- * the system at registration time. Devices directly attached to a HA
- * port, have no parents. All other devices do, and should have their
- * "parent" pointer set appropriately before calling this function.
- */
-int sas_discover_sata(struct domain_device *dev)
-{
- int res;
-
- sas_get_ata_command_set(dev);
-
- res = sas_notify_lldd_dev_found(dev);
- if (res)
- goto out_err2;
-
- switch (dev->dev_type) {
- case SATA_DEV:
- res = sas_discover_sata_dev(dev);
- break;
- case SATA_PM:
- res = sas_discover_sata_pm(dev);
- break;
- default:
- break;
- }
- if (res)
- goto out_err;
-
- sas_notify_lldd_dev_gone(dev);
- res = sas_notify_lldd_dev_found(dev);
- if (res)
- goto out_err2;
-
- res = sas_rphy_add(dev->rphy);
- if (res)
- goto out_err;
-
- return res;
-
-out_err:
- sas_notify_lldd_dev_gone(dev);
-out_err2:
- return res;
-}
/**
* sas_discover_end_dev -- discover an end device (SSP, etc)
@@ -685,11 +295,14 @@ static void sas_discover_domain(struct work_struct *work)
case FANOUT_DEV:
error = sas_discover_root_expander(dev);
break;
+#ifdef CONFIG_SCSI_SAS_ATA
case SATA_DEV:
case SATA_PM:
error = sas_discover_sata(dev);
break;
+#endif
default:
+ error = -ENXIO;
SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
break;
}
@@ -698,9 +311,9 @@ static void sas_discover_domain(struct work_struct *work)
sas_rphy_free(dev->rphy);
dev->rphy = NULL;
- spin_lock(&port->dev_list_lock);
+ spin_lock_irq(&port->dev_list_lock);
list_del_init(&dev->dev_list_node);
- spin_unlock(&port->dev_list_lock);
+ spin_unlock_irq(&port->dev_list_lock);
kfree(dev); /* not kobject_register-ed yet */
port->port_dev = NULL;
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index f1246d2c9bef..bf34a236f946 100644
--- a/drivers/scsi/libsas/sas_dump.c
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -56,7 +56,7 @@ void sas_dprint_phye(int phyid, enum phy_event pe)
void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
{
- SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev),
+ SAS_DPRINTK("ha %s: %s event\n", sas_ha->dev->bus_id,
sas_hae_str[he]);
}
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 23e90c5f8f35..8727436b222d 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -23,6 +23,7 @@
*/
#include <linux/scatterlist.h>
+#include <linux/blkdev.h>
#include "sas_internal.h"
@@ -36,14 +37,6 @@ static int sas_configure_phy(struct domain_device *dev, int phy_id,
u8 *sas_addr, int include);
static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);
-#if 0
-/* FIXME: smp needs to migrate into the sas class */
-static ssize_t smp_portal_read(struct kobject *, struct bin_attribute *,
- char *, loff_t, size_t);
-static ssize_t smp_portal_write(struct kobject *, struct bin_attribute *,
- char *, loff_t, size_t);
-#endif
-
/* ---------- SMP task management ---------- */
static void smp_task_timedout(unsigned long _task)
@@ -220,6 +213,36 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
#define DISCOVER_REQ_SIZE 16
#define DISCOVER_RESP_SIZE 56
+static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
+ u8 *disc_resp, int single)
+{
+ int i, res;
+
+ disc_req[9] = single;
+ for (i = 1 ; i < 3; i++) {
+ struct discover_resp *dr;
+
+ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+ disc_resp, DISCOVER_RESP_SIZE);
+ if (res)
+ return res;
+ /* This is detecting a failure to transmit inital
+ * dev to host FIS as described in section G.5 of
+ * sas-2 r 04b */
+ dr = &((struct smp_resp *)disc_resp)->disc;
+ if (!(dr->attached_dev_type == 0 &&
+ dr->attached_sata_dev))
+ break;
+ /* In order to generate the dev to host FIS, we
+ * send a link reset to the expander port */
+ sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
+ /* Wait for the reset to trigger the negotiation */
+ msleep(500);
+ }
+ sas_set_ex_phy(dev, single, disc_resp);
+ return 0;
+}
+
static int sas_ex_phy_discover(struct domain_device *dev, int single)
{
struct expander_device *ex = &dev->ex_dev;
@@ -240,23 +263,15 @@ static int sas_ex_phy_discover(struct domain_device *dev, int single)
disc_req[1] = SMP_DISCOVER;
if (0 <= single && single < ex->num_phys) {
- disc_req[9] = single;
- res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
- disc_resp, DISCOVER_RESP_SIZE);
- if (res)
- goto out_err;
- sas_set_ex_phy(dev, single, disc_resp);
+ res = sas_ex_phy_discover_helper(dev, disc_req, disc_resp, single);
} else {
int i;
for (i = 0; i < ex->num_phys; i++) {
- disc_req[9] = i;
- res = smp_execute_task(dev, disc_req,
- DISCOVER_REQ_SIZE, disc_resp,
- DISCOVER_RESP_SIZE);
+ res = sas_ex_phy_discover_helper(dev, disc_req,
+ disc_resp, i);
if (res)
goto out_err;
- sas_set_ex_phy(dev, i, disc_resp);
}
}
out_err:
@@ -492,13 +507,20 @@ static int sas_dev_present_in_domain(struct asd_sas_port *port,
int sas_smp_get_phy_events(struct sas_phy *phy)
{
int res;
+ u8 *req;
+ u8 *resp;
struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
struct domain_device *dev = sas_find_dev_by_rphy(rphy);
- u8 *req = alloc_smp_req(RPEL_REQ_SIZE);
- u8 *resp = kzalloc(RPEL_RESP_SIZE, GFP_KERNEL);
- if (!resp)
+ req = alloc_smp_req(RPEL_REQ_SIZE);
+ if (!req)
+ return -ENOMEM;
+
+ resp = alloc_smp_resp(RPEL_RESP_SIZE);
+ if (!resp) {
+ kfree(req);
return -ENOMEM;
+ }
req[1] = SMP_REPORT_PHY_ERR_LOG;
req[9] = phy->number;
@@ -520,6 +542,8 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
}
+#ifdef CONFIG_SCSI_SAS_ATA
+
#define RPS_REQ_SIZE 16
#define RPS_RESP_SIZE 60
@@ -529,6 +553,7 @@ static int sas_get_report_phy_sata(struct domain_device *dev,
{
int res;
u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
+ u8 *resp = (u8 *)rps_resp;
if (!rps_req)
return -ENOMEM;
@@ -539,9 +564,30 @@ static int sas_get_report_phy_sata(struct domain_device *dev,
res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
rps_resp, RPS_RESP_SIZE);
+ /* 0x34 is the FIS type for the D2H fis. There's a potential
+ * standards cockup here. sas-2 explicitly specifies the FIS
+ * should be encoded so that FIS type is in resp[24].
+ * However, some expanders endian reverse this. Undo the
+ * reversal here */
+ if (!res && resp[27] == 0x34 && resp[24] != 0x34) {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ int j = 24 + (i*4);
+ u8 a, b;
+ a = resp[j + 0];
+ b = resp[j + 1];
+ resp[j + 0] = resp[j + 3];
+ resp[j + 1] = resp[j + 2];
+ resp[j + 2] = b;
+ resp[j + 3] = a;
+ }
+ }
+
kfree(rps_req);
- return 0;
+ return res;
}
+#endif
static void sas_ex_get_linkrate(struct domain_device *parent,
struct domain_device *child,
@@ -609,6 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev(
}
sas_ex_get_linkrate(parent, child, phy);
+#ifdef CONFIG_SCSI_SAS_ATA
if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
child->dev_type = SATA_DEV;
if (phy->attached_tproto & SAS_PROTO_STP)
@@ -625,16 +672,30 @@ static struct domain_device *sas_ex_discover_end_dev(
}
memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
sizeof(struct dev_to_host_fis));
+
+ rphy = sas_end_device_alloc(phy->port);
+ if (unlikely(!rphy))
+ goto out_free;
+
sas_init_dev(child);
+
+ child->rphy = rphy;
+
+ spin_lock_irq(&parent->port->dev_list_lock);
+ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+ spin_unlock_irq(&parent->port->dev_list_lock);
+
res = sas_discover_sata(child);
if (res) {
SAS_DPRINTK("sas_discover_sata() for device %16llx at "
"%016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
- goto out_free;
+ goto out_list_del;
}
- } else if (phy->attached_tproto & SAS_PROTO_SSP) {
+ } else
+#endif
+ if (phy->attached_tproto & SAS_PROTO_SSP) {
child->dev_type = SAS_END_DEV;
rphy = sas_end_device_alloc(phy->port);
/* FIXME: error handling */
@@ -646,9 +707,9 @@ static struct domain_device *sas_ex_discover_end_dev(
child->rphy = rphy;
sas_fill_in_rphy(child, rphy);
- spin_lock(&parent->port->dev_list_lock);
+ spin_lock_irq(&parent->port->dev_list_lock);
list_add_tail(&child->dev_list_node, &parent->port->dev_list);
- spin_unlock(&parent->port->dev_list_lock);
+ spin_unlock_irq(&parent->port->dev_list_lock);
res = sas_discover_end_dev(child);
if (res) {
@@ -662,6 +723,7 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
phy_id);
+ goto out_free;
}
list_add_tail(&child->siblings, &parent_ex->children);
@@ -761,9 +823,9 @@ static struct domain_device *sas_ex_discover_expander(
sas_fill_in_rphy(child, rphy);
sas_rphy_add(rphy);
- spin_lock(&parent->port->dev_list_lock);
+ spin_lock_irq(&parent->port->dev_list_lock);
list_add_tail(&child->dev_list_node, &parent->port->dev_list);
- spin_unlock(&parent->port->dev_list_lock);
+ spin_unlock_irq(&parent->port->dev_list_lock);
res = sas_discover_expander(child);
if (res) {
@@ -1359,30 +1421,6 @@ static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr)
return 0;
}
-#if 0
-#define SMP_BIN_ATTR_NAME "smp_portal"
-
-static void sas_ex_smp_hook(struct domain_device *dev)
-{
- struct expander_device *ex_dev = &dev->ex_dev;
- struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
-
- memset(bin_attr, 0, sizeof(*bin_attr));
-
- bin_attr->attr.name = SMP_BIN_ATTR_NAME;
- bin_attr->attr.mode = 0600;
-
- bin_attr->size = 0;
- bin_attr->private = NULL;
- bin_attr->read = smp_portal_read;
- bin_attr->write= smp_portal_write;
- bin_attr->mmap = NULL;
-
- ex_dev->smp_portal_pid = -1;
- init_MUTEX(&ex_dev->smp_sema);
-}
-#endif
-
/**
* sas_discover_expander -- expander discovery
* @ex: pointer to expander domain device
@@ -1844,76 +1882,50 @@ out:
return res;
}
-#if 0
-/* ---------- SMP portal ---------- */
-
-static ssize_t smp_portal_write(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t offs, size_t size)
+int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ struct request *req)
{
- struct domain_device *dev = to_dom_device(kobj);
- struct expander_device *ex = &dev->ex_dev;
-
- if (offs != 0)
- return -EFBIG;
- else if (size == 0)
- return 0;
+ struct domain_device *dev;
+ int ret, type;
+ struct request *rsp = req->next_rq;
- down_interruptible(&ex->smp_sema);
- if (ex->smp_req)
- kfree(ex->smp_req);
- ex->smp_req = kzalloc(size, GFP_USER);
- if (!ex->smp_req) {
- up(&ex->smp_sema);
- return -ENOMEM;
+ if (!rsp) {
+ printk("%s: space for a smp response is missing\n",
+ __FUNCTION__);
+ return -EINVAL;
}
- memcpy(ex->smp_req, buf, size);
- ex->smp_req_size = size;
- ex->smp_portal_pid = current->pid;
- up(&ex->smp_sema);
- return size;
-}
-
-static ssize_t smp_portal_read(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t offs, size_t size)
-{
- struct domain_device *dev = to_dom_device(kobj);
- struct expander_device *ex = &dev->ex_dev;
- u8 *smp_resp;
- int res = -EINVAL;
-
- /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
- * it should be 0.
- */
+ /* no rphy means no smp target support (ie aic94xx host) */
+ if (!rphy) {
+ printk("%s: can we send a smp request to a host?\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ type = rphy->identify.device_type;
- down_interruptible(&ex->smp_sema);
- if (!ex->smp_req || ex->smp_portal_pid != current->pid)
- goto out;
+ if (type != SAS_EDGE_EXPANDER_DEVICE &&
+ type != SAS_FANOUT_EXPANDER_DEVICE) {
+ printk("%s: can we send a smp request to a device?\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
- res = 0;
- if (size == 0)
- goto out;
+ dev = sas_find_dev_by_rphy(rphy);
+ if (!dev) {
+ printk("%s: fail to find a domain_device?\n", __FUNCTION__);
+ return -EINVAL;
+ }
- res = -ENOMEM;
- smp_resp = alloc_smp_resp(size);
- if (!smp_resp)
- goto out;
- res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
- smp_resp, size);
- if (!res) {
- memcpy(buf, smp_resp, size);
- res = size;
+ /* do we need to support multiple segments? */
+ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+ printk("%s: multiple segments req %u %u, rsp %u %u\n",
+ __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+ rsp->bio->bi_vcnt, rsp->data_len);
+ return -EINVAL;
}
- kfree(smp_resp);
-out:
- kfree(ex->smp_req);
- ex->smp_req = NULL;
- ex->smp_req_size = 0;
- ex->smp_portal_pid = -1;
- up(&ex->smp_sema);
- return res;
+ ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
+ bio_data(rsp->bio), rsp->data_len);
+
+ return ret;
}
-#endif
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 965698c8b7bf..9cd5abe9e714 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -259,6 +259,7 @@ static struct sas_function_template sft = {
.phy_reset = sas_phy_reset,
.set_phy_speed = sas_set_phy_speed,
.get_linkerrors = sas_get_linkerrors,
+ .smp_handler = sas_smp_handler,
};
struct scsi_transport_template *
@@ -292,7 +293,7 @@ EXPORT_SYMBOL_GPL(sas_domain_release_transport);
static int __init sas_class_init(void)
{
sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (!sas_task_cache)
return -ENOMEM;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index a78638df2018..2b8213b1832d 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -39,6 +39,9 @@
#define SAS_DPRINTK(fmt, ...)
#endif
+#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
+#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
+
void sas_scsi_recover_host(struct Scsi_Host *shost);
int sas_show_class(enum sas_class class, char *buf);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 9c5342e7a69c..7663841eb4cf 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -34,6 +34,7 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_sas.h>
+#include <scsi/sas_ata.h>
#include "../scsi_sas_internal.h"
#include "../scsi_transport_api.h"
#include "../scsi_priv.h"
@@ -42,12 +43,10 @@
#include <linux/blkdev.h>
#include <linux/freezer.h>
#include <linux/scatterlist.h>
+#include <linux/libata.h>
/* ---------- SCSI Host glue ---------- */
-#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
-#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
-
static void sas_scsi_task_done(struct sas_task *task)
{
struct task_status_struct *ts = &task->task_status;
@@ -172,7 +171,7 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
return task;
}
-static int sas_queue_up(struct sas_task *task)
+int sas_queue_up(struct sas_task *task)
{
struct sas_ha_struct *sas_ha = task->dev->port->ha;
struct scsi_core *core = &sas_ha->core;
@@ -213,6 +212,16 @@ int sas_queuecommand(struct scsi_cmnd *cmd,
struct sas_ha_struct *sas_ha = dev->port->ha;
struct sas_task *task;
+ if (dev_is_sata(dev)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+ res = ata_sas_queuecmd(cmd, scsi_done,
+ dev->sata_dev.ap);
+ spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+ goto out;
+ }
+
res = -ENOMEM;
task = sas_create_task(cmd, dev, GFP_ATOMIC);
if (!task)
@@ -684,6 +693,16 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
return EH_NOT_HANDLED;
}
+int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+ struct domain_device *dev = sdev_to_domain_dev(sdev);
+
+ if (dev_is_sata(dev))
+ return ata_scsi_ioctl(sdev, cmd, arg);
+
+ return -EINVAL;
+}
+
struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
{
struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
@@ -723,10 +742,17 @@ static inline struct domain_device *sas_find_target(struct scsi_target *starget)
int sas_target_alloc(struct scsi_target *starget)
{
struct domain_device *found_dev = sas_find_target(starget);
+ int res;
if (!found_dev)
return -ENODEV;
+ if (dev_is_sata(found_dev)) {
+ res = sas_ata_init_host_and_port(found_dev, starget);
+ if (res)
+ return res;
+ }
+
starget->hostdata = found_dev;
return 0;
}
@@ -741,6 +767,11 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
+ if (dev_is_sata(dev)) {
+ ata_sas_slave_configure(scsi_dev, dev->sata_dev.ap);
+ return 0;
+ }
+
sas_ha = dev->port->ha;
sas_read_port_mode_page(scsi_dev);
@@ -764,6 +795,10 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
void sas_slave_destroy(struct scsi_device *scsi_dev)
{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+ if (dev_is_sata(dev))
+ ata_port_disable(dev->sata_dev.ap);
}
int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
@@ -980,10 +1015,38 @@ void sas_task_abort(struct sas_task *task)
return;
}
+ if (dev_is_sata(task->dev)) {
+ sas_ata_task_abort(task);
+ return;
+ }
+
scsi_req_abort_cmd(sc);
scsi_schedule_eh(sc->device->host);
}
+int sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+ if (dev_is_sata(dev))
+ return ata_sas_port_init(dev->sata_dev.ap);
+
+ return 0;
+}
+
+void sas_target_destroy(struct scsi_target *starget)
+{
+ struct domain_device *found_dev = sas_find_target(starget);
+
+ if (!found_dev)
+ return;
+
+ if (dev_is_sata(found_dev))
+ ata_sas_port_destroy(found_dev->sata_dev.ap);
+
+ return;
+}
+
EXPORT_SYMBOL_GPL(sas_queuecommand);
EXPORT_SYMBOL_GPL(sas_target_alloc);
EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -997,3 +1060,6 @@ EXPORT_SYMBOL_GPL(sas_phy_reset);
EXPORT_SYMBOL_GPL(sas_phy_enable);
EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
+EXPORT_SYMBOL_GPL(sas_slave_alloc);
+EXPORT_SYMBOL_GPL(sas_target_destroy);
+EXPORT_SYMBOL_GPL(sas_ioctl);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index f8f64d6485cd..ba3ecab9baf3 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -45,7 +45,7 @@ struct lpfc_sli2_slim;
#define LPFC_DISC_IOCB_BUFF_COUNT 20
#define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */
-#define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */
+#define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */
/* Define macros for 64 bit support */
#define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr)))
@@ -78,6 +78,7 @@ struct lpfc_dma_pool {
struct hbq_dmabuf {
struct lpfc_dmabuf dbuf;
+ uint32_t size;
uint32_t tag;
};
@@ -329,13 +330,30 @@ struct lpfc_vport {
#define FC_LOADING 0x1 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
char *vname; /* Application assigned name */
+
+ /* Vport Config Parameters */
+ uint32_t cfg_scan_down;
+ uint32_t cfg_lun_queue_depth;
+ uint32_t cfg_nodev_tmo;
+ uint32_t cfg_devloss_tmo;
+ uint32_t cfg_restrict_login;
+ uint32_t cfg_peer_port_login;
+ uint32_t cfg_fcp_class;
+ uint32_t cfg_use_adisc;
+ uint32_t cfg_fdmi_on;
+ uint32_t cfg_discovery_threads;
+ uint32_t cfg_log_verbose;
+ uint32_t cfg_max_luns;
+
+ uint32_t dev_loss_tmo_changed;
+
struct fc_vport *fc_vport;
#ifdef CONFIG_LPFC_DEBUG_FS
struct dentry *debug_disc_trc;
struct dentry *debug_nodelist;
struct dentry *vport_debugfs_root;
- struct lpfc_disc_trc *disc_trc;
+ struct lpfc_debugfs_trc *disc_trc;
atomic_t disc_trc_cnt;
#endif
};
@@ -345,17 +363,25 @@ struct hbq_s {
uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */
uint32_t hbqPutIdx; /* HBQ slot to use */
uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
+ void *hbq_virt; /* Virtual ptr to this hbq */
+ struct list_head hbq_buffer_list; /* buffers assigned to this HBQ */
+ /* Callback for HBQ buffer allocation */
+ struct hbq_dmabuf *(*hbq_alloc_buffer) (struct lpfc_hba *);
+ /* Callback for HBQ buffer free */
+ void (*hbq_free_buffer) (struct lpfc_hba *,
+ struct hbq_dmabuf *);
};
-#define LPFC_MAX_HBQS 16
-/* this matches the possition in the lpfc_hbq_defs array */
+#define LPFC_MAX_HBQS 4
+/* this matches the position in the lpfc_hbq_defs array */
#define LPFC_ELS_HBQ 0
+#define LPFC_EXTRA_HBQ 1
struct lpfc_hba {
struct lpfc_sli sli;
uint32_t sli_rev; /* SLI2 or SLI3 */
uint32_t sli3_options; /* Mask of enabled SLI3 options */
-#define LPFC_SLI3_ENABLED 0x01
+#define LPFC_SLI3_ENABLED 0x01
#define LPFC_SLI3_HBQ_ENABLED 0x02
#define LPFC_SLI3_NPIV_ENABLED 0x04
#define LPFC_SLI3_VPORT_TEARDOWN 0x08
@@ -364,7 +390,7 @@ struct lpfc_hba {
enum hba_state link_state;
uint32_t link_flag; /* link state flags */
-#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */
+#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */
/* This flag is set while issuing */
/* INIT_LINK mailbox command */
#define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */
@@ -413,28 +439,16 @@ struct lpfc_hba {
uint8_t wwpn[8];
uint32_t RandomData[7];
- uint32_t cfg_log_verbose;
- uint32_t cfg_lun_queue_depth;
- uint32_t cfg_nodev_tmo;
- uint32_t cfg_devloss_tmo;
- uint32_t cfg_hba_queue_depth;
- uint32_t cfg_peer_port_login;
- uint32_t cfg_vport_restrict_login;
- uint32_t cfg_npiv_enable;
- uint32_t cfg_fcp_class;
- uint32_t cfg_use_adisc;
+ /* HBA Config Parameters */
uint32_t cfg_ack0;
+ uint32_t cfg_enable_npiv;
uint32_t cfg_topology;
- uint32_t cfg_scan_down;
uint32_t cfg_link_speed;
uint32_t cfg_cr_delay;
uint32_t cfg_cr_count;
uint32_t cfg_multi_ring_support;
uint32_t cfg_multi_ring_rctl;
uint32_t cfg_multi_ring_type;
- uint32_t cfg_fdmi_on;
- uint32_t cfg_discovery_threads;
- uint32_t cfg_max_luns;
uint32_t cfg_poll;
uint32_t cfg_poll_tmo;
uint32_t cfg_use_msi;
@@ -442,8 +456,8 @@ struct lpfc_hba {
uint32_t cfg_sg_dma_buf_size;
uint64_t cfg_soft_wwnn;
uint64_t cfg_soft_wwpn;
+ uint32_t cfg_hba_queue_depth;
- uint32_t dev_loss_tmo_changed;
lpfc_vpd_t vpd; /* vital product data */
@@ -457,7 +471,6 @@ struct lpfc_hba {
wait_queue_head_t *work_wait;
struct task_struct *worker_thread;
- struct list_head hbq_buffer_list;
uint32_t hbq_count; /* Count of configured HBQs */
struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */
@@ -526,12 +539,14 @@ struct lpfc_hba {
mempool_t *nlp_mem_pool;
struct fc_host_statistics link_stats;
+ uint8_t using_msi;
struct list_head port_list;
- struct lpfc_vport *pport; /* physical lpfc_vport pointer */
- uint16_t max_vpi; /* Maximum virtual nports */
-#define LPFC_MAX_VPI 100 /* Max number of VPorts supported */
- unsigned long *vpi_bmask; /* vpi allocation table */
+ struct lpfc_vport *pport; /* physical lpfc_vport pointer */
+ uint16_t max_vpi; /* Maximum virtual nports */
+#define LPFC_MAX_VPI 100 /* Max number of VPI supported */
+#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
+ unsigned long *vpi_bmask; /* vpi allocation table */
/* Data structure used by fabric iocb scheduler */
struct list_head fabric_iocb_list;
@@ -547,6 +562,11 @@ struct lpfc_hba {
#ifdef CONFIG_LPFC_DEBUG_FS
struct dentry *hba_debugfs_root;
atomic_t debugfs_vport_count;
+ struct dentry *debug_hbqinfo;
+ struct dentry *debug_dumpslim;
+ struct dentry *debug_slow_ring_trc;
+ struct lpfc_debugfs_trc *slow_ring_trc;
+ atomic_t slow_ring_trc_cnt;
#endif
/* Fields used for heart beat. */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 860a52c090f4..80a11218b9bb 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -68,12 +68,6 @@ lpfc_drvr_version_show(struct class_device *cdev, char *buf)
}
static ssize_t
-management_version_show(struct class_device *cdev, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, DFC_API_VERSION "\n");
-}
-
-static ssize_t
lpfc_info_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
@@ -319,9 +313,8 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
if (cnt++ > 3000) {
lpfc_printf_log(phba,
KERN_WARNING, LOG_INIT,
- "%d:0466 Outstanding IO when "
- "bringing Adapter offline\n",
- phba->brd_no);
+ "0466 Outstanding IO when "
+ "bringing Adapter offline\n");
break;
}
}
@@ -437,7 +430,7 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
return -EIO;
}
-int
+static int
lpfc_get_hba_info(struct lpfc_hba *phba,
uint32_t *mxri, uint32_t *axri,
uint32_t *mrpi, uint32_t *arpi,
@@ -694,9 +687,8 @@ lpfc_##attr##_init(struct lpfc_hba *phba, int val) \
return 0;\
}\
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
- "%d:0449 lpfc_"#attr" attribute cannot be set to %d, "\
- "allowed range is ["#minval", "#maxval"]\n", \
- phba->brd_no, val); \
+ "0449 lpfc_"#attr" attribute cannot be set to %d, "\
+ "allowed range is ["#minval", "#maxval"]\n", val); \
phba->cfg_##attr = default;\
return -EINVAL;\
}
@@ -710,9 +702,8 @@ lpfc_##attr##_set(struct lpfc_hba *phba, int val) \
return 0;\
}\
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
- "%d:0450 lpfc_"#attr" attribute cannot be set to %d, "\
- "allowed range is ["#minval", "#maxval"]\n", \
- phba->brd_no, val); \
+ "0450 lpfc_"#attr" attribute cannot be set to %d, "\
+ "allowed range is ["#minval", "#maxval"]\n", val); \
return -EINVAL;\
}
@@ -734,6 +725,75 @@ lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
return -EINVAL;\
}
+#define lpfc_vport_param_show(attr) \
+static ssize_t \
+lpfc_##attr##_show(struct class_device *cdev, char *buf) \
+{ \
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ int val = 0;\
+ val = vport->cfg_##attr;\
+ return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\
+}
+
+#define lpfc_vport_param_hex_show(attr) \
+static ssize_t \
+lpfc_##attr##_show(struct class_device *cdev, char *buf) \
+{ \
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ int val = 0;\
+ val = vport->cfg_##attr;\
+ return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\
+}
+
+#define lpfc_vport_param_init(attr, default, minval, maxval) \
+static int \
+lpfc_##attr##_init(struct lpfc_vport *vport, int val) \
+{ \
+ if (val >= minval && val <= maxval) {\
+ vport->cfg_##attr = val;\
+ return 0;\
+ }\
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+ "0449 lpfc_"#attr" attribute cannot be set to %d, "\
+ "allowed range is ["#minval", "#maxval"]\n", val); \
+ vport->cfg_##attr = default;\
+ return -EINVAL;\
+}
+
+#define lpfc_vport_param_set(attr, default, minval, maxval) \
+static int \
+lpfc_##attr##_set(struct lpfc_vport *vport, int val) \
+{ \
+ if (val >= minval && val <= maxval) {\
+ vport->cfg_##attr = val;\
+ return 0;\
+ }\
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+ "0450 lpfc_"#attr" attribute cannot be set to %d, "\
+ "allowed range is ["#minval", "#maxval"]\n", val); \
+ return -EINVAL;\
+}
+
+#define lpfc_vport_param_store(attr) \
+static ssize_t \
+lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
+{ \
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ int val=0;\
+ if (!isdigit(buf[0]))\
+ return -EINVAL;\
+ if (sscanf(buf, "%i", &val) != 1)\
+ return -EINVAL;\
+ if (lpfc_##attr##_set(vport, val) == 0) \
+ return strlen(buf);\
+ else \
+ return -EINVAL;\
+}
+
+
#define LPFC_ATTR(name, defval, minval, maxval, desc) \
static int lpfc_##name = defval;\
module_param(lpfc_##name, int, 0);\
@@ -778,6 +838,50 @@ lpfc_param_store(name)\
static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
lpfc_##name##_show, lpfc_##name##_store)
+#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_init(name, defval, minval, maxval)
+
+#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+lpfc_vport_param_set(name, defval, minval, maxval)\
+lpfc_vport_param_store(name)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+ lpfc_##name##_show, lpfc_##name##_store)
+
+#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_hex_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_hex_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+lpfc_vport_param_set(name, defval, minval, maxval)\
+lpfc_vport_param_store(name)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+ lpfc_##name##_show, lpfc_##name##_store)
+
static CLASS_DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL);
static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL);
static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL);
@@ -794,8 +898,6 @@ static CLASS_DEVICE_ATTR(num_discovered_ports, S_IRUGO,
static CLASS_DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL);
static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,
NULL);
-static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
- NULL);
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
@@ -908,17 +1010,15 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
if (stat1)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
- "adapter - %d\n", phba->brd_no, stat1);
-
+ "0463 lpfc_soft_wwpn attribute set failed to "
+ "reinit adapter - %d\n", stat1);
init_completion(&online_compl);
lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
wait_for_completion(&online_compl);
if (stat2)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0464 lpfc_soft_wwpn attribute set failed to reinit "
- "adapter - %d\n", phba->brd_no, stat2);
-
+ "0464 lpfc_soft_wwpn attribute set failed to "
+ "reinit adapter - %d\n", stat2);
return (stat1 || stat2) ? -EIO : count;
}
static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
@@ -927,8 +1027,8 @@ static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
static ssize_t
lpfc_soft_wwnn_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
return snprintf(buf, PAGE_SIZE, "0x%llx\n",
(unsigned long long)phba->cfg_soft_wwnn);
}
@@ -937,8 +1037,8 @@ lpfc_soft_wwnn_show(struct class_device *cdev, char *buf)
static ssize_t
lpfc_soft_wwnn_store(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
unsigned int i, j, cnt=count;
u8 wwnn[8];
@@ -1002,7 +1102,7 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
" 2 - select SLI-2 even on SLI-3 capable HBAs,"
" 3 - select SLI-3");
-LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
+LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1019,90 +1119,75 @@ lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- struct lpfc_hba *phba = vport->phba;
int val = 0;
- val = phba->cfg_devloss_tmo;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- phba->cfg_devloss_tmo);
+ val = vport->cfg_devloss_tmo;
+ return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo);
}
static int
-lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
+lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val)
{
- static int warned;
- if (phba->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
- phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
- if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
- warned = 1;
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0402 Ignoring nodev_tmo module "
- "parameter because devloss_tmo is"
- " set.\n",
- phba->brd_no);
- }
+ if (vport->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
+ vport->cfg_nodev_tmo = vport->cfg_devloss_tmo;
+ if (val != LPFC_DEF_DEVLOSS_TMO)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0402 Ignoring nodev_tmo module "
+ "parameter because devloss_tmo is "
+ "set.\n");
return 0;
}
if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
- phba->cfg_nodev_tmo = val;
- phba->cfg_devloss_tmo = val;
+ vport->cfg_nodev_tmo = val;
+ vport->cfg_devloss_tmo = val;
return 0;
}
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
- "allowed range is [%d, %d]\n",
- phba->brd_no, val,
- LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
- phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0400 lpfc_nodev_tmo attribute cannot be set to"
+ " %d, allowed range is [%d, %d]\n",
+ val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
+ vport->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
return -EINVAL;
}
static void
-lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
{
- struct lpfc_vport *vport;
struct Scsi_Host *shost;
struct lpfc_nodelist *ndlp;
- list_for_each_entry(vport, &phba->port_list, listentry) {
- shost = lpfc_shost_from_vport(vport);
- spin_lock_irq(shost->host_lock);
- list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
- if (ndlp->rport)
- ndlp->rport->dev_loss_tmo =
- phba->cfg_devloss_tmo;
- spin_unlock_irq(shost->host_lock);
- }
+ shost = lpfc_shost_from_vport(vport);
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+ if (ndlp->rport)
+ ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;
+ spin_unlock_irq(shost->host_lock);
}
static int
-lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
+lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val)
{
- if (phba->dev_loss_tmo_changed ||
- (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0401 Ignoring change to nodev_tmo "
- "because devloss_tmo is set.\n",
- phba->brd_no);
+ if (vport->dev_loss_tmo_changed ||
+ (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0401 Ignoring change to nodev_tmo "
+ "because devloss_tmo is set.\n");
return 0;
}
-
if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
- phba->cfg_nodev_tmo = val;
- phba->cfg_devloss_tmo = val;
- lpfc_update_rport_devloss_tmo(phba);
+ vport->cfg_nodev_tmo = val;
+ vport->cfg_devloss_tmo = val;
+ lpfc_update_rport_devloss_tmo(vport);
return 0;
}
-
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
- "allowed range is [%d, %d]\n",
- phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
- LPFC_MAX_DEVLOSS_TMO);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0403 lpfc_nodev_tmo attribute cannot be set to"
+ "%d, allowed range is [%d, %d]\n",
+ val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
return -EINVAL;
}
-lpfc_param_store(nodev_tmo)
+lpfc_vport_param_store(nodev_tmo)
static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
@@ -1116,29 +1201,28 @@ module_param(lpfc_devloss_tmo, int, 0);
MODULE_PARM_DESC(lpfc_devloss_tmo,
"Seconds driver will hold I/O waiting "
"for a device to come back");
-lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
- LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
-lpfc_param_show(devloss_tmo)
+lpfc_vport_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
+lpfc_vport_param_show(devloss_tmo)
static int
-lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
+lpfc_devloss_tmo_set(struct lpfc_vport *vport, int val)
{
if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
- phba->cfg_nodev_tmo = val;
- phba->cfg_devloss_tmo = val;
- phba->dev_loss_tmo_changed = 1;
- lpfc_update_rport_devloss_tmo(phba);
+ vport->cfg_nodev_tmo = val;
+ vport->cfg_devloss_tmo = val;
+ vport->dev_loss_tmo_changed = 1;
+ lpfc_update_rport_devloss_tmo(vport);
return 0;
}
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0404 lpfc_devloss_tmo attribute cannot be set to"
- " %d, allowed range is [%d, %d]\n",
- phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
- LPFC_MAX_DEVLOSS_TMO);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0404 lpfc_devloss_tmo attribute cannot be set to"
+ " %d, allowed range is [%d, %d]\n",
+ val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
return -EINVAL;
}
-lpfc_param_store(devloss_tmo)
+lpfc_vport_param_store(devloss_tmo)
static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
@@ -1160,14 +1244,15 @@ static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
# LOG_LIBDFC 0x2000 LIBDFC events
# LOG_ALL_MSG 0xffff LOG all messages
*/
-LPFC_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask");
+LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
+ "Verbose logging bit-mask");
/*
# lun_queue_depth: This parameter is used to limit the number of outstanding
# commands per FCP LUN. Value range is [1,128]. Default value is 30.
*/
-LPFC_ATTR_R(lun_queue_depth, 30, 1, 128,
- "Max number of FCP commands we can queue to a specific LUN");
+LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
+ "Max number of FCP commands we can queue to a specific LUN");
/*
# hba_queue_depth: This parameter is used to limit the number of outstanding
@@ -1188,12 +1273,12 @@ LPFC_ATTR_R(hba_queue_depth, 8192, 32, 8192,
# are allowed to login to each other.
# Default value of this parameter is 0.
*/
-LPFC_ATTR_R(peer_port_login, 0, 0, 1,
- "Allow peer ports on the same physical port to login to each "
- "other.");
+LPFC_VPORT_ATTR_R(peer_port_login, 0, 0, 1,
+ "Allow peer ports on the same physical port to login to each "
+ "other.");
/*
-# vport_restrict_login: This parameter allows/prevents logins
+# restrict_login: This parameter allows/prevents logins
# between Virtual Ports and remote initiators.
# When this parameter is not set (0) Virtual Ports will accept PLOGIs from
# other initiators and will attempt to PLOGI all remote ports.
@@ -1203,8 +1288,55 @@ LPFC_ATTR_R(peer_port_login, 0, 0, 1,
# This parameter does not restrict logins to Fabric resident remote ports.
# Default value of this parameter is 1.
*/
-LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1,
- "Restrict virtual ports login to remote initiators.");
+static int lpfc_restrict_login = 1;
+module_param(lpfc_restrict_login, int, 0);
+MODULE_PARM_DESC(lpfc_restrict_login,
+ "Restrict virtual ports login to remote initiators.");
+lpfc_vport_param_show(restrict_login);
+
+static int
+lpfc_restrict_login_init(struct lpfc_vport *vport, int val)
+{
+ if (val < 0 || val > 1) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0449 lpfc_restrict_login attribute cannot "
+ "be set to %d, allowed range is [0, 1]\n",
+ val);
+ vport->cfg_restrict_login = 1;
+ return -EINVAL;
+ }
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ vport->cfg_restrict_login = 0;
+ return 0;
+ }
+ vport->cfg_restrict_login = val;
+ return 0;
+}
+
+static int
+lpfc_restrict_login_set(struct lpfc_vport *vport, int val)
+{
+ if (val < 0 || val > 1) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0450 lpfc_restrict_login attribute cannot "
+ "be set to %d, allowed range is [0, 1]\n",
+ val);
+ vport->cfg_restrict_login = 1;
+ return -EINVAL;
+ }
+ if (vport->port_type == LPFC_PHYSICAL_PORT && val != 0) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0468 lpfc_restrict_login must be 0 for "
+ "Physical ports.\n");
+ vport->cfg_restrict_login = 0;
+ return 0;
+ }
+ vport->cfg_restrict_login = val;
+ return 0;
+}
+lpfc_vport_param_store(restrict_login);
+static CLASS_DEVICE_ATTR(lpfc_restrict_login, S_IRUGO | S_IWUSR,
+ lpfc_restrict_login_show, lpfc_restrict_login_store);
/*
# Some disk devices have a "select ID" or "select Target" capability.
@@ -1223,8 +1355,8 @@ LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1,
# and will not work across a fabric. Also this parameter will take
# effect only in the case when ALPA map is not available.)
*/
-LPFC_ATTR_R(scan_down, 1, 0, 1,
- "Start scanning for devices from highest ALPA to lowest");
+LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
+ "Start scanning for devices from highest ALPA to lowest");
/*
# lpfc_topology: link topology for init link
@@ -1255,15 +1387,15 @@ LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
# lpfc_fcp_class: Determines FC class to use for the FCP protocol.
# Value range is [2,3]. Default value is 3.
*/
-LPFC_ATTR_R(fcp_class, 3, 2, 3,
- "Select Fibre Channel class of service for FCP sequences");
+LPFC_VPORT_ATTR_R(fcp_class, 3, 2, 3,
+ "Select Fibre Channel class of service for FCP sequences");
/*
# lpfc_use_adisc: Use ADISC for FCP rediscovery instead of PLOGI. Value range
# is [0,1]. Default value is 0.
*/
-LPFC_ATTR_RW(use_adisc, 0, 0, 1,
- "Use ADISC on rediscovery to authenticate FCP devices");
+LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
+ "Use ADISC on rediscovery to authenticate FCP devices");
/*
# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value
@@ -1315,13 +1447,13 @@ LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1,
# 2 = support FDMI with attribute of hostname
# Value range [0,2]. Default value is 0.
*/
-LPFC_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support");
+LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support");
/*
# Specifies the maximum number of ELS cmds we can have outstanding (for
# discovery). Value range is [1,64]. Default value = 32.
*/
-LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
+LPFC_VPORT_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
"during discovery");
/*
@@ -1329,8 +1461,7 @@ LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
# Value range is [0,65535]. Default value is 255.
# NOTE: The SCSI layer might probe all allowed LUN on some old targets.
*/
-LPFC_ATTR_R(max_luns, 255, 0, 65535,
- "Maximum allowed LUN");
+LPFC_VPORT_ATTR_R(max_luns, 255, 0, 65535, "Maximum allowed LUN");
/*
# lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring.
@@ -1367,7 +1498,6 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
&class_device_attr_lpfc_lun_queue_depth,
&class_device_attr_lpfc_hba_queue_depth,
&class_device_attr_lpfc_peer_port_login,
- &class_device_attr_lpfc_vport_restrict_login,
&class_device_attr_lpfc_nodev_tmo,
&class_device_attr_lpfc_devloss_tmo,
&class_device_attr_lpfc_fcp_class,
@@ -1383,9 +1513,8 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
&class_device_attr_lpfc_multi_ring_type,
&class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns,
- &class_device_attr_lpfc_npiv_enable,
+ &class_device_attr_lpfc_enable_npiv,
&class_device_attr_nport_evt_cnt,
- &class_device_attr_management_version,
&class_device_attr_board_mode,
&class_device_attr_max_vpi,
&class_device_attr_used_vpi,
@@ -1404,6 +1533,28 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
NULL,
};
+struct class_device_attribute *lpfc_vport_attrs[] = {
+ &class_device_attr_info,
+ &class_device_attr_state,
+ &class_device_attr_num_discovered_ports,
+ &class_device_attr_lpfc_drvr_version,
+
+ &class_device_attr_lpfc_log_verbose,
+ &class_device_attr_lpfc_lun_queue_depth,
+ &class_device_attr_lpfc_nodev_tmo,
+ &class_device_attr_lpfc_devloss_tmo,
+ &class_device_attr_lpfc_hba_queue_depth,
+ &class_device_attr_lpfc_peer_port_login,
+ &class_device_attr_lpfc_restrict_login,
+ &class_device_attr_lpfc_fcp_class,
+ &class_device_attr_lpfc_use_adisc,
+ &class_device_attr_lpfc_fdmi_on,
+ &class_device_attr_lpfc_max_luns,
+ &class_device_attr_nport_evt_cnt,
+ &class_device_attr_npiv_info,
+ NULL,
+};
+
static ssize_t
sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -2243,7 +2394,6 @@ struct fc_function_template lpfc_vport_transport_functions = {
.get_starget_port_name = lpfc_get_starget_port_name,
.show_starget_port_name = 1,
- .issue_fc_host_lip = lpfc_issue_lip,
.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
.terminate_rport_io = lpfc_terminate_rport_io,
@@ -2253,39 +2403,25 @@ struct fc_function_template lpfc_vport_transport_functions = {
void
lpfc_get_cfgparam(struct lpfc_hba *phba)
{
- lpfc_log_verbose_init(phba, lpfc_log_verbose);
lpfc_cr_delay_init(phba, lpfc_cr_delay);
lpfc_cr_count_init(phba, lpfc_cr_count);
lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support);
lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl);
lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type);
- lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth);
- lpfc_fcp_class_init(phba, lpfc_fcp_class);
- lpfc_use_adisc_init(phba, lpfc_use_adisc);
lpfc_ack0_init(phba, lpfc_ack0);
lpfc_topology_init(phba, lpfc_topology);
- lpfc_scan_down_init(phba, lpfc_scan_down);
lpfc_link_speed_init(phba, lpfc_link_speed);
- lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
- lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
- lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
- lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
- lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
- lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
+ lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_use_msi_init(phba, lpfc_use_msi);
- lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
- lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
phba->cfg_poll = lpfc_poll;
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
-
/*
* The total number of segments is the configuration value plus 2
* since the IOCB need a command and response bde.
*/
phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
-
/*
* Since the sg_tablesize is module parameter, the sg_dma_buf_size
* used to create the sg_dma_buf_pool must be dynamically calculated
@@ -2293,9 +2429,24 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
sizeof(struct fcp_rsp) +
(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
-
-
lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+ return;
+}
+void
+lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
+{
+ lpfc_log_verbose_init(vport, lpfc_log_verbose);
+ lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth);
+ lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo);
+ lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo);
+ lpfc_peer_port_login_init(vport, lpfc_peer_port_login);
+ lpfc_restrict_login_init(vport, lpfc_restrict_login);
+ lpfc_fcp_class_init(vport, lpfc_fcp_class);
+ lpfc_use_adisc_init(vport, lpfc_use_adisc);
+ lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
+ lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
+ lpfc_max_luns_init(vport, lpfc_max_luns);
+ lpfc_scan_down_init(vport, lpfc_scan_down);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index e19d1a746586..a599e1510710 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -40,6 +40,7 @@ void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
+struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -101,7 +102,7 @@ int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
- struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
+ struct lpfc_nodelist *, LPFC_MBOXQ_t *);
int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
struct lpfc_nodelist *, LPFC_MBOXQ_t *);
int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
@@ -117,6 +118,7 @@ void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
int lpfc_els_handle_rscn(struct lpfc_vport *);
void lpfc_els_flush_rscn(struct lpfc_vport *);
int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t);
+void lpfc_els_flush_all_cmd(struct lpfc_hba *);
void lpfc_els_flush_cmd(struct lpfc_vport *);
int lpfc_els_disc_adisc(struct lpfc_vport *);
int lpfc_els_disc_plogi(struct lpfc_vport *);
@@ -161,9 +163,11 @@ LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
-void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t ,
- LPFC_MBOXQ_t *);
+void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
+ uint32_t , LPFC_MBOXQ_t *);
struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
+struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
+void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
@@ -200,6 +204,7 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
struct lpfc_sli_ring *,
dma_addr_t);
+int lpfc_sli_hbq_count(void);
int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
@@ -207,10 +212,9 @@ struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
int lpfc_sli_hbq_size(void);
int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
-int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
- uint64_t, lpfc_ctx_cmd);
-int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
- uint64_t, uint32_t, lpfc_ctx_cmd);
+int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd);
+int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,
+ uint64_t, lpfc_ctx_cmd);
void lpfc_mbox_timeout(unsigned long);
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
@@ -234,8 +238,6 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba,
struct lpfc_iocbq * cmdiocb,
struct lpfc_iocbq * rspiocb);
-void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *);
-void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *);
void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
@@ -248,10 +250,13 @@ const char* lpfc_info(struct Scsi_Host *);
int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
void lpfc_get_cfgparam(struct lpfc_hba *);
+void lpfc_get_vport_cfgparam(struct lpfc_vport *);
int lpfc_alloc_sysfs_attr(struct lpfc_vport *);
void lpfc_free_sysfs_attr(struct lpfc_vport *);
extern struct class_device_attribute *lpfc_hba_attrs[];
+extern struct class_device_attribute *lpfc_vport_attrs[];
extern struct scsi_host_template lpfc_template;
+extern struct scsi_host_template lpfc_vport_template;
extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_vport_transport_functions;
extern int lpfc_sli_mode;
@@ -260,7 +265,7 @@ int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *);
void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
-struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct fc_vport *);
+struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *);
int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable);
void lpfc_mbx_unreg_vpi(struct lpfc_vport *);
void destroy_port(struct lpfc_vport *);
@@ -271,6 +276,9 @@ extern void lpfc_debugfs_initialize(struct lpfc_vport *);
extern void lpfc_debugfs_terminate(struct lpfc_vport *);
extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
uint32_t, uint32_t);
+extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
+ uint32_t, uint32_t);
+extern struct lpfc_hbq_init *lpfc_hbq_defs[];
/* Interface exported by fabric iocb scheduler */
int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index ae9d6f385a6c..c701e4d611a9 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -257,6 +257,10 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
{
struct lpfc_dmabuf *buf_ptr;
+ if (ctiocb->context_un.ndlp) {
+ lpfc_nlp_put(ctiocb->context_un.ndlp);
+ ctiocb->context_un.ndlp = NULL;
+ }
if (ctiocb->context1) {
buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
@@ -314,6 +318,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
/* Save for completion so we can release these resources */
geniocb->context1 = (uint8_t *) inp;
geniocb->context2 = (uint8_t *) outp;
+ geniocb->context_un.ndlp = ndlp;
/* Fill in payload, bp points to frame payload */
icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
@@ -341,11 +346,11 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
}
/* Issue GEN REQ IOCB for NPORT <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0119 Issue GEN REQ IOCB to NPORT x%x "
- "Data: x%x x%x\n", phba->brd_no, vport->vpi,
- ndlp->nlp_DID, icmd->ulpIoTag,
- vport->port_state);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0119 Issue GEN REQ IOCB to NPORT x%x "
+ "Data: x%x x%x\n",
+ ndlp->nlp_DID, icmd->ulpIoTag,
+ vport->port_state);
geniocb->iocb_cmpl = cmpl;
geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
geniocb->vport = vport;
@@ -390,17 +395,19 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
return 0;
}
-static struct lpfc_vport *
+struct lpfc_vport *
lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
-
struct lpfc_vport *vport_curr;
+ unsigned long flags;
+ spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport_curr, &phba->port_list, listentry) {
- if ((vport_curr->fc_myDID) &&
- (vport_curr->fc_myDID == did))
+ if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return vport_curr;
+ }
}
-
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return NULL;
}
@@ -449,10 +456,10 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
*/
if ((Did != vport->fc_myDID) &&
((lpfc_find_vport_by_did(phba, Did) == NULL) ||
- phba->cfg_peer_port_login)) {
+ vport->cfg_peer_port_login)) {
if ((vport->port_type != LPFC_NPIV_PORT) ||
(vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
- (!phba->cfg_vport_restrict_login)) {
+ (!vport->cfg_restrict_login)) {
ndlp = lpfc_setup_disc_node(vport, Did);
if (ndlp) {
lpfc_debugfs_disc_trc(vport,
@@ -462,14 +469,13 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
Did, ndlp->nlp_flag,
vport->fc_flag);
- lpfc_printf_log(phba, KERN_INFO,
+ lpfc_printf_vlog(vport,
+ KERN_INFO,
LOG_DISCOVERY,
- "%d (%d):0238 Process "
+ "0238 Process "
"x%x NameServer Rsp"
"Data: x%x x%x x%x\n",
- phba->brd_no,
- vport->vpi, Did,
- ndlp->nlp_flag,
+ Did, ndlp->nlp_flag,
vport->fc_flag,
vport->fc_rscn_id_cnt);
} else {
@@ -480,14 +486,13 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
Did, vport->fc_flag,
vport->fc_rscn_id_cnt);
- lpfc_printf_log(phba, KERN_INFO,
+ lpfc_printf_vlog(vport,
+ KERN_INFO,
LOG_DISCOVERY,
- "%d (%d):0239 Skip x%x "
+ "0239 Skip x%x "
"NameServer Rsp Data: "
"x%x x%x\n",
- phba->brd_no,
- vport->vpi, Did,
- vport->fc_flag,
+ Did, vport->fc_flag,
vport->fc_rscn_id_cnt);
}
@@ -514,14 +519,13 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
Did, vport->fc_flag,
vport->fc_rscn_id_cnt);
- lpfc_printf_log(phba, KERN_INFO,
+ lpfc_printf_vlog(vport,
+ KERN_INFO,
LOG_DISCOVERY,
- "%d (%d):0245 Skip x%x "
+ "0245 Skip x%x "
"NameServer Rsp Data: "
"x%x x%x\n",
- phba->brd_no,
- vport->vpi, Did,
- vport->fc_flag,
+ Did, vport->fc_flag,
vport->fc_rscn_id_cnt);
}
}
@@ -549,8 +553,12 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *bmp;
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *CTrsp;
+ struct lpfc_nodelist *ndlp;
int rc;
+ /* First save ndlp, before we overwrite it */
+ ndlp = cmdiocb->context_un.ndlp;
+
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -568,9 +576,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0216 Link event during NS query\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0216 Link event during NS query\n");
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
goto out;
}
@@ -588,46 +595,61 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n",
- phba->brd_no, vport->vpi, irsp->ulpStatus,
- vport->fc_ns_retry);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0257 GID_FT Query error: 0x%x 0x%x\n",
+ irsp->ulpStatus, vport->fc_ns_retry);
} else {
/* Good status, continue checking */
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0208 NameServer Rsp "
- "Data: x%x\n",
- phba->brd_no, vport->vpi,
- vport->fc_flag);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0208 NameServer Rsp Data: x%x\n",
+ vport->fc_flag);
lpfc_ns_rsp(vport, outp,
(uint32_t) (irsp->un.genreq64.bdl.bdeSize));
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* NameServer Rsp Error */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0240 NameServer Rsp Error "
+ if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
+ && (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
+ lpfc_printf_vlog(vport, KERN_INFO,
+ LOG_DISCOVERY,
+ "0269 No NameServer Entries "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation,
vport->fc_flag);
- lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT no entry cmd:x%x rsn:x%x exp:x%x",
+ (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+ (uint32_t) CTrsp->ReasonCode,
+ (uint32_t) CTrsp->Explanation);
+ } else {
+ lpfc_printf_vlog(vport, KERN_INFO,
+ LOG_DISCOVERY,
+ "0240 NameServer Rsp Error "
+ "Data: x%x x%x x%x x%x\n",
+ CTrsp->CommandResponse.bits.CmdRsp,
+ (uint32_t) CTrsp->ReasonCode,
+ (uint32_t) CTrsp->Explanation,
+ vport->fc_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
"GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation);
+ }
+
} else {
/* NameServer Rsp Error */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0241 NameServer Rsp Error "
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0241 NameServer Rsp Error "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation,
@@ -661,11 +683,12 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_disc_start(vport);
}
out:
+ cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
-void
+static void
lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
@@ -695,40 +718,37 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
if ((fbits & FC4_FEATURE_INIT) &&
!(fbits & FC4_FEATURE_TARGET)) {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0245 Skip x%x GFF "
- "NameServer Rsp Data: (init) "
- "x%x x%x\n", phba->brd_no,
- vport->vpi, did, fbits,
- vport->fc_rscn_id_cnt);
+ lpfc_printf_vlog(vport, KERN_INFO,
+ LOG_DISCOVERY,
+ "0270 Skip x%x GFF "
+ "NameServer Rsp Data: (init) "
+ "x%x x%x\n", did, fbits,
+ vport->fc_rscn_id_cnt);
goto out;
}
}
}
else {
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0267 NameServer GFF Rsp"
- " x%x Error (%d %d) Data: x%x x%x\n",
- phba->brd_no, vport->vpi, did,
- irsp->ulpStatus, irsp->un.ulpWord[4],
- vport->fc_flag, vport->fc_rscn_id_cnt)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0267 NameServer GFF Rsp "
+ "x%x Error (%d %d) Data: x%x x%x\n",
+ did, irsp->ulpStatus, irsp->un.ulpWord[4],
+ vport->fc_flag, vport->fc_rscn_id_cnt)
}
/* This is a target port, unregistered port, or the GFF_ID failed */
ndlp = lpfc_setup_disc_node(vport, did);
if (ndlp) {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0242 Process x%x GFF "
- "NameServer Rsp Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- did, ndlp->nlp_flag, vport->fc_flag,
- vport->fc_rscn_id_cnt);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0242 Process x%x GFF "
+ "NameServer Rsp Data: x%x x%x x%x\n",
+ did, ndlp->nlp_flag, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
} else {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0243 Skip x%x GFF "
- "NameServer Rsp Data: x%x x%x\n",
- phba->brd_no, vport->vpi, did,
- vport->fc_flag, vport->fc_rscn_id_cnt);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0243 Skip x%x GFF "
+ "NameServer Rsp Data: x%x x%x\n", did,
+ vport->fc_flag, vport->fc_rscn_id_cnt);
}
out:
/* Link up / RSCN discovery */
@@ -766,10 +786,14 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *outp;
IOCB_t *irsp;
struct lpfc_sli_ct_request *CTrsp;
+ struct lpfc_nodelist *ndlp;
int cmdcode, rc;
uint8_t retry;
uint32_t latt;
+ /* First save ndlp, before we overwrite it */
+ ndlp = cmdiocb->context_un.ndlp;
+
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -784,22 +808,21 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
latt = lpfc_els_chk_latt(vport);
/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0209 RFT request completes, latt %d, "
- "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
- phba->brd_no, vport->vpi, latt, irsp->ulpStatus,
- CTrsp->CommandResponse.bits.CmdRsp,
- cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0209 RFT request completes, latt %d, "
+ "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+ latt, irsp->ulpStatus,
+ CTrsp->CommandResponse.bits.CmdRsp,
+ cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
"CT cmd cmpl: status:x%x/x%x cmd:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
if (irsp->ulpStatus) {
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0268 NS cmd %x Error (%d %d)\n",
- phba->brd_no, vport->vpi, cmdcode,
- irsp->ulpStatus, irsp->un.ulpWord[4]);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0268 NS cmd %x Error (%d %d)\n",
+ cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
@@ -811,15 +834,15 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
retry++;
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0216 Retrying NS cmd %x\n",
- phba->brd_no, vport->vpi, cmdcode);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0216 Retrying NS cmd %x\n", cmdcode);
rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
if (rc == 0)
goto out;
}
out:
+ cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
@@ -862,7 +885,7 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
return;
}
-int
+static int
lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
size_t size)
{
@@ -957,10 +980,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
}
/* NameServer Req */
- lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY,
- "%d (%d):0236 NameServer Req Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, cmdcode, vport->fc_flag,
- vport->fc_rscn_id_cnt);
+ lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY,
+ "0236 NameServer Req Data: x%x x%x x%x\n",
+ cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt);
bpl = (struct ulp_bde64 *) bmp->virt;
memset(bpl, 0, sizeof(struct ulp_bde64));
@@ -1059,6 +1081,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cmpl = lpfc_cmpl_ct_cmd_rff_id;
break;
}
+ lpfc_nlp_get(ndlp);
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
/* On success, The cmpl function will free the buffers */
@@ -1069,6 +1092,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
}
rc=6;
+ lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
ns_cmd_free_bmp:
kfree(bmp);
@@ -1077,10 +1101,9 @@ ns_cmd_free_mpvirt:
ns_cmd_free_mp:
kfree(mp);
ns_cmd_exit:
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
- phba->brd_no, vport->vpi, cmdcode, rc, vport->fc_flag,
- vport->fc_rscn_id_cnt);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
+ cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt);
return 1;
}
@@ -1106,12 +1129,11 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4], latt);
if (latt || irsp->ulpStatus) {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0229 FDMI cmd %04x failed, latt = %d "
- "ulpStatus: x%x, rid x%x\n",
- phba->brd_no, vport->vpi,
- be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
- irsp->un.ulpWord[4]);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0229 FDMI cmd %04x failed, latt = %d "
+ "ulpStatus: x%x, rid x%x\n",
+ be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
@@ -1119,10 +1141,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0220 FDMI rsp failed Data: x%x\n",
- phba->brd_no, vport->vpi,
- be16_to_cpu(fdmi_cmd));
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0220 FDMI rsp failed Data: x%x\n",
+ be16_to_cpu(fdmi_cmd));
}
switch (be16_to_cpu(fdmi_cmd)) {
@@ -1185,11 +1206,9 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
INIT_LIST_HEAD(&bmp->list);
/* FDMI request */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0218 FDMI Request Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->fc_flag,
- vport->port_state, cmdcode);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0218 FDMI Request Data: x%x x%x x%x\n",
+ vport->fc_flag, vport->port_state, cmdcode);
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
@@ -1449,7 +1468,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
pab->ab.EntryCnt++;
size += FOURBYTES + len;
- if (phba->cfg_fdmi_on == 2) {
+ if (vport->cfg_fdmi_on == 2) {
/* #6 Port attribute entry */
ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab +
size);
@@ -1499,10 +1518,12 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
bpl->tus.w = le32_to_cpu(bpl->tus.w);
cmpl = lpfc_cmpl_ct_cmd_fdmi;
+ lpfc_nlp_get(ndlp);
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
return 0;
+ lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
fdmi_cmd_free_bmp:
kfree(bmp);
@@ -1512,9 +1533,9 @@ fdmi_cmd_free_mp:
kfree(mp);
fdmi_cmd_exit:
/* Issue FDMI request failed */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0244 Issue FDMI request failed Data: x%x\n",
- phba->brd_no, vport->vpi, cmdcode);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0244 Issue FDMI request failed Data: x%x\n",
+ cmdcode);
return 1;
}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 673cfe11cc2b..2e3c01bebed6 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -71,15 +71,22 @@
* lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in
* lpfc_debugfs.h .
*/
-static int lpfc_debugfs_enable = 0;
+static int lpfc_debugfs_enable = 1;
module_param(lpfc_debugfs_enable, int, 0);
MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
-static int lpfc_debugfs_max_disc_trc = 0; /* This MUST be a power of 2 */
+/* This MUST be a power of 2 */
+static int lpfc_debugfs_max_disc_trc = 0;
module_param(lpfc_debugfs_max_disc_trc, int, 0);
MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
"Set debugfs discovery trace depth");
+/* This MUST be a power of 2 */
+static int lpfc_debugfs_max_slow_ring_trc = 0;
+module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
+ "Set debugfs slow ring trace depth");
+
static int lpfc_debugfs_mask_disc_trc = 0;
module_param(lpfc_debugfs_mask_disc_trc, int, 0);
MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
@@ -87,28 +94,34 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
#include <linux/debugfs.h>
-/* size of discovery_trace output line */
-#define LPFC_DISC_TRC_ENTRY_SIZE 80
+/* size of output line, for discovery_trace and slow_ring_trace */
+#define LPFC_DEBUG_TRC_ENTRY_SIZE 100
/* nodelist output buffer size */
#define LPFC_NODELIST_SIZE 8192
#define LPFC_NODELIST_ENTRY_SIZE 120
+/* dumpslim output buffer size */
+#define LPFC_DUMPSLIM_SIZE 4096
+
+/* hbqinfo output buffer size */
+#define LPFC_HBQINFO_SIZE 8192
+
struct lpfc_debug {
char *buffer;
int len;
};
-atomic_t lpfc_debugfs_disc_trc_cnt = ATOMIC_INIT(0);
-unsigned long lpfc_debugfs_start_time = 0L;
+static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);
+static unsigned long lpfc_debugfs_start_time = 0L;
static int
lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
{
int i, index, len, enable;
uint32_t ms;
- struct lpfc_disc_trc *dtp;
- char buffer[80];
+ struct lpfc_debugfs_trc *dtp;
+ char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
enable = lpfc_debugfs_enable;
@@ -122,7 +135,8 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
if (!dtp->fmt)
continue;
ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
- snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+ snprintf(buffer,
+ LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
dtp->seq_cnt, ms, dtp->fmt);
len += snprintf(buf+len, size-len, buffer,
dtp->data1, dtp->data2, dtp->data3);
@@ -132,7 +146,8 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
if (!dtp->fmt)
continue;
ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
- snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+ snprintf(buffer,
+ LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
dtp->seq_cnt, ms, dtp->fmt);
len += snprintf(buf+len, size-len, buffer,
dtp->data1, dtp->data2, dtp->data3);
@@ -143,6 +158,236 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
}
static int
+lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
+{
+ int i, index, len, enable;
+ uint32_t ms;
+ struct lpfc_debugfs_trc *dtp;
+ char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
+
+
+ enable = lpfc_debugfs_enable;
+ lpfc_debugfs_enable = 0;
+
+ len = 0;
+ index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) &
+ (lpfc_debugfs_max_slow_ring_trc - 1);
+ for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) {
+ dtp = phba->slow_ring_trc + i;
+ if (!dtp->fmt)
+ continue;
+ ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+ snprintf(buffer,
+ LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
+ dtp->seq_cnt, ms, dtp->fmt);
+ len += snprintf(buf+len, size-len, buffer,
+ dtp->data1, dtp->data2, dtp->data3);
+ }
+ for (i = 0; i < index; i++) {
+ dtp = phba->slow_ring_trc + i;
+ if (!dtp->fmt)
+ continue;
+ ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+ snprintf(buffer,
+ LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
+ dtp->seq_cnt, ms, dtp->fmt);
+ len += snprintf(buf+len, size-len, buffer,
+ dtp->data1, dtp->data2, dtp->data3);
+ }
+
+ lpfc_debugfs_enable = enable;
+ return len;
+}
+
+static int lpfc_debugfs_last_hbq = -1;
+
+static int
+lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
+{
+ int len = 0;
+ int cnt, i, j, found, posted, low;
+ uint32_t phys, raw_index, getidx;
+ struct lpfc_hbq_init *hip;
+ struct hbq_s *hbqs;
+ struct lpfc_hbq_entry *hbqe;
+ struct lpfc_dmabuf *d_buf;
+ struct hbq_dmabuf *hbq_buf;
+
+ cnt = LPFC_HBQINFO_SIZE;
+ spin_lock_irq(&phba->hbalock);
+
+ /* toggle between multiple hbqs, if any */
+ i = lpfc_sli_hbq_count();
+ if (i > 1) {
+ lpfc_debugfs_last_hbq++;
+ if (lpfc_debugfs_last_hbq >= i)
+ lpfc_debugfs_last_hbq = 0;
+ }
+ else
+ lpfc_debugfs_last_hbq = 0;
+
+ i = lpfc_debugfs_last_hbq;
+
+ len += snprintf(buf+len, size-len, "HBQ %d Info\n", i);
+
+ hbqs = &phba->hbqs[i];
+ posted = 0;
+ list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list)
+ posted++;
+
+ hip = lpfc_hbq_defs[i];
+ len += snprintf(buf+len, size-len,
+ "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n",
+ hip->hbq_index, hip->profile, hip->rn,
+ hip->buffer_count, hip->init_count, hip->add_count, posted);
+
+ raw_index = phba->hbq_get[i];
+ getidx = le32_to_cpu(raw_index);
+ len += snprintf(buf+len, size-len,
+ "entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
+ hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx,
+ hbqs->local_hbqGetIdx, getidx);
+
+ hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
+ for (j=0; j<hbqs->entry_count; j++) {
+ len += snprintf(buf+len, size-len,
+ "%03d: %08x %04x %05x ", j,
+ hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag);
+
+ i = 0;
+ found = 0;
+
+ /* First calculate if slot has an associated posted buffer */
+ low = hbqs->hbqPutIdx - posted;
+ if (low >= 0) {
+ if ((j >= hbqs->hbqPutIdx) || (j < low)) {
+ len += snprintf(buf+len, size-len, "Unused\n");
+ goto skipit;
+ }
+ }
+ else {
+ if ((j >= hbqs->hbqPutIdx) &&
+ (j < (hbqs->entry_count+low))) {
+ len += snprintf(buf+len, size-len, "Unused\n");
+ goto skipit;
+ }
+ }
+
+ /* Get the Buffer info for the posted buffer */
+ list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
+ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
+ if (phys == hbqe->bde.addrLow) {
+ len += snprintf(buf+len, size-len,
+ "Buf%d: %p %06x\n", i,
+ hbq_buf->dbuf.virt, hbq_buf->tag);
+ found = 1;
+ break;
+ }
+ i++;
+ }
+ if (!found) {
+ len += snprintf(buf+len, size-len, "No DMAinfo?\n");
+ }
+skipit:
+ hbqe++;
+ if (len > LPFC_HBQINFO_SIZE - 54)
+ break;
+ }
+ spin_unlock_irq(&phba->hbalock);
+ return len;
+}
+
+static int
+lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
+{
+ int len = 0;
+ int cnt, i, off;
+ uint32_t word0, word1, word2, word3;
+ uint32_t *ptr;
+ struct lpfc_pgp *pgpp;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+
+ cnt = LPFC_DUMPSLIM_SIZE;
+ off = 0;
+ spin_lock_irq(&phba->hbalock);
+
+ len += snprintf(buf+len, size-len, "SLIM Mailbox\n");
+ ptr = (uint32_t *)phba->slim2p;
+ i = sizeof(MAILBOX_t);
+ while (i > 0) {
+ len += snprintf(buf+len, size-len,
+ "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+ *(ptr+5), *(ptr+6), *(ptr+7));
+ ptr += 8;
+ i -= (8 * sizeof(uint32_t));
+ off += (8 * sizeof(uint32_t));
+ }
+
+ len += snprintf(buf+len, size-len, "SLIM PCB\n");
+ ptr = (uint32_t *)&phba->slim2p->pcb;
+ i = sizeof(PCB_t);
+ while (i > 0) {
+ len += snprintf(buf+len, size-len,
+ "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+ *(ptr+5), *(ptr+6), *(ptr+7));
+ ptr += 8;
+ i -= (8 * sizeof(uint32_t));
+ off += (8 * sizeof(uint32_t));
+ }
+
+ pgpp = (struct lpfc_pgp *)&phba->slim2p->mbx.us.s3_pgp.port;
+ pring = &psli->ring[0];
+ len += snprintf(buf+len, size-len,
+ "Ring 0: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) "
+ "RSP PutInx:%d Max:%d\n",
+ pgpp->cmdGetInx, pring->numCiocb,
+ pring->next_cmdidx, pring->local_getidx, pring->flag,
+ pgpp->rspPutInx, pring->numRiocb);
+ pgpp++;
+
+ pring = &psli->ring[1];
+ len += snprintf(buf+len, size-len,
+ "Ring 1: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) "
+ "RSP PutInx:%d Max:%d\n",
+ pgpp->cmdGetInx, pring->numCiocb,
+ pring->next_cmdidx, pring->local_getidx, pring->flag,
+ pgpp->rspPutInx, pring->numRiocb);
+ pgpp++;
+
+ pring = &psli->ring[2];
+ len += snprintf(buf+len, size-len,
+ "Ring 2: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) "
+ "RSP PutInx:%d Max:%d\n",
+ pgpp->cmdGetInx, pring->numCiocb,
+ pring->next_cmdidx, pring->local_getidx, pring->flag,
+ pgpp->rspPutInx, pring->numRiocb);
+ pgpp++;
+
+ pring = &psli->ring[3];
+ len += snprintf(buf+len, size-len,
+ "Ring 3: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) "
+ "RSP PutInx:%d Max:%d\n",
+ pgpp->cmdGetInx, pring->numCiocb,
+ pring->next_cmdidx, pring->local_getidx, pring->flag,
+ pgpp->rspPutInx, pring->numRiocb);
+
+
+ ptr = (uint32_t *)&phba->slim2p->mbx.us.s3_pgp.hbq_get;
+ word0 = readl(phba->HAregaddr);
+ word1 = readl(phba->CAregaddr);
+ word2 = readl(phba->HSregaddr);
+ word3 = readl(phba->HCregaddr);
+ len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x HC:%08x\n",
+ word0, word1, word2, word3);
+ spin_unlock_irq(&phba->hbalock);
+ return len;
+}
+
+static int
lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
{
int len = 0;
@@ -204,7 +449,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
len += snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ",
ndlp->nlp_rpi, ndlp->nlp_flag);
if (!ndlp->nlp_type)
- len += snprintf(buf+len, size-len, "UNKNOWN_TYPE");
+ len += snprintf(buf+len, size-len, "UNKNOWN_TYPE ");
if (ndlp->nlp_type & NLP_FC_NODE)
len += snprintf(buf+len, size-len, "FC_NODE ");
if (ndlp->nlp_type & NLP_FABRIC)
@@ -213,7 +458,9 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
ndlp->nlp_sid);
if (ndlp->nlp_type & NLP_FCP_INITIATOR)
- len += snprintf(buf+len, size-len, "FCP_INITIATOR");
+ len += snprintf(buf+len, size-len, "FCP_INITIATOR ");
+ len += snprintf(buf+len, size-len, "refcnt:%x",
+ atomic_read(&ndlp->kref.refcount));
len += snprintf(buf+len, size-len, "\n");
}
spin_unlock_irq(shost->host_lock);
@@ -227,7 +474,7 @@ lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
uint32_t data1, uint32_t data2, uint32_t data3)
{
#ifdef CONFIG_LPFC_DEBUG_FS
- struct lpfc_disc_trc *dtp;
+ struct lpfc_debugfs_trc *dtp;
int index;
if (!(lpfc_debugfs_mask_disc_trc & mask))
@@ -244,7 +491,32 @@ lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
dtp->data1 = data1;
dtp->data2 = data2;
dtp->data3 = data3;
- dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_disc_trc_cnt);
+ dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
+ dtp->jif = jiffies;
+#endif
+ return;
+}
+
+inline void
+lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt,
+ uint32_t data1, uint32_t data2, uint32_t data3)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_debugfs_trc *dtp;
+ int index;
+
+ if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc ||
+ !phba || !phba->slow_ring_trc)
+ return;
+
+ index = atomic_inc_return(&phba->slow_ring_trc_cnt) &
+ (lpfc_debugfs_max_slow_ring_trc - 1);
+ dtp = phba->slow_ring_trc + index;
+ dtp->fmt = fmt;
+ dtp->data1 = data1;
+ dtp->data2 = data2;
+ dtp->data3 = data3;
+ dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
dtp->jif = jiffies;
#endif
return;
@@ -269,7 +541,7 @@ lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
goto out;
/* Round to page boundry */
- size = (lpfc_debugfs_max_disc_trc * LPFC_DISC_TRC_ENTRY_SIZE);
+ size = (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
size = PAGE_ALIGN(size);
debug->buffer = kmalloc(size, GFP_KERNEL);
@@ -287,6 +559,95 @@ out:
}
static int
+lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_hba *phba = inode->i_private;
+ struct lpfc_debug *debug;
+ int size;
+ int rc = -ENOMEM;
+
+ if (!lpfc_debugfs_max_slow_ring_trc) {
+ rc = -ENOSPC;
+ goto out;
+ }
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ size = (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
+ size = PAGE_ALIGN(size);
+
+ debug->buffer = kmalloc(size, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_hba *phba = inode->i_private;
+ struct lpfc_debug *debug;
+ int rc = -ENOMEM;
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer,
+ LPFC_HBQINFO_SIZE);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_hba *phba = inode->i_private;
+ struct lpfc_debug *debug;
+ int rc = -ENOMEM;
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
+ LPFC_DUMPSLIM_SIZE);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
{
struct lpfc_vport *vport = inode->i_private;
@@ -372,6 +733,33 @@ static struct file_operations lpfc_debugfs_op_nodelist = {
.release = lpfc_debugfs_release,
};
+#undef lpfc_debugfs_op_hbqinfo
+static struct file_operations lpfc_debugfs_op_hbqinfo = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_hbqinfo_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpslim
+static struct file_operations lpfc_debugfs_op_dumpslim = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_dumpslim_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_slow_ring_trc
+static struct file_operations lpfc_debugfs_op_slow_ring_trc = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_slow_ring_trc_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
static struct dentry *lpfc_debugfs_root = NULL;
static atomic_t lpfc_debugfs_hba_count;
#endif
@@ -387,60 +775,146 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
if (!lpfc_debugfs_enable)
return;
- if (lpfc_debugfs_max_disc_trc) {
- num = lpfc_debugfs_max_disc_trc - 1;
- if (num & lpfc_debugfs_max_disc_trc) {
- /* Change to be a power of 2 */
- num = lpfc_debugfs_max_disc_trc;
- i = 0;
- while (num > 1) {
- num = num >> 1;
- i++;
- }
- lpfc_debugfs_max_disc_trc = (1 << i);
- printk(KERN_ERR
- "lpfc_debugfs_max_disc_trc changed to %d\n",
- lpfc_debugfs_max_disc_trc);
- }
- }
-
+ /* Setup lpfc root directory */
if (!lpfc_debugfs_root) {
lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
atomic_set(&lpfc_debugfs_hba_count, 0);
- if (!lpfc_debugfs_root)
+ if (!lpfc_debugfs_root) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs root\n");
goto debug_failed;
+ }
}
+ if (!lpfc_debugfs_start_time)
+ lpfc_debugfs_start_time = jiffies;
+ /* Setup lpfcX directory for specific HBA */
snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
if (!phba->hba_debugfs_root) {
phba->hba_debugfs_root =
debugfs_create_dir(name, lpfc_debugfs_root);
- if (!phba->hba_debugfs_root)
+ if (!phba->hba_debugfs_root) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs hba\n");
goto debug_failed;
+ }
atomic_inc(&lpfc_debugfs_hba_count);
atomic_set(&phba->debugfs_vport_count, 0);
+
+ /* Setup hbqinfo */
+ snprintf(name, sizeof(name), "hbqinfo");
+ phba->debug_hbqinfo =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ phba->hba_debugfs_root,
+ phba, &lpfc_debugfs_op_hbqinfo);
+ if (!phba->debug_hbqinfo) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs hbqinfo\n");
+ goto debug_failed;
+ }
+
+ /* Setup dumpslim */
+ snprintf(name, sizeof(name), "dumpslim");
+ phba->debug_dumpslim =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ phba->hba_debugfs_root,
+ phba, &lpfc_debugfs_op_dumpslim);
+ if (!phba->debug_dumpslim) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs dumpslim\n");
+ goto debug_failed;
+ }
+
+ /* Setup slow ring trace */
+ if (lpfc_debugfs_max_slow_ring_trc) {
+ num = lpfc_debugfs_max_slow_ring_trc - 1;
+ if (num & lpfc_debugfs_max_slow_ring_trc) {
+ /* Change to be a power of 2 */
+ num = lpfc_debugfs_max_slow_ring_trc;
+ i = 0;
+ while (num > 1) {
+ num = num >> 1;
+ i++;
+ }
+ lpfc_debugfs_max_slow_ring_trc = (1 << i);
+ printk(KERN_ERR
+ "lpfc_debugfs_max_disc_trc changed to "
+ "%d\n", lpfc_debugfs_max_disc_trc);
+ }
+ }
+
+
+ snprintf(name, sizeof(name), "slow_ring_trace");
+ phba->debug_slow_ring_trc =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ phba->hba_debugfs_root,
+ phba, &lpfc_debugfs_op_slow_ring_trc);
+ if (!phba->debug_slow_ring_trc) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs "
+ "slow_ring_trace\n");
+ goto debug_failed;
+ }
+ if (!phba->slow_ring_trc) {
+ phba->slow_ring_trc = kmalloc(
+ (sizeof(struct lpfc_debugfs_trc) *
+ lpfc_debugfs_max_slow_ring_trc),
+ GFP_KERNEL);
+ if (!phba->slow_ring_trc) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs "
+ "slow_ring buffer\n");
+ goto debug_failed;
+ }
+ atomic_set(&phba->slow_ring_trc_cnt, 0);
+ memset(phba->slow_ring_trc, 0,
+ (sizeof(struct lpfc_debugfs_trc) *
+ lpfc_debugfs_max_slow_ring_trc));
+ }
}
snprintf(name, sizeof(name), "vport%d", vport->vpi);
if (!vport->vport_debugfs_root) {
vport->vport_debugfs_root =
debugfs_create_dir(name, phba->hba_debugfs_root);
- if (!vport->vport_debugfs_root)
+ if (!vport->vport_debugfs_root) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cant create debugfs");
goto debug_failed;
+ }
atomic_inc(&phba->debugfs_vport_count);
}
- if (!lpfc_debugfs_start_time)
- lpfc_debugfs_start_time = jiffies;
+ if (lpfc_debugfs_max_disc_trc) {
+ num = lpfc_debugfs_max_disc_trc - 1;
+ if (num & lpfc_debugfs_max_disc_trc) {
+ /* Change to be a power of 2 */
+ num = lpfc_debugfs_max_disc_trc;
+ i = 0;
+ while (num > 1) {
+ num = num >> 1;
+ i++;
+ }
+ lpfc_debugfs_max_disc_trc = (1 << i);
+ printk(KERN_ERR
+ "lpfc_debugfs_max_disc_trc changed to %d\n",
+ lpfc_debugfs_max_disc_trc);
+ }
+ }
vport->disc_trc = kmalloc(
- (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc),
+ (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
GFP_KERNEL);
- if (!vport->disc_trc)
+ if (!vport->disc_trc) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs disc trace "
+ "buffer\n");
goto debug_failed;
+ }
+ atomic_set(&vport->disc_trc_cnt, 0);
memset(vport->disc_trc, 0,
- (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc));
+ (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc));
snprintf(name, sizeof(name), "discovery_trace");
vport->debug_disc_trc =
@@ -448,9 +922,9 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_disc_trc);
if (!vport->debug_disc_trc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0409 Cannot create debugfs",
- phba->brd_no);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cannot create debugfs "
+ "discovery_trace\n");
goto debug_failed;
}
snprintf(name, sizeof(name), "nodelist");
@@ -459,9 +933,8 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
vport->vport_debugfs_root,
vport, &lpfc_debugfs_op_nodelist);
if (!vport->debug_nodelist) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0409 Cannot create debugfs",
- phba->brd_no);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0409 Cant create debugfs nodelist");
goto debug_failed;
}
debug_failed:
@@ -488,21 +961,45 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
debugfs_remove(vport->debug_nodelist); /* nodelist */
vport->debug_nodelist = NULL;
}
+
if (vport->vport_debugfs_root) {
debugfs_remove(vport->vport_debugfs_root); /* vportX */
vport->vport_debugfs_root = NULL;
atomic_dec(&phba->debugfs_vport_count);
}
if (atomic_read(&phba->debugfs_vport_count) == 0) {
- debugfs_remove(vport->phba->hba_debugfs_root); /* lpfcX */
- vport->phba->hba_debugfs_root = NULL;
- atomic_dec(&lpfc_debugfs_hba_count);
+
+ if (phba->debug_hbqinfo) {
+ debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
+ phba->debug_hbqinfo = NULL;
+ }
+ if (phba->debug_dumpslim) {
+ debugfs_remove(phba->debug_dumpslim); /* dumpslim */
+ phba->debug_dumpslim = NULL;
+ }
+ if (phba->slow_ring_trc) {
+ kfree(phba->slow_ring_trc);
+ phba->slow_ring_trc = NULL;
+ }
+ if (phba->debug_slow_ring_trc) {
+ /* slow_ring_trace */
+ debugfs_remove(phba->debug_slow_ring_trc);
+ phba->debug_slow_ring_trc = NULL;
+ }
+
+ if (phba->hba_debugfs_root) {
+ debugfs_remove(phba->hba_debugfs_root); /* lpfcX */
+ phba->hba_debugfs_root = NULL;
+ atomic_dec(&lpfc_debugfs_hba_count);
+ }
+
if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
debugfs_remove(lpfc_debugfs_root); /* lpfc */
lpfc_debugfs_root = NULL;
}
}
#endif
+ return;
}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index fffb678426a4..31e86a55391d 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -22,7 +22,7 @@
#define _H_LPFC_DEBUG_FS
#ifdef CONFIG_LPFC_DEBUG_FS
-struct lpfc_disc_trc {
+struct lpfc_debugfs_trc {
char *fmt;
uint32_t data1;
uint32_t data2;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 33fbc1666946..8085900635d4 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -63,10 +63,10 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
return 0;
/* Pending Link Event during Discovery */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0237 Pending Link Event during "
- "Discovery: State x%x\n",
- phba->brd_no, vport->vpi, phba->pport->port_state);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0237 Pending Link Event during "
+ "Discovery: State x%x\n",
+ phba->pport->port_state);
/* CLEAR_LA should re-enable link attention events and
* we should then imediately take a LATT event. The
@@ -196,9 +196,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
bpl->tus.w = le32_to_cpu(bpl->tus.w);
}
- /* Save for completion so we can release these resources */
- if (elscmd != ELS_CMD_LS_RJT)
- elsiocb->context1 = lpfc_nlp_get(ndlp);
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
elsiocb->context2 = pcmd;
elsiocb->context3 = pbuflist;
elsiocb->retry = retry;
@@ -208,23 +206,21 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
if (prsp) {
list_add(&prsp->list, &pcmd->list);
}
-
if (expectRsp) {
/* Xmit ELS command <elsCmd> to remote NPORT <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0116 Xmit ELS command x%x to remote "
- "NPORT x%x I/O tag: x%x, port state: x%x\n",
- phba->brd_no, vport->vpi, elscmd, did,
- elsiocb->iotag, vport->port_state);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0116 Xmit ELS command x%x to remote "
+ "NPORT x%x I/O tag: x%x, port state: x%x\n",
+ elscmd, did, elsiocb->iotag,
+ vport->port_state);
} else {
/* Xmit ELS response <elsCmd> to remote NPORT <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0117 Xmit ELS response x%x to remote "
- "NPORT x%x I/O tag: x%x, size: x%x\n",
- phba->brd_no, vport->vpi, elscmd,
- ndlp->nlp_DID, elsiocb->iotag, cmdSize);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0117 Xmit ELS response x%x to remote "
+ "NPORT x%x I/O tag: x%x, size: x%x\n",
+ elscmd, ndlp->nlp_DID, elsiocb->iotag,
+ cmdSize);
}
-
return elsiocb;
}
@@ -285,9 +281,8 @@ fail_free_mbox:
fail:
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0249 Cannot issue Register Fabric login\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0249 Cannot issue Register Fabric login\n");
return -ENXIO;
}
@@ -340,20 +335,19 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
if (sp->cmn.response_multiple_NPort) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
- "%d:1816 FLOGI NPIV supported, "
- "response data 0x%x\n",
- phba->brd_no,
- sp->cmn.response_multiple_NPort);
+ lpfc_printf_vlog(vport, KERN_WARNING,
+ LOG_ELS | LOG_VPORT,
+ "1816 FLOGI NPIV supported, "
+ "response data 0x%x\n",
+ sp->cmn.response_multiple_NPort);
phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
-
} else {
/* Because we asked f/w for NPIV it still expects us
- to call reg_vnpid atleast for the physcial host */
- lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
- "%d:1817 Fabric does not support NPIV "
- "- configuring single port mode.\n",
- phba->brd_no);
+ to call reg_vnpid atleast for the physcial host */
+ lpfc_printf_vlog(vport, KERN_WARNING,
+ LOG_ELS | LOG_VPORT,
+ "1817 Fabric does not support NPIV "
+ "- configuring single port mode.\n");
phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
}
}
@@ -518,16 +512,15 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* alpa map would take too long otherwise.
*/
if (phba->alpa_map[0] == 0) {
- phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
+ vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
}
/* FLOGI failure */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0100 FLOGI failure Data: x%x x%x "
- "x%x\n",
- phba->brd_no, vport->vpi,
- irsp->ulpStatus, irsp->un.ulpWord[4],
- irsp->ulpTimeout);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0100 FLOGI failure Data: x%x x%x "
+ "x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout);
goto flogifail;
}
@@ -540,12 +533,11 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
sp = prsp->virt + sizeof(uint32_t);
/* FLOGI completes successfully */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0101 FLOGI completes sucessfully "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- irsp->un.ulpWord[4], sp->cmn.e_d_tov,
- sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0101 FLOGI completes sucessfully "
+ "Data: x%x x%x x%x x%x\n",
+ irsp->un.ulpWord[4], sp->cmn.e_d_tov,
+ sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
if (vport->port_state == LPFC_FLOGI) {
/*
@@ -662,8 +654,8 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba)
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0201 Abort outstanding I/O on NPort x%x\n",
- phba->brd_no, Fabric_DID);
+ "0201 Abort outstanding I/O on NPort x%x\n",
+ Fabric_DID);
pring = &phba->sli.ring[LPFC_ELS_RING];
@@ -736,18 +728,16 @@ static void
lpfc_more_plogi(struct lpfc_vport *vport)
{
int sentplogi;
- struct lpfc_hba *phba = vport->phba;
if (vport->num_disc_nodes)
vport->num_disc_nodes--;
/* Continue discovery with <num_disc_nodes> PLOGIs to go */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0232 Continue discovery with %d PLOGIs to go "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->num_disc_nodes,
- vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0232 Continue discovery with %d PLOGIs to go "
+ "Data: x%x x%x x%x\n",
+ vport->num_disc_nodes, vport->fc_plogi_cnt,
+ vport->fc_flag, vport->port_state);
/* Check to see if there are more PLOGIs to be sent */
if (vport->fc_flag & FC_NLP_MORE)
/* go thru NPR nodes and issue any remaining ELS PLOGIs */
@@ -833,11 +823,12 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
if (!ndlp) {
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0136 PLOGI completes to NPort x%x "
- "with no ndlp. Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, irsp->un.elsreq64.remoteID,
- irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpIoTag);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0136 PLOGI completes to NPort x%x "
+ "with no ndlp. Data: x%x x%x x%x\n",
+ irsp->un.elsreq64.remoteID,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpIoTag);
goto out;
}
@@ -851,13 +842,11 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
rc = 0;
/* PLOGI completes to NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0102 PLOGI completes to NPort x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi, ndlp->nlp_DID,
- irsp->ulpStatus, irsp->un.ulpWord[4],
- irsp->ulpTimeout, disc, vport->num_disc_nodes);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0102 PLOGI completes to NPort x%x "
+ "Data: x%x x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, disc, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
if (lpfc_els_chk_latt(vport)) {
spin_lock_irq(shost->host_lock);
@@ -881,17 +870,14 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
goto out;
}
-
/* PLOGI failed */
if (ndlp->nlp_DID == NameServer_DID) {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0250 Nameserver login error: "
- "0x%x / 0x%x\n",
- phba->brd_no, vport->vpi,
- irsp->ulpStatus, irsp->un.ulpWord[4]);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0250 Nameserver login error: "
+ "0x%x / 0x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
}
-
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
if (lpfc_error_lost_link(irsp)) {
rc = NLP_STE_FREED_NODE;
@@ -1017,14 +1003,12 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"PRLI cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4],
ndlp->nlp_DID);
-
/* PRLI completes to NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0103 PRLI completes to NPort x%x "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi, ndlp->nlp_DID,
- irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
- vport->num_disc_nodes);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0103 PRLI completes to NPort x%x "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, vport->num_disc_nodes);
vport->fc_prli_sent--;
/* Check to see if link went down during discovery */
@@ -1129,18 +1113,15 @@ static void
lpfc_more_adisc(struct lpfc_vport *vport)
{
int sentadisc;
- struct lpfc_hba *phba = vport->phba;
if (vport->num_disc_nodes)
vport->num_disc_nodes--;
-
/* Continue discovery with <num_disc_nodes> ADISCs to go */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0210 Continue discovery with %d ADISCs to go "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->num_disc_nodes,
- vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0210 Continue discovery with %d ADISCs to go "
+ "Data: x%x x%x x%x\n",
+ vport->num_disc_nodes, vport->fc_adisc_cnt,
+ vport->fc_flag, vport->port_state);
/* Check to see if there are more ADISCs to be sent */
if (vport->fc_flag & FC_NLP_MORE) {
lpfc_set_disctmo(vport);
@@ -1206,15 +1187,12 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
spin_unlock_irq(shost->host_lock);
-
/* ADISC completes to NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0104 ADISC completes to NPort x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi, ndlp->nlp_DID,
- irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
- disc, vport->num_disc_nodes);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0104 ADISC completes to NPort x%x "
+ "Data: x%x x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, disc, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
if (lpfc_els_chk_latt(vport)) {
spin_lock_irq(shost->host_lock);
@@ -1374,15 +1352,12 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"LOGO cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4],
ndlp->nlp_DID);
-
/* LOGO completes to NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0105 LOGO completes to NPort x%x "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi, ndlp->nlp_DID,
- irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
- vport->num_disc_nodes);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0105 LOGO completes to NPort x%x "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
if (lpfc_els_chk_latt(vport))
goto out;
@@ -1488,15 +1463,11 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"ELS cmd cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->un.elsreq64.remoteID);
-
/* ELS cmd tag <ulpIoTag> completes */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0106 ELS cmd tag x%x completes Data: x%x x%x "
- "x%x\n",
- phba->brd_no, vport->vpi,
- irsp->ulpIoTag, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
+ irsp->ulpIoTag, irsp->ulpStatus,
+ irsp->un.ulpWord[4], irsp->ulpTimeout);
/* Check to see if link went down during discovery */
lpfc_els_chk_latt(vport);
lpfc_els_free_iocb(phba, cmdiocb);
@@ -1831,13 +1802,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
case IOERR_ILLEGAL_COMMAND:
if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
(cmd == ELS_CMD_FDISC)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0124 FDISC failed (3/6) retrying...\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0124 FDISC failed (3/6) "
+ "retrying...\n");
lpfc_mbx_unreg_vpi(vport);
retry = 1;
- /* Always retry for this case */
- cmdiocb->retry = 0;
+ /* FDISC retry policy */
+ maxretry = 48;
+ if (cmdiocb->retry >= 32)
+ delay = 1000;
}
break;
@@ -1898,10 +1871,10 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
(cmd == ELS_CMD_FDISC) &&
(stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0125 FDISC Failed (x%x)."
- " Fabric out of resources\n",
- phba->brd_no, vport->vpi, stat.un.lsRjtError);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0125 FDISC Failed (x%x). "
+ "Fabric out of resources\n",
+ stat.un.lsRjtError);
lpfc_vport_set_state(vport,
FC_VPORT_NO_FABRIC_RSCS);
}
@@ -1913,8 +1886,10 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
delay = 1000;
maxretry = 48;
} else if (cmd == ELS_CMD_FDISC) {
- /* Always retry for this case */
- cmdiocb->retry = 0;
+ /* FDISC retry policy */
+ maxretry = 48;
+ if (cmdiocb->retry >= 32)
+ delay = 1000;
}
retry = 1;
break;
@@ -1926,10 +1901,10 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
(stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
) {
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0123 FDISC Failed (x%x)."
- " Fabric Detected Bad WWN\n",
- phba->brd_no, vport->vpi, stat.un.lsRjtError);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0123 FDISC Failed (x%x). "
+ "Fabric Detected Bad WWN\n",
+ stat.un.lsRjtError);
lpfc_vport_set_state(vport,
FC_VPORT_FABRIC_REJ_WWN);
}
@@ -1959,11 +1934,10 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (retry) {
/* Retry ELS command <elsCmd> to remote NPORT <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0107 Retry ELS command x%x to remote "
- "NPORT x%x Data: x%x x%x\n",
- phba->brd_no, vport->vpi,
- cmd, did, cmdiocb->retry, delay);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0107 Retry ELS command x%x to remote "
+ "NPORT x%x Data: x%x x%x\n",
+ cmd, did, cmdiocb->retry, delay);
if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
@@ -2031,14 +2005,12 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
return 1;
}
}
-
/* No retry ELS command <elsCmd> to remote NPORT <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0108 No retry ELS command x%x to remote "
- "NPORT x%x Data: x%x\n",
- phba->brd_no, vport->vpi,
- cmd, did, cmdiocb->retry);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0108 No retry ELS command x%x to remote "
+ "NPORT x%x Retried:%d Error:x%x/%x\n",
+ cmd, did, cmdiocb->retry, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
return 0;
}
@@ -2087,14 +2059,12 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
"ACC LOGO cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
-
/* ACC to LOGO completes to NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0109 ACC to LOGO completes to NPort x%x "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0109 ACC to LOGO completes to NPort x%x "
+ "Data: x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
switch (ndlp->nlp_state) {
case NLP_STE_UNUSED_NODE: /* node is just allocated */
lpfc_drop_node(vport, ndlp);
@@ -2153,20 +2123,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
- "ACC cmpl: status:x%x/x%x did:x%x",
+ "ELS rsp cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4],
- irsp->un.rcvels.remoteID);
-
+ cmdiocb->iocb.un.elsreq64.remoteID);
/* ELS response tag <ulpIoTag> completes */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0110 ELS response tag x%x completes "
- "Data: x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
- rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
- ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
- ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0110 ELS response tag x%x completes "
+ "Data: x%x x%x x%x x%x x%x x%x x%x\n",
+ cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
+ rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
if (mbox) {
if ((rspiocb->iocb.ulpStatus == 0)
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
@@ -2219,7 +2186,7 @@ out:
int
lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
- LPFC_MBOXQ_t *mbox, uint8_t newnode)
+ LPFC_MBOXQ_t *mbox)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
@@ -2305,20 +2272,13 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
default:
return 1;
}
-
- if (newnode) {
- lpfc_nlp_put(ndlp);
- elsiocb->context1 = NULL;
- }
-
/* Xmit ELS ACC response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
- "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
- phba->brd_no, vport->vpi, elsiocb->iotag,
- elsiocb->iocb.ulpContext, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+ "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
if (ndlp->nlp_flag & NLP_LOGO_ACC) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
@@ -2370,20 +2330,17 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
pcmd += sizeof(uint32_t);
*((uint32_t *) (pcmd)) = rejectError;
- if (mbox) {
+ if (mbox)
elsiocb->context_un.mbox = mbox;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- }
/* Xmit ELS RJT <err> response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0129 Xmit ELS RJT x%x response tag x%x "
- "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
- "rpi x%x\n",
- phba->brd_no, vport->vpi, rejectError, elsiocb->iotag,
- elsiocb->iocb.ulpContext, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0129 Xmit ELS RJT x%x response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ rejectError, elsiocb->iotag,
+ elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+ ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
"Issue LS_RJT: did:x%x flg:x%x err:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
@@ -2391,6 +2348,15 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
phba->fc_stat.elsXmitLSRJT++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+
+ /* If the node is in the UNUSED state, and we are sending
+ * a reject, we are done with it. Release driver reference
+ * count here. The outstanding els will release its reference on
+ * completion and the node can be freed then.
+ */
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ lpfc_nlp_put(ndlp);
+
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2423,13 +2389,12 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
icmd->ulpContext = oldcmd->ulpContext; /* Xri */
/* Xmit ADISC ACC response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0130 Xmit ADISC ACC response iotag x%x xri: "
- "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
- phba->brd_no, vport->vpi, elsiocb->iotag,
- elsiocb->iocb.ulpContext, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0130 Xmit ADISC ACC response iotag x%x xri: "
+ "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2483,15 +2448,13 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
icmd->ulpContext = oldcmd->ulpContext; /* Xri */
-
/* Xmit PRLI ACC response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0131 Xmit PRLI ACC response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, vport->vpi, elsiocb->iotag,
- elsiocb->iocb.ulpContext, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0131 Xmit PRLI ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
@@ -2565,16 +2528,11 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
icmd->ulpContext = oldcmd->ulpContext; /* Xri */
-
/* Xmit RNID ACC response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0132 Xmit RNID ACC response tag x%x "
- "xri x%x\n",
- phba->brd_no, vport->vpi, elsiocb->iotag,
- elsiocb->iocb.ulpContext);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0132 Xmit RNID ACC response tag x%x xri x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
-
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
@@ -2641,7 +2599,7 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport)
sentadisc++;
vport->num_disc_nodes++;
if (vport->num_disc_nodes >=
- vport->phba->cfg_discovery_threads) {
+ vport->cfg_discovery_threads) {
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_NLP_MORE;
spin_unlock_irq(shost->host_lock);
@@ -2676,7 +2634,7 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
sentplogi++;
vport->num_disc_nodes++;
if (vport->num_disc_nodes >=
- vport->phba->cfg_discovery_threads) {
+ vport->cfg_discovery_threads) {
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_NLP_MORE;
spin_unlock_irq(shost->host_lock);
@@ -2717,7 +2675,6 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
D_ID rscn_did;
uint32_t *lp;
uint32_t payload_len, i;
- struct lpfc_hba *phba = vport->phba;
ns_did.un.word = did;
@@ -2752,12 +2709,10 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
break;
default:
/* Unknown Identifier in RSCN node */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0217 Unknown "
- "Identifier in RSCN payload "
- "Data: x%x\n",
- phba->brd_no, vport->vpi,
- rscn_did.un.word);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0217 Unknown Identifier in "
+ "RSCN payload Data: x%x\n",
+ rscn_did.un.word);
case 3: /* Whole Fabric effected */
return did;
}
@@ -2796,12 +2751,11 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport)
static int
lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- struct lpfc_nodelist *ndlp, uint8_t newnode)
+ struct lpfc_nodelist *ndlp)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
- struct lpfc_vport *next_vport;
uint32_t *lp, *datap;
IOCB_t *icmd;
uint32_t payload_len, length, nportid, *cmd;
@@ -2815,13 +2769,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
payload_len -= sizeof(uint32_t); /* take off word 0 */
-
/* RSCN received */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0214 RSCN received Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
- *lp, rscn_cnt);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0214 RSCN received Data: x%x x%x x%x x%x\n",
+ vport->fc_flag, payload_len, *lp, rscn_cnt);
for (i = 0; i < payload_len/sizeof(uint32_t); i++)
fc_host_post_event(shost, fc_get_event_number(),
FCH_EVT_RSCN, lp[i]);
@@ -2834,8 +2785,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
"RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
- newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
return 0;
}
@@ -2843,7 +2793,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
* just ACC and ignore it.
*/
if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
- !(phba->cfg_peer_port_login)) {
+ !(vport->cfg_peer_port_login)) {
i = payload_len;
datap = lp;
while (i > 0) {
@@ -2851,28 +2801,23 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
nportid = ((be32_to_cpu(nportid)) & Mask_DID);
i -= sizeof(uint32_t);
rscn_id++;
- list_for_each_entry(next_vport, &phba->port_list,
- listentry) {
- if (nportid == next_vport->fc_myDID) {
- hba_id++;
- break;
- }
- }
+ if (lpfc_find_vport_by_did(phba, nportid))
+ hba_id++;
}
if (rscn_id == hba_id) {
/* ALL NPortIDs in RSCN are on HBA */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0214 Ignore RSCN Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
- *lp, rscn_cnt);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0214 Ignore RSCN "
+ "Data: x%x x%x x%x x%x\n",
+ vport->fc_flag, payload_len,
+ *lp, rscn_cnt);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
ndlp->nlp_DID, vport->port_state,
ndlp->nlp_flag);
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
- ndlp, NULL, newnode);
+ ndlp, NULL);
return 0;
}
}
@@ -2911,27 +2856,24 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
}
/* Deferred RSCN */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0235 Deferred RSCN "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- vport->fc_rscn_id_cnt, vport->fc_flag,
- vport->port_state);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0235 Deferred RSCN "
+ "Data: x%x x%x x%x\n",
+ vport->fc_rscn_id_cnt, vport->fc_flag,
+ vport->port_state);
} else {
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_RSCN_DISCOVERY;
spin_unlock_irq(shost->host_lock);
/* ReDiscovery RSCN */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0234 ReDiscovery RSCN "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- vport->fc_rscn_id_cnt, vport->fc_flag,
- vport->port_state);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0234 ReDiscovery RSCN "
+ "Data: x%x x%x x%x\n",
+ vport->fc_rscn_id_cnt, vport->fc_flag,
+ vport->port_state);
}
/* Send back ACC */
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
- newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
/* send RECOVERY event for ALL nodes that match RSCN payload */
lpfc_rscn_recovery_check(vport);
@@ -2956,7 +2898,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
lpfc_set_disctmo(vport);
/* Send back ACC */
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
/* send RECOVERY event for ALL nodes that match RSCN payload */
lpfc_rscn_recovery_check(vport);
@@ -2980,11 +2922,10 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
lpfc_set_disctmo(vport);
/* RSCN processed */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0215 RSCN processed Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- vport->fc_flag, 0, vport->fc_rscn_id_cnt,
- vport->port_state);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0215 RSCN processed Data: x%x x%x x%x x%x\n",
+ vport->fc_flag, 0, vport->fc_rscn_id_cnt,
+ vport->port_state);
/* To process RSCN, first compare RSCN data with NameServer */
vport->fc_ns_retry = 0;
@@ -3026,7 +2967,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
static int
lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
- struct lpfc_nodelist *ndlp, uint8_t newnode)
+ struct lpfc_nodelist *ndlp)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
@@ -3052,10 +2993,10 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
/* An FLOGI ELS command <elsCmd> was received from DID <did> in
Loop Mode */
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0113 An FLOGI ELS command x%x was "
- "received from DID x%x in Loop Mode\n",
- phba->brd_no, vport->vpi, cmd, did);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0113 An FLOGI ELS command x%x was "
+ "received from DID x%x in Loop Mode\n",
+ cmd, did);
return 1;
}
@@ -3109,7 +3050,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
}
/* Send back ACC */
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
return 0;
}
@@ -3226,16 +3167,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
-
/* Xmit ELS RPS ACC response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0118 Xmit ELS RPS ACC response tag x%x "
- "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
- "rpi x%x\n",
- phba->brd_no, ndlp->vport->vpi, elsiocb->iotag,
- elsiocb->iocb.ulpContext, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+ "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
@@ -3337,21 +3275,16 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
sizeof(struct lpfc_name));
-
memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
-
-
/* Xmit ELS RPL ACC response tag <ulpIoTag> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0120 Xmit ELS RPL ACC response tag x%x "
- "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
- "rpi x%x\n",
- phba->brd_no, vport->vpi, elsiocb->iotag,
- elsiocb->iocb.ulpContext, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0120 Xmit ELS RPL ACC response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
-
phba->fc_stat.elsXmitACC++;
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
@@ -3404,7 +3337,6 @@ static int
lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp)
{
- struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
@@ -3418,12 +3350,9 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
cmd = *lp++;
fp = (FARP *) lp;
-
/* FARP-REQ received from DID <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0601 FARP-REQ received from DID x%x\n",
- phba->brd_no, vport->vpi, did);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0601 FARP-REQ received from DID x%x\n", did);
/* We will only support match on WWPN or WWNN */
if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
return 0;
@@ -3471,7 +3400,6 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
uint32_t *lp;
IOCB_t *icmd;
uint32_t cmd, did;
- struct lpfc_hba *phba = vport->phba;
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
@@ -3480,11 +3408,10 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
cmd = *lp++;
/* FARP-RSP received from DID <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0600 FARP-RSP received from DID x%x\n",
- phba->brd_no, vport->vpi, did);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0600 FARP-RSP received from DID x%x\n", did);
/* ACCEPT the Farp resp request */
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
return 0;
}
@@ -3502,10 +3429,8 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_hba *phba = vport->phba;
/* FAN received */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0265 FAN received\n",
- phba->brd_no, vport->vpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0265 FAN received\n");
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
@@ -3664,13 +3589,10 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
if (ndlp)
remote_ID = ndlp->nlp_DID;
}
-
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0127 ELS timeout Data: x%x x%x x%x "
- "x%x\n",
- phba->brd_no, vport->vpi, els_command,
- remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0127 ELS timeout Data: x%x x%x x%x "
+ "x%x\n", els_command,
+ remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
}
spin_unlock_irq(&phba->hbalock);
@@ -3741,6 +3663,50 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
return;
}
+void
+lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ IOCB_t *cmd = NULL;
+
+ lpfc_fabric_abort_hba(phba);
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
+ cmd = &piocb->iocb;
+ if (piocb->iocb_flag & LPFC_IO_LIBDFC)
+ continue;
+ /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
+ if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
+ cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
+ cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+ cmd->ulpCommand == CMD_ABORT_XRI_CN)
+ continue;
+ list_move_tail(&piocb->list, &completions);
+ pring->txq_cnt--;
+ }
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+ if (piocb->iocb_flag & LPFC_IO_LIBDFC)
+ continue;
+ lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ }
+ spin_unlock_irq(&phba->hbalock);
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ cmd = &piocb->iocb;
+ list_del_init(&piocb->list);
+ if (!piocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, piocb);
+ else {
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+ }
+ return;
+}
+
static void
lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
@@ -3801,11 +3767,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
cmd &= ELS_CMD_MASK;
}
/* ELS command <elsCmd> received from NPORT <did> */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0112 ELS command x%x received from NPORT x%x "
- "Data: x%x\n", phba->brd_no, vport->vpi, cmd, did,
- vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0112 ELS command x%x received from NPORT x%x "
+ "Data: x%x\n", cmd, did, vport->port_state);
switch (cmd) {
case ELS_CMD_PLOGI:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3829,7 +3793,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
did, vport->port_state, ndlp->nlp_flag);
phba->fc_stat.elsRcvFLOGI++;
- lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
+ lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
if (newnode)
lpfc_drop_node(vport, ndlp);
break;
@@ -3859,7 +3823,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
break;
case ELS_CMD_RSCN:
phba->fc_stat.elsRcvRSCN++;
- lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
+ lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
if (newnode)
lpfc_drop_node(vport, ndlp);
break;
@@ -3974,10 +3938,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
rjt_err = LSRJT_INVALID_CMD;
/* Unknown ELS command <elsCmd> received from NPORT <did> */
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0115 Unknown ELS command x%x "
- "received from NPORT x%x\n",
- phba->brd_no, vport->vpi, cmd, did);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0115 Unknown ELS command x%x "
+ "received from NPORT x%x\n", cmd, did);
if (newnode)
lpfc_drop_node(vport, ndlp);
break;
@@ -3990,19 +3953,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
NULL);
- if (newnode)
- lpfc_drop_node(vport, ndlp);
}
return;
dropit:
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0111 Dropping received ELS cmd "
+ "(%d):0111 Dropping received ELS cmd "
"Data: x%x x%x x%x\n",
- phba->brd_no, vport ? vport->vpi : 0xffff,
- icmd->ulpStatus, icmd->un.ulpWord[4],
- icmd->ulpTimeout);
+ vport ? vport->vpi : 0xffff, icmd->ulpStatus,
+ icmd->un.ulpWord[4], icmd->ulpTimeout);
phba->fc_stat.elsRcvDrop++;
}
@@ -4010,11 +3970,16 @@ static struct lpfc_vport *
lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
{
struct lpfc_vport *vport;
+ unsigned long flags;
+ spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
- if (vport->vpi == vpi)
+ if (vport->vpi == vpi) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return vport;
+ }
}
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return NULL;
}
@@ -4109,9 +4074,8 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
return;
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0251 NameServer login: no memory\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0251 NameServer login: no memory\n");
return;
}
lpfc_nlp_init(vport, ndlp, NameServer_DID);
@@ -4122,13 +4086,12 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0252 Cannot issue NameServer login\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0252 Cannot issue NameServer login\n");
return;
}
- if (phba->cfg_fdmi_on) {
+ if (vport->cfg_fdmi_on) {
ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
GFP_KERNEL);
if (ndlp_fdmi) {
@@ -4155,9 +4118,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_nlp_put(ndlp);
if (mb->mbxStatus) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0915 Register VPI failed: 0x%x\n",
- phba->brd_no, vport->vpi, mb->mbxStatus);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0915 Register VPI failed: 0x%x\n",
+ mb->mbxStatus);
switch (mb->mbxStatus) {
case 0x11: /* unsupported feature */
@@ -4206,17 +4169,14 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0253 Register VPI: Cannot send mbox\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0253 Register VPI: Can't send mbox\n");
}
} else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0254 Register VPI: no memory\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0254 Register VPI: no memory\n");
vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
lpfc_nlp_put(ndlp);
@@ -4235,11 +4195,10 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_iocbq *piocb;
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0123 FDISC completes. x%x/x%x prevDID: x%x\n",
- phba->brd_no, vport->vpi,
- irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0123 FDISC completes. x%x/x%x prevDID: x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ vport->fc_prevDID);
/* Since all FDISCs are being single threaded, we
* must reset the discovery timer for ALL vports
* waiting to send FDISC when one completes.
@@ -4256,13 +4215,10 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Check for retry */
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
-
/* FDISC failed */
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0124 FDISC failed. (%d/%d)\n",
- phba->brd_no, vport->vpi,
- irsp->ulpStatus, irsp->un.ulpWord[4]);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0124 FDISC failed. (%d/%d)\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
@@ -4328,10 +4284,8 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ELS_CMD_FDISC);
if (!elsiocb) {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0255 Issue FDISC: no IOCB\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0255 Issue FDISC: no IOCB\n");
return 1;
}
@@ -4377,11 +4331,8 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0256 Issue FDISC: Cannot send IOCB\n",
- phba->brd_no, vport->vpi);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0256 Issue FDISC: Cannot send IOCB\n");
return 1;
}
lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index f2f4639eab59..c81c2b3228d6 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -83,10 +83,17 @@ lpfc_terminate_rport_io(struct fc_rport *rport)
ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
if (ndlp->nlp_sid != NLP_NO_SID) {
- lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ lpfc_sli_abort_iocb(ndlp->vport,
+ &phba->sli.ring[phba->sli.fcp_ring],
+ ndlp->nlp_sid, 0, LPFC_CTX_TGT);
}
+ /*
+ * A device is normally blocked for rediscovery and unblocked when
+ * devloss timeout happens. In case a vport is removed or driver
+ * unloaded before devloss timeout happens, we need to unblock here.
+ */
+ scsi_target_unblock(&rport->dev);
return;
}
@@ -194,32 +201,30 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
if (ndlp->nlp_sid != NLP_NO_SID) {
warn_on = 1;
/* flush the target */
- lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
+ ndlp->nlp_sid, 0, LPFC_CTX_TGT);
}
if (vport->load_flag & FC_UNLOADING)
warn_on = 0;
if (warn_on) {
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0203 Devloss timeout on "
- "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
- "NPort x%x Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- *name, *(name+1), *(name+2), *(name+3),
- *(name+4), *(name+5), *(name+6), *(name+7),
- ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0203 Devloss timeout on "
+ "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
+ "NPort x%x Data: x%x x%x x%x\n",
+ *name, *(name+1), *(name+2), *(name+3),
+ *(name+4), *(name+5), *(name+6), *(name+7),
+ ndlp->nlp_DID, ndlp->nlp_flag,
+ ndlp->nlp_state, ndlp->nlp_rpi);
} else {
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0204 Devloss timeout on "
- "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
- "NPort x%x Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- *name, *(name+1), *(name+2), *(name+3),
- *(name+4), *(name+5), *(name+6), *(name+7),
- ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0204 Devloss timeout on "
+ "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
+ "NPort x%x Data: x%x x%x x%x\n",
+ *name, *(name+1), *(name+2), *(name+3),
+ *(name+4), *(name+5), *(name+6), *(name+7),
+ ndlp->nlp_DID, ndlp->nlp_flag,
+ ndlp->nlp_state, ndlp->nlp_rpi);
}
if (!(vport->load_flag & FC_UNLOADING) &&
@@ -344,12 +349,14 @@ lpfc_work_list_done(struct lpfc_hba *phba)
}
-void
+static void
lpfc_work_done(struct lpfc_hba *phba)
{
struct lpfc_sli_ring *pring;
uint32_t ha_copy, status, control, work_port_events;
+ struct lpfc_vport **vports;
struct lpfc_vport *vport;
+ int i;
spin_lock_irq(&phba->hbalock);
ha_copy = phba->work_ha;
@@ -364,48 +371,41 @@ lpfc_work_done(struct lpfc_hba *phba)
if (ha_copy & HA_LATT)
lpfc_handle_latt(phba);
-
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry(vport, &phba->port_list, listentry) {
- struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
- if (!scsi_host_get(shost)) {
- continue;
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS; i++) {
+ /*
+ * We could have no vports in array if unloading, so if
+ * this happens then just use the pport
+ */
+ if (vports[i] == NULL && i == 0)
+ vport = phba->pport;
+ else
+ vport = vports[i];
+ if (vport == NULL)
+ break;
+ work_port_events = vport->work_port_events;
+ if (work_port_events & WORKER_DISC_TMO)
+ lpfc_disc_timeout_handler(vport);
+ if (work_port_events & WORKER_ELS_TMO)
+ lpfc_els_timeout_handler(vport);
+ if (work_port_events & WORKER_HB_TMO)
+ lpfc_hb_timeout_handler(phba);
+ if (work_port_events & WORKER_MBOX_TMO)
+ lpfc_mbox_timeout_handler(phba);
+ if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
+ lpfc_unblock_fabric_iocbs(phba);
+ if (work_port_events & WORKER_FDMI_TMO)
+ lpfc_fdmi_timeout_handler(vport);
+ if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
+ lpfc_ramp_down_queue_handler(phba);
+ if (work_port_events & WORKER_RAMP_UP_QUEUE)
+ lpfc_ramp_up_queue_handler(phba);
+ spin_lock_irq(&vport->work_port_lock);
+ vport->work_port_events &= ~work_port_events;
+ spin_unlock_irq(&vport->work_port_lock);
}
- spin_unlock_irq(&phba->hbalock);
- work_port_events = vport->work_port_events;
-
- if (work_port_events & WORKER_DISC_TMO)
- lpfc_disc_timeout_handler(vport);
-
- if (work_port_events & WORKER_ELS_TMO)
- lpfc_els_timeout_handler(vport);
-
- if (work_port_events & WORKER_HB_TMO)
- lpfc_hb_timeout_handler(phba);
-
- if (work_port_events & WORKER_MBOX_TMO)
- lpfc_mbox_timeout_handler(phba);
-
- if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
- lpfc_unblock_fabric_iocbs(phba);
-
- if (work_port_events & WORKER_FDMI_TMO)
- lpfc_fdmi_timeout_handler(vport);
-
- if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
- lpfc_ramp_down_queue_handler(phba);
-
- if (work_port_events & WORKER_RAMP_UP_QUEUE)
- lpfc_ramp_up_queue_handler(phba);
-
- spin_lock_irq(&vport->work_port_lock);
- vport->work_port_events &= ~work_port_events;
- spin_unlock_irq(&vport->work_port_lock);
- scsi_host_put(shost);
- spin_lock_irq(&phba->hbalock);
- }
- spin_unlock_irq(&phba->hbalock);
+ lpfc_destroy_vport_work_array(vports);
pring = &phba->sli.ring[LPFC_ELS_RING];
status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING)));
@@ -426,10 +426,19 @@ lpfc_work_done(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
control = readl(phba->HCregaddr);
if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+ lpfc_debugfs_slow_ring_trc(phba,
+ "WRK Enable ring: cntl:x%x hacopy:x%x",
+ control, ha_copy, 0);
+
control |= (HC_R0INT_ENA << LPFC_ELS_RING);
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
+ else {
+ lpfc_debugfs_slow_ring_trc(phba,
+ "WRK Ring ok: cntl:x%x hacopy:x%x",
+ control, ha_copy, 0);
+ }
spin_unlock_irq(&phba->hbalock);
}
lpfc_work_list_done(phba);
@@ -439,32 +448,22 @@ static int
check_work_wait_done(struct lpfc_hba *phba)
{
struct lpfc_vport *vport;
- struct lpfc_sli_ring *pring;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
int rc = 0;
spin_lock_irq(&phba->hbalock);
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport->work_port_events) {
rc = 1;
- goto exit;
+ break;
}
}
-
- if (phba->work_ha || (!list_empty(&phba->work_list)) ||
- kthread_should_stop()) {
- rc = 1;
- goto exit;
- }
-
- pring = &phba->sli.ring[LPFC_ELS_RING];
- if (pring->flag & LPFC_DEFERRED_RING_EVENT)
+ if (rc || phba->work_ha || (!list_empty(&phba->work_list)) ||
+ kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) {
rc = 1;
-exit:
- if (rc)
phba->work_found++;
- else
+ } else
phba->work_found = 0;
-
spin_unlock_irq(&phba->hbalock);
return rc;
}
@@ -592,7 +591,6 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
/* free any ndlp's on unused list */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
- /* free any ndlp's in unused state */
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
lpfc_drop_node(vport, ndlp);
@@ -605,8 +603,9 @@ lpfc_linkdown(struct lpfc_hba *phba)
{
struct lpfc_vport *vport = phba->pport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_vport *port_iterator;
+ struct lpfc_vport **vports;
LPFC_MBOXQ_t *mb;
+ int i;
if (phba->link_state == LPFC_LINK_DOWN) {
return 0;
@@ -617,13 +616,13 @@ lpfc_linkdown(struct lpfc_hba *phba)
phba->pport->fc_flag &= ~FC_LBIT;
}
spin_unlock_irq(&phba->hbalock);
-
- list_for_each_entry(port_iterator, &phba->port_list, listentry) {
-
- /* Issue a LINK DOWN event to all nodes */
- lpfc_linkdown_port(port_iterator);
- }
-
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ /* Issue a LINK DOWN event to all nodes */
+ lpfc_linkdown_port(vports[i]);
+ }
+ lpfc_destroy_vport_work_array(vports);
/* Clean up any firmware default rpi's */
mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mb) {
@@ -724,7 +723,8 @@ lpfc_linkup_port(struct lpfc_vport *vport)
static int
lpfc_linkup(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport;
+ struct lpfc_vport **vports;
+ int i;
phba->link_state = LPFC_LINK_UP;
@@ -732,9 +732,11 @@ lpfc_linkup(struct lpfc_hba *phba)
clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
del_timer_sync(&phba->fabric_block_timer);
- list_for_each_entry(vport, &phba->port_list, listentry) {
- lpfc_linkup_port(vport);
- }
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+ lpfc_linkup_port(vports[i]);
+ lpfc_destroy_vport_work_array(vports);
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
lpfc_issue_clear_la(phba, phba->pport);
@@ -764,12 +766,10 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Check for error */
if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {
/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0320 CLEAR_LA mbxStatus error x%x hba "
- "state x%x\n",
- phba->brd_no, vport->vpi, mb->mbxStatus,
- vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0320 CLEAR_LA mbxStatus error x%x hba "
+ "state x%x\n",
+ mb->mbxStatus, vport->port_state);
phba->link_state = LPFC_HBA_ERROR;
goto out;
}
@@ -801,10 +801,8 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
out:
/* Device Discovery completes */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0225 Device Discovery completes\n",
- phba->brd_no, vport->vpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0225 Device Discovery completes\n");
mempool_free(pmb, phba->mbox_mem_pool);
spin_lock_irq(shost->host_lock);
@@ -861,19 +859,17 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
return;
out:
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0306 CONFIG_LINK mbxStatus error x%x "
- "HBA state x%x\n",
- phba->brd_no, vport->vpi, pmb->mb.mbxStatus,
- vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0306 CONFIG_LINK mbxStatus error x%x "
+ "HBA state x%x\n",
+ pmb->mb.mbxStatus, vport->port_state);
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_linkdown(phba);
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0200 CONFIG_LINK bad hba state x%x\n",
- phba->brd_no, vport->vpi, vport->port_state);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0200 CONFIG_LINK bad hba state x%x\n",
+ vport->port_state);
lpfc_issue_clear_la(phba, vport);
return;
@@ -890,12 +886,10 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Check for error */
if (mb->mbxStatus) {
/* READ_SPARAM mbox error <mbxStatus> state <hba_state> */
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0319 READ_SPARAM mbxStatus error x%x "
- "hba state x%x>\n",
- phba->brd_no, vport->vpi, mb->mbxStatus,
- vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0319 READ_SPARAM mbxStatus error x%x "
+ "hba state x%x>\n",
+ mb->mbxStatus, vport->port_state);
lpfc_linkdown(phba);
goto out;
}
@@ -978,7 +972,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
if (i == 0) {
phba->alpa_map[0] = 0;
} else {
- if (phba->cfg_log_verbose & LOG_LINK_EVENT) {
+ if (vport->cfg_log_verbose & LOG_LINK_EVENT) {
int numalpa, j, k;
union {
uint8_t pamap[16];
@@ -1004,10 +998,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
lpfc_printf_log(phba,
KERN_WARNING,
LOG_LINK_EVENT,
- "%d:1304 Link Up Event "
+ "1304 Link Up Event "
"ALPA map Data: x%x "
"x%x x%x x%x\n",
- phba->brd_no,
un.pa.wd1, un.pa.wd2,
un.pa.wd3, un.pa.wd4);
}
@@ -1015,7 +1008,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
}
} else {
if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
- if (phba->max_vpi && phba->cfg_npiv_enable &&
+ if (phba->max_vpi && phba->cfg_enable_npiv &&
(phba->sli_rev == 3))
phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
}
@@ -1055,11 +1048,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
}
out:
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0263 Discovery Mailbox error: state: 0x%x : %p %p\n",
- phba->brd_no, vport->vpi,
- vport->port_state, sparam_mbox, cfglink_mbox);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0263 Discovery Mailbox error: state: 0x%x : %p %p\n",
+ vport->port_state, sparam_mbox, cfglink_mbox);
lpfc_issue_clear_la(phba, vport);
return;
}
@@ -1100,8 +1091,8 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Check for error */
if (mb->mbxStatus) {
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
- "%d:1307 READ_LA mbox error x%x state x%x\n",
- phba->brd_no, mb->mbxStatus, vport->port_state);
+ "1307 READ_LA mbox error x%x state x%x\n",
+ mb->mbxStatus, vport->port_state);
lpfc_mbx_issue_link_down(phba);
phba->link_state = LPFC_HBA_ERROR;
goto lpfc_mbx_cmpl_read_la_free_mbuf;
@@ -1132,26 +1123,26 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
- "%d:1306 Link Up Event in loop back mode "
- "x%x received Data: x%x x%x x%x x%x\n",
- phba->brd_no, la->eventTag, phba->fc_eventTag,
- la->granted_AL_PA, la->UlnkSpeed,
- phba->alpa_map[0]);
+ "1306 Link Up Event in loop back mode "
+ "x%x received Data: x%x x%x x%x x%x\n",
+ la->eventTag, phba->fc_eventTag,
+ la->granted_AL_PA, la->UlnkSpeed,
+ phba->alpa_map[0]);
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
- "%d:1303 Link Up Event x%x received "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, la->eventTag, phba->fc_eventTag,
- la->granted_AL_PA, la->UlnkSpeed,
- phba->alpa_map[0]);
+ "1303 Link Up Event x%x received "
+ "Data: x%x x%x x%x x%x\n",
+ la->eventTag, phba->fc_eventTag,
+ la->granted_AL_PA, la->UlnkSpeed,
+ phba->alpa_map[0]);
}
lpfc_mbx_process_link_up(phba, la);
} else {
phba->fc_stat.LinkDown++;
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
- "%d:1305 Link Down Event x%x received "
+ "1305 Link Down Event x%x received "
"Data: x%x x%x x%x\n",
- phba->brd_no, la->eventTag, phba->fc_eventTag,
+ la->eventTag, phba->fc_eventTag,
phba->pport->port_state, vport->fc_flag);
lpfc_mbx_issue_link_down(phba);
}
@@ -1199,10 +1190,9 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
case 0x0011:
case 0x0020:
case 0x9700:
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d (%d):0911 cmpl_unreg_vpi, "
- "mb status = 0x%x\n",
- phba->brd_no, vport->vpi, mb->mbxStatus);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0911 cmpl_unreg_vpi, mb status = 0x%x\n",
+ mb->mbxStatus);
break;
}
vport->unreg_vpi_cmpl = VPORT_OK;
@@ -1231,9 +1221,8 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
- "%d (%d):1800 Could not issue unreg_vpi\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ "1800 Could not issue unreg_vpi\n");
mempool_free(mbox, phba->mbox_mem_pool);
vport->unreg_vpi_cmpl = VPORT_ERROR;
}
@@ -1250,9 +1239,9 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
case 0x0011:
case 0x9601:
case 0x9602:
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d (%d):0912 cmpl_reg_vpi, mb status = 0x%x\n",
- phba->brd_no, vport->vpi, mb->mbxStatus);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0912 cmpl_reg_vpi, mb status = 0x%x\n",
+ mb->mbxStatus);
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
@@ -1289,15 +1278,15 @@ void
lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
- struct lpfc_vport *next_vport;
MAILBOX_t *mb = &pmb->mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp;
- ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct lpfc_vport **vports;
+ int i;
+ ndlp = (struct lpfc_nodelist *) pmb->context2;
pmb->context1 = NULL;
pmb->context2 = NULL;
-
if (mb->mbxStatus) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -1314,10 +1303,9 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d (%d):0258 Register Fabric login error: 0x%x\n",
- phba->brd_no, vport->vpi, mb->mbxStatus);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+ "0258 Register Fabric login error: 0x%x\n",
+ mb->mbxStatus);
return;
}
@@ -1328,21 +1316,26 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
- list_for_each_entry(next_vport, &phba->port_list, listentry) {
- if (next_vport->port_type == LPFC_PHYSICAL_PORT)
- continue;
-
- if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
- lpfc_initial_fdisc(next_vport);
- else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
- lpfc_vport_set_state(vport,
- FC_VPORT_NO_FABRIC_SUPP);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0259 No NPIV Fabric "
- "support\n",
- phba->brd_no, vport->vpi);
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0;
+ i < LPFC_MAX_VPORTS && vports[i] != NULL;
+ i++) {
+ if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+ continue;
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+ lpfc_initial_fdisc(vports[i]);
+ else if (phba->sli3_options &
+ LPFC_SLI3_NPIV_ENABLED) {
+ lpfc_vport_set_state(vports[i],
+ FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_ELS,
+ "0259 No NPIV "
+ "Fabric support\n");
+ }
}
- }
+ lpfc_destroy_vport_work_array(vports);
lpfc_do_scr_ns_plogi(phba, vport);
}
@@ -1386,9 +1379,9 @@ out:
return;
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0260 Register NameServer error: 0x%x\n",
- phba->brd_no, vport->vpi, mb->mbxStatus);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0260 Register NameServer error: 0x%x\n",
+ mb->mbxStatus);
return;
}
@@ -1598,7 +1591,7 @@ lpfc_nlp_state_name(char *buffer, size_t size, int state)
[NLP_STE_NPR_NODE] = "NPR",
};
- if (state < ARRAY_SIZE(states) && states[state])
+ if (state < NLP_STE_MAX_STATE && states[state])
strlcpy(buffer, states[state], size);
else
snprintf(buffer, size, "unknown (%d)", state);
@@ -1613,12 +1606,11 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int old_state = ndlp->nlp_state;
char name1[16], name2[16];
- lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE,
- "%d (%d):0904 NPort state transition x%06x, %s -> %s\n",
- vport->phba->brd_no, vport->vpi,
- ndlp->nlp_DID,
- lpfc_nlp_state_name(name1, sizeof(name1), old_state),
- lpfc_nlp_state_name(name2, sizeof(name2), state));
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0904 NPort state transition x%06x, %s -> %s\n",
+ ndlp->nlp_DID,
+ lpfc_nlp_state_name(name1, sizeof(name1), old_state),
+ lpfc_nlp_state_name(name2, sizeof(name2), state));
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
"node statechg did:x%x old:%d ste:%d",
@@ -1664,16 +1656,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
void
lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
- if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
- if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
- lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
- spin_lock_irq(shost->host_lock);
- list_del_init(&ndlp->nlp_listp);
- ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
- spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
lpfc_nlp_put(ndlp);
}
@@ -1710,12 +1693,12 @@ lpfc_set_disctmo(struct lpfc_vport *vport)
spin_unlock_irq(shost->host_lock);
/* Start Discovery Timer state <hba_state> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0247 Start Discovery Timer state x%x "
- "Data: x%x x%lx x%x x%x\n",
- phba->brd_no, vport->vpi, vport->port_state, tmo,
- (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
- vport->fc_adisc_cnt);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0247 Start Discovery Timer state x%x "
+ "Data: x%x x%lx x%x x%x\n",
+ vport->port_state, tmo,
+ (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
return;
}
@@ -1727,7 +1710,6 @@ int
lpfc_can_disctmo(struct lpfc_vport *vport)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_hba *phba = vport->phba;
unsigned long iflags;
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
@@ -1746,13 +1728,11 @@ lpfc_can_disctmo(struct lpfc_vport *vport)
}
/* Cancel Discovery Timer state <hba_state> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0248 Cancel Discovery Timer state x%x "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->port_state,
- vport->fc_flag, vport->fc_plogi_cnt,
- vport->fc_adisc_cnt);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0248 Cancel Discovery Timer state x%x "
+ "Data: x%x x%x x%x\n",
+ vport->port_state, vport->fc_flag,
+ vport->fc_plogi_cnt, vport->fc_adisc_cnt);
return 0;
}
@@ -1935,10 +1915,9 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
rc = lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
- "%d (%d):1815 Could not issue "
- "unreg_did (default rpis)\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ "1815 Could not issue "
+ "unreg_did (default rpis)\n");
mempool_free(mbox, phba->mbox_mem_pool);
}
}
@@ -1957,12 +1936,11 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
struct lpfc_dmabuf *mp;
/* Cleanup node for NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d (%d):0900 Cleanup node for NPort x%x "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0900 Cleanup node for NPort x%x "
+ "Data: x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_flag,
+ ndlp->nlp_state, ndlp->nlp_rpi);
lpfc_dequeue_node(vport, ndlp);
/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
@@ -2094,7 +2072,6 @@ lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
static struct lpfc_nodelist *
__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
{
- struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
uint32_t data1;
@@ -2104,20 +2081,18 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
((uint32_t) ndlp->nlp_xri << 16) |
((uint32_t) ndlp->nlp_type << 8) |
((uint32_t) ndlp->nlp_rpi & 0xff));
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d (%d):0929 FIND node DID "
- " Data: x%p x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0929 FIND node DID "
+ "Data: x%p x%x x%x x%x\n",
+ ndlp, ndlp->nlp_DID,
+ ndlp->nlp_flag, data1);
return ndlp;
}
}
/* FIND node did <did> NOT FOUND */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d (%d):0932 FIND node did x%x NOT FOUND.\n",
- phba->brd_no, vport->vpi, did);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0932 FIND node did x%x NOT FOUND.\n", did);
return NULL;
}
@@ -2208,7 +2183,7 @@ lpfc_disc_list_loopmap(struct lpfc_vport *vport)
/* If cfg_scan_down is set, start from highest
* ALPA (0xef) to lowest (0x1).
*/
- if (phba->cfg_scan_down)
+ if (vport->cfg_scan_down)
index = j;
else
index = FC_MAXLOOP - j - 1;
@@ -2309,12 +2284,11 @@ lpfc_disc_start(struct lpfc_vport *vport)
vport->num_disc_nodes = 0;
/* Start Discovery state <hba_state> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0202 Start Discovery hba state x%x "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vport->vpi, vport->port_state,
- vport->fc_flag, vport->fc_plogi_cnt,
- vport->fc_adisc_cnt);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0202 Start Discovery hba state x%x "
+ "Data: x%x x%x x%x\n",
+ vport->port_state, vport->fc_flag, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
/* First do ADISCs - if any */
num_sent = lpfc_els_disc_adisc(vport);
@@ -2532,10 +2506,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
* FAN
*/
/* FAN timeout */
- lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
- "%d (%d):0221 FAN timeout\n",
- phba->brd_no, vport->vpi);
-
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY,
+ "0221 FAN timeout\n");
/* Start discovery by sending FLOGI, clean up old rpis */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
@@ -2562,10 +2534,9 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
case LPFC_FLOGI:
/* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
/* Initial FLOGI timeout */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0222 Initial %s timeout\n",
- phba->brd_no, vport->vpi,
- vport->vpi ? "FLOGI" : "FDISC");
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0222 Initial %s timeout\n",
+ vport->vpi ? "FLOGI" : "FDISC");
/* Assume no Fabric and go on with discovery.
* Check for outstanding ELS FLOGI to abort.
@@ -2581,11 +2552,9 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
case LPFC_FABRIC_CFG_LINK:
/* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
NameServer login */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0223 Timeout while waiting for "
- "NameServer login\n",
- phba->brd_no, vport->vpi);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0223 Timeout while waiting for "
+ "NameServer login\n");
/* Next look for NameServer ndlp */
ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp)
@@ -2596,11 +2565,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
case LPFC_NS_QRY:
/* Check for wait for NameServer Rsp timeout */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0224 NameServer Query timeout "
- "Data: x%x x%x\n",
- phba->brd_no, vport->vpi,
- vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0224 NameServer Query timeout "
+ "Data: x%x x%x\n",
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
/* Try it one more time */
@@ -2627,10 +2595,9 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
/* Setup and issue mailbox INITIALIZE LINK command */
initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!initlinkmbox) {
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0206 Device Discovery "
- "completion error\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0206 Device Discovery "
+ "completion error\n");
phba->link_state = LPFC_HBA_ERROR;
break;
}
@@ -2651,9 +2618,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
case LPFC_DISC_AUTH:
/* Node Authentication timeout */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0227 Node Authentication timeout\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0227 Node Authentication timeout\n");
lpfc_disc_flush_list(vport);
/*
@@ -2670,11 +2636,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
case LPFC_VPORT_READY:
if (vport->fc_flag & FC_RSCN_MODE) {
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0231 RSCN timeout Data: x%x "
- "x%x\n",
- phba->brd_no, vport->vpi,
- vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0231 RSCN timeout Data: x%x "
+ "x%x\n",
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
/* Cleanup any outstanding ELS commands */
lpfc_els_flush_cmd(vport);
@@ -2685,20 +2650,17 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
break;
default:
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0229 Unexpected discovery timeout, "
- "vport State x%x\n",
- phba->brd_no, vport->vpi, vport->port_state);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0229 Unexpected discovery timeout, "
+ "vport State x%x\n", vport->port_state);
break;
}
switch (phba->link_state) {
case LPFC_CLEAR_LA:
/* CLEAR LA timeout */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0228 CLEAR LA timeout\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0228 CLEAR LA timeout\n");
clrlaerr = 1;
break;
@@ -2709,10 +2671,9 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
case LPFC_LINK_DOWN:
case LPFC_LINK_UP:
case LPFC_HBA_ERROR:
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0230 Unexpected timeout, hba link "
- "state x%x\n",
- phba->brd_no, vport->vpi, phba->link_state);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0230 Unexpected timeout, hba link "
+ "state x%x\n", phba->link_state);
clrlaerr = 1;
break;
@@ -2757,7 +2718,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
* fdmi-on=2 (supporting RPA/hostnmae)
*/
- if (phba->cfg_fdmi_on == 1)
+ if (vport->cfg_fdmi_on == 1)
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
else
mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
@@ -2854,32 +2815,6 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn)
}
void
-lpfc_dev_loss_delay(unsigned long ptr)
-{
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
- struct lpfc_vport *vport = ndlp->vport;
- struct lpfc_hba *phba = vport->phba;
- struct lpfc_work_evt *evtp = &ndlp->dev_loss_evt;
- unsigned long flags;
-
- evtp = &ndlp->dev_loss_evt;
-
- spin_lock_irqsave(&phba->hbalock, flags);
- if (!list_empty(&evtp->evt_listp)) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
- return;
- }
-
- evtp->evt_arg1 = ndlp;
- evtp->evt = LPFC_EVT_DEV_LOSS_DELAY;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
- if (phba->work_wait)
- lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(&phba->hbalock, flags);
- return;
-}
-
-void
lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t did)
{
@@ -2902,7 +2837,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return;
}
-void
+static void
lpfc_nlp_release(struct kref *kref)
{
struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index c2fb59f595f3..451accd5564b 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -150,7 +150,11 @@ struct lpfc_sli_ct_request {
struct gff_acc {
uint8_t fbits[128];
} gff_acc;
+#ifdef __BIG_ENDIAN_BITFIELD
+#define FCP_TYPE_FEATURE_OFFSET 7
+#else /* __LITTLE_ENDIAN_BITFIELD */
#define FCP_TYPE_FEATURE_OFFSET 4
+#endif
struct rff {
uint32_t PortId;
uint8_t reserved[2];
@@ -805,7 +809,7 @@ typedef struct _RNID { /* Structure is in Big Endian format */
} un;
} RNID;
-typedef struct _RPS { /* Structure is in Big Endian format */
+typedef struct _RPS { /* Structure is in Big Endian format */
union {
uint32_t portNum;
struct lpfc_name portName;
@@ -823,7 +827,7 @@ typedef struct _RPS_RSP { /* Structure is in Big Endian format */
uint32_t crcCnt;
} RPS_RSP;
-typedef struct _RPL { /* Structure is in Big Endian format */
+typedef struct _RPL { /* Structure is in Big Endian format */
uint32_t maxsize;
uint32_t index;
} RPL;
@@ -834,7 +838,7 @@ typedef struct _PORT_NUM_BLK {
struct lpfc_name portName;
} PORT_NUM_BLK;
-typedef struct _RPL_RSP { /* Structure is in Big Endian format */
+typedef struct _RPL_RSP { /* Structure is in Big Endian format */
uint32_t listLen;
uint32_t index;
PORT_NUM_BLK port_num_blk;
@@ -2613,8 +2617,8 @@ typedef union {
LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */
READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */
WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */
- BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */
- INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */
+ BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */
+ INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */
DOWN_LINK_VAR varDwnLnk; /* cmd = 6 (DOWN_LINK) */
CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */
PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index f81f85ee190f..414350ab584e 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -53,8 +53,6 @@ static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
static DEFINE_IDR(lpfc_hba_index);
-
-
/************************************************************************/
/* */
/* lpfc_config_port_prep */
@@ -107,10 +105,9 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0324 Config Port initialization "
+ "0324 Config Port initialization "
"error, mbxCmd x%x READ_NVPARM, "
"mbxStatus x%x\n",
- phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
mempool_free(pmb, phba->mbox_mem_pool);
return -ERESTART;
@@ -128,9 +125,8 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0439 Adapter failed to init, mbxCmd x%x "
+ "0439 Adapter failed to init, mbxCmd x%x "
"READ_REV, mbxStatus x%x\n",
- phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
mempool_free( pmb, phba->mbox_mem_pool);
return -ERESTART;
@@ -144,9 +140,8 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
if (mb->un.varRdRev.rr == 0) {
vp->rev.rBit = 0;
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0440 Adapter failed to init, READ_REV has "
- "missing revision information.\n",
- phba->brd_no);
+ "0440 Adapter failed to init, READ_REV has "
+ "missing revision information.\n");
mempool_free(pmb, phba->mbox_mem_pool);
return -ERESTART;
}
@@ -197,9 +192,8 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0441 VPD not present on adapter, "
+ "0441 VPD not present on adapter, "
"mbxCmd x%x DUMP VPD, mbxStatus x%x\n",
- phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
mb->un.varDmp.word_cnt = 0;
}
@@ -253,9 +247,8 @@ lpfc_config_port_post(struct lpfc_hba *phba)
pmb->vport = vport;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0448 Adapter failed init, mbxCmd x%x "
+ "0448 Adapter failed init, mbxCmd x%x "
"READ_SPARM mbxStatus x%x\n",
- phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
phba->link_state = LPFC_HBA_ERROR;
mp = (struct lpfc_dmabuf *) pmb->context1;
@@ -312,9 +305,8 @@ lpfc_config_port_post(struct lpfc_hba *phba)
pmb->vport = vport;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0453 Adapter failed to init, mbxCmd x%x "
+ "0453 Adapter failed to init, mbxCmd x%x "
"READ_CONFIG, mbxStatus x%x\n",
- phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
phba->link_state = LPFC_HBA_ERROR;
mempool_free( pmb, phba->mbox_mem_pool);
@@ -344,9 +336,8 @@ lpfc_config_port_post(struct lpfc_hba *phba)
&& !(phba->lmt & LMT_10Gb))) {
/* Reset link speed to auto */
lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
- "%d:1302 Invalid speed for this board: "
+ "1302 Invalid speed for this board: "
"Reset link speed to auto: x%x\n",
- phba->brd_no,
phba->cfg_link_speed);
phba->cfg_link_speed = LINK_SPEED_AUTO;
}
@@ -402,9 +393,8 @@ lpfc_config_port_post(struct lpfc_hba *phba)
lpfc_set_loopback_flag(phba);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0454 Adapter failed to init, mbxCmd x%x "
+ "0454 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
- phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
/* Clear all interrupt enable conditions */
@@ -437,16 +427,11 @@ lpfc_config_port_post(struct lpfc_hba *phba)
int
lpfc_hba_down_prep(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport = phba->pport;
-
/* Disable interrupts */
writel(0, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- list_for_each_entry(vport, &phba->port_list, listentry) {
- lpfc_cleanup_discovery_resources(vport);
- }
-
+ lpfc_cleanup_discovery_resources(phba->pport);
return 0;
}
@@ -518,7 +503,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
mempool_free(pmboxq, phba->mbox_mem_pool);
if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
!(phba->link_state == LPFC_HBA_ERROR) &&
- !(phba->pport->fc_flag & FC_UNLOADING))
+ !(phba->pport->load_flag & FC_UNLOADING))
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
return;
@@ -532,7 +517,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
struct lpfc_sli *psli = &phba->sli;
if ((phba->link_state == LPFC_HBA_ERROR) ||
- (phba->pport->fc_flag & FC_UNLOADING) ||
+ (phba->pport->load_flag & FC_UNLOADING) ||
(phba->pport->fc_flag & FC_OFFLINE_MODE))
return;
@@ -586,8 +571,8 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
* need to take the HBA offline.
*/
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0459 Adapter heartbeat failure, taking "
- "this port offline.\n", phba->brd_no);
+ "0459 Adapter heartbeat failure, taking "
+ "this port offline.\n");
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
@@ -615,9 +600,10 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
struct lpfc_vport *vport = phba->pport;
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
- struct lpfc_vport *port_iterator;
+ struct lpfc_vport **vports;
uint32_t event_data;
struct Scsi_Host *shost;
+ int i;
/* If the pci channel is offline, ignore possible errors,
* since we cannot communicate with the pci card anyway. */
@@ -628,18 +614,21 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
phba->work_hs & HS_FFER5) {
/* Re-establishing Link */
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
- "%d:1301 Re-establishing Link "
+ "1301 Re-establishing Link "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->work_hs,
+ phba->work_hs,
phba->work_status[0], phba->work_status[1]);
- list_for_each_entry(port_iterator, &phba->port_list,
- listentry) {
- shost = lpfc_shost_from_vport(port_iterator);
-
- spin_lock_irq(shost->host_lock);
- port_iterator->fc_flag |= FC_ESTABLISH_LINK;
- spin_unlock_irq(shost->host_lock);
- }
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0;
+ i < LPFC_MAX_VPORTS && vports[i] != NULL;
+ i++){
+ shost = lpfc_shost_from_vport(vports[i]);
+ spin_lock_irq(shost->host_lock);
+ vports[i]->fc_flag |= FC_ESTABLISH_LINK;
+ spin_unlock_irq(shost->host_lock);
+ }
+ lpfc_destroy_vport_work_array(vports);
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
spin_unlock_irq(&phba->hbalock);
@@ -673,9 +662,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
* twice. This is the adapter hardware error path.
*/
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0457 Adapter Hardware Error "
+ "0457 Adapter Hardware Error "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->work_hs,
+ phba->work_hs,
phba->work_status[0], phba->work_status[1]);
event_data = FC_REG_DUMP_EVENT;
@@ -708,7 +697,6 @@ lpfc_handle_latt(struct lpfc_hba *phba)
{
struct lpfc_vport *vport = phba->pport;
struct lpfc_sli *psli = &phba->sli;
- struct lpfc_vport *port_iterator;
LPFC_MBOXQ_t *pmb;
volatile uint32_t control;
struct lpfc_dmabuf *mp;
@@ -729,8 +717,7 @@ lpfc_handle_latt(struct lpfc_hba *phba)
rc = -EIO;
/* Cleanup any outstanding ELS commands */
- list_for_each_entry(port_iterator, &phba->port_list, listentry)
- lpfc_els_flush_cmd(port_iterator);
+ lpfc_els_flush_all_cmd(phba);
psli->slistat.link_event++;
lpfc_read_la(phba, pmb, mp);
@@ -773,8 +760,7 @@ lpfc_handle_latt_err_exit:
/* The other case is an error from issue_mbox */
if (rc == -ENOMEM)
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
- "%d:0300 READ_LA: no buffers\n",
- phba->brd_no);
+ "0300 READ_LA: no buffers\n");
return;
}
@@ -799,8 +785,7 @@ lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len)
/* Vital Product */
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0455 Vital Product Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ "0455 Vital Product Data: x%x x%x x%x x%x\n",
(uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2],
(uint32_t) vpd[3]);
while (!finished && (index < (len - 4))) {
@@ -1313,22 +1298,25 @@ static void
lpfc_establish_link_tmo(unsigned long ptr)
{
struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
- struct lpfc_vport *vport = phba->pport;
+ struct lpfc_vport **vports;
unsigned long iflag;
+ int i;
/* Re-establishing Link, timer expired */
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
- "%d:1300 Re-establishing Link, timer expired "
+ "1300 Re-establishing Link, timer expired "
"Data: x%x x%x\n",
- phba->brd_no, vport->fc_flag,
- vport->port_state);
- list_for_each_entry(vport, &phba->port_list, listentry) {
- struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
- spin_lock_irqsave(shost->host_lock, iflag);
- vport->fc_flag &= ~FC_ESTABLISH_LINK;
- spin_unlock_irqrestore(shost->host_lock, iflag);
- }
+ phba->pport->fc_flag, phba->pport->port_state);
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ struct Scsi_Host *shost;
+ shost = lpfc_shost_from_vport(vports[i]);
+ spin_lock_irqsave(shost->host_lock, iflag);
+ vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
+ spin_unlock_irqrestore(shost->host_lock, iflag);
+ }
+ lpfc_destroy_vport_work_array(vports);
}
void
@@ -1343,12 +1331,9 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
static void
lpfc_stop_phba_timers(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport;
-
del_timer_sync(&phba->fcp_poll_timer);
del_timer_sync(&phba->fc_estabtmo);
- list_for_each_entry(vport, &phba->port_list, listentry)
- lpfc_stop_vport_timers(vport);
+ lpfc_stop_vport_timers(phba->pport);
del_timer_sync(&phba->sli.mbox_tmo);
del_timer_sync(&phba->fabric_block_timer);
phba->hb_outstanding = 0;
@@ -1360,6 +1345,8 @@ int
lpfc_online(struct lpfc_hba *phba)
{
struct lpfc_vport *vport = phba->pport;
+ struct lpfc_vport **vports;
+ int i;
if (!phba)
return 0;
@@ -1368,8 +1355,7 @@ lpfc_online(struct lpfc_hba *phba)
return 0;
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "%d:0458 Bring Adapter online\n",
- phba->brd_no);
+ "0458 Bring Adapter online\n");
lpfc_block_mgmt_io(phba);
@@ -1383,14 +1369,18 @@ lpfc_online(struct lpfc_hba *phba)
return 1;
}
- list_for_each_entry(vport, &phba->port_list, listentry) {
- struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_OFFLINE_MODE;
- if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
- vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- spin_unlock_irq(shost->host_lock);
- }
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ struct Scsi_Host *shost;
+ shost = lpfc_shost_from_vport(vports[i]);
+ spin_lock_irq(shost->host_lock);
+ vports[i]->fc_flag &= ~FC_OFFLINE_MODE;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
+ }
+ lpfc_destroy_vport_work_array(vports);
lpfc_unblock_mgmt_io(phba);
return 0;
@@ -1440,39 +1430,39 @@ lpfc_offline_prep(struct lpfc_hba * phba)
void
lpfc_offline(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport = phba->pport;
- struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_vport *port_iterator;
+ struct Scsi_Host *shost;
+ struct lpfc_vport **vports;
+ int i;
- if (vport->fc_flag & FC_OFFLINE_MODE)
+ if (phba->pport->fc_flag & FC_OFFLINE_MODE)
return;
/* stop all timers associated with this hba */
lpfc_stop_phba_timers(phba);
- list_for_each_entry(port_iterator, &phba->port_list, listentry) {
- port_iterator->work_port_events = 0;
- }
-
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+ lpfc_stop_vport_timers(vports[i]);
+ lpfc_destroy_vport_work_array(vports);
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "%d:0460 Bring Adapter offline\n",
- phba->brd_no);
-
+ "0460 Bring Adapter offline\n");
/* Bring down the SLI Layer and cleanup. The HBA is offline
now. */
lpfc_sli_hba_down(phba);
spin_lock_irq(&phba->hbalock);
phba->work_ha = 0;
- vport->fc_flag |= FC_OFFLINE_MODE;
spin_unlock_irq(&phba->hbalock);
- list_for_each_entry(port_iterator, &phba->port_list, listentry) {
- shost = lpfc_shost_from_vport(port_iterator);
-
- lpfc_cleanup(port_iterator);
- spin_lock_irq(shost->host_lock);
- vport->work_port_events = 0;
- vport->fc_flag |= FC_OFFLINE_MODE;
- spin_unlock_irq(shost->host_lock);
- }
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ shost = lpfc_shost_from_vport(vports[i]);
+ lpfc_cleanup(vports[i]);
+ spin_lock_irq(shost->host_lock);
+ vports[i]->work_port_events = 0;
+ vports[i]->fc_flag |= FC_OFFLINE_MODE;
+ spin_unlock_irq(shost->host_lock);
+ }
+ lpfc_destroy_vport_work_array(vports);
}
/******************************************************************************
@@ -1509,15 +1499,19 @@ lpfc_scsi_free(struct lpfc_hba *phba)
return 0;
}
-
struct lpfc_vport *
-lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
+lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
{
struct lpfc_vport *vport;
struct Scsi_Host *shost;
int error = 0;
- shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport));
+ if (dev != &phba->pcidev->dev)
+ shost = scsi_host_alloc(&lpfc_vport_template,
+ sizeof(struct lpfc_vport));
+ else
+ shost = scsi_host_alloc(&lpfc_template,
+ sizeof(struct lpfc_vport));
if (!shost)
goto out;
@@ -1527,9 +1521,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
vport->load_flag |= FC_LOADING;
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ lpfc_get_vport_cfgparam(vport);
shost->unique_id = instance;
shost->max_id = LPFC_MAX_TARGET;
- shost->max_lun = phba->cfg_max_luns;
+ shost->max_lun = vport->cfg_max_luns;
shost->this_id = -1;
shost->max_cmd_len = 16;
/*
@@ -1538,7 +1533,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
* max xri value determined in hba setup.
*/
shost->can_queue = phba->cfg_hba_queue_depth - 10;
- if (fc_vport != NULL) {
+ if (dev != &phba->pcidev->dev) {
shost->transportt = lpfc_vport_transport_template;
vport->port_type = LPFC_NPIV_PORT;
} else {
@@ -1562,15 +1557,13 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
vport->els_tmofunc.function = lpfc_els_timeout;
vport->els_tmofunc.data = (unsigned long)vport;
- if (fc_vport != NULL) {
- error = scsi_add_host(shost, &fc_vport->dev);
- } else {
- error = scsi_add_host(shost, &phba->pcidev->dev);
- }
+ error = scsi_add_host(shost, dev);
if (error)
goto out_put_shost;
+ spin_lock_irq(&phba->hbalock);
list_add_tail(&vport->listentry, &phba->port_list);
+ spin_unlock_irq(&phba->hbalock);
return vport;
out_put_shost:
@@ -1625,23 +1618,21 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
spin_lock_irq(shost->host_lock);
- if (vport->fc_flag & FC_UNLOADING) {
+ if (vport->load_flag & FC_UNLOADING) {
stat = 1;
goto finished;
}
if (time >= 30 * HZ) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0461 Scanning longer than 30 "
- "seconds. Continuing initialization\n",
- phba->brd_no);
+ "0461 Scanning longer than 30 "
+ "seconds. Continuing initialization\n");
stat = 1;
goto finished;
}
if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0465 Link down longer than 15 "
- "seconds. Continuing initialization\n",
- phba->brd_no);
+ "0465 Link down longer than 15 "
+ "seconds. Continuing initialization\n");
stat = 1;
goto finished;
}
@@ -1704,7 +1695,7 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
fc_host_max_npiv_vports(shost) = phba->max_vpi;
spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_LOADING;
+ vport->load_flag &= ~FC_LOADING;
spin_unlock_irq(shost->host_lock);
}
@@ -1716,9 +1707,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
struct lpfc_sli *psli;
struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
struct Scsi_Host *shost = NULL;
+ void *ptr;
unsigned long bar0map_len, bar2map_len;
int error = -ENODEV;
- int i;
+ int i, hbq_count;
uint16_t iotag;
if (pci_enable_device(pdev))
@@ -1739,7 +1731,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_phba;
INIT_LIST_HEAD(&phba->port_list);
- INIT_LIST_HEAD(&phba->hbq_buffer_list);
/*
* Get all the module params for configuring this host and then
* establish the host.
@@ -1817,6 +1808,17 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (!phba->hbqslimp.virt)
goto out_free_slim;
+ hbq_count = lpfc_sli_hbq_count();
+ ptr = phba->hbqslimp.virt;
+ for (i = 0; i < hbq_count; ++i) {
+ phba->hbqs[i].hbq_virt = ptr;
+ INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
+ ptr += (lpfc_hbq_defs[i]->entry_count *
+ sizeof(struct lpfc_hbq_entry));
+ }
+ phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc;
+ phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free;
+
memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
/* Initialize the SLI Layer to run with lpfc HBAs. */
@@ -1830,7 +1832,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Initialize and populate the iocb list per host. */
INIT_LIST_HEAD(&phba->lpfc_iocb_list);
for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
- iocbq_entry = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+ iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
if (iocbq_entry == NULL) {
printk(KERN_ERR "%s: only allocated %d iocbs of "
"expected %d count. Unloading driver.\n",
@@ -1839,7 +1841,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_iocbq;
}
- memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
if (iotag == 0) {
kfree (iocbq_entry);
@@ -1881,7 +1882,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Initialize list of fabric iocbs */
INIT_LIST_HEAD(&phba->fabric_iocb_list);
- vport = lpfc_create_port(phba, phba->brd_no, NULL);
+ vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
if (!vport)
goto out_kthread_stop;
@@ -1893,18 +1894,19 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (phba->cfg_use_msi) {
error = pci_enable_msi(phba->pcidev);
- if (error)
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "%d:0452 "
- "Enable MSI failed, continuing with "
- "IRQ\n", phba->brd_no);
+ if (!error)
+ phba->using_msi = 1;
+ else
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "0452 Enable MSI failed, continuing "
+ "with IRQ\n");
}
error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
LPFC_DRIVER_NAME, phba);
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0451 Enable interrupt handler failed\n",
- phba->brd_no);
+ "0451 Enable interrupt handler failed\n");
goto out_disable_msi;
}
@@ -1941,14 +1943,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
out_remove_device:
lpfc_free_sysfs_attr(vport);
spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_UNLOADING;
+ vport->load_flag |= FC_UNLOADING;
spin_unlock_irq(shost->host_lock);
out_free_irq:
lpfc_stop_phba_timers(phba);
phba->pport->work_port_events = 0;
free_irq(phba->pcidev->irq, phba);
out_disable_msi:
- pci_disable_msi(phba->pcidev);
+ if (phba->using_msi)
+ pci_disable_msi(phba->pcidev);
destroy_port(vport);
out_kthread_stop:
kthread_stop(phba->worker_thread);
@@ -1990,16 +1993,15 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_vport *port_iterator;
- list_for_each_entry(port_iterator, &phba->port_list, listentry)
- port_iterator->load_flag |= FC_UNLOADING;
+ spin_lock_irq(&phba->hbalock);
+ vport->load_flag |= FC_UNLOADING;
+ spin_unlock_irq(&phba->hbalock);
kfree(vport->vname);
lpfc_free_sysfs_attr(vport);
fc_remove_host(shost);
scsi_remove_host(shost);
-
/*
* Bring down the SLI Layer. This step disable all interrupts,
* clears the rings, discards all mailbox commands, and resets
@@ -2013,7 +2015,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
list_del_init(&vport->listentry);
spin_unlock_irq(&phba->hbalock);
-
lpfc_debugfs_terminate(vport);
lpfc_cleanup(vport);
@@ -2021,7 +2022,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
/* Release the irq reservation */
free_irq(phba->pcidev->irq, phba);
- pci_disable_msi(phba->pcidev);
+ if (phba->using_msi)
+ pci_disable_msi(phba->pcidev);
pci_set_drvdata(pdev, NULL);
scsi_host_put(shost);
@@ -2063,8 +2065,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
@@ -2080,6 +2082,11 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
pring = &psli->ring[psli->fcp_ring];
lpfc_sli_abort_iocb_ring(phba, pring);
+ /* Release the irq reservation */
+ free_irq(phba->pcidev->irq, phba);
+ if (phba->using_msi)
+ pci_disable_msi(phba->pcidev);
+
/* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
@@ -2092,8 +2099,8 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
*/
static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
struct lpfc_sli *psli = &phba->sli;
int bars = pci_select_bars(pdev, IORESOURCE_MEM);
@@ -2107,9 +2114,9 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
/* Re-establishing Link */
- spin_lock_irq(host->host_lock);
+ spin_lock_irq(shost->host_lock);
phba->pport->fc_flag |= FC_ESTABLISH_LINK;
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(shost->host_lock);
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
@@ -2132,8 +2139,8 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
*/
static void lpfc_io_resume(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
if (lpfc_online(phba) == 0) {
mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 8a6ceffeabcf..626e4d878725 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -33,6 +33,12 @@
#define LOG_VPORT 0x4000 /* NPIV events */
#define LOG_ALL_MSG 0xffff /* LOG all messages */
+#define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
+ { if (((mask) &(vport)->cfg_log_verbose) || (level[1] <= '3')) \
+ dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
+ fmt, (vport)->phba->brd_no, vport->vpi, ##arg); }
+
#define lpfc_printf_log(phba, level, mask, fmt, arg...) \
- { if (((mask) &(phba)->cfg_log_verbose) || (level[1] <= '3')) \
- dev_printk(level, &((phba)->pcidev)->dev, fmt, ##arg); }
+ { if (((mask) &(phba)->pport->cfg_log_verbose) || (level[1] <= '3')) \
+ dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
+ fmt, phba->brd_no, ##arg); }
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 8f42fbfdd29e..a592733664e9 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -275,11 +275,8 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
kfree(mp);
mb->mbxCommand = MBX_READ_SPARM64;
/* READ_SPARAM: no buffers */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX,
- "%d:0301 READ_SPARAM: no buffers\n",
- phba->brd_no);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+ "0301 READ_SPARAM: no buffers\n");
return (1);
}
INIT_LIST_HEAD(&mp->list);
@@ -378,9 +375,8 @@ lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
mb->mbxCommand = MBX_REG_LOGIN64;
/* REG_LOGIN: no buffers */
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
- "%d (%d):0302 REG_LOGIN: no buffers, DID x%x, "
- "flag x%x\n",
- phba->brd_no, vpi, did, flag);
+ "0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
+ "flag x%x\n", vpi, did, flag);
return (1);
}
INIT_LIST_HEAD(&mp->list);
@@ -564,7 +560,8 @@ lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb,
}
void
-lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
+lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id,
+ struct lpfc_hbq_init *hbq_desc,
uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
{
int i;
@@ -572,6 +569,7 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+ hbqmb->hbqId = id;
hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */
hbqmb->recvNotify = hbq_desc->rn; /* Receive
* Notification */
@@ -691,8 +689,8 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
- mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
- if (phba->max_vpi && phba->cfg_npiv_enable &&
+ mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
+ if (phba->max_vpi && phba->cfg_enable_npiv &&
phba->vpd.sli3Feat.cmv) {
mb->un.varCfgPort.max_vpi = phba->max_vpi;
mb->un.varCfgPort.cmv = 1;
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 3594c469494f..43c3b8a0d76a 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -231,21 +231,34 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
return;
}
-void *
-lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
+struct hbq_dmabuf *
+lpfc_els_hbq_alloc(struct lpfc_hba *phba)
{
- void *ret;
- ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle);
- return ret;
+ struct hbq_dmabuf *hbqbp;
+
+ hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL);
+ if (!hbqbp)
+ return NULL;
+
+ hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
+ &hbqbp->dbuf.phys);
+ if (!hbqbp->dbuf.virt) {
+ kfree(hbqbp);
+ return NULL;
+ }
+ hbqbp->size = LPFC_BPL_SIZE;
+ return hbqbp;
}
void
-lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma)
+lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
{
- pci_pool_free(phba->lpfc_hbq_pool, virt, dma);
+ pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
+ kfree(hbqbp);
return;
}
+/* This is ONLY called for the LPFC_ELS_HBQ */
void
lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
{
@@ -254,9 +267,8 @@ lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
if (hbq_entry->tag == -1) {
- lpfc_hbq_free(phba, hbq_entry->dbuf.virt,
- hbq_entry->dbuf.phys);
- kfree(hbq_entry);
+ (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
+ (phba, hbq_entry);
} else {
lpfc_sli_free_hbq(phba, hbq_entry);
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index bca2f5c9b4ba..880af0cd463d 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -133,15 +133,15 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
return 1;
bad_service_param:
- lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0207 Device %x "
- "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
- "invalid service parameters. Ignoring device.\n",
- vport->phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
- sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
- sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
- sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
- sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0207 Device %x "
+ "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
+ "invalid service parameters. Ignoring device.\n",
+ ndlp->nlp_DID,
+ sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
+ sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
+ sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
+ sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
return 0;
}
@@ -194,11 +194,11 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
IOCB_t *cmd;
/* Abort outstanding I/O on NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0205 Abort outstanding I/O on NPort x%x "
- "Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
- ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
+ "0205 Abort outstanding I/O on NPort x%x "
+ "Data: x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
lpfc_fabric_abort_nport(ndlp);
@@ -298,13 +298,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
icmd = &cmdiocb->iocb;
/* PLOGI chkparm OK */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
- ndlp->nlp_rpi);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
+ ndlp->nlp_rpi);
- if (phba->cfg_fcp_class == 2 && sp->cls2.classValid)
+ if (vport->cfg_fcp_class == 2 && sp->cls2.classValid)
ndlp->nlp_fcp_info |= CLASS2;
else
ndlp->nlp_fcp_info |= CLASS3;
@@ -330,7 +329,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
case NLP_STE_PRLI_ISSUE:
case NLP_STE_UNMAPPED_NODE:
case NLP_STE_MAPPED_NODE:
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
return 1;
}
@@ -392,7 +391,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
}
if ((vport->port_type == LPFC_NPIV_PORT &&
- phba->cfg_vport_restrict_login)) {
+ vport->cfg_restrict_login)) {
/* In order to preserve RPIs, we want to cleanup
* the default RPI the firmware created to rcv
@@ -408,7 +407,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp, mbox);
return 1;
}
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
return 1;
out:
@@ -452,7 +451,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
} else {
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
- NULL, 0);
+ NULL);
}
return 1;
}
@@ -489,9 +488,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_flag |= NLP_LOGO_ACC;
spin_unlock_irq(shost->host_lock);
if (els_cmd == ELS_CMD_PRLO)
- lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
else
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
if (!(ndlp->nlp_type & NLP_FABRIC) ||
(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
@@ -564,10 +563,14 @@ static uint32_t
lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_hba *phba = vport->phba;
+
+ if (!ndlp->nlp_rpi) {
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+ return 0;
+ }
/* Check config parameter use-adisc or FCP-2 */
- if ((phba->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
+ if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_ADISC;
@@ -583,12 +586,11 @@ static uint32_t
lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
- lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0253 Illegal State Transition: node x%x "
- "event x%x, state x%x Data: x%x x%x\n",
- vport->phba->brd_no, vport->vpi,
- ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
- ndlp->nlp_flag);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0253 Illegal State Transition: node x%x "
+ "event x%x, state x%x Data: x%x x%x\n",
+ ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
+ ndlp->nlp_flag);
return ndlp->nlp_state;
}
@@ -630,7 +632,7 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
spin_unlock_irq(shost->host_lock);
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
@@ -726,7 +728,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_els_abort(phba, ndlp);
if (evt == NLP_EVT_RCV_LOGO) {
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
} else {
lpfc_issue_els_logo(vport, ndlp, 0);
}
@@ -778,16 +780,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
goto out;
-
/* PLOGI chkparm OK */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (%d):0121 PLOGI chkparm OK "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- ndlp->nlp_DID, ndlp->nlp_state,
- ndlp->nlp_flag, ndlp->nlp_rpi);
-
- if (phba->cfg_fcp_class == 2 && (sp->cls2.classValid))
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "0121 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
+ if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid))
ndlp->nlp_fcp_info |= CLASS2;
else
ndlp->nlp_fcp_info |= CLASS3;
@@ -806,10 +804,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0133 PLOGI: no memory for reg_login "
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0133 PLOGI: no memory for reg_login "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
ndlp->nlp_DID, ndlp->nlp_state,
ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
@@ -844,30 +841,27 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
kfree(mp);
mempool_free(mbox, phba->mbox_mem_pool);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0134 PLOGI: cannot issue reg_login "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- ndlp->nlp_DID, ndlp->nlp_state,
- ndlp->nlp_flag, ndlp->nlp_rpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0134 PLOGI: cannot issue reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
} else {
mempool_free(mbox, phba->mbox_mem_pool);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0135 PLOGI: cannot format reg_login "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no, vport->vpi,
- ndlp->nlp_DID, ndlp->nlp_state,
- ndlp->nlp_flag, ndlp->nlp_rpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0135 PLOGI: cannot format reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
}
out:
if (ndlp->nlp_DID == NameServer_DID) {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0261 Cannot Register NameServer login\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0261 Cannot Register NameServer login\n");
}
/* Free this node since the driver cannot login or has the wrong
@@ -1178,7 +1172,7 @@ lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport,
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
return ndlp->nlp_state;
}
@@ -1189,19 +1183,15 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
uint32_t evt)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
MAILBOX_t *mb = &pmb->mb;
uint32_t did = mb->un.varWords[1];
if (mb->mbxStatus) {
/* RegLogin failed */
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d (%d):0246 RegLogin failed Data: x%x x%x "
- "x%x\n",
- phba->brd_no, vport->vpi,
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+ "0246 RegLogin failed Data: x%x x%x x%x\n",
did, mb->mbxStatus, vport->port_state);
-
/*
* If RegLogin failed due to lack of HBA resources do not
* retry discovery.
@@ -1337,7 +1327,7 @@ lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
{
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
return ndlp->nlp_state;
}
@@ -1358,7 +1348,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
if ((vport->port_type == LPFC_NPIV_PORT) &&
- phba->cfg_vport_restrict_login) {
+ vport->cfg_restrict_login) {
goto out;
}
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
@@ -1380,7 +1370,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
}
if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
(vport->port_type == LPFC_NPIV_PORT) &&
- phba->cfg_vport_restrict_login) {
+ vport->cfg_restrict_login) {
out:
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_TARGET_REMOVE;
@@ -1529,7 +1519,7 @@ lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
{
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
return ndlp->nlp_state;
}
@@ -1600,8 +1590,8 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* flush the target */
- lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
+ ndlp->nlp_sid, 0, LPFC_CTX_TGT);
/* Treat like rcv logo */
lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
@@ -1734,7 +1724,7 @@ lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_flag |= NLP_LOGO_ACC;
spin_unlock_irq(shost->host_lock);
- lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
@@ -2047,7 +2037,6 @@ int
lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
- struct lpfc_hba *phba = vport->phba;
uint32_t cur_state, rc;
uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t);
@@ -2056,11 +2045,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
cur_state = ndlp->nlp_state;
/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0211 DSM in event x%x on NPort x%x in "
- "state %d Data: x%x\n",
- phba->brd_no, vport->vpi,
- evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0211 DSM in event x%x on NPort x%x in "
+ "state %d Data: x%x\n",
+ evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
"DSM in: evt:%d ste:%d did:x%x",
@@ -2070,11 +2058,9 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
rc = (func) (vport, ndlp, arg, evt);
/* DSM out state <rc> on NPort <nlp_DID> */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d (%d):0212 DSM out state %d on NPort x%x "
- "Data: x%x\n",
- phba->brd_no, vport->vpi,
- rc, ndlp->nlp_DID, ndlp->nlp_flag);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "0212 DSM out state %d on NPort x%x Data: x%x\n",
+ rc, ndlp->nlp_DID, ndlp->nlp_flag);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
"DSM out: ste:%d did:x%x flg:x%x",
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 8f45bbc42126..17d7dc05149b 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -84,22 +84,21 @@ lpfc_adjust_queue_depth(struct lpfc_hba *phba)
* SCSI command completion.
*/
static inline void
-lpfc_rampup_queue_depth(struct lpfc_hba *phba,
+lpfc_rampup_queue_depth(struct lpfc_vport *vport,
struct scsi_device *sdev)
{
unsigned long flags;
+ struct lpfc_hba *phba = vport->phba;
atomic_inc(&phba->num_cmd_success);
- if (phba->cfg_lun_queue_depth <= sdev->queue_depth)
+ if (vport->cfg_lun_queue_depth <= sdev->queue_depth)
return;
-
spin_lock_irqsave(&phba->hbalock, flags);
if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
-
phba->last_ramp_up_time = jiffies;
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -119,43 +118,40 @@ lpfc_rampup_queue_depth(struct lpfc_hba *phba,
void
lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport;
- struct Scsi_Host *host;
+ struct lpfc_vport **vports;
+ struct Scsi_Host *shost;
struct scsi_device *sdev;
unsigned long new_queue_depth;
unsigned long num_rsrc_err, num_cmd_success;
+ int i;
num_rsrc_err = atomic_read(&phba->num_rsrc_err);
num_cmd_success = atomic_read(&phba->num_cmd_success);
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry(vport, &phba->port_list, listentry) {
- host = lpfc_shost_from_vport(vport);
- if (!scsi_host_get(host))
- continue;
-
- spin_unlock_irq(&phba->hbalock);
-
- shost_for_each_device(sdev, host) {
- new_queue_depth = sdev->queue_depth * num_rsrc_err /
- (num_rsrc_err + num_cmd_success);
- if (!new_queue_depth)
- new_queue_depth = sdev->queue_depth - 1;
- else
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ shost = lpfc_shost_from_vport(vports[i]);
+ shost_for_each_device(sdev, shost) {
new_queue_depth =
- sdev->queue_depth - new_queue_depth;
-
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
- new_queue_depth);
- else
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
- new_queue_depth);
+ sdev->queue_depth * num_rsrc_err /
+ (num_rsrc_err + num_cmd_success);
+ if (!new_queue_depth)
+ new_queue_depth = sdev->queue_depth - 1;
+ else
+ new_queue_depth = sdev->queue_depth -
+ new_queue_depth;
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev,
+ MSG_ORDERED_TAG,
+ new_queue_depth);
+ else
+ scsi_adjust_queue_depth(sdev,
+ MSG_SIMPLE_TAG,
+ new_queue_depth);
+ }
}
- spin_lock_irq(&phba->hbalock);
- scsi_host_put(host);
- }
- spin_unlock_irq(&phba->hbalock);
+ lpfc_destroy_vport_work_array(vports);
atomic_set(&phba->num_rsrc_err, 0);
atomic_set(&phba->num_cmd_success, 0);
}
@@ -163,29 +159,27 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
void
lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport;
- struct Scsi_Host *host;
+ struct lpfc_vport **vports;
+ struct Scsi_Host *shost;
struct scsi_device *sdev;
-
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry(vport, &phba->port_list, listentry) {
- host = lpfc_shost_from_vport(vport);
- if (!scsi_host_get(host))
- continue;
-
- spin_unlock_irq(&phba->hbalock);
- shost_for_each_device(sdev, host) {
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
- sdev->queue_depth+1);
- else
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
- sdev->queue_depth+1);
+ int i;
+
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports != NULL)
+ for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ shost = lpfc_shost_from_vport(vports[i]);
+ shost_for_each_device(sdev, shost) {
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev,
+ MSG_ORDERED_TAG,
+ sdev->queue_depth+1);
+ else
+ scsi_adjust_queue_depth(sdev,
+ MSG_SIMPLE_TAG,
+ sdev->queue_depth+1);
+ }
}
- spin_lock_irq(&phba->hbalock);
- scsi_host_put(host);
- }
- spin_unlock_irq(&phba->hbalock);
+ lpfc_destroy_vport_work_array(vports);
atomic_set(&phba->num_rsrc_err, 0);
atomic_set(&phba->num_cmd_success, 0);
}
@@ -411,9 +405,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
- struct lpfc_hba *phba = vport->phba;
uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
- uint32_t vpi = vport->vpi;
uint32_t resp_info = fcprsp->rspStatus2;
uint32_t scsi_status = fcprsp->rspStatus3;
uint32_t *lp;
@@ -445,15 +437,15 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
if (!scsi_status && (resp_info & RESID_UNDER))
logit = LOG_FCP;
- lpfc_printf_log(phba, KERN_WARNING, logit,
- "%d (%d):0730 FCP command x%x failed: x%x SNS x%x x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, vpi, cmnd->cmnd[0], scsi_status,
- be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
- be32_to_cpu(fcprsp->rspResId),
- be32_to_cpu(fcprsp->rspSnsLen),
- be32_to_cpu(fcprsp->rspRspLen),
- fcprsp->rspInfo3);
+ lpfc_printf_vlog(vport, KERN_WARNING, logit,
+ "0730 FCP command x%x failed: x%x SNS x%x x%x "
+ "Data: x%x x%x x%x x%x x%x\n",
+ cmnd->cmnd[0], scsi_status,
+ be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
+ be32_to_cpu(fcprsp->rspResId),
+ be32_to_cpu(fcprsp->rspSnsLen),
+ be32_to_cpu(fcprsp->rspRspLen),
+ fcprsp->rspInfo3);
if (resp_info & RSP_LEN_VALID) {
rsplen = be32_to_cpu(fcprsp->rspRspLen);
@@ -468,12 +460,12 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
if (resp_info & RESID_UNDER) {
scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d (%d):0716 FCP Read Underrun, expected %d, "
- "residual %d Data: x%x x%x x%x\n",
- phba->brd_no, vpi, be32_to_cpu(fcpcmd->fcpDl),
- scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
- cmnd->underflow);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0716 FCP Read Underrun, expected %d, "
+ "residual %d Data: x%x x%x x%x\n",
+ be32_to_cpu(fcpcmd->fcpDl),
+ scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
+ cmnd->underflow);
/*
* If there is an under run check if under run reported by
@@ -483,14 +475,13 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
fcpi_parm &&
(scsi_get_resid(cmnd) != fcpi_parm)) {
- lpfc_printf_log(phba, KERN_WARNING,
- LOG_FCP | LOG_FCP_ERROR,
- "%d (%d):0735 FCP Read Check Error "
- "and Underrun Data: x%x x%x x%x x%x\n",
- phba->brd_no, vpi,
- be32_to_cpu(fcpcmd->fcpDl),
- scsi_get_resid(cmnd), fcpi_parm,
- cmnd->cmnd[0]);
+ lpfc_printf_vlog(vport, KERN_WARNING,
+ LOG_FCP | LOG_FCP_ERROR,
+ "0735 FCP Read Check Error "
+ "and Underrun Data: x%x x%x x%x x%x\n",
+ be32_to_cpu(fcpcmd->fcpDl),
+ scsi_get_resid(cmnd), fcpi_parm,
+ cmnd->cmnd[0]);
scsi_set_resid(cmnd, scsi_bufflen(cmnd));
host_status = DID_ERROR;
}
@@ -504,21 +495,19 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
(scsi_status == SAM_STAT_GOOD) &&
(scsi_bufflen(cmnd) - scsi_get_resid(cmnd)
< cmnd->underflow)) {
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d (%d):0717 FCP command x%x residual "
- "underrun converted to error "
- "Data: x%x x%x x%x\n",
- phba->brd_no, vpi, cmnd->cmnd[0],
- scsi_bufflen(cmnd),
- scsi_get_resid(cmnd), cmnd->underflow);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0717 FCP command x%x residual "
+ "underrun converted to error "
+ "Data: x%x x%x x%x\n",
+ cmnd->cmnd[0], scsi_bufflen(cmnd),
+ scsi_get_resid(cmnd), cmnd->underflow);
host_status = DID_ERROR;
}
} else if (resp_info & RESID_OVER) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d (%d):0720 FCP command x%x residual "
- "overrun error. Data: x%x x%x \n",
- phba->brd_no, vpi, cmnd->cmnd[0],
- scsi_bufflen(cmnd), scsi_get_resid(cmnd));
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0720 FCP command x%x residual overrun error. "
+ "Data: x%x x%x \n", cmnd->cmnd[0],
+ scsi_bufflen(cmnd), scsi_get_resid(cmnd));
host_status = DID_ERROR;
/*
@@ -527,13 +516,12 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
*/
} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
- "%d (%d):0734 FCP Read Check Error Data: "
- "x%x x%x x%x x%x\n",
- phba->brd_no, vpi,
- be32_to_cpu(fcpcmd->fcpDl),
- be32_to_cpu(fcprsp->rspResId),
- fcpi_parm, cmnd->cmnd[0]);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
+ "0734 FCP Read Check Error Data: "
+ "x%x x%x x%x x%x\n",
+ be32_to_cpu(fcpcmd->fcpDl),
+ be32_to_cpu(fcprsp->rspResId),
+ fcpi_parm, cmnd->cmnd[0]);
host_status = DID_ERROR;
scsi_set_resid(cmnd, scsi_bufflen(cmnd));
}
@@ -552,9 +540,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
- uint32_t vpi = (lpfc_cmd->cur_iocbq.vport
- ? lpfc_cmd->cur_iocbq.vport->vpi
- : 0);
int result;
struct scsi_device *sdev, *tmp_sdev;
int depth = 0;
@@ -569,15 +554,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
else if (lpfc_cmd->status >= IOSTAT_CNT)
lpfc_cmd->status = IOSTAT_DEFAULT;
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d (%d):0729 FCP cmd x%x failed <%d/%d> "
- "status: x%x result: x%x Data: x%x x%x\n",
- phba->brd_no, vpi, cmd->cmnd[0],
- cmd->device ? cmd->device->id : 0xffff,
- cmd->device ? cmd->device->lun : 0xffff,
- lpfc_cmd->status, lpfc_cmd->result,
- pIocbOut->iocb.ulpContext,
- lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0729 FCP cmd x%x failed <%d/%d> "
+ "status: x%x result: x%x Data: x%x x%x\n",
+ cmd->cmnd[0],
+ cmd->device ? cmd->device->id : 0xffff,
+ cmd->device ? cmd->device->lun : 0xffff,
+ lpfc_cmd->status, lpfc_cmd->result,
+ pIocbOut->iocb.ulpContext,
+ lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
switch (lpfc_cmd->status) {
case IOSTAT_FCP_RSP_ERROR:
@@ -610,13 +595,12 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) {
uint32_t *lp = (uint32_t *)cmd->sense_buffer;
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d (%d):0710 Iodone <%d/%d> cmd %p, error "
- "x%x SNS x%x x%x Data: x%x x%x\n",
- phba->brd_no, vpi, cmd->device->id,
- cmd->device->lun, cmd, cmd->result,
- *lp, *(lp + 3), cmd->retries,
- scsi_get_resid(cmd));
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0710 Iodone <%d/%d> cmd %p, error "
+ "x%x SNS x%x x%x Data: x%x x%x\n",
+ cmd->device->id, cmd->device->lun, cmd,
+ cmd->result, *lp, *(lp + 3), cmd->retries,
+ scsi_get_resid(cmd));
}
result = cmd->result;
@@ -631,16 +615,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
if (!result)
- lpfc_rampup_queue_depth(phba, sdev);
+ lpfc_rampup_queue_depth(vport, sdev);
if (!result && pnode != NULL &&
((jiffies - pnode->last_ramp_up_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
((jiffies - pnode->last_q_full_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
- (phba->cfg_lun_queue_depth > sdev->queue_depth)) {
+ (vport->cfg_lun_queue_depth > sdev->queue_depth)) {
shost_for_each_device(tmp_sdev, sdev->host) {
- if (phba->cfg_lun_queue_depth > tmp_sdev->queue_depth) {
+ if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){
if (tmp_sdev->id != sdev->id)
continue;
if (tmp_sdev->ordered_tags)
@@ -680,10 +664,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
depth = sdev->host->cmd_per_lun;
if (depth) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d (%d):0711 detected queue full - "
- "lun queue depth adjusted to %d.\n",
- phba->brd_no, vpi, depth);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0711 detected queue full - lun queue "
+ "depth adjusted to %d.\n", depth);
}
}
@@ -853,12 +836,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,
return FAILED;
/* Issue Target Reset to TGT <num> */
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d (%d):0702 Issue Target Reset to TGT %d "
- "Data: x%x x%x\n",
- phba->brd_no, vport->vpi, tgt_id,
- rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0702 Issue Target Reset to TGT %d Data: x%x x%x\n",
+ tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -965,10 +945,9 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
if (lpfc_cmd == NULL) {
lpfc_adjust_queue_depth(phba);
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d (%d):0707 driver's buffer pool is empty, "
- "IO busied\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0707 driver's buffer pool is empty, "
+ "IO busied\n");
goto out_host_busy;
}
@@ -1103,28 +1082,25 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
if (++loop_count
- > (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
+ > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
break;
}
if (lpfc_cmd->pCmd == cmnd) {
ret = FAILED;
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0748 abort handler timed out waiting "
- "for abort to complete: ret %#x, ID %d, "
- "LUN %d, snum %#lx\n",
- phba->brd_no, vport->vpi, ret,
- cmnd->device->id, cmnd->device->lun,
- cmnd->serial_number);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0748 abort handler timed out waiting "
+ "for abort to complete: ret %#x, ID %d, "
+ "LUN %d, snum %#lx\n",
+ ret, cmnd->device->id, cmnd->device->lun,
+ cmnd->serial_number);
}
out:
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d (%d):0749 SCSI Layer I/O Abort Request "
- "Status x%x ID %d LUN %d snum %#lx\n",
- phba->brd_no, vport->vpi, ret, cmnd->device->id,
- cmnd->device->lun, cmnd->serial_number);
-
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0749 SCSI Layer I/O Abort Request Status x%x ID %d "
+ "LUN %d snum %#lx\n", ret, cmnd->device->id,
+ cmnd->device->lun, cmnd->serial_number);
return ret;
}
@@ -1158,12 +1134,11 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
loopcnt++;
rdata = cmnd->device->hostdata;
if (!rdata ||
- (loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0721 LUN Reset rport "
- "failure: cnt x%x rdata x%p\n",
- phba->brd_no, vport->vpi,
- loopcnt, rdata);
+ (loopcnt > ((vport->cfg_devloss_tmo * 2) + 1))){
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0721 LUN Reset rport "
+ "failure: cnt x%x rdata x%p\n",
+ loopcnt, rdata);
goto out;
}
pnode = rdata->pnode;
@@ -1193,12 +1168,10 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
if (iocbqrsp == NULL)
goto out_free_scsi_buf;
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d (%d):0703 Issue target reset to TGT %d LUN %d "
- "rpi x%x nlp_flag x%x\n",
- phba->brd_no, vport->vpi, cmnd->device->id,
- cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
-
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0703 Issue target reset to TGT %d LUN %d "
+ "rpi x%x nlp_flag x%x\n", cmnd->device->id,
+ cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
iocb_status = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -1221,33 +1194,28 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
* Unfortunately, some targets do not abide by this forcing the driver
* to double check.
*/
- cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- cmnd->device->id, cmnd->device->lun,
+ cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun,
LPFC_CTX_LUN);
if (cnt)
- lpfc_sli_abort_iocb(phba,
- &phba->sli.ring[phba->sli.fcp_ring],
+ lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
cmnd->device->id, cmnd->device->lun,
- 0, LPFC_CTX_LUN);
+ LPFC_CTX_LUN);
loopcnt = 0;
while(cnt) {
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
if (++loopcnt
- > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
+ > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT)
break;
- cnt = lpfc_sli_sum_iocb(phba,
- &phba->sli.ring[phba->sli.fcp_ring],
- cmnd->device->id, cmnd->device->lun,
- LPFC_CTX_LUN);
+ cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id,
+ cmnd->device->lun, LPFC_CTX_LUN);
}
if (cnt) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0719 device reset I/O flush failure: "
- "cnt x%x\n",
- phba->brd_no, vport->vpi, cnt);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0719 device reset I/O flush failure: "
+ "cnt x%x\n", cnt);
ret = FAILED;
}
@@ -1255,12 +1223,11 @@ out_free_scsi_buf:
if (iocb_status != IOCB_TIMEDOUT) {
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0713 SCSI layer issued device reset (%d, %d) "
- "return x%x status x%x result x%x\n",
- phba->brd_no, vport->vpi, cmnd->device->id,
- cmnd->device->lun, ret, cmd_status, cmd_result);
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0713 SCSI layer issued device reset (%d, %d) "
+ "return x%x status x%x result x%x\n",
+ cmnd->device->id, cmnd->device->lun, ret,
+ cmd_status, cmd_result);
out:
return ret;
}
@@ -1311,10 +1278,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
cmnd->device->lun,
ndlp->rport->dd_data);
if (ret != SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0700 Bus Reset on target %d "
- "failed\n",
- phba->brd_no, vport->vpi, i);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0700 Bus Reset on target %d failed\n",
+ i);
err_count++;
break;
}
@@ -1333,35 +1299,30 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
* the targets. Unfortunately, some targets do not abide by
* this forcing the driver to double check.
*/
- cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- 0, 0, LPFC_CTX_HOST);
+ cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
if (cnt)
- lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- 0, 0, 0, LPFC_CTX_HOST);
+ lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
+ 0, 0, LPFC_CTX_HOST);
loopcnt = 0;
while(cnt) {
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
if (++loopcnt
- > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
+ > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT)
break;
- cnt = lpfc_sli_sum_iocb(phba,
- &phba->sli.ring[phba->sli.fcp_ring],
- 0, 0, LPFC_CTX_HOST);
+ cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
}
if (cnt) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0715 Bus Reset I/O flush failure: "
- "cnt x%x left x%x\n",
- phba->brd_no, vport->vpi, cnt, i);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0715 Bus Reset I/O flush failure: "
+ "cnt x%x left x%x\n", cnt, i);
ret = FAILED;
}
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0714 SCSI layer issued Bus Reset Data: x%x\n",
- phba->brd_no, vport->vpi, ret);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0714 SCSI layer issued Bus Reset Data: x%x\n", ret);
out:
return ret;
}
@@ -1390,36 +1351,32 @@ lpfc_slave_alloc(struct scsi_device *sdev)
* extra. This list of scsi bufs exists for the lifetime of the driver.
*/
total = phba->total_scsi_bufs;
- num_to_alloc = phba->cfg_lun_queue_depth + 2;
+ num_to_alloc = vport->cfg_lun_queue_depth + 2;
/* Allow some exchanges to be available always to complete discovery */
if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d (%d):0704 At limitation of %d "
- "preallocated command buffers\n",
- phba->brd_no, vport->vpi, total);
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0704 At limitation of %d preallocated "
+ "command buffers\n", total);
return 0;
-
/* Allow some exchanges to be available always to complete discovery */
} else if (total + num_to_alloc >
phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d (%d):0705 Allocation request of %d "
- "command buffers will exceed max of %d. "
- "Reducing allocation request to %d.\n",
- phba->brd_no, vport->vpi, num_to_alloc,
- phba->cfg_hba_queue_depth,
- (phba->cfg_hba_queue_depth - total));
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0705 Allocation request of %d "
+ "command buffers will exceed max of %d. "
+ "Reducing allocation request to %d.\n",
+ num_to_alloc, phba->cfg_hba_queue_depth,
+ (phba->cfg_hba_queue_depth - total));
num_to_alloc = phba->cfg_hba_queue_depth - total;
}
for (i = 0; i < num_to_alloc; i++) {
scsi_buf = lpfc_new_scsi_buf(vport);
if (!scsi_buf) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d (%d):0706 Failed to allocate "
- "command buffer\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0706 Failed to allocate "
+ "command buffer\n");
break;
}
@@ -1439,9 +1396,9 @@ lpfc_slave_configure(struct scsi_device *sdev)
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, phba->cfg_lun_queue_depth);
+ scsi_activate_tcq(sdev, vport->cfg_lun_queue_depth);
else
- scsi_deactivate_tcq(sdev, phba->cfg_lun_queue_depth);
+ scsi_deactivate_tcq(sdev, vport->cfg_lun_queue_depth);
/*
* Initialize the fc transport attributes for the target
@@ -1449,7 +1406,7 @@ lpfc_slave_configure(struct scsi_device *sdev)
* target pointer is stored in the starget_data for the
* driver's sysfs entry point functions.
*/
- rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+ rport->dev_loss_tmo = vport->cfg_devloss_tmo;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_poll_fcp_ring(phba);
@@ -1487,3 +1444,23 @@ struct scsi_host_template lpfc_template = {
.shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
};
+
+struct scsi_host_template lpfc_vport_template = {
+ .module = THIS_MODULE,
+ .name = LPFC_DRIVER_NAME,
+ .info = lpfc_info,
+ .queuecommand = lpfc_queuecommand,
+ .eh_abort_handler = lpfc_abort_handler,
+ .eh_device_reset_handler= lpfc_device_reset_handler,
+ .eh_bus_reset_handler = lpfc_bus_reset_handler,
+ .slave_alloc = lpfc_slave_alloc,
+ .slave_configure = lpfc_slave_configure,
+ .slave_destroy = lpfc_slave_destroy,
+ .scan_finished = lpfc_scan_finished,
+ .this_id = -1,
+ .sg_tablesize = LPFC_SG_SEG_CNT,
+ .cmd_per_lun = LPFC_CMD_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = lpfc_vport_attrs,
+ .max_sectors = 0xFFFF,
+};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f4d5a6b00fde..ce5ff2bccba6 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -49,9 +49,8 @@
lpfc_printf_log(phba, \
KERN_INFO, \
LOG_MBOX | LOG_SLI, \
- "%d (%d):0311 Mailbox command x%x cannot " \
+ "(%d):0311 Mailbox command x%x cannot " \
"issue Data: x%x x%x x%x\n", \
- phba->brd_no, \
pmbox->vport ? pmbox->vport->vpi : 0, \
pmbox->mb.mbxCommand, \
phba->pport->port_state, \
@@ -231,13 +230,11 @@ lpfc_sli_ring_map(struct lpfc_hba *phba)
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0446 Adapter failed to init (%d), "
+ "0446 Adapter failed to init (%d), "
"mbxCmd x%x CFG_RING, mbxStatus x%x, "
"ring %d\n",
- phba->brd_no, rc,
- pmbox->mbxCommand,
- pmbox->mbxStatus,
- i);
+ rc, pmbox->mbxCommand,
+ pmbox->mbxStatus, i);
phba->link_state = LPFC_HBA_ERROR;
ret = -ENXIO;
break;
@@ -296,9 +293,9 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
if (unlikely(pring->local_getidx >= max_cmd_idx)) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0315 Ring %d issue: portCmdGet %d "
+ "0315 Ring %d issue: portCmdGet %d "
"is bigger then cmd ring %d\n",
- phba->brd_no, pring->ringno,
+ pring->ringno,
pring->local_getidx, max_cmd_idx);
phba->link_state = LPFC_HBA_ERROR;
@@ -366,7 +363,7 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
if (psli->iocbq_lookup)
memcpy(new_arr, old_arr,
((psli->last_iotag + 1) *
- sizeof (struct lpfc_iocbq *)));
+ sizeof (struct lpfc_iocbq *)));
psli->iocbq_lookup = new_arr;
psli->iocbq_lookup_len = new_len;
psli->last_iotag = iotag;
@@ -380,8 +377,8 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
- "%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
- phba->brd_no, psli->last_iotag);
+ "0318 Failed to allocate IOTAG.last IOTAG is %d\n",
+ psli->last_iotag);
return 0;
}
@@ -395,6 +392,14 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
*/
nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0;
+ if (pring->ringno == LPFC_ELS_RING) {
+ lpfc_debugfs_slow_ring_trc(phba,
+ "IOCB cmd ring: wd4:x%08x wd6:x%08x wd7:x%08x",
+ *(((uint32_t *) &nextiocb->iocb) + 4),
+ *(((uint32_t *) &nextiocb->iocb) + 6),
+ *(((uint32_t *) &nextiocb->iocb) + 7));
+ }
+
/*
* Issue iocb command to adapter
*/
@@ -527,10 +532,9 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
lpfc_printf_log(phba, KERN_ERR,
LOG_SLI | LOG_VPORT,
- "%d:1802 HBQ %d: local_hbqGetIdx "
+ "1802 HBQ %d: local_hbqGetIdx "
"%u is > than hbqp->entry_count %u\n",
- phba->brd_no, hbqno,
- hbqp->local_hbqGetIdx,
+ hbqno, hbqp->local_hbqGetIdx,
hbqp->entry_count);
phba->link_state = LPFC_HBA_ERROR;
@@ -541,7 +545,8 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
return NULL;
}
- return (struct lpfc_hbq_entry *) phba->hbqslimp.virt + hbqp->hbqPutIdx;
+ return (struct lpfc_hbq_entry *) phba->hbqs[hbqno].hbq_virt +
+ hbqp->hbqPutIdx;
}
void
@@ -549,18 +554,21 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
{
struct lpfc_dmabuf *dmabuf, *next_dmabuf;
struct hbq_dmabuf *hbq_buf;
+ int i, hbq_count;
+ hbq_count = lpfc_sli_hbq_count();
/* Return all memory used by all HBQs */
- list_for_each_entry_safe(dmabuf, next_dmabuf,
- &phba->hbq_buffer_list, list) {
- hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
- list_del(&hbq_buf->dbuf.list);
- lpfc_hbq_free(phba, hbq_buf->dbuf.virt, hbq_buf->dbuf.phys);
- kfree(hbq_buf);
+ for (i = 0; i < hbq_count; ++i) {
+ list_for_each_entry_safe(dmabuf, next_dmabuf,
+ &phba->hbqs[i].hbq_buffer_list, list) {
+ hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
+ list_del(&hbq_buf->dbuf.list);
+ (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
+ }
}
}
-static void
+static struct lpfc_hbq_entry *
lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
struct hbq_dmabuf *hbq_buf)
{
@@ -574,7 +582,7 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
hbqe->bde.addrLow = le32_to_cpu(putPaddrLow(physaddr));
- hbqe->bde.tus.f.bdeSize = FCELSSIZE;
+ hbqe->bde.tus.f.bdeSize = hbq_buf->size;
hbqe->bde.tus.f.bdeFlags = 0;
hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w);
hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag);
@@ -583,8 +591,9 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
/* flush */
readl(phba->hbq_put + hbqno);
- list_add_tail(&hbq_buf->dbuf.list, &phba->hbq_buffer_list);
+ list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list);
}
+ return hbqe;
}
static struct lpfc_hbq_init lpfc_els_hbq = {
@@ -592,22 +601,38 @@ static struct lpfc_hbq_init lpfc_els_hbq = {
.entry_count = 200,
.mask_count = 0,
.profile = 0,
- .ring_mask = 1 << LPFC_ELS_RING,
+ .ring_mask = (1 << LPFC_ELS_RING),
.buffer_count = 0,
.init_count = 20,
.add_count = 5,
};
-static struct lpfc_hbq_init *lpfc_hbq_defs[] = {
+static struct lpfc_hbq_init lpfc_extra_hbq = {
+ .rn = 1,
+ .entry_count = 200,
+ .mask_count = 0,
+ .profile = 0,
+ .ring_mask = (1 << LPFC_EXTRA_RING),
+ .buffer_count = 0,
+ .init_count = 0,
+ .add_count = 5,
+};
+
+struct lpfc_hbq_init *lpfc_hbq_defs[] = {
&lpfc_els_hbq,
+ &lpfc_extra_hbq,
};
-int
+static int
lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
{
uint32_t i, start, end;
struct hbq_dmabuf *hbq_buffer;
+ if (!phba->hbqs[hbqno].hbq_alloc_buffer) {
+ return 0;
+ }
+
start = lpfc_hbq_defs[hbqno]->buffer_count;
end = count + lpfc_hbq_defs[hbqno]->buffer_count;
if (end > lpfc_hbq_defs[hbqno]->entry_count) {
@@ -616,17 +641,14 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
/* Populate HBQ entries */
for (i = start; i < end; i++) {
- hbq_buffer = kmalloc(sizeof(struct hbq_dmabuf),
- GFP_KERNEL);
+ hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
if (!hbq_buffer)
return 1;
- hbq_buffer->dbuf.virt = lpfc_hbq_alloc(phba, MEM_PRI,
- &hbq_buffer->dbuf.phys);
- if (hbq_buffer->dbuf.virt == NULL)
- return 1;
hbq_buffer->tag = (i | (hbqno << 16));
- lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer);
- lpfc_hbq_defs[hbqno]->buffer_count++;
+ if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
+ lpfc_hbq_defs[hbqno]->buffer_count++;
+ else
+ (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
}
return 0;
}
@@ -650,28 +672,34 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
{
struct lpfc_dmabuf *d_buf;
struct hbq_dmabuf *hbq_buf;
+ uint32_t hbqno;
+
+ hbqno = tag >> 16;
+ if (hbqno > LPFC_MAX_HBQS)
+ return NULL;
- list_for_each_entry(d_buf, &phba->hbq_buffer_list, list) {
+ list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
- if ((hbq_buf->tag & 0xffff) == tag) {
+ if (hbq_buf->tag == tag) {
return hbq_buf;
}
}
lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
- "%d:1803 Bad hbq tag. Data: x%x x%x\n",
- phba->brd_no, tag,
- lpfc_hbq_defs[tag >> 16]->buffer_count);
+ "1803 Bad hbq tag. Data: x%x x%x\n",
+ tag, lpfc_hbq_defs[tag >> 16]->buffer_count);
return NULL;
}
void
-lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *sp)
+lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer)
{
uint32_t hbqno;
- if (sp) {
- hbqno = sp->tag >> 16;
- lpfc_sli_hbq_to_firmware(phba, hbqno, sp);
+ if (hbq_buffer) {
+ hbqno = hbq_buffer->tag >> 16;
+ if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
+ (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
+ }
}
}
@@ -837,12 +865,10 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
*/
if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) ==
MBX_SHUTDOWN) {
-
/* Unknow mailbox command compl */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "%d (%d):0323 Unknown Mailbox command "
+ "(%d):0323 Unknown Mailbox command "
"%x Cmpl\n",
- phba->brd_no,
pmb->vport ? pmb->vport->vpi : 0,
pmbox->mbxCommand);
phba->link_state = LPFC_HBA_ERROR;
@@ -857,10 +883,9 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
/* Mbox cmd cmpl error - RETRYing */
lpfc_printf_log(phba, KERN_INFO,
LOG_MBOX | LOG_SLI,
- "%d (%d):0305 Mbox cmd cmpl "
+ "(%d):0305 Mbox cmd cmpl "
"error - RETRYing Data: x%x "
"x%x x%x x%x\n",
- phba->brd_no,
pmb->vport ? pmb->vport->vpi :0,
pmbox->mbxCommand,
pmbox->mbxStatus,
@@ -879,9 +904,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
/* Mailbox cmd <cmd> Cmpl <cmpl> */
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
- "%d (%d):0307 Mailbox cmd x%x Cmpl x%p "
+ "(%d):0307 Mailbox cmd x%x Cmpl x%p "
"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no,
pmb->vport ? pmb->vport->vpi : 0,
pmbox->mbxCommand,
pmb->mbox_cmpl,
@@ -905,21 +929,26 @@ static struct lpfc_dmabuf *
lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
{
struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
+ uint32_t hbqno;
+ void *virt; /* virtual address ptr */
+ dma_addr_t phys; /* mapped address */
hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
if (hbq_entry == NULL)
return NULL;
list_del(&hbq_entry->dbuf.list);
- new_hbq_entry = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC);
+
+ hbqno = tag >> 16;
+ new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
if (new_hbq_entry == NULL)
return &hbq_entry->dbuf;
- new_hbq_entry->dbuf = hbq_entry->dbuf;
new_hbq_entry->tag = -1;
- hbq_entry->dbuf.virt = lpfc_hbq_alloc(phba, 0, &hbq_entry->dbuf.phys);
- if (hbq_entry->dbuf.virt == NULL) {
- kfree(new_hbq_entry);
- return &hbq_entry->dbuf;
- }
+ phys = new_hbq_entry->dbuf.phys;
+ virt = new_hbq_entry->dbuf.virt;
+ new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys;
+ new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt;
+ hbq_entry->dbuf.phys = phys;
+ hbq_entry->dbuf.virt = virt;
lpfc_sli_free_hbq(phba, hbq_entry);
return &new_hbq_entry->dbuf;
}
@@ -965,7 +994,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
irsp->un.ulpWord[3]);
if (irsp->ulpBdeCount == 2)
saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
- irsp->un.ulpWord[15]);
+ irsp->unsli3.sli3Words[7]);
}
/* unSolicited Responses */
@@ -996,12 +1025,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* Ring <ringno> handler: unexpected
Rctl <Rctl> Type <Type> received */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0313 Ring %d handler: unexpected Rctl x%x "
+ "0313 Ring %d handler: unexpected Rctl x%x "
"Type x%x received\n",
- phba->brd_no,
- pring->ringno,
- Rctl,
- Type);
+ pring->ringno, Rctl, Type);
}
return 1;
}
@@ -1024,10 +1050,9 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
}
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0317 iotag x%x is out off "
+ "0317 iotag x%x is out off "
"range: max iotag x%x wd0 x%x\n",
- phba->brd_no, iotag,
- phba->sli.last_iotag,
+ iotag, phba->sli.last_iotag,
*(((uint32_t *) &prspiocb->iocb) + 7));
return NULL;
}
@@ -1075,18 +1100,16 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* Ring <ringno> handler: unexpected completion IoTag
* <IoTag>
*/
- lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d (%d):0322 Ring %d handler: "
- "unexpected completion IoTag x%x "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- cmdiocbp->vport->vpi,
- pring->ringno,
- saveq->iocb.ulpIoTag,
- saveq->iocb.ulpStatus,
- saveq->iocb.un.ulpWord[4],
- saveq->iocb.ulpCommand,
- saveq->iocb.ulpContext);
+ lpfc_printf_vlog(cmdiocbp->vport, KERN_WARNING, LOG_SLI,
+ "0322 Ring %d handler: "
+ "unexpected completion IoTag x%x "
+ "Data: x%x x%x x%x x%x\n",
+ pring->ringno,
+ saveq->iocb.ulpIoTag,
+ saveq->iocb.ulpStatus,
+ saveq->iocb.un.ulpWord[4],
+ saveq->iocb.ulpCommand,
+ saveq->iocb.ulpContext);
}
}
@@ -1104,10 +1127,9 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
* rsp ring <portRspMax>
*/
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0312 Ring %d handler: portRspPut %d "
+ "0312 Ring %d handler: portRspPut %d "
"is bigger then rsp ring %d\n",
- phba->brd_no, pring->ringno,
- le32_to_cpu(pgp->rspPutInx),
+ pring->ringno, le32_to_cpu(pgp->rspPutInx),
pring->numRiocb);
phba->link_state = LPFC_HBA_ERROR;
@@ -1177,9 +1199,9 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
if (unlikely(irsp->ulpStatus)) {
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0326 Rsp Ring %d error: IOCB Data: "
+ "0326 Rsp Ring %d error: IOCB Data: "
"x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no, pring->ringno,
+ pring->ringno,
irsp->un.ulpWord[0],
irsp->un.ulpWord[1],
irsp->un.ulpWord[2],
@@ -1199,9 +1221,9 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
*/
if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0314 IOCB cmd 0x%x"
- " processed. Skipping"
- " completion", phba->brd_no,
+ "0314 IOCB cmd 0x%x "
+ "processed. Skipping "
+ "completion",
irsp->ulpCommand);
break;
}
@@ -1226,10 +1248,9 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0321 Unknown IOCB command "
+ "0321 Unknown IOCB command "
"Data: x%x, x%x x%x x%x x%x\n",
- phba->brd_no, type,
- irsp->ulpCommand,
+ type, irsp->ulpCommand,
irsp->ulpStatus,
irsp->ulpIoTag,
irsp->ulpContext);
@@ -1353,9 +1374,9 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0336 Rsp Ring %d error: IOCB Data: "
+ "0336 Rsp Ring %d error: IOCB Data: "
"x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no, pring->ringno,
+ pring->ringno,
irsp->un.ulpWord[0],
irsp->un.ulpWord[1],
irsp->un.ulpWord[2],
@@ -1375,10 +1396,9 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
*/
if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0333 IOCB cmd 0x%x"
+ "0333 IOCB cmd 0x%x"
" processed. Skipping"
" completion\n",
- phba->brd_no,
irsp->ulpCommand);
break;
}
@@ -1415,10 +1435,9 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0334 Unknown IOCB command "
+ "0334 Unknown IOCB command "
"Data: x%x, x%x x%x x%x x%x\n",
- phba->brd_no, type,
- irsp->ulpCommand,
+ type, irsp->ulpCommand,
irsp->ulpStatus,
irsp->ulpIoTag,
irsp->ulpContext);
@@ -1496,10 +1515,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
* rsp ring <portRspMax>
*/
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0303 Ring %d handler: portRspPut %d "
+ "0303 Ring %d handler: portRspPut %d "
"is bigger then rsp ring %d\n",
- phba->brd_no, pring->ringno, portRspPut,
- portRspMax);
+ pring->ringno, portRspPut, portRspMax);
phba->link_state = LPFC_HBA_ERROR;
spin_unlock_irqrestore(&phba->hbalock, iflag);
@@ -1542,6 +1560,14 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
+ if (pring->ringno == LPFC_ELS_RING) {
+ lpfc_debugfs_slow_ring_trc(phba,
+ "IOCB rsp ring: wd4:x%08x wd6:x%08x wd7:x%08x",
+ *(((uint32_t *) irsp) + 4),
+ *(((uint32_t *) irsp) + 6),
+ *(((uint32_t *) irsp) + 7));
+ }
+
writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (list_empty(&(pring->iocb_continueq))) {
@@ -1580,13 +1606,12 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
if (irsp->ulpStatus) {
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0328 Rsp Ring %d error: "
+ "0328 Rsp Ring %d error: "
"IOCB Data: "
"x%x x%x x%x x%x "
"x%x x%x x%x x%x "
"x%x x%x x%x x%x "
"x%x x%x x%x x%x\n",
- phba->brd_no,
pring->ringno,
irsp->un.ulpWord[0],
irsp->un.ulpWord[1],
@@ -1661,10 +1686,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0335 Unknown IOCB "
+ "0335 Unknown IOCB "
"command Data: x%x "
"x%x x%x x%x\n",
- phba->brd_no,
irsp->ulpCommand,
irsp->ulpStatus,
irsp->ulpIoTag,
@@ -1892,8 +1916,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
/* Kill HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0329 Kill HBA Data: x%x x%x\n",
- phba->brd_no, phba->pport->port_state, psli->sli_flag);
+ "0329 Kill HBA Data: x%x x%x\n",
+ phba->pport->port_state, psli->sli_flag);
if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL)) == 0)
@@ -1966,7 +1990,7 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
/* Reset HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,
+ "0325 Reset HBA Data: x%x x%x\n",
phba->pport->port_state, psli->sli_flag);
/* perform board reset */
@@ -2021,7 +2045,7 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba)
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
+ "0337 Restart HBA Data: x%x x%x\n",
phba->pport->port_state, psli->sli_flag);
word0 = 0;
@@ -2086,9 +2110,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
/* Adapter failed to init, timeout, status reg
<status> */
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0436 Adapter failed to init, "
- "timeout, status reg x%x\n",
- phba->brd_no, status);
+ "0436 Adapter failed to init, "
+ "timeout, status reg x%x\n", status);
phba->link_state = LPFC_HBA_ERROR;
return -ETIMEDOUT;
}
@@ -2099,10 +2122,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
/* Adapter failed to init, chipset, status reg
<status> */
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0437 Adapter failed to init, "
- "chipset, status reg x%x\n",
- phba->brd_no,
- status);
+ "0437 Adapter failed to init, "
+ "chipset, status reg x%x\n", status);
phba->link_state = LPFC_HBA_ERROR;
return -EIO;
}
@@ -2129,10 +2150,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
/* ERROR: During chipset initialization */
/* Adapter failed to init, chipset, status reg <status> */
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0438 Adapter failed to init, chipset, "
- "status reg x%x\n",
- phba->brd_no,
- status);
+ "0438 Adapter failed to init, chipset, "
+ "status reg x%x\n", status);
phba->link_state = LPFC_HBA_ERROR;
return -EIO;
}
@@ -2147,7 +2166,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
return 0;
}
-static int
+int
lpfc_sli_hbq_count(void)
{
return ARRAY_SIZE(lpfc_hbq_defs);
@@ -2200,8 +2219,8 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
phba->hbqs[hbqno].local_hbqGetIdx = 0;
phba->hbqs[hbqno].entry_count =
lpfc_hbq_defs[hbqno]->entry_count;
- lpfc_config_hbq(phba, lpfc_hbq_defs[hbqno], hbq_entry_index,
- pmb);
+ lpfc_config_hbq(phba, hbqno, lpfc_hbq_defs[hbqno],
+ hbq_entry_index, pmb);
hbq_entry_index += phba->hbqs[hbqno].entry_count;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
@@ -2210,9 +2229,9 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_ERR,
LOG_SLI | LOG_VPORT,
- "%d:1805 Adapter failed to init. "
+ "1805 Adapter failed to init. "
"Data: x%x x%x x%x\n",
- phba->brd_no, pmbox->mbxCommand,
+ pmbox->mbxCommand,
pmbox->mbxStatus, hbqno);
phba->link_state = LPFC_HBA_ERROR;
@@ -2279,10 +2298,9 @@ lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0442 Adapter failed to init, mbxCmd x%x "
+ "0442 Adapter failed to init, mbxCmd x%x "
"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
- phba->brd_no, pmb->mb.mbxCommand,
- pmb->mb.mbxStatus, 0);
+ pmb->mb.mbxCommand, pmb->mb.mbxStatus, 0);
spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
spin_unlock_irq(&phba->hbalock);
@@ -2321,11 +2339,11 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
switch (lpfc_sli_mode) {
case 2:
- if (phba->cfg_npiv_enable) {
+ if (phba->cfg_enable_npiv) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
- "%d:1824 NPIV enabled: Override lpfc_sli_mode "
+ "1824 NPIV enabled: Override lpfc_sli_mode "
"parameter (%d) to auto (0).\n",
- phba->brd_no, lpfc_sli_mode);
+ lpfc_sli_mode);
break;
}
mode = 2;
@@ -2335,9 +2353,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
break;
default:
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
- "%d:1819 Unrecognized lpfc_sli_mode "
- "parameter: %d.\n",
- phba->brd_no, lpfc_sli_mode);
+ "1819 Unrecognized lpfc_sli_mode "
+ "parameter: %d.\n", lpfc_sli_mode);
break;
}
@@ -2345,9 +2362,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
rc = lpfc_do_config_port(phba, mode);
if (rc && lpfc_sli_mode == 3)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
- "%d:1820 Unable to select SLI-3. "
- "Not supported by adapter.\n",
- phba->brd_no);
+ "1820 Unable to select SLI-3. "
+ "Not supported by adapter.\n");
if (rc && mode != 2)
rc = lpfc_do_config_port(phba, 2);
if (rc)
@@ -2366,8 +2382,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
}
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0444 Firmware in SLI %x mode. Max_vpi %d\n",
- phba->brd_no, phba->sli_rev, phba->max_vpi);
+ "0444 Firmware in SLI %x mode. Max_vpi %d\n",
+ phba->sli_rev, phba->max_vpi);
rc = lpfc_sli_ring_map(phba);
if (rc)
@@ -2392,8 +2408,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
lpfc_sli_hba_setup_error:
phba->link_state = LPFC_HBA_ERROR;
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0445 Firmware initialization failed\n",
- phba->brd_no);
+ "0445 Firmware initialization failed\n");
return rc;
}
@@ -2445,9 +2460,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
/* Mbox cmd <mbxCommand> timeout */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "%d:0310 Mailbox command x%x timeout Data: x%x x%x "
- "x%p\n",
- phba->brd_no,
+ "0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
mb->mbxCommand,
phba->pport->port_state,
phba->sli.sli_flag,
@@ -2470,8 +2483,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
lpfc_sli_abort_iocb_ring(phba, pring);
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "%d:0316 Resetting board due to mailbox timeout\n",
- phba->brd_no);
+ "0316 Resetting board due to mailbox timeout\n");
/*
* lpfc_offline calls lpfc_sli_hba_down which will clean up
* on oustanding mailbox commands.
@@ -2502,8 +2514,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
if(!pmbox->vport) {
lpfc_printf_log(phba, KERN_ERR,
LOG_MBOX | LOG_VPORT,
- "%d:1806 Mbox x%x failed. No vport\n",
- phba->brd_no,
+ "1806 Mbox x%x failed. No vport\n",
pmbox->mb.mbxCommand);
dump_stack();
return MBXERR_ERROR;
@@ -2580,9 +2591,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
/* Mbox cmd issue - BUSY */
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
- "%d (%d):0308 Mbox cmd issue - BUSY Data: "
+ "(%d):0308 Mbox cmd issue - BUSY Data: "
"x%x x%x x%x x%x\n",
- phba->brd_no,
pmbox->vport ? pmbox->vport->vpi : 0xffffff,
mb->mbxCommand, phba->pport->port_state,
psli->sli_flag, flag);
@@ -2644,9 +2654,9 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
/* Mailbox cmd <cmd> issue */
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
- "%d (%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
+ "(%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
"x%x\n",
- phba->brd_no, pmbox->vport ? pmbox->vport->vpi : 0,
+ pmbox->vport ? pmbox->vport->vpi : 0,
mb->mbxCommand, phba->pport->port_state,
psli->sli_flag, flag);
@@ -2848,8 +2858,7 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
lpfc_printf_log(phba, KERN_ERR,
LOG_SLI | LOG_VPORT,
- "%d:1807 IOCB x%x failed. No vport\n",
- phba->brd_no,
+ "1807 IOCB x%x failed. No vport\n",
piocb->iocb.ulpCommand);
dump_stack();
return IOCB_ERROR;
@@ -3080,11 +3089,10 @@ lpfc_sli_setup(struct lpfc_hba *phba)
}
if (totiocbsize > MAX_SLIM_IOCB_SIZE) {
/* Too many cmd / rsp ring entries in SLI2 SLIM */
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0462 Too many cmd / rsp ring entries in "
- "SLI2 SLIM Data: x%x x%lx\n",
- phba->brd_no, totiocbsize,
- (unsigned long) MAX_SLIM_IOCB_SIZE);
+ printk(KERN_ERR "%d:0462 Too many cmd / rsp ring entries in "
+ "SLI2 SLIM Data: x%x x%lx\n",
+ phba->brd_no, totiocbsize,
+ (unsigned long) MAX_SLIM_IOCB_SIZE);
}
if (phba->cfg_multi_ring_support == 2)
lpfc_extra_ring_setup(phba);
@@ -3305,9 +3313,9 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "%d:0410 Cannot find virtual addr for mapped buf on "
+ "0410 Cannot find virtual addr for mapped buf on "
"ring %d Data x%llx x%p x%p x%x\n",
- phba->brd_no, pring->ringno, (unsigned long long)phys,
+ pring->ringno, (unsigned long long)phys,
slp->next, slp->prev, pring->postbufq_cnt);
return NULL;
}
@@ -3332,12 +3340,11 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
- "%d:0327 Cannot abort els iocb %p "
+ "0327 Cannot abort els iocb %p "
"with tag %x context %x, abort status %x, "
"abort code %x\n",
- phba->brd_no, abort_iocb, abort_iotag,
- abort_context, irsp->ulpStatus,
- irsp->un.ulpWord[4]);
+ abort_iocb, abort_iotag, abort_context,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
/*
* make sure we have the right iocbq before taking it
@@ -3371,9 +3378,9 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* ELS cmd tag <ulpIoTag> completes */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d (X):0133 Ignoring ELS cmd tag x%x completion Data: "
+ "0133 Ignoring ELS cmd tag x%x completion Data: "
"x%x x%x x%x\n",
- phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus,
+ irsp->ulpIoTag, irsp->ulpStatus,
irsp->un.ulpWord[4], irsp->ulpTimeout);
if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR)
lpfc_ct_free_iocb(phba, cmdiocb);
@@ -3439,12 +3446,11 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d (%d):0339 Abort xri x%x, original iotag x%x, "
- "abort cmd iotag x%x\n",
- phba->brd_no, vport->vpi,
- iabt->un.acxri.abortContextTag,
- iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+ "0339 Abort xri x%x, original iotag x%x, "
+ "abort cmd iotag x%x\n",
+ iabt->un.acxri.abortContextTag,
+ iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
abort_iotag_exit:
@@ -3457,8 +3463,8 @@ abort_iotag_exit:
}
static int
-lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
- uint64_t lun_id, uint32_t ctx,
+lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
+ uint16_t tgt_id, uint64_t lun_id,
lpfc_ctx_cmd ctx_cmd)
{
struct lpfc_scsi_buf *lpfc_cmd;
@@ -3468,6 +3474,9 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
if (!(iocbq->iocb_flag & LPFC_IO_FCP))
return rc;
+ if (iocbq->vport != vport)
+ return rc;
+
lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
cmnd = lpfc_cmd->pCmd;
@@ -3484,10 +3493,6 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
if (cmnd->device->id == tgt_id)
rc = 0;
break;
- case LPFC_CTX_CTX:
- if (iocbq->iocb.ulpContext == ctx)
- rc = 0;
- break;
case LPFC_CTX_HOST:
rc = 0;
break;
@@ -3501,17 +3506,18 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
}
int
-lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
+lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
+ lpfc_ctx_cmd ctx_cmd)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *iocbq;
int sum, i;
for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
iocbq = phba->sli.iocbq_lookup[i];
- if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
- 0, ctx_cmd) == 0)
+ if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id,
+ ctx_cmd) == 0)
sum++;
}
@@ -3527,10 +3533,10 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
int
-lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- uint16_t tgt_id, uint64_t lun_id, uint32_t ctx,
- lpfc_ctx_cmd abort_cmd)
+lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
+ uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd abort_cmd)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *abtsiocb;
IOCB_t *cmd = NULL;
@@ -3540,7 +3546,7 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
for (i = 1; i <= phba->sli.last_iotag; i++) {
iocbq = phba->sli.iocbq_lookup[i];
- if (lpfc_sli_validate_fcp_iocb(iocbq, tgt_id, lun_id, 0,
+ if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
abort_cmd) != 0)
continue;
@@ -3647,25 +3653,23 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
if (piocb->iocb_flag & LPFC_IO_WAKE) {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0331 IOCB wake signaled\n",
- phba->brd_no);
+ "0331 IOCB wake signaled\n");
} else if (timeleft == 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0338 IOCB wait timeout error - no "
- "wake response Data x%x\n",
- phba->brd_no, timeout);
+ "0338 IOCB wait timeout error - no "
+ "wake response Data x%x\n", timeout);
retval = IOCB_TIMEDOUT;
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0330 IOCB wake NOT set, "
- "Data x%x x%lx\n", phba->brd_no,
+ "0330 IOCB wake NOT set, "
+ "Data x%x x%lx\n",
timeout, (timeleft / jiffies));
retval = IOCB_TIMEDOUT;
}
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0332 IOCB wait issue failed, Data x%x\n",
- phba->brd_no, retval);
+ ":0332 IOCB wait issue failed, Data x%x\n",
+ retval);
retval = IOCB_ERROR;
}
@@ -3850,12 +3854,33 @@ lpfc_intr_handler(int irq, void *dev_id)
if (status & HA_RXMASK) {
spin_lock(&phba->hbalock);
control = readl(phba->HCregaddr);
+
+ lpfc_debugfs_slow_ring_trc(phba,
+ "ISR slow ring: ctl:x%x stat:x%x isrcnt:x%x",
+ control, status,
+ (uint32_t)phba->sli.slistat.sli_intr);
+
if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
+ lpfc_debugfs_slow_ring_trc(phba,
+ "ISR Disable ring:"
+ "pwork:x%x hawork:x%x wait:x%x",
+ phba->work_ha, work_ha_copy,
+ (uint32_t)((unsigned long)
+ phba->work_wait));
+
control &=
~(HC_R0INT_ENA << LPFC_ELS_RING);
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
+ else {
+ lpfc_debugfs_slow_ring_trc(phba,
+ "ISR slow ring: pwork:"
+ "x%x hawork:x%x wait:x%x",
+ phba->work_ha, work_ha_copy,
+ (uint32_t)((unsigned long)
+ phba->work_wait));
+ }
spin_unlock(&phba->hbalock);
}
}
@@ -3895,12 +3920,10 @@ lpfc_intr_handler(int irq, void *dev_id)
*/
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
LOG_SLI,
- "%d (%d):0304 Stray Mailbox "
+ "(%d):0304 Stray Mailbox "
"Interrupt mbxCommand x%x "
"mbxStatus x%x\n",
- phba->brd_no,
- (vport
- ? vport->vpi : 0),
+ (vport ? vport->vpi : 0),
pmbox->mbxCommand,
pmbox->mbxStatus);
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 76058505795e..51b2b6b949be 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -26,7 +26,6 @@ struct lpfc_vport;
typedef enum _lpfc_ctx_cmd {
LPFC_CTX_LUN,
LPFC_CTX_TGT,
- LPFC_CTX_CTX,
LPFC_CTX_HOST
} lpfc_ctx_cmd;
@@ -54,9 +53,10 @@ struct lpfc_iocbq {
void *context2; /* caller context information */
void *context3; /* caller context information */
union {
- wait_queue_head_t *wait_queue;
- struct lpfc_iocbq *rsp_iocb;
- struct lpfcMboxq *mbox;
+ wait_queue_head_t *wait_queue;
+ struct lpfc_iocbq *rsp_iocb;
+ struct lpfcMboxq *mbox;
+ struct lpfc_nodelist *ndlp;
} context_un;
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
@@ -143,7 +143,7 @@ struct lpfc_sli_ring {
uint16_t numCiocb; /* number of command iocb's per ring */
uint16_t numRiocb; /* number of rsp iocb's per ring */
uint16_t sizeCiocb; /* Size of command iocb's in this ring */
- uint16_t sizeRiocb; /* Size of response iocb's in this ring */
+ uint16_t sizeRiocb; /* Size of response iocb's in this ring */
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index a5bc79eef052..0081f49286bc 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,12 +18,10 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.2.1"
+#define LPFC_DRIVER_VERSION "8.2.2"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
LPFC_DRIVER_VERSION
#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex. All rights reserved."
-
-#define DFC_API_VERSION "0.0.0"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 85797dbf5478..dcb415e717c3 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -125,11 +125,10 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
pmb->vport = vport;
rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
- "%d (%d):1818 VPort failed init, mbxCmd x%x "
- "READ_SPARM mbxStatus x%x, rc = x%x\n",
- phba->brd_no, vport->vpi,
- mb->mbxCommand, mb->mbxStatus, rc);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "1818 VPort failed init, mbxCmd x%x "
+ "READ_SPARM mbxStatus x%x, rc = x%x\n",
+ mb->mbxCommand, mb->mbxStatus, rc);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
if (rc != MBX_TIMEOUT)
@@ -162,9 +161,9 @@ lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn,
return 1;
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1822 Invalid %s: %02x:%02x:%02x:%02x:"
+ "1822 Invalid %s: %02x:%02x:%02x:%02x:"
"%02x:%02x:%02x:%02x\n",
- phba->brd_no, name_type,
+ name_type,
wwn->u.wwn[0], wwn->u.wwn[1],
wwn->u.wwn[2], wwn->u.wwn[3],
wwn->u.wwn[4], wwn->u.wwn[5],
@@ -176,16 +175,21 @@ static int
lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
{
struct lpfc_vport *vport;
+ unsigned long flags;
+ spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport == new_vport)
continue;
/* If they match, return not unique */
if (memcmp(&vport->fc_sparam.portName,
- &new_vport->fc_sparam.portName,
- sizeof(struct lpfc_name)) == 0)
+ &new_vport->fc_sparam.portName,
+ sizeof(struct lpfc_name)) == 0) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return 0;
+ }
}
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return 1;
}
@@ -193,8 +197,8 @@ int
lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
{
struct lpfc_nodelist *ndlp;
- struct lpfc_vport *pport =
- (struct lpfc_vport *) fc_vport->shost->hostdata;
+ struct Scsi_Host *shost = fc_vport->shost;
+ struct lpfc_vport *pport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = pport->phba;
struct lpfc_vport *vport = NULL;
int instance;
@@ -204,9 +208,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
if ((phba->sli_rev < 3) ||
!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1808 Create VPORT failed: "
+ "1808 Create VPORT failed: "
"NPIV is not enabled: SLImode:%d\n",
- phba->brd_no, phba->sli_rev);
+ phba->sli_rev);
rc = VPORT_INVAL;
goto error_out;
}
@@ -214,9 +218,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
vpi = lpfc_alloc_vpi(phba);
if (vpi == 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1809 Create VPORT failed: "
+ "1809 Create VPORT failed: "
"Max VPORTs (%d) exceeded\n",
- phba->brd_no, phba->max_vpi);
+ phba->max_vpi);
rc = VPORT_NORESOURCES;
goto error_out;
}
@@ -225,18 +229,17 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
/* Assign an unused board number */
if ((instance = lpfc_get_instance()) < 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1810 Create VPORT failed: Cannot get "
- "instance number\n", phba->brd_no);
+ "1810 Create VPORT failed: Cannot get "
+ "instance number\n");
lpfc_free_vpi(phba, vpi);
rc = VPORT_NORESOURCES;
goto error_out;
}
- vport = lpfc_create_port(phba, instance, fc_vport);
+ vport = lpfc_create_port(phba, instance, &fc_vport->dev);
if (!vport) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1811 Create VPORT failed: vpi x%x\n",
- phba->brd_no, vpi);
+ "1811 Create VPORT failed: vpi x%x\n", vpi);
lpfc_free_vpi(phba, vpi);
rc = VPORT_NORESOURCES;
goto error_out;
@@ -246,10 +249,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
lpfc_debugfs_initialize(vport);
if (lpfc_vport_sparm(phba, vport)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1813 Create VPORT failed: vpi:%d "
- "Cannot get sparam\n",
- phba->brd_no, vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1813 Create VPORT failed. "
+ "Cannot get sparam\n");
lpfc_free_vpi(phba, vpi);
destroy_port(vport);
rc = VPORT_NORESOURCES;
@@ -269,10 +271,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") ||
!lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) {
- lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1821 Create VPORT failed: vpi:%d "
- "Invalid WWN format\n",
- phba->brd_no, vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1821 Create VPORT failed. "
+ "Invalid WWN format\n");
lpfc_free_vpi(phba, vpi);
destroy_port(vport);
rc = VPORT_INVAL;
@@ -280,10 +281,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
}
if (!lpfc_unique_wwpn(phba, vport)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1823 Create VPORT failed: vpi:%d "
- "Duplicate WWN on HBA\n",
- phba->brd_no, vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1823 Create VPORT failed. "
+ "Duplicate WWN on HBA\n");
lpfc_free_vpi(phba, vpi);
destroy_port(vport);
rc = VPORT_INVAL;
@@ -315,10 +315,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
lpfc_initial_fdisc(vport);
} else {
lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0262 No NPIV Fabric "
- "support\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0262 No NPIV Fabric support\n");
}
} else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
@@ -326,12 +324,14 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
rc = VPORT_OK;
out:
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1825 Vport Created.\n");
lpfc_host_attrib_init(lpfc_shost_from_vport(vport));
error_out:
return rc;
}
-int
+static int
disable_vport(struct fc_vport *fc_vport)
{
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
@@ -371,10 +371,12 @@ disable_vport(struct fc_vport *fc_vport)
lpfc_mbx_unreg_vpi(vport);
lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1826 Vport Disabled.\n");
return VPORT_OK;
}
-int
+static int
enable_vport(struct fc_vport *fc_vport)
{
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
@@ -400,15 +402,14 @@ enable_vport(struct fc_vport *fc_vport)
lpfc_initial_fdisc(vport);
} else {
lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
- lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d (%d):0264 No NPIV Fabric "
- "support\n",
- phba->brd_no, vport->vpi);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0264 No NPIV Fabric support\n");
}
} else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
}
-
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1827 Vport Enabled.\n");
return VPORT_OK;
}
@@ -431,8 +432,29 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba;
long timeout;
- int rc = VPORT_ERROR;
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1812 vport_delete failed: Cannot delete "
+ "physical host\n");
+ return VPORT_ERROR;
+ }
+ /*
+ * If we are not unloading the driver then prevent the vport_delete
+ * from happening until after this vport's discovery is finished.
+ */
+ if (!(phba->pport->load_flag & FC_UNLOADING)) {
+ int check_count = 0;
+ while (check_count < ((phba->fc_ratov * 3) + 3) &&
+ vport->port_state > LPFC_VPORT_FAILED &&
+ vport->port_state < LPFC_VPORT_READY) {
+ check_count++;
+ msleep(1000);
+ }
+ if (vport->port_state > LPFC_VPORT_FAILED &&
+ vport->port_state < LPFC_VPORT_READY)
+ return -EAGAIN;
+ }
/*
* This is a bit of a mess. We want to ensure the shost doesn't get
* torn down until we're done with the embedded lpfc_vport structure.
@@ -450,16 +472,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
*/
if (!scsi_host_get(shost) || !scsi_host_get(shost))
return VPORT_INVAL;
-
- if (vport->port_type == LPFC_PHYSICAL_PORT) {
- lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
- "%d:1812 vport_delete failed: Cannot delete "
- "physical host\n", phba->brd_no);
- goto out;
- }
-
+ spin_lock_irq(&phba->hbalock);
vport->load_flag |= FC_UNLOADING;
-
+ spin_unlock_irq(&phba->hbalock);
kfree(vport->vname);
lpfc_debugfs_terminate(vport);
fc_remove_host(lpfc_shost_from_vport(vport));
@@ -511,13 +526,46 @@ skip_logo:
spin_lock_irq(&phba->hbalock);
list_del_init(&vport->listentry);
spin_unlock_irq(&phba->hbalock);
-
- rc = VPORT_OK;
-out:
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+ "1828 Vport Deleted.\n");
scsi_host_put(shost);
- return rc;
+ return VPORT_OK;
}
-
EXPORT_SYMBOL(lpfc_vport_create);
EXPORT_SYMBOL(lpfc_vport_delete);
+
+struct lpfc_vport **
+lpfc_create_vport_work_array(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *port_iterator;
+ struct lpfc_vport **vports;
+ int index = 0;
+ vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
+ GFP_KERNEL);
+ if (vports == NULL)
+ return NULL;
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+ if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
+ lpfc_printf_vlog(port_iterator, KERN_WARNING, LOG_VPORT,
+ "1801 Create vport work array FAILED: "
+ "cannot do scsi_host_get\n");
+ continue;
+ }
+ vports[index++] = port_iterator;
+ }
+ spin_unlock_irq(&phba->hbalock);
+ return vports;
+}
+
+void
+lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
+{
+ int i;
+ if (vports == NULL)
+ return;
+ for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
+ scsi_host_put(lpfc_shost_from_vport(vports[i]));
+ kfree(vports);
+}
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
index f223550f8cba..91da17751a37 100644
--- a/drivers/scsi/lpfc/lpfc_vport.h
+++ b/drivers/scsi/lpfc/lpfc_vport.h
@@ -88,6 +88,8 @@ int lpfc_vport_create(struct fc_vport *, bool);
int lpfc_vport_delete(struct fc_vport *);
int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
+struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
+void lpfc_destroy_vport_work_array(struct lpfc_vport **);
/*
* queuecommand VPORT-specific return codes. Specified in the host byte code.
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 3907f6718ede..da56163c30a8 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1753,6 +1753,14 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
*len = 0;
+ if (scsi_sg_count(cmd) == 1 && !adapter->has_64bit_addr) {
+ sg = scsi_sglist(cmd);
+ scb->dma_h_bulkdata = sg_dma_address(sg);
+ *buf = (u32)scb->dma_h_bulkdata;
+ *len = sg_dma_len(sg);
+ return 0;
+ }
+
scsi_for_each_sg(cmd, sg, sgcnt, idx) {
if (adapter->has_64bit_addr) {
scb->sgl64[idx].address = sg_dma_address(sg);
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index c46685a03a9f..c6a53dccc16a 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -454,7 +454,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_master(pdev);
// Allocate the per driver initialization structure
- adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
+ adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL);
if (adapter == NULL) {
con_log(CL_ANN, (KERN_WARNING
@@ -462,7 +462,6 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_probe_one;
}
- memset(adapter, 0, sizeof(adapter_t));
// set up PCI related soft state and other pre-known parameters
@@ -746,10 +745,9 @@ megaraid_init_mbox(adapter_t *adapter)
* Allocate and initialize the init data structure for mailbox
* controllers
*/
- raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
+ raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL);
if (raid_dev == NULL) return -1;
- memset(raid_dev, 0, sizeof(mraid_device_t));
/*
* Attach the adapter soft state to raid device soft state
@@ -1050,8 +1048,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
* since the calling routine does not yet know the number of available
* commands.
*/
- adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
- GFP_KERNEL);
+ adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL);
if (adapter->kscb_list == NULL) {
con_log(CL_ANN, (KERN_WARNING
@@ -1059,7 +1056,6 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
__LINE__));
goto out_free_ibuf;
}
- memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
// memory allocation for our command packets
if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
@@ -3495,8 +3491,7 @@ megaraid_cmm_register(adapter_t *adapter)
int i;
// Allocate memory for the base list of scb for management module.
- adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
- GFP_KERNEL);
+ adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL);
if (adapter->uscb_list == NULL) {
con_log(CL_ANN, (KERN_WARNING
@@ -3504,7 +3499,6 @@ megaraid_cmm_register(adapter_t *adapter)
__LINE__));
return -1;
}
- memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
// Initialize the synchronization parameters for resources for
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index 84d9c27133d4..b6587a6d8486 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -890,12 +890,11 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
if (lld_adp->drvr_type != DRVRTYPE_MBOX)
return (-EINVAL);
- adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
+ adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
- memset(adapter, 0, sizeof(mraid_mmadp_t));
adapter->unique_id = lld_adp->unique_id;
adapter->drvr_type = lld_adp->drvr_type;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index b7f2e613c903..ebb948c016bb 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -1636,15 +1636,13 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
* Allocate the dynamic array first and then allocate individual
* commands.
*/
- instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd,
- GFP_KERNEL);
+ instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
if (!instance->cmd_list) {
printk(KERN_DEBUG "megasas: out of memory\n");
return -ENOMEM;
}
- memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd);
for (i = 0; i < max_cmd; i++) {
instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
index d6ef22a941c4..1bdddad48571 100644
--- a/drivers/scsi/mvme16x_scsi.c
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -89,6 +89,7 @@ mvme16x_probe(struct device *dev)
out_be32(0xfff4202c, v);
}
+ dev_set_drvdata(dev, host);
scsi_scan_host(host);
return 0;
@@ -104,7 +105,7 @@ mvme16x_probe(struct device *dev)
static __devexit int
mvme16x_device_remove(struct device *dev)
{
- struct Scsi_Host *host = dev_to_shost(dev);
+ struct Scsi_Host *host = dev_get_drvdata(dev);
struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
/* Disable scsi chip ints */
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index 7dd787f6ab27..fa481b515ead 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -2,9 +2,12 @@
# PCMCIA SCSI adapter configuration
#
-menu "PCMCIA SCSI adapter support"
+menuconfig SCSI_LOWLEVEL_PCMCIA
+ bool "PCMCIA SCSI adapter support"
depends on SCSI!=n && PCMCIA!=n
+if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
+
config PCMCIA_AHA152X
tristate "Adaptec AHA152X PCMCIA support"
depends on !64BIT
@@ -77,4 +80,4 @@ config PCMCIA_SYM53C500
To compile this driver as a module, choose M here: the
module will be called sym53c500_cs.
-endmenu
+endif # SCSI_LOWLEVEL_PCMCIA
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 370802d24acd..2dd0dc9a9aed 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -106,9 +106,8 @@ static int aha152x_probe(struct pcmcia_device *link)
DEBUG(0, "aha152x_attach()\n");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) return -ENOMEM;
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index c6f8c6e65e05..445cfbbca9b3 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1602,9 +1602,8 @@ static int nsp_cs_probe(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "in");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) { return -ENOMEM; }
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
data->ScsiInfo = info;
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 697cfb76c3a4..67c5a58d17df 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -162,10 +162,9 @@ static int qlogic_probe(struct pcmcia_device *link)
DEBUG(0, "qlogic_attach()\n");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
link->io.NumPorts1 = 16;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 2695b7187b2f..961839ecfe86 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -875,10 +875,9 @@ SYM53C500_probe(struct pcmcia_device *link)
DEBUG(0, "SYM53C500_attach()\n");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
link->io.NumPorts1 = 16;
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 2f1fa1eb7e90..67b6d76a6c8d 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -1014,10 +1014,9 @@ static int __ppa_attach(struct parport *pb)
int modes, ppb, ppb_hi;
int err = -ENOMEM;
- dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL);
+ dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(ppa_struct));
dev->base = -1;
dev->mode = PPA_AUTODETECT;
dev->recon_tmo = PPA_RECON_TMO;
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
new file mode 100644
index 000000000000..b50f1e14f2a5
--- /dev/null
+++ b/drivers/scsi/ps3rom.c
@@ -0,0 +1,533 @@
+/*
+ * PS3 BD/DVD/CD-ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdrom.h>
+#include <linux/highmem.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME "ps3rom"
+
+#define BOUNCE_SIZE (64*1024)
+
+#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE)
+
+
+struct ps3rom_private {
+ struct ps3_storage_device *dev;
+ struct scsi_cmnd *curr_cmd;
+};
+
+
+#define LV1_STORAGE_SEND_ATAPI_COMMAND (1)
+
+struct lv1_atapi_cmnd_block {
+ u8 pkt[32]; /* packet command block */
+ u32 pktlen; /* should be 12 for ATAPI 8020 */
+ u32 blocks;
+ u32 block_size;
+ u32 proto; /* transfer mode */
+ u32 in_out; /* transfer direction */
+ u64 buffer; /* parameter except command block */
+ u32 arglen; /* length above */
+};
+
+enum lv1_atapi_proto {
+ NON_DATA_PROTO = 0,
+ PIO_DATA_IN_PROTO = 1,
+ PIO_DATA_OUT_PROTO = 2,
+ DMA_PROTO = 3
+};
+
+enum lv1_atapi_in_out {
+ DIR_WRITE = 0, /* memory -> device */
+ DIR_READ = 1 /* device -> memory */
+};
+
+
+static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
+{
+ struct ps3rom_private *priv = shost_priv(scsi_dev->host);
+ struct ps3_storage_device *dev = priv->dev;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__,
+ __LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
+
+ /*
+ * ATAPI SFF8020 devices use MODE_SENSE_10,
+ * so we can prohibit MODE_SENSE_6
+ */
+ scsi_dev->use_10_for_ms = 1;
+
+ /* we don't support {READ,WRITE}_6 */
+ scsi_dev->use_10_for_rw = 1;
+
+ return 0;
+}
+
+/*
+ * copy data from device into scatter/gather buffer
+ */
+static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
+{
+ int k, req_len, act_len, len, active;
+ void *kaddr;
+ struct scatterlist *sgpnt;
+ unsigned int buflen;
+
+ buflen = cmd->request_bufflen;
+ if (!buflen)
+ return 0;
+
+ if (!cmd->request_buffer)
+ return -1;
+
+ sgpnt = cmd->request_buffer;
+ active = 1;
+ for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ if (active) {
+ kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+ len = sgpnt->length;
+ if ((req_len + len) > buflen) {
+ active = 0;
+ len = buflen - req_len;
+ }
+ memcpy(kaddr + sgpnt->offset, buf + req_len, len);
+ flush_kernel_dcache_page(sgpnt->page);
+ kunmap_atomic(kaddr, KM_IRQ0);
+ act_len += len;
+ }
+ req_len += sgpnt->length;
+ }
+ cmd->resid = req_len - act_len;
+ return 0;
+}
+
+/*
+ * copy data from scatter/gather into device's buffer
+ */
+static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
+{
+ int k, req_len, len, fin;
+ void *kaddr;
+ struct scatterlist *sgpnt;
+ unsigned int buflen;
+
+ buflen = cmd->request_bufflen;
+ if (!buflen)
+ return 0;
+
+ if (!cmd->request_buffer)
+ return -1;
+
+ sgpnt = cmd->request_buffer;
+ for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+ len = sgpnt->length;
+ if ((req_len + len) > buflen) {
+ len = buflen - req_len;
+ fin = 1;
+ }
+ memcpy(buf + req_len, kaddr + sgpnt->offset, len);
+ kunmap_atomic(kaddr, KM_IRQ0);
+ if (fin)
+ return req_len + len;
+ req_len += sgpnt->length;
+ }
+ return req_len;
+}
+
+static int ps3rom_atapi_request(struct ps3_storage_device *dev,
+ struct scsi_cmnd *cmd)
+{
+ struct lv1_atapi_cmnd_block atapi_cmnd;
+ unsigned char opcode = cmd->cmnd[0];
+ int res;
+ u64 lpar;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
+ __LINE__, opcode);
+
+ memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
+ memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
+ atapi_cmnd.pktlen = 12;
+ atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
+ atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+ atapi_cmnd.buffer = dev->bounce_lpar;
+
+ switch (cmd->sc_data_direction) {
+ case DMA_FROM_DEVICE:
+ if (cmd->request_bufflen >= CD_FRAMESIZE)
+ atapi_cmnd.proto = DMA_PROTO;
+ else
+ atapi_cmnd.proto = PIO_DATA_IN_PROTO;
+ atapi_cmnd.in_out = DIR_READ;
+ break;
+
+ case DMA_TO_DEVICE:
+ if (cmd->request_bufflen >= CD_FRAMESIZE)
+ atapi_cmnd.proto = DMA_PROTO;
+ else
+ atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
+ atapi_cmnd.in_out = DIR_WRITE;
+ res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+ if (res < 0)
+ return DID_ERROR << 16;
+ break;
+
+ default:
+ atapi_cmnd.proto = NON_DATA_PROTO;
+ break;
+ }
+
+ lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
+ res = lv1_storage_send_device_command(dev->sbd.dev_id,
+ LV1_STORAGE_SEND_ATAPI_COMMAND,
+ lpar, sizeof(atapi_cmnd),
+ atapi_cmnd.buffer,
+ atapi_cmnd.arglen, &dev->tag);
+ if (res == LV1_DENIED_BY_POLICY) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: ATAPI command 0x%02x denied by policy\n",
+ __func__, __LINE__, opcode);
+ return DID_ERROR << 16;
+ }
+
+ if (res) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
+ __LINE__, opcode, res);
+ return DID_ERROR << 16;
+ }
+
+ return 0;
+}
+
+static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
+{
+ return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
+ cmd->cmnd[5];
+}
+
+static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
+{
+ return cmd->cmnd[7] << 8 | cmd->cmnd[8];
+}
+
+static int ps3rom_read_request(struct ps3_storage_device *dev,
+ struct scsi_cmnd *cmd, u32 start_sector,
+ u32 sectors)
+{
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
+ __func__, __LINE__, sectors, start_sector);
+
+ res = lv1_storage_read(dev->sbd.dev_id,
+ dev->regions[dev->region_idx].id, start_sector,
+ sectors, 0, dev->bounce_lpar, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
+ __LINE__, res);
+ return DID_ERROR << 16;
+ }
+
+ return 0;
+}
+
+static int ps3rom_write_request(struct ps3_storage_device *dev,
+ struct scsi_cmnd *cmd, u32 start_sector,
+ u32 sectors)
+{
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
+ __func__, __LINE__, sectors, start_sector);
+
+ res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+ if (res < 0)
+ return DID_ERROR << 16;
+
+ res = lv1_storage_write(dev->sbd.dev_id,
+ dev->regions[dev->region_idx].id, start_sector,
+ sectors, 0, dev->bounce_lpar, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
+ __LINE__, res);
+ return DID_ERROR << 16;
+ }
+
+ return 0;
+}
+
+static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct ps3rom_private *priv = shost_priv(cmd->device->host);
+ struct ps3_storage_device *dev = priv->dev;
+ unsigned char opcode;
+ int res;
+
+#ifdef DEBUG
+ scsi_print_command(cmd);
+#endif
+
+ priv->curr_cmd = cmd;
+ cmd->scsi_done = done;
+
+ opcode = cmd->cmnd[0];
+ /*
+ * While we can submit READ/WRITE SCSI commands as ATAPI commands,
+ * it's recommended for various reasons (performance, error handling,
+ * ...) to use lv1_storage_{read,write}() instead
+ */
+ switch (opcode) {
+ case READ_10:
+ res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
+ srb10_len(cmd));
+ break;
+
+ case WRITE_10:
+ res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
+ srb10_len(cmd));
+ break;
+
+ default:
+ res = ps3rom_atapi_request(dev, cmd);
+ break;
+ }
+
+ if (res) {
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ cmd->result = res;
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+ priv->curr_cmd = NULL;
+ cmd->scsi_done(cmd);
+ }
+
+ return 0;
+}
+
+static int decode_lv1_status(u64 status, unsigned char *sense_key,
+ unsigned char *asc, unsigned char *ascq)
+{
+ if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
+ return -1;
+
+ *sense_key = (status >> 16) & 0xff;
+ *asc = (status >> 8) & 0xff;
+ *ascq = status & 0xff;
+ return 0;
+}
+
+static irqreturn_t ps3rom_interrupt(int irq, void *data)
+{
+ struct ps3_storage_device *dev = data;
+ struct Scsi_Host *host;
+ struct ps3rom_private *priv;
+ struct scsi_cmnd *cmd;
+ int res;
+ u64 tag, status;
+ unsigned char sense_key, asc, ascq;
+
+ res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+ /*
+ * status = -1 may mean that ATAPI transport completed OK, but
+ * ATAPI command itself resulted CHECK CONDITION
+ * so, upper layer should issue REQUEST_SENSE to check the sense data
+ */
+
+ if (tag != dev->tag)
+ dev_err(&dev->sbd.core,
+ "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ __func__, __LINE__, tag, dev->tag);
+
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ __func__, __LINE__, res, status);
+ return IRQ_HANDLED;
+ }
+
+ host = dev->sbd.core.driver_data;
+ priv = shost_priv(host);
+ cmd = priv->curr_cmd;
+
+ if (!status) {
+ /* OK, completed */
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ res = fill_from_dev_buffer(cmd, dev->bounce_buf);
+ if (res) {
+ cmd->result = DID_ERROR << 16;
+ goto done;
+ }
+ }
+ cmd->result = DID_OK << 16;
+ goto done;
+ }
+
+ if (cmd->cmnd[0] == REQUEST_SENSE) {
+ /* SCSI spec says request sense should never get error */
+ dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
+ __func__, __LINE__);
+ cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
+ goto done;
+ }
+
+ if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
+ cmd->result = DID_ERROR << 16;
+ goto done;
+ }
+
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = sense_key;
+ cmd->sense_buffer[7] = 16 - 6;
+ cmd->sense_buffer[12] = asc;
+ cmd->sense_buffer[13] = ascq;
+ cmd->result = SAM_STAT_CHECK_CONDITION;
+
+done:
+ priv->curr_cmd = NULL;
+ cmd->scsi_done(cmd);
+ return IRQ_HANDLED;
+}
+
+static struct scsi_host_template ps3rom_host_template = {
+ .name = DEVICE_NAME,
+ .slave_configure = ps3rom_slave_configure,
+ .queuecommand = ps3rom_queuecommand,
+ .can_queue = 1,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .emulated = 1, /* only sg driver uses this */
+ .max_sectors = PS3ROM_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .module = THIS_MODULE,
+};
+
+
+static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ int error;
+ struct Scsi_Host *host;
+ struct ps3rom_private *priv;
+
+ if (dev->blk_size != CD_FRAMESIZE) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: cannot handle block size %lu\n", __func__,
+ __LINE__, dev->blk_size);
+ return -EINVAL;
+ }
+
+ dev->bounce_size = BOUNCE_SIZE;
+ dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+ if (!dev->bounce_buf)
+ return -ENOMEM;
+
+ error = ps3stor_setup(dev, ps3rom_interrupt);
+ if (error)
+ goto fail_free_bounce;
+
+ host = scsi_host_alloc(&ps3rom_host_template,
+ sizeof(struct ps3rom_private));
+ if (!host) {
+ dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
+ __func__, __LINE__);
+ goto fail_teardown;
+ }
+
+ priv = shost_priv(host);
+ dev->sbd.core.driver_data = host;
+ priv->dev = dev;
+
+ /* One device/LUN per SCSI bus */
+ host->max_id = 1;
+ host->max_lun = 1;
+
+ error = scsi_add_host(host, &dev->sbd.core);
+ if (error) {
+ dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
+ __func__, __LINE__, error);
+ error = -ENODEV;
+ goto fail_host_put;
+ }
+
+ scsi_scan_host(host);
+ return 0;
+
+fail_host_put:
+ scsi_host_put(host);
+ dev->sbd.core.driver_data = NULL;
+fail_teardown:
+ ps3stor_teardown(dev);
+fail_free_bounce:
+ kfree(dev->bounce_buf);
+ return error;
+}
+
+static int ps3rom_remove(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct Scsi_Host *host = dev->sbd.core.driver_data;
+
+ scsi_remove_host(host);
+ ps3stor_teardown(dev);
+ scsi_host_put(host);
+ dev->sbd.core.driver_data = NULL;
+ kfree(dev->bounce_buf);
+ return 0;
+}
+
+static struct ps3_system_bus_driver ps3rom = {
+ .match_id = PS3_MATCH_ID_STOR_ROM,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3rom_probe,
+ .remove = ps3rom_remove
+};
+
+
+static int __init ps3rom_init(void)
+{
+ return ps3_system_bus_driver_register(&ps3rom);
+}
+
+static void __exit ps3rom_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3rom);
+}
+
+module_init(ps3rom_init);
+module_exit(ps3rom_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 3eb2208675ae..0f2a9f5d801c 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -91,18 +91,20 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
- unsigned long flags;
+ int size = ha->nvram_size;
+ char *nvram_cache = ha->nvram;
- if (!capable(CAP_SYS_ADMIN) || off != 0)
+ if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
return 0;
+ if (off + count > size) {
+ size -= off;
+ count = size;
+ }
- /* Read NVRAM. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
- ha->nvram_size);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ /* Read NVRAM data from cache. */
+ memcpy(buf, &nvram_cache[off], count);
- return ha->nvram_size;
+ return count;
}
static ssize_t
@@ -119,7 +121,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
return 0;
/* Checksum NVRAM. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
uint32_t *iter;
uint32_t chksum;
@@ -143,7 +145,9 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
+ ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
+ ha->isp_ops->read_nvram(ha, (uint8_t *)&ha->nvram, ha->nvram_base,
+ count);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
@@ -206,7 +210,7 @@ static struct bin_attribute sysfs_optrom_attr = {
.name = "optrom",
.mode = S_IRUSR | S_IWUSR,
},
- .size = OPTROM_SIZE_24XX,
+ .size = 0,
.read = qla2x00_sysfs_read_optrom,
.write = qla2x00_sysfs_write_optrom,
};
@@ -252,7 +256,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
}
memset(ha->optrom_buffer, 0, ha->optrom_size);
- ha->isp_ops.read_optrom(ha, ha->optrom_buffer, 0,
+ ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0,
ha->optrom_size);
break;
case 2:
@@ -275,7 +279,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
if (ha->optrom_state != QLA_SWRITING)
break;
- ha->isp_ops.write_optrom(ha, ha->optrom_buffer, 0,
+ ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0,
ha->optrom_size);
break;
}
@@ -298,17 +302,20 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
- unsigned long flags;
+ int size = ha->vpd_size;
+ char *vpd_cache = ha->vpd;
- if (!capable(CAP_SYS_ADMIN) || off != 0)
+ if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
return 0;
+ if (off + count > size) {
+ size -= off;
+ count = size;
+ }
- /* Read NVRAM. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ /* Read NVRAM data from cache. */
+ memcpy(buf, &vpd_cache[off], count);
- return ha->vpd_size;
+ return count;
}
static ssize_t
@@ -325,7 +332,8 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj,
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
+ ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
+ ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd, ha->vpd_base, count);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return count;
@@ -410,7 +418,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
int ret;
for (iter = bin_file_entries; iter->name; iter++) {
- if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+ if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
continue;
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
@@ -429,7 +437,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
struct sysfs_entry *iter;
for (iter = bin_file_entries; iter->name; iter++) {
- if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+ if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
continue;
sysfs_remove_bin_file(&host->shost_gendev.kobj,
@@ -437,7 +445,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
}
if (ha->beacon_blink_led == 1)
- ha->isp_ops.beacon_off(ha);
+ ha->isp_ops->beacon_off(ha);
}
/* Scsi_Host attributes. */
@@ -455,7 +463,7 @@ qla2x00_fw_version_show(struct class_device *cdev, char *buf)
char fw_str[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
- ha->isp_ops.fw_version_str(ha, fw_str));
+ ha->isp_ops->fw_version_str(ha, fw_str));
}
static ssize_t
@@ -507,7 +515,7 @@ qla2x00_pci_info_show(struct class_device *cdev, char *buf)
char pci_info[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
- ha->isp_ops.pci_info_str(ha, pci_info));
+ ha->isp_ops->pci_info_str(ha, pci_info));
}
static ssize_t
@@ -652,9 +660,9 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
return -EINVAL;
if (val)
- rval = ha->isp_ops.beacon_on(ha);
+ rval = ha->isp_ops->beacon_on(ha);
else
- rval = ha->isp_ops.beacon_off(ha);
+ rval = ha->isp_ops->beacon_off(ha);
if (rval != QLA_SUCCESS)
count = 0;
@@ -898,7 +906,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat = &ha->fc_host_stat;
memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
sizeof(stat_buf) / 4, mb_stat);
} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 996c47a63074..c6680348b648 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -37,6 +37,121 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
return ptr + (ha->response_q_length * sizeof(response_t));
}
+static int
+qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+ uint32_t cram_size, uint32_t *ext_mem, void **nxt)
+{
+ int rval;
+ uint32_t cnt, stat, timer, risc_address, ext_mem_cnt;
+ uint16_t mb[4];
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ rval = QLA_SUCCESS;
+ risc_address = ext_mem_cnt = 0;
+ memset(mb, 0, sizeof(mb));
+
+ /* Code RAM. */
+ risc_address = 0x20000;
+ WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ for (cnt = 0; cnt < cram_size / 4 && rval == QLA_SUCCESS;
+ cnt++, risc_address++) {
+ WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
+ WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
+ RD_REG_WORD(&reg->mailbox8);
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+
+ for (timer = 6000000; timer; timer--) {
+ /* Check for pending interrupts. */
+ stat = RD_REG_DWORD(&reg->host_status);
+ if (stat & HSRX_RISC_INT) {
+ stat &= 0xff;
+
+ if (stat == 0x1 || stat == 0x2 ||
+ stat == 0x10 || stat == 0x11) {
+ set_bit(MBX_INTERRUPT,
+ &ha->mbx_cmd_flags);
+
+ mb[0] = RD_REG_WORD(&reg->mailbox0);
+ mb[2] = RD_REG_WORD(&reg->mailbox2);
+ mb[3] = RD_REG_WORD(&reg->mailbox3);
+
+ WRT_REG_DWORD(&reg->hccr,
+ HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ break;
+ }
+
+ /* Clear this intr; it wasn't a mailbox intr */
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ }
+ udelay(5);
+ }
+
+ if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ rval = mb[0] & MBS_MASK;
+ code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
+ } else {
+ rval = QLA_FUNCTION_FAILED;
+ }
+ }
+
+ if (rval == QLA_SUCCESS) {
+ /* External Memory. */
+ risc_address = 0x100000;
+ ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
+ WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ }
+ for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS;
+ cnt++, risc_address++) {
+ WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
+ WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
+ RD_REG_WORD(&reg->mailbox8);
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+
+ for (timer = 6000000; timer; timer--) {
+ /* Check for pending interrupts. */
+ stat = RD_REG_DWORD(&reg->host_status);
+ if (stat & HSRX_RISC_INT) {
+ stat &= 0xff;
+
+ if (stat == 0x1 || stat == 0x2 ||
+ stat == 0x10 || stat == 0x11) {
+ set_bit(MBX_INTERRUPT,
+ &ha->mbx_cmd_flags);
+
+ mb[0] = RD_REG_WORD(&reg->mailbox0);
+ mb[2] = RD_REG_WORD(&reg->mailbox2);
+ mb[3] = RD_REG_WORD(&reg->mailbox3);
+
+ WRT_REG_DWORD(&reg->hccr,
+ HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ break;
+ }
+
+ /* Clear this intr; it wasn't a mailbox intr */
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ }
+ udelay(5);
+ }
+
+ if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ rval = mb[0] & MBS_MASK;
+ ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
+ } else {
+ rval = QLA_FUNCTION_FAILED;
+ }
+ }
+
+ *nxt = rval == QLA_SUCCESS ? &ext_mem[cnt]: NULL;
+ return rval;
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -633,11 +748,10 @@ void
qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
{
int rval;
- uint32_t cnt, timer;
+ uint32_t cnt;
uint32_t risc_address;
- uint16_t mb[4], wd;
+ uint16_t mb0, wd;
- uint32_t stat;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t __iomem *dmp_reg;
uint32_t *iter_reg;
@@ -645,10 +759,9 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
unsigned long flags;
struct qla24xx_fw_dump *fw;
uint32_t ext_mem_cnt;
- void *eft;
+ void *nxt;
risc_address = ext_mem_cnt = 0;
- memset(mb, 0, sizeof(mb));
flags = 0;
if (!hardware_locked)
@@ -701,250 +814,236 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
/* Shadow registers. */
WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
RD_REG_DWORD(&reg->iobase_addr);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0000000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0100000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0200000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0300000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0400000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0500000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0600000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg));
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
/* Mailbox registers. */
- mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+ mbx_reg = &reg->mailbox0;
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Receive sequence registers. */
iter_reg = fw->rseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Command DMA registers. */
WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Queues. */
iter_reg = fw->req0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 8; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+ dmp_reg = &reg->iobase_q;
for (cnt = 0; cnt < 7; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->resp0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 8; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+ dmp_reg = &reg->iobase_q;
for (cnt = 0; cnt < 7; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->req1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 8; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+ dmp_reg = &reg->iobase_q;
for (cnt = 0; cnt < 7; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt2_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt3_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt4_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
fw->xmt_data_dma_reg[cnt] =
htonl(RD_REG_DWORD(dmp_reg++));
@@ -952,221 +1051,221 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
/* Receive DMA registers. */
iter_reg = fw->rcvt0_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->rcvt1_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* RISC registers. */
iter_reg = fw->risc_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Local memory controller registers. */
iter_reg = fw->lmc_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Fibre Protocol Module registers. */
iter_reg = fw->fpm_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Frame Buffer registers. */
iter_reg = fw->fb_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
@@ -1187,10 +1286,10 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
udelay(100);
/* Wait for firmware to complete NVRAM accesses. */
- mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- for (cnt = 10000 ; cnt && mb[0]; cnt--) {
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ for (cnt = 10000 ; cnt && mb0; cnt--) {
udelay(5);
- mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
barrier();
}
@@ -1214,110 +1313,717 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
rval = QLA_FUNCTION_TIMEOUT;
}
- /* Memory. */
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_memory(ha, fw->code_ram,
+ sizeof(fw->code_ram), fw->ext_mem, &nxt);
+
if (rval == QLA_SUCCESS) {
- /* Code RAM. */
- risc_address = 0x20000;
- WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ nxt = qla2xxx_copy_queues(ha, nxt);
+ if (ha->eft)
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
}
- for (cnt = 0; cnt < sizeof(fw->code_ram) / 4 && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
- WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
- RD_REG_WORD(&reg->mailbox8);
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->host_status);
- if (stat & HSRX_RISC_INT) {
- stat &= 0xff;
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to dump firmware (%x)!!!\n", rval);
+ ha->fw_dumped = 0;
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
+ } else {
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump saved to temp buffer (%ld/%p).\n",
+ ha->host_no, ha->fw_dump);
+ ha->fw_dumped = 1;
+ }
- mb[0] = RD_REG_WORD(&reg->mailbox0);
- mb[2] = RD_REG_WORD(&reg->mailbox2);
- mb[3] = RD_REG_WORD(&reg->mailbox3);
+qla24xx_fw_dump_failed:
+ if (!hardware_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
+void
+qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+{
+ int rval;
+ uint32_t cnt;
+ uint32_t risc_address;
+ uint16_t mb0, wd;
- /* Clear this intr; it wasn't a mailbox intr */
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- }
- udelay(5);
- }
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ uint32_t __iomem *dmp_reg;
+ uint32_t *iter_reg;
+ uint16_t __iomem *mbx_reg;
+ unsigned long flags;
+ struct qla25xx_fw_dump *fw;
+ uint32_t ext_mem_cnt;
+ void *nxt;
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb[0] & MBS_MASK;
- fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
- } else {
- rval = QLA_FUNCTION_FAILED;
+ risc_address = ext_mem_cnt = 0;
+ flags = 0;
+
+ if (!hardware_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ if (!ha->fw_dump) {
+ qla_printk(KERN_WARNING, ha,
+ "No buffer available for dump!!!\n");
+ goto qla25xx_fw_dump_failed;
+ }
+
+ if (ha->fw_dumped) {
+ qla_printk(KERN_WARNING, ha,
+ "Firmware has been previously dumped (%p) -- ignoring "
+ "request...\n", ha->fw_dump);
+ goto qla25xx_fw_dump_failed;
+ }
+ fw = &ha->fw_dump->isp.isp25;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
+
+ rval = QLA_SUCCESS;
+ fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
+
+ /* Pause RISC. */
+ if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
+ HCCRX_CLR_HOST_INT);
+ RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+ for (cnt = 30000;
+ (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
}
}
if (rval == QLA_SUCCESS) {
- /* External Memory. */
- risc_address = 0x100000;
- ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
- WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- }
- for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS;
- cnt++, risc_address++) {
- WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
- WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
- RD_REG_WORD(&reg->mailbox8);
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+ /* Host interface registers. */
+ dmp_reg = (uint32_t __iomem *)(reg + 0);
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->host_status);
- if (stat & HSRX_RISC_INT) {
- stat &= 0xff;
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
- mb[0] = RD_REG_WORD(&reg->mailbox0);
- mb[2] = RD_REG_WORD(&reg->mailbox2);
- mb[3] = RD_REG_WORD(&reg->mailbox3);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
- /* Clear this intr; it wasn't a mailbox intr */
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- }
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+ fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+ fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+ fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+ fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* RISC I/O register. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+ RD_REG_DWORD(&reg->iobase_addr);
+ fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xseq_0_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFC0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFD0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
+ fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->rseq_0_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFC0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
+ fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
+ fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Auxiliary sequence registers. */
+ iter_reg = fw->aseq_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB050);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB060);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB070);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->aseq_0_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0C0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0D0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0E0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++)
+ fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0F0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++)
+ fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Command DMA registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
+ fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 8; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 8; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 8; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt1_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt2_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt3_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt4_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
+ fw->xmt_data_dma_reg[cnt] =
+ htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3070);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6F00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Reset RISC. */
+ WRT_REG_DWORD(&reg->ctrl_status,
+ CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) &
+ CSRX_DMA_ACTIVE) == 0)
+ break;
+
+ udelay(10);
+ }
+
+ WRT_REG_DWORD(&reg->ctrl_status,
+ CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
+
+ udelay(100);
+ /* Wait for firmware to complete NVRAM accesses. */
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ for (cnt = 10000 ; cnt && mb0; cnt--) {
udelay(5);
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ barrier();
}
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb[0] & MBS_MASK;
- fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
- } else {
- rval = QLA_FUNCTION_FAILED;
+ /* Wait for soft-reset to complete. */
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) &
+ CSRX_ISP_SOFT_RESET) == 0)
+ break;
+
+ udelay(10);
}
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+ RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
}
+ for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_memory(ha, fw->code_ram,
+ sizeof(fw->code_ram), fw->ext_mem, &nxt);
+
if (rval == QLA_SUCCESS) {
- eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]);
+ nxt = qla2xxx_copy_queues(ha, nxt);
if (ha->eft)
- memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size));
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
}
if (rval != QLA_SUCCESS) {
@@ -1332,7 +2038,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
ha->fw_dumped = 1;
}
-qla24xx_fw_dump_failed:
+qla25xx_fw_dump_failed:
if (!hardware_locked)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
@@ -1344,21 +2050,18 @@ qla24xx_fw_dump_failed:
void
qla2x00_dump_regs(scsi_qla_host_t *ha)
{
+ int i;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+ uint16_t __iomem *mbx_reg;
+
+ mbx_reg = IS_FWI2_CAPABLE(ha) ? &reg24->mailbox0:
+ MAILBOX_REG(ha, reg, 0);
printk("Mailbox registers:\n");
- printk("scsi(%ld): mbox 0 0x%04x \n",
- ha->host_no, RD_MAILBOX_REG(ha, reg, 0));
- printk("scsi(%ld): mbox 1 0x%04x \n",
- ha->host_no, RD_MAILBOX_REG(ha, reg, 1));
- printk("scsi(%ld): mbox 2 0x%04x \n",
- ha->host_no, RD_MAILBOX_REG(ha, reg, 2));
- printk("scsi(%ld): mbox 3 0x%04x \n",
- ha->host_no, RD_MAILBOX_REG(ha, reg, 3));
- printk("scsi(%ld): mbox 4 0x%04x \n",
- ha->host_no, RD_MAILBOX_REG(ha, reg, 4));
- printk("scsi(%ld): mbox 5 0x%04x \n",
- ha->host_no, RD_MAILBOX_REG(ha, reg, 5));
+ for (i = 0; i < 6; i++)
+ printk("scsi(%ld): mbox %d 0x%04x \n", ha->host_no, i,
+ RD_REG_WORD(mbx_reg++));
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 49dffeb78512..cca4b0d8253e 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -213,6 +213,43 @@ struct qla24xx_fw_dump {
uint32_t ext_mem[1];
};
+struct qla25xx_fw_dump {
+ uint32_t host_status;
+ uint32_t host_reg[32];
+ uint32_t shadow_reg[11];
+ uint32_t risc_io_reg;
+ uint16_t mailbox_reg[32];
+ uint32_t xseq_gp_reg[128];
+ uint32_t xseq_0_reg[48];
+ uint32_t xseq_1_reg[16];
+ uint32_t rseq_gp_reg[128];
+ uint32_t rseq_0_reg[32];
+ uint32_t rseq_1_reg[16];
+ uint32_t rseq_2_reg[16];
+ uint32_t aseq_gp_reg[128];
+ uint32_t aseq_0_reg[32];
+ uint32_t aseq_1_reg[16];
+ uint32_t aseq_2_reg[16];
+ uint32_t cmd_dma_reg[16];
+ uint32_t req0_dma_reg[15];
+ uint32_t resp0_dma_reg[15];
+ uint32_t req1_dma_reg[15];
+ uint32_t xmt0_dma_reg[32];
+ uint32_t xmt1_dma_reg[32];
+ uint32_t xmt2_dma_reg[32];
+ uint32_t xmt3_dma_reg[32];
+ uint32_t xmt4_dma_reg[32];
+ uint32_t xmt_data_dma_reg[16];
+ uint32_t rcvt0_data_dma_reg[32];
+ uint32_t rcvt1_data_dma_reg[32];
+ uint32_t risc_gp_reg[128];
+ uint32_t lmc_reg[128];
+ uint32_t fpm_hdw_reg[192];
+ uint32_t fb_hdw_reg[192];
+ uint32_t code_ram[0x2000];
+ uint32_t ext_mem[1];
+};
+
#define EFT_NUM_BUFFERS 4
#define EFT_BYTES_PER_BUFFER 0x4000
#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
@@ -246,5 +283,6 @@ struct qla2xxx_fw_dump {
struct qla2100_fw_dump isp21;
struct qla2300_fw_dump isp23;
struct qla24xx_fw_dump isp24;
+ struct qla25xx_fw_dump isp25;
} isp;
};
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index a1ca590ba447..c1964866a423 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1502,7 +1502,6 @@ typedef struct {
uint8_t node_name[WWN_SIZE];
uint8_t port_name[WWN_SIZE];
uint8_t fabric_port_name[WWN_SIZE];
- uint16_t fp_speeds;
uint16_t fp_speed;
} sw_info_t;
@@ -1711,6 +1710,14 @@ struct ct_fdmi_hba_attributes {
#define FDMI_PORT_OS_DEVICE_NAME 5
#define FDMI_PORT_HOST_NAME 6
+#define FDMI_PORT_SPEED_1GB 0x1
+#define FDMI_PORT_SPEED_2GB 0x2
+#define FDMI_PORT_SPEED_10GB 0x4
+#define FDMI_PORT_SPEED_4GB 0x8
+#define FDMI_PORT_SPEED_8GB 0x10
+#define FDMI_PORT_SPEED_16GB 0x20
+#define FDMI_PORT_SPEED_UNKNOWN 0x8000
+
struct ct_fdmi_port_attr {
uint16_t type;
uint16_t len;
@@ -2201,6 +2208,7 @@ typedef struct scsi_qla_host {
#define SWITCH_FOUND BIT_3
#define DFLG_NO_CABLE BIT_4
+#define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532
uint32_t device_type;
#define DT_ISP2100 BIT_0
#define DT_ISP2200 BIT_1
@@ -2213,8 +2221,11 @@ typedef struct scsi_qla_host {
#define DT_ISP2432 BIT_8
#define DT_ISP5422 BIT_9
#define DT_ISP5432 BIT_10
-#define DT_ISP_LAST (DT_ISP5432 << 1)
+#define DT_ISP2532 BIT_11
+#define DT_ISP_LAST (DT_ISP2532 << 1)
+#define DT_IIDMA BIT_26
+#define DT_FWI2 BIT_27
#define DT_ZIO_SUPPORTED BIT_28
#define DT_OEM_001 BIT_29
#define DT_ISP2200A BIT_30
@@ -2232,12 +2243,16 @@ typedef struct scsi_qla_host {
#define IS_QLA2432(ha) (DT_MASK(ha) & DT_ISP2432)
#define IS_QLA5422(ha) (DT_MASK(ha) & DT_ISP5422)
#define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432)
+#define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
#define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha))
#define IS_QLA54XX(ha) (IS_QLA5422(ha) || IS_QLA5432(ha))
+#define IS_QLA25XX(ha) (IS_QLA2532(ha))
+#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
+#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
#define IS_ZIO_SUPPORTED(ha) ((ha)->device_type & DT_ZIO_SUPPORTED)
#define IS_OEM_001(ha) ((ha)->device_type & DT_OEM_001)
#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS)
@@ -2274,7 +2289,7 @@ typedef struct scsi_qla_host {
uint16_t rsp_ring_index; /* Current index. */
uint16_t response_q_length;
- struct isp_operations isp_ops;
+ struct isp_operations *isp_ops;
/* Outstandings ISP commands. */
srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS];
@@ -2298,6 +2313,7 @@ typedef struct scsi_qla_host {
#define PORT_SPEED_1GB 0x00
#define PORT_SPEED_2GB 0x01
#define PORT_SPEED_4GB 0x03
+#define PORT_SPEED_8GB 0x04
uint16_t link_data_rate; /* F/W operating speed */
uint8_t current_topology;
@@ -2323,10 +2339,14 @@ typedef struct scsi_qla_host {
uint8_t serial2;
/* NVRAM configuration data */
+#define MAX_NVRAM_SIZE 4096
+#define VPD_OFFSET MAX_NVRAM_SIZE / 2
uint16_t nvram_size;
uint16_t nvram_base;
+ void *nvram;
uint16_t vpd_size;
uint16_t vpd_base;
+ void *vpd;
uint16_t loop_reset_delay;
uint8_t retry_count;
@@ -2564,6 +2584,7 @@ typedef struct scsi_qla_host {
#define OPTROM_SIZE_2300 0x20000
#define OPTROM_SIZE_2322 0x100000
#define OPTROM_SIZE_24XX 0x100000
+#define OPTROM_SIZE_25XX 0x200000
#include "qla_gbl.h"
#include "qla_dbg.h"
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 63a11fef5d1b..99fe49618d61 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -8,14 +8,17 @@
#define __QLA_FW_H
#define MBS_CHECKSUM_ERROR 0x4010
+#define MBS_INVALID_PRODUCT_KEY 0x4020
/*
* Firmware Options.
*/
#define FO1_ENABLE_PUREX BIT_10
#define FO1_DISABLE_LED_CTRL BIT_6
+#define FO1_ENABLE_8016 BIT_0
#define FO2_ENABLE_SEL_CLASS2 BIT_5
#define FO3_NO_ABTS_ON_LINKDOWN BIT_14
+#define FO3_HOLD_STS_IOCB BIT_12
/*
* Port Database structure definition for ISP 24xx.
@@ -341,7 +344,9 @@ struct init_cb_24xx {
* BIT 10 = Reserved
* BIT 11 = Enable FC-SP Security
* BIT 12 = FC Tape Enable
- * BIT 13-31 = Reserved
+ * BIT 13 = Reserved
+ * BIT 14 = Enable Target PRLI Control
+ * BIT 15-31 = Reserved
*/
uint32_t firmware_options_2;
@@ -363,7 +368,8 @@ struct init_cb_24xx {
* BIT 13 = Data Rate bit 0
* BIT 14 = Data Rate bit 1
* BIT 15 = Data Rate bit 2
- * BIT 16-31 = Reserved
+ * BIT 16 = Enable 75 ohm Termination Select
+ * BIT 17-31 = Reserved
*/
uint32_t firmware_options_3;
@@ -435,6 +441,7 @@ struct cmd_type_7 {
#define TMF_LUN_RESET BIT_12
#define TMF_CLEAR_TASK_SET BIT_10
#define TMF_ABORT_TASK_SET BIT_9
+#define TMF_DSD_LIST_ENABLE BIT_2
#define TMF_READ_DATA BIT_1
#define TMF_WRITE_DATA BIT_0
@@ -589,7 +596,7 @@ struct els_entry_24xx {
#define EST_SOFI3 (1 << 4)
#define EST_SOFI2 (3 << 4)
- uint32_t rx_xchg_address[2]; /* Receive exchange address. */
+ uint32_t rx_xchg_address; /* Receive exchange address. */
uint16_t rx_dsd_count;
uint8_t opcode;
@@ -650,6 +657,7 @@ struct logio_entry_24xx {
uint16_t control_flags; /* Control flags. */
/* Modifiers. */
+#define LCF_INCLUDE_SNS BIT_10 /* Include SNS (FFFFFC) during LOGO. */
#define LCF_FCP2_OVERRIDE BIT_9 /* Set/Reset word 3 of PRLI. */
#define LCF_CLASS_2 BIT_8 /* Enable class 2 during PLOGI. */
#define LCF_FREE_NPORT BIT_7 /* Release NPORT handle after LOGO. */
@@ -779,6 +787,15 @@ struct device_reg_24xx {
#define FA_RISC_CODE_ADDR 0x20000
#define FA_RISC_CODE_SEGMENTS 2
+#define FA_FW_AREA_ADDR 0x40000
+#define FA_VPD_NVRAM_ADDR 0x48000
+#define FA_FEATURE_ADDR 0x4C000
+#define FA_FLASH_DESCR_ADDR 0x50000
+#define FA_HW_EVENT_ADDR 0x54000
+#define FA_BOOT_LOG_ADDR 0x58000
+#define FA_FW_DUMP0_ADDR 0x60000
+#define FA_FW_DUMP1_ADDR 0x70000
+
uint32_t flash_data; /* Flash/NVRAM BIOS data. */
uint32_t ctrl_status; /* Control/Status. */
@@ -859,10 +876,13 @@ struct device_reg_24xx {
#define HCCRX_CLR_RISC_INT 0xA0000000
uint32_t gpiod; /* GPIO Data register. */
+
/* LED update mask. */
#define GPDX_LED_UPDATE_MASK (BIT_20|BIT_19|BIT_18)
/* Data update mask. */
#define GPDX_DATA_UPDATE_MASK (BIT_17|BIT_16)
+ /* Data update mask. */
+#define GPDX_DATA_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16)
/* LED control mask. */
#define GPDX_LED_COLOR_MASK (BIT_4|BIT_3|BIT_2)
/* LED bit values. Color names as
@@ -877,6 +897,8 @@ struct device_reg_24xx {
uint32_t gpioe; /* GPIO Enable register. */
/* Enable update mask. */
#define GPEX_ENABLE_UPDATE_MASK (BIT_17|BIT_16)
+ /* Enable update mask. */
+#define GPEX_ENABLE_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16)
/* Enable. */
#define GPEX_ENABLE (BIT_1|BIT_0)
@@ -916,6 +938,14 @@ struct device_reg_24xx {
uint16_t mailbox29;
uint16_t mailbox30;
uint16_t mailbox31;
+
+ uint32_t iobase_window;
+ uint32_t unused_4[8]; /* Gap. */
+ uint32_t iobase_q;
+ uint32_t unused_5[2]; /* Gap. */
+ uint32_t iobase_select;
+ uint32_t unused_6[2]; /* Gap. */
+ uint32_t iobase_sdata;
};
/* MID Support ***************************************************************/
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index b44eff2803ce..aa1e41152283 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -17,6 +17,7 @@ extern int qla2x00_initialize_adapter(scsi_qla_host_t *);
extern int qla2100_pci_config(struct scsi_qla_host *);
extern int qla2300_pci_config(struct scsi_qla_host *);
extern int qla24xx_pci_config(scsi_qla_host_t *);
+extern int qla25xx_pci_config(scsi_qla_host_t *);
extern void qla2x00_reset_chip(struct scsi_qla_host *);
extern void qla24xx_reset_chip(struct scsi_qla_host *);
extern int qla2x00_chip_diag(struct scsi_qla_host *);
@@ -281,6 +282,10 @@ extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
+extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+ uint32_t);
+extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+ uint32_t);
extern int qla2x00_beacon_on(struct scsi_qla_host *);
extern int qla2x00_beacon_off(struct scsi_qla_host *);
@@ -307,6 +312,7 @@ extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
extern void qla2100_fw_dump(scsi_qla_host_t *, int);
extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index a086b3f0df65..a7e23583f899 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -127,7 +127,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt,
DEBUG2_3(printk("scsi(%ld): %s failed, error status (%x).\n",
ha->host_no, routine, ms_pkt->entry_status));
} else {
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
comp_status = le16_to_cpu(
((struct ct_entry_24xx *)ms_pkt)->comp_status);
else
@@ -180,7 +180,8 @@ qla2x00_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport)
/* Issue GA_NXT */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GA_NXT_REQ_SIZE, GA_NXT_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GA_NXT_REQ_SIZE,
+ GA_NXT_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
@@ -266,7 +267,8 @@ qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list)
/* Issue GID_PT */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GID_PT_REQ_SIZE, GID_PT_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GID_PT_REQ_SIZE,
+ GID_PT_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
@@ -293,6 +295,8 @@ qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list)
list[i].d_id.b.domain = gid_data->port_id[0];
list[i].d_id.b.area = gid_data->port_id[1];
list[i].d_id.b.al_pa = gid_data->port_id[2];
+ memset(list[i].fabric_port_name, 0, WWN_SIZE);
+ list[i].fp_speed = PORT_SPEED_UNKNOWN;
/* Last one exit. */
if (gid_data->control_byte & BIT_7) {
@@ -338,7 +342,7 @@ qla2x00_gpn_id(scsi_qla_host_t *ha, sw_info_t *list)
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
/* Issue GPN_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
GPN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -399,7 +403,7 @@ qla2x00_gnn_id(scsi_qla_host_t *ha, sw_info_t *list)
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
/* Issue GNN_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
GNN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -473,7 +477,8 @@ qla2x00_rft_id(scsi_qla_host_t *ha)
/* Issue RFT_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RFT_ID_REQ_SIZE, RFT_ID_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RFT_ID_REQ_SIZE,
+ RFT_ID_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
@@ -528,7 +533,8 @@ qla2x00_rff_id(scsi_qla_host_t *ha)
/* Issue RFF_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RFF_ID_REQ_SIZE, RFF_ID_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RFF_ID_REQ_SIZE,
+ RFF_ID_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
@@ -582,7 +588,8 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
/* Issue RNN_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RNN_ID_REQ_SIZE, RNN_ID_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RNN_ID_REQ_SIZE,
+ RNN_ID_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
@@ -645,7 +652,7 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
/* Issue RSNN_NN */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
@@ -1102,7 +1109,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *ha)
if (ha->flags.management_server_logged_in)
return ret;
- ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
+ ha->isp_ops->fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
mb, BIT_1);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
@@ -1198,7 +1205,7 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size)
ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
} else {
@@ -1253,7 +1260,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *ha)
/* Issue RHBA */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
- ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
@@ -1373,7 +1380,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *ha)
/* Firmware version */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION);
- ha->isp_ops.fw_version_str(ha, eiter->a.fw_version);
+ ha->isp_ops->fw_version_str(ha, eiter->a.fw_version);
alen = strlen(eiter->a.fw_version);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
@@ -1439,7 +1446,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *ha)
/* Issue RPA */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
DHBA_RSP_SIZE);
/* Prepare CT request */
@@ -1497,7 +1504,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* Issue RPA */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
- ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
@@ -1527,12 +1534,20 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
- eiter->a.sup_speed = __constant_cpu_to_be32(4);
+ if (IS_QLA25XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
+ FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB);
+ else if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
+ FDMI_PORT_SPEED_4GB);
else if (IS_QLA23XX(ha))
- eiter->a.sup_speed = __constant_cpu_to_be32(2);
+ eiter->a.sup_speed =__constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB);
else
- eiter->a.sup_speed = __constant_cpu_to_be32(1);
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB);
size += 4 + 4;
DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no,
@@ -1543,14 +1558,25 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
switch (ha->link_data_rate) {
- case 0:
- eiter->a.cur_speed = __constant_cpu_to_be32(1);
+ case PORT_SPEED_1GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_1GB);
+ break;
+ case PORT_SPEED_2GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_2GB);
break;
- case 1:
- eiter->a.cur_speed = __constant_cpu_to_be32(2);
+ case PORT_SPEED_4GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_4GB);
break;
- case 3:
- eiter->a.cur_speed = __constant_cpu_to_be32(4);
+ case PORT_SPEED_8GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_8GB);
+ break;
+ default:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
break;
}
size += 4 + 4;
@@ -1562,7 +1588,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
eiter->len = __constant_cpu_to_be16(4 + 4);
- max_frame_size = IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
+ max_frame_size = IS_FWI2_CAPABLE(ha) ?
(uint32_t) icb24->frame_payload_size:
(uint32_t) ha->init_cb->frame_payload_size;
eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
@@ -1678,15 +1704,13 @@ qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
/* Issue GFPN_ID */
- memset(list[i].fabric_port_name, 0, WWN_SIZE);
-
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
GFPN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -1786,7 +1810,7 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
if (!ha->flags.gpsc_supported)
return QLA_FUNCTION_FAILED;
@@ -1797,8 +1821,6 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
/* Issue GFPN_ID */
- list[i].fp_speeds = list[i].fp_speed = 0;
-
/* Prepare common MS IOCB */
ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
GPSC_RSP_SIZE);
@@ -1834,9 +1856,21 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
}
rval = QLA_FUNCTION_FAILED;
} else {
- /* Save portname */
- list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
- list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
+ /* Save port-speed */
+ switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) {
+ case BIT_15:
+ list[i].fp_speed = PORT_SPEED_1GB;
+ break;
+ case BIT_14:
+ list[i].fp_speed = PORT_SPEED_2GB;
+ break;
+ case BIT_13:
+ list[i].fp_speed = PORT_SPEED_4GB;
+ break;
+ case BIT_11:
+ list[i].fp_speed = PORT_SPEED_8GB;
+ break;
+ }
DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
"fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
@@ -1849,8 +1883,8 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
list[i].fabric_port_name[5],
list[i].fabric_port_name[6],
list[i].fabric_port_name[7],
- be16_to_cpu(list[i].fp_speeds),
- be16_to_cpu(list[i].fp_speed)));
+ be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
+ be16_to_cpu(ct_rsp->rsp.gpsc.speed)));
}
/* Last device exit. */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index cc6ebb609e98..1a058ec9bd0c 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -79,20 +79,20 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
- rval = ha->isp_ops.pci_config(ha);
+ rval = ha->isp_ops->pci_config(ha);
if (rval) {
DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
ha->host_no));
return (rval);
}
- ha->isp_ops.reset_chip(ha);
+ ha->isp_ops->reset_chip(ha);
- ha->isp_ops.get_flash_version(ha, ha->request_ring);
+ ha->isp_ops->get_flash_version(ha, ha->request_ring);
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
- ha->isp_ops.nvram_config(ha);
+ ha->isp_ops->nvram_config(ha);
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
@@ -108,7 +108,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
- rval = ha->isp_ops.chip_diag(ha);
+ rval = ha->isp_ops->chip_diag(ha);
if (rval)
return (rval);
rval = qla2x00_setup_chip(ha);
@@ -129,14 +129,13 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
int
qla2100_pci_config(scsi_qla_host_t *ha)
{
- int ret;
uint16_t w;
uint32_t d;
unsigned long flags;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- ret = pci_set_mwi(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -164,7 +163,6 @@ qla2100_pci_config(scsi_qla_host_t *ha)
int
qla2300_pci_config(scsi_qla_host_t *ha)
{
- int ret;
uint16_t w;
uint32_t d;
unsigned long flags = 0;
@@ -172,7 +170,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- ret = pci_set_mwi(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -250,15 +248,13 @@ qla2300_pci_config(scsi_qla_host_t *ha)
int
qla24xx_pci_config(scsi_qla_host_t *ha)
{
- int ret;
uint16_t w;
uint32_t d;
unsigned long flags = 0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- int pcix_cmd_reg, pcie_dctl_reg;
pci_set_master(ha->pdev);
- ret = pci_set_mwi(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -268,28 +264,12 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
- pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
- if (pcix_cmd_reg) {
- uint16_t pcix_cmd;
-
- pcix_cmd_reg += PCI_X_CMD;
- pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
- pcix_cmd &= ~PCI_X_CMD_MAX_READ;
- pcix_cmd |= 0x0008;
- pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
- }
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
+ pcix_set_mmrbc(ha->pdev, 2048);
/* PCIe -- adjust Maximum Read Request Size (2048). */
- pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
- if (pcie_dctl_reg) {
- uint16_t pcie_dctl;
-
- pcie_dctl_reg += PCI_EXP_DEVCTL;
- pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
- pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
- pcie_dctl |= 0x4000;
- pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
- }
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
/* Reset expansion ROM address decode enable */
pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
@@ -307,6 +287,40 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
}
/**
+ * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla25xx_pci_config(scsi_qla_host_t *ha)
+{
+ uint16_t w;
+ uint32_t d;
+
+ pci_set_master(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
+
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+ /* PCIe -- adjust Maximum Read Request Size (2048). */
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
+
+ /* Reset expansion ROM address decode enable */
+ pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
+ d &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+
+ ha->chip_revision = ha->pdev->revision;
+
+ return QLA_SUCCESS;
+}
+
+/**
* qla2x00_isp_firmware() - Choose firmware image.
* @ha: HA context
*
@@ -351,7 +365,7 @@ qla2x00_reset_chip(scsi_qla_host_t *ha)
uint32_t cnt;
uint16_t cmd;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -551,7 +565,7 @@ qla24xx_reset_risc(scsi_qla_host_t *ha)
void
qla24xx_reset_chip(scsi_qla_host_t *ha)
{
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
/* Perform RISC reset. */
qla24xx_reset_risc(ha);
@@ -736,8 +750,10 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
sizeof(uint16_t);
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+ } else if (IS_FWI2_CAPABLE(ha)) {
+ fixed_size = IS_QLA25XX(ha) ?
+ offsetof(struct qla25xx_fw_dump, ext_mem):
+ offsetof(struct qla24xx_fw_dump, ext_mem);
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
@@ -879,7 +895,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
uint32_t srisc_address = 0;
/* Load firmware sequences */
- rval = ha->isp_ops.load_risc(ha, &srisc_address);
+ rval = ha->isp_ops->load_risc(ha, &srisc_address);
if (rval == QLA_SUCCESS) {
DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
"code.\n", ha->host_no));
@@ -1130,12 +1146,12 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
/* Initialize response queue entries */
qla2x00_init_response_q_entries(ha);
- ha->isp_ops.config_rings(ha);
+ ha->isp_ops->config_rings(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Update any ISP specific firmware options before initialization. */
- ha->isp_ops.update_fw_options(ha);
+ ha->isp_ops->update_fw_options(ha);
DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
@@ -1445,8 +1461,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
uint16_t cnt;
uint8_t *dptr1, *dptr2;
init_cb_t *icb = ha->init_cb;
- nvram_t *nv = (nvram_t *)ha->request_ring;
- uint8_t *ptr = (uint8_t *)ha->request_ring;
+ nvram_t *nv = ha->nvram;
+ uint8_t *ptr = ha->nvram;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
rval = QLA_SUCCESS;
@@ -1459,13 +1475,12 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
ha->nvram_base = 0x80;
/* Get NVRAM data and calculate checksum. */
- ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
+ ha->isp_ops->read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
chksum += *ptr++;
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
- DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
- ha->nvram_size));
+ DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
/* Bad NVRAM data, set defaults parameters. */
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
@@ -2064,17 +2079,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
}
/* Base iIDMA settings on HBA port speed. */
- switch (ha->link_data_rate) {
- case PORT_SPEED_1GB:
- fcport->fp_speed = cpu_to_be16(BIT_15);
- break;
- case PORT_SPEED_2GB:
- fcport->fp_speed = cpu_to_be16(BIT_14);
- break;
- case PORT_SPEED_4GB:
- fcport->fp_speed = cpu_to_be16(BIT_13);
- break;
- }
+ fcport->fp_speed = ha->link_data_rate;
qla2x00_update_fcport(ha, fcport);
@@ -2115,38 +2120,25 @@ static void
qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
{
#define LS_UNKNOWN 2
- static char *link_speeds[5] = { "1", "2", "?", "4" };
+ static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
int rval;
- uint16_t port_speed, mb[6];
+ uint16_t mb[6];
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return;
- switch (be16_to_cpu(fcport->fp_speed)) {
- case BIT_15:
- port_speed = PORT_SPEED_1GB;
- break;
- case BIT_14:
- port_speed = PORT_SPEED_2GB;
- break;
- case BIT_13:
- port_speed = PORT_SPEED_4GB;
- break;
- default:
+ if (fcport->fp_speed == PORT_SPEED_UNKNOWN) {
DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
- "unsupported FM port operating speed (%04x).\n",
+ "unsupported FM port operating speed.\n",
ha->host_no, fcport->port_name[0], fcport->port_name[1],
fcport->port_name[2], fcport->port_name[3],
fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7],
- be16_to_cpu(fcport->fp_speed)));
- port_speed = PORT_SPEED_UNKNOWN;
- break;
- }
- if (port_speed == PORT_SPEED_UNKNOWN)
+ fcport->port_name[6], fcport->port_name[7]));
return;
+ }
- rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
+ rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed,
+ mb);
if (rval != QLA_SUCCESS) {
DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
"%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
@@ -2154,12 +2146,12 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
fcport->port_name[2], fcport->port_name[3],
fcport->port_name[4], fcport->port_name[5],
fcport->port_name[6], fcport->port_name[7], rval,
- port_speed, mb[0], mb[1]));
+ fcport->fp_speed, mb[0], mb[1]));
} else {
DEBUG2(qla_printk(KERN_INFO, ha,
"iIDMA adjusted to %s GB/s on "
"%02x%02x%02x%02x%02x%02x%02x%02x.\n",
- link_speeds[port_speed], fcport->port_name[0],
+ link_speeds[fcport->fp_speed], fcport->port_name[0],
fcport->port_name[1], fcport->port_name[2],
fcport->port_name[3], fcport->port_name[4],
fcport->port_name[5], fcport->port_name[6],
@@ -2267,7 +2259,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
scsi_qla_host_t *pha = to_qla_parent(ha);
/* If FL port exists, then SNS is present */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_F_PORT;
else
loop_id = SNS_FL_PORT;
@@ -2294,11 +2286,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
qla2x00_fdmi_register(ha);
/* Ensure we are logged into the SNS. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_SNS;
else
loop_id = SIMPLE_NAME_SERVER;
- ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
+ ha->isp_ops->fabric_login(ha, loop_id, 0xff, 0xff,
0xfc, mb, BIT_1 | BIT_0);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2(qla_printk(KERN_INFO, ha,
@@ -2355,7 +2347,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
(fcport->flags & FCF_TAPE_PRESENT) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
- ha->isp_ops.fabric_logout(ha,
+ ha->isp_ops->fabric_logout(ha,
fcport->loop_id,
fcport->d_id.b.domain,
fcport->d_id.b.area,
@@ -2664,7 +2656,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
(fcport->flags & FCF_TAPE_PRESENT) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
fcport->loop_id = FC_NO_LOOP_ID;
@@ -2919,7 +2911,7 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
opts |= BIT_1;
rval = qla2x00_get_port_database(ha, fcport, opts);
if (rval != QLA_SUCCESS) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -2964,7 +2956,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
fcport->d_id.b.area, fcport->d_id.b.al_pa));
/* Login fcport on switch. */
- ha->isp_ops.fabric_login(ha, fcport->loop_id,
+ ha->isp_ops->fabric_login(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb, BIT_0);
if (mb[0] == MBS_PORT_ID_USED) {
@@ -3032,7 +3024,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
* dead.
*/
*next_loopid = fcport->loop_id;
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -3050,7 +3042,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
*next_loopid = fcport->loop_id;
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
fcport->loop_id = FC_NO_LOOP_ID;
@@ -3206,7 +3198,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha,
"Performing ISP error recovery - ha= %p.\n", ha);
- ha->isp_ops.reset_chip(ha);
+ ha->isp_ops->reset_chip(ha);
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
@@ -3232,9 +3224,9 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- ha->isp_ops.get_flash_version(ha, ha->request_ring);
+ ha->isp_ops->get_flash_version(ha, ha->request_ring);
- ha->isp_ops.nvram_config(ha);
+ ha->isp_ops->nvram_config(ha);
if (!qla2x00_restart_isp(ha)) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3249,7 +3241,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->flags.online = 1;
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
@@ -3274,7 +3266,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
* The next call disables the board
* completely.
*/
- ha->isp_ops.reset_adapter(ha);
+ ha->isp_ops->reset_adapter(ha);
ha->flags.online = 0;
clear_bit(ISP_ABORT_RETRY,
&ha->dpc_flags);
@@ -3331,7 +3323,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(ha)) {
ha->flags.online = 0;
- if (!(status = ha->isp_ops.chip_diag(ha))) {
+ if (!(status = ha->isp_ops->chip_diag(ha))) {
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
status = qla2x00_setup_chip(ha);
goto done;
@@ -3339,7 +3331,8 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) &&
+ !IS_QLA25XX(ha)) {
/*
* Disable SRAM, Instruction RAM and GP RAM
* parity.
@@ -3355,7 +3348,8 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) &&
+ !IS_QLA25XX(ha)) {
/* Enable proper parity */
if (IS_QLA2300(ha))
/* SRAM parity */
@@ -3423,7 +3417,7 @@ qla2x00_reset_adapter(scsi_qla_host_t *ha)
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
ha->flags.online = 0;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -3440,7 +3434,7 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha)
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
ha->flags.online = 0;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
@@ -3484,7 +3478,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
rval = QLA_SUCCESS;
icb = (struct init_cb_24xx *)ha->init_cb;
- nv = (struct nvram_24xx *)ha->request_ring;
+ nv = ha->nvram;
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(struct nvram_24xx);
@@ -3496,16 +3490,20 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
}
- /* Get NVRAM data and calculate checksum. */
+ /* Get VPD data into cache */
+ ha->vpd = ha->nvram + VPD_OFFSET;
+ ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd,
+ ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
+
+ /* Get NVRAM data into cache and calculate checksum. */
dptr = (uint32_t *)nv;
- ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
+ ha->isp_ops->read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
chksum += le32_to_cpu(*dptr++);
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
- DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
- ha->nvram_size));
+ DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
/* Bad NVRAM data, set defaults parameters. */
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
@@ -4012,7 +4010,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
{
int ret, retries;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return;
if (!ha->fw_major_version)
return;
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index d3023338628f..8e3b04464cff 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -104,7 +104,7 @@ static __inline__ void qla2x00_poll(scsi_qla_host_t *);
static inline void
qla2x00_poll(scsi_qla_host_t *ha)
{
- ha->isp_ops.intr_handler(0, ha);
+ ha->isp_ops->intr_handler(0, ha);
}
static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
@@ -163,7 +163,7 @@ static inline int qla2x00_is_reserved_id(scsi_qla_host_t *, uint16_t);
static inline int
qla2x00_is_reserved_id(scsi_qla_host_t *ha, uint16_t loop_id)
{
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
return (loop_id > NPH_LAST_HANDLE);
return ((loop_id > ha->last_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c71863ff5489..3a5e78cb6b3f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -326,7 +326,7 @@ qla2x00_start_scsi(srb_t *sp)
tot_dsds = nseg;
/* Calculate the number of request entries needed. */
- req_cnt = ha->isp_ops.calc_req_entries(tot_dsds);
+ req_cnt = ha->isp_ops->calc_req_entries(tot_dsds);
if (ha->req_q_cnt < (req_cnt + 2)) {
cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
if (ha->req_ring_index < cnt)
@@ -364,7 +364,7 @@ qla2x00_start_scsi(srb_t *sp)
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
- ha->isp_ops.build_iocbs(sp, cmd_pkt, tot_dsds);
+ ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds);
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
@@ -432,7 +432,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
@@ -487,7 +487,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
for (timer = HZ; timer; timer--) {
if ((req_cnt + 2) >= ha->req_q_cnt) {
/* Calculate number of free request entries. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
cnt = (uint16_t)RD_REG_DWORD(
&reg->isp24.req_q_out);
else
@@ -561,7 +561,7 @@ qla2x00_isp_cmd(scsi_qla_host_t *ha)
ha->request_ring_ptr++;
/* Set chip new ring index. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, ha->req_ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 0ba4c8d37879..eecae9905ece 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -143,7 +143,7 @@ qla2300_intr_handler(int irq, void *dev_id)
WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
RD_REG_WORD(&reg->hccr);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSR_RISC_INT) == 0)
@@ -247,7 +247,7 @@ void
qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
{
#define LS_UNKNOWN 2
- static char *link_speeds[5] = { "1", "2", "?", "4", "10" };
+ static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
char *link_speed;
uint16_t handle_cnt;
uint16_t cnt;
@@ -334,9 +334,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
mb[1], mb[2], mb[3]);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
if (mb[1] == 0 && mb[2] == 0) {
qla_printk(KERN_ERR, ha,
"Unrecoverable Hardware Error: adapter "
@@ -490,6 +490,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
ha->flags.gpsc_supported = 1;
+ ha->flags.management_server_logged_in = 0;
break;
case MBA_CHG_IN_CONNECTION: /* Change in connection mode */
@@ -601,7 +602,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
"scsi(%ld): [R|Z]IO update completion.\n",
ha->host_no));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
qla24xx_process_response_queue(ha);
else
qla2x00_process_response_queue(ha);
@@ -823,7 +824,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
sts = (sts_entry_t *) pkt;
sts24 = (struct sts_entry_24xx *) pkt;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
comp_status = le16_to_cpu(sts24->comp_status);
scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
} else {
@@ -872,7 +873,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
fcport = sp->fcport;
sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
sense_len = le32_to_cpu(sts24->sense_len);
rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
resid_len = le32_to_cpu(sts24->rsp_residual_count);
@@ -891,7 +892,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
/* Check for any FCP transport errors. */
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
/* Sense data lies beyond any FCP RESPONSE data. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
sense_data += rsp_info_len;
if (rsp_info_len > 3 && rsp_info[3]) {
DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
@@ -990,7 +991,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
case CS_DATA_UNDERRUN:
resid = resid_len;
/* Use F/W calculated residual length. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
resid = fw_resid_len;
if (scsi_status & SS_RESIDUAL_UNDER) {
@@ -1062,6 +1063,25 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
cp->device->id, cp->device->lun, cp,
cp->serial_number));
+ /*
+ * In case of a Underrun condition, set both the lscsi
+ * status and the completion status to appropriate
+ * values.
+ */
+ if (resid &&
+ ((unsigned)(scsi_bufflen(cp) - resid) <
+ cp->underflow)) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp)));
+
+ cp->result = DID_ERROR << 16 | lscsi_status;
+ }
+
if (sense_len)
DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
CMD_ACTUAL_SNSLEN(cp)));
@@ -1166,7 +1186,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
case CS_TIMEOUT:
cp->result = DID_BUS_BUSY << 16;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
DEBUG2(printk(KERN_INFO
"scsi(%ld:%d:%d:%d): TIMEOUT status detected "
"0x%x-0x%x\n", ha->host_no, cp->device->channel,
@@ -1235,7 +1255,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
}
/* Move sense data. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
host_to_fcp_swap(pkt->data, sizeof(pkt->data));
memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
@@ -1483,7 +1503,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSRX_RISC_INT) == 0)
@@ -1617,7 +1637,7 @@ qla24xx_msix_default(int irq, void *dev_id)
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSRX_RISC_INT) == 0)
@@ -1739,11 +1759,11 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
int ret;
/* If possible, enable MSI-X. */
- if (!IS_QLA2432(ha))
+ if (!IS_QLA2432(ha) && !IS_QLA2532(ha))
goto skip_msix;
- if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
- !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) {
+ if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
+ !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
ha->chip_revision, ha->fw_attributes));
@@ -1762,7 +1782,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
"MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
- if (!IS_QLA24XX(ha))
+ if (!IS_QLA24XX(ha) && !IS_QLA2532(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
@@ -1772,7 +1792,7 @@ skip_msix:
}
skip_msi:
- ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
+ ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
if (!ret) {
ha->flags.inta_enabled = 1;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 2cd0cff25928..d3746ec80a85 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -90,7 +90,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Load mailbox registers. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
optr = (uint16_t __iomem *)&reg->isp24.mailbox0;
else
optr = (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 0);
@@ -154,7 +154,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
else
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -175,7 +175,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
ha->host_no, command));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
else
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -228,7 +228,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
uint16_t mb0;
uint32_t ictrl;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mb0 = RD_REG_WORD(&reg->isp24.mailbox0);
ictrl = RD_REG_DWORD(&reg->isp24.ictrl);
} else {
@@ -322,7 +322,7 @@ qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr,
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
- if (MSW(risc_addr) || IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) {
mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
mcp->mb[8] = MSW(risc_addr);
mcp->out_mb = MBX_8|MBX_0;
@@ -336,7 +336,7 @@ qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr,
mcp->mb[6] = MSW(MSD(req_dma));
mcp->mb[7] = LSW(MSD(req_dma));
mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[4] = MSW(risc_code_size);
mcp->mb[5] = LSW(risc_code_size);
mcp->out_mb |= MBX_5|MBX_4;
@@ -387,7 +387,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
@@ -410,7 +410,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
ha->host_no, rval, mcp->mb[0]));
} else {
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
__func__, ha->host_no, mcp->mb[1]));
} else {
@@ -551,7 +551,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts)
mcp->mb[3] = fwopts[3];
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->in_mb |= MBX_1;
} else {
mcp->mb[10] = fwopts[10];
@@ -664,7 +664,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
mcp->mb[0] = MBC_VERIFY_CHECKSUM;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->out_mb |= MBX_2|MBX_1;
@@ -681,8 +681,8 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
- ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
- (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1])));
+ ha->host_no, rval, IS_FWI2_CAPABLE(ha) ?
+ (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));
} else {
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
@@ -739,7 +739,7 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr,
/* Mask reserved bits. */
sts_entry->entry_status &=
- IS_QLA24XX(ha) || IS_QLA54XX(ha) ? RF_MASK_24XX :RF_MASK;
+ IS_FWI2_CAPABLE(ha) ? RF_MASK_24XX :RF_MASK;
}
return rval;
@@ -1085,7 +1085,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE));
mcp->mb[0] = MBC_GET_PORT_DATABASE;
- if (opt != 0 && !IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (opt != 0 && !IS_FWI2_CAPABLE(ha))
mcp->mb[0] = MBC_ENHANCED_GET_PORT_DATABASE;
mcp->mb[2] = MSW(pd_dma);
mcp->mb[3] = LSW(pd_dma);
@@ -1094,7 +1094,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
mcp->mb[9] = ha->vp_idx;
mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = fcport->loop_id;
mcp->mb[10] = opt;
mcp->out_mb |= MBX_10|MBX_1;
@@ -1107,15 +1107,15 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
mcp->mb[1] = fcport->loop_id << 8 | opt;
mcp->out_mb |= MBX_1;
}
- mcp->buf_size = (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
- PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE);
+ mcp->buf_size = IS_FWI2_CAPABLE(ha) ?
+ PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE;
mcp->flags = MBX_DMA_IN;
mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
rval = qla2x00_mailbox_command(ha, mcp);
if (rval != QLA_SUCCESS)
goto gpd_error_out;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
pd24 = (struct port_database_24xx *) pd;
/* Check for logged in state. */
@@ -1333,7 +1333,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
mcp->mb[1] = BIT_6;
mcp->mb[2] = 0;
@@ -1637,7 +1637,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
return qla24xx_login_fabric(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb_ret, opt);
@@ -1821,7 +1821,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
ha->host_no));
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
- mcp->mb[1] = IS_QLA24XX(ha) || IS_QLA54XX(ha) ? BIT_3: 0;
+ mcp->mb[1] = IS_FWI2_CAPABLE(ha) ? BIT_3: 0;
mcp->mb[2] = 0;
mcp->mb[3] = 0;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1871,7 +1871,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
mcp->mb[0] = MBC_GET_ID_LIST;
mcp->out_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[2] = MSW(id_list_dma);
mcp->mb[3] = LSW(id_list_dma);
mcp->mb[6] = MSW(MSD(id_list_dma));
@@ -2063,7 +2063,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
mcp->mb[7] = LSW(MSD(stat_buf_dma));
mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = loop_id;
mcp->mb[4] = 0;
mcp->mb[10] = 0;
@@ -2334,7 +2334,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2444,7 +2444,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2474,7 +2474,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2514,7 +2514,7 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2552,7 +2552,7 @@ qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2595,7 +2595,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b5a77b0c0deb..acca898ce0a2 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -265,6 +265,8 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
strcpy(str, "PCIe (");
if (lspeed == 1)
strcat(str, "2.5Gb/s ");
+ else if (lspeed == 2)
+ strcat(str, "5.0Gb/s ");
else
strcat(str, "<unknown> ");
snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
@@ -343,6 +345,12 @@ qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
strcat(str, "[IP] ");
if (ha->fw_attributes & BIT_2)
strcat(str, "[Multi-ID] ");
+ if (ha->fw_attributes & BIT_3)
+ strcat(str, "[SB-2] ");
+ if (ha->fw_attributes & BIT_4)
+ strcat(str, "[T10 CRC] ");
+ if (ha->fw_attributes & BIT_5)
+ strcat(str, "[VI] ");
if (ha->fw_attributes & BIT_13)
strcat(str, "[Experimental]");
return str;
@@ -681,7 +689,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
DEBUG3(qla2x00_print_scsi_cmd(cmd));
spin_unlock_irqrestore(&pha->hardware_lock, flags);
- if (ha->isp_ops.abort_command(ha, sp)) {
+ if (ha->isp_ops->abort_command(ha, sp)) {
DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, ha->host_no));
} else {
@@ -813,7 +821,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
#if defined(LOGOUT_AFTER_DEVICE_RESET)
if (ret == SUCCESS) {
if (fcport->flags & FC_FABRIC_DEVICE) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id);
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id);
qla2x00_mark_device_lost(ha, fcport, 0, 0);
}
}
@@ -1105,7 +1113,7 @@ static int
qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
{
/* Abort Target command will clear Reservation */
- return ha->isp_ops.abort_target(reset_fcport);
+ return ha->isp_ops->abort_target(reset_fcport);
}
static int
@@ -1184,8 +1192,8 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
!pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
/* Ok, a 64bit DMA mask is applicable. */
ha->flags.enable_64bit_addressing = 1;
- ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64;
- ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64;
+ ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
+ ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
return;
}
}
@@ -1194,6 +1202,193 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
}
+static void
+qla2x00_enable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 1;
+ /* enable risc and host interrupts */
+ WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
+ RD_REG_WORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+static void
+qla2x00_disable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 0;
+ /* disable risc and host interrupts */
+ WRT_REG_WORD(&reg->ictrl, 0);
+ RD_REG_WORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_enable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 1;
+ WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
+ RD_REG_DWORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_disable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 0;
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static struct isp_operations qla2100_isp_ops = {
+ .pci_config = qla2100_pci_config,
+ .reset_chip = qla2x00_reset_chip,
+ .chip_diag = qla2x00_chip_diag,
+ .config_rings = qla2x00_config_rings,
+ .reset_adapter = qla2x00_reset_adapter,
+ .nvram_config = qla2x00_nvram_config,
+ .update_fw_options = qla2x00_update_fw_options,
+ .load_risc = qla2x00_load_risc,
+ .pci_info_str = qla2x00_pci_info_str,
+ .fw_version_str = qla2x00_fw_version_str,
+ .intr_handler = qla2100_intr_handler,
+ .enable_intrs = qla2x00_enable_intrs,
+ .disable_intrs = qla2x00_disable_intrs,
+ .abort_command = qla2x00_abort_command,
+ .abort_target = qla2x00_abort_target,
+ .fabric_login = qla2x00_login_fabric,
+ .fabric_logout = qla2x00_fabric_logout,
+ .calc_req_entries = qla2x00_calc_iocbs_32,
+ .build_iocbs = qla2x00_build_scsi_iocbs_32,
+ .prep_ms_iocb = qla2x00_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb,
+ .read_nvram = qla2x00_read_nvram_data,
+ .write_nvram = qla2x00_write_nvram_data,
+ .fw_dump = qla2100_fw_dump,
+ .beacon_on = NULL,
+ .beacon_off = NULL,
+ .beacon_blink = NULL,
+ .read_optrom = qla2x00_read_optrom_data,
+ .write_optrom = qla2x00_write_optrom_data,
+ .get_flash_version = qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla2300_isp_ops = {
+ .pci_config = qla2300_pci_config,
+ .reset_chip = qla2x00_reset_chip,
+ .chip_diag = qla2x00_chip_diag,
+ .config_rings = qla2x00_config_rings,
+ .reset_adapter = qla2x00_reset_adapter,
+ .nvram_config = qla2x00_nvram_config,
+ .update_fw_options = qla2x00_update_fw_options,
+ .load_risc = qla2x00_load_risc,
+ .pci_info_str = qla2x00_pci_info_str,
+ .fw_version_str = qla2x00_fw_version_str,
+ .intr_handler = qla2300_intr_handler,
+ .enable_intrs = qla2x00_enable_intrs,
+ .disable_intrs = qla2x00_disable_intrs,
+ .abort_command = qla2x00_abort_command,
+ .abort_target = qla2x00_abort_target,
+ .fabric_login = qla2x00_login_fabric,
+ .fabric_logout = qla2x00_fabric_logout,
+ .calc_req_entries = qla2x00_calc_iocbs_32,
+ .build_iocbs = qla2x00_build_scsi_iocbs_32,
+ .prep_ms_iocb = qla2x00_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb,
+ .read_nvram = qla2x00_read_nvram_data,
+ .write_nvram = qla2x00_write_nvram_data,
+ .fw_dump = qla2300_fw_dump,
+ .beacon_on = qla2x00_beacon_on,
+ .beacon_off = qla2x00_beacon_off,
+ .beacon_blink = qla2x00_beacon_blink,
+ .read_optrom = qla2x00_read_optrom_data,
+ .write_optrom = qla2x00_write_optrom_data,
+ .get_flash_version = qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla24xx_isp_ops = {
+ .pci_config = qla24xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla24xx_nvram_config,
+ .update_fw_options = qla24xx_update_fw_options,
+ .load_risc = qla24xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .abort_target = qla24xx_abort_target,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla24xx_read_nvram_data,
+ .write_nvram = qla24xx_write_nvram_data,
+ .fw_dump = qla24xx_fw_dump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla24xx_beacon_blink,
+ .read_optrom = qla24xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+};
+
+static struct isp_operations qla25xx_isp_ops = {
+ .pci_config = qla25xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla24xx_nvram_config,
+ .update_fw_options = qla24xx_update_fw_options,
+ .load_risc = qla24xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .abort_target = qla24xx_abort_target,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla25xx_read_nvram_data,
+ .write_nvram = qla25xx_write_nvram_data,
+ .fw_dump = qla25xx_fw_dump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla24xx_beacon_blink,
+ .read_optrom = qla24xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+};
+
static inline void
qla2x00_set_isp_flags(scsi_qla_host_t *ha)
{
@@ -1238,19 +1433,32 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
case PCI_DEVICE_ID_QLOGIC_ISP2422:
ha->device_type |= DT_ISP2422;
ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2432:
ha->device_type |= DT_ISP2432;
ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP5422:
ha->device_type |= DT_ISP5422;
+ ha->device_type |= DT_FWI2;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP5432:
ha->device_type |= DT_ISP5432;
+ ha->device_type |= DT_FWI2;
+ ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+ break;
+ case PCI_DEVICE_ID_QLOGIC_ISP2532:
+ ha->device_type |= DT_ISP2532;
+ ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
}
@@ -1323,61 +1531,6 @@ iospace_error_exit:
}
static void
-qla2x00_enable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 1;
- /* enable risc and host interrupts */
- WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
- RD_REG_WORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-}
-
-static void
-qla2x00_disable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 0;
- /* disable risc and host interrupts */
- WRT_REG_WORD(&reg->ictrl, 0);
- RD_REG_WORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_enable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 1;
- WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
- RD_REG_DWORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_disable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 0;
- WRT_REG_DWORD(&reg->ictrl, 0);
- RD_REG_DWORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
qla2xxx_scan_start(struct Scsi_Host *shost)
{
scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
@@ -1411,7 +1564,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
struct Scsi_Host *host;
scsi_qla_host_t *ha;
unsigned long flags = 0;
- char pci_info[20];
+ char pci_info[30];
char fw_str[30];
struct scsi_host_template *sht;
@@ -1422,7 +1575,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432)
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532)
sht = &qla24xx_driver_template;
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
if (host == NULL) {
@@ -1466,33 +1620,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->max_q_depth = ql2xmaxqdepth;
/* Assign ISP specific operations. */
- ha->isp_ops.pci_config = qla2100_pci_config;
- ha->isp_ops.reset_chip = qla2x00_reset_chip;
- ha->isp_ops.chip_diag = qla2x00_chip_diag;
- ha->isp_ops.config_rings = qla2x00_config_rings;
- ha->isp_ops.reset_adapter = qla2x00_reset_adapter;
- ha->isp_ops.nvram_config = qla2x00_nvram_config;
- ha->isp_ops.update_fw_options = qla2x00_update_fw_options;
- ha->isp_ops.load_risc = qla2x00_load_risc;
- ha->isp_ops.pci_info_str = qla2x00_pci_info_str;
- ha->isp_ops.fw_version_str = qla2x00_fw_version_str;
- ha->isp_ops.intr_handler = qla2100_intr_handler;
- ha->isp_ops.enable_intrs = qla2x00_enable_intrs;
- ha->isp_ops.disable_intrs = qla2x00_disable_intrs;
- ha->isp_ops.abort_command = qla2x00_abort_command;
- ha->isp_ops.abort_target = qla2x00_abort_target;
- ha->isp_ops.fabric_login = qla2x00_login_fabric;
- ha->isp_ops.fabric_logout = qla2x00_fabric_logout;
- ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32;
- ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32;
- ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb;
- ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb;
- ha->isp_ops.read_nvram = qla2x00_read_nvram_data;
- ha->isp_ops.write_nvram = qla2x00_write_nvram_data;
- ha->isp_ops.fw_dump = qla2100_fw_dump;
- ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
- ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
- ha->isp_ops.get_flash_version = qla2x00_get_flash_version;
if (IS_QLA2100(ha)) {
host->max_id = MAX_TARGETS_2100;
ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1501,6 +1628,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
host->sg_tablesize = 32;
ha->gid_list_info_size = 4;
+ ha->isp_ops = &qla2100_isp_ops;
} else if (IS_QLA2200(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1508,21 +1636,17 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
ha->gid_list_info_size = 4;
+ ha->isp_ops = &qla2100_isp_ops;
} else if (IS_QLA23XX(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
ha->request_q_length = REQUEST_ENTRY_CNT_2200;
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
- ha->isp_ops.pci_config = qla2300_pci_config;
- ha->isp_ops.intr_handler = qla2300_intr_handler;
- ha->isp_ops.fw_dump = qla2300_fw_dump;
- ha->isp_ops.beacon_on = qla2x00_beacon_on;
- ha->isp_ops.beacon_off = qla2x00_beacon_off;
- ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
ha->gid_list_info_size = 6;
if (IS_QLA2322(ha) || IS_QLA6322(ha))
ha->optrom_size = OPTROM_SIZE_2322;
+ ha->isp_ops = &qla2300_isp_ops;
} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1531,36 +1655,20 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
- ha->isp_ops.pci_config = qla24xx_pci_config;
- ha->isp_ops.reset_chip = qla24xx_reset_chip;
- ha->isp_ops.chip_diag = qla24xx_chip_diag;
- ha->isp_ops.config_rings = qla24xx_config_rings;
- ha->isp_ops.reset_adapter = qla24xx_reset_adapter;
- ha->isp_ops.nvram_config = qla24xx_nvram_config;
- ha->isp_ops.update_fw_options = qla24xx_update_fw_options;
- ha->isp_ops.load_risc = qla24xx_load_risc;
- ha->isp_ops.pci_info_str = qla24xx_pci_info_str;
- ha->isp_ops.fw_version_str = qla24xx_fw_version_str;
- ha->isp_ops.intr_handler = qla24xx_intr_handler;
- ha->isp_ops.enable_intrs = qla24xx_enable_intrs;
- ha->isp_ops.disable_intrs = qla24xx_disable_intrs;
- ha->isp_ops.abort_command = qla24xx_abort_command;
- ha->isp_ops.abort_target = qla24xx_abort_target;
- ha->isp_ops.fabric_login = qla24xx_login_fabric;
- ha->isp_ops.fabric_logout = qla24xx_fabric_logout;
- ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb;
- ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb;
- ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
- ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
- ha->isp_ops.fw_dump = qla24xx_fw_dump;
- ha->isp_ops.read_optrom = qla24xx_read_optrom_data;
- ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
- ha->isp_ops.beacon_on = qla24xx_beacon_on;
- ha->isp_ops.beacon_off = qla24xx_beacon_off;
- ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
- ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_24XX;
+ ha->isp_ops = &qla24xx_isp_ops;
+ } else if (IS_QLA25XX(ha)) {
+ host->max_id = MAX_TARGETS_2200;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT;
+ ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
+ ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
+ ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
+ ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+ ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
+ ha->gid_list_info_size = 8;
+ ha->optrom_size = OPTROM_SIZE_25XX;
+ ha->isp_ops = &qla25xx_isp_ops;
}
host->can_queue = ha->request_q_length + 128;
@@ -1628,11 +1736,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
ha->host_no, ha));
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
reg = ha->iobase;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
} else {
@@ -1654,7 +1762,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
pci_set_drvdata(pdev, ha);
@@ -1679,9 +1787,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
" ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
qla2x00_version_str, ha->model_number,
ha->model_desc ? ha->model_desc: "", pdev->device,
- ha->isp_ops.pci_info_str(ha, pci_info), pci_name(pdev),
+ ha->isp_ops->pci_info_str(ha, pci_info), pci_name(pdev),
ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
- ha->isp_ops.fw_version_str(ha, fw_str));
+ ha->isp_ops->fw_version_str(ha, fw_str));
return 0;
@@ -1747,7 +1855,7 @@ qla2x00_free_device(scsi_qla_host_t *ha)
/* turn-off interrupts on the card */
if (ha->interrupts_on)
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
qla2x00_mem_free(ha);
@@ -2025,7 +2133,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
}
memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
/*
* Get consistent memory allocated for SFP
* block.
@@ -2046,6 +2154,19 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
}
}
+ /* Get memory for cached NVRAM */
+ ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
+ if (ha->nvram == NULL) {
+ /* error */
+ qla_printk(KERN_WARNING, ha,
+ "Memory Allocation failed - nvram cache\n");
+
+ qla2x00_mem_free(ha);
+ msleep(100);
+
+ continue;
+ }
+
/* Done all allocations without any error. */
status = 0;
@@ -2158,6 +2279,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
ha->fw_dump_reading = 0;
vfree(ha->optrom_buffer);
+ kfree(ha->nvram);
}
/*
@@ -2305,7 +2427,7 @@ qla2x00_do_dpc(void *data)
if (fcport->flags & FCF_FABRIC_DEVICE) {
if (fcport->flags &
FCF_TAPE_PRESENT)
- ha->isp_ops.fabric_logout(
+ ha->isp_ops->fabric_logout(
ha, fcport->loop_id,
fcport->d_id.b.domain,
fcport->d_id.b.area,
@@ -2385,10 +2507,10 @@ qla2x00_do_dpc(void *data)
}
if (!ha->interrupts_on)
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
- ha->isp_ops.beacon_blink(ha);
+ ha->isp_ops->beacon_blink(ha);
qla2x00_do_dpc_all_vps(ha);
@@ -2617,18 +2739,20 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
/* Firmware interface routines. */
-#define FW_BLOBS 5
+#define FW_BLOBS 6
#define FW_ISP21XX 0
#define FW_ISP22XX 1
#define FW_ISP2300 2
#define FW_ISP2322 3
#define FW_ISP24XX 4
+#define FW_ISP25XX 5
#define FW_FILE_ISP21XX "ql2100_fw.bin"
#define FW_FILE_ISP22XX "ql2200_fw.bin"
#define FW_FILE_ISP2300 "ql2300_fw.bin"
#define FW_FILE_ISP2322 "ql2322_fw.bin"
#define FW_FILE_ISP24XX "ql2400_fw.bin"
+#define FW_FILE_ISP25XX "ql2500_fw.bin"
static DECLARE_MUTEX(qla_fw_lock);
@@ -2638,6 +2762,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
{ .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
{ .name = FW_FILE_ISP24XX, },
+ { .name = FW_FILE_ISP25XX, },
};
struct fw_blob *
@@ -2656,6 +2781,8 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
blob = &qla_fw_blobs[FW_ISP2322];
} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
blob = &qla_fw_blobs[FW_ISP24XX];
+ } else if (IS_QLA25XX(ha)) {
+ blob = &qla_fw_blobs[FW_ISP25XX];
}
down(&qla_fw_lock);
@@ -2699,6 +2826,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -2723,7 +2851,7 @@ qla2x00_module_init(void)
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (srb_cachep == NULL) {
printk(KERN_ERR
"qla2xxx: Unable to allocate SRB cache...Failing load!\n");
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 206bda093da2..a925a3f179f9 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -766,6 +766,29 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
return ret;
}
+uint8_t *
+qla25xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ uint32_t i;
+ uint32_t *dwptr;
+
+ /* Dword reads to flash. */
+ dwptr = (uint32_t *)buf;
+ for (i = 0; i < bytes >> 2; i++, naddr++)
+ dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+ flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr)));
+
+ return buf;
+}
+
+int
+qla25xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ return qla24xx_write_flash_data(ha, (uint32_t *)buf,
+ FA_VPD_NVRAM_ADDR | naddr, bytes >> 2);
+}
static inline void
qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags)
@@ -919,7 +942,7 @@ qla2x00_beacon_off(struct scsi_qla_host *ha)
else
ha->beacon_color_state = QLA_LED_GRN_ON;
- ha->isp_ops.beacon_blink(ha); /* This turns green LED off */
+ ha->isp_ops->beacon_blink(ha); /* This turns green LED off */
ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7;
@@ -1031,7 +1054,7 @@ qla24xx_beacon_off(struct scsi_qla_host *ha)
ha->beacon_blink_led = 0;
ha->beacon_color_state = QLA_LED_ALL_ON;
- ha->isp_ops.beacon_blink(ha); /* Will flip to all off. */
+ ha->isp_ops->beacon_blink(ha); /* Will flip to all off. */
/* Give control back to firmware. */
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1419,7 +1442,7 @@ qla2x00_suspend_hba(struct scsi_qla_host *ha)
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Pause RISC. */
@@ -1705,7 +1728,7 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
{
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with read. */
@@ -1713,7 +1736,7 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Resume HBA. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
scsi_unblock_requests(ha->host);
return buf;
@@ -1727,7 +1750,7 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with write. */
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index fd2f10a25348..18095b9b76f4 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.00-k1"
+#define QLA2XXX_VERSION "8.02.00-k3"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index e69160a7bc60..b1d565c12c5b 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1677,7 +1677,7 @@ static int __init qla4xxx_module_init(void)
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (srb_cachep == NULL) {
printk(KERN_ERR
"%s: Unable to allocate SRB cache..."
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index c4195ea869e9..594887205b0f 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -193,7 +193,8 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f
cpu_relax();
}
if (!loop_count)
- printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #1\n");
+ printk(KERN_EMERG "qlogicpti%d: mbox_command loop timeout #1\n",
+ qpti->qpti_id);
/* Write mailbox command registers. */
switch (mbox_param[param[0]] >> 4) {
@@ -224,8 +225,8 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f
(sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_CRIRQ))
udelay(20);
if (!loop_count)
- printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #2\n",
- param[0]);
+ printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #2\n",
+ qpti->qpti_id, param[0]);
/* Wait for SBUS semaphore to get set. */
loop_count = DEFAULT_LOOP_COUNT;
@@ -238,16 +239,16 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f
break;
}
if (!loop_count)
- printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #3\n",
- param[0]);
+ printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #3\n",
+ qpti->qpti_id, param[0]);
/* Wait for MBOX busy condition to go away. */
loop_count = DEFAULT_LOOP_COUNT;
while (--loop_count && (sbus_readw(qpti->qregs + MBOX0) == 0x04))
udelay(20);
if (!loop_count)
- printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #4\n",
- param[0]);
+ printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #4\n",
+ qpti->qpti_id, param[0]);
/* Read back output parameters. */
switch (mbox_param[param[0]] & 0xf) {
@@ -342,7 +343,8 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
while (--loop_count && ((sbus_readw(qpti->qregs + MBOX0) & 0xff) == 0x04))
udelay(20);
if (!loop_count)
- printk(KERN_EMERG "qlogicpti: reset_hardware loop timeout\n");
+ printk(KERN_EMERG "qlogicpti%d: reset_hardware loop timeout\n",
+ qpti->qpti_id);
sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);
set_sbus_cfg1(qpti);
@@ -721,12 +723,12 @@ static int __init qpti_register_irq(struct qlogicpti *qpti)
IRQF_SHARED, "Qlogic/PTI", qpti))
goto fail;
- printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
+ printk("qlogicpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
return 0;
fail:
- printk("qpti%d: Cannot acquire irq line\n", qpti->qpti_id);
+ printk("qlogicpti%d: Cannot acquire irq line\n", qpti->qpti_id);
return -1;
}
@@ -1210,7 +1212,7 @@ static int qlogicpti_return_status(struct Status_Entry *sts, int id)
host_status = DID_OK;
break;
default:
- printk(KERN_EMERG "qpti%d: unknown completion status 0x%04x\n",
+ printk(KERN_EMERG "qlogicpti%d: unknown completion status 0x%04x\n",
id, sts->completion_status);
host_status = DID_ERROR;
break;
@@ -1329,8 +1331,8 @@ static int qlogicpti_abort(struct scsi_cmnd *Cmnd)
u32 cmd_cookie;
int i;
- printk(KERN_WARNING "qlogicpti : Aborting cmd for tgt[%d] lun[%d]\n",
- (int)Cmnd->device->id, (int)Cmnd->device->lun);
+ printk(KERN_WARNING "qlogicpti%d: Aborting cmd for tgt[%d] lun[%d]\n",
+ qpti->qpti_id, (int)Cmnd->device->id, (int)Cmnd->device->lun);
qlogicpti_disable_irqs(qpti);
@@ -1348,7 +1350,8 @@ static int qlogicpti_abort(struct scsi_cmnd *Cmnd)
param[3] = cmd_cookie & 0xffff;
if (qlogicpti_mbox_command(qpti, param, 0) ||
(param[0] != MBOX_COMMAND_COMPLETE)) {
- printk(KERN_EMERG "qlogicpti : scsi abort failure: %x\n", param[0]);
+ printk(KERN_EMERG "qlogicpti%d: scsi abort failure: %x\n",
+ qpti->qpti_id, param[0]);
return_status = FAILED;
}
@@ -1364,7 +1367,8 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
int return_status = SUCCESS;
- printk(KERN_WARNING "qlogicpti : Resetting SCSI bus!\n");
+ printk(KERN_WARNING "qlogicpti%d: Resetting SCSI bus!\n",
+ qpti->qpti_id);
qlogicpti_disable_irqs(qpti);
@@ -1372,7 +1376,8 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
param[1] = qpti->host_param.bus_reset_delay;
if (qlogicpti_mbox_command(qpti, param, 0) ||
(param[0] != MBOX_COMMAND_COMPLETE)) {
- printk(KERN_EMERG "qlogicisp : scsi bus reset failure: %x\n", param[0]);
+ printk(KERN_EMERG "qlogicisp%d: scsi bus reset failure: %x\n",
+ qpti->qpti_id, param[0]);
return_status = FAILED;
}
@@ -1454,22 +1459,25 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
if (qlogicpti_reset_hardware(host))
goto fail_unmap_queues;
- if (scsi_add_host(host, &dev->dev))
- goto fail_unmap_queues;
-
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
qpti->fware_minrev, qpti->fware_micrev);
fcode = of_get_property(dp, "isp-fcode", NULL);
if (fcode && fcode[0])
- printk("(Firmware %s)", fcode);
+ printk("(FCode %s)", fcode);
if (of_find_property(dp, "differential", NULL) != NULL)
qpti->differential = 1;
- printk (" [%s Wide, using %s interface]\n",
+ printk("\nqlogicpti%d: [%s Wide, using %s interface]\n",
+ qpti->qpti_id,
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
+ if (scsi_add_host(host, &dev->dev)) {
+ printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
+ goto fail_unmap_queues;
+ }
+
dev_set_drvdata(&sdev->ofdev.dev, qpti);
qpti_chain_add(qpti);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a691dda40d2c..a5de1a829a76 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -288,7 +288,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
if (!pool->users) {
pool->slab = kmem_cache_create(pool->name,
sizeof(struct scsi_cmnd), 0,
- pool->slab_flags, NULL, NULL);
+ pool->slab_flags, NULL);
if (!pool->slab)
goto fail;
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 4cd9c58efef1..4947dfe625a6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -2875,7 +2875,7 @@ static int __init scsi_debug_init(void)
init_all_queued();
- sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
+ sdebug_driver_template.proc_name = sdebug_proc_name;
host_to_add = scsi_debug_add_host;
scsi_debug_add_host = 0;
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 19c44f0781fd..e2ea739e33df 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -154,6 +154,9 @@ static struct {
{"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
{"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN},
+ {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN},
+ {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN},
+ {"easyRAID", "F8", NULL, BLIST_NOREPORTLUN},
{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36},
{"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 1f5a07bf2a75..604f4d717933 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -263,25 +263,12 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio)
bio->bi_rw |= (1 << BIO_RW);
blk_queue_bounce(q, &bio);
- if (!rq->bio)
- blk_rq_bio_prep(q, rq, bio);
- else if (!ll_back_merge_fn(q, rq, bio))
- return -EINVAL;
- else {
- rq->biotail->bi_next = bio;
- rq->biotail = bio;
- }
-
- return 0;
+ return blk_rq_append_bio(q, rq, bio);
}
-static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error)
+static void scsi_bi_endio(struct bio *bio, int error)
{
- if (bio->bi_size)
- return 1;
-
bio_put(bio);
- return 0;
}
/**
@@ -337,7 +324,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
if (bio->bi_vcnt >= nr_vecs) {
err = scsi_merge_bio(rq, bio);
if (err) {
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
goto free_bios;
}
bio = NULL;
@@ -359,7 +346,7 @@ free_bios:
/*
* call endio instead of bio_put incase it was bounced
*/
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
}
return err;
@@ -654,7 +641,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
int bytes, int requeue)
{
- request_queue_t *q = cmd->device->request_queue;
+ struct request_queue *q = cmd->device->request_queue;
struct request *req = cmd->request;
unsigned long flags;
@@ -818,7 +805,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
int result = cmd->result;
int this_count = cmd->request_bufflen;
- request_queue_t *q = cmd->device->request_queue;
+ struct request_queue *q = cmd->device->request_queue;
struct request *req = cmd->request;
int clear_errors = 1;
struct scsi_sense_hdr sshdr;
@@ -1038,22 +1025,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
return BLKPREP_KILL;
}
-static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- struct scsi_device *sdev = q->queuedata;
- struct scsi_driver *drv;
-
- if (sdev->sdev_state != SDEV_RUNNING)
- return -ENXIO;
-
- drv = *(struct scsi_driver **) disk->private_data;
- if (drv->issue_flush)
- return drv->issue_flush(&sdev->sdev_gendev, error_sector);
-
- return -EOPNOTSUPP;
-}
-
static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
struct request *req)
{
@@ -1340,7 +1311,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
/*
* Kill a request for a dead device
*/
-static void scsi_kill_request(struct request *req, request_queue_t *q)
+static void scsi_kill_request(struct request *req, struct request_queue *q)
{
struct scsi_cmnd *cmd = req->special;
struct scsi_device *sdev = cmd->device;
@@ -1596,7 +1567,6 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
return NULL;
blk_queue_prep_rq(q, scsi_prep_fn);
- blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
blk_queue_softirq_done(q, scsi_softirq_done);
return q;
}
@@ -1661,7 +1631,7 @@ int __init scsi_init_queue(void)
scsi_io_context_cache = kmem_cache_create("scsi_io_context",
sizeof(struct scsi_io_context),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!scsi_io_context_cache) {
printk(KERN_ERR "SCSI: can't init scsi io context cache\n");
return -ENOMEM;
@@ -1672,7 +1642,7 @@ int __init scsi_init_queue(void)
int size = sgp->size * sizeof(struct scatterlist);
sgp->slab = kmem_cache_create(sgp->name, size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!sgp->slab) {
printk(KERN_ERR "SCSI: can't init sg slab %s\n",
sgp->name);
@@ -2119,7 +2089,7 @@ EXPORT_SYMBOL(scsi_target_resume);
int
scsi_internal_device_block(struct scsi_device *sdev)
{
- request_queue_t *q = sdev->request_queue;
+ struct request_queue *q = sdev->request_queue;
unsigned long flags;
int err = 0;
@@ -2159,7 +2129,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
int
scsi_internal_device_unblock(struct scsi_device *sdev)
{
- request_queue_t *q = sdev->request_queue;
+ struct request_queue *q = sdev->request_queue;
int err;
unsigned long flags;
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 4bf9aa547c78..40579edca101 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -64,7 +64,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
err = -EBADMSG;
- goto next_msg;
+ return;
}
hdr = NLMSG_DATA(nlh);
@@ -99,27 +99,6 @@ next_msg:
/**
- * scsi_nl_rcv_msg -
- * Receive handler for a socket. Extracts a received message buffer from
- * the socket, and starts message processing.
- *
- * @sk: socket
- * @len: unused
- *
- **/
-static void
-scsi_nl_rcv(struct sock *sk, int len)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- scsi_nl_rcv_msg(skb);
- kfree_skb(skb);
- }
-}
-
-
-/**
* scsi_nl_rcv_event -
* Event handler for a netlink socket.
*
@@ -167,8 +146,8 @@ scsi_netlink_init(void)
return;
}
- scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
- SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
+ scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
+ SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
THIS_MODULE);
if (!scsi_nl_sock) {
printk(KERN_ERR "%s: register of recieve handler failed\n",
diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
index 6cfaaa2d0c81..63a30f566f3a 100644
--- a/drivers/scsi/scsi_sysctl.c
+++ b/drivers/scsi/scsi_sysctl.c
@@ -9,6 +9,7 @@
#include <linux/sysctl.h>
#include "scsi_logging.h"
+#include "scsi_priv.h"
static ctl_table scsi_table[] = {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ed720863ab97..ede9986d349a 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -16,6 +16,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
+#include <scsi/scsi_driver.h>
#include "scsi_priv.h"
#include "scsi_logging.h"
@@ -276,16 +277,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
-static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct scsi_device *sdev = to_scsi_device(dev);
- int i = 0;
- int length = 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
- envp[i] = NULL;
+ add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
return 0;
}
@@ -714,6 +710,7 @@ static int attr_add(struct device *dev, struct device_attribute *attr)
int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{
int error, i;
+ struct request_queue *rq = sdev->request_queue;
if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
return error;
@@ -733,6 +730,17 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
/* take a reference for the sdev_classdev; this is
* released by the sdev_class .release */
get_device(&sdev->sdev_gendev);
+
+ error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
+
+ if (error)
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to register bsg queue, errno=%d\n", error);
+
+ /* we're treating error on bsg register as non-fatal, so pretend
+ * nothing went wrong */
+ error = 0;
+
if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
error = attr_add(&sdev->sdev_gendev,
@@ -779,6 +787,7 @@ void __scsi_remove_device(struct scsi_device *sdev)
if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
return;
+ bsg_unregister_queue(sdev->request_queue);
class_device_unregister(&sdev->sdev_classdev);
transport_remove_device(dev);
device_del(dev);
@@ -803,7 +812,7 @@ void scsi_remove_device(struct scsi_device *sdev)
}
EXPORT_SYMBOL(scsi_remove_device);
-void __scsi_remove_target(struct scsi_target *starget)
+static void __scsi_remove_target(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 2570f48a69c7..371b69c110bc 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -585,7 +585,7 @@ static int __init scsi_tgt_init(void)
scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
sizeof(struct scsi_tgt_cmd),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!scsi_tgt_cmd_cache)
return -ENOMEM;
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index e8825709797e..47057254850d 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2358,7 +2358,7 @@ fc_rport_final_delete(struct work_struct *work)
* Notes:
* This routine assumes no locks are held on entry.
**/
-struct fc_rport *
+static struct fc_rport *
fc_rport_create(struct Scsi_Host *shost, int channel,
struct fc_rport_identifiers *ids)
{
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 34c1860a259d..5428d15f23c6 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1097,61 +1097,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
/*
- * Get message from skb (based on rtnetlink_rcv_skb). Each message is
- * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or
- * invalid creds are discarded silently.
+ * Get message from skb. Each message is processed by iscsi_if_recv_msg.
+ * Malformed skbs with wrong lengths or invalid creds are not processed.
*/
static void
-iscsi_if_rx(struct sock *sk, int len)
+iscsi_if_rx(struct sk_buff *skb)
{
- struct sk_buff *skb;
-
mutex_lock(&rx_queue_mutex);
- while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
- if (NETLINK_CREDS(skb)->uid) {
- skb_pull(skb, skb->len);
- goto free_skb;
+ while (skb->len >= NLMSG_SPACE(0)) {
+ int err;
+ uint32_t rlen;
+ struct nlmsghdr *nlh;
+ struct iscsi_uevent *ev;
+
+ nlh = nlmsg_hdr(skb);
+ if (nlh->nlmsg_len < sizeof(*nlh) ||
+ skb->len < nlh->nlmsg_len) {
+ break;
}
- while (skb->len >= NLMSG_SPACE(0)) {
- int err;
- uint32_t rlen;
- struct nlmsghdr *nlh;
- struct iscsi_uevent *ev;
+ ev = NLMSG_DATA(nlh);
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
- nlh = nlmsg_hdr(skb);
- if (nlh->nlmsg_len < sizeof(*nlh) ||
- skb->len < nlh->nlmsg_len) {
- break;
- }
-
- ev = NLMSG_DATA(nlh);
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
-
- err = iscsi_if_recv_msg(skb, nlh);
- if (err) {
- ev->type = ISCSI_KEVENT_IF_ERROR;
- ev->iferror = err;
- }
- do {
- /*
- * special case for GET_STATS:
- * on success - sending reply and stats from
- * inside of if_recv_msg(),
- * on error - fall through.
- */
- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
- break;
- err = iscsi_if_send_reply(
- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
- } while (err < 0 && err != -ECONNREFUSED);
- skb_pull(skb, rlen);
+ err = iscsi_if_recv_msg(skb, nlh);
+ if (err) {
+ ev->type = ISCSI_KEVENT_IF_ERROR;
+ ev->iferror = err;
}
-free_skb:
- kfree_skb(skb);
+ do {
+ /*
+ * special case for GET_STATS:
+ * on success - sending reply and stats from
+ * inside of if_recv_msg(),
+ * on error - fall through.
+ */
+ if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
+ break;
+ err = iscsi_if_send_reply(
+ NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+ } while (err < 0 && err != -ECONNREFUSED);
+ skb_pull(skb, rlen);
}
mutex_unlock(&rx_queue_mutex);
}
@@ -1523,7 +1511,7 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_conn_class;
- nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
+ nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
THIS_MODULE);
if (!nls) {
err = -ENOBUFS;
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index b2ef71a86292..3120f4b3a11a 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -29,6 +29,8 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/bsg.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -40,6 +42,7 @@
struct sas_host_attrs {
struct list_head rphy_list;
struct mutex lock;
+ struct request_queue *q;
u32 next_target_id;
u32 next_expander_id;
int next_port_id;
@@ -152,6 +155,106 @@ static struct {
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
+static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
+ struct sas_rphy *rphy)
+{
+ struct request *req;
+ int ret;
+ int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
+
+ while (!blk_queue_plugged(q)) {
+ req = elv_next_request(q);
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+
+ spin_unlock_irq(q->queue_lock);
+
+ handler = to_sas_internal(shost->transportt)->f->smp_handler;
+ ret = handler(shost, rphy, req);
+
+ spin_lock_irq(q->queue_lock);
+
+ req->end_io(req, ret);
+ }
+}
+
+static void sas_host_smp_request(struct request_queue *q)
+{
+ sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL);
+}
+
+static void sas_non_host_smp_request(struct request_queue *q)
+{
+ struct sas_rphy *rphy = q->queuedata;
+ sas_smp_request(q, rphy_to_shost(rphy), rphy);
+}
+
+static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
+{
+ struct request_queue *q;
+ int error;
+ struct device *dev;
+ char namebuf[BUS_ID_SIZE];
+ const char *name;
+
+ if (!to_sas_internal(shost->transportt)->f->smp_handler) {
+ printk("%s can't handle SMP requests\n", shost->hostt->name);
+ return 0;
+ }
+
+ if (rphy) {
+ q = blk_init_queue(sas_non_host_smp_request, NULL);
+ dev = &rphy->dev;
+ name = dev->bus_id;
+ } else {
+ q = blk_init_queue(sas_host_smp_request, NULL);
+ dev = &shost->shost_gendev;
+ snprintf(namebuf, sizeof(namebuf),
+ "sas_host%d", shost->host_no);
+ name = namebuf;
+ }
+ if (!q)
+ return -ENOMEM;
+
+ error = bsg_register_queue(q, dev, name);
+ if (error) {
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ if (rphy)
+ rphy->q = q;
+ else
+ to_sas_host_attrs(shost)->q = q;
+
+ if (rphy)
+ q->queuedata = rphy;
+ else
+ q->queuedata = shost;
+
+ set_bit(QUEUE_FLAG_BIDI, &q->queue_flags);
+
+ return 0;
+}
+
+static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
+{
+ struct request_queue *q;
+
+ if (rphy)
+ q = rphy->q;
+ else
+ q = to_sas_host_attrs(shost)->q;
+
+ if (!q)
+ return;
+
+ bsg_unregister_queue(q);
+ blk_cleanup_queue(q);
+}
+
/*
* SAS host attributes
*/
@@ -167,11 +270,26 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
sas_host->next_target_id = 0;
sas_host->next_expander_id = 0;
sas_host->next_port_id = 0;
+
+ if (sas_bsg_initialize(shost, NULL))
+ dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
+ shost->host_no);
+
+ return 0;
+}
+
+static int sas_host_remove(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+
+ sas_bsg_remove(shost, NULL);
+
return 0;
}
static DECLARE_TRANSPORT_CLASS(sas_host_class,
- "sas_host", sas_host_setup, NULL, NULL);
+ "sas_host", sas_host_setup, sas_host_remove, NULL);
static int sas_host_match(struct attribute_container *cont,
struct device *dev)
@@ -1287,6 +1405,9 @@ int sas_rphy_add(struct sas_rphy *rphy)
return error;
transport_add_device(&rphy->dev);
transport_configure_device(&rphy->dev);
+ if (sas_bsg_initialize(shost, rphy))
+ printk("fail to a bsg device %s\n", rphy->dev.bus_id);
+
mutex_lock(&sas_host->lock);
list_add_tail(&rphy->list, &sas_host->rphy_list);
@@ -1329,6 +1450,8 @@ void sas_rphy_free(struct sas_rphy *rphy)
list_del(&rphy->list);
mutex_unlock(&sas_host->lock);
+ sas_bsg_remove(shost, rphy);
+
transport_destroy_device(dev);
put_device(dev);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 6f56f8750635..4df21c92ff1e 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -787,10 +787,12 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
struct scsi_target *starget = sdev->sdev_target;
struct Scsi_Host *shost = sdev->host;
int len = sdev->inquiry_len;
+ int min_period = spi_min_period(starget);
+ int max_width = spi_max_width(starget);
/* first set us up for narrow async */
DV_SET(offset, 0);
DV_SET(width, 0);
-
+
if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
!= SPI_COMPARE_SUCCESS) {
starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n");
@@ -798,9 +800,13 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
return;
}
+ if (!scsi_device_wide(sdev)) {
+ spi_max_width(starget) = 0;
+ max_width = 0;
+ }
+
/* test width */
- if (i->f->set_width && spi_max_width(starget) &&
- scsi_device_wide(sdev)) {
+ if (i->f->set_width && max_width) {
i->f->set_width(starget, 1);
if (spi_dv_device_compare_inquiry(sdev, buffer,
@@ -809,6 +815,11 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
!= SPI_COMPARE_SUCCESS) {
starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n");
i->f->set_width(starget, 0);
+ /* Make sure we don't force wide back on by asking
+ * for a transfer period that requires it */
+ max_width = 0;
+ if (min_period < 10)
+ min_period = 10;
}
}
@@ -828,7 +839,8 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
/* now set up to the maximum */
DV_SET(offset, spi_max_offset(starget));
- DV_SET(period, spi_min_period(starget));
+ DV_SET(period, min_period);
+
/* try QAS requests; this should be harmless to set if the
* target supports it */
if (scsi_device_qas(sdev)) {
@@ -837,14 +849,14 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
DV_SET(qas, 0);
}
- if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+ if (scsi_device_ius(sdev) && min_period < 9) {
/* This u320 (or u640). Set IU transfers */
DV_SET(iu, 1);
/* Then set the optional parameters */
DV_SET(rd_strm, 1);
DV_SET(wr_flow, 1);
DV_SET(rti, 1);
- if (spi_min_period(starget) == 8)
+ if (min_period == 8)
DV_SET(pcomp_en, 1);
} else {
DV_SET(iu, 0);
@@ -862,6 +874,10 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
} else {
DV_SET(dt, 1);
}
+ /* set width last because it will pull all the other
+ * parameters down to required values */
+ DV_SET(width, max_width);
+
/* Do the read only INQUIRY tests */
spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
spi_dv_device_compare_inquiry);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 424d557284a9..2c6116fd4578 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -241,7 +241,6 @@ static struct scsi_driver sd_template = {
},
.rescan = sd_rescan,
.init_command = sd_init_command,
- .issue_flush = sd_issue_flush,
};
/*
@@ -800,10 +799,17 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
return 0;
}
-static int sd_issue_flush(struct device *dev, sector_t *error_sector)
+static int sd_issue_flush(struct request_queue *q, struct gendisk *disk,
+ sector_t *error_sector)
{
int ret = 0;
- struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+ struct scsi_device *sdp = q->queuedata;
+ struct scsi_disk *sdkp;
+
+ if (sdp->sdev_state != SDEV_RUNNING)
+ return -ENXIO;
+
+ sdkp = scsi_disk_get_from_dev(&sdp->sdev_gendev);
if (!sdkp)
return -ENODEV;
@@ -814,7 +820,7 @@ static int sd_issue_flush(struct device *dev, sector_t *error_sector)
return ret;
}
-static void sd_prepare_flush(request_queue_t *q, struct request *rq)
+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;
@@ -1285,7 +1291,7 @@ got_data:
*/
int hard_sector = sector_size;
sector_t sz = (sdkp->capacity/2) * (hard_sector/256);
- request_queue_t *queue = sdp->request_queue;
+ struct request_queue *queue = sdp->request_queue;
sector_t mb = sz;
blk_queue_hardsect_size(queue, hard_sector);
@@ -1663,6 +1669,8 @@ static int sd_probe(struct device *dev)
sd_revalidate_disk(gd);
+ blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
+
gd->driverfs_dev = &sdp->sdev_gendev;
gd->flags = GENHD_FL_DRIVERFS;
if (sdp->removable)
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index ff62e9708e1c..ce80fa9ad815 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -420,7 +420,7 @@ static inline void borken_wait (void)
#define ULOOP( i ) for (clock = i*8;;)
#define TIMEOUT (!(clock--))
-int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
+static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
{
struct Scsi_Host *instance;
int i, j;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 018c65f73ac4..d63d229e2323 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -100,7 +100,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
{
struct Scsi_Host * host = NULL;
struct NCR_700_Host_Parameters *hostdata =
- kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
printk(KERN_NOTICE "sim710: %s\n", dev->bus_id);
printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
@@ -110,7 +110,6 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
printk(KERN_ERR "sim710: Failed to allocate host data\n");
goto out;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
if(request_region(base_addr, 64, "sim710") == NULL) {
printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
@@ -139,6 +138,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
goto out_put_host;
}
+ dev_set_drvdata(dev, host);
scsi_scan_host(host);
return 0;
@@ -156,7 +156,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
static __devexit int
sim710_device_remove(struct device *dev)
{
- struct Scsi_Host *host = dev_to_shost(dev);
+ struct Scsi_Host *host = dev_get_drvdata(dev);
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)host->hostdata[0];
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 5143c8990845..902eb11ffe8a 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -175,7 +175,7 @@ static void scsi_cd_put(struct scsi_cd *cd)
* an inode for that to work, and we do not always have one.
*/
-int sr_media_change(struct cdrom_device_info *cdi, int slot)
+static int sr_media_change(struct cdrom_device_info *cdi, int slot)
{
struct scsi_cd *cd = cdi->handle;
int retval;
@@ -624,7 +624,7 @@ static void get_sectorsize(struct scsi_cd *cd)
unsigned char *buffer;
int the_result, retries = 3;
int sector_size;
- request_queue_t *queue;
+ struct request_queue *queue;
buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a4f7b8465773..73c44cbdea47 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -1485,7 +1485,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
struct st_buffer *STbp;
char *name = tape_name(STp);
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
retval = rw_checks(STp, filp, count);
@@ -1736,7 +1736,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
if (SRpnt != NULL)
st_release_request(SRpnt);
release_buffering(STp, 0);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -1942,7 +1942,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
struct st_buffer *STbp = STp->buffer;
DEB( char *name = tape_name(STp); )
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
retval = rw_checks(STp, filp, count);
@@ -2069,7 +2069,7 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
release_buffering(STp, 1);
STbp->buffer_bytes = 0;
}
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -3226,7 +3226,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
char *name = tape_name(STp);
void __user *p = (void __user *)arg;
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
DEB(
@@ -3537,7 +3537,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
retval = (-EFAULT);
goto out;
}
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
switch (cmd_in) {
case SCSI_IOCTL_GET_IDLUN:
case SCSI_IOCTL_GET_BUS_NUMBER:
@@ -3563,7 +3563,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
return retval;
out:
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -4029,7 +4029,7 @@ static int st_probe(struct device *dev)
tpnt->density_changed = tpnt->compression_changed =
tpnt->blksize_changed = 0;
- init_MUTEX(&tpnt->lock);
+ mutex_init(&tpnt->lock);
st_nr_dev++;
write_unlock(&st_dev_arr_lock);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 50f3deb1f9ed..6c8075712974 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -3,6 +3,7 @@
#define _ST_H
#include <linux/completion.h>
+#include <linux/mutex.h>
#include <linux/kref.h>
#include <scsi/scsi_cmnd.h>
@@ -98,7 +99,7 @@ struct st_partstat {
struct scsi_tape {
struct scsi_driver *driver;
struct scsi_device *device;
- struct semaphore lock; /* For serialization */
+ struct mutex lock; /* For serialization */
struct completion wait; /* For SCSI commands */
struct st_buffer *buffer;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 15a51459c81f..3db22325ea2c 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -2033,7 +2033,7 @@ static struct pci_device_id sym2_id_table[] __devinitdata = {
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL }, /* new */
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A,
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 14cba1ca38b3..5db1520f8ba9 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2082,10 +2082,9 @@ static int dc390_slave_alloc(struct scsi_device *scsi_device)
uint id = scsi_device->id;
uint lun = scsi_device->lun;
- pDCB = kmalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
+ pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
if (!pDCB)
return -ENOMEM;
- memset(pDCB, 0, sizeof(struct dc390_dcb));
if (!pACB->DCBCnt++) {
pACB->pLinkDCB = pDCB;
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index fa4e08e508ad..b92ff047af38 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -89,6 +89,8 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <asm/irq.h>
+
#include "wd33c93.h"
#define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns
@@ -1762,7 +1764,7 @@ static char setup_buffer[SETUP_BUFFER_SIZE];
static char setup_used[MAX_SETUP_ARGS];
static int done_setup = 0;
-int
+static int
wd33c93_setup(char *str)
{
int i;
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index 50703877a585..c822debc2668 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -130,6 +130,7 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z,
goto out_put_host;
}
+ zorro_set_drvdata(z, host);
scsi_scan_host(host);
return 0;
@@ -148,7 +149,7 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z,
static __devexit void zorro7xx_remove_one(struct zorro_dev *z)
{
- struct Scsi_Host *host = dev_to_shost(&z->dev);
+ struct Scsi_Host *host = zorro_get_drvdata(z);
struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
scsi_remove_host(host);
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index cad426c9711e..aad4012bbb30 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -33,7 +33,6 @@
#include <linux/keyboard.h>
#include <linux/init.h>
#include <linux/pm.h>
-#include <linux/pm_legacy.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -401,9 +400,9 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void do_softint(void *private)
+static void do_softint(struct work_struct *work)
{
- struct m68k_serial *info = (struct m68k_serial *) private;
+ struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue);
struct tty_struct *tty;
tty = info->tty;
@@ -425,9 +424,9 @@ static void do_softint(void *private)
* do_serial_hangup() -> tty->hangup() -> rs_hangup()
*
*/
-static void do_serial_hangup(void *private)
+static void do_serial_hangup(struct work_struct *work)
{
- struct m68k_serial *info = (struct m68k_serial *) private;
+ struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup);
struct tty_struct *tty;
tty = info->tty;
@@ -1324,59 +1323,6 @@ static void show_serial_version(void)
printk("MC68328 serial driver version 1.00\n");
}
-#ifdef CONFIG_PM_LEGACY
-/* Serial Power management
- * The console (currently fixed at line 0) is a special case for power
- * management because the kernel is so chatty. The console will be
- * explicitly disabled my our power manager as the last minute, so we won't
- * mess with it here.
- */
-static struct pm_dev *serial_pm[NR_PORTS];
-
-static int serial_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
-{
- struct m68k_serial *info = (struct m68k_serial *)dev->data;
-
- if(info == NULL)
- return -1;
-
- /* special case for line 0 - pm restores it */
- if(info->line == 0)
- return 0;
-
- switch (request) {
- case PM_SUSPEND:
- shutdown(info);
- break;
-
- case PM_RESUME:
- startup(info);
- break;
- }
- return 0;
-}
-
-void shutdown_console(void)
-{
- struct m68k_serial *info = &m68k_soft[0];
-
- /* HACK: wait a bit for any pending printk's to be dumped */
- {
- int i = 10000;
- while(i--);
- }
-
- shutdown(info);
-}
-
-void startup_console(void)
-{
- struct m68k_serial *info = &m68k_soft[0];
- startup(info);
-}
-#endif /* CONFIG_PM_LEGACY */
-
-
static const struct tty_operations rs_ops = {
.open = rs_open,
.close = rs_close,
@@ -1444,8 +1390,8 @@ rs68328_init(void)
info->event = 0;
info->count = 0;
info->blocked_open = 0;
- INIT_WORK(&info->tqueue, do_softint, info);
- INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+ INIT_WORK(&info->tqueue, do_softint);
+ INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->line = i;
@@ -1467,11 +1413,6 @@ rs68328_init(void)
IRQ_FLG_STD,
"M68328_UART", NULL))
panic("Unable to attach 68328 serial interrupt\n");
-#ifdef CONFIG_PM_LEGACY
- serial_pm[i] = pm_register(PM_SYS_DEV, PM_SYS_COM, serial_pm_callback);
- if (serial_pm[i])
- serial_pm[i]->data = info;
-#endif
}
local_irq_restore(flags);
return 0;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 0b3ec38ae614..f94109cbb46e 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -129,7 +129,16 @@ struct uart_8250_port {
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
- unsigned char lsr_break_flag;
+
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+ unsigned char lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+ unsigned char msr_saved_flags;
/*
* We provide a per-port pm hook.
@@ -1238,6 +1247,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr, iir;
lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
iir = serial_in(up, UART_IIR) & 0x0f;
if ((up->port.type == PORT_RM9000) ?
(lsr & UART_LSR_THRE &&
@@ -1290,18 +1300,10 @@ receive_chars(struct uart_8250_port *up, unsigned int *status)
flag = TTY_NORMAL;
up->port.icount.rx++;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
- /*
- * Recover the break flag from console xmit
- */
- if (up->port.line == up->port.cons->index) {
- lsr |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-#endif
+ lsr |= up->lsr_saved_flags;
+ up->lsr_saved_flags = 0;
- if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
/*
* For statistics only
*/
@@ -1392,6 +1394,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
{
unsigned int status = serial_in(up, UART_MSR);
+ status |= up->msr_saved_flags;
+ up->msr_saved_flags = 0;
if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
up->port.info != NULL) {
if (status & UART_MSR_TERI)
@@ -1591,7 +1595,8 @@ static void serial8250_timeout(unsigned long data)
static void serial8250_backup_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
- unsigned int iir, ier = 0;
+ unsigned int iir, ier = 0, lsr;
+ unsigned long flags;
/*
* Must disable interrupts or else we risk racing with the interrupt
@@ -1610,9 +1615,13 @@ static void serial8250_backup_timeout(unsigned long data)
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
+ spin_lock_irqsave(&up->port.lock, flags);
+ lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+ spin_unlock_irqrestore(&up->port.lock, flags);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
- (serial_in(up, UART_LSR) & UART_LSR_THRE)) {
+ (lsr & UART_LSR_THRE)) {
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
iir |= UART_IIR_THRI;
}
@@ -1631,13 +1640,14 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
- unsigned int ret;
+ unsigned int lsr;
spin_lock_irqsave(&up->port.lock, flags);
- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&up->port.lock, flags);
- return ret;
+ return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
}
static unsigned int serial8250_get_mctrl(struct uart_port *port)
@@ -1708,8 +1718,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
do {
status = serial_in(up, UART_LSR);
- if (status & UART_LSR_BI)
- up->lsr_break_flag = UART_LSR_BI;
+ up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
if (--tmout == 0)
break;
@@ -1718,8 +1727,12 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
- while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
+ unsigned int tmout;
+ for (tmout = 1000000; tmout; tmout--) {
+ unsigned int msr = serial_in(up, UART_MSR);
+ up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+ if (msr & UART_MSR_CTS)
+ break;
udelay(1);
touch_nmi_watchdog();
}
@@ -1889,6 +1902,18 @@ static int serial8250_startup(struct uart_port *port)
spin_unlock_irqrestore(&up->port.lock, flags);
/*
+ * Clear the interrupt registers again for luck, and clear the
+ * saved flags to avoid getting false values from polling
+ * routines or the previous session.
+ */
+ serial_inp(up, UART_LSR);
+ serial_inp(up, UART_RX);
+ serial_inp(up, UART_IIR);
+ serial_inp(up, UART_MSR);
+ up->lsr_saved_flags = 0;
+ up->msr_saved_flags = 0;
+
+ /*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
* anyway, so we don't enable them here.
@@ -1906,14 +1931,6 @@ static int serial8250_startup(struct uart_port *port)
(void) inb_p(icp);
}
- /*
- * And clear the interrupt registers again for luck.
- */
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
-
return 0;
}
@@ -2484,6 +2501,16 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(up, BOTH_EMPTY);
serial_out(up, UART_IER, ier);
+ /*
+ * The receive handling will happen properly because the
+ * receive ready bit will still be set; it is not cleared
+ * on read. However, modem control will not, we must
+ * call it if we have saved something in the saved flags
+ * while processing with interrupts off.
+ */
+ if (up->msr_saved_flags)
+ check_modem_status(up);
+
if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
@@ -2514,7 +2541,7 @@ static int __init serial8250_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-static int __init serial8250_console_early_setup(void)
+static int serial8250_console_early_setup(void)
{
return serial8250_find_port_for_earlycon();
}
@@ -2650,8 +2677,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
ret = serial8250_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%lx MEM%lx IRQ%d): %d\n", i,
- p->iobase, p->mapbase, p->irq, ret);
+ "(IO%lx MEM%llx IRQ%d): %d\n", i,
+ p->iobase, (unsigned long long)p->mapbase,
+ p->irq, ret);
}
}
return 0;
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 947c20507e1f..4d4c9f01be8d 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -151,8 +151,9 @@ static int __init parse_options(struct early_serial8250_device *device, char *op
#else
port->membase = ioremap(port->mapbase, 64);
if (!port->membase) {
- printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
- __FUNCTION__, port->mapbase);
+ printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
+ __FUNCTION__,
+ (unsigned long long)port->mapbase);
return -ENOMEM;
}
#endif
@@ -175,9 +176,10 @@ static int __init parse_options(struct early_serial8250_device *device, char *op
device->baud);
}
- printk(KERN_INFO "Early serial console at %s 0x%lx (options '%s')\n",
+ printk(KERN_INFO "Early serial console at %s 0x%llx (options '%s')\n",
mmio ? "MMIO" : "I/O port",
- mmio ? port->mapbase : (unsigned long) port->iobase,
+ mmio ? (unsigned long long) port->mapbase
+ : (unsigned long long) port->iobase,
device->options);
return 0;
}
@@ -225,7 +227,7 @@ int __init setup_early_serial8250_console(char *cmdline)
return 0;
}
-int __init serial8250_find_port_for_earlycon(void)
+int serial8250_find_port_for_earlycon(void)
{
struct early_serial8250_device *device = &early_device;
struct uart_port *port = &device->port;
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
index 53e81a44c1a3..2cf0953fe0ec 100644
--- a/drivers/serial/8250_hp300.c
+++ b/drivers/serial/8250_hp300.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/delay.h>
#include <linux/dio.h>
#include <linux/console.h>
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 6d7d616e9ccd..1ea1ed82c352 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -580,6 +580,138 @@ static int pci_netmos_init(struct pci_dev *dev)
return num_serial;
}
+/*
+ * ITE support by Niels de Vos <niels.devos@wincor-nixdorf.com>
+ *
+ * These chips are available with optionally one parallel port and up to
+ * two serial ports. Unfortunately they all have the same product id.
+ *
+ * Basic configuration is done over a region of 32 I/O ports. The base
+ * ioport is called INTA or INTC, depending on docs/other drivers.
+ *
+ * The region of the 32 I/O ports is configured in POSIO0R...
+ */
+
+/* registers */
+#define ITE_887x_MISCR 0x9c
+#define ITE_887x_INTCBAR 0x78
+#define ITE_887x_UARTBAR 0x7c
+#define ITE_887x_PS0BAR 0x10
+#define ITE_887x_POSIO0 0x60
+
+/* I/O space size */
+#define ITE_887x_IOSIZE 32
+/* I/O space size (bits 26-24; 8 bytes = 011b) */
+#define ITE_887x_POSIO_IOSIZE_8 (3 << 24)
+/* I/O space size (bits 26-24; 32 bytes = 101b) */
+#define ITE_887x_POSIO_IOSIZE_32 (5 << 24)
+/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
+#define ITE_887x_POSIO_SPEED (3 << 29)
+/* enable IO_Space bit */
+#define ITE_887x_POSIO_ENABLE (1 << 31)
+
+static int pci_ite887x_init(struct pci_dev *dev)
+{
+ /* inta_addr are the configuration addresses of the ITE */
+ static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
+ 0x200, 0x280, 0 };
+ int ret, i, type;
+ struct resource *iobase = NULL;
+ u32 miscr, uartbar, ioport;
+
+ /* search for the base-ioport */
+ i = 0;
+ while (inta_addr[i] && iobase == NULL) {
+ iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
+ "ite887x");
+ if (iobase != NULL) {
+ /* write POSIO0R - speed | size | ioport */
+ pci_write_config_dword(dev, ITE_887x_POSIO0,
+ ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+ ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
+ /* write INTCBAR - ioport */
+ pci_write_config_dword(dev, ITE_887x_INTCBAR, inta_addr[i]);
+ ret = inb(inta_addr[i]);
+ if (ret != 0xff) {
+ /* ioport connected */
+ break;
+ }
+ release_region(iobase->start, ITE_887x_IOSIZE);
+ iobase = NULL;
+ }
+ i++;
+ }
+
+ if (!inta_addr[i]) {
+ printk(KERN_ERR "ite887x: could not find iobase\n");
+ return -ENODEV;
+ }
+
+ /* start of undocumented type checking (see parport_pc.c) */
+ type = inb(iobase->start + 0x18) & 0x0f;
+
+ switch (type) {
+ case 0x2: /* ITE8871 (1P) */
+ case 0xa: /* ITE8875 (1P) */
+ ret = 0;
+ break;
+ case 0xe: /* ITE8872 (2S1P) */
+ ret = 2;
+ break;
+ case 0x6: /* ITE8873 (1S) */
+ ret = 1;
+ break;
+ case 0x8: /* ITE8874 (2S) */
+ ret = 2;
+ break;
+ default:
+ moan_device("Unknown ITE887x", dev);
+ ret = -ENODEV;
+ }
+
+ /* configure all serial ports */
+ for (i = 0; i < ret; i++) {
+ /* read the I/O port from the device */
+ pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
+ &ioport);
+ ioport &= 0x0000FF00; /* the actual base address */
+ pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
+ ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+ ITE_887x_POSIO_IOSIZE_8 | ioport);
+
+ /* write the ioport to the UARTBAR */
+ pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
+ uartbar &= ~(0xffff << (16 * i)); /* clear half the reg */
+ uartbar |= (ioport << (16 * i)); /* set the ioport */
+ pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
+
+ /* get current config */
+ pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
+ /* disable interrupts (UARTx_Routing[3:0]) */
+ miscr &= ~(0xf << (12 - 4 * i));
+ /* activate the UART (UARTx_En) */
+ miscr |= 1 << (23 - i);
+ /* write new config with activated UART */
+ pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
+ }
+
+ if (ret <= 0) {
+ /* the device has no UARTs if we get here */
+ release_region(iobase->start, ITE_887x_IOSIZE);
+ }
+
+ return ret;
+}
+
+static void __devexit pci_ite887x_exit(struct pci_dev *dev)
+{
+ u32 ioport;
+ /* the ioport is bit 0-15 in POSIO0R */
+ pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
+ ioport &= 0xffff;
+ release_region(ioport, ITE_887x_IOSIZE);
+}
+
static int
pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
struct uart_port *port, int idx)
@@ -653,6 +785,18 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.setup = pci_default_setup,
},
/*
+ * ITE
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ITE,
+ .device = PCI_DEVICE_ID_ITE_8872,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ite887x_init,
+ .setup = pci_default_setup,
+ .exit = __devexit_p(pci_ite887x_exit),
+ },
+ /*
* Panacom
*/
{
@@ -933,6 +1077,7 @@ enum pci_board_num_t {
pbn_b1_2_1250000,
+ pbn_b1_bt_1_115200,
pbn_b1_bt_2_921600,
pbn_b1_1_1382400,
@@ -976,7 +1121,6 @@ enum pci_board_num_t {
pbn_oxsemi,
pbn_intel_i960,
pbn_sgi_ioc3,
- pbn_nec_nile4,
pbn_computone_4,
pbn_computone_6,
pbn_computone_8,
@@ -984,6 +1128,7 @@ enum pci_board_num_t {
pbn_exar_XR17C152,
pbn_exar_XR17C154,
pbn_exar_XR17C158,
+ pbn_pasemi_1682M,
};
/*
@@ -1212,6 +1357,13 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.uart_offset = 8,
},
+ [pbn_b1_bt_1_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
[pbn_b1_bt_2_921600] = {
.flags = FL_BASE1|FL_BASE_BARS,
.num_ports = 2,
@@ -1443,18 +1595,6 @@ static struct pciserial_board pci_boards[] __devinitdata = {
},
/*
- * NEC Vrc-5074 (Nile 4) builtin UART.
- */
- [pbn_nec_nile4] = {
- .flags = FL_BASE0,
- .num_ports = 1,
- .base_baud = 520833,
- .uart_offset = 8 << 3,
- .reg_shift = 3,
- .first_offset = 0x300,
- },
-
- /*
* Computone - uses IOMEM.
*/
[pbn_computone_4] = {
@@ -1511,6 +1651,18 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 921600,
.uart_offset = 0x200,
},
+ /*
+ * PA Semi PWRficient PA6T-1682M on-chip UART
+ */
+ [pbn_pasemi_1682M] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 8333333,
+ },
+};
+
+static const struct pci_device_id softmodem_blacklist[] = {
+ { PCI_VDEVICE ( AL, 0x5457 ), }, /* ALi Corporation M5457 AC'97 Modem */
};
/*
@@ -1521,6 +1673,7 @@ static struct pciserial_board pci_boards[] __devinitdata = {
static int __devinit
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{
+ const struct pci_device_id *blacklist;
int num_iomem, num_port, first_port = -1, i;
/*
@@ -1535,6 +1688,18 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
(dev->class & 0xff) > 6)
return -ENODEV;
+ /*
+ * Do not access blacklisted devices that are known not to
+ * feature serial ports.
+ */
+ for (blacklist = softmodem_blacklist;
+ blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
+ blacklist++) {
+ if (dev->vendor == blacklist->vendor &&
+ dev->device == blacklist->device)
+ return -ENODEV;
+ }
+
num_iomem = num_port = 0;
for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
@@ -2345,13 +2510,6 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_1_115200 },
- /*
- * NEC Vrc-5074 (Nile 4) builtin UART.
- */
- { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_nec_nile4 },
-
{ PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b3_2_115200 },
@@ -2384,6 +2542,13 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_115200 },
+ /*
+ * ITE
+ */
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b1_bt_1_115200 },
/*
* IntaShield IS-200
@@ -2402,6 +2567,13 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
0, 0, pbn_b2_8_921600 },
/*
+ * PA Semi PA6T-1682M on-chip UART
+ */
+ { PCI_VENDOR_ID_PASEMI, 0xa004,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pasemi_1682M },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 7fa413ddccf5..d6ae38e55d01 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -88,21 +88,17 @@ config SERIAL_8250_PCI
depends on SERIAL_8250 && PCI
default SERIAL_8250
help
- Say Y here if you have PCI serial ports.
-
- To compile this driver as a module, choose M here: the module
- will be called 8250_pci.
+ This builds standard PCI serial support. You may be able to
+ disable this feature if you only need legacy serial support.
+ Saves about 9K.
config SERIAL_8250_PNP
tristate "8250/16550 PNP device support" if EMBEDDED
depends on SERIAL_8250 && PNP
default SERIAL_8250
help
- Say Y here if you have serial ports described by PNPBIOS or ACPI.
- These are typically ports built into the system board.
-
- To compile this driver as a module, choose M here: the module
- will be called 8250_pnp.
+ This builds standard PNP serial support. You may be able to
+ disable this feature if you only need legacy serial support.
config SERIAL_8250_HP300
tristate
@@ -486,6 +482,36 @@ config SERIAL_DZ_CONSOLE
If unsure, say Y.
+config SERIAL_ZS
+ tristate "DECstation Z85C30 serial support"
+ depends on MACH_DECSTATION
+ select SERIAL_CORE
+ default y
+ ---help---
+ Support for the Zilog 85C350 serial communications controller used
+ for serial ports in newer DECstation systems. These include the
+ DECsystem 5900 and all models of the DECstation and DECsystem 5000
+ systems except from model 200.
+
+ If unsure, say Y. To compile this driver as a module, choose M here:
+ the module will be called zs.
+
+config SERIAL_ZS_CONSOLE
+ bool "Support for console on a DECstation Z85C30 serial port"
+ depends on SERIAL_ZS=y
+ select SERIAL_CORE_CONSOLE
+ default y
+ ---help---
+ If you say Y here, it will be possible to use a serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ Note that the firmware uses ttyS1 as the serial console on the
+ Maxine and ttyS3 on the others using this driver.
+
+ If unsure, say Y.
+
config SERIAL_21285
tristate "DC21285 serial port support"
depends on ARM && FOOTBRIDGE
@@ -585,7 +611,7 @@ config SERIAL_BFIN
config SERIAL_BFIN_CONSOLE
bool "Console on Blackfin serial port"
- depends on SERIAL_BFIN
+ depends on SERIAL_BFIN=y
select SERIAL_CORE_CONSOLE
choice
@@ -806,10 +832,10 @@ config SERIAL_MUX
4. Change the kernel command console parameter to: console=ttyB0
config SERIAL_MUX_CONSOLE
- bool "Support for console on serial MUX"
- depends on SERIAL_MUX
+ bool "Support for console on serial MUX"
+ depends on SERIAL_MUX=y
select SERIAL_CORE_CONSOLE
- default y
+ default y
config PDC_CONSOLE
bool "PDC software console support"
@@ -960,6 +986,31 @@ config SERIAL_PMACZILOG
PowerMac machines.
Say Y or M if you want to be able to these serial ports.
+config SERIAL_PMACZILOG_TTYS
+ bool "Use ttySn device nodes for Zilog z85c30"
+ depends on SERIAL_PMACZILOG
+ help
+ The pmac_zilog driver for the z85C30 chip on many powermacs
+ historically used the device numbers for /dev/ttySn. The
+ 8250 serial port driver also uses these numbers, which means
+ the two drivers being unable to coexist; you could not use
+ both z85C30 and 8250 type ports at the same time.
+
+ If this option is not selected, the pmac_zilog driver will
+ use the device numbers allocated for /dev/ttyPZn. This allows
+ the pmac_zilog and 8250 drivers to co-exist, but may cause
+ existing userspace setups to break. Programs that need to
+ access the built-in serial ports on powermacs will need to
+ be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
+
+ If you enable this option, any z85c30 ports in the system will
+ be registered as ttyS0 onwards as in the past, and you will be
+ unable to use the 8250 module for PCMCIA or other 16C550-style
+ UARTs.
+
+ Say N unless you need the z85c30 ports on your powermac
+ to appear as /dev/ttySn.
+
config SERIAL_PMACZILOG_CONSOLE
bool "Console on PowerMac z85c30 serial port"
depends on SERIAL_PMACZILOG=y
@@ -1165,7 +1216,7 @@ config SERIAL_VR41XX
config SERIAL_VR41XX_CONSOLE
bool "Enable NEC VR4100 series Serial Interface Unit console"
- depends on SERIAL_VR41XX
+ depends on SERIAL_VR41XX=y
select SERIAL_CORE_CONSOLE
help
If you have a NEC VR4100 series processor and you want to use
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index c48cdd61b736..af6377d480d7 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_V850E_UART) += v850e_uart.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 954073c6ce3a..72229df9dc11 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -716,7 +716,7 @@ static int pl011_probe(struct amba_device *dev, void *id)
goto out;
}
- uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+ uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
if (uap == NULL) {
ret = -ENOMEM;
goto out;
@@ -728,7 +728,6 @@ static int pl011_probe(struct amba_device *dev, void *id)
goto free;
}
- memset(uap, 0, sizeof(struct uart_amba_port));
uap->clk = clk_get(&dev->dev, "UARTCLK");
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 66c92bc36f3d..6f475b609864 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -86,10 +86,8 @@ static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_BF54x
while (!(UART_GET_LSR(uart) & TEMT))
continue;
-#endif
#ifdef CONFIG_SERIAL_BFIN_DMA
disable_dma(uart->tx_dma_channel);
@@ -128,8 +126,8 @@ static void bfin_serial_start_tx(struct uart_port *port)
ier = UART_GET_IER(uart);
ier |= ETBEI;
UART_PUT_IER(uart, ier);
- bfin_serial_tx_chars(uart);
#endif
+ bfin_serial_tx_chars(uart);
#endif
}
@@ -139,18 +137,21 @@ 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) {
+#endif
#ifdef CONFIG_BF54x
UART_CLEAR_IER(uart, ERBFI);
#else
unsigned short ier;
ier = UART_GET_IER(uart);
-#ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
ier &= ~ERBFI;
UART_PUT_IER(uart, ier);
#endif
+#ifdef CONFIG_KGDB_UART
+ }
+#endif
}
/*
@@ -173,12 +174,15 @@ void kgdb_put_debug_char(int chr)
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
while (!(UART_GET_LSR(uart) & THRE)) {
- __builtin_bfin_ssync();
+ SSYNC();
}
+
+#ifndef CONFIG_BF54x
UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
- __builtin_bfin_ssync();
+ SSYNC();
+#endif
UART_PUT_CHAR(uart, (unsigned char)chr);
- __builtin_bfin_ssync();
+ SSYNC();
}
int kgdb_get_debug_char(void)
@@ -192,12 +196,14 @@ int kgdb_get_debug_char(void)
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
while(!(UART_GET_LSR(uart) & DR)) {
- __builtin_bfin_ssync();
+ SSYNC();
}
+#ifndef CONFIG_BF54x
UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
- __builtin_bfin_ssync();
+ SSYNC();
+#endif
chr = UART_GET_CHAR(uart);
- __builtin_bfin_ssync();
+ SSYNC();
return chr;
}
@@ -225,12 +231,10 @@ 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 int in_break = 0;
#ifdef CONFIG_KGDB_UART
struct pt_regs *regs = get_irq_regs();
#endif
-#ifdef BF533_FAMILY
- static int in_break = 0;
-#endif
status = UART_GET_LSR(uart);
ch = UART_GET_CHAR(uart);
@@ -256,29 +260,30 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
}
}
#endif
-
-#ifdef BF533_FAMILY
- /* The BF533 family of processors have a nice misbehavior where
- * they continuously generate characters for a "single" break.
- * We have to basically ignore this flood until the "next" valid
- * character comes across. All other Blackfin families operate
- * properly though.
- */
- if (in_break) {
- if (ch != 0) {
- in_break = 0;
- ch = UART_GET_CHAR(uart);
- if (bfin_revid() < 5)
+
+ if (ANOMALY_05000230) {
+ /* The BF533 family of processors have a nice misbehavior where
+ * they continuously generate characters for a "single" break.
+ * We have to basically ignore this flood until the "next" valid
+ * character comes across. All other Blackfin families operate
+ * properly though.
+ * Note: While Anomaly 05000230 does not directly address this,
+ * the changes that went in for it also fixed this issue.
+ */
+ if (in_break) {
+ if (ch != 0) {
+ in_break = 0;
+ ch = UART_GET_CHAR(uart);
+ if (bfin_revid() < 5)
+ return;
+ } else
return;
- } else
- return;
+ }
}
-#endif
if (status & BI) {
-#ifdef BF533_FAMILY
- in_break = 1;
-#endif
+ if (ANOMALY_05000230)
+ in_break = 1;
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
@@ -697,17 +702,19 @@ static int bfin_serial_startup(struct uart_port *port)
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
#else
+ if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
+ "BFIN_UART_RX", uart)) {
# ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq
-# else
- if (request_irq
+ if (uart->port.line != CONFIG_KGDB_UART_PORT) {
# endif
- (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
- "BFIN_UART_RX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
return -EBUSY;
+# ifdef CONFIG_KGDB_UART
+ }
+# endif
}
+
if (request_irq
(uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
"BFIN_UART_TX", uart)) {
@@ -962,30 +969,6 @@ static void __init bfin_serial_init_ports(void)
}
#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
- struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- while (!(UART_GET_LSR(uart) & THRE))
- barrier();
- UART_PUT_CHAR(uart, ch);
- SSYNC();
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
- int flags = 0;
-
- spin_lock_irqsave(&uart->port.lock, flags);
- uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
- spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
@@ -1038,19 +1021,25 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
}
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+static struct uart_driver bfin_serial_reg;
static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
struct bfin_serial_port *uart;
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
int baud = 57600;
int bits = 8;
int parity = 'n';
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# ifdef CONFIG_SERIAL_BFIN_CTSRTS
int flow = 'r';
-#else
+# else
int flow = 'n';
-#endif
+# endif
+# endif
/*
* Check whether an invalid uart number has been specified, and
@@ -1061,15 +1050,45 @@ bfin_serial_console_setup(struct console *co, char *options)
co->index = 0;
uart = &bfin_serial_ports[co->index];
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
bfin_serial_console_get_options(uart, &baud, &parity, &bits);
return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+# else
+ return 0;
+# endif
+}
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+ defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ while (!(UART_GET_LSR(uart) & THRE))
+ barrier();
+ UART_PUT_CHAR(uart, ch);
+ SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+ int flags = 0;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
}
-static struct uart_driver bfin_serial_reg;
static struct console bfin_serial_console = {
.name = BFIN_SERIAL_NAME,
.write = bfin_serial_console_write,
@@ -1095,7 +1114,64 @@ console_initcall(bfin_serial_rs_console_init);
#define BFIN_SERIAL_CONSOLE &bfin_serial_console
#else
#define BFIN_SERIAL_CONSOLE NULL
-#endif
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void early_serial_putc(struct uart_port *port, int ch)
+{
+ unsigned timeout = 0xffff;
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
+ cpu_relax();
+ UART_PUT_CHAR(uart, ch);
+}
+
+static __init void early_serial_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
+ unsigned int i;
+
+ for (i = 0; i < n; i++, s++) {
+ if (*s == '\n')
+ early_serial_putc(&uart->port, '\r');
+ early_serial_putc(&uart->port, *s);
+ }
+}
+
+static struct __init console bfin_early_serial_console = {
+ .name = "early_BFuart",
+ .write = early_serial_write,
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .setup = bfin_serial_console_setup,
+ .index = -1,
+ .data = &bfin_serial_reg,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag)
+{
+ struct bfin_serial_port *uart;
+ struct ktermios t;
+
+ if (port == -1 || port >= nr_ports)
+ port = 0;
+ bfin_serial_init_ports();
+ bfin_early_serial_console.index = port;
+ uart = &bfin_serial_ports[port];
+ t.c_cflag = cflag;
+ t.c_iflag = 0;
+ t.c_oflag = 0;
+ t.c_lflag = ICANON;
+ t.c_line = port;
+ bfin_serial_set_termios(&uart->port, &t, &t);
+ return &bfin_early_serial_console;
+}
+
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
@@ -1182,7 +1258,7 @@ static int __init bfin_serial_init(void)
int ret;
#ifdef CONFIG_KGDB_UART
struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
- struct termios t;
+ struct ktermios t;
#endif
pr_info("Serial: Blackfin serial driver\n");
@@ -1199,11 +1275,15 @@ static int __init bfin_serial_init(void)
}
#ifdef CONFIG_KGDB_UART
if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
- request_irq(uart->port.irq, bfin_serial_int,
+ 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);
- __builtin_bfin_ssync();
+#endif
+ SSYNC();
t.c_cflag = CS8|B57600;
t.c_iflag = 0;
t.c_oflag = 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index a8f894c78194..32b9737759c4 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -56,21 +56,21 @@ struct uart_cpm_port {
u16 rx_fifosize;
u16 tx_nrfifos;
u16 tx_fifosize;
- smc_t *smcp;
- smc_uart_t *smcup;
- scc_t *sccp;
- scc_uart_t *sccup;
- volatile cbd_t *rx_bd_base;
- volatile cbd_t *rx_cur;
- volatile cbd_t *tx_bd_base;
- volatile cbd_t *tx_cur;
+ smc_t __iomem *smcp;
+ smc_uart_t __iomem *smcup;
+ scc_t __iomem *sccp;
+ scc_uart_t __iomem *sccup;
+ cbd_t __iomem *rx_bd_base;
+ cbd_t __iomem *rx_cur;
+ cbd_t __iomem *tx_bd_base;
+ cbd_t __iomem *tx_cur;
unsigned char *tx_buf;
unsigned char *rx_buf;
u32 flags;
void (*set_lineif)(struct uart_cpm_port *);
u8 brg;
uint dp_addr;
- void *mem_addr;
+ void *mem_addr;
dma_addr_t dma_addr;
u32 mem_size;
/* helpers */
@@ -80,14 +80,18 @@ struct uart_cpm_port {
int is_portb;
/* wait on close if needed */
int wait_closing;
+ /* value to combine with opcode to form cpm command */
+ u32 command;
};
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
extern int cpm_uart_port_map[UART_NR];
+#endif
extern int cpm_uart_nr;
extern struct uart_cpm_port cpm_uart_ports[UART_NR];
/* these are located in their respective files */
-void cpm_line_cr_cmd(int line, int cmd);
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
int cpm_uart_init_portdesc(void);
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
@@ -102,34 +106,36 @@ void scc4_lineif(struct uart_cpm_port *pinfo);
/*
virtual to phys transtalion
*/
-static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo)
+static inline unsigned long cpu2cpm_addr(void *addr,
+ struct uart_cpm_port *pinfo)
{
int offset;
u32 val = (u32)addr;
+ u32 mem = (u32)pinfo->mem_addr;
/* sane check */
- if (likely((val >= (u32)pinfo->mem_addr)) &&
- (val<((u32)pinfo->mem_addr + pinfo->mem_size))) {
- offset = val - (u32)pinfo->mem_addr;
- return pinfo->dma_addr+offset;
+ if (likely(val >= mem && val < mem + pinfo->mem_size)) {
+ offset = val - mem;
+ return pinfo->dma_addr + offset;
}
/* something nasty happened */
BUG();
return 0;
}
-static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo)
+static inline void *cpm2cpu_addr(unsigned long addr,
+ struct uart_cpm_port *pinfo)
{
int offset;
u32 val = addr;
+ u32 dma = (u32)pinfo->dma_addr;
/* sane check */
- if (likely((val >= pinfo->dma_addr) &&
- (val<(pinfo->dma_addr + pinfo->mem_size)))) {
- offset = val - (u32)pinfo->dma_addr;
- return (void*)(pinfo->mem_addr+offset);
+ if (likely(val >= dma && val < dma + pinfo->mem_size)) {
+ offset = val - dma;
+ return pinfo->mem_addr + offset;
}
/* something nasty happened */
BUG();
- return 0;
+ return NULL;
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index cefde58dbad2..b5e4478de0e3 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -10,7 +10,7 @@
* Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
- * Copyright (C) 2004 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
* (C) 2005-2006 MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
@@ -47,6 +47,11 @@
#include <asm/irq.h>
#include <asm/delay.h>
#include <asm/fs_pd.h>
+#include <asm/udbg.h>
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -57,12 +62,6 @@
#include "cpm_uart.h"
-/***********************************************************************/
-
-/* Track which ports are configured as uarts */
-int cpm_uart_port_map[UART_NR];
-/* How many ports did we config as uarts */
-int cpm_uart_nr = 0;
/**************************************************************/
@@ -73,6 +72,11 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+/* Track which ports are configured as uarts */
+int cpm_uart_port_map[UART_NR];
+/* How many ports did we config as uarts */
+int cpm_uart_nr;
/* Place-holder for board-specific stuff */
struct platform_device* __attribute__ ((weak)) __init
@@ -119,6 +123,7 @@ static int cpm_uart_id2nr(int id)
/* not found or invalid argument */
return -1;
}
+#endif
/*
* Check, if transmit buffers are processed
@@ -126,14 +131,14 @@ static int cpm_uart_id2nr(int id)
static unsigned int cpm_uart_tx_empty(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile cbd_t *bdp = pinfo->tx_bd_base;
+ cbd_t __iomem *bdp = pinfo->tx_bd_base;
int ret = 0;
while (1) {
- if (bdp->cbd_sc & BD_SC_READY)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
break;
- if (bdp->cbd_sc & BD_SC_WRAP) {
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
ret = TIOCSER_TEMT;
break;
}
@@ -162,15 +167,15 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
static void cpm_uart_stop_tx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:stop tx\n", port->line);
if (IS_SMC(pinfo))
- smcp->smc_smcm &= ~SMCM_TX;
+ clrbits8(&smcp->smc_smcm, SMCM_TX);
else
- sccp->scc_sccm &= ~UART_SCCM_TX;
+ clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
}
/*
@@ -179,24 +184,24 @@ static void cpm_uart_stop_tx(struct uart_port *port)
static void cpm_uart_start_tx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:start tx\n", port->line);
if (IS_SMC(pinfo)) {
- if (smcp->smc_smcm & SMCM_TX)
+ if (in_8(&smcp->smc_smcm) & SMCM_TX)
return;
} else {
- if (sccp->scc_sccm & UART_SCCM_TX)
+ if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
return;
}
if (cpm_uart_tx_pump(port) != 0) {
if (IS_SMC(pinfo)) {
- smcp->smc_smcm |= SMCM_TX;
+ setbits8(&smcp->smc_smcm, SMCM_TX);
} else {
- sccp->scc_sccm |= UART_SCCM_TX;
+ setbits16(&sccp->scc_sccm, UART_SCCM_TX);
}
}
}
@@ -207,15 +212,15 @@ static void cpm_uart_start_tx(struct uart_port *port)
static void cpm_uart_stop_rx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:stop rx\n", port->line);
if (IS_SMC(pinfo))
- smcp->smc_smcm &= ~SMCM_RX;
+ clrbits8(&smcp->smc_smcm, SMCM_RX);
else
- sccp->scc_sccm &= ~UART_SCCM_RX;
+ clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
}
/*
@@ -232,15 +237,14 @@ static void cpm_uart_enable_ms(struct uart_port *port)
static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- int line = pinfo - cpm_uart_ports;
pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
break_state);
if (break_state)
- cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
else
- cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
}
/*
@@ -259,10 +263,11 @@ static void cpm_uart_int_tx(struct uart_port *port)
static void cpm_uart_int_rx(struct uart_port *port)
{
int i;
- unsigned char ch, *cp;
+ unsigned char ch;
+ u8 *cp;
struct tty_struct *tty = port->info->tty;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile cbd_t *bdp;
+ cbd_t __iomem *bdp;
u16 status;
unsigned int flg;
@@ -274,13 +279,13 @@ static void cpm_uart_int_rx(struct uart_port *port)
bdp = pinfo->rx_cur;
for (;;) {
/* get status */
- status = bdp->cbd_sc;
+ status = in_be16(&bdp->cbd_sc);
/* If this one is empty, return happy */
if (status & BD_SC_EMPTY)
break;
/* get number of characters, and check spce in flip-buffer */
- i = bdp->cbd_datlen;
+ i = in_be16(&bdp->cbd_datlen);
/* If we have not enough room in tty flip buffer, then we try
* later, which will be the next rx-interrupt or a timeout
@@ -291,7 +296,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
}
/* get pointer */
- cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
/* loop through the buffer */
while (i-- > 0) {
@@ -311,10 +316,11 @@ static void cpm_uart_int_rx(struct uart_port *port)
} /* End while (i--) */
/* This BD is ready to be used again. Clear status. get next */
- bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
- bdp->cbd_sc |= BD_SC_EMPTY;
+ clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+ BD_SC_OV | BD_SC_ID);
+ setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = pinfo->rx_bd_base;
else
bdp++;
@@ -322,7 +328,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
} /* End for (;;) */
/* Write back buffer pointer */
- pinfo->rx_cur = (volatile cbd_t *) bdp;
+ pinfo->rx_cur = bdp;
/* activate BH processing */
tty_flip_buffer_push(tty);
@@ -376,14 +382,14 @@ static irqreturn_t cpm_uart_int(int irq, void *data)
u8 events;
struct uart_port *port = (struct uart_port *)data;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:IRQ\n", port->line);
if (IS_SMC(pinfo)) {
- events = smcp->smc_smce;
- smcp->smc_smce = events;
+ events = in_8(&smcp->smc_smce);
+ out_8(&smcp->smc_smce, events);
if (events & SMCM_BRKE)
uart_handle_break(port);
if (events & SMCM_RX)
@@ -391,8 +397,8 @@ static irqreturn_t cpm_uart_int(int irq, void *data)
if (events & SMCM_TX)
cpm_uart_int_tx(port);
} else {
- events = sccp->scc_scce;
- sccp->scc_scce = events;
+ events = in_be16(&sccp->scc_scce);
+ out_be16(&sccp->scc_scce, events);
if (events & UART_SCCM_BRKE)
uart_handle_break(port);
if (events & UART_SCCM_RX)
@@ -407,7 +413,6 @@ static int cpm_uart_startup(struct uart_port *port)
{
int retval;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- int line = pinfo - cpm_uart_ports;
pr_debug("CPM uart[%d]:startup\n", port->line);
@@ -418,15 +423,15 @@ static int cpm_uart_startup(struct uart_port *port)
/* Startup rx-int */
if (IS_SMC(pinfo)) {
- pinfo->smcp->smc_smcm |= SMCM_RX;
- pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+ setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+ setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
} else {
- pinfo->sccp->scc_sccm |= UART_SCCM_RX;
- pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+ setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
}
if (!(pinfo->flags & FLAG_CONSOLE))
- cpm_line_cr_cmd(line,CPM_CR_INIT_TRX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
return 0;
}
@@ -442,7 +447,6 @@ inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
static void cpm_uart_shutdown(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- int line = pinfo - cpm_uart_ports;
pr_debug("CPM uart[%d]:shutdown\n", port->line);
@@ -462,20 +466,20 @@ static void cpm_uart_shutdown(struct uart_port *port)
/* Stop uarts */
if (IS_SMC(pinfo)) {
- volatile smc_t *smcp = pinfo->smcp;
- smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+ smc_t __iomem *smcp = pinfo->smcp;
+ clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+ clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
} else {
- volatile scc_t *sccp = pinfo->sccp;
- sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+ scc_t __iomem *sccp = pinfo->sccp;
+ clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
}
/* Shut them really down and reinit buffer descriptors */
if (IS_SMC(pinfo))
- cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
else
- cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
cpm_uart_initbd(pinfo);
}
@@ -490,8 +494,8 @@ static void cpm_uart_set_termios(struct uart_port *port,
u16 cval, scval, prev_mode;
int bits, sbits;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:set_termios\n", port->line);
@@ -586,16 +590,15 @@ static void cpm_uart_set_termios(struct uart_port *port,
* enables, because we want to put them back if they were
* present.
*/
- prev_mode = smcp->smc_smcmr;
- smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
- smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+ prev_mode = in_be16(&smcp->smc_smcmr);
+ out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | SMCMR_SM_UART);
+ setbits16(&smcp->smc_smcmr, (prev_mode & (SMCMR_REN | SMCMR_TEN)));
} else {
- sccp->scc_psmr = (sbits << 12) | scval;
+ out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
}
cpm_set_brg(pinfo->brg - 1, baud);
spin_unlock_irqrestore(&port->lock, flags);
-
}
static const char *cpm_uart_type(struct uart_port *port)
@@ -629,8 +632,8 @@ static int cpm_uart_verify_port(struct uart_port *port,
*/
static int cpm_uart_tx_pump(struct uart_port *port)
{
- volatile cbd_t *bdp;
- unsigned char *p;
+ cbd_t __iomem *bdp;
+ u8 *p;
int count;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
struct circ_buf *xmit = &port->info->xmit;
@@ -640,13 +643,14 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+ p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
*p++ = port->x_char;
- bdp->cbd_datlen = 1;
- bdp->cbd_sc |= BD_SC_READY;
+
+ out_be16(&bdp->cbd_datlen, 1);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
/* Get next BD. */
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
else
bdp++;
@@ -665,9 +669,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
+ while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
+ xmit->tail != xmit->head) {
count = 0;
- p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+ p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -676,11 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
if (xmit->head == xmit->tail)
break;
}
- bdp->cbd_datlen = count;
- bdp->cbd_sc |= BD_SC_READY;
- eieio();
+ out_be16(&bdp->cbd_datlen, count);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
/* Get next BD. */
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
else
bdp++;
@@ -705,7 +709,7 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
{
int i;
u8 *mem_addr;
- volatile cbd_t *bdp;
+ cbd_t __iomem *bdp;
pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
@@ -716,13 +720,13 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr;
bdp = pinfo->rx_cur = pinfo->rx_bd_base;
for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
mem_addr += pinfo->rx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
@@ -731,20 +735,19 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
bdp = pinfo->tx_cur = pinfo->tx_bd_base;
for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
mem_addr += pinfo->tx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
}
static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
{
- int line = pinfo - cpm_uart_ports;
- volatile scc_t *scp;
- volatile scc_uart_t *sup;
+ scc_t __iomem *scp;
+ scc_uart_t __iomem *sup;
pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
@@ -752,8 +755,10 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
sup = pinfo->sccup;
/* Store address */
- pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE;
- pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE;
+ out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
+ (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+ out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
+ (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
/* Set up the uart parameters in the
* parameter ram.
@@ -761,51 +766,50 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
cpm_set_scc_fcr(sup);
- sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize;
- sup->scc_maxidl = pinfo->rx_fifosize;
- sup->scc_brkcr = 1;
- sup->scc_parec = 0;
- sup->scc_frmec = 0;
- sup->scc_nosec = 0;
- sup->scc_brkec = 0;
- sup->scc_uaddr1 = 0;
- sup->scc_uaddr2 = 0;
- sup->scc_toseq = 0;
- sup->scc_char1 = 0x8000;
- sup->scc_char2 = 0x8000;
- sup->scc_char3 = 0x8000;
- sup->scc_char4 = 0x8000;
- sup->scc_char5 = 0x8000;
- sup->scc_char6 = 0x8000;
- sup->scc_char7 = 0x8000;
- sup->scc_char8 = 0x8000;
- sup->scc_rccm = 0xc0ff;
+ out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+ out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+ out_be16(&sup->scc_brkcr, 1);
+ out_be16(&sup->scc_parec, 0);
+ out_be16(&sup->scc_frmec, 0);
+ out_be16(&sup->scc_nosec, 0);
+ out_be16(&sup->scc_brkec, 0);
+ out_be16(&sup->scc_uaddr1, 0);
+ out_be16(&sup->scc_uaddr2, 0);
+ out_be16(&sup->scc_toseq, 0);
+ out_be16(&sup->scc_char1, 0x8000);
+ out_be16(&sup->scc_char2, 0x8000);
+ out_be16(&sup->scc_char3, 0x8000);
+ out_be16(&sup->scc_char4, 0x8000);
+ out_be16(&sup->scc_char5, 0x8000);
+ out_be16(&sup->scc_char6, 0x8000);
+ out_be16(&sup->scc_char7, 0x8000);
+ out_be16(&sup->scc_char8, 0x8000);
+ out_be16(&sup->scc_rccm, 0xc0ff);
/* Send the CPM an initialize command.
*/
- cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
- scp->scc_gsmrh = 0;
- scp->scc_gsmrl =
- (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+ out_be32(&scp->scc_gsmrh, 0);
+ out_be32(&scp->scc_gsmrl,
+ SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
/* Enable rx interrupts and clear all pending events. */
- scp->scc_sccm = 0;
- scp->scc_scce = 0xffff;
- scp->scc_dsr = 0x7e7e;
- scp->scc_psmr = 0x3000;
+ out_be16(&scp->scc_sccm, 0);
+ out_be16(&scp->scc_scce, 0xffff);
+ out_be16(&scp->scc_dsr, 0x7e7e);
+ out_be16(&scp->scc_psmr, 0x3000);
- scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
{
- int line = pinfo - cpm_uart_ports;
- volatile smc_t *sp;
- volatile smc_uart_t *up;
+ smc_t __iomem *sp;
+ smc_uart_t __iomem *up;
pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
@@ -813,19 +817,21 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
up = pinfo->smcup;
/* Store address */
- pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
- pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
+ out_be16(&pinfo->smcup->smc_rbase,
+ (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+ out_be16(&pinfo->smcup->smc_tbase,
+ (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
/*
* In case SMC1 is being relocated...
*/
#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
- up->smc_rbptr = pinfo->smcup->smc_rbase;
- up->smc_tbptr = pinfo->smcup->smc_tbase;
- up->smc_rstate = 0;
- up->smc_tstate = 0;
- up->smc_brkcr = 1; /* number of break chars */
- up->smc_brkec = 0;
+ out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
+ out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
+ out_be32(&up->smc_rstate, 0);
+ out_be32(&up->smc_tstate, 0);
+ out_be16(&up->smc_brkcr, 1); /* number of break chars */
+ out_be16(&up->smc_brkec, 0);
#endif
/* Set up the uart parameters in the
@@ -834,24 +840,24 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
cpm_set_smc_fcr(up);
/* Using idle charater time requires some additional tuning. */
- up->smc_mrblr = pinfo->rx_fifosize;
- up->smc_maxidl = pinfo->rx_fifosize;
- up->smc_brklen = 0;
- up->smc_brkec = 0;
- up->smc_brkcr = 1;
+ out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
+ out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+ out_be16(&up->smc_brklen, 0);
+ out_be16(&up->smc_brkec, 0);
+ out_be16(&up->smc_brkcr, 1);
- cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+ out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
/* Enable only rx interrupts clear all pending events. */
- sp->smc_smcm = 0;
- sp->smc_smce = 0xff;
+ out_8(&sp->smc_smcm, 0);
+ out_8(&sp->smc_smce, 0xff);
- sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+ setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
}
/*
@@ -869,11 +875,11 @@ static int cpm_uart_request_port(struct uart_port *port)
return 0;
if (IS_SMC(pinfo)) {
- pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
- pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+ clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+ clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
} else {
- pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
ret = cpm_uart_allocbuf(pinfo, 0);
@@ -929,6 +935,86 @@ static struct uart_ops cpm_uart_pops = {
.verify_port = cpm_uart_verify_port,
};
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+static int cpm_uart_init_port(struct device_node *np,
+ struct uart_cpm_port *pinfo)
+{
+ const u32 *data;
+ void __iomem *mem, *pram;
+ int len;
+ int ret;
+
+ data = of_get_property(np, "fsl,cpm-brg", &len);
+ if (!data || len != 4) {
+ printk(KERN_ERR "CPM UART %s has no/invalid "
+ "fsl,cpm-brg property.\n", np->name);
+ return -EINVAL;
+ }
+ pinfo->brg = *data;
+
+ data = of_get_property(np, "fsl,cpm-command", &len);
+ if (!data || len != 4) {
+ printk(KERN_ERR "CPM UART %s has no/invalid "
+ "fsl,cpm-command property.\n", np->name);
+ return -EINVAL;
+ }
+ pinfo->command = *data;
+
+ mem = of_iomap(np, 0);
+ if (!mem)
+ return -ENOMEM;
+
+ pram = of_iomap(np, 1);
+ if (!pram) {
+ ret = -ENOMEM;
+ goto out_mem;
+ }
+
+ if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
+ of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
+ pinfo->sccp = mem;
+ pinfo->sccup = pram;
+ } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
+ of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
+ pinfo->flags |= FLAG_SMC;
+ pinfo->smcp = mem;
+ pinfo->smcup = pram;
+ } else {
+ ret = -ENODEV;
+ goto out_pram;
+ }
+
+ pinfo->tx_nrfifos = TX_NUM_FIFO;
+ pinfo->tx_fifosize = TX_BUF_SIZE;
+ pinfo->rx_nrfifos = RX_NUM_FIFO;
+ pinfo->rx_fifosize = RX_BUF_SIZE;
+
+ pinfo->port.uartclk = ppc_proc_freq;
+ pinfo->port.mapbase = (unsigned long)mem;
+ pinfo->port.type = PORT_CPM;
+ pinfo->port.ops = &cpm_uart_pops,
+ pinfo->port.iotype = UPIO_MEM;
+ spin_lock_init(&pinfo->port.lock);
+
+ pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
+ if (pinfo->port.irq == NO_IRQ) {
+ ret = -EINVAL;
+ goto out_pram;
+ }
+
+ return cpm_uart_request_port(&pinfo->port);
+
+out_pram:
+ iounmap(pram);
+out_mem:
+ iounmap(mem);
+ return ret;
+}
+
+#else
+
struct uart_cpm_port cpm_uart_ports[UART_NR] = {
[UART_SMC1] = {
.port = {
@@ -1072,6 +1158,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
return 0;
}
+#endif
#ifdef CONFIG_SERIAL_CPM_CONSOLE
/*
@@ -1083,11 +1170,15 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
static void cpm_uart_console_write(struct console *co, const char *s,
u_int count)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
+#else
struct uart_cpm_port *pinfo =
&cpm_uart_ports[cpm_uart_port_map[co->index]];
+#endif
unsigned int i;
- volatile cbd_t *bdp, *bdbase;
- volatile unsigned char *cp;
+ cbd_t __iomem *bdp, *bdbase;
+ unsigned char *cp;
/* Get the address of the host memory buffer.
*/
@@ -1105,37 +1196,36 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* Ready indicates output is ready, and xmt is doing
* that, not that it is ready for us to send.
*/
- while ((bdp->cbd_sc & BD_SC_READY) != 0)
+ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
/* Send the character out.
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
- cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
+ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
*cp = *s;
- bdp->cbd_datlen = 1;
- bdp->cbd_sc |= BD_SC_READY;
+ out_be16(&bdp->cbd_datlen, 1);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
/* if a LF, also do CR... */
if (*s == 10) {
- while ((bdp->cbd_sc & BD_SC_READY) != 0)
+ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
- cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
+ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
*cp = 13;
- bdp->cbd_datlen = 1;
- bdp->cbd_sc |= BD_SC_READY;
- if (bdp->cbd_sc & BD_SC_WRAP)
+ out_be16(&bdp->cbd_datlen, 1);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
@@ -1146,22 +1236,56 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
- while ((bdp->cbd_sc & BD_SC_READY) != 0)
+ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
- pinfo->tx_cur = (volatile cbd_t *) bdp;
+ pinfo->tx_cur = bdp;
}
static int __init cpm_uart_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
- struct uart_cpm_port *pinfo;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
+ struct uart_cpm_port *pinfo;
+ struct uart_port *port;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct device_node *np = NULL;
+ int i = 0;
+
+ if (co->index >= UART_NR) {
+ printk(KERN_ERR "cpm_uart: console index %d too high\n",
+ co->index);
+ return -ENODEV;
+ }
+
+ do {
+ np = of_find_node_by_type(np, "serial");
+ if (!np)
+ return -ENODEV;
+
+ if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
+ !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
+ !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
+ !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
+ i--;
+ } while (i++ != co->index);
+
+ pinfo = &cpm_uart_ports[co->index];
+
+ pinfo->flags |= FLAG_CONSOLE;
+ port = &pinfo->port;
+
+ ret = cpm_uart_init_port(np, pinfo);
+ of_node_put(np);
+ if (ret)
+ return ret;
+
+#else
struct fs_uart_platform_info *pdata;
struct platform_device* pdev = early_uart_get_pdev(co->index);
@@ -1188,6 +1312,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
}
pinfo->flags |= FLAG_CONSOLE;
+#endif
if (options) {
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1196,12 +1321,18 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
baud = 9600;
}
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+ udbg_putc = NULL;
+#endif
+
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+
if (IS_SMC(pinfo)) {
- pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
- pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+ clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+ clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
} else {
- pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
ret = cpm_uart_allocbuf(pinfo, 1);
@@ -1217,6 +1348,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
cpm_uart_init_scc(pinfo);
uart_set_options(port, co, baud, parity, bits, flow);
+ cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
return 0;
}
@@ -1232,7 +1364,7 @@ static struct console cpm_scc_uart_console = {
.data = &cpm_reg,
};
-int __init cpm_uart_console_init(void)
+static int __init cpm_uart_console_init(void)
{
register_console(&cpm_scc_uart_console);
return 0;
@@ -1252,7 +1384,81 @@ static struct uart_driver cpm_reg = {
.major = SERIAL_CPM_MAJOR,
.minor = SERIAL_CPM_MINOR,
.cons = CPM_UART_CONSOLE,
+ .nr = UART_NR,
};
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int probe_index;
+
+static int __devinit cpm_uart_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ int index = probe_index++;
+ struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
+ int ret;
+
+ pinfo->port.line = index;
+
+ if (index >= UART_NR)
+ return -ENODEV;
+
+ dev_set_drvdata(&ofdev->dev, pinfo);
+
+ ret = cpm_uart_init_port(ofdev->node, pinfo);
+ if (ret)
+ return ret;
+
+ return uart_add_one_port(&cpm_reg, &pinfo->port);
+}
+
+static int __devexit cpm_uart_remove(struct of_device *ofdev)
+{
+ struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
+ return uart_remove_one_port(&cpm_reg, &pinfo->port);
+}
+
+static struct of_device_id cpm_uart_match[] = {
+ {
+ .compatible = "fsl,cpm1-smc-uart",
+ },
+ {
+ .compatible = "fsl,cpm1-scc-uart",
+ },
+ {
+ .compatible = "fsl,cpm2-smc-uart",
+ },
+ {
+ .compatible = "fsl,cpm2-scc-uart",
+ },
+ {}
+};
+
+static struct of_platform_driver cpm_uart_driver = {
+ .name = "cpm_uart",
+ .match_table = cpm_uart_match,
+ .probe = cpm_uart_probe,
+ .remove = cpm_uart_remove,
+ };
+
+static int __init cpm_uart_init(void)
+{
+ int ret = uart_register_driver(&cpm_reg);
+ if (ret)
+ return ret;
+
+ ret = of_register_platform_driver(&cpm_uart_driver);
+ if (ret)
+ uart_unregister_driver(&cpm_reg);
+
+ return ret;
+}
+
+static void __exit cpm_uart_exit(void)
+{
+ of_unregister_platform_driver(&cpm_uart_driver);
+ uart_unregister_driver(&cpm_reg);
+}
+#else
static int cpm_uart_drv_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1380,6 +1586,7 @@ static void __exit cpm_uart_exit(void)
driver_unregister(&cpm_smc_uart_driver);
uart_unregister_driver(&cpm_reg);
}
+#endif
module_init(cpm_uart_init);
module_exit(cpm_uart_exit);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 8c6324ed0202..52fb044bb79a 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -49,9 +49,20 @@
/**************************************************************/
-void cpm_line_cr_cmd(int line, int cmd)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+ u16 __iomem *cpcr = &cpmp->cp_cpcr;
+
+ out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG);
+ while (in_be16(cpcr) & CPM_CR_FLG)
+ ;
+}
+#else
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
{
ushort val;
+ int line = port - cpm_uart_ports;
volatile cpm8xx_t *cp = cpmp;
switch (line) {
@@ -114,6 +125,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo)
/* XXX SCC4: insert port configuration here */
pinfo->brg = 4;
}
+#endif
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
@@ -167,7 +179,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
- pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+ pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
@@ -184,6 +196,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
cpm_dpfree(pinfo->dp_addr);
}
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
@@ -279,3 +292,4 @@ int cpm_uart_init_portdesc(void)
#endif
return 0;
}
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index a99e45e2b6d8..9b5465fb0bbb 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -13,30 +13,32 @@
#include <asm/commproc.h>
/* defines for IRQs */
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
#define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1)
#define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2)
#define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1)
#define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2)
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
+#endif
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
}
-static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
{
- sup->scc_genscc.scc_rfcr = SMC_EB;
- sup->scc_genscc.scc_tfcr = SMC_EB;
+ out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
+ out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
}
-static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
{
- up->smc_rfcr = SMC_EB;
- up->smc_tfcr = SMC_EB;
+ out_8(&up->smc_rfcr, SMC_EB);
+ out_8(&up->smc_tfcr, SMC_EB);
}
-#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0])
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0))
#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 7b61d805ebe9..882dbc17d590 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -49,9 +49,22 @@
/**************************************************************/
-void cpm_line_cr_cmd(int line, int cmd)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+ cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm);
+
+ out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG);
+ while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG)
+ ;
+
+ cpm2_unmap(cp);
+}
+#else
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
{
ulong val;
+ int line = port - cpm_uart_ports;
volatile cpm_cpm2_t *cp = cpm2_map(im_cpm);
@@ -211,6 +224,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo)
cpm2_unmap(cpmux);
cpm2_unmap(io);
}
+#endif
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
@@ -221,7 +235,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo)
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
- u8 *dp_mem;
+ u8 __iomem *dp_mem;
unsigned long dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
@@ -264,7 +278,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
- pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+ pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
@@ -275,12 +289,13 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
- pinfo->tx_fifosize), pinfo->mem_addr,
+ pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
pinfo->dma_addr);
cpm_dpfree(pinfo->dp_addr);
}
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
@@ -386,3 +401,4 @@ int cpm_uart_init_portdesc(void)
return 0;
}
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 1b3219f56c81..40006a7dce46 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -13,30 +13,32 @@
#include <asm/cpm2.h>
/* defines for IRQs */
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
#define SMC1_IRQ SIU_INT_SMC1
#define SMC2_IRQ SIU_INT_SMC2
#define SCC1_IRQ SIU_INT_SCC1
#define SCC2_IRQ SIU_INT_SCC2
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
+#endif
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
}
-static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
{
- sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
- sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+ out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+ out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
}
-static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
{
- up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
- up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+ out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+ out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
}
-#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0))
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0))
#endif
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index e42faa4e4282..dc1967176fe2 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -1114,8 +1114,8 @@ static int __init imx_serial_init(void)
static void __exit imx_serial_exit(void)
{
- uart_unregister_driver(&imx_reg);
platform_driver_unregister(&serial_imx_driver);
+ uart_unregister_driver(&imx_reg);
}
module_init(imx_serial_init);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 35f8b86cc78f..035cca028199 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -1051,7 +1051,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx)
/* If the slot is already occupied, then swap slots */
if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
- mpc52xx_uart_nodes[i] = np;
+ mpc52xx_uart_nodes[idx] = np;
}
static void
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 00924feaf621..4d643c926657 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -74,10 +74,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
#define MPSC_NUM_CTLRS 2
/*
@@ -97,9 +93,8 @@
#define MPSC_TXBE_SIZE dma_get_cache_alignment()
#define MPSC_TXB_SIZE (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
-#define MPSC_DMA_ALLOC_SIZE (MPSC_RXR_SIZE + MPSC_RXB_SIZE + \
- MPSC_TXR_SIZE + MPSC_TXB_SIZE + \
- dma_get_cache_alignment() /* for alignment */)
+#define MPSC_DMA_ALLOC_SIZE (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
+ + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
struct mpsc_rx_desc {
@@ -270,8 +265,8 @@ struct mpsc_port_info *mpsc_device_remove(int index);
#define SDMA_DESC_CMDSTAT_EI (1<<23)
#define SDMA_DESC_CMDSTAT_O (1<<31)
-#define SDMA_DESC_DFLT (SDMA_DESC_CMDSTAT_O | \
- SDMA_DESC_CMDSTAT_EI)
+#define SDMA_DESC_DFLT (SDMA_DESC_CMDSTAT_O \
+ | SDMA_DESC_CMDSTAT_EI)
#define SDMA_SDC_RFT (1<<0)
#define SDMA_SDC_SFM (1<<1)
@@ -295,10 +290,10 @@ struct mpsc_port_info *mpsc_device_remove(int index);
#define SDMA_1_CAUSE_TXBUF (1<<10)
#define SDMA_1_CAUSE_TXEND (1<<11)
-#define SDMA_CAUSE_RX_MASK (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR | \
- SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define SDMA_CAUSE_TX_MASK (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND | \
- SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
+#define SDMA_CAUSE_RX_MASK (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
+ | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
+#define SDMA_CAUSE_TX_MASK (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
+ | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
/* SDMA Interrupt registers */
#define SDMA_INTR_CAUSE 0x0000
@@ -312,11 +307,11 @@ struct mpsc_port_info *mpsc_device_remove(int index);
* Define how this driver is known to the outside (we've been assigned a
* range on the "Low-density serial ports" major).
*/
-#define MPSC_MAJOR 204
-#define MPSC_MINOR_START 44
-#define MPSC_DRIVER_NAME "MPSC"
-#define MPSC_DEV_NAME "ttyMM"
-#define MPSC_VERSION "1.00"
+#define MPSC_MAJOR 204
+#define MPSC_MINOR_START 44
+#define MPSC_DRIVER_NAME "MPSC"
+#define MPSC_DEV_NAME "ttyMM"
+#define MPSC_VERSION "1.00"
static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
static struct mpsc_shared_regs mpsc_shared_regs;
@@ -332,8 +327,7 @@ static void mpsc_release_port(struct uart_port *port);
*
******************************************************************************
*/
-static void
-mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
+static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
{
u32 v;
@@ -349,11 +343,9 @@ mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
pi->brg_base + BRG_BTR);
- return;
}
-static void
-mpsc_brg_enable(struct mpsc_port_info *pi)
+static void mpsc_brg_enable(struct mpsc_port_info *pi)
{
u32 v;
@@ -363,11 +355,9 @@ mpsc_brg_enable(struct mpsc_port_info *pi)
if (pi->mirror_regs)
pi->BRG_BCR_m = v;
writel(v, pi->brg_base + BRG_BCR);
- return;
}
-static void
-mpsc_brg_disable(struct mpsc_port_info *pi)
+static void mpsc_brg_disable(struct mpsc_port_info *pi)
{
u32 v;
@@ -377,21 +367,19 @@ mpsc_brg_disable(struct mpsc_port_info *pi)
if (pi->mirror_regs)
pi->BRG_BCR_m = v;
writel(v, pi->brg_base + BRG_BCR);
- return;
}
-static inline void
-mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
+/*
+ * To set the baud, we adjust the CDV field in the BRG_BCR reg.
+ * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
+ * However, the input clock is divided by 16 in the MPSC b/c of how
+ * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
+ * calculation by 16 to account for that. So the real calculation
+ * that accounts for the way the mpsc is set up is:
+ * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
+ */
+static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
{
- /*
- * To set the baud, we adjust the CDV field in the BRG_BCR reg.
- * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
- * However, the input clock is divided by 16 in the MPSC b/c of how
- * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
- * calculation by 16 to account for that. So the real calculation
- * that accounts for the way the mpsc is set up is:
- * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
- */
u32 cdv = (pi->port.uartclk / (baud << 5)) - 1;
u32 v;
@@ -403,8 +391,6 @@ mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
pi->BRG_BCR_m = v;
writel(v, pi->brg_base + BRG_BCR);
mpsc_brg_enable(pi);
-
- return;
}
/*
@@ -415,13 +401,12 @@ mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
******************************************************************************
*/
-static void
-mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
+static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
{
u32 v;
pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
- pi->port.line, burst_size);
+ pi->port.line, burst_size);
burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
@@ -436,11 +421,9 @@ mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
pi->sdma_base + SDMA_SDC);
- return;
}
-static void
-mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
+static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
{
pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
burst_size);
@@ -448,11 +431,9 @@ mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
pi->sdma_base + SDMA_SDC);
mpsc_sdma_burstsize(pi, burst_size);
- return;
}
-static inline u32
-mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
+static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
{
u32 old, v;
@@ -475,15 +456,14 @@ mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
return old & 0xf;
}
-static inline void
-mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
+static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
{
u32 v;
pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
- v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
- readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+ v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
+ : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
mask &= 0xf;
if (pi->port.line)
@@ -493,41 +473,35 @@ mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
if (pi->mirror_regs)
pi->shared_regs->SDMA_INTR_MASK_m = v;
writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
- return;
}
-static inline void
-mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
+static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
{
pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
if (pi->mirror_regs)
pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
- writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE +
- pi->port.line);
- return;
+ writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
+ + pi->port.line);
}
-static inline void
-mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi, struct mpsc_rx_desc *rxre_p)
+static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
+ struct mpsc_rx_desc *rxre_p)
{
pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
- pi->port.line, (u32) rxre_p);
+ pi->port.line, (u32)rxre_p);
writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
- return;
}
-static inline void
-mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi, struct mpsc_tx_desc *txre_p)
+static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
+ struct mpsc_tx_desc *txre_p)
{
writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
- return;
}
-static inline void
-mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
+static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
{
u32 v;
@@ -539,46 +513,40 @@ mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
wmb();
writel(v, pi->sdma_base + SDMA_SDCM);
wmb();
- return;
}
-static inline uint
-mpsc_sdma_tx_active(struct mpsc_port_info *pi)
+static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
{
return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
}
-static inline void
-mpsc_sdma_start_tx(struct mpsc_port_info *pi)
+static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
{
struct mpsc_tx_desc *txre, *txre_p;
/* If tx isn't running & there's a desc ready to go, start it */
if (!mpsc_sdma_tx_active(pi)) {
- txre = (struct mpsc_tx_desc *)(pi->txr +
- (pi->txr_tail * MPSC_TXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
+ txre = (struct mpsc_tx_desc *)(pi->txr
+ + (pi->txr_tail * MPSC_TXRE_SIZE));
+ dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+ DMA_FROM_DEVICE);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
invalidate_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
+ (ulong)txre + MPSC_TXRE_SIZE);
#endif
if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
- txre_p = (struct mpsc_tx_desc *)(pi->txr_p +
- (pi->txr_tail *
- MPSC_TXRE_SIZE));
+ txre_p = (struct mpsc_tx_desc *)
+ (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
mpsc_sdma_set_tx_ring(pi, txre_p);
mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
}
}
-
- return;
}
-static inline void
-mpsc_sdma_stop(struct mpsc_port_info *pi)
+static void mpsc_sdma_stop(struct mpsc_port_info *pi)
{
pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
@@ -593,8 +561,6 @@ mpsc_sdma_stop(struct mpsc_port_info *pi)
/* Disable interrupts */
mpsc_sdma_intr_mask(pi, 0xf);
mpsc_sdma_intr_ack(pi);
-
- return;
}
/*
@@ -605,8 +571,7 @@ mpsc_sdma_stop(struct mpsc_port_info *pi)
******************************************************************************
*/
-static void
-mpsc_hw_init(struct mpsc_port_info *pi)
+static void mpsc_hw_init(struct mpsc_port_info *pi)
{
u32 v;
@@ -628,8 +593,7 @@ mpsc_hw_init(struct mpsc_port_info *pi)
v = (v & ~0xf0f) | 0x100;
pi->shared_regs->MPSC_TCRR_m = v;
writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
- }
- else {
+ } else {
v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
v &= ~0x1c7;
writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
@@ -646,7 +610,7 @@ mpsc_hw_init(struct mpsc_port_info *pi)
/* Put MPSC in UART mode & enabel Tx/Rx egines */
writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
- /* No preamble, 16x divider, low-latency, */
+ /* No preamble, 16x divider, low-latency, */
writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
if (pi->mirror_regs) {
@@ -663,12 +627,9 @@ mpsc_hw_init(struct mpsc_port_info *pi)
writel(0, pi->mpsc_base + MPSC_CHR_8);
writel(0, pi->mpsc_base + MPSC_CHR_9);
writel(0, pi->mpsc_base + MPSC_CHR_10);
-
- return;
}
-static inline void
-mpsc_enter_hunt(struct mpsc_port_info *pi)
+static void mpsc_enter_hunt(struct mpsc_port_info *pi)
{
pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
@@ -677,20 +638,16 @@ mpsc_enter_hunt(struct mpsc_port_info *pi)
pi->mpsc_base + MPSC_CHR_2);
/* Erratum prevents reading CHR_2 so just delay for a while */
udelay(100);
- }
- else {
+ } else {
writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
- pi->mpsc_base + MPSC_CHR_2);
+ pi->mpsc_base + MPSC_CHR_2);
while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
udelay(10);
}
-
- return;
}
-static inline void
-mpsc_freeze(struct mpsc_port_info *pi)
+static void mpsc_freeze(struct mpsc_port_info *pi)
{
u32 v;
@@ -703,11 +660,9 @@ mpsc_freeze(struct mpsc_port_info *pi)
if (pi->mirror_regs)
pi->MPSC_MPCR_m = v;
writel(v, pi->mpsc_base + MPSC_MPCR);
- return;
}
-static inline void
-mpsc_unfreeze(struct mpsc_port_info *pi)
+static void mpsc_unfreeze(struct mpsc_port_info *pi)
{
u32 v;
@@ -720,11 +675,9 @@ mpsc_unfreeze(struct mpsc_port_info *pi)
writel(v, pi->mpsc_base + MPSC_MPCR);
pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
- return;
}
-static inline void
-mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
+static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
{
u32 v;
@@ -737,11 +690,9 @@ mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
if (pi->mirror_regs)
pi->MPSC_MPCR_m = v;
writel(v, pi->mpsc_base + MPSC_MPCR);
- return;
}
-static inline void
-mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
+static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
{
u32 v;
@@ -756,11 +707,9 @@ mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
if (pi->mirror_regs)
pi->MPSC_MPCR_m = v;
writel(v, pi->mpsc_base + MPSC_MPCR);
- return;
}
-static inline void
-mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
+static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
{
u32 v;
@@ -775,7 +724,6 @@ mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
if (pi->mirror_regs)
pi->MPSC_CHR_2_m = v;
writel(v, pi->mpsc_base + MPSC_CHR_2);
- return;
}
/*
@@ -786,8 +734,7 @@ mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
******************************************************************************
*/
-static void
-mpsc_init_hw(struct mpsc_port_info *pi)
+static void mpsc_init_hw(struct mpsc_port_info *pi)
{
pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
@@ -796,12 +743,9 @@ mpsc_init_hw(struct mpsc_port_info *pi)
mpsc_sdma_init(pi, dma_get_cache_alignment()); /* burst a cacheline */
mpsc_sdma_stop(pi);
mpsc_hw_init(pi);
-
- return;
}
-static int
-mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
+static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
{
int rc = 0;
@@ -812,11 +756,10 @@ mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
if (!dma_supported(pi->port.dev, 0xffffffff)) {
printk(KERN_ERR "MPSC: Inadequate DMA support\n");
rc = -ENXIO;
- }
- else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
- MPSC_DMA_ALLOC_SIZE, &pi->dma_region_p, GFP_KERNEL))
- == NULL) {
-
+ } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
+ MPSC_DMA_ALLOC_SIZE,
+ &pi->dma_region_p, GFP_KERNEL))
+ == NULL) {
printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
rc = -ENOMEM;
}
@@ -825,23 +768,19 @@ mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
return rc;
}
-static void
-mpsc_free_ring_mem(struct mpsc_port_info *pi)
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
{
pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
if (pi->dma_region) {
dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
- pi->dma_region, pi->dma_region_p);
+ pi->dma_region, pi->dma_region_p);
pi->dma_region = NULL;
- pi->dma_region_p = (dma_addr_t) NULL;
+ pi->dma_region_p = (dma_addr_t)NULL;
}
-
- return;
}
-static void
-mpsc_init_rings(struct mpsc_port_info *pi)
+static void mpsc_init_rings(struct mpsc_port_info *pi)
{
struct mpsc_rx_desc *rxre;
struct mpsc_tx_desc *txre;
@@ -859,8 +798,8 @@ mpsc_init_rings(struct mpsc_port_info *pi)
* Descriptors & buffers are multiples of cacheline size and must be
* cacheline aligned.
*/
- dp = ALIGN((u32) pi->dma_region, dma_get_cache_alignment());
- dp_p = ALIGN((u32) pi->dma_region_p, dma_get_cache_alignment());
+ dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
+ dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
/*
* Partition dma region into rx ring descriptor, rx buffers,
@@ -871,8 +810,8 @@ mpsc_init_rings(struct mpsc_port_info *pi)
dp += MPSC_RXR_SIZE;
dp_p += MPSC_RXR_SIZE;
- pi->rxb = (u8 *) dp;
- pi->rxb_p = (u8 *) dp_p;
+ pi->rxb = (u8 *)dp;
+ pi->rxb_p = (u8 *)dp_p;
dp += MPSC_RXB_SIZE;
dp_p += MPSC_RXB_SIZE;
@@ -883,8 +822,8 @@ mpsc_init_rings(struct mpsc_port_info *pi)
dp += MPSC_TXR_SIZE;
dp_p += MPSC_TXR_SIZE;
- pi->txb = (u8 *) dp;
- pi->txb_p = (u8 *) dp_p;
+ pi->txb = (u8 *)dp;
+ pi->txb_p = (u8 *)dp_p;
pi->txr_head = 0;
pi->txr_tail = 0;
@@ -900,10 +839,9 @@ mpsc_init_rings(struct mpsc_port_info *pi)
rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
rxre->bytecnt = cpu_to_be16(0);
- rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
- SDMA_DESC_CMDSTAT_EI |
- SDMA_DESC_CMDSTAT_F |
- SDMA_DESC_CMDSTAT_L);
+ rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+ | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+ | SDMA_DESC_CMDSTAT_L);
rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
rxre->buf_ptr = cpu_to_be32(bp_p);
@@ -933,19 +871,19 @@ mpsc_init_rings(struct mpsc_port_info *pi)
}
txre->link = cpu_to_be32(pi->txr_p); /* Wrap last back to first */
- dma_cache_sync(pi->port.dev, (void *) pi->dma_region, MPSC_DMA_ALLOC_SIZE,
- DMA_BIDIRECTIONAL);
+ dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
+ MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
flush_dcache_range((ulong)pi->dma_region,
- (ulong)pi->dma_region + MPSC_DMA_ALLOC_SIZE);
+ (ulong)pi->dma_region
+ + MPSC_DMA_ALLOC_SIZE);
#endif
return;
}
-static void
-mpsc_uninit_rings(struct mpsc_port_info *pi)
+static void mpsc_uninit_rings(struct mpsc_port_info *pi)
{
pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
@@ -963,12 +901,9 @@ mpsc_uninit_rings(struct mpsc_port_info *pi)
pi->txb_p = NULL;
pi->txr_head = 0;
pi->txr_tail = 0;
-
- return;
}
-static int
-mpsc_make_ready(struct mpsc_port_info *pi)
+static int mpsc_make_ready(struct mpsc_port_info *pi)
{
int rc;
@@ -993,8 +928,7 @@ mpsc_make_ready(struct mpsc_port_info *pi)
******************************************************************************
*/
-static inline int
-mpsc_rx_intr(struct mpsc_port_info *pi)
+static int mpsc_rx_intr(struct mpsc_port_info *pi)
{
struct mpsc_rx_desc *rxre;
struct tty_struct *tty = pi->port.info->tty;
@@ -1007,21 +941,24 @@ mpsc_rx_intr(struct mpsc_port_info *pi)
rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+ dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+ DMA_FROM_DEVICE);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
invalidate_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
+ (ulong)rxre + MPSC_RXRE_SIZE);
#endif
/*
* Loop through Rx descriptors handling ones that have been completed.
*/
- while (!((cmdstat = be32_to_cpu(rxre->cmdstat)) & SDMA_DESC_CMDSTAT_O)){
+ while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
+ & SDMA_DESC_CMDSTAT_O)) {
bytes_in = be16_to_cpu(rxre->bytecnt);
/* Following use of tty struct directly is deprecated */
- if (unlikely(tty_buffer_request_room(tty, bytes_in) < bytes_in)) {
+ if (unlikely(tty_buffer_request_room(tty, bytes_in)
+ < bytes_in)) {
if (tty->low_latency)
tty_flip_buffer_push(tty);
/*
@@ -1031,11 +968,12 @@ mpsc_rx_intr(struct mpsc_port_info *pi)
}
bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
- dma_cache_sync(pi->port.dev, (void *) bp, MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
+ dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
+ DMA_FROM_DEVICE);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
invalidate_dcache_range((ulong)bp,
- (ulong)bp + MPSC_RXBE_SIZE);
+ (ulong)bp + MPSC_RXBE_SIZE);
#endif
/*
@@ -1046,8 +984,9 @@ mpsc_rx_intr(struct mpsc_port_info *pi)
* we'll assume there is no data in the buffer.
* If there is...it gets lost.
*/
- if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
- SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) {
+ if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+ | SDMA_DESC_CMDSTAT_FR
+ | SDMA_DESC_CMDSTAT_OR))) {
pi->port.icount.rx++;
@@ -1056,11 +995,11 @@ mpsc_rx_intr(struct mpsc_port_info *pi)
if (uart_handle_break(&pi->port))
goto next_frame;
- }
- else if (cmdstat & SDMA_DESC_CMDSTAT_FR)/* Framing */
+ } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
pi->port.icount.frame++;
- else if (cmdstat & SDMA_DESC_CMDSTAT_OR) /* Overrun */
+ } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
pi->port.icount.overrun++;
+ }
cmdstat &= pi->port.read_status_mask;
@@ -1080,12 +1019,12 @@ mpsc_rx_intr(struct mpsc_port_info *pi)
goto next_frame;
}
- if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
- SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
- !(cmdstat & pi->port.ignore_status_mask))
-
+ if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+ | SDMA_DESC_CMDSTAT_FR
+ | SDMA_DESC_CMDSTAT_OR)))
+ && !(cmdstat & pi->port.ignore_status_mask)) {
tty_insert_flip_char(tty, *bp, flag);
- else {
+ } else {
for (i=0; i<bytes_in; i++)
tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
@@ -1095,29 +1034,29 @@ mpsc_rx_intr(struct mpsc_port_info *pi)
next_frame:
rxre->bytecnt = cpu_to_be16(0);
wmb();
- rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
- SDMA_DESC_CMDSTAT_EI |
- SDMA_DESC_CMDSTAT_F |
- SDMA_DESC_CMDSTAT_L);
+ rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+ | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+ | SDMA_DESC_CMDSTAT_L);
wmb();
- dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
+ dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+ DMA_BIDIRECTIONAL);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
flush_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
+ (ulong)rxre + MPSC_RXRE_SIZE);
#endif
/* Advance to next descriptor */
pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
- rxre = (struct mpsc_rx_desc *)(pi->rxr +
- (pi->rxr_posn * MPSC_RXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+ rxre = (struct mpsc_rx_desc *)
+ (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
+ dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+ DMA_FROM_DEVICE);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
invalidate_dcache_range((ulong)rxre,
- (ulong)rxre + MPSC_RXRE_SIZE);
+ (ulong)rxre + MPSC_RXRE_SIZE);
#endif
-
rc = 1;
}
@@ -1129,42 +1068,38 @@ next_frame:
return rc;
}
-static inline void
-mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
+static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
{
struct mpsc_tx_desc *txre;
- txre = (struct mpsc_tx_desc *)(pi->txr +
- (pi->txr_head * MPSC_TXRE_SIZE));
+ txre = (struct mpsc_tx_desc *)(pi->txr
+ + (pi->txr_head * MPSC_TXRE_SIZE));
txre->bytecnt = cpu_to_be16(count);
txre->shadow = txre->bytecnt;
wmb(); /* ensure cmdstat is last field updated */
- txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F |
- SDMA_DESC_CMDSTAT_L | ((intr) ?
- SDMA_DESC_CMDSTAT_EI
- : 0));
+ txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
+ | SDMA_DESC_CMDSTAT_L
+ | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
wmb();
- dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE, DMA_BIDIRECTIONAL);
+ dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+ DMA_BIDIRECTIONAL);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
flush_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
+ (ulong)txre + MPSC_TXRE_SIZE);
#endif
-
- return;
}
-static inline void
-mpsc_copy_tx_data(struct mpsc_port_info *pi)
+static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
{
struct circ_buf *xmit = &pi->port.info->xmit;
u8 *bp;
u32 i;
/* Make sure the desc ring isn't full */
- while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES) <
- (MPSC_TXR_ENTRIES - 1)) {
+ while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
+ < (MPSC_TXR_ENTRIES - 1)) {
if (pi->port.x_char) {
/*
* Ideally, we should use the TCS field in
@@ -1178,11 +1113,11 @@ mpsc_copy_tx_data(struct mpsc_port_info *pi)
*bp = pi->port.x_char;
pi->port.x_char = 0;
i = 1;
- }
- else if (!uart_circ_empty(xmit) && !uart_tx_stopped(&pi->port)){
- i = min((u32) MPSC_TXBE_SIZE,
- (u32) uart_circ_chars_pending(xmit));
- i = min(i, (u32) CIRC_CNT_TO_END(xmit->head, xmit->tail,
+ } else if (!uart_circ_empty(xmit)
+ && !uart_tx_stopped(&pi->port)) {
+ i = min((u32)MPSC_TXBE_SIZE,
+ (u32)uart_circ_chars_pending(xmit));
+ i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
UART_XMIT_SIZE));
bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
memcpy(bp, &xmit->buf[xmit->tail], i);
@@ -1190,27 +1125,25 @@ mpsc_copy_tx_data(struct mpsc_port_info *pi)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&pi->port);
- }
- else /* All tx data copied into ring bufs */
+ } else { /* All tx data copied into ring bufs */
return;
+ }
- dma_cache_sync(pi->port.dev, (void *) bp, MPSC_TXBE_SIZE, DMA_BIDIRECTIONAL);
+ dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+ DMA_BIDIRECTIONAL);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
flush_dcache_range((ulong)bp,
- (ulong)bp + MPSC_TXBE_SIZE);
+ (ulong)bp + MPSC_TXBE_SIZE);
#endif
mpsc_setup_tx_desc(pi, i, 1);
/* Advance to next descriptor */
pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
}
-
- return;
}
-static inline int
-mpsc_tx_intr(struct mpsc_port_info *pi)
+static int mpsc_tx_intr(struct mpsc_port_info *pi)
{
struct mpsc_tx_desc *txre;
int rc = 0;
@@ -1219,14 +1152,15 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
spin_lock_irqsave(&pi->tx_lock, iflags);
if (!mpsc_sdma_tx_active(pi)) {
- txre = (struct mpsc_tx_desc *)(pi->txr +
- (pi->txr_tail * MPSC_TXRE_SIZE));
+ txre = (struct mpsc_tx_desc *)(pi->txr
+ + (pi->txr_tail * MPSC_TXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
+ dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+ DMA_FROM_DEVICE);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
invalidate_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
+ (ulong)txre + MPSC_TXRE_SIZE);
#endif
while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
@@ -1238,14 +1172,14 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
if (pi->txr_head == pi->txr_tail)
break;
- txre = (struct mpsc_tx_desc *)(pi->txr +
- (pi->txr_tail * MPSC_TXRE_SIZE));
- dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE,
- DMA_FROM_DEVICE);
+ txre = (struct mpsc_tx_desc *)(pi->txr
+ + (pi->txr_tail * MPSC_TXRE_SIZE));
+ dma_cache_sync(pi->port.dev, (void *)txre,
+ MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
invalidate_dcache_range((ulong)txre,
- (ulong)txre + MPSC_TXRE_SIZE);
+ (ulong)txre + MPSC_TXRE_SIZE);
#endif
}
@@ -1262,8 +1196,7 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
* the interrupt, then handle any completed Rx/Tx descriptors. When done
* handling those descriptors, we restart the Rx/Tx engines if they're stopped.
*/
-static irqreturn_t
-mpsc_sdma_intr(int irq, void *dev_id)
+static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
{
struct mpsc_port_info *pi = dev_id;
ulong iflags;
@@ -1290,8 +1223,7 @@ mpsc_sdma_intr(int irq, void *dev_id)
*
******************************************************************************
*/
-static uint
-mpsc_tx_empty(struct uart_port *port)
+static uint mpsc_tx_empty(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
ulong iflags;
@@ -1304,21 +1236,18 @@ mpsc_tx_empty(struct uart_port *port)
return rc;
}
-static void
-mpsc_set_mctrl(struct uart_port *port, uint mctrl)
+static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
{
/* Have no way to set modem control lines AFAICT */
- return;
}
-static uint
-mpsc_get_mctrl(struct uart_port *port)
+static uint mpsc_get_mctrl(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
u32 mflags, status;
- status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m :
- readl(pi->mpsc_base + MPSC_CHR_10);
+ status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
+ : readl(pi->mpsc_base + MPSC_CHR_10);
mflags = 0;
if (status & 0x1)
@@ -1329,19 +1258,16 @@ mpsc_get_mctrl(struct uart_port *port)
return mflags | TIOCM_DSR; /* No way to tell if DSR asserted */
}
-static void
-mpsc_stop_tx(struct uart_port *port)
+static void mpsc_stop_tx(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
pr_debug("mpsc_stop_tx[%d]\n", port->line);
mpsc_freeze(pi);
- return;
}
-static void
-mpsc_start_tx(struct uart_port *port)
+static void mpsc_start_tx(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
unsigned long iflags;
@@ -1355,42 +1281,45 @@ mpsc_start_tx(struct uart_port *port)
spin_unlock_irqrestore(&pi->tx_lock, iflags);
pr_debug("mpsc_start_tx[%d]\n", port->line);
- return;
}
-static void
-mpsc_start_rx(struct mpsc_port_info *pi)
+static void mpsc_start_rx(struct mpsc_port_info *pi)
{
pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
- /* Issue a Receive Abort to clear any receive errors */
- writel(MPSC_CHR_2_RA, pi->mpsc_base + MPSC_CHR_2);
if (pi->rcv_data) {
mpsc_enter_hunt(pi);
mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
}
- return;
}
-static void
-mpsc_stop_rx(struct uart_port *port)
+static void mpsc_stop_rx(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
+ if (pi->mirror_regs) {
+ writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
+ pi->mpsc_base + MPSC_CHR_2);
+ /* Erratum prevents reading CHR_2 so just delay for a while */
+ udelay(100);
+ } else {
+ writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
+ pi->mpsc_base + MPSC_CHR_2);
+
+ while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
+ udelay(10);
+ }
+
mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
- return;
}
-static void
-mpsc_enable_ms(struct uart_port *port)
+static void mpsc_enable_ms(struct uart_port *port)
{
- return; /* Not supported */
}
-static void
-mpsc_break_ctl(struct uart_port *port, int ctl)
+static void mpsc_break_ctl(struct uart_port *port, int ctl)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
ulong flags;
@@ -1403,12 +1332,9 @@ mpsc_break_ctl(struct uart_port *port, int ctl)
pi->MPSC_CHR_1_m = v;
writel(v, pi->mpsc_base + MPSC_CHR_1);
spin_unlock_irqrestore(&pi->port.lock, flags);
-
- return;
}
-static int
-mpsc_startup(struct uart_port *port)
+static int mpsc_startup(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
u32 flag = 0;
@@ -1426,20 +1352,19 @@ mpsc_startup(struct uart_port *port)
flag = IRQF_SHARED;
if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
- "mpsc-sdma", pi))
+ "mpsc-sdma", pi))
printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
- pi->port.irq);
+ pi->port.irq);
mpsc_sdma_intr_unmask(pi, 0xf);
- mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p +
- (pi->rxr_posn * MPSC_RXRE_SIZE)));
+ mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
+ + (pi->rxr_posn * MPSC_RXRE_SIZE)));
}
return rc;
}
-static void
-mpsc_shutdown(struct uart_port *port)
+static void mpsc_shutdown(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
@@ -1447,11 +1372,9 @@ mpsc_shutdown(struct uart_port *port)
mpsc_sdma_stop(pi);
free_irq(pi->port.irq, pi);
- return;
}
-static void
-mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
+static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
@@ -1508,12 +1431,11 @@ mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
mpsc_set_baudrate(pi, baud);
/* Characters/events to read */
- pi->rcv_data = 1;
pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
if (termios->c_iflag & INPCK)
- pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE |
- SDMA_DESC_CMDSTAT_FR;
+ pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
+ | SDMA_DESC_CMDSTAT_FR;
if (termios->c_iflag & (BRKINT | PARMRK))
pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
@@ -1522,8 +1444,8 @@ mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
pi->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE |
- SDMA_DESC_CMDSTAT_FR;
+ pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
+ | SDMA_DESC_CMDSTAT_FR;
if (termios->c_iflag & IGNBRK) {
pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
@@ -1532,32 +1454,32 @@ mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
}
- /* Ignore all chars if CREAD not set */
- if (!(termios->c_cflag & CREAD))
+ if ((termios->c_cflag & CREAD)) {
+ if (!pi->rcv_data) {
+ pi->rcv_data = 1;
+ mpsc_start_rx(pi);
+ }
+ } else if (pi->rcv_data) {
+ mpsc_stop_rx(port);
pi->rcv_data = 0;
- else
- mpsc_start_rx(pi);
+ }
spin_unlock_irqrestore(&pi->port.lock, flags);
- return;
}
-static const char *
-mpsc_type(struct uart_port *port)
+static const char *mpsc_type(struct uart_port *port)
{
pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
return MPSC_DRIVER_NAME;
}
-static int
-mpsc_request_port(struct uart_port *port)
+static int mpsc_request_port(struct uart_port *port)
{
/* Should make chip/platform specific call */
return 0;
}
-static void
-mpsc_release_port(struct uart_port *port)
+static void mpsc_release_port(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
@@ -1566,18 +1488,13 @@ mpsc_release_port(struct uart_port *port)
mpsc_free_ring_mem(pi);
pi->ready = 0;
}
-
- return;
}
-static void
-mpsc_config_port(struct uart_port *port, int flags)
+static void mpsc_config_port(struct uart_port *port, int flags)
{
- return;
}
-static int
-mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
int rc = 0;
@@ -1603,22 +1520,22 @@ mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
}
static struct uart_ops mpsc_pops = {
- .tx_empty = mpsc_tx_empty,
- .set_mctrl = mpsc_set_mctrl,
- .get_mctrl = mpsc_get_mctrl,
- .stop_tx = mpsc_stop_tx,
- .start_tx = mpsc_start_tx,
- .stop_rx = mpsc_stop_rx,
- .enable_ms = mpsc_enable_ms,
- .break_ctl = mpsc_break_ctl,
- .startup = mpsc_startup,
- .shutdown = mpsc_shutdown,
- .set_termios = mpsc_set_termios,
- .type = mpsc_type,
- .release_port = mpsc_release_port,
- .request_port = mpsc_request_port,
- .config_port = mpsc_config_port,
- .verify_port = mpsc_verify_port,
+ .tx_empty = mpsc_tx_empty,
+ .set_mctrl = mpsc_set_mctrl,
+ .get_mctrl = mpsc_get_mctrl,
+ .stop_tx = mpsc_stop_tx,
+ .start_tx = mpsc_start_tx,
+ .stop_rx = mpsc_stop_rx,
+ .enable_ms = mpsc_enable_ms,
+ .break_ctl = mpsc_break_ctl,
+ .startup = mpsc_startup,
+ .shutdown = mpsc_shutdown,
+ .set_termios = mpsc_set_termios,
+ .type = mpsc_type,
+ .release_port = mpsc_release_port,
+ .request_port = mpsc_request_port,
+ .config_port = mpsc_config_port,
+ .verify_port = mpsc_verify_port,
};
/*
@@ -1630,8 +1547,7 @@ static struct uart_ops mpsc_pops = {
*/
#ifdef CONFIG_SERIAL_MPSC_CONSOLE
-static void
-mpsc_console_write(struct console *co, const char *s, uint count)
+static void mpsc_console_write(struct console *co, const char *s, uint count)
{
struct mpsc_port_info *pi = &mpsc_ports[co->index];
u8 *bp, *dp, add_cr = 0;
@@ -1660,8 +1576,7 @@ mpsc_console_write(struct console *co, const char *s, uint count)
if (add_cr) {
*(dp++) = '\r';
add_cr = 0;
- }
- else {
+ } else {
*(dp++) = *s;
if (*(s++) == '\n') { /* add '\r' after '\n' */
@@ -1673,11 +1588,12 @@ mpsc_console_write(struct console *co, const char *s, uint count)
count--;
}
- dma_cache_sync(pi->port.dev, (void *) bp, MPSC_TXBE_SIZE, DMA_BIDIRECTIONAL);
+ dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+ DMA_BIDIRECTIONAL);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
flush_dcache_range((ulong)bp,
- (ulong)bp + MPSC_TXBE_SIZE);
+ (ulong)bp + MPSC_TXBE_SIZE);
#endif
mpsc_setup_tx_desc(pi, i, 0);
pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
@@ -1690,11 +1606,9 @@ mpsc_console_write(struct console *co, const char *s, uint count)
}
spin_unlock_irqrestore(&pi->tx_lock, iflags);
- return;
}
-static int __init
-mpsc_console_setup(struct console *co, char *options)
+static int __init mpsc_console_setup(struct console *co, char *options)
{
struct mpsc_port_info *pi;
int baud, bits, parity, flow;
@@ -1723,17 +1637,16 @@ mpsc_console_setup(struct console *co, char *options)
}
static struct console mpsc_console = {
- .name = MPSC_DEV_NAME,
- .write = mpsc_console_write,
- .device = uart_console_device,
- .setup = mpsc_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &mpsc_reg,
+ .name = MPSC_DEV_NAME,
+ .write = mpsc_console_write,
+ .device = uart_console_device,
+ .setup = mpsc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mpsc_reg,
};
-static int __init
-mpsc_late_console_init(void)
+static int __init mpsc_late_console_init(void)
{
pr_debug("mpsc_late_console_init: Enter\n");
@@ -1755,43 +1668,40 @@ late_initcall(mpsc_late_console_init);
*
******************************************************************************
*/
-static void
-mpsc_resource_err(char *s)
+static void mpsc_resource_err(char *s)
{
printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
- return;
}
-static int
-mpsc_shared_map_regs(struct platform_device *pd)
+static int mpsc_shared_map_regs(struct platform_device *pd)
{
struct resource *r;
if ((r = platform_get_resource(pd, IORESOURCE_MEM,
- MPSC_ROUTING_BASE_ORDER)) && request_mem_region(r->start,
- MPSC_ROUTING_REG_BLOCK_SIZE, "mpsc_routing_regs")) {
-
+ MPSC_ROUTING_BASE_ORDER))
+ && request_mem_region(r->start,
+ MPSC_ROUTING_REG_BLOCK_SIZE,
+ "mpsc_routing_regs")) {
mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
- MPSC_ROUTING_REG_BLOCK_SIZE);
+ MPSC_ROUTING_REG_BLOCK_SIZE);
mpsc_shared_regs.mpsc_routing_base_p = r->start;
- }
- else {
+ } else {
mpsc_resource_err("MPSC routing base");
return -ENOMEM;
}
if ((r = platform_get_resource(pd, IORESOURCE_MEM,
- MPSC_SDMA_INTR_BASE_ORDER)) && request_mem_region(r->start,
- MPSC_SDMA_INTR_REG_BLOCK_SIZE, "sdma_intr_regs")) {
-
+ MPSC_SDMA_INTR_BASE_ORDER))
+ && request_mem_region(r->start,
+ MPSC_SDMA_INTR_REG_BLOCK_SIZE,
+ "sdma_intr_regs")) {
mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
MPSC_SDMA_INTR_REG_BLOCK_SIZE);
mpsc_shared_regs.sdma_intr_base_p = r->start;
- }
- else {
+ } else {
iounmap(mpsc_shared_regs.mpsc_routing_base);
release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
- MPSC_ROUTING_REG_BLOCK_SIZE);
+ MPSC_ROUTING_REG_BLOCK_SIZE);
mpsc_resource_err("SDMA intr base");
return -ENOMEM;
}
@@ -1799,18 +1709,17 @@ mpsc_shared_map_regs(struct platform_device *pd)
return 0;
}
-static void
-mpsc_shared_unmap_regs(void)
+static void mpsc_shared_unmap_regs(void)
{
if (!mpsc_shared_regs.mpsc_routing_base) {
iounmap(mpsc_shared_regs.mpsc_routing_base);
release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
- MPSC_ROUTING_REG_BLOCK_SIZE);
+ MPSC_ROUTING_REG_BLOCK_SIZE);
}
if (!mpsc_shared_regs.sdma_intr_base) {
iounmap(mpsc_shared_regs.sdma_intr_base);
release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
- MPSC_SDMA_INTR_REG_BLOCK_SIZE);
+ MPSC_SDMA_INTR_REG_BLOCK_SIZE);
}
mpsc_shared_regs.mpsc_routing_base = NULL;
@@ -1818,19 +1727,17 @@ mpsc_shared_unmap_regs(void)
mpsc_shared_regs.mpsc_routing_base_p = 0;
mpsc_shared_regs.sdma_intr_base_p = 0;
-
- return;
}
-static int
-mpsc_shared_drv_probe(struct platform_device *dev)
+static int mpsc_shared_drv_probe(struct platform_device *dev)
{
struct mpsc_shared_pdata *pdata;
int rc = -ENODEV;
if (dev->id == 0) {
- if (!(rc = mpsc_shared_map_regs(dev))) {
- pdata = (struct mpsc_shared_pdata *)dev->dev.platform_data;
+ if (!(rc = mpsc_shared_map_regs(dev))) {
+ pdata = (struct mpsc_shared_pdata *)
+ dev->dev.platform_data;
mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
@@ -1847,8 +1754,7 @@ mpsc_shared_drv_probe(struct platform_device *dev)
return rc;
}
-static int
-mpsc_shared_drv_remove(struct platform_device *dev)
+static int mpsc_shared_drv_remove(struct platform_device *dev)
{
int rc = -ENODEV;
@@ -1869,7 +1775,7 @@ static struct platform_driver mpsc_shared_driver = {
.probe = mpsc_shared_drv_probe,
.remove = mpsc_shared_drv_remove,
.driver = {
- .name = MPSC_SHARED_NAME,
+ .name = MPSC_SHARED_NAME,
},
};
@@ -1881,55 +1787,51 @@ static struct platform_driver mpsc_shared_driver = {
******************************************************************************
*/
static struct uart_driver mpsc_reg = {
- .owner = THIS_MODULE,
- .driver_name = MPSC_DRIVER_NAME,
- .dev_name = MPSC_DEV_NAME,
- .major = MPSC_MAJOR,
- .minor = MPSC_MINOR_START,
- .nr = MPSC_NUM_CTLRS,
- .cons = MPSC_CONSOLE,
+ .owner = THIS_MODULE,
+ .driver_name = MPSC_DRIVER_NAME,
+ .dev_name = MPSC_DEV_NAME,
+ .major = MPSC_MAJOR,
+ .minor = MPSC_MINOR_START,
+ .nr = MPSC_NUM_CTLRS,
+ .cons = MPSC_CONSOLE,
};
-static int
-mpsc_drv_map_regs(struct mpsc_port_info *pi, struct platform_device *pd)
+static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
+ struct platform_device *pd)
{
struct resource *r;
- if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER)) &&
- request_mem_region(r->start, MPSC_REG_BLOCK_SIZE, "mpsc_regs")){
-
+ if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
+ && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
+ "mpsc_regs")) {
pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
pi->mpsc_base_p = r->start;
- }
- else {
+ } else {
mpsc_resource_err("MPSC base");
- return -ENOMEM;
+ goto err;
}
if ((r = platform_get_resource(pd, IORESOURCE_MEM,
- MPSC_SDMA_BASE_ORDER)) && request_mem_region(r->start,
- MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
-
+ MPSC_SDMA_BASE_ORDER))
+ && request_mem_region(r->start,
+ MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
pi->sdma_base_p = r->start;
- }
- else {
+ } else {
mpsc_resource_err("SDMA base");
if (pi->mpsc_base) {
iounmap(pi->mpsc_base);
pi->mpsc_base = NULL;
}
- return -ENOMEM;
+ goto err;
}
if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
- && request_mem_region(r->start, MPSC_BRG_REG_BLOCK_SIZE,
- "brg_regs")) {
-
+ && request_mem_region(r->start,
+ MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
pi->brg_base_p = r->start;
- }
- else {
+ } else {
mpsc_resource_err("BRG base");
if (pi->mpsc_base) {
iounmap(pi->mpsc_base);
@@ -1939,14 +1841,15 @@ mpsc_drv_map_regs(struct mpsc_port_info *pi, struct platform_device *pd)
iounmap(pi->sdma_base);
pi->sdma_base = NULL;
}
- return -ENOMEM;
+ goto err;
}
-
return 0;
+
+err:
+ return -ENOMEM;
}
-static void
-mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
+static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
{
if (!pi->mpsc_base) {
iounmap(pi->mpsc_base);
@@ -1968,13 +1871,10 @@ mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
pi->mpsc_base_p = 0;
pi->sdma_base_p = 0;
pi->brg_base_p = 0;
-
- return;
}
-static void
-mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
- struct platform_device *pd, int num)
+static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
+ struct platform_device *pd, int num)
{
struct mpsc_pdata *pdata;
@@ -2009,12 +1909,9 @@ mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
pi->shared_regs = &mpsc_shared_regs;
pi->port.irq = platform_get_irq(pd, 0);
-
- return;
}
-static int
-mpsc_drv_probe(struct platform_device *dev)
+static int mpsc_drv_probe(struct platform_device *dev)
{
struct mpsc_port_info *pi;
int rc = -ENODEV;
@@ -2030,47 +1927,46 @@ mpsc_drv_probe(struct platform_device *dev)
if (!(rc = mpsc_make_ready(pi))) {
spin_lock_init(&pi->tx_lock);
if (!(rc = uart_add_one_port(&mpsc_reg,
- &pi->port)))
+ &pi->port))) {
rc = 0;
- else {
- mpsc_release_port(
- (struct uart_port *)pi);
+ } else {
+ mpsc_release_port((struct uart_port *)
+ pi);
mpsc_drv_unmap_regs(pi);
}
- }
- else
+ } else {
mpsc_drv_unmap_regs(pi);
+ }
}
}
return rc;
}
-static int
-mpsc_drv_remove(struct platform_device *dev)
+static int mpsc_drv_remove(struct platform_device *dev)
{
pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
if (dev->id < MPSC_NUM_CTLRS) {
uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
- mpsc_release_port((struct uart_port *)&mpsc_ports[dev->id].port);
+ mpsc_release_port((struct uart_port *)
+ &mpsc_ports[dev->id].port);
mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
return 0;
- }
- else
+ } else {
return -ENODEV;
+ }
}
static struct platform_driver mpsc_driver = {
.probe = mpsc_drv_probe,
.remove = mpsc_drv_remove,
.driver = {
- .name = MPSC_CTLR_NAME,
+ .name = MPSC_CTLR_NAME,
},
};
-static int __init
-mpsc_drv_init(void)
+static int __init mpsc_drv_init(void)
{
int rc;
@@ -2085,24 +1981,21 @@ mpsc_drv_init(void)
platform_driver_unregister(&mpsc_shared_driver);
uart_unregister_driver(&mpsc_reg);
}
- }
- else
+ } else {
uart_unregister_driver(&mpsc_reg);
+ }
}
return rc;
-
}
-static void __exit
-mpsc_drv_exit(void)
+static void __exit mpsc_drv_exit(void)
{
platform_driver_unregister(&mpsc_driver);
platform_driver_unregister(&mpsc_shared_driver);
uart_unregister_driver(&mpsc_reg);
memset(mpsc_ports, 0, sizeof(mpsc_ports));
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
- return;
}
module_init(mpsc_drv_init);
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 0fa9f6761763..794bd0f50d73 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -88,6 +88,16 @@ MODULE_LICENSE("GPL");
#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+#define PMACZILOG_MAJOR TTY_MAJOR
+#define PMACZILOG_MINOR 64
+#define PMACZILOG_NAME "ttyS"
+#else
+#define PMACZILOG_MAJOR 204
+#define PMACZILOG_MINOR 192
+#define PMACZILOG_NAME "ttyPZ"
+#endif
+
/*
* For the sake of early serial console, we can do a pre-probe
@@ -99,9 +109,10 @@ static DEFINE_MUTEX(pmz_irq_mutex);
static struct uart_driver pmz_uart_reg = {
.owner = THIS_MODULE,
- .driver_name = "ttyS",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
+ .driver_name = PMACZILOG_NAME,
+ .dev_name = PMACZILOG_NAME,
+ .major = PMACZILOG_MAJOR,
+ .minor = PMACZILOG_MINOR,
};
@@ -1587,7 +1598,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
return 0;
- pmz_debug("suspend, switching to state %d\n", pm_state);
+ pmz_debug("suspend, switching to state %d\n", pm_state.event);
state = pmz_uart_reg.state + uap->port.line;
@@ -1778,7 +1789,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
static int __init pmz_console_setup(struct console *co, char *options);
static struct console pmz_console = {
- .name = "ttyS",
+ .name = PMACZILOG_NAME,
.write = pmz_console_write,
.device = uart_console_device,
.setup = pmz_console_setup,
@@ -1802,7 +1813,6 @@ static int __init pmz_register(void)
pmz_uart_reg.nr = pmz_ports_count;
pmz_uart_reg.cons = PMACZILOG_CONSOLE;
- pmz_uart_reg.minor = 64;
/*
* Register this driver with the serial core
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 10bc0209cd66..3f26c4b2f322 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -78,7 +78,7 @@
#include <asm/hardware.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
/* structures */
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
index 1d9d7285172a..2d6c08b3dbcf 100644
--- a/drivers/serial/sb1250-duart.c
+++ b/drivers/serial/sb1250-duart.c
@@ -25,6 +25,7 @@
#define SUPPORT_SYSRQ
#endif
+#include <linux/compiler.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -57,6 +58,12 @@
#define SBD_CTRLREGS(line) A_BCM1480_DUART_CTRLREG((line), 0)
#define SBD_INT(line) (K_BCM1480_INT_UART_0 + (line))
+#define DUART_CHANREG_SPACING BCM1480_DUART_CHANREG_SPACING
+
+#define R_DUART_IMRREG(line) R_BCM1480_DUART_IMRREG(line)
+#define R_DUART_INCHREG(line) R_BCM1480_DUART_INCHREG(line)
+#define R_DUART_ISRREG(line) R_BCM1480_DUART_ISRREG(line)
+
#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
@@ -103,8 +110,6 @@ struct sbd_duart {
static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
-#define __unused __attribute__((__unused__))
-
/*
* Reading and writing SB1250 DUART registers.
@@ -204,12 +209,12 @@ static int sbd_receive_drain(struct sbd_port *sport)
return loops;
}
-static int __unused sbd_transmit_ready(struct sbd_port *sport)
+static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport)
{
return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
}
-static int __unused sbd_transmit_drain(struct sbd_port *sport)
+static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
{
int loops = 10000;
@@ -664,7 +669,7 @@ static void sbd_release_port(struct uart_port *uport)
static int sbd_map_port(struct uart_port *uport)
{
- static const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
+ const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
struct sbd_port *sport = to_sport(uport);
struct sbd_duart *duart = sport->duart;
@@ -691,8 +696,7 @@ static int sbd_map_port(struct uart_port *uport)
static int sbd_request_port(struct uart_port *uport)
{
- static const char *err = KERN_ERR
- "sbd: Unable to reserve MMIO resource\n";
+ const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
struct sbd_duart *duart = to_sport(uport)->duart;
int map_guard;
int ret = 0;
@@ -755,7 +759,7 @@ static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser)
}
-static struct uart_ops sbd_ops = {
+static const struct uart_ops sbd_ops = {
.tx_empty = sbd_tx_empty,
.set_mctrl = sbd_set_mctrl,
.get_mctrl = sbd_get_mctrl,
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 9c57486c2e7f..a055f58f342f 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -626,7 +626,7 @@ static int uart_get_info(struct uart_state *state,
tmp.hub6 = port->hub6;
tmp.io_type = port->iotype;
tmp.iomem_reg_shift = port->regshift;
- tmp.iomem_base = (void *)port->mapbase;
+ tmp.iomem_base = (void *)(unsigned long)port->mapbase;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
@@ -1146,11 +1146,14 @@ static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/*
* These are the bits that are used to setup various
- * flags in the low level driver.
+ * flags in the low level driver. We can ignore the Bfoo
+ * bits in c_cflag; c_[io]speed will always be set
+ * appropriately by set_termios() in tty_ioctl.c
*/
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
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)
return;
@@ -1666,10 +1669,11 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
return 0;
mmio = port->iotype >= UPIO_MEM;
- ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d",
+ ret = sprintf(buf, "%d: uart:%s %s%08llX irq:%d",
port->line, uart_type(port),
mmio ? "mmio:0x" : "port:",
- mmio ? port->mapbase : (unsigned long) port->iobase,
+ mmio ? (unsigned long long)port->mapbase
+ : (unsigned long long) port->iobase,
port->irq);
if (port->type == PORT_UNKNOWN) {
@@ -2069,7 +2073,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_TSI:
case UPIO_DWAPB:
snprintf(address, sizeof(address),
- "MMIO 0x%lx", port->mapbase);
+ "MMIO 0x%llx", (unsigned long long)port->mapbase);
break;
default:
strlcpy(address, "*unknown*", sizeof(address));
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index a0ea43598515..7c8d78fbbbfb 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -943,6 +943,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+ PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
/* too generic */
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
/* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 1deb5764326d..0930e2a85514 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -37,7 +37,7 @@
#include <asm/io.h>
-static char *serial_version = "1.09";
+static char *serial_version = "1.10";
static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256
@@ -436,8 +436,10 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned int ret;
- ret = ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS)
- | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS);
+ /* no modem control lines */
+ ret = TIOCM_CAR | TIOCM_DSR;
+ ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
+ ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
return ret;
}
@@ -557,6 +559,12 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags;
unsigned int baud, quot;
+ /*
+ * We don't support modem control lines.
+ */
+ termios->c_cflag &= ~(HUPCL | CMSPAR);
+ termios->c_cflag |= CLOCAL;
+
cval = sio_in(up, TXX9_SILCR);
/* byte size and parity */
cval &= ~TXX9_SILCR_UMODE_MASK;
@@ -1043,8 +1051,9 @@ static int __devinit serial_txx9_probe(struct platform_device *dev)
ret = serial_txx9_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%x MEM%lx IRQ%d): %d\n", i,
- p->iobase, p->mapbase, p->irq, ret);
+ "(IO%x MEM%llx IRQ%d): %d\n", i,
+ p->iobase, (unsigned long long)p->mapbase,
+ p->irq, ret);
}
}
return 0;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 672cd1042539..053fca41b08a 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -12,6 +12,7 @@
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SecureEdge. David McCullough (2002)
* Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+ * Removed SH7300 support (Jul 2007).
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -289,13 +290,7 @@ static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
#endif
#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
-/* SH7300 doesn't use RTS/CTS */
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
-{
- sci_out(port, SCFCR, 0);
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
{
unsigned int fcr_val = 0;
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 247fb66bf0f4..cf75466ebf57 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -9,6 +9,7 @@
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
* Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
+ * Removed SH7300 support (Jul 2007).
*/
#include <linux/serial_core.h>
#include <asm/io.h>
@@ -23,13 +24,10 @@
#endif
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
-# define SCSPTR 0xffffff7c /* 8 bit */
-# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define SCI_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
- defined(CONFIG_CPU_SUBTYPE_SH7709) || \
- defined(CONFIG_CPU_SUBTYPE_SH7706)
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
@@ -73,11 +71,6 @@
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
-# define SCPCR 0xA4050116 /* 16 bit SCIF */
-# define SCPDR 0xA4050136 /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
# define SCI_NPORTS 2
@@ -86,12 +79,6 @@
# define PBCR 0xa4050102
# define SCSCR_INIT(port) 0x3B
# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
-# define SCPDR 0xA4050138 /* 16 bit SCIF */
-# define SCSPTR2 SCPDR
-# define SCIF_ORER 0x0001 /* overrun error bit */
-# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
# define SCSPTR0 0xffe00010 /* 16 bit SCIF */
# define SCSPTR1 0xffe10010 /* 16 bit SCIF */
@@ -230,7 +217,7 @@
#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCIF_ORER 0x0200
#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
#define SCIF_RFDC_MASK 0x007f
@@ -259,7 +246,7 @@
# define SCxSR_ERRORS(port) SCIF_ERRORS
# define SCxSR_RDxF(port) SCIF_RDF
# define SCxSR_TDxE(port) SCIF_TDFE
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
# define SCxSR_ORER(port) SCIF_ORER
#else
# define SCxSR_ORER(port) 0x0000
@@ -267,13 +254,13 @@
# define SCxSR_FER(port) SCIF_FER
# define SCxSR_PER(port) SCIF_PER
# define SCxSR_BRK(port) SCIF_BRK
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
# define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc)
# define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73)
# define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf)
# define SCxSR_BREAK_CLEAR(port) (sci_in(port,SCxSR)&0xffe3)
#else
-/* SH7705 can also use this, clearing is same between 7705 and 7709 and 7300 */
+/* SH7705 can also use this, clearing is same between 7705 and 7709 */
# define SCxSR_RDxF_CLEAR(port) 0x00fc
# define SCxSR_ERROR_CLEAR(port) 0x0073
# define SCxSR_TDxE_CLEAR(port) 0x00df
@@ -375,8 +362,7 @@
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -402,8 +388,7 @@
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
@@ -485,16 +470,10 @@ static const struct __attribute__((packed)) {
};
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xfffffe80)
- return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
- defined(CONFIG_CPU_SUBTYPE_SH7709) || \
- defined(CONFIG_CPU_SUBTYPE_SH7706)
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
@@ -562,18 +541,6 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xa4430000)
- return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
- return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
-}
#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -721,8 +688,7 @@ static inline int sci_rxd_in(struct uart_port *port)
* -- Mitch Davis - 15 Jul 2000
*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
defined(CONFIG_CPU_SUBTYPE_SH7785)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index b45ba5392dd3..70a09a3d5af0 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -16,9 +16,10 @@
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/serial_core.h>
#include <linux/init.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
#include "suncore.h"
@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor);
-void
-sunserial_console_termios(struct console *con)
+int sunserial_console_match(struct console *con, struct device_node *dp,
+ struct uart_driver *drv, int line)
{
- char mode[16], buf[16], *s;
- char mode_prop[] = "ttyX-mode";
- char cd_prop[] = "ttyX-ignore-cd";
- char dtr_prop[] = "ttyX-rts-dtr-off";
- char *ssp_console_modes_prop = "ssp-console-modes";
- int baud, bits, stop, cflag;
- char parity;
- int carrier = 0;
- int rtsdtr = 1;
- int topnd, nd;
-
- if (!serial_console)
- return;
-
- switch (serial_console) {
- case PROMDEV_OTTYA:
- mode_prop[3] = 'a';
- cd_prop[3] = 'a';
- dtr_prop[3] = 'a';
- break;
-
- case PROMDEV_OTTYB:
- mode_prop[3] = 'b';
- cd_prop[3] = 'b';
- dtr_prop[3] = 'b';
- break;
-
- case PROMDEV_ORSC:
-
- nd = prom_pathtoinode("rsc");
- if (!nd) {
- strcpy(mode, "115200,8,n,1,-");
- goto no_options;
- }
+ int off;
- if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
- strcpy(mode, "115200,8,n,1,-");
- goto no_options;
- }
+ if (!con || of_console_device != dp)
+ return 0;
- memset(mode, 0, sizeof(mode));
- prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
- goto no_options;
+ off = 0;
+ if (of_console_options &&
+ *of_console_options == 'b')
+ off = 1;
- default:
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
+ if ((line & 1) != off)
+ return 0;
- topnd = prom_getchild(prom_root_node);
- nd = prom_searchsiblings(topnd, "options");
- if (!nd) {
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
-
- if (!prom_node_has_property(nd, mode_prop)) {
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
+ con->index = line;
+ drv->cons = con;
+ add_preferred_console(con->name, line, NULL);
- memset(mode, 0, sizeof(mode));
- prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
- if (prom_node_has_property(nd, cd_prop)) {
- memset(buf, 0, sizeof(buf));
- prom_getstring(nd, cd_prop, buf, sizeof(buf));
- if (!strcmp(buf, "false"))
- carrier = 1;
-
- /* XXX: this is unused below. */
- }
+ return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
- if (prom_node_has_property(nd, dtr_prop)) {
- memset(buf, 0, sizeof(buf));
- prom_getstring(nd, dtr_prop, buf, sizeof(buf));
- if (!strcmp(buf, "false"))
- rtsdtr = 0;
+void
+sunserial_console_termios(struct console *con)
+{
+ struct device_node *dp;
+ const char *od, *mode, *s;
+ char mode_prop[] = "ttyX-mode";
+ int baud, bits, stop, cflag;
+ char parity;
- /* XXX: this is unused below. */
+ dp = of_find_node_by_path("/options");
+ od = of_get_property(dp, "output-device", NULL);
+ if (!strcmp(od, "rsc")) {
+ mode = of_get_property(of_console_device,
+ "ssp-console-modes", NULL);
+ if (!mode)
+ mode = "115200,8,n,1,-";
+ } else {
+ char c;
+
+ c = 'a';
+ if (of_console_options)
+ c = *of_console_options;
+
+ mode_prop[3] = c;
+
+ mode = of_get_property(dp, mode_prop, NULL);
+ if (!mode)
+ mode = "9600,8,n,1,-";
}
-no_options:
cflag = CREAD | HUPCL | CLOCAL;
s = mode;
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
index 513916a8ce37..829d7d65d6db 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/serial/suncore.h
@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor;
+extern int sunserial_console_match(struct console *, struct device_node *,
+ struct uart_driver *, int);
extern void sunserial_console_termios(struct console *);
#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index d82be42ff29a..8ff900b09811 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -520,16 +520,6 @@ static struct console sunhv_console = {
.data = &sunhv_reg,
};
-static inline struct console *SUNHV_CONSOLE(void)
-{
- if (con_is_present())
- return NULL;
-
- sunhv_console.index = 0;
-
- return &sunhv_console;
-}
-
static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{
struct uart_port *port;
@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
- sunhv_reg.cons = SUNHV_CONSOLE();
+ sunserial_console_match(&sunhv_console, op->node,
+ &sunhv_reg, port->line);
err = uart_add_one_port(&sunhv_reg, port);
if (err)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 8a0f9e4408d4..ff610c23314b 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -38,7 +38,7 @@
#include <asm/prom.h>
#include <asm/of_device.h>
-#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
@@ -58,6 +58,7 @@ struct uart_sunsab_port {
unsigned char interrupt_mask1;/* ISR1 masking */
unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */
unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */
+ unsigned int gis_shift;
int type; /* SAB82532 version */
/* Setting configuration bits while the transmitter is active
@@ -305,13 +306,15 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
struct tty_struct *tty;
union sab82532_irq_status status;
unsigned long flags;
+ unsigned char gis;
spin_lock_irqsave(&up->port.lock, flags);
status.stat = 0;
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA0)
+ gis = readb(&up->regs->r.gis) >> up->gis_shift;
+ if (gis & 1)
status.sreg.isr0 = readb(&up->regs->r.isr0);
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1)
+ if (gis & 2)
status.sreg.isr1 = readb(&up->regs->r.isr1);
tty = NULL;
@@ -327,35 +330,6 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
transmit_chars(up, &status);
}
- spin_unlock(&up->port.lock);
-
- if (tty)
- tty_flip_buffer_push(tty);
-
- up++;
-
- spin_lock(&up->port.lock);
-
- status.stat = 0;
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB0)
- status.sreg.isr0 = readb(&up->regs->r.isr0);
- if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1)
- status.sreg.isr1 = readb(&up->regs->r.isr1);
-
- tty = NULL;
- if (status.stat) {
- if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
- SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
- (status.sreg.isr1 & SAB82532_ISR1_BRK))
-
- tty = receive_chars(up, &status);
- if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
- (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
- check_status(up, &status);
- if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
- transmit_chars(up, &status);
- }
-
spin_unlock_irqrestore(&up->port.lock, flags);
if (tty)
@@ -539,6 +513,10 @@ static int sunsab_startup(struct uart_port *port)
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags;
unsigned char tmp;
+ int err = request_irq(up->port.irq, sunsab_interrupt,
+ IRQF_SHARED, "sab", up);
+ if (err)
+ return err;
spin_lock_irqsave(&up->port.lock, flags);
@@ -641,6 +619,7 @@ static void sunsab_shutdown(struct uart_port *port)
#endif
spin_unlock_irqrestore(&up->port.lock, flags);
+ free_irq(up->port.irq, up);
}
/*
@@ -968,22 +947,6 @@ static struct console sunsab_console = {
static inline struct console *SUNSAB_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < num_channels; i++) {
- int this_minor = sunsab_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == num_channels)
- return NULL;
-
- sunsab_console.index = i;
-
return &sunsab_console;
}
#else
@@ -1024,9 +987,11 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
if ((up->port.line & 0x1) == 0) {
up->pvr_dsr_bit = (1 << 0);
up->pvr_dtr_bit = (1 << 1);
+ up->gis_shift = 2;
} else {
up->pvr_dsr_bit = (1 << 3);
up->pvr_dtr_bit = (1 << 2);
+ up->gis_shift = 0;
}
up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
writeb(up->cached_pvr, &up->regs->w.pvr);
@@ -1039,19 +1004,6 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
- if (!(up->port.line & 0x01)) {
- int err;
-
- err = request_irq(up->port.irq, sunsab_interrupt,
- IRQF_SHARED, "sab", up);
- if (err) {
- of_iounmap(&op->resource[0],
- up->port.membase,
- sizeof(union sab82532_async_regs));
- return err;
- }
- }
-
return 0;
}
@@ -1067,47 +1019,60 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
0,
(inst * 2) + 0);
if (err)
- return err;
+ goto out;
err = sunsab_init_one(&up[1], op,
sizeof(union sab82532_async_regs),
(inst * 2) + 1);
- if (err) {
- of_iounmap(&op->resource[0],
- up[0].port.membase,
- sizeof(union sab82532_async_regs));
- free_irq(up[0].port.irq, &up[0]);
- return err;
- }
+ if (err)
+ goto out1;
+
+ sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+ &sunsab_reg, up[0].port.line);
- uart_add_one_port(&sunsab_reg, &up[0].port);
- uart_add_one_port(&sunsab_reg, &up[1].port);
+ sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+ &sunsab_reg, up[1].port.line);
+
+ err = uart_add_one_port(&sunsab_reg, &up[0].port);
+ if (err)
+ goto out2;
+
+ err = uart_add_one_port(&sunsab_reg, &up[1].port);
+ if (err)
+ goto out3;
dev_set_drvdata(&op->dev, &up[0]);
inst++;
return 0;
-}
-static void __devexit sab_remove_one(struct uart_sunsab_port *up)
-{
- struct of_device *op = to_of_device(up->port.dev);
-
- uart_remove_one_port(&sunsab_reg, &up->port);
- if (!(up->port.line & 1))
- free_irq(up->port.irq, up);
+out3:
+ uart_remove_one_port(&sunsab_reg, &up[0].port);
+out2:
+ of_iounmap(&op->resource[0],
+ up[1].port.membase,
+ sizeof(union sab82532_async_regs));
+out1:
of_iounmap(&op->resource[0],
- up->port.membase,
+ up[0].port.membase,
sizeof(union sab82532_async_regs));
+out:
+ return err;
}
static int __devexit sab_remove(struct of_device *op)
{
struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
- sab_remove_one(&up[0]);
- sab_remove_one(&up[1]);
+ uart_remove_one_port(&sunsab_reg, &up[1].port);
+ uart_remove_one_port(&sunsab_reg, &up[0].port);
+ of_iounmap(&op->resource[0],
+ up[1].port.membase,
+ sizeof(union sab82532_async_regs));
+ of_iounmap(&op->resource[0],
+ up[0].port.membase,
+ sizeof(union sab82532_async_regs));
dev_set_drvdata(&op->dev, NULL);
@@ -1154,6 +1119,7 @@ static int __init sunsab_init(void)
sunsab_reg.minor = sunserial_current_minor;
sunsab_reg.nr = num_channels;
+ sunsab_reg.cons = SUNSAB_CONSOLE();
err = uart_register_driver(&sunsab_reg);
if (err) {
@@ -1164,7 +1130,6 @@ static int __init sunsab_init(void)
}
sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
- sunsab_reg.cons = SUNSAB_CONSOLE();
sunserial_current_minor += num_channels;
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 26d720baf88c..e074943feff5 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1198,10 +1198,11 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up)
if (up->port.type == PORT_UNKNOWN)
return -ENODEV;
- printk("%s: %s port at %lx, irq %u\n",
+ printk("%s: %s port at %llx, irq %u\n",
to_of_device(up->port.dev)->node->full_name,
(up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
- up->port.mapbase, up->port.irq);
+ (unsigned long long) up->port.mapbase,
+ up->port.irq);
#ifdef CONFIG_SERIO
serio = &up->serio;
@@ -1371,28 +1372,12 @@ static struct console sunsu_console = {
* Register console.
*/
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < num_uart; i++) {
- int this_minor = sunsu_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == num_uart)
- return NULL;
-
- sunsu_console.index = i;
-
return &sunsu_console;
}
#else
-#define SUNSU_CONSOLE(num_uart) (NULL)
+#define SUNSU_CONSOLE() (NULL)
#define sunsu_serial_console_init() do { } while (0)
#endif
@@ -1482,6 +1467,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
up->port.ops = &sunsu_pops;
+ sunserial_console_match(SUNSU_CONSOLE(), dp,
+ &sunsu_reg, up->port.line);
err = uart_add_one_port(&sunsu_reg, &up->port);
if (err)
goto out_unmap;
@@ -1572,7 +1559,6 @@ static int __init sunsu_init(void)
return err;
sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
sunserial_current_minor += num_uart;
- sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
}
err = of_register_driver(&su_driver, &of_bus_type);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 0a3e10a4a35d..283bef0d24cb 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = {
static inline struct console *SUNZILOG_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- int this_minor = sunzilog_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == NUM_CHANNELS)
- return NULL;
-
- sunzilog_console_ops.index = i;
- sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
return &sunzilog_console_ops;
}
@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
sunzilog_init_hw(&up[1]);
if (!keyboard_mouse) {
+ if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+ &sunzilog_reg, up[0].port.line))
+ up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) {
of_iounmap(&op->resource[0],
rp, sizeof(struct zilog_layout));
return err;
}
+ if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+ &sunzilog_reg, up[1].port.line))
+ up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[1].port);
if (err) {
uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1442,14 +1431,16 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
return err;
}
} else {
- printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+ printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
"is a %s\n",
- op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
- sunzilog_type (&up[0].port));
- printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+ op->dev.bus_id,
+ (unsigned long long) up[0].port.mapbase,
+ op->irqs[0], sunzilog_type(&up[0].port));
+ printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
"is a %s\n",
- op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
- sunzilog_type (&up[1].port));
+ op->dev.bus_id,
+ (unsigned long long) up[1].port.mapbase,
+ op->irqs[0], sunzilog_type(&up[1].port));
}
dev_set_drvdata(&op->dev, &up[0]);
@@ -1531,7 +1522,6 @@ static int __init sunzilog_init(void)
goto out_free_tables;
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
- sunzilog_reg.cons = SUNZILOG_CONSOLE();
sunserial_current_minor += uart_count;
}
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index f5051cf1a0c8..dfef83f14960 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -1,7 +1,8 @@
/*
* uartlite.c: Serial driver for Xilinx uartlite serial controller
*
- * Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2007 Secret Lab Technologies Ltd.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
@@ -17,14 +18,23 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/io.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
+#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
#define ULITE_NR_UARTS 4
-/* For register details see datasheet:
- http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
-*/
+/* ---------------------------------------------------------------------
+ * Register definitions
+ *
+ * For register details see datasheet:
+ * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+ */
+
#define ULITE_RX 0x00
#define ULITE_TX 0x04
#define ULITE_STATUS 0x08
@@ -46,7 +56,11 @@
#define ULITE_CONTROL_IE 0x10
-static struct uart_port ports[ULITE_NR_UARTS];
+static struct uart_port ulite_ports[ULITE_NR_UARTS];
+
+/* ---------------------------------------------------------------------
+ * Core UART driver operations
+ */
static int ulite_receive(struct uart_port *port, int stat)
{
@@ -307,6 +321,10 @@ static struct uart_ops ulite_ops = {
.verify_port = ulite_verify_port
};
+/* ---------------------------------------------------------------------
+ * Console driver operations
+ */
+
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static void ulite_console_wait_tx(struct uart_port *port)
{
@@ -329,7 +347,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch)
static void ulite_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &ports[co->index];
+ struct uart_port *port = &ulite_ports[co->index];
unsigned long flags;
unsigned int ier;
int locked = 1;
@@ -355,6 +373,31 @@ static void ulite_console_write(struct console *co, const char *s,
spin_unlock_irqrestore(&port->lock, flags);
}
+#if defined(CONFIG_OF)
+static inline void __init ulite_console_of_find_device(int id)
+{
+ struct device_node *np;
+ struct resource res;
+ const unsigned int *of_id;
+ int rc;
+
+ for_each_compatible_node(np, NULL, "xilinx,uartlite") {
+ of_id = of_get_property(np, "port-number", NULL);
+ if ((!of_id) || (*of_id != id))
+ continue;
+
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc)
+ continue;
+
+ ulite_ports[id].mapbase = res.start;
+ return;
+ }
+}
+#else /* CONFIG_OF */
+static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ }
+#endif /* CONFIG_OF */
+
static int __init ulite_console_setup(struct console *co, char *options)
{
struct uart_port *port;
@@ -366,11 +409,23 @@ static int __init ulite_console_setup(struct console *co, char *options)
if (co->index < 0 || co->index >= ULITE_NR_UARTS)
return -EINVAL;
- port = &ports[co->index];
+ port = &ulite_ports[co->index];
- /* not initialized yet? */
- if (!port->membase)
+ /* Check if it is an OF device */
+ if (!port->mapbase)
+ ulite_console_of_find_device(co->index);
+
+ /* Do we have a device now? */
+ if (!port->mapbase) {
+ pr_debug("console on ttyUL%i not present\n", co->index);
return -ENODEV;
+ }
+
+ /* not initialized yet? */
+ if (!port->membase) {
+ if (ulite_request_port(port))
+ return -ENODEV;
+ }
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -381,7 +436,7 @@ static int __init ulite_console_setup(struct console *co, char *options)
static struct uart_driver ulite_uart_driver;
static struct console ulite_console = {
- .name = "ttyUL",
+ .name = ULITE_NAME,
.write = ulite_console_write,
.device = uart_console_device,
.setup = ulite_console_setup,
@@ -403,7 +458,7 @@ console_initcall(ulite_console_init);
static struct uart_driver ulite_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "uartlite",
- .dev_name = "ttyUL",
+ .dev_name = ULITE_NAME,
.major = ULITE_MAJOR,
.minor = ULITE_MINOR,
.nr = ULITE_NR_UARTS,
@@ -412,59 +467,111 @@ static struct uart_driver ulite_uart_driver = {
#endif
};
-static int __devinit ulite_probe(struct platform_device *pdev)
+/* ---------------------------------------------------------------------
+ * Port assignment functions (mapping devices to uart_port structures)
+ */
+
+/** ulite_assign: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ * @id: requested id number. Pass -1 for automatic port assignment
+ * @base: base address of uartlite registers
+ * @irq: irq number for uartlite
+ *
+ * Returns: 0 on success, <0 otherwise
+ */
+static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
{
- struct resource *res, *res2;
struct uart_port *port;
+ int rc;
- if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
+ /* if id = -1; then scan for a free id and use that */
+ if (id < 0) {
+ for (id = 0; id < ULITE_NR_UARTS; id++)
+ if (ulite_ports[id].mapbase == 0)
+ break;
+ }
+ if (id < 0 || id >= ULITE_NR_UARTS) {
+ dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
return -EINVAL;
+ }
- if (ports[pdev->id].membase)
+ if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
+ dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+ ULITE_NAME, id);
return -EBUSY;
+ }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
+ port = &ulite_ports[id];
- res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res2)
- return -ENODEV;
+ spin_lock_init(&port->lock);
+ port->fifosize = 16;
+ port->regshift = 2;
+ port->iotype = UPIO_MEM;
+ port->iobase = 1; /* mark port in use */
+ port->mapbase = base;
+ port->membase = NULL;
+ port->ops = &ulite_ops;
+ port->irq = irq;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->dev = dev;
+ port->type = PORT_UNKNOWN;
+ port->line = id;
+
+ dev_set_drvdata(dev, port);
+
+ /* Register the port */
+ rc = uart_add_one_port(&ulite_uart_driver, port);
+ if (rc) {
+ dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
+ port->mapbase = 0;
+ dev_set_drvdata(dev, NULL);
+ return rc;
+ }
- port = &ports[pdev->id];
+ return 0;
+}
- port->fifosize = 16;
- port->regshift = 2;
- port->iotype = UPIO_MEM;
- port->iobase = 1; /* mark port in use */
- port->mapbase = res->start;
- port->membase = NULL;
- port->ops = &ulite_ops;
- port->irq = res2->start;
- port->flags = UPF_BOOT_AUTOCONF;
- port->dev = &pdev->dev;
- port->type = PORT_UNKNOWN;
- port->line = pdev->id;
+/** ulite_release: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ */
+static int __devinit ulite_release(struct device *dev)
+{
+ struct uart_port *port = dev_get_drvdata(dev);
+ int rc = 0;
- uart_add_one_port(&ulite_uart_driver, port);
- platform_set_drvdata(pdev, port);
+ if (port) {
+ rc = uart_remove_one_port(&ulite_uart_driver, port);
+ dev_set_drvdata(dev, NULL);
+ port->mapbase = 0;
+ }
- return 0;
+ return rc;
}
-static int ulite_remove(struct platform_device *pdev)
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+
+static int __devinit ulite_probe(struct platform_device *pdev)
{
- struct uart_port *port = platform_get_drvdata(pdev);
+ struct resource *res, *res2;
- platform_set_drvdata(pdev, NULL);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
- if (port)
- uart_remove_one_port(&ulite_uart_driver, port);
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
- /* mark port as free */
- port->membase = NULL;
+ return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
+}
- return 0;
+static int ulite_remove(struct platform_device *pdev)
+{
+ return ulite_release(&pdev->dev);
}
static struct platform_driver ulite_platform_driver = {
@@ -476,24 +583,109 @@ static struct platform_driver ulite_platform_driver = {
},
};
+/* ---------------------------------------------------------------------
+ * OF bus bindings
+ */
+#if defined(CONFIG_OF)
+static int __devinit
+ulite_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ const unsigned int *id;
+ int irq, rc;
+
+ dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match);
+
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+
+ irq = irq_of_parse_and_map(op->node, 0);
+
+ id = of_get_property(op->node, "port-number", NULL);
+
+ return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq);
+}
+
+static int __devexit ulite_of_remove(struct of_device *op)
+{
+ return ulite_release(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit ulite_of_match[] = {
+ { .type = "serial", .compatible = "xilinx,uartlite", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ulite_of_match);
+
+static struct of_platform_driver ulite_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "uartlite",
+ .match_table = ulite_of_match,
+ .probe = ulite_of_probe,
+ .remove = __devexit_p(ulite_of_remove),
+ .driver = {
+ .name = "uartlite",
+ },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ulite_of_register(void)
+{
+ pr_debug("uartlite: calling of_register_platform_driver()\n");
+ return of_register_platform_driver(&ulite_of_driver);
+}
+
+static inline void __exit ulite_of_unregister(void)
+{
+ of_unregister_platform_driver(&ulite_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init ulite_of_register(void) { return 0; }
+static inline void __exit ulite_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
+ * Module setup/teardown
+ */
+
int __init ulite_init(void)
{
int ret;
+ pr_debug("uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret)
- return ret;
+ goto err_uart;
+ ret = ulite_of_register();
+ if (ret)
+ goto err_of;
+
+ pr_debug("uartlite: calling platform_driver_register()\n");
ret = platform_driver_register(&ulite_platform_driver);
if (ret)
- uart_unregister_driver(&ulite_uart_driver);
+ goto err_plat;
+ return 0;
+
+err_plat:
+ ulite_of_unregister();
+err_of:
+ uart_unregister_driver(&ulite_uart_driver);
+err_uart:
+ printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
return ret;
}
void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
+ ulite_of_unregister();
uart_unregister_driver(&ulite_uart_driver);
}
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 85309acb75f6..6fd51b0022ca 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -65,7 +65,9 @@ static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
},
};
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
static uint8_t lsr_break_flag[SIU_PORTS_MAX];
+#endif
#define siu_read(port, offset) readb((port)->membase + (offset))
#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
@@ -782,7 +784,7 @@ static void siu_console_write(struct console *con, const char *s, unsigned count
siu_write(port, UART_IER, ier);
}
-static int siu_console_setup(struct console *con, char *options)
+static int __init siu_console_setup(struct console *con, char *options)
{
struct uart_port *port;
int baud = 9600;
@@ -800,7 +802,8 @@ static int siu_console_setup(struct console *con, char *options)
port->membase = ioremap(port->mapbase, siu_port_size(port));
}
- vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
+ if (port->type == PORT_VR41XX_SIU)
+ vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
if (options != NULL)
uart_parse_options(options, &baud, &parity, &bits, &flow);
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
new file mode 100644
index 000000000000..65f1294fd27b
--- /dev/null
+++ b/drivers/serial/zs.c
@@ -0,0 +1,1287 @@
+/*
+ * zs.c: Serial port driver for IOASIC DECstations.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ *
+ * DECstation changes
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4 signal SCC
+ * 2 1 TxD <- A.TxD
+ * 3 4 RxD -> A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal SCC
+ * 2 2 TxD <- B.TxD
+ * 3 5 RxD -> B.RxD
+ * 4 RTS <- ~A.RTS
+ * 5 CTS -> ~B.CTS
+ * 6 6 DSR -> ~A.SYNC
+ * 8 CD -> ~B.DCD
+ * 12 DSRS(DCE) -> ~A.CTS (*)
+ * 15 TxC -> B.TxC
+ * 17 RxC -> B.RxC
+ * 20 1 DTR <- ~A.DTR
+ * 22 RI -> ~A.DCD
+ * 23 DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ * is shared with DSRS(DTE) at pin 23.
+ *
+ * As you can immediately notice the wiring of the RTS, DTR and DSR signals
+ * is a bit odd. This makes the handling of port B unnecessarily
+ * complicated and prevents the use of some automatic modes of operation.
+ */
+
+#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bug.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irqflags.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/system.h>
+
+#include "zs.h"
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+static char zs_version[] __initdata = "0.10";
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on ZS_NUM_SCCS, so we could support any number of
+ * Z85C30s, but for now...
+ */
+#define ZS_NUM_SCCS 2 /* Max # of ZS chips supported. */
+#define ZS_NUM_CHAN 2 /* 2 channels per chip. */
+#define ZS_CHAN_A 0 /* Index of the channel A. */
+#define ZS_CHAN_B 1 /* Index of the channel B. */
+#define ZS_CHAN_IO_SIZE 8 /* IOMEM space size. */
+#define ZS_CHAN_IO_STRIDE 4 /* Register alignment. */
+#define ZS_CHAN_IO_OFFSET 1 /* The SCC resides on the high byte
+ of the 16-bit IOBUS. */
+#define ZS_CLOCK 7372800 /* Z85C30 PCLK input clock rate. */
+
+#define to_zport(uport) container_of(uport, struct zs_port, port)
+
+struct zs_parms {
+ resource_size_t scc[ZS_NUM_SCCS];
+ int irq[ZS_NUM_SCCS];
+};
+
+static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+
+static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+ 0, /* write 0 */
+ PAR_SPEC, /* write 1 */
+ 0, /* write 2 */
+ 0, /* write 3 */
+ X16CLK | SB1, /* write 4 */
+ 0, /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ MIE | DLC | NV, /* write 9 */
+ NRZ, /* write 10 */
+ TCBR | RCBR, /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ BRSRC | BRENABL, /* write 14 */
+ 0, /* write 15 */
+};
+
+/*
+ * Debugging.
+ */
+#undef ZS_DEBUG_REGS
+
+
+/*
+ * Reading and writing Z85C30 registers.
+ */
+static void recovery_delay(void)
+{
+ udelay(2);
+}
+
+static u8 read_zsreg(struct zs_port *zport, int reg)
+{
+ void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+ u8 retval;
+
+ if (reg != 0) {
+ writeb(reg & 0xf, control);
+ fast_iob();
+ recovery_delay();
+ }
+ retval = readb(control);
+ recovery_delay();
+ return retval;
+}
+
+static void write_zsreg(struct zs_port *zport, int reg, u8 value)
+{
+ void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+
+ if (reg != 0) {
+ writeb(reg & 0xf, control);
+ fast_iob(); recovery_delay();
+ }
+ writeb(value, control);
+ fast_iob();
+ recovery_delay();
+ return;
+}
+
+static u8 read_zsdata(struct zs_port *zport)
+{
+ void __iomem *data = zport->port.membase +
+ ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+ u8 retval;
+
+ retval = readb(data);
+ recovery_delay();
+ return retval;
+}
+
+static void write_zsdata(struct zs_port *zport, u8 value)
+{
+ void __iomem *data = zport->port.membase +
+ ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+
+ writeb(value, data);
+ fast_iob();
+ recovery_delay();
+ return;
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump(void)
+{
+ struct zs_port *zport;
+ int i, j;
+
+ for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+ zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
+
+ if (!zport->scc)
+ continue;
+
+ for (j = 0; j < 16; j++)
+ printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
+ printk("\n");
+ for (j = 0; j < 16; j++)
+ printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
+ printk("\n\n");
+ }
+}
+#endif
+
+
+static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
+{
+ if (irq)
+ spin_lock_irq(lock);
+ else
+ spin_lock(lock);
+}
+
+static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
+{
+ if (irq)
+ spin_unlock_irq(lock);
+ else
+ spin_unlock(lock);
+}
+
+static int zs_receive_drain(struct zs_port *zport)
+{
+ int loops = 10000;
+
+ while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--)
+ read_zsdata(zport);
+ return loops;
+}
+
+static int zs_transmit_drain(struct zs_port *zport, int irq)
+{
+ struct zs_scc *scc = zport->scc;
+ int loops = 10000;
+
+ while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) {
+ zs_spin_unlock_cond_irq(&scc->zlock, irq);
+ udelay(2);
+ zs_spin_lock_cond_irq(&scc->zlock, irq);
+ }
+ return loops;
+}
+
+static int zs_line_drain(struct zs_port *zport, int irq)
+{
+ struct zs_scc *scc = zport->scc;
+ int loops = 10000;
+
+ while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) {
+ zs_spin_unlock_cond_irq(&scc->zlock, irq);
+ udelay(2);
+ zs_spin_lock_cond_irq(&scc->zlock, irq);
+ }
+ return loops;
+}
+
+
+static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
+{
+ /* Let the current transmission finish. */
+ zs_line_drain(zport, irq);
+ /* Load 'em up. */
+ write_zsreg(zport, R3, regs[3] & ~RxENABLE);
+ write_zsreg(zport, R5, regs[5] & ~TxENAB);
+ write_zsreg(zport, R4, regs[4]);
+ write_zsreg(zport, R9, regs[9]);
+ write_zsreg(zport, R1, regs[1]);
+ write_zsreg(zport, R2, regs[2]);
+ write_zsreg(zport, R10, regs[10]);
+ write_zsreg(zport, R14, regs[14] & ~BRENABL);
+ write_zsreg(zport, R11, regs[11]);
+ write_zsreg(zport, R12, regs[12]);
+ write_zsreg(zport, R13, regs[13]);
+ write_zsreg(zport, R14, regs[14]);
+ write_zsreg(zport, R15, regs[15]);
+ if (regs[3] & RxENABLE)
+ write_zsreg(zport, R3, regs[3]);
+ if (regs[5] & TxENAB)
+ write_zsreg(zport, R5, regs[5]);
+ return;
+}
+
+
+/*
+ * Status handling routines.
+ */
+
+/*
+ * zs_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static unsigned int zs_tx_empty(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ u8 status;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ status = read_zsreg(zport, R1);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ return status & ALL_SNT ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
+ struct zs_port *zport_b)
+{
+ u8 status_a, status_b;
+ unsigned int mctrl;
+
+ status_a = read_zsreg(zport_a, R0);
+ status_b = read_zsreg(zport_b, R0);
+
+ mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
+ ((status_b & DCD) ? TIOCM_CAR : 0) |
+ ((status_a & DCD) ? TIOCM_RNG : 0) |
+ ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
+
+ return mctrl;
+}
+
+static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
+{
+ struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+
+ return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
+}
+
+static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
+{
+ struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+ unsigned int mmask, mctrl, delta;
+ u8 mask_a, mask_b;
+
+ if (zport == zport_a)
+ return 0;
+
+ mask_a = zport_a->regs[15];
+ mask_b = zport->regs[15];
+
+ mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
+ ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
+ ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
+ ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
+
+ mctrl = zport->mctrl;
+ if (mmask) {
+ mctrl &= ~mmask;
+ mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
+ }
+
+ delta = mctrl ^ zport->mctrl;
+ if (delta)
+ zport->mctrl = mctrl;
+
+ return delta;
+}
+
+static unsigned int zs_get_mctrl(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned int mctrl;
+
+ spin_lock(&scc->zlock);
+ mctrl = zs_raw_get_mctrl(zport);
+ spin_unlock(&scc->zlock);
+
+ return mctrl;
+}
+
+static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+ u8 oldloop, newloop;
+
+ spin_lock(&scc->zlock);
+ if (zport != zport_a) {
+ if (mctrl & TIOCM_DTR)
+ zport_a->regs[5] |= DTR;
+ else
+ zport_a->regs[5] &= ~DTR;
+ if (mctrl & TIOCM_RTS)
+ zport_a->regs[5] |= RTS;
+ else
+ zport_a->regs[5] &= ~RTS;
+ write_zsreg(zport_a, R5, zport_a->regs[5]);
+ }
+
+ /* Rarely modified, so don't poke at hardware unless necessary. */
+ oldloop = zport->regs[14];
+ newloop = oldloop;
+ if (mctrl & TIOCM_LOOP)
+ newloop |= LOOPBAK;
+ else
+ newloop &= ~LOOPBAK;
+ if (newloop != oldloop) {
+ zport->regs[14] = newloop;
+ write_zsreg(zport, R14, zport->regs[14]);
+ }
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_stop_tx(struct zs_port *zport)
+{
+ write_zsreg(zport, R0, RES_Tx_P);
+ zport->tx_stopped = 1;
+}
+
+static void zs_stop_tx(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+
+ spin_lock(&scc->zlock);
+ zs_raw_stop_tx(zport);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *);
+
+static void zs_start_tx(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+
+ spin_lock(&scc->zlock);
+ if (zport->tx_stopped) {
+ zs_transmit_drain(zport, 0);
+ zport->tx_stopped = 0;
+ zs_raw_transmit_chars(zport);
+ }
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_stop_rx(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+ spin_lock(&scc->zlock);
+ zport->regs[15] &= ~BRKIE;
+ zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
+ zport->regs[1] |= RxINT_DISAB;
+
+ if (zport != zport_a) {
+ /* A-side DCD tracks RI and SYNC tracks DSR. */
+ zport_a->regs[15] &= ~(DCDIE | SYNCIE);
+ write_zsreg(zport_a, R15, zport_a->regs[15]);
+ if (!(zport_a->regs[15] & BRKIE)) {
+ zport_a->regs[1] &= ~EXT_INT_ENAB;
+ write_zsreg(zport_a, R1, zport_a->regs[1]);
+ }
+
+ /* This-side DCD tracks DCD and CTS tracks CTS. */
+ zport->regs[15] &= ~(DCDIE | CTSIE);
+ zport->regs[1] &= ~EXT_INT_ENAB;
+ } else {
+ /* DCD tracks RI and SYNC tracks DSR for the B side. */
+ if (!(zport->regs[15] & (DCDIE | SYNCIE)))
+ zport->regs[1] &= ~EXT_INT_ENAB;
+ }
+
+ write_zsreg(zport, R15, zport->regs[15]);
+ write_zsreg(zport, R1, zport->regs[1]);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_enable_ms(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+ if (zport == zport_a)
+ return;
+
+ spin_lock(&scc->zlock);
+
+ /* Clear Ext interrupts if not being handled already. */
+ if (!(zport_a->regs[1] & EXT_INT_ENAB))
+ write_zsreg(zport_a, R0, RES_EXT_INT);
+
+ /* A-side DCD tracks RI and SYNC tracks DSR. */
+ zport_a->regs[1] |= EXT_INT_ENAB;
+ zport_a->regs[15] |= DCDIE | SYNCIE;
+
+ /* This-side DCD tracks DCD and CTS tracks CTS. */
+ zport->regs[15] |= DCDIE | CTSIE;
+
+ zs_raw_xor_mctrl(zport);
+
+ write_zsreg(zport_a, R1, zport_a->regs[1]);
+ write_zsreg(zport_a, R15, zport_a->regs[15]);
+ write_zsreg(zport, R15, zport->regs[15]);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_break_ctl(struct uart_port *uport, int break_state)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ if (break_state == -1)
+ zport->regs[5] |= SND_BRK;
+ else
+ zport->regs[5] &= ~SND_BRK;
+ write_zsreg(zport, R5, zport->regs[5]);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+/*
+ * Interrupt handling routines.
+ */
+#define Rx_BRK 0x0100 /* BREAK event software flag. */
+#define Rx_SYS 0x0200 /* SysRq event software flag. */
+
+static void zs_receive_chars(struct zs_port *zport)
+{
+ struct uart_port *uport = &zport->port;
+ struct zs_scc *scc = zport->scc;
+ struct uart_icount *icount;
+ unsigned int avail, status, ch, flag;
+ int count;
+
+ for (count = 16; count; count--) {
+ spin_lock(&scc->zlock);
+ avail = read_zsreg(zport, R0) & Rx_CH_AV;
+ spin_unlock(&scc->zlock);
+ if (!avail)
+ break;
+
+ spin_lock(&scc->zlock);
+ status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
+ ch = read_zsdata(zport);
+ spin_unlock(&scc->zlock);
+
+ flag = TTY_NORMAL;
+
+ icount = &uport->icount;
+ icount->rx++;
+
+ /* Handle the null char got when BREAK is removed. */
+ if (!ch)
+ status |= zport->tty_break;
+ if (unlikely(status &
+ (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
+ zport->tty_break = 0;
+
+ /* Reset the error indication. */
+ if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
+ spin_lock(&scc->zlock);
+ write_zsreg(zport, R0, ERR_RES);
+ spin_unlock(&scc->zlock);
+ }
+
+ if (status & (Rx_SYS | Rx_BRK)) {
+ icount->brk++;
+ /* SysRq discards the null char. */
+ if (status & Rx_SYS)
+ continue;
+ } else if (status & FRM_ERR)
+ icount->frame++;
+ else if (status & PAR_ERR)
+ icount->parity++;
+ if (status & Rx_OVR)
+ icount->overrun++;
+
+ status &= uport->read_status_mask;
+ if (status & Rx_BRK)
+ flag = TTY_BREAK;
+ else if (status & FRM_ERR)
+ flag = TTY_FRAME;
+ else if (status & PAR_ERR)
+ flag = TTY_PARITY;
+ }
+
+ if (uart_handle_sysrq_char(uport, ch))
+ continue;
+
+ uart_insert_char(uport, status, Rx_OVR, ch, flag);
+ }
+
+ tty_flip_buffer_push(uport->info->tty);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *zport)
+{
+ struct circ_buf *xmit = &zport->port.info->xmit;
+
+ /* XON/XOFF chars. */
+ if (zport->port.x_char) {
+ write_zsdata(zport, zport->port.x_char);
+ zport->port.icount.tx++;
+ zport->port.x_char = 0;
+ return;
+ }
+
+ /* If nothing to do or stopped or hardware stopped. */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+ zs_raw_stop_tx(zport);
+ return;
+ }
+
+ /* Send char. */
+ write_zsdata(zport, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ zport->port.icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&zport->port);
+
+ /* Are we are done? */
+ if (uart_circ_empty(xmit))
+ zs_raw_stop_tx(zport);
+}
+
+static void zs_transmit_chars(struct zs_port *zport)
+{
+ struct zs_scc *scc = zport->scc;
+
+ spin_lock(&scc->zlock);
+ zs_raw_transmit_chars(zport);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
+{
+ struct uart_port *uport = &zport->port;
+ struct zs_scc *scc = zport->scc;
+ unsigned int delta;
+ u8 status, brk;
+
+ spin_lock(&scc->zlock);
+
+ /* Get status from Read Register 0. */
+ status = read_zsreg(zport, R0);
+
+ if (zport->regs[15] & BRKIE) {
+ brk = status & BRK_ABRT;
+ if (brk && !zport->brk) {
+ spin_unlock(&scc->zlock);
+ if (uart_handle_break(uport))
+ zport->tty_break = Rx_SYS;
+ else
+ zport->tty_break = Rx_BRK;
+ spin_lock(&scc->zlock);
+ }
+ zport->brk = brk;
+ }
+
+ if (zport != zport_a) {
+ delta = zs_raw_xor_mctrl(zport);
+ spin_unlock(&scc->zlock);
+
+ if (delta & TIOCM_CTS)
+ uart_handle_cts_change(uport,
+ zport->mctrl & TIOCM_CTS);
+ if (delta & TIOCM_CAR)
+ uart_handle_dcd_change(uport,
+ zport->mctrl & TIOCM_CAR);
+ if (delta & TIOCM_RNG)
+ uport->icount.dsr++;
+ if (delta & TIOCM_DSR)
+ uport->icount.rng++;
+
+ if (delta)
+ wake_up_interruptible(&uport->info->delta_msr_wait);
+
+ spin_lock(&scc->zlock);
+ }
+
+ /* Clear the status condition... */
+ write_zsreg(zport, R0, RES_EXT_INT);
+
+ spin_unlock(&scc->zlock);
+}
+
+/*
+ * This is the Z85C30 driver's generic interrupt routine.
+ */
+static irqreturn_t zs_interrupt(int irq, void *dev_id)
+{
+ struct zs_scc *scc = dev_id;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+ struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
+ irqreturn_t status = IRQ_NONE;
+ u8 zs_intreg;
+ int count;
+
+ /*
+ * NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+ for (count = 16; count; count--) {
+ spin_lock(&scc->zlock);
+ zs_intreg = read_zsreg(zport_a, R3);
+ spin_unlock(&scc->zlock);
+ if (!zs_intreg)
+ break;
+
+ /*
+ * We do not like losing characters, so we prioritise
+ * interrupt sources a little bit differently than
+ * the SCC would, was it allowed to.
+ */
+ if (zs_intreg & CHBRxIP)
+ zs_receive_chars(zport_b);
+ if (zs_intreg & CHARxIP)
+ zs_receive_chars(zport_a);
+ if (zs_intreg & CHBEXT)
+ zs_status_handle(zport_b, zport_a);
+ if (zs_intreg & CHAEXT)
+ zs_status_handle(zport_a, zport_a);
+ if (zs_intreg & CHBTxIP)
+ zs_transmit_chars(zport_b);
+ if (zs_intreg & CHATxIP)
+ zs_transmit_chars(zport_a);
+
+ status = IRQ_HANDLED;
+ }
+
+ return status;
+}
+
+
+/*
+ * Finally, routines used to initialize the serial port.
+ */
+static int zs_startup(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ int irq_guard;
+ int ret;
+
+ irq_guard = atomic_add_return(1, &scc->irq_guard);
+ if (irq_guard == 1) {
+ ret = request_irq(zport->port.irq, zs_interrupt,
+ IRQF_SHARED, "scc", scc);
+ if (ret) {
+ atomic_add(-1, &scc->irq_guard);
+ printk(KERN_ERR "zs: can't get irq %d\n",
+ zport->port.irq);
+ return ret;
+ }
+ }
+
+ spin_lock_irqsave(&scc->zlock, flags);
+
+ /* Clear the receive FIFO. */
+ zs_receive_drain(zport);
+
+ /* Clear the interrupt registers. */
+ write_zsreg(zport, R0, ERR_RES);
+ write_zsreg(zport, R0, RES_Tx_P);
+ /* But Ext only if not being handled already. */
+ if (!(zport->regs[1] & EXT_INT_ENAB))
+ write_zsreg(zport, R0, RES_EXT_INT);
+
+ /* Finally, enable sequencing and interrupts. */
+ zport->regs[1] &= ~RxINT_MASK;
+ zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
+ zport->regs[3] |= RxENABLE;
+ zport->regs[5] |= TxENAB;
+ zport->regs[15] |= BRKIE;
+ write_zsreg(zport, R1, zport->regs[1]);
+ write_zsreg(zport, R3, zport->regs[3]);
+ write_zsreg(zport, R5, zport->regs[5]);
+ write_zsreg(zport, R15, zport->regs[15]);
+
+ /* Record the current state of RR0. */
+ zport->mctrl = zs_raw_get_mctrl(zport);
+ zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
+
+ zport->tx_stopped = 1;
+
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ return 0;
+}
+
+static void zs_shutdown(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ int irq_guard;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+
+ zport->regs[5] &= ~TxENAB;
+ zport->regs[3] &= ~RxENABLE;
+ write_zsreg(zport, R5, zport->regs[5]);
+ write_zsreg(zport, R3, zport->regs[3]);
+
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ irq_guard = atomic_add_return(-1, &scc->irq_guard);
+ if (!irq_guard)
+ free_irq(zport->port.irq, scc);
+}
+
+
+static void zs_reset(struct zs_port *zport)
+{
+ struct zs_scc *scc = zport->scc;
+ int irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+ if (!scc->initialised) {
+ /* Reset the pointer first, just in case... */
+ read_zsreg(zport, R0);
+ /* And let the current transmission finish. */
+ zs_line_drain(zport, irq);
+ write_zsreg(zport, R9, FHWRES);
+ udelay(10);
+ write_zsreg(zport, R9, 0);
+ scc->initialised = 1;
+ }
+ load_zsregs(zport, zport->regs, irq);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
+ struct ktermios *old_termios)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+ int irq;
+ unsigned int baud, brg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+
+ /* Byte size. */
+ zport->regs[3] &= ~RxNBITS_MASK;
+ zport->regs[5] &= ~TxNBITS_MASK;
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ zport->regs[3] |= Rx5;
+ zport->regs[5] |= Tx5;
+ break;
+ case CS6:
+ zport->regs[3] |= Rx6;
+ zport->regs[5] |= Tx6;
+ break;
+ case CS7:
+ zport->regs[3] |= Rx7;
+ zport->regs[5] |= Tx7;
+ break;
+ case CS8:
+ default:
+ zport->regs[3] |= Rx8;
+ zport->regs[5] |= Tx8;
+ break;
+ }
+
+ /* Parity and stop bits. */
+ zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
+ if (termios->c_cflag & CSTOPB)
+ zport->regs[4] |= SB2;
+ else
+ zport->regs[4] |= SB1;
+ if (termios->c_cflag & PARENB)
+ zport->regs[4] |= PAR_ENA;
+ if (!(termios->c_cflag & PARODD))
+ zport->regs[4] |= PAR_EVEN;
+ switch (zport->clk_mode) {
+ case 64:
+ zport->regs[4] |= X64CLK;
+ break;
+ case 32:
+ zport->regs[4] |= X32CLK;
+ break;
+ case 16:
+ zport->regs[4] |= X16CLK;
+ break;
+ case 1:
+ zport->regs[4] |= X1CLK;
+ break;
+ default:
+ BUG();
+ }
+
+ baud = uart_get_baud_rate(uport, termios, old_termios, 0,
+ uport->uartclk / zport->clk_mode / 4);
+
+ brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
+ zport->regs[12] = brg & 0xff;
+ zport->regs[13] = (brg >> 8) & 0xff;
+
+ uart_update_timeout(uport, termios->c_cflag, baud);
+
+ uport->read_status_mask = Rx_OVR;
+ if (termios->c_iflag & INPCK)
+ uport->read_status_mask |= FRM_ERR | PAR_ERR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ uport->read_status_mask |= Rx_BRK;
+
+ uport->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
+ if (termios->c_iflag & IGNBRK) {
+ uport->ignore_status_mask |= Rx_BRK;
+ if (termios->c_iflag & IGNPAR)
+ uport->ignore_status_mask |= Rx_OVR;
+ }
+
+ if (termios->c_cflag & CREAD)
+ zport->regs[3] |= RxENABLE;
+ else
+ zport->regs[3] &= ~RxENABLE;
+
+ if (zport != zport_a) {
+ if (!(termios->c_cflag & CLOCAL)) {
+ zport->regs[15] |= DCDIE;
+ } else
+ zport->regs[15] &= ~DCDIE;
+ if (termios->c_cflag & CRTSCTS) {
+ zport->regs[15] |= CTSIE;
+ } else
+ zport->regs[15] &= ~CTSIE;
+ zs_raw_xor_mctrl(zport);
+ }
+
+ /* Load up the new values. */
+ load_zsregs(zport, zport->regs, irq);
+
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+static const char *zs_type(struct uart_port *uport)
+{
+ return "Z85C30 SCC";
+}
+
+static void zs_release_port(struct uart_port *uport)
+{
+ iounmap(uport->membase);
+ uport->membase = 0;
+ release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+}
+
+static int zs_map_port(struct uart_port *uport)
+{
+ if (!uport->membase)
+ uport->membase = ioremap_nocache(uport->mapbase,
+ ZS_CHAN_IO_SIZE);
+ if (!uport->membase) {
+ printk(KERN_ERR "zs: Cannot map MMIO\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int zs_request_port(struct uart_port *uport)
+{
+ int ret;
+
+ if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
+ printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
+ return -EBUSY;
+ }
+ ret = zs_map_port(uport);
+ if (ret) {
+ release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+ return ret;
+ }
+ return 0;
+}
+
+static void zs_config_port(struct uart_port *uport, int flags)
+{
+ struct zs_port *zport = to_zport(uport);
+
+ if (flags & UART_CONFIG_TYPE) {
+ if (zs_request_port(uport))
+ return;
+
+ uport->type = PORT_ZS;
+
+ zs_reset(zport);
+ }
+}
+
+static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+ struct zs_port *zport = to_zport(uport);
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
+ ret = -EINVAL;
+ if (ser->irq != uport->irq)
+ ret = -EINVAL;
+ if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
+ ret = -EINVAL;
+ return ret;
+}
+
+
+static struct uart_ops zs_ops = {
+ .tx_empty = zs_tx_empty,
+ .set_mctrl = zs_set_mctrl,
+ .get_mctrl = zs_get_mctrl,
+ .stop_tx = zs_stop_tx,
+ .start_tx = zs_start_tx,
+ .stop_rx = zs_stop_rx,
+ .enable_ms = zs_enable_ms,
+ .break_ctl = zs_break_ctl,
+ .startup = zs_startup,
+ .shutdown = zs_shutdown,
+ .set_termios = zs_set_termios,
+ .type = zs_type,
+ .release_port = zs_release_port,
+ .request_port = zs_request_port,
+ .config_port = zs_config_port,
+ .verify_port = zs_verify_port,
+};
+
+/*
+ * Initialize Z85C30 port structures.
+ */
+static int __init zs_probe_sccs(void)
+{
+ static int probed;
+ struct zs_parms zs_parms;
+ int chip, side, irq;
+ int n_chips = 0;
+ int i;
+
+ if (probed)
+ return 0;
+
+ irq = dec_interrupt[DEC_IRQ_SCC0];
+ if (irq >= 0) {
+ zs_parms.scc[n_chips] = IOASIC_SCC0;
+ zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+ n_chips++;
+ }
+ irq = dec_interrupt[DEC_IRQ_SCC1];
+ if (irq >= 0) {
+ zs_parms.scc[n_chips] = IOASIC_SCC1;
+ zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+ n_chips++;
+ }
+ if (!n_chips)
+ return -ENXIO;
+
+ probed = 1;
+
+ for (chip = 0; chip < n_chips; chip++) {
+ spin_lock_init(&zs_sccs[chip].zlock);
+ for (side = 0; side < ZS_NUM_CHAN; side++) {
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct uart_port *uport = &zport->port;
+
+ zport->scc = &zs_sccs[chip];
+ zport->clk_mode = 16;
+
+ uport->irq = zs_parms.irq[chip];
+ uport->uartclk = ZS_CLOCK;
+ uport->fifosize = 1;
+ uport->iotype = UPIO_MEM;
+ uport->flags = UPF_BOOT_AUTOCONF;
+ uport->ops = &zs_ops;
+ uport->line = chip * ZS_NUM_CHAN + side;
+ uport->mapbase = dec_kn_slot_base +
+ zs_parms.scc[chip] +
+ (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+
+ for (i = 0; i < ZS_NUM_REGS; i++)
+ zport->regs[i] = zs_init_regs[i];
+ }
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_ZS_CONSOLE
+static void zs_console_putchar(struct uart_port *uport, int ch)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ int irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+ if (zs_transmit_drain(zport, irq))
+ write_zsdata(zport, ch);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void zs_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ u8 txint, txenb;
+ int irq;
+
+ /* Disable transmit interrupts and enable the transmitter. */
+ spin_lock_irqsave(&scc->zlock, flags);
+ txint = zport->regs[1];
+ txenb = zport->regs[5];
+ if (txint & TxINT_ENAB) {
+ zport->regs[1] = txint & ~TxINT_ENAB;
+ write_zsreg(zport, R1, zport->regs[1]);
+ }
+ if (!(txenb & TxENAB)) {
+ zport->regs[5] = txenb | TxENAB;
+ write_zsreg(zport, R5, zport->regs[5]);
+ }
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ uart_console_write(&zport->port, s, count, zs_console_putchar);
+
+ /* Restore transmit interrupts and the transmitter enable. */
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+ zs_line_drain(zport, irq);
+ if (!(txenb & TxENAB)) {
+ zport->regs[5] &= ~TxENAB;
+ write_zsreg(zport, R5, zport->regs[5]);
+ }
+ if (txint & TxINT_ENAB) {
+ zport->regs[1] |= TxINT_ENAB;
+ write_zsreg(zport, R1, zport->regs[1]);
+ }
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Setup serial console baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first uart_open()
+ * - initialise the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+static int __init zs_console_setup(struct console *co, char *options)
+{
+ int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct uart_port *uport = &zport->port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int ret;
+
+ ret = zs_map_port(uport);
+ if (ret)
+ return ret;
+
+ zs_reset(zport);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver zs_reg;
+static struct console zs_console = {
+ .name = "ttyS",
+ .write = zs_console_write,
+ .device = uart_console_device,
+ .setup = zs_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &zs_reg,
+};
+
+/*
+ * Register console.
+ */
+static int __init zs_serial_console_init(void)
+{
+ int ret;
+
+ ret = zs_probe_sccs();
+ if (ret)
+ return ret;
+ register_console(&zs_console);
+
+ return 0;
+}
+
+console_initcall(zs_serial_console_init);
+
+#define SERIAL_ZS_CONSOLE &zs_console
+#else
+#define SERIAL_ZS_CONSOLE NULL
+#endif /* CONFIG_SERIAL_ZS_CONSOLE */
+
+static struct uart_driver zs_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = ZS_NUM_SCCS * ZS_NUM_CHAN,
+ .cons = SERIAL_ZS_CONSOLE,
+};
+
+/* zs_init inits the driver. */
+static int __init zs_init(void)
+{
+ int i, ret;
+
+ pr_info("%s%s\n", zs_name, zs_version);
+
+ /* Find out how many Z85C30 SCCs we have. */
+ ret = zs_probe_sccs();
+ if (ret)
+ return ret;
+
+ ret = uart_register_driver(&zs_reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+ struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+ struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+ struct uart_port *uport = &zport->port;
+
+ if (zport->scc)
+ uart_add_one_port(&zs_reg, uport);
+ }
+
+ return 0;
+}
+
+static void __exit zs_exit(void)
+{
+ int i;
+
+ for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+ struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+ struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+ struct uart_port *uport = &zport->port;
+
+ if (zport->scc)
+ uart_remove_one_port(&zs_reg, uport);
+ }
+
+ uart_unregister_driver(&zs_reg);
+}
+
+module_init(zs_init);
+module_exit(zs_exit);
diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h
new file mode 100644
index 000000000000..aa921b57d827
--- /dev/null
+++ b/drivers/serial/zs.h
@@ -0,0 +1,284 @@
+/*
+ * zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004, 2005, 2007 Maciej W. Rozycki
+ */
+#ifndef _SERIAL_ZS_H
+#define _SERIAL_ZS_H
+
+#ifdef __KERNEL__
+
+#define ZS_NUM_REGS 16
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct zs_port {
+ struct zs_scc *scc; /* Containing SCC. */
+ struct uart_port port; /* Underlying UART. */
+
+ int clk_mode; /* May be 1, 16, 32, or 64. */
+
+ unsigned int tty_break; /* Set on BREAK condition. */
+ int tx_stopped; /* Output is suspended. */
+
+ unsigned int mctrl; /* State of modem lines. */
+ u8 brk; /* BREAK state from RR0. */
+
+ u8 regs[ZS_NUM_REGS]; /* Channel write registers. */
+};
+
+/*
+ * Per-SCC state for locking and the interrupt handler.
+ */
+struct zs_scc {
+ struct zs_port zport[2];
+ spinlock_t zlock;
+ atomic_t irq_guard;
+ int initialised;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * Conversion routines to/from brg time constants from/to bits per second.
+ */
+#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/*
+ * The Zilog register set.
+ */
+
+/* Write Register 0 (Command) */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */
+#define RxINT_ERR 0x18 /* Int on error only */
+#define RxINT_MASK 0x18
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register 2 (Interrupt Vector) */
+
+/* Write Register 3 (Receive Parameters and Control) */
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxNBITS_MASK 0xc0
+
+/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+#define SB_MASK 0xc
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xc0 /* x64 clock mode */
+#define XCLK_MASK 0xc0
+
+/* Write Register 5 (Transmit Parameters and Controls) */
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxNBITS_MASK 0x60
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (Transmit Buffer) */
+
+/* Write Register 9 (Master Interrupt Control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define SOFTACK 0x20 /* Software Interrupt Acknowledge */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode Control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 14 (Miscellaneous Control Bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (External/Status Interrupt Control) */
+#define WR7P_EN 1 /* WR7 Prime SDLC Feature Enable */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 (Special Receive Condition Status) */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity Error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define FRM_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (Interrupt Vector (WR2) -- channel A). */
+
+/* Read Register 2 (Modified Interrupt Vector -- channel B). */
+
+/* Read Register 3 (Interrupt Pending Bits -- channel A only). */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
+
+/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
+
+/* Read Register 8 (Receive Data) */
+
+/* Read Register 10 (Miscellaneous Status Bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
+
+/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
+
+/* Read Register 15 (External/Status Interrupt Control (WR15)) */
+
+#endif /* _SERIAL_ZS_H */
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
index 94b229031198..7d873b3b0513 100644
--- a/drivers/sh/superhyway/superhyway.c
+++ b/drivers/sh/superhyway/superhyway.c
@@ -56,11 +56,10 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *sdev,
struct superhyway_device *dev = sdev;
if (!dev) {
- dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(struct superhyway_device));
}
dev->bus = bus;
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 2dd6eed50aa0..29fcd6d0301d 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -629,7 +629,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
#endif
/* Set up per-IOC3 data */
- idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
+ idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
if (!idd) {
printk(KERN_WARNING
"%s: Failed to allocate IOC3 data for pci_dev %s.\n",
@@ -637,7 +637,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
ret = -ENODEV;
goto out_idd;
}
- memset(idd, 0, sizeof(struct ioc3_driver_data));
spin_lock_init(&idd->ir_lock);
spin_lock_init(&idd->gpio_lock);
idd->pdev = pdev;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index ad144054da30..b0469749310a 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -251,7 +251,7 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
xfer->rx_dma = dma_map_single(dev,
xfer->rx_buf, xfer->len,
DMA_FROM_DEVICE);
- if (dma_mapping_error(xfer->tx_dma)) {
+ if (dma_mapping_error(xfer->rx_dma)) {
if (xfer->tx_buf)
dma_unmap_single(dev,
xfer->tx_dma, xfer->len,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 018884d7a5fa..bcb8dd5fb0b4 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
}
-static int spi_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
- envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
- envp[1] = NULL;
+ add_uevent_var(env, "MODALIAS=%s", spi->modalias);
return 0;
}
@@ -200,6 +197,8 @@ static DEFINE_MUTEX(board_lock);
* platforms may not be able to use spi_register_board_info though, and
* this is exported so that for example a USB or parport based adapter
* driver could add devices (which it would learn about out-of-band).
+ *
+ * Returns the new device, or NULL.
*/
struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
@@ -208,7 +207,20 @@ struct spi_device *spi_new_device(struct spi_master *master,
struct device *dev = master->cdev.dev;
int status;
- /* NOTE: caller did any chip->bus_num checks necessary */
+ /* NOTE: caller did any chip->bus_num checks necessary.
+ *
+ * Also, unless we change the return value convention to use
+ * error-or-pointer (not NULL-or-pointer), troubleshootability
+ * suggests syslogged diagnostics are best here (ugh).
+ */
+
+ /* Chipselects are numbered 0..max; validate. */
+ if (chip->chip_select >= master->num_chipselect) {
+ dev_err(dev, "cs%d > max %d\n",
+ chip->chip_select,
+ master->num_chipselect);
+ return NULL;
+ }
if (!spi_master_get(master))
return NULL;
@@ -236,10 +248,10 @@ struct spi_device *spi_new_device(struct spi_master *master,
proxy->controller_state = NULL;
proxy->dev.release = spidev_release;
- /* drivers may modify this default i/o setup */
+ /* drivers may modify this initial i/o setup */
status = master->setup(proxy);
if (status < 0) {
- dev_dbg(dev, "can't %s %s, status %d\n",
+ dev_err(dev, "can't %s %s, status %d\n",
"setup", proxy->dev.bus_id, status);
goto fail;
}
@@ -249,7 +261,7 @@ struct spi_device *spi_new_device(struct spi_master *master,
*/
status = device_register(&proxy->dev);
if (status < 0) {
- dev_dbg(dev, "can't %s %s, status %d\n",
+ dev_err(dev, "can't %s %s, status %d\n",
"add", proxy->dev.bus_id, status);
goto fail;
}
@@ -303,11 +315,9 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
* creates board info from kernel command lines
*/
-static void __init_or_module
-scan_boardinfo(struct spi_master *master)
+static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi;
- struct device *dev = master->cdev.dev;
mutex_lock(&board_lock);
list_for_each_entry(bi, &board_list, list) {
@@ -317,17 +327,9 @@ scan_boardinfo(struct spi_master *master)
for (n = bi->n_board_info; n > 0; n--, chip++) {
if (chip->bus_num != master->bus_num)
continue;
- /* some controllers only have one chip, so they
- * might not use chipselects. otherwise, the
- * chipselects are numbered 0..max.
+ /* NOTE: this relies on spi_new_device to
+ * issue diagnostics when given bogus inputs
*/
- if (chip->chip_select >= master->num_chipselect
- && master->num_chipselect) {
- dev_dbg(dev, "cs%d > max %d\n",
- chip->chip_select,
- master->num_chipselect);
- continue;
- }
(void) spi_new_device(master, chip);
}
}
@@ -420,8 +422,17 @@ int spi_register_master(struct spi_master *master)
if (!dev)
return -ENODEV;
+ /* even if it's just one always-selected device, there must
+ * be at least one chipselect
+ */
+ if (master->num_chipselect == 0)
+ return -EINVAL;
+
/* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < 0) {
+ /* FIXME switch to an IDR based scheme, something like
+ * I2C now uses, so we can't run out of "dynamic" IDs
+ */
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = 1;
}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 48587c27050d..f540ed77a102 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1303,8 +1303,9 @@ static int bfin5xx_spi_resume(struct platform_device *pdev)
#define bfin5xx_spi_resume NULL
#endif /* CONFIG_PM */
+MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */
static struct platform_driver bfin5xx_spi_driver = {
- .driver = {
+ .driver = {
.name = "bfin-spi-master",
.owner = THIS_MODULE,
},
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index aee9ad6f633c..bd9177f51de9 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1735,7 +1735,7 @@ static int spi_imx_resume(struct platform_device *pdev)
static struct platform_driver driver = {
.driver = {
- .name = "imx-spi",
+ .name = "spi_imx",
.bus = &platform_bus_type,
.owner = THIS_MODULE,
},
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 3295cfcc9f20..32cda77b31cd 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -39,6 +39,7 @@ struct mpc83xx_spi_reg {
};
/* SPI Controller mode register definitions */
+#define SPMODE_LOOP (1 << 30)
#define SPMODE_CI_INACTIVEHIGH (1 << 29)
#define SPMODE_CP_BEGIN_EDGECLK (1 << 28)
#define SPMODE_DIV16 (1 << 27)
@@ -85,7 +86,7 @@ struct mpc83xx_spi {
unsigned nsecs; /* (clock cycle time)/2 */
- u32 sysclk;
+ u32 spibrg; /* SPIBRG input clock */
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
@@ -147,35 +148,48 @@ 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 &= ~0x38ff0000;
+ 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->sysclk / spi->max_speed_hz) >= 64) {
- u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 64);
+ if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) {
+ pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64) - 1;
if (pm > 0x0f) {
- printk(KERN_WARNING "MPC83xx SPI: SPICLK can't be less then a SYSCLK/1024!\n"
- "Requested SPICLK is %d Hz. Will use %d Hz instead.\n",
- spi->max_speed_hz, mpc83xx_spi->sysclk / 1024);
+ 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 {
- u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 4);
+ pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4);
+ if (pm)
+ pm--;
regval |= SPMODE_PM(pm);
}
+ /* 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);
@@ -231,6 +245,14 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
} else
return -EINVAL;
+ if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
+ mpc83xx_spi->tx_shift = 0;
+ if (bits_per_word <= 8)
+ mpc83xx_spi->rx_shift = 8;
+ else
+ mpc83xx_spi->rx_shift = 0;
+ }
+
/* nsecs = (clock period)/2 */
if (!hz)
hz = spi->max_speed_hz;
@@ -245,17 +267,22 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
- /* Mask out bits_per_wordgth */
- regval &= 0xff0fffff;
+ /* 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;
+ /* 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);
return 0;
}
/* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+ | SPI_LSB_FIRST | SPI_LOOP)
static int mpc83xx_spi_setup(struct spi_device *spi)
{
@@ -357,11 +384,8 @@ irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
mpc83xx_spi->count -= 1;
if (mpc83xx_spi->count) {
- if (mpc83xx_spi->tx) {
- u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
- mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit,
- word);
- }
+ u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
+ mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
} else {
complete(&mpc83xx_spi->done);
}
@@ -407,13 +431,17 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
- mpc83xx_spi->sysclk = pdata->sysclk;
mpc83xx_spi->activate_cs = pdata->activate_cs;
mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
mpc83xx_spi->qe_mode = pdata->qe_mode;
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+ if (mpc83xx_spi->qe_mode)
+ mpc83xx_spi->spibrg = pdata->sysclk / 2;
+ else
+ mpc83xx_spi->spibrg = pdata->sysclk;
+
mpc83xx_spi->rx_shift = 0;
mpc83xx_spi->tx_shift = 0;
if (mpc83xx_spi->qe_mode) {
@@ -499,6 +527,7 @@ static int __devexit mpc83xx_spi_remove(struct platform_device *dev)
return 0;
}
+MODULE_ALIAS("mpc83xx_spi"); /* for platform bus hotplug */
static struct platform_driver mpc83xx_spi_driver = {
.probe = mpc83xx_spi_probe,
.remove = __devexit_p(mpc83xx_spi_remove),
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 7071ff8da63e..e9b683f7d7b3 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -28,7 +28,7 @@
#include <asm/hardware.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
#include <asm/arch/spi.h>
struct s3c24xx_spi {
@@ -427,6 +427,7 @@ static int s3c24xx_spi_resume(struct platform_device *pdev)
#define s3c24xx_spi_resume NULL
#endif
+MODULE_ALIAS("s3c2410_spi"); /* for platform bus hotplug */
static struct platform_driver s3c24xx_spidrv = {
.probe = s3c24xx_spi_probe,
.remove = s3c24xx_spi_remove,
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index 611ac22b7cdc..0fa25e2e80fe 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -180,7 +180,7 @@ static struct platform_driver s3c2410_spigpio_drv = {
.suspend = s3c2410_spigpio_suspend,
.resume = s3c2410_spigpio_resume,
.driver = {
- .name = "s3c24xx-spi-gpio",
+ .name = "spi_s3c24xx_gpio",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
index 08e981c40646..b7f4bb239eaf 100644
--- a/drivers/spi/spi_txx9.c
+++ b/drivers/spi/spi_txx9.c
@@ -453,7 +453,7 @@ static int __exit txx9spi_remove(struct platform_device *dev)
static struct platform_driver txx9spi_driver = {
.remove = __exit_p(txx9spi_remove),
.driver = {
- .name = "txx9spi",
+ .name = "spi_txx9",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 38b60ad0eda0..c55459c592b8 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -55,9 +55,16 @@
static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
-/* Bit masks for spi_device.mode management */
-#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL)
-
+/* Bit masks for spi_device.mode management. Note that incorrect
+ * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
+ * devices on a shared bus: CS_HIGH, because this device will be
+ * active when it shouldn't be; 3WIRE, because when active it won't
+ * behave as it should.
+ *
+ * REVISIT should changing those two modes be privileged?
+ */
+#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
+ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
struct spidev_data {
struct device dev;
@@ -176,7 +183,9 @@ static int spidev_message(struct spidev_data *spidev,
if (u_tmp->rx_buf) {
k_tmp->rx_buf = buf;
- if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len))
+ if (!access_ok(VERIFY_WRITE, (u8 __user *)
+ (ptrdiff_t) u_tmp->rx_buf,
+ u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index f0bf9a68e96b..5d04f520c123 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -21,7 +21,7 @@
#include <syslib/virtex_devices.h>
-#define XILINX_SPI_NAME "xspi"
+#define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
* Product Specification", DS464
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
new file mode 100644
index 000000000000..b4a5e5e9d9fc
--- /dev/null
+++ b/drivers/ssb/Kconfig
@@ -0,0 +1,117 @@
+menu "Sonics Silicon Backplane"
+
+config SSB_POSSIBLE
+ bool
+ depends on HAS_IOMEM
+ default y
+
+config SSB
+ tristate "Sonics Silicon Backplane support"
+ depends on SSB_POSSIBLE
+ help
+ Support for the Sonics Silicon Backplane bus.
+ You only need to enable this option, if you are
+ configuring a kernel for an embedded system with
+ this bus.
+ It will be auto-selected if needed in other
+ environments.
+
+ The module will be called ssb.
+
+ If unsure, say N.
+
+config SSB_PCIHOST_POSSIBLE
+ bool
+ depends on SSB && PCI
+ default y
+
+config SSB_PCIHOST
+ bool "Support for SSB on PCI-bus host"
+ depends on SSB_PCIHOST_POSSIBLE
+ default y
+ help
+ Support for a Sonics Silicon Backplane on top
+ of a PCI device.
+
+ If unsure, say Y
+
+config SSB_PCMCIAHOST_POSSIBLE
+ bool
+ depends on SSB && PCMCIA && EXPERIMENTAL
+ default y
+
+config SSB_PCMCIAHOST
+ bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)"
+ depends on SSB_PCMCIAHOST_POSSIBLE
+ help
+ Support for a Sonics Silicon Backplane on top
+ of a PCMCIA device.
+
+ If unsure, say N
+
+config SSB_SILENT
+ bool "No SSB kernel messages"
+ depends on SSB && EMBEDDED
+ help
+ This option turns off all Sonics Silicon Backplane printks.
+ Note that you won't be able to identify problems, once
+ messages are turned off.
+ This might only be desired for production kernels on
+ embedded devices to reduce the kernel size.
+
+ Say N
+
+config SSB_DEBUG
+ bool "SSB debugging"
+ depends on SSB && !SSB_SILENT
+ help
+ This turns on additional runtime checks and debugging
+ messages. Turn this on for SSB troubleshooting.
+
+ If unsure, say N
+
+config SSB_SERIAL
+ bool
+ depends on SSB
+ # ChipCommon and ExtIf serial support routines.
+
+config SSB_DRIVER_PCICORE_POSSIBLE
+ bool
+ depends on SSB_PCIHOST
+ default y
+
+config SSB_DRIVER_PCICORE
+ bool "SSB PCI core driver"
+ depends on SSB_DRIVER_PCICORE_POSSIBLE
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom PCI core.
+
+ If unsure, say Y
+
+config SSB_PCICORE_HOSTMODE
+ bool "Hostmode support for SSB PCI core (EXPERIMENTAL)"
+ depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL
+ help
+ PCIcore hostmode operation (external PCI bus).
+
+config SSB_DRIVER_MIPS
+ bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)"
+ depends on SSB && MIPS && EXPERIMENTAL
+ select SSB_SERIAL
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom MIPS core.
+
+ If unsure, say N
+
+config SSB_DRIVER_EXTIF
+ bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
+ depends on SSB_DRIVER_MIPS && EXPERIMENTAL
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom EXTIF core.
+
+ If unsure, say N
+
+endmenu
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
new file mode 100644
index 000000000000..7be397595805
--- /dev/null
+++ b/drivers/ssb/Makefile
@@ -0,0 +1,18 @@
+# core
+ssb-y += main.o scan.o
+
+# host support
+ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
+ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o
+
+# built-in drivers
+ssb-y += driver_chipcommon.o
+ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
+ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
+ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
+
+# b43 pci-ssb-bridge driver
+# Not strictly a part of SSB, but kept here for convenience
+ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o
+
+obj-$(CONFIG_SSB) += ssb.o
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
new file mode 100644
index 000000000000..f145d8a4cfde
--- /dev/null
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -0,0 +1,48 @@
+/*
+ * Broadcom 43xx PCI-SSB bridge module
+ *
+ * This technically is a seperate PCI driver module, but
+ * because of its small size we include it in the SSB core
+ * instead of creating a standalone module.
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+
+static const struct pci_device_id b43_pci_bridge_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
+
+static struct pci_driver b43_pci_bridge_driver = {
+ .name = "b43-pci-bridge",
+ .id_table = b43_pci_bridge_tbl,
+};
+
+
+int __init b43_pci_ssb_bridge_init(void)
+{
+ return ssb_pcihost_register(&b43_pci_bridge_driver);
+}
+
+void __exit b43_pci_ssb_bridge_exit(void)
+{
+ ssb_pcihost_unregister(&b43_pci_bridge_driver);
+}
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
new file mode 100644
index 000000000000..6fbf1c53b6f2
--- /dev/null
+++ b/drivers/ssb/driver_chipcommon.c
@@ -0,0 +1,445 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom ChipCommon core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+
+#include "ssb_private.h"
+
+
+/* Clock sources */
+enum ssb_clksrc {
+ /* PCI clock */
+ SSB_CHIPCO_CLKSRC_PCI,
+ /* Crystal slow clock oscillator */
+ SSB_CHIPCO_CLKSRC_XTALOS,
+ /* Low power oscillator */
+ SSB_CHIPCO_CLKSRC_LOPWROS,
+};
+
+
+static inline u32 chipco_read32(struct ssb_chipcommon *cc,
+ u16 offset)
+{
+ return ssb_read32(cc->dev, offset);
+}
+
+static inline void chipco_write32(struct ssb_chipcommon *cc,
+ u16 offset,
+ u32 value)
+{
+ ssb_write32(cc->dev, offset, value);
+}
+
+static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
+ u32 mask, u32 value)
+{
+ value &= mask;
+ value |= chipco_read32(cc, offset) & ~mask;
+ chipco_write32(cc, offset, value);
+}
+
+void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+ enum ssb_clkmode mode)
+{
+ struct ssb_device *ccdev = cc->dev;
+ struct ssb_bus *bus;
+ u32 tmp;
+
+ if (!ccdev)
+ return;
+ bus = ccdev->bus;
+ /* chipcommon cores prior to rev6 don't support dynamic clock control */
+ if (ccdev->id.revision < 6)
+ return;
+ /* chipcommon cores rev10 are a whole new ball game */
+ if (ccdev->id.revision >= 10)
+ return;
+ if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ return;
+
+ switch (mode) {
+ case SSB_CLKMODE_SLOW:
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+ break;
+ case SSB_CLKMODE_FAST:
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+ break;
+ case SSB_CLKMODE_DYNAMIC:
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+ if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+
+ /* for dynamic control, we have to release our xtal_pu "force on" */
+ if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+}
+
+/* Get the Slow Clock Source */
+static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+ u32 uninitialized_var(tmp);
+
+ if (cc->dev->id.revision < 6) {
+ if (bus->bustype == SSB_BUSTYPE_SSB ||
+ bus->bustype == SSB_BUSTYPE_PCMCIA)
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp);
+ if (tmp & 0x10)
+ return SSB_CHIPCO_CLKSRC_PCI;
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+ }
+ }
+ if (cc->dev->id.revision < 10) {
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= 0x7;
+ if (tmp == 0)
+ return SSB_CHIPCO_CLKSRC_LOPWROS;
+ if (tmp == 1)
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+ if (tmp == 2)
+ return SSB_CHIPCO_CLKSRC_PCI;
+ }
+
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+}
+
+/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */
+static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max)
+{
+ int uninitialized_var(limit);
+ enum ssb_clksrc clocksrc;
+ int divisor = 1;
+ u32 tmp;
+
+ clocksrc = chipco_pctl_get_slowclksrc(cc);
+ if (cc->dev->id.revision < 6) {
+ switch (clocksrc) {
+ case SSB_CHIPCO_CLKSRC_PCI:
+ divisor = 64;
+ break;
+ case SSB_CHIPCO_CLKSRC_XTALOS:
+ divisor = 32;
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+ } else if (cc->dev->id.revision < 10) {
+ switch (clocksrc) {
+ case SSB_CHIPCO_CLKSRC_LOPWROS:
+ break;
+ case SSB_CHIPCO_CLKSRC_XTALOS:
+ case SSB_CHIPCO_CLKSRC_PCI:
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ divisor = (tmp >> 16) + 1;
+ divisor *= 4;
+ break;
+ }
+ } else {
+ tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL);
+ divisor = (tmp >> 16) + 1;
+ divisor *= 4;
+ }
+
+ switch (clocksrc) {
+ case SSB_CHIPCO_CLKSRC_LOPWROS:
+ if (get_max)
+ limit = 43000;
+ else
+ limit = 25000;
+ break;
+ case SSB_CHIPCO_CLKSRC_XTALOS:
+ if (get_max)
+ limit = 20200000;
+ else
+ limit = 19800000;
+ break;
+ case SSB_CHIPCO_CLKSRC_PCI:
+ if (get_max)
+ limit = 34000000;
+ else
+ limit = 25000000;
+ break;
+ }
+ limit /= divisor;
+
+ return limit;
+}
+
+static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ if (bus->chip_id == 0x4321) {
+ if (bus->chip_rev == 0)
+ chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4);
+ else if (bus->chip_rev == 1)
+ chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4);
+ }
+
+ if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ return;
+
+ if (cc->dev->id.revision >= 10) {
+ /* Set Idle Power clock rate to 1Mhz */
+ chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+ (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
+ 0x0000FFFF) | 0x00040000);
+ } else {
+ int maxfreq;
+
+ maxfreq = chipco_pctl_clockfreqlimit(cc, 1);
+ chipco_write32(cc, SSB_CHIPCO_PLLONDELAY,
+ (maxfreq * 150 + 999999) / 1000000);
+ chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY,
+ (maxfreq * 15 + 999999) / 1000000);
+ }
+}
+
+static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+ int minfreq;
+ unsigned int tmp;
+ u32 pll_on_delay;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return;
+ if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ return;
+
+ minfreq = chipco_pctl_clockfreqlimit(cc, 0);
+ pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
+ tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
+ SSB_WARN_ON(tmp & ~0xFFFF);
+
+ cc->fast_pwrup_delay = tmp;
+}
+
+void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+{
+ if (!cc->dev)
+ return; /* We don't have a ChipCommon */
+ chipco_powercontrol_init(cc);
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+ calc_fast_powerup_delay(cc);
+}
+
+void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
+{
+ if (!cc->dev)
+ return;
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
+}
+
+void ssb_chipco_resume(struct ssb_chipcommon *cc)
+{
+ if (!cc->dev)
+ return;
+ chipco_powercontrol_init(cc);
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+}
+
+/* Get the processor clock */
+void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
+ u32 *plltype, u32 *n, u32 *m)
+{
+ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
+ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+ switch (*plltype) {
+ case SSB_PLLTYPE_2:
+ case SSB_PLLTYPE_4:
+ case SSB_PLLTYPE_6:
+ case SSB_PLLTYPE_7:
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
+ break;
+ case SSB_PLLTYPE_3:
+ /* 5350 uses m2 to control mips */
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
+ break;
+ default:
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
+ break;
+ }
+}
+
+/* Get the bus clock */
+void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
+ u32 *plltype, u32 *n, u32 *m)
+{
+ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
+ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+ switch (*plltype) {
+ case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
+ break;
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ if (cc->dev->bus->chip_id != 0x5365) {
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
+ break;
+ }
+ /* Fallthough */
+ default:
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
+ }
+}
+
+void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
+ unsigned long ns)
+{
+ struct ssb_device *dev = cc->dev;
+ struct ssb_bus *bus = dev->bus;
+ u32 tmp;
+
+ /* set register for external IO to control LED. */
+ chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11);
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
+ tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */
+ tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */
+ chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
+
+ /* Set timing for the flash */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */
+ tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */
+ tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */
+ if ((bus->chip_id == 0x5365) ||
+ (dev->id.revision < 9))
+ chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp);
+ if ((bus->chip_id == 0x5365) ||
+ (dev->id.revision < 9) ||
+ ((bus->chip_id == 0x5350) && (bus->chip_rev == 0)))
+ chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp);
+
+ if (bus->chip_id == 0x5350) {
+ /* Enable EXTIF */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
+ tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */
+ tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */
+ tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */
+ chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
+ }
+}
+
+/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+{
+ /* instant NMI */
+ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
+}
+
+u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
+{
+ return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
+}
+
+void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+}
+
+void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+}
+
+#ifdef CONFIG_SSB_SERIAL
+int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
+ struct ssb_serial_port *ports)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+ int nr_ports = 0;
+ u32 plltype;
+ unsigned int irq;
+ u32 baud_base, div;
+ u32 i, n;
+
+ plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+ irq = ssb_mips_irq(cc->dev);
+
+ if (plltype == SSB_PLLTYPE_1) {
+ /* PLL clock */
+ baud_base = ssb_calc_clock_rate(plltype,
+ chipco_read32(cc, SSB_CHIPCO_CLOCK_N),
+ chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
+ div = 1;
+ } else {
+ if (cc->dev->id.revision >= 11) {
+ /* Fixed ALP clock */
+ baud_base = 20000000;
+ div = 1;
+ /* Set the override bit so we don't divide it */
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
+ SSB_CHIPCO_CORECTL_UARTCLK0);
+ } else if (cc->dev->id.revision >= 3) {
+ /* Internal backplane clock */
+ baud_base = ssb_clockspeed(bus);
+ div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
+ & SSB_CHIPCO_CLKDIV_UART;
+ } else {
+ /* Fixed internal backplane clock */
+ baud_base = 88000000;
+ div = 48;
+ }
+
+ /* Clock source depends on strapping if UartClkOverride is unset */
+ if ((cc->dev->id.revision > 0) &&
+ !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
+ if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
+ SSB_CHIPCO_CAP_UARTCLK_INT) {
+ /* Internal divided backplane clock */
+ baud_base /= div;
+ } else {
+ /* Assume external clock of 1.8432 MHz */
+ baud_base = 1843200;
+ }
+ }
+ }
+
+ /* Determine the registers of the UARTs */
+ n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART);
+ for (i = 0; i < n; i++) {
+ void __iomem *cc_mmio;
+ void __iomem *uart_regs;
+
+ cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
+ uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
+ /* Offset changed at after rev 0 */
+ if (cc->dev->id.revision == 0)
+ uart_regs += (i * 8);
+ else
+ uart_regs += (i * 256);
+
+ nr_ports++;
+ ports[i].regs = uart_regs;
+ ports[i].irq = irq;
+ ports[i].baud_base = baud_base;
+ ports[i].reg_shift = 0;
+ }
+
+ return nr_ports;
+}
+#endif /* CONFIG_SSB_SERIAL */
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c
new file mode 100644
index 000000000000..fe55eb8b038a
--- /dev/null
+++ b/drivers/ssb/driver_extif.c
@@ -0,0 +1,129 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom EXTIF core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+ * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include "ssb_private.h"
+
+
+static inline u32 extif_read32(struct ssb_extif *extif, u16 offset)
+{
+ return ssb_read32(extif->dev, offset);
+}
+
+static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
+{
+ ssb_write32(extif->dev, offset, value);
+}
+
+static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
+ u32 mask, u32 value)
+{
+ value &= mask;
+ value |= extif_read32(extif, offset) & ~mask;
+ extif_write32(extif, offset, value);
+}
+
+#ifdef CONFIG_SSB_SERIAL
+static bool serial_exists(u8 *regs)
+{
+ u8 save_mcr, msr = 0;
+
+ if (regs) {
+ save_mcr = regs[UART_MCR];
+ regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
+ msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI
+ | UART_MSR_CTS | UART_MSR_DSR);
+ regs[UART_MCR] = save_mcr;
+ }
+ return (msr == (UART_MSR_DCD | UART_MSR_CTS));
+}
+
+int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports)
+{
+ u32 i, nr_ports = 0;
+
+ /* Disable GPIO interrupt initially */
+ extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0);
+ extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0);
+
+ for (i = 0; i < 2; i++) {
+ void __iomem *uart_regs;
+
+ uart_regs = ioremap_nocache(SSB_EUART, 16);
+ if (uart_regs) {
+ uart_regs += (i * 8);
+
+ if (serial_exists(uart_regs) && ports) {
+ extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2);
+
+ nr_ports++;
+ ports[i].regs = uart_regs;
+ ports[i].irq = 2;
+ ports[i].baud_base = 13500000;
+ ports[i].reg_shift = 0;
+ }
+ iounmap(uart_regs);
+ }
+ }
+ return nr_ports;
+}
+#endif /* CONFIG_SSB_SERIAL */
+
+void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns)
+{
+ u32 tmp;
+
+ /* Initialize extif so we can get to the LEDs and external UART */
+ extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN);
+
+ /* Set timing for the flash */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
+ tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT;
+ tmp |= DIV_ROUND_UP(120, ns);
+ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
+
+ /* Set programmable interface timing for external uart */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
+ tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT;
+ tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT;
+ tmp |= DIV_ROUND_UP(120, ns);
+ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
+}
+
+void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
+ u32 *pll_type, u32 *n, u32 *m)
+{
+ *pll_type = SSB_PLLTYPE_1;
+ *n = extif_read32(extif, SSB_EXTIF_CLOCK_N);
+ *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+}
+
+u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
+{
+ return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
+}
+
+void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
+{
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
+ mask, value);
+}
+
+void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
+{
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
+ mask, value);
+}
+
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
new file mode 100644
index 000000000000..ab8691a32580
--- /dev/null
+++ b/drivers/ssb/driver_mipscore.c
@@ -0,0 +1,223 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom MIPS core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+#include "ssb_private.h"
+
+
+static inline u32 mips_read32(struct ssb_mipscore *mcore,
+ u16 offset)
+{
+ return ssb_read32(mcore->dev, offset);
+}
+
+static inline void mips_write32(struct ssb_mipscore *mcore,
+ u16 offset,
+ u32 value)
+{
+ ssb_write32(mcore->dev, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+ 0,
+ SSB_IPSFLAG_IRQ1,
+ SSB_IPSFLAG_IRQ2,
+ SSB_IPSFLAG_IRQ3,
+ SSB_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+ 0,
+ SSB_IPSFLAG_IRQ1_SHIFT,
+ SSB_IPSFLAG_IRQ2_SHIFT,
+ SSB_IPSFLAG_IRQ3_SHIFT,
+ SSB_IPSFLAG_IRQ4_SHIFT,
+};
+
+static inline u32 ssb_irqflag(struct ssb_device *dev)
+{
+ return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+}
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ */
+unsigned int ssb_mips_irq(struct ssb_device *dev)
+{
+ struct ssb_bus *bus = dev->bus;
+ u32 irqflag;
+ u32 ipsflag;
+ u32 tmp;
+ unsigned int irq;
+
+ irqflag = ssb_irqflag(dev);
+ ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
+ for (irq = 1; irq <= 4; irq++) {
+ tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
+ if (tmp == irqflag)
+ break;
+ }
+ if (irq == 5)
+ irq = 0;
+
+ return irq;
+}
+
+static void clear_irq(struct ssb_bus *bus, unsigned int irq)
+{
+ struct ssb_device *dev = bus->mipscore.dev;
+
+ /* Clear the IRQ in the MIPScore backplane registers */
+ if (irq == 0) {
+ ssb_write32(dev, SSB_INTVEC, 0);
+ } else {
+ ssb_write32(dev, SSB_IPSFLAG,
+ ssb_read32(dev, SSB_IPSFLAG) |
+ ipsflag_irq_mask[irq]);
+ }
+}
+
+static void set_irq(struct ssb_device *dev, unsigned int irq)
+{
+ unsigned int oldirq = ssb_mips_irq(dev);
+ struct ssb_bus *bus = dev->bus;
+ struct ssb_device *mdev = bus->mipscore.dev;
+ u32 irqflag = ssb_irqflag(dev);
+
+ dev->irq = irq + 2;
+
+ ssb_dprintk(KERN_INFO PFX
+ "set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.coreid, oldirq, irq);
+ /* clear the old irq */
+ if (oldirq == 0)
+ ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
+ else
+ clear_irq(bus, oldirq);
+
+ /* assign the new one */
+ if (irq == 0)
+ ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
+
+ irqflag <<= ipsflag_irq_shift[irq];
+ irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
+ ssb_write32(mdev, SSB_IPSFLAG, irqflag);
+}
+
+static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+
+ if (bus->extif.dev)
+ mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
+ else if (bus->chipco.dev)
+ mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
+ else
+ mcore->nr_serial_ports = 0;
+}
+
+static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+
+ mcore->flash_buswidth = 2;
+ if (bus->chipco.dev) {
+ mcore->flash_window = 0x1c000000;
+ mcore->flash_window_size = 0x02000000;
+ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+ & SSB_CHIPCO_CFG_DS16) == 0)
+ mcore->flash_buswidth = 1;
+ } else {
+ mcore->flash_window = 0x1fc00000;
+ mcore->flash_window_size = 0x00400000;
+ }
+}
+
+u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+ u32 pll_type, n, m, rate = 0;
+
+ if (bus->extif.dev) {
+ ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
+ } else if (bus->chipco.dev) {
+ ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
+ } else
+ return 0;
+
+ if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
+ rate = 200000000;
+ } else {
+ rate = ssb_calc_clock_rate(pll_type, n, m);
+ }
+
+ if (pll_type == SSB_PLLTYPE_6) {
+ rate *= 2;
+ }
+
+ return rate;
+}
+
+void ssb_mipscore_init(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+ struct ssb_device *dev;
+ unsigned long hz, ns;
+ unsigned int irq, i;
+
+ if (!mcore->dev)
+ return; /* We don't have a MIPS core */
+
+ ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
+
+ hz = ssb_clockspeed(bus);
+ if (!hz)
+ hz = 100000000;
+ ns = 1000000000 / hz;
+
+ if (bus->extif.dev)
+ ssb_extif_timing_init(&bus->extif, ns);
+ else if (bus->chipco.dev)
+ ssb_chipco_timing_init(&bus->chipco, ns);
+
+ /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
+ for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ dev->irq = ssb_mips_irq(dev) + 2;
+ switch (dev->id.coreid) {
+ case SSB_DEV_USB11_HOST:
+ /* shouldn't need a separate irq line for non-4710, most of them have a proper
+ * external usb controller on the pci */
+ if ((bus->chip_id == 0x4710) && (irq <= 4)) {
+ set_irq(dev, irq++);
+ break;
+ }
+ /* fallthrough */
+ case SSB_DEV_PCI:
+ case SSB_DEV_ETHERNET:
+ case SSB_DEV_80211:
+ case SSB_DEV_USB20_HOST:
+ /* These devices get their own IRQ line if available, the rest goes on IRQ0 */
+ if (irq <= 4) {
+ set_irq(dev, irq++);
+ break;
+ }
+ }
+ }
+
+ ssb_mips_serial_init(mcore);
+ ssb_mips_flash_detect(mcore);
+}
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
new file mode 100644
index 000000000000..2faaa906d5d6
--- /dev/null
+++ b/drivers/ssb/driver_pcicore.c
@@ -0,0 +1,576 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom PCI-core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "ssb_private.h"
+
+
+static inline
+u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
+{
+ return ssb_read32(pc->dev, offset);
+}
+
+static inline
+void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
+{
+ ssb_write32(pc->dev, offset, value);
+}
+
+/**************************************************
+ * Code for hostmode operation.
+ **************************************************/
+
+#ifdef CONFIG_SSB_PCICORE_HOSTMODE
+
+#include <asm/paccess.h>
+/* Probe a 32bit value on the bus and catch bus exceptions.
+ * Returns nonzero on a bus exception.
+ * This is MIPS specific */
+#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
+
+/* Assume one-hot slot wiring */
+#define SSB_PCI_SLOT_MAX 16
+
+/* Global lock is OK, as we won't have more than one extpci anyway. */
+static DEFINE_SPINLOCK(cfgspace_lock);
+/* Core to access the external PCI config space. Can only have one. */
+static struct ssb_pcicore *extpci_core;
+
+static u32 ssb_pcicore_pcibus_iobase = 0x100;
+static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
+
+int pcibios_plat_dev_init(struct pci_dev *d)
+{
+ struct resource *res;
+ int pos, size;
+ u32 *base;
+
+ ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
+ pci_name(d));
+
+ /* Fix up resource bases */
+ for (pos = 0; pos < 6; pos++) {
+ res = &d->resource[pos];
+ if (res->flags & IORESOURCE_IO)
+ base = &ssb_pcicore_pcibus_iobase;
+ else
+ base = &ssb_pcicore_pcibus_membase;
+ if (res->end) {
+ size = res->end - res->start + 1;
+ if (*base & (size - 1))
+ *base = (*base + size) & ~(size - 1);
+ res->start = *base;
+ res->end = res->start + size - 1;
+ *base += size;
+ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
+ }
+ /* Fix up PCI bridge BAR0 only */
+ if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
+ break;
+ }
+ /* Fix up interrupt lines */
+ d->irq = ssb_mips_irq(extpci_core->dev) + 2;
+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
+
+ return 0;
+}
+
+static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
+{
+ if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
+ return;
+
+ ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
+
+ /* Enable PCI bridge bus mastering and memory space */
+ pci_set_master(dev);
+ pcibios_enable_device(dev, ~0);
+
+ /* Enable PCI bridge BAR1 prefetch and burst */
+ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
+
+ /* Make sure our latency is high enough to handle the devices behind us */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return ssb_mips_irq(extpci_core->dev) + 2;
+}
+
+static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
+ unsigned int bus, unsigned int dev,
+ unsigned int func, unsigned int off)
+{
+ u32 addr = 0;
+ u32 tmp;
+
+ if (unlikely(pc->cardbusmode && dev > 1))
+ goto out;
+ if (bus == 0) {
+ /* Type 0 transaction */
+ if (unlikely(dev >= SSB_PCI_SLOT_MAX))
+ goto out;
+ /* Slide the window */
+ tmp = SSB_PCICORE_SBTOPCI_CFG0;
+ tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK);
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp);
+ /* Calculate the address */
+ addr = SSB_PCI_CFG;
+ addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK);
+ addr |= (func << 8);
+ addr |= (off & ~3);
+ } else {
+ /* Type 1 transaction */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
+ SSB_PCICORE_SBTOPCI_CFG1);
+ /* Calculate the address */
+ addr = SSB_PCI_CFG;
+ addr |= (bus << 16);
+ addr |= (dev << 11);
+ addr |= (func << 8);
+ addr |= (off & ~3);
+ }
+out:
+ return addr;
+}
+
+static int ssb_extpci_read_config(struct ssb_pcicore *pc,
+ unsigned int bus, unsigned int dev,
+ unsigned int func, unsigned int off,
+ void *buf, int len)
+{
+ int err = -EINVAL;
+ u32 addr, val;
+ void __iomem *mmio;
+
+ SSB_WARN_ON(!pc->hostmode);
+ if (unlikely(len != 1 && len != 2 && len != 4))
+ goto out;
+ addr = get_cfgspace_addr(pc, bus, dev, func, off);
+ if (unlikely(!addr))
+ goto out;
+ err = -ENOMEM;
+ mmio = ioremap_nocache(addr, len);
+ if (!mmio)
+ goto out;
+
+ if (mips_busprobe32(val, mmio)) {
+ val = 0xffffffff;
+ goto unmap;
+ }
+
+ val = readl(mmio);
+ val >>= (8 * (off & 3));
+
+ switch (len) {
+ case 1:
+ *((u8 *)buf) = (u8)val;
+ break;
+ case 2:
+ *((u16 *)buf) = (u16)val;
+ break;
+ case 4:
+ *((u32 *)buf) = (u32)val;
+ break;
+ }
+ err = 0;
+unmap:
+ iounmap(mmio);
+out:
+ return err;
+}
+
+static int ssb_extpci_write_config(struct ssb_pcicore *pc,
+ unsigned int bus, unsigned int dev,
+ unsigned int func, unsigned int off,
+ const void *buf, int len)
+{
+ int err = -EINVAL;
+ u32 addr, val = 0;
+ void __iomem *mmio;
+
+ SSB_WARN_ON(!pc->hostmode);
+ if (unlikely(len != 1 && len != 2 && len != 4))
+ goto out;
+ addr = get_cfgspace_addr(pc, bus, dev, func, off);
+ if (unlikely(!addr))
+ goto out;
+ err = -ENOMEM;
+ mmio = ioremap_nocache(addr, len);
+ if (!mmio)
+ goto out;
+
+ if (mips_busprobe32(val, mmio)) {
+ val = 0xffffffff;
+ goto unmap;
+ }
+
+ switch (len) {
+ case 1:
+ val = readl(mmio);
+ val &= ~(0xFF << (8 * (off & 3)));
+ val |= *((const u8 *)buf) << (8 * (off & 3));
+ break;
+ case 2:
+ val = readl(mmio);
+ val &= ~(0xFFFF << (8 * (off & 3)));
+ val |= *((const u16 *)buf) << (8 * (off & 3));
+ break;
+ case 4:
+ val = *((const u32 *)buf);
+ break;
+ }
+ writel(val, mmio);
+
+ err = 0;
+unmap:
+ iounmap(mmio);
+out:
+ return err;
+}
+
+static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&cfgspace_lock, flags);
+ err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), reg, val, size);
+ spin_unlock_irqrestore(&cfgspace_lock, flags);
+
+ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&cfgspace_lock, flags);
+ err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), reg, &val, size);
+ spin_unlock_irqrestore(&cfgspace_lock, flags);
+
+ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops ssb_pcicore_pciops = {
+ .read = ssb_pcicore_read_config,
+ .write = ssb_pcicore_write_config,
+};
+
+static struct resource ssb_pcicore_mem_resource = {
+ .name = "SSB PCIcore external memory",
+ .start = SSB_PCI_DMA,
+ .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource ssb_pcicore_io_resource = {
+ .name = "SSB PCIcore external I/O",
+ .start = 0x100,
+ .end = 0x7FF,
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller ssb_pcicore_controller = {
+ .pci_ops = &ssb_pcicore_pciops,
+ .io_resource = &ssb_pcicore_io_resource,
+ .mem_resource = &ssb_pcicore_mem_resource,
+ .mem_offset = 0x24000000,
+};
+
+static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
+{
+ u32 val;
+
+ if (WARN_ON(extpci_core))
+ return;
+ extpci_core = pc;
+
+ ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
+ /* Reset devices on the external PCI bus */
+ val = SSB_PCICORE_CTL_RST_OE;
+ val |= SSB_PCICORE_CTL_CLK_OE;
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
+ val |= SSB_PCICORE_CTL_CLK; /* Clock on */
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
+ udelay(150); /* Assertion time demanded by the PCI standard */
+ val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
+ val = SSB_PCICORE_ARBCTL_INTERN;
+ pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
+ udelay(1); /* Assertion time demanded by the PCI standard */
+
+ /*TODO cardbus mode */
+
+ /* 64MB I/O window */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
+ SSB_PCICORE_SBTOPCI_IO);
+ /* 64MB config space */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
+ SSB_PCICORE_SBTOPCI_CFG0);
+ /* 1GB memory window */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
+ SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
+
+ /* Enable PCI bridge BAR0 prefetch and burst */
+ val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
+ /* Clear error conditions */
+ val = 0;
+ ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);
+
+ /* Enable PCI interrupts */
+ pcicore_write32(pc, SSB_PCICORE_IMASK,
+ SSB_PCICORE_IMASK_INTA);
+
+ /* Ok, ready to run, register it to the system.
+ * The following needs change, if we want to port hostmode
+ * to non-MIPS platform. */
+ set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
+ /* Give some time to the PCI controller to configure itself with the new
+ * values. Not waiting at this point causes crashes of the machine. */
+ mdelay(10);
+ register_pci_controller(&ssb_pcicore_controller);
+}
+
+static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
+{
+ struct ssb_bus *bus = pc->dev->bus;
+ u16 chipid_top;
+ u32 tmp;
+
+ chipid_top = (bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 &&
+ chipid_top != 0x5300)
+ return 0;
+
+ if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ return 0;
+
+ /* The 200-pin BCM4712 package does not bond out PCI. Even when
+ * PCI is bonded out, some boards may leave the pins floating. */
+ if (bus->chip_id == 0x4712) {
+ if (bus->chip_package == SSB_CHIPPACK_BCM4712S)
+ return 0;
+ if (bus->chip_package == SSB_CHIPPACK_BCM4712M)
+ return 0;
+ }
+ if (bus->chip_id == 0x5350)
+ return 0;
+
+ return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE)));
+}
+#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+
+
+/**************************************************
+ * Generic and Clientmode operation code.
+ **************************************************/
+
+static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+{
+ /* Disable PCI interrupts. */
+ ssb_write32(pc->dev, SSB_INTVEC, 0);
+}
+
+void ssb_pcicore_init(struct ssb_pcicore *pc)
+{
+ struct ssb_device *dev = pc->dev;
+ struct ssb_bus *bus;
+
+ if (!dev)
+ return;
+ bus = dev->bus;
+ if (!ssb_device_is_enabled(dev))
+ ssb_device_enable(dev, 0);
+
+#ifdef CONFIG_SSB_PCICORE_HOSTMODE
+ pc->hostmode = pcicore_is_in_hostmode(pc);
+ if (pc->hostmode)
+ ssb_pcicore_init_hostmode(pc);
+#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+ if (!pc->hostmode)
+ ssb_pcicore_init_clientmode(pc);
+}
+
+static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
+{
+ pcicore_write32(pc, 0x130, address);
+ return pcicore_read32(pc, 0x134);
+}
+
+static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
+{
+ pcicore_write32(pc, 0x130, address);
+ pcicore_write32(pc, 0x134, data);
+}
+
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+ u8 address, u16 data)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ u32 v;
+ int i;
+
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ v |= data;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < 10; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
+}
+
+static void ssb_broadcast_value(struct ssb_device *dev,
+ u32 address, u32 data)
+{
+ /* This is used for both, PCI and ChipCommon core, so be careful. */
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
+
+ ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
+ ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
+ ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
+ ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
+}
+
+static void ssb_commit_settings(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+
+ dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
+ if (WARN_ON(!dev))
+ return;
+ /* This forces an update of the cached registers. */
+ ssb_broadcast_value(dev, 0xFD8, 0);
+}
+
+int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
+ struct ssb_device *dev)
+{
+ struct ssb_device *pdev = pc->dev;
+ struct ssb_bus *bus;
+ int err = 0;
+ u32 tmp;
+
+ might_sleep();
+
+ if (!pdev)
+ goto out;
+ bus = pdev->bus;
+
+ /* Enable interrupts for this device. */
+ if (bus->host_pci &&
+ ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
+ u32 coremask;
+
+ /* Calculate the "coremask" for the device. */
+ coremask = (1 << dev->core_index);
+
+ err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
+ if (err)
+ goto out;
+ tmp |= coremask << 8;
+ err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp);
+ if (err)
+ goto out;
+ } else {
+ u32 intvec;
+
+ intvec = ssb_read32(pdev, SSB_INTVEC);
+ if ((bus->chip_id & 0xFF00) == 0x4400) {
+ /* Workaround: On the BCM44XX the BPFLAG routing
+ * bit is wrong. Use a hardcoded constant. */
+ intvec |= 0x00000002;
+ } else {
+ tmp = ssb_read32(dev, SSB_TPSFLAG);
+ tmp &= SSB_TPSFLAG_BPFLAG;
+ intvec |= tmp;
+ }
+ ssb_write32(pdev, SSB_INTVEC, intvec);
+ }
+
+ /* Setup PCIcore operation. */
+ if (pc->setup_done)
+ goto out;
+ if (pdev->id.coreid == SSB_DEV_PCI) {
+ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+ tmp |= SSB_PCICORE_SBTOPCI_PREF;
+ tmp |= SSB_PCICORE_SBTOPCI_BURST;
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+
+ if (pdev->id.revision < 5) {
+ tmp = ssb_read32(pdev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ tmp |= 2;
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
+ ssb_write32(pdev, SSB_IMCFGLO, tmp);
+ ssb_commit_settings(bus);
+ } else if (pdev->id.revision >= 11) {
+ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+ tmp |= SSB_PCICORE_SBTOPCI_MRM;
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+ }
+ } else {
+ WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
+ //TODO: Better make defines for all these magic PCIE values.
+ if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
+ /* TLP Workaround register. */
+ tmp = ssb_pcie_read(pc, 0x4);
+ tmp |= 0x8;
+ ssb_pcie_write(pc, 0x4, tmp);
+ }
+ if (pdev->id.revision == 0) {
+ const u8 serdes_rx_device = 0x1F;
+
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 2 /* Timer */, 0x8128);
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 6 /* CDR */, 0x0100);
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 7 /* CDR BW */, 0x1466);
+ } else if (pdev->id.revision == 1) {
+ /* DLLP Link Control register. */
+ tmp = ssb_pcie_read(pc, 0x100);
+ tmp |= 0x40;
+ ssb_pcie_write(pc, 0x100, tmp);
+ }
+ }
+ pc->setup_done = 1;
+out:
+ return err;
+}
+EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
new file mode 100644
index 000000000000..74d5182db4b2
--- /dev/null
+++ b/drivers/ssb/main.c
@@ -0,0 +1,1162 @@
+/*
+ * Sonics Silicon Backplane
+ * Subsystem core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "ssb_private.h"
+
+#include <linux/delay.h>
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+
+MODULE_DESCRIPTION("Sonics Silicon Backplane driver");
+MODULE_LICENSE("GPL");
+
+
+/* Temporary list of yet-to-be-attached buses */
+static LIST_HEAD(attach_queue);
+/* List if running buses */
+static LIST_HEAD(buses);
+/* Software ID counter */
+static unsigned int next_busnumber;
+/* buses_mutes locks the two buslists and the next_busnumber.
+ * Don't lock this directly, but use ssb_buses_[un]lock() below. */
+static DEFINE_MUTEX(buses_mutex);
+
+/* There are differences in the codeflow, if the bus is
+ * initialized from early boot, as various needed services
+ * are not available early. This is a mechanism to delay
+ * these initializations to after early boot has finished.
+ * It's also used to avoid mutex locking, as that's not
+ * available and needed early. */
+static bool ssb_is_early_boot = 1;
+
+static void ssb_buses_lock(void);
+static void ssb_buses_unlock(void);
+
+
+#ifdef CONFIG_SSB_PCIHOST
+struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev)
+{
+ struct ssb_bus *bus;
+
+ ssb_buses_lock();
+ list_for_each_entry(bus, &buses, list) {
+ if (bus->bustype == SSB_BUSTYPE_PCI &&
+ bus->host_pci == pdev)
+ goto found;
+ }
+ bus = NULL;
+found:
+ ssb_buses_unlock();
+
+ return bus;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+static struct ssb_device *ssb_device_get(struct ssb_device *dev)
+{
+ if (dev)
+ get_device(dev->dev);
+ return dev;
+}
+
+static void ssb_device_put(struct ssb_device *dev)
+{
+ if (dev)
+ put_device(dev->dev);
+}
+
+static int ssb_bus_resume(struct ssb_bus *bus)
+{
+ int err;
+
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ err = ssb_pcmcia_init(bus);
+ if (err) {
+ /* No need to disable XTAL, as we don't have one on PCMCIA. */
+ return err;
+ }
+ ssb_chipco_resume(&bus->chipco);
+
+ return 0;
+}
+
+static int ssb_device_resume(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv;
+ struct ssb_bus *bus;
+ int err = 0;
+
+ bus = ssb_dev->bus;
+ if (bus->suspend_cnt == bus->nr_devices) {
+ err = ssb_bus_resume(bus);
+ if (err)
+ return err;
+ }
+ bus->suspend_cnt--;
+ if (dev->driver) {
+ ssb_drv = drv_to_ssb_drv(dev->driver);
+ if (ssb_drv && ssb_drv->resume)
+ err = ssb_drv->resume(ssb_dev);
+ if (err)
+ goto out;
+ }
+out:
+ return err;
+}
+
+static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state)
+{
+ ssb_chipco_suspend(&bus->chipco, state);
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+
+ /* Reset HW state information in memory, so that HW is
+ * completely reinitialized on resume. */
+ bus->mapped_device = NULL;
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ bus->pcicore.setup_done = 0;
+#endif
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 0;
+#endif
+}
+
+static int ssb_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv;
+ struct ssb_bus *bus;
+ int err = 0;
+
+ if (dev->driver) {
+ ssb_drv = drv_to_ssb_drv(dev->driver);
+ if (ssb_drv && ssb_drv->suspend)
+ err = ssb_drv->suspend(ssb_dev, state);
+ if (err)
+ goto out;
+ }
+
+ bus = ssb_dev->bus;
+ bus->suspend_cnt++;
+ if (bus->suspend_cnt == bus->nr_devices) {
+ /* All devices suspended. Shutdown the bus. */
+ ssb_bus_suspend(bus, state);
+ }
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_SSB_PCIHOST
+int ssb_devices_freeze(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+ struct ssb_driver *drv;
+ int err = 0;
+ int i;
+ pm_message_t state = PMSG_FREEZE;
+
+ /* First check that we are capable to freeze all devices. */
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ if (!drv->suspend) {
+ /* Nope, can't suspend this one. */
+ return -EOPNOTSUPP;
+ }
+ }
+ /* Now suspend all devices */
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ err = drv->suspend(dev, state);
+ if (err) {
+ ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
+ dev->dev->bus_id);
+ goto err_unwind;
+ }
+ }
+
+ return 0;
+err_unwind:
+ for (i--; i >= 0; i--) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ if (drv->resume)
+ drv->resume(dev);
+ }
+ return err;
+}
+
+int ssb_devices_thaw(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+ struct ssb_driver *drv;
+ int err;
+ int i;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ if (SSB_WARN_ON(!drv->resume))
+ continue;
+ err = drv->resume(dev);
+ if (err) {
+ ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
+ dev->dev->bus_id);
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+static void ssb_device_shutdown(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv;
+
+ if (!dev->driver)
+ return;
+ ssb_drv = drv_to_ssb_drv(dev->driver);
+ if (ssb_drv && ssb_drv->shutdown)
+ ssb_drv->shutdown(ssb_dev);
+}
+
+static int ssb_device_remove(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver);
+
+ if (ssb_drv && ssb_drv->remove)
+ ssb_drv->remove(ssb_dev);
+ ssb_device_put(ssb_dev);
+
+ return 0;
+}
+
+static int ssb_device_probe(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver);
+ int err = 0;
+
+ ssb_device_get(ssb_dev);
+ if (ssb_drv && ssb_drv->probe)
+ err = ssb_drv->probe(ssb_dev, &ssb_dev->id);
+ if (err)
+ ssb_device_put(ssb_dev);
+
+ return err;
+}
+
+static int ssb_match_devid(const struct ssb_device_id *tabid,
+ const struct ssb_device_id *devid)
+{
+ if ((tabid->vendor != devid->vendor) &&
+ tabid->vendor != SSB_ANY_VENDOR)
+ return 0;
+ if ((tabid->coreid != devid->coreid) &&
+ tabid->coreid != SSB_ANY_ID)
+ return 0;
+ if ((tabid->revision != devid->revision) &&
+ tabid->revision != SSB_ANY_REV)
+ return 0;
+ return 1;
+}
+
+static int ssb_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv);
+ const struct ssb_device_id *id;
+
+ for (id = ssb_drv->id_table;
+ id->vendor || id->coreid || id->revision;
+ id++) {
+ if (ssb_match_devid(id, &ssb_dev->id))
+ return 1; /* found */
+ }
+
+ return 0;
+}
+
+static int ssb_device_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ int ret, i = 0, length = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ ret = add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS=ssb:v%04Xid%04Xrev%02X",
+ ssb_dev->id.vendor, ssb_dev->id.coreid,
+ ssb_dev->id.revision);
+ envp[i] = NULL;
+
+ return ret;
+}
+
+static struct bus_type ssb_bustype = {
+ .name = "ssb",
+ .match = ssb_bus_match,
+ .probe = ssb_device_probe,
+ .remove = ssb_device_remove,
+ .shutdown = ssb_device_shutdown,
+ .suspend = ssb_device_suspend,
+ .resume = ssb_device_resume,
+ .uevent = ssb_device_uevent,
+};
+
+static void ssb_buses_lock(void)
+{
+ /* See the comment at the ssb_is_early_boot definition */
+ if (!ssb_is_early_boot)
+ mutex_lock(&buses_mutex);
+}
+
+static void ssb_buses_unlock(void)
+{
+ /* See the comment at the ssb_is_early_boot definition */
+ if (!ssb_is_early_boot)
+ mutex_unlock(&buses_mutex);
+}
+
+static void ssb_devices_unregister(struct ssb_bus *bus)
+{
+ struct ssb_device *sdev;
+ int i;
+
+ for (i = bus->nr_devices - 1; i >= 0; i--) {
+ sdev = &(bus->devices[i]);
+ if (sdev->dev)
+ device_unregister(sdev->dev);
+ }
+}
+
+void ssb_bus_unregister(struct ssb_bus *bus)
+{
+ ssb_buses_lock();
+ ssb_devices_unregister(bus);
+ list_del(&bus->list);
+ ssb_buses_unlock();
+
+ /* ssb_pcmcia_exit(bus); */
+ ssb_pci_exit(bus);
+ ssb_iounmap(bus);
+}
+EXPORT_SYMBOL(ssb_bus_unregister);
+
+static void ssb_release_dev(struct device *dev)
+{
+ struct __ssb_dev_wrapper *devwrap;
+
+ devwrap = container_of(dev, struct __ssb_dev_wrapper, dev);
+ kfree(devwrap);
+}
+
+static int ssb_devices_register(struct ssb_bus *bus)
+{
+ struct ssb_device *sdev;
+ struct device *dev;
+ struct __ssb_dev_wrapper *devwrap;
+ int i, err = 0;
+ int dev_idx = 0;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ sdev = &(bus->devices[i]);
+
+ /* We don't register SSB-system devices to the kernel,
+ * as the drivers for them are built into SSB. */
+ switch (sdev->id.coreid) {
+ case SSB_DEV_CHIPCOMMON:
+ case SSB_DEV_PCI:
+ case SSB_DEV_PCIE:
+ case SSB_DEV_PCMCIA:
+ case SSB_DEV_MIPS:
+ case SSB_DEV_MIPS_3302:
+ case SSB_DEV_EXTIF:
+ continue;
+ }
+
+ devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);
+ if (!devwrap) {
+ ssb_printk(KERN_ERR PFX
+ "Could not allocate device\n");
+ err = -ENOMEM;
+ goto error;
+ }
+ dev = &devwrap->dev;
+ devwrap->sdev = sdev;
+
+ dev->release = ssb_release_dev;
+ dev->bus = &ssb_bustype;
+ snprintf(dev->bus_id, sizeof(dev->bus_id),
+ "ssb%u:%d", bus->busnumber, dev_idx);
+
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+ sdev->irq = bus->host_pci->irq;
+ dev->parent = &bus->host_pci->dev;
+#endif
+ break;
+ case SSB_BUSTYPE_PCMCIA:
+#ifdef CONFIG_SSB_PCMCIAHOST
+ dev->parent = &bus->host_pcmcia->dev;
+#endif
+ break;
+ case SSB_BUSTYPE_SSB:
+ break;
+ }
+
+ sdev->dev = dev;
+ err = device_register(dev);
+ if (err) {
+ ssb_printk(KERN_ERR PFX
+ "Could not register %s\n",
+ dev->bus_id);
+ /* Set dev to NULL to not unregister
+ * dev on error unwinding. */
+ sdev->dev = NULL;
+ kfree(devwrap);
+ goto error;
+ }
+ dev_idx++;
+ }
+
+ return 0;
+error:
+ /* Unwind the already registered devices. */
+ ssb_devices_unregister(bus);
+ return err;
+}
+
+/* Needs ssb_buses_lock() */
+static int ssb_attach_queued_buses(void)
+{
+ struct ssb_bus *bus, *n;
+ int err = 0;
+ int drop_them_all = 0;
+
+ list_for_each_entry_safe(bus, n, &attach_queue, list) {
+ if (drop_them_all) {
+ list_del(&bus->list);
+ continue;
+ }
+ /* Can't init the PCIcore in ssb_bus_register(), as that
+ * is too early in boot for embedded systems
+ * (no udelay() available). So do it here in attach stage.
+ */
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto error;
+ ssb_pcicore_init(&bus->pcicore);
+ ssb_bus_may_powerdown(bus);
+
+ err = ssb_devices_register(bus);
+error:
+ if (err) {
+ drop_them_all = 1;
+ list_del(&bus->list);
+ continue;
+ }
+ list_move_tail(&bus->list, &buses);
+ }
+
+ return err;
+}
+
+static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readw(bus->mmio + offset);
+}
+
+static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readl(bus->mmio + offset);
+}
+
+static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writew(value, bus->mmio + offset);
+}
+
+static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writel(value, bus->mmio + offset);
+}
+
+/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
+static const struct ssb_bus_ops ssb_ssb_ops = {
+ .read16 = ssb_ssb_read16,
+ .read32 = ssb_ssb_read32,
+ .write16 = ssb_ssb_write16,
+ .write32 = ssb_ssb_write32,
+};
+
+static int ssb_fetch_invariants(struct ssb_bus *bus,
+ ssb_invariants_func_t get_invariants)
+{
+ struct ssb_init_invariants iv;
+ int err;
+
+ memset(&iv, 0, sizeof(iv));
+ err = get_invariants(bus, &iv);
+ if (err)
+ goto out;
+ memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo));
+ memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom));
+out:
+ return err;
+}
+
+static int ssb_bus_register(struct ssb_bus *bus,
+ ssb_invariants_func_t get_invariants,
+ unsigned long baseaddr)
+{
+ int err;
+
+ spin_lock_init(&bus->bar_lock);
+ INIT_LIST_HEAD(&bus->list);
+
+ /* Powerup the bus */
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ if (err)
+ goto out;
+ ssb_buses_lock();
+ bus->busnumber = next_busnumber;
+ /* Scan for devices (cores) */
+ err = ssb_bus_scan(bus, baseaddr);
+ if (err)
+ goto err_disable_xtal;
+
+ /* Init PCI-host device (if any) */
+ err = ssb_pci_init(bus);
+ if (err)
+ goto err_unmap;
+ /* Init PCMCIA-host device (if any) */
+ err = ssb_pcmcia_init(bus);
+ if (err)
+ goto err_pci_exit;
+
+ /* Initialize basic system devices (if available) */
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto err_pcmcia_exit;
+ ssb_chipcommon_init(&bus->chipco);
+ ssb_mipscore_init(&bus->mipscore);
+ err = ssb_fetch_invariants(bus, get_invariants);
+ if (err) {
+ ssb_bus_may_powerdown(bus);
+ goto err_pcmcia_exit;
+ }
+ ssb_bus_may_powerdown(bus);
+
+ /* Queue it for attach.
+ * See the comment at the ssb_is_early_boot definition. */
+ list_add_tail(&bus->list, &attach_queue);
+ if (!ssb_is_early_boot) {
+ /* This is not early boot, so we must attach the bus now */
+ err = ssb_attach_queued_buses();
+ if (err)
+ goto err_dequeue;
+ }
+ next_busnumber++;
+ ssb_buses_unlock();
+
+out:
+ return err;
+
+err_dequeue:
+ list_del(&bus->list);
+err_pcmcia_exit:
+/* ssb_pcmcia_exit(bus); */
+err_pci_exit:
+ ssb_pci_exit(bus);
+err_unmap:
+ ssb_iounmap(bus);
+err_disable_xtal:
+ ssb_buses_unlock();
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+ return err;
+}
+
+#ifdef CONFIG_SSB_PCIHOST
+int ssb_bus_pcibus_register(struct ssb_bus *bus,
+ struct pci_dev *host_pci)
+{
+ int err;
+
+ bus->bustype = SSB_BUSTYPE_PCI;
+ bus->host_pci = host_pci;
+ bus->ops = &ssb_pci_ops;
+
+ err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
+ if (!err) {
+ ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+ "PCI device %s\n", host_pci->dev.bus_id);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(ssb_bus_pcibus_register);
+#endif /* CONFIG_SSB_PCIHOST */
+
+#ifdef CONFIG_SSB_PCMCIAHOST
+int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
+ struct pcmcia_device *pcmcia_dev,
+ unsigned long baseaddr)
+{
+ int err;
+
+ bus->bustype = SSB_BUSTYPE_PCMCIA;
+ bus->host_pcmcia = pcmcia_dev;
+ bus->ops = &ssb_pcmcia_ops;
+
+ err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
+ if (!err) {
+ ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+ "PCMCIA device %s\n", pcmcia_dev->devname);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+int ssb_bus_ssbbus_register(struct ssb_bus *bus,
+ unsigned long baseaddr,
+ ssb_invariants_func_t get_invariants)
+{
+ int err;
+
+ bus->bustype = SSB_BUSTYPE_SSB;
+ bus->ops = &ssb_ssb_ops;
+
+ err = ssb_bus_register(bus, get_invariants, baseaddr);
+ if (!err) {
+ ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at "
+ "address 0x%08lX\n", baseaddr);
+ }
+
+ return err;
+}
+
+int __ssb_driver_register(struct ssb_driver *drv, struct module *owner)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &ssb_bustype;
+ drv->drv.owner = owner;
+
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL(__ssb_driver_register);
+
+void ssb_driver_unregister(struct ssb_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL(ssb_driver_unregister);
+
+void ssb_set_devtypedata(struct ssb_device *dev, void *data)
+{
+ struct ssb_bus *bus = dev->bus;
+ struct ssb_device *ent;
+ int i;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ ent = &(bus->devices[i]);
+ if (ent->id.vendor != dev->id.vendor)
+ continue;
+ if (ent->id.coreid != dev->id.coreid)
+ continue;
+
+ ent->devtypedata = data;
+ }
+}
+EXPORT_SYMBOL(ssb_set_devtypedata);
+
+static u32 clkfactor_f6_resolve(u32 v)
+{
+ /* map the magic values */
+ switch (v) {
+ case SSB_CHIPCO_CLK_F6_2:
+ return 2;
+ case SSB_CHIPCO_CLK_F6_3:
+ return 3;
+ case SSB_CHIPCO_CLK_F6_4:
+ return 4;
+ case SSB_CHIPCO_CLK_F6_5:
+ return 5;
+ case SSB_CHIPCO_CLK_F6_6:
+ return 6;
+ case SSB_CHIPCO_CLK_F6_7:
+ return 7;
+ }
+ return 0;
+}
+
+/* Calculate the speed the backplane would run at a given set of clockcontrol values */
+u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m)
+{
+ u32 n1, n2, clock, m1, m2, m3, mc;
+
+ n1 = (n & SSB_CHIPCO_CLK_N1);
+ n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT);
+
+ switch (plltype) {
+ case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+ if (m & SSB_CHIPCO_CLK_T6_MMASK)
+ return SSB_CHIPCO_CLK_T6_M0;
+ return SSB_CHIPCO_CLK_T6_M1;
+ case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+ case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+ n1 = clkfactor_f6_resolve(n1);
+ n2 += SSB_CHIPCO_CLK_F5_BIAS;
+ break;
+ case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */
+ n1 += SSB_CHIPCO_CLK_T2_BIAS;
+ n2 += SSB_CHIPCO_CLK_T2_BIAS;
+ SSB_WARN_ON(!((n1 >= 2) && (n1 <= 7)));
+ SSB_WARN_ON(!((n2 >= 5) && (n2 <= 23)));
+ break;
+ case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */
+ return 100000000;
+ default:
+ SSB_WARN_ON(1);
+ }
+
+ switch (plltype) {
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+ clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2;
+ break;
+ default:
+ clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2;
+ }
+ if (!clock)
+ return 0;
+
+ m1 = (m & SSB_CHIPCO_CLK_M1);
+ m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT);
+ m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT);
+ mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT);
+
+ switch (plltype) {
+ case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+ case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+ m1 = clkfactor_f6_resolve(m1);
+ if ((plltype == SSB_PLLTYPE_1) ||
+ (plltype == SSB_PLLTYPE_3))
+ m2 += SSB_CHIPCO_CLK_F5_BIAS;
+ else
+ m2 = clkfactor_f6_resolve(m2);
+ m3 = clkfactor_f6_resolve(m3);
+
+ switch (mc) {
+ case SSB_CHIPCO_CLK_MC_BYPASS:
+ return clock;
+ case SSB_CHIPCO_CLK_MC_M1:
+ return (clock / m1);
+ case SSB_CHIPCO_CLK_MC_M1M2:
+ return (clock / (m1 * m2));
+ case SSB_CHIPCO_CLK_MC_M1M2M3:
+ return (clock / (m1 * m2 * m3));
+ case SSB_CHIPCO_CLK_MC_M1M3:
+ return (clock / (m1 * m3));
+ }
+ return 0;
+ case SSB_PLLTYPE_2:
+ m1 += SSB_CHIPCO_CLK_T2_BIAS;
+ m2 += SSB_CHIPCO_CLK_T2M2_BIAS;
+ m3 += SSB_CHIPCO_CLK_T2_BIAS;
+ SSB_WARN_ON(!((m1 >= 2) && (m1 <= 7)));
+ SSB_WARN_ON(!((m2 >= 3) && (m2 <= 10)));
+ SSB_WARN_ON(!((m3 >= 2) && (m3 <= 7)));
+
+ if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP))
+ clock /= m1;
+ if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP))
+ clock /= m2;
+ if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP))
+ clock /= m3;
+ return clock;
+ default:
+ SSB_WARN_ON(1);
+ }
+ return 0;
+}
+
+/* Get the current speed the backplane is running at */
+u32 ssb_clockspeed(struct ssb_bus *bus)
+{
+ u32 rate;
+ u32 plltype;
+ u32 clkctl_n, clkctl_m;
+
+ if (ssb_extif_available(&bus->extif))
+ ssb_extif_get_clockcontrol(&bus->extif, &plltype,
+ &clkctl_n, &clkctl_m);
+ else if (bus->chipco.dev)
+ ssb_chipco_get_clockcontrol(&bus->chipco, &plltype,
+ &clkctl_n, &clkctl_m);
+ else
+ return 0;
+
+ if (bus->chip_id == 0x5365) {
+ rate = 100000000;
+ } else {
+ rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m);
+ if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */
+ rate /= 2;
+ }
+
+ return rate;
+}
+EXPORT_SYMBOL(ssb_clockspeed);
+
+static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
+{
+ /* The REJECT bit changed position in TMSLOW between
+ * Backplane revisions. */
+ switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) {
+ case SSB_IDLOW_SSBREV_22:
+ return SSB_TMSLOW_REJECT_22;
+ case SSB_IDLOW_SSBREV_23:
+ return SSB_TMSLOW_REJECT_23;
+ default:
+ WARN_ON(1);
+ }
+ return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
+}
+
+int ssb_device_is_enabled(struct ssb_device *dev)
+{
+ u32 val;
+ u32 reject;
+
+ reject = ssb_tmslow_reject_bitmask(dev);
+ val = ssb_read32(dev, SSB_TMSLOW);
+ val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject;
+
+ return (val == SSB_TMSLOW_CLOCK);
+}
+EXPORT_SYMBOL(ssb_device_is_enabled);
+
+static void ssb_flush_tmslow(struct ssb_device *dev)
+{
+ /* Make _really_ sure the device has finished the TMSLOW
+ * register write transaction, as we risk running into
+ * a machine check exception otherwise.
+ * Do this by reading the register back to commit the
+ * PCI write and delay an additional usec for the device
+ * to react to the change. */
+ ssb_read32(dev, SSB_TMSLOW);
+ udelay(1);
+}
+
+void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags)
+{
+ u32 val;
+
+ ssb_device_disable(dev, core_specific_flags);
+ ssb_write32(dev, SSB_TMSLOW,
+ SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK |
+ SSB_TMSLOW_FGC | core_specific_flags);
+ ssb_flush_tmslow(dev);
+
+ /* Clear SERR if set. This is a hw bug workaround. */
+ if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR)
+ ssb_write32(dev, SSB_TMSHIGH, 0);
+
+ val = ssb_read32(dev, SSB_IMSTATE);
+ if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) {
+ val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO);
+ ssb_write32(dev, SSB_IMSTATE, val);
+ }
+
+ ssb_write32(dev, SSB_TMSLOW,
+ SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+
+ ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+}
+EXPORT_SYMBOL(ssb_device_enable);
+
+/* Wait for a bit in a register to get set or unset.
+ * timeout is in units of ten-microseconds */
+static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+ int timeout, int set)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < timeout; i++) {
+ val = ssb_read32(dev, reg);
+ if (set) {
+ if (val & bitmask)
+ return 0;
+ } else {
+ if (!(val & bitmask))
+ return 0;
+ }
+ udelay(10);
+ }
+ printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on "
+ "register %04X to %s.\n",
+ bitmask, reg, (set ? "set" : "clear"));
+
+ return -ETIMEDOUT;
+}
+
+void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+{
+ u32 reject;
+
+ if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ return;
+
+ reject = ssb_tmslow_reject_bitmask(dev);
+ ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+ ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+ ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+ ssb_write32(dev, SSB_TMSLOW,
+ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+ reject | SSB_TMSLOW_RESET |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+
+ ssb_write32(dev, SSB_TMSLOW,
+ reject | SSB_TMSLOW_RESET |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+}
+EXPORT_SYMBOL(ssb_device_disable);
+
+u32 ssb_dma_translation(struct ssb_device *dev)
+{
+ switch (dev->bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ return 0;
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ return SSB_PCI_DMA;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(ssb_dma_translation);
+
+int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
+{
+ struct device *dev = ssb_dev->dev;
+
+#ifdef CONFIG_SSB_PCIHOST
+ if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI &&
+ !dma_supported(dev, mask))
+ return -EIO;
+#endif
+ dev->coherent_dma_mask = mask;
+ dev->dma_mask = &dev->coherent_dma_mask;
+
+ return 0;
+}
+EXPORT_SYMBOL(ssb_dma_set_mask);
+
+int ssb_bus_may_powerdown(struct ssb_bus *bus)
+{
+ struct ssb_chipcommon *cc;
+ int err = 0;
+
+ /* On buses where more than one core may be working
+ * at a time, we must not powerdown stuff if there are
+ * still cores that may want to run. */
+ if (bus->bustype == SSB_BUSTYPE_SSB)
+ goto out;
+
+ cc = &bus->chipco;
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+ if (err)
+ goto error;
+out:
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 0;
+#endif
+ return err;
+error:
+ ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
+ goto out;
+}
+EXPORT_SYMBOL(ssb_bus_may_powerdown);
+
+int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
+{
+ struct ssb_chipcommon *cc;
+ int err;
+ enum ssb_clkmode mode;
+
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ if (err)
+ goto error;
+ cc = &bus->chipco;
+ mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+ ssb_chipco_set_clockmode(cc, mode);
+
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 1;
+#endif
+ return 0;
+error:
+ ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+ return err;
+}
+EXPORT_SYMBOL(ssb_bus_powerup);
+
+u32 ssb_admatch_base(u32 adm)
+{
+ u32 base = 0;
+
+ switch (adm & SSB_ADM_TYPE) {
+ case SSB_ADM_TYPE0:
+ base = (adm & SSB_ADM_BASE0);
+ break;
+ case SSB_ADM_TYPE1:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ base = (adm & SSB_ADM_BASE1);
+ break;
+ case SSB_ADM_TYPE2:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ base = (adm & SSB_ADM_BASE2);
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+
+ return base;
+}
+EXPORT_SYMBOL(ssb_admatch_base);
+
+u32 ssb_admatch_size(u32 adm)
+{
+ u32 size = 0;
+
+ switch (adm & SSB_ADM_TYPE) {
+ case SSB_ADM_TYPE0:
+ size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT);
+ break;
+ case SSB_ADM_TYPE1:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT);
+ break;
+ case SSB_ADM_TYPE2:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT);
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+ size = (1 << (size + 1));
+
+ return size;
+}
+EXPORT_SYMBOL(ssb_admatch_size);
+
+static int __init ssb_modinit(void)
+{
+ int err;
+
+ /* See the comment at the ssb_is_early_boot definition */
+ ssb_is_early_boot = 0;
+ err = bus_register(&ssb_bustype);
+ if (err)
+ return err;
+
+ /* Maybe we already registered some buses at early boot.
+ * Check for this and attach them
+ */
+ ssb_buses_lock();
+ err = ssb_attach_queued_buses();
+ ssb_buses_unlock();
+ if (err)
+ bus_unregister(&ssb_bustype);
+
+ err = b43_pci_ssb_bridge_init();
+ if (err) {
+ ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
+ "initialization failed");
+ /* don't fail SSB init because of this */
+ err = 0;
+ }
+
+ return err;
+}
+subsys_initcall(ssb_modinit);
+
+static void __exit ssb_modexit(void)
+{
+ b43_pci_ssb_bridge_exit();
+ bus_unregister(&ssb_bustype);
+}
+module_exit(ssb_modexit)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
new file mode 100644
index 000000000000..0ab095c6581a
--- /dev/null
+++ b/drivers/ssb/pci.c
@@ -0,0 +1,740 @@
+/*
+ * Sonics Silicon Backplane PCI-Hostbus related functions.
+ *
+ * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ *
+ * Derived from the Broadcom 4400 device driver.
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "ssb_private.h"
+
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
+
+
+/* Lowlevel coreswitching */
+int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
+{
+ int err;
+ int attempts = 0;
+ u32 cur_core;
+
+ while (1) {
+ err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
+ (coreidx * SSB_CORE_SIZE)
+ + SSB_ENUM_BASE);
+ if (err)
+ goto error;
+ err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
+ &cur_core);
+ if (err)
+ goto error;
+ cur_core = (cur_core - SSB_ENUM_BASE)
+ / SSB_CORE_SIZE;
+ if (cur_core == coreidx)
+ break;
+
+ if (attempts++ > SSB_BAR0_MAX_RETRIES)
+ goto error;
+ udelay(10);
+ }
+ return 0;
+error:
+ ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+ return -ENODEV;
+}
+
+int ssb_pci_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ int err;
+ unsigned long flags;
+
+#if SSB_VERBOSE_PCICORESWITCH_DEBUG
+ ssb_printk(KERN_INFO PFX
+ "Switching to %s core, index %d\n",
+ ssb_core_name(dev->id.coreid),
+ dev->core_index);
+#endif
+
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ err = ssb_pci_switch_coreidx(bus, dev->core_index);
+ if (!err)
+ bus->mapped_device = dev;
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+ return err;
+}
+
+/* Enable/disable the on board crystal oscillator and/or PLL. */
+int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
+{
+ int err;
+ u32 in, out, outenable;
+ u16 pci_status;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return 0;
+
+ err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
+ if (err)
+ goto err_pci;
+ err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
+ if (err)
+ goto err_pci;
+ err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
+ if (err)
+ goto err_pci;
+
+ outenable |= what;
+
+ if (turn_on) {
+ /* Avoid glitching the clock if GPRS is already using it.
+ * We can't actually read the state of the PLLPD so we infer it
+ * by the value of XTAL_PU which *is* readable via gpioin.
+ */
+ if (!(in & SSB_GPIO_XTAL)) {
+ if (what & SSB_GPIO_XTAL) {
+ /* Turn the crystal on */
+ out |= SSB_GPIO_XTAL;
+ if (what & SSB_GPIO_PLL)
+ out |= SSB_GPIO_PLL;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+ if (err)
+ goto err_pci;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
+ outenable);
+ if (err)
+ goto err_pci;
+ msleep(1);
+ }
+ if (what & SSB_GPIO_PLL) {
+ /* Turn the PLL on */
+ out &= ~SSB_GPIO_PLL;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+ if (err)
+ goto err_pci;
+ msleep(5);
+ }
+ }
+
+ err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
+ if (err)
+ goto err_pci;
+ pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
+ err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
+ if (err)
+ goto err_pci;
+ } else {
+ if (what & SSB_GPIO_XTAL) {
+ /* Turn the crystal off */
+ out &= ~SSB_GPIO_XTAL;
+ }
+ if (what & SSB_GPIO_PLL) {
+ /* Turn the PLL off */
+ out |= SSB_GPIO_PLL;
+ }
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+ if (err)
+ goto err_pci;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
+ if (err)
+ goto err_pci;
+ }
+
+out:
+ return err;
+
+err_pci:
+ printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
+ err = -EBUSY;
+ goto out;
+}
+
+/* Get the word-offset for a SSB_SPROM_XXX define. */
+#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
+/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
+#define SPEX(_outvar, _offset, _mask, _shift) \
+ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+
+static inline u8 ssb_crc8(u8 crc, u8 data)
+{
+ /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
+ static const u8 t[] = {
+ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+ };
+ return t[crc ^ data];
+}
+
+static u8 ssb_sprom_crc(const u16 *sprom)
+{
+ int word;
+ u8 crc = 0xFF;
+
+ for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
+ crc = ssb_crc8(crc, sprom[word] & 0x00FF);
+ crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+ }
+ crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
+ crc ^= 0xFF;
+
+ return crc;
+}
+
+static int sprom_check_crc(const u16 *sprom)
+{
+ u8 crc;
+ u8 expected_crc;
+ u16 tmp;
+
+ crc = ssb_sprom_crc(sprom);
+ tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
+ expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+ if (crc != expected_crc)
+ return -EPROTO;
+
+ return 0;
+}
+
+static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
+{
+ int i;
+
+ for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
+ sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
+}
+
+static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
+{
+ struct pci_dev *pdev = bus->host_pci;
+ int i, err;
+ u32 spromctl;
+
+ ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+ err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+ if (err)
+ goto err_ctlreg;
+ spromctl |= SSB_SPROMCTL_WE;
+ err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+ if (err)
+ goto err_ctlreg;
+ ssb_printk(KERN_NOTICE PFX "[ 0%%");
+ msleep(500);
+ for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+ if (i == SSB_SPROMSIZE_WORDS / 4)
+ ssb_printk("25%%");
+ else if (i == SSB_SPROMSIZE_WORDS / 2)
+ ssb_printk("50%%");
+ else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
+ ssb_printk("75%%");
+ else if (i % 2)
+ ssb_printk(".");
+ writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
+ mmiowb();
+ msleep(20);
+ }
+ err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+ if (err)
+ goto err_ctlreg;
+ spromctl &= ~SSB_SPROMCTL_WE;
+ err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+ if (err)
+ goto err_ctlreg;
+ msleep(500);
+ ssb_printk("100%% ]\n");
+ ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+
+ return 0;
+err_ctlreg:
+ ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+ return err;
+}
+
+static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+{
+ int i;
+ u16 v;
+
+ SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
+ SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
+ SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
+ for (i = 0; i < 3; i++) {
+ v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
+ *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+ }
+ for (i = 0; i < 3; i++) {
+ v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
+ *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+ }
+ for (i = 0; i < 3; i++) {
+ v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
+ *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+ }
+ SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
+ SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
+ SSB_SPROM1_ETHPHY_ET1A_SHIFT);
+ SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
+ SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
+ SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+ SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
+ SSB_SPROM1_BINF_CCODE_SHIFT);
+ SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
+ SSB_SPROM1_BINF_ANTA_SHIFT);
+ SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
+ SSB_SPROM1_BINF_ANTBG_SHIFT);
+ SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
+ SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
+ SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
+ SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
+ SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
+ SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
+ SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
+ SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
+ SSB_SPROM1_GPIOA_P1_SHIFT);
+ SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
+ SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
+ SSB_SPROM1_GPIOB_P3_SHIFT);
+ SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
+ SSB_SPROM1_MAXPWR_A_SHIFT);
+ SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
+ SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
+ SSB_SPROM1_ITSSI_A_SHIFT);
+ SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
+ SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
+ SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
+ SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
+ SSB_SPROM1_AGAIN_BG_SHIFT);
+ for (i = 0; i < 4; i++) {
+ v = in[SPOFF(SSB_SPROM1_OEM) + i];
+ *(((__le16 *)out->oem) + i) = cpu_to_le16(v);
+ }
+}
+
+static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
+{
+ int i;
+ u16 v;
+
+ SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+ SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+ SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+ SSB_SPROM2_MAXP_A_LO_SHIFT);
+ SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+ SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+ SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+ SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+ SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+ SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+ SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+ for (i = 0; i < 4; i++) {
+ v = in[SPOFF(SSB_SPROM2_CCODE) + i];
+ *(((__le16 *)out->country_str) + i) = cpu_to_le16(v);
+ }
+}
+
+static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
+{
+ out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
+ out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
+ out->ofdmapo <<= 16;
+ out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
+ out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
+
+ out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
+ out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
+ out->ofdmalpo <<= 16;
+ out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
+ out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
+
+ out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
+ out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
+ out->ofdmahpo <<= 16;
+ out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
+ out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
+
+ SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
+ SSB_SPROM3_GPIOLDC_ON_SHIFT);
+ SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
+ SSB_SPROM3_GPIOLDC_OFF_SHIFT);
+ SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
+ SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
+ SSB_SPROM3_CCKPO_2M_SHIFT);
+ SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
+ SSB_SPROM3_CCKPO_55M_SHIFT);
+ SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
+ SSB_SPROM3_CCKPO_11M_SHIFT);
+
+ out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
+ out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
+ out->ofdmgpo <<= 16;
+ out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
+ out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
+}
+
+static int sprom_extract(struct ssb_bus *bus,
+ struct ssb_sprom *out, const u16 *in)
+{
+ memset(out, 0, sizeof(*out));
+
+ SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
+ SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
+ SSB_SPROM_REVISION_CRC_SHIFT);
+
+ if ((bus->chip_id & 0xFF00) == 0x4400) {
+ /* Workaround: The BCM44XX chip has a stupid revision
+ * number stored in the SPROM.
+ * Always extract r1. */
+ sprom_extract_r1(&out->r1, in);
+ } else {
+ if (out->revision == 0)
+ goto unsupported;
+ if (out->revision >= 1 && out->revision <= 3)
+ sprom_extract_r1(&out->r1, in);
+ if (out->revision >= 2 && out->revision <= 3)
+ sprom_extract_r2(&out->r2, in);
+ if (out->revision == 3)
+ sprom_extract_r3(&out->r3, in);
+ if (out->revision >= 4)
+ goto unsupported;
+ }
+
+ return 0;
+unsupported:
+ ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
+ "detected. Will extract v1\n", out->revision);
+ sprom_extract_r1(&out->r1, in);
+ return 0;
+}
+
+static int ssb_pci_sprom_get(struct ssb_bus *bus,
+ struct ssb_sprom *sprom)
+{
+ int err = -ENOMEM;
+ u16 *buf;
+
+ buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+ if (!buf)
+ goto out;
+ sprom_do_read(bus, buf);
+ err = sprom_check_crc(buf);
+ if (err) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
+ }
+ err = sprom_extract(bus, sprom, buf);
+
+ kfree(buf);
+out:
+ return err;
+}
+
+static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
+ struct ssb_boardinfo *bi)
+{
+ pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
+ &bi->vendor);
+ pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
+ &bi->type);
+ pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+ &bi->rev);
+}
+
+int ssb_pci_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv)
+{
+ int err;
+
+ err = ssb_pci_sprom_get(bus, &iv->sprom);
+ if (err)
+ goto out;
+ ssb_pci_get_boardinfo(bus, &iv->boardinfo);
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_SSB_DEBUG
+static int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+ if (likely(bus->powered_up))
+ return 0;
+
+ printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
+ "while accessing PCI MMIO space\n");
+ if (bus->power_warn_count <= 10) {
+ bus->power_warn_count++;
+ dump_stack();
+ }
+
+ return -ENODEV;
+}
+#else /* DEBUG */
+static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* DEBUG */
+
+static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFFFF;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return 0xFFFF;
+ }
+ return ioread16(bus->mmio + offset);
+}
+
+static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFFFFFFFF;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return 0xFFFFFFFF;
+ }
+ return ioread32(bus->mmio + offset);
+}
+
+static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return;
+ }
+ iowrite16(value, bus->mmio + offset);
+}
+
+static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return;
+ }
+ iowrite32(value, bus->mmio + offset);
+}
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_pci_ops = {
+ .read16 = ssb_pci_read16,
+ .read32 = ssb_pci_read32,
+ .write16 = ssb_pci_write16,
+ .write32 = ssb_pci_write32,
+};
+
+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
+{
+ int i, pos = 0;
+
+ for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+ pos += snprintf(buf + pos, buf_len - pos - 1,
+ "%04X", swab16(sprom[i]) & 0xFFFF);
+ }
+ pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+
+ return pos + 1;
+}
+
+static int hex2sprom(u16 *sprom, const char *dump, size_t len)
+{
+ char tmp[5] = { 0 };
+ int cnt = 0;
+ unsigned long parsed;
+
+ if (len < SSB_SPROMSIZE_BYTES * 2)
+ return -EINVAL;
+
+ while (cnt < SSB_SPROMSIZE_WORDS) {
+ memcpy(tmp, dump, 4);
+ dump += 4;
+ parsed = simple_strtoul(tmp, NULL, 16);
+ sprom[cnt++] = swab16((u16)parsed);
+ }
+
+ return 0;
+}
+
+static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
+ struct ssb_bus *bus;
+ u16 *sprom;
+ int err = -ENODEV;
+ ssize_t count = 0;
+
+ bus = ssb_pci_dev_to_bus(pdev);
+ if (!bus)
+ goto out;
+ err = -ENOMEM;
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
+ goto out_kfree;
+ sprom_do_read(bus, sprom);
+ mutex_unlock(&bus->pci_sprom_mutex);
+
+ count = sprom2hex(sprom, buf, PAGE_SIZE);
+ err = 0;
+
+out_kfree:
+ kfree(sprom);
+out:
+ return err ? err : count;
+}
+
+static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
+ struct ssb_bus *bus;
+ u16 *sprom;
+ int res = 0, err = -ENODEV;
+
+ bus = ssb_pci_dev_to_bus(pdev);
+ if (!bus)
+ goto out;
+ err = -ENOMEM;
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+ err = hex2sprom(sprom, buf, count);
+ if (err) {
+ err = -EINVAL;
+ goto out_kfree;
+ }
+ err = sprom_check_crc(sprom);
+ if (err) {
+ err = -EINVAL;
+ goto out_kfree;
+ }
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
+ goto out_kfree;
+ err = ssb_devices_freeze(bus);
+ if (err == -EOPNOTSUPP) {
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
+ "No suspend support. Is CONFIG_PM enabled?\n");
+ goto out_unlock;
+ }
+ if (err) {
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
+ goto out_unlock;
+ }
+ res = sprom_do_write(bus, sprom);
+ err = ssb_devices_thaw(bus);
+ if (err)
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
+out_unlock:
+ mutex_unlock(&bus->pci_sprom_mutex);
+out_kfree:
+ kfree(sprom);
+out:
+ if (res)
+ return res;
+ return err ? err : count;
+}
+
+static DEVICE_ATTR(ssb_sprom, 0600,
+ ssb_pci_attr_sprom_show,
+ ssb_pci_attr_sprom_store);
+
+void ssb_pci_exit(struct ssb_bus *bus)
+{
+ struct pci_dev *pdev;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return;
+
+ pdev = bus->host_pci;
+ device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
+}
+
+int ssb_pci_init(struct ssb_bus *bus)
+{
+ struct pci_dev *pdev;
+ int err;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return 0;
+
+ pdev = bus->host_pci;
+ mutex_init(&bus->pci_sprom_mutex);
+ err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
+ if (err)
+ goto out;
+
+out:
+ return err;
+}
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
new file mode 100644
index 000000000000..82a10abef640
--- /dev/null
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -0,0 +1,104 @@
+/*
+ * Sonics Silicon Backplane
+ * PCI Hostdevice wrapper
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+
+#ifdef CONFIG_PM
+static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ return 0;
+}
+
+static int ssb_pcihost_resume(struct pci_dev *dev)
+{
+ int err;
+
+ pci_set_power_state(dev, 0);
+ err = pci_enable_device(dev);
+ if (err)
+ return err;
+ pci_restore_state(dev);
+
+ return 0;
+}
+#else /* CONFIG_PM */
+# define ssb_pcihost_suspend NULL
+# define ssb_pcihost_resume NULL
+#endif /* CONFIG_PM */
+
+static int ssb_pcihost_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct ssb_bus *ssb;
+ int err = -ENOMEM;
+ const char *name;
+
+ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ if (!ssb)
+ goto out;
+ err = pci_enable_device(dev);
+ if (err)
+ goto err_kfree_ssb;
+ name = dev->dev.bus_id;
+ if (dev->driver && dev->driver->name)
+ name = dev->driver->name;
+ err = pci_request_regions(dev, name);
+ if (err)
+ goto err_pci_disable;
+ pci_set_master(dev);
+
+ err = ssb_bus_pcibus_register(ssb, dev);
+ if (err)
+ goto err_pci_release_regions;
+
+ pci_set_drvdata(dev, ssb);
+
+out:
+ return err;
+
+err_pci_release_regions:
+ pci_release_regions(dev);
+err_pci_disable:
+ pci_disable_device(dev);
+err_kfree_ssb:
+ kfree(ssb);
+ return err;
+}
+
+static void ssb_pcihost_remove(struct pci_dev *dev)
+{
+ struct ssb_bus *ssb = pci_get_drvdata(dev);
+
+ ssb_bus_unregister(ssb);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(ssb);
+ pci_set_drvdata(dev, NULL);
+}
+
+int ssb_pcihost_register(struct pci_driver *driver)
+{
+ driver->probe = ssb_pcihost_probe;
+ driver->remove = ssb_pcihost_remove;
+ driver->suspend = ssb_pcihost_suspend;
+ driver->resume = ssb_pcihost_resume;
+
+ return pci_register_driver(driver);
+}
+EXPORT_SYMBOL(ssb_pcihost_register);
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
new file mode 100644
index 000000000000..7c773603b402
--- /dev/null
+++ b/drivers/ssb/pcmcia.c
@@ -0,0 +1,271 @@
+/*
+ * Sonics Silicon Backplane
+ * PCMCIA-Hostbus related functions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "ssb_private.h"
+
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
+
+
+int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx)
+{
+ struct pcmcia_device *pdev = bus->host_pcmcia;
+ int err;
+ int attempts = 0;
+ u32 cur_core;
+ conf_reg_t reg;
+ u32 addr;
+ u32 read_addr;
+
+ addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
+ while (1) {
+ reg.Action = CS_WRITE;
+ reg.Offset = 0x2E;
+ reg.Value = (addr & 0x0000F000) >> 12;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ reg.Offset = 0x30;
+ reg.Value = (addr & 0x00FF0000) >> 16;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ reg.Offset = 0x32;
+ reg.Value = (addr & 0xFF000000) >> 24;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+
+ read_addr = 0;
+
+ reg.Action = CS_READ;
+ reg.Offset = 0x2E;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ read_addr |= (reg.Value & 0xF) << 12;
+ reg.Offset = 0x30;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ read_addr |= reg.Value << 16;
+ reg.Offset = 0x32;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ read_addr |= reg.Value << 24;
+
+ cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
+ if (cur_core == coreidx)
+ break;
+
+ if (attempts++ > SSB_BAR0_MAX_RETRIES)
+ goto error;
+ udelay(10);
+ }
+
+ return 0;
+error:
+ ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+ return -ENODEV;
+}
+
+int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ int err;
+ unsigned long flags;
+
+#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
+ ssb_printk(KERN_INFO PFX
+ "Switching to %s core, index %d\n",
+ ssb_core_name(dev->id.coreid),
+ dev->core_index);
+#endif
+
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
+ if (!err)
+ bus->mapped_device = dev;
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+ return err;
+}
+
+int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
+{
+ int attempts = 0;
+ unsigned long flags;
+ conf_reg_t reg;
+ int res, err = 0;
+
+ SSB_WARN_ON((seg != 0) && (seg != 1));
+ reg.Offset = 0x34;
+ reg.Function = 0;
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ while (1) {
+ reg.Action = CS_WRITE;
+ reg.Value = seg;
+ res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (unlikely(res != CS_SUCCESS))
+ goto error;
+ reg.Value = 0xFF;
+ reg.Action = CS_READ;
+ res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (unlikely(res != CS_SUCCESS))
+ goto error;
+
+ if (reg.Value == seg)
+ break;
+
+ if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
+ goto error;
+ udelay(10);
+ }
+ bus->mapped_pcmcia_seg = seg;
+out_unlock:
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+ return err;
+error:
+ ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
+ err = -ENODEV;
+ goto out_unlock;
+}
+
+/* These are the main device register access functions.
+ * do_select_core is inline to have the likely hotpath inline.
+ * All unlikely codepaths are out-of-line. */
+static inline int do_select_core(struct ssb_bus *bus,
+ struct ssb_device *dev,
+ u16 *offset)
+{
+ int err;
+ u8 need_seg = (*offset >= 0x800) ? 1 : 0;
+
+ if (unlikely(dev != bus->mapped_device)) {
+ err = ssb_pcmcia_switch_core(bus, dev);
+ if (unlikely(err))
+ return err;
+ }
+ if (unlikely(need_seg != bus->mapped_pcmcia_seg)) {
+ err = ssb_pcmcia_switch_segment(bus, need_seg);
+ if (unlikely(err))
+ return err;
+ }
+ if (need_seg == 1)
+ *offset -= 0x800;
+
+ return 0;
+}
+
+static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+ u16 x;
+
+ if (unlikely(do_select_core(bus, dev, &offset)))
+ return 0xFFFF;
+ x = readw(bus->mmio + offset);
+
+ return x;
+}
+
+static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+ u32 x;
+
+ if (unlikely(do_select_core(bus, dev, &offset)))
+ return 0xFFFFFFFF;
+ x = readl(bus->mmio + offset);
+
+ return x;
+}
+
+static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(do_select_core(bus, dev, &offset)))
+ return;
+ writew(value, bus->mmio + offset);
+}
+
+static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(do_select_core(bus, dev, &offset)))
+ return;
+ readw(bus->mmio + offset);
+ writew(value >> 16, bus->mmio + offset + 2);
+ readw(bus->mmio + offset);
+ writew(value, bus->mmio + offset);
+}
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_pcmcia_ops = {
+ .read16 = ssb_pcmcia_read16,
+ .read32 = ssb_pcmcia_read32,
+ .write16 = ssb_pcmcia_write16,
+ .write32 = ssb_pcmcia_write32,
+};
+
+int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv)
+{
+ //TODO
+ return 0;
+}
+
+int ssb_pcmcia_init(struct ssb_bus *bus)
+{
+ conf_reg_t reg;
+ int err;
+
+ if (bus->bustype != SSB_BUSTYPE_PCMCIA)
+ return 0;
+
+ /* Switch segment to a known state and sync
+ * bus->mapped_pcmcia_seg with hardware state. */
+ ssb_pcmcia_switch_segment(bus, 0);
+
+ /* Init IRQ routing */
+ reg.Action = CS_READ;
+ reg.Function = 0;
+ if (bus->chip_id == 0x4306)
+ reg.Offset = 0x00;
+ else
+ reg.Offset = 0x80;
+ err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ reg.Action = CS_WRITE;
+ reg.Value |= 0x04 | 0x01;
+ err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+
+ return 0;
+error:
+ return -ENODEV;
+}
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
new file mode 100644
index 000000000000..96258c60919d
--- /dev/null
+++ b/drivers/ssb/scan.c
@@ -0,0 +1,413 @@
+/*
+ * Sonics Silicon Backplane
+ * Bus scanning
+ *
+ * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "ssb_private.h"
+
+
+const char *ssb_core_name(u16 coreid)
+{
+ switch (coreid) {
+ case SSB_DEV_CHIPCOMMON:
+ return "ChipCommon";
+ case SSB_DEV_ILINE20:
+ return "ILine 20";
+ case SSB_DEV_SDRAM:
+ return "SDRAM";
+ case SSB_DEV_PCI:
+ return "PCI";
+ case SSB_DEV_MIPS:
+ return "MIPS";
+ case SSB_DEV_ETHERNET:
+ return "Fast Ethernet";
+ case SSB_DEV_V90:
+ return "V90";
+ case SSB_DEV_USB11_HOSTDEV:
+ return "USB 1.1 Hostdev";
+ case SSB_DEV_ADSL:
+ return "ADSL";
+ case SSB_DEV_ILINE100:
+ return "ILine 100";
+ case SSB_DEV_IPSEC:
+ return "IPSEC";
+ case SSB_DEV_PCMCIA:
+ return "PCMCIA";
+ case SSB_DEV_INTERNAL_MEM:
+ return "Internal Memory";
+ case SSB_DEV_MEMC_SDRAM:
+ return "MEMC SDRAM";
+ case SSB_DEV_EXTIF:
+ return "EXTIF";
+ case SSB_DEV_80211:
+ return "IEEE 802.11";
+ case SSB_DEV_MIPS_3302:
+ return "MIPS 3302";
+ case SSB_DEV_USB11_HOST:
+ return "USB 1.1 Host";
+ case SSB_DEV_USB11_DEV:
+ return "USB 1.1 Device";
+ case SSB_DEV_USB20_HOST:
+ return "USB 2.0 Host";
+ case SSB_DEV_USB20_DEV:
+ return "USB 2.0 Device";
+ case SSB_DEV_SDIO_HOST:
+ return "SDIO Host";
+ case SSB_DEV_ROBOSWITCH:
+ return "Roboswitch";
+ case SSB_DEV_PARA_ATA:
+ return "PATA";
+ case SSB_DEV_SATA_XORDMA:
+ return "SATA XOR-DMA";
+ case SSB_DEV_ETHERNET_GBIT:
+ return "GBit Ethernet";
+ case SSB_DEV_PCIE:
+ return "PCI-E";
+ case SSB_DEV_MIMO_PHY:
+ return "MIMO PHY";
+ case SSB_DEV_SRAM_CTRLR:
+ return "SRAM Controller";
+ case SSB_DEV_MINI_MACPHY:
+ return "Mini MACPHY";
+ case SSB_DEV_ARM_1176:
+ return "ARM 1176";
+ case SSB_DEV_ARM_7TDMI:
+ return "ARM 7TDMI";
+ }
+ return "UNKNOWN";
+}
+
+static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
+{
+ u16 chipid_fallback = 0;
+
+ switch (pci_dev->device) {
+ case 0x4301:
+ chipid_fallback = 0x4301;
+ break;
+ case 0x4305 ... 0x4307:
+ chipid_fallback = 0x4307;
+ break;
+ case 0x4403:
+ chipid_fallback = 0x4402;
+ break;
+ case 0x4610 ... 0x4615:
+ chipid_fallback = 0x4610;
+ break;
+ case 0x4710 ... 0x4715:
+ chipid_fallback = 0x4710;
+ break;
+ case 0x4320 ... 0x4325:
+ chipid_fallback = 0x4309;
+ break;
+ case PCI_DEVICE_ID_BCM4401:
+ case PCI_DEVICE_ID_BCM4401B0:
+ case PCI_DEVICE_ID_BCM4401B1:
+ chipid_fallback = 0x4401;
+ break;
+ default:
+ ssb_printk(KERN_ERR PFX
+ "PCI-ID not in fallback list\n");
+ }
+
+ return chipid_fallback;
+}
+
+static u8 chipid_to_nrcores(u16 chipid)
+{
+ switch (chipid) {
+ case 0x5365:
+ return 7;
+ case 0x4306:
+ return 6;
+ case 0x4310:
+ return 8;
+ case 0x4307:
+ case 0x4301:
+ return 5;
+ case 0x4401:
+ case 0x4402:
+ return 3;
+ case 0x4710:
+ case 0x4610:
+ case 0x4704:
+ return 9;
+ default:
+ ssb_printk(KERN_ERR PFX
+ "CHIPID not in nrcores fallback list\n");
+ }
+
+ return 1;
+}
+
+static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
+ u16 offset)
+{
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ offset += current_coreidx * SSB_CORE_SIZE;
+ break;
+ case SSB_BUSTYPE_PCI:
+ break;
+ case SSB_BUSTYPE_PCMCIA:
+ if (offset >= 0x800) {
+ ssb_pcmcia_switch_segment(bus, 1);
+ offset -= 0x800;
+ } else
+ ssb_pcmcia_switch_segment(bus, 0);
+ break;
+ }
+ return readl(bus->mmio + offset);
+}
+
+static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
+{
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ break;
+ case SSB_BUSTYPE_PCI:
+ return ssb_pci_switch_coreidx(bus, coreidx);
+ case SSB_BUSTYPE_PCMCIA:
+ return ssb_pcmcia_switch_coreidx(bus, coreidx);
+ }
+ return 0;
+}
+
+void ssb_iounmap(struct ssb_bus *bus)
+{
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ case SSB_BUSTYPE_PCMCIA:
+ iounmap(bus->mmio);
+ break;
+ case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+ pci_iounmap(bus->host_pci, bus->mmio);
+#else
+ SSB_BUG_ON(1); /* Can't reach this code. */
+#endif
+ break;
+ }
+ bus->mmio = NULL;
+ bus->mapped_device = NULL;
+}
+
+static void __iomem *ssb_ioremap(struct ssb_bus *bus,
+ unsigned long baseaddr)
+{
+ void __iomem *mmio = NULL;
+
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ /* Only map the first core for now. */
+ /* fallthrough... */
+ case SSB_BUSTYPE_PCMCIA:
+ mmio = ioremap(baseaddr, SSB_CORE_SIZE);
+ break;
+ case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+ mmio = pci_iomap(bus->host_pci, 0, ~0UL);
+#else
+ SSB_BUG_ON(1); /* Can't reach this code. */
+#endif
+ break;
+ }
+
+ return mmio;
+}
+
+static int we_support_multiple_80211_cores(struct ssb_bus *bus)
+{
+ /* More than one 802.11 core is only supported by special chips.
+ * There are chips with two 802.11 cores, but with dangling
+ * pins on the second core. Be careful and reject them here.
+ */
+
+#ifdef CONFIG_SSB_PCIHOST
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
+ bus->host_pci->device == 0x4324)
+ return 1;
+ }
+#endif /* CONFIG_SSB_PCIHOST */
+ return 0;
+}
+
+int ssb_bus_scan(struct ssb_bus *bus,
+ unsigned long baseaddr)
+{
+ int err = -ENOMEM;
+ void __iomem *mmio;
+ u32 idhi, cc, rev, tmp;
+ int dev_i, i;
+ struct ssb_device *dev;
+ int nr_80211_cores = 0;
+
+ mmio = ssb_ioremap(bus, baseaddr);
+ if (!mmio)
+ goto out;
+ bus->mmio = mmio;
+
+ err = scan_switchcore(bus, 0); /* Switch to first core */
+ if (err)
+ goto err_unmap;
+
+ idhi = scan_read32(bus, 0, SSB_IDHIGH);
+ cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
+ rev = (idhi & SSB_IDHIGH_RCLO);
+ rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+
+ bus->nr_devices = 0;
+ if (cc == SSB_DEV_CHIPCOMMON) {
+ tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
+
+ bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
+ bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
+ SSB_CHIPCO_REVSHIFT;
+ bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
+ SSB_CHIPCO_PACKSHIFT;
+ if (rev >= 4) {
+ bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
+ SSB_CHIPCO_NRCORESSHIFT;
+ }
+ tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
+ bus->chipco.capabilities = tmp;
+ } else {
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ bus->chip_id = pcidev_to_chipid(bus->host_pci);
+ pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+ &bus->chip_rev);
+ bus->chip_package = 0;
+ } else {
+ bus->chip_id = 0x4710;
+ bus->chip_rev = 0;
+ bus->chip_package = 0;
+ }
+ }
+ if (!bus->nr_devices)
+ bus->nr_devices = chipid_to_nrcores(bus->chip_id);
+ if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
+ ssb_printk(KERN_ERR PFX
+ "More than %d ssb cores found (%d)\n",
+ SSB_MAX_NR_CORES, bus->nr_devices);
+ goto err_unmap;
+ }
+ if (bus->bustype == SSB_BUSTYPE_SSB) {
+ /* Now that we know the number of cores,
+ * remap the whole IO space for all cores.
+ */
+ err = -ENOMEM;
+ iounmap(mmio);
+ mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
+ if (!mmio)
+ goto out;
+ bus->mmio = mmio;
+ }
+
+ /* Fetch basic information about each core/device */
+ for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
+ err = scan_switchcore(bus, i);
+ if (err)
+ goto err_unmap;
+ dev = &(bus->devices[dev_i]);
+
+ idhi = scan_read32(bus, i, SSB_IDHIGH);
+ dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
+ dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
+ dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+ dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
+ dev->core_index = i;
+ dev->bus = bus;
+ dev->ops = bus->ops;
+
+ ssb_dprintk(KERN_INFO PFX
+ "Core %d found: %s "
+ "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
+ i, ssb_core_name(dev->id.coreid),
+ dev->id.coreid, dev->id.revision, dev->id.vendor);
+
+ switch (dev->id.coreid) {
+ case SSB_DEV_80211:
+ nr_80211_cores++;
+ if (nr_80211_cores > 1) {
+ if (!we_support_multiple_80211_cores(bus)) {
+ ssb_dprintk(KERN_INFO PFX "Ignoring additional "
+ "802.11 core\n");
+ continue;
+ }
+ }
+ break;
+ case SSB_DEV_EXTIF:
+#ifdef CONFIG_SSB_DRIVER_EXTIF
+ if (bus->extif.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple EXTIFs found\n");
+ break;
+ }
+ bus->extif.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_EXTIF */
+ break;
+ case SSB_DEV_CHIPCOMMON:
+ if (bus->chipco.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple ChipCommon found\n");
+ break;
+ }
+ bus->chipco.dev = dev;
+ break;
+ case SSB_DEV_MIPS:
+ case SSB_DEV_MIPS_3302:
+#ifdef CONFIG_SSB_DRIVER_MIPS
+ if (bus->mipscore.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple MIPS cores found\n");
+ break;
+ }
+ bus->mipscore.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_MIPS */
+ break;
+ case SSB_DEV_PCI:
+ case SSB_DEV_PCIE:
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ if (bus->pcicore.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple PCI(E) cores found\n");
+ break;
+ }
+ bus->pcicore.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+ break;
+ default:
+ break;
+ }
+
+ dev_i++;
+ }
+ bus->nr_devices = dev_i;
+
+ err = 0;
+out:
+ return err;
+err_unmap:
+ ssb_iounmap(bus);
+ goto out;
+}
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
new file mode 100644
index 000000000000..a789364264a6
--- /dev/null
+++ b/drivers/ssb/ssb_private.h
@@ -0,0 +1,136 @@
+#ifndef LINUX_SSB_PRIVATE_H_
+#define LINUX_SSB_PRIVATE_H_
+
+#include <linux/ssb/ssb.h>
+#include <linux/types.h>
+
+
+#define PFX "ssb: "
+
+#ifdef CONFIG_SSB_SILENT
+# define ssb_printk(fmt, x...) do { /* nothing */ } while (0)
+#else
+# define ssb_printk printk
+#endif /* CONFIG_SSB_SILENT */
+
+/* dprintk: Debugging printk; vanishes for non-debug compilation */
+#ifdef CONFIG_SSB_DEBUG
+# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x)
+#else
+# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0)
+#endif
+
+#ifdef CONFIG_SSB_DEBUG
+# define SSB_WARN_ON(x) WARN_ON(x)
+# define SSB_BUG_ON(x) BUG_ON(x)
+#else
+static inline int __ssb_do_nothing(int x) { return x; }
+# define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x)))
+# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x)))
+#endif
+
+
+/* pci.c */
+#ifdef CONFIG_SSB_PCIHOST
+extern int ssb_pci_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev);
+extern int ssb_pci_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx);
+extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
+ int turn_on);
+extern int ssb_pci_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv);
+extern void ssb_pci_exit(struct ssb_bus *bus);
+extern int ssb_pci_init(struct ssb_bus *bus);
+extern const struct ssb_bus_ops ssb_pci_ops;
+
+#else /* CONFIG_SSB_PCIHOST */
+
+static inline int ssb_pci_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ return 0;
+}
+static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx)
+{
+ return 0;
+}
+static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
+ int turn_on)
+{
+ return 0;
+}
+static inline void ssb_pci_exit(struct ssb_bus *bus)
+{
+}
+static inline int ssb_pci_init(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+
+/* pcmcia.c */
+#ifdef CONFIG_SSB_PCMCIAHOST
+extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev);
+extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx);
+extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+ u8 seg);
+extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv);
+extern int ssb_pcmcia_init(struct ssb_bus *bus);
+extern const struct ssb_bus_ops ssb_pcmcia_ops;
+#else /* CONFIG_SSB_PCMCIAHOST */
+static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ return 0;
+}
+static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx)
+{
+ return 0;
+}
+static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+ u8 seg)
+{
+ return 0;
+}
+static inline int ssb_pcmcia_init(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+
+/* scan.c */
+extern const char *ssb_core_name(u16 coreid);
+extern int ssb_bus_scan(struct ssb_bus *bus,
+ unsigned long baseaddr);
+extern void ssb_iounmap(struct ssb_bus *ssb);
+
+
+/* core.c */
+extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
+extern int ssb_devices_freeze(struct ssb_bus *bus);
+extern int ssb_devices_thaw(struct ssb_bus *bus);
+extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
+
+/* b43_pci_bridge.c */
+#ifdef CONFIG_SSB_PCIHOST
+extern int __init b43_pci_ssb_bridge_init(void);
+extern void __exit b43_pci_ssb_bridge_exit(void);
+#else /* CONFIG_SSB_PCIHOST */
+static inline int b43_pci_ssb_bridge_init(void)
+{
+ return 0;
+}
+static inline void b43_pci_ssb_bridge_exit(void)
+{
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+#endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 967342692211..c899246bd362 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -5,7 +5,6 @@
# Object file lists.
obj-$(CONFIG_TC) += tc.o tc-driver.o
-obj-$(CONFIG_ZS) += zs.o
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
$(obj)/lk201-map.o: $(obj)/lk201-map.c
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
deleted file mode 100644
index ed979f13908a..000000000000
--- a/drivers/tc/zs.c
+++ /dev/null
@@ -1,2203 +0,0 @@
-/*
- * decserial.c: Serial port driver for IOASIC DECstations.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
- *
- * DECstation changes
- * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Maciej W. Rozycki
- *
- * For the rest of the code the original Copyright applies:
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- *
- * Note: for IOASIC systems the wiring is as follows:
- *
- * mouse/keyboard:
- * DIN-7 MJ-4 signal SCC
- * 2 1 TxD <- A.TxD
- * 3 4 RxD -> A.RxD
- *
- * EIA-232/EIA-423:
- * DB-25 MMJ-6 signal SCC
- * 2 2 TxD <- B.TxD
- * 3 5 RxD -> B.RxD
- * 4 RTS <- ~A.RTS
- * 5 CTS -> ~B.CTS
- * 6 6 DSR -> ~A.SYNC
- * 8 CD -> ~B.DCD
- * 12 DSRS(DCE) -> ~A.CTS (*)
- * 15 TxC -> B.TxC
- * 17 RxC -> B.RxC
- * 20 1 DTR <- ~A.DTR
- * 22 RI -> ~A.DCD
- * 23 DSRS(DTE) <- ~B.RTS
- *
- * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
- * is shared with DSRS(DTE) at pin 23.
- */
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-#include <linux/console.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/serial.h>
-#include <asm/dec/system.h>
-
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#endif
-
-#include "zs.h"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL 2 /* Max number of ZS chips supported */
-#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
-#define CHANNEL_A_NR (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
- /* Number of channel A in the chip */
-#define ZS_CHAN_IO_SIZE 8
-#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */
-
-#define RECOVERY_DELAY udelay(2)
-
-struct zs_parms {
- unsigned long scc0;
- unsigned long scc1;
- int channel_a_offset;
- int channel_b_offset;
- int irq0;
- int irq1;
- int clock;
-};
-
-static struct zs_parms *zs_parms;
-
-#ifdef CONFIG_MACH_DECSTATION
-static struct zs_parms ds_parms = {
- scc0 : IOASIC_SCC0,
- scc1 : IOASIC_SCC1,
- channel_a_offset : 1,
- channel_b_offset : 9,
- irq0 : -1,
- irq1 : -1,
- clock : ZS_CLOCK
-};
-#endif
-
-#ifdef CONFIG_MACH_DECSTATION
-#define DS_BUS_PRESENT (IOASIC)
-#else
-#define DS_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT)
-
-DEFINE_SPINLOCK(zs_lock);
-
-struct dec_zschannel zs_channels[NUM_CHANNELS];
-struct dec_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct dec_serial *zs_chain; /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-static struct console zs_console;
-#endif
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
- !defined(MODULE)
-static unsigned long break_pressed; /* break, really ... */
-#endif
-
-static unsigned char zs_init_regs[16] __initdata = {
- 0, /* write 0 */
- 0, /* write 1 */
- 0, /* write 2 */
- 0, /* write 3 */
- (X16CLK), /* write 4 */
- 0, /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- (MIE | DLC | NV), /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 0, 0, /* BRG time constant, write 12 + 13 */
- (BRSRC | BRENABL), /* write 14 */
- 0 /* write 15 */
-};
-
-static struct tty_driver *serial_driver;
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL 1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_PARANOIA_CHECK
-
-#undef ZS_DEBUG_REGS
-
-#ifdef SERIAL_DEBUG_THROTTLE
-#define _tty_name(tty,buf) tty_name(tty,buf)
-#endif
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-static void probe_sccs(void);
-static void change_speed(struct dec_serial *info);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(struct dec_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char *badinfo =
- "Warning: null mac_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char read_zsreg(struct dec_zschannel *channel,
- unsigned char reg)
-{
- unsigned char retval;
-
- if (reg != 0) {
- *channel->control = reg & 0xf;
- fast_iob(); RECOVERY_DELAY;
- }
- retval = *channel->control;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsreg(struct dec_zschannel *channel,
- unsigned char reg, unsigned char value)
-{
- if (reg != 0) {
- *channel->control = reg & 0xf;
- fast_iob(); RECOVERY_DELAY;
- }
- *channel->control = value;
- fast_iob(); RECOVERY_DELAY;
- return;
-}
-
-static inline unsigned char read_zsdata(struct dec_zschannel *channel)
-{
- unsigned char retval;
-
- retval = *channel->data;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsdata(struct dec_zschannel *channel,
- unsigned char value)
-{
- *channel->data = value;
- fast_iob(); RECOVERY_DELAY;
- return;
-}
-
-static inline void load_zsregs(struct dec_zschannel *channel,
- unsigned char *regs)
-{
-/* ZS_CLEARERR(channel);
- ZS_CLEARFIFO(channel); */
- /* Load 'em up */
- write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
- write_zsreg(channel, R5, regs[R5] & ~TxENAB);
- write_zsreg(channel, R4, regs[R4]);
- write_zsreg(channel, R9, regs[R9]);
- write_zsreg(channel, R1, regs[R1]);
- write_zsreg(channel, R2, regs[R2]);
- write_zsreg(channel, R10, regs[R10]);
- write_zsreg(channel, R11, regs[R11]);
- write_zsreg(channel, R12, regs[R12]);
- write_zsreg(channel, R13, regs[R13]);
- write_zsreg(channel, R14, regs[R14]);
- write_zsreg(channel, R15, regs[R15]);
- write_zsreg(channel, R3, regs[R3]);
- write_zsreg(channel, R5, regs[R5]);
- return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct dec_serial *info, int which, int set)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&zs_lock, flags);
- if (info->zs_channel != info->zs_chan_a) {
- if (set) {
- info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));
- } else {
- info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR));
- }
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct dec_serial *ss)
-{
- struct dec_zschannel *channel = ss->zs_channel;
- int brg;
-
- /* The baud rate is split up between two 8-bit registers in
- * what is termed 'BRG time constant' format in my docs for
- * the chip, it is a function of the clk rate the chip is
- * receiving which happens to be constant.
- */
- brg = (read_zsreg(channel, 13) << 8);
- brg |= read_zsreg(channel, 12);
- return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct dec_zschannel *zsc)
-{
- write_zsreg(zsc, 0, ERR_RES);
- write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct dec_serial *info, int event)
-{
- info->event |= 1 << event;
- tasklet_schedule(&info->tlet);
-}
-
-static void receive_chars(struct dec_serial *info)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch, stat, flag;
-
- while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {
-
- stat = read_zsreg(info->zs_channel, R1);
- ch = read_zsdata(info->zs_channel);
-
- if (!tty && (!info->hook || !info->hook->rx_char))
- continue;
-
- flag = TTY_NORMAL;
- if (info->tty_break) {
- info->tty_break = 0;
- flag = TTY_BREAK;
- if (info->flags & ZILOG_SAK)
- do_SAK(tty);
- /* Ignore the null char got when BREAK is removed. */
- if (ch == 0)
- continue;
- } else {
- if (stat & Rx_OVR) {
- flag = TTY_OVERRUN;
- } else if (stat & FRM_ERR) {
- flag = TTY_FRAME;
- } else if (stat & PAR_ERR) {
- flag = TTY_PARITY;
- }
- if (flag != TTY_NORMAL)
- /* reset the error indication */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- }
-
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
- !defined(MODULE)
- if (break_pressed && info->line == zs_console.index) {
- /* Ignore the null char got when BREAK is removed. */
- if (ch == 0)
- continue;
- if (time_before(jiffies, break_pressed + HZ * 5)) {
- handle_sysrq(ch, NULL);
- break_pressed = 0;
- continue;
- }
- break_pressed = 0;
- }
-#endif
-
- if (info->hook && info->hook->rx_char) {
- (*info->hook->rx_char)(ch, flag);
- return;
- }
-
- tty_insert_flip_char(tty, ch, flag);
- }
- if (tty)
- tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct dec_serial *info)
-{
- if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)
- return;
- info->tx_active = 0;
-
- if (info->x_char) {
- /* Send next char */
- write_zsdata(info->zs_channel, info->x_char);
- info->x_char = 0;
- info->tx_active = 1;
- return;
- }
-
- if ((info->xmit_cnt <= 0) || (info->tty && info->tty->stopped)
- || info->tx_stopped) {
- write_zsreg(info->zs_channel, R0, RES_Tx_P);
- return;
- }
- /* Send char */
- write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- info->tx_active = 1;
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void status_handle(struct dec_serial *info)
-{
- unsigned char stat;
-
- /* Get status from Read Register 0 */
- stat = read_zsreg(info->zs_channel, R0);
-
- if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
- !defined(MODULE)
- if (info->line == zs_console.index) {
- if (!break_pressed)
- break_pressed = jiffies;
- } else
-#endif
- info->tty_break = 1;
- }
-
- if (info->zs_channel != info->zs_chan_a) {
-
- /* Check for DCD transitions */
- if (info->tty && !C_CLOCAL(info->tty) &&
- ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
- if (stat & DCD) {
- wake_up_interruptible(&info->open_wait);
- } else {
- tty_hangup(info->tty);
- }
- }
-
- /* Check for CTS transitions */
- if (info->tty && C_CRTSCTS(info->tty)) {
- if ((stat & CTS) != 0) {
- if (info->tx_stopped) {
- info->tx_stopped = 0;
- if (!info->tx_active)
- transmit_chars(info);
- }
- } else {
- info->tx_stopped = 1;
- }
- }
-
- }
-
- /* Clear status condition... */
- write_zsreg(info->zs_channel, R0, RES_EXT_INT);
- info->read_reg_zero = stat;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
- struct dec_serial *info = (struct dec_serial *) dev_id;
- irqreturn_t status = IRQ_NONE;
- unsigned char zs_intreg;
- int shift;
-
- /* NOTE: The read register 3, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the A
- * channel and is only valid when read from channel A.
- * Yes... broken hardware...
- */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
- if (info->zs_chan_a == info->zs_channel)
- shift = 3; /* Channel A */
- else
- shift = 0; /* Channel B */
-
- for (;;) {
- zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
- if ((zs_intreg & CHAN_IRQMASK) == 0)
- break;
-
- status = IRQ_HANDLED;
-
- if (zs_intreg & CHBRxIP) {
- receive_chars(info);
- }
- if (zs_intreg & CHBTxIP) {
- transmit_chars(info);
- }
- if (zs_intreg & CHBEXT) {
- status_handle(info);
- }
- }
-
- /* Why do we need this ? */
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
- return status;
-}
-
-#ifdef ZS_DEBUG_REGS
-void zs_dump (void) {
- int i, j;
- for (i = 0; i < zs_channels_found; i++) {
- struct dec_zschannel *ch = &zs_channels[i];
- if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
- for (j = 0; j < 15; j++) {
- printk("W%d = 0x%x\t",
- j, (int)ch->curregs[j]);
- }
- for (j = 0; j < 15; j++) {
- printk("R%d = 0x%x\t",
- j, (int)read_zsreg(ch,j));
- }
- printk("\n\n");
- }
- }
-}
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
-#if 1
- spin_lock_irqsave(&zs_lock, flags);
- if (info->zs_channel->curregs[5] & TxENAB) {
- info->zs_channel->curregs[5] &= ~TxENAB;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- spin_lock_irqsave(&zs_lock, flags);
-#if 1
- if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
- info->zs_channel->curregs[5] |= TxENAB;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- }
-#else
- if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
- transmit_chars(info);
- }
-#endif
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-
-static void do_softint(unsigned long private_)
-{
- struct dec_serial *info = (struct dec_serial *) private_;
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
- tty_wakeup(tty);
-}
-
-static int zs_startup(struct dec_serial * info)
-{
- unsigned long flags;
-
- if (info->flags & ZILOG_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&zs_lock, flags);
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
-#endif
-
- /*
- * Clear the receive FIFO.
- */
- ZS_CLEARFIFO(info->zs_channel);
- info->xmit_fifo_size = 1;
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
- /*
- * Set the speed of the serial port
- */
- change_speed(info);
-
- /*
- * Turn on RTS and DTR.
- */
- zs_rtsdtr(info, RTS | DTR, 1);
-
- /*
- * Finally, enable sequencing and interrupts
- */
- info->zs_channel->curregs[R1] &= ~RxINT_MASK;
- info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
- EXT_INT_ENAB);
- info->zs_channel->curregs[R3] |= RxENABLE;
- info->zs_channel->curregs[R5] |= TxENAB;
- info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
- write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
- write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
- write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
- write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
-
- /*
- * And clear the interrupt registers again for luck.
- */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- info->flags |= ZILOG_INITIALIZED;
- spin_unlock_irqrestore(&zs_lock, flags);
- return 0;
-}
-
-/*
- * 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 dec_serial * info)
-{
- unsigned long flags;
-
- if (!(info->flags & ZILOG_INITIALIZED))
- return;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....", info->line,
- info->irq);
-#endif
-
- spin_lock_irqsave(&zs_lock, flags);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- info->zs_channel->curregs[1] = 0;
- write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); /* no interrupts */
-
- info->zs_channel->curregs[3] &= ~RxENABLE;
- write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-
- info->zs_channel->curregs[5] &= ~TxENAB;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- if (!info->tty || C_HUPCL(info->tty)) {
- zs_rtsdtr(info, RTS | DTR, 0);
- }
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- info->flags &= ~ZILOG_INITIALIZED;
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct dec_serial *info)
-{
- unsigned cflag;
- int i;
- int brg, bits;
- unsigned long flags;
-
- if (!info->hook) {
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
- if (!info->port)
- return;
- } else {
- cflag = info->hook->cflags;
- }
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2) {
- if (!info->hook)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- info->hook->cflags &= ~CBAUDEX;
- } else
- i += 15;
- }
-
- spin_lock_irqsave(&zs_lock, flags);
- info->zs_baud = baud_table[i];
- if (info->zs_baud) {
- brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
- info->zs_channel->curregs[12] = (brg & 255);
- info->zs_channel->curregs[13] = ((brg >> 8) & 255);
- zs_rtsdtr(info, DTR, 1);
- } else {
- zs_rtsdtr(info, RTS | DTR, 0);
- return;
- }
-
- /* byte size and parity */
- info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
- info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- bits = 7;
- info->zs_channel->curregs[3] |= Rx5;
- info->zs_channel->curregs[5] |= Tx5;
- break;
- case CS6:
- bits = 8;
- info->zs_channel->curregs[3] |= Rx6;
- info->zs_channel->curregs[5] |= Tx6;
- break;
- case CS7:
- bits = 9;
- info->zs_channel->curregs[3] |= Rx7;
- info->zs_channel->curregs[5] |= Tx7;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- bits = 10;
- info->zs_channel->curregs[3] |= Rx8;
- info->zs_channel->curregs[5] |= Tx8;
- break;
- }
-
- info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
- info->timeout += HZ/50; /* Add .02 seconds of slop */
-
- info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->zs_channel->curregs[4] |= SB2;
- } else {
- info->zs_channel->curregs[4] |= SB1;
- }
- if (cflag & PARENB) {
- info->zs_channel->curregs[4] |= PAR_ENA;
- }
- if (!(cflag & PARODD)) {
- info->zs_channel->curregs[4] |= PAR_EVEN;
- }
-
- if (!(cflag & CLOCAL)) {
- if (!(info->zs_channel->curregs[15] & DCDIE))
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
- info->zs_channel->curregs[15] |= DCDIE;
- } else
- info->zs_channel->curregs[15] &= ~DCDIE;
- if (cflag & CRTSCTS) {
- info->zs_channel->curregs[15] |= CTSIE;
- if ((read_zsreg(info->zs_channel, 0) & CTS) == 0)
- info->tx_stopped = 1;
- } else {
- info->zs_channel->curregs[15] &= ~CTSIE;
- info->tx_stopped = 0;
- }
-
- /* Load up the new values */
- load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-
- if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
- !info->xmit_buf)
- return;
-
- /* Enable transmitter */
- spin_lock_irqsave(&zs_lock, flags);
- transmit_chars(info);
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, total = 0;
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- while (1) {
- spin_lock_irqsave(&zs_lock, flags);
- c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- spin_unlock_irqrestore(&zs_lock, flags);
- buf += c;
- count -= c;
- total += c;
- }
-
- if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
- && !info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&zs_lock, flags);
- return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- spin_lock_irq(&zs_lock);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irq(&zs_lock);
- tty_wakeup(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)
-{
- struct dec_serial *info = (struct dec_serial *)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));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&zs_lock, flags);
- info->x_char = STOP_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&zs_lock, flags);
- }
-
- if (C_CRTSCTS(tty)) {
- zs_rtsdtr(info, RTS, 0);
- }
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
- struct dec_serial *info = (struct dec_serial *)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));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&zs_lock, flags);
- if (info->x_char)
- info->x_char = 0;
- else {
- info->x_char = START_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
- }
-
- if (C_CRTSCTS(tty)) {
- zs_rtsdtr(info, RTS, 1);
- }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct dec_serial * info,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct dec_serial * info,
- struct serial_struct * new_info)
-{
- struct serial_struct new_serial;
- struct dec_serial old_info;
- int retval = 0;
-
- if (!new_info)
- return -EFAULT;
- copy_from_user(&new_serial,new_info,sizeof(new_serial));
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~ZILOG_USR_MASK) !=
- (info->flags & ~ZILOG_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ZILOG_USR_MASK) |
- (new_serial.flags & ZILOG_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (info->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~ZILOG_FLAGS) |
- (new_serial.flags & ZILOG_FLAGS));
- info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- retval = zs_startup(info);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct dec_serial * info, unsigned int *value)
-{
- unsigned char status;
-
- spin_lock(&zs_lock);
- status = read_zsreg(info->zs_channel, 0);
- spin_unlock_irq(&zs_lock);
- put_user(status,value);
- return 0;
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
- unsigned char control, status_a, status_b;
- unsigned int result;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- if (info->zs_channel == info->zs_chan_a)
- result = 0;
- else {
- spin_lock(&zs_lock);
- control = info->zs_chan_a->curregs[5];
- status_a = read_zsreg(info->zs_chan_a, 0);
- status_b = read_zsreg(info->zs_channel, 0);
- spin_unlock_irq(&zs_lock);
- result = ((control & RTS) ? TIOCM_RTS: 0)
- | ((control & DTR) ? TIOCM_DTR: 0)
- | ((status_b & DCD) ? TIOCM_CAR: 0)
- | ((status_a & DCD) ? TIOCM_RNG: 0)
- | ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0)
- | ((status_b & CTS) ? TIOCM_CTS: 0);
- }
- return result;
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- if (info->zs_channel == info->zs_chan_a)
- return 0;
-
- spin_lock(&zs_lock);
- if (set & TIOCM_RTS)
- info->zs_chan_a->curregs[5] |= RTS;
- if (set & TIOCM_DTR)
- info->zs_chan_a->curregs[5] |= DTR;
- if (clear & TIOCM_RTS)
- info->zs_chan_a->curregs[5] &= ~RTS;
- if (clear & TIOCM_DTR)
- info->zs_chan_a->curregs[5] &= ~DTR;
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- spin_unlock_irq(&zs_lock);
- return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
- struct dec_serial *info = (struct dec_serial *) tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_break"))
- return;
- if (!info->port)
- return;
-
- spin_lock_irqsave(&zs_lock, flags);
- if (break_state == -1)
- info->zs_channel->curregs[5] |= SND_BRK;
- else
- info->zs_channel->curregs[5] &= ~SND_BRK;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TIOCGSERIAL:
- if (!access_ok(VERIFY_WRITE, (void *)arg,
- sizeof(struct serial_struct)))
- return -EFAULT;
- return get_serial_info(info, (struct serial_struct *)arg);
-
- case TIOCSSERIAL:
- return set_serial_info(info, (struct serial_struct *)arg);
-
- case TIOCSERGETLSR: /* Get line status register */
- if (!access_ok(VERIFY_WRITE, (void *)arg,
- sizeof(unsigned int)))
- return -EFAULT;
- return get_lsr_info(info, (unsigned int *)arg);
-
- case TIOCSERGSTRUCT:
- if (!access_ok(VERIFY_WRITE, (void *)arg,
- sizeof(struct dec_serial)))
- return -EFAULT;
- copy_from_user((struct dec_serial *)arg, info,
- sizeof(struct dec_serial));
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- int was_stopped;
-
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- was_stopped = info->tx_stopped;
-
- change_speed(info);
-
- if (was_stopped && !info->tx_stopped)
- rs_start(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- spin_lock_irqsave(&zs_lock, flags);
-
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&zs_lock, flags);
- return;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("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",
- info->line, info->count);
- info->count = 0;
- }
- if (info->count) {
- spin_unlock_irqrestore(&zs_lock, flags);
- return;
- }
- info->flags |= ZILOG_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receiver and receive interrupts.
- */
- info->zs_channel->curregs[3] &= ~RxENABLE;
- write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
- info->zs_channel->curregs[1] = 0; /* disable any rx ints */
- write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
- ZS_CLEARFIFO(info->zs_channel);
- if (info->flags & ZILOG_INITIALIZED) {
- /*
- * Before we drop DTR, make sure the SCC transmitter
- * has completely drained.
- */
- rs_wait_until_sent(tty, info->timeout);
- }
-
- shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- info->event = 0;
- info->tty = 0;
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
- wake_up_interruptible(&info->close_wait);
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct dec_serial *info = (struct dec_serial *) tty->driver_data;
- unsigned long orig_jiffies;
- int char_time;
-
- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
- return;
-
- orig_jiffies = jiffies;
- /*
- * 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
- * interval should also be less than the timeout.
- */
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time == 0)
- char_time = 1;
- if (timeout)
- char_time = min(char_time, timeout);
- while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
- current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~ZILOG_NORMAL_ACTIVE;
- info->tty = 0;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct dec_serial *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ZILOG_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- return ((info->flags & ZILOG_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- spin_lock(&zs_lock);
- if (!tty_hung_up_p(filp))
- info->count--;
- spin_unlock_irq(&zs_lock);
- info->blocked_open++;
- while (1) {
- spin_lock(&zs_lock);
- if (tty->termios->c_cflag & CBAUD)
- zs_rtsdtr(info, RTS | DTR, 1);
- spin_unlock_irq(&zs_lock);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ZILOG_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ZILOG_CLOSING) &&
- (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- if (retval)
- return retval;
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its ZILOG structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
- struct dec_serial *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (line >= zs_channels_found))
- return -ENODEV;
- info = zs_soft + line;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s, count = %d\n", tty->name, info->count);
-#endif
-
- info->count++;
- tty->driver_data = info;
- info->tty = tty;
-
- /*
- * If the port is the middle of closing, bail out now
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ZILOG_CLOSING)) {
- if (info->flags & ZILOG_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- return ((info->flags & ZILOG_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * Start up serial port
- */
- retval = zs_startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
- if (zs_console.cflag && zs_console.index == line) {
- tty->termios->c_cflag = zs_console.cflag;
- zs_console.cflag = 0;
- change_speed(info);
- }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s successful...", tty->name);
-#endif
-/* tty->low_latency = 1; */
- return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void __init show_serial_version(void)
-{
- printk("DECstation Z8530 serial driver version 0.09\n");
-}
-
-/* Initialize Z8530s zs_channels
- */
-
-static void __init probe_sccs(void)
-{
- struct dec_serial **pp;
- int i, n, n_chips = 0, n_channels, chip, channel;
- unsigned long flags;
-
- /*
- * did we get here by accident?
- */
- if(!BUS_PRESENT) {
- printk("Not on JUNKIO machine, skipping probe_sccs\n");
- return;
- }
-
- switch(mips_machtype) {
-#ifdef CONFIG_MACH_DECSTATION
- case MACH_DS5000_2X0:
- case MACH_DS5900:
- n_chips = 2;
- zs_parms = &ds_parms;
- zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
- zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
- break;
- case MACH_DS5000_1XX:
- n_chips = 2;
- zs_parms = &ds_parms;
- zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
- zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
- break;
- case MACH_DS5000_XX:
- n_chips = 1;
- zs_parms = &ds_parms;
- zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
- break;
-#endif
- default:
- panic("zs: unsupported bus");
- }
- if (!zs_parms)
- panic("zs: uninitialized parms");
-
- pp = &zs_chain;
-
- n_channels = 0;
-
- for (chip = 0; chip < n_chips; chip++) {
- for (channel = 0; channel <= 1; channel++) {
- /*
- * The sccs reside on the high byte of the 16 bit IOBUS
- */
- zs_channels[n_channels].control =
- (volatile void *)CKSEG1ADDR(dec_kn_slot_base +
- (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
- (0 == channel ? zs_parms->channel_a_offset :
- zs_parms->channel_b_offset));
- zs_channels[n_channels].data =
- zs_channels[n_channels].control + 4;
-
-#ifndef CONFIG_SERIAL_DEC_CONSOLE
- /*
- * We're called early and memory managment isn't up, yet.
- * Thus request_region would fail.
- */
- if (!request_region((unsigned long)
- zs_channels[n_channels].control,
- ZS_CHAN_IO_SIZE, "SCC"))
- panic("SCC I/O region is not free");
-#endif
- zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
- /* HACK alert! */
- if (!(chip & 1))
- zs_soft[n_channels].irq = zs_parms->irq0;
- else
- zs_soft[n_channels].irq = zs_parms->irq1;
-
- /*
- * Identification of channel A. Location of channel A
- * inside chip depends on mapping of internal address
- * the chip decodes channels by.
- * CHANNEL_A_NR returns either 0 (in case of
- * DECstations) or 1 (in case of Baget).
- */
- if (CHANNEL_A_NR == channel)
- zs_soft[n_channels].zs_chan_a =
- &zs_channels[n_channels+1-2*CHANNEL_A_NR];
- else
- zs_soft[n_channels].zs_chan_a =
- &zs_channels[n_channels];
-
- *pp = &zs_soft[n_channels];
- pp = &zs_soft[n_channels].zs_next;
- n_channels++;
- }
- }
-
- *pp = 0;
- zs_channels_found = n_channels;
-
- for (n = 0; n < zs_channels_found; n++) {
- for (i = 0; i < 16; i++) {
- zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i];
- }
- }
-
- spin_lock_irqsave(&zs_lock, flags);
- for (n = 0; n < zs_channels_found; n++) {
- if (n % 2 == 0) {
- write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
- udelay(10);
- write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
- }
- load_zsregs(zs_soft[n].zs_channel,
- zs_soft[n].zs_channel->curregs);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static const struct tty_operations serial_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .break_ctl = rs_break,
- .wait_until_sent = rs_wait_until_sent,
- .tiocmget = rs_tiocmget,
- .tiocmset = rs_tiocmset,
-};
-
-/* zs_init inits the driver */
-int __init zs_init(void)
-{
- int channel, i;
- struct dec_serial *info;
-
- if(!BUS_PRESENT)
- return -ENODEV;
-
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
- serial_driver = alloc_tty_driver(zs_channels_found);
- if (!serial_driver)
- return -ENOMEM;
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* Not all of this is exactly right for us. */
-
- serial_driver->owner = THIS_MODULE;
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(serial_driver, &serial_ops);
-
- if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver");
-
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
-
- /* Needed before interrupts are enabled. */
- info->tty = 0;
- info->x_char = 0;
-
- if (info->hook && info->hook->init_info) {
- (*info->hook->init_info)(info);
- continue;
- }
-
- info->magic = SERIAL_MAGIC;
- info->port = (int) info->zs_channel->control;
- info->line = i;
- info->custom_divisor = 16;
- info->close_delay = 50;
- info->closing_wait = 3000;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- tasklet_init(&info->tlet, do_softint, (unsigned long)info);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
- info->line, info->port, info->irq);
- tty_register_device(serial_driver, info->line, NULL);
-
- }
-
- for (channel = 0; channel < zs_channels_found; ++channel) {
- zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-
- if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED,
- "scc", &zs_soft[channel]))
- printk(KERN_ERR "decserial: can't get irq %d\n",
- zs_soft[channel].irq);
-
- if (zs_soft[channel].hook) {
- zs_startup(&zs_soft[channel]);
- if (zs_soft[channel].hook->init_channel)
- (*zs_soft[channel].hook->init_channel)
- (&zs_soft[channel]);
- }
- }
-
- return 0;
-}
-
-/*
- * polling I/O routines
- */
-static int zs_poll_tx_char(void *handle, unsigned char ch)
-{
- struct dec_serial *info = handle;
- struct dec_zschannel *chan = info->zs_channel;
- int ret;
-
- if(chan) {
- int loops = 10000;
-
- while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
- loops--;
-
- if (loops) {
- write_zsdata(chan, ch);
- ret = 0;
- } else
- ret = -EAGAIN;
-
- return ret;
- } else
- return -ENODEV;
-}
-
-static int zs_poll_rx_char(void *handle)
-{
- struct dec_serial *info = handle;
- struct dec_zschannel *chan = info->zs_channel;
- int ret;
-
- if(chan) {
- int loops = 10000;
-
- while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
- loops--;
-
- if (loops)
- ret = read_zsdata(chan);
- else
- ret = -EAGAIN;
-
- return ret;
- } else
- return -ENODEV;
-}
-
-int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
-{
- struct dec_serial *info = &zs_soft[channel];
-
- if (info->hook) {
- printk("%s: line %d has already a hook registered\n",
- __FUNCTION__, channel);
-
- return 0;
- } else {
- hook->poll_rx_char = zs_poll_rx_char;
- hook->poll_tx_char = zs_poll_tx_char;
- info->hook = hook;
-
- return 1;
- }
-}
-
-int unregister_zs_hook(unsigned int channel)
-{
- struct dec_serial *info = &zs_soft[channel];
-
- if (info->hook) {
- info->hook = NULL;
- return 1;
- } else {
- printk("%s: trying to unregister hook on line %d,"
- " but none is registered\n", __FUNCTION__, channel);
- return 0;
- }
-}
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
- unsigned count)
-{
- struct dec_serial *info;
- int i;
-
- info = zs_soft + co->index;
-
- for (i = 0; i < count; i++, s++) {
- if(*s == '\n')
- zs_poll_tx_char(info, '\r');
- zs_poll_tx_char(info, *s);
- }
-}
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-/*
- * Setup initial baud/bits/parity. We do two things here:
- * - construct a cflag setting for the first rs_open()
- * - initialize the serial port
- * Return non-zero if we didn't find a serial port.
- */
-static int __init serial_console_setup(struct console *co, char *options)
-{
- struct dec_serial *info;
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int cflag = CREAD | HUPCL | CLOCAL;
- int clk_divisor = 16;
- int brg;
- char *s;
- unsigned long flags;
-
- if(!BUS_PRESENT)
- return -ENODEV;
-
- info = zs_soft + co->index;
-
- if (zs_chain == 0)
- probe_sccs();
-
- info->is_cons = 1;
-
- if (options) {
- baud = simple_strtoul(options, NULL, 10);
- s = options;
- while(*s >= '0' && *s <= '9')
- s++;
- if (*s)
- parity = *s++;
- if (*s)
- bits = *s - '0';
- }
-
- /*
- * Now construct a cflag setting.
- */
- switch(baud) {
- 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;
- /*
- * Set this to a sane value to prevent a divide error.
- */
- baud = 9600;
- break;
- }
- switch(bits) {
- case 7:
- cflag |= CS7;
- break;
- default:
- case 8:
- cflag |= CS8;
- break;
- }
- switch(parity) {
- case 'o': case 'O':
- cflag |= PARODD;
- break;
- case 'e': case 'E':
- cflag |= PARENB;
- break;
- }
- co->cflag = cflag;
-
- spin_lock_irqsave(&zs_lock, flags);
-
- /*
- * Set up the baud rate generator.
- */
- brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
- info->zs_channel->curregs[R12] = (brg & 255);
- info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
-
- /*
- * Set byte size and parity.
- */
- if (bits == 7) {
- info->zs_channel->curregs[R3] |= Rx7;
- info->zs_channel->curregs[R5] |= Tx7;
- } else {
- info->zs_channel->curregs[R3] |= Rx8;
- info->zs_channel->curregs[R5] |= Tx8;
- }
- if (cflag & PARENB) {
- info->zs_channel->curregs[R4] |= PAR_ENA;
- }
- if (!(cflag & PARODD)) {
- info->zs_channel->curregs[R4] |= PAR_EVEN;
- }
- info->zs_channel->curregs[R4] |= SB1;
-
- /*
- * Turn on RTS and DTR.
- */
- zs_rtsdtr(info, RTS | DTR, 1);
-
- /*
- * Finally, enable sequencing.
- */
- info->zs_channel->curregs[R3] |= RxENABLE;
- info->zs_channel->curregs[R5] |= TxENAB;
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
- /*
- * Load up the new values.
- */
- load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
- zs_soft[co->index].clk_divisor = clk_divisor;
- zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
-
- spin_unlock_irqrestore(&zs_lock, flags);
-
- return 0;
-}
-
-static struct console zs_console = {
- .name = "ttyS",
- .write = serial_console_write,
- .device = serial_console_device,
- .setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-/*
- * Register console.
- */
-void __init zs_serial_console_init(void)
-{
- register_console(&zs_console);
-}
-#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
-
-#ifdef CONFIG_KGDB
-struct dec_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
- 9, 0x80, /* reset A side (CHRA) */
- 13, 0, /* set baud rate divisor */
- 12, 1,
- 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
- 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
- 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
- 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
- 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct dec_zschannel *chan = zs_kgdbchan;
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- RECOVERY_DELAY;
- write_zsdata(chan, kgdb_char);
-}
-char getDebugChar(void)
-{
- struct dec_zschannel *chan = zs_kgdbchan;
- while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- eieio(); /*barrier();*/
- return read_zsdata(chan);
-}
-void kgdb_interruptible(int yes)
-{
- struct dec_zschannel *chan = zs_kgdbchan;
- int one, nine;
- nine = read_zsreg(chan, 9);
- if (yes == 1) {
- one = EXT_INT_ENAB|RxINT_ALL;
- nine |= MIE;
- printk("turning serial ints on\n");
- } else {
- one = RxINT_DISAB;
- nine &= ~MIE;
- printk("turning serial ints off\n");
- }
- write_zsreg(chan, 1, one);
- write_zsreg(chan, 9, nine);
-}
-
-static int kgdbhook_init_channel(void *handle)
-{
- return 0;
-}
-
-static void kgdbhook_init_info(void *handle)
-{
-}
-
-static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
-{
- struct dec_serial *info = handle;
-
- if (fl != TTY_NORMAL)
- return;
- if (ch == 0x03 || ch == '$')
- breakpoint();
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
-{
- int brg;
- int i, x;
- volatile char *sccc = ms->control;
- brg = BPS_TO_BRG(bps, zs_parms->clock/16);
- printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
- for (i = 20000; i != 0; --i) {
- x = *sccc; eieio();
- }
- for (i = 0; i < sizeof(scc_inittab); ++i) {
- write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
- i++;
- }
-}
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- */
-struct dec_serial_hook zs_kgdbhook = {
- .init_channel = kgdbhook_init_channel,
- .init_info = kgdbhook_init_info,
- .rx_char = kgdbhook_rx_char,
- .cflags = B38400 | CS8 | CLOCAL,
-};
-
-void __init zs_kgdb_hook(int tty_num)
-{
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
- zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
- zs_kgdbchan = zs_soft[tty_num].zs_channel;
- zs_soft[tty_num].change_needed = 0;
- zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = 38400;
- zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */
- /* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
- printk("KGDB: on channel %d initialized\n", tty_num);
- set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h
deleted file mode 100644
index 13512200ceba..000000000000
--- a/drivers/tc/zs.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2004, 2005 Maciej W. Rozycki
- */
-#ifndef _DECSERIAL_H
-#define _DECSERIAL_H
-
-#include <asm/dec/serial.h>
-
-#define NUM_ZSREGS 16
-
-struct serial_struct {
- int type;
- int line;
- int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char reserved_char[2];
- int hub6;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- on the callout port */
-#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct dec_zschannel {
- volatile unsigned char *control;
- volatile unsigned char *data;
-
- /* Current write register values */
- unsigned char curregs[NUM_ZSREGS];
-};
-
-struct dec_serial {
- struct dec_serial *zs_next; /* For IRQ servicing chain. */
- struct dec_zschannel *zs_channel; /* Channel registers. */
- struct dec_zschannel *zs_chan_a; /* A side registers. */
- unsigned char read_reg_zero;
-
- struct dec_serial_hook *hook; /* Hook on this channel. */
- int tty_break; /* Set on BREAK condition. */
- int is_cons; /* Is this our console. */
- int tx_active; /* Char is being xmitted. */
- int tx_stopped; /* Output is suspended. */
-
- /*
- * We need to know the current clock divisor
- * to read the bps rate the chip has currently loaded.
- */
- int clk_divisor; /* May be 1, 16, 32, or 64. */
- int zs_baud;
-
- char change_needed;
-
- int magic;
- int baud_base;
- int port;
- int irq;
- int flags; /* Defined in tty.h. */
- int type; /* UART type. */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int xmit_fifo_size;
- int custom_divisor;
- int x_char; /* XON/XOFF character. */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fds on device. */
- int blocked_open; /* # of blocked opens. */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct tasklet_struct tlet;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define FLAG 0x7e
-
-/* Write Register 0 */
-#define R0 0 /* Register selects */
-#define R1 1
-#define R2 2
-#define R3 3
-#define R4 4
-#define R5 5
-#define R6 6
-#define R7 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-#define R12 12
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define NULLCODE 0 /* Null Code */
-#define POINT_HIGH 0x8 /* Select upper half of registers */
-#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
-#define SEND_ABORT 0x18 /* HDLC Abort */
-#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
-#define RES_Tx_P 0x28 /* Reset TxINT Pending */
-#define ERR_RES 0x30 /* Error Reset */
-#define RES_H_IUS 0x38 /* Reset highest IUS */
-
-#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
-#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
-#define RES_EOM_L 0xC0 /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
-#define TxINT_ENAB 0x2 /* Tx Int Enable */
-#define PAR_SPEC 0x4 /* Parity is special condition */
-
-#define RxINT_DISAB 0 /* Rx Int Disable */
-#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
-#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */
-#define RxINT_ERR 0x18 /* Int on error only */
-#define RxINT_MASK 0x18
-
-#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
-#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
-#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define RxENABLE 0x1 /* Rx Enable */
-#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
-#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
-#define ENT_HM 0x10 /* Enter Hunt Mode */
-#define AUTO_ENAB 0x20 /* Auto Enables */
-#define Rx5 0x0 /* Rx 5 Bits/Character */
-#define Rx7 0x40 /* Rx 7 Bits/Character */
-#define Rx6 0x80 /* Rx 6 Bits/Character */
-#define Rx8 0xc0 /* Rx 8 Bits/Character */
-#define RxNBITS_MASK 0xc0
-
-/* Write Register 4 */
-
-#define PAR_ENA 0x1 /* Parity Enable */
-#define PAR_EVEN 0x2 /* Parity Even/Odd* */
-
-#define SYNC_ENAB 0 /* Sync Modes Enable */
-#define SB1 0x4 /* 1 stop bit/char */
-#define SB15 0x8 /* 1.5 stop bits/char */
-#define SB2 0xc /* 2 stop bits/char */
-#define SB_MASK 0xc
-
-#define MONSYNC 0 /* 8 Bit Sync character */
-#define BISYNC 0x10 /* 16 bit sync character */
-#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC 0x30 /* External Sync Mode */
-
-#define X1CLK 0x0 /* x1 clock mode */
-#define X16CLK 0x40 /* x16 clock mode */
-#define X32CLK 0x80 /* x32 clock mode */
-#define X64CLK 0xC0 /* x64 clock mode */
-#define XCLK_MASK 0xC0
-
-/* Write Register 5 */
-
-#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
-#define RTS 0x2 /* RTS */
-#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENAB 0x8 /* Tx Enable */
-#define SND_BRK 0x10 /* Send Break */
-#define Tx5 0x0 /* Tx 5 bits (or less)/character */
-#define Tx7 0x20 /* Tx 7 bits/character */
-#define Tx6 0x40 /* Tx 6 bits/character */
-#define Tx8 0x60 /* Tx 8 bits/character */
-#define TxNBITS_MASK 0x60
-#define DTR 0x80 /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define VIS 1 /* Vector Includes Status */
-#define NV 2 /* No Vector */
-#define DLC 4 /* Disable Lower Chain */
-#define MIE 8 /* Master Interrupt Enable */
-#define STATHI 0x10 /* Status high */
-#define SOFTACK 0x20 /* Software Interrupt Acknowledge */
-#define NORESET 0 /* No reset on write to R9 */
-#define CHRB 0x40 /* Reset channel B */
-#define CHRA 0x80 /* Reset channel A */
-#define FHWRES 0xc0 /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define BIT6 1 /* 6 bit/8bit sync */
-#define LOOPMODE 2 /* SDLC Loop mode */
-#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE 8 /* Mark/flag on idle */
-#define GAOP 0x10 /* Go active on poll */
-#define NRZ 0 /* NRZ mode */
-#define NRZI 0x20 /* NRZI mode */
-#define FM1 0x40 /* FM1 (transition = 1) */
-#define FM0 0x60 /* FM0 (transition = 0) */
-#define CRCPS 0x80 /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define TRxCXT 0 /* TRxC = Xtal output */
-#define TRxCTC 1 /* TRxC = Transmit clock */
-#define TRxCBR 2 /* TRxC = BR Generator Output */
-#define TRxCDP 3 /* TRxC = DPLL output */
-#define TRxCOI 4 /* TRxC O/I */
-#define TCRTxCP 0 /* Transmit clock = RTxC pin */
-#define TCTRxCP 8 /* Transmit clock = TRxC pin */
-#define TCBR 0x10 /* Transmit clock = BR Generator output */
-#define TCDPLL 0x18 /* Transmit clock = DPLL output */
-#define RCRTxCP 0 /* Receive clock = RTxC pin */
-#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
-#define RCBR 0x40 /* Receive clock = BR Generator output */
-#define RCDPLL 0x60 /* Receive clock = DPLL output */
-#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
-#define BRSRC 2 /* Baud rate generator source */
-#define DTRREQ 4 /* DTR/Request function */
-#define AUTOECHO 8 /* Auto Echo */
-#define LOOPBAK 0x10 /* Local loopback */
-#define SEARCH 0x20 /* Enter search mode */
-#define RMC 0x40 /* Reset missing clock */
-#define DISDPLL 0x60 /* Disable DPLL */
-#define SSBR 0x80 /* Set DPLL source = BR generator */
-#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
-#define SFMM 0xc0 /* Set FM mode */
-#define SNRZI 0xe0 /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define ZCIE 2 /* Zero count IE */
-#define DCDIE 8 /* DCD IE */
-#define SYNCIE 0x10 /* Sync/hunt IE */
-#define CTSIE 0x20 /* CTS IE */
-#define TxUIE 0x40 /* Tx Underrun/EOM IE */
-#define BRKIE 0x80 /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define Rx_CH_AV 0x1 /* Rx Character Available */
-#define ZCOUNT 0x2 /* Zero count */
-#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
-#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
-#define CTS 0x20 /* CTS */
-#define TxEOM 0x40 /* Tx underrun */
-#define BRK_ABRT 0x80 /* Break/Abort */
-
-/* Read Register 1 */
-#define ALL_SNT 0x1 /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3 0x8 /* 0/3 */
-#define RES4 0x4 /* 0/4 */
-#define RES5 0xc /* 0/5 */
-#define RES6 0x2 /* 0/6 */
-#define RES7 0xa /* 0/7 */
-#define RES8 0x6 /* 0/8 */
-#define RES18 0xe /* 1/8 */
-#define RES28 0x0 /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR 0x10 /* Parity error */
-#define Rx_OVR 0x20 /* Rx Overrun Error */
-#define FRM_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
-#define CHBTxIP 0x2 /* Channel B Tx IP */
-#define CHBRxIP 0x4 /* Channel B Rx IP */
-#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
-#define CHATxIP 0x10 /* Channel A Tx IP */
-#define CHARxIP 0x20 /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10 (misc status bits) */
-#define ONLOOP 2 /* On loop */
-#define LOOPSEND 0x10 /* Loop sending */
-#define CLK2MIS 0x40 /* Two clocks missing */
-#define CLK1MIS 0x80 /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- } while(0)
-
-#endif /* !(_DECSERIAL_H) */
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index 3e658dc7c2d8..ff9a29b76336 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -45,11 +45,10 @@ static int ixj_probe(struct pcmcia_device *p_dev)
p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
p_dev->io.IOAddrLines = 3;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
- p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
+ p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
if (!p_dev->priv) {
return -ENOMEM;
}
- memset(p_dev->priv, 0, sizeof(struct ixj_info_t));
return ixj_config(p_dev);
}
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
new file mode 100644
index 000000000000..b778ed71f636
--- /dev/null
+++ b/drivers/uio/Kconfig
@@ -0,0 +1,29 @@
+menu "Userspace I/O"
+ depends on !S390
+
+config UIO
+ tristate "Userspace I/O drivers"
+ default n
+ help
+ Enable this to allow the userspace driver core code to be
+ built. This code allows userspace programs easy access to
+ kernel interrupts and memory locations, allowing some drivers
+ to be written in userspace. Note that a small kernel driver
+ is also required for interrupt handling to work properly.
+
+ If you don't know what to do here, say N.
+
+config UIO_CIF
+ tristate "generic Hilscher CIF Card driver"
+ depends on UIO && PCI
+ default n
+ help
+ Driver for Hilscher CIF DeviceNet and Profibus cards. This
+ driver requires a userspace component that handles all of the
+ heavy lifting and can be found at:
+ http://www.osadl.org/projects/downloads/UIO/user/cif-*
+
+ To compile this driver as a module, choose M here: the module
+ will be called uio_cif.
+
+endmenu
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
new file mode 100644
index 000000000000..7fecfb459da5
--- /dev/null
+++ b/drivers/uio/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_UIO) += uio.o
+obj-$(CONFIG_UIO_CIF) += uio_cif.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
new file mode 100644
index 000000000000..865f32b63b5c
--- /dev/null
+++ b/drivers/uio/uio.c
@@ -0,0 +1,701 @@
+/*
+ * drivers/uio/uio.c
+ *
+ * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * Userspace IO
+ *
+ * Base Functions
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/uio_driver.h>
+
+#define UIO_MAX_DEVICES 255
+
+struct uio_device {
+ struct module *owner;
+ struct device *dev;
+ int minor;
+ atomic_t event;
+ struct fasync_struct *async_queue;
+ wait_queue_head_t wait;
+ int vma_count;
+ struct uio_info *info;
+ struct kset map_attr_kset;
+};
+
+static int uio_major;
+static DEFINE_IDR(uio_idr);
+static struct file_operations uio_fops;
+
+/* UIO class infrastructure */
+static struct uio_class {
+ struct kref kref;
+ struct class *class;
+} *uio_class;
+
+/*
+ * attributes
+ */
+
+static struct attribute attr_addr = {
+ .name = "addr",
+ .mode = S_IRUGO,
+};
+
+static struct attribute attr_size = {
+ .name = "size",
+ .mode = S_IRUGO,
+};
+
+static struct attribute* map_attrs[] = {
+ &attr_addr, &attr_size, NULL
+};
+
+static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
+
+ if (strncmp(attr->name,"addr",4) == 0)
+ return sprintf(buf, "0x%lx\n", mem->addr);
+
+ if (strncmp(attr->name,"size",4) == 0)
+ return sprintf(buf, "0x%lx\n", mem->size);
+
+ return -ENODEV;
+}
+
+static void map_attr_release(struct kobject *kobj)
+{
+ /* TODO ??? */
+}
+
+static struct sysfs_ops map_attr_ops = {
+ .show = map_attr_show,
+};
+
+static struct kobj_type map_attr_type = {
+ .release = map_attr_release,
+ .sysfs_ops = &map_attr_ops,
+ .default_attrs = map_attrs,
+};
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uio_device *idev = dev_get_drvdata(dev);
+ if (idev)
+ return sprintf(buf, "%s\n", idev->info->name);
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static ssize_t show_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uio_device *idev = dev_get_drvdata(dev);
+ if (idev)
+ return sprintf(buf, "%s\n", idev->info->version);
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uio_device *idev = dev_get_drvdata(dev);
+ if (idev)
+ return sprintf(buf, "%u\n",
+ (unsigned int)atomic_read(&idev->event));
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
+
+static struct attribute *uio_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_version.attr,
+ &dev_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group uio_attr_grp = {
+ .attrs = uio_attrs,
+};
+
+/*
+ * device functions
+ */
+static int uio_dev_add_attributes(struct uio_device *idev)
+{
+ int ret;
+ int mi;
+ int map_found = 0;
+ struct uio_mem *mem;
+
+ ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
+ if (ret)
+ goto err_group;
+
+ for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+ mem = &idev->info->mem[mi];
+ if (mem->size == 0)
+ break;
+ if (!map_found) {
+ map_found = 1;
+ kobject_set_name(&idev->map_attr_kset.kobj,"maps");
+ idev->map_attr_kset.ktype = &map_attr_type;
+ idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
+ ret = kset_register(&idev->map_attr_kset);
+ if (ret)
+ goto err_remove_group;
+ }
+ kobject_init(&mem->kobj);
+ kobject_set_name(&mem->kobj,"map%d",mi);
+ mem->kobj.parent = &idev->map_attr_kset.kobj;
+ mem->kobj.kset = &idev->map_attr_kset;
+ ret = kobject_add(&mem->kobj);
+ if (ret)
+ goto err_remove_maps;
+ }
+
+ return 0;
+
+err_remove_maps:
+ for (mi--; mi>=0; mi--) {
+ mem = &idev->info->mem[mi];
+ kobject_unregister(&mem->kobj);
+ }
+ kset_unregister(&idev->map_attr_kset); /* Needed ? */
+err_remove_group:
+ sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+err_group:
+ dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
+ return ret;
+}
+
+static void uio_dev_del_attributes(struct uio_device *idev)
+{
+ int mi;
+ struct uio_mem *mem;
+ for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+ mem = &idev->info->mem[mi];
+ if (mem->size == 0)
+ break;
+ kobject_unregister(&mem->kobj);
+ }
+ kset_unregister(&idev->map_attr_kset);
+ sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+}
+
+static int uio_get_minor(struct uio_device *idev)
+{
+ static DEFINE_MUTEX(minor_lock);
+ int retval = -ENOMEM;
+ int id;
+
+ mutex_lock(&minor_lock);
+ if (idr_pre_get(&uio_idr, GFP_KERNEL) == 0)
+ goto exit;
+
+ retval = idr_get_new(&uio_idr, idev, &id);
+ if (retval < 0) {
+ if (retval == -EAGAIN)
+ retval = -ENOMEM;
+ goto exit;
+ }
+ idev->minor = id & MAX_ID_MASK;
+exit:
+ mutex_unlock(&minor_lock);
+ return retval;
+}
+
+static void uio_free_minor(struct uio_device *idev)
+{
+ idr_remove(&uio_idr, idev->minor);
+}
+
+/**
+ * uio_event_notify - trigger an interrupt event
+ * @info: UIO device capabilities
+ */
+void uio_event_notify(struct uio_info *info)
+{
+ struct uio_device *idev = info->uio_dev;
+
+ atomic_inc(&idev->event);
+ wake_up_interruptible(&idev->wait);
+ kill_fasync(&idev->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(uio_event_notify);
+
+/**
+ * uio_interrupt - hardware interrupt handler
+ * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer
+ * @dev_id: Pointer to the devices uio_device structure
+ */
+static irqreturn_t uio_interrupt(int irq, void *dev_id)
+{
+ struct uio_device *idev = (struct uio_device *)dev_id;
+ irqreturn_t ret = idev->info->handler(irq, idev->info);
+
+ if (ret == IRQ_HANDLED)
+ uio_event_notify(idev->info);
+
+ return ret;
+}
+
+struct uio_listener {
+ struct uio_device *dev;
+ s32 event_count;
+};
+
+static int uio_open(struct inode *inode, struct file *filep)
+{
+ struct uio_device *idev;
+ struct uio_listener *listener;
+ int ret = 0;
+
+ idev = idr_find(&uio_idr, iminor(inode));
+ if (!idev)
+ return -ENODEV;
+
+ listener = kmalloc(sizeof(*listener), GFP_KERNEL);
+ if (!listener)
+ return -ENOMEM;
+
+ listener->dev = idev;
+ listener->event_count = atomic_read(&idev->event);
+ filep->private_data = listener;
+
+ if (idev->info->open) {
+ if (!try_module_get(idev->owner))
+ return -ENODEV;
+ ret = idev->info->open(idev->info, inode);
+ module_put(idev->owner);
+ }
+
+ if (ret)
+ kfree(listener);
+
+ return ret;
+}
+
+static int uio_fasync(int fd, struct file *filep, int on)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+
+ return fasync_helper(fd, filep, on, &idev->async_queue);
+}
+
+static int uio_release(struct inode *inode, struct file *filep)
+{
+ int ret = 0;
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+
+ if (idev->info->release) {
+ if (!try_module_get(idev->owner))
+ return -ENODEV;
+ ret = idev->info->release(idev->info, inode);
+ module_put(idev->owner);
+ }
+ if (filep->f_flags & FASYNC)
+ ret = uio_fasync(-1, filep, 0);
+ kfree(listener);
+ return ret;
+}
+
+static unsigned int uio_poll(struct file *filep, poll_table *wait)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+
+ if (idev->info->irq == UIO_IRQ_NONE)
+ return -EIO;
+
+ poll_wait(filep, &idev->wait, wait);
+ if (listener->event_count != atomic_read(&idev->event))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static ssize_t uio_read(struct file *filep, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t retval;
+ s32 event_count;
+
+ if (idev->info->irq == UIO_IRQ_NONE)
+ return -EIO;
+
+ if (count != sizeof(s32))
+ return -EINVAL;
+
+ add_wait_queue(&idev->wait, &wait);
+
+ do {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ event_count = atomic_read(&idev->event);
+ if (event_count != listener->event_count) {
+ if (copy_to_user(buf, &event_count, count))
+ retval = -EFAULT;
+ else {
+ listener->event_count = event_count;
+ retval = count;
+ }
+ break;
+ }
+
+ if (filep->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ } while (1);
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&idev->wait, &wait);
+
+ return retval;
+}
+
+static int uio_find_mem_index(struct vm_area_struct *vma)
+{
+ int mi;
+ struct uio_device *idev = vma->vm_private_data;
+
+ for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+ if (idev->info->mem[mi].size == 0)
+ return -1;
+ if (vma->vm_pgoff == mi)
+ return mi;
+ }
+ return -1;
+}
+
+static void uio_vma_open(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ idev->vma_count++;
+}
+
+static void uio_vma_close(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ idev->vma_count--;
+}
+
+static struct page *uio_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ struct page* page = NOPAGE_SIGBUS;
+
+ int mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return page;
+
+ if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
+ page = virt_to_page(idev->info->mem[mi].addr);
+ else
+ page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
+ get_page(page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return page;
+}
+
+static struct vm_operations_struct uio_vm_ops = {
+ .open = uio_vma_open,
+ .close = uio_vma_close,
+ .nopage = uio_vma_nopage,
+};
+
+static int uio_mmap_physical(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ int mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return -EINVAL;
+
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ return remap_pfn_range(vma,
+ vma->vm_start,
+ idev->info->mem[mi].addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &uio_vm_ops;
+ uio_vma_open(vma);
+ return 0;
+}
+
+static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+ int mi;
+ unsigned long requested_pages, actual_pages;
+ int ret = 0;
+
+ if (vma->vm_end < vma->vm_start)
+ return -EINVAL;
+
+ vma->vm_private_data = idev;
+
+ mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return -EINVAL;
+
+ requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
+ if (requested_pages > actual_pages)
+ return -EINVAL;
+
+ if (idev->info->mmap) {
+ if (!try_module_get(idev->owner))
+ return -ENODEV;
+ ret = idev->info->mmap(idev->info, vma);
+ module_put(idev->owner);
+ return ret;
+ }
+
+ switch (idev->info->mem[mi].memtype) {
+ case UIO_MEM_PHYS:
+ return uio_mmap_physical(vma);
+ case UIO_MEM_LOGICAL:
+ case UIO_MEM_VIRTUAL:
+ return uio_mmap_logical(vma);
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct file_operations uio_fops = {
+ .owner = THIS_MODULE,
+ .open = uio_open,
+ .release = uio_release,
+ .read = uio_read,
+ .mmap = uio_mmap,
+ .poll = uio_poll,
+ .fasync = uio_fasync,
+};
+
+static int uio_major_init(void)
+{
+ uio_major = register_chrdev(0, "uio", &uio_fops);
+ if (uio_major < 0)
+ return uio_major;
+ return 0;
+}
+
+static void uio_major_cleanup(void)
+{
+ unregister_chrdev(uio_major, "uio");
+}
+
+static int init_uio_class(void)
+{
+ int ret = 0;
+
+ if (uio_class != NULL) {
+ kref_get(&uio_class->kref);
+ goto exit;
+ }
+
+ /* This is the first time in here, set everything up properly */
+ ret = uio_major_init();
+ if (ret)
+ goto exit;
+
+ uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL);
+ if (!uio_class) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ kref_init(&uio_class->kref);
+ uio_class->class = class_create(THIS_MODULE, "uio");
+ if (IS_ERR(uio_class->class)) {
+ ret = IS_ERR(uio_class->class);
+ printk(KERN_ERR "class_create failed for uio\n");
+ goto err_class_create;
+ }
+ return 0;
+
+err_class_create:
+ kfree(uio_class);
+ uio_class = NULL;
+err_kzalloc:
+ uio_major_cleanup();
+exit:
+ return ret;
+}
+
+static void release_uio_class(struct kref *kref)
+{
+ /* Ok, we cheat as we know we only have one uio_class */
+ class_destroy(uio_class->class);
+ kfree(uio_class);
+ uio_major_cleanup();
+ uio_class = NULL;
+}
+
+static void uio_class_destroy(void)
+{
+ if (uio_class)
+ kref_put(&uio_class->kref, release_uio_class);
+}
+
+/**
+ * uio_register_device - register a new userspace IO device
+ * @owner: module that creates the new device
+ * @parent: parent device
+ * @info: UIO device capabilities
+ *
+ * returns zero on success or a negative error code.
+ */
+int __uio_register_device(struct module *owner,
+ struct device *parent,
+ struct uio_info *info)
+{
+ struct uio_device *idev;
+ int ret = 0;
+
+ if (!parent || !info || !info->name || !info->version)
+ return -EINVAL;
+
+ info->uio_dev = NULL;
+
+ ret = init_uio_class();
+ if (ret)
+ return ret;
+
+ idev = kzalloc(sizeof(*idev), GFP_KERNEL);
+ if (!idev) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ idev->owner = owner;
+ idev->info = info;
+ init_waitqueue_head(&idev->wait);
+ atomic_set(&idev->event, 0);
+
+ ret = uio_get_minor(idev);
+ if (ret)
+ goto err_get_minor;
+
+ idev->dev = device_create(uio_class->class, parent,
+ MKDEV(uio_major, idev->minor),
+ "uio%d", idev->minor);
+ if (IS_ERR(idev->dev)) {
+ printk(KERN_ERR "UIO: device register failed\n");
+ ret = PTR_ERR(idev->dev);
+ goto err_device_create;
+ }
+ dev_set_drvdata(idev->dev, idev);
+
+ ret = uio_dev_add_attributes(idev);
+ if (ret)
+ goto err_uio_dev_add_attributes;
+
+ info->uio_dev = idev;
+
+ if (idev->info->irq >= 0) {
+ ret = request_irq(idev->info->irq, uio_interrupt,
+ idev->info->irq_flags, idev->info->name, idev);
+ if (ret)
+ goto err_request_irq;
+ }
+
+ return 0;
+
+err_request_irq:
+ uio_dev_del_attributes(idev);
+err_uio_dev_add_attributes:
+ device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+err_device_create:
+ uio_free_minor(idev);
+err_get_minor:
+ kfree(idev);
+err_kzalloc:
+ uio_class_destroy();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__uio_register_device);
+
+/**
+ * uio_unregister_device - unregister a industrial IO device
+ * @info: UIO device capabilities
+ *
+ */
+void uio_unregister_device(struct uio_info *info)
+{
+ struct uio_device *idev;
+
+ if (!info || !info->uio_dev)
+ return;
+
+ idev = info->uio_dev;
+
+ uio_free_minor(idev);
+
+ if (info->irq >= 0)
+ free_irq(info->irq, idev);
+
+ uio_dev_del_attributes(idev);
+
+ dev_set_drvdata(idev->dev, NULL);
+ device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+ kfree(idev);
+ uio_class_destroy();
+
+ return;
+}
+EXPORT_SYMBOL_GPL(uio_unregister_device);
+
+static int __init uio_init(void)
+{
+ return 0;
+}
+
+static void __exit uio_exit(void)
+{
+}
+
+module_init(uio_init)
+module_exit(uio_exit)
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
new file mode 100644
index 000000000000..838bae460831
--- /dev/null
+++ b/drivers/uio/uio_cif.c
@@ -0,0 +1,156 @@
+/*
+ * UIO Hilscher CIF card driver
+ *
+ * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#include <asm/io.h>
+
+#ifndef PCI_DEVICE_ID_PLX_9030
+#define PCI_DEVICE_ID_PLX_9030 0x9030
+#endif
+
+#define PLX9030_INTCSR 0x4C
+#define INTSCR_INT1_ENABLE 0x01
+#define INTSCR_INT1_STATUS 0x04
+#define INT1_ENABLED_AND_ACTIVE (INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS)
+
+#define PCI_SUBVENDOR_ID_PEP 0x1518
+#define CIF_SUBDEVICE_PROFIBUS 0x430
+#define CIF_SUBDEVICE_DEVICENET 0x432
+
+
+static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
+{
+ void __iomem *plx_intscr = dev_info->mem[0].internal_addr
+ + PLX9030_INTCSR;
+
+ if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE)
+ != INT1_ENABLED_AND_ACTIVE)
+ return IRQ_NONE;
+
+ /* Disable interrupt */
+ iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr);
+ return IRQ_HANDLED;
+}
+
+static int __devinit hilscher_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct uio_info *info;
+
+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (pci_enable_device(dev))
+ goto out_free;
+
+ if (pci_request_regions(dev, "hilscher"))
+ goto out_disable;
+
+ info->mem[0].addr = pci_resource_start(dev, 0);
+ if (!info->mem[0].addr)
+ goto out_release;
+ info->mem[0].internal_addr = ioremap(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!info->mem[0].internal_addr)
+ goto out_release;
+
+ info->mem[0].size = pci_resource_len(dev, 0);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+ info->mem[1].addr = pci_resource_start(dev, 2);
+ info->mem[1].size = pci_resource_len(dev, 2);
+ info->mem[1].memtype = UIO_MEM_PHYS;
+ switch (id->subdevice) {
+ case CIF_SUBDEVICE_PROFIBUS:
+ info->name = "CIF_Profibus";
+ break;
+ case CIF_SUBDEVICE_DEVICENET:
+ info->name = "CIF_Devicenet";
+ break;
+ default:
+ info->name = "CIF_???";
+ }
+ info->version = "0.0.1";
+ info->irq = dev->irq;
+ info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
+ info->handler = hilscher_handler;
+
+ if (uio_register_device(&dev->dev, info))
+ goto out_unmap;
+
+ pci_set_drvdata(dev, info);
+
+ return 0;
+out_unmap:
+ iounmap(info->mem[0].internal_addr);
+out_release:
+ pci_release_regions(dev);
+out_disable:
+ pci_disable_device(dev);
+out_free:
+ kfree (info);
+ return -ENODEV;
+}
+
+static void hilscher_pci_remove(struct pci_dev *dev)
+{
+ struct uio_info *info = pci_get_drvdata(dev);
+
+ uio_unregister_device(info);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ pci_set_drvdata(dev, NULL);
+ iounmap(info->mem[0].internal_addr);
+
+ kfree (info);
+}
+
+static struct pci_device_id hilscher_pci_ids[] = {
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_SUBVENDOR_ID_PEP,
+ .subdevice = CIF_SUBDEVICE_PROFIBUS,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_SUBVENDOR_ID_PEP,
+ .subdevice = CIF_SUBDEVICE_DEVICENET,
+ },
+ { 0, }
+};
+
+static struct pci_driver hilscher_pci_driver = {
+ .name = "hilscher",
+ .id_table = hilscher_pci_ids,
+ .probe = hilscher_pci_probe,
+ .remove = hilscher_pci_remove,
+};
+
+static int __init hilscher_init_module(void)
+{
+ return pci_register_driver(&hilscher_pci_driver);
+}
+
+static void __exit hilscher_exit_module(void)
+{
+ pci_unregister_driver(&hilscher_pci_driver);
+}
+
+module_init(hilscher_init_module);
+module_exit(hilscher_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7dd73546bf43..7580aa5da0f8 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -6,6 +6,9 @@ menuconfig USB_SUPPORT
bool "USB support"
depends on HAS_IOMEM
default y
+ ---help---
+ This option adds core support for Universal Serial Bus (USB).
+ You will also need drivers from the following menu to make use of it.
if USB_SUPPORT
@@ -18,6 +21,7 @@ config USB_ARCH_HAS_HCD
default y if USB_ARCH_HAS_EHCI
default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811
+ default y if SUPERH # r8a66597-hcd
default PCI
# many non-PCI SOC chips embed OHCI
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index befff5f9d58c..516a6400db43 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,26 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
-obj-$(CONFIG_USB_ADUTUX) += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
-obj-$(CONFIG_USB_AUERSWALD) += misc/
-obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM) += misc/
-obj-$(CONFIG_USB_EMI26) += misc/
-obj-$(CONFIG_USB_EMI62) += misc/
-obj-$(CONFIG_USB_FTDI_ELAN) += misc/
-obj-$(CONFIG_USB_IDMOUSE) += misc/
-obj-$(CONFIG_USB_LCD) += misc/
-obj-$(CONFIG_USB_LD) += misc/
-obj-$(CONFIG_USB_LED) += misc/
-obj-$(CONFIG_USB_LEGOTOWER) += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_RIO500) += misc/
-obj-$(CONFIG_USB_SISUSBVGA) += misc/
-obj-$(CONFIG_USB_TEST) += misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720) += misc/
+obj-$(CONFIG_USB) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 1bc884051e0f..a51eeedc18d4 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -456,7 +456,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
int* actual_length)
{
struct timer_list timer;
- int status;
init_timer(&timer);
timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -464,12 +463,11 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
timer.function = cxacru_timeout_kill;
add_timer(&timer);
wait_for_completion(done);
- status = urb->status;
del_timer_sync(&timer);
if (actual_length)
*actual_length = urb->actual_length;
- return status;
+ return urb->status; /* must read status after completion */
}
static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
@@ -484,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
- dbg("too big transfer requested");
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+ wbuflen, rbuflen);
ret = -ENOMEM;
goto fail;
}
@@ -495,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
- dbg("submitting read urb for cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+ cm, ret);
goto fail;
}
@@ -512,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
- dbg("submitting write urb for cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+ cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
- dbg("sending cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
- dbg("receiving cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
- dbg("response is not a positive multiple of %d: %#x",
- CMD_PACKET_SIZE, actlen);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+ cm, actlen);
ret = -EIO;
goto fail;
}
@@ -540,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
- dbg("wrong cm %#x in response", rbuf[offb]);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+ rbuf[offb], cm);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
- dbg("response failed: %#x", rbuf[offb + 1]);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+ cm, rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
@@ -584,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
- dbg("wrong data length %#x in response", l);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+ cm, l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
- dbg("wrong index %#x in response", offd);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+ offd, cm);
ret = -EIO;
goto cleanup;
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 638b8009b3bc..8b132c4a503b 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
{
unsigned char *buffer;
struct usbatm_data *usbatm = instance->usbatm;
- struct usb_interface *intf;
struct usb_device *usb_dev = usbatm->usb_dev;
int actual_length;
int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
goto out;
}
- if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+ if (!usb_ifnum_to_if(usb_dev, 2)) {
ret = -ENODEV;
usb_dbg(usbatm, "%s: interface not found!\n", __func__);
goto out_free;
@@ -612,7 +611,8 @@ static void speedtch_handle_int(struct urb *int_urb)
struct speedtch_instance_data *instance = int_urb->context;
struct usbatm_data *usbatm = instance->usbatm;
unsigned int count = int_urb->actual_length;
- int ret = int_urb->status;
+ int status = int_urb->status;
+ int ret;
/* The magic interrupt for "up state" */
static const unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +621,8 @@ static void speedtch_handle_int(struct urb *int_urb)
atm_dbg(usbatm, "%s entered\n", __func__);
- if (ret < 0) {
- atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+ if (status < 0) {
+ atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
goto fail;
}
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 8f046659b4e9..389c5b164eb2 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2,7 +2,8 @@
* Copyright (c) 2003, 2004
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -107,18 +108,51 @@
#define uea_info(usb_dev, format,args...) \
dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
u32 address;
u16 offset;
u32 data;
} __attribute__ ((packed));
+struct uea_cmvs_v2 {
+ u32 group;
+ u32 address;
+ u32 offset;
+ u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+ u8 function;
+ u16 idx;
+ u32 address;
+ u16 offset;
+};
+
+struct cmv_dsc_e4 {
+ u16 function;
+ u16 offset;
+ u16 address;
+ u16 group;
+};
+
+union cmv_dsc {
+ struct cmv_dsc_e1 e1;
+ struct cmv_dsc_e4 e4;
+};
+
struct uea_softc {
struct usb_device *usb_dev;
struct usbatm_data *usbatm;
int modem_index;
unsigned int driver_info;
+ int annex;
+#define ANNEXA 0
+#define ANNEXB 1
int booting;
int reset;
@@ -127,20 +161,23 @@ struct uea_softc {
struct task_struct *kthread;
u32 data;
- wait_queue_head_t cmv_ack_wait;
+ u32 data1;
+
int cmv_ack;
+ union cmv_dsc cmv_dsc;
struct work_struct task;
+ struct workqueue_struct *work_q;
u16 pageno;
u16 ovl;
const struct firmware *dsp_firm;
struct urb *urb_int;
- u8 cmv_function;
- u16 cmv_idx;
- u32 cmv_address;
- u16 cmv_offset;
+ void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+ void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+ int (*stat) (struct uea_softc *);
+ int (*send_cmvs) (struct uea_softc *);
/* keep in sync with eaglectl */
struct uea_stats {
@@ -174,10 +211,34 @@ struct uea_softc {
#define ELSA_PID_PSTFIRM 0x3350
#define ELSA_PID_PREFIRM 0x3351
+#define ELSA_PID_A_PREFIRM 0x3352
+#define ELSA_PID_A_PSTFIRM 0x3353
+#define ELSA_PID_B_PREFIRM 0x3362
+#define ELSA_PID_B_PSTFIRM 0x3363
+
/*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
*/
-#define EAGLE_VID 0x1110
+#define DEVOLO_VID 0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID 0x1110
+#define ADI930_PID_PREFIRM 0x9001
+#define ADI930_PID_PSTFIRM 0x9000
+
#define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */
#define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */
@@ -187,12 +248,12 @@ struct uea_softc {
#define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */
#define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */
-/*
- * Eagle III Pid
- */
#define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */
#define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */
+#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */
+
/*
* USR USB IDs
*/
@@ -208,11 +269,15 @@ struct uea_softc {
#define PREFIRM 0
#define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
enum {
ADI930 = 0,
EAGLE_I,
EAGLE_II,
- EAGLE_III
+ EAGLE_III,
+ EAGLE_IV
};
/* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@ enum {
#define UEA_CHIP_VERSION(x) \
((x)->driver_info & 0xf)
-#define IS_ISDN(usb_dev) \
- (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+ ((x)->annex & ANNEXB)
#define INS_TO_USBDEV(ins) ins->usb_dev
#define GET_STATUS(data) \
((data >> 8) & 0xf)
+
#define IS_OPERATIONAL(sc) \
- (GET_STATUS(sc->stats.phy.state) == 2)
+ ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+ (GET_STATUS(sc->stats.phy.state) == 2) : \
+ (sc->stats.phy.state == 7))
/*
* Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@ enum {
#define UEA_INTR_PIPE 0x04
#define UEA_ISO_DATA_PIPE 0x08
-#define UEA_SET_BLOCK 0x0001
+#define UEA_E1_SET_BLOCK 0x0001
+#define UEA_E4_SET_BLOCK 0x002c
#define UEA_SET_MODE 0x0003
#define UEA_SET_2183_DATA 0x0004
#define UEA_SET_TIMEOUT 0x0011
@@ -275,71 +344,179 @@ enum {
#define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000)
#define UEA_MPRX_MAILBOX (0x3fdf | 0x4000)
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware */
+struct block_index {
+ __le32 PageOffset;
+ __le32 NotLastBlock;
+ __le32 dummy;
+ __le32 PageSize;
+ __le32 PageAddress;
+ __le16 dummy1;
+ __le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+ u8 string_header[E4_L1_STRING_HEADER];
+ u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+ struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+ u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
__le16 wHdr;
-#define UEA_BIHDR 0xabcd
__le16 wAddress;
__le16 wSize;
__le16 wOvlOffset;
__le16 wOvl; /* overlay */
__le16 wLast;
} __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
+
+struct block_info_e4 {
+ __be16 wHdr;
+ __u8 bBootPage;
+ __u8 bPageNumber;
+ __be32 dwSize;
+ __be32 dwAddress;
+ __be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
- __le16 wPreamble;
-#define PREAMBLE 0x535c
- __u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
- __u8 bFunction;
-#define FUNCTION_TYPE(f) ((f) >> 4)
-#define MEMACCESS 0x1
-#define ADSLDIRECTIVE 0x7
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
/* for MEMACCESS */
-#define REQUESTREAD 0x0
-#define REQUESTWRITE 0x1
-#define REPLYREAD 0x2
-#define REPLYWRITE 0x3
+#define E1_REQUESTREAD 0x0
+#define E1_REQUESTWRITE 0x1
+#define E1_REPLYREAD 0x2
+#define E1_REPLYWRITE 0x3
+
+#define E4_REQUESTREAD 0x0
+#define E4_REQUESTWRITE 0x4
+#define E4_REPLYREAD (E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE (E4_REQUESTWRITE | 1)
+
/* for ADSLDIRECTIVE */
-#define KERNELREADY 0x0
-#define MODEMREADY 0x1
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY 0x1
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
- __le16 wIndex;
- __le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d) \
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY 0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d) \
(((c) & 0xff) << 24 | \
((d) & 0xff) << 16 | \
((a) & 0xff) << 8 | \
((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
-
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+ __le16 wPreamble;
+ __u8 bDirection;
+ __u8 bFunction;
+ __le16 wIndex;
+ __le32 dwSymbolicAddress;
__le16 wOffsetAddress;
__le32 dwData;
} __attribute__ ((packed));
-#define CMV_SIZE 16
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+ __be16 wGroup;
+ __be16 wFunction;
+ __be16 wOffset;
+ __be16 wAddress;
+ __be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
__u8 bSwapPageNo;
__u8 bOvl; /* overlay */
} __attribute__ ((packed));
-/* structure representing interrupt data */
+struct swap_info_e4 {
+ __u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV 0x0002
+
+union intr_data_e1 {
+ struct {
+ struct swap_info_e1 swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
+ struct {
+ struct cmv_e1 cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+ struct {
+ struct swap_info_e4 swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
+ struct {
+ struct cmv_e4 cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
struct intr_pkt {
__u8 bType;
__u8 bNotification;
@@ -347,43 +524,48 @@ struct intr_pkt {
__le16 wIndex;
__le16 wLength;
__le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV 0x0002
union {
- struct {
- struct swap_info swapinfo;
- __le16 wDataSize;
- } __attribute__ ((packed)) s1;
-
- struct {
- struct cmv cmv;
- __le16 wDataSize;
- } __attribute__ ((packed)) s2;
- } __attribute__ ((packed)) u;
-#define bSwapPageNo u.s1.swapinfo.bSwapPageNo
-#define bOvl u.s1.swapinfo.bOvl
+ union intr_data_e1 e1;
+ union intr_data_e4 e4;
+ } u;
} __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
static struct usb_driver uea_driver;
static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
static int modem_index;
static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
static int sync_wait[NB_MODEM];
static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
module_param(debug, uint, 0644);
MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+ "1=isoc slowest, ... , 8=isoc fastest (default)");
module_param_array(sync_wait, bool, NULL, 0644);
MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
module_param_array(cmv_file, charp, NULL, 0644);
MODULE_PARM_DESC(cmv_file,
"file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+ "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+ int _r = wait_event_interruptible_timeout(sc->sync_q, \
+ (cond) || kthread_should_stop(), timeo); \
+ if (kthread_should_stop()) \
+ _r = -ENODEV; \
+ _r; \
+})
#define UPDATE_ATM_STAT(type, val) \
do { \
@@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
case EAGLE_III:
fw_name = FW_DIR "eagleIII.fw";
break;
+ case EAGLE_IV:
+ fw_name = FW_DIR "eagleIV.fw";
+ break;
}
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
/*
* Make sure that the DSP code provided is safe to use.
*/
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
{
u8 pagecount, blockcount;
u16 blocksize;
@@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len)
return 0;
}
+static int check_dsp_e4(u8 *dsp, int len)
+{
+ int i;
+ struct l1_code *p = (struct l1_code *) dsp;
+ unsigned int sum = p->code - dsp;
+
+ if (len < sum)
+ return 1;
+
+ if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+ strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+ return 1;
+
+ for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+ struct block_index *blockidx;
+ u8 blockno = p->page_number_to_block_index[i];
+ if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+ continue;
+
+ do {
+ u64 l;
+
+ if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+ return 1;
+
+ blockidx = &p->page_header[blockno++];
+ if ((u8 *)(blockidx + 1) - dsp >= len)
+ return 1;
+
+ if (le16_to_cpu(blockidx->PageNumber) != i)
+ return 1;
+
+ l = E4_PAGE_BYTES(blockidx->PageSize);
+ sum += l;
+ l += le32_to_cpu(blockidx->PageOffset);
+ if (l > len)
+ return 1;
+
+ /* zero is zero regardless endianes */
+ } while (blockidx->NotLastBlock);
+ }
+
+ return (sum == len) ? 0 : 1;
+}
+
/*
* send data to the idma pipe
* */
@@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc)
int ret;
char *dsp_name;
- if (UEA_CHIP_VERSION(sc) == ADI930) {
- if (IS_ISDN(sc->usb_dev))
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ if (IS_ISDN(sc))
+ dsp_name = FW_DIR "DSP4i.bin";
+ else
+ dsp_name = FW_DIR "DSP4p.bin";
+ } else if (UEA_CHIP_VERSION(sc) == ADI930) {
+ if (IS_ISDN(sc))
dsp_name = FW_DIR "DSP9i.bin";
else
dsp_name = FW_DIR "DSP9p.bin";
} else {
- if (IS_ISDN(sc->usb_dev))
+ if (IS_ISDN(sc))
dsp_name = FW_DIR "DSPei.bin";
else
dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"requesting firmware %s failed with error %d\n",
- dsp_name, ret);
+ dsp_name, ret);
return ret;
}
- if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+ else
+ ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+ if (ret) {
uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
dsp_name);
release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc)
/*
* The uea_load_page() function must be called within a process context
*/
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
{
struct uea_softc *sc = container_of(work, struct uea_softc, task);
u16 pageno = sc->pageno;
u16 ovl = sc->ovl;
- struct block_info bi;
+ struct block_info_e1 bi;
u8 *p;
u8 pagecount, blockcount;
@@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work)
bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
/* send block info through the IDMA pipe */
- if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+ if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
goto bad2;
/* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@ bad1:
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
}
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+ struct block_info_e4 bi;
+ struct block_index *blockidx;
+ struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+ u8 blockno = p->page_number_to_block_index[pageno];
+
+ bi.wHdr = cpu_to_be16(UEA_BIHDR);
+ bi.bBootPage = boot;
+ bi.bPageNumber = pageno;
+ bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+ do {
+ u8 *blockoffset;
+ unsigned int blocksize;
+
+ blockidx = &p->page_header[blockno];
+ blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+ blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+ bi.dwSize = cpu_to_be32(blocksize);
+ bi.dwAddress = swab32(blockidx->PageAddress);
+
+ uea_dbg(INS_TO_USBDEV(sc),
+ "sending block %u for DSP page %u size %u adress %x\n",
+ blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+ /* send block info through the IDMA pipe */
+ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+ goto bad;
+
+ /* send block data through the IDMA pipe */
+ if (uea_idma_write(sc, blockoffset, blocksize))
+ goto bad;
+
+ blockno++;
+ } while (blockidx->NotLastBlock);
+
+ return;
+
+bad:
+ uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+ return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+ struct uea_softc *sc = container_of(work, struct uea_softc, task);
+ u8 pageno = sc->pageno;
+ int i;
+ struct block_info_e4 bi;
+ struct l1_code *p;
+
+ uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+ /* reload firmware when reboot start and it's loaded already */
+ if (pageno == 0 && sc->dsp_firm) {
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+
+ if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+ return;
+
+ p = (struct l1_code *) sc->dsp_firm->data;
+ if (pageno >= p->page_header[0].PageNumber) {
+ uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+ return;
+ }
+
+ if (pageno != 0) {
+ __uea_load_page_e4(sc, pageno, 0);
+ return;
+ }
+
+ uea_dbg(INS_TO_USBDEV(sc),
+ "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+ for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+ if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+ __uea_load_page_e4(sc, i, 1);
+ }
+
+ uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+ bi.wHdr = cpu_to_be16(UEA_BIHDR);
+ bi.bBootPage = 0;
+ bi.bPageNumber = 0xff;
+ bi.wReserved = cpu_to_be16(UEA_RESERVED);
+ bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+ bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+ /* send block info through the IDMA pipe */
+ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+ uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
static inline void wake_up_cmv_ack(struct uea_softc *sc)
{
BUG_ON(sc->cmv_ack);
sc->cmv_ack = 1;
- wake_up(&sc->cmv_ack_wait);
+ wake_up(&sc->sync_q);
}
static inline int wait_cmv_ack(struct uea_softc *sc)
{
- int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
- sc->cmv_ack, ACK_TIMEOUT);
+ int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
sc->cmv_ack = 0;
uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,34 @@ static int uea_request(struct uea_softc *sc,
return 0;
}
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
u8 function, u32 address, u16 offset, u32 data)
{
- struct cmv cmv;
+ struct cmv_e1 cmv;
int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
"offset : 0x%04x, data : 0x%08x\n",
- FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
- GETSA1(address), GETSA2(address), GETSA3(address),
- GETSA4(address), offset, data);
+ E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+ E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+ E1_GETSA4(address), offset, data);
+
/* we send a request, but we expect a reply */
- sc->cmv_function = function | 0x2;
- sc->cmv_idx++;
- sc->cmv_address = address;
- sc->cmv_offset = offset;
+ sc->cmv_dsc.e1.function = function | 0x2;
+ sc->cmv_dsc.e1.idx++;
+ sc->cmv_dsc.e1.address = address;
+ sc->cmv_dsc.e1.offset = offset;
- cmv.wPreamble = cpu_to_le16(PREAMBLE);
- cmv.bDirection = HOSTTOMODEM;
+ cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+ cmv.bDirection = E1_HOSTTOMODEM;
cmv.bFunction = function;
- cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+ cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
- ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+ ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
if (ret < 0)
return ret;
ret = wait_cmv_ack(sc);
@@ -826,10 +1164,44 @@ static int uea_cmv(struct uea_softc *sc,
return ret;
}
-static inline int uea_read_cmv(struct uea_softc *sc,
+static int uea_cmv_e4(struct uea_softc *sc,
+ u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+ struct cmv_e4 cmv;
+ int ret;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ memset(&cmv, 0, sizeof(cmv));
+
+ uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+ "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+ E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+ group, address, offset, data);
+
+ /* we send a request, but we expect a reply */
+ sc->cmv_dsc.e4.function = function | (0x1 << 4);
+ sc->cmv_dsc.e4.offset = offset;
+ sc->cmv_dsc.e4.address = address;
+ sc->cmv_dsc.e4.group = group;
+
+ cmv.wFunction = cpu_to_be16(function);
+ cmv.wGroup = cpu_to_be16(group);
+ cmv.wAddress = cpu_to_be16(address);
+ cmv.wOffset = cpu_to_be16(offset);
+ cmv.dwData[0] = cpu_to_be32(data);
+
+ ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+ if (ret < 0)
+ return ret;
+ ret = wait_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return ret;
+}
+
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
u32 address, u16 offset, u32 *data)
{
- int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+ int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
address, offset, 0);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc,
return ret;
}
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+ u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+ int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+ group, address, offset, 0);
+ if (ret < 0)
+ uea_err(INS_TO_USBDEV(sc),
+ "reading cmv failed with error %d\n", ret);
+ else {
+ *data = sc->data;
+ /* size is in 16-bit word quantities */
+ if (size > 2)
+ *(data + 1) = sc->data1;
+ }
+ return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
u32 address, u16 offset, u32 data)
{
- int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+ int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
address, offset, data);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc,
return ret;
}
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+ u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+ int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+ group, address, offset, data);
+ if (ret < 0)
+ uea_err(INS_TO_USBDEV(sc),
+ "writing cmv failed with error %d\n", ret);
+
+ return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+ int ret;
+ u16 timeout;
+
+ /* in bulk mode the modem have problem with high rate
+ * changing internal timing could improve things, but the
+ * value is misterious.
+ * ADI930 don't support it (-EPIPE error).
+ */
+
+ if (UEA_CHIP_VERSION(sc) == ADI930 ||
+ altsetting[sc->modem_index] > 0 ||
+ sc->stats.phy.dsrate == dsrate)
+ return;
+
+ /* Original timming (1Mbit/s) from ADI (used in windows driver) */
+ timeout = (dsrate <= 1024*1024) ? 0 : 1;
+ ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+ timeout, ret < 0 ? " failed" : "");
+
+}
+
/*
* Monitor the modem and update the stat
* return 0 if everything is ok
* return < 0 if an error occurs (-EAGAIN reboot needed)
*/
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
{
u32 data;
int ret;
@@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc)
uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
- ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+ ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
if (ret < 0)
return ret;
@@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc)
case 3: /* fail ... */
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
- " (may be try other cmv/dsp)\n");
+ " (may be try other cmv/dsp)\n");
return -EAGAIN;
case 4 ... 6: /* test state */
@@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc)
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
- ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
if (ret < 0)
return ret;
sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc)
return 0;
}
- ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
if (ret < 0)
return ret;
- /* in bulk mode the modem have problem with high rate
- * changing internal timing could improve things, but the
- * value is misterious.
- * ADI930 don't support it (-EPIPE error).
- */
- if (UEA_CHIP_VERSION(sc) != ADI930
- && !use_iso[sc->modem_index]
- && sc->stats.phy.dsrate != (data >> 16) * 32) {
- /* Original timming from ADI(used in windows driver)
- * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
- */
- u16 timeout = (data <= 0x20ffff) ? 0 : 1;
- ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
- uea_info(INS_TO_USBDEV(sc),
- "setting new timeout %d%s\n", timeout,
- ret < 0?" failed":"");
- }
+ uea_set_bulk_timeout(sc, (data >> 16) * 32);
sc->stats.phy.dsrate = (data >> 16) * 32;
sc->stats.phy.usrate = (data & 0xffff) * 32;
UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
- ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
if (ret < 0)
return ret;
sc->stats.phy.dsattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
if (ret < 0)
return ret;
sc->stats.phy.usattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
if (ret < 0)
return ret;
return 0;
}
-static int request_cmvs(struct uea_softc *sc,
- struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
{
- int ret, size;
- u8 *data;
+ u32 data;
+ u32 tmp_arr[2];
+ int ret;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ data = sc->stats.phy.state;
+
+ /* XXX only need to be done before operationnal... */
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+ if (ret < 0)
+ return ret;
+
+ switch (sc->stats.phy.state) {
+ case 0x0: /* not yet synchronized */
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+ return 0;
+ case 0x5: /* initialization */
+ case 0x6:
+ case 0x9:
+ case 0xa:
+ uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+ return 0;
+ case 0x2: /* fail ... */
+ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+ " (may be try other cmv/dsp)\n");
+ return -EAGAIN;
+ case 0x7: /* operational */
+ break;
+ default:
+ uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+ return 0;
+ }
+
+ if (data != 7) {
+ uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+ /* release the dsp firmware as it is not needed until
+ * the next failure
+ */
+ if (sc->dsp_firm) {
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+ }
+
+ /* always update it as atm layer could not be init when we switch to
+ * operational state
+ */
+ UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+ /* wake up processes waiting for synchronization */
+ wake_up(&sc->sync_q);
+
+ /* TODO improve this state machine :
+ * we need some CMV info : what they do and their unit
+ * we should find the equivalent of eagle3- CMV
+ */
+ /* check flags */
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+ /* in case of a flags ( for example delineation LOSS (& 0x10)),
+ * we check the status again in order to detect the failure earlier
+ */
+ if (sc->stats.phy.flags) {
+ uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+ sc->stats.phy.flags);
+ if (sc->stats.phy.flags & 1) //delineation LOSS
+ return -EAGAIN;
+ if (sc->stats.phy.flags & 0x4000) //Reset Flag
+ return -EAGAIN;
+ return 0;
+ }
+
+ /* rate data may be in upper or lower half of 64 bit word, strange */
+ ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+ if (ret < 0)
+ return ret;
+ data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+ sc->stats.phy.usrate = data / 1000;
+
+ ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+ if (ret < 0)
+ return ret;
+ data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+ uea_set_bulk_timeout(sc, data / 1000);
+ sc->stats.phy.dsrate = data / 1000;
+ UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.dsattenuation = data / 10;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.usattenuation = data / 10;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.dsmargin = data / 2;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.usmargin = data / 10;
+
+ return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+ char file_arr[] = "CMVxy.bin";
char *file;
- char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ /* set proper name corresponding modem version and line type */
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
- file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+ file_arr[3] = '9';
+ else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ file_arr[3] = '4';
else
- file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+ file_arr[3] = 'e';
+
+ file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+ file = file_arr;
} else
file = cmv_file[sc->modem_index];
strcpy(cmv_name, FW_DIR);
- strlcat(cmv_name, file, sizeof(cmv_name));
+ strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+ if (ver == 2)
+ strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
+
+static int request_cmvs_old(struct uea_softc *sc,
+ void **cmvs, const struct firmware **fw)
+{
+ int ret, size;
+ u8 *data;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ cmvs_file_name(sc, cmv_name, 1);
ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc,
}
data = (u8 *) (*fw)->data;
- size = *data * sizeof(struct uea_cmvs) + 1;
- if (size != (*fw)->size) {
- uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
- cmv_name);
- release_firmware(*fw);
- return -EILSEQ;
+ size = (*fw)->size;
+ if (size < 1)
+ goto err_fw_corrupted;
+
+ if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+ goto err_fw_corrupted;
+
+ *cmvs = (void *)(data + 1);
+ return *data;
+
+err_fw_corrupted:
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+ void **cmvs, const struct firmware **fw, int *ver)
+{
+ int ret, size;
+ u32 crc;
+ u8 *data;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+ cmvs_file_name(sc, cmv_name, 2);
+ ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+ if (ret < 0) {
+ /* if caller can handle old version, try to provide it */
+ if (*ver == 1) {
+ uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+ "try to get older cmvs\n", cmv_name);
+ return request_cmvs_old(sc, cmvs, fw);
+ }
+ uea_err(INS_TO_USBDEV(sc),
+ "requesting firmware %s failed with error %d\n",
+ cmv_name, ret);
+ return ret;
}
- *cmvs = (struct uea_cmvs *)(data + 1);
+ size = (*fw)->size;
+ data = (u8 *) (*fw)->data;
+ if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+ if (*ver == 1) {
+ uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+ "try to get older cmvs\n", cmv_name);
+ release_firmware(*fw);
+ return request_cmvs_old(sc, cmvs, fw);
+ }
+ goto err_fw_corrupted;
+ }
+
+ *ver = 2;
+
+ data += 4;
+ size -= 4;
+ if (size < 5)
+ goto err_fw_corrupted;
+
+ crc = FW_GET_LONG(data);
+ data += 4;
+ size -= 4;
+ if (crc32_be(0, data, size) != crc)
+ goto err_fw_corrupted;
+
+ if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+ goto err_fw_corrupted;
+
+ *cmvs = (void *) (data + 1);
return *data;
+
+err_fw_corrupted:
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+ int i, ret, len;
+ void *cmvs_ptr;
+ const struct firmware *cmvs_fw;
+ int ver = 1; // we can handle v1 cmv firmware version;
+
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ if (ver == 1) {
+ struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+ uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+ "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));
+ if (ret < 0)
+ goto out;
+ }
+ } else if (ver == 2) {
+ 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));
+ if (ret < 0)
+ goto out;
+ }
+ } else {
+ /* This realy should not happen */
+ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+ goto out;
+ }
+
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+ release_firmware(cmvs_fw);
+ return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+ int i, ret, len;
+ void *cmvs_ptr;
+ const struct firmware *cmvs_fw;
+ int ver = 2; // we can only handle v2 cmv firmware version;
+
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ /* XXX don't read the 3th byte as it is always 6 */
+ ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
+
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ if (ver == 2) {
+ struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+ 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));
+ if (ret < 0)
+ goto out;
+ }
+ } else {
+ /* This realy should not happen */
+ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+ goto out;
+ }
+
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+ release_firmware(cmvs_fw);
+ return ret;
}
/* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc,
static int uea_start_reset(struct uea_softc *sc)
{
u16 zero = 0; /* ;-) */
- int i, len, ret;
- struct uea_cmvs *cmvs;
- const struct firmware *cmvs_fw;
+ int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc)
uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
/* original driver use 200ms, but windows driver use 100ms */
- msleep(100);
+ ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+ if (ret < 0)
+ return ret;
/* leave reset mode */
uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
- /* clear tx and rx mailboxes */
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+ /* clear tx and rx mailboxes */
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ }
+
+ ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+ if (ret < 0)
+ return ret;
+
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+ else
+ sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
- msleep(1000);
- sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
/* demask interrupt */
sc->booting = 0;
/* start loading DSP */
sc->pageno = 0;
sc->ovl = 0;
- schedule_work(&sc->task);
+ queue_work(sc->work_q, &sc->task);
/* wait for modem ready CMV */
ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc)
uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
- /* Enter in R-IDLE (cmv) until instructed otherwise */
- ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
+ ret = sc->send_cmvs(sc);
if (ret < 0)
return ret;
- /* Dump firmware version */
- ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
- if (ret < 0)
- return ret;
- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
- sc->stats.phy.firmid);
-
- /* get options */
- ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
- if (ret < 0)
- return ret;
-
- /* send options */
- for (i = 0; i < len; i++) {
- ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
- FW_GET_WORD(&cmvs[i].offset),
- FW_GET_LONG(&cmvs[i].data));
- if (ret < 0)
- goto out;
- }
- /* Enter in R-ACT-REQ */
- ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
- uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
- uea_info(INS_TO_USBDEV(sc), "Modem started, "
- "waiting synchronization\n");
-out:
- release_firmware(cmvs_fw);
sc->reset = 0;
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1174,12 +1879,10 @@ static int uea_kthread(void *data)
if (ret < 0 || sc->reset)
ret = uea_start_reset(sc);
if (!ret)
- ret = uea_stat(sc);
+ ret = sc->stat(sc);
if (ret != -EAGAIN)
- msleep_interruptible(1000);
- if (try_to_freeze())
- uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
- "please unplug/replug your modem\n");
+ uea_wait(sc, 0, msecs_to_jiffies(1000));
+ try_to_freeze();
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
if (ret < 0)
uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
-
err1:
release_firmware(fw_entry);
err0:
@@ -1243,40 +1945,41 @@ err0:
}
/* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
{
+ struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+ struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
uea_enters(INS_TO_USBDEV(sc));
- if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+ if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
goto bad1;
- if (cmv->bDirection != MODEMTOHOST)
+ if (cmv->bDirection != E1_MODEMTOHOST)
goto bad1;
/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
* the first MEMACESS cmv. Ignore it...
*/
- if (cmv->bFunction != sc->cmv_function) {
+ if (cmv->bFunction != dsc->function) {
if (UEA_CHIP_VERSION(sc) == ADI930
- && cmv->bFunction == MAKEFUNCTION(2, 2)) {
- cmv->wIndex = cpu_to_le16(sc->cmv_idx);
- put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
- cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
- }
- else
+ && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
+ cmv->wIndex = cpu_to_le16(dsc->idx);
+ put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+ cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+ } else
goto bad2;
}
- if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+ if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
wake_up_cmv_ack(sc);
uea_leaves(INS_TO_USBDEV(sc));
return;
}
/* in case of MEMACCESS */
- if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
- sc->cmv_address
- || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+ if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+ le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+ le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
goto bad2;
sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
bad2:
uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
"Function : %d, Subfunction : %d\n",
- FUNCTION_TYPE(cmv->bFunction),
- FUNCTION_SUBTYPE(cmv->bFunction));
+ E1_FUNCTION_TYPE(cmv->bFunction),
+ E1_FUNCTION_SUBTYPE(cmv->bFunction));
uea_leaves(INS_TO_USBDEV(sc));
return;
@@ -1301,6 +2004,61 @@ bad1:
uea_leaves(INS_TO_USBDEV(sc));
}
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+ struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+ be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+ be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+ be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+ if (be16_to_cpu(cmv->wFunction) != dsc->function)
+ goto bad2;
+
+ if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+ wake_up_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+ }
+
+ /* in case of MEMACCESS */
+ if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+ be16_to_cpu(cmv->wGroup) != dsc->group ||
+ be16_to_cpu(cmv->wAddress) != dsc->address)
+ goto bad2;
+
+ sc->data = be32_to_cpu(cmv->dwData[0]);
+ sc->data1 = be32_to_cpu(cmv->dwData[1]);
+ wake_up_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+
+bad2:
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ "Function : %d, Subfunction : %d\n",
+ E4_FUNCTION_TYPE(cmv->wFunction),
+ E4_FUNCTION_SUBTYPE(cmv->wFunction));
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ sc->pageno = intr->e1_bSwapPageNo;
+ sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+ queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ sc->pageno = intr->e4_bSwapPageNo;
+ queue_work(sc->work_q, &sc->task);
+}
+
/*
* interrupt handler
*/
@@ -1308,11 +2066,13 @@ static void uea_intr(struct urb *urb)
{
struct uea_softc *sc = urb->context;
struct intr_pkt *intr = urb->transfer_buffer;
+ int status = urb->status;
+
uea_enters(INS_TO_USBDEV(sc));
- if (unlikely(urb->status < 0)) {
+ if (unlikely(status < 0)) {
uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
- urb->status);
+ status);
return;
}
@@ -1324,13 +2084,11 @@ static void uea_intr(struct urb *urb)
switch (le16_to_cpu(intr->wInterrupt)) {
case INT_LOADSWAPPAGE:
- sc->pageno = intr->bSwapPageNo;
- sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
- schedule_work(&sc->task);
+ sc->schedule_load_page(sc, intr);
break;
case INT_INCOMINGCMV:
- uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+ sc->dispatch_cmv(sc, intr);
break;
default:
@@ -1347,35 +2105,55 @@ resubmit:
*/
static int uea_boot(struct uea_softc *sc)
{
- int ret;
+ int ret, size;
struct intr_pkt *intr;
uea_enters(INS_TO_USBDEV(sc));
- INIT_WORK(&sc->task, uea_load_page);
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ size = E4_INTR_PKT_SIZE;
+ sc->dispatch_cmv = uea_dispatch_cmv_e4;
+ sc->schedule_load_page = uea_schedule_load_page_e4;
+ sc->stat = uea_stat_e4;
+ sc->send_cmvs = uea_send_cmvs_e4;
+ INIT_WORK(&sc->task, uea_load_page_e4);
+ } else {
+ size = E1_INTR_PKT_SIZE;
+ sc->dispatch_cmv = uea_dispatch_cmv_e1;
+ sc->schedule_load_page = uea_schedule_load_page_e1;
+ sc->stat = uea_stat_e1;
+ sc->send_cmvs = uea_send_cmvs_e1;
+ INIT_WORK(&sc->task, uea_load_page_e1);
+ }
+
init_waitqueue_head(&sc->sync_q);
- init_waitqueue_head(&sc->cmv_ack_wait);
+
+ sc->work_q = create_workqueue("ueagle-dsp");
+ if (!sc->work_q) {
+ uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+ uea_leaves(INS_TO_USBDEV(sc));
+ return -ENOMEM;
+ }
if (UEA_CHIP_VERSION(sc) == ADI930)
load_XILINX_firmware(sc);
- intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+ intr = kmalloc(size, GFP_KERNEL);
if (!intr) {
uea_err(INS_TO_USBDEV(sc),
"cannot allocate interrupt package\n");
- uea_leaves(INS_TO_USBDEV(sc));
- return -ENOMEM;
+ goto err0;
}
sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
if (!sc->urb_int) {
uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
- goto err;
+ goto err1;
}
usb_fill_int_urb(sc->urb_int, sc->usb_dev,
usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
- intr, INTR_PKT_SIZE, uea_intr, sc,
+ intr, size, uea_intr, sc,
sc->usb_dev->actconfig->interface[0]->altsetting[0].
endpoint[0].desc.bInterval);
@@ -1383,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"urb submition failed with error %d\n", ret);
- goto err;
+ goto err1;
}
sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1397,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc)
err2:
usb_kill_urb(sc->urb_int);
-err:
+err1:
usb_free_urb(sc->urb_int);
sc->urb_int = NULL;
kfree(intr);
+err0:
+ destroy_workqueue(sc->work_q);
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
@@ -1415,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc)
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
- /* stop any pending boot process */
- flush_scheduled_work();
-
uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
usb_kill_urb(sc->urb_int);
kfree(sc->urb_int->transfer_buffer);
usb_free_urb(sc->urb_int);
+ /* stop any pending boot process, when no one can schedule work */
+ destroy_workqueue(sc->work_q);
+
if (sc->dsp_firm)
release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
@@ -1485,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
char *buf)
{
int ret = -ENODEV;
+ int modem_state;
struct uea_softc *sc;
mutex_lock(&uea_mutex);
@@ -1492,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
if (!sc)
goto out;
- switch (GET_STATUS(sc->stats.phy.state)) {
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ switch (sc->stats.phy.state) {
+ case 0x0: /* not yet synchronized */
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ modem_state = 0;
+ break;
+ case 0x5: /* initialization */
+ case 0x6:
+ case 0x9:
+ case 0xa:
+ modem_state = 1;
+ break;
+ case 0x7: /* operational */
+ modem_state = 2;
+ break;
+ case 0x2: /* fail ... */
+ modem_state = 3;
+ break;
+ default: /* unknown */
+ modem_state = 4;
+ break;
+ }
+ } else
+ modem_state = GET_STATUS(sc->stats.phy.state);
+
+ switch (modem_state) {
case 0:
ret = sprintf(buf, "Modem is booting\n");
break;
@@ -1502,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
case 2:
ret = sprintf(buf, "Modem is operational\n");
break;
- default:
+ case 3:
ret = sprintf(buf, "Modem synchronization failed\n");
break;
+ default:
+ ret = sprintf(buf, "Modem state is unknown\n");
+ break;
}
out:
mutex_unlock(&uea_mutex);
@@ -1518,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
{
int ret = -ENODEV;
struct uea_softc *sc;
+ char *delin = "GOOD";
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev);
if (!sc)
goto out;
- if (sc->stats.phy.flags & 0x0C00)
- ret = sprintf(buf, "ERROR\n");
- else if (sc->stats.phy.flags & 0x0030)
- ret = sprintf(buf, "LOSS\n");
- else
- ret = sprintf(buf, "GOOD\n");
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ if (sc->stats.phy.flags & 0x4000)
+ delin = "RESET";
+ else if (sc->stats.phy.flags & 0x0001)
+ delin = "LOSS";
+ } else {
+ if (sc->stats.phy.flags & 0x0C00)
+ delin = "ERROR";
+ else if (sc->stats.phy.flags & 0x0030)
+ delin = "LOSS";
+ }
+
+ ret = sprintf(buf, "%s\n", delin);
out:
mutex_unlock(&uea_mutex);
return ret;
@@ -1660,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
struct usb_device *usb = interface_to_usbdev(intf);
struct uea_softc *sc;
int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+ unsigned int alt;
uea_enters(usb);
@@ -1694,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
sc->driver_info = id->driver_info;
- /* ADI930 don't support iso */
- if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
- int i;
-
- /* try set fastest alternate for inbound traffic interface */
- for (i = FASTEST_ISO_INTF; i > 0; i--)
- if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
- break;
+ /* first try to use module parameter */
+ if (annex[sc->modem_index] == 1)
+ sc->annex = ANNEXA;
+ else if (annex[sc->modem_index] == 2)
+ sc->annex = ANNEXB;
+ /* try to autodetect annex */
+ else if (sc->driver_info & AUTO_ANNEX_A)
+ sc->annex = ANNEXA;
+ else if (sc->driver_info & AUTO_ANNEX_B)
+ sc->annex = ANNEXB;
+ else
+ sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
- if (i > 0) {
- uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+ alt = altsetting[sc->modem_index];
+ /* ADI930 don't support iso */
+ if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+ if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+ uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
uea_info(usb, "using iso mode\n");
usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
} else {
- uea_err(usb, "setting any alternate failed for "
- "2 interface, using bulk mode\n");
+ uea_err(usb, "setting alternate %u failed for "
+ "2 interface, using bulk mode\n", alt);
}
}
@@ -1719,9 +2546,12 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
ret = uea_boot(sc);
if (ret < 0)
- goto error;
+ goto error_rm_grp;
return 0;
+
+error_rm_grp:
+ sysfs_remove_group(&intf->dev.kobj, &attr_grp);
error:
kfree(sc);
return ret;
@@ -1752,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
uea_enters(usb);
- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
- le16_to_cpu(usb->descriptor.idVendor),
- le16_to_cpu(usb->descriptor.idProduct),
- chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+ le16_to_cpu(usb->descriptor.idVendor),
+ le16_to_cpu(usb->descriptor.idProduct),
+ le16_to_cpu(usb->descriptor.bcdDevice),
+ chip_name[UEA_CHIP_VERSION(id)]);
usb_reset_device(usb);
@@ -1788,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf)
* List of supported VID/PID
*/
static const struct usb_device_id uea_ids[] = {
+ {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
{USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
{USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
{}
};
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 11e9b15ca45a..e717f5b1caee 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -257,9 +257,10 @@ static void usbatm_complete(struct urb *urb)
{
struct usbatm_channel *channel = urb->context;
unsigned long flags;
+ int status = urb->status;
vdbg("%s: urb 0x%p, status %d, actual_length %d",
- __func__, urb, urb->status, urb->actual_length);
+ __func__, urb, status, urb->actual_length);
/* usually in_interrupt(), but not always */
spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@ static void usbatm_complete(struct urb *urb)
spin_unlock_irqrestore(&channel->lock, flags);
- if (unlikely(urb->status) &&
+ if (unlikely(status) &&
(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
- urb->status != -EILSEQ ))
+ status != -EILSEQ ))
{
- if (urb->status == -ESHUTDOWN)
+ if (status == -ESHUTDOWN)
return;
if (printk_ratelimit())
atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
- __func__, urb, urb->status);
+ __func__, urb, status);
/* throttle processing in case of an error */
mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
} else
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index cd51520c7e72..f51e22490edf 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -257,9 +257,10 @@ static void acm_ctrl_irq(struct urb *urb)
struct usb_cdc_notification *dr = urb->transfer_buffer;
unsigned char *data;
int newctrl;
- int status;
+ int retval;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -267,10 +268,10 @@ static void acm_ctrl_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
goto exit;
}
@@ -311,10 +312,10 @@ static void acm_ctrl_irq(struct urb *urb)
break;
}
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
/* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@ static void acm_read_bulk(struct urb *urb)
struct acm_ru *rcv = urb->context;
struct acm *acm = rcv->instance;
int status = urb->status;
- dbg("Entering acm_read_bulk with status %d", urb->status);
+
+ dbg("Entering acm_read_bulk with status %d", status);
if (!ACM_READY(acm))
return;
@@ -919,6 +921,10 @@ skip_normal_probe:
return -EINVAL;
}
}
+
+ /* Accept probe requests only for the control interface */
+ if (intf != control_interface)
+ return -ENODEV;
if (usb_interface_claimed(data_interface)) { /* valid in this context */
dev_dbg(&intf->dev,"The data interface isn't available");
@@ -1107,10 +1113,12 @@ static void acm_disconnect(struct usb_interface *intf)
return;
}
if (acm->country_codes){
- device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
- device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
+ device_remove_file(&acm->control->dev,
+ &dev_attr_wCountryCodes);
+ device_remove_file(&acm->control->dev,
+ &dev_attr_iCountryCodeRelDate);
}
- device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
+ device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
acm->dev = NULL;
usb_set_intfdata(acm->control, NULL);
usb_set_intfdata(acm->data, NULL);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 9a1478972bf5..ad632f2d6f94 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -28,6 +28,7 @@
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
+ * none - Maintained in Linux kernel after v0.13
*/
/*
@@ -69,7 +70,6 @@
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
-#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
+#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
@@ -159,10 +159,12 @@ struct usblp {
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
+ unsigned int flags; /* mode flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
+ unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
- request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+ request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
@@ -289,16 +291,17 @@ static int proto_bias = -1;
static void usblp_bulk_read(struct urb *urb)
{
struct usblp *usblp = urb->context;
+ int status = urb->status;
if (usblp->present && usblp->used) {
- if (urb->status)
+ if (status)
printk(KERN_WARNING "usblp%d: "
"nonzero read bulk status received: %d\n",
- usblp->minor, urb->status);
+ usblp->minor, status);
}
spin_lock(&usblp->lock);
- if (urb->status < 0)
- usblp->rstatus = urb->status;
+ if (status < 0)
+ usblp->rstatus = status;
else
usblp->rstatus = urb->actual_length;
usblp->rcomplete = 1;
@@ -311,25 +314,24 @@ static void usblp_bulk_read(struct urb *urb)
static void usblp_bulk_write(struct urb *urb)
{
struct usblp *usblp = urb->context;
+ int status = urb->status;
if (usblp->present && usblp->used) {
- if (urb->status)
+ if (status)
printk(KERN_WARNING "usblp%d: "
"nonzero write bulk status received: %d\n",
- usblp->minor, urb->status);
+ usblp->minor, status);
}
spin_lock(&usblp->lock);
- if (urb->status < 0)
- usblp->wstatus = urb->status;
+ if (status < 0)
+ usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
+ usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock(&usblp->lock);
- /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
- kfree(urb->transfer_buffer);
- urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
usb_free_urb(urb);
}
@@ -344,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
- error = usblp_read_status (usblp, usblp->statusbuf);
- if (error < 0) {
+ mutex_lock(&usblp->mut);
+ if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+ mutex_unlock(&usblp->mut);
if (printk_ratelimit())
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
-
status = *usblp->statusbuf;
+ mutex_unlock(&usblp->mut);
if (~status & LP_PERRORP)
newerr = 3;
@@ -409,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
/*
- * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
- * This is #if 0-ed because we *don't* want to fail an open
- * just because the printer is off-line.
+ * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+ * - We do not want persistent state which close(2) does not clear
+ * - It is not used anyway, according to CUPS people
*/
-#if 0
- if ((retval = usblp_check_status(usblp, 0))) {
- retval = retval > 1 ? -EIO : -ENOSPC;
- goto out;
- }
-#else
- retval = 0;
-#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
@@ -461,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
+ usblp->flags &= ~LP_ABORT;
+
mutex_lock (&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
@@ -483,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
poll_wait(file, &usblp->rwait, wait);
poll_wait(file, &usblp->wwait, wait);
spin_lock_irqsave(&usblp->lock, flags);
- ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
- | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+ ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) |
+ ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
@@ -673,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
+ case LPABORT:
+ if (arg)
+ usblp->flags |= LP_ABORT;
+ else
+ usblp->flags &= ~LP_ABORT;
+ break;
+
default:
retval = -ENOTTY;
}
@@ -682,10 +686,30 @@ done:
return retval;
}
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+ struct urb *urb;
+ char *writebuf;
+
+ if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+ return NULL;
+ if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+ kfree(writebuf);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, usblp->dev,
+ usb_sndbulkpipe(usblp->dev,
+ usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+ writebuf, transfer_length, usblp_bulk_write, usblp);
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ return urb;
+}
+
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
@@ -706,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
- if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
- goto raise_buf;
- if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+ if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
goto raise_urb;
- usb_fill_bulk_urb(writeurb, usblp->dev,
- usb_sndbulkpipe(usblp->dev,
- usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
- writebuf, transfer_length, usblp_bulk_write, usblp);
usb_anchor_urb(writeurb, &usblp->urbs);
- if (copy_from_user(writebuf,
+ if (copy_from_user(writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
rv = -EFAULT;
goto raise_badaddr;
@@ -728,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
+ usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
@@ -741,15 +760,21 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
*/
rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
if (rv < 0) {
- /*
- * If interrupted, we simply leave the URB to dangle,
- * so the ->release will call usb_kill_urb().
- */
+ if (rv == -EAGAIN) {
+ /* Presume that it's going to complete well. */
+ writecount += transfer_length;
+ }
+ if (rv == -ENOSPC) {
+ spin_lock_irq(&usblp->lock);
+ usblp->no_paper = 1; /* Mark for poll(2) */
+ spin_unlock_irq(&usblp->lock);
+ writecount += transfer_length;
+ }
+ /* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
if (usblp->wstatus < 0) {
- usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
@@ -768,8 +793,6 @@ raise_badaddr:
usb_unanchor_urb(writeurb);
usb_free_urb(writeurb);
raise_urb:
- kfree(writebuf);
-raise_buf:
raise_wait:
collect_error: /* Out of raise sequence */
mutex_unlock(&usblp->wmut);
@@ -835,32 +858,36 @@ done:
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
* select(2) or poll(2) to wait for the buffer to drain before closing.
* Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
*/
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
+ int err = 0;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
- set_current_state(TASK_INTERRUPTIBLE);
- if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
- mutex_unlock(&usblp->mut);
- break;
- }
+ rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
- if (rc == 0)
+ if (rc <= 0)
break;
- schedule();
+
+ if (usblp->flags & LP_ABORT) {
+ if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+ err = usblp_check_status(usblp, err);
+ if (err == 1) { /* Paper out */
+ rc = -ENOSPC;
+ break;
+ }
+ }
+ } else {
+ schedule();
+ }
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index cb69aa1e02e8..1a8edcee7f30 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
}
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ * whole thing. A non-authorized USB device has no
+ * configurations.
+ */
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
- int result = -ENOMEM;
+ int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
+ cfgno = 0;
+ if (dev->authorized == 0) /* Not really an error */
+ goto out_not_authorized;
+ result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
- for (cfgno = 0; cfgno < ncfg; cfgno++) {
+ result = 0;
+ for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s\n", cfgno, "start");
+ "descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
err:
kfree(buffer);
+out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 927a181120a9..f013b4012c9a 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -71,6 +71,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
+ int status;
u32 secid;
};
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop)
return;
- if (urb->pipe & USB_DIR_IN)
- dev_info(&urb->dev->dev, "direction=IN\n");
- else
- dev_info(&urb->dev->dev, "direction=OUT\n");
+ dev_info(&urb->dev->dev, "direction=%s\n",
+ usb_urb_dir_in(urb) ? "IN" : "OUT");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
+ as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
- sinfo.si_errno = as->urb->status;
+ sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
+ int is_in;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum)))
return ret;
}
- if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
- ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- else
- ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+ is_in = 1;
+ ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ } else {
+ is_in = 0;
+ ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ }
if (!ep)
return -ENOENT;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_CONTROL)
+ if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return ret;
}
- uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+ if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+ is_in = 1;
+ uurb->endpoint |= USB_DIR_IN;
+ } else {
+ is_in = 0;
+ uurb->endpoint &= ~USB_DIR_IN;
+ }
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
- dr->bRequest, dr->bRequestType, dr->wValue,
- dr->wIndex, dr->wLength);
+ dr->bRequest, dr->bRequestType,
+ __le16_to_cpup(&dr->wValue),
+ __le16_to_cpup(&dr->wIndex),
+ __le16_to_cpup(&dr->wLength));
break;
case USBDEVFS_URB_TYPE_BULK:
- switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_ISOC)
+ if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_INT)
+ if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM;
}
as->urb->dev = ps->dev;
- as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb->flags;
+ as->urb->pipe = (uurb->type << 30) |
+ __create_pipe(ps->dev, uurb->endpoint & 0xf) |
+ (uurb->endpoint & USB_DIR_IN);
+ as->urb->transfer_flags = uurb->flags |
+ (is_in ? URB_DIR_IN : URB_DIR_OUT);
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
- if (!(uurb->endpoint & USB_DIR_IN)) {
- if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+ if (!is_in) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+ as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
- snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(urb->status, &userurb->status))
+ if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_pipeisoc(urb->pipe)) {
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(urb->status, &userurb->status))
+ if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_pipeisoc(urb->pipe)) {
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1576,6 +1591,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
}
const struct file_operations usbdev_file_operations = {
+ .owner = THIS_MODULE,
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@ -1625,10 +1641,7 @@ static struct notifier_block usbdev_nb = {
};
#endif
-static struct cdev usb_device_cdev = {
- .kobj = {.name = "usb_device", },
- .owner = THIS_MODULE,
-};
+static struct cdev usb_device_cdev;
int __init usb_devio_init(void)
{
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 73c49362cd47..8586817698ad 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -29,13 +29,6 @@
#include "hcd.h"
#include "usb.h"
-#define VERBOSE_DEBUG 0
-
-#if VERBOSE_DEBUG
-#define dev_vdbg dev_dbg
-#else
-#define dev_vdbg(dev, fmt, args...) do { } while (0)
-#endif
#ifdef CONFIG_HOTPLUG
@@ -67,7 +60,7 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
spin_lock(&dynids->lock);
- list_add_tail(&dynids->list, &dynid->node);
+ list_add_tail(&dynid->node, &dynids->list);
spin_unlock(&dynids->lock);
if (get_driver(driver)) {
@@ -209,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+ return -ENODEV;
+ }
+
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
@@ -583,12 +581,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -617,51 +612,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
* all the device descriptors we don't tell them about. Or
* act as usermode drivers.
*/
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
#endif
/* per-device configurations are common */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
/* class-based driver binding models */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "BUSNUM=%03d",
+ if (add_uevent_var(env, "BUSNUM=%03d",
usb_dev->bus->busnum))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVNUM=%03d",
+ if (add_uevent_var(env, "DEVNUM=%03d",
usb_dev->devnum))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
#else
-static int usb_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -952,11 +935,11 @@ done:
#ifdef CONFIG_USB_SUSPEND
/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
{
int i;
struct usb_interface *intf;
- unsigned long suspend_time;
+ unsigned long suspend_time, j;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
@@ -998,20 +981,20 @@ static int autosuspend_check(struct usb_device *udev)
}
/* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request.
+ * enough, queue a delayed autosuspend request. If the device
+ * _has_ been idle for long enough and the reschedule flag is set,
+ * likewise queue a delayed (1 second) autosuspend request.
*/
- if (time_after(suspend_time, jiffies)) {
+ j = jiffies;
+ if (time_before(j, suspend_time))
+ reschedule = 1;
+ else
+ suspend_time = j + HZ;
+ if (reschedule) {
if (!timer_pending(&udev->autosuspend.timer)) {
-
- /* The value of jiffies may change between the
- * time_after() comparison above and the subtraction
- * below. That's okay; the system behaves sanely
- * when a timer is registered for the present moment
- * or for the past.
- */
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- round_jiffies_relative(suspend_time - jiffies));
- }
+ round_jiffies_relative(suspend_time - j));
+ }
return -EAGAIN;
}
return 0;
@@ -1019,7 +1002,7 @@ static int autosuspend_check(struct usb_device *udev)
#else
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
{
return 0;
}
@@ -1076,7 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
- status = autosuspend_check(udev);
+ status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
}
@@ -1090,15 +1073,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
- if (status == 0) {
-
- /* Non-root devices don't need to do anything for FREEZE
- * or PRETHAW. */
- if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
- msg.event == PM_EVENT_PRETHAW))
- goto done;
+ if (status == 0)
status = usb_suspend_device(udev, msg);
- }
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
@@ -1109,12 +1085,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* Try another autosuspend when the interfaces aren't busy */
if (udev->auto_pm)
- autosuspend_check(udev);
+ autosuspend_check(udev, status == -EBUSY);
- /* If the suspend succeeded, propagate it up the tree */
+ /* If the suspend succeeded then prevent any more URB submissions,
+ * flush any outstanding URBs, and propagate the suspend up the tree.
+ */
} else {
cancel_delayed_work(&udev->autosuspend);
- if (parent)
+ udev->can_submit = 0;
+ for (i = 0; i < 16; ++i) {
+ usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+ usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+ }
+
+ /* If this is just a FREEZE or a PRETHAW, udev might
+ * not really be suspended. Only true suspends get
+ * propagated up the device tree.
+ */
+ if (parent && udev->state == USB_STATE_SUSPENDED)
usb_autosuspend_device(parent);
}
@@ -1163,6 +1151,7 @@ static int usb_resume_both(struct usb_device *udev)
status = -ENODEV;
goto done;
}
+ udev->can_submit = 1;
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
@@ -1231,6 +1220,8 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
udev->auto_pm = 1;
udev->pm_usage_cnt += inc_usage_cnt;
WARN_ON(udev->pm_usage_cnt < 0);
+ if (inc_usage_cnt)
+ udev->last_busy = jiffies;
if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
if (udev->state == USB_STATE_SUSPENDED)
status = usb_resume_both(udev);
@@ -1239,8 +1230,6 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
else if (inc_usage_cnt)
udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
- if (inc_usage_cnt)
- udev->last_busy = jiffies;
status = usb_suspend_both(udev, PMSG_SUSPEND);
}
usb_pm_unlock(udev);
@@ -1349,16 +1338,15 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
else {
udev->auto_pm = 1;
intf->pm_usage_cnt += inc_usage_cnt;
+ udev->last_busy = jiffies;
if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
if (udev->state == USB_STATE_SUSPENDED)
status = usb_resume_both(udev);
if (status != 0)
intf->pm_usage_cnt -= inc_usage_cnt;
- else if (inc_usage_cnt)
+ else
udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
- if (inc_usage_cnt)
- udev->last_busy = jiffies;
status = usb_suspend_both(udev, PMSG_SUSPEND);
}
}
@@ -1537,9 +1525,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
+ struct usb_device *udev;
+
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
- return usb_external_suspend_device(to_usb_device(dev), message);
+ udev = to_usb_device(dev);
+
+ /* If udev is already suspended, we can skip this suspend and
+ * we should also skip the upcoming system resume. */
+ if (udev->state == USB_STATE_SUSPENDED) {
+ udev->skip_sys_resume = 1;
+ return 0;
+ }
+
+ udev->skip_sys_resume = 0;
+ return usb_external_suspend_device(udev, message);
}
static int usb_resume(struct device *dev)
@@ -1550,13 +1550,14 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
- /* If autoresume is disabled then we also want to prevent resume
- * during system wakeup. However, a "persistent-device" reset-resume
- * after power loss counts as a wakeup event. So allow a
- * reset-resume to occur if remote wakeup is enabled. */
- if (udev->autoresume_disabled) {
+ /* If udev->skip_sys_resume is set then udev was already suspended
+ * when the system suspend started, so we don't want to resume
+ * udev during this system wakeup. However a reset-resume counts
+ * as a wakeup event, so allow a reset-resume to occur if remote
+ * wakeup is enabled. */
+ if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
- return -EPERM;
+ return -EHOSTUNREACH;
}
return usb_external_resume_device(udev);
}
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index e0ec7045e865..7dc123d6b2d0 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
- dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index b2fc2b115256..c1cb94e9f242 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
- c = choose_configuration(udev);
- if (c >= 0) {
- err = usb_set_configuration(udev, c);
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ if (udev->authorized == 0)
+ dev_err(&udev->dev, "Device is not authorized for usage\n");
+ else {
+ c = usb_choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
}
}
-
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
*/
if (!udev->parent)
rc = hcd_bus_suspend(udev);
+
+ /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+ else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ rc = 0;
else
rc = usb_port_suspend(udev);
+
return rc;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 963520fbef90..3dd997df8505 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -99,12 +99,17 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock);
/* used for controlling access to virtual root hubs */
static DEFINE_SPINLOCK(hcd_root_hub_lock);
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
/* wait queue for synchronous unlinks */
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
+static inline int is_root_hub(struct usb_device *udev)
+{
+ return (udev->parent == NULL);
+}
+
/*-------------------------------------------------------------------------*/
/*
@@ -351,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
- unsigned long flags;
- int status = 0;
+ int status;
int n;
+ might_sleep();
+
+ spin_lock_irq(&hcd_root_hub_lock);
+ status = usb_hcd_link_urb_to_ep(hcd, urb);
+ spin_unlock_irq(&hcd_root_hub_lock);
+ if (status)
+ return status;
+ urb->hcpriv = hcd; /* Indicate it's queued */
+
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
@@ -518,13 +531,18 @@ error:
}
/* any errors get returned through the urb completion */
- local_irq_save (flags);
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock (&urb->lock);
- usb_hcd_giveback_urb (hcd, urb);
- local_irq_restore (flags);
+ spin_lock_irq(&hcd_root_hub_lock);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ /* This peculiar use of spinlocks echoes what real HC drivers do.
+ * Avoiding calls to local_irq_disable/enable makes the code
+ * RT-friendly.
+ */
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+
+ spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
@@ -554,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
if (length > 0) {
/* try to complete the status urb */
- local_irq_save (flags);
- spin_lock(&hcd_root_hub_lock);
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (urb) {
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS) {
- hcd->poll_pending = 0;
- hcd->status_urb = NULL;
- urb->status = 0;
- urb->hcpriv = NULL;
- urb->actual_length = length;
- memcpy(urb->transfer_buffer, buffer, length);
- } else /* urb has been unlinked */
- length = 0;
- spin_unlock(&urb->lock);
- } else
- length = 0;
- spin_unlock(&hcd_root_hub_lock);
+ hcd->poll_pending = 0;
+ hcd->status_urb = NULL;
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
- /* local irqs are always blocked in completions */
- if (length > 0)
- usb_hcd_giveback_urb (hcd, urb);
- else
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, 0);
+ spin_lock(&hcd_root_hub_lock);
+ } else {
+ length = 0;
hcd->poll_pending = 1;
- local_irq_restore (flags);
+ }
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
@@ -606,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
- if (urb->status != -EINPROGRESS) /* already unlinked */
- retval = urb->status;
- else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+ if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
- } else {
- hcd->status_urb = urb;
- urb->hcpriv = hcd; /* indicate it's queued */
+ goto done;
+ }
- if (!hcd->uses_new_polling)
- mod_timer (&hcd->rh_timer,
- (jiffies/(HZ/4) + 1) * (HZ/4));
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
+ goto done;
- /* If a status change has already occurred, report it ASAP */
- else if (hcd->poll_pending)
- mod_timer (&hcd->rh_timer, jiffies);
- retval = 0;
- }
+ hcd->status_urb = urb;
+ urb->hcpriv = hcd; /* indicate it's queued */
+ if (!hcd->uses_new_polling)
+ mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+ /* If a status change has already occurred, report it ASAP */
+ else if (hcd->poll_pending)
+ mod_timer(&hcd->rh_timer, jiffies);
+ retval = 0;
+ done:
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_pipeint (urb->pipe))
+ if (usb_endpoint_xfer_int(&urb->ep->desc))
return rh_queue_status (hcd, urb);
- if (usb_pipecontrol (urb->pipe))
+ if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
return -EINVAL;
}
@@ -642,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/* Unlinks of root-hub control URBs are legal, but they don't do anything
* since these URBs always execute synchronously.
*/
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
+ int rc;
- if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
+ if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer (&hcd->rh_timer);
- local_irq_save (flags);
- spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
- urb->hcpriv = NULL;
- } else
- urb = NULL; /* wasn't fully queued */
- spin_unlock (&hcd_root_hub_lock);
- if (urb)
- usb_hcd_giveback_urb (hcd, urb);
- local_irq_restore (flags);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+ }
}
+ done:
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ return rc;
+}
- return 0;
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned val;
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ result = sscanf(buf, "%u\n", &val);
+ if (result == 1) {
+ usb_hcd->authorized_default = val? 1 : 0;
+ result = size;
+ }
+ else
+ result = -EINVAL;
+ return result;
}
+static DEVICE_ATTR(authorized_default, 0644,
+ usb_host_authorized_default_show,
+ usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+ &dev_attr_authorized_default.attr,
+ NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = usb_bus_attrs,
+};
+
+
+
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
@@ -721,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus)
*/
static int usb_register_bus(struct usb_bus *bus)
{
+ int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
- if (busnum < USB_MAXBUS) {
- set_bit (busnum, busmap.busmap);
- bus->busnum = busnum;
- } else {
+ if (busnum >= USB_MAXBUS) {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
- mutex_unlock(&usb_bus_list_lock);
- return -E2BIG;
+ goto error_find_busnum;
}
-
+ set_bit (busnum, busmap.busmap);
+ bus->busnum = busnum;
bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
- bus->controller, "usb_host%d", busnum);
- if (IS_ERR(bus->class_dev)) {
- clear_bit(busnum, busmap.busmap);
- mutex_unlock(&usb_bus_list_lock);
- return PTR_ERR(bus->class_dev);
- }
-
+ bus->controller, "usb_host%d",
+ busnum);
+ result = PTR_ERR(bus->class_dev);
+ if (IS_ERR(bus->class_dev))
+ goto error_create_class_dev;
class_set_devdata(bus->class_dev, bus);
/* Add it to the local list of buses */
@@ -750,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus)
usb_notify_add_bus(bus);
- dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+ dev_info (bus->controller, "new USB bus registered, assigned bus "
+ "number %d\n", bus->busnum);
return 0;
+
+error_create_class_dev:
+ clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+ mutex_unlock(&usb_bus_list_lock);
+ return result;
}
/**
@@ -903,104 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail). If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
{
- unsigned long flags;
- int at_root_hub = (urb->dev == hcd->self.root_hub);
+ int rc = 0;
- /* clear all state linking urb to this dev (and hcd) */
- spin_lock_irqsave (&hcd_data_lock, flags);
- list_del_init (&urb->urb_list);
- spin_unlock_irqrestore (&hcd_data_lock, flags);
+ spin_lock(&hcd_urb_list_lock);
- if (hcd->self.uses_dma && !at_root_hub) {
- if (usb_pipecontrol (urb->pipe)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- dma_unmap_single (hcd->self.controller, urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
- dma_unmap_single (hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
+ /* Check that the URB isn't being killed */
+ if (unlikely(urb->reject)) {
+ rc = -EPERM;
+ goto done;
}
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
- int status;
- struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
- struct usb_host_endpoint *ep;
- unsigned long flags;
- if (!hcd)
- return -ENODEV;
+ if (unlikely(!urb->ep->enabled)) {
+ rc = -ENOENT;
+ goto done;
+ }
- usbmon_urb_submit(&hcd->self, urb);
+ if (unlikely(!urb->dev->can_submit)) {
+ rc = -EHOSTUNREACH;
+ goto done;
+ }
/*
- * Atomically queue the urb, first to our records, then to the HCD.
- * Access to urb->status is controlled by urb->lock ... changes on
- * i/o completion (normal or fault) or unlinking.
+ * Check the host controller's state and add the URB to the
+ * endpoint's queue.
*/
-
- // FIXME: verify that quiescing hc works right (RH cleans up)
-
- spin_lock_irqsave (&hcd_data_lock, flags);
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (unlikely (!ep))
- status = -ENOENT;
- else if (unlikely (urb->reject))
- status = -EPERM;
- else switch (hcd->state) {
+ switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
- list_add_tail (&urb->urb_list, &ep->urb_list);
- status = 0;
+ urb->unlinked = 0;
+ list_add_tail(&urb->urb_list, &urb->ep->urb_list);
break;
default:
- status = -ESHUTDOWN;
- break;
+ rc = -ESHUTDOWN;
+ goto done;
}
- spin_unlock_irqrestore (&hcd_data_lock, flags);
- if (status) {
- INIT_LIST_HEAD (&urb->urb_list);
- usbmon_urb_submit_error(&hcd->self, urb, status);
- return status;
+ done:
+ spin_unlock(&hcd_urb_list_lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail). The possible error codes are:
+ *
+ * -EIDRM: @urb was not submitted or has already completed.
+ * The completion function may not have been called yet.
+ *
+ * -EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct list_head *tmp;
+
+ /* insist the urb is still queued */
+ list_for_each(tmp, &urb->ep->urb_list) {
+ if (tmp == &urb->urb_list)
+ break;
}
+ if (tmp != &urb->urb_list)
+ return -EIDRM;
- /* increment urb's reference count as part of giving it to the HCD
- * (which now controls it). HCD guarantees that it either returns
- * an error or calls giveback(), but not both.
+ /* Any status except -EINPROGRESS means something already started to
+ * unlink this URB from the hardware. So there's no more work to do.
*/
- urb = usb_get_urb (urb);
- atomic_inc (&urb->use_count);
-
- if (urb->dev == hcd->self.root_hub) {
- /* NOTE: requirement on hub callers (usbfs and the hub
- * driver, for now) that URBs' urb->transfer_buffer be
- * valid and usb_buffer_{sync,unmap}() not be needed, since
- * they could clobber root hub response data.
- */
- status = rh_urb_enqueue (hcd, urb);
- goto done;
+ if (urb->unlinked)
+ return -EBUSY;
+ urb->unlinked = status;
+
+ /* IRQ setup can easily be broken so that USB controllers
+ * never get completion IRQs ... maybe even the ones we need to
+ * finish unlinking the initial failed usb_set_address()
+ * or device descriptor fetch.
+ */
+ if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+ !is_root_hub(urb->dev)) {
+ dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
+ "Controller is probably using the wrong IRQ.\n");
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
- /* lower level hcd code should use *_dma exclusively,
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
+ * interrupts must be disabled. The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* clear all state linking urb to this dev (and hcd) */
+ spin_lock(&hcd_urb_list_lock);
+ list_del_init(&urb->urb_list);
+ spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* Map the URB's buffers for DMA access.
+ * Lower level HCD code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.uses_dma) {
- if (usb_pipecontrol (urb->pipe)
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
hcd->self.controller,
@@ -1013,34 +1133,77 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
hcd->self.controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_urb_dir_in(urb)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
+}
- status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
- if (unlikely (status)) {
- urb_unlink(hcd, urb);
- atomic_dec (&urb->use_count);
- if (urb->reject)
- wake_up (&usb_kill_urb_queue);
- usbmon_urb_submit_error(&hcd->self, urb, status);
- usb_put_urb (urb);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ dma_unmap_single(hcd->self.controller, urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ dma_unmap_single(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_urb_dir_in(urb)
+ ? DMA_FROM_DEVICE
+ : DMA_TO_DEVICE);
}
- return status;
}
/*-------------------------------------------------------------------------*/
-/* called in any context */
-int usb_hcd_get_frame_number (struct usb_device *udev)
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int status;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
- if (!HC_IS_RUNNING (hcd->state))
- return -ESHUTDOWN;
- return hcd->driver->get_frame_number (hcd);
+ /* increment urb's reference count as part of giving it to the HCD
+ * (which will control it). HCD guarantees that it either returns
+ * an error or calls giveback(), but not both.
+ */
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usbmon_urb_submit(&hcd->self, urb);
+
+ /* NOTE requirements on root-hub callers (usbfs and the hub
+ * driver, for now): URBs' urb->transfer_buffer must be
+ * valid and usb_buffer_{sync,unmap}() not be needed, since
+ * they could clobber root hub response data. Also, control
+ * URBs must be submitted in process context with interrupts
+ * enabled.
+ */
+ map_urb_for_dma(hcd, urb);
+ if (is_root_hub(urb->dev))
+ status = rh_urb_enqueue(hcd, urb);
+ else
+ status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+ if (unlikely(status)) {
+ usbmon_urb_submit_error(&hcd->self, urb, status);
+ unmap_urb_for_dma(hcd, urb);
+ urb->hcpriv = NULL;
+ INIT_LIST_HEAD(&urb->urb_list);
+ atomic_dec(&urb->use_count);
+ atomic_dec(&urb->dev->urbnum);
+ if (urb->reject)
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
+ }
+ return status;
}
/*-------------------------------------------------------------------------*/
@@ -1050,24 +1213,19 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
* soon as practical. we've already set up the urb's return status,
* but we can't know if the callback completed already.
*/
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
{
int value;
- if (urb->dev == hcd->self.root_hub)
- value = usb_rh_urb_dequeue (hcd, urb);
+ if (is_root_hub(urb->dev))
+ value = usb_rh_urb_dequeue(hcd, urb, status);
else {
/* The only reason an HCD might fail this call is if
* it has not yet fully queued the urb to begin with.
* Such failures should be harmless. */
- value = hcd->driver->urb_dequeue (hcd, urb);
+ value = hcd->driver->urb_dequeue(hcd, urb, status);
}
-
- if (value != 0)
- dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
- urb, value);
return value;
}
@@ -1079,168 +1237,122 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
*/
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
- struct usb_host_endpoint *ep;
- struct usb_hcd *hcd = NULL;
- struct device *sys = NULL;
- unsigned long flags;
- struct list_head *tmp;
- int retval;
-
- if (!urb)
- return -EINVAL;
- if (!urb->dev || !urb->dev->bus)
- return -ENODEV;
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep)
- return -ENODEV;
-
- /*
- * we contend for urb->status with the hcd core,
- * which changes it while returning the urb.
- *
- * Caller guaranteed that the urb pointer hasn't been freed, and
- * that it was submitted. But as a rule it can't know whether or
- * not it's already been unlinked ... so we respect the reversed
- * lock sequence needed for the usb_hcd_giveback_urb() code paths
- * (urb lock, then hcd_data_lock) in case some other CPU is now
- * unlinking it.
- */
- spin_lock_irqsave (&urb->lock, flags);
- spin_lock (&hcd_data_lock);
+ struct usb_hcd *hcd;
+ int retval;
- sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
- if (hcd == NULL) {
- retval = -ENODEV;
- goto done;
- }
-
- /* insist the urb is still queued */
- list_for_each(tmp, &ep->urb_list) {
- if (tmp == &urb->urb_list)
- break;
- }
- if (tmp != &urb->urb_list) {
- retval = -EIDRM;
- goto done;
- }
-
- /* Any status except -EINPROGRESS means something already started to
- * unlink this URB from the hardware. So there's no more work to do.
- */
- if (urb->status != -EINPROGRESS) {
- retval = -EBUSY;
- goto done;
- }
-
- /* IRQ setup can easily be broken so that USB controllers
- * never get completion IRQs ... maybe even the ones we need to
- * finish unlinking the initial failed usb_set_address()
- * or device descriptor fetch.
- */
- if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
- && hcd->self.root_hub != urb->dev) {
- dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
- "Controller is probably using the wrong IRQ."
- "\n");
- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
- }
-
- urb->status = status;
+ retval = unlink1(hcd, urb, status);
- spin_unlock (&hcd_data_lock);
- spin_unlock_irqrestore (&urb->lock, flags);
-
- retval = unlink1 (hcd, urb);
if (retval == 0)
retval = -EINPROGRESS;
- return retval;
-
-done:
- spin_unlock (&hcd_data_lock);
- spin_unlock_irqrestore (&urb->lock, flags);
- if (retval != -EIDRM && sys && sys->driver)
- dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+ else if (retval != -EIDRM && retval != -EBUSY)
+ dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+ urb, retval);
return retval;
}
/*-------------------------------------------------------------------------*/
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
+ * Context: in_interrupt()
*
- * example: a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function. The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv). It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked. Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
+ */
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ urb->hcpriv = NULL;
+ if (unlikely(urb->unlinked))
+ status = urb->unlinked;
+ else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length < urb->transfer_buffer_length &&
+ !status))
+ status = -EREMOTEIO;
+
+ unmap_urb_for_dma(hcd, urb);
+ usbmon_urb_complete(&hcd->self, urb, status);
+ usb_unanchor_urb(urb);
+
+ /* pass ownership to the completion handler */
+ urb->status = status;
+ urb->complete (urb);
+ atomic_dec (&urb->use_count);
+ if (unlikely (urb->reject))
+ wake_up (&usb_kill_urb_queue);
+ usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely. The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
*/
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
+ if (!ep)
+ return;
+ might_sleep();
hcd = bus_to_hcd(udev->bus);
- local_irq_disable ();
- /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+ /* No more submits can occur */
rescan:
- spin_lock (&hcd_data_lock);
+ spin_lock_irq(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
- int tmp;
+ int is_in;
- /* the urb may already have been unlinked */
- if (urb->status != -EINPROGRESS)
+ if (urb->unlinked)
continue;
usb_get_urb (urb);
- spin_unlock (&hcd_data_lock);
-
- spin_lock (&urb->lock);
- tmp = urb->status;
- if (tmp == -EINPROGRESS)
- urb->status = -ESHUTDOWN;
- spin_unlock (&urb->lock);
-
- /* kick hcd unless it's already returning this */
- if (tmp == -EINPROGRESS) {
- tmp = urb->pipe;
- unlink1 (hcd, urb);
- dev_dbg (hcd->self.controller,
- "shutdown urb %p pipe %08x ep%d%s%s\n",
- urb, tmp, usb_pipeendpoint (tmp),
- (tmp & USB_DIR_IN) ? "in" : "out",
- ({ char *s; \
- switch (usb_pipetype (tmp)) { \
- case PIPE_CONTROL: s = ""; break; \
- case PIPE_BULK: s = "-bulk"; break; \
- case PIPE_INTERRUPT: s = "-intr"; break; \
- default: s = "-iso"; break; \
- }; s;}));
- }
+ is_in = usb_urb_dir_in(urb);
+ spin_unlock(&hcd_urb_list_lock);
+
+ /* kick hcd */
+ unlink1(hcd, urb, -ESHUTDOWN);
+ dev_dbg (hcd->self.controller,
+ "shutdown urb %p ep%d%s%s\n",
+ urb, usb_endpoint_num(&ep->desc),
+ is_in ? "in" : "out",
+ ({ char *s;
+
+ switch (usb_endpoint_type(&ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ s = ""; break;
+ case USB_ENDPOINT_XFER_BULK:
+ s = "-bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+ s = "-intr"; break;
+ default:
+ s = "-iso"; break;
+ };
+ s;
+ }));
usb_put_urb (urb);
/* list contents may have changed */
goto rescan;
}
- spin_unlock (&hcd_data_lock);
- local_irq_enable ();
-
- /* synchronize with the hardware, so old configuration state
- * clears out immediately (and will be freed).
- */
- might_sleep ();
- if (hcd->driver->endpoint_disable)
- hcd->driver->endpoint_disable (hcd, ep);
+ spin_unlock_irq(&hcd_urb_list_lock);
- /* Wait until the endpoint queue is completely empty. Most HCDs
- * will have done this already in their endpoint_disable method,
- * but some might not. And there could be root-hub control URBs
- * still pending since they aren't affected by the HCDs'
- * endpoint_disable methods.
- */
+ /* Wait until the endpoint queue is completely empty */
while (!list_empty (&ep->urb_list)) {
- spin_lock_irq (&hcd_data_lock);
+ spin_lock_irq(&hcd_urb_list_lock);
/* The list may have changed while we acquired the spinlock */
urb = NULL;
@@ -1249,7 +1361,7 @@ rescan:
urb_list);
usb_get_urb (urb);
}
- spin_unlock_irq (&hcd_data_lock);
+ spin_unlock_irq(&hcd_urb_list_lock);
if (urb) {
usb_kill_urb (urb);
@@ -1258,6 +1370,37 @@ rescan:
}
}
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd;
+
+ might_sleep();
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable(hcd, ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HC_IS_RUNNING (hcd->state))
+ return -ESHUTDOWN;
+ return hcd->driver->get_frame_number (hcd);
+}
+
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
@@ -1395,35 +1538,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
/*-------------------------------------------------------------------------*/
/**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function. The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv). It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
- urb_unlink(hcd, urb);
- usbmon_urb_complete (&hcd->self, urb);
- usb_unanchor_urb(urb);
-
- /* pass ownership to the completion handler */
- urb->complete (urb);
- atomic_dec (&urb->use_count);
- if (unlikely (urb->reject))
- wake_up (&usb_kill_urb_queue);
- usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
-/**
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
* @irq: the IRQ being raised
* @__hcd: pointer to the HCD whose IRQ is being signaled
@@ -1522,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
-
return hcd;
}
EXPORT_SYMBOL (usb_create_hcd);
@@ -1567,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+ hcd->authorized_default = hcd->wireless? 0 : 1;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* HC is in reset state, but accessible. Now do the one-time init,
@@ -1643,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;
+ retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+ if (retval < 0) {
+ printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+ retval);
+ goto error_create_attr_group;
+ }
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
+error_create_attr_group:
+ mutex_lock(&usb_bus_list_lock);
+ usb_disconnect(&hcd->self.root_hub);
+ mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
@@ -1688,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
+ sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index b5ebb73c2332..98e24194a4ab 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -19,6 +19,8 @@
#ifdef __KERNEL__
+#include <linux/rwsem.h>
+
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
@@ -51,6 +53,12 @@
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ * connect by default or they require explicit
+ * user space authorization; this bit is settable
+ * through /sys/class/usb_host/X/authorized_default.
+ * For the rest is RO, so we don't lock to r/w it.
*/
/*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@ struct usb_hcd {
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
+ unsigned authorized_default:1;
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
- int (*urb_enqueue) (struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
- struct urb *urb,
- gfp_t mem_flags);
- int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+ int (*urb_enqueue)(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags);
+ int (*urb_dequeue)(struct usb_hcd *hcd,
+ struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
- void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+ void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_submit_error)(bus, urb, error);
}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ int status)
{
if (bus->monitored)
- (*mon_ops->urb_complete)(bus, urb);
+ (*mon_ops->urb_complete)(bus, urb, status);
}
int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ int status) {}
#endif /* CONFIG_USB_MON */
@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
: (in_interrupt () ? "in_interrupt" : "can sleep"))
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
+#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index fd74c50b1804..d20cb545a6e4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "
"first one fails");
+/* Mutual exclusion for EHCI CF initialization. This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
static inline char *portspeed(int portstatus)
{
@@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
- int status;
+ int status = urb->status;
int i;
unsigned long bits;
- switch (urb->status) {
+ switch (status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
- dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+ dev_dbg (hub->intfdev, "transfer --> %d\n", status);
if ((++hub->nerrors < 10) || hub->error)
goto resubmit;
- hub->error = urb->status;
+ hub->error = status;
/* FALL THROUGH */
/* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#endif
/**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not. Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
*/
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
{
- int err;
-
- /* Determine quirks */
- usb_detect_quirks(udev);
-
- err = usb_get_configuration(udev);
- if (err < 0) {
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
- goto fail;
- }
-
- /* read the standard strings and cache them if present */
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
- udev->manufacturer = usb_cache_string(udev,
- udev->descriptor.iManufacturer);
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
- /* Tell the world! */
- dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
- "SerialNumber=%d\n",
- udev->descriptor.iManufacturer,
- udev->descriptor.iProduct,
- udev->descriptor.iSerialNumber);
- show_string(udev, "Product", udev->product);
- show_string(udev, "Manufacturer", udev->manufacturer);
- show_string(udev, "SerialNumber", udev->serial);
+ int err = 0;
#ifdef CONFIG_USB_OTG
/*
@@ -1329,12 +1295,90 @@ int usb_new_device(struct usb_device *udev)
err = -ENOTSUPP;
goto fail;
}
+fail:
#endif
+ return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+ int err;
+
+ if (udev->config == NULL) {
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ goto fail;
+ }
+ }
+ if (udev->wusb == 1 && udev->authorized == 0) {
+ udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ }
+ else {
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+ }
+ err = usb_configure_device_otg(udev);
+fail:
+ return err;
+}
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+ int err;
+
+ usb_detect_quirks(udev); /* Determine quirks */
+ err = usb_configure_device(udev); /* detect & probe dev/intfs */
+ if (err < 0)
+ goto fail;
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
+ /* Increment the parent's count of unsuspended children */
+ if (udev->parent)
+ usb_autoresume_device(udev->parent);
+
/* Register the device. The device driver is responsible
* for adding the device files to sysfs and for configuring
* the device.
@@ -1345,18 +1389,103 @@ int usb_new_device(struct usb_device *udev)
goto fail;
}
- /* Increment the parent's count of unsuspended children */
- if (udev->parent)
- usb_autoresume_device(udev->parent);
-
-exit:
+ /* Tell the world! */
+ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+ "SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- goto exit;
+ return err;
+}
+
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+ unsigned cnt;
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 0)
+ goto out_unauthorized;
+ usb_dev->authorized = 0;
+ usb_set_configuration(usb_dev, -1);
+ usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->config);
+ usb_dev->config = NULL;
+ for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+ kfree(usb_dev->rawdescriptors[cnt]);
+ usb_dev->descriptor.bNumConfigurations = 0;
+ kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+ usb_unlock_device(usb_dev);
+ return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+ int result = 0, c;
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 1)
+ goto out_authorized;
+ kfree(usb_dev->product);
+ usb_dev->product = NULL;
+ kfree(usb_dev->manufacturer);
+ usb_dev->manufacturer = NULL;
+ kfree(usb_dev->serial);
+ usb_dev->serial = NULL;
+ result = usb_autoresume_device(usb_dev);
+ if (result < 0) {
+ dev_err(&usb_dev->dev,
+ "can't autoresume for authorization: %d\n", result);
+ goto error_autoresume;
+ }
+ result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+ if (result < 0) {
+ dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+ "authorization: %d\n", result);
+ goto error_device_descriptor;
+ }
+ usb_dev->authorized = 1;
+ result = usb_configure_device(usb_dev);
+ if (result < 0)
+ goto error_configure;
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ c = usb_choose_configuration(usb_dev);
+ if (c >= 0) {
+ result = usb_set_configuration(usb_dev, c);
+ if (result) {
+ dev_err(&usb_dev->dev,
+ "can't set config #%d, error %d\n", c, result);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+ dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+ usb_unlock_device(usb_dev); // complements locktree
+ return result;
}
+
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
@@ -1458,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
{
int i, status;
+ /* Block EHCI CF initialization during the port reset.
+ * Some companion controllers don't like it when they mix.
+ */
+ down_read(&ehci_cf_port_reset_rwsem);
+
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
status = set_port_feature(hub->hdev,
@@ -1479,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
+ udev->devnum = 0; /* Device now at address 0 */
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@@ -1488,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
usb_set_device_state(udev, status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
- return status;
+ goto done;
}
dev_dbg (hub->intfdev,
@@ -1501,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
+ done:
+ up_read(&ehci_cf_port_reset_rwsem);
return status;
}
@@ -1642,9 +1779,10 @@ static int finish_port_resume(struct usb_device *udev)
* and device drivers will know about any resume quirks.
*/
if (status == 0) {
+ devstatus = 0;
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
if (status >= 0)
- status = (status == 2 ? 0 : -ENODEV);
+ status = (status > 0 ? 0 : -ENODEV);
}
if (status) {
@@ -1830,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
- if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef CONFIG_USB_SUSPEND
- udev->state != USB_STATE_SUSPENDED
-#else
- udev->dev.power.power_state.event
- == PM_EVENT_ON
-#endif
- ) {
+ if (udev && udev->can_submit) {
if (!hdev->auto_pm)
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
@@ -1996,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+ usb_enable_endpoint(udev, &udev->ep0);
}
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
- if (udev->devnum == 0)
+ if (devnum <= 1)
return -EINVAL;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
- USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+ USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
+ udev->devnum = devnum; /* Device now using proper address */
usb_set_device_state(udev, USB_STATE_ADDRESS);
ep0_reinit(udev);
}
@@ -2042,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
+ int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -2071,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
oldspeed = udev->speed;
-
+
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2112,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
- udev->bus->controller->driver->name, udev->devnum);
+ udev->bus->controller->driver->name, devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -2199,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev);
+ retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
msleep(200);
@@ -2207,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
- udev->devnum, retval);
+ devnum, retval);
goto fail;
}
@@ -2260,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = 0;
fail:
- if (retval)
+ if (retval) {
hub_port_disable(hub, port1, 0);
+ udev->devnum = devnum; /* for disconnect processing */
+ }
mutex_unlock(&usb_address0_mutex);
return retval;
}
@@ -2696,9 +2831,9 @@ static void hub_events(void)
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
/* FIXME: Is this always true? */
- hub->limited_power = 0;
- else
hub->limited_power = 1;
+ else
+ hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 530e854961ce..c021af390372 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -18,9 +18,17 @@
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
+struct api_context {
+ struct completion done;
+ int status;
+};
+
static void usb_api_blocking_completion(struct urb *urb)
{
- complete((struct completion *)urb->context);
+ struct api_context *ctx = urb->context;
+
+ ctx->status = urb->status;
+ complete(&ctx->done);
}
@@ -32,38 +40,37 @@ static void usb_api_blocking_completion(struct urb *urb)
*/
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
- struct completion done;
+ struct api_context ctx;
unsigned long expire;
- int status;
+ int retval;
- init_completion(&done);
- urb->context = &done;
+ init_completion(&ctx.done);
+ urb->context = &ctx;
urb->actual_length = 0;
- status = usb_submit_urb(urb, GFP_NOIO);
- if (unlikely(status))
+ retval = usb_submit_urb(urb, GFP_NOIO);
+ if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
- if (!wait_for_completion_timeout(&done, expire)) {
+ if (!wait_for_completion_timeout(&ctx.done, expire)) {
+ usb_kill_urb(urb);
+ retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
-
- usb_kill_urb(urb);
- status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
} else
- status = urb->status;
+ retval = ctx.status;
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
- return status;
+ return retval;
}
/*-------------------------------------------------------------------*/
@@ -243,13 +250,15 @@ static void sg_clean (struct usb_sg_request *io)
io->urbs = NULL;
}
if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+ usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+ io->sg, io->nents);
io->dev = NULL;
}
static void sg_complete (struct urb *urb)
{
struct usb_sg_request *io = urb->context;
+ int status = urb->status;
spin_lock (&io->lock);
@@ -265,21 +274,21 @@ static void sg_complete (struct urb *urb)
*/
if (io->status
&& (io->status != -ECONNRESET
- || urb->status != -ECONNRESET)
+ || status != -ECONNRESET)
&& urb->actual_length) {
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
- usb_pipeendpoint (urb->pipe),
- usb_pipein (urb->pipe) ? "in" : "out",
- urb->status, io->status);
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
+ status, io->status);
// BUG ();
}
- if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
- int i, found, status;
+ if (io->status == 0 && status && status != -ECONNRESET) {
+ int i, found, retval;
- io->status = urb->status;
+ io->status = status;
/* the previous urbs, and this one, completed already.
* unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +299,13 @@ static void sg_complete (struct urb *urb)
if (!io->urbs [i] || !io->urbs [i]->dev)
continue;
if (found) {
- status = usb_unlink_urb (io->urbs [i]);
- if (status != -EINPROGRESS
- && status != -ENODEV
- && status != -EBUSY)
+ retval = usb_unlink_urb (io->urbs [i]);
+ if (retval != -EINPROGRESS &&
+ retval != -ENODEV &&
+ retval != -EBUSY)
dev_err (&io->dev->dev,
"%s, unlink --> %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
} else if (urb == io->urbs [i])
found = 1;
}
@@ -371,7 +380,8 @@ int usb_sg_init (
*/
dma = (dev->dev.dma_mask != NULL);
if (dma)
- io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+ io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+ sg, nents);
else
io->entries = nents;
@@ -409,15 +419,22 @@ int usb_sg_init (
* Some systems need to revert to PIO when DMA is temporarily
* unavailable. For their sakes, both transfer_buffer and
* transfer_dma are set when possible. However this can only
- * work on systems without HIGHMEM, since DMA buffers located
- * in high memory are not directly addressable by the CPU for
- * PIO ... so when HIGHMEM is in use, transfer_buffer is NULL
+ * work on systems without:
+ *
+ * - HIGHMEM, since DMA buffers located in high memory are
+ * not directly addressable by the CPU for PIO;
+ *
+ * - IOMMU, since dma_map_sg() is allowed to use an IOMMU to
+ * make virtually discontiguous buffers be "dma-contiguous"
+ * so that PIO and DMA need diferent numbers of URBs.
+ *
+ * So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL
* to prevent stale pointers and to help spot bugs.
*/
if (dma) {
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
-#ifdef CONFIG_HIGHMEM
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_IOMMU)
io->urbs[i]->transfer_buffer = NULL;
#else
io->urbs[i]->transfer_buffer =
@@ -622,12 +639,12 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
memset(buf,0,size); // Make sure we parse really received data
for (i = 0; i < 3; ++i) {
- /* retry on length 0 or stall; some devices are flakey */
+ /* retry on length 0 or error; some devices are flakey */
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(type << 8) + index, 0, buf, size,
USB_CTRL_GET_TIMEOUT);
- if (result == 0 || result == -EPIPE)
+ if (result <= 0 && result != -ETIMEDOUT)
continue;
if (result > 1 && ((u8 *)buf)[1] != type) {
result = -EPROTO;
@@ -998,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
- if (ep && dev->bus)
- usb_hcd_endpoint_disable(dev, ep);
+ if (ep) {
+ ep->enabled = 0;
+ usb_hcd_flush_endpoint(dev, ep);
+ usb_hcd_disable_endpoint(dev, ep);
+ }
}
/**
@@ -1081,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
* Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
* For control endpoints, both the input and output sides are handled.
*/
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
- unsigned int epaddr = ep->desc.bEndpointAddress;
- unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
- int is_control;
+ int epnum = usb_endpoint_num(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ int is_control = usb_endpoint_xfer_control(&ep->desc);
- is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_CONTROL);
- if (usb_endpoint_out(epaddr) || is_control) {
+ if (is_out || is_control) {
usb_settoggle(dev, epnum, 1, 0);
dev->ep_out[epnum] = ep;
}
- if (!usb_endpoint_out(epaddr) || is_control) {
+ if (!is_out || is_control) {
usb_settoggle(dev, epnum, 0, 0);
dev->ep_in[epnum] = ep;
}
+ ep->enabled = 1;
}
/*
@@ -1156,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
struct usb_host_interface *alt;
int ret;
int manual = 0;
+ int changed;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@@ -1195,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
- if (device_is_registered(&iface->dev))
+ changed = (iface->cur_altsetting != alt);
+ if (changed && device_is_registered(&iface->dev))
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface);
@@ -1232,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* (Likewise, EP0 never "halts" on well designed devices.)
*/
usb_enable_interface(dev, iface);
- if (device_is_registered(&iface->dev))
+ if (changed && device_is_registered(&iface->dev))
usb_create_sysfs_intf_files(iface);
return 0;
@@ -1313,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@@ -1324,14 +1344,11 @@ void usb_release_interface(struct device *dev)
}
#ifdef CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
struct usb_interface *intf;
struct usb_host_interface *alt;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -1343,16 +1360,31 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
usb_dev = interface_to_usbdev(intf);
alt = intf->cur_altsetting;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "INTERFACE=%d/%d/%d",
+#ifdef CONFIG_USB_DEVICEFS
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
+ usb_dev->bus->busnum, usb_dev->devnum))
+ return -ENOMEM;
+#endif
+
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
+ if (add_uevent_var(env,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
@@ -1365,14 +1397,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
#else
-static int usb_if_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -1442,6 +1472,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
* channels are available independently; and choosing between open
* standard device protocols (like CDC) or proprietary ones.
*
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
@@ -1463,7 +1496,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL;
int n, nintf;
- if (configuration == -1)
+ if (dev->authorized == 0 || configuration == -1)
configuration = 0;
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index aa21b38a31ce..d42c561c75f1 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -28,42 +28,26 @@
* devices is broken...
*/
static const struct usb_device_id usb_quirk_list[] = {
+ /* CBM - Flash disk */
+ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
- /* Benq S2W 3300U */
- { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp. Perfection 1200 */
- { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp - Perfection 1670 */
- { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Samsung ML-2510 Series printer */
- { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Elsa MicroLink 56k (V.250) */
- { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Ultima Electronics Corp.*/
- { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Umax [hex] Astra 3400U */
- { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* INTEL VALUE SSD */
+ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* M-Systems Flash Disk Pioneers */
+ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
- /* RIM Blackberry */
- { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* SKYMEDI USB_DRIVE */
+ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */
};
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef CONFIG_USB_SUSPEND
- /* disable autosuspend, but allow the user to re-enable it via sysfs */
- udev->autosuspend_disabled = 1;
-#endif
-}
-
static const struct usb_device_id *find_id(struct usb_device *udev)
{
const struct usb_device_id *id = usb_quirk_list;
@@ -90,7 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
- /* do any special quirk handling here if needed */
- if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
- usb_autosuspend_quirk(udev);
+ /* By default, disable autosuspend for all non-hubs */
+#ifdef CONFIG_USB_SUSPEND
+ if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
+ udev->autosuspend_disabled = 1;
+#endif
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d47ae89154a7..b04afd06e502 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
@@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *usb_dev = to_usb_device(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_device *usb_dev = to_usb_device(dev);
+ unsigned val;
+ result = sscanf(buf, "%u\n", &val);
+ if (result != 1)
+ result = -EINVAL;
+ else if (val == 0)
+ result = usb_deauthorize_device(usb_dev);
+ else
+ result = usb_authorize_device(usb_dev);
+ return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+ usb_dev_authorized_show, usb_dev_authorized_store);
+
+
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
&dev_attr_bMaxPower.attr,
+ &dev_attr_urbnum.attr,
/* device attributes */
&dev_attr_idVendor.attr,
&dev_attr_idProduct.attr,
@@ -435,12 +484,61 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
+ &dev_attr_authorized.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct usb_device *udev = to_usb_device(
+ container_of(kobj, struct device, kobj));
+ size_t nleft = count;
+ size_t srclen, n;
+
+ usb_lock_device(udev);
+
+ /* The binary attribute begins with the device descriptor */
+ srclen = sizeof(struct usb_device_descriptor);
+ if (off < srclen) {
+ n = min_t(size_t, nleft, srclen - off);
+ memcpy(buf, off + (char *) &udev->descriptor, n);
+ nleft -= n;
+ buf += n;
+ off = 0;
+ } else {
+ off -= srclen;
+ }
+
+ /* Then follows the raw descriptor entry for the current
+ * configuration (config plus subsidiary descriptors).
+ */
+ if (udev->actconfig) {
+ int cfgno = udev->actconfig - udev->config;
+
+ srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+ if (off < srclen) {
+ n = min_t(size_t, nleft, srclen - off);
+ memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+ nleft -= n;
+ }
+ }
+ usb_unlock_device(udev);
+ return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+ .attr = {.name = "descriptors", .mode = 0444},
+ .read = read_descriptors,
+ .size = 18 + 65535, /* dev descr + max-size raw descriptor */
+};
+
int usb_create_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
@@ -450,6 +548,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
return retval;
+ retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+ if (retval)
+ goto error;
+
retval = add_persist_attributes(dev);
if (retval)
goto error;
@@ -492,6 +594,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
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);
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 52ec44b828f3..c20c03aaf012 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/log2.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
if (urb) {
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
- spin_lock_init(&urb->lock);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
@@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
- int pipe, temp, max;
- struct usb_device *dev;
- int is_out;
+ int xfertype, max;
+ struct usb_device *dev;
+ struct usb_host_endpoint *ep;
+ int is_out;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
- if (!(dev = urb->dev) ||
- (dev->state < USB_STATE_DEFAULT) ||
- (!dev->bus) || (dev->devnum <= 0))
+ if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
return -ENODEV;
- if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
- || dev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
+ /* For now, get the endpoint from the pipe. Eventually drivers
+ * will be required to set urb->ep directly and we will eliminate
+ * urb->pipe.
+ */
+ ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep)
+ return -ENOENT;
+
+ urb->ep = ep;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
- pipe = urb->pipe;
- temp = usb_pipetype(pipe);
- is_out = usb_pipeout(pipe);
+ xfertype = usb_endpoint_type(&ep->desc);
+ if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+ struct usb_ctrlrequest *setup =
+ (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!setup)
+ return -ENOEXEC;
+ is_out = !(setup->bRequestType & USB_DIR_IN) ||
+ !setup->wLength;
+ } else {
+ is_out = usb_endpoint_dir_out(&ep->desc);
+ }
- if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
- return -ENODEV;
+ /* Cache the direction for later use */
+ urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+ (is_out ? URB_DIR_OUT : URB_DIR_IN);
- /* FIXME there should be a sharable lock protecting us against
- * config/altsetting changes and disconnects, kicking in here.
- * (here == before maxpacket, and eventually endpoint type,
- * checks get made.)
- */
+ if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+ dev->state < USB_STATE_CONFIGURED)
+ return -ENODEV;
- max = usb_maxpacket(dev, pipe, is_out);
+ max = le16_to_cpu(ep->desc.wMaxPacketSize);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_pipeendpoint(pipe), is_out ? "out" : "in",
+ usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
- if (temp == PIPE_ISOCHRONOUS) {
+ if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
- URB_NO_INTERRUPT);
- switch (temp) {
- case PIPE_BULK:
+ URB_NO_INTERRUPT | URB_DIR_MASK);
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
- case PIPE_CONTROL:
+ case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
- case PIPE_ISOCHRONOUS:
+ case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
@@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
- switch (temp) {
- case PIPE_ISOCHRONOUS:
- case PIPE_INTERRUPT:
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_ISOC:
+ case USB_ENDPOINT_XFER_INT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
- temp = 1024 * 8;
+ max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
- if (temp == PIPE_INTERRUPT) {
+ if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
- temp = 128;
+ max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
- temp = 1024;
+ max = 1024;
}
break;
default:
return -EINVAL;
}
- /* power of two? */
- while (temp > urb->interval)
- temp >>= 1;
- urb->interval = temp;
+ /* Round down to a power of 2, no more than max */
+ urb->interval = min(max, 1 << ilog2(urb->interval));
}
return usb_hcd_submit_urb(urb, mem_flags);
@@ -440,62 +452,66 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* @urb: pointer to urb describing a previously submitted request,
* may be NULL
*
- * This routine cancels an in-progress request. URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
- *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver. When it is called, the completion
- * function will see urb->status == -ECONNRESET. Failure is indicated
- * by any other return value. Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This routine cancels an in-progress request. URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
+ *
+ * This request is always asynchronous. Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver. When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
*
* Unlinking and Endpoint Queues:
*
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
* Host Controller Drivers (HCDs) place all the URBs for a particular
* endpoint in a queue. Normally the queue advances as the controller
* hardware processes each request. But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns. It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns. Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
- *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
- *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
- *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates. Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets. It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns. It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns. The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
+ *
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO. Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors. Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates. Such queues do not stop when an URB
+ * encounters an error or is unlinked. An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
+ *
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set. By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
+ *
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
*/
int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
- if (!(urb->dev && urb->dev->bus))
+ if (!urb->dev)
return -ENODEV;
+ if (!urb->ep)
+ return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
@@ -521,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
*/
void usb_kill_urb(struct urb *urb)
{
+ static DEFINE_MUTEX(reject_mutex);
+
might_sleep();
- if (!(urb && urb->dev && urb->dev->bus))
+ if (!(urb && urb->dev && urb->ep))
return;
- spin_lock_irq(&urb->lock);
+ mutex_lock(&reject_mutex);
++urb->reject;
- spin_unlock_irq(&urb->lock);
+ mutex_unlock(&reject_mutex);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
- spin_lock_irq(&urb->lock);
+ mutex_lock(&reject_mutex);
--urb->reject;
- spin_unlock_irq(&urb->lock);
+ mutex_unlock(&reject_mutex);
}
/**
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0fee5c66fd64..c99938d5f78e 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
#endif /* CONFIG_PM */
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+ struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+ return hcd->wireless;
+}
+
+
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
+ struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+ unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
+ atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
- dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+ usb_enable_endpoint(dev, &dev->ep0);
+ dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
@@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.parent = bus->controller;
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+ root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
+ if (root_hub) /* Root hub always ok [and always wired] */
+ dev->authorized = 1;
+ else {
+ dev->authorized = usb_hcd->authorized_default;
+ dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+ }
return dev;
}
@@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
@@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
- || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
@@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
// FIXME generic api broken like pci, can't report errors
return dma_map_sg(controller, sg, nents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_sync_sg(controller, sg, n_hw_ents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_unmap_sg(controller, sg, n_hw_ents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index ad5fa0338f49..c52626c51f70 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
+extern void usb_enable_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *ep);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 45e01e289455..f81d08d6538b 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
+config USB_GADGET_DEBUG_FS
+ boolean "Debugging information files in debugfs"
+ depends on USB_GADGET && DEBUG_FS
+ help
+ Some of the drivers in the "gadget" framework can expose
+ debugging information in files under /sys/kernel/debug/.
+ The information in these files may help when you're
+ troubleshooting or bringing up a driver on a new board.
+ Enable these files by choosing "Y" here. If in doubt, or
+ to conserve kernel memory, say "N".
+
config USB_GADGET_SELECTED
boolean
@@ -82,6 +93,41 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
+config USB_GADGET_AMD5536UDC
+ boolean "AMD5536 UDC"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+ It is a USB Highspeed DMA capable USB device controller. Beside ep0
+ it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ The UDC port supports OTG operation, and may be used as a host port
+ if it's not being used to implement peripheral or OTG roles.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "amd5536udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+ tristate
+ depends on USB_GADGET_AMD5536UDC
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_ATMEL_USBA
+ boolean "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+ depends on AVR32
+ help
+ USBA is the integrated high-speed USB Device controller on
+ the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+ tristate
+ depends on USB_GADGET_ATMEL_USBA
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -156,6 +202,24 @@ config USB_PXA2XX_SMALL
default y if USB_ETH
default y if USB_G_SERIAL
+config USB_GADGET_M66592
+ boolean "Renesas M66592 USB Peripheral Controller"
+ select USB_GADGET_DUALSPEED
+ help
+ M66592 is a discrete USB peripheral controller chip that
+ supports both full and high speed USB 2.0 data transfers.
+ It has seven configurable endpoints, and endpoint zero.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "m66592_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_M66592
+ tristate
+ depends on USB_GADGET_M66592
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
@@ -189,7 +253,6 @@ config USB_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
-
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
@@ -261,24 +324,6 @@ config USB_AT91
depends on USB_GADGET_AT91
default USB_GADGET
-config USB_GADGET_M66592
- boolean "M66592 driver"
- select USB_GADGET_DUALSPEED
- help
- M66592 is a USB 2.0 peripheral controller.
-
- It has seven configurable endpoints, and endpoint zero.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "m66592_udc" and force all
- gadget drivers to also be dynamically linked.
-
-config USB_M66592
- tristate
- depends on USB_GADGET_M66592
- default USB_GADGET
- select USB_GADGET_SELECTED
-
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 8ae76f738635..904e57bf6112 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -7,12 +7,14 @@ endif
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_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 000000000000..1c8040602525
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,3451 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde 0 == do not touch RDE, do no start the RDE timer
+ * set_rde 1 == timer function will look whether FIFO has data
+ * set_rde 2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+ (unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+ ep0_string,
+ "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+ "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+ "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+ "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+ "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+ "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+ "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+ "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+ DBG(dev, "------- Device registers -------\n");
+ DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg));
+ DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl));
+ DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts));
+ DBG(dev, "\n");
+ DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts));
+ DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts));
+ DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "USE DMA = %d\n", use_dma);
+ if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBNDU (packet per buffer "
+ "WITHOUT desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+ } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBDU (packet per buffer "
+ "WITH desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+ }
+ if (use_dma && use_dma_bufferfill_mode) {
+ DBG(dev, "DMA mode = BF (buffer fill mode)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+ }
+ if (!use_dma) {
+ dev_info(&dev->pdev->dev, "FIFO mode\n");
+ }
+ DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ /* mask all dev interrupts */
+ tmp = AMD_BIT(UDC_DEVINT_SVC) |
+ AMD_BIT(UDC_DEVINT_ENUM) |
+ AMD_BIT(UDC_DEVINT_US) |
+ AMD_BIT(UDC_DEVINT_UR) |
+ AMD_BIT(UDC_DEVINT_ES) |
+ AMD_BIT(UDC_DEVINT_SI) |
+ AMD_BIT(UDC_DEVINT_SOF)|
+ AMD_BIT(UDC_DEVINT_SC);
+ writel(tmp, &dev->regs->irqmsk);
+
+ /* mask all ep interrupts */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ /* enable ep0 irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+ & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "enable device interrupts for setup data\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->irqmsk);
+
+ /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+ writel(tmp, &dev->regs->irqmsk);
+
+ return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+ struct udc *dev;
+ u32 tmp;
+ int i;
+
+ if (!ep || !(ep->in))
+ return -EINVAL;
+
+ dev = ep->dev;
+ ep->txfifo = dev->txfifo;
+
+ /* traverse ep's */
+ for (i = 0; i < ep->num; i++) {
+ if (dev->ep[i].regs) {
+ /* read fifo size */
+ tmp = readl(&dev->ep[i].regs->bufin_framenum);
+ tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+ ep->txfifo += tmp;
+ }
+ }
+ return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+ if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+ DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+ cnak_pending |= 1 << (num);
+ ep->naking = 1;
+ } else
+ cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+ struct udc_ep *ep;
+ struct udc *dev;
+ u32 tmp;
+ unsigned long iflags;
+ u8 udc_csr_epix;
+
+ if (!usbep
+ || usbep->name == ep0_string
+ || !desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ dev = ep->dev;
+
+ DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ ep->desc = desc;
+
+ ep->halted = 0;
+
+ /* set traffic type */
+ tmp = readl(&dev->ep[ep->num].regs->ctl);
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+ writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+ /* set max packet size */
+ tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+ ep->ep.maxpacket = desc->wMaxPacketSize;
+ writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+ /* IN ep */
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+ /* set buffer size (tx fifo entries) */
+ tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+ /* double buffering: fifo size = 2 x max packet size */
+ tmp = AMD_ADDBITS(
+ tmp,
+ desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+ / UDC_DWORD_BYTES,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+ /* calc. tx fifo base addr */
+ udc_set_txfifo_addr(ep);
+
+ /* flush fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+ /* set max packet size UDC CSR */
+ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+ if (use_dma && !ep->in) {
+ /* alloc and init BNA dummy request */
+ ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+ ep->bna_occurred = 0;
+ }
+
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_enabled = 1;
+ }
+
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* max packet */
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ /* ep number */
+ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+ /* ep direction */
+ tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+ /* ep type */
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+ /* ep config */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ /*
+ * clear NAK by writing CNAK
+ * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+ */
+ if (!use_dma || ep->in) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ tmp = desc->bEndpointAddress;
+ DBG(dev, "%s enabled\n", usbep->name);
+
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+ u32 tmp;
+
+ VDBG(ep->dev, "ep-%d reset\n", ep->num);
+ ep->desc = NULL;
+ ep->ep.ops = &udc_ep_ops;
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->ep.maxpacket = (u16) ~0;
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+
+ /* disable interrupt */
+ tmp = readl(&regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp, &regs->ep_irqmsk);
+
+ if (ep->in) {
+ /* unset P and IN bit of potential former DMA */
+ tmp = readl(&ep->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+
+ tmp = readl(&ep->regs->sts);
+ tmp |= AMD_BIT(UDC_EPSTS_IN);
+ writel(tmp, &ep->regs->sts);
+
+ /* flush the fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ }
+ /* reset desc pointer */
+ writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+ struct udc_ep *ep = NULL;
+ unsigned long iflags;
+
+ if (!usbep)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (usbep->name == ep0_string || !ep->desc)
+ return -EINVAL;
+
+ DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+ empty_req_queue(ep);
+ ep_init(ep->dev->regs, ep);
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+ return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+ struct udc_request *req;
+ struct udc_data_dma *dma_desc;
+ struct udc_ep *ep;
+
+ if (!usbep)
+ return NULL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+
+ VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+ req = kzalloc(sizeof(struct udc_request), gfp);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_DONT_USE;
+ INIT_LIST_HEAD(&req->queue);
+
+ if (ep->dma) {
+ /* ep0 in requests are allocated from data pool here */
+ dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+ &req->td_phys);
+ if (!dma_desc) {
+ kfree(req);
+ return NULL;
+ }
+
+ VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+ "td_phys = %lx\n",
+ req, dma_desc,
+ (unsigned long)req->td_phys);
+ /* prevent from using desc. - set HOST BUSY */
+ dma_desc->status = AMD_ADDBITS(dma_desc->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+ req->td_data = dma_desc;
+ req->td_data_last = NULL;
+ req->chain_len = 1;
+ }
+
+ return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+
+ if (!usbep || !usbreq)
+ return;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ req = container_of(usbreq, struct udc_request, req);
+ VDBG(ep->dev, "free_req req=%p\n", req);
+ BUG_ON(!list_empty(&req->queue));
+ if (req->td_data) {
+ VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+ /* free dma chain if created */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+
+ pci_pool_free(ep->dev->data_requests, req->td_data,
+ req->td_phys);
+ }
+ kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+ if (req) {
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* set next pointer to itself */
+ req->td_data->next = req->td_phys;
+ /* set HOST BUSY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_DMA_DONE,
+ UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+ pr_debug("bna desc = %p, sts = %08x\n",
+ req->td_data, req->td_data->status);
+#endif
+ }
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+ struct udc_request *req = NULL;
+ struct usb_request *_req = NULL;
+
+ /* alloc the dummy request */
+ _req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+ if (_req) {
+ req = container_of(_req, struct udc_request, req);
+ ep->bna_dummy_req = req;
+ udc_init_bna_dummy(req);
+ }
+ return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+ u8 *req_buf;
+ u32 *buf;
+ int i, j;
+ unsigned bytes = 0;
+ unsigned remaining = 0;
+
+ if (!req || !ep)
+ return;
+
+ req_buf = req->buf + req->actual;
+ prefetch(req_buf);
+ remaining = req->length - req->actual;
+
+ buf = (u32 *) req_buf;
+
+ bytes = ep->ep.maxpacket;
+ if (bytes > remaining)
+ bytes = remaining;
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ writel(*(buf + i), ep->txfifo);
+ }
+
+ /* remaining bytes must be written by byte access */
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+ ep->txfifo);
+ }
+
+ /* dummy write confirm */
+ writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+ int i;
+
+ VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+ for (i = 0; i < dwords; i++) {
+ *(buf + i) = readl(dev->rxfifo);
+ }
+ return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+ int i, j;
+ u32 tmp;
+
+ VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+ }
+
+ /* remaining bytes must be read by byte access */
+ if (bytes % UDC_DWORD_BYTES) {
+ tmp = readl(dev->rxfifo);
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+ tmp = tmp >> UDC_BITS_PER_BYTE;
+ }
+ }
+
+ return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+ u8 *buf;
+ unsigned buf_space;
+ unsigned bytes = 0;
+ unsigned finished = 0;
+
+ /* received number bytes */
+ bytes = readl(&ep->regs->sts);
+ bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+ buf_space = req->req.length - req->req.actual;
+ buf = req->req.buf + req->req.actual;
+ if (bytes > buf_space) {
+ if ((buf_space % ep->ep.maxpacket) != 0) {
+ DBG(ep->dev,
+ "%s: rx %d bytes, rx-buf space = %d bytesn\n",
+ ep->ep.name, bytes, buf_space);
+ req->req.status = -EOVERFLOW;
+ }
+ bytes = buf_space;
+ }
+ req->req.actual += bytes;
+
+ /* last packet ? */
+ if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+ || ((req->req.actual == req->req.length) && !req->req.zero))
+ finished = 1;
+
+ /* read rx fifo bytes */
+ VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+ udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+ return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+ int retval = 0;
+ u32 tmp;
+
+ VDBG(ep->dev, "prep_dma\n");
+ VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+ ep->num, req->td_data);
+
+ /* set buffer pointer */
+ req->td_data->bufptr = req->req.dma;
+
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+ /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+ if (use_dma_ppb) {
+
+ retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+ if (retval != 0) {
+ if (retval == -ENOMEM)
+ DBG(ep->dev, "Out of DMA memory\n");
+ return retval;
+ }
+ if (ep->in) {
+ if (req->req.length == ep->ep.maxpacket) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+
+ }
+ }
+
+ }
+
+ if (ep->in) {
+ VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+ "maxpacket=%d ep%d\n",
+ use_dma_ppb, req->req.length,
+ ep->ep.maxpacket, ep->num);
+ /*
+ * if bytes < max packet then tx bytes must
+ * be written in packet per buffer mode
+ */
+ if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+ || ep->num == UDC_EP0OUT_IX
+ || ep->num == UDC_EP0IN_IX) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ req->req.length,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* reset frame num */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ 0,
+ UDC_DMA_IN_STS_FRAMENUM);
+ }
+ /* set HOST BUSY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ } else {
+ VDBG(ep->dev, "OUT set host ready\n");
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ }
+
+ return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+ struct udc *dev;
+ unsigned halted;
+
+ VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+ dev = ep->dev;
+ /* unmap DMA */
+ if (req->dma_mapping) {
+ if (ep->in)
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 0;
+ req->req.dma = DMA_DONT_USE;
+ }
+
+ halted = ep->halted;
+ ep->halted = 1;
+
+ /* set new status if pending */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = sts;
+
+ /* remove from ep queue */
+ list_del_init(&req->queue);
+
+ VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+ &req->req, req->req.length, ep->ep.name, sts);
+
+ spin_unlock(&dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dev->lock);
+ ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+ int ret_val = 0;
+ struct udc_data_dma *td;
+ struct udc_data_dma *td_last = NULL;
+ unsigned int i;
+
+ DBG(dev, "free chain req = %p\n", req);
+
+ /* do not free first desc., will be done by free for request */
+ td_last = req->td_data;
+ td = phys_to_virt(td_last->next);
+
+ for (i = 1; i < req->chain_len; i++) {
+
+ pci_pool_free(dev->data_requests, td,
+ (dma_addr_t) td_last->next);
+ td_last = td;
+ td = phys_to_virt(td_last->next);
+ }
+
+ return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+
+ td = req->td_data;
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ }
+
+ return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+ u32 count;
+
+ td = req->td_data;
+ /* received number bytes */
+ count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ /* received number bytes */
+ if (td) {
+ count += AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ }
+ }
+
+ return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+ struct udc_ep *ep,
+ struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags
+)
+{
+ unsigned long bytes = req->req.length;
+ unsigned int i;
+ dma_addr_t dma_addr;
+ struct udc_data_dma *td = NULL;
+ struct udc_data_dma *last = NULL;
+ unsigned long txbytes;
+ unsigned create_new_chain = 0;
+ unsigned len;
+
+ VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+ bytes, buf_len);
+ dma_addr = DMA_DONT_USE;
+
+ /* unset L bit in first desc for OUT */
+ if (!ep->in) {
+ req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+ }
+
+ /* alloc only new desc's if not already available */
+ len = req->req.length / ep->ep.maxpacket;
+ if (req->req.length % ep->ep.maxpacket) {
+ len++;
+ }
+
+ if (len > req->chain_len) {
+ /* shorter chain already allocated before */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+ req->chain_len = len;
+ create_new_chain = 1;
+ }
+
+ td = req->td_data;
+ /* gen. required number of descriptors and buffers */
+ for (i = buf_len; i < bytes; i += buf_len) {
+ /* create or determine next desc. */
+ if (create_new_chain) {
+
+ td = pci_pool_alloc(ep->dev->data_requests,
+ gfp_flags, &dma_addr);
+ if (!td)
+ return -ENOMEM;
+
+ td->status = 0;
+ } else if (i == buf_len) {
+ /* first td */
+ td = (struct udc_data_dma *) phys_to_virt(
+ req->td_data->next);
+ td->status = 0;
+ } else {
+ td = (struct udc_data_dma *) phys_to_virt(last->next);
+ td->status = 0;
+ }
+
+
+ if (td)
+ td->bufptr = req->req.dma + i; /* assign buffer */
+ else
+ break;
+
+ /* short packet ? */
+ if ((bytes - i) >= buf_len) {
+ txbytes = buf_len;
+ } else {
+ /* short packet */
+ txbytes = bytes - i;
+ }
+
+ /* link td and assign tx bytes */
+ if (i == buf_len) {
+ if (create_new_chain) {
+ req->td_data->next = dma_addr;
+ } else {
+ /* req->td_data->next = virt_to_phys(td); */
+ }
+ /* write tx bytes */
+ if (ep->in) {
+ /* first desc */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* second desc */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ } else {
+ if (create_new_chain) {
+ last->next = dma_addr;
+ } else {
+ /* last->next = virt_to_phys(td); */
+ }
+ if (ep->in) {
+ /* write tx bytes */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ }
+ last = td;
+ }
+ /* set last bit */
+ if (td) {
+ td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* last desc. points to itself */
+ req->td_data_last = td;
+ }
+
+ return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+ u32 tmp;
+
+ VDBG(dev, "udc_set_rde()\n");
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* set RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+ int retval = 0;
+ u8 open_rxfifo = 0;
+ unsigned long iflags;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc *dev;
+ u32 tmp;
+
+ /* check the inputs */
+ req = container_of(usbreq, struct udc_request, req);
+
+ if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+ || !list_empty(&req->queue))
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+
+ VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+ dev = ep->dev;
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* map dma (usually done before) */
+ if (ep->dma && usbreq->length != 0
+ && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+ VDBG(dev, "DMA map req %p\n", req);
+ if (ep->in)
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_TODEVICE);
+ else
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 1;
+ }
+
+ VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+ usbep->name, usbreq, usbreq->length,
+ req->td_data, usbreq->buf);
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ usbreq->actual = 0;
+ usbreq->status = -EINPROGRESS;
+ req->dma_done = 0;
+
+ /* on empty queue just do first transfer */
+ if (list_empty(&ep->queue)) {
+ /* zlp */
+ if (usbreq->length == 0) {
+ /* IN zlp's are handled by hardware */
+ complete_req(ep, req, 0);
+ VDBG(dev, "%s: zlp\n", ep->ep.name);
+ /*
+ * if set_config or set_intf is waiting for ack by zlp
+ * then set CSR_DONE
+ */
+ if (dev->set_cfg_not_acked) {
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+ writel(tmp, &dev->regs->ctl);
+ dev->set_cfg_not_acked = 0;
+ }
+ /* setup command is ACK'ed now by zlp */
+ if (dev->waiting_zlp_ack_ep0in) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+ UDC_EP0IN_IX);
+ dev->waiting_zlp_ack_ep0in = 0;
+ }
+ goto finished;
+ }
+ if (ep->dma) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ /* write desc pointer to enable DMA */
+ if (ep->in) {
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+ }
+
+ /* disabled rx dma while descriptor update */
+ if (!ep->in) {
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* clear RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+ open_rxfifo = 1;
+
+ /*
+ * if BNA occurred then let BNA dummy desc.
+ * point to current desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "copy to BNA dummy desc.\n");
+ memcpy(ep->bna_dummy_req->td_data,
+ req->td_data,
+ sizeof(struct udc_data_dma));
+ }
+ }
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
+ }
+
+ } else if (ep->dma) {
+
+ /*
+ * prep_dma not used for OUT ep's, this is not possible
+ * for PPB modes, because of chain creation reasons
+ */
+ if (ep->in) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ }
+ }
+ VDBG(dev, "list_add\n");
+ /* add request to ep queue */
+ if (req) {
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ /* open rxfifo if out data queued */
+ if (open_rxfifo) {
+ /* enable DMA */
+ req->dma_going = 1;
+ udc_set_rde(dev);
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 1;
+ }
+ /* stop OUT naking */
+ if (!ep->in) {
+ if (!use_dma && udc_rxfifo_pending) {
+ DBG(dev, "udc_queue(): pending bytes in"
+ "rxfifo after nyet\n");
+ /*
+ * read pending bytes afer nyet:
+ * referring to isr
+ */
+ if (udc_rxfifo_read(ep, req)) {
+ /* finish */
+ complete_req(ep, req, 0);
+ }
+ udc_rxfifo_pending = 0;
+
+ }
+ }
+ }
+
+finished:
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+ struct udc_request *req;
+
+ ep->halted = 1;
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ complete_req(ep, req, -ESHUTDOWN);
+ }
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned halted;
+ unsigned long iflags;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+ && ep->num != UDC_EP0OUT_IX)))
+ return -EINVAL;
+
+ req = container_of(usbreq, struct udc_request, req);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ halted = ep->halted;
+ ep->halted = 1;
+ /* request in processing or next one */
+ if (ep->queue.next == &req->queue) {
+ if (ep->dma && req->dma_going) {
+ if (ep->in)
+ ep->cancel_transfer = 1;
+ else {
+ u32 tmp;
+ u32 dma_sts;
+ /* stop potential receive DMA */
+ tmp = readl(&udc->regs->ctl);
+ writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+ &udc->regs->ctl);
+ /*
+ * Cancel transfer later in ISR
+ * if descriptor was touched.
+ */
+ dma_sts = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+ ep->cancel_transfer = 1;
+ else {
+ udc_init_bna_dummy(ep->req);
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ }
+ writel(tmp, &udc->regs->ctl);
+ }
+ }
+ }
+ complete_req(ep, req, -ECONNRESET);
+ ep->halted = halted;
+
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+ return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ unsigned long iflags;
+ int retval = 0;
+
+ if (!usbep)
+ return -EINVAL;
+
+ pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&udc_stall_spinlock, iflags);
+ /* halt or clear halt */
+ if (halt) {
+ if (ep->num == 0)
+ ep->dev->stall_ep0in = 1;
+ else {
+ /*
+ * set STALL
+ * rxfifo empty not taken into acount
+ */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 1;
+
+ /* setup poll timer */
+ if (!timer_pending(&udc_pollstall_timer)) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ if (!stop_pollstall_timer) {
+ DBG(ep->dev, "start polltimer\n");
+ add_timer(&udc_pollstall_timer);
+ }
+ }
+ }
+ } else {
+ /* ep is halted by set_halt() before */
+ if (ep->halted) {
+ tmp = readl(&ep->regs->ctl);
+ /* clear stall bit */
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+ spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+ return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+ .enable = udc_ep_enable,
+ .disable = udc_ep_disable,
+
+ .alloc_request = udc_alloc_request,
+ .free_request = udc_free_request,
+
+ .queue = udc_queue,
+ .dequeue = udc_dequeue,
+
+ .set_halt = udc_set_halt,
+ /* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+ return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+ struct udc *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct udc, gadget);
+ udc_remote_wakeup(dev);
+
+ return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+ .wakeup = udc_wakeup,
+ .get_frame = udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+ /* make gadget ep lists */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+
+ /* fifo config */
+ dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+ dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+ u32 tmp;
+
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+
+ /* program speed */
+ tmp = readl(&dev->regs->cfg);
+ if (use_fullspeed) {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ } else {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+ }
+ writel(tmp, &dev->regs->cfg);
+
+ return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_basic_init()\n");
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop poll stall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* disable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+ writel(tmp, &dev->regs->ctl);
+
+ /* enable dynamic CSR programming */
+ tmp = readl(&dev->regs->cfg);
+ tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+ /* set self powered */
+ tmp |= AMD_BIT(UDC_DEVCFG_SP);
+ /* set remote wakeupable */
+ tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+ writel(tmp, &dev->regs->cfg);
+
+ make_ep_lists(dev);
+
+ dev->data_ep_enabled = 0;
+ dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ u32 reg;
+
+ DBG(dev, "udc_setup_endpoints()\n");
+
+ /* read enum speed */
+ tmp = readl(&dev->regs->sts);
+ tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+ if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+ dev->gadget.speed = USB_SPEED_HIGH;
+ } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+ dev->gadget.speed = USB_SPEED_FULL;
+ }
+
+ /* set basic ep parameters */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ ep = &dev->ep[tmp];
+ ep->dev = dev;
+ ep->ep.name = ep_string[tmp];
+ ep->num = tmp;
+ /* txfifo size is calculated at enable time */
+ ep->txfifo = dev->txfifo;
+
+ /* fifo size */
+ if (tmp < UDC_EPIN_NUM) {
+ ep->fifo_depth = UDC_TXFIFO_SIZE;
+ ep->in = 1;
+ } else {
+ ep->fifo_depth = UDC_RXFIFO_SIZE;
+ ep->in = 0;
+
+ }
+ ep->regs = &dev->ep_regs[tmp];
+ /*
+ * ep will be reset only if ep was not enabled before to avoid
+ * disabling ep interrupts when ENUM interrupt occurs but ep is
+ * not enabled by gadget driver
+ */
+ if (!ep->desc) {
+ ep_init(dev->regs, ep);
+ }
+
+ if (use_dma) {
+ /*
+ * ep->dma is not really used, just to indicate that
+ * DMA is active: remove this
+ * dma regs = dev control regs
+ */
+ ep->dma = &dev->regs->ctl;
+
+ /* nak OUT endpoints until enable - not for ep0 */
+ if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+ && tmp > UDC_EPIN_NUM) {
+ /* set NAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 1;
+
+ }
+ }
+ }
+ /* EP0 max packet */
+ if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+ UDC_FS_EP0OUT_MAX_PKT_SIZE;
+ } else if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+ }
+
+ /*
+ * with suspend bug workaround, ep0 params for gadget driver
+ * are set at gadget driver bind() call
+ */
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ dev->ep[UDC_EP0IN_IX].halted = 0;
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+ /* init cfg/alt/int */
+ dev->cur_config = 0;
+ dev->cur_intf = 0;
+ dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Connect\n");
+
+ dev->connected = 1;
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+ dev->connected = 0;
+
+ /* mask interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* REVISIT there doesn't seem to be a point to having this
+ * talk to a tasklet ... do it directly, we already hold
+ * the spinlock needed to process the disconnect.
+ */
+
+ tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+ struct udc *dev = (struct udc *)(*((struct udc **) par));
+ u32 tmp;
+
+ DBG(dev, "Tasklet disconnect\n");
+ spin_lock_irq(&dev->lock);
+
+ if (dev->driver) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* empty queues */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ }
+
+ /* disable ep0 */
+ ep_init(dev->regs,
+ &dev->ep[UDC_EP0IN_IX]);
+
+
+ if (!soft_reset_occured) {
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+ soft_reset_occured++;
+ }
+
+ /* re-enable dev interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+ /* back to full speed ? */
+ if (use_fullspeed) {
+ tmp = readl(&dev->regs->cfg);
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ writel(tmp, &dev->regs->cfg);
+ }
+
+ spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+ unsigned long flags;
+
+ DBG(dev, "Soft reset\n");
+ /*
+ * reset possible waiting interrupts, because int.
+ * status is lost after soft reset,
+ * ep int. status reset
+ */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+ /* device int. status reset */
+ writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+ spin_lock_irqsave(&udc_irq_spinlock, flags);
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ readl(&dev->regs->cfg);
+ spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+ u32 tmp;
+
+ spin_lock_irq(&udc_irq_spinlock);
+
+ if (set_rde > 0) {
+ /*
+ * open the fifo if fifo was filled on last timer call
+ * conditionally
+ */
+ if (set_rde > 1) {
+ /* set RDE to receive setup data */
+ tmp = readl(&udc->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &udc->regs->ctl);
+ set_rde = -1;
+ } else if (readl(&udc->regs->sts)
+ & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ /*
+ * if fifo empty setup polling, do not just
+ * open the fifo
+ */
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ } else {
+ /*
+ * fifo contains data now, setup timer for opening
+ * the fifo when timer expires to be able to receive
+ * setup packets, when data packets gets queued by
+ * gadget layer then timer will forced to expire with
+ * set_rde=0 (RDE is set in udc_queue())
+ */
+ set_rde++;
+ /* debug: lhadmot_timer_start = 221070 */
+ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+
+ } else
+ set_rde = -1; /* RDE was set by udc_queue() */
+ spin_unlock_irq(&udc_irq_spinlock);
+ if (stop_timer)
+ complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+ u32 tmp;
+ /* set stall as long not halted */
+ if (ep->halted == 1) {
+ tmp = readl(&ep->regs->ctl);
+ /* STALL cleared ? */
+ if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+ /*
+ * FIXME: MSC spec requires that stall remains
+ * even on receivng of CLEAR_FEATURE HALT. So
+ * we would set STALL again here to be compliant.
+ * But with current mass storage drivers this does
+ * not work (would produce endless host retries).
+ * So we clear halt on CLEAR_FEATURE.
+ *
+ DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);*/
+
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+ struct udc_ep *ep;
+ int halted = 0;
+
+ spin_lock_irq(&udc_stall_spinlock);
+ /*
+ * only one IN and OUT endpoints are handled
+ * IN poll stall
+ */
+ ep = &udc->ep[UDC_EPIN_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+ /* OUT poll stall */
+ ep = &udc->ep[UDC_EPOUT_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+
+ /* setup timer again when still halted */
+ if (!stop_pollstall_timer && halted) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ add_timer(&udc_pollstall_timer);
+ }
+ spin_unlock_irq(&udc_stall_spinlock);
+
+ if (stop_pollstall_timer)
+ complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "activate_control_endpoints\n");
+
+ /* flush fifo */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* set ep0 directions */
+ dev->ep[UDC_EP0IN_IX].in = 1;
+ dev->ep[UDC_EP0OUT_IX].in = 0;
+
+ /* set buffer size (tx fifo entries) of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+ /* set max packet size of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0_OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0 in UDC CSR */
+ tmp = readl(&dev->csr->ne[0]);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[0]);
+
+ if (use_dma) {
+ dev->ep[UDC_EP0OUT_IX].td->status |=
+ AMD_BIT(UDC_DMA_OUT_STS_L);
+ /* write dma desc address */
+ writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+ &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop pollstall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* enable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+ | AMD_BIT(UDC_DEVCTL_RDE)
+ | AMD_BIT(UDC_DEVCTL_TDE);
+ if (use_dma_bufferfill_mode) {
+ tmp |= AMD_BIT(UDC_DEVCTL_BF);
+ } else if (use_dma_ppb_du) {
+ tmp |= AMD_BIT(UDC_DEVCTL_DU);
+ }
+ writel(tmp, &dev->regs->ctl);
+ }
+
+ /* clear NAK by writing CNAK for EP0IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* clear NAK by writing CNAK for EP0OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+ activate_control_endpoints(dev);
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ int retval;
+ u32 tmp;
+
+ if (!driver || !driver->bind || !driver->setup
+ || driver->speed != USB_SPEED_HIGH)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ driver->driver.bus = NULL;
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+
+ retval = driver->bind(&dev->gadget);
+
+ /* Some gadget drivers use both ep0 directions.
+ * NOTE: to gadget driver, ep0 is just one endpoint...
+ */
+ dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+ dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+ if (retval) {
+ DBG(dev, "binding to %s returning %d\n",
+ driver->driver.name, retval);
+ dev->driver = NULL;
+ dev->gadget.dev.driver = NULL;
+ return retval;
+ }
+
+ /* get ready for ep0 traffic */
+ setup_ep0(dev);
+
+ /* clear SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+ usb_connect(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ int tmp;
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ /* init */
+ udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ unsigned long flags;
+ u32 tmp;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ udc_mask_unused_interrupts(dev);
+ shutdown(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ driver->unbind(&dev->gadget);
+ dev->driver = NULL;
+
+ /* set SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+
+ DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+ u32 tmp;
+ u32 reg;
+
+ /* check epin's */
+ DBG(dev, "CNAK pending queue processing\n");
+ for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+ if (cnak_pending & (1 << tmp)) {
+ DBG(dev, "CNAK pending for ep%d\n", tmp);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+ }
+ }
+ /* ... and ep0out */
+ if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+ DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+ dev->ep[UDC_EP0OUT_IX].num);
+ }
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+ if (use_dma) {
+ /*
+ * only enable RXDMA when no data endpoint enabled
+ * or data is queued
+ */
+ if (!dev->data_ep_enabled || dev->data_ep_queued) {
+ udc_set_rde(dev);
+ } else {
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data endpoints to early)
+ */
+ if (set_rde != 0 && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies + HZ/UDC_RDE_TIMER_DIV;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+ }
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned int count;
+ struct udc_data_dma *td = NULL;
+ unsigned dma_done;
+
+ VDBG(dev, "ep%d irq\n", ep_ix);
+ ep = &dev->ep[ep_ix];
+
+ tmp = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+ ep->num, readl(&ep->regs->desptr));
+ /* clear BNA */
+ writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+ if (!ep->cancel_transfer)
+ ep->bna_occurred = 1;
+ else
+ ep->cancel_transfer = 0;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+ /* clear HE */
+ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ if (!list_empty(&ep->queue)) {
+
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else {
+ req = NULL;
+ udc_rxfifo_pending = 1;
+ }
+ VDBG(dev, "req = %p\n", req);
+ /* fifo mode */
+ if (!use_dma) {
+
+ /* read fifo */
+ if (req && udc_rxfifo_read(ep, req)) {
+ ret_val = IRQ_HANDLED;
+
+ /* finish */
+ complete_req(ep, req, 0);
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else
+ req = NULL;
+ }
+
+ /* DMA */
+ } else if (!ep->cancel_transfer && req != NULL) {
+ ret_val = IRQ_HANDLED;
+
+ /* check for DMA done */
+ if (!use_dma_ppb) {
+ dma_done = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ /*
+ * if BNA occurred then recover desc. from
+ * BNA dummy desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "Recover desc. from BNA dummy\n");
+ memcpy(req->td_data, ep->bna_dummy_req->td_data,
+ sizeof(struct udc_data_dma));
+ ep->bna_occurred = 0;
+ udc_init_bna_dummy(ep->req);
+ }
+ td = udc_get_last_dma_desc(req);
+ dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+ }
+ if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+ /* buffer fill mode - rx bytes */
+ if (!use_dma_ppb) {
+ /* received number bytes */
+ count = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ VDBG(dev, "rx bytes=%u\n", count);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ VDBG(dev, "req->td_data=%p\n", req->td_data);
+ VDBG(dev, "last desc = %p\n", td);
+ /* received number bytes */
+ if (use_dma_ppb_du) {
+ /* every desc. counts bytes */
+ count = udc_get_ppbdu_rxbytes(req);
+ } else {
+ /* last desc. counts bytes */
+ count = AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ if (!count && req->req.length
+ == UDC_DMA_MAXPACKET) {
+ /*
+ * on 64k packets the RXBYTES
+ * field is zero
+ */
+ count = UDC_DMA_MAXPACKET;
+ }
+ }
+ VDBG(dev, "last desc rx bytes=%u\n", count);
+ }
+
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ if ((tmp % ep->ep.maxpacket) != 0) {
+ DBG(dev, "%s: rx %db, space=%db\n",
+ ep->ep.name, count, tmp);
+ req->req.status = -EOVERFLOW;
+ }
+ count = tmp;
+ }
+ req->req.actual += count;
+ req->dma_going = 0;
+ /* complete request */
+ complete_req(ep, req, 0);
+
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ /*
+ * DMA may be already started by udc_queue()
+ * called by gadget drivers completion
+ * routine. This happens when queue
+ * holds one request only.
+ */
+ if (req->dma_going == 0) {
+ /* next dma */
+ if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+ goto finished;
+ /* write desc pointer */
+ writel(req->td_phys,
+ &ep->regs->desptr);
+ req->dma_going = 1;
+ /* enable DMA */
+ udc_set_rde(dev);
+ }
+ } else {
+ /*
+ * implant BNA dummy descriptor to allow
+ * RXFIFO opening by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ /*
+ * schedule timer for setting RDE if queue
+ * remains empty to allow ep0 packets pass
+ * through
+ */
+ if (set_rde != 0
+ && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies
+ + HZ*UDC_RDE_TIMER_SECONDS;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 0;
+ }
+
+ } else {
+ /*
+ * RX DMA must be reenabled for each desc in PPBDU mode
+ * and must be enabled for PPBNDU mode in case of BNA
+ */
+ udc_set_rde(dev);
+ }
+
+ } else if (ep->cancel_transfer) {
+ ret_val = IRQ_HANDLED;
+ ep->cancel_transfer = 0;
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 epsts;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc_data_dma *td;
+ unsigned dma_done;
+ unsigned len;
+
+ ep = &dev->ep[ep_ix];
+
+ epsts = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+ dev_err(&dev->pdev->dev,
+ "BNA ep%din occured - DESPTR = %08lx \n",
+ ep->num,
+ (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear BNA */
+ writel(epsts, &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev,
+ "HE ep%dn occured - DESPTR = %08lx \n",
+ ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear HE */
+ writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* DMA completion */
+ if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "TDC set- completion\n");
+ ret_val = IRQ_HANDLED;
+ if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ if (req) {
+ /*
+ * length bytes transfered
+ * check dma done of last desc. in PPBDU mode
+ */
+ if (use_dma_ppb_du) {
+ td = udc_get_last_dma_desc(req);
+ if (td) {
+ dma_done =
+ AMD_GETBITS(td->status,
+ UDC_DMA_IN_STS_BS);
+ /* don't care DMA done */
+ req->req.actual =
+ req->req.length;
+ }
+ } else {
+ /* assume all bytes transferred */
+ req->req.actual = req->req.length;
+ }
+
+ if (req->req.actual == req->req.length) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ req->dma_going = 0;
+ /* further request available ? */
+ if (list_empty(&ep->queue)) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
+ }
+
+ }
+ }
+ }
+ ep->cancel_transfer = 0;
+
+ }
+ /*
+ * status reg has IN bit set and TDC not set (if TDC was handled,
+ * IN must not be handled (UDC defect) ?
+ */
+ if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+ && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+ ret_val = IRQ_HANDLED;
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ /* FIFO mode */
+ if (!use_dma) {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ /* DMA */
+ } else if (req && !req->dma_going) {
+ VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+ req, req->td_data);
+ if (req->td_data) {
+
+ req->dma_going = 1;
+
+ /*
+ * unset L bit of first desc.
+ * for chain
+ */
+ if (use_dma_ppb && req->req.length >
+ ep->ep.maxpacket) {
+ req->td_data->status &=
+ AMD_CLEAR_BIT(
+ UDC_DMA_IN_STS_L);
+ }
+
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+
+ /* set poll demand bit */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+ }
+ }
+
+ }
+ }
+ /* clear status bits */
+ writel(epsts, &ep->regs->sts);
+
+finished:
+ return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ int setup_supported;
+ u32 count;
+ int set = 0;
+ struct udc_ep *ep;
+ struct udc_ep *ep_tmp;
+
+ ep = &dev->ep[UDC_EP0OUT_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ /* check BNA and clear if set */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ VDBG(dev, "ep0: BNA set\n");
+ writel(AMD_BIT(UDC_EPSTS_BNA),
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ ep->bna_occurred = 1;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* type of data: SETUP or DATA 0 bytes */
+ tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+ VDBG(dev, "data_typ = %x\n", tmp);
+
+ /* setup data */
+ if (tmp == UDC_EPSTS_OUT_SETUP) {
+ ret_val = IRQ_HANDLED;
+
+ ep->dev->stall_ep0in = 0;
+ dev->waiting_zlp_ack_ep0in = 0;
+
+ /* set NAK for EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 1;
+ /* get setup data */
+ if (use_dma) {
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ setup_data.data[0] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+ setup_data.data[1] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td_stp->status =
+ UDC_DMA_STP_STS_BS_HOST_READY;
+ } else {
+ /* read fifo */
+ udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+ }
+
+ /* determine direction of control data */
+ if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ set = 0;
+ } else {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+ /*
+ * implant BNA dummy descriptor to allow RXFIFO opening
+ * by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ set = 1;
+ dev->ep[UDC_EP0OUT_IX].naking = 1;
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data to early)
+ */
+ set_rde = 1;
+ if (!timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies +
+ HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+
+ /*
+ * mass storage reset must be processed here because
+ * next packet may be a CLEAR_FEATURE HALT which would not
+ * clear the stall bit when no STALL handshake was received
+ * before (autostall can cause this)
+ */
+ if (setup_data.data[0] == UDC_MSCRES_DWORD0
+ && setup_data.data[1] == UDC_MSCRES_DWORD1) {
+ DBG(dev, "MSC Reset\n");
+ /*
+ * clear stall bits
+ * only one IN and OUT endpoints are handled
+ */
+ ep_tmp = &udc->ep[UDC_EPIN_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ ep_tmp = &udc->ep[UDC_EPOUT_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ }
+
+ /* call gadget with setup data received */
+ spin_unlock(&dev->lock);
+ setup_supported = dev->driver->setup(&dev->gadget,
+ &setup_data.request);
+ spin_lock(&dev->lock);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ /* ep0 in returns data (not zlp) on IN phase */
+ if (setup_supported >= 0 && setup_supported <
+ UDC_EP0IN_MAXPACKET) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* if unsupported request then stall */
+ } else if (setup_supported < 0) {
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ } else
+ dev->waiting_zlp_ack_ep0in = 1;
+
+
+ /* clear NAK by writing CNAK in EP0_OUT */
+ if (!set) {
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+ }
+
+ if (!use_dma) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ }
+
+ /* data packet 0 bytes */
+ } else if (tmp == UDC_EPSTS_OUT_DATA) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ /* get setup data: only 0 packet */
+ if (use_dma) {
+ /* no req if 0 packet, just reactivate */
+ if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+ VDBG(dev, "ZLP\n");
+
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td->status =
+ AMD_ADDBITS(
+ dev->ep[UDC_EP0OUT_IX].td->status,
+ UDC_DMA_OUT_STS_BS_HOST_READY,
+ UDC_DMA_OUT_STS_BS);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ ret_val = IRQ_HANDLED;
+
+ } else {
+ /* control write */
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ /* re-program desc. pointer for possible ZLPs */
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ }
+ } else {
+
+ /* received number bytes */
+ count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+ /* out data for fifo mode not working */
+ count = 0;
+
+ /* 0 packet or real data ? */
+ if (count != 0) {
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ } else {
+ /* dummy read confirm */
+ readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+ ret_val = IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned len;
+
+ ep = &dev->ep[UDC_EP0IN_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+ /* DMA completion */
+ if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "isr: TDC clear \n");
+ ret_val = IRQ_HANDLED;
+
+ /* clear TDC bit */
+ writel(AMD_BIT(UDC_EPSTS_TDC),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+
+ /* status reg has IN bit set ? */
+ } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+ ret_val = IRQ_HANDLED;
+
+ if (ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ if (dev->stall_ep0in) {
+ DBG(dev, "stall ep0in\n");
+ /* halt ep0in */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ } else {
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+
+ if (ep->dma) {
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+ /* set poll demand bit */
+ tmp =
+ readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp,
+ &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* all bytes will be transferred */
+ req->req.actual = req->req.length;
+
+ /* complete req */
+ complete_req(ep, req, 0);
+
+ } else {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+
+ /* lengh bytes transfered */
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ }
+
+ }
+ }
+ ep->halted = 0;
+ dev->stall_ep0in = 0;
+ if (!ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ }
+
+ return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 cfg;
+ struct udc_ep *ep;
+ u16 i;
+ u8 udc_csr_epix;
+
+ /* SET_CONFIG irq ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+ ret_val = IRQ_HANDLED;
+
+ /* read config value */
+ tmp = readl(&dev->regs->sts);
+ cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+ DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+ dev->cur_config = cfg;
+ dev->set_cfg_not_acked = 1;
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.request.wValue = dev->cur_config;
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep cfg */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+ UDC_CSR_NE_CFG);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* SET_INTERFACE ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+ ret_val = IRQ_HANDLED;
+
+ dev->set_cfg_not_acked = 1;
+ /* read interface and alt setting values */
+ tmp = readl(&dev->regs->sts);
+ dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+ dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+ setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+ setup_data.request.wValue = dev->cur_alt;
+ setup_data.request.wIndex = dev->cur_intf;
+
+ DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+ dev->cur_alt, dev->cur_intf);
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ /* UDC CSR reg */
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+ UDC_CSR_NE_INTF);
+ /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+ UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* USB reset */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+ DBG(dev, "USB Reset interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* allow soft reset when suspend occurs */
+ soft_reset_occured = 0;
+
+ dev->waiting_zlp_ack_ep0in = 0;
+ dev->set_cfg_not_acked = 0;
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* call gadget to resume and reset configs etc. */
+ spin_unlock(&dev->lock);
+ if (dev->sys_suspended && dev->driver->resume) {
+ dev->driver->resume(&dev->gadget);
+ dev->sys_suspended = 0;
+ }
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* soft reset when rxfifo not empty */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+ && !soft_reset_after_usbreset_occured) {
+ udc_soft_reset(dev);
+ soft_reset_after_usbreset_occured++;
+ }
+
+ /*
+ * DMA reset to kill potential old DMA hw hang,
+ * POLL bit is already reset by ep_init() through
+ * disconnect()
+ */
+ DBG(dev, "DMA machine reset\n");
+ tmp = readl(&dev->regs->cfg);
+ writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+ writel(tmp, &dev->regs->cfg);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ /* enable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+
+ } /* USB suspend */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+ DBG(dev, "USB Suspend interrupt\n");
+ ret_val = IRQ_HANDLED;
+ if (dev->driver->suspend) {
+ spin_unlock(&dev->lock);
+ dev->sys_suspended = 1;
+ dev->driver->suspend(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ } /* new speed ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+ DBG(dev, "ENUM interrupt\n");
+ ret_val = IRQ_HANDLED;
+ soft_reset_after_usbreset_occured = 0;
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+ if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "high");
+ } else if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "full");
+ }
+
+ /* init ep 0 */
+ activate_control_endpoints(dev);
+
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ }
+ /* session valid change interrupt */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+ DBG(dev, "USB SVC interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* check that session is not valid to detect disconnect */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+ /* disable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp |= AMD_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+ DBG(dev, "USB Disconnect (session valid low)\n");
+ /* cleanup on disconnect */
+ usb_disconnect(udc);
+ }
+
+ }
+
+ return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+ struct udc *dev = pdev;
+ u32 reg;
+ u16 i;
+ u32 ep_irq;
+ irqreturn_t ret_val = IRQ_NONE;
+
+ spin_lock(&dev->lock);
+
+ /* check for ep irq */
+ reg = readl(&dev->regs->ep_irqsts);
+ if (reg) {
+ if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+ ret_val |= udc_control_out_isr(dev);
+ if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+ ret_val |= udc_control_in_isr(dev);
+
+ /*
+ * data endpoint
+ * iterate ep's
+ */
+ for (i = 1; i < UDC_EP_NUM; i++) {
+ ep_irq = 1 << i;
+ if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+ continue;
+
+ /* clear irq status */
+ writel(ep_irq, &dev->regs->ep_irqsts);
+
+ /* irq for out ep ? */
+ if (i > UDC_EPIN_NUM)
+ ret_val |= udc_data_out_isr(dev, i);
+ else
+ ret_val |= udc_data_in_isr(dev, i);
+ }
+
+ }
+
+
+ /* check for dev irq */
+ reg = readl(&dev->regs->irqsts);
+ if (reg) {
+ /* clear irq */
+ writel(reg, &dev->regs->irqsts);
+ ret_val |= udc_dev_isr(dev, reg);
+ }
+
+
+ spin_unlock(&dev->lock);
+ return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+ struct amd5536udc *dev = dev_get_drvdata(pdev);
+ kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+ /* remove timer */
+ stop_timer++;
+ if (timer_pending(&udc_timer))
+ wait_for_completion(&on_exit);
+ if (udc_timer.data)
+ del_timer_sync(&udc_timer);
+ /* remove pollstall timer */
+ stop_pollstall_timer++;
+ if (timer_pending(&udc_pollstall_timer))
+ wait_for_completion(&on_pollstall_exit);
+ if (udc_pollstall_timer.data)
+ del_timer_sync(&udc_pollstall_timer);
+ udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+ struct udc *dev;
+
+ dev = pci_get_drvdata(pdev);
+
+ /* gadget driver must not be registered */
+ BUG_ON(dev->driver != NULL);
+
+ /* dma pool cleanup */
+ if (dev->data_requests)
+ pci_pool_destroy(dev->data_requests);
+
+ if (dev->stp_requests) {
+ /* cleanup DMA desc's for ep0in */
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td_stp,
+ dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td,
+ dev->ep[UDC_EP0OUT_IX].td_phys);
+
+ pci_pool_destroy(dev->stp_requests);
+ }
+
+ /* reset controller */
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ if (dev->irq_registered)
+ free_irq(pdev->irq, dev);
+ if (dev->regs)
+ iounmap(dev->regs);
+ if (dev->mem_region)
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (dev->active)
+ pci_disable_device(pdev);
+
+ device_unregister(&dev->gadget.dev);
+ pci_set_drvdata(pdev, NULL);
+
+ udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td_data;
+ int retval;
+
+ /* consistent DMA mode setting ? */
+ if (use_dma_ppb) {
+ use_dma_bufferfill_mode = 0;
+ } else {
+ use_dma_ppb_du = 0;
+ use_dma_bufferfill_mode = 1;
+ }
+
+ /* DMA setup */
+ dev->data_requests = dma_pool_create("data_requests", NULL,
+ sizeof(struct udc_data_dma), 0, 0);
+ if (!dev->data_requests) {
+ DBG(dev, "can't get request data pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* EP0 in dma regs = dev control regs */
+ dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+ /* dma desc for setup data */
+ dev->stp_requests = dma_pool_create("setup requests", NULL,
+ sizeof(struct udc_stp_dma), 0, 0);
+ if (!dev->stp_requests) {
+ DBG(dev, "can't get stp request pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+ /* setup */
+ td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ if (td_stp == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+ /* data: 0 packets !? */
+ td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_phys);
+ if (td_data == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td = td_data;
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+ struct pci_dev *pdev,
+ const struct pci_device_id *id
+)
+{
+ struct udc *dev;
+ unsigned long resource;
+ unsigned long len;
+ int retval = 0;
+
+ /* one udc only */
+ if (udc) {
+ dev_dbg(&pdev->dev, "already probed\n");
+ return -EBUSY;
+ }
+
+ /* init */
+ dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* pci setup */
+ if (pci_enable_device(pdev) < 0) {
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev->active = 1;
+
+ /* PCI resource allocation */
+ resource = pci_resource_start(pdev, 0);
+ len = pci_resource_len(pdev, 0);
+
+ if (!request_mem_region(resource, len, name)) {
+ dev_dbg(&pdev->dev, "pci device used already\n");
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->mem_region = 1;
+
+ dev->virt_addr = ioremap_nocache(resource, len);
+ if (dev->virt_addr == NULL) {
+ dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+ retval = -EFAULT;
+ goto finished;
+ }
+
+ if (!pdev->irq) {
+ dev_err(&dev->pdev->dev, "irq not set\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+
+ if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+ dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->irq_registered = 1;
+
+ pci_set_drvdata(pdev, dev);
+
+ /* chip revision for Hs AMD5536 */
+ dev->chiprev = pdev->revision;
+
+ pci_set_master(pdev);
+ pci_set_mwi(pdev);
+
+ /* init dma pools */
+ if (use_dma) {
+ retval = init_dma_pools(dev);
+ if (retval != 0)
+ goto finished;
+ }
+
+ dev->phys_addr = resource;
+ dev->irq = pdev->irq;
+ dev->pdev = pdev;
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ /* general probing */
+ if (udc_probe(dev) == 0)
+ return 0;
+
+finished:
+ if (dev)
+ udc_pci_remove(pdev);
+ return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+ char tmp[128];
+ u32 reg;
+ int retval;
+
+ /* mark timer as not initialized */
+ udc_timer.data = 0;
+ udc_pollstall_timer.data = 0;
+
+ /* device struct setup */
+ spin_lock_init(&dev->lock);
+ dev->gadget.ops = &udc_ops;
+
+ strcpy(dev->gadget.dev.bus_id, "gadget");
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = name;
+ dev->gadget.name = name;
+ dev->gadget.is_dualspeed = 1;
+
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+ /* init registers, interrupts, ... */
+ startup_registers(dev);
+
+ dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+ snprintf(tmp, sizeof tmp, "%d", dev->irq);
+ dev_info(&dev->pdev->dev,
+ "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+ tmp, dev->phys_addr, dev->chiprev,
+ (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+ strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+ if (dev->chiprev == UDC_HSA0_REV) {
+ dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev_info(&dev->pdev->dev,
+ "driver version: %s(for Geode5536 B1)\n", tmp);
+ udc = dev;
+
+ retval = device_register(&dev->gadget.dev);
+ if (retval)
+ goto finished;
+
+ /* timer init */
+ init_timer(&udc_timer);
+ udc_timer.function = udc_timer_function;
+ udc_timer.data = 1;
+ /* timer pollstall init */
+ init_timer(&udc_pollstall_timer);
+ udc_pollstall_timer.function = udc_pollstall_timer_function;
+ udc_pollstall_timer.data = 1;
+
+ /* set SD */
+ reg = readl(&dev->regs->ctl);
+ reg |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(reg, &dev->regs->ctl);
+
+ /* print dev register info */
+ print_regs(dev);
+
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ DBG(dev, "UDC initiates remote wakeup\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+ tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class_mask = 0xffffffff,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+ .name = (char *) name,
+ .id_table = pci_id,
+ .probe = udc_pci_probe,
+ .remove = udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+ return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+ pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 000000000000..4bbabbbfc93f
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS 1
+#define UDC_RDE_TIMER_DIV 10
+#define UDC_POLLSTALL_TIMER_USECONDS 500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0 0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16
+
+#define UDC_SETCONFIG_DWORD1 0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0 0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS 16
+
+#define UDC_SETINTF_DWORD1 0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS 0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0 0x0000ff21
+#define UDC_MSCRES_DWORD1 0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR 0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_NUM_OFS 0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_DIR_OFS 4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_TYPE_OFS 5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_CFG_OFS 7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_INTF_OFS 11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_ALT_OFS 15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR 0x400
+
+#define UDC_DEVCFG_SOFTRESET 31
+#define UDC_DEVCFG_HNPSFEN 30
+#define UDC_DEVCFG_DMARST 29
+#define UDC_DEVCFG_SET_DESC 18
+#define UDC_DEVCFG_CSR_PRG 17
+#define UDC_DEVCFG_STATUS 7
+#define UDC_DEVCFG_DIR 6
+#define UDC_DEVCFG_PI 5
+#define UDC_DEVCFG_SS 4
+#define UDC_DEVCFG_SP 3
+#define UDC_DEVCFG_RWKP 2
+
+#define UDC_DEVCFG_SPD_MASK 0x3
+#define UDC_DEVCFG_SPD_OFS 0
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+/*#define UDC_DEVCFG_SPD_FS 0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR 0x404
+
+#define UDC_DEVCTL_THLEN_MASK 0xff000000
+#define UDC_DEVCTL_THLEN_OFS 24
+
+#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS 16
+
+#define UDC_DEVCTL_CSR_DONE 13
+#define UDC_DEVCTL_DEVNAK 12
+#define UDC_DEVCTL_SD 10
+#define UDC_DEVCTL_MODE 9
+#define UDC_DEVCTL_BREN 8
+#define UDC_DEVCTL_THE 7
+#define UDC_DEVCTL_BF 6
+#define UDC_DEVCTL_BE 5
+#define UDC_DEVCTL_DU 4
+#define UDC_DEVCTL_TDE 3
+#define UDC_DEVCTL_RDE 2
+#define UDC_DEVCTL_RES 0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR 0x408
+
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_TS_OFS 18
+
+#define UDC_DEVSTS_SESSVLD 17
+#define UDC_DEVSTS_PHY_ERROR 16
+#define UDC_DEVSTS_RXFIFO_EMPTY 15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS 13
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+
+#define UDC_DEVSTS_SUSP 12
+
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_ALT_OFS 8
+
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_INTF_OFS 4
+
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+#define UDC_DEVSTS_CFG_OFS 0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR 0x40c
+
+#define UDC_DEVINT_SVC 7
+#define UDC_DEVINT_ENUM 6
+#define UDC_DEVINT_SOF 5
+#define UDC_DEVINT_US 4
+#define UDC_DEVINT_UR 3
+#define UDC_DEVINT_ES 2
+#define UDC_DEVINT_SI 1
+#define UDC_DEVINT_SC 0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR 0x410
+
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR 0x414
+
+#define UDC_EPINT_OUT_MASK 0xffff0000
+#define UDC_EPINT_OUT_OFS 16
+#define UDC_EPINT_IN_MASK 0x0000ffff
+#define UDC_EPINT_IN_OFS 0
+
+#define UDC_EPINT_IN_EP0 0
+#define UDC_EPINT_IN_EP1 1
+#define UDC_EPINT_IN_EP2 2
+#define UDC_EPINT_IN_EP3 3
+#define UDC_EPINT_OUT_EP0 16
+#define UDC_EPINT_OUT_EP1 17
+#define UDC_EPINT_OUT_EP2 18
+#define UDC_EPINT_OUT_EP3 19
+
+#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR 0x418
+
+#define UDC_EPINT_OUT_MSK_MASK 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS 16
+#define UDC_EPINT_IN_MSK_MASK 0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS 0
+
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE 0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR 0x0
+#define UDC_EPIN_REGS_ADDR 0x0
+#define UDC_EPOUT_REGS_ADDR 0x200
+
+#define UDC_EPCTL_ADDR 0x0
+
+#define UDC_EPCTL_RRDY 9
+#define UDC_EPCTL_CNAK 8
+#define UDC_EPCTL_SNAK 7
+#define UDC_EPCTL_NAK 6
+
+#define UDC_EPCTL_ET_MASK 0x00000030
+#define UDC_EPCTL_ET_OFS 4
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+#define UDC_EPCTL_P 3
+#define UDC_EPCTL_SN 2
+#define UDC_EPCTL_F 1
+#define UDC_EPCTL_S 0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR 0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS 11
+
+#define UDC_EPSTS_TDC 10
+#define UDC_EPSTS_HE 9
+#define UDC_EPSTS_BNA 7
+#define UDC_EPSTS_IN 6
+
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_OUT_OFS 4
+#define UDC_EPSTS_OUT_DATA 1
+#define UDC_EPSTS_OUT_DATA_CLEAR 0x10
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20
+#define UDC_EPSTS_OUT_CLEAR 0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR 0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE 32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT 2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE 256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE 32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE 32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS 0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS 16
+#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS 0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE 64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS 16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS 16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS 20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS 24
+#define UDC_DMA_STP_STS_RX_MASK 0x30000000
+#define UDC_DMA_STP_STS_RX_OFS 28
+#define UDC_DMA_STP_STS_BS_MASK 0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS 30
+#define UDC_DMA_STP_STS_BS_HOST_READY 0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY 1
+#define UDC_DMA_STP_STS_BS_DMA_DONE 2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY 3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS 0
+#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS 0
+#define UDC_DMA_IN_STS_L 27
+#define UDC_DMA_IN_STS_TX_MASK 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS 28
+#define UDC_DMA_IN_STS_BS_MASK 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS 30
+#define UDC_DMA_IN_STS_BS_HOST_READY 0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY 1
+#define UDC_DMA_IN_STS_BS_DMA_DONE 2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY 3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS 0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0
+#define UDC_DMA_OUT_STS_L 27
+#define UDC_DMA_OUT_STS_RX_MASK 0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS 28
+#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY 0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE 2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET 1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET 65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR 0x10
+#define UDC_EP_DESPTR_ADDR 0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM 32
+#define UDC_EPIN_NUM 16
+#define UDC_EPIN_NUM_USED 5
+#define UDC_EPOUT_NUM 16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM 9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS 12
+
+#define UDC_EP0OUT_IX 16
+#define UDC_EP0IN_IX 0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR 0x800
+#define UDC_RXFIFO_SIZE 0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR 0xc00
+#define UDC_TXFIFO_SIZE 0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX 1
+#define UDC_EPIN_IX 2
+#define UDC_EPOUT_IX 18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES 4
+#define UDC_BITS_PER_BYTE_SHIFT 3
+#define UDC_BYTE_MASK 0xff
+#define UDC_BITS_PER_BYTE 8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+ /* sca - setup command address */
+ u32 sca;
+
+ /* ep ne's */
+ u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+ /* device configuration */
+ u32 cfg;
+
+ /* device control */
+ u32 ctl;
+
+ /* device status */
+ u32 sts;
+
+ /* device interrupt */
+ u32 irqsts;
+
+ /* device interrupt mask */
+ u32 irqmsk;
+
+ /* endpoint interrupt */
+ u32 ep_irqsts;
+
+ /* endpoint interrupt mask */
+ u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+ /* endpoint control */
+ u32 ctl;
+
+ /* endpoint status */
+ u32 sts;
+
+ /* endpoint buffer size in/ receive packet frame number out */
+ u32 bufin_framenum;
+
+ /* endpoint buffer size out/max packet size */
+ u32 bufout_maxpkt;
+
+ /* endpoint setup buffer pointer */
+ u32 subptr;
+
+ /* endpoint data descriptor pointer */
+ u32 desptr;
+
+ /* reserverd */
+ u32 reserved;
+
+ /* write/read confirmation */
+ u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* first setup word */
+ u32 data12;
+ /* second setup word */
+ u32 data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* buffer pointer */
+ u32 bufptr;
+ /* next descriptor pointer */
+ u32 next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+ /* embedded gadget ep */
+ struct usb_request req;
+
+ /* flags */
+ unsigned dma_going : 1,
+ dma_mapping : 1,
+ dma_done : 1;
+ /* phys. address */
+ dma_addr_t td_phys;
+ /* first dma desc. of chain */
+ struct udc_data_dma *td_data;
+ /* last dma desc. of chain */
+ struct udc_data_dma *td_data_last;
+ struct list_head queue;
+
+ /* chain length */
+ unsigned chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+ struct usb_ep ep;
+ struct udc_ep_regs __iomem *regs;
+ u32 __iomem *txfifo;
+ u32 __iomem *dma;
+ dma_addr_t td_phys;
+ dma_addr_t td_stp_dma;
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td;
+ /* temp request */
+ struct udc_request *req;
+ unsigned req_used;
+ unsigned req_completed;
+ /* dummy DMA desc for BNA dummy */
+ struct udc_request *bna_dummy_req;
+ unsigned bna_occurred;
+
+ /* NAK state */
+ unsigned naking;
+
+ struct udc *dev;
+
+ /* queue for requests */
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned halted;
+ unsigned cancel_transfer;
+ unsigned num : 5,
+ fifo_depth : 14,
+ in : 1;
+};
+
+/* device struct */
+struct udc {
+ struct usb_gadget gadget;
+ spinlock_t lock; /* protects all state */
+ /* all endpoints */
+ struct udc_ep ep[UDC_EP_NUM];
+ struct usb_gadget_driver *driver;
+ /* operational flags */
+ unsigned active : 1,
+ stall_ep0in : 1,
+ waiting_zlp_ack_ep0in : 1,
+ set_cfg_not_acked : 1,
+ irq_registered : 1,
+ data_ep_enabled : 1,
+ data_ep_queued : 1,
+ mem_region : 1,
+ sys_suspended : 1,
+ connected;
+
+ u16 chiprev;
+
+ /* registers */
+ struct pci_dev *pdev;
+ struct udc_csrs __iomem *csr;
+ struct udc_regs __iomem *regs;
+ struct udc_ep_regs __iomem *ep_regs;
+ u32 __iomem *rxfifo;
+ u32 __iomem *txfifo;
+
+ /* DMA desc pools */
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+
+ /* device data */
+ unsigned long phys_addr;
+ void __iomem *virt_addr;
+ unsigned irq;
+
+ /* states */
+ u16 cur_config;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+ u32 data[2];
+ struct usb_ctrlrequest request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ ((u32Val) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name) \
+ ((u32Val & ((u32) bitfield_stub_name##_MASK)) \
+ >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(udc , args...) do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 63d7d6568699..a6adf7e0f6f8 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -38,7 +38,7 @@
#include <linux/proc_fs.h>
#include <linux/clk.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 000000000000..4fb5ff469574
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+ struct usba_ep *ep = inode->i_private;
+ struct usba_request *req, *req_copy;
+ struct list_head *queue_data;
+
+ queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+ if (!queue_data)
+ return -ENOMEM;
+ INIT_LIST_HEAD(queue_data);
+
+ spin_lock_irq(&ep->udc->lock);
+ list_for_each_entry(req, &ep->queue, queue) {
+ req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+ if (!req_copy)
+ goto fail;
+ memcpy(req_copy, req, sizeof(*req_copy));
+ list_add_tail(&req_copy->queue, queue_data);
+ }
+ spin_unlock_irq(&ep->udc->lock);
+
+ file->private_data = queue_data;
+ return 0;
+
+fail:
+ spin_unlock_irq(&ep->udc->lock);
+ list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+ list_del(&req->queue);
+ kfree(req);
+ }
+ kfree(queue_data);
+ return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct list_head *queue = file->private_data;
+ struct usba_request *req, *tmp_req;
+ size_t len, remaining, actual = 0;
+ char tmpbuf[38];
+
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ list_for_each_entry_safe(req, tmp_req, queue, queue) {
+ len = snprintf(tmpbuf, sizeof(tmpbuf),
+ "%8p %08x %c%c%c %5d %c%c%c\n",
+ req->req.buf, req->req.length,
+ req->req.no_interrupt ? 'i' : 'I',
+ req->req.zero ? 'Z' : 'z',
+ req->req.short_not_ok ? 's' : 'S',
+ req->req.status,
+ req->submitted ? 'F' : 'f',
+ req->using_dma ? 'D' : 'd',
+ req->last_transaction ? 'L' : 'l');
+ len = min(len, sizeof(tmpbuf));
+ if (len > nbytes)
+ break;
+
+ list_del(&req->queue);
+ kfree(req);
+
+ remaining = __copy_to_user(buf, tmpbuf, len);
+ actual += len - remaining;
+ if (remaining)
+ break;
+
+ nbytes -= len;
+ buf += len;
+ }
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+ return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+ struct list_head *queue_data = file->private_data;
+ struct usba_request *req, *tmp_req;
+
+ list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+ list_del(&req->queue);
+ kfree(req);
+ }
+ kfree(queue_data);
+ return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+ struct usba_udc *udc;
+ unsigned int i;
+ u32 *data;
+ int ret = -ENOMEM;
+
+ mutex_lock(&inode->i_mutex);
+ udc = inode->i_private;
+ data = kmalloc(inode->i_size, GFP_KERNEL);
+ if (!data)
+ goto out;
+
+ spin_lock_irq(&udc->lock);
+ for (i = 0; i < inode->i_size / 4; i++)
+ data[i] = __raw_readl(udc->regs + i * 4);
+ spin_unlock_irq(&udc->lock);
+
+ file->private_data = data;
+ ret = 0;
+
+out:
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ mutex_lock(&inode->i_mutex);
+ ret = simple_read_from_buffer(buf, nbytes, ppos,
+ file->private_data,
+ file->f_dentry->d_inode->i_size);
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = queue_dbg_open,
+ .llseek = no_llseek,
+ .read = queue_dbg_read,
+ .release = queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = regs_dbg_open,
+ .llseek = generic_file_llseek,
+ .read = regs_dbg_read,
+ .release = regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+ struct usba_ep *ep)
+{
+ struct dentry *ep_root;
+
+ ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+ if (!ep_root)
+ goto err_root;
+ ep->debugfs_dir = ep_root;
+
+ ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+ ep, &queue_dbg_fops);
+ if (!ep->debugfs_queue)
+ goto err_queue;
+
+ if (ep->can_dma) {
+ ep->debugfs_dma_status
+ = debugfs_create_u32("dma_status", 0400, ep_root,
+ &ep->last_dma_status);
+ if (!ep->debugfs_dma_status)
+ goto err_dma_status;
+ }
+ if (ep_is_control(ep)) {
+ ep->debugfs_state
+ = debugfs_create_u32("state", 0400, ep_root,
+ &ep->state);
+ if (!ep->debugfs_state)
+ goto err_state;
+ }
+
+ return;
+
+err_state:
+ if (ep->can_dma)
+ debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+ debugfs_remove(ep->debugfs_queue);
+err_queue:
+ debugfs_remove(ep_root);
+err_root:
+ dev_err(&ep->udc->pdev->dev,
+ "failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+ debugfs_remove(ep->debugfs_queue);
+ debugfs_remove(ep->debugfs_dma_status);
+ debugfs_remove(ep->debugfs_state);
+ debugfs_remove(ep->debugfs_dir);
+ ep->debugfs_dma_status = NULL;
+ ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+ struct dentry *root, *regs;
+ struct resource *regs_resource;
+
+ root = debugfs_create_dir(udc->gadget.name, NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+ udc->debugfs_root = root;
+
+ regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+ if (!regs)
+ goto err_regs;
+
+ regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+ CTRL_IOMEM_ID);
+ regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+ udc->debugfs_regs = regs;
+
+ usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+ return;
+
+err_regs:
+ debugfs_remove(root);
+err_root:
+ udc->debugfs_root = NULL;
+ dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+ usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+ debugfs_remove(udc->debugfs_regs);
+ debugfs_remove(udc->debugfs_root);
+ udc->debugfs_regs = NULL;
+ udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+ struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+ if (udc->vbus_pin != -1)
+ return gpio_get_value(udc->vbus_pin);
+
+ /* No Vbus detection: Assume always present */
+ return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+ unsigned long tmp;
+
+ DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+ for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+ tmp = *(unsigned long *)buf;
+ if (len >= 4) {
+ DBG(DBG_FIFO, " -> %08lx\n", tmp);
+ __raw_writel(tmp, fifo);
+ } else {
+ do {
+ DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24);
+ __raw_writeb(tmp >> 24, fifo);
+ fifo++;
+ tmp <<= 8;
+ } while (--len);
+ break;
+ }
+ }
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+ union {
+ unsigned long *w;
+ unsigned char *b;
+ } p;
+ unsigned long tmp;
+
+ DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+ for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+ if (len >= 4) {
+ tmp = __raw_readl(fifo);
+ *p.w = tmp;
+ DBG(DBG_FIFO, " -> %08lx\n", tmp);
+ } else {
+ do {
+ tmp = __raw_readb(fifo);
+ *p.b = tmp;
+ DBG(DBG_FIFO, " -> %02lx\n", tmp);
+ fifo++, p.b++;
+ } while (--len);
+ }
+ }
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+ unsigned int transaction_len;
+
+ transaction_len = req->req.length - req->req.actual;
+ req->last_transaction = 1;
+ if (transaction_len > ep->ep.maxpacket) {
+ transaction_len = ep->ep.maxpacket;
+ req->last_transaction = 0;
+ } else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+ req->last_transaction = 0;
+
+ DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+ ep->ep.name, req, transaction_len,
+ req->last_transaction ? ", done" : "");
+
+ copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+ DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+ ep->ep.name, req, req->req.length);
+
+ req->req.actual = 0;
+ req->submitted = 1;
+
+ if (req->using_dma) {
+ if (req->req.length == 0) {
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ return;
+ }
+
+ if (req->req.zero)
+ usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+ else
+ usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+ usba_dma_writel(ep, ADDRESS, req->req.dma);
+ usba_dma_writel(ep, CONTROL, req->ctrl);
+ } else {
+ next_fifo_transaction(ep, req);
+ if (req->last_transaction) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ } else {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ }
+ }
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+ struct usba_request *req;
+
+ if (list_empty(&ep->queue)) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+ if (!req->submitted)
+ submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+ ep->state = STATUS_STAGE_IN;
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+ struct usba_udc *udc = ep->udc;
+ struct usba_request *req;
+ unsigned long status;
+ unsigned int bytecount, nr_busy;
+ int is_complete = 0;
+
+ status = usba_ep_readl(ep, STA);
+ nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+ DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+ while (nr_busy > 0) {
+ if (list_empty(&ep->queue)) {
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ break;
+ }
+ req = list_entry(ep->queue.next,
+ struct usba_request, queue);
+
+ bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+ if (status & (1 << 31))
+ is_complete = 1;
+ if (req->req.actual + bytecount >= req->req.length) {
+ is_complete = 1;
+ bytecount = req->req.length - req->req.actual;
+ }
+
+ copy_from_fifo(req->req.buf + req->req.actual,
+ ep->fifo, bytecount);
+ req->req.actual += bytecount;
+
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+ if (is_complete) {
+ DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+ req->req.status = 0;
+ list_del_init(&req->queue);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+ }
+
+ status = usba_ep_readl(ep, STA);
+ nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+ if (is_complete && ep_is_control(ep)) {
+ send_status(udc, ep);
+ break;
+ }
+ }
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+ struct usba_udc *udc = ep->udc;
+
+ WARN_ON(!list_empty(&req->queue));
+
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+
+ if (req->mapped) {
+ dma_unmap_single(
+ &udc->pdev->dev, req->req.dma, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+
+ DBG(DBG_GADGET | DBG_REQ,
+ "%s: req %p complete: status %d, actual %u\n",
+ ep->ep.name, req, req->req.status, req->req.actual);
+
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+ struct usba_request *req, *tmp_req;
+
+ list_for_each_entry_safe(req, tmp_req, list, queue) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, status);
+ }
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags, ept_cfg, maxpacket;
+ unsigned int nr_trans;
+
+ DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+ maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+ if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+ || ep->index == 0
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || maxpacket == 0
+ || maxpacket > ep->fifo_size) {
+ DBG(DBG_ERR, "ep_enable: Invalid argument");
+ return -EINVAL;
+ }
+
+ ep->is_isoc = 0;
+ ep->is_in = 0;
+
+ if (maxpacket <= 8)
+ ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+ else
+ /* LSB is bit 1, not 0 */
+ ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+ DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+ ep->ep.name, ept_cfg, maxpacket);
+
+ if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ ep->is_in = 1;
+ ept_cfg |= USBA_EPT_DIR_IN;
+ }
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (!ep->can_isoc) {
+ DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+ ep->ep.name);
+ return -EINVAL;
+ }
+
+ /*
+ * Bits 11:12 specify number of _additional_
+ * transactions per microframe.
+ */
+ nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+ if (nr_trans > 3)
+ return -EINVAL;
+
+ ep->is_isoc = 1;
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+ /*
+ * Do triple-buffering on high-bandwidth iso endpoints.
+ */
+ if (nr_trans > 1 && ep->nr_banks == 3)
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+ else
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ break;
+ }
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ if (ep->desc) {
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+ return -EBUSY;
+ }
+
+ ep->desc = desc;
+ ep->ep.maxpacket = maxpacket;
+
+ usba_ep_writel(ep, CFG, ept_cfg);
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+ if (ep->can_dma) {
+ u32 ctrl;
+
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1 << ep->index)
+ | USBA_BF(DMA_INT, 1 << ep->index)));
+ ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+ usba_ep_writel(ep, CTL_ENB, ctrl);
+ } else {
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1 << ep->index)));
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+ (unsigned long)usba_ep_readl(ep, CFG));
+ DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+ (unsigned long)usba_readl(udc, INT_ENB));
+
+ return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ LIST_HEAD(req_list);
+ unsigned long flags;
+
+ DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!ep->desc) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+ return -EINVAL;
+ }
+ ep->desc = NULL;
+
+ list_splice_init(&ep->queue, &req_list);
+ if (ep->can_dma) {
+ usba_dma_writel(ep, CONTROL, 0);
+ usba_dma_writel(ep, ADDRESS, 0);
+ usba_dma_readl(ep, STATUS);
+ }
+ usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+ usba_writel(udc, INT_ENB,
+ usba_readl(udc, INT_ENB)
+ & ~USBA_BF(EPT_INT, 1 << ep->index));
+
+ request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct usba_request *req;
+
+ DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->req.dma = DMA_ADDR_INVALID;
+
+ return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usba_request *req = to_usba_req(_req);
+
+ DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+ kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+ struct usba_request *req, gfp_t gfp_flags)
+{
+ unsigned long flags;
+ int ret;
+
+ DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+ ep->ep.name, req->req.length, req->req.dma,
+ req->req.zero ? 'Z' : 'z',
+ req->req.short_not_ok ? 'S' : 's',
+ req->req.no_interrupt ? 'I' : 'i');
+
+ if (req->req.length > 0x10000) {
+ /* Lengths from 0 to 65536 (inclusive) are supported */
+ DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+ return -EINVAL;
+ }
+
+ req->using_dma = 1;
+
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(
+ &udc->pdev->dev, req->req.buf, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(
+ &udc->pdev->dev, req->req.dma, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+ | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+ | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+ if (ep->is_in)
+ req->ctrl |= USBA_DMA_END_BUF_EN;
+
+ /*
+ * Add this request to the queue and submit for DMA if
+ * possible. Check if we're still alive first -- we may have
+ * received a reset since last time we checked.
+ */
+ ret = -ESHUTDOWN;
+ spin_lock_irqsave(&udc->lock, flags);
+ if (ep->desc) {
+ if (list_empty(&ep->queue))
+ submit_request(ep, req);
+
+ list_add_tail(&req->queue, &ep->queue);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct usba_request *req = to_usba_req(_req);
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret;
+
+ DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+ ep->ep.name, req, _req->length);
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+ return -ESHUTDOWN;
+
+ req->submitted = 0;
+ req->using_dma = 0;
+ req->last_transaction = 0;
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ if (ep->can_dma)
+ return queue_dma(udc, ep, req, gfp_flags);
+
+ /* May have received a reset since last time we checked */
+ ret = -ESHUTDOWN;
+ spin_lock_irqsave(&udc->lock, flags);
+ if (ep->desc) {
+ list_add_tail(&req->queue, &ep->queue);
+
+ if (ep->is_in || (ep_is_control(ep)
+ && (ep->state == DATA_STAGE_IN
+ || ep->state == STATUS_STAGE_IN)))
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ else
+ usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+ req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+ unsigned int timeout;
+ u32 status;
+
+ /*
+ * Stop the DMA controller. When writing both CH_EN
+ * and LINK to 0, the other bits are not affected.
+ */
+ usba_dma_writel(ep, CONTROL, 0);
+
+ /* Wait for the FIFO to empty */
+ for (timeout = 40; timeout; --timeout) {
+ status = usba_dma_readl(ep, STATUS);
+ if (!(status & USBA_DMA_CH_EN))
+ break;
+ udelay(1);
+ }
+
+ if (pstatus)
+ *pstatus = status;
+
+ if (timeout == 0) {
+ dev_err(&ep->udc->pdev->dev,
+ "%s: timed out waiting for DMA FIFO to empty\n",
+ ep->ep.name);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ struct usba_request *req = to_usba_req(_req);
+ unsigned long flags;
+ u32 status;
+
+ DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+ ep->ep.name, req);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (req->using_dma) {
+ /*
+ * If this request is currently being transferred,
+ * stop the DMA controller and reset the FIFO.
+ */
+ if (ep->queue.next == &req->queue) {
+ status = usba_dma_readl(ep, STATUS);
+ if (status & USBA_DMA_CH_EN)
+ stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ ep->last_dma_status = status;
+#endif
+
+ usba_writel(udc, EPT_RST, 1 << ep->index);
+
+ usba_update_req(ep, req, status);
+ }
+ }
+
+ /*
+ * Errors should stop the queue from advancing until the
+ * completion function returns.
+ */
+ list_del_init(&req->queue);
+
+ request_complete(ep, req, -ECONNRESET);
+
+ /* Process the next request if any */
+ submit_next_request(ep);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret = 0;
+
+ DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+ value ? "set" : "clear");
+
+ if (!ep->desc) {
+ DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+ ep->ep.name);
+ return -ENODEV;
+ }
+ if (ep->is_isoc) {
+ DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+ ep->ep.name);
+ return -ENOTTY;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*
+ * We can't halt IN endpoints while there are still data to be
+ * transferred
+ */
+ if (!list_empty(&ep->queue)
+ || ((value && ep->is_in && (usba_ep_readl(ep, STA)
+ & USBA_BF(BUSY_BANKS, -1L))))) {
+ ret = -EAGAIN;
+ } else {
+ if (value)
+ usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+ else
+ usba_ep_writel(ep, CLR_STA,
+ USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+ usba_ep_readl(ep, STA);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+
+ return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+
+ usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+ .enable = usba_ep_enable,
+ .disable = usba_ep_disable,
+ .alloc_request = usba_ep_alloc_request,
+ .free_request = usba_ep_free_request,
+ .queue = usba_ep_queue,
+ .dequeue = usba_ep_dequeue,
+ .set_halt = usba_ep_set_halt,
+ .fifo_status = usba_ep_fifo_status,
+ .fifo_flush = usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+
+ return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+ unsigned long flags;
+ u32 ctrl;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+ ctrl = usba_readl(udc, CTRL);
+ usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (is_selfpowered)
+ udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+ .get_frame = usba_udc_get_frame,
+ .wakeup = usba_udc_wakeup,
+ .set_selfpowered = usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
+{ \
+ .ep = { \
+ .ops = &usba_ep_ops, \
+ .name = nam, \
+ .maxpacket = maxpkt, \
+ }, \
+ .udc = &the_udc, \
+ .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \
+ .fifo_size = maxpkt, \
+ .nr_banks = maxbk, \
+ .index = idx, \
+ .can_dma = dma, \
+ .can_isoc = isoc, \
+}
+
+static struct usba_ep usba_ep[] = {
+ EP("ep0", 0, 64, 1, 0, 0),
+ EP("ep1in-bulk", 1, 512, 2, 1, 1),
+ EP("ep2out-bulk", 2, 512, 2, 1, 1),
+ EP("ep3in-int", 3, 64, 3, 1, 0),
+ EP("ep4out-int", 4, 64, 3, 1, 0),
+ EP("ep5in-iso", 5, 1024, 3, 1, 1),
+ EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
+ /* FIXME: I have no idea what to put here */
+ .bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+ .gadget = {
+ .ops = &usba_udc_ops,
+ .ep0 = &usba_ep[0].ep,
+ .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list),
+ .is_dualspeed = 1,
+ .name = "atmel_usba_udc",
+ .dev = {
+ .bus_id = "gadget",
+ .release = nop_release,
+ },
+ },
+
+ .lock = SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+ struct usba_ep *ep;
+ struct usba_request *req, *tmp_req;
+
+ usba_writel(udc, EPT_RST, ~0UL);
+
+ ep = to_usba_ep(udc->gadget.ep0);
+ list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, -ECONNRESET);
+ }
+
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc) {
+ spin_unlock(&udc->lock);
+ usba_ep_disable(&ep->ep);
+ spin_lock(&udc->lock);
+ }
+ }
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+ struct usba_ep *ep;
+
+ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+ return to_usba_ep(udc->gadget.ep0);
+
+ list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+ u8 bEndpointAddress;
+
+ if (!ep->desc)
+ continue;
+ bEndpointAddress = ep->desc->bEndpointAddress;
+ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+ continue;
+ if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+ == (wIndex & USB_ENDPOINT_NUMBER_MASK))
+ return ep;
+ }
+
+ return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+ usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+ ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+ if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+ return 1;
+ return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+ u32 regval;
+
+ DBG(DBG_BUS, "setting address %u...\n", addr);
+ regval = usba_readl(udc, CTRL);
+ regval = USBA_BFINS(DEV_ADDR, addr, regval);
+ usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+ static const char test_packet_buffer[] = {
+ /* JKJKJKJK * 9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK * 8 */
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ /* JJKKJJKK * 8 */
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ /* JJJJJJJKKKKKKK * 8 */
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* JJJJJJJK * 8 */
+ 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+ /* {JKKKKKKK * 10}, JK */
+ 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+ };
+ struct usba_ep *ep;
+ struct device *dev = &udc->pdev->dev;
+ int test_mode;
+
+ test_mode = udc->test_mode;
+
+ /* Start from a clean slate */
+ reset_all_endpoints(udc);
+
+ switch (test_mode) {
+ case 0x0100:
+ /* Test_J */
+ usba_writel(udc, TST, USBA_TST_J_MODE);
+ dev_info(dev, "Entering Test_J mode...\n");
+ break;
+ case 0x0200:
+ /* Test_K */
+ usba_writel(udc, TST, USBA_TST_K_MODE);
+ dev_info(dev, "Entering Test_K mode...\n");
+ break;
+ case 0x0300:
+ /*
+ * Test_SE0_NAK: Force high-speed mode and set up ep0
+ * for Bulk IN transfers
+ */
+ ep = &usba_ep[0];
+ usba_writel(udc, TST,
+ USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+ usba_ep_writel(ep, CFG,
+ USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+ | USBA_EPT_DIR_IN
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+ | USBA_BF(BK_NUMBER, 1));
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+ set_protocol_stall(udc, ep);
+ dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+ } else {
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+ dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+ }
+ break;
+ case 0x0400:
+ /* Test_Packet */
+ ep = &usba_ep[0];
+ usba_ep_writel(ep, CFG,
+ USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+ | USBA_EPT_DIR_IN
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+ | USBA_BF(BK_NUMBER, 1));
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+ set_protocol_stall(udc, ep);
+ dev_err(dev, "Test_Packet: ep0 not mapped\n");
+ } else {
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+ usba_writel(udc, TST, USBA_TST_PKT_MODE);
+ copy_to_fifo(ep->fifo, test_packet_buffer,
+ sizeof(test_packet_buffer));
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ dev_info(dev, "Entering Test_Packet mode...\n");
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+ return true;
+ return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+ return true;
+ return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+ return true;
+ return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+ struct usb_ctrlrequest *crq)
+{
+ int retval = 0;;
+
+ switch (crq->bRequest) {
+ case USB_REQ_GET_STATUS: {
+ u16 status;
+
+ if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+ status = cpu_to_le16(udc->devstatus);
+ } else if (crq->bRequestType
+ == (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+ status = __constant_cpu_to_le16(0);
+ } else if (crq->bRequestType
+ == (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+ struct usba_ep *target;
+
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ status = 0;
+ if (is_stalled(udc, target))
+ status |= __constant_cpu_to_le16(1);
+ } else
+ goto delegate;
+
+ /* Write directly to the FIFO. No queueing is done. */
+ if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+ goto stall;
+ ep->state = DATA_STAGE_IN;
+ __raw_writew(status, ep->fifo);
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ break;
+ }
+
+ case USB_REQ_CLEAR_FEATURE: {
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ if (feature_is_dev_remote_wakeup(crq))
+ udc->devstatus
+ &= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+ else
+ /* Can't CLEAR_FEATURE TEST_MODE */
+ goto stall;
+ } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+ struct usba_ep *target;
+
+ if (crq->wLength != __constant_cpu_to_le16(0)
+ || !feature_is_ep_halt(crq))
+ goto stall;
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+ if (target->index != 0)
+ usba_ep_writel(target, CLR_STA,
+ USBA_TOGGLE_CLR);
+ } else {
+ goto delegate;
+ }
+
+ send_status(udc, ep);
+ break;
+ }
+
+ case USB_REQ_SET_FEATURE: {
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ if (feature_is_dev_test_mode(crq)) {
+ send_status(udc, ep);
+ ep->state = STATUS_STAGE_TEST;
+ udc->test_mode = le16_to_cpu(crq->wIndex);
+ return 0;
+ } else if (feature_is_dev_remote_wakeup(crq)) {
+ udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+ } else {
+ goto stall;
+ }
+ } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+ struct usba_ep *target;
+
+ if (crq->wLength != __constant_cpu_to_le16(0)
+ || !feature_is_ep_halt(crq))
+ goto stall;
+
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+ } else
+ goto delegate;
+
+ send_status(udc, ep);
+ break;
+ }
+
+ case USB_REQ_SET_ADDRESS:
+ if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+ goto delegate;
+
+ set_address(udc, le16_to_cpu(crq->wValue));
+ send_status(udc, ep);
+ ep->state = STATUS_STAGE_ADDR;
+ break;
+
+ default:
+delegate:
+ spin_unlock(&udc->lock);
+ retval = udc->driver->setup(&udc->gadget, crq);
+ spin_lock(&udc->lock);
+ }
+
+ return retval;
+
+stall:
+ printk(KERN_ERR
+ "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+ "halting endpoint...\n",
+ ep->ep.name, crq->bRequestType, crq->bRequest,
+ le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+ le16_to_cpu(crq->wLength));
+ set_protocol_stall(udc, ep);
+ return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 epstatus;
+ u32 epctrl;
+
+restart:
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+
+ DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+ ep->ep.name, ep->state, epstatus, epctrl);
+
+ req = NULL;
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next,
+ struct usba_request, queue);
+
+ if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+ if (req->submitted)
+ next_fifo_transaction(ep, req);
+ else
+ submit_request(ep, req);
+
+ if (req->last_transaction) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ }
+ goto restart;
+ }
+ if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+ usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+ switch (ep->state) {
+ case DATA_STAGE_IN:
+ usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = STATUS_STAGE_OUT;
+ break;
+ case STATUS_STAGE_ADDR:
+ /* Activate our new address */
+ usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+ | USBA_FADDR_EN));
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ break;
+ case STATUS_STAGE_IN:
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, 0);
+ submit_next_request(ep);
+ }
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ break;
+ case STATUS_STAGE_TEST:
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ if (do_test_mode(udc))
+ set_protocol_stall(udc, ep);
+ break;
+ default:
+ printk(KERN_ERR
+ "udc: %s: TXCOMP: Invalid endpoint state %d, "
+ "halting endpoint...\n",
+ ep->ep.name, ep->state);
+ set_protocol_stall(udc, ep);
+ break;
+ }
+
+ goto restart;
+ }
+ if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+ switch (ep->state) {
+ case STATUS_STAGE_OUT:
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, 0);
+ }
+ ep->state = WAIT_FOR_SETUP;
+ break;
+
+ case DATA_STAGE_OUT:
+ receive_data(ep);
+ break;
+
+ default:
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ printk(KERN_ERR
+ "udc: %s: RXRDY: Invalid endpoint state %d, "
+ "halting endpoint...\n",
+ ep->ep.name, ep->state);
+ set_protocol_stall(udc, ep);
+ break;
+ }
+
+ goto restart;
+ }
+ if (epstatus & USBA_RX_SETUP) {
+ union {
+ struct usb_ctrlrequest crq;
+ unsigned long data[2];
+ } crq;
+ unsigned int pkt_len;
+ int ret;
+
+ if (ep->state != WAIT_FOR_SETUP) {
+ /*
+ * Didn't expect a SETUP packet at this
+ * point. Clean up any pending requests (which
+ * may be successful).
+ */
+ int status = -EPROTO;
+
+ /*
+ * RXRDY and TXCOMP are dropped when SETUP
+ * packets arrive. Just pretend we received
+ * the status packet.
+ */
+ if (ep->state == STATUS_STAGE_OUT
+ || ep->state == STATUS_STAGE_IN) {
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ status = 0;
+ }
+
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, status);
+ }
+ }
+
+ pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+ DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+ if (pkt_len != sizeof(crq)) {
+ printk(KERN_WARNING "udc: Invalid packet length %u "
+ "(expected %lu)\n", pkt_len, sizeof(crq));
+ set_protocol_stall(udc, ep);
+ return;
+ }
+
+ DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+ copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+ /* Free up one bank in the FIFO so that we can
+ * generate or receive a reply right away. */
+ usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+ /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+ ep->state, crq.crq.bRequestType,
+ crq.crq.bRequest); */
+
+ if (crq.crq.bRequestType & USB_DIR_IN) {
+ /*
+ * The USB 2.0 spec states that "if wLength is
+ * zero, there is no data transfer phase."
+ * However, testusb #14 seems to actually
+ * expect a data phase even if wLength = 0...
+ */
+ ep->state = DATA_STAGE_IN;
+ } else {
+ if (crq.crq.wLength != __constant_cpu_to_le16(0))
+ ep->state = DATA_STAGE_OUT;
+ else
+ ep->state = STATUS_STAGE_IN;
+ }
+
+ ret = -1;
+ if (ep->index == 0)
+ ret = handle_ep0_setup(udc, ep, &crq.crq);
+ else {
+ spin_unlock(&udc->lock);
+ ret = udc->driver->setup(&udc->gadget, &crq.crq);
+ spin_lock(&udc->lock);
+ }
+
+ DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+ crq.crq.bRequestType, crq.crq.bRequest,
+ le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+ if (ret < 0) {
+ /* Let the host know that we failed */
+ set_protocol_stall(udc, ep);
+ }
+ }
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 epstatus;
+ u32 epctrl;
+
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+
+ DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+ while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+ DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+ if (list_empty(&ep->queue)) {
+ dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+
+ if (req->using_dma) {
+ /* Send a zero-length packet */
+ usba_ep_writel(ep, SET_STA,
+ USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_DIS,
+ USBA_TX_PK_RDY);
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ } else {
+ if (req->submitted)
+ next_fifo_transaction(ep, req);
+ else
+ submit_request(ep, req);
+
+ if (req->last_transaction) {
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ }
+ }
+
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+ }
+ if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+ DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+ receive_data(ep);
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ }
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 status, control, pending;
+
+ status = usba_dma_readl(ep, STATUS);
+ control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ ep->last_dma_status = status;
+#endif
+ pending = status & control;
+ DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+ if (status & USBA_DMA_CH_EN) {
+ dev_err(&udc->pdev->dev,
+ "DMA_CH_EN is set after transfer is finished!\n");
+ dev_err(&udc->pdev->dev,
+ "status=%#08x, pending=%#08x, control=%#08x\n",
+ status, pending, control);
+
+ /*
+ * try to pretend nothing happened. We might have to
+ * do something here...
+ */
+ }
+
+ if (list_empty(&ep->queue))
+ /* Might happen if a reset comes along at the right moment */
+ return;
+
+ if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+ usba_update_req(ep, req, status);
+
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ }
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+ struct usba_udc *udc = devid;
+ u32 status;
+ u32 dma_status;
+ u32 ep_status;
+
+ spin_lock(&udc->lock);
+
+ status = usba_readl(udc, INT_STA);
+ DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+ if (status & USBA_DET_SUSPEND) {
+ usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+ DBG(DBG_BUS, "Suspend detected\n");
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->suspend) {
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ if (status & USBA_WAKE_UP) {
+ usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+ DBG(DBG_BUS, "Wake Up CPU detected\n");
+ }
+
+ if (status & USBA_END_OF_RESUME) {
+ usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+ DBG(DBG_BUS, "Resume detected\n");
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ dma_status = USBA_BFEXT(DMA_INT, status);
+ if (dma_status) {
+ int i;
+
+ for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+ if (dma_status & (1 << i))
+ usba_dma_irq(udc, &usba_ep[i]);
+ }
+
+ ep_status = USBA_BFEXT(EPT_INT, status);
+ if (ep_status) {
+ int i;
+
+ for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+ if (ep_status & (1 << i)) {
+ if (ep_is_control(&usba_ep[i]))
+ usba_control_irq(udc, &usba_ep[i]);
+ else
+ usba_ep_irq(udc, &usba_ep[i]);
+ }
+ }
+
+ if (status & USBA_END_OF_RESET) {
+ struct usba_ep *ep0;
+
+ usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+ reset_all_endpoints(udc);
+
+ if (status & USBA_HIGH_SPEED) {
+ DBG(DBG_BUS, "High-speed bus reset detected\n");
+ udc->gadget.speed = USB_SPEED_HIGH;
+ } else {
+ DBG(DBG_BUS, "Full-speed bus reset detected\n");
+ udc->gadget.speed = USB_SPEED_FULL;
+ }
+
+ ep0 = &usba_ep[0];
+ ep0->desc = &usba_ep0_desc;
+ ep0->state = WAIT_FOR_SETUP;
+ usba_ep_writel(ep0, CFG,
+ (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+ | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+ usba_ep_writel(ep0, CTL_ENB,
+ USBA_EPT_ENABLE | USBA_RX_SETUP);
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1)
+ | USBA_DET_SUSPEND
+ | USBA_END_OF_RESUME));
+
+ if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+ dev_warn(&udc->pdev->dev,
+ "WARNING: EP0 configuration is invalid!\n");
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+ struct usba_udc *udc = devid;
+ int vbus;
+
+ /* debounce */
+ udelay(10);
+
+ spin_lock(&udc->lock);
+
+ /* May happen if Vbus pin toggles during probe() */
+ if (!udc->driver)
+ goto out;
+
+ vbus = gpio_get_value(udc->vbus_pin);
+ if (vbus != udc->vbus_prev) {
+ if (vbus) {
+ usba_writel(udc, CTRL, USBA_EN_USBA);
+ usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ } else {
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ reset_all_endpoints(udc);
+ usba_writel(udc, CTRL, 0);
+ spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ udc->vbus_prev = vbus;
+ }
+
+out:
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct usba_udc *udc = &the_udc;
+ unsigned long flags;
+ int ret;
+
+ if (!udc->pdev)
+ return -ENODEV;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->driver) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EBUSY;
+ }
+
+ udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ clk_enable(udc->pclk);
+ clk_enable(udc->hclk);
+
+ ret = driver->bind(&udc->gadget);
+ if (ret) {
+ DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+ driver->driver.name, ret);
+ goto err_driver_bind;
+ }
+
+ DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+ udc->vbus_prev = 0;
+ if (udc->vbus_pin != -1)
+ enable_irq(gpio_to_irq(udc->vbus_pin));
+
+ /* If Vbus is present, enable the controller and wait for reset */
+ spin_lock_irqsave(&udc->lock, flags);
+ if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+ usba_writel(udc, CTRL, USBA_EN_USBA);
+ usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+
+err_driver_bind:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct usba_udc *udc = &the_udc;
+ unsigned long flags;
+
+ if (!udc->pdev)
+ return -ENODEV;
+ if (driver != udc->driver)
+ return -EINVAL;
+
+ if (udc->vbus_pin != -1)
+ disable_irq(gpio_to_irq(udc->vbus_pin));
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ reset_all_endpoints(udc);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* This will also disable the DP pullup */
+ usba_writel(udc, CTRL, 0);
+
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ clk_disable(udc->hclk);
+ clk_disable(udc->pclk);
+
+ DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+ struct usba_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *regs, *fifo;
+ struct clk *pclk, *hclk;
+ struct usba_udc *udc = &the_udc;
+ int irq, ret, i;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+ fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+ if (!regs || !fifo)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+ hclk = clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(hclk)) {
+ ret = PTR_ERR(hclk);
+ goto err_get_hclk;
+ }
+
+ udc->pdev = pdev;
+ udc->pclk = pclk;
+ udc->hclk = hclk;
+ udc->vbus_pin = -1;
+
+ ret = -ENOMEM;
+ udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!udc->regs) {
+ dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+ goto err_map_regs;
+ }
+ dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+ (unsigned long)regs->start, udc->regs);
+ udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+ if (!udc->fifo) {
+ dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+ goto err_map_fifo;
+ }
+ dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+ (unsigned long)fifo->start, udc->fifo);
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ platform_set_drvdata(pdev, udc);
+
+ /* Make sure we start from a clean slate */
+ clk_enable(pclk);
+ usba_writel(udc, CTRL, 0);
+ clk_disable(pclk);
+
+ INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+ usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+ usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+ usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+ struct usba_ep *ep = &usba_ep[i];
+
+ ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+ ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+ ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ }
+
+ ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+ irq, ret);
+ goto err_request_irq;
+ }
+ udc->irq = irq;
+
+ ret = device_add(&udc->gadget.dev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+ goto err_device_add;
+ }
+
+ if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+ if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+ udc->vbus_pin = pdata->vbus_pin;
+
+ ret = request_irq(gpio_to_irq(udc->vbus_pin),
+ usba_vbus_irq, 0,
+ "atmel_usba_udc", udc);
+ if (ret) {
+ gpio_free(udc->vbus_pin);
+ udc->vbus_pin = -1;
+ dev_warn(&udc->pdev->dev,
+ "failed to request vbus irq; "
+ "assuming always on\n");
+ } else {
+ disable_irq(gpio_to_irq(udc->vbus_pin));
+ }
+ }
+ }
+
+ usba_init_debugfs(udc);
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+ usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+ return 0;
+
+err_device_add:
+ free_irq(irq, udc);
+err_request_irq:
+ iounmap(udc->fifo);
+err_map_fifo:
+ iounmap(udc->regs);
+err_map_regs:
+ clk_put(hclk);
+err_get_hclk:
+ clk_put(pclk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+ struct usba_udc *udc;
+ int i;
+
+ udc = platform_get_drvdata(pdev);
+
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+ usba_ep_cleanup_debugfs(&usba_ep[i]);
+ usba_cleanup_debugfs(udc);
+
+ if (udc->vbus_pin != -1)
+ gpio_free(udc->vbus_pin);
+
+ free_irq(udc->irq, udc);
+ iounmap(udc->fifo);
+ iounmap(udc->regs);
+ clk_put(udc->hclk);
+ clk_put(udc->pclk);
+
+ device_unregister(&udc->gadget.dev);
+
+ return 0;
+}
+
+static struct platform_driver udc_driver = {
+ .remove = __exit_p(usba_udc_remove),
+ .driver = {
+ .name = "atmel_usba_udc",
+ },
+};
+
+static int __init udc_init(void)
+{
+ return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644
index 000000000000..a68304e31a68
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL 0x0000
+#define USBA_FNUM 0x0004
+#define USBA_INT_ENB 0x0010
+#define USBA_INT_STA 0x0014
+#define USBA_INT_CLR 0x0018
+#define USBA_EPT_RST 0x001c
+#define USBA_TST 0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG 0x0000
+#define USBA_EPT_CTL_ENB 0x0004
+#define USBA_EPT_CTL_DIS 0x0008
+#define USBA_EPT_CTL 0x000c
+#define USBA_EPT_SET_STA 0x0014
+#define USBA_EPT_CLR_STA 0x0018
+#define USBA_EPT_STA 0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC 0x0000
+#define USBA_DMA_ADDRESS 0x0004
+#define USBA_DMA_CONTROL 0x0008
+#define USBA_DMA_STATUS 0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET 0
+#define USBA_DEV_ADDR_SIZE 7
+#define USBA_FADDR_EN (1 << 7)
+#define USBA_EN_USBA (1 << 8)
+#define USBA_DETACH (1 << 9)
+#define USBA_REMOTE_WAKE_UP (1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET 0
+#define USBA_MICRO_FRAME_NUM_SIZE 3
+#define USBA_FRAME_NUMBER_OFFSET 3
+#define USBA_FRAME_NUMBER_SIZE 11
+#define USBA_FRAME_NUM_ERROR (1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED (1 << 0)
+#define USBA_DET_SUSPEND (1 << 1)
+#define USBA_MICRO_SOF (1 << 2)
+#define USBA_SOF (1 << 3)
+#define USBA_END_OF_RESET (1 << 4)
+#define USBA_WAKE_UP (1 << 5)
+#define USBA_END_OF_RESUME (1 << 6)
+#define USBA_UPSTREAM_RESUME (1 << 7)
+#define USBA_EPT_INT_OFFSET 8
+#define USBA_EPT_INT_SIZE 16
+#define USBA_DMA_INT_OFFSET 24
+#define USBA_DMA_INT_SIZE 8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET 0
+#define USBA_RST_SIZE 16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET 0
+#define USBA_SPEED_CFG_SIZE 2
+#define USBA_TST_J_MODE (1 << 2)
+#define USBA_TST_K_MODE (1 << 3)
+#define USBA_TST_PKT_MODE (1 << 4)
+#define USBA_OPMODE2 (1 << 5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET 0
+#define USBA_EPT_SIZE_SIZE 3
+#define USBA_EPT_DIR_IN (1 << 3)
+#define USBA_EPT_TYPE_OFFSET 4
+#define USBA_EPT_TYPE_SIZE 2
+#define USBA_BK_NUMBER_OFFSET 6
+#define USBA_BK_NUMBER_SIZE 2
+#define USBA_NB_TRANS_OFFSET 8
+#define USBA_NB_TRANS_SIZE 2
+#define USBA_EPT_MAPPED (1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE (1 << 0)
+#define USBA_AUTO_VALID (1 << 1)
+#define USBA_INTDIS_DMA (1 << 3)
+#define USBA_NYET_DIS (1 << 4)
+#define USBA_DATAX_RX (1 << 6)
+#define USBA_MDATA_RX (1 << 7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE (1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL (1 << 5)
+#define USBA_TOGGLE_CLR (1 << 6)
+#define USBA_TOGGLE_SEQ_OFFSET 6
+#define USBA_TOGGLE_SEQ_SIZE 2
+#define USBA_ERR_OVFLW (1 << 8)
+#define USBA_RX_BK_RDY (1 << 9)
+#define USBA_KILL_BANK (1 << 9)
+#define USBA_TX_COMPLETE (1 << 10)
+#define USBA_TX_PK_RDY (1 << 11)
+#define USBA_ISO_ERR_TRANS (1 << 11)
+#define USBA_RX_SETUP (1 << 12)
+#define USBA_ISO_ERR_FLOW (1 << 12)
+#define USBA_STALL_SENT (1 << 13)
+#define USBA_ISO_ERR_CRC (1 << 13)
+#define USBA_ISO_ERR_NBTRANS (1 << 13)
+#define USBA_NAK_IN (1 << 14)
+#define USBA_ISO_ERR_FLUSH (1 << 14)
+#define USBA_NAK_OUT (1 << 15)
+#define USBA_CURRENT_BANK_OFFSET 16
+#define USBA_CURRENT_BANK_SIZE 2
+#define USBA_BUSY_BANKS_OFFSET 18
+#define USBA_BUSY_BANKS_SIZE 2
+#define USBA_BYTE_COUNT_OFFSET 20
+#define USBA_BYTE_COUNT_SIZE 11
+#define USBA_SHORT_PACKET (1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN (1 << 0)
+#define USBA_DMA_LINK (1 << 1)
+#define USBA_DMA_END_TR_EN (1 << 2)
+#define USBA_DMA_END_BUF_EN (1 << 3)
+#define USBA_DMA_END_TR_IE (1 << 4)
+#define USBA_DMA_END_BUF_IE (1 << 5)
+#define USBA_DMA_DESC_LOAD_IE (1 << 6)
+#define USBA_DMA_BURST_LOCK (1 << 7)
+#define USBA_DMA_BUF_LEN_OFFSET 16
+#define USBA_DMA_BUF_LEN_SIZE 16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE (1 << 1)
+#define USBA_DMA_END_TR_ST (1 << 4)
+#define USBA_DMA_END_BUF_ST (1 << 5)
+#define USBA_DMA_DESC_LOAD_ST (1 << 6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL 0
+#define USBA_SPEED_CFG_FORCE_HIGH 2
+#define USBA_SPEED_CFG_FORCE_FULL 3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8 0
+#define USBA_EPT_SIZE_16 1
+#define USBA_EPT_SIZE_32 2
+#define USBA_EPT_SIZE_64 3
+#define USBA_EPT_SIZE_128 4
+#define USBA_EPT_SIZE_256 5
+#define USBA_EPT_SIZE_512 6
+#define USBA_EPT_SIZE_1024 7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL 0
+#define USBA_EPT_TYPE_ISO 1
+#define USBA_EPT_TYPE_BULK 2
+#define USBA_EPT_TYPE_INT 3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO 0
+#define USBA_BK_NUMBER_ONE 1
+#define USBA_BK_NUMBER_DOUBLE 2
+#define USBA_BK_NUMBER_TRIPLE 3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value) \
+ (((value) & ((1 << USBA_##name##_SIZE) - 1)) \
+ << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value) \
+ (((value) >> USBA_##name##_OFFSET) \
+ & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old) \
+ (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \
+ << USBA_##name##_OFFSET)) \
+ | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg) \
+ __raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value) \
+ __raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg) \
+ __raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value) \
+ __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg) \
+ __raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value) \
+ __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x) ((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS 7
+
+#define EP0_FIFO_SIZE 64
+#define EP0_EPT_SIZE USBA_EPT_SIZE_64
+#define EP0_NR_BANKS 1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID 0
+#define CTRL_IOMEM_ID 1
+
+#ifdef DEBUG
+#define DBG_ERR 0x0001 /* report all error returns */
+#define DBG_HW 0x0002 /* debug hardware initialization */
+#define DBG_GADGET 0x0004 /* calls to/from gadget driver */
+#define DBG_INT 0x0008 /* interrupts */
+#define DBG_BUS 0x0010 /* report changes in bus state */
+#define DBG_QUEUE 0x0020 /* debug request queue processing */
+#define DBG_FIFO 0x0040 /* debug FIFO contents */
+#define DBG_DMA 0x0080 /* debug DMA handling */
+#define DBG_REQ 0x0100 /* print out queued request length */
+#define DBG_ALL 0xffff
+#define DBG_NONE 0x0000
+
+#define DEBUG_LEVEL (DBG_ERR)
+#define DBG(level, fmt, ...) \
+ do { \
+ if ((level) & DEBUG_LEVEL) \
+ printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+ WAIT_FOR_SETUP,
+ DATA_STAGE_IN,
+ DATA_STAGE_OUT,
+ STATUS_STAGE_IN,
+ STATUS_STAGE_OUT,
+ STATUS_STAGE_ADDR,
+ STATUS_STAGE_TEST,
+};
+/*
+ EP_STATE_IDLE,
+ EP_STATE_SETUP,
+ EP_STATE_IN_DATA,
+ EP_STATE_OUT_DATA,
+ EP_STATE_SET_ADDR_STATUS,
+ EP_STATE_RX_STATUS,
+ EP_STATE_TX_STATUS,
+ EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+ dma_addr_t next;
+ dma_addr_t addr;
+ u32 ctrl;
+};
+
+struct usba_ep {
+ int state;
+ void __iomem *ep_regs;
+ void __iomem *dma_regs;
+ void __iomem *fifo;
+ struct usb_ep ep;
+ struct usba_udc *udc;
+
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+
+ u16 fifo_size;
+ u8 nr_banks;
+ u8 index;
+ unsigned int can_dma:1;
+ unsigned int can_isoc:1;
+ unsigned int is_isoc:1;
+ unsigned int is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ u32 last_dma_status;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_queue;
+ struct dentry *debugfs_dma_status;
+ struct dentry *debugfs_state;
+#endif
+};
+
+struct usba_request {
+ struct usb_request req;
+ struct list_head queue;
+
+ u32 ctrl;
+
+ unsigned int submitted:1;
+ unsigned int last_transaction:1;
+ unsigned int using_dma:1;
+ unsigned int mapped:1;
+};
+
+struct usba_udc {
+ /* Protect hw registers from concurrent modifications */
+ spinlock_t lock;
+
+ void __iomem *regs;
+ void __iomem *fifo;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct platform_device *pdev;
+ int irq;
+ int vbus_pin;
+ struct clk *pclk;
+ struct clk *hclk;
+
+ u16 devstatus;
+
+ u16 test_mode;
+ int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+ return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep) ((ep)->index == 0)
+#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index d18901b92cda..a4e54b2743f0 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -25,7 +25,7 @@
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/**
@@ -50,7 +50,7 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen,
return -EINVAL;
/* fill buffer from src[] until null descriptor ptr */
- for (; 0 != *src; src++) {
+ for (; NULL != *src; src++) {
unsigned len = (*src)->bLength;
if (len > buflen)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index f2fbdc7fe376..9db2482bdfa2 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -34,8 +34,6 @@
* bypassing some hardware (and driver) issues. UML could help too.
*/
-#define DEBUG
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -48,7 +46,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -964,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
static int dummy_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
unsigned long flags;
+ int rc;
if (!urb->transfer_buffer && urb->transfer_buffer_length)
return -EINVAL;
@@ -982,6 +980,11 @@ static int dummy_urb_enqueue (
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
+ rc = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (rc) {
+ kfree(urbp);
+ goto done;
+ }
if (!dum->udev) {
dum->udev = urb->dev;
@@ -998,36 +1001,35 @@ static int dummy_urb_enqueue (
if (!timer_pending (&dum->timer))
mod_timer (&dum->timer, jiffies + 1);
- spin_unlock_irqrestore (&dum->lock, flags);
- return 0;
+ done:
+ spin_unlock_irqrestore(&dum->lock, flags);
+ return rc;
}
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct dummy *dum;
unsigned long flags;
+ int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
- if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+ !list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
- spin_unlock_irqrestore (&dum->lock, flags);
- return 0;
-}
-static void maybe_set_status (struct urb *urb, int status)
-{
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock (&urb->lock);
+ spin_unlock_irqrestore (&dum->lock, flags);
+ return rc;
}
/* transfer up to a frame's worth; caller must own lock */
static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+ int *status)
{
struct dummy_request *req;
@@ -1090,24 +1092,20 @@ top:
*
* partially filling a buffer optionally blocks queue advances
* (so completion handlers can clean up the queue) but we don't
- * need to emulate such data-in-flight. so we only show part
- * of the URB_SHORT_NOT_OK effect: completion status.
+ * need to emulate such data-in-flight.
*/
if (is_short) {
if (host_len == dev_len) {
req->req.status = 0;
- maybe_set_status (urb, 0);
+ *status = 0;
} else if (to_host) {
req->req.status = 0;
if (dev_len > host_len)
- maybe_set_status (urb, -EOVERFLOW);
+ *status = -EOVERFLOW;
else
- maybe_set_status (urb,
- (urb->transfer_flags
- & URB_SHORT_NOT_OK)
- ? -EREMOTEIO : 0);
+ *status = 0;
} else if (!to_host) {
- maybe_set_status (urb, 0);
+ *status = 0;
if (host_len > dev_len)
req->req.status = -EOVERFLOW;
else
@@ -1121,9 +1119,8 @@ top:
req->req.status = 0;
if (urb->transfer_buffer_length == urb->actual_length
&& !(urb->transfer_flags
- & URB_ZERO_PACKET)) {
- maybe_set_status (urb, 0);
- }
+ & URB_ZERO_PACKET))
+ *status = 0;
}
/* device side completion --> continuable */
@@ -1139,7 +1136,7 @@ top:
}
/* host side completion --> terminate */
- if (urb->status != -EINPROGRESS)
+ if (*status != -EINPROGRESS)
break;
/* rescan to continue with any other queued i/o */
@@ -1250,12 +1247,12 @@ restart:
u8 address;
struct dummy_ep *ep = NULL;
int type;
+ int status = -EINPROGRESS;
urb = urbp->urb;
- if (urb->status != -EINPROGRESS) {
- /* likely it was just unlinked */
+ if (urb->unlinked)
goto return_urb;
- } else if (dum->rh_state != DUMMY_RH_RUNNING)
+ else if (dum->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype (urb->pipe);
@@ -1276,7 +1273,7 @@ restart:
dev_dbg (dummy_dev(dum),
"no ep configured for urb %p\n",
urb);
- maybe_set_status (urb, -EPROTO);
+ status = -EPROTO;
goto return_urb;
}
@@ -1291,7 +1288,7 @@ restart:
/* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
ep->ep.name, urb);
- maybe_set_status (urb, -EPIPE);
+ status = -EPIPE;
goto return_urb;
}
/* FIXME make sure both ends agree on maxpacket */
@@ -1309,7 +1306,7 @@ restart:
w_value = le16_to_cpu(setup.wValue);
if (le16_to_cpu(setup.wLength) !=
urb->transfer_buffer_length) {
- maybe_set_status (urb, -EOVERFLOW);
+ status = -EOVERFLOW;
goto return_urb;
}
@@ -1339,7 +1336,7 @@ restart:
if (setup.bRequestType != Dev_Request)
break;
dum->address = w_value;
- maybe_set_status (urb, 0);
+ status = 0;
dev_dbg (udc_dev(dum), "set_address = %d\n",
w_value);
value = 0;
@@ -1366,7 +1363,7 @@ restart:
if (value == 0) {
dum->devstatus |=
(1 << w_value);
- maybe_set_status (urb, 0);
+ status = 0;
}
} else if (setup.bRequestType == Ep_Request) {
@@ -1378,7 +1375,7 @@ restart:
}
ep2->halted = 1;
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
case USB_REQ_CLEAR_FEATURE:
@@ -1388,7 +1385,7 @@ restart:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
break;
default:
value = -EOPNOTSUPP;
@@ -1403,7 +1400,7 @@ restart:
}
ep2->halted = 0;
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
case USB_REQ_GET_STATUS:
@@ -1440,7 +1437,7 @@ restart:
urb->actual_length = min (2,
urb->transfer_buffer_length);
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
}
@@ -1467,7 +1464,7 @@ restart:
dev_dbg (udc_dev(dum),
"setup --> %d\n",
value);
- maybe_set_status (urb, -EPIPE);
+ status = -EPIPE;
urb->actual_length = 0;
}
@@ -1484,7 +1481,7 @@ restart:
* report random errors, to debug drivers.
*/
limit = max (limit, periodic_bytes (dum, ep));
- maybe_set_status (urb, -ENOSYS);
+ status = -ENOSYS;
break;
case PIPE_INTERRUPT:
@@ -1498,23 +1495,23 @@ restart:
default:
treat_control_like_bulk:
ep->last_io = jiffies;
- total = transfer (dum, urb, ep, limit);
+ total = transfer(dum, urb, ep, limit, &status);
break;
}
/* incomplete transfer? */
- if (urb->status == -EINPROGRESS)
+ if (status == -EINPROGRESS)
continue;
return_urb:
- urb->hcpriv = NULL;
list_del (&urbp->urbp_list);
kfree (urbp);
if (ep)
ep->already_seen = ep->setup_stage = 0;
+ usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
spin_unlock (&dum->lock);
- usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+ usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
spin_lock (&dum->lock);
goto restart;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 6042364402b8..f9d07108bc30 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -28,7 +28,7 @@
#include <linux/string.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -71,7 +71,7 @@ ep_matches (
u16 max;
/* endpoint already claimed? */
- if (0 != ep->driver_data)
+ if (NULL != ep->driver_data)
return 0;
/* only support ep0 for portable CONTROL traffic */
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index dbaf867436df..9e732bff9df0 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -19,40 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/* #define VERBOSE_DEBUG */
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
#include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -305,6 +283,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DEV_CONFIG_CDC
+#endif
+
/*-------------------------------------------------------------------------*/
@@ -352,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
#define qlen(gadget) \
(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY qmult
-
static inline int BITRATE(struct usb_gadget *g)
{
return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
}
#else /* full speed (low speed doesn't do bulk) */
+
+#define qmult 1
+
#define DEVSPEED USB_SPEED_FULL
#define qlen(gadget) DEFAULT_QLEN
@@ -386,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
#define VDEBUG DEBUG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -826,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
};
#endif
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -930,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
}
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
@@ -985,22 +962,19 @@ static struct usb_gadget_strings stringtab = {
* complications: class descriptors, and an altsetting.
*/
static int
-config_buf (enum usb_device_speed speed,
- u8 *buf, u8 type,
- unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
{
int len;
const struct usb_config_descriptor *config;
const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (speed == USB_SPEED_HIGH);
+ int hs = 0;
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(g)) {
+ hs = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define which_fn(t) (fs_ ## t ## _function)
-#endif
if (index >= device_desc.bNumConfigurations)
return -EINVAL;
@@ -1213,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
if (number)
eth_reset_config (dev);
usb_gadget_vbus_draw(dev->gadget,
- dev->gadget->is_otg ? 8 : 100);
+ gadget_is_otg(dev->gadget) ? 8 : 100);
} else {
char *speed;
unsigned power;
@@ -1395,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
value = min (wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- value = config_buf (gadget->speed, req->buf,
+ value = config_buf(gadget, req->buf,
wValue >> 8,
wValue & 0xff,
- gadget->is_otg);
+ gadget_is_otg(gadget));
if (value >= 0)
value = min (wLength, (u16) value);
break;
@@ -1581,12 +1553,12 @@ done_set_intf:
&& rndis_control_intf.bInterfaceNumber
== wIndex) {
u8 *buf;
+ u32 n;
/* return the result */
- buf = rndis_get_next_response (dev->rndis_config,
- &value);
+ buf = rndis_get_next_response(dev->rndis_config, &n);
if (buf) {
- memcpy (req->buf, buf, value);
+ memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
rndis_free_response(dev->rndis_config, buf);
}
@@ -1719,7 +1691,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
size += sizeof (struct rndis_packet_msg_type);
size -= size % dev->out_ep->maxpacket;
- if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
+ skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+ if (skb == NULL) {
DEBUG (dev, "no rx skb\n");
goto enomem;
}
@@ -1984,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
spin_lock_irqsave(&dev->req_lock, flags);
+ /*
+ * this freelist can be empty if an interrupt triggered disconnect()
+ * and reconfigured the gadget (shutting down this queue) after the
+ * network stack decided to xmit but before we got the spinlock.
+ */
+ if (list_empty(&dev->tx_reqs)) {
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+ return 1;
+ }
+
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
+
+ /* temporarily stop TX queue when the freelist empties */
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2021,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
req->length = length;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
- req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
- ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
- : 0;
-#endif
+ if (gadget_is_dualspeed(dev->gadget))
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+ : 0;
retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
switch (retval) {
@@ -2183,8 +2167,7 @@ static int eth_stop (struct net_device *net)
}
if (rndis_active(dev)) {
- rndis_set_param_medium (dev->rndis_config,
- NDIS_MEDIUM_802_3, 0);
+ rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
(void) rndis_signal_disconnect (dev->rndis_config);
}
@@ -2438,26 +2421,28 @@ autoconf_fail:
if (rndis)
device_desc.bNumConfigurations = 2;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (rndis)
- dev_qualifier.bNumConfigurations = 2;
- else if (!cdc)
- dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+ if (gadget_is_dualspeed(gadget)) {
+ if (rndis)
+ dev_qualifier.bNumConfigurations = 2;
+ else if (!cdc)
+ dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
- /* assumes ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ /* assumes ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
- if (status_ep)
- hs_status_desc.bEndpointAddress =
- fs_status_desc.bEndpointAddress;
+ if (status_ep)
+ hs_status_desc.bEndpointAddress =
+ fs_status_desc.bEndpointAddress;
#endif
-#endif /* DUALSPEED */
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
eth_config.bMaxPower = 4;
@@ -2479,7 +2464,6 @@ autoconf_fail:
/* network device setup */
dev->net = net;
- SET_MODULE_OWNER (net);
strcpy (net->name, "usb%d");
dev->cdc = cdc;
dev->zlp = zlp;
@@ -2594,12 +2578,11 @@ fail0:
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats, &dev->cdc_filter))
goto fail0;
- if (rndis_set_param_vendor (dev->rndis_config, vendorID,
- manufacturer))
+ if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+ manufacturer))
goto fail0;
- if (rndis_set_param_medium (dev->rndis_config,
- NDIS_MEDIUM_802_3,
- 0))
+ if (rndis_set_param_medium(dev->rndis_config,
+ NDIS_MEDIUM_802_3, 0))
goto fail0;
INFO (dev, "RNDIS ready\n");
}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index be7a1bd2823b..73726c570a6e 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,17 +217,11 @@
*/
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
-
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/bitops.h>
#include <linux/blkdev.h>
-#include <linux/compiler.h>
#include <linux/completion.h>
#include <linux/dcache.h>
#include <linux/delay.h>
@@ -235,18 +229,10 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -254,7 +240,7 @@
#include <linux/utsname.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -263,7 +249,7 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-#define DRIVER_VERSION "28 November 2005"
+#define DRIVER_VERSION "7 August 2007"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
/*-------------------------------------------------------------------------*/
-#define xprintk(f,level,fmt,args...) \
- dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
- dev_printk(level , &(l)->dev , fmt , ## args)
-
#ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
- xprintk(fsg , KERN_DEBUG , fmt , ## args)
#define LDBG(lun,fmt,args...) \
- yprintk(lun , KERN_DEBUG , fmt , ## args)
+ dev_dbg(&(lun)->dev , fmt , ## args)
#define MDBG(fmt,args...) \
printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
#else
-#define DBG(fsg,fmt,args...) \
- do { } while (0)
#define LDBG(lun,fmt,args...) \
do { } while (0)
#define MDBG(fmt,args...) \
do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
#undef DUMP_MSGS
#endif /* DEBUG */
-#ifdef VERBOSE
-#define VDBG DBG
+#ifdef VERBOSE_DEBUG
#define VLDBG LDBG
#else
-#define VDBG(fsg,fmt,args...) \
- do { } while (0)
#define VLDBG(lun,fmt,args...) \
do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
-#define ERROR(fsg,fmt,args...) \
- xprintk(fsg , KERN_ERR , fmt , ## args)
#define LERROR(lun,fmt,args...) \
- yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
- xprintk(fsg , KERN_WARNING , fmt , ## args)
+ dev_err(&(lun)->dev , fmt , ## args)
#define LWARN(lun,fmt,args...) \
- yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
- xprintk(fsg , KERN_INFO , fmt , ## args)
+ dev_warn(&(lun)->dev , fmt , ## args)
#define LINFO(lun,fmt,args...) \
- yprintk(lun , KERN_INFO , fmt , ## args)
+ dev_info(&(lun)->dev , fmt , ## args)
#define MINFO(fmt,args...) \
printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
+
/*-------------------------------------------------------------------------*/
@@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
static struct {
char *file[MAX_LUNS];
int ro[MAX_LUNS];
- int num_filenames;
- int num_ros;
+ unsigned int num_filenames;
+ unsigned int num_ros;
unsigned int nluns;
int removable;
@@ -578,7 +555,7 @@ struct lun {
#define backing_file_is_open(curlun) ((curlun)->filp != NULL)
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
{
return container_of(dev, struct lun, dev);
}
@@ -599,7 +576,6 @@ enum fsg_buffer_state {
struct fsg_buffhd {
void *buf;
- dma_addr_t dma;
enum fsg_buffer_state state;
struct fsg_buffhd *next;
@@ -712,13 +688,13 @@ struct fsg_dev {
typedef void (*fsg_routine_t)(struct fsg_dev *);
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
{
return (fsg->state > FSG_STATE_IDLE);
}
/* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
struct fsg_buffhd *bh, unsigned int length)
{
unsigned int rem;
@@ -744,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg);
static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{
- unsigned int start, num, i;
- char line[52], *p;
-
- if (length >= 512)
- return;
- DBG(fsg, "%s, length %u:\n", label, length);
-
- start = 0;
- while (length > 0) {
- num = min(length, 16u);
- p = line;
- for (i = 0; i < num; ++i) {
- if (i == 8)
- *p++ = ' ';
- sprintf(p, " %02x", buf[i]);
- p += 3;
- }
- *p = 0;
- printk(KERN_DEBUG "%6x: %s\n", start, line);
- buf += num;
- start += num;
- length -= num;
+ if (length < 512) {
+ DBG(fsg, "%s, length %u:\n", label, length);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, length, 0);
}
}
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
{}
#else
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{}
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
- int i;
- char cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
- for (i = 0; i < fsg->cmnd_size; ++i)
- sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
- VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+ 16, 1, fsg->cmnd, fsg->cmnd_size, 0);
}
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
#endif /* DUMP_MSGS */
@@ -810,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Routines for unaligned data access */
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
{
return ((u16) buf[0] << 8) | ((u16) buf[1]);
}
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
{
return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
((u32) buf[2] << 8) | ((u32) buf[3]);
}
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
{
buf[0] = val >> 8;
buf[1] = val;
}
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
@@ -951,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
#define FS_FUNCTION_PRE_EP_ENTRIES 2
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -1015,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
#define HS_FUNCTION_PRE_EP_ENTRIES 2
/* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs) fs
-
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+ struct usb_endpoint_descriptor *hs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
/* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1054,26 +1014,22 @@ static struct usb_gadget_strings stringtab = {
static int populate_config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
-#ifdef CONFIG_USB_GADGET_DUALSPEED
enum usb_device_speed speed = gadget->speed;
-#endif
int len;
const struct usb_descriptor_header **function;
if (index > 0)
return -EINVAL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (type == USB_DT_OTHER_SPEED_CONFIG)
+ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
- if (speed == USB_SPEED_HIGH)
+ if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
function = hs_function;
else
-#endif
function = fs_function;
/* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
+ if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1295,6 +1251,7 @@ static int class_setup_req(struct fsg_dev *fsg,
struct usb_request *req = fsg->ep0req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
if (!fsg->config)
@@ -1308,7 +1265,7 @@ static int class_setup_req(struct fsg_dev *fsg,
if (ctrl->bRequestType != (USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (w_index != 0) {
+ if (w_index != 0 || w_value != 0) {
value = -EDOM;
break;
}
@@ -1324,7 +1281,7 @@ static int class_setup_req(struct fsg_dev *fsg,
if (ctrl->bRequestType != (USB_DIR_IN |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (w_index != 0) {
+ if (w_index != 0 || w_value != 0) {
value = -EDOM;
break;
}
@@ -1343,7 +1300,7 @@ static int class_setup_req(struct fsg_dev *fsg,
if (ctrl->bRequestType != (USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (w_index != 0) {
+ if (w_index != 0 || w_value != 0) {
value = -EDOM;
break;
}
@@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
- if (!fsg->gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(fsg->gadget))
break;
value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
- if (!fsg->gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(fsg->gadget))
break;
goto get_config;
-#endif
case USB_DT_CONFIG:
VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- get_config:
-#endif
+get_config:
value = populate_config_buf(fsg->gadget,
req->buf,
w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
}
/* Wait for something to happen */
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
/* Wait for the next buffer to be free */
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
}
/* Otherwise wait for something to happen */
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2611,7 +2569,6 @@ static int send_status(struct fsg_dev *fsg)
fsg->intr_buffhd = bh; // Point to the right buffhd
fsg->intreq->buf = bh->inreq->buf;
- fsg->intreq->dma = bh->inreq->dma;
fsg->intreq->context = bh;
start_transfer(fsg, fsg->intr_in, fsg->intreq,
&fsg->intreq_busy, &bh->state);
@@ -2772,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available for data or status */
bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
fsg->phase_error = 0;
fsg->short_packet_received = 0;
@@ -3006,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Is the CBW meaningful? */
if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
- cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
cbw->Lun, cbw->Flags, cbw->Length);
@@ -3046,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3062,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the CBW to arrive */
while (bh->state != BUF_STATE_FULL) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
smp_rmb();
rc = received_cbw(fsg, bh);
bh->state = BUF_STATE_EMPTY;
@@ -3073,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next command to arrive */
while (fsg->cbbuf_cmnd_size == 0) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
/* Is the previous status interrupt request still busy?
* The host is allowed to skip reading the status,
@@ -3200,7 +3161,6 @@ reset:
if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
goto reset;
bh->inreq->buf = bh->outreq->buf = bh->buf;
- bh->inreq->dma = bh->outreq->dma = bh->dma;
bh->inreq->context = bh->outreq->context = bh;
bh->inreq->complete = bulk_in_complete;
bh->outreq->complete = bulk_out_complete;
@@ -3597,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
return sprintf(buf, "%d\n", curlun->ro);
}
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@@ -3606,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
down_read(&fsg->filesem);
if (backing_file_is_open(curlun)) { // Get the complete pathname
- p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
- buf, PAGE_SIZE - 1);
+ p = d_path(curlun->filp->f_path.dentry,
+ curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
if (IS_ERR(p))
rc = PTR_ERR(p);
else {
@@ -3625,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
}
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
@@ -3649,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
return rc;
}
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@@ -3861,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Find out how many LUNs there should be */
i = mod_data.nluns;
if (i == 0)
- i = max(mod_data.num_filenames, 1);
+ i = max(mod_data.num_filenames, 1u);
if (i > MAX_LUNS) {
ERROR(fsg, "invalid number of LUNs: %d\n", i);
rc = -EINVAL;
@@ -3946,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
intf_desc.bInterfaceProtocol = mod_data.transport_type;
fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+ if (gadget_is_dualspeed(gadget)) {
+ hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
- /* Assume ep0 uses the same maxpacket value for both speeds */
- dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+ /* Assume ep0 uses the same maxpacket value for both speeds */
+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
- /* Assume that all endpoint addresses are the same for both speeds */
- hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
- hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
- hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
+ /* Assume endpoint addresses are the same for both speeds */
+ hs_bulk_in_desc.bEndpointAddress =
+ fs_bulk_in_desc.bEndpointAddress;
+ hs_bulk_out_desc.bEndpointAddress =
+ fs_bulk_out_desc.bEndpointAddress;
+ hs_intr_in_desc.bEndpointAddress =
+ fs_intr_in_desc.bEndpointAddress;
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget))
otg_desc.bmAttributes |= USB_OTG_HNP;
- }
rc = -ENOMEM;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 10b2b33b8698..9bb7f64a85cd 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -35,7 +35,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
*/
static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
-#ifdef CONFIG_USB_OTG
struct fsl_udc *udc;
udc = container_of(gadget, struct fsl_udc, gadget);
-
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
-#endif
return -ENOTSUPP;
}
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
static struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
@@ -1277,31 +1274,32 @@ static void setup_received_irq(struct fsl_udc *udc,
udc_reset_ep_queue(udc, 0);
+ /* We process some stardard setup requests here */
switch (setup->bRequest) {
- /* Request that need Data+Status phase from udc */
case USB_REQ_GET_STATUS:
- if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD))
+ /* Data+Status phase from udc */
+ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
!= (USB_DIR_IN | USB_TYPE_STANDARD))
break;
ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
- break;
+ return;
- /* Requests that need Status phase from udc */
case USB_REQ_SET_ADDRESS:
+ /* Status phase from udc */
if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
| USB_RECIP_DEVICE))
break;
ch9setaddress(udc, wValue, wIndex, wLength);
- break;
+ return;
- /* Handled by udc, no data, status by udc */
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
- { /* status transaction */
+ /* Status phase from udc */
+ {
int rc = -EOPNOTSUPP;
- if ((setup->bRequestType & USB_RECIP_MASK)
- == USB_RECIP_ENDPOINT) {
+ if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+ == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
int pipe = get_pipe_by_windex(wIndex);
struct fsl_ep *ep;
@@ -1315,11 +1313,12 @@ static void setup_received_irq(struct fsl_udc *udc,
? 1 : 0);
spin_lock(&udc->lock);
- } else if ((setup->bRequestType & USB_RECIP_MASK)
- == USB_RECIP_DEVICE) {
+ } else if ((setup->bRequestType & (USB_RECIP_MASK
+ | USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+ | USB_TYPE_STANDARD)) {
/* Note: The driver has not include OTG support yet.
* This will be set when OTG support is added */
- if (!udc->gadget.is_otg)
+ if (!gadget_is_otg(udc->gadget))
break;
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
udc->gadget.b_hnp_enable = 1;
@@ -1328,40 +1327,45 @@ static void setup_received_irq(struct fsl_udc *udc,
else if (setup->bRequest ==
USB_DEVICE_A_ALT_HNP_SUPPORT)
udc->gadget.a_alt_hnp_support = 1;
+ else
+ break;
rc = 0;
- }
+ } else
+ break;
+
if (rc == 0) {
if (ep0_prime_status(udc, EP_DIR_IN))
ep0stall(udc);
}
- break;
+ return;
}
- /* Requests handled by gadget */
- default:
- if (wLength) {
- /* Data phase from gadget, status phase from udc */
- udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
- ? USB_DIR_IN : USB_DIR_OUT;
- spin_unlock(&udc->lock);
- if (udc->driver->setup(&udc->gadget,
- &udc->local_setup_buff) < 0)
- ep0stall(udc);
- spin_lock(&udc->lock);
- udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
- ? DATA_STATE_XMIT : DATA_STATE_RECV;
- } else {
- /* No data phase, IN status from gadget */
- udc->ep0_dir = USB_DIR_IN;
- spin_unlock(&udc->lock);
- if (udc->driver->setup(&udc->gadget,
- &udc->local_setup_buff) < 0)
- ep0stall(udc);
- spin_lock(&udc->lock);
- udc->ep0_state = WAIT_FOR_OUT_STATUS;
- }
+ default:
break;
}
+
+ /* Requests handled by gadget */
+ if (wLength) {
+ /* Data phase from gadget, status phase from udc */
+ udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+ ? USB_DIR_IN : USB_DIR_OUT;
+ spin_unlock(&udc->lock);
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
+ ? DATA_STATE_XMIT : DATA_STATE_RECV;
+ } else {
+ /* No data phase, IN status from gadget */
+ udc->ep0_dir = USB_DIR_IN;
+ spin_unlock(&udc->lock);
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) < 0)
+ ep0stall(udc);
+ spin_lock(&udc->lock);
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
}
/* Process request for Data or Status phase of ep0
@@ -1835,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!driver || driver != udc_controller->driver || !driver->unbind)
return -EINVAL;
-#ifdef CONFIG_USB_OTG
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 53e9139ba388..f7f159c1002b 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -17,6 +17,12 @@
#define gadget_is_net2280(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define gadget_is_amd5536udc(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
#else
@@ -202,7 +208,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
return 0x19;
- else if (gadget_is_m66592(gadget))
+ else if (gadget_is_amd5536udc(gadget))
return 0x20;
+ else if (gadget_is_m66592(gadget))
+ return 0x21;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 1c5aa49d7432..0689189550bc 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -18,17 +18,11 @@
* http://www.usb.org/developers/devclass_docs/midi10.pdf
*/
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
#include <sound/driver.h>
#include <sound/core.h>
@@ -36,7 +30,7 @@
#include <sound/rawmidi.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
@@ -139,30 +133,16 @@ struct gmidi_device {
static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
-#define xprintk(d,level,fmt,args...) \
- dev_printk(level , &(d)->gadget->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 DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
return len;
}
-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;
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
* Receives a chunk of MIDI data.
*/
static void gmidi_read_data(struct usb_ep *ep, int cable,
- uint8_t* data, int length)
+ uint8_t *data, int length)
{
struct gmidi_device *dev = ep->driver_data;
/* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
{
int err = 0;
struct usb_request *req;
- struct usb_ep* ep;
+ struct usb_ep *ep;
unsigned i;
err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
- INFO(dev, "can't change configurations\n");
+ ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
gmidi_reset_config(dev);
@@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
{
struct gmidi_device *dev = get_gadget_data(gadget);
- struct snd_card* card;
+ struct snd_card *card;
DBG(dev, "unbind\n");
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
return 0;
}
-static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
uint8_t p1, uint8_t p2, uint8_t p3)
{
unsigned length = req->length;
+ u8 *buf = (u8 *)req->buf + length;
- uint8_t* buf = (uint8_t*)req->buf + length;
buf[0] = p0;
buf[1] = p1;
buf[2] = p2;
@@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
/*
* Converts MIDI commands to USB MIDI packets.
*/
-static void gmidi_transmit_byte(struct usb_request* req,
- struct gmidi_in_port* port, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+ struct gmidi_in_port *port, uint8_t b)
{
uint8_t p0 = port->cable;
@@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
}
}
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
{
- struct usb_ep* ep = dev->in_ep;
- struct gmidi_in_port* port = &dev->in_port;
+ struct usb_ep *ep = dev->in_ep;
+ struct gmidi_in_port *port = &dev->in_port;
if (!ep) {
return;
@@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
static void gmidi_in_tasklet(unsigned long data)
{
- struct gmidi_device* dev = (struct gmidi_device*)data;
+ struct gmidi_device *dev = (struct gmidi_device *)data;
gmidi_transmit(dev, NULL);
}
static int gmidi_in_open(struct snd_rawmidi_substream *substream)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_open\n");
dev->in_substream = substream;
@@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
static int gmidi_in_close(struct snd_rawmidi_substream *substream)
{
+ struct gmidi_device *dev = substream->rmidi->private_data;
+
VDBG(dev, "gmidi_in_close\n");
return 0;
}
static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_trigger %d\n", up);
dev->in_port.active = up;
@@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
static int gmidi_out_open(struct snd_rawmidi_substream *substream)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_open\n");
dev->out_substream = substream;
@@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
static int gmidi_out_close(struct snd_rawmidi_substream *substream)
{
+ struct gmidi_device *dev = substream->rmidi->private_data;
+
VDBG(dev, "gmidi_out_close\n");
return 0;
}
static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_trigger %d\n", up);
if (up) {
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d6c5f1150ae7..2ec9d196a8cf 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -37,7 +37,7 @@
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -1777,14 +1777,13 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* alloc, and start init */
- dev = kmalloc (sizeof *dev, GFP_KERNEL);
+ dev = kzalloc (sizeof *dev, GFP_KERNEL);
if (dev == NULL){
pr_debug("enomem %s\n", pci_name(pdev));
retval = -ENOMEM;
goto done;
}
- memset(dev, 0, sizeof *dev);
spin_lock_init(&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &goku_ops;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index e60745ffaf8e..47ef8bd58a00 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,8 +20,7 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
-// #define VERBOSE /* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
#include <linux/init.h>
#include <linux/module.h>
@@ -38,7 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/*
@@ -253,7 +252,7 @@ static const char *CHIP;
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
#define VDEBUG DBG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -964,7 +963,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
}
if (len > sizeof (dev->rbuf))
req->buf = kmalloc(len, GFP_ATOMIC);
- if (req->buf == 0) {
+ if (req->buf == NULL) {
req->buf = dev->rbuf;
return -ENOMEM;
}
@@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
unsigned power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (dev->gadget->speed == USB_SPEED_HIGH)
+
+ if (gadget_is_dualspeed(dev->gadget)
+ && (dev->gadget->speed
+ == USB_SPEED_HIGH))
power = dev->hs_config->bMaxPower;
else
-#endif
power = dev->config->bMaxPower;
usb_gadget_vbus_draw(dev->gadget, 2 * power);
}
@@ -1355,24 +1355,21 @@ static int
config_buf (struct dev_data *dev, u8 type, unsigned index)
{
int len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs;
-#endif
+ int hs = 0;
/* only one configuration */
if (index > 0)
return -EINVAL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs = (dev->gadget->speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(dev->gadget)) {
+ hs = (dev->gadget->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
if (hs) {
dev->req->buf = dev->hs_config;
len = le16_to_cpu(dev->hs_config->wTotalLength);
- } else
-#endif
- {
+ } else {
dev->req->buf = dev->config;
len = le16_to_cpu(dev->config->wTotalLength);
}
@@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+ if (gadget_is_dualspeed(gadget)
+ && gadget->speed == USB_SPEED_HIGH
+ && dev->hs_config == NULL) {
spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
dev->state = STATE_DEV_CONNECTED;
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
// user mode expected to disable endpoints
} else {
u8 config, power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH) {
+
+ if (gadget_is_dualspeed(gadget)
+ && gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue;
power = dev->hs_config->bMaxPower;
- } else
-#endif
- {
+ } else {
config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index b3fe197e1eeb..1ecfd6366b9a 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -50,7 +50,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/*
* Memory map
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 0174a322e007..ebc5536aa271 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -21,26 +21,18 @@
*/
#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/list.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
#include "m66592-udc.h"
-MODULE_DESCRIPTION("M66592 USB gadget driiver");
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
@@ -49,16 +41,21 @@ MODULE_AUTHOR("Yoshihiro Shimoda");
/* module parameters */
static unsigned short clock = M66592_XTAL24;
module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+ "(default=16384)");
+
static unsigned short vif = M66592_LDRV;
module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
static unsigned short irq_sense = M66592_INTL;
module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+ "(default=2)");
static const char udc_name[] = "m66592_udc";
static const char *m66592_ep_name[] = {
@@ -72,8 +69,8 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags);
static void transfer_complete(struct m66592_ep *ep,
- struct m66592_request *req,
- int status);
+ struct m66592_request *req, int status);
+
/*-------------------------------------------------------------------------*/
static inline u16 get_usb_speed(struct m66592 *m66592)
{
@@ -81,25 +78,25 @@ static inline u16 get_usb_speed(struct m66592 *m66592)
}
static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
- unsigned long reg)
+ unsigned long reg)
{
u16 tmp;
tmp = m66592_read(m66592, M66592_INTENB0);
m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bset(m66592, (1 << pipenum), reg);
m66592_write(m66592, tmp, M66592_INTENB0);
}
static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
- unsigned long reg)
+ unsigned long reg)
{
u16 tmp;
tmp = m66592_read(m66592, M66592_INTENB0);
m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bclr(m66592, (1 << pipenum), reg);
m66592_write(m66592, tmp, M66592_INTENB0);
}
@@ -108,17 +105,19 @@ static void m66592_usb_connect(struct m66592 *m66592)
{
m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
}
static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
@@ -148,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
}
static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
- u16 pid)
+ u16 pid)
{
unsigned long offset;
@@ -250,7 +249,7 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
}
static int pipe_buffer_setting(struct m66592 *m66592,
- struct m66592_pipe_info *info)
+ struct m66592_pipe_info *info)
{
u16 bufnum = 0, buf_bsize = 0;
u16 pipecfg = 0;
@@ -287,7 +286,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
}
if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
- m66592->bi_bufnum);
+ m66592->bi_bufnum);
return -ENOMEM;
}
@@ -328,7 +327,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
m66592->bulk--;
} else
printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
- info->pipe);
+ info->pipe);
}
static void pipe_initialize(struct m66592_ep *ep)
@@ -350,8 +349,8 @@ static void pipe_initialize(struct m66592_ep *ep)
}
static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
- const struct usb_endpoint_descriptor *desc,
- u16 pipenum, int dma)
+ const struct usb_endpoint_descriptor *desc,
+ u16 pipenum, int dma)
{
if ((pipenum != 0) && dma) {
if (m66592->num_dma == 0) {
@@ -385,7 +384,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
ep->pipectr = get_pipectr_addr(pipenum);
ep->pipenum = pipenum;
- ep->ep.maxpacket = desc->wMaxPacketSize;
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
m66592->pipenum2ep[pipenum] = ep;
m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
INIT_LIST_HEAD(&ep->queue);
@@ -407,7 +406,7 @@ static void m66592_ep_release(struct m66592_ep *ep)
}
static int alloc_pipe_config(struct m66592_ep *ep,
- const struct usb_endpoint_descriptor *desc)
+ const struct usb_endpoint_descriptor *desc)
{
struct m66592 *m66592 = ep->m66592;
struct m66592_pipe_info info;
@@ -419,15 +418,15 @@ static int alloc_pipe_config(struct m66592_ep *ep,
BUG_ON(ep->pipenum);
- switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_BULK:
if (m66592->bulk >= M66592_MAX_NUM_BULK) {
if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
printk(KERN_ERR "bulk pipe is insufficient\n");
return -ENODEV;
} else {
- info.pipe = M66592_BASE_PIPENUM_ISOC +
- m66592->isochronous;
+ info.pipe = M66592_BASE_PIPENUM_ISOC
+ + m66592->isochronous;
counter = &m66592->isochronous;
}
} else {
@@ -462,7 +461,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
ep->type = info.type;
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = desc->wMaxPacketSize;
+ info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
info.interval = desc->bInterval;
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
info.dir_in = 1;
@@ -525,8 +524,8 @@ static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
pipe_change(m66592, ep->pipenum);
m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
- (M66592_ISEL | M66592_CURPIPE),
- M66592_CFIFOSEL);
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
m66592_write(m66592, M66592_BCLR, ep->fifoctr);
if (req->req.length == 0) {
m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
@@ -561,8 +560,8 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
if (ep->pipenum == 0) {
m66592_mdfy(m66592, M66592_PIPE0,
- (M66592_ISEL | M66592_CURPIPE),
- M66592_CFIFOSEL);
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
m66592_write(m66592, M66592_BCLR, ep->fifoctr);
pipe_start(m66592, pipenum);
pipe_irq_enable(m66592, pipenum);
@@ -572,8 +571,9 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
pipe_change(m66592, pipenum);
m66592_bset(m66592, M66592_TRENB, ep->fifosel);
m66592_write(m66592,
- (req->req.length + ep->ep.maxpacket - 1) /
- ep->ep.maxpacket, ep->fifotrn);
+ (req->req.length + ep->ep.maxpacket - 1)
+ / ep->ep.maxpacket,
+ ep->fifotrn);
}
pipe_start(m66592, pipenum); /* trigger once */
pipe_irq_enable(m66592, pipenum);
@@ -614,7 +614,7 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
static void init_controller(struct m66592 *m66592)
{
m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
- M66592_PINCFG);
+ M66592_PINCFG);
m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
@@ -634,7 +634,7 @@ static void init_controller(struct m66592 *m66592)
m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
- M66592_DMA0CFG);
+ M66592_DMA0CFG);
}
static void disable_controller(struct m66592 *m66592)
@@ -659,8 +659,9 @@ static void m66592_start_xclock(struct m66592 *m66592)
/*-------------------------------------------------------------------------*/
static void transfer_complete(struct m66592_ep *ep,
- struct m66592_request *req,
- int status)
+ struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
int restart = 0;
@@ -680,8 +681,9 @@ static void transfer_complete(struct m66592_ep *ep,
if (!list_empty(&ep->queue))
restart = 1;
- if (likely(req->req.complete))
- req->req.complete(&ep->ep, &req->req);
+ spin_unlock(&ep->m66592->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->m66592->lock);
if (restart) {
req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -693,7 +695,7 @@ static void transfer_complete(struct m66592_ep *ep,
static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
{
int i;
- volatile u16 tmp;
+ u16 tmp;
unsigned bufsize;
size_t size;
void *buf;
@@ -731,8 +733,9 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
req->req.actual += size;
/* check transfer finish */
- if ((!req->req.zero && (req->req.actual == req->req.length)) ||
- (size % ep->ep.maxpacket) || (size == 0)) {
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
disable_irq_ready(m66592, pipenum);
disable_irq_empty(m66592, pipenum);
} else {
@@ -768,16 +771,19 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
/* write fifo */
if (req->req.buf) {
m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
- if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
- ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+ if ((size == 0)
+ || ((size % ep->ep.maxpacket) != 0)
+ || ((bufsize != ep->ep.maxpacket)
+ && (bufsize > size)))
m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
}
/* update parameters */
req->req.actual += size;
/* check transfer finish */
- if ((!req->req.zero && (req->req.actual == req->req.length)) ||
- (size % ep->ep.maxpacket) || (size == 0)) {
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
disable_irq_ready(m66592, pipenum);
enable_irq_empty(m66592, pipenum);
} else {
@@ -821,8 +827,9 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
req->req.actual += size;
/* check transfer finish */
- if ((!req->req.zero && (req->req.actual == req->req.length)) ||
- (size % ep->ep.maxpacket) || (size == 0)) {
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
pipe_stop(m66592, pipenum);
pipe_irq_disable(m66592, pipenum);
finish = 1;
@@ -850,7 +857,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
- M66592_CFIFOSEL);
+ M66592_CFIFOSEL);
ep = &m66592->ep[0];
req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -909,23 +916,26 @@ static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
}
static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
struct m66592_ep *ep;
u16 pid;
u16 status = 0;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
- status = 1; /* selfpower */
+ status = 1 << USB_DEVICE_SELF_POWERED;
break;
case USB_RECIP_INTERFACE:
status = 0;
break;
case USB_RECIP_ENDPOINT:
- ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
pid = control_reg_get_pid(m66592, ep->pipenum);
if (pid == M66592_PID_STALL)
- status = 1;
+ status = 1 << USB_ENDPOINT_HALT;
else
status = 0;
break;
@@ -934,11 +944,13 @@ static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
return; /* exit */
}
- *m66592->ep0_buf = status;
- m66592->ep0_req->buf = m66592->ep0_buf;
+ m66592->ep0_data = cpu_to_le16(status);
+ m66592->ep0_req->buf = &m66592->ep0_data;
m66592->ep0_req->length = 2;
/* AV: what happens if we get called again before that gets through? */
+ spin_unlock(&m66592->lock);
m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+ spin_lock(&m66592->lock);
}
static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
@@ -953,8 +965,9 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
case USB_RECIP_ENDPOINT: {
struct m66592_ep *ep;
struct m66592_request *req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
- ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
pipe_stop(m66592, ep->pipenum);
control_reg_sqclr(m66592, ep->pipenum);
@@ -989,8 +1002,9 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
break;
case USB_RECIP_ENDPOINT: {
struct m66592_ep *ep;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
- ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
pipe_stall(m66592, ep->pipenum);
control_end(m66592, 1);
@@ -1066,14 +1080,16 @@ static void irq_device_state(struct m66592 *m66592)
}
if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
m66592_update_usb_speed(m66592);
- if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
- m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+ && m66592->gadget.speed == USB_SPEED_UNKNOWN)
m66592_update_usb_speed(m66592);
m66592->old_dvsq = dvsq;
}
static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
struct usb_ctrlrequest ctrl;
u16 ctsq;
@@ -1095,8 +1111,10 @@ static void irq_control_stage(struct m66592 *m66592)
case M66592_CS_WRDS:
case M66592_CS_WRND:
if (setup_packet(m66592, &ctrl)) {
+ spin_unlock(&m66592->lock);
if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
pipe_stall(m66592, 0);
+ spin_lock(&m66592->lock);
}
break;
case M66592_CS_RDSS:
@@ -1119,6 +1137,8 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
u16 savepipe;
u16 mask0;
+ spin_lock(&m66592->lock);
+
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
@@ -1134,27 +1154,27 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
bempenb = m66592_read(m66592, M66592_BEMPENB);
if (mask0 & M66592_VBINT) {
- m66592_write(m66592, (u16)~M66592_VBINT,
- M66592_INTSTS0);
+ m66592_write(m66592, 0xffff & ~M66592_VBINT,
+ M66592_INTSTS0);
m66592_start_xclock(m66592);
/* start vbus sampling */
m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
- & M66592_VBSTS;
+ & M66592_VBSTS;
m66592->scount = M66592_MAX_SAMPLING;
mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ jiffies + msecs_to_jiffies(50));
}
if (intsts0 & M66592_DVSQ)
irq_device_state(m66592);
- if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
- (brdysts & brdyenb)) {
+ if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+ && (brdysts & brdyenb)) {
irq_pipe_ready(m66592, brdysts, brdyenb);
}
- if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
- (bempsts & bempenb)) {
+ if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+ && (bempsts & bempenb)) {
irq_pipe_empty(m66592, bempsts, bempenb);
}
@@ -1164,6 +1184,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
m66592_write(m66592, savepipe, M66592_CFIFOSEL);
+ spin_unlock(&m66592->lock);
return IRQ_HANDLED;
}
@@ -1191,13 +1212,13 @@ static void m66592_timer(unsigned long _m66592)
m66592_usb_disconnect(m66592);
} else {
mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ jiffies + msecs_to_jiffies(50));
}
} else {
m66592->scount = M66592_MAX_SAMPLING;
m66592->old_vbus = tmp;
mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ jiffies + msecs_to_jiffies(50));
}
}
spin_unlock_irqrestore(&m66592->lock, flags);
@@ -1278,7 +1299,7 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == 0) /* control */
+ if (ep->desc == NULL) /* control */
start_ep0(ep, req);
else {
if (request && !ep->busy)
@@ -1335,11 +1356,6 @@ out:
return ret;
}
-static int m66592_fifo_status(struct usb_ep *_ep)
-{
- return -EOPNOTSUPP;
-}
-
static void m66592_fifo_flush(struct usb_ep *_ep)
{
struct m66592_ep *ep;
@@ -1365,7 +1381,6 @@ static struct usb_ep_ops m66592_ep_ops = {
.dequeue = m66592_dequeue,
.set_halt = m66592_set_halt,
- .fifo_status = m66592_fifo_status,
.fifo_flush = m66592_fifo_flush,
};
@@ -1377,11 +1392,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
struct m66592 *m66592 = the_controller;
int retval;
- if (!driver ||
- driver->speed != USB_SPEED_HIGH ||
- !driver->bind ||
- !driver->unbind ||
- !driver->setup)
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->setup)
return -EINVAL;
if (!m66592)
return -ENODEV;
@@ -1413,8 +1427,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
m66592->old_vbus = m66592_read(m66592,
M66592_INTSTS0) & M66592_VBSTS;
m66592->scount = M66592_MAX_SAMPLING;
- mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
}
return 0;
@@ -1432,6 +1445,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
struct m66592 *m66592 = the_controller;
unsigned long flags;
+ if (driver != m66592->driver || !driver->unbind)
+ return -EINVAL;
+
spin_lock_irqsave(&m66592->lock, flags);
if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
m66592_usb_disconnect(m66592);
@@ -1461,46 +1477,35 @@ static struct usb_gadget_ops m66592_gadget_ops = {
.get_frame = m66592_get_frame,
};
-#if defined(CONFIG_PM)
-static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
-{
- pdev->dev.power.power_state = state;
- return 0;
-}
-
-static int m66592_resume(struct platform_device *pdev)
-{
- pdev->dev.power.power_state = PMSG_ON;
- return 0;
-}
-#else /* if defined(CONFIG_PM) */
-#define m66592_suspend NULL
-#define m66592_resume NULL
-#endif
-
-static int __init_or_module m66592_remove(struct platform_device *pdev)
+static int __exit m66592_remove(struct platform_device *pdev)
{
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
del_timer_sync(&m66592->timer);
iounmap(m66592->reg);
free_irq(platform_get_irq(pdev, 0), m66592);
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
kfree(m66592);
return 0;
}
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
#define resource_len(r) (((r)->end - (r)->start) + 1)
+
static int __init m66592_probe(struct platform_device *pdev)
{
- struct resource *res = NULL;
- int irq = -1;
+ struct resource *res;
+ int irq;
void __iomem *reg = NULL;
struct m66592 *m66592 = NULL;
int ret = 0;
int i;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- (char *)udc_name);
+ (char *)udc_name);
if (!res) {
ret = -ENODEV;
printk(KERN_ERR "platform_get_resource_byname error.\n");
@@ -1548,7 +1553,7 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->bi_bufnum = M66592_BASE_BUFNUM;
ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
- udc_name, m66592);
+ udc_name, m66592);
if (ret < 0) {
printk(KERN_ERR "request_irq error (%d)\n", ret);
goto clean_up;
@@ -1563,7 +1568,7 @@ static int __init m66592_probe(struct platform_device *pdev)
if (i != 0) {
INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
list_add_tail(&m66592->ep[i].ep.ep_list,
- &m66592->gadget.ep_list);
+ &m66592->gadget.ep_list);
}
ep->m66592 = m66592;
INIT_LIST_HEAD(&ep->queue);
@@ -1583,20 +1588,18 @@ static int __init m66592_probe(struct platform_device *pdev)
the_controller = m66592;
- /* AV: leaks */
m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
if (m66592->ep0_req == NULL)
- goto clean_up;
- /* AV: leaks, and do we really need it separately allocated? */
- m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
- if (m66592->ep0_buf == NULL)
- goto clean_up;
+ goto clean_up2;
+ m66592->ep0_req->complete = nop_completion;
init_controller(m66592);
- printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
+clean_up2:
+ free_irq(irq, m66592);
clean_up:
if (m66592) {
if (m66592->ep0_req)
@@ -1611,10 +1614,7 @@ clean_up:
/*-------------------------------------------------------------------------*/
static struct platform_driver m66592_driver = {
- .probe = m66592_probe,
- .remove = m66592_remove,
- .suspend = m66592_suspend,
- .resume = m66592_resume,
+ .remove = __exit_p(m66592_remove),
.driver = {
.name = (char *) udc_name,
},
@@ -1622,7 +1622,7 @@ static struct platform_driver m66592_driver = {
static int __init m66592_udc_init(void)
{
- return platform_driver_register(&m66592_driver);
+ return platform_driver_probe(&m66592_driver, m66592_probe);
}
module_init(m66592_udc_init);
@@ -1631,4 +1631,3 @@ static void __exit m66592_udc_cleanup(void)
platform_driver_unregister(&m66592_driver);
}
module_exit(m66592_udc_cleanup);
-
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 26b54f8b8945..bfa0c645f229 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -24,73 +24,73 @@
#define __M66592_UDC_H__
#define M66592_SYSCFG 0x00
-#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
-#define M66592_XTAL48 0x8000 /* 48MHz */
-#define M66592_XTAL24 0x4000 /* 24MHz */
-#define M66592_XTAL12 0x0000 /* 12MHz */
-#define M66592_XCKE 0x2000 /* b13: External clock enable */
-#define M66592_RCKE 0x1000 /* b12: Register clock enable */
-#define M66592_PLLC 0x0800 /* b11: PLL control */
-#define M66592_SCKE 0x0400 /* b10: USB clock enable */
-#define M66592_ATCKM 0x0100 /* b8: Automatic supply functional enable */
-#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
-#define M66592_DCFM 0x0040 /* b6: Controller function select */
-#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
-#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
-#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
-#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
-#define M66592_USBE 0x0001 /* b0: USB module operation enable */
+#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
+#define M66592_XTAL48 0x8000 /* 48MHz */
+#define M66592_XTAL24 0x4000 /* 24MHz */
+#define M66592_XTAL12 0x0000 /* 12MHz */
+#define M66592_XCKE 0x2000 /* b13: External clock enable */
+#define M66592_RCKE 0x1000 /* b12: Register clock enable */
+#define M66592_PLLC 0x0800 /* b11: PLL control */
+#define M66592_SCKE 0x0400 /* b10: USB clock enable */
+#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */
+#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
+#define M66592_DCFM 0x0040 /* b6: Controller function select */
+#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
+#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
+#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
+#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
+#define M66592_USBE 0x0001 /* b0: USB module operation enable */
#define M66592_SYSSTS 0x02
-#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
-#define M66592_SE1 0x0003 /* SE1 */
-#define M66592_KSTS 0x0002 /* K State */
-#define M66592_JSTS 0x0001 /* J State */
-#define M66592_SE0 0x0000 /* SE0 */
+#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
+#define M66592_SE1 0x0003 /* SE1 */
+#define M66592_KSTS 0x0002 /* K State */
+#define M66592_JSTS 0x0001 /* J State */
+#define M66592_SE0 0x0000 /* SE0 */
#define M66592_DVSTCTR 0x04
-#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
-#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
-#define M66592_USBRST 0x0040 /* b6: USB reset enable */
-#define M66592_RESUME 0x0020 /* b5: Resume enable */
-#define M66592_UACT 0x0010 /* b4: USB bus enable */
-#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
-#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
-#define M66592_FSMODE 0x0002 /* Full-Speed mode */
-#define M66592_HSPROC 0x0001 /* HS handshake is processing */
+#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
+#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define M66592_USBRST 0x0040 /* b6: USB reset enable */
+#define M66592_RESUME 0x0020 /* b5: Resume enable */
+#define M66592_UACT 0x0010 /* b4: USB bus enable */
+#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
+#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
+#define M66592_FSMODE 0x0002 /* Full-Speed mode */
+#define M66592_HSPROC 0x0001 /* HS handshake is processing */
#define M66592_TESTMODE 0x06
-#define M66592_UTST 0x000F /* b4-0: Test select */
-#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
-#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
-#define M66592_H_TST_K 0x000A /* HOST TEST K */
-#define M66592_H_TST_J 0x0009 /* HOST TEST J */
-#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
-#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
-#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
-#define M66592_P_TST_K 0x0002 /* PERI TEST K */
-#define M66592_P_TST_J 0x0001 /* PERI TEST J */
-#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+#define M66592_UTST 0x000F /* b4-0: Test select */
+#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define M66592_H_TST_K 0x000A /* HOST TEST K */
+#define M66592_H_TST_J 0x0009 /* HOST TEST J */
+#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define M66592_P_TST_K 0x0002 /* PERI TEST K */
+#define M66592_P_TST_J 0x0001 /* PERI TEST J */
+#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
#define M66592_PINCFG 0x0A
-#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
-#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
+#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
+#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
#define M66592_DMA0CFG 0x0C
#define M66592_DMA1CFG 0x0E
-#define M66592_DREQA 0x4000 /* b14: Dreq active select */
-#define M66592_BURST 0x2000 /* b13: Burst mode */
-#define M66592_DACKA 0x0400 /* b10: Dack active select */
-#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
-#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
-#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
-#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
-#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
-#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
-#define M66592_DENDA 0x0040 /* b6: Dend active select */
-#define M66592_PKTM 0x0020 /* b5: Packet mode */
-#define M66592_DENDE 0x0010 /* b4: Dend enable */
-#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
+#define M66592_DREQA 0x4000 /* b14: Dreq active select */
+#define M66592_BURST 0x2000 /* b13: Burst mode */
+#define M66592_DACKA 0x0400 /* b10: Dack active select */
+#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
+#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA 0x0040 /* b6: Dend active select */
+#define M66592_PKTM 0x0020 /* b5: Packet mode */
+#define M66592_DENDE 0x0010 /* b4: Dend enable */
+#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
#define M66592_CFIFO 0x10
#define M66592_D0FIFO 0x14
@@ -99,300 +99,300 @@
#define M66592_CFIFOSEL 0x1E
#define M66592_D0FIFOSEL 0x24
#define M66592_D1FIFOSEL 0x2A
-#define M66592_RCNT 0x8000 /* b15: Read count mode */
-#define M66592_REW 0x4000 /* b14: Buffer rewind */
-#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
-#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
-#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO access */
-#define M66592_MBW_8 0x0000 /* 8bit */
-#define M66592_MBW_16 0x0400 /* 16bit */
-#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
-#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
-#define M66592_DEZPM 0x0080 /* b7: Zero-length packet additional mode */
-#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
-#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
+#define M66592_RCNT 0x8000 /* b15: Read count mode */
+#define M66592_REW 0x4000 /* b14: Buffer rewind */
+#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
+#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
+#define M66592_MBW_8 0x0000 /* 8bit */
+#define M66592_MBW_16 0x0400 /* 16bit */
+#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
+#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
+#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */
+#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
#define M66592_CFIFOCTR 0x20
#define M66592_D0FIFOCTR 0x26
#define M66592_D1FIFOCTR 0x2c
-#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
-#define M66592_BCLR 0x4000 /* b14: Buffer clear */
-#define M66592_FRDY 0x2000 /* b13: FIFO ready */
-#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
+#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
+#define M66592_BCLR 0x4000 /* b14: Buffer clear */
+#define M66592_FRDY 0x2000 /* b13: FIFO ready */
+#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
#define M66592_CFIFOSIE 0x22
-#define M66592_TGL 0x8000 /* b15: Buffer toggle */
-#define M66592_SCLR 0x4000 /* b14: Buffer clear */
-#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
+#define M66592_TGL 0x8000 /* b15: Buffer toggle */
+#define M66592_SCLR 0x4000 /* b14: Buffer clear */
+#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
#define M66592_D0FIFOTRN 0x28
#define M66592_D1FIFOTRN 0x2E
-#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
+#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
#define M66592_INTENB0 0x30
-#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
-#define M66592_RSME 0x4000 /* b14: Resume interrupt */
-#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
-#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
-#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
-#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
-#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
-#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
-#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
-#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
-#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
-#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
-#define M66592_WDST 0x0008 /* b3: Control write data stage completed interrupt */
-#define M66592_RDST 0x0004 /* b2: Control read data stage completed interrupt */
-#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
-#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
+#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
+#define M66592_RSME 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
+#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
+#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */
+#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
+#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
+#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
+#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
+#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */
+#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */
+#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
+#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
#define M66592_INTENB1 0x32
-#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
-#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
-#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
-#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
-#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
-#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
-#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
+#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
+#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
+#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
+#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
#define M66592_BRDYENB 0x36
#define M66592_BRDYSTS 0x46
-#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
-#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
-#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
-#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
-#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
-#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
-#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
-#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
+#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
#define M66592_NRDYENB 0x38
#define M66592_NRDYSTS 0x48
-#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
-#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
-#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
-#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
-#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
-#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
-#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
-#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
+#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
#define M66592_BEMPENB 0x3A
#define M66592_BEMPSTS 0x4A
-#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
-#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
-#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
-#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
-#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
-#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
-#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
-#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
+#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
+#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
+#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
+#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
+#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
+#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
+#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
+#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
#define M66592_SOFCFG 0x3C
-#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
-#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
-#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
-#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
+#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
+#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
+#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
#define M66592_INTSTS0 0x40
-#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
-#define M66592_RESM 0x4000 /* b14: Resume interrupt */
-#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
-#define M66592_DVST 0x1000 /* b12: Device state transition interrupt */
-#define M66592_CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
-#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
-#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
-#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
-#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
-#define M66592_DVSQ 0x0070 /* b6-4: Device state */
-#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
-#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
-#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
-#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
-#define M66592_DS_SUSP 0x0040 /* Suspend */
-#define M66592_DS_CNFG 0x0030 /* Configured */
-#define M66592_DS_ADDS 0x0020 /* Address */
-#define M66592_DS_DFLT 0x0010 /* Default */
-#define M66592_DS_POWR 0x0000 /* Powered */
-#define M66592_DVSQS 0x0030 /* b5-4: Device state */
-#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
-#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
-#define M66592_CS_SQER 0x0006 /* Sequence error */
-#define M66592_CS_WRND 0x0005 /* Control write nodata status stage */
-#define M66592_CS_WRSS 0x0004 /* Control write status stage */
-#define M66592_CS_WRDS 0x0003 /* Control write data stage */
-#define M66592_CS_RDSS 0x0002 /* Control read status stage */
-#define M66592_CS_RDDS 0x0001 /* Control read data stage */
-#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
+#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
+#define M66592_RESM 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define M66592_DVST 0x1000 /* b12: Device state transition */
+#define M66592_CTRT 0x0800 /* b11: Control stage transition */
+#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
+#define M66592_DVSQ 0x0070 /* b6-4: Device state */
+#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define M66592_DS_SUSP 0x0040 /* Suspend */
+#define M66592_DS_CNFG 0x0030 /* Configured */
+#define M66592_DS_ADDS 0x0020 /* Address */
+#define M66592_DS_DFLT 0x0010 /* Default */
+#define M66592_DS_POWR 0x0000 /* Powered */
+#define M66592_DVSQS 0x0030 /* b5-4: Device state */
+#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
+#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define M66592_CS_SQER 0x0006 /* Sequence error */
+#define M66592_CS_WRND 0x0005 /* Control write nodata status */
+#define M66592_CS_WRSS 0x0004 /* Control write status stage */
+#define M66592_CS_WRDS 0x0003 /* Control write data stage */
+#define M66592_CS_RDSS 0x0002 /* Control read status stage */
+#define M66592_CS_RDDS 0x0001 /* Control read data stage */
+#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
#define M66592_INTSTS1 0x42
-#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
-#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
-#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
-#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
+#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
#define M66592_FRMNUM 0x4C
-#define M66592_OVRN 0x8000 /* b15: Overrun error */
-#define M66592_CRCE 0x4000 /* b14: Received data error */
-#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
-#define M66592_FRNM 0x07FF /* b10-0: Frame number */
+#define M66592_OVRN 0x8000 /* b15: Overrun error */
+#define M66592_CRCE 0x4000 /* b14: Received data error */
+#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
+#define M66592_FRNM 0x07FF /* b10-0: Frame number */
#define M66592_UFRMNUM 0x4E
-#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
+#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
#define M66592_RECOVER 0x50
-#define M66592_STSRECOV 0x0700 /* Status recovery */
-#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
-#define M66592_STSR_DEFAULT 0x0100 /* Default state */
-#define M66592_STSR_ADDRESS 0x0200 /* Address state */
-#define M66592_STSR_CONFIG 0x0300 /* Configured state */
-#define M66592_USBADDR 0x007F /* b6-0: USB address */
+#define M66592_STSRECOV 0x0700 /* Status recovery */
+#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
+#define M66592_STSR_DEFAULT 0x0100 /* Default state */
+#define M66592_STSR_ADDRESS 0x0200 /* Address state */
+#define M66592_STSR_CONFIG 0x0300 /* Configured state */
+#define M66592_USBADDR 0x007F /* b6-0: USB address */
#define M66592_USBREQ 0x54
-#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
-#define M66592_GET_STATUS 0x0000
-#define M66592_CLEAR_FEATURE 0x0100
-#define M66592_ReqRESERVED 0x0200
-#define M66592_SET_FEATURE 0x0300
-#define M66592_ReqRESERVED1 0x0400
-#define M66592_SET_ADDRESS 0x0500
-#define M66592_GET_DESCRIPTOR 0x0600
-#define M66592_SET_DESCRIPTOR 0x0700
-#define M66592_GET_CONFIGURATION 0x0800
-#define M66592_SET_CONFIGURATION 0x0900
-#define M66592_GET_INTERFACE 0x0A00
-#define M66592_SET_INTERFACE 0x0B00
-#define M66592_SYNCH_FRAME 0x0C00
-#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
-#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data transfer direction */
-#define M66592_HOST_TO_DEVICE 0x0000
-#define M66592_DEVICE_TO_HOST 0x0080
-#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
-#define M66592_STANDARD 0x0000
-#define M66592_CLASS 0x0020
-#define M66592_VENDOR 0x0040
-#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
-#define M66592_DEVICE 0x0000
-#define M66592_INTERFACE 0x0001
-#define M66592_ENDPOINT 0x0002
+#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
+#define M66592_GET_STATUS 0x0000
+#define M66592_CLEAR_FEATURE 0x0100
+#define M66592_ReqRESERVED 0x0200
+#define M66592_SET_FEATURE 0x0300
+#define M66592_ReqRESERVED1 0x0400
+#define M66592_SET_ADDRESS 0x0500
+#define M66592_GET_DESCRIPTOR 0x0600
+#define M66592_SET_DESCRIPTOR 0x0700
+#define M66592_GET_CONFIGURATION 0x0800
+#define M66592_SET_CONFIGURATION 0x0900
+#define M66592_GET_INTERFACE 0x0A00
+#define M66592_SET_INTERFACE 0x0B00
+#define M66592_SYNCH_FRAME 0x0C00
+#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */
+#define M66592_HOST_TO_DEVICE 0x0000
+#define M66592_DEVICE_TO_HOST 0x0080
+#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
+#define M66592_STANDARD 0x0000
+#define M66592_CLASS 0x0020
+#define M66592_VENDOR 0x0040
+#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
+#define M66592_DEVICE 0x0000
+#define M66592_INTERFACE 0x0001
+#define M66592_ENDPOINT 0x0002
#define M66592_USBVAL 0x56
-#define M66592_wValue 0xFFFF /* b15-0: wValue */
+#define M66592_wValue 0xFFFF /* b15-0: wValue */
/* Standard Feature Selector */
-#define M66592_ENDPOINT_HALT 0x0000
-#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
-#define M66592_TEST_MODE 0x0002
+#define M66592_ENDPOINT_HALT 0x0000
+#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
+#define M66592_TEST_MODE 0x0002
/* Descriptor Types */
-#define M66592_DT_TYPE 0xFF00
-#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
-#define M66592_DT_DEVICE 0x01
-#define M66592_DT_CONFIGURATION 0x02
-#define M66592_DT_STRING 0x03
-#define M66592_DT_INTERFACE 0x04
-#define M66592_DT_ENDPOINT 0x05
-#define M66592_DT_DEVICE_QUALIFIER 0x06
-#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
-#define M66592_DT_INTERFACE_POWER 0x08
-#define M66592_DT_INDEX 0x00FF
-#define M66592_CONF_NUM 0x00FF
-#define M66592_ALT_SET 0x00FF
+#define M66592_DT_TYPE 0xFF00
+#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
+#define M66592_DT_DEVICE 0x01
+#define M66592_DT_CONFIGURATION 0x02
+#define M66592_DT_STRING 0x03
+#define M66592_DT_INTERFACE 0x04
+#define M66592_DT_ENDPOINT 0x05
+#define M66592_DT_DEVICE_QUALIFIER 0x06
+#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
+#define M66592_DT_INTERFACE_POWER 0x08
+#define M66592_DT_INDEX 0x00FF
+#define M66592_CONF_NUM 0x00FF
+#define M66592_ALT_SET 0x00FF
#define M66592_USBINDEX 0x58
-#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
-#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode Selectors */
-#define M66592_TEST_J 0x0100 /* Test_J */
-#define M66592_TEST_K 0x0200 /* Test_K */
-#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
-#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
-#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
-#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
-#define M66592_TEST_Reserved 0x4000 /* Reserved */
-#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific test modes */
-#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
-#define M66592_EP_DIR_IN 0x0080
-#define M66592_EP_DIR_OUT 0x0000
+#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
+#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */
+#define M66592_TEST_J 0x0100 /* Test_J */
+#define M66592_TEST_K 0x0200 /* Test_K */
+#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
+#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
+#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
+#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
+#define M66592_TEST_Reserved 0x4000 /* Reserved */
+#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */
+#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
+#define M66592_EP_DIR_IN 0x0080
+#define M66592_EP_DIR_OUT 0x0000
#define M66592_USBLENG 0x5A
-#define M66592_wLength 0xFFFF /* b15-0: wLength */
+#define M66592_wLength 0xFFFF /* b15-0: wLength */
#define M66592_DCPCFG 0x5C
-#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
#define M66592_DCPMAXP 0x5E
-#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
-#define M66592_DEVICE_0 0x0000 /* Device address 0 */
-#define M66592_DEVICE_1 0x4000 /* Device address 1 */
-#define M66592_DEVICE_2 0x8000 /* Device address 2 */
-#define M66592_DEVICE_3 0xC000 /* Device address 3 */
-#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
+#define M66592_DEVICE_0 0x0000 /* Device address 0 */
+#define M66592_DEVICE_1 0x4000 /* Device address 1 */
+#define M66592_DEVICE_2 0x8000 /* Device address 2 */
+#define M66592_DEVICE_3 0xC000 /* Device address 3 */
+#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */
#define M66592_DCPCTR 0x60
-#define M66592_BSTS 0x8000 /* b15: Buffer status */
-#define M66592_SUREQ 0x4000 /* b14: Send USB request */
-#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define M66592_CCPL 0x0004 /* b2: Enable control transfer complete */
-#define M66592_PID 0x0003 /* b1-0: Response PID */
-#define M66592_PID_STALL 0x0002 /* STALL */
-#define M66592_PID_BUF 0x0001 /* BUF */
-#define M66592_PID_NAK 0x0000 /* NAK */
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_SUREQ 0x4000 /* b14: Send USB request */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_CCPL 0x0004 /* b2: control transfer complete */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
+#define M66592_PID_STALL 0x0002 /* STALL */
+#define M66592_PID_BUF 0x0001 /* BUF */
+#define M66592_PID_NAK 0x0000 /* NAK */
#define M66592_PIPESEL 0x64
-#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
-#define M66592_PIPE0 0x0000 /* PIPE 0 */
-#define M66592_PIPE1 0x0001 /* PIPE 1 */
-#define M66592_PIPE2 0x0002 /* PIPE 2 */
-#define M66592_PIPE3 0x0003 /* PIPE 3 */
-#define M66592_PIPE4 0x0004 /* PIPE 4 */
-#define M66592_PIPE5 0x0005 /* PIPE 5 */
-#define M66592_PIPE6 0x0006 /* PIPE 6 */
-#define M66592_PIPE7 0x0007 /* PIPE 7 */
+#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
+#define M66592_PIPE0 0x0000 /* PIPE 0 */
+#define M66592_PIPE1 0x0001 /* PIPE 1 */
+#define M66592_PIPE2 0x0002 /* PIPE 2 */
+#define M66592_PIPE3 0x0003 /* PIPE 3 */
+#define M66592_PIPE4 0x0004 /* PIPE 4 */
+#define M66592_PIPE5 0x0005 /* PIPE 5 */
+#define M66592_PIPE6 0x0006 /* PIPE 6 */
+#define M66592_PIPE7 0x0007 /* PIPE 7 */
#define M66592_PIPECFG 0x66
-#define M66592_TYP 0xC000 /* b15-14: Transfer type */
-#define M66592_ISO 0xC000 /* Isochronous */
-#define M66592_INT 0x8000 /* Interrupt */
-#define M66592_BULK 0x4000 /* Bulk */
-#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
-#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
-#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
-#define M66592_DIR 0x0010 /* b4: Transfer direction select */
-#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
-#define M66592_DIR_P_IN 0x0010 /* PERI IN */
-#define M66592_DIR_H_IN 0x0000 /* HOST IN */
-#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
-#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
-#define M66592_EP1 0x0001
-#define M66592_EP2 0x0002
-#define M66592_EP3 0x0003
-#define M66592_EP4 0x0004
-#define M66592_EP5 0x0005
-#define M66592_EP6 0x0006
-#define M66592_EP7 0x0007
-#define M66592_EP8 0x0008
-#define M66592_EP9 0x0009
-#define M66592_EP10 0x000A
-#define M66592_EP11 0x000B
-#define M66592_EP12 0x000C
-#define M66592_EP13 0x000D
-#define M66592_EP14 0x000E
-#define M66592_EP15 0x000F
+#define M66592_TYP 0xC000 /* b15-14: Transfer type */
+#define M66592_ISO 0xC000 /* Isochronous */
+#define M66592_INT 0x8000 /* Interrupt */
+#define M66592_BULK 0x4000 /* Bulk */
+#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */
+#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define M66592_DIR 0x0010 /* b4: Transfer direction select */
+#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
+#define M66592_DIR_P_IN 0x0010 /* PERI IN */
+#define M66592_DIR_H_IN 0x0000 /* HOST IN */
+#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
+#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
+#define M66592_EP1 0x0001
+#define M66592_EP2 0x0002
+#define M66592_EP3 0x0003
+#define M66592_EP4 0x0004
+#define M66592_EP5 0x0005
+#define M66592_EP6 0x0006
+#define M66592_EP7 0x0007
+#define M66592_EP8 0x0008
+#define M66592_EP9 0x0009
+#define M66592_EP10 0x000A
+#define M66592_EP11 0x000B
+#define M66592_EP12 0x000C
+#define M66592_EP13 0x000D
+#define M66592_EP14 0x000E
+#define M66592_EP15 0x000F
#define M66592_PIPEBUF 0x68
-#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
-#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
-#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
+#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
#define M66592_PIPEMAXP 0x6A
-#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
+#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
#define M66592_PIPEPERI 0x6C
-#define M66592_IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
-#define M66592_IITV 0x0007 /* b2-0: Isochronous interval */
+#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */
+#define M66592_IITV 0x0007 /* b2-0: ISO interval */
#define M66592_PIPE1CTR 0x70
#define M66592_PIPE2CTR 0x72
@@ -401,19 +401,17 @@
#define M66592_PIPE5CTR 0x78
#define M66592_PIPE6CTR 0x7A
#define M66592_PIPE7CTR 0x7C
-#define M66592_BSTS 0x8000 /* b15: Buffer status */
-#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
-#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define M66592_PID 0x0003 /* b1-0: Response PID */
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
#define M66592_INVALID_REG 0x7E
-#define __iomem
-
#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2)
#define M66592_MAX_SAMPLING 10
@@ -449,7 +447,7 @@ struct m66592_ep {
struct m66592 *m66592;
struct list_head queue;
- unsigned busy:1;
+ unsigned busy:1;
unsigned internal_ccpl:1; /* use only control */
/* this member can able to after m66592_enable */
@@ -477,7 +475,7 @@ struct m66592 {
struct m66592_ep *epaddr2ep[16];
struct usb_request *ep0_req; /* for internal request */
- u16 *ep0_buf; /* for internal request */
+ u16 ep0_data; /* for internal request */
struct timer_list timer;
@@ -527,8 +525,8 @@ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
}
static inline void m66592_read_fifo(struct m66592 *m66592,
- unsigned long offset,
- void *buf, unsigned long len)
+ unsigned long offset,
+ void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
@@ -543,8 +541,8 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,
}
static inline void m66592_write_fifo(struct m66592 *m66592,
- unsigned long offset,
- void *buf, unsigned long len)
+ unsigned long offset,
+ void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
unsigned long odd = len & 0x0001;
@@ -558,7 +556,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
}
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
- unsigned long offset)
+ unsigned long offset)
{
u16 tmp;
tmp = m66592_read(m66592, offset);
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index c3d364ecd4f8..d5d473f8144b 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -62,7 +62,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 9b0f0925dddf..87c4f50dfb61 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
@@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
udc->gadget.dev.parent->power.power_state = PMSG_ON;
udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
+ if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
}
static void pullup_disable(struct omap_udc *udc)
{
-#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
+ if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
}
@@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
{
u16 devstat;
- if (!udc->gadget.is_otg)
+ if (!gadget_is_otg(udc->gadget))
return;
if (OTG_CTRL_REG & OTG_ID)
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 63b9521c1322..3e715082de36 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -54,7 +54,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/mach/udc_pxa2xx.h>
@@ -93,8 +93,6 @@ static const char driver_name [] = "pxa2xx_udc";
static const char ep0name [] = "ep0";
-// #define DISABLE_TEST_MODE
-
#ifdef CONFIG_ARCH_IXP4XX
/* cpu-specific register addresses are compiled in to this code */
@@ -113,17 +111,6 @@ static const char ep0name [] = "ep0";
#define SIZE_STR ""
#endif
-#ifdef DISABLE_TEST_MODE
-/* (mode == 0) == no undocumented chip tweaks
- * (mode & 1) == double buffer bulk IN
- * (mode & 2) == double buffer bulk OUT
- * ... so mode = 3 (or 7, 15, etc) does it for both
- */
-static ushort fifo_mode = 0;
-module_param(fifo_mode, ushort, 0);
-MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
-#endif
-
/* ---------------------------------------------------------------------------
* endpoint related parts of the api to the usb controller hardware,
* used by gadget driver; and the inner talker-to-hardware core.
@@ -980,7 +967,7 @@ static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active)
udc = container_of(_gadget, struct pxa2xx_udc, gadget);
/* not all boards support pullup control */
- if (!udc->mach->udc_command)
+ if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
return -EOPNOTSUPP;
is_active = (is_active != 0);
@@ -1252,23 +1239,6 @@ static void udc_enable (struct pxa2xx_udc *dev)
UDC_RES2 = 0x00;
}
-#ifdef DISABLE_TEST_MODE
- /* "test mode" seems to have become the default in later chip
- * revs, preventing double buffering (and invalidating docs).
- * this EXPERIMENT enables it for bulk endpoints by tweaking
- * undefined/reserved register bits (that other drivers clear).
- * Belcarra code comments noted this usage.
- */
- if (fifo_mode & 1) { /* IN endpoints */
- UDC_RES1 |= USIR0_IR1|USIR0_IR6;
- UDC_RES2 |= USIR1_IR11;
- }
- if (fifo_mode & 2) { /* OUT endpoints */
- UDC_RES1 |= USIR0_IR2|USIR0_IR7;
- UDC_RES2 |= USIR1_IR12;
- }
-#endif
-
/* enable suspend/resume and reset irqs */
udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
@@ -2339,7 +2309,7 @@ static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
{
struct pxa2xx_udc *udc = platform_get_drvdata(dev);
- if (!udc->mach->udc_command)
+ if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
WARN("USB host won't detect disconnect!\n");
pullup(udc, 0);
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 0be80c635c48..e3e90f8a75e7 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -42,7 +42,7 @@
#include <linux/seq_file.h>
#include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index dd33ff0ae4ce..f5738eb8e765 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -17,33 +17,15 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
-
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -88,30 +70,29 @@
#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
#define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
+
/* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
static int debug = 1;
+#else
+#define debug 0
+#endif
#define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
#define gs_debug_level(level, format, arg...) \
do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
-#else
-
-#define gs_debug(format, arg...) \
- do { } while(0)
-#define gs_debug_level(level, format, arg...) \
- do { } while(0)
-
-#endif /* GS_DEBUG */
/* Thanks to NetChip Technologies for donating this product ID.
*
@@ -146,10 +127,10 @@ struct gs_req_entry {
/* 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 */
+ struct gs_dev *port_dev; /* pointer to device struct */
struct tty_struct *port_tty; /* pointer to tty struct */
spinlock_t port_lock;
- int port_num;
+ int port_num;
int port_open_count;
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
@@ -187,7 +168,7 @@ 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,
+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);
@@ -221,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
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, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -258,7 +239,7 @@ static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
static const char *EP_NOTIFY_NAME;
-static struct semaphore gs_open_close_sem[GS_NUM_PORTS];
+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;
@@ -414,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
};
static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
- .bLength = sizeof(gs_call_mgmt_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
- .bmCapabilities = 0,
- .bDataInterface = 1, /* index of data interface */
+ .bLength = sizeof(gs_call_mgmt_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
+ .bmCapabilities = 0,
+ .bDataInterface = 1, /* index of data interface */
};
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,
+ .bLength = sizeof(gs_acm_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_ACM_TYPE,
+ .bmCapabilities = 0,
};
static const struct usb_cdc_union_desc gs_union_desc = {
@@ -435,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
.bMasterInterface0 = 0, /* index of control interface */
.bSlaveInterface0 = 1, /* index of data interface */
};
-
+
static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -481,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
NULL,
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -535,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
NULL,
};
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
/* Module */
MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL");
-#ifdef GS_DEBUG
+#ifdef DEBUG
module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
@@ -595,7 +573,7 @@ static int __init gs_module_init(void)
tty_set_operations(gs_tty_driver, &gs_tty_ops);
for (i=0; i < GS_NUM_PORTS; i++)
- sema_init(&gs_open_close_sem[i], 1);
+ mutex_init(&gs_open_close_lock[i]);
retval = tty_register_driver(gs_tty_driver);
if (retval) {
@@ -635,7 +613,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
struct gs_port *port;
struct gs_dev *dev;
struct gs_buf *buf;
- struct semaphore *sem;
+ struct mutex *mtx;
int ret;
port_num = tty->index;
@@ -656,10 +634,10 @@ static int gs_open(struct tty_struct *tty, struct file *file)
return -ENODEV;
}
- sem = &gs_open_close_sem[port_num];
- if (down_interruptible(sem)) {
+ mtx = &gs_open_close_lock[port_num];
+ if (mutex_lock_interruptible(mtx)) {
printk(KERN_ERR
- "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+ "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
port_num, tty, file);
return -ERESTARTSYS;
}
@@ -754,12 +732,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
exit_unlock_port:
spin_unlock_irqrestore(&port->port_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
exit_unlock_dev:
spin_unlock_irqrestore(&dev->dev_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
}
@@ -781,7 +759,7 @@ exit_unlock_dev:
static void gs_close(struct tty_struct *tty, struct file *file)
{
struct gs_port *port = tty->driver_data;
- struct semaphore *sem;
+ struct mutex *mtx;
if (port == NULL) {
printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +768,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
- sem = &gs_open_close_sem[port->port_num];
- down(sem);
+ mtx = &gs_open_close_lock[port->port_num];
+ mutex_lock(mtx);
spin_lock_irq(&port->port_lock);
@@ -846,7 +824,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
exit:
spin_unlock_irq(&port->port_lock);
- up(sem);
+ mutex_unlock(mtx);
}
/*
@@ -914,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
return;
}
- gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+ gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+ port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
@@ -1115,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
len = gs_send_packet(dev, req->buf, ep->maxpacket);
if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+ gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+ "0x%2.2x 0x%2.2x ...\n", len,
+ *((unsigned char *)req->buf),
+ *((unsigned char *)req->buf+1),
+ *((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1268,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
switch(req->status) {
case 0:
- /* normal completion */
+ /* normal completion */
gs_recv_packet(dev, req->buf, req->actual);
requeue:
req->length = ep->maxpacket;
@@ -1405,29 +1388,30 @@ static int __init gs_bind(struct usb_gadget *gadget)
? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- gs_qualifier_desc.bDeviceClass = use_acm
- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
- /* assume ep0 uses the same packet size for both speeds */
- gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
- /* assume endpoints are dual-speed */
- gs_highspeed_notify_desc.bEndpointAddress =
- gs_fullspeed_notify_desc.bEndpointAddress;
- gs_highspeed_in_desc.bEndpointAddress =
- gs_fullspeed_in_desc.bEndpointAddress;
- gs_highspeed_out_desc.bEndpointAddress =
- gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ if (gadget_is_dualspeed(gadget)) {
+ gs_qualifier_desc.bDeviceClass = use_acm
+ ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+ /* assume ep0 uses the same packet size for both speeds */
+ gs_qualifier_desc.bMaxPacketSize0 =
+ gs_device_desc.bMaxPacketSize0;
+ /* assume endpoints are dual-speed */
+ gs_highspeed_notify_desc.bEndpointAddress =
+ gs_fullspeed_notify_desc.bEndpointAddress;
+ gs_highspeed_in_desc.bEndpointAddress =
+ gs_fullspeed_in_desc.bEndpointAddress;
+ gs_highspeed_out_desc.bEndpointAddress =
+ gs_fullspeed_out_desc.bEndpointAddress;
+ }
usb_gadget_set_selfpowered(gadget);
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
+ gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
@@ -1435,7 +1419,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
- memset(dev, 0, sizeof(struct gs_dev));
dev->dev_gadget = gadget;
spin_lock_init(&dev->dev_lock);
INIT_LIST_HEAD(&dev->dev_req_list);
@@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
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);
}
@@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
memcpy(req->buf, &gs_device_desc, ret);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
ret = min(wLength,
(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- ret = gs_build_config_buf(req->buf, gadget->speed,
+ ret = gs_build_config_buf(req->buf, gadget,
wValue >> 8, wValue & 0xff,
- gadget->is_otg);
+ gadget_is_otg(gadget));
if (ret >= 0)
ret = min(wLength, (u16)ret);
break;
@@ -1691,14 +1678,12 @@ static int gs_setup_class(struct usb_gadget *gadget,
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
- ret = min(wLength,
- (u16)sizeof(struct usb_cdc_line_coding));
- if (port) {
- spin_lock(&port->port_lock);
- memcpy(&port->port_line_coding, req->buf, ret);
- spin_unlock(&port->port_lock);
- }
- ret = 0;
+ /* 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.
+ */
+ printk(KERN_WARNING "gs_setup: set_line_coding "
+ "unuspported\n");
break;
case USB_CDC_REQ_GET_LINE_CODING:
@@ -1713,11 +1698,18 @@ static int gs_setup_class(struct usb_gadget *gadget,
break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- ret = 0;
+ /* 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.
+ */
+ printk(KERN_WARNING "gs_setup: set_control_line_state "
+ "unuspported\n");
break;
default:
- printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+ printk(KERN_ERR "gs_setup: unknown class request, "
+ "type=%02x, request=%02x, value=%04x, "
+ "index=%04x, length=%d\n",
ctrl->bRequestType, ctrl->bRequest,
wValue, wIndex, wLength);
break;
@@ -1822,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
if (EP_NOTIFY_NAME
&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
+ ep_desc = choose_ep_desc(gadget,
&gs_highspeed_notify_desc,
&gs_fullspeed_notify_desc);
ret = usb_ep_enable(ep,ep_desc);
@@ -1839,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_IN_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
- &gs_highspeed_in_desc,
+ ep_desc = choose_ep_desc(gadget,
+ &gs_highspeed_in_desc,
&gs_fullspeed_in_desc);
ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
@@ -1856,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
+ ep_desc = choose_ep_desc(gadget,
&gs_highspeed_out_desc,
&gs_fullspeed_out_desc);
ret = usb_ep_enable(ep,ep_desc);
@@ -1976,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
* Builds the config descriptors in the given buffer and returns the
* length, or a negative error number.
*/
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg)
{
int len;
- int high_speed;
+ int high_speed = 0;
const struct usb_config_descriptor *config_desc;
const struct usb_descriptor_header **function;
@@ -1988,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
return -EINVAL;
/* other speed switches high and full speed */
- high_speed = (speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- high_speed = !high_speed;
+ if (gadget_is_dualspeed(g)) {
+ high_speed = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ high_speed = !high_speed;
+ }
if (use_acm) {
config_desc = &gs_acm_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_acm_highspeed_function,
- gs_acm_fullspeed_function);
+ function = high_speed
+ ? gs_acm_highspeed_function
+ : gs_acm_fullspeed_function;
} else {
config_desc = &gs_bulk_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_bulk_highspeed_function,
- gs_bulk_fullspeed_function);
+ function = high_speed
+ ? gs_bulk_highspeed_function
+ : gs_bulk_fullspeed_function;
}
/* for now, don't advertise srp-only devices */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 3459ea6c6c0b..878e428a0ec1 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index a2e6e3fc8c8d..fcde5d9c87df 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1,38 +1,22 @@
/*
* zero.c -- Gadget Zero, for USB development
*
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
* All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * ALTERNATIVELY, this software may be 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.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * You 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
*/
@@ -57,40 +41,28 @@
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
* driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions? To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
*/
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "St Patrick's Day 2004"
+#define DRIVER_VERSION "Lughnasadh, 2007"
static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
struct timer_list resume;
};
-#define xprintk(d,level,fmt,args...) \
- dev_printk(level , &(d)->gadget->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 DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
NULL,
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
};
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+static char manufacturer[50];
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
-static char manufacturer [50];
-static char serial [40];
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
int is_source_sink;
int len;
const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+ int hs = 0;
/* two configurations will always be index 0 and index 1 */
if (index > 1)
return -EINVAL;
is_source_sink = loopdefault ? (index == 1) : (index == 0);
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(gadget)) {
+ hs = (gadget->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
if (hs)
function = is_source_sink
? hs_source_sink_function
: hs_loopback_function;
else
-#endif
function = is_source_sink
? fs_source_sink_function
: fs_loopback_function;
/* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
+ if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/*-------------------------------------------------------------------------*/
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic. The network
+ * link (g_ether) is probably the best option for that.
+ */
+
/* optionally require specific source/sink data patterns */
static int
@@ -534,12 +505,7 @@ check_read_data (
return 0;
}
-static void
-reinit_write_data (
- struct zero_dev *dev,
- struct usb_ep *ep,
- struct usb_request *req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
{
unsigned i;
u8 *buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
- case 0: /* normal completion? */
+ case 0: /* normal completion? */
if (ep == dev->out_ep) {
check_read_data (dev, ep, req);
memset (req->buf, 0x55, req->length);
} else
- reinit_write_data (dev, ep, req);
+ reinit_write_data(ep, req);
break;
/* this endpoint is normally active while we're configured */
- case -ECONNABORTED: /* hardware forced ep reset */
+ 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,
@@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
}
}
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
{
struct usb_request *req;
int status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
req->complete = source_sink_complete;
if (strcmp (ep->name, EP_IN_NAME) == 0)
- reinit_write_data (ep->driver_data, ep, req);
+ reinit_write_data(ep, req);
else
memset (req->buf, 0x55, req->length);
- status = usb_ep_queue (ep, req, gfp_flags);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
@@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
return req;
}
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@@ -653,7 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
- if (source_sink_start_ep (ep, gfp_flags) != 0) {
+ if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
@@ -667,7 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
- if (source_sink_start_ep (ep, gfp_flags) != 0) {
+ if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
@@ -699,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
- case 0: /* normal completion? */
+ case 0: /* normal completion? */
if (ep == dev->out_ep) {
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
@@ -733,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
* rely on the hardware driver to clean up on disconnect or
* endpoint disable.
*/
- case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_ep_req (ep, req);
@@ -741,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
}
}
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@@ -842,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
* code can do, perhaps by disallowing more than one configuration or
* by limiting configuration choices (like the pxa2xx).
*/
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
@@ -853,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100 (gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
- INFO (dev, "can't change configurations\n");
+ ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
zero_reset_config (dev);
switch (number) {
case CONFIG_SOURCE_SINK:
- result = set_source_sink_config (dev, gfp_flags);
+ result = set_source_sink_config(dev);
break;
case CONFIG_LOOPBACK:
- result = set_loopback_config (dev, gfp_flags);
+ result = set_loopback_config(dev);
break;
default:
result = -EINVAL;
@@ -883,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
+ default: speed = "?"; break;
}
dev->config = number;
@@ -936,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (w_length, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
value = min (w_length, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget, req->buf,
w_value >> 8,
@@ -982,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
else
VDBG (dev, "HNP inactive\n");
spin_lock (&dev->lock);
- value = zero_set_config (dev, w_value, GFP_ATOMIC);
+ value = zero_set_config(dev, w_value);
spin_unlock (&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
@@ -1011,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* use this "reset the config" shortcut.
*/
zero_reset_config (dev);
- zero_set_config (dev, config, GFP_ATOMIC);
+ zero_set_config(dev, config);
value = 0;
}
spin_unlock (&dev->lock);
@@ -1161,7 +1121,7 @@ autoconf_fail:
}
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
-
+
ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
@@ -1205,16 +1165,18 @@ autoconf_fail:
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- /* assume ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ if (gadget_is_dualspeed(gadget)) {
+ /* assume ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1292,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
.suspend = zero_suspend,
.resume = zero_resume,
- .driver = {
+ .driver = {
.name = (char *) shortname,
.owner = THIS_MODULE,
},
};
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
static int __init init (void)
{
- /* a real value would likely come through some id prom
- * or module option. this one takes at least two packets.
- */
- strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
return usb_gadget_register_driver (&zero_driver);
}
module_init (init);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2f529828c74d..c978d622fa8a 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
+config USB_OHCI_HCD_SSB
+ bool "OHCI support for Broadcom SSB OHCI core"
+ depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+ default n
+ ---help---
+ Support for the Sonics Silicon Backplane (SSB) attached
+ Broadcom USB OHCI core.
+
+ This device is present in some embedded devices with
+ Broadcom based SSB bus.
+
+ If unsure, say N.
+
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD
@@ -237,7 +250,7 @@ config USB_SL811_CS
module will be called "sl811_cs".
config USB_R8A66597_HCD
- tristate "R8A66597 HCD suppoort"
+ tristate "R8A66597 HCD support"
depends on USB
help
The R8A66597 is a USB 2.0 host and peripheral controller.
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 5d1b12aad776..766ef68a0b43 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -1,8 +1,6 @@
/*
* EHCI HCD (Host Controller Driver) for USB.
*
- * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
- *
* Bus Glue for AMD Alchemy Au1xxx
*
* Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
@@ -196,6 +194,9 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
/*
* basic lifecycle operations
+ *
+ * FIXME -- ehci_init() doesn't do enough here.
+ * See ehci-ppc-soc for a complete implementation.
*/
.reset = ehci_init,
.start = ehci_run,
@@ -219,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .hub_suspend = ehci_hub_suspend,
- .hub_resume = ehci_hub_resume,
-#endif
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c4e15ed1405a..c1514442883e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -275,58 +275,6 @@ static void ehci_work(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_CPU_FREQ
-
-#include <linux/cpufreq.h>
-
-static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ehci->lock, flags);
- if (!ehci->cpufreq_changing++)
- qh_inactivate_split_intr_qhs(ehci);
- spin_unlock_irqrestore(&ehci->lock, flags);
-}
-
-static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ehci->lock, flags);
- if (!--ehci->cpufreq_changing)
- qh_reactivate_split_intr_qhs(ehci);
- spin_unlock_irqrestore(&ehci->lock, flags);
-}
-
-/*
- * ehci_cpufreq_notifier is needed to avoid MMF errors that occur when
- * EHCI controllers that don't cache many uframes get delayed trying to
- * read main memory during CPU frequency transitions. This can cause
- * split interrupt transactions to not be completed in the required uframe.
- * This has been observed on the Broadcom/ServerWorks HT1000 controller.
- */
-static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
- cpufreq_transition);
-
- switch (val) {
- case CPUFREQ_PRECHANGE:
- ehci_cpufreq_pause(ehci);
- break;
- case CPUFREQ_POSTCHANGE:
- ehci_cpufreq_unpause(ehci);
- break;
- }
- return 0;
-}
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
@@ -460,10 +408,6 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
-#ifdef CONFIG_CPU_FREQ
- cpufreq_unregister_notifier(&ehci->cpufreq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-#endif
/* let companion controllers work when we aren't */
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
@@ -569,17 +513,6 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
-#ifdef CONFIG_CPU_FREQ
- INIT_LIST_HEAD(&ehci->split_intr_qhs);
- /*
- * If the EHCI controller caches enough uframes, this probably
- * isn't needed unless there are so many low/full speed devices
- * that the controller's can't cache it all.
- */
- ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
- cpufreq_register_notifier(&ehci->cpufreq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-#endif
return 0;
}
@@ -637,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
* are explicitly handed to companion controller(s), so no TT is
* involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.)
+ *
+ * Turning on the CF flag will transfer ownership of all ports
+ * from the companions to the EHCI controller. If any of the
+ * companions are in the middle of a port reset at the time, it
+ * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
+ * guarantees that no resets are in progress.
*/
+ down_write(&ehci_cf_port_reset_rwsem);
hcd->state = HC_STATE_RUNNING;
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ up_write(&ehci_cf_port_reset_rwsem);
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
@@ -786,7 +727,6 @@ dead:
*/
static int ehci_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -801,12 +741,12 @@ static int ehci_urb_enqueue (
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
- return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+ return submit_async(ehci, urb, &qtd_list, mem_flags);
case PIPE_INTERRUPT:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
- return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+ return intr_submit(ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
if (urb->dev->speed == USB_SPEED_HIGH)
@@ -844,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
* completions normally happen asynchronously
*/
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh;
unsigned long flags;
+ int rc;
spin_lock_irqsave (&ehci->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL:
// case PIPE_BULK:
@@ -905,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 8816d09903d0..0431397836f6 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -94,9 +94,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
-#ifdef CONFIG_CPU_FREQ
- INIT_LIST_HEAD (&qh->split_intr_qhs);
-#endif
/* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a7816e392a85..ad0d4965f2fb 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if (!retval)
ehci_dbg(ehci, "MWI active\n");
- ehci_port_power(ehci, 0);
-
return 0;
}
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break;
}
- if (ehci_is_TDI(ehci))
- ehci_reset(ehci);
+ ehci_reset(ehci);
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index c2cedb09ed8b..452d4b1bc859 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -6,7 +6,7 @@
* Bus Glue for PPC On-Chip EHCI driver
* Tested on AMCC 440EPx
*
- * Based on "ehci-au12xx.c" by David Brownell <dbrownell@users.sourceforge.net>
+ * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
*
* This file is licenced under the GPL.
*/
@@ -15,6 +15,24 @@
extern int usb_disabled(void);
+/* called during probe() after chip reset completes */
+static int ehci_ppc_soc_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci->sbrn = 0x20;
+ return ehci_reset(ehci);
+}
+
/**
* usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
* Context: !in_interrupt()
@@ -120,7 +138,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
/*
* basic lifecycle operations
*/
- .reset = ehci_init,
+ .reset = ehci_ppc_soc_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -142,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .hub_suspend = ehci_hub_suspend,
- .hub_resume = ehci_hub_resume,
-#endif
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 829fe649a981..03a6b2f4e6ed 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
if (result)
return result;
- ehci_port_power(ehci, 0);
+ ehci_reset(ehci);
return result;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 2284028f8aa5..b10f39c047e9 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-static void qtd_copy_status (
+static int qtd_copy_status (
struct ehci_hcd *ehci,
struct urb *urb,
size_t length,
u32 token
)
{
+ int status = -EINPROGRESS;
+
/* count IN/OUT bytes, not SETUP (even short packets) */
if (likely (QTD_PID (token) != 2))
urb->actual_length += length - QTD_LENGTH (token);
/* don't modify error codes */
- if (unlikely (urb->status != -EINPROGRESS))
- return;
+ if (unlikely(urb->unlinked))
+ return status;
/* force cleanup after short read; not always an error */
if (unlikely (IS_SHORT_READ (token)))
- urb->status = -EREMOTEIO;
+ status = -EREMOTEIO;
/* serious "can't proceed" faults reported by the hardware */
if (token & QTD_STS_HALT) {
if (token & QTD_STS_BABBLE) {
/* FIXME "must" disable babbling device's port too */
- urb->status = -EOVERFLOW;
+ status = -EOVERFLOW;
} else if (token & QTD_STS_MMF) {
/* fs/ls interrupt xfer missed the complete-split */
- urb->status = -EPROTO;
+ status = -EPROTO;
} else if (token & QTD_STS_DBE) {
- urb->status = (QTD_PID (token) == 1) /* IN ? */
+ status = (QTD_PID (token) == 1) /* IN ? */
? -ENOSR /* hc couldn't read data */
: -ECOMM; /* hc couldn't write data */
} else if (token & QTD_STS_XACT) {
/* timeout, bad crc, wrong PID, etc; retried */
if (QTD_CERR (token))
- urb->status = -EPIPE;
+ status = -EPIPE;
else {
ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out");
- urb->status = -EPROTO;
+ status = -EPROTO;
}
/* CERR nonzero + no errors + halt --> stall */
} else if (QTD_CERR (token))
- urb->status = -EPIPE;
+ status = -EPIPE;
else /* unknown */
- urb->status = -EPROTO;
+ status = -EPROTO;
ehci_vdbg (ehci,
"dev%d ep%d%s qtd token %08x --> status %d\n",
usb_pipedevice (urb->pipe),
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- token, urb->status);
+ token, status);
/* if async CSPLIT failed, try cleaning out the TT buffer */
- if (urb->status != -EPIPE
+ if (status != -EPIPE
&& urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
}
}
+
+ return status;
}
static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
__releases(ehci->lock)
__acquires(ehci->lock)
{
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
qh_put (qh);
}
- spin_lock (&urb->lock);
- urb->hcpriv = NULL;
- switch (urb->status) {
- case -EINPROGRESS: /* success */
- urb->status = 0;
- default: /* fault */
- COUNT (ehci->stats.complete);
- break;
- case -EREMOTEIO: /* fault or normal */
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
- urb->status = 0;
- COUNT (ehci->stats.complete);
- break;
- case -ECONNRESET: /* canceled */
- case -ENOENT:
- COUNT (ehci->stats.unlink);
- break;
+ if (unlikely(urb->unlinked)) {
+ COUNT(ehci->stats.unlink);
+ } else {
+ if (likely(status == -EINPROGRESS))
+ status = 0;
+ COUNT(ehci->stats.complete);
}
- spin_unlock (&urb->lock);
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
__FUNCTION__, urb->dev->devpath, urb,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- urb->status,
+ status,
urb->actual_length, urb->transfer_buffer_length);
#endif
/* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
spin_unlock (&ehci->lock);
- usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+ usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
spin_lock (&ehci->lock);
}
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
struct list_head *entry, *tmp;
+ int last_status = -EINPROGRESS;
int stopped;
unsigned count = 0;
int do_status = 0;
@@ -311,10 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct ehci_qtd *qtd;
struct urb *urb;
u32 token = 0;
-
- /* ignore QHs that are currently inactive */
- if (qh->hw_info1 & __constant_cpu_to_le32(QH_INACTIVATE))
- break;
+ int qtd_status;
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@@ -322,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
- ehci_urb_done (ehci, last->urb);
+ ehci_urb_done(ehci, last->urb, last_status);
count++;
}
ehci_qtd_free (ehci, last);
last = NULL;
+ last_status = -EINPROGRESS;
}
/* ignore urbs submitted during completions we reported */
@@ -362,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
- urb->status = -ESHUTDOWN;
+ last_status = -ESHUTDOWN;
/* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds.
*/
- if (likely (urb->status == -EINPROGRESS))
+ if (likely(last_status == -EINPROGRESS &&
+ !urb->unlinked))
continue;
/* issue status after short control reads */
@@ -396,11 +389,14 @@ halt:
}
/* remove it from the queue */
- spin_lock (&urb->lock);
- qtd_copy_status (ehci, urb, qtd->length, token);
- do_status = (urb->status == -EREMOTEIO)
- && usb_pipecontrol (urb->pipe);
- spin_unlock (&urb->lock);
+ qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+ if (unlikely(qtd_status == -EREMOTEIO)) {
+ do_status = (!urb->unlinked &&
+ usb_pipecontrol(urb->pipe));
+ qtd_status = 0;
+ }
+ if (likely(last_status == -EINPROGRESS))
+ last_status = qtd_status;
if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
last = list_entry (qtd->qtd_list.prev,
@@ -413,7 +409,7 @@ halt:
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
- ehci_urb_done (ehci, last->urb);
+ ehci_urb_done(ehci, last->urb, last_status);
count++;
ehci_qtd_free (ehci, last);
}
@@ -917,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
static int
submit_async (
struct ehci_hcd *ehci,
- struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@@ -926,10 +921,10 @@ submit_async (
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
- int rc = 0;
+ int rc;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
- epnum = ep->desc.bEndpointAddress;
+ epnum = urb->ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@@ -937,7 +932,7 @@ submit_async (
__FUNCTION__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
- qtd, ep->hcpriv);
+ qtd, urb->ep->hcpriv);
#endif
spin_lock_irqsave (&ehci->lock, flags);
@@ -946,9 +941,13 @@ submit_async (
rc = -ESHUTDOWN;
goto done;
}
+ rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(rc))
+ goto done;
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
if (unlikely(qh == NULL)) {
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
rc = -ENOMEM;
goto done;
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index d4a8ace49676..80d99bce2b38 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -479,109 +479,6 @@ static int disable_periodic (struct ehci_hcd *ehci)
}
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_CPU_FREQ
-
-static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
- int now; /* current (frame * 8) + uframe */
- int prev_start, next_start; /* uframes from/to split start */
- int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK);
- int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8);
- int split_duration = end_uframe - start_uframe;
-
- now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3);
-
- next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now)
- % (qh->period << 3);
- prev_start = (qh->period << 3) - next_start;
-
- /*
- * Make sure there will be at least one uframe when qh is safe.
- */
- if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration))
- /* never safe */
- return -EINVAL;
-
- /*
- * Wait 1 uframe after transaction should have started, to make
- * sure controller has time to write back overlay, so we can
- * check QTD_STS_STS to see if transaction is in progress.
- */
- if ((next_start > ehci->i_thresh) && (prev_start > 1))
- /* safe to set "i" bit if split isn't in progress */
- return (qh->hw_token & STATUS_BIT(ehci)) ? 0 : 1;
- else
- return 0;
-}
-
-/* Set inactivate bit for all the split interrupt QHs. */
-static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
-{
- struct ehci_qh *qh;
- int not_done, safe;
- u32 inactivate = INACTIVATE_BIT(ehci);
- u32 active = ACTIVE_BIT(ehci);
-
- do {
- not_done = 0;
- list_for_each_entry(qh, &ehci->split_intr_qhs,
- split_intr_qhs) {
- if (qh->hw_info1 & inactivate)
- /* already off */
- continue;
- /*
- * To avoid setting "I" after the start split happens,
- * don't set it if the QH might be cached in the
- * controller. Some HCs (Broadcom/ServerWorks HT1000)
- * will stop in the middle of a split transaction when
- * the "I" bit is set.
- */
- safe = safe_to_modify_i(ehci, qh);
- if (safe == 0) {
- not_done = 1;
- } else if (safe > 0) {
- qh->was_active = qh->hw_token & active;
- qh->hw_info1 |= inactivate;
- }
- }
- } while (not_done);
- wmb();
-}
-
-static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
-{
- struct ehci_qh *qh;
- u32 token;
- int not_done, safe;
- u32 inactivate = INACTIVATE_BIT(ehci);
- u32 active = ACTIVE_BIT(ehci);
- u32 halt = HALT_BIT(ehci);
-
- do {
- not_done = 0;
- list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) {
- if (!(qh->hw_info1 & inactivate)) /* already on */
- continue;
- /*
- * Don't reactivate if cached, or controller might
- * overwrite overlay after we modify it!
- */
- safe = safe_to_modify_i(ehci, qh);
- if (safe == 0) {
- not_done = 1;
- } else if (safe > 0) {
- /* See EHCI 1.0 section 4.15.2.4. */
- token = qh->hw_token;
- qh->hw_token = (token | halt) & ~active;
- wmb();
- qh->hw_info1 &= ~inactivate;
- wmb();
- qh->hw_token = (token & ~halt) | qh->was_active;
- }
- }
- } while (not_done);
-}
-#endif
/* periodic schedule slots have iso tds (normal or split) first, then a
* sparse tree for active interrupt transfers.
@@ -599,17 +496,6 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs);
-#ifdef CONFIG_CPU_FREQ
- /*
- * If low/full speed interrupt QHs are inactive (because of
- * cpufreq changing processor speeds), start QH with I flag set--
- * it will automatically be cleared when cpufreq is done.
- */
- if (ehci->cpufreq_changing)
- if (!(qh->hw_info1 & (cpu_to_le32(1 << 13))))
- qh->hw_info1 |= INACTIVATE_BIT(ehci);
-#endif
-
/* high bandwidth, or otherwise every microframe */
if (period == 0)
period = 1;
@@ -658,12 +544,6 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
? ((qh->usecs + qh->c_usecs) / qh->period)
: (qh->usecs * 8);
-#ifdef CONFIG_CPU_FREQ
- /* add qh to list of low/full speed interrupt QHs, if applicable */
- if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
- list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs);
- }
-#endif
/* maybe enable periodic schedule processing */
if (!ehci->periodic_sched++)
return enable_periodic (ehci);
@@ -683,13 +563,6 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
// THEN
// qh->hw_info1 |= __constant_cpu_to_hc32(1 << 7 /* "ignore" */);
-#ifdef CONFIG_CPU_FREQ
- /* remove qh from list of low/full speed interrupt QHs */
- if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
- list_del_init(&qh->split_intr_qhs);
- }
-#endif
-
/* high bandwidth, or otherwise part of every microframe */
if ((period = qh->period) == 0)
period = 1;
@@ -924,7 +797,6 @@ done:
static int intr_submit (
struct ehci_hcd *ehci,
- struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@@ -932,23 +804,26 @@ static int intr_submit (
unsigned epnum;
unsigned long flags;
struct ehci_qh *qh;
- int status = 0;
+ int status;
struct list_head empty;
/* get endpoint and transfer/schedule data */
- epnum = ep->desc.bEndpointAddress;
+ epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- goto done;
+ goto done_not_linked;
}
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
/* get qh and force any scheduling errors */
INIT_LIST_HEAD (&empty);
- qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
if (qh == NULL) {
status = -ENOMEM;
goto done;
@@ -959,13 +834,16 @@ static int intr_submit (
}
/* then queue the urb's tds to the qh */
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
done:
+ if (unlikely(status))
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
if (status)
qtd_list_free (ehci, urb, qtd_list);
@@ -1749,7 +1627,7 @@ itd_complete (
/* give urb back to the driver ... can be out-of-order */
dev = urb->dev;
- ehci_urb_done (ehci, urb);
+ ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -1813,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags)))
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- else
- status = iso_stream_schedule (ehci, urb, stream);
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(ehci, urb, stream);
if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
@@ -2115,7 +2000,7 @@ sitd_complete (
/* give urb back to the driver */
dev = urb->dev;
- ehci_urb_done (ehci, urb);
+ ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -2176,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags)))
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- else
- status = iso_stream_schedule (ehci, urb, stream);
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(ehci, urb, stream);
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2c68a04230c1..951d69fec513 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -71,12 +71,6 @@ struct ehci_hcd { /* one per controller */
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
-#ifdef CONFIG_CPU_FREQ
- struct notifier_block cpufreq_transition;
- int cpufreq_changing;
- struct list_head split_intr_qhs;
-#endif
-
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
@@ -439,10 +433,6 @@ struct ehci_qh {
__hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_HEAD 0x00008000
-#define QH_INACTIVATE 0x00000080
-
-#define INACTIVATE_BIT(ehci) cpu_to_hc32(ehci, QH_INACTIVATE)
-
__hc32 hw_info2; /* see EHCI 3.6.2 */
#define QH_SMASK 0x000000ff
#define QH_CMASK 0x0000ff00
@@ -492,10 +482,6 @@ struct ehci_qh {
unsigned short start; /* where polling starts */
#define NO_FRAME ((unsigned short)~0) /* pick new start */
struct usb_device *dev; /* access to TT */
-#ifdef CONFIG_CPU_FREQ
- struct list_head split_intr_qhs; /* list of split qhs */
- __le32 was_active; /* active bit before "i" set */
-#endif
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 46873f2534b5..c27417f5b9d8 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
struct urb, urb_list);
ptd = &ep->ptd;
len = ep->length;
- spin_lock(&urb->lock);
ep->data = (unsigned char *)urb->transfer_buffer
+ urb->actual_length;
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
| PTD_EP(ep->epnum);
ptd->len = PTD_LEN(len) | PTD_DIR(dir);
ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
- spin_unlock(&urb->lock);
if (!ep->active) {
ptd->mps |= PTD_LAST_MSK;
isp116x->atl_last_dir = dir;
@@ -275,6 +273,61 @@ static void preproc_atl_queue(struct isp116x *isp116x)
}
/*
+ Take done or failed requests out of schedule. Give back
+ processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+ struct urb *urb, int status)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+ unsigned i;
+
+ ep->error_count = 0;
+
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_SETUP;
+
+ urb_dbg(urb, "Finish");
+
+ usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
+ spin_unlock(&isp116x->lock);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
+ spin_lock(&isp116x->lock);
+
+ /* take idle endpoints out of the schedule */
+ if (!list_empty(&ep->hep->urb_list))
+ return;
+
+ /* async deschedule */
+ if (!list_empty(&ep->schedule)) {
+ list_del_init(&ep->schedule);
+ return;
+ }
+
+ /* periodic deschedule */
+ DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+ struct isp116x_ep *temp;
+ struct isp116x_ep **prev = &isp116x->periodic[i];
+
+ while (*prev && ((temp = *prev) != ep))
+ prev = &temp->next;
+ if (*prev)
+ *prev = ep->next;
+ isp116x->load[i] -= ep->load;
+ }
+ ep->branch = PERIODIC_SIZE;
+ isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+ ep->load / ep->period;
+
+ /* switch irq type? */
+ if (!--isp116x->periodic_count) {
+ isp116x->irqenb &= ~HCuPINT_SOF;
+ isp116x->irqenb |= HCuPINT_ATL;
+ }
+}
+
+/*
Analyze transfer results, handle partial transfers and errors
*/
static void postproc_atl_queue(struct isp116x *isp116x)
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
struct usb_device *udev;
struct ptd *ptd;
int short_not_ok;
+ int status;
u8 cc;
for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
ptd = &ep->ptd;
cc = PTD_GET_CC(ptd);
short_not_ok = 1;
- spin_lock(&urb->lock);
+ status = -EINPROGRESS;
/* Data underrun is special. For allowed underrun
we clear the error and continue as normal. For
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x)
immediately while for control transfer,
we do a STATUS stage. */
if (cc == TD_DATAUNDERRUN) {
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
- DBG("Allowed data underrun\n");
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+ usb_pipecontrol(urb->pipe)) {
+ DBG("Allowed or control data underrun\n");
cc = TD_CC_NOERROR;
short_not_ok = 0;
} else {
ep->error_count = 1;
- if (usb_pipecontrol(urb->pipe))
- ep->nextpid = USB_PID_ACK;
- else
- usb_settoggle(udev, ep->epnum,
- ep->nextpid ==
- USB_PID_OUT,
- PTD_GET_TOGGLE(ptd));
+ usb_settoggle(udev, ep->epnum,
+ ep->nextpid == USB_PID_OUT,
+ PTD_GET_TOGGLE(ptd));
urb->actual_length += PTD_GET_COUNT(ptd);
- urb->status = cc_to_error[TD_DATAUNDERRUN];
- spin_unlock(&urb->lock);
- continue;
+ status = cc_to_error[TD_DATAUNDERRUN];
+ goto done;
}
}
- /* Keep underrun error through the STATUS stage */
- if (urb->status == cc_to_error[TD_DATAUNDERRUN])
- cc = TD_DATAUNDERRUN;
if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
&& (++ep->error_count >= 3 || cc == TD_CC_STALL
|| cc == TD_DATAOVERRUN)) {
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error[cc];
+ status = cc_to_error[cc];
if (ep->nextpid == USB_PID_ACK)
ep->nextpid = 0;
- spin_unlock(&urb->lock);
- continue;
+ goto done;
}
/* According to usb spec, zero-length Int transfer signals
finishing of the urb. Hey, does this apply only
for IN endpoints? */
if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
- spin_unlock(&urb->lock);
- continue;
+ status = 0;
+ goto done;
}
/* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
/* All data for this URB is transferred, let's finish */
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_ACK;
- else if (urb->status == -EINPROGRESS)
- urb->status = 0;
+ else
+ status = 0;
break;
case USB_PID_SETUP:
if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,16 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
+ status = 0;
ep->nextpid = 0;
break;
default:
BUG();
}
- spin_unlock(&urb->lock);
- }
-}
-/*
- Take done or failed requests out of schedule. Give back
- processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
- struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
- unsigned i;
-
- urb->hcpriv = NULL;
- ep->error_count = 0;
-
- if (usb_pipecontrol(urb->pipe))
- ep->nextpid = USB_PID_SETUP;
-
- urb_dbg(urb, "Finish");
-
- spin_unlock(&isp116x->lock);
- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
- spin_lock(&isp116x->lock);
-
- /* take idle endpoints out of the schedule */
- if (!list_empty(&ep->hep->urb_list))
- return;
-
- /* async deschedule */
- if (!list_empty(&ep->schedule)) {
- list_del_init(&ep->schedule);
- return;
- }
-
- /* periodic deschedule */
- DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
- for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
- struct isp116x_ep *temp;
- struct isp116x_ep **prev = &isp116x->periodic[i];
-
- while (*prev && ((temp = *prev) != ep))
- prev = &temp->next;
- if (*prev)
- *prev = ep->next;
- isp116x->load[i] -= ep->load;
- }
- ep->branch = PERIODIC_SIZE;
- isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
- ep->load / ep->period;
-
- /* switch irq type? */
- if (!--isp116x->periodic_count) {
- isp116x->irqenb &= ~HCuPINT_SOF;
- isp116x->irqenb |= HCuPINT_ATL;
+ done:
+ if (status != -EINPROGRESS || urb->unlinked)
+ finish_request(isp116x, ep, urb, status);
}
}
@@ -570,9 +560,6 @@ static void start_atl_transfers(struct isp116x *isp116x)
*/
static void finish_atl_transfers(struct isp116x *isp116x)
{
- struct isp116x_ep *ep;
- struct urb *urb;
-
if (!isp116x->atl_active)
return;
/* Fifo not ready? */
@@ -582,16 +569,6 @@ static void finish_atl_transfers(struct isp116x *isp116x)
atomic_inc(&isp116x->atl_finishing);
unpack_fifo(isp116x);
postproc_atl_queue(isp116x);
- for (ep = isp116x->atl_active; ep; ep = ep->active) {
- urb =
- container_of(ep->hep->urb_list.next, struct urb, urb_list);
- /* USB_PID_ACK check here avoids finishing of
- control transfers, for which TD_DATAUNDERRUN
- occured, while URB_SHORT_NOT_OK was set */
- if (urb && urb->status != -EINPROGRESS
- && ep->nextpid != USB_PID_ACK)
- finish_request(isp116x, ep, urb);
- }
atomic_dec(&isp116x->atl_finishing);
}
@@ -685,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
/*-----------------------------------------------------------------*/
static int isp116x_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
gfp_t mem_flags)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -694,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
int is_out = !usb_pipein(pipe);
int type = usb_pipetype(pipe);
int epnum = usb_pipeendpoint(pipe);
+ struct usb_host_endpoint *hep = urb->ep;
struct isp116x_ep *ep = NULL;
unsigned long flags;
int i;
@@ -717,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
if (!HC_IS_RUNNING(hcd->state)) {
kfree(ep);
ret = -ENODEV;
- goto fail;
+ goto fail_not_linked;
+ }
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret) {
+ kfree(ep);
+ goto fail_not_linked;
}
if (hep->hcpriv)
@@ -820,19 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
}
- /* in case of unlink-during-submit */
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- finish_request(isp116x, ep, urb);
- ret = 0;
- goto fail;
- }
urb->hcpriv = hep;
- spin_unlock(&urb->lock);
start_atl_transfers(isp116x);
fail:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ fail_not_linked:
spin_unlock_irqrestore(&isp116x->lock, flags);
return ret;
}
@@ -840,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
/*
Dequeue URBs.
*/
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
struct usb_host_endpoint *hep;
struct isp116x_ep *ep, *ep_act;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&isp116x->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
hep = urb->hcpriv;
- /* URB already unlinked (or never linked)? */
- if (!hep) {
- spin_unlock_irqrestore(&isp116x->lock, flags);
- return 0;
- }
ep = hep->hcpriv;
WARN_ON(hep != ep->hep);
@@ -870,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
}
if (urb)
- finish_request(isp116x, ep, urb);
-
+ finish_request(isp116x, ep, urb, status);
+ done:
spin_unlock_irqrestore(&isp116x->lock, flags);
- return 0;
+ return rc;
}
static void isp116x_endpoint_disable(struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 6f9e43e9a6ca..ebab5ce8f5ce 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -24,7 +24,7 @@
* small: 0) header + data packets 1) just header
*/
static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
{
unsigned int pipe= urb->pipe;
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
}
#ifndef OHCI_VERBOSE_DEBUG
- if (urb->status != 0)
+ if (status != 0)
#endif
dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_flags,
urb->actual_length,
urb->transfer_buffer_length,
- urb->status);
+ status);
#ifdef OHCI_VERBOSE_DEBUG
if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_buffer_length: urb->actual_length;
for (i = 0; i < 16 && i < len; i++)
printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
- printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+ printk ("%s stat:%d\n", i < len? "...": "", status);
}
}
#endif
@@ -74,7 +74,7 @@ urb_print (struct urb * urb, char * str, int small)
#define ohci_dbg_sw(ohci, next, size, format, arg...) \
do { \
- if (next) { \
+ if (next != NULL) { \
unsigned s_len; \
s_len = scnprintf (*next, *size, format, ## arg ); \
*size -= s_len; *next += s_len; \
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 2038125b7f8c..240c7f507541 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "SUB", usb_pipein (pipe));
+ urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
- if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+ if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
/* for the private part of the URB we need the number of TDs (size) */
@@ -171,11 +169,10 @@ static int ohci_urb_enqueue (
}
/* allocate the private part of the URB */
- urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+ urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
mem_flags);
if (!urb_priv)
return -ENOMEM;
- memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
INIT_LIST_HEAD (&urb_priv->pending);
urb_priv->length = size;
urb_priv->ed = ed;
@@ -201,22 +198,17 @@ static int ohci_urb_enqueue (
retval = -ENODEV;
goto fail;
}
-
- /* in case of unlink-during-submit */
- spin_lock (&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock (&urb->lock);
- urb->hcpriv = urb_priv;
- finish_urb (ohci, urb);
- retval = 0;
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
goto fail;
- }
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
- if (retval < 0)
- goto fail0;
+ if (retval < 0) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ goto fail;
+ }
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = ohci_frame_no(ohci);
@@ -240,8 +232,6 @@ static int ohci_urb_enqueue (
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
-fail0:
- spin_unlock (&urb->lock);
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
@@ -250,22 +240,26 @@ fail:
}
/*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status. reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
+ int rc;
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "UNLINK", 1);
+ urb_print(urb, "UNLINK", 1, status);
#endif
spin_lock_irqsave (&ohci->lock, flags);
- if (HC_IS_RUNNING(hcd->state)) {
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc) {
+ ; /* Do nothing */
+ } else if (HC_IS_RUNNING(hcd->state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@@ -283,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv)
- finish_urb (ohci, urb);
+ finish_urb(ohci, urb, status);
}
spin_unlock_irqrestore (&ohci->lock, flags);
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
@@ -315,6 +309,8 @@ rescan:
if (!HC_IS_RUNNING (hcd->state)) {
sanitize:
ed->state = ED_IDLE;
+ if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+ ohci->eds_scheduled--;
finish_unlinks (ohci, 0);
}
@@ -322,7 +318,12 @@ sanitize:
case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */
if (limit-- == 0) {
- ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+ ohci_warn(ohci, "ED unlink timeout\n");
+ if (quirk_zfmicro(ohci)) {
+ ohci_warn(ohci, "Attempting ZF TD recovery\n");
+ ohci->ed_to_check = ed;
+ ohci->zf_delay = 2;
+ }
goto sanitize;
}
spin_unlock_irqrestore (&ohci->lock, flags);
@@ -380,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
}
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+ return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+ && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+ == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+ && !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist. On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+ long flags;
+ unsigned max;
+ unsigned seen_count = 0;
+ unsigned i;
+ struct ed **seen = NULL;
+ struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+ max = ohci->eds_scheduled;
+ if (!max)
+ goto done;
+
+ if (ohci->ed_to_check)
+ goto out;
+
+ seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+ if (!seen)
+ goto out;
+
+ for (i = 0; i < NUM_INTS; i++) {
+ struct ed *ed = ohci->periodic[i];
+
+ while (ed) {
+ unsigned temp;
+
+ /* scan this branch of the periodic schedule tree */
+ for (temp = 0; temp < seen_count; temp++) {
+ if (seen[temp] == ed) {
+ /* we've checked it and what's after */
+ ed = NULL;
+ break;
+ }
+ }
+ if (!ed)
+ break;
+ seen[seen_count++] = ed;
+ if (!check_ed(ohci, ed)) {
+ ed = ed->ed_next;
+ continue;
+ }
+
+ /* HC's TD list is empty, but HCD sees at least one
+ * TD that's not been sent through the donelist.
+ */
+ ohci->ed_to_check = ed;
+ ohci->zf_delay = 2;
+
+ /* The HC may wait until the next frame to report the
+ * TD as done through the donelist and INTR_WDH. (We
+ * just *assume* it's not a multi-TD interrupt URB;
+ * those could defer the IRQ more than one frame, using
+ * DI...) Check again after the next INTR_SF.
+ */
+ ohci_writel(ohci, OHCI_INTR_SF,
+ &ohci->regs->intrstatus);
+ ohci_writel(ohci, OHCI_INTR_SF,
+ &ohci->regs->intrenable);
+
+ /* flush those writes */
+ (void) ohci_readl(ohci, &ohci->regs->control);
+
+ goto out;
+ }
+ }
+out:
+ kfree(seen);
+ if (ohci->eds_scheduled)
+ mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+ spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@@ -617,6 +705,15 @@ retry:
mdelay ((temp >> 23) & 0x1fe);
hcd->state = HC_STATE_RUNNING;
+ if (quirk_zfmicro(ohci)) {
+ /* Create timer to watch for bad queue state on ZF Micro */
+ setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+ (unsigned long) ohci);
+
+ ohci->eds_scheduled = 0;
+ ohci->ed_to_check = NULL;
+ }
+
ohci_dump (ohci, 1);
return 0;
@@ -630,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs __iomem *regs = ohci->regs;
- int ints;
+ int ints;
/* we can eliminate a (slow) ohci_readl()
- if _only_ WDH caused this irq */
+ * if _only_ WDH caused this irq
+ */
if ((ohci->hcca->done_head != 0)
&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
& 0x01)) {
@@ -652,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if (ints & OHCI_INTR_UE) {
// e.g. due to PCI Master/Target Abort
- if (ohci->flags & OHCI_QUIRK_NEC) {
+ if (quirk_nec(ohci)) {
/* Workaround for a silicon bug in some NEC chips used
* in Apple's PowerBooks. Adapted from Darwin code.
*/
@@ -714,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
}
+ if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+ spin_lock(&ohci->lock);
+ if (ohci->ed_to_check) {
+ struct ed *ed = ohci->ed_to_check;
+
+ if (check_ed(ohci, ed)) {
+ /* HC thinks the TD list is empty; HCD knows
+ * at least one TD is outstanding
+ */
+ if (--ohci->zf_delay == 0) {
+ struct td *td = list_entry(
+ ed->td_list.next,
+ struct td, td_list);
+ ohci_warn(ohci,
+ "Reclaiming orphan TD %p\n",
+ td);
+ takeback_td(ohci, td);
+ ohci->ed_to_check = NULL;
+ }
+ } else
+ ohci->ed_to_check = NULL;
+ }
+ spin_unlock(&ohci->lock);
+ }
+
/* could track INTR_SO to reduce available PCI/... bandwidth */
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -722,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, ohci_frame_no(ohci));
- if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+ if ((ints & OHCI_INTR_SF) != 0
+ && !ohci->ed_rm_list
+ && !ohci->ed_to_check
&& HC_IS_RUNNING(hcd->state))
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
@@ -752,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
free_irq(hcd->irq, hcd);
hcd->irq = -1;
+ if (quirk_zfmicro(ohci))
+ del_timer(&ohci->unlink_watchdog);
+
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
@@ -799,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
ed, ed->state);
}
- spin_lock (&urb->lock);
- urb->status = -ESHUTDOWN;
- spin_unlock (&urb->lock);
+ if (!urb->unlinked)
+ urb->unlinked = -ESHUTDOWN;
}
finish_unlinks (ohci, 0);
spin_unlock_irq(&ohci->lock);
@@ -829,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
- struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
- int status;
-
- status = ohci_init(ohci);
- if (status != 0) {
- ohci_err(ohci, "Restarting NEC controller failed "
- "in ohci_init, %d\n", status);
- return;
- }
-
- status = ohci_restart(ohci);
- if (status != 0)
- ohci_err(ohci, "Restarting NEC controller failed "
- "in ohci_restart, %d\n", status);
-}
-
-/*-------------------------------------------------------------------------*/
-
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -927,11 +1033,17 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER ssb_ohci_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER)
+ !defined(PS3_SYSTEM_BUS_DRIVER) && \
+ !defined(SSB_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -976,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
goto error_pci;
#endif
+#ifdef SSB_OHCI_DRIVER
+ retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+ if (retval)
+ goto error_ssb;
+#endif
+
return retval;
/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
error_pci:
#endif
#ifdef SA1111_DRIVER
@@ -1004,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
+#ifdef SSB_OHCI_DRIVER
+ ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 450c7b460c5a..2f20d3dc895b 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
- INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a5e2eb85d073..d0360f65ebd9 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_ZFMICRO;
- ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+ ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
return 0;
}
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
/* Check for NEC chip and apply quirk for allegedly lost interrupts.
*/
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+ struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+ int status;
+
+ status = ohci_init(ohci);
+ if (status != 0) {
+ ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+ "ohci_init", status);
+ return;
+ }
+
+ status = ohci_restart(ohci);
+ if (status != 0)
+ ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+ "ohci_restart", status);
+}
+
static int ohci_quirk_nec(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_NEC;
+ INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
return 0;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index c43b66acd4d5..0a7426920150 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}
ohci = hcd_to_ohci(hcd);
- if (is_bigendian)
+ if (is_bigendian) {
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ if (of_device_is_compatible(dn, "mpc5200-ohci"))
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ }
ohci_hcd_init(ohci);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e1777ca61..f95be1896b0d 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+ /* MPC52xx doesn't need frame_no shift */
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 830a3fe8615e..51817322232b 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
* PRECONDITION: ohci lock held, irqs blocked.
*/
static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
__releases(ohci->lock)
__acquires(ohci->lock)
{
// ASSERT (urb->hcpriv != 0);
urb_free_priv (ohci, urb->hcpriv);
- urb->hcpriv = NULL;
-
- spin_lock (&urb->lock);
- if (likely (urb->status == -EINPROGRESS))
- urb->status = 0;
- /* report short control reads right even though the data TD always
- * has TD_R set. (much simpler, but creates the 1-td limit.)
- */
- if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
- && unlikely (usb_pipecontrol (urb->pipe))
- && urb->actual_length < urb->transfer_buffer_length
- && usb_pipein (urb->pipe)
- && urb->status == 0) {
- urb->status = -EREMOTEIO;
- }
- spin_unlock (&urb->lock);
+ if (likely(status == -EINPROGRESS))
+ status = 0;
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
}
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "RET", usb_pipeout (urb->pipe));
+ urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
#endif
/* urb->complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
spin_unlock (&ohci->lock);
- usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+ usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
spin_lock (&ohci->lock);
/* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
ed->ed_prev = NULL;
ed->ed_next = NULL;
ed->hwNextED = 0;
+ if (quirk_zfmicro(ohci)
+ && (ed->type == PIPE_INTERRUPT)
+ && !(ohci->eds_scheduled++))
+ mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
wmb ();
/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@ static void td_submit_urb (
* Done List handling functions
*-------------------------------------------------------------------------*/
-/* calculate transfer length/status and update the urb
- * PRECONDITION: irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
{
u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
int cc = 0;
+ int status = -EINPROGRESS;
list_del (&td->td_list);
/* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
- u16 tdPSW = ohci_hwPSW (ohci, td, 0);
+ u16 tdPSW = ohci_hwPSW(ohci, td, 0);
int dlen = 0;
/* NOTE: assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
cc = (tdPSW >> 12) & 0xF;
if (tdINFO & TD_CC) /* hc didn't touch? */
- return;
+ return status;
if (usb_pipeout (urb->pipe))
dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
if (cc == TD_DATAUNDERRUN
&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
cc = TD_CC_NOERROR;
- if (cc != TD_CC_NOERROR && cc < 0x0E) {
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error [cc];
- spin_unlock (&urb->lock);
- }
+ if (cc != TD_CC_NOERROR && cc < 0x0E)
+ status = cc_to_error[cc];
/* count all non-empty packets except control SETUP packet */
if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
urb->actual_length,
urb->transfer_buffer_length);
}
+ return status;
}
/*-------------------------------------------------------------------------*/
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
{
struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
struct list_head *tmp = td->td_list.next;
__hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
wmb ();
ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
- /* put any later tds from this urb onto the donelist, after 'td',
- * order won't matter here: no errors, and nothing was transferred.
- * also patch the ed so it looks as if those tds completed normally.
+ /* Get rid of all later tds from this urb. We don't have
+ * to be careful: no errors and nothing was transferred.
+ * Also patch the ed so it looks as if those tds completed normally.
*/
while (tmp != &ed->td_list) {
struct td *next;
- __hc32 info;
next = list_entry (tmp, struct td, td_list);
tmp = next->td_list.next;
@@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
* then we need to leave the control STATUS packet queued
* and clear ED_SKIP.
*/
- info = next->hwINFO;
- info |= cpu_to_hc32 (ohci, TD_DONE);
- info &= ~cpu_to_hc32 (ohci, TD_CC);
- next->hwINFO = info;
-
- next->next_dl_td = rev;
- rev = next;
+ list_del(&next->td_list);
+ urb_priv->td_cnt++;
ed->hwHeadP = next->hwNextTD | toggle;
}
@@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
hc32_to_cpu (ohci, td->hwINFO),
cc, cc_to_error [cc]);
}
-
- return rev;
}
/* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
*/
if (cc != TD_CC_NOERROR
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
- td_rev = ed_halted (ohci, td, cc, td_rev);
+ ed_halted(ohci, td, cc);
td->next_dl_td = td_rev;
td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
TD_MASK;
/* INTR_WDH may need to clean up first */
- if (td->td_dma != head)
- goto skip_ed;
+ if (td->td_dma != head) {
+ if (ed == ohci->ed_to_check)
+ ohci->ed_to_check = NULL;
+ else
+ goto skip_ed;
+ }
}
}
@@ -974,7 +957,7 @@ rescan_this:
urb = td->urb;
urb_priv = td->urb->hcpriv;
- if (urb->status == -EINPROGRESS) {
+ if (!urb->unlinked) {
prev = &td->hwNextTD;
continue;
}
@@ -990,7 +973,7 @@ rescan_this:
/* if URB is done, clean up */
if (urb_priv->td_cnt == urb_priv->length) {
modified = completed = 1;
- finish_urb (ohci, urb);
+ finish_urb(ohci, urb, 0);
}
}
if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
/* ED's now officially unlinked, hc doesn't see */
ed->state = ED_IDLE;
+ if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+ ohci->eds_scheduled--;
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
ed->hwNextED = 0;
wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
if (ohci->ed_controltail) {
command |= OHCI_CLF;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
}
if (ohci->ed_bulktail) {
command |= OHCI_BLF;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
if (control) {
ohci->hc_control |= control;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, ohci->hc_control,
&ohci->regs->control);
}
if (command) {
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, command, &ohci->regs->cmdstatus);
}
@@ -1061,11 +1046,60 @@ rescan_this:
/*-------------------------------------------------------------------------*/
/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames). This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+ struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
+ struct ed *ed = td->ed;
+ int status;
+
+ /* update URB's length and status from TD */
+ status = td_done(ohci, urb, td);
+ urb_priv->td_cnt++;
+
+ /* If all this urb's TDs are done, call complete() */
+ if (urb_priv->td_cnt == urb_priv->length)
+ finish_urb(ohci, urb, status);
+
+ /* clean schedule: unlink EDs that are no longer busy */
+ if (list_empty(&ed->td_list)) {
+ if (ed->state == ED_OPER)
+ start_ed_unlink(ohci, ed);
+
+ /* ... reenabling halted EDs only after fault cleanup */
+ } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+ == cpu_to_hc32(ohci, ED_SKIP)) {
+ td = list_entry(ed->td_list.next, struct td, td_list);
+ if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+ ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+ /* ... hc may need waking-up */
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ohci_writel(ohci, OHCI_CLF,
+ &ohci->regs->cmdstatus);
+ break;
+ case PIPE_BULK:
+ ohci_writel(ohci, OHCI_BLF,
+ &ohci->regs->cmdstatus);
+ break;
+ }
+ }
+ }
+}
+
+/*
* Process normal completions (error or success) and clean the schedules.
*
* This is the main path for handing urbs back to drivers. The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does. There's
+ * an abnormal path too, handling a quirk in some Compaq silicon: URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
*/
static void
dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
while (td) {
struct td *td_next = td->next_dl_td;
- struct urb *urb = td->urb;
- urb_priv_t *urb_priv = urb->hcpriv;
- struct ed *ed = td->ed;
-
- /* update URB's length and status from TD */
- td_done (ohci, urb, td);
- urb_priv->td_cnt++;
-
- /* If all this urb's TDs are done, call complete() */
- if (urb_priv->td_cnt == urb_priv->length)
- finish_urb (ohci, urb);
-
- /* clean schedule: unlink EDs that are no longer busy */
- if (list_empty (&ed->td_list)) {
- if (ed->state == ED_OPER)
- start_ed_unlink (ohci, ed);
-
- /* ... reenabling halted EDs only after fault cleanup */
- } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
- ED_SKIP | ED_DEQUEUE))
- == cpu_to_hc32 (ohci, ED_SKIP)) {
- td = list_entry (ed->td_list.next, struct td, td_list);
- if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
- ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
- /* ... hc may need waking-up */
- switch (ed->type) {
- case PIPE_CONTROL:
- ohci_writel (ohci, OHCI_CLF,
- &ohci->regs->cmdstatus);
- break;
- case PIPE_BULK:
- ohci_writel (ohci, OHCI_BLF,
- &ohci->regs->cmdstatus);
- break;
- }
- }
- }
-
+ takeback_td(ohci, td);
td = td_next;
}
}
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644
index 000000000000..bc3e785d8c00
--- /dev/null
+++ b/drivers/usb/host/ohci-ssb.c
@@ -0,0 +1,247 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
+
+struct ssb_ohci_device {
+ struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+ u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+ return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ int err;
+
+ ohci_hcd_init(ohci);
+ err = ohci_init(ohci);
+
+ return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ int err;
+
+ err = ohci_run(ohci);
+ if (err < 0) {
+ ohci_err(ohci, "can't start\n");
+ ohci_stop(hcd);
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+ /* make sure snapshot being resumed re-enumerates everything */
+ if (message.event == PM_EVENT_PRETHAW)
+ ohci_usb_reset(ohci);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ usb_hcd_resume_root_hub(hcd);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+ .description = "ssb-usb-ohci",
+ .product_desc = "SSB OHCI Controller",
+ .hcd_priv_size = sizeof(struct ssb_ohci_device),
+
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+
+ .reset = ssb_ohci_reset,
+ .start = ssb_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+#ifdef CONFIG_PM
+ .suspend = ssb_ohci_hcd_suspend,
+ .resume = ssb_ohci_hcd_resume,
+#endif
+
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ .get_frame_number = ohci_get_frame,
+
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ usb_put_hcd(hcd);
+ ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+ struct ssb_ohci_device *ohcidev;
+ struct usb_hcd *hcd;
+ int err = -ENOMEM;
+ u32 tmp, flags = 0;
+
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+ ssb_device_enable(dev, flags);
+
+ hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+ dev->dev->bus_id);
+ if (!hcd)
+ goto err_dev_disable;
+ ohcidev = hcd_to_ssb_ohci(hcd);
+ ohcidev->enable_flags = flags;
+
+ tmp = ssb_read32(dev, SSB_ADMATCH0);
+ hcd->rsrc_start = ssb_admatch_base(tmp);
+ hcd->rsrc_len = ssb_admatch_size(tmp);
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs)
+ goto err_put_hcd;
+ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+ if (err)
+ goto err_iounmap;
+
+ ssb_set_drvdata(dev, hcd);
+
+ return err;
+
+err_iounmap:
+ iounmap(hcd->regs);
+err_put_hcd:
+ usb_put_hcd(hcd);
+err_dev_disable:
+ ssb_device_disable(dev, flags);
+ return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ int err;
+ u16 chipid_top;
+
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (dev->bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
+ * as HOST OHCI. If we want to attach it as Client device,
+ * we must branch here and call into the (yet to
+ * be written) Client mode driver. Same for remove(). */
+
+ err = ssb_ohci_attach(dev);
+
+ return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+ ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ ssb_device_disable(dev, 0);
+
+ return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+ ssb_device_enable(dev, ohcidev->enable_flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend NULL
+#define ssb_ohci_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ssb_ohci_table,
+ .probe = ssb_ohci_probe,
+ .remove = ssb_ohci_remove,
+ .suspend = ssb_ohci_suspend,
+ .resume = ssb_ohci_resume,
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 4ada43cf1387..47c5c66a282c 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -398,11 +398,38 @@ struct ohci_hcd {
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
+#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
+
+ /* Needed for ZF Micro quirk */
+ struct timer_list unlink_watchdog;
+ unsigned eds_scheduled;
+ struct ed *ed_to_check;
+ unsigned zf_delay;
};
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+ return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+ return 0;
+}
+#endif
+
/* convert between an hcd pointer and the corresponding ohci_hcd */
static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
{
@@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
*/
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT 16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO)
#else
-#define OHCI_BE_FRAME_NO_SHIFT 0
+#define big_endian_frame_no_quirk(ohci) 0
#endif
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
u32 tmp;
if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
- tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+ if (!big_endian_frame_no_quirk(ohci))
+ tmp >>= 16;
} else
tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index a7a7070c6e2a..ae8ec4474eb8 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -35,10 +35,8 @@
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
#include "../core/hcd.h"
#include "r8a66597.h"
@@ -54,16 +52,21 @@ static const char hcd_name[] = "r8a66597_hcd";
/* module parameters */
static unsigned short clock = XTAL12;
module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+ "(default=0)");
+
static unsigned short vif = LDRV;
module_param(vif, ushort, 0644);
MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+
+static unsigned short endian;
module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
static unsigned short irq_sense = INTL;
module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+ "(default=32)");
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
static int r8a66597_get_frame(struct usb_hcd *hcd);
@@ -308,7 +311,7 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
struct r8a66597_device *dev;
int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */
- dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
if (dev == NULL)
return -ENOMEM;
@@ -611,33 +614,33 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
memset(array, 0, sizeof(array));
- switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_BULK:
+ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
array[i++] = 4;
else {
array[i++] = 3;
array[i++] = 5;
}
- break;
- case USB_ENDPOINT_XFER_INT:
+ break;
+ case USB_ENDPOINT_XFER_INT:
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
array[i++] = 6;
array[i++] = 7;
array[i++] = 8;
} else
array[i++] = 9;
- break;
- case USB_ENDPOINT_XFER_ISOC:
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
array[i++] = 2;
else
array[i++] = 1;
- break;
- default:
- err("Illegal type");
- return 0;
- }
+ break;
+ default:
+ err("Illegal type");
+ return 0;
+ }
i = 1;
min = array[0];
@@ -654,7 +657,7 @@ static u16 get_r8a66597_type(__u8 type)
{
u16 r8a66597_type;
- switch(type) {
+ switch (type) {
case USB_ENDPOINT_XFER_BULK:
r8a66597_type = R8A66597_BULK;
break;
@@ -779,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
kfree(td);
if (urb) {
- urb->status = -ENODEV;
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+ urb);
+
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+ usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+ -ENODEV);
spin_lock(&r8a66597->lock);
}
break;
@@ -829,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
info.pipenum = get_empty_pipenum(r8a66597, ep);
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = ep->wMaxPacketSize;
+ info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
info.type = get_r8a66597_type(ep->bmAttributes
& USB_ENDPOINT_XFERTYPE_MASK);
info.bufnum = get_bufnum(info.pipenum);
@@ -874,7 +879,7 @@ static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
{
r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
| (1 << USB_PORT_FEAT_C_CONNECTION);
- r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+ r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
}
@@ -917,10 +922,10 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
DCPMAXP);
- r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+ r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
- r8a66597_write(r8a66597, p[i], setup_addr);
+ r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
setup_addr += 2;
}
r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -948,19 +953,18 @@ static void prepare_packet_read(struct r8a66597 *r8a66597,
pipe_irq_disable(r8a66597, td->pipenum);
pipe_setting(r8a66597, td);
pipe_stop(r8a66597, td->pipe);
- r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
- BRDYSTS);
+ r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
if (td->pipe->pipetre) {
r8a66597_write(r8a66597, TRCLR,
- td->pipe->pipetre);
+ td->pipe->pipetre);
r8a66597_write(r8a66597,
- (urb->transfer_buffer_length
- + td->maxpacket - 1)
- / td->maxpacket,
- td->pipe->pipetrn);
+ (urb->transfer_buffer_length
+ + td->maxpacket - 1)
+ / td->maxpacket,
+ td->pipe->pipetrn);
r8a66597_bset(r8a66597, TRENB,
- td->pipe->pipetre);
+ td->pipe->pipetre);
}
pipe_start(r8a66597, td->pipe);
@@ -991,7 +995,7 @@ static void prepare_packet_write(struct r8a66597 *r8a66597,
if (td->pipe->pipetre)
r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
}
- r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+ r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
@@ -1009,27 +1013,36 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
struct urb *urb = td->urb;
r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+ pipe_stop(r8a66597, td->pipe);
if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
- r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
- r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ r8a66597_write(r8a66597, BVAL, CFIFOCTR);
enable_irq_empty(r8a66597, 0);
} else {
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
- r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
enable_irq_ready(r8a66597, 0);
}
enable_irq_nrdy(r8a66597, 0);
pipe_start(r8a66597, td->pipe);
}
+static int is_set_address(unsigned char *setup_packet)
+{
+ if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+ setup_packet[1] == USB_REQ_SET_ADDRESS)
+ return 1;
+ else
+ return 0;
+}
+
/* this function must be called with interrupt disabled */
static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
@@ -1037,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
switch (td->type) {
case USB_PID_SETUP:
- if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+ if (is_set_address(td->urb->setup_packet)) {
td->set_address = 1;
td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
td->urb);
@@ -1104,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
}
/* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+ u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
int restart = 0;
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1113,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
r8a66597->timeout_map &= ~(1 << pipenum);
if (likely(td)) {
- if (td->set_address && urb->status != 0)
+ if (td->set_address && (status != 0 || urb->unlinked))
r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1128,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&r8a66597->lock);
}
@@ -1144,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
}
}
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
- done(r8a66597, td, pipenum, urb);
-}
-
static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
{
u16 tmp;
@@ -1160,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
struct urb *urb;
int finish = 0;
+ int status = 0;
if (unlikely(!td))
return;
@@ -1168,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("in fifo not ready (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
return;
}
/* prepare parameters */
rcv_len = tmp & DTLN;
- bufsize = td->maxpacket;
if (usb_pipeisoc(urb->pipe)) {
buf = (u16 *)(urb->transfer_buffer +
urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1187,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf = (void *)urb->transfer_buffer + urb->actual_length;
urb_len = urb->transfer_buffer_length - urb->actual_length;
}
- if (rcv_len < bufsize)
- size = min(rcv_len, urb_len);
- else
- size = min(bufsize, urb_len);
+ bufsize = min(urb_len, (int) td->maxpacket);
+ if (rcv_len <= bufsize) {
+ size = rcv_len;
+ } else {
+ size = bufsize;
+ status = -EOVERFLOW;
+ finish = 1;
+ }
/* update parameters */
urb->actual_length += size;
if (rcv_len == 0)
td->zero_packet = 1;
- if ((size % td->maxpacket) > 0) {
+ if (rcv_len < bufsize) {
td->short_packet = 1;
- if (urb->transfer_buffer_length != urb->actual_length &&
- urb->transfer_flags & URB_SHORT_NOT_OK)
- td->urb->status = -EREMOTEIO;
}
if (usb_pipeisoc(urb->pipe)) {
urb->iso_frame_desc[td->iso_cnt].actual_length = size;
- urb->iso_frame_desc[td->iso_cnt].status = 0;
+ urb->iso_frame_desc[td->iso_cnt].status = status;
td->iso_cnt++;
+ finish = 0;
}
/* check transfer finish */
- if (check_transfer_finish(td, urb)) {
+ if (finish || check_transfer_finish(td, urb)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
finish = 1;
@@ -1224,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf, size);
}
- if (finish && pipenum != 0) {
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, urb);
- }
+ if (finish && pipenum != 0)
+ finish_request(r8a66597, td, pipenum, urb, status);
}
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1246,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("out write fifo not ready. (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, urb, -EPIPE);
return;
}
@@ -1269,7 +1272,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
/* write fifo */
if (pipenum > 0)
- r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+ r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
if (urb->transfer_buffer) {
r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
@@ -1295,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
}
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
struct urb *urb;
@@ -1308,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
switch (td->type) {
case USB_PID_IN:
case USB_PID_OUT:
- if (urb->status != -EINPROGRESS) {
- finish = 1;
- break;
- }
if (check_transfer_finish(td, urb))
td->type = USB_PID_ACK;
break;
case USB_PID_SETUP:
- if (urb->status != -EINPROGRESS)
- finish = 1;
- else if (urb->transfer_buffer_length == urb->actual_length) {
+ if (urb->transfer_buffer_length == urb->actual_length)
td->type = USB_PID_ACK;
- urb->status = 0;
- } else if (usb_pipeout(urb->pipe))
+ else if (usb_pipeout(urb->pipe))
td->type = USB_PID_OUT;
else
td->type = USB_PID_IN;
break;
case USB_PID_ACK:
finish = 1;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
break;
}
- if (finish)
- finish_request(r8a66597, td, 0, urb);
+ if (finish || status != 0 || urb->unlinked)
+ finish_request(r8a66597, td, 0, urb, status);
else
start_transfer(r8a66597, td);
}
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
- if (td && td->urb) {
+ if (td) {
u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
if (pid == PID_NAK)
- td->urb->status = -ECONNRESET;
+ return -ECONNRESET;
else
- td->urb->status = -EPIPE;
+ return -EPIPE;
}
+ return 0;
}
static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1362,14 +1357,14 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
mask = r8a66597_read(r8a66597, BRDYSTS)
& r8a66597_read(r8a66597, BRDYENB);
- r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+ r8a66597_write(r8a66597, ~mask, BRDYSTS);
if (mask & BRDY0) {
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type == USB_PID_IN)
packet_read(r8a66597, 0);
else
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1397,13 +1392,13 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
mask = r8a66597_read(r8a66597, BEMPSTS)
& r8a66597_read(r8a66597, BEMPENB);
- r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+ r8a66597_write(r8a66597, ~mask, BEMPSTS);
if (mask & BEMP0) {
cfifo_change(r8a66597, 0);
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type != USB_PID_OUT)
disable_irq_empty(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1418,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
if ((tmp & INBUFM) == 0) {
disable_irq_empty(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb,
+ 0);
}
}
}
@@ -1431,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
u16 check;
u16 pipenum;
u16 mask;
+ int status;
mask = r8a66597_read(r8a66597, NRDYSTS)
& r8a66597_read(r8a66597, NRDYENB);
- r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+ r8a66597_write(r8a66597, ~mask, NRDYSTS);
if (mask & NRDY0) {
cfifo_change(r8a66597, 0);
- set_urb_error(r8a66597, 0);
+ status = get_urb_error(r8a66597, 0);
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, status);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1450,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
if (unlikely(!td))
continue;
- set_urb_error(r8a66597, pipenum);
+ status = get_urb_error(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
pipe_stop(r8a66597, td->pipe);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, status);
}
}
}
@@ -1473,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
u16 intsts0, intsts1, intsts2;
u16 intenb0, intenb1, intenb2;
u16 mask0, mask1, mask2;
+ int status;
spin_lock(&r8a66597->lock);
@@ -1488,14 +1484,14 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
if (mask2) {
if (mask2 & ATTCH) {
- r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+ r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
/* start usb bus sampling */
start_root_hub_sampling(r8a66597, 1);
}
if (mask2 & DTCH) {
- r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+ r8a66597_write(r8a66597, ~DTCH, INTSTS2);
r8a66597_bclr(r8a66597, DTCHE, INTENB2);
r8a66597_usb_disconnect(r8a66597, 1);
}
@@ -1503,25 +1499,25 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
if (mask1) {
if (mask1 & ATTCH) {
- r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+ r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
/* start usb bus sampling */
start_root_hub_sampling(r8a66597, 0);
}
if (mask1 & DTCH) {
- r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+ r8a66597_write(r8a66597, ~DTCH, INTSTS1);
r8a66597_bclr(r8a66597, DTCHE, INTENB1);
r8a66597_usb_disconnect(r8a66597, 0);
}
if (mask1 & SIGN) {
- r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
- set_urb_error(r8a66597, 0);
- check_next_phase(r8a66597);
+ r8a66597_write(r8a66597, ~SIGN, INTSTS1);
+ status = get_urb_error(r8a66597, 0);
+ check_next_phase(r8a66597, status);
}
if (mask1 & SACK) {
- r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
- check_next_phase(r8a66597);
+ r8a66597_write(r8a66597, ~SACK, INTSTS1);
+ check_next_phase(r8a66597, 0);
}
}
if (mask0) {
@@ -1663,13 +1659,9 @@ static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
static int r8a66597_start(struct usb_hcd *hcd)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
- int ret;
hcd->state = HC_STATE_RUNNING;
- if ((ret = enable_controller(r8a66597)) < 0)
- return ret;
-
- return 0;
+ return enable_controller(r8a66597);
}
static void r8a66597_stop(struct usb_hcd *hcd)
@@ -1696,13 +1688,12 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
struct urb *urb,
- struct usb_host_endpoint *hep,
- gfp_t mem_flags)
+ struct usb_host_endpoint *hep)
{
struct r8a66597_td *td;
u16 pipenum;
- td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+ td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
if (td == NULL)
return NULL;
@@ -1725,23 +1716,28 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
}
static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
+ struct usb_host_endpoint *hep = urb->ep;
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td = NULL;
- int ret = 0, request = 0;
+ int ret, request = 0;
unsigned long flags;
spin_lock_irqsave(&r8a66597->lock, flags);
if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
ret = -ENODEV;
- goto error;
+ goto error_not_linked;
}
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto error_not_linked;
+
if (!hep->hcpriv) {
- hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+ hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+ GFP_ATOMIC);
if (!hep->hcpriv) {
ret = -ENOMEM;
goto error;
@@ -1755,7 +1751,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
init_pipe_config(r8a66597, urb);
set_address_zero(r8a66597, urb);
- td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+ td = r8a66597_make_td(r8a66597, urb, hep);
if (td == NULL) {
ret = -ENOMEM;
goto error;
@@ -1763,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
request = 1;
list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- ret = -EPIPE;
- goto error;
- }
urb->hcpriv = td;
- spin_unlock(&urb->lock);
if (request) {
ret = start_transfer(r8a66597, td);
@@ -1783,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
set_td_timer(r8a66597, td);
error:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return ret;
}
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&r8a66597->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
if (urb->hcpriv) {
td = urb->hcpriv;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, td->pipenum);
disable_irq_empty(r8a66597, td->pipenum);
- done(r8a66597, td, td->pipenum, urb);
+ finish_request(r8a66597, td, td->pipenum, urb, status);
}
+ done:
spin_unlock_irqrestore(&r8a66597->lock, flags);
- return 0;
+ return rc;
}
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1832,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
td = r8a66597_get_td(r8a66597, pipenum);
if (td)
urb = td->urb;
- done(r8a66597, td, pipenum, urb);
+ finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
kfree(hep->hcpriv);
hep->hcpriv = NULL;
spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2029,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case GetPortStatus:
if (wIndex > R8A66597_MAX_ROOT_HUB)
goto error;
- *(u32 *)buf = rh->port;
+ *(u32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2128,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
del_timer_sync(&r8a66597->rh_timer);
- iounmap((void *)r8a66597->reg);
usb_remove_hcd(hcd);
+ iounmap((void *)r8a66597->reg);
usb_put_hcd(hcd);
return 0;
}
@@ -2210,8 +2208,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
clean_up:
if (reg)
iounmap(reg);
- if (res)
- release_mem_region(res->start, 1);
return ret;
}
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 97c2a71ac7a1..fe9ceb077d9b 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -203,14 +203,14 @@
#define DTLN 0x0FFF /* b11-0: FIFO received data length */
/* Interrupt Enable Register 0 */
-#define VBSE 0x8000 /* b15: VBUS interrupt */
-#define RSME 0x4000 /* b14: Resume interrupt */
-#define SOFE 0x2000 /* b13: Frame update interrupt */
-#define DVSE 0x1000 /* b12: Device state transition interrupt */
-#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
-#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
+#define VBSE 0x8000 /* b15: VBUS interrupt */
+#define RSME 0x4000 /* b14: Resume interrupt */
+#define SOFE 0x2000 /* b13: Frame update interrupt */
+#define DVSE 0x1000 /* b12: Device state transition interrupt */
+#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
/* Interrupt Enable Register 1 */
#define OVRCRE 0x8000 /* b15: Over-current interrupt */
@@ -268,16 +268,16 @@
#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
/* Interrupt Status Register 0 */
-#define VBINT 0x8000 /* b15: VBUS interrupt */
-#define RESM 0x4000 /* b14: Resume interrupt */
-#define SOFR 0x2000 /* b13: SOF frame update interrupt */
-#define DVST 0x1000 /* b12: Device state transition interrupt */
-#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMP 0x0400 /* b10: Buffer empty interrupt */
-#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDY 0x0100 /* b8: Buffer ready interrupt */
-#define VBSTS 0x0080 /* b7: VBUS input port */
-#define DVSQ 0x0070 /* b6-4: Device state */
+#define VBINT 0x8000 /* b15: VBUS interrupt */
+#define RESM 0x4000 /* b14: Resume interrupt */
+#define SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define DVST 0x1000 /* b12: Device state transition interrupt */
+#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define VBSTS 0x0080 /* b7: VBUS input port */
+#define DVSQ 0x0070 /* b6-4: Device state */
#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
#define DS_SPD_ADDR 0x0060 /* Suspend Address */
#define DS_SPD_DFLT 0x0050 /* Suspend Default */
@@ -315,13 +315,10 @@
/* Micro Frame Number Register */
#define UFRNM 0x0007 /* b2-0: Micro frame number */
-/* USB Address / Low Power Status Recovery Register */
-//#define USBADDR 0x007F /* b6-0: USB address */
-
/* Default Control Pipe Maxpacket Size Register */
/* Pipe Maxpacket Size Register */
-#define DEVSEL 0xF000 /* b15-14: Device address select */
-#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+#define DEVSEL 0xF000 /* b15-14: Device address select */
+#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
/* Default Control Pipe Control Register */
#define BSTS 0x8000 /* b15: Buffer status */
@@ -366,21 +363,21 @@
#define MXPS 0x07FF /* b10-0: Maxpacket size */
/* Pipe Cycle Configuration Register */
-#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
-#define IITV 0x0007 /* b2-0: Isochronous interval */
+#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
+#define IITV 0x0007 /* b2-0: Isochronous interval */
/* Pipex Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define ATREPM 0x0400 /* b10: Auto repeat mode */
-#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PID 0x0003 /* b1-0: Response PID */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define ATREPM 0x0400 /* b10: Auto repeat mode */
+#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PID 0x0003 /* b1-0: Response PID */
/* PIPExTRE */
#define TRENB 0x0200 /* b9: Transaction counter enable */
@@ -407,15 +404,15 @@
#define make_devsel(addr) (addr << 12)
struct r8a66597_pipe_info {
- u16 pipenum;
- u16 address; /* R8A66597 HCD usb addres */
- u16 epnum;
- u16 maxpacket;
- u16 type;
- u16 bufnum;
- u16 buf_bsize;
- u16 interval;
- u16 dir_in;
+ u16 pipenum;
+ u16 address; /* R8A66597 HCD usb addres */
+ u16 epnum;
+ u16 maxpacket;
+ u16 type;
+ u16 bufnum;
+ u16 buf_bsize;
+ u16 interval;
+ u16 dir_in;
};
struct r8a66597_pipe {
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4cfa3ff2c993..94d859aa73f8 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -435,14 +435,9 @@ static void finish_request(
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_SETUP;
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- urb->hcpriv = NULL;
- spin_unlock(&urb->lock);
-
+ usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
spin_unlock(&sl811->lock);
- usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+ usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
spin_lock(&sl811->lock);
/* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank + SL11H_XFERCNTREG);
if (len > ep->length) {
len = ep->length;
- urb->status = -EOVERFLOW;
+ urbstat = -EOVERFLOW;
}
urb->actual_length += len;
sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
buf, len);
usb_dotoggle(udev, ep->epnum, 0);
- if (urb->actual_length == urb->transfer_buffer_length)
- urbstat = 0;
- else if (len < ep->maxpacket) {
- if (urb->transfer_flags & URB_SHORT_NOT_OK)
- urbstat = -EREMOTEIO;
+ if (urbstat == -EINPROGRESS &&
+ (len < ep->maxpacket ||
+ urb->actual_length ==
+ urb->transfer_buffer_length)) {
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_ACK;
else
urbstat = 0;
}
- if (usb_pipecontrol(urb->pipe)
- && (urbstat == -EREMOTEIO
- || urbstat == 0)) {
-
- /* NOTE if the status stage STALLs (why?),
- * this reports the wrong urb status.
- */
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = urbstat;
- spin_unlock(&urb->lock);
-
- urb = NULL;
- ep->nextpid = USB_PID_ACK;
- }
break;
case USB_PID_SETUP:
// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank, status, ep, urbstat);
}
- if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+ if (urbstat != -EINPROGRESS || urb->unlinked)
finish_request(sl811, ep, urb, urbstat);
}
@@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
static int sl811h_urb_enqueue(
struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
struct sl811h_ep *ep = NULL;
unsigned long flags;
int i;
- int retval = 0;
+ int retval;
+ struct usb_host_endpoint *hep = urb->ep;
#ifdef DISABLE_ISO
if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
|| !HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV;
kfree(ep);
- goto fail;
+ goto fail_not_linked;
+ }
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval) {
+ kfree(ep);
+ goto fail_not_linked;
}
if (hep->hcpriv) {
@@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
sofirq_on(sl811);
}
- /* in case of unlink-during-submit */
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- finish_request(sl811, ep, urb, 0);
- retval = 0;
- goto fail;
- }
urb->hcpriv = hep;
- spin_unlock(&urb->lock);
-
start_transfer(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
fail:
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_host_endpoint *hep;
unsigned long flags;
struct sl811h_ep *ep;
- int retval = 0;
+ int retval;
spin_lock_irqsave(&sl811->lock, flags);
- hep = urb->hcpriv;
- if (!hep)
+ retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (retval)
goto fail;
+ hep = urb->hcpriv;
ep = hep->hcpriv;
if (ep) {
/* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
-fail:
retval = -EINVAL;
+ fail:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 2d0e73b20099..5da63f535005 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -278,10 +278,9 @@ static int sl811_cs_probe(struct pcmcia_device *link)
{
local_info_t *local;
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->p_dev = link;
link->priv = local;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index e98df2ee9901..ac283b09a63f 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -51,7 +51,7 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
-#include <linux/pci_ids.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
@@ -83,7 +83,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
* u132_module_lock exists to protect access to global variables
*
*/
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
static int u132_exiting = 0;
static int u132_instances = 0;
static struct list_head u132_static_list;
@@ -183,7 +183,7 @@ struct u132_ring {
struct u132 {
struct kref kref;
struct list_head u132_list;
- struct semaphore sw_lock;
+ struct mutex sw_lock;
struct semaphore scheduler_lock;
struct u132_platform_data *board;
struct platform_device *platform_dev;
@@ -258,10 +258,10 @@ static void u132_hcd_delete(struct kref *kref)
struct platform_device *pdev = u132->platform_dev;
struct usb_hcd *hcd = u132_to_hcd(u132);
u132->going += 1;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
list_del_init(&u132->u132_list);
u132_instances -= 1;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
"2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
usb_put_hcd(hcd);
@@ -492,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
return;
} else {
int retval;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
retval = read_roothub_info(u132);
if (retval) {
struct usb_hcd *hcd = u132_to_hcd(u132);
u132_disable(u132);
u132->going = 1;
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
usb_hc_died(hcd);
ftdi_elan_gone_away(u132->platform_dev);
u132_monitor_put_kref(u132);
return;
} else {
u132_monitor_requeue_work(u132, 500);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return;
}
}
@@ -518,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
- urb->status = status;
- urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@@ -542,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
u132_ring_queue_work(u132, ring, 0);
up(&u132->scheduler_lock);
u132_endp_put_kref(u132, endp);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@@ -558,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
- urb->status = status;
- urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@@ -575,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
endp->active = 0;
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(urbq);
- } usb_hcd_giveback_urb(hcd, urb);
+ } usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@@ -645,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@@ -716,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -744,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
urb->actual_length += len;
endp->toggle_bits = toggle_bits;
@@ -768,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -797,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@@ -871,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -898,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -936,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
u8 *b = buf;
@@ -980,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1007,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1045,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
if (usb_pipein(urb->pipe)) {
int retval;
struct u132_ring *ring = endp->ring;
@@ -1077,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1106,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
u132->addr[0].address = 0;
endp->usb_addr = udev->usb_addr;
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1145,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@@ -1162,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1189,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1227,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
@@ -1251,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1279,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@@ -1296,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1519,12 +1517,15 @@ static void u132_hcd_endp_work_scheduler(struct work_struct *work)
}
}
}
+#ifdef CONFIG_PM
static void port_power(struct u132 *u132, int pn, int is_on)
{
u132->port[pn].power = is_on;
}
+#endif
+
static void u132_power(struct u132 *u132, int is_on)
{
struct usb_hcd *hcd = u132_to_hcd(u132)
@@ -1801,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
"ed\n", hcd);
} else {
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
msleep(100);
u132_power(u132, 0);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
}
}
@@ -1826,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
(pdev->dev.platform_data))->vendor;
u16 device = ((struct u132_platform_data *)
(pdev->dev.platform_data))->device;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
msleep(10);
if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
u132->flags = OHCI_QUIRK_AMD756;
@@ -1841,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
u132->going = 1;
}
msleep(100);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
} else {
dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1861,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
return -ESHUTDOWN;
} else {
int retval;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
retval = u132_init(u132);
if (retval) {
u132_disable(u132);
u132->going = 1;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
}
}
static int create_endpoint_and_queue_int(struct u132 *u132,
- struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
struct u132_ring *ring;
unsigned long irqs;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@@ -1902,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@@ -1921,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
u132_udev_get_kref(u132, udev);
}
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->delayed = 1;
endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
endp->udev_number = address;
@@ -1936,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
return 0;
}
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@@ -1961,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_bulk(struct u132 *u132,
- struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
int ring_number;
struct u132_ring *ring;
unsigned long irqs;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
endp->dequeueing = 0;
endp->edset_flush = 0;
@@ -1983,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@@ -2012,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
ring->length += 1;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->udev_number = address;
endp->usb_addr = usb_addr;
endp->usb_endp = usb_endp;
@@ -2026,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@@ -2048,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_control(struct u132 *u132,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
gfp_t mem_flags)
{
struct u132_ring *ring;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ unsigned long irqs;
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@@ -2076,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
u132_endp_init_kref(u132, endp);
u132_endp_get_kref(u132, endp);
if (usb_addr == 0) {
- unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@@ -2094,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@@ -2103,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
u132_endp_queue_work(u132, endp, 0);
return 0;
} else { /*(usb_addr > 0) */
- unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@@ -2117,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@@ -2129,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
}
static int queue_control_on_old_endpoint(struct u132 *u132,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp)
{
@@ -2229,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
}
}
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
- struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (irqs_disabled()) {
@@ -2245,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
, u132->going);
return -ENODEV;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
return -ESHUTDOWN;
} else {
u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2255,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_int_on_old_endpoint(u132, udev,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp, address);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_int_on_old_endpoint(
+ u132, udev, urb,
+ usb_dev, endp,
+ usb_addr, usb_endp,
+ address);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2279,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else { /*(endp == NULL) */
return create_endpoint_and_queue_int(u132, udev,
- hep, urb, usb_dev, usb_addr, usb_endp,
- address, mem_flags);
+ urb, usb_dev, usb_addr,
+ usb_endp, address, mem_flags);
}
} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2289,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_bulk_on_old_endpoint(u132, udev,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp, address);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_bulk_on_old_endpoint(
+ u132, udev, urb,
+ usb_dev, endp,
+ usb_addr, usb_endp,
+ address);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2311,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_bulk(u132,
- udev, hep, urb, usb_dev, usb_addr,
+ udev, urb, usb_dev, usb_addr,
usb_endp, address, mem_flags);
} else {
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
u16 urb_size = 8;
u8 *b = urb->setup_packet;
int i = 0;
@@ -2337,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_control_on_old_endpoint(u132,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_control_on_old_endpoint(
+ u132, urb, usb_dev,
+ endp, usb_addr,
+ usb_endp);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2352,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_control(u132,
- hep, urb, usb_dev, usb_addr, usb_endp,
+ urb, usb_dev, usb_addr, usb_endp,
mem_flags);
}
}
@@ -2371,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
list_del(scan);
endp->queue_size -= 1;
urb->error_count = 0;
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, 0);
return 0;
} else
continue;
@@ -2387,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
}
static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb)
+ struct urb *urb, int status)
{
unsigned long irqs;
+ int rc;
+
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return rc;
+ }
if (endp->queue_size == 0) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
"=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2406,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
endp->edset_flush = 1;
u132_endp_queue_work(u132, endp, 0);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- urb->hcpriv = NULL;
return 0;
} else {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+ u132_hcd_abandon_urb(u132, endp, urb, status);
return 0;
}
} else {
@@ -2435,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
if (urb_slot) {
struct usb_hcd *hcd = u132_to_hcd(u132);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_size -= 1;
if (list_empty(&endp->urb_more)) {
spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2449,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
irqs);
kfree(urbq);
} urb->error_count = 0;
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
return 0;
} else if (list_empty(&endp->urb_more)) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2464,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return -EINVAL;
} else {
- int retval = dequeue_from_overflow_chain(u132, endp,
+ int retval;
+
+ usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+ retval = dequeue_from_overflow_chain(u132, endp,
urb);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return retval;
@@ -2472,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
}
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (u132->going > 2) {
@@ -2487,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
if (usb_pipein(urb->pipe)) {
u8 endp_number = udev->endp_number_in[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb);
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
} else {
u8 endp_number = udev->endp_number_out[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb);
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
}
}
}
@@ -2801,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return -ESHUTDOWN;
} else {
int retval = 0;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
switch (typeReq) {
case ClearHubFeature:
switch (wValue) {
@@ -2864,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
stall:retval = -EPIPE;
break;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
}
}
@@ -3000,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
dev_err(&u132->platform_dev->dev, "removing device u132"
".%d\n", u132->sequence_num);
msleep(100);
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
u132_monitor_cancel_work(u132);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@@ -3013,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
u132->going += 1;
printk(KERN_INFO "removing device u132.%d\n",
u132->sequence_num);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
usb_remove_hcd(hcd);
u132_u132_put_kref(u132);
return 0;
@@ -3033,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
u132->platform_dev = pdev;
u132->power = 0;
u132->reset = 0;
- init_MUTEX(&u132->sw_lock);
+ mutex_init(&u132->sw_lock);
init_MUTEX(&u132->scheduler_lock);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@@ -3043,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
ring->curr_endp = NULL;
INIT_DELAYED_WORK(&ring->scheduler,
u132_hcd_ring_work_scheduler);
- } down(&u132->sw_lock);
+ } mutex_lock(&u132->sw_lock);
INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
while (ports-- > 0) {
struct u132_port *port = &u132->port[ports];
@@ -3073,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
while (endps-- > 0) {
u132->endp[endps] = NULL;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return;
}
@@ -3111,10 +3175,10 @@ static int __devinit u132_probe(struct platform_device *pdev)
int retval = 0;
struct u132 *u132 = hcd_to_u132(hcd);
hcd->rsrc_start = 0;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
list_add_tail(&u132->u132_list, &u132_static_list);
u132->sequence_num = ++u132_instances;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
u132_u132_init_kref(u132);
u132_initialise(u132, pdev);
hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3280,7 @@ static int __init u132_hcd_init(void)
INIT_LIST_HEAD(&u132_static_list);
u132_instances = 0;
u132_exiting = 0;
- init_MUTEX(&u132_module_lock);
+ mutex_init(&u132_module_lock);
if (usb_disabled())
return -ENODEV;
printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3296,9 @@ static void __exit u132_hcd_exit(void)
{
struct u132 *u132;
struct u132 *temp;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
u132_exiting += 1;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
platform_device_unregister(u132->platform_dev);
} platform_driver_unregister(&u132_platform_driver);
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1497371583b9..20cc58b97807 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
- if (urbp->urb->status != -EINPROGRESS)
- out += sprintf(out, " Status=%d", urbp->urb->status);
+ if (urbp->urb->unlinked)
+ out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
out += sprintf(out, "\n");
i = nactive = ninactive = 0;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 76c555a67dac..4db17f75f4f1 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -237,7 +237,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
{
int port;
- char *sys_info;
+ const char *sys_info;
static char bad_Asus_board[] = "A7V8X";
/* One of Asus's motherboards has a bug which causes it to
@@ -933,7 +933,7 @@ static int __init uhci_hcd_init(void)
}
uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
- sizeof(struct urb_priv), 0, 0, NULL, NULL);
+ sizeof(struct urb_priv), 0, 0, NULL);
if (!uhci_up_cachep)
goto up_failed;
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 1b3d23406ac4..340d6ed3e6e9 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -146,7 +146,6 @@ struct uhci_qh {
short phase; /* Between 0 and period-1 */
short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
- int iso_status; /* Status for Isochronous URBs */
int state; /* QH_STATE_xxx; see above */
int type; /* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@ struct urb_priv {
};
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock. urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
/* Some special IDs */
#define PCI_VENDOR_ID_GENESYS 0x17a0
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 4aed305982ec..e5d60d5b105a 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
uhci_free_td(uhci, td);
}
- urbp->urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
}
@@ -827,8 +826,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* If direction is "send", change the packet ID from SETUP (0x2D)
* to OUT (0xE1). Else change it from SETUP to IN (0x69) and
* set Short Packet Detect (SPD) for all data packets.
+ *
+ * 0-length transfers always get treated as "send".
*/
- if (usb_pipeout(urb->pipe))
+ if (usb_pipeout(urb->pipe) || len == 0)
destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
else {
destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +840,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* Build the DATA TDs
*/
while (len > 0) {
- int pktsze = min(len, maxsze);
+ int pktsze = maxsze;
+
+ if (len <= pktsze) { /* The last data packet */
+ pktsze = len;
+ status &= ~TD_CTRL_SPD;
+ }
td = uhci_alloc_td(uhci);
if (!td)
@@ -866,20 +872,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
goto nomem;
*plink = LINK_TO_TD(td);
- /*
- * It's IN if the pipe is an output pipe or we're not expecting
- * data back.
- */
- destination &= ~TD_TOKEN_PID_MASK;
- if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
- destination |= USB_PID_IN;
- else
- destination |= USB_PID_OUT;
-
+ /* Change direction for the status transaction */
+ destination ^= (USB_PID_IN ^ USB_PID_OUT);
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
- status &= ~TD_CTRL_SPD;
-
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(0), 0);
@@ -1185,10 +1181,18 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
}
}
+ /* Did we receive a short packet? */
} else if (len < uhci_expected_length(td_token(td))) {
- /* We received a short packet */
- if (urb->transfer_flags & URB_SHORT_NOT_OK)
+ /* For control transfers, go to the status TD if
+ * this isn't already the last data TD */
+ if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (td->list.next != urbp->td_list.prev)
+ ret = 1;
+ }
+
+ /* For bulk and interrupt, this may be an error */
+ else if (urb->transfer_flags & URB_SHORT_NOT_OK)
ret = -EREMOTEIO;
/* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1212,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
err:
if (ret < 0) {
- /* In case a control transfer gets an error
- * during the setup stage */
- urb->actual_length = max(urb->actual_length, 0);
-
/* Note that the queue has stopped and save
* the next toggle value */
qh->element = UHCI_PTR_TERM;
@@ -1323,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
if (list_empty(&qh->queue)) {
qh->iso_packet_desc = &urb->iso_frame_desc[0];
qh->iso_frame = urb->start_frame;
- qh->iso_status = 0;
}
qh->skel = SKEL_ISO;
@@ -1360,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
qh->iso_packet_desc->actual_length = actlength;
qh->iso_packet_desc->status = status;
}
-
- if (status) {
+ if (status)
urb->error_count++;
- qh->iso_status = status;
- }
uhci_remove_td_from_urbp(td);
uhci_free_td(uhci, td);
qh->iso_frame += qh->period;
++qh->iso_packet_desc;
}
- return qh->iso_status;
+ return 0;
}
static int uhci_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb, gfp_t mem_flags)
{
int ret;
@@ -1386,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
spin_lock_irqsave(&uhci->lock, flags);
- ret = urb->status;
- if (ret != -EINPROGRESS) /* URB already unlinked! */
- goto done;
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto done_not_linked;
ret = -ENOMEM;
urbp = uhci_alloc_urb_priv(uhci, urb);
if (!urbp)
goto done;
- if (hep->hcpriv)
- qh = (struct uhci_qh *) hep->hcpriv;
+ if (urb->ep->hcpriv)
+ qh = urb->ep->hcpriv;
else {
- qh = uhci_alloc_qh(uhci, urb->dev, hep);
+ qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
if (!qh)
goto err_no_qh;
}
@@ -1439,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
err_submit_failed:
if (qh->state == QH_STATE_IDLE)
uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
-
err_no_qh:
uhci_free_urb_priv(uhci, urbp);
-
done:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
spin_unlock_irqrestore(&uhci->lock, flags);
return ret;
}
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
- struct urb_priv *urbp;
struct uhci_qh *qh;
+ int rc;
spin_lock_irqsave(&uhci->lock, flags);
- urbp = urb->hcpriv;
- if (!urbp) /* URB was never linked! */
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
goto done;
- qh = urbp->qh;
+
+ qh = ((struct urb_priv *) urb->hcpriv)->qh;
/* Remove Isochronous TDs from the frame list ASAP */
if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1476,22 +1473,31 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
done:
spin_unlock_irqrestore(&uhci->lock, flags);
- return 0;
+ return rc;
}
/*
* Finish unlinking an URB and give it back
*/
static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
- struct urb *urb)
+ struct urb *urb, int status)
__releases(uhci->lock)
__acquires(uhci->lock)
{
struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+ if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+ /* urb->actual_length < 0 means the setup transaction didn't
+ * complete successfully. Either it failed or the URB was
+ * unlinked first. Regardless, don't confuse people with a
+ * negative length. */
+ urb->actual_length = max(urb->actual_length, 0);
+ }
+
/* When giving back the first URB in an Isochronous queue,
* reinitialize the QH's iso-related members for the next URB. */
- if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+ else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
urbp->node.prev == &qh->queue &&
urbp->node.next != &qh->queue) {
struct urb *nurb = list_entry(urbp->node.next,
@@ -1499,7 +1505,6 @@ __acquires(uhci->lock)
qh->iso_packet_desc = &nurb->iso_frame_desc[0];
qh->iso_frame = nurb->start_frame;
- qh->iso_status = 0;
}
/* Take the URB off the QH's queue. If the queue is now empty,
@@ -1512,9 +1517,10 @@ __acquires(uhci->lock)
}
uhci_free_urb_priv(uhci, urbp);
+ usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
spin_unlock(&uhci->lock);
- usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+ usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
spin_lock(&uhci->lock);
/* If the queue is now empty, we can unlink the QH and give up its
@@ -1550,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (status == -EINPROGRESS)
break;
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS) /* Not dequeued */
- urb->status = status;
- else
- status = ECONNRESET; /* Not -ECONNRESET */
- spin_unlock(&urb->lock);
-
/* Dequeued but completed URBs can't be given back unless
* the QH is stopped or has finished unlinking. */
- if (status == ECONNRESET) {
+ if (urb->unlinked) {
if (QH_FINISHED_UNLINKING(qh))
qh->is_stopped = 1;
else if (!qh->is_stopped)
return;
}
- uhci_giveback_urb(uhci, qh, urb);
- if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+ uhci_giveback_urb(uhci, qh, urb, status);
+ if (status < 0)
break;
}
@@ -1582,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
restart:
list_for_each_entry(urbp, &qh->queue, node) {
urb = urbp->urb;
- if (urb->status != -EINPROGRESS) {
+ if (urb->unlinked) {
/* Fix up the TD links and save the toggles for
* non-Isochronous queues. For Isochronous queues,
@@ -1591,7 +1590,7 @@ restart:
qh->is_stopped = 0;
return;
}
- uhci_giveback_urb(uhci, qh, urb);
+ uhci_giveback_urb(uhci, qh, urb, 0);
goto restart;
}
}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 36502a06f73a..d1131a87a5b1 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,9 +284,9 @@ static void mdc800_usb_irq (struct urb *urb)
int data_received=0, wake_up;
unsigned char* b=urb->transfer_buffer;
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status >= 0)
- {
+ if (status >= 0) {
//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
@@ -324,7 +324,7 @@ static void mdc800_usb_irq (struct urb *urb)
||
((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
||
- (urb->status < 0)
+ (status < 0)
);
if (wake_up)
@@ -376,15 +376,12 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
static void mdc800_usb_write_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status != 0)
- {
- err ("writing command fails (status=%i)", urb->status);
- }
+ if (status != 0)
+ err ("writing command fails (status=%i)", status);
else
- {
mdc800->state=READY;
- }
mdc800->written = 1;
wake_up (&mdc800->write_wait);
}
@@ -396,9 +393,9 @@ static void mdc800_usb_write_notify (struct urb *urb)
static void mdc800_usb_download_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status == 0)
- {
+ if (status == 0) {
/* Fill output buffer with these data */
memcpy (mdc800->out, urb->transfer_buffer, 64);
mdc800->out_count=64;
@@ -408,10 +405,8 @@ static void mdc800_usb_download_notify (struct urb *urb)
{
mdc800->state=READY;
}
- }
- else
- {
- err ("request bytes fails (status:%i)", urb->status);
+ } else {
+ err ("request bytes fails (status:%i)", status);
}
mdc800->downloaded = 1;
wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
retval=0;
mdc800->irq_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
- {
- err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+ if (retval) {
+ err ("request USB irq fails (submit_retval=%i).", retval);
errn = -EIO;
goto error_out;
}
@@ -698,6 +693,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
{
size_t left=len, sts=len; /* single transfer size */
char __user *ptr = buf;
+ int retval;
mutex_lock(&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
/* Download -> Request new bytes */
mdc800->download_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
- {
- err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+ retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+ if (retval) {
+ err ("Can't submit download urb (retval=%i)",retval);
mutex_unlock(&mdc800->io_lock);
return len-left;
}
@@ -788,6 +784,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
{
size_t i=0;
+ int retval;
mutex_lock(&mdc800->io_lock);
if (mdc800->state != READY)
@@ -854,9 +851,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
mdc800->state=WORKING;
memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
mdc800->write_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
- {
- err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+ retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+ if (retval) {
+ err ("submitting write urb fails (retval=%i)", retval);
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 51bd80d2b8cc..768b2c11a231 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -189,7 +189,7 @@ static struct usb_driver mts_usb_driver = {
#define MTS_DEBUG_INT() \
do { MTS_DEBUG_GOT_HERE(); \
MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
- MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+ MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
mts_debug_dump(context->instance);\
} while(0)
#else
@@ -393,8 +393,6 @@ void mts_int_submit_urb (struct urb* transfer,
context
);
- transfer->status = 0;
-
res = usb_submit_urb( transfer, GFP_ATOMIC );
if ( unlikely(res) ) {
MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@ static void mts_get_status( struct urb *transfer )
static void mts_data_done( struct urb* transfer )
/* Interrupt context! */
{
+ int status = transfer->status;
MTS_INT_INIT();
if ( context->data_length != transfer->actual_length ) {
context->srb->resid = context->data_length - transfer->actual_length;
- } else if ( unlikely(transfer->status) ) {
- context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+ } else if ( unlikely(status) ) {
+ context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
}
mts_get_status(transfer);
@@ -461,10 +460,11 @@ static void mts_data_done( struct urb* transfer )
static void mts_command_done( struct urb *transfer )
/* Interrupt context! */
{
+ int status = transfer->status;
MTS_INT_INIT();
- if ( unlikely(transfer->status) ) {
- if (transfer->status == -ENOENT) {
+ if ( unlikely(status) ) {
+ if (status == -ENOENT) {
/* We are being killed */
MTS_DEBUG_GOT_HERE();
context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@ static void mts_command_done( struct urb *transfer )
static void mts_do_sg (struct urb* transfer)
{
struct scatterlist * sg;
+ int status = transfer->status;
MTS_INT_INIT();
MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
- if (unlikely(transfer->status)) {
- context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+ if (unlikely(status)) {
+ context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
mts_transfer_cleanup(transfer);
}
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index d72c42e5f22d..5131cbfb2f52 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* Structure to hold all of our device specific stuff */
struct adu_device {
- struct semaphore sem; /* locks this structure */
+ struct mutex mtx; /* locks this structure */
struct usb_device* udev; /* save off the usb device pointer */
struct usb_interface* interface;
unsigned char minor; /* the starting minor number for this device */
@@ -178,17 +179,19 @@ static void adu_delete(struct adu_device *dev)
static void adu_interrupt_in_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
+ int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : enter, status %d", __FUNCTION__, status);
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
spin_lock(&dev->buflock);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+ if (status != 0) {
+ if ((status != -ENOENT) && (status != -ECONNRESET) &&
+ (status != -ESHUTDOWN)) {
dbg(1," %s : nonzero status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
goto exit;
}
@@ -216,21 +219,22 @@ exit:
wake_up_interruptible(&dev->read_wait);
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : leave, status %d", __FUNCTION__, status);
}
static void adu_interrupt_out_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
+ int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : enter, status %d", __FUNCTION__, status);
adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
+ if (status != 0) {
+ if ((status != -ENOENT) &&
+ (status != -ECONNRESET)) {
dbg(1, " %s :nonzero status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
goto exit;
}
@@ -240,7 +244,7 @@ exit:
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : leave, status %d", __FUNCTION__, status);
}
static int adu_open(struct inode *inode, struct file *file)
@@ -269,8 +273,8 @@ static int adu_open(struct inode *inode, struct file *file)
}
/* lock this device */
- if ((retval = down_interruptible(&dev->sem))) {
- dbg(2, "%s : sem down failed", __FUNCTION__);
+ if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+ dbg(2, "%s : mutex lock failed", __FUNCTION__);
goto exit_no_device;
}
@@ -299,7 +303,7 @@ static int adu_open(struct inode *inode, struct file *file)
if (retval)
--dev->open_count;
}
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
exit_no_device:
dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
@@ -347,7 +351,7 @@ static int adu_release(struct inode *inode, struct file *file)
}
/* lock our device */
- down(&dev->sem); /* not interruptible */
+ mutex_lock(&dev->mtx); /* not interruptible */
if (dev->open_count <= 0) {
dbg(1," %s : device not opened", __FUNCTION__);
@@ -357,7 +361,7 @@ static int adu_release(struct inode *inode, struct file *file)
if (dev->udev == NULL) {
/* the device was unplugged before the file was released */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
adu_delete(dev);
dev = NULL;
} else {
@@ -367,7 +371,7 @@ static int adu_release(struct inode *inode, struct file *file)
exit:
if (dev)
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -390,7 +394,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
dev = file->private_data;
dbg(2," %s : dev=%p", __FUNCTION__, dev);
/* lock this object */
- if (down_interruptible(&dev->sem))
+ if (mutex_lock_interruptible(&dev->mtx))
return -ERESTARTSYS;
/* verify that the device wasn't unplugged */
@@ -522,7 +526,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
@@ -543,7 +547,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
dev = file->private_data;
/* lock this object */
- retval = down_interruptible(&dev->sem);
+ retval = mutex_lock_interruptible(&dev->mtx);
if (retval)
goto exit_nolock;
@@ -571,9 +575,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
retval = -EINTR;
goto exit;
}
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
- retval = down_interruptible(&dev->sem);
+ retval = mutex_lock_interruptible(&dev->mtx);
if (retval) {
retval = bytes_written ? bytes_written : retval;
goto exit_nolock;
@@ -638,7 +642,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
exit_nolock:
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -698,7 +702,7 @@ static int adu_probe(struct usb_interface *interface,
goto exit;
}
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mtx);
spin_lock_init(&dev->buflock);
dev->udev = udev;
init_waitqueue_head(&dev->read_wait);
@@ -835,16 +839,16 @@ static void adu_disconnect(struct usb_interface *interface)
usb_deregister_dev(interface, &adu_class);
dev->minor = 0;
- down(&dev->sem); /* not interruptible */
+ mutex_lock(&dev->mtx); /* not interruptible */
/* if the device is not opened, then we clean up right now */
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
if (!dev->open_count) {
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
adu_delete(dev);
} else {
dev->udev = NULL;
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
}
dev_info(&interface->dev, "ADU device adutux%d now disconnected",
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index cf70c16f0e3f..1cb56f2d5c84 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,9 +88,10 @@ static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
unsigned long flags;
+ int status = urb->status;
int retval;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -102,12 +103,12 @@ static void appledisplay_complete(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
+ dbg("%s - urb shuttingdown with status: %d",
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
@@ -137,7 +138,7 @@ exit:
static int appledisplay_bl_update_status(struct backlight_device *bd)
{
- struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+ struct appledisplay *pdata = bl_get_data(bd);
int retval;
pdata->msgdata[0] = 0x10;
@@ -158,7 +159,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
static int appledisplay_bl_get_brightness(struct backlight_device *bd)
{
- struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+ struct appledisplay *pdata = bl_get_data(bd);
int retval;
retval = usb_control_msg(
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 42d4e6454a77..df7e1ecc810a 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -862,14 +862,16 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb)
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp;
int ret;
+ int status = urb->status;
+
dbg ("auerswald_ctrlread_wretcomplete called");
- dbg ("complete with status: %d", urb->status);
+ dbg ("complete with status: %d", status);
cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
/* check if it is possible to advance */
- if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+ if (!auerswald_status_retry(status) || !cp->usbdev) {
/* reuse the buffer */
- err ("control dummy: transmission error %d, can not retry", urb->status);
+ err ("control dummy: transmission error %d, can not retry", status);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@ static void auerswald_ctrlread_complete (struct urb * urb)
pauerswald_t cp;
pauerscon_t scp;
pauerbuf_t bp = (pauerbuf_t) urb->context;
+ int status = urb->status;
int ret;
+
dbg ("auerswald_ctrlread_complete called");
cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
/* check if there is valid data in this urb */
- if (urb->status) {
- dbg ("complete with non-zero status: %d", urb->status);
+ if (status) {
+ dbg ("complete with non-zero status: %d", status);
/* should we do a retry? */
- if (!auerswald_status_retry (urb->status)
+ if (!auerswald_status_retry(status)
|| !cp->usbdev
|| (cp->version < AUV_RETRY)
|| (bp->retries >= AU_RETRIES)) {
/* reuse the buffer */
- err ("control read: transmission error %d, can not retry", urb->status);
+ err ("control read: transmission error %d, can not retry", status);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@ static void auerswald_int_complete (struct urb * urb)
unsigned int channelid;
unsigned int bytecount;
int ret;
+ int status = urb->status;
pauerbuf_t bp = NULL;
pauerswald_t cp = (pauerswald_t) urb->context;
dbg ("%s called", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -987,10 +992,10 @@ static void auerswald_int_complete (struct urb * urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
goto exit;
}
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index 92c1d2768df9..24e2dc3148a4 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 2) {
dev_err(&udev->dev, "First magic command failed: %d.\n",
retval);
- return retval;
+ goto exit;
}
dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 0) {
dev_err(&udev->dev, "Second magic command failed: %d.\n",
retval);
- return retval;
+ goto exit;
}
dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+exit:
+ kfree(dummy_buffer);
return retval;
}
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+ kfree(dummy_buffer);
return retval;
}
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index e0f122e131d7..d3d8cd6ff103 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -44,6 +44,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/workqueue.h>
@@ -64,7 +65,7 @@ static struct workqueue_struct *respond_queue;
* ftdi_module_lock exists to protect access to global variables
*
*/
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
static int ftdi_instances = 0;
static struct list_head ftdi_static_list;
/*
@@ -199,10 +200,10 @@ static void ftdi_elan_delete(struct kref *kref)
dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
usb_put_dev(ftdi->udev);
ftdi->disconnected += 1;
- down(&ftdi_module_lock);
+ mutex_lock(&ftdi_module_lock);
list_del_init(&ftdi->ftdi_list);
ftdi_instances -= 1;
- up(&ftdi_module_lock);
+ mutex_unlock(&ftdi_module_lock);
kfree(ftdi->bulk_in_buffer);
ftdi->bulk_in_buffer = NULL;
}
@@ -746,10 +747,12 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
static void ftdi_elan_write_bulk_callback(struct urb *urb)
{
struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
- if (urb->status && !(urb->status == -ENOENT || urb->status ==
- -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ int status = urb->status;
+
+ if (status && !(status == -ENOENT || status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
- "d\n", urb, urb->status);
+ "d\n", urb, status);
}
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
@@ -2774,16 +2777,18 @@ static int ftdi_elan_probe(struct usb_interface *interface,
size_t buffer_size;
int i;
int retval = -ENOMEM;
- struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
- if (ftdi == NULL) {
+ struct usb_ftdi *ftdi;
+
+ ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+ if (!ftdi) {
printk(KERN_ERR "Out of memory\n");
return -ENOMEM;
}
- memset(ftdi, 0x00, sizeof(struct usb_ftdi));
- down(&ftdi_module_lock);
+
+ mutex_lock(&ftdi_module_lock);
list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
ftdi->sequence_num = ++ftdi_instances;
- up(&ftdi_module_lock);
+ mutex_unlock(&ftdi_module_lock);
ftdi_elan_init_kref(ftdi);
init_MUTEX(&ftdi->sw_lock);
ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2914,7 @@ static int __init ftdi_elan_init(void)
int result;
printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
__TIME__, __DATE__);
- init_MUTEX(&ftdi_module_lock);
+ mutex_init(&ftdi_module_lock);
INIT_LIST_HEAD(&ftdi_static_list);
status_queue = create_singlethread_workqueue("ftdi-status-control");
if (!status_queue)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 28548d186712..46d9f27ec173 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -158,9 +158,10 @@ static void iowarrior_callback(struct urb *urb)
int read_idx;
int aux_idx;
int offset;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -213,10 +214,10 @@ static void iowarrior_callback(struct urb *urb)
wake_up_interruptible(&dev->read_wait);
exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
@@ -226,13 +227,15 @@ exit:
static void iowarrior_write_callback(struct urb *urb)
{
struct iowarrior *dev;
+ int status = urb->status;
+
dev = (struct iowarrior *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ if (status &&
+ !(status == -ENOENT ||
+ status == -ECONNRESET || status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ __func__, status);
}
/* free up our allocated buffer */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5e950b90c541..8208496dfc63 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -219,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
struct ld_usb *dev = urb->context;
size_t *actual_buffer;
unsigned int next_ring_head;
+ int status = urb->status;
int retval;
- if (urb->status) {
- if (urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (status) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN) {
goto exit;
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
spin_lock(&dev->rbsl);
goto resubmit; /* maybe we can recover */
}
@@ -275,14 +276,15 @@ exit:
static void ld_usb_interrupt_out_callback(struct urb *urb)
{
struct ld_usb *dev = urb->context;
+ int status = urb->status;
/* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN))
+ if (status && !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN))
dbg_info(&dev->intf->dev,
"%s - nonzero write interrupt status received: %d\n",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 2ed0daea894c..561970b889a5 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -742,19 +742,20 @@ exit:
static void tower_interrupt_in_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int status = urb->status;
int retval;
- dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, status);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status) {
- if (urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (status) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN) {
goto exit;
} else {
- dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+ dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
goto resubmit; /* maybe we can recover */
}
}
@@ -788,7 +789,7 @@ exit:
wake_up_interruptible (&dev->read_wait);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, status);
}
@@ -798,23 +799,24 @@ exit:
static void tower_interrupt_out_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int status = urb->status;
- dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, status);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
/* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
+ if (status && !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dbg(1, "%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, status);
}
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 371bf2b1197d..aa9bcceabe74 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -305,9 +305,10 @@ static void interfacekit_irq(struct urb *urb)
struct interfacekit *kit = urb->context;
unsigned char *buffer = kit->data;
int i, level, sensor;
- int status;
+ int retval;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -377,11 +378,11 @@ static void interfacekit_irq(struct urb *urb)
schedule_delayed_work(&kit->do_notify, 0);
resubmit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
kit->udev->bus->bus_name,
- kit->udev->devpath, status);
+ kit->udev->devpath, retval);
}
static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index 5727e1ea2f91..df0ebcdb9d6a 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -95,9 +95,10 @@ static void motorcontrol_irq(struct urb *urb)
struct motorcontrol *mc = urb->context;
unsigned char *buffer = mc->data;
int i, level;
- int status;
+ int retval;
+ int status = urb->status;;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -151,12 +152,12 @@ static void motorcontrol_irq(struct urb *urb)
schedule_delayed_work(&mc->do_notify, 0);
resubmit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&mc->intf->dev,
- "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+ "can't resubmit intr, %s-%s/motorcontrol0, retval %d",
mc->udev->bus->bus_name,
- mc->udev->devpath, status);
+ mc->udev->devpath, retval);
}
static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 9f37ba44c132..9244d067cec1 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
packet.address = 0x00000194;
packet.data = addr;
ret = sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
+ &packet, 0);
packet.header = 0x001f;
packet.address = 0x00000190;
packet.data = (length & ~3);
ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
+ &packet, 0);
if (sisusb->flagb0 != 0x16) {
packet.header = 0x001f;
packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
if (ret) {
msgcount++;
if (msgcount < 500)
- printk(KERN_ERR
- "sisusbvga[%d]: Wrote %zd of "
- "%d bytes, error %d\n",
- sisusb->minor, *bytes_written,
- length, ret);
+ dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+ *bytes_written, length, ret);
else if (msgcount == 500)
- printk(KERN_ERR
- "sisusbvga[%d]: Too many errors"
- ", logging stopped\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
}
addr += (*bytes_written);
length -= (*bytes_written);
}
if (ret)
- break;
+ break;
}
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
addr += 4;
length -= 4;
}
-#if 0 /* That does not work, as EP 2 is an OUT EP! */
- default:
- CLEARPACKET(&packet);
- packet.header = 0x001f;
- packet.address = 0x000001a0;
- packet.data = 0x00000006;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001b0;
- packet.data = (length & ~3) | 0x40000000;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001b4;
- packet.data = addr;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001a4;
- packet.data = 0x00000001;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- if (userbuffer) {
- ret |= sisusb_recv_bulk_msg(sisusb,
- SISUSB_EP_GFX_BULK_IN,
- (length & ~3),
- NULL, userbuffer,
- bytes_read, 0);
- if (!ret) userbuffer += (*bytes_read);
- } else {
- ret |= sisusb_recv_bulk_msg(sisusb,
- SISUSB_EP_GFX_BULK_IN,
- (length & ~3),
- kernbuffer, NULL,
- bytes_read, 0);
- if (!ret) kernbuffer += (*bytes_read);
- }
- addr += (*bytes_read);
- length -= (*bytes_read);
-#endif
}
if (ret)
- break;
+ break;
}
return ret;
@@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
}
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
- return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
- return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif /* 0 */
-
int
sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
for(i = 1; i <= 7; i++) {
- printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+ dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
for(j = 0; j < i; j++) {
- printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+ dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
}
}
}
@@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
static int
sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
SETIREG(SISSR, 0x26, 0x00);
}
- SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
+ SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
return ret;
}
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
if (ramtype <= 1) {
ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
if (iret) {
- printk(KERN_ERR "sisusbvga[%d]: RAM size "
- "detection failed, "
- "assuming 8MB video RAM\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* TODO */
}
} else {
- printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
- "assuming 8MB video RAM\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* *** TODO *** */
}
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
break;
}
- printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
- sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+ dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
ramtypetext2[ramtype], bw);
}
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
- if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
- printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
- subminor);
+ if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
return -ENODEV;
- }
if (!(sisusb = usb_get_intfdata(interface)))
return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to initialize "
- "device\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
return -EIO;
}
} else {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Device not attached to "
- "USB 2.0 hub\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
return -EIO;
}
}
@@ -2586,7 +2508,6 @@ static int
sisusb_release(struct inode *inode, struct file *file)
{
struct sisusb_usb_data *sisusb;
- int myminor;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
sisusb_kill_all_busy(sisusb);
}
- myminor = sisusb->minor;
-
sisusb->isopen = 0;
file->private_data = NULL;
@@ -2942,7 +2861,7 @@ static int
sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
unsigned long arg)
{
- int retval, port, length;
+ int retval, port, length;
u32 address;
/* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
static int
sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
struct sisusb_usb_data *sisusb;
struct sisusb_info x;
struct sisusb_command y;
- int retval = 0;
+ int retval = 0;
u32 __user *argp = (u32 __user *)arg;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case SISUSB_GET_CONFIG:
- x.sisusb_id = SISUSB_ID;
+ x.sisusb_id = SISUSB_ID;
x.sisusb_version = SISUSB_VERSION;
x.sisusb_revision = SISUSB_REVISION;
x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
.release = sisusb_release,
.read = sisusb_read,
.write = sisusb_write,
- .llseek = sisusb_lseek,
+ .llseek = sisusb_lseek,
#ifdef SISUSB_NEW_CONFIG_COMPAT
.compat_ioctl = sisusb_compat_ioctl,
#endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct sisusb_usb_data *sisusb;
int retval = 0, i;
- const char *memfail =
- KERN_ERR
- "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
- printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+ dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
dev->devnum);
/* Allocate memory for our private */
if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusb: Failed to allocate memory for private data\n");
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
return -ENOMEM;
}
kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Register device */
if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
- printk(KERN_ERR
- "sisusb: Failed to get a minor for device %d\n",
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
dev->devnum);
retval = -ENODEV;
goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->ibufsize = SISUSB_IBUF_SIZE;
if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
GFP_KERNEL, &sisusb->transfer_dma_in))) {
- printk(memfail, "input", sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
retval = -ENOMEM;
goto error_2;
}
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
GFP_KERNEL,
&sisusb->transfer_dma_out[i]))) {
if (i == 0) {
- printk(memfail, "output", sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
retval = -ENOMEM;
goto error_3;
}
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate URBs */
if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate URBs\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_3;
}
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
for (i = 0; i < sisusb->numobufs; i++) {
if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate URBs\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_4;
}
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->urbstatus[i] = 0;
}
- printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
- sisusb->minor, sisusb->numobufs);
+ dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
#ifdef INCL_SISUSB_CON
/* Allocate our SiS_Pr */
if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
}
#endif
@@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
if (ret)
- printk(KERN_ERR
- "sisusbvga[%d]: Error registering ioctl32 "
- "translations\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
else
sisusb->ioctl32registered = 1;
}
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
initscreen = 0;
#endif
if (sisusb_init_gfxdevice(sisusb, initscreen))
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to early "
- "initialize device\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
} else
- printk(KERN_INFO
- "sisusbvga[%d]: Not attached to USB 2.0 hub, "
- "deferring init\n",
- sisusb->minor);
+ dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
sisusb->ready = 1;
#ifdef SISUSBENDIANTEST
- printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
sisusb_testreadwrite(sisusb);
- printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
#endif
#ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
static void sisusb_disconnect(struct usb_interface *intf)
{
struct sisusb_usb_data *sisusb;
- int minor;
/* This should *not* happen */
if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
sisusb_console_exit(sisusb);
#endif
- minor = sisusb->minor;
-
usb_deregister_dev(intf, &usb_sisusb_class);
mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
if (ret) {
- printk(KERN_ERR
- "sisusbvga[%d]: Error unregistering "
- "ioctl32 translations\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
}
}
#endif
@@ -3400,10 +3292,11 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
- printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+ dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
}
static struct usb_device_id sisusb_table [] = {
+ { USB_DEVICE(0x0711, 0x0550) },
{ USB_DEVICE(0x0711, 0x0900) },
{ USB_DEVICE(0x0711, 0x0901) },
{ USB_DEVICE(0x0711, 0x0902) },
@@ -3423,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
static int __init usb_sisusb_init(void)
{
- int retval;
#ifdef INCL_SISUSB_CON
sisusb_init_concode();
#endif
- if (!(retval = usb_register(&sisusb_driver))) {
-
- printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
- SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
- printk(KERN_INFO
- "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
- }
-
- return retval;
+ return usb_register(&sisusb_driver);
}
static void __exit usb_sisusb_exit(void)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 8e1120a64806..d2d7872cd022 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -8,29 +8,29 @@
*
* Otherwise, the following license terms apply:
*
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * * notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * * notice, this list of conditions and the following disclaimer in the
- * * documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * * derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -44,16 +44,14 @@
#include <linux/mutex.h>
/* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
*/
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
/* Version Information */
#define SISUSB_VERSION 0
-#define SISUSB_REVISION 0
+#define SISUSB_REVISION 0
#define SISUSB_PATCHLEVEL 8
/* Include console and mode switching code? */
@@ -74,7 +72,7 @@
#define SISUSB_IBUF_SIZE 0x01000
#define SISUSB_OBUF_SIZE 0x10000 /* fixed */
-#define NUMOBUFS 8 /* max number of output buffers/output URBs */
+#define NUMOBUFS 8 /* max number of output buffers/output URBs */
/* About endianness:
*
@@ -93,7 +91,7 @@
*/
#ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
do { \
p->header = cpu_to_le16(p->header); \
p->address = cpu_to_le32(p->address); \
@@ -105,7 +103,7 @@
struct sisusb_usb_data;
-struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
+struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
struct sisusb_usb_data *sisusb;
int urbindex;
int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
struct usb_interface *interface;
struct kref kref;
wait_queue_head_t wait_q; /* for syncind and timeouts */
- struct mutex lock; /* general race avoidance */
- unsigned int ifnum; /* interface number of the USB device */
- int minor; /* minor (for logging clarity) */
- int isopen; /* !=0 if open */
- int present; /* !=0 if device is present on the bus */
- int ready; /* !=0 if device is ready for userland */
+ struct mutex lock; /* general race avoidance */
+ unsigned int ifnum; /* interface number of the USB device */
+ int minor; /* minor (for logging clarity) */
+ int isopen; /* !=0 if open */
+ int present; /* !=0 if device is present on the bus */
+ int ready; /* !=0 if device is ready for userland */
#ifdef SISUSB_OLD_CONFIG_COMPAT
int ioctl32registered;
#endif
- int numobufs; /* number of obufs = number of out urbs */
+ int numobufs; /* number of obufs = number of out urbs */
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
int obufsize, ibufsize;
dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
unsigned char completein;
struct sisusb_urb_context urbout_context[NUMOBUFS];
unsigned long flagb0;
- unsigned long vrambase; /* framebuffer base */
- unsigned int vramsize; /* framebuffer size (bytes) */
+ unsigned long vrambase; /* framebuffer base */
+ unsigned int vramsize; /* framebuffer size (bytes) */
unsigned long mmiobase;
unsigned int mmiosize;
unsigned long ioportbase;
- unsigned char devinit; /* device initialized? */
- unsigned char gfxinit; /* graphics core initialized? */
+ unsigned char devinit; /* device initialized? */
+ unsigned char gfxinit; /* graphics core initialized? */
unsigned short chipid, chipvendor;
unsigned short chiprevision;
#ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
int haveconsole, con_first, con_last;
int havethisconsole[MAX_NR_CONSOLES];
int textmodedestroyed;
- unsigned int sisusb_num_columns; /* real number, not vt's idea */
+ unsigned int sisusb_num_columns; /* real number, not vt's idea */
int cur_start_addr, con_rolled_over;
int sisusb_cursor_loc, bad_cursor_pos;
int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
unsigned short header;
u32 address;
u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
#define CLEARPACKET(packet) memset(packet, 0, 10)
@@ -265,36 +263,36 @@ struct sisusb_packet {
/* Structure argument for SISUSB_GET_INFO ioctl */
struct sisusb_info {
- __u32 sisusb_id; /* for identifying sisusb */
-#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
- __u8 sisusb_version;
- __u8 sisusb_revision;
- __u8 sisusb_patchlevel;
- __u8 sisusb_gfxinit; /* graphics core initialized? */
+ __u32 sisusb_id; /* for identifying sisusb */
+#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
+ __u8 sisusb_version;
+ __u8 sisusb_revision;
+ __u8 sisusb_patchlevel;
+ __u8 sisusb_gfxinit; /* graphics core initialized? */
- __u32 sisusb_vrambase;
- __u32 sisusb_mmiobase;
- __u32 sisusb_iobase;
- __u32 sisusb_pcibase;
+ __u32 sisusb_vrambase;
+ __u32 sisusb_mmiobase;
+ __u32 sisusb_iobase;
+ __u32 sisusb_pcibase;
- __u32 sisusb_vramsize; /* framebuffer size in bytes */
+ __u32 sisusb_vramsize; /* framebuffer size in bytes */
- __u32 sisusb_minor;
+ __u32 sisusb_minor;
- __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
+ __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
- __u32 sisusb_conactive; /* != 0 if console driver active */
+ __u32 sisusb_conactive; /* != 0 if console driver active */
- __u8 sisusb_reserved[28]; /* for future use */
+ __u8 sisusb_reserved[28]; /* for future use */
};
struct sisusb_command {
- __u8 operation; /* see below */
- __u8 data0; /* operation dependent */
- __u8 data1; /* operation dependent */
- __u8 data2; /* operation dependent */
- __u32 data3; /* operation dependent */
- __u32 data4; /* for future use */
+ __u8 operation; /* see below */
+ __u8 data0; /* operation dependent */
+ __u8 data1; /* operation dependent */
+ __u8 data2; /* operation dependent */
+ __u32 data3; /* operation dependent */
+ __u32 data4; /* for future use */
};
#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@ struct sisusb_command {
#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */
#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@ struct sisusb_command {
#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
-
#endif /* SISUSB_H */
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 8d0edc867f33..43722e5a49d1 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -52,6 +52,7 @@
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/fs.h>
+#include <linux/usb.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
return;
/* sisusb->lock is down */
-
- /* Don't need to put the character into buffer ourselves,
- * because the vt does this BEFORE calling us.
- */
-#if 0
- sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
struct sisusb_usb_data *sisusb;
ssize_t written;
int cols, length;
-#if 0
- u16 *src, *dest;
- int i;
-#endif
if (width <= 0 || height <= 0)
return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
cols = sisusb->sisusb_num_columns;
- /* Don't need to move data outselves, because
- * vt does this BEFORE calling us.
- * This is only used by vt's insert/deletechar.
- */
-#if 0
- if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
- sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
- height * width * 2);
-
- } else if (dy < sy || (dy == sy && dx < sx)) {
-
- src = SISUSB_VADDR(sx, sy);
- dest = SISUSB_VADDR(dx, dy);
-
- for (i = height; i > 0; i--) {
- sisusbcon_memmovew(dest, src, width * 2);
- src += cols;
- dest += cols;
- }
-
- } else {
-
- src = SISUSB_VADDR(sx, sy + height - 1);
- dest = SISUSB_VADDR(dx, dy + height - 1);
-
- for (i = height; i > 0; i--) {
- sisusbcon_memmovew(dest, src, width * 2);
- src -= cols;
- dest -= cols;
- }
-
- }
-#endif
-
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
*/
if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
mutex_unlock(&sisusb->lock);
- printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
return 0;
}
@@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
int
sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
{
- int i, ret, minor = sisusb->minor;
+ int i, ret;
mutex_lock(&sisusb->lock);
@@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Set up text mode (and upload default font) */
if (sisusb_reset_text_mode(sisusb, 1)) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to set up text mode\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
return 1;
}
@@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Allocate screen buffer */
if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate screen buffer\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
return 1;
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index 9b30f8962814..273de5d0934e 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -55,109 +55,18 @@
/* POINTER INITIALIZATION */
/*********************************************/
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
{
- SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
- SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
-
- SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
- SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
- SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
- SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
-
- SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
-}
-
-/*********************************************/
-/* HELPER: Get ModeID */
-/*********************************************/
+ SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+ SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
- unsigned short ModeIndex = 0;
-
- switch (HDisplay)
- {
- case 320:
- if (VDisplay == 200)
- ModeIndex = ModeIndex_320x200[Depth];
- else if (VDisplay == 240)
- ModeIndex = ModeIndex_320x240[Depth];
- break;
- case 400:
- if (VDisplay == 300)
- ModeIndex = ModeIndex_400x300[Depth];
- break;
- case 512:
- if (VDisplay == 384)
- ModeIndex = ModeIndex_512x384[Depth];
- break;
- case 640:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_640x480[Depth];
- else if (VDisplay == 400)
- ModeIndex = ModeIndex_640x400[Depth];
- break;
- case 720:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_720x480[Depth];
- else if (VDisplay == 576)
- ModeIndex = ModeIndex_720x576[Depth];
- break;
- case 768:
- if (VDisplay == 576)
- ModeIndex = ModeIndex_768x576[Depth];
- break;
- case 800:
- if (VDisplay == 600)
- ModeIndex = ModeIndex_800x600[Depth];
- else if (VDisplay == 480)
- ModeIndex = ModeIndex_800x480[Depth];
- break;
- case 848:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_848x480[Depth];
- break;
- case 856:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_856x480[Depth];
- break;
- case 960:
- if (VDisplay == 540)
- ModeIndex = ModeIndex_960x540[Depth];
- else if (VDisplay == 600)
- ModeIndex = ModeIndex_960x600[Depth];
- break;
- case 1024:
- if (VDisplay == 576)
- ModeIndex = ModeIndex_1024x576[Depth];
- else if (VDisplay == 768)
- ModeIndex = ModeIndex_1024x768[Depth];
- break;
- case 1152:
- if (VDisplay == 864)
- ModeIndex = ModeIndex_1152x864[Depth];
- break;
- case 1280:
- switch (VDisplay) {
- case 720:
- ModeIndex = ModeIndex_1280x720[Depth];
- break;
- case 768:
- ModeIndex = ModeIndex_1280x768[Depth];
- break;
- case 1024:
- ModeIndex = ModeIndex_1280x1024[Depth];
- break;
- }
- }
+ SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+ SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+ SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+ SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
- return ModeIndex;
+ SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
}
-#endif /* 0 */
/*********************************************/
/* HELPER: SetReg, GetReg */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
static void
SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short data)
+ unsigned short index, unsigned short data)
{
sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
}
static void
SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short data)
+ unsigned short data)
{
sisusb_setreg(SiS_Pr->sisusb, port, data);
}
static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
{
u8 data;
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
static void
SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short DataAND,
- unsigned short DataOR)
+ unsigned short index, unsigned short DataAND,
+ unsigned short DataOR)
{
sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
}
static void
SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short DataAND)
+ unsigned short index, unsigned short DataAND)
{
sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
}
static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
- unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+ unsigned short index, unsigned short DataOR)
{
sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
}
@@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
/* HELPER: DisplayOn, DisplayOff */
/*********************************************/
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
{
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
}
@@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
/* HELPER: Init Port Addresses */
/*********************************************/
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
{
SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
/* HELPER: GetSysFlags */
/*********************************************/
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
{
SiS_Pr->SiS_MyCR63 = 0x63;
}
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
/* HELPER: Init PCI & Engines */
/*********************************************/
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
{
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
/* - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
/* HELPER: SET SEGMENT REGISTERS */
/*********************************************/
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
{
SiS_SetSegRegLower(SiS_Pr, value);
SiS_SetSegRegUpper(SiS_Pr, value);
}
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentReg(SiS_Pr, 0);
}
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetSegmentReg(SiS_Pr, value);
}
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentRegOver(SiS_Pr, 0);
}
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
{
SiS_ResetSegmentReg(SiS_Pr);
SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
static int
SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
- unsigned short *ModeIdIndex)
+ unsigned short *ModeIdIndex)
{
if ((*ModeNo) <= 0x13) {
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
} else {
- for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+ if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+ (*ModeNo))
break;
- if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+ if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+ 0xFF)
return 0;
}
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
/* HELPER: ENABLE CRT1 */
/*********************************************/
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
{
/* Enable CRT1 gating */
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
static unsigned short
SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
- static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+ static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
unsigned short modeflag;
short index;
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
index = (modeflag & ModeTypeMask) - ModeEGA;
- if (index < 0) index = 0;
+ if (index < 0)
+ index = 0;
return ColorDepth[index];
}
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static unsigned short
SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short xres, temp, colordepth, infoflag;
@@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
- for(i = 2; i <= 4; i++) {
- SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+ for (i = 2; i <= 4; i++) {
+ SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
}
}
@@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
- for(i = 0; i <= 0x18; i++) {
+ for (i = 0; i <= 0x18; i++) {
CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
}
@@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char ARdata;
unsigned short i;
- for(i = 0; i <= 0x13; i++) {
+ for (i = 0; i <= 0x13; i++) {
ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char GRdata;
unsigned short i;
- for(i = 0; i <= 0x08; i++) {
+ for (i = 0; i <= 0x08; i++) {
GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
}
@@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
/* CLEAR EXTENDED REGISTERS */
/*********************************************/
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
int i;
- for(i = 0x0A; i <= 0x0E; i++) {
+ for (i = 0x0A; i <= 0x0E; i++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
}
@@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
static unsigned short
SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
unsigned short rrti, i, index, temp;
if (ModeNo <= 0x13)
return 0xFFFF;
- index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
- if (index > 0) index--;
+ index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+ if (index > 0)
+ index--;
rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
break;
- temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+ temp =
+ SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
if (temp < SiS_Pr->SiS_ModeType)
break;
i++;
index--;
- } while(index != 0xFFFF);
+ } while (index != 0xFFFF);
i--;
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SYNC */
/*********************************************/
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
{
unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
static void
SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
- unsigned char index;
+ unsigned char index;
unsigned short temp, i, j, modeflag;
- SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
- for(i = 0,j = 0; i <= 7; i++, j++) {
+ for (i = 0, j = 0; i <= 7; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x10; i <= 10; i++, j++) {
+ for (j = 0x10; i <= 10; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x15; i <= 12; i++, j++) {
+ for (j = 0x15; i <= 12; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x0A; i <= 15; i++, j++) {
+ for (j = 0x0A; i <= 15; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
- if (modeflag & DoubleScanMode) temp |= 0x80;
+ if (modeflag & DoubleScanMode)
+ temp |= 0x80;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
- unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+ unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
unsigned short temp;
temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
- if (infoflag & InterlaceMode) du >>= 1;
+ if (infoflag & InterlaceMode)
+ du >>= 1;
du <<= 5;
temp = (du >> 8) & 0xff;
- if (du & 0xff) temp++;
+ if (du & 0xff)
+ temp++;
temp++;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
}
@@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short rrti)
+ unsigned short rrti)
{
unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
- SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
}
/*********************************************/
@@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short mi)
+ unsigned short mi)
{
unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
@@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short rrti)
+ unsigned short rrti)
{
unsigned short data = 0, VCLK = 0, index = 0;
@@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
}
- if (VCLK >= 166) data |= 0x0c;
+ if (VCLK >= 166)
+ data |= 0x0c;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short data, infoflag = 0, modeflag;
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
data |= 0x02;
data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
}
- if (infoflag & InterlaceMode) data |= 0x20;
+ if (infoflag & InterlaceMode)
+ data |= 0x20;
}
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
data = 0;
if (infoflag & InterlaceMode) {
/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
- unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
- ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
- unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
- ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+ unsigned short hrs =
+ (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+ ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+ - 3;
+ unsigned short hto =
+ (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+ ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+ + 5;
data = hrs - (hto >> 1) + 3;
}
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
- unsigned short shiftflag, unsigned short dl, unsigned short ah,
- unsigned short al, unsigned short dh)
+ unsigned short shiftflag, unsigned short dl, unsigned short ah,
+ unsigned short al, unsigned short dh)
{
unsigned short d1, d2, d3;
switch (dl) {
- case 0:
- d1 = dh; d2 = ah; d3 = al;
- break;
- case 1:
- d1 = ah; d2 = al; d3 = dh;
- break;
- default:
- d1 = al; d2 = dh; d3 = ah;
+ case 0:
+ d1 = dh;
+ d2 = ah;
+ d3 = al;
+ break;
+ case 1:
+ d1 = ah;
+ d2 = al;
+ d3 = dh;
+ break;
+ default:
+ d1 = al;
+ d2 = dh;
+ d3 = ah;
}
SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
}
static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+ unsigned short mi)
{
unsigned short data, data2, time, i, j, k, m, n, o;
unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
- for(i = 0; i < j; i++) {
+ for (i = 0; i < j; i++) {
data = table[i];
- for(k = 0; k < 3; k++) {
+ for (k = 0; k < 3; k++) {
data2 = 0;
- if (data & 0x01) data2 += 0x2A;
- if (data & 0x02) data2 += 0x15;
+ if (data & 0x01)
+ data2 += 0x2A;
+ if (data & 0x02)
+ data2 += 0x15;
SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
data >>= 2;
}
}
if (time == 256) {
- for(i = 16; i < 32; i++) {
+ for (i = 16; i < 32; i++) {
data = table[i] << sf;
- for(k = 0; k < 3; k++)
+ for (k = 0; k < 3; k++)
SiS_SetRegByte(SiS_Pr, DACData, data);
}
si = 32;
- for(m = 0; m < 9; m++) {
+ for (m = 0; m < 9; m++) {
di = si;
bx = si + 4;
- for(n = 0; n < 3; n++) {
- for(o = 0; o < 5; o++) {
+ for (n = 0; n < 3; n++) {
+ for (o = 0; o < 5; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
- table[di], table[bx], table[si]);
+ table[di], table[bx],
+ table[si]);
si++;
}
si -= 2;
- for(o = 0; o < 3; o++) {
+ for (o = 0; o < 3; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
- table[di], table[si], table[bx]);
+ table[di], table[si],
+ table[bx]);
si--;
}
}
- si += 5;
+ si += 5;
}
}
}
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
static void
SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
unsigned short StandTableIndex, rrti;
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SiSSetMode() */
/*********************************************/
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
unsigned short ModeIdIndex;
- unsigned long BaseAddr = SiS_Pr->IOAddress;
+ unsigned long BaseAddr = SiS_Pr->IOAddress;
SiSUSB_InitPtr(SiS_Pr);
SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
ModeNo &= 0x7f;
SiS_Pr->SiS_ModeType =
- SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+ SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
SiS_Pr->SiS_SetFlag = LowModeTests;
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
return 1;
}
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
{
unsigned short ModeNo = 0;
int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
}
#endif /* INCL_SISUSB_CON */
-
-
-
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
index 864bc0e96591..c46ce42d4489 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -46,7 +46,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -76,21 +76,21 @@
#define CRT2Mode 0x0800
#define HalfDCLK 0x1000
#define NoSupportSimuTV 0x2000
-#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
#define DoubleScanMode 0x8000
/* Infoflag */
#define SupportTV 0x0008
#define SupportTV1024 0x0800
-#define SupportCHTV 0x0800
-#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
+#define SupportCHTV 0x0800
+#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
#define SupportHiVision 0x0010
#define SupportYPbPr750p 0x1000
#define SupportLCD 0x0020
#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */
-#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
-#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
+#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
+#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
#define InterlaceMode 0x0080
#define SyncPP 0x0000
#define SyncPN 0x4000
@@ -129,7 +129,7 @@
#define SIS_RI_856x480 19
#define SIS_RI_1280x768 20
#define SIS_RI_1400x1050 21
-#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
+#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
#define SIS_RI_848x480 23
#define SIS_RI_1360x768 24
#define SIS_RI_1024x600 25
@@ -147,691 +147,691 @@
#define SIS_CRT2_PORT_04 0x04 - 0x30
/* Mode numbers */
-static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
-static const unsigned char SiS_MDA_DAC[] =
-{
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
};
-static const unsigned char SiS_CGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
};
-static const unsigned char SiS_EGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
- 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
- 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
- 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
- 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
- 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
- 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+ 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+ 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+ 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+ 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+ 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+ 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
};
-static const unsigned char SiS_VGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
- 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
- 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
- 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
- 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
- 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
- 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
- 0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+ 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+ 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+ 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+ 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+ 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+ 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+ 0x0B, 0x0C, 0x0D, 0x0F, 0x10
};
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
- {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
- {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+ {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+ {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
- { 640,400},
- { 640,350},
- { 720,400},
- { 720,350},
- { 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+ {640, 400},
+ {640, 350},
+ {720, 400},
+ {720, 350},
+ {640, 480}
};
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
- { 320, 200, 8, 8}, /* 0x00 */
- { 320, 240, 8, 8}, /* 0x01 */
- { 320, 400, 8, 8}, /* 0x02 */
- { 400, 300, 8, 8}, /* 0x03 */
- { 512, 384, 8, 8}, /* 0x04 */
- { 640, 400, 8,16}, /* 0x05 */
- { 640, 480, 8,16}, /* 0x06 */
- { 800, 600, 8,16}, /* 0x07 */
- { 1024, 768, 8,16}, /* 0x08 */
- { 1280,1024, 8,16}, /* 0x09 */
- { 1600,1200, 8,16}, /* 0x0a */
- { 1920,1440, 8,16}, /* 0x0b */
- { 2048,1536, 8,16}, /* 0x0c */
- { 720, 480, 8,16}, /* 0x0d */
- { 720, 576, 8,16}, /* 0x0e */
- { 1280, 960, 8,16}, /* 0x0f */
- { 800, 480, 8,16}, /* 0x10 */
- { 1024, 576, 8,16}, /* 0x11 */
- { 1280, 720, 8,16}, /* 0x12 */
- { 856, 480, 8,16}, /* 0x13 */
- { 1280, 768, 8,16}, /* 0x14 */
- { 1400,1050, 8,16}, /* 0x15 */
- { 1152, 864, 8,16}, /* 0x16 */
- { 848, 480, 8,16}, /* 0x17 */
- { 1360, 768, 8,16}, /* 0x18 */
- { 1024, 600, 8,16}, /* 0x19 */
- { 1152, 768, 8,16}, /* 0x1a */
- { 768, 576, 8,16}, /* 0x1b */
- { 1360,1024, 8,16}, /* 0x1c */
- { 1680,1050, 8,16}, /* 0x1d */
- { 1280, 800, 8,16}, /* 0x1e */
- { 1920,1080, 8,16}, /* 0x1f */
- { 960, 540, 8,16}, /* 0x20 */
- { 960, 600, 8,16} /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+ {320, 200, 8, 8}, /* 0x00 */
+ {320, 240, 8, 8}, /* 0x01 */
+ {320, 400, 8, 8}, /* 0x02 */
+ {400, 300, 8, 8}, /* 0x03 */
+ {512, 384, 8, 8}, /* 0x04 */
+ {640, 400, 8, 16}, /* 0x05 */
+ {640, 480, 8, 16}, /* 0x06 */
+ {800, 600, 8, 16}, /* 0x07 */
+ {1024, 768, 8, 16}, /* 0x08 */
+ {1280, 1024, 8, 16}, /* 0x09 */
+ {1600, 1200, 8, 16}, /* 0x0a */
+ {1920, 1440, 8, 16}, /* 0x0b */
+ {2048, 1536, 8, 16}, /* 0x0c */
+ {720, 480, 8, 16}, /* 0x0d */
+ {720, 576, 8, 16}, /* 0x0e */
+ {1280, 960, 8, 16}, /* 0x0f */
+ {800, 480, 8, 16}, /* 0x10 */
+ {1024, 576, 8, 16}, /* 0x11 */
+ {1280, 720, 8, 16}, /* 0x12 */
+ {856, 480, 8, 16}, /* 0x13 */
+ {1280, 768, 8, 16}, /* 0x14 */
+ {1400, 1050, 8, 16}, /* 0x15 */
+ {1152, 864, 8, 16}, /* 0x16 */
+ {848, 480, 8, 16}, /* 0x17 */
+ {1360, 768, 8, 16}, /* 0x18 */
+ {1024, 600, 8, 16}, /* 0x19 */
+ {1152, 768, 8, 16}, /* 0x1a */
+ {768, 576, 8, 16}, /* 0x1b */
+ {1360, 1024, 8, 16}, /* 0x1c */
+ {1680, 1050, 8, 16}, /* 0x1d */
+ {1280, 800, 8, 16}, /* 0x1e */
+ {1920, 1080, 8, 16}, /* 0x1f */
+ {960, 540, 8, 16}, /* 0x20 */
+ {960, 600, 8, 16} /* 0x21 */
};
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
/* MD_3_400 - mode 0x03 - 400 */
{
- 0x50,0x18,0x10,0x1000,
- { 0x00,0x03,0x00,0x02 },
- 0x67,
- { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
- 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
- 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
- 0xff },
- { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
- 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
- 0x0c,0x00,0x0f,0x08 },
- { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
- },
+ 0x50, 0x18, 0x10, 0x1000,
+ {0x00, 0x03, 0x00, 0x02},
+ 0x67,
+ {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+ },
/* Generic for VGA and higher */
{
- 0x00,0x00,0x00,0x0000,
- { 0x01,0x0f,0x00,0x0e },
- 0x23,
- { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
- 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
- 0xff },
- { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
- 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
- 0x01,0x00,0x00,0x00 },
- { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
- }
+ 0x00, 0x00, 0x00, 0x0000,
+ {0x01, 0x0f, 0x00, 0x0e},
+ 0x23,
+ {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x01, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+ }
};
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
- {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
- {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
- {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
- {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
- {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
- {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
- {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
- {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
- {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
- {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
- {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
- {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
- {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
- {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
- {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
- {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
- {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */
- {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */
- {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */
- {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
- {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
- {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
- {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */
- {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
- {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
- {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
- {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
- {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
- {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
- {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
- {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
- {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
- {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
- {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
- {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
- {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
- {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
- {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
- {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
- {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
- {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
- {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
- {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
- {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
- {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
- {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
- {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
- {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
- {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
- {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
- {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
- {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
- {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
- {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
- {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
- {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
- {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
- {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
- {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
- {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
- {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
- {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
- {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
- {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+ {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */
+ {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */
+ {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */
+ {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */
+ {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */
+ {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */
+ {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */
+ {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */
+ {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */
+ {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */
+ {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */
+ {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */
+ {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */
+ {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */
+ {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */
+ {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */
+ {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */
+ {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */
+ {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */
+ {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */
+ {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */
+ {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */
+ {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */
+ {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */
+ {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */
+ {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */
+ {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */
+ {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */
+ {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */
+ {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */
+ {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */
+ {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */
+ {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */
+ {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */
+ {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */
+ {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */
+ {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */
+ {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */
+ {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */
+ {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */
+ {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */
+ {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */
+ {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */
+ {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+ -1},
+ {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+ -1},
+ {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */
+ {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ -1},
+ {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ -1},
+ {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */
+ {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */
+ {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */
+ {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */
+ {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+ -1},
+ {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+ -1},
+ {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */
+ {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ -1},
+ {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ -1},
+ {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */
+ {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+ -1},
+ {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+ -1},
+ {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */
+ {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+ -1},
+ {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+ -1},
+ {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
};
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
- {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
- {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
- {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
- {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
- {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
- {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
- {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
- {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
- {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
- {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
- {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
- {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
- {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
- {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
- {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
- {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
- {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
- {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
- {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
- {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
- {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
- {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
- {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
- {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
- {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
- {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
- {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
- {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
- {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
- {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
- {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
- {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
- {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
- {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
- {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
- {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
- {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
- {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
- {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
- {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
- {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
- {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
- {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
- {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
- {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
- {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
- {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
- {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
- {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
- {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
- {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
- {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
- {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
- {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
- {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+ {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
+ {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
+ {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
+ {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
+ {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
+ {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
+ {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
+ {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
+ {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
+ {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
+ {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
+ {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
+ {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
+ {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
+ {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
+ {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
+ {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
+ {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
+ {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
+ {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
+ {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
+ {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
+ {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
+ {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
+ {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
+ {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
+ {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
+ {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
+ {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
+ {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
+ {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
+ {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
+ {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
+ {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
+ {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
+ {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
+ {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
+ {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
+ {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
+ {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
+ {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
+ {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
+ {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
+ {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
+ {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
+ {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
+ {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
+ {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */
+ {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */
+ {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */
+ {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */
+ {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
+ {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
+ {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
+ {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
};
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
- 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
- 0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
- 0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
- 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
- 0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
- 0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
- 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
- 0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
- 0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
- 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
- 0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
- 0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
- 0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
- 0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
- 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
- 0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
- 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
- 0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
- 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
- 0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
- 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
- 0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
- 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
- 0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
- 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
- 0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
- 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
- 0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
- 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
- 0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
- 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
- 0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
- 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
- 0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
- 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
- 0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
- 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
- 0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
- 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
- 0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
- 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
- 0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
- 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
- 0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
- 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
- 0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
- 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
- 0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
- 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
- 0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
- 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
- 0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
- 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
- 0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
- 0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
- 0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
- 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
- 0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
- 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
- 0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
- 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
- 0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
- 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
- 0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
- 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
- 0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
- 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
- 0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
- 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
- 0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
- 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
- 0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
- 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
- 0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
- 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
- 0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
- 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
- 0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
- 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
- 0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
- 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
- 0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
- 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
- 0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
- 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
- 0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
- 0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
- 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
- 0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
- 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
- 0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
- 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
- 0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
- 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
- 0x01}}, /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
- 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
- 0x01}}, /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
- 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
- 0x00}}, /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
- 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
- 0x01}}, /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
- 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
- 0x00}}, /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
- 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
- 0x00}}, /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
- 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
- 0x00}}, /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
- 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
- 0x00}}, /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
- 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
- 0x01}}, /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
- 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
- 0x01}}, /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
- 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
- 0x00}}, /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
- 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
- 0x01}}, /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
- 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
- 0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
- 0x00}}, /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
- 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
- 0x21}}, /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
- 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
- 0x20}}, /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
- 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
- 0x61}}, /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
- 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
- 0x41}}, /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
- 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
- 0x01}}, /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
- 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
- 0x41}} /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+ 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+ 0x00}}, /* 0x0 */
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+ 0x00}}, /* 0x1 */
+ {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+ 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+ 0x01}}, /* 0x2 */
+ {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+ 0x01}}, /* 0x3 */
+ {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+ 0x00}}, /* 0x4 */
+ {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+ 0x00}}, /* 0x5 */
+ {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+ 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+ 0x00}}, /* 0x6 */
+ {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+ 0x00}}, /* 0x7 */
+ {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+ 0x00}}, /* 0x8 */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+ 0x61}}, /* 0x9 */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+ 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+ 0x61}}, /* 0xa */
+ {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+ 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+ 0x61}}, /* 0xb */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+ 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+ 0x00}}, /* 0xc */
+ {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+ 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+ 0x01}}, /* 0xd */
+ {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+ 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0xe */
+ {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+ 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0xf */
+ {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0x10 */
+ {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0x11 */
+ {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x12 */
+ {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x13 */
+ {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x14 */
+ {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+ 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+ 0x00}}, /* 0x15 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x16 */
+ {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x17 */
+ {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x18 */
+ {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x19 */
+ {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+ 0x62}}, /* 0x1a */
+ {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+ 0x62}}, /* 0x1b */
+ {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+ 0x00}}, /* 0x1c */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1d */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1e */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1f */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x20 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x21 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x22 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x23 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x24 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x25 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x26 */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x27 */
+ {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+ 0x63}}, /* 0x28 */
+ {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+ 0x63}}, /* 0x29 */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2a */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2b */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2c */
+ {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2d */
+ {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2e */
+ {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2f */
+ {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+ 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x30 */
+ {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+ 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+ 0x00}}, /* 0x31 */
+ {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+ 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x32 */
+ {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+ 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x33 */
+ {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+ 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x34 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+ 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x35 */
+ {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+ 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x36 */
+ {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+ 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x37 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+ 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x38 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+ 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x39 */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+ 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x3a */
+ {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+ 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x3b */
+ {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+ 0x00}}, /* 0x3c */
+ {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+ 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+ 0x41}}, /* 0x3d */
+ {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+ 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x3e */
+ {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+ 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+ 0x00}}, /* 0x3f */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+ 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x40 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x41 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+ 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x42 */
+ {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+ 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+ 0x00}}, /* 0x43 */
+ {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+ 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x44 */
+ {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+ 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x45 */
+ {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+ 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+ 0x00}}, /* 0x46 */
+ {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+ 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x47 */
+ {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+ 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+ 0x00}}, /* 0x48 */
+ {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+ 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+ 0x01}}, /* 0x49 */
+ {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+ 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+ 0x01}}, /* 0x4a */
+ {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+ 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+ 0x00}}, /* 0x4b */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+ 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x4c */
+ {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+ 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+ 0x41}},
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+ 0x00}}, /* 0x4e */
+ {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+ 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+ 0x21}}, /* 0x4f */
+ {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+ 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+ 0x20}}, /* 0x50 */
+ {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+ 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+ 0x61}}, /* 0x51 */
+ {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+ 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+ 0x41}}, /* 0x52 */
+ {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+ 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+ 0x01}}, /* 0x53 */
+ {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+ 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+ 0x41}} /* 0x54 */
};
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
- { 0x1b,0xe1, 25}, /* 0x00 */
- { 0x4e,0xe4, 28}, /* 0x01 */
- { 0x57,0xe4, 31}, /* 0x02 */
- { 0xc3,0xc8, 36}, /* 0x03 */
- { 0x42,0xe2, 40}, /* 0x04 */
- { 0xfe,0xcd, 43}, /* 0x05 */
- { 0x5d,0xc4, 44}, /* 0x06 */
- { 0x52,0xe2, 49}, /* 0x07 */
- { 0x53,0xe2, 50}, /* 0x08 */
- { 0x74,0x67, 52}, /* 0x09 */
- { 0x6d,0x66, 56}, /* 0x0a */
- { 0x5a,0x64, 65}, /* 0x0b */
- { 0x46,0x44, 67}, /* 0x0c */
- { 0xb1,0x46, 68}, /* 0x0d */
- { 0xd3,0x4a, 72}, /* 0x0e */
- { 0x29,0x61, 75}, /* 0x0f */
- { 0x6e,0x46, 76}, /* 0x10 */
- { 0x2b,0x61, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x41,104}, /* 0x17 */
- { 0x3a,0x23,105}, /* 0x18 */
- { 0x70,0x44,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0x54,0x42,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x62,0x06,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a 301 TV */
- { 0x52,0x6a, 27}, /* 0x3b 301 TV */
- { 0x62,0x24, 70}, /* 0x3c 301 TV */
- { 0x62,0x64, 70}, /* 0x3d 301 TV */
- { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
- { 0x20,0x26, 33}, /* 0x3f 301 TV */
- { 0x31,0xc2, 39}, /* 0x40 */
- { 0x60,0x36, 30}, /* 0x41 Chrontel */
- { 0x40,0x4a, 28}, /* 0x42 Chrontel */
- { 0x9f,0x46, 44}, /* 0x43 Chrontel */
- { 0x97,0x2c, 26}, /* 0x44 */
- { 0x44,0xe4, 25}, /* 0x45 Chrontel */
- { 0x7e,0x32, 47}, /* 0x46 Chrontel */
- { 0x8a,0x24, 31}, /* 0x47 Chrontel */
- { 0x97,0x2c, 26}, /* 0x48 Chrontel */
- { 0xce,0x3c, 39}, /* 0x49 */
- { 0x52,0x4a, 36}, /* 0x4a Chrontel */
- { 0x34,0x61, 95}, /* 0x4b */
- { 0x78,0x27,108}, /* 0x4c - was 102 */
- { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
- { 0x41,0x4e, 21}, /* 0x4e */
- { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
- { 0x19,0x42, 42}, /* 0x50 */
- { 0x54,0x46, 58}, /* 0x51 Chrontel */
- { 0x25,0x42, 61}, /* 0x52 */
- { 0x44,0x44, 66}, /* 0x53 Chrontel */
- { 0x3a,0x62, 70}, /* 0x54 Chrontel */
- { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
- { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
- { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
- { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
- { 0x52,0x07,149}, /* 0x59 1280x960-85 */
- { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
- { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
- { 0x45,0x25, 83}, /* 0x5c 1280x800 */
- { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
- { 0x70,0x24,162}, /* 0x5e 1600x1200 */
- { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
- { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
- { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
- { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
- { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
- { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
- { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
- { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
- { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
- { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
- { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
- { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
- { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
- { 0x45,0x25, 83}, /* 0x6c 1280x800 */
- { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
- { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
- { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
- { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
- { 0x2b,0xc2, 35} /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+ {0x1b, 0xe1, 25}, /* 0x00 */
+ {0x4e, 0xe4, 28}, /* 0x01 */
+ {0x57, 0xe4, 31}, /* 0x02 */
+ {0xc3, 0xc8, 36}, /* 0x03 */
+ {0x42, 0xe2, 40}, /* 0x04 */
+ {0xfe, 0xcd, 43}, /* 0x05 */
+ {0x5d, 0xc4, 44}, /* 0x06 */
+ {0x52, 0xe2, 49}, /* 0x07 */
+ {0x53, 0xe2, 50}, /* 0x08 */
+ {0x74, 0x67, 52}, /* 0x09 */
+ {0x6d, 0x66, 56}, /* 0x0a */
+ {0x5a, 0x64, 65}, /* 0x0b */
+ {0x46, 0x44, 67}, /* 0x0c */
+ {0xb1, 0x46, 68}, /* 0x0d */
+ {0xd3, 0x4a, 72}, /* 0x0e */
+ {0x29, 0x61, 75}, /* 0x0f */
+ {0x6e, 0x46, 76}, /* 0x10 */
+ {0x2b, 0x61, 78}, /* 0x11 */
+ {0x31, 0x42, 79}, /* 0x12 */
+ {0xab, 0x44, 83}, /* 0x13 */
+ {0x46, 0x25, 84}, /* 0x14 */
+ {0x78, 0x29, 86}, /* 0x15 */
+ {0x62, 0x44, 94}, /* 0x16 */
+ {0x2b, 0x41, 104}, /* 0x17 */
+ {0x3a, 0x23, 105}, /* 0x18 */
+ {0x70, 0x44, 108}, /* 0x19 */
+ {0x3c, 0x23, 109}, /* 0x1a */
+ {0x5e, 0x43, 113}, /* 0x1b */
+ {0xbc, 0x44, 116}, /* 0x1c */
+ {0xe0, 0x46, 132}, /* 0x1d */
+ {0x54, 0x42, 135}, /* 0x1e */
+ {0xea, 0x2a, 139}, /* 0x1f */
+ {0x41, 0x22, 157}, /* 0x20 */
+ {0x70, 0x24, 162}, /* 0x21 */
+ {0x30, 0x21, 175}, /* 0x22 */
+ {0x4e, 0x22, 189}, /* 0x23 */
+ {0xde, 0x26, 194}, /* 0x24 */
+ {0x62, 0x06, 202}, /* 0x25 */
+ {0x3f, 0x03, 229}, /* 0x26 */
+ {0xb8, 0x06, 234}, /* 0x27 */
+ {0x34, 0x02, 253}, /* 0x28 */
+ {0x58, 0x04, 255}, /* 0x29 */
+ {0x24, 0x01, 265}, /* 0x2a */
+ {0x9b, 0x02, 267}, /* 0x2b */
+ {0x70, 0x05, 270}, /* 0x2c */
+ {0x25, 0x01, 272}, /* 0x2d */
+ {0x9c, 0x02, 277}, /* 0x2e */
+ {0x27, 0x01, 286}, /* 0x2f */
+ {0x3c, 0x02, 291}, /* 0x30 */
+ {0xef, 0x0a, 292}, /* 0x31 */
+ {0xf6, 0x0a, 310}, /* 0x32 */
+ {0x95, 0x01, 315}, /* 0x33 */
+ {0xf0, 0x09, 324}, /* 0x34 */
+ {0xfe, 0x0a, 331}, /* 0x35 */
+ {0xf3, 0x09, 332}, /* 0x36 */
+ {0xea, 0x08, 340}, /* 0x37 */
+ {0xe8, 0x07, 376}, /* 0x38 */
+ {0xde, 0x06, 389}, /* 0x39 */
+ {0x52, 0x2a, 54}, /* 0x3a 301 TV */
+ {0x52, 0x6a, 27}, /* 0x3b 301 TV */
+ {0x62, 0x24, 70}, /* 0x3c 301 TV */
+ {0x62, 0x64, 70}, /* 0x3d 301 TV */
+ {0xa8, 0x4c, 30}, /* 0x3e 301 TV */
+ {0x20, 0x26, 33}, /* 0x3f 301 TV */
+ {0x31, 0xc2, 39}, /* 0x40 */
+ {0x60, 0x36, 30}, /* 0x41 Chrontel */
+ {0x40, 0x4a, 28}, /* 0x42 Chrontel */
+ {0x9f, 0x46, 44}, /* 0x43 Chrontel */
+ {0x97, 0x2c, 26}, /* 0x44 */
+ {0x44, 0xe4, 25}, /* 0x45 Chrontel */
+ {0x7e, 0x32, 47}, /* 0x46 Chrontel */
+ {0x8a, 0x24, 31}, /* 0x47 Chrontel */
+ {0x97, 0x2c, 26}, /* 0x48 Chrontel */
+ {0xce, 0x3c, 39}, /* 0x49 */
+ {0x52, 0x4a, 36}, /* 0x4a Chrontel */
+ {0x34, 0x61, 95}, /* 0x4b */
+ {0x78, 0x27, 108}, /* 0x4c - was 102 */
+ {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
+ {0x41, 0x4e, 21}, /* 0x4e */
+ {0xa1, 0x4a, 29}, /* 0x4f Chrontel */
+ {0x19, 0x42, 42}, /* 0x50 */
+ {0x54, 0x46, 58}, /* 0x51 Chrontel */
+ {0x25, 0x42, 61}, /* 0x52 */
+ {0x44, 0x44, 66}, /* 0x53 Chrontel */
+ {0x3a, 0x62, 70}, /* 0x54 Chrontel */
+ {0x62, 0xc6, 34}, /* 0x55 848x480-60 */
+ {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */
+ {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */
+ {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
+ {0x52, 0x07, 149}, /* 0x59 1280x960-85 */
+ {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */
+ {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */
+ {0x45, 0x25, 83}, /* 0x5c 1280x800 */
+ {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */
+ {0x70, 0x24, 162}, /* 0x5e 1600x1200 */
+ {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */
+ {0x63, 0x46, 68}, /* 0x60 1280x768_2 */
+ {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */
+ {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
+ {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+ {0x70, 0x28, 90}, /* 0x64 1152x864@60 */
+ {0x41, 0xc4, 32}, /* 0x65 848x480@60 */
+ {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */
+ {0x76, 0xe7, 27}, /* 0x67 720x480@60 */
+ {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */
+ {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
+ {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */
+ {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */
+ {0x45, 0x25, 83}, /* 0x6c 1280x800 */
+ {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */
+ {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
+ {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */
+ {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
+ {0x2b, 0xc2, 35} /* 0x71 768@576@60 */
};
-int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
-extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 data);
-extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 *data);
-extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
- u8 idx, u8 myand, u8 myor);
-extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 myor);
-extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
- u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand);
void sisusb_delete(struct kref *kref);
int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
- u32 dest, int length, size_t *bytes_written);
+ u32 dest, int length, size_t * bytes_written);
int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
- u8 *arg, int cmapsz, int ch512, int dorecalc,
+ u8 * arg, int cmapsz, int ch512, int dorecalc,
struct vc_data *c, int fh, int uplock);
void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb);
void sisusb_init_concode(void);
#endif
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
index f325ecb29a61..1c4240e802c1 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_struct.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -44,7 +44,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -52,85 +52,78 @@
#define _SISUSB_STRUCT_H_
struct SiS_St {
- unsigned char St_ModeID;
- unsigned short St_ModeFlag;
- unsigned char St_StTableIndex;
- unsigned char St_CRT2CRTC;
- unsigned char St_ResInfo;
- unsigned char VB_StTVFlickerIndex;
- unsigned char VB_StTVEdgeIndex;
- unsigned char VB_StTVYFilterIndex;
- unsigned char St_PDC;
+ unsigned char St_ModeID;
+ unsigned short St_ModeFlag;
+ unsigned char St_StTableIndex;
+ unsigned char St_CRT2CRTC;
+ unsigned char St_ResInfo;
+ unsigned char VB_StTVFlickerIndex;
+ unsigned char VB_StTVEdgeIndex;
+ unsigned char VB_StTVYFilterIndex;
+ unsigned char St_PDC;
};
-struct SiS_StandTable
-{
- unsigned char CRT_COLS;
- unsigned char ROWS;
- unsigned char CHAR_HEIGHT;
- unsigned short CRT_LEN;
- unsigned char SR[4];
- unsigned char MISC;
- unsigned char CRTC[0x19];
- unsigned char ATTR[0x14];
- unsigned char GRC[9];
+struct SiS_StandTable {
+ unsigned char CRT_COLS;
+ unsigned char ROWS;
+ unsigned char CHAR_HEIGHT;
+ unsigned short CRT_LEN;
+ unsigned char SR[4];
+ unsigned char MISC;
+ unsigned char CRTC[0x19];
+ unsigned char ATTR[0x14];
+ unsigned char GRC[9];
};
struct SiS_StResInfo_S {
- unsigned short HTotal;
- unsigned short VTotal;
+ unsigned short HTotal;
+ unsigned short VTotal;
};
-struct SiS_Ext
-{
- unsigned char Ext_ModeID;
- unsigned short Ext_ModeFlag;
- unsigned short Ext_VESAID;
- unsigned char Ext_RESINFO;
- unsigned char VB_ExtTVFlickerIndex;
- unsigned char VB_ExtTVEdgeIndex;
- unsigned char VB_ExtTVYFilterIndex;
- unsigned char VB_ExtTVYFilterIndexROM661;
- unsigned char REFindex;
- char ROMMODEIDX661;
+struct SiS_Ext {
+ unsigned char Ext_ModeID;
+ unsigned short Ext_ModeFlag;
+ unsigned short Ext_VESAID;
+ unsigned char Ext_RESINFO;
+ unsigned char VB_ExtTVFlickerIndex;
+ unsigned char VB_ExtTVEdgeIndex;
+ unsigned char VB_ExtTVYFilterIndex;
+ unsigned char VB_ExtTVYFilterIndexROM661;
+ unsigned char REFindex;
+ char ROMMODEIDX661;
};
-struct SiS_Ext2
-{
- unsigned short Ext_InfoFlag;
- unsigned char Ext_CRT1CRTC;
- unsigned char Ext_CRTVCLK;
- unsigned char Ext_CRT2CRTC;
- unsigned char Ext_CRT2CRTC_NS;
- unsigned char ModeID;
- unsigned short XRes;
- unsigned short YRes;
- unsigned char Ext_PDC;
- unsigned char Ext_FakeCRT2CRTC;
- unsigned char Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+ unsigned short Ext_InfoFlag;
+ unsigned char Ext_CRT1CRTC;
+ unsigned char Ext_CRTVCLK;
+ unsigned char Ext_CRT2CRTC;
+ unsigned char Ext_CRT2CRTC_NS;
+ unsigned char ModeID;
+ unsigned short XRes;
+ unsigned short YRes;
+ unsigned char Ext_PDC;
+ unsigned char Ext_FakeCRT2CRTC;
+ unsigned char Ext_FakeCRT2Clk;
};
-struct SiS_CRT1Table
-{
- unsigned char CR[17];
+struct SiS_CRT1Table {
+ unsigned char CR[17];
};
-struct SiS_VCLKData
-{
- unsigned char SR2B,SR2C;
- unsigned short CLOCK;
+struct SiS_VCLKData {
+ unsigned char SR2B, SR2C;
+ unsigned short CLOCK;
};
-struct SiS_ModeResInfo
-{
- unsigned short HTotal;
- unsigned short VTotal;
- unsigned char XChar;
- unsigned char YChar;
+struct SiS_ModeResInfo {
+ unsigned short HTotal;
+ unsigned short VTotal;
+ unsigned char XChar;
+ unsigned char YChar;
};
-struct SiS_Private
-{
+struct SiS_Private {
void *sisusb;
unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
unsigned long SiS_P3da;
unsigned long SiS_Part1Port;
- unsigned char SiS_MyCR63;
- unsigned short SiS_CRT1Mode;
- unsigned short SiS_ModeType;
- unsigned short SiS_SetFlag;
-
- const struct SiS_StandTable *SiS_StandTable;
- const struct SiS_St *SiS_SModeIDTable;
- const struct SiS_Ext *SiS_EModeIDTable;
- const struct SiS_Ext2 *SiS_RefIndex;
- const struct SiS_CRT1Table *SiS_CRT1Table;
- const struct SiS_VCLKData *SiS_VCLKData;
- const struct SiS_ModeResInfo *SiS_ModeResInfo;
+ unsigned char SiS_MyCR63;
+ unsigned short SiS_CRT1Mode;
+ unsigned short SiS_ModeType;
+ unsigned short SiS_SetFlag;
+
+ const struct SiS_StandTable *SiS_StandTable;
+ const struct SiS_St *SiS_SModeIDTable;
+ const struct SiS_Ext *SiS_EModeIDTable;
+ const struct SiS_Ext2 *SiS_RefIndex;
+ const struct SiS_CRT1Table *SiS_CRT1Table;
+ const struct SiS_VCLKData *SiS_VCLKData;
+ const struct SiS_ModeResInfo *SiS_ModeResInfo;
};
#endif
-
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 504f7221b0d0..719842032712 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -176,16 +176,17 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
static void lcd_write_bulk_callback(struct urb *urb)
{
struct usb_lcd *dev;
+ int status = urb->status;
dev = (struct usb_lcd *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
+ if (status &&
+ !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dbg("USBLCD: %s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
/* free up our allocated buffer */
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index fb321864a92d..e901d31e051b 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -768,8 +768,8 @@ static void ctrl_complete (struct urb *urb)
/* some faults are allowed, not required */
if (subcase->expected > 0 && (
- ((urb->status == -subcase->expected /* happened */
- || urb->status == 0)))) /* didn't */
+ ((status == -subcase->expected /* happened */
+ || status == 0)))) /* didn't */
status = 0;
/* sometimes more than one fault is allowed */
else if (subcase->number == 12 && status == -EPIPE)
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 1a60f9c473ad..2734fe2b9c43 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -111,12 +111,13 @@ static void async_complete(struct urb *urb)
struct uss720_async_request *rq;
struct parport *pp;
struct parport_uss720_private *priv;
+ int status = urb->status;
rq = urb->context;
priv = rq->priv;
pp = priv->pp;
- if (urb->status) {
- err("async_complete: urb error %d", urb->status);
+ if (status) {
+ err("async_complete: urb error %d", status);
} else if (rq->dr.bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index c03dfd7a9d36..f06e4e2b49d3 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+static unsigned char xfer_to_pipe[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
const struct urb *urb, char ev_type)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
return '-';
- if (urb->dev->bus->uses_dma &&
- (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
- }
if (urb->setup_packet == NULL)
return 'Z';
@@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
}
static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
- char ev_type)
+ char ev_type, int status)
{
+ const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
unsigned long flags;
struct timeval ts;
unsigned int urb_length;
unsigned int offset;
unsigned int length;
+ unsigned char dir;
struct mon_bin_hdr *ep;
char data_tag = 0;
@@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
if (length >= rp->b_size/5)
length = rp->b_size/5;
- if (usb_pipein(urb->pipe)) {
+ if (usb_urb_dir_in(urb)) {
if (ev_type == 'S') {
length = 0;
data_tag = '<';
}
+ /* Cannot rely on endpoint number in case of control ep.0 */
+ dir = USB_DIR_IN;
} else {
if (ev_type == 'C') {
length = 0;
data_tag = '>';
}
+ dir = 0;
}
if (rp->mmap_active)
@@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
*/
memset(ep, 0, PKT_SIZE);
ep->type = ev_type;
- ep->xfer_type = usb_pipetype(urb->pipe);
- /* We use the fact that usb_pipein() returns 0x80 */
- ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
- ep->devnum = usb_pipedevice(urb->pipe);
+ ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+ ep->epnum = dir | usb_endpoint_num(epd);
+ ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
ep->ts_usec = ts.tv_usec;
- ep->status = urb->status;
+ ep->status = status;
ep->len_urb = urb_length;
ep->len_cap = length;
@@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
static void mon_bin_submit(void *data, struct urb *urb)
{
struct mon_reader_bin *rp = data;
- mon_bin_event(rp, urb, 'S');
+ mon_bin_event(rp, urb, 'S', -EINPROGRESS);
}
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_bin *rp = data;
- mon_bin_event(rp, urb, 'C');
+ mon_bin_event(rp, urb, 'C', status);
}
static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
memset(ep, 0, PKT_SIZE);
ep->type = 'E';
- ep->xfer_type = usb_pipetype(urb->pipe);
- /* We use the fact that usb_pipein() returns 0x80 */
- ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
- ep->devnum = usb_pipedevice(urb->pipe);
+ ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+ ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+ ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+ ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->status = error;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index ce61d8b0fd86..b371ffd39d36 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
/*
*/
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+ int status)
{
unsigned long flags;
struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
- r->rnf_complete(r->r_data, urb);
+ r->rnf_complete(r->r_data, urb, status);
}
spin_unlock_irqrestore(&mbus->lock, flags);
}
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
{
struct mon_bus *mbus;
- mbus = ubus->mon_bus;
- if (mbus == NULL) {
- /*
- * This should not happen.
- * At this point we do not even know the bus number...
- */
- printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
- urb->pipe);
- return;
- }
-
- mon_bus_complete(mbus, urb);
- mon_bus_complete(&mon_bus0, urb);
+ if ((mbus = ubus->mon_bus) != NULL)
+ mon_bus_complete(mbus, urb, status);
+ mon_bus_complete(&mon_bus0, urb, status);
}
/* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
*/
static void mon_stop(struct mon_bus *mbus)
{
- struct usb_bus *ubus = mbus->u_bus;
+ struct usb_bus *ubus;
struct list_head *p;
if (mbus == &mon_bus0) {
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 982b773d71e6..ebb04ac4857b 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -50,10 +50,13 @@ struct mon_iso_desc {
struct mon_event_text {
struct list_head e_link;
int type; /* submit, complete, etc. */
- unsigned int pipe; /* Pipe */
unsigned long id; /* From pointer, most of the time */
unsigned int tstamp;
int busnum;
+ char devnum;
+ char epnum;
+ char is_in;
+ char xfertype;
int length; /* Depends on type: xfer length or act length */
int status;
int interval;
@@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
struct urb *urb, char ev_type, struct mon_bus *mbus)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
return '-';
- if (urb->dev->bus->uses_dma &&
- (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
- }
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type, struct mon_bus *mbus)
{
- int pipe = urb->pipe;
-
if (len <= 0)
return 'L';
if (len >= DATA_MAX)
len = DATA_MAX;
- if (usb_pipein(pipe)) {
+ if (ep->is_in) {
if (ev_type != 'C')
return '<';
} else {
@@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
}
static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
- char ev_type)
+ char ev_type, int status)
{
struct mon_event_text *ep;
unsigned int stamp;
@@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
}
ep->type = ev_type;
- ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = urb->dev->bus->busnum;
+ ep->devnum = urb->dev->devnum;
+ ep->epnum = usb_endpoint_num(&urb->ep->desc);
+ ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+ ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = stamp;
ep->length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
/* Collecting status makes debugging sense for submits, too */
- ep->status = urb->status;
+ ep->status = status;
- if (usb_pipeint(urb->pipe)) {
+ if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
ep->interval = urb->interval;
- } else if (usb_pipeisoc(urb->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
ep->interval = urb->interval;
ep->start_frame = urb->start_frame;
ep->error_count = urb->error_count;
}
ep->numdesc = urb->number_of_packets;
- if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+ if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+ urb->number_of_packets > 0) {
if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
ndesc = ISODESC_MAX;
fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
static void mon_text_submit(void *data, struct urb *urb)
{
struct mon_reader_text *rp = data;
- mon_text_event(rp, urb, 'S');
+ mon_text_event(rp, urb, 'S', -EINPROGRESS);
}
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_text *rp = data;
- mon_text_event(rp, urb, 'C');
+ mon_text_event(rp, urb, 'C', status);
}
static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
}
ep->type = 'E';
- ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = 0;
+ ep->devnum = urb->dev->devnum;
+ ep->epnum = usb_endpoint_num(&urb->ep->desc);
+ ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+ ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = 0;
ep->length = 0;
ep->status = error;
@@ -340,7 +344,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
- mon_text_ctor, NULL);
+ mon_text_ctor);
if (rp->e_slab == NULL) {
rc = -ENOMEM;
goto err_slab;
@@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
mon_text_read_head_u(rp, &ptr, ep);
if (ep->type == 'E') {
mon_text_read_statset(rp, &ptr, ep);
- } else if (usb_pipeisoc(ep->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
mon_text_read_isostat(rp, &ptr, ep);
mon_text_read_isodesc(rp, &ptr, ep);
- } else if (usb_pipeint(ep->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
mon_text_read_intstat(rp, &ptr, ep);
} else {
mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
{
char udir, utype;
- udir = usb_pipein(ep->pipe) ? 'i' : 'o';
- switch (usb_pipetype(ep->pipe)) {
- case PIPE_ISOCHRONOUS: utype = 'Z'; break;
- case PIPE_INTERRUPT: utype = 'I'; break;
- case PIPE_CONTROL: utype = 'C'; break;
+ udir = (ep->is_in ? 'i' : 'o');
+ switch (ep->xfertype) {
+ case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
+ case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
+ case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
- utype, udir,
- usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+ utype, udir, ep->devnum, ep->epnum);
}
static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
{
char udir, utype;
- udir = usb_pipein(ep->pipe) ? 'i' : 'o';
- switch (usb_pipetype(ep->pipe)) {
- case PIPE_ISOCHRONOUS: utype = 'Z'; break;
- case PIPE_INTERRUPT: utype = 'I'; break;
- case PIPE_CONTROL: utype = 'C'; break;
+ udir = (ep->is_in ? 'i' : 'o');
+ switch (ep->xfertype) {
+ case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
+ case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
+ case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%d:%03u:%u",
ep->id, ep->tstamp, ep->type,
- utype, udir,
- ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+ utype, udir, ep->busnum, ep->devnum, ep->epnum);
}
static void mon_text_read_statset(struct mon_reader_text *rp,
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index f68ad6d99ad7..f5d84ff8c101 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -46,7 +46,7 @@ struct mon_reader {
void (*rnf_submit)(void *data, struct urb *urb);
void (*rnf_error)(void *data, struct urb *urb, int error);
- void (*rnf_complete)(void *data, struct urb *urb);
+ void (*rnf_complete)(void *data, struct urb *urb, int status);
};
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 43d6db696f90..99fefed77919 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
To compile this driver as a module, choose M here: the
module will be called belkin_sa.
+config USB_SERIAL_CH341
+ tristate "USB Winchiphead CH341 Single Port Serial Driver"
+ depends on USB_SERIAL
+ help
+ Say Y here if you want to use a Winchiphead CH341 single port
+ USB to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ch341.
+
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07a976eca6b7..d6fb384e52b2 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index cff6fd190a28..77bb893bf2e9 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -18,7 +18,6 @@
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
- { USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index c9fd486c1c7d..2a8e537cb046 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index e67ce25f7512..86724e885704 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -383,6 +383,10 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
}
baud = tty_get_baud_rate(port->tty);
+ if (baud == 0) {
+ dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__);
+ return;
+ }
urb_value = BELKIN_SA_BAUD(baud);
/* Clip to maximum speed */
if (urb_value == 0)
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index c08a38402b93..0b14aea8ebd5 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
return 0;
}
+static ssize_t show_port_number(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_serial_port *port = to_usb_serial_port(dev);
+
+ return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
static int usb_serial_device_probe (struct device *dev)
{
struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
goto exit;
}
+ retval = device_create_file(dev, &dev_attr_port_number);
+ if (retval)
+ goto exit;
+
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
return -ENODEV;
}
+ device_remove_file(&port->dev, &dev_attr_port_number);
+
driver = port->serial->type;
if (driver->port_remove) {
if (!try_module_get(driver->driver.owner)) {
@@ -138,7 +154,7 @@ static void free_dynids(struct usb_serial_driver *drv)
static struct driver_attribute drv_attrs[] = {
__ATTR_NULL,
};
-static inline void free_dynids(struct usb_driver *drv)
+static inline void free_dynids(struct usb_serial_driver *drv)
{
}
#endif
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644
index 000000000000..6b252ceb39a8
--- /dev/null
+++ b/drivers/usb/serial/ch341.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT 1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x4348, 0x5523) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+ unsigned baud_rate;
+ u8 dtr;
+ u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+ u16 value, u16 index)
+{
+ int r;
+ dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+ (int)request, (int)value, (int)index);
+
+ r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+ return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+ u8 request, u16 value, u16 index,
+ char *buf, unsigned bufsize)
+{
+ int r;
+ dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+ (int)request, (int)value, (int)index, buf, (int)bufsize);
+
+ r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ value, index, buf, bufsize, DEFAULT_TIMEOUT);
+ return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+ struct ch341_private *priv)
+{
+ short a, b;
+ int r;
+
+ dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+ switch (priv->baud_rate) {
+ case 2400:
+ a = 0xd901;
+ b = 0x0038;
+ break;
+ case 4800:
+ a = 0x6402;
+ b = 0x001f;
+ break;
+ case 9600:
+ a = 0xb202;
+ b = 0x0013;
+ break;
+ case 19200:
+ a = 0xd902;
+ b = 0x000d;
+ break;
+ case 38400:
+ a = 0x6403;
+ b = 0x000a;
+ break;
+ case 115200:
+ a = 0xcc03;
+ b = 0x0008;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ r = ch341_control_out(dev, 0x9a, 0x1312, a);
+ if (!r)
+ r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+ return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+ struct ch341_private *priv)
+{
+ dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+ return ch341_control_out(dev, 0xa4,
+ ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+ char *buffer;
+ int r;
+ const unsigned size = 8;
+
+ dbg("ch341_get_status()");
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+ if ( r < 0)
+ goto out;
+
+ /* Not having the datasheet for the CH341, we ignore the bytes returned
+ * from the device. Return error if the device did not respond in time.
+ */
+ r = 0;
+
+out: kfree(buffer);
+ return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+ char *buffer;
+ int r;
+ const unsigned size = 8;
+
+ dbg("ch341_configure()");
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ /* expect two bytes 0x27 0x00 */
+ r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0xa1, 0, 0);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_baudrate(dev, priv);
+ if (r < 0)
+ goto out;
+
+ /* expect two bytes 0x56 0x00 */
+ r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+ if (r < 0)
+ goto out;
+
+ /* expect 0xff 0xee */
+ r = ch341_get_status(dev);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_baudrate(dev, priv);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_handshake(dev, priv);
+ if (r < 0)
+ goto out;
+
+ /* expect 0x9f 0xee */
+ r = ch341_get_status(dev);
+
+out: kfree(buffer);
+ return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+ struct ch341_private *priv;
+ int r;
+
+ dbg("ch341_attach()");
+
+ /* private data */
+ priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->dtr = 1;
+ priv->rts = 1;
+
+ r = ch341_configure(serial->dev, priv);
+ if (r < 0)
+ goto error;
+
+ usb_set_serial_port_data(serial->port[0], priv);
+ return 0;
+
+error: kfree(priv);
+ return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+ int r;
+
+ dbg("ch341_open()");
+
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->dtr = 1;
+ priv->rts = 1;
+
+ r = ch341_configure(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = ch341_set_handshake(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = ch341_set_baudrate(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = usb_serial_generic_open(port, filp);
+
+out: return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct ch341_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty = port->tty;
+ unsigned baud_rate;
+
+ dbg("ch341_set_termios()");
+
+ if (!tty || !tty->termios)
+ return;
+
+ baud_rate = tty_get_baud_rate(tty);
+
+ switch (baud_rate) {
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 115200:
+ priv->baud_rate = baud_rate;
+ break;
+ default:
+ dbg("Rate %d not supported, using %d",
+ baud_rate, DEFAULT_BAUD_RATE);
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ }
+
+ ch341_set_baudrate(port->serial->dev, priv);
+
+ /* Unimplemented:
+ * (cflag & CSIZE) : data bits [5, 8]
+ * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+ * (cflag & CSTOPB) : stop bits [1, 2]
+ */
+}
+
+static struct usb_driver ch341_driver = {
+ .name = "ch341",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ch341-uart",
+ },
+ .id_table = id_table,
+ .usb_driver = &ch341_driver,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ch341_open,
+ .set_termios = ch341_set_termios,
+ .attach = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&ch341_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&ch341_driver);
+ if (retval)
+ usb_serial_deregister(&ch341_device);
+ return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+ usb_deregister(&ch341_driver);
+ usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index e831cb7f64fd..eb7df1835c11 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
static int debug;
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -356,7 +357,7 @@ static void cp2101_get_termios (struct usb_serial_port *port)
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
@@ -521,55 +522,40 @@ static void cp2101_set_termios (struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
cflag = port->tty->termios->c_cflag;
-
- /* Check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
- }
-
- old_cflag = old_termios->c_cflag;
- }
+ old_cflag = old_termios->c_cflag;
+ baud = tty_get_baud_rate(port->tty);
/* If the baud rate is to be updated*/
- if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
- switch (cflag & CBAUD) {
- /*
- * The baud rates which are commented out below
- * appear to be supported by the device
- * but are non-standard
- */
- case B0: baud = 0; break;
- case B600: baud = 600; break;
- case B1200: baud = 1200; break;
- case B1800: baud = 1800; break;
- case B2400: baud = 2400; break;
- case B4800: baud = 4800; break;
- /*case B7200: baud = 7200; break;*/
- case B9600: baud = 9600; break;
- /*ase B14400: baud = 14400; break;*/
- case B19200: baud = 19200; break;
- /*case B28800: baud = 28800; break;*/
- case B38400: baud = 38400; break;
- /*case B55854: baud = 55054; break;*/
- case B57600: baud = 57600; break;
- case B115200: baud = 115200; break;
- /*case B127117: baud = 127117; break;*/
- case B230400: baud = 230400; break;
- case B460800: baud = 460800; break;
- case B921600: baud = 921600; break;
- /*case B3686400: baud = 3686400; break;*/
+ if (baud != tty_termios_baud_rate(old_termios)) {
+ switch (baud) {
+ case 0:
+ case 600:
+ case 1200:
+ case 1800:
+ case 2400:
+ case 4800:
+ case 7200:
+ case 9600:
+ case 14400:
+ case 19200:
+ case 28800:
+ case 38400:
+ case 55854:
+ case 57600:
+ case 115200:
+ case 127117:
+ case 230400:
+ case 460800:
+ case 921600:
+ case 3686400:
+ break;
default:
- dev_err(&port->dev, "cp2101 driver does not "
- "support the baudrate requested\n");
+ baud = 9600;
break;
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 976f54ec26e6..dab2e66d111d 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -433,38 +433,38 @@ struct digi_port {
/* Local Function Declarations */
-static void digi_wakeup_write( struct usb_serial_port *port );
+static void digi_wakeup_write(struct usb_serial_port *port);
static void digi_wakeup_write_lock(struct work_struct *work);
-static int digi_write_oob_command( struct usb_serial_port *port,
- unsigned char *buf, int count, int interruptible );
-static int digi_write_inb_command( struct usb_serial_port *port,
- unsigned char *buf, int count, unsigned long timeout );
-static int digi_set_modem_signals( struct usb_serial_port *port,
- unsigned int modem_signals, int interruptible );
-static int digi_transmit_idle( struct usb_serial_port *port,
- unsigned long timeout );
+static int digi_write_oob_command(struct usb_serial_port *port,
+ unsigned char *buf, int count, int interruptible);
+static int digi_write_inb_command(struct usb_serial_port *port,
+ unsigned char *buf, int count, unsigned long timeout);
+static int digi_set_modem_signals(struct usb_serial_port *port,
+ unsigned int modem_signals, int interruptible);
+static int digi_transmit_idle(struct usb_serial_port *port,
+ unsigned long timeout);
static void digi_rx_throttle (struct usb_serial_port *port);
static void digi_rx_unthrottle (struct usb_serial_port *port);
-static void digi_set_termios( struct usb_serial_port *port,
- struct ktermios *old_termios );
-static void digi_break_ctl( struct usb_serial_port *port, int break_state );
-static int digi_ioctl( struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg );
-static int digi_tiocmget( struct usb_serial_port *port, struct file *file );
-static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
- unsigned int set, unsigned int clear );
-static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count );
-static void digi_write_bulk_callback( struct urb *urb );
-static int digi_write_room( struct usb_serial_port *port );
-static int digi_chars_in_buffer( struct usb_serial_port *port );
-static int digi_open( struct usb_serial_port *port, struct file *filp );
-static void digi_close( struct usb_serial_port *port, struct file *filp );
-static int digi_startup_device( struct usb_serial *serial );
-static int digi_startup( struct usb_serial *serial );
-static void digi_shutdown( struct usb_serial *serial );
-static void digi_read_bulk_callback( struct urb *urb );
-static int digi_read_inb_callback( struct urb *urb );
-static int digi_read_oob_callback( struct urb *urb );
+static void digi_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios);
+static void digi_break_ctl(struct usb_serial_port *port, int break_state);
+static int digi_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static int digi_tiocmget(struct usb_serial_port *port, struct file *file);
+static int digi_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear);
+static int digi_write(struct usb_serial_port *port, const unsigned char *buf, int count);
+static void digi_write_bulk_callback(struct urb *urb);
+static int digi_write_room(struct usb_serial_port *port);
+static int digi_chars_in_buffer(struct usb_serial_port *port);
+static int digi_open(struct usb_serial_port *port, struct file *filp);
+static void digi_close(struct usb_serial_port *port, struct file *filp);
+static int digi_startup_device(struct usb_serial *serial);
+static int digi_startup(struct usb_serial *serial);
+static void digi_shutdown(struct usb_serial *serial);
+static void digi_read_bulk_callback(struct urb *urb);
+static int digi_read_inb_callback(struct urb *urb);
+static int digi_read_oob_callback(struct urb *urb);
/* Statics */
@@ -576,9 +576,9 @@ static struct usb_serial_driver digi_acceleport_4_device = {
* with the equivalent code.
*/
-static inline long cond_wait_interruptible_timeout_irqrestore(
+static long cond_wait_interruptible_timeout_irqrestore(
wait_queue_head_t *q, long timeout,
- spinlock_t *lock, unsigned long flags )
+ spinlock_t *lock, unsigned long flags)
{
DEFINE_WAIT(wait);
@@ -600,18 +600,16 @@ static inline long cond_wait_interruptible_timeout_irqrestore(
static void digi_wakeup_write_lock(struct work_struct *work)
{
- struct digi_port *priv =
- container_of(work, struct digi_port, dp_wakeup_work);
+ struct digi_port *priv = container_of(work, struct digi_port, dp_wakeup_work);
struct usb_serial_port *port = priv->dp_port;
unsigned long flags;
-
- spin_lock_irqsave( &priv->dp_port_lock, flags );
- digi_wakeup_write( port );
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
+ digi_wakeup_write(port);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
}
-static void digi_wakeup_write( struct usb_serial_port *port )
+static void digi_wakeup_write(struct usb_serial_port *port)
{
tty_wakeup(port->tty);
}
@@ -628,8 +626,8 @@ static void digi_wakeup_write( struct usb_serial_port *port )
* returned by usb_submit_urb.
*/
-static int digi_write_oob_command( struct usb_serial_port *port,
- unsigned char *buf, int count, int interruptible )
+static int digi_write_oob_command(struct usb_serial_port *port,
+ unsigned char *buf, int count, int interruptible)
{
int ret = 0;
@@ -638,49 +636,37 @@ static int digi_write_oob_command( struct usb_serial_port *port,
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
unsigned long flags = 0;
+ dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count);
-dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count );
-
- spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
-
- while( count > 0 ) {
-
- while( oob_port->write_urb->status == -EINPROGRESS
- || oob_priv->dp_write_urb_in_use ) {
+ spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
+ while(count > 0) {
+ while(oob_port->write_urb->status == -EINPROGRESS
+ || oob_priv->dp_write_urb_in_use) {
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
- &oob_priv->dp_port_lock, flags );
- if( interruptible && signal_pending(current) ) {
- return( -EINTR );
- }
- spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
+ &oob_priv->dp_port_lock, flags);
+ if (interruptible && signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
}
/* len must be a multiple of 4, so commands are not split */
- len = min(count, oob_port->bulk_out_size );
- if( len > 4 )
+ len = min(count, oob_port->bulk_out_size);
+ if (len > 4)
len &= ~3;
-
- memcpy( oob_port->write_urb->transfer_buffer, buf, len );
+ memcpy(oob_port->write_urb->transfer_buffer, buf, len);
oob_port->write_urb->transfer_buffer_length = len;
oob_port->write_urb->dev = port->serial->dev;
-
- if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) {
+ if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) {
oob_priv->dp_write_urb_in_use = 1;
count -= len;
buf += len;
}
-
- }
-
- spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
-
- if( ret ) {
- err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__,
- ret );
}
-
- return( ret );
+ spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
+ if (ret)
+ err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);
+ return ret;
}
@@ -697,63 +683,58 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co
* error returned by digi_write.
*/
-static int digi_write_inb_command( struct usb_serial_port *port,
- unsigned char *buf, int count, unsigned long timeout )
+static int digi_write_inb_command(struct usb_serial_port *port,
+ unsigned char *buf, int count, unsigned long timeout)
{
-
int ret = 0;
int len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long flags = 0;
+ dbg("digi_write_inb_command: TOP: port=%d, count=%d",
+ priv->dp_port_num, count);
-dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num,
-count );
-
- if( timeout )
+ if (timeout)
timeout += jiffies;
else
timeout = ULONG_MAX;
- spin_lock_irqsave( &priv->dp_port_lock, flags );
-
- while( count > 0 && ret == 0 ) {
-
- while( (port->write_urb->status == -EINPROGRESS
- || priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) {
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
+ while(count > 0 && ret == 0) {
+ while((port->write_urb->status == -EINPROGRESS
+ || priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) {
cond_wait_interruptible_timeout_irqrestore(
&port->write_wait, DIGI_RETRY_TIMEOUT,
- &priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
- return( -EINTR );
- }
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ &priv->dp_port_lock, flags);
+ if (signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
}
/* len must be a multiple of 4 and small enough to */
/* guarantee the write will send buffered data first, */
/* so commands are in order with data and not split */
- len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len );
- if( len > 4 )
+ len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
+ if (len > 4)
len &= ~3;
/* write any buffered data first */
- if( priv->dp_out_buf_len > 0 ) {
+ if (priv->dp_out_buf_len > 0) {
data[0] = DIGI_CMD_SEND_DATA;
data[1] = priv->dp_out_buf_len;
- memcpy( data+2, priv->dp_out_buf,
- priv->dp_out_buf_len );
- memcpy( data+2+priv->dp_out_buf_len, buf, len );
+ memcpy(data + 2, priv->dp_out_buf,
+ priv->dp_out_buf_len);
+ memcpy(data + 2 + priv->dp_out_buf_len, buf, len);
port->write_urb->transfer_buffer_length
- = priv->dp_out_buf_len+2+len;
+ = priv->dp_out_buf_len + 2 + len;
} else {
- memcpy( data, buf, len );
+ memcpy(data, buf, len);
port->write_urb->transfer_buffer_length = len;
}
port->write_urb->dev = port->serial->dev;
- if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
+ if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {
priv->dp_write_urb_in_use = 1;
priv->dp_out_buf_len = 0;
count -= len;
@@ -761,16 +742,12 @@ count );
}
}
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
- if( ret ) {
- err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
- ret, priv->dp_port_num );
- }
-
- return( ret );
-
+ if (ret)
+ err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ __FUNCTION__, ret, priv->dp_port_num);
+ return ret;
}
@@ -784,8 +761,8 @@ count );
* returned by usb_submit_urb.
*/
-static int digi_set_modem_signals( struct usb_serial_port *port,
- unsigned int modem_signals, int interruptible )
+static int digi_set_modem_signals(struct usb_serial_port *port,
+ unsigned int modem_signals, int interruptible)
{
int ret;
@@ -796,60 +773,47 @@ static int digi_set_modem_signals( struct usb_serial_port *port,
unsigned long flags = 0;
-dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
-port_priv->dp_port_num, modem_signals );
+ dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
+ port_priv->dp_port_num, modem_signals);
- spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
- spin_lock( &port_priv->dp_port_lock );
+ spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
+ spin_lock(&port_priv->dp_port_lock);
- while( oob_port->write_urb->status == -EINPROGRESS
- || oob_priv->dp_write_urb_in_use ) {
- spin_unlock( &port_priv->dp_port_lock );
+ while(oob_port->write_urb->status == -EINPROGRESS || oob_priv->dp_write_urb_in_use) {
+ spin_unlock(&port_priv->dp_port_lock);
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
- &oob_priv->dp_port_lock, flags );
- if( interruptible && signal_pending(current) ) {
- return( -EINTR );
- }
- spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
- spin_lock( &port_priv->dp_port_lock );
+ &oob_priv->dp_port_lock, flags);
+ if (interruptible && signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
+ spin_lock(&port_priv->dp_port_lock);
}
-
data[0] = DIGI_CMD_SET_DTR_SIGNAL;
data[1] = port_priv->dp_port_num;
- data[2] = (modem_signals&TIOCM_DTR) ?
- DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;
+ data[2] = (modem_signals&TIOCM_DTR) ? DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;
data[3] = 0;
-
data[4] = DIGI_CMD_SET_RTS_SIGNAL;
data[5] = port_priv->dp_port_num;
- data[6] = (modem_signals&TIOCM_RTS) ?
- DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;
+ data[6] = (modem_signals&TIOCM_RTS) ? DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;
data[7] = 0;
oob_port->write_urb->transfer_buffer_length = 8;
oob_port->write_urb->dev = port->serial->dev;
- if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) {
+ if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) {
oob_priv->dp_write_urb_in_use = 1;
port_priv->dp_modem_signals =
(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
| (modem_signals&(TIOCM_DTR|TIOCM_RTS));
}
-
- spin_unlock( &port_priv->dp_port_lock );
- spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
-
- if( ret ) {
- err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__,
- ret );
- }
-
- return( ret );
-
+ spin_unlock(&port_priv->dp_port_lock);
+ spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
+ if (ret)
+ err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);
+ return ret;
}
-
/*
* Digi Transmit Idle
*
@@ -862,203 +826,182 @@ port_priv->dp_port_num, modem_signals );
* port at a time, so its ok.
*/
-static int digi_transmit_idle( struct usb_serial_port *port,
- unsigned long timeout )
+static int digi_transmit_idle(struct usb_serial_port *port,
+ unsigned long timeout)
{
-
int ret;
unsigned char buf[2];
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned long flags = 0;
-
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_transmit_idle = 0;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
buf[0] = DIGI_CMD_TRANSMIT_IDLE;
buf[1] = 0;
timeout += jiffies;
- if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 )
- return( ret );
+ if ((ret = digi_write_inb_command(port, buf, 2, timeout - jiffies)) != 0)
+ return ret;
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
- while( time_before(jiffies, timeout) && !priv->dp_transmit_idle ) {
+ while(time_before(jiffies, timeout) && !priv->dp_transmit_idle) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,
- &priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
- return( -EINTR );
- }
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ &priv->dp_port_lock, flags);
+ if (signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
}
-
priv->dp_transmit_idle = 0;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
- return( 0 );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ return 0;
}
-static void digi_rx_throttle( struct usb_serial_port *port )
+static void digi_rx_throttle(struct usb_serial_port *port)
{
-
unsigned long flags;
struct digi_port *priv = usb_get_serial_port_data(port);
-dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
+ dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num);
/* stop receiving characters by not resubmitting the read urb */
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_throttled = 1;
priv->dp_throttle_restart = 0;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
}
-static void digi_rx_unthrottle( struct usb_serial_port *port )
+static void digi_rx_unthrottle(struct usb_serial_port *port)
{
-
int ret = 0;
unsigned long flags;
struct digi_port *priv = usb_get_serial_port_data(port);
-dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
+ dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num);
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
/* turn throttle off */
priv->dp_throttled = 0;
priv->dp_throttle_restart = 0;
/* restart read chain */
- if( priv->dp_throttle_restart ) {
+ if (priv->dp_throttle_restart) {
port->read_urb->dev = port->serial->dev;
- ret = usb_submit_urb( port->read_urb, GFP_ATOMIC );
+ ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
}
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
- if( ret ) {
- err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
- ret, priv->dp_port_num );
- }
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ if (ret)
+ err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ __FUNCTION__, ret, priv->dp_port_num);
}
-static void digi_set_termios( struct usb_serial_port *port,
- struct ktermios *old_termios )
+static void digi_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios)
{
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned int iflag = port->tty->termios->c_iflag;
- unsigned int cflag = port->tty->termios->c_cflag;
+ struct tty_struct *tty = port->tty;
+ unsigned int iflag = tty->termios->c_iflag;
+ unsigned int cflag = tty->termios->c_cflag;
unsigned int old_iflag = old_termios->c_iflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned char buf[32];
unsigned int modem_signals;
int arg,ret;
int i = 0;
+ speed_t baud;
-
-dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag );
+ dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag);
/* set baud rate */
- if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
-
+ if ((baud = tty_get_baud_rate(tty)) != tty_termios_baud_rate(old_termios)) {
arg = -1;
/* reassert DTR and (maybe) RTS on transition from B0 */
- if( (old_cflag&CBAUD) == B0 ) {
+ if ((old_cflag&CBAUD) == B0) {
/* don't set RTS if using hardware flow control */
/* and throttling input */
modem_signals = TIOCM_DTR;
- if( !(port->tty->termios->c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &port->tty->flags) ) {
+ if (!(tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags))
modem_signals |= TIOCM_RTS;
- }
- digi_set_modem_signals( port, modem_signals, 1 );
+ digi_set_modem_signals(port, modem_signals, 1);
}
-
- switch( (cflag&CBAUD) ) {
+ switch (baud) {
/* drop DTR and RTS on transition to B0 */
- case B0: digi_set_modem_signals( port, 0, 1 ); break;
- case B50: arg = DIGI_BAUD_50; break;
- case B75: arg = DIGI_BAUD_75; break;
- case B110: arg = DIGI_BAUD_110; break;
- case B150: arg = DIGI_BAUD_150; break;
- case B200: arg = DIGI_BAUD_200; break;
- case B300: arg = DIGI_BAUD_300; break;
- case B600: arg = DIGI_BAUD_600; break;
- case B1200: arg = DIGI_BAUD_1200; break;
- case B1800: arg = DIGI_BAUD_1800; break;
- case B2400: arg = DIGI_BAUD_2400; break;
- case B4800: arg = DIGI_BAUD_4800; break;
- case B9600: arg = DIGI_BAUD_9600; break;
- case B19200: arg = DIGI_BAUD_19200; break;
- case B38400: arg = DIGI_BAUD_38400; break;
- case B57600: arg = DIGI_BAUD_57600; break;
- case B115200: arg = DIGI_BAUD_115200; break;
- case B230400: arg = DIGI_BAUD_230400; break;
- case B460800: arg = DIGI_BAUD_460800; break;
- default:
- dbg( "digi_set_termios: can't handle baud rate 0x%x",
- (cflag&CBAUD) );
- break;
+ case 0: digi_set_modem_signals(port, 0, 1); break;
+ case 50: arg = DIGI_BAUD_50; break;
+ case 75: arg = DIGI_BAUD_75; break;
+ case 110: arg = DIGI_BAUD_110; break;
+ case 150: arg = DIGI_BAUD_150; break;
+ case 200: arg = DIGI_BAUD_200; break;
+ case 300: arg = DIGI_BAUD_300; break;
+ case 600: arg = DIGI_BAUD_600; break;
+ case 1200: arg = DIGI_BAUD_1200; break;
+ case 1800: arg = DIGI_BAUD_1800; break;
+ case 2400: arg = DIGI_BAUD_2400; break;
+ case 4800: arg = DIGI_BAUD_4800; break;
+ case 9600: arg = DIGI_BAUD_9600; break;
+ case 19200: arg = DIGI_BAUD_19200; break;
+ case 38400: arg = DIGI_BAUD_38400; break;
+ case 57600: arg = DIGI_BAUD_57600; break;
+ case 115200: arg = DIGI_BAUD_115200; break;
+ case 230400: arg = DIGI_BAUD_230400; break;
+ case 460800: arg = DIGI_BAUD_460800; break;
+ default:
+ arg = DIGI_BAUD_9600;
+ baud = 9600;
+ break;
}
-
- if( arg != -1 ) {
+ if (arg != -1) {
buf[i++] = DIGI_CMD_SET_BAUD_RATE;
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
buf[i++] = 0;
}
-
}
-
/* set parity */
- if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
-
- if( (cflag&PARENB) ) {
- if( (cflag&PARODD) )
+ if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
+ if (cflag&PARENB) {
+ if (cflag&PARODD)
arg = DIGI_PARITY_ODD;
else
arg = DIGI_PARITY_EVEN;
} else {
arg = DIGI_PARITY_NONE;
}
-
buf[i++] = DIGI_CMD_SET_PARITY;
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
buf[i++] = 0;
-
}
-
/* set word size */
- if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
-
+ if ((cflag&CSIZE) != (old_cflag&CSIZE)) {
arg = -1;
-
- switch( (cflag&CSIZE) ) {
+ switch (cflag&CSIZE) {
case CS5: arg = DIGI_WORD_SIZE_5; break;
case CS6: arg = DIGI_WORD_SIZE_6; break;
case CS7: arg = DIGI_WORD_SIZE_7; break;
case CS8: arg = DIGI_WORD_SIZE_8; break;
default:
- dbg( "digi_set_termios: can't handle word size %d",
- (cflag&CSIZE) );
+ dbg("digi_set_termios: can't handle word size %d",
+ (cflag&CSIZE));
break;
}
- if( arg != -1 ) {
+ if (arg != -1) {
buf[i++] = DIGI_CMD_SET_WORD_SIZE;
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
@@ -1068,9 +1011,9 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
}
/* set stop bits */
- if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+ if ((cflag&CSTOPB) != (old_cflag&CSTOPB)) {
- if( (cflag&CSTOPB) )
+ if ((cflag&CSTOPB))
arg = DIGI_STOP_BITS_2;
else
arg = DIGI_STOP_BITS_1;
@@ -1083,18 +1026,15 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
}
/* set input flow control */
- if( (iflag&IXOFF) != (old_iflag&IXOFF)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
-
+ if ((iflag&IXOFF) != (old_iflag&IXOFF)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) {
arg = 0;
-
- if( (iflag&IXOFF) )
+ if (iflag&IXOFF)
arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
else
arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
- if( (cflag&CRTSCTS) ) {
-
+ if (cflag&CRTSCTS) {
arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
/* On USB-4 it is necessary to assert RTS prior */
@@ -1107,43 +1047,37 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
} else {
arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS;
}
-
buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
buf[i++] = 0;
-
}
/* set output flow control */
- if( (iflag&IXON) != (old_iflag&IXON)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
-
+ if ((iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) {
arg = 0;
-
- if( (iflag&IXON) )
+ if (iflag&IXON)
arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
else
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
- if( (cflag&CRTSCTS) ) {
+ if (cflag&CRTSCTS) {
arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
} else {
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
- port->tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
}
buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
buf[i++] = 0;
-
}
/* set receive enable/disable */
- if( (cflag&CREAD) != (old_cflag&CREAD) ) {
-
- if( (cflag&CREAD) )
+ if ((cflag&CREAD) != (old_cflag&CREAD)) {
+ if (cflag&CREAD)
arg = DIGI_ENABLE;
else
arg = DIGI_DISABLE;
@@ -1152,32 +1086,26 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
buf[i++] = 0;
-
}
-
- if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 )
- dbg( "digi_set_termios: write oob failed, ret=%d", ret );
+ if ((ret = digi_write_oob_command(port, buf, i, 1)) != 0)
+ dbg("digi_set_termios: write oob failed, ret=%d", ret);
}
-static void digi_break_ctl( struct usb_serial_port *port, int break_state )
+static void digi_break_ctl(struct usb_serial_port *port, int break_state)
{
-
unsigned char buf[4];
-
buf[0] = DIGI_CMD_BREAK_CONTROL;
buf[1] = 2; /* length */
buf[2] = break_state ? 1 : 0;
buf[3] = 0; /* pad */
-
- digi_write_inb_command( port, buf, 4, 0 );
-
+ digi_write_inb_command(port, buf, 4, 0);
}
-static int digi_tiocmget( struct usb_serial_port *port, struct file *file )
+static int digi_tiocmget(struct usb_serial_port *port, struct file *file)
{
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned int val;
@@ -1185,15 +1113,15 @@ static int digi_tiocmget( struct usb_serial_port *port, struct file *file )
dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num);
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
val = priv->dp_modem_signals;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return val;
}
-static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
- unsigned int set, unsigned int clear )
+static int digi_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
{
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned int val;
@@ -1201,41 +1129,34 @@ static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num);
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
val = (priv->dp_modem_signals & ~clear) | set;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return digi_set_modem_signals( port, val, 1 );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ return digi_set_modem_signals(port, val, 1);
}
-static int digi_ioctl( struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg )
+static int digi_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
-
struct digi_port *priv = usb_get_serial_port_data(port);
-
-dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd );
+ dbg("digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd);
switch (cmd) {
-
case TIOCMIWAIT:
/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
/* TODO */
- return( 0 );
-
+ return 0;
case TIOCGICOUNT:
/* return count of modemline transitions */
/* TODO */
return 0;
-
}
-
- return( -ENOIOCTLCMD );
+ return -ENOIOCTLCMD;
}
-
-static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count )
+static int digi_write(struct usb_serial_port *port, const unsigned char *buf, int count)
{
int ret,data_len,new_len;
@@ -1243,35 +1164,29 @@ static int digi_write( struct usb_serial_port *port, const unsigned char *buf, i
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long flags = 0;
-
-dbg( "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld",
-priv->dp_port_num, count, in_interrupt() );
+ dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld",
+ priv->dp_port_num, count, in_interrupt());
/* copy user data (which can sleep) before getting spin lock */
- count = min( count, port->bulk_out_size-2 );
- count = min( 64, count);
+ count = min(count, port->bulk_out_size-2);
+ count = min(64, count);
/* be sure only one write proceeds at a time */
/* there are races on the port private buffer */
/* and races to check write_urb->status */
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
/* wait for urb status clear to submit another urb */
- if( port->write_urb->status == -EINPROGRESS
- || priv->dp_write_urb_in_use ) {
-
+ if (port->write_urb->status == -EINPROGRESS || priv->dp_write_urb_in_use) {
/* buffer data if count is 1 (probably put_char) if possible */
- if( count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE ) {
+ if (count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE) {
priv->dp_out_buf[priv->dp_out_buf_len++] = *buf;
new_len = 1;
} else {
new_len = 0;
}
-
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
- return( new_len );
-
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ return new_len;
}
/* allow space for any buffered data and for new data, up to */
@@ -1279,9 +1194,9 @@ priv->dp_port_num, count, in_interrupt() );
new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
data_len = new_len + priv->dp_out_buf_len;
- if( data_len == 0 ) {
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( 0 );
+ if (data_len == 0) {
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ return 0;
}
port->write_urb->transfer_buffer_length = data_len+2;
@@ -1291,32 +1206,29 @@ priv->dp_port_num, count, in_interrupt() );
*data++ = data_len;
/* copy in buffered data first */
- memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len );
+ memcpy(data, priv->dp_out_buf, priv->dp_out_buf_len);
data += priv->dp_out_buf_len;
/* copy in new data */
- memcpy( data, buf, new_len );
+ memcpy(data, buf, new_len);
- if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
+ if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {
priv->dp_write_urb_in_use = 1;
ret = new_len;
priv->dp_out_buf_len = 0;
}
/* return length of new data written, or error */
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- if( ret < 0 ) {
- err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
- ret, priv->dp_port_num );
- }
-
-dbg( "digi_write: returning %d", ret );
- return( ret );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ if (ret < 0)
+ err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ __FUNCTION__, ret, priv->dp_port_num);
+ dbg("digi_write: returning %d", ret);
+ return ret;
}
-
-static void digi_write_bulk_callback( struct urb *urb )
+static void digi_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1326,153 +1238,136 @@ static void digi_write_bulk_callback( struct urb *urb )
int ret = 0;
int status = urb->status;
-
- dbg("digi_write_bulk_callback: TOP, urb status=%d", status);
+ dbg("digi_write_bulk_callback: TOP, urb->status=%d", status);
/* port and serial sanity check */
- if( port == NULL || (priv=usb_get_serial_port_data(port)) == NULL ) {
+ if (port == NULL || (priv=usb_get_serial_port_data(port)) == NULL) {
err("%s: port or port->private is NULL, status=%d",
__FUNCTION__, status);
return;
}
serial = port->serial;
- if( serial == NULL || (serial_priv=usb_get_serial_data(serial)) == NULL ) {
+ if (serial == NULL || (serial_priv=usb_get_serial_data(serial)) == NULL) {
err("%s: serial or serial->private is NULL, status=%d",
__FUNCTION__, status);
return;
}
/* handle oob callback */
- if( priv->dp_port_num == serial_priv->ds_oob_port_num ) {
- dbg( "digi_write_bulk_callback: oob callback" );
- spin_lock( &priv->dp_port_lock );
+ if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
+ dbg("digi_write_bulk_callback: oob callback");
+ spin_lock(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
- wake_up_interruptible( &port->write_wait );
- spin_unlock( &priv->dp_port_lock );
+ wake_up_interruptible(&port->write_wait);
+ spin_unlock(&priv->dp_port_lock);
return;
}
/* try to send any buffered data on this port, if it is open */
- spin_lock( &priv->dp_port_lock );
+ spin_lock(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
- if( port->open_count && port->write_urb->status != -EINPROGRESS
- && priv->dp_out_buf_len > 0 ) {
-
+ if (port->open_count && port->write_urb->status != -EINPROGRESS
+ && priv->dp_out_buf_len > 0) {
*((unsigned char *)(port->write_urb->transfer_buffer))
= (unsigned char)DIGI_CMD_SEND_DATA;
*((unsigned char *)(port->write_urb->transfer_buffer)+1)
= (unsigned char)priv->dp_out_buf_len;
-
- port->write_urb->transfer_buffer_length
- = priv->dp_out_buf_len+2;
+ port->write_urb->transfer_buffer_length = priv->dp_out_buf_len+2;
port->write_urb->dev = serial->dev;
-
- memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,
- priv->dp_out_buf_len );
-
- if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
+ memcpy(port->write_urb->transfer_buffer+2, priv->dp_out_buf,
+ priv->dp_out_buf_len);
+ if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {
priv->dp_write_urb_in_use = 1;
priv->dp_out_buf_len = 0;
}
-
}
-
/* wake up processes sleeping on writes immediately */
- digi_wakeup_write( port );
-
+ digi_wakeup_write(port);
/* also queue up a wakeup at scheduler time, in case we */
/* lost the race in write_chan(). */
schedule_work(&priv->dp_wakeup_work);
- spin_unlock( &priv->dp_port_lock );
-
- if( ret ) {
- err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
- ret, priv->dp_port_num );
- }
-
+ spin_unlock(&priv->dp_port_lock);
+ if (ret)
+ err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ __FUNCTION__, ret, priv->dp_port_num);
}
-
-static int digi_write_room( struct usb_serial_port *port )
+static int digi_write_room(struct usb_serial_port *port)
{
int room;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned long flags = 0;
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
- spin_lock_irqsave( &priv->dp_port_lock, flags );
-
- if( port->write_urb->status == -EINPROGRESS
- || priv->dp_write_urb_in_use )
+ if (port->write_urb->status == -EINPROGRESS || priv->dp_write_urb_in_use)
room = 0;
else
room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room );
- return( room );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room);
+ return room;
}
-
-static int digi_chars_in_buffer( struct usb_serial_port *port )
+static int digi_chars_in_buffer(struct usb_serial_port *port)
{
struct digi_port *priv = usb_get_serial_port_data(port);
- if( port->write_urb->status == -EINPROGRESS
- || priv->dp_write_urb_in_use ) {
-dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );
- /* return( port->bulk_out_size - 2 ); */
- return( 256 );
+ if (port->write_urb->status == -EINPROGRESS
+ || priv->dp_write_urb_in_use) {
+ dbg("digi_chars_in_buffer: port=%d, chars=%d",
+ priv->dp_port_num, port->bulk_out_size - 2);
+ /* return(port->bulk_out_size - 2); */
+ return 256;
} else {
-dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len );
- return( priv->dp_out_buf_len );
+ dbg("digi_chars_in_buffer: port=%d, chars=%d",
+ priv->dp_port_num, priv->dp_out_buf_len);
+ return priv->dp_out_buf_len;
}
}
-static int digi_open( struct usb_serial_port *port, struct file *filp )
+static int digi_open(struct usb_serial_port *port, struct file *filp)
{
-
int ret;
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
unsigned long flags = 0;
-
-dbg( "digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
+ dbg("digi_open: TOP: port=%d, open_count=%d",
+ priv->dp_port_num, port->open_count);
/* be sure the device is started up */
- if( digi_startup_device( port->serial ) != 0 )
- return( -ENXIO );
+ if (digi_startup_device(port->serial) != 0)
+ return -ENXIO;
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
/* don't wait on a close in progress for non-blocking opens */
- if( priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( -EAGAIN );
+ if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ return -EAGAIN;
}
/* wait for a close in progress to finish */
- while( priv->dp_in_close ) {
+ while(priv->dp_in_close) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
- &priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
- return( -EINTR );
- }
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ &priv->dp_port_lock, flags);
+ if (signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
}
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
/* read modem signals automatically whenever they change */
buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
@@ -1486,23 +1381,22 @@ dbg( "digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_cou
buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
buf[7] = 0;
- if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 )
- dbg( "digi_open: write oob failed, ret=%d", ret );
+ if ((ret = digi_write_oob_command(port, buf, 8, 1)) != 0)
+ dbg("digi_open: write oob failed, ret=%d", ret);
/* set termios settings */
not_termios.c_cflag = ~port->tty->termios->c_cflag;
not_termios.c_iflag = ~port->tty->termios->c_iflag;
- digi_set_termios( port, &not_termios );
+ digi_set_termios(port, &not_termios);
/* set DTR and RTS */
- digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 );
-
- return( 0 );
+ digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1);
+ return 0;
}
-static void digi_close( struct usb_serial_port *port, struct file *filp )
+static void digi_close(struct usb_serial_port *port, struct file *filp)
{
DEFINE_WAIT(wait);
int ret;
@@ -1511,40 +1405,37 @@ static void digi_close( struct usb_serial_port *port, struct file *filp )
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned long flags = 0;
-
-dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
-
+ dbg("digi_close: TOP: port=%d, open_count=%d",
+ priv->dp_port_num, port->open_count);
/* if disconnected, just clear flags */
if (!usb_get_intfdata(port->serial->interface))
goto exit;
/* do cleanup only after final close on this port */
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_in_close = 1;
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
/* tell line discipline to process only XON/XOFF */
tty->closing = 1;
/* wait for output to drain */
- if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
- tty_wait_until_sent( tty, DIGI_CLOSE_TIMEOUT );
- }
+ if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
+ tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */
- if( tty->driver->flush_buffer )
- tty->driver->flush_buffer( tty );
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
if (port->serial->dev) {
/* wait for transmit idle */
- if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
- digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT );
+ if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
+ digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
}
-
/* drop DTR and RTS */
- digi_set_modem_signals( port, 0, 0 );
+ digi_set_modem_signals(port, 0, 0);
/* disable input flow control */
buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
@@ -1576,8 +1467,8 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
buf[19] = 0;
- if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
- dbg( "digi_close: write oob failed, ret=%d", ret );
+ if ((ret = digi_write_oob_command(port, buf, 20, 0)) != 0)
+ dbg("digi_close: write oob failed, ret=%d", ret);
/* wait for final commands on oob port to complete */
prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE);
@@ -1587,17 +1478,14 @@ dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_co
/* shutdown any outstanding bulk writes */
usb_kill_urb(port->write_urb);
}
-
tty->closing = 0;
-
exit:
- spin_lock_irqsave( &priv->dp_port_lock, flags );
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
- wake_up_interruptible( &priv->dp_close_wait );
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-dbg( "digi_close: done" );
+ wake_up_interruptible(&priv->dp_close_wait);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ dbg("digi_close: done");
}
@@ -1608,155 +1496,136 @@ dbg( "digi_close: done" );
* urbs initialized. Returns 0 if successful, non-zero error otherwise.
*/
-static int digi_startup_device( struct usb_serial *serial )
+static int digi_startup_device(struct usb_serial *serial)
{
-
int i,ret = 0;
struct digi_serial *serial_priv = usb_get_serial_data(serial);
struct usb_serial_port *port;
-
/* be sure this happens exactly once */
- spin_lock( &serial_priv->ds_serial_lock );
- if( serial_priv->ds_device_started ) {
- spin_unlock( &serial_priv->ds_serial_lock );
- return( 0 );
+ spin_lock(&serial_priv->ds_serial_lock);
+ if (serial_priv->ds_device_started) {
+ spin_unlock(&serial_priv->ds_serial_lock);
+ return 0;
}
serial_priv->ds_device_started = 1;
- spin_unlock( &serial_priv->ds_serial_lock );
+ spin_unlock(&serial_priv->ds_serial_lock);
/* start reading from each bulk in endpoint for the device */
/* set USB_DISABLE_SPD flag for write bulk urbs */
- for( i=0; i<serial->type->num_ports+1; i++ ) {
-
+ for (i = 0; i < serial->type->num_ports + 1; i++) {
port = serial->port[i];
-
port->write_urb->dev = port->serial->dev;
-
- if( (ret=usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0 ) {
- err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
- ret, i );
+ if ((ret = usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0) {
+ err("%s: usb_submit_urb failed, ret=%d, port=%d",
+ __FUNCTION__, ret, i);
break;
}
-
}
-
- return( ret );
-
+ return ret;
}
-static int digi_startup( struct usb_serial *serial )
+static int digi_startup(struct usb_serial *serial)
{
int i;
struct digi_port *priv;
struct digi_serial *serial_priv;
-
-dbg( "digi_startup: TOP" );
+ dbg("digi_startup: TOP");
/* allocate the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
- for( i=0; i<serial->type->num_ports+1; i++ ) {
-
+ for(i = 0; i < serial->type->num_ports + 1; i++) {
/* allocate port private structure */
- priv = kmalloc( sizeof(struct digi_port),
- GFP_KERNEL );
- if( priv == (struct digi_port *)0 ) {
- while( --i >= 0 )
- kfree( usb_get_serial_port_data(serial->port[i]) );
- return( 1 ); /* error */
+ priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL);
+ if (priv == NULL) {
+ while (--i >= 0)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ return 1; /* error */
}
/* initialize port private structure */
- spin_lock_init( &priv->dp_port_lock );
+ spin_lock_init(&priv->dp_port_lock);
priv->dp_port_num = i;
priv->dp_out_buf_len = 0;
priv->dp_write_urb_in_use = 0;
priv->dp_modem_signals = 0;
- init_waitqueue_head( &priv->dp_modem_change_wait );
+ init_waitqueue_head(&priv->dp_modem_change_wait);
priv->dp_transmit_idle = 0;
- init_waitqueue_head( &priv->dp_transmit_idle_wait );
+ init_waitqueue_head(&priv->dp_transmit_idle_wait);
priv->dp_throttled = 0;
priv->dp_throttle_restart = 0;
- init_waitqueue_head( &priv->dp_flush_wait );
+ init_waitqueue_head(&priv->dp_flush_wait);
priv->dp_in_close = 0;
- init_waitqueue_head( &priv->dp_close_wait );
+ init_waitqueue_head(&priv->dp_close_wait);
INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
priv->dp_port = serial->port[i];
-
/* initialize write wait queue for this port */
- init_waitqueue_head( &serial->port[i]->write_wait );
+ init_waitqueue_head(&serial->port[i]->write_wait);
usb_set_serial_port_data(serial->port[i], priv);
}
/* allocate serial private structure */
- serial_priv = kmalloc( sizeof(struct digi_serial),
- GFP_KERNEL );
- if( serial_priv == (struct digi_serial *)0 ) {
- for( i=0; i<serial->type->num_ports+1; i++ )
- kfree( usb_get_serial_port_data(serial->port[i]) );
- return( 1 ); /* error */
+ serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL);
+ if (serial_priv == NULL) {
+ for (i = 0; i < serial->type->num_ports + 1; i++)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ return 1; /* error */
}
/* initialize serial private structure */
- spin_lock_init( &serial_priv->ds_serial_lock );
+ spin_lock_init(&serial_priv->ds_serial_lock);
serial_priv->ds_oob_port_num = serial->type->num_ports;
serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];
serial_priv->ds_device_started = 0;
usb_set_serial_data(serial, serial_priv);
- return( 0 );
-
+ return 0;
}
-static void digi_shutdown( struct usb_serial *serial )
+static void digi_shutdown(struct usb_serial *serial)
{
-
int i;
-
-
-dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() );
+ dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt());
/* stop reads and writes on all ports */
- for( i=0; i<serial->type->num_ports+1; i++ ) {
+ for (i = 0; i < serial->type->num_ports + 1; i++) {
usb_kill_urb(serial->port[i]->read_urb);
usb_kill_urb(serial->port[i]->write_urb);
}
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
- for( i=0; i<serial->type->num_ports+1; i++ )
- kfree( usb_get_serial_port_data(serial->port[i]) );
- kfree( usb_get_serial_data(serial) );
+ for(i = 0; i < serial->type->num_ports + 1; i++)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ kfree(usb_get_serial_data(serial));
}
-static void digi_read_bulk_callback( struct urb *urb )
+static void digi_read_bulk_callback(struct urb *urb)
{
-
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct digi_port *priv;
struct digi_serial *serial_priv;
int ret;
int status = urb->status;
-
-dbg( "digi_read_bulk_callback: TOP" );
+ dbg("digi_read_bulk_callback: TOP");
/* port sanity check, do not resubmit if port is not valid */
- if( port == NULL || (priv=usb_get_serial_port_data(port)) == NULL ) {
+ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
err("%s: port or port->private is NULL, status=%d",
__FUNCTION__, status);
return;
}
- if( port->serial == NULL
- || (serial_priv=usb_get_serial_data(port->serial)) == NULL ) {
+ if (port->serial == NULL ||
+ (serial_priv=usb_get_serial_data(port->serial)) == NULL) {
err("%s: serial is bad or serial->private is NULL, status=%d",
- __FUNCTION__, status);
+ __FUNCTION__, status);
return;
}
@@ -1768,24 +1637,23 @@ dbg( "digi_read_bulk_callback: TOP" );
}
/* handle oob or inb callback, do not resubmit if error */
- if( priv->dp_port_num == serial_priv->ds_oob_port_num ) {
- if( digi_read_oob_callback( urb ) != 0 )
+ if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
+ if (digi_read_oob_callback(urb) != 0)
return;
} else {
- if( digi_read_inb_callback( urb ) != 0 )
+ if (digi_read_inb_callback(urb) != 0)
return;
}
/* continue read */
urb->dev = port->serial->dev;
- if( (ret=usb_submit_urb(urb, GFP_ATOMIC)) != 0 ) {
- err("%s: failed resubmitting urb, ret=%d, port=%d", __FUNCTION__,
- ret, priv->dp_port_num );
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+ err("%s: failed resubmitting urb, ret=%d, port=%d",
+ __FUNCTION__, ret, priv->dp_port_num);
}
}
-
/*
* Digi Read INB Callback
*
@@ -1796,7 +1664,7 @@ dbg( "digi_read_bulk_callback: TOP" );
* throttled, and -1 if the sanity checks failed.
*/
-static int digi_read_inb_callback( struct urb *urb )
+static int digi_read_inb_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1812,72 +1680,67 @@ static int digi_read_inb_callback( struct urb *urb )
/* do not process callbacks on closed ports */
/* but do continue the read chain */
- if( port->open_count == 0 )
- return( 0 );
+ if (port->open_count == 0)
+ return 0;
/* short/multiple packet check */
- if( urb->actual_length != len + 2 ) {
- err("%s: INCOMPLETE OR MULTIPLE PACKET, urb status=%d, "
+ if (urb->actual_length != len + 2) {
+ err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, "
"port=%d, opcode=%d, len=%d, actual_length=%d, "
- "port_status=%d", __FUNCTION__, status, priv->dp_port_num,
+ "status=%d", __FUNCTION__, status, priv->dp_port_num,
opcode, len, urb->actual_length, port_status);
- return( -1 );
+ return -1;
}
- spin_lock( &priv->dp_port_lock );
+ spin_lock(&priv->dp_port_lock);
/* check for throttle; if set, do not resubmit read urb */
/* indicate the read chain needs to be restarted on unthrottle */
throttled = priv->dp_throttled;
- if( throttled )
+ if (throttled)
priv->dp_throttle_restart = 1;
/* receive data */
- if( opcode == DIGI_CMD_RECEIVE_DATA ) {
-
+ if (opcode == DIGI_CMD_RECEIVE_DATA) {
/* get flag from port_status */
flag = 0;
/* overrun is special, not associated with a char */
- if (port_status & DIGI_OVERRUN_ERROR) {
- tty_insert_flip_char( tty, 0, TTY_OVERRUN );
- }
+ if (port_status & DIGI_OVERRUN_ERROR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
- if (port_status & DIGI_BREAK_ERROR) {
+ if (port_status & DIGI_BREAK_ERROR)
flag = TTY_BREAK;
- } else if (port_status & DIGI_PARITY_ERROR) {
+ else if (port_status & DIGI_PARITY_ERROR)
flag = TTY_PARITY;
- } else if (port_status & DIGI_FRAMING_ERROR) {
+ else if (port_status & DIGI_FRAMING_ERROR)
flag = TTY_FRAME;
- }
/* data length is len-1 (one byte of len is port_status) */
--len;
len = tty_buffer_request_room(tty, len);
- if( len > 0 ) {
+ if (len > 0) {
/* Hot path */
- if(flag == TTY_NORMAL)
+ if (flag == TTY_NORMAL)
tty_insert_flip_string(tty, data, len);
else {
for(i = 0; i < len; i++)
tty_insert_flip_char(tty, data[i], flag);
}
- tty_flip_buffer_push( tty );
+ tty_flip_buffer_push(tty);
}
}
+ spin_unlock(&priv->dp_port_lock);
- spin_unlock( &priv->dp_port_lock );
-
- if( opcode == DIGI_CMD_RECEIVE_DISABLE ) {
- dbg("%s: got RECEIVE_DISABLE", __FUNCTION__ );
- } else if( opcode != DIGI_CMD_RECEIVE_DATA ) {
- dbg("%s: unknown opcode: %d", __FUNCTION__, opcode );
- }
+ if (opcode == DIGI_CMD_RECEIVE_DISABLE)
+ dbg("%s: got RECEIVE_DISABLE", __FUNCTION__);
+ else if (opcode != DIGI_CMD_RECEIVE_DATA)
+ dbg("%s: unknown opcode: %d", __FUNCTION__, opcode);
- return( throttled ? 1 : 0 );
+ return(throttled ? 1 : 0);
}
@@ -1891,7 +1754,7 @@ static int digi_read_inb_callback( struct urb *urb )
* -1 if the sanity checks failed.
*/
-static int digi_read_oob_callback( struct urb *urb )
+static int digi_read_oob_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1900,87 +1763,75 @@ static int digi_read_oob_callback( struct urb *urb )
int opcode, line, status, val;
int i;
-
-dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num,
-urb->actual_length );
+ dbg("digi_read_oob_callback: port=%d, len=%d",
+ priv->dp_port_num, urb->actual_length);
/* handle each oob command */
- for( i=0; i<urb->actual_length-3; ) {
-
+ for(i = 0; i < urb->actual_length - 3;) {
opcode = ((unsigned char *)urb->transfer_buffer)[i++];
line = ((unsigned char *)urb->transfer_buffer)[i++];
status = ((unsigned char *)urb->transfer_buffer)[i++];
val = ((unsigned char *)urb->transfer_buffer)[i++];
-dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
-opcode, line, status, val );
+ dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
+ opcode, line, status, val);
- if( status != 0 || line >= serial->type->num_ports )
+ if (status != 0 || line >= serial->type->num_ports)
continue;
port = serial->port[line];
- if ((priv=usb_get_serial_port_data(port)) == NULL )
+ if ((priv=usb_get_serial_port_data(port)) == NULL)
return -1;
- if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) {
-
- spin_lock( &priv->dp_port_lock );
-
+ if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
+ spin_lock(&priv->dp_port_lock);
/* convert from digi flags to termiox flags */
- if( val & DIGI_READ_INPUT_SIGNALS_CTS ) {
+ if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
priv->dp_modem_signals |= TIOCM_CTS;
/* port must be open to use tty struct */
- if( port->open_count
- && port->tty->termios->c_cflag & CRTSCTS ) {
+ if (port->open_count
+ && port->tty->termios->c_cflag & CRTSCTS) {
port->tty->hw_stopped = 0;
- digi_wakeup_write( port );
+ digi_wakeup_write(port);
}
} else {
priv->dp_modem_signals &= ~TIOCM_CTS;
/* port must be open to use tty struct */
- if( port->open_count
- && port->tty->termios->c_cflag & CRTSCTS ) {
+ if (port->open_count
+ && port->tty->termios->c_cflag & CRTSCTS) {
port->tty->hw_stopped = 1;
}
}
- if( val & DIGI_READ_INPUT_SIGNALS_DSR )
+ if (val & DIGI_READ_INPUT_SIGNALS_DSR)
priv->dp_modem_signals |= TIOCM_DSR;
else
priv->dp_modem_signals &= ~TIOCM_DSR;
- if( val & DIGI_READ_INPUT_SIGNALS_RI )
+ if (val & DIGI_READ_INPUT_SIGNALS_RI)
priv->dp_modem_signals |= TIOCM_RI;
else
priv->dp_modem_signals &= ~TIOCM_RI;
- if( val & DIGI_READ_INPUT_SIGNALS_DCD )
+ if (val & DIGI_READ_INPUT_SIGNALS_DCD)
priv->dp_modem_signals |= TIOCM_CD;
else
priv->dp_modem_signals &= ~TIOCM_CD;
- wake_up_interruptible( &priv->dp_modem_change_wait );
- spin_unlock( &priv->dp_port_lock );
-
- } else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) {
-
- spin_lock( &priv->dp_port_lock );
+ wake_up_interruptible(&priv->dp_modem_change_wait);
+ spin_unlock(&priv->dp_port_lock);
+ } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
+ spin_lock(&priv->dp_port_lock);
priv->dp_transmit_idle = 1;
- wake_up_interruptible( &priv->dp_transmit_idle_wait );
- spin_unlock( &priv->dp_port_lock );
-
- } else if( opcode == DIGI_CMD_IFLUSH_FIFO ) {
-
- wake_up_interruptible( &priv->dp_flush_wait );
-
+ wake_up_interruptible(&priv->dp_transmit_idle_wait);
+ spin_unlock(&priv->dp_port_lock);
+ } else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
+ wake_up_interruptible(&priv->dp_flush_wait);
}
-
}
-
- return( 0 );
+ return 0;
}
-
-static int __init digi_init (void)
+static int __init digi_init(void)
{
int retval;
retval = usb_serial_register(&digi_acceleport_2_device);
@@ -2002,12 +1853,11 @@ failed_acceleport_2_device:
return retval;
}
-
static void __exit digi_exit (void)
{
- usb_deregister (&digi_driver);
- usb_serial_deregister (&digi_acceleport_2_device);
- usb_serial_deregister (&digi_acceleport_4_device);
+ usb_deregister(&digi_driver);
+ usb_serial_deregister(&digi_acceleport_2_device);
+ usb_serial_deregister(&digi_acceleport_4_device);
}
@@ -2015,8 +1865,8 @@ module_init(digi_init);
module_exit(digi_exit);
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 7b1673a44077..e4c248c98e84 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -538,6 +538,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
+ { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
+ { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
@@ -566,6 +568,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
+ { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
.driver_info = (kernel_ulong_t)&ftdi_olimex_quirk },
{ }, /* Optional parameter entry */
@@ -1166,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&port->dev, &dev_attr_event_char);
- if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+ if (priv->chip_type == FT232BM ||
+ priv->chip_type == FT2232C ||
+ priv->chip_type == FT232RL) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@@ -2099,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT8U232AM:
case FT232BM:
case FT2232C:
+ case FT232RL:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
if ((ret = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index d9e49716db13..b57b90ae9f9d 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -430,6 +430,9 @@
*/
#define EVOLUTION_VID 0xDEEE /* Vendor ID */
#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */
+#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
+#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
+#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
/* Pyramid Computer GmbH */
#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */
@@ -531,6 +534,14 @@
#define OLIMEX_VID 0x15BA
#define OLIMEX_ARM_USB_OCD_PID 0x0003
+
+/*
+ * The Mobility Lab (TML)
+ * Submitted by Pierre Castella
+ */
+#define TML_VID 0x1B91 /* Vendor ID */
+#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4092f6dc9efd..b5194dc7d3bb 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ktermios t;
-
- dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
- if (cmd == TCSETSF) {
- if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
- return -EFAULT;
-
- dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
- t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
- if (!(t.c_lflag & ICANON))
- return -EINVAL;
- }
- return -ENOIOCTLCMD;
-}
-
static struct usb_driver funsoft_driver = {
.name = "funsoft",
.probe = usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
- .ioctl = funsoft_ioctl,
};
static int __init funsoft_init(void)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 04bd3b7a2985..f1c90cfe7251 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1,7 +1,7 @@
/*
* Garmin GPS driver
*
- * Copyright (C) 2006 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006,2007 Hermann Kneissel herkne@users.sourceforge.net
*
* The latest version of the driver can be found at
* http://sourceforge.net/projects/garmin-gps/
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
@@ -52,7 +53,7 @@ static int debug = 0;
*/
#define VERSION_MAJOR 0
-#define VERSION_MINOR 28
+#define VERSION_MINOR 31
#define _STR(s) #s
#define _DRIVER_VERSION(a,b) "v" _STR(a) "." _STR(b)
@@ -141,6 +142,8 @@ struct garmin_data {
__u8 inbuffer [GPS_IN_BUFSIZ]; /* tty -> usb */
__u8 outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */
__u8 privpkt[4*6];
+ atomic_t req_count;
+ atomic_t resp_count;
spinlock_t lock;
struct list_head pktlist;
};
@@ -171,8 +174,6 @@ struct garmin_data {
#define CLEAR_HALT_REQUIRED 0x0001
#define FLAGS_QUEUING 0x0100
-#define FLAGS_APP_RESP_SEEN 0x0200
-#define FLAGS_APP_REQ_SEEN 0x0400
#define FLAGS_DROP_DATA 0x0800
#define FLAGS_GSP_SKIP 0x1000
@@ -186,7 +187,8 @@ struct garmin_data {
/* function prototypes */
static void gsp_next_packet(struct garmin_data * garmin_data_p);
static int garmin_write_bulk(struct usb_serial_port *port,
- const unsigned char *buf, int count);
+ const unsigned char *buf, int count,
+ int dismiss_ack);
/* some special packets to be send or received */
static unsigned char const GARMIN_START_SESSION_REQ[]
@@ -233,9 +235,7 @@ static struct usb_driver garmin_driver = {
static inline int noResponseFromAppLayer(struct garmin_data * garmin_data_p)
{
- return ((garmin_data_p->flags
- & (FLAGS_APP_REQ_SEEN|FLAGS_APP_RESP_SEEN))
- == FLAGS_APP_REQ_SEEN);
+ return atomic_read(&garmin_data_p->req_count) == atomic_read(&garmin_data_p->resp_count);
}
@@ -463,7 +463,7 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
usbdata[2] = __cpu_to_le32(size);
garmin_write_bulk (garmin_data_p->port, garmin_data_p->inbuffer,
- GARMIN_PKTHDR_LENGTH+size);
+ GARMIN_PKTHDR_LENGTH+size, 0);
/* if this was an abort-transfer command, flush all
queued data. */
@@ -818,7 +818,7 @@ static int nat_receive(struct garmin_data * garmin_data_p,
if (garmin_data_p->insize >= len) {
garmin_write_bulk (garmin_data_p->port,
garmin_data_p->inbuffer,
- len);
+ len, 0);
garmin_data_p->insize = 0;
/* if this was an abort-transfer command,
@@ -893,10 +893,11 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
struct usb_serial_port *port = garmin_data_p->port;
- if (port != NULL && garmin_data_p->flags & FLAGS_APP_RESP_SEEN) {
+ if (port != NULL && atomic_read(&garmin_data_p->resp_count)) {
/* send a terminate command */
status = garmin_write_bulk(port, GARMIN_STOP_TRANSFER_REQ,
- sizeof(GARMIN_STOP_TRANSFER_REQ));
+ sizeof(GARMIN_STOP_TRANSFER_REQ),
+ 1);
}
/* flush all queued data */
@@ -939,7 +940,8 @@ static int garmin_init_session(struct usb_serial_port *port)
dbg("%s - starting session ...", __FUNCTION__);
garmin_data_p->state = STATE_ACTIVE;
status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ,
- sizeof(GARMIN_START_SESSION_REQ));
+ sizeof(GARMIN_START_SESSION_REQ),
+ 0);
if (status >= 0) {
@@ -950,7 +952,8 @@ static int garmin_init_session(struct usb_serial_port *port)
/* not needed, but the win32 driver does it too ... */
status = garmin_write_bulk(port,
GARMIN_START_SESSION_REQ2,
- sizeof(GARMIN_START_SESSION_REQ2));
+ sizeof(GARMIN_START_SESSION_REQ2),
+ 0);
if (status >= 0) {
status = 0;
spin_lock_irqsave(&garmin_data_p->lock, flags);
@@ -987,6 +990,8 @@ static int garmin_open (struct usb_serial_port *port, struct file *filp)
garmin_data_p->mode = initial_mode;
garmin_data_p->count = 0;
garmin_data_p->flags = 0;
+ atomic_set(&garmin_data_p->req_count, 0);
+ atomic_set(&garmin_data_p->resp_count, 0);
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* shutdown any bulk reads that might be going on */
@@ -1035,28 +1040,39 @@ static void garmin_write_bulk_callback (struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
int status = urb->status;
- /* free up the transfer buffer, as usb_free_urb() does not do this */
- kfree (urb->transfer_buffer);
+ if (port) {
+ struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
- if (status) {
- dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, status);
- spin_lock_irqsave(&garmin_data_p->lock, flags);
- garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
- spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)
+ && (garmin_data_p->mode == MODE_GARMIN_SERIAL)) {
+ gsp_send_ack(garmin_data_p, ((__u8 *)urb->transfer_buffer)[4]);
+ }
+
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+
+ usb_serial_port_softint(port);
}
- usb_serial_port_softint(port);
+ /* Ignore errors that resulted from garmin_write_bulk with dismiss_ack=1 */
+
+ /* free up the transfer buffer, as usb_free_urb() does not do this */
+ kfree (urb->transfer_buffer);
}
static int garmin_write_bulk (struct usb_serial_port *port,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count,
+ int dismiss_ack)
{
unsigned long flags;
struct usb_serial *serial = port->serial;
@@ -1093,13 +1109,12 @@ static int garmin_write_bulk (struct usb_serial_port *port,
usb_sndbulkpipe (serial->dev,
port->bulk_out_endpointAddress),
buffer, count,
- garmin_write_bulk_callback, port);
+ garmin_write_bulk_callback,
+ dismiss_ack ? NULL : port);
urb->transfer_flags |= URB_ZERO_PACKET;
if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
- spin_lock_irqsave(&garmin_data_p->lock, flags);
- garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
- spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ atomic_inc(&garmin_data_p->req_count);
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
pkt_clear(garmin_data_p);
garmin_data_p->state = STATE_GSP_WAIT_DATA;
@@ -1114,13 +1129,6 @@ static int garmin_write_bulk (struct usb_serial_port *port,
"failed with status = %d\n",
__FUNCTION__, status);
count = status;
- } else {
-
- if (GARMIN_LAYERID_APPL == getLayerId(buffer)
- && (garmin_data_p->mode == MODE_GARMIN_SERIAL)) {
-
- gsp_send_ack(garmin_data_p, buffer[4]);
- }
}
/* we are done with this urb, so let the host driver
@@ -1135,7 +1143,6 @@ static int garmin_write_bulk (struct usb_serial_port *port,
static int garmin_write (struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- unsigned long flags;
int pktid, pktsiz, len;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
__le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
@@ -1186,9 +1193,7 @@ static int garmin_write (struct usb_serial_port *port,
break;
case PRIV_PKTID_RESET_REQ:
- spin_lock_irqsave(&garmin_data_p->lock, flags);
- garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
- spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ atomic_inc(&garmin_data_p->req_count);
break;
case PRIV_PKTID_SET_DEF_MODE:
@@ -1241,8 +1246,6 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
static void garmin_read_process(struct garmin_data * garmin_data_p,
unsigned char *data, unsigned data_length)
{
- unsigned long flags;
-
if (garmin_data_p->flags & FLAGS_DROP_DATA) {
/* abort-transfer cmd is actice */
dbg("%s - pkt dropped", __FUNCTION__);
@@ -1254,9 +1257,7 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
the device */
if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
sizeof(GARMIN_APP_LAYER_REPLY))) {
- spin_lock_irqsave(&garmin_data_p->lock, flags);
- garmin_data_p->flags |= FLAGS_APP_RESP_SEEN;
- spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ atomic_inc(&garmin_data_p->resp_count);
}
/* if throttling is active or postprecessing is required
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index dd42f57089ff..2ecb1d2a034d 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2366,9 +2366,8 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
int status;
unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+ if (edge_serial->is_epic &&
+ !edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) {
dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
edge_port->port->number, baudRate);
return 0;
@@ -2461,18 +2460,16 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
- (regNum == MCR))) {
+ if (edge_serial->is_epic &&
+ !edge_serial->epic_descriptor.Supports.IOSPWriteMCR &&
+ regNum == MCR) {
dbg("SendCmdWriteUartReg - Not writing to MCR Register");
return 0;
}
- if ((!edge_serial->is_epic) ||
- ((edge_serial->is_epic) &&
- (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
- (regNum == LCR))) {
+ if (edge_serial->is_epic &&
+ !edge_serial->epic_descriptor.Supports.IOSPWriteLCR &&
+ regNum == LCR) {
dbg ("SendCmdWriteUartReg - Not writing to LCR Register");
return 0;
}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 0d3903691e8c..b8670905bc3a 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2794,16 +2794,14 @@ static void edge_shutdown (struct usb_serial *serial)
dbg ("%s", __FUNCTION__);
- for (i=0; i < serial->num_ports; ++i) {
+ for (i = 0; i < serial->num_ports; ++i) {
edge_port = usb_get_serial_port_data(serial->port[i]);
edge_remove_sysfs_attrs(edge_port->port);
- if (edge_port) {
- edge_buf_free(edge_port->ep_out_buf);
- kfree(edge_port);
- }
+ edge_buf_free(edge_port->ep_out_buf);
+ kfree(edge_port);
usb_set_serial_port_data(serial->port[i], NULL);
}
- kfree (usb_get_serial_data(serial));
+ kfree(usb_get_serial_data(serial));
usb_set_serial_data(serial, NULL);
}
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 0455c1552ae9..e836ad07fdb9 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+ { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -545,6 +546,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */
{ USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */
{ USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */
+ { USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC smartphone modems */
{ } /* Terminating entry */
};
@@ -645,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
kfree(port->bulk_out_buffer);
port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_in_buffer == NULL) {
+ port->bulk_out_buffer = NULL; /* prevent double free */
goto enomem;
}
port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_out_buffer == NULL) {
kfree(port->bulk_in_buffer);
+ port->bulk_in_buffer = NULL;
goto enomem;
}
port->read_urb->transfer_buffer = port->bulk_in_buffer;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5a4127e62c4a..90e3216abd1f 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
#endif
}
- switch(cflag & CBAUD) {
- case B0: /* handled below */
+ switch(tty_get_baud_rate(port->tty)) {
+ case 0: /* handled below */
break;
- case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+ case 1200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b1200;
break;
- case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+ case 2400:
+ priv->cfg.baudrate = kl5kusb105a_sio_b2400;
break;
- case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+ case 4800:
+ priv->cfg.baudrate = kl5kusb105a_sio_b4800;
break;
- case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+ case 9600:
+ priv->cfg.baudrate = kl5kusb105a_sio_b9600;
break;
- case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+ case 19200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b19200;
break;
- case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+ case 38400:
+ priv->cfg.baudrate = kl5kusb105a_sio_b38400;
break;
- case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+ case 57600:
+ priv->cfg.baudrate = kl5kusb105a_sio_b57600;
break;
- case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+ case 115200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
err("KLSI USB->Serial converter:"
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 02a86dbc0e97..6f224195bd25 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static void kobil_read_int_callback( struct urb *urb );
static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
.attach = kobil_startup,
.shutdown = kobil_shutdown,
.ioctl = kobil_ioctl,
+ .set_termios = kobil_set_termios,
.tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset,
.open = kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
int cur_pos; // index of the next char to send in buf
__u16 device_type;
int line_state;
- struct ktermios internal_termios;
};
@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
static int kobil_open (struct usb_serial_port *port, struct file *filp)
{
- int i, result = 0;
+ int result = 0;
struct kobil_private *priv;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
- // set up internal termios structure
- priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
- priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
- priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
- priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
- for (i=0; i<NCCS; i++) {
- priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
- }
-
// allocate memory for transfer buffer
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) {
@@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
return (result < 0) ? result : 0;
}
-
-static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
{
struct kobil_private * priv;
int result;
unsigned short urb_val = 0;
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
- char *settings;
- void __user *user_arg = (void __user *)arg;
+ int c_cflag = port->tty->termios->c_cflag;
+ speed_t speed;
+ void * settings;
priv = usb_get_serial_port_data(port);
- if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+ if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls
- return 0;
- }
-
- switch (cmd) {
- case TCGETS: // 0x5401
- if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
- dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
- return -EFAULT;
- }
- if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
- &priv->internal_termios))
- return -EFAULT;
- return 0;
-
- case TCSETS: // 0x5402
- if (!(port->tty->termios)) {
- dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
- return -ENOTTY;
- }
- if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
- dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
- return -EFAULT;
- }
- if (user_termios_to_kernel_termios(&priv->internal_termios,
- (struct ktermios __user *)arg))
- return -EFAULT;
-
- settings = kzalloc(50, GFP_KERNEL);
- if (! settings) {
- return -ENOBUFS;
- }
+ return;
- switch (priv->internal_termios.c_cflag & CBAUD) {
- case B1200:
+ switch (speed = tty_get_baud_rate(port->tty)) {
+ case 1200:
urb_val = SUSBCR_SBR_1200;
- strcat(settings, "1200 ");
break;
- case B9600:
+ case 9600:
default:
urb_val = SUSBCR_SBR_9600;
- strcat(settings, "9600 ");
break;
- }
+ }
+ urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+
+ settings = kzalloc(50, GFP_KERNEL);
+ if (! settings)
+ return;
- urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
- strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+ sprintf(settings, "%d ", speed);
- if (priv->internal_termios.c_cflag & PARENB) {
- if (priv->internal_termios.c_cflag & PARODD) {
- urb_val |= SUSBCR_SPASB_OddParity;
- strcat(settings, "Odd Parity");
- } else {
- urb_val |= SUSBCR_SPASB_EvenParity;
- strcat(settings, "Even Parity");
- }
+ if (c_cflag & PARENB) {
+ if (c_cflag & PARODD) {
+ urb_val |= SUSBCR_SPASB_OddParity;
+ strcat(settings, "Odd Parity");
} else {
- urb_val |= SUSBCR_SPASB_NoParity;
- strcat(settings, "No Parity");
+ urb_val |= SUSBCR_SPASB_EvenParity;
+ strcat(settings, "Even Parity");
}
- dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+ } else {
+ urb_val |= SUSBCR_SPASB_NoParity;
+ strcat(settings, "No Parity");
+ }
- result = usb_control_msg( port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0 ),
- SUSBCRequest_SetBaudRateParityAndStopBits,
- USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
- urb_val,
- 0,
- settings,
- 0,
- KOBIL_TIMEOUT
- );
+ result = usb_control_msg( port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0 ),
+ SUSBCRequest_SetBaudRateParityAndStopBits,
+ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+ urb_val,
+ 0,
+ settings,
+ 0,
+ KOBIL_TIMEOUT
+ );
+ kfree(settings);
+}
- dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
- kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct kobil_private * priv = usb_get_serial_port_data(port);
+ unsigned char *transfer_buffer;
+ int transfer_buffer_length = 8;
+ int result;
+
+ if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+ // This device doesn't support ioctl calls
return 0;
+ switch (cmd) {
case TCFLSH: // 0x540B
transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
- if (! transfer_buffer) {
+ if (! transfer_buffer)
return -ENOBUFS;
- }
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
@@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
);
dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
kfree(transfer_buffer);
- return ((result < 0) ? -EFAULT : 0);
-
+ return (result < 0) ? -EFAULT : 0;
+ default:
+ return -ENOIOCTLCMD;
}
- return -ENOIOCTLCMD;
}
-
static int __init kobil_init (void)
{
int retval;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 2a3fabcf5186..0dc99f75bb09 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -184,21 +184,21 @@ struct mct_u232_private {
* we do not know how to support. We ignore them for the moment.
* XXX Rate-limit the error message, it's user triggerable.
*/
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value)
{
if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
|| le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
switch (value) {
- case B300: return 0x01;
- case B600: return 0x02; /* this one not tested */
- case B1200: return 0x03;
- case B2400: return 0x04;
- case B4800: return 0x06;
- case B9600: return 0x08;
- case B19200: return 0x09;
- case B38400: return 0x0a;
- case B57600: return 0x0b;
- case B115200: return 0x0c;
+ case 300: return 0x01;
+ case 600: return 0x02; /* this one not tested */
+ case 1200: return 0x03;
+ case 2400: return 0x04;
+ case 4800: return 0x06;
+ case 9600: return 0x08;
+ case 19200: return 0x09;
+ case 38400: return 0x0a;
+ case 57600: return 0x0b;
+ case 115200: return 0x0c;
default:
err("MCT USB-RS232: unsupported baudrate request 0x%x,"
" using default of B9600", value);
@@ -206,16 +206,16 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
}
} else {
switch (value) {
- case B300: value = 300; break;
- case B600: value = 600; break;
- case B1200: value = 1200; break;
- case B2400: value = 2400; break;
- case B4800: value = 4800; break;
- case B9600: value = 9600; break;
- case B19200: value = 19200; break;
- case B38400: value = 38400; break;
- case B57600: value = 57600; break;
- case B115200: value = 115200; break;
+ case 300: break;
+ case 600: break;
+ case 1200: break;
+ case 2400: break;
+ case 4800: break;
+ case 9600: break;
+ case 19200: break;
+ case 38400: break;
+ case 57600: break;
+ case 115200: break;
default:
err("MCT USB-RS232: unsupported baudrate request 0x%x,"
" using default of B9600", value);
@@ -226,7 +226,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
}
static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_port *port,
- int value)
+ speed_t value)
{
__le32 divisor;
int rc;
@@ -634,7 +634,7 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
mct_u232_set_modem_ctrl(serial, control_state);
}
- mct_u232_set_baud_rate(serial, port, cflag & CBAUD);
+ mct_u232_set_baud_rate(serial, port, tty_get_baud_rate(port->tty));
if ((cflag & CBAUD) == B0 ) {
dbg("%s: baud is B0", __FUNCTION__);
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index a61bac8f224a..aae10c8174d6 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -79,7 +79,7 @@
* and "Intel solution". They are the regular MCT and "Sitecom" for us.
* This is pointless to document in the header, see the code for the bits.
*/
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value);
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value);
/*
* Line Control Register (LCR)
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 231b584f6d0f..01e811becec4 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -110,11 +110,6 @@ static void mos7720_interrupt_callback(struct urb *urb)
dbg("%s"," : Entering\n");
- if (!urb) {
- dbg("%s","Invalid Pointer !!!!:\n");
- return;
- }
-
switch (status) {
case 0:
/* success */
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 37f41f576d3d..f76480f1455d 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -436,11 +436,6 @@ static void mos7840_control_callback(struct urb *urb)
int result = 0;
int status = urb->status;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
mos7840_port = (struct moschip_port *)urb->context;
switch (status) {
@@ -525,10 +520,6 @@ static void mos7840_interrupt_callback(struct urb *urb)
int status = urb->status;
dbg("%s", " : Entering\n");
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
switch (status) {
case 0:
@@ -676,11 +667,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
struct tty_struct *tty;
int status = urb->status;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
if (status) {
dbg("nonzero read bulk status received: %d", status);
return;
@@ -753,11 +739,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
int status = urb->status;
int i;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
mos7840_port = (struct moschip_port *)urb->context;
spin_lock(&mos7840_port->pool_lock);
for (i = 0; i < NUM_URBS; i++) {
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 84c12b5f1271..a18659e0700c 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -108,8 +108,10 @@ static int option_send_setup(struct usb_serial_port *port);
#define HUAWEI_VENDOR_ID 0x12D1
#define HUAWEI_PRODUCT_E600 0x1001
#define HUAWEI_PRODUCT_E220 0x1003
+#define HUAWEI_PRODUCT_E220BIS 0x1004
#define NOVATELWIRELESS_VENDOR_ID 0x1410
+#define DELL_VENDOR_ID 0x413C
#define ANYDATA_VENDOR_ID 0x16d5
#define ANYDATA_PRODUCT_ADU_E100A 0x6501
@@ -119,8 +121,6 @@ static int option_send_setup(struct usb_serial_port *port);
#define BANDRICH_PRODUCT_C100_1 0x1002
#define BANDRICH_PRODUCT_C100_2 0x1003
-#define DELL_VENDOR_ID 0x413C
-
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -159,6 +159,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */
@@ -171,11 +172,17 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8114) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8115) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8116) }, /* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
- { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index d7db71eca520..d19861166b50 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -817,23 +817,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
__FUNCTION__, port->number, cmd, arg);
switch (cmd) {
- case TCGETS:
- if (copy_to_user(user_arg, port->tty->termios,
- sizeof(struct ktermios))) {
- return -EFAULT;
- }
- return 0;
-
- case TCSETS:
- case TCSETSW: /* FIXME: this is not the same! */
- case TCSETSF: /* FIXME: this is not the same! */
- if (copy_from_user(port->tty->termios, user_arg,
- sizeof(struct ktermios))) {
- return -EFAULT;
- }
- oti6858_set_termios(port, NULL);
- return 0;
-
case TCFLSH:
/* FIXME */
return 0;
@@ -1161,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
if (size == 0)
return NULL;
- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index f9f85f56f0db..1da57fd9ea23 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index f9a71d0c102e..c39bace5cbcc 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -59,6 +59,7 @@
#define SIEMENS_PRODUCT_ID_SX1 0x0001
#define SIEMENS_PRODUCT_ID_X65 0x0003
#define SIEMENS_PRODUCT_ID_X75 0x0004
+#define SIEMENS_PRODUCT_ID_EF81 0x0005
#define SYNTECH_VENDOR_ID 0x0745
#define SYNTECH_PRODUCT_ID 0x0001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 86899d55d8d8..4e6dcc199be9 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -74,13 +74,13 @@
#include <linux/usb/serial.h>
-#ifndef CONFIG_USB_SAFE_PADDED
-#define CONFIG_USB_SAFE_PADDED 0
+#ifndef CONFIG_USB_SERIAL_SAFE_PADDED
+#define CONFIG_USB_SERIAL_SAFE_PADDED 0
#endif
static int debug;
static int safe = 1;
-static int padded = CONFIG_USB_SAFE_PADDED;
+static int padded = CONFIG_USB_SERIAL_SAFE_PADDED;
#define DRIVER_VERSION "v0.0b"
#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
@@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE("GPL");
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
static __u16 vendor; // no default
static __u16 product; // no default
module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = {
{MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
{MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
{MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
- {MY_USB_DEVICE
- (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
- LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
// extra null entry for module
// vendor/produc parameters
{MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index e7db20343d1a..0bb8de4cc524 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
/*
USB Driver for Sierra Wireless
- Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com>
+ Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
@@ -12,10 +12,9 @@
Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
*/
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -28,23 +27,99 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#define SWIMS_USB_REQUEST_SetMode 0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
+#define SWIMS_USB_INDEX_SetMode 0x0000
+#define SWIMS_SET_MODE_Modem 0x0001
+
+/* per port private data */
+#define N_IN_URB 4
+#define N_OUT_URB 4
+#define IN_BUFLEN 4096
+
+static int debug;
+
+enum devicetype {
+ DEVICE_3_PORT = 0,
+ DEVICE_1_PORT = 1,
+ DEVICE_INSTALLER = 2,
+};
+
+static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x00, /* __u8 request */
+ 0x40, /* __u8 request type */
+ swiState, /* __u16 value */
+ 0, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_SetMode, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
+ eSocMode, /* __u16 value */
+ SWIMS_USB_INDEX_SetMode, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+static int sierra_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct usb_device *udev;
+
+ udev = usb_get_dev(interface_to_usbdev(iface));
+
+ /* Check if in installer mode */
+ if (id->driver_info == DEVICE_INSTALLER) {
+ dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+ result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+ /*We do not want to bind to the device when in installer mode*/
+ return -EIO;
+ }
+
+ return usb_serial_probe(iface, id);
+}
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
+ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
- { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+ { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+ { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+ { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,35 +133,36 @@ static struct usb_device_id id_table_1port [] = {
static struct usb_device_id id_table_3port [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
+
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
+ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
{ }
};
static struct usb_driver sierra_driver = {
.name = "sierra",
- .probe = usb_serial_probe,
+ .probe = sierra_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
-static int debug;
-
-/* per port private data */
-#define N_IN_URB 4
-#define N_OUT_URB 4
-#define IN_BUFLEN 4096
-
struct sierra_port_private {
spinlock_t lock; /* lock the structure */
int outstanding_urbs; /* number of out urbs in flight */
@@ -421,7 +497,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
int i;
struct urb *urb;
int result;
- __u16 set_mode_dzero = 0x0000;
portdata = usb_get_serial_port_data(port);
@@ -457,12 +532,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
port->tty->low_latency = 1;
- /* set mode to D0 */
- result = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x00, 0x40, set_mode_dzero, 0, NULL,
- 0, USB_CTRL_SET_TIMEOUT);
-
sierra_send_setup(port);
/* start up the interrupt endpoint if we have one */
@@ -510,6 +579,9 @@ static int sierra_startup(struct usb_serial *serial)
dbg("%s", __FUNCTION__);
+ /*Set Device mode to D0 */
+ sierra_set_power_state(serial->dev, 0x0000);
+
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index a3665659d13b..4b1bd7def4a5 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -60,19 +60,19 @@ static struct usb_driver usb_serial_driver = {
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
-static spinlock_t table_lock;
+static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
struct usb_serial *serial;
- spin_lock(&table_lock);
+ mutex_lock(&table_lock);
serial = serial_table[index];
if (serial)
kref_get(&serial->kref);
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
return serial;
}
@@ -84,7 +84,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s %d", __FUNCTION__, num_ports);
*minor = 0;
- spin_lock(&table_lock);
+ mutex_lock(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
@@ -106,10 +106,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
serial_table[i] = serial;
serial->port[j++]->number = i;
}
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
return serial;
}
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
return NULL;
}
@@ -172,9 +172,9 @@ static void destroy_serial(struct kref *kref)
void usb_serial_put(struct usb_serial *serial)
{
- spin_lock(&table_lock);
+ mutex_lock(&table_lock);
kref_put(&serial->kref, destroy_serial);
- spin_unlock(&table_lock);
+ mutex_unlock(&table_lock);
}
/*****************************************************************************
@@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
+ /*
+ * This is tricky.
+ * Some drivers submit the read_urb in the
+ * handler for the write_urb or vice versa
+ * this order determines the order in which
+ * usb_kill_urb() must be used to reliably
+ * kill the URBs. As it is unknown here,
+ * both orders must be used in turn.
+ * The call below is not redundant.
+ */
+ usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
}
@@ -651,16 +662,14 @@ exit:
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
- struct list_head *p;
const struct usb_device_id *id;
- struct usb_serial_driver *t;
+ struct usb_serial_driver *drv;
/* Check if the usb id matches a known device */
- list_for_each(p, &usb_serial_driver_list) {
- t = list_entry(p, struct usb_serial_driver, driver_list);
- id = get_iface_id(t, iface);
+ list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+ id = get_iface_id(drv, iface);
if (id)
- return t;
+ return drv;
}
return NULL;
@@ -800,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface,
/* END HORRIBLE HACK FOR PL2303 */
#endif
- /* found all that we need */
- dev_info(&interface->dev, "%s converter detected\n", type->description);
-
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
@@ -836,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_interrupt_in = num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out;
+ /* check that the device meets the driver's requirements */
+ if ((type->num_interrupt_in != NUM_DONT_CARE &&
+ type->num_interrupt_in != num_interrupt_in)
+ || (type->num_interrupt_out != NUM_DONT_CARE &&
+ type->num_interrupt_out != num_interrupt_out)
+ || (type->num_bulk_in != NUM_DONT_CARE &&
+ type->num_bulk_in != num_bulk_in)
+ || (type->num_bulk_out != NUM_DONT_CARE &&
+ type->num_bulk_out != num_bulk_out)) {
+ dbg("wrong number of endpoints");
+ kfree(serial);
+ return -EIO;
+ }
+
+ /* found all that we need */
+ dev_info(&interface->dev, "%s converter detected\n",
+ type->description);
+
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
@@ -1077,16 +1101,17 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
struct usb_serial_port *port;
int i, r = 0;
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port)
- kill_traffic(port);
- }
+ if (!serial) /* device has been disconnected */
+ return 0;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port)
+ kill_traffic(port);
}
if (serial->type->suspend)
- serial->type->suspend(serial, message);
+ r = serial->type->suspend(serial, message);
return r;
}
@@ -1128,7 +1153,6 @@ static int __init usb_serial_init(void)
return -ENOMEM;
/* Initialize our global data */
- spin_lock_init(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 7d84a7647e81..7ee087fed913 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id
static int visor_calc_num_ports(struct usb_serial *serial);
static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void visor_write_bulk_callback (struct urb *urb);
static void visor_read_bulk_callback (struct urb *urb);
static void visor_read_int_callback (struct urb *urb);
@@ -104,6 +103,8 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+ { USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID),
+ .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID),
@@ -201,7 +202,6 @@ static struct usb_serial_driver handspring_device = {
.calc_num_ports = visor_calc_num_ports,
.shutdown = visor_shutdown,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -232,7 +232,6 @@ static struct usb_serial_driver clie_5_device = {
.calc_num_ports = visor_calc_num_ports,
.shutdown = visor_shutdown,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -260,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = {
.unthrottle = visor_unthrottle,
.attach = clie_3_5_startup,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -934,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
return -ENOIOCTLCMD;
}
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
- unsigned int cflag;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
- cflag = port->tty->termios->c_cflag;
-
- /* get the byte size */
- switch (cflag & CSIZE) {
- case CS5: dbg("%s - data bits = 5", __FUNCTION__); break;
- case CS6: dbg("%s - data bits = 6", __FUNCTION__); break;
- case CS7: dbg("%s - data bits = 7", __FUNCTION__); break;
- default:
- case CS8: dbg("%s - data bits = 8", __FUNCTION__); break;
- }
-
- /* determine the parity */
- if (cflag & PARENB)
- if (cflag & PARODD)
- dbg("%s - parity = odd", __FUNCTION__);
- else
- dbg("%s - parity = even", __FUNCTION__);
- else
- dbg("%s - parity = none", __FUNCTION__);
-
- /* figure out the stop bits requested */
- if (cflag & CSTOPB)
- dbg("%s - stop bits = 2", __FUNCTION__);
- else
- dbg("%s - stop bits = 1", __FUNCTION__);
-
-
- /* figure out the flow control settings */
- if (cflag & CRTSCTS)
- dbg("%s - RTS/CTS is enabled", __FUNCTION__);
- else
- dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-
- /* determine software flow control */
- if (I_IXOFF(port->tty))
- dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
- __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
- else
- dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
- /* get the baud rate wanted */
- dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
- return;
-}
-
-
static int __init visor_init (void)
{
int i, retval;
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 4ce6f62a6f39..57229cf66477 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -48,6 +48,9 @@
#define SONY_CLIE_UX50_ID 0x0144
#define SONY_CLIE_TJ25_ID 0x0169
+#define ACER_VENDOR_ID 0x0502
+#define ACER_S10_ID 0x0001
+
#define SAMSUNG_VENDOR_ID 0x04E8
#define SAMSUNG_SCH_I330_ID 0x8001
#define SAMSUNG_SPH_I500_ID 0x6601
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 1628cb258562..9a410b5a6e5b 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -46,43 +46,43 @@
*/
int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
{
- int ret;
+ int ret;
- if(srb == NULL)
- return USB_STOR_TRANSPORT_ERROR;
+ if (srb == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+ US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
- switch(srb->device->lun) {
- case 0:
+ switch (srb->device->lun) {
+ case 0:
- /*
- * LUN 0 corresponds to the CompactFlash card reader.
- */
- ret = usb_stor_CB_transport(srb, us);
- break;
+ /*
+ * LUN 0 corresponds to the CompactFlash card reader.
+ */
+ ret = usb_stor_CB_transport(srb, us);
+ break;
#ifdef CONFIG_USB_STORAGE_SDDR09
- case 1:
+ case 1:
- /*
- * LUN 1 corresponds to the SmartMedia card reader.
- */
+ /*
+ * LUN 1 corresponds to the SmartMedia card reader.
+ */
- /*
- * Set the LUN to 0 (just in case).
- */
- srb->device->lun = 0; us->srb->device->lun = 0;
- ret = sddr09_transport(srb, us);
- srb->device->lun = 1; us->srb->device->lun = 1;
- break;
+ /*
+ * Set the LUN to 0 (just in case).
+ */
+ srb->device->lun = 0; us->srb->device->lun = 0;
+ ret = sddr09_transport(srb, us);
+ srb->device->lun = 1; us->srb->device->lun = 1;
+ break;
#endif
- default:
- US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
- ret = USB_STOR_TRANSPORT_ERROR;
- break;
- }
- return ret;
+ default:
+ US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+ ret = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+ return ret;
}
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 3a41740cad97..ee5b42aa5363 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
return (res ? -1 : 0);
}
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+ int result;
+
+ us->iobuf[0] = 0x1;
+ result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+ USB_REQ_SET_FEATURE,
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 0x01, 0x0, us->iobuf, 0x1, 1000);
+ US_DEBUGP("usb_control_msg performing result is %d\n", result);
+ return (result ? 0 : -1);
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index e2967a4d48a2..ad3ffd4236c2 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us);
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d35369392fed..dfd42fe9e5f0 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -57,9 +57,10 @@ static void usb_onetouch_irq(struct urb *urb)
struct usb_onetouch *onetouch = urb->context;
signed char *data = onetouch->data;
struct input_dev *dev = onetouch->dev;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -75,11 +76,11 @@ static void usb_onetouch_irq(struct urb *urb)
input_sync(dev);
resubmit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("can't resubmit intr, %s-%s/input0, retval %d",
onetouch->udev->bus->bus_name,
- onetouch->udev->devpath, status);
+ onetouch->udev->devpath, retval);
}
static int usb_onetouch_open(struct input_dev *dev)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 47e56079925d..1ba19eaa1970 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -285,15 +285,10 @@ static int device_reset(struct scsi_cmnd *srb)
US_DEBUGP("%s called\n", __FUNCTION__);
- result = usb_autopm_get_interface(us->pusb_intf);
- if (result == 0) {
-
- /* lock the device pointers and do the reset */
- mutex_lock(&(us->dev_mutex));
- result = us->transport_reset(us);
- mutex_unlock(&us->dev_mutex);
- usb_autopm_put_interface(us->pusb_intf);
- }
+ /* lock the device pointers and do the reset */
+ mutex_lock(&(us->dev_mutex));
+ result = us->transport_reset(us);
+ mutex_unlock(&us->dev_mutex);
return result < 0 ? FAILED : SUCCESS;
}
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 5e27297c0175..17ca4d73577b 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us)
unsigned char *reply = us->iobuf;
int rc;
- if (!us)
- return USB_STOR_TRANSPORT_ERROR;
-
rc = usbat_get_status(us, reply);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_FAILED;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b6bf31a97b60..9b656ec427d0 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
/* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610,
"Nokia",
"6131",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -313,6 +313,20 @@ UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010,
US_SC_DEVICE, US_PR_DEVICE,NULL,
US_FL_NOT_LOCKABLE ),
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV( 0x04b0, 0x0401, 0x0200, 0x0200,
+ "NIKON",
+ "NIKON DSC D100",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported by Milinevsky Dmitry <niam.niam@gmail.com> */
+UNUSUAL_DEV( 0x04b0, 0x0409, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D50",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Andreas Bockhold <andreas@bockionline.de> */
UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
"NIKON",
@@ -327,13 +341,41 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200,
+ "NIKON",
+ "NIKON DSC D200",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Emil Larsson <emil@swip.net> */
-UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101,
"NIKON",
"NIKON DSC D80",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported by Ortwin Glueck <odi@odi.ch> */
+UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110,
+ "NIKON",
+ "NIKON DSC D40",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D2Xs",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D40X",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* BENQ DC5330
* Reported by Manuel Fombuena <mfombuena@ya.com> and
* Frank Copeland <fjc@thingy.apana.org.au> */
@@ -883,6 +925,22 @@ UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
+ * This USB MP3/AVI player device fails and disconnects if more than 128
+ * sectors (64kB) are read/written in a single command, and may be present
+ * at least in the following products:
+ * "Magnex Digital Video Panel DVP 1800"
+ * "MP4 AIGO 4GB SLOT SD"
+ * "Teclast TL-C260 MP3"
+ * "i.Meizu PMP MP3/MP4"
+ * "Speed MV8 MP4 Audio Player"
+ */
+UNUSUAL_DEV( 0x071b, 0x3203, 0x0100, 0x0100,
+ "RockChip",
+ "ROCK MP3",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
/* Reported by Olivier Blondeau <zeitoun@gmail.com> */
UNUSUAL_DEV( 0x0727, 0x0306, 0x0100, 0x0100,
"ATMEL",
@@ -1350,6 +1408,20 @@ UNUSUAL_DEV( 0x0f19, 0x0105, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Jeremy Katz <katzj@redhat.com>:
+ * The Blackberry Pearl can run in two modes; a usb-storage only mode
+ * and a mode that allows access via mass storage and to its database.
+ * The berry_charge module will set the device to dual mode and thus we
+ * should ignore its native mode if that module is built
+ */
+#ifdef CONFIG_USB_BERRY_CHARGE
+UNUSUAL_DEV( 0x0fca, 0x0006, 0x0001, 0x0001,
+ "RIM",
+ "Blackberry Pearl",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
+#endif
+
/* Reported by Michael Stattmann <michael@stattmann.com> */
UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
"Sony Ericsson",
@@ -1365,6 +1437,13 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+/* Reported by Ricardo Barberis <ricardo@dattatec.com> */
+UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P1i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
"Sony Ericsson",
@@ -1384,6 +1463,17 @@ UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
0 ),
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999,
+ "Sierra Wireless",
+ "USB MMC Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE),
+
/* Reported by Jaco Kroon <jaco@kroon.co.za>
* The usb-storage module found on the Digitech GNX4 (and supposedly other
* devices) misbehaves and causes a bunch of invalid I/O errors.
@@ -1394,6 +1484,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
"Minolta",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 28842d208bb0..3451e8d03ab0 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -112,13 +112,6 @@ module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
-/* These are used to make sure the module doesn't unload before all the
- * threads have exited.
- */
-static atomic_t total_threads = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(threads_gone);
-
-
/*
* The entries in this table correspond, line for line,
* with the entries of us_unusual_dev_list[].
@@ -191,14 +184,16 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
-
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
+ US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
+ /* When runtime PM is working, we'll set a flag to indicate
+ * whether we should autoresume when a SCSI request arrives. */
+
mutex_unlock(&us->dev_mutex);
return 0;
}
@@ -207,11 +202,13 @@ static int storage_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __FUNCTION__);
+ mutex_lock(&us->dev_mutex);
+ US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
+ mutex_unlock(&us->dev_mutex);
return 0;
}
@@ -309,7 +306,6 @@ static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
- int autopm_rc;
for(;;) {
US_DEBUGP("*** thread sleeping.\n");
@@ -318,9 +314,6 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("*** thread awakened.\n");
- /* Autoresume the device */
- autopm_rc = usb_autopm_get_interface(us->pusb_intf);
-
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
@@ -379,12 +372,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = SAM_STAT_GOOD;
}
- /* Did the autoresume fail? */
- else if (autopm_rc < 0) {
- US_DEBUGP("Could not wake device\n");
- us->srb->result = DID_ERROR << 16;
- }
-
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
@@ -427,10 +414,6 @@ SkipForAbort:
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
-
- /* Start an autosuspend */
- if (autopm_rc == 0)
- usb_autopm_put_interface(us->pusb_intf);
} /* for (;;) */
/* Wait until we are told to stop */
@@ -879,9 +862,6 @@ static void quiesce_and_remove_host(struct us_data *us)
usb_stor_stop_transport(us);
wake_up(&us->delay_wait);
- /* It doesn't matter if the SCSI-scanning thread is still running.
- * The thread will exit when it sees the DISCONNECTING flag. */
-
/* queuecommand won't accept any new commands and the control
* thread won't execute a previously-queued command. If there
* is such a command pending, complete it with an error. */
@@ -891,12 +871,16 @@ static void quiesce_and_remove_host(struct us_data *us)
scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
+ complete(&us->notify); /* in case of an abort */
scsi_unlock(host);
}
mutex_unlock(&us->dev_mutex);
/* Now we own no commands so it's safe to remove the SCSI host */
scsi_remove_host(host);
+
+ /* Wait for the SCSI-scanning thread to stop */
+ wait_for_completion(&us->scanning_done);
}
/* Second stage of disconnect processing: deallocate all resources */
@@ -947,9 +931,7 @@ retry:
/* Should we unbind if no devices were detected? */
}
- scsi_host_put(us_to_host(us));
- usb_autopm_put_interface(us->pusb_intf);
- complete_and_exit(&threads_gone, 0);
+ complete_and_exit(&us->scanning_done, 0);
}
@@ -978,12 +960,17 @@ static int storage_probe(struct usb_interface *intf,
return -ENOMEM;
}
+ /*
+ * Allow 16-byte CDBs and thus > 2TB
+ */
+ host->max_cmd_len = 16;
us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
init_MUTEX_LOCKED(&(us->sema));
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
+ init_completion(&us->scanning_done);
/* Associate the us_data structure with the USB device */
result = associate_dev(us, intf);
@@ -1033,12 +1020,6 @@ static int storage_probe(struct usb_interface *intf,
goto BadDevice;
}
- /* Take a reference to the host for the scanning thread and
- * count it among all the threads we have launched. Then
- * start it up. */
- scsi_host_get(us_to_host(us));
- atomic_inc(&total_threads);
- usb_autopm_get_interface(intf); /* dropped in the scanning thread */
wake_up_process(th);
return 0;
@@ -1076,7 +1057,6 @@ static struct usb_driver usb_storage_driver = {
.pre_reset = storage_pre_reset,
.post_reset = storage_post_reset,
.id_table = storage_usb_ids,
- .supports_autosuspend = 1,
};
static int __init usb_stor_init(void)
@@ -1104,16 +1084,6 @@ static void __exit usb_stor_exit(void)
US_DEBUGP("-- calling usb_deregister()\n");
usb_deregister(&usb_storage_driver) ;
- /* Don't return until all of our control and scanning threads
- * have exited. Since each thread signals threads_gone as its
- * last act, we have to call wait_for_completion the right number
- * of times.
- */
- while (atomic_read(&total_threads) > 0) {
- wait_for_completion(&threads_gone);
- atomic_dec(&total_threads);
- }
-
usb_usual_clear_present(USB_US_TYPE_STOR);
}
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 6445665b1577..8d87503e2560 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -150,6 +150,7 @@ struct us_data {
struct semaphore sema; /* to sleep thread on */
struct completion notify; /* thread begin/end */
wait_queue_head_t delay_wait; /* wait during scan, reset */
+ struct completion scanning_done; /* wait for scan thread */
/* subdriver information */
void *extra; /* Any extra data */
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8de11deb5d14..c815a40e167f 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file)
/* save our object in the file's private structure */
file->private_data = dev;
+ mutex_unlock(&dev->io_mutex);
exit:
return retval;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0c5644bb59af..5216c11d4dec 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -12,6 +12,13 @@ config VGASTATE
tristate
default n
+config VIDEO_OUTPUT_CONTROL
+ tristate "Lowlevel video output switch controls"
+ default m
+ help
+ This framework adds support for low-level control of the video
+ output switch.
+
config FB
tristate "Support for frame buffer devices"
---help---
@@ -849,6 +856,16 @@ config FB_INTSRAM
Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
to let frame buffer in external SDRAM.
+config FB_ATMEL_STN
+ bool "Use a STN display with AT91/AT32 LCD Controller"
+ depends on FB_ATMEL && MACH_AT91SAM9261EK
+ default n
+ help
+ Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
+ Controller. Say N if you want to connect a TFT.
+
+ If unsure, say N.
+
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
@@ -1554,7 +1571,14 @@ config FB_PM3
config FB_AU1100
bool "Au1100 LCD Driver"
- depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+ depends on (FB = y) && MIPS && SOC_AU1100
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the framebuffer driver for the AMD Au1100 SOC. It can drive
+ various panels and CRTs by passing in kernel cmd line option
+ au1100fb:panel=<name>.
config FB_AU1200
bool "Au1200 LCD Driver"
@@ -1621,18 +1645,6 @@ config FB_MAXINE
DECstation series (Personal DECstation 5000/20, /25, /33, /50,
Codename "Maxine").
-config FB_TX3912
- bool "TMPTX3912/PR31700 frame buffer support"
- depends on (FB = y) && NINO
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- help
- The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core
- see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>.
-
- Say Y here to enable kernel support for the on-board framebuffer.
-
config FB_G364
bool "G364 frame buffer support"
depends on (FB = y) && (MIPS_MAGNUM_4000 || OLIVETTI_M700)
@@ -1796,13 +1808,14 @@ config FB_PS3
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
+ select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
---help---
Include support for the virtual frame buffer in the PS3 platform.
config FB_PS3_DEFAULT_SIZE_M
int "PS3 default frame buffer size (in MiB)"
depends on FB_PS3
- default 18
+ default 9
---help---
This is the default size (in MiB) of the virtual frame buffer in
the PS3.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a562f9d69d2c..06eec7b182b7 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -103,7 +103,6 @@ obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o
obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o
obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o
-obj-$(CONFIG_FB_TX3912) += tx3912fb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
@@ -123,3 +122,6 @@ obj-$(CONFIG_FB_OF) += offb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
+
+#video output switch sysfs driver
+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 61a8bf159cb0..eedb8285e32f 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -138,17 +138,6 @@ static struct pixclock arc_clocks[] = {
{ 41250, 42083, VIDC_CTRL_DIV1, VID_CTL_24MHz }, /* 24.000MHz */
};
-#ifdef CONFIG_ARCH_A5K
-static struct pixclock a5k_clocks[] = {
- { 117974, 120357, VIDC_CTRL_DIV3, VID_CTL_25MHz }, /* 8.392MHz */
- { 78649, 80238, VIDC_CTRL_DIV2, VID_CTL_25MHz }, /* 12.588MHz */
- { 58987, 60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz }, /* 16.588MHz */
- { 55000, 56111, VIDC_CTRL_DIV2, VID_CTL_36MHz }, /* 18.000MHz */
- { 39325, 40119, VIDC_CTRL_DIV1, VID_CTL_25MHz }, /* 25.175MHz */
- { 27500, 28055, VIDC_CTRL_DIV1, VID_CTL_36MHz }, /* 36.000MHz */
-};
-#endif
-
static struct pixclock *
acornfb_valid_pixrate(struct fb_var_screeninfo *var)
{
@@ -163,15 +152,6 @@ acornfb_valid_pixrate(struct fb_var_screeninfo *var)
pixclock < arc_clocks[i].max_clock)
return arc_clocks + i;
-#ifdef CONFIG_ARCH_A5K
- if (machine_is_a5k()) {
- for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
- if (pixclock > a5k_clocks[i].min_clock &&
- pixclock < a5k_clocks[i].max_clock)
- return a5k_clocks + i;
- }
-#endif
-
return NULL;
}
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 6c9dc2e69c82..a7a1c891bfa2 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -447,13 +447,12 @@ static int clcdfb_probe(struct amba_device *dev, void *id)
goto out;
}
- fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+ fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
if (!fb) {
printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
ret = -ENOMEM;
goto free_region;
}
- memset(fb, 0, sizeof(struct clcd_fb));
fb->dev = dev;
fb->board = board;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index e1d5bd0c98c4..235b618b4117 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -79,6 +79,29 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+{
+ unsigned long value;
+
+ if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+ return xres;
+
+ value = xres;
+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+ /* STN display */
+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+ value *= 3;
+ }
+ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+ value = DIV_ROUND_UP(value, 4);
+ else
+ value = DIV_ROUND_UP(value, 8);
+ }
+
+ return value;
+}
static void atmel_lcdfb_update_dma(struct fb_info *info,
struct fb_var_screeninfo *var)
@@ -181,6 +204,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->xoffset = var->yoffset = 0;
switch (var->bits_per_pixel) {
+ case 1:
case 2:
case 4:
case 8:
@@ -195,8 +219,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->blue.offset = 10;
var->red.length = var->green.length = var->blue.length = 5;
break;
- case 24:
case 32:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ /* fall through */
+ case 24:
var->red.offset = 0;
var->green.offset = 8;
var->blue.offset = 16;
@@ -228,8 +255,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
static int atmel_lcdfb_set_par(struct fb_info *info)
{
struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned long hozval_linesz;
unsigned long value;
unsigned long clk_value_khz;
+ unsigned long bits_per_line;
dev_dbg(info->device, "%s:\n", __func__);
dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
@@ -241,12 +270,15 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
- if (info->var.bits_per_pixel <= 8)
+ if (info->var.bits_per_pixel == 1)
+ info->fix.visual = FB_VISUAL_MONO01;
+ else if (info->var.bits_per_pixel <= 8)
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
else
info->fix.visual = FB_VISUAL_TRUECOLOR;
- info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+ bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+ info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
/* Re-initialize the DMA engine... */
dev_dbg(info->device, " * update DMA engine\n");
@@ -262,18 +294,21 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Set pixel clock */
clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
- value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
-
- if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
- value++;
+ 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) {
dev_notice(info->device, "Bypassing pixel clock divider\n");
lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
- } else
+ } else {
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));
+ }
+
/* Initialize control register 2 */
value = sinfo->default_lcdcon2;
@@ -311,9 +346,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+ /* Horizontal value (aka line size) */
+ hozval_linesz = compute_hozval(info->var.xres,
+ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+
/* Display size */
- value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
value |= info->var.yres - 1;
+ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
/* FIFO Threshold: Use formula from data sheet */
@@ -421,6 +461,15 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
ret = 0;
}
break;
+
+ case FB_VISUAL_MONO01:
+ if (regno < 2) {
+ val = (regno == 0) ? 0x00 : 0x1F;
+ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+ ret = 0;
+ }
+ break;
+
}
return ret;
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index 685a754991c6..dca2eb8f2dde 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -192,6 +192,12 @@
#define PCI_CHIP_RS300_5835 0x5835
#define PCI_CHIP_RS300_5836 0x5836
#define PCI_CHIP_RS300_5837 0x5837
+#define PCI_CHIP_RS480_5955 0x5955
+#define PCI_CHIP_RV280_5960 0x5960
+#define PCI_CHIP_RV280_5961 0x5961
+#define PCI_CHIP_RV280_5962 0x5962
+#define PCI_CHIP_RV280_5964 0x5964
+#define PCI_CHIP_RS482_5975 0x5975
#define PCI_CHIP_RV370_5B60 0x5B60
#define PCI_CHIP_RV370_5B61 0x5B61
#define PCI_CHIP_RV370_5B62 0x5B62
@@ -200,14 +206,8 @@
#define PCI_CHIP_RV370_5B65 0x5B65
#define PCI_CHIP_RV370_5B66 0x5B66
#define PCI_CHIP_RV370_5B67 0x5B67
-#define PCI_CHIP_RV280_5960 0x5960
-#define PCI_CHIP_RV280_5961 0x5961
-#define PCI_CHIP_RV280_5962 0x5962
-#define PCI_CHIP_RV280_5964 0x5964
-#define PCI_CHIP_RS485_5975 0x5975
#define PCI_CHIP_RV280_5C61 0x5C61
#define PCI_CHIP_RV280_5C63 0x5C63
#define PCI_CHIP_R423_5D57 0x5D57
#define PCI_CHIP_RS350_7834 0x7834
#define PCI_CHIP_RS350_7835 0x7835
-#define PCI_CHIP_RS480_5955 0x5955
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 7fea4d8ae8e2..cfcbe37d2d70 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1733,7 +1733,7 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
static int aty128_bl_update_status(struct backlight_device *bd)
{
- struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+ struct aty128fb_par *par = bl_get_data(bd);
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
int level;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index ef330e34d031..bc6f0096aa04 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2141,7 +2141,7 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
static int aty_bl_update_status(struct backlight_device *bd)
{
- struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+ struct atyfb_par *par = bl_get_data(bd);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
int level;
@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
int node, len, i, j, ret;
u32 mem, chip_id;
- /* Do not attach when we have a serial console. */
- if (!con_is_present())
- return -ENXIO;
-
/*
* Map memory-mapped registers.
*/
@@ -2937,12 +2933,11 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
/* nothing */ ;
j = i + 4;
- par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
+ par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);
if (!par->mmap_map) {
PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
return -ENOMEM;
}
- memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
struct resource *rp = &pdev->resource[i];
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 0be25fa5540c..1a056adb61c8 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -47,7 +47,7 @@ static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
static int radeon_bl_update_status(struct backlight_device *bd)
{
- struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+ struct radeon_bl_privdata *pdata = bl_get_data(bd);
struct radeonfb_info *rinfo = pdata->rinfo;
u32 lvds_gen_cntl, tmpPixclksCntl;
int level;
@@ -206,7 +206,7 @@ void radeonfb_bl_exit(struct radeonfb_info *rinfo)
if (bd) {
struct radeon_bl_privdata *pdata;
- pdata = class_get_devdata(&bd->class_dev);
+ pdata = bl_get_data(bd);
backlight_device_unregister(bd);
kfree(pdata);
rinfo->info->bl_dev = NULL;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 47ca62fe7c3e..4b747bdaeea6 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -102,6 +102,7 @@
static struct pci_device_id radeonfb_pci_table[] = {
/* Radeon Xpress 200m */
CHIP_DEF(PCI_CHIP_RS480_5955, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+ CHIP_DEF(PCI_CHIP_RS482_5975, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* Mobility M6 */
CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
@@ -153,8 +154,6 @@ static struct pci_device_id radeonfb_pci_table[] = {
/* Mobility 9200 (M9+) */
CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
- /*Mobility Xpress 200 */
- CHIP_DEF(PCI_CHIP_RS485_5975, R300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* 9200 */
CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2),
@@ -1285,7 +1284,8 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
if (rinfo->family == CHIP_FAMILY_R300 ||
rinfo->family == CHIP_FAMILY_RS300 ||
rinfo->family == CHIP_FAMILY_R350 ||
- rinfo->family == CHIP_FAMILY_RV350) {
+ rinfo->family == CHIP_FAMILY_RV350 ||
+ rinfo->family == CHIP_FAMILY_RV380 ) {
if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
/* When restoring console mode, use saved PPLL_REF_DIV
* setting.
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 80a81eccad36..832e4613673a 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -115,6 +115,52 @@ static int nocursor = 0;
module_param(nocursor, int, 0644);
MODULE_PARM_DESC(nocursor, "cursor enable/disable");
+/* fb_blank
+ * Blank the screen. Depending on the mode, the screen will be
+ * activated with the backlight color, or desactivated
+ */
+static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+ struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
+
+ print_dbg("fb_blank %d %p", blank_mode, fbi);
+
+ switch (blank_mode) {
+
+ case VESA_NO_BLANKING:
+ /* Turn on panel */
+ fbdev->regs->lcd_control |= LCD_CONTROL_GO;
+#ifdef CONFIG_MIPS_PB1100
+ if (drv_info.panel_idx == 1) {
+ au_writew(au_readw(PB1100_G_CONTROL)
+ | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
+ PB1100_G_CONTROL);
+ }
+#endif
+ au_sync();
+ break;
+
+ case VESA_VSYNC_SUSPEND:
+ case VESA_HSYNC_SUSPEND:
+ case VESA_POWERDOWN:
+ /* Turn off panel */
+ fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
+#ifdef CONFIG_MIPS_PB1100
+ if (drv_info.panel_idx == 1) {
+ au_writew(au_readw(PB1100_G_CONTROL)
+ & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
+ PB1100_G_CONTROL);
+ }
+#endif
+ au_sync();
+ break;
+ default:
+ break;
+
+ }
+ return 0;
+}
+
/*
* Set hardware with var settings. This will enable the controller with a specific
* mode, normally validated with the fb_check_var method
@@ -272,52 +318,6 @@ int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned
return 0;
}
-/* fb_blank
- * Blank the screen. Depending on the mode, the screen will be
- * activated with the backlight color, or desactivated
- */
-int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
-{
- struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
-
- print_dbg("fb_blank %d %p", blank_mode, fbi);
-
- switch (blank_mode) {
-
- case VESA_NO_BLANKING:
- /* Turn on panel */
- fbdev->regs->lcd_control |= LCD_CONTROL_GO;
-#ifdef CONFIG_MIPS_PB1100
- if (drv_info.panel_idx == 1) {
- au_writew(au_readw(PB1100_G_CONTROL)
- | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
- PB1100_G_CONTROL);
- }
-#endif
- au_sync();
- break;
-
- case VESA_VSYNC_SUSPEND:
- case VESA_HSYNC_SUSPEND:
- case VESA_POWERDOWN:
- /* Turn off panel */
- fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
-#ifdef CONFIG_MIPS_PB1100
- if (drv_info.panel_idx == 1) {
- au_writew(au_readw(PB1100_G_CONTROL)
- & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
- PB1100_G_CONTROL);
- }
-#endif
- au_sync();
- break;
- default:
- break;
-
- }
- return 0;
-}
-
/* fb_pan_display
* Pan display in x and/or y as specified
*/
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index dbf4ec3f6d57..03e57ef88378 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1589,11 +1589,10 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
return -EFAULT;
}
- fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
if (!fbi->pseudo_palette) {
return -ENOMEM;
}
- memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
print_err("Fail to allocate colormap (%d entries)",
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index fbef663fc057..9609a6c676be 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -8,37 +8,56 @@ menuconfig BACKLIGHT_LCD_SUPPORT
Enable this to be able to choose the drivers for controlling the
backlight and the LCD panel on some platforms, for example on PDAs.
-config BACKLIGHT_CLASS_DEVICE
- tristate "Lowlevel Backlight controls"
+#
+# LCD
+#
+config LCD_CLASS_DEVICE
+ tristate "Lowlevel LCD controls"
depends on BACKLIGHT_LCD_SUPPORT
default m
help
- This framework adds support for low-level control of the LCD
- backlight. This includes support for brightness and power.
+ This framework adds support for low-level control of LCD.
+ Some framebuffer devices connect to platform-specific LCD modules
+ in order to have a platform-specific way to control the flat panel
+ (contrast and applying power to the LCD (not to the backlight!)).
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
-config LCD_CLASS_DEVICE
- tristate "Lowlevel LCD controls"
+config LCD_LTV350QV
+ tristate "Samsung LTV350QV LCD Panel"
+ depends on LCD_CLASS_DEVICE && SPI_MASTER
+ default n
+ help
+ If you have a Samsung LTV350QV LCD panel, say y to include a
+ power control driver for it. The panel starts up in power
+ off state, so you need this driver in order to see any
+ output.
+
+ The LTV350QV panel is present on all ATSTK1000 boards.
+
+#
+# Backlight
+#
+config BACKLIGHT_CLASS_DEVICE
+ tristate "Lowlevel Backlight controls"
depends on BACKLIGHT_LCD_SUPPORT
default m
help
- This framework adds support for low-level control of LCD.
- Some framebuffer devices connect to platform-specific LCD modules
- in order to have a platform-specific way to control the flat panel
- (contrast and applying power to the LCD (not to the backlight!)).
+ This framework adds support for low-level control of the LCD
+ backlight. This includes support for brightness and power.
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
config BACKLIGHT_CORGI
- tristate "Sharp Corgi Backlight Driver (SL Series)"
- depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
- default y
+ tristate "Generic (aka Sharp Corgi) Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
help
- If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
- backlight driver.
+ Say y to enable the generic platform backlight driver previously
+ known as the Corgi backlight driver. If you have a Sharp Zaurus
+ SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n.
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index c6e2266f63e2..965a78b18118 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,6 +1,8 @@
# Backlight & LCD drivers
obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
+obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
+
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 7e06223bca94..4840fe217e4d 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -69,18 +69,20 @@ static inline void backlight_unregister_fb(struct backlight_device *bd)
}
#endif /* CONFIG_FB */
-static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_power(struct device *dev,
+ struct device_attribute *attr,char *buf)
{
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.power);
}
-static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_power(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
int power = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -101,18 +103,20 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf,
return rc;
}
-static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.brightness);
}
-static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_brightness(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
int brightness = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -138,18 +142,19 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char
return rc;
}
-static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_max_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.max_brightness);
}
-static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
- char *buf)
+static ssize_t backlight_show_actual_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
mutex_lock(&bd->ops_lock);
if (bd->ops && bd->ops->get_brightness)
@@ -159,31 +164,22 @@ static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
return rc;
}
-static void backlight_class_release(struct class_device *dev)
+static struct class *backlight_class;
+
+static void bl_device_release(struct device *dev)
{
struct backlight_device *bd = to_backlight_device(dev);
kfree(bd);
}
-static struct class backlight_class = {
- .name = "backlight",
- .release = backlight_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store) \
-{ \
- .attr = { .name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-}
-
-static const struct class_device_attribute bl_class_device_attributes[] = {
- DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
- DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
+static struct device_attribute bl_device_attributes[] = {
+ __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
+ __ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
- DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
+ __ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
NULL),
- DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+ __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+ __ATTR_NULL,
};
/**
@@ -191,22 +187,20 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
* backlight_device class.
* @name: the name of the new object(must be the same as the name of the
* respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- * methods may retrieve it by using class_get_devdata(&bd->class_dev).
+ * @devdata: an optional pointer to be stored for private driver use. The
+ * methods may retrieve it by using bl_get_data(bd).
* @ops: the backlight operations structure.
*
- * Creates and registers new backlight class_device. Returns either an
+ * Creates and registers new backlight device. Returns either an
* ERR_PTR() or a pointer to the newly allocated device.
*/
struct backlight_device *backlight_device_register(const char *name,
- struct device *dev,
- void *devdata,
- struct backlight_ops *ops)
+ struct device *parent, void *devdata, struct backlight_ops *ops)
{
- int i, rc;
struct backlight_device *new_bd;
+ int rc;
- pr_debug("backlight_device_alloc: name=%s\n", name);
+ pr_debug("backlight_device_register: name=%s\n", name);
new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
if (!new_bd)
@@ -214,13 +208,14 @@ struct backlight_device *backlight_device_register(const char *name,
mutex_init(&new_bd->update_lock);
mutex_init(&new_bd->ops_lock);
- new_bd->ops = ops;
- new_bd->class_dev.class = &backlight_class;
- new_bd->class_dev.dev = dev;
- strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
- class_set_devdata(&new_bd->class_dev, devdata);
- rc = class_device_register(&new_bd->class_dev);
+ new_bd->dev.class = backlight_class;
+ new_bd->dev.parent = parent;
+ new_bd->dev.release = bl_device_release;
+ strlcpy(new_bd->dev.bus_id, name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_bd->dev, devdata);
+
+ rc = device_register(&new_bd->dev);
if (rc) {
kfree(new_bd);
return ERR_PTR(rc);
@@ -228,23 +223,11 @@ struct backlight_device *backlight_device_register(const char *name,
rc = backlight_register_fb(new_bd);
if (rc) {
- class_device_unregister(&new_bd->class_dev);
+ device_unregister(&new_bd->dev);
return ERR_PTR(rc);
}
-
- for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
- rc = class_device_create_file(&new_bd->class_dev,
- &bl_class_device_attributes[i]);
- if (rc) {
- while (--i >= 0)
- class_device_remove_file(&new_bd->class_dev,
- &bl_class_device_attributes[i]);
- class_device_unregister(&new_bd->class_dev);
- /* No need to kfree(new_bd) since release() method was called */
- return ERR_PTR(rc);
- }
- }
+ new_bd->ops = ops;
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
@@ -265,42 +248,40 @@ EXPORT_SYMBOL(backlight_device_register);
*/
void backlight_device_unregister(struct backlight_device *bd)
{
- int i;
-
if (!bd)
return;
- pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
-
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight == bd)
pmac_backlight = NULL;
mutex_unlock(&pmac_backlight_mutex);
#endif
-
- for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
- class_device_remove_file(&bd->class_dev,
- &bl_class_device_attributes[i]);
-
mutex_lock(&bd->ops_lock);
bd->ops = NULL;
mutex_unlock(&bd->ops_lock);
backlight_unregister_fb(bd);
-
- class_device_unregister(&bd->class_dev);
+ device_unregister(&bd->dev);
}
EXPORT_SYMBOL(backlight_device_unregister);
static void __exit backlight_class_exit(void)
{
- class_unregister(&backlight_class);
+ class_destroy(backlight_class);
}
static int __init backlight_class_init(void)
{
- return class_register(&backlight_class);
+ backlight_class = class_create(THIS_MODULE, "backlight");
+ if (IS_ERR(backlight_class)) {
+ printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+ PTR_ERR(backlight_class));
+ return PTR_ERR(backlight_class);
+ }
+
+ backlight_class->dev_attrs = bl_device_attributes;
+ return 0;
}
/*
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index ce00e18a4e5d..4d4d037e3ec9 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -18,13 +18,11 @@
#include <linux/mutex.h>
#include <linux/fb.h>
#include <linux/backlight.h>
-#include <asm/arch/sharpsl.h>
-#include <asm/hardware/sharpsl_pm.h>
static int corgibl_intensity;
static struct backlight_properties corgibl_data;
static struct backlight_device *corgi_backlight_device;
-static struct corgibl_machinfo *bl_machinfo;
+static struct generic_bl_info *bl_machinfo;
static unsigned long corgibl_flags;
#define CORGIBL_SUSPENDED 0x01
@@ -32,7 +30,6 @@ static unsigned long corgibl_flags;
static int corgibl_send_intensity(struct backlight_device *bd)
{
- void (*corgi_kick_batt)(void);
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
@@ -48,11 +45,8 @@ static int corgibl_send_intensity(struct backlight_device *bd)
corgibl_intensity = intensity;
- corgi_kick_batt = symbol_get(sharpsl_battery_kick);
- if (corgi_kick_batt) {
- corgi_kick_batt();
- symbol_put(sharpsl_battery_kick);
- }
+ if (bl_machinfo->kick_battery)
+ bl_machinfo->kick_battery();
return 0;
}
@@ -107,13 +101,17 @@ static struct backlight_ops corgibl_ops = {
static int corgibl_probe(struct platform_device *pdev)
{
- struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
+ struct generic_bl_info *machinfo = pdev->dev.platform_data;
+ const char *name = "generic-bl";
bl_machinfo = machinfo;
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
- corgi_backlight_device = backlight_device_register ("corgi-bl",
+ if (machinfo->name)
+ name = machinfo->name;
+
+ corgi_backlight_device = backlight_device_register (name,
&pdev->dev, NULL, &corgibl_ops);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
@@ -149,7 +147,7 @@ static struct platform_driver corgibl_driver = {
.suspend = corgibl_suspend,
.resume = corgibl_resume,
.driver = {
- .name = "corgi-bl",
+ .name = "generic-bl",
},
};
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index e9bbc3455c94..92e201e81fbd 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -171,13 +171,11 @@ static struct lcd_ops cr_lcd_ops = {
static int cr_backlight_probe(struct platform_device *pdev)
{
+ struct backlight_device *bdp;
+ struct lcd_device *ldp;
struct cr_panel *crp;
u8 dev_en;
- crp = kzalloc(sizeof(crp), GFP_KERNEL);
- if (crp == NULL)
- return -ENOMEM;
-
lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
CRVML_DEVICE_LPC, NULL);
if (!lpc_dev) {
@@ -193,27 +191,34 @@ static int cr_backlight_probe(struct platform_device *pdev)
return -ENODEV;
}
- crp->cr_backlight_device = backlight_device_register("cr-backlight",
- &pdev->dev, NULL,
- &cr_backlight_ops);
- if (IS_ERR(crp->cr_backlight_device)) {
+ bdp = backlight_device_register("cr-backlight",
+ &pdev->dev, NULL, &cr_backlight_ops);
+ if (IS_ERR(bdp)) {
pci_dev_put(lpc_dev);
- return PTR_ERR(crp->cr_backlight_device);
+ return PTR_ERR(bdp);
}
- crp->cr_lcd_device = lcd_device_register("cr-lcd",
- &pdev->dev,
- &cr_lcd_ops);
-
- if (IS_ERR(crp->cr_lcd_device)) {
+ ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops);
+ if (IS_ERR(ldp)) {
+ backlight_device_unregister(bdp);
pci_dev_put(lpc_dev);
- return PTR_ERR(crp->cr_backlight_device);
+ return PTR_ERR(bdp);
}
pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
&gpio_bar);
gpio_bar &= ~0x3F;
+ crp = kzalloc(sizeof(*crp), GFP_KERNEL);
+ if (!crp) {
+ lcd_device_unregister(ldp);
+ backlight_device_unregister(bdp);
+ pci_dev_put(lpc_dev);
+ return -ENOMEM;
+ }
+
+ crp->cr_backlight_device = bdp;
+ crp->cr_lcd_device = ldp;
crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
crp->cr_backlight_device->props.brightness = 0;
crp->cr_backlight_device->props.max_brightness = 0;
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 648b53c1fdea..299fd318dd45 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -61,10 +61,11 @@ static inline void lcd_unregister_fb(struct lcd_device *ld)
}
#endif /* CONFIG_FB */
-static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
int rc;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->get_power)
@@ -76,11 +77,12 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
return rc;
}
-static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_power(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
int power = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -100,10 +102,11 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
return rc;
}
-static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_contrast(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->get_contrast)
@@ -113,11 +116,12 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
return rc;
}
-static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_contrast(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
int contrast = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -137,53 +141,45 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
return rc;
}
-static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_max_contrast(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
return sprintf(buf, "%d\n", ld->props.max_contrast);
}
-static void lcd_class_release(struct class_device *dev)
+static struct class *lcd_class;
+
+static void lcd_device_release(struct device *dev)
{
struct lcd_device *ld = to_lcd_device(dev);
kfree(ld);
}
-static struct class lcd_class = {
- .name = "lcd",
- .release = lcd_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store) \
-{ \
- .attr = { .name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-}
-
-static const struct class_device_attribute lcd_class_device_attributes[] = {
- DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
- DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
- DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+static struct device_attribute lcd_device_attributes[] = {
+ __ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
+ __ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+ __ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+ __ATTR_NULL,
};
/**
* lcd_device_register - register a new object of lcd_device class.
* @name: the name of the new object(must be the same as the name of the
* respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- * methods may retrieve it by using class_get_devdata(ld->class_dev).
+ * @devdata: an optional pointer to be stored in the device. The
+ * methods may retrieve it by using lcd_get_data(ld).
* @ops: the lcd operations structure.
*
- * Creates and registers a new lcd class_device. Returns either an ERR_PTR()
+ * Creates and registers a new lcd device. Returns either an ERR_PTR()
* or a pointer to the newly allocated device.
*/
-struct lcd_device *lcd_device_register(const char *name, void *devdata,
- struct lcd_ops *ops)
+struct lcd_device *lcd_device_register(const char *name, struct device *parent,
+ void *devdata, struct lcd_ops *ops)
{
- int i, rc;
struct lcd_device *new_ld;
+ int rc;
pr_debug("lcd_device_register: name=%s\n", name);
@@ -193,12 +189,14 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata,
mutex_init(&new_ld->ops_lock);
mutex_init(&new_ld->update_lock);
- new_ld->ops = ops;
- new_ld->class_dev.class = &lcd_class;
- strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
- class_set_devdata(&new_ld->class_dev, devdata);
- rc = class_device_register(&new_ld->class_dev);
+ new_ld->dev.class = lcd_class;
+ new_ld->dev.parent = parent;
+ new_ld->dev.release = lcd_device_release;
+ strlcpy(new_ld->dev.bus_id, name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_ld->dev, devdata);
+
+ rc = device_register(&new_ld->dev);
if (rc) {
kfree(new_ld);
return ERR_PTR(rc);
@@ -206,22 +204,11 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata,
rc = lcd_register_fb(new_ld);
if (rc) {
- class_device_unregister(&new_ld->class_dev);
+ device_unregister(&new_ld->dev);
return ERR_PTR(rc);
}
- for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
- rc = class_device_create_file(&new_ld->class_dev,
- &lcd_class_device_attributes[i]);
- if (rc) {
- while (--i >= 0)
- class_device_remove_file(&new_ld->class_dev,
- &lcd_class_device_attributes[i]);
- class_device_unregister(&new_ld->class_dev);
- /* No need to kfree(new_ld) since release() method was called */
- return ERR_PTR(rc);
- }
- }
+ new_ld->ops = ops;
return new_ld;
}
@@ -235,33 +222,34 @@ EXPORT_SYMBOL(lcd_device_register);
*/
void lcd_device_unregister(struct lcd_device *ld)
{
- int i;
-
if (!ld)
return;
- pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id);
-
- for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++)
- class_device_remove_file(&ld->class_dev,
- &lcd_class_device_attributes[i]);
-
mutex_lock(&ld->ops_lock);
ld->ops = NULL;
mutex_unlock(&ld->ops_lock);
lcd_unregister_fb(ld);
- class_device_unregister(&ld->class_dev);
+
+ device_unregister(&ld->dev);
}
EXPORT_SYMBOL(lcd_device_unregister);
static void __exit lcd_class_exit(void)
{
- class_unregister(&lcd_class);
+ class_destroy(lcd_class);
}
static int __init lcd_class_init(void)
{
- return class_register(&lcd_class);
+ lcd_class = class_create(THIS_MODULE, "lcd");
+ if (IS_ERR(lcd_class)) {
+ printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+ PTR_ERR(lcd_class));
+ return PTR_ERR(lcd_class);
+ }
+
+ lcd_class->dev_attrs = lcd_device_attributes;
+ return 0;
}
/*
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
new file mode 100644
index 000000000000..2eb206bf73e6
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.c
@@ -0,0 +1,330 @@
+/*
+ * Power control for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "ltv350qv.h"
+
+#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
+
+struct ltv350qv {
+ struct spi_device *spi;
+ u8 *buffer;
+ int power;
+ struct lcd_device *ld;
+};
+
+/*
+ * The power-on and power-off sequences are taken from the
+ * LTV350QV-F04 data sheet from Samsung. The register definitions are
+ * taken from the S6F2002 command list also from Samsung. Both
+ * documents are distributed with the AVR32 Linux BSP CD from Atmel.
+ *
+ * There's still some voodoo going on here, but it's a lot better than
+ * in the first incarnation of the driver where all we had was the raw
+ * numbers from the initialization sequence.
+ */
+static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val)
+{
+ struct spi_message msg;
+ struct spi_transfer index_xfer = {
+ .len = 3,
+ .cs_change = 1,
+ };
+ struct spi_transfer value_xfer = {
+ .len = 3,
+ };
+
+ spi_message_init(&msg);
+
+ /* register index */
+ lcd->buffer[0] = LTV_OPC_INDEX;
+ lcd->buffer[1] = 0x00;
+ lcd->buffer[2] = reg & 0x7f;
+ index_xfer.tx_buf = lcd->buffer;
+ spi_message_add_tail(&index_xfer, &msg);
+
+ /* register value */
+ lcd->buffer[4] = LTV_OPC_DATA;
+ lcd->buffer[5] = val >> 8;
+ lcd->buffer[6] = val;
+ value_xfer.tx_buf = lcd->buffer + 4;
+ spi_message_add_tail(&value_xfer, &msg);
+
+ return spi_sync(lcd->spi, &msg);
+}
+
+/* The comments are taken straight from the data sheet */
+static int ltv350qv_power_on(struct ltv350qv *lcd)
+{
+ int ret;
+
+ /* Power On Reset Display off State */
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000))
+ goto err;
+ msleep(15);
+
+ /* Power Setting Function 1 */
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE))
+ goto err;
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE))
+ goto err_power1;
+
+ /* Power Setting Function 2 */
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5)))
+ goto err_power2;
+
+ msleep(55);
+
+ /* Instruction Setting */
+ ret = ltv350qv_write_reg(lcd, LTV_IFCTL,
+ LTV_NMD | LTV_REV | LTV_NL(0x1d));
+ ret |= ltv350qv_write_reg(lcd, LTV_DATACTL,
+ LTV_DS_SAME | LTV_CHS_480
+ | LTV_DF_RGB | LTV_RGB_BGR);
+ ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE,
+ LTV_VSPL_ACTIVE_LOW
+ | LTV_HSPL_ACTIVE_LOW
+ | LTV_DPL_SAMPLE_RISING
+ | LTV_EPL_ACTIVE_LOW
+ | LTV_SS_RIGHT_TO_LEFT);
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3));
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_FWI(3));
+ ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a);
+ ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021);
+ ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0));
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000);
+ if (ret)
+ goto err_settings;
+
+ /* Wait more than 2 frames */
+ msleep(20);
+
+ /* Display On Sequence */
+ ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE
+ | LTV_POWER_ON | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5));
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3));
+ if (ret)
+ goto err_disp_on;
+
+ /* Display should now be ON. Phew. */
+ return 0;
+
+err_disp_on:
+ /*
+ * Try to recover. Error handling probably isn't very useful
+ * at this point, just make a best effort to switch the panel
+ * off.
+ */
+ ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5));
+ ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_FWI(3));
+err_settings:
+err_power2:
+err_power1:
+ ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+ msleep(1);
+err:
+ ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+ return -EIO;
+}
+
+static int ltv350qv_power_off(struct ltv350qv *lcd)
+{
+ int ret;
+
+ /* Display Off Sequence */
+ ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE
+ | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5));
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_FWI(3));
+
+ /* Power down setting 1 */
+ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+
+ /* Wait at least 1 ms */
+ msleep(1);
+
+ /* Power down setting 2 */
+ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+
+ /*
+ * No point in trying to recover here. If we can't switch the
+ * panel off, what are we supposed to do other than inform the
+ * user about the failure?
+ */
+ if (ret)
+ return -EIO;
+
+ /* Display power should now be OFF */
+ return 0;
+}
+
+static int ltv350qv_power(struct ltv350qv *lcd, int power)
+{
+ int ret = 0;
+
+ if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+ ret = ltv350qv_power_on(lcd);
+ else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+ ret = ltv350qv_power_off(lcd);
+
+ if (!ret)
+ lcd->power = power;
+
+ return ret;
+}
+
+static int ltv350qv_set_power(struct lcd_device *ld, int power)
+{
+ struct ltv350qv *lcd = lcd_get_data(ld);
+
+ return ltv350qv_power(lcd, power);
+}
+
+static int ltv350qv_get_power(struct lcd_device *ld)
+{
+ struct ltv350qv *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static struct lcd_ops ltv_ops = {
+ .get_power = ltv350qv_get_power,
+ .set_power = ltv350qv_set_power,
+};
+
+static int __devinit ltv350qv_probe(struct spi_device *spi)
+{
+ struct ltv350qv *lcd;
+ struct lcd_device *ld;
+ int ret;
+
+ lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ lcd->spi = spi;
+ lcd->power = FB_BLANK_POWERDOWN;
+ lcd->buffer = kzalloc(8, GFP_KERNEL);
+
+ ld = lcd_device_register("ltv350qv", &spi->dev, lcd, &ltv_ops);
+ if (IS_ERR(ld)) {
+ ret = PTR_ERR(ld);
+ goto out_free_lcd;
+ }
+ lcd->ld = ld;
+
+ ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+ if (ret)
+ goto out_unregister;
+
+ dev_set_drvdata(&spi->dev, lcd);
+
+ return 0;
+
+out_unregister:
+ lcd_device_unregister(ld);
+out_free_lcd:
+ kfree(lcd);
+ return ret;
+}
+
+static int __devexit ltv350qv_remove(struct spi_device *spi)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+ lcd_device_unregister(lcd->ld);
+ kfree(lcd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static int ltv350qv_resume(struct spi_device *spi)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+}
+#else
+#define ltv350qv_suspend NULL
+#define ltv350qv_resume NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt */
+static void ltv350qv_shutdown(struct spi_device *spi)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ltv350qv_driver = {
+ .driver = {
+ .name = "ltv350qv",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ltv350qv_probe,
+ .remove = __devexit_p(ltv350qv_remove),
+ .shutdown = ltv350qv_shutdown,
+ .suspend = ltv350qv_suspend,
+ .resume = ltv350qv_resume,
+};
+
+static int __init ltv350qv_init(void)
+{
+ return spi_register_driver(&ltv350qv_driver);
+}
+
+static void __exit ltv350qv_exit(void)
+{
+ spi_unregister_driver(&ltv350qv_driver);
+}
+module_init(ltv350qv_init);
+module_exit(ltv350qv_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h
new file mode 100644
index 000000000000..189112e3fc7a
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.h
@@ -0,0 +1,95 @@
+/*
+ * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LTV350QV_H
+#define __LTV350QV_H
+
+#define LTV_OPC_INDEX 0x74
+#define LTV_OPC_DATA 0x76
+
+#define LTV_ID 0x00 /* ID Read */
+#define LTV_IFCTL 0x01 /* Display Interface Control */
+#define LTV_DATACTL 0x02 /* Display Data Control */
+#define LTV_ENTRY_MODE 0x03 /* Entry Mode */
+#define LTV_GATECTL1 0x04 /* Gate Control 1 */
+#define LTV_GATECTL2 0x05 /* Gate Control 2 */
+#define LTV_VBP 0x06 /* Vertical Back Porch */
+#define LTV_HBP 0x07 /* Horizontal Back Porch */
+#define LTV_SOTCTL 0x08 /* Source Output Timing Control */
+#define LTV_PWRCTL1 0x09 /* Power Control 1 */
+#define LTV_PWRCTL2 0x0a /* Power Control 2 */
+#define LTV_GAMMA(x) (0x10 + (x)) /* Gamma control */
+
+/* Bit definitions for LTV_IFCTL */
+#define LTV_IM (1 << 15)
+#define LTV_NMD (1 << 14)
+#define LTV_SSMD (1 << 13)
+#define LTV_REV (1 << 7)
+#define LTV_NL(x) (((x) & 0x001f) << 0)
+
+/* Bit definitions for LTV_DATACTL */
+#define LTV_DS_SAME (0 << 12)
+#define LTV_DS_D_TO_S (1 << 12)
+#define LTV_DS_S_TO_D (2 << 12)
+#define LTV_CHS_384 (0 << 9)
+#define LTV_CHS_480 (1 << 9)
+#define LTV_CHS_492 (2 << 9)
+#define LTV_DF_RGB (0 << 6)
+#define LTV_DF_RGBX (1 << 6)
+#define LTV_DF_XRGB (2 << 6)
+#define LTV_RGB_RGB (0 << 2)
+#define LTV_RGB_BGR (1 << 2)
+#define LTV_RGB_GRB (2 << 2)
+#define LTV_RGB_RBG (3 << 2)
+
+/* Bit definitions for LTV_ENTRY_MODE */
+#define LTV_VSPL_ACTIVE_LOW (0 << 15)
+#define LTV_VSPL_ACTIVE_HIGH (1 << 15)
+#define LTV_HSPL_ACTIVE_LOW (0 << 14)
+#define LTV_HSPL_ACTIVE_HIGH (1 << 14)
+#define LTV_DPL_SAMPLE_RISING (0 << 13)
+#define LTV_DPL_SAMPLE_FALLING (1 << 13)
+#define LTV_EPL_ACTIVE_LOW (0 << 12)
+#define LTV_EPL_ACTIVE_HIGH (1 << 12)
+#define LTV_SS_LEFT_TO_RIGHT (0 << 8)
+#define LTV_SS_RIGHT_TO_LEFT (1 << 8)
+#define LTV_STB (1 << 1)
+
+/* Bit definitions for LTV_GATECTL1 */
+#define LTV_CLW(x) (((x) & 0x0007) << 12)
+#define LTV_GAON (1 << 5)
+#define LTV_SDR (1 << 3)
+
+/* Bit definitions for LTV_GATECTL2 */
+#define LTV_NW_INV_FRAME (0 << 14)
+#define LTV_NW_INV_1LINE (1 << 14)
+#define LTV_NW_INV_2LINE (2 << 14)
+#define LTV_DSC (1 << 12)
+#define LTV_GIF (1 << 8)
+#define LTV_FHN (1 << 7)
+#define LTV_FTI(x) (((x) & 0x0003) << 4)
+#define LTV_FWI(x) (((x) & 0x0003) << 0)
+
+/* Bit definitions for LTV_SOTCTL */
+#define LTV_SDT(x) (((x) & 0x0007) << 10)
+#define LTV_EQ(x) (((x) & 0x0007) << 2)
+
+/* Bit definitions for LTV_PWRCTL1 */
+#define LTV_VCOM_DISABLE (1 << 14)
+#define LTV_VCOMOUT_ENABLE (1 << 11)
+#define LTV_POWER_ON (1 << 9)
+#define LTV_DRIVE_CURRENT(x) (((x) & 0x0007) << 4) /* 0=off, 5=max */
+#define LTV_SUPPLY_CURRENT(x) (((x) & 0x0007) << 0) /* 0=off, 5=max */
+
+/* Bit definitions for LTV_PWRCTL2 */
+#define LTV_VCOML_ENABLE (1 << 13)
+#define LTV_VCOML_VOLTAGE(x) (((x) & 0x001f) << 8) /* 0=1V, 31=-1V */
+#define LTV_VCOMH_VOLTAGE(x) (((x) & 0x001f) << 0) /* 0=3V, 31=4.5V */
+
+#endif /* __LTV350QV_H */
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index b0b2e40bbd9f..833b10c84064 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -233,9 +233,9 @@ static u8 bw2regs_66hz[] __devinitdata = {
0x10, 0x20, 0
};
-static void __devinit bw2_do_default_mode(struct bw2_par *par,
- struct fb_info *info,
- int *linebytes)
+static int __devinit bw2_do_default_mode(struct bw2_par *par,
+ struct fb_info *info,
+ int *linebytes)
{
u8 status, mon;
u8 *p;
@@ -266,103 +266,108 @@ static void __devinit bw2_do_default_mode(struct bw2_par *par,
break;
case BWTWO_SR_ID_NOCONN:
- return;
+ return 0;
default:
- prom_printf("bw2: can't handle SR %02x\n",
- status);
- prom_halt();
+ printk(KERN_ERR "bw2: can't handle SR %02x\n",
+ status);
+ return -EINVAL;
}
for ( ; *p; p += 2) {
u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
sbus_writeb(p[1], regp);
}
+ return 0;
}
-struct all_info {
- struct fb_info info;
- struct bw2_par par;
-};
-
-static int __devinit bw2_init_one(struct of_device *op)
+static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct bw2_par *par;
int linebytes, err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
- spin_lock_init(&all->par.lock);
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- all->par.physbase = op->resource[0].start;
- all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+ spin_lock_init(&par->lock);
- sbusfb_fill_var(&all->info.var, dp->node, 1);
- linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
+ par->physbase = op->resource[0].start;
+ par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- all->info.var.red.length = all->info.var.green.length =
- all->info.var.blue.length = all->info.var.bits_per_pixel;
- all->info.var.red.offset = all->info.var.green.offset =
- all->info.var.blue.offset = 0;
-
- all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
- sizeof(struct bw2_regs), "bw2 regs");
-
- if (!of_find_property(dp, "width", NULL))
- bw2_do_default_mode(&all->par, &all->info, &linebytes);
+ sbusfb_fill_var(&info->var, dp->node, 1);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ info->var.xres);
+
+ info->var.red.length = info->var.green.length =
+ info->var.blue.length = info->var.bits_per_pixel;
+ info->var.red.offset = info->var.green.offset =
+ info->var.blue.offset = 0;
+
+ par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
+ sizeof(struct bw2_regs), "bw2 regs");
+ if (!par->regs)
+ goto out_release_fb;
+
+ if (!of_find_property(dp, "width", NULL)) {
+ err = bw2_do_default_mode(par, info, &linebytes);
+ if (err)
+ goto out_unmap_regs;
+ }
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
- all->info.flags = FBINFO_DEFAULT;
- all->info.fbops = &bw2_ops;
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &bw2_ops;
- all->info.screen_base =
- of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
- all->info.par = &all->par;
+ info->screen_base = of_ioremap(&op->resource[0], 0,
+ par->fbsize, "bw2 ram");
+ if (!info->screen_base)
+ goto out_unmap_regs;
- bw2_blank(0, &all->info);
+ bw2_blank(0, info);
- bw2_init_fix(&all->info, linebytes);
+ bw2_init_fix(info, linebytes);
- err= register_framebuffer(&all->info);
- if (err < 0) {
- of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct bw2_regs));
- of_iounmap(&op->resource[0],
- all->info.screen_base, all->par.fbsize);
- kfree(all);
- return err;
- }
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_unmap_screen;
- dev_set_drvdata(&op->dev, all);
+ dev_set_drvdata(&op->dev, info);
printk("%s: bwtwo at %lx:%lx\n",
- dp->full_name,
- all->par.which_io, all->par.physbase);
+ dp->full_name, par->which_io, par->physbase);
return 0;
-}
-static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_unmap_screen:
+ of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+
+out_unmap_regs:
+ of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
+
+out_release_fb:
+ framebuffer_release(info);
- return bw2_init_one(op);
+out_err:
+ return err;
}
static int __devexit bw2_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct bw2_par *par = info->par;
- unregister_framebuffer(&all->info);
+ unregister_framebuffer(info);
- of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs));
- of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
+ of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index b071bb632b97..41f6dbf61be7 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -448,81 +448,79 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = {
{ .size = 0 }
};
-struct all_info {
- struct fb_info info;
- struct cg14_par par;
-};
-
-static void cg14_unmap_regs(struct of_device *op, struct all_info *all)
+static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
+ struct cg14_par *par)
{
- if (all->par.regs)
+ if (par->regs)
of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct cg14_regs));
- if (all->par.clut)
+ par->regs, sizeof(struct cg14_regs));
+ if (par->clut)
of_iounmap(&op->resource[0],
- all->par.clut, sizeof(struct cg14_clut));
- if (all->par.cursor)
+ par->clut, sizeof(struct cg14_clut));
+ if (par->cursor)
of_iounmap(&op->resource[0],
- all->par.cursor, sizeof(struct cg14_cursor));
- if (all->info.screen_base)
+ par->cursor, sizeof(struct cg14_cursor));
+ if (info->screen_base)
of_iounmap(&op->resource[1],
- all->info.screen_base, all->par.fbsize);
+ info->screen_base, par->fbsize);
}
-static int __devinit cg14_init_one(struct of_device *op)
+static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct cg14_par *par;
int is_8mb, linebytes, i, err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev);
+
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- spin_lock_init(&all->par.lock);
+ spin_lock_init(&par->lock);
- sbusfb_fill_var(&all->info.var, dp->node, 8);
- all->info.var.red.length = 8;
- all->info.var.green.length = 8;
- all->info.var.blue.length = 8;
+ sbusfb_fill_var(&info->var, dp->node, 8);
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+ info->var.xres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
if (!strcmp(dp->parent->name, "sbus") ||
!strcmp(dp->parent->name, "sbi")) {
- all->par.physbase = op->resource[0].start;
- all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
+ par->physbase = op->resource[0].start;
+ par->iospace = op->resource[0].flags & IORESOURCE_BITS;
} else {
- all->par.physbase = op->resource[1].start;
- all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
+ par->physbase = op->resource[1].start;
+ par->iospace = op->resource[0].flags & IORESOURCE_BITS;
}
- all->par.regs = of_ioremap(&op->resource[0], 0,
- sizeof(struct cg14_regs), "cg14 regs");
- all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1,
- sizeof(struct cg14_clut), "cg14 clut");
- all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
- sizeof(struct cg14_cursor), "cg14 cursor");
+ par->regs = of_ioremap(&op->resource[0], 0,
+ sizeof(struct cg14_regs), "cg14 regs");
+ par->clut = of_ioremap(&op->resource[0], CG14_CLUT1,
+ sizeof(struct cg14_clut), "cg14 clut");
+ par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
+ sizeof(struct cg14_cursor), "cg14 cursor");
- all->info.screen_base = of_ioremap(&op->resource[1], 0,
- all->par.fbsize, "cg14 ram");
+ info->screen_base = of_ioremap(&op->resource[1], 0,
+ par->fbsize, "cg14 ram");
- if (!all->par.regs || !all->par.clut || !all->par.cursor ||
- !all->info.screen_base)
- cg14_unmap_regs(op, all);
+ if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
+ goto out_unmap_regs;
is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) ==
(8 * 1024 * 1024));
- BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map));
+ BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map));
- memcpy(&all->par.mmap_map, &__cg14_mmap_map,
- sizeof(all->par.mmap_map));
+ memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map));
for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
- struct sbus_mmap_map *map = &all->par.mmap_map[i];
+ struct sbus_mmap_map *map = &par->mmap_map[i];
if (!map->size)
break;
@@ -536,59 +534,55 @@ static int __devinit cg14_init_one(struct of_device *op)
map->size *= 2;
}
- all->par.mode = MDI_8_PIX;
- all->par.ramsize = (is_8mb ? 0x800000 : 0x400000);
+ par->mode = MDI_8_PIX;
+ par->ramsize = (is_8mb ? 0x800000 : 0x400000);
- all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
- all->info.fbops = &cg14_ops;
- all->info.par = &all->par;
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+ info->fbops = &cg14_ops;
- __cg14_reset(&all->par);
+ __cg14_reset(par);
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- cg14_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
- fb_set_cmap(&all->info.cmap, &all->info);
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_regs;
- cg14_init_fix(&all->info, linebytes, dp);
+ fb_set_cmap(&info->cmap, info);
- err = register_framebuffer(&all->info);
- if (err < 0) {
- fb_dealloc_cmap(&all->info.cmap);
- cg14_unmap_regs(op, all);
- kfree(all);
- return err;
- }
+ cg14_init_fix(info, linebytes, dp);
+
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
- dev_set_drvdata(&op->dev, all);
+ dev_set_drvdata(&op->dev, info);
printk("%s: cgfourteen at %lx:%lx, %dMB\n",
dp->full_name,
- all->par.iospace, all->par.physbase,
- all->par.ramsize >> 20);
+ par->iospace, par->physbase,
+ par->ramsize >> 20);
return 0;
-}
-static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_regs:
+ cg14_unmap_regs(op, info, par);
- return cg14_init_one(op);
+out_err:
+ return err;
}
static int __devexit cg14_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct cg14_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- cg14_unmap_regs(op, all);
+ cg14_unmap_regs(op, info, par);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index f042428a84f4..a5c7fb331527 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -315,7 +315,7 @@ static u_char cg3_dacvals[] __devinitdata = {
4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
};
-static void __devinit cg3_do_default_mode(struct cg3_par *par)
+static int __devinit cg3_do_default_mode(struct cg3_par *par)
{
enum cg3_type type;
u8 *p;
@@ -332,10 +332,9 @@ static void __devinit cg3_do_default_mode(struct cg3_par *par)
else
type = CG3_AT_66HZ;
} else {
- prom_printf("cgthree: can't handle SR %02x\n",
- status);
- prom_halt();
- return;
+ printk(KERN_ERR "cgthree: can't handle SR %02x\n",
+ status);
+ return -EINVAL;
}
}
@@ -351,106 +350,108 @@ static void __devinit cg3_do_default_mode(struct cg3_par *par)
regp = (u8 __iomem *)&par->regs->cmap.control;
sbus_writeb(p[1], regp);
}
+ return 0;
}
-struct all_info {
- struct fb_info info;
- struct cg3_par par;
-};
-
-static int __devinit cg3_init_one(struct of_device *op)
+static int __devinit cg3_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct cg3_par *par;
int linebytes, err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);
+
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- spin_lock_init(&all->par.lock);
+ spin_lock_init(&par->lock);
- all->par.physbase = op->resource[0].start;
- all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+ par->physbase = op->resource[0].start;
+ par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, dp->node, 8);
- all->info.var.red.length = 8;
- all->info.var.green.length = 8;
- all->info.var.blue.length = 8;
+ sbusfb_fill_var(&info->var, dp->node, 8);
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
if (!strcmp(dp->name, "cgRDI"))
- all->par.flags |= CG3_FLAG_RDI;
- if (all->par.flags & CG3_FLAG_RDI)
- cg3_rdi_maybe_fixup_var(&all->info.var, dp);
+ par->flags |= CG3_FLAG_RDI;
+ if (par->flags & CG3_FLAG_RDI)
+ cg3_rdi_maybe_fixup_var(&info->var, dp);
linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
-
- all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
- sizeof(struct cg3_regs), "cg3 regs");
-
- all->info.flags = FBINFO_DEFAULT;
- all->info.fbops = &cg3_ops;
- all->info.screen_base =
- of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
- all->par.fbsize, "cg3 ram");
- all->info.par = &all->par;
-
- cg3_blank(0, &all->info);
-
- if (!of_find_property(dp, "width", NULL))
- cg3_do_default_mode(&all->par);
-
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct cg3_regs));
- of_iounmap(&op->resource[0],
- all->info.screen_base, all->par.fbsize);
- kfree(all);
- return -ENOMEM;
- }
- fb_set_cmap(&all->info.cmap, &all->info);
-
- cg3_init_fix(&all->info, linebytes, dp);
-
- err = register_framebuffer(&all->info);
- if (err < 0) {
- fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct cg3_regs));
- of_iounmap(&op->resource[0],
- all->info.screen_base, all->par.fbsize);
- kfree(all);
- return err;
+ info->var.xres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+
+ par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
+ sizeof(struct cg3_regs), "cg3 regs");
+ if (!par->regs)
+ goto out_release_fb;
+
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &cg3_ops;
+ info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
+ par->fbsize, "cg3 ram");
+ if (!info->screen_base)
+ goto out_unmap_regs;
+
+ cg3_blank(0, info);
+
+ if (!of_find_property(dp, "width", NULL)) {
+ err = cg3_do_default_mode(par);
+ if (err)
+ goto out_unmap_screen;
}
- dev_set_drvdata(&op->dev, all);
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_screen;
+
+ fb_set_cmap(&info->cmap, info);
+
+ cg3_init_fix(info, linebytes, dp);
+
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
+
+ dev_set_drvdata(&op->dev, info);
printk("%s: cg3 at %lx:%lx\n",
- dp->full_name, all->par.which_io, all->par.physbase);
+ dp->full_name, par->which_io, par->physbase);
return 0;
-}
-static int __devinit cg3_probe(struct of_device *dev,
- const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_screen:
+ of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+
+out_unmap_regs:
+ of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
+
+out_release_fb:
+ framebuffer_release(info);
- return cg3_init_one(op);
+out_err:
+ return err;
}
static int __devexit cg3_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct cg3_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs));
- of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
+ of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 4dad23a28f58..ee9046db9c7d 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -653,135 +653,123 @@ static void cg6_chip_init(struct fb_info *info)
sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
}
-struct all_info {
- struct fb_info info;
- struct cg6_par par;
-};
-
-static void cg6_unmap_regs(struct of_device *op, struct all_info *all)
+static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
+ struct cg6_par *par)
{
- if (all->par.fbc)
- of_iounmap(&op->resource[0], all->par.fbc, 4096);
- if (all->par.tec)
- of_iounmap(&op->resource[0],
- all->par.tec, sizeof(struct cg6_tec));
- if (all->par.thc)
- of_iounmap(&op->resource[0],
- all->par.thc, sizeof(struct cg6_thc));
- if (all->par.bt)
- of_iounmap(&op->resource[0],
- all->par.bt, sizeof(struct bt_regs));
- if (all->par.fhc)
- of_iounmap(&op->resource[0],
- all->par.fhc, sizeof(u32));
-
- if (all->info.screen_base)
- of_iounmap(&op->resource[0],
- all->info.screen_base, all->par.fbsize);
+ if (par->fbc)
+ of_iounmap(&op->resource[0], par->fbc, 4096);
+ if (par->tec)
+ of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec));
+ if (par->thc)
+ of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc));
+ if (par->bt)
+ of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs));
+ if (par->fhc)
+ of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
+
+ if (info->screen_base)
+ of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
}
-static int __devinit cg6_init_one(struct of_device *op)
+static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct cg6_par *par;
int linebytes, err;
+ int dblbuf;
+
+ info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev);
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- spin_lock_init(&all->par.lock);
+ spin_lock_init(&par->lock);
- all->par.physbase = op->resource[0].start;
- all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+ par->physbase = op->resource[0].start;
+ par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, dp->node, 8);
- all->info.var.red.length = 8;
- all->info.var.green.length = 8;
- all->info.var.blue.length = 8;
+ sbusfb_fill_var(&info->var, dp->node, 8);
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
- if (of_find_property(dp, "dblbuf", NULL))
- all->par.fbsize *= 4;
+ info->var.xres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
- all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
+ dblbuf = of_getintprop_default(dp, "dblbuf", 0);
+ if (dblbuf)
+ par->fbsize *= 4;
+
+ par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
4096, "cgsix fbc");
- all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
+ par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
sizeof(struct cg6_tec), "cgsix tec");
- all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
+ par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
sizeof(struct cg6_thc), "cgsix thc");
- all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
+ par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
sizeof(struct bt_regs), "cgsix dac");
- all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
+ par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
sizeof(u32), "cgsix fhc");
- all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
- all->info.fbops = &cg6_ops;
-
- all->info.screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
- all->par.fbsize, "cgsix ram");
- if (!all->par.fbc || !all->par.tec || !all->par.thc ||
- !all->par.bt || !all->par.fhc || !all->info.screen_base) {
- cg6_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
+ info->fbops = &cg6_ops;
- all->info.par = &all->par;
+ info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
+ par->fbsize, "cgsix ram");
+ if (!par->fbc || !par->tec || !par->thc ||
+ !par->bt || !par->fhc || !info->screen_base)
+ goto out_unmap_regs;
- all->info.var.accel_flags = FB_ACCELF_TEXT;
+ info->var.accel_flags = FB_ACCELF_TEXT;
- cg6_bt_init(&all->par);
- cg6_chip_init(&all->info);
- cg6_blank(0, &all->info);
+ cg6_bt_init(par);
+ cg6_chip_init(info);
+ cg6_blank(0, info);
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- cg6_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_regs;
- fb_set_cmap(&all->info.cmap, &all->info);
- cg6_init_fix(&all->info, linebytes);
+ fb_set_cmap(&info->cmap, info);
+ cg6_init_fix(info, linebytes);
- err = register_framebuffer(&all->info);
- if (err < 0) {
- cg6_unmap_regs(op, all);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- return err;
- }
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
- dev_set_drvdata(&op->dev, all);
+ dev_set_drvdata(&op->dev, info);
printk("%s: CGsix [%s] at %lx:%lx\n",
- dp->full_name,
- all->info.fix.id,
- all->par.which_io, all->par.physbase);
+ dp->full_name, info->fix.id,
+ par->which_io, par->physbase);
return 0;
-}
-static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_regs:
+ cg6_unmap_regs(op, info, par);
- return cg6_init_one(op);
+out_err:
+ return err;
}
static int __devexit cg6_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct cg6_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- cg6_unmap_regs(op, all);
+ cg6_unmap_regs(op, info, par);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index f48e8c534c87..6796ba62c3c6 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
+#include <linux/pm.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
@@ -458,7 +459,7 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
if (state.event == pdev->dev.power.power_state.event)
return 0;
- if (state.event != PM_SUSPEND_MEM)
+ if (state.event != PM_EVENT_SUSPEND)
goto done;
acquire_console_sem();
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 50b78af0fa24..dea6579941b7 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -366,11 +366,10 @@ int __init clps711xfb_init(void)
if (fb_get_options("clps711xfb", NULL))
return -ENODEV;
- cfb = kmalloc(sizeof(*cfb), GFP_KERNEL);
+ cfb = kzalloc(sizeof(*cfb), GFP_KERNEL);
if (!cfb)
goto out;
- memset(cfb, 0, sizeof(*cfb));
strcpy(cfb->fix.id, "clps711x");
cfb->fbops = &clps7111fb_ops;
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 49643969f9f8..a22ccf9485a4 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -145,7 +145,7 @@ config FRAMEBUFFER_CONSOLE_ROTATION
oriented.
config STI_CONSOLE
- tristate "STI text console"
+ bool "STI text console"
depends on PARISC
default y
help
@@ -182,7 +182,7 @@ config FONT_8x8
config FONT_8x16
bool "VGA 8x16 font" if FONTS
- depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || STI_CONSOLE || USB_SISUSBVGA_CON
+ depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE || STI_CONSOLE || USB_SISUSBVGA_CON
default y if !SPARC && !FONTS
help
This is the "high resolution" font for the VGA frame buffer (the one
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index decfdc8eb9cc..e58c87b3e3a0 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -127,8 +127,20 @@ static int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1;
static int fbcon_has_exited;
static int primary_device = -1;
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
static int map_override;
+static inline void fbcon_map_override(void)
+{
+ map_override = 1;
+}
+#else
+static inline void fbcon_map_override(void)
+{
+}
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */
+
/* font data */
static char fontname[40];
@@ -506,7 +518,7 @@ static int __init fb_console_setup(char *this_opt)
(options[j++]-'0') % FB_MAX;
}
- map_override = 1;
+ fbcon_map_override();
}
return 1;
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index a6828d0a4c56..96979c377518 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -133,8 +133,8 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
if ((yres < 400) == (f->height <= 8))
c += 1000;
- if (!(font_w & (1 << (f->width - 1))) ||
- !(font_w & (1 << (f->height - 1))))
+ if ((font_w & (1 << (f->width - 1))) &&
+ (font_h & (1 << (f->height - 1))))
c += 1000;
if (c > cc) {
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 7fa1afeae8dc..dda0586ab3f3 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -738,9 +738,8 @@ const struct consw newport_con = {
#ifdef MODULE
static int __init newport_console_init(void)
{
-
if (!sgi_gfxaddr)
- return NULL;
+ return 0;
if (!npregs)
npregs = (struct newport_regs *)/* ioremap cannot fail */
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 870017d44970..e9ab657f0bb7 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -232,18 +232,14 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x,
}
-/* FIXME: Do we have another solution for this ? */
-static void sti_flush(unsigned long from, unsigned long len)
+static void sti_flush(unsigned long start, unsigned long end)
{
- flush_data_cache();
- flush_kernel_dcache_range(from, len);
- flush_icache_range(from, from+len);
+ flush_icache_range(start, end);
}
void __devinit
sti_rom_copy(unsigned long base, unsigned long count, void *dest)
{
- unsigned long dest_len = count;
unsigned long dest_start = (unsigned long) dest;
/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
@@ -260,7 +256,7 @@ sti_rom_copy(unsigned long base, unsigned long count, void *dest)
dest++;
}
- sti_flush(dest_start, dest_len);
+ sti_flush(dest_start, (unsigned long)dest);
}
@@ -663,7 +659,6 @@ sti_bmode_font_raw(struct sti_cooked_font *f)
static void __devinit
sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
{
- unsigned long dest_len = count;
unsigned long dest_start = (unsigned long) dest;
while (count) {
@@ -672,7 +667,8 @@ sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
base += 4;
dest++;
}
- sti_flush(dest_start, dest_len);
+
+ sti_flush(dest_start, (unsigned long)dest);
}
static struct sti_rom * __devinit
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index f46fe95f69fb..d18b73aafa0d 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -187,7 +187,11 @@ static void vgacon_scrollback_init(int pitch)
}
}
-static void vgacon_scrollback_startup(void)
+/*
+ * Called only duing init so call of alloc_bootmen is ok.
+ * Marked __init_refok to silence modpost.
+ */
+static void __init_refok vgacon_scrollback_startup(void)
{
vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
* 1024);
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 7a6eeda5ae9a..30ede6e8830f 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1221,11 +1221,10 @@ cyberpro_alloc_fb_info(unsigned int id, char *name)
{
struct cfb_info *cfb;
- cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL);
+ cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
if (!cfb)
return NULL;
- memset(cfb, 0, sizeof(struct cfb_info));
cfb->id = id;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 215ac579f901..074027204702 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -244,8 +244,17 @@ static void fb_set_logo(struct fb_info *info,
u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
u8 fg = 1, d;
- if (fb_get_color_depth(&info->var, &info->fix) == 3)
+ switch (fb_get_color_depth(&info->var, &info->fix)) {
+ case 1:
+ fg = 1;
+ break;
+ case 2:
+ fg = 3;
+ break;
+ default:
fg = 7;
+ break;
+ }
if (info->fix.visual == FB_VISUAL_MONO01 ||
info->fix.visual == FB_VISUAL_MONO10)
@@ -564,21 +573,6 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
depth = 4;
}
- if (depth >= 8) {
- switch (info->fix.visual) {
- case FB_VISUAL_TRUECOLOR:
- fb_logo.needs_truepalette = 1;
- break;
- case FB_VISUAL_DIRECTCOLOR:
- fb_logo.needs_directpalette = 1;
- fb_logo.needs_cmapreset = 1;
- break;
- case FB_VISUAL_PSEUDOCOLOR:
- fb_logo.needs_cmapreset = 1;
- break;
- }
- }
-
/* Return if no suitable logo was found */
fb_logo.logo = fb_find_logo(depth);
@@ -604,6 +598,22 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
else
fb_logo.depth = 1;
+
+ if (fb_logo.depth > 4 && depth > 4) {
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ fb_logo.needs_truepalette = 1;
+ break;
+ case FB_VISUAL_DIRECTCOLOR:
+ fb_logo.needs_directpalette = 1;
+ fb_logo.needs_cmapreset = 1;
+ break;
+ case FB_VISUAL_PSEUDOCOLOR:
+ fb_logo.needs_cmapreset = 1;
+ break;
+ }
+ }
+
return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
}
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 3f6c98fad437..4b520b573911 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -371,6 +371,8 @@ struct ffb_par {
unsigned long fbsize;
int board_type;
+
+ u32 pseudo_palette[16];
};
static void FFBFifo(struct ffb_par *par, int n)
@@ -900,75 +902,67 @@ ffb_init_fix(struct fb_info *info)
info->fix.accel = FB_ACCEL_SUN_CREATOR;
}
-struct all_info {
- struct fb_info info;
- struct ffb_par par;
- u32 pseudo_palette[16];
-};
-
-static int ffb_init_one(struct of_device *op)
+static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct ffb_fbc __iomem *fbc;
struct ffb_dac __iomem *dac;
- struct all_info *all;
- int err;
+ struct fb_info *info;
+ struct ffb_par *par;
u32 dac_pnum, dac_rev, dac_mrev;
+ int err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev);
- spin_lock_init(&all->par.lock);
- all->par.fbc = of_ioremap(&op->resource[2], 0,
- sizeof(struct ffb_fbc), "ffb fbc");
- if (!all->par.fbc) {
- kfree(all);
- return -ENOMEM;
- }
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
- all->par.dac = of_ioremap(&op->resource[1], 0,
- sizeof(struct ffb_dac), "ffb dac");
- if (!all->par.dac) {
- of_iounmap(&op->resource[2],
- all->par.fbc, sizeof(struct ffb_fbc));
- kfree(all);
- return -ENOMEM;
- }
+ par = info->par;
+
+ spin_lock_init(&par->lock);
+ par->fbc = of_ioremap(&op->resource[2], 0,
+ sizeof(struct ffb_fbc), "ffb fbc");
+ if (!par->fbc)
+ goto out_release_fb;
+
+ par->dac = of_ioremap(&op->resource[1], 0,
+ sizeof(struct ffb_dac), "ffb dac");
+ if (!par->dac)
+ goto out_unmap_fbc;
- all->par.rop_cache = FFB_ROP_NEW;
- all->par.physbase = op->resource[0].start;
+ par->rop_cache = FFB_ROP_NEW;
+ par->physbase = op->resource[0].start;
/* Don't mention copyarea, so SCROLL_REDRAW is always
* used. It is the fastest on this chip.
*/
- all->info.flags = (FBINFO_DEFAULT |
- /* FBINFO_HWACCEL_COPYAREA | */
- FBINFO_HWACCEL_FILLRECT |
- FBINFO_HWACCEL_IMAGEBLIT);
- all->info.fbops = &ffb_ops;
- all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
- all->info.par = &all->par;
- all->info.pseudo_palette = all->pseudo_palette;
-
- sbusfb_fill_var(&all->info.var, dp->node, 32);
- all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
- all->info.var.yres *
- 4);
- ffb_fixup_var_rgb(&all->info.var);
-
- all->info.var.accel_flags = FB_ACCELF_TEXT;
+ info->flags = (FBINFO_DEFAULT |
+ /* FBINFO_HWACCEL_COPYAREA | */
+ FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_IMAGEBLIT);
+
+ info->fbops = &ffb_ops;
+
+ info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;
+ info->pseudo_palette = par->pseudo_palette;
+
+ sbusfb_fill_var(&info->var, dp->node, 32);
+ par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);
+ ffb_fixup_var_rgb(&info->var);
+
+ info->var.accel_flags = FB_ACCELF_TEXT;
if (!strcmp(dp->name, "SUNW,afb"))
- all->par.flags |= FFB_FLAG_AFB;
+ par->flags |= FFB_FLAG_AFB;
- all->par.board_type = of_getintprop_default(dp, "board_type", 0);
+ par->board_type = of_getintprop_default(dp, "board_type", 0);
- fbc = all->par.fbc;
+ fbc = par->fbc;
if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
- dac = all->par.dac;
+ dac = par->dac;
upa_writel(FFB_DAC_DID, &dac->type);
dac_pnum = upa_readl(&dac->value);
dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;
@@ -985,76 +979,70 @@ static int ffb_init_one(struct of_device *op)
* cursor logic. We identify Pacifica 1 as not Pacifica 2, the
* latter having a part number value of 0x236e.
*/
- if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
- all->par.flags &= ~FFB_FLAG_INVCURSOR;
+ if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
+ par->flags &= ~FFB_FLAG_INVCURSOR;
} else {
if (dac_mrev < 3)
- all->par.flags |= FFB_FLAG_INVCURSOR;
+ par->flags |= FFB_FLAG_INVCURSOR;
}
- ffb_switch_from_graph(&all->par);
+ ffb_switch_from_graph(par);
/* Unblank it just to be sure. When there are multiple
* FFB/AFB cards in the system, or it is not the OBP
* chosen console, it will have video outputs off in
* the DAC.
*/
- ffb_blank(0, &all->info);
-
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "ffb: Could not allocate color map.\n");
- of_iounmap(&op->resource[2],
- all->par.fbc, sizeof(struct ffb_fbc));
- of_iounmap(&op->resource[1],
- all->par.dac, sizeof(struct ffb_dac));
- kfree(all);
- return -ENOMEM;
- }
+ ffb_blank(0, info);
- ffb_init_fix(&all->info);
-
- err = register_framebuffer(&all->info);
- if (err < 0) {
- printk(KERN_ERR "ffb: Could not register framebuffer.\n");
- fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(&op->resource[2],
- all->par.fbc, sizeof(struct ffb_fbc));
- of_iounmap(&op->resource[1],
- all->par.dac, sizeof(struct ffb_dac));
- kfree(all);
- return err;
- }
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_dac;
+
+ ffb_init_fix(info);
- dev_set_drvdata(&op->dev, all);
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
+
+ dev_set_drvdata(&op->dev, info);
printk("%s: %s at %016lx, type %d, "
"DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
dp->full_name,
- ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
- all->par.physbase, all->par.board_type,
+ ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
+ par->physbase, par->board_type,
dac_pnum, dac_rev, dac_mrev);
return 0;
-}
-static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_dac:
+ of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+
+out_unmap_fbc:
+ of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+
+out_release_fb:
+ framebuffer_release(info);
- return ffb_init_one(op);
+out_err:
+ return err;
}
static int __devexit ffb_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct ffb_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc));
- of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac));
+ of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+ of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index a814b6c2605c..7608429b3943 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -8,6 +8,21 @@ config FB_GEODE
Say 'Y' here to allow you to select framebuffer drivers for
the AMD Geode family of processors.
+config FB_GEODE_LX
+ tristate "AMD Geode LX framebuffer support (EXPERIMENTAL)"
+ depends on FB && FB_GEODE
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Framebuffer driver for the display controller integrated into the
+ AMD Geode LX processors.
+
+ To compile this driver as a module, choose M here: the module will
+ be called lxfb.
+
+ If unsure, say N.
+
config FB_GEODE_GX
tristate "AMD Geode GX framebuffer support (EXPERIMENTAL)"
depends on FB && FB_GEODE && EXPERIMENTAL
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
index f896565bc312..957304b45fba 100644
--- a/drivers/video/geode/Makefile
+++ b/drivers/video/geode/Makefile
@@ -2,6 +2,8 @@
obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o
obj-$(CONFIG_FB_GEODE_GX) += gxfb.o
+obj-$(CONFIG_FB_GEODE_LX) += lxfb.o
gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
gxfb-objs := gxfb_core.o display_gx.o video_gx.o
+lxfb-objs := lxfb_core.o lxfb_ops.o
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
new file mode 100644
index 000000000000..6c227f9592a5
--- /dev/null
+++ b/drivers/video/geode/lxfb.h
@@ -0,0 +1,199 @@
+#ifndef _LXFB_H_
+#define _LXFB_H_
+
+#include <linux/fb.h>
+
+#define OUTPUT_CRT 0x01
+#define OUTPUT_PANEL 0x02
+
+struct lxfb_par {
+ int output;
+ int panel_width;
+ int panel_height;
+
+ void __iomem *gp_regs;
+ void __iomem *dc_regs;
+ void __iomem *df_regs;
+};
+
+static inline unsigned int lx_get_pitch(unsigned int xres, int bpp)
+{
+ return (((xres * (bpp >> 3)) + 7) & ~7);
+}
+
+void lx_set_mode(struct fb_info *);
+void lx_get_gamma(struct fb_info *, unsigned int *, int);
+void lx_set_gamma(struct fb_info *, unsigned int *, int);
+unsigned int lx_framebuffer_size(void);
+int lx_blank_display(struct fb_info *, int);
+void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
+ unsigned int, unsigned int);
+
+/* MSRS */
+
+#define MSR_LX_GLD_CONFIG 0x48002001
+#define MSR_LX_GLCP_DOTPLL 0x4c000015
+#define MSR_LX_DF_PADSEL 0x48000011
+#define MSR_LX_DC_SPARE 0x80000011
+#define MSR_LX_DF_GLCONFIG 0x48002001
+
+#define MSR_LX_GLIU0_P2D_RO0 0x10000029
+
+#define GLCP_DOTPLL_RESET (1 << 0)
+#define GLCP_DOTPLL_BYPASS (1 << 15)
+#define GLCP_DOTPLL_HALFPIX (1 << 24)
+#define GLCP_DOTPLL_LOCK (1 << 25)
+
+#define DF_CONFIG_OUTPUT_MASK 0x38
+#define DF_OUTPUT_PANEL 0x08
+#define DF_OUTPUT_CRT 0x00
+#define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15)
+
+#define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF
+#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F
+
+#define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800
+#define DC_SPARE_VFIFO_ARB_SELECT 0x00000400
+#define DC_SPARE_WM_LPEN_OVRD 0x00000200
+#define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100
+#define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080
+#define DC_SPARE_DISABLE_VFIFO_WM 0x00000040
+#define DC_SPARE_DISABLE_CWD_CHECK 0x00000020
+#define DC_SPARE_PIX8_PAN_FIX 0x00000010
+#define DC_SPARE_FIRST_REQ_MASK 0x00000002
+
+/* Registers */
+
+#define DC_UNLOCK 0x00
+#define DC_UNLOCK_CODE 0x4758
+
+#define DC_GENERAL_CFG 0x04
+#define DC_GCFG_DFLE (1 << 0)
+#define DC_GCFG_VIDE (1 << 3)
+#define DC_GCFG_VGAE (1 << 7)
+#define DC_GCFG_CMPE (1 << 5)
+#define DC_GCFG_DECE (1 << 6)
+#define DC_GCFG_FDTY (1 << 17)
+
+#define DC_DISPLAY_CFG 0x08
+#define DC_DCFG_TGEN (1 << 0)
+#define DC_DCFG_GDEN (1 << 3)
+#define DC_DCFG_VDEN (1 << 4)
+#define DC_DCFG_TRUP (1 << 6)
+#define DC_DCFG_DCEN (1 << 24)
+#define DC_DCFG_PALB (1 << 25)
+#define DC_DCFG_VISL (1 << 27)
+
+#define DC_DCFG_16BPP 0x0
+
+#define DC_DCFG_DISP_MODE_MASK 0x00000300
+#define DC_DCFG_DISP_MODE_8BPP 0x00000000
+#define DC_DCFG_DISP_MODE_16BPP 0x00000100
+#define DC_DCFG_DISP_MODE_24BPP 0x00000200
+#define DC_DCFG_DISP_MODE_32BPP 0x00000300
+
+
+#define DC_ARB_CFG 0x0C
+
+#define DC_FB_START 0x10
+#define DC_CB_START 0x14
+#define DC_CURSOR_START 0x18
+
+#define DC_DV_TOP 0x2C
+#define DC_DV_TOP_ENABLE (1 << 0)
+
+#define DC_LINE_SIZE 0x30
+#define DC_GRAPHICS_PITCH 0x34
+#define DC_H_ACTIVE_TIMING 0x40
+#define DC_H_BLANK_TIMING 0x44
+#define DC_H_SYNC_TIMING 0x48
+#define DC_V_ACTIVE_TIMING 0x50
+#define DC_V_BLANK_TIMING 0x54
+#define DC_V_SYNC_TIMING 0x58
+#define DC_FB_ACTIVE 0x5C
+
+#define DC_PAL_ADDRESS 0x70
+#define DC_PAL_DATA 0x74
+
+#define DC_PHY_MEM_OFFSET 0x84
+
+#define DC_DV_CTL 0x88
+#define DC_DV_LINE_SIZE_MASK 0x00000C00
+#define DC_DV_LINE_SIZE_1024 0x00000000
+#define DC_DV_LINE_SIZE_2048 0x00000400
+#define DC_DV_LINE_SIZE_4096 0x00000800
+#define DC_DV_LINE_SIZE_8192 0x00000C00
+
+
+#define DC_GFX_SCALE 0x90
+#define DC_IRQ_FILT_CTL 0x94
+
+
+#define DC_IRQ 0xC8
+#define DC_IRQ_MASK (1 << 0)
+#define DC_VSYNC_IRQ_MASK (1 << 1)
+#define DC_IRQ_STATUS (1 << 20)
+#define DC_VSYNC_IRQ_STATUS (1 << 21)
+
+#define DC_GENLCK_CTRL 0xD4
+#define DC_GENLCK_ENABLE (1 << 18)
+#define DC_GC_ALPHA_FLICK_ENABLE (1 << 25)
+#define DC_GC_FLICKER_FILTER_ENABLE (1 << 24)
+#define DC_GC_FLICKER_FILTER_MASK (0x0F << 28)
+
+#define DC_COLOR_KEY 0xB8
+#define DC_CLR_KEY_ENABLE (1 << 24)
+
+
+#define DC3_DV_LINE_SIZE_MASK 0x00000C00
+#define DC3_DV_LINE_SIZE_1024 0x00000000
+#define DC3_DV_LINE_SIZE_2048 0x00000400
+#define DC3_DV_LINE_SIZE_4096 0x00000800
+#define DC3_DV_LINE_SIZE_8192 0x00000C00
+
+#define DF_VIDEO_CFG 0x0
+#define DF_VCFG_VID_EN (1 << 0)
+
+#define DF_DISPLAY_CFG 0x08
+
+#define DF_DCFG_CRT_EN (1 << 0)
+#define DF_DCFG_HSYNC_EN (1 << 1)
+#define DF_DCFG_VSYNC_EN (1 << 2)
+#define DF_DCFG_DAC_BL_EN (1 << 3)
+#define DF_DCFG_CRT_HSYNC_POL (1 << 8)
+#define DF_DCFG_CRT_VSYNC_POL (1 << 9)
+#define DF_DCFG_GV_PAL_BYP (1 << 21)
+
+#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000
+#define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000
+
+#define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000
+#define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000
+
+#define DF_MISC 0x50
+
+#define DF_MISC_GAM_BYPASS (1 << 0)
+#define DF_MISC_DAC_PWRDN (1 << 10)
+#define DF_MISC_A_PWRDN (1 << 11)
+
+#define DF_PAR 0x38
+#define DF_PDR 0x40
+#define DF_ALPHA_CONTROL_1 0xD8
+#define DF_VIDEO_REQUEST 0x120
+
+#define DF_PANEL_TIM1 0x400
+#define DF_DEFAULT_TFT_PMTIM1 0x0
+
+#define DF_PANEL_TIM2 0x408
+#define DF_DEFAULT_TFT_PMTIM2 0x08000000
+
+#define DF_FP_PM 0x410
+#define DF_FP_PM_P (1 << 24)
+
+#define DF_DITHER_CONTROL 0x418
+#define DF_DEFAULT_TFT_DITHCTL 0x00000070
+#define GP_BLT_STATUS 0x44
+#define GP_BS_BLT_BUSY (1 << 0)
+#define GP_BS_CB_EMPTY (1 << 4)
+
+#endif
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
new file mode 100644
index 000000000000..5e30b40c8c0f
--- /dev/null
+++ b/drivers/video/geode/lxfb_core.c
@@ -0,0 +1,621 @@
+/*
+ * Geode LX framebuffer driver.
+ *
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Built from gxfb (which is Copyright (C) 2006 Arcom Control Systems Ltd.)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+
+#include "lxfb.h"
+
+static char *mode_option;
+static int noclear, nopanel, nocrt;
+static int fbsize;
+
+/* Most of these modes are sorted in ascending order, but
+ * since the first entry in this table is the "default" mode,
+ * we try to make it something sane - 640x480-60 is sane
+ */
+
+const struct fb_videomode geode_modedb[] __initdata = {
+ /* 640x480-60 */
+ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 640x400-70 */
+ { NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2,
+ FB_SYNC_HOR_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-70 */
+ { NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-72 */
+ { NULL, 72, 640, 480, 32102, 120, 16, 20, 1, 40, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-75 */
+ { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-85 */
+ { NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-90 */
+ { NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-100 */
+ { NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 640x480-60 */
+ { NULL, 60, 640, 480, 39682, 48, 16, 25, 10, 88, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-56 */
+ { NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-60 */
+ { NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-70 */
+ { NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-72 */
+ { NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-75 */
+ { NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-85 */
+ { NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-90 */
+ { NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-100 */
+ { NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 800x600-60 */
+ { NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-60 */
+ { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-70 */
+ { NULL, 70, 1024, 768, 13346, 144, 24, 29, 3, 136, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-72 */
+ { NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-75 */
+ { NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-85 */
+ { NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-90 */
+ { NULL, 90, 1024, 768, 9981, 176, 64, 37, 1, 112, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-100 */
+ { NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1024x768-60 */
+ { NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-60 */
+ { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-70 */
+ { NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-72 */
+ { NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-75 */
+ { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-85 */
+ { NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-90 */
+ { NULL, 90, 1152, 864, 7719, 208, 80, 42, 9, 128, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-100 */
+ { NULL, 100, 1152, 864, 6947, 208, 80, 48, 3, 128, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1152x864-60 */
+ { NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-60 */
+ { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-70 */
+ { NULL, 70, 1280, 1024, 7719, 224, 88, 38, 6, 136, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-72 */
+ { NULL, 72, 1280, 1024, 7490, 224, 88, 39, 7, 136, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-75 */
+ { NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-85 */
+ { NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-90 */
+ { NULL, 90, 1280, 1024, 5791, 240, 96, 51, 12, 144, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-100 */
+ { NULL, 100, 1280, 1024, 5212, 240, 96, 57, 6, 144, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1280x1024-60 */
+ { NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-60 */
+ { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-70 */
+ { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-72 */
+ { NULL, 72, 1600, 1200, 5053, 288, 112, 47, 13, 176, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-75 */
+ { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-85 */
+ { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-90 */
+ { NULL, 90, 1600, 1200, 3981, 304, 128, 60, 1, 176, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-100 */
+ { NULL, 100, 1600, 1200, 3563, 304, 128, 67, 1, 176, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1600x1200-60 */
+ { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, 0 },
+ /* 1920x1440-60 */
+ { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1920x1440-70 */
+ { NULL, 70, 1920, 1440, 3593, 360, 152, 55, 8, 208, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1920x1440-72 */
+ { NULL, 72, 1920, 1440, 3472, 360, 152, 68, 4, 208, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1920x1440-75 */
+ { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+ /* 1920x1440-85 */
+ { NULL, 85, 1920, 1440, 2929, 368, 152, 68, 1, 216, 3,
+ 0, FB_VMODE_NONINTERLACED, 0 },
+};
+
+static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ if (var->xres > 1920 || var->yres > 1440)
+ return -EINVAL;
+
+ if (var->bits_per_pixel == 32) {
+ var->red.offset = 16; var->red.length = 8;
+ var->green.offset = 8; var->green.length = 8;
+ var->blue.offset = 0; var->blue.length = 8;
+ } else 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;
+ } else if (var->bits_per_pixel == 8) {
+ var->red.offset = 0; var->red.length = 8;
+ var->green.offset = 0; var->green.length = 8;
+ var->blue.offset = 0; var->blue.length = 8;
+ } else
+ return -EINVAL;
+
+ var->transp.offset = 0; var->transp.length = 0;
+
+ /* Enough video memory? */
+ if ((lx_get_pitch(var->xres, var->bits_per_pixel) * var->yres)
+ > info->fix.smem_len)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int lxfb_set_par(struct fb_info *info)
+{
+ if (info->var.bits_per_pixel > 8) {
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ fb_dealloc_cmap(&info->cmap);
+ } else {
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+ }
+
+ info->fix.line_length = lx_get_pitch(info->var.xres,
+ info->var.bits_per_pixel);
+
+ lx_set_mode(info);
+ return 0;
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int lxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* Truecolor has hardware independent palette */
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 *pal = info->pseudo_palette;
+ u32 v;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ v = chan_to_field(red, &info->var.red);
+ v |= chan_to_field(green, &info->var.green);
+ v |= chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = v;
+ } else {
+ if (regno >= 256)
+ return -EINVAL;
+
+ lx_set_palette_reg(info, regno, red, green, blue);
+ }
+
+ return 0;
+}
+
+static int lxfb_blank(int blank_mode, struct fb_info *info)
+{
+ return lx_blank_display(info, blank_mode);
+}
+
+
+static int __init lxfb_map_video_memory(struct fb_info *info,
+ struct pci_dev *dev)
+{
+ struct lxfb_par *par = info->par;
+ int ret;
+
+ ret = pci_enable_device(dev);
+
+ if (ret)
+ return ret;
+
+ ret = pci_request_region(dev, 0, "lxfb-framebuffer");
+
+ if (ret)
+ return ret;
+
+ ret = pci_request_region(dev, 1, "lxfb-gp");
+
+ if (ret)
+ return ret;
+
+ ret = pci_request_region(dev, 2, "lxfb-vg");
+
+ if (ret)
+ return ret;
+
+ ret = pci_request_region(dev, 3, "lxfb-vip");
+
+ if (ret)
+ return ret;
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size();
+
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+
+ ret = -ENOMEM;
+
+ if (info->screen_base == NULL)
+ return ret;
+
+ par->gp_regs = ioremap(pci_resource_start(dev, 1),
+ pci_resource_len(dev, 1));
+
+ if (par->gp_regs == NULL)
+ return ret;
+
+ par->dc_regs = ioremap(pci_resource_start(dev, 2),
+ pci_resource_len(dev, 2));
+
+ if (par->dc_regs == NULL)
+ return ret;
+
+ par->df_regs = ioremap(pci_resource_start(dev, 3),
+ pci_resource_len(dev, 3));
+
+ if (par->df_regs == NULL)
+ return ret;
+
+ writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+ writel(info->fix.smem_start & 0xFF000000,
+ par->dc_regs + DC_PHY_MEM_OFFSET);
+
+ writel(0, par->dc_regs + DC_UNLOCK);
+
+ dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
+ info->fix.smem_len / 1024, info->fix.smem_start);
+
+ return 0;
+}
+
+static struct fb_ops lxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = lxfb_check_var,
+ .fb_set_par = lxfb_set_par,
+ .fb_setcolreg = lxfb_setcolreg,
+ .fb_blank = lxfb_blank,
+ /* No HW acceleration for now. */
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
+{
+ struct lxfb_par *par;
+ struct fb_info *info;
+
+ /* Alloc enough space for the pseudo palette. */
+ info = framebuffer_alloc(sizeof(struct lxfb_par) + sizeof(u32) * 16,
+ dev);
+ if (!info)
+ return NULL;
+
+ par = info->par;
+
+ strcpy(info->fix.id, "Geode LX");
+
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->var.nonstd = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.height = -1;
+ info->var.width = -1;
+ info->var.accel_flags = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ info->fbops = &lxfb_ops;
+ info->flags = FBINFO_DEFAULT;
+ info->node = -1;
+
+ info->pseudo_palette = (void *)par + sizeof(struct lxfb_par);
+
+ info->var.grayscale = 0;
+
+ return info;
+}
+
+static int __init lxfb_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct lxfb_par *par;
+ struct fb_info *info;
+ int ret;
+
+ struct fb_videomode *modedb_ptr;
+ int modedb_size;
+
+ info = lxfb_init_fbinfo(&pdev->dev);
+
+ if (info == NULL)
+ return -ENOMEM;
+
+ par = info->par;
+
+ ret = lxfb_map_video_memory(info, pdev);
+
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to map frame buffer or controller registers\n");
+ goto err;
+ }
+
+ /* Set up the desired outputs */
+
+ par->output = 0;
+ par->output |= (nopanel) ? 0 : OUTPUT_PANEL;
+ par->output |= (nocrt) ? 0 : OUTPUT_CRT;
+
+ /* Set up the mode database */
+
+ modedb_ptr = (struct fb_videomode *) geode_modedb;
+ modedb_size = ARRAY_SIZE(geode_modedb);
+
+ ret = fb_find_mode(&info->var, info, mode_option,
+ modedb_ptr, modedb_size, NULL, 16);
+
+ if (ret == 0 || ret == 4) {
+ dev_err(&pdev->dev, "could not find valid video mode\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Clear the screen of garbage, unless noclear was specified,
+ * in which case we assume the user knows what he is doing */
+
+ if (!noclear)
+ memset_io(info->screen_base, 0, info->fix.smem_len);
+
+ /* Set the mode */
+
+ lxfb_check_var(&info->var, info);
+ lxfb_set_par(info);
+
+ if (register_framebuffer(info) < 0) {
+ ret = -EINVAL;
+ goto err;
+ }
+ pci_set_drvdata(pdev, info);
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+
+ return 0;
+
+err:
+ if (info->screen_base) {
+ iounmap(info->screen_base);
+ pci_release_region(pdev, 0);
+ }
+ if (par->gp_regs) {
+ iounmap(par->gp_regs);
+ pci_release_region(pdev, 1);
+ }
+ if (par->dc_regs) {
+ iounmap(par->dc_regs);
+ pci_release_region(pdev, 2);
+ }
+ if (par->df_regs) {
+ iounmap(par->df_regs);
+ pci_release_region(pdev, 3);
+ }
+
+ if (info)
+ framebuffer_release(info);
+
+ return ret;
+}
+
+static void lxfb_remove(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct lxfb_par *par = info->par;
+
+ unregister_framebuffer(info);
+
+ iounmap(info->screen_base);
+ pci_release_region(pdev, 0);
+
+ iounmap(par->gp_regs);
+ pci_release_region(pdev, 1);
+
+ iounmap(par->dc_regs);
+ pci_release_region(pdev, 2);
+
+ iounmap(par->df_regs);
+ pci_release_region(pdev, 3);
+
+ pci_set_drvdata(pdev, NULL);
+ framebuffer_release(info);
+}
+
+static struct pci_device_id lxfb_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_VIDEO) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, lxfb_id_table);
+
+static struct pci_driver lxfb_driver = {
+ .name = "lxfb",
+ .id_table = lxfb_id_table,
+ .probe = lxfb_probe,
+ .remove = lxfb_remove,
+};
+
+#ifndef MODULE
+static int __init lxfb_setup(char *options)
+{
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while (1) {
+ char *opt = strsep(&options, ",");
+
+ if (opt == NULL)
+ break;
+
+ if (!*opt)
+ continue;
+
+ if (!strncmp(opt, "fbsize:", 7))
+ fbsize = simple_strtoul(opt+7, NULL, 0);
+ else if (!strcmp(opt, "noclear"))
+ noclear = 1;
+ else if (!strcmp(opt, "nopanel"))
+ nopanel = 1;
+ else if (!strcmp(opt, "nocrt"))
+ nocrt = 1;
+ else
+ mode_option = opt;
+ }
+
+ return 0;
+}
+#endif
+
+static int __init lxfb_init(void)
+{
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("lxfb", &option))
+ return -ENODEV;
+
+ lxfb_setup(option);
+#endif
+ return pci_register_driver(&lxfb_driver);
+}
+static void __exit lxfb_cleanup(void)
+{
+ pci_unregister_driver(&lxfb_driver);
+}
+
+module_init(lxfb_init);
+module_exit(lxfb_cleanup);
+
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+
+module_param(fbsize, int, 0);
+MODULE_PARM_DESC(fbsize, "video memory size");
+
+MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
new file mode 100644
index 000000000000..4fbc99be96ef
--- /dev/null
+++ b/drivers/video/geode/lxfb_ops.c
@@ -0,0 +1,536 @@
+/* Geode LX framebuffer driver
+ *
+ * Copyright (C) 2006-2007, Advanced Micro Devices,Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+
+#include "lxfb.h"
+
+/* TODO
+ * Support panel scaling
+ * Add acceleration
+ * Add support for interlacing (TV out)
+ * Support compression
+ */
+
+/* This is the complete list of PLL frequencies that we can set -
+ * we will choose the closest match to the incoming clock.
+ * freq is the frequency of the dotclock * 1000 (for example,
+ * 24823 = 24.983 Mhz).
+ * pllval is the corresponding PLL value
+*/
+
+static const struct {
+ unsigned int pllval;
+ unsigned int freq;
+} pll_table[] = {
+ { 0x000031AC, 24923 },
+ { 0x0000215D, 25175 },
+ { 0x00001087, 27000 },
+ { 0x0000216C, 28322 },
+ { 0x0000218D, 28560 },
+ { 0x000010C9, 31200 },
+ { 0x00003147, 31500 },
+ { 0x000010A7, 33032 },
+ { 0x00002159, 35112 },
+ { 0x00004249, 35500 },
+ { 0x00000057, 36000 },
+ { 0x0000219A, 37889 },
+ { 0x00002158, 39168 },
+ { 0x00000045, 40000 },
+ { 0x00000089, 43163 },
+ { 0x000010E7, 44900 },
+ { 0x00002136, 45720 },
+ { 0x00003207, 49500 },
+ { 0x00002187, 50000 },
+ { 0x00004286, 56250 },
+ { 0x000010E5, 60065 },
+ { 0x00004214, 65000 },
+ { 0x00001105, 68179 },
+ { 0x000031E4, 74250 },
+ { 0x00003183, 75000 },
+ { 0x00004284, 78750 },
+ { 0x00001104, 81600 },
+ { 0x00006363, 94500 },
+ { 0x00005303, 97520 },
+ { 0x00002183, 100187 },
+ { 0x00002122, 101420 },
+ { 0x00001081, 108000 },
+ { 0x00006201, 113310 },
+ { 0x00000041, 119650 },
+ { 0x000041A1, 129600 },
+ { 0x00002182, 133500 },
+ { 0x000041B1, 135000 },
+ { 0x00000051, 144000 },
+ { 0x000041E1, 148500 },
+ { 0x000062D1, 157500 },
+ { 0x000031A1, 162000 },
+ { 0x00000061, 169203 },
+ { 0x00004231, 172800 },
+ { 0x00002151, 175500 },
+ { 0x000052E1, 189000 },
+ { 0x00000071, 192000 },
+ { 0x00003201, 198000 },
+ { 0x00004291, 202500 },
+ { 0x00001101, 204750 },
+ { 0x00007481, 218250 },
+ { 0x00004170, 229500 },
+ { 0x00006210, 234000 },
+ { 0x00003140, 251182 },
+ { 0x00006250, 261000 },
+ { 0x000041C0, 278400 },
+ { 0x00005220, 280640 },
+ { 0x00000050, 288000 },
+ { 0x000041E0, 297000 },
+ { 0x00002130, 320207 }
+};
+
+
+static void lx_set_dotpll(u32 pllval)
+{
+ u32 dotpll_lo, dotpll_hi;
+ int i;
+
+ rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+
+ if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval))
+ return;
+
+ dotpll_hi = pllval;
+ dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX);
+ dotpll_lo |= GLCP_DOTPLL_RESET;
+
+ wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+
+ /* Wait 100us for the PLL to lock */
+
+ udelay(100);
+
+ /* Now, loop for the lock bit */
+
+ for (i = 0; i < 1000; i++) {
+ rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+ if (dotpll_lo & GLCP_DOTPLL_LOCK)
+ break;
+ }
+
+ /* Clear the reset bit */
+
+ dotpll_lo &= ~GLCP_DOTPLL_RESET;
+ wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+}
+
+/* Set the clock based on the frequency specified by the current mode */
+
+static void lx_set_clock(struct fb_info *info)
+{
+ unsigned int diff, min, best = 0;
+ unsigned int freq, i;
+
+ freq = (unsigned int) (0x3b9aca00 / info->var.pixclock);
+
+ min = abs(pll_table[0].freq - freq);
+
+ for (i = 0; i < ARRAY_SIZE(pll_table); i++) {
+ diff = abs(pll_table[i].freq - freq);
+ if (diff < min) {
+ min = diff;
+ best = i;
+ }
+ }
+
+ lx_set_dotpll(pll_table[best].pllval & 0x7FFF);
+}
+
+static void lx_graphics_disable(struct fb_info *info)
+{
+ struct lxfb_par *par = info->par;
+ unsigned int val, gcfg;
+
+ /* Note: This assumes that the video is in a quitet state */
+
+ writel(0, par->df_regs + DF_ALPHA_CONTROL_1);
+ writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32);
+ writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64);
+
+ /* Turn off the VGA and video enable */
+ val = readl (par->dc_regs + DC_GENERAL_CFG) &
+ ~(DC_GCFG_VGAE | DC_GCFG_VIDE);
+
+ writel(val, par->dc_regs + DC_GENERAL_CFG);
+
+ val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN;
+ writel(val, par->df_regs + DF_VIDEO_CFG);
+
+ writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK |
+ DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS,
+ par->dc_regs + DC_IRQ);
+
+ val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE;
+ writel(val, par->dc_regs + DC_GENLCK_CTRL);
+
+ val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE;
+ writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY);
+
+ /* We don't actually blank the panel, due to the long latency
+ involved with bringing it back */
+
+ val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN;
+ writel(val, par->df_regs + DF_MISC);
+
+ /* Turn off the display */
+
+ val = readl(par->df_regs + DF_DISPLAY_CFG);
+ writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN |
+ DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG);
+
+ gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
+ gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE);
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ /* Turn off the TGEN */
+ val = readl(par->dc_regs + DC_DISPLAY_CFG);
+ val &= ~DC_DCFG_TGEN;
+ writel(val, par->dc_regs + DC_DISPLAY_CFG);
+
+ /* Wait 1000 usecs to ensure that the TGEN is clear */
+ udelay(1000);
+
+ /* Turn off the FIFO loader */
+
+ gcfg &= ~DC_GCFG_DFLE;
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ /* Lastly, wait for the GP to go idle */
+
+ do {
+ val = readl(par->gp_regs + GP_BLT_STATUS);
+ } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY));
+}
+
+static void lx_graphics_enable(struct fb_info *info)
+{
+ struct lxfb_par *par = info->par;
+ u32 temp, config;
+
+ /* Set the video request register */
+ writel(0, par->df_regs + DF_VIDEO_REQUEST);
+
+ /* Set up the polarities */
+
+ config = readl(par->df_regs + DF_DISPLAY_CFG);
+
+ config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK |
+ DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL);
+
+ config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT |
+ DF_DCFG_GV_PAL_BYP);
+
+ if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ config |= DF_DCFG_CRT_HSYNC_POL;
+
+ if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ config |= DF_DCFG_CRT_VSYNC_POL;
+
+ if (par->output & OUTPUT_PANEL) {
+ u32 msrlo, msrhi;
+
+ writel(DF_DEFAULT_TFT_PMTIM1,
+ par->df_regs + DF_PANEL_TIM1);
+ writel(DF_DEFAULT_TFT_PMTIM2,
+ par->df_regs + DF_PANEL_TIM2);
+ writel(DF_DEFAULT_TFT_DITHCTL,
+ par->df_regs + DF_DITHER_CONTROL);
+
+ msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW;
+ msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH;
+
+ wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi);
+ }
+
+ if (par->output & OUTPUT_CRT) {
+ config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN |
+ DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN;
+ }
+
+ writel(config, par->df_regs + DF_DISPLAY_CFG);
+
+ /* Turn the CRT dacs back on */
+
+ if (par->output & OUTPUT_CRT) {
+ temp = readl(par->df_regs + DF_MISC);
+ temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN);
+ writel(temp, par->df_regs + DF_MISC);
+ }
+
+ /* Turn the panel on (if it isn't already) */
+
+ if (par->output & OUTPUT_PANEL) {
+ temp = readl(par->df_regs + DF_FP_PM);
+
+ if (!(temp & 0x09))
+ writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM);
+ }
+
+ temp = readl(par->df_regs + DF_MISC);
+ temp = readl(par->df_regs + DF_DISPLAY_CFG);
+}
+
+unsigned int lx_framebuffer_size(void)
+{
+ unsigned int val;
+
+ /* The frame buffer size is reported by a VSM in VSA II */
+ /* Virtual Register Class = 0x02 */
+ /* VG_MEM_SIZE (1MB units) = 0x00 */
+
+ outw(0xFC53, 0xAC1C);
+ outw(0x0200, 0xAC1C);
+
+ val = (unsigned int)(inw(0xAC1E)) & 0xFE;
+ return (val << 20);
+}
+
+void lx_set_mode(struct fb_info *info)
+{
+ struct lxfb_par *par = info->par;
+ u64 msrval;
+
+ unsigned int max, dv, val, size;
+
+ unsigned int gcfg, dcfg;
+ int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+ int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+ /* Unlock the DC registers */
+ writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+ lx_graphics_disable(info);
+
+ lx_set_clock(info);
+
+ /* Set output mode */
+
+ rdmsrl(MSR_LX_DF_GLCONFIG, msrval);
+ msrval &= ~DF_CONFIG_OUTPUT_MASK;
+
+ if (par->output & OUTPUT_PANEL) {
+ msrval |= DF_OUTPUT_PANEL;
+
+ if (par->output & OUTPUT_CRT)
+ msrval |= DF_SIMULTANEOUS_CRT_AND_FP;
+ else
+ msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP;
+ } else {
+ msrval |= DF_OUTPUT_CRT;
+ }
+
+ wrmsrl(MSR_LX_DF_GLCONFIG, msrval);
+
+ /* Clear the various buffers */
+ /* FIXME: Adjust for panning here */
+
+ writel(0, par->dc_regs + DC_FB_START);
+ writel(0, par->dc_regs + DC_CB_START);
+ writel(0, par->dc_regs + DC_CURSOR_START);
+
+ /* FIXME: Add support for interlacing */
+ /* FIXME: Add support for scaling */
+
+ val = readl(par->dc_regs + DC_GENLCK_CTRL);
+ val &= ~(DC_GC_ALPHA_FLICK_ENABLE |
+ DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK);
+
+ /* Default scaling params */
+
+ writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE);
+ writel(0, par->dc_regs + DC_IRQ_FILT_CTL);
+ writel(val, par->dc_regs + DC_GENLCK_CTRL);
+
+ /* FIXME: Support compression */
+
+ if (info->fix.line_length > 4096)
+ dv = DC_DV_LINE_SIZE_8192;
+ else if (info->fix.line_length > 2048)
+ dv = DC_DV_LINE_SIZE_4096;
+ else if (info->fix.line_length > 1024)
+ dv = DC_DV_LINE_SIZE_2048;
+ else
+ dv = DC_DV_LINE_SIZE_1024;
+
+ max = info->fix.line_length * info->var.yres;
+ max = (max + 0x3FF) & 0xFFFFFC00;
+
+ writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP);
+
+ val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK;
+ writel(val | dv, par->dc_regs + DC_DV_CTL);
+
+ size = info->var.xres * (info->var.bits_per_pixel >> 3);
+
+ writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH);
+ writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE);
+
+ /* Set default watermark values */
+
+ rdmsrl(MSR_LX_DC_SPARE, msrval);
+
+ msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT |
+ DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD |
+ DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM);
+ msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI;
+ wrmsrl(MSR_LX_DC_SPARE, msrval);
+
+ gcfg = DC_GCFG_DFLE; /* Display fifo enable */
+ gcfg |= 0xB600; /* Set default priority */
+ gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */
+
+ dcfg = DC_DCFG_VDEN; /* Enable video data */
+ dcfg |= DC_DCFG_GDEN; /* Enable graphics */
+ dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */
+ dcfg |= DC_DCFG_TRUP; /* Update timings immediately */
+ dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */
+ dcfg |= DC_DCFG_VISL;
+ dcfg |= DC_DCFG_DCEN; /* Always center the display */
+
+ /* Set the current BPP mode */
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ dcfg |= DC_DCFG_DISP_MODE_8BPP;
+ break;
+
+ case 16:
+ dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP;
+ break;
+
+ case 32:
+ case 24:
+ dcfg |= DC_DCFG_DISP_MODE_24BPP;
+ break;
+ }
+
+ /* Now - set up the timings */
+
+ hactive = info->var.xres;
+ hblankstart = hactive;
+ hsyncstart = hblankstart + info->var.right_margin;
+ hsyncend = hsyncstart + info->var.hsync_len;
+ hblankend = hsyncend + info->var.left_margin;
+ htotal = hblankend;
+
+ vactive = info->var.yres;
+ vblankstart = vactive;
+ vsyncstart = vblankstart + info->var.lower_margin;
+ vsyncend = vsyncstart + info->var.vsync_len;
+ vblankend = vsyncend + info->var.upper_margin;
+ vtotal = vblankend;
+
+ writel((hactive - 1) | ((htotal - 1) << 16),
+ par->dc_regs + DC_H_ACTIVE_TIMING);
+ writel((hblankstart - 1) | ((hblankend - 1) << 16),
+ par->dc_regs + DC_H_BLANK_TIMING);
+ writel((hsyncstart - 1) | ((hsyncend - 1) << 16),
+ par->dc_regs + DC_H_SYNC_TIMING);
+
+ writel((vactive - 1) | ((vtotal - 1) << 16),
+ par->dc_regs + DC_V_ACTIVE_TIMING);
+
+ writel((vblankstart - 1) | ((vblankend - 1) << 16),
+ par->dc_regs + DC_V_BLANK_TIMING);
+
+ writel((vsyncstart - 1) | ((vsyncend - 1) << 16),
+ par->dc_regs + DC_V_SYNC_TIMING);
+
+ writel( (info->var.xres - 1) << 16 | (info->var.yres - 1),
+ par->dc_regs + DC_FB_ACTIVE);
+
+ /* And re-enable the graphics output */
+ lx_graphics_enable(info);
+
+ /* Write the two main configuration registers */
+ writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
+ writel(0, par->dc_regs + DC_ARB_CFG);
+ writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+ /* Lock the DC registers */
+ writel(0, par->dc_regs + DC_UNLOCK);
+}
+
+void lx_set_palette_reg(struct fb_info *info, unsigned regno,
+ unsigned red, unsigned green, unsigned blue)
+{
+ struct lxfb_par *par = info->par;
+ int val;
+
+ /* Hardware palette is in RGB 8-8-8 format. */
+
+ val = (red << 8) & 0xff0000;
+ val |= (green) & 0x00ff00;
+ val |= (blue >> 8) & 0x0000ff;
+
+ writel(regno, par->dc_regs + DC_PAL_ADDRESS);
+ writel(val, par->dc_regs + DC_PAL_DATA);
+}
+
+int lx_blank_display(struct fb_info *info, int blank_mode)
+{
+ struct lxfb_par *par = info->par;
+ u32 dcfg, fp_pm;
+ int blank, hsync, vsync;
+
+ /* CRT power saving modes. */
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ blank = 0; hsync = 1; vsync = 1;
+ break;
+ case FB_BLANK_NORMAL:
+ blank = 1; hsync = 1; vsync = 1;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ blank = 1; hsync = 1; vsync = 0;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ blank = 1; hsync = 0; vsync = 1;
+ break;
+ case FB_BLANK_POWERDOWN:
+ blank = 1; hsync = 0; vsync = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
+ dcfg &= ~(DF_DCFG_DAC_BL_EN
+ | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
+ if (!blank)
+ dcfg |= DF_DCFG_DAC_BL_EN;
+ if (hsync)
+ dcfg |= DF_DCFG_HSYNC_EN;
+ if (vsync)
+ dcfg |= DF_DCFG_VSYNC_EN;
+ writel(dcfg, par->df_regs + DF_DISPLAY_CFG);
+
+ /* Power on/off flat panel */
+
+ if (par->output & OUTPUT_PANEL) {
+ fp_pm = readl(par->df_regs + DF_FP_PM);
+ if (blank_mode == FB_BLANK_POWERDOWN)
+ fp_pm &= ~DF_FP_PM_P;
+ else
+ fp_pm |= DF_FP_PM_P;
+ writel(fp_pm, par->df_regs + DF_FP_PM);
+ }
+
+ return 0;
+}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index eb1a4812ad1d..b87ea21d3d78 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -379,10 +379,6 @@ int __init igafb_init(void)
if (fb_get_options("igafb", NULL))
return -ENODEV;
- /* Do not attach when we have a serial console. */
- if (!con_is_present())
- return -ENXIO;
-
pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) {
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
index 18ea4a549105..6455fd2a39f2 100644
--- a/drivers/video/imacfb.c
+++ b/drivers/video/imacfb.c
@@ -58,7 +58,7 @@ static int model = M_UNKNOWN;
static int manual_height;
static int manual_width;
-static int set_system(struct dmi_system_id *id)
+static int set_system(const struct dmi_system_id *id)
{
printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
id->ident, (long)id->driver_data);
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 5715b8ad0ddc..94f4511023d8 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -1391,7 +1391,7 @@ init_imstt(struct fb_info *info)
}
}
-#if USE_NV_MODES && defined(CONFIG_PPC)
+#if USE_NV_MODES && defined(CONFIG_PPC32)
{
int vmode = init_vmode, cmode = init_cmode;
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 16bc8d75e36e..6a47682d8614 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -924,10 +924,10 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
if (m > pll->max_m)
m = pll->max_m - 1;
for (testm = m - 1; testm <= m; testm++) {
- f_out = calc_vclock3(index, m, n, p);
+ f_out = calc_vclock3(index, testm, n, p);
if (splitm(index, testm, &m1, &m2)) {
- WRN_MSG("cannot split m = %d\n", m);
- n++;
+ WRN_MSG("cannot split m = %d\n",
+ testm);
continue;
}
if (clock > f_out)
@@ -1352,7 +1352,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
/* turn off PLL */
tmp = INREG(dpll_reg);
- dpll_reg &= ~DPLL_VCO_ENABLE;
+ tmp &= ~DPLL_VCO_ENABLE;
OUTREG(dpll_reg, tmp);
/* Set PLL parameters */
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index a038aa5a9e1c..45b9a5d55dec 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -525,130 +525,123 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var)
var->transp.length = 0;
}
-struct all_info {
- struct fb_info info;
- struct leo_par par;
-};
-
-static void leo_unmap_regs(struct of_device *op, struct all_info *all)
+static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
+ struct leo_par *par)
{
- if (all->par.lc_ss0_usr)
- of_iounmap(&op->resource[0], all->par.lc_ss0_usr, 0x1000);
- if (all->par.ld_ss0)
- of_iounmap(&op->resource[0], all->par.ld_ss0, 0x1000);
- if (all->par.ld_ss1)
- of_iounmap(&op->resource[0], all->par.ld_ss1, 0x1000);
- if (all->par.lx_krn)
- of_iounmap(&op->resource[0], all->par.lx_krn, 0x1000);
- if (all->par.cursor)
+ if (par->lc_ss0_usr)
+ of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000);
+ if (par->ld_ss0)
+ of_iounmap(&op->resource[0], par->ld_ss0, 0x1000);
+ if (par->ld_ss1)
+ of_iounmap(&op->resource[0], par->ld_ss1, 0x1000);
+ if (par->lx_krn)
+ of_iounmap(&op->resource[0], par->lx_krn, 0x1000);
+ if (par->cursor)
of_iounmap(&op->resource[0],
- all->par.cursor, sizeof(struct leo_cursor));
- if (all->info.screen_base)
- of_iounmap(&op->resource[0], all->info.screen_base, 0x800000);
+ par->cursor, sizeof(struct leo_cursor));
+ if (info->screen_base)
+ of_iounmap(&op->resource[0], info->screen_base, 0x800000);
}
-static int __devinit leo_init_one(struct of_device *op)
+static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct leo_par *par;
int linebytes, err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct leo_par), &op->dev);
+
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- spin_lock_init(&all->par.lock);
+ spin_lock_init(&par->lock);
- all->par.physbase = op->resource[0].start;
- all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+ par->physbase = op->resource[0].start;
+ par->which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, dp->node, 32);
- leo_fixup_var_rgb(&all->info.var);
+ sbusfb_fill_var(&info->var, dp->node, 32);
+ leo_fixup_var_rgb(&info->var);
linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+ info->var.xres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
- all->par.lc_ss0_usr =
+ par->lc_ss0_usr =
of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR,
0x1000, "leolc ss0usr");
- all->par.ld_ss0 =
+ par->ld_ss0 =
of_ioremap(&op->resource[0], LEO_OFF_LD_SS0,
0x1000, "leold ss0");
- all->par.ld_ss1 =
+ par->ld_ss1 =
of_ioremap(&op->resource[0], LEO_OFF_LD_SS1,
0x1000, "leold ss1");
- all->par.lx_krn =
+ par->lx_krn =
of_ioremap(&op->resource[0], LEO_OFF_LX_KRN,
0x1000, "leolx krn");
- all->par.cursor =
+ par->cursor =
of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR,
sizeof(struct leo_cursor), "leolx cursor");
- all->info.screen_base =
+ info->screen_base =
of_ioremap(&op->resource[0], LEO_OFF_SS0,
0x800000, "leo ram");
- if (!all->par.lc_ss0_usr ||
- !all->par.ld_ss0 ||
- !all->par.ld_ss1 ||
- !all->par.lx_krn ||
- !all->par.cursor ||
- !all->info.screen_base) {
- leo_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
+ if (!par->lc_ss0_usr ||
+ !par->ld_ss0 ||
+ !par->ld_ss1 ||
+ !par->lx_krn ||
+ !par->cursor ||
+ !info->screen_base)
+ goto out_unmap_regs;
- all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
- all->info.fbops = &leo_ops;
- all->info.par = &all->par;
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+ info->fbops = &leo_ops;
- leo_init_wids(&all->info);
- leo_init_hw(&all->info);
+ leo_init_wids(info);
+ leo_init_hw(info);
- leo_blank(0, &all->info);
+ leo_blank(0, info);
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- leo_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;;
- }
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_regs;
- leo_init_fix(&all->info, dp);
+ leo_init_fix(info, dp);
- err = register_framebuffer(&all->info);
- if (err < 0) {
- fb_dealloc_cmap(&all->info.cmap);
- leo_unmap_regs(op, all);
- kfree(all);
- return err;
- }
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
- dev_set_drvdata(&op->dev, all);
+ dev_set_drvdata(&op->dev, info);
printk("%s: leo at %lx:%lx\n",
dp->full_name,
- all->par.which_io, all->par.physbase);
+ par->which_io, par->physbase);
return 0;
-}
-static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_regs:
+ leo_unmap_regs(op, info, par);
+ framebuffer_release(info);
- return leo_init_one(op);
+out_err:
+ return err;
}
static int __devexit leo_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct leo_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- leo_unmap_regs(op, all);
+ leo_unmap_regs(op, info, par);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index da219c043c99..9de1c114f809 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -12,7 +12,7 @@ if LOGO
config FB_LOGO_EXTRA
bool
- depends on FB
+ depends on FB=y
default y if SPU_BASE
config LOGO_LINUX_MONO
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 80c03618eb53..2b0f799aa8da 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -34,8 +34,11 @@ extern const struct linux_logo logo_superh_vga16;
extern const struct linux_logo logo_superh_clut224;
extern const struct linux_logo logo_m32r_clut224;
-
-const struct linux_logo *fb_find_logo(int depth)
+/* logo's are marked __initdata. Use __init_refok to tell
+ * modpost that it is intended that this function uses data
+ * marked __initdata.
+ */
+const struct linux_logo * __init_refok fb_find_logo(int depth)
{
const struct linux_logo *logo = NULL;
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
index 7c76e079ca7d..d42346e7fdda 100644
--- a/drivers/video/matrox/g450_pll.c
+++ b/drivers/video/matrox/g450_pll.c
@@ -331,16 +331,19 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
tmp |= M1064_XPIXCLKCTRL_PLL_UP;
}
matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp);
-#ifdef __powerpc__
- /* This is necessary to avoid jitter on PowerPC
- * (OpenFirmware) systems, but apparently
- * introduces jitter, at least on a x86-64
- * using DVI.
- * A simple workaround is disable for non-PPC.
- */
- matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL, 0);
-#endif /* __powerpc__ */
- matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl);
+ /* DVI PLL preferred for frequencies up to
+ panel link max, standard PLL otherwise */
+ if (fout >= MINFO->max_pixel_clock_panellink)
+ tmp = 0;
+ else tmp =
+ M1064_XDVICLKCTRL_DVIDATAPATHSEL |
+ M1064_XDVICLKCTRL_C1DVICLKSEL |
+ M1064_XDVICLKCTRL_C1DVICLKEN |
+ M1064_XDVICLKCTRL_DVILOOPCTL |
+ M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
+ matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL,tmp);
+ matroxfb_DAC_out(PMINFO M1064_XPWRCTRL,
+ xpwrctrl);
matroxfb_DAC_unlock_irqrestore(flags);
}
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
index df39c3193735..7a98ce8043d7 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.h
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -33,6 +33,21 @@ void DAC1064_global_restore(WPMINFO2);
#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
+ /* drive DVI by standard(0)/DVI(1) PLL */
+ /* if set(1), C?DVICLKEN and C?DVICLKSEL must be set(1) */
+#define M1064_XDVICLKCTRL_DVIDATAPATHSEL 0x01
+ /* drive CRTC1 by standard(0)/DVI(1) PLL */
+#define M1064_XDVICLKCTRL_C1DVICLKSEL 0x02
+ /* drive CRTC2 by standard(0)/DVI(1) PLL */
+#define M1064_XDVICLKCTRL_C2DVICLKSEL 0x04
+ /* pixel clock allowed to(0)/blocked from(1) driving CRTC1 */
+#define M1064_XDVICLKCTRL_C1DVICLKEN 0x08
+ /* DVI PLL loop filter bandwidth selection bits */
+#define M1064_XDVICLKCTRL_DVILOOPCTL 0x30
+ /* CRTC2 pixel clock allowed to(0)/blocked from(1) driving CRTC2 */
+#define M1064_XDVICLKCTRL_C2DVICLKEN 0x40
+ /* P1PLL loop filter bandwith selection */
+#define M1064_XDVICLKCTRL_P1LOOPBWDTCTL 0x80
#define M1064_XCURCOL0RED 0x08
#define M1064_XCURCOL0GREEN 0x09
#define M1064_XCURCOL0BLUE 0x0A
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index d59577c8de86..f3107ad7e545 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -424,6 +424,7 @@ struct matrox_fb_info {
} mmio;
unsigned int max_pixel_clock;
+ unsigned int max_pixel_clock_panellink;
struct matrox_switch* hw_switch;
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 5948e54b9ef9..ab7fb50bc1de 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -658,6 +658,7 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) {
MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) |
wtst_xlat[MINFO->values.reg.mctlwtst & 7];
}
+ MINFO->max_pixel_clock_panellink = bd->pins[47] * 4000;
return 0;
}
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 43f62d8ee41d..443e3c85a9a0 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -50,7 +50,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
static int nvidia_bl_update_status(struct backlight_device *bd)
{
- struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+ struct nvidia_par *par = bl_get_data(bd);
u32 tmp_pcrt, tmp_pmc, fpcontrol;
int level;
diff --git a/drivers/video/output.c b/drivers/video/output.c
index 1473f2c892d2..f2df5519c9c4 100644
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
-static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+static ssize_t video_output_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
ssize_t ret_size = 0;
struct output_device *od = to_output_device(dev);
@@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf)
return ret_size;
}
-static ssize_t video_output_store_state(struct class_device *dev,
- const char *buf,size_t count)
+static ssize_t video_output_store_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,size_t count)
{
char *endp;
struct output_device *od = to_output_device(dev);
@@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev,
return count;
}
-static void video_output_class_release(struct class_device *dev)
+static void video_output_release(struct device *dev)
{
struct output_device *od = to_output_device(dev);
kfree(od);
}
-static struct class_device_attribute video_output_attributes[] = {
+static struct device_attribute video_output_attributes[] = {
__ATTR(state, 0644, video_output_show_state, video_output_store_state),
__ATTR_NULL,
};
+
static struct class video_output_class = {
.name = "video_output",
- .release = video_output_class_release,
- .class_dev_attrs = video_output_attributes,
+ .dev_release = video_output_release,
+ .dev_attrs = video_output_attributes,
};
struct output_device *video_output_register(const char *name,
@@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name,
goto error_return;
}
new_dev->props = op;
- new_dev->class_dev.class = &video_output_class;
- new_dev->class_dev.dev = dev;
- strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
- class_set_devdata(&new_dev->class_dev,devdata);
- ret_code = class_device_register(&new_dev->class_dev);
+ new_dev->dev.class = &video_output_class;
+ new_dev->dev.parent = dev;
+ strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_dev->dev, devdata);
+ ret_code = device_register(&new_dev->dev);
if (ret_code) {
kfree(new_dev);
goto error_return;
@@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev)
{
if (!dev)
return;
- class_device_unregister(&dev->class_dev);
+ device_unregister(&dev->dev);
}
EXPORT_SYMBOL(video_output_unregister);
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 637b78bb4bf7..58496061142d 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -255,107 +255,95 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no
info->fix.accel = FB_ACCEL_SUN_CGTHREE;
}
-struct all_info {
- struct fb_info info;
- struct p9100_par par;
-};
-
-static int __devinit p9100_init_one(struct of_device *op)
+static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct p9100_par *par;
int linebytes, err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev);
+
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- spin_lock_init(&all->par.lock);
+ spin_lock_init(&par->lock);
/* This is the framebuffer and the only resource apps can mmap. */
- all->par.physbase = op->resource[2].start;
- all->par.which_io = op->resource[2].flags & IORESOURCE_BITS;
-
- sbusfb_fill_var(&all->info.var, dp->node, 8);
- all->info.var.red.length = 8;
- all->info.var.green.length = 8;
- all->info.var.blue.length = 8;
-
- linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
-
- all->par.regs = of_ioremap(&op->resource[0], 0,
- sizeof(struct p9100_regs), "p9100 regs");
- if (!all->par.regs) {
- kfree(all);
- return -ENOMEM;
- }
+ par->physbase = op->resource[2].start;
+ par->which_io = op->resource[2].flags & IORESOURCE_BITS;
- all->info.flags = FBINFO_DEFAULT;
- all->info.fbops = &p9100_ops;
- all->info.screen_base = of_ioremap(&op->resource[2], 0,
- all->par.fbsize, "p9100 ram");
- if (!all->info.screen_base) {
- of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct p9100_regs));
- kfree(all);
- return -ENOMEM;
- }
- all->info.par = &all->par;
+ sbusfb_fill_var(&info->var, dp->node, 8);
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
- p9100_blank(0, &all->info);
+ linebytes = of_getintprop_default(dp, "linebytes", info->var.xres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct p9100_regs));
- of_iounmap(&op->resource[2],
- all->info.screen_base, all->par.fbsize);
- kfree(all);
- return -ENOMEM;
- }
+ par->regs = of_ioremap(&op->resource[0], 0,
+ sizeof(struct p9100_regs), "p9100 regs");
+ if (!par->regs)
+ goto out_release_fb;
- p9100_init_fix(&all->info, linebytes, dp);
-
- err = register_framebuffer(&all->info);
- if (err < 0) {
- fb_dealloc_cmap(&all->info.cmap);
- of_iounmap(&op->resource[0],
- all->par.regs, sizeof(struct p9100_regs));
- of_iounmap(&op->resource[2],
- all->info.screen_base, all->par.fbsize);
- kfree(all);
- return err;
- }
- fb_set_cmap(&all->info.cmap, &all->info);
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &p9100_ops;
+ info->screen_base = of_ioremap(&op->resource[2], 0,
+ par->fbsize, "p9100 ram");
+ if (!info->screen_base)
+ goto out_unmap_regs;
+
+ p9100_blank(0, info);
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_screen;
- dev_set_drvdata(&op->dev, all);
+ p9100_init_fix(info, linebytes, dp);
+
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
+
+ fb_set_cmap(&info->cmap, info);
+
+ dev_set_drvdata(&op->dev, info);
printk("%s: p9100 at %lx:%lx\n",
dp->full_name,
- all->par.which_io, all->par.physbase);
+ par->which_io, par->physbase);
return 0;
-}
-static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_screen:
+ of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
+
+out_unmap_regs:
+ of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
+
+out_release_fb:
+ framebuffer_release(info);
- return p9100_init_one(op);
+out_err:
+ return err;
}
static int __devexit p9100_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct p9100_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- of_iounmap(&op->resource[0], all->par.regs, sizeof(struct p9100_regs));
- of_iounmap(&op->resource[2], all->info.screen_base, all->par.fbsize);
+ of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
+ of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 8503e733a172..cbe71a5338d0 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -17,6 +17,8 @@
* more details.
*/
+#undef DEBUG
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -535,33 +537,35 @@ static int __devinit platinumfb_probe(struct of_device* odev,
volatile __u8 *fbuffer;
int bank0, bank1, bank2, bank3, rc;
- printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
+ dev_info(&odev->dev, "Found Apple Platinum video hardware\n");
info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
- if (info == NULL)
+ if (info == NULL) {
+ dev_err(&odev->dev, "Failed to allocate fbdev !\n");
return -ENOMEM;
+ }
pinfo = info->par;
if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
- printk(KERN_ERR "platinumfb: Can't get resources\n");
- framebuffer_release(info);
- return -ENXIO;
- }
- if (!request_mem_region(pinfo->rsrc_reg.start,
- pinfo->rsrc_reg.start -
- pinfo->rsrc_reg.end + 1,
- "platinumfb registers")) {
+ dev_err(&odev->dev, "Can't get resources\n");
framebuffer_release(info);
return -ENXIO;
}
+ dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n",
+ (unsigned long long)pinfo->rsrc_reg.start,
+ (unsigned long long)pinfo->rsrc_reg.end);
+ dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n",
+ (unsigned long long)pinfo->rsrc_fb.start,
+ (unsigned long long)pinfo->rsrc_fb.end);
+
+ /* Do not try to request register space, they overlap with the
+ * northbridge and that can fail. Only request framebuffer
+ */
if (!request_mem_region(pinfo->rsrc_fb.start,
- pinfo->rsrc_fb.start
- - pinfo->rsrc_fb.end + 1,
+ pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1,
"platinumfb framebuffer")) {
- release_mem_region(pinfo->rsrc_reg.start,
- pinfo->rsrc_reg.end -
- pinfo->rsrc_reg.start + 1);
+ printk(KERN_ERR "platinumfb: Can't request framebuffer !\n");
framebuffer_release(info);
return -ENXIO;
}
@@ -600,7 +604,8 @@ static int __devinit platinumfb_probe(struct of_device* odev,
bank2 = fbuffer[0x200000] == 0x56;
bank3 = fbuffer[0x300000] == 0x78;
pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
- printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024),
+ printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n",
+ (unsigned int) (pinfo->total_vram / 1024 / 1024),
bank3, bank2, bank1, bank0);
/*
@@ -644,16 +649,15 @@ static int __devexit platinumfb_remove(struct of_device* odev)
unregister_framebuffer (info);
/* Unmap frame buffer and registers */
+ iounmap(pinfo->frame_buffer);
+ iounmap(pinfo->platinum_regs);
+ iounmap(pinfo->cmap_regs);
+
release_mem_region(pinfo->rsrc_fb.start,
pinfo->rsrc_fb.end -
pinfo->rsrc_fb.start + 1);
- release_mem_region(pinfo->rsrc_reg.start,
- pinfo->rsrc_reg.end -
- pinfo->rsrc_reg.start + 1);
- iounmap(pinfo->frame_buffer);
- iounmap(pinfo->platinum_regs);
+
release_mem_region(pinfo->cmap_regs_phys, 0x1000);
- iounmap(pinfo->cmap_regs);
framebuffer_release(info);
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 3972aa8cf859..646ec823c168 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1067,7 +1067,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
info->fix.smem_len = ps3fb_videomemory.size - offset;
info->pseudo_palette = info->par;
info->par = NULL;
- info->flags = FBINFO_FLAG_DEFAULT;
+ info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0)
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 0f88c30f94f8..7d6c29800d14 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -94,6 +94,7 @@
#define DISP_DIWCONF (DISP_BASE + 0xe8)
#define DISP_DIWHSTRT (DISP_BASE + 0xec)
#define DISP_DIWVSTRT (DISP_BASE + 0xf0)
+#define DISP_PIXDEPTH (DISP_BASE + 0x108)
/* Pixel clocks, one for TV output, doubled for VGA output */
#define TV_CLK 74239
@@ -143,6 +144,7 @@ static struct pvr2fb_par {
unsigned char is_lowres; /* Is horizontal pixel-doubling enabled? */
unsigned long mmio_base; /* MMIO base */
+ u32 palette[16];
} *currentpar;
static struct fb_info *fb_info;
@@ -599,6 +601,7 @@ static void pvr2_init_display(struct fb_info *info)
/* bits per pixel */
fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE);
+ fb_writel(bytesperpixel << 2, DISP_PIXDEPTH);
/* video enable, color sync, interlace,
* hsync and vsync polarity (currently unused) */
@@ -790,7 +793,7 @@ static int __devinit pvr2fb_common_init(void)
fb_info->fbops = &pvr2fb_ops;
fb_info->fix = pvr2_fix;
fb_info->par = currentpar;
- fb_info->pseudo_palette = (void *)(fb_info->par + 1);
+ fb_info->pseudo_palette = currentpar->palette;
fb_info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
if (video_output == VO_VGA)
@@ -807,6 +810,8 @@ static int __devinit pvr2fb_common_init(void)
if (register_framebuffer(fb_info) < 0)
goto out_err;
+ /*Must write PIXDEPTH to register before anything is displayed - so force init */
+ pvr2_init_display(fb_info);
modememused = get_line_length(fb_info->var.xres_virtual,
fb_info->var.bits_per_pixel);
@@ -1082,15 +1087,15 @@ static int __init pvr2fb_init(void)
#endif
size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
- fb_info = kmalloc(size, GFP_KERNEL);
+ fb_info = framebuffer_alloc(sizeof(struct pvr2fb_par), NULL);
+
if (!fb_info) {
printk(KERN_ERR "Failed to allocate memory for fb_info\n");
return -ENOMEM;
}
- memset(fb_info, 0, size);
- currentpar = (struct pvr2fb_par *)(fb_info + 1);
+ currentpar = fb_info->par;
for (i = 0; i < ARRAY_SIZE(board_driver); i++) {
struct pvr2_board *pvr_board = board_driver + i;
@@ -1103,7 +1108,7 @@ static int __init pvr2fb_init(void)
if (ret != 0) {
printk(KERN_ERR "pvr2fb: Failed init of %s device\n",
pvr_board->name);
- kfree(fb_info);
+ framebuffer_release(fb_info);
break;
}
}
@@ -1127,7 +1132,7 @@ static void __exit pvr2fb_exit(void)
#endif
unregister_framebuffer(fb_info);
- kfree(fb_info);
+ framebuffer_release(fb_info);
}
module_init(pvr2fb_init);
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 81e571d59b50..a280a52f8efe 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -66,7 +66,7 @@ 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] __initdata = "";
+static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
#endif
static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 0fe547842c64..5c47968e7f21 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -307,7 +307,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
static int riva_bl_update_status(struct backlight_device *bd)
{
- struct riva_par *par = class_get_devdata(&bd->class_dev);
+ struct riva_par *par = bl_get_data(bd);
U032 tmp_pcrt, tmp_pmc;
int level;
@@ -2146,7 +2146,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd)
* ------------------------------------------------------------------------- */
#ifndef MODULE
-static int __init rivafb_setup(char *options)
+static int __devinit rivafb_setup(char *options)
{
char *this_opt;
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index ed3426062a8b..8a4c6470d799 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -474,6 +474,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
{
unsigned long flags;
unsigned long irqen;
+ void __iomem *regs = fbi->io;
local_irq_save(flags);
@@ -483,9 +484,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
fbi->palette_ready = 1;
/* enable IRQ */
- irqen = readl(S3C2410_LCDINTMSK);
+ irqen = readl(regs + S3C2410_LCDINTMSK);
irqen &= ~S3C2410_LCDINT_FRSYNC;
- writel(irqen, S3C2410_LCDINTMSK);
+ writel(irqen, regs + S3C2410_LCDINTMSK);
}
local_irq_restore(flags);
@@ -680,6 +681,7 @@ static inline void modify_gpio(void __iomem *reg,
static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
{
unsigned long flags;
+ void __iomem *regs = fbi->io;
/* Initialise LCD with values from haret */
@@ -694,25 +696,25 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
local_irq_restore(flags);
- writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
- writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
- writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
- writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
- writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);
+ writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
+ writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
+ writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
+ writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
+ writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
s3c2410fb_set_lcdaddr(fbi);
dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel);
- writel(mach_info->lpcsel, S3C2410_LPCSEL);
+ writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
- dprintk("replacing TPAL %08x\n", readl(S3C2410_TPAL));
+ dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
/* ensure temporary palette disabled */
- writel(0x00, S3C2410_TPAL);
+ writel(0x00, regs + S3C2410_TPAL);
/* Enable video by setting the ENVID bit to 1 */
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
- writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+ writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
return 0;
}
@@ -720,6 +722,7 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
{
unsigned int i;
unsigned long ent;
+ void __iomem *regs = fbi->io;
fbi->palette_ready = 0;
@@ -727,14 +730,14 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR)
continue;
- writel(ent, S3C2410_TFTPAL(i));
+ writel(ent, regs + S3C2410_TFTPAL(i));
/* it seems the only way to know exactly
* if the palette wrote ok, is to check
* to see if the value verifies ok
*/
- if (readw(S3C2410_TFTPAL(i)) == ent)
+ if (readw(regs + S3C2410_TFTPAL(i)) == ent)
fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;
else
fbi->palette_ready = 1; /* retry */
@@ -744,14 +747,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
{
struct s3c2410fb_info *fbi = dev_id;
- unsigned long lcdirq = readl(S3C2410_LCDINTPND);
+ void __iomem *regs = fbi->io;
+ unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
if (lcdirq & S3C2410_LCDINT_FRSYNC) {
if (fbi->palette_ready)
s3c2410fb_write_palette(fbi);
- writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDINTPND);
- writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDSRCPND);
+ writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
+ writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
}
return IRQ_HANDLED;
@@ -764,9 +768,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
struct s3c2410fb_info *info;
struct fb_info *fbinfo;
struct s3c2410fb_hw *mregs;
+ struct resource *res;
int ret;
int irq;
int i;
+ int size;
u32 lcdcon1;
mach_info = pdev->dev.platform_data;
@@ -788,11 +794,32 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
return -ENOMEM;
}
-
info = fbinfo->par;
info->fb = fbinfo;
info->dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory registersn");
+ ret = -ENXIO;
+ goto dealloc_fb;
+ }
+
+ size = (res->end - res->start)+1;
+ info->mem = request_mem_region(res->start, size, pdev->name);
+ if (info->mem == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region\n");
+ ret = -ENOENT;
+ goto dealloc_fb;
+ }
+
+ info->io = ioremap(res->start, size);
+ if (info->io == NULL) {
+ dev_err(&pdev->dev, "ioremap() of registers failed\n");
+ ret = -ENXIO;
+ goto release_mem;
+ }
+
platform_set_drvdata(pdev, fbinfo);
dprintk("devinit\n");
@@ -803,8 +830,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
/* Stop the video and unset ENVID if set */
info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
- lcdcon1 = readl(S3C2410_LCDCON1);
- writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+ lcdcon1 = readl(info->io + S3C2410_LCDCON1);
+ writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
info->mach_info = pdev->dev.platform_data;
@@ -855,19 +882,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
for (i = 0; i < 256; i++)
info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
- if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c2410-lcd")) {
- ret = -EBUSY;
- goto dealloc_fb;
- }
-
-
- dprintk("got LCD region\n");
-
ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
if (ret) {
dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
ret = -EBUSY;
- goto release_mem;
+ goto release_regs;
}
info->clk = clk_get(NULL, "lcd");
@@ -889,6 +908,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto release_clock;
}
+
dprintk("got video memory\n");
ret = s3c2410fb_init_registers(info);
@@ -916,8 +936,11 @@ release_clock:
clk_put(info->clk);
release_irq:
free_irq(irq,info);
+release_regs:
+ iounmap(info->io);
release_mem:
- release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
+ release_resource(info->mem);
+ kfree(info->mem);
dealloc_fb:
framebuffer_release(fbinfo);
return ret;
@@ -935,7 +958,7 @@ static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
local_irq_save(flags);
fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
- writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+ writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1);
local_irq_restore(flags);
}
@@ -962,7 +985,10 @@ static int s3c2410fb_remove(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
free_irq(irq,info);
- release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
+
+ release_resource(info->mem);
+ kfree(info->mem);
+ iounmap(info->io);
unregister_framebuffer(fbinfo);
return 0;
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index f3f8a8e15012..17c7915b7acd 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -30,6 +30,9 @@ struct s3c2410fb_info {
struct device *dev;
struct clk *clk;
+ struct resource *mem;
+ void __iomem *io;
+
struct s3c2410fb_mach_info *mach_info;
/* raw memory addresses */
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 3d7507ad55f6..b855f4a34afe 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2174,11 +2174,10 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
#if defined(CONFIG_FB_SAVAGE_ACCEL)
/* FIFO size + padding for commands */
- info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+ info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL);
err = -ENOMEM;
if (info->pixmap.addr) {
- memset(info->pixmap.addr, 0, 8*1024);
info->pixmap.size = 8*1024;
info->pixmap.scan_align = 4;
info->pixmap.buf_align = 4;
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
index 34ef859ee414..963a454b7074 100644
--- a/drivers/video/sbuslib.c
+++ b/drivers/video/sbuslib.c
@@ -190,17 +190,6 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
EXPORT_SYMBOL(sbusfb_ioctl_helper);
#ifdef CONFIG_COMPAT
-struct fbcmap32 {
- int index; /* first element (0 origin) */
- int count;
- u32 red;
- u32 green;
- u32 blue;
-};
-
-#define FBIOPUTCMAP32 _IOW('F', 3, struct fbcmap32)
-#define FBIOGETCMAP32 _IOW('F', 4, struct fbcmap32)
-
static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
struct fbcmap32 __user *argp = (void __user *)arg;
@@ -223,20 +212,6 @@ static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long
(unsigned long)p);
}
-struct fbcursor32 {
- short set; /* what to set, choose from the list above */
- short enable; /* cursor on/off */
- struct fbcurpos pos; /* cursor position */
- struct fbcurpos hot; /* cursor hot spot */
- struct fbcmap32 cmap; /* color map info */
- struct fbcurpos size; /* cursor bit map size */
- u32 image; /* cursor image bits */
- u32 mask; /* cursor mask bits */
-};
-
-#define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32)
-#define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32)
-
static int fbiogscursor(struct fb_info *info, unsigned long arg)
{
struct fbcursor __user *p = compat_alloc_user_space(sizeof(*p));
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index c97709ecbad0..e7c8db2eb49b 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -1100,13 +1100,18 @@ stifb_init_fb(struct sti_struct *sti, int bpp_pref)
/* only supported cards are allowed */
switch (fb->id) {
case CRT_ID_VISUALIZE_EG:
- /* look for a double buffering device like e.g. the
- "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
- which won't work. The same device in non-double
- buffering mode returns "INTERNAL_EG_X1024". */
- if (strstr(sti->outptr.dev_name, "EG_DX")) {
- printk(KERN_WARNING
- "stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
+ /* Visualize cards can run either in "double buffer" or
+ "standard" mode. Depending on the mode, the card reports
+ a different device name, e.g. "INTERNAL_EG_DX1024" in double
+ buffer mode and "INTERNAL_EG_X1024" in standard mode.
+ Since this driver only supports standard mode, we check
+ if the device name contains the string "DX" and tell the
+ user how to reconfigure the card. */
+ if (strstr(sti->outptr.dev_name, "DX")) {
+ printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
+ "support '%s' in double-buffer mode.\n"
+ KERN_WARNING "WARNING: Please disable the double-buffer mode "
+ "in IPL menu (the PARISC-BIOS).\n",
sti->outptr.dev_name);
goto out_err0;
}
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 5a99669232ce..e5a9ddb3c8be 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -345,88 +345,82 @@ tcx_init_fix(struct fb_info *info, int linebytes)
info->fix.accel = FB_ACCEL_SUN_TCX;
}
-struct all_info {
- struct fb_info info;
- struct tcx_par par;
-};
-
-static void tcx_unmap_regs(struct of_device *op, struct all_info *all)
+static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
+ struct tcx_par *par)
{
- if (all->par.tec)
+ if (par->tec)
of_iounmap(&op->resource[7],
- all->par.tec, sizeof(struct tcx_tec));
- if (all->par.thc)
+ par->tec, sizeof(struct tcx_tec));
+ if (par->thc)
of_iounmap(&op->resource[9],
- all->par.thc, sizeof(struct tcx_thc));
- if (all->par.bt)
+ par->thc, sizeof(struct tcx_thc));
+ if (par->bt)
of_iounmap(&op->resource[8],
- all->par.bt, sizeof(struct bt_regs));
- if (all->par.cplane)
+ par->bt, sizeof(struct bt_regs));
+ if (par->cplane)
of_iounmap(&op->resource[4],
- all->par.cplane, all->par.fbsize * sizeof(u32));
- if (all->info.screen_base)
+ par->cplane, par->fbsize * sizeof(u32));
+ if (info->screen_base)
of_iounmap(&op->resource[0],
- all->info.screen_base, all->par.fbsize);
+ info->screen_base, par->fbsize);
}
static int __devinit tcx_init_one(struct of_device *op)
{
struct device_node *dp = op->node;
- struct all_info *all;
+ struct fb_info *info;
+ struct tcx_par *par;
int linebytes, i, err;
- all = kzalloc(sizeof(*all), GFP_KERNEL);
- if (!all)
- return -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct tcx_par), &op->dev);
- spin_lock_init(&all->par.lock);
+ err = -ENOMEM;
+ if (!info)
+ goto out_err;
+ par = info->par;
- all->par.lowdepth =
+ spin_lock_init(&par->lock);
+
+ par->lowdepth =
(of_find_property(dp, "tcx-8-bit", NULL) != NULL);
- sbusfb_fill_var(&all->info.var, dp->node, 8);
- all->info.var.red.length = 8;
- all->info.var.green.length = 8;
- all->info.var.blue.length = 8;
+ sbusfb_fill_var(&info->var, dp->node, 8);
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
linebytes = of_getintprop_default(dp, "linebytes",
- all->info.var.xres);
- all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+ info->var.xres);
+ par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
- all->par.tec = of_ioremap(&op->resource[7], 0,
+ par->tec = of_ioremap(&op->resource[7], 0,
sizeof(struct tcx_tec), "tcx tec");
- all->par.thc = of_ioremap(&op->resource[9], 0,
+ par->thc = of_ioremap(&op->resource[9], 0,
sizeof(struct tcx_thc), "tcx thc");
- all->par.bt = of_ioremap(&op->resource[8], 0,
+ par->bt = of_ioremap(&op->resource[8], 0,
sizeof(struct bt_regs), "tcx dac");
- all->info.screen_base = of_ioremap(&op->resource[0], 0,
- all->par.fbsize, "tcx ram");
- if (!all->par.tec || !all->par.thc ||
- !all->par.bt || !all->info.screen_base) {
- tcx_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
-
- memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
- if (!all->par.lowdepth) {
- all->par.cplane = of_ioremap(&op->resource[4], 0,
- all->par.fbsize * sizeof(u32),
+ info->screen_base = of_ioremap(&op->resource[0], 0,
+ par->fbsize, "tcx ram");
+ if (!par->tec || !par->thc ||
+ !par->bt || !info->screen_base)
+ goto out_unmap_regs;
+
+ memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map));
+ if (!par->lowdepth) {
+ par->cplane = of_ioremap(&op->resource[4], 0,
+ par->fbsize * sizeof(u32),
"tcx cplane");
- if (!all->par.cplane) {
- tcx_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
+ if (!par->cplane)
+ goto out_unmap_regs;
} else {
- all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
- all->par.mmap_map[4].size = SBUS_MMAP_EMPTY;
- all->par.mmap_map[5].size = SBUS_MMAP_EMPTY;
- all->par.mmap_map[6].size = SBUS_MMAP_EMPTY;
+ par->mmap_map[1].size = SBUS_MMAP_EMPTY;
+ par->mmap_map[4].size = SBUS_MMAP_EMPTY;
+ par->mmap_map[5].size = SBUS_MMAP_EMPTY;
+ par->mmap_map[6].size = SBUS_MMAP_EMPTY;
}
- all->par.physbase = 0;
- all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+ par->physbase = 0;
+ par->which_io = op->resource[0].flags & IORESOURCE_BITS;
for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
int j;
@@ -444,53 +438,54 @@ static int __devinit tcx_init_one(struct of_device *op)
j = i;
break;
};
- all->par.mmap_map[i].poff = op->resource[j].start;
+ par->mmap_map[i].poff = op->resource[j].start;
}
- all->info.flags = FBINFO_DEFAULT;
- all->info.fbops = &tcx_ops;
- all->info.par = &all->par;
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &tcx_ops;
/* Initialize brooktree DAC. */
- sbus_writel(0x04 << 24, &all->par.bt->addr); /* color planes */
- sbus_writel(0xff << 24, &all->par.bt->control);
- sbus_writel(0x05 << 24, &all->par.bt->addr);
- sbus_writel(0x00 << 24, &all->par.bt->control);
- sbus_writel(0x06 << 24, &all->par.bt->addr); /* overlay plane */
- sbus_writel(0x73 << 24, &all->par.bt->control);
- sbus_writel(0x07 << 24, &all->par.bt->addr);
- sbus_writel(0x00 << 24, &all->par.bt->control);
-
- tcx_reset(&all->info);
-
- tcx_blank(FB_BLANK_UNBLANK, &all->info);
-
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- tcx_unmap_regs(op, all);
- kfree(all);
- return -ENOMEM;
- }
+ sbus_writel(0x04 << 24, &par->bt->addr); /* color planes */
+ sbus_writel(0xff << 24, &par->bt->control);
+ sbus_writel(0x05 << 24, &par->bt->addr);
+ sbus_writel(0x00 << 24, &par->bt->control);
+ sbus_writel(0x06 << 24, &par->bt->addr); /* overlay plane */
+ sbus_writel(0x73 << 24, &par->bt->control);
+ sbus_writel(0x07 << 24, &par->bt->addr);
+ sbus_writel(0x00 << 24, &par->bt->control);
+
+ tcx_reset(info);
- fb_set_cmap(&all->info.cmap, &all->info);
- tcx_init_fix(&all->info, linebytes);
+ tcx_blank(FB_BLANK_UNBLANK, info);
- err = register_framebuffer(&all->info);
- if (err < 0) {
- fb_dealloc_cmap(&all->info.cmap);
- tcx_unmap_regs(op, all);
- kfree(all);
- return err;
- }
+ if (fb_alloc_cmap(&info->cmap, 256, 0))
+ goto out_unmap_regs;
+
+ fb_set_cmap(&info->cmap, info);
+ tcx_init_fix(info, linebytes);
+
+ err = register_framebuffer(info);
+ if (err < 0)
+ goto out_dealloc_cmap;
- dev_set_drvdata(&op->dev, all);
+ dev_set_drvdata(&op->dev, info);
printk("%s: TCX at %lx:%lx, %s\n",
dp->full_name,
- all->par.which_io,
+ par->which_io,
op->resource[0].start,
- all->par.lowdepth ? "8-bit only" : "24-bit depth");
+ par->lowdepth ? "8-bit only" : "24-bit depth");
return 0;
+
+out_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
+
+out_unmap_regs:
+ tcx_unmap_regs(op, info, par);
+
+out_err:
+ return err;
}
static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match)
@@ -502,14 +497,15 @@ static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id
static int __devexit tcx_remove(struct of_device *op)
{
- struct all_info *all = dev_get_drvdata(&op->dev);
+ struct fb_info *info = dev_get_drvdata(&op->dev);
+ struct tcx_par *par = info->par;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- tcx_unmap_regs(op, all);
+ tcx_unmap_regs(op, info, par);
- kfree(all);
+ framebuffer_release(info);
dev_set_drvdata(&op->dev, NULL);
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 89facb73edfc..d292a37ec7d6 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -849,7 +849,7 @@ tgafb_clut_imageblit(struct fb_info *info, const struct fb_image *image)
u32 *palette = ((u32 *)info->pseudo_palette);
unsigned long pos, line_length, i, j;
const unsigned char *data;
- void *regs_base, *fb_base;
+ void __iomem *regs_base, *fb_base;
dx = image->dx;
dy = image->dy;
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
deleted file mode 100644
index e6f7c78da68b..000000000000
--- a/drivers/video/tx3912fb.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * drivers/video/tx3912fb.c
- *
- * Copyright (C) 1999 Harald Koerfgen
- * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- * Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/fb.h>
-#include <asm/io.h>
-#include <asm/bootinfo.h>
-#include <asm/uaccess.h>
-#include <asm/tx3912.h>
-#include <video/tx3912.h>
-
-/*
- * Frame buffer, palette and console structures
- */
-static struct fb_info fb_info;
-static u32 cfb8[16];
-
-static struct fb_fix_screeninfo tx3912fb_fix __initdata = {
- .id = "tx3912fb",
- .smem_len = ((240 * 320)/2),
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_TRUECOLOR,
- .xpanstep = 1,
- .ypanstep = 1,
- .ywrapstep = 1,
- .accel = FB_ACCEL_NONE,
-};
-
-static struct fb_var_screeninfo tx3912fb_var = {
- .xres = 240,
- .yres = 320,
- .xres_virtual = 240,
- .yres_virtual = 320,
- .bits_per_pixel =4,
- .red = { 0, 4, 0 }, /* ??? */
- .green = { 0, 4, 0 },
- .blue = { 0, 4, 0 },
- .activate = FB_ACTIVATE_NOW,
- .width = -1,
- .height = -1,
- .pixclock = 20000,
- .left_margin = 64,
- .right_margin = 64,
- .upper_margin = 32,
- .lower_margin = 32,
- .hsync_len = 64,
- .vsync_len = 2,
- .vmode = FB_VMODE_NONINTERLACED,
-};
-
-/*
- * Interface used by the world
- */
-int tx3912fb_init(void);
-
-static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
- u_int blue, u_int transp,
- struct fb_info *info);
-
-/*
- * Macros
- */
-#define get_line_length(xres_virtual, bpp) \
- (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
-
-/*
- * Frame buffer operations structure used by console driver
- */
-static struct fb_ops tx3912fb_ops = {
- .owner = THIS_MODULE,
- .fb_setcolreg = tx3912fb_setcolreg,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
-static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- /*
- * Memory limit
- */
- line_length =
- get_line_length(var->xres_virtual, var->bits_per_pixel);
- if ((line_length * var->yres_virtual) > info->fix.smem_len)
- return -ENOMEM;
-
- return 0;
-}
-
-static int tx3912fb_set_par(struct fb_info *info)
-{
- u_long tx3912fb_paddr = 0;
-
- /* Disable the video logic */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
- TX3912_VIDEO_CTRL1);
- udelay(200);
-
- /* Set start address for DMA transfer */
- outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
-
- /* Set end address for DMA transfer */
- outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
-
- /* Set the pixel depth */
- switch (info->var.bits_per_pixel) {
- case 1:
- /* Monochrome */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- info->fix.visual = FB_VISUAL_MONO10;
- break;
- case 4:
- /* 4-bit gray */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- outl(inl(TX3912_VIDEO_CTRL1) |
- TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
- TX3912_VIDEO_CTRL1);
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- break;
- case 8:
- /* 8-bit color */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- outl(inl(TX3912_VIDEO_CTRL1) |
- TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
- TX3912_VIDEO_CTRL1);
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- break;
- case 2:
- default:
- /* 2-bit gray */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- outl(inl(TX3912_VIDEO_CTRL1) |
- TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
- TX3912_VIDEO_CTRL1);
- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- break;
- }
-
- /* Enable the video clock */
- outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
- TX3912_CLK_CTRL);
-
- /* Unfreeze video logic and enable DF toggle */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME |
- TX3912_VIDEO_CTRL1_DFMODE)
- , TX3912_VIDEO_CTRL1);
- udelay(200);
-
- /* Enable the video logic */
- outl(inl(TX3912_VIDEO_CTRL1) |
- (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
- TX3912_VIDEO_CTRL1);
-
- info->fix.line_length = get_line_length(var->xres_virtual,
- var->bits_per_pixel);
-}
-
-/*
- * Set a single color register
- */
-static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
- u_int blue, u_int transp,
- struct fb_info *info)
-{
- if (regno > 255)
- return 1;
-
- if (regno < 16)
- ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8)
- | ((green & 0xe000) >> 11)
- | ((blue & 0xc000) >> 14);
- return 0;
-}
-
-int __init tx3912fb_setup(char *options);
-
-/*
- * Initialization of the framebuffer
- */
-int __init tx3912fb_init(void)
-{
- u_long tx3912fb_paddr = 0;
- int size = (info->var.bits_per_pixel == 8) ? 256 : 16;
- char *option = NULL;
-
- if (fb_get_options("tx3912fb", &option))
- return -ENODEV;
- tx3912fb_setup(option);
-
- /* Disable the video logic */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
- TX3912_VIDEO_CTRL1);
- udelay(200);
-
- /* Set start address for DMA transfer */
- outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
-
- /* Set end address for DMA transfer */
- outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
-
- /* Set the pixel depth */
- switch (tx3912fb_var.bits_per_pixel) {
- case 1:
- /* Monochrome */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- tx3912fb_fix.visual = FB_VISUAL_MONO10;
- break;
- case 4:
- /* 4-bit gray */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- outl(inl(TX3912_VIDEO_CTRL1) |
- TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
- TX3912_VIDEO_CTRL1);
- tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
- tx3912fb_fix.grayscale = 1;
- break;
- case 8:
- /* 8-bit color */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- outl(inl(TX3912_VIDEO_CTRL1) |
- TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
- TX3912_VIDEO_CTRL1);
- tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
- break;
- case 2:
- default:
- /* 2-bit gray */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
- outl(inl(TX3912_VIDEO_CTRL1) |
- TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
- TX3912_VIDEO_CTRL1);
- tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
- tx3912fb_fix.grayscale = 1;
- break;
- }
-
- /* Enable the video clock */
- outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
- TX3912_CLK_CTRL);
-
- /* Unfreeze video logic and enable DF toggle */
- outl(inl(TX3912_VIDEO_CTRL1) &
- ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
- TX3912_VIDEO_CTRL1);
- udelay(200);
-
- /* Clear the framebuffer */
- memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len);
- udelay(200);
-
- /* Enable the video logic */
- outl(inl(TX3912_VIDEO_CTRL1) |
- (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
- TX3912_VIDEO_CTRL1);
-
- /*
- * Memory limit
- */
- tx3912fb_fix.line_length =
- get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel);
- if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len)
- return -ENOMEM;
-
- fb_info.fbops = &tx3912fb_ops;
- fb_info.var = tx3912fb_var;
- fb_info.fix = tx3912fb_fix;
- fb_info.pseudo_palette = cfb8;
- fb_info.flags = FBINFO_DEFAULT;
-
- /* Clear the framebuffer */
- memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len);
- udelay(200);
-
- fb_alloc_cmap(&info->cmap, size, 0);
-
- if (register_framebuffer(&fb_info) < 0)
- return -1;
-
- printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
- fb_info.node, (u_int) (fb_info.fix.smem_len >> 10));
- return 0;
-}
-
-int __init tx3912fb_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep(&options, ","))) {
- if (!strncmp(options, "bpp:", 4))
- tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0);
- }
- return 0;
-}
-
-module_init(tx3912fb_init);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index ad66f070acb8..7b0cef9ca8f9 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -356,10 +356,9 @@ int __init valkyriefb_init(void)
}
#endif /* ppc (!CONFIG_MAC) */
- p = kmalloc(sizeof(*p), GFP_ATOMIC);
+ p = kzalloc(sizeof(*p), GFP_ATOMIC);
if (p == 0)
return -ENOMEM;
- memset(p, 0, sizeof(*p));
/* Map in frame buffer and registers */
if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) {
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 1d29a89a86b4..6ef99b2d13ca 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -6,9 +6,12 @@
* Author: MontaVista Software, Inc.
* source@mvista.com
*
- * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * 2002-2007 (c) MontaVista Software, Inc.
+ * 2007 (c) Secret Lab Technologies, Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
/*
@@ -18,6 +21,7 @@
* Geert Uytterhoeven.
*/
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
@@ -28,9 +32,12 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
-
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
#include <asm/io.h>
-#include <syslib/virtex_devices.h>
+#include <linux/xilinxfb.h>
#define DRIVER_NAME "xilinxfb"
#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver"
@@ -63,12 +70,6 @@
*/
#define BYTES_PER_PIXEL 4
#define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8)
-#define XRES 640
-#define YRES 480
-#define XRES_VIRTUAL 1024
-#define YRES_VIRTUAL YRES
-#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL)
-#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH)
#define RED_SHIFT 16
#define GREEN_SHIFT 8
@@ -77,23 +78,26 @@
#define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */
/*
+ * Default xilinxfb configuration
+ */
+static struct xilinxfb_platform_data xilinx_fb_default_pdata = {
+ .xres = 640,
+ .yres = 480,
+ .xvirt = 1024,
+ .yvirt = 480;
+};
+
+/*
* Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
*/
-static struct fb_fix_screeninfo xilinx_fb_fix __initdata = {
+static struct fb_fix_screeninfo xilinx_fb_fix = {
.id = "Xilinx",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
- .smem_len = FB_SIZE,
- .line_length = LINE_LENGTH,
.accel = FB_ACCEL_NONE
};
-static struct fb_var_screeninfo xilinx_fb_var __initdata = {
- .xres = XRES,
- .yres = YRES,
- .xres_virtual = XRES_VIRTUAL,
- .yres_virtual = YRES_VIRTUAL,
-
+static struct fb_var_screeninfo xilinx_fb_var = {
.bits_per_pixel = BITS_PER_PIXEL,
.red = { RED_SHIFT, 8, 0 },
@@ -111,8 +115,9 @@ struct xilinxfb_drvdata {
u32 regs_phys; /* phys. address of the control registers */
u32 __iomem *regs; /* virt. address of the control registers */
- unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */
+ void *fb_virt; /* virt. address of the frame buffer */
dma_addr_t fb_phys; /* phys. address of the frame buffer */
+ int fb_alloced; /* Flag, was the fb memory alloced? */
u32 reg_ctrl_default;
@@ -195,135 +200,136 @@ static struct fb_ops xilinxfb_ops =
.fb_imageblit = cfb_imageblit,
};
-/* === The device driver === */
+/* ---------------------------------------------------------------------
+ * Bus independent setup/teardown
+ */
-static int
-xilinxfb_drv_probe(struct device *dev)
+static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
+ struct xilinxfb_platform_data *pdata)
{
- struct platform_device *pdev;
- struct xilinxfb_platform_data *pdata;
struct xilinxfb_drvdata *drvdata;
- struct resource *regs_res;
- int retval;
-
- if (!dev)
- return -EINVAL;
-
- pdev = to_platform_device(dev);
- pdata = pdev->dev.platform_data;
-
- if (pdata == NULL) {
- printk(KERN_ERR "Couldn't find platform data.\n");
- return -EFAULT;
- }
+ int rc;
+ int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
+ /* Allocate the driver data region */
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
- printk(KERN_ERR "Couldn't allocate device private record\n");
+ dev_err(dev, "Couldn't allocate device private record\n");
return -ENOMEM;
}
dev_set_drvdata(dev, drvdata);
/* Map the control registers in */
- regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) {
- printk(KERN_ERR "Couldn't get registers resource\n");
- retval = -EFAULT;
- goto failed1;
+ if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
+ dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+ physaddr);
+ rc = -ENODEV;
+ goto err_region;
}
-
- if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
- printk(KERN_ERR
- "Couldn't lock memory region at 0x%08X\n",
- regs_res->start);
- retval = -EBUSY;
- goto failed1;
+ drvdata->regs_phys = physaddr;
+ drvdata->regs = ioremap(physaddr, 8);
+ if (!drvdata->regs) {
+ dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+ physaddr);
+ rc = -ENODEV;
+ goto err_map;
}
- drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
- drvdata->regs_phys = regs_res->start;
/* Allocate the framebuffer memory */
- drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE),
- &drvdata->fb_phys, GFP_KERNEL);
+ if (pdata->fb_phys) {
+ drvdata->fb_phys = pdata->fb_phys;
+ drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
+ } else {
+ drvdata->fb_alloced = 1;
+ drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
+ &drvdata->fb_phys, GFP_KERNEL);
+ }
+
if (!drvdata->fb_virt) {
- printk(KERN_ERR "Could not allocate frame buffer memory\n");
- retval = -ENOMEM;
- goto failed2;
+ dev_err(dev, "Could not allocate frame buffer memory\n");
+ rc = -ENOMEM;
+ goto err_fbmem;
}
/* Clear (turn to black) the framebuffer */
- memset_io((void *) drvdata->fb_virt, 0, FB_SIZE);
+ memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
/* Tell the hardware where the frame buffer is */
xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
/* Turn on the display */
- if (pdata->rotate_screen) {
- drvdata->reg_ctrl_default = REG_CTRL_ENABLE | REG_CTRL_ROTATE;
- } else {
- drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
- }
+ drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
+ if (pdata->rotate_screen)
+ drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
/* Fill struct fb_info */
drvdata->info.device = dev;
- drvdata->info.screen_base = drvdata->fb_virt;
+ drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
drvdata->info.fbops = &xilinxfb_ops;
drvdata->info.fix = xilinx_fb_fix;
drvdata->info.fix.smem_start = drvdata->fb_phys;
- drvdata->info.pseudo_palette = drvdata->pseudo_palette;
-
- if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) {
- printk(KERN_ERR "Fail to allocate colormap (%d entries)\n",
- PALETTE_ENTRIES_NO);
- retval = -EFAULT;
- goto failed3;
- }
+ drvdata->info.fix.smem_len = fbsize;
+ drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
+ drvdata->info.pseudo_palette = drvdata->pseudo_palette;
drvdata->info.flags = FBINFO_DEFAULT;
- xilinx_fb_var.height = pdata->screen_height_mm;
- xilinx_fb_var.width = pdata->screen_width_mm;
drvdata->info.var = xilinx_fb_var;
+ drvdata->info.var.height = pdata->screen_height_mm;
+ drvdata->info.var.width = pdata->screen_width_mm;
+ drvdata->info.var.xres = pdata->xres;
+ drvdata->info.var.yres = pdata->yres;
+ drvdata->info.var.xres_virtual = pdata->xvirt;
+ drvdata->info.var.yres_virtual = pdata->yvirt;
+
+ /* Allocate a colour map */
+ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
+ if (rc) {
+ dev_err(dev, "Fail to allocate colormap (%d entries)\n",
+ PALETTE_ENTRIES_NO);
+ goto err_cmap;
+ }
/* Register new frame buffer */
- if (register_framebuffer(&drvdata->info) < 0) {
- printk(KERN_ERR "Could not register frame buffer\n");
- retval = -EINVAL;
- goto failed4;
+ rc = register_framebuffer(&drvdata->info);
+ if (rc) {
+ dev_err(dev, "Could not register frame buffer\n");
+ goto err_regfb;
}
+ /* Put a banner in the log (for DEBUG) */
+ dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs);
+ dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n",
+ (void*)drvdata->fb_phys, drvdata->fb_virt, fbsize);
+
return 0; /* success */
-failed4:
+err_regfb:
fb_dealloc_cmap(&drvdata->info.cmap);
-failed3:
- dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
- drvdata->fb_phys);
-
+err_cmap:
+ if (drvdata->fb_alloced)
+ dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
+ drvdata->fb_phys);
/* Turn off the display */
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+
+err_fbmem:
iounmap(drvdata->regs);
-failed2:
- release_mem_region(regs_res->start, 8);
+err_map:
+ release_mem_region(physaddr, 8);
-failed1:
+err_region:
kfree(drvdata);
dev_set_drvdata(dev, NULL);
- return retval;
+ return rc;
}
-static int
-xilinxfb_drv_remove(struct device *dev)
+static int xilinxfb_release(struct device *dev)
{
- struct xilinxfb_drvdata *drvdata;
-
- if (!dev)
- return -ENODEV;
-
- drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev);
+ struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
@@ -333,8 +339,9 @@ xilinxfb_drv_remove(struct device *dev)
fb_dealloc_cmap(&drvdata->info.cmap);
- dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
- drvdata->fb_phys);
+ if (drvdata->fb_alloced)
+ dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
+ drvdata->fb_virt, drvdata->fb_phys);
/* Turn off the display */
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
@@ -348,29 +355,168 @@ xilinxfb_drv_remove(struct device *dev)
return 0;
}
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
-static struct device_driver xilinxfb_driver = {
- .name = DRIVER_NAME,
- .bus = &platform_bus_type,
+static int
+xilinxfb_platform_probe(struct platform_device *pdev)
+{
+ struct xilinxfb_platform_data *pdata;
+ struct resource *res;
- .probe = xilinxfb_drv_probe,
- .remove = xilinxfb_drv_remove
+ /* Find the registers address */
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Couldn't get registers resource\n");
+ return -ENODEV;
+ }
+
+ /* If a pdata structure is provided, then extract the parameters */
+ pdata = &xilinx_fb_default_pdata;
+ if (pdev->dev.platform_data) {
+ pdata = pdev->dev.platform_data;
+ if (!pdata->xres)
+ pdata->xres = xilinx_fb_default_pdata.xres;
+ if (!pdata->yres)
+ pdata->yres = xilinx_fb_default_pdata.yres;
+ if (!pdata->xvirt)
+ pdata->xvirt = xilinx_fb_default_pdata.xvirt;
+ if (!pdata->yvirt)
+ pdata->yvirt = xilinx_fb_default_pdata.yvirt;
+ }
+
+ return xilinxfb_assign(&pdev->dev, res->start, pdata);
+}
+
+static int
+xilinxfb_platform_remove(struct platform_device *pdev)
+{
+ return xilinxfb_release(&pdev->dev);
+}
+
+
+static struct platform_driver xilinxfb_platform_driver = {
+ .probe = xilinxfb_platform_probe,
+ .remove = xilinxfb_platform_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus binding
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ const u32 *prop;
+ struct xilinxfb_platform_data pdata;
+ int size, rc;
+
+ /* Copy with the default pdata (not a ptr reference!) */
+ pdata = xilinx_fb_default_pdata;
+
+ dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match);
+
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+
+ prop = of_get_property(op->node, "phys-size", &size);
+ if ((prop) && (size >= sizeof(u32)*2)) {
+ pdata.screen_width_mm = prop[0];
+ pdata.screen_height_mm = prop[1];
+ }
+
+ prop = of_get_property(op->node, "resolution", &size);
+ if ((prop) && (size >= sizeof(u32)*2)) {
+ pdata.xres = prop[0];
+ pdata.yres = prop[1];
+ }
+
+ prop = of_get_property(op->node, "virtual-resolution", &size);
+ if ((prop) && (size >= sizeof(u32)*2)) {
+ pdata.xvirt = prop[0];
+ pdata.yvirt = prop[1];
+ }
+
+ if (of_find_property(op->node, "rotate-display", NULL))
+ pdata.rotate_screen = 1;
+
+ return xilinxfb_assign(&op->dev, res.start, &pdata);
+}
+
+static int __devexit xilinxfb_of_remove(struct of_device *op)
+{
+ return xilinxfb_release(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit xilinxfb_of_match[] = {
+ { .compatible = "xilinx,ml300-fb", },
+ {},
};
+MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
+
+static struct of_platform_driver xilinxfb_of_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = xilinxfb_of_match,
+ .probe = xilinxfb_of_probe,
+ .remove = __devexit_p(xilinxfb_of_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init xilinxfb_of_register(void)
+{
+ pr_debug("xilinxfb: calling of_register_platform_driver()\n");
+ return of_register_platform_driver(&xilinxfb_of_driver);
+}
+
+static inline void __exit xilinxfb_of_unregister(void)
+{
+ of_unregister_platform_driver(&xilinxfb_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init xilinxfb_of_register(void) { return 0; }
+static inline void __exit xilinxfb_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown
+ */
static int __init
xilinxfb_init(void)
{
- /*
- * No kernel boot options used,
- * so we just need to register the driver
- */
- return driver_register(&xilinxfb_driver);
+ int rc;
+ rc = xilinxfb_of_register();
+ if (rc)
+ return rc;
+
+ rc = platform_driver_register(&xilinxfb_platform_driver);
+ if (rc)
+ xilinxfb_of_unregister();
+
+ return rc;
}
static void __exit
xilinxfb_cleanup(void)
{
- driver_unregister(&xilinxfb_driver);
+ platform_driver_unregister(&xilinxfb_platform_driver);
+ xilinxfb_of_unregister();
}
module_init(xilinxfb_init);
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 763bc73e5070..4b696641ce33 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -85,7 +85,7 @@ static struct {
};
struct ds1wm_data {
- void *map;
+ void __iomem *map;
int bus_shift; /* # of shifts to calc register offsets */
struct platform_device *pdev;
struct ds1wm_platform_data *pdata;
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index 6f9d880ab2e9..d356da5709fc 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -164,7 +164,7 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
return -ENODEV;
- dev = kmalloc(sizeof(struct matrox_device) +
+ dev = kzalloc(sizeof(struct matrox_device) +
sizeof(struct w1_bus_master), GFP_KERNEL);
if (!dev) {
dev_err(&pdev->dev,
@@ -173,7 +173,6 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
return -ENOMEM;
}
- memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
dev->bus_master = (struct w1_bus_master *)(dev + 1);
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index cab56005dd49..858c16a544c2 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -266,10 +266,9 @@ static int w1_f23_add_slave(struct w1_slave *sl)
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
struct w1_f23_data *data;
- data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+ data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- memset(data, 0, sizeof(struct w1_f23_data));
sl->family_data = data;
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index c6332108f1c5..070217322c9f 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -197,7 +197,7 @@ static struct w1_family w1_default_family = {
.fops = &w1_default_fops,
};
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
static struct bus_type w1_bus_type = {
.name = "w1",
@@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master)
}
#ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct w1_master *md = NULL;
struct w1_slave *sl = NULL;
char *event_owner, *name;
- int err, cur_index=0, cur_len=0;
+ int err;
if (dev->driver == &w1_master_driver) {
md = container_of(dev, struct w1_master, dev);
@@ -423,22 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp,
if (dev->driver != &w1_slave_driver || !sl)
return 0;
- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
- &cur_len, "W1_FID=%02X", sl->reg_num.family);
+ err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
if (err)
return err;
- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
- &cur_len, "W1_SLAVE_ID=%024LX",
- (unsigned long long)sl->reg_num.id);
+ err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+ (unsigned long long)sl->reg_num.id);
if (err)
return err;
return 0;
};
#else
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return 0;
}
@@ -520,7 +516,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
int err;
struct w1_netlink_msg msg;
- sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
+ sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
if (!sl) {
dev_err(&dev->dev,
"%s: failed to allocate new slave device.\n",
@@ -528,7 +524,6 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
return -ENOMEM;
}
- memset(sl, 0, sizeof(*sl));
sl->owner = THIS_MODULE;
sl->master = dev;
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 258defdb2efd..6840dfebe4d4 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -41,7 +41,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
/*
* We are in process context(kernel thread), so can sleep.
*/
- dev = kmalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
if (!dev) {
printk(KERN_ERR
"Failed to allocate %zd bytes for new w1 device.\n",
@@ -49,7 +49,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
return NULL;
}
- memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
dev->bus_master = (struct w1_bus_master *)(dev + 1);
@@ -171,22 +170,24 @@ void __w1_remove_master_device(struct w1_master *dev)
void w1_remove_master_device(struct w1_bus_master *bm)
{
- struct w1_master *dev = NULL;
+ struct w1_master *dev, *found = NULL;
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
if (!dev->initialized)
continue;
- if (dev->bus_master->data == bm->data)
+ if (dev->bus_master->data == bm->data) {
+ found = dev;
break;
+ }
}
- if (!dev) {
+ if (!found) {
printk(KERN_ERR "Device doesn't exist.\n");
return;
}
- __w1_remove_master_device(dev);
+ __w1_remove_master_device(found);
}
EXPORT_SYMBOL(w1_add_master_device);
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
new file mode 100644
index 000000000000..56592f0d6cef
--- /dev/null
+++ b/drivers/xen/Makefile
@@ -0,0 +1,2 @@
+obj-y += grant-table.o
+obj-y += xenbus/
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
new file mode 100644
index 000000000000..ea94dbabf9a9
--- /dev/null
+++ b/drivers/xen/grant-table.c
@@ -0,0 +1,582 @@
+/******************************************************************************
+ * grant_table.c
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A Fraser
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+#include <asm/sync_bitops.h>
+
+
+/* External tools reserve first few grant table entries. */
+#define NR_RESERVED_ENTRIES 8
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
+static int gnttab_free_count;
+static grant_ref_t gnttab_free_head;
+static DEFINE_SPINLOCK(gnttab_list_lock);
+
+static struct grant_entry *shared;
+
+static struct gnttab_free_callback *gnttab_free_callback_list;
+
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+
+static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
+{
+ return &gnttab_list[(entry) / RPP][(entry) % RPP];
+}
+/* This can be used as an l-value */
+#define gnttab_entry(entry) (*__gnttab_entry(entry))
+
+static int get_free_entries(unsigned count)
+{
+ unsigned long flags;
+ int ref, rc;
+ grant_ref_t head;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+
+ if ((gnttab_free_count < count) &&
+ ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+ return rc;
+ }
+
+ ref = head = gnttab_free_head;
+ gnttab_free_count -= count;
+ while (count-- > 1)
+ head = gnttab_entry(head);
+ gnttab_free_head = gnttab_entry(head);
+ gnttab_entry(head) = GNTTAB_LIST_END;
+
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
+ return ref;
+}
+
+static void do_free_callbacks(void)
+{
+ struct gnttab_free_callback *callback, *next;
+
+ callback = gnttab_free_callback_list;
+ gnttab_free_callback_list = NULL;
+
+ while (callback != NULL) {
+ next = callback->next;
+ if (gnttab_free_count >= callback->count) {
+ callback->next = NULL;
+ callback->fn(callback->arg);
+ } else {
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ }
+ callback = next;
+ }
+}
+
+static inline void check_free_callbacks(void)
+{
+ if (unlikely(gnttab_free_callback_list))
+ do_free_callbacks();
+}
+
+static void put_free_entry(grant_ref_t ref)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ gnttab_entry(ref) = gnttab_free_head;
+ gnttab_free_head = ref;
+ gnttab_free_count++;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+static void update_grant_entry(grant_ref_t ref, domid_t domid,
+ unsigned long frame, unsigned flags)
+{
+ /*
+ * Introducing a valid entry into the grant table:
+ * 1. Write ent->domid.
+ * 2. Write ent->frame:
+ * GTF_permit_access: Frame to which access is permitted.
+ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ * frame, or zero if none.
+ * 3. Write memory barrier (WMB).
+ * 4. Write ent->flags, inc. valid type.
+ */
+ shared[ref].frame = frame;
+ shared[ref].domid = domid;
+ wmb();
+ shared[ref].flags = flags;
+}
+
+/*
+ * Public grant-issuing interface functions
+ */
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly)
+{
+ update_grant_entry(ref, domid, frame,
+ GTF_permit_access | (readonly ? GTF_readonly : 0));
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+ int readonly)
+{
+ int ref;
+
+ ref = get_free_entries(1);
+ if (unlikely(ref < 0))
+ return -ENOSPC;
+
+ gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
+
+ return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+
+int gnttab_query_foreign_access(grant_ref_t ref)
+{
+ u16 nflags;
+
+ nflags = shared[ref].flags;
+
+ return (nflags & (GTF_reading|GTF_writing));
+}
+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
+{
+ u16 flags, nflags;
+
+ nflags = shared[ref].flags;
+ do {
+ flags = nflags;
+ if (flags & (GTF_reading|GTF_writing)) {
+ printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+ return 0;
+ }
+ } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
+
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+ unsigned long page)
+{
+ if (gnttab_end_foreign_access_ref(ref, readonly)) {
+ put_free_entry(ref);
+ if (page != 0)
+ free_page(page);
+ } else {
+ /* XXX This needs to be fixed so that the ref and page are
+ placed on a list to be freed up later. */
+ printk(KERN_WARNING
+ "WARNING: leaking g.e. and page still in use!\n");
+ }
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
+{
+ int ref;
+
+ ref = get_free_entries(1);
+ if (unlikely(ref < 0))
+ return -ENOSPC;
+ gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
+
+ return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+ unsigned long pfn)
+{
+ update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
+{
+ unsigned long frame;
+ u16 flags;
+
+ /*
+ * If a transfer is not even yet started, try to reclaim the grant
+ * reference and return failure (== 0).
+ */
+ while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
+ if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
+ return 0;
+ cpu_relax();
+ }
+
+ /* If a transfer is in progress then wait until it is completed. */
+ while (!(flags & GTF_transfer_completed)) {
+ flags = shared[ref].flags;
+ cpu_relax();
+ }
+
+ rmb(); /* Read the frame number /after/ reading completion status. */
+ frame = shared[ref].frame;
+ BUG_ON(frame == 0);
+
+ return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
+{
+ unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
+ put_free_entry(ref);
+ return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
+
+void gnttab_free_grant_reference(grant_ref_t ref)
+{
+ put_free_entry(ref);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
+
+void gnttab_free_grant_references(grant_ref_t head)
+{
+ grant_ref_t ref;
+ unsigned long flags;
+ int count = 1;
+ if (head == GNTTAB_LIST_END)
+ return;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ ref = head;
+ while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+ ref = gnttab_entry(ref);
+ count++;
+ }
+ gnttab_entry(ref) = gnttab_free_head;
+ gnttab_free_head = head;
+ gnttab_free_count += count;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
+
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+ int h = get_free_entries(count);
+
+ if (h < 0)
+ return -ENOSPC;
+
+ *head = h;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
+
+int gnttab_empty_grant_references(const grant_ref_t *private_head)
+{
+ return (*private_head == GNTTAB_LIST_END);
+}
+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
+
+int gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+ grant_ref_t g = *private_head;
+ if (unlikely(g == GNTTAB_LIST_END))
+ return -ENOSPC;
+ *private_head = gnttab_entry(g);
+ return g;
+}
+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+ grant_ref_t release)
+{
+ gnttab_entry(release) = *private_head;
+ *private_head = release;
+}
+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+ void (*fn)(void *), void *arg, u16 count)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ if (callback->next)
+ goto out;
+ callback->fn = fn;
+ callback->arg = arg;
+ callback->count = count;
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ check_free_callbacks();
+out:
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
+
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+ struct gnttab_free_callback **pcb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+ if (*pcb == callback) {
+ *pcb = callback->next;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
+
+static int grow_gnttab_list(unsigned int more_frames)
+{
+ unsigned int new_nr_grant_frames, extra_entries, i;
+
+ new_nr_grant_frames = nr_grant_frames + more_frames;
+ extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
+
+ for (i = nr_grant_frames; i < new_nr_grant_frames; i++) {
+ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+ if (!gnttab_list[i])
+ goto grow_nomem;
+ }
+
+
+ for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+ gnttab_entry(i) = i + 1;
+
+ gnttab_entry(i) = gnttab_free_head;
+ gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ gnttab_free_count += extra_entries;
+
+ nr_grant_frames = new_nr_grant_frames;
+
+ check_free_callbacks();
+
+ return 0;
+
+grow_nomem:
+ for ( ; i >= nr_grant_frames; i--)
+ free_page((unsigned long) gnttab_list[i]);
+ return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+ struct gnttab_query_size query;
+ int rc;
+
+ query.dom = DOMID_SELF;
+
+ rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+ if ((rc < 0) || (query.status != GNTST_okay))
+ return 4; /* Legacy max supported number of frames */
+
+ return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+ unsigned int xen_max = __max_nr_grant_frames();
+
+ if (xen_max > boot_max_nr_grant_frames)
+ return boot_max_nr_grant_frames;
+ return xen_max;
+}
+
+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
+ unsigned long addr, void *data)
+{
+ unsigned long **frames = (unsigned long **)data;
+
+ set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
+ (*frames)++;
+ return 0;
+}
+
+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
+ unsigned long addr, void *data)
+{
+
+ set_pte_at(&init_mm, addr, pte, __pte(0));
+ return 0;
+}
+
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
+{
+ struct gnttab_setup_table setup;
+ unsigned long *frames;
+ unsigned int nr_gframes = end_idx + 1;
+ int rc;
+
+ frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+ if (!frames)
+ return -ENOMEM;
+
+ setup.dom = DOMID_SELF;
+ setup.nr_frames = nr_gframes;
+ setup.frame_list = frames;
+
+ rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+ if (rc == -ENOSYS) {
+ kfree(frames);
+ return -ENOSYS;
+ }
+
+ BUG_ON(rc || setup.status);
+
+ if (shared == NULL) {
+ struct vm_struct *area;
+ area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
+ BUG_ON(area == NULL);
+ shared = area->addr;
+ }
+ rc = apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_gframes,
+ map_pte_fn, &frames);
+ BUG_ON(rc);
+ frames -= nr_gframes; /* adjust after map_pte_fn() */
+
+ kfree(frames);
+
+ return 0;
+}
+
+static int gnttab_resume(void)
+{
+ if (max_nr_grant_frames() < nr_grant_frames)
+ return -ENOSYS;
+ return gnttab_map(0, nr_grant_frames - 1);
+}
+
+static int gnttab_suspend(void)
+{
+ apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_grant_frames,
+ unmap_pte_fn, NULL);
+
+ return 0;
+}
+
+static int gnttab_expand(unsigned int req_entries)
+{
+ int rc;
+ unsigned int cur, extra;
+
+ cur = nr_grant_frames;
+ extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+ GREFS_PER_GRANT_FRAME);
+ if (cur + extra > max_nr_grant_frames())
+ return -ENOSPC;
+
+ rc = gnttab_map(cur, cur + extra - 1);
+ if (rc == 0)
+ rc = grow_gnttab_list(extra);
+
+ return rc;
+}
+
+static int __devinit gnttab_init(void)
+{
+ int i;
+ unsigned int max_nr_glist_frames;
+ unsigned int nr_init_grefs;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ nr_grant_frames = 1;
+ boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+ /* Determine the maximum number of frames required for the
+ * grant reference free list on the current hypervisor.
+ */
+ max_nr_glist_frames = (boot_max_nr_grant_frames *
+ GREFS_PER_GRANT_FRAME /
+ (PAGE_SIZE / sizeof(grant_ref_t)));
+
+ gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+ GFP_KERNEL);
+ if (gnttab_list == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_grant_frames; i++) {
+ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+ if (gnttab_list[i] == NULL)
+ goto ini_nomem;
+ }
+
+ if (gnttab_resume() < 0)
+ return -ENODEV;
+
+ nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+ for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+ gnttab_entry(i) = i + 1;
+
+ gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+ gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
+ gnttab_free_head = NR_RESERVED_ENTRIES;
+
+ printk("Grant table initialized\n");
+ return 0;
+
+ ini_nomem:
+ for (i--; i >= 0; i--)
+ free_page((unsigned long)gnttab_list[i]);
+ kfree(gnttab_list);
+ return -ENOMEM;
+}
+
+core_initcall(gnttab_init);
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
new file mode 100644
index 000000000000..5571f5b84223
--- /dev/null
+++ b/drivers/xen/xenbus/Makefile
@@ -0,0 +1,7 @@
+obj-y += xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
new file mode 100644
index 000000000000..9fd2f70ab46d
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -0,0 +1,569 @@
+/******************************************************************************
+ * Client-facing interface for the Xenbus driver. In other words, the
+ * interface between the Xenbus and the device-specific code, be it the
+ * frontend or the backend of that driver.
+ *
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+ static const char *const name[] = {
+ [ XenbusStateUnknown ] = "Unknown",
+ [ XenbusStateInitialising ] = "Initialising",
+ [ XenbusStateInitWait ] = "InitWait",
+ [ XenbusStateInitialised ] = "Initialised",
+ [ XenbusStateConnected ] = "Connected",
+ [ XenbusStateClosing ] = "Closing",
+ [ XenbusStateClosed ] = "Closed",
+ };
+ return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+EXPORT_SYMBOL_GPL(xenbus_strstate);
+
+/**
+ * xenbus_watch_path - register a watch
+ * @dev: xenbus device
+ * @path: path to watch
+ * @watch: watch to register
+ * @callback: callback to register
+ *
+ * Register a @watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given @callback function as the callback. Return 0 on
+ * success, or -errno on error. On success, the given @path will be saved as
+ * @watch->node, and remains the caller's to free. On error, @watch->node will
+ * be NULL, the device will switch to %XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int))
+{
+ int err;
+
+ watch->node = path;
+ watch->callback = callback;
+
+ err = register_xenbus_watch(watch);
+
+ if (err) {
+ watch->node = NULL;
+ watch->callback = NULL;
+ xenbus_dev_fatal(dev, err, "adding watch on %s", path);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_path);
+
+
+/**
+ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
+ * @dev: xenbus device
+ * @watch: watch to register
+ * @callback: callback to register
+ * @pathfmt: format of path to watch
+ *
+ * Register a watch on the given @path, using the given xenbus_watch
+ * structure for storage, and the given @callback function as the callback.
+ * Return 0 on success, or -errno on error. On success, the watched path
+ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
+ * kfree(). On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to %XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_pathfmt(struct xenbus_device *dev,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int),
+ const char *pathfmt, ...)
+{
+ int err;
+ va_list ap;
+ char *path;
+
+ va_start(ap, pathfmt);
+ path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+ va_end(ap);
+
+ if (!path) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
+ return -ENOMEM;
+ }
+ err = xenbus_watch_path(dev, path, watch, callback);
+
+ if (err)
+ kfree(path);
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @xbt: transaction handle
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error. On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+ /* We check whether the state is currently set to the given value, and
+ if not, then the state is set. We don't want to unconditionally
+ write the given state, because we don't want to fire watches
+ unnecessarily. Furthermore, if the node has gone, we don't write
+ to it, as the device will be tearing down, and we don't want to
+ resurrect that directory.
+
+ Note that, because of this cached value of our state, this function
+ will not work inside a Xenstore transaction (something it was
+ trying to in the past) because dev->state would not get reset if
+ the transaction was aborted.
+
+ */
+
+ int current_state;
+ int err;
+
+ if (state == dev->state)
+ return 0;
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
+ &current_state);
+ if (err != 1)
+ return 0;
+
+ err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+ if (err) {
+ if (state != XenbusStateClosing) /* Avoid looping */
+ xenbus_dev_fatal(dev, err, "writing new state");
+ return err;
+ }
+
+ dev->state = state;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_switch_state);
+
+int xenbus_frontend_closed(struct xenbus_device *dev)
+{
+ xenbus_switch_state(dev, XenbusStateClosed);
+ complete(&dev->down);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
+
+/**
+ * Return the path to the error node for the given device, or NULL on failure.
+ * If the value returned is non-NULL, then it is the caller's to kfree.
+ */
+static char *error_path(struct xenbus_device *dev)
+{
+ return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+}
+
+
+static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
+ const char *fmt, va_list ap)
+{
+ int ret;
+ unsigned int len;
+ char *printf_buffer = NULL;
+ char *path_buffer = NULL;
+
+#define PRINTF_BUFFER_SIZE 4096
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ if (printf_buffer == NULL)
+ goto fail;
+
+ len = sprintf(printf_buffer, "%i ", -err);
+ ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+
+ BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+
+ dev_err(&dev->dev, "%s\n", printf_buffer);
+
+ path_buffer = error_path(dev);
+
+ if (path_buffer == NULL) {
+ dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+ dev->nodename, printf_buffer);
+ goto fail;
+ }
+
+ if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+ dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+ dev->nodename, printf_buffer);
+ goto fail;
+ }
+
+fail:
+ kfree(printf_buffer);
+ kfree(path_buffer);
+}
+
+
+/**
+ * xenbus_dev_error
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_error);
+
+/**
+ * xenbus_dev_fatal
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+
+ xenbus_switch_state(dev, XenbusStateClosing);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
+
+/**
+ * xenbus_grant_ring
+ * @dev: xenbus device
+ * @ring_mfn: mfn of ring to grant
+
+ * Grant access to the given @ring_mfn to the peer of the given device. Return
+ * 0 on success, or -errno on error. On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
+{
+ int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
+ if (err < 0)
+ xenbus_dev_fatal(dev, err, "granting access to ring page");
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_grant_ring);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port. Return 0 on success, or -errno on error. On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+{
+ struct evtchn_alloc_unbound alloc_unbound;
+ int err;
+
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = dev->otherend_id;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+ &alloc_unbound);
+ if (err)
+ xenbus_dev_fatal(dev, err, "allocating event channel");
+ else
+ *port = alloc_unbound.port;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
+
+
+/**
+ * Bind to an existing interdomain event channel in another domain. Returns 0
+ * on success and stores the local port in *port. On error, returns -errno,
+ * switches the device to XenbusStateClosing, and saves the error in XenStore.
+ */
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
+{
+ struct evtchn_bind_interdomain bind_interdomain;
+ int err;
+
+ bind_interdomain.remote_dom = dev->otherend_id;
+ bind_interdomain.remote_port = remote_port;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+ &bind_interdomain);
+ if (err)
+ xenbus_dev_fatal(dev, err,
+ "binding to event channel %d from domain %d",
+ remote_port, dev->otherend_id);
+ else
+ *port = bind_interdomain.local_port;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
+
+
+/**
+ * Free an existing event channel. Returns 0 on success or -errno on error.
+ */
+int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+{
+ struct evtchn_close close;
+ int err;
+
+ close.port = port;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+ if (err)
+ xenbus_dev_error(dev, err, "freeing event channel %d", port);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
+
+
+/**
+ * xenbus_map_ring_valloc
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @vaddr: pointer to address to be filled out by mapping
+ *
+ * Based on Rusty Russell's skeleton driver's map_page.
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
+ * page to that address, and sets *vaddr to that address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
+{
+ struct gnttab_map_grant_ref op = {
+ .flags = GNTMAP_host_map,
+ .ref = gnt_ref,
+ .dom = dev->otherend_id,
+ };
+ struct vm_struct *area;
+
+ *vaddr = NULL;
+
+ area = alloc_vm_area(PAGE_SIZE);
+ if (!area)
+ return -ENOMEM;
+
+ op.host_addr = (unsigned long)area->addr;
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay) {
+ free_vm_area(area);
+ xenbus_dev_fatal(dev, op.status,
+ "mapping in shared page %d from domain %d",
+ gnt_ref, dev->otherend_id);
+ return op.status;
+ }
+
+ /* Stuff the handle in an unused field */
+ area->phys_addr = (unsigned long)op.handle;
+
+ *vaddr = area->addr;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
+
+
+/**
+ * xenbus_map_ring
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @handle: pointer to grant handle to be filled
+ * @vaddr: address to be mapped to
+ *
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring does not allocate the virtual address space (you must do
+ * this yourself!). It only maps in the page to the specified address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+ grant_handle_t *handle, void *vaddr)
+{
+ struct gnttab_map_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ .flags = GNTMAP_host_map,
+ .ref = gnt_ref,
+ .dom = dev->otherend_id,
+ };
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay) {
+ xenbus_dev_fatal(dev, op.status,
+ "mapping in shared page %d from domain %d",
+ gnt_ref, dev->otherend_id);
+ } else
+ *handle = op.handle;
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring);
+
+
+/**
+ * xenbus_unmap_ring_vfree
+ * @dev: xenbus device
+ * @vaddr: addr to unmap
+ *
+ * Based on Rusty Russell's skeleton driver's unmap_page.
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
+ * xenbus_map_ring_valloc (it will free the virtual address space).
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
+{
+ struct vm_struct *area;
+ struct gnttab_unmap_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ };
+
+ /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
+ * method so that we don't have to muck with vmalloc internals here.
+ * We could force the user to hang on to their struct vm_struct from
+ * xenbus_map_ring_valloc, but these 6 lines considerably simplify
+ * this API.
+ */
+ read_lock(&vmlist_lock);
+ for (area = vmlist; area != NULL; area = area->next) {
+ if (area->addr == vaddr)
+ break;
+ }
+ read_unlock(&vmlist_lock);
+
+ if (!area) {
+ xenbus_dev_error(dev, -ENOENT,
+ "can't find mapped virtual address %p", vaddr);
+ return GNTST_bad_virt_addr;
+ }
+
+ op.handle = (grant_handle_t)area->phys_addr;
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status == GNTST_okay)
+ free_vm_area(area);
+ else
+ xenbus_dev_error(dev, op.status,
+ "unmapping page at handle %d error %d",
+ (int16_t)area->phys_addr, op.status);
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
+
+
+/**
+ * xenbus_unmap_ring
+ * @dev: xenbus device
+ * @handle: grant handle
+ * @vaddr: addr to unmap
+ *
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring(struct xenbus_device *dev,
+ grant_handle_t handle, void *vaddr)
+{
+ struct gnttab_unmap_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ .handle = handle,
+ };
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay)
+ xenbus_dev_error(dev, op.status,
+ "unmapping page at handle %d error %d",
+ handle, op.status);
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
+
+
+/**
+ * xenbus_read_driver_state
+ * @path: path for driver
+ *
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateUnknown if no state can be read.
+ */
+enum xenbus_state xenbus_read_driver_state(const char *path)
+{
+ enum xenbus_state result;
+ int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
+ if (err)
+ result = XenbusStateUnknown;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
new file mode 100644
index 000000000000..6efbe3f29ca5
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenbus_comms.c
+ *
+ * Low level code to talks to Xen Store: ringbuffer and event channel.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include "xenbus_comms.h"
+
+static int xenbus_irq;
+
+static DECLARE_WORK(probe_work, xenbus_probe);
+
+static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+
+static irqreturn_t wake_waiting(int irq, void *unused)
+{
+ if (unlikely(xenstored_ready == 0)) {
+ xenstored_ready = 1;
+ schedule_work(&probe_work);
+ }
+
+ wake_up(&xb_waitq);
+ return IRQ_HANDLED;
+}
+
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+ return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+ XENSTORE_RING_IDX prod,
+ char *buf, uint32_t *len)
+{
+ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+ if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+ *len = XENSTORE_RING_SIZE - (prod - cons);
+ return buf + MASK_XENSTORE_IDX(prod);
+}
+
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+ XENSTORE_RING_IDX prod,
+ const char *buf, uint32_t *len)
+{
+ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+ if ((prod - cons) < *len)
+ *len = prod - cons;
+ return buf + MASK_XENSTORE_IDX(cons);
+}
+
+/**
+ * xb_write - low level write
+ * @data: buffer to send
+ * @len: length of buffer
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int xb_write(const void *data, unsigned len)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ XENSTORE_RING_IDX cons, prod;
+ int rc;
+
+ while (len != 0) {
+ void *dst;
+ unsigned int avail;
+
+ rc = wait_event_interruptible(
+ xb_waitq,
+ (intf->req_prod - intf->req_cons) !=
+ XENSTORE_RING_SIZE);
+ if (rc < 0)
+ return rc;
+
+ /* Read indexes, then verify. */
+ cons = intf->req_cons;
+ prod = intf->req_prod;
+ if (!check_indexes(cons, prod)) {
+ intf->req_cons = intf->req_prod = 0;
+ return -EIO;
+ }
+
+ dst = get_output_chunk(cons, prod, intf->req, &avail);
+ if (avail == 0)
+ continue;
+ if (avail > len)
+ avail = len;
+
+ /* Must write data /after/ reading the consumer index. */
+ mb();
+
+ memcpy(dst, data, avail);
+ data += avail;
+ len -= avail;
+
+ /* Other side must not see new producer until data is there. */
+ wmb();
+ intf->req_prod += avail;
+
+ /* Implies mb(): other side will see the updated producer. */
+ notify_remote_via_evtchn(xen_store_evtchn);
+ }
+
+ return 0;
+}
+
+int xb_data_to_read(void)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+ return wait_event_interruptible(xb_waitq, xb_data_to_read());
+}
+
+int xb_read(void *data, unsigned len)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ XENSTORE_RING_IDX cons, prod;
+ int rc;
+
+ while (len != 0) {
+ unsigned int avail;
+ const char *src;
+
+ rc = xb_wait_for_data_to_read();
+ if (rc < 0)
+ return rc;
+
+ /* Read indexes, then verify. */
+ cons = intf->rsp_cons;
+ prod = intf->rsp_prod;
+ if (!check_indexes(cons, prod)) {
+ intf->rsp_cons = intf->rsp_prod = 0;
+ return -EIO;
+ }
+
+ src = get_input_chunk(cons, prod, intf->rsp, &avail);
+ if (avail == 0)
+ continue;
+ if (avail > len)
+ avail = len;
+
+ /* Must read data /after/ reading the producer index. */
+ rmb();
+
+ memcpy(data, src, avail);
+ data += avail;
+ len -= avail;
+
+ /* Other side must not see free space until we've copied out */
+ mb();
+ intf->rsp_cons += avail;
+
+ pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
+
+ /* Implies mb(): other side will see the updated consumer. */
+ notify_remote_via_evtchn(xen_store_evtchn);
+ }
+
+ return 0;
+}
+
+/**
+ * xb_init_comms - Set up interrupt handler off store event channel.
+ */
+int xb_init_comms(void)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ int err;
+
+ if (intf->req_prod != intf->req_cons)
+ printk(KERN_ERR "XENBUS request ring is not quiescent "
+ "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+ if (intf->rsp_prod != intf->rsp_cons) {
+ printk(KERN_WARNING "XENBUS response ring is not quiescent "
+ "(%08x:%08x): fixing up\n",
+ intf->rsp_cons, intf->rsp_prod);
+ intf->rsp_cons = intf->rsp_prod;
+ }
+
+ if (xenbus_irq)
+ unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+
+ err = bind_evtchn_to_irqhandler(
+ xen_store_evtchn, wake_waiting,
+ 0, "xenbus", &xb_waitq);
+ if (err <= 0) {
+ printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+ return err;
+ }
+
+ xenbus_irq = err;
+
+ return 0;
+}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
new file mode 100644
index 000000000000..c21db7513736
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.h
@@ -0,0 +1,46 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_COMMS_H
+#define _XENBUS_COMMS_H
+
+int xs_init(void);
+int xb_init_comms(void);
+
+/* Low level routines. */
+int xb_write(const void *data, unsigned len);
+int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
+int xb_wait_for_data_to_read(void);
+int xs_input_avail(void);
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
+#endif /* _XENBUS_COMMS_H */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
new file mode 100644
index 000000000000..0b769f7c4a48
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -0,0 +1,935 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define DPRINTK(fmt, args...) \
+ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
+ __func__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
+static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
+
+static void wait_for_devices(struct xenbus_driver *xendrv);
+
+static int xenbus_probe_frontend(const char *type, const char *name);
+
+static void xenbus_dev_shutdown(struct device *_dev);
+
+/* If something in array of ids matches this device, return it. */
+static const struct xenbus_device_id *
+match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
+{
+ for (; *arr->devicetype != '\0'; arr++) {
+ if (!strcmp(arr->devicetype, dev->devicetype))
+ return arr;
+ }
+ return NULL;
+}
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct xenbus_driver *drv = to_xenbus_driver(_drv);
+
+ if (!drv->ids)
+ return 0;
+
+ return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
+}
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+ nodename = strchr(nodename, '/');
+ if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
+ printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+ return -EINVAL;
+ }
+
+ strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
+ if (!strchr(bus_id, '/')) {
+ printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+ return -EINVAL;
+ }
+ *strchr(bus_id, '/') = '-';
+ return 0;
+}
+
+
+static void free_otherend_details(struct xenbus_device *dev)
+{
+ kfree(dev->otherend);
+ dev->otherend = NULL;
+}
+
+
+static void free_otherend_watch(struct xenbus_device *dev)
+{
+ if (dev->otherend_watch.node) {
+ unregister_xenbus_watch(&dev->otherend_watch);
+ kfree(dev->otherend_watch.node);
+ dev->otherend_watch.node = NULL;
+ }
+}
+
+
+int read_otherend_details(struct xenbus_device *xendev,
+ char *id_node, char *path_node)
+{
+ int err = xenbus_gather(XBT_NIL, xendev->nodename,
+ id_node, "%i", &xendev->otherend_id,
+ path_node, NULL, &xendev->otherend,
+ NULL);
+ if (err) {
+ xenbus_dev_fatal(xendev, err,
+ "reading other end details from %s",
+ xendev->nodename);
+ return err;
+ }
+ if (strlen(xendev->otherend) == 0 ||
+ !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
+ xenbus_dev_fatal(xendev, -ENOENT,
+ "unable to read other end from %s. "
+ "missing or inaccessible.",
+ xendev->nodename);
+ free_otherend_details(xendev);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+
+static int read_backend_details(struct xenbus_device *xendev)
+{
+ return read_otherend_details(xendev, "backend-id", "backend");
+}
+
+
+/* Bus type for frontend drivers. */
+static struct xen_bus_type xenbus_frontend = {
+ .root = "device",
+ .levels = 2, /* device/type/<id> */
+ .get_bus_id = frontend_bus_id,
+ .probe = xenbus_probe_frontend,
+ .bus = {
+ .name = "xen",
+ .match = xenbus_match,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
+ },
+};
+
+static void otherend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct xenbus_device *dev =
+ container_of(watch, struct xenbus_device, otherend_watch);
+ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+ enum xenbus_state state;
+
+ /* Protect us against watches firing on old details when the otherend
+ details change, say immediately after a resume. */
+ if (!dev->otherend ||
+ strncmp(dev->otherend, vec[XS_WATCH_PATH],
+ strlen(dev->otherend))) {
+ dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+ return;
+ }
+
+ state = xenbus_read_driver_state(dev->otherend);
+
+ dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+ state, xenbus_strstate(state), dev->otherend_watch.node,
+ vec[XS_WATCH_PATH]);
+
+ /*
+ * Ignore xenbus transitions during shutdown. This prevents us doing
+ * work that can fail e.g., when the rootfs is gone.
+ */
+ if (system_state > SYSTEM_RUNNING) {
+ struct xen_bus_type *bus = bus;
+ bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+ /* If we're frontend, drive the state machine to Closed. */
+ /* This should cause the backend to release our resources. */
+ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+ xenbus_frontend_closed(dev);
+ return;
+ }
+
+ if (drv->otherend_changed)
+ drv->otherend_changed(dev, state);
+}
+
+
+static int talk_to_otherend(struct xenbus_device *dev)
+{
+ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+
+ free_otherend_watch(dev);
+ free_otherend_details(dev);
+
+ return drv->read_otherend_details(dev);
+}
+
+
+static int watch_otherend(struct xenbus_device *dev)
+{
+ return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed,
+ "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_dev_probe(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+ const struct xenbus_device_id *id;
+ int err;
+
+ DPRINTK("%s", dev->nodename);
+
+ if (!drv->probe) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ id = match_device(drv->ids, dev);
+ if (!id) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ err = talk_to_otherend(dev);
+ if (err) {
+ dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
+ dev->nodename);
+ return err;
+ }
+
+ err = drv->probe(dev, id);
+ if (err)
+ goto fail;
+
+ err = watch_otherend(dev);
+ if (err) {
+ dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+ dev->nodename);
+ return err;
+ }
+
+ return 0;
+fail:
+ xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
+ xenbus_switch_state(dev, XenbusStateClosed);
+ return -ENODEV;
+}
+
+int xenbus_dev_remove(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+
+ DPRINTK("%s", dev->nodename);
+
+ free_otherend_watch(dev);
+ free_otherend_details(dev);
+
+ if (drv->remove)
+ drv->remove(dev);
+
+ xenbus_switch_state(dev, XenbusStateClosed);
+ return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ unsigned long timeout = 5*HZ;
+
+ DPRINTK("%s", dev->nodename);
+
+ get_device(&dev->dev);
+ if (dev->state != XenbusStateConnected) {
+ printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
+ dev->nodename, xenbus_strstate(dev->state));
+ goto out;
+ }
+ xenbus_switch_state(dev, XenbusStateClosing);
+ timeout = wait_for_completion_timeout(&dev->down, timeout);
+ if (!timeout)
+ printk(KERN_INFO "%s: %s timeout closing device\n",
+ __func__, dev->nodename);
+ out:
+ put_device(&dev->dev);
+}
+
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus,
+ struct module *owner,
+ const char *mod_name)
+{
+ drv->driver.name = drv->name;
+ drv->driver.bus = &bus->bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
+
+ return driver_register(&drv->driver);
+}
+
+int __xenbus_register_frontend(struct xenbus_driver *drv,
+ struct module *owner, const char *mod_name)
+{
+ int ret;
+
+ drv->read_otherend_details = read_backend_details;
+
+ ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+ owner, mod_name);
+ if (ret)
+ return ret;
+
+ /* If this driver is loaded as a module wait for devices to attach. */
+ wait_for_devices(drv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+
+void xenbus_unregister_driver(struct xenbus_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
+
+struct xb_find_info
+{
+ struct xenbus_device *dev;
+ const char *nodename;
+};
+
+static int cmp_dev(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct xb_find_info *info = data;
+
+ if (!strcmp(xendev->nodename, info->nodename)) {
+ info->dev = xendev;
+ get_device(dev);
+ return 1;
+ }
+ return 0;
+}
+
+struct xenbus_device *xenbus_device_find(const char *nodename,
+ struct bus_type *bus)
+{
+ struct xb_find_info info = { .dev = NULL, .nodename = nodename };
+
+ bus_for_each_dev(bus, NULL, &info, cmp_dev);
+ return info.dev;
+}
+
+static int cleanup_dev(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct xb_find_info *info = data;
+ int len = strlen(info->nodename);
+
+ DPRINTK("%s", info->nodename);
+
+ /* Match the info->nodename path, or any subdirectory of that path. */
+ if (strncmp(xendev->nodename, info->nodename, len))
+ return 0;
+
+ /* If the node name is longer, ensure it really is a subdirectory. */
+ if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
+ return 0;
+
+ info->dev = xendev;
+ get_device(dev);
+ return 1;
+}
+
+static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
+{
+ struct xb_find_info info = { .nodename = path };
+
+ do {
+ info.dev = NULL;
+ bus_for_each_dev(bus, NULL, &info, cleanup_dev);
+ if (info.dev) {
+ device_unregister(&info.dev->dev);
+ put_device(&info.dev->dev);
+ }
+ } while (info.dev);
+}
+
+static void xenbus_dev_release(struct device *dev)
+{
+ if (dev)
+ kfree(to_xenbus_device(dev));
+}
+
+static ssize_t xendev_show_nodename(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+}
+DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+static ssize_t xendev_show_devtype(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+
+int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename)
+{
+ int err;
+ struct xenbus_device *xendev;
+ size_t stringlen;
+ char *tmpstring;
+
+ enum xenbus_state state = xenbus_read_driver_state(nodename);
+
+ if (state != XenbusStateInitialising) {
+ /* Device is not new, so ignore it. This can happen if a
+ device is going away after switching to Closed. */
+ return 0;
+ }
+
+ stringlen = strlen(nodename) + 1 + strlen(type) + 1;
+ xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+ if (!xendev)
+ return -ENOMEM;
+
+ xendev->state = XenbusStateInitialising;
+
+ /* Copy the strings into the extra space. */
+
+ tmpstring = (char *)(xendev + 1);
+ strcpy(tmpstring, nodename);
+ xendev->nodename = tmpstring;
+
+ tmpstring += strlen(tmpstring) + 1;
+ strcpy(tmpstring, type);
+ xendev->devicetype = tmpstring;
+ init_completion(&xendev->down);
+
+ xendev->dev.bus = &bus->bus;
+ xendev->dev.release = xenbus_dev_release;
+
+ err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
+ if (err)
+ goto fail;
+
+ /* Register with generic device framework. */
+ err = device_register(&xendev->dev);
+ if (err)
+ goto fail;
+
+ err = device_create_file(&xendev->dev, &dev_attr_nodename);
+ if (err)
+ goto fail_unregister;
+
+ err = device_create_file(&xendev->dev, &dev_attr_devtype);
+ if (err)
+ goto fail_remove_file;
+
+ return 0;
+fail_remove_file:
+ device_remove_file(&xendev->dev, &dev_attr_nodename);
+fail_unregister:
+ device_unregister(&xendev->dev);
+fail:
+ kfree(xendev);
+ return err;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(const char *type, const char *name)
+{
+ char *nodename;
+ int err;
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s",
+ xenbus_frontend.root, type, name);
+ if (!nodename)
+ return -ENOMEM;
+
+ DPRINTK("%s", nodename);
+
+ err = xenbus_probe_node(&xenbus_frontend, type, nodename);
+ kfree(nodename);
+ return err;
+}
+
+static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
+{
+ int err = 0;
+ char **dir;
+ unsigned int dir_n = 0;
+ int i;
+
+ dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ for (i = 0; i < dir_n; i++) {
+ err = bus->probe(type, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ return err;
+}
+
+int xenbus_probe_devices(struct xen_bus_type *bus)
+{
+ int err = 0;
+ char **dir;
+ unsigned int i, dir_n;
+
+ dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ for (i = 0; i < dir_n; i++) {
+ err = xenbus_probe_device_type(bus, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ return err;
+}
+
+static unsigned int char_count(const char *str, char c)
+{
+ unsigned int i, ret = 0;
+
+ for (i = 0; str[i]; i++)
+ if (str[i] == c)
+ ret++;
+ return ret;
+}
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; str[i]; i++)
+ if (str[i] == c) {
+ if (len == 0)
+ return i;
+ len--;
+ }
+ return (len == 0) ? i : -ERANGE;
+}
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
+{
+ int exists, rootlen;
+ struct xenbus_device *dev;
+ char type[BUS_ID_SIZE];
+ const char *p, *root;
+
+ if (char_count(node, '/') < 2)
+ return;
+
+ exists = xenbus_exists(XBT_NIL, node, "");
+ if (!exists) {
+ xenbus_cleanup_devices(node, &bus->bus);
+ return;
+ }
+
+ /* backend/<type>/... or device/<type>/... */
+ p = strchr(node, '/') + 1;
+ snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
+ type[BUS_ID_SIZE-1] = '\0';
+
+ rootlen = strsep_len(node, '/', bus->levels);
+ if (rootlen < 0)
+ return;
+ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
+ if (!root)
+ return;
+
+ dev = xenbus_device_find(root, &bus->bus);
+ if (!dev)
+ xenbus_probe_node(bus, type, root);
+ else
+ put_device(&dev->dev);
+
+ kfree(root);
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ DPRINTK("");
+
+ xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+}
+
+/* We watch for devices appearing and vanishing. */
+static struct xenbus_watch fe_watch = {
+ .node = "device",
+ .callback = frontend_changed,
+};
+
+static int suspend_dev(struct device *dev, void *data)
+{
+ int err = 0;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+ if (drv->suspend)
+ err = drv->suspend(xdev);
+ if (err)
+ printk(KERN_WARNING
+ "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
+ return 0;
+}
+
+static int suspend_cancel_dev(struct device *dev, void *data)
+{
+ int err = 0;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+ if (drv->suspend_cancel)
+ err = drv->suspend_cancel(xdev);
+ if (err)
+ printk(KERN_WARNING
+ "xenbus: suspend_cancel %s failed: %i\n",
+ dev->bus_id, err);
+ return 0;
+}
+
+static int resume_dev(struct device *dev, void *data)
+{
+ int err;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+
+ err = talk_to_otherend(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus: resume (talk_to_otherend) %s failed: %i\n",
+ dev->bus_id, err);
+ return err;
+ }
+
+ xdev->state = XenbusStateInitialising;
+
+ if (drv->resume) {
+ err = drv->resume(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus: resume %s failed: %i\n",
+ dev->bus_id, err);
+ return err;
+ }
+ }
+
+ err = watch_otherend(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus_probe: resume (watch_otherend) %s failed: "
+ "%d.\n", dev->bus_id, err);
+ return err;
+ }
+
+ return 0;
+}
+
+void xenbus_suspend(void)
+{
+ DPRINTK("");
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
+ xenbus_backend_suspend(suspend_dev);
+ xs_suspend();
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend);
+
+void xenbus_resume(void)
+{
+ xb_init_comms();
+ xs_resume();
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
+ xenbus_backend_resume(resume_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_resume);
+
+void xenbus_suspend_cancel(void)
+{
+ xs_suspend_cancel();
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
+ xenbus_backend_resume(suspend_cancel_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
+
+/* A flag to determine if xenstored is 'ready' (i.e. has started) */
+int xenstored_ready = 0;
+
+
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+ int ret = 0;
+
+ if (xenstored_ready > 0)
+ ret = nb->notifier_call(nb, 0, NULL);
+ else
+ blocking_notifier_chain_register(&xenstore_chain, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&xenstore_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
+
+void xenbus_probe(struct work_struct *unused)
+{
+ BUG_ON((xenstored_ready <= 0));
+
+ /* Enumerate devices in xenstore and watch for changes. */
+ xenbus_probe_devices(&xenbus_frontend);
+ register_xenbus_watch(&fe_watch);
+ xenbus_backend_probe_and_watch();
+
+ /* Notify others that xenstore is up */
+ blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
+}
+
+static int __init xenbus_probe_init(void)
+{
+ int err = 0;
+
+ DPRINTK("");
+
+ err = -ENODEV;
+ if (!is_running_on_xen())
+ goto out_error;
+
+ /* Register ourselves with the kernel bus subsystem */
+ err = bus_register(&xenbus_frontend.bus);
+ if (err)
+ goto out_error;
+
+ err = xenbus_backend_bus_register();
+ if (err)
+ goto out_unreg_front;
+
+ /*
+ * Domain0 doesn't have a store_evtchn or store_mfn yet.
+ */
+ if (is_initial_xendomain()) {
+ /* dom0 not yet supported */
+ } else {
+ xenstored_ready = 1;
+ xen_store_evtchn = xen_start_info->store_evtchn;
+ xen_store_mfn = xen_start_info->store_mfn;
+ }
+ xen_store_interface = mfn_to_virt(xen_store_mfn);
+
+ /* Initialize the interface to xenstore. */
+ err = xs_init();
+ if (err) {
+ printk(KERN_WARNING
+ "XENBUS: Error initializing xenstore comms: %i\n", err);
+ goto out_unreg_back;
+ }
+
+ if (!is_initial_xendomain())
+ xenbus_probe(NULL);
+
+ return 0;
+
+ out_unreg_back:
+ xenbus_backend_bus_unregister();
+
+ out_unreg_front:
+ bus_unregister(&xenbus_frontend.bus);
+
+ out_error:
+ return err;
+}
+
+postcore_initcall(xenbus_probe_init);
+
+MODULE_LICENSE("GPL");
+
+static int is_disconnected_device(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+
+ /*
+ * A device with no driver will never connect. We care only about
+ * devices which should currently be in the process of connecting.
+ */
+ if (!dev->driver)
+ return 0;
+
+ /* Is this search limited to a particular driver? */
+ if (drv && (dev->driver != drv))
+ return 0;
+
+ return (xendev->state != XenbusStateConnected);
+}
+
+static int exists_disconnected_device(struct device_driver *drv)
+{
+ return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ is_disconnected_device);
+}
+
+static int print_device_status(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+
+ /* Is this operation limited to a particular driver? */
+ if (drv && (dev->driver != drv))
+ return 0;
+
+ if (!dev->driver) {
+ /* Information only: is this too noisy? */
+ printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
+ xendev->nodename);
+ } else if (xendev->state != XenbusStateConnected) {
+ printk(KERN_WARNING "XENBUS: Timeout connecting "
+ "to device: %s (state %d)\n",
+ xendev->nodename, xendev->state);
+ }
+
+ return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 10 second timeout, wait for all devices currently configured. We need
+ * to do this to guarantee that the filesystems and / or network devices
+ * needed for boot are available, before we can allow the boot to proceed.
+ *
+ * This needs to be on a late_initcall, to happen after the frontend device
+ * drivers have been initialised, but before the root fs is mounted.
+ *
+ * A possible improvement here would be to have the tools add a per-device
+ * flag to the store entry, indicating whether it is needed at boot time.
+ * This would allow people who knew what they were doing to accelerate their
+ * boot slightly, but of course needs tools or manual intervention to set up
+ * those flags correctly.
+ */
+static void wait_for_devices(struct xenbus_driver *xendrv)
+{
+ unsigned long timeout = jiffies + 10*HZ;
+ struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+
+ if (!ready_to_wait_for_devices || !is_running_on_xen())
+ return;
+
+ while (exists_disconnected_device(drv)) {
+ if (time_after(jiffies, timeout))
+ break;
+ schedule_timeout_interruptible(HZ/10);
+ }
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ print_device_status);
+}
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+ ready_to_wait_for_devices = 1;
+ wait_for_devices(NULL);
+ return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644
index 000000000000..e09b19415a40
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern int xenbus_backend_bus_register(void);
+extern void xenbus_backend_bus_unregister(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline int xenbus_backend_bus_register(void) { return 0; }
+static inline void xenbus_backend_bus_unregister(void) {}
+#endif
+
+struct xen_bus_type
+{
+ char *root;
+ unsigned int levels;
+ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+ int (*probe)(const char *type, const char *dir);
+ struct bus_type bus;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus,
+ struct module *owner,
+ const char *mod_name);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
new file mode 100644
index 000000000000..227d53b12a5c
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -0,0 +1,861 @@
+/******************************************************************************
+ * xenbus_xs.c
+ *
+ * This is the kernel equivalent of the "xs" library. We don't need everything
+ * and we use xenbus_comms for communication.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include "xenbus_comms.h"
+
+struct xs_stored_msg {
+ struct list_head list;
+
+ struct xsd_sockmsg hdr;
+
+ union {
+ /* Queued replies. */
+ struct {
+ char *body;
+ } reply;
+
+ /* Queued watch events. */
+ struct {
+ struct xenbus_watch *handle;
+ char **vec;
+ unsigned int vec_size;
+ } watch;
+ } u;
+};
+
+struct xs_handle {
+ /* A list of replies. Currently only one will ever be outstanding. */
+ struct list_head reply_list;
+ spinlock_t reply_lock;
+ wait_queue_head_t reply_waitq;
+
+ /*
+ * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
+ * response_mutex is never taken simultaneously with the other three.
+ */
+
+ /* One request at a time. */
+ struct mutex request_mutex;
+
+ /* Protect xenbus reader thread against save/restore. */
+ struct mutex response_mutex;
+
+ /* Protect transactions against save/restore. */
+ struct rw_semaphore transaction_mutex;
+
+ /* Protect watch (de)register against save/restore. */
+ struct rw_semaphore watch_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
+static LIST_HEAD(watches);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+static pid_t xenwatch_pid;
+static DEFINE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+
+static int get_error(const char *errorstring)
+{
+ unsigned int i;
+
+ for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
+ if (i == ARRAY_SIZE(xsd_errors) - 1) {
+ printk(KERN_WARNING
+ "XENBUS xen store gave: unknown error %s",
+ errorstring);
+ return EINVAL;
+ }
+ }
+ return xsd_errors[i].errnum;
+}
+
+static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+{
+ struct xs_stored_msg *msg;
+ char *body;
+
+ spin_lock(&xs_state.reply_lock);
+
+ while (list_empty(&xs_state.reply_list)) {
+ spin_unlock(&xs_state.reply_lock);
+ /* XXX FIXME: Avoid synchronous wait for response here. */
+ wait_event(xs_state.reply_waitq,
+ !list_empty(&xs_state.reply_list));
+ spin_lock(&xs_state.reply_lock);
+ }
+
+ msg = list_entry(xs_state.reply_list.next,
+ struct xs_stored_msg, list);
+ list_del(&msg->list);
+
+ spin_unlock(&xs_state.reply_lock);
+
+ *type = msg->hdr.type;
+ if (len)
+ *len = msg->hdr.len;
+ body = msg->u.reply.body;
+
+ kfree(msg);
+
+ return body;
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+ void *ret;
+ struct xsd_sockmsg req_msg = *msg;
+ int err;
+
+ if (req_msg.type == XS_TRANSACTION_START)
+ down_read(&xs_state.transaction_mutex);
+
+ mutex_lock(&xs_state.request_mutex);
+
+ err = xb_write(msg, sizeof(*msg) + msg->len);
+ if (err) {
+ msg->type = XS_ERROR;
+ ret = ERR_PTR(err);
+ } else
+ ret = read_reply(&msg->type, &msg->len);
+
+ mutex_unlock(&xs_state.request_mutex);
+
+ if ((msg->type == XS_TRANSACTION_END) ||
+ ((req_msg.type == XS_TRANSACTION_START) &&
+ (msg->type == XS_ERROR)))
+ up_read(&xs_state.transaction_mutex);
+
+ return ret;
+}
+
+/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
+static void *xs_talkv(struct xenbus_transaction t,
+ enum xsd_sockmsg_type type,
+ const struct kvec *iovec,
+ unsigned int num_vecs,
+ unsigned int *len)
+{
+ struct xsd_sockmsg msg;
+ void *ret = NULL;
+ unsigned int i;
+ int err;
+
+ msg.tx_id = t.id;
+ msg.req_id = 0;
+ msg.type = type;
+ msg.len = 0;
+ for (i = 0; i < num_vecs; i++)
+ msg.len += iovec[i].iov_len;
+
+ mutex_lock(&xs_state.request_mutex);
+
+ err = xb_write(&msg, sizeof(msg));
+ if (err) {
+ mutex_unlock(&xs_state.request_mutex);
+ return ERR_PTR(err);
+ }
+
+ for (i = 0; i < num_vecs; i++) {
+ err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
+ if (err) {
+ mutex_unlock(&xs_state.request_mutex);
+ return ERR_PTR(err);
+ }
+ }
+
+ ret = read_reply(&msg.type, len);
+
+ mutex_unlock(&xs_state.request_mutex);
+
+ if (IS_ERR(ret))
+ return ret;
+
+ if (msg.type == XS_ERROR) {
+ err = get_error(ret);
+ kfree(ret);
+ return ERR_PTR(-err);
+ }
+
+ if (msg.type != type) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING
+ "XENBUS unexpected type [%d], expected [%d]\n",
+ msg.type, type);
+ kfree(ret);
+ return ERR_PTR(-EINVAL);
+ }
+ return ret;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xenbus_transaction t,
+ enum xsd_sockmsg_type type,
+ const char *string,
+ unsigned int *len)
+{
+ struct kvec iovec;
+
+ iovec.iov_base = (void *)string;
+ iovec.iov_len = strlen(string) + 1;
+ return xs_talkv(t, type, &iovec, 1, len);
+}
+
+/* Many commands only need an ack, don't care what it says. */
+static int xs_error(char *reply)
+{
+ if (IS_ERR(reply))
+ return PTR_ERR(reply);
+ kfree(reply);
+ return 0;
+}
+
+static unsigned int count_strings(const char *strings, unsigned int len)
+{
+ unsigned int num;
+ const char *p;
+
+ for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
+ num++;
+
+ return num;
+}
+
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
+static char *join(const char *dir, const char *name)
+{
+ char *buffer;
+
+ if (strlen(name) == 0)
+ buffer = kasprintf(GFP_KERNEL, "%s", dir);
+ else
+ buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+ return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
+}
+
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+ char *p, **ret;
+
+ /* Count the strings. */
+ *num = count_strings(strings, len);
+
+ /* Transfer to one big alloc for easy freeing. */
+ ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+ if (!ret) {
+ kfree(strings);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(&ret[*num], strings, len);
+ kfree(strings);
+
+ strings = (char *)&ret[*num];
+ for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+ ret[(*num)++] = p;
+
+ return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *num)
+{
+ char *strings, *path;
+ unsigned int len;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return (char **)path;
+
+ strings = xs_single(t, XS_DIRECTORY, path, &len);
+ kfree(path);
+ if (IS_ERR(strings))
+ return (char **)strings;
+
+ return split(strings, len, num);
+}
+EXPORT_SYMBOL_GPL(xenbus_directory);
+
+/* Check if a path exists. Return 1 if it does. */
+int xenbus_exists(struct xenbus_transaction t,
+ const char *dir, const char *node)
+{
+ char **d;
+ int dir_n;
+
+ d = xenbus_directory(t, dir, node, &dir_n);
+ if (IS_ERR(d))
+ return 0;
+ kfree(d);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(xenbus_exists);
+
+/* Get the value of a single file.
+ * Returns a kmalloced value: call free() on it after use.
+ * len indicates length in bytes.
+ */
+void *xenbus_read(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *len)
+{
+ char *path;
+ void *ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return (void *)path;
+
+ ret = xs_single(t, XS_READ, path, len);
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_read);
+
+/* Write the value of a single file.
+ * Returns -err on failure.
+ */
+int xenbus_write(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *string)
+{
+ const char *path;
+ struct kvec iovec[2];
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ iovec[0].iov_base = (void *)path;
+ iovec[0].iov_len = strlen(path) + 1;
+ iovec[1].iov_base = (void *)string;
+ iovec[1].iov_len = strlen(string);
+
+ ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_write);
+
+/* Create a new directory. */
+int xenbus_mkdir(struct xenbus_transaction t,
+ const char *dir, const char *node)
+{
+ char *path;
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_mkdir);
+
+/* Destroy a file or directory (directories must be empty). */
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
+{
+ char *path;
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ ret = xs_error(xs_single(t, XS_RM, path, NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_rm);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ */
+int xenbus_transaction_start(struct xenbus_transaction *t)
+{
+ char *id_str;
+
+ down_read(&xs_state.transaction_mutex);
+
+ id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
+ if (IS_ERR(id_str)) {
+ up_read(&xs_state.transaction_mutex);
+ return PTR_ERR(id_str);
+ }
+
+ t->id = simple_strtoul(id_str, NULL, 0);
+ kfree(id_str);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_start);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ */
+int xenbus_transaction_end(struct xenbus_transaction t, int abort)
+{
+ char abortstr[2];
+ int err;
+
+ if (abort)
+ strcpy(abortstr, "F");
+ else
+ strcpy(abortstr, "T");
+
+ err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+ up_read(&xs_state.transaction_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_end);
+
+/* Single read and scanf: returns -errno or num scanned. */
+int xenbus_scanf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *val;
+
+ val = xenbus_read(t, dir, node, NULL);
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ va_start(ap, fmt);
+ ret = vsscanf(val, fmt, ap);
+ va_end(ap);
+ kfree(val);
+ /* Distinctive errno. */
+ if (ret == 0)
+ return -ERANGE;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_scanf);
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+#define PRINTF_BUFFER_SIZE 4096
+ char *printf_buffer;
+
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ if (printf_buffer == NULL)
+ return -ENOMEM;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+ ret = xenbus_write(t, dir, node, printf_buffer);
+
+ kfree(printf_buffer);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_printf);
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
+{
+ va_list ap;
+ const char *name;
+ int ret = 0;
+
+ va_start(ap, dir);
+ while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+ const char *fmt = va_arg(ap, char *);
+ void *result = va_arg(ap, void *);
+ char *p;
+
+ p = xenbus_read(t, dir, name, NULL);
+ if (IS_ERR(p)) {
+ ret = PTR_ERR(p);
+ break;
+ }
+ if (fmt) {
+ if (sscanf(p, fmt, result) == 0)
+ ret = -EINVAL;
+ kfree(p);
+ } else
+ *(char **)result = p;
+ }
+ va_end(ap);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_gather);
+
+static int xs_watch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
+ iov[0].iov_base = (void *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (void *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
+ ARRAY_SIZE(iov), NULL));
+}
+
+static int xs_unwatch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
+ iov[0].iov_base = (char *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (char *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
+ ARRAY_SIZE(iov), NULL));
+}
+
+static struct xenbus_watch *find_watch(const char *token)
+{
+ struct xenbus_watch *i, *cmp;
+
+ cmp = (void *)simple_strtoul(token, NULL, 16);
+
+ list_for_each_entry(i, &watches, list)
+ if (i == cmp)
+ return i;
+
+ return NULL;
+}
+
+/* Register callback to watch this node. */
+int register_xenbus_watch(struct xenbus_watch *watch)
+{
+ /* Pointer in ascii is the token. */
+ char token[sizeof(watch) * 2 + 1];
+ int err;
+
+ sprintf(token, "%lX", (long)watch);
+
+ down_read(&xs_state.watch_mutex);
+
+ spin_lock(&watches_lock);
+ BUG_ON(find_watch(token));
+ list_add(&watch->list, &watches);
+ spin_unlock(&watches_lock);
+
+ err = xs_watch(watch->node, token);
+
+ /* Ignore errors due to multiple registration. */
+ if ((err != 0) && (err != -EEXIST)) {
+ spin_lock(&watches_lock);
+ list_del(&watch->list);
+ spin_unlock(&watches_lock);
+ }
+
+ up_read(&xs_state.watch_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_xenbus_watch);
+
+void unregister_xenbus_watch(struct xenbus_watch *watch)
+{
+ struct xs_stored_msg *msg, *tmp;
+ char token[sizeof(watch) * 2 + 1];
+ int err;
+
+ sprintf(token, "%lX", (long)watch);
+
+ down_read(&xs_state.watch_mutex);
+
+ spin_lock(&watches_lock);
+ BUG_ON(!find_watch(token));
+ list_del(&watch->list);
+ spin_unlock(&watches_lock);
+
+ err = xs_unwatch(watch->node, token);
+ if (err)
+ printk(KERN_WARNING
+ "XENBUS Failed to release watch %s: %i\n",
+ watch->node, err);
+
+ up_read(&xs_state.watch_mutex);
+
+ /* Make sure there are no callbacks running currently (unless
+ its us) */
+ if (current->pid != xenwatch_pid)
+ mutex_lock(&xenwatch_mutex);
+
+ /* Cancel pending watch events. */
+ spin_lock(&watch_events_lock);
+ list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+ if (msg->u.watch.handle != watch)
+ continue;
+ list_del(&msg->list);
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+ spin_unlock(&watch_events_lock);
+
+ if (current->pid != xenwatch_pid)
+ mutex_unlock(&xenwatch_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
+
+void xs_suspend(void)
+{
+ down_write(&xs_state.transaction_mutex);
+ down_write(&xs_state.watch_mutex);
+ mutex_lock(&xs_state.request_mutex);
+ mutex_lock(&xs_state.response_mutex);
+}
+
+void xs_resume(void)
+{
+ struct xenbus_watch *watch;
+ char token[sizeof(watch) * 2 + 1];
+
+ mutex_unlock(&xs_state.response_mutex);
+ mutex_unlock(&xs_state.request_mutex);
+ up_write(&xs_state.transaction_mutex);
+
+ /* No need for watches_lock: the watch_mutex is sufficient. */
+ list_for_each_entry(watch, &watches, list) {
+ sprintf(token, "%lX", (long)watch);
+ xs_watch(watch->node, token);
+ }
+
+ up_write(&xs_state.watch_mutex);
+}
+
+void xs_suspend_cancel(void)
+{
+ mutex_unlock(&xs_state.response_mutex);
+ mutex_unlock(&xs_state.request_mutex);
+ up_write(&xs_state.watch_mutex);
+ up_write(&xs_state.transaction_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+ struct list_head *ent;
+ struct xs_stored_msg *msg;
+
+ for (;;) {
+ wait_event_interruptible(watch_events_waitq,
+ !list_empty(&watch_events));
+
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&xenwatch_mutex);
+
+ spin_lock(&watch_events_lock);
+ ent = watch_events.next;
+ if (ent != &watch_events)
+ list_del(ent);
+ spin_unlock(&watch_events_lock);
+
+ if (ent != &watch_events) {
+ msg = list_entry(ent, struct xs_stored_msg, list);
+ msg->u.watch.handle->callback(
+ msg->u.watch.handle,
+ (const char **)msg->u.watch.vec,
+ msg->u.watch.vec_size);
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+
+ mutex_unlock(&xenwatch_mutex);
+ }
+
+ return 0;
+}
+
+static int process_msg(void)
+{
+ struct xs_stored_msg *msg;
+ char *body;
+ int err;
+
+ /*
+ * We must disallow save/restore while reading a xenstore message.
+ * A partial read across s/r leaves us out of sync with xenstored.
+ */
+ for (;;) {
+ err = xb_wait_for_data_to_read();
+ if (err)
+ return err;
+ mutex_lock(&xs_state.response_mutex);
+ if (xb_data_to_read())
+ break;
+ /* We raced with save/restore: pending data 'disappeared'. */
+ mutex_unlock(&xs_state.response_mutex);
+ }
+
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (msg == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = xb_read(&msg->hdr, sizeof(msg->hdr));
+ if (err) {
+ kfree(msg);
+ goto out;
+ }
+
+ body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+ if (body == NULL) {
+ kfree(msg);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = xb_read(body, msg->hdr.len);
+ if (err) {
+ kfree(body);
+ kfree(msg);
+ goto out;
+ }
+ body[msg->hdr.len] = '\0';
+
+ if (msg->hdr.type == XS_WATCH_EVENT) {
+ msg->u.watch.vec = split(body, msg->hdr.len,
+ &msg->u.watch.vec_size);
+ if (IS_ERR(msg->u.watch.vec)) {
+ err = PTR_ERR(msg->u.watch.vec);
+ kfree(msg);
+ goto out;
+ }
+
+ spin_lock(&watches_lock);
+ msg->u.watch.handle = find_watch(
+ msg->u.watch.vec[XS_WATCH_TOKEN]);
+ if (msg->u.watch.handle != NULL) {
+ spin_lock(&watch_events_lock);
+ list_add_tail(&msg->list, &watch_events);
+ wake_up(&watch_events_waitq);
+ spin_unlock(&watch_events_lock);
+ } else {
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+ spin_unlock(&watches_lock);
+ } else {
+ msg->u.reply.body = body;
+ spin_lock(&xs_state.reply_lock);
+ list_add_tail(&msg->list, &xs_state.reply_list);
+ spin_unlock(&xs_state.reply_lock);
+ wake_up(&xs_state.reply_waitq);
+ }
+
+ out:
+ mutex_unlock(&xs_state.response_mutex);
+ return err;
+}
+
+static int xenbus_thread(void *unused)
+{
+ int err;
+
+ for (;;) {
+ err = process_msg();
+ if (err)
+ printk(KERN_WARNING "XENBUS error %d while reading "
+ "message\n", err);
+ if (kthread_should_stop())
+ break;
+ }
+
+ return 0;
+}
+
+int xs_init(void)
+{
+ int err;
+ struct task_struct *task;
+
+ INIT_LIST_HEAD(&xs_state.reply_list);
+ spin_lock_init(&xs_state.reply_lock);
+ init_waitqueue_head(&xs_state.reply_waitq);
+
+ mutex_init(&xs_state.request_mutex);
+ mutex_init(&xs_state.response_mutex);
+ init_rwsem(&xs_state.transaction_mutex);
+ init_rwsem(&xs_state.watch_mutex);
+
+ /* Initialize the shared memory rings to talk to xenstored */
+ err = xb_init_comms();
+ if (err)
+ return err;
+
+ task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ xenwatch_pid = task->pid;
+
+ task = kthread_run(xenbus_thread, NULL, "xenbus");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+
+ return 0;
+}
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 9130f1c12c26..808b4f8675c5 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -78,7 +78,7 @@ static ssize_t zorro_read_config(struct kobject *kobj,
static struct bin_attribute zorro_config_attr = {
.attr = {
.name = "config",
- .mode = S_IRUGO | S_IWUSR,
+ .mode = S_IRUGO,
},
.size = sizeof(struct ConfigDev),
.read = zorro_read_config,